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:
authorMartin Poirier <theeth@yahoo.com>2007-11-07 01:29:20 +0300
committerMartin Poirier <theeth@yahoo.com>2007-11-07 01:29:20 +0300
commit0de103c1cdf1e4c40cfad4e233a42a6d1165953d (patch)
treea57039fa592cf0f5af3738a9624d0b0ccbf20ec0 /source/blender
Filling in branch from trunk
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/CMakeLists.txt42
-rw-r--r--source/blender/Makefile53
-rw-r--r--source/blender/SConscript33
-rw-r--r--source/blender/avi/AVI_avi.h309
-rw-r--r--source/blender/avi/CMakeLists.txt38
-rw-r--r--source/blender/avi/Makefile37
-rw-r--r--source/blender/avi/SConscript10
-rw-r--r--source/blender/avi/intern/Makefile54
-rw-r--r--source/blender/avi/intern/avi.c843
-rw-r--r--source/blender/avi/intern/avi_intern.h54
-rw-r--r--source/blender/avi/intern/avirgb.c153
-rw-r--r--source/blender/avi/intern/avirgb.h35
-rw-r--r--source/blender/avi/intern/codecs.c147
-rw-r--r--source/blender/avi/intern/endian.c216
-rw-r--r--source/blender/avi/intern/endian.h55
-rw-r--r--source/blender/avi/intern/mjpeg.c458
-rw-r--r--source/blender/avi/intern/mjpeg.h35
-rw-r--r--source/blender/avi/intern/options.c130
-rw-r--r--source/blender/avi/intern/rgb32.c91
-rw-r--r--source/blender/avi/intern/rgb32.h35
-rw-r--r--source/blender/blenkernel/BKE_DerivedMesh.h461
-rw-r--r--source/blender/blenkernel/BKE_action.h164
-rw-r--r--source/blender/blenkernel/BKE_anim.h61
-rw-r--r--source/blender/blenkernel/BKE_armature.h122
-rw-r--r--source/blender/blenkernel/BKE_bad_level_calls.h235
-rw-r--r--source/blender/blenkernel/BKE_blender.h79
-rw-r--r--source/blender/blenkernel/BKE_bmfont.h65
-rw-r--r--source/blender/blenkernel/BKE_bmfont_types.h62
-rw-r--r--source/blender/blenkernel/BKE_booleanops.h52
-rw-r--r--source/blender/blenkernel/BKE_booleanops_mesh.h120
-rw-r--r--source/blender/blenkernel/BKE_brush.h77
-rw-r--r--source/blender/blenkernel/BKE_cdderivedmesh.h109
-rw-r--r--source/blender/blenkernel/BKE_colortools.h62
-rw-r--r--source/blender/blenkernel/BKE_constraint.h140
-rw-r--r--source/blender/blenkernel/BKE_curve.h91
-rw-r--r--source/blender/blenkernel/BKE_customdata.h244
-rw-r--r--source/blender/blenkernel/BKE_deform.h53
-rw-r--r--source/blender/blenkernel/BKE_depsgraph.h113
-rw-r--r--source/blender/blenkernel/BKE_displist.h127
-rw-r--r--source/blender/blenkernel/BKE_effect.h79
-rw-r--r--source/blender/blenkernel/BKE_endian.h47
-rw-r--r--source/blender/blenkernel/BKE_exotic.h56
-rw-r--r--source/blender/blenkernel/BKE_font.h74
-rw-r--r--source/blender/blenkernel/BKE_global.h264
-rw-r--r--source/blender/blenkernel/BKE_group.h57
-rw-r--r--source/blender/blenkernel/BKE_icons.h88
-rw-r--r--source/blender/blenkernel/BKE_idprop.h177
-rw-r--r--source/blender/blenkernel/BKE_image.h156
-rw-r--r--source/blender/blenkernel/BKE_ipo.h118
-rw-r--r--source/blender/blenkernel/BKE_key.h65
-rw-r--r--source/blender/blenkernel/BKE_lattice.h74
-rw-r--r--source/blender/blenkernel/BKE_library.h77
-rw-r--r--source/blender/blenkernel/BKE_main.h85
-rw-r--r--source/blender/blenkernel/BKE_material.h78
-rw-r--r--source/blender/blenkernel/BKE_mball.h182
-rw-r--r--source/blender/blenkernel/BKE_mesh.h127
-rw-r--r--source/blender/blenkernel/BKE_modifier.h295
-rw-r--r--source/blender/blenkernel/BKE_nla.h47
-rw-r--r--source/blender/blenkernel/BKE_node.h347
-rw-r--r--source/blender/blenkernel/BKE_object.h118
-rw-r--r--source/blender/blenkernel/BKE_packedFile.h64
-rw-r--r--source/blender/blenkernel/BKE_plugin_types.h72
-rw-r--r--source/blender/blenkernel/BKE_property.h55
-rw-r--r--source/blender/blenkernel/BKE_sca.h75
-rw-r--r--source/blender/blenkernel/BKE_scene.h84
-rw-r--r--source/blender/blenkernel/BKE_screen.h40
-rw-r--r--source/blender/blenkernel/BKE_script.h49
-rw-r--r--source/blender/blenkernel/BKE_softbody.h58
-rw-r--r--source/blender/blenkernel/BKE_sound.h55
-rw-r--r--source/blender/blenkernel/BKE_subsurf.h49
-rw-r--r--source/blender/blenkernel/BKE_text.h144
-rw-r--r--source/blender/blenkernel/BKE_texture.h80
-rw-r--r--source/blender/blenkernel/BKE_utildefines.h192
-rw-r--r--source/blender/blenkernel/BKE_verse.h586
-rw-r--r--source/blender/blenkernel/BKE_world.h45
-rw-r--r--source/blender/blenkernel/BKE_writeavi.h62
-rw-r--r--source/blender/blenkernel/BKE_writeffmpeg.h76
-rw-r--r--source/blender/blenkernel/BKE_writeframeserver.h50
-rw-r--r--source/blender/blenkernel/CMakeLists.txt77
-rw-r--r--source/blender/blenkernel/Makefile37
-rw-r--r--source/blender/blenkernel/SConscript47
-rw-r--r--source/blender/blenkernel/bad_level_call_stubs/CMakeLists.txt46
-rw-r--r--source/blender/blenkernel/bad_level_call_stubs/Makefile51
-rw-r--r--source/blender/blenkernel/bad_level_call_stubs/SConscript14
-rw-r--r--source/blender/blenkernel/bad_level_call_stubs/stubs.c338
-rw-r--r--source/blender/blenkernel/depsgraph_private.h133
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf.c2294
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf.h152
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c3310
-rw-r--r--source/blender/blenkernel/intern/Makefile109
-rw-r--r--source/blender/blenkernel/intern/action.c1373
-rw-r--r--source/blender/blenkernel/intern/anim.c844
-rw-r--r--source/blender/blenkernel/intern/armature.c2130
-rw-r--r--source/blender/blenkernel/intern/blender.c735
-rw-r--r--source/blender/blenkernel/intern/bmfont.c297
-rw-r--r--source/blender/blenkernel/intern/brush.c882
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c1130
-rw-r--r--source/blender/blenkernel/intern/colortools.c719
-rw-r--r--source/blender/blenkernel/intern/constraint.c3422
-rw-r--r--source/blender/blenkernel/intern/curve.c2595
-rw-r--r--source/blender/blenkernel/intern/customdata.c1482
-rw-r--r--source/blender/blenkernel/intern/deform.c225
-rw-r--r--source/blender/blenkernel/intern/depsgraph.c2236
-rw-r--r--source/blender/blenkernel/intern/displist.c1589
-rw-r--r--source/blender/blenkernel/intern/effect.c2110
-rw-r--r--source/blender/blenkernel/intern/exotic.c4943
-rw-r--r--source/blender/blenkernel/intern/font.c1189
-rw-r--r--source/blender/blenkernel/intern/group.c327
-rw-r--r--source/blender/blenkernel/intern/icons.c302
-rw-r--r--source/blender/blenkernel/intern/idprop.c443
-rw-r--r--source/blender/blenkernel/intern/image.c1805
-rw-r--r--source/blender/blenkernel/intern/ipo.c2432
-rw-r--r--source/blender/blenkernel/intern/key.c1408
-rw-r--r--source/blender/blenkernel/intern/lattice.c915
-rw-r--r--source/blender/blenkernel/intern/library.c1098
-rw-r--r--source/blender/blenkernel/intern/material.c1110
-rw-r--r--source/blender/blenkernel/intern/mball.c2088
-rw-r--r--source/blender/blenkernel/intern/mesh.c1250
-rw-r--r--source/blender/blenkernel/intern/modifier.c5765
-rw-r--r--source/blender/blenkernel/intern/nla.c190
-rw-r--r--source/blender/blenkernel/intern/node.c2414
-rw-r--r--source/blender/blenkernel/intern/object.c2080
-rw-r--r--source/blender/blenkernel/intern/packedFile.c614
-rw-r--r--source/blender/blenkernel/intern/property.c269
-rw-r--r--source/blender/blenkernel/intern/sca.c638
-rw-r--r--source/blender/blenkernel/intern/scene.c564
-rw-r--r--source/blender/blenkernel/intern/screen.c57
-rw-r--r--source/blender/blenkernel/intern/script.c71
-rw-r--r--source/blender/blenkernel/intern/softbody.c3420
-rw-r--r--source/blender/blenkernel/intern/sound.c138
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c2540
-rw-r--r--source/blender/blenkernel/intern/text.c2393
-rw-r--r--source/blender/blenkernel/intern/texture.c820
-rw-r--r--source/blender/blenkernel/intern/verse_bitmap_node.c451
-rw-r--r--source/blender/blenkernel/intern/verse_geometry_node.c2101
-rw-r--r--source/blender/blenkernel/intern/verse_method.c523
-rw-r--r--source/blender/blenkernel/intern/verse_node.c750
-rw-r--r--source/blender/blenkernel/intern/verse_object_node.c620
-rw-r--r--source/blender/blenkernel/intern/verse_session.c480
-rw-r--r--source/blender/blenkernel/intern/world.c187
-rw-r--r--source/blender/blenkernel/intern/writeavi.c223
-rw-r--r--source/blender/blenkernel/intern/writeffmpeg.c827
-rw-r--r--source/blender/blenkernel/intern/writeframeserver.c381
-rw-r--r--source/blender/blenlib/BLI_arithb.h385
-rw-r--r--source/blender/blenlib/BLI_blenlib.h406
-rw-r--r--source/blender/blenlib/BLI_boxpack2d.h69
-rw-r--r--source/blender/blenlib/BLI_dynamiclist.h58
-rw-r--r--source/blender/blenlib/BLI_dynstr.h90
-rw-r--r--source/blender/blenlib/BLI_edgehash.h99
-rw-r--r--source/blender/blenlib/BLI_editVert.h190
-rw-r--r--source/blender/blenlib/BLI_ghash.h118
-rw-r--r--source/blender/blenlib/BLI_gsqueue.h96
-rw-r--r--source/blender/blenlib/BLI_heap.h74
-rw-r--r--source/blender/blenlib/BLI_jitter.h40
-rw-r--r--source/blender/blenlib/BLI_linklist.h62
-rw-r--r--source/blender/blenlib/BLI_memarena.h61
-rw-r--r--source/blender/blenlib/BLI_rand.h99
-rw-r--r--source/blender/blenlib/BLI_storage_types.h83
-rw-r--r--source/blender/blenlib/BLI_threads.h54
-rw-r--r--source/blender/blenlib/BLI_vfontdata.h103
-rw-r--r--source/blender/blenlib/BLI_winstuff.h119
-rw-r--r--source/blender/blenlib/CMakeLists.txt56
-rw-r--r--source/blender/blenlib/MTC_matrixops.h165
-rw-r--r--source/blender/blenlib/MTC_vectorops.h61
-rw-r--r--source/blender/blenlib/Makefile37
-rw-r--r--source/blender/blenlib/PIL_dynlib.h55
-rw-r--r--source/blender/blenlib/PIL_time.h62
-rw-r--r--source/blender/blenlib/SConscript26
-rw-r--r--source/blender/blenlib/intern/BLI_callbacks.h44
-rw-r--r--source/blender/blenlib/intern/BLI_dynstr.c118
-rw-r--r--source/blender/blenlib/intern/BLI_fileops.h50
-rw-r--r--source/blender/blenlib/intern/BLI_ghash.c295
-rw-r--r--source/blender/blenlib/intern/BLI_heap.c220
-rw-r--r--source/blender/blenlib/intern/BLI_linklist.c119
-rw-r--r--source/blender/blenlib/intern/BLI_memarena.c96
-rw-r--r--source/blender/blenlib/intern/BLI_scanfill.h41
-rw-r--r--source/blender/blenlib/intern/BLI_storage.h41
-rw-r--r--source/blender/blenlib/intern/BLI_util.h45
-rw-r--r--source/blender/blenlib/intern/Makefile61
-rw-r--r--source/blender/blenlib/intern/arithb.c3672
-rw-r--r--source/blender/blenlib/intern/boxpack2d.c416
-rw-r--r--source/blender/blenlib/intern/dynlib.c343
-rw-r--r--source/blender/blenlib/intern/edgehash.c220
-rw-r--r--source/blender/blenlib/intern/fileops.c364
-rw-r--r--source/blender/blenlib/intern/freetypefont.c634
-rw-r--r--source/blender/blenlib/intern/gsqueue.c122
-rw-r--r--source/blender/blenlib/intern/jitter.c178
-rw-r--r--source/blender/blenlib/intern/matrixops.c441
-rw-r--r--source/blender/blenlib/intern/noise.c1392
-rw-r--r--source/blender/blenlib/intern/psfont.c2126
-rw-r--r--source/blender/blenlib/intern/rand.c192
-rw-r--r--source/blender/blenlib/intern/rct.c171
-rw-r--r--source/blender/blenlib/intern/scanfill.c1056
-rw-r--r--source/blender/blenlib/intern/storage.c540
-rw-r--r--source/blender/blenlib/intern/threads.c221
-rw-r--r--source/blender/blenlib/intern/time.c105
-rw-r--r--source/blender/blenlib/intern/util.c1691
-rw-r--r--source/blender/blenlib/intern/vectorops.c169
-rw-r--r--source/blender/blenlib/intern/winstuff.c209
-rw-r--r--source/blender/blenloader/BLO_genfile.h38
-rw-r--r--source/blender/blenloader/BLO_readfile.h250
-rw-r--r--source/blender/blenloader/BLO_soundfile.h44
-rw-r--r--source/blender/blenloader/BLO_sys_types.h102
-rw-r--r--source/blender/blenloader/BLO_undofile.h58
-rw-r--r--source/blender/blenloader/BLO_writefile.h44
-rw-r--r--source/blender/blenloader/CMakeLists.txt46
-rw-r--r--source/blender/blenloader/Makefile37
-rw-r--r--source/blender/blenloader/SConscript18
-rw-r--r--source/blender/blenloader/intern/Makefile76
-rw-r--r--source/blender/blenloader/intern/genfile.c1102
-rw-r--r--source/blender/blenloader/intern/genfile.h49
-rw-r--r--source/blender/blenloader/intern/readblenentry.c456
-rw-r--r--source/blender/blenloader/intern/readfile.c8134
-rw-r--r--source/blender/blenloader/intern/readfile.h127
-rw-r--r--source/blender/blenloader/intern/undofile.c146
-rw-r--r--source/blender/blenloader/intern/writefile.c2202
-rw-r--r--source/blender/blenpluginapi/CMakeLists.txt42
-rw-r--r--source/blender/blenpluginapi/Makefile37
-rw-r--r--source/blender/blenpluginapi/SConscript14
-rw-r--r--source/blender/blenpluginapi/documentation.h72
-rw-r--r--source/blender/blenpluginapi/externdef.h43
-rw-r--r--source/blender/blenpluginapi/floatpatch.h90
-rw-r--r--source/blender/blenpluginapi/iff.h215
-rw-r--r--source/blender/blenpluginapi/intern/Makefile57
-rw-r--r--source/blender/blenpluginapi/intern/pluginapi.c365
-rw-r--r--source/blender/blenpluginapi/plugin.DEF40
-rw-r--r--source/blender/blenpluginapi/plugin.h103
-rw-r--r--source/blender/blenpluginapi/util.h100
-rw-r--r--source/blender/ftfont/CMakeLists.txt46
-rw-r--r--source/blender/ftfont/FTF_Api.h166
-rw-r--r--source/blender/ftfont/FTF_Settings.h49
-rw-r--r--source/blender/ftfont/Makefile37
-rw-r--r--source/blender/ftfont/SConscript16
-rw-r--r--source/blender/ftfont/intern/FTF_Api.cpp208
-rw-r--r--source/blender/ftfont/intern/FTF_TTFont.cpp448
-rw-r--r--source/blender/ftfont/intern/FTF_TTFont.h139
-rw-r--r--source/blender/ftfont/intern/Makefile59
-rw-r--r--source/blender/imbuf/CMakeLists.txt61
-rw-r--r--source/blender/imbuf/IMB_imbuf.h583
-rw-r--r--source/blender/imbuf/IMB_imbuf_types.h242
-rw-r--r--source/blender/imbuf/IMB_thumbs.h74
-rw-r--r--source/blender/imbuf/Makefile37
-rw-r--r--source/blender/imbuf/SConscript34
-rw-r--r--source/blender/imbuf/intern/IMB_allocimbuf.h59
-rw-r--r--source/blender/imbuf/intern/IMB_amiga.h50
-rw-r--r--source/blender/imbuf/intern/IMB_anim.h193
-rw-r--r--source/blender/imbuf/intern/IMB_anim5.h20
-rw-r--r--source/blender/imbuf/intern/IMB_bitplanes.h50
-rw-r--r--source/blender/imbuf/intern/IMB_bmp.h50
-rw-r--r--source/blender/imbuf/intern/IMB_cmap.h49
-rw-r--r--source/blender/imbuf/intern/IMB_divers.h48
-rw-r--r--source/blender/imbuf/intern/IMB_dpxcineon.h47
-rw-r--r--source/blender/imbuf/intern/IMB_filter.h48
-rw-r--r--source/blender/imbuf/intern/IMB_ham.h48
-rw-r--r--source/blender/imbuf/intern/IMB_hamx.h50
-rw-r--r--source/blender/imbuf/intern/IMB_iff.h49
-rw-r--r--source/blender/imbuf/intern/IMB_imginfo.h85
-rw-r--r--source/blender/imbuf/intern/IMB_iris.h49
-rw-r--r--source/blender/imbuf/intern/IMB_jpeg.h52
-rw-r--r--source/blender/imbuf/intern/IMB_png.h51
-rw-r--r--source/blender/imbuf/intern/IMB_radiance_hdr.h42
-rw-r--r--source/blender/imbuf/intern/IMB_targa.h51
-rw-r--r--source/blender/imbuf/intern/IMB_tiff.h48
-rw-r--r--source/blender/imbuf/intern/Makefile82
-rw-r--r--source/blender/imbuf/intern/allocimbuf.c573
-rw-r--r--source/blender/imbuf/intern/amiga.c538
-rw-r--r--source/blender/imbuf/intern/anim.c932
-rw-r--r--source/blender/imbuf/intern/anim5.c534
-rw-r--r--source/blender/imbuf/intern/antialias.c469
-rw-r--r--source/blender/imbuf/intern/bitplanes.c359
-rw-r--r--source/blender/imbuf/intern/bmp.c248
-rw-r--r--source/blender/imbuf/intern/cineon/CMakeLists.txt44
-rw-r--r--source/blender/imbuf/intern/cineon/Makefile60
-rw-r--r--source/blender/imbuf/intern/cineon/README8
-rw-r--r--source/blender/imbuf/intern/cineon/SConscript17
-rw-r--r--source/blender/imbuf/intern/cineon/cin_debug_stuff.h1
-rw-r--r--source/blender/imbuf/intern/cineon/cineon_dpx.c193
-rw-r--r--source/blender/imbuf/intern/cineon/cineonfile.h143
-rw-r--r--source/blender/imbuf/intern/cineon/cineonlib.c802
-rw-r--r--source/blender/imbuf/intern/cineon/cineonlib.h68
-rw-r--r--source/blender/imbuf/intern/cineon/dpxfile.h124
-rw-r--r--source/blender/imbuf/intern/cineon/dpxlib.c625
-rw-r--r--source/blender/imbuf/intern/cineon/dpxlib.h56
-rw-r--r--source/blender/imbuf/intern/cineon/logImageCore.c212
-rw-r--r--source/blender/imbuf/intern/cineon/logImageCore.h109
-rw-r--r--source/blender/imbuf/intern/cineon/logImageLib.c158
-rw-r--r--source/blender/imbuf/intern/cineon/logImageLib.h86
-rw-r--r--source/blender/imbuf/intern/cineon/logmemfile.c77
-rw-r--r--source/blender/imbuf/intern/cineon/logmemfile.h29
-rw-r--r--source/blender/imbuf/intern/cmap.c583
-rw-r--r--source/blender/imbuf/intern/cspace.c179
-rw-r--r--source/blender/imbuf/intern/data.c145
-rw-r--r--source/blender/imbuf/intern/dds/BlockDXT.cpp523
-rw-r--r--source/blender/imbuf/intern/dds/BlockDXT.h227
-rw-r--r--source/blender/imbuf/intern/dds/Color.h99
-rw-r--r--source/blender/imbuf/intern/dds/ColorBlock.cpp310
-rw-r--r--source/blender/imbuf/intern/dds/ColorBlock.h115
-rw-r--r--source/blender/imbuf/intern/dds/Common.h44
-rw-r--r--source/blender/imbuf/intern/dds/DirectDrawSurface.cpp924
-rw-r--r--source/blender/imbuf/intern/dds/DirectDrawSurface.h162
-rw-r--r--source/blender/imbuf/intern/dds/Image.cpp132
-rw-r--r--source/blender/imbuf/intern/dds/Image.h103
-rw-r--r--source/blender/imbuf/intern/dds/Makefile63
-rw-r--r--source/blender/imbuf/intern/dds/SConscript19
-rw-r--r--source/blender/imbuf/intern/dds/Stream.cpp99
-rw-r--r--source/blender/imbuf/intern/dds/Stream.h49
-rw-r--r--source/blender/imbuf/intern/dds/dds_api.cpp132
-rw-r--r--source/blender/imbuf/intern/dds/dds_api.h43
-rw-r--r--source/blender/imbuf/intern/dither.c133
-rw-r--r--source/blender/imbuf/intern/divers.c258
-rw-r--r--source/blender/imbuf/intern/dynlibtiff.c197
-rw-r--r--source/blender/imbuf/intern/dynlibtiff.h58
-rw-r--r--source/blender/imbuf/intern/filter.c329
-rwxr-xr-xsource/blender/imbuf/intern/gen_dynlibtiff.py254
-rw-r--r--source/blender/imbuf/intern/ham.c279
-rw-r--r--source/blender/imbuf/intern/hamx.c583
-rw-r--r--source/blender/imbuf/intern/iff.c226
-rw-r--r--source/blender/imbuf/intern/imageprocess.c301
-rw-r--r--source/blender/imbuf/intern/imbuf.h171
-rw-r--r--source/blender/imbuf/intern/imbuf_patch.h114
-rw-r--r--source/blender/imbuf/intern/imginfo.c158
-rw-r--r--source/blender/imbuf/intern/iris.c653
-rw-r--r--source/blender/imbuf/intern/jpeg.c620
-rw-r--r--source/blender/imbuf/intern/matrix.h87
-rw-r--r--source/blender/imbuf/intern/md5.c361
-rw-r--r--source/blender/imbuf/intern/md5.h116
-rw-r--r--source/blender/imbuf/intern/openexr/CMakeLists.txt45
-rw-r--r--source/blender/imbuf/intern/openexr/Makefile48
-rw-r--r--source/blender/imbuf/intern/openexr/SConscript18
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.cpp967
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.h59
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_multi.h93
-rw-r--r--source/blender/imbuf/intern/png.c461
-rw-r--r--source/blender/imbuf/intern/radiance_hdr.c366
-rw-r--r--source/blender/imbuf/intern/readimage.c311
-rw-r--r--source/blender/imbuf/intern/rectop.c601
-rw-r--r--source/blender/imbuf/intern/rotate.c120
-rw-r--r--source/blender/imbuf/intern/scaling.c1267
-rw-r--r--source/blender/imbuf/intern/targa.c647
-rw-r--r--source/blender/imbuf/intern/thumbs.c459
-rw-r--r--source/blender/imbuf/intern/tiff.c547
-rw-r--r--source/blender/imbuf/intern/util.c397
-rw-r--r--source/blender/imbuf/intern/writeimage.c185
-rw-r--r--source/blender/imbuf/readme.txt50
-rw-r--r--source/blender/include/BDR_drawaction.h88
-rw-r--r--source/blender/include/BDR_drawmesh.h84
-rw-r--r--source/blender/include/BDR_drawobject.h82
-rw-r--r--source/blender/include/BDR_editcurve.h102
-rw-r--r--source/blender/include/BDR_editface.h61
-rw-r--r--source/blender/include/BDR_editmball.h56
-rw-r--r--source/blender/include/BDR_editobject.h125
-rw-r--r--source/blender/include/BDR_imagepaint.h44
-rw-r--r--source/blender/include/BDR_sculptmode.h142
-rw-r--r--source/blender/include/BDR_unwrapper.h51
-rw-r--r--source/blender/include/BDR_vpaint.h58
-rw-r--r--source/blender/include/BIF_butspace.h139
-rw-r--r--source/blender/include/BIF_cursors.h103
-rw-r--r--source/blender/include/BIF_drawimage.h74
-rw-r--r--source/blender/include/BIF_drawoops.h41
-rw-r--r--source/blender/include/BIF_drawscene.h35
-rw-r--r--source/blender/include/BIF_drawscript.h41
-rw-r--r--source/blender/include/BIF_drawseq.h46
-rw-r--r--source/blender/include/BIF_drawtext.h54
-rw-r--r--source/blender/include/BIF_editaction.h162
-rw-r--r--source/blender/include/BIF_editarmature.h142
-rw-r--r--source/blender/include/BIF_editconstraint.h72
-rw-r--r--source/blender/include/BIF_editdeform.h74
-rw-r--r--source/blender/include/BIF_editfont.h73
-rw-r--r--source/blender/include/BIF_editgroup.h40
-rw-r--r--source/blender/include/BIF_editkey.h70
-rw-r--r--source/blender/include/BIF_editlattice.h45
-rw-r--r--source/blender/include/BIF_editmesh.h265
-rw-r--r--source/blender/include/BIF_editmode_undo.h59
-rw-r--r--source/blender/include/BIF_editnla.h65
-rw-r--r--source/blender/include/BIF_editoops.h47
-rw-r--r--source/blender/include/BIF_editsca.h41
-rw-r--r--source/blender/include/BIF_editseq.h134
-rw-r--r--source/blender/include/BIF_editsima.h124
-rw-r--r--source/blender/include/BIF_editsound.h87
-rw-r--r--source/blender/include/BIF_editview.h60
-rw-r--r--source/blender/include/BIF_filelist.h87
-rw-r--r--source/blender/include/BIF_fsmenu.h76
-rw-r--r--source/blender/include/BIF_gl.h82
-rw-r--r--source/blender/include/BIF_glutil.h225
-rw-r--r--source/blender/include/BIF_graphics.h59
-rw-r--r--source/blender/include/BIF_imasel.h51
-rw-r--r--source/blender/include/BIF_interface.h331
-rw-r--r--source/blender/include/BIF_interface_icons.h72
-rw-r--r--source/blender/include/BIF_keyval.h39
-rw-r--r--source/blender/include/BIF_language.h69
-rw-r--r--source/blender/include/BIF_mainqueue.h47
-rw-r--r--source/blender/include/BIF_meshlaplacian.h87
-rw-r--r--source/blender/include/BIF_meshtools.h50
-rw-r--r--source/blender/include/BIF_mywindow.h145
-rw-r--r--source/blender/include/BIF_oops.h71
-rw-r--r--source/blender/include/BIF_outliner.h106
-rw-r--r--source/blender/include/BIF_poseobject.h71
-rw-r--r--source/blender/include/BIF_previewrender.h94
-rw-r--r--source/blender/include/BIF_renderwin.h67
-rw-r--r--source/blender/include/BIF_resources.h599
-rw-r--r--source/blender/include/BIF_retopo.h110
-rw-r--r--source/blender/include/BIF_scrarea.h54
-rw-r--r--source/blender/include/BIF_screen.h137
-rw-r--r--source/blender/include/BIF_space.h148
-rw-r--r--source/blender/include/BIF_spacetypes.h67
-rw-r--r--source/blender/include/BIF_tbcallback.h42
-rw-r--r--source/blender/include/BIF_toets.h41
-rw-r--r--source/blender/include/BIF_toolbox.h68
-rw-r--r--source/blender/include/BIF_transform.h108
-rw-r--r--source/blender/include/BIF_usiblender.h54
-rw-r--r--source/blender/include/BIF_verse.h142
-rw-r--r--source/blender/include/BIF_writeavicodec.h44
-rw-r--r--source/blender/include/BIF_writeimage.h45
-rw-r--r--source/blender/include/BIF_writemovie.h41
-rw-r--r--source/blender/include/BPI_script.h71
-rw-r--r--source/blender/include/BSE_drawimasel.h60
-rw-r--r--source/blender/include/BSE_drawipo.h76
-rw-r--r--source/blender/include/BSE_drawnla.h52
-rw-r--r--source/blender/include/BSE_drawoops.h50
-rw-r--r--source/blender/include/BSE_drawview.h88
-rw-r--r--source/blender/include/BSE_edit.h55
-rw-r--r--source/blender/include/BSE_editaction_types.h77
-rw-r--r--source/blender/include/BSE_editipo.h178
-rw-r--r--source/blender/include/BSE_editipo_types.h53
-rw-r--r--source/blender/include/BSE_editnla_types.h41
-rw-r--r--source/blender/include/BSE_filesel.h66
-rw-r--r--source/blender/include/BSE_headerbuttons.h158
-rw-r--r--source/blender/include/BSE_node.h137
-rw-r--r--source/blender/include/BSE_seqaudio.h53
-rw-r--r--source/blender/include/BSE_seqeffects.h96
-rw-r--r--source/blender/include/BSE_seqscopes.h38
-rw-r--r--source/blender/include/BSE_sequence.h85
-rw-r--r--source/blender/include/BSE_time.h71
-rw-r--r--source/blender/include/BSE_trans_types.h90
-rw-r--r--source/blender/include/BSE_types.h69
-rw-r--r--source/blender/include/BSE_view.h97
-rw-r--r--source/blender/include/LOD_DependKludge.h40
-rw-r--r--source/blender/include/blendef.h460
-rw-r--r--source/blender/include/butspace.h723
-rw-r--r--source/blender/include/datatoc.h63
-rw-r--r--source/blender/include/editlattice_ext.h42
-rw-r--r--source/blender/include/editmesh.h110
-rw-r--r--source/blender/include/interface.h236
-rw-r--r--source/blender/include/keyed_functions.h58
-rw-r--r--source/blender/include/license_key.h95
-rw-r--r--source/blender/include/multires.h81
-rw-r--r--source/blender/include/mydevice.h260
-rw-r--r--source/blender/include/nla.h59
-rw-r--r--source/blender/include/objfnt.h105
-rw-r--r--source/blender/include/particle_effect.h47
-rw-r--r--source/blender/include/playanim_ext.h41
-rw-r--r--source/blender/include/transform.h452
-rw-r--r--source/blender/makesdna/CMakeLists.txt30
-rw-r--r--source/blender/makesdna/DNA_ID.h229
-rw-r--r--source/blender/makesdna/DNA_action_types.h225
-rw-r--r--source/blender/makesdna/DNA_actuator_types.h395
-rw-r--r--source/blender/makesdna/DNA_armature_types.h154
-rw-r--r--source/blender/makesdna/DNA_brush_types.h91
-rw-r--r--source/blender/makesdna/DNA_camera_types.h91
-rw-r--r--source/blender/makesdna/DNA_color_types.h81
-rw-r--r--source/blender/makesdna/DNA_constraint_types.h493
-rw-r--r--source/blender/makesdna/DNA_controller_types.h79
-rw-r--r--source/blender/makesdna/DNA_curve_types.h290
-rw-r--r--source/blender/makesdna/DNA_customdata_types.h102
-rw-r--r--source/blender/makesdna/DNA_documentation.h79
-rw-r--r--source/blender/makesdna/DNA_effect_types.h144
-rw-r--r--source/blender/makesdna/DNA_fileglobal_types.h60
-rw-r--r--source/blender/makesdna/DNA_group_types.h65
-rw-r--r--source/blender/makesdna/DNA_image_types.h124
-rw-r--r--source/blender/makesdna/DNA_ipo_types.h401
-rw-r--r--source/blender/makesdna/DNA_key_types.h91
-rw-r--r--source/blender/makesdna/DNA_lamp_types.h174
-rw-r--r--source/blender/makesdna/DNA_lattice_types.h67
-rw-r--r--source/blender/makesdna/DNA_listBase.h64
-rw-r--r--source/blender/makesdna/DNA_material_types.h294
-rw-r--r--source/blender/makesdna/DNA_mesh_types.h139
-rw-r--r--source/blender/makesdna/DNA_meshdata_types.h250
-rw-r--r--source/blender/makesdna/DNA_meta_types.h120
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h366
-rw-r--r--source/blender/makesdna/DNA_nla_types.h105
-rw-r--r--source/blender/makesdna/DNA_node_types.h257
-rw-r--r--source/blender/makesdna/DNA_object_fluidsim.h157
-rw-r--r--source/blender/makesdna/DNA_object_force.h154
-rw-r--r--source/blender/makesdna/DNA_object_types.h442
-rw-r--r--source/blender/makesdna/DNA_oops_types.h86
-rw-r--r--source/blender/makesdna/DNA_packedFile_types.h65
-rw-r--r--source/blender/makesdna/DNA_property_types.h68
-rw-r--r--source/blender/makesdna/DNA_radio_types.h53
-rw-r--r--source/blender/makesdna/DNA_scene_types.h672
-rw-r--r--source/blender/makesdna/DNA_screen_types.h171
-rw-r--r--source/blender/makesdna/DNA_scriptlink_types.h77
-rw-r--r--source/blender/makesdna/DNA_sdna_types.h83
-rw-r--r--source/blender/makesdna/DNA_sensor_types.h253
-rw-r--r--source/blender/makesdna/DNA_sequence_types.h239
-rw-r--r--source/blender/makesdna/DNA_sound_types.h183
-rw-r--r--source/blender/makesdna/DNA_space_types.h649
-rw-r--r--source/blender/makesdna/DNA_text_types.h80
-rw-r--r--source/blender/makesdna/DNA_texture_types.h377
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h288
-rw-r--r--source/blender/makesdna/DNA_vec_types.h91
-rw-r--r--source/blender/makesdna/DNA_vfont_types.h63
-rw-r--r--source/blender/makesdna/DNA_view2d_types.h67
-rw-r--r--source/blender/makesdna/DNA_view3d_types.h212
-rw-r--r--source/blender/makesdna/DNA_wave_types.h53
-rw-r--r--source/blender/makesdna/DNA_world_types.h181
-rw-r--r--source/blender/makesdna/Makefile42
-rw-r--r--source/blender/makesdna/SConscript11
-rw-r--r--source/blender/makesdna/intern/CMakeLists.txt37
-rw-r--r--source/blender/makesdna/intern/Makefile86
-rw-r--r--source/blender/makesdna/intern/SConscript41
-rw-r--r--source/blender/makesdna/intern/makesdna.c1149
-rw-r--r--source/blender/nodes/CMP_node.h105
-rw-r--r--source/blender/nodes/CMakeLists.txt71
-rw-r--r--source/blender/nodes/Makefile37
-rw-r--r--source/blender/nodes/SConscript46
-rw-r--r--source/blender/nodes/SHD_node.h68
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_alphaOver.c128
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_blur.c687
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_brightness.c113
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_channelMatte.c207
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_chromaMatte.c192
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_colorSpill.c144
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_composite.c105
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_crop.c119
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_curves.c206
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_defocus.c855
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_diffMatte.c217
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_dilate.c163
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_displace.c163
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_filter.c235
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_flip.c105
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_gamma.c91
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_glare.c498
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_hueSatVal.c122
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_idMask.c104
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_image.c352
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_invert.c134
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_lensdist.c192
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_lummaMatte.c122
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_mapUV.c149
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_mapValue.c101
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_math.c187
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_mixrgb.c96
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_normal.c97
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_normalize.c113
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_outputFile.c112
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_rgb.c64
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_rotate.c150
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_scale.c125
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_sepcombHSVA.c191
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_sepcombRGBA.c167
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_sepcombYCCA.c197
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_sepcombYUVA.c190
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_setalpha.c89
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_splitViewer.c164
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_texture.c149
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_tonemap.c173
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_translate.c75
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_valToRgb.c157
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_value.c61
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_vecBlur.c110
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_viewer.c144
-rw-r--r--source/blender/nodes/intern/CMP_nodes/CMP_zcombine.c155
-rw-r--r--source/blender/nodes/intern/CMP_nodes/Makefile47
-rw-r--r--source/blender/nodes/intern/CMP_util.c1166
-rw-r--r--source/blender/nodes/intern/CMP_util.h221
-rw-r--r--source/blender/nodes/intern/Makefile47
-rw-r--r--source/blender/nodes/intern/SHD_nodes/Makefile47
-rw-r--r--source/blender/nodes/intern/SHD_nodes/SHD_camera.c68
-rw-r--r--source/blender/nodes/intern/SHD_nodes/SHD_curves.c119
-rw-r--r--source/blender/nodes/intern/SHD_nodes/SHD_dynamic.c247
-rw-r--r--source/blender/nodes/intern/SHD_nodes/SHD_geom.c144
-rw-r--r--source/blender/nodes/intern/SHD_nodes/SHD_hueSatVal.c94
-rw-r--r--source/blender/nodes/intern/SHD_nodes/SHD_invert.c83
-rw-r--r--source/blender/nodes/intern/SHD_nodes/SHD_mapping.c89
-rw-r--r--source/blender/nodes/intern/SHD_nodes/SHD_material.c224
-rw-r--r--source/blender/nodes/intern/SHD_nodes/SHD_math.c197
-rw-r--r--source/blender/nodes/intern/SHD_nodes/SHD_mixRgb.c79
-rw-r--r--source/blender/nodes/intern/SHD_nodes/SHD_normal.c76
-rw-r--r--source/blender/nodes/intern/SHD_nodes/SHD_output.c82
-rw-r--r--source/blender/nodes/intern/SHD_nodes/SHD_rgb.c61
-rw-r--r--source/blender/nodes/intern/SHD_nodes/SHD_sepcombRGB.c105
-rw-r--r--source/blender/nodes/intern/SHD_nodes/SHD_squeeze.c73
-rw-r--r--source/blender/nodes/intern/SHD_nodes/SHD_texture.c130
-rw-r--r--source/blender/nodes/intern/SHD_nodes/SHD_valToRgb.c116
-rw-r--r--source/blender/nodes/intern/SHD_nodes/SHD_value.c64
-rw-r--r--source/blender/nodes/intern/SHD_nodes/SHD_vectMath.c118
-rw-r--r--source/blender/nodes/intern/SHD_util.c208
-rw-r--r--source/blender/nodes/intern/SHD_util.h140
-rw-r--r--source/blender/nodes/intern/node_util.c52
-rw-r--r--source/blender/nodes/intern/node_util.h42
-rw-r--r--source/blender/python/BPY_extern.h136
-rw-r--r--source/blender/python/BPY_interface.c2663
-rw-r--r--source/blender/python/BPY_menus.c1118
-rw-r--r--source/blender/python/BPY_menus.h128
-rw-r--r--source/blender/python/CMakeLists.txt57
-rw-r--r--source/blender/python/Makefile37
-rw-r--r--source/blender/python/SConscript26
-rw-r--r--source/blender/python/api2_2x/Armature.c1490
-rw-r--r--source/blender/python/api2_2x/Armature.h70
-rw-r--r--source/blender/python/api2_2x/BGL.c1590
-rw-r--r--source/blender/python/api2_2x/BGL.h333
-rw-r--r--source/blender/python/api2_2x/BezTriple.c716
-rw-r--r--source/blender/python/api2_2x/BezTriple.h64
-rw-r--r--source/blender/python/api2_2x/Blender.c982
-rw-r--r--source/blender/python/api2_2x/Blender.h41
-rw-r--r--source/blender/python/api2_2x/Bone.c1425
-rw-r--r--source/blender/python/api2_2x/Bone.h76
-rw-r--r--source/blender/python/api2_2x/Camera.c1057
-rw-r--r--source/blender/python/api2_2x/Camera.h82
-rw-r--r--source/blender/python/api2_2x/Constraint.c2678
-rw-r--r--source/blender/python/api2_2x/Constraint.h76
-rw-r--r--source/blender/python/api2_2x/CurNurb.c1078
-rw-r--r--source/blender/python/api2_2x/CurNurb.h70
-rw-r--r--source/blender/python/api2_2x/Curve.c1659
-rw-r--r--source/blender/python/api2_2x/Curve.h78
-rw-r--r--source/blender/python/api2_2x/Draw.c2210
-rw-r--r--source/blender/python/api2_2x/Draw.h77
-rw-r--r--source/blender/python/api2_2x/EXPP_interface.c230
-rw-r--r--source/blender/python/api2_2x/EXPP_interface.h56
-rw-r--r--source/blender/python/api2_2x/Effect.c1575
-rw-r--r--source/blender/python/api2_2x/Effect.h58
-rw-r--r--source/blender/python/api2_2x/Font.c403
-rw-r--r--source/blender/python/api2_2x/Font.h53
-rw-r--r--source/blender/python/api2_2x/Geometry.c433
-rw-r--r--source/blender/python/api2_2x/Geometry.h42
-rw-r--r--source/blender/python/api2_2x/Group.c813
-rw-r--r--source/blender/python/api2_2x/Group.h66
-rw-r--r--source/blender/python/api2_2x/IDProp.c895
-rw-r--r--source/blender/python/api2_2x/IDProp.h61
-rw-r--r--source/blender/python/api2_2x/Image.c1339
-rw-r--r--source/blender/python/api2_2x/Image.h60
-rw-r--r--source/blender/python/api2_2x/Ipo.c1842
-rw-r--r--source/blender/python/api2_2x/Ipo.h63
-rw-r--r--source/blender/python/api2_2x/Ipocurve.c1080
-rw-r--r--source/blender/python/api2_2x/Ipocurve.h58
-rw-r--r--source/blender/python/api2_2x/Key.c683
-rw-r--r--source/blender/python/api2_2x/Key.h68
-rw-r--r--source/blender/python/api2_2x/Lamp.c1570
-rw-r--r--source/blender/python/api2_2x/Lamp.h61
-rw-r--r--source/blender/python/api2_2x/Lattice.c813
-rw-r--r--source/blender/python/api2_2x/Lattice.h60
-rw-r--r--source/blender/python/api2_2x/Library.c1192
-rw-r--r--source/blender/python/api2_2x/Library.h78
-rw-r--r--source/blender/python/api2_2x/MTex.c827
-rw-r--r--source/blender/python/api2_2x/MTex.h63
-rw-r--r--source/blender/python/api2_2x/Makefile64
-rw-r--r--source/blender/python/api2_2x/Material.c3048
-rw-r--r--source/blender/python/api2_2x/Material.h78
-rw-r--r--source/blender/python/api2_2x/Mathutils.c1804
-rw-r--r--source/blender/python/api2_2x/Mathutils.h85
-rw-r--r--source/blender/python/api2_2x/Mesh.c8648
-rw-r--r--source/blender/python/api2_2x/Mesh.h127
-rw-r--r--source/blender/python/api2_2x/Metaball.c1189
-rw-r--r--source/blender/python/api2_2x/Metaball.h81
-rw-r--r--source/blender/python/api2_2x/Modifier.c1693
-rw-r--r--source/blender/python/api2_2x/Modifier.h72
-rw-r--r--source/blender/python/api2_2x/NLA.c1590
-rw-r--r--source/blender/python/api2_2x/NLA.h77
-rw-r--r--source/blender/python/api2_2x/NMesh.c4164
-rw-r--r--source/blender/python/api2_2x/NMesh.h157
-rw-r--r--source/blender/python/api2_2x/Node.c1213
-rw-r--r--source/blender/python/api2_2x/Node.h91
-rw-r--r--source/blender/python/api2_2x/Noise.c713
-rw-r--r--source/blender/python/api2_2x/Object.c5942
-rw-r--r--source/blender/python/api2_2x/Object.h62
-rw-r--r--source/blender/python/api2_2x/Particle.c1040
-rw-r--r--source/blender/python/api2_2x/Particle.h67
-rw-r--r--source/blender/python/api2_2x/Pose.c1395
-rw-r--r--source/blender/python/api2_2x/Pose.h71
-rw-r--r--source/blender/python/api2_2x/Registry.c245
-rw-r--r--source/blender/python/api2_2x/Registry.h50
-rw-r--r--source/blender/python/api2_2x/Scene.c1839
-rw-r--r--source/blender/python/api2_2x/Scene.h70
-rw-r--r--source/blender/python/api2_2x/Sound.c607
-rw-r--r--source/blender/python/api2_2x/Sound.h57
-rw-r--r--source/blender/python/api2_2x/SurfNurb.c857
-rw-r--r--source/blender/python/api2_2x/SurfNurb.h68
-rw-r--r--source/blender/python/api2_2x/Sys.c400
-rw-r--r--source/blender/python/api2_2x/Sys.h40
-rw-r--r--source/blender/python/api2_2x/Text.c576
-rw-r--r--source/blender/python/api2_2x/Text.h52
-rw-r--r--source/blender/python/api2_2x/Text3d.c1206
-rw-r--r--source/blender/python/api2_2x/Text3d.h56
-rw-r--r--source/blender/python/api2_2x/Texture.c2501
-rw-r--r--source/blender/python/api2_2x/Texture.h64
-rw-r--r--source/blender/python/api2_2x/Types.c262
-rw-r--r--source/blender/python/api2_2x/Types.h41
-rw-r--r--source/blender/python/api2_2x/Window.c1526
-rw-r--r--source/blender/python/api2_2x/Window.h43
-rw-r--r--source/blender/python/api2_2x/World.c1034
-rw-r--r--source/blender/python/api2_2x/World.h58
-rw-r--r--source/blender/python/api2_2x/bpy.c86
-rw-r--r--source/blender/python/api2_2x/bpy.h41
-rw-r--r--source/blender/python/api2_2x/bpy_config.c414
-rw-r--r--source/blender/python/api2_2x/bpy_config.h52
-rw-r--r--source/blender/python/api2_2x/bpy_data.c817
-rw-r--r--source/blender/python/api2_2x/bpy_data.h55
-rw-r--r--source/blender/python/api2_2x/bpy_types.h93
-rw-r--r--source/blender/python/api2_2x/charRGBA.c475
-rw-r--r--source/blender/python/api2_2x/charRGBA.h59
-rw-r--r--source/blender/python/api2_2x/constant.c269
-rw-r--r--source/blender/python/api2_2x/constant.h53
-rw-r--r--source/blender/python/api2_2x/doc/API_intro.py247
-rw-r--r--source/blender/python/api2_2x/doc/API_related.py564
-rw-r--r--source/blender/python/api2_2x/doc/Armature.py368
-rw-r--r--source/blender/python/api2_2x/doc/BGL.py1778
-rw-r--r--source/blender/python/api2_2x/doc/BezTriple.py96
-rw-r--r--source/blender/python/api2_2x/doc/Blender.py238
-rw-r--r--source/blender/python/api2_2x/doc/Blender_API.css44
-rw-r--r--source/blender/python/api2_2x/doc/Bpy.py25
-rw-r--r--source/blender/python/api2_2x/doc/Bpy_config.py38
-rw-r--r--source/blender/python/api2_2x/doc/Bpy_data.py281
-rw-r--r--source/blender/python/api2_2x/doc/Camera.py257
-rw-r--r--source/blender/python/api2_2x/doc/Constraint.py248
-rw-r--r--source/blender/python/api2_2x/doc/Curve.py721
-rw-r--r--source/blender/python/api2_2x/doc/Curvedoc.txt105
-rw-r--r--source/blender/python/api2_2x/doc/Draw.py880
-rw-r--r--source/blender/python/api2_2x/doc/Effect.py590
-rw-r--r--source/blender/python/api2_2x/doc/Effectdoc.txt257
-rw-r--r--source/blender/python/api2_2x/doc/Font.py69
-rw-r--r--source/blender/python/api2_2x/doc/Geometry.py97
-rw-r--r--source/blender/python/api2_2x/doc/Group.py127
-rw-r--r--source/blender/python/api2_2x/doc/IDProp.py130
-rw-r--r--source/blender/python/api2_2x/doc/Image.py374
-rw-r--r--source/blender/python/api2_2x/doc/Ipo.py437
-rw-r--r--source/blender/python/api2_2x/doc/IpoCurve.py226
-rw-r--r--source/blender/python/api2_2x/doc/Ipodoc.txt66
-rw-r--r--source/blender/python/api2_2x/doc/Key.py124
-rw-r--r--source/blender/python/api2_2x/doc/Lamp.py521
-rw-r--r--source/blender/python/api2_2x/doc/Lattice.py209
-rw-r--r--source/blender/python/api2_2x/doc/LibData.py137
-rw-r--r--source/blender/python/api2_2x/doc/Library.py114
-rw-r--r--source/blender/python/api2_2x/doc/Material.py1061
-rw-r--r--source/blender/python/api2_2x/doc/Mathutils.py864
-rw-r--r--source/blender/python/api2_2x/doc/Mesh.py1210
-rw-r--r--source/blender/python/api2_2x/doc/MeshPrimitives.py157
-rw-r--r--source/blender/python/api2_2x/doc/Metaball.py246
-rw-r--r--source/blender/python/api2_2x/doc/Metaballdoc.txt58
-rw-r--r--source/blender/python/api2_2x/doc/Modifier.py225
-rw-r--r--source/blender/python/api2_2x/doc/NLA.py245
-rw-r--r--source/blender/python/api2_2x/doc/NMesh.py823
-rw-r--r--source/blender/python/api2_2x/doc/Noise.py300
-rw-r--r--source/blender/python/api2_2x/doc/Object.py1754
-rw-r--r--source/blender/python/api2_2x/doc/Pose.py245
-rw-r--r--source/blender/python/api2_2x/doc/Radio.py351
-rw-r--r--source/blender/python/api2_2x/doc/Registry.py122
-rw-r--r--source/blender/python/api2_2x/doc/Render.py1192
-rw-r--r--source/blender/python/api2_2x/doc/Scene.py392
-rw-r--r--source/blender/python/api2_2x/doc/Sound.py147
-rw-r--r--source/blender/python/api2_2x/doc/Sys.py167
-rw-r--r--source/blender/python/api2_2x/doc/Text.py129
-rw-r--r--source/blender/python/api2_2x/doc/Text3d.py302
-rw-r--r--source/blender/python/api2_2x/doc/Texture.py555
-rw-r--r--source/blender/python/api2_2x/doc/Theme.py211
-rw-r--r--source/blender/python/api2_2x/doc/TimeLine.py80
-rw-r--r--source/blender/python/api2_2x/doc/Types.py70
-rw-r--r--source/blender/python/api2_2x/doc/Window.py524
-rw-r--r--source/blender/python/api2_2x/doc/World.py351
-rw-r--r--source/blender/python/api2_2x/doc/Worlddoc.txt55
-rw-r--r--source/blender/python/api2_2x/doc/epy_docgen-3.sh12
-rw-r--r--source/blender/python/api2_2x/doc/epy_docgen.sh12
-rw-r--r--source/blender/python/api2_2x/doc/id_generics.py30
-rw-r--r--source/blender/python/api2_2x/doc/testbgl.py45
-rw-r--r--source/blender/python/api2_2x/doc/testcamera.py137
-rw-r--r--source/blender/python/api2_2x/doc/testcurve.py20
-rw-r--r--source/blender/python/api2_2x/doc/testeffect.py65
-rw-r--r--source/blender/python/api2_2x/doc/testipo.py24
-rw-r--r--source/blender/python/api2_2x/doc/testmball.py37
-rw-r--r--source/blender/python/api2_2x/doc/testtext.py29
-rw-r--r--source/blender/python/api2_2x/doc/testworld.py21
-rw-r--r--source/blender/python/api2_2x/euler.c502
-rw-r--r--source/blender/python/api2_2x/euler.h67
-rw-r--r--source/blender/python/api2_2x/gen_library.c332
-rw-r--r--source/blender/python/api2_2x/gen_library.h94
-rw-r--r--source/blender/python/api2_2x/gen_utils.c948
-rw-r--r--source/blender/python/api2_2x/gen_utils.h176
-rw-r--r--source/blender/python/api2_2x/logic.c529
-rw-r--r--source/blender/python/api2_2x/logic.h61
-rw-r--r--source/blender/python/api2_2x/matrix.c975
-rw-r--r--source/blender/python/api2_2x/matrix.h80
-rw-r--r--source/blender/python/api2_2x/meshPrimitive.c279
-rw-r--r--source/blender/python/api2_2x/meshPrimitive.h46
-rw-r--r--source/blender/python/api2_2x/modules.h65
-rw-r--r--source/blender/python/api2_2x/point.c526
-rw-r--r--source/blender/python/api2_2x/point.h67
-rw-r--r--source/blender/python/api2_2x/quat.c668
-rw-r--r--source/blender/python/api2_2x/quat.h73
-rw-r--r--source/blender/python/api2_2x/rgbTuple.c420
-rw-r--r--source/blender/python/api2_2x/rgbTuple.h56
-rw-r--r--source/blender/python/api2_2x/sceneRadio.c893
-rw-r--r--source/blender/python/api2_2x/sceneRadio.h51
-rw-r--r--source/blender/python/api2_2x/sceneRender.c3216
-rw-r--r--source/blender/python/api2_2x/sceneRender.h52
-rw-r--r--source/blender/python/api2_2x/sceneSequence.c1133
-rw-r--r--source/blender/python/api2_2x/sceneSequence.h83
-rw-r--r--source/blender/python/api2_2x/sceneTimeLine.c319
-rw-r--r--source/blender/python/api2_2x/sceneTimeLine.h58
-rw-r--r--source/blender/python/api2_2x/vector.c1264
-rw-r--r--source/blender/python/api2_2x/vector.h61
-rw-r--r--source/blender/python/api2_2x/windowTheme.c828
-rw-r--r--source/blender/python/api2_2x/windowTheme.h60
-rw-r--r--source/blender/quicktime/CMakeLists.txt58
-rw-r--r--source/blender/quicktime/Makefile40
-rw-r--r--source/blender/quicktime/SConscript29
-rw-r--r--source/blender/quicktime/apple/Makefile60
-rw-r--r--source/blender/quicktime/apple/quicktime_export.c683
-rw-r--r--source/blender/quicktime/apple/quicktime_import.c779
-rw-r--r--source/blender/quicktime/quicktime_export.h52
-rw-r--r--source/blender/quicktime/quicktime_import.h105
-rw-r--r--source/blender/radiosity/CMakeLists.txt39
-rw-r--r--source/blender/radiosity/Makefile37
-rw-r--r--source/blender/radiosity/SConscript12
-rw-r--r--source/blender/radiosity/extern/include/radio.h174
-rw-r--r--source/blender/radiosity/extern/include/radio_types.h175
-rw-r--r--source/blender/radiosity/intern/Makefile37
-rw-r--r--source/blender/radiosity/intern/source/Makefile56
-rw-r--r--source/blender/radiosity/intern/source/raddisplay.c490
-rw-r--r--source/blender/radiosity/intern/source/radfactors.c946
-rw-r--r--source/blender/radiosity/intern/source/radio.c397
-rw-r--r--source/blender/radiosity/intern/source/radnode.c1106
-rw-r--r--source/blender/radiosity/intern/source/radpostprocess.c832
-rw-r--r--source/blender/radiosity/intern/source/radpreprocess.c842
-rw-r--r--source/blender/radiosity/intern/source/radrender.c501
-rw-r--r--source/blender/readblenfile/BLO_readblenfile.h84
-rw-r--r--source/blender/readblenfile/CMakeLists.txt37
-rw-r--r--source/blender/readblenfile/Makefile37
-rw-r--r--source/blender/readblenfile/SConscript8
-rw-r--r--source/blender/readblenfile/intern/BLO_readblenfile.c175
-rw-r--r--source/blender/readblenfile/intern/Makefile50
-rw-r--r--source/blender/readblenfile/stub/BLO_readblenfileSTUB.c96
-rw-r--r--source/blender/readblenfile/stub/Makefile47
-rw-r--r--source/blender/readblenfile/test/Makefile49
-rw-r--r--source/blender/readblenfile/test/test.c58
-rw-r--r--source/blender/render/CMakeLists.txt56
-rw-r--r--source/blender/render/Makefile37
-rw-r--r--source/blender/render/SConscript31
-rw-r--r--source/blender/render/extern/include/RE_pipeline.h217
-rw-r--r--source/blender/render/extern/include/RE_raytrace.h90
-rw-r--r--source/blender/render/extern/include/RE_render_ext.h57
-rw-r--r--source/blender/render/extern/include/RE_shader_ext.h182
-rw-r--r--source/blender/render/intern/Makefile37
-rw-r--r--source/blender/render/intern/include/envmap.h51
-rw-r--r--source/blender/render/intern/include/gammaCorrectionTables.h54
-rw-r--r--source/blender/render/intern/include/initrender.h52
-rw-r--r--source/blender/render/intern/include/pixelblending.h68
-rw-r--r--source/blender/render/intern/include/pixelshading.h62
-rw-r--r--source/blender/render/intern/include/render_types.h420
-rw-r--r--source/blender/render/intern/include/rendercore.h108
-rw-r--r--source/blender/render/intern/include/renderdatabase.h116
-rw-r--r--source/blender/render/intern/include/renderpipeline.h43
-rw-r--r--source/blender/render/intern/include/shadbuf.h110
-rw-r--r--source/blender/render/intern/include/shading.h83
-rw-r--r--source/blender/render/intern/include/sss.h65
-rw-r--r--source/blender/render/intern/include/texture.h74
-rw-r--r--source/blender/render/intern/include/zbuf.h111
-rw-r--r--source/blender/render/intern/source/Makefile68
-rw-r--r--source/blender/render/intern/source/convertblender.c4336
-rw-r--r--source/blender/render/intern/source/envmap.c719
-rw-r--r--source/blender/render/intern/source/gammaCorrectionTables.c148
-rw-r--r--source/blender/render/intern/source/imagetexture.c972
-rw-r--r--source/blender/render/intern/source/initrender.c680
-rw-r--r--source/blender/render/intern/source/pipeline.c2402
-rw-r--r--source/blender/render/intern/source/pixelblending.c288
-rw-r--r--source/blender/render/intern/source/pixelshading.c571
-rw-r--r--source/blender/render/intern/source/rayshade.c2025
-rw-r--r--source/blender/render/intern/source/raytrace.c1353
-rw-r--r--source/blender/render/intern/source/rendercore.c1961
-rw-r--r--source/blender/render/intern/source/renderdatabase.c938
-rw-r--r--source/blender/render/intern/source/shadbuf.c2050
-rw-r--r--source/blender/render/intern/source/shadeinput.c1016
-rw-r--r--source/blender/render/intern/source/shadeoutput.c1653
-rw-r--r--source/blender/render/intern/source/sss.c1024
-rw-r--r--source/blender/render/intern/source/texture.c2455
-rw-r--r--source/blender/render/intern/source/zbuf.c3438
-rw-r--r--source/blender/src/.BCkey1
-rw-r--r--source/blender/src/B.blend.c3076
-rw-r--r--source/blender/src/Bfont.c139
-rw-r--r--source/blender/src/CMakeLists.txt85
-rw-r--r--source/blender/src/Makefile149
-rw-r--r--source/blender/src/SConscript64
-rw-r--r--source/blender/src/bfont.ttf.c5992
-rw-r--r--source/blender/src/blenderbuttons.c2078
-rw-r--r--source/blender/src/booleanops.c566
-rw-r--r--source/blender/src/booleanops_mesh.c296
-rw-r--r--source/blender/src/butspace.c799
-rw-r--r--source/blender/src/buttons_editing.c5624
-rw-r--r--source/blender/src/buttons_logic.c2814
-rw-r--r--source/blender/src/buttons_object.c3546
-rw-r--r--source/blender/src/buttons_scene.c2070
-rw-r--r--source/blender/src/buttons_script.c384
-rw-r--r--source/blender/src/buttons_shading.c4235
-rw-r--r--source/blender/src/cmap.tga.c92
-rw-r--r--source/blender/src/cmovie.tga.c205
-rw-r--r--source/blender/src/cre/license.jpeg.c38
-rw-r--r--source/blender/src/cre/license_key.c197
-rw-r--r--source/blender/src/cursors.c840
-rw-r--r--source/blender/src/drawaction.c1291
-rw-r--r--source/blender/src/drawarmature.c2080
-rw-r--r--source/blender/src/drawdeps.c316
-rw-r--r--source/blender/src/drawimage.c2703
-rw-r--r--source/blender/src/drawimasel.c734
-rw-r--r--source/blender/src/drawipo.c2728
-rw-r--r--source/blender/src/drawmesh.c1220
-rw-r--r--source/blender/src/drawnla.c824
-rw-r--r--source/blender/src/drawnode.c2871
-rw-r--r--source/blender/src/drawobject.c4645
-rw-r--r--source/blender/src/drawoops.c521
-rw-r--r--source/blender/src/drawscene.c142
-rw-r--r--source/blender/src/drawscript.c153
-rw-r--r--source/blender/src/drawseq.c1487
-rw-r--r--source/blender/src/drawsound.c241
-rw-r--r--source/blender/src/drawtext.c2175
-rw-r--r--source/blender/src/drawtime.c421
-rw-r--r--source/blender/src/drawview.c3465
-rw-r--r--source/blender/src/edit.c1889
-rw-r--r--source/blender/src/editaction.c2916
-rw-r--r--source/blender/src/editarmature.c3144
-rw-r--r--source/blender/src/editconstraint.c1103
-rw-r--r--source/blender/src/editcurve.c4435
-rw-r--r--source/blender/src/editdeform.c897
-rw-r--r--source/blender/src/editface.c1437
-rw-r--r--source/blender/src/editfont.c1289
-rw-r--r--source/blender/src/editgroup.c186
-rw-r--r--source/blender/src/editimasel.c1137
-rw-r--r--source/blender/src/editipo.c5625
-rw-r--r--source/blender/src/editipo_lib.c390
-rw-r--r--source/blender/src/editipo_mods.c1356
-rw-r--r--source/blender/src/editkey.c773
-rw-r--r--source/blender/src/editlattice.c327
-rw-r--r--source/blender/src/editmball.c533
-rw-r--r--source/blender/src/editmesh.c2205
-rw-r--r--source/blender/src/editmesh_add.c1349
-rw-r--r--source/blender/src/editmesh_lib.c2207
-rw-r--r--source/blender/src/editmesh_loop.c954
-rw-r--r--source/blender/src/editmesh_mods.c4132
-rw-r--r--source/blender/src/editmesh_tools.c6800
-rw-r--r--source/blender/src/editmode_undo.c348
-rw-r--r--source/blender/src/editnla.c2029
-rw-r--r--source/blender/src/editnode.c2244
-rw-r--r--source/blender/src/editobject.c5554
-rw-r--r--source/blender/src/editoops.c675
-rw-r--r--source/blender/src/editscreen.c3819
-rw-r--r--source/blender/src/editseq.c3703
-rw-r--r--source/blender/src/editsima.c2343
-rw-r--r--source/blender/src/editsound.c1063
-rw-r--r--source/blender/src/edittime.c1008
-rw-r--r--source/blender/src/editview.c2776
-rw-r--r--source/blender/src/eventdebug.c195
-rw-r--r--source/blender/src/filelist.c1141
-rw-r--r--source/blender/src/filesel.c2597
-rw-r--r--source/blender/src/fluidsim.c1147
-rw-r--r--source/blender/src/fsmenu.c257
-rw-r--r--source/blender/src/ghostwinlay.c835
-rw-r--r--source/blender/src/glutil.c695
-rw-r--r--source/blender/src/hddaudio.c577
-rw-r--r--source/blender/src/header_action.c1240
-rw-r--r--source/blender/src/header_buttonswin.c728
-rw-r--r--source/blender/src/header_filesel.c194
-rw-r--r--source/blender/src/header_image.c1305
-rw-r--r--source/blender/src/header_imasel.c211
-rw-r--r--source/blender/src/header_info.c2119
-rw-r--r--source/blender/src/header_ipo.c1365
-rw-r--r--source/blender/src/header_nla.c562
-rw-r--r--source/blender/src/header_node.c673
-rw-r--r--source/blender/src/header_oops.c578
-rw-r--r--source/blender/src/header_script.c280
-rw-r--r--source/blender/src/header_seq.c727
-rw-r--r--source/blender/src/header_sound.c444
-rw-r--r--source/blender/src/header_text.c821
-rw-r--r--source/blender/src/header_time.c539
-rw-r--r--source/blender/src/header_view3d.c5261
-rw-r--r--source/blender/src/headerbuttons.c2080
-rw-r--r--source/blender/src/imagepaint.c790
-rw-r--r--source/blender/src/imasel.c85
-rw-r--r--source/blender/src/interface.c6684
-rw-r--r--source/blender/src/interface_draw.c2467
-rw-r--r--source/blender/src/interface_icons.c1074
-rw-r--r--source/blender/src/interface_panel.c1950
-rw-r--r--source/blender/src/keyval.c354
-rw-r--r--source/blender/src/language.c453
-rw-r--r--source/blender/src/lorem.c516
-rw-r--r--source/blender/src/mainqueue.c102
-rw-r--r--source/blender/src/meshlaplacian.c1777
-rw-r--r--source/blender/src/meshtools.c980
-rw-r--r--source/blender/src/multires-firstlevel.c410
-rw-r--r--source/blender/src/multires.c1650
-rw-r--r--source/blender/src/mywindow.c744
-rw-r--r--source/blender/src/oops.c1104
-rw-r--r--source/blender/src/outliner.c3640
-rw-r--r--source/blender/src/parametrizer.c4203
-rw-r--r--source/blender/src/parametrizer.h85
-rw-r--r--source/blender/src/parametrizer_intern.h192
-rw-r--r--source/blender/src/playanim.c794
-rw-r--r--source/blender/src/poseobject.c963
-rw-r--r--source/blender/src/preview.blend.c14367
-rw-r--r--source/blender/src/previewrender.c912
-rw-r--r--source/blender/src/prvicons.c436
-rw-r--r--source/blender/src/pub/license_key.c447
-rw-r--r--source/blender/src/renderwin.c1431
-rw-r--r--source/blender/src/resources.c913
-rw-r--r--source/blender/src/retopo.c924
-rw-r--r--source/blender/src/scrarea.c69
-rw-r--r--source/blender/src/screendump.c161
-rw-r--r--source/blender/src/sculptmode-stroke.c279
-rw-r--r--source/blender/src/sculptmode.c2193
-rw-r--r--source/blender/src/seqaudio.c546
-rw-r--r--source/blender/src/seqeffects.c3029
-rw-r--r--source/blender/src/seqscopes.c340
-rw-r--r--source/blender/src/sequence.c1713
-rw-r--r--source/blender/src/space.c6603
-rw-r--r--source/blender/src/spacetypes.c161
-rw-r--r--source/blender/src/splash.jpg.c2483
-rw-r--r--source/blender/src/swapbuffers.c289
-rw-r--r--source/blender/src/toets.c973
-rw-r--r--source/blender/src/toolbox.c2245
-rw-r--r--source/blender/src/transform.c3890
-rw-r--r--source/blender/src/transform_constraints.c1027
-rw-r--r--source/blender/src/transform_conversions.c3242
-rw-r--r--source/blender/src/transform_generics.c1009
-rw-r--r--source/blender/src/transform_manipulator.c1692
-rw-r--r--source/blender/src/transform_numinput.c247
-rw-r--r--source/blender/src/transform_snap.c710
-rw-r--r--source/blender/src/unwrapper.c480
-rw-r--r--source/blender/src/usiblender.c1039
-rw-r--r--source/blender/src/verse_common.c298
-rw-r--r--source/blender/src/verse_image.c343
-rw-r--r--source/blender/src/verse_mesh.c1629
-rw-r--r--source/blender/src/verse_object.c600
-rw-r--r--source/blender/src/view.c1867
-rw-r--r--source/blender/src/vpaint.c1621
-rw-r--r--source/blender/src/winlay.h88
-rw-r--r--source/blender/src/writeavicodec.c835
-rw-r--r--source/blender/src/writeimage.c242
-rw-r--r--source/blender/src/writemovie.c502
-rw-r--r--source/blender/verify/BLO_sign_verify_Header.h83
-rw-r--r--source/blender/verify/BLO_signer_info.h48
-rw-r--r--source/blender/verify/BLO_verify.h79
-rw-r--r--source/blender/verify/Makefile37
-rw-r--r--source/blender/verify/intern/BLO_verify.c427
-rw-r--r--source/blender/verify/intern/Makefile53
-rw-r--r--source/blender/yafray/CMakeLists.txt38
-rw-r--r--source/blender/yafray/Makefile34
-rw-r--r--source/blender/yafray/SConscript9
-rw-r--r--source/blender/yafray/YafRay_Api.h17
-rw-r--r--source/blender/yafray/intern/Makefile46
-rw-r--r--source/blender/yafray/intern/api.cpp16
-rw-r--r--source/blender/yafray/intern/export_File.cpp2058
-rw-r--r--source/blender/yafray/intern/export_File.h34
-rw-r--r--source/blender/yafray/intern/export_Plugin.cpp1981
-rw-r--r--source/blender/yafray/intern/export_Plugin.h78
-rw-r--r--source/blender/yafray/intern/yafexternal.cpp155
-rw-r--r--source/blender/yafray/intern/yafexternal.h186
-rw-r--r--source/blender/yafray/intern/yafray_Render.cpp219
-rw-r--r--source/blender/yafray/intern/yafray_Render.h107
1055 files changed, 591878 insertions, 0 deletions
diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt
new file mode 100644
index 00000000000..fa9199006a8
--- /dev/null
+++ b/source/blender/CMakeLists.txt
@@ -0,0 +1,42 @@
+# $Id$
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2006, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Jacques Beaurain.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+
+SUBDIRS(avi nodes blenkernel blenlib blenloader blenpluginapi imbuf imbuf/intern/cineon makesdna python radiosity readblenfile render src yafray)
+
+IF(WITH_INTERNATIONAL)
+ SUBDIRS(ftfont)
+ENDIF(WITH_INTERNATIONAL)
+
+IF(WITH_OPENEXR)
+ SUBDIRS(imbuf/intern/openexr)
+ENDIF(WITH_OPENEXR)
+
+IF(WITH_QUICKTIME)
+ SUBDIRS(quicktime)
+ENDIF(WITH_QUICKTIME)
diff --git a/source/blender/Makefile b/source/blender/Makefile
new file mode 100644
index 00000000000..c0001495210
--- /dev/null
+++ b/source/blender/Makefile
@@ -0,0 +1,53 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+#
+
+include nan_definitions.mk
+
+DIRS = blenloader readblenfile
+DIRS += avi imbuf render radiosity blenlib blenkernel blenpluginapi
+DIRS += makesdna src yafray
+DIRS += python nodes
+
+ifeq ($(INTERNATIONAL), true)
+ DIRS += ftfont
+endif
+
+ifeq ($(WITH_QUICKTIME), true)
+ DIRS += quicktime
+endif
+
+DIR = $(OCGDIR)/blender
+SOURCEDIR = source/blender
+TESTDIRS = deflate streamglue
+
+include nan_subdirs.mk
diff --git a/source/blender/SConscript b/source/blender/SConscript
new file mode 100644
index 00000000000..56a661238f8
--- /dev/null
+++ b/source/blender/SConscript
@@ -0,0 +1,33 @@
+#!/usr/bin/python
+Import ('env')
+import sys
+
+SConscript(['avi/SConscript',
+ 'blenkernel/SConscript',
+ 'blenlib/SConscript',
+ 'blenloader/SConscript',
+ 'blenpluginapi/SConscript',
+ 'imbuf/SConscript',
+ 'imbuf/intern/cineon/SConscript',
+ 'makesdna/SConscript',
+ 'python/SConscript',
+ 'radiosity/SConscript',
+ 'readblenfile/SConscript',
+ 'render/SConscript',
+ 'src/SConscript',
+ 'nodes/SConscript'])
+
+if env['WITH_BF_YAFRAY'] == 1:
+ SConscript(['yafray/SConscript'])
+
+if env['WITH_BF_INTERNATIONAL'] == 1:
+ SConscript (['ftfont/SConscript'])
+
+if env['WITH_BF_DDS'] == 1:
+ SConscript (['imbuf/intern/dds/SConscript'])
+
+if env['WITH_BF_OPENEXR'] == 1:
+ SConscript (['imbuf/intern/openexr/SConscript'])
+
+if env['WITH_BF_QUICKTIME'] == 1:
+ SConscript (['quicktime/SConscript'])
diff --git a/source/blender/avi/AVI_avi.h b/source/blender/avi/AVI_avi.h
new file mode 100644
index 00000000000..76442d9d55e
--- /dev/null
+++ b/source/blender/avi/AVI_avi.h
@@ -0,0 +1,309 @@
+/**
+ * @mainpage AVI - AVI module external interface
+ *
+ * @section about About the AVI module
+ *
+ * This is external code. It provides avi file import/export and
+ * conversions. It has been adapted to make use of Blender memory
+ * management functions, and because of this it needs module
+ * blenlib. You need to provide this lib when linking with libavi.a .
+ *
+ * @section issues Known issues with AVI
+ *
+ * - avi uses mallocN, freeN from blenlib.
+ * - Not all functions that are used externally are properly
+ * prototyped.
+ *
+ * This header has not been split, since it interleaves type defines
+ * and functions. You would need the types to be able to include the
+ * function headers anyway. And, after all, it is someone else's
+ * code. So we keep it like this.
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ *
+ */
+
+#ifndef __AVI_H__
+#define __AVI_H__
+
+#include <stdio.h> /* for FILE */
+
+typedef struct _AviChunk {
+ int fcc;
+ int size;
+} AviChunk;
+
+typedef struct _AviList {
+ int fcc;
+ int size;
+ int ids;
+} AviList;
+
+typedef struct _AviMainHeader {
+ int fcc;
+ int size;
+ int MicroSecPerFrame; /* MicroSecPerFrame - timing between frames */
+ int MaxBytesPerSec; /* MaxBytesPerSec - approx bps system must handle */
+ int PaddingGranularity;
+ int Flags;
+#define AVIF_HASINDEX 0x00000010 /* had idx1 chunk */
+#define AVIF_MUSTUSEINDEX 0x00000020 /* must use idx1 chunk to determine order */
+#define AVIF_ISINTERLEAVED 0x00000100 /* AVI file is interleaved */
+#define AVIF_TRUSTCKTYPE 0x00000800
+#define AVIF_WASCAPTUREFILE 0x00010000 /* specially allocated used for capturing real time video */
+#define AVIF_COPYRIGHTED 0x00020000 /* contains copyrighted data */
+
+ int TotalFrames;
+ int InitialFrames; /* InitialFrames - initial frame before interleaving */
+ int Streams;
+ int SuggestedBufferSize;
+ int Width;
+ int Height;
+ int Reserved[4];
+} AviMainHeader;
+
+typedef struct _AviStreamHeader {
+ int fcc;
+ int size;
+ int Type;
+#define AVIST_VIDEO FCC("vids")
+#define AVIST_AUDIO FCC("auds")
+#define AVIST_MIDI FCC("mids")
+#define AVIST_TEXT FCC("txts")
+
+ int Handler;
+ int Flags;
+#define AVISF_DISABLED 0x00000001
+#define AVISF_VIDEO_PALCHANGES 0x00010000
+
+ short Priority;
+ short Language;
+ int InitialFrames;
+ int Scale;
+ int Rate;
+ int Start;
+ int Length;
+ int SuggestedBufferSize;
+ int Quality;
+ int SampleSize;
+ short left;
+ short top;
+ short right;
+ short bottom;
+} AviStreamHeader;
+
+typedef struct _AviBitmapInfoHeader {
+ int fcc;
+ int size;
+ int Size;
+ int Width;
+ int Height;
+ short Planes;
+ short BitCount;
+ int Compression;
+ int SizeImage;
+ int XPelsPerMeter;
+ int YPelsPerMeter;
+ int ClrUsed;
+ int ClrImportant;
+} AviBitmapInfoHeader;
+
+typedef struct _AviMJPEGUnknown {
+ int a;
+ int b;
+ int c;
+ int d;
+ int e;
+ int f;
+ int g;
+} AviMJPEGUnknown;
+
+typedef struct _AviIndexEntry {
+ int ChunkId;
+ int Flags;
+#define AVIIF_LIST 0x00000001
+#define AVIIF_KEYFRAME 0x00000010
+#define AVIIF_NO_TIME 0x00000100
+#define AVIIF_COMPRESSOR 0x0FFF0000
+ int Offset;
+ int Size;
+} AviIndexEntry;
+
+typedef struct _AviIndex {
+ int fcc;
+ int size;
+ AviIndexEntry *entrys;
+} AviIndex;
+
+typedef enum {
+ AVI_FORMAT_RGB24, /* The most basic of forms, 3 bytes per pixel, 1 per r, g, b */
+ AVI_FORMAT_RGB32, /* The second most basic of forms, 4 bytes per pixel, 1 per r, g, b, alpha */
+ AVI_FORMAT_AVI_RGB, /* Same as above, but is in the wierd AVI order (bottom to top, left to right) */
+ AVI_FORMAT_MJPEG /* Motion-JPEG */
+} AviFormat;
+
+typedef struct _AviStreamRec {
+ AviStreamHeader sh;
+ void *sf;
+ int sf_size;
+ AviFormat format;
+} AviStreamRec;
+
+typedef struct _AviMovie {
+ FILE *fp;
+
+ int type;
+#define AVI_MOVIE_READ 0
+#define AVI_MOVIE_WRITE 1
+
+ unsigned long size;
+
+ AviMainHeader *header;
+ AviStreamRec *streams;
+ AviIndexEntry *entries;
+ int index_entries;
+
+ int movi_offset;
+ int read_offset;
+ long *offset_table;
+
+ /* Local data goes here */
+ int interlace;
+ int odd_fields;
+} AviMovie;
+
+typedef enum {
+ AVI_ERROR_NONE=0,
+ AVI_ERROR_COMPRESSION,
+ AVI_ERROR_OPEN,
+ AVI_ERROR_READING,
+ AVI_ERROR_WRITING,
+ AVI_ERROR_FORMAT,
+ AVI_ERROR_ALLOC,
+ AVI_ERROR_FOUND,
+ AVI_ERROR_OPTION
+} AviError;
+
+/* belongs to the option-setting function. */
+typedef enum {
+ AVI_OPTION_WIDTH=0,
+ AVI_OPTION_HEIGHT,
+ AVI_OPTION_QUALITY,
+ AVI_OPTION_FRAMERATE
+} AviOption;
+
+/* The offsets that will always stay the same in AVI files we
+ * write... used to seek around to the places where we need to write
+ * the sizes */
+
+#define AVI_RIFF_SOFF 4L
+#define AVI_HDRL_SOFF 16L
+
+/**
+ * This is a sort of MAKE_ID thing. Used in imbuf :( It is used
+ * through options in the AVI header (AviStreamHeader). */
+#define FCC(ch4) (ch4[0] | ch4[1]<<8 | ch4[2]<<16 | ch4[3] << 24)
+
+/**
+ * Test whether this is an avi-format.
+ */
+int AVI_is_avi (char *name);
+
+
+/**
+ * Open a compressed file, decompress it into memory.
+ */
+AviError AVI_open_compress (char *name, AviMovie *movie, int streams, ...);
+
+/**
+ * Finalize a compressed output stream.
+ */
+AviError AVI_close_compress (AviMovie *movie);
+
+/**
+ * Choose a compression option for <movie>. Possible options are
+ * AVI_OPTION_TYPE_MAIN, AVI_OPTION_TYPE_STRH, AVI_OPTION_TYPE_STRF
+ */
+AviError AVI_set_compress_option (AviMovie *movie,
+ int option_type,
+ int stream,
+ AviOption option,
+ void *opt_data);
+/* Hmmm... there should be some explanantion about what these mean */
+/**
+ * Compression option, for use in avi_set_compress_option
+ */
+#define AVI_OPTION_TYPE_MAIN 0
+/**
+ * Compression option, for use in avi_set_compress_option
+ */
+#define AVI_OPTION_TYPE_STRH 1
+/**
+ * Compression option, for use in avi_set_compress_option
+ */
+#define AVI_OPTION_TYPE_STRF 2
+
+/**
+ * Direct the streams <avist_type> to <movie>. Redirect <stream_num>
+ * streams.
+ */
+int AVI_get_stream (AviMovie *movie, int avist_type, int stream_num);
+
+/**
+ * Open a movie stream from file.
+ */
+AviError AVI_open_movie (char *name, AviMovie *movie);
+
+/**
+ * Read a frame from a movie stream.
+ */
+void *AVI_read_frame (AviMovie *movie,
+ AviFormat format,
+ int frame,
+ int stream);
+/**
+ * Close an open movie stream.
+ */
+AviError AVI_close (AviMovie *movie);
+
+/**
+ * Write frames to a movie stream.
+ */
+AviError AVI_write_frame (AviMovie *movie, int frame_num, ...);
+
+/**
+ * Unused but still external
+ */
+AviError AVI_print_error (AviError error);
+void AVI_set_debug (int mode);
+
+#endif /* __AVI_H__ */
+
diff --git a/source/blender/avi/CMakeLists.txt b/source/blender/avi/CMakeLists.txt
new file mode 100644
index 00000000000..0bf69d735ce
--- /dev/null
+++ b/source/blender/avi/CMakeLists.txt
@@ -0,0 +1,38 @@
+# $Id$
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2006, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Jacques Beaurain.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+
+FILE(GLOB SRC intern/*.c)
+
+SET(INC
+ . ../../../intern/guardedalloc
+ ${JPEG_INC}
+)
+
+BLENDERLIB(bf_avi "${SRC}" "${INC}")
+#env.BlenderLib ('bf_avi', sources, Split(incs), [], libtype=['core','player'], priority = [90, 50] )
diff --git a/source/blender/avi/Makefile b/source/blender/avi/Makefile
new file mode 100644
index 00000000000..457eebbb516
--- /dev/null
+++ b/source/blender/avi/Makefile
@@ -0,0 +1,37 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+# Bounces make to subdirectories.
+
+SOURCEDIR = source/blender/avi
+DIRS = intern
+
+include nan_subdirs.mk
diff --git a/source/blender/avi/SConscript b/source/blender/avi/SConscript
new file mode 100644
index 00000000000..91239c66ead
--- /dev/null
+++ b/source/blender/avi/SConscript
@@ -0,0 +1,10 @@
+#!/usr/bin/python
+#Import ('extra_includes')
+Import ('env')
+
+sources = env.Glob('intern/*.c')
+
+incs = '. #/intern/guardedalloc'
+incs += ' ' + env['BF_JPEG_INC']
+
+env.BlenderLib ('bf_avi', sources, Split(incs), [], libtype=['core','player'], priority = [90, 50] )
diff --git a/source/blender/avi/intern/Makefile b/source/blender/avi/intern/Makefile
new file mode 100644
index 00000000000..71e892e3db6
--- /dev/null
+++ b/source/blender/avi/intern/Makefile
@@ -0,0 +1,54 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+#
+
+LIBNAME = avi
+DIR = $(OCGDIR)/blender/$(LIBNAME)
+
+include nan_compile.mk
+
+CFLAGS += $(LEVEL1_C_WARNINGS)
+
+ifeq ($(CPU),$(findstring $(CPU), "powerpc mips sparc"))
+ CPPFLAGS += -DWORDS_BIGENDIAN
+else
+ # alpha i386
+ CPPFLAGS += -DWORDS_LITTLEENDIAN
+endif
+
+# the JPEG library
+CPPFLAGS += -I$(NAN_JPEG)/include
+# path to the guarded memory allocator
+CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
+# our own include
+CPPFLAGS += -I..
+
diff --git a/source/blender/avi/intern/avi.c b/source/blender/avi/intern/avi.c
new file mode 100644
index 00000000000..3ad844bfdc1
--- /dev/null
+++ b/source/blender/avi/intern/avi.c
@@ -0,0 +1,843 @@
+/**
+ * avi.c
+ *
+ * This is external code.
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#include "AVI_avi.h"
+#include "avi_intern.h"
+
+#include "endian.h"
+
+static int AVI_DEBUG=0;
+static char DEBUG_FCC[4];
+
+#define DEBUG(x) if(AVI_DEBUG) printf("AVI DEBUG: " x);
+
+/* local functions */
+char *fcc_to_char (unsigned int fcc);
+char *tcc_to_char (unsigned int tcc);
+
+
+
+/* implemetation */
+
+unsigned int GET_FCC (FILE *fp) {
+ unsigned char tmp[4];
+
+ tmp[0] = getc(fp);
+ tmp[1] = getc(fp);
+ tmp[2] = getc(fp);
+ tmp[3] = getc(fp);
+
+ return FCC (tmp);
+}
+
+unsigned int GET_TCC (FILE *fp) {
+ char tmp[5];
+
+ tmp[0] = getc(fp);
+ tmp[1] = getc(fp);
+ tmp[2] = 0;
+ tmp[3] = 0;
+
+ return FCC (tmp);
+}
+
+char *fcc_to_char (unsigned int fcc) {
+ DEBUG_FCC[0]= (fcc)&0177;
+ DEBUG_FCC[1]= (fcc>>8)&0177;
+ DEBUG_FCC[2]= (fcc>>16)&0177;
+ DEBUG_FCC[3]= (fcc>>24)&0177;
+
+ return DEBUG_FCC;
+}
+
+char *tcc_to_char (unsigned int tcc) {
+ DEBUG_FCC[0]= (tcc)&0177;
+ DEBUG_FCC[1]= (tcc>>8)&0177;
+ DEBUG_FCC[2]= 0;
+ DEBUG_FCC[3]= 0;
+
+ return DEBUG_FCC;
+}
+
+int AVI_get_stream (AviMovie *movie, int avist_type, int stream_num) {
+ int cur_stream;
+
+ if (movie == NULL)
+ return -AVI_ERROR_OPTION;
+
+ for (cur_stream=0; cur_stream < movie->header->Streams; cur_stream++) {
+ if (movie->streams[cur_stream].sh.Type == avist_type) {
+ if (stream_num == 0)
+ return cur_stream;
+ else
+ stream_num--;
+ }
+ }
+
+ return -AVI_ERROR_FOUND;
+}
+
+static int fcc_get_stream (int fcc) {
+ char fccs[4];
+
+ fccs[0] = fcc;
+ fccs[1] = fcc>>8;
+ fccs[2] = fcc>>16;
+ fccs[3] = fcc>>24;
+
+ return 10*(fccs[0]-'0') + (fccs[1]-'0');
+}
+
+static int fcc_is_data (int fcc) {
+ char fccs[4];
+
+ fccs[0] = fcc;
+ fccs[1] = fcc>>8;
+ fccs[2] = fcc>>16;
+ fccs[3] = fcc>>24;
+
+ if (!isdigit (fccs[0]) || !isdigit (fccs[1]) || (fccs[2] != 'd' && fccs[2] != 'w'))
+ return 0;
+ if (fccs[3] != 'b' && fccs[3] != 'c')
+ return 0;
+
+ return 1;
+}
+
+AviError AVI_print_error (AviError in_error) {
+ int error;
+
+ if ((int) in_error < 0)
+ error = -in_error;
+ else
+ error = in_error;
+
+ switch (error) {
+ case AVI_ERROR_NONE:
+ break;
+ case AVI_ERROR_COMPRESSION:
+ printf ("AVI ERROR: compressed in an unsupported format\n");
+ break;
+ case AVI_ERROR_OPEN:
+ printf ("AVI ERROR: could not open file\n");
+ break;
+ case AVI_ERROR_READING:
+ printf ("AVI ERROR: could not read from file\n");
+ break;
+ case AVI_ERROR_WRITING:
+ printf ("AVI ERROR: could not write to file\n");
+ break;
+ case AVI_ERROR_FORMAT:
+ printf ("AVI ERROR: file is in an illegal or unrecognized format\n");
+ break;
+ case AVI_ERROR_ALLOC:
+ printf ("AVI ERROR: error encountered while allocating memory\n");
+ break;
+ case AVI_ERROR_OPTION:
+ printf ("AVI ERROR: program made illegal request\n");
+ break;
+ case AVI_ERROR_FOUND:
+ printf ("AVI ERROR: movie did not contain expected item\n");
+ break;
+ default:
+ break;
+ }
+
+ return in_error;
+}
+
+void AVI_set_debug (int mode) {
+ AVI_DEBUG= mode;
+}
+
+int AVI_is_avi (char *name) {
+ FILE *fp;
+ int ret;
+
+ fp = fopen (name, "rb");
+ if (fp == NULL)
+ return 0;
+
+ if (GET_FCC (fp) != FCC("RIFF") ||
+ !GET_FCC (fp) ||
+ GET_FCC (fp) != FCC("AVI ")) {
+ ret = 0;
+ } else {
+ ret = 1;
+ }
+
+ fclose(fp);
+ return ret;
+}
+
+AviError AVI_open_movie (char *name, AviMovie *movie) {
+ int temp, fcca, size, j;
+
+ DEBUG("opening movie\n");
+
+ memset(movie, 0, sizeof(AviMovie));
+
+ movie->type = AVI_MOVIE_READ;
+ movie->fp = fopen (name, "rb");
+ movie->offset_table = NULL;
+
+ if (movie->fp == NULL)
+ return AVI_ERROR_OPEN;
+
+ if (GET_FCC (movie->fp) != FCC("RIFF") ||
+ !(movie->size = GET_FCC (movie->fp)))
+ return AVI_ERROR_FORMAT;
+
+ movie->header = (AviMainHeader *) MEM_mallocN (sizeof (AviMainHeader), "movieheader");
+
+ if (GET_FCC (movie->fp) != FCC("AVI ") ||
+ GET_FCC (movie->fp) != FCC("LIST") ||
+ !GET_FCC (movie->fp) ||
+ GET_FCC (movie->fp) != FCC("hdrl") ||
+ (movie->header->fcc = GET_FCC (movie->fp)) != FCC("avih") ||
+ !(movie->header->size = GET_FCC (movie->fp))) {
+ DEBUG("bad initial header info\n");
+ return AVI_ERROR_FORMAT;
+ }
+
+ movie->header->MicroSecPerFrame = GET_FCC(movie->fp);
+ movie->header->MaxBytesPerSec = GET_FCC(movie->fp);
+ movie->header->PaddingGranularity = GET_FCC(movie->fp);
+ movie->header->Flags = GET_FCC(movie->fp);
+ movie->header->TotalFrames = GET_FCC(movie->fp);
+ movie->header->InitialFrames = GET_FCC(movie->fp);
+ movie->header->Streams = GET_FCC(movie->fp);
+ movie->header->SuggestedBufferSize = GET_FCC(movie->fp);
+ movie->header->Width = GET_FCC(movie->fp);
+ movie->header->Height = GET_FCC(movie->fp);
+ movie->header->Reserved[0] = GET_FCC(movie->fp);
+ movie->header->Reserved[1] = GET_FCC(movie->fp);
+ movie->header->Reserved[2] = GET_FCC(movie->fp);
+ movie->header->Reserved[3] = GET_FCC(movie->fp);
+
+ fseek (movie->fp, movie->header->size-14*4, SEEK_CUR);
+
+ if (movie->header->Streams < 1) {
+ DEBUG("streams less than 1\n");
+ return AVI_ERROR_FORMAT;
+ }
+
+ movie->streams = (AviStreamRec *) MEM_callocN (sizeof(AviStreamRec) * movie->header->Streams, "moviestreams");
+
+ for (temp=0; temp < movie->header->Streams; temp++) {
+
+ if (GET_FCC(movie->fp) != FCC("LIST") ||
+ !GET_FCC (movie->fp) ||
+ GET_FCC (movie->fp) != FCC ("strl") ||
+ (movie->streams[temp].sh.fcc = GET_FCC (movie->fp)) != FCC ("strh") ||
+ !(movie->streams[temp].sh.size = GET_FCC (movie->fp))) {
+ DEBUG("bad stream header information\n");
+ return AVI_ERROR_FORMAT;
+ }
+
+ movie->streams[temp].sh.Type = GET_FCC (movie->fp);
+ movie->streams[temp].sh.Handler = GET_FCC (movie->fp);
+
+ fcca = movie->streams[temp].sh.Handler;
+
+ if (movie->streams[temp].sh.Type == FCC("vids")) {
+ if (fcca == FCC ("DIB ") ||
+ fcca == FCC ("RGB ") ||
+ fcca == FCC ("rgb ") ||
+ fcca == FCC ("RAW ") ||
+ fcca == 0) {
+ movie->streams[temp].format = AVI_FORMAT_AVI_RGB;
+ } else if (fcca == FCC ("mjpg")||fcca == FCC ("MJPG")) {
+ movie->streams[temp].format = AVI_FORMAT_MJPEG;
+ } else {
+ return AVI_ERROR_COMPRESSION;
+ }
+ }
+
+ movie->streams[temp].sh.Flags = GET_FCC (movie->fp);
+ movie->streams[temp].sh.Priority = GET_TCC (movie->fp);
+ movie->streams[temp].sh.Language = GET_TCC (movie->fp);
+ movie->streams[temp].sh.InitialFrames = GET_FCC (movie->fp);
+ movie->streams[temp].sh.Scale = GET_FCC (movie->fp);
+ movie->streams[temp].sh.Rate = GET_FCC (movie->fp);
+ movie->streams[temp].sh.Start = GET_FCC (movie->fp);
+ movie->streams[temp].sh.Length = GET_FCC (movie->fp);
+ movie->streams[temp].sh.SuggestedBufferSize = GET_FCC (movie->fp);
+ movie->streams[temp].sh.Quality = GET_FCC (movie->fp);
+ movie->streams[temp].sh.SampleSize = GET_FCC (movie->fp);
+ movie->streams[temp].sh.left = GET_TCC (movie->fp);
+ movie->streams[temp].sh.top = GET_TCC (movie->fp);
+ movie->streams[temp].sh.right = GET_TCC (movie->fp);
+ movie->streams[temp].sh.bottom = GET_TCC (movie->fp);
+
+ fseek (movie->fp, movie->streams[temp].sh.size-14*4, SEEK_CUR);
+
+ if (GET_FCC (movie->fp) != FCC("strf")) {
+ DEBUG("no stream format information\n");
+ return AVI_ERROR_FORMAT;
+ }
+
+ movie->streams[temp].sf_size= GET_FCC(movie->fp);
+ if (movie->streams[temp].sh.Type == FCC("vids")) {
+ j = movie->streams[temp].sf_size - (sizeof(AviBitmapInfoHeader) - 8);
+ if (j >= 0) {
+ AviBitmapInfoHeader *bi;
+
+ movie->streams[temp].sf= MEM_mallocN(sizeof(AviBitmapInfoHeader), "streamformat");
+
+ bi= (AviBitmapInfoHeader *) movie->streams[temp].sf;
+
+ bi->fcc= FCC("strf");
+ bi->size= movie->streams[temp].sf_size;
+ bi->Size= GET_FCC(movie->fp);
+ bi->Width= GET_FCC(movie->fp);
+ bi->Height= GET_FCC(movie->fp);
+ bi->Planes= GET_TCC(movie->fp);
+ bi->BitCount= GET_TCC(movie->fp);
+ bi->Compression= GET_FCC(movie->fp);
+ bi->SizeImage= GET_FCC(movie->fp);
+ bi->XPelsPerMeter= GET_FCC(movie->fp);
+ bi->YPelsPerMeter= GET_FCC(movie->fp);
+ bi->ClrUsed= GET_FCC(movie->fp);
+ bi->ClrImportant= GET_FCC(movie->fp);
+
+ fcca = bi->Compression;
+
+ if ( movie->streams[temp].format ==
+ AVI_FORMAT_AVI_RGB) {
+ if (fcca == FCC ("DIB ") ||
+ fcca == FCC ("RGB ") ||
+ fcca == FCC ("rgb ") ||
+ fcca == FCC ("RAW ") ||
+ fcca == 0 ) {
+ } else if ( fcca == FCC ("mjpg") ||
+ fcca == FCC ("MJPG")) {
+ movie->streams[temp].format = AVI_FORMAT_MJPEG;
+ } else {
+ return AVI_ERROR_COMPRESSION;
+ }
+ }
+
+ }
+ if (j > 0) fseek (movie->fp, j, SEEK_CUR);
+ } else fseek (movie->fp, movie->streams[temp].sf_size, SEEK_CUR);
+
+ /* Walk to the next LIST */
+ while (GET_FCC (movie->fp) != FCC("LIST")) {
+ temp= GET_FCC (movie->fp);
+ if (temp<0 || ftell(movie->fp) > movie->size) {
+ DEBUG("incorrect size in header or error in AVI\n");
+ return AVI_ERROR_FORMAT;
+ }
+ fseek(movie->fp, temp, SEEK_CUR);
+ }
+
+ fseek(movie->fp, -4L, SEEK_CUR);
+ }
+
+ while (1) {
+ temp = GET_FCC (movie->fp);
+ size = GET_FCC (movie->fp);
+
+ if (size == 0)
+ break;
+
+ if (temp == FCC("LIST")) {
+ if (GET_FCC(movie->fp) == FCC ("movi"))
+ break;
+ else
+ fseek (movie->fp, size-4, SEEK_CUR);
+ } else {
+ fseek (movie->fp, size, SEEK_CUR);
+ }
+ if (ftell(movie->fp) > movie->size) {
+ DEBUG("incorrect size in header or error in AVI\n");
+ return AVI_ERROR_FORMAT;
+ }
+ }
+
+ movie->movi_offset = ftell (movie->fp);
+ movie->read_offset = movie->movi_offset;
+ if (AVI_DEBUG) printf ("movi_offset is %d\n", movie->movi_offset);
+
+ /* Read in the index if the file has one, otherwise create one */
+ if (movie->header->Flags & AVIF_HASINDEX) {
+ fseek(movie->fp, size-4, SEEK_CUR);
+
+ if (GET_FCC(movie->fp) != FCC("idx1")) {
+ DEBUG("bad index informatio\n");
+ return AVI_ERROR_FORMAT;
+ }
+
+ movie->index_entries = GET_FCC (movie->fp)/sizeof(AviIndexEntry);
+ if (movie->index_entries == 0) {
+ DEBUG("no index entries\n");
+ return AVI_ERROR_FORMAT;
+ }
+
+ movie->entries = (AviIndexEntry *) MEM_mallocN (movie->index_entries * sizeof(AviIndexEntry),"movieentries");
+
+ for (temp=0; temp < movie->index_entries; temp++) {
+ movie->entries[temp].ChunkId = GET_FCC (movie->fp);
+ movie->entries[temp].Flags = GET_FCC (movie->fp);
+ movie->entries[temp].Offset = GET_FCC (movie->fp);
+ movie->entries[temp].Size = GET_FCC (movie->fp);
+
+ if (AVI_DEBUG) printf ("Index entry %04d: ChunkId:%s Flags:%d Offset:%d Size:%d\n", temp, fcc_to_char(movie->entries[temp].ChunkId), movie->entries[temp].Flags, movie->entries[temp].Offset, movie->entries[temp].Size);
+ }
+
+/* Some AVI's have offset entries in absolute coordinates
+ * instead of an offset from the movie beginning... this is...
+ * wacky, but we need to handle it. The wacky offset always
+ * starts at movi_offset it seems... so we'll check that.
+ * Note the the offset needs an extra 4 bytes for some
+ * undetermined reason */
+
+ if (movie->entries[0].Offset == movie->movi_offset)
+ movie->read_offset= 4;
+ }
+
+ DEBUG("movie succesfully opened\n");
+ return AVI_ERROR_NONE;
+}
+
+void *AVI_read_frame (AviMovie *movie, AviFormat format, int frame, int stream) {
+ int cur_frame, temp, i, rewind=1;
+ void *buffer;
+
+ /* Retrieve the record number of the desired frame in the index
+ If a chunk has Size 0 we need to rewind to previous frame */
+ while(rewind && frame > -1) {
+ i=0;
+ cur_frame=-1;
+ rewind = 0;
+
+ while (cur_frame < frame && i < movie->index_entries) {
+ if (fcc_is_data (movie->entries[i].ChunkId) &&
+ fcc_get_stream (movie->entries[i].ChunkId) == stream) {
+ if ((cur_frame == frame -1) && (movie->entries[i].Size == 0)) {
+ rewind = 1;
+ frame = frame -1;
+ } else {
+ cur_frame++;
+ }
+ }
+ i++;
+ }
+ }
+
+ if (cur_frame != frame) return NULL;
+
+
+ fseek (movie->fp, movie->read_offset + movie->entries[i-1].Offset, SEEK_SET);
+
+ temp = GET_FCC(movie->fp);
+ buffer = MEM_mallocN (temp,"readbuffer");
+
+ if (fread (buffer, 1, temp, movie->fp) != temp) {
+ MEM_freeN(buffer);
+
+ return NULL;
+ }
+
+ buffer = avi_format_convert (movie, stream, buffer, movie->streams[stream].format, format, &temp);
+
+ return buffer;
+}
+
+AviError AVI_close (AviMovie *movie) {
+ int i;
+
+ fclose (movie->fp);
+
+ for (i=0; i < movie->header->Streams; i++) {
+ if (movie->streams[i].sf != NULL)
+ MEM_freeN (movie->streams[i].sf);
+ }
+
+ if (movie->header != NULL)
+ MEM_freeN (movie->header);
+ if (movie->streams!= NULL)
+ MEM_freeN (movie->streams);
+ if (movie->entries != NULL)
+ MEM_freeN (movie->entries);
+ if (movie->offset_table != NULL)
+ MEM_freeN (movie->offset_table);
+
+ return AVI_ERROR_NONE;
+}
+
+AviError AVI_open_compress (char *name, AviMovie *movie, int streams, ...) {
+ va_list ap;
+ AviList list;
+ AviChunk chunk;
+ int i;
+ int header_pos1, header_pos2;
+ int stream_pos1, stream_pos2;
+
+ movie->type = AVI_MOVIE_WRITE;
+ movie->fp = fopen (name, "wb");
+
+ movie->index_entries = 0;
+
+ if (movie->fp == NULL)
+ return AVI_ERROR_OPEN;
+
+ movie->offset_table = (long *) MEM_mallocN ((1+streams*2) * sizeof (long),"offsettable");
+
+ for (i=0; i < 1 + streams*2; i++)
+ movie->offset_table[i] = -1L;
+
+ movie->entries = NULL;
+
+ movie->header = (AviMainHeader *) MEM_mallocN (sizeof(AviMainHeader),"movieheader");
+
+ movie->header->fcc = FCC("avih");
+ movie->header->size = 56;
+ movie->header->MicroSecPerFrame = 66667;
+ movie->header->MaxBytesPerSec = 0;
+ movie->header->PaddingGranularity = 0;
+ movie->header->Flags = AVIF_HASINDEX | AVIF_MUSTUSEINDEX;
+ movie->header->TotalFrames = 0;
+ movie->header->InitialFrames = 0;
+ movie->header->Streams = streams;
+ movie->header->SuggestedBufferSize = 0;
+ movie->header->Width = 0;
+ movie->header->Height = 0;
+ movie->header->Reserved[0] = 0;
+ movie->header->Reserved[1] = 0;
+ movie->header->Reserved[2] = 0;
+ movie->header->Reserved[3] = 0;
+
+ movie->streams = (AviStreamRec *) MEM_mallocN (sizeof(AviStreamRec) * movie->header->Streams,"moviestreams");
+
+ va_start (ap, streams);
+
+ for (i=0; i < movie->header->Streams; i++) {
+ movie->streams[i].format = va_arg(ap, AviFormat);
+
+ movie->streams[i].sh.fcc = FCC ("strh");
+ movie->streams[i].sh.size = 56;
+ movie->streams[i].sh.Type = avi_get_format_type (movie->streams[i].format);
+ if (movie->streams[i].sh.Type == 0)
+ return AVI_ERROR_FORMAT;
+
+ movie->streams[i].sh.Handler = avi_get_format_fcc (movie->streams[i].format);
+ if (movie->streams[i].sh.Handler == 0)
+ return AVI_ERROR_FORMAT;
+
+ movie->streams[i].sh.Flags = 0;
+ movie->streams[i].sh.Priority = 0;
+ movie->streams[i].sh.Language = 0;
+ movie->streams[i].sh.InitialFrames = 0;
+ movie->streams[i].sh.Scale = 66667;
+ movie->streams[i].sh.Rate = 1000000;
+ movie->streams[i].sh.Start = 0;
+ movie->streams[i].sh.Length = 0;
+ movie->streams[i].sh.SuggestedBufferSize = 0;
+ movie->streams[i].sh.Quality = 10000;
+ movie->streams[i].sh.SampleSize = 0;
+ movie->streams[i].sh.left = 0;
+ movie->streams[i].sh.top = 0;
+ movie->streams[i].sh.right = 0;
+ movie->streams[i].sh.bottom = 0;
+
+ if (movie->streams[i].sh.Type == FCC("vids")) {
+/*
+ if (movie->streams[i].format == AVI_FORMAT_MJPEG) {
+ movie->streams[i].sf = MEM_mallocN (sizeof(AviBitmapInfoHeader)
+ + sizeof(AviMJPEGUnknown),"moviestreamformatL");
+ movie->streams[i].sf_size = sizeof(AviBitmapInfoHeader) + sizeof(AviMJPEGUnknown);
+ } else {
+*/
+ movie->streams[i].sf = MEM_mallocN (sizeof(AviBitmapInfoHeader), "moviestreamformatS");
+ movie->streams[i].sf_size = sizeof(AviBitmapInfoHeader);
+
+ ((AviBitmapInfoHeader *) movie->streams[i].sf)->fcc = FCC ("strf");
+ ((AviBitmapInfoHeader *) movie->streams[i].sf)->size = movie->streams[i].sf_size - 8;
+ ((AviBitmapInfoHeader *) movie->streams[i].sf)->Size = movie->streams[i].sf_size - 8;
+ ((AviBitmapInfoHeader *) movie->streams[i].sf)->Width = 0;
+ ((AviBitmapInfoHeader *) movie->streams[i].sf)->Height = 0;
+ ((AviBitmapInfoHeader *) movie->streams[i].sf)->Planes = 1;
+ ((AviBitmapInfoHeader *) movie->streams[i].sf)->BitCount = 24;
+ ((AviBitmapInfoHeader *) movie->streams[i].sf)->Compression = avi_get_format_compression (movie->streams[i].format);
+ ((AviBitmapInfoHeader *) movie->streams[i].sf)->SizeImage = 0;
+ ((AviBitmapInfoHeader *) movie->streams[i].sf)->XPelsPerMeter = 0;
+ ((AviBitmapInfoHeader *) movie->streams[i].sf)->YPelsPerMeter = 0;
+ ((AviBitmapInfoHeader *) movie->streams[i].sf)->ClrUsed = 0;
+ ((AviBitmapInfoHeader *) movie->streams[i].sf)->ClrImportant = 0;
+
+/*
+ if (movie->streams[i].format == AVI_FORMAT_MJPEG) {
+ AviMJPEGUnknown *tmp;
+
+ tmp = (AviMJPEGUnknown *) ((char*) movie->streams[i].sf +sizeof(AviBitmapInfoHeader));
+
+ tmp->a = 44;
+ tmp->b = 24;
+ tmp->c = 0;
+ tmp->d = 2;
+ tmp->e = 8;
+ tmp->f = 2;
+ tmp->g = 1;
+ }
+ } else if (movie->streams[i].sh.Type == FCC("auds")) {
+ ;
+*/
+ }
+ }
+
+ list.fcc = FCC("RIFF");
+ list.size = 0;
+ list.ids = FCC("AVI ");
+
+ awrite (movie, &list, 1, sizeof(AviList), movie->fp, AVI_LIST);
+
+ list.fcc = FCC("LIST");
+ list.size = 0;
+ list.ids = FCC("hdrl");
+
+ awrite (movie, &list, 1, sizeof(AviList), movie->fp, AVI_LIST);
+
+ header_pos1 = ftell(movie->fp);
+
+ movie->offset_table[0] = ftell(movie->fp);
+
+ awrite (movie, movie->header, 1, sizeof(AviMainHeader), movie->fp, AVI_MAINH);
+
+ for (i=0; i < movie->header->Streams; i++) {
+ list.fcc = FCC("LIST");
+ list.size = 0;
+ list.ids = FCC("strl");
+
+ awrite (movie, &list, 1, sizeof(AviList), movie->fp, AVI_LIST);
+
+ stream_pos1 = ftell(movie->fp);
+
+ movie->offset_table[1+i*2] = ftell(movie->fp);
+ awrite (movie, &movie->streams[i].sh, 1, sizeof(AviStreamHeader), movie->fp, AVI_STREAMH);
+
+ movie->offset_table[1+i*2+1] = ftell(movie->fp);
+ awrite (movie, movie->streams[i].sf, 1, movie->streams[i].sf_size, movie->fp, AVI_BITMAPH);
+
+ stream_pos2 = ftell(movie->fp);
+
+ fseek (movie->fp, stream_pos1-8, SEEK_SET);
+
+ PUT_FCCN((stream_pos2-stream_pos1+4L), movie->fp);
+
+ fseek (movie->fp, stream_pos2, SEEK_SET);
+ }
+
+ if (ftell(movie->fp) < 2024 - 8) {
+ chunk.fcc = FCC("JUNK");
+ chunk.size = 2024-8-ftell(movie->fp);
+
+ awrite (movie, &chunk, 1, sizeof(AviChunk), movie->fp, AVI_CHUNK);
+
+ for (i=0; i < chunk.size; i++)
+ putc(0, movie->fp);
+ }
+
+ header_pos2 = ftell(movie->fp);
+
+ list.fcc = FCC("LIST");
+ list.size = 0;
+ list.ids = FCC("movi");
+
+ awrite (movie, &list, 1, sizeof(AviList), movie->fp, AVI_LIST);
+
+ movie->movi_offset = ftell(movie->fp)-8L;
+
+ fseek (movie->fp, AVI_HDRL_SOFF, SEEK_SET);
+
+ PUT_FCCN((header_pos2-header_pos1+4L), movie->fp);
+
+ return AVI_ERROR_NONE;
+}
+
+AviError AVI_write_frame (AviMovie *movie, int frame_num, ...) {
+ AviList list;
+ AviChunk chunk;
+ AviIndexEntry *temp;
+ va_list ap;
+ int stream;
+ long rec_off;
+ AviFormat format;
+ void *buffer;
+ int size;
+
+ if (frame_num < 0)
+ return AVI_ERROR_OPTION;
+
+ /* Allocate the new memory for the index entry */
+
+ if (frame_num+1 > movie->index_entries) {
+ temp = (AviIndexEntry *) MEM_mallocN ((frame_num+1) *
+ (movie->header->Streams+1) * sizeof(AviIndexEntry),"newidxentry");
+ if (movie->entries != NULL) {
+ memcpy (temp, movie->entries, movie->index_entries * (movie->header->Streams+1)
+ * sizeof(AviIndexEntry));
+ MEM_freeN (movie->entries);
+ }
+
+ movie->entries = temp;
+ movie->index_entries = frame_num+1;
+ }
+
+ /* Slap a new record entry onto the end of the file */
+
+ fseek (movie->fp, 0L, SEEK_END);
+
+ list.fcc = FCC("LIST");
+ list.size = 0;
+ list.ids = FCC("rec ");
+
+ awrite (movie, &list, 1, sizeof(AviList), movie->fp, AVI_LIST);
+
+ rec_off = ftell (movie->fp)-8L;
+
+ /* Write a frame for every stream */
+
+ va_start (ap, frame_num);
+
+ for (stream=0; stream < movie->header->Streams; stream++) {
+ unsigned int tbuf=0;
+
+ format = va_arg (ap, AviFormat);
+ buffer = va_arg (ap, void*);
+ size = va_arg (ap, int);
+
+ /* Convert the buffer into the output format */
+ buffer = avi_format_convert (movie, stream, buffer, format, movie->streams[stream].format, &size);
+
+ /* Write the header info for this data chunk */
+
+ fseek (movie->fp, 0L, SEEK_END);
+
+ chunk.fcc = avi_get_data_id (format, stream);
+ chunk.size = size;
+
+ if (size%4) chunk.size += 4 - size%4;
+
+ awrite (movie, &chunk, 1, sizeof(AviChunk), movie->fp, AVI_CHUNK);
+
+ /* Write the index entry for this data chunk */
+
+ movie->entries[frame_num * (movie->header->Streams+1) + stream + 1].ChunkId = chunk.fcc;
+ movie->entries[frame_num * (movie->header->Streams+1) + stream + 1].Flags = AVIIF_KEYFRAME;
+ movie->entries[frame_num * (movie->header->Streams+1) + stream + 1].Offset = ftell(movie->fp)-12L-movie->movi_offset;
+ movie->entries[frame_num * (movie->header->Streams+1) + stream + 1].Size = chunk.size;
+
+ /* Write the chunk */
+ awrite (movie, buffer, 1, size, movie->fp, AVI_RAW);
+ MEM_freeN (buffer);
+
+ if (size%4) awrite (movie, &tbuf, 1, 4-size%4, movie->fp, AVI_RAW);
+
+ /* Update the stream headers length field */
+ movie->streams[stream].sh.Length++;
+ fseek (movie->fp, movie->offset_table[1+stream*2], SEEK_SET);
+ awrite (movie, &movie->streams[stream].sh, 1, sizeof(AviStreamHeader), movie->fp, AVI_STREAMH);
+ }
+ va_end (ap);
+
+ /* Record the entry for the new record */
+
+ fseek (movie->fp, 0L, SEEK_END);
+
+ movie->entries[frame_num * (movie->header->Streams+1)].ChunkId = FCC("rec ");
+ movie->entries[frame_num * (movie->header->Streams+1)].Flags = AVIIF_LIST;
+ movie->entries[frame_num * (movie->header->Streams+1)].Offset = rec_off-8L-movie->movi_offset;
+ movie->entries[frame_num * (movie->header->Streams+1)].Size = ftell(movie->fp)-(rec_off+4L);
+
+ /* Update the record size */
+ fseek (movie->fp, rec_off, SEEK_SET);
+ PUT_FCCN (movie->entries[frame_num * (movie->header->Streams+1)].Size, movie->fp);
+
+ /* Update the main header information in the file */
+ movie->header->TotalFrames++;
+ fseek (movie->fp, movie->offset_table[0], SEEK_SET);
+ awrite (movie, movie->header, 1, sizeof(AviMainHeader), movie->fp, AVI_MAINH);
+
+ return AVI_ERROR_NONE;
+}
+
+AviError AVI_close_compress (AviMovie *movie) {
+ int temp, movi_size, i;
+
+ fseek (movie->fp, 0L, SEEK_END);
+ movi_size = ftell (movie->fp);
+
+ PUT_FCC ("idx1", movie->fp);
+ PUT_FCCN ((movie->index_entries*(movie->header->Streams+1)*16), movie->fp);
+
+ for (temp=0; temp < movie->index_entries*(movie->header->Streams+1); temp++)
+ awrite (movie, &movie->entries[temp], 1, sizeof(AviIndexEntry), movie->fp, AVI_INDEXE);
+
+ temp = ftell (movie->fp);
+
+ fseek (movie->fp, AVI_RIFF_SOFF, SEEK_SET);
+
+ PUT_FCCN((temp-8L), movie->fp);
+
+ fseek (movie->fp, movie->movi_offset, SEEK_SET);
+
+ PUT_FCCN((movi_size-(movie->movi_offset+4L)),movie->fp);
+
+ fclose (movie->fp);
+
+ for (i=0; i < movie->header->Streams; i++) {
+ if (movie->streams[i].sf != NULL)
+ MEM_freeN (movie->streams[i].sf);
+ }
+ if (movie->header != NULL)
+ MEM_freeN (movie->header);
+ if (movie->entries != NULL)
+ MEM_freeN (movie->entries);
+ if (movie->streams != NULL)
+ MEM_freeN (movie->streams);
+ if (movie->offset_table != NULL)
+ MEM_freeN (movie->offset_table);
+ return AVI_ERROR_NONE;
+}
diff --git a/source/blender/avi/intern/avi_intern.h b/source/blender/avi/intern/avi_intern.h
new file mode 100644
index 00000000000..189072eba8d
--- /dev/null
+++ b/source/blender/avi/intern/avi_intern.h
@@ -0,0 +1,54 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef AVI_INTERN_H
+#define AVI_INTERN_H
+
+#include <stdio.h> /* for FILE */
+
+#include "MEM_guardedalloc.h"
+
+unsigned int GET_FCC (FILE *fp);
+unsigned int GET_TCC (FILE *fp);
+
+#define PUT_FCC(ch4, fp) putc(ch4[0],fp); putc(ch4[1],fp); putc(ch4[2],fp); putc(ch4[3],fp)
+#define PUT_FCCN(num, fp) putc((num>>0)&0377,fp); putc((num>>8)&0377,fp); putc((num>>16)&0377,fp); putc((num>>24)&0377,fp)
+#define PUT_TCC(ch2, fp) putc(ch2[0],fp); putc(ch2[1],fp)
+
+void *avi_format_convert (AviMovie *movie, int stream, void *buffer, AviFormat from, AviFormat to, int *size);
+
+int avi_get_data_id(AviFormat format, int stream);
+int avi_get_format_type(AviFormat format);
+int avi_get_format_fcc(AviFormat format);
+int avi_get_format_compression(AviFormat format);
+
+#endif
+
diff --git a/source/blender/avi/intern/avirgb.c b/source/blender/avi/intern/avirgb.c
new file mode 100644
index 00000000000..8461167efc8
--- /dev/null
+++ b/source/blender/avi/intern/avirgb.c
@@ -0,0 +1,153 @@
+/**
+ * avirgb.c
+ *
+ * This is external code. Converts rgb-type avi-s.
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "AVI_avi.h"
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+#include "avirgb.h"
+
+#if defined(__sgi) || defined (__sparc) || defined (__sparc__) || defined (__PPC__) || defined (__ppc__) || defined (__BIG_ENDIAN__)
+#define WORDS_BIGENDIAN
+#endif
+
+
+/* implementation */
+
+void *avi_converter_from_avi_rgb (AviMovie *movie, int stream, unsigned char *buffer, int *size) {
+ int x, y,i, rowstride;
+ unsigned char *buf;
+ AviBitmapInfoHeader *bi;
+ short bits= 32;
+
+ bi= (AviBitmapInfoHeader *) movie->streams[stream].sf;
+ if (bi) bits= bi->BitCount;
+
+ if (bits==16) {
+ unsigned short *pxl;
+ unsigned char *to;
+ #ifdef WORDS_BIGENDIAN
+ unsigned char *pxla;
+ #endif
+
+ buf = MEM_mallocN (movie->header->Height * movie->header->Width * 3, "fromavirgbbuf");
+
+ y= movie->header->Height;
+ to= buf;
+
+ while (y--) {
+ pxl= (unsigned short *) (buffer + y * movie->header->Width * 2);
+
+ #ifdef WORDS_BIGENDIAN
+ pxla= (unsigned char *)pxl;
+ #endif
+
+ x= movie->header->Width;
+ while (x--) {
+ #ifdef WORDS_BIGENDIAN
+ i= pxla[0];
+ pxla[0]= pxla[1];
+ pxla[1]= i;
+
+ pxla+=2;
+ #endif
+
+ *(to++)= ((*pxl>>10)&0x1f)*8;
+ *(to++)= ((*pxl>>5)&0x1f)*8;
+ *(to++)= (*pxl&0x1f)*8;
+ pxl++;
+ }
+ }
+
+ MEM_freeN (buffer);
+
+ return buf;
+ } else {
+ buf = MEM_mallocN (movie->header->Height * movie->header->Width * 3, "fromavirgbbuf");
+
+ rowstride = movie->header->Width*3;
+ if (bits!=16) if (movie->header->Width%2) rowstride++;
+
+ for (y=0; y < movie->header->Height; y++) {
+ memcpy (&buf[y*movie->header->Width*3], &buffer[((movie->header->Height-1)-y)*rowstride], movie->header->Width*3);
+ }
+
+ for (y=0; y < movie->header->Height*movie->header->Width*3; y+=3) {
+ i = buf[y];
+ buf[y] = buf[y+2];
+ buf[y+2] = i;
+ }
+
+ MEM_freeN (buffer);
+
+ return buf;
+ }
+}
+
+void *avi_converter_to_avi_rgb (AviMovie *movie, int stream, unsigned char *buffer, int *size) {
+ int y, x, i, rowstride;
+ unsigned char *buf;
+
+ *size= movie->header->Height * movie->header->Width * 3;
+ if (movie->header->Width%2) *size+= movie->header->Height;
+
+ buf = MEM_mallocN (*size,"toavirgbbuf");
+
+ rowstride = movie->header->Width*3;
+ if (movie->header->Width%2) rowstride++;
+
+ for (y=0; y < movie->header->Height; y++) {
+ memcpy (&buf[y*rowstride], &buffer[((movie->header->Height-1)-y)*movie->header->Width*3], movie->header->Width*3);
+ }
+
+ for (y=0; y < movie->header->Height; y++) {
+ for (x=0; x < movie->header->Width*3; x+=3) {
+ i = buf[y*rowstride+x];
+ buf[y*rowstride+x] = buf[y*rowstride+x+2];
+ buf[y*rowstride+x+2] = i;
+ }
+ }
+
+ MEM_freeN (buffer);
+
+ return buf;
+}
diff --git a/source/blender/avi/intern/avirgb.h b/source/blender/avi/intern/avirgb.h
new file mode 100644
index 00000000000..03c0682b024
--- /dev/null
+++ b/source/blender/avi/intern/avirgb.h
@@ -0,0 +1,35 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+void *avi_converter_from_avi_rgb (AviMovie *movie, int stream, unsigned char *buffer, int *size);
+void *avi_converter_to_avi_rgb (AviMovie *movie, int stream, unsigned char *buffer, int *size);
+
diff --git a/source/blender/avi/intern/codecs.c b/source/blender/avi/intern/codecs.c
new file mode 100644
index 00000000000..3daff52a947
--- /dev/null
+++ b/source/blender/avi/intern/codecs.c
@@ -0,0 +1,147 @@
+/**
+ * codecs.c
+ *
+ * This is external code. Identify and convert different avi-files.
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "AVI_avi.h"
+#include "avi_intern.h"
+
+#include "avirgb.h"
+#include "mjpeg.h"
+#include "rgb32.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+void *avi_format_convert (AviMovie *movie, int stream, void *buffer, AviFormat from, AviFormat to, int *size) {
+ if (from == to)
+ return buffer;
+
+ if (from != AVI_FORMAT_RGB24 &&
+ to != AVI_FORMAT_RGB24)
+ return avi_format_convert(movie, stream,
+ avi_format_convert (movie, stream, buffer, from, AVI_FORMAT_RGB24, size),
+ AVI_FORMAT_RGB24, to, size);
+
+ switch (to) {
+ case AVI_FORMAT_RGB24:
+ switch (from) {
+ case AVI_FORMAT_AVI_RGB:
+ buffer = avi_converter_from_avi_rgb (movie, stream, buffer, size);
+ break;
+ case AVI_FORMAT_MJPEG:
+ buffer = avi_converter_from_mjpeg (movie, stream, buffer, size);
+ break;
+ case AVI_FORMAT_RGB32:
+ buffer = avi_converter_from_rgb32 (movie, stream, buffer, size);
+ break;
+ default:
+ break;
+ }
+ break;
+ case AVI_FORMAT_AVI_RGB:
+ buffer = avi_converter_to_avi_rgb (movie, stream, buffer, size);
+ break;
+ case AVI_FORMAT_MJPEG:
+ buffer = avi_converter_to_mjpeg (movie, stream, buffer, size);
+ break;
+ case AVI_FORMAT_RGB32:
+ buffer = avi_converter_to_rgb32 (movie, stream, buffer, size);
+ break;
+ default:
+ break;
+ }
+
+ return buffer;
+}
+
+int avi_get_data_id (AviFormat format, int stream) {
+ char fcc[5];
+
+ if (avi_get_format_type (format) == FCC("vids"))
+ sprintf (fcc,"%2.2ddc",stream);
+ else if (avi_get_format_type (format) == FCC("auds"))
+ sprintf (fcc,"%2.2ddc",stream);
+ else
+ return 0;
+
+ return FCC(fcc);
+}
+
+int avi_get_format_type (AviFormat format) {
+ switch (format) {
+ case AVI_FORMAT_RGB24:
+ case AVI_FORMAT_RGB32:
+ case AVI_FORMAT_AVI_RGB:
+ case AVI_FORMAT_MJPEG:
+ return FCC("vids");
+ break;
+ default:
+ return 0;
+ break;
+ }
+}
+
+int avi_get_format_fcc (AviFormat format) {
+ switch (format) {
+ case AVI_FORMAT_RGB24:
+ case AVI_FORMAT_RGB32:
+ case AVI_FORMAT_AVI_RGB:
+ return FCC("DIB ");
+ break;
+ case AVI_FORMAT_MJPEG:
+ return FCC("MJPG");
+ break;
+ default:
+ return 0;
+ break;
+ }
+}
+
+int avi_get_format_compression (AviFormat format) {
+ switch (format) {
+ case AVI_FORMAT_RGB24:
+ case AVI_FORMAT_RGB32:
+ case AVI_FORMAT_AVI_RGB:
+ return 0;
+ break;
+ case AVI_FORMAT_MJPEG:
+ return FCC("MJPG");
+ break;
+ default:
+ return 0;
+ break;
+ }
+}
diff --git a/source/blender/avi/intern/endian.c b/source/blender/avi/intern/endian.c
new file mode 100644
index 00000000000..152530dac0d
--- /dev/null
+++ b/source/blender/avi/intern/endian.c
@@ -0,0 +1,216 @@
+/**
+ * endian.h
+ *
+ * This is external code. Streams bytes to output depending on the
+ * endianness of the system.
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "AVI_avi.h"
+#include "endian.h"
+#include "avi_intern.h"
+
+#if defined(__sgi) || defined (__sparc) || defined (__sparc__) || defined (__PPC__) || defined (__ppc__) || defined (__BIG_ENDIAN__)
+#define WORDS_BIGENDIAN
+#endif
+
+static void invert (int *num) {
+ int new=0,i,j;
+
+ for (j=0; j < 4; j++) {
+ for (i=0; i<8; i++) {
+ new |= ((*num>>(j*8+i))&1)<<((3-j)*8+i);
+ }
+ }
+
+ *num = new;
+}
+
+static void sinvert (short int *num) {
+ short int new=0;
+ int i,j;
+
+ for (j=0; j < 2; j++) {
+ for (i=0; i<8; i++) {
+ new |= ((*num>>(j*8+i))&1)<<((1-j)*8+i);
+ }
+ }
+
+ *num = new;
+}
+
+static void Ichunk (AviChunk *chunk) {
+ invert (&chunk->fcc);
+ invert (&chunk->size);
+}
+
+#ifdef WORDS_BIGENDIAN
+static void Ilist (AviList *list){
+ invert (&list->fcc);
+ invert (&list->size);
+ invert (&list->ids);
+}
+
+static void Imainh (AviMainHeader *mainh) {
+ invert (&mainh->fcc);
+ invert (&mainh->size);
+ invert (&mainh->MicroSecPerFrame);
+ invert (&mainh->MaxBytesPerSec);
+ invert (&mainh->PaddingGranularity);
+ invert (&mainh->Flags);
+ invert (&mainh->TotalFrames);
+ invert (&mainh->InitialFrames);
+ invert (&mainh->Streams);
+ invert (&mainh->SuggestedBufferSize);
+ invert (&mainh->Width);
+ invert (&mainh->Height);
+ invert (&mainh->Reserved[0]);
+ invert (&mainh->Reserved[1]);
+ invert (&mainh->Reserved[2]);
+ invert (&mainh->Reserved[3]);
+}
+
+static void Istreamh (AviStreamHeader *streamh) {
+ invert (&streamh->fcc);
+ invert (&streamh->size);
+ invert (&streamh->Type);
+ invert (&streamh->Handler);
+ invert (&streamh->Flags);
+ sinvert (&streamh->Priority);
+ sinvert (&streamh->Language);
+ invert (&streamh->InitialFrames);
+ invert (&streamh->Scale);
+ invert (&streamh->Rate);
+ invert (&streamh->Start);
+ invert (&streamh->Length);
+ invert (&streamh->SuggestedBufferSize);
+ invert (&streamh->Quality);
+ invert (&streamh->SampleSize);
+ sinvert (&streamh->left);
+ sinvert (&streamh->right);
+ sinvert (&streamh->top);
+ sinvert (&streamh->bottom);
+}
+
+static void Ibitmaph (AviBitmapInfoHeader *bitmaph) {
+ invert (&bitmaph->fcc);
+ invert (&bitmaph->size);
+ invert (&bitmaph->Size);
+ invert (&bitmaph->Width);
+ invert (&bitmaph->Height);
+ sinvert (&bitmaph->Planes);
+ sinvert (&bitmaph->BitCount);
+ invert (&bitmaph->Compression);
+ invert (&bitmaph->SizeImage);
+ invert (&bitmaph->XPelsPerMeter);
+ invert (&bitmaph->YPelsPerMeter);
+ invert (&bitmaph->ClrUsed);
+ invert (&bitmaph->ClrImportant);
+}
+
+static void Imjpegu (AviMJPEGUnknown *mjpgu) {
+ invert (&mjpgu->a);
+ invert (&mjpgu->b);
+ invert (&mjpgu->c);
+ invert (&mjpgu->d);
+ invert (&mjpgu->e);
+ invert (&mjpgu->f);
+ invert (&mjpgu->g);
+}
+
+static void Iindexe (AviIndexEntry *indexe) {
+ invert (&indexe->ChunkId);
+ invert (&indexe->Flags);
+ invert (&indexe->Offset);
+ invert (&indexe->Size);
+}
+#endif /* WORDS_BIGENDIAN */
+
+void awrite (AviMovie *movie, void *datain, int block, int size, FILE *fp, int type) {
+#ifdef WORDS_BIGENDIAN
+ void *data;
+
+ data = MEM_mallocN (size, "avi endian");
+
+ memcpy (data, datain, size);
+
+ switch (type) {
+ case AVI_RAW:
+ fwrite (data, block, size, fp);
+ break;
+ case AVI_CHUNK:
+ Ichunk ((AviChunk *) data);
+ fwrite (data, block, size, fp);
+ break;
+ case AVI_LIST:
+ Ilist ((AviList *) data);
+ fwrite (data, block, size, fp);
+ break;
+ case AVI_MAINH:
+ Imainh ((AviMainHeader *) data);
+ fwrite (data, block, size, fp);
+ break;
+ case AVI_STREAMH:
+ Istreamh ((AviStreamHeader *) data);
+ fwrite (data, block, size, fp);
+ break;
+ case AVI_BITMAPH:
+ Ibitmaph ((AviBitmapInfoHeader *) data);
+ if (size==sizeof(AviBitmapInfoHeader) + sizeof(AviMJPEGUnknown)) {
+ Imjpegu((AviMJPEGUnknown*)((char*)data+sizeof(AviBitmapInfoHeader)));
+ }
+ fwrite (data, block, size, fp);
+ break;
+ case AVI_MJPEGU:
+ Imjpegu ((AviMJPEGUnknown *) data);
+ fwrite (data, block, size, fp);
+ break;
+ case AVI_INDEXE:
+ Iindexe ((AviIndexEntry *) data);
+ fwrite (data, block, size, fp);
+ break;
+ default:
+ break;
+ }
+
+ MEM_freeN (data);
+#else /* WORDS_BIGENDIAN */
+ fwrite (datain, block, size, fp);
+#endif /* WORDS_BIGENDIAN */
+}
diff --git a/source/blender/avi/intern/endian.h b/source/blender/avi/intern/endian.h
new file mode 100644
index 00000000000..907069c1f87
--- /dev/null
+++ b/source/blender/avi/intern/endian.h
@@ -0,0 +1,55 @@
+/**
+ * endian.h
+ *
+ * This is external code.
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * */
+
+#ifndef AVI_ENDIAN_H
+#define AVI_ENDIAN_H
+
+#include <stdio.h>
+#include "AVI_avi.h"
+
+#define AVI_RAW 0
+#define AVI_CHUNK 1
+#define AVI_LIST 2
+#define AVI_MAINH 3
+#define AVI_STREAMH 4
+#define AVI_BITMAPH 5
+#define AVI_INDEXE 6
+#define AVI_MJPEGU 7
+
+void awrite (AviMovie *movie, void *datain, int block, int size, FILE *fp, int type);
+
+#endif
+
diff --git a/source/blender/avi/intern/mjpeg.c b/source/blender/avi/intern/mjpeg.c
new file mode 100644
index 00000000000..d51c04a1834
--- /dev/null
+++ b/source/blender/avi/intern/mjpeg.c
@@ -0,0 +1,458 @@
+/**
+ * mjpeg.c
+ *
+ * This is external code. Converts between avi and mpeg/jpeg.
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * */
+
+#include "AVI_avi.h"
+#include <stdlib.h>
+#include <string.h>
+#include "jpeglib.h"
+#include "jerror.h"
+#include "MEM_guardedalloc.h"
+
+#include "mjpeg.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define PADUP(num, amt) ((num+(amt-1))&~(amt-1))
+
+static void jpegmemdestmgr_build (j_compress_ptr cinfo, unsigned char *buffer, int bufsize);
+static void jpegmemsrcmgr_build (j_decompress_ptr dinfo, unsigned char *buffer, int bufsize);
+
+static int numbytes;
+
+static void add_huff_table (j_decompress_ptr dinfo, JHUFF_TBL **htblptr, const UINT8 *bits, const UINT8 *val) {
+ if (*htblptr == NULL)
+ *htblptr = jpeg_alloc_huff_table((j_common_ptr) dinfo);
+
+ memcpy((*htblptr)->bits, bits, sizeof((*htblptr)->bits));
+ memcpy((*htblptr)->huffval, val, sizeof((*htblptr)->huffval));
+
+ /* Initialize sent_table FALSE so table will be written to JPEG file. */
+ (*htblptr)->sent_table = FALSE;
+}
+
+/* Set up the standard Huffman tables (cf. JPEG standard section K.3) */
+/* IMPORTANT: these are only valid for 8-bit data precision! */
+
+static void std_huff_tables (j_decompress_ptr dinfo) {
+ static const UINT8 bits_dc_luminance[17] =
+ { /* 0-base */
+ 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 };
+ static const UINT8 val_dc_luminance[] =
+ {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
+
+ static const UINT8 bits_dc_chrominance[17] =
+ { /* 0-base */
+ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 };
+ static const UINT8 val_dc_chrominance[] =
+ {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
+
+ static const UINT8 bits_ac_luminance[17] =
+ { /* 0-base */
+ 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d };
+ static const UINT8 val_ac_luminance[] =
+ {
+ 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
+ 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
+ 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
+ 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
+ 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
+ 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+ 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+ 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+ 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+ 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+ 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+ 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+ 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
+ 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
+ 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
+ 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
+ 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa };
+ static const UINT8 bits_ac_chrominance[17] =
+ { /* 0-base */
+ 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 };
+ static const UINT8 val_ac_chrominance[] =
+ {
+ 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
+ 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
+ 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
+ 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
+ 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
+ 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
+ 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
+ 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
+ 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+ 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
+ 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
+ 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
+ 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
+ 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
+ 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
+ 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
+ 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa };
+
+ add_huff_table(dinfo, &dinfo->dc_huff_tbl_ptrs[0],
+ bits_dc_luminance, val_dc_luminance);
+ add_huff_table(dinfo, &dinfo->ac_huff_tbl_ptrs[0],
+ bits_ac_luminance, val_ac_luminance);
+ add_huff_table(dinfo, &dinfo->dc_huff_tbl_ptrs[1],
+ bits_dc_chrominance, val_dc_chrominance);
+ add_huff_table(dinfo, &dinfo->ac_huff_tbl_ptrs[1],
+ bits_ac_chrominance, val_ac_chrominance);
+}
+
+static int Decode_JPEG(unsigned char *inBuffer, unsigned char *outBuffer, unsigned int width, unsigned int height, int bufsize) {
+ int rowstride;
+ unsigned int y;
+ struct jpeg_decompress_struct dinfo;
+ struct jpeg_error_mgr jerr;
+
+ numbytes= 0;
+
+ dinfo.err = jpeg_std_error(&jerr);
+ jpeg_create_decompress(&dinfo);
+ jpegmemsrcmgr_build(&dinfo, inBuffer, bufsize);
+ jpeg_read_header(&dinfo, TRUE);
+ if (dinfo.dc_huff_tbl_ptrs[0] == NULL){
+ std_huff_tables(&dinfo);
+ }
+ dinfo.out_color_space = JCS_RGB;
+ dinfo.dct_method = JDCT_IFAST;
+
+ jpeg_start_decompress(&dinfo);
+
+ rowstride= dinfo.output_width*dinfo.output_components;
+ for (y= 0; y<dinfo.output_height; y++) {
+ jpeg_read_scanlines(&dinfo, (JSAMPARRAY) &outBuffer, 1);
+ outBuffer += rowstride;
+ }
+ jpeg_finish_decompress(&dinfo);
+
+ if (dinfo.output_height >= height) return 0;
+
+ inBuffer+= numbytes;
+ jpegmemsrcmgr_build(&dinfo, inBuffer, bufsize-numbytes);
+
+ numbytes= 0;
+ jpeg_read_header(&dinfo, TRUE);
+ if (dinfo.dc_huff_tbl_ptrs[0] == NULL){
+ std_huff_tables(&dinfo);
+ }
+
+ jpeg_start_decompress(&dinfo);
+ rowstride= dinfo.output_width*dinfo.output_components;
+ for (y= 0; y<dinfo.output_height; y++){
+ jpeg_read_scanlines(&dinfo, (JSAMPARRAY) &outBuffer, 1);
+ outBuffer += rowstride;
+ }
+ jpeg_finish_decompress(&dinfo);
+ jpeg_destroy_decompress(&dinfo);
+
+ return 1;
+}
+
+static void Compress_JPEG(int quality, unsigned char *outbuffer, unsigned char *inBuffer, int width, int height, int bufsize) {
+ int i, rowstride;
+ unsigned int y;
+ struct jpeg_compress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+ unsigned char marker[60];
+
+ cinfo.err = jpeg_std_error(&jerr);
+ jpeg_create_compress(&cinfo);
+ jpegmemdestmgr_build(&cinfo, outbuffer, bufsize);
+
+ cinfo.image_width = width;
+ cinfo.image_height = height;
+ cinfo.input_components = 3;
+ cinfo.in_color_space = JCS_RGB;
+
+ jpeg_set_defaults(&cinfo);
+ jpeg_set_colorspace (&cinfo, JCS_YCbCr);
+
+ jpeg_set_quality (&cinfo, quality, TRUE);
+
+ cinfo.dc_huff_tbl_ptrs[0]->sent_table = TRUE;
+ cinfo.dc_huff_tbl_ptrs[1]->sent_table = TRUE;
+ cinfo.ac_huff_tbl_ptrs[0]->sent_table = TRUE;
+ cinfo.ac_huff_tbl_ptrs[1]->sent_table = TRUE;
+
+ cinfo.comp_info[0].component_id = 0;
+ cinfo.comp_info[0].v_samp_factor = 1;
+ cinfo.comp_info[1].component_id = 1;
+ cinfo.comp_info[2].component_id = 2;
+
+ cinfo.write_JFIF_header = FALSE;
+
+ jpeg_start_compress(&cinfo, FALSE);
+
+ i=0;
+ marker[i++] = 'A';
+ marker[i++] = 'V';
+ marker[i++] = 'I';
+ marker[i++] = '1';
+ marker[i++] = 0;
+ while (i<60)
+ marker[i++] = 32;
+
+ jpeg_write_marker (&cinfo, JPEG_APP0, marker, 60);
+
+ i=0;
+ while (i<60)
+ marker[i++] = 0;
+
+ jpeg_write_marker (&cinfo, JPEG_COM, marker, 60);
+
+ rowstride= cinfo.image_width*cinfo.input_components;
+ for (y = 0; y < cinfo.image_height; y++){
+ jpeg_write_scanlines(&cinfo, (JSAMPARRAY) &inBuffer, 1);
+ inBuffer += rowstride;
+ }
+ jpeg_finish_compress(&cinfo);
+ jpeg_destroy_compress(&cinfo);
+}
+
+static void interlace(unsigned char *to, unsigned char *from, int width, int height) {
+ int i, rowstride= width*3;
+
+ for (i=0; i<height; i++) {
+ if (i&1)
+ memcpy (&to[i*rowstride], &from[(i/2 + height/2)*rowstride], rowstride);
+ else
+ memcpy (&to[i*rowstride], &from[(i/2)*rowstride], rowstride);
+ }
+}
+
+static void deinterlace(int odd, unsigned char *to, unsigned char *from, int width, int height) {
+ int i, rowstride= width*3;
+
+ for (i=0; i<height; i++) {
+ if ((i&1)==odd)
+ memcpy (&to[(i/2 + height/2)*rowstride], &from[i*rowstride], rowstride);
+ else
+ memcpy (&to[(i/2)*rowstride], &from[i*rowstride], rowstride);
+ }
+}
+
+static int check_and_decode_jpeg(unsigned char *inbuf, unsigned char *outbuf, int width, int height, int bufsize) {
+ /* JPEG's are always multiples of 16, extra is cropped out AVI's */
+ if ((width&0xF) || (height&0xF)) {
+ int i, rrowstride, jrowstride;
+ int jwidth= PADUP(width, 16);
+ int jheight= PADUP(height, 16);
+ unsigned char *tmpbuf= MEM_mallocN(jwidth*jheight*3, "avi.check_and_decode_jpeg");
+ int ret= Decode_JPEG(inbuf, tmpbuf, jwidth, jheight, bufsize);
+
+ /* crop the tmpbuf into the real buffer */
+ rrowstride= width*3;
+ jrowstride= jwidth*3;
+ for (i=0; i<height; i++)
+ memcpy(&outbuf[i*rrowstride], &tmpbuf[i*jrowstride], rrowstride);
+ MEM_freeN(tmpbuf);
+
+ return ret;
+ } else {
+ return Decode_JPEG(inbuf, outbuf, width, height, bufsize);
+ }
+}
+
+static void check_and_compress_jpeg(int quality, unsigned char *outbuf, unsigned char *inbuf, int width, int height, int bufsize) {
+ /* JPEG's are always multiples of 16, extra is ignored in AVI's */
+ if ((width&0xF) || (height&0xF)) {
+ int i, rrowstride, jrowstride;
+ int jwidth= PADUP(width, 16);
+ int jheight= PADUP(height, 16);
+ unsigned char *tmpbuf= MEM_mallocN(jwidth*jheight*3, "avi.check_and_compress_jpeg");
+
+ /* resize the realbuf into the tmpbuf */
+ rrowstride= width*3;
+ jrowstride= jwidth*3;
+ for (i=0; i<jheight; i++) {
+ if (i<height)
+ memcpy(&tmpbuf[i*jrowstride], &inbuf[i*rrowstride], rrowstride);
+ else
+ memset(&tmpbuf[i*jrowstride], 0, rrowstride);
+ memset(&tmpbuf[i*jrowstride+rrowstride], 0, jrowstride-rrowstride);
+ }
+
+ Compress_JPEG(quality, outbuf, tmpbuf, jwidth, jheight, bufsize);
+
+ MEM_freeN(tmpbuf);
+ } else {
+ Compress_JPEG(quality, outbuf, inbuf, width, height, bufsize);
+ }
+}
+
+void *avi_converter_from_mjpeg (AviMovie *movie, int stream, unsigned char *buffer, int *size) {
+ int deint;
+ unsigned char *buf;
+
+ buf= MEM_mallocN (movie->header->Height * movie->header->Width * 3, "avi.avi_converter_from_mjpeg 1");
+
+ deint= check_and_decode_jpeg(buffer, buf, movie->header->Width, movie->header->Height, *size);
+
+ MEM_freeN(buffer);
+
+ if (deint) {
+ buffer = MEM_mallocN (movie->header->Height * movie->header->Width * 3, "avi.avi_converter_from_mjpeg 2");
+ interlace (buffer, buf, movie->header->Width, movie->header->Height);
+ MEM_freeN (buf);
+
+ buf= buffer;
+ }
+
+ return buf;
+}
+
+void *avi_converter_to_mjpeg (AviMovie *movie, int stream, unsigned char *buffer, int *size) {
+ unsigned char *buf;
+ int bufsize= *size;
+
+ numbytes = 0;
+ *size= 0;
+
+ buf = MEM_mallocN (movie->header->Height * movie->header->Width * 3, "avi.avi_converter_to_mjpeg 1");
+ if (!movie->interlace) {
+ check_and_compress_jpeg(movie->streams[stream].sh.Quality/100, buf, buffer, movie->header->Width, movie->header->Height, bufsize);
+ } else {
+ deinterlace (movie->odd_fields, buf, buffer, movie->header->Width, movie->header->Height);
+ MEM_freeN (buffer);
+
+ buffer= buf;
+ buf= MEM_mallocN (movie->header->Height * movie->header->Width * 3, "avi.avi_converter_to_mjpeg 2");
+
+ check_and_compress_jpeg(movie->streams[stream].sh.Quality/100, buf, buffer, movie->header->Width, movie->header->Height/2, bufsize/2);
+ *size+= numbytes;
+ numbytes=0;
+ check_and_compress_jpeg(movie->streams[stream].sh.Quality/100, buf+*size, buffer+(movie->header->Height/2)*movie->header->Width*3, movie->header->Width, movie->header->Height/2, bufsize/2);
+ }
+ *size += numbytes;
+
+ MEM_freeN (buffer);
+ return buf;
+}
+
+
+/* Compression from memory */
+
+static void jpegmemdestmgr_init_destination(j_compress_ptr cinfo) {
+ ;
+}
+
+static boolean jpegmemdestmgr_empty_output_buffer(j_compress_ptr cinfo) {
+ return TRUE;
+}
+
+static void jpegmemdestmgr_term_destination(j_compress_ptr cinfo) {
+ numbytes-= cinfo->dest->free_in_buffer;
+
+ MEM_freeN(cinfo->dest);
+}
+
+static void jpegmemdestmgr_build(j_compress_ptr cinfo, unsigned char *buffer, int bufsize) {
+ cinfo->dest= MEM_mallocN(sizeof(*(cinfo->dest)), "avi.jpegmemdestmgr_build");
+
+ cinfo->dest->init_destination= jpegmemdestmgr_init_destination;
+ cinfo->dest->empty_output_buffer= jpegmemdestmgr_empty_output_buffer;
+ cinfo->dest->term_destination= jpegmemdestmgr_term_destination;
+
+ cinfo->dest->next_output_byte= buffer;
+ cinfo->dest->free_in_buffer= bufsize;
+
+ numbytes= bufsize;
+}
+
+/* Decompression from memory */
+
+static void jpegmemsrcmgr_init_source(j_decompress_ptr dinfo) {
+ ;
+}
+
+static boolean jpegmemsrcmgr_fill_input_buffer(j_decompress_ptr dinfo) {
+ unsigned char *buf= (unsigned char*) dinfo->src->next_input_byte-2;
+
+ /* if we get called, must have run out of data */
+ WARNMS(dinfo, JWRN_JPEG_EOF);
+
+ buf[0]= (JOCTET) 0xFF;
+ buf[1]= (JOCTET) JPEG_EOI;
+
+ dinfo->src->next_input_byte= buf;
+ dinfo->src->bytes_in_buffer= 2;
+
+ return TRUE;
+}
+
+static void jpegmemsrcmgr_skip_input_data(j_decompress_ptr dinfo, long skipcnt) {
+ if (dinfo->src->bytes_in_buffer<skipcnt)
+ skipcnt= dinfo->src->bytes_in_buffer;
+
+ dinfo->src->next_input_byte+= skipcnt;
+ dinfo->src->bytes_in_buffer-= skipcnt;
+}
+
+static void jpegmemsrcmgr_term_source(j_decompress_ptr dinfo) {
+ numbytes-= dinfo->src->bytes_in_buffer;
+
+ MEM_freeN(dinfo->src);
+}
+
+static void jpegmemsrcmgr_build(j_decompress_ptr dinfo, unsigned char *buffer, int bufsize) {
+ dinfo->src= MEM_mallocN(sizeof(*(dinfo->src)), "avi.jpegmemsrcmgr_build");
+
+ dinfo->src->init_source= jpegmemsrcmgr_init_source;
+ dinfo->src->fill_input_buffer= jpegmemsrcmgr_fill_input_buffer;
+ dinfo->src->skip_input_data= jpegmemsrcmgr_skip_input_data;
+ dinfo->src->resync_to_restart= jpeg_resync_to_restart;
+ dinfo->src->term_source= jpegmemsrcmgr_term_source;
+
+ dinfo->src->bytes_in_buffer= bufsize;
+ dinfo->src->next_input_byte= buffer;
+
+ numbytes= bufsize;
+}
diff --git a/source/blender/avi/intern/mjpeg.h b/source/blender/avi/intern/mjpeg.h
new file mode 100644
index 00000000000..5b7f54a6e42
--- /dev/null
+++ b/source/blender/avi/intern/mjpeg.h
@@ -0,0 +1,35 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+void *avi_converter_from_mjpeg (AviMovie *movie, int stream, unsigned char *buffer, int *size);
+void *avi_converter_to_mjpeg (AviMovie *movie, int stream, unsigned char *buffer, int *size);
+
diff --git a/source/blender/avi/intern/options.c b/source/blender/avi/intern/options.c
new file mode 100644
index 00000000000..08c8cb254f0
--- /dev/null
+++ b/source/blender/avi/intern/options.c
@@ -0,0 +1,130 @@
+/**
+ * options.h
+ *
+ * This is external code. Sets some compression related options
+ * (width, height quality, framerate).
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * */
+
+#include "AVI_avi.h"
+#include "avi_intern.h"
+#include "endian.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* avi_set_compress_options gets its own file... now don't WE feel important? */
+
+AviError AVI_set_compress_option (AviMovie *movie, int option_type, int stream, AviOption option, void *opt_data) {
+ int i;
+
+ if (movie->header->TotalFrames != 0) /* Can't change params after we have already started writing frames */
+ return AVI_ERROR_OPTION;
+
+ switch (option_type) {
+ case AVI_OPTION_TYPE_MAIN:
+ switch (option) {
+ case AVI_OPTION_WIDTH:
+ movie->header->Width = *((int *) opt_data);
+ movie->header->SuggestedBufferSize = movie->header->Width*movie->header->Height*3;
+
+ for (i=0; i < movie->header->Streams; i++) {
+ if (avi_get_format_type(movie->streams[i].format) == FCC("vids")) {
+ ((AviBitmapInfoHeader *) movie->streams[i].sf)->Width = *((int *) opt_data);
+ movie->streams[i].sh.SuggestedBufferSize = movie->header->SuggestedBufferSize;
+ movie->streams[i].sh.right = *((int *) opt_data);
+ ((AviBitmapInfoHeader *) movie->streams[i].sf)->SizeImage = movie->header->SuggestedBufferSize;
+ fseek (movie->fp, movie->offset_table[1+i*2+1], SEEK_SET);
+ awrite (movie, movie->streams[i].sf, 1, movie->streams[i].sf_size, movie->fp, AVI_BITMAPH);
+ }
+ }
+
+ break;
+
+ case AVI_OPTION_HEIGHT:
+ movie->header->Height = *((int *) opt_data);
+ movie->header->SuggestedBufferSize = movie->header->Width*movie->header->Height*3;
+
+ for (i=0; i < movie->header->Streams; i++) {
+ if (avi_get_format_type(movie->streams[i].format) == FCC("vids")) {
+ ((AviBitmapInfoHeader *) movie->streams[i].sf)->Height = *((int *) opt_data);
+ movie->streams[i].sh.SuggestedBufferSize = movie->header->SuggestedBufferSize;
+ movie->streams[i].sh.bottom = *((int *) opt_data);
+ ((AviBitmapInfoHeader *) movie->streams[i].sf)->SizeImage = movie->header->SuggestedBufferSize;
+ fseek (movie->fp, movie->offset_table[1+i*2+1], SEEK_SET);
+ awrite (movie, movie->streams[i].sf, 1, movie->streams[i].sf_size, movie->fp, AVI_BITMAPH);
+ }
+ }
+
+ break;
+
+ case AVI_OPTION_QUALITY:
+ for (i=0; i < movie->header->Streams; i++) {
+ if (avi_get_format_type(movie->streams[i].format) == FCC("vids")) {
+ movie->streams[i].sh.Quality = (*((int *) opt_data))*100;
+ fseek (movie->fp, movie->offset_table[1+i*2+1], SEEK_SET);
+ awrite (movie, movie->streams[i].sf, 1, movie->streams[i].sf_size, movie->fp, AVI_BITMAPH);
+ }
+ }
+ break;
+
+ case AVI_OPTION_FRAMERATE:
+ if (1000000/(*((double *) opt_data)))
+ movie->header->MicroSecPerFrame = 1000000/(*((double *) opt_data));
+
+ for (i=0; i < movie->header->Streams; i++) {
+ if (avi_get_format_type(movie->streams[i].format) == FCC("vids")) {
+ movie->streams[i].sh.Scale = movie->header->MicroSecPerFrame;
+ fseek (movie->fp, movie->offset_table[1+i*2+1], SEEK_SET);
+ awrite (movie, movie->streams[i].sf, 1, movie->streams[i].sf_size, movie->fp, AVI_BITMAPH);
+ }
+ }
+
+ }
+
+ fseek (movie->fp, movie->offset_table[0], SEEK_SET);
+ awrite (movie, movie->header, 1, sizeof(AviMainHeader), movie->fp, AVI_MAINH);
+
+ break;
+ case AVI_OPTION_TYPE_STRH:
+ break;
+ case AVI_OPTION_TYPE_STRF:
+ break;
+ default:
+ return AVI_ERROR_OPTION;
+ break;
+ }
+
+ return AVI_ERROR_NONE;
+}
+
diff --git a/source/blender/avi/intern/rgb32.c b/source/blender/avi/intern/rgb32.c
new file mode 100644
index 00000000000..d838ba5b786
--- /dev/null
+++ b/source/blender/avi/intern/rgb32.c
@@ -0,0 +1,91 @@
+/**
+ * rgb32.c
+ *
+ * This is external code. Converts between rgb32 and avi.
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * */
+
+#include "AVI_avi.h"
+#include <stdlib.h>
+#include <string.h>
+#include "MEM_guardedalloc.h"
+#include "rgb32.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+void *avi_converter_from_rgb32 (AviMovie *movie, int stream, unsigned char *buffer, int *size) {
+ int y, x, rowstridea, rowstrideb;
+ unsigned char *buf;
+
+ buf = MEM_mallocN (movie->header->Height * movie->header->Width * 3, "fromrgb32buf");
+ *size = movie->header->Height * movie->header->Width * 3;
+
+ rowstridea = movie->header->Width*3;
+ rowstrideb = movie->header->Width*4;
+
+ for (y=0; y < movie->header->Height; y++) {
+ for (x=0; x < movie->header->Width; x++) {
+ buf[y*rowstridea + x*3 + 0] = buffer[y*rowstrideb + x*4 + 3];
+ buf[y*rowstridea + x*3 + 1] = buffer[y*rowstrideb + x*4 + 2];
+ buf[y*rowstridea + x*3 + 2] = buffer[y*rowstrideb + x*4 + 1];
+ }
+ }
+
+ MEM_freeN (buffer);
+
+ return buf;
+}
+
+void *avi_converter_to_rgb32 (AviMovie *movie, int stream, unsigned char *buffer, int *size) {
+ int i;
+ unsigned char *buf;
+ unsigned char *to, *from;
+
+ buf= MEM_mallocN (movie->header->Height * movie->header->Width * 4, "torgb32buf");
+ *size= movie->header->Height * movie->header->Width * 4;
+
+ memset(buf, 255, *size);
+
+ to= buf; from= buffer;
+ i=movie->header->Height*movie->header->Width;
+
+ while(i--) {
+ memcpy(to, from, 3);
+ to+=4; from+=3;
+ }
+
+ MEM_freeN (buffer);
+
+ return buf;
+}
diff --git a/source/blender/avi/intern/rgb32.h b/source/blender/avi/intern/rgb32.h
new file mode 100644
index 00000000000..019869c6058
--- /dev/null
+++ b/source/blender/avi/intern/rgb32.h
@@ -0,0 +1,35 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+void *avi_converter_from_rgb32 (AviMovie *movie, int stream, unsigned char *buffer, int *size);
+void *avi_converter_to_rgb32 (AviMovie *movie, int stream, unsigned char *buffer, int *size);
+
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h
new file mode 100644
index 00000000000..1852dc72a40
--- /dev/null
+++ b/source/blender/blenkernel/BKE_DerivedMesh.h
@@ -0,0 +1,461 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BKE_DERIVEDMESH_H
+#define BKE_DERIVEDMESH_H
+
+/* TODO (Probably)
+ *
+ * o Make drawMapped* functions take a predicate function that
+ * determines whether to draw the edge (this predicate can
+ * also set color, etc). This will be slightly more general
+ * and allow some of the functions to be collapsed.
+ * o Once accessor functions are added then single element draw
+ * functions can be implemented using primitive accessors.
+ * o Add function to dispatch to renderer instead of using
+ * conversion to DLM.
+ */
+
+#include "DNA_customdata_types.h"
+#include "BKE_customdata.h"
+
+struct MVert;
+struct MEdge;
+struct MFace;
+struct MTFace;
+struct Object;
+struct Mesh;
+struct EditMesh;
+struct ModifierData;
+struct MCol;
+struct ColorBand;
+
+/* number of sub-elements each mesh element has (for interpolation) */
+#define SUB_ELEMS_VERT 0
+#define SUB_ELEMS_EDGE 2
+#define SUB_ELEMS_FACE 4
+
+typedef struct DerivedMesh DerivedMesh;
+struct DerivedMesh {
+ /* Private DerivedMesh data, only for internal DerivedMesh use */
+ CustomData vertData, edgeData, faceData;
+ int numVertData, numEdgeData, numFaceData;
+ int needsFree; /* checked on ->release, is set to 0 for cached results */
+
+ /* Misc. Queries */
+
+ /* Also called in Editmode */
+ int (*getNumVerts)(DerivedMesh *dm);
+ /* Also called in Editmode */
+ int (*getNumFaces)(DerivedMesh *dm);
+
+ int (*getNumEdges)(DerivedMesh *dm);
+
+ /* copy a single vert/edge/face from the derived mesh into
+ * *{vert/edge/face}_r. note that the current implementation
+ * of this function can be quite slow, iterating over all
+ * elements (editmesh, verse mesh)
+ */
+ void (*getVert)(DerivedMesh *dm, int index, struct MVert *vert_r);
+ void (*getEdge)(DerivedMesh *dm, int index, struct MEdge *edge_r);
+ void (*getFace)(DerivedMesh *dm, int index, struct MFace *face_r);
+
+ /* return a pointer to the entire array of verts/edges/face from the
+ * derived mesh. if such an array does not exist yet, it will be created,
+ * and freed on the next ->release(). consider using getVert/Edge/Face if
+ * you are only interested in a few verts/edges/faces.
+ */
+ struct MVert *(*getVertArray)(DerivedMesh *dm);
+ struct MEdge *(*getEdgeArray)(DerivedMesh *dm);
+ struct MFace *(*getFaceArray)(DerivedMesh *dm);
+
+ /* copy all verts/edges/faces from the derived mesh into
+ * *{vert/edge/face}_r (must point to a buffer large enough)
+ */
+ void (*copyVertArray)(DerivedMesh *dm, struct MVert *vert_r);
+ void (*copyEdgeArray)(DerivedMesh *dm, struct MEdge *edge_r);
+ void (*copyFaceArray)(DerivedMesh *dm, struct MFace *face_r);
+
+ /* return a copy of all verts/edges/faces from the derived mesh
+ * it is the caller's responsibility to free the returned pointer
+ */
+ struct MVert *(*dupVertArray)(DerivedMesh *dm);
+ struct MEdge *(*dupEdgeArray)(DerivedMesh *dm);
+ struct MFace *(*dupFaceArray)(DerivedMesh *dm);
+
+ /* return a pointer to a single element of vert/edge/face custom data
+ * from the derived mesh (this gives a pointer to the actual data, not
+ * a copy)
+ */
+ void *(*getVertData)(DerivedMesh *dm, int index, int type);
+ void *(*getEdgeData)(DerivedMesh *dm, int index, int type);
+ void *(*getFaceData)(DerivedMesh *dm, int index, int type);
+
+ /* return a pointer to the entire array of vert/edge/face custom data
+ * from the derived mesh (this gives a pointer to the actual data, not
+ * a copy)
+ */
+ void *(*getVertDataArray)(DerivedMesh *dm, int type);
+ void *(*getEdgeDataArray)(DerivedMesh *dm, int type);
+ void *(*getFaceDataArray)(DerivedMesh *dm, int type);
+
+ /* Iterate over each mapped vertex in the derived mesh, calling the
+ * given function with the original vert and the mapped vert's new
+ * coordinate and normal. For historical reasons the normal can be
+ * passed as a float or short array, only one should be non-NULL.
+ */
+ void (*foreachMappedVert)(
+ DerivedMesh *dm,
+ void (*func)(void *userData, int index, float *co,
+ float *no_f, short *no_s),
+ void *userData);
+
+ /* Iterate over each mapped edge in the derived mesh, calling the
+ * given function with the original edge and the mapped edge's new
+ * coordinates.
+ */
+ void (*foreachMappedEdge)(DerivedMesh *dm,
+ void (*func)(void *userData, int index,
+ float *v0co, float *v1co),
+ void *userData);
+
+ /* Iterate over each mapped face in the derived mesh, calling the
+ * given function with the original face and the mapped face's (or
+ * faces') center and normal.
+ */
+ void (*foreachMappedFaceCenter)(DerivedMesh *dm,
+ void (*func)(void *userData, int index,
+ float *cent, float *no),
+ void *userData);
+
+ /* Iterate over all vertex points, calling DO_MINMAX with given args.
+ *
+ * Also called in Editmode
+ */
+ void (*getMinMax)(DerivedMesh *dm, float min_r[3], float max_r[3]);
+
+ /* Direct Access Operations */
+ /* o Can be undefined */
+ /* o Must be defined for modifiers that only deform however */
+
+ /* Get vertex location, undefined if index is not valid */
+ void (*getVertCo)(DerivedMesh *dm, int index, float co_r[3]);
+
+ /* Fill the array (of length .getNumVerts()) with all vertex locations */
+ void (*getVertCos)(DerivedMesh *dm, float (*cos_r)[3]);
+
+ /* Get vertex normal, undefined if index is not valid */
+ void (*getVertNo)(DerivedMesh *dm, int index, float no_r[3]);
+
+ /* Drawing Operations */
+
+ /* Draw all vertices as bgl points (no options) */
+ void (*drawVerts)(DerivedMesh *dm);
+
+ /* Draw edges in the UV mesh (if exists) */
+ void (*drawUVEdges)(DerivedMesh *dm);
+
+ /* Draw all edges as lines (no options)
+ *
+ * Also called for *final* editmode DerivedMeshes
+ */
+ void (*drawEdges)(DerivedMesh *dm, int drawLooseEdges);
+
+ /* Draw all loose edges (edges w/ no adjoining faces) */
+ void (*drawLooseEdges)(DerivedMesh *dm);
+
+ /* Draw all faces
+ * o Set face normal or vertex normal based on inherited face flag
+ * o Use inherited face material index to call setMaterial
+ * o Only if setMaterial returns true
+ *
+ * Also called for *final* editmode DerivedMeshes
+ */
+ void (*drawFacesSolid)(DerivedMesh *dm, int (*setMaterial)(int));
+
+ /* Draw all faces
+ * o If useTwoSided, draw front and back using col arrays
+ * o col1,col2 are arrays of length numFace*4 of 4 component colors
+ * in ABGR format, and should be passed as per-face vertex color.
+ */
+ void (*drawFacesColored)(DerivedMesh *dm, int useTwoSided,
+ unsigned char *col1, unsigned char *col2);
+
+ /* Draw all faces using MTFace
+ * o Drawing options too complicated to enumerate, look at code.
+ */
+ void (*drawFacesTex)(DerivedMesh *dm,
+ int (*setDrawOptions)(struct MTFace *tface,
+ struct MCol *mcol, int matnr));
+
+ /* Draw mapped faces (no color, or texture)
+ * o Only if !setDrawOptions or
+ * setDrawOptions(userData, mapped-face-index, drawSmooth_r)
+ * returns true
+ *
+ * If drawSmooth is set to true then vertex normals should be set and
+ * glShadeModel called with GL_SMOOTH. Otherwise the face normal should
+ * be set and glShadeModel called with GL_FLAT.
+ *
+ * The setDrawOptions is allowed to not set drawSmooth (for example, when
+ * lighting is disabled), in which case the implementation should draw as
+ * smooth shaded.
+ */
+ void (*drawMappedFaces)(DerivedMesh *dm,
+ int (*setDrawOptions)(void *userData, int index,
+ int *drawSmooth_r),
+ void *userData, int useColors);
+
+ /* Draw mapped faces using MTFace
+ * o Drawing options too complicated to enumerate, look at code.
+ */
+ void (*drawMappedFacesTex)(DerivedMesh *dm,
+ int (*setDrawOptions)(void *userData,
+ int index),
+ void *userData);
+
+ /* Draw mapped edges as lines
+ * o Only if !setDrawOptions or setDrawOptions(userData, mapped-edge)
+ * returns true
+ */
+ void (*drawMappedEdges)(DerivedMesh *dm,
+ int (*setDrawOptions)(void *userData, int index),
+ void *userData);
+
+ /* Draw mapped edges as lines with interpolation values
+ * o Only if !setDrawOptions or
+ * setDrawOptions(userData, mapped-edge, mapped-v0, mapped-v1, t)
+ * returns true
+ *
+ * NOTE: This routine is optional!
+ */
+ void (*drawMappedEdgesInterp)(DerivedMesh *dm,
+ int (*setDrawOptions)(void *userData,
+ int index),
+ void (*setDrawInterpOptions)(void *userData,
+ int index,
+ float t),
+ void *userData);
+
+ /* Release reference to the DerivedMesh. This function decides internally
+ * if the DerivedMesh will be freed, or cached for later use. */
+ void (*release)(DerivedMesh *dm);
+};
+
+/* utility function to initialise a DerivedMesh's function pointers to
+ * the default implementation (for those functions which have a default)
+ */
+void DM_init_funcs(DerivedMesh *dm);
+
+/* utility function to initialise a DerivedMesh for the desired number
+ * of vertices, edges and faces (doesn't allocate memory for them, just
+ * sets up the custom data layers)
+ */
+void DM_init(DerivedMesh *dm, int numVerts, int numEdges, int numFaces);
+
+/* utility function to initialise a DerivedMesh for the desired number
+ * of vertices, edges and faces, with a layer setup copied from source
+ */
+void DM_from_template(DerivedMesh *dm, DerivedMesh *source,
+ int numVerts, int numEdges, int numFaces);
+
+/* utility function to release a DerivedMesh's layers
+ * returns 1 if DerivedMesh has to be released by the backend, 0 otherwise
+ */
+int DM_release(DerivedMesh *dm);
+
+/* utility function to convert a DerivedMesh to a Mesh
+ */
+void DM_to_mesh(DerivedMesh *dm, struct Mesh *me);
+
+/* set the CD_FLAG_NOCOPY flag in custom data layers where the mask is
+ * zero for the layer type, so only layer types specified by the mask
+ * will be copied
+ */
+void DM_set_only_copy(DerivedMesh *dm, CustomDataMask mask);
+
+/* adds a vertex/edge/face custom data layer to a DerivedMesh, optionally
+ * backed by an external data array
+ * alloctype defines how the layer is allocated or copied, and how it is
+ * freed, see BKE_customdata.h for the different options
+ */
+void DM_add_vert_layer(struct DerivedMesh *dm, int type, int alloctype,
+ void *layer);
+void DM_add_edge_layer(struct DerivedMesh *dm, int type, int alloctype,
+ void *layer);
+void DM_add_face_layer(struct DerivedMesh *dm, int type, int alloctype,
+ void *layer);
+
+/* custom data access functions
+ * return pointer to data from first layer which matches type
+ * if they return NULL for valid indices, data doesn't exist
+ * note these return pointers - any change modifies the internals of the mesh
+ */
+void *DM_get_vert_data(struct DerivedMesh *dm, int index, int type);
+void *DM_get_edge_data(struct DerivedMesh *dm, int index, int type);
+void *DM_get_face_data(struct DerivedMesh *dm, int index, int type);
+
+/* custom data layer access functions
+ * return pointer to first data layer which matches type (a flat array)
+ * if they return NULL, data doesn't exist
+ * note these return pointers - any change modifies the internals of the mesh
+ */
+void *DM_get_vert_data_layer(struct DerivedMesh *dm, int type);
+void *DM_get_edge_data_layer(struct DerivedMesh *dm, int type);
+void *DM_get_face_data_layer(struct DerivedMesh *dm, int type);
+
+/* custom data setting functions
+ * copy supplied data into first layer of type using layer's copy function
+ * (deep copy if appropriate)
+ */
+void DM_set_vert_data(struct DerivedMesh *dm, int index, int type, void *data);
+void DM_set_edge_data(struct DerivedMesh *dm, int index, int type, void *data);
+void DM_set_face_data(struct DerivedMesh *dm, int index, int type, void *data);
+
+/* custom data copy functions
+ * copy count elements from source_index in source to dest_index in dest
+ * these copy all layers for which the CD_FLAG_NOCOPY flag is not set
+ */
+void DM_copy_vert_data(struct DerivedMesh *source, struct DerivedMesh *dest,
+ int source_index, int dest_index, int count);
+void DM_copy_edge_data(struct DerivedMesh *source, struct DerivedMesh *dest,
+ int source_index, int dest_index, int count);
+void DM_copy_face_data(struct DerivedMesh *source, struct DerivedMesh *dest,
+ int source_index, int dest_index, int count);
+
+/* custom data free functions
+ * free count elements, starting at index
+ * they free all layers for which the CD_FLAG_NOCOPY flag is not set
+ */
+void DM_free_vert_data(struct DerivedMesh *dm, int index, int count);
+void DM_free_edge_data(struct DerivedMesh *dm, int index, int count);
+void DM_free_face_data(struct DerivedMesh *dm, int index, int count);
+
+/* interpolates vertex data from the vertices indexed by src_indices in the
+ * source mesh using the given weights and stores the result in the vertex
+ * indexed by dest_index in the dest mesh
+ */
+void DM_interp_vert_data(struct DerivedMesh *source, struct DerivedMesh *dest,
+ int *src_indices, float *weights,
+ int count, int dest_index);
+
+/* interpolates edge data from the edges indexed by src_indices in the
+ * source mesh using the given weights and stores the result in the edge indexed
+ * by dest_index in the dest mesh.
+ * if weights is NULL, all weights default to 1.
+ * if vert_weights is non-NULL, any per-vertex edge data is interpolated using
+ * vert_weights[i] multiplied by weights[i].
+ */
+typedef float EdgeVertWeight[SUB_ELEMS_EDGE][SUB_ELEMS_EDGE];
+void DM_interp_edge_data(struct DerivedMesh *source, struct DerivedMesh *dest,
+ int *src_indices,
+ float *weights, EdgeVertWeight *vert_weights,
+ int count, int dest_index);
+
+/* interpolates face data from the faces indexed by src_indices in the
+ * source mesh using the given weights and stores the result in the face indexed
+ * by dest_index in the dest mesh.
+ * if weights is NULL, all weights default to 1.
+ * if vert_weights is non-NULL, any per-vertex face data is interpolated using
+ * vert_weights[i] multiplied by weights[i].
+ */
+typedef float FaceVertWeight[SUB_ELEMS_FACE][SUB_ELEMS_FACE];
+void DM_interp_face_data(struct DerivedMesh *source, struct DerivedMesh *dest,
+ int *src_indices,
+ float *weights, FaceVertWeight *vert_weights,
+ int count, int dest_index);
+
+void DM_swap_face_data(struct DerivedMesh *dm, int index, int *corner_indices);
+
+/* Temporary? A function to give a colorband to derivedmesh for vertexcolor ranges */
+void vDM_ColorBand_store(struct ColorBand *coba);
+
+/* Simple function to get me->totvert amount of vertices/normals,
+ correctly deformed and subsurfered. Needed especially when vertexgroups are involved.
+ In use now by vertex/weigt paint and particles */
+float *mesh_get_mapped_verts_nors(struct Object *ob);
+
+ /* */
+DerivedMesh *mesh_get_derived_final(struct Object *ob,
+ CustomDataMask dataMask);
+DerivedMesh *mesh_get_derived_deform(struct Object *ob,
+ CustomDataMask dataMask);
+
+DerivedMesh *mesh_create_derived_for_modifier(struct Object *ob, struct ModifierData *md);
+
+DerivedMesh *mesh_create_derived_render(struct Object *ob,
+ CustomDataMask dataMask);
+/* same as above but wont use render settings */
+DerivedMesh *mesh_create_derived_view(struct Object *ob,
+ CustomDataMask dataMask);
+DerivedMesh *mesh_create_derived_no_deform(struct Object *ob,
+ float (*vertCos)[3],
+ CustomDataMask dataMask);
+DerivedMesh *mesh_create_derived_no_deform_render(struct Object *ob,
+ float (*vertCos)[3],
+ CustomDataMask dataMask);
+
+DerivedMesh *editmesh_get_derived_base(void);
+DerivedMesh *editmesh_get_derived_cage(CustomDataMask dataMask);
+DerivedMesh *editmesh_get_derived_cage_and_final(DerivedMesh **final_r,
+ CustomDataMask dataMask);
+
+/* returns an array of deform matrices for crazyspace correction, and the
+ number of modifiers left */
+int editmesh_get_first_deform_matrices(float (**deformmats)[3][3],
+ float (**deformcos)[3]);
+
+void weight_to_rgb(float input, float *fr, float *fg, float *fb);
+
+/* determines required DerivedMesh data according to view and edit modes */
+CustomDataMask get_viewedit_datamask();
+
+/* repeate this pattern
+ X000X000
+ 00000000
+ 00X000X0
+ 00000000 */
+
+#define DM_FACE_STIPPLE \
+{ \
+ 136,136,136,136,0,0,0,0,34,34,34,34,0,0,0,0, \
+ 136,136,136,136,0,0,0,0,34,34,34,34,0,0,0,0, \
+ 136,136,136,136,0,0,0,0,34,34,34,34,0,0,0,0, \
+ 136,136,136,136,0,0,0,0,34,34,34,34,0,0,0,0, \
+ 136,136,136,136,0,0,0,0,34,34,34,34,0,0,0,0, \
+ 136,136,136,136,0,0,0,0,34,34,34,34,0,0,0,0, \
+ 136,136,136,136,0,0,0,0,34,34,34,34,0,0,0,0, \
+ 136,136,136,136,0,0,0,0,34,34,34,34,0,0,0,0 \
+}
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h
new file mode 100644
index 00000000000..cbec4cf04fb
--- /dev/null
+++ b/source/blender/blenkernel/BKE_action.h
@@ -0,0 +1,164 @@
+/* BKE_action.h May 2001
+ *
+ * Blender kernel action functionality
+ *
+ * Reevan McKay
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Full recode, Ton Roosendaal, Crete 2005
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BKE_ACTION_H
+#define BKE_ACTION_H
+
+#include "DNA_listBase.h"
+
+/**
+ * The following structures are defined in DNA_action_types.h
+ */
+
+struct bAction;
+struct bActionChannel;
+struct bPose;
+struct bPoseChannel;
+struct Object;
+
+/* Kernel prototypes */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * Removes and deallocates all channels from a pose.
+ * Does not free the pose itself.
+ */
+void free_pose_channels(struct bPose *pose);
+
+/**
+ * Allocate a new pose on the heap, and copy the src pose and it's channels
+ * into the new pose. *dst is set to the newly allocated structure, and assumed to be NULL.
+ */
+void copy_pose(struct bPose **dst, struct bPose *src,
+ int copyconstraints);
+
+/**
+ * Deallocate the action's channels including constraint channels.
+ * does not free the action structure.
+ */
+void free_action(struct bAction * id);
+
+void make_local_action(struct bAction *act);
+
+/* only for armatures, doing pose actions only too */
+void do_all_pose_actions(struct Object *);
+/* only for objects, doing only 1 channel */
+void do_all_object_actions(struct Object *);
+/* only for Mesh, Curve, Surface, Lattice, doing only Shape channel */
+void do_all_shape_actions(struct Object *);
+
+
+/**
+ * Return a pointer to the pose channel of the given name
+ * from this pose.
+ */
+struct bPoseChannel *get_pose_channel(const struct bPose *pose,
+ const char *name);
+
+/**
+ * Looks to see if the channel with the given name
+ * already exists in this pose - if not a new one is
+ * allocated and initialized.
+ */
+struct bPoseChannel *verify_pose_channel(struct bPose* pose,
+ const char* name);
+
+/* sets constraint flags */
+void update_pose_constraint_flags(struct bPose *pose);
+
+/* clears BONE_UNKEYED flags for frame changing */
+void framechange_poses_clear_unkeyed(void);
+
+/**
+ * Allocate a new bAction on the heap and copy
+ * the contents of src into it. If src is NULL NULL is returned.
+ */
+
+struct bAction *copy_action(struct bAction *src);
+
+/**
+ * Some kind of bounding box operation on the action.
+ */
+void calc_action_range(const struct bAction *act, float *start, float *end, int incl_hidden);
+
+/**
+ * Set the pose channels from the given action.
+ */
+void extract_pose_from_action(struct bPose *pose, struct bAction *act, float ctime);
+
+/**
+ * Get the effects of the given action using a workob
+ */
+void what_does_obaction(struct Object *ob, struct bAction *act, float cframe);
+
+/**
+ * Iterate through the action channels of the action
+ * and return the channel with the given name.
+ * Returns NULL if no channel.
+ */
+struct bActionChannel *get_action_channel(struct bAction *act, const char *name);
+/**
+ * Iterate through the action channels of the action
+ * and return the channel with the given name.
+ * Returns and adds new channel if no channel.
+ */
+struct bActionChannel *verify_action_channel(struct bAction *act, const char *name);
+
+ /* baking */
+struct bAction *bake_obIPO_to_action(struct Object *ob);
+
+/* exported for game engine */
+void blend_poses(struct bPose *dst, struct bPose *src, float srcweight, short mode);
+void extract_pose_from_pose(struct bPose *pose, const struct bPose *src);
+
+/* for proxy */
+void copy_pose_result(struct bPose *to, struct bPose *from);
+/* clear all transforms */
+void rest_pose(struct bPose *pose);
+
+/* map global time (frame nr) to strip converted time, doesn't clip */
+float get_action_frame(struct Object *ob, float cframe);
+/* map strip time to global time (frame nr) */
+float get_action_frame_inv(struct Object *ob, float cframe);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_anim.h b/source/blender/blenkernel/BKE_anim.h
new file mode 100644
index 00000000000..c7808331d7e
--- /dev/null
+++ b/source/blender/blenkernel/BKE_anim.h
@@ -0,0 +1,61 @@
+/**
+ * blenlib/BKE_anim.h (mar-2001 nzc);
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BKE_ANIM_H
+#define BKE_ANIM_H
+
+struct Path;
+struct Object;
+struct PartEff;
+struct Scene;
+struct ListBase;
+
+typedef struct DupliObject {
+ struct DupliObject *next, *prev;
+ struct Object *ob;
+ unsigned int origlay;
+ int index, no_draw;
+ float mat[4][4], omat[4][4];
+} DupliObject;
+
+void free_path(struct Path *path);
+void calc_curvepath(struct Object *ob);
+int interval_test(int min, int max, int p1, int cycl);
+int where_on_path(struct Object *ob, float ctime, float *vec, float *dir);
+
+struct ListBase *object_duplilist(struct Scene *sce, struct Object *ob);
+void free_object_duplilist(struct ListBase *lb);
+int count_duplilist(struct Object *ob);
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h
new file mode 100644
index 00000000000..fb527051a0d
--- /dev/null
+++ b/source/blender/blenkernel/BKE_armature.h
@@ -0,0 +1,122 @@
+/**
+ * blenlib/BKE_armature.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BKE_ARMATURE_H
+#define BKE_ARMATURE_H
+
+struct Bone;
+struct Main;
+struct bArmature;
+struct bPose;
+struct bPoseChannel;
+struct bConstraint;
+struct Object;
+struct MDeformVert;
+struct Mesh;
+struct PoseTree;
+struct ListBase;
+
+typedef struct PoseTarget
+{
+ struct PoseTarget *next, *prev;
+
+ struct bConstraint *con; /* the constrait of this target */
+ int tip; /* index of tip pchan in PoseTree */
+} PoseTarget;
+
+typedef struct PoseTree
+{
+ struct PoseTree *next, *prev;
+
+ struct ListBase targets; /* list of targets of the tree */
+ struct bPoseChannel **pchan; /* array of pose channels */
+ int *parent; /* and their parents */
+ int totchannel; /* number of pose channels */
+ float (*basis_change)[3][3]; /* basis change result from solver */
+ int iterations; /* iterations from the constraint */
+ int stretch; /* disable stretching */
+} PoseTree;
+
+/* Core armature functionality */
+#ifdef __cplusplus
+extern "C" {
+#endif
+struct bArmature *add_armature(char *name);
+void free_boneChildren(struct Bone *bone);
+void free_bones (struct bArmature *arm);
+void unlink_armature(struct bArmature *arm);
+void free_armature(struct bArmature *arm);
+void make_local_armature(struct bArmature *arm);
+struct bArmature *copy_armature(struct bArmature *arm);
+void bone_flip_name (char *name, int strip_number);
+
+struct bArmature *get_armature (struct Object *ob);
+struct Bone *get_named_bone (struct bArmature *arm, const char *name);
+
+float distfactor_to_bone (float vec[3], float b1[3], float b2[3], float rad1, float rad2, float rdist);
+
+void where_is_armature (struct bArmature *arm);
+void where_is_armature_bone(struct Bone *bone, struct Bone *prevbone);
+void armature_rebuild_pose(struct Object *ob, struct bArmature *arm);
+void where_is_pose (struct Object *ob);
+
+/* get_objectspace_bone_matrix has to be removed still */
+void get_objectspace_bone_matrix (struct Bone* bone, float M_accumulatedMatrix[][4], int root, int posed);
+void vec_roll_to_mat3(float *vec, float roll, float mat[][3]);
+void mat3_to_vec_roll(float mat[][3], float *vec, float *roll);
+
+/* Common Conversions Between Co-ordinate Spaces */
+void armature_mat_world_to_pose(struct Object *ob, float inmat[][4], float outmat[][4]);
+void armature_loc_world_to_pose(struct Object *ob, float *inloc, float *outloc);
+void armature_mat_pose_to_bone(struct bPoseChannel *pchan, float inmat[][4], float outmat[][4]);
+void armature_loc_pose_to_bone(struct bPoseChannel *pchan, float *inloc, float *outloc);
+void armature_mat_pose_to_delta(float delta_mat[][4], float pose_mat[][4], float arm_mat[][4]);
+
+/* Animation functions */
+struct PoseTree *ik_tree_to_posetree(struct Object *ob, struct Bone *bone);
+void solve_posetree(PoseTree *tree);
+void free_posetree(PoseTree *tree);
+
+/* B-Bone support */
+typedef struct Mat4 {
+ float mat[4][4];
+} Mat4;
+
+Mat4 *b_bone_spline_setup(struct bPoseChannel *pchan, int rest);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_bad_level_calls.h b/source/blender/blenkernel/BKE_bad_level_calls.h
new file mode 100644
index 00000000000..b942add80e2
--- /dev/null
+++ b/source/blender/blenkernel/BKE_bad_level_calls.h
@@ -0,0 +1,235 @@
+/**
+ * blenlib/BKE_bad_level_calls.h (mar-2001 nzc)
+ *
+ * Stuff that definitely does not belong in the kernel! These will all
+ * have to be removed in order to restore sanity.
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BKE_BAD_LEVEL_CALLS_H
+#define BKE_BAD_LEVEL_CALLS_H
+
+/* blender.c */
+void freeAllRad(void);
+void free_editText(void);
+void free_vertexpaint(void);
+
+/* readfile.c */
+struct SpaceButs;
+void set_rects_butspace(struct SpaceButs *buts);
+struct SpaceImaSel;
+void check_imasel_copy(struct SpaceImaSel *simasel);
+struct ScrArea;
+struct bScreen;
+void unlink_screen(struct bScreen *sc);
+void setscreen(struct bScreen *sc);
+void force_draw_all(int);
+ /* otherwise the WHILE_SEQ doesn't work */
+struct Sequence;
+struct ListBase;
+void build_seqar(struct ListBase *seqbase, struct Sequence ***seqar, int *totseq);
+
+/* BPython API */
+struct ID;
+struct Script;
+struct Text;
+struct IpoDriver; /* DNA_curve_types.h */
+struct Object;
+struct bPythonConstraint;
+struct bConstraintOb;
+struct bConstraintTarget;
+void BPY_do_pyscript (struct ID *id, short int event);
+void BPY_clear_script (struct Script *script);
+void BPY_free_compiled_text (struct Text *text);
+/* pydrivers */
+struct Object **BPY_pydriver_get_objects(struct IpoDriver *driver);
+float BPY_pydriver_eval(struct IpoDriver *driver);
+void BPY_pydriver_update(void);
+/* button python evaluation */
+int BPY_button_eval(char *expr, double *value);
+/* pyconstraints */
+void BPY_pyconstraint_eval(struct bPythonConstraint *con, struct bConstraintOb *cob, struct ListBase *targets);
+void BPY_pyconstraint_targets(struct bPythonConstraint *con, struct bConstraintTarget *ct);
+
+
+/* writefile.c */
+struct Oops;
+void free_oops(struct Oops *oops);
+void error(char *str, ...);
+
+/* anim.c */
+extern struct ListBase editNurb;
+
+void mainqenter (unsigned short event, short val);
+void waitcursor(int);
+void allqueue(unsigned short event, short val);
+#define REDRAWVIEW3D 0x4010
+#define REDRAWBUTSEDIT 0x4019
+struct Material;
+extern struct Material defmaterial;
+
+
+/* exotic.c */
+void load_editMesh(void);
+void make_editMesh(void);
+struct EditMesh;
+void free_editMesh(struct EditMesh *);
+void free_editArmature(void);
+void docenter_new(void);
+int saveover(char *str);
+
+/* image.c */
+#include "DNA_image_types.h"
+void free_realtime_image(Image *ima); // has to become a callback, opengl stuff
+
+/* ipo.c */
+void copy_view3d_lock(short val); // was a hack, to make scene layer ipo's possible
+
+/* library.c */
+void allspace(unsigned short event, short val) ;
+#define OOPS_TEST 2
+
+/* mball.c */
+extern struct ListBase editelems;
+
+/* object.c */
+struct ScriptLink;
+void BPY_free_scriptlink(struct ScriptLink *slink);
+void BPY_copy_scriptlink(struct ScriptLink *scriptlink);
+float *give_cursor(void); // become a callback or argument
+void exit_posemode(int freedata);
+
+/* packedFile.c */
+short pupmenu(char *instr); // will be general callback
+
+/* sca.c */
+#define LEFTMOUSE 0x001 // because of mouse sensor
+
+/* scene.c */
+#include "DNA_sequence_types.h"
+void free_editing(struct Editing *ed); // scenes and sequences problem...
+void BPY_do_all_scripts (short int event);
+int BPY_call_importloader(char *name);
+
+
+extern char texstr[20][12]; /* buttons.c */
+
+
+/* editsca.c */
+void make_unique_prop_names(char *str);
+
+/* DerivedMesh.c */
+void bglBegin(int mode);
+void bglVertex3fv(float *vec);
+void bglVertex3f(float x, float y, float z);
+void bglEnd(void);
+
+struct Object;
+
+/* booleanops.c */
+struct DerivedMesh *NewBooleanDerivedMesh(struct Object *ob,
+ struct Object *ob_select, int int_op_type);
+
+/* verse_*.c */
+struct VerseVert;
+struct VerseFace;
+struct VerseSession;
+struct VNode;
+struct VTag;
+struct VTagGroup;
+struct VBitmapLayer;
+struct VLink;
+struct VLayer;
+struct Mesh;
+
+void post_vertex_create(struct VerseVert *vvert);
+void post_vertex_set_xyz(struct VerseVert *vvert);
+void post_vertex_delete(struct VerseVert *vvert);
+void post_vertex_free_constraint(struct VerseVert *vvert);
+void post_polygon_create(struct VerseFace *vface);
+void post_polygon_set_corner(struct VerseFace *vface);
+void post_polygon_delete(struct VerseFace *vface);
+void post_polygon_free_constraint(struct VerseFace *vface);
+void post_polygon_set_uint8(struct VerseFace *vface);
+void post_node_create(struct VNode *vnode);
+void post_node_destroy(struct VNode *vnode);
+void post_node_name_set(struct VNode *vnode);
+void post_tag_change(struct VTag *vtag);
+void post_taggroup_create(struct VTagGroup *vtaggroup);
+char *verse_client_name(void);
+void post_transform(struct VNode *vnode);
+void post_transform_pos(struct VNode *vnode);
+void post_transform_rot(struct VNode *vnode);
+void post_transform_scale(struct VNode *vnode);
+void post_object_free_constraint(struct VNode *vnode);
+void post_link_set(struct VLink *vlink);
+void post_link_destroy(struct VLink *vlink);
+void post_connect_accept(struct VerseSession *session);
+void post_connect_terminated(struct VerseSession *session);
+void post_connect_update(struct VerseSession *session);
+void add_screenhandler(struct bScreen *sc, short eventcode, short val);
+void post_bitmap_dimension_set(struct VNode *vnode);
+void post_bitmap_layer_create(struct VBitmapLayer *vblayer);
+void post_bitmap_layer_destroy(struct VBitmapLayer *vblayer);
+void post_bitmap_tile_set(struct VBitmapLayer *vblayer, unsigned int xs, unsigned int ys);
+void create_meshdata_from_geom_node(struct Mesh *me, struct VNode *vnode);
+void post_geometry_free_constraint(struct VNode *vnode);
+void post_layer_create(struct VLayer *vlayer);
+void post_layer_destroy(struct VLayer *vlayer);
+void post_server_add(void);
+
+/* multires.c */
+struct Multires;
+struct MultiresLevel;
+struct MultiresLevel *multires_level_n(struct Multires *mr, int n);
+void multires_free(struct Multires *mr);
+void multires_set_level(struct Object *ob, struct Mesh *me, const int render);
+void multires_update_levels(struct Mesh *me, const int render);
+void multires_calc_level_maps(struct MultiresLevel *lvl);
+struct Multires *multires_copy(struct Multires *orig);
+/* sculptmode.c */
+void sculptmode_free_all(struct Scene *sce);
+void sculptmode_init(struct Scene *sce);
+
+/* zbuf.c */
+void antialias_tagbuf(int xsize, int ysize, char *rectmove);
+
+/* imagetexture.c */
+void ibuf_sample(struct ImBuf *ibuf, float fx, float fy, float dx, float dy, float *result);
+
+/* modifier.c */
+struct MeshDeformModifierData;
+
+void harmonic_coordinates_bind(struct MeshDeformModifierData *mmd,
+ float (*vertexcos)[3], int totvert, float cagemat[][4]);
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h
new file mode 100644
index 00000000000..55a542f51d5
--- /dev/null
+++ b/source/blender/blenkernel/BKE_blender.h
@@ -0,0 +1,79 @@
+/**
+ * blenlib/BKE_blender.h (mar-2001 nzc)
+ *
+ * Blender util stuff?
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BKE_BLENDER_H
+#define BKE_BLENDER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct ListBase;
+struct MemFile;
+
+#define BLENDER_VERSION 245
+#define BLENDER_SUBVERSION 7
+
+#define BLENDER_MINVERSION 240
+#define BLENDER_MINSUBVERSION 0
+
+int BKE_read_file(char *dir, void *type_r);
+int BKE_read_file_from_memory(char* filebuf, int filelength, void *type_r);
+int BKE_read_file_from_memfile(struct MemFile *memfile);
+
+void duplicatelist(struct ListBase *list1, struct ListBase *list2);
+void free_blender(void);
+void initglobals(void);
+
+void pushdata(void *data, int len);
+void popfirst(void *data);
+void poplast(void *data);
+void free_pushpop(void);
+void pushpop_test(void);
+
+/* global undo */
+extern void BKE_write_undo(char *name);
+extern void BKE_undo_step(int step);
+extern void BKE_reset_undo(void);
+extern char *BKE_undo_menu_string(void);
+extern void BKE_undo_number(int nr);
+extern void BKE_undo_save_quit(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_bmfont.h b/source/blender/blenkernel/BKE_bmfont.h
new file mode 100644
index 00000000000..0d42b673769
--- /dev/null
+++ b/source/blender/blenkernel/BKE_bmfont.h
@@ -0,0 +1,65 @@
+/**
+ * blenlib/BKE_bmfont.h (mar-2001 nzc)
+ *
+ *
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BKE_BMFONT_H
+#define BKE_BMFONT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct bmGlyph;
+struct ImBuf;
+struct bmFont;
+
+void printfGlyph(struct bmGlyph * glyph);
+void calcAlpha(struct ImBuf * ibuf);
+void readBitmapFontVersion0(struct ImBuf * ibuf,
+ unsigned char * rect,
+ int step);
+void detectBitmapFont(struct ImBuf *ibuf);
+int locateGlyph(struct bmFont *bmfont, unsigned short unicode);
+void matrixGlyph(struct ImBuf * ibuf, unsigned short unicode,
+ float *centerx, float *centery,
+ float *sizex, float *sizey,
+ float *transx, float *transy,
+ float *movex, float *movey, float *advance);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_bmfont_types.h b/source/blender/blenkernel/BKE_bmfont_types.h
new file mode 100644
index 00000000000..a3bb43b5ca8
--- /dev/null
+++ b/source/blender/blenkernel/BKE_bmfont_types.h
@@ -0,0 +1,62 @@
+/**
+ * blenlib/BKE_bmfont_types.h (mar-2001 nzc)
+ *
+ *
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BKE_BMFONT_TYPES_H
+#define BKE_BMFONT_TYPES_H
+
+#define is_power_of_two(N) ((N ^ (N - 1)) == (2 * N - 1))
+/*
+Moved to IMB_imbuf_types.h where it will live close to the ImBuf type.
+It is used as a userflag bit mask.
+#define IB_BITMAPFONT 1
+*/
+typedef struct bmGlyph {
+ unsigned short unicode;
+ short locx, locy;
+ signed char ofsx, ofsy;
+ unsigned char sizex, sizey;
+ unsigned char advance, reserved;
+} bmGlyph;
+
+typedef struct bmFont {
+ char magic[4];
+ short version;
+ short glyphcount;
+ short xsize, ysize;
+ bmGlyph glyphs[1];
+} bmFont;
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_booleanops.h b/source/blender/blenkernel/BKE_booleanops.h
new file mode 100644
index 00000000000..4e98c81c067
--- /dev/null
+++ b/source/blender/blenkernel/BKE_booleanops.h
@@ -0,0 +1,52 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BKE_BOOLEANOPS_H
+#define BKE_BOOLEANOPS_H
+
+struct Object;
+struct Base;
+struct DerivedMesh;
+
+/* Performs a boolean between two mesh objects, it is assumed that both objects
+ are in fact a mesh object. On success returns 1 and creates a new mesh object
+ into blender data structures. On failure returns 0 and reports an error. */
+int NewBooleanMesh(struct Base *base, struct Base *base_select, int op);
+
+
+/* Performs a boolean between two mesh objects, it is assumed that both objects
+ are in fact mesh object. On success returns a DerivedMesh. On failure
+ returns NULL and reports an error. */
+struct DerivedMesh *NewBooleanDerivedMesh(struct Object *ob,
+ struct Object *ob_select,
+ int op);
+#endif
+
diff --git a/source/blender/blenkernel/BKE_booleanops_mesh.h b/source/blender/blenkernel/BKE_booleanops_mesh.h
new file mode 100644
index 00000000000..7b0e703da04
--- /dev/null
+++ b/source/blender/blenkernel/BKE_booleanops_mesh.h
@@ -0,0 +1,120 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BKE_PyBooleanOps_h
+#define BKE_PyBooleanOps_h
+
+#include "CSG_BooleanOps.h"
+
+/**
+ * Internal mesh structure.
+ * Safe to copy by value... hopefully.
+ */
+
+struct Base;
+struct Object;
+struct CSG_MeshDescriptor;
+
+typedef void (*CSG_DestroyMeshFunc)(struct CSG_MeshDescriptor *);
+
+typedef struct CSG_MeshDescriptor {
+ struct Base *base; // Ptr to base of original blender object - used in creating a new object
+ CSG_MeshPropertyDescriptor m_descriptor;
+ CSG_FaceIteratorDescriptor m_face_iterator;
+ CSG_VertexIteratorDescriptor m_vertex_iterator;
+ CSG_DestroyMeshFunc m_destroy_func;
+} CSG_MeshDescriptor;
+
+
+extern
+ int
+CSG_LoadBlenderMesh(
+ struct Object * obj,
+ CSG_MeshDescriptor *output
+);
+
+/**
+ * Destroy the contents of a mesh descriptor.
+ * If the internal descriptor refers to a blender
+ * mesh, no action is performed apart from freeing
+ * internal memory in the desriptor.
+ */
+
+extern
+ void
+CSG_DestroyMeshDescriptor(
+ CSG_MeshDescriptor *mesh
+);
+
+/**
+ * Perform a boolean operation between 2 meshes and return the
+ * result as a new mesh descriptor.
+ * op_type is an integer code of the boolean operation type.
+ * 1 = intersection,
+ * 2 = union,
+ * 3 = difference.
+ */
+
+extern
+ int
+CSG_PerformOp(
+ CSG_MeshDescriptor *mesh1,
+ CSG_MeshDescriptor *mesh2,
+ int op_type,
+ CSG_MeshDescriptor *output
+);
+
+
+
+/**
+ * Add a mesh to blender as a new object.
+ */
+
+extern
+ int
+CSG_AddMeshToBlender(
+ CSG_MeshDescriptor *mesh
+);
+
+/**
+ * Test functionality.
+ */
+
+extern
+ int
+NewBooleanMeshTest(
+ struct Base * base,
+ struct Base * base_select,
+ int op_type
+);
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h
new file mode 100644
index 00000000000..2c0034ad234
--- /dev/null
+++ b/source/blender/blenkernel/BKE_brush.h
@@ -0,0 +1,77 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * General operations for brushes.
+ */
+
+#ifndef BKE_BRUSH_H
+#define BKE_BRUSH_H
+
+struct ID;
+struct Brush;
+struct ImBuf;
+
+/* datablock functions */
+struct Brush *add_brush(char *name);
+struct Brush *copy_brush(struct Brush *brush);
+void make_local_brush(struct Brush *brush);
+void free_brush(struct Brush *brush);
+
+/* brush library operations used by different paint panels */
+int brush_set_nr(struct Brush **current_brush, int nr);
+int brush_delete(struct Brush **current_brush);
+void brush_check_exists(struct Brush **brush);
+void brush_toggle_fake_user(struct Brush *brush);
+int brush_texture_set_nr(struct Brush *brush, int nr);
+int brush_texture_delete(struct Brush *brush);
+int brush_clone_image_set_nr(struct Brush *brush, int nr);
+int brush_clone_image_delete(struct Brush *brush);
+
+/* sampling */
+float brush_sample_falloff(struct Brush *brush, float dist);
+void brush_sample_tex(struct Brush *brush, float *xy, float *rgba);
+void brush_imbuf_new(struct Brush *brush, short flt, short texfalloff, int size,
+ struct ImBuf **imbuf);
+
+/* painting */
+struct BrushPainter;
+typedef struct BrushPainter BrushPainter;
+typedef int (*BrushFunc)(void *user, struct ImBuf *ibuf, float *lastpos, float *pos);
+
+BrushPainter *brush_painter_new(struct Brush *brush);
+void brush_painter_require_imbuf(BrushPainter *painter, short flt,
+ short texonly, int size);
+int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos,
+ double time, float pressure, void *user);
+void brush_painter_break_stroke(BrushPainter *painter);
+void brush_painter_free(BrushPainter *painter);
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_cdderivedmesh.h b/source/blender/blenkernel/BKE_cdderivedmesh.h
new file mode 100644
index 00000000000..a570b4fe598
--- /dev/null
+++ b/source/blender/blenkernel/BKE_cdderivedmesh.h
@@ -0,0 +1,109 @@
+/*
+* $Id$
+*
+* ***** BEGIN GPL LICENSE BLOCK *****
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*
+* The Original Code is Copyright (C) 2006 Blender Foundation.
+* All rights reserved.
+*
+* The Original Code is: all of this file.
+*
+* Contributor(s): Ben Batt <benbatt@gmail.com>
+*
+* ***** END GPL LICENSE BLOCK *****
+*/
+
+/* CDDerivedMesh interface.
+ * CDDerivedMesh (CD = Custom Data) is a DerivedMesh backend which stores
+ * mesh elements (vertices, edges and faces) as layers of custom element data.
+ */
+
+#ifndef BKE_CDDERIVEDMESH_H
+#define BKE_CDDERIVEDMESH_H
+
+#include "BKE_DerivedMesh.h"
+
+struct DerivedMesh;
+struct EditMesh;
+struct Mesh;
+struct Object;
+
+/* creates a new CDDerivedMesh */
+struct DerivedMesh *CDDM_new(int numVerts, int numEdges, int numFaces);
+
+/* creates a CDDerivedMesh from the given Mesh, this will reference the
+ original data in Mesh, but it is safe to apply vertex coordinates or
+ calculate normals as those functions will automtically create new
+ data to not overwrite the original */
+struct DerivedMesh *CDDM_from_mesh(struct Mesh *mesh, struct Object *ob);
+
+/* creates a CDDerivedMesh from the given EditMesh */
+struct DerivedMesh *CDDM_from_editmesh(struct EditMesh *em, struct Mesh *me);
+
+/* Copies the given DerivedMesh with verts, faces & edges stored as
+ * custom element data.
+ */
+struct DerivedMesh *CDDM_copy(struct DerivedMesh *dm);
+
+/* creates a CDDerivedMesh with the same layer stack configuration as the
+ * given DerivedMesh and containing the requested numbers of elements.
+ * elements are initialised to all zeros
+ */
+struct DerivedMesh *CDDM_from_template(struct DerivedMesh *source,
+ int numVerts, int numEdges, int numFaces);
+
+/* applies vertex coordinates or normals to a CDDerivedMesh. if the MVert
+ * layer is a referenced layer, it will be duplicate to not overwrite the
+ * original
+ */
+void CDDM_apply_vert_coords(struct DerivedMesh *cddm, float (*vertCoords)[3]);
+void CDDM_apply_vert_normals(struct DerivedMesh *cddm, short (*vertNormals)[3]);
+
+/* recalculates vertex and face normals for a CDDerivedMesh
+ */
+void CDDM_calc_normals(struct DerivedMesh *dm);
+
+/* calculates edges for a CDDerivedMesh (from face data)
+ * this completely replaces the current edge data in the DerivedMesh
+ */
+void CDDM_calc_edges(struct DerivedMesh *dm);
+
+/* lowers the number of vertices/edges/faces in a CDDerivedMesh
+ * the layer data stays the same size
+ */
+void CDDM_lower_num_verts(struct DerivedMesh *dm, int numVerts);
+void CDDM_lower_num_edges(struct DerivedMesh *dm, int numEdges);
+void CDDM_lower_num_faces(struct DerivedMesh *dm, int numFaces);
+
+/* vertex/edge/face access functions
+ * should always succeed if index is within bounds
+ * note these return pointers - any change modifies the internals of the mesh
+ */
+struct MVert *CDDM_get_vert(struct DerivedMesh *dm, int index);
+struct MEdge *CDDM_get_edge(struct DerivedMesh *dm, int index);
+struct MFace *CDDM_get_face(struct DerivedMesh *dm, int index);
+
+/* vertex/edge/face array access functions - return the array holding the
+ * desired data
+ * should always succeed
+ * note these return pointers - any change modifies the internals of the mesh
+ */
+struct MVert *CDDM_get_verts(struct DerivedMesh *dm);
+struct MEdge *CDDM_get_edges(struct DerivedMesh *dm);
+struct MFace *CDDM_get_faces(struct DerivedMesh *dm);
+#endif
+
diff --git a/source/blender/blenkernel/BKE_colortools.h b/source/blender/blenkernel/BKE_colortools.h
new file mode 100644
index 00000000000..e78882220a9
--- /dev/null
+++ b/source/blender/blenkernel/BKE_colortools.h
@@ -0,0 +1,62 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BKE_COLORTOOLS_H
+#define BKE_COLORTOOLS_H
+
+struct CurveMapping;
+struct CurveMap;
+struct ImBuf;
+struct rctf;
+
+struct CurveMapping *curvemapping_add(int tot, float minx, float miny, float maxx, float maxy);
+void curvemapping_free(struct CurveMapping *cumap);
+struct CurveMapping *curvemapping_copy(struct CurveMapping *cumap);
+void curvemapping_set_black_white(struct CurveMapping *cumap, float *black, float *white);
+
+void curvemap_remove(struct CurveMap *cuma, int flag);
+void curvemap_insert(struct CurveMap *cuma, float x, float y);
+void curvemap_reset(struct CurveMap *cuma, struct rctf *clipr);
+void curvemap_sethandle(struct CurveMap *cuma, int type);
+
+void curvemapping_changed(struct CurveMapping *cumap, int rem_doubles);
+
+ /* single curve, no table check */
+float curvemap_evaluateF(struct CurveMap *cuma, float value);
+ /* single curve, with table check */
+float curvemapping_evaluateF(struct CurveMapping *cumap, int cur, float value);
+void curvemapping_evaluate3F(struct CurveMapping *cumap, float *vecout, const float *vecin);
+void curvemapping_evaluateRGBF(struct CurveMapping *cumap, float *vecout, const float *vecin);
+void curvemapping_evaluate_premulRGBF(struct CurveMapping *cumap, float *vecout, const float *vecin);
+void curvemapping_do_ibuf(struct CurveMapping *cumap, struct ImBuf *ibuf);
+void curvemapping_premultiply(struct CurveMapping *cumap, int restore);
+int curvemapping_RGBA_does_something(struct CurveMapping *cumap);
+void curvemapping_initialize(struct CurveMapping *cumap);
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_constraint.h b/source/blender/blenkernel/BKE_constraint.h
new file mode 100644
index 00000000000..aa8e9cf18f8
--- /dev/null
+++ b/source/blender/blenkernel/BKE_constraint.h
@@ -0,0 +1,140 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): 2007 - Joshua Leung (major recode)
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BKE_CONSTRAINT_H
+#define BKE_CONSTRAINT_H
+
+struct bConstraint;
+struct bConstraintTarget;
+struct ListBase;
+struct Object;
+struct bConstraintChannel;
+struct bPoseChannel;
+
+/* ---------------------------------------------------------------------------- */
+
+/* special struct for use in constraint evaluation */
+typedef struct bConstraintOb {
+ struct Object *ob; /* if pchan, then armature that it comes from, otherwise constraint owner */
+ struct bPoseChannel *pchan; /* pose channel that owns the constraints being evaluated */
+
+ float matrix[4][4]; /* matrix where constraints are accumulated + solved */
+ float startmat[4][4]; /* original matrix (before constraint solving) */
+
+ short type; /* type of owner */
+} bConstraintOb;
+
+/* ---------------------------------------------------------------------------- */
+
+/* Constraint Type-Info (shorthand in code = cti):
+ * This struct provides function pointers for runtime, so that functions can be
+ * written more generally (with fewer/no special exceptions for various constraints).
+ *
+ * Callers of these functions must check that they actually point to something useful,
+ * as some constraints don't define some of these.
+ *
+ * Warning: it is not too advisable to reorder order of members of this struct,
+ * as you'll have to edit quite a few ($NUM_CONSTRAINT_TYPES) of these
+ * structs.
+ */
+typedef struct bConstraintTypeInfo {
+ /* admin/ident */
+ short type; /* CONSTRAINT_TYPE_### */
+ short size; /* size in bytes of the struct */
+ char name[32]; /* name constraint in interface */
+ char structName[32]; /* name of struct for SDNA */
+
+ /* data management function pointers - special handling */
+ /* free any data that is allocated separately (optional) */
+ void (*free_data)(struct bConstraint *con);
+ /* adjust pointer to other ID-data using ID_NEW(), but not to targets (optional) */
+ void (*relink_data)(struct bConstraint *con);
+ /* copy any special data that is allocated separately (optional) */
+ void (*copy_data)(struct bConstraint *con, struct bConstraint *src);
+ /* set settings for data that will be used for bConstraint.data (memory already allocated) */
+ void (*new_data)(void *cdata);
+
+ /* target handling function pointers */
+ /* for multi-target constraints: return that list; otherwise make a temporary list */
+ void (*get_constraint_targets)(struct bConstraint *con, struct ListBase *list);
+ /* for single-target constraints only: flush data back to source data, and the free memory used */
+ void (*flush_constraint_targets)(struct bConstraint *con, struct ListBase *list, short nocopy);
+
+ /* evaluation */
+ /* set the ct->matrix for the given constraint target (at the given ctime) */
+ void (*get_target_matrix)(struct bConstraint *con, struct bConstraintOb *cob, struct bConstraintTarget *ct, float ctime);
+ /* evaluate the constraint for the given time */
+ void (*evaluate_constraint)(struct bConstraint *con, struct bConstraintOb *cob, struct ListBase *targets);
+} bConstraintTypeInfo;
+
+/* Function Prototypes for bConstraintTypeInfo's */
+bConstraintTypeInfo *constraint_get_typeinfo(struct bConstraint *con);
+bConstraintTypeInfo *get_constraint_typeinfo(int type);
+
+/* ---------------------------------------------------------------------------- */
+/* Useful macros for testing various common flag combinations */
+
+/* Constraint Target Macros */
+#define VALID_CONS_TARGET(ct) ((ct) && (ct->tar))
+
+
+/* ---------------------------------------------------------------------------- */
+
+/* Constraint function prototypes */
+void unique_constraint_name(struct bConstraint *con, struct ListBase *list);
+
+void free_constraints(struct ListBase *conlist);
+void copy_constraints(struct ListBase *dst, struct ListBase *src);
+void relink_constraints(struct ListBase *list);
+void free_constraint_data(struct bConstraint *con);
+
+
+/* Constraint Channel function prototypes */
+struct bConstraintChannel *get_constraint_channel(struct ListBase *list, const char *name);
+struct bConstraintChannel *verify_constraint_channel(struct ListBase *list, const char *name);
+void do_constraint_channels(struct ListBase *conbase, struct ListBase *chanbase, float ctime, short onlydrivers);
+void copy_constraint_channels(struct ListBase *dst, struct ListBase *src);
+void clone_constraint_channels(struct ListBase *dst, struct ListBase *src);
+void free_constraint_channels(struct ListBase *chanbase);
+
+/* Constraint Evaluation function prototypes */
+struct bConstraintOb *constraints_make_evalob(struct Object *ob, void *subdata, short datatype);
+void constraints_clear_evalob(struct bConstraintOb *cob);
+
+void constraint_mat_convertspace(struct Object *ob, struct bPoseChannel *pchan, float mat[][4], short from, short to);
+
+void get_constraint_target_matrix(struct bConstraint *con, int n, short ownertype, void *ownerdata, float mat[][4], float ctime);
+void solve_constraints(struct ListBase *conlist, struct bConstraintOb *cob, float ctime);
+
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h
new file mode 100644
index 00000000000..ee63f678505
--- /dev/null
+++ b/source/blender/blenkernel/BKE_curve.h
@@ -0,0 +1,91 @@
+/**
+ * blenlib/BKE_curve.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BKE_CURVE_H
+#define BKE_CURVE_H
+
+struct Curve;
+struct ListBase;
+struct Object;
+struct Nurb;
+struct ListBase;
+struct BezTriple;
+struct BevList;
+
+#define KNOTSU(nu) ( (nu)->orderu+ (nu)->pntsu+ (nu->orderu-1)*((nu)->flagu & 1) )
+#define KNOTSV(nu) ( (nu)->orderv+ (nu)->pntsv+ (nu->orderv-1)*((nu)->flagv & 1) )
+
+
+void unlink_curve( struct Curve *cu);
+void free_curve( struct Curve *cu);
+struct Curve *add_curve(char *name, int type);
+struct Curve *copy_curve( struct Curve *cu);
+void make_local_curve( struct Curve *cu);
+short curve_type( struct Curve *cu);
+void test_curve_type( struct Object *ob);
+void tex_space_curve( struct Curve *cu);
+int count_curveverts( struct ListBase *nurb);
+int count_curveverts_without_handles( struct ListBase *nurb);
+void freeNurb( struct Nurb *nu);
+void freeNurblist( struct ListBase *lb);
+struct Nurb *duplicateNurb( struct Nurb *nu);
+void duplicateNurblist( struct ListBase *lb1, struct ListBase *lb2);
+void test2DNurb( struct Nurb *nu);
+void minmaxNurb( struct Nurb *nu, float *min, float *max);
+
+void makeknots( struct Nurb *nu, short uv, short type);
+
+void makeNurbfaces( struct Nurb *nu, float *data, int rowstride);
+void makeNurbcurve( struct Nurb *nu, float *data, int resolu, int dim);
+void forward_diff_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride);
+float *make_orco_curve( struct Object *ob);
+float *make_orco_surf( struct Object *ob);
+void makebevelcurve( struct Object *ob, struct ListBase *disp);
+
+void makeBevelList( struct Object *ob);
+float calc_curve_subdiv_radius( struct Curve *cu, struct Nurb *nu, int cursubdiv);
+
+void calchandleNurb( struct BezTriple *bezt, struct BezTriple *prev, struct BezTriple *next, int mode);
+void calchandlesNurb( struct Nurb *nu);
+void testhandlesNurb( struct Nurb *nu);
+void autocalchandlesNurb( struct Nurb *nu, int flag);
+void autocalchandlesNurb_all(int flag);
+void sethandlesNurb(short code);
+
+void switchdirectionNurb( struct Nurb *nu);
+
+float (*curve_getVertexCos(struct Curve *cu, struct ListBase *lb, int *numVerts_r))[3];
+void curve_applyVertexCos(struct Curve *cu, struct ListBase *lb, float (*vertexCos)[3]);
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h
new file mode 100644
index 00000000000..d0535f1752e
--- /dev/null
+++ b/source/blender/blenkernel/BKE_customdata.h
@@ -0,0 +1,244 @@
+/*
+* $Id$
+*
+* ***** BEGIN GPL LICENSE BLOCK *****
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*
+* The Original Code is Copyright (C) 2006 Blender Foundation.
+* All rights reserved.
+*
+* The Original Code is: all of this file.
+*
+* Contributor(s): Ben Batt <benbatt@gmail.com>
+*
+* ***** END GPL LICENSE BLOCK *****
+*/
+
+/* CustomData interface, see also DNA_customdata_types.h. */
+
+#ifndef BKE_CUSTOMDATA_H
+#define BKE_CUSTOMDATA_H
+
+struct CustomData;
+struct CustomDataLayer;
+typedef long CustomDataMask;
+
+extern const CustomDataMask CD_MASK_BAREMESH;
+extern const CustomDataMask CD_MASK_MESH;
+extern const CustomDataMask CD_MASK_EDITMESH;
+extern const CustomDataMask CD_MASK_DERIVEDMESH;
+
+/* for ORIGINDEX layer type, indicates no original index for this element */
+#define ORIGINDEX_NONE -1
+
+/* initialises a CustomData object with the same layer setup as source and
+ * memory space for totelem elements. mask must be an array of length
+ * CD_NUMTYPES elements, that indicate if a layer can be copied. */
+
+/* add/copy/merge allocation types */
+#define CD_ASSIGN 0 /* use the data pointer */
+#define CD_CALLOC 1 /* allocate blank memory */
+#define CD_DEFAULT 2 /* allocate and set to default */
+#define CD_REFERENCE 3 /* use data pointers, set layer flag NOFREE */
+#define CD_DUPLICATE 4 /* do a full copy of all layers, only allowed if source
+ has same number of elements */
+
+/* initialises a CustomData object with the same layer setup as source.
+ * mask is a bitfield where (mask & (1 << (layer type))) indicates
+ * if a layer should be copied or not. alloctype must be one of the above. */
+void CustomData_copy(const struct CustomData *source, struct CustomData *dest,
+ CustomDataMask mask, int alloctype, int totelem);
+
+/* same as the above, except that this will preserve existing layers, and only
+ * add the layers that were not there yet */
+void CustomData_merge(const struct CustomData *source, struct CustomData *dest,
+ CustomDataMask mask, int alloctype, int totelem);
+
+/* frees data associated with a CustomData object (doesn't free the object
+ * itself, though)
+ */
+void CustomData_free(struct CustomData *data, int totelem);
+
+/* frees all layers with CD_FLAG_TEMPORARY */
+void CustomData_free_temporary(struct CustomData *data, int totelem);
+
+/* adds a data layer of the given type to the CustomData object, optionally
+ * backed by an external data array. the different allocation types are
+ * defined above. returns the data of the layer.
+ *
+ * in editmode, use EM_add_data_layer instead of this function
+ */
+void *CustomData_add_layer(struct CustomData *data, int type, int alloctype,
+ void *layer, int totelem);
+/*same as above but accepts a name */
+void *CustomData_add_layer_named(struct CustomData *data, int type, int alloctype,
+ void *layer, int totelem, char *name);
+
+/* frees the active or first data layer with the give type.
+ * returns 1 on succes, 0 if no layer with the given type is found
+ *
+ * in editmode, use EM_free_data_layer instead of this function
+ */
+int CustomData_free_layer(struct CustomData *data, int type, int totelem, int index);
+
+/* frees the layer index with the give type.
+ * returns 1 on succes, 0 if no layer with the given type is found
+ *
+ * in editmode, use EM_free_data_layer instead of this function
+ */
+int CustomData_free_layer_active(struct CustomData *data, int type, int totelem);
+
+/* same as above, but free all layers with type */
+void CustomData_free_layers(struct CustomData *data, int type, int totelem);
+
+/* returns 1 if a layer with the specified type exists */
+int CustomData_has_layer(const struct CustomData *data, int type);
+
+/* returns the number of layers with this type */
+int CustomData_number_of_layers(const struct CustomData *data, int type);
+
+/* duplicate data of a layer with flag NOFREE, and remove that flag.
+ * returns the layer data */
+void *CustomData_duplicate_referenced_layer(struct CustomData *data, int type);
+void *CustomData_duplicate_referenced_layer_named(struct CustomData *data,
+ int type, char *name);
+
+/* set the CD_FLAG_NOCOPY flag in custom data layers where the mask is
+ * zero for the layer type, so only layer types specified by the mask
+ * will be copied
+ */
+void CustomData_set_only_copy(const struct CustomData *data,
+ CustomDataMask mask);
+
+/* copies data from one CustomData object to another
+ * objects need not be compatible, each source layer is copied to the
+ * first dest layer of correct type (if there is none, the layer is skipped)
+ * return 1 on success, 0 on failure
+ */
+void CustomData_copy_data(const struct CustomData *source,
+ struct CustomData *dest, int source_index,
+ int dest_index, int count);
+void CustomData_em_copy_data(const struct CustomData *source,
+ struct CustomData *dest, void *src_block,
+ void **dest_block);
+
+/* frees data in a CustomData object
+ * return 1 on success, 0 on failure
+ */
+void CustomData_free_elem(struct CustomData *data, int index, int count);
+
+/* interpolates data from one CustomData object to another
+ * objects need not be compatible, each source layer is interpolated to the
+ * first dest layer of correct type (if there is none, the layer is skipped)
+ * if weights == NULL or sub_weights == NULL, they default to all 1's
+ *
+ * src_indices gives the source elements to interpolate from
+ * weights gives the weight for each source element
+ * sub_weights is an array of matrices of weights for sub-elements (matrices
+ * should be source->subElems * source->subElems in size)
+ * count gives the number of source elements to interpolate from
+ * dest_index gives the dest element to write the interpolated value to
+ *
+ * returns 1 on success, 0 on failure
+ */
+void CustomData_interp(const struct CustomData *source, struct CustomData *dest,
+ int *src_indices, float *weights, float *sub_weights,
+ int count, int dest_index);
+void CustomData_em_interp(struct CustomData *data, void **src_blocks,
+ float *weights, float *sub_weights, int count,
+ void *dest_block);
+
+/* swaps the data in the element corners, to new corners with indices as
+ specified in corner_indices. for edges this is an array of length 2, for
+ faces an array of length 4 */
+void CustomData_swap(struct CustomData *data, int index, int *corner_indices);
+
+/* gets a pointer to the data element at index from the first layer of type
+ * returns NULL if there is no layer of type
+ */
+void *CustomData_get(const struct CustomData *data, int index, int type);
+void *CustomData_em_get(const struct CustomData *data, void *block, int type);
+void *CustomData_em_get_n(const struct CustomData *data, void *block, int type, int n);
+
+/* gets a pointer to the active or first layer of type
+ * returns NULL if there is no layer of type
+ */
+void *CustomData_get_layer(const struct CustomData *data, int type);
+void *CustomData_get_layer_n(const struct CustomData *data, int type, int n);
+void *CustomData_get_layer_named(const struct CustomData *data, int type,
+ char *name);
+
+int CustomData_get_layer_index(const struct CustomData *data, int type);
+int CustomData_get_named_layer_index(const struct CustomData *data, int type, char *name);
+int CustomData_get_active_layer_index(const struct CustomData *data, int type);
+int CustomData_get_render_layer_index(const struct CustomData *data, int type);
+int CustomData_get_active_layer(const struct CustomData *data, int type);
+int CustomData_get_render_layer(const struct CustomData *data, int type);
+
+/* copies the data from source to the data element at index in the first
+ * layer of type
+ * no effect if there is no layer of type
+ */
+void CustomData_set(const struct CustomData *data, int index, int type,
+ void *source);
+void CustomData_em_set(struct CustomData *data, void *block, int type,
+ void *source);
+void CustomData_em_set_n(struct CustomData *data, void *block, int type, int n,
+ void *source);
+
+/* set the pointer of to the first layer of type. the old data is not freed.
+ * returns the value of ptr if the layer is found, NULL otherwise
+ */
+void *CustomData_set_layer(const struct CustomData *data, int type, void *ptr);
+void *CustomData_set_layer_n(const struct CustomData *data, int type, int n, void *ptr);
+
+/* sets the nth layer of type as active */
+void CustomData_set_layer_active(struct CustomData *data, int type, int n);
+void CustomData_set_layer_render(struct CustomData *data, int type, int n);
+
+/* same as above but works with an index from CustomData_get_layer_index */
+void CustomData_set_layer_active_index(struct CustomData *data, int type, int n);
+void CustomData_set_layer_render_index(struct CustomData *data, int type, int n);
+
+/* adds flag to the layer flags */
+void CustomData_set_layer_flag(struct CustomData *data, int type, int flag);
+
+/* alloc/free a block of custom data attached to one element in editmode */
+void CustomData_em_set_default(struct CustomData *data, void **block);
+void CustomData_em_free_block(struct CustomData *data, void **block);
+
+/* copy custom data to/from layers as in mesh/derivedmesh, to editmesh
+ blocks of data. the CustomData's must not be compatible */
+void CustomData_to_em_block(const struct CustomData *source,
+ struct CustomData *dest, int index, void **block);
+void CustomData_from_em_block(const struct CustomData *source,
+ struct CustomData *dest, void *block, int index);
+
+/* query info over types */
+void CustomData_file_write_info(int type, char **structname, int *structnum);
+int CustomData_sizeof(int type);
+
+/* get the name of a layer type */
+const char *CustomData_layertype_name(int type);
+
+/* make sure the name of layer at index is unique */
+void CustomData_set_layer_unique_name(struct CustomData *data, int index);
+
+/* for file reading compatibility, returns false if the layer was freed,
+ only after this test passes, layer->data should be assigned */
+int CustomData_verify_versions(struct CustomData *data, int index);
+
+#endif
diff --git a/source/blender/blenkernel/BKE_deform.h b/source/blender/blenkernel/BKE_deform.h
new file mode 100644
index 00000000000..67e2a8948d5
--- /dev/null
+++ b/source/blender/blenkernel/BKE_deform.h
@@ -0,0 +1,53 @@
+/* BKE_deform.h June 2001
+ *
+ * support for deformation groups and hooks
+ *
+ * Reevan McKay et al
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BKE_DEFORM_H
+#define BKE_DEFORM_H
+
+struct Object;
+struct ListBase;
+struct bDeformGroup;
+
+void copy_defgroups (struct ListBase *lb1, struct ListBase *lb2);
+struct bDeformGroup *copy_defgroup (struct bDeformGroup *ingroup);
+struct bDeformGroup *get_named_vertexgroup (Object *ob, char *name);
+int get_defgroup_num (struct Object *ob, struct bDeformGroup *dg);
+int get_named_vertexgroup_num (Object *ob, char *name);
+void unique_vertexgroup_name (struct bDeformGroup *dg, struct Object *ob);
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_depsgraph.h b/source/blender/blenkernel/BKE_depsgraph.h
new file mode 100644
index 00000000000..294f61e54bd
--- /dev/null
+++ b/source/blender/blenkernel/BKE_depsgraph.h
@@ -0,0 +1,113 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef DEPSGRAPH_API
+#define DEPSGRAPH_API
+
+/*
+#define DEPS_DEBUG
+*/
+
+struct Scene;
+struct DagNodeQueue;
+struct DagForest;
+struct DagNode;
+
+/* **** DAG relation types *** */
+
+ /* scene link to object */
+#define DAG_RL_SCENE 1
+ /* object link to data */
+#define DAG_RL_DATA 2
+
+ /* object changes object (parent, track, constraints) */
+#define DAG_RL_OB_OB 4
+ /* object changes obdata (hooks, constraints) */
+#define DAG_RL_OB_DATA 8
+ /* data changes object (vertex parent) */
+#define DAG_RL_DATA_OB 16
+ /* data changes data (deformers) */
+#define DAG_RL_DATA_DATA 32
+
+#define DAG_NO_RELATION 64
+#define DAG_RL_ALL 63
+#define DAG_RL_ALL_BUT_DATA 61
+
+
+typedef void (*graph_action_func)(void * ob, void **data);
+
+// queues are returned by all BFS & DFS queries
+// opaque type
+void *pop_ob_queue(struct DagNodeQueue *queue);
+int queue_count(struct DagNodeQueue *queue);
+void queue_delete(struct DagNodeQueue *queue);
+
+// queries
+struct DagForest *build_dag(struct Scene *sce, short mask);
+void free_forest(struct DagForest *Dag);
+
+// note :
+// the meanings of the 2 returning values is a bit different :
+// BFS return 1 for cross-edges and back-edges. the latter are considered harmfull, not the former
+// DFS return 1 only for back-edges
+int pre_and_post_BFS(struct DagForest *dag, short mask, graph_action_func pre_func, graph_action_func post_func, void **data);
+int pre_and_post_DFS(struct DagForest *dag, short mask, graph_action_func pre_func, graph_action_func post_func, void **data);
+
+int pre_and_post_source_BFS(struct DagForest *dag, short mask, struct DagNode *source, graph_action_func pre_func, graph_action_func post_func, void **data);
+int pre_and_post_source_DFS(struct DagForest *dag, short mask, struct DagNode *source, graph_action_func pre_func, graph_action_func post_func, void **data);
+
+struct DagNodeQueue *get_obparents(struct DagForest *dag, void *ob);
+struct DagNodeQueue *get_first_ancestors(struct DagForest *dag, void *ob);
+struct DagNodeQueue *get_all_childs(struct DagForest *dag, void *ob); //
+short are_obs_related(struct DagForest *dag, void *ob1, void *ob2);
+int is_acyclic(struct DagForest *dag); //
+//int get_cycles(struct DagForest *dag, struct DagNodeQueue **queues, int *count); //
+
+void boundbox_deps(void);
+void draw_all_deps(void);
+
+/* ********** API *************** */
+/* Note that the DAG never executes changes in Objects, only sets flags in Objects */
+
+void DAG_scene_sort(struct Scene *sce);
+
+ /* flag all objects that need recalc because they're animated */
+void DAG_scene_update_flags(struct Scene *sce, unsigned int lay);
+ /* flag all objects that need recalc because they're animated, influencing this object only */
+void DAG_object_update_flags(struct Scene *sce, struct Object *ob, unsigned int lay);
+
+ /* flushes all recalc flags in objects down the dependency tree */
+void DAG_scene_flush_update(struct Scene *sce, unsigned int lay);
+ /* flushes all recalc flags for this object down the dependency tree */
+void DAG_object_flush_update(struct Scene *sce, struct Object *ob, short flag);
+
+void DAG_pose_sort(struct Object *ob);
+
+#endif
diff --git a/source/blender/blenkernel/BKE_displist.h b/source/blender/blenkernel/BKE_displist.h
new file mode 100644
index 00000000000..979ed31fb20
--- /dev/null
+++ b/source/blender/blenkernel/BKE_displist.h
@@ -0,0 +1,127 @@
+/* display list (or rather multi purpose list) stuff */
+/*
+ $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+
+*/
+
+#ifndef BKE_DISPLIST_H
+#define BKE_DISPLIST_H
+
+#include "DNA_customdata_types.h"
+#include "BKE_customdata.h"
+
+/* dl->type */
+#define DL_POLY 0
+#define DL_SEGM 1
+#define DL_SURF 2
+#define DL_INDEX3 4
+#define DL_INDEX4 5
+#define DL_VERTCOL 6
+#define DL_VERTS 7
+
+/* dl->flag */
+#define DL_CYCL_U 1
+#define DL_CYCL_V 2
+#define DL_FRONT_CURVE 4
+#define DL_BACK_CURVE 8
+
+#define DL_SURFINDEX(cyclu, cyclv, sizeu, sizev) \
+\
+if( (cyclv)==0 && a==(sizev)-1) break; \
+if(cyclu) { \
+ p1= sizeu*a; \
+ p2= p1+ sizeu-1; \
+ p3= p1+ sizeu; \
+ p4= p2+ sizeu; \
+ b= 0; \
+} \
+else { \
+ p2= sizeu*a; \
+ p1= p2+1; \
+ p4= p2+ sizeu; \
+ p3= p1+ sizeu; \
+ b= 1; \
+} \
+if( (cyclv) && a==sizev-1) { \
+ p3-= sizeu*sizev; \
+ p4-= sizeu*sizev; \
+}
+
+
+/* prototypes */
+
+struct Base;
+struct Object;
+struct Curve;
+struct ListBase;
+struct Material;
+struct Bone;
+struct Mesh;
+
+
+/* used for curves, nurbs, mball, importing */
+typedef struct DispList {
+ struct DispList *next, *prev;
+ short type, flag;
+ int parts, nr;
+ short col, rt; /* rt used by initrenderNurbs */
+ float *verts, *nors;
+ int *index;
+ unsigned int *col1, *col2;
+ int charidx;
+ int totindex; /* indexed array drawing surfaces */
+
+ unsigned int *bevelSplitFlag;
+} DispList;
+
+extern void copy_displist(struct ListBase *lbn, struct ListBase *lb);
+extern void free_disp_elem(DispList *dl);
+extern DispList *find_displist_create(struct ListBase *lb, int type);
+extern DispList *find_displist(struct ListBase *lb, int type);
+extern void addnormalsDispList(struct Object *ob, struct ListBase *lb);
+extern void count_displist(struct ListBase *lb, int *totvert, int *totface);
+extern void freedisplist(struct ListBase *lb);
+extern int displist_has_faces(struct ListBase *lb);
+extern void makeDerivedMesh(struct Object *ob, CustomDataMask dataMask);
+extern void makeDispListSurf(struct Object *ob, struct ListBase *dispbase, int forRender);
+extern void makeDispListCurveTypes(struct Object *ob, int forOrco);
+extern void makeDispListMBall(struct Object *ob);
+extern void shadeDispList(struct Base *base);
+extern void shadeMeshMCol(struct Object *ob, struct Mesh *me);
+
+void imagestodisplist(void);
+void reshadeall_displist(void);
+void filldisplist(struct ListBase *dispbase, struct ListBase *to);
+
+void fastshade_free_render(void);
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_effect.h b/source/blender/blenkernel/BKE_effect.h
new file mode 100644
index 00000000000..5585735e0b5
--- /dev/null
+++ b/source/blender/blenkernel/BKE_effect.h
@@ -0,0 +1,79 @@
+/**
+ * blenlib/BKE_effect.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BKE_EFFECT_H
+#define BKE_EFFECT_H
+
+#include "DNA_object_types.h"
+
+struct Effect;
+struct ListBase;
+struct PartEff;
+struct Particle;
+struct Group;
+
+typedef struct pEffectorCache {
+ struct pEffectorCache *next, *prev;
+ Object *ob;
+
+ /* precalculated variables */
+ float oldloc[3], oldspeed[3];
+ float scale, time_scale;
+ float guide_dist;
+
+ Object obcopy; /* for restoring transformation data */
+} pEffectorCache;
+
+
+struct Effect *add_effect(int type);
+void free_effect(struct Effect *eff);
+void free_effects(struct ListBase *lb);
+struct Effect *copy_effect(struct Effect *eff);
+void copy_act_effect(struct Object *ob);
+void copy_effects(struct ListBase *lbn, struct ListBase *lb);
+void deselectall_eff(struct Object *ob);
+struct PartEff *give_parteff(struct Object *ob);
+void where_is_particle(struct PartEff *paf, struct Particle *pa, float ctime, float *vec);
+void build_particle_system(struct Object *ob);
+
+/* particle deflector */
+#define PE_WIND_AS_SPEED 0x00000001
+
+struct ListBase *pdInitEffectors(struct Object *obsrc, struct Group *group);
+void pdEndEffectors(struct ListBase *lb);
+void pdDoEffectors(struct ListBase *lb, float *opco, float *force, float *speed, float cur_time, float loc_time, unsigned int flags);
+
+
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_endian.h b/source/blender/blenkernel/BKE_endian.h
new file mode 100644
index 00000000000..11d39a2ecb6
--- /dev/null
+++ b/source/blender/blenkernel/BKE_endian.h
@@ -0,0 +1,47 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * Are we little or big endian? From Harbison&Steele.
+ * BKE_ENDIANNESS(a) returns 1 if big endian and returns 0 if little endian
+ */
+#ifndef BKE_ENDIAN_H
+#define BKE_ENDIAN_H
+
+#define BKE_ENDIANNESS(a) { \
+ union { \
+ long l; \
+ char c[sizeof (long)]; \
+ } u; \
+ u.l = 1; \
+ a = (u.c[sizeof (long) - 1] == 1) ? 1 : 0; \
+}
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_exotic.h b/source/blender/blenkernel/BKE_exotic.h
new file mode 100644
index 00000000000..2a56f894c42
--- /dev/null
+++ b/source/blender/blenkernel/BKE_exotic.h
@@ -0,0 +1,56 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * dxf/vrml/stl external file io function prototypes
+ */
+
+#ifndef BKE_EXOTIC_H
+#define BKE_EXOTIC_H
+
+struct Mesh;
+
+void mcol_to_rgba(unsigned int col, float *r, float *g, float *b, float *a);
+unsigned int *mcol_to_vcol(struct Mesh *me); // used in py_main.c
+
+/**
+ * Reads all 3D fileformats other than Blender fileformat
+ * @retval 0 The file could not be read.
+ * @retval 1 The file was read succesfully.
+ * @attention Used in filesel.c
+ */
+int BKE_read_exotic(char *name);
+
+void write_dxf(char *str);
+void write_vrml(char *str);
+void write_videoscape(char *str);
+void write_stl(char *str);
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_font.h b/source/blender/blenkernel/BKE_font.h
new file mode 100644
index 00000000000..05621a4d9b2
--- /dev/null
+++ b/source/blender/blenkernel/BKE_font.h
@@ -0,0 +1,74 @@
+/**
+ * blenlib/BKE_vfont.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BKE_VFONT_H
+#define BKE_VFONT_H
+
+#include <wchar.h>
+
+struct VFont;
+struct Object;
+struct Curve;
+struct objfnt;
+
+struct chartrans {
+ float xof, yof;
+ float rot;
+ short linenr,charnr;
+ char dobreak;
+};
+
+typedef struct SelBox {
+ float x, y, w, h;
+} SelBox;
+
+extern struct SelBox *selboxes;
+
+void BKE_font_register_builtin(void *mem, int size);
+
+void free_vfont(struct VFont *sc);
+struct VFont *load_vfont(char *name);
+
+struct chartrans *text_to_curve(struct Object *ob, int mode);
+int style_to_sel(int style, int toggle);
+int mat_to_sel(void);
+
+int getselection(int *start, int *end);
+
+void chtoutf8(unsigned long c, char *o);
+void wcs2utf8s(char *dst, wchar_t *src);
+int wcsleninu8(wchar_t *src);
+int utf8towchar_(wchar_t *w, char *c);
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h
new file mode 100644
index 00000000000..da90c8e156c
--- /dev/null
+++ b/source/blender/blenkernel/BKE_global.h
@@ -0,0 +1,264 @@
+/**
+ * blenlib/BKE_global.h (mar-2001 nzc)
+ *
+ * Global settings, handles, pointers. This is the root for finding
+ * any data in Blender. This block is not serialized, but built anew
+ * for every fresh Blender run.
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BKE_GLOBAL_H
+#define BKE_GLOBAL_H
+
+#include "DNA_listBase.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* forwards */
+struct View3D;
+struct View2D;
+struct SpaceIpo;
+struct SpaceButs;
+struct SpaceImage;
+struct SpaceOops;
+struct SpaceText;
+struct SpaceSound;
+struct SpaceAction;
+struct SpaceNla;
+struct Main;
+struct Scene;
+struct bScreen;
+struct Object;
+struct bSoundListener;
+struct BMF_Font;
+struct EditMesh;
+
+typedef struct Global {
+
+ /* active pointers */
+ struct View3D *vd;
+ struct View2D *v2d;
+ struct SpaceIpo *sipo;
+ struct SpaceButs *buts;
+ struct SpaceImage *sima;
+ struct SpaceOops *soops;
+ struct SpaceSound *ssound;
+ struct SpaceAction *saction; /* __NLA */
+ struct SpaceNla *snla;
+ struct Main *main;
+ struct Scene *scene; /* denk aan file.c */
+ struct bScreen *curscreen;
+ struct Object *obedit;
+ char editModeTitleExtra[64];
+
+ /* fonts, allocated global data */
+ struct BMF_Font *font, *fonts, *fontss;
+
+ /* strings: lastsaved */
+ char ima[256], sce[256], lib[256];
+
+ /* flag: if != 0 G.sce contains valid relative base path */
+ int relbase_valid;
+
+ /* strings of recent opend files */
+ struct ListBase recent_files;
+
+ /* totals */
+ int totobj, totlamp, totobjsel, totcurve, totmesh;
+ int totbone, totbonesel;
+ int totvert, totedge, totface, totvertsel, totedgesel, totfacesel;
+
+ short afbreek, moving;
+ short qual, background;
+ short winpos, displaymode; /* used to be in Render */
+ short rendering; /* to indicate render is busy, prevent renderwindow events etc */
+ /**
+ * The current version of Blender.
+ */
+ short version;
+ short simulf, order, rt;
+ int f;
+
+ /* Editmode lists */
+ struct EditMesh *editMesh;
+
+ float textcurs[4][2];
+
+ /* Frank's variables */
+ int save_over;
+
+ /* Reevan's __NLA variables */
+ struct ListBase edbo; /* Armature Editmode bones */
+
+ /* Rob's variables */
+ int have_quicktime;
+ int ui_international;
+ int charstart;
+ int charmin;
+ int charmax;
+ struct VFont *selfont;
+ struct ListBase ttfdata;
+
+ /* libtiff flag used to determine if shared library loaded for libtiff*/
+ int have_libtiff;
+
+ /* this variable is written to / read from FileGlobal->fileflags */
+ int fileflags;
+
+ /* save the allowed windowstate of blender when using -W or -w */
+ int windowstate;
+
+ /* Janco's playing ground */
+ struct bSoundListener* listener;
+
+ /* Test thingy for Nzc */
+ int compat; /* toggle compatibility mode for edge rendering */
+ int notonlysolid;/* T-> also edge-render transparent faces */
+
+ /* confusing... G.f and G.flags */
+ int flags;
+
+} Global;
+
+/* **************** GLOBAL ********************* */
+
+/* G.f */
+#define G_DISABLE_OK (1 << 0)
+#define G_PLAYANIM (1 << 1)
+/* also uses G_FILE_AUTOPLAY */
+#define G_SIMULATION (1 << 3)
+#define G_BACKBUFSEL (1 << 4)
+#define G_PICKSEL (1 << 5)
+#define G_DRAWNORMALS (1 << 6)
+#define G_DRAWFACES (1 << 7)
+#define G_FACESELECT (1 << 8)
+#define G_DRAW_EXT (1 << 9)
+#define G_VERTEXPAINT (1 << 10)
+#define G_ALLEDGES (1 << 11)
+#define G_DEBUG (1 << 12)
+#define G_DOSCRIPTLINKS (1 << 13)
+#define G_DRAW_VNORMALS (1 << 14)
+#define G_WEIGHTPAINT (1 << 15)
+#define G_TEXTUREPAINT (1 << 16)
+/* #define G_NOFROZEN (1 << 17) also removed */
+#define G_DRAWEDGES (1 << 18)
+#define G_DRAWCREASES (1 << 19)
+#define G_DRAWSEAMS (1 << 20)
+#define G_HIDDENEDGES (1 << 21)
+#define G_HIDDENHANDLES (1 << 22) /* used for curves only */
+
+
+/* Measurement info Drawing */
+#define G_DRAW_EDGELEN (1 << 22)
+#define G_DRAW_FACEAREA (1 << 23)
+#define G_DRAW_EDGEANG (1 << 24)
+
+#define G_RECORDKEYS (1 << 25)
+
+/*#ifdef WITH_VERSE*/
+#define G_VERSE_CONNECTED (1 << 26)
+#define G_DRAW_VERSE_DEBUG (1 << 27)
+/*#endif*/
+
+#define G_DRAWSHARP (1 << 28) /* draw edges with the sharp flag */
+#define G_SCULPTMODE (1 << 29)
+
+#define G_AUTOMATKEYS (1 << 30)
+
+/* macro for testing face select mode
+ * Texture paint could be removed since selected faces are not used
+ * however hiding faces is useful */
+#define FACESEL_PAINT_TEST ((G.f&G_FACESELECT) && (G.f & (G_VERTEXPAINT|G_WEIGHTPAINT|G_TEXTUREPAINT)))
+
+/* G.fileflags */
+
+#define G_AUTOPACK (1 << 0)
+#define G_FILE_COMPRESS (1 << 1)
+#define G_FILE_AUTOPLAY (1 << 2)
+#define G_FILE_ENABLE_ALL_FRAMES (1 << 3)
+#define G_FILE_SHOW_DEBUG_PROPS (1 << 4)
+#define G_FILE_SHOW_FRAMERATE (1 << 5)
+#define G_FILE_SHOW_PROFILE (1 << 6)
+#define G_FILE_LOCK (1 << 7)
+#define G_FILE_SIGN (1 << 8)
+#define G_FIle_PUBLISH (1 << 9)
+#define G_FILE_NO_UI (1 << 10)
+#define G_FILE_GAME_TO_IPO (1 << 11)
+#define G_FILE_GAME_MAT (1 << 12)
+#define G_FILE_DIAPLAY_LISTS (1 << 13)
+#define G_FILE_SHOW_PHYSICS (1 << 14)
+
+/* G.windowstate */
+#define G_WINDOWSTATE_USERDEF 0
+#define G_WINDOWSTATE_BORDER 1
+#define G_WINDOWSTATE_FULLSCREEN 2
+
+/* G.simulf */
+#define G_LOADFILE 2
+#define G_RESTART 4
+#define G_QUIT 8
+#define G_SETSCENE 16
+
+/* G.qual */
+#define R_SHIFTKEY 1
+#define L_SHIFTKEY 2
+#define LR_SHIFTKEY 3
+#define R_ALTKEY 4
+#define L_ALTKEY 8
+#define LR_ALTKEY 12
+#define R_CTRLKEY 16
+#define L_CTRLKEY 32
+#define LR_CTRLKEY 48
+#define LR_COMMANDKEY 64
+
+/* G.order: indicates what endianness the platform where the file was
+ * written had. */
+#define L_ENDIAN 1
+#define B_ENDIAN 0
+
+/* G.moving, signals drawing in (3d) window to denote transform */
+#define G_TRANSFORM_OBJ 1
+#define G_TRANSFORM_EDIT 2
+#define G_TRANSFORM_MANIP 4
+
+/* G.special1 */
+
+/* Memory is allocated where? blender.c */
+extern Global G;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_group.h b/source/blender/blenkernel/BKE_group.h
new file mode 100644
index 00000000000..9038422795d
--- /dev/null
+++ b/source/blender/blenkernel/BKE_group.h
@@ -0,0 +1,57 @@
+/**
+ * blenlib/BKE_group.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BKE_GROUP_H
+#define BKE_GROUP_H
+
+struct Group;
+struct GroupObject;
+struct Object;
+struct bAction;
+
+void free_group_object(struct GroupObject *go);
+void free_group(struct Group *group);
+void unlink_group(struct Group *group);
+struct Group *add_group(char *name);
+void add_to_group(struct Group *group, struct Object *ob);
+void rem_from_group(struct Group *group, struct Object *ob);
+struct Group *find_group(struct Object *ob);
+int object_in_group(struct Object *ob, struct Group *group);
+
+void group_tag_recalc(struct Group *group);
+void group_handle_recalc_and_update(struct Object *parent, struct Group *group);
+struct Object *group_get_member_with_action(struct Group *group, struct bAction *act);
+void group_relink_nla_objects(struct Object *ob);
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_icons.h b/source/blender/blenkernel/BKE_icons.h
new file mode 100644
index 00000000000..737adea78be
--- /dev/null
+++ b/source/blender/blenkernel/BKE_icons.h
@@ -0,0 +1,88 @@
+/**
+* $Id$
+*
+* ***** BEGIN GPL LICENSE BLOCK *****
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*
+* The Original Code is Copyright (C) 2006-2007 Blender Foundation.
+* All rights reserved.
+*
+* The Original Code is: all of this file.
+*
+* Contributor(s): none yet.
+*
+* ***** END GPL LICENSE BLOCK *****
+*
+*/
+
+#ifndef BKE_ICONS_H
+#define BKE_ICONS_H
+
+/*
+ Resizable Icons for Blender
+*/
+
+typedef void (*DrawInfoFreeFP) (void *drawinfo);
+
+struct Icon
+{
+ void *drawinfo;
+ void *obj;
+ short type;
+ DrawInfoFreeFP drawinfo_free;
+};
+
+typedef struct Icon Icon;
+
+struct PreviewImage;
+
+void BKE_icons_init(int first_dyn_id);
+
+/* return icon id for library object or create new icon if not found */
+int BKE_icon_getid(struct ID* id);
+
+/* retrieve icon for id */
+struct Icon* BKE_icon_get(int icon_id);
+
+/* set icon for id if not already defined */
+/* used for inserting the internal icons */
+void BKE_icon_set(int icon_id, struct Icon* icon);
+
+/* remove icon and free date if library object becomes invalid */
+void BKE_icon_delete(struct ID* id);
+
+/* report changes - icon needs to be recalculated */
+void BKE_icon_changed(int icon_id);
+
+/* free all icons */
+void BKE_icons_free();
+
+/* free the preview image */
+void BKE_previewimg_free(struct PreviewImage **prv);
+
+/* free the preview image belonging to the id */
+void BKE_previewimg_free_id(ID *id);
+
+/* create a new preview image */
+struct PreviewImage* BKE_previewimg_create() ;
+
+/* create a copy of the preview image */
+struct PreviewImage* BKE_previewimg_copy(struct PreviewImage *prv);
+
+/* retrieve existing or create new preview image */
+PreviewImage* BKE_previewimg_get(ID *id);
+
+#endif /* BKE_ICONS_H */
diff --git a/source/blender/blenkernel/BKE_idprop.h b/source/blender/blenkernel/BKE_idprop.h
new file mode 100644
index 00000000000..961cca511de
--- /dev/null
+++ b/source/blender/blenkernel/BKE_idprop.h
@@ -0,0 +1,177 @@
+/**
+ * $Id: BKE_idprop.h
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Joseph Eagar
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef _BKE_IDPROP_H
+#define _BKE_IDPROP_H
+
+#include "DNA_ID.h"
+
+/*
+these two are included for their (new :P )function
+pointers.
+*/
+#include "BLO_readfile.h"
+#include "BLO_writefile.h"
+
+struct WriteData;
+struct FileData;
+
+struct IDProperty;
+struct ID;
+
+typedef union {
+ int i;
+ float f;
+ char *str;
+ struct ID *id;
+ struct {
+ short type;
+ short len;
+ } array;
+ struct {
+ int matvec_size;
+ float *example;
+ } matrix_or_vector;
+} IDPropertyTemplate;
+
+/* ----------- Array Type ----------- */
+/*this function works for strings too!*/
+void IDP_ResizeArray(struct IDProperty *prop, int newlen);
+void IDP_FreeArray(struct IDProperty *prop);
+void IDP_UnlinkArray(struct IDProperty *prop);
+
+/* ---------- String Type ------------ */
+void IDP_AssignString(struct IDProperty *prop, char *st);
+void IDP_ConcatStringC(struct IDProperty *prop, char *st);
+void IDP_ConcatString(struct IDProperty *str1, struct IDProperty *append);
+void IDP_FreeString(struct IDProperty *prop);
+
+/*-------- ID Type -------*/
+void IDP_LinkID(struct IDProperty *prop, ID *id);
+void IDP_UnlinkID(struct IDProperty *prop);
+
+/*-------- Group Functions -------*/
+
+/*checks if a property with the same name as prop exists, and if so replaces it.
+ Use this to preserve order!*/
+void IDP_ReplaceInGroup(struct IDProperty *group, struct IDProperty *prop);
+
+/*
+This function has a sanity check to make sure ID properties with the same name don't
+get added to the group.
+
+The sanity check just means the property is not added to the group if another property
+exists with the same name; the client code using ID properties then needs to detect this
+(the function that adds new properties to groups, IDP_AddToGroup, returns 0 if a property can't
+be added to the group, and 1 if it can) and free the property.
+
+Currently the code to free ID properties is designesd to leave the actual struct
+you pass it un-freed, this is needed for how the system works. This means
+to free an ID property, you first call IDP_FreeProperty then MEM_freeN the
+struct. In the future this will just be IDP_FreeProperty and the code will
+be reorganized to work properly.
+*/
+int IDP_AddToGroup(struct IDProperty *group, struct IDProperty *prop);
+
+/*this is the same as IDP_AddToGroup, only you pass an item
+ in the group list to be inserted after.*/
+int IDP_InsertToGroup(struct IDProperty *group, struct IDProperty *previous,
+ struct IDProperty *pnew);
+
+/*NOTE: this does not free the property!!
+
+ To free the property, you have to do:
+ IDP_FreeProperty(prop); //free all subdata
+ MEM_freeN(prop); //free property struct itself
+
+*/
+void IDP_RemFromGroup(struct IDProperty *group, struct IDProperty *prop);
+
+IDProperty *IDP_GetPropertyFromGroup(struct IDProperty *prop, char *name);
+
+/*Get an iterator to iterate over the members of an id property group.
+ Note that this will automatically free the iterator once iteration is complete;
+ if you stop the iteration before hitting the end, make sure to call
+ IDP_FreeIterBeforeEnd().*/
+void *IDP_GetGroupIterator(struct IDProperty *prop);
+
+/*Returns the next item in the iteration. To use, simple for a loop like the following:
+ while (IDP_GroupIterNext(iter) != NULL) {
+ . . .
+ }*/
+IDProperty *IDP_GroupIterNext(void *vself);
+
+/*Frees the iterator pointed to at vself, only use this if iteration is stopped early;
+ when the iterator hits the end of the list it'll automatially free itself.*/
+void IDP_FreeIterBeforeEnd(void *vself);
+
+/*-------- Main Functions --------*/
+/*Get the Group property that contains the id properties for ID id. Set create_if_needed
+ to create the Group property and attach it to id if it doesn't exist; otherwise
+ the function will return NULL if there's no Group property attached to the ID.*/
+struct IDProperty *IDP_GetProperties(struct ID *id, int create_if_needed);
+struct IDProperty *IDP_CopyProperty(struct IDProperty *prop);
+
+/*
+Allocate a new ID.
+
+This function takes three arguments: the ID property type, a union which defines
+it's initial value, and a name.
+
+The union is simple to use; see the top of this header file for its definition.
+An example of using this function:
+
+ IDPropertyTemplate val;
+ IDProperty *group, *idgroup, *color;
+ group = IDP_New(IDP_GROUP, val, "group1"); //groups don't need a template.
+
+ val.array.len = 4
+ val.array.type = IDP_FLOAT;
+ color = IDP_New(IDP_ARRAY, val, "color1");
+
+ idgroup = IDP_GetProperties(some_id, 1);
+ IDP_AddToGroup(idgroup, color);
+ IDP_AddToGroup(idgroup, group);
+
+Note that you MUST either attach the id property to an id property group with
+IDP_AddToGroup or MEM_freeN the property, doing anything else might result in
+a memory leak.
+*/
+struct IDProperty *IDP_New(int type, IDPropertyTemplate val, char *name);
+\
+/*NOTE: this will free all child properties of list arrays and groups!
+ Also, note that this does NOT unlink anything! Plus it doesn't free
+ the actual struct IDProperty struct either.*/
+void IDP_FreeProperty(struct IDProperty *prop);
+
+/*Unlinks any struct IDProperty<->ID linkage that might be going on.*/
+void IDP_UnlinkProperty(struct IDProperty *prop);
+
+#endif /* _BKE_IDPROP_H */
diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h
new file mode 100644
index 00000000000..b308342ac1e
--- /dev/null
+++ b/source/blender/blenkernel/BKE_image.h
@@ -0,0 +1,156 @@
+/**
+ * blenlib/BKE_image.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BKE_IMAGE_H
+#define BKE_IMAGE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct Image;
+struct ImBuf;
+struct Tex;
+struct anim;
+
+/* call from library */
+void free_image(struct Image *me);
+
+void BKE_stamp_info(struct ImBuf *ibuf);
+void BKE_stamp_buf(unsigned char *rect, float *rectf, int width, int height);
+int BKE_write_ibuf(struct ImBuf *ibuf, char *name, int imtype, int subimtype, int quality);
+void BKE_makepicstring(char *string, char *base, int frame, int imtype);
+void BKE_add_image_extension(char *string, int imtype);
+int BKE_ftype_to_imtype(int ftype);
+int BKE_imtype_to_ftype(int imtype);
+int BKE_imtype_is_movie(int imtype);
+
+struct anim *openanim(char * name, int flags);
+
+void converttopremul(struct ImBuf *ibuf);
+void image_de_interlace(struct Image *ima, int odd);
+
+void tag_image_time(struct Image *ima);
+void free_old_images(void);
+
+/* ********************************** NEW IMAGE API *********************** */
+
+/* ImageUser is in Texture, in Nodes, Background Image, Image Window, .... */
+/* should be used in conjunction with an ID * to Image. */
+struct ImageUser;
+struct RenderPass;
+struct RenderResult;
+
+/* ima->source; where image comes from */
+#define IMA_SRC_CHECK 0
+#define IMA_SRC_FILE 1
+#define IMA_SRC_SEQUENCE 2
+#define IMA_SRC_MOVIE 3
+#define IMA_SRC_GENERATED 4
+#define IMA_SRC_VIEWER 5
+
+/* ima->type, how to handle/generate it */
+#define IMA_TYPE_IMAGE 0
+#define IMA_TYPE_MULTILAYER 1
+ /* generated */
+#define IMA_TYPE_UV_TEST 2
+#define IMA_TYPE_VERSE 3
+ /* viewers */
+#define IMA_TYPE_R_RESULT 4
+#define IMA_TYPE_COMPOSITE 5
+
+/* ima->ok */
+#define IMA_OK 1
+#define IMA_OK_LOADED 2
+
+/* signals */
+ /* reload only frees, doesn't read until image_get_ibuf() called */
+#define IMA_SIGNAL_RELOAD 0
+#define IMA_SIGNAL_FREE 1
+ /* pack signals are executed */
+#define IMA_SIGNAL_PACK 2
+#define IMA_SIGNAL_REPACK 3
+#define IMA_SIGNAL_UNPACK 4
+ /* source changes, from image to sequence or movie, etc */
+#define IMA_SIGNAL_SRC_CHANGE 5
+ /* image-user gets a new image, check settings */
+#define IMA_SIGNAL_USER_NEW_IMAGE 6
+
+/* depending Image type, and (optional) ImageUser setting it returns ibuf */
+/* always call to make signals work */
+struct ImBuf *BKE_image_get_ibuf(struct Image *ima, struct ImageUser *iuser);
+
+/* returns existing Image when filename/type is same */
+struct Image *BKE_add_image_file(const char *name);
+
+/* adds image, adds ibuf, generates color or pattern */
+struct Image *BKE_add_image_size(int width, int height, char *name, short uvtestgrid, float color[4]);
+
+/* for reload, refresh, pack */
+void BKE_image_signal(struct Image *ima, struct ImageUser *iuser, int signal);
+
+/* ensures an Image exists for viewing nodes or render */
+struct Image *BKE_image_verify_viewer(int type, const char *name);
+
+/* force an ImBuf to become part of Image */
+void BKE_image_assign_ibuf(struct Image *ima, struct ImBuf *ibuf);
+
+/* called on frame change or before render */
+void BKE_image_user_calc_imanr(struct ImageUser *iuser, int cfra, int fieldnr);
+
+/* fix things in ImageUser when new image gets assigned */
+void BKE_image_user_new_image(struct Image *ima, struct ImageUser *iuser);
+
+/* sets index offset for multilayer files */
+struct RenderPass *BKE_image_multilayer_index(struct RenderResult *rr, struct ImageUser *iuser);
+
+/* for multilayer images as well as for render-viewer */
+struct RenderResult *BKE_image_get_renderresult(struct Image *ima);
+
+/* goes over all textures that use images */
+void BKE_image_free_all_textures(void);
+
+/* does one image! */
+void BKE_image_free_anim_ibufs(struct Image *ima, int except_frame);
+
+/* does all images with type MOVIE or SEQUENCE */
+void BKE_image_all_free_anim_ibufs(int except_frame);
+
+void BKE_image_memorypack(struct Image *ima);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_ipo.h b/source/blender/blenkernel/BKE_ipo.h
new file mode 100644
index 00000000000..2a6065eb4f1
--- /dev/null
+++ b/source/blender/blenkernel/BKE_ipo.h
@@ -0,0 +1,118 @@
+/**
+ * blenlib/BKE_ipo.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BKE_IPO_H
+#define BKE_IPO_H
+
+typedef struct CfraElem {
+ struct CfraElem *next, *prev;
+ float cfra;
+ int sel;
+} CfraElem;
+
+struct Ipo;
+struct IpoCurve;
+struct MTex;
+struct Material;
+struct Object;
+struct Sequence;
+struct ListBase;
+struct BezTriple;
+struct ID;
+struct bPoseChannel;
+struct bActionChannel;
+struct rctf;
+
+float frame_to_float(int cfra);
+
+void free_ipo_curve(struct IpoCurve *icu);
+void free_ipo(struct Ipo *ipo);
+void ipo_default_v2d_cur(int blocktype, struct rctf *cur);
+struct Ipo *add_ipo(char *name, int idcode);
+struct Ipo *copy_ipo(struct Ipo *ipo);
+void ipo_idnew(struct Ipo *ipo);
+void make_local_obipo(struct Ipo *ipo);
+void make_local_matipo(struct Ipo *ipo);
+void make_local_keyipo(struct Ipo *ipo);
+void make_local_ipo(struct Ipo *ipo);
+struct IpoCurve *find_ipocurve(struct Ipo *ipo, int adrcode);
+
+void calchandles_ipocurve(struct IpoCurve *icu);
+void testhandles_ipocurve(struct IpoCurve *icu);
+void sort_time_ipocurve(struct IpoCurve *icu);
+int test_time_ipocurve(struct IpoCurve *icu);
+void correct_bezpart(float *v1, float *v2, float *v3, float *v4);
+int findzero(float x, float q0, float q1, float q2, float q3, float *o);
+void berekeny(float f1, float f2, float f3, float f4, float *o, int b);
+void berekenx(float *f, float *o, int b);
+float eval_icu(struct IpoCurve *icu, float ipotime);
+void calc_icu(struct IpoCurve *icu, float ctime);
+float calc_ipo_time(struct Ipo *ipo, float ctime);
+void calc_ipo(struct Ipo *ipo, float ctime);
+void write_ipo_poin(void *poin, int type, float val);
+float read_ipo_poin(void *poin, int type);
+void *give_mtex_poin(struct MTex *mtex, int adrcode );
+
+void *get_ipo_poin(struct ID *id, struct IpoCurve *icu, int *type);
+void *get_pchan_ipo_poin(struct bPoseChannel *pchan, int adrcode);
+
+void set_icu_vars(struct IpoCurve *icu);
+
+void execute_ipo(struct ID *id, struct Ipo *ipo);
+void execute_action_ipo(struct bActionChannel *achan, struct bPoseChannel *pchan);
+
+void do_ipo_nocalc(struct Ipo *ipo);
+void do_ipo(struct Ipo *ipo);
+void do_mat_ipo(struct Material *ma);
+void do_ob_ipo(struct Object *ob);
+void do_seq_ipo(struct Sequence *seq);
+void do_ob_ipodrivers(struct Object *ob, struct Ipo *ipo, float ctime);
+
+int has_ipo_code(struct Ipo *ipo, int code);
+void do_all_data_ipos(void);
+int calc_ipo_spec(struct Ipo *ipo, int adrcode, float *ctime);
+void clear_delta_obipo(struct Ipo *ipo);
+void add_to_cfra_elem(struct ListBase *lb, struct BezTriple *bezt);
+void make_cfra_list(struct Ipo *ipo, struct ListBase *elems);
+
+/* the sort is an IPO_Channel... */
+int IPO_GetChannels(struct Ipo *ipo, short *channels);
+
+float IPO_GetFloatValue(struct Ipo *ipo,
+/* struct IPO_Channel channel, */
+ /* channels are shorts... bit ugly for now*/
+ short c,
+ float ctime);
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h
new file mode 100644
index 00000000000..5325b3a8bc1
--- /dev/null
+++ b/source/blender/blenkernel/BKE_key.h
@@ -0,0 +1,65 @@
+/**
+ * blenlib/BKE_key.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BKE_KEY_H
+#define BKE_KEY_H
+
+struct Key;
+struct KeyBlock;
+struct ID;
+struct ListBase;
+struct Curve;
+struct Object;
+struct Lattice;
+struct Mesh;
+
+void free_key(struct Key *sc);
+struct Key *add_key(struct ID *id);
+struct Key *copy_key(struct Key *key);
+void make_local_key(struct Key *key);
+void sort_keys(struct Key *key);
+
+void set_four_ipo(float d, float *data, int type);
+void set_afgeleide_four_ipo(float d, float *data, int type);
+
+/* only exported to curve.c! */
+void cp_cu_key(struct Curve *cu, struct KeyBlock *kb, int start, int end);
+
+int do_ob_key(struct Object *ob);
+
+struct Key *ob_get_key(struct Object *ob);
+struct KeyBlock *ob_get_keyblock(struct Object *ob);
+struct KeyBlock *key_get_keyblock(struct Key *key, int index);
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h
new file mode 100644
index 00000000000..3dc4b49b52b
--- /dev/null
+++ b/source/blender/blenkernel/BKE_lattice.h
@@ -0,0 +1,74 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * june-2001 ton
+ */
+
+#ifndef BKE_LATTICE_H
+#define BKE_LATTICE_H
+
+struct Lattice;
+struct Object;
+struct DerivedMesh;
+struct BPoint;
+
+extern struct Lattice *editLatt;
+
+
+void resizelattice(struct Lattice *lt, int u, int v, int w, struct Object *ltOb);
+struct Lattice *add_lattice(char *name);
+struct Lattice *copy_lattice(struct Lattice *lt);
+void free_lattice(struct Lattice *lt);
+void make_local_lattice(struct Lattice *lt);
+void calc_lat_fudu(int flag, int res, float *fu, float *du);
+void init_latt_deform(struct Object *oblatt, struct Object *ob);
+void calc_latt_deform(float *co, float weight);
+void end_latt_deform(void);
+int object_deform_mball(struct Object *ob);
+void outside_lattice(struct Lattice *lt);
+void curve_deform_verts(struct Object *cuOb, struct Object *target,
+ struct DerivedMesh *dm, float (*vertexCos)[3],
+ int numVerts, char *vgroup, short defaxis);
+void curve_deform_vector(struct Object *cuOb, struct Object *target,
+ float *orco, float *vec, float mat[][3], int no_rot_axis);
+
+void lattice_deform_verts(struct Object *laOb, struct Object *target,
+ struct DerivedMesh *dm, float (*vertexCos)[3],
+ int numVerts, char *vgroup);
+void armature_deform_verts(struct Object *armOb, struct Object *target,
+ struct DerivedMesh *dm, float (*vertexCos)[3],
+ float (*defMats)[3][3], int numVerts,
+ int deformflag, const char *defgrp_name);
+float (*lattice_getVertexCos(struct Object *ob, int *numVerts_r))[3];
+void lattice_applyVertexCos(struct Object *ob, float (*vertexCos)[3]);
+void lattice_calc_modifiers(struct Object *ob);
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h
new file mode 100644
index 00000000000..1954cfe1e37
--- /dev/null
+++ b/source/blender/blenkernel/BKE_library.h
@@ -0,0 +1,77 @@
+/**
+ * blenlib/BKE_library.h (mar-2001 nzc)
+ *
+ * Library
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BKE_LIBRARY_TYPES_H
+#define BKE_LIBRARY_TYPES_H
+
+struct ListBase;
+struct ID;
+struct Main;
+struct Library;
+
+void *alloc_libblock(struct ListBase *lb, short type, const char *name);
+void *copy_libblock(void *rt);
+
+void id_lib_extern(struct ID *id);
+void id_us_plus(struct ID *id);
+
+int check_for_dupid(struct ListBase *lb, struct ID *id, char *name);
+int new_id(struct ListBase *lb, struct ID *id, const char *name);
+
+struct ListBase *wich_libbase(struct Main *mainlib, short type);
+
+#define MAX_LIBARRAY 40
+int set_listbasepointers(struct Main *main, struct ListBase **lb);
+
+void free_libblock(struct ListBase *lb, void *idv);
+void free_libblock_us(struct ListBase *lb, void *idv);
+void free_main(struct Main *mainvar);
+
+void splitIDname(char *name, char *left, int *nr);
+void rename_id(struct ID *id, char *name);
+void test_idbutton(char *name);
+void all_local(struct Library *lib, int untagged_only);
+struct ID *find_id(char *type, char *name);
+void clear_id_newpoins(void);
+
+void IDnames_to_pupstring(char **str, char *title, char *extraops, struct ListBase *lb,struct ID* link, short *nr);
+void IMAnames_to_pupstring(char **str, char *title, char *extraops, struct ListBase *lb, struct ID *link, short *nr);
+void IPOnames_to_pupstring(char **str, char *title, char *extraops, struct ListBase *lb, struct ID* link, short *nr, int blocktype);
+
+void flag_listbase_ids(ListBase *lb, short flag, short value);
+void flag_all_listbases_ids(short flag, short value);
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h
new file mode 100644
index 00000000000..6e0f2fdb284
--- /dev/null
+++ b/source/blender/blenkernel/BKE_main.h
@@ -0,0 +1,85 @@
+/**
+ * blenlib/BKE_main.h (mar-2001 nzc)
+ *
+ * Main is the root of the 'database' of a Blender context. All data
+ * is stuffed into lists, and all these lists are knotted to here. A
+ * Blender file is not much more but a binary dump of these
+ * lists. This list of lists is not serialized itself.
+ *
+ * Oops... this should be a _types.h file.
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BKE_MAIN_H
+#define BKE_MAIN_H
+
+#include "DNA_listBase.h"
+
+struct Library;
+
+typedef struct Main {
+ struct Main *next, *prev;
+ char name[160];
+ short versionfile, subversionfile;
+ short minversionfile, minsubversionfile;
+
+ struct Library *curlib;
+ ListBase scene;
+ ListBase library;
+ ListBase object;
+ ListBase mesh;
+ ListBase curve;
+ ListBase mball;
+ ListBase mat;
+ ListBase tex;
+ ListBase image;
+ ListBase wave;
+ ListBase latt;
+ ListBase lamp;
+ ListBase camera;
+ ListBase ipo;
+ ListBase key;
+ ListBase world;
+ ListBase screen;
+ ListBase script;
+ ListBase vfont;
+ ListBase text;
+ ListBase sound;
+ ListBase group;
+ ListBase armature;
+ ListBase action;
+ ListBase nodetree;
+ ListBase brush;
+} Main;
+
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h
new file mode 100644
index 00000000000..2add4b95080
--- /dev/null
+++ b/source/blender/blenkernel/BKE_material.h
@@ -0,0 +1,78 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * General operations, lookup, etc. for materials.
+ */
+
+#ifndef BKE_MATERIAL_H
+#define BKE_MATERIAL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct Material;
+struct ID;
+struct Object;
+
+void init_def_material(void);
+void free_material(struct Material *sc);
+void test_object_materials(struct ID *id);
+void init_material(struct Material *ma);
+struct Material *add_material(char *name);
+struct Material *copy_material(struct Material *ma);
+void make_local_material(struct Material *ma);
+
+struct Material ***give_matarar(struct Object *ob);
+short *give_totcolp(struct Object *ob);
+struct Material *give_current_material(struct Object *ob, int act);
+struct ID *material_from(struct Object *ob, int act);
+void assign_material(struct Object *ob, struct Material *ma, int act);
+void new_material_to_objectdata(struct Object *ob);
+
+void init_render_material(struct Material *, int, float *);
+void init_render_materials(int, float *);
+void end_render_material(struct Material *);
+void end_render_materials(void);
+
+int material_in_material(struct Material *parmat, struct Material *mat);
+
+void automatname(struct Material *);
+void delete_material_index(void);
+
+void ramp_blend(int type, float *r, float *g, float *b, float fac, float *col);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_mball.h b/source/blender/blenkernel/BKE_mball.h
new file mode 100644
index 00000000000..269e7150768
--- /dev/null
+++ b/source/blender/blenkernel/BKE_mball.h
@@ -0,0 +1,182 @@
+/**
+ * blenlib/BKE_mball.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BKE_MBALL_H
+#define BKE_MBALL_H
+
+struct MetaBall;
+struct Object;
+struct MetaElem;
+
+typedef struct point { /* a three-dimensional point */
+ float x, y, z; /* its coordinates */
+} MB_POINT;
+
+typedef struct vertex { /* surface vertex */
+ MB_POINT position, normal; /* position and surface normal */
+} VERTEX;
+
+typedef struct vertices { /* list of vertices in polygonization */
+ int count, max; /* # vertices, max # allowed */
+ VERTEX *ptr; /* dynamically allocated */
+} VERTICES;
+
+typedef struct corner { /* corner of a cube */
+ int i, j, k; /* (i, j, k) is index within lattice */
+ float x, y, z, value; /* location and function value */
+ struct corner *next;
+} CORNER;
+
+typedef struct cube { /* partitioning cell (cube) */
+ int i, j, k; /* lattice location of cube */
+ CORNER *corners[8]; /* eight corners */
+} CUBE;
+
+typedef struct cubes { /* linked list of cubes acting as stack */
+ CUBE cube; /* a single cube */
+ struct cubes *next; /* remaining elements */
+} CUBES;
+
+typedef struct centerlist { /* list of cube locations */
+ int i, j, k; /* cube location */
+ struct centerlist *next; /* remaining elements */
+} CENTERLIST;
+
+typedef struct edgelist { /* list of edges */
+ int i1, j1, k1, i2, j2, k2; /* edge corner ids */
+ int vid; /* vertex id */
+ struct edgelist *next; /* remaining elements */
+} EDGELIST;
+
+typedef struct intlist { /* list of integers */
+ int i; /* an integer */
+ struct intlist *next; /* remaining elements */
+} INTLIST;
+
+typedef struct intlists { /* list of list of integers */
+ INTLIST *list; /* a list of integers */
+ struct intlists *next; /* remaining elements */
+} INTLISTS;
+
+typedef struct process { /* parameters, function, storage */
+ /* what happens here? floats, I think. */
+ /* float (*function)(void); */ /* implicit surface function */
+ float (*function)(float, float, float);
+ float size, delta; /* cube size, normal delta */
+ int bounds; /* cube range within lattice */
+ MB_POINT start; /* start point on surface */
+ CUBES *cubes; /* active cubes */
+ VERTICES vertices; /* surface vertices */
+ CENTERLIST **centers; /* cube center hash table */
+ CORNER **corners; /* corner value hash table */
+ EDGELIST **edges; /* edge and vertex id hash table */
+} PROCESS;
+
+/* dividing scene using octal tree makes polygonisation faster */
+typedef struct ml_pointer {
+ struct ml_pointer *next, *prev;
+ struct MetaElem *ml;
+} ml_pointer;
+
+typedef struct octal_node {
+ struct octal_node *nodes[8]; /* children of current node */
+ struct octal_node *parent; /* parent of current node */
+ struct ListBase elems; /* ListBase of MetaElem pointers (ml_pointer) */
+ float x_min, y_min, z_min; /* 1st border point */
+ float x_max, y_max, z_max; /* 7th border point */
+ float x,y,z; /* center of node */
+ int pos, neg; /* number of positive and negative MetaElements in the node */
+ int count; /* number of MetaElems, which belongs to the node */
+} octal_node;
+
+typedef struct octal_tree {
+ struct octal_node *first; /* first node */
+ int pos, neg; /* number of positive and negative MetaElements in the scene */
+ short depth; /* number of scene subdivision */
+} octal_tree;
+
+struct pgn_elements {
+ struct pgn_elements *next, *prev;
+ char *data;
+};
+
+void calc_mballco(struct MetaElem *ml, float *vec);
+float densfunc(struct MetaElem *ball, float x, float y, float z);
+octal_node* find_metaball_octal_node(octal_node *node, float x, float y, float z, short depth);
+float metaball(float x, float y, float z);
+void accum_mballfaces(int i1, int i2, int i3, int i4);
+void *new_pgn_element(int size);
+
+void freepolygonize(PROCESS *p);
+void docube(CUBE *cube, PROCESS *p, struct MetaBall *mb);
+void testface(int i, int j, int k, CUBE* old, int bit, int c1, int c2, int c3, int c4, PROCESS *p);
+CORNER *setcorner (PROCESS* p, int i, int j, int k);
+int vertid (CORNER *c1, CORNER *c2, PROCESS *p, struct MetaBall *mb);
+int setcenter(CENTERLIST *table[], int i, int j, int k);
+int otherface (int edge, int face);
+void makecubetable (void);
+void setedge (EDGELIST *table[], int i1, int j1, int k1, int i2, int j2, int k2, int vid);
+int getedge (EDGELIST *table[], int i1, int j1, int k1, int i2, int j2, int k2);
+void addtovertices (VERTICES *vertices, VERTEX v);
+void vnormal (MB_POINT *point, PROCESS *p, MB_POINT *v);
+void converge (MB_POINT *p1, MB_POINT *p2, float v1, float v2, float (*function)(float, float, float), MB_POINT *p, struct MetaBall *mb, int f);
+void add_cube(PROCESS *mbproc, int i, int j, int k, int count);
+void find_first_points(PROCESS *mbproc, struct MetaBall *mb, int a);
+
+void fill_metaball_octal_node(octal_node *node, struct MetaElem *ml, short i);
+void subdivide_metaball_octal_node(octal_node *node, float *size, short depth);
+void free_metaball_octal_node(octal_node *node);
+void init_metaball_octal_tree(int depth);
+void polygonize(PROCESS *mbproc, struct MetaBall *mb);
+float init_meta(struct Object *ob);
+
+void unlink_mball(struct MetaBall *mb);
+void free_mball(struct MetaBall *mb);
+struct MetaBall *add_mball(char *name);
+struct MetaBall *copy_mball(struct MetaBall *mb);
+void make_local_mball(struct MetaBall *mb);
+void tex_space_mball( struct Object *ob);
+void make_orco_mball( struct Object *ob);
+struct Object *find_basis_mball( struct Object *ob);
+int is_basis_mball(struct Object *ob);
+void metaball_polygonize(struct Object *ob);
+void calc_mballco(struct MetaElem *ml, float *vec);
+float densfunc(struct MetaElem *ball, float x, float y, float z);
+float metaball(float x, float y, float z);
+void accum_mballfaces(int i1, int i2, int i3, int i4);
+void *new_pgn_element(int size);
+int nextcwedge (int edge, int face);
+void BKE_freecubetable(void);
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
new file mode 100644
index 00000000000..a8e4969ad43
--- /dev/null
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -0,0 +1,127 @@
+/**
+ * blenlib/BKE_mesh.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BKE_MESH_H
+#define BKE_MESH_H
+
+/***/
+
+struct BoundBox;
+struct DispList;
+struct ListBase;
+struct MDeformVert;
+struct Mesh;
+struct MFace;
+struct MVert;
+struct MCol;
+struct Object;
+struct MTFace;
+struct VecNor;
+struct CustomData;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void unlink_mesh(struct Mesh *me);
+void free_mesh(struct Mesh *me);
+struct Mesh *add_mesh(char *name);
+struct Mesh *copy_mesh(struct Mesh *me);
+void mesh_update_customdata_pointers(struct Mesh *me);
+void make_local_tface(struct Mesh *me);
+void make_local_mesh(struct Mesh *me);
+void boundbox_mesh(struct Mesh *me, float *loc, float *size);
+void tex_space_mesh(struct Mesh *me);
+float *mesh_create_orco_render(struct Object *ob);
+float *mesh_create_orco(struct Object *ob);
+void test_index_face(struct MFace *mface, struct CustomData *mfdata, int mfindex, int nr);
+struct Mesh *get_mesh(struct Object *ob);
+void set_mesh(struct Object *ob, struct Mesh *me);
+void mball_to_mesh(struct ListBase *lb, struct Mesh *me);
+void nurbs_to_mesh(struct Object *ob);
+void free_dverts(struct MDeformVert *dvert, int totvert);
+void copy_dverts(struct MDeformVert *dst, struct MDeformVert *src, int totvert); /* __NLA */
+int update_realtime_texture(struct MTFace *tface, double time);
+void mesh_delete_material_index(struct Mesh *me, int index);
+void mesh_set_smooth_flag(struct Object *meshOb, int enableSmooth);
+
+struct BoundBox *mesh_get_bb(struct Mesh *me);
+void mesh_get_texspace(struct Mesh *me, float *loc_r, float *rot_r, float *size_r);
+
+/* if old, it converts mface->edcode to edge drawflags */
+void make_edges(struct Mesh *me, int old);
+void mesh_strip_loose_faces(struct Mesh *me);
+
+ /* Calculate vertex and face normals, face normals are returned in *faceNors_r if non-NULL
+ * and vertex normals are stored in actual mverts.
+ */
+void mesh_calc_normals(struct MVert *mverts, int numVerts, struct MFace *mfaces, int numFaces, float **faceNors_r);
+
+ /* Return a newly MEM_malloc'd array of all the mesh vertex locations
+ * (_numVerts_r_ may be NULL) */
+float (*mesh_getVertexCos(struct Mesh *me, int *numVerts_r))[3];
+float (*mesh_getRefKeyCos(struct Mesh *me, int *numVerts_r))[3];
+
+/* map from uv vertex to face (for select linked, stitch, uv suburf) */
+
+/* UvVertMap */
+
+typedef struct UvVertMap {
+ struct UvMapVert **vert;
+ struct UvMapVert *buf;
+} UvVertMap;
+
+typedef struct UvMapVert {
+ struct UvMapVert *next;
+ unsigned int f;
+ unsigned char tfindex, separate;
+} UvMapVert;
+
+UvVertMap *make_uv_vert_map(struct MFace *mface, struct MTFace *tface, unsigned int totface, unsigned int totvert, int selected, float *limit);
+UvMapVert *get_uv_map_vert(UvVertMap *vmap, unsigned int v);
+void free_uv_vert_map(UvVertMap *vmap);
+
+
+/* functions for making menu's from customdata layers */
+int mesh_layers_menu_charlen(struct CustomData *data, int type); /* use this to work out how many chars to allocate */
+void mesh_layers_menu_concat(struct CustomData *data, int type, char *str);
+int mesh_layers_menu(struct CustomData *data, int type);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h
new file mode 100644
index 00000000000..297443b883d
--- /dev/null
+++ b/source/blender/blenkernel/BKE_modifier.h
@@ -0,0 +1,295 @@
+/**
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BKE_MODIFIER_H
+#define BKE_MODIFIER_H
+
+#include "DNA_modifier_types.h" /* needed for all enum typdefs */
+#include "BKE_customdata.h"
+
+struct EditMesh;
+struct DerivedMesh;
+struct DagForest;
+struct DagNode;
+struct Object;
+struct ListBase;
+struct LinkNode;
+struct bArmature;
+struct ModifierData;
+
+typedef enum {
+ /* Should not be used, only for None modifier type */
+ eModifierTypeType_None,
+
+ /* Modifier only does deformation, implies that modifier
+ * type should have a valid deformVerts function. OnlyDeform
+ * style modifiers implicitly accept either mesh or CV
+ * input but should still declare flags appropriately.
+ */
+ eModifierTypeType_OnlyDeform,
+
+ eModifierTypeType_Constructive,
+ eModifierTypeType_Nonconstructive,
+} ModifierTypeType;
+
+typedef enum {
+ eModifierTypeFlag_AcceptsMesh = (1<<0),
+ eModifierTypeFlag_AcceptsCVs = (1<<1),
+ eModifierTypeFlag_SupportsMapping = (1<<2),
+ eModifierTypeFlag_SupportsEditmode = (1<<3),
+
+ /* For modifiers that support editmode this determines if the
+ * modifier should be enabled by default in editmode. This should
+ * only be used by modifiers that are relatively speedy and
+ * also generally used in editmode, otherwise let the user enable
+ * it by hand.
+ */
+ eModifierTypeFlag_EnableInEditmode = (1<<4),
+
+ /* For modifiers that require original data and so cannot
+ * be placed after any non-deformative modifier.
+ */
+ eModifierTypeFlag_RequiresOriginalData = (1<<5),
+} ModifierTypeFlag;
+
+typedef void (*ObjectWalkFunc)(void *userData, Object *ob, Object **obpoin);
+typedef void (*IDWalkFunc)(void *userData, Object *ob, ID **idpoin);
+
+typedef struct ModifierTypeInfo {
+ /* The user visible name for this modifier */
+ char name[32];
+
+ /* The DNA struct name for the modifier data type, used to
+ * write the DNA data out.
+ */
+ char structName[32];
+
+ /* The size of the modifier data type, used by allocation. */
+ int structSize;
+
+ ModifierTypeType type;
+ ModifierTypeFlag flags;
+
+
+ /********************* Non-optional functions *********************/
+
+ /* Copy instance data for this modifier type. Should copy all user
+ * level settings to the target modifier.
+ */
+ void (*copyData)(struct ModifierData *md, struct ModifierData *target);
+
+ /********************* Deform modifier functions *********************/
+
+ /* Only for deform types, should apply the deformation
+ * to the given vertex array. If the deformer requires information from
+ * the object it can obtain it from the derivedData argument if non-NULL,
+ * and otherwise the ob argument.
+ */
+ void (*deformVerts)(struct ModifierData *md, struct Object *ob,
+ struct DerivedMesh *derivedData,
+ float (*vertexCos)[3], int numVerts);
+
+ /* Like deformVerts but called during editmode (for supporting modifiers)
+ */
+ void (*deformVertsEM)(
+ struct ModifierData *md, struct Object *ob,
+ struct EditMesh *editData, struct DerivedMesh *derivedData,
+ float (*vertexCos)[3], int numVerts);
+
+ /* Set deform matrix per vertex for crazyspace correction */
+ void (*deformMatricesEM)(
+ struct ModifierData *md, struct Object *ob,
+ struct EditMesh *editData, struct DerivedMesh *derivedData,
+ float (*vertexCos)[3], float (*defMats)[3][3], int numVerts);
+
+ /********************* Non-deform modifier functions *********************/
+
+ /* For non-deform types: apply the modifier and return a derived
+ * data object (type is dependent on object type).
+ *
+ * The derivedData argument should always be non-NULL; the modifier
+ * should read the object data from the derived object instead of the
+ * actual object data.
+ *
+ * The useRenderParams argument indicates if the modifier is being
+ * applied in the service of the renderer which may alter quality
+ * settings.
+ *
+ * The isFinalCalc parameter indicates if the modifier is being
+ * calculated for a final result or for something temporary
+ * (like orcos). This is a hack at the moment, it is meant so subsurf
+ * can know if it is safe to reuse its internal cache.
+ *
+ * The modifier may reuse the derivedData argument (i.e. return it in
+ * modified form), but must not release it.
+ */
+ struct DerivedMesh *(*applyModifier)(
+ struct ModifierData *md, struct Object *ob,
+ struct DerivedMesh *derivedData,
+ int useRenderParams, int isFinalCalc);
+
+ /* Like applyModifier but called during editmode (for supporting
+ * modifiers).
+ *
+ * The derived object that is returned must support the operations that
+ * are expected from editmode objects. The same qualifications regarding
+ * derivedData apply as for applyModifier.
+ */
+ struct DerivedMesh *(*applyModifierEM)(
+ struct ModifierData *md, struct Object *ob,
+ struct EditMesh *editData,
+ struct DerivedMesh *derivedData);
+
+
+ /********************* Optional functions *********************/
+
+ /* Initialize new instance data for this modifier type, this function
+ * should set modifier variables to their default values.
+ *
+ * This function is optional.
+ */
+ void (*initData)(struct ModifierData *md);
+
+ /* Should return a CustomDataMask indicating what data this
+ * modifier needs. If (mask & (1 << (layer type))) != 0, this modifier
+ * needs that custom data layer. This function's return value can change
+ * depending on the modifier's settings.
+ *
+ * Note that this means extra data (e.g. vertex groups) - it is assumed
+ * that all modifiers need mesh data and deform modifiers need vertex
+ * coordinates.
+ *
+ * Note that this limits the number of custom data layer types to 32.
+ *
+ * If this function is not present or it returns 0, it is assumed that
+ * no extra data is needed.
+ *
+ * This function is optional.
+ */
+ CustomDataMask (*requiredDataMask)(struct ModifierData *md);
+
+ /* Free internal modifier data variables, this function should
+ * not free the md variable itself.
+ *
+ * This function is optional.
+ */
+ void (*freeData)(struct ModifierData *md);
+
+ /* Return a boolean value indicating if this modifier is able to be
+ * calculated based on the modifier data. This is *not* regarding the
+ * md->flag, that is tested by the system, this is just if the data
+ * validates (for example, a lattice will return false if the lattice
+ * object is not defined).
+ *
+ * This function is optional (assumes never disabled if not present).
+ */
+ int (*isDisabled)(struct ModifierData *md);
+
+ /* Add the appropriate relations to the DEP graph depending on the
+ * modifier data.
+ *
+ * This function is optional.
+ */
+ void (*updateDepgraph)(struct ModifierData *md, struct DagForest *forest,
+ struct Object *ob, struct DagNode *obNode);
+
+ /* Should return true if the modifier needs to be recalculated on time
+ * changes.
+ *
+ * This function is optional (assumes false if not present).
+ */
+ int (*dependsOnTime)(struct ModifierData *md);
+
+ /* Should call the given walk function on with a pointer to each Object
+ * pointer that the modifier data stores. This is used for linking on file
+ * load and for unlinking objects or forwarding object references.
+ *
+ * This function is optional.
+ */
+ void (*foreachObjectLink)(struct ModifierData *md, struct Object *ob,
+ ObjectWalkFunc walk, void *userData);
+
+ /* Should call the given walk function with a pointer to each ID
+ * pointer (i.e. each datablock pointer) that the modifier data
+ * stores. This is used for linking on file load and for
+ * unlinking datablocks or forwarding datablock references.
+ *
+ * This function is optional. If it is not present, foreachObjectLink
+ * will be used.
+ */
+ void (*foreachIDLink)(struct ModifierData *md, struct Object *ob,
+ IDWalkFunc walk, void *userData);
+} ModifierTypeInfo;
+
+ModifierTypeInfo *modifierType_getInfo (ModifierType type);
+
+/* Modifier utility calls, do call through type pointer and return
+ * default values if pointer is optional.
+ */
+struct ModifierData *modifier_new(int type);
+void modifier_free(struct ModifierData *md);
+
+void modifier_copyData(struct ModifierData *md, struct ModifierData *target);
+int modifier_dependsOnTime(struct ModifierData *md);
+int modifier_supportsMapping(struct ModifierData *md);
+int modifier_couldBeCage(struct ModifierData *md);
+int modifier_isDeformer(struct ModifierData *md);
+void modifier_setError(struct ModifierData *md, char *format, ...);
+
+void modifiers_foreachObjectLink(struct Object *ob,
+ ObjectWalkFunc walk,
+ void *userData);
+void modifiers_foreachIDLink(struct Object *ob,
+ IDWalkFunc walk,
+ void *userData);
+struct ModifierData *modifiers_findByType(struct Object *ob, ModifierType type);
+void modifiers_clearErrors(struct Object *ob);
+int modifiers_getCageIndex(struct Object *ob,
+ int *lastPossibleCageIndex_r);
+
+int modifiers_isSoftbodyEnabled(struct Object *ob);
+struct Object *modifiers_isDeformedByArmature(struct Object *ob);
+struct Object *modifiers_isDeformedByLattice(struct Object *ob);
+int modifiers_usesArmature(struct Object *ob, struct bArmature *arm);
+int modifiers_isDeformed(struct Object *ob);
+
+/* Calculates and returns a linked list of CustomDataMasks indicating the
+ * data required by each modifier in the stack pointed to by md for correct
+ * evaluation, assuming the data indicated by dataMask is required at the
+ * end of the stack.
+ */
+struct LinkNode *modifiers_calcDataMasks(struct ModifierData *md,
+ CustomDataMask dataMask);
+struct ModifierData *modifiers_getVirtualModifierList(struct Object *ob);
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_nla.h b/source/blender/blenkernel/BKE_nla.h
new file mode 100644
index 00000000000..560e5d5c33c
--- /dev/null
+++ b/source/blender/blenkernel/BKE_nla.h
@@ -0,0 +1,47 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BKE_NLA_H
+#define BKE_NLA_H
+
+struct bActionStrip;
+struct ListBase;
+struct Object;
+
+void free_actionstrip (struct bActionStrip* strip);
+void free_nlastrips (struct ListBase *nlalist);
+void copy_nlastrips (struct ListBase *dst, struct ListBase *src);
+void copy_actionstrip (struct bActionStrip **dst, struct bActionStrip **src);
+void find_stridechannel(struct Object *ob, struct bActionStrip *strip);
+struct bActionStrip *convert_action_to_strip (struct Object *ob);
+#endif
+
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
new file mode 100644
index 00000000000..e4ddc089a86
--- /dev/null
+++ b/source/blender/blenkernel/BKE_node.h
@@ -0,0 +1,347 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef BKE_NODE_H
+#define BKE_NODE_H
+
+
+
+struct ID;
+struct bNodeTree;
+struct bNode;
+struct bNodeLink;
+struct bNodeSocket;
+struct bNodeStack;
+struct uiBlock;
+struct rctf;
+struct ListBase;
+struct RenderData;
+struct Scene;
+
+#define SOCK_IN 1
+#define SOCK_OUT 2
+
+/* ************** NODE TYPE DEFINITIONS ***** */
+
+typedef struct bNodeSocketType {
+ int type, limit;
+ char *name;
+ float val1, val2, val3, val4; /* default alloc value for inputs */
+ float min, max; /* default range for inputs */
+
+ /* after this line is used internal only */
+ struct bNodeSocket *sock; /* used during verify_types */
+ struct bNodeSocket *internsock; /* group nodes, the internal socket counterpart */
+ int own_index; /* verify group nodes */
+
+} bNodeSocketType;
+
+typedef struct bNodeType {
+ void *next,*prev;
+ int type;
+ char *name;
+ float width, minwidth, maxwidth;
+ short nclass, flag;
+
+ bNodeSocketType *inputs, *outputs;
+
+ char storagename[64]; /* struct name for DNA */
+
+ void (*execfunc)(void *data, struct bNode *, struct bNodeStack **, struct bNodeStack **);
+
+ /* this line is set on startup of blender */
+ int (*butfunc)(struct uiBlock *, struct bNodeTree *, struct bNode *, struct rctf *);
+
+ void (*initfunc)(struct bNode *);
+ void (*freestoragefunc)(struct bNode *);
+ void (*copystoragefunc)(struct bNode *, struct bNode *);
+
+ /* for use with dynamic typedefs */
+ ID *id;
+ void *script; /* holds pointer to python script */
+ void *dict; /* holds pointer to python script dictionary (scope)*/
+
+} bNodeType;
+
+/* node->exec, now in use for composites (#define for break is same as ready yes) */
+#define NODE_PROCESSING 1
+#define NODE_READY 2
+#define NODE_BREAK 2
+#define NODE_FINISHED 4
+#define NODE_FREEBUFS 8
+
+/* nodetype->nclass, for add-menu and themes */
+#define NODE_CLASS_INPUT 0
+#define NODE_CLASS_OUTPUT 1
+#define NODE_CLASS_OP_COLOR 3
+#define NODE_CLASS_OP_VECTOR 4
+#define NODE_CLASS_OP_FILTER 5
+#define NODE_CLASS_GROUP 6
+#define NODE_CLASS_FILE 7
+#define NODE_CLASS_CONVERTOR 8
+#define NODE_CLASS_MATTE 9
+#define NODE_CLASS_DISTORT 10
+
+/* ************** GENERIC API, TREES *************** */
+
+void ntreeVerifyTypes(struct bNodeTree *ntree);
+
+struct bNodeTree *ntreeAddTree(int type);
+void ntreeInitTypes(struct bNodeTree *ntree);
+
+void ntreeMakeOwnType(struct bNodeTree *ntree);
+void ntreeFreeTree(struct bNodeTree *ntree);
+struct bNodeTree *ntreeCopyTree(struct bNodeTree *ntree, int internal_select);
+void ntreeMakeLocal(struct bNodeTree *ntree);
+
+void ntreeSocketUseFlags(struct bNodeTree *ntree);
+
+void ntreeSolveOrder(struct bNodeTree *ntree);
+
+void ntreeBeginExecTree(struct bNodeTree *ntree);
+void ntreeExecTree(struct bNodeTree *ntree, void *callerdata, int thread);
+void ntreeCompositExecTree(struct bNodeTree *ntree, struct RenderData *rd, int do_previews);
+void ntreeEndExecTree(struct bNodeTree *ntree);
+
+void ntreeInitPreview(struct bNodeTree *, int xsize, int ysize);
+void ntreeClearPreview(struct bNodeTree *ntree);
+
+void ntreeFreeCache(struct bNodeTree *ntree);
+
+/* ************** GENERIC API, NODES *************** */
+
+void nodeVerifyType(struct bNodeTree *ntree, struct bNode *node);
+
+void nodeAddToPreview(struct bNode *, float *, int, int);
+
+struct bNode *nodeAddNodeType(struct bNodeTree *ntree, int type, struct bNodeTree *ngroup);
+void nodeFreeNode(struct bNodeTree *ntree, struct bNode *node);
+struct bNode *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node);
+
+struct bNodeLink *nodeAddLink(struct bNodeTree *ntree, struct bNode *fromnode, struct bNodeSocket *fromsock, struct bNode *tonode, struct bNodeSocket *tosock);
+void nodeRemLink(struct bNodeTree *ntree, struct bNodeLink *link);
+
+struct bNodeLink *nodeFindLink(struct bNodeTree *ntree, struct bNodeSocket *from, struct bNodeSocket *to);
+int nodeCountSocketLinks(struct bNodeTree *ntree, struct bNodeSocket *sock);
+
+void nodeSetActive(struct bNodeTree *ntree, struct bNode *node);
+struct bNode *nodeGetActive(struct bNodeTree *ntree);
+struct bNode *nodeGetActiveID(struct bNodeTree *ntree, short idtype);
+void nodeClearActiveID(struct bNodeTree *ntree, short idtype);
+
+void NodeTagChanged(struct bNodeTree *ntree, struct bNode *node);
+void NodeTagIDChanged(struct bNodeTree *ntree, struct ID *id);
+
+/* ************** Groups ****************** */
+
+struct bNode *nodeMakeGroupFromSelected(struct bNodeTree *ntree);
+int nodeGroupUnGroup(struct bNodeTree *ntree, struct bNode *gnode);
+
+void nodeVerifyGroup(struct bNodeTree *ngroup);
+void nodeGroupSocketUseFlags(struct bNodeTree *ngroup);
+
+/* ************** COMMON NODES *************** */
+
+#define NODE_GROUP 2
+#define NODE_GROUP_MENU 1000
+
+extern bNodeType node_group_typeinfo;
+
+
+/* ************** SHADER NODES *************** */
+
+struct ShadeInput;
+struct ShadeResult;
+
+/* note: types are needed to restore callbacks, don't change values */
+/* range 1 - 100 is reserved for common nodes */
+/* using toolbox, we add node groups by assuming the values below don't exceed NODE_GROUP_MENU for now */
+
+#define SH_NODE_OUTPUT 1
+
+#define SH_NODE_MATERIAL 100
+#define SH_NODE_RGB 101
+#define SH_NODE_VALUE 102
+#define SH_NODE_MIX_RGB 103
+#define SH_NODE_VALTORGB 104
+#define SH_NODE_RGBTOBW 105
+#define SH_NODE_TEXTURE 106
+#define SH_NODE_NORMAL 107
+#define SH_NODE_GEOMETRY 108
+#define SH_NODE_MAPPING 109
+#define SH_NODE_CURVE_VEC 110
+#define SH_NODE_CURVE_RGB 111
+#define SH_NODE_CAMERA 114
+#define SH_NODE_MATH 115
+#define SH_NODE_VECT_MATH 116
+#define SH_NODE_SQUEEZE 117
+#define SH_NODE_MATERIAL_EXT 118
+#define SH_NODE_INVERT 119
+#define SH_NODE_SEPRGB 120
+#define SH_NODE_COMBRGB 121
+#define SH_NODE_HUE_SAT 122
+
+
+/* custom defines options for Material node */
+#define SH_NODE_MAT_DIFF 1
+#define SH_NODE_MAT_SPEC 2
+#define SH_NODE_MAT_NEG 4
+
+/* the type definitions array */
+extern struct ListBase node_all_shaders;
+
+/* API */
+
+void ntreeShaderExecTree(struct bNodeTree *ntree, struct ShadeInput *shi, struct ShadeResult *shr);
+void ntreeShaderGetTexcoMode(struct bNodeTree *ntree, int osa, short *texco, int *mode);
+void nodeShaderSynchronizeID(struct bNode *node, int copyto);
+
+ /* switch material render loop */
+extern void (*node_shader_lamp_loop)(struct ShadeInput *, struct ShadeResult *);
+void set_node_shader_lamp_loop(void (*lamp_loop_func)(struct ShadeInput *, struct ShadeResult *));
+
+
+/* ************** COMPOSITE NODES *************** */
+
+/* output socket defines */
+#define RRES_OUT_IMAGE 0
+#define RRES_OUT_ALPHA 1
+#define RRES_OUT_Z 2
+#define RRES_OUT_NORMAL 3
+#define RRES_OUT_UV 4
+#define RRES_OUT_VEC 5
+#define RRES_OUT_RGBA 6
+#define RRES_OUT_DIFF 7
+#define RRES_OUT_SPEC 8
+#define RRES_OUT_SHADOW 9
+#define RRES_OUT_AO 10
+#define RRES_OUT_REFLECT 11
+#define RRES_OUT_REFRACT 12
+#define RRES_OUT_RADIO 13
+#define RRES_OUT_INDEXOB 14
+
+/* note: types are needed to restore callbacks, don't change values */
+#define CMP_NODE_VIEWER 201
+#define CMP_NODE_RGB 202
+#define CMP_NODE_VALUE 203
+#define CMP_NODE_MIX_RGB 204
+#define CMP_NODE_VALTORGB 205
+#define CMP_NODE_RGBTOBW 206
+#define CMP_NODE_NORMAL 207
+#define CMP_NODE_CURVE_VEC 208
+#define CMP_NODE_CURVE_RGB 209
+#define CMP_NODE_ALPHAOVER 210
+#define CMP_NODE_BLUR 211
+#define CMP_NODE_FILTER 212
+#define CMP_NODE_MAP_VALUE 213
+#define CMP_NODE_TIME 214
+#define CMP_NODE_VECBLUR 215
+#define CMP_NODE_SEPRGBA 216
+#define CMP_NODE_SEPHSVA 217
+#define CMP_NODE_SETALPHA 218
+#define CMP_NODE_HUE_SAT 219
+#define CMP_NODE_IMAGE 220
+#define CMP_NODE_R_LAYERS 221
+#define CMP_NODE_COMPOSITE 222
+#define CMP_NODE_OUTPUT_FILE 223
+#define CMP_NODE_TEXTURE 224
+#define CMP_NODE_TRANSLATE 225
+#define CMP_NODE_ZCOMBINE 226
+#define CMP_NODE_COMBRGBA 227
+#define CMP_NODE_DILATEERODE 228
+#define CMP_NODE_ROTATE 229
+#define CMP_NODE_SCALE 230
+#define CMP_NODE_SEPYCCA 231
+#define CMP_NODE_COMBYCCA 232
+#define CMP_NODE_SEPYUVA 233
+#define CMP_NODE_COMBYUVA 234
+#define CMP_NODE_DIFF_MATTE 235
+#define CMP_NODE_COLOR_SPILL 236
+#define CMP_NODE_CHROMA 237
+#define CMP_NODE_CHANNEL_MATTE 238
+#define CMP_NODE_FLIP 239
+#define CMP_NODE_SPLITVIEWER 240
+#define CMP_NODE_INDEX_MASK 241
+#define CMP_NODE_MAP_UV 242
+#define CMP_NODE_ID_MASK 243
+#define CMP_NODE_DEFOCUS 244
+#define CMP_NODE_DISPLACE 245
+#define CMP_NODE_COMBHSVA 246
+#define CMP_NODE_MATH 247
+#define CMP_NODE_LUMA_MATTE 248
+#define CMP_NODE_BRIGHTCONTRAST 249
+#define CMP_NODE_GAMMA 250
+#define CMP_NODE_INVERT 251
+#define CMP_NODE_NORMALIZE 252
+#define CMP_NODE_CROP 253
+
+#define CMP_NODE_GLARE 301
+#define CMP_NODE_TONEMAP 302
+#define CMP_NODE_LENSDIST 303
+
+/* channel toggles */
+#define CMP_CHAN_RGB 1
+#define CMP_CHAN_A 2
+#define CMP_CHAN_R 4
+#define CMP_CHAN_G 8
+#define CMP_CHAN_B 16
+
+/* filter types */
+#define CMP_FILT_SOFT 0
+#define CMP_FILT_SHARP 1
+#define CMP_FILT_LAPLACE 2
+#define CMP_FILT_SOBEL 3
+#define CMP_FILT_PREWITT 4
+#define CMP_FILT_KIRSCH 5
+#define CMP_FILT_SHADOW 6
+
+/* scale node type, in custom1 */
+#define CMP_SCALE_RELATIVE 0
+#define CMP_SCALE_ABSOLUTE 1
+
+
+/* the type definitions array */
+extern struct ListBase node_all_composit;
+
+/* API */
+struct CompBuf;
+void ntreeCompositTagRender(struct Scene *sce);
+int ntreeCompositTagAnimated(struct bNodeTree *ntree);
+void ntreeCompositTagGenerators(struct bNodeTree *ntree);
+void ntreeCompositForceHidden(struct bNodeTree *ntree);
+
+void free_compbuf(struct CompBuf *cbuf); /* internal...*/
+
+void init_nodesystem(void);
+void free_nodesystem(void);
+
+#endif
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
new file mode 100644
index 00000000000..6e363515f41
--- /dev/null
+++ b/source/blender/blenkernel/BKE_object.h
@@ -0,0 +1,118 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * General operations, lookup, etc. for blender objects.
+ */
+
+#ifndef BKE_OBJECT_H
+#define BKE_OBJECT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct Base;
+struct Object;
+struct Camera;
+struct BoundBox;
+struct View3D;
+struct SoftBody;
+struct Group;
+struct bAction;
+
+void clear_workob(void);
+void copy_baseflags(void);
+void copy_objectflags(void);
+struct SoftBody *copy_softbody(struct SoftBody *sb);
+void update_base_layer(struct Object *ob);
+
+void free_object(struct Object *ob);
+void object_free_display(struct Object *ob);
+void object_free_modifiers(struct Object *ob);
+
+void object_make_proxy(struct Object *ob, struct Object *target, struct Object *gob);
+
+void unlink_object(struct Object *ob);
+int exist_object(struct Object *obtest);
+void *add_camera(char *name);
+struct Camera *copy_camera(struct Camera *cam);
+void make_local_camera(struct Camera *cam);
+float dof_camera(struct Object *ob);
+void *add_lamp(char *name);
+struct Lamp *copy_lamp(struct Lamp *la);
+void make_local_lamp(struct Lamp *la);
+void free_camera(struct Camera *ca);
+void free_lamp(struct Lamp *la);
+void *add_wave(void);
+
+struct Object *add_only_object(int type, char *name);
+struct Object *add_object(int type);
+void base_init_from_view3d(struct Base *base, struct View3D *v3d);
+
+struct Object *copy_object(struct Object *ob);
+void expand_local_object(struct Object *ob);
+void make_local_object(struct Object *ob);
+void set_mblur_offs(float blur);
+void set_field_offs(float field);
+void disable_speed_curve(int val);
+
+float bsystem_time(struct Object *ob, float cfra, float ofs);
+void object_to_mat3(struct Object *ob, float mat[][3]);
+void object_to_mat4(struct Object *ob, float mat[][4]);
+
+void set_no_parent_ipo(int val);
+
+void disable_where_script(short on);
+int during_script(void);
+void disable_where_scriptlink(short on);
+int during_scriptlink(void);
+
+void where_is_object_time(struct Object *ob, float ctime);
+void where_is_object(struct Object *ob);
+void where_is_object_simul(struct Object *ob);
+
+void what_does_parent(struct Object *ob);
+
+struct BoundBox *unit_boundbox(void);
+void boundbox_set_from_min_max(struct BoundBox *bb, float min[3], float max[3]);
+struct BoundBox *object_get_boundbox(struct Object *ob);
+void object_boundbox_flag(struct Object *ob, int flag, int set);
+void minmax_object(struct Object *ob, float *min, float *max);
+void minmax_object_duplis(struct Object *ob, float *min, float *max);
+void solve_tracking (struct Object *ob, float targetmat[][4]);
+
+void object_handle_update(struct Object *ob);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_packedFile.h b/source/blender/blenkernel/BKE_packedFile.h
new file mode 100644
index 00000000000..4b362bbb38f
--- /dev/null
+++ b/source/blender/blenkernel/BKE_packedFile.h
@@ -0,0 +1,64 @@
+/**
+ * blenlib/BKE_packedFile.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BKE_PACKEDFILE_H
+#define BKE_PACKEDFILE_H
+
+#define RET_OK 0
+#define RET_ERROR 1
+
+struct PackedFile;
+struct VFont;
+struct bSample;
+struct bSound;
+struct Image;
+
+struct PackedFile * newPackedFile(char * filename);
+struct PackedFile * newPackedFileMemory(void *mem, int memlen);
+
+int seekPackedFile(struct PackedFile * pf, int offset, int whence);
+void rewindPackedFile(struct PackedFile * pf);
+int readPackedFile(struct PackedFile * pf, void * data, int size);
+int countPackedFiles(void);
+void freePackedFile(struct PackedFile * pf);
+void packAll(void);
+int writePackedFile(char * filename, struct PackedFile *pf, int guimode);
+int checkPackedFile(char * filename, struct PackedFile * pf);
+char * unpackFile(char * abs_name, char * local_name, struct PackedFile * pf, int how);
+int unpackVFont(struct VFont * vfont, int how);
+int unpackSample(struct bSample *sample, int how);
+int unpackImage(struct Image * ima, int how);
+void unpackAll(int how);
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_plugin_types.h b/source/blender/blenkernel/BKE_plugin_types.h
new file mode 100644
index 00000000000..2b7c6c06832
--- /dev/null
+++ b/source/blender/blenkernel/BKE_plugin_types.h
@@ -0,0 +1,72 @@
+/**
+ * blenlib/BKE_plugin_types.h (mar-2001 nzc)
+ *
+ * Renderrecipe and scene decription. The fact that there is a
+ * hierarchy here is a bit strange, and not desirable.
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BKE_PLUGIN_TYPES_H
+#define BKE_PLUGIN_TYPES_H
+
+struct ImBuf;
+
+typedef int (*TexDoit)(int, void*, float*, float*, float*);
+typedef void (*SeqDoit)(void*, float, float, int, int,
+ struct ImBuf*, struct ImBuf*,
+ struct ImBuf*, struct ImBuf*);
+
+typedef struct VarStruct {
+ int type;
+ char name[16];
+ float def, min, max;
+ char tip[80];
+} VarStruct;
+
+typedef struct _PluginInfo {
+ char *name;
+ char *snames;
+
+ int stypes;
+ int nvars;
+ VarStruct *varstr;
+ float *result;
+ float *cfra;
+
+ void (*init)(void);
+ void (*callback)(int);
+ TexDoit tex_doit;
+ SeqDoit seq_doit;
+ void (*instance_init)(void *);
+} PluginInfo;
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_property.h b/source/blender/blenkernel/BKE_property.h
new file mode 100644
index 00000000000..c8af07e3ee8
--- /dev/null
+++ b/source/blender/blenkernel/BKE_property.h
@@ -0,0 +1,55 @@
+/**
+ * blenkernel/BKE_property.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BKE_PROPERTY_H
+#define BKE_PROPERTY_H
+
+struct bProperty;
+struct ListBase;
+struct Object;
+
+void free_property(struct bProperty *prop);
+void free_properties(struct ListBase *lb);
+struct bProperty *copy_property(struct bProperty *prop);
+void copy_properties(struct ListBase *lbn, struct ListBase *lbo);
+void init_property(struct bProperty *prop);
+struct bProperty *new_property(int type);
+struct bProperty *get_property(struct Object *ob, char *name);
+int compare_property(struct bProperty *prop, char *str);
+void set_property(struct bProperty *prop, char *str);
+void add_property(struct bProperty *prop, char *str);
+void set_property_valstr(struct bProperty *prop, char *str);
+void cp_property(struct bProperty *prop1, struct bProperty *prop2);
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_sca.h b/source/blender/blenkernel/BKE_sca.h
new file mode 100644
index 00000000000..62ed06665fe
--- /dev/null
+++ b/source/blender/blenkernel/BKE_sca.h
@@ -0,0 +1,75 @@
+/**
+ * blenlib/BKE_sca.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BKE_SCA_H
+#define BKE_SCA_H
+
+struct Text;
+struct bSensor;
+struct Object;
+struct bController;
+struct bActuator;
+
+void unlink_controller(struct bController *cont);
+void unlink_controllers(struct ListBase *lb);
+void free_controller(struct bController *cont);
+void free_controllers(struct ListBase *lb);
+
+void unlink_actuator(struct bActuator *act);
+void unlink_actuators(struct ListBase *lb);
+void free_actuator(struct bActuator *act);
+void free_actuators(struct ListBase *lb);
+
+void free_text_controllers(struct Text *txt);
+void free_sensor(struct bSensor *sens);
+void free_sensors(struct ListBase *lb);
+struct bSensor *copy_sensor(struct bSensor *sens);
+void copy_sensors(struct ListBase *lbn, struct ListBase *lbo);
+void init_sensor(struct bSensor *sens);
+struct bSensor *new_sensor(int type);
+struct bController *copy_controller(struct bController *cont);
+void copy_controllers(struct ListBase *lbn, struct ListBase *lbo);
+void init_controller(struct bController *cont);
+struct bController *new_controller(int type);
+struct bActuator *copy_actuator(struct bActuator *act);
+void copy_actuators(struct ListBase *lbn, struct ListBase *lbo);
+void init_actuator(struct bActuator *act);
+struct bActuator *new_actuator(int type);
+void clear_sca_new_poins_ob(struct Object *ob);
+void clear_sca_new_poins(void);
+void set_sca_new_poins_ob(struct Object *ob);
+void set_sca_new_poins(void);
+void sca_remove_ob_poin(struct Object *obt, struct Object *ob);
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h
new file mode 100644
index 00000000000..69ff6876acd
--- /dev/null
+++ b/source/blender/blenkernel/BKE_scene.h
@@ -0,0 +1,84 @@
+/**
+ * blenlib/BKE_scene.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BKE_SCENE_H
+#define BKE_SCENE_H
+
+struct Scene;
+struct Object;
+struct Base;
+struct AviCodecData;
+struct QuicktimeCodecData;
+
+/* sequence related defines */
+#define WHILE_SEQ(base) { \
+ int totseq_, seq_; Sequence **seqar; \
+ build_seqar( base, &seqar, &totseq_); \
+ for(seq_ = 0; seq_ < totseq_; seq_++) { \
+ seq= seqar[seq_];
+
+
+#define END_SEQ } \
+ if(seqar) MEM_freeN(seqar); \
+}
+
+/* note; doesn't work when scene is empty */
+#define SETLOOPER(s, b) sce= s, b= sce->base.first; b; b= (b->next?b->next:sce->set?(sce=sce->set)->base.first:NULL)
+
+
+void free_avicodecdata(struct AviCodecData *acd);
+void free_qtcodecdata(struct QuicktimeCodecData *acd);
+
+void free_scene(struct Scene *me);
+struct Scene *add_scene(char *name);
+struct Base *object_in_scene(struct Object *ob, struct Scene *sce);
+
+void set_scene_bg(struct Scene *sce);
+void set_scene_name(char *name);
+
+int next_object(int val, struct Base **base, struct Object **ob);
+struct Object *scene_find_camera(struct Scene *sc);
+
+struct Base *scene_add_base(struct Scene *sce, struct Object *ob);
+void scene_deselect_all(struct Scene *sce);
+void scene_select_base(struct Scene *sce, struct Base *selbase);
+
+/* checks for cycle, returns 1 if it's all OK */
+int scene_check_setscene(struct Scene *sce);
+
+void scene_update_for_newframe(struct Scene *sce, unsigned int lay);
+
+void scene_add_render_layer(struct Scene *sce);
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h
new file mode 100644
index 00000000000..e20b00a00e7
--- /dev/null
+++ b/source/blender/blenkernel/BKE_screen.h
@@ -0,0 +1,40 @@
+/**
+ * blenlib/BKE_screen.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BKE_SCREEN_H
+#define BKE_SCREEN_H
+
+void free_screen(struct bScreen *sc);
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_script.h b/source/blender/blenkernel/BKE_script.h
new file mode 100644
index 00000000000..70f3d58fcae
--- /dev/null
+++ b/source/blender/blenkernel/BKE_script.h
@@ -0,0 +1,49 @@
+/**
+ * blenlib/BKE_script.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BKE_SCRIPT_H
+#define BKE_SCRIPT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct Script;
+
+void free_script (struct Script *script);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BKE_SCRIPT_H */
diff --git a/source/blender/blenkernel/BKE_softbody.h b/source/blender/blenkernel/BKE_softbody.h
new file mode 100644
index 00000000000..15200bf46f8
--- /dev/null
+++ b/source/blender/blenkernel/BKE_softbody.h
@@ -0,0 +1,58 @@
+/**
+ * BKE_softbody.h
+ *
+ * $Id: BKE_softbody.h
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BKE_SOFTBODY_H
+#define BKE_SOFTBODY_H
+
+struct Object;
+struct SoftBody;
+
+/* allocates and initializes general main data */
+extern struct SoftBody *sbNew(void);
+
+/* frees internal data and softbody itself */
+extern void sbFree(struct SoftBody *sb);
+
+/* do one simul step, reading and writing vertex locs from given array */
+extern void sbObjectStep(struct Object *ob, float framnr, float (*vertexCos)[3], int numVerts);
+
+/* makes totally fresh start situation, resets time */
+extern void sbObjectToSoftbody(struct Object *ob);
+
+/* links the softbody module to a 'test for Interrupt' function */
+/* pass NULL to unlink again */
+extern void sbSetInterruptCallBack(int (*f)(void));
+
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h
new file mode 100644
index 00000000000..0a747847b11
--- /dev/null
+++ b/source/blender/blenkernel/BKE_sound.h
@@ -0,0 +1,55 @@
+/**
+ * sound.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BKE_SOUND_H
+#define BKE_SOUND_H
+
+struct PackedFile;
+struct bSound;
+struct bSample;
+struct ListBase;
+
+/* bad bad global... */
+extern struct ListBase *samples;
+
+void sound_free_all_samples(void);
+
+/* void *sound_get_listener(void); implemented in src!also declared there now */
+
+void sound_set_packedfile(struct bSample* sample, struct PackedFile* pf);
+struct PackedFile* sound_find_packedfile(struct bSound* sound);
+void sound_free_sample(struct bSample* sample);
+void sound_free_sound(struct bSound* sound);
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_subsurf.h b/source/blender/blenkernel/BKE_subsurf.h
new file mode 100644
index 00000000000..459519913c5
--- /dev/null
+++ b/source/blender/blenkernel/BKE_subsurf.h
@@ -0,0 +1,49 @@
+/* $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BKE_SUBSURF_H
+#define BKE_SUBSURF_H
+
+struct Mesh;
+struct Object;
+struct DerivedMesh;
+struct EditMesh;
+struct SubsurfModifierData;
+
+struct DerivedMesh *subsurf_make_derived_from_derived(
+ struct DerivedMesh *dm,
+ struct SubsurfModifierData *smd,
+ int useRenderParams, float (*vertCos)[3],
+ int isFinalCalc, int editMode);
+
+void subsurf_calculate_limit_positions(Mesh *me, float (*positions_r)[3]);
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h
new file mode 100644
index 00000000000..35f0ee841be
--- /dev/null
+++ b/source/blender/blenkernel/BKE_text.h
@@ -0,0 +1,144 @@
+/**
+ * blenlib/BKE_text.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BKE_TEXT_H
+#define BKE_TEXT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct Text;
+struct TextLine;
+struct SpaceText;
+
+void free_text (struct Text *text);
+void txt_set_undostate (int u);
+int txt_get_undostate (void);
+struct Text* add_empty_text (char *name);
+int reopen_text (struct Text *text);
+struct Text* add_text (char *file);
+struct Text* copy_text (struct Text *ta);
+
+void txt_free_cut_buffer (void);
+
+char* txt_to_buf (struct Text *text);
+void txt_clean_text (struct Text *text);
+void txt_order_cursors (struct Text *text);
+int txt_find_string (struct Text *text, char *findstr);
+int txt_has_sel (struct Text *text);
+int txt_get_span (struct TextLine *from, struct TextLine *to);
+void txt_move_up (struct Text *text, short sel);
+void txt_move_down (struct Text *text, short sel);
+void txt_move_left (struct Text *text, short sel);
+void txt_move_right (struct Text *text, short sel);
+void txt_move_bof (struct Text *text, short sel);
+void txt_move_eof (struct Text *text, short sel);
+void txt_move_bol (struct Text *text, short sel);
+void txt_move_eol (struct Text *text, short sel);
+void txt_move_toline (struct Text *text, unsigned int line, short sel);
+void txt_pop_sel (struct Text *text);
+void txt_delete_char (struct Text *text);
+void txt_copy_sel (struct Text *text);
+void txt_sel_all (struct Text *text);
+void txt_sel_line (struct Text *text);
+void txt_print_cutbuffer (void);
+void txt_cut_sel (struct Text *text);
+char* txt_sel_to_buf (struct Text *text);
+void txt_insert_buf (struct Text *text, char *in_buffer);
+void txt_paste (struct Text *text);
+void txt_print_undo (struct Text *text);
+void txt_undo_add_toop (struct Text *text, int op, unsigned int froml, unsigned short fromc, unsigned int tol, unsigned short toc);
+void txt_do_undo (struct Text *text);
+void txt_do_redo (struct Text *text);
+void txt_split_curline (struct Text *text);
+void txt_backspace_char (struct Text *text);
+int txt_add_char (struct Text *text, char add);
+void txt_find_panel (struct SpaceText *st, int again);
+void run_python_script (struct SpaceText *st);
+int jumptoline_interactive (struct SpaceText *st);
+void txt_export_to_object (struct Text *text);
+void txt_export_to_objects(struct Text *text);
+void unindent (struct Text *text);
+void comment (struct Text *text);
+void indent (struct Text *text);
+void uncomment (struct Text *text);
+int setcurr_tab (struct Text *text);
+void convert_tabs (struct SpaceText *st, int tab);
+
+/* Undo opcodes */
+
+/* Simple main cursor movement */
+#define UNDO_CLEFT 001
+#define UNDO_CRIGHT 002
+#define UNDO_CUP 003
+#define UNDO_CDOWN 004
+
+/* Simple selection cursor movement */
+#define UNDO_SLEFT 005
+#define UNDO_SRIGHT 006
+#define UNDO_SUP 007
+#define UNDO_SDOWN 021
+
+/* Complex movement (opcode is followed
+ * by 4 character line ID + a 2 character
+ * position ID and opcode (repeat)) */
+#define UNDO_CTO 022
+#define UNDO_STO 023
+
+/* Complex editing (opcode is followed
+ * by 1 character ID and opcode (repeat)) */
+#define UNDO_INSERT 024
+#define UNDO_BS 025
+#define UNDO_DEL 026
+
+/* Text block (opcode is followed
+ * by 4 character length ID + the text
+ * block itself + the 4 character length
+ * ID (repeat) and opcode (repeat)) */
+#define UNDO_DBLOCK 027 /* Delete block */
+#define UNDO_IBLOCK 030 /* Insert block */
+
+/* Misc */
+#define UNDO_SWAP 031 /* Swap cursors */
+
+#define UNDO_INDENT 032
+#define UNDO_UNINDENT 033
+#define UNDO_COMMENT 034
+#define UNDO_UNCOMMENT 035
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/source/blender/blenkernel/BKE_texture.h b/source/blender/blenkernel/BKE_texture.h
new file mode 100644
index 00000000000..902423482b1
--- /dev/null
+++ b/source/blender/blenkernel/BKE_texture.h
@@ -0,0 +1,80 @@
+/**
+ * blenlib/BKE_texture.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BKE_TEXTURE_H
+#define BKE_TEXTURE_H
+
+struct Tex;
+struct MTex;
+struct PluginTex;
+struct LampRen;
+struct ColorBand;
+struct HaloRen;
+struct TexMapping;
+struct EnvMap;
+
+/* in ColorBand struct */
+#define MAXCOLORBAND 32
+
+
+void free_texture(struct Tex *t);
+int test_dlerr(const char *name, const char *symbol);
+void open_plugin_tex(struct PluginTex *pit);
+struct PluginTex *add_plugin_tex(char *str);
+void free_plugin_tex(struct PluginTex *pit);
+
+void init_colorband(struct ColorBand *coba, int rangetype);
+struct ColorBand *add_colorband(int rangetype);
+int do_colorband(struct ColorBand *coba, float in, float out[4]);
+
+void default_tex(struct Tex *tex);
+struct Tex *add_texture(char *name);
+void default_mtex(struct MTex *mtex);
+struct MTex *add_mtex(void);
+struct Tex *copy_texture(struct Tex *tex);
+void make_local_texture(struct Tex *tex);
+void autotexname(struct Tex *tex);
+struct Tex *give_current_texture(struct Object *ob, int act);
+
+struct TexMapping *add_mapping(void);
+void init_mapping(struct TexMapping *texmap);
+
+
+void BKE_free_envmapdata(struct EnvMap *env);
+void BKE_free_envmap(struct EnvMap *env);
+struct EnvMap *BKE_add_envmap(void);
+struct EnvMap *BKE_copy_envmap(struct EnvMap *env);
+
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_utildefines.h b/source/blender/blenkernel/BKE_utildefines.h
new file mode 100644
index 00000000000..a30617a2f15
--- /dev/null
+++ b/source/blender/blenkernel/BKE_utildefines.h
@@ -0,0 +1,192 @@
+/*
+ $Id$
+
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef BKE_UTILDEFINES_H
+#define BKE_UTILDEFINES_H
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+/* these values need to be hardcoded in structs, dna does not recognize defines */
+/* also defined in DNA_space_types.h */
+#ifndef FILE_MAXDIR
+#define FILE_MAXDIR 160
+#define FILE_MAXFILE 80
+#define FILE_MAX 240
+#endif
+
+#define ELEM(a, b, c) ( (a)==(b) || (a)==(c) )
+#define ELEM3(a, b, c, d) ( ELEM(a, b, c) || (a)==(d) )
+#define ELEM4(a, b, c, d, e) ( ELEM(a, b, c) || ELEM(a, d, e) )
+#define ELEM5(a, b, c, d, e, f) ( ELEM(a, b, c) || ELEM3(a, d, e, f) )
+#define ELEM6(a, b, c, d, e, f, g) ( ELEM(a, b, c) || ELEM4(a, d, e, f, g) )
+#define ELEM7(a, b, c, d, e, f, g, h) ( ELEM3(a, b, c, d) || ELEM4(a, e, f, g, h) )
+#define ELEM8(a, b, c, d, e, f, g, h, i) ( ELEM4(a, b, c, d, e) || ELEM4(a, f, g, h, i) )
+#define ELEM9(a, b, c, d, e, f, g, h, i, j) ( ELEM4(a, b, c, d, e) || ELEM5(a, f, g, h, i, j) )
+
+/* string compare */
+#define STREQ(str, a) ( strcmp((str), (a))==0 )
+#define STREQ2(str, a, b) ( STREQ(str, a) || STREQ(str, b) )
+#define STREQ3(str, a, b, c) ( STREQ2(str, a, b) || STREQ(str, c) )
+
+/* min/max */
+#define MIN2(x,y) ( (x)<(y) ? (x) : (y) )
+#define MIN3(x,y,z) MIN2( MIN2((x),(y)) , (z) )
+#define MIN4(x,y,z,a) MIN2( MIN2((x),(y)) , MIN2((z),(a)) )
+
+#define MAX2(x,y) ( (x)>(y) ? (x) : (y) )
+#define MAX3(x,y,z) MAX2( MAX2((x),(y)) , (z) )
+#define MAX4(x,y,z,a) MAX2( MAX2((x),(y)) , MAX2((z),(a)) )
+
+#define INIT_MINMAX(min, max) { (min)[0]= (min)[1]= (min)[2]= 1.0e30f; (max)[0]= (max)[1]= (max)[2]= -1.0e30f; }
+
+#define INIT_MINMAX2(min, max) { (min)[0]= (min)[1]= 1.0e30f; (max)[0]= (max)[1]= -1.0e30f; }
+
+#define DO_MINMAX(vec, min, max) { if( (min)[0]>(vec)[0] ) (min)[0]= (vec)[0]; \
+ if( (min)[1]>(vec)[1] ) (min)[1]= (vec)[1]; \
+ if( (min)[2]>(vec)[2] ) (min)[2]= (vec)[2]; \
+ if( (max)[0]<(vec)[0] ) (max)[0]= (vec)[0]; \
+ if( (max)[1]<(vec)[1] ) (max)[1]= (vec)[1]; \
+ if( (max)[2]<(vec)[2] ) (max)[2]= (vec)[2]; } \
+
+#define DO_MINMAX2(vec, min, max) { if( (min)[0]>(vec)[0] ) (min)[0]= (vec)[0]; \
+ if( (min)[1]>(vec)[1] ) (min)[1]= (vec)[1]; \
+ if( (max)[0]<(vec)[0] ) (max)[0]= (vec)[0]; \
+ if( (max)[1]<(vec)[1] ) (max)[1]= (vec)[1]; }
+
+#define MINSIZE(val, size) ( ((val)>=0.0) ? (((val)<(size)) ? (size): (val)) : ( ((val)>(-size)) ? (-size) : (val)))
+
+/* some math and copy defines */
+
+#define SWAP(type, a, b) { type sw_ap; sw_ap=(a); (a)=(b); (b)=sw_ap; }
+
+#define ABS(a) ( (a)<0 ? (-(a)) : (a) )
+
+#define VECCOPY(v1,v2) {*(v1)= *(v2); *(v1+1)= *(v2+1); *(v1+2)= *(v2+2);}
+#define VECCOPY2D(v1,v2) {*(v1)= *(v2); *(v1+1)= *(v2+1);}
+#define QUATCOPY(v1,v2) {*(v1)= *(v2); *(v1+1)= *(v2+1); *(v1+2)= *(v2+2); *(v1+3)= *(v2+3);}
+#define LONGCOPY(a, b, c) {int lcpc=c, *lcpa=(int *)a, *lcpb=(int *)b; while(lcpc-->0) *(lcpa++)= *(lcpb++);}
+
+
+#define VECADD(v1,v2,v3) {*(v1)= *(v2) + *(v3); *(v1+1)= *(v2+1) + *(v3+1); *(v1+2)= *(v2+2) + *(v3+2);}
+#define VECSUB(v1,v2,v3) {*(v1)= *(v2) - *(v3); *(v1+1)= *(v2+1) - *(v3+1); *(v1+2)= *(v2+2) - *(v3+2);}
+#define VECADDFAC(v1,v2,v3,fac) {*(v1)= *(v2) + *(v3)*(fac); *(v1+1)= *(v2+1) + *(v3+1)*(fac); *(v1+2)= *(v2+2) + *(v3+2)*(fac);}
+
+#define INPR(v1, v2) ( (v1)[0]*(v2)[0] + (v1)[1]*(v2)[1] + (v1)[2]*(v2)[2] )
+
+
+/* some misc stuff.... */
+#define CLAMP(a, b, c) if((a)<(b)) (a)=(b); else if((a)>(c)) (a)=(c)
+#define CLAMPIS(a, b, c) ((a)<(b) ? (b) : (a)>(c) ? (c) : (a))
+#define CLAMPTEST(a, b, c) if((b)<(c)) {CLAMP(a, b, c);} else {CLAMP(a, c, b);}
+
+#define IS_EQ(a,b) ((fabs((double)(a)-(b)) >= (double) FLT_EPSILON) ? 0 : 1)
+
+#define IS_EQT(a, b, c) ((a > b)? (((a-b) <= c)? 1:0) : ((((b-a) <= c)? 1:0)))
+#define IN_RANGE(a, b, c) ((b < c)? ((b<a && a<c)? 1:0) : ((c<a && a<b)? 1:0))
+
+/* this weirdo pops up in two places ... */
+#if !defined(WIN32) && !defined(__BeOS)
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+#endif
+
+/* INTEGER CODES */
+#if defined(__sgi) || defined (__sparc) || defined (__sparc__) || defined (__PPC__) || defined (__ppc__) || defined (__BIG_ENDIAN__)
+ /* Big Endian */
+#define MAKE_ID(a,b,c,d) ( (int)(a)<<24 | (int)(b)<<16 | (c)<<8 | (d) )
+#else
+ /* Little Endian */
+#define MAKE_ID(a,b,c,d) ( (int)(d)<<24 | (int)(c)<<16 | (b)<<8 | (a) )
+#endif
+
+#define ID_NEW(a) if( (a) && (a)->id.newid ) (a)= (void *)(a)->id.newid
+
+#define FORM MAKE_ID('F','O','R','M')
+#define DDG1 MAKE_ID('3','D','G','1')
+#define DDG2 MAKE_ID('3','D','G','2')
+#define DDG3 MAKE_ID('3','D','G','3')
+#define DDG4 MAKE_ID('3','D','G','4')
+
+#define GOUR MAKE_ID('G','O','U','R')
+
+#define BLEN MAKE_ID('B','L','E','N')
+#define DER_ MAKE_ID('D','E','R','_')
+#define V100 MAKE_ID('V','1','0','0')
+
+#define DATA MAKE_ID('D','A','T','A')
+#define GLOB MAKE_ID('G','L','O','B')
+#define IMAG MAKE_ID('I','M','A','G')
+
+#define DNA1 MAKE_ID('D','N','A','1')
+#define TEST MAKE_ID('T','E','S','T')
+#define REND MAKE_ID('R','E','N','D')
+#define USER MAKE_ID('U','S','E','R')
+
+#define ENDB MAKE_ID('E','N','D','B')
+
+
+/* This one rotates the bytes in an int */
+#define SWITCH_INT(a) { \
+ char s_i, *p_i; \
+ p_i= (char *)&(a); \
+ s_i=p_i[0]; p_i[0]=p_i[3]; p_i[3]=s_i; \
+ s_i=p_i[1]; p_i[1]=p_i[2]; p_i[2]=s_i; }
+
+#define SWITCH_SHORT(a) { \
+ char s_i, *p_i; \
+ p_i= (char *)&(a); \
+ s_i=p_i[0]; p_i[0]=p_i[1]; p_i[1]=s_i; }
+
+
+/* Bit operations */
+#define BTST(a,b) ( ( (a) & 1<<(b) )!=0 )
+#define BSET(a,b) ( (a) | 1<<(b) )
+#define BCLR(a,b) ( (a) & ~(1<<(b)) )
+/* bit-row */
+#define BROW(min, max) (((max)>=31? 0xFFFFFFFF: (1<<(max+1))-1) - ((min)? ((1<<(min))-1):0) )
+
+
+#ifdef GS
+#undef GS
+#endif
+#define GS(a) (*((short *)(a)))
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_verse.h b/source/blender/blenkernel/BKE_verse.h
new file mode 100644
index 00000000000..aba42302364
--- /dev/null
+++ b/source/blender/blenkernel/BKE_verse.h
@@ -0,0 +1,586 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributor(s): Jiri Hnidek.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/* #define WITH_VERSE */
+
+#ifndef BKE_VERSE_H
+#define BKE_VERSE_H
+
+#include "DNA_listBase.h"
+#include "BLI_dynamiclist.h"
+
+#include "verse.h"
+#include "verse_ms.h"
+
+struct VNode;
+struct VerseEdge;
+
+/*
+ * Verse Edge Hash (similar to edit edge hash)
+ */
+#define VEDHASHSIZE (512*512)
+#define VEDHASH(a, b) ((a<b ? a : b) % VEDHASHSIZE)
+
+/*
+ * verse data: 4 float value
+ */
+typedef struct quat_real32_item {
+ struct quat_real32_item *next, *prev;
+ struct VLayer *vlayer; /* pointer at VerseLayer */
+ uint32 id; /* id of item */
+ real32 value[4];
+} quat_real32_item;
+
+/*
+ * verse data: 4 uint32 values
+ */
+typedef struct quat_uint32_item {
+ struct quat_uint32_item *next, *prev;
+ struct VLayer *vlayer; /* pointer at VerseLayer */
+ uint32 id; /* id of item */
+ uint32 value[4];
+} quat_uint32_item;
+
+/*
+ * verse data: 3 float values
+ */
+typedef struct vec_real32_item {
+ struct vec_real32_item *next, *prev;
+ struct VLayer *vlayer; /* pointer at VerseLayer */
+ uint32 id; /* id of item */
+ real32 value[3];
+} vec_real32_item;
+
+/*
+ * verse data: float value (weight)
+ */
+typedef struct real32_item {
+ struct real32_item *next, *prev;
+ struct VLayer *vlayer; /* pointer at VerseLayer */
+ uint32 id; /* id of item */
+ real32 value;
+} real32_item;
+
+/*
+ * verse data: uint32 value
+ */
+typedef struct uint32_item {
+ struct uint32_item *next, *prev;
+ struct VLayer *vlayer; /* pointer at VerseLayer */
+ uint32 id; /* id of item */
+ uint32 value;
+} uint32_item;
+
+/*
+ * verse data: uint8 value
+ */
+typedef struct uint8_item {
+ struct uint8_item *next, *prev;
+ struct VLayer *vlayer; /* pointer at VerseLayer */
+ uint32 id; /* id of item */
+ uint8 value;
+} uint8_item;
+
+/*
+ * verse data: vertex
+ */
+typedef struct VerseVert {
+ struct VerseVert *next, *prev;
+ /* verse data */
+ struct VLayer *vlayer; /* pointer at VerseLayer */
+ uint32 id; /* id of vertex */
+ real32 co[3]; /* x,y,z-coordinates of vertex */
+ real32 no[3]; /* normal of vertex */
+ /* blender internals */
+ short flag; /* flags: VERT_DELETED, VERT_RECEIVED, etc. */
+ void *vertex; /* pointer at EditVert or MVert */
+ int counter; /* counter of VerseFaces using this VerseVert */
+ union {
+ unsigned int index; /* counter need during transformation to mesh */
+ struct VerseVert *vvert;
+ } tmp; /* pointer at new created verse vert, it is
+ * used during duplicating geometry node */
+ float *cos; /* modified coordinates of vertex */
+ float *nos; /* modified normal vector */
+} VerseVert;
+
+/*
+ * structture used for verse edge hash
+ */
+typedef struct HashVerseEdge {
+ struct VerseEdge *vedge;
+ struct HashVerseEdge *next;
+} HashVerseEdge;
+
+/*
+ * fake verse data: edge
+ */
+typedef struct VerseEdge {
+ struct VerseEdge *next, *prev;
+ uint32 v0, v1; /* indexes of verse vertexes */
+ int counter; /* counter of verse faces using this edge */
+ struct HashVerseEdge hash; /* hash table */
+ union {
+ unsigned int index; /* temporary index of edge */
+ } tmp;
+} VerseEdge;
+
+/*
+ * verse data: polygon
+ */
+typedef struct VerseFace {
+ struct VerseFace *next, *prev;
+ /* verse data */
+ struct VLayer *vlayer; /* pointer at VerseLayer */
+ uint32 id; /* id of face */
+ struct VerseVert *vvert0; /* pointer at 1st VerseVert */
+ struct VerseVert *vvert1; /* pointer at 2nd VerseVert */
+ struct VerseVert *vvert2; /* pointer at 3th VerseVert */
+ struct VerseVert *vvert3; /* pointer at 4th VerseVert */
+ unsigned int v0, v1, v2, v3; /* indexes of VerseVerts ... needed during receiving */
+ /* blender internals */
+ char flag; /* flags: FACE_SEND_READY, FACE_SENT, FACE_RECEIVED, FACE_CHANGED*/
+ short counter; /* counter of missed VerseVertexes */
+ void *face; /* pointer at EditFace */
+ float no[3]; /* normal vector */
+ float *nos; /* modified normal vector */
+} VerseFace;
+
+/*
+ * verse data: layer
+ */
+typedef struct VLayer {
+ struct VLayer *next, *prev;
+ /* verse data*/
+ struct VNode *vnode; /* pointer at VerseNode */
+ uint16 id; /* id of layer */
+ char *name; /* name of layer */
+ VNGLayerType type; /* type of layer (VN_G_LAYER_VERTEX_XYZ, VN_G_LAYER_POLYGON_CORNER_UINT32) */
+ uint32 def_int; /* default integer value */
+ real64 def_real; /* default float value */
+ /* blender internals */
+ char flag; /* flags: LAYER_SENT, LAYER_RECEIVED, LAYER_DELETED, LAYER_OBSOLETE */
+ short content; /* type of content (VERTEX_LAYER, POLYGON_LAYER) */
+ struct DynamicList dl; /* vertexes, polygons, etc. */
+ struct ListBase queue; /* queue of vertexes, polygons, etc. waiting for sending to verse server */
+ struct ListBase orphans; /* list of versedata (polygons, etc.), that can be added to the DynamicList
+ * due to not received VerseVerts */
+ unsigned int counter; /* counter of sent items */
+ /* client dependent methods */
+ void (*post_layer_create)(struct VLayer *vlayer);
+ void (*post_layer_destroy)(struct VLayer *vlayer);
+} VLayer;
+
+/*
+ * verse data: link
+ */
+typedef struct VLink{
+ struct VLink *next, *prev;
+ /* verse data */
+ struct VerseSession *session; /* session pointer */
+ struct VNode *source; /* object VerseNode "pointing" at some other VerseNode */
+ struct VNode *target; /* VerseNode linked with some object node */
+ unsigned int id; /* id of VerseLink */
+ unsigned int target_id; /* some unknow id */
+ char *label; /* name/label of VerseLink */
+ /* blender internals */
+ char flag; /* flags: LINK_SEND_READY */
+ /* client dependent methods */
+ void (*post_link_set)(struct VLink *vlink);
+ void (*post_link_destroy)(struct VLink *vlink);
+} VLink;
+
+/*
+ * bitmap layer
+ */
+typedef struct VBitmapLayer {
+ struct VBitmapLayer *next, *prev;
+ /* verse data */
+ struct VNode *vnode; /* pointer at Verse Node */
+ VLayerID id; /* id of layer */
+ char *name; /* name of layer */
+ VNBLayerType type; /* type of layer (bits per channel) 1, 8, 16, 32, 64 */
+ void *data; /* dynamic allocated data */
+ /* blender internals */
+ char flag;
+} VBitmapLayer;
+
+/*
+ * data of bitmap node
+ */
+typedef struct VBitmapData {
+ struct DynamicList layers; /* dynamic list with access array of bitmap layers */
+ struct ListBase queue; /* queue of layers waiting for receiving from verse server */
+ uint16 width; /* width of all verse layers */
+ uint16 height; /* height of all verse layers */
+ uint16 depth; /* depth of bitmap 1 is 2D bitmap, >1 is 3D bitmap */
+ /* blender internals */
+ uint16 t_width; /* = (width/VN_B_TILE_SIZE + 1)*VN_B_TILE_SIZE */
+ uint16 t_height; /* = (height/VN_B_TILE_SIZE + 1)*VN_B_TILE_SIZE */
+ void *image; /* pointer at image */
+ /* client dependent methods */
+ void (*post_bitmap_dimension_set)(struct VNode *vnode);
+ void (*post_bitmap_layer_create)(struct VBitmapLayer *vblayer);
+ void (*post_bitmap_layer_destroy)(struct VBitmapLayer *vblayer);
+ void (*post_bitmap_tile_set)(struct VBitmapLayer *vblayer, unsigned int xs, unsigned int ys);
+}VBitmapData;
+
+/*
+ * data of geometry node
+ */
+typedef struct VGeomData {
+ struct DynamicList layers; /* dynamic list with access array of Layers */
+ struct VLink *vlink; /* pointer at VerseLink connecting object node and geom node */
+ struct ListBase queue; /* queue of our layers waiting for receiving from verse server */
+ void *mesh; /* pointer at Mesh (object node) */
+ void *editmesh; /* pointer at EditMesh (edit mode) */
+ struct HashVerseEdge *hash; /* verse edge hash */
+ struct ListBase edges; /* list of fake verse edges */
+ /* client dependent methods */
+ void (*post_vertex_create)(struct VerseVert *vvert);
+ void (*post_vertex_set_xyz)(struct VerseVert *vvert);
+ void (*post_vertex_delete)(struct VerseVert *vvert);
+ void (*post_vertex_free_constraint)(struct VerseVert *vvert);
+ void (*post_polygon_create)(struct VerseFace *vface);
+ void (*post_polygon_set_corner)(struct VerseFace *vface);
+ void (*post_polygon_delete)(struct VerseFace *vface);
+ void (*post_polygon_free_constraint)(struct VerseFace *vface);
+ void (*post_geometry_free_constraint)(struct VNode *vnode);
+ void (*post_polygon_set_uint8)(struct VerseFace *vface);
+} VGeomData;
+
+/*
+ * data of object node
+ */
+typedef struct VObjectData {
+ struct DynamicList links; /* dynamic list with access array of links between other nodes */
+ struct ListBase queue; /* queue of links waiting for sending and receiving from verse server */
+ float pos[3]; /* position of object VerseNode */
+ float quat[4]; /* rotation of object VerseNode stored in quat */
+ float scale[3]; /* scale of object VerseNode */
+ void *object; /* pointer at object */
+ short flag; /* flag: POS_RECEIVE_READY, ROT_RECEIVE_READY. SCALE_RECEIVE_READY */
+ /* client dependent methods */
+/* void (*post_transform)(struct VNode *vnode);*/
+ void (*post_transform_pos)(struct VNode *vnode);
+ void (*post_transform_rot)(struct VNode *vnode);
+ void (*post_transform_scale)(struct VNode *vnode);
+ void (*post_object_free_constraint)(struct VNode *vnode);
+} VObjectData;
+
+/*
+ * Verse Tag
+ */
+typedef struct VTag {
+ struct VTag *next, *prev;
+ /* verse data*/
+ struct VTagGroup *vtaggroup; /* pointer at Verse Tag Group */
+ uint16 id; /* id of this tag */
+ char *name; /* name of this tag*/
+ VNTagType type; /* type: VN_TAG_BOOLEAN, VN_TAG_UINT32, VN_TAG_REAL64, VN_TAG_REAL64_VEC3,
+ VN_TAG_LINK, VN_TAG_ANIMATION, VN_TAG_BLOB */
+ VNTag *tag; /* pointer at value (enum: vboolean, vuint32, vreal64, vstring,
+ vreal64_vec3, vlink, vanimation, vblob)*/
+ /* blender internals */
+ void *value; /* pointer at blender value */
+} VTag;
+
+/*
+ * Verse Tag Group (verse tags are grouped in tag groups)
+ */
+typedef struct VTagGroup {
+ struct VTagGroup *next, *prev;
+ /* verse data*/
+ struct VNode *vnode; /* pointer at Verse Node */
+ uint16 id; /* id of this tag group */
+ char *name; /* name of this tag group */
+ /* blender internals */
+ struct DynamicList tags; /* dynamic list with access array containing tags */
+ struct ListBase queue; /* list of tags waiting for receiving from verse server */
+ /* client dependent methods */
+ void (*post_tag_change)(struct VTag *vatg);
+ void (*post_taggroup_create)(struct VTagGroup *vtaggroup);
+} VTagGroup;
+
+ /*
+ * Verse Method Group
+ */
+typedef struct VMethodGroup
+{
+ struct VMethodGroup *next, *prev;
+ uint16 group_id;
+ char name[16];
+ struct ListBase methods;
+} VMethodGroup;
+
+/*
+ * Verse Method
+ */
+typedef struct VMethod
+{
+ struct VMethod *next, *prev;
+ uint16 id;
+ char name[500];
+ uint8 param_count;
+ VNOParamType *param_type;
+ char **param_name;
+} VMethod;
+
+/*
+ * Verse Node
+ */
+typedef struct VNode {
+ struct VNode *next, *prev;
+ /* verse data*/
+ struct VerseSession *session; /* session pointer */
+ VNodeID id; /* node id */
+ VNodeID owner_id; /* owner's id of this node */
+ char *name; /* name of this node */
+ uint32 type; /* type of node (V_NT_OBJECT, V_NT_GEOMETRY, V_NT_BITMAP) */
+ /* blender internals */
+ char flag; /* flags: NODE_SENT, NODE_RECEIVED, NODE_DELTED, NODE_OBSOLETE */
+ struct DynamicList taggroups; /* dynamic list with access array of taggroups */
+ struct ListBase methodgroups; /* method groups */
+ struct ListBase queue; /* list of taggroups waiting for receiving from verse server */
+ void *data; /* generic pointer at some data (VObjectData, VGeomData, ...) */
+ int counter; /* counter of verse link pointing at this vnode (vlink->target) */
+ /* client dependent methods */
+ void (*post_node_create)(struct VNode *vnode);
+ void (*post_node_destroy)(struct VNode *vnode);
+ void (*post_node_name_set)(struct VNode *vnode);
+#ifdef VERSECHAT
+ /* verse chat */
+ int chat_flag; /* CHAT_LOGGED, CHAT_NOTLOGGED */
+#endif
+} VNode;
+
+
+/*
+ * Verse Session: verse client can be connected to several verse servers
+ * it is neccessary to store some information about each session
+ */
+typedef struct VerseSession {
+ struct VerseSession *next, *prev;
+ /* verse data */
+ VSession *vsession; /* pointer at VSeesion (verse.h) */
+ uint32 avatar; /* id of avatar */
+ char *address; /* string containg IP/domain name of verse server and number of port */
+ void *connection; /* no clue */
+ uint8 *host_id; /* no clue */
+ /* blender internals */
+ short flag; /* flag: VERSE_CONNECTING, VERSE_CONNECTED */
+ DynamicList nodes; /* list of verse nodes */
+ ListBase queue; /* list of nodes waiting for sending to verse server */
+ unsigned int counter; /* count of events, when connection wasn't accepted */
+ /* client dependent methods */
+ void (*post_connect_accept)(struct VerseSession *session);
+ void (*post_connect_terminated)(struct VerseSession *session);
+ void (*post_connect_update)(struct VerseSession *session);
+} VerseSession;
+
+typedef struct VerseServer {
+ struct VerseServer *next, *prev;
+ char *name; /* human-readable server name */
+ char *ip; /* string containing IP/domain name of verse server and number of port */
+ short flag; /* flag: VERSE_CONNECTING, VERSE_CONNECTED */
+ struct VerseSession *session; /* pointer to related session */
+} VerseServer;
+/*
+ * list of post callback functions
+ */
+typedef struct PostCallbackFunction {
+ void (*function)(void *arg);
+ void *param;
+} PostCallbackFunction;
+
+/* VerseSession->flag */
+#define VERSE_CONNECTING 1
+#define VERSE_CONNECTED 2
+#define VERSE_AUTOSUBSCRIBE 4
+
+/* max VerseSession->counter value */
+#define MAX_UNCONNECTED_EVENTS 100
+
+/* VNode flags */
+#define NODE_SENT 1
+#define NODE_RECEIVED 2
+#define NODE_DELTED 4
+#define NODE_OBSOLETE 8
+
+#ifdef VERSECHAT
+#define CHAT_NOTLOGGED 0
+#define CHAT_LOGGED 1
+#endif
+
+/* VLayer flags */
+#define LAYER_SENT 1
+#define LAYER_RECEIVED 2
+#define LAYER_DELETED 4
+#define LAYER_OBSOLETE 8
+
+/* VLink->flag */
+#define LINK_SEND_READY 1
+
+/* VObjectData->flag */
+#define POS_RECEIVE_READY 1
+#define ROT_RECEIVE_READY 2
+#define SCALE_RECEIVE_READY 4
+#define POS_SEND_READY 8
+#define ROT_SEND_READY 16
+#define SCALE_SEND_READY 32
+
+/* VLayer->content */
+#define VERTEX_LAYER 0
+#define POLYGON_LAYER 1
+
+/* VerseVert->flag */
+#define VERT_DELETED 1 /* vertex delete command was received from verse server */
+#define VERT_RECEIVED 2 /* VerseVert was received from verse server (is not in sending queue) */
+#define VERT_LOCKED 4 /* VerseVert is ready to send local position to verse server */
+#define VERT_POS_OBSOLETE 8 /* position of vertex was changed during sending to verse server */
+#define VERT_OBSOLETE 16 /* vertex delete command was sent to verse server; it means, that
+ * no information related to this vertex shoudln't be sent to verse
+ * until verse vertex is completely deleted ... then this vertex id
+ * can be reused again for new vertex */
+
+/* VerseFace->flag */
+#define FACE_SEND_READY 1 /* VerseFace is ready for sending to verse server */
+#define FACE_RECEIVED 2 /* VerseFace was received from verse server */
+#define FACE_SENT 4 /* VerseFace was sent to verse server and we expect receiving from verse server */
+#define FACE_DELETED 8 /* delete command was sent to verse server */
+#define FACE_CHANGED 16 /* VerseFace was only changed not created */
+#define FACE_OBSOLETE 32 /* VerseFace was changed during sending to verse server */
+
+/* Queue type */
+#define VERSE_NODE 1
+#define VERSE_LINK 2
+#define VERSE_LAYER 3
+#define VERSE_VERT 4
+#define VERSE_FACE 5
+
+#define VERSE_TAG 6
+#define VERSE_TAG_GROUP 7
+
+#define VERSE_VERT_UINT32 8
+#define VERSE_VERT_REAL32 9
+#define VERSE_VERT_VEC_REAL32 10
+
+#define VERSE_FACE_UINT8 11
+#define VERSE_FACE_UINT32 12
+#define VERSE_FACE_REAL32 13
+#define VERSE_FACE_QUAT_UINT32 14
+#define VERSE_FACE_QUAT_REAL32 15
+
+/* Verse Bitmap Layer flags */
+#define VBLAYER_SUBSCRIBED 1
+
+/* function prototypes */
+
+/* functions from verse_session.c */
+void set_verse_session_callbacks(void);
+struct VerseSession *versesession_from_vsession(VSession *vsession);
+struct VerseSession *current_verse_session(void);
+struct VerseSession *create_verse_session(const char *name, const char *pass, const char *address, uint8 *expected_key);
+void free_verse_session(struct VerseSession *session);
+void b_verse_update(void);
+void b_verse_ms_get(void);
+void b_verse_connect(char *address);
+void end_verse_session(struct VerseSession *session);
+void end_all_verse_sessions(void);
+
+/* functions from verse_node.c */
+void send_verse_tag(struct VTag *vtag);
+void send_verse_taggroup(struct VTagGroup *vtaggroup);
+void send_verse_node(struct VNode *vnode);
+void free_verse_node_data(struct VNode *vnode);
+void free_verse_node(struct VNode *vnode);
+struct VNode* lookup_vnode(VerseSession *session, VNodeID node_id);
+struct VNode* create_verse_node(VerseSession *session, VNodeID node_id, uint8 type, VNodeID owner_id);
+void set_node_callbacks(void);
+
+/* functions from verse_object_node.c */
+struct VLink *find_unsent_parent_vlink(struct VerseSession *session, struct VNode *vnode);
+struct VLink *find_unsent_child_vlink(struct VerseSession *session, struct VNode *vnode);
+struct VLink *create_verse_link(VerseSession *session, struct VNode *source, struct VNode *target, uint16 link_id, uint32 target_id, const char *label);
+void send_verse_object_position(struct VNode *vnode);
+void send_verse_object_rotation(struct VNode *vnode);
+void send_verse_object_scale(struct VNode *vnode);
+void send_verse_link(struct VLink *vlink);
+
+void free_object_data(struct VNode *vnode);
+void set_object_callbacks(void);
+struct VObjectData *create_object_data(void);
+
+
+/* functions from verse_method.c */
+void free_verse_methodgroup(VMethodGroup *vmg);
+#ifdef VERSECHAT
+void send_say(const char *chan, const char *utter);
+void send_login(struct VNode *vnode);
+void send_logout(struct VNode *vnode);
+void send_join(struct VNode *vnode, const char *chan);
+void send_leave(struct VNode *vnode, const char *chan);
+#endif
+void set_method_callbacks(void);
+
+/* functions from verse_geometry_node.c */
+struct VerseFace* create_verse_face(struct VLayer *vlayer, uint32 polygon_id, uint32 v0, uint32 v1, uint32 v2, uint32 v3);
+struct VerseVert* create_verse_vertex(struct VLayer *vlayer, uint32 vertex_id, real32 x, real32 y, real32 z);
+struct VLayer *create_verse_layer(struct VNode *vnode, VLayerID layer_id, const char *name, VNGLayerType type, uint32 def_integer, real64 def_real);
+struct VGeomData *create_geometry_data(void);
+
+void send_verse_layer(struct VLayer *vlayer);
+
+void send_verse_face_corner_quat_real32(struct quat_real32_item *item, short type);
+void send_verse_face_corner_quat_uint32(struct quat_uint32_item *item, short type);
+void send_verse_face_real32(struct real32_item *item, short type);
+void send_verse_face_uint32(struct uint32_item *item, short type);
+void send_verse_face_uint8(struct uint8_item *item, short type);
+
+void send_verse_vert_vec_real32(struct vec_real32_item *item, short type);
+void send_verse_vert_real32(struct real32_item *item, short type);
+void send_verse_vert_uint32(struct uint32_item *item, short type);
+
+void send_verse_vertex_delete(struct VerseVert *vvert);
+void send_verse_vertex(struct VerseVert *vvert);
+void send_verse_face_delete(struct VerseFace *vface);
+
+void destroy_geometry(struct VNode *vnode);
+
+struct VLayer* find_verse_layer_type(struct VGeomData *geom, short content);
+void add_item_to_send_queue(struct ListBase *lb, void *item, short type);
+void free_geom_data(struct VNode *vnode);
+void set_geometry_callbacks(void);
+
+/* functions prototypes from verse_bitmap.c */
+void set_bitmap_callbacks(void);
+void free_bitmap_layer_data(struct VBitmapLayer *vblayer);
+struct VBitmapLayer *create_bitmap_layer(struct VNode *vnode, VLayerID layer_id, const char *name, VNBLayerType type);
+void free_bitmap_node_data(struct VNode *vnode);
+struct VBitmapData *create_bitmap_data(void);
+
+#endif
diff --git a/source/blender/blenkernel/BKE_world.h b/source/blender/blenkernel/BKE_world.h
new file mode 100644
index 00000000000..b51eaff420c
--- /dev/null
+++ b/source/blender/blenkernel/BKE_world.h
@@ -0,0 +1,45 @@
+/**
+ * blenlib/BKE_world.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BKE_WORLD_H
+#define BKE_WORLD_H
+
+struct World;
+
+void free_world(struct World *sc);
+struct World *add_world(char *name);
+struct World *copy_world(struct World *wrld);
+void make_local_world(struct World *wrld);
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_writeavi.h b/source/blender/blenkernel/BKE_writeavi.h
new file mode 100644
index 00000000000..6faa5f44878
--- /dev/null
+++ b/source/blender/blenkernel/BKE_writeavi.h
@@ -0,0 +1,62 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BKE_WRITEAVI_H
+#define BKE_WRITEAVI_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* generic blender movie support, could move to own module */
+
+struct RenderData;
+void start_avi(struct RenderData *rd, int rectx, int recty);
+void end_avi(void);
+void append_avi(int frame, int *pixels, int rectx, int recty);
+void makeavistring (struct RenderData *rd, char *string);
+
+typedef struct bMovieHandle {
+ void (*start_movie)(struct RenderData *rd, int rectx, int recty);
+ void (*append_movie)(int frame, int *pixels, int rectx, int recty);
+ void (*end_movie)(void);
+ int (*get_next_frame)(void); /* can be null */
+} bMovieHandle;
+
+bMovieHandle *BKE_get_movie_handle(int imtype);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_writeffmpeg.h b/source/blender/blenkernel/BKE_writeffmpeg.h
new file mode 100644
index 00000000000..13084e925e0
--- /dev/null
+++ b/source/blender/blenkernel/BKE_writeffmpeg.h
@@ -0,0 +1,76 @@
+/**
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BKE_WRITEFFMPEG_H
+#define BKE_WRITEFFMPEG_H
+
+#ifdef WITH_FFMPEG
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define FFMPEG_MPEG1 0
+#define FFMPEG_MPEG2 1
+#define FFMPEG_MPEG4 2
+#define FFMPEG_AVI 3
+#define FFMPEG_MOV 4
+#define FFMPEG_DV 5
+#define FFMPEG_H264 6
+#define FFMPEG_XVID 7
+
+#define FFMPEG_CODEC_MPEG1 0
+#define FFMPEG_CODEC_MPEG2 1
+#define FFMPEG_CODEC_MPEG4 2
+#define FFMPEG_CODEC_HUFFYUV 3
+#define FFMPEG_CODEC_DV 4
+#define FFMPEG_CODEC_H264 5
+#define FFMPEG_CODEC_XVID 6
+
+#define FFMPEG_PRESET_NONE 0
+#define FFMPEG_PRESET_DVD 1
+#define FFMPEG_PRESET_SVCD 2
+#define FFMPEG_PRESET_VCD 3
+#define FFMPEG_PRESET_DV 4
+
+struct RenderData;
+
+extern void start_ffmpeg(struct RenderData *rd, int rectx, int recty);
+extern void end_ffmpeg(void);
+extern void append_ffmpeg(int frame, int *pixels, int rectx, int recty);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+#endif
+
diff --git a/source/blender/blenkernel/BKE_writeframeserver.h b/source/blender/blenkernel/BKE_writeframeserver.h
new file mode 100644
index 00000000000..d8414e51f43
--- /dev/null
+++ b/source/blender/blenkernel/BKE_writeframeserver.h
@@ -0,0 +1,50 @@
+/**
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BKE_WRITEFRAMESERVER_H
+#define BKE_WRITEFRAMESERVER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct RenderData;
+
+extern void start_frameserver(struct RenderData *rd, int rectx, int recty);
+extern void end_frameserver(void);
+extern void append_frameserver(int frame, int *pixels, int rectx, int recty);
+extern int frameserver_loop();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
new file mode 100644
index 00000000000..c0776583a04
--- /dev/null
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -0,0 +1,77 @@
+# $Id$
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2006, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Jacques Beaurain.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+
+FILE(GLOB SRC intern/*.c)
+
+SET(INC
+ . ../../../intern/guardedalloc ../include ../blenlib ../makesdna
+ ../python ../render/extern/include ../../../intern/decimation/extern
+ ../imbuf ../avi ../../../intern/elbeem/extern
+ ../../../intern/iksolver/extern ../blenloader ../quicktime
+ ../../../intern/bmfont
+ ../nodes
+ ${SDL_INC}
+ ${ZLIB_INC}
+)
+
+IF(WITH_VERSE)
+ ADD_DEFINITIONS(-DWITH_VERSE)
+ SET(INC ${INC} ${VERSE_INC})
+ENDIF(WITH_VERSE)
+
+IF(WITH_OPENEXR)
+ ADD_DEFINITIONS(-DWITH_OPENEXR)
+ENDIF(WITH_OPENEXR)
+
+IF(WITH_QUICKTIME)
+ SET(INC ${INC} ${QUICKTIME_INC})
+ ADD_DEFINITIONS(-DWITH_QUICKTIME)
+ENDIF(WITH_QUICKTIME)
+
+IF(WITH_FFMPEG)
+ SET(INC ${INC} ${FFMPEG_INC})
+ ADD_DEFINITIONS(-DWITH_FFMPEG)
+ENDIF(WITH_FFMPEG)
+
+IF(WITH_PLAYER)
+ SUBDIRS(bad_level_call_stubs)
+ENDIF(WITH_PLAYER)
+
+ADD_DEFINITIONS(-DWITH_CCGSUBSURF)
+
+BLENDERLIB(bf_blenkernel "${SRC}" "${INC}")
+
+IF(WITH_VERSE)
+ ADD_DEPENDENCIES(bf_blenkernel mkprot verse)
+ENDIF(WITH_VERSE)
+
+IF(WITH_INTERNATIONAL)
+ ADD_DEFINITIONS(-DWITH_FREETYPE2)
+ENDIF(WITH_INTERNATIONAL)
+
diff --git a/source/blender/blenkernel/Makefile b/source/blender/blenkernel/Makefile
new file mode 100644
index 00000000000..239941ec59b
--- /dev/null
+++ b/source/blender/blenkernel/Makefile
@@ -0,0 +1,37 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+# Bounces make to subdirectories.
+
+SOURCEDIR = source/blender/blenkernel
+DIRS = intern bad_level_call_stubs
+
+include nan_subdirs.mk
diff --git a/source/blender/blenkernel/SConscript b/source/blender/blenkernel/SConscript
new file mode 100644
index 00000000000..9ecc76046c7
--- /dev/null
+++ b/source/blender/blenkernel/SConscript
@@ -0,0 +1,47 @@
+#!/usr/bin/python
+Import ('env')
+
+sources = env.Glob('intern/*.c')
+
+incs = '. #/intern/guardedalloc ../include ../blenlib ../makesdna'
+incs += ' ../python ../render/extern/include #/intern/decimation/extern'
+incs += ' ../imbuf ../avi #/intern/elbeem/extern ../nodes'
+incs += ' #/intern/iksolver/extern ../blenloader ../quicktime'
+incs += ' #/intern/bmfont'
+
+incs += ' ' + env['BF_OPENGL_INC']
+incs += ' ' + env['BF_ZLIB_INC']
+incs += ' ' + env['BF_SDL_INC']
+
+defs = ''
+
+if env['WITH_BF_INTERNATIONAL']:
+ defs += 'WITH_FREETYPE2'
+
+if env['WITH_BF_VERSE']:
+ defs += ' WITH_VERSE'
+ incs += ' ' + env['BF_VERSE_INCLUDE']
+
+if env['WITH_BF_VERSE']:
+ defs += ' WITH_VERSE'
+
+if env['WITH_BF_OPENEXR'] == 1:
+ defs += ' WITH_OPENEXR'
+
+if env['WITH_BF_DDS'] == 1:
+ defs += ' WITH_DDS'
+
+if env['WITH_BF_FFMPEG'] == 1:
+ defs += ' WITH_FFMPEG'
+ incs += ' ' + env['BF_FFMPEG_INC']
+
+if env['WITH_BF_QUICKTIME'] == 1:
+ defs += ' WITH_QUICKTIME'
+ incs += ' ' + env['BF_QUICKTIME_INC']
+
+defs += ' WITH_CCGSUBSURF'
+
+if env['WITH_BF_PLAYER']:
+ SConscript(['bad_level_call_stubs/SConscript'])
+
+env.BlenderLib ( libname = 'bf_blenkernel', sources = sources, includes = Split(incs), defines = Split(defs), libtype=['core','player'], priority = [65, 20] )
diff --git a/source/blender/blenkernel/bad_level_call_stubs/CMakeLists.txt b/source/blender/blenkernel/bad_level_call_stubs/CMakeLists.txt
new file mode 100644
index 00000000000..67463f901c6
--- /dev/null
+++ b/source/blender/blenkernel/bad_level_call_stubs/CMakeLists.txt
@@ -0,0 +1,46 @@
+# $Id$
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2006, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Jacques Beaurain.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+
+FILE(GLOB SRC stubs.c)
+
+SET(INC
+ .
+ ..
+ ../../render/extern/include
+ ../../../intern/iksolver/extern
+ ../../blenlib
+ ../../include
+ ../../makesdna
+)
+
+IF(WITH_INTERNATIONAL)
+ ADD_DEFINITIONS(-DWITH_FREETYPE2)
+ENDIF(WITH_INTERNATIONAL)
+
+BLENDERLIB_NOLIST(blenkernel_blc "${SRC}" "${INC}")
diff --git a/source/blender/blenkernel/bad_level_call_stubs/Makefile b/source/blender/blenkernel/bad_level_call_stubs/Makefile
new file mode 100644
index 00000000000..1d4db1037ea
--- /dev/null
+++ b/source/blender/blenkernel/bad_level_call_stubs/Makefile
@@ -0,0 +1,51 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+#
+
+LIBNAME = blenkernel_blc
+DIR = $(OCGDIR)/blender/blenkernel/$(LIBNAME)
+
+include nan_compile.mk
+
+CFLAGS += $(LEVEL_2_C_WARNINGS)
+CFLAGS += $(FIX_STUBS_WARNINGS)
+
+CPPFLAGS += $(OGL_CPPFLAGS)
+CPPFLAGS += -I../../makesdna
+CPPFLAGS += -I../../include
+CPPFLAGS += -I../../blenlib
+CPPFLAGS += -I../../render/extern/include
+CPPFLAGS += -I$(NAN_IKSOLVER)/include
+
+# path to our own external headerfiles
+CPPFLAGS += -I..
+
diff --git a/source/blender/blenkernel/bad_level_call_stubs/SConscript b/source/blender/blenkernel/bad_level_call_stubs/SConscript
new file mode 100644
index 00000000000..955a989c9f9
--- /dev/null
+++ b/source/blender/blenkernel/bad_level_call_stubs/SConscript
@@ -0,0 +1,14 @@
+#!/usr/bin/python
+Import ('env')
+
+sources = 'stubs.c'
+
+incs = '. .. ../../render/extern/include'
+incs += ' #/intern/iksolver/extern ../../blenlib'
+incs += ' ../../include ../../makesdna'
+
+defs = ''
+if env['WITH_BF_INTERNATIONAL']:
+ defs += 'WITH_FREETYPE2'
+
+env.BlenderLib ('blenkernel_blc', sources = Split(sources), includes=Split(incs), defines=Split(defs), libtype='player',priority=225 )
diff --git a/source/blender/blenkernel/bad_level_call_stubs/stubs.c b/source/blender/blenkernel/bad_level_call_stubs/stubs.c
new file mode 100644
index 00000000000..63bc23a71bf
--- /dev/null
+++ b/source/blender/blenkernel/bad_level_call_stubs/stubs.c
@@ -0,0 +1,338 @@
+
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * BKE_bad_level_calls function stubs
+ */
+
+#include <stdlib.h>
+
+#include "BKE_bad_level_calls.h"
+#include "BLI_blenlib.h"
+#include "BPI_script.h"
+#include "DNA_texture_types.h"
+#include "DNA_material_types.h"
+#include "DNA_node_types.h"
+#include "DNA_scene_types.h"
+
+#include "RE_render_ext.h"
+#include "RE_shader_ext.h"
+#include "RE_pipeline.h"
+
+int winqueue_break= 0;
+
+char bprogname[1];
+
+struct IpoCurve;
+struct FluidsimSettings;
+struct Render;
+struct RenderResult;
+struct Object;
+struct bPythonConstraint;
+struct bConstraintOb;
+struct bConstraintTarget;
+struct ListBase;
+
+char *getIpoCurveName( struct IpoCurve * icu );
+void insert_vert_icu(struct IpoCurve *icu, float x, float y, short fast);
+struct IpoCurve *verify_ipocurve(struct ID *id, short a, char *b, char *d, int e);
+void elbeemDebugOut(char *msg);
+void fluidsimSettingsFree(struct FluidsimSettings* sb);
+void fluidsimSettingsCopy(struct FluidsimSettings* sb);
+
+
+/* readfile.c */
+ /* struct SpaceButs; */
+void set_rects_butspace(struct SpaceButs *buts){}
+ /* struct SpaceImaSel; */
+void check_imasel_copy(struct SpaceImaSel *simasel){}
+ /* struct ScrArea; */
+void unlink_screen(struct bScreen *sc){}
+void freeAllRad(void){}
+void free_editText(void){}
+void free_editArmature(void){}
+void free_vertexpaint(void){}
+
+char *getIpoCurveName( struct IpoCurve * icu )
+{
+ return 0;
+}
+
+void insert_vert_icu(struct IpoCurve *icu, float x, float y, short fast)
+{
+}
+
+
+struct IpoCurve *verify_ipocurve(struct ID *id, short a, char *b, char *d, int e)
+{
+ return 0;
+}
+
+
+void setscreen(struct bScreen *sc){}
+void force_draw_all(int header){}
+ /* otherwise the WHILE_SEQ doesn't work */
+ /* struct Sequence; */
+
+/* MAART: added "seqar = 0; totseq = 0" because the loader will crash without it. */
+void build_seqar(struct ListBase *seqbase, struct Sequence ***seqar, int *totseq)
+{
+ *seqar = 0;
+ *totseq = 0;
+}
+
+/* blender.c */
+void mainqenter (unsigned short event, short val){}
+
+void BPY_do_pyscript(ID *id, short int event){}
+void BPY_clear_script(Script *script){}
+void BPY_free_compiled_text(struct Text *text){}
+void BPY_pydriver_update(void){}
+float BPY_pydriver_eval(struct IpoDriver *driver)
+{
+ return 0;
+}
+/* depsgraph.c: */
+struct Object **BPY_pydriver_get_objects(struct IpoDriver *driver)
+{
+ return 0;
+}
+int BPY_button_eval(char *expr, double *value)
+{
+ return 0;
+}
+
+/* PyConstraints - BPY_interface.c */
+void BPY_pyconstraint_eval(struct bPythonConstraint *con, struct bConstraintOb *cob, struct ListBase *targets)
+{
+}
+void BPY_pyconstraint_target(struct bPythonConstraint *con, struct bConstraintTarget *ct)
+{
+}
+
+
+/* writefile.c */
+ /* struct Oops; */
+void free_oops(struct Oops *oops){}
+void exit_posemode(int freedata){}
+void error(char *str, ...){}
+
+/* anim.c */
+ListBase editNurb;
+
+void waitcursor(int val){}
+void allqueue(unsigned short event, short val){}
+#define REDRAWVIEW3D 0x4010
+Material defmaterial;
+
+/* exotic.c */
+void load_editMesh(void){}
+void make_editMesh(void){}
+void free_editMesh(struct EditMesh *em){}
+void docenter_new(void){}
+int saveover(char *str){ return 0;}
+
+/* image.c */
+#include "DNA_image_types.h"
+void free_realtime_image(Image *ima){} // has to become a callback, opengl stuff
+
+/* ipo.c */
+void copy_view3d_lock(short val){} // was a hack, to make scene layer ipo's possible
+
+/* library.c */
+void allspace(unsigned short event, short val){}
+#define OOPS_TEST 2
+
+/* mball.c */
+ListBase editelems;
+
+/* object.c */
+void BPY_free_scriptlink(ScriptLink *slink){}
+void BPY_copy_scriptlink(ScriptLink *scriptlink){}
+float *give_cursor(void){ return 0;} // become a callback or argument
+
+
+/* packedFile.c */
+short pupmenu(char *instr){ return 0;} // will be general callback
+
+/* sca.c */
+#define LEFTMOUSE 0x001 // because of mouse sensor
+
+/* scene.c */
+#include "DNA_sequence_types.h"
+void free_editing(struct Editing *ed){} // scenes and sequences problem...
+void BPY_do_all_scripts (short int event){}
+
+/* IKsolver stubs */
+#include "IK_solver.h"
+
+IK_Segment *IK_CreateSegment(int flag) { return 0; }
+void IK_FreeSegment(IK_Segment *seg) {}
+
+void IK_SetParent(IK_Segment *seg, IK_Segment *parent) {}
+void IK_SetTransform(IK_Segment *seg, float start[3], float rest_basis[][3], float basis[][3], float length) {}
+void IK_GetBasisChange(IK_Segment *seg, float basis_change[][3]) {}
+void IK_GetTranslationChange(IK_Segment *seg, float *translation_change) {};
+void IK_SetLimit(IK_Segment *seg, IK_SegmentAxis axis, float lower, float upper) {};
+void IK_SetStiffness(IK_Segment *seg, IK_SegmentAxis axis, float stiffness) {};
+
+IK_Solver *IK_CreateSolver(IK_Segment *root) { return 0; }
+void IK_FreeSolver(IK_Solver *solver) {};
+
+void IK_SolverAddGoal(IK_Solver *solver, IK_Segment *tip, float goal[3], float weight) {}
+void IK_SolverAddGoalOrientation(IK_Solver *solver, IK_Segment *tip, float goal[][3], float weight) {}
+void IK_SolverSetPoleVectorConstraint(IK_Solver *solver, IK_Segment *tip, float goal[3], float polegoal[3], float poleangle, int getangle) {}
+float IK_SolverGetPoleAngle(IK_Solver *solver) {}
+
+int IK_Solve(IK_Solver *solver, float tolerance, int max_iterations) { return 0; }
+
+/* exotic.c */
+int BPY_call_importloader(char *name)
+{
+ return 0;
+}
+
+
+/* texture.c */
+#define FLO 128
+#define INT 96
+
+
+char texstr[20][12]; /* buttons.c */
+
+/* editsca.c */
+void make_unique_prop_names(char *str) {}
+
+/* DerivedMesh.c */
+void bglBegin(int mode) {}
+void bglVertex3fv(float *vec) {}
+void bglVertex3f(float x, float y, float z) {}
+void bglEnd(void) {}
+
+/* booleanops.c */
+struct DerivedMesh *NewBooleanDerivedMesh(struct Object *ob, struct Object *ob_select, int int_op_type) { return 0; }
+
+// bobj read/write debug messages
+void elbeemDebugOut(char *msg) {}
+void fluidsimSettingsFree(struct FluidsimSettings* sb) {}
+void fluidsimSettingsCopy(struct FluidsimSettings* sb) {}
+
+/*new render funcs */
+int externtex(struct MTex *mtex, float *vec, float *tin, float *tr, float *tg, float *tb, float *ta) { return 0; }
+
+void RE_FreeRenderResult(struct RenderResult *rr) {}
+void RE_GetResultImage(struct Render *re, struct RenderResult *rr) {}
+struct RenderResult *RE_MultilayerConvert(void *exrhandle, int rectx, int recty){return NULL;}
+struct Render *RE_GetRender(const char *name) {return (struct Render *)NULL;}
+struct RenderResult *RE_GetResult(Render *re) {return (struct RenderResult *)NULL;}
+float *RE_RenderLayerGetPass(RenderLayer *rl, int passtype) {return NULL;}
+float RE_filter_value(int type, float x) {return 0.0f;}
+struct RenderLayer *RE_GetRenderLayer(RenderResult *rr, const char *name) {return (struct RenderLayer *)NULL;}
+void RE_Database_Free (struct Render *re) {}
+void RE_FreeRender(Render *re) {}
+void RE_shade_external(Render *re, ShadeInput *shi, ShadeResult *shr) {}
+void RE_DataBase_GetView(Render *re, float mat[][4]) {}
+struct Render *RE_NewRender(const char *name) {return (struct Render *)NULL;}
+void RE_Database_Baking(struct Render *re, struct Scene *scene, int make_faces) {};
+
+
+/* node_composite.c */
+void RE_zbuf_accumulate_vecblur(struct NodeBlurData *nd, int xsize, int ysize, float *newrect, float *imgrect, float *vecbufrect, float *zbufrect) {}
+
+int multitex_ext(Tex *tex, float *texvec, float *dxt, float *dyt, int osatex, TexResult *texres)
+{
+ return 1969;
+}
+
+/* verse */
+
+void post_vertex_create(struct VerseVert *vvert) {}
+void post_vertex_set_xyz(struct VerseVert *vvert) {}
+void post_vertex_delete(struct VerseVert *vvert) {}
+void post_vertex_free_constraint(struct VerseVert *vvert) {}
+void post_polygon_create(struct VerseFace *vface) {}
+void post_polygon_set_corner(struct VerseFace *vface) {}
+void post_polygon_delete(struct VerseFace *vface) {}
+void post_polygon_free_constraint(struct VerseFace *vface) {}
+void post_polygon_set_uint8(struct VerseFace *vface) {}
+void post_node_create(struct VNode *vnode) {}
+void post_node_destroy(struct VNode *vnode) {}
+void post_node_name_set(struct VNode *vnode) {}
+void post_tag_change(struct VTag *vtag) {}
+void post_taggroup_create(struct VTagGroup *vtaggroup) {}
+char *verse_client_name(void) { return NULL; }
+void post_transform(struct VNode *vnode) {}
+void post_transform_pos(struct VNode *vnode) {}
+void post_transform_rot(struct VNode *vnode) {}
+void post_transform_scale(struct VNode *vnode) {}
+void post_object_free_constraint(struct VNode *vnode) {}
+void post_link_set(struct VLink *vlink) {}
+void post_link_destroy(struct VLink *vlink) {}
+void post_connect_accept(struct VerseSession *session) {}
+void post_connect_terminated(struct VerseSession *session) {}
+void post_connect_update(struct VerseSession *session) {}
+void add_screenhandler(struct bScreen *sc, short eventcode, short val) {}
+void post_bitmap_dimension_set(struct VNode *vnode) {}
+void post_bitmap_layer_create(struct VBitmapLayer *vblayer) {}
+void post_bitmap_layer_destroy(struct VBitmapLayer *vblayer) {}
+void post_bitmap_tile_set(struct VBitmapLayer *vblayer, unsigned int xs, unsigned int ys) {}
+void create_meshdata_from_geom_node(struct Mesh *me, struct VNode *vnode) {}
+void post_geometry_free_constraint(struct VNode *vnode) {}
+void post_layer_create(struct VLayer *vlayer) {}
+void post_layer_destroy(struct VLayer *vlayer) {}
+void post_server_add(void) {}
+ /* Multires/sculpt stubs */
+struct MultiresLevel *multires_level_n(struct Multires *mr, int n) {return NULL;}
+void multires_free(struct Multires *mr) {}
+void multires_set_level(struct Object *ob, struct Mesh *me, const int render) {}
+void multires_update_levels(struct Mesh *me, const int render) {}
+void multires_calc_level_maps(struct MultiresLevel *lvl) {}
+struct Multires *multires_copy(struct Multires *orig) {return NULL;}
+void sculptmode_init(struct Scene *sce) {}
+void sculptmode_free_all(struct Scene *sce) {}
+
+/* zbuf.c stub */
+void antialias_tagbuf(int xsize, int ysize, char *rectmove) {}
+
+/* imagetexture.c stub */
+void ibuf_sample(struct ImBuf *ibuf, float fx, float fy, float dx, float dy, float *result) {}
+
+void update_for_newframe() {}
+
+struct FileList;
+void BIF_filelist_freelib(struct FileList* filelist) {};
+
+/* edittime.c stub */
+TimeMarker *get_frame_marker(int frame){return 0;};
+
+/* modifier.c stub */
+void harmonic_coordinates_bind(struct MeshDeformModifierData *mmd,
+ float (*vertexcos)[3], int totvert, float cagemat[][4]) {}
+
diff --git a/source/blender/blenkernel/depsgraph_private.h b/source/blender/blenkernel/depsgraph_private.h
new file mode 100644
index 00000000000..15c06b8ae79
--- /dev/null
+++ b/source/blender/blenkernel/depsgraph_private.h
@@ -0,0 +1,133 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef DEPSGRAPH_PRIVATE
+#define DEPSGRAPH_PRIVATE
+
+#include "BKE_depsgraph.h"
+#include "DNA_constraint_types.h"
+#include "BKE_constraint.h"
+
+
+#define DEPSX 5.0f
+#define DEPSY 1.8f
+
+#define DAGQUEUEALLOC 50
+
+enum {
+ DAG_WHITE = 0,
+ DAG_GRAY = 1,
+ DAG_BLACK = 2
+};
+
+
+
+typedef struct DagAdjList
+{
+ struct DagNode *node;
+ short type;
+ int count; // number of identical arcs
+ unsigned int lay; // for flushing redraw/rebuild events
+ struct DagAdjList *next;
+} DagAdjList;
+
+
+typedef struct DagNode
+{
+ int color;
+ short type;
+ float x, y, k;
+ void * ob;
+ void * first_ancestor;
+ int ancestor_count;
+ int lay; // accumulated layers of its relations + itself
+ int lasttime; // if lasttime != DagForest->time, this node was not evaluated yet for flushing
+ int BFS_dist; // BFS distance
+ int DFS_dist; // DFS distance
+ int DFS_dvtm; // DFS discovery time
+ int DFS_fntm; // DFS Finishing time
+ struct DagAdjList *child;
+ struct DagAdjList *parent;
+ struct DagNode *next;
+} DagNode;
+
+typedef struct DagNodeQueueElem {
+ struct DagNode *node;
+ struct DagNodeQueueElem *next;
+} DagNodeQueueElem;
+
+typedef struct DagNodeQueue
+{
+ DagNodeQueueElem *first;
+ DagNodeQueueElem *last;
+ int count;
+ int maxlevel;
+ struct DagNodeQueue *freenodes;
+} DagNodeQueue;
+
+// forest as we may have more than one DAG unnconected
+typedef struct DagForest
+{
+ ListBase DagNode;
+ int numNodes;
+ int is_acyclic;
+ int time; // for flushing/tagging, compare with node->lasttime
+} DagForest;
+
+
+// queue operations
+DagNodeQueue * queue_create (int slots);
+void queue_raz(DagNodeQueue *queue);
+void push_queue(DagNodeQueue *queue, DagNode *node);
+void push_stack(DagNodeQueue *queue, DagNode *node);
+DagNode * pop_queue(DagNodeQueue *queue);
+DagNode * get_top_node_queue(DagNodeQueue *queue);
+
+// Dag management
+DagForest *getMainDag(void);
+void setMainDag(DagForest *dag);
+DagForest * dag_init(void);
+DagNode * dag_find_node (DagForest *forest,void * fob);
+DagNode * dag_add_node (DagForest *forest,void * fob);
+DagNode * dag_get_node (DagForest *forest,void * fob);
+DagNode * dag_get_sub_node (DagForest *forest,void * fob);
+void dag_add_relation(DagForest *forest, DagNode *fob1, DagNode *fob2, short rel);
+
+void graph_bfs(void);
+
+DagNodeQueue * graph_dfs(void);
+
+void set_node_xy(DagNode *node, float x, float y);
+void graph_print_queue(DagNodeQueue *nqueue);
+void graph_print_queue_dist(DagNodeQueue *nqueue);
+void graph_print_adj_list(void);
+
+int build_deps(short mask);
+
+#endif
diff --git a/source/blender/blenkernel/intern/CCGSubSurf.c b/source/blender/blenkernel/intern/CCGSubSurf.c
new file mode 100644
index 00000000000..4e00e29029c
--- /dev/null
+++ b/source/blender/blenkernel/intern/CCGSubSurf.c
@@ -0,0 +1,2294 @@
+/* $Id$ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <float.h>
+
+#include "CCGSubSurf.h"
+
+/***/
+
+typedef unsigned char byte;
+
+/***/
+
+static int kHashSizes[] = {
+ 1, 3, 5, 11, 17, 37, 67, 131, 257, 521, 1031, 2053, 4099, 8209,
+ 16411, 32771, 65537, 131101, 262147, 524309, 1048583, 2097169,
+ 4194319, 8388617, 16777259, 33554467, 67108879, 134217757, 268435459
+};
+
+typedef struct _EHEntry EHEntry;
+struct _EHEntry {
+ EHEntry *next;
+ void *key;
+};
+typedef struct _EHash {
+ EHEntry **buckets;
+ int numEntries, curSize, curSizeIdx;
+
+ CCGAllocatorIFC allocatorIFC;
+ CCGAllocatorHDL allocator;
+} EHash;
+
+#define EHASH_alloc(eh, nb) ((eh)->allocatorIFC.alloc((eh)->allocator, nb))
+#define EHASH_free(eh, ptr) ((eh)->allocatorIFC.free((eh)->allocator, ptr))
+
+#define EHASH_hash(eh, item) (((unsigned long) (item))%((unsigned int) (eh)->curSize))
+
+static EHash *_ehash_new(int estimatedNumEntries, CCGAllocatorIFC *allocatorIFC, CCGAllocatorHDL allocator) {
+ EHash *eh = allocatorIFC->alloc(allocator, sizeof(*eh));
+ eh->allocatorIFC = *allocatorIFC;
+ eh->allocator = allocator;
+ eh->numEntries = 0;
+ eh->curSizeIdx = 0;
+ while (kHashSizes[eh->curSizeIdx]<estimatedNumEntries)
+ eh->curSizeIdx++;
+ eh->curSize = kHashSizes[eh->curSizeIdx];
+ eh->buckets = EHASH_alloc(eh, eh->curSize*sizeof(*eh->buckets));
+ memset(eh->buckets, 0, eh->curSize*sizeof(*eh->buckets));
+
+ return eh;
+}
+typedef void (*EHEntryFreeFP)(EHEntry *, void *);
+static void _ehash_free(EHash *eh, EHEntryFreeFP freeEntry, void *userData) {
+ int numBuckets = eh->curSize;
+
+ while (numBuckets--) {
+ EHEntry *entry = eh->buckets[numBuckets];
+
+ while (entry) {
+ EHEntry *next = entry->next;
+
+ freeEntry(entry, userData);
+
+ entry = next;
+ }
+ }
+
+ EHASH_free(eh, eh->buckets);
+ EHASH_free(eh, eh);
+}
+
+static void _ehash_insert(EHash *eh, EHEntry *entry) {
+ int numBuckets = eh->curSize;
+ int hash = EHASH_hash(eh, entry->key);
+ entry->next = eh->buckets[hash];
+ eh->buckets[hash] = entry;
+ eh->numEntries++;
+
+ if (eh->numEntries > (numBuckets*3)) {
+ EHEntry **oldBuckets = eh->buckets;
+ eh->curSize = kHashSizes[++eh->curSizeIdx];
+
+ eh->buckets = EHASH_alloc(eh, eh->curSize*sizeof(*eh->buckets));
+ memset(eh->buckets, 0, eh->curSize*sizeof(*eh->buckets));
+
+ while (numBuckets--) {
+ for (entry = oldBuckets[numBuckets]; entry;) {
+ EHEntry *next = entry->next;
+
+ hash = EHASH_hash(eh, entry->key);
+ entry->next = eh->buckets[hash];
+ eh->buckets[hash] = entry;
+
+ entry = next;
+ }
+ }
+
+ EHASH_free(eh, oldBuckets);
+ }
+}
+
+static void *_ehash_lookupWithPrev(EHash *eh, void *key, void ***prevp_r) {
+ int hash = EHASH_hash(eh, key);
+ void **prevp = (void**) &eh->buckets[hash];
+ EHEntry *entry;
+
+ for (; (entry = *prevp); prevp = (void**) &entry->next) {
+ if (entry->key==key) {
+ *prevp_r = (void**) prevp;
+ return entry;
+ }
+ }
+
+ return NULL;
+}
+
+static void *_ehash_lookup(EHash *eh, void *key) {
+ int hash = EHASH_hash(eh, key);
+ EHEntry *entry;
+
+ for (entry = eh->buckets[hash]; entry; entry = entry->next)
+ if (entry->key==key)
+ break;
+
+ return entry;
+}
+
+/**/
+
+typedef struct _EHashIterator {
+ EHash *eh;
+ int curBucket;
+ EHEntry *curEntry;
+} EHashIterator;
+
+static EHashIterator *_ehashIterator_new(EHash *eh) {
+ EHashIterator *ehi = EHASH_alloc(eh, sizeof(*ehi));
+ ehi->eh = eh;
+ ehi->curEntry = NULL;
+ ehi->curBucket = -1;
+ while (!ehi->curEntry) {
+ ehi->curBucket++;
+ if (ehi->curBucket==ehi->eh->curSize)
+ break;
+ ehi->curEntry = ehi->eh->buckets[ehi->curBucket];
+ }
+ return ehi;
+}
+static void _ehashIterator_free(EHashIterator *ehi) {
+ EHASH_free(ehi->eh, ehi);
+}
+
+static void *_ehashIterator_getCurrent(EHashIterator *ehi) {
+ return ehi->curEntry;
+}
+
+static void _ehashIterator_next(EHashIterator *ehi) {
+ if (ehi->curEntry) {
+ ehi->curEntry = ehi->curEntry->next;
+ while (!ehi->curEntry) {
+ ehi->curBucket++;
+ if (ehi->curBucket==ehi->eh->curSize)
+ break;
+ ehi->curEntry = ehi->eh->buckets[ehi->curBucket];
+ }
+ }
+}
+static int _ehashIterator_isStopped(EHashIterator *ehi) {
+ return !ehi->curEntry;
+}
+
+/***/
+
+static void *_stdAllocator_alloc(CCGAllocatorHDL a, int numBytes) {
+ return malloc(numBytes);
+}
+static void *_stdAllocator_realloc(CCGAllocatorHDL a, void *ptr, int newSize, int oldSize) {
+ return realloc(ptr, newSize);
+}
+static void _stdAllocator_free(CCGAllocatorHDL a, void *ptr) {
+ free(ptr);
+}
+
+static CCGAllocatorIFC *_getStandardAllocatorIFC(void) {
+ static CCGAllocatorIFC ifc;
+
+ ifc.alloc = _stdAllocator_alloc;
+ ifc.realloc = _stdAllocator_realloc;
+ ifc.free = _stdAllocator_free;
+ ifc.release = NULL;
+
+ return &ifc;
+}
+
+/***/
+
+static int VertDataEqual(float *a, float *b) {
+ return a[0]==b[0] && a[1]==b[1] && a[2]==b[2];
+}
+#define VertDataZero(av) { float *a = (float*) av; a[0] = a[1] = a[2] = 0.0f; }
+#define VertDataCopy(av, bv) { float *a = (float*) av, *b = (float*) bv; a[0] =b[0]; a[1] =b[1]; a[2] =b[2]; }
+#define VertDataAdd(av, bv) { float *a = (float*) av, *b = (float*) bv; a[0]+=b[0]; a[1]+=b[1]; a[2]+=b[2]; }
+#define VertDataSub(av, bv) { float *a = (float*) av, *b = (float*) bv; a[0]-=b[0]; a[1]-=b[1]; a[2]-=b[2]; }
+#define VertDataMulN(av, n) { float *a = (float*) av; a[0]*=n; a[1]*=n; a[2]*=n; }
+#define VertDataAvg4(tv, av, bv, cv, dv) \
+ { \
+ float *t = (float*) tv, *a = (float*) av, *b = (float*) bv, *c = (float*) cv, *d = (float*) dv; \
+ t[0] = (a[0]+b[0]+c[0]+d[0])*.25; \
+ t[1] = (a[1]+b[1]+c[1]+d[1])*.25; \
+ t[2] = (a[2]+b[2]+c[2]+d[2])*.25; \
+ }
+#define NormZero(av) { float *a = (float*) av; a[0] = a[1] = a[2] = 0.0f; }
+#define NormCopy(av, bv) { float *a = (float*) av, *b = (float*) bv; a[0] =b[0]; a[1] =b[1]; a[2] =b[2]; }
+#define NormAdd(av, bv) { float *a = (float*) av, *b = (float*) bv; a[0]+=b[0]; a[1]+=b[1]; a[2]+=b[2]; }
+
+
+static int _edge_isBoundary(CCGEdge *e);
+
+/***/
+
+enum {
+ Vert_eEffected= (1<<0),
+ Vert_eChanged= (1<<1),
+ Vert_eSeam= (1<<2),
+} VertFlags;
+enum {
+ Edge_eEffected= (1<<0),
+} CCGEdgeFlags;
+enum {
+ Face_eEffected= (1<<0),
+} FaceFlags;
+
+struct _CCGVert {
+ CCGVert *next; /* EHData.next */
+ CCGVertHDL vHDL; /* EHData.key */
+
+ short numEdges, numFaces, flags, pad;
+
+ CCGEdge **edges;
+ CCGFace **faces;
+// byte *levelData;
+// byte *userData;
+};
+#define VERT_getLevelData(v) ((byte*) &(v)[1])
+
+struct _CCGEdge {
+ CCGEdge *next; /* EHData.next */
+ CCGEdgeHDL eHDL; /* EHData.key */
+
+ short numFaces, flags;
+ float crease;
+
+ CCGVert *v0,*v1;
+ CCGFace **faces;
+
+// byte *levelData;
+// byte *userData;
+};
+#define EDGE_getLevelData(e) ((byte*) &(e)[1])
+
+struct _CCGFace {
+ CCGFace *next; /* EHData.next */
+ CCGFaceHDL fHDL; /* EHData.key */
+
+ short numVerts, flags, pad1, pad2;
+
+// CCGVert **verts;
+// CCGEdge **edges;
+// byte *centerData;
+// byte **gridData;
+// byte *userData;
+};
+#define FACE_getVerts(f) ((CCGVert**) &(f)[1])
+#define FACE_getEdges(f) ((CCGEdge**) &(FACE_getVerts(f)[(f)->numVerts]))
+#define FACE_getCenterData(f) ((byte*) &(FACE_getEdges(f)[(f)->numVerts]))
+
+typedef enum {
+ eSyncState_None = 0,
+ eSyncState_Vert,
+ eSyncState_Edge,
+ eSyncState_Face,
+ eSyncState_Partial,
+} SyncState;
+
+struct _CCGSubSurf {
+ EHash *vMap; /* map of CCGVertHDL -> Vert */
+ EHash *eMap; /* map of CCGEdgeHDL -> Edge */
+ EHash *fMap; /* map of CCGFaceHDL -> Face */
+
+ CCGMeshIFC meshIFC;
+
+ CCGAllocatorIFC allocatorIFC;
+ CCGAllocatorHDL allocator;
+
+ int subdivLevels;
+ int numGrids;
+ int allowEdgeCreation;
+ float defaultCreaseValue;
+ void *defaultEdgeUserData;
+
+ void *q, *r;
+
+ // data for calc vert normals
+ int calcVertNormals;
+ int normalDataOffset;
+
+ // data for age'ing (to debug sync)
+ int currentAge;
+ int useAgeCounts;
+ int vertUserAgeOffset;
+ int edgeUserAgeOffset;
+ int faceUserAgeOffset;
+
+ // data used during syncing
+ SyncState syncState;
+
+ EHash *oldVMap, *oldEMap, *oldFMap;
+ int lenTempArrays;
+ CCGVert **tempVerts;
+ CCGEdge **tempEdges;
+};
+
+#define CCGSUBSURF_alloc(ss, nb) ((ss)->allocatorIFC.alloc((ss)->allocator, nb))
+#define CCGSUBSURF_realloc(ss, ptr, nb, ob) ((ss)->allocatorIFC.realloc((ss)->allocator, ptr, nb, ob))
+#define CCGSUBSURF_free(ss, ptr) ((ss)->allocatorIFC.free((ss)->allocator, ptr))
+
+/***/
+
+static CCGVert *_vert_new(CCGVertHDL vHDL, int levels, int dataSize, CCGSubSurf *ss) {
+ CCGVert *v = CCGSUBSURF_alloc(ss, sizeof(CCGVert) + ss->meshIFC.vertDataSize * (ss->subdivLevels+1) + ss->meshIFC.vertUserSize);
+ byte *userData;
+
+ v->vHDL = vHDL;
+ v->edges = NULL;
+ v->faces = NULL;
+ v->numEdges = v->numFaces = 0;
+ v->flags = 0;
+
+ userData = ccgSubSurf_getVertUserData(ss, v);
+ memset(userData, 0, ss->meshIFC.vertUserSize);
+ if (ss->useAgeCounts) *((int*) &userData[ss->vertUserAgeOffset]) = ss->currentAge;
+
+ return v;
+}
+static void _vert_remEdge(CCGVert *v, CCGEdge *e, CCGSubSurf *ss) {
+ int i;
+ for (i=0; i<v->numEdges; i++) {
+ if (v->edges[i]==e) {
+ v->edges[i] = v->edges[--v->numEdges];
+ break;
+ }
+ }
+}
+static void _vert_remFace(CCGVert *v, CCGFace *f, CCGSubSurf *ss) {
+ int i;
+ for (i=0; i<v->numFaces; i++) {
+ if (v->faces[i]==f) {
+ v->faces[i] = v->faces[--v->numFaces];
+ break;
+ }
+ }
+}
+static void _vert_addEdge(CCGVert *v, CCGEdge *e, CCGSubSurf *ss) {
+ v->edges = CCGSUBSURF_realloc(ss, v->edges, (v->numEdges+1)*sizeof(*v->edges), v->numEdges*sizeof(*v->edges));
+ v->edges[v->numEdges++] = e;
+}
+static void _vert_addFace(CCGVert *v, CCGFace *f, CCGSubSurf *ss) {
+ v->faces = CCGSUBSURF_realloc(ss, v->faces, (v->numFaces+1)*sizeof(*v->faces), v->numFaces*sizeof(*v->faces));
+ v->faces[v->numFaces++] = f;
+}
+static CCGEdge *_vert_findEdgeTo(CCGVert *v, CCGVert *vQ) {
+ int i;
+ for (i=0; i<v->numEdges; i++) {
+ CCGEdge *e = v->edges[v->numEdges-1-i]; // XXX, note reverse
+ if ( (e->v0==v && e->v1==vQ) ||
+ (e->v1==v && e->v0==vQ))
+ return e;
+ }
+ return 0;
+}
+static int _vert_isBoundary(CCGVert *v) {
+ int i;
+ for (i=0; i<v->numEdges; i++)
+ if (_edge_isBoundary(v->edges[i]))
+ return 1;
+ return 0;
+}
+
+static void *_vert_getCo(CCGVert *v, int lvl, int dataSize) {
+ return &VERT_getLevelData(v)[lvl*dataSize];
+}
+static float *_vert_getNo(CCGVert *v, int lvl, int dataSize, int normalDataOffset) {
+ return (float*) &VERT_getLevelData(v)[lvl*dataSize + normalDataOffset];
+}
+
+static void _vert_free(CCGVert *v, CCGSubSurf *ss) {
+ CCGSUBSURF_free(ss, v->edges);
+ CCGSUBSURF_free(ss, v->faces);
+ CCGSUBSURF_free(ss, v);
+}
+
+static int VERT_seam(CCGVert *v, CCGSubSurf *ss) {
+ return ((v->flags & Vert_eSeam) != 0);
+}
+
+/***/
+
+static CCGEdge *_edge_new(CCGEdgeHDL eHDL, CCGVert *v0, CCGVert *v1, float crease, int levels, int dataSize, CCGSubSurf *ss) {
+ CCGEdge *e = CCGSUBSURF_alloc(ss, sizeof(CCGEdge) + ss->meshIFC.vertDataSize *((ss->subdivLevels+1) + (1<<(ss->subdivLevels+1))-1) + ss->meshIFC.edgeUserSize);
+ byte *userData;
+
+ e->eHDL = eHDL;
+ e->v0 = v0;
+ e->v1 = v1;
+ e->crease = crease;
+ e->faces = NULL;
+ e->numFaces = 0;
+ e->flags = 0;
+ _vert_addEdge(v0, e, ss);
+ _vert_addEdge(v1, e, ss);
+
+ userData = ccgSubSurf_getEdgeUserData(ss, e);
+ memset(userData, 0, ss->meshIFC.edgeUserSize);
+ if (ss->useAgeCounts) *((int*) &userData[ss->edgeUserAgeOffset]) = ss->currentAge;
+
+ return e;
+}
+static void _edge_remFace(CCGEdge *e, CCGFace *f, CCGSubSurf *ss) {
+ int i;
+ for (i=0; i<e->numFaces; i++) {
+ if (e->faces[i]==f) {
+ e->faces[i] = e->faces[--e->numFaces];
+ break;
+ }
+ }
+}
+static void _edge_addFace(CCGEdge *e, CCGFace *f, CCGSubSurf *ss) {
+ e->faces = CCGSUBSURF_realloc(ss, e->faces, (e->numFaces+1)*sizeof(*e->faces), e->numFaces*sizeof(*e->faces));
+ e->faces[e->numFaces++] = f;
+}
+static int _edge_isBoundary(CCGEdge *e) {
+ return e->numFaces<2;
+}
+
+static CCGVert *_edge_getOtherVert(CCGEdge *e, CCGVert *vQ) {
+ if (vQ==e->v0) {
+ return e->v1;
+ } else {
+ return e->v0;
+ }
+}
+
+static void *_edge_getCo(CCGEdge *e, int lvl, int x, int dataSize) {
+ int levelBase = lvl + (1<<lvl) - 1;
+ return &EDGE_getLevelData(e)[dataSize*(levelBase + x)];
+}
+#if 0
+static float *_edge_getNo(CCGEdge *e, int lvl, int x, int dataSize, int normalDataOffset) {
+ int levelBase = lvl + (1<<lvl) - 1;
+ return (float*) &EDGE_getLevelData(e)[dataSize*(levelBase + x) + normalDataOffset];
+}
+#endif
+static void *_edge_getCoVert(CCGEdge *e, CCGVert *v, int lvl, int x, int dataSize) {
+ int levelBase = lvl + (1<<lvl) - 1;
+ if (v==e->v0) {
+ return &EDGE_getLevelData(e)[dataSize*(levelBase + x)];
+ } else {
+ return &EDGE_getLevelData(e)[dataSize*(levelBase + (1<<lvl) - x)];
+ }
+}
+
+static void _edge_free(CCGEdge *e, CCGSubSurf *ss) {
+ CCGSUBSURF_free(ss, e->faces);
+ CCGSUBSURF_free(ss, e);
+}
+static void _edge_unlinkMarkAndFree(CCGEdge *e, CCGSubSurf *ss) {
+ _vert_remEdge(e->v0, e, ss);
+ _vert_remEdge(e->v1, e, ss);
+ e->v0->flags |= Vert_eEffected;
+ e->v1->flags |= Vert_eEffected;
+ _edge_free(e, ss);
+}
+
+static float EDGE_getSharpness(CCGEdge *e, int lvl) {
+ if (!lvl)
+ return e->crease;
+ else if (!e->crease)
+ return 0.0;
+ else if (e->crease - lvl < 0.0)
+ return 0.0;
+ else
+ return e->crease - lvl;
+}
+
+static CCGFace *_face_new(CCGFaceHDL fHDL, CCGVert **verts, CCGEdge **edges, int numVerts, int levels, int dataSize, CCGSubSurf *ss) {
+ int maxGridSize = 1 + (1<<(ss->subdivLevels-1));
+ CCGFace *f = CCGSUBSURF_alloc(ss, sizeof(CCGFace) + sizeof(CCGVert*)*numVerts + sizeof(CCGEdge*)*numVerts + ss->meshIFC.vertDataSize *(1 + numVerts*maxGridSize + numVerts*maxGridSize*maxGridSize) + ss->meshIFC.faceUserSize);
+ byte *userData;
+ int i;
+
+ f->numVerts = numVerts;
+ f->fHDL = fHDL;
+ f->flags = 0;
+
+ for (i=0; i<numVerts; i++) {
+ FACE_getVerts(f)[i] = verts[i];
+ FACE_getEdges(f)[i] = edges[i];
+ _vert_addFace(verts[i], f, ss);
+ _edge_addFace(edges[i], f, ss);
+ }
+
+ userData = ccgSubSurf_getFaceUserData(ss, f);
+ memset(userData, 0, ss->meshIFC.faceUserSize);
+ if (ss->useAgeCounts) *((int*) &userData[ss->faceUserAgeOffset]) = ss->currentAge;
+
+ return f;
+}
+
+static void *_face_getIECo(CCGFace *f, int lvl, int S, int x, int levels, int dataSize) {
+ int maxGridSize = 1 + (1<<(levels-1));
+ int spacing = 1<<(levels-lvl);
+ byte *gridBase = FACE_getCenterData(f) + dataSize*(1 + S*(maxGridSize + maxGridSize*maxGridSize));
+ return &gridBase[dataSize*x*spacing];
+}
+static void *_face_getIFCo(CCGFace *f, int lvl, int S, int x, int y, int levels, int dataSize) {
+ int maxGridSize = 1 + (1<<(levels-1));
+ int spacing = 1<<(levels-lvl);
+ byte *gridBase = FACE_getCenterData(f) + dataSize*(1 + S*(maxGridSize + maxGridSize*maxGridSize));
+ return &gridBase[dataSize*(maxGridSize + (y*maxGridSize + x)*spacing)];
+}
+static float *_face_getIFNo(CCGFace *f, int lvl, int S, int x, int y, int levels, int dataSize, int normalDataOffset) {
+ int maxGridSize = 1 + (1<<(levels-1));
+ int spacing = 1<<(levels-lvl);
+ byte *gridBase = FACE_getCenterData(f) + dataSize*(1 + S*(maxGridSize + maxGridSize*maxGridSize));
+ return (float*) &gridBase[dataSize*(maxGridSize + (y*maxGridSize + x)*spacing) + normalDataOffset];
+}
+static int _face_getVertIndex(CCGFace *f, CCGVert *v) {
+ int i;
+ for (i=0; i<f->numVerts; i++)
+ if (FACE_getVerts(f)[i]==v)
+ return i;
+ return -1;
+}
+static void *_face_getIFCoEdge(CCGFace *f, CCGEdge *e, int lvl, int eX, int eY, int levels, int dataSize) {
+ int maxGridSize = 1 + (1<<(levels-1));
+ int spacing = 1<<(levels-lvl);
+ int S, x, y, cx, cy;
+
+ for (S=0; S<f->numVerts; S++)
+ if (FACE_getEdges(f)[S]==e)
+ break;
+
+ eX = eX*spacing;
+ eY = eY*spacing;
+ if (e->v0!=FACE_getVerts(f)[S]) {
+ eX = (maxGridSize*2 - 1)-1 - eX;
+ }
+ y = maxGridSize - 1 - eX;
+ x = maxGridSize - 1 - eY;
+ if (x<0) {
+ S = (S+f->numVerts-1)%f->numVerts;
+ cx = y;
+ cy = -x;
+ } else if (y<0) {
+ S = (S+1)%f->numVerts;
+ cx = -y;
+ cy = x;
+ } else {
+ cx = x;
+ cy = y;
+ }
+ return _face_getIFCo(f, levels, S, cx, cy, levels, dataSize);
+}
+static float *_face_getIFNoEdge(CCGFace *f, CCGEdge *e, int lvl, int eX, int eY, int levels, int dataSize, int normalDataOffset) {
+ return (float*) ((byte*) _face_getIFCoEdge(f, e, lvl, eX, eY, levels, dataSize) + normalDataOffset);
+}
+void _face_calcIFNo(CCGFace *f, int lvl, int S, int x, int y, float *no, int levels, int dataSize) {
+ float *a = _face_getIFCo(f, lvl, S, x+0, y+0, levels, dataSize);
+ float *b = _face_getIFCo(f, lvl, S, x+1, y+0, levels, dataSize);
+ float *c = _face_getIFCo(f, lvl, S, x+1, y+1, levels, dataSize);
+ float *d = _face_getIFCo(f, lvl, S, x+0, y+1, levels, dataSize);
+ float a_cX = c[0]-a[0], a_cY = c[1]-a[1], a_cZ = c[2]-a[2];
+ float b_dX = d[0]-b[0], b_dY = d[1]-b[1], b_dZ = d[2]-b[2];
+ float length;
+
+ no[0] = b_dY*a_cZ - b_dZ*a_cY;
+ no[1] = b_dZ*a_cX - b_dX*a_cZ;
+ no[2] = b_dX*a_cY - b_dY*a_cX;
+
+ length = sqrt(no[0]*no[0] + no[1]*no[1] + no[2]*no[2]);
+
+ if (length>FLT_EPSILON) {
+ float invLength = 1.f/length;
+
+ no[0] *= invLength;
+ no[1] *= invLength;
+ no[2] *= invLength;
+ } else {
+ NormZero(no);
+ }
+}
+
+static void _face_free(CCGFace *f, CCGSubSurf *ss) {
+ CCGSUBSURF_free(ss, f);
+}
+static void _face_unlinkMarkAndFree(CCGFace *f, CCGSubSurf *ss) {
+ int j;
+ for (j=0; j<f->numVerts; j++) {
+ _vert_remFace(FACE_getVerts(f)[j], f, ss);
+ _edge_remFace(FACE_getEdges(f)[j], f, ss);
+ FACE_getVerts(f)[j]->flags |= Vert_eEffected;
+ }
+ _face_free(f, ss);
+}
+
+/***/
+
+CCGSubSurf *ccgSubSurf_new(CCGMeshIFC *ifc, int subdivLevels, CCGAllocatorIFC *allocatorIFC, CCGAllocatorHDL allocator) {
+ if (!allocatorIFC) {
+ allocatorIFC = _getStandardAllocatorIFC();
+ allocator = NULL;
+ }
+
+ if (subdivLevels<1) {
+ return NULL;
+ } else {
+ CCGSubSurf *ss = allocatorIFC->alloc(allocator, sizeof(*ss));
+
+ ss->allocatorIFC = *allocatorIFC;
+ ss->allocator = allocator;
+
+ ss->vMap = _ehash_new(0, &ss->allocatorIFC, ss->allocator);
+ ss->eMap = _ehash_new(0, &ss->allocatorIFC, ss->allocator);
+ ss->fMap = _ehash_new(0, &ss->allocatorIFC, ss->allocator);
+
+ ss->meshIFC = *ifc;
+
+ ss->subdivLevels = subdivLevels;
+ ss->numGrids = 0;
+ ss->allowEdgeCreation = 0;
+ ss->defaultCreaseValue = 0;
+ ss->defaultEdgeUserData = NULL;
+
+ ss->useAgeCounts = 0;
+ ss->vertUserAgeOffset = ss->edgeUserAgeOffset = ss->faceUserAgeOffset = 0;
+
+ ss->calcVertNormals = 0;
+ ss->normalDataOffset = 0;
+
+ ss->q = CCGSUBSURF_alloc(ss, ss->meshIFC.vertDataSize);
+ ss->r = CCGSUBSURF_alloc(ss, ss->meshIFC.vertDataSize);
+
+ ss->currentAge = 0;
+
+ ss->syncState = eSyncState_None;
+
+ ss->oldVMap = ss->oldEMap = ss->oldFMap = NULL;
+ ss->lenTempArrays = 0;
+ ss->tempVerts = NULL;
+ ss->tempEdges = NULL;
+
+ return ss;
+ }
+}
+
+void ccgSubSurf_free(CCGSubSurf *ss) {
+ CCGAllocatorIFC allocatorIFC = ss->allocatorIFC;
+ CCGAllocatorHDL allocator = ss->allocator;
+
+ if (ss->syncState) {
+ _ehash_free(ss->oldFMap, (EHEntryFreeFP) _face_free, ss);
+ _ehash_free(ss->oldEMap, (EHEntryFreeFP) _edge_free, ss);
+ _ehash_free(ss->oldVMap, (EHEntryFreeFP) _vert_free, ss);
+
+ CCGSUBSURF_free(ss, ss->tempVerts);
+ CCGSUBSURF_free(ss, ss->tempEdges);
+ }
+
+ CCGSUBSURF_free(ss, ss->r);
+ CCGSUBSURF_free(ss, ss->q);
+ if (ss->defaultEdgeUserData) CCGSUBSURF_free(ss, ss->defaultEdgeUserData);
+
+ _ehash_free(ss->fMap, (EHEntryFreeFP) _face_free, ss);
+ _ehash_free(ss->eMap, (EHEntryFreeFP) _edge_free, ss);
+ _ehash_free(ss->vMap, (EHEntryFreeFP) _vert_free, ss);
+
+ CCGSUBSURF_free(ss, ss);
+
+ if (allocatorIFC.release) {
+ allocatorIFC.release(allocator);
+ }
+}
+
+CCGError ccgSubSurf_setAllowEdgeCreation(CCGSubSurf *ss, int allowEdgeCreation, float defaultCreaseValue, void *defaultUserData) {
+ if (ss->defaultEdgeUserData) {
+ CCGSUBSURF_free(ss, ss->defaultEdgeUserData);
+ }
+
+ ss->allowEdgeCreation = !!allowEdgeCreation;
+ ss->defaultCreaseValue = defaultCreaseValue;
+ ss->defaultEdgeUserData = CCGSUBSURF_alloc(ss, ss->meshIFC.edgeUserSize);
+
+ if (defaultUserData) {
+ memcpy(ss->defaultEdgeUserData, defaultUserData, ss->meshIFC.edgeUserSize);
+ } else {
+ memset(ss->defaultEdgeUserData, 0, ss->meshIFC.edgeUserSize);
+ }
+
+ return eCCGError_None;
+}
+void ccgSubSurf_getAllowEdgeCreation(CCGSubSurf *ss, int *allowEdgeCreation_r, float *defaultCreaseValue_r, void *defaultUserData_r) {
+ if (allowEdgeCreation_r) *allowEdgeCreation_r = ss->allowEdgeCreation;
+ if (ss->allowEdgeCreation) {
+ if (defaultCreaseValue_r) *defaultCreaseValue_r = ss->defaultCreaseValue;
+ if (defaultUserData_r) memcpy(defaultUserData_r, ss->defaultEdgeUserData, ss->meshIFC.edgeUserSize);
+ }
+}
+
+CCGError ccgSubSurf_setSubdivisionLevels(CCGSubSurf *ss, int subdivisionLevels) {
+ if (subdivisionLevels<=0) {
+ return eCCGError_InvalidValue;
+ } else if (subdivisionLevels!=ss->subdivLevels) {
+ ss->numGrids = 0;
+ ss->subdivLevels = subdivisionLevels;
+ _ehash_free(ss->vMap, (EHEntryFreeFP) _vert_free, ss);
+ _ehash_free(ss->eMap, (EHEntryFreeFP) _edge_free, ss);
+ _ehash_free(ss->fMap, (EHEntryFreeFP) _face_free, ss);
+ ss->vMap = _ehash_new(0, &ss->allocatorIFC, ss->allocator);
+ ss->eMap = _ehash_new(0, &ss->allocatorIFC, ss->allocator);
+ ss->fMap = _ehash_new(0, &ss->allocatorIFC, ss->allocator);
+ }
+
+ return eCCGError_None;
+}
+
+void ccgSubSurf_getUseAgeCounts(CCGSubSurf *ss, int *useAgeCounts_r, int *vertUserOffset_r, int *edgeUserOffset_r, int *faceUserOffset_r)
+{
+ *useAgeCounts_r = ss->useAgeCounts;
+
+ if (vertUserOffset_r) *vertUserOffset_r = ss->vertUserAgeOffset;
+ if (edgeUserOffset_r) *edgeUserOffset_r = ss->edgeUserAgeOffset;
+ if (faceUserOffset_r) *faceUserOffset_r = ss->faceUserAgeOffset;
+}
+
+CCGError ccgSubSurf_setUseAgeCounts(CCGSubSurf *ss, int useAgeCounts, int vertUserOffset, int edgeUserOffset, int faceUserOffset) {
+ if (useAgeCounts) {
+ if ( (vertUserOffset+4>ss->meshIFC.vertUserSize) ||
+ (edgeUserOffset+4>ss->meshIFC.edgeUserSize) ||
+ (faceUserOffset+4>ss->meshIFC.faceUserSize)) {
+ return eCCGError_InvalidValue;
+ } else {
+ ss->useAgeCounts = 1;
+ ss->vertUserAgeOffset = vertUserOffset;
+ ss->edgeUserAgeOffset = edgeUserOffset;
+ ss->faceUserAgeOffset = faceUserOffset;
+ }
+ } else {
+ ss->useAgeCounts = 0;
+ ss->vertUserAgeOffset = ss->edgeUserAgeOffset = ss->faceUserAgeOffset = 0;
+ }
+
+ return eCCGError_None;
+}
+
+CCGError ccgSubSurf_setCalcVertexNormals(CCGSubSurf *ss, int useVertNormals, int normalDataOffset) {
+ if (useVertNormals) {
+ if (normalDataOffset<0 || normalDataOffset+12>ss->meshIFC.vertDataSize) {
+ return eCCGError_InvalidValue;
+ } else {
+ ss->calcVertNormals = 1;
+ ss->normalDataOffset = normalDataOffset;
+ }
+ } else {
+ ss->calcVertNormals = 0;
+ ss->normalDataOffset = 0;
+ }
+
+ return eCCGError_None;
+}
+
+/***/
+
+CCGError ccgSubSurf_initFullSync(CCGSubSurf *ss) {
+ if (ss->syncState!=eSyncState_None) {
+ return eCCGError_InvalidSyncState;
+ }
+
+ ss->currentAge++;
+
+ ss->oldVMap = ss->vMap;
+ ss->oldEMap = ss->eMap;
+ ss->oldFMap = ss->fMap;
+
+ ss->vMap = _ehash_new(0, &ss->allocatorIFC, ss->allocator);
+ ss->eMap = _ehash_new(0, &ss->allocatorIFC, ss->allocator);
+ ss->fMap = _ehash_new(0, &ss->allocatorIFC, ss->allocator);
+
+ ss->numGrids = 0;
+
+ ss->lenTempArrays = 12;
+ ss->tempVerts = CCGSUBSURF_alloc(ss, sizeof(*ss->tempVerts)*ss->lenTempArrays);
+ ss->tempEdges = CCGSUBSURF_alloc(ss, sizeof(*ss->tempEdges)*ss->lenTempArrays);
+
+ ss->syncState = eSyncState_Vert;
+
+ return eCCGError_None;
+}
+
+CCGError ccgSubSurf_initPartialSync(CCGSubSurf *ss) {
+ if (ss->syncState!=eSyncState_None) {
+ return eCCGError_InvalidSyncState;
+ }
+
+ ss->currentAge++;
+
+ ss->syncState = eSyncState_Partial;
+
+ return eCCGError_None;
+}
+
+CCGError ccgSubSurf_syncVertDel(CCGSubSurf *ss, CCGVertHDL vHDL) {
+ if (ss->syncState!=eSyncState_Partial) {
+ return eCCGError_InvalidSyncState;
+ } else {
+ void **prevp;
+ CCGVert *v = _ehash_lookupWithPrev(ss->vMap, vHDL, &prevp);
+
+ if (!v || v->numFaces || v->numEdges) {
+ return eCCGError_InvalidValue;
+ } else {
+ *prevp = v->next;
+ _vert_free(v, ss);
+ }
+ }
+
+ return eCCGError_None;
+}
+
+CCGError ccgSubSurf_syncEdgeDel(CCGSubSurf *ss, CCGEdgeHDL eHDL) {
+ if (ss->syncState!=eSyncState_Partial) {
+ return eCCGError_InvalidSyncState;
+ } else {
+ void **prevp;
+ CCGEdge *e = _ehash_lookupWithPrev(ss->eMap, eHDL, &prevp);
+
+ if (!e || e->numFaces) {
+ return eCCGError_InvalidValue;
+ } else {
+ *prevp = e->next;
+ _edge_unlinkMarkAndFree(e, ss);
+ }
+ }
+
+ return eCCGError_None;
+}
+
+CCGError ccgSubSurf_syncFaceDel(CCGSubSurf *ss, CCGFaceHDL fHDL) {
+ if (ss->syncState!=eSyncState_Partial) {
+ return eCCGError_InvalidSyncState;
+ } else {
+ void **prevp;
+ CCGFace *f = _ehash_lookupWithPrev(ss->fMap, fHDL, &prevp);
+
+ if (!f) {
+ return eCCGError_InvalidValue;
+ } else {
+ *prevp = f->next;
+ _face_unlinkMarkAndFree(f, ss);
+ }
+ }
+
+ return eCCGError_None;
+}
+
+CCGError ccgSubSurf_syncVert(CCGSubSurf *ss, CCGVertHDL vHDL, void *vertData, int seam, CCGVert **v_r) {
+ void **prevp;
+ CCGVert *v = NULL;
+ short seamflag = (seam)? Vert_eSeam: 0;
+
+ if (ss->syncState==eSyncState_Partial) {
+ v = _ehash_lookupWithPrev(ss->vMap, vHDL, &prevp);
+ if (!v) {
+ v = _vert_new(vHDL, ss->subdivLevels, ss->meshIFC.vertDataSize, ss);
+ VertDataCopy(_vert_getCo(v,0,ss->meshIFC.vertDataSize), vertData);
+ _ehash_insert(ss->vMap, (EHEntry*) v);
+ v->flags = Vert_eEffected|seamflag;
+ } else if (!VertDataEqual(vertData, _vert_getCo(v, 0, ss->meshIFC.vertDataSize)) || ((v->flags & Vert_eSeam) != seamflag)) {
+ int i, j;
+
+ VertDataCopy(_vert_getCo(v,0,ss->meshIFC.vertDataSize), vertData);
+ v->flags = Vert_eEffected|seamflag;
+
+ for (i=0; i<v->numEdges; i++) {
+ CCGEdge *e = v->edges[i];
+ e->v0->flags |= Vert_eEffected;
+ e->v1->flags |= Vert_eEffected;
+ }
+ for (i=0; i<v->numFaces; i++) {
+ CCGFace *f = v->faces[i];
+ for (j=0; j<f->numVerts; j++) {
+ FACE_getVerts(f)[j]->flags |= Vert_eEffected;
+ }
+ }
+ }
+ } else {
+ if (ss->syncState!=eSyncState_Vert) {
+ return eCCGError_InvalidSyncState;
+ }
+
+ v = _ehash_lookupWithPrev(ss->oldVMap, vHDL, &prevp);
+ if (!v) {
+ v = _vert_new(vHDL, ss->subdivLevels, ss->meshIFC.vertDataSize, ss);
+ VertDataCopy(_vert_getCo(v,0,ss->meshIFC.vertDataSize), vertData);
+ _ehash_insert(ss->vMap, (EHEntry*) v);
+ v->flags = Vert_eEffected|seamflag;
+ } else if (!VertDataEqual(vertData, _vert_getCo(v, 0, ss->meshIFC.vertDataSize)) || ((v->flags & Vert_eSeam) != seamflag)) {
+ *prevp = v->next;
+ _ehash_insert(ss->vMap, (EHEntry*) v);
+ VertDataCopy(_vert_getCo(v,0,ss->meshIFC.vertDataSize), vertData);
+ v->flags = Vert_eEffected|Vert_eChanged|seamflag;
+ } else {
+ *prevp = v->next;
+ _ehash_insert(ss->vMap, (EHEntry*) v);
+ v->flags = 0;
+ }
+ }
+
+ if (v_r) *v_r = v;
+ return eCCGError_None;
+}
+
+CCGError ccgSubSurf_syncEdge(CCGSubSurf *ss, CCGEdgeHDL eHDL, CCGVertHDL e_vHDL0, CCGVertHDL e_vHDL1, float crease, CCGEdge **e_r) {
+ void **prevp;
+ CCGEdge *e = NULL, *eNew;
+
+ if (ss->syncState==eSyncState_Partial) {
+ e = _ehash_lookupWithPrev(ss->eMap, eHDL, &prevp);
+ if (!e || e->v0->vHDL!=e_vHDL0 || e->v1->vHDL!=e_vHDL1 || crease!=e->crease) {
+ CCGVert *v0 = _ehash_lookup(ss->vMap, e_vHDL0);
+ CCGVert *v1 = _ehash_lookup(ss->vMap, e_vHDL1);
+
+ eNew = _edge_new(eHDL, v0, v1, crease, ss->subdivLevels, ss->meshIFC.vertDataSize, ss);
+
+ if (e) {
+ *prevp = eNew;
+ eNew->next = e->next;
+
+ _edge_unlinkMarkAndFree(e, ss);
+ } else {
+ _ehash_insert(ss->eMap, (EHEntry*) eNew);
+ }
+
+ eNew->v0->flags |= Vert_eEffected;
+ eNew->v1->flags |= Vert_eEffected;
+ }
+ } else {
+ if (ss->syncState==eSyncState_Vert) {
+ ss->syncState = eSyncState_Edge;
+ } else if (ss->syncState!=eSyncState_Edge) {
+ return eCCGError_InvalidSyncState;
+ }
+
+ e = _ehash_lookupWithPrev(ss->oldEMap, eHDL, &prevp);
+ if (!e || e->v0->vHDL!=e_vHDL0 || e->v1->vHDL!=e_vHDL1|| e->crease!=crease) {
+ CCGVert *v0 = _ehash_lookup(ss->vMap, e_vHDL0);
+ CCGVert *v1 = _ehash_lookup(ss->vMap, e_vHDL1);
+ e = _edge_new(eHDL, v0, v1, crease, ss->subdivLevels, ss->meshIFC.vertDataSize, ss);
+ _ehash_insert(ss->eMap, (EHEntry*) e);
+ e->v0->flags |= Vert_eEffected;
+ e->v1->flags |= Vert_eEffected;
+ } else {
+ *prevp = e->next;
+ _ehash_insert(ss->eMap, (EHEntry*) e);
+ e->flags = 0;
+ if ((e->v0->flags|e->v1->flags)&Vert_eChanged) {
+ e->v0->flags |= Vert_eEffected;
+ e->v1->flags |= Vert_eEffected;
+ }
+ }
+ }
+
+ if (e_r) *e_r = e;
+ return eCCGError_None;
+}
+
+CCGError ccgSubSurf_syncFace(CCGSubSurf *ss, CCGFaceHDL fHDL, int numVerts, CCGVertHDL *vHDLs, CCGFace **f_r) {
+ void **prevp;
+ CCGFace *f = NULL, *fNew;
+ int j, k, topologyChanged = 0;
+
+ if (numVerts>ss->lenTempArrays) {
+ int oldLen = ss->lenTempArrays;
+ ss->lenTempArrays = (numVerts<ss->lenTempArrays*2)?ss->lenTempArrays*2:numVerts;
+ ss->tempVerts = CCGSUBSURF_realloc(ss, ss->tempVerts, sizeof(*ss->tempVerts)*ss->lenTempArrays, sizeof(*ss->tempVerts)*oldLen);
+ ss->tempEdges = CCGSUBSURF_realloc(ss, ss->tempEdges, sizeof(*ss->tempEdges)*ss->lenTempArrays, sizeof(*ss->tempEdges)*oldLen);
+ }
+
+ if (ss->syncState==eSyncState_Partial) {
+ f = _ehash_lookupWithPrev(ss->fMap, fHDL, &prevp);
+
+ for (k=0; k<numVerts; k++) {
+ ss->tempVerts[k] = _ehash_lookup(ss->vMap, vHDLs[k]);
+ }
+ for (k=0; k<numVerts; k++) {
+ ss->tempEdges[k] = _vert_findEdgeTo(ss->tempVerts[k], ss->tempVerts[(k+1)%numVerts]);
+ }
+
+ if (f) {
+ if ( f->numVerts!=numVerts ||
+ memcmp(FACE_getVerts(f), ss->tempVerts, sizeof(*ss->tempVerts)*numVerts) ||
+ memcmp(FACE_getEdges(f), ss->tempEdges, sizeof(*ss->tempEdges)*numVerts))
+ topologyChanged = 1;
+ }
+
+ if (!f || topologyChanged) {
+ fNew = _face_new(fHDL, ss->tempVerts, ss->tempEdges, numVerts, ss->subdivLevels, ss->meshIFC.vertDataSize, ss);
+
+ if (f) {
+ ss->numGrids += numVerts - f->numVerts;
+
+ *prevp = fNew;
+ fNew->next = f->next;
+
+ _face_unlinkMarkAndFree(f, ss);
+ } else {
+ ss->numGrids += numVerts;
+ _ehash_insert(ss->fMap, (EHEntry*) fNew);
+ }
+
+ for (k=0; k<numVerts; k++)
+ FACE_getVerts(fNew)[k]->flags |= Vert_eEffected;
+ }
+ } else {
+ if (ss->syncState==eSyncState_Vert || ss->syncState==eSyncState_Edge) {
+ ss->syncState = eSyncState_Face;
+ } else if (ss->syncState!=eSyncState_Face) {
+ return eCCGError_InvalidSyncState;
+ }
+
+ f = _ehash_lookupWithPrev(ss->oldFMap, fHDL, &prevp);
+
+ for (k=0; k<numVerts; k++) {
+ ss->tempVerts[k] = _ehash_lookup(ss->vMap, vHDLs[k]);
+
+ if (!ss->tempVerts[k])
+ return eCCGError_InvalidValue;
+ }
+ for (k=0; k<numVerts; k++) {
+ ss->tempEdges[k] = _vert_findEdgeTo(ss->tempVerts[k], ss->tempVerts[(k+1)%numVerts]);
+
+ if (!ss->tempEdges[k]) {
+ if (ss->allowEdgeCreation) {
+ CCGEdge *e = ss->tempEdges[k] = _edge_new((CCGEdgeHDL) -1, ss->tempVerts[k], ss->tempVerts[(k+1)%numVerts], ss->defaultCreaseValue, ss->subdivLevels, ss->meshIFC.vertDataSize, ss);
+ _ehash_insert(ss->eMap, (EHEntry*) e);
+ e->v0->flags |= Vert_eEffected;
+ e->v1->flags |= Vert_eEffected;
+ if (ss->meshIFC.edgeUserSize) {
+ memcpy(ccgSubSurf_getEdgeUserData(ss, e), ss->defaultEdgeUserData, ss->meshIFC.edgeUserSize);
+ }
+ } else {
+ return eCCGError_InvalidValue;
+ }
+ }
+ }
+
+ if (f) {
+ if ( f->numVerts!=numVerts ||
+ memcmp(FACE_getVerts(f), ss->tempVerts, sizeof(*ss->tempVerts)*numVerts) ||
+ memcmp(FACE_getEdges(f), ss->tempEdges, sizeof(*ss->tempEdges)*numVerts))
+ topologyChanged = 1;
+ }
+
+ if (!f || topologyChanged) {
+ f = _face_new(fHDL, ss->tempVerts, ss->tempEdges, numVerts, ss->subdivLevels, ss->meshIFC.vertDataSize, ss);
+ _ehash_insert(ss->fMap, (EHEntry*) f);
+ ss->numGrids += numVerts;
+
+ for (k=0; k<numVerts; k++)
+ FACE_getVerts(f)[k]->flags |= Vert_eEffected;
+ } else {
+ *prevp = f->next;
+ _ehash_insert(ss->fMap, (EHEntry*) f);
+ f->flags = 0;
+ ss->numGrids += f->numVerts;
+
+ for (j=0; j<f->numVerts; j++) {
+ if (FACE_getVerts(f)[j]->flags&Vert_eChanged) {
+ for (k=0; k<f->numVerts; k++)
+ FACE_getVerts(f)[k]->flags |= Vert_eEffected;
+ break;
+ }
+ }
+ }
+ }
+
+ if (f_r) *f_r = f;
+ return eCCGError_None;
+}
+
+static void ccgSubSurf__sync(CCGSubSurf *ss);
+CCGError ccgSubSurf_processSync(CCGSubSurf *ss) {
+ if (ss->syncState==eSyncState_Partial) {
+ ss->syncState = eSyncState_None;
+
+ ccgSubSurf__sync(ss);
+ } else if (ss->syncState) {
+ _ehash_free(ss->oldFMap, (EHEntryFreeFP) _face_unlinkMarkAndFree, ss);
+ _ehash_free(ss->oldEMap, (EHEntryFreeFP) _edge_unlinkMarkAndFree, ss);
+ _ehash_free(ss->oldVMap, (EHEntryFreeFP) _vert_free, ss);
+ CCGSUBSURF_free(ss, ss->tempEdges);
+ CCGSUBSURF_free(ss, ss->tempVerts);
+
+ ss->lenTempArrays = 0;
+
+ ss->oldFMap = ss->oldEMap = ss->oldVMap = NULL;
+ ss->tempVerts = NULL;
+ ss->tempEdges = NULL;
+
+ ss->syncState = eSyncState_None;
+
+ ccgSubSurf__sync(ss);
+ } else {
+ return eCCGError_InvalidSyncState;
+ }
+
+ return eCCGError_None;
+}
+
+static void ccgSubSurf__sync(CCGSubSurf *ss) {
+ CCGVert **effectedV;
+ CCGEdge **effectedE;
+ CCGFace **effectedF;
+ int numEffectedV, numEffectedE, numEffectedF;
+ int subdivLevels = ss->subdivLevels;
+ int vertDataSize = ss->meshIFC.vertDataSize;
+ int i,ptrIdx,cornerIdx;
+ int S,x,y;
+ void *q = ss->q, *r = ss->r;
+ int curLvl, nextLvl;
+ int j;
+
+ effectedV = CCGSUBSURF_alloc(ss, sizeof(*effectedV)*ss->vMap->numEntries);
+ effectedE = CCGSUBSURF_alloc(ss, sizeof(*effectedE)*ss->eMap->numEntries);
+ effectedF = CCGSUBSURF_alloc(ss, sizeof(*effectedF)*ss->fMap->numEntries);
+ numEffectedV = numEffectedE = numEffectedF = 0;
+ for (i=0; i<ss->vMap->curSize; i++) {
+ CCGVert *v = (CCGVert*) ss->vMap->buckets[i];
+ for (; v; v = v->next) {
+ if (v->flags&Vert_eEffected) {
+ effectedV[numEffectedV++] = v;
+
+ for (j=0; j<v->numEdges; j++) {
+ CCGEdge *e = v->edges[j];
+ if (!(e->flags&Edge_eEffected)) {
+ effectedE[numEffectedE++] = e;
+ e->flags |= Edge_eEffected;
+ }
+ }
+
+ for (j=0; j<v->numFaces; j++) {
+ CCGFace *f = v->faces[j];
+ if (!(f->flags&Face_eEffected)) {
+ effectedF[numEffectedF++] = f;
+ f->flags |= Face_eEffected;
+ }
+ }
+ }
+ }
+ }
+
+#define VERT_getCo(v, lvl) _vert_getCo(v, lvl, vertDataSize)
+#define EDGE_getCo(e, lvl, x) _edge_getCo(e, lvl, x, vertDataSize)
+#define FACE_getIECo(f, lvl, S, x) _face_getIECo(f, lvl, S, x, subdivLevels, vertDataSize)
+#define FACE_getIFCo(f, lvl, S, x, y) _face_getIFCo(f, lvl, S, x, y, subdivLevels, vertDataSize)
+ curLvl = 0;
+ nextLvl = curLvl+1;
+
+ for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) {
+ CCGFace *f = effectedF[ptrIdx];
+ void *co = FACE_getCenterData(f);
+ VertDataZero(co);
+ for (i=0; i<f->numVerts; i++) {
+ VertDataAdd(co, VERT_getCo(FACE_getVerts(f)[i], curLvl));
+ }
+ VertDataMulN(co, 1.0f/f->numVerts);
+
+ f->flags = 0;
+ }
+ for (ptrIdx=0; ptrIdx<numEffectedE; ptrIdx++) {
+ CCGEdge *e = effectedE[ptrIdx];
+ void *co = EDGE_getCo(e, nextLvl, 1);
+ float sharpness = EDGE_getSharpness(e, curLvl);
+
+ if (_edge_isBoundary(e) || sharpness>=1.0) {
+ VertDataCopy(co, VERT_getCo(e->v0, curLvl));
+ VertDataAdd(co, VERT_getCo(e->v1, curLvl));
+ VertDataMulN(co, 0.5f);
+ } else {
+ int numFaces = 0;
+ VertDataCopy(q, VERT_getCo(e->v0, curLvl));
+ VertDataAdd(q, VERT_getCo(e->v1, curLvl));
+ for (i=0; i<e->numFaces; i++) {
+ CCGFace *f = e->faces[i];
+ VertDataAdd(q, FACE_getCenterData(f));
+ numFaces++;
+ }
+ VertDataMulN(q, 1.0f/(2.0f+numFaces));
+
+ VertDataCopy(r, VERT_getCo(e->v0, curLvl));
+ VertDataAdd(r, VERT_getCo(e->v1, curLvl));
+ VertDataMulN(r, 0.5f);
+
+ VertDataCopy(co, q);
+ VertDataSub(r, q);
+ VertDataMulN(r, sharpness);
+ VertDataAdd(co, r);
+ }
+
+ // edge flags cleared later
+ }
+ for (ptrIdx=0; ptrIdx<numEffectedV; ptrIdx++) {
+ CCGVert *v = effectedV[ptrIdx];
+ void *co = VERT_getCo(v, curLvl);
+ void *nCo = VERT_getCo(v, nextLvl);
+ int sharpCount = 0, allSharp = 1;
+ float avgSharpness = 0.0;
+ int seam = VERT_seam(v, ss), seamEdges = 0;
+
+ for (i=0; i<v->numEdges; i++) {
+ CCGEdge *e = v->edges[i];
+ float sharpness = EDGE_getSharpness(e, curLvl);
+
+ if (seam && _edge_isBoundary(e))
+ seamEdges++;
+
+ if (sharpness!=0.0f) {
+ sharpCount++;
+ avgSharpness += sharpness;
+ } else {
+ allSharp = 0;
+ }
+ }
+
+ avgSharpness /= sharpCount;
+ if (avgSharpness>1.0) {
+ avgSharpness = 1.0;
+ }
+
+ if (seam && seamEdges < 2)
+ seam = 0;
+
+ if (!v->numEdges) {
+ VertDataCopy(nCo, co);
+ } else if (_vert_isBoundary(v)) {
+ int numBoundary = 0;
+
+ VertDataZero(r);
+ for (i=0; i<v->numEdges; i++) {
+ CCGEdge *e = v->edges[i];
+ if (_edge_isBoundary(e)) {
+ VertDataAdd(r, VERT_getCo(_edge_getOtherVert(e, v), curLvl));
+ numBoundary++;
+ }
+ }
+ VertDataCopy(nCo, co);
+ VertDataMulN(nCo, 0.75);
+ VertDataMulN(r, 0.25f/numBoundary);
+ VertDataAdd(nCo, r);
+ } else {
+ int numEdges = 0, numFaces = 0;
+
+ VertDataZero(q);
+ for (i=0; i<v->numFaces; i++) {
+ CCGFace *f = v->faces[i];
+ VertDataAdd(q, FACE_getCenterData(f));
+ numFaces++;
+ }
+ VertDataMulN(q, 1.0f/numFaces);
+ VertDataZero(r);
+ for (i=0; i<v->numEdges; i++) {
+ CCGEdge *e = v->edges[i];
+ VertDataAdd(r, VERT_getCo(_edge_getOtherVert(e, v), curLvl));
+ numEdges++;
+ }
+ VertDataMulN(r, 1.0f/numEdges);
+
+ VertDataCopy(nCo, co);
+ VertDataMulN(nCo, numEdges-2.0f);
+ VertDataAdd(nCo, q);
+ VertDataAdd(nCo, r);
+ VertDataMulN(nCo, 1.0f/numEdges);
+ }
+
+ if ((sharpCount>1 && v->numFaces) || seam) {
+ VertDataZero(q);
+
+ if (seam) {
+ avgSharpness = 1.0f;
+ sharpCount = seamEdges;
+ allSharp = 1;
+ }
+
+ for (i=0; i<v->numEdges; i++) {
+ CCGEdge *e = v->edges[i];
+ float sharpness = EDGE_getSharpness(e, curLvl);
+
+ if (seam) {
+ if (_edge_isBoundary(e)) {
+ CCGVert *oV = _edge_getOtherVert(e, v);
+ VertDataAdd(q, VERT_getCo(oV, curLvl));
+ }
+ } else if (sharpness != 0.0) {
+ CCGVert *oV = _edge_getOtherVert(e, v);
+ VertDataAdd(q, VERT_getCo(oV, curLvl));
+ }
+ }
+
+ VertDataMulN(q, (float) 1/sharpCount);
+
+ if (sharpCount!=2 || allSharp) {
+ // q = q + (co-q)*avgSharpness
+ VertDataCopy(r, co);
+ VertDataSub(r, q);
+ VertDataMulN(r, avgSharpness);
+ VertDataAdd(q, r);
+ }
+
+ // r = co*.75 + q*.25
+ VertDataCopy(r, co);
+ VertDataMulN(r, .75);
+ VertDataMulN(q, .25);
+ VertDataAdd(r, q);
+
+ // nCo = nCo + (r-nCo)*avgSharpness
+ VertDataSub(r, nCo);
+ VertDataMulN(r, avgSharpness);
+ VertDataAdd(nCo, r);
+ }
+
+ // vert flags cleared later
+ }
+
+ if (ss->useAgeCounts) {
+ for (i=0; i<numEffectedV; i++) {
+ CCGVert *v = effectedV[i];
+ byte *userData = ccgSubSurf_getVertUserData(ss, v);
+ *((int*) &userData[ss->vertUserAgeOffset]) = ss->currentAge;
+ }
+
+ for (i=0; i<numEffectedE; i++) {
+ CCGEdge *e = effectedE[i];
+ byte *userData = ccgSubSurf_getEdgeUserData(ss, e);
+ *((int*) &userData[ss->edgeUserAgeOffset]) = ss->currentAge;
+ }
+
+ for (i=0; i<numEffectedF; i++) {
+ CCGFace *f = effectedF[i];
+ byte *userData = ccgSubSurf_getFaceUserData(ss, f);
+ *((int*) &userData[ss->faceUserAgeOffset]) = ss->currentAge;
+ }
+ }
+
+ for (i=0; i<numEffectedE; i++) {
+ CCGEdge *e = effectedE[i];
+ VertDataCopy(EDGE_getCo(e, nextLvl, 0), VERT_getCo(e->v0, nextLvl));
+ VertDataCopy(EDGE_getCo(e, nextLvl, 2), VERT_getCo(e->v1, nextLvl));
+ }
+ for (i=0; i<numEffectedF; i++) {
+ CCGFace *f = effectedF[i];
+ for (S=0; S<f->numVerts; S++) {
+ CCGEdge *e = FACE_getEdges(f)[S];
+ CCGEdge *prevE = FACE_getEdges(f)[(S+f->numVerts-1)%f->numVerts];
+
+ VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 0), FACE_getCenterData(f));
+ VertDataCopy(FACE_getIECo(f, nextLvl, S, 0), FACE_getCenterData(f));
+ VertDataCopy(FACE_getIFCo(f, nextLvl, S, 1, 1), VERT_getCo(FACE_getVerts(f)[S], nextLvl));
+ VertDataCopy(FACE_getIECo(f, nextLvl, S, 1), EDGE_getCo(FACE_getEdges(f)[S], nextLvl, 1));
+
+ VertDataCopy(FACE_getIFCo(f, nextLvl, S, 1, 0), _edge_getCoVert(e, FACE_getVerts(f)[S], nextLvl, 1, vertDataSize));
+ VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 1), _edge_getCoVert(prevE, FACE_getVerts(f)[S], nextLvl, 1, vertDataSize));
+ }
+ }
+
+ for (curLvl=1; curLvl<subdivLevels; curLvl++) {
+ int edgeSize = 1 + (1<<curLvl);
+ int gridSize = 1 + (1<<(curLvl-1));
+ nextLvl = curLvl+1;
+
+ for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) {
+ CCGFace *f = (CCGFace*) effectedF[ptrIdx];
+
+ /* interior face midpoints
+ * o old interior face points
+ */
+ for (S=0; S<f->numVerts; S++) {
+ for (y=0; y<gridSize-1; y++) {
+ for (x=0; x<gridSize-1; x++) {
+ int fx = 1 + 2*x;
+ int fy = 1 + 2*y;
+ void *co0 = FACE_getIFCo(f, curLvl, S, x+0, y+0);
+ void *co1 = FACE_getIFCo(f, curLvl, S, x+1, y+0);
+ void *co2 = FACE_getIFCo(f, curLvl, S, x+1, y+1);
+ void *co3 = FACE_getIFCo(f, curLvl, S, x+0, y+1);
+ void *co = FACE_getIFCo(f, nextLvl, S, fx, fy);
+
+ VertDataAvg4(co, co0, co1, co2, co3);
+ }
+ }
+ }
+
+ /* interior edge midpoints
+ * o old interior edge points
+ * o new interior face midpoints
+ */
+ for (S=0; S<f->numVerts; S++) {
+ for (x=0; x<gridSize-1; x++) {
+ int fx = x*2 + 1;
+ void *co0 = FACE_getIECo(f, curLvl, S, x+0);
+ void *co1 = FACE_getIECo(f, curLvl, S, x+1);
+ void *co2 = FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx);
+ void *co3 = FACE_getIFCo(f, nextLvl, S, fx, 1);
+ void *co = FACE_getIECo(f, nextLvl, S, fx);
+
+ VertDataAvg4(co, co0, co1, co2, co3);
+ }
+
+ /* interior face interior edge midpoints
+ * o old interior face points
+ * o new interior face midpoints
+ */
+
+ /* vertical */
+ for (x=1; x<gridSize-1; x++) {
+ for (y=0; y<gridSize-1; y++) {
+ int fx = x*2;
+ int fy = y*2+1;
+ void *co0 = FACE_getIFCo(f, curLvl, S, x, y+0);
+ void *co1 = FACE_getIFCo(f, curLvl, S, x, y+1);
+ void *co2 = FACE_getIFCo(f, nextLvl, S, fx-1, fy);
+ void *co3 = FACE_getIFCo(f, nextLvl, S, fx+1, fy);
+ void *co = FACE_getIFCo(f, nextLvl, S, fx, fy);
+
+ VertDataAvg4(co, co0, co1, co2, co3);
+ }
+ }
+
+ /* horizontal */
+ for (y=1; y<gridSize-1; y++) {
+ for (x=0; x<gridSize-1; x++) {
+ int fx = x*2+1;
+ int fy = y*2;
+ void *co0 = FACE_getIFCo(f, curLvl, S, x+0, y);
+ void *co1 = FACE_getIFCo(f, curLvl, S, x+1, y);
+ void *co2 = FACE_getIFCo(f, nextLvl, S, fx, fy-1);
+ void *co3 = FACE_getIFCo(f, nextLvl, S, fx, fy+1);
+ void *co = FACE_getIFCo(f, nextLvl, S, fx, fy);
+
+ VertDataAvg4(co, co0, co1, co2, co3);
+ }
+ }
+ }
+ }
+
+ /* exterior edge midpoints
+ * o old exterior edge points
+ * o new interior face midpoints
+ */
+ for (ptrIdx=0; ptrIdx<numEffectedE; ptrIdx++) {
+ CCGEdge *e = (CCGEdge*) effectedE[ptrIdx];
+ float sharpness = EDGE_getSharpness(e, curLvl);
+
+ if (_edge_isBoundary(e) || sharpness>1.0) {
+ for (x=0; x<edgeSize-1; x++) {
+ int fx = x*2 + 1;
+ void *co0 = EDGE_getCo(e, curLvl, x+0);
+ void *co1 = EDGE_getCo(e, curLvl, x+1);
+ void *co = EDGE_getCo(e, nextLvl, fx);
+
+ VertDataCopy(co, co0);
+ VertDataAdd(co, co1);
+ VertDataMulN(co, 0.5);
+ }
+ } else {
+ for (x=0; x<edgeSize-1; x++) {
+ int fx = x*2 + 1;
+ void *co0 = EDGE_getCo(e, curLvl, x+0);
+ void *co1 = EDGE_getCo(e, curLvl, x+1);
+ void *co = EDGE_getCo(e, nextLvl, fx);
+ int numFaces = 0;
+
+ VertDataCopy(q, co0);
+ VertDataAdd(q, co1);
+
+ for (i=0; i<e->numFaces; i++) {
+ CCGFace *f = e->faces[i];
+ VertDataAdd(q, _face_getIFCoEdge(f, e, nextLvl, fx, 1, subdivLevels, vertDataSize));
+ numFaces++;
+ }
+
+ VertDataMulN(q, 1.0f/(2.0f+numFaces));
+
+ VertDataCopy(r, co0);
+ VertDataAdd(r, co1);
+ VertDataMulN(r, 0.5);
+
+ VertDataCopy(co, q);
+ VertDataSub(r, q);
+ VertDataMulN(r, sharpness);
+ VertDataAdd(co, r);
+ }
+ }
+ }
+
+ /* exterior vertex shift
+ * o old vertex points (shifting)
+ * o old exterior edge points
+ * o new interior face midpoints
+ */
+ for (ptrIdx=0; ptrIdx<numEffectedV; ptrIdx++) {
+ CCGVert *v = (CCGVert*) effectedV[ptrIdx];
+ void *co = VERT_getCo(v, curLvl);
+ void *nCo = VERT_getCo(v, nextLvl);
+ int sharpCount = 0, allSharp = 1;
+ float avgSharpness = 0.0;
+ int seam = VERT_seam(v, ss), seamEdges = 0;
+
+ for (i=0; i<v->numEdges; i++) {
+ CCGEdge *e = v->edges[i];
+ float sharpness = EDGE_getSharpness(e, curLvl);
+
+ if (seam && _edge_isBoundary(e))
+ seamEdges++;
+
+ if (sharpness!=0.0f) {
+ sharpCount++;
+ avgSharpness += sharpness;
+ } else {
+ allSharp = 0;
+ }
+ }
+
+ avgSharpness /= sharpCount;
+ if (avgSharpness>1.0) {
+ avgSharpness = 1.0;
+ }
+
+ if (seam && seamEdges < 2)
+ seam = 0;
+
+ if (!v->numEdges) {
+ VertDataCopy(nCo, co);
+ } else if (_vert_isBoundary(v)) {
+ int numBoundary = 0;
+
+ VertDataZero(r);
+ for (i=0; i<v->numEdges; i++) {
+ CCGEdge *e = v->edges[i];
+ if (_edge_isBoundary(e)) {
+ VertDataAdd(r, _edge_getCoVert(e, v, curLvl, 1, vertDataSize));
+ numBoundary++;
+ }
+ }
+
+ VertDataCopy(nCo, co);
+ VertDataMulN(nCo, 0.75);
+ VertDataMulN(r, 0.25f/numBoundary);
+ VertDataAdd(nCo, r);
+ } else {
+ int cornerIdx = (1 + (1<<(curLvl))) - 2;
+ int numEdges = 0, numFaces = 0;
+
+ VertDataZero(q);
+ for (i=0; i<v->numFaces; i++) {
+ CCGFace *f = v->faces[i];
+ VertDataAdd(q, FACE_getIFCo(f, nextLvl, _face_getVertIndex(f,v), cornerIdx, cornerIdx));
+ numFaces++;
+ }
+ VertDataMulN(q, 1.0f/numFaces);
+ VertDataZero(r);
+ for (i=0; i<v->numEdges; i++) {
+ CCGEdge *e = v->edges[i];
+ VertDataAdd(r, _edge_getCoVert(e, v, curLvl, 1,vertDataSize));
+ numEdges++;
+ }
+ VertDataMulN(r, 1.0f/numEdges);
+
+ VertDataCopy(nCo, co);
+ VertDataMulN(nCo, numEdges-2.0f);
+ VertDataAdd(nCo, q);
+ VertDataAdd(nCo, r);
+ VertDataMulN(nCo, 1.0f/numEdges);
+ }
+
+ if ((sharpCount>1 && v->numFaces) || seam) {
+ VertDataZero(q);
+
+ if (seam) {
+ avgSharpness = 1.0f;
+ sharpCount = seamEdges;
+ allSharp = 1;
+ }
+
+ for (i=0; i<v->numEdges; i++) {
+ CCGEdge *e = v->edges[i];
+ float sharpness = EDGE_getSharpness(e, curLvl);
+
+ if (seam) {
+ if (_edge_isBoundary(e))
+ VertDataAdd(q, _edge_getCoVert(e, v, curLvl, 1, vertDataSize));
+ } else if (sharpness != 0.0) {
+ VertDataAdd(q, _edge_getCoVert(e, v, curLvl, 1, vertDataSize));
+ }
+ }
+
+ VertDataMulN(q, (float) 1/sharpCount);
+
+ if (sharpCount!=2 || allSharp) {
+ // q = q + (co-q)*avgSharpness
+ VertDataCopy(r, co);
+ VertDataSub(r, q);
+ VertDataMulN(r, avgSharpness);
+ VertDataAdd(q, r);
+ }
+
+ // r = co*.75 + q*.25
+ VertDataCopy(r, co);
+ VertDataMulN(r, .75);
+ VertDataMulN(q, .25);
+ VertDataAdd(r, q);
+
+ // nCo = nCo + (r-nCo)*avgSharpness
+ VertDataSub(r, nCo);
+ VertDataMulN(r, avgSharpness);
+ VertDataAdd(nCo, r);
+ }
+ }
+
+ /* exterior edge interior shift
+ * o old exterior edge midpoints (shifting)
+ * o old exterior edge midpoints
+ * o new interior face midpoints
+ */
+ for (ptrIdx=0; ptrIdx<numEffectedE; ptrIdx++) {
+ CCGEdge *e = (CCGEdge*) effectedE[ptrIdx];
+ float sharpness = EDGE_getSharpness(e, curLvl);
+ int sharpCount = 0;
+ float avgSharpness = 0.0;
+
+ if (sharpness!=0.0f) {
+ sharpCount = 2;
+ avgSharpness += sharpness;
+
+ if (avgSharpness>1.0) {
+ avgSharpness = 1.0;
+ }
+ } else {
+ sharpCount = 0;
+ avgSharpness = 0;
+ }
+
+ if (_edge_isBoundary(e) && (!e->numFaces || sharpCount<2)) {
+ for (x=1; x<edgeSize-1; x++) {
+ int fx = x*2;
+ void *co = EDGE_getCo(e, curLvl, x);
+ void *nCo = EDGE_getCo(e, nextLvl, fx);
+ VertDataCopy(r, EDGE_getCo(e, curLvl, x-1));
+ VertDataAdd(r, EDGE_getCo(e, curLvl, x+1));
+ VertDataMulN(r, 0.5);
+ VertDataCopy(nCo, co);
+ VertDataMulN(nCo, 0.75);
+ VertDataMulN(r, 0.25);
+ VertDataAdd(nCo, r);
+ }
+ } else {
+ for (x=1; x<edgeSize-1; x++) {
+ int fx = x*2;
+ void *co = EDGE_getCo(e, curLvl, x);
+ void *nCo = EDGE_getCo(e, nextLvl, fx);
+ int numFaces = 0;
+
+ VertDataZero(q);
+ VertDataZero(r);
+ VertDataAdd(r, EDGE_getCo(e, curLvl, x-1));
+ VertDataAdd(r, EDGE_getCo(e, curLvl, x+1));
+ for (i=0; i<e->numFaces; i++) {
+ CCGFace *f = e->faces[i];
+ VertDataAdd(q, _face_getIFCoEdge(f, e, nextLvl, fx-1, 1, subdivLevels, vertDataSize));
+ VertDataAdd(q, _face_getIFCoEdge(f, e, nextLvl, fx+1, 1, subdivLevels, vertDataSize));
+
+ VertDataAdd(r, _face_getIFCoEdge(f, e, curLvl, x, 1, subdivLevels, vertDataSize));
+ numFaces++;
+ }
+ VertDataMulN(q, 1.0/(numFaces*2.0f));
+ VertDataMulN(r, 1.0/(2.0f + numFaces));
+
+ VertDataCopy(nCo, co);
+ VertDataMulN(nCo, (float) numFaces);
+ VertDataAdd(nCo, q);
+ VertDataAdd(nCo, r);
+ VertDataMulN(nCo, 1.0f/(2+numFaces));
+
+ if (sharpCount==2) {
+ VertDataCopy(q, co);
+ VertDataMulN(q, 6.0f);
+ VertDataAdd(q, EDGE_getCo(e, curLvl, x-1));
+ VertDataAdd(q, EDGE_getCo(e, curLvl, x+1));
+ VertDataMulN(q, 1/8.0f);
+
+ VertDataSub(q, nCo);
+ VertDataMulN(q, avgSharpness);
+ VertDataAdd(nCo, q);
+ }
+ }
+ }
+ }
+
+ for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) {
+ CCGFace *f = (CCGFace*) effectedF[ptrIdx];
+
+ /* interior center point shift
+ * o old face center point (shifting)
+ * o old interior edge points
+ * o new interior face midpoints
+ */
+ VertDataZero(q);
+ for (S=0; S<f->numVerts; S++) {
+ VertDataAdd(q, FACE_getIFCo(f, nextLvl, S, 1, 1));
+ }
+ VertDataMulN(q, 1.0f/f->numVerts);
+ VertDataZero(r);
+ for (S=0; S<f->numVerts; S++) {
+ VertDataAdd(r, FACE_getIECo(f, curLvl, S, 1));
+ }
+ VertDataMulN(r, 1.0f/f->numVerts);
+
+ VertDataMulN(FACE_getCenterData(f), f->numVerts-2.0f);
+ VertDataAdd(FACE_getCenterData(f), q);
+ VertDataAdd(FACE_getCenterData(f), r);
+ VertDataMulN(FACE_getCenterData(f), 1.0f/f->numVerts);
+
+ for (S=0; S<f->numVerts; S++) {
+ /* interior face shift
+ * o old interior face point (shifting)
+ * o new interior edge midpoints
+ * o new interior face midpoints
+ */
+ for (x=1; x<gridSize-1; x++) {
+ for (y=1; y<gridSize-1; y++) {
+ int fx = x*2;
+ int fy = y*2;
+ void *co = FACE_getIFCo(f, curLvl, S, x, y);
+ void *nCo = FACE_getIFCo(f, nextLvl, S, fx, fy);
+
+ VertDataAvg4(q, FACE_getIFCo(f, nextLvl, S, fx-1, fy-1),
+ FACE_getIFCo(f, nextLvl, S, fx+1, fy-1),
+ FACE_getIFCo(f, nextLvl, S, fx+1, fy+1),
+ FACE_getIFCo(f, nextLvl, S, fx-1, fy+1));
+
+ VertDataAvg4(r, FACE_getIFCo(f, nextLvl, S, fx-1, fy+0),
+ FACE_getIFCo(f, nextLvl, S, fx+1, fy+0),
+ FACE_getIFCo(f, nextLvl, S, fx+0, fy-1),
+ FACE_getIFCo(f, nextLvl, S, fx+0, fy+1));
+
+ VertDataCopy(nCo, co);
+ VertDataSub(nCo, q);
+ VertDataMulN(nCo, 0.25f);
+ VertDataAdd(nCo, r);
+ }
+ }
+
+ /* interior edge interior shift
+ * o old interior edge point (shifting)
+ * o new interior edge midpoints
+ * o new interior face midpoints
+ */
+ for (x=1; x<gridSize-1; x++) {
+ int fx = x*2;
+ void *co = FACE_getIECo(f, curLvl, S, x);
+ void *nCo = FACE_getIECo(f, nextLvl, S, fx);
+
+ VertDataAvg4(q, FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx-1),
+ FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx+1),
+ FACE_getIFCo(f, nextLvl, S, fx+1, +1),
+ FACE_getIFCo(f, nextLvl, S, fx-1, +1));
+
+ VertDataAvg4(r, FACE_getIECo(f, nextLvl, S, fx-1),
+ FACE_getIECo(f, nextLvl, S, fx+1),
+ FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx),
+ FACE_getIFCo(f, nextLvl, S, fx, 1));
+
+ VertDataCopy(nCo, co);
+ VertDataSub(nCo, q);
+ VertDataMulN(nCo, 0.25f);
+ VertDataAdd(nCo, r);
+ }
+ }
+ }
+
+ /* copy down */
+ edgeSize = 1 + (1<<(nextLvl));
+ gridSize = 1 + (1<<((nextLvl)-1));
+ cornerIdx = gridSize-1;
+ for (i=0; i<numEffectedE; i++) {
+ CCGEdge *e = effectedE[i];
+ VertDataCopy(EDGE_getCo(e, nextLvl, 0), VERT_getCo(e->v0, nextLvl));
+ VertDataCopy(EDGE_getCo(e, nextLvl, edgeSize-1), VERT_getCo(e->v1, nextLvl));
+ }
+ for (i=0; i<numEffectedF; i++) {
+ CCGFace *f = effectedF[i];
+ for (S=0; S<f->numVerts; S++) {
+ CCGEdge *e = FACE_getEdges(f)[S];
+ CCGEdge *prevE = FACE_getEdges(f)[(S+f->numVerts-1)%f->numVerts];
+
+ VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 0), FACE_getCenterData(f));
+ VertDataCopy(FACE_getIECo(f, nextLvl, S, 0), FACE_getCenterData(f));
+ VertDataCopy(FACE_getIFCo(f, nextLvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], nextLvl));
+ VertDataCopy(FACE_getIECo(f, nextLvl, S, cornerIdx), EDGE_getCo(FACE_getEdges(f)[S], nextLvl, cornerIdx));
+ for (x=1; x<gridSize-1; x++) {
+ void *co = FACE_getIECo(f, nextLvl, S, x);
+ VertDataCopy(FACE_getIFCo(f, nextLvl, S, x, 0), co);
+ VertDataCopy(FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 0, x), co);
+ }
+ for (x=0; x<gridSize-1; x++) {
+ int eI = gridSize-1-x;
+ VertDataCopy(FACE_getIFCo(f, nextLvl, S, cornerIdx, x), _edge_getCoVert(e, FACE_getVerts(f)[S], nextLvl, eI,vertDataSize));
+ VertDataCopy(FACE_getIFCo(f, nextLvl, S, x, cornerIdx), _edge_getCoVert(prevE, FACE_getVerts(f)[S], nextLvl, eI,vertDataSize));
+ }
+ }
+ }
+ }
+
+#define FACE_getIFNo(f, lvl, S, x, y) _face_getIFNo(f, lvl, S, x, y, subdivLevels, vertDataSize, normalDataOffset)
+#define FACE_calcIFNo(f, lvl, S, x, y, no) _face_calcIFNo(f, lvl, S, x, y, no, subdivLevels, vertDataSize)
+ if (ss->calcVertNormals) {
+ int lvl = ss->subdivLevels;
+ int edgeSize = 1 + (1<<lvl);
+ int gridSize = 1 + (1<<(lvl-1));
+ int normalDataOffset = ss->normalDataOffset;
+
+ for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) {
+ CCGFace *f = (CCGFace*) effectedF[ptrIdx];
+ int S, x, y;
+
+ for (S=0; S<f->numVerts; S++) {
+ for (y=0; y<gridSize-1; y++)
+ for (x=0; x<gridSize-1; x++)
+ NormZero(FACE_getIFNo(f, lvl, S, x, y));
+
+ if (FACE_getEdges(f)[(S-1+f->numVerts)%f->numVerts]->flags&Edge_eEffected)
+ for (x=0; x<gridSize-1; x++)
+ NormZero(FACE_getIFNo(f, lvl, S, x, gridSize-1));
+ if (FACE_getEdges(f)[S]->flags&Edge_eEffected)
+ for (y=0; y<gridSize-1; y++)
+ NormZero(FACE_getIFNo(f, lvl, S, gridSize-1, y));
+ if (FACE_getVerts(f)[S]->flags&Vert_eEffected)
+ NormZero(FACE_getIFNo(f, lvl, S, gridSize-1, gridSize-1));
+ }
+ }
+
+ for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) {
+ CCGFace *f = (CCGFace*) effectedF[ptrIdx];
+ int S, x, y;
+ float no[3];
+
+ for (S=0; S<f->numVerts; S++) {
+ int yLimit = !(FACE_getEdges(f)[(S-1+f->numVerts)%f->numVerts]->flags&Edge_eEffected);
+ int xLimit = !(FACE_getEdges(f)[S]->flags&Edge_eEffected);
+ int yLimitNext = xLimit;
+ int xLimitPrev = yLimit;
+
+ for (y=0; y<gridSize - 1; y++) {
+ for (x=0; x<gridSize - 1; x++) {
+ int xPlusOk = (!xLimit || x<gridSize-2);
+ int yPlusOk = (!yLimit || y<gridSize-2);
+
+ FACE_calcIFNo(f, lvl, S, x, y, no);
+
+ NormAdd(FACE_getIFNo(f, lvl, S, x+0, y+0), no);
+ if (xPlusOk)
+ NormAdd(FACE_getIFNo(f, lvl, S, x+1, y+0), no);
+ if (yPlusOk)
+ NormAdd(FACE_getIFNo(f, lvl, S, x+0, y+1), no);
+ if (xPlusOk && yPlusOk) {
+ if (x<gridSize-2 || y<gridSize-2 || FACE_getVerts(f)[S]->flags&Vert_eEffected) {
+ NormAdd(FACE_getIFNo(f, lvl, S, x+1, y+1), no);
+ }
+ }
+
+ if (x==0 && y==0) {
+ int K;
+
+ if (!yLimitNext || 1<gridSize-1)
+ NormAdd(FACE_getIFNo(f, lvl, (S+1)%f->numVerts, 0, 1), no);
+ if (!xLimitPrev || 1<gridSize-1)
+ NormAdd(FACE_getIFNo(f, lvl, (S-1+f->numVerts)%f->numVerts, 1, 0), no);
+
+ for (K=0; K<f->numVerts; K++) {
+ if (K!=S) {
+ NormAdd(FACE_getIFNo(f, lvl, K, 0, 0), no);
+ }
+ }
+ } else if (y==0) {
+ NormAdd(FACE_getIFNo(f, lvl, (S+1)%f->numVerts, 0, x), no);
+ if (!yLimitNext || x<gridSize-2)
+ NormAdd(FACE_getIFNo(f, lvl, (S+1)%f->numVerts, 0, x+1), no);
+ } else if (x==0) {
+ NormAdd(FACE_getIFNo(f, lvl, (S-1+f->numVerts)%f->numVerts, y, 0), no);
+ if (!xLimitPrev || y<gridSize-2)
+ NormAdd(FACE_getIFNo(f, lvl, (S-1+f->numVerts)%f->numVerts, y+1, 0), no);
+ }
+ }
+ }
+ }
+ }
+ // XXX can I reduce the number of normalisations here?
+ for (ptrIdx=0; ptrIdx<numEffectedV; ptrIdx++) {
+ CCGVert *v = (CCGVert*) effectedV[ptrIdx];
+ float length, *no = _vert_getNo(v, lvl, vertDataSize, normalDataOffset);
+
+ NormZero(no);
+
+ for (i=0; i<v->numFaces; i++) {
+ CCGFace *f = v->faces[i];
+ NormAdd(no, FACE_getIFNo(f, lvl, _face_getVertIndex(f,v), gridSize-1, gridSize-1));
+ }
+
+ length = sqrt(no[0]*no[0] + no[1]*no[1] + no[2]*no[2]);
+
+ if (length>FLT_EPSILON) {
+ float invLength = 1.0f/length;
+ no[0] *= invLength;
+ no[1] *= invLength;
+ no[2] *= invLength;
+ } else {
+ NormZero(no);
+ }
+
+ for (i=0; i<v->numFaces; i++) {
+ CCGFace *f = v->faces[i];
+ NormCopy(FACE_getIFNo(f, lvl, _face_getVertIndex(f,v), gridSize-1, gridSize-1), no);
+ }
+ }
+ for (ptrIdx=0; ptrIdx<numEffectedE; ptrIdx++) {
+ CCGEdge *e = (CCGEdge*) effectedE[ptrIdx];
+
+ if (e->numFaces) {
+ CCGFace *fLast = e->faces[e->numFaces-1];
+ int x;
+
+ for (i=0; i<e->numFaces-1; i++) {
+ CCGFace *f = e->faces[i];
+
+ for (x=1; x<edgeSize-1; x++) {
+ NormAdd(_face_getIFNoEdge(fLast, e, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset),
+ _face_getIFNoEdge(f, e, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset));
+ }
+ }
+
+ for (i=0; i<e->numFaces-1; i++) {
+ CCGFace *f = e->faces[i];
+
+ for (x=1; x<edgeSize-1; x++) {
+ NormCopy(_face_getIFNoEdge(f, e, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset),
+ _face_getIFNoEdge(fLast, e, lvl, x, 0, subdivLevels, vertDataSize, normalDataOffset));
+ }
+ }
+ }
+ }
+ for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) {
+ CCGFace *f = (CCGFace*) effectedF[ptrIdx];
+ int S;
+
+ for (S=0; S<f->numVerts; S++) {
+ NormCopy(FACE_getIFNo(f, lvl, (S+1)%f->numVerts, 0, gridSize-1),
+ FACE_getIFNo(f, lvl, S, gridSize-1, 0));
+ }
+ }
+ for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) {
+ CCGFace *f = (CCGFace*) effectedF[ptrIdx];
+ int S, x, y;
+
+ for (S=0; S<f->numVerts; S++) {
+ for (y=0; y<gridSize; y++) {
+ for (x=0; x<gridSize; x++) {
+ float *no = FACE_getIFNo(f, lvl, S, x, y);
+ float length = sqrt(no[0]*no[0] + no[1]*no[1] + no[2]*no[2]);
+
+ if (length>FLT_EPSILON) {
+ float invLength = 1.0f/length;
+ no[0] *= invLength;
+ no[1] *= invLength;
+ no[2] *= invLength;
+ } else {
+ NormZero(no);
+ }
+ }
+ }
+ }
+ }
+ }
+#undef FACE_getIFNo
+
+ for (ptrIdx=0; ptrIdx<numEffectedV; ptrIdx++) {
+ CCGVert *v = effectedV[ptrIdx];
+ v->flags = 0;
+ }
+ for (ptrIdx=0; ptrIdx<numEffectedE; ptrIdx++) {
+ CCGEdge *e = effectedE[ptrIdx];
+ e->flags = 0;
+ }
+
+#undef VERT_getCo
+#undef EDGE_getCo
+#undef FACE_getIECo
+#undef FACE_getIFCo
+
+ CCGSUBSURF_free(ss, effectedF);
+ CCGSUBSURF_free(ss, effectedE);
+ CCGSUBSURF_free(ss, effectedV);
+}
+
+/*** External API accessor functions ***/
+
+int ccgSubSurf_getNumVerts(CCGSubSurf *ss) {
+ return ss->vMap->numEntries;
+}
+int ccgSubSurf_getNumEdges(CCGSubSurf *ss) {
+ return ss->eMap->numEntries;
+}
+int ccgSubSurf_getNumFaces(CCGSubSurf *ss) {
+ return ss->fMap->numEntries;
+}
+
+CCGVert *ccgSubSurf_getVert(CCGSubSurf *ss, CCGVertHDL v) {
+ return (CCGVert*) _ehash_lookup(ss->vMap, v);
+}
+CCGEdge *ccgSubSurf_getEdge(CCGSubSurf *ss, CCGEdgeHDL e) {
+ return (CCGEdge*) _ehash_lookup(ss->eMap, e);
+}
+CCGFace *ccgSubSurf_getFace(CCGSubSurf *ss, CCGFaceHDL f) {
+ return (CCGFace*) _ehash_lookup(ss->fMap, f);
+}
+
+int ccgSubSurf_getSubdivisionLevels(CCGSubSurf *ss) {
+ return ss->subdivLevels;
+}
+int ccgSubSurf_getEdgeSize(CCGSubSurf *ss) {
+ return ccgSubSurf_getEdgeLevelSize(ss, ss->subdivLevels);
+}
+int ccgSubSurf_getEdgeLevelSize(CCGSubSurf *ss, int level) {
+ if (level<1 || level>ss->subdivLevels) {
+ return -1;
+ } else {
+ return 1 + (1<<level);
+ }
+}
+int ccgSubSurf_getGridSize(CCGSubSurf *ss) {
+ return ccgSubSurf_getGridLevelSize(ss, ss->subdivLevels);
+}
+int ccgSubSurf_getGridLevelSize(CCGSubSurf *ss, int level) {
+ if (level<1 || level>ss->subdivLevels) {
+ return -1;
+ } else {
+ return 1 + (1<<(level-1));
+ }
+}
+
+/* Vert accessors */
+
+CCGVertHDL ccgSubSurf_getVertVertHandle(CCGSubSurf *ss, CCGVert *v) {
+ return v->vHDL;
+}
+int ccgSubSurf_getVertAge(CCGSubSurf *ss, CCGVert *v) {
+ if (ss->useAgeCounts) {
+ byte *userData = ccgSubSurf_getVertUserData(ss, v);
+ return ss->currentAge - *((int*) &userData[ss->vertUserAgeOffset]);
+ } else {
+ return 0;
+ }
+}
+void *ccgSubSurf_getVertUserData(CCGSubSurf *ss, CCGVert *v) {
+ return VERT_getLevelData(v) + ss->meshIFC.vertDataSize*(ss->subdivLevels+1);
+}
+int ccgSubSurf_getVertNumFaces(CCGSubSurf *ss, CCGVert *v) {
+ return v->numFaces;
+}
+CCGFace *ccgSubSurf_getVertFace(CCGSubSurf *ss, CCGVert *v, int index) {
+ if (index<0 || index>=v->numFaces) {
+ return NULL;
+ } else {
+ return v->faces[index];
+ }
+}
+int ccgSubSurf_getVertNumEdges(CCGSubSurf *ss, CCGVert *v) {
+ return v->numEdges;
+}
+CCGEdge *ccgSubSurf_getVertEdge(CCGSubSurf *ss, CCGVert *v, int index) {
+ if (index<0 || index>=v->numEdges) {
+ return NULL;
+ } else {
+ return v->edges[index];
+ }
+}
+void *ccgSubSurf_getVertData(CCGSubSurf *ss, CCGVert *v) {
+ return ccgSubSurf_getVertLevelData(ss, v, ss->subdivLevels);
+}
+void *ccgSubSurf_getVertLevelData(CCGSubSurf *ss, CCGVert *v, int level) {
+ if (level<0 || level>ss->subdivLevels) {
+ return NULL;
+ } else {
+ return _vert_getCo(v, level, ss->meshIFC.vertDataSize);
+ }
+}
+
+/* Edge accessors */
+
+CCGEdgeHDL ccgSubSurf_getEdgeEdgeHandle(CCGSubSurf *ss, CCGEdge *e) {
+ return e->eHDL;
+}
+int ccgSubSurf_getEdgeAge(CCGSubSurf *ss, CCGEdge *e) {
+ if (ss->useAgeCounts) {
+ byte *userData = ccgSubSurf_getEdgeUserData(ss, e);
+ return ss->currentAge - *((int*) &userData[ss->edgeUserAgeOffset]);
+ } else {
+ return 0;
+ }
+}
+void *ccgSubSurf_getEdgeUserData(CCGSubSurf *ss, CCGEdge *e) {
+ return EDGE_getLevelData(e) + ss->meshIFC.vertDataSize *((ss->subdivLevels+1) + (1<<(ss->subdivLevels+1))-1);
+}
+int ccgSubSurf_getEdgeNumFaces(CCGSubSurf *ss, CCGEdge *e) {
+ return e->numFaces;
+}
+CCGFace *ccgSubSurf_getEdgeFace(CCGSubSurf *ss, CCGEdge *e, int index) {
+ if (index<0 || index>=e->numFaces) {
+ return NULL;
+ } else {
+ return e->faces[index];
+ }
+}
+CCGVert *ccgSubSurf_getEdgeVert0(CCGSubSurf *ss, CCGEdge *e) {
+ return e->v0;
+}
+CCGVert *ccgSubSurf_getEdgeVert1(CCGSubSurf *ss, CCGEdge *e) {
+ return e->v1;
+}
+void *ccgSubSurf_getEdgeDataArray(CCGSubSurf *ss, CCGEdge *e) {
+ return ccgSubSurf_getEdgeData(ss, e, 0);
+}
+void *ccgSubSurf_getEdgeData(CCGSubSurf *ss, CCGEdge *e, int x) {
+ return ccgSubSurf_getEdgeLevelData(ss, e, x, ss->subdivLevels);
+}
+void *ccgSubSurf_getEdgeLevelData(CCGSubSurf *ss, CCGEdge *e, int x, int level) {
+ if (level<0 || level>ss->subdivLevels) {
+ return NULL;
+ } else {
+ return _edge_getCo(e, level, x, ss->meshIFC.vertDataSize);
+ }
+}
+float ccgSubSurf_getEdgeCrease(CCGSubSurf *ss, CCGEdge *e) {
+ return e->crease;
+}
+
+/* Face accessors */
+
+CCGFaceHDL ccgSubSurf_getFaceFaceHandle(CCGSubSurf *ss, CCGFace *f) {
+ return f->fHDL;
+}
+int ccgSubSurf_getFaceAge(CCGSubSurf *ss, CCGFace *f) {
+ if (ss->useAgeCounts) {
+ byte *userData = ccgSubSurf_getFaceUserData(ss, f);
+ return ss->currentAge - *((int*) &userData[ss->faceUserAgeOffset]);
+ } else {
+ return 0;
+ }
+}
+void *ccgSubSurf_getFaceUserData(CCGSubSurf *ss, CCGFace *f) {
+ int maxGridSize = 1 + (1<<(ss->subdivLevels-1));
+ return FACE_getCenterData(f) + ss->meshIFC.vertDataSize *(1 + f->numVerts*maxGridSize + f->numVerts*maxGridSize*maxGridSize);
+}
+int ccgSubSurf_getFaceNumVerts(CCGSubSurf *ss, CCGFace *f) {
+ return f->numVerts;
+}
+CCGVert *ccgSubSurf_getFaceVert(CCGSubSurf *ss, CCGFace *f, int index) {
+ if (index<0 || index>=f->numVerts) {
+ return NULL;
+ } else {
+ return FACE_getVerts(f)[index];
+ }
+}
+CCGEdge *ccgSubSurf_getFaceEdge(CCGSubSurf *ss, CCGFace *f, int index) {
+ if (index<0 || index>=f->numVerts) {
+ return NULL;
+ } else {
+ return FACE_getEdges(f)[index];
+ }
+}
+int ccgSubSurf_getFaceEdgeIndex(CCGSubSurf *ss, CCGFace *f, CCGEdge *e) {
+ int i;
+
+ for (i=0; i<f->numVerts; i++)
+ if (FACE_getEdges(f)[i]==e)
+ return i;
+
+ return -1;
+}
+void *ccgSubSurf_getFaceCenterData(CCGSubSurf *ss, CCGFace *f) {
+ return FACE_getCenterData(f);
+}
+void *ccgSubSurf_getFaceGridEdgeDataArray(CCGSubSurf *ss, CCGFace *f, int gridIndex) {
+ return ccgSubSurf_getFaceGridEdgeData(ss, f, gridIndex, 0);
+}
+void *ccgSubSurf_getFaceGridEdgeData(CCGSubSurf *ss, CCGFace *f, int gridIndex, int x) {
+ return _face_getIECo(f, ss->subdivLevels, gridIndex, x, ss->subdivLevels, ss->meshIFC.vertDataSize);
+}
+void *ccgSubSurf_getFaceGridDataArray(CCGSubSurf *ss, CCGFace *f, int gridIndex) {
+ return ccgSubSurf_getFaceGridData(ss, f, gridIndex, 0, 0);
+}
+void *ccgSubSurf_getFaceGridData(CCGSubSurf *ss, CCGFace *f, int gridIndex, int x, int y) {
+ return _face_getIFCo(f, ss->subdivLevels, gridIndex, x, y, ss->subdivLevels, ss->meshIFC.vertDataSize);
+}
+
+/*** External API iterator functions ***/
+
+CCGVertIterator *ccgSubSurf_getVertIterator(CCGSubSurf *ss) {
+ return (CCGVertIterator*) _ehashIterator_new(ss->vMap);
+}
+CCGEdgeIterator *ccgSubSurf_getEdgeIterator(CCGSubSurf *ss) {
+ return (CCGEdgeIterator*) _ehashIterator_new(ss->eMap);
+}
+CCGFaceIterator *ccgSubSurf_getFaceIterator(CCGSubSurf *ss) {
+ return (CCGFaceIterator*) _ehashIterator_new(ss->fMap);
+}
+
+CCGVert *ccgVertIterator_getCurrent(CCGVertIterator *vi) {
+ return (CCGVert*) _ehashIterator_getCurrent((EHashIterator*) vi);
+}
+int ccgVertIterator_isStopped(CCGVertIterator *vi) {
+ return _ehashIterator_isStopped((EHashIterator*) vi);
+}
+void ccgVertIterator_next(CCGVertIterator *vi) {
+ _ehashIterator_next((EHashIterator*) vi);
+}
+void ccgVertIterator_free(CCGVertIterator *vi) {
+ _ehashIterator_free((EHashIterator*) vi);
+}
+
+CCGEdge *ccgEdgeIterator_getCurrent(CCGEdgeIterator *vi) {
+ return (CCGEdge*) _ehashIterator_getCurrent((EHashIterator*) vi);
+}
+int ccgEdgeIterator_isStopped(CCGEdgeIterator *vi) {
+ return _ehashIterator_isStopped((EHashIterator*) vi);
+}
+void ccgEdgeIterator_next(CCGEdgeIterator *vi) {
+ _ehashIterator_next((EHashIterator*) vi);
+}
+void ccgEdgeIterator_free(CCGEdgeIterator *vi) {
+ _ehashIterator_free((EHashIterator*) vi);
+}
+
+CCGFace *ccgFaceIterator_getCurrent(CCGFaceIterator *vi) {
+ return (CCGFace*) _ehashIterator_getCurrent((EHashIterator*) vi);
+}
+int ccgFaceIterator_isStopped(CCGFaceIterator *vi) {
+ return _ehashIterator_isStopped((EHashIterator*) vi);
+}
+void ccgFaceIterator_next(CCGFaceIterator *vi) {
+ _ehashIterator_next((EHashIterator*) vi);
+}
+void ccgFaceIterator_free(CCGFaceIterator *vi) {
+ _ehashIterator_free((EHashIterator*) vi);
+}
+
+/*** Extern API final vert/edge/face interface ***/
+
+int ccgSubSurf_getNumFinalVerts(CCGSubSurf *ss) {
+ int edgeSize = 1 + (1<<ss->subdivLevels);
+ int gridSize = 1 + (1<<(ss->subdivLevels-1));
+ int numFinalVerts = ss->vMap->numEntries + ss->eMap->numEntries*(edgeSize-2) + ss->fMap->numEntries + ss->numGrids*((gridSize-2) + ((gridSize-2)*(gridSize-2)));
+ return numFinalVerts;
+}
+int ccgSubSurf_getNumFinalEdges(CCGSubSurf *ss) {
+ int edgeSize = 1 + (1<<ss->subdivLevels);
+ int gridSize = 1 + (1<<(ss->subdivLevels-1));
+ int numFinalEdges = ss->eMap->numEntries*(edgeSize-1) + ss->numGrids*((gridSize-1) + 2*((gridSize-2)*(gridSize-1)));
+ return numFinalEdges;
+}
+int ccgSubSurf_getNumFinalFaces(CCGSubSurf *ss) {
+ int gridSize = 1 + (1<<(ss->subdivLevels-1));
+ int numFinalFaces = ss->numGrids*((gridSize-1)*(gridSize-1));
+ return numFinalFaces;
+}
diff --git a/source/blender/blenkernel/intern/CCGSubSurf.h b/source/blender/blenkernel/intern/CCGSubSurf.h
new file mode 100644
index 00000000000..91f3ffab43b
--- /dev/null
+++ b/source/blender/blenkernel/intern/CCGSubSurf.h
@@ -0,0 +1,152 @@
+/* $Id$ */
+
+typedef void* CCGMeshHDL;
+typedef void* CCGVertHDL;
+typedef void* CCGEdgeHDL;
+typedef void* CCGFaceHDL;
+
+typedef struct _CCGVert CCGVert;
+typedef struct _CCGEdge CCGEdge;
+typedef struct _CCGFace CCGFace;
+
+typedef struct _CCGMeshIFC CCGMeshIFC;
+struct _CCGMeshIFC {
+ int vertUserSize, edgeUserSize, faceUserSize;
+
+ int vertDataSize;
+};
+
+/***/
+
+typedef void* CCGAllocatorHDL;
+
+typedef struct _CCGAllocatorIFC CCGAllocatorIFC;
+struct _CCGAllocatorIFC {
+ void* (*alloc) (CCGAllocatorHDL a, int numBytes);
+ void* (*realloc) (CCGAllocatorHDL a, void *ptr, int newSize, int oldSize);
+ void (*free) (CCGAllocatorHDL a, void *ptr);
+ void (*release) (CCGAllocatorHDL a);
+};
+
+/***/
+
+typedef enum {
+ eCCGError_None = 0,
+
+ eCCGError_InvalidSyncState,
+ eCCGError_InvalidValue,
+} CCGError;
+
+/***/
+
+typedef struct _CCGSubSurf CCGSubSurf;
+
+CCGSubSurf* ccgSubSurf_new (CCGMeshIFC *ifc, int subdivisionLevels, CCGAllocatorIFC *allocatorIFC, CCGAllocatorHDL allocator);
+void ccgSubSurf_free (CCGSubSurf *ss);
+
+CCGError ccgSubSurf_sync (CCGSubSurf *ss);
+
+CCGError ccgSubSurf_initFullSync (CCGSubSurf *ss);
+CCGError ccgSubSurf_initPartialSync (CCGSubSurf *ss);
+
+CCGError ccgSubSurf_syncVert (CCGSubSurf *ss, CCGVertHDL vHDL, void *vertData, int seam, CCGVert **v_r);
+CCGError ccgSubSurf_syncEdge (CCGSubSurf *ss, CCGEdgeHDL eHDL, CCGVertHDL e_vHDL0, CCGVertHDL e_vHDL1, float crease, CCGEdge **e_r);
+CCGError ccgSubSurf_syncFace (CCGSubSurf *ss, CCGFaceHDL fHDL, int numVerts, CCGVertHDL *vHDLs, CCGFace **f_r);
+
+CCGError ccgSubSurf_syncVertDel (CCGSubSurf *ss, CCGVertHDL vHDL);
+CCGError ccgSubSurf_syncEdgeDel (CCGSubSurf *ss, CCGEdgeHDL eHDL);
+CCGError ccgSubSurf_syncFaceDel (CCGSubSurf *ss, CCGFaceHDL fHDL);
+
+CCGError ccgSubSurf_processSync (CCGSubSurf *ss);
+
+CCGError ccgSubSurf_setSubdivisionLevels (CCGSubSurf *ss, int subdivisionLevels);
+
+CCGError ccgSubSurf_setAllowEdgeCreation (CCGSubSurf *ss, int allowEdgeCreation, float defaultCreaseValue, void *defaultUserData);
+void ccgSubSurf_getAllowEdgeCreation (CCGSubSurf *ss, int *allowEdgeCreation_r, float *defaultCreaseValue_r, void *defaultUserData_r);
+
+void ccgSubSurf_getUseAgeCounts (CCGSubSurf *ss, int *useAgeCounts_r, int *vertUserOffset_r, int *edgeUserOffset_r, int *faceUserOffset_r);
+CCGError ccgSubSurf_setUseAgeCounts (CCGSubSurf *ss, int useAgeCounts, int vertUserOffset, int edgeUserOffset, int faceUserOffset);
+
+CCGError ccgSubSurf_setCalcVertexNormals (CCGSubSurf *ss, int useVertNormals, int normalDataOffset);
+
+/***/
+
+int ccgSubSurf_getNumVerts (CCGSubSurf *ss);
+int ccgSubSurf_getNumEdges (CCGSubSurf *ss);
+int ccgSubSurf_getNumFaces (CCGSubSurf *ss);
+
+int ccgSubSurf_getSubdivisionLevels (CCGSubSurf *ss);
+int ccgSubSurf_getEdgeSize (CCGSubSurf *ss);
+int ccgSubSurf_getEdgeLevelSize (CCGSubSurf *ss, int level);
+int ccgSubSurf_getGridSize (CCGSubSurf *ss);
+int ccgSubSurf_getGridLevelSize (CCGSubSurf *ss, int level);
+
+CCGVert* ccgSubSurf_getVert (CCGSubSurf *ss, CCGVertHDL v);
+CCGVertHDL ccgSubSurf_getVertVertHandle (CCGSubSurf *ss, CCGVert *v);
+int ccgSubSurf_getVertNumFaces (CCGSubSurf *ss, CCGVert *v);
+CCGFace* ccgSubSurf_getVertFace (CCGSubSurf *ss, CCGVert *v, int index);
+int ccgSubSurf_getVertNumEdges (CCGSubSurf *ss, CCGVert *v);
+CCGEdge* ccgSubSurf_getVertEdge (CCGSubSurf *ss, CCGVert *v, int index);
+
+int ccgSubSurf_getVertAge (CCGSubSurf *ss, CCGVert *v);
+void* ccgSubSurf_getVertUserData (CCGSubSurf *ss, CCGVert *v);
+void* ccgSubSurf_getVertData (CCGSubSurf *ss, CCGVert *v);
+void* ccgSubSurf_getVertLevelData (CCGSubSurf *ss, CCGVert *v, int level);
+
+CCGEdge* ccgSubSurf_getEdge (CCGSubSurf *ss, CCGEdgeHDL e);
+CCGEdgeHDL ccgSubSurf_getEdgeEdgeHandle (CCGSubSurf *ss, CCGEdge *e);
+int ccgSubSurf_getEdgeNumFaces (CCGSubSurf *ss, CCGEdge *e);
+CCGFace* ccgSubSurf_getEdgeFace (CCGSubSurf *ss, CCGEdge *e, int index);
+CCGVert* ccgSubSurf_getEdgeVert0 (CCGSubSurf *ss, CCGEdge *e);
+CCGVert* ccgSubSurf_getEdgeVert1 (CCGSubSurf *ss, CCGEdge *e);
+float ccgSubSurf_getEdgeCrease (CCGSubSurf *ss, CCGEdge *e);
+
+int ccgSubSurf_getEdgeAge (CCGSubSurf *ss, CCGEdge *e);
+void* ccgSubSurf_getEdgeUserData (CCGSubSurf *ss, CCGEdge *e);
+void* ccgSubSurf_getEdgeDataArray (CCGSubSurf *ss, CCGEdge *e);
+void* ccgSubSurf_getEdgeData (CCGSubSurf *ss, CCGEdge *e, int x);
+void* ccgSubSurf_getEdgeLevelData (CCGSubSurf *ss, CCGEdge *e, int x, int level);
+
+CCGFace* ccgSubSurf_getFace (CCGSubSurf *ss, CCGFaceHDL f);
+CCGFaceHDL ccgSubSurf_getFaceFaceHandle (CCGSubSurf *ss, CCGFace *f);
+int ccgSubSurf_getFaceNumVerts (CCGSubSurf *ss, CCGFace *f);
+CCGVert* ccgSubSurf_getFaceVert (CCGSubSurf *ss, CCGFace *f, int index);
+CCGEdge* ccgSubSurf_getFaceEdge (CCGSubSurf *ss, CCGFace *f, int index);
+int ccgSubSurf_getFaceEdgeIndex (CCGSubSurf *ss, CCGFace *f, CCGEdge *e);
+
+int ccgSubSurf_getFaceAge (CCGSubSurf *ss, CCGFace *f);
+void* ccgSubSurf_getFaceUserData (CCGSubSurf *ss, CCGFace *f);
+void* ccgSubSurf_getFaceCenterData (CCGSubSurf *ss, CCGFace *f);
+void* ccgSubSurf_getFaceGridEdgeDataArray (CCGSubSurf *ss, CCGFace *f, int gridIndex);
+void* ccgSubSurf_getFaceGridEdgeData (CCGSubSurf *ss, CCGFace *f, int gridIndex, int x);
+void* ccgSubSurf_getFaceGridDataArray (CCGSubSurf *ss, CCGFace *f, int gridIndex);
+void* ccgSubSurf_getFaceGridData (CCGSubSurf *ss, CCGFace *f, int gridIndex, int x, int y);
+
+int ccgSubSurf_getNumFinalVerts (CCGSubSurf *ss);
+int ccgSubSurf_getNumFinalEdges (CCGSubSurf *ss);
+int ccgSubSurf_getNumFinalFaces (CCGSubSurf *ss);
+
+/***/
+
+typedef struct _CCGVertIterator CCGVertIterator;
+typedef struct _CCGEdgeIterator CCGEdgeIterator;
+typedef struct _CCGFaceIterator CCGFaceIterator;
+
+CCGVertIterator* ccgSubSurf_getVertIterator (CCGSubSurf *ss);
+CCGEdgeIterator* ccgSubSurf_getEdgeIterator (CCGSubSurf *ss);
+CCGFaceIterator* ccgSubSurf_getFaceIterator (CCGSubSurf *ss);
+
+CCGVert* ccgVertIterator_getCurrent (CCGVertIterator *vi);
+int ccgVertIterator_isStopped (CCGVertIterator *vi);
+void ccgVertIterator_next (CCGVertIterator *vi);
+void ccgVertIterator_free (CCGVertIterator *vi);
+
+CCGEdge* ccgEdgeIterator_getCurrent (CCGEdgeIterator *ei);
+int ccgEdgeIterator_isStopped (CCGEdgeIterator *ei);
+void ccgEdgeIterator_next (CCGEdgeIterator *ei);
+void ccgEdgeIterator_free (CCGEdgeIterator *ei);
+
+CCGFace* ccgFaceIterator_getCurrent (CCGFaceIterator *fi);
+int ccgFaceIterator_isStopped (CCGFaceIterator *fi);
+void ccgFaceIterator_next (CCGFaceIterator *fi);
+void ccgFaceIterator_free (CCGFaceIterator *fi);
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
new file mode 100644
index 00000000000..4e6d4a31173
--- /dev/null
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -0,0 +1,3310 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <zlib.h>
+
+#include "PIL_time.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_effect_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_key_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_object_force.h"
+#include "DNA_object_fluidsim.h" // N_T
+#include "DNA_scene_types.h" // N_T
+#include "DNA_texture_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+#include "BLI_edgehash.h"
+#include "BLI_editVert.h"
+#include "BLI_linklist.h"
+
+#include "BKE_cdderivedmesh.h"
+#include "BKE_customdata.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_deform.h"
+#include "BKE_displist.h"
+#include "BKE_effect.h"
+#include "BKE_global.h"
+#include "BKE_key.h"
+#include "BKE_material.h"
+#include "BKE_modifier.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_subsurf.h"
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
+
+#ifdef WITH_VERSE
+#include "BKE_verse.h"
+#endif
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+#include "multires.h"
+
+// headers for fluidsim bobj meshes
+#include <stdlib.h>
+#include "LBM_fluidsim.h"
+#include "elbeem.h"
+
+///////////////////////////////////
+///////////////////////////////////
+
+MVert *dm_getVertArray(DerivedMesh *dm)
+{
+ MVert *mvert = CustomData_get_layer(&dm->vertData, CD_MVERT);
+
+ if (!mvert) {
+ mvert = CustomData_add_layer(&dm->vertData, CD_MVERT, CD_CALLOC, NULL,
+ dm->getNumVerts(dm));
+ CustomData_set_layer_flag(&dm->vertData, CD_MVERT, CD_FLAG_TEMPORARY);
+ dm->copyVertArray(dm, mvert);
+ }
+
+ return mvert;
+}
+
+MEdge *dm_getEdgeArray(DerivedMesh *dm)
+{
+ MEdge *medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE);
+
+ if (!medge) {
+ medge = CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_CALLOC, NULL,
+ dm->getNumEdges(dm));
+ CustomData_set_layer_flag(&dm->edgeData, CD_MEDGE, CD_FLAG_TEMPORARY);
+ dm->copyEdgeArray(dm, medge);
+ }
+
+ return medge;
+}
+
+MFace *dm_getFaceArray(DerivedMesh *dm)
+{
+ MFace *mface = CustomData_get_layer(&dm->faceData, CD_MFACE);
+
+ if (!mface) {
+ mface = CustomData_add_layer(&dm->faceData, CD_MFACE, CD_CALLOC, NULL,
+ dm->getNumFaces(dm));
+ CustomData_set_layer_flag(&dm->faceData, CD_MFACE, CD_FLAG_TEMPORARY);
+ dm->copyFaceArray(dm, mface);
+ }
+
+ return mface;
+}
+
+MVert *dm_dupVertArray(DerivedMesh *dm)
+{
+ MVert *tmp = MEM_callocN(sizeof(*tmp) * dm->getNumVerts(dm),
+ "dm_dupVertArray tmp");
+
+ if(tmp) dm->copyVertArray(dm, tmp);
+
+ return tmp;
+}
+
+MEdge *dm_dupEdgeArray(DerivedMesh *dm)
+{
+ MEdge *tmp = MEM_callocN(sizeof(*tmp) * dm->getNumEdges(dm),
+ "dm_dupEdgeArray tmp");
+
+ if(tmp) dm->copyEdgeArray(dm, tmp);
+
+ return tmp;
+}
+
+MFace *dm_dupFaceArray(DerivedMesh *dm)
+{
+ MFace *tmp = MEM_callocN(sizeof(*tmp) * dm->getNumFaces(dm),
+ "dm_dupFaceArray tmp");
+
+ if(tmp) dm->copyFaceArray(dm, tmp);
+
+ return tmp;
+}
+
+void DM_init_funcs(DerivedMesh *dm)
+{
+ /* default function implementations */
+ dm->getVertArray = dm_getVertArray;
+ dm->getEdgeArray = dm_getEdgeArray;
+ dm->getFaceArray = dm_getFaceArray;
+ dm->dupVertArray = dm_dupVertArray;
+ dm->dupEdgeArray = dm_dupEdgeArray;
+ dm->dupFaceArray = dm_dupFaceArray;
+
+ dm->getVertData = DM_get_vert_data;
+ dm->getEdgeData = DM_get_edge_data;
+ dm->getFaceData = DM_get_face_data;
+ dm->getVertDataArray = DM_get_vert_data_layer;
+ dm->getEdgeDataArray = DM_get_edge_data_layer;
+ dm->getFaceDataArray = DM_get_face_data_layer;
+}
+
+void DM_init(DerivedMesh *dm,
+ int numVerts, int numEdges, int numFaces)
+{
+ CustomData_add_layer(&dm->vertData, CD_ORIGINDEX, CD_CALLOC, NULL, numVerts);
+ CustomData_add_layer(&dm->edgeData, CD_ORIGINDEX, CD_CALLOC, NULL, numEdges);
+ CustomData_add_layer(&dm->faceData, CD_ORIGINDEX, CD_CALLOC, NULL, numFaces);
+
+ dm->numVertData = numVerts;
+ dm->numEdgeData = numEdges;
+ dm->numFaceData = numFaces;
+
+ DM_init_funcs(dm);
+
+ dm->needsFree = 1;
+}
+
+void DM_from_template(DerivedMesh *dm, DerivedMesh *source,
+ int numVerts, int numEdges, int numFaces)
+{
+ CustomData_copy(&source->vertData, &dm->vertData, CD_MASK_DERIVEDMESH,
+ CD_CALLOC, numVerts);
+ CustomData_copy(&source->edgeData, &dm->edgeData, CD_MASK_DERIVEDMESH,
+ CD_CALLOC, numEdges);
+ CustomData_copy(&source->faceData, &dm->faceData, CD_MASK_DERIVEDMESH,
+ CD_CALLOC, numFaces);
+
+ dm->numVertData = numVerts;
+ dm->numEdgeData = numEdges;
+ dm->numFaceData = numFaces;
+
+ DM_init_funcs(dm);
+
+ dm->needsFree = 1;
+}
+
+int DM_release(DerivedMesh *dm)
+{
+ if (dm->needsFree) {
+ CustomData_free(&dm->vertData, dm->numVertData);
+ CustomData_free(&dm->edgeData, dm->numEdgeData);
+ CustomData_free(&dm->faceData, dm->numFaceData);
+
+ return 1;
+ }
+ else {
+ CustomData_free_temporary(&dm->vertData, dm->numVertData);
+ CustomData_free_temporary(&dm->edgeData, dm->numEdgeData);
+ CustomData_free_temporary(&dm->faceData, dm->numFaceData);
+
+ return 0;
+ }
+}
+
+void DM_to_mesh(DerivedMesh *dm, Mesh *me)
+{
+ /* dm might depend on me, so we need to do everything with a local copy */
+ Mesh tmp = *me;
+ int totvert, totedge, totface;
+
+ memset(&tmp.vdata, 0, sizeof(tmp.vdata));
+ memset(&tmp.edata, 0, sizeof(tmp.edata));
+ memset(&tmp.fdata, 0, sizeof(tmp.fdata));
+
+ totvert = tmp.totvert = dm->getNumVerts(dm);
+ totedge = tmp.totedge = dm->getNumEdges(dm);
+ totface = tmp.totface = dm->getNumFaces(dm);
+
+ CustomData_copy(&dm->vertData, &tmp.vdata, CD_MASK_MESH, CD_DUPLICATE, totvert);
+ CustomData_copy(&dm->edgeData, &tmp.edata, CD_MASK_MESH, CD_DUPLICATE, totedge);
+ CustomData_copy(&dm->faceData, &tmp.fdata, CD_MASK_MESH, CD_DUPLICATE, totface);
+
+ /* not all DerivedMeshes store their verts/edges/faces in CustomData, so
+ we set them here in case they are missing */
+ if(!CustomData_has_layer(&tmp.vdata, CD_MVERT))
+ CustomData_add_layer(&tmp.vdata, CD_MVERT, CD_ASSIGN, dm->dupVertArray(dm), totvert);
+ if(!CustomData_has_layer(&tmp.edata, CD_MEDGE))
+ CustomData_add_layer(&tmp.edata, CD_MEDGE, CD_ASSIGN, dm->dupEdgeArray(dm), totedge);
+ if(!CustomData_has_layer(&tmp.fdata, CD_MFACE))
+ CustomData_add_layer(&tmp.fdata, CD_MFACE, CD_ASSIGN, dm->dupFaceArray(dm), totface);
+
+ mesh_update_customdata_pointers(&tmp);
+
+ CustomData_free(&me->vdata, me->totvert);
+ CustomData_free(&me->edata, me->totedge);
+ CustomData_free(&me->fdata, me->totface);
+
+ /* if the number of verts has changed, remove invalid data */
+ if(tmp.totvert != me->totvert) {
+ if(me->key) me->key->id.us--;
+ me->key = NULL;
+ }
+
+ *me = tmp;
+}
+
+void DM_set_only_copy(DerivedMesh *dm, CustomDataMask mask)
+{
+ CustomData_set_only_copy(&dm->vertData, mask);
+ CustomData_set_only_copy(&dm->edgeData, mask);
+ CustomData_set_only_copy(&dm->faceData, mask);
+}
+
+void DM_add_vert_layer(DerivedMesh *dm, int type, int alloctype, void *layer)
+{
+ CustomData_add_layer(&dm->vertData, type, alloctype, layer, dm->numVertData);
+}
+
+void DM_add_edge_layer(DerivedMesh *dm, int type, int alloctype, void *layer)
+{
+ CustomData_add_layer(&dm->edgeData, type, alloctype, layer, dm->numEdgeData);
+}
+
+void DM_add_face_layer(DerivedMesh *dm, int type, int alloctype, void *layer)
+{
+ CustomData_add_layer(&dm->faceData, type, alloctype, layer, dm->numFaceData);
+}
+
+void *DM_get_vert_data(DerivedMesh *dm, int index, int type)
+{
+ return CustomData_get(&dm->vertData, index, type);
+}
+
+void *DM_get_edge_data(DerivedMesh *dm, int index, int type)
+{
+ return CustomData_get(&dm->edgeData, index, type);
+}
+
+void *DM_get_face_data(DerivedMesh *dm, int index, int type)
+{
+ return CustomData_get(&dm->faceData, index, type);
+}
+
+void *DM_get_vert_data_layer(DerivedMesh *dm, int type)
+{
+ return CustomData_get_layer(&dm->vertData, type);
+}
+
+void *DM_get_edge_data_layer(DerivedMesh *dm, int type)
+{
+ return CustomData_get_layer(&dm->edgeData, type);
+}
+
+void *DM_get_face_data_layer(DerivedMesh *dm, int type)
+{
+ return CustomData_get_layer(&dm->faceData, type);
+}
+
+void DM_set_vert_data(DerivedMesh *dm, int index, int type, void *data)
+{
+ CustomData_set(&dm->vertData, index, type, data);
+}
+
+void DM_set_edge_data(DerivedMesh *dm, int index, int type, void *data)
+{
+ CustomData_set(&dm->edgeData, index, type, data);
+}
+
+void DM_set_face_data(DerivedMesh *dm, int index, int type, void *data)
+{
+ CustomData_set(&dm->faceData, index, type, data);
+}
+
+void DM_copy_vert_data(DerivedMesh *source, DerivedMesh *dest,
+ int source_index, int dest_index, int count)
+{
+ CustomData_copy_data(&source->vertData, &dest->vertData,
+ source_index, dest_index, count);
+}
+
+void DM_copy_edge_data(DerivedMesh *source, DerivedMesh *dest,
+ int source_index, int dest_index, int count)
+{
+ CustomData_copy_data(&source->edgeData, &dest->edgeData,
+ source_index, dest_index, count);
+}
+
+void DM_copy_face_data(DerivedMesh *source, DerivedMesh *dest,
+ int source_index, int dest_index, int count)
+{
+ CustomData_copy_data(&source->faceData, &dest->faceData,
+ source_index, dest_index, count);
+}
+
+void DM_free_vert_data(struct DerivedMesh *dm, int index, int count)
+{
+ CustomData_free_elem(&dm->vertData, index, count);
+}
+
+void DM_free_edge_data(struct DerivedMesh *dm, int index, int count)
+{
+ CustomData_free_elem(&dm->edgeData, index, count);
+}
+
+void DM_free_face_data(struct DerivedMesh *dm, int index, int count)
+{
+ CustomData_free_elem(&dm->faceData, index, count);
+}
+
+void DM_interp_vert_data(DerivedMesh *source, DerivedMesh *dest,
+ int *src_indices, float *weights,
+ int count, int dest_index)
+{
+ CustomData_interp(&source->vertData, &dest->vertData, src_indices,
+ weights, NULL, count, dest_index);
+}
+
+void DM_interp_edge_data(DerivedMesh *source, DerivedMesh *dest,
+ int *src_indices,
+ float *weights, EdgeVertWeight *vert_weights,
+ int count, int dest_index)
+{
+ CustomData_interp(&source->edgeData, &dest->edgeData, src_indices,
+ weights, (float*)vert_weights, count, dest_index);
+}
+
+void DM_interp_face_data(DerivedMesh *source, DerivedMesh *dest,
+ int *src_indices,
+ float *weights, FaceVertWeight *vert_weights,
+ int count, int dest_index)
+{
+ CustomData_interp(&source->faceData, &dest->faceData, src_indices,
+ weights, (float*)vert_weights, count, dest_index);
+}
+
+void DM_swap_face_data(DerivedMesh *dm, int index, int *corner_indices)
+{
+ CustomData_swap(&dm->faceData, index, corner_indices);
+}
+
+static DerivedMesh *getMeshDerivedMesh(Mesh *me, Object *ob, float (*vertCos)[3])
+{
+ DerivedMesh *dm = CDDM_from_mesh(me, ob);
+ int i, dofluidsim;
+
+ dofluidsim = ((ob->fluidsimFlag & OB_FLUIDSIM_ENABLE) &&
+ (ob->fluidsimSettings->type & OB_FLUIDSIM_DOMAIN)&&
+ (ob->fluidsimSettings->meshSurface) &&
+ (1) && (!give_parteff(ob)) && // doesnt work together with particle systems!
+ (me->totvert == ((Mesh *)(ob->fluidsimSettings->meshSurface))->totvert));
+
+ if (vertCos && !dofluidsim)
+ CDDM_apply_vert_coords(dm, vertCos);
+
+ CDDM_calc_normals(dm);
+
+ /* apply fluidsim normals */
+ if (dofluidsim) {
+ // use normals from readBobjgz
+ // TODO? check for modifiers!?
+ MVert *fsvert = ob->fluidsimSettings->meshSurfNormals;
+ short (*normals)[3] = MEM_mallocN(sizeof(short)*3*me->totvert, "fluidsim nor");
+
+ for (i=0; i<me->totvert; i++) {
+ VECCOPY(normals[i], fsvert[i].no);
+ //mv->no[0]= 30000; mv->no[1]= mv->no[2]= 0; // DEBUG fixed test normals
+ }
+
+ CDDM_apply_vert_normals(dm, normals);
+
+ MEM_freeN(normals);
+ }
+
+ return dm;
+}
+
+///
+
+typedef struct {
+ DerivedMesh dm;
+
+ EditMesh *em;
+ float (*vertexCos)[3];
+ float (*vertexNos)[3];
+ float (*faceNos)[3];
+} EditMeshDerivedMesh;
+
+static void emDM_foreachMappedVert(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no_f, short *no_s), void *userData)
+{
+ EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
+ EditVert *eve;
+ int i;
+
+ for (i=0,eve= emdm->em->verts.first; eve; i++,eve=eve->next) {
+ if (emdm->vertexCos) {
+ func(userData, i, emdm->vertexCos[i], emdm->vertexNos[i], NULL);
+ } else {
+ func(userData, i, eve->co, eve->no, NULL);
+ }
+ }
+}
+static void emDM_foreachMappedEdge(DerivedMesh *dm, void (*func)(void *userData, int index, float *v0co, float *v1co), void *userData)
+{
+ EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
+ EditEdge *eed;
+ int i;
+
+ if (emdm->vertexCos) {
+ EditVert *eve;
+
+ for (i=0,eve=emdm->em->verts.first; eve; eve= eve->next)
+ eve->tmp.l = (long) i++;
+ for(i=0,eed= emdm->em->edges.first; eed; i++,eed= eed->next)
+ func(userData, i, emdm->vertexCos[(int) eed->v1->tmp.l], emdm->vertexCos[(int) eed->v2->tmp.l]);
+ } else {
+ for(i=0,eed= emdm->em->edges.first; eed; i++,eed= eed->next)
+ func(userData, i, eed->v1->co, eed->v2->co);
+ }
+}
+static void emDM_drawMappedEdges(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData)
+{
+ EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
+ EditEdge *eed;
+ int i;
+
+ if (emdm->vertexCos) {
+ EditVert *eve;
+
+ for (i=0,eve=emdm->em->verts.first; eve; eve= eve->next)
+ eve->tmp.l = (long) i++;
+
+ glBegin(GL_LINES);
+ for(i=0,eed= emdm->em->edges.first; eed; i++,eed= eed->next) {
+ if(!setDrawOptions || setDrawOptions(userData, i)) {
+ glVertex3fv(emdm->vertexCos[(int) eed->v1->tmp.l]);
+ glVertex3fv(emdm->vertexCos[(int) eed->v2->tmp.l]);
+ }
+ }
+ glEnd();
+ } else {
+ glBegin(GL_LINES);
+ for(i=0,eed= emdm->em->edges.first; eed; i++,eed= eed->next) {
+ if(!setDrawOptions || setDrawOptions(userData, i)) {
+ glVertex3fv(eed->v1->co);
+ glVertex3fv(eed->v2->co);
+ }
+ }
+ glEnd();
+ }
+}
+static void emDM_drawEdges(DerivedMesh *dm, int drawLooseEdges)
+{
+ emDM_drawMappedEdges(dm, NULL, NULL);
+}
+static void emDM_drawMappedEdgesInterp(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void (*setDrawInterpOptions)(void *userData, int index, float t), void *userData)
+{
+ EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
+ EditEdge *eed;
+ int i;
+
+ if (emdm->vertexCos) {
+ EditVert *eve;
+
+ for (i=0,eve=emdm->em->verts.first; eve; eve= eve->next)
+ eve->tmp.l = (long) i++;
+
+ glBegin(GL_LINES);
+ for (i=0,eed= emdm->em->edges.first; eed; i++,eed= eed->next) {
+ if(!setDrawOptions || setDrawOptions(userData, i)) {
+ setDrawInterpOptions(userData, i, 0.0);
+ glVertex3fv(emdm->vertexCos[(int) eed->v1->tmp.l]);
+ setDrawInterpOptions(userData, i, 1.0);
+ glVertex3fv(emdm->vertexCos[(int) eed->v2->tmp.l]);
+ }
+ }
+ glEnd();
+ } else {
+ glBegin(GL_LINES);
+ for (i=0,eed= emdm->em->edges.first; eed; i++,eed= eed->next) {
+ if(!setDrawOptions || setDrawOptions(userData, i)) {
+ setDrawInterpOptions(userData, i, 0.0);
+ glVertex3fv(eed->v1->co);
+ setDrawInterpOptions(userData, i, 1.0);
+ glVertex3fv(eed->v2->co);
+ }
+ }
+ glEnd();
+ }
+}
+
+static void emDM_drawUVEdges(DerivedMesh *dm)
+{
+ EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
+ EditFace *efa;
+ MTFace *tf;
+
+ glBegin(GL_LINES);
+ for(efa= emdm->em->faces.first; efa; efa= efa->next) {
+ tf = CustomData_em_get(&emdm->em->fdata, efa->data, CD_MTFACE);
+
+ if(tf && !(efa->h)) {
+ glVertex2fv(tf->uv[0]);
+ glVertex2fv(tf->uv[1]);
+
+ glVertex2fv(tf->uv[1]);
+ glVertex2fv(tf->uv[2]);
+
+ if (!efa->v4) {
+ glVertex2fv(tf->uv[2]);
+ glVertex2fv(tf->uv[0]);
+ } else {
+ glVertex2fv(tf->uv[2]);
+ glVertex2fv(tf->uv[3]);
+ glVertex2fv(tf->uv[3]);
+ glVertex2fv(tf->uv[0]);
+ }
+ }
+ }
+ glEnd();
+}
+
+static void emDM__calcFaceCent(EditFace *efa, float cent[3], float (*vertexCos)[3])
+{
+ if (vertexCos) {
+ VECCOPY(cent, vertexCos[(int) efa->v1->tmp.l]);
+ VecAddf(cent, cent, vertexCos[(int) efa->v2->tmp.l]);
+ VecAddf(cent, cent, vertexCos[(int) efa->v3->tmp.l]);
+ if (efa->v4) VecAddf(cent, cent, vertexCos[(int) efa->v4->tmp.l]);
+ } else {
+ VECCOPY(cent, efa->v1->co);
+ VecAddf(cent, cent, efa->v2->co);
+ VecAddf(cent, cent, efa->v3->co);
+ if (efa->v4) VecAddf(cent, cent, efa->v4->co);
+ }
+
+ if (efa->v4) {
+ VecMulf(cent, 0.25f);
+ } else {
+ VecMulf(cent, 0.33333333333f);
+ }
+}
+static void emDM_foreachMappedFaceCenter(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no), void *userData)
+{
+ EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
+ EditVert *eve;
+ EditFace *efa;
+ float cent[3];
+ int i;
+
+ if (emdm->vertexCos) {
+ for (i=0,eve=emdm->em->verts.first; eve; eve= eve->next)
+ eve->tmp.l = (long) i++;
+ }
+
+ for(i=0,efa= emdm->em->faces.first; efa; i++,efa= efa->next) {
+ emDM__calcFaceCent(efa, cent, emdm->vertexCos);
+ func(userData, i, cent, emdm->vertexCos?emdm->faceNos[i]:efa->n);
+ }
+}
+static void emDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int useColors)
+{
+ GLubyte act_face_stipple[32*32/8] = DM_FACE_STIPPLE;
+ EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
+ EditFace *efa;
+ int i, draw;
+
+ if (emdm->vertexCos) {
+ EditVert *eve;
+
+ for (i=0,eve=emdm->em->verts.first; eve; eve= eve->next)
+ eve->tmp.l = (long) i++;
+
+ for (i=0,efa= emdm->em->faces.first; efa; i++,efa= efa->next) {
+ int drawSmooth = (efa->flag & ME_SMOOTH);
+ draw = setDrawOptions==NULL ? 1 : setDrawOptions(userData, i, &drawSmooth);
+ if(draw) {
+ if (draw==2) { /* enabled with stipple */
+ glEnable(GL_POLYGON_STIPPLE);
+ glPolygonStipple(act_face_stipple);
+ }
+
+ glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT);
+
+ glBegin(efa->v4?GL_QUADS:GL_TRIANGLES);
+ if (!drawSmooth) {
+ glNormal3fv(emdm->faceNos[i]);
+ glVertex3fv(emdm->vertexCos[(int) efa->v1->tmp.l]);
+ glVertex3fv(emdm->vertexCos[(int) efa->v2->tmp.l]);
+ glVertex3fv(emdm->vertexCos[(int) efa->v3->tmp.l]);
+ if(efa->v4) glVertex3fv(emdm->vertexCos[(int) efa->v4->tmp.l]);
+ } else {
+ glNormal3fv(emdm->vertexNos[(int) efa->v1->tmp.l]);
+ glVertex3fv(emdm->vertexCos[(int) efa->v1->tmp.l]);
+ glNormal3fv(emdm->vertexNos[(int) efa->v2->tmp.l]);
+ glVertex3fv(emdm->vertexCos[(int) efa->v2->tmp.l]);
+ glNormal3fv(emdm->vertexNos[(int) efa->v3->tmp.l]);
+ glVertex3fv(emdm->vertexCos[(int) efa->v3->tmp.l]);
+ if(efa->v4) {
+ glNormal3fv(emdm->vertexNos[(int) efa->v4->tmp.l]);
+ glVertex3fv(emdm->vertexCos[(int) efa->v4->tmp.l]);
+ }
+ }
+ glEnd();
+
+ if (draw==2)
+ glDisable(GL_POLYGON_STIPPLE);
+ }
+ }
+ } else {
+ for (i=0,efa= emdm->em->faces.first; efa; i++,efa= efa->next) {
+ int drawSmooth = (efa->flag & ME_SMOOTH);
+ draw = setDrawOptions==NULL ? 1 : setDrawOptions(userData, i, &drawSmooth);
+ if(draw) {
+ if (draw==2) { /* enabled with stipple */
+ glEnable(GL_POLYGON_STIPPLE);
+ glPolygonStipple(act_face_stipple);
+ }
+ glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT);
+
+ glBegin(efa->v4?GL_QUADS:GL_TRIANGLES);
+ if (!drawSmooth) {
+ glNormal3fv(efa->n);
+ glVertex3fv(efa->v1->co);
+ glVertex3fv(efa->v2->co);
+ glVertex3fv(efa->v3->co);
+ if(efa->v4) glVertex3fv(efa->v4->co);
+ } else {
+ glNormal3fv(efa->v1->no);
+ glVertex3fv(efa->v1->co);
+ glNormal3fv(efa->v2->no);
+ glVertex3fv(efa->v2->co);
+ glNormal3fv(efa->v3->no);
+ glVertex3fv(efa->v3->co);
+ if(efa->v4) {
+ glNormal3fv(efa->v4->no);
+ glVertex3fv(efa->v4->co);
+ }
+ }
+ glEnd();
+
+ if (draw==2)
+ glDisable(GL_POLYGON_STIPPLE);
+ }
+ }
+ }
+}
+
+static void emDM_drawFacesTex_common(DerivedMesh *dm,
+ int (*drawParams)(MTFace *tface, MCol *mcol, int matnr),
+ int (*drawParamsMapped)(void *userData, int index),
+ void *userData)
+{
+ EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
+ EditMesh *em= emdm->em;
+ float (*vertexCos)[3]= emdm->vertexCos;
+ float (*vertexNos)[3]= emdm->vertexNos;
+ EditFace *efa;
+ int i;
+
+ if (vertexCos) {
+ EditVert *eve;
+
+ for (i=0,eve=em->verts.first; eve; eve= eve->next)
+ eve->tmp.l = (long) i++;
+
+ for (i=0,efa= em->faces.first; efa; i++,efa= efa->next) {
+ MTFace *tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ MCol *mcol= CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
+ unsigned char *cp= NULL;
+ int drawSmooth= (efa->flag & ME_SMOOTH);
+ int flag;
+
+ if(drawParams)
+ flag= drawParams(tf, mcol, efa->mat_nr);
+ else if(drawParamsMapped)
+ flag= drawParamsMapped(userData, i);
+ else
+ flag= 1;
+
+ if(flag != 0) { /* flag 0 == the face is hidden or invisible */
+ if (flag==1 && mcol)
+ cp= (unsigned char*)mcol;
+
+ glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT);
+
+ glBegin(efa->v4?GL_QUADS:GL_TRIANGLES);
+ if (!drawSmooth) {
+ glNormal3fv(emdm->faceNos[i]);
+
+ if(tf) glTexCoord2fv(tf->uv[0]);
+ if(cp) glColor3ub(cp[3], cp[2], cp[1]);
+ glVertex3fv(vertexCos[(int) efa->v1->tmp.l]);
+
+ if(tf) glTexCoord2fv(tf->uv[1]);
+ if(cp) glColor3ub(cp[7], cp[6], cp[5]);
+ glVertex3fv(vertexCos[(int) efa->v2->tmp.l]);
+
+ if(tf) glTexCoord2fv(tf->uv[2]);
+ if(cp) glColor3ub(cp[11], cp[10], cp[9]);
+ glVertex3fv(vertexCos[(int) efa->v3->tmp.l]);
+
+ if(efa->v4) {
+ if(tf) glTexCoord2fv(tf->uv[3]);
+ if(cp) glColor3ub(cp[15], cp[14], cp[13]);
+ glVertex3fv(vertexCos[(int) efa->v4->tmp.l]);
+ }
+ } else {
+ if(tf) glTexCoord2fv(tf->uv[0]);
+ if(cp) glColor3ub(cp[3], cp[2], cp[1]);
+ glNormal3fv(vertexNos[(int) efa->v1->tmp.l]);
+ glVertex3fv(vertexCos[(int) efa->v1->tmp.l]);
+
+ if(tf) glTexCoord2fv(tf->uv[1]);
+ if(cp) glColor3ub(cp[7], cp[6], cp[5]);
+ glNormal3fv(vertexNos[(int) efa->v2->tmp.l]);
+ glVertex3fv(vertexCos[(int) efa->v2->tmp.l]);
+
+ if(tf) glTexCoord2fv(tf->uv[2]);
+ if(cp) glColor3ub(cp[11], cp[10], cp[9]);
+ glNormal3fv(vertexNos[(int) efa->v3->tmp.l]);
+ glVertex3fv(vertexCos[(int) efa->v3->tmp.l]);
+
+ if(efa->v4) {
+ if(tf) glTexCoord2fv(tf->uv[3]);
+ if(cp) glColor3ub(cp[15], cp[14], cp[13]);
+ glNormal3fv(vertexNos[(int) efa->v4->tmp.l]);
+ glVertex3fv(vertexCos[(int) efa->v4->tmp.l]);
+ }
+ }
+ glEnd();
+ }
+ }
+ } else {
+ for (i=0,efa= em->faces.first; efa; i++,efa= efa->next) {
+ MTFace *tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ MCol *mcol= CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
+ unsigned char *cp= NULL;
+ int drawSmooth= (efa->flag & ME_SMOOTH);
+ int flag;
+
+ if(drawParams)
+ flag= drawParams(tf, mcol, efa->mat_nr);
+ else if(drawParamsMapped)
+ flag= drawParamsMapped(userData, i);
+ else
+ flag= 1;
+
+ if(flag != 0) { /* flag 0 == the face is hidden or invisible */
+ if (flag==1 && mcol)
+ cp= (unsigned char*)mcol;
+
+ glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT);
+
+ glBegin(efa->v4?GL_QUADS:GL_TRIANGLES);
+ if (!drawSmooth) {
+ glNormal3fv(efa->n);
+
+ if(tf) glTexCoord2fv(tf->uv[0]);
+ if(cp) glColor3ub(cp[3], cp[2], cp[1]);
+ glVertex3fv(efa->v1->co);
+
+ if(tf) glTexCoord2fv(tf->uv[1]);
+ if(cp) glColor3ub(cp[7], cp[6], cp[5]);
+ glVertex3fv(efa->v2->co);
+
+ if(tf) glTexCoord2fv(tf->uv[2]);
+ if(cp) glColor3ub(cp[11], cp[10], cp[9]);
+ glVertex3fv(efa->v3->co);
+
+ if(efa->v4) {
+ if(tf) glTexCoord2fv(tf->uv[3]);
+ if(cp) glColor3ub(cp[15], cp[14], cp[13]);
+ glVertex3fv(efa->v4->co);
+ }
+ } else {
+ if(tf) glTexCoord2fv(tf->uv[0]);
+ if(cp) glColor3ub(cp[3], cp[2], cp[1]);
+ glNormal3fv(efa->v1->no);
+ glVertex3fv(efa->v1->co);
+
+ if(tf) glTexCoord2fv(tf->uv[1]);
+ if(cp) glColor3ub(cp[7], cp[6], cp[5]);
+ glNormal3fv(efa->v2->no);
+ glVertex3fv(efa->v2->co);
+
+ if(tf) glTexCoord2fv(tf->uv[2]);
+ if(cp) glColor3ub(cp[11], cp[10], cp[9]);
+ glNormal3fv(efa->v3->no);
+ glVertex3fv(efa->v3->co);
+
+ if(efa->v4) {
+ if(tf) glTexCoord2fv(tf->uv[3]);
+ if(cp) glColor3ub(cp[15], cp[14], cp[13]);
+ glNormal3fv(efa->v4->no);
+ glVertex3fv(efa->v4->co);
+ }
+ }
+ glEnd();
+ }
+ }
+ }
+}
+
+static void emDM_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tface, MCol *mcol, int matnr))
+{
+ emDM_drawFacesTex_common(dm, setDrawOptions, NULL, NULL);
+}
+
+static void emDM_drawMappedFacesTex(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData)
+{
+ emDM_drawFacesTex_common(dm, NULL, setDrawOptions, userData);
+}
+
+static void emDM_getMinMax(DerivedMesh *dm, float min_r[3], float max_r[3])
+{
+ EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
+ EditVert *eve;
+ int i;
+
+ if (emdm->em->verts.first) {
+ for (i=0,eve= emdm->em->verts.first; eve; i++,eve= eve->next) {
+ if (emdm->vertexCos) {
+ DO_MINMAX(emdm->vertexCos[i], min_r, max_r);
+ } else {
+ DO_MINMAX(eve->co, min_r, max_r);
+ }
+ }
+ } else {
+ min_r[0] = min_r[1] = min_r[2] = max_r[0] = max_r[1] = max_r[2] = 0.0;
+ }
+}
+static int emDM_getNumVerts(DerivedMesh *dm)
+{
+ EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
+
+ return BLI_countlist(&emdm->em->verts);
+}
+
+static int emDM_getNumEdges(DerivedMesh *dm)
+{
+ EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
+
+ return BLI_countlist(&emdm->em->edges);
+}
+
+static int emDM_getNumFaces(DerivedMesh *dm)
+{
+ EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
+
+ return BLI_countlist(&emdm->em->faces);
+}
+
+void emDM_getVert(DerivedMesh *dm, int index, MVert *vert_r)
+{
+ EditVert *ev = ((EditMeshDerivedMesh *)dm)->em->verts.first;
+ int i;
+
+ for(i = 0; i < index; ++i) ev = ev->next;
+
+ VECCOPY(vert_r->co, ev->co);
+
+ vert_r->no[0] = ev->no[0] * 32767.0;
+ vert_r->no[1] = ev->no[1] * 32767.0;
+ vert_r->no[2] = ev->no[2] * 32767.0;
+
+ /* TODO what to do with vert_r->flag and vert_r->mat_nr? */
+ vert_r->mat_nr = 0;
+}
+
+void emDM_getEdge(DerivedMesh *dm, int index, MEdge *edge_r)
+{
+ EditMesh *em = ((EditMeshDerivedMesh *)dm)->em;
+ EditEdge *ee = em->edges.first;
+ EditVert *ev, *v1, *v2;
+ int i;
+
+ for(i = 0; i < index; ++i) ee = ee->next;
+
+ edge_r->crease = (unsigned char) (ee->crease*255.0f);
+ /* TODO what to do with edge_r->flag? */
+ edge_r->flag = ME_EDGEDRAW|ME_EDGERENDER;
+ if (ee->seam) edge_r->flag |= ME_SEAM;
+ if (ee->sharp) edge_r->flag |= ME_SHARP;
+#if 0
+ /* this needs setup of f2 field */
+ if (!ee->f2) edge_r->flag |= ME_LOOSEEDGE;
+#endif
+
+ /* goddamn, we have to search all verts to find indices */
+ v1 = ee->v1;
+ v2 = ee->v2;
+ for(i = 0, ev = em->verts.first; v1 || v2; i++, ev = ev->next) {
+ if(ev == v1) {
+ edge_r->v1 = i;
+ v1 = NULL;
+ }
+ if(ev == v2) {
+ edge_r->v2 = i;
+ v2 = NULL;
+ }
+ }
+}
+
+void emDM_getFace(DerivedMesh *dm, int index, MFace *face_r)
+{
+ EditMesh *em = ((EditMeshDerivedMesh *)dm)->em;
+ EditFace *ef = em->faces.first;
+ EditVert *ev, *v1, *v2, *v3, *v4;
+ int i;
+
+ for(i = 0; i < index; ++i) ef = ef->next;
+
+ face_r->mat_nr = ef->mat_nr;
+ face_r->flag = ef->flag;
+
+ /* goddamn, we have to search all verts to find indices */
+ v1 = ef->v1;
+ v2 = ef->v2;
+ v3 = ef->v3;
+ v4 = ef->v4;
+ if(!v4) face_r->v4 = 0;
+
+ for(i = 0, ev = em->verts.first; v1 || v2 || v3 || v4;
+ i++, ev = ev->next) {
+ if(ev == v1) {
+ face_r->v1 = i;
+ v1 = NULL;
+ }
+ if(ev == v2) {
+ face_r->v2 = i;
+ v2 = NULL;
+ }
+ if(ev == v3) {
+ face_r->v3 = i;
+ v3 = NULL;
+ }
+ if(ev == v4) {
+ face_r->v4 = i;
+ v4 = NULL;
+ }
+ }
+
+ test_index_face(face_r, NULL, 0, ef->v4?4:3);
+}
+
+void emDM_copyVertArray(DerivedMesh *dm, MVert *vert_r)
+{
+ EditVert *ev = ((EditMeshDerivedMesh *)dm)->em->verts.first;
+
+ for( ; ev; ev = ev->next, ++vert_r) {
+ VECCOPY(vert_r->co, ev->co);
+
+ vert_r->no[0] = ev->no[0] * 32767.0;
+ vert_r->no[1] = ev->no[1] * 32767.0;
+ vert_r->no[2] = ev->no[2] * 32767.0;
+
+ /* TODO what to do with vert_r->flag and vert_r->mat_nr? */
+ vert_r->mat_nr = 0;
+ vert_r->flag = 0;
+ }
+}
+
+void emDM_copyEdgeArray(DerivedMesh *dm, MEdge *edge_r)
+{
+ EditMesh *em = ((EditMeshDerivedMesh *)dm)->em;
+ EditEdge *ee = em->edges.first;
+ EditVert *ev;
+ int i;
+
+ /* store vertex indices in tmp union */
+ for(ev = em->verts.first, i = 0; ev; ev = ev->next, ++i)
+ ev->tmp.l = (long) i++;
+
+ for( ; ee; ee = ee->next, ++edge_r) {
+ edge_r->crease = (unsigned char) (ee->crease*255.0f);
+ /* TODO what to do with edge_r->flag? */
+ edge_r->flag = ME_EDGEDRAW|ME_EDGERENDER;
+ if (ee->seam) edge_r->flag |= ME_SEAM;
+ if (ee->sharp) edge_r->flag |= ME_SHARP;
+#if 0
+ /* this needs setup of f2 field */
+ if (!ee->f2) edge_r->flag |= ME_LOOSEEDGE;
+#endif
+
+ edge_r->v1 = (int)ee->v1->tmp.l;
+ edge_r->v2 = (int)ee->v2->tmp.l;
+ }
+}
+
+void emDM_copyFaceArray(DerivedMesh *dm, MFace *face_r)
+{
+ EditMesh *em = ((EditMeshDerivedMesh *)dm)->em;
+ EditFace *ef = em->faces.first;
+ EditVert *ev;
+ int i;
+
+ /* store vertexes indices in tmp union */
+ for(ev = em->verts.first, i = 0; ev; ev = ev->next, ++i)
+ ev->tmp.l = (long) i;
+
+ for( ; ef; ef = ef->next, ++face_r) {
+ face_r->mat_nr = ef->mat_nr;
+ face_r->flag = ef->flag;
+
+ face_r->v1 = (int)ef->v1->tmp.l;
+ face_r->v2 = (int)ef->v2->tmp.l;
+ face_r->v3 = (int)ef->v3->tmp.l;
+ if(ef->v4) face_r->v4 = (int)ef->v4->tmp.l;
+ else face_r->v4 = 0;
+
+ test_index_face(face_r, NULL, 0, ef->v4?4:3);
+ }
+}
+
+static void emDM_release(DerivedMesh *dm)
+{
+ EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
+
+ if (DM_release(dm)) {
+ if (emdm->vertexCos) {
+ MEM_freeN(emdm->vertexCos);
+ MEM_freeN(emdm->vertexNos);
+ MEM_freeN(emdm->faceNos);
+ }
+
+ MEM_freeN(emdm);
+ }
+}
+
+static DerivedMesh *getEditMeshDerivedMesh(EditMesh *em, Object *ob,
+ float (*vertexCos)[3])
+{
+ EditMeshDerivedMesh *emdm = MEM_callocN(sizeof(*emdm), "emdm");
+
+ DM_init(&emdm->dm, BLI_countlist(&em->verts),
+ BLI_countlist(&em->edges), BLI_countlist(&em->faces));
+
+ emdm->dm.getMinMax = emDM_getMinMax;
+
+ emdm->dm.getNumVerts = emDM_getNumVerts;
+ emdm->dm.getNumEdges = emDM_getNumEdges;
+ emdm->dm.getNumFaces = emDM_getNumFaces;
+
+ emdm->dm.getVert = emDM_getVert;
+ emdm->dm.getEdge = emDM_getEdge;
+ emdm->dm.getFace = emDM_getFace;
+ emdm->dm.copyVertArray = emDM_copyVertArray;
+ emdm->dm.copyEdgeArray = emDM_copyEdgeArray;
+ emdm->dm.copyFaceArray = emDM_copyFaceArray;
+
+ emdm->dm.foreachMappedVert = emDM_foreachMappedVert;
+ emdm->dm.foreachMappedEdge = emDM_foreachMappedEdge;
+ emdm->dm.foreachMappedFaceCenter = emDM_foreachMappedFaceCenter;
+
+ emdm->dm.drawEdges = emDM_drawEdges;
+ emdm->dm.drawMappedEdges = emDM_drawMappedEdges;
+ emdm->dm.drawMappedEdgesInterp = emDM_drawMappedEdgesInterp;
+ emdm->dm.drawMappedFaces = emDM_drawMappedFaces;
+ emdm->dm.drawMappedFacesTex = emDM_drawMappedFacesTex;
+ emdm->dm.drawFacesTex = emDM_drawFacesTex;
+ emdm->dm.drawUVEdges = emDM_drawUVEdges;
+
+ emdm->dm.release = emDM_release;
+
+ emdm->em = em;
+ emdm->vertexCos = vertexCos;
+
+ if(CustomData_has_layer(&em->vdata, CD_MDEFORMVERT)) {
+ EditVert *eve;
+ int i;
+
+ DM_add_vert_layer(&emdm->dm, CD_MDEFORMVERT, CD_CALLOC, NULL);
+
+ for(eve = em->verts.first, i = 0; eve; eve = eve->next, ++i)
+ DM_set_vert_data(&emdm->dm, i, CD_MDEFORMVERT,
+ CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT));
+ }
+
+ if(vertexCos) {
+ EditVert *eve;
+ EditFace *efa;
+ int totface = BLI_countlist(&em->faces);
+ int i;
+
+ for (i=0,eve=em->verts.first; eve; eve= eve->next)
+ eve->tmp.l = (long) i++;
+
+ emdm->vertexNos = MEM_callocN(sizeof(*emdm->vertexNos)*i, "emdm_vno");
+ emdm->faceNos = MEM_mallocN(sizeof(*emdm->faceNos)*totface, "emdm_vno");
+
+ for(i=0, efa= em->faces.first; efa; i++, efa=efa->next) {
+ float *v1 = vertexCos[(int) efa->v1->tmp.l];
+ float *v2 = vertexCos[(int) efa->v2->tmp.l];
+ float *v3 = vertexCos[(int) efa->v3->tmp.l];
+ float *no = emdm->faceNos[i];
+
+ if(efa->v4) {
+ float *v4 = vertexCos[(int) efa->v4->tmp.l];
+
+ CalcNormFloat4(v1, v2, v3, v4, no);
+ VecAddf(emdm->vertexNos[(int) efa->v4->tmp.l], emdm->vertexNos[(int) efa->v4->tmp.l], no);
+ }
+ else {
+ CalcNormFloat(v1, v2, v3, no);
+ }
+
+ VecAddf(emdm->vertexNos[(int) efa->v1->tmp.l], emdm->vertexNos[(int) efa->v1->tmp.l], no);
+ VecAddf(emdm->vertexNos[(int) efa->v2->tmp.l], emdm->vertexNos[(int) efa->v2->tmp.l], no);
+ VecAddf(emdm->vertexNos[(int) efa->v3->tmp.l], emdm->vertexNos[(int) efa->v3->tmp.l], no);
+ }
+
+ for(i=0, eve= em->verts.first; eve; i++, eve=eve->next) {
+ float *no = emdm->vertexNos[i];
+ /* following Mesh convention; we use vertex coordinate itself
+ * for normal in this case */
+ if (Normalize(no)==0.0) {
+ VECCOPY(no, vertexCos[i]);
+ Normalize(no);
+ }
+ }
+ }
+
+ return (DerivedMesh*) emdm;
+}
+
+#ifdef WITH_VERSE
+
+/* verse derived mesh */
+typedef struct {
+ struct DerivedMesh dm;
+ struct VNode *vnode;
+ struct VLayer *vertex_layer;
+ struct VLayer *polygon_layer;
+ struct ListBase *edges;
+ float (*vertexCos)[3];
+} VDerivedMesh;
+
+/* this function set up border points of verse mesh bounding box */
+static void vDM_getMinMax(DerivedMesh *dm, float min_r[3], float max_r[3])
+{
+ VDerivedMesh *vdm = (VDerivedMesh*)dm;
+ struct VerseVert *vvert;
+
+ if(!vdm->vertex_layer) return;
+
+ vvert = (VerseVert*)vdm->vertex_layer->dl.lb.first;
+
+ if(vdm->vertex_layer->dl.da.count > 0) {
+ while(vvert) {
+ DO_MINMAX(vdm->vertexCos ? vvert->cos : vvert->co, min_r, max_r);
+ vvert = vvert->next;
+ }
+ }
+ else {
+ min_r[0] = min_r[1] = min_r[2] = max_r[0] = max_r[1] = max_r[2] = 0.0;
+ }
+}
+
+/* this function return number of vertexes in vertex layer */
+static int vDM_getNumVerts(DerivedMesh *dm)
+{
+ VDerivedMesh *vdm = (VDerivedMesh*)dm;
+
+ if(!vdm->vertex_layer) return 0;
+ else return vdm->vertex_layer->dl.da.count;
+}
+
+/* this function return number of 'fake' edges */
+static int vDM_getNumEdges(DerivedMesh *dm)
+{
+ VDerivedMesh *vdm = (VDerivedMesh*)dm;
+
+ return BLI_countlist(vdm->edges);
+}
+
+/* this function returns number of polygons in polygon layer */
+static int vDM_getNumFaces(DerivedMesh *dm)
+{
+ VDerivedMesh *vdm = (VDerivedMesh*)dm;
+
+ if(!vdm->polygon_layer) return 0;
+ else return vdm->polygon_layer->dl.da.count;
+}
+
+/* this function doesn't return vertex with index of access array,
+ * but it return 'indexth' vertex of dynamic list */
+void vDM_getVert(DerivedMesh *dm, int index, MVert *vert_r)
+{
+ VDerivedMesh *vdm = (VDerivedMesh*)dm;
+ struct VerseVert *vvert;
+ int i;
+
+ if(!vdm->vertex_layer) return;
+
+ for(vvert = vdm->vertex_layer->dl.lb.first, i=0 ; i<index; i++) vvert = vvert->next;
+
+ if(vvert) {
+ VECCOPY(vert_r->co, vvert->co);
+
+ vert_r->no[0] = vvert->no[0] * 32767.0;
+ vert_r->no[1] = vvert->no[1] * 32767.0;
+ vert_r->no[2] = vvert->no[2] * 32767.0;
+
+ /* TODO what to do with vert_r->flag and vert_r->mat_nr? */
+ vert_r->mat_nr = 0;
+ vert_r->flag = 0;
+ }
+}
+
+/* this function returns fake verse edge */
+void vDM_getEdge(DerivedMesh *dm, int index, MEdge *edge_r)
+{
+ VDerivedMesh *vdm = (VDerivedMesh*)dm;
+ struct VerseEdge *vedge;
+ struct VLayer *vert_vlayer = vdm->vertex_layer;
+ struct VerseVert *vvert;
+ int j;
+
+ if(!vdm->vertex_layer || !vdm->edges) return;
+
+ if(vdm->edges->first) {
+ struct VerseVert *vvert1, *vvert2;
+
+ /* store vert indices in tmp union */
+ for(vvert = vdm->vertex_layer->dl.lb.first, j = 0; vvert; vvert = vvert->next, j++)
+ vvert->tmp.index = j;
+
+ for(vedge = vdm->edges->first; vedge; vedge = vedge->next) {
+ if(vedge->tmp.index==index) {
+ vvert1 = BLI_dlist_find_link(&(vert_vlayer->dl), (unsigned int)vedge->v0);
+ vvert2 = BLI_dlist_find_link(&(vert_vlayer->dl), (unsigned int)vedge->v1);
+
+ if(vvert1 && vvert2) {
+ edge_r->v1 = vvert1->tmp.index;
+ edge_r->v2 = vvert2->tmp.index;
+ }
+ else {
+ edge_r->v1 = 0;
+ edge_r->v2 = 0;
+ }
+ /* not supported yet */
+ edge_r->flag = 0;
+ edge_r->crease = 0;
+ break;
+ }
+ }
+ }
+}
+
+/* this function doesn't return face with index of access array,
+ * but it returns 'indexth' vertex of dynamic list */
+void vDM_getFace(DerivedMesh *dm, int index, MFace *face_r)
+{
+ VDerivedMesh *vdm = (VDerivedMesh*)dm;
+ struct VerseFace *vface;
+ struct VerseVert *vvert;
+ struct VerseVert *vvert0, *vvert1, *vvert2, *vvert3;
+ int i;
+
+ if(!vdm->vertex_layer || !vdm->polygon_layer) return;
+
+ for(vface = vdm->polygon_layer->dl.lb.first, i = 0; i < index; ++i) vface = vface->next;
+
+ face_r->mat_nr = 0;
+ face_r->flag = 0;
+
+ /* goddamn, we have to search all verts to find indices */
+ vvert0 = vface->vvert0;
+ vvert1 = vface->vvert1;
+ vvert2 = vface->vvert2;
+ vvert3 = vface->vvert3;
+ if(!vvert3) face_r->v4 = 0;
+
+ for(vvert = vdm->vertex_layer->dl.lb.first, i = 0; vvert0 || vvert1 || vvert2 || vvert3; i++, vvert = vvert->next) {
+ if(vvert == vvert0) {
+ face_r->v1 = i;
+ vvert0 = NULL;
+ }
+ if(vvert == vvert1) {
+ face_r->v2 = i;
+ vvert1 = NULL;
+ }
+ if(vvert == vvert2) {
+ face_r->v3 = i;
+ vvert2 = NULL;
+ }
+ if(vvert == vvert3) {
+ face_r->v4 = i;
+ vvert3 = NULL;
+ }
+ }
+
+ test_index_face(face_r, NULL, 0, vface->vvert3?4:3);
+}
+
+/* fill array of mvert */
+void vDM_copyVertArray(DerivedMesh *dm, MVert *vert_r)
+{
+ VDerivedMesh *vdm = (VDerivedMesh*)dm;
+ struct VerseVert *vvert;
+
+ if(!vdm->vertex_layer) return;
+
+ for(vvert = vdm->vertex_layer->dl.lb.first ; vvert; vvert = vvert->next, ++vert_r) {
+ VECCOPY(vert_r->co, vvert->co);
+
+ vert_r->no[0] = vvert->no[0] * 32767.0;
+ vert_r->no[1] = vvert->no[1] * 32767.0;
+ vert_r->no[2] = vvert->no[2] * 32767.0;
+
+ vert_r->mat_nr = 0;
+ vert_r->flag = 0;
+ }
+}
+
+/* dummy function, edges arent supported in verse mesh */
+void vDM_copyEdgeArray(DerivedMesh *dm, MEdge *edge_r)
+{
+ VDerivedMesh *vdm = (VDerivedMesh*)dm;
+
+ if(!vdm->vertex_layer || !vdm->edges) return;
+
+ if(vdm->edges->first) {
+ struct VerseEdge *vedge;
+ struct VLayer *vert_vlayer = vdm->vertex_layer;
+ struct VerseVert *vvert, *vvert1, *vvert2;
+ int j;
+
+ /* store vert indices in tmp union */
+ for(vvert = vdm->vertex_layer->dl.lb.first, j = 0; vvert; vvert = vvert->next, ++j)
+ vvert->tmp.index = j;
+
+ for(vedge = vdm->edges->first, j=0 ; vedge; vedge = vedge->next, ++edge_r, j++) {
+ /* create temporary edge index */
+ vedge->tmp.index = j;
+ vvert1 = BLI_dlist_find_link(&(vert_vlayer->dl), (unsigned int)vedge->v0);
+ vvert2 = BLI_dlist_find_link(&(vert_vlayer->dl), (unsigned int)vedge->v1);
+ if(vvert1 && vvert2) {
+ edge_r->v1 = vvert1->tmp.index;
+ edge_r->v2 = vvert2->tmp.index;
+ }
+ else {
+ printf("error: vDM_copyEdgeArray: %d, %d\n", vedge->v0, vedge->v1);
+ edge_r->v1 = 0;
+ edge_r->v2 = 0;
+ }
+ /* not supported yet */
+ edge_r->flag = 0;
+ edge_r->crease = 0;
+ }
+ }
+}
+
+/* fill array of mfaces */
+void vDM_copyFaceArray(DerivedMesh *dm, MFace *face_r)
+{
+ VDerivedMesh *vdm = (VDerivedMesh*)dm;
+ struct VerseFace *vface;
+ struct VerseVert *vvert;
+ int i;
+
+ if(!vdm->vertex_layer || !vdm->polygon_layer) return;
+
+ /* store vertexes indices in tmp union */
+ for(vvert = vdm->vertex_layer->dl.lb.first, i = 0; vvert; vvert = vvert->next, ++i)
+ vvert->tmp.index = i;
+
+ for(vface = vdm->polygon_layer->dl.lb.first; vface; vface = vface->next, ++face_r) {
+ face_r->mat_nr = 0;
+ face_r->flag = 0;
+
+ face_r->v1 = vface->vvert0->tmp.index;
+ face_r->v2 = vface->vvert1->tmp.index;
+ face_r->v3 = vface->vvert2->tmp.index;
+ if(vface->vvert3) face_r->v4 = vface->vvert3->tmp.index;
+ else face_r->v4 = 0;
+
+ test_index_face(face_r, NULL, 0, vface->vvert3?4:3);
+ }
+}
+
+/* return coordination of vertex with index */
+static void vDM_getVertCo(DerivedMesh *dm, int index, float co_r[3])
+{
+ VDerivedMesh *vdm = (VDerivedMesh*)dm;
+ struct VerseVert *vvert = NULL;
+
+ if(!vdm->vertex_layer) return;
+
+ vvert = BLI_dlist_find_link(&(vdm->vertex_layer->dl), index);
+
+ if(vvert) {
+ VECCOPY(co_r, vdm->vertexCos ? vvert->cos : vvert->co);
+ }
+ else {
+ co_r[0] = co_r[1] = co_r[2] = 0.0;
+ }
+}
+
+/* return array of vertex coordiantions */
+static void vDM_getVertCos(DerivedMesh *dm, float (*cos_r)[3])
+{
+ VDerivedMesh *vdm = (VDerivedMesh*)dm;
+ struct VerseVert *vvert;
+ int i = 0;
+
+ if(!vdm->vertex_layer) return;
+
+ vvert = vdm->vertex_layer->dl.lb.first;
+ while(vvert) {
+ VECCOPY(cos_r[i], vdm->vertexCos ? vvert->cos : vvert->co);
+ i++;
+ vvert = vvert->next;
+ }
+}
+
+/* return normal of vertex with index */
+static void vDM_getVertNo(DerivedMesh *dm, int index, float no_r[3])
+{
+ VDerivedMesh *vdm = (VDerivedMesh*)dm;
+ struct VerseVert *vvert = NULL;
+
+ if(!vdm->vertex_layer) return;
+
+ vvert = BLI_dlist_find_link(&(vdm->vertex_layer->dl), index);
+ if(vvert) {
+ VECCOPY(no_r, vvert->no);
+ }
+ else {
+ no_r[0] = no_r[1] = no_r[2] = 0.0;
+ }
+}
+
+/* draw all VerseVertexes */
+static void vDM_drawVerts(DerivedMesh *dm)
+{
+ VDerivedMesh *vdm = (VDerivedMesh*)dm;
+ struct VerseVert *vvert;
+
+ if(!vdm->vertex_layer) return;
+
+ vvert = vdm->vertex_layer->dl.lb.first;
+
+ bglBegin(GL_POINTS);
+ while(vvert) {
+ bglVertex3fv(vdm->vertexCos ? vvert->cos : vvert->co);
+ vvert = vvert->next;
+ }
+ bglEnd();
+}
+
+/* draw all edges of VerseFaces ... it isn't optimal, because verse
+ * specification doesn't support edges :-( ... bother eskil ;-)
+ * ... some edges (most of edges) are drawn twice */
+static void vDM_drawEdges(DerivedMesh *dm, int drawLooseEdges)
+{
+ VDerivedMesh *vdm = (VDerivedMesh*)dm;
+ struct VerseEdge *vedge;
+ struct VLayer *vert_vlayer = vdm->vertex_layer;
+
+ if(vert_vlayer && vdm->edges && (BLI_countlist(vdm->edges) > 0)) {
+ struct VerseVert *vvert1, *vvert2;
+
+ glBegin(GL_LINES);
+ for(vedge = vdm->edges->first; vedge; vedge = vedge->next) {
+ vvert1 = BLI_dlist_find_link(&(vert_vlayer->dl), (unsigned int)vedge->v0);
+ vvert2 = BLI_dlist_find_link(&(vert_vlayer->dl), (unsigned int)vedge->v1);
+ if(vvert1 && vvert2) {
+ glVertex3fv(vdm->vertexCos ? vvert1->cos : vvert1->co);
+ glVertex3fv(vdm->vertexCos ? vvert2->cos : vvert2->co);
+ }
+ }
+ glEnd();
+ }
+}
+
+/* verse spec doesn't support edges ... loose edges can't exist */
+void vDM_drawLooseEdges(DerivedMesh *dm)
+{
+}
+
+/* draw uv edges, not supported yet */
+static void vDM_drawUVEdges(DerivedMesh *dm)
+{
+}
+
+/* draw all VerseFaces */
+static void vDM_drawFacesSolid(DerivedMesh *dm, int (*setMaterial)(int))
+{
+ VDerivedMesh *vdm = (VDerivedMesh*)dm;
+ struct VerseFace *vface;
+
+ if(!vdm->polygon_layer) return;
+
+ vface = vdm->polygon_layer->dl.lb.first;
+
+ glShadeModel(GL_FLAT);
+ while(vface) {
+ glBegin(vface->vvert3?GL_QUADS:GL_TRIANGLES);
+ glNormal3fv(vface->no);
+ glVertex3fv(vdm->vertexCos ? vface->vvert0->cos : vface->vvert0->co);
+ glVertex3fv(vdm->vertexCos ? vface->vvert1->cos : vface->vvert1->co);
+ glVertex3fv(vdm->vertexCos ? vface->vvert2->cos : vface->vvert2->co);
+ if(vface->vvert3)
+ glVertex3fv(vdm->vertexCos ? vface->vvert3->cos : vface->vvert3->co);
+ glEnd();
+ vface = vface->next;
+ }
+}
+
+/* this function should draw mesh with mapped texture, but it isn't supported yet */
+static void vDM_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tface, MCol *mcol, int matnr))
+{
+ VDerivedMesh *vdm = (VDerivedMesh*)dm;
+ struct VerseFace *vface;
+
+ if(!vdm->polygon_layer) return;
+
+ vface = vdm->polygon_layer->dl.lb.first;
+
+ while(vface) {
+ glBegin(vface->vvert3?GL_QUADS:GL_TRIANGLES);
+ glVertex3fv(vdm->vertexCos ? vface->vvert0->cos : vface->vvert0->co);
+ glVertex3fv(vdm->vertexCos ? vface->vvert1->cos : vface->vvert1->co);
+ glVertex3fv(vdm->vertexCos ? vface->vvert2->cos : vface->vvert2->co);
+ if(vface->vvert3)
+ glVertex3fv(vdm->vertexCos ? vface->vvert3->cos : vface->vvert3->co);
+ glEnd();
+
+ vface = vface->next;
+ }
+}
+
+/* this function should draw mesh with colored faces (weight paint, vertex
+ * colors, etc.), but it isn't supported yet */
+static void vDM_drawFacesColored(DerivedMesh *dm, int useTwoSided, unsigned char *col1, unsigned char *col2)
+{
+ VDerivedMesh *vdm = (VDerivedMesh*)dm;
+ struct VerseFace *vface;
+
+ if(!vdm->polygon_layer) return;
+
+ vface = vdm->polygon_layer->dl.lb.first;
+
+ while(vface) {
+ glBegin(vface->vvert3?GL_QUADS:GL_TRIANGLES);
+ glVertex3fv(vdm->vertexCos ? vface->vvert0->cos : vface->vvert0->co);
+ glVertex3fv(vdm->vertexCos ? vface->vvert1->cos : vface->vvert1->co);
+ glVertex3fv(vdm->vertexCos ? vface->vvert2->cos : vface->vvert2->co);
+ if(vface->vvert3)
+ glVertex3fv(vdm->vertexCos ? vface->vvert3->cos : vface->vvert3->co);
+ glEnd();
+
+ vface = vface->next;
+ }
+}
+
+/**/
+static void vDM_foreachMappedVert(
+ DerivedMesh *dm,
+ void (*func)(void *userData, int index, float *co, float *no_f, short *no_s),
+ void *userData)
+{
+}
+
+/**/
+static void vDM_foreachMappedEdge(
+ DerivedMesh *dm,
+ void (*func)(void *userData, int index, float *v0co, float *v1co),
+ void *userData)
+{
+}
+
+/**/
+static void vDM_foreachMappedFaceCenter(
+ DerivedMesh *dm,
+ void (*func)(void *userData, int index, float *cent, float *no),
+ void *userData)
+{
+}
+
+/**/
+static void vDM_drawMappedFacesTex(
+ DerivedMesh *dm,
+ int (*setDrawParams)(void *userData, int index),
+ void *userData)
+{
+}
+
+/**/
+static void vDM_drawMappedFaces(
+ DerivedMesh *dm,
+ int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r),
+ void *userData,
+ int useColors)
+{
+}
+
+/**/
+static void vDM_drawMappedEdges(
+ DerivedMesh *dm,
+ int (*setDrawOptions)(void *userData, int index),
+ void *userData)
+{
+}
+
+/**/
+static void vDM_drawMappedEdgesInterp(
+ DerivedMesh *dm,
+ int (*setDrawOptions)(void *userData, int index),
+ void (*setDrawInterpOptions)(void *userData, int index, float t),
+ void *userData)
+{
+}
+
+/* free all DerivedMesh data */
+static void vDM_release(DerivedMesh *dm)
+{
+ VDerivedMesh *vdm = (VDerivedMesh*)dm;
+
+ if (DM_release(dm)) {
+ if(vdm->vertexCos) MEM_freeN(vdm->vertexCos);
+ MEM_freeN(vdm);
+ }
+}
+
+/* create derived mesh from verse mesh ... it is used in object mode, when some other client can
+ * change shared data and want to see this changes in real time too */
+DerivedMesh *derivedmesh_from_versemesh(VNode *vnode, float (*vertexCos)[3])
+{
+ VDerivedMesh *vdm = MEM_callocN(sizeof(*vdm), "vdm");
+
+ vdm->vnode = vnode;
+ vdm->vertex_layer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER);
+ vdm->polygon_layer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER);
+ vdm->edges = &((VGeomData*)vnode->data)->edges;
+
+ /* vertex and polygon layer has to exist */
+ if(vdm->vertex_layer && vdm->polygon_layer)
+ DM_init(&vdm->dm, vdm->vertex_layer->dl.da.count, BLI_countlist(vdm->edges), vdm->polygon_layer->dl.da.count);
+ else
+ DM_init(&vdm->dm, 0, 0, 0);
+
+ vdm->dm.getMinMax = vDM_getMinMax;
+
+ vdm->dm.getNumVerts = vDM_getNumVerts;
+ vdm->dm.getNumEdges = vDM_getNumEdges;
+ vdm->dm.getNumFaces = vDM_getNumFaces;
+
+ vdm->dm.getVert = vDM_getVert;
+ vdm->dm.getEdge = vDM_getEdge;
+ vdm->dm.getFace = vDM_getFace;
+ vdm->dm.copyVertArray = vDM_copyVertArray;
+ vdm->dm.copyEdgeArray = vDM_copyEdgeArray;
+ vdm->dm.copyFaceArray = vDM_copyFaceArray;
+
+ vdm->dm.foreachMappedVert = vDM_foreachMappedVert;
+ vdm->dm.foreachMappedEdge = vDM_foreachMappedEdge;
+ vdm->dm.foreachMappedFaceCenter = vDM_foreachMappedFaceCenter;
+
+ vdm->dm.getVertCos = vDM_getVertCos;
+ vdm->dm.getVertCo = vDM_getVertCo;
+ vdm->dm.getVertNo = vDM_getVertNo;
+
+ vdm->dm.drawVerts = vDM_drawVerts;
+
+ vdm->dm.drawEdges = vDM_drawEdges;
+ vdm->dm.drawLooseEdges = vDM_drawLooseEdges;
+ vdm->dm.drawUVEdges = vDM_drawUVEdges;
+
+ vdm->dm.drawFacesSolid = vDM_drawFacesSolid;
+ vdm->dm.drawFacesTex = vDM_drawFacesTex;
+ vdm->dm.drawFacesColored = vDM_drawFacesColored;
+
+ vdm->dm.drawMappedFacesTex = vDM_drawMappedFacesTex;
+ vdm->dm.drawMappedFaces = vDM_drawMappedFaces;
+ vdm->dm.drawMappedEdges = vDM_drawMappedEdges;
+ vdm->dm.drawMappedEdgesInterp = vDM_drawMappedEdgesInterp;
+
+ vdm->dm.release = vDM_release;
+
+ vdm->vertexCos = vertexCos;
+
+ return (DerivedMesh*) vdm;
+}
+
+#endif
+
+/***/
+
+DerivedMesh *mesh_create_derived_for_modifier(Object *ob, ModifierData *md)
+{
+ Mesh *me = ob->data;
+ ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ DerivedMesh *dm;
+
+ if (!(md->mode&eModifierMode_Realtime)) return NULL;
+ if (mti->isDisabled && mti->isDisabled(md)) return NULL;
+
+ if (mti->type==eModifierTypeType_OnlyDeform) {
+ int numVerts;
+ float (*deformedVerts)[3] = mesh_getVertexCos(me, &numVerts);
+
+ mti->deformVerts(md, ob, NULL, deformedVerts, numVerts);
+#ifdef WITH_VERSE
+ if(me->vnode) dm = derivedmesh_from_versemesh(me->vnode, deformedVerts);
+ else dm = getMeshDerivedMesh(me, ob, deformedVerts);
+#else
+ dm = getMeshDerivedMesh(me, ob, deformedVerts);
+#endif
+
+ MEM_freeN(deformedVerts);
+ } else {
+ DerivedMesh *tdm = getMeshDerivedMesh(me, ob, NULL);
+ dm = mti->applyModifier(md, ob, tdm, 0, 0);
+
+ if(tdm != dm) tdm->release(tdm);
+ }
+
+ return dm;
+}
+
+CustomDataMask get_viewedit_datamask()
+{
+ CustomDataMask mask = CD_MASK_BAREMESH;
+ ScrArea *sa;
+
+ /* check if we need tfaces & mcols due to face select or texture paint */
+ if(FACESEL_PAINT_TEST || G.f & G_TEXTUREPAINT) {
+ mask |= CD_MASK_MTFACE | CD_MASK_MCOL;
+ } else {
+ /* check if we need tfaces & mcols due to view mode */
+ for(sa = G.curscreen->areabase.first; sa; sa = sa->next) {
+ if(sa->spacetype == SPACE_VIEW3D) {
+ View3D *view = sa->spacedata.first;
+ if(view->drawtype == OB_SHADED) {
+ /* this includes normals for mesh_create_shadedColors */
+ mask |= CD_MASK_MTFACE | CD_MASK_MCOL | CD_MASK_NORMAL;
+ }
+ if((view->drawtype == OB_TEXTURE) || ((view->drawtype == OB_SOLID) && (view->flag2 & V3D_SOLID_TEX))) {
+ mask |= CD_MASK_MTFACE | CD_MASK_MCOL;
+ }
+ }
+ }
+ }
+
+ /* check if we need mcols due to vertex paint or weightpaint */
+ if(G.f & G_VERTEXPAINT || G.f & G_WEIGHTPAINT)
+ mask |= CD_MASK_MCOL;
+
+ return mask;
+}
+
+static void mesh_calc_modifiers(Object *ob, float (*inputVertexCos)[3],
+ DerivedMesh **deform_r, DerivedMesh **final_r,
+ int useRenderParams, int useDeform,
+ int needMapping, CustomDataMask dataMask)
+{
+ Mesh *me = ob->data;
+ ModifierData *md = modifiers_getVirtualModifierList(ob);
+ LinkNode *datamasks, *curr;
+ float (*deformedVerts)[3] = NULL;
+ DerivedMesh *dm;
+ int numVerts = me->totvert;
+ int fluidsimMeshUsed = 0;
+ int required_mode;
+
+ modifiers_clearErrors(ob);
+
+ /* we always want to keep original indices */
+ dataMask |= CD_MASK_ORIGINDEX;
+
+ datamasks = modifiers_calcDataMasks(md, dataMask);
+ curr = datamasks;
+
+ if(deform_r) *deform_r = NULL;
+ *final_r = NULL;
+
+ /* replace original mesh by fluidsim surface mesh for fluidsim
+ * domain objects
+ */
+ if((G.obedit!=ob) && !needMapping) {
+ if((ob->fluidsimFlag & OB_FLUIDSIM_ENABLE) &&
+ (1) && (!give_parteff(ob)) ) { // doesnt work together with particle systems!
+ if(ob->fluidsimSettings->type & OB_FLUIDSIM_DOMAIN) {
+ loadFluidsimMesh(ob,useRenderParams);
+ fluidsimMeshUsed = 1;
+ /* might have changed... */
+ me = ob->data;
+ numVerts = me->totvert;
+ }
+ }
+ }
+
+ if(useRenderParams) required_mode = eModifierMode_Render;
+ else required_mode = eModifierMode_Realtime;
+
+ if(useDeform) {
+ if(do_ob_key(ob)) /* shape key makes deform verts */
+ deformedVerts = mesh_getVertexCos(me, &numVerts);
+
+ /* Apply all leading deforming modifiers */
+ for(; md; md = md->next, curr = curr->next) {
+ ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ if((md->mode & required_mode) != required_mode) continue;
+ if(mti->isDisabled && mti->isDisabled(md)) continue;
+
+ if(mti->type == eModifierTypeType_OnlyDeform) {
+ if(!deformedVerts)
+ deformedVerts = mesh_getVertexCos(me, &numVerts);
+
+ mti->deformVerts(md, ob, NULL, deformedVerts, numVerts);
+ } else {
+ break;
+ }
+ }
+
+ /* Result of all leading deforming modifiers is cached for
+ * places that wish to use the original mesh but with deformed
+ * coordinates (vpaint, etc.)
+ */
+ if (deform_r) {
+#ifdef WITH_VERSE
+ if(me->vnode) *deform_r = derivedmesh_from_versemesh(me->vnode, deformedVerts);
+ else {
+ *deform_r = CDDM_from_mesh(me, ob);
+ if(deformedVerts) {
+ CDDM_apply_vert_coords(*deform_r, deformedVerts);
+ CDDM_calc_normals(*deform_r);
+ }
+ }
+#else
+ *deform_r = CDDM_from_mesh(me, ob);
+ if(deformedVerts) {
+ CDDM_apply_vert_coords(*deform_r, deformedVerts);
+ CDDM_calc_normals(*deform_r);
+ }
+#endif
+ }
+ } else {
+ if(!fluidsimMeshUsed) {
+ /* default behaviour for meshes */
+ if(inputVertexCos)
+ deformedVerts = inputVertexCos;
+ else
+ deformedVerts = mesh_getRefKeyCos(me, &numVerts);
+ } else {
+ /* the fluid sim mesh might have more vertices than the original
+ * one, so inputVertexCos shouldnt be used
+ */
+ deformedVerts = mesh_getVertexCos(me, &numVerts);
+ }
+ }
+
+
+ /* Now apply all remaining modifiers. If useDeform is off then skip
+ * OnlyDeform ones.
+ */
+ dm = NULL;
+
+#ifdef WITH_VERSE
+ /* hack to make sure modifiers don't try to use mesh data from a verse
+ * node
+ */
+ if(me->vnode) dm = derivedmesh_from_versemesh(me->vnode, deformedVerts);
+#endif
+
+ for(; md; md = md->next, curr = curr->next) {
+ ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ if((md->mode & required_mode) != required_mode) continue;
+ if(mti->type == eModifierTypeType_OnlyDeform && !useDeform) continue;
+ if((mti->flags & eModifierTypeFlag_RequiresOriginalData) && dm) {
+ modifier_setError(md, "Internal error, modifier requires "
+ "original data (bad stack position).");
+ continue;
+ }
+ if(mti->isDisabled && mti->isDisabled(md)) continue;
+ if(needMapping && !modifier_supportsMapping(md)) continue;
+
+ /* How to apply modifier depends on (a) what we already have as
+ * a result of previous modifiers (could be a DerivedMesh or just
+ * deformed vertices) and (b) what type the modifier is.
+ */
+
+ if(mti->type == eModifierTypeType_OnlyDeform) {
+ /* No existing verts to deform, need to build them. */
+ if(!deformedVerts) {
+ if(dm) {
+ /* Deforming a derived mesh, read the vertex locations
+ * out of the mesh and deform them. Once done with this
+ * run of deformers verts will be written back.
+ */
+ numVerts = dm->getNumVerts(dm);
+ deformedVerts =
+ MEM_mallocN(sizeof(*deformedVerts) * numVerts, "dfmv");
+ dm->getVertCos(dm, deformedVerts);
+ } else {
+ deformedVerts = mesh_getVertexCos(me, &numVerts);
+ }
+ }
+
+ mti->deformVerts(md, ob, dm, deformedVerts, numVerts);
+ } else {
+ DerivedMesh *ndm;
+
+ /* apply vertex coordinates or build a DerivedMesh as necessary */
+ if(dm) {
+ if(deformedVerts) {
+ DerivedMesh *tdm = CDDM_copy(dm);
+ dm->release(dm);
+ dm = tdm;
+
+ CDDM_apply_vert_coords(dm, deformedVerts);
+ CDDM_calc_normals(dm);
+ }
+ } else {
+ dm = CDDM_from_mesh(me, ob);
+
+ if(deformedVerts) {
+ CDDM_apply_vert_coords(dm, deformedVerts);
+ CDDM_calc_normals(dm);
+ }
+ }
+
+ /* set the DerivedMesh to only copy needed data */
+ DM_set_only_copy(dm, (CustomDataMask)curr->link);
+
+ ndm = mti->applyModifier(md, ob, dm, useRenderParams,
+ !inputVertexCos);
+
+ if(ndm) {
+ /* if the modifier returned a new dm, release the old one */
+ if(dm && dm != ndm) dm->release(dm);
+
+ dm = ndm;
+
+ if(deformedVerts) {
+ if(deformedVerts != inputVertexCos)
+ MEM_freeN(deformedVerts);
+
+ deformedVerts = NULL;
+ }
+ }
+ }
+ }
+
+ /* Yay, we are done. If we have a DerivedMesh and deformed vertices
+ * need to apply these back onto the DerivedMesh. If we have no
+ * DerivedMesh then we need to build one.
+ */
+ if(dm && deformedVerts) {
+ *final_r = CDDM_copy(dm);
+
+ dm->release(dm);
+
+ CDDM_apply_vert_coords(*final_r, deformedVerts);
+ CDDM_calc_normals(*final_r);
+ } else if(dm) {
+ *final_r = dm;
+ } else {
+#ifdef WITH_VERSE
+ if(me->vnode)
+ *final_r = derivedmesh_from_versemesh(me->vnode, deformedVerts);
+ else {
+ *final_r = CDDM_from_mesh(me, ob);
+ if(deformedVerts) {
+ CDDM_apply_vert_coords(*final_r, deformedVerts);
+ CDDM_calc_normals(*final_r);
+ }
+ }
+#else
+ *final_r = CDDM_from_mesh(me, ob);
+ if(deformedVerts) {
+ CDDM_apply_vert_coords(*final_r, deformedVerts);
+ CDDM_calc_normals(*final_r);
+ }
+#endif
+ }
+
+ if(deformedVerts && deformedVerts != inputVertexCos)
+ MEM_freeN(deformedVerts);
+
+ BLI_linklist_free(datamasks, NULL);
+
+ /* restore mesh in any case */
+ if(fluidsimMeshUsed) ob->data = ob->fluidsimSettings->orgMesh;
+}
+
+static float (*editmesh_getVertexCos(EditMesh *em, int *numVerts_r))[3]
+{
+ int i, numVerts = *numVerts_r = BLI_countlist(&em->verts);
+ float (*cos)[3];
+ EditVert *eve;
+
+ cos = MEM_mallocN(sizeof(*cos)*numVerts, "vertexcos");
+ for (i=0,eve=em->verts.first; i<numVerts; i++,eve=eve->next) {
+ VECCOPY(cos[i], eve->co);
+ }
+
+ return cos;
+}
+
+static int editmesh_modifier_is_enabled(ModifierData *md, DerivedMesh *dm)
+{
+ ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ int required_mode = eModifierMode_Realtime | eModifierMode_Editmode;
+
+ if((md->mode & required_mode) != required_mode) return 0;
+ if((mti->flags & eModifierTypeFlag_RequiresOriginalData) && dm) {
+ modifier_setError(md, "Internal error, modifier requires"
+ "original data (bad stack position).");
+ return 0;
+ }
+ if(mti->isDisabled && mti->isDisabled(md)) return 0;
+ if(!(mti->flags & eModifierTypeFlag_SupportsEditmode)) return 0;
+ if(md->mode & eModifierMode_DisableTemporary) return 0;
+
+ return 1;
+}
+
+static void editmesh_calc_modifiers(DerivedMesh **cage_r,
+ DerivedMesh **final_r,
+ CustomDataMask dataMask)
+{
+ Object *ob = G.obedit;
+ EditMesh *em = G.editMesh;
+ ModifierData *md;
+ float (*deformedVerts)[3] = NULL;
+ DerivedMesh *dm;
+ int i, numVerts = 0, cageIndex = modifiers_getCageIndex(ob, NULL);
+ LinkNode *datamasks, *curr;
+
+ modifiers_clearErrors(ob);
+
+ if(cage_r && cageIndex == -1) {
+ *cage_r = getEditMeshDerivedMesh(em, ob, NULL);
+ }
+
+ dm = NULL;
+ md = ob->modifiers.first;
+
+ /* we always want to keep original indices */
+ dataMask |= CD_MASK_ORIGINDEX;
+
+ datamasks = modifiers_calcDataMasks(md, dataMask);
+
+ curr = datamasks;
+ for(i = 0; md; i++, md = md->next, curr = curr->next) {
+ ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ if(!editmesh_modifier_is_enabled(md, dm))
+ continue;
+
+ /* How to apply modifier depends on (a) what we already have as
+ * a result of previous modifiers (could be a DerivedMesh or just
+ * deformed vertices) and (b) what type the modifier is.
+ */
+
+ if(mti->type == eModifierTypeType_OnlyDeform) {
+ /* No existing verts to deform, need to build them. */
+ if(!deformedVerts) {
+ if(dm) {
+ /* Deforming a derived mesh, read the vertex locations
+ * out of the mesh and deform them. Once done with this
+ * run of deformers verts will be written back.
+ */
+ numVerts = dm->getNumVerts(dm);
+ deformedVerts =
+ MEM_mallocN(sizeof(*deformedVerts) * numVerts, "dfmv");
+ dm->getVertCos(dm, deformedVerts);
+ } else {
+ deformedVerts = editmesh_getVertexCos(em, &numVerts);
+ }
+ }
+
+ mti->deformVertsEM(md, ob, em, dm, deformedVerts, numVerts);
+ } else {
+ DerivedMesh *ndm;
+
+ /* apply vertex coordinates or build a DerivedMesh as necessary */
+ if(dm) {
+ if(deformedVerts) {
+ DerivedMesh *tdm = CDDM_copy(dm);
+ if(!(cage_r && dm == *cage_r)) dm->release(dm);
+ dm = tdm;
+
+ CDDM_apply_vert_coords(dm, deformedVerts);
+ CDDM_calc_normals(dm);
+ } else if(cage_r && dm == *cage_r) {
+ /* dm may be changed by this modifier, so we need to copy it
+ */
+ dm = CDDM_copy(dm);
+ }
+
+ } else {
+ dm = CDDM_from_editmesh(em, ob->data);
+
+ if(deformedVerts) {
+ CDDM_apply_vert_coords(dm, deformedVerts);
+ CDDM_calc_normals(dm);
+ }
+ }
+
+ /* set the DerivedMesh to only copy needed data */
+ DM_set_only_copy(dm, (CustomDataMask)curr->link);
+
+ ndm = mti->applyModifierEM(md, ob, em, dm);
+
+ if (ndm) {
+ if(dm && dm != ndm)
+ dm->release(dm);
+
+ dm = ndm;
+
+ if (deformedVerts) {
+ MEM_freeN(deformedVerts);
+ deformedVerts = NULL;
+ }
+ }
+ }
+
+ if(cage_r && i == cageIndex) {
+ if(dm && deformedVerts) {
+ *cage_r = CDDM_copy(dm);
+ CDDM_apply_vert_coords(*cage_r, deformedVerts);
+ } else if(dm) {
+ *cage_r = dm;
+ } else {
+ *cage_r =
+ getEditMeshDerivedMesh(em, ob,
+ deformedVerts ? MEM_dupallocN(deformedVerts) : NULL);
+ }
+ }
+ }
+
+ BLI_linklist_free(datamasks, NULL);
+
+ /* Yay, we are done. If we have a DerivedMesh and deformed vertices need
+ * to apply these back onto the DerivedMesh. If we have no DerivedMesh
+ * then we need to build one.
+ */
+ if(dm && deformedVerts) {
+ *final_r = CDDM_copy(dm);
+
+ if(!(cage_r && dm == *cage_r)) dm->release(dm);
+
+ CDDM_apply_vert_coords(*final_r, deformedVerts);
+ CDDM_calc_normals(*final_r);
+ } else if (dm) {
+ *final_r = dm;
+ } else if (!deformedVerts && cage_r && *cage_r) {
+ *final_r = *cage_r;
+ } else {
+ *final_r = getEditMeshDerivedMesh(em, ob, deformedVerts);
+ deformedVerts = NULL;
+ }
+
+ if(deformedVerts)
+ MEM_freeN(deformedVerts);
+}
+
+/***/
+
+
+ /* Something of a hack, at the moment deal with weightpaint
+ * by tucking into colors during modifier eval, only in
+ * wpaint mode. Works ok but need to make sure recalc
+ * happens on enter/exit wpaint.
+ */
+
+void weight_to_rgb(float input, float *fr, float *fg, float *fb)
+{
+ float blend;
+
+ blend= ((input/2.0f)+0.5f);
+
+ if (input<=0.25f){ // blue->cyan
+ *fr= 0.0f;
+ *fg= blend*input*4.0f;
+ *fb= blend;
+ }
+ else if (input<=0.50f){ // cyan->green
+ *fr= 0.0f;
+ *fg= blend;
+ *fb= blend*(1.0f-((input-0.25f)*4.0f));
+ }
+ else if (input<=0.75){ // green->yellow
+ *fr= blend * ((input-0.50f)*4.0f);
+ *fg= blend;
+ *fb= 0.0f;
+ }
+ else if (input<=1.0){ // yellow->red
+ *fr= blend;
+ *fg= blend * (1.0f-((input-0.75f)*4.0f));
+ *fb= 0.0f;
+ }
+}
+static void calc_weightpaint_vert_color(Object *ob, ColorBand *coba, int vert, unsigned char *col)
+{
+ Mesh *me = ob->data;
+ float colf[4], input = 0.0f;
+ int i;
+
+ if (me->dvert) {
+ for (i=0; i<me->dvert[vert].totweight; i++)
+ if (me->dvert[vert].dw[i].def_nr==ob->actdef-1)
+ input+=me->dvert[vert].dw[i].weight;
+ }
+
+ CLAMP(input, 0.0f, 1.0f);
+
+ if(coba)
+ do_colorband(coba, input, colf);
+ else
+ weight_to_rgb(input, colf, colf+1, colf+2);
+
+ col[3] = (unsigned char)(colf[0] * 255.0f);
+ col[2] = (unsigned char)(colf[1] * 255.0f);
+ col[1] = (unsigned char)(colf[2] * 255.0f);
+ col[0] = 255;
+}
+
+static ColorBand *stored_cb= NULL;
+
+void vDM_ColorBand_store(ColorBand *coba)
+{
+ stored_cb= coba;
+}
+
+static unsigned char *calc_weightpaint_colors(Object *ob)
+{
+ Mesh *me = ob->data;
+ MFace *mf = me->mface;
+ ColorBand *coba= stored_cb; /* warning, not a local var */
+ unsigned char *wtcol;
+ int i;
+
+ wtcol = MEM_callocN (sizeof (unsigned char) * me->totface*4*4, "weightmap");
+
+ memset(wtcol, 0x55, sizeof (unsigned char) * me->totface*4*4);
+ for (i=0; i<me->totface; i++, mf++) {
+ calc_weightpaint_vert_color(ob, coba, mf->v1, &wtcol[(i*4 + 0)*4]);
+ calc_weightpaint_vert_color(ob, coba, mf->v2, &wtcol[(i*4 + 1)*4]);
+ calc_weightpaint_vert_color(ob, coba, mf->v3, &wtcol[(i*4 + 2)*4]);
+ if (mf->v4)
+ calc_weightpaint_vert_color(ob, coba, mf->v4, &wtcol[(i*4 + 3)*4]);
+ }
+
+ return wtcol;
+}
+
+static void clear_mesh_caches(Object *ob)
+{
+ Mesh *me= ob->data;
+
+ /* also serves as signal to remake texspace */
+ if (me->bb) {
+ MEM_freeN(me->bb);
+ me->bb = NULL;
+ }
+
+ freedisplist(&ob->disp);
+
+ if (ob->derivedFinal) {
+ ob->derivedFinal->needsFree = 1;
+ ob->derivedFinal->release(ob->derivedFinal);
+ ob->derivedFinal= NULL;
+ }
+ if (ob->derivedDeform) {
+ ob->derivedDeform->needsFree = 1;
+ ob->derivedDeform->release(ob->derivedDeform);
+ ob->derivedDeform= NULL;
+ }
+}
+
+static void mesh_build_data(Object *ob, CustomDataMask dataMask)
+{
+ Mesh *me = ob->data;
+ float min[3], max[3];
+
+ clear_mesh_caches(ob);
+
+ if(ob!=G.obedit) {
+ Object *obact = G.scene->basact?G.scene->basact->object:NULL;
+ int editing = (FACESEL_PAINT_TEST);
+ int needMapping = editing && (ob==obact);
+
+ if( (G.f & G_WEIGHTPAINT) && ob==obact ) {
+ MCol *wpcol = (MCol*)calc_weightpaint_colors(ob);
+ int layernum = CustomData_number_of_layers(&me->fdata, CD_MCOL);
+
+ /* ugly hack here, we temporarily add a new active mcol layer with
+ weightpaint colors in it, that is then duplicated in CDDM_from_mesh */
+ CustomData_add_layer(&me->fdata, CD_MCOL, CD_ASSIGN, wpcol, me->totface);
+ CustomData_set_layer_active(&me->fdata, CD_MCOL, layernum);
+
+ mesh_calc_modifiers(ob, NULL, &ob->derivedDeform,
+ &ob->derivedFinal, 0, 1,
+ needMapping, dataMask);
+
+ CustomData_free_layer_active(&me->fdata, CD_MCOL, me->totface);
+ } else {
+ mesh_calc_modifiers(ob, NULL, &ob->derivedDeform,
+ &ob->derivedFinal, 0, 1,
+ needMapping, dataMask);
+ }
+
+ INIT_MINMAX(min, max);
+
+ ob->derivedFinal->getMinMax(ob->derivedFinal, min, max);
+
+ boundbox_set_from_min_max(mesh_get_bb(ob->data), min, max);
+
+ ob->derivedFinal->needsFree = 0;
+ ob->derivedDeform->needsFree = 0;
+ ob->lastDataMask = dataMask;
+ }
+}
+
+static void editmesh_build_data(CustomDataMask dataMask)
+{
+ float min[3], max[3];
+
+ EditMesh *em = G.editMesh;
+
+ clear_mesh_caches(G.obedit);
+
+ if (em->derivedFinal) {
+ if (em->derivedFinal!=em->derivedCage) {
+ em->derivedFinal->needsFree = 1;
+ em->derivedFinal->release(em->derivedFinal);
+ }
+ em->derivedFinal = NULL;
+ }
+ if (em->derivedCage) {
+ em->derivedCage->needsFree = 1;
+ em->derivedCage->release(em->derivedCage);
+ em->derivedCage = NULL;
+ }
+
+ editmesh_calc_modifiers(&em->derivedCage, &em->derivedFinal, dataMask);
+ em->lastDataMask = dataMask;
+
+ INIT_MINMAX(min, max);
+
+ em->derivedFinal->getMinMax(em->derivedFinal, min, max);
+
+ boundbox_set_from_min_max(mesh_get_bb(G.obedit->data), min, max);
+
+ em->derivedFinal->needsFree = 0;
+ em->derivedCage->needsFree = 0;
+}
+
+void makeDerivedMesh(Object *ob, CustomDataMask dataMask)
+{
+ if (ob==G.obedit) {
+ editmesh_build_data(dataMask);
+ } else {
+ PartEff *paf= give_parteff(ob);
+
+ mesh_build_data(ob, dataMask);
+
+ if(paf) {
+ if((paf->flag & PAF_STATIC) || (ob->recalc & OB_RECALC_TIME)==0)
+ build_particle_system(ob);
+ }
+ }
+}
+
+/***/
+
+DerivedMesh *mesh_get_derived_final(Object *ob, CustomDataMask dataMask)
+{
+ /* if there's no derived mesh or the last data mask used doesn't include
+ * the data we need, rebuild the derived mesh
+ */
+ if(!ob->derivedFinal || (dataMask & ob->lastDataMask) != dataMask)
+ mesh_build_data(ob, dataMask);
+
+ return ob->derivedFinal;
+}
+
+DerivedMesh *mesh_get_derived_deform(Object *ob, CustomDataMask dataMask)
+{
+ /* if there's no derived mesh or the last data mask used doesn't include
+ * the data we need, rebuild the derived mesh
+ */
+ if(!ob->derivedDeform || (dataMask & ob->lastDataMask) != dataMask)
+ mesh_build_data(ob, dataMask);
+
+ return ob->derivedDeform;
+}
+
+/* Move to multires Pin level, returns a copy of the original vertex coords. */
+float *multires_render_pin(Object *ob, Mesh *me, int *orig_lvl)
+{
+ float *vert_copy= NULL;
+
+ if(me->mr) {
+ MultiresLevel *lvl= NULL;
+ int i;
+
+ /* Make sure all mesh edits are properly stored in the multires data*/
+ multires_update_levels(me, 1);
+
+ /* Copy the highest level of multires verts */
+ *orig_lvl= me->mr->current;
+ lvl= multires_level_n(me->mr, BLI_countlist(&me->mr->levels));
+ vert_copy= MEM_callocN(sizeof(float)*3*lvl->totvert, "multires vert_copy");
+ for(i=0; i<lvl->totvert; ++i)
+ VecCopyf(&vert_copy[i*3], me->mr->verts[i].co);
+
+ /* Goto the pin level for multires */
+ me->mr->newlvl= me->mr->pinlvl;
+ multires_set_level(ob, me, 1);
+ }
+
+ return vert_copy;
+}
+
+/* Propagate the changes to render level - fails if mesh topology changed */
+void multires_render_final(Object *ob, Mesh *me, DerivedMesh **dm, float *vert_copy, const int orig_lvl)
+{
+ if(me->mr) {
+ if((*dm)->getNumVerts(*dm) == me->totvert &&
+ (*dm)->getNumFaces(*dm) == me->totface) {
+ MultiresLevel *lvl= multires_level_n(me->mr, BLI_countlist(&me->mr->levels));
+ DerivedMesh *old= NULL;
+ int i;
+
+ (*dm)->copyVertArray(*dm, me->mvert);
+ (*dm)->release(*dm);
+
+ me->mr->newlvl= me->mr->renderlvl;
+ multires_set_level(ob, me, 1);
+ (*dm)= getMeshDerivedMesh(me, ob, NULL);
+
+ /* Some of the data in dm is referenced externally, so make a copy */
+ old= *dm;
+ (*dm)= CDDM_copy(old);
+ old->release(old);
+
+ /* Restore the original verts */
+ me->mr->newlvl= BLI_countlist(&me->mr->levels);
+ multires_set_level(ob, me, 1);
+ for(i=0; i<lvl->totvert; ++i)
+ VecCopyf(me->mvert[i].co, &vert_copy[i*3]);
+ }
+
+ if(vert_copy)
+ MEM_freeN(vert_copy);
+
+ me->mr->newlvl= orig_lvl;
+ multires_set_level(ob, me, 1);
+ }
+}
+
+/* Multires note - if mesh has multires enabled, mesh is first set to the Pin level,
+ where all modifiers are applied, then if the topology hasn't changed, the changes
+ from modifiers are propagated up to the Render level. */
+DerivedMesh *mesh_create_derived_render(Object *ob, CustomDataMask dataMask)
+{
+ DerivedMesh *final;
+ Mesh *me= get_mesh(ob);
+ float *vert_copy= NULL;
+ int orig_lvl= 0;
+
+ vert_copy= multires_render_pin(ob, me, &orig_lvl);
+ mesh_calc_modifiers(ob, NULL, NULL, &final, 1, 1, 0, dataMask);
+ multires_render_final(ob, me, &final, vert_copy, orig_lvl);
+
+ return final;
+}
+
+DerivedMesh *mesh_create_derived_view(Object *ob, CustomDataMask dataMask)
+{
+ DerivedMesh *final;
+
+ mesh_calc_modifiers(ob, NULL, NULL, &final, 0, 1, 0, dataMask);
+
+ return final;
+}
+
+DerivedMesh *mesh_create_derived_no_deform(Object *ob, float (*vertCos)[3],
+ CustomDataMask dataMask)
+{
+ DerivedMesh *final;
+
+ mesh_calc_modifiers(ob, vertCos, NULL, &final, 0, 0, 0, dataMask);
+
+ return final;
+}
+
+DerivedMesh *mesh_create_derived_no_deform_render(Object *ob,
+ float (*vertCos)[3],
+ CustomDataMask dataMask)
+{
+ DerivedMesh *final;
+ Mesh *me= get_mesh(ob);
+ float *vert_copy= NULL;
+ int orig_lvl= 0;
+
+ vert_copy= multires_render_pin(ob, me, &orig_lvl);
+ mesh_calc_modifiers(ob, vertCos, NULL, &final, 1, 0, 0, dataMask);
+ multires_render_final(ob, me, &final, vert_copy, orig_lvl);
+
+ return final;
+}
+
+/***/
+
+DerivedMesh *editmesh_get_derived_cage_and_final(DerivedMesh **final_r,
+ CustomDataMask dataMask)
+{
+ /* if there's no derived mesh or the last data mask used doesn't include
+ * the data we need, rebuild the derived mesh
+ */
+ if(!G.editMesh->derivedCage ||
+ (G.editMesh->lastDataMask & dataMask) != dataMask)
+ editmesh_build_data(dataMask);
+
+ *final_r = G.editMesh->derivedFinal;
+ return G.editMesh->derivedCage;
+}
+
+DerivedMesh *editmesh_get_derived_cage(CustomDataMask dataMask)
+{
+ /* if there's no derived mesh or the last data mask used doesn't include
+ * the data we need, rebuild the derived mesh
+ */
+ if(!G.editMesh->derivedCage ||
+ (G.editMesh->lastDataMask & dataMask) != dataMask)
+ editmesh_build_data(dataMask);
+
+ return G.editMesh->derivedCage;
+}
+
+DerivedMesh *editmesh_get_derived_base(void)
+{
+ return getEditMeshDerivedMesh(G.editMesh, G.obedit, NULL);
+}
+
+
+/* ********* For those who don't grasp derived stuff! (ton) :) *************** */
+
+static void make_vertexcosnos__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s)
+{
+ float *vec = userData;
+
+ vec+= 6*index;
+
+ /* check if we've been here before (normal should not be 0) */
+ if(vec[3] || vec[4] || vec[5]) return;
+
+ VECCOPY(vec, co);
+ vec+= 3;
+ if(no_f) {
+ VECCOPY(vec, no_f);
+ }
+ else {
+ VECCOPY(vec, no_s);
+ }
+}
+
+/* always returns original amount me->totvert of vertices and normals, but fully deformed and subsurfered */
+/* this is needed for all code using vertexgroups (no subsurf support) */
+/* it stores the normals as floats, but they can still be scaled as shorts (32767 = unit) */
+/* in use now by vertex/weight paint and particle generating */
+
+float *mesh_get_mapped_verts_nors(Object *ob)
+{
+ Mesh *me= ob->data;
+ DerivedMesh *dm;
+ float *vertexcosnos;
+
+ /* lets prevent crashing... */
+ if(ob->type!=OB_MESH || me->totvert==0)
+ return NULL;
+
+ dm= mesh_get_derived_final(ob, CD_MASK_BAREMESH);
+ vertexcosnos= MEM_callocN(6*sizeof(float)*me->totvert, "vertexcosnos map");
+
+ if(dm->foreachMappedVert) {
+ dm->foreachMappedVert(dm, make_vertexcosnos__mapFunc, vertexcosnos);
+ }
+ else {
+ float *fp= vertexcosnos;
+ int a;
+
+ for(a=0; a< me->totvert; a++, fp+=6) {
+ dm->getVertCo(dm, a, fp);
+ dm->getVertNo(dm, a, fp+3);
+ }
+ }
+
+ dm->release(dm);
+ return vertexcosnos;
+}
+
+/* ********* crazyspace *************** */
+
+int editmesh_get_first_deform_matrices(float (**deformmats)[3][3], float (**deformcos)[3])
+{
+ Object *ob = G.obedit;
+ EditMesh *em = G.editMesh;
+ ModifierData *md;
+ DerivedMesh *dm;
+ int i, a, numleft = 0, numVerts = 0;
+ int cageIndex = modifiers_getCageIndex(ob, NULL);
+ float (*defmats)[3][3] = NULL, (*deformedVerts)[3] = NULL;
+
+ modifiers_clearErrors(ob);
+
+ dm = NULL;
+ md = ob->modifiers.first;
+
+ /* compute the deformation matrices and coordinates for the first
+ modifiers with on cage editing that are enabled and support computing
+ deform matrices */
+ for(i = 0; md && i <= cageIndex; i++, md = md->next) {
+ ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ if(!editmesh_modifier_is_enabled(md, dm))
+ continue;
+
+ if(mti->type==eModifierTypeType_OnlyDeform && mti->deformMatricesEM) {
+ if(!defmats) {
+ dm= getEditMeshDerivedMesh(em, ob, NULL);
+ deformedVerts= editmesh_getVertexCos(em, &numVerts);
+ defmats= MEM_callocN(sizeof(*defmats)*numVerts, "defmats");
+
+ for(a=0; a<numVerts; a++)
+ Mat3One(defmats[a]);
+ }
+
+ mti->deformMatricesEM(md, ob, em, dm, deformedVerts, defmats,
+ numVerts);
+ }
+ else
+ break;
+ }
+
+ for(; md && i <= cageIndex; md = md->next, i++)
+ if(editmesh_modifier_is_enabled(md, dm) && modifier_isDeformer(md))
+ numleft++;
+
+ if(dm)
+ dm->release(dm);
+
+ *deformmats= defmats;
+ *deformcos= deformedVerts;
+
+ return numleft;
+}
+
+/* ************************* fluidsim bobj file handling **************************** */
+
+#ifndef DISABLE_ELBEEM
+
+#ifdef WIN32
+#ifndef snprintf
+#define snprintf _snprintf
+#endif
+#endif
+
+/* write .bobj.gz file for a mesh object */
+void writeBobjgz(char *filename, struct Object *ob, int useGlobalCoords, int append, float time)
+{
+ char debugStrBuffer[256];
+ int wri,i,j,totvert,totface;
+ float wrf;
+ gzFile gzf;
+ DerivedMesh *dm;
+ float vec[3];
+ float rotmat[3][3];
+ MVert *mvert;
+ MFace *mface;
+ //if(append)return; // DEBUG
+
+ if(!ob->data || (ob->type!=OB_MESH)) {
+ snprintf(debugStrBuffer,256,"Writing GZ_BOBJ Invalid object %s ...\n", ob->id.name);
+ elbeemDebugOut(debugStrBuffer);
+ return;
+ }
+ if((ob->size[0]<0.0) || (ob->size[0]<0.0) || (ob->size[0]<0.0) ) {
+ snprintf(debugStrBuffer,256,"\nfluidSim::writeBobjgz:: Warning object %s has negative scaling - check triangle ordering...?\n\n", ob->id.name);
+ elbeemDebugOut(debugStrBuffer);
+ }
+
+ snprintf(debugStrBuffer,256,"Writing GZ_BOBJ '%s' ... ",filename); elbeemDebugOut(debugStrBuffer);
+ if(append) gzf = gzopen(filename, "a+b9");
+ else gzf = gzopen(filename, "wb9");
+ if (!gzf) {
+ snprintf(debugStrBuffer,256,"writeBobjgz::error - Unable to open file for writing '%s'\n", filename);
+ elbeemDebugOut(debugStrBuffer);
+ return;
+ }
+
+ dm = mesh_create_derived_render(ob, CD_MASK_BAREMESH);
+ //dm = mesh_create_derived_no_deform(ob,NULL);
+
+ mvert = dm->getVertArray(dm);
+ mface = dm->getFaceArray(dm);
+ totvert = dm->getNumVerts(dm);
+ totface = dm->getNumFaces(dm);
+
+ // write time value for appended anim mesh
+ if(append) {
+ gzwrite(gzf, &time, sizeof(time));
+ }
+
+ // continue with verts/norms
+ if(sizeof(wri)!=4) { snprintf(debugStrBuffer,256,"Writing GZ_BOBJ, Invalid int size %d...\n", wri); elbeemDebugOut(debugStrBuffer); return; } // paranoia check
+ wri = dm->getNumVerts(dm);
+ mvert = dm->getVertArray(dm);
+ gzwrite(gzf, &wri, sizeof(wri));
+ for(i=0; i<wri;i++) {
+ VECCOPY(vec, mvert[i].co);
+ if(useGlobalCoords) { Mat4MulVecfl(ob->obmat, vec); }
+ for(j=0; j<3; j++) {
+ wrf = vec[j];
+ gzwrite(gzf, &wrf, sizeof( wrf ));
+ }
+ }
+
+ // should be the same as Vertices.size
+ wri = totvert;
+ gzwrite(gzf, &wri, sizeof(wri));
+ EulToMat3(ob->rot, rotmat);
+ for(i=0; i<wri;i++) {
+ VECCOPY(vec, mvert[i].no);
+ Normalize(vec);
+ if(useGlobalCoords) { Mat3MulVecfl(rotmat, vec); }
+ for(j=0; j<3; j++) {
+ wrf = vec[j];
+ gzwrite(gzf, &wrf, sizeof( wrf ));
+ }
+ }
+
+ // append only writes verts&norms
+ if(!append) {
+ //float side1[3],side2[3],norm1[3],norm2[3];
+ //float inpf;
+
+ // compute no. of triangles
+ wri = 0;
+ for(i=0; i<totface; i++) {
+ wri++;
+ if(mface[i].v4) { wri++; }
+ }
+ gzwrite(gzf, &wri, sizeof(wri));
+ for(i=0; i<totface; i++) {
+
+ int face[4];
+ face[0] = mface[i].v1;
+ face[1] = mface[i].v2;
+ face[2] = mface[i].v3;
+ face[3] = mface[i].v4;
+ //snprintf(debugStrBuffer,256,"F %s %d = %d,%d,%d,%d \n",ob->id.name, i, face[0],face[1],face[2],face[3] ); elbeemDebugOut(debugStrBuffer);
+ //VecSubf(side1, mvert[face[1]].co,mvert[face[0]].co);
+ //VecSubf(side2, mvert[face[2]].co,mvert[face[0]].co);
+ //Crossf(norm1,side1,side2);
+ gzwrite(gzf, &(face[0]), sizeof( face[0] ));
+ gzwrite(gzf, &(face[1]), sizeof( face[1] ));
+ gzwrite(gzf, &(face[2]), sizeof( face[2] ));
+ if(face[3]) {
+ //VecSubf(side1, mvert[face[2]].co,mvert[face[0]].co);
+ //VecSubf(side2, mvert[face[3]].co,mvert[face[0]].co);
+ //Crossf(norm2,side1,side2);
+ //inpf = Inpf(norm1,norm2);
+ //if(inpf>0.) {
+ gzwrite(gzf, &(face[0]), sizeof( face[0] ));
+ gzwrite(gzf, &(face[2]), sizeof( face[2] ));
+ gzwrite(gzf, &(face[3]), sizeof( face[3] ));
+ //} else {
+ //gzwrite(gzf, &(face[0]), sizeof( face[0] ));
+ //gzwrite(gzf, &(face[3]), sizeof( face[3] ));
+ //gzwrite(gzf, &(face[2]), sizeof( face[2] ));
+ //}
+ } // quad
+ }
+ }
+
+ snprintf(debugStrBuffer,256,"Done. #Vertices: %d, #Triangles: %d\n", totvert, totface );
+ elbeemDebugOut(debugStrBuffer);
+
+ gzclose( gzf );
+ dm->release(dm);
+}
+
+void initElbeemMesh(struct Object *ob,
+ int *numVertices, float **vertices,
+ int *numTriangles, int **triangles,
+ int useGlobalCoords)
+{
+ DerivedMesh *dm = NULL;
+ MVert *mvert;
+ MFace *mface;
+ int countTris=0, i, totvert, totface;
+ float *verts;
+ int *tris;
+
+ dm = mesh_create_derived_render(ob, CD_MASK_BAREMESH);
+ //dm = mesh_create_derived_no_deform(ob,NULL);
+
+ mvert = dm->getVertArray(dm);
+ mface = dm->getFaceArray(dm);
+ totvert = dm->getNumVerts(dm);
+ totface = dm->getNumFaces(dm);
+
+ *numVertices = totvert;
+ verts = MEM_callocN( totvert*3*sizeof(float), "elbeemmesh_vertices");
+ for(i=0; i<totvert; i++) {
+ VECCOPY( &verts[i*3], mvert[i].co);
+ if(useGlobalCoords) { Mat4MulVecfl(ob->obmat, &verts[i*3]); }
+ }
+ *vertices = verts;
+
+ for(i=0; i<totface; i++) {
+ countTris++;
+ if(mface[i].v4) { countTris++; }
+ }
+ *numTriangles = countTris;
+ tris = MEM_callocN( countTris*3*sizeof(int), "elbeemmesh_triangles");
+ countTris = 0;
+ for(i=0; i<totface; i++) {
+ int face[4];
+ face[0] = mface[i].v1;
+ face[1] = mface[i].v2;
+ face[2] = mface[i].v3;
+ face[3] = mface[i].v4;
+
+ tris[countTris*3+0] = face[0];
+ tris[countTris*3+1] = face[1];
+ tris[countTris*3+2] = face[2];
+ countTris++;
+ if(face[3]) {
+ tris[countTris*3+0] = face[0];
+ tris[countTris*3+1] = face[2];
+ tris[countTris*3+2] = face[3];
+ countTris++;
+ }
+ }
+ *triangles = tris;
+
+ dm->release(dm);
+}
+
+/* read .bobj.gz file into a fluidsimDerivedMesh struct */
+Mesh* readBobjgz(char *filename, Mesh *orgmesh, float* bbstart, float *bbsize) //, fluidsimDerivedMesh *fsdm)
+{
+ int wri,i,j;
+ char debugStrBuffer[256];
+ float wrf;
+ Mesh *newmesh;
+ const int debugBobjRead = 1;
+ // init data from old mesh (materials,flags)
+ MFace *origMFace = &((MFace*) orgmesh->mface)[0];
+ int mat_nr = -1;
+ int flag = -1;
+ MFace *fsface = NULL;
+ int gotBytes;
+ gzFile gzf;
+
+ if(!orgmesh) return NULL;
+ if(!origMFace) return NULL;
+ mat_nr = origMFace->mat_nr;
+ flag = origMFace->flag;
+
+ // similar to copy_mesh
+ newmesh = MEM_dupallocN(orgmesh);
+ newmesh->mat= orgmesh->mat;
+
+ newmesh->mvert= NULL;
+ newmesh->medge= NULL;
+ newmesh->mface= NULL;
+ newmesh->mtface= NULL;
+
+ newmesh->dvert = NULL;
+
+ newmesh->mcol= NULL;
+ newmesh->msticky= NULL;
+ newmesh->texcomesh= NULL;
+ memset(&newmesh->vdata, 0, sizeof(newmesh->vdata));
+ memset(&newmesh->edata, 0, sizeof(newmesh->edata));
+ memset(&newmesh->fdata, 0, sizeof(newmesh->fdata));
+
+ newmesh->key= NULL;
+ newmesh->totface = 0;
+ newmesh->totvert = 0;
+ newmesh->totedge = 0;
+ newmesh->medge = NULL;
+
+
+ snprintf(debugStrBuffer,256,"Reading '%s' GZ_BOBJ... ",filename); elbeemDebugOut(debugStrBuffer);
+ gzf = gzopen(filename, "rb");
+ // gzf = fopen(filename, "rb");
+ // debug: fread(b,c,1,a) = gzread(a,b,c)
+ if (!gzf) {
+ //snprintf(debugStrBuffer,256,"readBobjgz::error - Unable to open file for reading '%s'\n", filename); // DEBUG
+ MEM_freeN(newmesh);
+ return NULL;
+ }
+
+ //if(sizeof(wri)!=4) { snprintf(debugStrBuffer,256,"Reading GZ_BOBJ, Invalid int size %d...\n", wri); return NULL; } // paranoia check
+ gotBytes = gzread(gzf, &wri, sizeof(wri));
+ newmesh->totvert = wri;
+ newmesh->mvert = CustomData_add_layer(&newmesh->vdata, CD_MVERT, CD_CALLOC, NULL, newmesh->totvert);
+ if(debugBobjRead){ snprintf(debugStrBuffer,256,"#vertices %d ", newmesh->totvert); elbeemDebugOut(debugStrBuffer); } //DEBUG
+ for(i=0; i<newmesh->totvert;i++) {
+ //if(debugBobjRead) snprintf(debugStrBuffer,256,"V %d = ",i);
+ for(j=0; j<3; j++) {
+ gotBytes = gzread(gzf, &wrf, sizeof( wrf ));
+ newmesh->mvert[i].co[j] = wrf;
+ //if(debugBobjRead) snprintf(debugStrBuffer,256,"%25.20f ", wrf);
+ }
+ //if(debugBobjRead) snprintf(debugStrBuffer,256,"\n");
+ }
+
+ // should be the same as Vertices.size
+ gotBytes = gzread(gzf, &wri, sizeof(wri));
+ if(wri != newmesh->totvert) {
+ // complain #vertices has to be equal to #normals, reset&abort
+ CustomData_free_layer_active(&newmesh->vdata, CD_MVERT, newmesh->totvert);
+ MEM_freeN(newmesh);
+ snprintf(debugStrBuffer,256,"Reading GZ_BOBJ, #normals=%d, #vertices=%d, aborting...\n", wri,newmesh->totvert );
+ return NULL;
+ }
+ for(i=0; i<newmesh->totvert;i++) {
+ for(j=0; j<3; j++) {
+ gotBytes = gzread(gzf, &wrf, sizeof( wrf ));
+ newmesh->mvert[i].no[j] = (short)(wrf*32767.0f);
+ //newmesh->mvert[i].no[j] = 0.5; // DEBUG tst
+ }
+ //fprintf(stderr," DEBDPCN nm%d, %d = %d,%d,%d \n",
+ //(int)(newmesh->mvert), i, newmesh->mvert[i].no[0], newmesh->mvert[i].no[1], newmesh->mvert[i].no[2]);
+ }
+ //fprintf(stderr," DPCN 0 = %d,%d,%d \n", newmesh->mvert[0].no[0], newmesh->mvert[0].no[1], newmesh->mvert[0].no[2]);
+
+
+ /* compute no. of triangles */
+ gotBytes = gzread(gzf, &wri, sizeof(wri));
+ newmesh->totface = wri;
+ newmesh->mface = CustomData_add_layer(&newmesh->fdata, CD_MFACE, CD_CALLOC, NULL, newmesh->totface);
+ if(debugBobjRead){ snprintf(debugStrBuffer,256,"#faces %d ", newmesh->totface); elbeemDebugOut(debugStrBuffer); } //DEBUG
+ fsface = newmesh->mface;
+ for(i=0; i<newmesh->totface; i++) {
+ int face[4];
+
+ gotBytes = gzread(gzf, &(face[0]), sizeof( face[0] ));
+ gotBytes = gzread(gzf, &(face[1]), sizeof( face[1] ));
+ gotBytes = gzread(gzf, &(face[2]), sizeof( face[2] ));
+ face[3] = 0;
+
+ fsface[i].v1 = face[0];
+ fsface[i].v2 = face[1];
+ fsface[i].v3 = face[2];
+ fsface[i].v4 = face[3];
+ }
+
+ // correct triangles with v3==0 for blender, cycle verts
+ for(i=0; i<newmesh->totface; i++) {
+ if(!fsface[i].v3) {
+ int temp = fsface[i].v1;
+ fsface[i].v1 = fsface[i].v2;
+ fsface[i].v2 = fsface[i].v3;
+ fsface[i].v3 = temp;
+ }
+ }
+
+ gzclose( gzf );
+ for(i=0;i<newmesh->totface;i++) {
+ fsface[i].mat_nr = mat_nr;
+ fsface[i].flag = flag;
+ fsface[i].edcode = ME_V1V2 | ME_V2V3 | ME_V3V1;
+ //snprintf(debugStrBuffer,256,"%d : %d,%d,%d\n", i,fsface[i].mat_nr, fsface[i].flag, fsface[i].edcode );
+ }
+
+ snprintf(debugStrBuffer,256," (%d,%d) done\n", newmesh->totvert,newmesh->totface); elbeemDebugOut(debugStrBuffer); //DEBUG
+ return newmesh;
+}
+
+/* read zipped fluidsim velocities into the co's of the fluidsimsettings normals struct */
+void readVelgz(char *filename, Object *srcob)
+{
+ char debugStrBuffer[256];
+ int wri, i, j;
+ float wrf;
+ gzFile gzf;
+ MVert *vverts = srcob->fluidsimSettings->meshSurfNormals;
+ int len = strlen(filename);
+ Mesh *mesh = srcob->data;
+ // mesh and vverts have to be valid from loading...
+
+ // clean up in any case
+ for(i=0; i<mesh->totvert;i++) {
+ for(j=0; j<3; j++) {
+ vverts[i].co[j] = 0.;
+ }
+ }
+ if(srcob->fluidsimSettings->domainNovecgen>0) return;
+
+ if(len<7) {
+ //printf("readVelgz Eror: invalid filename '%s'\n",filename); // DEBUG
+ return;
+ }
+
+ // .bobj.gz , correct filename
+ // 87654321
+ filename[len-6] = 'v';
+ filename[len-5] = 'e';
+ filename[len-4] = 'l';
+
+ snprintf(debugStrBuffer,256,"Reading '%s' GZ_VEL... ",filename); elbeemDebugOut(debugStrBuffer);
+ gzf = gzopen(filename, "rb");
+ if (!gzf) {
+ //printf("readVelgz Eror: unable to open file '%s'\n",filename); // DEBUG
+ return;
+ }
+
+ gzread(gzf, &wri, sizeof( wri ));
+ if(wri != mesh->totvert) {
+ //printf("readVelgz Eror: invalid no. of velocities %d vs. %d aborting.\n" ,wri ,mesh->totvert ); // DEBUG
+ return;
+ }
+
+ for(i=0; i<mesh->totvert;i++) {
+ for(j=0; j<3; j++) {
+ gzread(gzf, &wrf, sizeof( wrf ));
+ vverts[i].co[j] = wrf;
+ }
+ //if(i<20) fprintf(stderr, "GZ_VELload %d = %f,%f,%f \n",i,vverts[i].co[0],vverts[i].co[1],vverts[i].co[2]); // DEBUG
+ }
+
+ gzclose(gzf);
+}
+
+
+/* ***************************** fluidsim derived mesh ***************************** */
+
+/* check which file to load, and replace old mesh of the object with it */
+/* this replacement is undone at the end of mesh_calc_modifiers */
+void loadFluidsimMesh(Object *srcob, int useRenderParams)
+{
+ Mesh *mesh = NULL;
+ float *bbStart = NULL, *bbSize = NULL;
+ float lastBB[3];
+ int displaymode = 0;
+ int curFrame = G.scene->r.cfra - 1 /*G.scene->r.sfra*/; /* start with 0 at start frame */
+ char targetDir[FILE_MAXFILE+FILE_MAXDIR], targetFile[FILE_MAXFILE+FILE_MAXDIR];
+ char debugStrBuffer[256];
+ //snprintf(debugStrBuffer,256,"loadFluidsimMesh call (obid '%s', rp %d)\n", srcob->id.name, useRenderParams); // debug
+
+ if((!srcob)||(!srcob->fluidsimSettings)) {
+ snprintf(debugStrBuffer,256,"DEBUG - Invalid loadFluidsimMesh call, rp %d, dm %d)\n", useRenderParams, displaymode); // debug
+ elbeemDebugOut(debugStrBuffer); // debug
+ return;
+ }
+ // make sure the original mesh data pointer is stored
+ if(!srcob->fluidsimSettings->orgMesh) {
+ srcob->fluidsimSettings->orgMesh = srcob->data;
+ }
+
+ // free old mesh, if there is one (todo, check if it's still valid?)
+ if(srcob->fluidsimSettings->meshSurface) {
+ Mesh *freeFsMesh = srcob->fluidsimSettings->meshSurface;
+
+ // similar to free_mesh(...) , but no things like unlink...
+ CustomData_free(&freeFsMesh->vdata, freeFsMesh->totvert);
+ CustomData_free(&freeFsMesh->edata, freeFsMesh->totedge);
+ CustomData_free(&freeFsMesh->fdata, freeFsMesh->totface);
+ MEM_freeN(freeFsMesh);
+
+ if(srcob->data == srcob->fluidsimSettings->meshSurface)
+ srcob->data = srcob->fluidsimSettings->orgMesh;
+ srcob->fluidsimSettings->meshSurface = NULL;
+
+ if(srcob->fluidsimSettings->meshSurfNormals) MEM_freeN(srcob->fluidsimSettings->meshSurfNormals);
+ srcob->fluidsimSettings->meshSurfNormals = NULL;
+ }
+
+ // init bounding box
+ bbStart = srcob->fluidsimSettings->bbStart;
+ bbSize = srcob->fluidsimSettings->bbSize;
+ lastBB[0] = bbSize[0]; // TEST
+ lastBB[1] = bbSize[1];
+ lastBB[2] = bbSize[2];
+ fluidsimGetAxisAlignedBB(srcob->fluidsimSettings->orgMesh, srcob->obmat, bbStart, bbSize, &srcob->fluidsimSettings->meshBB);
+ // check free fsmesh... TODO
+
+ if(!useRenderParams) {
+ displaymode = srcob->fluidsimSettings->guiDisplayMode;
+ } else {
+ displaymode = srcob->fluidsimSettings->renderDisplayMode;
+ }
+
+ snprintf(debugStrBuffer,256,"loadFluidsimMesh call (obid '%s', rp %d, dm %d), curFra=%d, sFra=%d #=%d \n",
+ srcob->id.name, useRenderParams, displaymode, G.scene->r.cfra, G.scene->r.sfra, curFrame ); // debug
+ elbeemDebugOut(debugStrBuffer); // debug
+
+ strncpy(targetDir, srcob->fluidsimSettings->surfdataPath, FILE_MAXDIR);
+ // use preview or final mesh?
+ if(displaymode==1) {
+ // just display original object
+ srcob->data = srcob->fluidsimSettings->orgMesh;
+ return;
+ } else if(displaymode==2) {
+ strcat(targetDir,"fluidsurface_preview_#");
+ } else { // 3
+ strcat(targetDir,"fluidsurface_final_#");
+ }
+ BLI_convertstringcode(targetDir, G.sce, curFrame); // fixed #frame-no
+ strcpy(targetFile,targetDir);
+ strcat(targetFile, ".bobj.gz");
+
+ snprintf(debugStrBuffer,256,"loadFluidsimMesh call (obid '%s', rp %d, dm %d) '%s' \n", srcob->id.name, useRenderParams, displaymode, targetFile); // debug
+ elbeemDebugOut(debugStrBuffer); // debug
+
+ if(displaymode!=2) { // dont add bounding box for final
+ mesh = readBobjgz(targetFile, srcob->fluidsimSettings->orgMesh ,NULL,NULL);
+ } else {
+ mesh = readBobjgz(targetFile, srcob->fluidsimSettings->orgMesh, bbSize,bbSize );
+ }
+ if(!mesh) {
+ // switch, abort background rendering when fluidsim mesh is missing
+ const char *strEnvName2 = "BLENDER_ELBEEMBOBJABORT"; // from blendercall.cpp
+ if(G.background==1) {
+ if(getenv(strEnvName2)) {
+ int elevel = atoi(getenv(strEnvName2));
+ if(elevel>0) {
+ printf("Env. var %s set, fluid sim mesh '%s' not found, aborting render...\n",strEnvName2, targetFile);
+ exit(1);
+ }
+ }
+ }
+
+ // display org. object upon failure
+ srcob->data = srcob->fluidsimSettings->orgMesh;
+ return;
+ }
+
+ if((mesh)&&(mesh->totvert>0)) {
+ make_edges(mesh, 0); // 0 = make all edges draw
+ }
+ srcob->fluidsimSettings->meshSurface = mesh;
+ srcob->data = mesh;
+ srcob->fluidsimSettings->meshSurfNormals = MEM_dupallocN(mesh->mvert);
+
+ // load vertex velocities, if they exist...
+ // TODO? use generate flag as loading flag as well?
+ // warning, needs original .bobj.gz mesh loading filename
+ if(displaymode==3) {
+ readVelgz(targetFile, srcob);
+ } else {
+ // no data for preview, only clear...
+ int i,j;
+ for(i=0; i<mesh->totvert;i++) { for(j=0; j<3; j++) { srcob->fluidsimSettings->meshSurfNormals[i].co[j] = 0.; }}
+ }
+
+ //fprintf(stderr,"LOADFLM DEBXHCH fs=%d 3:%d,%d,%d \n", (int)mesh, ((Mesh *)(srcob->fluidsimSettings->meshSurface))->mvert[3].no[0], ((Mesh *)(srcob->fluidsimSettings->meshSurface))->mvert[3].no[1], ((Mesh *)(srcob->fluidsimSettings->meshSurface))->mvert[3].no[2]);
+ return;
+}
+
+/* helper function */
+/* init axis aligned BB for mesh object */
+void fluidsimGetAxisAlignedBB(struct Mesh *mesh, float obmat[][4],
+ /*RET*/ float start[3], /*RET*/ float size[3], /*RET*/ struct Mesh **bbmesh )
+{
+ float bbsx=0.0, bbsy=0.0, bbsz=0.0;
+ float bbex=1.0, bbey=1.0, bbez=1.0;
+ int i;
+ float vec[3];
+
+ VECCOPY(vec, mesh->mvert[0].co);
+ Mat4MulVecfl(obmat, vec);
+ bbsx = vec[0]; bbsy = vec[1]; bbsz = vec[2];
+ bbex = vec[0]; bbey = vec[1]; bbez = vec[2];
+
+ for(i=1; i<mesh->totvert;i++) {
+ VECCOPY(vec, mesh->mvert[i].co);
+ Mat4MulVecfl(obmat, vec);
+
+ if(vec[0] < bbsx){ bbsx= vec[0]; }
+ if(vec[1] < bbsy){ bbsy= vec[1]; }
+ if(vec[2] < bbsz){ bbsz= vec[2]; }
+ if(vec[0] > bbex){ bbex= vec[0]; }
+ if(vec[1] > bbey){ bbey= vec[1]; }
+ if(vec[2] > bbez){ bbez= vec[2]; }
+ }
+
+ // return values...
+ if(start) {
+ start[0] = bbsx;
+ start[1] = bbsy;
+ start[2] = bbsz;
+ }
+ if(size) {
+ size[0] = bbex-bbsx;
+ size[1] = bbey-bbsy;
+ size[2] = bbez-bbsz;
+ }
+
+ // init bounding box mesh?
+ if(bbmesh) {
+ int i,j;
+ Mesh *newmesh = NULL;
+ if(!(*bbmesh)) { newmesh = MEM_callocN(sizeof(Mesh), "fluidsimGetAxisAlignedBB_meshbb"); }
+ else { newmesh = *bbmesh; }
+
+ newmesh->totvert = 8;
+ if(!newmesh->mvert)
+ newmesh->mvert = CustomData_add_layer(&newmesh->vdata, CD_MVERT, CD_CALLOC, NULL, newmesh->totvert);
+ for(i=0; i<8; i++) {
+ for(j=0; j<3; j++) newmesh->mvert[i].co[j] = start[j];
+ }
+
+ newmesh->totface = 6;
+ if(!newmesh->mface)
+ newmesh->mface = CustomData_add_layer(&newmesh->fdata, CD_MFACE, CD_CALLOC, NULL, newmesh->totface);
+
+ *bbmesh = newmesh;
+ }
+}
+
+#else // DISABLE_ELBEEM
+
+/* dummy for mesh_calc_modifiers */
+void loadFluidsimMesh(Object *srcob, int useRenderParams) {
+}
+
+#endif // DISABLE_ELBEEM
+
diff --git a/source/blender/blenkernel/intern/Makefile b/source/blender/blenkernel/intern/Makefile
new file mode 100644
index 00000000000..89b91ed2a8f
--- /dev/null
+++ b/source/blender/blenkernel/intern/Makefile
@@ -0,0 +1,109 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+#
+
+LIBNAME = blenkernel
+DIR = $(OCGDIR)/blender/$(LIBNAME)
+
+include nan_compile.mk
+
+CFLAGS += $(LEVEL_1_C_WARNINGS)
+
+# OpenGL and Python
+CPPFLAGS += -I$(OPENGL_HEADERS)
+CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION)
+
+CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
+# Reference to the types in makesdna and imbuf
+CPPFLAGS += -I../../makesdna
+CPPFLAGS += -I../../imbuf
+# This mod uses the BLI and BLO module
+CPPFLAGS += -I../../blenlib
+CPPFLAGS += -I../../blenloader
+CPPFLAGS += -I../../python
+# also avi is used
+CPPFLAGS += -I../../avi
+CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
+
+# we still refer to /include a bit...
+CPPFLAGS += -I../../include
+
+# to include the render stuff:
+CPPFLAGS += -I../../render/extern/include
+
+# for image stamping
+CPPFLAGS += -I$(NAN_BMFONT)/include
+# for sound
+#CPPFLAGS += -I../../../kernel/gen_system
+CPPFLAGS += $(NAN_SDLCFLAGS)
+
+CPPFLAGS += -I$(NAN_IKSOLVER)/include
+CPPFLAGS += -I$(NAN_DECIMATION)/include
+CPPFLAGS += -I$(NAN_ELBEEM)/include
+
+# path to zlib
+CPPFLAGS += -I$(NAN_ZLIB)/include
+
+#path to nodes
+CPPFLAGS += -I../../nodes
+
+# path to our own external headerfiles
+CPPFLAGS += -I..
+
+ifeq ($(WITH_FREETYPE2), true)
+ CPPFLAGS += -DWITH_FREETYPE2
+ CPPFLAGS += -I$(NAN_FREETYPE)/include
+ CPPFLAGS += -I$(NAN_FREETYPE)/include/freetype2
+endif
+
+ifeq ($(WITH_VERSE), true)
+ CPPFLAGS += -DWITH_VERSE
+ CPPFLAGS += -I$(NAN_VERSE)/include
+endif
+
+ifeq ($(WITH_FFMPEG),true)
+ CPPFLAGS += -DWITH_FFMPEG
+ CPPFLAGS += $(NAN_FFMPEGCFLAGS)
+endif
+
+ifeq ($(WITH_OPENEXR), true)
+ CPPFLAGS += -DWITH_OPENEXR
+endif
+
+ifeq ($(WITH_DDS), true)
+ CPPFLAGS += -DWITH_DDS
+endif
+
+ifeq ($(WITH_QUICKTIME), true)
+ CPPFLAGS += -I../../quicktime
+ CPPFLAGS += -DWITH_QUICKTIME
+endif
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
new file mode 100644
index 00000000000..d202178fc0a
--- /dev/null
+++ b/source/blender/blenkernel/intern/action.c
@@ -0,0 +1,1373 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Full recode, Ton Roosendaal, Crete 2005
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <math.h>
+#include <stdlib.h> /* for NULL */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_action_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_key_types.h"
+#include "DNA_nla_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_action.h"
+#include "BKE_anim.h"
+#include "BKE_armature.h"
+#include "BKE_blender.h"
+#include "BKE_constraint.h"
+#include "BKE_displist.h"
+#include "BKE_global.h"
+#include "BKE_ipo.h"
+#include "BKE_key.h"
+#include "BKE_lattice.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_object.h"
+#include "BKE_utildefines.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+
+#include "nla.h"
+
+/* *********************** NOTE ON POSE AND ACTION **********************
+
+ - Pose is the local (object level) component of armature. The current
+ object pose is saved in files, and (will be) is presorted for dependency
+ - Actions have fewer (or other) channels, and write data to a Pose
+ - Currently ob->pose data is controlled in where_is_pose only. The (recalc)
+ event system takes care of calling that
+ - The NLA system (here too) uses Poses as interpolation format for Actions
+ - Therefore we assume poses to be static, and duplicates of poses have channels in
+ same order, for quick interpolation reasons
+
+ ****************************** (ton) ************************************ */
+
+/* ***************** Library data level operations on action ************** */
+
+static void make_local_action_channels(bAction *act)
+{
+ bActionChannel *chan;
+ bConstraintChannel *conchan;
+
+ for (chan=act->chanbase.first; chan; chan=chan->next) {
+ if(chan->ipo) {
+ if(chan->ipo->id.us==1) {
+ chan->ipo->id.lib= NULL;
+ chan->ipo->id.flag= LIB_LOCAL;
+ new_id(0, (ID *)chan->ipo, 0);
+ }
+ else {
+ chan->ipo= copy_ipo(chan->ipo);
+ }
+ }
+ for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next) {
+ if(conchan->ipo) {
+ if(conchan->ipo->id.us==1) {
+ conchan->ipo->id.lib= NULL;
+ conchan->ipo->id.flag= LIB_LOCAL;
+ new_id(0, (ID *)conchan->ipo, 0);
+ }
+ else {
+ conchan->ipo= copy_ipo(conchan->ipo);
+ }
+ }
+ }
+ }
+}
+
+void make_local_action(bAction *act)
+{
+ Object *ob;
+ bAction *actn;
+ int local=0, lib=0;
+
+ if(act->id.lib==0) return;
+ if(act->id.us==1) {
+ act->id.lib= 0;
+ act->id.flag= LIB_LOCAL;
+ make_local_action_channels(act);
+ new_id(0, (ID *)act, 0);
+ return;
+ }
+
+ ob= G.main->object.first;
+ while(ob) {
+ if(ob->action==act) {
+ if(ob->id.lib) lib= 1;
+ else local= 1;
+ }
+ ob= ob->id.next;
+ }
+
+ if(local && lib==0) {
+ act->id.lib= 0;
+ act->id.flag= LIB_LOCAL;
+ make_local_action_channels(act);
+ new_id(0, (ID *)act, 0);
+ }
+ else if(local && lib) {
+ actn= copy_action(act);
+ actn->id.us= 0;
+
+ ob= G.main->object.first;
+ while(ob) {
+ if(ob->action==act) {
+
+ if(ob->id.lib==0) {
+ ob->action = actn;
+ actn->id.us++;
+ act->id.us--;
+ }
+ }
+ ob= ob->id.next;
+ }
+ }
+}
+
+
+void free_action (bAction *act)
+{
+ bActionChannel *chan;
+
+ /* Free channels */
+ for (chan=act->chanbase.first; chan; chan=chan->next) {
+ if (chan->ipo)
+ chan->ipo->id.us--;
+ free_constraint_channels(&chan->constraintChannels);
+ }
+
+ if (act->chanbase.first)
+ BLI_freelistN(&act->chanbase);
+}
+
+bAction *copy_action (bAction *src)
+{
+ bAction *dst = NULL;
+ bActionChannel *dchan, *schan;
+
+ if (!src) return NULL;
+
+ dst= copy_libblock(src);
+ duplicatelist(&(dst->chanbase), &(src->chanbase));
+
+ for (dchan=dst->chanbase.first, schan=src->chanbase.first; dchan; dchan=dchan->next, schan=schan->next){
+ dchan->ipo = copy_ipo(dchan->ipo);
+ copy_constraint_channels(&dchan->constraintChannels, &schan->constraintChannels);
+ }
+ dst->id.flag |= LIB_FAKEUSER;
+ dst->id.us++;
+ return dst;
+}
+
+
+
+/* ************************ Pose channels *************** */
+
+/* usually used within a loop, so we got a N^2 slowdown */
+bPoseChannel *get_pose_channel(const bPose *pose, const char *name)
+{
+ bPoseChannel *chan;
+
+ if(pose==NULL) return NULL;
+
+ for (chan=pose->chanbase.first; chan; chan=chan->next) {
+ if(chan->name[0] == name[0])
+ if (!strcmp (chan->name, name))
+ return chan;
+ }
+
+ return NULL;
+}
+
+/* Use with care, not on Armature poses but for temporal ones */
+/* (currently used for action constraints and in rebuild_pose) */
+bPoseChannel *verify_pose_channel(bPose* pose, const char* name)
+{
+ bPoseChannel *chan;
+
+ if (!pose) {
+ return NULL;
+ }
+
+ /* See if this channel exists */
+ for (chan=pose->chanbase.first; chan; chan=chan->next) {
+ if (!strcmp (name, chan->name))
+ return chan;
+ }
+
+ /* If not, create it and add it */
+ chan = MEM_callocN(sizeof(bPoseChannel), "verifyPoseChannel");
+
+ strncpy (chan->name, name, 31);
+ /* init vars to prevent math errors */
+ chan->quat[0] = 1.0F;
+ chan->size[0] = chan->size[1] = chan->size[2] = 1.0F;
+
+ chan->limitmin[0]= chan->limitmin[1]= chan->limitmin[2]= -180.0f;
+ chan->limitmax[0]= chan->limitmax[1]= chan->limitmax[2]= 180.0f;
+ chan->stiffness[0]= chan->stiffness[1]= chan->stiffness[2]= 0.0f;
+
+ Mat4One(chan->constinv);
+
+ BLI_addtail (&pose->chanbase, chan);
+
+ return chan;
+}
+
+
+/* dst should be freed already, makes entire duplicate */
+void copy_pose(bPose **dst, bPose *src, int copycon)
+{
+ bPose *outPose;
+ bPoseChannel *pchan;
+ ListBase listb;
+
+ if (!src){
+ *dst=NULL;
+ return;
+ }
+
+ outPose= MEM_callocN(sizeof(bPose), "pose");
+
+ duplicatelist (&outPose->chanbase, &src->chanbase);
+
+ if (copycon) {
+ for (pchan=outPose->chanbase.first; pchan; pchan=pchan->next) {
+ copy_constraints(&listb, &pchan->constraints); // copy_constraints NULLs listb
+ pchan->constraints= listb;
+ pchan->path= NULL;
+ }
+ }
+
+ *dst=outPose;
+}
+
+void free_pose_channels(bPose *pose)
+{
+ bPoseChannel *pchan;
+
+ if (pose->chanbase.first){
+ for (pchan = pose->chanbase.first; pchan; pchan=pchan->next){
+ if(pchan->path)
+ MEM_freeN(pchan->path);
+ free_constraints(&pchan->constraints);
+ }
+ BLI_freelistN (&pose->chanbase);
+ }
+}
+
+static void copy_pose_channel_data(bPoseChannel *pchan, const bPoseChannel *chan)
+{
+ bConstraint *pcon, *con;
+
+ VECCOPY(pchan->loc, chan->loc);
+ VECCOPY(pchan->size, chan->size);
+ QUATCOPY(pchan->quat, chan->quat);
+ pchan->flag= chan->flag;
+
+ con= chan->constraints.first;
+ for(pcon= pchan->constraints.first; pcon; pcon= pcon->next)
+ pcon->enforce= con->enforce;
+}
+
+/* checks for IK constraint, can do more constraints flags later */
+/* pose should be entirely OK */
+void update_pose_constraint_flags(bPose *pose)
+{
+ bPoseChannel *pchan, *parchan;
+ bConstraint *con;
+
+ /* clear */
+ for (pchan = pose->chanbase.first; pchan; pchan=pchan->next) {
+ pchan->constflag= 0;
+ }
+ /* detect */
+ for (pchan = pose->chanbase.first; pchan; pchan=pchan->next) {
+ for(con= pchan->constraints.first; con; con= con->next) {
+ if(con->type==CONSTRAINT_TYPE_KINEMATIC) {
+ bKinematicConstraint *data = (bKinematicConstraint*)con->data;
+
+ pchan->constflag |= PCHAN_HAS_IK;
+
+ if(data->tar==NULL || (data->tar->type==OB_ARMATURE && data->subtarget[0]==0))
+ pchan->constflag |= PCHAN_HAS_TARGET;
+
+ /* negative rootbone = recalc rootbone index. used in do_versions */
+ if(data->rootbone<0) {
+ data->rootbone= 0;
+
+ if(data->flag & CONSTRAINT_IK_TIP) parchan= pchan;
+ else parchan= pchan->parent;
+
+ while(parchan) {
+ data->rootbone++;
+ if((parchan->bone->flag & BONE_CONNECTED)==0)
+ break;
+ parchan= parchan->parent;
+ }
+ }
+ }
+ else pchan->constflag |= PCHAN_HAS_CONST;
+ }
+ }
+}
+
+/* Clears all BONE_UNKEYED flags for every pose channel in every pose
+ * This should only be called on frame changing, when it is acceptable to
+ * do this. Otherwise, these flags should not get cleared as poses may get lost.
+ */
+void framechange_poses_clear_unkeyed(void)
+{
+ Object *ob;
+ bPose *pose;
+ bPoseChannel *pchan;
+
+ /* This needs to be done for each object that has a pose */
+ // TODO: proxies may/may not be correctly handled here... (this needs checking)
+ for (ob= G.main->object.first; ob; ob= ob->id.next) {
+ /* we only need to do this on objects with a pose */
+ if ( (pose= ob->pose) ) {
+ for (pchan= pose->chanbase.first; pchan; pchan= pchan->next) {
+ if (pchan->bone)
+ pchan->bone->flag &= ~BONE_UNKEYED;
+ }
+ }
+ }
+}
+
+/* ************************ END Pose channels *************** */
+
+/* ************************ Action channels *************** */
+
+
+bActionChannel *get_action_channel(bAction *act, const char *name)
+{
+ bActionChannel *chan;
+
+ if (!act || !name)
+ return NULL;
+
+ for (chan = act->chanbase.first; chan; chan=chan->next){
+ if (!strcmp (chan->name, name))
+ return chan;
+ }
+
+ return NULL;
+}
+
+/* returns existing channel, or adds new one. In latter case it doesnt activate it, context is required for that*/
+bActionChannel *verify_action_channel(bAction *act, const char *name)
+{
+ bActionChannel *chan;
+
+ chan= get_action_channel(act, name);
+ if(chan==NULL) {
+ if (!chan) {
+ chan = MEM_callocN (sizeof(bActionChannel), "actionChannel");
+ strncpy (chan->name, name, 31);
+ BLI_addtail (&act->chanbase, chan);
+ }
+ }
+ return chan;
+}
+
+/* ************** time ****************** */
+
+static bActionStrip *get_active_strip(Object *ob)
+{
+ bActionStrip *strip;
+
+ if(ob->action==NULL)
+ return NULL;
+
+ for (strip=ob->nlastrips.first; strip; strip=strip->next)
+ if(strip->flag & ACTSTRIP_ACTIVE)
+ break;
+
+ if(strip && strip->act==ob->action)
+ return strip;
+ return NULL;
+}
+
+/* non clipped mapping of strip */
+static float get_actionstrip_frame(bActionStrip *strip, float cframe, int invert)
+{
+ float length, actlength, repeat;
+
+ if (strip->flag & ACTSTRIP_USESTRIDE)
+ repeat= 1.0f;
+ else
+ repeat= strip->repeat;
+
+ length = strip->end-strip->start;
+ if(length==0.0f)
+ length= 1.0f;
+ actlength = strip->actend-strip->actstart;
+
+
+
+ if(invert)
+ return length*(cframe - strip->actstart)/(repeat*actlength) + strip->start;
+ else
+ return repeat*actlength*(cframe - strip->start)/length + strip->actstart;
+}
+
+/* if the conditions match, it converts current time to strip time */
+float get_action_frame(Object *ob, float cframe)
+{
+ bActionStrip *strip= get_active_strip(ob);
+
+ if(strip)
+ return get_actionstrip_frame(strip, cframe, 0);
+ return cframe;
+}
+
+/* inverted, strip time to current time */
+float get_action_frame_inv(Object *ob, float cframe)
+{
+ bActionStrip *strip= get_active_strip(ob);
+
+ if(strip)
+ return get_actionstrip_frame(strip, cframe, 1);
+ return cframe;
+}
+
+
+/* ************************ Blending with NLA *************** */
+
+static void blend_pose_strides(bPose *dst, bPose *src, float srcweight, short mode)
+{
+ float dstweight;
+
+ switch (mode){
+ case ACTSTRIPMODE_BLEND:
+ dstweight = 1.0F - srcweight;
+ break;
+ case ACTSTRIPMODE_ADD:
+ dstweight = 1.0F;
+ break;
+ default :
+ dstweight = 1.0F;
+ }
+
+ VecLerpf(dst->stride_offset, dst->stride_offset, src->stride_offset, srcweight);
+}
+
+
+/*
+
+bone matching diagram, strips A and B
+
+ .------------------------.
+ | A |
+ '------------------------'
+ . . b2
+ . .-------------v----------.
+ . | B . |
+ . '------------------------'
+ . . .
+ . . .
+offset: . 0 . A-B . A-b2+B
+ . . .
+
+*/
+
+
+static void blend_pose_offset_bone(bActionStrip *strip, bPose *dst, bPose *src, float srcweight, short mode)
+{
+ /* matching offset bones */
+ /* take dst offset, and put src on on that location */
+
+ if(strip->offs_bone[0]==0)
+ return;
+
+ /* are we also blending with matching bones? */
+ if(strip->prev && strip->start>=strip->prev->start) {
+ bPoseChannel *dpchan= get_pose_channel(dst, strip->offs_bone);
+ if(dpchan) {
+ bPoseChannel *spchan= get_pose_channel(src, strip->offs_bone);
+ if(spchan) {
+ float vec[3];
+
+ /* dst->ctime has the internal strip->prev action time */
+ /* map this time to nla time */
+
+ float ctime= get_actionstrip_frame(strip, src->ctime, 1);
+
+ if( ctime > strip->prev->end) {
+ bActionChannel *achan;
+
+ /* add src to dest, minus the position of src on strip->prev->end */
+
+ ctime= get_actionstrip_frame(strip, strip->prev->end, 0);
+
+ achan= get_action_channel(strip->act, strip->offs_bone);
+ if(achan && achan->ipo) {
+ bPoseChannel pchan;
+ /* Evaluates and sets the internal ipo value */
+ calc_ipo(achan->ipo, ctime);
+ /* This call also sets the pchan flags */
+ execute_action_ipo(achan, &pchan);
+
+ /* store offset that moves src to location of pchan */
+ VecSubf(vec, dpchan->loc, pchan.loc);
+
+ Mat4Mul3Vecfl(dpchan->bone->arm_mat, vec);
+ }
+ }
+ else {
+ /* store offset that moves src to location of dst */
+
+ VecSubf(vec, dpchan->loc, spchan->loc);
+ Mat4Mul3Vecfl(dpchan->bone->arm_mat, vec);
+ }
+
+ /* if blending, we only add with factor scrweight */
+ VecMulf(vec, srcweight);
+
+ VecAddf(dst->cyclic_offset, dst->cyclic_offset, vec);
+ }
+ }
+ }
+
+ VecAddf(dst->cyclic_offset, dst->cyclic_offset, src->cyclic_offset);
+}
+
+
+/* Only allowed for Poses with identical channels */
+void blend_poses(bPose *dst, bPose *src, float srcweight, short mode)
+{
+ bPoseChannel *dchan;
+ const bPoseChannel *schan;
+ bConstraint *dcon, *scon;
+ float dquat[4], squat[4];
+ float dstweight;
+ int i;
+
+ switch (mode){
+ case ACTSTRIPMODE_BLEND:
+ dstweight = 1.0F - srcweight;
+ break;
+ case ACTSTRIPMODE_ADD:
+ dstweight = 1.0F;
+ break;
+ default :
+ dstweight = 1.0F;
+ }
+
+ schan= src->chanbase.first;
+ for (dchan = dst->chanbase.first; dchan; dchan=dchan->next, schan= schan->next){
+ if (schan->flag & (POSE_ROT|POSE_LOC|POSE_SIZE)) {
+ /* replaced quat->matrix->quat conversion with decent quaternion interpol (ton) */
+
+ /* Do the transformation blend */
+ if (schan->flag & POSE_ROT) {
+ QUATCOPY(dquat, dchan->quat);
+ QUATCOPY(squat, schan->quat);
+ if(mode==ACTSTRIPMODE_BLEND)
+ QuatInterpol(dchan->quat, dquat, squat, srcweight);
+ else
+ QuatAdd(dchan->quat, dquat, squat, srcweight);
+
+ NormalQuat (dchan->quat);
+ }
+
+ for (i=0; i<3; i++){
+ if (schan->flag & POSE_LOC)
+ dchan->loc[i] = (dchan->loc[i]*dstweight) + (schan->loc[i]*srcweight);
+ if (schan->flag & POSE_SIZE)
+ dchan->size[i] = 1.0f + ((dchan->size[i]-1.0f)*dstweight) + ((schan->size[i]-1.0f)*srcweight);
+ }
+ dchan->flag |= schan->flag;
+ }
+ for(dcon= dchan->constraints.first, scon= schan->constraints.first; dcon && scon; dcon= dcon->next, scon= scon->next) {
+ /* no 'add' option for constraint blending */
+ dcon->enforce= dcon->enforce*(1.0f-srcweight) + scon->enforce*srcweight;
+ }
+ }
+
+ /* this pose is now in src time */
+ dst->ctime= src->ctime;
+}
+
+
+void calc_action_range(const bAction *act, float *start, float *end, int incl_hidden)
+{
+ const bActionChannel *chan;
+ const bConstraintChannel *conchan;
+ const IpoCurve *icu;
+ float min=999999999.0f, max=-999999999.0;
+ int foundvert=0;
+
+ if(act) {
+ for (chan=act->chanbase.first; chan; chan=chan->next) {
+ if(incl_hidden || (chan->flag & ACHAN_HIDDEN)==0) {
+ if(chan->ipo) {
+ for (icu=chan->ipo->curve.first; icu; icu=icu->next) {
+ if(icu->totvert) {
+ min= MIN2 (min, icu->bezt[0].vec[1][0]);
+ max= MAX2 (max, icu->bezt[icu->totvert-1].vec[1][0]);
+ foundvert=1;
+ }
+ }
+ }
+ for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next) {
+ if(conchan->ipo) {
+ for (icu=conchan->ipo->curve.first; icu; icu=icu->next) {
+ if(icu->totvert) {
+ min= MIN2 (min, icu->bezt[0].vec[1][0]);
+ max= MAX2 (max, icu->bezt[icu->totvert-1].vec[1][0]);
+ foundvert=1;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if (foundvert) {
+ if(min==max) max+= 1.0f;
+ *start= min;
+ *end= max;
+ }
+ else {
+ *start= 0.0f;
+ *end= 1.0f;
+ }
+}
+
+/* Copy the data from the action-pose (src) into the pose */
+/* both args are assumed to be valid */
+/* exported to game engine */
+void extract_pose_from_pose(bPose *pose, const bPose *src)
+{
+ const bPoseChannel *schan;
+ bPoseChannel *pchan= pose->chanbase.first;
+
+ for (schan=src->chanbase.first; schan; schan=schan->next, pchan= pchan->next) {
+ copy_pose_channel_data(pchan, schan);
+ }
+}
+
+/* Pose should exist, can have any number of channels too (used for constraint) */
+void extract_pose_from_action(bPose *pose, bAction *act, float ctime)
+{
+ bActionChannel *achan;
+ bPoseChannel *pchan;
+ Ipo *ipo;
+
+ if (!act)
+ return;
+ if (!pose)
+ return;
+
+ /* Copy the data from the action into the pose */
+ for (pchan= pose->chanbase.first; pchan; pchan=pchan->next) {
+ /* skip this pose channel if it has been tagged as having unkeyed poses */
+ if ((pchan->bone) && (pchan->bone->flag & BONE_UNKEYED))
+ continue;
+
+ /* get action channel and clear pchan-transform flags */
+ achan= get_action_channel(act, pchan->name);
+ pchan->flag &= ~(POSE_LOC|POSE_ROT|POSE_SIZE);
+
+ if (achan) {
+ ipo = achan->ipo;
+ if (ipo) {
+ /* Evaluates and sets the internal ipo value */
+ calc_ipo(ipo, ctime);
+ /* This call also sets the pchan flags */
+ execute_action_ipo(achan, pchan);
+ }
+ /* 0 = do all ipos, not only drivers */
+ do_constraint_channels(&pchan->constraints, &achan->constraintChannels, ctime, 0);
+ }
+ }
+
+ pose->ctime= ctime; /* used for cyclic offset matching */
+}
+
+/* for do_all_pose_actions, clears the pose. Now also exported for proxy and tools */
+void rest_pose(bPose *pose)
+{
+ bPoseChannel *pchan;
+ int i;
+
+ if (!pose)
+ return;
+
+ memset(pose->stride_offset, 0, sizeof(pose->stride_offset));
+ memset(pose->cyclic_offset, 0, sizeof(pose->cyclic_offset));
+
+ for (pchan=pose->chanbase.first; pchan; pchan= pchan->next){
+ for (i=0; i<3; i++) {
+ pchan->loc[i]= 0.0f;
+ pchan->quat[i+1]= 0.0f;
+ pchan->size[i]= 1.0f;
+ }
+ pchan->quat[0]= 1.0f;
+
+ pchan->flag &= ~(POSE_LOC|POSE_ROT|POSE_SIZE);
+ }
+}
+
+/* both poses should be in sync */
+void copy_pose_result(bPose *to, bPose *from)
+{
+ bPoseChannel *pchanto, *pchanfrom;
+
+ if(to==NULL || from==NULL) {
+ printf("pose result copy error\n"); // debug temp
+ return;
+ }
+
+ for(pchanfrom= from->chanbase.first; pchanfrom; pchanfrom= pchanfrom->next) {
+ pchanto= get_pose_channel(to, pchanfrom->name);
+ if(pchanto) {
+ Mat4CpyMat4(pchanto->pose_mat, pchanfrom->pose_mat);
+ Mat4CpyMat4(pchanto->chan_mat, pchanfrom->chan_mat);
+ /* used for local constraints */
+ VECCOPY(pchanto->loc, pchanfrom->loc);
+ QUATCOPY(pchanto->quat, pchanfrom->quat);
+ VECCOPY(pchanto->size, pchanfrom->size);
+
+ VECCOPY(pchanto->pose_head, pchanfrom->pose_head);
+ VECCOPY(pchanto->pose_tail, pchanfrom->pose_tail);
+ pchanto->flag= pchanfrom->flag;
+ }
+ }
+}
+
+/* ********** NLA with non-poses works with ipo channels ********** */
+
+typedef struct NlaIpoChannel {
+ struct NlaIpoChannel *next, *prev;
+ float val;
+ void *poin;
+ int type;
+} NlaIpoChannel;
+
+static void extract_ipochannels_from_action(ListBase *lb, ID *id, bAction *act, char *name, float ctime)
+{
+ bActionChannel *achan= get_action_channel(act, name);
+ IpoCurve *icu;
+ NlaIpoChannel *nic;
+
+ if(achan==NULL) return;
+
+ if(achan->ipo) {
+ calc_ipo(achan->ipo, ctime);
+
+ for(icu= achan->ipo->curve.first; icu; icu= icu->next) {
+ /* skip IPO_BITS, is for layers and cannot be blended */
+ if(icu->vartype != IPO_BITS) {
+ nic= MEM_callocN(sizeof(NlaIpoChannel), "NlaIpoChannel");
+ BLI_addtail(lb, nic);
+ nic->val= icu->curval;
+ nic->poin= get_ipo_poin(id, icu, &nic->type);
+ }
+ }
+ }
+
+ /* constraint channels only for objects */
+ if(GS(id->name)==ID_OB) {
+ Object *ob= (Object *)id;
+ bConstraint *con;
+ bConstraintChannel *conchan;
+
+ for (con=ob->constraints.first; con; con=con->next) {
+ conchan = get_constraint_channel(&achan->constraintChannels, con->name);
+
+ if(conchan && conchan->ipo) {
+ calc_ipo(conchan->ipo, ctime);
+
+ icu= conchan->ipo->curve.first; // only one ipo now
+ if(icu) {
+ nic= MEM_callocN(sizeof(NlaIpoChannel), "NlaIpoChannel constr");
+ BLI_addtail(lb, nic);
+ nic->val= icu->curval;
+ nic->poin= &con->enforce;
+ nic->type= IPO_FLOAT;
+ }
+ }
+ }
+ }
+}
+
+static NlaIpoChannel *find_nla_ipochannel(ListBase *lb, void *poin)
+{
+ NlaIpoChannel *nic;
+
+ if(poin) {
+ for(nic= lb->first; nic; nic= nic->next) {
+ if(nic->poin==poin)
+ return nic;
+ }
+ }
+ return NULL;
+}
+
+
+static void blend_ipochannels(ListBase *dst, ListBase *src, float srcweight, int mode)
+{
+ NlaIpoChannel *snic, *dnic, *next;
+ float dstweight;
+
+ switch (mode){
+ case ACTSTRIPMODE_BLEND:
+ dstweight = 1.0F - srcweight;
+ break;
+ case ACTSTRIPMODE_ADD:
+ dstweight = 1.0F;
+ break;
+ default :
+ dstweight = 1.0F;
+ }
+
+ for(snic= src->first; snic; snic= next) {
+ next= snic->next;
+
+ dnic= find_nla_ipochannel(dst, snic->poin);
+ if(dnic==NULL) {
+ /* remove from src list, and insert in dest */
+ BLI_remlink(src, snic);
+ BLI_addtail(dst, snic);
+ }
+ else {
+ /* we do the blend */
+ dnic->val= dstweight*dnic->val + srcweight*snic->val;
+ }
+ }
+}
+
+static void execute_ipochannels(ListBase *lb)
+{
+ NlaIpoChannel *nic;
+
+ for(nic= lb->first; nic; nic= nic->next) {
+ if(nic->poin) {
+ write_ipo_poin(nic->poin, nic->type, nic->val);
+ }
+ }
+}
+
+/* nla timing */
+
+/* this now only used for repeating cycles, to enable fields and blur. */
+/* the whole time control in blender needs serious thinking... */
+static float nla_time(float cfra, float unit)
+{
+ extern float bluroffs; // bad construct, borrowed from object.c for now
+ extern float fieldoffs;
+
+ /* motion blur & fields */
+ cfra+= unit*(bluroffs+fieldoffs);
+
+ /* global time */
+ cfra*= G.scene->r.framelen;
+
+
+ /* decide later... */
+// if(no_speed_curve==0) if(ob && ob->ipo) cfra= calc_ipo_time(ob->ipo, cfra);
+
+ return cfra;
+}
+
+/* added "sizecorr" here, to allow armatures to be scaled and still have striding.
+ Only works for uniform scaling. In general I'd advise against scaling armatures ever though! (ton)
+*/
+static float stridechannel_frame(Object *ob, float sizecorr, bActionStrip *strip, Path *path, float pathdist, float *stride_offset)
+{
+ bAction *act= strip->act;
+ char *name= strip->stridechannel;
+ bActionChannel *achan= get_action_channel(act, name);
+ int stride_axis= strip->stride_axis;
+
+ if(achan && achan->ipo) {
+ IpoCurve *icu= NULL;
+ float minx=0.0f, maxx=0.0f, miny=0.0f, maxy=0.0f;
+ int foundvert= 0;
+
+ if(stride_axis==0) stride_axis= AC_LOC_X;
+ else if(stride_axis==1) stride_axis= AC_LOC_Y;
+ else stride_axis= AC_LOC_Z;
+
+ /* calculate the min/max */
+ for (icu=achan->ipo->curve.first; icu; icu=icu->next) {
+ if(icu->adrcode==stride_axis) {
+ if(icu->totvert>1) {
+ foundvert= 1;
+ minx= icu->bezt[0].vec[1][0];
+ maxx= icu->bezt[icu->totvert-1].vec[1][0];
+
+ miny= icu->bezt[0].vec[1][1];
+ maxy= icu->bezt[icu->totvert-1].vec[1][1];
+ }
+ break;
+ }
+ }
+
+ if(foundvert && miny!=maxy) {
+ float stridelen= sizecorr*fabs(maxy-miny), striptime;
+ float actiondist, pdist, pdistNewNormalized, offs;
+ float vec1[4], vec2[4], dir[3];
+
+ /* internal cycling, actoffs is in frames */
+ offs= stridelen*strip->actoffs/(maxx-minx);
+
+ /* amount path moves object */
+ pdist = (float)fmod (pathdist+offs, stridelen);
+ striptime= pdist/stridelen;
+
+ /* amount stride bone moves */
+ actiondist= sizecorr*eval_icu(icu, minx + striptime*(maxx-minx)) - miny;
+
+ pdist = fabs(actiondist) - pdist;
+ pdistNewNormalized = (pathdist+pdist)/path->totdist;
+
+ /* now we need to go pdist further (or less) on cu path */
+ where_on_path(ob, (pathdist)/path->totdist, vec1, dir); /* vec needs size 4 */
+ if (pdistNewNormalized <= 1) {
+ // search for correction in positive path-direction
+ where_on_path(ob, pdistNewNormalized, vec2, dir); /* vec needs size 4 */
+ VecSubf(stride_offset, vec2, vec1);
+ }
+ else {
+ // we reached the end of the path, search backwards instead
+ where_on_path(ob, (pathdist-pdist)/path->totdist, vec2, dir); /* vec needs size 4 */
+ VecSubf(stride_offset, vec1, vec2);
+ }
+ Mat4Mul3Vecfl(ob->obmat, stride_offset);
+ return striptime;
+ }
+ }
+ return 0.0f;
+}
+
+static void cyclic_offs_bone(Object *ob, bPose *pose, bActionStrip *strip, float time)
+{
+ /* only called when strip has cyclic, so >= 1.0f works... */
+ if(time >= 1.0f) {
+ bActionChannel *achan= get_action_channel(strip->act, strip->offs_bone);
+
+ if(achan && achan->ipo) {
+ IpoCurve *icu= NULL;
+ Bone *bone;
+ float min[3]={0.0f, 0.0f, 0.0f}, max[3]={0.0f, 0.0f, 0.0f};
+ int index=0, foundvert= 0;
+
+ /* calculate the min/max */
+ for (icu=achan->ipo->curve.first; icu; icu=icu->next) {
+ if(icu->totvert>1) {
+
+ if(icu->adrcode==AC_LOC_X)
+ index= 0;
+ else if(icu->adrcode==AC_LOC_Y)
+ index= 1;
+ else if(icu->adrcode==AC_LOC_Z)
+ index= 2;
+ else
+ continue;
+
+ foundvert= 1;
+ min[index]= icu->bezt[0].vec[1][1];
+ max[index]= icu->bezt[icu->totvert-1].vec[1][1];
+ }
+ }
+ if(foundvert) {
+ /* bring it into armature space */
+ VecSubf(min, max, min);
+ bone= get_named_bone(ob->data, strip->offs_bone); /* weak */
+ if(bone) {
+ Mat4Mul3Vecfl(bone->arm_mat, min);
+
+ /* dominant motion, cyclic_offset was cleared in rest_pose */
+ if (strip->flag & (ACTSTRIP_CYCLIC_USEX | ACTSTRIP_CYCLIC_USEY | ACTSTRIP_CYCLIC_USEZ)) {
+ if (strip->flag & ACTSTRIP_CYCLIC_USEX) pose->cyclic_offset[0]= time*min[0];
+ if (strip->flag & ACTSTRIP_CYCLIC_USEY) pose->cyclic_offset[1]= time*min[1];
+ if (strip->flag & ACTSTRIP_CYCLIC_USEZ) pose->cyclic_offset[2]= time*min[2];
+ } else {
+ if( fabs(min[0]) >= fabs(min[1]) && fabs(min[0]) >= fabs(min[2]))
+ pose->cyclic_offset[0]= time*min[0];
+ else if( fabs(min[1]) >= fabs(min[0]) && fabs(min[1]) >= fabs(min[2]))
+ pose->cyclic_offset[1]= time*min[1];
+ else
+ pose->cyclic_offset[2]= time*min[2];
+ }
+ }
+ }
+ }
+ }
+}
+
+/* simple case for now; only the curve path with constraint value > 0.5 */
+/* blending we might do later... */
+static Object *get_parent_path(Object *ob)
+{
+ bConstraint *con;
+
+ if(ob->parent && ob->parent->type==OB_CURVE)
+ return ob->parent;
+
+ for (con = ob->constraints.first; con; con=con->next) {
+ if(con->type==CONSTRAINT_TYPE_FOLLOWPATH) {
+ if(con->enforce>0.5f) {
+ bFollowPathConstraint *data= con->data;
+ return data->tar;
+ }
+ }
+ }
+ return NULL;
+}
+
+/* ************** do the action ************ */
+
+/* For the calculation of the effects of an action at the given frame on an object
+ * This is currently only used for the action constraint
+ */
+void what_does_obaction (Object *ob, bAction *act, float cframe)
+{
+ ListBase tchanbase= {NULL, NULL};
+
+ clear_workob();
+ Mat4CpyMat4(workob.obmat, ob->obmat);
+ Mat4CpyMat4(workob.parentinv, ob->parentinv);
+ Mat4CpyMat4(workob.constinv, ob->constinv);
+ workob.parent= ob->parent;
+ workob.track= ob->track;
+
+ workob.trackflag= ob->trackflag;
+ workob.upflag= ob->upflag;
+
+ workob.partype= ob->partype;
+ workob.par1= ob->par1;
+ workob.par2= ob->par2;
+ workob.par3= ob->par3;
+
+ workob.constraints.first = ob->constraints.first;
+ workob.constraints.last = ob->constraints.last;
+
+ strcpy(workob.parsubstr, ob->parsubstr);
+
+ /* extract_ipochannels_from_action needs id's! */
+ workob.action= act;
+
+ extract_ipochannels_from_action(&tchanbase, &ob->id, act, "Object", bsystem_time(&workob, cframe, 0.0));
+
+ if (tchanbase.first) {
+ execute_ipochannels(&tchanbase);
+ BLI_freelistN(&tchanbase);
+ }
+}
+
+/* ----- nla, etc. --------- */
+
+static void do_nla(Object *ob, int blocktype)
+{
+ bPose *tpose= NULL;
+ Key *key= NULL;
+ ListBase tchanbase={NULL, NULL}, chanbase={NULL, NULL};
+ bActionStrip *strip, *striplast=NULL, *stripfirst=NULL;
+ float striptime, frametime, length, actlength;
+ float blendfac, stripframe;
+ float scene_cfra= frame_to_float(G.scene->r.cfra);
+ int doit, dostride;
+
+ if(blocktype==ID_AR) {
+ copy_pose(&tpose, ob->pose, 1);
+ rest_pose(ob->pose); // potentially destroying current not-keyed pose
+ }
+ else {
+ key= ob_get_key(ob);
+ }
+
+ /* check on extend to left or right, when no strip is hit by 'cfra' */
+ for (strip=ob->nlastrips.first; strip; strip=strip->next) {
+ /* escape loop on a hit */
+ if( scene_cfra >= strip->start && scene_cfra <= strip->end + 0.1f) /* note 0.1 comes back below */
+ break;
+ if(scene_cfra < strip->start) {
+ if(stripfirst==NULL)
+ stripfirst= strip;
+ else if(stripfirst->start > strip->start)
+ stripfirst= strip;
+ }
+ else if(scene_cfra > strip->end) {
+ if(striplast==NULL)
+ striplast= strip;
+ else if(striplast->end < strip->end)
+ striplast= strip;
+ }
+ }
+ if(strip==NULL) { /* extend */
+ if(striplast)
+ scene_cfra= striplast->end;
+ else if(stripfirst)
+ scene_cfra= stripfirst->start;
+ }
+
+ /* and now go over all strips */
+ for (strip=ob->nlastrips.first; strip; strip=strip->next){
+ doit=dostride= 0;
+
+ if (strip->act && !(strip->flag & ACTSTRIP_MUTE)) { /* so theres an action */
+
+ /* Determine if the current frame is within the strip's range */
+ length = strip->end-strip->start;
+ actlength = strip->actend-strip->actstart;
+ striptime = (scene_cfra-(strip->start)) / length;
+ stripframe = (scene_cfra-(strip->start)) ;
+
+ if (striptime>=0.0){
+
+ if(blocktype==ID_AR)
+ rest_pose(tpose);
+
+ /* To handle repeat, we add 0.1 frame extra to make sure the last frame is included */
+ if (striptime < 1.0f + 0.1f/length) {
+
+ /* Handle path */
+ if ((strip->flag & ACTSTRIP_USESTRIDE) && (blocktype==ID_AR) && (ob->ipoflag & OB_DISABLE_PATH)==0){
+ Object *parent= get_parent_path(ob);
+
+ if (parent) {
+ Curve *cu = parent->data;
+ float ctime, pdist;
+
+ if (cu->flag & CU_PATH){
+ /* Ensure we have a valid path */
+ if(cu->path==NULL || cu->path->data==NULL) makeDispListCurveTypes(parent, 0);
+ if(cu->path) {
+
+ /* Find the position on the path */
+ ctime= bsystem_time(ob, scene_cfra, 0.0);
+
+ if(calc_ipo_spec(cu->ipo, CU_SPEED, &ctime)==0) {
+ /* correct for actions not starting on zero */
+ ctime= (ctime - strip->actstart)/cu->pathlen;
+ CLAMP(ctime, 0.0, 1.0);
+ }
+ pdist = ctime*cu->path->totdist;
+
+ if(tpose && strip->stridechannel[0]) {
+ striptime= stridechannel_frame(parent, ob->size[0], strip, cu->path, pdist, tpose->stride_offset);
+ }
+ else {
+ if (strip->stridelen) {
+ striptime = pdist / strip->stridelen;
+ striptime = (float)fmod (striptime+strip->actoffs, 1.0);
+ }
+ else
+ striptime = 0;
+ }
+
+ frametime = (striptime * actlength) + strip->actstart;
+ frametime= bsystem_time(ob, frametime, 0.0);
+
+ if(blocktype==ID_AR) {
+ extract_pose_from_action (tpose, strip->act, frametime);
+ }
+ else if(blocktype==ID_OB) {
+ extract_ipochannels_from_action(&tchanbase, &ob->id, strip->act, "Object", frametime);
+ if(key)
+ extract_ipochannels_from_action(&tchanbase, &key->id, strip->act, "Shape", frametime);
+ }
+ doit=dostride= 1;
+ }
+ }
+ }
+ }
+ /* To handle repeat, we add 0.1 frame extra to make sure the last frame is included */
+ else {
+
+ /* Mod to repeat */
+ if(strip->repeat!=1.0f) {
+ float cycle= striptime*strip->repeat;
+
+ striptime = (float)fmod (cycle, 1.0f + 0.1f/length);
+ cycle-= striptime;
+
+ if(blocktype==ID_AR)
+ cyclic_offs_bone(ob, tpose, strip, cycle);
+ }
+
+ frametime = (striptime * actlength) + strip->actstart;
+ frametime= nla_time(frametime, (float)strip->repeat);
+
+ if(blocktype==ID_AR) {
+ extract_pose_from_action (tpose, strip->act, frametime);
+ }
+ else if(blocktype==ID_OB) {
+ extract_ipochannels_from_action(&tchanbase, &ob->id, strip->act, "Object", frametime);
+ if(key)
+ extract_ipochannels_from_action(&tchanbase, &key->id, strip->act, "Shape", frametime);
+ }
+
+ doit=1;
+ }
+ }
+ /* Handle extend */
+ else {
+ if (strip->flag & ACTSTRIP_HOLDLASTFRAME){
+ /* we want the strip to hold on the exact fraction of the repeat value */
+
+ frametime = actlength * (strip->repeat-(int)strip->repeat);
+ if(frametime<=0.000001f) frametime= actlength; /* rounding errors... */
+ frametime= bsystem_time(ob, frametime+strip->actstart, 0.0);
+
+ if(blocktype==ID_AR)
+ extract_pose_from_action (tpose, strip->act, frametime);
+ else if(blocktype==ID_OB) {
+ extract_ipochannels_from_action(&tchanbase, &ob->id, strip->act, "Object", frametime);
+ if(key)
+ extract_ipochannels_from_action(&tchanbase, &key->id, strip->act, "Shape", frametime);
+ }
+
+ /* handle cycle hold */
+ if(strip->repeat!=1.0f) {
+ if(blocktype==ID_AR)
+ cyclic_offs_bone(ob, tpose, strip, strip->repeat-1.0f);
+ }
+
+ doit=1;
+ }
+ }
+
+ /* Handle blendin & blendout */
+ if (doit){
+ /* Handle blendin */
+
+ if (strip->blendin>0.0 && stripframe<=strip->blendin && scene_cfra>=strip->start){
+ blendfac = stripframe/strip->blendin;
+ }
+ else if (strip->blendout>0.0 && stripframe>=(length-strip->blendout) && scene_cfra<=strip->end){
+ blendfac = (length-stripframe)/(strip->blendout);
+ }
+ else
+ blendfac = 1;
+
+ if(blocktype==ID_AR) {/* Blend this pose with the accumulated pose */
+ /* offset bone, for matching cycles */
+ blend_pose_offset_bone (strip, ob->pose, tpose, blendfac, strip->mode);
+
+ blend_poses (ob->pose, tpose, blendfac, strip->mode);
+ if(dostride)
+ blend_pose_strides (ob->pose, tpose, blendfac, strip->mode);
+ }
+ else {
+ blend_ipochannels(&chanbase, &tchanbase, blendfac, strip->mode);
+ BLI_freelistN(&tchanbase);
+ }
+ }
+ }
+ }
+ }
+
+ if(blocktype==ID_OB) {
+ execute_ipochannels(&chanbase);
+ }
+ else if(blocktype==ID_AR) {
+ /* apply stride offset to object */
+ VecAddf(ob->obmat[3], ob->obmat[3], ob->pose->stride_offset);
+ }
+
+ /* free */
+ if (tpose){
+ free_pose_channels(tpose);
+ MEM_freeN(tpose);
+ }
+ if(chanbase.first)
+ BLI_freelistN(&chanbase);
+}
+
+void do_all_pose_actions(Object *ob)
+{
+ /* only to have safe calls from editor */
+ if(ob==NULL) return;
+ if(ob->type!=OB_ARMATURE || ob->pose==NULL) return;
+
+ if(ob->pose->flag & POSE_LOCKED) { /* no actions to execute while transform */
+ if(ob->pose->flag & POSE_DO_UNLOCK)
+ ob->pose->flag &= ~(POSE_LOCKED|POSE_DO_UNLOCK);
+ }
+ else if(ob->action && ((ob->nlaflag & OB_NLA_OVERRIDE)==0 || ob->nlastrips.first==NULL) ) {
+ float cframe= (float) G.scene->r.cfra;
+
+ cframe= get_action_frame(ob, cframe);
+
+ extract_pose_from_action (ob->pose, ob->action, bsystem_time(ob, cframe, 0.0));
+ }
+ else if(ob->nlastrips.first) {
+ do_nla(ob, ID_AR);
+ }
+
+ /* clear POSE_DO_UNLOCK flags that might have slipped through (just in case) */
+ ob->pose->flag &= ~POSE_DO_UNLOCK;
+}
+
+/* called from where_is_object */
+void do_all_object_actions(Object *ob)
+{
+ if(ob==NULL) return;
+ if(ob->dup_group) return; /* prevent conflicts, might add smarter check later */
+
+ /* Do local action */
+ if(ob->action && ((ob->nlaflag & OB_NLA_OVERRIDE)==0 || ob->nlastrips.first==NULL) ) {
+ ListBase tchanbase= {NULL, NULL};
+ Key *key= ob_get_key(ob);
+ float cframe= (float) G.scene->r.cfra;
+
+ cframe= get_action_frame(ob, cframe);
+
+ extract_ipochannels_from_action(&tchanbase, &ob->id, ob->action, "Object", bsystem_time(ob, cframe, 0.0));
+ if(key)
+ extract_ipochannels_from_action(&tchanbase, &key->id, ob->action, "Shape", bsystem_time(ob, cframe, 0.0));
+
+ if(tchanbase.first) {
+ execute_ipochannels(&tchanbase);
+ BLI_freelistN(&tchanbase);
+ }
+ }
+ else if(ob->nlastrips.first) {
+ do_nla(ob, ID_OB);
+ }
+}
diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c
new file mode 100644
index 00000000000..32ea2b3ed2c
--- /dev/null
+++ b/source/blender/blenkernel/intern/anim.c
@@ -0,0 +1,844 @@
+/** anim.c
+ *
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <math.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "DNA_listBase.h"
+
+#include "DNA_curve_types.h"
+#include "DNA_effect_types.h"
+#include "DNA_group_types.h"
+#include "DNA_key_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_vfont_types.h"
+
+#include "BKE_anim.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_displist.h"
+#include "BKE_effect.h"
+#include "BKE_font.h"
+#include "BKE_group.h"
+#include "BKE_global.h"
+#include "BKE_ipo.h"
+#include "BKE_key.h"
+#include "BKE_main.h"
+#include "BKE_object.h"
+#include "BKE_utildefines.h"
+
+#include "BKE_bad_level_calls.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+void free_path(Path *path)
+{
+ if(path->data) MEM_freeN(path->data);
+ MEM_freeN(path);
+}
+
+
+void calc_curvepath(Object *ob)
+{
+ BevList *bl;
+ BevPoint *bevp, *bevpn, *bevpfirst, *bevplast, *tempbevp;
+ Curve *cu;
+ Nurb *nu;
+ Path *path;
+ float *fp, *dist, *maxdist, x, y, z;
+ float fac, d=0, fac1, fac2;
+ int a, tot, cycl=0;
+ float *ft;
+
+ /* in a path vertices are with equal differences: path->len = number of verts */
+ /* NOW WITH BEVELCURVE!!! */
+
+ if(ob==NULL || ob->type != OB_CURVE) return;
+ cu= ob->data;
+ if(ob==G.obedit) nu= editNurb.first;
+ else nu= cu->nurb.first;
+
+ if(cu->path) free_path(cu->path);
+ cu->path= NULL;
+
+ bl= cu->bev.first;
+ if(bl==NULL) return;
+
+ cu->path=path= MEM_callocN(sizeof(Path), "path");
+
+ /* if POLY: last vertice != first vertice */
+ cycl= (bl->poly!= -1);
+
+ if(cycl) tot= bl->nr;
+ else tot= bl->nr-1;
+
+ path->len= tot+1;
+ /* exception: vector handle paths and polygon paths should be subdivided at least a factor resolu */
+ if(path->len<nu->resolu*nu->pntsu) path->len= nu->resolu*nu->pntsu;
+
+ dist= (float *)MEM_mallocN((tot+1)*4, "calcpathdist");
+
+ /* all lengths in *dist */
+ bevp= bevpfirst= (BevPoint *)(bl+1);
+ fp= dist;
+ *fp= 0;
+ for(a=0; a<tot; a++) {
+ fp++;
+ if(cycl && a==tot-1) {
+ x= bevpfirst->x - bevp->x;
+ y= bevpfirst->y - bevp->y;
+ z= bevpfirst->z - bevp->z;
+ }
+ else {
+ tempbevp = bevp+1;
+ x= (tempbevp)->x - bevp->x;
+ y= (tempbevp)->y - bevp->y;
+ z= (tempbevp)->z - bevp->z;
+ }
+ *fp= *(fp-1)+ (float)sqrt(x*x+y*y+z*z);
+
+ bevp++;
+ }
+
+ path->totdist= *fp;
+
+ /* the path verts in path->data */
+ /* now also with TILT value */
+ ft= path->data = (float *)MEM_callocN(16*path->len, "pathdata");
+
+ bevp= bevpfirst;
+ bevpn= bevp+1;
+ bevplast= bevpfirst + (bl->nr-1);
+ fp= dist+1;
+ maxdist= dist+tot;
+ fac= 1.0f/((float)path->len-1.0f);
+ fac = fac * path->totdist;
+
+ for(a=0; a<path->len; a++) {
+
+ d= ((float)a)*fac;
+
+ /* we're looking for location (distance) 'd' in the array */
+ while((d>= *fp) && fp<maxdist) {
+ fp++;
+ if(bevp<bevplast) bevp++;
+ bevpn= bevp+1;
+ if(bevpn>bevplast) {
+ if(cycl) bevpn= bevpfirst;
+ else bevpn= bevplast;
+ }
+ }
+
+ fac1= *(fp)- *(fp-1);
+ fac2= *(fp)-d;
+ fac1= fac2/fac1;
+ fac2= 1.0f-fac1;
+
+ ft[0]= fac1*bevp->x+ fac2*(bevpn)->x;
+ ft[1]= fac1*bevp->y+ fac2*(bevpn)->y;
+ ft[2]= fac1*bevp->z+ fac2*(bevpn)->z;
+ ft[3]= fac1*bevp->alfa+ fac2*(bevpn)->alfa;
+
+ ft+= 4;
+
+ }
+
+ MEM_freeN(dist);
+}
+
+int interval_test(int min, int max, int p1, int cycl)
+{
+
+ if(cycl) {
+ if( p1 < min)
+ p1= ((p1 -min) % (max-min+1)) + max+1;
+ else if(p1 > max)
+ p1= ((p1 -min) % (max-min+1)) + min;
+ }
+ else {
+ if(p1 < min) p1= min;
+ else if(p1 > max) p1= max;
+ }
+ return p1;
+}
+
+/* warning, *vec needs FOUR items! */
+/* ctime is normalized range <0-1> */
+int where_on_path(Object *ob, float ctime, float *vec, float *dir) /* returns OK */
+{
+ Curve *cu;
+ Nurb *nu;
+ BevList *bl;
+ Path *path;
+ float *fp, *p0, *p1, *p2, *p3, fac;
+ float data[4];
+ int cycl=0, s0, s1, s2, s3;
+
+ if(ob==NULL || ob->type != OB_CURVE) return 0;
+ cu= ob->data;
+ if(cu->path==NULL || cu->path->data==NULL) {
+ printf("no path!\n");
+ }
+ path= cu->path;
+ fp= path->data;
+
+ /* test for cyclic */
+ bl= cu->bev.first;
+ if(bl && bl->poly> -1) cycl= 1;
+
+ ctime *= (path->len-1);
+
+ s1= (int)floor(ctime);
+ fac= (float)(s1+1)-ctime;
+
+ /* path->len is corected for cyclic */
+ s0= interval_test(0, path->len-1-cycl, s1-1, cycl);
+ s1= interval_test(0, path->len-1-cycl, s1, cycl);
+ s2= interval_test(0, path->len-1-cycl, s1+1, cycl);
+ s3= interval_test(0, path->len-1-cycl, s1+2, cycl);
+
+ p0= fp + 4*s0;
+ p1= fp + 4*s1;
+ p2= fp + 4*s2;
+ p3= fp + 4*s3;
+
+ /* note, commented out for follow constraint */
+ //if(cu->flag & CU_FOLLOW) {
+
+ set_afgeleide_four_ipo(1.0f-fac, data, KEY_BSPLINE);
+
+ dir[0]= data[0]*p0[0] + data[1]*p1[0] + data[2]*p2[0] + data[3]*p3[0] ;
+ dir[1]= data[0]*p0[1] + data[1]*p1[1] + data[2]*p2[1] + data[3]*p3[1] ;
+ dir[2]= data[0]*p0[2] + data[1]*p1[2] + data[2]*p2[2] + data[3]*p3[2] ;
+
+ /* make compatible with vectoquat */
+ dir[0]= -dir[0];
+ dir[1]= -dir[1];
+ dir[2]= -dir[2];
+ //}
+
+ nu= cu->nurb.first;
+
+ /* make sure that first and last frame are included in the vectors here */
+ if((nu->type & 7)==CU_POLY) set_four_ipo(1.0f-fac, data, KEY_LINEAR);
+ else if((nu->type & 7)==CU_BEZIER) set_four_ipo(1.0f-fac, data, KEY_LINEAR);
+ else if(s0==s1 || p2==p3) set_four_ipo(1.0f-fac, data, KEY_CARDINAL);
+ else set_four_ipo(1.0f-fac, data, KEY_BSPLINE);
+
+ vec[0]= data[0]*p0[0] + data[1]*p1[0] + data[2]*p2[0] + data[3]*p3[0] ;
+ vec[1]= data[0]*p0[1] + data[1]*p1[1] + data[2]*p2[1] + data[3]*p3[1] ;
+ vec[2]= data[0]*p0[2] + data[1]*p1[2] + data[2]*p2[2] + data[3]*p3[2] ;
+
+ vec[3]= data[0]*p0[3] + data[1]*p1[3] + data[2]*p2[3] + data[3]*p3[3] ;
+
+ return 1;
+}
+
+/* ****************** DUPLICATOR ************** */
+
+static DupliObject *new_dupli_object(ListBase *lb, Object *ob, float mat[][4], int lay, int index)
+{
+ DupliObject *dob= MEM_callocN(sizeof(DupliObject), "dupliobject");
+
+ BLI_addtail(lb, dob);
+ dob->ob= ob;
+ Mat4CpyMat4(dob->mat, mat);
+ Mat4CpyMat4(dob->omat, ob->obmat);
+ dob->origlay= ob->lay;
+ dob->index= index;
+ ob->lay= lay;
+
+ /* allowing duplicators for particle systems... a bit silly still */
+ {
+ PartEff *paf= give_parteff(ob);
+ if(paf) {
+ Mat4Invert(ob->imat, ob->obmat);
+ Mat4CpyMat4(paf->imat, ob->imat);
+ }
+ }
+ return dob;
+}
+
+static void group_duplilist(ListBase *lb, Object *ob, int level)
+{
+ DupliObject *dob;
+ Group *group;
+ GroupObject *go;
+ float mat[4][4];
+
+ if(ob->dup_group==NULL) return;
+ group= ob->dup_group;
+
+ /* simple preventing of too deep nested groups */
+ if(level>4) return;
+
+ /* handles animated groups, and */
+ /* we need to check update for objects that are not in scene... */
+ group_handle_recalc_and_update(ob, group);
+
+ for(go= group->gobject.first; go; go= go->next) {
+ /* note, if you check on layer here, render goes wrong... it still deforms verts and uses parent imat */
+ if(go->ob!=ob) {
+ Mat4MulMat4(mat, go->ob->obmat, ob->obmat);
+ dob= new_dupli_object(lb, go->ob, mat, ob->lay, 0);
+ dob->no_draw= (dob->origlay & group->layer)==0;
+
+ if(go->ob->dup_group && (go->ob->transflag & OB_DUPLIGROUP)) {
+ Mat4CpyMat4(dob->ob->obmat, dob->mat);
+ group_duplilist(lb, go->ob, level+1);
+ Mat4CpyMat4(dob->ob->obmat, dob->omat);
+ }
+ }
+ }
+}
+
+static void frames_duplilist(ListBase *lb, Object *ob)
+{
+ extern int enable_cu_speed; /* object.c */
+ Object copyob;
+ int cfrao, ok;
+
+ cfrao= G.scene->r.cfra;
+ if(ob->parent==NULL && ob->track==NULL && ob->ipo==NULL && ob->constraints.first==NULL) return;
+
+ if(ob->transflag & OB_DUPLINOSPEED) enable_cu_speed= 0;
+ copyob= *ob; /* store transform info */
+
+ for(G.scene->r.cfra= ob->dupsta; G.scene->r.cfra<=ob->dupend; G.scene->r.cfra++) {
+
+ ok= 1;
+ if(ob->dupoff) {
+ ok= G.scene->r.cfra - ob->dupsta;
+ ok= ok % (ob->dupon+ob->dupoff);
+ if(ok < ob->dupon) ok= 1;
+ else ok= 0;
+ }
+ if(ok) {
+ do_ob_ipo(ob);
+ where_is_object_time(ob, (float)G.scene->r.cfra);
+ new_dupli_object(lb, ob, ob->obmat, ob->lay, G.scene->r.cfra);
+ }
+ }
+
+ *ob= copyob; /* restore transform info */
+ G.scene->r.cfra= cfrao;
+ enable_cu_speed= 1;
+}
+
+struct vertexDupliData {
+ ListBase *lb;
+ float pmat[4][4];
+ Object *ob, *par;
+};
+
+static void vertex_dupli__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s)
+{
+ struct vertexDupliData *vdd= userData;
+ float vec[3], *q2, mat[3][3], tmat[4][4], obmat[4][4];
+
+ VECCOPY(vec, co);
+ Mat4MulVecfl(vdd->pmat, vec);
+ VecSubf(vec, vec, vdd->pmat[3]);
+ VecAddf(vec, vec, vdd->ob->obmat[3]);
+
+ Mat4CpyMat4(obmat, vdd->ob->obmat);
+ VECCOPY(obmat[3], vec);
+
+ if(vdd->par->transflag & OB_DUPLIROT) {
+ if(no_f) {
+ vec[0]= -no_f[0]; vec[1]= -no_f[1]; vec[2]= -no_f[2];
+ }
+ else if(no_s) {
+ vec[0]= -no_s[0]; vec[1]= -no_s[1]; vec[2]= -no_s[2];
+ }
+
+ q2= vectoquat(vec, vdd->ob->trackflag, vdd->ob->upflag);
+
+ QuatToMat3(q2, mat);
+ Mat4CpyMat4(tmat, obmat);
+ Mat4MulMat43(obmat, tmat, mat);
+ }
+ new_dupli_object(vdd->lb, vdd->ob, obmat, vdd->par->lay, index);
+}
+
+static void vertex_duplilist(ListBase *lb, Scene *sce, Object *par)
+{
+ Object *ob;
+ Base *base;
+ float vec[3], no[3], pmat[4][4];
+ int lay, totvert, a;
+ DerivedMesh *dm;
+
+ Mat4CpyMat4(pmat, par->obmat);
+
+ lay= G.scene->lay;
+
+ if(par==G.obedit)
+ dm= editmesh_get_derived_cage(CD_MASK_BAREMESH);
+ else
+ dm = mesh_get_derived_deform(par, CD_MASK_BAREMESH);
+
+ totvert = dm->getNumVerts(dm);
+
+ base= sce->base.first;
+ while(base) {
+
+ if(base->object->type>0 && (lay & base->lay) && G.obedit!=base->object) {
+ ob= base->object->parent;
+ while(ob) {
+ if(ob==par) {
+ struct vertexDupliData vdd;
+
+ ob= base->object;
+ vdd.lb= lb;
+ vdd.ob= ob;
+ vdd.par= par;
+ Mat4CpyMat4(vdd.pmat, pmat);
+
+ /* mballs have a different dupli handling */
+ if(ob->type!=OB_MBALL) ob->flag |= OB_DONE; /* doesnt render */
+
+ if(par==G.obedit) {
+ dm->foreachMappedVert(dm, vertex_dupli__mapFunc, (void*) &vdd);
+ }
+ else {
+ for(a=0; a<totvert; a++) {
+ dm->getVertCo(dm, a, vec);
+ dm->getVertNo(dm, a, no);
+
+ vertex_dupli__mapFunc(&vdd, a, vec, no, NULL);
+ }
+ }
+
+ break;
+ }
+ ob= ob->parent;
+ }
+ }
+ base= base->next;
+ }
+
+ dm->release(dm);
+}
+
+static void face_duplilist(ListBase *lb, Scene *sce, Object *par)
+{
+ Object *ob;
+ Base *base;
+ DerivedMesh *dm;
+ MFace *mface;
+ MVert *mvert;
+ float pmat[4][4], imat[3][3];
+ int lay, totface, a;
+
+ Mat4CpyMat4(pmat, par->obmat);
+
+ lay= G.scene->lay;
+
+ if(par==G.obedit) {
+ int totvert;
+ dm= editmesh_get_derived_cage(CD_MASK_BAREMESH);
+
+ totface= dm->getNumFaces(dm);
+ mface= MEM_mallocN(sizeof(MFace)*totface, "mface temp");
+ dm->copyFaceArray(dm, mface);
+ totvert= dm->getNumVerts(dm);
+ mvert= MEM_mallocN(sizeof(MVert)*totvert, "mvert temp");
+ dm->copyVertArray(dm, mvert);
+ }
+ else {
+ dm = mesh_get_derived_deform(par, CD_MASK_BAREMESH);
+
+ totface= dm->getNumFaces(dm);
+ mface= dm->getFaceArray(dm);
+ mvert= dm->getVertArray(dm);
+ }
+
+
+ for(base= sce->base.first; base; base= base->next) {
+
+ if(base->object->type>0 && (lay & base->lay) && G.obedit!=base->object) {
+ ob= base->object->parent;
+ while(ob) {
+ if(ob==par) {
+
+ ob= base->object;
+ Mat3CpyMat4(imat, ob->parentinv);
+
+ /* mballs have a different dupli handling */
+ if(ob->type!=OB_MBALL) ob->flag |= OB_DONE; /* doesnt render */
+
+ for(a=0; a<totface; a++) {
+ float *v1= mvert[ mface[a].v1 ].co;
+ float *v2= mvert[ mface[a].v2 ].co;
+ float *v3= mvert[ mface[a].v3 ].co;
+ float *v4= mface[a].v4?mvert[ mface[a].v4 ].co:NULL;
+ float cent[3], quat[4], mat[3][3], mat3[3][3], tmat[4][4], obmat[4][4];
+
+ /* translation */
+ if(v4)
+ CalcCent4f(cent, v1, v2, v3, v4);
+ else
+ CalcCent3f(cent, v1, v2, v3);
+ Mat4MulVecfl(pmat, cent);
+
+ VecSubf(cent, cent, pmat[3]);
+ VecAddf(cent, cent, ob->obmat[3]);
+
+ Mat4CpyMat4(obmat, ob->obmat);
+ VECCOPY(obmat[3], cent);
+
+ /* rotation */
+ triatoquat(v1, v2, v3, quat);
+ QuatToMat3(quat, mat);
+
+ /* scale */
+ if(par->transflag & OB_DUPLIFACES_SCALE) {
+ float size= v4?AreaQ3Dfl(v1, v2, v3, v4):AreaT3Dfl(v1, v2, v3);
+ size= sqrt(size);
+ Mat3MulFloat(mat[0], size);
+ }
+
+ Mat3CpyMat3(mat3, mat);
+ Mat3MulMat3(mat, imat, mat3);
+
+ Mat4CpyMat4(tmat, obmat);
+ Mat4MulMat43(obmat, tmat, mat);
+
+ new_dupli_object(lb, ob, obmat, lay, a);
+
+ }
+
+ break;
+ }
+ ob= ob->parent;
+ }
+ }
+ }
+
+ if(par==G.obedit) {
+ MEM_freeN(mface);
+ MEM_freeN(mvert);
+ }
+
+ dm->release(dm);
+}
+
+
+
+static void particle_duplilist(ListBase *lb, Scene *sce, Object *par, PartEff *paf)
+{
+ Object *ob, copyob;
+ Base *base;
+ Particle *pa;
+ float ctime, vec1[3];
+ float vec[3], tmat[4][4], mat[3][3];
+ float *q2;
+ int lay, a, counter; /* counter is used to find in render the indexed object */
+
+ pa= paf->keys;
+ if(pa==NULL || (G.rendering && paf->disp!=100)) {
+ build_particle_system(par);
+ pa= paf->keys;
+ if(pa==NULL) return;
+ }
+
+ ctime= bsystem_time(par, (float)G.scene->r.cfra, 0.0);
+
+ lay= G.scene->lay;
+
+ for(base= sce->base.first; base; base= base->next) {
+ if(base->object->type>0 && (base->lay & lay) && G.obedit!=base->object) {
+ ob= base->object->parent;
+ while(ob) {
+ if(ob==par) {
+
+ ob= base->object;
+ /* temp copy, to have ipos etc to work OK */
+ copyob= *ob;
+
+ /* don't want parent animation to apply on past object positions */
+ if(!(paf->flag & PAF_STATIC))
+ ob->parent= NULL;
+
+ for(a=0, pa= paf->keys, counter=0; a<paf->totpart; a++, pa+=paf->totkey, counter++) {
+
+ if(paf->flag & PAF_STATIC) {
+ float mtime;
+
+ where_is_particle(paf, pa, pa->time, vec1);
+ mtime= pa->time+pa->lifetime;
+
+ for(ctime= pa->time; ctime<mtime; ctime+=paf->staticstep, counter++) {
+
+ /* make sure hair grows until the end.. */
+ if(ctime>pa->time+pa->lifetime) ctime= pa->time+pa->lifetime;
+
+ /* to give ipos in object correct offset */
+ where_is_object_time(ob, ctime-pa->time);
+
+ where_is_particle(paf, pa, ctime, vec); // makes sure there's always a vec
+ Mat4MulVecfl(par->obmat, vec);
+
+ if(paf->stype==PAF_VECT) {
+ where_is_particle(paf, pa, ctime+1.0, vec1); // makes sure there's always a vec
+ Mat4MulVecfl(par->obmat, vec1);
+
+ VecSubf(vec1, vec1, vec);
+ q2= vectoquat(vec1, ob->trackflag, ob->upflag);
+
+ QuatToMat3(q2, mat);
+ Mat4CpyMat4(tmat, ob->obmat);
+ Mat4MulMat43(ob->obmat, tmat, mat);
+ }
+
+ VECCOPY(ob->obmat[3], vec);
+ /* put object back in original state, so it cam be restored OK */
+ Mat4CpyMat4(tmat, ob->obmat);
+ Mat4CpyMat4(ob->obmat, copyob.obmat);
+ new_dupli_object(lb, ob, tmat, par->lay, counter);
+ }
+ }
+ else { // non static particles
+
+ if((paf->flag & PAF_UNBORN)==0 && ctime < pa->time) continue;
+ if((paf->flag & PAF_DIED)==0 && ctime > pa->time+pa->lifetime) continue;
+
+ //if(ctime < pa->time+pa->lifetime) {
+
+ /* to give ipos in object correct offset, ob->parent is NULLed */
+ where_is_object_time(ob, ctime-pa->time);
+
+ where_is_particle(paf, pa, ctime, vec);
+ if(paf->stype==PAF_VECT) {
+
+ /* if particle died, we use previous position */
+ if(ctime > pa->time+pa->lifetime) {
+ where_is_particle(paf, pa, pa->time+pa->lifetime-1.0f, vec1);
+ VecSubf(vec1, vec, vec1);
+ }
+ else {
+ where_is_particle(paf, pa, ctime+1.0f, vec1);
+ VecSubf(vec1, vec1, vec);
+ }
+ q2= vectoquat(vec1, ob->trackflag, ob->upflag);
+
+ QuatToMat3(q2, mat);
+ Mat4CpyMat4(tmat, ob->obmat);
+ Mat4MulMat43(ob->obmat, tmat, mat);
+ }
+
+ VECCOPY(ob->obmat[3], vec);
+
+ /* put object back in original state, so it can be restored OK */
+ Mat4CpyMat4(tmat, ob->obmat);
+ Mat4CpyMat4(ob->obmat, copyob.obmat);
+ new_dupli_object(lb, ob, tmat, par->lay, counter);
+ }
+ }
+ /* temp copy, to have ipos etc to work OK */
+ *ob= copyob;
+
+ break;
+ }
+ ob= ob->parent;
+ }
+ }
+ }
+
+ if(G.rendering && paf->disp!=100) {
+ MEM_freeN(paf->keys);
+ paf->keys= NULL;
+ }
+
+
+}
+
+static Object *find_family_object(Object **obar, char *family, char ch)
+{
+ Object *ob;
+ int flen;
+
+ if( obar[ch] ) return obar[ch];
+
+ flen= strlen(family);
+
+ ob= G.main->object.first;
+ while(ob) {
+ if( ob->id.name[flen+2]==ch ) {
+ if( strncmp(ob->id.name+2, family, flen)==0 ) break;
+ }
+ ob= ob->id.next;
+ }
+
+ obar[ch]= ob;
+
+ return ob;
+}
+
+
+static void font_duplilist(ListBase *lb, Object *par)
+{
+ Object *ob, *obar[256];
+ Curve *cu;
+ struct chartrans *ct, *chartransdata;
+ float vec[3], obmat[4][4], pmat[4][4], fsize, xof, yof;
+ int slen, a;
+
+ Mat4CpyMat4(pmat, par->obmat);
+
+ /* in par the family name is stored, use this to find the other objects */
+
+ chartransdata= text_to_curve(par, FO_DUPLI);
+ if(chartransdata==0) return;
+
+ memset(obar, 0, 256*sizeof(void *));
+
+ cu= par->data;
+ slen= strlen(cu->str);
+ fsize= cu->fsize;
+ xof= cu->xof;
+ yof= cu->yof;
+
+ ct= chartransdata;
+
+ for(a=0; a<slen; a++, ct++) {
+
+ ob= find_family_object(obar, cu->family, cu->str[a]);
+ if(ob) {
+ vec[0]= fsize*(ct->xof - xof);
+ vec[1]= fsize*(ct->yof - yof);
+ vec[2]= 0.0;
+
+ Mat4MulVecfl(pmat, vec);
+
+ Mat4CpyMat4(obmat, par->obmat);
+ VECCOPY(obmat[3], vec);
+
+ new_dupli_object(lb, ob, obmat, par->lay, a);
+ }
+
+ }
+
+ MEM_freeN(chartransdata);
+}
+
+/* ***************************** */
+
+/* note; group dupli's already set transform matrix. see note in group_duplilist() */
+ListBase *object_duplilist(Scene *sce, Object *ob)
+{
+ ListBase *duplilist= MEM_mallocN(sizeof(ListBase), "duplilist");
+ duplilist->first= duplilist->last= NULL;
+
+ if(ob->transflag & OB_DUPLI) {
+ if(ob->transflag & OB_DUPLIVERTS) {
+ if(ob->type==OB_MESH) {
+ PartEff *paf;
+ if( (paf=give_parteff(ob)) )
+ particle_duplilist(duplilist, sce, ob, paf);
+ else
+ vertex_duplilist(duplilist, sce, ob);
+ }
+ else if(ob->type==OB_FONT) {
+ font_duplilist(duplilist, ob);
+ }
+ }
+ else if(ob->transflag & OB_DUPLIFACES) {
+ if(ob->type==OB_MESH)
+ face_duplilist(duplilist, sce, ob);
+ }
+ else if(ob->transflag & OB_DUPLIFRAMES)
+ frames_duplilist(duplilist, ob);
+ else if(ob->transflag & OB_DUPLIGROUP) {
+ DupliObject *dob;
+
+ group_duplilist(duplilist, ob, 0); /* now recursive */
+
+ /* make copy already, because in group dupli's deform displists can be makde, requiring parent matrices */
+ for(dob= duplilist->first; dob; dob= dob->next)
+ Mat4CpyMat4(dob->ob->obmat, dob->mat);
+ }
+
+ }
+
+ return duplilist;
+}
+
+void free_object_duplilist(ListBase *lb)
+{
+ DupliObject *dob;
+
+ for(dob= lb->first; dob; dob= dob->next) {
+ dob->ob->lay= dob->origlay;
+ Mat4CpyMat4(dob->ob->obmat, dob->omat);
+ }
+
+ BLI_freelistN(lb);
+ MEM_freeN(lb);
+}
+
+int count_duplilist(Object *ob)
+{
+ if(ob->transflag & OB_DUPLI) {
+ if(ob->transflag & OB_DUPLIVERTS) {
+ if(ob->type==OB_MESH) {
+ if(ob->transflag & OB_DUPLIVERTS) {
+ PartEff *paf;
+ if( (paf=give_parteff(ob)) ) {
+ return paf->totpart;
+ }
+ else {
+ Mesh *me= ob->data;
+ return me->totvert;
+ }
+ }
+ }
+ }
+ else if(ob->transflag & OB_DUPLIFRAMES) {
+ int tot= ob->dupend - ob->dupsta;
+ tot/= (ob->dupon+ob->dupoff);
+ return tot*ob->dupon;
+ }
+ }
+ return 1;
+}
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
new file mode 100644
index 00000000000..40f4ae7298e
--- /dev/null
+++ b/source/blender/blenkernel/intern/armature.c
@@ -0,0 +1,2130 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Full recode, Ton Roosendaal, Crete 2005
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <stdio.h>
+#include "MEM_guardedalloc.h"
+
+#include "nla.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+
+#include "DNA_armature_types.h"
+#include "DNA_action_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_nla_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_armature.h"
+#include "BKE_action.h"
+#include "BKE_blender.h"
+#include "BKE_constraint.h"
+#include "BKE_curve.h"
+#include "BKE_deform.h"
+#include "BKE_depsgraph.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_displist.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_lattice.h"
+#include "BKE_main.h"
+#include "BKE_object.h"
+#include "BKE_object.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_editdeform.h"
+
+#include "IK_solver.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* **************** Generic Functions, data level *************** */
+
+bArmature *get_armature(Object *ob)
+{
+ if(ob==NULL) return NULL;
+ if(ob->type==OB_ARMATURE) return ob->data;
+ else return NULL;
+}
+
+bArmature *add_armature(char *name)
+{
+ bArmature *arm;
+
+ arm= alloc_libblock (&G.main->armature, ID_AR, name);
+ arm->deformflag = ARM_DEF_VGROUP|ARM_DEF_ENVELOPE;
+ arm->layer= 1;
+ return arm;
+}
+
+
+void free_boneChildren(Bone *bone)
+{
+ Bone *child;
+
+ if (bone) {
+
+ child=bone->childbase.first;
+ if (child){
+ while (child){
+ free_boneChildren (child);
+ child=child->next;
+ }
+ BLI_freelistN (&bone->childbase);
+ }
+ }
+}
+
+void free_bones (bArmature *arm)
+{
+ Bone *bone;
+ /* Free children (if any) */
+ bone= arm->bonebase.first;
+ if (bone) {
+ while (bone){
+ free_boneChildren (bone);
+ bone=bone->next;
+ }
+ }
+
+
+ BLI_freelistN(&arm->bonebase);
+}
+
+void free_armature(bArmature *arm)
+{
+ if (arm) {
+ /* unlink_armature(arm);*/
+ free_bones(arm);
+ }
+}
+
+void make_local_armature(bArmature *arm)
+{
+ int local=0, lib=0;
+ Object *ob;
+ bArmature *newArm;
+
+ if (arm->id.lib==0)
+ return;
+ if (arm->id.us==1) {
+ arm->id.lib= 0;
+ arm->id.flag= LIB_LOCAL;
+ new_id(0, (ID*)arm, 0);
+ return;
+ }
+
+ if(local && lib==0) {
+ arm->id.lib= 0;
+ arm->id.flag= LIB_LOCAL;
+ new_id(0, (ID *)arm, 0);
+ }
+ else if(local && lib) {
+ newArm= copy_armature(arm);
+ newArm->id.us= 0;
+
+ ob= G.main->object.first;
+ while(ob) {
+ if(ob->data==arm) {
+
+ if(ob->id.lib==0) {
+ ob->data= newArm;
+ newArm->id.us++;
+ arm->id.us--;
+ }
+ }
+ ob= ob->id.next;
+ }
+ }
+}
+
+static void copy_bonechildren (Bone* newBone, Bone* oldBone)
+{
+ Bone *curBone, *newChildBone;
+
+ /* Copy this bone's list*/
+ duplicatelist (&newBone->childbase, &oldBone->childbase);
+
+ /* For each child in the list, update it's children*/
+ newChildBone=newBone->childbase.first;
+ for (curBone=oldBone->childbase.first;curBone;curBone=curBone->next){
+ newChildBone->parent=newBone;
+ copy_bonechildren(newChildBone,curBone);
+ newChildBone=newChildBone->next;
+ }
+}
+
+bArmature *copy_armature(bArmature *arm)
+{
+ bArmature *newArm;
+ Bone *oldBone, *newBone;
+
+ newArm= copy_libblock (arm);
+ duplicatelist(&newArm->bonebase, &arm->bonebase);
+
+ /* Duplicate the childrens' lists*/
+ newBone=newArm->bonebase.first;
+ for (oldBone=arm->bonebase.first;oldBone;oldBone=oldBone->next){
+ newBone->parent=NULL;
+ copy_bonechildren (newBone, oldBone);
+ newBone=newBone->next;
+ };
+
+ return newArm;
+}
+
+static Bone *get_named_bone_bonechildren (Bone *bone, const char *name)
+{
+ Bone *curBone, *rbone;
+
+ if (!strcmp (bone->name, name))
+ return bone;
+
+ for (curBone=bone->childbase.first; curBone; curBone=curBone->next){
+ rbone=get_named_bone_bonechildren (curBone, name);
+ if (rbone)
+ return rbone;
+ }
+
+ return NULL;
+}
+
+
+Bone *get_named_bone (bArmature *arm, const char *name)
+/*
+ Walk the list until the bone is found
+ */
+{
+ Bone *bone=NULL, *curBone;
+
+ if (!arm) return NULL;
+
+ for (curBone=arm->bonebase.first; curBone; curBone=curBone->next){
+ bone = get_named_bone_bonechildren (curBone, name);
+ if (bone)
+ return bone;
+ }
+
+ return bone;
+}
+
+
+#define IS_SEPARATOR(a) (a=='.' || a==' ' || a=='-' || a=='_')
+
+/* finds the best possible flipped name. For renaming; check for unique names afterwards */
+/* if strip_number: removes number extensions */
+void bone_flip_name (char *name, int strip_number)
+{
+ int len;
+ char prefix[128]={""}; /* The part before the facing */
+ char suffix[128]={""}; /* The part after the facing */
+ char replace[128]={""}; /* The replacement string */
+ char number[128]={""}; /* The number extension string */
+ char *index=NULL;
+
+ len= strlen(name);
+ if(len<3) return; // we don't do names like .R or .L
+
+ /* We first check the case with a .### extension, let's find the last period */
+ if(isdigit(name[len-1])) {
+ index= strrchr(name, '.'); // last occurrance
+ if (index && isdigit(index[1]) ) { // doesnt handle case bone.1abc2 correct..., whatever!
+ if(strip_number==0)
+ strcpy(number, index);
+ *index= 0;
+ len= strlen(name);
+ }
+ }
+
+ strcpy (prefix, name);
+
+ /* first case; separator . - _ with extensions r R l L */
+ if( IS_SEPARATOR(name[len-2]) ) {
+ switch(name[len-1]) {
+ case 'l':
+ prefix[len-1]= 0;
+ strcpy(replace, "r");
+ break;
+ case 'r':
+ prefix[len-1]= 0;
+ strcpy(replace, "l");
+ break;
+ case 'L':
+ prefix[len-1]= 0;
+ strcpy(replace, "R");
+ break;
+ case 'R':
+ prefix[len-1]= 0;
+ strcpy(replace, "L");
+ break;
+ }
+ }
+ /* case; beginning with r R l L , with separator after it */
+ else if( IS_SEPARATOR(name[1]) ) {
+ switch(name[0]) {
+ case 'l':
+ strcpy(replace, "r");
+ strcpy(suffix, name+1);
+ prefix[0]= 0;
+ break;
+ case 'r':
+ strcpy(replace, "l");
+ strcpy(suffix, name+1);
+ prefix[0]= 0;
+ break;
+ case 'L':
+ strcpy(replace, "R");
+ strcpy(suffix, name+1);
+ prefix[0]= 0;
+ break;
+ case 'R':
+ strcpy(replace, "L");
+ strcpy(suffix, name+1);
+ prefix[0]= 0;
+ break;
+ }
+ }
+ else if(len > 5) {
+ /* hrms, why test for a separator? lets do the rule 'ultimate left or right' */
+ index = BLI_strcasestr(prefix, "right");
+ if (index==prefix || index==prefix+len-5) {
+ if(index[0]=='r')
+ strcpy (replace, "left");
+ else {
+ if(index[1]=='I')
+ strcpy (replace, "LEFT");
+ else
+ strcpy (replace, "Left");
+ }
+ *index= 0;
+ strcpy (suffix, index+5);
+ }
+ else {
+ index = BLI_strcasestr(prefix, "left");
+ if (index==prefix || index==prefix+len-4) {
+ if(index[0]=='l')
+ strcpy (replace, "right");
+ else {
+ if(index[1]=='E')
+ strcpy (replace, "RIGHT");
+ else
+ strcpy (replace, "Right");
+ }
+ *index= 0;
+ strcpy (suffix, index+4);
+ }
+ }
+ }
+
+ sprintf (name, "%s%s%s%s", prefix, replace, suffix, number);
+}
+
+
+/* ************* B-Bone support ******************* */
+
+#define MAX_BBONE_SUBDIV 32
+
+/* data has MAX_BBONE_SUBDIV+1 interpolated points, will become desired amount with equal distances */
+static void equalize_bezier(float *data, int desired)
+{
+ float *fp, totdist, ddist, dist, fac1, fac2;
+ float pdist[MAX_BBONE_SUBDIV+1];
+ float temp[MAX_BBONE_SUBDIV+1][4];
+ int a, nr;
+
+ pdist[0]= 0.0f;
+ for(a=0, fp= data; a<MAX_BBONE_SUBDIV; a++, fp+=4) {
+ QUATCOPY(temp[a], fp);
+ pdist[a+1]= pdist[a]+VecLenf(fp, fp+4);
+ }
+ /* do last point */
+ QUATCOPY(temp[a], fp);
+ totdist= pdist[a];
+
+ /* go over distances and calculate new points */
+ ddist= totdist/((float)desired);
+ nr= 1;
+ for(a=1, fp= data+4; a<desired; a++, fp+=4) {
+
+ dist= ((float)a)*ddist;
+
+ /* we're looking for location (distance) 'dist' in the array */
+ while((dist>= pdist[nr]) && nr<MAX_BBONE_SUBDIV) {
+ nr++;
+ }
+
+ fac1= pdist[nr]- pdist[nr-1];
+ fac2= pdist[nr]-dist;
+ fac1= fac2/fac1;
+ fac2= 1.0f-fac1;
+
+ fp[0]= fac1*temp[nr-1][0]+ fac2*temp[nr][0];
+ fp[1]= fac1*temp[nr-1][1]+ fac2*temp[nr][1];
+ fp[2]= fac1*temp[nr-1][2]+ fac2*temp[nr][2];
+ fp[3]= fac1*temp[nr-1][3]+ fac2*temp[nr][3];
+ }
+ /* set last point, needed for orientation calculus */
+ QUATCOPY(fp, temp[MAX_BBONE_SUBDIV]);
+}
+
+/* returns pointer to static array, filled with desired amount of bone->segments elements */
+/* this calculation is done within unit bone space */
+Mat4 *b_bone_spline_setup(bPoseChannel *pchan, int rest)
+{
+ static Mat4 bbone_array[MAX_BBONE_SUBDIV];
+ static Mat4 bbone_rest_array[MAX_BBONE_SUBDIV];
+ Mat4 *result_array= (rest)? bbone_rest_array: bbone_array;
+ bPoseChannel *next, *prev;
+ Bone *bone= pchan->bone;
+ float h1[3], h2[3], scale[3], length, hlength1, hlength2, roll1=0.0f, roll2;
+ float mat3[3][3], imat[4][4], posemat[4][4], scalemat[4][4], iscalemat[4][4];
+ float data[MAX_BBONE_SUBDIV+1][4], *fp;
+ int a, doscale= 0;
+
+ length= bone->length;
+
+ if(!rest) {
+ /* check if we need to take non-uniform bone scaling into account */
+ scale[0]= VecLength(pchan->pose_mat[0]);
+ scale[1]= VecLength(pchan->pose_mat[1]);
+ scale[2]= VecLength(pchan->pose_mat[2]);
+
+ if(fabs(scale[0] - scale[1]) > 1e-6f || fabs(scale[1] - scale[2]) > 1e-6f) {
+ Mat4One(scalemat);
+ scalemat[0][0]= scale[0];
+ scalemat[1][1]= scale[1];
+ scalemat[2][2]= scale[2];
+ Mat4Invert(iscalemat, scalemat);
+
+ length *= scale[1];
+ doscale = 1;
+ }
+ }
+
+ hlength1= bone->ease1*length*0.390464f; // 0.5*sqrt(2)*kappa, the handle length for near-perfect circles
+ hlength2= bone->ease2*length*0.390464f;
+
+ /* evaluate next and prev bones */
+ if(bone->flag & BONE_CONNECTED)
+ prev= pchan->parent;
+ else
+ prev= NULL;
+
+ next= pchan->child;
+
+ /* find the handle points, since this is inside bone space, the
+ first point = (0,0,0)
+ last point = (0, length, 0) */
+
+ if(rest) {
+ Mat4Invert(imat, pchan->bone->arm_mat);
+ }
+ else if(doscale) {
+ Mat4CpyMat4(posemat, pchan->pose_mat);
+ Mat4Ortho(posemat);
+ Mat4Invert(imat, posemat);
+ }
+ else
+ Mat4Invert(imat, pchan->pose_mat);
+
+ if(prev) {
+ float difmat[4][4], result[3][3], imat3[3][3];
+
+ /* transform previous point inside this bone space */
+ if(rest)
+ VECCOPY(h1, prev->bone->arm_head)
+ else
+ VECCOPY(h1, prev->pose_head)
+ Mat4MulVecfl(imat, h1);
+
+ if(prev->bone->segments>1) {
+ /* if previous bone is B-bone too, use average handle direction */
+ h1[1]-= length;
+ roll1= 0.0f;
+ }
+
+ Normalize(h1);
+ VecMulf(h1, -hlength1);
+
+ if(prev->bone->segments==1) {
+ /* find the previous roll to interpolate */
+ if(rest)
+ Mat4MulMat4(difmat, prev->bone->arm_mat, imat);
+ else
+ Mat4MulMat4(difmat, prev->pose_mat, imat);
+ Mat3CpyMat4(result, difmat); // the desired rotation at beginning of next bone
+
+ vec_roll_to_mat3(h1, 0.0f, mat3); // the result of vec_roll without roll
+
+ Mat3Inv(imat3, mat3);
+ Mat3MulMat3(mat3, result, imat3); // the matrix transforming vec_roll to desired roll
+
+ roll1= atan2(mat3[2][0], mat3[2][2]);
+ }
+ }
+ else {
+ h1[0]= 0.0f; h1[1]= hlength1; h1[2]= 0.0f;
+ roll1= 0.0f;
+ }
+ if(next) {
+ float difmat[4][4], result[3][3], imat3[3][3];
+
+ /* transform next point inside this bone space */
+ if(rest)
+ VECCOPY(h2, next->bone->arm_tail)
+ else
+ VECCOPY(h2, next->pose_tail)
+ Mat4MulVecfl(imat, h2);
+ /* if next bone is B-bone too, use average handle direction */
+ if(next->bone->segments>1);
+ else h2[1]-= length;
+ Normalize(h2);
+
+ /* find the next roll to interpolate as well */
+ if(rest)
+ Mat4MulMat4(difmat, next->bone->arm_mat, imat);
+ else
+ Mat4MulMat4(difmat, next->pose_mat, imat);
+ Mat3CpyMat4(result, difmat); // the desired rotation at beginning of next bone
+
+ vec_roll_to_mat3(h2, 0.0f, mat3); // the result of vec_roll without roll
+
+ Mat3Inv(imat3, mat3);
+ Mat3MulMat3(mat3, imat3, result); // the matrix transforming vec_roll to desired roll
+
+ roll2= atan2(mat3[2][0], mat3[2][2]);
+
+ /* and only now negate handle */
+ VecMulf(h2, -hlength2);
+ }
+ else {
+ h2[0]= 0.0f; h2[1]= -hlength2; h2[2]= 0.0f;
+ roll2= 0.0;
+ }
+
+ /* make curve */
+ if(bone->segments > MAX_BBONE_SUBDIV)
+ bone->segments= MAX_BBONE_SUBDIV;
+
+ forward_diff_bezier(0.0, h1[0], h2[0], 0.0, data[0], MAX_BBONE_SUBDIV, 4);
+ forward_diff_bezier(0.0, h1[1], length + h2[1], length, data[0]+1, MAX_BBONE_SUBDIV, 4);
+ forward_diff_bezier(0.0, h1[2], h2[2], 0.0, data[0]+2, MAX_BBONE_SUBDIV, 4);
+ forward_diff_bezier(roll1, roll1 + 0.390464f*(roll2-roll1), roll2 - 0.390464f*(roll2-roll1), roll2, data[0]+3, MAX_BBONE_SUBDIV, 4);
+
+ equalize_bezier(data[0], bone->segments); // note: does stride 4!
+
+ /* make transformation matrices for the segments for drawing */
+ for(a=0, fp= data[0]; a<bone->segments; a++, fp+=4) {
+ VecSubf(h1, fp+4, fp);
+ vec_roll_to_mat3(h1, fp[3], mat3); // fp[3] is roll
+
+ Mat4CpyMat3(result_array[a].mat, mat3);
+ VECCOPY(result_array[a].mat[3], fp);
+
+ if(doscale) {
+ /* correct for scaling when this matrix is used in scaled space */
+ Mat4MulSerie(result_array[a].mat, iscalemat, result_array[a].mat,
+ scalemat, NULL, NULL, NULL, NULL, NULL);
+ }
+ }
+
+ return result_array;
+}
+
+/* ************ Armature Deform ******************* */
+
+static void pchan_b_bone_defmats(bPoseChannel *pchan, int use_quaternion, int rest_def)
+{
+ Bone *bone= pchan->bone;
+ Mat4 *b_bone= b_bone_spline_setup(pchan, 0);
+ Mat4 *b_bone_rest= (rest_def)? NULL: b_bone_spline_setup(pchan, 1);
+ Mat4 *b_bone_mats;
+ DualQuat *b_bone_dual_quats= NULL;
+ float tmat[4][4];
+ int a;
+
+ /* allocate b_bone matrices and dual quats */
+ b_bone_mats= MEM_mallocN((1+bone->segments)*sizeof(Mat4), "BBone defmats");
+ pchan->b_bone_mats= b_bone_mats;
+
+ if(use_quaternion) {
+ b_bone_dual_quats= MEM_mallocN((bone->segments)*sizeof(DualQuat), "BBone dqs");
+ pchan->b_bone_dual_quats= b_bone_dual_quats;
+ }
+
+ /* first matrix is the inverse arm_mat, to bring points in local bone space
+ for finding out which segment it belongs to */
+ Mat4Invert(b_bone_mats[0].mat, bone->arm_mat);
+
+ /* then we make the b_bone_mats:
+ - first transform to local bone space
+ - translate over the curve to the bbone mat space
+ - transform with b_bone matrix
+ - transform back into global space */
+ Mat4One(tmat);
+
+ for(a=0; a<bone->segments; a++) {
+ if(b_bone_rest)
+ Mat4Invert(tmat, b_bone_rest[a].mat);
+ else
+ tmat[3][1] = -a*(bone->length/(float)bone->segments);
+
+ Mat4MulSerie(b_bone_mats[a+1].mat, pchan->chan_mat, bone->arm_mat,
+ b_bone[a].mat, tmat, b_bone_mats[0].mat, NULL, NULL, NULL);
+
+ if(use_quaternion)
+ Mat4ToDQuat(bone->arm_mat, b_bone_mats[a+1].mat, &b_bone_dual_quats[a]);
+ }
+}
+
+static void b_bone_deform(bPoseChannel *pchan, Bone *bone, float *co, DualQuat *dq, float defmat[][3])
+{
+ Mat4 *b_bone= pchan->b_bone_mats;
+ float (*mat)[4]= b_bone[0].mat;
+ float segment, y;
+ int a;
+
+ /* need to transform co back to bonespace, only need y */
+ y= mat[0][1]*co[0] + mat[1][1]*co[1] + mat[2][1]*co[2] + mat[3][1];
+
+ /* now calculate which of the b_bones are deforming this */
+ segment= bone->length/((float)bone->segments);
+ a= (int)(y/segment);
+
+ /* note; by clamping it extends deform at endpoints, goes best with
+ straight joints in restpos. */
+ CLAMP(a, 0, bone->segments-1);
+
+ if(dq) {
+ DQuatCpyDQuat(dq, &((DualQuat*)pchan->b_bone_dual_quats)[a]);
+ }
+ else {
+ Mat4MulVecfl(b_bone[a+1].mat, co);
+
+ if(defmat)
+ Mat3CpyMat4(defmat, b_bone[a+1].mat);
+ }
+}
+
+/* using vec with dist to bone b1 - b2 */
+float distfactor_to_bone (float vec[3], float b1[3], float b2[3], float rad1, float rad2, float rdist)
+{
+ float dist=0.0f;
+ float bdelta[3];
+ float pdelta[3];
+ float hsqr, a, l, rad;
+
+ VecSubf (bdelta, b2, b1);
+ l = Normalize (bdelta);
+
+ VecSubf (pdelta, vec, b1);
+
+ a = bdelta[0]*pdelta[0] + bdelta[1]*pdelta[1] + bdelta[2]*pdelta[2];
+ hsqr = ((pdelta[0]*pdelta[0]) + (pdelta[1]*pdelta[1]) + (pdelta[2]*pdelta[2]));
+
+ if (a < 0.0F){
+ /* If we're past the end of the bone, do a spherical field attenuation thing */
+ dist= ((b1[0]-vec[0])*(b1[0]-vec[0]) +(b1[1]-vec[1])*(b1[1]-vec[1]) +(b1[2]-vec[2])*(b1[2]-vec[2])) ;
+ rad= rad1;
+ }
+ else if (a > l){
+ /* If we're past the end of the bone, do a spherical field attenuation thing */
+ dist= ((b2[0]-vec[0])*(b2[0]-vec[0]) +(b2[1]-vec[1])*(b2[1]-vec[1]) +(b2[2]-vec[2])*(b2[2]-vec[2])) ;
+ rad= rad2;
+ }
+ else {
+ dist= (hsqr - (a*a));
+
+ if(l!=0.0f) {
+ rad= a/l;
+ rad= rad*rad2 + (1.0-rad)*rad1;
+ }
+ else rad= rad1;
+ }
+
+ a= rad*rad;
+ if(dist < a)
+ return 1.0f;
+ else {
+ l= rad+rdist;
+ l*= l;
+ if(rdist==0.0f || dist >= l)
+ return 0.0f;
+ else {
+ a= sqrt(dist)-rad;
+ return 1.0-( a*a )/( rdist*rdist );
+ }
+ }
+}
+
+static void pchan_deform_mat_add(bPoseChannel *pchan, float weight, float bbonemat[][3], float mat[][3])
+{
+ float wmat[3][3];
+
+ if(pchan->bone->segments>1)
+ Mat3CpyMat3(wmat, bbonemat);
+ else
+ Mat3CpyMat4(wmat, pchan->chan_mat);
+
+ Mat3MulFloat((float*)wmat, weight);
+ Mat3AddMat3(mat, mat, wmat);
+}
+
+static float dist_bone_deform(bPoseChannel *pchan, float *vec, DualQuat *dq, float mat[][3], float *co)
+{
+ Bone *bone= pchan->bone;
+ float fac, contrib=0.0;
+ float cop[3], bbonemat[3][3];
+ DualQuat bbonedq;
+
+ if(bone==NULL) return 0.0f;
+
+ VECCOPY (cop, co);
+
+ fac= distfactor_to_bone(cop, bone->arm_head, bone->arm_tail, bone->rad_head, bone->rad_tail, bone->dist);
+
+ if (fac>0.0) {
+
+ fac*=bone->weight;
+ contrib= fac;
+ if(contrib>0.0) {
+ if(vec) {
+ if(bone->segments>1)
+ // applies on cop and bbonemat
+ b_bone_deform(pchan, bone, cop, NULL, (mat)?bbonemat:NULL);
+ else
+ Mat4MulVecfl(pchan->chan_mat, cop);
+
+ // Make this a delta from the base position
+ VecSubf (cop, cop, co);
+ cop[0]*=fac; cop[1]*=fac; cop[2]*=fac;
+ VecAddf (vec, vec, cop);
+
+ if(mat)
+ pchan_deform_mat_add(pchan, fac, bbonemat, mat);
+ }
+ else {
+ if(bone->segments>1) {
+ b_bone_deform(pchan, bone, cop, &bbonedq, NULL);
+ DQuatAddWeighted(dq, &bbonedq, fac);
+ }
+ else
+ DQuatAddWeighted(dq, pchan->dual_quat, fac);
+ }
+ }
+ }
+
+ return contrib;
+}
+
+static void pchan_bone_deform(bPoseChannel *pchan, float weight, float *vec, DualQuat *dq, float mat[][3], float *co, float *contrib)
+{
+ float cop[3], bbonemat[3][3];
+ DualQuat bbonedq;
+
+ if (!weight)
+ return;
+
+ VECCOPY(cop, co);
+
+ if(vec) {
+ if(pchan->bone->segments>1)
+ // applies on cop and bbonemat
+ b_bone_deform(pchan, pchan->bone, cop, NULL, (mat)?bbonemat:NULL);
+ else
+ Mat4MulVecfl(pchan->chan_mat, cop);
+
+ vec[0]+=(cop[0]-co[0])*weight;
+ vec[1]+=(cop[1]-co[1])*weight;
+ vec[2]+=(cop[2]-co[2])*weight;
+
+ if(mat)
+ pchan_deform_mat_add(pchan, weight, bbonemat, mat);
+ }
+ else {
+ if(pchan->bone->segments>1) {
+ b_bone_deform(pchan, pchan->bone, cop, &bbonedq, NULL);
+ DQuatAddWeighted(dq, &bbonedq, weight);
+ }
+ else
+ DQuatAddWeighted(dq, pchan->dual_quat, weight);
+ }
+
+ (*contrib)+=weight;
+}
+
+void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm,
+ float (*vertexCos)[3], float (*defMats)[3][3],
+ int numVerts, int deformflag, const char *defgrp_name)
+{
+ bPoseChannel *pchan, **defnrToPC = NULL;
+ MDeformVert *dverts = NULL;
+ bDeformGroup *dg;
+ DualQuat *dualquats= NULL;
+ float obinv[4][4], premat[4][4], postmat[4][4];
+ int use_envelope = deformflag & ARM_DEF_ENVELOPE;
+ int use_quaternion = deformflag & ARM_DEF_QUATERNION;
+ int bbone_rest_def = deformflag & ARM_DEF_B_BONE_REST;
+ int numGroups = 0; /* safety for vertexgroup index overflow */
+ int i, target_totvert = 0; /* safety for vertexgroup overflow */
+ int use_dverts = 0;
+ int armature_def_nr = -1;
+ int totchan;
+
+ if(armOb == G.obedit) return;
+
+ Mat4Invert(obinv, target->obmat);
+ Mat4CpyMat4(premat, target->obmat);
+ Mat4MulMat4(postmat, armOb->obmat, obinv);
+ Mat4Invert(premat, postmat);
+
+ /* bone defmats are already in the channels, chan_mat */
+
+ /* initialize B_bone matrices and dual quaternions */
+ if(use_quaternion) {
+ totchan= BLI_countlist(&armOb->pose->chanbase);
+ dualquats= MEM_callocN(sizeof(DualQuat)*totchan, "dualquats");
+ }
+
+ totchan= 0;
+ for(pchan = armOb->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if(!(pchan->bone->flag & BONE_NO_DEFORM)) {
+ if(pchan->bone->segments > 1)
+ pchan_b_bone_defmats(pchan, use_quaternion, bbone_rest_def);
+
+ if(use_quaternion) {
+ pchan->dual_quat= &dualquats[totchan++];
+ Mat4ToDQuat(pchan->bone->arm_mat, pchan->chan_mat, pchan->dual_quat);
+ }
+ }
+ }
+
+ /* get the def_nr for the overall armature vertex group if present */
+ for(i = 0, dg = target->defbase.first; dg; i++, dg = dg->next)
+ if(defgrp_name && strcmp(defgrp_name, dg->name) == 0)
+ armature_def_nr = i;
+
+ /* get a vertex-deform-index to posechannel array */
+ if(deformflag & ARM_DEF_VGROUP) {
+ if(ELEM(target->type, OB_MESH, OB_LATTICE)) {
+ numGroups = BLI_countlist(&target->defbase);
+
+ if(target->type==OB_MESH) {
+ Mesh *me= target->data;
+ dverts = me->dvert;
+ target_totvert = me->totvert;
+ }
+ else {
+ Lattice *lt= target->data;
+ dverts = lt->dvert;
+ if(dverts)
+ target_totvert = lt->pntsu*lt->pntsv*lt->pntsw;
+ }
+ /* if we have a DerivedMesh, only use dverts if it has them */
+ if(dm)
+ if(dm->getVertData(dm, 0, CD_MDEFORMVERT))
+ use_dverts = 1;
+ else use_dverts = 0;
+ else if(dverts) use_dverts = 1;
+
+ if(use_dverts) {
+ defnrToPC = MEM_callocN(sizeof(*defnrToPC) * numGroups,
+ "defnrToBone");
+ for(i = 0, dg = target->defbase.first; dg;
+ i++, dg = dg->next) {
+ defnrToPC[i] = get_pose_channel(armOb->pose, dg->name);
+ /* exclude non-deforming bones */
+ if(defnrToPC[i]) {
+ if(defnrToPC[i]->bone->flag & BONE_NO_DEFORM)
+ defnrToPC[i]= NULL;
+ }
+ }
+ }
+ }
+ }
+
+ for(i = 0; i < numVerts; i++) {
+ MDeformVert *dvert;
+ DualQuat sumdq, *dq = NULL;
+ float *co = vertexCos[i], dco[3];
+ float sumvec[3], summat[3][3];
+ float *vec = NULL, (*smat)[3] = NULL;
+ float contrib = 0.0f;
+ float armature_weight = 1.0f; /* default to 1 if no overall def group */
+ int j;
+
+ if(use_quaternion) {
+ memset(&sumdq, 0, sizeof(DualQuat));
+ dq= &sumdq;
+ }
+ else {
+ sumvec[0] = sumvec[1] = sumvec[2] = 0.0f;
+ vec= sumvec;
+
+ if(defMats) {
+ Mat3Clr((float*)summat);
+ smat = summat;
+ }
+ }
+
+ if(use_dverts || armature_def_nr >= 0) {
+ if(dm) dvert = dm->getVertData(dm, i, CD_MDEFORMVERT);
+ else if(dverts && i < target_totvert) dvert = dverts + i;
+ else dvert = NULL;
+ } else
+ dvert = NULL;
+
+ if(armature_def_nr >= 0 && dvert) {
+ armature_weight = 0.0f; /* a def group was given, so default to 0 */
+ for(j = 0; j < dvert->totweight; j++) {
+ if(dvert->dw[j].def_nr == armature_def_nr) {
+ armature_weight = dvert->dw[j].weight;
+ break;
+ }
+ }
+ }
+
+ /* check if there's any point in calculating for this vert */
+ if(armature_weight == 0.0f) continue;
+
+ /* Apply the object's matrix */
+ Mat4MulVecfl(premat, co);
+
+ if(use_dverts && dvert && dvert->totweight) { // use weight groups ?
+ int deformed = 0;
+
+ for(j = 0; j < dvert->totweight; j++){
+ int index = dvert->dw[j].def_nr;
+ pchan = index < numGroups?defnrToPC[index]:NULL;
+ if(pchan) {
+ float weight = dvert->dw[j].weight;
+ Bone *bone = pchan->bone;
+
+ deformed = 1;
+
+ if(bone && bone->flag & BONE_MULT_VG_ENV) {
+ weight *= distfactor_to_bone(co, bone->arm_head,
+ bone->arm_tail,
+ bone->rad_head,
+ bone->rad_tail,
+ bone->dist);
+ }
+ pchan_bone_deform(pchan, weight, vec, dq, smat, co, &contrib);
+ }
+ }
+ /* if there are vertexgroups but not groups with bones
+ * (like for softbody groups)
+ */
+ if(deformed == 0 && use_envelope) {
+ for(pchan = armOb->pose->chanbase.first; pchan;
+ pchan = pchan->next) {
+ if(!(pchan->bone->flag & BONE_NO_DEFORM))
+ contrib += dist_bone_deform(pchan, vec, dq, smat, co);
+ }
+ }
+ }
+ else if(use_envelope) {
+ for(pchan = armOb->pose->chanbase.first; pchan;
+ pchan = pchan->next) {
+ if(!(pchan->bone->flag & BONE_NO_DEFORM))
+ contrib += dist_bone_deform(pchan, vec, dq, smat, co);
+ }
+ }
+
+ /* actually should be EPSILON? weight values and contrib can be like 10e-39 small */
+ if(contrib > 0.0001f) {
+ if(use_quaternion) {
+ DQuatNormalize(dq, contrib, armature_weight);
+
+ if(armature_weight != 1.0f) {
+ VECCOPY(dco, co);
+ DQuatMulVecfl(dq, dco, (defMats)? summat: NULL);
+ VecSubf(dco, dco, co);
+ VecMulf(dco, armature_weight);
+ VecAddf(co, co, dco);
+ }
+ else
+ DQuatMulVecfl(dq, co, (defMats)? summat: NULL);
+
+ smat = summat;
+ }
+ else {
+ VecMulf(vec, armature_weight/contrib);
+ VecAddf(co, vec, co);
+ }
+
+ if(defMats) {
+ float pre[3][3], post[3][3], tmpmat[3][3];
+
+ Mat3CpyMat4(pre, premat);
+ Mat3CpyMat4(post, postmat);
+ Mat3CpyMat3(tmpmat, defMats[i]);
+
+ if(!use_quaternion) /* quaternion already is scale corrected */
+ Mat3MulFloat((float*)smat, armature_weight/contrib);
+
+ Mat3MulSerie(defMats[i], tmpmat, pre, smat, post,
+ NULL, NULL, NULL, NULL);
+ }
+ }
+
+ /* always, check above code */
+ Mat4MulVecfl(postmat, co);
+ }
+
+ if(dualquats) MEM_freeN(dualquats);
+ if(defnrToPC) MEM_freeN(defnrToPC);
+
+ /* free B_bone matrices */
+ for(pchan = armOb->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if(pchan->b_bone_mats) {
+ MEM_freeN(pchan->b_bone_mats);
+ pchan->b_bone_mats = NULL;
+ }
+ if(pchan->b_bone_dual_quats) {
+ MEM_freeN(pchan->b_bone_dual_quats);
+ pchan->b_bone_dual_quats = NULL;
+ }
+
+ pchan->dual_quat = NULL;
+ }
+}
+
+/* ************ END Armature Deform ******************* */
+
+void get_objectspace_bone_matrix (struct Bone* bone, float M_accumulatedMatrix[][4], int root, int posed)
+{
+ Mat4CpyMat4(M_accumulatedMatrix, bone->arm_mat);
+}
+
+/* **************** Space to Space API ****************** */
+
+/* Convert World-Space Matrix to Pose-Space Matrix */
+void armature_mat_world_to_pose(Object *ob, float inmat[][4], float outmat[][4])
+{
+ float obmat[4][4];
+
+ /* prevent crashes */
+ if (ob==NULL) return;
+
+ /* get inverse of (armature) object's matrix */
+ Mat4Invert(obmat, ob->obmat);
+
+ /* multiply given matrix by object's-inverse to find pose-space matrix */
+ Mat4MulMat4(outmat, obmat, inmat);
+}
+
+/* Convert Wolrd-Space Location to Pose-Space Location
+ * NOTE: this cannot be used to convert to pose-space location of the supplied
+ * pose-channel into its local space (i.e. 'visual'-keyframing)
+ */
+void armature_loc_world_to_pose(Object *ob, float *inloc, float *outloc)
+{
+ float xLocMat[4][4];
+ float nLocMat[4][4];
+
+ /* build matrix for location */
+ Mat4One(xLocMat);
+ VECCOPY(xLocMat[3], inloc);
+
+ /* get bone-space cursor matrix and extract location */
+ armature_mat_world_to_pose(ob, xLocMat, nLocMat);
+ VECCOPY(outloc, nLocMat[3]);
+}
+
+/* Convert Pose-Space Matrix to Bone-Space Matrix
+ * NOTE: this cannot be used to convert to pose-space transforms of the supplied
+ * pose-channel into its local space (i.e. 'visual'-keyframing)
+ */
+void armature_mat_pose_to_bone(bPoseChannel *pchan, float inmat[][4], float outmat[][4])
+{
+ float pc_trans[4][4], inv_trans[4][4];
+ float pc_posemat[4][4], inv_posemat[4][4];
+
+ /* paranoia: prevent crashes with no pose-channel supplied */
+ if (pchan==NULL) return;
+
+ /* get the inverse matrix of the pchan's transforms */
+ LocQuatSizeToMat4(pc_trans, pchan->loc, pchan->quat, pchan->size);
+ Mat4Invert(inv_trans, pc_trans);
+
+ /* Remove the pchan's transforms from it's pose_mat.
+ * This should leave behind the effects of restpose +
+ * parenting + constraints
+ */
+ Mat4MulMat4(pc_posemat, inv_trans, pchan->pose_mat);
+
+ /* get the inverse of the leftovers so that we can remove
+ * that component from the supplied matrix
+ */
+ Mat4Invert(inv_posemat, pc_posemat);
+
+ /* get the new matrix */
+ Mat4MulMat4(outmat, inmat, inv_posemat);
+}
+
+/* Convert Pose-Space Location to Bone-Space Location
+ * NOTE: this cannot be used to convert to pose-space location of the supplied
+ * pose-channel into its local space (i.e. 'visual'-keyframing)
+ */
+void armature_loc_pose_to_bone(bPoseChannel *pchan, float *inloc, float *outloc)
+{
+ float xLocMat[4][4];
+ float nLocMat[4][4];
+
+ /* build matrix for location */
+ Mat4One(xLocMat);
+ VECCOPY(xLocMat[3], inloc);
+
+ /* get bone-space cursor matrix and extract location */
+ armature_mat_pose_to_bone(pchan, xLocMat, nLocMat);
+ VECCOPY(outloc, nLocMat[3]);
+}
+
+/* Remove rest-position effects from pose-transform for obtaining
+ * 'visual' transformation of pose-channel.
+ * (used by the Visual-Keyframing stuff)
+ */
+void armature_mat_pose_to_delta(float delta_mat[][4], float pose_mat[][4], float arm_mat[][4])
+{
+ float imat[4][4];
+
+ Mat4Invert(imat, arm_mat);
+ Mat4MulMat4(delta_mat, pose_mat, imat);
+}
+
+
+/* **************** The new & simple (but OK!) armature evaluation ********* */
+
+/* ****************** And how it works! ****************************************
+
+ This is the bone transformation trick; they're hierarchical so each bone(b)
+ is in the coord system of bone(b-1):
+
+ arm_mat(b)= arm_mat(b-1) * yoffs(b-1) * d_root(b) * bone_mat(b)
+
+ -> yoffs is just the y axis translation in parent's coord system
+ -> d_root is the translation of the bone root, also in parent's coord system
+
+ pose_mat(b)= pose_mat(b-1) * yoffs(b-1) * d_root(b) * bone_mat(b) * chan_mat(b)
+
+ we then - in init deform - store the deform in chan_mat, such that:
+
+ pose_mat(b)= arm_mat(b) * chan_mat(b)
+
+ *************************************************************************** */
+/* Computes vector and roll based on a rotation. "mat" must
+ contain only a rotation, and no scaling. */
+void mat3_to_vec_roll(float mat[][3], float *vec, float *roll)
+{
+ if (vec)
+ VecCopyf(vec, mat[1]);
+
+ if (roll) {
+ float vecmat[3][3], vecmatinv[3][3], rollmat[3][3];
+
+ vec_roll_to_mat3(mat[1], 0.0f, vecmat);
+ Mat3Inv(vecmatinv, vecmat);
+ Mat3MulMat3(rollmat, vecmatinv, mat);
+
+ *roll= atan2(rollmat[2][0], rollmat[2][2]);
+ }
+}
+
+/* Calculates the rest matrix of a bone based
+ On its vector and a roll around that vector */
+void vec_roll_to_mat3(float *vec, float roll, float mat[][3])
+{
+ float nor[3], axis[3], target[3]={0,1,0};
+ float theta;
+ float rMatrix[3][3], bMatrix[3][3];
+
+ VECCOPY (nor, vec);
+ Normalize (nor);
+
+ /* Find Axis & Amount for bone matrix*/
+ Crossf (axis,target,nor);
+
+ if (Inpf(axis,axis) > 0.0000000000001) {
+ /* if nor is *not* a multiple of target ... */
+ Normalize (axis);
+
+ theta= NormalizedVecAngle2(target, nor);
+
+ /* Make Bone matrix*/
+ VecRotToMat3(axis, theta, bMatrix);
+ }
+ else {
+ /* if nor is a multiple of target ... */
+ float updown;
+
+ /* point same direction, or opposite? */
+ updown = ( Inpf (target,nor) > 0 ) ? 1.0 : -1.0;
+
+ /* I think this should work ... */
+ bMatrix[0][0]=updown; bMatrix[0][1]=0.0; bMatrix[0][2]=0.0;
+ bMatrix[1][0]=0.0; bMatrix[1][1]=updown; bMatrix[1][2]=0.0;
+ bMatrix[2][0]=0.0; bMatrix[2][1]=0.0; bMatrix[2][2]=1.0;
+ }
+
+ /* Make Roll matrix*/
+ VecRotToMat3(nor, roll, rMatrix);
+
+ /* Combine and output result*/
+ Mat3MulMat3 (mat, rMatrix, bMatrix);
+}
+
+
+/* recursive part, calculates restposition of entire tree of children */
+/* used by exiting editmode too */
+void where_is_armature_bone(Bone *bone, Bone *prevbone)
+{
+ float vec[3];
+
+ /* Bone Space */
+ VecSubf (vec, bone->tail, bone->head);
+ vec_roll_to_mat3(vec, bone->roll, bone->bone_mat);
+
+ bone->length= VecLenf(bone->head, bone->tail);
+
+ /* this is called on old file reading too... */
+ if(bone->xwidth==0.0) {
+ bone->xwidth= 0.1f;
+ bone->zwidth= 0.1f;
+ bone->segments= 1;
+ }
+
+ if(prevbone) {
+ float offs_bone[4][4]; // yoffs(b-1) + root(b) + bonemat(b)
+
+ /* bone transform itself */
+ Mat4CpyMat3(offs_bone, bone->bone_mat);
+
+ /* The bone's root offset (is in the parent's coordinate system) */
+ VECCOPY(offs_bone[3], bone->head);
+
+ /* Get the length translation of parent (length along y axis) */
+ offs_bone[3][1]+= prevbone->length;
+
+ /* Compose the matrix for this bone */
+ Mat4MulMat4(bone->arm_mat, offs_bone, prevbone->arm_mat);
+ }
+ else {
+ Mat4CpyMat3(bone->arm_mat, bone->bone_mat);
+ VECCOPY(bone->arm_mat[3], bone->head);
+ }
+
+ /* head */
+ VECCOPY(bone->arm_head, bone->arm_mat[3]);
+ /* tail is in current local coord system */
+ VECCOPY(vec, bone->arm_mat[1]);
+ VecMulf(vec, bone->length);
+ VecAddf(bone->arm_tail, bone->arm_head, vec);
+
+ /* and the kiddies */
+ prevbone= bone;
+ for(bone= bone->childbase.first; bone; bone= bone->next) {
+ where_is_armature_bone(bone, prevbone);
+ }
+}
+
+/* updates vectors and matrices on rest-position level, only needed
+ after editing armature itself, now only on reading file */
+void where_is_armature (bArmature *arm)
+{
+ Bone *bone;
+
+ /* hierarchical from root to children */
+ for(bone= arm->bonebase.first; bone; bone= bone->next) {
+ where_is_armature_bone(bone, NULL);
+ }
+}
+
+/* if bone layer is protected, copy the data from from->pose */
+static void pose_proxy_synchronize(Object *ob, Object *from, int layer_protected)
+{
+ bPose *pose= ob->pose, *frompose= from->pose;
+ bPoseChannel *pchan, *pchanp, pchanw;
+ bConstraint *con;
+
+ if(frompose==NULL) return;
+
+ /* exception, armature local layer should be proxied too */
+ if(pose->proxy_layer)
+ ((bArmature *)ob->data)->layer= pose->proxy_layer;
+
+ /* clear all transformation values from library */
+ rest_pose(frompose);
+
+ pchan= pose->chanbase.first;
+ for(; pchan; pchan= pchan->next) {
+ if(pchan->bone->layer & layer_protected) {
+ pchanp= get_pose_channel(frompose, pchan->name);
+
+ /* copy posechannel to temp, but restore important pointers */
+ pchanw= *pchanp;
+ pchanw.prev= pchan->prev;
+ pchanw.next= pchan->next;
+ pchanw.parent= pchan->parent;
+ pchanw.child= pchan->child;
+ pchanw.path= NULL;
+
+ /* constraints, set target ob pointer to own object */
+ copy_constraints(&pchanw.constraints, &pchanp->constraints);
+
+ for (con= pchanw.constraints.first; con; con= con->next) {
+ bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+
+ if (cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(con, &targets);
+
+ for (ct= targets.first; ct; ct= ct->next) {
+ if (ct->tar == from)
+ ct->tar = ob;
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(con, &targets, 0);
+ }
+ }
+
+ /* free stuff from current channel */
+ if (pchan->path) MEM_freeN(pchan->path);
+ free_constraints(&pchan->constraints);
+
+ /* the final copy */
+ *pchan= pchanw;
+ }
+ }
+}
+
+static int rebuild_pose_bone(bPose *pose, Bone *bone, bPoseChannel *parchan, int counter)
+{
+ bPoseChannel *pchan = verify_pose_channel (pose, bone->name); // verify checks and/or adds
+
+ pchan->bone= bone;
+ pchan->parent= parchan;
+
+ counter++;
+
+ for(bone= bone->childbase.first; bone; bone= bone->next) {
+ counter= rebuild_pose_bone(pose, bone, pchan, counter);
+ /* for quick detecting of next bone in chain, only b-bone uses it now */
+ if(bone->flag & BONE_CONNECTED)
+ pchan->child= get_pose_channel(pose, bone->name);
+ }
+
+ return counter;
+}
+
+/* only after leave editmode, duplicating, validating older files, library syncing */
+/* NOTE: pose->flag is set for it */
+void armature_rebuild_pose(Object *ob, bArmature *arm)
+{
+ Bone *bone;
+ bPose *pose;
+ bPoseChannel *pchan, *next;
+ int counter=0;
+
+ /* only done here */
+ if(ob->pose==NULL) ob->pose= MEM_callocN(sizeof(bPose), "new pose");
+ pose= ob->pose;
+
+ /* clear */
+ for(pchan= pose->chanbase.first; pchan; pchan= pchan->next) {
+ pchan->bone= NULL;
+ pchan->child= NULL;
+ }
+
+ /* first step, check if all channels are there */
+ for(bone= arm->bonebase.first; bone; bone= bone->next) {
+ counter= rebuild_pose_bone(pose, bone, NULL, counter);
+ }
+
+ /* and a check for garbage */
+ for(pchan= pose->chanbase.first; pchan; pchan= next) {
+ next= pchan->next;
+ if(pchan->bone==NULL) {
+ if(pchan->path)
+ MEM_freeN(pchan->path);
+ free_constraints(&pchan->constraints);
+ BLI_freelinkN(&pose->chanbase, pchan);
+ }
+ }
+ // printf("rebuild pose %s, %d bones\n", ob->id.name, counter);
+
+ /* synchronize protected layers with proxy */
+ if(ob->proxy)
+ pose_proxy_synchronize(ob, ob->proxy, arm->layer_protected);
+
+ update_pose_constraint_flags(ob->pose); // for IK detection for example
+
+ /* the sorting */
+ if(counter>1)
+ DAG_pose_sort(ob);
+
+ ob->pose->flag &= ~POSE_RECALC;
+}
+
+
+/* ********************** THE IK SOLVER ******************* */
+
+
+
+/* allocates PoseTree, and links that to root bone/channel */
+/* Note: detecting the IK chain is duplicate code... in drawarmature.c and in transform_conversions.c */
+static void initialize_posetree(struct Object *ob, bPoseChannel *pchan_tip)
+{
+ bPoseChannel *curchan, *pchan_root=NULL, *chanlist[256], **oldchan;
+ PoseTree *tree;
+ PoseTarget *target;
+ bConstraint *con;
+ bKinematicConstraint *data;
+ int a, segcount= 0, size, newsize, *oldparent, parent;
+
+ /* find IK constraint, and validate it */
+ for(con= pchan_tip->constraints.first; con; con= con->next) {
+ if(con->type==CONSTRAINT_TYPE_KINEMATIC) break;
+ }
+ if(con==NULL) return;
+
+ data=(bKinematicConstraint*)con->data;
+
+ /* two types of targets */
+ if(data->flag & CONSTRAINT_IK_AUTO);
+ else {
+ if(con->flag & CONSTRAINT_DISABLE) return; /* checked in editconstraint.c */
+ if(con->enforce == 0.0f) return;
+ if(data->tar==NULL) return;
+ if(data->tar->type==OB_ARMATURE && data->subtarget[0]==0) return;
+ }
+
+ /* exclude tip from chain? */
+ if(!(data->flag & CONSTRAINT_IK_TIP))
+ pchan_tip= pchan_tip->parent;
+
+ /* Find the chain's root & count the segments needed */
+ for (curchan = pchan_tip; curchan; curchan=curchan->parent){
+ pchan_root = curchan;
+
+ curchan->flag |= POSE_CHAIN; // don't forget to clear this
+ chanlist[segcount]=curchan;
+ segcount++;
+
+ if(segcount==data->rootbone || segcount>255) break; // 255 is weak
+ }
+ if (!segcount) return;
+
+ /* setup the chain data */
+
+ /* we make tree-IK, unless all existing targets are in this chain */
+ for(tree= pchan_root->iktree.first; tree; tree= tree->next) {
+ for(target= tree->targets.first; target; target= target->next) {
+ curchan= tree->pchan[target->tip];
+ if(curchan->flag & POSE_CHAIN)
+ curchan->flag &= ~POSE_CHAIN;
+ else
+ break;
+ }
+ if(target) break;
+ }
+
+ /* create a target */
+ target= MEM_callocN(sizeof(PoseTarget), "posetarget");
+ target->con= con;
+ pchan_tip->flag &= ~POSE_CHAIN;
+
+ if(tree==NULL) {
+ /* make new tree */
+ tree= MEM_callocN(sizeof(PoseTree), "posetree");
+
+ tree->iterations= data->iterations;
+ tree->totchannel= segcount;
+ tree->stretch = (data->flag & CONSTRAINT_IK_STRETCH);
+
+ tree->pchan= MEM_callocN(segcount*sizeof(void*), "ik tree pchan");
+ tree->parent= MEM_callocN(segcount*sizeof(int), "ik tree parent");
+ for(a=0; a<segcount; a++) {
+ tree->pchan[a]= chanlist[segcount-a-1];
+ tree->parent[a]= a-1;
+ }
+ target->tip= segcount-1;
+
+ /* AND! link the tree to the root */
+ BLI_addtail(&pchan_root->iktree, tree);
+ }
+ else {
+ tree->iterations= MAX2(data->iterations, tree->iterations);
+ tree->stretch= tree->stretch && !(data->flag & CONSTRAINT_IK_STRETCH);
+
+ /* skip common pose channels and add remaining*/
+ size= MIN2(segcount, tree->totchannel);
+ for(a=0; a<size && tree->pchan[a]==chanlist[segcount-a-1]; a++);
+ parent= a-1;
+
+ segcount= segcount-a;
+ target->tip= tree->totchannel + segcount - 1;
+
+ if (segcount > 0) {
+ /* resize array */
+ newsize= tree->totchannel + segcount;
+ oldchan= tree->pchan;
+ oldparent= tree->parent;
+
+ tree->pchan= MEM_callocN(newsize*sizeof(void*), "ik tree pchan");
+ tree->parent= MEM_callocN(newsize*sizeof(int), "ik tree parent");
+ memcpy(tree->pchan, oldchan, sizeof(void*)*tree->totchannel);
+ memcpy(tree->parent, oldparent, sizeof(int)*tree->totchannel);
+ MEM_freeN(oldchan);
+ MEM_freeN(oldparent);
+
+ /* add new pose channels at the end, in reverse order */
+ for(a=0; a<segcount; a++) {
+ tree->pchan[tree->totchannel+a]= chanlist[segcount-a-1];
+ tree->parent[tree->totchannel+a]= tree->totchannel+a-1;
+ }
+ tree->parent[tree->totchannel]= parent;
+
+ tree->totchannel= newsize;
+ }
+
+ /* move tree to end of list, for correct evaluation order */
+ BLI_remlink(&pchan_root->iktree, tree);
+ BLI_addtail(&pchan_root->iktree, tree);
+ }
+
+ /* add target to the tree */
+ BLI_addtail(&tree->targets, target);
+}
+
+/* called from within the core where_is_pose loop, all animsystems and constraints
+were executed & assigned. Now as last we do an IK pass */
+static void execute_posetree(Object *ob, PoseTree *tree)
+{
+ float R_parmat[3][3];
+ float iR_parmat[3][3];
+ float R_bonemat[3][3];
+ float goalrot[3][3], goalpos[3];
+ float rootmat[4][4], imat[4][4];
+ float goal[4][4], goalinv[4][4];
+ float irest_basis[3][3], full_basis[3][3];
+ float end_pose[4][4], world_pose[4][4];
+ float length, basis[3][3], rest_basis[3][3], start[3], *ikstretch=NULL;
+ int a, flag, hasstretch=0;
+ bPoseChannel *pchan;
+ IK_Segment *seg, *parent, **iktree, *iktarget;
+ IK_Solver *solver;
+ PoseTarget *target;
+ bKinematicConstraint *data, *poleangledata=NULL;
+ Bone *bone;
+
+ if (tree->totchannel == 0)
+ return;
+
+ iktree= MEM_mallocN(sizeof(void*)*tree->totchannel, "ik tree");
+
+ for(a=0; a<tree->totchannel; a++) {
+ pchan= tree->pchan[a];
+ bone= pchan->bone;
+
+ /* set DoF flag */
+ flag= 0;
+ if((pchan->ikflag & BONE_IK_NO_XDOF) == 0)
+ flag |= IK_XDOF;
+ if((pchan->ikflag & BONE_IK_NO_YDOF) == 0)
+ flag |= IK_YDOF;
+ if((pchan->ikflag & BONE_IK_NO_ZDOF) == 0)
+ flag |= IK_ZDOF;
+
+ if(tree->stretch && (pchan->ikstretch > 0.0)) {
+ flag |= IK_TRANS_YDOF;
+ hasstretch = 1;
+ }
+
+ seg= iktree[a]= IK_CreateSegment(flag);
+
+ /* find parent */
+ if(a == 0)
+ parent= NULL;
+ else
+ parent= iktree[tree->parent[a]];
+
+ IK_SetParent(seg, parent);
+
+ /* get the matrix that transforms from prevbone into this bone */
+ Mat3CpyMat4(R_bonemat, pchan->pose_mat);
+
+ /* gather transformations for this IK segment */
+
+ if (pchan->parent)
+ Mat3CpyMat4(R_parmat, pchan->parent->pose_mat);
+ else
+ Mat3One(R_parmat);
+
+ /* bone offset */
+ if (pchan->parent && (a > 0))
+ VecSubf(start, pchan->pose_head, pchan->parent->pose_tail);
+ else
+ /* only root bone (a = 0) has no parent */
+ start[0]= start[1]= start[2]= 0.0f;
+
+ /* change length based on bone size */
+ length= bone->length*VecLength(R_bonemat[1]);
+
+ /* compute rest basis and its inverse */
+ Mat3CpyMat3(rest_basis, bone->bone_mat);
+ Mat3CpyMat3(irest_basis, bone->bone_mat);
+ Mat3Transp(irest_basis);
+
+ /* compute basis with rest_basis removed */
+ Mat3Inv(iR_parmat, R_parmat);
+ Mat3MulMat3(full_basis, iR_parmat, R_bonemat);
+ Mat3MulMat3(basis, irest_basis, full_basis);
+
+ /* basis must be pure rotation */
+ Mat3Ortho(basis);
+
+ /* transform offset into local bone space */
+ Mat3Ortho(iR_parmat);
+ Mat3MulVecfl(iR_parmat, start);
+
+ IK_SetTransform(seg, start, rest_basis, basis, length);
+
+ if (pchan->ikflag & BONE_IK_XLIMIT)
+ IK_SetLimit(seg, IK_X, pchan->limitmin[0], pchan->limitmax[0]);
+ if (pchan->ikflag & BONE_IK_YLIMIT)
+ IK_SetLimit(seg, IK_Y, pchan->limitmin[1], pchan->limitmax[1]);
+ if (pchan->ikflag & BONE_IK_ZLIMIT)
+ IK_SetLimit(seg, IK_Z, pchan->limitmin[2], pchan->limitmax[2]);
+
+ IK_SetStiffness(seg, IK_X, pchan->stiffness[0]);
+ IK_SetStiffness(seg, IK_Y, pchan->stiffness[1]);
+ IK_SetStiffness(seg, IK_Z, pchan->stiffness[2]);
+
+ if(tree->stretch && (pchan->ikstretch > 0.0)) {
+ float ikstretch = pchan->ikstretch*pchan->ikstretch;
+ IK_SetStiffness(seg, IK_TRANS_Y, MIN2(1.0-ikstretch, 0.999));
+ IK_SetLimit(seg, IK_TRANS_Y, 0.001, 1e10);
+ }
+ }
+
+ solver= IK_CreateSolver(iktree[0]);
+
+ /* set solver goals */
+
+ /* first set the goal inverse transform, assuming the root of tree was done ok! */
+ pchan= tree->pchan[0];
+ if (pchan->parent)
+ /* transform goal by parent mat, so this rotation is not part of the
+ segment's basis. otherwise rotation limits do not work on the
+ local transform of the segment itself. */
+ Mat4CpyMat4(rootmat, pchan->parent->pose_mat);
+ else
+ Mat4One(rootmat);
+ VECCOPY(rootmat[3], pchan->pose_head);
+
+ Mat4MulMat4 (imat, rootmat, ob->obmat);
+ Mat4Invert (goalinv, imat);
+
+ for (target=tree->targets.first; target; target=target->next) {
+ float polepos[3];
+ int poleconstrain= 0;
+
+ data= (bKinematicConstraint*)target->con->data;
+
+ /* 1.0=ctime, we pass on object for auto-ik (owner-type here is object, even though
+ * strictly speaking, it is a posechannel)
+ */
+ get_constraint_target_matrix(target->con, 0, CONSTRAINT_OBTYPE_OBJECT, ob, rootmat, 1.0);
+
+ /* and set and transform goal */
+ Mat4MulMat4(goal, rootmat, goalinv);
+
+ VECCOPY(goalpos, goal[3]);
+ Mat3CpyMat4(goalrot, goal);
+
+ /* same for pole vector target */
+ if(data->poletar) {
+ get_constraint_target_matrix(target->con, 1, CONSTRAINT_OBTYPE_OBJECT, ob, rootmat, 1.0);
+
+ if(data->flag & CONSTRAINT_IK_SETANGLE) {
+ /* don't solve IK when we are setting the pole angle */
+ break;
+ }
+ else {
+ Mat4MulMat4(goal, rootmat, goalinv);
+ VECCOPY(polepos, goal[3]);
+ poleconstrain= 1;
+
+ if(data->flag & CONSTRAINT_IK_GETANGLE) {
+ poleangledata= data;
+ data->flag &= ~CONSTRAINT_IK_GETANGLE;
+ }
+ }
+ }
+
+ /* do we need blending? */
+ if (target->con->enforce!=1.0) {
+ float q1[4], q2[4], q[4];
+ float fac= target->con->enforce;
+ float mfac= 1.0-fac;
+
+ pchan= tree->pchan[target->tip];
+
+ /* end effector in world space */
+ Mat4CpyMat4(end_pose, pchan->pose_mat);
+ VECCOPY(end_pose[3], pchan->pose_tail);
+ Mat4MulSerie(world_pose, goalinv, ob->obmat, end_pose, 0, 0, 0, 0, 0);
+
+ /* blend position */
+ goalpos[0]= fac*goalpos[0] + mfac*world_pose[3][0];
+ goalpos[1]= fac*goalpos[1] + mfac*world_pose[3][1];
+ goalpos[2]= fac*goalpos[2] + mfac*world_pose[3][2];
+
+ /* blend rotation */
+ Mat3ToQuat(goalrot, q1);
+ Mat4ToQuat(world_pose, q2);
+ QuatInterpol(q, q1, q2, mfac);
+ QuatToMat3(q, goalrot);
+ }
+
+ iktarget= iktree[target->tip];
+
+ if(data->weight != 0.0) {
+ if(poleconstrain)
+ IK_SolverSetPoleVectorConstraint(solver, iktarget, goalpos,
+ polepos, data->poleangle*M_PI/180, (poleangledata == data));
+ IK_SolverAddGoal(solver, iktarget, goalpos, data->weight);
+ }
+ if((data->flag & CONSTRAINT_IK_ROT) && (data->orientweight != 0.0))
+ if((data->flag & CONSTRAINT_IK_AUTO)==0)
+ IK_SolverAddGoalOrientation(solver, iktarget, goalrot,
+ data->orientweight);
+ }
+
+ /* solve */
+ IK_Solve(solver, 0.0f, tree->iterations);
+
+ if(poleangledata)
+ poleangledata->poleangle= IK_SolverGetPoleAngle(solver)*180/M_PI;
+
+ IK_FreeSolver(solver);
+
+ /* gather basis changes */
+ tree->basis_change= MEM_mallocN(sizeof(float[3][3])*tree->totchannel, "ik basis change");
+ if(hasstretch)
+ ikstretch= MEM_mallocN(sizeof(float)*tree->totchannel, "ik stretch");
+
+ for(a=0; a<tree->totchannel; a++) {
+ IK_GetBasisChange(iktree[a], tree->basis_change[a]);
+
+ if(hasstretch) {
+ /* have to compensate for scaling received from parent */
+ float parentstretch, stretch;
+
+ pchan= tree->pchan[a];
+ parentstretch= (tree->parent[a] >= 0)? ikstretch[tree->parent[a]]: 1.0;
+
+ if(tree->stretch && (pchan->ikstretch > 0.0)) {
+ float trans[3], length;
+
+ IK_GetTranslationChange(iktree[a], trans);
+ length= pchan->bone->length*VecLength(pchan->pose_mat[1]);
+
+ ikstretch[a]= (length == 0.0)? 1.0: (trans[1]+length)/length;
+ }
+ else
+ ikstretch[a] = 1.0;
+
+ stretch= (parentstretch == 0.0)? 1.0: ikstretch[a]/parentstretch;
+
+ VecMulf(tree->basis_change[a][0], stretch);
+ VecMulf(tree->basis_change[a][1], stretch);
+ VecMulf(tree->basis_change[a][2], stretch);
+
+ }
+
+ IK_FreeSegment(iktree[a]);
+ }
+
+ MEM_freeN(iktree);
+ if(ikstretch) MEM_freeN(ikstretch);
+}
+
+void free_posetree(PoseTree *tree)
+{
+ BLI_freelistN(&tree->targets);
+ if(tree->pchan) MEM_freeN(tree->pchan);
+ if(tree->parent) MEM_freeN(tree->parent);
+ if(tree->basis_change) MEM_freeN(tree->basis_change);
+ MEM_freeN(tree);
+}
+
+/* ********************** THE POSE SOLVER ******************* */
+
+
+/* loc/rot/size to mat4 */
+/* used in constraint.c too */
+void chan_calc_mat(bPoseChannel *chan)
+{
+ float smat[3][3];
+ float rmat[3][3];
+ float tmat[3][3];
+
+ SizeToMat3(chan->size, smat);
+
+ NormalQuat(chan->quat);
+
+ QuatToMat3(chan->quat, rmat);
+
+ Mat3MulMat3(tmat, rmat, smat);
+
+ Mat4CpyMat3(chan->chan_mat, tmat);
+
+ /* prevent action channels breaking chains */
+ /* need to check for bone here, CONSTRAINT_TYPE_ACTION uses this call */
+ if (chan->bone==NULL || !(chan->bone->flag & BONE_CONNECTED)) {
+ VECCOPY(chan->chan_mat[3], chan->loc);
+ }
+
+}
+
+/* transform from bone(b) to bone(b+1), store in chan_mat */
+static void make_dmats(bPoseChannel *pchan)
+{
+ if (pchan->parent) {
+ float iR_parmat[4][4];
+ Mat4Invert(iR_parmat, pchan->parent->pose_mat);
+ Mat4MulMat4(pchan->chan_mat, pchan->pose_mat, iR_parmat); // delta mat
+ }
+ else Mat4CpyMat4(pchan->chan_mat, pchan->pose_mat);
+}
+
+/* applies IK matrix to pchan, IK is done separated */
+/* formula: pose_mat(b) = pose_mat(b-1) * diffmat(b-1, b) * ik_mat(b) */
+/* to make this work, the diffmats have to be precalculated! Stored in chan_mat */
+static void where_is_ik_bone(bPoseChannel *pchan, float ik_mat[][3]) // nr = to detect if this is first bone
+{
+ float vec[3], ikmat[4][4];
+
+ Mat4CpyMat3(ikmat, ik_mat);
+
+ if (pchan->parent)
+ Mat4MulSerie(pchan->pose_mat, pchan->parent->pose_mat, pchan->chan_mat, ikmat, NULL, NULL, NULL, NULL, NULL);
+ else
+ Mat4MulMat4(pchan->pose_mat, ikmat, pchan->chan_mat);
+
+ /* calculate head */
+ VECCOPY(pchan->pose_head, pchan->pose_mat[3]);
+ /* calculate tail */
+ VECCOPY(vec, pchan->pose_mat[1]);
+ VecMulf(vec, pchan->bone->length);
+ VecAddf(pchan->pose_tail, pchan->pose_head, vec);
+
+ pchan->flag |= POSE_DONE;
+}
+
+/* NLA strip modifiers */
+static void do_strip_modifiers(Object *armob, Bone *bone, bPoseChannel *pchan)
+{
+ bActionModifier *amod;
+ bActionStrip *strip;
+ float scene_cfra= G.scene->r.cfra;
+
+ for (strip=armob->nlastrips.first; strip; strip=strip->next) {
+ if(scene_cfra>=strip->start && scene_cfra<=strip->end) {
+
+ /* temporal solution to prevent 2 strips accumulating */
+ if(scene_cfra==strip->end && strip->next && strip->next->start==scene_cfra)
+ continue;
+
+ for(amod= strip->modifiers.first; amod; amod= amod->next) {
+ switch (amod->type) {
+ case ACTSTRIP_MOD_DEFORM:
+ {
+ /* validate first */
+ if(amod->ob && amod->ob->type==OB_CURVE && amod->channel[0]) {
+
+ if( strcmp(pchan->name, amod->channel)==0 ) {
+ float mat4[4][4], mat3[3][3];
+
+ curve_deform_vector(amod->ob, armob, bone->arm_mat[3], pchan->pose_mat[3], mat3, amod->no_rot_axis);
+ Mat4CpyMat4(mat4, pchan->pose_mat);
+ Mat4MulMat34(pchan->pose_mat, mat3, mat4);
+
+ }
+ }
+ }
+ break;
+ case ACTSTRIP_MOD_NOISE:
+ {
+ if( strcmp(pchan->name, amod->channel)==0 ) {
+ float nor[3], loc[3], ofs;
+ float eul[3], size[3], eulo[3], sizeo[3];
+
+ /* calculate turbulance */
+ ofs = amod->turbul / 200.0f;
+
+ /* make a copy of starting conditions */
+ VECCOPY(loc, pchan->pose_mat[3]);
+ Mat4ToEul(pchan->pose_mat, eul);
+ Mat4ToSize(pchan->pose_mat, size);
+ VECCOPY(eulo, eul);
+ VECCOPY(sizeo, size);
+
+ /* apply noise to each set of channels */
+ if (amod->channels & 4) {
+ /* for scaling */
+ nor[0] = BLI_gNoise(amod->noisesize, size[0]+ofs, size[1], size[2], 0, 0) - ofs;
+ nor[1] = BLI_gNoise(amod->noisesize, size[0], size[1]+ofs, size[2], 0, 0) - ofs;
+ nor[2] = BLI_gNoise(amod->noisesize, size[0], size[1], size[2]+ofs, 0, 0) - ofs;
+ VecAddf(size, size, nor);
+
+ if (sizeo[0] != 0)
+ VecMulf(pchan->pose_mat[0], size[0] / sizeo[0]);
+ if (sizeo[1] != 0)
+ VecMulf(pchan->pose_mat[1], size[1] / sizeo[1]);
+ if (sizeo[2] != 0)
+ VecMulf(pchan->pose_mat[2], size[2] / sizeo[2]);
+ }
+ if (amod->channels & 2) {
+ /* for rotation */
+ nor[0] = BLI_gNoise(amod->noisesize, eul[0]+ofs, eul[1], eul[2], 0, 0) - ofs;
+ nor[1] = BLI_gNoise(amod->noisesize, eul[0], eul[1]+ofs, eul[2], 0, 0) - ofs;
+ nor[2] = BLI_gNoise(amod->noisesize, eul[0], eul[1], eul[2]+ofs, 0, 0) - ofs;
+
+ compatible_eul(nor, eulo);
+ VecAddf(eul, eul, nor);
+ compatible_eul(eul, eulo);
+
+ LocEulSizeToMat4(pchan->pose_mat, loc, eul, size);
+ }
+ if (amod->channels & 1) {
+ /* for location */
+ nor[0] = BLI_gNoise(amod->noisesize, loc[0]+ofs, loc[1], loc[2], 0, 0) - ofs;
+ nor[1] = BLI_gNoise(amod->noisesize, loc[0], loc[1]+ofs, loc[2], 0, 0) - ofs;
+ nor[2] = BLI_gNoise(amod->noisesize, loc[0], loc[1], loc[2]+ofs, 0, 0) - ofs;
+
+ VecAddf(pchan->pose_mat[3], loc, nor);
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+}
+
+
+/* The main armature solver, does all constraints excluding IK */
+/* pchan is validated, as having bone and parent pointer */
+static void where_is_pose_bone(Object *ob, bPoseChannel *pchan, float ctime)
+{
+ Bone *bone, *parbone;
+ bPoseChannel *parchan;
+ float vec[3];
+
+ /* set up variables for quicker access below */
+ bone= pchan->bone;
+ parbone= bone->parent;
+ parchan= pchan->parent;
+
+ /* this gives a chan_mat with actions (ipos) results */
+ chan_calc_mat(pchan);
+
+ /* construct the posemat based on PoseChannels, that we do before applying constraints */
+ /* pose_mat(b)= pose_mat(b-1) * yoffs(b-1) * d_root(b) * bone_mat(b) * chan_mat(b) */
+
+ if(parchan) {
+ float offs_bone[4][4]; // yoffs(b-1) + root(b) + bonemat(b)
+
+ /* bone transform itself */
+ Mat4CpyMat3(offs_bone, bone->bone_mat);
+
+ /* The bone's root offset (is in the parent's coordinate system) */
+ VECCOPY(offs_bone[3], bone->head);
+
+ /* Get the length translation of parent (length along y axis) */
+ offs_bone[3][1]+= parbone->length;
+
+ /* Compose the matrix for this bone */
+ if(bone->flag & BONE_HINGE) { // uses restposition rotation, but actual position
+ float tmat[4][4];
+
+ /* the rotation of the parent restposition */
+ Mat4CpyMat4(tmat, parbone->arm_mat);
+
+ /* the location of actual parent transform */
+ VECCOPY(tmat[3], offs_bone[3]);
+ offs_bone[3][0]= offs_bone[3][1]= offs_bone[3][2]= 0.0f;
+ Mat4MulVecfl(parchan->pose_mat, tmat[3]);
+
+ Mat4MulSerie(pchan->pose_mat, tmat, offs_bone, pchan->chan_mat, NULL, NULL, NULL, NULL, NULL);
+ }
+ else
+ Mat4MulSerie(pchan->pose_mat, parchan->pose_mat, offs_bone, pchan->chan_mat, NULL, NULL, NULL, NULL, NULL);
+ }
+ else {
+ Mat4MulMat4(pchan->pose_mat, pchan->chan_mat, bone->arm_mat);
+ /* only rootbones get the cyclic offset */
+ VecAddf(pchan->pose_mat[3], pchan->pose_mat[3], ob->pose->cyclic_offset);
+ }
+
+ /* do NLA strip modifiers - i.e. curve follow */
+ do_strip_modifiers(ob, bone, pchan);
+
+ /* Do constraints */
+ if (pchan->constraints.first) {
+ bConstraintOb *cob;
+
+ /* make a copy of location of PoseChannel for later */
+ VECCOPY(vec, pchan->pose_mat[3]);
+
+ /* prepare PoseChannel for Constraint solving
+ * - makes a copy of matrix, and creates temporary struct to use
+ */
+ cob= constraints_make_evalob(ob, pchan, CONSTRAINT_OBTYPE_BONE);
+
+ /* Solve PoseChannel's Constraints */
+ solve_constraints(&pchan->constraints, cob, ctime); // ctime doesnt alter objects
+
+ /* cleanup after Constraint Solving
+ * - applies matrix back to pchan, and frees temporary struct used
+ */
+ constraints_clear_evalob(cob);
+
+ /* prevent constraints breaking a chain */
+ if(pchan->bone->flag & BONE_CONNECTED) {
+ VECCOPY(pchan->pose_mat[3], vec);
+ }
+ }
+
+ /* calculate head */
+ VECCOPY(pchan->pose_head, pchan->pose_mat[3]);
+ /* calculate tail */
+ VECCOPY(vec, pchan->pose_mat[1]);
+ VecMulf(vec, bone->length);
+ VecAddf(pchan->pose_tail, pchan->pose_head, vec);
+}
+
+/* This only reads anim data from channels, and writes to channels */
+/* This is the only function adding poses */
+void where_is_pose (Object *ob)
+{
+ bArmature *arm;
+ Bone *bone;
+ bPoseChannel *pchan;
+ float imat[4][4];
+ float ctime= bsystem_time(ob, (float)G.scene->r.cfra, 0.0); /* not accurate... */
+
+ arm = get_armature(ob);
+
+ if(arm==NULL) return;
+ if(ob->pose==NULL || (ob->pose->flag & POSE_RECALC))
+ armature_rebuild_pose(ob, arm);
+
+ /* In restposition we read the data from the bones */
+ if(ob==G.obedit || (arm->flag & ARM_RESTPOS)) {
+
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ bone= pchan->bone;
+ if(bone) {
+ Mat4CpyMat4(pchan->pose_mat, bone->arm_mat);
+ VECCOPY(pchan->pose_head, bone->arm_head);
+ VECCOPY(pchan->pose_tail, bone->arm_tail);
+ }
+ }
+ }
+ else {
+ Mat4Invert(ob->imat, ob->obmat); // imat is needed
+
+ /* 1. construct the PoseTrees, clear flags */
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ pchan->flag &= ~(POSE_DONE|POSE_CHAIN);
+ if(pchan->constflag & PCHAN_HAS_IK) // flag is set on editing constraints
+ initialize_posetree(ob, pchan); // will attach it to root!
+ }
+
+ /* 2. the main loop, channels are already hierarchical sorted from root to children */
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+
+ /* 3. if we find an IK root, we handle it separated */
+ if(pchan->iktree.first) {
+ while(pchan->iktree.first) {
+ PoseTree *tree= pchan->iktree.first;
+ int a;
+
+ /* 4. walk over the tree for regular solving */
+ for(a=0; a<tree->totchannel; a++) {
+ if(!(tree->pchan[a]->flag & POSE_DONE)) // successive trees can set the flag
+ where_is_pose_bone(ob, tree->pchan[a], ctime);
+ }
+ /* 5. execute the IK solver */
+ execute_posetree(ob, tree);
+
+ /* 6. apply the differences to the channels,
+ we need to calculate the original differences first */
+ for(a=0; a<tree->totchannel; a++)
+ make_dmats(tree->pchan[a]);
+
+ for(a=0; a<tree->totchannel; a++)
+ /* sets POSE_DONE */
+ where_is_ik_bone(tree->pchan[a], tree->basis_change[a]);
+
+ /* 7. and free */
+ BLI_remlink(&pchan->iktree, tree);
+ free_posetree(tree);
+ }
+ }
+ else if(!(pchan->flag & POSE_DONE)) {
+ where_is_pose_bone(ob, pchan, ctime);
+ }
+ }
+ }
+
+ /* calculating deform matrices */
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ if(pchan->bone) {
+ Mat4Invert(imat, pchan->bone->arm_mat);
+ Mat4MulMat4(pchan->chan_mat, imat, pchan->pose_mat);
+ }
+ }
+}
diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c
new file mode 100644
index 00000000000..9d86b86a47f
--- /dev/null
+++ b/source/blender/blenkernel/intern/blender.c
@@ -0,0 +1,735 @@
+/* blender.c jan 94 MIXED MODEL
+ *
+ * common help functions and data
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef WIN32
+ #include <unistd.h> // for read close
+ #include <sys/param.h> // for MAXPATHLEN
+#else
+ #include <io.h> // for open close read
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h> // for open
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+#include "DNA_sdna_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_object_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_dynstr.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_screen_types.h"
+
+#include "BKE_blender.h"
+#include "BKE_curve.h"
+#include "BKE_depsgraph.h"
+#include "BKE_displist.h"
+#include "BKE_font.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_node.h"
+#include "BKE_object.h"
+#include "BKE_scene.h"
+#include "BKE_sound.h"
+
+#include "BLI_editVert.h"
+
+#include "BLO_undofile.h"
+#include "BLO_readfile.h"
+#include "BLO_writefile.h"
+
+#include "BKE_bad_level_calls.h" // for freeAllRad editNurb free_editMesh free_editText free_editArmature
+#include "BKE_utildefines.h" // O_BINARY FALSE
+#include "BIF_mainqueue.h" // mainqenter for onload script
+#include "mydevice.h"
+#include "nla.h"
+#include "blendef.h"
+
+Global G;
+UserDef U;
+
+char versionstr[48]= "";
+
+/* ************************************************ */
+/* pushpop facility: to store data temporally, FIFO! */
+
+ListBase ppmain={0, 0};
+
+typedef struct PushPop {
+ struct PushPop *next, *prev;
+ void *data;
+ int len;
+} PushPop;
+
+void pushdata(void *data, int len)
+{
+ PushPop *pp;
+
+ pp= MEM_mallocN(sizeof(PushPop), "pushpop");
+ BLI_addtail(&ppmain, pp);
+ pp->data= MEM_mallocN(len, "pushpop");
+ pp->len= len;
+ memcpy(pp->data, data, len);
+}
+
+void popfirst(void *data)
+{
+ PushPop *pp;
+
+ pp= ppmain.first;
+ if(pp) {
+ memcpy(data, pp->data, pp->len);
+ BLI_remlink(&ppmain, pp);
+ MEM_freeN(pp->data);
+ MEM_freeN(pp);
+ }
+ else printf("error in popfirst\n");
+}
+
+void poplast(void *data)
+{
+ PushPop *pp;
+
+ pp= ppmain.last;
+ if(pp) {
+ memcpy(data, pp->data, pp->len);
+ BLI_remlink(&ppmain, pp);
+ MEM_freeN(pp->data);
+ MEM_freeN(pp);
+ }
+ else printf("error in poplast\n");
+}
+
+void free_pushpop()
+{
+ PushPop *pp;
+
+ pp= ppmain.first;
+ while(pp) {
+ BLI_remlink(&ppmain, pp);
+ MEM_freeN(pp->data);
+ MEM_freeN(pp);
+ }
+}
+
+void pushpop_test()
+{
+ if(ppmain.first) printf("pushpop not empty\n");
+ free_pushpop();
+}
+
+
+
+/* ********** free ********** */
+
+void free_blender(void)
+{
+ /* samples are in a global list..., also sets G.main->sound->sample NULL */
+ sound_free_all_samples();
+
+ free_main(G.main);
+ G.main= NULL;
+
+ IMB_freeImBufdata(); /* imbuf lib */
+
+ free_nodesystem();
+}
+
+void duplicatelist(ListBase *list1, ListBase *list2) /* copy from 2 to 1 */
+{
+ struct Link *link1, *link2;
+
+ list1->first= list1->last= 0;
+
+ link2= list2->first;
+ while(link2) {
+
+ link1= MEM_dupallocN(link2);
+ BLI_addtail(list1, link1);
+
+ link2= link2->next;
+ }
+}
+
+static EditMesh theEditMesh;
+
+void initglobals(void)
+{
+ memset(&G, 0, sizeof(Global));
+
+ memset(&theEditMesh, 0, sizeof(theEditMesh));
+ G.editMesh = &theEditMesh;
+
+ U.savetime= 1;
+
+ G.main= MEM_callocN(sizeof(Main), "initglobals");
+
+ strcpy(G.ima, "//");
+
+ G.version= BLENDER_VERSION;
+
+ G.order= 1;
+ G.order= (((char*)&G.order)[0])?L_ENDIAN:B_ENDIAN;
+
+ if(BLENDER_SUBVERSION)
+ sprintf(versionstr, "www.blender.org %d.%d", G.version, BLENDER_SUBVERSION);
+ else
+ sprintf(versionstr, "www.blender.org %d", G.version);
+
+#ifdef _WIN32 // FULLSCREEN
+ G.windowstate = G_WINDOWSTATE_USERDEF;
+#endif
+
+ clear_workob(); /* object.c */
+
+ G.charstart = 0x0000;
+ G.charmin = 0x0000;
+ G.charmax = 0xffff;
+}
+
+/***/
+
+static void clear_global(void)
+{
+ extern short winqueue_break; /* screen.c */
+
+ freeAllRad();
+ fastshade_free_render(); /* lamps hang otherwise */
+ free_main(G.main); /* free all lib data */
+
+ /* force all queues to be left */
+ winqueue_break= 1;
+
+ if (G.obedit) {
+ freeNurblist(&editNurb);
+ free_editMesh(G.editMesh);
+ free_editText();
+ free_editArmature();
+ }
+
+ G.curscreen= NULL;
+ G.scene= NULL;
+ G.main= NULL;
+
+ G.obedit= NULL;
+ G.saction= NULL;
+ G.buts= NULL;
+ G.v2d= NULL;
+ G.vd= NULL;
+ G.soops= NULL;
+ G.sima= NULL;
+ G.sipo= NULL;
+
+ free_vertexpaint();
+
+ G.f &= ~(G_WEIGHTPAINT + G_VERTEXPAINT + G_FACESELECT);
+}
+
+/* make sure path names are correct for OS */
+static void clean_paths(Main *main)
+{
+ Image *image= main->image.first;
+ bSound *sound= main->sound.first;
+ Scene *scene= main->scene.first;
+ Editing *ed;
+ Sequence *seq;
+ Strip *strip;
+
+ while(image) {
+ BLI_clean(image->name);
+ image= image->id.next;
+ }
+
+ while(sound) {
+ BLI_clean(sound->name);
+ sound= sound->id.next;
+ }
+
+ while(scene) {
+ ed= scene->ed;
+ if(ed) {
+ seq= ed->seqbasep->first;
+ while(seq) {
+ if(seq->plugin) {
+ BLI_clean(seq->plugin->name);
+ }
+ strip= seq->strip;
+ while(strip) {
+ BLI_clean(strip->dir);
+ strip= strip->next;
+ }
+ seq= seq->next;
+ }
+ }
+ BLI_clean(scene->r.backbuf);
+ BLI_clean(scene->r.pic);
+ BLI_clean(scene->r.ftype);
+
+ scene= scene->id.next;
+ }
+}
+
+static void setup_app_data(BlendFileData *bfd, char *filename)
+{
+ Object *ob;
+ bScreen *curscreen= NULL;
+ Scene *curscene= NULL;
+ char mode;
+
+ /* 'u' = undo save, 'n' = no UI load */
+ if(bfd->main->screen.first==NULL) mode= 'u';
+ else if(G.fileflags & G_FILE_NO_UI) mode= 'n';
+ else mode= 0;
+
+ clean_paths(bfd->main);
+
+ /* no load screens? */
+ if(mode) {
+ /* comes from readfile.c */
+ extern void lib_link_screen_restore(Main *, Scene *);
+
+ SWAP(ListBase, G.main->screen, bfd->main->screen);
+
+ /* we re-use current screen */
+ curscreen= G.curscreen;
+ /* but use new Scene pointer */
+ curscene= bfd->curscene;
+ if(curscene==NULL) curscene= bfd->main->scene.first;
+ /* and we enforce curscene to be in current screen */
+ curscreen->scene= curscene;
+
+ /* clear_global will free G.main, here we can still restore pointers */
+ lib_link_screen_restore(bfd->main, curscene);
+ }
+
+ clear_global(); /* free Main database */
+
+ if(mode!='u') G.save_over = 1;
+
+ G.main= bfd->main;
+ if (bfd->user) {
+
+ /* only here free userdef themes... */
+ BLI_freelistN(&U.themes);
+
+ U= *bfd->user;
+ MEM_freeN(bfd->user);
+
+ }
+
+ /* samples is a global list... */
+ sound_free_all_samples();
+
+ /* case G_FILE_NO_UI or no screens in file */
+ if(mode) {
+ G.curscreen= curscreen;
+ G.scene= curscene;
+ }
+ else {
+ G.winpos= bfd->winpos;
+ G.displaymode= bfd->displaymode;
+ G.fileflags= bfd->fileflags;
+ G.curscreen= bfd->curscreen;
+ G.scene= G.curscreen->scene;
+ }
+ /* this can happen when active scene was lib-linked, and doesnt exist anymore */
+ if(G.scene==NULL) {
+ G.scene= G.main->scene.first;
+ G.curscreen->scene= G.scene;
+ }
+
+ /* special cases, override loaded flags: */
+ if (G.f & G_DEBUG) bfd->globalf |= G_DEBUG;
+ else bfd->globalf &= ~G_DEBUG;
+ if (!(G.f & G_DOSCRIPTLINKS)) bfd->globalf &= ~G_DOSCRIPTLINKS;
+
+ G.f= bfd->globalf;
+
+ if (!G.background) {
+ setscreen(G.curscreen);
+ }
+
+ /* baseflags, groups, make depsgraph, etc */
+ set_scene_bg(G.scene);
+
+ /* last stage of do_versions actually, that sets recalc flags for recalc poses */
+ for(ob= G.main->object.first; ob; ob= ob->id.next) {
+ if(ob->type==OB_ARMATURE)
+ if(ob->recalc) object_handle_update(ob);
+ }
+
+ /* now tag update flags, to ensure deformers get calculated on redraw */
+ DAG_scene_update_flags(G.scene, G.scene->lay);
+
+ if (G.f & G_DOSCRIPTLINKS) {
+ /* there's an onload scriptlink to execute in screenmain */
+ mainqenter(ONLOAD_SCRIPT, 1);
+ }
+ if (G.sce != filename) /* these are the same at times, should never copy to the same location */
+ strcpy(G.sce, filename);
+
+ strcpy(G.main->name, filename); /* is guaranteed current file */
+
+ MEM_freeN(bfd);
+}
+
+static void handle_subversion_warning(Main *main)
+{
+ if(main->minversionfile > BLENDER_VERSION ||
+ (main->minversionfile == BLENDER_VERSION &&
+ main->minsubversionfile > BLENDER_SUBVERSION)) {
+
+ char str[128];
+
+ sprintf(str, "File written by newer Blender binary: %d.%d , expect loss of data!", main->minversionfile, main->minsubversionfile);
+ error(str);
+ }
+
+}
+
+/* returns:
+ 0: no load file
+ 1: OK
+ 2: OK, and with new user settings
+*/
+
+int BKE_read_file(char *dir, void *type_r)
+{
+ BlendReadError bre;
+ BlendFileData *bfd;
+ int retval= 1;
+
+ if (!G.background)
+ waitcursor(1);
+
+ bfd= BLO_read_from_file(dir, &bre);
+ if (bfd) {
+ if(bfd->user) retval= 2;
+ if (type_r)
+ *((BlenFileType*)type_r)= bfd->type;
+
+ setup_app_data(bfd, dir);
+
+ handle_subversion_warning(G.main);
+ }
+ else {
+ error("Loading %s failed: %s", dir, BLO_bre_as_string(bre));
+ }
+
+ if (!G.background)
+ waitcursor(0);
+
+ return (bfd?retval:0);
+}
+
+int BKE_read_file_from_memory(char* filebuf, int filelength, void *type_r)
+{
+ BlendReadError bre;
+ BlendFileData *bfd;
+
+ if (!G.background)
+ waitcursor(1);
+
+ bfd= BLO_read_from_memory(filebuf, filelength, &bre);
+ if (bfd) {
+ if (type_r)
+ *((BlenFileType*)type_r)= bfd->type;
+
+ setup_app_data(bfd, "<memory>");
+ } else {
+ error("Loading failed: %s", BLO_bre_as_string(bre));
+ }
+
+ if (!G.background)
+ waitcursor(0);
+
+ return (bfd?1:0);
+}
+
+/* memfile is the undo buffer */
+int BKE_read_file_from_memfile(MemFile *memfile)
+{
+ BlendReadError bre;
+ BlendFileData *bfd;
+
+ if (!G.background)
+ waitcursor(1);
+
+ bfd= BLO_read_from_memfile(G.sce, memfile, &bre);
+ if (bfd) {
+ setup_app_data(bfd, "<memory>");
+ } else {
+ error("Loading failed: %s", BLO_bre_as_string(bre));
+ }
+
+ if (!G.background)
+ waitcursor(0);
+
+ return (bfd?1:0);
+}
+
+
+/* ***************** GLOBAL UNDO *************** */
+
+#define UNDO_DISK 0
+
+#define MAXUNDONAME 64
+typedef struct UndoElem {
+ struct UndoElem *next, *prev;
+ char str[FILE_MAXDIR+FILE_MAXFILE];
+ char name[MAXUNDONAME];
+ MemFile memfile;
+} UndoElem;
+
+static ListBase undobase={NULL, NULL};
+static UndoElem *curundo= NULL;
+
+
+static int read_undosave(UndoElem *uel)
+{
+ char scestr[FILE_MAXDIR+FILE_MAXFILE];
+ int success=0, fileflags;
+
+ strcpy(scestr, G.sce); /* temporal store */
+ fileflags= G.fileflags;
+ G.fileflags |= G_FILE_NO_UI;
+
+ if(UNDO_DISK)
+ success= BKE_read_file(uel->str, NULL);
+ else
+ success= BKE_read_file_from_memfile(&uel->memfile);
+
+ /* restore */
+ strcpy(G.sce, scestr);
+ G.fileflags= fileflags;
+
+ return success;
+}
+
+/* name can be a dynamic string */
+void BKE_write_undo(char *name)
+{
+ int nr, success;
+ UndoElem *uel;
+
+ if( (U.uiflag & USER_GLOBALUNDO)==0) return;
+ if( U.undosteps==0) return;
+
+ /* remove all undos after (also when curundo==NULL) */
+ while(undobase.last != curundo) {
+ uel= undobase.last;
+ BLI_remlink(&undobase, uel);
+ BLO_free_memfile(&uel->memfile);
+ MEM_freeN(uel);
+ }
+
+ /* make new */
+ curundo= uel= MEM_callocN(sizeof(UndoElem), "undo file");
+ strncpy(uel->name, name, MAXUNDONAME-1);
+ BLI_addtail(&undobase, uel);
+
+ /* and limit amount to the maximum */
+ nr= 0;
+ uel= undobase.last;
+ while(uel) {
+ nr++;
+ if(nr==U.undosteps) break;
+ uel= uel->prev;
+ }
+ if(uel) {
+ while(undobase.first!=uel) {
+ UndoElem *first= undobase.first;
+ BLI_remlink(&undobase, first);
+ /* the merge is because of compression */
+ BLO_merge_memfile(&first->memfile, &first->next->memfile);
+ MEM_freeN(first);
+ }
+ }
+
+
+ /* disk save version */
+ if(UNDO_DISK) {
+ static int counter= 0;
+ char *err, tstr[FILE_MAXDIR+FILE_MAXFILE];
+ char numstr[32];
+
+ /* calculate current filename */
+ counter++;
+ counter= counter % U.undosteps;
+
+ sprintf(numstr, "%d.blend", counter);
+ BLI_make_file_string("/", tstr, U.tempdir, numstr);
+
+ success= BLO_write_file(tstr, G.fileflags, &err);
+
+ strcpy(curundo->str, tstr);
+ }
+ else {
+ MemFile *prevfile=NULL;
+ char *err;
+
+ if(curundo->prev) prevfile= &(curundo->prev->memfile);
+
+ success= BLO_write_file_mem(prevfile, &curundo->memfile, G.fileflags, &err);
+
+ }
+}
+
+/* 1= an undo, -1 is a redo. we have to make sure 'curundo' remains at current situation */
+void BKE_undo_step(int step)
+{
+
+ if(step==0) {
+ read_undosave(curundo);
+ }
+ else if(step==1) {
+ /* curundo should never be NULL, after restart or load file it should call undo_save */
+ if(curundo==NULL || curundo->prev==NULL) error("No undo available");
+ else {
+ if(G.f & G_DEBUG) printf("undo %s\n", curundo->name);
+ curundo= curundo->prev;
+ read_undosave(curundo);
+ }
+ }
+ else {
+
+ /* curundo has to remain current situation! */
+
+ if(curundo==NULL || curundo->next==NULL) error("No redo available");
+ else {
+ read_undosave(curundo->next);
+ curundo= curundo->next;
+ if(G.f & G_DEBUG) printf("redo %s\n", curundo->name);
+ }
+ }
+}
+
+void BKE_reset_undo(void)
+{
+ UndoElem *uel;
+
+ uel= undobase.first;
+ while(uel) {
+ BLO_free_memfile(&uel->memfile);
+ uel= uel->next;
+ }
+
+ BLI_freelistN(&undobase);
+ curundo= NULL;
+}
+
+/* based on index nr it does a restore */
+void BKE_undo_number(int nr)
+{
+ UndoElem *uel;
+ int a=1;
+
+ for(uel= undobase.first; uel; uel= uel->next, a++) {
+ if(a==nr) break;
+ }
+ curundo= uel;
+ BKE_undo_step(0);
+}
+
+char *BKE_undo_menu_string(void)
+{
+ UndoElem *uel;
+ DynStr *ds= BLI_dynstr_new();
+ char *menu;
+
+ BLI_dynstr_append(ds, "Global Undo History %t");
+
+ for(uel= undobase.first; uel; uel= uel->next) {
+ BLI_dynstr_append(ds, "|");
+ BLI_dynstr_append(ds, uel->name);
+ }
+
+ menu= BLI_dynstr_get_cstring(ds);
+ BLI_dynstr_free(ds);
+
+ return menu;
+}
+
+ /* saves quit.blend */
+void BKE_undo_save_quit(void)
+{
+ UndoElem *uel;
+ MemFileChunk *chunk;
+ int file;
+ char str[FILE_MAXDIR+FILE_MAXFILE];
+
+ if( (U.uiflag & USER_GLOBALUNDO)==0) return;
+
+ uel= curundo;
+ if(uel==NULL) {
+ printf("No undo buffer to save recovery file\n");
+ return;
+ }
+
+ /* no undo state to save */
+ if(undobase.first==undobase.last) return;
+
+ BLI_make_file_string("/", str, U.tempdir, "quit.blend");
+
+ file = open(str,O_BINARY+O_WRONLY+O_CREAT+O_TRUNC, 0666);
+ if(file == -1) {
+ printf("Unable to save %s\n", str);
+ return;
+ }
+
+ chunk= uel->memfile.chunks.first;
+ while(chunk) {
+ if( write(file, chunk->buf, chunk->size) != chunk->size) break;
+ chunk= chunk->next;
+ }
+
+ close(file);
+
+ if(chunk) printf("Unable to save %s\n", str);
+ else printf("Saved session recovery to %s\n", str);
+}
+
diff --git a/source/blender/blenkernel/intern/bmfont.c b/source/blender/blenkernel/intern/bmfont.c
new file mode 100644
index 00000000000..6ea08b5cfbb
--- /dev/null
+++ b/source/blender/blenkernel/intern/bmfont.c
@@ -0,0 +1,297 @@
+/**
+ * bmfont.c
+ *
+ * 04-10-2000 frank
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ *
+ */
+
+/**
+ * Two external functions:
+ *
+ * void detectBitmapFont(ImBuf *ibuf)
+ * detects if an image buffer contains a bitmap font. It makes the
+ * specific bitmap data which is stored in the bitmap invisible to blender.
+ *
+ * void matrixGlyph(ImBuf * ibuf, unsigned short unicode, *float x 7)
+ * returns all the information about the character (unicode) in the floats
+ *
+ * Room for improvement:
+ * add kerning data in the bitmap
+ * all calculations in matrixGlyph() are static and could be done during
+ * initialization
+ */
+
+#include <stdio.h>
+
+#include "MEM_guardedalloc.h"
+#include "BLI_blenlib.h"
+#include "BKE_global.h"
+#include "IMB_imbuf_types.h"
+
+#include "BKE_bmfont.h"
+#include "BKE_bmfont_types.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+void printfGlyph(bmGlyph * glyph)
+{
+ printf("unicode: %d '%c'\n", glyph->unicode, glyph->unicode);
+ printf(" locx: %4d locy: %4d\n", glyph->locx, glyph->locy);
+ printf(" sizex: %3d sizey: %3d\n", glyph->sizex, glyph->sizey);
+ printf(" ofsx: %3d ofsy: %3d\n", glyph->ofsx, glyph->ofsy);
+ printf(" advan: %3d reser: %3d\n", glyph->advance, glyph->reserved);
+}
+
+#define MAX2(x,y) ( (x)>(y) ? (x) : (y) )
+#define MAX3(x,y,z) MAX2( MAX2((x),(y)) , (z) )
+
+void calcAlpha(ImBuf * ibuf)
+{
+ int i;
+ char * rect;
+
+ if (ibuf) {
+ rect = (char *) ibuf->rect;
+ for (i = ibuf->x * ibuf->y ; i > 0 ; i--) {
+ rect[3] = MAX3(rect[0], rect[1], rect[2]);
+ rect += 4;
+ }
+ }
+}
+
+void readBitmapFontVersion0(ImBuf * ibuf, unsigned char * rect, int step)
+{
+ int glyphcount, bytes, i, index, linelength, ysize;
+ unsigned char * buffer;
+ bmFont * bmfont;
+
+ linelength = ibuf->x * step;
+
+ glyphcount = (rect[6 * step] << 8) | rect[7 * step];
+ bytes = ((glyphcount - 1) * sizeof(bmGlyph)) + sizeof(bmFont);
+
+ ysize = (bytes + (ibuf->x - 1)) / ibuf->x;
+
+ if (ysize < ibuf->y) {
+ // we're first going to copy all data into a liniar buffer.
+ // step can be 4 or 1 bytes, and the data is not sequential because
+ // the bitmap was flipped vertically.
+
+ buffer = MEM_mallocN(bytes, "readBitmapFontVersion0:buffer");
+
+ index = 0;
+ for (i = 0; i < bytes; i++) {
+ buffer[i] = rect[index];
+ index += step;
+ if (index >= linelength) {
+ // we've read one line, no skip to the line *before* that
+ rect -= linelength;
+ index -= linelength;
+ }
+ }
+
+ // we're now going to endian convert the data
+
+ bmfont = MEM_mallocN(bytes, "readBitmapFontVersion0:bmfont");
+ index = 0;
+
+ // first read the header
+ bmfont->magic[0] = buffer[index++];
+ bmfont->magic[1] = buffer[index++];
+ bmfont->magic[2] = buffer[index++];
+ bmfont->magic[3] = buffer[index++];
+ bmfont->version = (buffer[index] << 8) | buffer[index + 1]; index += 2;
+ bmfont->glyphcount = (buffer[index] << 8) | buffer[index + 1]; index += 2;
+ bmfont->xsize = (buffer[index] << 8) | buffer[index + 1]; index += 2;
+ bmfont->ysize = (buffer[index] << 8) | buffer[index + 1]; index += 2;
+
+ for (i = 0; i < bmfont->glyphcount; i++) {
+ bmfont->glyphs[i].unicode = (buffer[index] << 8) | buffer[index + 1]; index += 2;
+ bmfont->glyphs[i].locx = (buffer[index] << 8) | buffer[index + 1]; index += 2;
+ bmfont->glyphs[i].locy = (buffer[index] << 8) | buffer[index + 1]; index += 2;
+ bmfont->glyphs[i].ofsx = buffer[index++];
+ bmfont->glyphs[i].ofsy = buffer[index++];
+ bmfont->glyphs[i].sizex = buffer[index++];
+ bmfont->glyphs[i].sizey = buffer[index++];
+ bmfont->glyphs[i].advance = buffer[index++];
+ bmfont->glyphs[i].reserved = buffer[index++];
+ if (G.f & G_DEBUG) {
+ printfGlyph(&bmfont->glyphs[i]);
+ }
+ }
+
+ MEM_freeN(buffer);
+
+ if (G.f & G_DEBUG) {
+ printf("Oldy = %d Newy = %d\n", ibuf->y, ibuf->y - ysize);
+ printf("glyphcount = %d\n", glyphcount);
+ printf("bytes = %d\n", bytes);
+ }
+
+ // we've read the data from the image. Now we're going
+ // to crop the image vertically so only the bitmap data
+ // remains visible
+
+ ibuf->y -= ysize;
+ ibuf->userdata = bmfont;
+ ibuf->userflags |= IB_BITMAPFONT;
+
+ if (ibuf->depth < 32) {
+ // we're going to fake alpha here:
+ calcAlpha(ibuf);
+ }
+ } else {
+ printf("readBitmapFontVersion0: corrupted bitmapfont\n");
+ }
+}
+
+void detectBitmapFont(ImBuf *ibuf)
+{
+ unsigned char * rect;
+ unsigned short version;
+ long i;
+
+ if (ibuf != NULL) {
+ // bitmap must have an x size that is a power of two
+ if (is_power_of_two(ibuf->x)) {
+ rect = (unsigned char *) (ibuf->rect + (ibuf->x * (ibuf->y - 1)));
+ // printf ("starts with: %s %c %c %c %c\n", rect, rect[0], rect[1], rect[2], rect[3]);
+ if (rect[0] == 'B' && rect[1] == 'F' && rect[2] == 'N' && rect[3] == 'T') {
+ // printf("found 8bit font !\n");
+ // round y size down
+ // do the 8 bit font stuff. (not yet)
+ } else {
+ // we try all 4 possible combinations
+ for (i = 0; i < 4; i++) {
+ if (rect[0] == 'B' && rect[4] == 'F' && rect[8] == 'N' && rect[12] == 'T') {
+ // printf("found 24bit font !\n");
+ // We're going to parse the file:
+
+ version = (rect[16] << 8) | rect[20];
+
+ if (version == 0) {
+ readBitmapFontVersion0(ibuf, rect, 4);
+ } else {
+ printf("detectBitmapFont :Unsupported version %d\n", version);
+ }
+
+ // on succes ibuf->userdata points to the bitmapfont
+ if (ibuf->userdata) {
+ break;
+ }
+ }
+ rect++;
+ }
+ }
+ }
+ }
+}
+
+int locateGlyph(bmFont *bmfont, unsigned short unicode)
+{
+ int min, max, current = 0;
+
+ if (bmfont) {
+ min = 0;
+ max = bmfont->glyphcount;
+ while (1) {
+ // look halfway for glyph
+ current = (min + max) >> 1;
+
+ if (bmfont->glyphs[current].unicode == unicode) {
+ break;
+ } else if (bmfont->glyphs[current].unicode < unicode) {
+ // have to move up
+ min = current;
+ } else {
+ // have to move down
+ max = current;
+ }
+
+ if (max - min <= 1) {
+ // unable to locate glyph
+ current = 0;
+ break;
+ }
+ }
+ }
+
+ return(current);
+}
+
+void matrixGlyph(ImBuf * ibuf, unsigned short unicode,
+ float *centerx, float *centery,
+ float *sizex, float *sizey,
+ float *transx, float *transy,
+ float *movex, float *movey,
+ float *advance)
+{
+ int index;
+ bmFont *bmfont;
+
+ *centerx = *centery = 0.0;
+ *sizex = *sizey = 1.0;
+ *transx = *transy = 0.0;
+ *movex = *movey = 0.0;
+ *advance = 1.0;
+
+ if (ibuf) {
+ bmfont = ibuf->userdata;
+ if (bmfont && (ibuf->userflags & IB_BITMAPFONT)) {
+ index = locateGlyph(bmfont, unicode);
+ if (index) {
+
+ *sizex = (bmfont->glyphs[index].sizex) / (float) (bmfont->glyphs[0].sizex);
+ *sizey = (bmfont->glyphs[index].sizey) / (float) (bmfont->glyphs[0].sizey);
+
+ *transx = bmfont->glyphs[index].locx / (float) ibuf->x;
+ *transy = (ibuf->y - bmfont->glyphs[index].locy) / (float) ibuf->y;
+
+ *centerx = bmfont->glyphs[0].locx / (float) ibuf->x;
+ *centery = (ibuf->y - bmfont->glyphs[0].locy) / (float) ibuf->y;
+
+ // 2.0 units is the default size of an object
+
+ *movey = 1.0f - *sizey + 2.0f * (bmfont->glyphs[index].ofsy - bmfont->glyphs[0].ofsy) / (float) bmfont->glyphs[0].sizey;
+ *movex = *sizex - 1.0f + 2.0f * (bmfont->glyphs[index].ofsx - bmfont->glyphs[0].ofsx) / (float) bmfont->glyphs[0].sizex;
+
+ *advance = 2.0f * bmfont->glyphs[index].advance / (float) bmfont->glyphs[0].advance;
+
+ // printfGlyph(&bmfont->glyphs[index]);
+ // printf("%c %d %0.5f %0.5f %0.5f %0.5f %0.5f \n", unicode, index, *sizex, *sizey, *transx, *transy, *advance);
+ }
+ }
+ }
+}
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
new file mode 100644
index 00000000000..ca2f7b114d5
--- /dev/null
+++ b/source/blender/blenkernel/intern/brush.c
@@ -0,0 +1,882 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_image_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+
+#include "BKE_brush.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "RE_render_ext.h" /* externtex */
+
+/* Datablock add/copy/free/make_local */
+
+Brush *add_brush(char *name)
+{
+ Brush *brush;
+
+ brush= alloc_libblock(&G.main->brush, ID_BR, name);
+
+ brush->rgb[0]= 1.0f;
+ brush->rgb[1]= 1.0f;
+ brush->rgb[2]= 1.0f;
+ brush->alpha= 0.2f;
+ brush->size= 25;
+ brush->spacing= 10.0f;
+ brush->rate= 0.1f;
+ brush->innerradius= 0.5f;
+ brush->clone.alpha= 0.5;
+
+ /* enable fake user by default */
+ brush_toggle_fake_user(brush);
+
+ return brush;
+}
+
+Brush *copy_brush(Brush *brush)
+{
+ Brush *brushn;
+ MTex *mtex;
+ int a;
+
+ brushn= copy_libblock(brush);
+
+ for(a=0; a<MAX_MTEX; a++) {
+ mtex= brush->mtex[a];
+ if(mtex) {
+ brushn->mtex[a]= MEM_dupallocN(mtex);
+ if(mtex->tex) id_us_plus((ID*)mtex->tex);
+ }
+ }
+
+ /* enable fake user by default */
+ if (!(brushn->id.flag & LIB_FAKEUSER))
+ brush_toggle_fake_user(brushn);
+
+ return brushn;
+}
+
+/* not brush itself */
+void free_brush(Brush *brush)
+{
+ MTex *mtex;
+ int a;
+
+ for(a=0; a<MAX_MTEX; a++) {
+ mtex= brush->mtex[a];
+ if(mtex) {
+ if(mtex->tex) mtex->tex->id.us--;
+ MEM_freeN(mtex);
+ }
+ }
+}
+
+void make_local_brush(Brush *brush)
+{
+ /* - only lib users: do nothing
+ * - only local users: set flag
+ * - mixed: make copy
+ */
+
+ Brush *brushn;
+ Scene *scene;
+ int local= 0, lib= 0;
+
+ if(brush->id.lib==0) return;
+
+ if(brush->clone.image) {
+ /* special case: ima always local immediately */
+ brush->clone.image->id.lib= 0;
+ brush->clone.image->id.flag= LIB_LOCAL;
+ new_id(0, (ID *)brush->clone.image, 0);
+ }
+
+ for(scene= G.main->scene.first; scene; scene=scene->id.next)
+ if(scene->toolsettings->imapaint.brush==brush) {
+ if(scene->id.lib) lib= 1;
+ else local= 1;
+ }
+
+ if(local && lib==0) {
+ brush->id.lib= 0;
+ brush->id.flag= LIB_LOCAL;
+ new_id(0, (ID *)brush, 0);
+
+ /* enable fake user by default */
+ if (!(brush->id.flag & LIB_FAKEUSER))
+ brush_toggle_fake_user(brush);
+ }
+ else if(local && lib) {
+ brushn= copy_brush(brush);
+ brushn->id.us= 1; /* only keep fake user */
+ brushn->id.flag |= LIB_FAKEUSER;
+
+ for(scene= G.main->scene.first; scene; scene=scene->id.next)
+ if(scene->toolsettings->imapaint.brush==brush)
+ if(scene->id.lib==0) {
+ scene->toolsettings->imapaint.brush= brushn;
+ brushn->id.us++;
+ brush->id.us--;
+ }
+ }
+}
+
+/* Library Operations */
+
+int brush_set_nr(Brush **current_brush, int nr)
+{
+ ID *idtest, *id;
+
+ id= (ID*)(*current_brush);
+ idtest= (ID*)BLI_findlink(&G.main->brush, nr-1);
+
+ if(idtest==0) { /* new brush */
+ if(id) idtest= (ID *)copy_brush((Brush *)id);
+ else idtest= (ID *)add_brush("Brush");
+ idtest->us--;
+ }
+ if(idtest!=id) {
+ brush_delete(current_brush);
+ *current_brush= (Brush *)idtest;
+ id_us_plus(idtest);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+int brush_delete(Brush **current_brush)
+{
+ if (*current_brush) {
+ (*current_brush)->id.us--;
+ *current_brush= NULL;
+
+ return 1;
+ }
+
+ return 0;
+}
+
+void brush_toggle_fake_user(Brush *brush)
+{
+ ID *id= (ID*)brush;
+ if(id) {
+ if(id->flag & LIB_FAKEUSER) {
+ id->flag -= LIB_FAKEUSER;
+ id->us--;
+ } else {
+ id->flag |= LIB_FAKEUSER;
+ id_us_plus(id);
+ }
+ }
+}
+
+int brush_texture_set_nr(Brush *brush, int nr)
+{
+ ID *idtest, *id=NULL;
+
+ if(brush->mtex[brush->texact])
+ id= (ID *)brush->mtex[brush->texact]->tex;
+
+ idtest= (ID*)BLI_findlink(&G.main->tex, nr-1);
+ if(idtest==0) { /* new tex */
+ if(id) idtest= (ID *)copy_texture((Tex *)id);
+ else idtest= (ID *)add_texture("Tex");
+ idtest->us--;
+ }
+ if(idtest!=id) {
+ brush_texture_delete(brush);
+
+ if(brush->mtex[brush->texact]==NULL) {
+ brush->mtex[brush->texact]= add_mtex();
+ brush->mtex[brush->texact]->r = 1.0f;
+ brush->mtex[brush->texact]->g = 1.0f;
+ brush->mtex[brush->texact]->b = 1.0f;
+ }
+ brush->mtex[brush->texact]->tex= (Tex*)idtest;
+ id_us_plus(idtest);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+int brush_texture_delete(Brush *brush)
+{
+ if(brush->mtex[brush->texact]) {
+ if(brush->mtex[brush->texact]->tex)
+ brush->mtex[brush->texact]->tex->id.us--;
+ MEM_freeN(brush->mtex[brush->texact]);
+ brush->mtex[brush->texact]= NULL;
+
+ return 1;
+ }
+
+ return 0;
+}
+
+int brush_clone_image_set_nr(Brush *brush, int nr)
+{
+ if(brush && nr > 0) {
+ Image *ima= (Image*)BLI_findlink(&G.main->image, nr-1);
+
+ if(ima) {
+ brush_clone_image_delete(brush);
+ brush->clone.image= ima;
+ id_us_plus(&ima->id);
+ brush->clone.offset[0]= brush->clone.offset[1]= 0.0f;
+
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+int brush_clone_image_delete(Brush *brush)
+{
+ if (brush && brush->clone.image) {
+ brush->clone.image->id.us--;
+ brush->clone.image= NULL;
+ return 1;
+ }
+
+ return 0;
+}
+
+void brush_check_exists(Brush **brush)
+{
+ if(*brush==NULL)
+ brush_set_nr(brush, 1);
+}
+
+/* Brush Sampling */
+
+/*static float taylor_approx_cos(float f)
+{
+ f = f*f;
+ f = 1.0f - f/2.0f + f*f/24.0f;
+ return f;
+}*/
+
+float brush_sample_falloff(Brush *brush, float dist)
+{
+ float a, outer, inner;
+
+ outer = brush->size >> 1;
+ inner = outer*brush->innerradius;
+
+ if (dist <= inner) {
+ return brush->alpha;
+ }
+ else if ((dist < outer) && (inner < outer)) {
+ a = sqrt((dist - inner)/(outer - inner));
+ return (1 - a)*brush->alpha;
+
+ /* formula used by sculpt, with taylor approx
+ a = 0.5f*(taylor_approx_cos(3.0f*(dist - inner)/(outer - inner)) + 1.0f);
+ return a*brush->alpha; */
+ }
+ else
+ return 0.0f;
+}
+
+void brush_sample_tex(Brush *brush, float *xy, float *rgba)
+{
+ MTex *mtex= brush->mtex[brush->texact];
+
+ if (mtex && mtex->tex) {
+ float co[3], tin, tr, tg, tb, ta;
+ int hasrgb;
+
+ co[0]= xy[0]/(brush->size >> 1);
+ co[1]= xy[1]/(brush->size >> 1);
+ co[2]= 0.0f;
+
+ hasrgb= externtex(mtex, co, &tin, &tr, &tg, &tb, &ta);
+
+ if (hasrgb) {
+ rgba[0]= tr;
+ rgba[1]= tg;
+ rgba[2]= tb;
+ rgba[3]= ta;
+ }
+ else {
+ rgba[0]= tin;
+ rgba[1]= tin;
+ rgba[2]= tin;
+ rgba[3]= 1.0f;
+ }
+ }
+ else if (rgba)
+ rgba[0]= rgba[1]= rgba[2]= rgba[3]= 1.0f;
+}
+
+#define FTOCHAR(val) val<=0.0f?0: (val>=1.0f?255: (char)(255.0f*val))
+
+void brush_imbuf_new(Brush *brush, short flt, short texfall, int size, ImBuf **outbuf)
+{
+ ImBuf *ibuf;
+ float xy[2], dist, rgba[4], *dstf;
+ int x, y, rowbytes, xoff, yoff, imbflag;
+ char *dst, crgb[3];
+
+ imbflag= (flt)? IB_rectfloat: IB_rect;
+ xoff = -size/2.0f + 0.5f;
+ yoff = -size/2.0f + 0.5f;
+ rowbytes= size*4;
+
+ if (*outbuf)
+ ibuf= *outbuf;
+ else
+ ibuf= IMB_allocImBuf(size, size, 32, imbflag, 0);
+
+ if (flt) {
+ for (y=0; y < ibuf->y; y++) {
+ dstf = ibuf->rect_float + y*rowbytes;
+
+ for (x=0; x < ibuf->x; x++, dstf+=4) {
+ xy[0] = x + xoff;
+ xy[1] = y + yoff;
+
+ if (texfall == 0) {
+ dist = sqrt(xy[0]*xy[0] + xy[1]*xy[1]);
+
+ VECCOPY(dstf, brush->rgb);
+ dstf[3]= brush_sample_falloff(brush, dist);
+ }
+ else if (texfall == 1) {
+ brush_sample_tex(brush, xy, dstf);
+ }
+ else {
+ dist = sqrt(xy[0]*xy[0] + xy[1]*xy[1]);
+
+ brush_sample_tex(brush, xy, rgba);
+
+ dstf[0] = rgba[0]*brush->rgb[0];
+ dstf[1] = rgba[1]*brush->rgb[1];
+ dstf[2] = rgba[2]*brush->rgb[2];
+ dstf[3] = rgba[3]*brush_sample_falloff(brush, dist);
+ }
+ }
+ }
+ }
+ else {
+ crgb[0]= FTOCHAR(brush->rgb[0]);
+ crgb[1]= FTOCHAR(brush->rgb[1]);
+ crgb[2]= FTOCHAR(brush->rgb[2]);
+
+ for (y=0; y < ibuf->y; y++) {
+ dst = (char*)ibuf->rect + y*rowbytes;
+
+ for (x=0; x < ibuf->x; x++, dst+=4) {
+ xy[0] = x + xoff;
+ xy[1] = y + yoff;
+
+ if (texfall == 0) {
+ dist = sqrt(xy[0]*xy[0] + xy[1]*xy[1]);
+
+ dst[0]= crgb[0];
+ dst[1]= crgb[1];
+ dst[2]= crgb[2];
+ dst[3]= FTOCHAR(brush_sample_falloff(brush, dist));
+ }
+ else if (texfall == 1) {
+ brush_sample_tex(brush, xy, rgba);
+ dst[0]= FTOCHAR(rgba[0]);
+ dst[1]= FTOCHAR(rgba[1]);
+ dst[2]= FTOCHAR(rgba[2]);
+ dst[3]= FTOCHAR(rgba[3]);
+ }
+ else {
+ dist = sqrt(xy[0]*xy[0] + xy[1]*xy[1]);
+
+ brush_sample_tex(brush, xy, rgba);
+ dst[0] = FTOCHAR(rgba[0]*brush->rgb[0]);
+ dst[1] = FTOCHAR(rgba[1]*brush->rgb[1]);
+ dst[2] = FTOCHAR(rgba[2]*brush->rgb[2]);
+ dst[3] = FTOCHAR(rgba[3]*brush_sample_falloff(brush, dist));
+ }
+ }
+ }
+ }
+
+ *outbuf= ibuf;
+}
+
+/* Brush Painting */
+
+typedef struct BrushPainterCache {
+ short enabled;
+
+ int size; /* size override, if 0 uses brush->size */
+ short flt; /* need float imbuf? */
+ short texonly; /* no alpha, color or fallof, only texture in imbuf */
+
+ int lastsize;
+ float lastalpha;
+ float lastinnerradius;
+
+ ImBuf *ibuf;
+ ImBuf *texibuf;
+ ImBuf *maskibuf;
+} BrushPainterCache;
+
+struct BrushPainter {
+ Brush *brush;
+
+ float lastmousepos[2]; /* mouse position of last paint call */
+
+ float accumdistance; /* accumulated distance of brush since last paint op */
+ float lastpaintpos[2]; /* position of last paint op */
+ float startpaintpos[2]; /* position of first paint */
+
+ double accumtime; /* accumulated time since last paint op (airbrush) */
+ double lasttime; /* time of last update */
+
+ float lastpressure;
+
+ short firsttouch; /* first paint op */
+
+ float startsize;
+ float startalpha;
+ float startinnerradius;
+ float startspacing;
+
+ BrushPainterCache cache;
+};
+
+BrushPainter *brush_painter_new(Brush *brush)
+{
+ BrushPainter *painter= MEM_callocN(sizeof(BrushPainter), "BrushPainter");
+
+ painter->brush= brush;
+ painter->firsttouch= 1;
+ painter->cache.lastsize= -1; /* force ibuf create in refresh */
+
+ painter->startsize = brush->size;
+ painter->startalpha = brush->alpha;
+ painter->startinnerradius = brush->innerradius;
+ painter->startspacing = brush->spacing;
+
+ return painter;
+}
+
+void brush_painter_require_imbuf(BrushPainter *painter, short flt, short texonly, int size)
+{
+ if ((painter->cache.flt != flt) || (painter->cache.size != size) ||
+ ((painter->cache.texonly != texonly) && texonly)) {
+ if (painter->cache.ibuf) IMB_freeImBuf(painter->cache.ibuf);
+ if (painter->cache.maskibuf) IMB_freeImBuf(painter->cache.maskibuf);
+ painter->cache.ibuf= painter->cache.maskibuf= NULL;
+ painter->cache.lastsize= -1; /* force ibuf create in refresh */
+ }
+
+ if (painter->cache.flt != flt) {
+ if (painter->cache.texibuf) IMB_freeImBuf(painter->cache.texibuf);
+ painter->cache.texibuf= NULL;
+ painter->cache.lastsize= -1; /* force ibuf create in refresh */
+ }
+
+ painter->cache.size= size;
+ painter->cache.flt= flt;
+ painter->cache.texonly= texonly;
+ painter->cache.enabled= 1;
+}
+
+void brush_painter_free(BrushPainter *painter)
+{
+ Brush *brush = painter->brush;
+
+ brush->size = painter->startsize;
+ brush->alpha = painter->startalpha;
+ brush->innerradius = painter->startinnerradius;
+ brush->spacing = painter->startspacing;
+
+ if (painter->cache.ibuf) IMB_freeImBuf(painter->cache.ibuf);
+ if (painter->cache.texibuf) IMB_freeImBuf(painter->cache.texibuf);
+ if (painter->cache.maskibuf) IMB_freeImBuf(painter->cache.maskibuf);
+ MEM_freeN(painter);
+}
+
+static void brush_painter_do_partial(BrushPainter *painter, ImBuf *oldtexibuf, int x, int y, int w, int h, int xt, int yt, float *pos)
+{
+ Brush *brush= painter->brush;
+ ImBuf *ibuf, *maskibuf, *texibuf;
+ float *bf, *mf, *tf, *otf=NULL, xoff, yoff, xy[2], rgba[4];
+ char *b, *m, *t, *ot= NULL;
+ int dotexold, origx= x, origy= y;
+
+ xoff = -brush->size/2.0f + 0.5f;
+ yoff = -brush->size/2.0f + 0.5f;
+ xoff += (int)pos[0] - (int)painter->startpaintpos[0];
+ yoff += (int)pos[1] - (int)painter->startpaintpos[1];
+
+ ibuf = painter->cache.ibuf;
+ texibuf = painter->cache.texibuf;
+ maskibuf = painter->cache.maskibuf;
+
+ dotexold = (oldtexibuf != NULL);
+
+ if (painter->cache.flt) {
+ for (; y < h; y++) {
+ bf = ibuf->rect_float + (y*ibuf->x + origx)*4;
+ tf = texibuf->rect_float + (y*texibuf->x + origx)*4;
+ mf = maskibuf->rect_float + (y*maskibuf->x + origx)*4;
+
+ if (dotexold)
+ otf = oldtexibuf->rect_float + ((y - origy + yt)*oldtexibuf->x + xt)*4;
+
+ for (x=origx; x < w; x++, bf+=4, mf+=4, tf+=4) {
+ if (dotexold) {
+ VECCOPY(tf, otf);
+ tf[3] = otf[3];
+ otf += 4;
+ }
+ else {
+ xy[0] = x + xoff;
+ xy[1] = y + yoff;
+
+ brush_sample_tex(brush, xy, tf);
+ }
+
+ bf[0] = tf[0]*mf[0];
+ bf[1] = tf[1]*mf[1];
+ bf[2] = tf[2]*mf[2];
+ bf[3] = tf[3]*mf[3];
+ }
+ }
+ }
+ else {
+ for (; y < h; y++) {
+ b = (char*)ibuf->rect + (y*ibuf->x + origx)*4;
+ t = (char*)texibuf->rect + (y*texibuf->x + origx)*4;
+ m = (char*)maskibuf->rect + (y*maskibuf->x + origx)*4;
+
+ if (dotexold)
+ ot = (char*)oldtexibuf->rect + ((y - origy + yt)*oldtexibuf->x + xt)*4;
+
+ for (x=origx; x < w; x++, b+=4, m+=4, t+=4) {
+ if (dotexold) {
+ t[0] = ot[0];
+ t[1] = ot[1];
+ t[2] = ot[2];
+ t[3] = ot[3];
+ ot += 4;
+ }
+ else {
+ xy[0] = x + xoff;
+ xy[1] = y + yoff;
+
+ brush_sample_tex(brush, xy, rgba);
+ t[0]= FTOCHAR(rgba[0]);
+ t[1]= FTOCHAR(rgba[1]);
+ t[2]= FTOCHAR(rgba[2]);
+ t[3]= FTOCHAR(rgba[3]);
+ }
+
+ b[0] = t[0]*m[0]/255;
+ b[1] = t[1]*m[1]/255;
+ b[2] = t[2]*m[2]/255;
+ b[3] = t[3]*m[3]/255;
+ }
+ }
+ }
+}
+
+void brush_painter_fixed_tex_partial_update(BrushPainter *painter, float *pos)
+{
+ Brush *brush= painter->brush;
+ BrushPainterCache *cache= &painter->cache;
+ ImBuf *oldtexibuf, *ibuf;
+ int imbflag, destx, desty, srcx, srcy, w, h, x1, y1, x2, y2;
+
+ imbflag= (cache->flt)? IB_rectfloat: IB_rect;
+ if (!cache->ibuf)
+ cache->ibuf= IMB_allocImBuf(brush->size, brush->size, 32, imbflag, 0);
+ ibuf= cache->ibuf;
+
+ oldtexibuf= cache->texibuf;
+ cache->texibuf= IMB_allocImBuf(brush->size, brush->size, 32, imbflag, 0);
+
+ if (oldtexibuf) {
+ srcx= srcy= 0;
+ destx= (int)painter->lastpaintpos[0] - (int)pos[0];
+ desty= (int)painter->lastpaintpos[1] - (int)pos[1];
+ w= oldtexibuf->x;
+ h= oldtexibuf->y;
+
+ IMB_rectclip(cache->texibuf, oldtexibuf, &destx, &desty, &srcx, &srcy, &w, &h);
+ }
+ else {
+ srcx= srcy= 0;
+ destx= desty= 0;
+ w= h= 0;
+ }
+
+ x1= destx;
+ y1= desty;
+ x2= destx+w;
+ y2= desty+h;
+
+ /* blend existing texture in new position */
+ if ((x1 < x2) && (y1 < y2))
+ brush_painter_do_partial(painter, oldtexibuf, x1, y1, x2, y2, srcx, srcy, pos);
+
+ if (oldtexibuf)
+ IMB_freeImBuf(oldtexibuf);
+
+ /* sample texture in new areas */
+ if ((0 < x1) && (0 < ibuf->y))
+ brush_painter_do_partial(painter, NULL, 0, 0, x1, ibuf->y, 0, 0, pos);
+ if ((x2 < ibuf->x) && (0 < ibuf->y))
+ brush_painter_do_partial(painter, NULL, x2, 0, ibuf->x, ibuf->y, 0, 0, pos);
+ if ((x1 < x2) && (0 < y1))
+ brush_painter_do_partial(painter, NULL, x1, 0, x2, y1, 0, 0, pos);
+ if ((x1 < x2) && (y2 < ibuf->y))
+ brush_painter_do_partial(painter, NULL, x1, y2, x2, ibuf->y, 0, 0, pos);
+}
+
+static void brush_painter_refresh_cache(BrushPainter *painter, float *pos)
+{
+ Brush *brush= painter->brush;
+ BrushPainterCache *cache= &painter->cache;
+ MTex *mtex= brush->mtex[brush->texact];
+ int size;
+ short flt;
+
+ if ((brush->size != cache->lastsize) || (brush->alpha != cache->lastalpha)
+ || (brush->innerradius != cache->lastinnerradius)) {
+ if (cache->ibuf) {
+ IMB_freeImBuf(cache->ibuf);
+ cache->ibuf= NULL;
+ }
+ if (cache->maskibuf) {
+ IMB_freeImBuf(cache->maskibuf);
+ cache->maskibuf= NULL;
+ }
+
+ flt= cache->flt;
+ size= (cache->size)? cache->size: brush->size;
+
+ if (!(mtex && mtex->tex) || (mtex->tex->type==0)) {
+ brush_imbuf_new(brush, flt, 0, size, &cache->ibuf);
+ }
+ else if (brush->flag & BRUSH_FIXED_TEX) {
+ brush_imbuf_new(brush, flt, 0, size, &cache->maskibuf);
+ brush_painter_fixed_tex_partial_update(painter, pos);
+ }
+ else
+ brush_imbuf_new(brush, flt, 2, size, &cache->ibuf);
+
+ cache->lastsize= brush->size;
+ cache->lastalpha= brush->alpha;
+ cache->lastinnerradius= brush->innerradius;
+ }
+ else if ((brush->flag & BRUSH_FIXED_TEX) && mtex && mtex->tex) {
+ int dx = (int)painter->lastpaintpos[0] - (int)pos[0];
+ int dy = (int)painter->lastpaintpos[1] - (int)pos[1];
+
+ if ((dx != 0) || (dy != 0))
+ brush_painter_fixed_tex_partial_update(painter, pos);
+ }
+}
+
+void brush_painter_break_stroke(BrushPainter *painter)
+{
+ painter->firsttouch= 1;
+}
+
+static void brush_apply_pressure(BrushPainter *painter, Brush *brush, float pressure)
+{
+ if (brush->flag & BRUSH_ALPHA_PRESSURE)
+ brush->alpha = MAX2(0.0, painter->startalpha*pressure);
+ if (brush->flag & BRUSH_SIZE_PRESSURE)
+ brush->size = MAX2(1.0, painter->startsize*pressure);
+ if (brush->flag & BRUSH_RAD_PRESSURE)
+ brush->innerradius = MAX2(0.0, painter->startinnerradius*pressure);
+ if (brush->flag & BRUSH_SPACING_PRESSURE)
+ brush->spacing = MAX2(1.0, painter->startspacing*(1.5f-pressure));
+}
+
+int brush_painter_paint(BrushPainter *painter, BrushFunc func, float *pos, double time, float pressure, void *user)
+{
+ Brush *brush= painter->brush;
+ int totpaintops= 0;
+
+ if (pressure == 0.0f)
+ pressure = 1.0f; /* zero pressure == not using tablet */
+
+ if (painter->firsttouch) {
+ /* paint exactly once on first touch */
+ painter->startpaintpos[0]= pos[0];
+ painter->startpaintpos[1]= pos[1];
+
+ brush_apply_pressure(painter, brush, pressure);
+ if (painter->cache.enabled)
+ brush_painter_refresh_cache(painter, pos);
+ totpaintops += func(user, painter->cache.ibuf, pos, pos);
+
+ painter->lasttime= time;
+ painter->firsttouch= 0;
+ painter->lastpaintpos[0]= pos[0];
+ painter->lastpaintpos[1]= pos[1];
+ }
+#if 0
+ else if (painter->brush->flag & BRUSH_AIRBRUSH) {
+ float spacing, step, paintpos[2], dmousepos[2], len;
+ double starttime, curtime= time;
+
+ /* compute brush spacing adapted to brush size */
+ spacing= brush->rate; //brush->size*brush->spacing*0.01f;
+
+ /* setup starting time, direction vector and accumulated time */
+ starttime= painter->accumtime;
+ Vec2Subf(dmousepos, pos, painter->lastmousepos);
+ len= Normalize2(dmousepos);
+ painter->accumtime += curtime - painter->lasttime;
+
+ /* do paint op over unpainted time distance */
+ while (painter->accumtime >= spacing) {
+ step= (spacing - starttime)*len;
+ paintpos[0]= painter->lastmousepos[0] + dmousepos[0]*step;
+ paintpos[1]= painter->lastmousepos[1] + dmousepos[1]*step;
+
+ if (painter->cache.enabled)
+ brush_painter_refresh_cache(painter);
+ totpaintops += func(user, painter->cache.ibuf,
+ painter->lastpaintpos, paintpos);
+
+ painter->lastpaintpos[0]= paintpos[0];
+ painter->lastpaintpos[1]= paintpos[1];
+ painter->accumtime -= spacing;
+ starttime -= spacing;
+ }
+
+ painter->lasttime= curtime;
+ }
+#endif
+ else {
+ float startdistance, spacing, step, paintpos[2], dmousepos[2];
+ float t, len, press;
+
+ /* compute brush spacing adapted to brush size, spacing may depend
+ on pressure, so update it */
+ brush_apply_pressure(painter, brush, painter->lastpressure);
+ spacing= MAX2(1.0f, brush->size)*brush->spacing*0.01f;
+
+ /* setup starting distance, direction vector and accumulated distance */
+ startdistance= painter->accumdistance;
+ Vec2Subf(dmousepos, pos, painter->lastmousepos);
+ len= Normalize2(dmousepos);
+ painter->accumdistance += len;
+
+ /* do paint op over unpainted distance */
+ while ((len > 0.0f) && (painter->accumdistance >= spacing)) {
+ step= spacing - startdistance;
+ paintpos[0]= painter->lastmousepos[0] + dmousepos[0]*step;
+ paintpos[1]= painter->lastmousepos[1] + dmousepos[1]*step;
+
+ t = step/len;
+ press= (1.0f-t)*painter->lastpressure + t*pressure;
+ brush_apply_pressure(painter, brush, press);
+ spacing= MAX2(1.0f, brush->size)*brush->spacing*0.01f;
+
+ if (painter->cache.enabled)
+ brush_painter_refresh_cache(painter, paintpos);
+
+ totpaintops +=
+ func(user, painter->cache.ibuf, painter->lastpaintpos, paintpos);
+
+ painter->lastpaintpos[0]= paintpos[0];
+ painter->lastpaintpos[1]= paintpos[1];
+ painter->accumdistance -= spacing;
+ startdistance -= spacing;
+ }
+
+ /* do airbrush paint ops, based on the number of paint ops left over
+ from regular painting. this is a temporary solution until we have
+ accurate time stamps for mouse move events */
+ if (brush->flag & BRUSH_AIRBRUSH) {
+ double curtime= time;
+ double painttime= brush->rate*totpaintops;
+
+ painter->accumtime += curtime - painter->lasttime;
+ if (painter->accumtime <= painttime)
+ painter->accumtime= 0.0;
+ else
+ painter->accumtime -= painttime;
+
+ while (painter->accumtime >= brush->rate) {
+ brush_apply_pressure(painter, brush, pressure);
+ if (painter->cache.enabled)
+ brush_painter_refresh_cache(painter, paintpos);
+ totpaintops +=
+ func(user, painter->cache.ibuf, painter->lastmousepos, pos);
+ painter->accumtime -= brush->rate;
+ }
+
+ painter->lasttime= curtime;
+ }
+ }
+
+ painter->lastmousepos[0]= pos[0];
+ painter->lastmousepos[1]= pos[1];
+ painter->lastpressure= pressure;
+
+ brush->alpha = painter->startalpha;
+ brush->size = painter->startsize;
+ brush->innerradius = painter->startinnerradius;
+ brush->spacing = painter->startspacing;
+
+ return totpaintops;
+}
+
+
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
new file mode 100644
index 00000000000..2d5f5f091c3
--- /dev/null
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -0,0 +1,1130 @@
+/*
+* $Id$
+*
+* ***** BEGIN GPL LICENSE BLOCK *****
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*
+* The Original Code is Copyright (C) 2006 Blender Foundation.
+* All rights reserved.
+*
+* The Original Code is: all of this file.
+*
+* Contributor(s): Ben Batt <benbatt@gmail.com>
+*
+* ***** END GPL LICENSE BLOCK *****
+*
+* Implementation of CDDerivedMesh.
+*
+* BKE_cdderivedmesh.h contains the function prototypes for this file.
+*
+*/
+
+/* TODO maybe BIF_gl.h should include string.h? */
+#include <string.h>
+#include "BIF_gl.h"
+
+#include "BKE_cdderivedmesh.h"
+#include "BKE_customdata.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_displist.h"
+#include "BKE_global.h"
+#include "BKE_mesh.h"
+#include "BKE_utildefines.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+#include "BLI_edgehash.h"
+#include "BLI_editVert.h"
+#include "BLI_ghash.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include <string.h>
+#include <limits.h>
+
+typedef struct {
+ DerivedMesh dm;
+
+ /* these point to data in the DerivedMesh custom data layers,
+ they are only here for efficiency and convenience **/
+ MVert *mvert;
+ MEdge *medge;
+ MFace *mface;
+} CDDerivedMesh;
+
+/**************** DerivedMesh interface functions ****************/
+static int cdDM_getNumVerts(DerivedMesh *dm)
+{
+ return dm->numVertData;
+}
+
+static int cdDM_getNumEdges(DerivedMesh *dm)
+{
+ return dm->numEdgeData;
+}
+
+static int cdDM_getNumFaces(DerivedMesh *dm)
+{
+ return dm->numFaceData;
+}
+
+static void cdDM_getVert(DerivedMesh *dm, int index, MVert *vert_r)
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
+ *vert_r = cddm->mvert[index];
+}
+
+static void cdDM_getEdge(DerivedMesh *dm, int index, MEdge *edge_r)
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
+ *edge_r = cddm->medge[index];
+}
+
+static void cdDM_getFace(DerivedMesh *dm, int index, MFace *face_r)
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
+ *face_r = cddm->mface[index];
+}
+
+static void cdDM_copyVertArray(DerivedMesh *dm, MVert *vert_r)
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
+ memcpy(vert_r, cddm->mvert, sizeof(*vert_r) * dm->numVertData);
+}
+
+static void cdDM_copyEdgeArray(DerivedMesh *dm, MEdge *edge_r)
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
+ memcpy(edge_r, cddm->medge, sizeof(*edge_r) * dm->numEdgeData);
+}
+
+void cdDM_copyFaceArray(DerivedMesh *dm, MFace *face_r)
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
+ memcpy(face_r, cddm->mface, sizeof(*face_r) * dm->numFaceData);
+}
+
+static void cdDM_getMinMax(DerivedMesh *dm, float min_r[3], float max_r[3])
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
+ int i;
+
+ if (dm->numVertData) {
+ for (i=0; i<dm->numVertData; i++) {
+ DO_MINMAX(cddm->mvert[i].co, min_r, max_r);
+ }
+ } else {
+ min_r[0] = min_r[1] = min_r[2] = max_r[0] = max_r[1] = max_r[2] = 0.0;
+ }
+}
+
+static void cdDM_getVertCo(DerivedMesh *dm, int index, float co_r[3])
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
+
+ VECCOPY(co_r, cddm->mvert[index].co);
+}
+
+static void cdDM_getVertCos(DerivedMesh *dm, float (*cos_r)[3])
+{
+ MVert *mv = CDDM_get_verts(dm);
+ int i;
+
+ for(i = 0; i < dm->numVertData; i++, mv++)
+ VECCOPY(cos_r[i], mv->co);
+}
+
+static void cdDM_getVertNo(DerivedMesh *dm, int index, float no_r[3])
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
+ short *no = cddm->mvert[index].no;
+
+ no_r[0] = no[0]/32767.f;
+ no_r[1] = no[1]/32767.f;
+ no_r[2] = no[2]/32767.f;
+}
+
+static void cdDM_drawVerts(DerivedMesh *dm)
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
+ MVert *mv = cddm->mvert;
+ int i;
+
+ glBegin(GL_POINTS);
+ for(i = 0; i < dm->numVertData; i++, mv++)
+ glVertex3fv(mv->co);
+ glEnd();
+}
+
+static void cdDM_drawUVEdges(DerivedMesh *dm)
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
+ MFace *mf = cddm->mface;
+ MTFace *tf = DM_get_face_data_layer(dm, CD_MTFACE);
+ int i;
+
+ if(mf) {
+ glBegin(GL_LINES);
+ for(i = 0; i < dm->numFaceData; i++, mf++, tf++) {
+ if(!(mf->flag&ME_HIDE)) {
+ glVertex2fv(tf->uv[0]);
+ glVertex2fv(tf->uv[1]);
+
+ glVertex2fv(tf->uv[1]);
+ glVertex2fv(tf->uv[2]);
+
+ if(!mf->v4) {
+ glVertex2fv(tf->uv[2]);
+ glVertex2fv(tf->uv[0]);
+ } else {
+ glVertex2fv(tf->uv[2]);
+ glVertex2fv(tf->uv[3]);
+
+ glVertex2fv(tf->uv[3]);
+ glVertex2fv(tf->uv[0]);
+ }
+ }
+ }
+ glEnd();
+ }
+}
+
+static void cdDM_drawEdges(DerivedMesh *dm, int drawLooseEdges)
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
+ MVert *mvert = cddm->mvert;
+ MEdge *medge = cddm->medge;
+ int i;
+
+ glBegin(GL_LINES);
+ for(i = 0; i < dm->numEdgeData; i++, medge++) {
+ if((medge->flag&ME_EDGEDRAW)
+ && (drawLooseEdges || !(medge->flag&ME_LOOSEEDGE))) {
+ glVertex3fv(mvert[medge->v1].co);
+ glVertex3fv(mvert[medge->v2].co);
+ }
+ }
+ glEnd();
+}
+
+static void cdDM_drawLooseEdges(DerivedMesh *dm)
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
+ MVert *mvert = cddm->mvert;
+ MEdge *medge = cddm->medge;
+ int i;
+
+ glBegin(GL_LINES);
+ for(i = 0; i < dm->numEdgeData; i++, medge++) {
+ if(medge->flag&ME_LOOSEEDGE) {
+ glVertex3fv(mvert[medge->v1].co);
+ glVertex3fv(mvert[medge->v2].co);
+ }
+ }
+ glEnd();
+}
+
+static void cdDM_drawFacesSolid(DerivedMesh *dm, int (*setMaterial)(int))
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
+ MVert *mvert = cddm->mvert;
+ MFace *mface = cddm->mface;
+ float *nors= dm->getFaceDataArray(dm, CD_NORMAL);
+ int a, glmode = -1, shademodel = -1, matnr = -1, drawCurrentMat = 1;
+
+#define PASSVERT(index) { \
+ if(shademodel == GL_SMOOTH) { \
+ short *no = mvert[index].no; \
+ glNormal3sv(no); \
+ } \
+ glVertex3fv(mvert[index].co); \
+}
+
+ glBegin(glmode = GL_QUADS);
+ for(a = 0; a < dm->numFaceData; a++, mface++) {
+ int new_glmode, new_matnr, new_shademodel;
+
+ new_glmode = mface->v4?GL_QUADS:GL_TRIANGLES;
+ new_matnr = mface->mat_nr + 1;
+ new_shademodel = (mface->flag & ME_SMOOTH)?GL_SMOOTH:GL_FLAT;
+
+ if(new_glmode != glmode || new_matnr != matnr
+ || new_shademodel != shademodel) {
+ glEnd();
+
+ drawCurrentMat = setMaterial(matnr = new_matnr);
+
+ glShadeModel(shademodel = new_shademodel);
+ glBegin(glmode = new_glmode);
+ }
+
+ if(drawCurrentMat) {
+ if(shademodel == GL_FLAT) {
+ if (nors) {
+ glNormal3fv(nors);
+ }
+ else {
+ /* TODO make this better (cache facenormals as layer?) */
+ float nor[3];
+ if(mface->v4) {
+ CalcNormFloat4(mvert[mface->v1].co, mvert[mface->v2].co,
+ mvert[mface->v3].co, mvert[mface->v4].co,
+ nor);
+ } else {
+ CalcNormFloat(mvert[mface->v1].co, mvert[mface->v2].co,
+ mvert[mface->v3].co, nor);
+ }
+ glNormal3fv(nor);
+ }
+ }
+
+ PASSVERT(mface->v1);
+ PASSVERT(mface->v2);
+ PASSVERT(mface->v3);
+ if(mface->v4) {
+ PASSVERT(mface->v4);
+ }
+ }
+
+ if(nors) nors += 3;
+ }
+ glEnd();
+
+ glShadeModel(GL_FLAT);
+#undef PASSVERT
+}
+
+static void cdDM_drawFacesColored(DerivedMesh *dm, int useTwoSided, unsigned char *col1, unsigned char *col2)
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
+ int a, glmode;
+ unsigned char *cp1, *cp2;
+ MVert *mvert = cddm->mvert;
+ MFace *mface = cddm->mface;
+
+ cp1 = col1;
+ if(col2) {
+ cp2 = col2;
+ } else {
+ cp2 = NULL;
+ useTwoSided = 0;
+ }
+
+ /* there's a conflict here... twosided colors versus culling...? */
+ /* defined by history, only texture faces have culling option */
+ /* we need that as mesh option builtin, next to double sided lighting */
+ if(col1 && col2)
+ glEnable(GL_CULL_FACE);
+
+ glShadeModel(GL_SMOOTH);
+ glBegin(glmode = GL_QUADS);
+ for(a = 0; a < dm->numFaceData; a++, mface++, cp1 += 16) {
+ int new_glmode = mface->v4?GL_QUADS:GL_TRIANGLES;
+
+ if(new_glmode != glmode) {
+ glEnd();
+ glBegin(glmode = new_glmode);
+ }
+
+ glColor3ub(cp1[0], cp1[1], cp1[2]);
+ glVertex3fv(mvert[mface->v1].co);
+ glColor3ub(cp1[4], cp1[5], cp1[6]);
+ glVertex3fv(mvert[mface->v2].co);
+ glColor3ub(cp1[8], cp1[9], cp1[10]);
+ glVertex3fv(mvert[mface->v3].co);
+ if(mface->v4) {
+ glColor3ub(cp1[12], cp1[13], cp1[14]);
+ glVertex3fv(mvert[mface->v4].co);
+ }
+
+ if(useTwoSided) {
+ glColor3ub(cp2[8], cp2[9], cp2[10]);
+ glVertex3fv(mvert[mface->v3].co );
+ glColor3ub(cp2[4], cp2[5], cp2[6]);
+ glVertex3fv(mvert[mface->v2].co );
+ glColor3ub(cp2[0], cp2[1], cp2[2]);
+ glVertex3fv(mvert[mface->v1].co );
+ if(mface->v4) {
+ glColor3ub(cp2[12], cp2[13], cp2[14]);
+ glVertex3fv(mvert[mface->v4].co );
+ }
+ }
+ if(col2) cp2 += 16;
+ }
+ glEnd();
+
+ glShadeModel(GL_FLAT);
+ glDisable(GL_CULL_FACE);
+}
+
+static void cdDM_drawFacesTex_common(DerivedMesh *dm,
+ int (*drawParams)(MTFace *tface, MCol *mcol, int matnr),
+ int (*drawParamsMapped)(void *userData, int index),
+ void *userData)
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
+ MVert *mv = cddm->mvert;
+ MFace *mf = cddm->mface;
+ MCol *mcol = dm->getFaceDataArray(dm, CD_MCOL);
+ float *nors= dm->getFaceDataArray(dm, CD_NORMAL);
+ MTFace *tf = DM_get_face_data_layer(dm, CD_MTFACE);
+ int i, orig, *index = DM_get_face_data_layer(dm, CD_ORIGINDEX);
+
+ for(i = 0; i < dm->numFaceData; i++, mf++) {
+ MVert *mvert;
+ int flag;
+ unsigned char *cp = NULL;
+
+ if(drawParams) {
+ flag = drawParams(tf? &tf[i]: NULL, mcol? &mcol[i*4]: NULL, mf->mat_nr);
+ }
+ else {
+ if(index) {
+ orig = *index++;
+ if(orig == ORIGINDEX_NONE) { if(nors) nors += 3; continue; }
+ if(drawParamsMapped) flag = drawParamsMapped(userData, orig);
+ else { if(nors) nors += 3; continue; }
+ }
+ else
+ if(drawParamsMapped) flag = drawParamsMapped(userData, i);
+ else { if(nors) nors += 3; continue; }
+ }
+
+ if(flag != 0) { /* if the flag is 0 it means the face is hidden or invisible */
+ if (flag==1 && mcol)
+ cp= (unsigned char*) &mcol[i*4];
+
+ if(!(mf->flag&ME_SMOOTH)) {
+ if (nors) {
+ glNormal3fv(nors);
+ }
+ else {
+ /* TODO make this better (cache facenormals as layer?) */
+ float nor[3];
+ if(mf->v4) {
+ CalcNormFloat4(mv[mf->v1].co, mv[mf->v2].co,
+ mv[mf->v3].co, mv[mf->v4].co,
+ nor);
+ } else {
+ CalcNormFloat(mv[mf->v1].co, mv[mf->v2].co,
+ mv[mf->v3].co, nor);
+ }
+ glNormal3fv(nor);
+ }
+ }
+
+ glBegin(mf->v4?GL_QUADS:GL_TRIANGLES);
+ if(tf) glTexCoord2fv(tf[i].uv[0]);
+ if(cp) glColor3ub(cp[3], cp[2], cp[1]);
+ mvert = &mv[mf->v1];
+ if(mf->flag&ME_SMOOTH) glNormal3sv(mvert->no);
+ glVertex3fv(mvert->co);
+
+ if(tf) glTexCoord2fv(tf[i].uv[1]);
+ if(cp) glColor3ub(cp[7], cp[6], cp[5]);
+ mvert = &mv[mf->v2];
+ if(mf->flag&ME_SMOOTH) glNormal3sv(mvert->no);
+ glVertex3fv(mvert->co);
+
+ if(tf) glTexCoord2fv(tf[i].uv[2]);
+ if(cp) glColor3ub(cp[11], cp[10], cp[9]);
+ mvert = &mv[mf->v3];
+ if(mf->flag&ME_SMOOTH) glNormal3sv(mvert->no);
+ glVertex3fv(mvert->co);
+
+ if(mf->v4) {
+ if(tf) glTexCoord2fv(tf[i].uv[3]);
+ if(cp) glColor3ub(cp[15], cp[14], cp[13]);
+ mvert = &mv[mf->v4];
+ if(mf->flag&ME_SMOOTH) glNormal3sv(mvert->no);
+ glVertex3fv(mvert->co);
+ }
+ glEnd();
+ }
+
+ if(nors) nors += 3;
+ }
+}
+
+static void cdDM_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tface, MCol *mcol, int matnr))
+{
+ cdDM_drawFacesTex_common(dm, setDrawOptions, NULL, NULL);
+}
+
+static void cdDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int useColors)
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
+ MVert *mv = cddm->mvert;
+ MFace *mf = cddm->mface;
+ MCol *mc = DM_get_face_data_layer(dm, CD_MCOL);
+ float *nors= dm->getFaceDataArray(dm, CD_NORMAL);
+ int i, orig, *index = DM_get_face_data_layer(dm, CD_ORIGINDEX);
+
+ for(i = 0; i < dm->numFaceData; i++, mf++) {
+ int drawSmooth = (mf->flag & ME_SMOOTH);
+
+ if(index) {
+ orig = *index++;
+ if(setDrawOptions && orig == ORIGINDEX_NONE)
+ { if(nors) nors += 3; continue; }
+ }
+ else
+ orig = i;
+
+ if(!setDrawOptions || setDrawOptions(userData, orig, &drawSmooth)) {
+ unsigned char *cp = NULL;
+
+ if(useColors && mc)
+ cp = (unsigned char *)&mc[i * 4];
+
+ glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT);
+ glBegin(mf->v4?GL_QUADS:GL_TRIANGLES);
+
+ if (!drawSmooth) {
+ if (nors) {
+ glNormal3fv(nors);
+ }
+ else {
+ /* TODO make this better (cache facenormals as layer?) */
+ float nor[3];
+ if(mf->v4) {
+ CalcNormFloat4(mv[mf->v1].co, mv[mf->v2].co,
+ mv[mf->v3].co, mv[mf->v4].co,
+ nor);
+ } else {
+ CalcNormFloat(mv[mf->v1].co, mv[mf->v2].co,
+ mv[mf->v3].co, nor);
+ }
+ glNormal3fv(nor);
+ }
+
+ if(cp) glColor3ub(cp[3], cp[2], cp[1]);
+ glVertex3fv(mv[mf->v1].co);
+ if(cp) glColor3ub(cp[7], cp[6], cp[5]);
+ glVertex3fv(mv[mf->v2].co);
+ if(cp) glColor3ub(cp[11], cp[10], cp[9]);
+ glVertex3fv(mv[mf->v3].co);
+ if(mf->v4) {
+ if(cp) glColor3ub(cp[15], cp[14], cp[13]);
+ glVertex3fv(mv[mf->v4].co);
+ }
+ } else {
+ if(cp) glColor3ub(cp[3], cp[2], cp[1]);
+ glNormal3sv(mv[mf->v1].no);
+ glVertex3fv(mv[mf->v1].co);
+ if(cp) glColor3ub(cp[7], cp[6], cp[5]);
+ glNormal3sv(mv[mf->v2].no);
+ glVertex3fv(mv[mf->v2].co);
+ if(cp) glColor3ub(cp[11], cp[10], cp[9]);
+ glNormal3sv(mv[mf->v3].no);
+ glVertex3fv(mv[mf->v3].co);
+ if(mf->v4) {
+ if(cp) glColor3ub(cp[15], cp[14], cp[13]);
+ glNormal3sv(mv[mf->v4].no);
+ glVertex3fv(mv[mf->v4].co);
+ }
+ }
+
+ glEnd();
+ }
+
+ if (nors) nors += 3;
+ }
+}
+
+static void cdDM_drawMappedFacesTex(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData)
+{
+ cdDM_drawFacesTex_common(dm, NULL, setDrawOptions, userData);
+}
+
+static void cdDM_drawMappedEdges(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData)
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
+ MVert *vert = cddm->mvert;
+ MEdge *edge = cddm->medge;
+ int i, orig, *index = DM_get_edge_data_layer(dm, CD_ORIGINDEX);
+
+ glBegin(GL_LINES);
+ for(i = 0; i < dm->numEdgeData; i++, edge++) {
+ if(index) {
+ orig = *index++;
+ if(setDrawOptions && orig == ORIGINDEX_NONE) continue;
+ }
+ else
+ orig = i;
+
+ if(!setDrawOptions || setDrawOptions(userData, orig)) {
+ glVertex3fv(vert[edge->v1].co);
+ glVertex3fv(vert[edge->v2].co);
+ }
+ }
+ glEnd();
+}
+
+static void cdDM_foreachMappedVert(
+ DerivedMesh *dm,
+ void (*func)(void *userData, int index, float *co,
+ float *no_f, short *no_s),
+ void *userData)
+{
+ MVert *mv = CDDM_get_verts(dm);
+ int i, orig, *index = DM_get_vert_data_layer(dm, CD_ORIGINDEX);
+
+ for(i = 0; i < dm->numVertData; i++, mv++) {
+ if(index) {
+ orig = *index++;
+ if(orig == ORIGINDEX_NONE) continue;
+ func(userData, orig, mv->co, NULL, mv->no);
+ }
+ else
+ func(userData, i, mv->co, NULL, mv->no);
+ }
+}
+
+static void cdDM_foreachMappedEdge(
+ DerivedMesh *dm,
+ void (*func)(void *userData, int index,
+ float *v0co, float *v1co),
+ void *userData)
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
+ MVert *mv = cddm->mvert;
+ MEdge *med = cddm->medge;
+ int i, orig, *index = DM_get_edge_data_layer(dm, CD_ORIGINDEX);
+
+ for(i = 0; i < dm->numEdgeData; i++, med++) {
+ if (index) {
+ orig = *index++;
+ if(orig == ORIGINDEX_NONE) continue;
+ func(userData, orig, mv[med->v1].co, mv[med->v2].co);
+ }
+ else
+ func(userData, i, mv[med->v1].co, mv[med->v2].co);
+ }
+}
+
+static void cdDM_foreachMappedFaceCenter(
+ DerivedMesh *dm,
+ void (*func)(void *userData, int index,
+ float *cent, float *no),
+ void *userData)
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
+ MVert *mv = cddm->mvert;
+ MFace *mf = cddm->mface;
+ int i, orig, *index = DM_get_face_data_layer(dm, CD_ORIGINDEX);
+
+ for(i = 0; i < dm->numFaceData; i++, mf++) {
+ float cent[3];
+ float no[3];
+
+ if (index) {
+ orig = *index++;
+ if(orig == ORIGINDEX_NONE) continue;
+ }
+ else
+ orig = i;
+
+ VECCOPY(cent, mv[mf->v1].co);
+ VecAddf(cent, cent, mv[mf->v2].co);
+ VecAddf(cent, cent, mv[mf->v3].co);
+
+ if (mf->v4) {
+ CalcNormFloat4(mv[mf->v1].co, mv[mf->v2].co,
+ mv[mf->v3].co, mv[mf->v4].co, no);
+ VecAddf(cent, cent, mv[mf->v4].co);
+ VecMulf(cent, 0.25f);
+ } else {
+ CalcNormFloat(mv[mf->v1].co, mv[mf->v2].co,
+ mv[mf->v3].co, no);
+ VecMulf(cent, 0.33333333333f);
+ }
+
+ func(userData, orig, cent, no);
+ }
+}
+
+static void cdDM_release(DerivedMesh *dm)
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
+
+ if (DM_release(dm))
+ MEM_freeN(cddm);
+}
+
+/**************** CDDM interface functions ****************/
+static CDDerivedMesh *cdDM_create(const char *desc)
+{
+ CDDerivedMesh *cddm;
+ DerivedMesh *dm;
+
+ cddm = MEM_callocN(sizeof(*cddm), desc);
+ dm = &cddm->dm;
+
+ dm->getMinMax = cdDM_getMinMax;
+
+ dm->getNumVerts = cdDM_getNumVerts;
+ dm->getNumFaces = cdDM_getNumFaces;
+ dm->getNumEdges = cdDM_getNumEdges;
+
+ dm->getVert = cdDM_getVert;
+ dm->getEdge = cdDM_getEdge;
+ dm->getFace = cdDM_getFace;
+ dm->copyVertArray = cdDM_copyVertArray;
+ dm->copyEdgeArray = cdDM_copyEdgeArray;
+ dm->copyFaceArray = cdDM_copyFaceArray;
+ dm->getVertData = DM_get_vert_data;
+ dm->getEdgeData = DM_get_edge_data;
+ dm->getFaceData = DM_get_face_data;
+ dm->getVertDataArray = DM_get_vert_data_layer;
+ dm->getEdgeDataArray = DM_get_edge_data_layer;
+ dm->getFaceDataArray = DM_get_face_data_layer;
+
+ dm->getVertCos = cdDM_getVertCos;
+ dm->getVertCo = cdDM_getVertCo;
+ dm->getVertNo = cdDM_getVertNo;
+
+ dm->drawVerts = cdDM_drawVerts;
+
+ dm->drawUVEdges = cdDM_drawUVEdges;
+ dm->drawEdges = cdDM_drawEdges;
+ dm->drawLooseEdges = cdDM_drawLooseEdges;
+ dm->drawMappedEdges = cdDM_drawMappedEdges;
+
+ dm->drawFacesSolid = cdDM_drawFacesSolid;
+ dm->drawFacesColored = cdDM_drawFacesColored;
+ dm->drawFacesTex = cdDM_drawFacesTex;
+ dm->drawMappedFaces = cdDM_drawMappedFaces;
+ dm->drawMappedFacesTex = cdDM_drawMappedFacesTex;
+
+ dm->foreachMappedVert = cdDM_foreachMappedVert;
+ dm->foreachMappedEdge = cdDM_foreachMappedEdge;
+ dm->foreachMappedFaceCenter = cdDM_foreachMappedFaceCenter;
+
+ dm->release = cdDM_release;
+
+ return cddm;
+}
+
+DerivedMesh *CDDM_new(int numVerts, int numEdges, int numFaces)
+{
+ CDDerivedMesh *cddm = cdDM_create("CDDM_new dm");
+ DerivedMesh *dm = &cddm->dm;
+
+ DM_init(dm, numVerts, numEdges, numFaces);
+
+ CustomData_add_layer(&dm->vertData, CD_MVERT, CD_CALLOC, NULL, numVerts);
+ CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges);
+ CustomData_add_layer(&dm->faceData, CD_MFACE, CD_CALLOC, NULL, numFaces);
+
+ cddm->mvert = CustomData_get_layer(&dm->vertData, CD_MVERT);
+ cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE);
+ cddm->mface = CustomData_get_layer(&dm->faceData, CD_MFACE);
+
+ return dm;
+}
+
+DerivedMesh *CDDM_from_mesh(Mesh *mesh, Object *ob)
+{
+ CDDerivedMesh *cddm = cdDM_create("CDDM_from_mesh dm");
+ DerivedMesh *dm = &cddm->dm;
+ int i, *index;
+
+ /* this does a referenced copy, the only new layers being ORIGINDEX */
+
+ DM_init(dm, mesh->totvert, mesh->totedge, mesh->totface);
+
+ CustomData_merge(&mesh->vdata, &dm->vertData, CD_MASK_MESH, CD_REFERENCE,
+ mesh->totvert);
+ CustomData_merge(&mesh->edata, &dm->edgeData, CD_MASK_MESH, CD_REFERENCE,
+ mesh->totedge);
+ CustomData_merge(&mesh->fdata, &dm->faceData, CD_MASK_MESH, CD_REFERENCE,
+ mesh->totface);
+
+ cddm->mvert = CustomData_get_layer(&dm->vertData, CD_MVERT);
+ cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE);
+ cddm->mface = CustomData_get_layer(&dm->faceData, CD_MFACE);
+
+ index = CustomData_get_layer(&dm->vertData, CD_ORIGINDEX);
+ for(i = 0; i < mesh->totvert; ++i, ++index)
+ *index = i;
+
+ index = CustomData_get_layer(&dm->edgeData, CD_ORIGINDEX);
+ for(i = 0; i < mesh->totedge; ++i, ++index)
+ *index = i;
+
+ index = CustomData_get_layer(&dm->faceData, CD_ORIGINDEX);
+ for(i = 0; i < mesh->totface; ++i, ++index)
+ *index = i;
+
+ /* works in conjunction with hack during modifier calc, where active mcol
+ layer with weight paint colors is temporarily added */
+ if ((G.f & G_WEIGHTPAINT) &&
+ (ob && ob==(G.scene->basact?G.scene->basact->object:NULL)))
+ CustomData_duplicate_referenced_layer(&dm->faceData, CD_MCOL);
+
+ return dm;
+}
+
+DerivedMesh *CDDM_from_editmesh(EditMesh *em, Mesh *me)
+{
+ DerivedMesh *dm = CDDM_new(BLI_countlist(&em->verts),
+ BLI_countlist(&em->edges),
+ BLI_countlist(&em->faces));
+ CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
+ EditVert *eve;
+ EditEdge *eed;
+ EditFace *efa;
+ MVert *mvert = cddm->mvert;
+ MEdge *medge = cddm->medge;
+ MFace *mface = cddm->mface;
+ int i, *index;
+
+ CustomData_merge(&em->vdata, &dm->vertData, CD_MASK_DERIVEDMESH,
+ CD_CALLOC, dm->numVertData);
+ /* CustomData_merge(&em->edata, &dm->edgeData, CD_MASK_DERIVEDMESH,
+ CD_CALLOC, dm->numEdgeData); */
+ CustomData_merge(&em->fdata, &dm->faceData, CD_MASK_DERIVEDMESH,
+ CD_CALLOC, dm->numFaceData);
+
+ /* set eve->hash to vert index */
+ for(i = 0, eve = em->verts.first; eve; eve = eve->next, ++i)
+ eve->tmp.l = i;
+
+ /* Need to be able to mark loose edges */
+ for(eed = em->edges.first; eed; eed = eed->next) {
+ eed->f2 = 0;
+ }
+ for(efa = em->faces.first; efa; efa = efa->next) {
+ efa->e1->f2 = 1;
+ efa->e2->f2 = 1;
+ efa->e3->f2 = 1;
+ if(efa->e4) efa->e4->f2 = 1;
+ }
+
+ index = dm->getVertDataArray(dm, CD_ORIGINDEX);
+ for(i = 0, eve = em->verts.first; i < dm->numVertData;
+ i++, eve = eve->next, index++) {
+ MVert *mv = &mvert[i];
+
+ VECCOPY(mv->co, eve->co);
+
+ mv->no[0] = eve->no[0] * 32767.0;
+ mv->no[1] = eve->no[1] * 32767.0;
+ mv->no[2] = eve->no[2] * 32767.0;
+
+ mv->mat_nr = 0;
+ mv->flag = 0;
+
+ *index = i;
+
+ CustomData_from_em_block(&em->vdata, &dm->vertData, eve->data, i);
+ }
+
+ index = dm->getEdgeDataArray(dm, CD_ORIGINDEX);
+ for(i = 0, eed = em->edges.first; i < dm->numEdgeData;
+ i++, eed = eed->next, index++) {
+ MEdge *med = &medge[i];
+
+ med->v1 = eed->v1->tmp.l;
+ med->v2 = eed->v2->tmp.l;
+ med->crease = (unsigned char) (eed->crease * 255.0f);
+ med->flag = ME_EDGEDRAW|ME_EDGERENDER;
+
+ if(eed->seam) med->flag |= ME_SEAM;
+ if(eed->sharp) med->flag |= ME_SHARP;
+ if(!eed->f2) med->flag |= ME_LOOSEEDGE;
+
+ *index = i;
+
+ /* CustomData_from_em_block(&em->edata, &dm->edgeData, eed->data, i); */
+ }
+
+ index = dm->getFaceDataArray(dm, CD_ORIGINDEX);
+ for(i = 0, efa = em->faces.first; i < dm->numFaceData;
+ i++, efa = efa->next, index++) {
+ MFace *mf = &mface[i];
+
+ mf->v1 = efa->v1->tmp.l;
+ mf->v2 = efa->v2->tmp.l;
+ mf->v3 = efa->v3->tmp.l;
+ mf->v4 = efa->v4 ? efa->v4->tmp.l : 0;
+ mf->mat_nr = efa->mat_nr;
+ mf->flag = efa->flag;
+
+ *index = i;
+
+ CustomData_from_em_block(&em->fdata, &dm->faceData, efa->data, i);
+ test_index_face(mf, &dm->faceData, i, efa->v4?4:3);
+ }
+
+ return dm;
+}
+
+DerivedMesh *CDDM_copy(DerivedMesh *source)
+{
+ CDDerivedMesh *cddm = cdDM_create("CDDM_copy cddm");
+ DerivedMesh *dm = &cddm->dm;
+ int numVerts = source->numVertData;
+ int numEdges = source->numEdgeData;
+ int numFaces = source->numFaceData;
+
+ /* this initializes dm, and copies all non mvert/medge/mface layers */
+ DM_from_template(dm, source, numVerts, numEdges, numFaces);
+
+ CustomData_copy_data(&source->vertData, &dm->vertData, 0, 0, numVerts);
+ CustomData_copy_data(&source->edgeData, &dm->edgeData, 0, 0, numEdges);
+ CustomData_copy_data(&source->faceData, &dm->faceData, 0, 0, numFaces);
+
+ /* now add mvert/medge/mface layers */
+ cddm->mvert = source->dupVertArray(source);
+ cddm->medge = source->dupEdgeArray(source);
+ cddm->mface = source->dupFaceArray(source);
+
+ CustomData_add_layer(&dm->vertData, CD_MVERT, CD_ASSIGN, cddm->mvert, numVerts);
+ CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_ASSIGN, cddm->medge, numEdges);
+ CustomData_add_layer(&dm->faceData, CD_MFACE, CD_ASSIGN, cddm->mface, numFaces);
+
+ return dm;
+}
+
+DerivedMesh *CDDM_from_template(DerivedMesh *source,
+ int numVerts, int numEdges, int numFaces)
+{
+ CDDerivedMesh *cddm = cdDM_create("CDDM_from_template dest");
+ DerivedMesh *dm = &cddm->dm;
+
+ /* this does a copy of all non mvert/medge/mface layers */
+ DM_from_template(dm, source, numVerts, numEdges, numFaces);
+
+ /* now add mvert/medge/mface layers */
+ CustomData_add_layer(&dm->vertData, CD_MVERT, CD_CALLOC, NULL, numVerts);
+ CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges);
+ CustomData_add_layer(&dm->faceData, CD_MFACE, CD_CALLOC, NULL, numFaces);
+
+ cddm->mvert = CustomData_get_layer(&dm->vertData, CD_MVERT);
+ cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE);
+ cddm->mface = CustomData_get_layer(&dm->faceData, CD_MFACE);
+
+ return dm;
+}
+
+void CDDM_apply_vert_coords(DerivedMesh *dm, float (*vertCoords)[3])
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
+ MVert *vert;
+ int i;
+
+ /* this will just return the pointer if it wasn't a referenced layer */
+ vert = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT);
+ cddm->mvert = vert;
+
+ for(i = 0; i < dm->numVertData; ++i, ++vert)
+ VECCOPY(vert->co, vertCoords[i]);
+}
+
+void CDDM_apply_vert_normals(DerivedMesh *dm, short (*vertNormals)[3])
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
+ MVert *vert;
+ int i;
+
+ /* this will just return the pointer if it wasn't a referenced layer */
+ vert = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT);
+ cddm->mvert = vert;
+
+ for(i = 0; i < dm->numVertData; ++i, ++vert)
+ VECCOPY(vert->no, vertNormals[i]);
+}
+
+/* adapted from mesh_calc_normals */
+void CDDM_calc_normals(DerivedMesh *dm)
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
+ float (*temp_nors)[3];
+ float (*face_nors)[3];
+ int i;
+ int numVerts = dm->numVertData;
+ int numFaces = dm->numFaceData;
+ MFace *mf;
+ MVert *mv;
+
+ if(numVerts == 0) return;
+
+ temp_nors = MEM_callocN(numVerts * sizeof(*temp_nors),
+ "CDDM_calc_normals temp_nors");
+
+ /* we don't want to overwrite any referenced layers */
+ mv = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT);
+ cddm->mvert = mv;
+
+ /* make a face normal layer if not present */
+ face_nors = CustomData_get_layer(&dm->faceData, CD_NORMAL);
+ if(!face_nors)
+ face_nors = CustomData_add_layer(&dm->faceData, CD_NORMAL, CD_CALLOC,
+ NULL, dm->numFaceData);
+
+ /* calculate face normals and add to vertex normals */
+ mf = CDDM_get_faces(dm);
+ for(i = 0; i < numFaces; i++, mf++) {
+ float *f_no = face_nors[i];
+
+ if(mf->v4)
+ CalcNormFloat4(mv[mf->v1].co, mv[mf->v2].co,
+ mv[mf->v3].co, mv[mf->v4].co, f_no);
+ else
+ CalcNormFloat(mv[mf->v1].co, mv[mf->v2].co,
+ mv[mf->v3].co, f_no);
+
+ VecAddf(temp_nors[mf->v1], temp_nors[mf->v1], f_no);
+ VecAddf(temp_nors[mf->v2], temp_nors[mf->v2], f_no);
+ VecAddf(temp_nors[mf->v3], temp_nors[mf->v3], f_no);
+ if(mf->v4)
+ VecAddf(temp_nors[mf->v4], temp_nors[mf->v4], f_no);
+ }
+
+ /* normalize vertex normals and assign */
+ for(i = 0; i < numVerts; i++, mv++) {
+ float *no = temp_nors[i];
+
+ if (Normalize(no) == 0.0) {
+ VECCOPY(no, mv->co);
+ Normalize(no);
+ }
+
+ mv->no[0] = (short)(no[0] * 32767.0);
+ mv->no[1] = (short)(no[1] * 32767.0);
+ mv->no[2] = (short)(no[2] * 32767.0);
+ }
+
+ MEM_freeN(temp_nors);
+}
+
+void CDDM_calc_edges(DerivedMesh *dm)
+{
+ CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
+ CustomData edgeData;
+ EdgeHashIterator *ehi;
+ MFace *mf = cddm->mface;
+ MEdge *med;
+ EdgeHash *eh = BLI_edgehash_new();
+ int i, *index, numEdges, maxFaces = dm->numFaceData;
+
+ for (i = 0; i < maxFaces; i++, mf++) {
+ if (!BLI_edgehash_haskey(eh, mf->v1, mf->v2))
+ BLI_edgehash_insert(eh, mf->v1, mf->v2, NULL);
+ if (!BLI_edgehash_haskey(eh, mf->v2, mf->v3))
+ BLI_edgehash_insert(eh, mf->v2, mf->v3, NULL);
+
+ if (mf->v4) {
+ if (!BLI_edgehash_haskey(eh, mf->v3, mf->v4))
+ BLI_edgehash_insert(eh, mf->v3, mf->v4, NULL);
+ if (!BLI_edgehash_haskey(eh, mf->v4, mf->v1))
+ BLI_edgehash_insert(eh, mf->v4, mf->v1, NULL);
+ } else {
+ if (!BLI_edgehash_haskey(eh, mf->v3, mf->v1))
+ BLI_edgehash_insert(eh, mf->v3, mf->v1, NULL);
+ }
+ }
+
+ numEdges = BLI_edgehash_size(eh);
+
+ /* write new edges into a temporary CustomData */
+ memset(&edgeData, 0, sizeof(edgeData));
+ CustomData_add_layer(&edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges);
+ CustomData_add_layer(&edgeData, CD_ORIGINDEX, CD_CALLOC, NULL, numEdges);
+
+ ehi = BLI_edgehashIterator_new(eh);
+ med = CustomData_get_layer(&edgeData, CD_MEDGE);
+ index = CustomData_get_layer(&edgeData, CD_ORIGINDEX);
+ for(i = 0; !BLI_edgehashIterator_isDone(ehi);
+ BLI_edgehashIterator_step(ehi), ++i, ++med, ++index) {
+ BLI_edgehashIterator_getKey(ehi, (int*)&med->v1, (int*)&med->v2);
+
+ med->flag = ME_EDGEDRAW|ME_EDGERENDER;
+ *index = ORIGINDEX_NONE;
+ }
+ BLI_edgehashIterator_free(ehi);
+
+ /* free old CustomData and assign new one */
+ CustomData_free(&dm->edgeData, dm->numVertData);
+ dm->edgeData = edgeData;
+ dm->numEdgeData = numEdges;
+
+ cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE);
+
+ BLI_edgehash_free(eh, NULL);
+}
+
+void CDDM_lower_num_verts(DerivedMesh *dm, int numVerts)
+{
+ if (numVerts < dm->numVertData)
+ CustomData_free_elem(&dm->vertData, numVerts, dm->numVertData-numVerts);
+
+ dm->numVertData = numVerts;
+}
+
+void CDDM_lower_num_edges(DerivedMesh *dm, int numEdges)
+{
+ if (numEdges < dm->numEdgeData)
+ CustomData_free_elem(&dm->edgeData, numEdges, dm->numEdgeData-numEdges);
+
+ dm->numEdgeData = numEdges;
+}
+
+void CDDM_lower_num_faces(DerivedMesh *dm, int numFaces)
+{
+ if (numFaces < dm->numFaceData)
+ CustomData_free_elem(&dm->faceData, numFaces, dm->numFaceData-numFaces);
+
+ dm->numFaceData = numFaces;
+}
+
+MVert *CDDM_get_vert(DerivedMesh *dm, int index)
+{
+ return &((CDDerivedMesh*)dm)->mvert[index];
+}
+
+MEdge *CDDM_get_edge(DerivedMesh *dm, int index)
+{
+ return &((CDDerivedMesh*)dm)->medge[index];
+}
+
+MFace *CDDM_get_face(DerivedMesh *dm, int index)
+{
+ return &((CDDerivedMesh*)dm)->mface[index];
+}
+
+MVert *CDDM_get_verts(DerivedMesh *dm)
+{
+ return ((CDDerivedMesh*)dm)->mvert;
+}
+
+MEdge *CDDM_get_edges(DerivedMesh *dm)
+{
+ return ((CDDerivedMesh*)dm)->medge;
+}
+
+MFace *CDDM_get_faces(DerivedMesh *dm)
+{
+ return ((CDDerivedMesh*)dm)->mface;
+}
+
diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c
new file mode 100644
index 00000000000..83b014cdd63
--- /dev/null
+++ b/source/blender/blenkernel/intern/colortools.c
@@ -0,0 +1,719 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <string.h>
+#include <math.h>
+#include <stdlib.h>
+#include <float.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_color_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_image_types.h"
+#include "DNA_texture_types.h"
+
+#include "BKE_colortools.h"
+#include "BKE_curve.h"
+#include "BKE_global.h"
+#include "BKE_ipo.h"
+#include "BKE_image.h"
+#include "BKE_main.h"
+#include "BKE_utildefines.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_threads.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+/* ********************************* color curve ********************* */
+
+/* ***************** operations on full struct ************* */
+
+CurveMapping *curvemapping_add(int tot, float minx, float miny, float maxx, float maxy)
+{
+ CurveMapping *cumap;
+ int a;
+ float clipminx, clipminy, clipmaxx, clipmaxy;
+
+ cumap= MEM_callocN(sizeof(CurveMapping), "new curvemap");
+ cumap->flag= CUMA_DO_CLIP;
+ if(tot==4) cumap->cur= 3; /* rhms, hack for 'col' curve? */
+
+ clipminx = MIN2(minx, maxx);
+ clipminy = MIN2(miny, maxy);
+ clipmaxx = MAX2(minx, maxx);
+ clipmaxy = MAX2(miny, maxy);
+
+ BLI_init_rctf(&cumap->curr, clipminx, clipmaxx, clipminy, clipmaxy);
+ cumap->clipr= cumap->curr;
+
+ cumap->white[0]= cumap->white[1]= cumap->white[2]= 1.0f;
+ cumap->bwmul[0]= cumap->bwmul[1]= cumap->bwmul[2]= 1.0f;
+
+ for(a=0; a<tot; a++) {
+ cumap->cm[a].flag= CUMA_EXTEND_EXTRAPOLATE;
+ cumap->cm[a].totpoint= 2;
+ cumap->cm[a].curve= MEM_callocN(2*sizeof(CurveMapPoint), "curve points");
+
+ cumap->cm[a].curve[0].x= minx;
+ cumap->cm[a].curve[0].y= miny;
+ cumap->cm[a].curve[1].x= maxx;
+ cumap->cm[a].curve[1].y= maxy;
+ }
+ return cumap;
+}
+
+void curvemapping_free(CurveMapping *cumap)
+{
+ int a;
+
+ if(cumap) {
+ for(a=0; a<CM_TOT; a++) {
+ if(cumap->cm[a].curve) MEM_freeN(cumap->cm[a].curve);
+ if(cumap->cm[a].table) MEM_freeN(cumap->cm[a].table);
+ }
+ MEM_freeN(cumap);
+ }
+}
+
+CurveMapping *curvemapping_copy(CurveMapping *cumap)
+{
+ int a;
+
+ if(cumap) {
+ CurveMapping *cumapn= MEM_dupallocN(cumap);
+ for(a=0; a<CM_TOT; a++) {
+ if(cumap->cm[a].curve)
+ cumapn->cm[a].curve= MEM_dupallocN(cumap->cm[a].curve);
+ if(cumap->cm[a].table)
+ cumapn->cm[a].table= MEM_dupallocN(cumap->cm[a].table);
+ }
+ return cumapn;
+ }
+ return NULL;
+}
+
+void curvemapping_set_black_white(CurveMapping *cumap, float *black, float *white)
+{
+ int a;
+
+ if(white)
+ VECCOPY(cumap->white, white);
+ if(black)
+ VECCOPY(cumap->black, black);
+
+ for(a=0; a<3; a++) {
+ if(cumap->white[a]==cumap->black[a])
+ cumap->bwmul[a]= 0.0f;
+ else
+ cumap->bwmul[a]= 1.0f/(cumap->white[a] - cumap->black[a]);
+ }
+}
+
+/* ***************** operations on single curve ************* */
+/* ********** NOTE: requires curvemapping_changed() call after ******** */
+
+/* removes with flag set */
+void curvemap_remove(CurveMap *cuma, int flag)
+{
+ CurveMapPoint *cmp= MEM_mallocN((cuma->totpoint)*sizeof(CurveMapPoint), "curve points");
+ int a, b, removed=0;
+
+ /* well, lets keep the two outer points! */
+ cmp[0]= cuma->curve[0];
+ for(a=1, b=1; a<cuma->totpoint-1; a++) {
+ if(!(cuma->curve[a].flag & flag)) {
+ cmp[b]= cuma->curve[a];
+ b++;
+ }
+ else removed++;
+ }
+ cmp[b]= cuma->curve[a];
+
+ MEM_freeN(cuma->curve);
+ cuma->curve= cmp;
+ cuma->totpoint -= removed;
+}
+
+void curvemap_insert(CurveMap *cuma, float x, float y)
+{
+ CurveMapPoint *cmp= MEM_callocN((cuma->totpoint+1)*sizeof(CurveMapPoint), "curve points");
+ int a;
+
+ memcpy(cmp, cuma->curve, (cuma->totpoint)*sizeof(CurveMapPoint));
+ MEM_freeN(cuma->curve);
+ cuma->curve= cmp;
+
+ cuma->curve[cuma->totpoint].x= x;
+ cuma->curve[cuma->totpoint].y= y;
+ cuma->curve[cuma->totpoint].flag = CUMA_SELECT;
+ for(a=0; a<cuma->totpoint; a++, cmp++)
+ cmp->flag= 0;
+ cuma->totpoint++;
+}
+
+void curvemap_reset(CurveMap *cuma, rctf *clipr)
+{
+ cuma->totpoint= 2;
+
+ cuma->curve[0].x= clipr->xmin;
+ cuma->curve[0].y= clipr->ymin;
+ cuma->curve[0].flag= 0;
+ cuma->curve[1].x= clipr->xmax;
+ cuma->curve[1].y= clipr->ymax;
+ cuma->curve[1].flag= 0;
+
+ if(cuma->table) {
+ MEM_freeN(cuma->table);
+ cuma->table= NULL;
+ }
+}
+
+/* if type==1: vector, else auto */
+void curvemap_sethandle(CurveMap *cuma, int type)
+{
+ int a;
+
+ for(a=0; a<cuma->totpoint; a++) {
+ if(cuma->curve[a].flag & CUMA_SELECT) {
+ if(type) cuma->curve[a].flag |= CUMA_VECTOR;
+ else cuma->curve[a].flag &= ~CUMA_VECTOR;
+ }
+ }
+}
+
+/* *********************** Making the tables and display ************** */
+
+/* reduced copy of garbled calchandleNurb() code in curve.c */
+static void calchandle_curvemap(BezTriple *bezt, BezTriple *prev, BezTriple *next, int mode)
+{
+ float *p1,*p2,*p3,pt[3];
+ float dx1,dy1, dx,dy, vx,vy, len,len1,len2;
+
+ if(bezt->h1==0 && bezt->h2==0) return;
+
+ p2= bezt->vec[1];
+
+ if(prev==NULL) {
+ p3= next->vec[1];
+ pt[0]= 2*p2[0]- p3[0];
+ pt[1]= 2*p2[1]- p3[1];
+ p1= pt;
+ }
+ else p1= prev->vec[1];
+
+ if(next==NULL) {
+ p1= prev->vec[1];
+ pt[0]= 2*p2[0]- p1[0];
+ pt[1]= 2*p2[1]- p1[1];
+ p3= pt;
+ }
+ else p3= next->vec[1];
+
+ dx= p2[0]- p1[0];
+ dy= p2[1]- p1[1];
+
+ len1= (float)sqrt(dx*dx+dy*dy);
+
+ dx1= p3[0]- p2[0];
+ dy1= p3[1]- p2[1];
+
+ len2= (float)sqrt(dx1*dx1+dy1*dy1);
+
+ if(len1==0.0f) len1=1.0f;
+ if(len2==0.0f) len2=1.0f;
+
+ if(bezt->h1==HD_AUTO || bezt->h2==HD_AUTO) { /* auto */
+ vx= dx1/len2 + dx/len1;
+ vy= dy1/len2 + dy/len1;
+
+ len= 2.5614f*(float)sqrt(vx*vx + vy*vy);
+ if(len!=0.0f) {
+
+ if(bezt->h1==HD_AUTO) {
+ len1/=len;
+ *(p2-3)= *p2-vx*len1;
+ *(p2-2)= *(p2+1)-vy*len1;
+ }
+ if(bezt->h2==HD_AUTO) {
+ len2/=len;
+ *(p2+3)= *p2+vx*len2;
+ *(p2+4)= *(p2+1)+vy*len2;
+ }
+ }
+ }
+
+ if(bezt->h1==HD_VECT) { /* vector */
+ dx/=3.0;
+ dy/=3.0;
+ *(p2-3)= *p2-dx;
+ *(p2-2)= *(p2+1)-dy;
+ }
+ if(bezt->h2==HD_VECT) {
+ dx1/=3.0;
+ dy1/=3.0;
+ *(p2+3)= *p2+dx1;
+ *(p2+4)= *(p2+1)+dy1;
+ }
+}
+
+/* in X, out Y.
+ X is presumed to be outside first or last */
+static float curvemap_calc_extend(CurveMap *cuma, float x, float *first, float *last)
+{
+ if(x <= first[0]) {
+ if((cuma->flag & CUMA_EXTEND_EXTRAPOLATE)==0) {
+ /* no extrapolate */
+ return first[1];
+ }
+ else {
+ if(cuma->ext_in[0]==0.0f)
+ return first[1] + cuma->ext_in[1]*10000.0f;
+ else
+ return first[1] + cuma->ext_in[1]*(x - first[0])/cuma->ext_in[0];
+ }
+ }
+ else if(x >= last[0]) {
+ if((cuma->flag & CUMA_EXTEND_EXTRAPOLATE)==0) {
+ /* no extrapolate */
+ return last[1];
+ }
+ else {
+ if(cuma->ext_out[0]==0.0f)
+ return last[1] - cuma->ext_out[1]*10000.0f;
+ else
+ return last[1] + cuma->ext_out[1]*(x - last[0])/cuma->ext_out[0];
+ }
+ }
+ return 0.0f;
+}
+
+/* only creates a table for a single channel in CurveMapping */
+static void curvemap_make_table(CurveMap *cuma, rctf *clipr)
+{
+ CurveMapPoint *cmp= cuma->curve;
+ BezTriple *bezt;
+ float *fp, *allpoints, *lastpoint, curf, range;
+ int a, totpoint;
+
+ if(cuma->curve==NULL) return;
+
+ /* default rect also is table range */
+ cuma->mintable= clipr->xmin;
+ cuma->maxtable= clipr->xmax;
+
+ /* hrmf... we now rely on blender ipo beziers, these are more advanced */
+ bezt= MEM_callocN(cuma->totpoint*sizeof(BezTriple), "beztarr");
+
+ for(a=0; a<cuma->totpoint; a++) {
+ cuma->mintable= MIN2(cuma->mintable, cmp[a].x);
+ cuma->maxtable= MAX2(cuma->maxtable, cmp[a].x);
+ bezt[a].vec[1][0]= cmp[a].x;
+ bezt[a].vec[1][1]= cmp[a].y;
+ if(cmp[a].flag & CUMA_VECTOR)
+ bezt[a].h1= bezt[a].h2= HD_VECT;
+ else
+ bezt[a].h1= bezt[a].h2= HD_AUTO;
+ }
+
+ for(a=0; a<cuma->totpoint; a++) {
+ if(a==0)
+ calchandle_curvemap(bezt, NULL, bezt+1, 0);
+ else if(a==cuma->totpoint-1)
+ calchandle_curvemap(bezt+a, bezt+a-1, NULL, 0);
+ else
+ calchandle_curvemap(bezt+a, bezt+a-1, bezt+a+1, 0);
+ }
+
+ /* first and last handle need correction, instead of pointing to center of next/prev,
+ we let it point to the closest handle */
+ if(cuma->totpoint>2) {
+ float hlen, nlen, vec[3];
+
+ if(bezt[0].h2==HD_AUTO) {
+
+ hlen= VecLenf(bezt[0].vec[1], bezt[0].vec[2]); /* original handle length */
+ /* clip handle point */
+ VECCOPY(vec, bezt[1].vec[0]);
+ if(vec[0] < bezt[0].vec[1][0])
+ vec[0]= bezt[0].vec[1][0];
+
+ VecSubf(vec, vec, bezt[0].vec[1]);
+ nlen= VecLength(vec);
+ if(nlen>FLT_EPSILON) {
+ VecMulf(vec, hlen/nlen);
+ VecAddf(bezt[0].vec[2], vec, bezt[0].vec[1]);
+ VecSubf(bezt[0].vec[0], bezt[0].vec[1], vec);
+ }
+ }
+ a= cuma->totpoint-1;
+ if(bezt[a].h2==HD_AUTO) {
+
+ hlen= VecLenf(bezt[a].vec[1], bezt[a].vec[0]); /* original handle length */
+ /* clip handle point */
+ VECCOPY(vec, bezt[a-1].vec[2]);
+ if(vec[0] > bezt[a].vec[1][0])
+ vec[0]= bezt[a].vec[1][0];
+
+ VecSubf(vec, vec, bezt[a].vec[1]);
+ nlen= VecLength(vec);
+ if(nlen>FLT_EPSILON) {
+ VecMulf(vec, hlen/nlen);
+ VecAddf(bezt[a].vec[0], vec, bezt[a].vec[1]);
+ VecSubf(bezt[a].vec[2], bezt[a].vec[1], vec);
+ }
+ }
+ }
+ /* make the bezier curve */
+ if(cuma->table)
+ MEM_freeN(cuma->table);
+ totpoint= (cuma->totpoint-1)*CM_RESOL;
+ fp= allpoints= MEM_callocN(totpoint*2*sizeof(float), "table");
+
+ for(a=0; a<cuma->totpoint-1; a++, fp += 2*CM_RESOL) {
+ correct_bezpart(bezt[a].vec[1], bezt[a].vec[2], bezt[a+1].vec[0], bezt[a+1].vec[1]);
+ forward_diff_bezier(bezt[a].vec[1][0], bezt[a].vec[2][0], bezt[a+1].vec[0][0], bezt[a+1].vec[1][0], fp, CM_RESOL-1, 2);
+ forward_diff_bezier(bezt[a].vec[1][1], bezt[a].vec[2][1], bezt[a+1].vec[0][1], bezt[a+1].vec[1][1], fp+1, CM_RESOL-1, 2);
+ }
+
+ /* store first and last handle for extrapolation, unit length */
+ cuma->ext_in[0]= bezt[0].vec[0][0] - bezt[0].vec[1][0];
+ cuma->ext_in[1]= bezt[0].vec[0][1] - bezt[0].vec[1][1];
+ range= sqrt(cuma->ext_in[0]*cuma->ext_in[0] + cuma->ext_in[1]*cuma->ext_in[1]);
+ cuma->ext_in[0]/= range;
+ cuma->ext_in[1]/= range;
+
+ a= cuma->totpoint-1;
+ cuma->ext_out[0]= bezt[a].vec[1][0] - bezt[a].vec[2][0];
+ cuma->ext_out[1]= bezt[a].vec[1][1] - bezt[a].vec[2][1];
+ range= sqrt(cuma->ext_out[0]*cuma->ext_out[0] + cuma->ext_out[1]*cuma->ext_out[1]);
+ cuma->ext_out[0]/= range;
+ cuma->ext_out[1]/= range;
+
+ /* cleanup */
+ MEM_freeN(bezt);
+
+ range= CM_TABLEDIV*(cuma->maxtable - cuma->mintable);
+ cuma->range= 1.0f/range;
+
+ /* now make a table with CM_TABLE equal x distances */
+ fp= allpoints;
+ lastpoint= allpoints + 2*(totpoint-1);
+ cmp= MEM_callocN((CM_TABLE+1)*sizeof(CurveMapPoint), "dist table");
+
+ for(a=0; a<=CM_TABLE; a++) {
+ curf= cuma->mintable + range*(float)a;
+ cmp[a].x= curf;
+
+ /* get the first x coordinate larger than curf */
+ while(curf >= fp[0] && fp!=lastpoint) {
+ fp+=2;
+ }
+ if(fp==allpoints || (curf >= fp[0] && fp==lastpoint))
+ cmp[a].y= curvemap_calc_extend(cuma, curf, allpoints, lastpoint);
+ else {
+ float fac1= fp[0] - fp[-2];
+ float fac2= fp[0] - curf;
+ if(fac1 > FLT_EPSILON)
+ fac1= fac2/fac1;
+ else
+ fac1= 0.0f;
+ cmp[a].y= fac1*fp[-1] + (1.0f-fac1)*fp[1];
+ }
+ }
+
+ MEM_freeN(allpoints);
+ cuma->table= cmp;
+}
+
+/* call when you do images etc, needs restore too. also verifies tables */
+/* it uses a flag to prevent premul or free to happen twice */
+void curvemapping_premultiply(CurveMapping *cumap, int restore)
+{
+ int a;
+
+ if(restore) {
+ if(cumap->flag & CUMA_PREMULLED) {
+ for(a=0; a<3; a++) {
+ MEM_freeN(cumap->cm[a].table);
+ cumap->cm[a].table= cumap->cm[a].premultable;
+ cumap->cm[a].premultable= NULL;
+ }
+
+ cumap->flag &= ~CUMA_PREMULLED;
+ }
+ }
+ else {
+ if((cumap->flag & CUMA_PREMULLED)==0) {
+ /* verify and copy */
+ for(a=0; a<3; a++) {
+ if(cumap->cm[a].table==NULL)
+ curvemap_make_table(cumap->cm+a, &cumap->clipr);
+ cumap->cm[a].premultable= cumap->cm[a].table;
+ cumap->cm[a].table= MEM_mallocN((CM_TABLE+1)*sizeof(CurveMapPoint), "premul table");
+ memcpy(cumap->cm[a].table, cumap->cm[a].premultable, (CM_TABLE+1)*sizeof(CurveMapPoint));
+ }
+
+ if(cumap->cm[3].table==NULL)
+ curvemap_make_table(cumap->cm+3, &cumap->clipr);
+
+ /* premul */
+ for(a=0; a<3; a++) {
+ int b;
+ for(b=0; b<=CM_TABLE; b++) {
+ cumap->cm[a].table[b].y= curvemap_evaluateF(cumap->cm+3, cumap->cm[a].table[b].y);
+ }
+ }
+
+ cumap->flag |= CUMA_PREMULLED;
+ }
+ }
+}
+
+static int sort_curvepoints(const void *a1, const void *a2)
+{
+ const struct CurveMapPoint *x1=a1, *x2=a2;
+
+ if( x1->x > x2->x ) return 1;
+ else if( x1->x < x2->x) return -1;
+ return 0;
+}
+
+/* ************************ more CurveMapping calls *************** */
+
+/* note; only does current curvemap! */
+void curvemapping_changed(CurveMapping *cumap, int rem_doubles)
+{
+ CurveMap *cuma= cumap->cm+cumap->cur;
+ CurveMapPoint *cmp= cuma->curve;
+ rctf *clipr= &cumap->clipr;
+ float thresh= 0.01f*(clipr->xmax - clipr->xmin);
+ float dx= 0.0f, dy= 0.0f;
+ int a;
+
+ /* clamp with clip */
+ if(cumap->flag & CUMA_DO_CLIP) {
+ for(a=0; a<cuma->totpoint; a++) {
+ if(cmp[a].flag & CUMA_SELECT) {
+ if(cmp[a].x < clipr->xmin)
+ dx= MIN2(dx, cmp[a].x - clipr->xmin);
+ else if(cmp[a].x > clipr->xmax)
+ dx= MAX2(dx, cmp[a].x - clipr->xmax);
+ if(cmp[a].y < clipr->ymin)
+ dy= MIN2(dy, cmp[a].y - clipr->ymin);
+ else if(cmp[a].y > clipr->ymax)
+ dy= MAX2(dy, cmp[a].y - clipr->ymax);
+ }
+ }
+ for(a=0; a<cuma->totpoint; a++) {
+ if(cmp[a].flag & CUMA_SELECT) {
+ cmp[a].x -= dx;
+ cmp[a].y -= dy;
+ }
+ }
+ }
+
+
+ qsort(cmp, cuma->totpoint, sizeof(CurveMapPoint), sort_curvepoints);
+
+ /* remove doubles, threshold set on 1% of default range */
+ if(rem_doubles && cuma->totpoint>2) {
+ for(a=0; a<cuma->totpoint-1; a++) {
+ dx= cmp[a].x - cmp[a+1].x;
+ dy= cmp[a].y - cmp[a+1].y;
+ if( sqrt(dx*dx + dy*dy) < thresh ) {
+ if(a==0) {
+ cmp[a+1].flag|= 2;
+ if(cmp[a+1].flag & CUMA_SELECT)
+ cmp[a].flag |= CUMA_SELECT;
+ }
+ else {
+ cmp[a].flag|= 2;
+ if(cmp[a].flag & CUMA_SELECT)
+ cmp[a+1].flag |= CUMA_SELECT;
+ }
+ break; /* we assume 1 deletion per edit is ok */
+ }
+ }
+ if(a != cuma->totpoint-1)
+ curvemap_remove(cuma, 2);
+ }
+ curvemap_make_table(cuma, clipr);
+}
+
+/* table should be verified */
+float curvemap_evaluateF(CurveMap *cuma, float value)
+{
+ float fi;
+ int i;
+
+ /* index in table */
+ fi= (value-cuma->mintable)*cuma->range;
+ i= (int)fi;
+
+ if(fi<0.0f || fi>cuma->range)
+ return curvemap_calc_extend(cuma, value, &cuma->table[0].x, &cuma->table[CM_TABLE].x);
+ else {
+ if(i<0) return cuma->table[0].y;
+ if(i>=CM_TABLE) return cuma->table[CM_TABLE].y;
+
+ fi= fi-(float)i;
+ return (1.0f-fi)*cuma->table[i].y + (fi)*cuma->table[i+1].y;
+ }
+}
+
+/* works with curve 'cur' */
+float curvemapping_evaluateF(CurveMapping *cumap, int cur, float value)
+{
+ CurveMap *cuma= cumap->cm+cur;
+
+ /* allocate or bail out */
+ if(cuma->table==NULL) {
+ curvemap_make_table(cuma, &cumap->clipr);
+ if(cuma->table==NULL)
+ return value;
+ }
+ return curvemap_evaluateF(cuma, value);
+}
+
+/* vector case */
+void curvemapping_evaluate3F(CurveMapping *cumap, float *vecout, const float *vecin)
+{
+ vecout[0]= curvemapping_evaluateF(cumap, 0, vecin[0]);
+ vecout[1]= curvemapping_evaluateF(cumap, 1, vecin[1]);
+ vecout[2]= curvemapping_evaluateF(cumap, 2, vecin[2]);
+}
+
+/* RGB case, no black/white points, no premult */
+void curvemapping_evaluateRGBF(CurveMapping *cumap, float *vecout, const float *vecin)
+{
+ vecout[0]= curvemapping_evaluateF(cumap, 0, curvemapping_evaluateF(cumap, 3, vecin[0]));
+ vecout[1]= curvemapping_evaluateF(cumap, 1, curvemapping_evaluateF(cumap, 3, vecin[1]));
+ vecout[2]= curvemapping_evaluateF(cumap, 2, curvemapping_evaluateF(cumap, 3, vecin[2]));
+}
+
+
+/* RGB with black/white points and premult. tables are checked */
+void curvemapping_evaluate_premulRGBF(CurveMapping *cumap, float *vecout, const float *vecin)
+{
+ float fac;
+
+ fac= (vecin[0] - cumap->black[0])*cumap->bwmul[0];
+ vecout[0]= curvemap_evaluateF(cumap->cm, fac);
+
+ fac= (vecin[1] - cumap->black[1])*cumap->bwmul[1];
+ vecout[1]= curvemap_evaluateF(cumap->cm+1, fac);
+
+ fac= (vecin[2] - cumap->black[2])*cumap->bwmul[2];
+ vecout[2]= curvemap_evaluateF(cumap->cm+2, fac);
+}
+
+#define FTOCHAR(val) val<=0.0f?0: (val>=1.0f?255: (char)(255.0f*val))
+
+void curvemapping_do_ibuf(CurveMapping *cumap, ImBuf *ibuf)
+{
+ int pixel;
+
+ if(ibuf==NULL)
+ return;
+ if(ibuf->rect_float==NULL)
+ IMB_float_from_rect(ibuf);
+ else if(ibuf->rect==NULL)
+ imb_addrectImBuf(ibuf);
+
+ curvemapping_premultiply(cumap, 0);
+
+ if(ibuf->rect_float && ibuf->rect) {
+ float *pixf= ibuf->rect_float;
+ float col[3];
+ int stride= 4;
+ char *pixc= (char *)ibuf->rect;
+
+ if(ibuf->channels)
+ stride= ibuf->channels;
+
+ for(pixel= ibuf->x*ibuf->y; pixel>0; pixel--, pixf+=stride, pixc+=4) {
+ if(stride<3) {
+ col[0]= curvemap_evaluateF(cumap->cm, *pixf);
+ pixc[1]= pixc[2]= pixc[3]= pixc[0]= FTOCHAR(col[0]);
+ }
+ else {
+ curvemapping_evaluate_premulRGBF(cumap, col, pixf);
+ pixc[0]= FTOCHAR(col[0]);
+ pixc[1]= FTOCHAR(col[1]);
+ pixc[2]= FTOCHAR(col[2]);
+ if(stride>3)
+ pixc[3]= FTOCHAR(pixf[3]);
+ else
+ pixc[3]= 255;
+ }
+ }
+ }
+
+ curvemapping_premultiply(cumap, 1);
+}
+
+int curvemapping_RGBA_does_something(CurveMapping *cumap)
+{
+ int a;
+
+ if(cumap->black[0]!=0.0f) return 1;
+ if(cumap->black[1]!=0.0f) return 1;
+ if(cumap->black[2]!=0.0f) return 1;
+ if(cumap->white[0]!=1.0f) return 1;
+ if(cumap->white[1]!=1.0f) return 1;
+ if(cumap->white[2]!=1.0f) return 1;
+
+ for(a=0; a<CM_TOT; a++) {
+ if(cumap->cm[a].curve) {
+ if(cumap->cm[a].totpoint!=2) return 1;
+
+ if(cumap->cm[a].curve[0].x != 0.0f) return 1;
+ if(cumap->cm[a].curve[0].y != 0.0f) return 1;
+ if(cumap->cm[a].curve[1].x != 1.0f) return 1;
+ if(cumap->cm[a].curve[1].y != 1.0f) return 1;
+ }
+ }
+ return 0;
+}
+
+void curvemapping_initialize(CurveMapping *cumap)
+{
+ int a;
+
+ if(cumap==NULL) return;
+
+ for(a=0; a<CM_TOT; a++) {
+ if(cumap->cm[a].table==NULL)
+ curvemap_make_table(cumap->cm+a, &cumap->clipr);
+ }
+}
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
new file mode 100644
index 00000000000..f50cb2c6be0
--- /dev/null
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -0,0 +1,3422 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): 2007, Joshua Leung, major recode
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+#include "nla.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "DNA_armature_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_object_types.h"
+#include "DNA_action_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_text_types.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_action.h"
+#include "BKE_anim.h" /* for the curve calculation part */
+#include "BKE_armature.h"
+#include "BKE_blender.h"
+#include "BKE_constraint.h"
+#include "BKE_displist.h"
+#include "BKE_deform.h"
+#include "BKE_DerivedMesh.h" /* for geometry targets */
+#include "BKE_cdderivedmesh.h" /* for geometry targets */
+#include "BKE_object.h"
+#include "BKE_ipo.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_idprop.h"
+
+
+#include "BPY_extern.h"
+
+#include "blendef.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+
+/* ******************* Constraint Channels ********************** */
+/* Constraint Channels exist in one of two places:
+ * - Under Action Channels in an Action (act->chanbase->achan->constraintChannels)
+ * - Under Object without object-level action yet (ob->constraintChannels)
+ *
+ * The main purpose that constraint channels serve is to act as a link
+ * between an IPO-block which
+ */
+
+/* ------------ Data Management ----------- */
+
+/* Free constraint channels, and reduce the number of users of the related ipo-blocks */
+void free_constraint_channels (ListBase *chanbase)
+{
+ bConstraintChannel *chan;
+
+ for (chan=chanbase->first; chan; chan=chan->next) {
+ if (chan->ipo) {
+ chan->ipo->id.us--;
+ }
+ }
+
+ BLI_freelistN(chanbase);
+}
+
+/* Make a copy of the constraint channels from dst to src, and also give the
+ * new constraint channels their own copy of the original's IPO.
+ */
+void copy_constraint_channels (ListBase *dst, ListBase *src)
+{
+ bConstraintChannel *dchan, *schan;
+
+ dst->first = dst->last = NULL;
+ duplicatelist(dst, src);
+
+ for (dchan=dst->first, schan=src->first; dchan; dchan=dchan->next, schan=schan->next) {
+ dchan->ipo = copy_ipo(schan->ipo);
+ }
+}
+
+/* Make a copy of the constraint channels from dst to src, but make the
+ * new constraint channels use the same IPO-data as their twin.
+ */
+void clone_constraint_channels (ListBase *dst, ListBase *src)
+{
+ bConstraintChannel *dchan, *schan;
+
+ dst->first = dst->last = NULL;
+ duplicatelist(dst, src);
+
+ for (dchan=dst->first, schan=src->first; dchan; dchan=dchan->next, schan=schan->next) {
+ id_us_plus((ID *)dchan->ipo);
+ }
+}
+
+/* ------------- Constraint Channel Tools ------------ */
+
+/* Find the constraint channel with a given name */
+bConstraintChannel *get_constraint_channel (ListBase *list, const char name[])
+{
+ bConstraintChannel *chan;
+
+ for (chan = list->first; chan; chan=chan->next) {
+ if (!strcmp(name, chan->name)) {
+ return chan;
+ }
+ }
+
+ return NULL;
+}
+
+/* Find or create a new constraint channel */
+bConstraintChannel *verify_constraint_channel (ListBase *list, const char name[])
+{
+ bConstraintChannel *chan;
+
+ chan= get_constraint_channel(list, name);
+
+ if (chan == NULL) {
+ chan= MEM_callocN(sizeof(bConstraintChannel), "new constraint channel");
+ BLI_addtail(list, chan);
+ strcpy(chan->name, name);
+ }
+
+ return chan;
+}
+
+/* --------- Constraint Channel Evaluation/Execution --------- */
+
+/* IPO-system call: calculate IPO-block for constraint channels, and flush that
+ * info onto the corresponding constraint.
+ */
+void do_constraint_channels (ListBase *conbase, ListBase *chanbase, float ctime, short onlydrivers)
+{
+ bConstraint *con;
+ bConstraintChannel *chan;
+ IpoCurve *icu= NULL;
+
+ /* for each Constraint, calculate its Influence from the corresponding ConstraintChannel */
+ for (con=conbase->first; con; con=con->next) {
+ chan = get_constraint_channel(chanbase, con->name);
+
+ if (chan && chan->ipo) {
+ calc_ipo(chan->ipo, ctime);
+
+ for (icu=chan->ipo->curve.first; icu; icu=icu->next) {
+ if (!onlydrivers || icu->driver) {
+ switch (icu->adrcode) {
+ case CO_ENFORCE:
+ {
+ /* Influence is clamped to 0.0f -> 1.0f range */
+ con->enforce = CLAMPIS(icu->curval, 0.0f, 1.0f);
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+/* ************************ Constraints - General Utilities *************************** */
+/* These functions here don't act on any specific constraints, and are therefore should/will
+ * not require any of the special function-pointers afforded by the relevant constraint
+ * type-info structs.
+ */
+
+/* -------------- Naming -------------- */
+
+/* Find the first available, non-duplicate name for a given constraint */
+void unique_constraint_name (bConstraint *con, ListBase *list)
+{
+ bConstraint *curcon;
+ char tempname[64];
+ int number = 1, exists = 0;
+ char *dot;
+
+ /* See if we are given an empty string */
+ if (con->name[0] == '\0') {
+ /* give it default name first */
+ strcpy(con->name, "Const");
+ }
+
+ /* See if we even need to do this */
+ for (curcon = list->first; curcon; curcon=curcon->next) {
+ if (curcon != con) {
+ if (!strcmp(curcon->name, con->name)) {
+ exists = 1;
+ break;
+ }
+ }
+ }
+
+ if (exists == 0)
+ return;
+
+ /* Strip off the suffix */
+ dot = strchr(con->name, '.');
+ if (dot)
+ *dot=0;
+
+ for (number = 1; number <= 999; number++) {
+ sprintf(tempname, "%s.%03d", con->name, number);
+
+ exists = 0;
+ for (curcon=list->first; curcon; curcon=curcon->next) {
+ if (con != curcon) {
+ if (strcmp(curcon->name, tempname)==0) {
+ exists = 1;
+ break;
+ }
+ }
+ }
+ if (exists == 0) {
+ strcpy(con->name, tempname);
+ return;
+ }
+ }
+}
+
+/* ----------------- Evaluation Loop Preparation --------------- */
+
+/* package an object/bone for use in constraint evaluation */
+/* This function MEM_calloc's a bConstraintOb struct, that will need to be freed after evaluation */
+bConstraintOb *constraints_make_evalob (Object *ob, void *subdata, short datatype)
+{
+ bConstraintOb *cob;
+
+ /* create regardless of whether we have any data! */
+ cob= MEM_callocN(sizeof(bConstraintOb), "bConstraintOb");
+
+ /* based on type of available data */
+ switch (datatype) {
+ case CONSTRAINT_OBTYPE_OBJECT:
+ {
+ /* disregard subdata... calloc should set other values right */
+ if (ob) {
+ cob->ob = ob;
+ cob->type = datatype;
+ Mat4CpyMat4(cob->matrix, ob->obmat);
+ }
+ else
+ Mat4One(cob->matrix);
+
+ Mat4CpyMat4(cob->startmat, cob->matrix);
+ }
+ break;
+ case CONSTRAINT_OBTYPE_BONE:
+ {
+ /* only set if we have valid bone, otherwise default */
+ if (ob && subdata) {
+ cob->ob = ob;
+ cob->pchan = (bPoseChannel *)subdata;
+ cob->type = datatype;
+
+ /* matrix in world-space */
+ Mat4MulMat4(cob->matrix, cob->pchan->pose_mat, ob->obmat);
+ }
+ else
+ Mat4One(cob->matrix);
+
+ Mat4CpyMat4(cob->startmat, cob->matrix);
+ }
+ break;
+
+ default: /* other types not yet handled */
+ Mat4One(cob->matrix);
+ Mat4One(cob->startmat);
+ break;
+ }
+
+ return cob;
+}
+
+/* cleanup after constraint evaluation */
+void constraints_clear_evalob (bConstraintOb *cob)
+{
+ float delta[4][4], imat[4][4];
+
+ /* prevent crashes */
+ if (cob == NULL)
+ return;
+
+ /* calculate delta of constraints evaluation */
+ Mat4Invert(imat, cob->startmat);
+ Mat4MulMat4(delta, cob->matrix, imat);
+
+ /* copy matrices back to source */
+ switch (cob->type) {
+ case CONSTRAINT_OBTYPE_OBJECT:
+ {
+ /* cob->ob might not exist! */
+ if (cob->ob) {
+ /* copy new ob-matrix back to owner */
+ Mat4CpyMat4(cob->ob->obmat, cob->matrix);
+
+ /* copy inverse of delta back to owner */
+ Mat4Invert(cob->ob->constinv, delta);
+ }
+ }
+ break;
+ case CONSTRAINT_OBTYPE_BONE:
+ {
+ /* cob->ob or cob->pchan might not exist */
+ if (cob->ob && cob->pchan) {
+ /* copy new pose-matrix back to owner */
+ Mat4MulMat4(cob->pchan->pose_mat, cob->matrix, cob->ob->imat);
+
+ /* copy inverse of delta back to owner */
+ Mat4Invert(cob->pchan->constinv, delta);
+ }
+ }
+ break;
+ }
+
+ /* free tempolary struct */
+ MEM_freeN(cob);
+}
+
+/* -------------- Space-Conversion API -------------- */
+
+/* This function is responsible for the correct transformations/conversions
+ * of a matrix from one space to another for constraint evaluation.
+ * For now, this is only implemented for Objects and PoseChannels.
+ */
+void constraint_mat_convertspace (Object *ob, bPoseChannel *pchan, float mat[][4], short from, short to)
+{
+ float tempmat[4][4];
+ float diff_mat[4][4];
+ float imat[4][4];
+
+ /* prevent crashes in these unlikely events */
+ if (ob==NULL || mat==NULL) return;
+ /* optimise trick - check if need to do anything */
+ if (from == to) return;
+
+ /* are we dealing with pose-channels or objects */
+ if (pchan) {
+ /* pose channels */
+ switch (from) {
+ case CONSTRAINT_SPACE_WORLD: /* ---------- FROM WORLDSPACE ---------- */
+ {
+ /* world to pose */
+ if (to==CONSTRAINT_SPACE_POSE || to==CONSTRAINT_SPACE_LOCAL || to==CONSTRAINT_SPACE_PARLOCAL) {
+ Mat4Invert(imat, ob->obmat);
+ Mat4CpyMat4(tempmat, mat);
+ Mat4MulMat4(mat, tempmat, imat);
+ }
+
+ /* pose to local */
+ if (to == CONSTRAINT_SPACE_LOCAL) {
+ /* call self with slightly different values */
+ constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to);
+ }
+ /* pose to local + parent */
+ else if (to == CONSTRAINT_SPACE_PARLOCAL) {
+ /* call self with slightly different values */
+ constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to);
+ }
+ }
+ break;
+ case CONSTRAINT_SPACE_POSE: /* ---------- FROM POSESPACE ---------- */
+ {
+ /* pose to world */
+ if (to == CONSTRAINT_SPACE_WORLD) {
+ Mat4CpyMat4(tempmat, mat);
+ Mat4MulMat4(mat, tempmat, ob->obmat);
+ }
+ /* pose to local */
+ else if (to == CONSTRAINT_SPACE_LOCAL) {
+ if (pchan->bone) {
+ if (pchan->parent) {
+ float offs_bone[4][4];
+
+ /* construct offs_bone the same way it is done in armature.c */
+ Mat4CpyMat3(offs_bone, pchan->bone->bone_mat);
+ VECCOPY(offs_bone[3], pchan->bone->head);
+ offs_bone[3][1]+= pchan->bone->parent->length;
+
+ if (pchan->bone->flag & BONE_HINGE) {
+ /* pose_mat = par_pose-space_location * chan_mat */
+ float tmat[4][4];
+
+ /* the rotation of the parent restposition */
+ Mat4CpyMat4(tmat, pchan->bone->parent->arm_mat);
+
+ /* the location of actual parent transform */
+ VECCOPY(tmat[3], offs_bone[3]);
+ offs_bone[3][0]= offs_bone[3][1]= offs_bone[3][2]= 0.0f;
+ Mat4MulVecfl(pchan->parent->pose_mat, tmat[3]);
+
+ Mat4MulMat4(diff_mat, offs_bone, tmat);
+ Mat4Invert(imat, diff_mat);
+ }
+ else {
+ /* pose_mat = par_pose_mat * bone_mat * chan_mat */
+ Mat4MulMat4(diff_mat, offs_bone, pchan->parent->pose_mat);
+ Mat4Invert(imat, diff_mat);
+ }
+ }
+ else {
+ /* pose_mat = chan_mat * arm_mat */
+ Mat4Invert(imat, pchan->bone->arm_mat);
+ }
+
+ Mat4CpyMat4(tempmat, mat);
+ Mat4MulMat4(mat, tempmat, imat);
+ }
+ }
+ /* pose to local with parent */
+ else if (to == CONSTRAINT_SPACE_PARLOCAL) {
+ if (pchan->bone) {
+ Mat4Invert(imat, pchan->bone->arm_mat);
+ Mat4CpyMat4(tempmat, mat);
+ Mat4MulMat4(mat, tempmat, imat);
+ }
+ }
+ }
+ break;
+ case CONSTRAINT_SPACE_LOCAL: /* ------------ FROM LOCALSPACE --------- */
+ {
+ /* local to pose */
+ if (to==CONSTRAINT_SPACE_POSE || to==CONSTRAINT_SPACE_WORLD) {
+ /* do inverse procedure that was done for pose to local */
+ if (pchan->bone) {
+ /* we need the posespace_matrix = local_matrix + (parent_posespace_matrix + restpos) */
+ if (pchan->parent) {
+ float offs_bone[4][4];
+
+ /* construct offs_bone the same way it is done in armature.c */
+ Mat4CpyMat3(offs_bone, pchan->bone->bone_mat);
+ VECCOPY(offs_bone[3], pchan->bone->head);
+ offs_bone[3][1]+= pchan->bone->parent->length;
+
+ if (pchan->bone->flag & BONE_HINGE) {
+ /* pose_mat = par_pose-space_location * chan_mat */
+ float tmat[4][4];
+
+ /* the rotation of the parent restposition */
+ Mat4CpyMat4(tmat, pchan->bone->parent->arm_mat);
+
+ /* the location of actual parent transform */
+ VECCOPY(tmat[3], offs_bone[3]);
+ offs_bone[3][0]= offs_bone[3][1]= offs_bone[3][2]= 0.0f;
+ Mat4MulVecfl(pchan->parent->pose_mat, tmat[3]);
+
+ Mat4MulMat4(diff_mat, offs_bone, tmat);
+ Mat4CpyMat4(tempmat, mat);
+ Mat4MulMat4(mat, tempmat, diff_mat);
+ }
+ else {
+ /* pose_mat = par_pose_mat * bone_mat * chan_mat */
+ Mat4MulMat4(diff_mat, offs_bone, pchan->parent->pose_mat);
+ Mat4CpyMat4(tempmat, mat);
+ Mat4MulMat4(mat, tempmat, diff_mat);
+ }
+ }
+ else {
+ Mat4CpyMat4(diff_mat, pchan->bone->arm_mat);
+
+ Mat4CpyMat4(tempmat, mat);
+ Mat4MulMat4(mat, tempmat, diff_mat);
+ }
+ }
+ }
+ /* local to world */
+ if (to == CONSTRAINT_SPACE_WORLD) {
+ /* call self with slightly different values */
+ constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to);
+ }
+ }
+ break;
+ case CONSTRAINT_SPACE_PARLOCAL: /* -------------- FROM LOCAL WITH PARENT ---------- */
+ {
+ /* local to pose */
+ if (to==CONSTRAINT_SPACE_POSE || to==CONSTRAINT_SPACE_WORLD) {
+ if (pchan->bone) {
+ Mat4CpyMat4(diff_mat, pchan->bone->arm_mat);
+ Mat4CpyMat4(tempmat, mat);
+ Mat4MulMat4(mat, diff_mat, tempmat);
+ }
+ }
+ /* local to world */
+ if (to == CONSTRAINT_SPACE_WORLD) {
+ /* call self with slightly different values */
+ constraint_mat_convertspace(ob, pchan, mat, CONSTRAINT_SPACE_POSE, to);
+ }
+ }
+ break;
+ }
+ }
+ else {
+ /* objects */
+ if (from==CONSTRAINT_SPACE_WORLD && to==CONSTRAINT_SPACE_LOCAL) {
+ /* check if object has a parent - otherwise this won't work */
+ if (ob->parent) {
+ /* 'subtract' parent's effects from owner */
+ Mat4MulMat4(diff_mat, ob->parentinv, ob->parent->obmat);
+ Mat4Invert(imat, diff_mat);
+ Mat4CpyMat4(tempmat, mat);
+ Mat4MulMat4(mat, tempmat, imat);
+ }
+ }
+ else if (from==CONSTRAINT_SPACE_LOCAL && to==CONSTRAINT_SPACE_WORLD) {
+ /* check that object has a parent - otherwise this won't work */
+ if (ob->parent) {
+ /* 'add' parent's effect back to owner */
+ Mat4CpyMat4(tempmat, mat);
+ Mat4MulMat4(diff_mat, ob->parentinv, ob->parent->obmat);
+ Mat4MulMat4(mat, tempmat, diff_mat);
+ }
+ }
+ }
+}
+
+/* ------------ General Target Matrix Tools ---------- */
+
+/* function that sets the given matrix based on given vertex group in mesh */
+static void contarget_get_mesh_mat (Object *ob, char *substring, float mat[][4])
+{
+ DerivedMesh *dm;
+ float vec[3] = {0.0f, 0.0f, 0.0f}, tvec[3];
+ float normal[3] = {0.0f, 0.0f, 0.0f}, plane[3];
+ float imat[3][3], tmat[3][3];
+ int dgroup;
+
+ /* initialize target matrix using target matrix */
+ Mat4CpyMat4(mat, ob->obmat);
+
+ /* get index of vertex group */
+ dgroup = get_named_vertexgroup_num(ob, substring);
+ if (dgroup < 0) return;
+
+ /* get DerivedMesh */
+ if (G.obedit && G.editMesh) {
+ /* we are in editmode, so get a special derived mesh */
+ dm = CDDM_from_editmesh(G.editMesh, ob->data);
+ }
+ else {
+ /* when not in EditMode, this should exist */
+ dm = (DerivedMesh *)ob->derivedFinal;
+ }
+
+ /* only continue if there's a valid DerivedMesh */
+ if (dm) {
+ MDeformVert *dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
+ int *index = (int *)dm->getVertDataArray(dm, CD_ORIGINDEX);
+ int numVerts = dm->getNumVerts(dm);
+ int i, j, count = 0;
+ float co[3], nor[3];
+
+ /* check that dvert and index are valid pointers (just in case) */
+ if (dvert && index) {
+ /* get the average of all verts with that are in the vertex-group */
+ for (i = 0; i < numVerts; i++, index++) {
+ for (j = 0; j < dvert[i].totweight; j++) {
+ /* does this vertex belong to nominated vertex group? */
+ if (dvert[i].dw[j].def_nr == dgroup) {
+ dm->getVertCo(dm, i, co);
+ dm->getVertNo(dm, i, nor);
+ VecAddf(vec, vec, co);
+ VecAddf(normal, normal, nor);
+ count++;
+ break;
+ }
+
+ }
+ }
+
+
+ /* calculate averages of normal and coordinates */
+ if (count > 0) {
+ VecMulf(vec, 1.0f / count);
+ VecMulf(normal, 1.0f / count);
+ }
+
+
+ /* derive the rotation from the average normal:
+ * - code taken from transform_manipulator.c,
+ * calc_manipulator_stats, V3D_MANIP_NORMAL case
+ */
+ /* we need the transpose of the inverse for a normal... */
+ Mat3CpyMat4(imat, ob->obmat);
+
+ Mat3Inv(tmat, imat);
+ Mat3Transp(tmat);
+ Mat3MulVecfl(tmat, normal);
+
+ Normalize(normal);
+ VECCOPY(plane, tmat[1]);
+
+ VECCOPY(tmat[2], normal);
+ Crossf(tmat[0], normal, plane);
+ Crossf(tmat[1], tmat[2], tmat[0]);
+
+ Mat4CpyMat3(mat, tmat);
+ Mat4Ortho(mat);
+
+
+ /* apply the average coordinate as the new location */
+ VecMat4MulVecfl(tvec, ob->obmat, vec);
+ VECCOPY(mat[3], tvec);
+ }
+ }
+
+ /* free temporary DerivedMesh created (in EditMode case) */
+ if (G.editMesh) {
+ if (dm) dm->release(dm);
+ }
+}
+
+/* function that sets the given matrix based on given vertex group in lattice */
+static void contarget_get_lattice_mat (Object *ob, char *substring, float mat[][4])
+{
+ Lattice *lt= (Lattice *)ob->data;
+
+ DispList *dl = find_displist(&ob->disp, DL_VERTS);
+ float *co = dl?dl->verts:NULL;
+ BPoint *bp = lt->def;
+
+ MDeformVert *dvert = lt->dvert;
+ int tot_verts= lt->pntsu*lt->pntsv*lt->pntsw;
+ float vec[3]= {0.0f, 0.0f, 0.0f}, tvec[3];
+ int dgroup=0, grouped=0;
+ int i, n;
+
+ /* initialize target matrix using target matrix */
+ Mat4CpyMat4(mat, ob->obmat);
+
+ /* get index of vertex group */
+ dgroup = get_named_vertexgroup_num(ob, substring);
+ if (dgroup < 0) return;
+ if (dvert == NULL) return;
+
+ /* 1. Loop through control-points checking if in nominated vertex-group.
+ * 2. If it is, add it to vec to find the average point.
+ */
+ for (i=0; i < tot_verts; i++, dvert++) {
+ for (n= 0; n < dvert->totweight; n++) {
+ /* found match - vert is in vgroup */
+ if (dvert->dw[n].def_nr == dgroup) {
+ /* copy coordinates of point to temporary vector, then add to find average */
+ if (co)
+ memcpy(tvec, co, 3*sizeof(float));
+ else
+ memcpy(tvec, bp->vec, 3*sizeof(float));
+
+ VecAddf(vec, vec, tvec);
+ grouped++;
+
+ break;
+ }
+ }
+
+ /* advance pointer to coordinate data */
+ if (co) co+= 3;
+ else bp++;
+ }
+
+ /* find average location, then multiply by ob->obmat to find world-space location */
+ if (grouped)
+ VecMulf(vec, 1.0f / grouped);
+ VecMat4MulVecfl(tvec, ob->obmat, vec);
+
+ /* copy new location to matrix */
+ VECCOPY(mat[3], tvec);
+}
+
+/* generic function to get the appropriate matrix for most target cases */
+/* The cases where the target can be object data have not been implemented */
+static void constraint_target_to_mat4 (Object *ob, char *substring, float mat[][4], short from, short to)
+{
+ /* Case OBJECT */
+ if (!strlen(substring)) {
+ Mat4CpyMat4(mat, ob->obmat);
+ constraint_mat_convertspace(ob, NULL, mat, from, to);
+ }
+ /* Case VERTEXGROUP */
+ /* Current method just takes the average location of all the points in the
+ * VertexGroup, and uses that as the location value of the targets. Where
+ * possible, the orientation will also be calculated, by calculating an
+ * 'average' vertex normal, and deriving the rotaation from that.
+ *
+ * NOTE: EditMode is not currently supported, and will most likely remain that
+ * way as constraints can only really affect things on object/bone level.
+ */
+ else if (ob->type == OB_MESH) {
+ contarget_get_mesh_mat(ob, substring, mat);
+ constraint_mat_convertspace(ob, NULL, mat, from, to);
+ }
+ else if (ob->type == OB_LATTICE) {
+ contarget_get_lattice_mat(ob, substring, mat);
+ constraint_mat_convertspace(ob, NULL, mat, from, to);
+ }
+ /* Case BONE */
+ else {
+ bPoseChannel *pchan;
+
+ pchan = get_pose_channel(ob->pose, substring);
+ if (pchan) {
+ /* Multiply the PoseSpace accumulation/final matrix for this
+ * PoseChannel by the Armature Object's Matrix to get a worldspace
+ * matrix.
+ */
+ Mat4MulMat4(mat, pchan->pose_mat, ob->obmat);
+ }
+ else
+ Mat4CpyMat4(mat, ob->obmat);
+
+ /* convert matrix space as required */
+ constraint_mat_convertspace(ob, pchan, mat, from, to);
+ }
+}
+
+/* ************************* Specific Constraints ***************************** */
+/* Each constraint defines a set of functions, which will be called at the appropriate
+ * times. In addition to this, each constraint should have a type-info struct, where
+ * its functions are attached for use.
+ */
+
+/* Template for type-info data:
+ * - make a copy of this when creating new constraints, and just change the functions
+ * pointed to as necessary
+ * - although the naming of functions doesn't matter, it would help for code
+ * readability, to follow the same naming convention as is presented here
+ * - any functions that a constraint doesn't need to define, don't define
+ * for such cases, just use NULL
+ * - these should be defined after all the functions have been defined, so that
+ * forward-definitions/prototypes don't need to be used!
+ * - keep this copy #if-def'd so that future constraints can get based off this
+ */
+#if 0
+static bConstraintTypeInfo CTI_CONSTRNAME = {
+ CONSTRAINT_TYPE_CONSTRNAME, /* type */
+ sizeof(bConstrNameConstraint), /* size */
+ "ConstrName", /* name */
+ "bConstrNameConstraint", /* struct name */
+ constrname_free, /* free data */
+ constrname_relink, /* relink data */
+ constrname_copy, /* copy data */
+ constrname_new_data, /* new data */
+ constrname_get_tars, /* get constraint targets */
+ constrname_flush_tars, /* flush constraint targets */
+ constrname_get_tarmat, /* get target matrix */
+ constrname_evaluate /* evaluate */
+};
+#endif
+
+/* This function should be used for the get_target_matrix member of all
+ * constraints that are not picky about what happens to their target matrix.
+ */
+static void default_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float ctime)
+{
+ if (VALID_CONS_TARGET(ct))
+ constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space);
+ else if (ct)
+ Mat4One(ct->matrix);
+}
+
+/* This following macro should be used for all standard single-target *_get_tars functions
+ * to save typing and reduce maintainance woes.
+ * (Hopefully all compilers will be happy with the lines with just a space on them. Those are
+ * really just to help this code easier to read)
+ */
+#define SINGLETARGET_GET_TARS(con, datatar, datasubtarget, ct, list) \
+ { \
+ ct= MEM_callocN(sizeof(bConstraintTarget), "tempConstraintTarget"); \
+ \
+ ct->tar= datatar; \
+ strcpy(ct->subtarget, datasubtarget); \
+ ct->space= con->tarspace; \
+ ct->flag= CONSTRAINT_TAR_TEMP; \
+ \
+ if (ct->tar) { \
+ if ((ct->tar->type==OB_ARMATURE) && (ct->subtarget[0])) ct->type = CONSTRAINT_OBTYPE_BONE; \
+ else if (ELEM(ct->tar->type, OB_MESH, OB_LATTICE) && (ct->subtarget[0])) ct->type = CONSTRAINT_OBTYPE_VERT; \
+ else ct->type = CONSTRAINT_OBTYPE_OBJECT; \
+ } \
+ \
+ BLI_addtail(list, ct); \
+ }
+
+/* This following macro should be used for all standard single-target *_get_tars functions
+ * to save typing and reduce maintainance woes. It does not do the subtarget related operations
+ * (Hopefully all compilers will be happy with the lines with just a space on them. Those are
+ * really just to help this code easier to read)
+ */
+#define SINGLETARGETNS_GET_TARS(con, datatar, ct, list) \
+ { \
+ ct= MEM_callocN(sizeof(bConstraintTarget), "tempConstraintTarget"); \
+ \
+ ct->tar= datatar; \
+ ct->space= con->tarspace; \
+ ct->flag= CONSTRAINT_TAR_TEMP; \
+ \
+ if (ct->tar) ct->type = CONSTRAINT_OBTYPE_OBJECT; \
+ \
+ BLI_addtail(list, ct); \
+ }
+
+/* This following macro should be used for all standard single-target *_flush_tars functions
+ * to save typing and reduce maintainance woes.
+ * (Hopefully all compilers will be happy with the lines with just a space on them. Those are
+ * really just to help this code easier to read)
+ */
+#define SINGLETARGET_FLUSH_TARS(con, datatar, datasubtarget, ct, list, nocopy) \
+ { \
+ if (ct) { \
+ if (nocopy == 0) { \
+ datatar= ct->tar; \
+ strcpy(datasubtarget, ct->subtarget); \
+ con->tarspace= ct->space; \
+ } \
+ \
+ BLI_freelinkN(list, ct); \
+ } \
+ }
+
+/* This following macro should be used for all standard single-target *_flush_tars functions
+ * to save typing and reduce maintainance woes. It does not do the subtarget related operations
+ * (Hopefully all compilers will be happy with the lines with just a space on them. Those are
+ * really just to help this code easier to read)
+ */
+#define SINGLETARGETNS_FLUSH_TARS(con, datatar, ct, list, nocopy) \
+ { \
+ if (ct) { \
+ if (nocopy == 0) { \
+ datatar= ct->tar; \
+ con->tarspace= ct->space; \
+ } \
+ \
+ BLI_freelinkN(list, ct); \
+ } \
+ }
+
+/* --------- ChildOf Constraint ------------ */
+
+static void childof_new_data (void *cdata)
+{
+ bChildOfConstraint *data= (bChildOfConstraint *)cdata;
+
+ data->flag = (CHILDOF_LOCX | CHILDOF_LOCY | CHILDOF_LOCZ |
+ CHILDOF_ROTX |CHILDOF_ROTY | CHILDOF_ROTZ |
+ CHILDOF_SIZEX | CHILDOF_SIZEY | CHILDOF_SIZEZ);
+ Mat4One(data->invmat);
+}
+
+static void childof_get_tars (bConstraint *con, ListBase *list)
+{
+ if (con && list) {
+ bChildOfConstraint *data= con->data;
+ bConstraintTarget *ct;
+
+ /* standard target-getting macro for single-target constraints */
+ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list)
+ }
+}
+
+static void childof_flush_tars (bConstraint *con, ListBase *list, short nocopy)
+{
+ if (con && list) {
+ bChildOfConstraint *data= con->data;
+ bConstraintTarget *ct= list->first;
+
+ /* the following macro is used for all standard single-target constraints */
+ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, nocopy)
+ }
+}
+
+static void childof_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets)
+{
+ bChildOfConstraint *data= con->data;
+ bConstraintTarget *ct= targets->first;
+
+ /* only evaluate if there is a target */
+ if (VALID_CONS_TARGET(ct)) {
+ float parmat[4][4], invmat[4][4], tempmat[4][4];
+ float loc[3], eul[3], size[3];
+ float loco[3], eulo[3], sizo[3];
+
+ /* get offset (parent-inverse) matrix */
+ Mat4CpyMat4(invmat, data->invmat);
+
+ /* extract components of both matrices */
+ VECCOPY(loc, ct->matrix[3]);
+ Mat4ToEul(ct->matrix, eul);
+ Mat4ToSize(ct->matrix, size);
+
+ VECCOPY(loco, invmat[3]);
+ Mat4ToEul(invmat, eulo);
+ Mat4ToSize(invmat, sizo);
+
+ /* disable channels not enabled */
+ if (!(data->flag & CHILDOF_LOCX)) loc[0]= loco[0]= 0.0f;
+ if (!(data->flag & CHILDOF_LOCY)) loc[1]= loco[1]= 0.0f;
+ if (!(data->flag & CHILDOF_LOCZ)) loc[2]= loco[2]= 0.0f;
+ if (!(data->flag & CHILDOF_ROTX)) eul[0]= eulo[0]= 0.0f;
+ if (!(data->flag & CHILDOF_ROTY)) eul[1]= eulo[1]= 0.0f;
+ if (!(data->flag & CHILDOF_ROTZ)) eul[2]= eulo[2]= 0.0f;
+ if (!(data->flag & CHILDOF_SIZEX)) size[0]= sizo[0]= 1.0f;
+ if (!(data->flag & CHILDOF_SIZEY)) size[1]= sizo[1]= 1.0f;
+ if (!(data->flag & CHILDOF_SIZEZ)) size[2]= sizo[2]= 1.0f;
+
+ /* make new target mat and offset mat */
+ LocEulSizeToMat4(ct->matrix, loc, eul, size);
+ LocEulSizeToMat4(invmat, loco, eulo, sizo);
+
+ /* multiply target (parent matrix) by offset (parent inverse) to get
+ * the effect of the parent that will be exherted on the owner
+ */
+ Mat4MulMat4(parmat, invmat, ct->matrix);
+
+ /* now multiply the parent matrix by the owner matrix to get the
+ * the effect of this constraint (i.e. owner is 'parented' to parent)
+ */
+ Mat4CpyMat4(tempmat, cob->matrix);
+ Mat4MulMat4(cob->matrix, tempmat, parmat);
+ }
+}
+
+static bConstraintTypeInfo CTI_CHILDOF = {
+ CONSTRAINT_TYPE_CHILDOF, /* type */
+ sizeof(bChildOfConstraint), /* size */
+ "ChildOf", /* name */
+ "bChildOfConstraint", /* struct name */
+ NULL, /* free data */
+ NULL, /* relink data */
+ NULL, /* copy data */
+ childof_new_data, /* new data */
+ childof_get_tars, /* get constraint targets */
+ childof_flush_tars, /* flush constraint targets */
+ default_get_tarmat, /* get a target matrix */
+ childof_evaluate /* evaluate */
+};
+
+/* -------- TrackTo Constraint ------- */
+
+static void trackto_new_data (void *cdata)
+{
+ bTrackToConstraint *data= (bTrackToConstraint *)cdata;
+
+ data->reserved1 = TRACK_Y;
+ data->reserved2 = UP_Z;
+}
+
+static void trackto_get_tars (bConstraint *con, ListBase *list)
+{
+ if (con && list) {
+ bTrackToConstraint *data= con->data;
+ bConstraintTarget *ct;
+
+ /* standard target-getting macro for single-target constraints */
+ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list)
+ }
+}
+
+static void trackto_flush_tars (bConstraint *con, ListBase *list, short nocopy)
+{
+ if (con && list) {
+ bTrackToConstraint *data= con->data;
+ bConstraintTarget *ct= list->first;
+
+ /* the following macro is used for all standard single-target constraints */
+ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, nocopy)
+ }
+}
+
+
+static int basis_cross (int n, int m)
+{
+ switch (n-m) {
+ case 1:
+ case -2:
+ return 1;
+
+ case -1:
+ case 2:
+ return -1;
+
+ default:
+ return 0;
+ }
+}
+
+static void vectomat (float *vec, float *target_up, short axis, short upflag, short flags, float m[][3])
+{
+ float n[3];
+ float u[3]; /* vector specifying the up axis */
+ float proj[3];
+ float right[3];
+ float neg = -1;
+ int right_index;
+
+ VecCopyf(n, vec);
+ if (Normalize(n) == 0.0) {
+ n[0] = 0.0;
+ n[1] = 0.0;
+ n[2] = 1.0;
+ }
+ if (axis > 2) axis -= 3;
+ else VecMulf(n,-1);
+
+ /* n specifies the transformation of the track axis */
+ if (flags & TARGET_Z_UP) {
+ /* target Z axis is the global up axis */
+ u[0] = target_up[0];
+ u[1] = target_up[1];
+ u[2] = target_up[2];
+ }
+ else {
+ /* world Z axis is the global up axis */
+ u[0] = 0;
+ u[1] = 0;
+ u[2] = 1;
+ }
+
+ /* project the up vector onto the plane specified by n */
+ Projf(proj, u, n); /* first u onto n... */
+ VecSubf(proj, u, proj); /* then onto the plane */
+ /* proj specifies the transformation of the up axis */
+
+ if (Normalize(proj) == 0.0) { /* degenerate projection */
+ proj[0] = 0.0;
+ proj[1] = 1.0;
+ proj[2] = 0.0;
+ }
+
+ /* Normalized cross product of n and proj specifies transformation of the right axis */
+ Crossf(right, proj, n);
+ Normalize(right);
+
+ if (axis != upflag) {
+ right_index = 3 - axis - upflag;
+ neg = (float)basis_cross(axis, upflag);
+
+ /* account for up direction, track direction */
+ m[right_index][0] = neg * right[0];
+ m[right_index][1] = neg * right[1];
+ m[right_index][2] = neg * right[2];
+
+ m[upflag][0] = proj[0];
+ m[upflag][1] = proj[1];
+ m[upflag][2] = proj[2];
+
+ m[axis][0] = n[0];
+ m[axis][1] = n[1];
+ m[axis][2] = n[2];
+ }
+ /* identity matrix - don't do anything if the two axes are the same */
+ else {
+ m[0][0]= m[1][1]= m[2][2]= 1.0;
+ m[0][1]= m[0][2]= m[0][3]= 0.0;
+ m[1][0]= m[1][2]= m[1][3]= 0.0;
+ m[2][0]= m[2][1]= m[2][3]= 0.0;
+ }
+}
+
+
+static void trackto_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets)
+{
+ bTrackToConstraint *data= con->data;
+ bConstraintTarget *ct= targets->first;
+
+ if (VALID_CONS_TARGET(ct)) {
+ float size[3], vec[3];
+ float totmat[3][3];
+ float tmat[4][4];
+
+ /* Get size property, since ob->size is only the object's own relative size, not its global one */
+ Mat4ToSize(cob->matrix, size);
+
+ /* Clear the object's rotation */
+ cob->matrix[0][0]=size[0];
+ cob->matrix[0][1]=0;
+ cob->matrix[0][2]=0;
+ cob->matrix[1][0]=0;
+ cob->matrix[1][1]=size[1];
+ cob->matrix[1][2]=0;
+ cob->matrix[2][0]=0;
+ cob->matrix[2][1]=0;
+ cob->matrix[2][2]=size[2];
+
+ /* targetmat[2] instead of ownermat[2] is passed to vectomat
+ * for backwards compatability it seems... (Aligorith)
+ */
+ VecSubf(vec, cob->matrix[3], ct->matrix[3]);
+ vectomat(vec, ct->matrix[2],
+ (short)data->reserved1, (short)data->reserved2,
+ data->flags, totmat);
+
+ Mat4CpyMat4(tmat, cob->matrix);
+ Mat4MulMat34(cob->matrix, totmat, tmat);
+ }
+}
+
+static bConstraintTypeInfo CTI_TRACKTO = {
+ CONSTRAINT_TYPE_TRACKTO, /* type */
+ sizeof(bTrackToConstraint), /* size */
+ "TrackTo", /* name */
+ "bTrackToConstraint", /* struct name */
+ NULL, /* free data */
+ NULL, /* relink data */
+ NULL, /* copy data */
+ trackto_new_data, /* new data */
+ trackto_get_tars, /* get constraint targets */
+ trackto_flush_tars, /* flush constraint targets */
+ default_get_tarmat, /* get target matrix */
+ trackto_evaluate /* evaluate */
+};
+
+/* --------- Inverse-Kinemetics --------- */
+
+static void kinematic_new_data (void *cdata)
+{
+ bKinematicConstraint *data= (bKinematicConstraint *)cdata;
+
+ data->weight= (float)1.0;
+ data->orientweight= (float)1.0;
+ data->iterations = 500;
+ data->flag= CONSTRAINT_IK_TIP|CONSTRAINT_IK_STRETCH|CONSTRAINT_IK_POS;
+}
+
+static void kinematic_get_tars (bConstraint *con, ListBase *list)
+{
+ if (con && list) {
+ bKinematicConstraint *data= con->data;
+ bConstraintTarget *ct;
+
+ /* standard target-getting macro for single-target constraints */
+ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list)
+ SINGLETARGET_GET_TARS(con, data->poletar, data->polesubtarget, ct, list)
+ }
+}
+
+static void kinematic_flush_tars (bConstraint *con, ListBase *list, short nocopy)
+{
+ if (con && list) {
+ bKinematicConstraint *data= con->data;
+ bConstraintTarget *ct= list->first;
+
+ /* the following macro is used for all standard single-target constraints */
+ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, nocopy)
+ ct= ct->next;
+ SINGLETARGET_FLUSH_TARS(con, data->poletar, data->polesubtarget, ct, list, nocopy)
+ }
+}
+
+static void kinematic_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float ctime)
+{
+ bKinematicConstraint *data= con->data;
+
+ if (VALID_CONS_TARGET(ct))
+ constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space);
+ else if (ct) {
+ if (data->flag & CONSTRAINT_IK_AUTO) {
+ Object *ob= cob->ob;
+
+ if (ob == NULL) {
+ Mat4One(ct->matrix);
+ }
+ else {
+ float vec[3];
+ /* move grabtarget into world space */
+ VECCOPY(vec, data->grabtarget);
+ Mat4MulVecfl(ob->obmat, vec);
+ Mat4CpyMat4(ct->matrix, ob->obmat);
+ VECCOPY(ct->matrix[3], vec);
+ }
+ }
+ else
+ Mat4One(ct->matrix);
+ }
+}
+
+static bConstraintTypeInfo CTI_KINEMATIC = {
+ CONSTRAINT_TYPE_KINEMATIC, /* type */
+ sizeof(bKinematicConstraint), /* size */
+ "IK", /* name */
+ "bKinematicConstraint", /* struct name */
+ NULL, /* free data */
+ NULL, /* relink data */
+ NULL, /* copy data */
+ kinematic_new_data, /* new data */
+ kinematic_get_tars, /* get constraint targets */
+ kinematic_flush_tars, /* flush constraint targets */
+ kinematic_get_tarmat, /* get target matrix */
+ NULL /* evaluate - solved as separate loop */
+};
+
+/* -------- Follow-Path Constraint ---------- */
+
+static void followpath_new_data (void *cdata)
+{
+ bFollowPathConstraint *data= (bFollowPathConstraint *)cdata;
+
+ data->trackflag = TRACK_Y;
+ data->upflag = UP_Z;
+ data->offset = 0;
+ data->followflag = 0;
+}
+
+static void followpath_get_tars (bConstraint *con, ListBase *list)
+{
+ if (con && list) {
+ bFollowPathConstraint *data= con->data;
+ bConstraintTarget *ct;
+
+ /* standard target-getting macro for single-target constraints without subtargets */
+ SINGLETARGETNS_GET_TARS(con, data->tar, ct, list)
+ }
+}
+
+static void followpath_flush_tars (bConstraint *con, ListBase *list, short nocopy)
+{
+ if (con && list) {
+ bFollowPathConstraint *data= con->data;
+ bConstraintTarget *ct= list->first;
+
+ /* the following macro is used for all standard single-target constraints */
+ SINGLETARGETNS_FLUSH_TARS(con, data->tar, ct, list, nocopy)
+ }
+}
+
+static void followpath_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float ctime)
+{
+ bFollowPathConstraint *data= con->data;
+
+ if (VALID_CONS_TARGET(ct)) {
+ Curve *cu= ct->tar->data;
+ float q[4], vec[4], dir[3], *quat, x1;
+ float totmat[4][4];
+ float curvetime;
+
+ Mat4One(totmat);
+ Mat4One(ct->matrix);
+
+ /* note: when creating constraints that follow path, the curve gets the CU_PATH set now,
+ * currently for paths to work it needs to go through the bevlist/displist system (ton)
+ */
+
+ /* only happens on reload file, but violates depsgraph still... fix! */
+ if (cu->path==NULL || cu->path->data==NULL)
+ makeDispListCurveTypes(ct->tar, 0);
+
+ if (cu->path && cu->path->data) {
+ curvetime= bsystem_time(ct->tar, (float)ctime, 0.0) - data->offset;
+
+ if (calc_ipo_spec(cu->ipo, CU_SPEED, &curvetime)==0) {
+ curvetime /= cu->pathlen;
+ CLAMP(curvetime, 0.0, 1.0);
+ }
+
+ if ( where_on_path(ct->tar, curvetime, vec, dir) ) {
+ if (data->followflag) {
+ quat= vectoquat(dir, (short) data->trackflag, (short) data->upflag);
+
+ Normalize(dir);
+ q[0]= (float)cos(0.5*vec[3]);
+ x1= (float)sin(0.5*vec[3]);
+ q[1]= -x1*dir[0];
+ q[2]= -x1*dir[1];
+ q[3]= -x1*dir[2];
+ QuatMul(quat, q, quat);
+
+ QuatToMat4(quat, totmat);
+ }
+ VECCOPY(totmat[3], vec);
+
+ Mat4MulSerie(ct->matrix, ct->tar->obmat, totmat, NULL, NULL, NULL, NULL, NULL, NULL);
+ }
+ }
+ }
+ else if (ct)
+ Mat4One(ct->matrix);
+}
+
+static void followpath_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets)
+{
+ bConstraintTarget *ct= targets->first;
+
+ /* only evaluate if there is a target */
+ if (VALID_CONS_TARGET(ct)) {
+ float obmat[4][4];
+ float size[3], obsize[3];
+
+ /* get Object local transform (loc/rot/size) to determine transformation from path */
+ //object_to_mat4(ob, obmat);
+ Mat4CpyMat4(obmat, cob->matrix); // FIXME!!!
+
+ /* get scaling of object before applying constraint */
+ Mat4ToSize(cob->matrix, size);
+
+ /* apply targetmat - containing location on path, and rotation */
+ Mat4MulSerie(cob->matrix, ct->matrix, obmat, NULL, NULL, NULL, NULL, NULL, NULL);
+
+ /* un-apply scaling caused by path */
+ Mat4ToSize(cob->matrix, obsize);
+ if (obsize[0])
+ VecMulf(cob->matrix[0], size[0] / obsize[0]);
+ if (obsize[1])
+ VecMulf(cob->matrix[1], size[1] / obsize[1]);
+ if (obsize[2])
+ VecMulf(cob->matrix[2], size[2] / obsize[2]);
+ }
+}
+
+static bConstraintTypeInfo CTI_FOLLOWPATH = {
+ CONSTRAINT_TYPE_FOLLOWPATH, /* type */
+ sizeof(bFollowPathConstraint), /* size */
+ "Follow Path", /* name */
+ "bFollowPathConstraint", /* struct name */
+ NULL, /* free data */
+ NULL, /* relink data */
+ NULL, /* copy data */
+ followpath_new_data, /* new data */
+ followpath_get_tars, /* get constraint targets */
+ followpath_flush_tars, /* flush constraint targets */
+ followpath_get_tarmat, /* get target matrix */
+ followpath_evaluate /* evaluate */
+};
+
+/* --------- Limit Location --------- */
+
+
+static void loclimit_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets)
+{
+ bLocLimitConstraint *data = con->data;
+
+ if (data->flag & LIMIT_XMIN) {
+ if (cob->matrix[3][0] < data->xmin)
+ cob->matrix[3][0] = data->xmin;
+ }
+ if (data->flag & LIMIT_XMAX) {
+ if (cob->matrix[3][0] > data->xmax)
+ cob->matrix[3][0] = data->xmax;
+ }
+ if (data->flag & LIMIT_YMIN) {
+ if (cob->matrix[3][1] < data->ymin)
+ cob->matrix[3][1] = data->ymin;
+ }
+ if (data->flag & LIMIT_YMAX) {
+ if (cob->matrix[3][1] > data->ymax)
+ cob->matrix[3][1] = data->ymax;
+ }
+ if (data->flag & LIMIT_ZMIN) {
+ if (cob->matrix[3][2] < data->zmin)
+ cob->matrix[3][2] = data->zmin;
+ }
+ if (data->flag & LIMIT_ZMAX) {
+ if (cob->matrix[3][2] > data->zmax)
+ cob->matrix[3][2] = data->zmax;
+ }
+}
+
+static bConstraintTypeInfo CTI_LOCLIMIT = {
+ CONSTRAINT_TYPE_LOCLIMIT, /* type */
+ sizeof(bLocLimitConstraint), /* size */
+ "Limit Location", /* name */
+ "bLocLimitConstraint", /* struct name */
+ NULL, /* free data */
+ NULL, /* relink data */
+ NULL, /* copy data */
+ NULL, /* new data */
+ NULL, /* get constraint targets */
+ NULL, /* flush constraint targets */
+ NULL, /* get target matrix */
+ loclimit_evaluate /* evaluate */
+};
+
+/* -------- Limit Rotation --------- */
+
+static void rotlimit_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets)
+{
+ bRotLimitConstraint *data = con->data;
+ float loc[3];
+ float eul[3];
+ float size[3];
+
+ VECCOPY(loc, cob->matrix[3]);
+ Mat4ToSize(cob->matrix, size);
+
+ Mat4ToEul(cob->matrix, eul);
+
+ /* eulers: radians to degrees! */
+ eul[0] = (eul[0] / M_PI * 180);
+ eul[1] = (eul[1] / M_PI * 180);
+ eul[2] = (eul[2] / M_PI * 180);
+
+ /* limiting of euler values... */
+ if (data->flag & LIMIT_XROT) {
+ if (eul[0] < data->xmin)
+ eul[0] = data->xmin;
+
+ if (eul[0] > data->xmax)
+ eul[0] = data->xmax;
+ }
+ if (data->flag & LIMIT_YROT) {
+ if (eul[1] < data->ymin)
+ eul[1] = data->ymin;
+
+ if (eul[1] > data->ymax)
+ eul[1] = data->ymax;
+ }
+ if (data->flag & LIMIT_ZROT) {
+ if (eul[2] < data->zmin)
+ eul[2] = data->zmin;
+
+ if (eul[2] > data->zmax)
+ eul[2] = data->zmax;
+ }
+
+ /* eulers: degrees to radians ! */
+ eul[0] = (eul[0] / 180 * M_PI);
+ eul[1] = (eul[1] / 180 * M_PI);
+ eul[2] = (eul[2] / 180 * M_PI);
+
+ LocEulSizeToMat4(cob->matrix, loc, eul, size);
+}
+
+static bConstraintTypeInfo CTI_ROTLIMIT = {
+ CONSTRAINT_TYPE_ROTLIMIT, /* type */
+ sizeof(bRotLimitConstraint), /* size */
+ "Limit Rotation", /* name */
+ "bRotLimitConstraint", /* struct name */
+ NULL, /* free data */
+ NULL, /* relink data */
+ NULL, /* copy data */
+ NULL, /* new data */
+ NULL, /* get constraint targets */
+ NULL, /* flush constraint targets */
+ NULL, /* get target matrix */
+ rotlimit_evaluate /* evaluate */
+};
+
+/* --------- Limit Scaling --------- */
+
+
+static void sizelimit_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets)
+{
+ bSizeLimitConstraint *data = con->data;
+ float obsize[3], size[3];
+
+ Mat4ToSize(cob->matrix, size);
+ Mat4ToSize(cob->matrix, obsize);
+
+ if (data->flag & LIMIT_XMIN) {
+ if (size[0] < data->xmin)
+ size[0] = data->xmin;
+ }
+ if (data->flag & LIMIT_XMAX) {
+ if (size[0] > data->xmax)
+ size[0] = data->xmax;
+ }
+ if (data->flag & LIMIT_YMIN) {
+ if (size[1] < data->ymin)
+ size[1] = data->ymin;
+ }
+ if (data->flag & LIMIT_YMAX) {
+ if (size[1] > data->ymax)
+ size[1] = data->ymax;
+ }
+ if (data->flag & LIMIT_ZMIN) {
+ if (size[2] < data->zmin)
+ size[2] = data->zmin;
+ }
+ if (data->flag & LIMIT_ZMAX) {
+ if (size[2] > data->zmax)
+ size[2] = data->zmax;
+ }
+
+ if (obsize[0])
+ VecMulf(cob->matrix[0], size[0]/obsize[0]);
+ if (obsize[1])
+ VecMulf(cob->matrix[1], size[1]/obsize[1]);
+ if (obsize[2])
+ VecMulf(cob->matrix[2], size[2]/obsize[2]);
+}
+
+static bConstraintTypeInfo CTI_SIZELIMIT = {
+ CONSTRAINT_TYPE_SIZELIMIT, /* type */
+ sizeof(bSizeLimitConstraint), /* size */
+ "Limit Scaling", /* name */
+ "bSizeLimitConstraint", /* struct name */
+ NULL, /* free data */
+ NULL, /* relink data */
+ NULL, /* copy data */
+ NULL, /* new data */
+ NULL, /* get constraint targets */
+ NULL, /* flush constraint targets */
+ NULL, /* get target matrix */
+ sizelimit_evaluate /* evaluate */
+};
+
+/* ----------- Copy Location ------------- */
+
+static void loclike_new_data (void *cdata)
+{
+ bLocateLikeConstraint *data= (bLocateLikeConstraint *)cdata;
+
+ data->flag = LOCLIKE_X|LOCLIKE_Y|LOCLIKE_Z;
+}
+
+static void loclike_get_tars (bConstraint *con, ListBase *list)
+{
+ if (con && list) {
+ bLocateLikeConstraint *data= con->data;
+ bConstraintTarget *ct;
+
+ /* standard target-getting macro for single-target constraints */
+ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list)
+ }
+}
+
+static void loclike_flush_tars (bConstraint *con, ListBase *list, short nocopy)
+{
+ if (con && list) {
+ bLocateLikeConstraint *data= con->data;
+ bConstraintTarget *ct= list->first;
+
+ /* the following macro is used for all standard single-target constraints */
+ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, nocopy)
+ }
+}
+
+static void loclike_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float ctime)
+{
+ bLocateLikeConstraint *data = con->data;
+
+ if (VALID_CONS_TARGET(ct)) {
+ if (ct->tar->type==OB_ARMATURE && strlen(ct->subtarget)) {
+ /* Pose-Channels for the CopyLoc target are handled specially, so that
+ * we can support using the bone-tip as an option.
+ */
+ bPoseChannel *pchan;
+ float tmat[4][4];
+
+ pchan = get_pose_channel(ct->tar->pose, ct->subtarget);
+ if (pchan) {
+ Mat4CpyMat4(tmat, pchan->pose_mat);
+
+ if (data->flag & LOCLIKE_TIP) {
+ VECCOPY(tmat[3], pchan->pose_tail);
+ }
+
+ Mat4MulMat4(ct->matrix, tmat, ct->tar->obmat);
+ }
+ else
+ Mat4CpyMat4(ct->matrix, ct->tar->obmat);
+
+ /* convert matrix space as required */
+ constraint_mat_convertspace(ct->tar, pchan, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space);
+ }
+ else {
+ /* get target matrix as is done normally for other constraints */
+ constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space);
+ }
+ }
+ else if (ct)
+ Mat4One(ct->matrix);
+}
+
+static void loclike_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets)
+{
+ bLocateLikeConstraint *data= con->data;
+ bConstraintTarget *ct= targets->first;
+
+ if (VALID_CONS_TARGET(ct)) {
+ float offset[3] = {0.0f, 0.0f, 0.0f};
+
+ if (data->flag & LOCLIKE_OFFSET)
+ VECCOPY(offset, cob->matrix[3]);
+
+ if (data->flag & LOCLIKE_X) {
+ cob->matrix[3][0] = ct->matrix[3][0];
+
+ if (data->flag & LOCLIKE_X_INVERT) cob->matrix[3][0] *= -1;
+ cob->matrix[3][0] += offset[0];
+ }
+ if (data->flag & LOCLIKE_Y) {
+ cob->matrix[3][1] = ct->matrix[3][1];
+
+ if (data->flag & LOCLIKE_Y_INVERT) cob->matrix[3][1] *= -1;
+ cob->matrix[3][1] += offset[1];
+ }
+ if (data->flag & LOCLIKE_Z) {
+ cob->matrix[3][2] = ct->matrix[3][2];
+
+ if (data->flag & LOCLIKE_Z_INVERT) cob->matrix[3][2] *= -1;
+ cob->matrix[3][2] += offset[2];
+ }
+ }
+}
+
+static bConstraintTypeInfo CTI_LOCLIKE = {
+ CONSTRAINT_TYPE_LOCLIKE, /* type */
+ sizeof(bLocateLikeConstraint), /* size */
+ "Copy Location", /* name */
+ "bLocateLikeConstraint", /* struct name */
+ NULL, /* free data */
+ NULL, /* relink data */
+ NULL, /* copy data */
+ loclike_new_data, /* new data */
+ loclike_get_tars, /* get constraint targets */
+ loclike_flush_tars, /* flush constraint targets */
+ loclike_get_tarmat, /* get target matrix */
+ loclike_evaluate /* evaluate */
+};
+
+/* ----------- Copy Rotation ------------- */
+
+static void rotlike_new_data (void *cdata)
+{
+ bRotateLikeConstraint *data= (bRotateLikeConstraint *)cdata;
+
+ data->flag = ROTLIKE_X|ROTLIKE_Y|ROTLIKE_Z;
+}
+
+static void rotlike_get_tars (bConstraint *con, ListBase *list)
+{
+ if (con && list) {
+ bRotateLikeConstraint *data= con->data;
+ bConstraintTarget *ct;
+
+ /* standard target-getting macro for single-target constraints */
+ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list)
+ }
+}
+
+static void rotlike_flush_tars (bConstraint *con, ListBase *list, short nocopy)
+{
+ if (con && list) {
+ bRotateLikeConstraint *data= con->data;
+ bConstraintTarget *ct= list->first;
+
+ /* the following macro is used for all standard single-target constraints */
+ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, nocopy)
+ }
+}
+
+static void rotlike_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets)
+{
+ bRotateLikeConstraint *data= con->data;
+ bConstraintTarget *ct= targets->first;
+
+ if (VALID_CONS_TARGET(ct)) {
+ float loc[3];
+ float eul[3], obeul[3];
+ float size[3];
+
+ VECCOPY(loc, cob->matrix[3]);
+ Mat4ToSize(cob->matrix, size);
+
+ Mat4ToEul(ct->matrix, eul);
+ Mat4ToEul(cob->matrix, obeul);
+
+ if ((data->flag & ROTLIKE_X)==0)
+ eul[0] = obeul[0];
+ else {
+ if (data->flag & ROTLIKE_OFFSET)
+ euler_rot(eul, obeul[0], 'x');
+
+ if (data->flag & ROTLIKE_X_INVERT)
+ eul[0] *= -1;
+ }
+
+ if ((data->flag & ROTLIKE_Y)==0)
+ eul[1] = obeul[1];
+ else {
+ if (data->flag & ROTLIKE_OFFSET)
+ euler_rot(eul, obeul[1], 'y');
+
+ if (data->flag & ROTLIKE_Y_INVERT)
+ eul[1] *= -1;
+ }
+
+ if ((data->flag & ROTLIKE_Z)==0)
+ eul[2] = obeul[2];
+ else {
+ if (data->flag & ROTLIKE_OFFSET)
+ euler_rot(eul, obeul[2], 'z');
+
+ if (data->flag & ROTLIKE_Z_INVERT)
+ eul[2] *= -1;
+ }
+
+ compatible_eul(eul, obeul);
+ LocEulSizeToMat4(cob->matrix, loc, eul, size);
+ }
+}
+
+static bConstraintTypeInfo CTI_ROTLIKE = {
+ CONSTRAINT_TYPE_ROTLIKE, /* type */
+ sizeof(bRotateLikeConstraint), /* size */
+ "Copy Rotation", /* name */
+ "bRotateLikeConstraint", /* struct name */
+ NULL, /* free data */
+ NULL, /* relink data */
+ NULL, /* copy data */
+ rotlike_new_data, /* new data */
+ rotlike_get_tars, /* get constraint targets */
+ rotlike_flush_tars, /* flush constraint targets */
+ default_get_tarmat, /* get target matrix */
+ rotlike_evaluate /* evaluate */
+};
+
+/* ---------- Copy Scaling ---------- */
+
+static void sizelike_new_data (void *cdata)
+{
+ bSizeLikeConstraint *data= (bSizeLikeConstraint *)cdata;
+
+ data->flag = SIZELIKE_X|SIZELIKE_Y|SIZELIKE_Z;
+}
+
+static void sizelike_get_tars (bConstraint *con, ListBase *list)
+{
+ if (con && list) {
+ bSizeLikeConstraint *data= con->data;
+ bConstraintTarget *ct;
+
+ /* standard target-getting macro for single-target constraints */
+ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list)
+ }
+}
+
+static void sizelike_flush_tars (bConstraint *con, ListBase *list, short nocopy)
+{
+ if (con && list) {
+ bSizeLikeConstraint *data= con->data;
+ bConstraintTarget *ct= list->first;
+
+ /* the following macro is used for all standard single-target constraints */
+ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, nocopy)
+ }
+}
+
+static void sizelike_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets)
+{
+ bSizeLikeConstraint *data= con->data;
+ bConstraintTarget *ct= targets->first;
+
+ if (VALID_CONS_TARGET(ct)) {
+ float obsize[3], size[3];
+
+ Mat4ToSize(ct->matrix, size);
+ Mat4ToSize(cob->matrix, obsize);
+
+ if ((data->flag & SIZELIKE_X) && (obsize[0] != 0)) {
+ if (data->flag & SIZELIKE_OFFSET) {
+ size[0] += (obsize[0] - 1.0f);
+ VecMulf(cob->matrix[0], size[0] / obsize[0]);
+ }
+ else
+ VecMulf(cob->matrix[0], size[0] / obsize[0]);
+ }
+ if ((data->flag & SIZELIKE_Y) && (obsize[1] != 0)) {
+ if (data->flag & SIZELIKE_OFFSET) {
+ size[1] += (obsize[1] - 1.0f);
+ VecMulf(cob->matrix[1], size[1] / obsize[1]);
+ }
+ else
+ VecMulf(cob->matrix[1], size[1] / obsize[1]);
+ }
+ if ((data->flag & SIZELIKE_Z) && (obsize[2] != 0)) {
+ if (data->flag & SIZELIKE_OFFSET) {
+ size[2] += (obsize[2] - 1.0f);
+ VecMulf(cob->matrix[2], size[2] / obsize[2]);
+ }
+ else
+ VecMulf(cob->matrix[2], size[2] / obsize[2]);
+ }
+ }
+}
+
+static bConstraintTypeInfo CTI_SIZELIKE = {
+ CONSTRAINT_TYPE_SIZELIKE, /* type */
+ sizeof(bSizeLikeConstraint), /* size */
+ "Copy Scale", /* name */
+ "bSizeLikeConstraint", /* struct name */
+ NULL, /* free data */
+ NULL, /* relink data */
+ NULL, /* copy data */
+ sizelike_new_data, /* new data */
+ sizelike_get_tars, /* get constraint targets */
+ sizelike_flush_tars, /* flush constraint targets */
+ default_get_tarmat, /* get target matrix */
+ sizelike_evaluate /* evaluate */
+};
+
+/* ----------- Python Constraint -------------- */
+
+static void pycon_free (bConstraint *con)
+{
+ bPythonConstraint *data= con->data;
+
+ /* id-properties */
+ IDP_FreeProperty(data->prop);
+ MEM_freeN(data->prop);
+
+ /* multiple targets */
+ BLI_freelistN(&data->targets);
+}
+
+static void pycon_relink (bConstraint *con)
+{
+ bPythonConstraint *data= con->data;
+
+ ID_NEW(data->text);
+}
+
+static void pycon_copy (bConstraint *con, bConstraint *srccon)
+{
+ bPythonConstraint *pycon = (bPythonConstraint *)con->data;
+ bPythonConstraint *opycon = (bPythonConstraint *)srccon->data;
+
+ pycon->prop = IDP_CopyProperty(opycon->prop);
+ duplicatelist(&pycon->targets, &opycon->targets);
+}
+
+static void pycon_new_data (void *cdata)
+{
+ bPythonConstraint *data= (bPythonConstraint *)cdata;
+
+ /* everything should be set correctly by calloc, except for the prop->type constant.*/
+ data->prop = MEM_callocN(sizeof(IDProperty), "PyConstraintProps");
+ data->prop->type = IDP_GROUP;
+}
+
+static void pycon_get_tars (bConstraint *con, ListBase *list)
+{
+ if (con && list) {
+ bPythonConstraint *data= con->data;
+
+ list->first = data->targets.first;
+ list->last = data->targets.last;
+ }
+}
+
+/* Whether this approach is maintained remains to be seen (aligorith) */
+static void pycon_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float ctime)
+{
+ bPythonConstraint *data= con->data;
+
+ if (VALID_CONS_TARGET(ct)) {
+ /* special exception for curves - depsgraph issues */
+ if (ct->tar->type == OB_CURVE) {
+ Curve *cu= ct->tar->data;
+
+ /* this check is to make sure curve objects get updated on file load correctly.*/
+ if (cu->path==NULL || cu->path->data==NULL) /* only happens on reload file, but violates depsgraph still... fix! */
+ makeDispListCurveTypes(ct->tar, 0);
+ }
+
+ /* firstly calculate the matrix the normal way, then let the py-function override
+ * this matrix if it needs to do so
+ */
+ constraint_target_to_mat4(ct->tar, ct->subtarget, ct->matrix, CONSTRAINT_SPACE_WORLD, ct->space);
+ BPY_pyconstraint_target(data, ct);
+ }
+ else if (ct)
+ Mat4One(ct->matrix);
+}
+
+static void pycon_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets)
+{
+ bPythonConstraint *data= con->data;
+
+/* currently removed, until I this can be re-implemented for multiple targets */
+#if 0
+ /* Firstly, run the 'driver' function which has direct access to the objects involved
+ * Technically, this is potentially dangerous as users may abuse this and cause dependency-problems,
+ * but it also allows certain 'clever' rigging hacks to work.
+ */
+ BPY_pyconstraint_driver(data, cob, targets);
+#endif
+
+ /* Now, run the actual 'constraint' function, which should only access the matrices */
+ BPY_pyconstraint_eval(data, cob, targets);
+}
+
+static bConstraintTypeInfo CTI_PYTHON = {
+ CONSTRAINT_TYPE_PYTHON, /* type */
+ sizeof(bPythonConstraint), /* size */
+ "Script", /* name */
+ "bPythonConstraint", /* struct name */
+ pycon_free, /* free data */
+ pycon_relink, /* relink data */
+ pycon_copy, /* copy data */
+ pycon_new_data, /* new data */
+ pycon_get_tars, /* get constraint targets */
+ NULL, /* flush constraint targets */
+ pycon_get_tarmat, /* get target matrix */
+ pycon_evaluate /* evaluate */
+};
+
+/* -------- Action Constraint ----------- */
+
+static void actcon_relink (bConstraint *con)
+{
+ bActionConstraint *data= con->data;
+ ID_NEW(data->act);
+}
+
+static void actcon_new_data (void *cdata)
+{
+ bActionConstraint *data= (bActionConstraint *)cdata;
+
+ /* set type to 20 (Loc X), as 0 is Rot X for backwards compatability */
+ data->type = 20;
+}
+
+static void actcon_get_tars (bConstraint *con, ListBase *list)
+{
+ if (con && list) {
+ bActionConstraint *data= con->data;
+ bConstraintTarget *ct;
+
+ /* standard target-getting macro for single-target constraints */
+ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list)
+ }
+}
+
+static void actcon_flush_tars (bConstraint *con, ListBase *list, short nocopy)
+{
+ if (con && list) {
+ bActionConstraint *data= con->data;
+ bConstraintTarget *ct= list->first;
+
+ /* the following macro is used for all standard single-target constraints */
+ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, nocopy)
+ }
+}
+
+static void actcon_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float ctime)
+{
+ extern void chan_calc_mat(bPoseChannel *chan);
+ bActionConstraint *data = con->data;
+
+ if (VALID_CONS_TARGET(ct)) {
+ float tempmat[4][4], vec[3];
+ float s, t;
+ short axis;
+
+ /* initialise return matrix */
+ Mat4One(ct->matrix);
+
+ /* get the transform matrix of the target */
+ constraint_target_to_mat4(ct->tar, ct->subtarget, tempmat, CONSTRAINT_SPACE_WORLD, ct->space);
+
+ /* determine where in transform range target is */
+ /* data->type is mapped as follows for backwards compatability:
+ * 00,01,02 - rotation (it used to be like this)
+ * 10,11,12 - scaling
+ * 20,21,22 - location
+ */
+ if (data->type < 10) {
+ /* extract rotation (is in whatever space target should be in) */
+ Mat4ToEul(tempmat, vec);
+ vec[0] *= (float)(180.0/M_PI);
+ vec[1] *= (float)(180.0/M_PI);
+ vec[2] *= (float)(180.0/M_PI);
+ axis= data->type;
+ }
+ else if (data->type < 20) {
+ /* extract scaling (is in whatever space target should be in) */
+ Mat4ToSize(tempmat, vec);
+ axis= data->type - 10;
+ }
+ else {
+ /* extract location */
+ VECCOPY(vec, tempmat[3]);
+ axis= data->type - 20;
+ }
+
+ /* Target defines the animation */
+ s = (vec[axis]-data->min) / (data->max-data->min);
+ CLAMP(s, 0, 1);
+ t = ( s * (data->end-data->start)) + data->start;
+
+ /* Get the appropriate information from the action */
+ if (cob->type == CONSTRAINT_OBTYPE_BONE) {
+ bPose *pose;
+ bPoseChannel *pchan, *tchan;
+
+ /* make a temporary pose and evaluate using that */
+ pose = MEM_callocN(sizeof(bPose), "pose");
+
+ pchan = cob->pchan;
+ tchan= verify_pose_channel(pose, pchan->name);
+ extract_pose_from_action(pose, data->act, t);
+
+ chan_calc_mat(tchan);
+
+ Mat4CpyMat4(ct->matrix, tchan->chan_mat);
+
+ /* Clean up */
+ free_pose_channels(pose);
+ MEM_freeN(pose);
+ }
+ else if (cob->type == CONSTRAINT_OBTYPE_OBJECT) {
+ /* evaluate using workob */
+ what_does_obaction(cob->ob, data->act, t);
+ object_to_mat4(&workob, ct->matrix);
+ }
+ else {
+ /* behaviour undefined... */
+ puts("Error: unknown owner type for Action Constraint");
+ }
+ }
+}
+
+static void actcon_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets)
+{
+ bConstraintTarget *ct= targets->first;
+
+ if (VALID_CONS_TARGET(ct)) {
+ float temp[4][4];
+
+ /* Nice and simple... we just need to multiply the matrices, as the get_target_matrix
+ * function has already taken care of everything else.
+ */
+ Mat4CpyMat4(temp, cob->matrix);
+ Mat4MulMat4(cob->matrix, ct->matrix, temp);
+ }
+}
+
+static bConstraintTypeInfo CTI_ACTION = {
+ CONSTRAINT_TYPE_ACTION, /* type */
+ sizeof(bActionConstraint), /* size */
+ "Action", /* name */
+ "bActionConstraint", /* struct name */
+ NULL, /* free data */
+ actcon_relink, /* relink data */
+ NULL, /* copy data */
+ actcon_new_data, /* new data */
+ actcon_get_tars, /* get constraint targets */
+ actcon_flush_tars, /* flush constraint targets */
+ actcon_get_tarmat, /* get target matrix */
+ actcon_evaluate /* evaluate */
+};
+
+/* --------- Locked Track ---------- */
+
+static void locktrack_new_data (void *cdata)
+{
+ bLockTrackConstraint *data= (bLockTrackConstraint *)cdata;
+
+ data->trackflag = TRACK_Y;
+ data->lockflag = LOCK_Z;
+}
+
+static void locktrack_get_tars (bConstraint *con, ListBase *list)
+{
+ if (con && list) {
+ bLockTrackConstraint *data= con->data;
+ bConstraintTarget *ct;
+
+ /* the following macro is used for all standard single-target constraints */
+ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list)
+ }
+}
+
+static void locktrack_flush_tars (bConstraint *con, ListBase *list, short nocopy)
+{
+ if (con && list) {
+ bLockTrackConstraint *data= con->data;
+ bConstraintTarget *ct= list->first;
+
+ /* the following macro is used for all standard single-target constraints */
+ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, nocopy)
+ }
+}
+
+static void locktrack_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets)
+{
+ bLockTrackConstraint *data= con->data;
+ bConstraintTarget *ct= targets->first;
+
+ if (VALID_CONS_TARGET(ct)) {
+ float vec[3],vec2[3];
+ float totmat[3][3];
+ float tmpmat[3][3];
+ float invmat[3][3];
+ float tmat[4][4];
+ float mdet;
+
+ /* Vector object -> target */
+ VecSubf(vec, ct->matrix[3], cob->matrix[3]);
+ switch (data->lockflag){
+ case LOCK_X: /* LOCK X */
+ {
+ switch (data->trackflag) {
+ case TRACK_Y: /* LOCK X TRACK Y */
+ {
+ /* Projection of Vector on the plane */
+ Projf(vec2, vec, cob->matrix[0]);
+ VecSubf(totmat[1], vec, vec2);
+ Normalize(totmat[1]);
+
+ /* the x axis is fixed */
+ totmat[0][0] = cob->matrix[0][0];
+ totmat[0][1] = cob->matrix[0][1];
+ totmat[0][2] = cob->matrix[0][2];
+ Normalize(totmat[0]);
+
+ /* the z axis gets mapped onto a third orthogonal vector */
+ Crossf(totmat[2], totmat[0], totmat[1]);
+ }
+ break;
+ case TRACK_Z: /* LOCK X TRACK Z */
+ {
+ /* Projection of Vector on the plane */
+ Projf(vec2, vec, cob->matrix[0]);
+ VecSubf(totmat[2], vec, vec2);
+ Normalize(totmat[2]);
+
+ /* the x axis is fixed */
+ totmat[0][0] = cob->matrix[0][0];
+ totmat[0][1] = cob->matrix[0][1];
+ totmat[0][2] = cob->matrix[0][2];
+ Normalize(totmat[0]);
+
+ /* the z axis gets mapped onto a third orthogonal vector */
+ Crossf(totmat[1], totmat[2], totmat[0]);
+ }
+ break;
+ case TRACK_nY: /* LOCK X TRACK -Y */
+ {
+ /* Projection of Vector on the plane */
+ Projf(vec2, vec, cob->matrix[0]);
+ VecSubf(totmat[1], vec, vec2);
+ Normalize(totmat[1]);
+ VecMulf(totmat[1],-1);
+
+ /* the x axis is fixed */
+ totmat[0][0] = cob->matrix[0][0];
+ totmat[0][1] = cob->matrix[0][1];
+ totmat[0][2] = cob->matrix[0][2];
+ Normalize(totmat[0]);
+
+ /* the z axis gets mapped onto a third orthogonal vector */
+ Crossf(totmat[2], totmat[0], totmat[1]);
+ }
+ break;
+ case TRACK_nZ: /* LOCK X TRACK -Z */
+ {
+ /* Projection of Vector on the plane */
+ Projf(vec2, vec, cob->matrix[0]);
+ VecSubf(totmat[2], vec, vec2);
+ Normalize(totmat[2]);
+ VecMulf(totmat[2],-1);
+
+ /* the x axis is fixed */
+ totmat[0][0] = cob->matrix[0][0];
+ totmat[0][1] = cob->matrix[0][1];
+ totmat[0][2] = cob->matrix[0][2];
+ Normalize(totmat[0]);
+
+ /* the z axis gets mapped onto a third orthogonal vector */
+ Crossf(totmat[1], totmat[2], totmat[0]);
+ }
+ break;
+ default:
+ {
+ totmat[0][0] = 1;totmat[0][1] = 0;totmat[0][2] = 0;
+ totmat[1][0] = 0;totmat[1][1] = 1;totmat[1][2] = 0;
+ totmat[2][0] = 0;totmat[2][1] = 0;totmat[2][2] = 1;
+ }
+ break;
+ }
+ }
+ break;
+ case LOCK_Y: /* LOCK Y */
+ {
+ switch (data->trackflag) {
+ case TRACK_X: /* LOCK Y TRACK X */
+ {
+ /* Projection of Vector on the plane */
+ Projf(vec2, vec, cob->matrix[1]);
+ VecSubf(totmat[0], vec, vec2);
+ Normalize(totmat[0]);
+
+ /* the y axis is fixed */
+ totmat[1][0] = cob->matrix[1][0];
+ totmat[1][1] = cob->matrix[1][1];
+ totmat[1][2] = cob->matrix[1][2];
+ Normalize(totmat[1]);
+
+ /* the z axis gets mapped onto a third orthogonal vector */
+ Crossf(totmat[2], totmat[0], totmat[1]);
+ }
+ break;
+ case TRACK_Z: /* LOCK Y TRACK Z */
+ {
+ /* Projection of Vector on the plane */
+ Projf(vec2, vec, cob->matrix[1]);
+ VecSubf(totmat[2], vec, vec2);
+ Normalize(totmat[2]);
+
+ /* the y axis is fixed */
+ totmat[1][0] = cob->matrix[1][0];
+ totmat[1][1] = cob->matrix[1][1];
+ totmat[1][2] = cob->matrix[1][2];
+ Normalize(totmat[1]);
+
+ /* the z axis gets mapped onto a third orthogonal vector */
+ Crossf(totmat[0], totmat[1], totmat[2]);
+ }
+ break;
+ case TRACK_nX: /* LOCK Y TRACK -X */
+ {
+ /* Projection of Vector on the plane */
+ Projf(vec2, vec, cob->matrix[1]);
+ VecSubf(totmat[0], vec, vec2);
+ Normalize(totmat[0]);
+ VecMulf(totmat[0],-1);
+
+ /* the y axis is fixed */
+ totmat[1][0] = cob->matrix[1][0];
+ totmat[1][1] = cob->matrix[1][1];
+ totmat[1][2] = cob->matrix[1][2];
+ Normalize(totmat[1]);
+
+ /* the z axis gets mapped onto a third orthogonal vector */
+ Crossf(totmat[2], totmat[0], totmat[1]);
+ }
+ break;
+ case TRACK_nZ: /* LOCK Y TRACK -Z */
+ {
+ /* Projection of Vector on the plane */
+ Projf(vec2, vec, cob->matrix[1]);
+ VecSubf(totmat[2], vec, vec2);
+ Normalize(totmat[2]);
+ VecMulf(totmat[2],-1);
+
+ /* the y axis is fixed */
+ totmat[1][0] = cob->matrix[1][0];
+ totmat[1][1] = cob->matrix[1][1];
+ totmat[1][2] = cob->matrix[1][2];
+ Normalize(totmat[1]);
+
+ /* the z axis gets mapped onto a third orthogonal vector */
+ Crossf(totmat[0], totmat[1], totmat[2]);
+ }
+ break;
+ default:
+ {
+ totmat[0][0] = 1;totmat[0][1] = 0;totmat[0][2] = 0;
+ totmat[1][0] = 0;totmat[1][1] = 1;totmat[1][2] = 0;
+ totmat[2][0] = 0;totmat[2][1] = 0;totmat[2][2] = 1;
+ }
+ break;
+ }
+ }
+ break;
+ case LOCK_Z: /* LOCK Z */
+ {
+ switch (data->trackflag) {
+ case TRACK_X: /* LOCK Z TRACK X */
+ {
+ /* Projection of Vector on the plane */
+ Projf(vec2, vec, cob->matrix[2]);
+ VecSubf(totmat[0], vec, vec2);
+ Normalize(totmat[0]);
+
+ /* the z axis is fixed */
+ totmat[2][0] = cob->matrix[2][0];
+ totmat[2][1] = cob->matrix[2][1];
+ totmat[2][2] = cob->matrix[2][2];
+ Normalize(totmat[2]);
+
+ /* the x axis gets mapped onto a third orthogonal vector */
+ Crossf(totmat[1], totmat[2], totmat[0]);
+ }
+ break;
+ case TRACK_Y: /* LOCK Z TRACK Y */
+ {
+ /* Projection of Vector on the plane */
+ Projf(vec2, vec, cob->matrix[2]);
+ VecSubf(totmat[1], vec, vec2);
+ Normalize(totmat[1]);
+
+ /* the z axis is fixed */
+ totmat[2][0] = cob->matrix[2][0];
+ totmat[2][1] = cob->matrix[2][1];
+ totmat[2][2] = cob->matrix[2][2];
+ Normalize(totmat[2]);
+
+ /* the x axis gets mapped onto a third orthogonal vector */
+ Crossf(totmat[0], totmat[1], totmat[2]);
+ }
+ break;
+ case TRACK_nX: /* LOCK Z TRACK -X */
+ {
+ /* Projection of Vector on the plane */
+ Projf(vec2, vec, cob->matrix[2]);
+ VecSubf(totmat[0], vec, vec2);
+ Normalize(totmat[0]);
+ VecMulf(totmat[0],-1);
+
+ /* the z axis is fixed */
+ totmat[2][0] = cob->matrix[2][0];
+ totmat[2][1] = cob->matrix[2][1];
+ totmat[2][2] = cob->matrix[2][2];
+ Normalize(totmat[2]);
+
+ /* the x axis gets mapped onto a third orthogonal vector */
+ Crossf(totmat[1], totmat[2], totmat[0]);
+ }
+ break;
+ case TRACK_nY: /* LOCK Z TRACK -Y */
+ {
+ /* Projection of Vector on the plane */
+ Projf(vec2, vec, cob->matrix[2]);
+ VecSubf(totmat[1], vec, vec2);
+ Normalize(totmat[1]);
+ VecMulf(totmat[1],-1);
+
+ /* the z axis is fixed */
+ totmat[2][0] = cob->matrix[2][0];
+ totmat[2][1] = cob->matrix[2][1];
+ totmat[2][2] = cob->matrix[2][2];
+ Normalize(totmat[2]);
+
+ /* the x axis gets mapped onto a third orthogonal vector */
+ Crossf(totmat[0], totmat[1], totmat[2]);
+ }
+ break;
+ default:
+ {
+ totmat[0][0] = 1;totmat[0][1] = 0;totmat[0][2] = 0;
+ totmat[1][0] = 0;totmat[1][1] = 1;totmat[1][2] = 0;
+ totmat[2][0] = 0;totmat[2][1] = 0;totmat[2][2] = 1;
+ }
+ break;
+ }
+ }
+ break;
+ default:
+ {
+ totmat[0][0] = 1;totmat[0][1] = 0;totmat[0][2] = 0;
+ totmat[1][0] = 0;totmat[1][1] = 1;totmat[1][2] = 0;
+ totmat[2][0] = 0;totmat[2][1] = 0;totmat[2][2] = 1;
+ }
+ break;
+ }
+ /* Block to keep matrix heading */
+ tmpmat[0][0] = cob->matrix[0][0];tmpmat[0][1] = cob->matrix[0][1];tmpmat[0][2] = cob->matrix[0][2];
+ tmpmat[1][0] = cob->matrix[1][0];tmpmat[1][1] = cob->matrix[1][1];tmpmat[1][2] = cob->matrix[1][2];
+ tmpmat[2][0] = cob->matrix[2][0];tmpmat[2][1] = cob->matrix[2][1];tmpmat[2][2] = cob->matrix[2][2];
+ Normalize(tmpmat[0]);
+ Normalize(tmpmat[1]);
+ Normalize(tmpmat[2]);
+ Mat3Inv(invmat, tmpmat);
+ Mat3MulMat3(tmpmat, totmat, invmat);
+ totmat[0][0] = tmpmat[0][0];totmat[0][1] = tmpmat[0][1];totmat[0][2] = tmpmat[0][2];
+ totmat[1][0] = tmpmat[1][0];totmat[1][1] = tmpmat[1][1];totmat[1][2] = tmpmat[1][2];
+ totmat[2][0] = tmpmat[2][0];totmat[2][1] = tmpmat[2][1];totmat[2][2] = tmpmat[2][2];
+
+ Mat4CpyMat4(tmat, cob->matrix);
+
+ mdet = Det3x3( totmat[0][0],totmat[0][1],totmat[0][2],
+ totmat[1][0],totmat[1][1],totmat[1][2],
+ totmat[2][0],totmat[2][1],totmat[2][2]);
+ if (mdet==0) {
+ totmat[0][0] = 1;totmat[0][1] = 0;totmat[0][2] = 0;
+ totmat[1][0] = 0;totmat[1][1] = 1;totmat[1][2] = 0;
+ totmat[2][0] = 0;totmat[2][1] = 0;totmat[2][2] = 1;
+ }
+
+ /* apply out transformaton to the object */
+ Mat4MulMat34(cob->matrix, totmat, tmat);
+ }
+}
+
+static bConstraintTypeInfo CTI_LOCKTRACK = {
+ CONSTRAINT_TYPE_LOCKTRACK, /* type */
+ sizeof(bLockTrackConstraint), /* size */
+ "Locked Track", /* name */
+ "bLockTrackConstraint", /* struct name */
+ NULL, /* free data */
+ NULL, /* relink data */
+ NULL, /* copy data */
+ locktrack_new_data, /* new data */
+ locktrack_get_tars, /* get constraint targets */
+ locktrack_flush_tars, /* flush constraint targets */
+ default_get_tarmat, /* get target matrix */
+ locktrack_evaluate /* evaluate */
+};
+
+/* ---------- Stretch To ------------ */
+
+static void stretchto_new_data (void *cdata)
+{
+ bStretchToConstraint *data= (bStretchToConstraint *)cdata;
+
+ data->volmode = 0;
+ data->plane = 0;
+ data->orglength = 0.0;
+ data->bulge = 1.0;
+}
+
+static void stretchto_get_tars (bConstraint *con, ListBase *list)
+{
+ if (con && list) {
+ bStretchToConstraint *data= con->data;
+ bConstraintTarget *ct;
+
+ /* standard target-getting macro for single-target constraints */
+ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list)
+ }
+}
+
+static void stretchto_flush_tars (bConstraint *con, ListBase *list, short nocopy)
+{
+ if (con && list) {
+ bStretchToConstraint *data= con->data;
+ bConstraintTarget *ct= list->first;
+
+ /* the following macro is used for all standard single-target constraints */
+ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, nocopy)
+ }
+}
+
+static void stretchto_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets)
+{
+ bStretchToConstraint *data= con->data;
+ bConstraintTarget *ct= targets->first;
+
+ /* only evaluate if there is a target */
+ if (VALID_CONS_TARGET(ct)) {
+ float size[3], scale[3], vec[3], xx[3], zz[3], orth[3];
+ float totmat[3][3];
+ float tmat[4][4];
+ float dist;
+
+ /* store scaling before destroying obmat */
+ Mat4ToSize(cob->matrix, size);
+
+ /* store X orientation before destroying obmat */
+ xx[0] = cob->matrix[0][0];
+ xx[1] = cob->matrix[0][1];
+ xx[2] = cob->matrix[0][2];
+ Normalize(xx);
+
+ /* store Z orientation before destroying obmat */
+ zz[0] = cob->matrix[2][0];
+ zz[1] = cob->matrix[2][1];
+ zz[2] = cob->matrix[2][2];
+ Normalize(zz);
+
+ VecSubf(vec, cob->matrix[3], ct->matrix[3]);
+ vec[0] /= size[0];
+ vec[1] /= size[1];
+ vec[2] /= size[2];
+
+ dist = Normalize(vec);
+ //dist = VecLenf( ob->obmat[3], targetmat[3]);
+
+ /* data->orglength==0 occurs on first run, and after 'R' button is clicked */
+ if (data->orglength == 0)
+ data->orglength = dist;
+ if (data->bulge == 0)
+ data->bulge = 1.0;
+
+ scale[1] = dist/data->orglength;
+ switch (data->volmode) {
+ /* volume preserving scaling */
+ case VOLUME_XZ :
+ scale[0] = 1.0f - (float)sqrt(data->bulge) + (float)sqrt(data->bulge*(data->orglength/dist));
+ scale[2] = scale[0];
+ break;
+ case VOLUME_X:
+ scale[0] = 1.0f + data->bulge * (data->orglength /dist - 1);
+ scale[2] = 1.0;
+ break;
+ case VOLUME_Z:
+ scale[0] = 1.0;
+ scale[2] = 1.0f + data->bulge * (data->orglength /dist - 1);
+ break;
+ /* don't care for volume */
+ case NO_VOLUME:
+ scale[0] = 1.0;
+ scale[2] = 1.0;
+ break;
+ default: /* should not happen, but in case*/
+ return;
+ } /* switch (data->volmode) */
+
+ /* Clear the object's rotation and scale */
+ cob->matrix[0][0]=size[0]*scale[0];
+ cob->matrix[0][1]=0;
+ cob->matrix[0][2]=0;
+ cob->matrix[1][0]=0;
+ cob->matrix[1][1]=size[1]*scale[1];
+ cob->matrix[1][2]=0;
+ cob->matrix[2][0]=0;
+ cob->matrix[2][1]=0;
+ cob->matrix[2][2]=size[2]*scale[2];
+
+ VecSubf(vec, cob->matrix[3], ct->matrix[3]);
+ Normalize(vec);
+
+ /* new Y aligns object target connection*/
+ totmat[1][0] = -vec[0];
+ totmat[1][1] = -vec[1];
+ totmat[1][2] = -vec[2];
+ switch (data->plane) {
+ case PLANE_X:
+ /* build new Z vector */
+ /* othogonal to "new Y" "old X! plane */
+ Crossf(orth, vec, xx);
+ Normalize(orth);
+
+ /* new Z*/
+ totmat[2][0] = orth[0];
+ totmat[2][1] = orth[1];
+ totmat[2][2] = orth[2];
+
+ /* we decided to keep X plane*/
+ Crossf(xx, orth, vec);
+ Normalize(xx);
+ totmat[0][0] = xx[0];
+ totmat[0][1] = xx[1];
+ totmat[0][2] = xx[2];
+ break;
+ case PLANE_Z:
+ /* build new X vector */
+ /* othogonal to "new Y" "old Z! plane */
+ Crossf(orth, vec, zz);
+ Normalize(orth);
+
+ /* new X */
+ totmat[0][0] = -orth[0];
+ totmat[0][1] = -orth[1];
+ totmat[0][2] = -orth[2];
+
+ /* we decided to keep Z */
+ Crossf(zz, orth, vec);
+ Normalize(zz);
+ totmat[2][0] = zz[0];
+ totmat[2][1] = zz[1];
+ totmat[2][2] = zz[2];
+ break;
+ } /* switch (data->plane) */
+
+ Mat4CpyMat4(tmat, cob->matrix);
+ Mat4MulMat34(cob->matrix, totmat, tmat);
+ }
+}
+
+static bConstraintTypeInfo CTI_STRETCHTO = {
+ CONSTRAINT_TYPE_STRETCHTO, /* type */
+ sizeof(bStretchToConstraint), /* size */
+ "Stretch To", /* name */
+ "bStretchToConstraint", /* struct name */
+ NULL, /* free data */
+ NULL, /* relink data */
+ NULL, /* copy data */
+ stretchto_new_data, /* new data */
+ stretchto_get_tars, /* get constraint targets */
+ stretchto_flush_tars, /* flush constraint targets */
+ default_get_tarmat, /* get target matrix */
+ stretchto_evaluate /* evaluate */
+};
+
+/* ---------- Floor ------------ */
+
+static void minmax_new_data (void *cdata)
+{
+ bMinMaxConstraint *data= (bMinMaxConstraint *)cdata;
+
+ data->minmaxflag = TRACK_Z;
+ data->offset = 0.0f;
+ data->cache[0] = data->cache[1] = data->cache[2] = 0.0f;
+ data->flag = 0;
+}
+
+static void minmax_get_tars (bConstraint *con, ListBase *list)
+{
+ if (con && list) {
+ bMinMaxConstraint *data= con->data;
+ bConstraintTarget *ct;
+
+ /* standard target-getting macro for single-target constraints */
+ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list)
+ }
+}
+
+static void minmax_flush_tars (bConstraint *con, ListBase *list, short nocopy)
+{
+ if (con && list) {
+ bMinMaxConstraint *data= con->data;
+ bConstraintTarget *ct= list->first;
+
+ /* the following macro is used for all standard single-target constraints */
+ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, nocopy)
+ }
+}
+
+static void minmax_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets)
+{
+ bMinMaxConstraint *data= con->data;
+ bConstraintTarget *ct= targets->first;
+
+ /* only evaluate if there is a target */
+ if (VALID_CONS_TARGET(ct)) {
+ float obmat[4][4], imat[4][4], tarmat[4][4], tmat[4][4];
+ float val1, val2;
+ int index;
+
+ Mat4CpyMat4(obmat, cob->matrix);
+ Mat4CpyMat4(tarmat, ct->matrix);
+
+ if (data->flag & MINMAX_USEROT) {
+ /* take rotation of target into account by doing the transaction in target's localspace */
+ Mat4Invert(imat, tarmat);
+ Mat4MulMat4(tmat, obmat, imat);
+ Mat4CpyMat4(obmat, tmat);
+ Mat4One(tarmat);
+ }
+
+ switch (data->minmaxflag) {
+ case TRACK_Z:
+ val1 = tarmat[3][2];
+ val2 = obmat[3][2]-data->offset;
+ index = 2;
+ break;
+ case TRACK_Y:
+ val1 = tarmat[3][1];
+ val2 = obmat[3][1]-data->offset;
+ index = 1;
+ break;
+ case TRACK_X:
+ val1 = tarmat[3][0];
+ val2 = obmat[3][0]-data->offset;
+ index = 0;
+ break;
+ case TRACK_nZ:
+ val2 = tarmat[3][2];
+ val1 = obmat[3][2]-data->offset;
+ index = 2;
+ break;
+ case TRACK_nY:
+ val2 = tarmat[3][1];
+ val1 = obmat[3][1]-data->offset;
+ index = 1;
+ break;
+ case TRACK_nX:
+ val2 = tarmat[3][0];
+ val1 = obmat[3][0]-data->offset;
+ index = 0;
+ break;
+ default:
+ return;
+ }
+
+ if (val1 > val2) {
+ obmat[3][index] = tarmat[3][index] + data->offset;
+ if (data->flag & MINMAX_STICKY) {
+ if (data->flag & MINMAX_STUCK) {
+ VECCOPY(obmat[3], data->cache);
+ }
+ else {
+ VECCOPY(data->cache, obmat[3]);
+ data->flag |= MINMAX_STUCK;
+ }
+ }
+ if (data->flag & MINMAX_USEROT) {
+ /* get out of localspace */
+ Mat4MulMat4(tmat, obmat, ct->matrix);
+ Mat4CpyMat4(cob->matrix, tmat);
+ }
+ else {
+ VECCOPY(cob->matrix[3], obmat[3]);
+ }
+ }
+ else {
+ data->flag &= ~MINMAX_STUCK;
+ }
+ }
+}
+
+static bConstraintTypeInfo CTI_MINMAX = {
+ CONSTRAINT_TYPE_MINMAX, /* type */
+ sizeof(bMinMaxConstraint), /* size */
+ "Floor", /* name */
+ "bMinMaxConstraint", /* struct name */
+ NULL, /* free data */
+ NULL, /* relink data */
+ NULL, /* copy data */
+ minmax_new_data, /* new data */
+ minmax_get_tars, /* get constraint targets */
+ minmax_flush_tars, /* flush constraint targets */
+ default_get_tarmat, /* get target matrix */
+ minmax_evaluate /* evaluate */
+};
+
+/* ------- RigidBody Joint ---------- */
+
+static void rbj_new_data (void *cdata)
+{
+ bRigidBodyJointConstraint *data= (bRigidBodyJointConstraint *)cdata;
+
+ // removed code which set target of this constraint
+ data->type=1;
+}
+
+static void rbj_get_tars (bConstraint *con, ListBase *list)
+{
+ if (con && list) {
+ bRigidBodyJointConstraint *data= con->data;
+ bConstraintTarget *ct;
+
+ /* standard target-getting macro for single-target constraints without subtargets */
+ SINGLETARGETNS_GET_TARS(con, data->tar, ct, list)
+ }
+}
+
+static void rbj_flush_tars (bConstraint *con, ListBase *list, short nocopy)
+{
+ if (con && list) {
+ bRigidBodyJointConstraint *data= con->data;
+ bConstraintTarget *ct= list->first;
+
+ /* the following macro is used for all standard single-target constraints */
+ SINGLETARGETNS_FLUSH_TARS(con, data->tar, ct, list, nocopy)
+ }
+}
+
+static bConstraintTypeInfo CTI_RIGIDBODYJOINT = {
+ CONSTRAINT_TYPE_RIGIDBODYJOINT, /* type */
+ sizeof(bRigidBodyJointConstraint), /* size */
+ "RigidBody Joint", /* name */
+ "bRigidBodyJointConstraint", /* struct name */
+ NULL, /* free data */
+ NULL, /* relink data */
+ NULL, /* copy data */
+ rbj_new_data, /* new data */
+ rbj_get_tars, /* get constraint targets */
+ rbj_flush_tars, /* flush constraint targets */
+ default_get_tarmat, /* get target matrix */
+ NULL /* evaluate - this is not solved here... is just an interface for game-engine */
+};
+
+/* -------- Clamp To ---------- */
+
+static void clampto_get_tars (bConstraint *con, ListBase *list)
+{
+ if (con && list) {
+ bClampToConstraint *data= con->data;
+ bConstraintTarget *ct;
+
+ /* standard target-getting macro for single-target constraints without subtargets */
+ SINGLETARGETNS_GET_TARS(con, data->tar, ct, list)
+ }
+}
+
+static void clampto_flush_tars (bConstraint *con, ListBase *list, short nocopy)
+{
+ if (con && list) {
+ bClampToConstraint *data= con->data;
+ bConstraintTarget *ct= list->first;
+
+ /* the following macro is used for all standard single-target constraints */
+ SINGLETARGETNS_FLUSH_TARS(con, data->tar, ct, list, nocopy)
+ }
+}
+
+static void clampto_get_tarmat (bConstraint *con, bConstraintOb *cob, bConstraintTarget *ct, float ctime)
+{
+ if (VALID_CONS_TARGET(ct)) {
+ Curve *cu= ct->tar->data;
+
+ /* note: when creating constraints that follow path, the curve gets the CU_PATH set now,
+ * currently for paths to work it needs to go through the bevlist/displist system (ton)
+ */
+
+ /* only happens on reload file, but violates depsgraph still... fix! */
+ if (cu->path==NULL || cu->path->data==NULL)
+ makeDispListCurveTypes(ct->tar, 0);
+ }
+
+ /* technically, this isn't really needed for evaluation, but we don't know what else
+ * might end up calling this...
+ */
+ if (ct)
+ Mat4One(ct->matrix);
+}
+
+static void clampto_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets)
+{
+ bClampToConstraint *data= con->data;
+ bConstraintTarget *ct= targets->first;
+
+ /* only evaluate if there is a target and it is a curve */
+ if (VALID_CONS_TARGET(ct) && (ct->tar->type == OB_CURVE)) {
+ Curve *cu= data->tar->data;
+ float obmat[4][4], targetMatrix[4][4], ownLoc[3];
+ float curveMin[3], curveMax[3];
+
+ Mat4CpyMat4(obmat, cob->matrix);
+ Mat4One(targetMatrix);
+ VECCOPY(ownLoc, obmat[3]);
+
+ INIT_MINMAX(curveMin, curveMax)
+ minmax_object(ct->tar, curveMin, curveMax);
+
+ /* get targetmatrix */
+ if (cu->path && cu->path->data) {
+ float vec[4], dir[3], totmat[4][4];
+ float curvetime;
+ short clamp_axis;
+
+ /* find best position on curve */
+ /* 1. determine which axis to sample on? */
+ if (data->flag == CLAMPTO_AUTO) {
+ float size[3];
+ VecSubf(size, curveMax, curveMin);
+
+ /* find axis along which the bounding box has the greatest
+ * extent. Otherwise, default to the x-axis, as that is quite
+ * frequently used.
+ */
+ if ((size[2]>size[0]) && (size[2]>size[1]))
+ clamp_axis= CLAMPTO_Z - 1;
+ else if ((size[1]>size[0]) && (size[1]>size[2]))
+ clamp_axis= CLAMPTO_Y - 1;
+ else
+ clamp_axis = CLAMPTO_X - 1;
+ }
+ else
+ clamp_axis= data->flag - 1;
+
+ /* 2. determine position relative to curve on a 0-1 scale based on bounding box */
+ if (data->flag2 & CLAMPTO_CYCLIC) {
+ /* cyclic, so offset within relative bounding box is used */
+ float len= (curveMax[clamp_axis] - curveMin[clamp_axis]);
+ float offset;
+
+ /* find bounding-box range where target is located */
+ if (ownLoc[clamp_axis] < curveMin[clamp_axis]) {
+ /* bounding-box range is before */
+ offset= curveMin[clamp_axis];
+
+ while (ownLoc[clamp_axis] < offset)
+ offset -= len;
+
+ /* now, we calculate as per normal, except using offset instead of curveMin[clamp_axis] */
+ curvetime = (ownLoc[clamp_axis] - offset) / (len);
+ }
+ else if (ownLoc[clamp_axis] > curveMax[clamp_axis]) {
+ /* bounding-box range is after */
+ offset= curveMax[clamp_axis];
+
+ while (ownLoc[clamp_axis] > offset) {
+ if ((offset + len) > ownLoc[clamp_axis])
+ break;
+ else
+ offset += len;
+ }
+
+ /* now, we calculate as per normal, except using offset instead of curveMax[clamp_axis] */
+ curvetime = (ownLoc[clamp_axis] - offset) / (len);
+ }
+ else {
+ /* as the location falls within bounds, just calculate */
+ curvetime = (ownLoc[clamp_axis] - curveMin[clamp_axis]) / (len);
+ }
+ }
+ else {
+ /* no cyclic, so position is clamped to within the bounding box */
+ if (ownLoc[clamp_axis] <= curveMin[clamp_axis])
+ curvetime = 0.0;
+ else if (ownLoc[clamp_axis] >= curveMax[clamp_axis])
+ curvetime = 1.0;
+ else
+ curvetime = (ownLoc[clamp_axis] - curveMin[clamp_axis]) / (curveMax[clamp_axis] - curveMin[clamp_axis]);
+ }
+
+ /* 3. position on curve */
+ if (where_on_path(ct->tar, curvetime, vec, dir) ) {
+ Mat4One(totmat);
+ VECCOPY(totmat[3], vec);
+
+ Mat4MulSerie(targetMatrix, ct->tar->obmat, totmat, NULL, NULL, NULL, NULL, NULL, NULL);
+ }
+ }
+
+ /* obtain final object position */
+ VECCOPY(cob->matrix[3], targetMatrix[3]);
+ }
+}
+
+static bConstraintTypeInfo CTI_CLAMPTO = {
+ CONSTRAINT_TYPE_CLAMPTO, /* type */
+ sizeof(bClampToConstraint), /* size */
+ "Clamp To", /* name */
+ "bClampToConstraint", /* struct name */
+ NULL, /* free data */
+ NULL, /* relink data */
+ NULL, /* copy data */
+ NULL, /* new data */
+ clampto_get_tars, /* get constraint targets */
+ clampto_flush_tars, /* flush constraint targets */
+ clampto_get_tarmat, /* get target matrix */
+ clampto_evaluate /* evaluate */
+};
+
+/* ---------- Transform Constraint ----------- */
+
+static void transform_new_data (void *cdata)
+{
+ bTransformConstraint *data= (bTransformConstraint *)cdata;
+
+ data->map[0]= 0;
+ data->map[1]= 1;
+ data->map[2]= 2;
+}
+
+static void transform_get_tars (bConstraint *con, ListBase *list)
+{
+ if (con && list) {
+ bTransformConstraint *data= con->data;
+ bConstraintTarget *ct;
+
+ /* standard target-getting macro for single-target constraints */
+ SINGLETARGET_GET_TARS(con, data->tar, data->subtarget, ct, list)
+ }
+}
+
+static void transform_flush_tars (bConstraint *con, ListBase *list, short nocopy)
+{
+ if (con && list) {
+ bTransformConstraint *data= con->data;
+ bConstraintTarget *ct= list->first;
+
+ /* the following macro is used for all standard single-target constraints */
+ SINGLETARGET_FLUSH_TARS(con, data->tar, data->subtarget, ct, list, nocopy)
+ }
+}
+
+static void transform_evaluate (bConstraint *con, bConstraintOb *cob, ListBase *targets)
+{
+ bTransformConstraint *data= con->data;
+ bConstraintTarget *ct= targets->first;
+
+ /* only evaluate if there is a target */
+ if (VALID_CONS_TARGET(ct)) {
+ float loc[3], eul[3], size[3];
+ float dvec[3], sval[3];
+ short i;
+
+ /* obtain target effect */
+ switch (data->from) {
+ case 2: /* scale */
+ Mat4ToSize(ct->matrix, dvec);
+ break;
+ case 1: /* rotation */
+ Mat4ToEul(ct->matrix, dvec);
+ break;
+ default: /* location */
+ VecCopyf(dvec, ct->matrix[3]);
+ break;
+ }
+
+ /* extract components of owner's matrix */
+ VECCOPY(loc, cob->matrix[3]);
+ Mat4ToEul(cob->matrix, eul);
+ Mat4ToSize(cob->matrix, size);
+
+ /* determine where in range current transforms lie */
+ if (data->expo) {
+ for (i=0; i<3; i++) {
+ if (data->from_max[i] - data->from_min[i])
+ sval[i]= (dvec[i] - data->from_min[i]) / (data->from_max[i] - data->from_min[i]);
+ else
+ sval[i]= 0.0f;
+ }
+ }
+ else {
+ /* clamp transforms out of range */
+ for (i=0; i<3; i++) {
+ CLAMP(dvec[i], data->from_min[i], data->from_max[i]);
+ if (data->from_max[i] - data->from_min[i])
+ sval[i]= (dvec[i] - data->from_min[i]) / (data->from_max[i] - data->from_min[i]);
+ else
+ sval[i]= 0.0f;
+ }
+ }
+
+ /* convert radian<->degree */
+ if (data->from==1 && data->to==0) {
+ /* from radians to degrees */
+ for (i=0; i<3; i++)
+ sval[i] = sval[i] / M_PI * 180;
+ }
+ else if (data->from==0 && data->to==1) {
+ /* from degrees to radians */
+ for (i=0; i<3; i++)
+ sval[i] = sval[i] / 180 * M_PI;
+ }
+
+ /* apply transforms */
+ switch (data->to) {
+ case 2: /* scaling */
+ for (i=0; i<3; i++)
+ size[i]= data->to_min[i] + (sval[data->map[i]] * (data->to_max[i] - data->to_min[i]));
+ break;
+ case 1: /* rotation */
+ for (i=0; i<3; i++) {
+ float tmin, tmax;
+
+ /* convert destination min/max ranges from degrees to radians */
+ tmin= data->to_min[i] / M_PI * 180;
+ tmax= data->to_max[i] / M_PI * 180;
+
+ eul[i]= tmin + (sval[data->map[i]] * (tmax - tmin));
+ }
+ break;
+ default: /* location */
+ /* get new location */
+ for (i=0; i<3; i++)
+ loc[i]= (data->to_min[i] + (sval[data->map[i]] * (data->to_max[i] - data->to_min[i])));
+
+ /* add original location back on (so that it can still be moved) */
+ VecAddf(loc, cob->matrix[3], loc);
+ break;
+ }
+
+ /* apply to matrix */
+ LocEulSizeToMat4(cob->matrix, loc, eul, size);
+ }
+}
+
+static bConstraintTypeInfo CTI_TRANSFORM = {
+ CONSTRAINT_TYPE_TRANSFORM, /* type */
+ sizeof(bTransformConstraint), /* size */
+ "Transform", /* name */
+ "bTransformConstraint", /* struct name */
+ NULL, /* free data */
+ NULL, /* relink data */
+ NULL, /* copy data */
+ transform_new_data, /* new data */
+ transform_get_tars, /* get constraint targets */
+ transform_flush_tars, /* flush constraint targets */
+ default_get_tarmat, /* get a target matrix */
+ transform_evaluate /* evaluate */
+};
+
+/* ************************* Constraints Type-Info *************************** */
+/* All of the constraints api functions use bConstraintTypeInfo structs to carry out
+ * and operations that involve constraint specifc code.
+ */
+
+/* These globals only ever get directly accessed in this file */
+static bConstraintTypeInfo *constraintsTypeInfo[NUM_CONSTRAINT_TYPES];
+static short CTI_INIT= 1; /* when non-zero, the list needs to be updated */
+
+/* This function only gets called when CTI_INIT is non-zero */
+static void constraints_init_typeinfo () {
+ constraintsTypeInfo[0]= NULL; /* 'Null' Constraint */
+ constraintsTypeInfo[1]= &CTI_CHILDOF; /* ChildOf Constraint */
+ constraintsTypeInfo[2]= &CTI_TRACKTO; /* TrackTo Constraint */
+ constraintsTypeInfo[3]= &CTI_KINEMATIC; /* IK Constraint */
+ constraintsTypeInfo[4]= &CTI_FOLLOWPATH; /* Follow-Path Constraint */
+ constraintsTypeInfo[5]= &CTI_ROTLIMIT; /* Limit Rotation Constraint */
+ constraintsTypeInfo[6]= &CTI_LOCLIMIT; /* Limit Location Constraint */
+ constraintsTypeInfo[7]= &CTI_SIZELIMIT; /* Limit Scaling Constraint */
+ constraintsTypeInfo[8]= &CTI_ROTLIKE; /* Copy Rotation Constraint */
+ constraintsTypeInfo[9]= &CTI_LOCLIKE; /* Copy Location Constraint */
+ constraintsTypeInfo[10]= &CTI_SIZELIKE; /* Copy Scaling Constraint */
+ constraintsTypeInfo[11]= &CTI_PYTHON; /* Python/Script Constraint */
+ constraintsTypeInfo[12]= &CTI_ACTION; /* Action Constraint */
+ constraintsTypeInfo[13]= &CTI_LOCKTRACK; /* Locked-Track Constraint */
+ constraintsTypeInfo[14]= NULL; /* 'Distance Limit' Constraint */
+ constraintsTypeInfo[15]= &CTI_STRETCHTO; /* StretchTo Constaint */
+ constraintsTypeInfo[16]= &CTI_MINMAX; /* Floor Constraint */
+ constraintsTypeInfo[17]= &CTI_RIGIDBODYJOINT; /* RigidBody Constraint */
+ constraintsTypeInfo[18]= &CTI_CLAMPTO; /* ClampTo Constraint */
+ constraintsTypeInfo[19]= &CTI_TRANSFORM; /* Transformation Constraint */
+}
+
+/* This function should be used for getting the appropriate type-info when only
+ * a constraint type is known
+ */
+bConstraintTypeInfo *get_constraint_typeinfo (int type)
+{
+ /* initialise the type-info list? */
+ if (CTI_INIT) {
+ constraints_init_typeinfo();
+ CTI_INIT = 0;
+ }
+
+ /* only return for valid types */
+ if ( (type >= CONSTRAINT_TYPE_NULL) &&
+ (type <= NUM_CONSTRAINT_TYPES ) )
+ {
+ /* there shouldn't be any segfaults here... */
+ return constraintsTypeInfo[type];
+ }
+ else {
+ printf("No valid constraint type-info data available. Type = %i \n", type);
+ }
+
+ return NULL;
+}
+
+/* This function should always be used to get the appropriate type-info, as it
+ * has checks which prevent segfaults in some weird cases.
+ */
+bConstraintTypeInfo *constraint_get_typeinfo (bConstraint *con)
+{
+ /* only return typeinfo for valid constraints */
+ if (con)
+ return get_constraint_typeinfo(con->type);
+ else
+ return NULL;
+}
+
+/* ************************* General Constraints API ************************** */
+/* The functions here are called by various parts of Blender. Very few (should be none if possible)
+ * constraint-specific code should occur here.
+ */
+
+/* ---------- Data Management ------- */
+
+/* Free data of a specific constraint if it has any info */
+void free_constraint_data (bConstraint *con)
+{
+ if (con->data) {
+ bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
+
+ /* perform any special freeing constraint may have */
+ if (cti && cti->free_data)
+ cti->free_data(con);
+
+ /* free constraint data now */
+ MEM_freeN(con->data);
+ }
+}
+
+/* Free all constraints from a constraint-stack */
+void free_constraints (ListBase *conlist)
+{
+ bConstraint *con;
+
+ /* Free constraint data and also any extra data */
+ for (con= conlist->first; con; con= con->next) {
+ free_constraint_data(con);
+ }
+
+ /* Free the whole list */
+ BLI_freelistN(conlist);
+}
+
+/* Reassign links that constraints have to other data (called during file loading?) */
+void relink_constraints (ListBase *conlist)
+{
+ bConstraint *con;
+ bConstraintTarget *ct;
+
+ for (con= conlist->first; con; con= con->next) {
+ bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
+
+ if (cti) {
+ /* relink any targets */
+ if (cti->get_constraint_targets) {
+ ListBase targets = {NULL, NULL};
+
+ cti->get_constraint_targets(con, &targets);
+ for (ct= targets.first; ct; ct= ct->next) {
+ ID_NEW(ct->tar);
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(con, &targets, 0);
+ }
+
+ /* relink any other special data */
+ if (cti->relink_data)
+ cti->relink_data(con);
+ }
+ }
+}
+
+/* duplicate all of the constraints in a constraint stack */
+void copy_constraints (ListBase *dst, ListBase *src)
+{
+ bConstraint *con, *srccon;
+
+ dst->first= dst->last= NULL;
+ duplicatelist(dst, src);
+
+ for (con=dst->first, srccon=src->first; con; srccon=srccon->next, con=con->next) {
+ bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
+
+ /* make a new copy of the constraint's data */
+ con->data = MEM_dupallocN(con->data);
+
+ /* only do specific constraints if required */
+ if (cti && cti->copy_data)
+ cti->copy_data(con, srccon);
+ }
+}
+
+/* -------- Target-Matrix Stuff ------- */
+
+/* This function is a relic from the prior implementations of the constraints system, when all
+ * constraints either had one or no targets. It used to be called during the main constraint solving
+ * loop, but is now only used for the remaining cases for a few constraints.
+ *
+ * None of the actual calculations of the matricies should be done here! Also, this function is
+ * not to be used by any new constraints, particularly any that have multiple targets.
+ */
+void get_constraint_target_matrix (bConstraint *con, int n, short ownertype, void *ownerdata, float mat[][4], float ctime)
+{
+ bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
+ ListBase targets = {NULL, NULL};
+ bConstraintOb *cob;
+ bConstraintTarget *ct;
+
+ if (cti && cti->get_constraint_targets) {
+ /* make 'constraint-ob' */
+ cob= MEM_callocN(sizeof(bConstraintOb), "tempConstraintOb");
+ cob->type= ownertype;
+ switch (ownertype) {
+ case CONSTRAINT_OBTYPE_OBJECT: /* it is usually this case */
+ {
+ cob->ob= (Object *)ownerdata;
+ cob->pchan= NULL;
+ if (cob->ob) {
+ Mat4CpyMat4(cob->matrix, cob->ob->obmat);
+ Mat4CpyMat4(cob->startmat, cob->matrix);
+ }
+ else {
+ Mat4One(cob->matrix);
+ Mat4One(cob->startmat);
+ }
+ }
+ break;
+ case CONSTRAINT_OBTYPE_BONE: /* this may occur in some cases */
+ {
+ cob->ob= NULL; /* this might not work at all :/ */
+ cob->pchan= (bPoseChannel *)ownerdata;
+ if (cob->pchan) {
+ Mat4CpyMat4(cob->matrix, cob->pchan->pose_mat);
+ Mat4CpyMat4(cob->startmat, cob->matrix);
+ }
+ else {
+ Mat4One(cob->matrix);
+ Mat4One(cob->startmat);
+ }
+ }
+ break;
+ }
+
+ /* get targets - we only need the first one though (and there should only be one) */
+ cti->get_constraint_targets(con, &targets);
+
+ /* only calculate the target matrix on the first target */
+ ct= (bConstraintTarget *)targets.first;
+ while(ct && n-- > 0)
+ ct= ct->next;
+
+ if (ct) {
+ if (cti->get_target_matrix)
+ cti->get_target_matrix(con, cob, ct, ctime);
+ Mat4CpyMat4(mat, ct->matrix);
+ }
+
+ /* free targets + 'constraint-ob' */
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(con, &targets, 1);
+ MEM_freeN(cob);
+ }
+ else {
+ /* invalid constraint - perhaps... */
+ Mat4One(mat);
+ }
+}
+
+/* ---------- Evaluation ----------- */
+
+/* This function is called whenever constraints need to be evaluated. Currently, all
+ * constraints that can be evaluated are everytime this gets run.
+ *
+ * constraints_make_evalob and constraints_clear_evalob should be called before and
+ * after running this function, to sort out cob
+ */
+void solve_constraints (ListBase *conlist, bConstraintOb *cob, float ctime)
+{
+ bConstraint *con;
+ float solution[4][4], delta[4][4];
+ float oldmat[4][4], imat[4][4];
+ float enf;
+
+ /* check that there is a valid constraint object to evaluate */
+ if (cob == NULL)
+ return;
+
+ /* loop over available constraints, solving and blending them */
+ for (con= conlist->first; con; con= con->next) {
+ bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
+ ListBase targets = {NULL, NULL};
+
+ /* these we can skip completely (invalid constraints...) */
+ if (cti == NULL) continue;
+ if (con->flag & CONSTRAINT_DISABLE) continue;
+ /* these constraints can't be evaluated anyway */
+ if (cti->evaluate_constraint == NULL) continue;
+ /* influence == 0 should be ignored */
+ if (con->enforce == 0.0f) continue;
+
+ /* influence of constraint
+ * - value should have been set from IPO's/Constraint Channels already
+ */
+ enf = con->enforce;
+
+ /* move owner matrix into right space */
+ constraint_mat_convertspace(cob->ob, cob->pchan, cob->matrix, CONSTRAINT_SPACE_WORLD, con->ownspace);
+ Mat4CpyMat4(oldmat, cob->matrix);
+
+ /* prepare targets for constraint solving */
+ if (cti->get_constraint_targets) {
+ bConstraintTarget *ct;
+
+ /* get targets
+ * - constraints should use ct->matrix, not directly accessing values
+ * - ct->matrix members have not yet been calculated here!
+ */
+ cti->get_constraint_targets(con, &targets);
+
+ /* set matrices
+ * - calculate if possible, otherwise just initialise as identity matrix
+ */
+ if (cti->get_target_matrix) {
+ for (ct= targets.first; ct; ct= ct->next)
+ cti->get_target_matrix(con, cob, ct, ctime);
+ }
+ else {
+ for (ct= targets.first; ct; ct= ct->next)
+ Mat4One(ct->matrix);
+ }
+ }
+
+ /* Solve the constraint */
+ cti->evaluate_constraint(con, cob, &targets);
+
+ /* clear targets after use
+ * - this should free temp targets but no data should be copied back
+ * as constraints may have done some nasty things to it...
+ */
+ if (cti->flush_constraint_targets) {
+ cti->flush_constraint_targets(con, &targets, 1);
+ }
+
+ /* Interpolate the enforcement, to blend result of constraint into final owner transform */
+ /* 1. Remove effects of original matrix from constraint solution ==> delta */
+ Mat4Invert(imat, oldmat);
+ Mat4CpyMat4(solution, cob->matrix);
+ Mat4MulMat4(delta, solution, imat);
+
+ /* 2. If constraint influence is not full strength, then interpolate
+ * identity_matrix --> delta_matrix to get the effect the constraint actually exerts
+ */
+ if (enf < 1.0) {
+ float identity[4][4];
+ Mat4One(identity);
+ Mat4BlendMat4(delta, identity, delta, enf);
+ }
+
+ /* 3. Now multiply the delta by the matrix in use before the evaluation */
+ Mat4MulMat4(cob->matrix, delta, oldmat);
+
+ /* move owner back into worldspace for next constraint/other business */
+ if ((con->flag & CONSTRAINT_SPACEONCE) == 0)
+ constraint_mat_convertspace(cob->ob, cob->pchan, cob->matrix, con->ownspace, CONSTRAINT_SPACE_WORLD);
+ }
+}
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
new file mode 100644
index 00000000000..ece0a7f1d6c
--- /dev/null
+++ b/source/blender/blenkernel/intern/curve.c
@@ -0,0 +1,2595 @@
+
+/* curve.c
+ *
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <math.h> // floor
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "DNA_object_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_material_types.h"
+
+/* for dereferencing pointers */
+#include "DNA_ID.h"
+#include "DNA_vfont_types.h"
+#include "DNA_key_types.h"
+#include "DNA_ipo_types.h"
+
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_utildefines.h" // VECCOPY
+#include "BKE_object.h"
+#include "BKE_mesh.h"
+#include "BKE_curve.h"
+#include "BKE_displist.h"
+#include "BKE_ipo.h"
+#include "BKE_anim.h"
+#include "BKE_library.h"
+#include "BKE_key.h"
+
+
+/* globals */
+
+extern ListBase editNurb; /* editcurve.c */
+
+/* local */
+int cu_isectLL(float *v1, float *v2, float *v3, float *v4,
+ short cox, short coy,
+ float *labda, float *mu, float *vec);
+
+void unlink_curve(Curve *cu)
+{
+ int a;
+
+ for(a=0; a<cu->totcol; a++) {
+ if(cu->mat[a]) cu->mat[a]->id.us--;
+ cu->mat[a]= 0;
+ }
+ if(cu->vfont) cu->vfont->id.us--;
+ cu->vfont= 0;
+ if(cu->key) cu->key->id.us--;
+ cu->key= 0;
+ if(cu->ipo) cu->ipo->id.us--;
+ cu->ipo= 0;
+}
+
+
+/* niet curve zelf vrijgeven */
+void free_curve(Curve *cu)
+{
+
+ freeNurblist(&cu->nurb);
+ BLI_freelistN(&cu->bev);
+ freedisplist(&cu->disp);
+
+ unlink_curve(cu);
+
+ if(cu->mat) MEM_freeN(cu->mat);
+ if(cu->str) MEM_freeN(cu->str);
+ if(cu->strinfo) MEM_freeN(cu->strinfo);
+ if(cu->bb) MEM_freeN(cu->bb);
+ if(cu->path) free_path(cu->path);
+ if(cu->tb) MEM_freeN(cu->tb);
+}
+
+Curve *add_curve(char *name, int type)
+{
+ Curve *cu;
+
+ cu= alloc_libblock(&G.main->curve, ID_CU, name);
+
+ cu->size[0]= cu->size[1]= cu->size[2]= 1.0;
+ cu->flag= CU_FRONT+CU_BACK;
+ cu->pathlen= 100;
+ cu->resolu= cu->resolv= 12;
+ cu->width= 1.0;
+ cu->wordspace = 1.0;
+ cu->spacing= cu->linedist= 1.0;
+ cu->fsize= 1.0;
+ cu->ulheight = 0.05;
+ cu->texflag= CU_AUTOSPACE;
+
+ cu->bb= unit_boundbox();
+
+ return cu;
+}
+
+Curve *copy_curve(Curve *cu)
+{
+ Curve *cun;
+ int a;
+
+ cun= copy_libblock(cu);
+ cun->nurb.first= cun->nurb.last= 0;
+ duplicateNurblist( &(cun->nurb), &(cu->nurb));
+
+ cun->mat= MEM_dupallocN(cu->mat);
+ for(a=0; a<cun->totcol; a++) {
+ id_us_plus((ID *)cun->mat[a]);
+ }
+
+ cun->str= MEM_dupallocN(cu->str);
+ cun->strinfo= MEM_dupallocN(cu->strinfo);
+ cun->tb= MEM_dupallocN(cu->tb);
+ cun->bb= MEM_dupallocN(cu->bb);
+
+ cun->key= copy_key(cu->key);
+ if(cun->key) cun->key->from= (ID *)cun;
+
+ cun->disp.first= cun->disp.last= 0;
+ cun->bev.first= cun->bev.last= 0;
+ cun->path= 0;
+
+ /* single user ipo too */
+ if(cun->ipo) cun->ipo= copy_ipo(cun->ipo);
+
+ id_us_plus((ID *)cun->vfont);
+ id_us_plus((ID *)cun->vfontb);
+ id_us_plus((ID *)cun->vfonti);
+ id_us_plus((ID *)cun->vfontbi);
+
+ return cun;
+}
+
+void make_local_curve(Curve *cu)
+{
+ Object *ob = 0;
+ Curve *cun;
+ int local=0, lib=0;
+
+ /* - when there are only lib users: don't do
+ * - when there are only local users: set flag
+ * - mixed: do a copy
+ */
+
+ if(cu->id.lib==0) return;
+
+ if(cu->vfont) cu->vfont->id.lib= 0;
+
+ if(cu->id.us==1) {
+ cu->id.lib= 0;
+ cu->id.flag= LIB_LOCAL;
+ new_id(0, (ID *)cu, 0);
+ return;
+ }
+
+ ob= G.main->object.first;
+ while(ob) {
+ if(ob->data==cu) {
+ if(ob->id.lib) lib= 1;
+ else local= 1;
+ }
+ ob= ob->id.next;
+ }
+
+ if(local && lib==0) {
+ cu->id.lib= 0;
+ cu->id.flag= LIB_LOCAL;
+ new_id(0, (ID *)cu, 0);
+ }
+ else if(local && lib) {
+ cun= copy_curve(cu);
+ cun->id.us= 0;
+
+ ob= G.main->object.first;
+ while(ob) {
+ if(ob->data==cu) {
+
+ if(ob->id.lib==0) {
+ ob->data= cun;
+ cun->id.us++;
+ cu->id.us--;
+ }
+ }
+ ob= ob->id.next;
+ }
+ }
+}
+
+short curve_type(Curve *cu)
+{
+ Nurb *nu;
+ if(cu->vfont) {
+ return OB_FONT;
+ }
+ for (nu= cu->nurb.first; nu; nu= nu->next) {
+ if(nu->pntsv>1) {
+ return OB_SURF;
+ }
+ }
+
+ return OB_CURVE;
+}
+
+void test_curve_type(Object *ob)
+{
+ ob->type = curve_type(ob->data);
+}
+
+void tex_space_curve(Curve *cu)
+{
+ DispList *dl;
+ BoundBox *bb;
+ float *data, min[3], max[3], loc[3], size[3];
+ int tot, doit= 0;
+
+ if(cu->bb==NULL) cu->bb= MEM_callocN(sizeof(BoundBox), "boundbox");
+ bb= cu->bb;
+
+ INIT_MINMAX(min, max);
+
+ dl= cu->disp.first;
+ while(dl) {
+
+ if(dl->type==DL_INDEX3 || dl->type==DL_INDEX3) tot= dl->nr;
+ else tot= dl->nr*dl->parts;
+
+ if(tot) doit= 1;
+ data= dl->verts;
+ while(tot--) {
+ DO_MINMAX(data, min, max);
+ data+= 3;
+ }
+ dl= dl->next;
+ }
+
+ if(!doit) {
+ min[0] = min[1] = min[2] = -1.0f;
+ max[0] = max[1] = max[2] = 1.0f;
+ }
+
+ loc[0]= (min[0]+max[0])/2.0f;
+ loc[1]= (min[1]+max[1])/2.0f;
+ loc[2]= (min[2]+max[2])/2.0f;
+
+ size[0]= (max[0]-min[0])/2.0f;
+ size[1]= (max[1]-min[1])/2.0f;
+ size[2]= (max[2]-min[2])/2.0f;
+
+ boundbox_set_from_min_max(bb, min, max);
+
+ if(cu->texflag & CU_AUTOSPACE) {
+ VECCOPY(cu->loc, loc);
+ VECCOPY(cu->size, size);
+ cu->rot[0]= cu->rot[1]= cu->rot[2]= 0.0;
+
+ if(cu->size[0]==0.0) cu->size[0]= 1.0;
+ else if(cu->size[0]>0.0 && cu->size[0]<0.00001) cu->size[0]= 0.00001;
+ else if(cu->size[0]<0.0 && cu->size[0]> -0.00001) cu->size[0]= -0.00001;
+
+ if(cu->size[1]==0.0) cu->size[1]= 1.0;
+ else if(cu->size[1]>0.0 && cu->size[1]<0.00001) cu->size[1]= 0.00001;
+ else if(cu->size[1]<0.0 && cu->size[1]> -0.00001) cu->size[1]= -0.00001;
+
+ if(cu->size[2]==0.0) cu->size[2]= 1.0;
+ else if(cu->size[2]>0.0 && cu->size[2]<0.00001) cu->size[2]= 0.00001;
+ else if(cu->size[2]<0.0 && cu->size[2]> -0.00001) cu->size[2]= -0.00001;
+
+ }
+}
+
+
+int count_curveverts(ListBase *nurb)
+{
+ Nurb *nu;
+ int tot=0;
+
+ nu= nurb->first;
+ while(nu) {
+ if(nu->bezt) tot+= 3*nu->pntsu;
+ else if(nu->bp) tot+= nu->pntsu*nu->pntsv;
+
+ nu= nu->next;
+ }
+ return tot;
+}
+
+int count_curveverts_without_handles(ListBase *nurb)
+{
+ Nurb *nu;
+ int tot=0;
+
+ nu= nurb->first;
+ while(nu) {
+ if(nu->bezt) tot+= nu->pntsu;
+ else if(nu->bp) tot+= nu->pntsu*nu->pntsv;
+
+ nu= nu->next;
+ }
+ return tot;
+}
+
+/* **************** NURBS ROUTINES ******************** */
+
+void freeNurb(Nurb *nu)
+{
+
+ if(nu==0) return;
+
+ if(nu->bezt) MEM_freeN(nu->bezt);
+ nu->bezt= 0;
+ if(nu->bp) MEM_freeN(nu->bp);
+ nu->bp= 0;
+ if(nu->knotsu) MEM_freeN(nu->knotsu);
+ nu->knotsu= 0;
+ if(nu->knotsv) MEM_freeN(nu->knotsv);
+ nu->knotsv= 0;
+ /* if(nu->trim.first) freeNurblist(&(nu->trim)); */
+
+ MEM_freeN(nu);
+
+}
+
+
+void freeNurblist(ListBase *lb)
+{
+ Nurb *nu, *next;
+
+ if(lb==0) return;
+
+ nu= lb->first;
+ while(nu) {
+ next= nu->next;
+ freeNurb(nu);
+ nu= next;
+ }
+ lb->first= lb->last= 0;
+}
+
+Nurb *duplicateNurb(Nurb *nu)
+{
+ Nurb *newnu;
+ int len;
+
+ newnu= (Nurb*)MEM_mallocN(sizeof(Nurb),"duplicateNurb");
+ if(newnu==0) return 0;
+ memcpy(newnu, nu, sizeof(Nurb));
+
+ if(nu->bezt) {
+ newnu->bezt=
+ (BezTriple*)MEM_mallocN((nu->pntsu)* sizeof(BezTriple),"duplicateNurb2");
+ memcpy(newnu->bezt, nu->bezt, nu->pntsu*sizeof(BezTriple));
+ }
+ else {
+ len= nu->pntsu*nu->pntsv;
+ newnu->bp=
+ (BPoint*)MEM_mallocN((len)* sizeof(BPoint),"duplicateNurb3");
+ memcpy(newnu->bp, nu->bp, len*sizeof(BPoint));
+
+ newnu->knotsu=newnu->knotsv= 0;
+
+ if(nu->knotsu) {
+ len= KNOTSU(nu);
+ if(len) {
+ newnu->knotsu= MEM_mallocN(len*sizeof(float), "duplicateNurb4");
+ memcpy(newnu->knotsu, nu->knotsu, sizeof(float)*len);
+ }
+ }
+ if(nu->pntsv>1 && nu->knotsv) {
+ len= KNOTSV(nu);
+ if(len) {
+ newnu->knotsv= MEM_mallocN(len*sizeof(float), "duplicateNurb5");
+ memcpy(newnu->knotsv, nu->knotsv, sizeof(float)*len);
+ }
+ }
+ }
+ return newnu;
+}
+
+void duplicateNurblist(ListBase *lb1, ListBase *lb2)
+{
+ Nurb *nu, *nun;
+
+ freeNurblist(lb1);
+
+ nu= lb2->first;
+ while(nu) {
+ nun= duplicateNurb(nu);
+ BLI_addtail(lb1, nun);
+
+ nu= nu->next;
+ }
+}
+
+void test2DNurb(Nurb *nu)
+{
+ BezTriple *bezt;
+ BPoint *bp;
+ int a;
+
+ if( nu->type== CU_BEZIER+CU_2D ) {
+ a= nu->pntsu;
+ bezt= nu->bezt;
+ while(a--) {
+ bezt->vec[0][2]= 0.0;
+ bezt->vec[1][2]= 0.0;
+ bezt->vec[2][2]= 0.0;
+ bezt++;
+ }
+ }
+ else if(nu->type & CU_2D) {
+ a= nu->pntsu*nu->pntsv;
+ bp= nu->bp;
+ while(a--) {
+ bp->vec[2]= 0.0;
+ bp++;
+ }
+ }
+}
+
+void minmaxNurb(Nurb *nu, float *min, float *max)
+{
+ BezTriple *bezt;
+ BPoint *bp;
+ int a;
+
+ if( (nu->type & 7)==CU_BEZIER ) {
+ a= nu->pntsu;
+ bezt= nu->bezt;
+ while(a--) {
+ DO_MINMAX(bezt->vec[0], min, max);
+ DO_MINMAX(bezt->vec[1], min, max);
+ DO_MINMAX(bezt->vec[2], min, max);
+ bezt++;
+ }
+ }
+ else {
+ a= nu->pntsu*nu->pntsv;
+ bp= nu->bp;
+ while(a--) {
+ DO_MINMAX(bp->vec, min, max);
+ bp++;
+ }
+ }
+
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~Non Uniform Rational B Spline calculations ~~~~~~~~~~~ */
+
+
+static void calcknots(float *knots, short aantal, short order, short type)
+/* knots: number of pnts NOT corrected for cyclic */
+/* type; 0: uniform, 1: endpoints, 2: bezier */
+{
+ float k;
+ int a, t;
+
+ t = aantal+order;
+ if(type==0) {
+
+ for(a=0;a<t;a++) {
+ knots[a]= (float)a;
+ }
+ }
+ else if(type==1) {
+ k= 0.0;
+ for(a=1;a<=t;a++) {
+ knots[a-1]= k;
+ if(a>=order && a<=aantal) k+= 1.0;
+ }
+ }
+ else if(type==2) {
+ if(order==4) {
+ k= 0.34;
+ for(a=0;a<t;a++) {
+ knots[a]= (float)floor(k);
+ k+= (1.0/3.0);
+ }
+ }
+ else if(order==3) {
+ k= 0.6;
+ for(a=0;a<t;a++) {
+ if(a>=order && a<=aantal) k+= (0.5);
+ knots[a]= (float)floor(k);
+ }
+ }
+ }
+}
+
+static void makecyclicknots(float *knots, short pnts, short order)
+/* pnts, order: number of pnts NOT corrected for cyclic */
+{
+ int a, b, order2, c;
+
+ if(knots==0) return;
+ order2=order-1;
+
+ /* do first long rows (order -1), remove identical knots at endpoints */
+ if(order>2) {
+ b= pnts+order2;
+ for(a=1; a<order2; a++) {
+ if(knots[b]!= knots[b-a]) break;
+ }
+ if(a==order2) knots[pnts+order-2]+= 1.0;
+ }
+
+ b= order;
+ c=pnts + order + order2;
+ for(a=pnts+order2; a<c; a++) {
+ knots[a]= knots[a-1]+ (knots[b]-knots[b-1]);
+ b--;
+ }
+}
+
+
+void makeknots(Nurb *nu, short uv, short type) /* 0: uniform, 1: endpoints, 2: bezier */
+{
+ if( (nu->type & 7)==CU_NURBS ) {
+ if(uv & 1) {
+ if(nu->knotsu) MEM_freeN(nu->knotsu);
+ if(nu->pntsu>1) {
+ nu->knotsu= MEM_callocN(4+sizeof(float)*KNOTSU(nu), "makeknots");
+ calcknots(nu->knotsu, nu->pntsu, nu->orderu, type);
+ if(nu->flagu & 1) makecyclicknots(nu->knotsu, nu->pntsu, nu->orderu);
+ }
+ else nu->knotsu= 0;
+ }
+ if(uv & 2) {
+ if(nu->knotsv) MEM_freeN(nu->knotsv);
+ if(nu->pntsv>1) {
+ nu->knotsv= MEM_callocN(4+sizeof(float)*KNOTSV(nu), "makeknots");
+ calcknots(nu->knotsv, nu->pntsv, nu->orderv, type);
+ if(nu->flagv & 1) makecyclicknots(nu->knotsv, nu->pntsv, nu->orderv);
+ }
+ else nu->knotsv= 0;
+ }
+ }
+}
+
+static void basisNurb(float t, short order, short pnts, float *knots, float *basis, int *start, int *end)
+{
+ float d, e;
+ int i, i1 = 0, i2 = 0 ,j, orderpluspnts, opp2, o2;
+
+ orderpluspnts= order+pnts;
+ opp2 = orderpluspnts-1;
+
+ /* this is for float inaccuracy */
+ if(t < knots[0]) t= knots[0];
+ else if(t > knots[opp2]) t= knots[opp2];
+
+ /* this part is order '1' */
+ o2 = order + 1;
+ for(i=0;i<opp2;i++) {
+ if(knots[i]!=knots[i+1] && t>= knots[i] && t<=knots[i+1]) {
+ basis[i]= 1.0;
+ i1= i-o2;
+ if(i1<0) i1= 0;
+ i2= i;
+ i++;
+ while(i<opp2) {
+ basis[i]= 0.0;
+ i++;
+ }
+ break;
+ }
+ else basis[i]= 0.0;
+ }
+ basis[i]= 0.0;
+
+ /* this is order 2,3,... */
+ for(j=2; j<=order; j++) {
+
+ if(i2+j>= orderpluspnts) i2= opp2-j;
+
+ for(i= i1; i<=i2; i++) {
+ if(basis[i]!=0.0)
+ d= ((t-knots[i])*basis[i]) / (knots[i+j-1]-knots[i]);
+ else
+ d= 0.0;
+
+ if(basis[i+1]!=0.0)
+ e= ((knots[i+j]-t)*basis[i+1]) / (knots[i+j]-knots[i+1]);
+ else
+ e= 0.0;
+
+ basis[i]= d+e;
+ }
+ }
+
+ *start= 1000;
+ *end= 0;
+
+ for(i=i1; i<=i2; i++) {
+ if(basis[i]>0.0) {
+ *end= i;
+ if(*start==1000) *start= i;
+ }
+ }
+}
+
+
+void makeNurbfaces(Nurb *nu, float *data, int rowstride)
+/* data has to be 3*4*resolu*resolv in size, and zero-ed */
+{
+ BPoint *bp;
+ float *basisu, *basis, *basisv, *sum, *fp, *in;
+ float u, v, ustart, uend, ustep, vstart, vend, vstep, sumdiv;
+ int i, j, iofs, jofs, cycl, len, resolu, resolv;
+ int istart, iend, jsta, jen, *jstart, *jend, ratcomp;
+
+ if(nu->knotsu==0 || nu->knotsv==0) return;
+ if(nu->orderu>nu->pntsu) return;
+ if(nu->orderv>nu->pntsv) return;
+ if(data==0) return;
+
+ /* allocate and initialize */
+ len= nu->pntsu*nu->pntsv;
+ if(len==0) return;
+
+
+
+ sum= (float *)MEM_callocN(sizeof(float)*len, "makeNurbfaces1");
+
+ resolu= nu->resolu;
+ resolv= nu->resolv;
+ len= resolu*resolv;
+ if(len==0) {
+ MEM_freeN(sum);
+ return;
+ }
+
+ bp= nu->bp;
+ i= nu->pntsu*nu->pntsv;
+ ratcomp=0;
+ while(i--) {
+ if(bp->vec[3]!=1.0) {
+ ratcomp= 1;
+ break;
+ }
+ bp++;
+ }
+
+ fp= nu->knotsu;
+ ustart= fp[nu->orderu-1];
+ if(nu->flagu & 1) uend= fp[nu->pntsu+nu->orderu-1];
+ else uend= fp[nu->pntsu];
+ ustep= (uend-ustart)/(resolu-1+(nu->flagu & 1));
+ basisu= (float *)MEM_mallocN(sizeof(float)*KNOTSU(nu), "makeNurbfaces3");
+
+ fp= nu->knotsv;
+ vstart= fp[nu->orderv-1];
+
+ if(nu->flagv & 1) vend= fp[nu->pntsv+nu->orderv-1];
+ else vend= fp[nu->pntsv];
+ vstep= (vend-vstart)/(resolv-1+(nu->flagv & 1));
+ len= KNOTSV(nu);
+ basisv= (float *)MEM_mallocN(sizeof(float)*len*resolv, "makeNurbfaces3");
+ jstart= (int *)MEM_mallocN(sizeof(float)*resolv, "makeNurbfaces4");
+ jend= (int *)MEM_mallocN(sizeof(float)*resolv, "makeNurbfaces5");
+
+ /* precalculation of basisv and jstart,jend */
+ if(nu->flagv & 1) cycl= nu->orderv-1;
+ else cycl= 0;
+ v= vstart;
+ basis= basisv;
+ while(resolv--) {
+ basisNurb(v, nu->orderv, (short)(nu->pntsv+cycl), nu->knotsv, basis, jstart+resolv, jend+resolv);
+ basis+= KNOTSV(nu);
+ v+= vstep;
+ }
+
+ if(nu->flagu & 1) cycl= nu->orderu-1;
+ else cycl= 0;
+ in= data;
+ u= ustart;
+ while(resolu--) {
+
+ basisNurb(u, nu->orderu, (short)(nu->pntsu+cycl), nu->knotsu, basisu, &istart, &iend);
+
+ basis= basisv;
+ resolv= nu->resolv;
+ while(resolv--) {
+
+ jsta= jstart[resolv];
+ jen= jend[resolv];
+
+ /* calculate sum */
+ sumdiv= 0.0;
+ fp= sum;
+
+ for(j= jsta; j<=jen; j++) {
+
+ if(j>=nu->pntsv) jofs= (j - nu->pntsv);
+ else jofs= j;
+ bp= nu->bp+ nu->pntsu*jofs+istart-1;
+
+ for(i= istart; i<=iend; i++, fp++) {
+
+ if(i>= nu->pntsu) {
+ iofs= i- nu->pntsu;
+ bp= nu->bp+ nu->pntsu*jofs+iofs;
+ }
+ else bp++;
+
+ if(ratcomp) {
+ *fp= basisu[i]*basis[j]*bp->vec[3];
+ sumdiv+= *fp;
+ }
+ else *fp= basisu[i]*basis[j];
+ }
+ }
+
+ if(ratcomp) {
+ fp= sum;
+ for(j= jsta; j<=jen; j++) {
+ for(i= istart; i<=iend; i++, fp++) {
+ *fp/= sumdiv;
+ }
+ }
+ }
+
+ /* one! (1.0) real point now */
+ fp= sum;
+ for(j= jsta; j<=jen; j++) {
+
+ if(j>=nu->pntsv) jofs= (j - nu->pntsv);
+ else jofs= j;
+ bp= nu->bp+ nu->pntsu*jofs+istart-1;
+
+ for(i= istart; i<=iend; i++, fp++) {
+
+ if(i>= nu->pntsu) {
+ iofs= i- nu->pntsu;
+ bp= nu->bp+ nu->pntsu*jofs+iofs;
+ }
+ else bp++;
+
+ if(*fp!=0.0) {
+ in[0]+= (*fp) * bp->vec[0];
+ in[1]+= (*fp) * bp->vec[1];
+ in[2]+= (*fp) * bp->vec[2];
+ }
+ }
+ }
+
+ in+=3;
+ basis+= KNOTSV(nu);
+ }
+ u+= ustep;
+ if (rowstride!=0) in = (float*) (((unsigned char*) in) + (rowstride - 3*nu->resolv*sizeof(*in)));
+ }
+
+ /* free */
+ MEM_freeN(sum);
+ MEM_freeN(basisu);
+ MEM_freeN(basisv);
+ MEM_freeN(jstart);
+ MEM_freeN(jend);
+}
+
+void makeNurbcurve(Nurb *nu, float *data, int resolu, int dim)
+/* data has to be dim*4*pntsu*resolu in size and zero-ed */
+{
+ BPoint *bp;
+ float u, ustart, uend, ustep, sumdiv;
+ float *basisu, *sum, *fp, *in;
+ int i, len, istart, iend, cycl;
+
+ if(nu->knotsu==0) return;
+ if(nu->orderu>nu->pntsu) return;
+ if(data==0) return;
+
+ /* allocate and initialize */
+ len= nu->pntsu;
+ if(len==0) return;
+ sum= (float *)MEM_callocN(sizeof(float)*len, "makeNurbcurve1");
+
+ resolu*= nu->pntsu;
+ if(resolu==0) {
+ MEM_freeN(sum);
+ return;
+ }
+
+ fp= nu->knotsu;
+ ustart= fp[nu->orderu-1];
+ if(nu->flagu & 1) uend= fp[nu->pntsu+nu->orderu-1];
+ else uend= fp[nu->pntsu];
+ ustep= (uend-ustart)/(resolu-1+(nu->flagu & 1));
+ basisu= (float *)MEM_mallocN(sizeof(float)*KNOTSU(nu), "makeNurbcurve3");
+
+ if(nu->flagu & 1) cycl= nu->orderu-1;
+ else cycl= 0;
+
+ in= data;
+ u= ustart;
+ while(resolu--) {
+
+ basisNurb(u, nu->orderu, (short)(nu->pntsu+cycl), nu->knotsu, basisu, &istart, &iend);
+ /* calc sum */
+ sumdiv= 0.0;
+ fp= sum;
+ bp= nu->bp+ istart-1;
+ for(i= istart; i<=iend; i++, fp++) {
+
+ if(i>=nu->pntsu) bp= nu->bp+(i - nu->pntsu);
+ else bp++;
+
+ *fp= basisu[i]*bp->vec[3];
+ sumdiv+= *fp;
+ }
+ if(sumdiv!=0.0) if(sumdiv<0.999 || sumdiv>1.001) {
+ /* is normalizing needed? */
+ fp= sum;
+ for(i= istart; i<=iend; i++, fp++) {
+ *fp/= sumdiv;
+ }
+ }
+
+ /* one! (1.0) real point */
+ fp= sum;
+ bp= nu->bp+ istart-1;
+ for(i= istart; i<=iend; i++, fp++) {
+
+ if(i>=nu->pntsu) bp= nu->bp+(i - nu->pntsu);
+ else bp++;
+
+ if(*fp!=0.0) {
+
+ in[0]+= (*fp) * bp->vec[0];
+ in[1]+= (*fp) * bp->vec[1];
+ if(dim>=3) {
+ in[2]+= (*fp) * bp->vec[2];
+ if(dim==4) in[3]+= (*fp) * bp->alfa;
+ }
+ }
+ }
+
+ in+= dim;
+
+ u+= ustep;
+ }
+
+ /* free */
+ MEM_freeN(sum);
+ MEM_freeN(basisu);
+}
+
+/* forward differencing method for bezier curve */
+void forward_diff_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride)
+{
+ float rt0,rt1,rt2,rt3,f;
+ int a;
+
+ f= (float)it;
+ rt0= q0;
+ rt1= 3.0f*(q1-q0)/f;
+ f*= f;
+ rt2= 3.0f*(q0-2.0f*q1+q2)/f;
+ f*= it;
+ rt3= (q3-q0+3.0f*(q1-q2))/f;
+
+ q0= rt0;
+ q1= rt1+rt2+rt3;
+ q2= 2*rt2+6*rt3;
+ q3= 6*rt3;
+
+ for(a=0; a<=it; a++) {
+ *p= q0;
+ p+= stride;
+ q0+= q1;
+ q1+= q2;
+ q2+= q3;
+ }
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+float *make_orco_surf(Object *ob)
+{
+ Curve *cu= ob->data;
+ Nurb *nu;
+ int a, b, tot=0;
+ int sizeu, sizev;
+ float *data, *orco;
+
+ /* first calculate the size of the datablock */
+ nu= cu->nurb.first;
+ while(nu) {
+ /* as we want to avoid the seam in a cyclic nurbs
+ texture wrapping, reserve extra orco data space to save these extra needed
+ vertex based UV coordinates for the meridian vertices.
+ Vertices on the 0/2pi boundary are not duplicated inside the displist but later in
+ the renderface/vert construction.
+
+ See also convertblender.c: init_render_surf()
+ */
+
+ sizeu = nu->resolu;
+ sizev = nu->resolv;
+ if (nu->flagu & CU_CYCLIC) sizeu++;
+ if (nu->flagv & CU_CYCLIC) sizev++;
+ if(nu->pntsv>1) tot+= sizeu * sizev;
+
+ nu= nu->next;
+ }
+ /* makeNurbfaces wants zeros */
+ data= orco= MEM_callocN(3*sizeof(float)*tot, "make_orco");
+
+ nu= cu->nurb.first;
+ while(nu) {
+ if(nu->pntsv>1) {
+ sizeu = nu->resolu;
+ sizev = nu->resolv;
+ if (nu->flagu & CU_CYCLIC) sizeu++;
+ if (nu->flagv & CU_CYCLIC) sizev++;
+
+ if(cu->flag & CU_UV_ORCO) {
+ for(b=0; b< sizeu; b++) {
+ for(a=0; a< sizev; a++) {
+
+ if(sizev <2) data[0]= 0.0f;
+ else data[0]= -1.0f + 2.0f*((float)a)/(sizev - 1);
+
+ if(sizeu <2) data[1]= 0.0f;
+ else data[1]= -1.0f + 2.0f*((float)b)/(sizeu - 1);
+
+ data[2]= 0.0;
+
+ data+= 3;
+ }
+ }
+ }
+ else {
+ float *_tdata= MEM_callocN(nu->resolu*nu->resolv*3*sizeof(float), "temp data");
+ float *tdata= _tdata;
+
+ makeNurbfaces(nu, tdata, 0);
+
+ for(b=0; b<sizeu; b++) {
+ int use_b= b;
+ if (b==sizeu-1 && (nu->flagu & CU_CYCLIC))
+ use_b= 0;
+
+ for(a=0; a<sizev; a++) {
+ int use_a= a;
+ if (a==sizev-1 && (nu->flagv & CU_CYCLIC))
+ use_a= 0;
+
+ tdata = _tdata + 3 * (use_b * nu->resolv + use_a);
+
+ data[0]= (tdata[0]-cu->loc[0])/cu->size[0];
+ data[1]= (tdata[1]-cu->loc[1])/cu->size[1];
+ data[2]= (tdata[2]-cu->loc[2])/cu->size[2];
+ data+= 3;
+ }
+ }
+
+ MEM_freeN(_tdata);
+ }
+ }
+ nu= nu->next;
+ }
+
+ return orco;
+}
+
+
+ /* NOTE: This routine is tied to the order of vertex
+ * built by displist and as passed to the renderer.
+ */
+float *make_orco_curve(Object *ob)
+{
+ Curve *cu = ob->data;
+ DispList *dl;
+ int u, v, numVerts;
+ float *fp, *orco;
+ int remakeDisp = 0;
+
+ if (!(cu->flag&CU_UV_ORCO) && cu->key && cu->key->refkey) {
+ cp_cu_key(cu, cu->key->refkey, 0, count_curveverts(&cu->nurb));
+ makeDispListCurveTypes(ob, 1);
+ remakeDisp = 1;
+ }
+
+ /* Assumes displist has been built */
+
+ numVerts = 0;
+ for (dl=cu->disp.first; dl; dl=dl->next) {
+ if (dl->type==DL_INDEX3) {
+ numVerts += dl->nr;
+ } else if (dl->type==DL_SURF) {
+ /* convertblender.c uses the Surface code for creating renderfaces when cyclic U only (closed circle beveling) */
+ if (dl->flag & DL_CYCL_U) {
+ if (dl->flag & DL_CYCL_V)
+ numVerts += (dl->parts+1)*(dl->nr+1);
+ else
+ numVerts += dl->parts*(dl->nr+1);
+ }
+ else
+ numVerts += dl->parts*dl->nr;
+ }
+ }
+
+ fp= orco= MEM_mallocN(3*sizeof(float)*numVerts, "cu_orco");
+ for (dl=cu->disp.first; dl; dl=dl->next) {
+ if (dl->type==DL_INDEX3) {
+ for (u=0; u<dl->nr; u++, fp+=3) {
+ if (cu->flag & CU_UV_ORCO) {
+ fp[0]= 2.0f*u/(dl->nr-1) - 1.0f;
+ fp[1]= 0.0;
+ fp[2]= 0.0;
+ } else {
+ VECCOPY(fp, &dl->verts[u*3]);
+
+ fp[0]= (fp[0]-cu->loc[0])/cu->size[0];
+ fp[1]= (fp[1]-cu->loc[1])/cu->size[1];
+ fp[2]= (fp[2]-cu->loc[2])/cu->size[2];
+ }
+ }
+ } else if (dl->type==DL_SURF) {
+ int sizeu= dl->nr, sizev= dl->parts;
+
+ /* exception as handled in convertblender.c too */
+ if (dl->flag & DL_CYCL_U) {
+ sizeu++;
+ if (dl->flag & DL_CYCL_V)
+ sizev++;
+ }
+
+ for (u=0; u<sizev; u++) {
+ for (v=0; v<sizeu; v++,fp+=3) {
+ if (cu->flag & CU_UV_ORCO) {
+ fp[0]= 2.0f*u/(dl->parts-1) - 1.0f;
+ fp[1]= 2.0f*v/(dl->nr-1) - 1.0f;
+ fp[2]= 0.0;
+ } else {
+ int realv= v % dl->nr;
+
+ VECCOPY(fp, &dl->verts[(dl->nr*u + realv)*3]);
+
+ fp[0]= (fp[0]-cu->loc[0])/cu->size[0];
+ fp[1]= (fp[1]-cu->loc[1])/cu->size[1];
+ fp[2]= (fp[2]-cu->loc[2])/cu->size[2];
+ }
+ }
+ }
+ }
+ }
+
+ if (remakeDisp) {
+ makeDispListCurveTypes(ob, 0);
+ }
+
+ return orco;
+}
+
+
+/* ***************** BEVEL ****************** */
+
+void makebevelcurve(Object *ob, ListBase *disp)
+{
+ DispList *dl, *dlnew;
+ Curve *bevcu, *cu;
+ float *fp, facx, facy, angle, dangle;
+ int nr, a;
+
+ cu= ob->data;
+ disp->first = disp->last = NULL;
+
+ /* if a font object is being edited, then do nothing */
+ if( ob == G.obedit && ob->type == OB_FONT ) return;
+
+ if(cu->bevobj && cu->bevobj!=ob) {
+ if(cu->bevobj->type==OB_CURVE) {
+ bevcu= cu->bevobj->data;
+ if(bevcu->ext1==0.0 && bevcu->ext2==0.0) {
+ facx= cu->bevobj->size[0];
+ facy= cu->bevobj->size[1];
+
+ dl= bevcu->disp.first;
+ if(dl==0) {
+ makeDispListCurveTypes(cu->bevobj, 0);
+ dl= bevcu->disp.first;
+ }
+ while(dl) {
+ if ELEM(dl->type, DL_POLY, DL_SEGM) {
+ dlnew= MEM_mallocN(sizeof(DispList), "makebevelcurve1");
+ *dlnew= *dl;
+ dlnew->verts= MEM_mallocN(3*sizeof(float)*dl->parts*dl->nr, "makebevelcurve1");
+ memcpy(dlnew->verts, dl->verts, 3*sizeof(float)*dl->parts*dl->nr);
+
+ if(dlnew->type==DL_SEGM) dlnew->flag |= (DL_FRONT_CURVE|DL_BACK_CURVE);
+
+ BLI_addtail(disp, dlnew);
+ fp= dlnew->verts;
+ nr= dlnew->parts*dlnew->nr;
+ while(nr--) {
+ fp[2]= fp[1]*facy;
+ fp[1]= -fp[0]*facx;
+ fp[0]= 0.0;
+ fp+= 3;
+ }
+ }
+ dl= dl->next;
+ }
+ }
+ }
+ }
+ else if(cu->ext1==0.0 && cu->ext2==0.0) {
+ ;
+ }
+ else if(cu->ext2==0.0) {
+ dl= MEM_callocN(sizeof(DispList), "makebevelcurve2");
+ dl->verts= MEM_mallocN(2*3*sizeof(float), "makebevelcurve2");
+ BLI_addtail(disp, dl);
+ dl->type= DL_SEGM;
+ dl->parts= 1;
+ dl->flag= DL_FRONT_CURVE|DL_BACK_CURVE;
+ dl->nr= 2;
+
+ fp= dl->verts;
+ fp[0]= fp[1]= 0.0;
+ fp[2]= -cu->ext1;
+ fp[3]= fp[4]= 0.0;
+ fp[5]= cu->ext1;
+ }
+ else if( (cu->flag & (CU_FRONT|CU_BACK))==0 && cu->ext1==0.0f) { // we make a full round bevel in that case
+
+ nr= 4+ 2*cu->bevresol;
+
+ dl= MEM_callocN(sizeof(DispList), "makebevelcurve p1");
+ dl->verts= MEM_mallocN(nr*3*sizeof(float), "makebevelcurve p1");
+ BLI_addtail(disp, dl);
+ dl->type= DL_POLY;
+ dl->parts= 1;
+ dl->flag= DL_BACK_CURVE;
+ dl->nr= nr;
+
+ /* a circle */
+ fp= dl->verts;
+ dangle= (2.0f*M_PI/(nr));
+ angle= -(nr-1)*dangle;
+
+ for(a=0; a<nr; a++) {
+ fp[0]= 0.0;
+ fp[1]= (float)(cos(angle)*(cu->ext2));
+ fp[2]= (float)(sin(angle)*(cu->ext2)) - cu->ext1;
+ angle+= dangle;
+ fp+= 3;
+ }
+ }
+ else {
+ short dnr;
+
+ /* bevel now in three parts, for proper vertex normals */
+ /* part 1 */
+ dnr= nr= 2+ cu->bevresol;
+ if( (cu->flag & (CU_FRONT|CU_BACK))==0)
+ nr= 3+ 2*cu->bevresol;
+
+ dl= MEM_callocN(sizeof(DispList), "makebevelcurve p1");
+ dl->verts= MEM_mallocN(nr*3*sizeof(float), "makebevelcurve p1");
+ BLI_addtail(disp, dl);
+ dl->type= DL_SEGM;
+ dl->parts= 1;
+ dl->flag= DL_BACK_CURVE;
+ dl->nr= nr;
+
+ /* half a circle */
+ fp= dl->verts;
+ dangle= (0.5*M_PI/(dnr-1));
+ angle= -(nr-1)*dangle;
+
+ for(a=0; a<nr; a++) {
+ fp[0]= 0.0;
+ fp[1]= (float)(cos(angle)*(cu->ext2));
+ fp[2]= (float)(sin(angle)*(cu->ext2)) - cu->ext1;
+ angle+= dangle;
+ fp+= 3;
+ }
+
+ /* part 2, sidefaces */
+ if(cu->ext1!=0.0) {
+ nr= 2;
+
+ dl= MEM_callocN(sizeof(DispList), "makebevelcurve p2");
+ dl->verts= MEM_callocN(nr*3*sizeof(float), "makebevelcurve p2");
+ BLI_addtail(disp, dl);
+ dl->type= DL_SEGM;
+ dl->parts= 1;
+ dl->nr= nr;
+
+ fp= dl->verts;
+ fp[1]= cu->ext2;
+ fp[2]= -cu->ext1;
+ fp[4]= cu->ext2;
+ fp[5]= cu->ext1;
+
+ if( (cu->flag & (CU_FRONT|CU_BACK))==0) {
+ dl= MEM_dupallocN(dl);
+ dl->verts= MEM_dupallocN(dl->verts);
+ BLI_addtail(disp, dl);
+
+ fp= dl->verts;
+ fp[1]= -fp[1];
+ fp[2]= -fp[2];
+ fp[4]= -fp[4];
+ fp[5]= -fp[5];
+ }
+ }
+
+ /* part 3 */
+ dnr= nr= 2+ cu->bevresol;
+ if( (cu->flag & (CU_FRONT|CU_BACK))==0)
+ nr= 3+ 2*cu->bevresol;
+
+ dl= MEM_callocN(sizeof(DispList), "makebevelcurve p3");
+ dl->verts= MEM_mallocN(nr*3*sizeof(float), "makebevelcurve p3");
+ BLI_addtail(disp, dl);
+ dl->type= DL_SEGM;
+ dl->flag= DL_FRONT_CURVE;
+ dl->parts= 1;
+ dl->nr= nr;
+
+ /* half a circle */
+ fp= dl->verts;
+ angle= 0.0;
+ dangle= (0.5*M_PI/(dnr-1));
+
+ for(a=0; a<nr; a++) {
+ fp[0]= 0.0;
+ fp[1]= (float)(cos(angle)*(cu->ext2));
+ fp[2]= (float)(sin(angle)*(cu->ext2)) + cu->ext1;
+ angle+= dangle;
+ fp+= 3;
+ }
+ }
+}
+
+int cu_isectLL(float *v1, float *v2, float *v3, float *v4, short cox, short coy, float *labda, float *mu, float *vec)
+{
+ /* return:
+ -1: colliniar
+ 0: no intersection of segments
+ 1: exact intersection of segments
+ 2: cross-intersection of segments
+ */
+ float deler;
+
+ deler= (v1[cox]-v2[cox])*(v3[coy]-v4[coy])-(v3[cox]-v4[cox])*(v1[coy]-v2[coy]);
+ if(deler==0.0) return -1;
+
+ *labda= (v1[coy]-v3[coy])*(v3[cox]-v4[cox])-(v1[cox]-v3[cox])*(v3[coy]-v4[coy]);
+ *labda= -(*labda/deler);
+
+ deler= v3[coy]-v4[coy];
+ if(deler==0) {
+ deler=v3[cox]-v4[cox];
+ *mu= -(*labda*(v2[cox]-v1[cox])+v1[cox]-v3[cox])/deler;
+ } else {
+ *mu= -(*labda*(v2[coy]-v1[coy])+v1[coy]-v3[coy])/deler;
+ }
+ vec[cox]= *labda*(v2[cox]-v1[cox])+v1[cox];
+ vec[coy]= *labda*(v2[coy]-v1[coy])+v1[coy];
+
+ if(*labda>=0.0 && *labda<=1.0 && *mu>=0.0 && *mu<=1.0) {
+ if(*labda==0.0 || *labda==1.0 || *mu==0.0 || *mu==1.0) return 1;
+ return 2;
+ }
+ return 0;
+}
+
+
+static short bevelinside(BevList *bl1,BevList *bl2)
+{
+ /* is bl2 INSIDE bl1 ? with left-right method and "labda's" */
+ /* returns '1' if correct hole */
+ BevPoint *bevp, *prevbevp;
+ float min,max,vec[3],hvec1[3],hvec2[3],lab,mu;
+ int nr, links=0,rechts=0,mode;
+
+ /* take first vertex of possible hole */
+
+ bevp= (BevPoint *)(bl2+1);
+ hvec1[0]= bevp->x;
+ hvec1[1]= bevp->y;
+ hvec1[2]= 0.0;
+ VECCOPY(hvec2,hvec1);
+ hvec2[0]+=1000;
+
+ /* test it with all edges of potential surounding poly */
+ /* count number of transitions left-right */
+
+ bevp= (BevPoint *)(bl1+1);
+ nr= bl1->nr;
+ prevbevp= bevp+(nr-1);
+
+ while(nr--) {
+ min= prevbevp->y;
+ max= bevp->y;
+ if(max<min) {
+ min= max;
+ max= prevbevp->y;
+ }
+ if(min!=max) {
+ if(min<=hvec1[1] && max>=hvec1[1]) {
+ /* there's a transition, calc intersection point */
+ mode= cu_isectLL(&(prevbevp->x),&(bevp->x),hvec1,hvec2,0,1,&lab,&mu,vec);
+ /* if lab==0.0 or lab==1.0 then the edge intersects exactly a transition
+ only allow for one situation: we choose lab= 1.0
+ */
+ if(mode>=0 && lab!=0.0) {
+ if(vec[0]<hvec1[0]) links++;
+ else rechts++;
+ }
+ }
+ }
+ prevbevp= bevp;
+ bevp++;
+ }
+
+ if( (links & 1) && (rechts & 1) ) return 1;
+ return 0;
+}
+
+
+struct bevelsort {
+ float left;
+ BevList *bl;
+ int dir;
+};
+
+static int vergxcobev(const void *a1, const void *a2)
+{
+ const struct bevelsort *x1=a1,*x2=a2;
+
+ if( x1->left > x2->left ) return 1;
+ else if( x1->left < x2->left) return -1;
+ return 0;
+}
+
+/* this function cannot be replaced with atan2, but why? */
+
+static void calc_bevel_sin_cos(float x1, float y1, float x2, float y2, float *sina, float *cosa)
+{
+ float t01, t02, x3, y3;
+
+ t01= (float)sqrt(x1*x1+y1*y1);
+ t02= (float)sqrt(x2*x2+y2*y2);
+ if(t01==0.0) t01= 1.0;
+ if(t02==0.0) t02= 1.0;
+
+ x1/=t01;
+ y1/=t01;
+ x2/=t02;
+ y2/=t02;
+
+ t02= x1*x2+y1*y2;
+ if(fabs(t02)>=1.0) t02= .5*M_PI;
+ else t02= (saacos(t02))/2.0f;
+
+ t02= (float)sin(t02);
+ if(t02==0.0) t02= 1.0;
+
+ x3= x1-x2;
+ y3= y1-y2;
+ if(x3==0 && y3==0) {
+ x3= y1;
+ y3= -x1;
+ } else {
+ t01= (float)sqrt(x3*x3+y3*y3);
+ x3/=t01;
+ y3/=t01;
+ }
+
+ *sina= -y3/t02;
+ *cosa= x3/t02;
+
+}
+
+static void alfa_bezpart(BezTriple *prevbezt, BezTriple *bezt, Nurb *nu, float *data_a, int resolu)
+{
+ BezTriple *pprev, *next, *last;
+ float fac, dfac, t[4];
+ int a;
+
+ last= nu->bezt+(nu->pntsu-1);
+
+ /* returns a point */
+ if(prevbezt==nu->bezt) {
+ if(nu->flagu & 1) pprev= last;
+ else pprev= prevbezt;
+ }
+ else pprev= prevbezt-1;
+
+ /* next point */
+ if(bezt==last) {
+ if(nu->flagu & 1) next= nu->bezt;
+ else next= bezt;
+ }
+ else next= bezt+1;
+
+ fac= 0.0;
+ dfac= 1.0f/(float)resolu;
+
+ for(a=0; a<resolu; a++, fac+= dfac) {
+
+ set_four_ipo(fac, t, nu->tilt_interp);
+
+ data_a[a]= t[0]*pprev->alfa + t[1]*prevbezt->alfa + t[2]*bezt->alfa + t[3]*next->alfa;
+ }
+}
+
+void makeBevelList(Object *ob)
+{
+ /*
+ - convert all curves to polys, with indication of resol and flags for double-vertices
+ - possibly; do a smart vertice removal (in case Nurb)
+ - separate in individual blicks with BoundBox
+ - AutoHole detection
+ */
+ Curve *cu;
+ Nurb *nu;
+ BezTriple *bezt, *prevbezt;
+ BPoint *bp;
+ BevList *bl, *blnew, *blnext;
+ BevPoint *bevp, *bevp2, *bevp1 = NULL, *bevp0;
+ float *data, *data_a, *v1, *v2, min, inp, x1, x2, y1, y2, vec[3];
+ struct bevelsort *sortdata, *sd, *sd1;
+ int a, b, len, nr, poly, resolu;
+
+ /* this function needs an object, because of tflag and upflag */
+ cu= ob->data;
+
+ /* STEP 1: MAKE POLYS */
+
+ BLI_freelistN(&(cu->bev));
+ if(ob==G.obedit && ob->type!=OB_FONT) nu= editNurb.first;
+ else nu= cu->nurb.first;
+
+ while(nu) {
+ if(nu->pntsu>1) {
+ if(G.rendering && cu->resolu_ren!=0)
+ resolu= cu->resolu_ren;
+ else
+ resolu= nu->resolu;
+
+ if((nu->type & 7)==CU_POLY) {
+
+ len= nu->pntsu;
+ bl= MEM_callocN(sizeof(BevList)+len*sizeof(BevPoint), "makeBevelList");
+ BLI_addtail(&(cu->bev), bl);
+
+ if(nu->flagu & 1) bl->poly= 0;
+ else bl->poly= -1;
+ bl->nr= len;
+ bl->flag= 0;
+ bevp= (BevPoint *)(bl+1);
+ bp= nu->bp;
+
+ while(len--) {
+ bevp->x= bp->vec[0];
+ bevp->y= bp->vec[1];
+ bevp->z= bp->vec[2];
+ bevp->alfa= bp->alfa;
+ bevp->f1= 1;
+ bevp++;
+ bp++;
+ }
+ }
+ else if((nu->type & 7)==CU_BEZIER) {
+
+ len= resolu*(nu->pntsu+ (nu->flagu & 1) -1)+1; /* in case last point is not cyclic */
+ bl= MEM_callocN(sizeof(BevList)+len*sizeof(BevPoint), "makeBevelList");
+ BLI_addtail(&(cu->bev), bl);
+
+ if(nu->flagu & 1) bl->poly= 0;
+ else bl->poly= -1;
+ bevp= (BevPoint *)(bl+1);
+
+ a= nu->pntsu-1;
+ bezt= nu->bezt;
+ if(nu->flagu & 1) {
+ a++;
+ prevbezt= nu->bezt+(nu->pntsu-1);
+ }
+ else {
+ prevbezt= bezt;
+ bezt++;
+ }
+
+ data= MEM_mallocN(3*sizeof(float)*(resolu+1), "makeBevelList2");
+ data_a= MEM_callocN(sizeof(float)*(resolu+1), "data_a");
+
+ while(a--) {
+ if(prevbezt->h2==HD_VECT && bezt->h1==HD_VECT) {
+
+ bevp->x= prevbezt->vec[1][0];
+ bevp->y= prevbezt->vec[1][1];
+ bevp->z= prevbezt->vec[1][2];
+ bevp->alfa= prevbezt->alfa;
+ bevp->f1= 1;
+ bevp->f2= 0;
+ bevp++;
+ bl->nr++;
+ bl->flag= 1;
+ }
+ else {
+ v1= prevbezt->vec[1];
+ v2= bezt->vec[0];
+
+ /* always do all three, to prevent data hanging around */
+ forward_diff_bezier(v1[0], v1[3], v2[0], v2[3], data, resolu, 3);
+ forward_diff_bezier(v1[1], v1[4], v2[1], v2[4], data+1, resolu, 3);
+ forward_diff_bezier(v1[2], v1[5], v2[2], v2[5], data+2, resolu, 3);
+
+ if((nu->type & CU_2D)==0) {
+ if(cu->flag & CU_3D) {
+ alfa_bezpart(prevbezt, bezt, nu, data_a, resolu);
+ }
+ }
+
+
+ /* indicate with handlecodes double points */
+ if(prevbezt->h1==prevbezt->h2) {
+ if(prevbezt->h1==0 || prevbezt->h1==HD_VECT) bevp->f1= 1;
+ }
+ else {
+ if(prevbezt->h1==0 || prevbezt->h1==HD_VECT) bevp->f1= 1;
+ else if(prevbezt->h2==0 || prevbezt->h2==HD_VECT) bevp->f1= 1;
+ }
+
+ v1= data;
+ v2= data_a;
+ nr= resolu;
+
+ while(nr--) {
+ bevp->x= v1[0];
+ bevp->y= v1[1];
+ bevp->z= v1[2];
+ bevp->alfa= v2[0];
+ bevp++;
+ v1+=3;
+ v2++;
+ }
+ bl->nr+= resolu;
+
+ }
+ prevbezt= bezt;
+ bezt++;
+ }
+
+ MEM_freeN(data);
+ MEM_freeN(data_a);
+
+ if((nu->flagu & 1)==0) { /* not cyclic: endpoint */
+ bevp->x= prevbezt->vec[1][0];
+ bevp->y= prevbezt->vec[1][1];
+ bevp->z= prevbezt->vec[1][2];
+ bevp->alfa= prevbezt->alfa;
+ bl->nr++;
+ }
+
+ }
+ else if((nu->type & 7)==CU_NURBS) {
+ if(nu->pntsv==1) {
+ len= resolu*nu->pntsu;
+ bl= MEM_mallocN(sizeof(BevList)+len*sizeof(BevPoint), "makeBevelList3");
+ BLI_addtail(&(cu->bev), bl);
+ bl->nr= len;
+ bl->flag= 0;
+ if(nu->flagu & 1) bl->poly= 0;
+ else bl->poly= -1;
+ bevp= (BevPoint *)(bl+1);
+
+ data= MEM_callocN(4*sizeof(float)*len, "makeBevelList4"); /* has to be zero-ed */
+ makeNurbcurve(nu, data, resolu, 4);
+
+ v1= data;
+ while(len--) {
+ bevp->x= v1[0];
+ bevp->y= v1[1];
+ bevp->z= v1[2];
+ bevp->alfa= v1[3];
+
+ bevp->f1= bevp->f2= 0;
+ bevp++;
+ v1+=4;
+ }
+ MEM_freeN(data);
+ }
+ }
+ }
+ nu= nu->next;
+ }
+
+ /* STEP 2: DOUBLE POINTS AND AUTOMATIC RESOLUTION, REDUCE DATABLOCKS */
+ bl= cu->bev.first;
+ while(bl) {
+ nr= bl->nr;
+ bevp1= (BevPoint *)(bl+1);
+ bevp0= bevp1+(nr-1);
+ nr--;
+ while(nr--) {
+ if( fabs(bevp0->x-bevp1->x)<0.00001 ) {
+ if( fabs(bevp0->y-bevp1->y)<0.00001 ) {
+ if( fabs(bevp0->z-bevp1->z)<0.00001 ) {
+ bevp0->f2= 1;
+ bl->flag++;
+ }
+ }
+ }
+ bevp0= bevp1;
+ bevp1++;
+ }
+ bl= bl->next;
+ }
+ bl= cu->bev.first;
+ while(bl) {
+ blnext= bl->next;
+ if(bl->flag) {
+ nr= bl->nr- bl->flag+1; /* +1 because vectorbezier sets flag too */
+ blnew= MEM_mallocN(sizeof(BevList)+nr*sizeof(BevPoint), "makeBevelList");
+ memcpy(blnew, bl, sizeof(BevList));
+ blnew->nr= 0;
+ BLI_remlink(&(cu->bev), bl);
+ BLI_insertlinkbefore(&(cu->bev),blnext,blnew); /* to make sure bevlijst is tuned with nurblist */
+ bevp0= (BevPoint *)(bl+1);
+ bevp1= (BevPoint *)(blnew+1);
+ nr= bl->nr;
+ while(nr--) {
+ if(bevp0->f2==0) {
+ memcpy(bevp1, bevp0, sizeof(BevPoint));
+ bevp1++;
+ blnew->nr++;
+ }
+ bevp0++;
+ }
+ MEM_freeN(bl);
+ blnew->flag= 0;
+ }
+ bl= blnext;
+ }
+
+ /* STEP 3: COUNT POLYS TELLEN AND AUTOHOLE */
+ bl= cu->bev.first;
+ poly= 0;
+ while(bl) {
+ if(bl->poly>=0) {
+ poly++;
+ bl->poly= poly;
+ bl->gat= 0; /* 'gat' is dutch for hole */
+ }
+ bl= bl->next;
+ }
+
+
+ /* find extreme left points, also test (turning) direction */
+ if(poly>0) {
+ sd= sortdata= MEM_mallocN(sizeof(struct bevelsort)*poly, "makeBevelList5");
+ bl= cu->bev.first;
+ while(bl) {
+ if(bl->poly>0) {
+
+ min= 300000.0;
+ bevp= (BevPoint *)(bl+1);
+ nr= bl->nr;
+ while(nr--) {
+ if(min>bevp->x) {
+ min= bevp->x;
+ bevp1= bevp;
+ }
+ bevp++;
+ }
+ sd->bl= bl;
+ sd->left= min;
+
+ bevp= (BevPoint *)(bl+1);
+ if(bevp1== bevp) bevp0= bevp+ (bl->nr-1);
+ else bevp0= bevp1-1;
+ bevp= bevp+ (bl->nr-1);
+ if(bevp1== bevp) bevp2= (BevPoint *)(bl+1);
+ else bevp2= bevp1+1;
+
+ inp= (bevp1->x- bevp0->x)*(bevp0->y- bevp2->y)
+ +(bevp0->y- bevp1->y)*(bevp0->x- bevp2->x);
+
+ if(inp>0.0) sd->dir= 1;
+ else sd->dir= 0;
+
+ sd++;
+ }
+
+ bl= bl->next;
+ }
+ qsort(sortdata,poly,sizeof(struct bevelsort), vergxcobev);
+
+ sd= sortdata+1;
+ for(a=1; a<poly; a++, sd++) {
+ bl= sd->bl; /* is bl a hole? */
+ sd1= sortdata+ (a-1);
+ for(b=a-1; b>=0; b--, sd1--) { /* all polys to the left */
+ if(bevelinside(sd1->bl, bl)) {
+ bl->gat= 1- sd1->bl->gat;
+ break;
+ }
+ }
+ }
+
+ /* turning direction */
+ if((cu->flag & CU_3D)==0) {
+ sd= sortdata;
+ for(a=0; a<poly; a++, sd++) {
+ if(sd->bl->gat==sd->dir) {
+ bl= sd->bl;
+ bevp1= (BevPoint *)(bl+1);
+ bevp2= bevp1+ (bl->nr-1);
+ nr= bl->nr/2;
+ while(nr--) {
+ SWAP(BevPoint, *bevp1, *bevp2);
+ bevp1++;
+ bevp2--;
+ }
+ }
+ }
+ }
+ MEM_freeN(sortdata);
+ }
+
+ /* STEP 4: COSINES */
+ bl= cu->bev.first;
+ while(bl) {
+
+ if(bl->nr==2) { /* 2 pnt, treat separate */
+ bevp2= (BevPoint *)(bl+1);
+ bevp1= bevp2+1;
+
+ x1= bevp1->x- bevp2->x;
+ y1= bevp1->y- bevp2->y;
+
+ calc_bevel_sin_cos(x1, y1, -x1, -y1, &(bevp1->sina), &(bevp1->cosa));
+ bevp2->sina= bevp1->sina;
+ bevp2->cosa= bevp1->cosa;
+
+ if(cu->flag & CU_3D) { /* 3D */
+ float *quat, q[4];
+
+ vec[0]= bevp1->x - bevp2->x;
+ vec[1]= bevp1->y - bevp2->y;
+ vec[2]= bevp1->z - bevp2->z;
+
+ quat= vectoquat(vec, 5, 1);
+
+ Normalize(vec);
+ q[0]= (float)cos(0.5*bevp1->alfa);
+ x1= (float)sin(0.5*bevp1->alfa);
+ q[1]= x1*vec[0];
+ q[2]= x1*vec[1];
+ q[3]= x1*vec[2];
+ QuatMul(quat, q, quat);
+
+ QuatToMat3(quat, bevp1->mat);
+ Mat3CpyMat3(bevp2->mat, bevp1->mat);
+ }
+
+ }
+ else if(bl->nr>2) {
+ bevp2= (BevPoint *)(bl+1);
+ bevp1= bevp2+(bl->nr-1);
+ bevp0= bevp1-1;
+
+
+ nr= bl->nr;
+
+ while(nr--) {
+
+ if(cu->flag & CU_3D) { /* 3D */
+ float *quat, q[4];
+
+ vec[0]= bevp2->x - bevp0->x;
+ vec[1]= bevp2->y - bevp0->y;
+ vec[2]= bevp2->z - bevp0->z;
+
+ Normalize(vec);
+
+ quat= vectoquat(vec, 5, 1);
+
+ q[0]= (float)cos(0.5*bevp1->alfa);
+ x1= (float)sin(0.5*bevp1->alfa);
+ q[1]= x1*vec[0];
+ q[2]= x1*vec[1];
+ q[3]= x1*vec[2];
+ QuatMul(quat, q, quat);
+
+ QuatToMat3(quat, bevp1->mat);
+ }
+
+ x1= bevp1->x- bevp0->x;
+ x2= bevp1->x- bevp2->x;
+ y1= bevp1->y- bevp0->y;
+ y2= bevp1->y- bevp2->y;
+
+ calc_bevel_sin_cos(x1, y1, x2, y2, &(bevp1->sina), &(bevp1->cosa));
+
+
+ bevp0= bevp1;
+ bevp1= bevp2;
+ bevp2++;
+ }
+ /* correct non-cyclic cases */
+ if(bl->poly== -1) {
+ if(bl->nr>2) {
+ bevp= (BevPoint *)(bl+1);
+ bevp1= bevp+1;
+ bevp->sina= bevp1->sina;
+ bevp->cosa= bevp1->cosa;
+ Mat3CpyMat3(bevp->mat, bevp1->mat);
+ bevp= (BevPoint *)(bl+1);
+ bevp+= (bl->nr-1);
+ bevp1= bevp-1;
+ bevp->sina= bevp1->sina;
+ bevp->cosa= bevp1->cosa;
+ Mat3CpyMat3(bevp->mat, bevp1->mat);
+ }
+ }
+ }
+ bl= bl->next;
+ }
+}
+
+/* calculates a bevel width (radius) for a particular subdivided curve part,
+ * based on the radius value of the surrounding CVs */
+float calc_curve_subdiv_radius(Curve *cu, Nurb *nu, int cursubdiv)
+{
+ BezTriple *bezt, *beztfirst, *beztlast, *beztnext, *beztprev;
+ BPoint *bp, *bpfirst, *bplast;
+ int resolu;
+ float prevrad=0.0, nextrad=0.0, rad=0.0, ratio=0.0;
+ int vectseg=0, subdivs=0;
+
+ if((nu==NULL) || (nu->pntsu<=1)) return 1.0;
+ bezt= nu->bezt;
+ bp = nu->bp;
+
+ if(G.rendering && cu->resolu_ren!=0) resolu= cu->resolu_ren;
+ else resolu= nu->resolu;
+
+ if(((nu->type & 7)==CU_BEZIER) && (bezt != NULL)) {
+ beztfirst = nu->bezt;
+ beztlast = nu->bezt + (nu->pntsu - 1);
+
+ /* loop through the CVs to end up with a pointer to the CV before the subdiv in question, and a ratio
+ * of how far that subdiv is between this CV and the next */
+ while(bezt<=beztlast) {
+ beztnext = bezt+1;
+ beztprev = bezt-1;
+ vectseg=0;
+
+ if (subdivs==cursubdiv) {
+ ratio= 0.0;
+ break;
+ }
+
+ /* check to see if we're looking at a vector segment (no subdivisions) */
+ if (nu->flagu & CU_CYCLIC) {
+ if (bezt == beztfirst) {
+ if ((beztlast->h2==HD_VECT) && (bezt->h1==HD_VECT)) vectseg = 1;
+ } else {
+ if ((beztprev->h2==HD_VECT) && (bezt->h1==HD_VECT)) vectseg = 1;
+ }
+ } else if ((bezt->h2==HD_VECT) && (beztnext->h1==HD_VECT)) vectseg = 1;
+
+
+ if (vectseg==0) {
+ /* if it's NOT a vector segment, check to see if the subdiv falls within the segment */
+ subdivs += resolu;
+
+ if (cursubdiv < subdivs) {
+ ratio = 1.0 - ((subdivs - cursubdiv)/(float)resolu);
+ break;
+ }
+ } else {
+ /* must be a vector segment.. loop again! */
+ subdivs += 1;
+ }
+
+ bezt++;
+ }
+
+ /* Now we have a nice bezt pointer to the CV that we want. But cyclic messes it up, so must correct for that..
+ * (cyclic goes last-> first -> first+1 -> first+2 -> ...) */
+ if (nu->flagu & CU_CYCLIC) {
+ if (bezt == beztfirst) bezt = beztlast;
+ else bezt--;
+ }
+
+ /* find the radii at the bounding CVs and interpolate between them based on ratio */
+ rad = prevrad = bezt->radius;
+
+ if ((bezt == beztlast) && (nu->flagu & CU_CYCLIC)) { /* loop around */
+ bezt= beztfirst;
+ } else if (bezt != beztlast) {
+ bezt++;
+ }
+ nextrad = bezt->radius;
+
+ }
+ else if( ( ((nu->type & 7)==CU_NURBS) || ((nu->type & 7)==CU_POLY)) && (bp != NULL)) {
+ /* follows similar algo as for bezt above */
+ bpfirst = nu->bp;
+ bplast = nu->bp + (nu->pntsu - 1);
+
+ if ((nu->type & 7)==CU_POLY) resolu=1;
+
+ while(bp<=bplast) {
+ if (subdivs==cursubdiv) {
+ ratio= 0.0;
+ break;
+ }
+
+ subdivs += resolu;
+
+ if (cursubdiv < subdivs) {
+ ratio = 1.0 - ((subdivs - cursubdiv)/(float)resolu);
+ break;
+ }
+
+ bp++;
+ }
+
+ if ( ((nu->type & 7)==CU_NURBS) && (nu->flagu & CU_CYCLIC)) {
+ if (bp == bplast) bp = bpfirst;
+ else bp++;
+ }
+
+ rad = prevrad = bp->radius;
+
+ if ((bp == bplast) && (nu->flagu & CU_CYCLIC)) { /* loop around */
+ bp= bpfirst;
+ } else if (bp != bplast) {
+ bp++;
+ }
+ nextrad = bp->radius;
+
+ }
+
+
+ if (nextrad != prevrad) {
+ /* smooth interpolation */
+ rad = prevrad + (nextrad-prevrad)*(3.0f*ratio*ratio - 2.0f*ratio*ratio*ratio);
+ }
+
+ if (rad > 0.0)
+ return rad;
+ else
+ return 1.0;
+}
+
+/* ****************** HANDLES ************** */
+
+/*
+ * handlecodes:
+ * 1: nothing, 1:auto, 2:vector, 3:aligned
+ */
+
+/* mode: is not zero when IpoCurve, is 2 when forced horizontal for autohandles */
+void calchandleNurb(BezTriple *bezt, BezTriple *prev, BezTriple *next, int mode)
+{
+ float *p1,*p2,*p3, pt[3];
+ float dx1,dy1,dz1,dx,dy,dz,vx,vy,vz,len,len1,len2;
+
+ if(bezt->h1==0 && bezt->h2==0) return;
+
+ p2= bezt->vec[1];
+
+ if(prev==0) {
+ p3= next->vec[1];
+ pt[0]= 2*p2[0]- p3[0];
+ pt[1]= 2*p2[1]- p3[1];
+ pt[2]= 2*p2[2]- p3[2];
+ p1= pt;
+ }
+ else p1= prev->vec[1];
+
+ if(next==0) {
+ pt[0]= 2*p2[0]- p1[0];
+ pt[1]= 2*p2[1]- p1[1];
+ pt[2]= 2*p2[2]- p1[2];
+ p3= pt;
+ }
+ else p3= next->vec[1];
+
+ dx= p2[0]- p1[0];
+ dy= p2[1]- p1[1];
+ dz= p2[2]- p1[2];
+
+ if(mode) len1= dx;
+ else len1= (float)sqrt(dx*dx+dy*dy+dz*dz);
+
+ dx1= p3[0]- p2[0];
+ dy1= p3[1]- p2[1];
+ dz1= p3[2]- p2[2];
+
+ if(mode) len2= dx1;
+ else len2= (float)sqrt(dx1*dx1+dy1*dy1+dz1*dz1);
+
+ if(len1==0.0f) len1=1.0f;
+ if(len2==0.0f) len2=1.0f;
+
+
+ if(bezt->h1==HD_AUTO || bezt->h2==HD_AUTO) { /* auto */
+ vx= dx1/len2 + dx/len1;
+ vy= dy1/len2 + dy/len1;
+ vz= dz1/len2 + dz/len1;
+ len= 2.5614f*(float)sqrt(vx*vx + vy*vy + vz*vz);
+ if(len!=0.0f) {
+ int leftviolate=0, rightviolate=0; /* for mode==2 */
+
+ if(len1>5.0f*len2) len1= 5.0f*len2;
+ if(len2>5.0f*len1) len2= 5.0f*len1;
+
+ if(bezt->h1==HD_AUTO) {
+ len1/=len;
+ *(p2-3)= *p2-vx*len1;
+ *(p2-2)= *(p2+1)-vy*len1;
+ *(p2-1)= *(p2+2)-vz*len1;
+
+ if(mode==2 && next && prev) { // keep horizontal if extrema
+ float ydiff1= prev->vec[1][1] - bezt->vec[1][1];
+ float ydiff2= next->vec[1][1] - bezt->vec[1][1];
+ if( (ydiff1<=0.0 && ydiff2<=0.0) || (ydiff1>=0.0 && ydiff2>=0.0) ) {
+ bezt->vec[0][1]= bezt->vec[1][1];
+ }
+ else { // handles should not be beyond y coord of two others
+ if(ydiff1<=0.0) {
+ if(prev->vec[1][1] > bezt->vec[0][1]) {
+ bezt->vec[0][1]= prev->vec[1][1];
+ leftviolate= 1;
+ }
+ }
+ else {
+ if(prev->vec[1][1] < bezt->vec[0][1]) {
+ bezt->vec[0][1]= prev->vec[1][1];
+ leftviolate= 1;
+ }
+ }
+ }
+ }
+ }
+ if(bezt->h2==HD_AUTO) {
+ len2/=len;
+ *(p2+3)= *p2+vx*len2;
+ *(p2+4)= *(p2+1)+vy*len2;
+ *(p2+5)= *(p2+2)+vz*len2;
+
+ if(mode==2 && next && prev) { // keep horizontal if extrema
+ float ydiff1= prev->vec[1][1] - bezt->vec[1][1];
+ float ydiff2= next->vec[1][1] - bezt->vec[1][1];
+ if( (ydiff1<=0.0 && ydiff2<=0.0) || (ydiff1>=0.0 && ydiff2>=0.0) ) {
+ bezt->vec[2][1]= bezt->vec[1][1];
+ }
+ else { // handles should not be beyond y coord of two others
+ if(ydiff1<=0.0) {
+ if(next->vec[1][1] < bezt->vec[2][1]) {
+ bezt->vec[2][1]= next->vec[1][1];
+ rightviolate= 1;
+ }
+ }
+ else {
+ if(next->vec[1][1] > bezt->vec[2][1]) {
+ bezt->vec[2][1]= next->vec[1][1];
+ rightviolate= 1;
+ }
+ }
+ }
+ }
+ }
+ if(leftviolate || rightviolate) { /* align left handle */
+ float h1[3], h2[3];
+
+ VecSubf(h1, p2-3, p2);
+ VecSubf(h2, p2, p2+3);
+ len1= Normalize(h1);
+ len2= Normalize(h2);
+
+ vz= INPR(h1, h2);
+
+ if(leftviolate) {
+ *(p2+3)= *(p2) - vz*len2*h1[0];
+ *(p2+4)= *(p2+1) - vz*len2*h1[1];
+ *(p2+5)= *(p2+2) - vz*len2*h1[2];
+ }
+ else {
+ *(p2-3)= *(p2) + vz*len1*h2[0];
+ *(p2-2)= *(p2+1) + vz*len1*h2[1];
+ *(p2-1)= *(p2+2) + vz*len1*h2[2];
+ }
+ }
+
+ }
+ }
+
+ if(bezt->h1==HD_VECT) { /* vector */
+ dx/=3.0;
+ dy/=3.0;
+ dz/=3.0;
+ *(p2-3)= *p2-dx;
+ *(p2-2)= *(p2+1)-dy;
+ *(p2-1)= *(p2+2)-dz;
+ }
+ if(bezt->h2==HD_VECT) {
+ dx1/=3.0;
+ dy1/=3.0;
+ dz1/=3.0;
+ *(p2+3)= *p2+dx1;
+ *(p2+4)= *(p2+1)+dy1;
+ *(p2+5)= *(p2+2)+dz1;
+ }
+
+ len2= VecLenf(p2, p2+3);
+ len1= VecLenf(p2, p2-3);
+ if(len1==0.0) len1=1.0;
+ if(len2==0.0) len2=1.0;
+
+ if(bezt->f1 & 1) { /* order of calculation */
+ if(bezt->h2==HD_ALIGN) { /* aligned */
+ len= len2/len1;
+ p2[3]= p2[0]+len*(p2[0]-p2[-3]);
+ p2[4]= p2[1]+len*(p2[1]-p2[-2]);
+ p2[5]= p2[2]+len*(p2[2]-p2[-1]);
+ }
+ if(bezt->h1==HD_ALIGN) {
+ len= len1/len2;
+ p2[-3]= p2[0]+len*(p2[0]-p2[3]);
+ p2[-2]= p2[1]+len*(p2[1]-p2[4]);
+ p2[-1]= p2[2]+len*(p2[2]-p2[5]);
+ }
+ }
+ else {
+ if(bezt->h1==HD_ALIGN) {
+ len= len1/len2;
+ p2[-3]= p2[0]+len*(p2[0]-p2[3]);
+ p2[-2]= p2[1]+len*(p2[1]-p2[4]);
+ p2[-1]= p2[2]+len*(p2[2]-p2[5]);
+ }
+ if(bezt->h2==HD_ALIGN) { /* aligned */
+ len= len2/len1;
+ p2[3]= p2[0]+len*(p2[0]-p2[-3]);
+ p2[4]= p2[1]+len*(p2[1]-p2[-2]);
+ p2[5]= p2[2]+len*(p2[2]-p2[-1]);
+ }
+ }
+}
+
+void calchandlesNurb(Nurb *nu) /* first, if needed, set handle flags */
+{
+ BezTriple *bezt, *prev, *next;
+ short a;
+
+ if((nu->type & 7)!=CU_BEZIER) return;
+ if(nu->pntsu<2) return;
+
+ a= nu->pntsu;
+ bezt= nu->bezt;
+ if(nu->flagu & 1) prev= bezt+(a-1);
+ else prev= 0;
+ next= bezt+1;
+
+ while(a--) {
+ calchandleNurb(bezt, prev, next, 0);
+ prev= bezt;
+ if(a==1) {
+ if(nu->flagu & 1) next= nu->bezt;
+ else next= 0;
+ }
+ else next++;
+
+ bezt++;
+ }
+}
+
+
+void testhandlesNurb(Nurb *nu)
+{
+ /* use when something has changed with handles.
+ it treats all BezTriples with the following rules:
+ PHASE 1: do types have to be altered?
+ Auto handles: become aligned when selection status is NOT(000 || 111)
+ Vector handles: become 'nothing' when (one half selected AND other not)
+ PHASE 2: recalculate handles
+ */
+ BezTriple *bezt;
+ short flag, a;
+
+ if((nu->type & 7)!=CU_BEZIER) return;
+
+ bezt= nu->bezt;
+ a= nu->pntsu;
+ while(a--) {
+ flag= 0;
+ if(bezt->f1 & 1) flag++;
+ if(bezt->f2 & 1) flag += 2;
+ if(bezt->f3 & 1) flag += 4;
+
+ if( !(flag==0 || flag==7) ) {
+ if(bezt->h1==HD_AUTO) { /* auto */
+ bezt->h1= HD_ALIGN;
+ }
+ if(bezt->h2==HD_AUTO) { /* auto */
+ bezt->h2= HD_ALIGN;
+ }
+
+ if(bezt->h1==HD_VECT) { /* vector */
+ if(flag < 4) bezt->h1= 0;
+ }
+ if(bezt->h2==HD_VECT) { /* vector */
+ if( flag > 3) bezt->h2= 0;
+ }
+ }
+ bezt++;
+ }
+
+ calchandlesNurb(nu);
+}
+
+void autocalchandlesNurb(Nurb *nu, int flag)
+{
+ /* checks handle coordinates and calculates type */
+
+ BezTriple *bezt2, *bezt1, *bezt0;
+ int i, align, leftsmall, rightsmall;
+
+ if(nu==0 || nu->bezt==0) return;
+
+ bezt2 = nu->bezt;
+ bezt1 = bezt2 + (nu->pntsu-1);
+ bezt0 = bezt1 - 1;
+ i = nu->pntsu;
+
+ while(i--) {
+
+ align= leftsmall= rightsmall= 0;
+
+ /* left handle: */
+ if(flag==0 || (bezt1->f1 & flag) ) {
+ bezt1->h1= 0;
+ /* distance too short: vectorhandle */
+ if( VecLenf( bezt1->vec[1], bezt0->vec[1] ) < 0.0001) {
+ bezt1->h1= HD_VECT;
+ leftsmall= 1;
+ }
+ else {
+ /* aligned handle? */
+ if(DistVL2Dfl(bezt1->vec[1], bezt1->vec[0], bezt1->vec[2]) < 0.0001) {
+ align= 1;
+ bezt1->h1= HD_ALIGN;
+ }
+ /* or vector handle? */
+ if(DistVL2Dfl(bezt1->vec[0], bezt1->vec[1], bezt0->vec[1]) < 0.0001)
+ bezt1->h1= HD_VECT;
+
+ }
+ }
+ /* right handle: */
+ if(flag==0 || (bezt1->f3 & flag) ) {
+ bezt1->h2= 0;
+ /* distance too short: vectorhandle */
+ if( VecLenf( bezt1->vec[1], bezt2->vec[1] ) < 0.0001) {
+ bezt1->h2= HD_VECT;
+ rightsmall= 1;
+ }
+ else {
+ /* aligned handle? */
+ if(align) bezt1->h2= HD_ALIGN;
+
+ /* or vector handle? */
+ if(DistVL2Dfl(bezt1->vec[2], bezt1->vec[1], bezt2->vec[1]) < 0.0001)
+ bezt1->h2= HD_VECT;
+
+ }
+ }
+ if(leftsmall && bezt1->h2==HD_ALIGN) bezt1->h2= 0;
+ if(rightsmall && bezt1->h1==HD_ALIGN) bezt1->h1= 0;
+
+ /* undesired combination: */
+ if(bezt1->h1==HD_ALIGN && bezt1->h2==HD_VECT) bezt1->h1= 0;
+ if(bezt1->h2==HD_ALIGN && bezt1->h1==HD_VECT) bezt1->h2= 0;
+
+ bezt0= bezt1;
+ bezt1= bezt2;
+ bezt2++;
+ }
+
+ calchandlesNurb(nu);
+}
+
+void autocalchandlesNurb_all(int flag)
+{
+ Nurb *nu;
+
+ nu= editNurb.first;
+ while(nu) {
+ autocalchandlesNurb(nu, flag);
+ nu= nu->next;
+ }
+}
+
+void sethandlesNurb(short code)
+{
+ /* code==1: set autohandle */
+ /* code==2: set vectorhandle */
+ /* code==3 (HD_ALIGN) it toggle, vectorhandles become HD_FREE */
+ /* code==4: sets icu flag to become IPO_AUTO_HORIZ, horizontal extremes on auto-handles */
+ Nurb *nu;
+ BezTriple *bezt;
+ short a, ok=0;
+
+ if(code==1 || code==2) {
+ nu= editNurb.first;
+ while(nu) {
+ if( (nu->type & 7)==1) {
+ bezt= nu->bezt;
+ a= nu->pntsu;
+ while(a--) {
+ if(bezt->f1 || bezt->f3) {
+ if(bezt->f1) bezt->h1= code;
+ if(bezt->f3) bezt->h2= code;
+ if(bezt->h1!=bezt->h2) {
+ if ELEM(bezt->h1, HD_ALIGN, HD_AUTO) bezt->h1= HD_FREE;
+ if ELEM(bezt->h2, HD_ALIGN, HD_AUTO) bezt->h2= HD_FREE;
+ }
+ }
+ bezt++;
+ }
+ calchandlesNurb(nu);
+ }
+ nu= nu->next;
+ }
+ }
+ else {
+ /* there is 1 handle not FREE: FREE it all, else make ALIGNED */
+
+ nu= editNurb.first;
+ while(nu) {
+ if( (nu->type & 7)==1) {
+ bezt= nu->bezt;
+ a= nu->pntsu;
+ while(a--) {
+ if(bezt->f1 && bezt->h1) ok= 1;
+ if(bezt->f3 && bezt->h2) ok= 1;
+ if(ok) break;
+ bezt++;
+ }
+ }
+ nu= nu->next;
+ }
+ if(ok) ok= HD_FREE;
+ else ok= HD_ALIGN;
+
+ nu= editNurb.first;
+ while(nu) {
+ if( (nu->type & 7)==1) {
+ bezt= nu->bezt;
+ a= nu->pntsu;
+ while(a--) {
+ if(bezt->f1) bezt->h1= ok;
+ if(bezt->f3 ) bezt->h2= ok;
+
+ bezt++;
+ }
+ calchandlesNurb(nu);
+ }
+ nu= nu->next;
+ }
+ }
+}
+
+static void swapdata(void *adr1, void *adr2, int len)
+{
+
+ if(len<=0) return;
+
+ if(len<65) {
+ char adr[64];
+
+ memcpy(adr, adr1, len);
+ memcpy(adr1, adr2, len);
+ memcpy(adr2, adr, len);
+ }
+ else {
+ char *adr;
+
+ adr= (char *)MEM_mallocN(len, "curve swap");
+ memcpy(adr, adr1, len);
+ memcpy(adr1, adr2, len);
+ memcpy(adr2, adr, len);
+ MEM_freeN(adr);
+ }
+}
+
+void switchdirectionNurb(Nurb *nu)
+{
+ BezTriple *bezt1, *bezt2;
+ BPoint *bp1, *bp2;
+ float *fp1, *fp2, *tempf;
+ int a, b;
+
+ if(nu->pntsu==1 && nu->pntsv==1) return;
+
+ if((nu->type & 7)==CU_BEZIER) {
+ a= nu->pntsu;
+ bezt1= nu->bezt;
+ bezt2= bezt1+(a-1);
+ if(a & 1) a+= 1; /* if odd, also swap middle content */
+ a/= 2;
+ while(a>0) {
+ if(bezt1!=bezt2) SWAP(BezTriple, *bezt1, *bezt2);
+
+ swapdata(bezt1->vec[0], bezt1->vec[2], 12);
+ if(bezt1!=bezt2) swapdata(bezt2->vec[0], bezt2->vec[2], 12);
+
+ SWAP(char, bezt1->h1, bezt1->h2);
+ SWAP(short, bezt1->f1, bezt1->f3);
+
+ if(bezt1!=bezt2) {
+ SWAP(char, bezt2->h1, bezt2->h2);
+ SWAP(short, bezt2->f1, bezt2->f3);
+ bezt1->alfa= -bezt1->alfa;
+ bezt2->alfa= -bezt2->alfa;
+ }
+ a--;
+ bezt1++;
+ bezt2--;
+ }
+ }
+ else if(nu->pntsv==1) {
+ a= nu->pntsu;
+ bp1= nu->bp;
+ bp2= bp1+(a-1);
+ a/= 2;
+ while(bp1!=bp2 && a>0) {
+ SWAP(BPoint, *bp1, *bp2);
+ a--;
+ bp1->alfa= -bp1->alfa;
+ bp2->alfa= -bp2->alfa;
+ bp1++;
+ bp2--;
+ }
+ if((nu->type & 7)==CU_NURBS) {
+ /* inverse knots */
+ a= KNOTSU(nu);
+ fp1= nu->knotsu;
+ fp2= fp1+(a-1);
+ a/= 2;
+ while(fp1!=fp2 && a>0) {
+ SWAP(float, *fp1, *fp2);
+ a--;
+ fp1++;
+ fp2--;
+ }
+ /* and make in increasing order again */
+ a= KNOTSU(nu);
+ fp1= nu->knotsu;
+ fp2=tempf= MEM_mallocN(sizeof(float)*a, "switchdirect");
+ while(a--) {
+ fp2[0]= fabs(fp1[1]-fp1[0]);
+ fp1++;
+ fp2++;
+ }
+
+ a= KNOTSU(nu)-1;
+ fp1= nu->knotsu;
+ fp2= tempf;
+ fp1[0]= 0.0;
+ fp1++;
+ while(a--) {
+ fp1[0]= fp1[-1]+fp2[0];
+ fp1++;
+ fp2++;
+ }
+ MEM_freeN(tempf);
+ }
+ }
+ else {
+
+ for(b=0; b<nu->pntsv; b++) {
+
+ bp1= nu->bp+b*nu->pntsu;
+ a= nu->pntsu;
+ bp2= bp1+(a-1);
+ a/= 2;
+
+ while(bp1!=bp2 && a>0) {
+ SWAP(BPoint, *bp1, *bp2);
+ a--;
+ bp1++;
+ bp2--;
+ }
+ }
+ }
+}
+
+
+float (*curve_getVertexCos(Curve *cu, ListBase *lb, int *numVerts_r))[3]
+{
+ int i, numVerts = *numVerts_r = count_curveverts(lb);
+ float *co, (*cos)[3] = MEM_mallocN(sizeof(*cos)*numVerts, "cu_vcos");
+ Nurb *nu;
+
+ co = cos[0];
+ for (nu=lb->first; nu; nu=nu->next) {
+ if ((nu->type & 7)==CU_BEZIER) {
+ BezTriple *bezt = nu->bezt;
+
+ for (i=0; i<nu->pntsu; i++,bezt++) {
+ VECCOPY(co, bezt->vec[0]); co+=3;
+ VECCOPY(co, bezt->vec[1]); co+=3;
+ VECCOPY(co, bezt->vec[2]); co+=3;
+ }
+ } else {
+ BPoint *bp = nu->bp;
+
+ for (i=0; i<nu->pntsu*nu->pntsv; i++,bp++) {
+ VECCOPY(co, bp->vec); co+=3;
+ }
+ }
+ }
+
+ return cos;
+}
+
+void curve_applyVertexCos(Curve *cu, ListBase *lb, float (*vertexCos)[3])
+{
+ float *co = vertexCos[0];
+ Nurb *nu;
+ int i;
+
+ for (nu=lb->first; nu; nu=nu->next) {
+ if ((nu->type & 7)==CU_BEZIER) {
+ BezTriple *bezt = nu->bezt;
+
+ for (i=0; i<nu->pntsu; i++,bezt++) {
+ VECCOPY(bezt->vec[0], co); co+=3;
+ VECCOPY(bezt->vec[1], co); co+=3;
+ VECCOPY(bezt->vec[2], co); co+=3;
+ }
+ } else {
+ BPoint *bp = nu->bp;
+
+ for (i=0; i<nu->pntsu*nu->pntsv; i++,bp++) {
+ VECCOPY(bp->vec, co); co+=3;
+ }
+ }
+ }
+}
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
new file mode 100644
index 00000000000..466ba9f4201
--- /dev/null
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -0,0 +1,1482 @@
+/*
+* $Id$
+*
+* ***** BEGIN GPL LICENSE BLOCK *****
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*
+* The Original Code is Copyright (C) 2006 Blender Foundation.
+* All rights reserved.
+*
+* The Original Code is: all of this file.
+*
+* Contributor(s): Ben Batt <benbatt@gmail.com>
+*
+* ***** END GPL LICENSE BLOCK *****
+*
+* Implementation of CustomData.
+*
+* BKE_customdata.h contains the function prototypes for this file.
+*
+*/
+
+#include "BKE_customdata.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_linklist.h"
+
+#include "DNA_customdata_types.h"
+#include "DNA_listBase.h"
+#include "DNA_meshdata_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include <string.h>
+
+/* number of layers to add when growing a CustomData object */
+#define CUSTOMDATA_GROW 5
+
+/********************* Layer type information **********************/
+typedef struct LayerTypeInfo {
+ int size; /* the memory size of one element of this layer's data */
+ char *structname; /* name of the struct used, for file writing */
+ int structnum; /* number of structs per element, for file writing */
+ char *defaultname; /* default layer name */
+
+ /* a function to copy count elements of this layer's data
+ * (deep copy if appropriate)
+ * if NULL, memcpy is used
+ */
+ void (*copy)(const void *source, void *dest, int count);
+
+ /* a function to free any dynamically allocated components of this
+ * layer's data (note the data pointer itself should not be freed)
+ * size should be the size of one element of this layer's data (e.g.
+ * LayerTypeInfo.size)
+ */
+ void (*free)(void *data, int count, int size);
+
+ /* a function to interpolate between count source elements of this
+ * layer's data and store the result in dest
+ * if weights == NULL or sub_weights == NULL, they should default to 1
+ *
+ * weights gives the weight for each element in sources
+ * sub_weights gives the sub-element weights for each element in sources
+ * (there should be (sub element count)^2 weights per element)
+ * count gives the number of elements in sources
+ */
+ void (*interp)(void **sources, float *weights, float *sub_weights,
+ int count, void *dest);
+
+ /* a function to swap the data in corners of the element */
+ void (*swap)(void *data, int *corner_indices);
+
+ /* a function to set a layer's data to default values. if NULL, the
+ default is assumed to be all zeros */
+ void (*set_default)(void *data, int count);
+} LayerTypeInfo;
+
+static void layerCopy_mdeformvert(const void *source, void *dest,
+ int count)
+{
+ int i, size = sizeof(MDeformVert);
+
+ memcpy(dest, source, count * size);
+
+ for(i = 0; i < count; ++i) {
+ MDeformVert *dvert = (MDeformVert *)((char *)dest + i * size);
+ MDeformWeight *dw = MEM_callocN(dvert->totweight * sizeof(*dw),
+ "layerCopy_mdeformvert dw");
+
+ memcpy(dw, dvert->dw, dvert->totweight * sizeof(*dw));
+ dvert->dw = dw;
+ }
+}
+
+static void layerFree_mdeformvert(void *data, int count, int size)
+{
+ int i;
+
+ for(i = 0; i < count; ++i) {
+ MDeformVert *dvert = (MDeformVert *)((char *)data + i * size);
+
+ if(dvert->dw) {
+ MEM_freeN(dvert->dw);
+ dvert->dw = NULL;
+ dvert->totweight = 0;
+ }
+ }
+}
+
+static void linklist_free_simple(void *link)
+{
+ MEM_freeN(link);
+}
+
+static void layerInterp_mdeformvert(void **sources, float *weights,
+ float *sub_weights, int count, void *dest)
+{
+ MDeformVert *dvert = dest;
+ LinkNode *dest_dw = NULL; /* a list of lists of MDeformWeight pointers */
+ LinkNode *node;
+ int i, j, totweight;
+
+ if(count <= 0) return;
+
+ /* build a list of unique def_nrs for dest */
+ totweight = 0;
+ for(i = 0; i < count; ++i) {
+ MDeformVert *source = sources[i];
+ float interp_weight = weights ? weights[i] : 1.0f;
+
+ for(j = 0; j < source->totweight; ++j) {
+ MDeformWeight *dw = &source->dw[j];
+
+ for(node = dest_dw; node; node = node->next) {
+ MDeformWeight *tmp_dw = (MDeformWeight *)node->link;
+
+ if(tmp_dw->def_nr == dw->def_nr) {
+ tmp_dw->weight += dw->weight * interp_weight;
+ break;
+ }
+ }
+
+ /* if this def_nr is not in the list, add it */
+ if(!node) {
+ MDeformWeight *tmp_dw = MEM_callocN(sizeof(*tmp_dw),
+ "layerInterp_mdeformvert tmp_dw");
+ tmp_dw->def_nr = dw->def_nr;
+ tmp_dw->weight = dw->weight * interp_weight;
+ BLI_linklist_prepend(&dest_dw, tmp_dw);
+ totweight++;
+ }
+ }
+ }
+
+ /* now we know how many unique deform weights there are, so realloc */
+ if(dvert->dw) MEM_freeN(dvert->dw);
+
+ if(totweight) {
+ dvert->dw = MEM_callocN(sizeof(*dvert->dw) * totweight,
+ "layerInterp_mdeformvert dvert->dw");
+ dvert->totweight = totweight;
+
+ for(i = 0, node = dest_dw; node; node = node->next, ++i)
+ dvert->dw[i] = *((MDeformWeight *)node->link);
+ }
+ else
+ memset(dvert, 0, sizeof(*dvert));
+
+ BLI_linklist_free(dest_dw, linklist_free_simple);
+}
+
+
+static void layerInterp_msticky(void **sources, float *weights,
+ float *sub_weights, int count, void *dest)
+{
+ float co[2], w;
+ MSticky *mst;
+ int i;
+
+ co[0] = co[1] = 0.0f;
+ for(i = 0; i < count; i++) {
+ w = weights ? weights[i] : 1.0f;
+ mst = (MSticky*)sources[i];
+
+ co[0] += w*mst->co[0];
+ co[1] += w*mst->co[1];
+ }
+
+ mst = (MSticky*)dest;
+ mst->co[0] = co[0];
+ mst->co[1] = co[1];
+}
+
+
+static void layerCopy_tface(const void *source, void *dest, int count)
+{
+ const MTFace *source_tf = (const MTFace*)source;
+ MTFace *dest_tf = (MTFace*)dest;
+ int i;
+
+ for(i = 0; i < count; ++i)
+ dest_tf[i] = source_tf[i];
+}
+
+static void layerInterp_tface(void **sources, float *weights,
+ float *sub_weights, int count, void *dest)
+{
+ MTFace *tf = dest;
+ int i, j, k;
+ float uv[4][2];
+ float *sub_weight;
+
+ if(count <= 0) return;
+
+ memset(uv, 0, sizeof(uv));
+
+ sub_weight = sub_weights;
+ for(i = 0; i < count; ++i) {
+ float weight = weights ? weights[i] : 1;
+ MTFace *src = sources[i];
+
+ for(j = 0; j < 4; ++j) {
+ if(sub_weights) {
+ for(k = 0; k < 4; ++k, ++sub_weight) {
+ float w = (*sub_weight) * weight;
+ float *tmp_uv = src->uv[k];
+
+ uv[j][0] += tmp_uv[0] * w;
+ uv[j][1] += tmp_uv[1] * w;
+ }
+ } else {
+ uv[j][0] += src->uv[j][0] * weight;
+ uv[j][1] += src->uv[j][1] * weight;
+ }
+ }
+ }
+
+ *tf = *(MTFace *)sources[0];
+ for(j = 0; j < 4; ++j) {
+ tf->uv[j][0] = uv[j][0];
+ tf->uv[j][1] = uv[j][1];
+ }
+}
+
+static void layerSwap_tface(void *data, int *corner_indices)
+{
+ MTFace *tf = data;
+ float uv[4][2];
+ int j;
+
+ for(j = 0; j < 4; ++j) {
+ uv[j][0] = tf->uv[corner_indices[j]][0];
+ uv[j][1] = tf->uv[corner_indices[j]][1];
+ }
+
+ memcpy(tf->uv, uv, sizeof(tf->uv));
+}
+
+static void layerDefault_tface(void *data, int count)
+{
+ static MTFace default_tf = {{{0, 1}, {0, 0}, {1, 0}, {1, 1}}, NULL,
+ 0, 0, TF_DYNAMIC, 0, 0};
+ MTFace *tf = (MTFace*)data;
+ int i;
+
+ for(i = 0; i < count; i++)
+ tf[i] = default_tf;
+}
+
+static void layerInterp_mcol(void **sources, float *weights,
+ float *sub_weights, int count, void *dest)
+{
+ MCol *mc = dest;
+ int i, j, k;
+ struct {
+ float a;
+ float r;
+ float g;
+ float b;
+ } col[4];
+ float *sub_weight;
+
+ if(count <= 0) return;
+
+ memset(col, 0, sizeof(col));
+
+ sub_weight = sub_weights;
+ for(i = 0; i < count; ++i) {
+ float weight = weights ? weights[i] : 1;
+
+ for(j = 0; j < 4; ++j) {
+ if(sub_weights) {
+ MCol *src = sources[i];
+ for(k = 0; k < 4; ++k, ++sub_weight, ++src) {
+ col[j].a += src->a * (*sub_weight) * weight;
+ col[j].r += src->r * (*sub_weight) * weight;
+ col[j].g += src->g * (*sub_weight) * weight;
+ col[j].b += src->b * (*sub_weight) * weight;
+ }
+ } else {
+ MCol *src = sources[i];
+ col[j].a += src[j].a * weight;
+ col[j].r += src[j].r * weight;
+ col[j].g += src[j].g * weight;
+ col[j].b += src[j].b * weight;
+ }
+ }
+ }
+
+ for(j = 0; j < 4; ++j) {
+ mc[j].a = (int)col[j].a;
+ mc[j].r = (int)col[j].r;
+ mc[j].g = (int)col[j].g;
+ mc[j].b = (int)col[j].b;
+ }
+}
+
+static void layerSwap_mcol(void *data, int *corner_indices)
+{
+ MCol *mcol = data;
+ MCol col[4];
+ int j;
+
+ for(j = 0; j < 4; ++j)
+ col[j] = mcol[corner_indices[j]];
+
+ memcpy(mcol, col, sizeof(col));
+}
+
+static void layerDefault_mcol(void *data, int count)
+{
+ static MCol default_mcol = {255, 255, 255, 255};
+ MCol *mcol = (MCol*)data;
+ int i;
+
+ for(i = 0; i < 4*count; i++)
+ mcol[i] = default_mcol;
+}
+
+const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
+ {sizeof(MVert), "MVert", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(MSticky), "MSticky", 1, NULL, NULL, NULL, layerInterp_msticky, NULL,
+ NULL},
+ {sizeof(MDeformVert), "MDeformVert", 1, NULL, layerCopy_mdeformvert,
+ layerFree_mdeformvert, layerInterp_mdeformvert, NULL, NULL},
+ {sizeof(MEdge), "MEdge", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(MFace), "MFace", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(MTFace), "MTFace", 1, "UVTex", layerCopy_tface, NULL,
+ layerInterp_tface, layerSwap_tface, layerDefault_tface},
+ /* 4 MCol structs per face */
+ {sizeof(MCol)*4, "MCol", 4, "Col", NULL, NULL, layerInterp_mcol,
+ layerSwap_mcol, layerDefault_mcol},
+ {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
+ /* 3 floats per normal vector */
+ {sizeof(float)*3, "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(MFloatProperty), "MFloatProperty",1,"Float",NULL,NULL,NULL,NULL},
+ {sizeof(MIntProperty), "MIntProperty",1,"Int",NULL,NULL,NULL,NULL},
+ {sizeof(MStringProperty), "MStringProperty",1,"String",NULL,NULL,NULL,NULL},
+};
+
+const char *LAYERTYPENAMES[CD_NUMTYPES] = {
+ "CDMVert", "CDMSticky", "CDMDeformVert", "CDMEdge", "CDMFace", "CDMTFace",
+ "CDMCol", "CDOrigIndex", "CDNormal", "CDFlags","CDMFloatProperty","CDMIntProperty","CDMStringProperty"};
+
+const CustomDataMask CD_MASK_BAREMESH =
+ CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MFACE;
+const CustomDataMask CD_MASK_MESH =
+ CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MFACE |
+ CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE | CD_MASK_MCOL |
+ CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR;
+const CustomDataMask CD_MASK_EDITMESH =
+ CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE |
+ CD_MASK_MCOL|CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR;
+const CustomDataMask CD_MASK_DERIVEDMESH =
+ CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE |
+ CD_MASK_MCOL | CD_MASK_ORIGINDEX|
+ CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR;
+
+static const LayerTypeInfo *layerType_getInfo(int type)
+{
+ if(type < 0 || type >= CD_NUMTYPES) return NULL;
+
+ return &LAYERTYPEINFO[type];
+}
+
+static const char *layerType_getName(int type)
+{
+ if(type < 0 || type >= CD_NUMTYPES) return NULL;
+
+ return LAYERTYPENAMES[type];
+}
+
+/********************* CustomData functions *********************/
+static void customData_update_offsets(CustomData *data);
+
+static CustomDataLayer *customData_add_layer__internal(CustomData *data,
+ int type, int alloctype, void *layerdata, int totelem, const char *name);
+
+void CustomData_merge(const struct CustomData *source, struct CustomData *dest,
+ CustomDataMask mask, int alloctype, int totelem)
+{
+ const LayerTypeInfo *typeInfo;
+ CustomDataLayer *layer, *newlayer;
+ int i, type, number = 0, lasttype = -1, lastactive = 0, lastrender = 0;
+
+ for(i = 0; i < source->totlayer; ++i) {
+ layer = &source->layers[i];
+ typeInfo = layerType_getInfo(layer->type);
+
+ type = layer->type;
+
+ if (type != lasttype) {
+ number = 0;
+ lastactive = layer->active;
+ lastrender = layer->active_rnd;
+ lasttype = type;
+ }
+ else
+ number++;
+
+ if(layer->flag & CD_FLAG_NOCOPY) continue;
+ else if(!(mask & (1 << type))) continue;
+ else if(number < CustomData_number_of_layers(dest, type)) continue;
+
+ if((alloctype == CD_ASSIGN) && (layer->flag & CD_FLAG_NOFREE))
+ newlayer = customData_add_layer__internal(dest, type, CD_REFERENCE,
+ layer->data, totelem, layer->name);
+ else
+ newlayer = customData_add_layer__internal(dest, type, alloctype,
+ layer->data, totelem, layer->name);
+
+ if(newlayer) {
+ newlayer->active = lastactive;
+ newlayer->active_rnd = lastrender;
+ }
+ }
+}
+
+void CustomData_copy(const struct CustomData *source, struct CustomData *dest,
+ CustomDataMask mask, int alloctype, int totelem)
+{
+ memset(dest, 0, sizeof(*dest));
+
+ CustomData_merge(source, dest, mask, alloctype, totelem);
+}
+
+static void customData_free_layer__internal(CustomDataLayer *layer, int totelem)
+{
+ const LayerTypeInfo *typeInfo;
+
+ if(!(layer->flag & CD_FLAG_NOFREE) && layer->data) {
+ typeInfo = layerType_getInfo(layer->type);
+
+ if(typeInfo->free)
+ typeInfo->free(layer->data, totelem, typeInfo->size);
+
+ if(layer->data)
+ MEM_freeN(layer->data);
+ }
+}
+
+void CustomData_free(CustomData *data, int totelem)
+{
+ int i;
+
+ for(i = 0; i < data->totlayer; ++i)
+ customData_free_layer__internal(&data->layers[i], totelem);
+
+ if(data->layers)
+ MEM_freeN(data->layers);
+
+ memset(data, 0, sizeof(*data));
+}
+
+static void customData_update_offsets(CustomData *data)
+{
+ const LayerTypeInfo *typeInfo;
+ int i, offset = 0;
+
+ for(i = 0; i < data->totlayer; ++i) {
+ typeInfo = layerType_getInfo(data->layers[i].type);
+
+ data->layers[i].offset = offset;
+ offset += typeInfo->size;
+ }
+
+ data->totsize = offset;
+}
+
+int CustomData_get_layer_index(const CustomData *data, int type)
+{
+ int i;
+
+ for(i=0; i < data->totlayer; ++i)
+ if(data->layers[i].type == type)
+ return i;
+
+ return -1;
+}
+
+int CustomData_get_named_layer_index(const CustomData *data, int type, char *name)
+{
+ int i;
+
+ for(i=0; i < data->totlayer; ++i)
+ if(data->layers[i].type == type && strcmp(data->layers[i].name, name)==0)
+ return i;
+
+ return -1;
+}
+
+int CustomData_get_active_layer_index(const CustomData *data, int type)
+{
+ int i;
+
+ for(i=0; i < data->totlayer; ++i)
+ if(data->layers[i].type == type)
+ return i + data->layers[i].active;
+
+ return -1;
+}
+
+int CustomData_get_render_layer_index(const CustomData *data, int type)
+{
+ int i;
+
+ for(i=0; i < data->totlayer; ++i)
+ if(data->layers[i].type == type)
+ return i + data->layers[i].active_rnd;
+
+ return -1;
+}
+
+int CustomData_get_active_layer(const CustomData *data, int type)
+{
+ int i;
+
+ for(i=0; i < data->totlayer; ++i)
+ if(data->layers[i].type == type)
+ return data->layers[i].active;
+
+ return -1;
+}
+
+int CustomData_get_render_layer(const CustomData *data, int type)
+{
+ int i;
+
+ for(i=0; i < data->totlayer; ++i)
+ if(data->layers[i].type == type)
+ return data->layers[i].active_rnd;
+
+ return -1;
+}
+
+
+void CustomData_set_layer_active(CustomData *data, int type, int n)
+{
+ int i;
+
+ for(i=0; i < data->totlayer; ++i)
+ if(data->layers[i].type == type)
+ data->layers[i].active = n;
+}
+
+void CustomData_set_layer_render(CustomData *data, int type, int n)
+{
+ int i;
+
+ for(i=0; i < data->totlayer; ++i)
+ if(data->layers[i].type == type)
+ data->layers[i].active_rnd = n;
+}
+
+/* for using with an index from CustomData_get_active_layer_index and CustomData_get_render_layer_index */
+void CustomData_set_layer_active_index(CustomData *data, int type, int n)
+{
+ int i;
+
+ for(i=0; i < data->totlayer; ++i)
+ if(data->layers[i].type == type)
+ data->layers[i].active = n-i;
+}
+
+void CustomData_set_layer_render_index(CustomData *data, int type, int n)
+{
+ int i;
+
+ for(i=0; i < data->totlayer; ++i)
+ if(data->layers[i].type == type)
+ data->layers[i].active_rnd = n-i;
+}
+
+
+void CustomData_set_layer_flag(struct CustomData *data, int type, int flag)
+{
+ int i;
+
+ for(i=0; i < data->totlayer; ++i)
+ if(data->layers[i].type == type)
+ data->layers[i].flag |= flag;
+}
+
+static int customData_resize(CustomData *data, int amount)
+{
+ CustomDataLayer *tmp = MEM_callocN(sizeof(*tmp)*(data->maxlayer + amount),
+ "CustomData->layers");
+ if(!tmp) return 0;
+
+ data->maxlayer += amount;
+ if (data->layers) {
+ memcpy(tmp, data->layers, sizeof(*tmp) * data->totlayer);
+ MEM_freeN(data->layers);
+ }
+ data->layers = tmp;
+
+ return 1;
+}
+
+static CustomDataLayer *customData_add_layer__internal(CustomData *data,
+ int type, int alloctype, void *layerdata, int totelem, const char *name)
+{
+ const LayerTypeInfo *typeInfo= layerType_getInfo(type);
+ int size = typeInfo->size * totelem, flag = 0, index = data->totlayer;
+ void *newlayerdata;
+
+ if (!typeInfo->defaultname && CustomData_has_layer(data, type))
+ return &data->layers[CustomData_get_layer_index(data, type)];
+
+ if((alloctype == CD_ASSIGN) || (alloctype == CD_REFERENCE)) {
+ newlayerdata = layerdata;
+ }
+ else {
+ newlayerdata = MEM_callocN(size, layerType_getName(type));
+ if(!newlayerdata)
+ return NULL;
+ }
+
+ if (alloctype == CD_DUPLICATE) {
+ if(typeInfo->copy)
+ typeInfo->copy(layerdata, newlayerdata, totelem);
+ else
+ memcpy(newlayerdata, layerdata, size);
+ }
+ else if (alloctype == CD_DEFAULT) {
+ if(typeInfo->set_default)
+ typeInfo->set_default((char*)newlayerdata, totelem);
+ }
+ else if (alloctype == CD_REFERENCE)
+ flag |= CD_FLAG_NOFREE;
+
+ if(index >= data->maxlayer) {
+ if(!customData_resize(data, CUSTOMDATA_GROW)) {
+ if(newlayerdata != layerdata)
+ MEM_freeN(newlayerdata);
+ return NULL;
+ }
+ }
+
+ data->totlayer++;
+
+ /* keep layers ordered by type */
+ for( ; index > 0 && data->layers[index - 1].type > type; --index)
+ data->layers[index] = data->layers[index - 1];
+
+ data->layers[index].type = type;
+ data->layers[index].flag = flag;
+ data->layers[index].data = newlayerdata;
+
+ if(name) {
+ strcpy(data->layers[index].name, name);
+ CustomData_set_layer_unique_name(data, index);
+ }
+ else
+ data->layers[index].name[0] = '\0';
+
+ if(index > 0 && data->layers[index-1].type == type) {
+ data->layers[index].active = data->layers[index-1].active;
+ data->layers[index].active_rnd = data->layers[index-1].active_rnd;
+ } else {
+ data->layers[index].active = 0;
+ data->layers[index].active_rnd = 0;
+ }
+
+ customData_update_offsets(data);
+
+ return &data->layers[index];
+}
+
+void *CustomData_add_layer(CustomData *data, int type, int alloctype,
+ void *layerdata, int totelem)
+{
+ CustomDataLayer *layer;
+ const LayerTypeInfo *typeInfo= layerType_getInfo(type);
+
+ layer = customData_add_layer__internal(data, type, alloctype, layerdata,
+ totelem, typeInfo->defaultname);
+
+ if(layer)
+ return layer->data;
+
+ return NULL;
+}
+
+/*same as above but accepts a name*/
+void *CustomData_add_layer_named(CustomData *data, int type, int alloctype,
+ void *layerdata, int totelem, char *name)
+{
+ CustomDataLayer *layer;
+
+ layer = customData_add_layer__internal(data, type, alloctype, layerdata,
+ totelem, name);
+
+ if(layer)
+ return layer->data;
+
+ return NULL;
+}
+
+
+int CustomData_free_layer(CustomData *data, int type, int totelem, int index)
+{
+ int i;
+ CustomDataLayer *layer;
+
+ if (index < 0) return 0;
+
+ layer = &data->layers[index];
+
+ customData_free_layer__internal(&data->layers[index], totelem);
+
+ for (i=index+1; i < data->totlayer; ++i)
+ data->layers[i-1] = data->layers[i];
+
+ data->totlayer--;
+
+ /* if layer was last of type in array, set new active layer */
+ if ((index >= data->totlayer) || (data->layers[index].type != type)) {
+ i = CustomData_get_layer_index(data, type);
+
+ if (i >= 0)
+ for (; i < data->totlayer && data->layers[i].type == type; i++) {
+ data->layers[i].active--;
+ data->layers[i].active_rnd--;
+ }
+ }
+
+ if (data->totlayer <= data->maxlayer-CUSTOMDATA_GROW)
+ customData_resize(data, -CUSTOMDATA_GROW);
+
+ customData_update_offsets(data);
+
+ return 1;
+}
+
+int CustomData_free_layer_active(CustomData *data, int type, int totelem)
+{
+ int index = 0;
+ index = CustomData_get_active_layer_index(data, type);
+ if (index < 0) return 0;
+ return CustomData_free_layer(data, type, totelem, index);
+}
+
+
+void CustomData_free_layers(CustomData *data, int type, int totelem)
+{
+ while (CustomData_has_layer(data, type))
+ CustomData_free_layer_active(data, type, totelem);
+}
+
+int CustomData_has_layer(const CustomData *data, int type)
+{
+ return (CustomData_get_layer_index(data, type) != -1);
+}
+
+int CustomData_number_of_layers(const CustomData *data, int type)
+{
+ int i, number = 0;
+
+ for(i = 0; i < data->totlayer; i++)
+ if(data->layers[i].type == type)
+ number++;
+
+ return number;
+}
+
+void *CustomData_duplicate_referenced_layer(struct CustomData *data, int type)
+{
+ CustomDataLayer *layer;
+ int layer_index;
+
+ /* get the layer index of the first layer of type */
+ layer_index = CustomData_get_active_layer_index(data, type);
+ if(layer_index < 0) return NULL;
+
+ layer = &data->layers[layer_index];
+
+ if (layer->flag & CD_FLAG_NOFREE) {
+ layer->data = MEM_dupallocN(layer->data);
+ layer->flag &= ~CD_FLAG_NOFREE;
+ }
+
+ return layer->data;
+}
+
+void *CustomData_duplicate_referenced_layer_named(struct CustomData *data,
+ int type, char *name)
+{
+ CustomDataLayer *layer;
+ int layer_index;
+
+ /* get the layer index of the desired layer */
+ layer_index = CustomData_get_named_layer_index(data, type, name);
+ if(layer_index < 0) return NULL;
+
+ layer = &data->layers[layer_index];
+
+ if (layer->flag & CD_FLAG_NOFREE) {
+ layer->data = MEM_dupallocN(layer->data);
+ layer->flag &= ~CD_FLAG_NOFREE;
+ }
+
+ return layer->data;
+}
+
+void CustomData_free_temporary(CustomData *data, int totelem)
+{
+ CustomDataLayer *layer;
+ int i, j;
+
+ for(i = 0, j = 0; i < data->totlayer; ++i) {
+ layer = &data->layers[i];
+
+ if (i != j)
+ data->layers[j] = data->layers[i];
+
+ if ((layer->flag & CD_FLAG_TEMPORARY) == CD_FLAG_TEMPORARY)
+ customData_free_layer__internal(layer, totelem);
+ else
+ j++;
+ }
+
+ data->totlayer = j;
+
+ if(data->totlayer <= data->maxlayer-CUSTOMDATA_GROW)
+ customData_resize(data, -CUSTOMDATA_GROW);
+
+ customData_update_offsets(data);
+}
+
+void CustomData_set_only_copy(const struct CustomData *data,
+ CustomDataMask mask)
+{
+ int i;
+
+ for(i = 0; i < data->totlayer; ++i)
+ if(!(mask & (1 << data->layers[i].type)))
+ data->layers[i].flag |= CD_FLAG_NOCOPY;
+}
+
+void CustomData_copy_data(const CustomData *source, CustomData *dest,
+ int source_index, int dest_index, int count)
+{
+ const LayerTypeInfo *typeInfo;
+ int src_i, dest_i;
+ int src_offset;
+ int dest_offset;
+
+ /* copies a layer at a time */
+ dest_i = 0;
+ for(src_i = 0; src_i < source->totlayer; ++src_i) {
+
+ /* find the first dest layer with type >= the source type
+ * (this should work because layers are ordered by type)
+ */
+ while(dest_i < dest->totlayer
+ && dest->layers[dest_i].type < source->layers[src_i].type)
+ ++dest_i;
+
+ /* if there are no more dest layers, we're done */
+ if(dest_i >= dest->totlayer) return;
+
+ /* if we found a matching layer, copy the data */
+ if(dest->layers[dest_i].type == source->layers[src_i].type) {
+ char *src_data = source->layers[src_i].data;
+ char *dest_data = dest->layers[dest_i].data;
+
+ typeInfo = layerType_getInfo(source->layers[src_i].type);
+
+ src_offset = source_index * typeInfo->size;
+ dest_offset = dest_index * typeInfo->size;
+
+ if(typeInfo->copy)
+ typeInfo->copy(src_data + src_offset,
+ dest_data + dest_offset,
+ count);
+ else
+ memcpy(dest_data + dest_offset,
+ src_data + src_offset,
+ count * typeInfo->size);
+
+ /* if there are multiple source & dest layers of the same type,
+ * we don't want to copy all source layers to the same dest, so
+ * increment dest_i
+ */
+ ++dest_i;
+ }
+ }
+}
+
+void CustomData_free_elem(CustomData *data, int index, int count)
+{
+ int i;
+ const LayerTypeInfo *typeInfo;
+
+ for(i = 0; i < data->totlayer; ++i) {
+ if(!(data->layers[i].flag & CD_FLAG_NOFREE)) {
+ typeInfo = layerType_getInfo(data->layers[i].type);
+
+ if(typeInfo->free) {
+ int offset = typeInfo->size * index;
+
+ typeInfo->free((char *)data->layers[i].data + offset,
+ count, typeInfo->size);
+ }
+ }
+ }
+}
+
+#define SOURCE_BUF_SIZE 100
+
+void CustomData_interp(const CustomData *source, CustomData *dest,
+ int *src_indices, float *weights, float *sub_weights,
+ int count, int dest_index)
+{
+ int src_i, dest_i;
+ int dest_offset;
+ int j;
+ void *source_buf[SOURCE_BUF_SIZE];
+ void **sources = source_buf;
+
+ /* slow fallback in case we're interpolating a ridiculous number of
+ * elements
+ */
+ if(count > SOURCE_BUF_SIZE)
+ sources = MEM_callocN(sizeof(*sources) * count,
+ "CustomData_interp sources");
+
+ /* interpolates a layer at a time */
+ dest_i = 0;
+ for(src_i = 0; src_i < source->totlayer; ++src_i) {
+ const LayerTypeInfo *typeInfo= layerType_getInfo(source->layers[src_i].type);
+ if(!typeInfo->interp) continue;
+
+ /* find the first dest layer with type >= the source type
+ * (this should work because layers are ordered by type)
+ */
+ while(dest_i < dest->totlayer
+ && dest->layers[dest_i].type < source->layers[src_i].type)
+ ++dest_i;
+
+ /* if there are no more dest layers, we're done */
+ if(dest_i >= dest->totlayer) return;
+
+ /* if we found a matching layer, copy the data */
+ if(dest->layers[dest_i].type == source->layers[src_i].type) {
+ void *src_data = source->layers[src_i].data;
+
+ for(j = 0; j < count; ++j)
+ sources[j] = (char *)src_data
+ + typeInfo->size * src_indices[j];
+
+ dest_offset = dest_index * typeInfo->size;
+
+ typeInfo->interp(sources, weights, sub_weights, count,
+ (char *)dest->layers[dest_i].data + dest_offset);
+
+ /* if there are multiple source & dest layers of the same type,
+ * we don't want to copy all source layers to the same dest, so
+ * increment dest_i
+ */
+ ++dest_i;
+ }
+ }
+
+ if(count > SOURCE_BUF_SIZE) MEM_freeN(sources);
+}
+
+void CustomData_swap(struct CustomData *data, int index, int *corner_indices)
+{
+ const LayerTypeInfo *typeInfo;
+ int i;
+
+ for(i = 0; i < data->totlayer; ++i) {
+ typeInfo = layerType_getInfo(data->layers[i].type);
+
+ if(typeInfo->swap) {
+ int offset = typeInfo->size * index;
+
+ typeInfo->swap((char *)data->layers[i].data + offset, corner_indices);
+ }
+ }
+}
+
+void *CustomData_get(const CustomData *data, int index, int type)
+{
+ int offset;
+ int layer_index;
+
+ /* get the layer index of the active layer of type */
+ layer_index = CustomData_get_active_layer_index(data, type);
+ if(layer_index < 0) return NULL;
+
+ /* get the offset of the desired element */
+ offset = layerType_getInfo(type)->size * index;
+
+ return (char *)data->layers[layer_index].data + offset;
+}
+
+void *CustomData_get_layer(const CustomData *data, int type)
+{
+ /* get the layer index of the active layer of type */
+ int layer_index = CustomData_get_active_layer_index(data, type);
+ if(layer_index < 0) return NULL;
+
+ return data->layers[layer_index].data;
+}
+
+void *CustomData_get_layer_n(const CustomData *data, int type, int n)
+{
+ /* get the layer index of the active layer of type */
+ int layer_index = CustomData_get_layer_index(data, type);
+ if(layer_index < 0) return NULL;
+
+ return data->layers[layer_index+n].data;
+}
+
+void *CustomData_get_layer_named(const struct CustomData *data, int type,
+ char *name)
+{
+ int layer_index = CustomData_get_named_layer_index(data, type, name);
+ if(layer_index < 0) return NULL;
+
+ return data->layers[layer_index].data;
+}
+
+void *CustomData_set_layer(const CustomData *data, int type, void *ptr)
+{
+ /* get the layer index of the first layer of type */
+ int layer_index = CustomData_get_active_layer_index(data, type);
+
+ if(layer_index < 0) return NULL;
+
+ data->layers[layer_index].data = ptr;
+
+ return ptr;
+}
+
+void *CustomData_set_layer_n(const struct CustomData *data, int type, int n, void *ptr)
+{
+ /* get the layer index of the first layer of type */
+ int layer_index = CustomData_get_layer_index(data, type);
+ if(layer_index < 0) return NULL;
+
+ data->layers[layer_index+n].data = ptr;
+
+ return ptr;
+}
+
+void CustomData_set(const CustomData *data, int index, int type, void *source)
+{
+ void *dest = CustomData_get(data, index, type);
+ const LayerTypeInfo *typeInfo = layerType_getInfo(type);
+
+ if(!dest) return;
+
+ if(typeInfo->copy)
+ typeInfo->copy(source, dest, 1);
+ else
+ memcpy(dest, source, typeInfo->size);
+}
+
+/* EditMesh functions */
+
+void CustomData_em_free_block(CustomData *data, void **block)
+{
+ const LayerTypeInfo *typeInfo;
+ int i;
+
+ if(!*block) return;
+
+ for(i = 0; i < data->totlayer; ++i) {
+ if(!(data->layers[i].flag & CD_FLAG_NOFREE)) {
+ typeInfo = layerType_getInfo(data->layers[i].type);
+
+ if(typeInfo->free) {
+ int offset = data->layers[i].offset;
+ typeInfo->free((char*)*block + offset, 1, typeInfo->size);
+ }
+ }
+ }
+
+ MEM_freeN(*block);
+ *block = NULL;
+}
+
+static void CustomData_em_alloc_block(CustomData *data, void **block)
+{
+ /* TODO: optimize free/alloc */
+
+ if (*block)
+ CustomData_em_free_block(data, block);
+
+ if (data->totsize > 0)
+ *block = MEM_callocN(data->totsize, "CustomData EM block");
+ else
+ *block = NULL;
+}
+
+void CustomData_em_copy_data(const CustomData *source, CustomData *dest,
+ void *src_block, void **dest_block)
+{
+ const LayerTypeInfo *typeInfo;
+ int dest_i, src_i;
+
+ if (!*dest_block)
+ CustomData_em_alloc_block(dest, dest_block);
+
+ /* copies a layer at a time */
+ dest_i = 0;
+ for(src_i = 0; src_i < source->totlayer; ++src_i) {
+
+ /* find the first dest layer with type >= the source type
+ * (this should work because layers are ordered by type)
+ */
+ while(dest_i < dest->totlayer
+ && dest->layers[dest_i].type < source->layers[src_i].type)
+ ++dest_i;
+
+ /* if there are no more dest layers, we're done */
+ if(dest_i >= dest->totlayer) return;
+
+ /* if we found a matching layer, copy the data */
+ if(dest->layers[dest_i].type == source->layers[src_i].type) {
+ char *src_data = (char*)src_block + source->layers[src_i].offset;
+ char *dest_data = (char*)*dest_block + dest->layers[dest_i].offset;
+
+ typeInfo = layerType_getInfo(source->layers[src_i].type);
+
+ if(typeInfo->copy)
+ typeInfo->copy(src_data, dest_data, 1);
+ else
+ memcpy(dest_data, src_data, typeInfo->size);
+
+ /* if there are multiple source & dest layers of the same type,
+ * we don't want to copy all source layers to the same dest, so
+ * increment dest_i
+ */
+ ++dest_i;
+ }
+ }
+}
+
+void *CustomData_em_get(const CustomData *data, void *block, int type)
+{
+ int layer_index;
+
+ /* get the layer index of the first layer of type */
+ layer_index = CustomData_get_active_layer_index(data, type);
+ if(layer_index < 0) return NULL;
+
+ return (char *)block + data->layers[layer_index].offset;
+}
+
+void *CustomData_em_get_n(const CustomData *data, void *block, int type, int n)
+{
+ int layer_index;
+
+ /* get the layer index of the first layer of type */
+ layer_index = CustomData_get_active_layer_index(data, type);
+ if(layer_index < 0) return NULL;
+
+ return (char *)block + data->layers[layer_index+n].offset;
+}
+
+void CustomData_em_set(CustomData *data, void *block, int type, void *source)
+{
+ void *dest = CustomData_em_get(data, block, type);
+ const LayerTypeInfo *typeInfo = layerType_getInfo(type);
+
+ if(!dest) return;
+
+ if(typeInfo->copy)
+ typeInfo->copy(source, dest, 1);
+ else
+ memcpy(dest, source, typeInfo->size);
+}
+
+void CustomData_em_set_n(CustomData *data, void *block, int type, int n, void *source)
+{
+ void *dest = CustomData_em_get_n(data, block, type, n);
+ const LayerTypeInfo *typeInfo = layerType_getInfo(type);
+
+ if(!dest) return;
+
+ if(typeInfo->copy)
+ typeInfo->copy(source, dest, 1);
+ else
+ memcpy(dest, source, typeInfo->size);
+}
+
+void CustomData_em_interp(CustomData *data, void **src_blocks, float *weights,
+ float *sub_weights, int count, void *dest_block)
+{
+ int i, j;
+ void *source_buf[SOURCE_BUF_SIZE];
+ void **sources = source_buf;
+
+ /* slow fallback in case we're interpolating a ridiculous number of
+ * elements
+ */
+ if(count > SOURCE_BUF_SIZE)
+ sources = MEM_callocN(sizeof(*sources) * count,
+ "CustomData_interp sources");
+
+ /* interpolates a layer at a time */
+ for(i = 0; i < data->totlayer; ++i) {
+ CustomDataLayer *layer = &data->layers[i];
+ const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type);
+
+ if(typeInfo->interp) {
+ for(j = 0; j < count; ++j)
+ sources[j] = (char *)src_blocks[j] + layer->offset;
+
+ typeInfo->interp(sources, weights, sub_weights, count,
+ (char *)dest_block + layer->offset);
+ }
+ }
+
+ if(count > SOURCE_BUF_SIZE) MEM_freeN(sources);
+}
+
+void CustomData_em_set_default(CustomData *data, void **block)
+{
+ const LayerTypeInfo *typeInfo;
+ int i;
+
+ if (!*block)
+ CustomData_em_alloc_block(data, block);
+
+ for(i = 0; i < data->totlayer; ++i) {
+ int offset = data->layers[i].offset;
+
+ typeInfo = layerType_getInfo(data->layers[i].type);
+
+ if(typeInfo->set_default)
+ typeInfo->set_default((char*)*block + offset, 1);
+ }
+}
+
+void CustomData_to_em_block(const CustomData *source, CustomData *dest,
+ int src_index, void **dest_block)
+{
+ const LayerTypeInfo *typeInfo;
+ int dest_i, src_i, src_offset;
+
+ if (!*dest_block)
+ CustomData_em_alloc_block(dest, dest_block);
+
+ /* copies a layer at a time */
+ dest_i = 0;
+ for(src_i = 0; src_i < source->totlayer; ++src_i) {
+
+ /* find the first dest layer with type >= the source type
+ * (this should work because layers are ordered by type)
+ */
+ while(dest_i < dest->totlayer
+ && dest->layers[dest_i].type < source->layers[src_i].type)
+ ++dest_i;
+
+ /* if there are no more dest layers, we're done */
+ if(dest_i >= dest->totlayer) return;
+
+ /* if we found a matching layer, copy the data */
+ if(dest->layers[dest_i].type == source->layers[src_i].type) {
+ int offset = dest->layers[dest_i].offset;
+ char *src_data = source->layers[src_i].data;
+ char *dest_data = (char*)*dest_block + offset;
+
+ typeInfo = layerType_getInfo(dest->layers[dest_i].type);
+ src_offset = src_index * typeInfo->size;
+
+ if(typeInfo->copy)
+ typeInfo->copy(src_data + src_offset, dest_data, 1);
+ else
+ memcpy(dest_data, src_data + src_offset, typeInfo->size);
+
+ /* if there are multiple source & dest layers of the same type,
+ * we don't want to copy all source layers to the same dest, so
+ * increment dest_i
+ */
+ ++dest_i;
+ }
+ }
+}
+
+void CustomData_from_em_block(const CustomData *source, CustomData *dest,
+ void *src_block, int dest_index)
+{
+ const LayerTypeInfo *typeInfo;
+ int dest_i, src_i, dest_offset;
+
+ /* copies a layer at a time */
+ dest_i = 0;
+ for(src_i = 0; src_i < source->totlayer; ++src_i) {
+
+ /* find the first dest layer with type >= the source type
+ * (this should work because layers are ordered by type)
+ */
+ while(dest_i < dest->totlayer
+ && dest->layers[dest_i].type < source->layers[src_i].type)
+ ++dest_i;
+
+ /* if there are no more dest layers, we're done */
+ if(dest_i >= dest->totlayer) return;
+
+ /* if we found a matching layer, copy the data */
+ if(dest->layers[dest_i].type == source->layers[src_i].type) {
+ int offset = source->layers[src_i].offset;
+ char *src_data = (char*)src_block + offset;
+ char *dest_data = dest->layers[dest_i].data;
+
+ typeInfo = layerType_getInfo(dest->layers[dest_i].type);
+ dest_offset = dest_index * typeInfo->size;
+
+ if(typeInfo->copy)
+ typeInfo->copy(src_data, dest_data + dest_offset, 1);
+ else
+ memcpy(dest_data + dest_offset, src_data, typeInfo->size);
+
+ /* if there are multiple source & dest layers of the same type,
+ * we don't want to copy all source layers to the same dest, so
+ * increment dest_i
+ */
+ ++dest_i;
+ }
+ }
+
+}
+
+void CustomData_file_write_info(int type, char **structname, int *structnum)
+{
+ const LayerTypeInfo *typeInfo = layerType_getInfo(type);
+
+ *structname = typeInfo->structname;
+ *structnum = typeInfo->structnum;
+}
+
+int CustomData_sizeof(int type)
+{
+ const LayerTypeInfo *typeInfo = layerType_getInfo(type);
+
+ return typeInfo->size;
+}
+
+const char *CustomData_layertype_name(int type)
+{
+ return layerType_getName(type);
+}
+
+static int CustomData_is_property_layer(int type)
+{
+ if((type == CD_PROP_FLT) || (type == CD_PROP_INT) || (type == CD_PROP_STR))
+ return 1;
+ return 0;
+}
+
+void CustomData_set_layer_unique_name(CustomData *data, int index)
+{
+ char tempname[64];
+ int number, i, type;
+ char *dot, *name;
+ CustomDataLayer *layer, *nlayer= &data->layers[index];
+ const LayerTypeInfo *typeInfo= layerType_getInfo(nlayer->type);
+
+ if (!typeInfo->defaultname)
+ return;
+
+ type = nlayer->type;
+ name = nlayer->name;
+
+ if (name[0] == '\0')
+ BLI_strncpy(nlayer->name, typeInfo->defaultname, sizeof(nlayer->name));
+
+ /* see if there is a duplicate */
+ for(i=0; i<data->totlayer; i++) {
+ layer = &data->layers[i];
+
+ if(CustomData_is_property_layer(type)){
+ if(i!=index && CustomData_is_property_layer(layer->type) &&
+ strcmp(layer->name, name)==0)
+ break;
+
+ }
+ else{
+ if(i!=index && layer->type==type && strcmp(layer->name, name)==0)
+ break;
+ }
+ }
+
+ if(i == data->totlayer)
+ return;
+
+ /* strip off the suffix */
+ dot = strchr(nlayer->name, '.');
+ if(dot) *dot=0;
+
+ for(number=1; number <=999; number++) {
+ sprintf(tempname, "%s.%03d", nlayer->name, number);
+
+ for(i=0; i<data->totlayer; i++) {
+ layer = &data->layers[i];
+
+ if(CustomData_is_property_layer(type)){
+ if(i!=index && CustomData_is_property_layer(layer->type) &&
+ strcmp(layer->name, tempname)==0)
+
+ break;
+ }
+ else{
+ if(i!=index && layer->type==type && strcmp(layer->name, tempname)==0)
+ break;
+ }
+ }
+
+ if(i == data->totlayer) {
+ BLI_strncpy(nlayer->name, tempname, sizeof(nlayer->name));
+ return;
+ }
+ }
+}
+
+int CustomData_verify_versions(struct CustomData *data, int index)
+{
+ const LayerTypeInfo *typeInfo;
+ CustomDataLayer *layer = &data->layers[index];
+ int i, keeplayer = 1;
+
+ if (layer->type >= CD_NUMTYPES) {
+ keeplayer = 0; /* unknown layer type from future version */
+ }
+ else {
+ typeInfo = layerType_getInfo(layer->type);
+
+ if (!typeInfo->defaultname && (index > 0) &&
+ data->layers[index-1].type == layer->type)
+ keeplayer = 0; /* multiple layers of which we only support one */
+ }
+
+ if (!keeplayer) {
+ for (i=index+1; i < data->totlayer; ++i)
+ data->layers[i-1] = data->layers[i];
+ data->totlayer--;
+ }
+
+ return keeplayer;
+}
+
diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c
new file mode 100644
index 00000000000..9356ba14071
--- /dev/null
+++ b/source/blender/blenkernel/intern/deform.c
@@ -0,0 +1,225 @@
+/* deform.c June 2001
+ *
+ * support for deformation groups
+ *
+ * Reevan McKay
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <string.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_curve_types.h"
+#include "DNA_effect_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_object_force.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_curve.h"
+#include "BKE_deform.h"
+#include "BKE_displist.h"
+#include "BKE_effect.h"
+#include "BKE_global.h"
+#include "BKE_key.h"
+#include "BKE_lattice.h"
+#include "BKE_object.h"
+#include "BKE_softbody.h"
+#include "BKE_utildefines.h"
+#include "BKE_mesh.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+void copy_defgroups (ListBase *outbase, ListBase *inbase)
+{
+ bDeformGroup *defgroup, *defgroupn;
+
+ outbase->first= outbase->last= 0;
+
+ for (defgroup = inbase->first; defgroup; defgroup=defgroup->next){
+ defgroupn= copy_defgroup(defgroup);
+ BLI_addtail(outbase, defgroupn);
+ }
+}
+
+bDeformGroup *copy_defgroup (bDeformGroup *ingroup)
+{
+ bDeformGroup *outgroup;
+
+ if (!ingroup)
+ return NULL;
+
+ outgroup=MEM_callocN(sizeof(bDeformGroup), "copy deformGroup");
+
+ /* For now, just copy everything over. */
+ memcpy (outgroup, ingroup, sizeof(bDeformGroup));
+
+ outgroup->next=outgroup->prev=NULL;
+
+ return outgroup;
+}
+
+bDeformGroup *get_named_vertexgroup (Object *ob, char *name)
+{
+ /* return a pointer to the deform group with this name
+ * or return NULL otherwise.
+ */
+ bDeformGroup *curdef;
+
+ for (curdef = ob->defbase.first; curdef; curdef=curdef->next) {
+ if (!strcmp(curdef->name, name)) {
+ return curdef;
+ }
+ }
+ return NULL;
+}
+
+int get_named_vertexgroup_num (Object *ob, char *name)
+{
+ /* Return the location of the named deform group within the list of
+ * deform groups. This function is a combination of get_defgroup_num and
+ * get_named_vertexgroup. The other two could be called instead, but that
+ * require looping over the vertexgroups twice.
+ */
+ bDeformGroup *curdef;
+ int def_nr;
+
+ for (curdef=ob->defbase.first, def_nr=0; curdef; curdef=curdef->next, def_nr++) {
+ if (!strcmp(curdef->name, name))
+ return def_nr;
+ }
+
+ return -1;
+}
+
+int get_defgroup_num (Object *ob, bDeformGroup *dg)
+{
+ /* Fetch the location of this deform group
+ * within the linked list of deform groups.
+ * (this number is stored in the deform
+ * weights of the deform verts to link them
+ * to this deform group).
+ */
+
+ bDeformGroup *eg;
+ int def_nr;
+
+ eg = ob->defbase.first;
+ def_nr = 0;
+
+ /* loop through all deform groups */
+ while (eg != NULL) {
+
+ /* if the current deform group is
+ * the one we are after, return
+ * def_nr
+ */
+ if (eg == dg) {
+ break;
+ }
+ ++def_nr;
+ eg = eg->next;
+ }
+
+ /* if there was no deform group found then
+ * return -1 (should set up a nice symbolic
+ * constant for this)
+ */
+ if (eg == NULL) return -1;
+
+ return def_nr;
+
+}
+
+void unique_vertexgroup_name (bDeformGroup *dg, Object *ob)
+{
+ bDeformGroup *curdef;
+ int number;
+ int exists = 0;
+ char tempname[64];
+ char *dot;
+
+ if (!ob)
+ return;
+
+ /* See if we are given an empty string */
+ if (dg->name[0] == '\0') {
+ /* give it default name first */
+ strcpy (dg->name, "Group");
+ }
+
+ /* See if we even need to do this */
+ for (curdef = ob->defbase.first; curdef; curdef=curdef->next) {
+ if (dg!=curdef) {
+ if (!strcmp(curdef->name, dg->name)) {
+ exists = 1;
+ break;
+ }
+ }
+ }
+
+ if (!exists)
+ return;
+
+ /* Strip off the suffix */
+ dot=strchr(dg->name, '.');
+ if (dot)
+ *dot=0;
+
+ for (number = 1; number <=999; number++) {
+ sprintf (tempname, "%s.%03d", dg->name, number);
+
+ exists = 0;
+ for (curdef=ob->defbase.first; curdef; curdef=curdef->next) {
+ if (dg!=curdef) {
+ if (!strcmp (curdef->name, tempname)) {
+ exists = 1;
+ break;
+ }
+ }
+ }
+ if (!exists) {
+ BLI_strncpy (dg->name, tempname, 32);
+ return;
+ }
+ }
+}
diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c
new file mode 100644
index 00000000000..11ec8670ed1
--- /dev/null
+++ b/source/blender/blenkernel/intern/depsgraph.c
@@ -0,0 +1,2236 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+#ifdef _WIN32
+#include "BLI_winstuff.h"
+#endif
+
+//#include "BMF_Api.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "DNA_action_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_ID.h"
+#include "DNA_effect_types.h"
+#include "DNA_group_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_key_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_nla_types.h"
+#include "DNA_object_types.h"
+#include "DNA_object_force.h"
+#include "DNA_object_fluidsim.h"
+#include "DNA_oops_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_view2d_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_action.h"
+#include "BKE_effect.h"
+#include "BKE_global.h"
+#include "BKE_group.h"
+#include "BKE_key.h"
+#include "BKE_main.h"
+#include "BKE_mball.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+#include "BKE_scene.h"
+#include "BKE_utildefines.h"
+
+#include "MEM_guardedalloc.h"
+#include "blendef.h"
+
+#include "BPY_extern.h"
+
+ #include "depsgraph_private.h"
+
+/* Queue and stack operations for dag traversal
+ *
+ * the queue store a list of freenodes to avoid successives alloc/dealloc
+ */
+
+DagNodeQueue * queue_create (int slots)
+{
+ DagNodeQueue * queue;
+ DagNodeQueueElem * elem;
+ int i;
+
+ queue = MEM_mallocN(sizeof(DagNodeQueue),"DAG queue");
+ queue->freenodes = MEM_mallocN(sizeof(DagNodeQueue),"DAG queue");
+ queue->count = 0;
+ queue->maxlevel = 0;
+ queue->first = queue->last = NULL;
+ elem = MEM_mallocN(sizeof(DagNodeQueueElem),"DAG queue elem3");
+ elem->node = NULL;
+ elem->next = NULL;
+ queue->freenodes->first = queue->freenodes->last = elem;
+
+ for (i = 1; i <slots;i++) {
+ elem = MEM_mallocN(sizeof(DagNodeQueueElem),"DAG queue elem4");
+ elem->node = NULL;
+ elem->next = NULL;
+ queue->freenodes->last->next = elem;
+ queue->freenodes->last = elem;
+ }
+ queue->freenodes->count = slots;
+ return queue;
+}
+
+void queue_raz(DagNodeQueue *queue)
+{
+ DagNodeQueueElem * elem;
+
+ elem = queue->first;
+ if (queue->freenodes->last)
+ queue->freenodes->last->next = elem;
+ else
+ queue->freenodes->first = queue->freenodes->last = elem;
+
+ elem->node = NULL;
+ queue->freenodes->count++;
+ while (elem->next) {
+ elem = elem->next;
+ elem->node = NULL;
+ queue->freenodes->count++;
+ }
+ queue->freenodes->last = elem;
+ queue->count = 0;
+}
+
+void queue_delete(DagNodeQueue *queue)
+{
+ DagNodeQueueElem * elem;
+ DagNodeQueueElem * temp;
+
+ elem = queue->first;
+ while (elem) {
+ temp = elem;
+ elem = elem->next;
+ MEM_freeN(temp);
+ }
+
+ elem = queue->freenodes->first;
+ while (elem) {
+ temp = elem;
+ elem = elem->next;
+ MEM_freeN(temp);
+ }
+
+ MEM_freeN(queue->freenodes);
+ MEM_freeN(queue);
+}
+
+/* insert in queue, remove in front */
+void push_queue(DagNodeQueue *queue, DagNode *node)
+{
+ DagNodeQueueElem * elem;
+ int i;
+
+ if (node == NULL) {
+ fprintf(stderr,"pushing null node \n");
+ return;
+ }
+ /*fprintf(stderr,"BFS push : %s %d\n",((ID *) node->ob)->name, queue->count);*/
+
+ elem = queue->freenodes->first;
+ if (elem != NULL) {
+ queue->freenodes->first = elem->next;
+ if ( queue->freenodes->last == elem) {
+ queue->freenodes->last = NULL;
+ queue->freenodes->first = NULL;
+ }
+ queue->freenodes->count--;
+ } else { /* alllocating more */
+ elem = MEM_mallocN(sizeof(DagNodeQueueElem),"DAG queue elem1");
+ elem->node = NULL;
+ elem->next = NULL;
+ queue->freenodes->first = queue->freenodes->last = elem;
+
+ for (i = 1; i <DAGQUEUEALLOC;i++) {
+ elem = MEM_mallocN(sizeof(DagNodeQueueElem),"DAG queue elem2");
+ elem->node = NULL;
+ elem->next = NULL;
+ queue->freenodes->last->next = elem;
+ queue->freenodes->last = elem;
+ }
+ queue->freenodes->count = DAGQUEUEALLOC;
+
+ elem = queue->freenodes->first;
+ queue->freenodes->first = elem->next;
+ }
+ elem->next = NULL;
+ elem->node = node;
+ if (queue->last != NULL)
+ queue->last->next = elem;
+ queue->last = elem;
+ if (queue->first == NULL) {
+ queue->first = elem;
+ }
+ queue->count++;
+}
+
+
+/* insert in front, remove in front */
+void push_stack(DagNodeQueue *queue, DagNode *node)
+{
+ DagNodeQueueElem * elem;
+ int i;
+
+ elem = queue->freenodes->first;
+ if (elem != NULL) {
+ queue->freenodes->first = elem->next;
+ if ( queue->freenodes->last == elem) {
+ queue->freenodes->last = NULL;
+ queue->freenodes->first = NULL;
+ }
+ queue->freenodes->count--;
+ } else { /* alllocating more */
+ elem = MEM_mallocN(sizeof(DagNodeQueueElem),"DAG queue elem1");
+ elem->node = NULL;
+ elem->next = NULL;
+ queue->freenodes->first = queue->freenodes->last = elem;
+
+ for (i = 1; i <DAGQUEUEALLOC;i++) {
+ elem = MEM_mallocN(sizeof(DagNodeQueueElem),"DAG queue elem2");
+ elem->node = NULL;
+ elem->next = NULL;
+ queue->freenodes->last->next = elem;
+ queue->freenodes->last = elem;
+ }
+ queue->freenodes->count = DAGQUEUEALLOC;
+
+ elem = queue->freenodes->first;
+ queue->freenodes->first = elem->next;
+ }
+ elem->next = queue->first;
+ elem->node = node;
+ queue->first = elem;
+ if (queue->last == NULL)
+ queue->last = elem;
+ queue->count++;
+}
+
+
+DagNode * pop_queue(DagNodeQueue *queue)
+{
+ DagNodeQueueElem * elem;
+ DagNode *node;
+
+ elem = queue->first;
+ if (elem) {
+ queue->first = elem->next;
+ if (queue->last == elem) {
+ queue->last=NULL;
+ queue->first=NULL;
+ }
+ queue->count--;
+ if (queue->freenodes->last)
+ queue->freenodes->last->next=elem;
+ queue->freenodes->last=elem;
+ if (queue->freenodes->first == NULL)
+ queue->freenodes->first=elem;
+ node = elem->node;
+ elem->node = NULL;
+ elem->next = NULL;
+ queue->freenodes->count++;
+ return node;
+ } else {
+ fprintf(stderr,"return null \n");
+ return NULL;
+ }
+}
+
+void *pop_ob_queue(struct DagNodeQueue *queue) {
+ return(pop_queue(queue)->ob);
+}
+
+DagNode * get_top_node_queue(DagNodeQueue *queue)
+{
+ return queue->first->node;
+}
+
+int queue_count(struct DagNodeQueue *queue){
+ return queue->count;
+}
+
+
+DagForest * dag_init()
+{
+ DagForest *forest;
+ /* use callocN to init all zero */
+ forest = MEM_callocN(sizeof(DagForest),"DAG root");
+ return forest;
+}
+
+static void dag_add_driver_relation(Ipo *ipo, DagForest *dag, DagNode *node, int isdata)
+{
+ IpoCurve *icu;
+ DagNode *node1;
+
+ for(icu= ipo->curve.first; icu; icu= icu->next) {
+ if(icu->driver) {
+
+ if (icu->driver->type == IPO_DRIVER_TYPE_PYTHON) {
+
+ if ((icu->driver->flag & IPO_DRIVER_FLAG_INVALID) || (icu->driver->name[0] == '\0'))
+ continue; /* empty or invalid expression */
+ else {
+ /* now we need refs to all objects mentioned in this
+ * pydriver expression, to call 'dag_add_relation'
+ * for each of them */
+ Object **obarray = BPY_pydriver_get_objects(icu->driver);
+ if (obarray) {
+ Object *ob, **oba = obarray;
+
+ while (*oba) {
+ ob = *oba;
+ node1 = dag_get_node(dag, ob);
+ if (ob->type == OB_ARMATURE)
+ dag_add_relation(dag, node1, node, isdata?DAG_RL_DATA_DATA:DAG_RL_DATA_OB);
+ else
+ dag_add_relation(dag, node1, node, isdata?DAG_RL_OB_DATA:DAG_RL_OB_OB);
+ oba++;
+ }
+
+ MEM_freeN(obarray);
+ }
+ }
+ }
+ else if (icu->driver->ob) {
+ node1 = dag_get_node(dag, icu->driver->ob);
+ if(icu->driver->blocktype==ID_AR)
+ dag_add_relation(dag, node1, node, isdata?DAG_RL_DATA_DATA:DAG_RL_DATA_OB);
+ else
+ dag_add_relation(dag, node1, node, isdata?DAG_RL_OB_DATA:DAG_RL_OB_OB);
+ }
+ }
+ }
+}
+
+static void build_dag_object(DagForest *dag, DagNode *scenenode, Object *ob, int mask)
+{
+ bConstraint *con;
+ bConstraintChannel *conchan;
+ DagNode * node;
+ DagNode * node2;
+ DagNode * node3;
+ Key *key;
+ int addtoroot= 1;
+
+ node = dag_get_node(dag, ob);
+
+ if ((ob->data) && (mask&DAG_RL_DATA)) {
+ node2 = dag_get_node(dag,ob->data);
+ dag_add_relation(dag,node,node2,DAG_RL_DATA);
+ node2->first_ancestor = ob;
+ node2->ancestor_count += 1;
+ }
+
+ if (ob->type == OB_ARMATURE) {
+ if (ob->pose){
+ bPoseChannel *pchan;
+ bConstraint *con;
+
+ for (pchan = ob->pose->chanbase.first; pchan; pchan=pchan->next) {
+ for (con = pchan->constraints.first; con; con=con->next) {
+ bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+
+ if (cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(con, &targets);
+
+ for (ct= targets.first; ct; ct= ct->next) {
+ if (ct->tar && ct->tar != ob) {
+ // fprintf(stderr,"armature %s target :%s \n", ob->id.name, target->id.name);
+ node3 = dag_get_node(dag, ct->tar);
+
+ if (ct->subtarget[0])
+ dag_add_relation(dag,node3,node, DAG_RL_OB_DATA|DAG_RL_DATA_DATA);
+ else if(ELEM(con->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO))
+ dag_add_relation(dag,node3,node, DAG_RL_DATA_DATA|DAG_RL_OB_DATA);
+ else
+ dag_add_relation(dag,node3,node, DAG_RL_OB_DATA);
+ }
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(con, &targets, 1);
+ }
+
+ }
+ }
+ }
+ }
+
+ /* driver dependencies, nla modifiers */
+ if(ob->ipo)
+ dag_add_driver_relation(ob->ipo, dag, node, 0);
+
+ key= ob_get_key(ob);
+ if(key && key->ipo)
+ dag_add_driver_relation(key->ipo, dag, node, 1);
+
+ for (conchan=ob->constraintChannels.first; conchan; conchan=conchan->next)
+ if(conchan->ipo)
+ dag_add_driver_relation(conchan->ipo, dag, node, 0);
+
+ if(ob->action) {
+ bActionChannel *chan;
+ for (chan = ob->action->chanbase.first; chan; chan=chan->next){
+ if(chan->ipo)
+ dag_add_driver_relation(chan->ipo, dag, node, 1);
+ for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
+ if(conchan->ipo)
+ dag_add_driver_relation(conchan->ipo, dag, node, 1);
+ }
+ }
+ if(ob->nlastrips.first) {
+ bActionStrip *strip;
+ bActionChannel *chan;
+ for(strip= ob->nlastrips.first; strip; strip= strip->next) {
+ if(strip->act && strip->act!=ob->action)
+ for (chan = strip->act->chanbase.first; chan; chan=chan->next)
+ if(chan->ipo)
+ dag_add_driver_relation(chan->ipo, dag, node, 1);
+ if(strip->modifiers.first) {
+ bActionModifier *amod;
+ for(amod= strip->modifiers.first; amod; amod= amod->next) {
+ if(amod->ob) {
+ node2 = dag_get_node(dag, amod->ob);
+ dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA|DAG_RL_OB_DATA);
+ }
+ }
+ }
+ }
+ }
+ if (ob->modifiers.first) {
+ ModifierData *md;
+
+ for(md=ob->modifiers.first; md; md=md->next) {
+ ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ if (mti->updateDepgraph) mti->updateDepgraph(md, dag, ob, node);
+ }
+ }
+ if (ob->parent) {
+ node2 = dag_get_node(dag,ob->parent);
+
+ switch(ob->partype) {
+ case PARSKEL:
+ dag_add_relation(dag,node2,node,DAG_RL_DATA_DATA|DAG_RL_OB_OB);
+ break;
+ case PARVERT1: case PARVERT3: case PARBONE:
+ dag_add_relation(dag,node2,node,DAG_RL_DATA_OB|DAG_RL_OB_OB);
+ break;
+ default:
+ if(ob->parent->type==OB_LATTICE)
+ dag_add_relation(dag,node2,node,DAG_RL_DATA_DATA|DAG_RL_OB_OB);
+ else if(ob->parent->type==OB_CURVE) {
+ Curve *cu= ob->parent->data;
+ if(cu->flag & CU_PATH)
+ dag_add_relation(dag,node2,node,DAG_RL_DATA_OB|DAG_RL_OB_OB);
+ else
+ dag_add_relation(dag,node2,node,DAG_RL_OB_OB);
+ }
+ else
+ dag_add_relation(dag,node2,node,DAG_RL_OB_OB);
+ }
+ /* exception case: parent is duplivert */
+ if(ob->type==OB_MBALL && (ob->parent->transflag & OB_DUPLIVERTS)) {
+ dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA|DAG_RL_OB_OB);
+ }
+
+ addtoroot = 0;
+ }
+ if (ob->track) {
+ node2 = dag_get_node(dag,ob->track);
+ dag_add_relation(dag,node2,node,DAG_RL_OB_OB);
+ addtoroot = 0;
+ }
+ if (ob->proxy) {
+ node2 = dag_get_node(dag, ob->proxy);
+ dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA|DAG_RL_OB_OB);
+ /* inverted relation, so addtoroot shouldn't be set to zero */
+ }
+ if (ob->type==OB_CAMERA) {
+ Camera *cam = (Camera *)ob->data;
+ if (cam->dof_ob) {
+ node2 = dag_get_node(dag, cam->dof_ob);
+ dag_add_relation(dag,node2,node,DAG_RL_OB_OB);
+ }
+ }
+ if (ob->transflag & OB_DUPLI) {
+ if((ob->transflag & OB_DUPLIGROUP) && ob->dup_group) {
+ GroupObject *go;
+ for(go= ob->dup_group->gobject.first; go; go= go->next) {
+ if(go->ob) {
+ node2 = dag_get_node(dag, go->ob);
+ /* node2 changes node1, this keeps animations updated in groups?? not logical? */
+ dag_add_relation(dag, node2, node, DAG_RL_OB_OB);
+ }
+ }
+ }
+ }
+
+ /* softbody collision */
+ if((ob->type==OB_MESH) || (ob->type==OB_CURVE) || (ob->type==OB_LATTICE)) {
+ Base *base;
+ if(modifiers_isSoftbodyEnabled(ob)){
+ // would be nice to have a list of colliders here
+ // so for now walk all objects in scene check 'same layer rule'
+ for(base = G.scene->base.first; base; base= base->next) {
+ if( (base->lay & ob->lay) && base->object->pd) {
+ Object *ob1= base->object;
+ if((ob1->pd->deflect) && (ob1 != ob)) {
+ node2 = dag_get_node(dag, ob1);
+ dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA|DAG_RL_OB_DATA);
+ }
+ }
+ }
+ }
+ }
+
+ if (ob->type==OB_MBALL) {
+ Object *mom= find_basis_mball(ob);
+ if(mom!=ob) {
+ node2 = dag_get_node(dag, mom);
+ dag_add_relation(dag,node,node2,DAG_RL_DATA_DATA|DAG_RL_OB_DATA); // mom depends on children!
+ }
+ }
+ else if (ob->type==OB_CURVE) {
+ Curve *cu= ob->data;
+ if(cu->bevobj) {
+ node2 = dag_get_node(dag, cu->bevobj);
+ dag_add_relation(dag,node2,node,DAG_RL_DATA_DATA|DAG_RL_OB_DATA);
+ }
+ if(cu->taperobj) {
+ node2 = dag_get_node(dag, cu->taperobj);
+ dag_add_relation(dag,node2,node,DAG_RL_DATA_DATA|DAG_RL_OB_DATA);
+ }
+ if(cu->ipo)
+ dag_add_driver_relation(cu->ipo, dag, node, 1);
+
+ }
+ else if(ob->type==OB_FONT) {
+ Curve *cu= ob->data;
+ if(cu->textoncurve) {
+ node2 = dag_get_node(dag, cu->textoncurve);
+ dag_add_relation(dag,node2,node,DAG_RL_DATA_DATA|DAG_RL_OB_DATA);
+ }
+ }
+ else if(ob->type==OB_MESH) {
+ PartEff *paf= give_parteff(ob);
+ if(paf) {
+ ListBase *listb;
+ pEffectorCache *ec;
+
+ /* ob location depends on itself */
+ if((paf->flag & PAF_STATIC)==0)
+ dag_add_relation(dag, node, node, DAG_RL_OB_DATA);
+
+ listb= pdInitEffectors(ob, paf->group); /* note, makes copy... */
+ if(listb) {
+ for(ec= listb->first; ec; ec= ec->next) {
+ Object *ob1= ec->ob;
+ PartDeflect *pd= ob1->pd;
+
+ if(pd->forcefield) {
+ node2 = dag_get_node(dag, ob1);
+ if(pd->forcefield==PFIELD_GUIDE)
+ dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA|DAG_RL_OB_DATA);
+ else
+ dag_add_relation(dag, node2, node, DAG_RL_OB_DATA);
+ }
+ }
+
+ pdEndEffectors(listb); /* restores copy... */
+ }
+ }
+ }
+
+ for (con = ob->constraints.first; con; con=con->next) {
+ bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+
+ if (cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(con, &targets);
+
+ for (ct= targets.first; ct; ct= ct->next) {
+ Object *obt;
+
+ if (ct->tar)
+ obt= ct->tar;
+ else
+ continue;
+
+ node2 = dag_get_node(dag, obt);
+ if (ELEM(con->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO))
+ dag_add_relation(dag, node2, node, DAG_RL_DATA_OB|DAG_RL_OB_OB);
+ else {
+ if (ELEM3(obt->type, OB_ARMATURE, OB_MESH, OB_LATTICE) && (ct->subtarget[0]))
+ dag_add_relation(dag, node2, node, DAG_RL_DATA_OB|DAG_RL_OB_OB);
+ else
+ dag_add_relation(dag, node2, node, DAG_RL_OB_OB);
+ }
+ addtoroot = 0;
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(con, &targets, 1);
+ }
+ }
+
+ if (addtoroot == 1 )
+ dag_add_relation(dag,scenenode,node,DAG_RL_SCENE);
+}
+
+struct DagForest *build_dag(struct Scene *sce, short mask)
+{
+ Base *base;
+ Object *ob;
+ Group *group;
+ GroupObject *go;
+ DagNode *node;
+ DagNode *scenenode;
+ DagForest *dag;
+ DagAdjList *itA;
+
+ dag = sce->theDag;
+ sce->dagisvalid=1;
+ if ( dag)
+ free_forest( dag );
+ else {
+ dag = dag_init();
+ sce->theDag = dag;
+ }
+
+ /* add base node for scene. scene is always the first node in DAG */
+ scenenode = dag_add_node(dag, sce);
+
+ /* add current scene objects */
+ for(base = sce->base.first; base; base= base->next) {
+ ob= base->object;
+
+ build_dag_object(dag, scenenode, ob, mask);
+ if(ob->proxy)
+ build_dag_object(dag, scenenode, ob->proxy, mask);
+
+ /* handled in next loop */
+ if(ob->dup_group)
+ ob->dup_group->id.flag |= LIB_DOIT;
+ }
+
+ /* add groups used in current scene objects */
+ for(group= G.main->group.first; group; group= group->id.next) {
+ if(group->id.flag & LIB_DOIT) {
+ for(go= group->gobject.first; go; go= go->next) {
+ build_dag_object(dag, scenenode, go->ob, mask);
+ }
+ group->id.flag &= ~LIB_DOIT;
+ }
+ }
+
+ /* Now all relations were built, but we need to solve 1 exceptional case;
+ When objects have multiple "parents" (for example parent + constraint working on same object)
+ the relation type has to be synced. One of the parents can change, and should give same event to child */
+
+ /* nodes were callocced, so we can use node->color for temporal storage */
+ for(node = sce->theDag->DagNode.first; node; node= node->next) {
+ if(node->type==ID_OB) {
+ for(itA = node->child; itA; itA= itA->next) {
+ if(itA->node->type==ID_OB) {
+ itA->node->color |= itA->type;
+ }
+ }
+ }
+ }
+ /* now set relations equal, so that when only one parent changes, the correct recalcs are found */
+ for(node = sce->theDag->DagNode.first; node; node= node->next) {
+ if(node->type==ID_OB) {
+ for(itA = node->child; itA; itA= itA->next) {
+ if(itA->node->type==ID_OB) {
+ itA->type |= itA->node->color;
+ }
+ }
+ }
+ }
+
+ // cycle detection and solving
+ // solve_cycles(dag);
+
+ return dag;
+}
+
+
+void free_forest(DagForest *Dag)
+{ /* remove all nodes and deps */
+ DagNode *tempN;
+ DagAdjList *tempA;
+ DagAdjList *itA;
+ DagNode *itN = Dag->DagNode.first;
+
+ while (itN) {
+ itA = itN->child;
+ while (itA) {
+ tempA = itA;
+ itA = itA->next;
+ MEM_freeN(tempA);
+ }
+
+ itA = itN->parent;
+ while (itA) {
+ tempA = itA;
+ itA = itA->next;
+ MEM_freeN(tempA);
+ }
+
+ tempN = itN;
+ itN = itN->next;
+ MEM_freeN(tempN);
+ }
+ Dag->DagNode.first = NULL;
+ Dag->DagNode.last = NULL;
+ Dag->numNodes = 0;
+
+}
+
+DagNode * dag_find_node (DagForest *forest,void * fob)
+{
+ DagNode *node = forest->DagNode.first;
+
+ while (node) {
+ if (node->ob == fob)
+ return node;
+ node = node->next;
+ }
+ return NULL;
+}
+
+static int ugly_hack_sorry= 1; // prevent type check
+
+/* no checking of existance, use dag_find_node first or dag_get_node */
+DagNode * dag_add_node (DagForest *forest, void * fob)
+{
+ DagNode *node;
+
+ node = MEM_callocN(sizeof(DagNode),"DAG node");
+ if (node) {
+ node->ob = fob;
+ node->color = DAG_WHITE;
+
+ if(ugly_hack_sorry) node->type = GS(((ID *) fob)->name); // sorry, done for pose sorting
+ if (forest->numNodes) {
+ ((DagNode *) forest->DagNode.last)->next = node;
+ forest->DagNode.last = node;
+ forest->numNodes++;
+ } else {
+ forest->DagNode.last = node;
+ forest->DagNode.first = node;
+ forest->numNodes = 1;
+ }
+ }
+ return node;
+}
+
+DagNode * dag_get_node (DagForest *forest,void * fob)
+{
+ DagNode *node;
+
+ node = dag_find_node (forest, fob);
+ if (!node)
+ node = dag_add_node(forest, fob);
+ return node;
+}
+
+
+
+DagNode * dag_get_sub_node (DagForest *forest,void * fob)
+{
+ DagNode *node;
+ DagAdjList *mainchild, *prev=NULL;
+
+ mainchild = ((DagNode *) forest->DagNode.first)->child;
+ /* remove from first node (scene) adj list if present */
+ while (mainchild) {
+ if (mainchild->node == fob) {
+ if (prev) {
+ prev->next = mainchild->next;
+ MEM_freeN(mainchild);
+ break;
+ } else {
+ ((DagNode *) forest->DagNode.first)->child = mainchild->next;
+ MEM_freeN(mainchild);
+ break;
+ }
+ }
+ prev = mainchild;
+ mainchild = mainchild->next;
+ }
+ node = dag_find_node (forest, fob);
+ if (!node)
+ node = dag_add_node(forest, fob);
+ return node;
+}
+
+void dag_add_relation(DagForest *forest, DagNode *fob1, DagNode *fob2, short rel)
+{
+ DagAdjList *itA = fob1->child;
+
+ while (itA) { /* search if relation exist already */
+ if (itA->node == fob2) {
+ itA->type |= rel;
+ itA->count += 1;
+ return;
+ }
+ itA = itA->next;
+ }
+ /* create new relation and insert at head. MALLOC alert! */
+ itA = MEM_mallocN(sizeof(DagAdjList),"DAG adj list");
+ itA->node = fob2;
+ itA->type = rel;
+ itA->count = 1;
+ itA->next = fob1->child;
+ fob1->child = itA;
+}
+
+static void dag_add_parent_relation(DagForest *forest, DagNode *fob1, DagNode *fob2, short rel)
+{
+ DagAdjList *itA = fob2->parent;
+
+ while (itA) { /* search if relation exist already */
+ if (itA->node == fob1) {
+ itA->type |= rel;
+ itA->count += 1;
+ return;
+ }
+ itA = itA->next;
+ }
+ /* create new relation and insert at head. MALLOC alert! */
+ itA = MEM_mallocN(sizeof(DagAdjList),"DAG adj list");
+ itA->node = fob1;
+ itA->type = rel;
+ itA->count = 1;
+ itA->next = fob2->parent;
+ fob2->parent = itA;
+}
+
+
+/*
+ * MainDAG is the DAG of all objects in current scene
+ * used only for drawing there is one also in each scene
+ */
+static DagForest * MainDag = NULL;
+
+DagForest *getMainDag(void)
+{
+ return MainDag;
+}
+
+
+void setMainDag(DagForest *dag)
+{
+ MainDag = dag;
+}
+
+
+/*
+ * note for BFS/DFS
+ * in theory we should sweep the whole array
+ * but in our case the first node is the scene
+ * and is linked to every other object
+ *
+ * for general case we will need to add outer loop
+ */
+
+/*
+ * ToDo : change pos kludge
+ */
+
+/* adjust levels for drawing in oops space */
+void graph_bfs(void)
+{
+ DagNode *node;
+ DagNodeQueue *nqueue;
+ int pos[50];
+ int i;
+ DagAdjList *itA;
+ int minheight;
+
+ /* fprintf(stderr,"starting BFS \n ------------\n"); */
+ nqueue = queue_create(DAGQUEUEALLOC);
+ for ( i=0; i<50; i++)
+ pos[i] = 0;
+
+ /* Init
+ * dagnode.first is alway the root (scene)
+ */
+ node = MainDag->DagNode.first;
+ while(node) {
+ node->color = DAG_WHITE;
+ node->BFS_dist = 9999;
+ node->k = 0;
+ node = node->next;
+ }
+
+ node = MainDag->DagNode.first;
+ if (node->color == DAG_WHITE) {
+ node->color = DAG_GRAY;
+ node->BFS_dist = 1;
+ push_queue(nqueue,node);
+ while(nqueue->count) {
+ node = pop_queue(nqueue);
+
+ minheight = pos[node->BFS_dist];
+ itA = node->child;
+ while(itA != NULL) {
+ if((itA->node->color == DAG_WHITE) ) {
+ itA->node->color = DAG_GRAY;
+ itA->node->BFS_dist = node->BFS_dist + 1;
+ itA->node->k = (float) minheight;
+ push_queue(nqueue,itA->node);
+ }
+
+ else {
+ fprintf(stderr,"bfs not dag tree edge color :%i \n",itA->node->color);
+ }
+
+
+ itA = itA->next;
+ }
+ if (pos[node->BFS_dist] > node->k ) {
+ pos[node->BFS_dist] += 1;
+ node->k = (float) pos[node->BFS_dist];
+ } else {
+ pos[node->BFS_dist] = (int) node->k +1;
+ }
+ set_node_xy(node, node->BFS_dist*DEPSX*2, pos[node->BFS_dist]*DEPSY*2);
+ node->color = DAG_BLACK;
+ /*
+ fprintf(stderr,"BFS node : %20s %i %5.0f %5.0f\n",((ID *) node->ob)->name,node->BFS_dist, node->x, node->y);
+ */
+ }
+ }
+ queue_delete(nqueue);
+}
+
+int pre_and_post_BFS(DagForest *dag, short mask, graph_action_func pre_func, graph_action_func post_func, void **data) {
+ DagNode *node;
+
+ node = dag->DagNode.first;
+ return pre_and_post_source_BFS(dag, mask, node, pre_func, post_func, data);
+}
+
+
+int pre_and_post_source_BFS(DagForest *dag, short mask, DagNode *source, graph_action_func pre_func, graph_action_func post_func, void **data)
+{
+ DagNode *node;
+ DagNodeQueue *nqueue;
+ DagAdjList *itA;
+ int retval = 0;
+ /* fprintf(stderr,"starting BFS \n ------------\n"); */
+
+ /* Init
+ * dagnode.first is alway the root (scene)
+ */
+ node = dag->DagNode.first;
+ nqueue = queue_create(DAGQUEUEALLOC);
+ while(node) {
+ node->color = DAG_WHITE;
+ node->BFS_dist = 9999;
+ node = node->next;
+ }
+
+ node = source;
+ if (node->color == DAG_WHITE) {
+ node->color = DAG_GRAY;
+ node->BFS_dist = 1;
+ pre_func(node->ob,data);
+
+ while(nqueue->count) {
+ node = pop_queue(nqueue);
+
+ itA = node->child;
+ while(itA != NULL) {
+ if((itA->node->color == DAG_WHITE) && (itA->type & mask)) {
+ itA->node->color = DAG_GRAY;
+ itA->node->BFS_dist = node->BFS_dist + 1;
+ push_queue(nqueue,itA->node);
+ pre_func(node->ob,data);
+ }
+
+ else { // back or cross edge
+ retval = 1;
+ }
+ itA = itA->next;
+ }
+ post_func(node->ob,data);
+ node->color = DAG_BLACK;
+ /*
+ fprintf(stderr,"BFS node : %20s %i %5.0f %5.0f\n",((ID *) node->ob)->name,node->BFS_dist, node->x, node->y);
+ */
+ }
+ }
+ queue_delete(nqueue);
+ return retval;
+}
+
+/* non recursive version of DFS, return queue -- outer loop present to catch odd cases (first level cycles)*/
+DagNodeQueue * graph_dfs(void)
+{
+ DagNode *node;
+ DagNodeQueue *nqueue;
+ DagNodeQueue *retqueue;
+ int pos[50];
+ int i;
+ DagAdjList *itA;
+ int time;
+ int skip = 0;
+ int minheight;
+ int maxpos=0;
+ int is_cycle = 0;
+ /*
+ *fprintf(stderr,"starting DFS \n ------------\n");
+ */
+ nqueue = queue_create(DAGQUEUEALLOC);
+ retqueue = queue_create(MainDag->numNodes);
+ for ( i=0; i<50; i++)
+ pos[i] = 0;
+
+ /* Init
+ * dagnode.first is alway the root (scene)
+ */
+ node = MainDag->DagNode.first;
+ while(node) {
+ node->color = DAG_WHITE;
+ node->DFS_dist = 9999;
+ node->DFS_dvtm = node->DFS_fntm = 9999;
+ node->k = 0;
+ node = node->next;
+ }
+
+ time = 1;
+
+ node = MainDag->DagNode.first;
+
+ do {
+ if (node->color == DAG_WHITE) {
+ node->color = DAG_GRAY;
+ node->DFS_dist = 1;
+ node->DFS_dvtm = time;
+ time++;
+ push_stack(nqueue,node);
+
+ while(nqueue->count) {
+ //graph_print_queue(nqueue);
+
+ skip = 0;
+ node = get_top_node_queue(nqueue);
+
+ minheight = pos[node->DFS_dist];
+
+ itA = node->child;
+ while(itA != NULL) {
+ if((itA->node->color == DAG_WHITE) ) {
+ itA->node->DFS_dvtm = time;
+ itA->node->color = DAG_GRAY;
+
+ time++;
+ itA->node->DFS_dist = node->DFS_dist + 1;
+ itA->node->k = (float) minheight;
+ push_stack(nqueue,itA->node);
+ skip = 1;
+ break;
+ } else {
+ if (itA->node->color == DAG_GRAY) { // back edge
+ fprintf(stderr,"dfs back edge :%15s %15s \n",((ID *) node->ob)->name, ((ID *) itA->node->ob)->name);
+ is_cycle = 1;
+ } else if (itA->node->color == DAG_BLACK) {
+ ;
+ /* already processed node but we may want later to change distance either to shorter to longer.
+ * DFS_dist is the first encounter
+ */
+ /*if (node->DFS_dist >= itA->node->DFS_dist)
+ itA->node->DFS_dist = node->DFS_dist + 1;
+
+ fprintf(stderr,"dfs forward or cross edge :%15s %i-%i %15s %i-%i \n",
+ ((ID *) node->ob)->name,
+ node->DFS_dvtm,
+ node->DFS_fntm,
+ ((ID *) itA->node->ob)->name,
+ itA->node->DFS_dvtm,
+ itA->node->DFS_fntm);
+ */
+ } else
+ fprintf(stderr,"dfs unknown edge \n");
+ }
+ itA = itA->next;
+ }
+
+ if (!skip) {
+ node = pop_queue(nqueue);
+ node->color = DAG_BLACK;
+
+ node->DFS_fntm = time;
+ time++;
+ if (node->DFS_dist > maxpos)
+ maxpos = node->DFS_dist;
+ if (pos[node->DFS_dist] > node->k ) {
+ pos[node->DFS_dist] += 1;
+ node->k = (float) pos[node->DFS_dist];
+ } else {
+ pos[node->DFS_dist] = (int) node->k +1;
+ }
+ set_node_xy(node, node->DFS_dist*DEPSX*2, pos[node->DFS_dist]*DEPSY*2);
+
+ /*
+ fprintf(stderr,"DFS node : %20s %i %i %i %i\n",((ID *) node->ob)->name,node->BFS_dist, node->DFS_dist, node->DFS_dvtm, node->DFS_fntm );
+ */
+ push_stack(retqueue,node);
+
+ }
+ }
+ }
+ node = node->next;
+ } while (node);
+// fprintf(stderr,"i size : %i \n", maxpos);
+
+ queue_delete(nqueue);
+ return(retqueue);
+}
+
+/* unused */
+int pre_and_post_DFS(DagForest *dag, short mask, graph_action_func pre_func, graph_action_func post_func, void **data) {
+ DagNode *node;
+
+ node = dag->DagNode.first;
+ return pre_and_post_source_DFS(dag, mask, node, pre_func, post_func, data);
+}
+
+int pre_and_post_source_DFS(DagForest *dag, short mask, DagNode *source, graph_action_func pre_func, graph_action_func post_func, void **data)
+{
+ DagNode *node;
+ DagNodeQueue *nqueue;
+ DagAdjList *itA;
+ int time;
+ int skip = 0;
+ int retval = 0;
+ /*
+ *fprintf(stderr,"starting DFS \n ------------\n");
+ */
+ nqueue = queue_create(DAGQUEUEALLOC);
+
+ /* Init
+ * dagnode.first is alway the root (scene)
+ */
+ node = dag->DagNode.first;
+ while(node) {
+ node->color = DAG_WHITE;
+ node->DFS_dist = 9999;
+ node->DFS_dvtm = node->DFS_fntm = 9999;
+ node->k = 0;
+ node = node->next;
+ }
+
+ time = 1;
+
+ node = source;
+ do {
+ if (node->color == DAG_WHITE) {
+ node->color = DAG_GRAY;
+ node->DFS_dist = 1;
+ node->DFS_dvtm = time;
+ time++;
+ push_stack(nqueue,node);
+ pre_func(node->ob,data);
+
+ while(nqueue->count) {
+ skip = 0;
+ node = get_top_node_queue(nqueue);
+
+ itA = node->child;
+ while(itA != NULL) {
+ if((itA->node->color == DAG_WHITE) && (itA->type & mask) ) {
+ itA->node->DFS_dvtm = time;
+ itA->node->color = DAG_GRAY;
+
+ time++;
+ itA->node->DFS_dist = node->DFS_dist + 1;
+ push_stack(nqueue,itA->node);
+ pre_func(node->ob,data);
+
+ skip = 1;
+ break;
+ } else {
+ if (itA->node->color == DAG_GRAY) {// back edge
+ retval = 1;
+ }
+// else if (itA->node->color == DAG_BLACK) { // cross or forward
+// ;
+ }
+ itA = itA->next;
+ }
+
+ if (!skip) {
+ node = pop_queue(nqueue);
+ node->color = DAG_BLACK;
+
+ node->DFS_fntm = time;
+ time++;
+ post_func(node->ob,data);
+ }
+ }
+ }
+ node = node->next;
+ } while (node);
+ queue_delete(nqueue);
+ return(retval);
+}
+
+
+// used to get the obs owning a datablock
+struct DagNodeQueue *get_obparents(struct DagForest *dag, void *ob)
+{
+ DagNode * node, *node1;
+ DagNodeQueue *nqueue;
+ DagAdjList *itA;
+
+ node = dag_find_node(dag,ob);
+ if(node==NULL) {
+ return NULL;
+ }
+ else if (node->ancestor_count == 1) { // simple case
+ nqueue = queue_create(1);
+ push_queue(nqueue,node);
+ } else { // need to go over the whole dag for adj list
+ nqueue = queue_create(node->ancestor_count);
+
+ node1 = dag->DagNode.first;
+ do {
+ if (node1->DFS_fntm > node->DFS_fntm) { // a parent is finished after child. must check adj list
+ itA = node->child;
+ while(itA != NULL) {
+ if ((itA->node == node) && (itA->type == DAG_RL_DATA)) {
+ push_queue(nqueue,node);
+ }
+ itA = itA->next;
+ }
+ }
+ node1 = node1->next;
+ } while (node1);
+ }
+ return nqueue;
+}
+
+struct DagNodeQueue *get_first_ancestors(struct DagForest *dag, void *ob)
+{
+ DagNode * node, *node1;
+ DagNodeQueue *nqueue;
+ DagAdjList *itA;
+
+ node = dag_find_node(dag,ob);
+
+ // need to go over the whole dag for adj list
+ nqueue = queue_create(node->ancestor_count);
+
+ node1 = dag->DagNode.first;
+ do {
+ if (node1->DFS_fntm > node->DFS_fntm) {
+ itA = node->child;
+ while(itA != NULL) {
+ if (itA->node == node) {
+ push_queue(nqueue,node);
+ }
+ itA = itA->next;
+ }
+ }
+ node1 = node1->next;
+ } while (node1);
+
+ return nqueue;
+}
+
+// standard DFS list
+struct DagNodeQueue *get_all_childs(struct DagForest *dag, void *ob)
+{
+ DagNode *node;
+ DagNodeQueue *nqueue;
+ DagNodeQueue *retqueue;
+ DagAdjList *itA;
+ int time;
+ int skip = 0;
+
+ nqueue = queue_create(DAGQUEUEALLOC);
+ retqueue = queue_create(dag->numNodes); // was MainDag... why? (ton)
+
+ node = dag->DagNode.first;
+ while(node) {
+ node->color = DAG_WHITE;
+ node = node->next;
+ }
+
+ time = 1;
+
+ node = dag_find_node(dag, ob); // could be done in loop above (ton)
+ if(node) { // can be null for newly added objects
+
+ node->color = DAG_GRAY;
+ time++;
+ push_stack(nqueue,node);
+
+ while(nqueue->count) {
+
+ skip = 0;
+ node = get_top_node_queue(nqueue);
+
+ itA = node->child;
+ while(itA != NULL) {
+ if((itA->node->color == DAG_WHITE) ) {
+ itA->node->DFS_dvtm = time;
+ itA->node->color = DAG_GRAY;
+
+ time++;
+ push_stack(nqueue,itA->node);
+ skip = 1;
+ break;
+ }
+ itA = itA->next;
+ }
+
+ if (!skip) {
+ node = pop_queue(nqueue);
+ node->color = DAG_BLACK;
+
+ time++;
+ push_stack(retqueue,node);
+ }
+ }
+ }
+ queue_delete(nqueue);
+ return(retqueue);
+}
+
+/* unused */
+short are_obs_related(struct DagForest *dag, void *ob1, void *ob2) {
+ DagNode * node;
+ DagAdjList *itA;
+
+ node = dag_find_node(dag, ob1);
+
+ itA = node->child;
+ while(itA != NULL) {
+ if((itA->node->ob == ob2) ) {
+ return itA->node->type;
+ }
+ itA = itA->next;
+ }
+ return DAG_NO_RELATION;
+}
+
+int is_acyclic( DagForest *dag) {
+ return dag->is_acyclic;
+}
+
+void set_node_xy(DagNode *node, float x, float y)
+{
+ node->x = x;
+ node->y = y;
+}
+
+
+/* debug test functions */
+
+void graph_print_queue(DagNodeQueue *nqueue)
+{
+ DagNodeQueueElem *queueElem;
+
+ queueElem = nqueue->first;
+ while(queueElem) {
+ fprintf(stderr,"** %s %i %i-%i ",((ID *) queueElem->node->ob)->name,queueElem->node->color,queueElem->node->DFS_dvtm,queueElem->node->DFS_fntm);
+ queueElem = queueElem->next;
+ }
+ fprintf(stderr,"\n");
+}
+
+void graph_print_queue_dist(DagNodeQueue *nqueue)
+{
+ DagNodeQueueElem *queueElem;
+ int max, count;
+
+ queueElem = nqueue->first;
+ max = queueElem->node->DFS_fntm;
+ count = 0;
+ while(queueElem) {
+ fprintf(stderr,"** %25s %2.2i-%2.2i ",((ID *) queueElem->node->ob)->name,queueElem->node->DFS_dvtm,queueElem->node->DFS_fntm);
+ while (count < queueElem->node->DFS_dvtm-1) { fputc(' ',stderr); count++;}
+ fputc('|',stderr);
+ while (count < queueElem->node->DFS_fntm-2) { fputc('-',stderr); count++;}
+ fputc('|',stderr);
+ fputc('\n',stderr);
+ count = 0;
+ queueElem = queueElem->next;
+ }
+ fprintf(stderr,"\n");
+}
+
+void graph_print_adj_list(void)
+{
+ DagNode *node;
+ DagAdjList *itA;
+
+ node = (getMainDag())->DagNode.first;
+ while(node) {
+ fprintf(stderr,"node : %s col: %i",((ID *) node->ob)->name, node->color);
+ itA = node->child;
+ while (itA) {
+ fprintf(stderr,"-- %s ",((ID *) itA->node->ob)->name);
+
+ itA = itA->next;
+ }
+ fprintf(stderr,"\n");
+ node = node->next;
+ }
+}
+
+/* ************************ API *********************** */
+
+/* groups with objects in this scene need to be put in the right order as well */
+static void scene_sort_groups(Scene *sce)
+{
+ Base *base;
+ Group *group;
+ GroupObject *go;
+ Object *ob;
+
+ /* test; are group objects all in this scene? */
+ for(ob= G.main->object.first; ob; ob= ob->id.next) {
+ ob->id.flag &= ~LIB_DOIT;
+ ob->id.newid= NULL; /* newid abuse for GroupObject */
+ }
+ for(base = sce->base.first; base; base= base->next)
+ base->object->id.flag |= LIB_DOIT;
+
+ for(group= G.main->group.first; group; group= group->id.next) {
+ for(go= group->gobject.first; go; go= go->next) {
+ if((go->ob->id.flag & LIB_DOIT)==0)
+ break;
+ }
+ /* this group is entirely in this scene */
+ if(go==NULL) {
+ ListBase listb= {NULL, NULL};
+
+ for(go= group->gobject.first; go; go= go->next)
+ go->ob->id.newid= (ID *)go;
+
+ /* in order of sorted bases we reinsert group objects */
+ for(base = sce->base.first; base; base= base->next) {
+
+ if(base->object->id.newid) {
+ go= (GroupObject *)base->object->id.newid;
+ base->object->id.newid= NULL;
+ BLI_remlink( &group->gobject, go);
+ BLI_addtail( &listb, go);
+ }
+ }
+ /* copy the newly sorted listbase */
+ group->gobject= listb;
+ }
+ }
+}
+
+/* sort the base list on dependency order */
+void DAG_scene_sort(struct Scene *sce)
+{
+ DagNode *node;
+ DagNodeQueue *nqueue;
+ DagAdjList *itA;
+ int time;
+ int skip = 0;
+ ListBase tempbase;
+ Base *base;
+
+ tempbase.first= tempbase.last= NULL;
+
+ build_dag(sce, DAG_RL_ALL_BUT_DATA);
+
+ nqueue = queue_create(DAGQUEUEALLOC);
+
+ for(node = sce->theDag->DagNode.first; node; node= node->next) {
+ node->color = DAG_WHITE;
+ }
+
+ time = 1;
+
+ node = sce->theDag->DagNode.first;
+
+ node->color = DAG_GRAY;
+ time++;
+ push_stack(nqueue,node);
+
+ while(nqueue->count) {
+
+ skip = 0;
+ node = get_top_node_queue(nqueue);
+
+ itA = node->child;
+ while(itA != NULL) {
+ if((itA->node->color == DAG_WHITE) ) {
+ itA->node->DFS_dvtm = time;
+ itA->node->color = DAG_GRAY;
+
+ time++;
+ push_stack(nqueue,itA->node);
+ skip = 1;
+ break;
+ }
+ itA = itA->next;
+ }
+
+ if (!skip) {
+ if (node) {
+ node = pop_queue(nqueue);
+ if (node->ob == sce) // we are done
+ break ;
+ node->color = DAG_BLACK;
+
+ time++;
+ base = sce->base.first;
+ while (base && base->object != node->ob)
+ base = base->next;
+ if(base) {
+ BLI_remlink(&sce->base,base);
+ BLI_addhead(&tempbase,base);
+ }
+ }
+ }
+ }
+
+ // temporal correction for circular dependancies
+ base = sce->base.first;
+ while (base) {
+ BLI_remlink(&sce->base,base);
+ BLI_addhead(&tempbase,base);
+ //if(G.f & G_DEBUG)
+ printf("cyclic %s\n", base->object->id.name);
+ base = sce->base.first;
+ }
+
+ sce->base = tempbase;
+ queue_delete(nqueue);
+
+ /* all groups with objects in this scene gets resorted too */
+ scene_sort_groups(sce);
+
+ if(G.f & G_DEBUG) {
+ printf("\nordered\n");
+ for(base = sce->base.first; base; base= base->next) {
+ printf(" %s\n", base->object->id.name);
+ }
+ }
+ /* temporal...? */
+ sce->recalc |= SCE_PRV_CHANGED; /* test for 3d preview */
+}
+
+/* node was checked to have lasttime != curtime and is if type ID_OB */
+static void flush_update_node(DagNode *node, unsigned int layer, int curtime)
+{
+ DagAdjList *itA;
+ Object *ob, *obc;
+ int oldflag, changed=0;
+ unsigned int all_layer;
+
+ node->lasttime= curtime;
+
+ ob= node->ob;
+ if(ob && (ob->recalc & OB_RECALC)) {
+ all_layer= ob->lay;
+ /* got an object node that changes, now check relations */
+ for(itA = node->child; itA; itA= itA->next) {
+ all_layer |= itA->lay;
+ /* the relationship is visible */
+ if(itA->lay & layer) {
+ if(itA->node->type==ID_OB) {
+ obc= itA->node->ob;
+ oldflag= obc->recalc;
+
+ /* got a ob->obc relation, now check if flag needs flush */
+ if(ob->recalc & OB_RECALC_OB) {
+ if(itA->type & DAG_RL_OB_OB) {
+ //printf("ob %s changes ob %s\n", ob->id.name, obc->id.name);
+ obc->recalc |= OB_RECALC_OB;
+ }
+ if(itA->type & DAG_RL_OB_DATA) {
+ //printf("ob %s changes obdata %s\n", ob->id.name, obc->id.name);
+ obc->recalc |= OB_RECALC_DATA;
+ }
+ }
+ if(ob->recalc & OB_RECALC_DATA) {
+ if(itA->type & DAG_RL_DATA_OB) {
+ //printf("obdata %s changes ob %s\n", ob->id.name, obc->id.name);
+ obc->recalc |= OB_RECALC_OB;
+ }
+ if(itA->type & DAG_RL_DATA_DATA) {
+ //printf("obdata %s changes obdata %s\n", ob->id.name, obc->id.name);
+ obc->recalc |= OB_RECALC_DATA;
+ }
+ }
+ if(oldflag!=obc->recalc) changed= 1;
+ }
+ }
+ }
+ /* even nicer, we can clear recalc flags... */
+ if((all_layer & layer)==0) {
+ /* but existing displaylists or derivedmesh should be freed */
+ if(ob->recalc & OB_RECALC_DATA)
+ object_free_display(ob);
+
+ ob->recalc &= ~OB_RECALC;
+ }
+ }
+
+ /* check case where child changes and parent forcing obdata to change */
+ /* should be done regardless if this ob has recalc set */
+ /* could merge this in with loop above...? (ton) */
+ for(itA = node->child; itA; itA= itA->next) {
+ /* the relationship is visible */
+ if(itA->lay & layer) {
+ if(itA->node->type==ID_OB) {
+ obc= itA->node->ob;
+ /* child moves */
+ if((obc->recalc & OB_RECALC)==OB_RECALC_OB) {
+ /* parent has deforming info */
+ if(itA->type & (DAG_RL_OB_DATA|DAG_RL_DATA_DATA)) {
+ // printf("parent %s changes ob %s\n", ob->id.name, obc->id.name);
+ obc->recalc |= OB_RECALC_DATA;
+ }
+ }
+ }
+ }
+ }
+
+ /* we only go deeper if node not checked or something changed */
+ for(itA = node->child; itA; itA= itA->next) {
+ if(changed || itA->node->lasttime!=curtime)
+ flush_update_node(itA->node, layer, curtime);
+ }
+
+}
+
+/* node was checked to have lasttime != curtime , and is of type ID_OB */
+static unsigned int flush_layer_node(DagNode *node, int curtime)
+{
+ DagAdjList *itA;
+
+ node->lasttime= curtime;
+ node->lay= ((Object *)node->ob)->lay;
+
+ for(itA = node->child; itA; itA= itA->next) {
+ if(itA->node->type==ID_OB) {
+ if(itA->node->lasttime!=curtime) {
+ itA->lay= flush_layer_node(itA->node, curtime); // lay is only set once for each relation
+ //printf("layer %d for relation %s to %s\n", itA->lay, ((Object *)node->ob)->id.name, ((Object *)itA->node->ob)->id.name);
+ }
+ else itA->lay= itA->node->lay;
+
+ node->lay |= itA->lay;
+ }
+ }
+
+ return node->lay;
+}
+
+/* flushes all recalc flags in objects down the dependency tree */
+void DAG_scene_flush_update(Scene *sce, unsigned int lay)
+{
+ DagNode *firstnode;
+ DagAdjList *itA;
+ int lasttime;
+
+ if(sce->theDag==NULL) {
+ printf("DAG zero... not allowed to happen!\n");
+ DAG_scene_sort(sce);
+ }
+
+ firstnode= sce->theDag->DagNode.first; // always scene node
+
+ /* first we flush the layer flags */
+ sce->theDag->time++; // so we know which nodes were accessed
+ lasttime= sce->theDag->time;
+ for(itA = firstnode->child; itA; itA= itA->next) {
+ if(itA->node->lasttime!=lasttime && itA->node->type==ID_OB)
+ flush_layer_node(itA->node, lasttime);
+ }
+
+ /* then we use the relationships + layer info to flush update events */
+ sce->theDag->time++; // so we know which nodes were accessed
+ lasttime= sce->theDag->time;
+ for(itA = firstnode->child; itA; itA= itA->next) {
+ if(itA->node->lasttime!=lasttime && itA->node->type==ID_OB)
+ flush_update_node(itA->node, lay, lasttime);
+ }
+}
+
+static int object_modifiers_use_time(Object *ob)
+{
+ ModifierData *md;
+
+ for (md=ob->modifiers.first; md; md=md->next)
+ if (modifier_dependsOnTime(md))
+ return 1;
+
+ return 0;
+}
+
+static int exists_channel(Object *ob, char *name)
+{
+ bActionStrip *strip;
+
+ if(ob->action)
+ if(get_action_channel(ob->action, name))
+ return 1;
+
+ for (strip=ob->nlastrips.first; strip; strip=strip->next)
+ if(get_action_channel(strip->act, name))
+ return 1;
+ return 0;
+}
+
+static void dag_object_time_update_flags(Object *ob)
+{
+
+ if(ob->ipo) ob->recalc |= OB_RECALC_OB;
+ else if(ob->constraints.first) {
+ bConstraint *con;
+ for (con = ob->constraints.first; con; con=con->next) {
+ bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+
+ if (cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(con, &targets);
+
+ for (ct= targets.first; ct; ct= ct->next) {
+ if (ct->tar) {
+ ob->recalc |= OB_RECALC_OB;
+ break;
+ }
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(con, &targets, 1);
+ }
+ }
+ }
+ else if(ob->scriptlink.totscript) ob->recalc |= OB_RECALC_OB;
+ else if(ob->parent) {
+ /* motion path or bone child */
+ if(ob->parent->type==OB_CURVE || ob->parent->type==OB_ARMATURE) ob->recalc |= OB_RECALC_OB;
+ }
+
+ if(ob->action || ob->nlastrips.first) {
+ /* since actions now are mixed, we set the recalcs on the safe side */
+ ob->recalc |= OB_RECALC_OB;
+ if(ob->type==OB_ARMATURE)
+ ob->recalc |= OB_RECALC_DATA;
+ else if(exists_channel(ob, "Shape"))
+ ob->recalc |= OB_RECALC_DATA;
+ else if(ob->dup_group) {
+ bActionStrip *strip;
+ /* this case is for groups with nla, whilst nla target has no action or nla */
+ for(strip= ob->nlastrips.first; strip; strip= strip->next) {
+ if(strip->object)
+ strip->object->recalc |= OB_RECALC;
+ }
+ }
+ }
+ else if(modifiers_isSoftbodyEnabled(ob)) ob->recalc |= OB_RECALC_DATA;
+ else if(object_modifiers_use_time(ob)) ob->recalc |= OB_RECALC_DATA;
+ else {
+ Mesh *me;
+ Curve *cu;
+ Lattice *lt;
+
+ switch(ob->type) {
+ case OB_MESH:
+ me= ob->data;
+ if(me->key) {
+ if(!(ob->shapeflag & OB_SHAPE_LOCK)) {
+ ob->recalc |= OB_RECALC_DATA;
+ ob->shapeflag &= ~OB_SHAPE_TEMPLOCK;
+ }
+ }
+ else if(ob->effect.first) {
+ Effect *eff= ob->effect.first;
+ PartEff *paf= give_parteff(ob);
+
+ if(eff->type==EFF_WAVE)
+ ob->recalc |= OB_RECALC_DATA;
+ else if(paf && paf->keys==NULL)
+ ob->recalc |= OB_RECALC_DATA;
+ }
+ if((ob->fluidsimFlag & OB_FLUIDSIM_ENABLE) && (ob->fluidsimSettings)) {
+ // fluidsimSettings might not be initialized during load...
+ if(ob->fluidsimSettings->type & (OB_FLUIDSIM_DOMAIN|OB_FLUIDSIM_PARTICLE)) {
+ ob->recalc |= OB_RECALC_DATA; // NT FSPARTICLE
+ }
+ }
+ break;
+ case OB_CURVE:
+ case OB_SURF:
+ cu= ob->data;
+ if(cu->key) {
+ if(!(ob->shapeflag & OB_SHAPE_LOCK)) {
+ ob->recalc |= OB_RECALC_DATA;
+ ob->shapeflag &= ~OB_SHAPE_TEMPLOCK;
+ }
+ }
+ break;
+ case OB_FONT:
+ cu= ob->data;
+ if(cu->nurb.first==NULL && cu->str && cu->vfont)
+ ob->recalc |= OB_RECALC_DATA;
+ break;
+ case OB_LATTICE:
+ lt= ob->data;
+ if(lt->key) {
+ if(!(ob->shapeflag & OB_SHAPE_LOCK)) {
+ ob->recalc |= OB_RECALC_DATA;
+ ob->shapeflag &= ~OB_SHAPE_TEMPLOCK;
+ }
+ }
+ break;
+ case OB_MBALL:
+ if(ob->transflag & OB_DUPLI) ob->recalc |= OB_RECALC_DATA;
+ break;
+ }
+ }
+}
+
+/* flag all objects that need recalc, for changes in time for example */
+void DAG_scene_update_flags(Scene *scene, unsigned int lay)
+{
+ Base *base;
+ Object *ob;
+ Group *group;
+ GroupObject *go;
+ Scene *sce;
+
+ /* set ob flags where animated systems are */
+ for(SETLOOPER(scene, base)) {
+ ob= base->object;
+
+ /* now if DagNode were part of base, the node->lay could be checked... */
+ /* we do all now, since the scene_flush checks layers and clears recalc flags even */
+ dag_object_time_update_flags(ob);
+
+ /* handled in next loop */
+ if(ob->dup_group)
+ ob->dup_group->id.flag |= LIB_DOIT;
+ }
+
+ /* we do groups each once */
+ for(group= G.main->group.first; group; group= group->id.next) {
+ if(group->id.flag & LIB_DOIT) {
+ for(go= group->gobject.first; go; go= go->next) {
+ dag_object_time_update_flags(go->ob);
+ }
+ }
+ }
+
+ for(sce= scene; sce; sce= sce->set)
+ DAG_scene_flush_update(sce, lay);
+
+ /* test: set time flag, to disable baked systems to update */
+ for(SETLOOPER(scene, base)) {
+ ob= base->object;
+ if(ob->recalc)
+ ob->recalc |= OB_RECALC_TIME;
+ }
+
+ /* hrmf... an exception to look at once, for invisible camera object we do it over */
+ if(scene->camera)
+ dag_object_time_update_flags(scene->camera);
+
+ /* and store the info in groupobject */
+ for(group= G.main->group.first; group; group= group->id.next) {
+ if(group->id.flag & LIB_DOIT) {
+ for(go= group->gobject.first; go; go= go->next) {
+ go->recalc= go->ob->recalc;
+ // printf("ob %s recalc %d\n", go->ob->id.name, go->recalc);
+ }
+ group->id.flag &= ~LIB_DOIT;
+ }
+ }
+
+}
+
+/* for depgraph updating, all layers visible in a screen */
+/* this is a copy from editscreen.c... I need to think over a more proper solution for this */
+/* probably the DAG_object_flush_update() should give layer too? */
+/* or some kind of dag context... (DAG_set_layer) */
+static unsigned int dag_screen_view3d_layers(void)
+{
+ ScrArea *sa;
+ int layer= 0;
+
+ for(sa= G.curscreen->areabase.first; sa; sa= sa->next) {
+ if(sa->spacetype==SPACE_VIEW3D)
+ layer |= ((View3D *)sa->spacedata.first)->lay;
+ }
+ return layer;
+}
+
+
+/* flag this object and all its relations to recalc */
+/* if you need to do more objects, tag object yourself and
+ use DAG_scene_flush_update() in end */
+void DAG_object_flush_update(Scene *sce, Object *ob, short flag)
+{
+
+ if(ob==NULL || sce->theDag==NULL) return;
+ ob->recalc |= flag;
+
+ /* all users of this ob->data should be checked */
+ /* BUT! displists for curves are still only on cu */
+ if(flag & OB_RECALC_DATA) {
+ if(ob->type!=OB_CURVE && ob->type!=OB_SURF) {
+ ID *id= ob->data;
+ if(id && id->us>1) {
+ /* except when there's a key and shapes are locked */
+ if(ob_get_key(ob) && (ob->shapeflag & (OB_SHAPE_LOCK|OB_SHAPE_TEMPLOCK)));
+ else {
+ Object *obt;
+ for (obt=G.main->object.first; obt; obt= obt->id.next) {
+ if (obt->data==ob->data) {
+ obt->recalc |= OB_RECALC_DATA;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if(G.curscreen)
+ DAG_scene_flush_update(sce, dag_screen_view3d_layers());
+ else
+ DAG_scene_flush_update(sce, sce->lay);
+}
+
+/* recursively descends tree, each node only checked once */
+/* node is checked to be of type object */
+static int parent_check_node(DagNode *node, int curtime)
+{
+ DagAdjList *itA;
+
+ node->lasttime= curtime;
+
+ if(node->color==DAG_GRAY)
+ return DAG_GRAY;
+
+ for(itA = node->child; itA; itA= itA->next) {
+ if(itA->node->type==ID_OB) {
+
+ if(itA->node->color==DAG_GRAY)
+ return DAG_GRAY;
+
+ /* descend if not done */
+ if(itA->node->lasttime!=curtime) {
+ itA->node->color= parent_check_node(itA->node, curtime);
+
+ if(itA->node->color==DAG_GRAY)
+ return DAG_GRAY;
+ }
+ }
+ }
+
+ return DAG_WHITE;
+}
+
+/* all nodes that influence this object get tagged, for calculating the exact
+ position of this object at a given timeframe */
+void DAG_object_update_flags(Scene *sce, Object *ob, unsigned int lay)
+{
+ DagNode *node;
+ DagAdjList *itA;
+
+ /* tag nodes unchecked */
+ for(node = sce->theDag->DagNode.first; node; node= node->next)
+ node->color = DAG_WHITE;
+
+ node= dag_find_node(sce->theDag, ob);
+
+ /* object not in scene? then handle group exception. needs to be dagged once too */
+ if(node==NULL) {
+ Group *group= find_group(ob);
+ if(group) {
+ GroupObject *go;
+ /* primitive; tag all... this call helps building groups for particles */
+ for(go= group->gobject.first; go; go= go->next)
+ go->ob->recalc= OB_RECALC;
+ }
+ }
+ else {
+
+ node->color = DAG_GRAY;
+
+ sce->theDag->time++;
+ node= sce->theDag->DagNode.first;
+ for(itA = node->child; itA; itA= itA->next) {
+ if(itA->node->type==ID_OB && itA->node->lasttime!=sce->theDag->time)
+ itA->node->color= parent_check_node(itA->node, sce->theDag->time);
+ }
+
+ /* set recalcs and flushes */
+ DAG_scene_update_flags(sce, lay);
+
+ /* now we clear recalcs, unless color is set */
+ for(node = sce->theDag->DagNode.first; node; node= node->next) {
+ if(node->type==ID_OB && node->color==DAG_WHITE) {
+ Object *ob= node->ob;
+ ob->recalc= 0;
+ }
+ }
+ }
+}
+
+/* ******************* DAG FOR ARMATURE POSE ***************** */
+
+static int node_recurs_level(DagNode *node, int level)
+{
+ DagAdjList *itA;
+
+ node->color= DAG_BLACK; /* done */
+ level++;
+
+ for(itA= node->parent; itA; itA= itA->next) {
+ if(itA->node->color==DAG_WHITE)
+ itA->node->ancestor_count= node_recurs_level(itA->node, level);
+ }
+
+ return level;
+}
+
+static void pose_check_cycle(DagForest *dag)
+{
+ DagNode *node;
+ DagAdjList *itA;
+
+ /* tag nodes unchecked */
+ for(node = dag->DagNode.first; node; node= node->next)
+ node->color= DAG_WHITE;
+
+ for(node = dag->DagNode.first; node; node= node->next) {
+ if(node->color==DAG_WHITE) {
+ node->ancestor_count= node_recurs_level(node, 0);
+ }
+ }
+
+ /* check relations, and print errors */
+ for(node = dag->DagNode.first; node; node= node->next) {
+ for(itA= node->parent; itA; itA= itA->next) {
+ if(itA->node->ancestor_count > node->ancestor_count) {
+ bPoseChannel *pchan= (bPoseChannel *)node->ob;
+ bPoseChannel *parchan= (bPoseChannel *)itA->node->ob;
+
+ if(pchan && parchan)
+ if(pchan->parent!=parchan)
+ printf("Cycle in %s to %s\n", pchan->name, parchan->name);
+ }
+ }
+ }
+}
+
+/* we assume its an armature with pose */
+void DAG_pose_sort(Object *ob)
+{
+ bPose *pose= ob->pose;
+ bPoseChannel *pchan;
+ bConstraint *con;
+ DagNode *node;
+ DagNode *node2, *node3;
+ DagNode *rootnode;
+ DagForest *dag;
+ DagNodeQueue *nqueue;
+ DagAdjList *itA;
+ ListBase tempbase;
+ int skip = 0;
+
+ dag = dag_init();
+ ugly_hack_sorry= 0; // no ID structs
+
+ rootnode = dag_add_node(dag, NULL); // node->ob becomes NULL
+
+ /* we add the hierarchy and the constraints */
+ for(pchan = pose->chanbase.first; pchan; pchan= pchan->next) {
+ int addtoroot = 1;
+
+ node = dag_get_node(dag, pchan);
+
+ if(pchan->parent) {
+ node2 = dag_get_node(dag, pchan->parent);
+ dag_add_relation(dag, node2, node, 0);
+ dag_add_parent_relation(dag, node2, node, 0);
+ addtoroot = 0;
+ }
+ for (con = pchan->constraints.first; con; con=con->next) {
+ bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+
+ if (cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(con, &targets);
+
+ for (ct= targets.first; ct; ct= ct->next) {
+ if (ct->tar==ob && ct->subtarget[0]) {
+ bPoseChannel *target= get_pose_channel(ob->pose, ct->subtarget);
+ if (target) {
+ node2= dag_get_node(dag, target);
+ dag_add_relation(dag, node2, node, 0);
+ dag_add_parent_relation(dag, node2, node, 0);
+
+ if (con->type==CONSTRAINT_TYPE_KINEMATIC) {
+ bKinematicConstraint *data = (bKinematicConstraint *)con->data;
+ bPoseChannel *parchan;
+ int segcount= 0;
+
+ /* exclude tip from chain? */
+ if(!(data->flag & CONSTRAINT_IK_TIP))
+ parchan= pchan->parent;
+ else
+ parchan= pchan;
+
+ /* Walk to the chain's root */
+ while (parchan) {
+ node3= dag_get_node(dag, parchan);
+ dag_add_relation(dag, node2, node3, 0);
+ dag_add_parent_relation(dag, node2, node3, 0);
+
+ segcount++;
+ if (segcount==data->rootbone || segcount>255) break; // 255 is weak
+ parchan= parchan->parent;
+ }
+ }
+ }
+ }
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(con, &targets, 1);
+ }
+ }
+ if (addtoroot == 1 ) {
+ dag_add_relation(dag, rootnode, node, 0);
+ dag_add_parent_relation(dag, rootnode, node, 0);
+ }
+ }
+
+ pose_check_cycle(dag);
+
+ /* now we try to sort... */
+ tempbase.first= tempbase.last= NULL;
+
+ nqueue = queue_create(DAGQUEUEALLOC);
+
+ /* tag nodes unchecked */
+ for(node = dag->DagNode.first; node; node= node->next)
+ node->color = DAG_WHITE;
+
+ node = dag->DagNode.first;
+
+ node->color = DAG_GRAY;
+ push_stack(nqueue, node);
+
+ while(nqueue->count) {
+
+ skip = 0;
+ node = get_top_node_queue(nqueue);
+
+ itA = node->child;
+ while(itA != NULL) {
+ if((itA->node->color == DAG_WHITE) ) {
+ itA->node->color = DAG_GRAY;
+ push_stack(nqueue,itA->node);
+ skip = 1;
+ break;
+ }
+ itA = itA->next;
+ }
+
+ if (!skip) {
+ if (node) {
+ node = pop_queue(nqueue);
+ if (node->ob == NULL) // we are done
+ break ;
+ node->color = DAG_BLACK;
+
+ /* put node in new list */
+ BLI_remlink(&pose->chanbase, node->ob);
+ BLI_addhead(&tempbase, node->ob);
+ }
+ }
+ }
+
+ // temporal correction for circular dependancies
+ while(pose->chanbase.first) {
+ pchan= pose->chanbase.first;
+ BLI_remlink(&pose->chanbase, pchan);
+ BLI_addhead(&tempbase, pchan);
+
+ printf("cyclic %s\n", pchan->name);
+ }
+
+ pose->chanbase = tempbase;
+ queue_delete(nqueue);
+
+// printf("\nordered\n");
+// for(pchan = pose->chanbase.first; pchan; pchan= pchan->next) {
+// printf(" %s\n", pchan->name);
+// }
+
+ free_forest( dag );
+ MEM_freeN( dag );
+
+ ugly_hack_sorry= 1;
+}
+
+
+
diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c
new file mode 100644
index 00000000000..30a4c8c3433
--- /dev/null
+++ b/source/blender/blenkernel/intern/displist.c
@@ -0,0 +1,1589 @@
+/* displist.c
+ *
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "IMB_imbuf_types.h"
+
+#include "DNA_texture_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_effect_types.h"
+#include "DNA_listBase.h"
+#include "DNA_lamp_types.h"
+#include "DNA_object_types.h"
+#include "DNA_object_force.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_image_types.h"
+#include "DNA_material_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_key_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_editVert.h"
+#include "BLI_edgehash.h"
+
+#include "BKE_bad_level_calls.h"
+#include "BKE_utildefines.h"
+#include "BKE_global.h"
+#include "BKE_displist.h"
+#include "BKE_deform.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_object.h"
+#include "BKE_world.h"
+#include "BKE_mesh.h"
+#include "BKE_effect.h"
+#include "BKE_mball.h"
+#include "BKE_material.h"
+#include "BKE_curve.h"
+#include "BKE_key.h"
+#include "BKE_anim.h"
+#include "BKE_screen.h"
+#include "BKE_texture.h"
+#include "BKE_library.h"
+#include "BKE_font.h"
+#include "BKE_lattice.h"
+#include "BKE_scene.h"
+#include "BKE_subsurf.h"
+#include "BKE_modifier.h"
+#include "BKE_customdata.h"
+
+#include "RE_pipeline.h"
+#include "RE_shader_ext.h"
+
+
+static void boundbox_displist(Object *ob);
+
+void free_disp_elem(DispList *dl)
+{
+ if(dl) {
+ if(dl->verts) MEM_freeN(dl->verts);
+ if(dl->nors) MEM_freeN(dl->nors);
+ if(dl->index) MEM_freeN(dl->index);
+ if(dl->col1) MEM_freeN(dl->col1);
+ if(dl->col2) MEM_freeN(dl->col2);
+ if(dl->bevelSplitFlag) MEM_freeN(dl->bevelSplitFlag);
+ MEM_freeN(dl);
+ }
+}
+
+void freedisplist(ListBase *lb)
+{
+ DispList *dl;
+
+ dl= lb->first;
+ while(dl) {
+ BLI_remlink(lb, dl);
+ free_disp_elem(dl);
+ dl= lb->first;
+ }
+}
+
+DispList *find_displist_create(ListBase *lb, int type)
+{
+ DispList *dl;
+
+ dl= lb->first;
+ while(dl) {
+ if(dl->type==type) return dl;
+ dl= dl->next;
+ }
+
+ dl= MEM_callocN(sizeof(DispList), "find_disp");
+ dl->type= type;
+ BLI_addtail(lb, dl);
+
+ return dl;
+}
+
+DispList *find_displist(ListBase *lb, int type)
+{
+ DispList *dl;
+
+ dl= lb->first;
+ while(dl) {
+ if(dl->type==type) return dl;
+ dl= dl->next;
+ }
+
+ return 0;
+}
+
+int displist_has_faces(ListBase *lb)
+{
+ DispList *dl;
+
+ dl= lb->first;
+ while(dl) {
+ if ELEM3(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)
+ return 1;
+ dl= dl->next;
+ }
+ return 0;
+}
+
+void copy_displist(ListBase *lbn, ListBase *lb)
+{
+ DispList *dln, *dl;
+
+ lbn->first= lbn->last= 0;
+
+ dl= lb->first;
+ while(dl) {
+
+ dln= MEM_dupallocN(dl);
+ BLI_addtail(lbn, dln);
+ dln->verts= MEM_dupallocN(dl->verts);
+ dln->nors= MEM_dupallocN(dl->nors);
+ dln->index= MEM_dupallocN(dl->index);
+ dln->col1= MEM_dupallocN(dl->col1);
+ dln->col2= MEM_dupallocN(dl->col2);
+
+ dl= dl->next;
+ }
+}
+
+void addnormalsDispList(Object *ob, ListBase *lb)
+{
+ DispList *dl = NULL;
+ float *vdata, *ndata, nor[3];
+ float *v1, *v2, *v3, *v4;
+ float *n1, *n2, *n3, *n4;
+ int a, b, p1, p2, p3, p4;
+
+
+ dl= lb->first;
+
+ while(dl) {
+ if(dl->type==DL_INDEX3) {
+ if(dl->nors==NULL) {
+ dl->nors= MEM_callocN(sizeof(float)*3, "dlnors");
+ if(dl->verts[2]<0.0) dl->nors[2]= -1.0;
+ else dl->nors[2]= 1.0;
+ }
+ }
+ else if(dl->type==DL_SURF) {
+ if(dl->nors==NULL) {
+ dl->nors= MEM_callocN(sizeof(float)*3*dl->nr*dl->parts, "dlnors");
+
+ vdata= dl->verts;
+ ndata= dl->nors;
+
+ for(a=0; a<dl->parts; a++) {
+
+ DL_SURFINDEX(dl->flag & DL_CYCL_U, dl->flag & DL_CYCL_V, dl->nr, dl->parts);
+
+ v1= vdata+ 3*p1;
+ n1= ndata+ 3*p1;
+ v2= vdata+ 3*p2;
+ n2= ndata+ 3*p2;
+ v3= vdata+ 3*p3;
+ n3= ndata+ 3*p3;
+ v4= vdata+ 3*p4;
+ n4= ndata+ 3*p4;
+
+ for(; b<dl->nr; b++) {
+
+ CalcNormFloat4(v1, v3, v4, v2, nor);
+
+ VecAddf(n1, n1, nor);
+ VecAddf(n2, n2, nor);
+ VecAddf(n3, n3, nor);
+ VecAddf(n4, n4, nor);
+
+ v2= v1; v1+= 3;
+ v4= v3; v3+= 3;
+ n2= n1; n1+= 3;
+ n4= n3; n3+= 3;
+ }
+ }
+ a= dl->parts*dl->nr;
+ v1= ndata;
+ while(a--) {
+ Normalize(v1);
+ v1+= 3;
+ }
+ }
+ }
+ dl= dl->next;
+ }
+}
+
+void count_displist(ListBase *lb, int *totvert, int *totface)
+{
+ DispList *dl;
+
+ dl= lb->first;
+ while(dl) {
+
+ switch(dl->type) {
+ case DL_SURF:
+ *totvert+= dl->nr*dl->parts;
+ *totface+= (dl->nr-1)*(dl->parts-1);
+ break;
+ case DL_INDEX3:
+ case DL_INDEX4:
+ *totvert+= dl->nr;
+ *totface+= dl->parts;
+ break;
+ case DL_POLY:
+ case DL_SEGM:
+ *totvert+= dl->nr*dl->parts;
+ }
+
+ dl= dl->next;
+ }
+}
+
+
+/* ***************************** shade displist. note colors now are in rgb(a) order ******************** */
+
+/* create default shade input... save cpu cycles with ugly global */
+/* XXXX bad code warning: local ShadeInput initialize... */
+static ShadeInput shi;
+static void init_fastshade_shadeinput(void)
+{
+ memset(&shi, 0, sizeof(ShadeInput));
+ shi.lay= G.scene->lay;
+ shi.view[2]= -1.0f;
+ shi.passflag= SCE_PASS_COMBINED;
+ shi.combinedflag= -1;
+}
+
+static Render *fastshade_get_render(void)
+{
+ Render *re= RE_GetRender("_Shade View_");
+ if(re==NULL) {
+ re= RE_NewRender("_Shade View_");
+
+ RE_Database_Baking(re, G.scene, 0); /* 0= no faces */
+ }
+ return re;
+}
+
+/* called on file reading */
+void fastshade_free_render(void)
+{
+ Render *re= RE_GetRender("_Shade View_");
+
+ if(re) {
+ RE_Database_Free(re);
+ RE_FreeRender(re);
+ }
+}
+
+static int fastshade_customdata_layer_num(int n, int active)
+{
+ /* make the active layer the first */
+ if (n == active) return 0;
+ else if (n < active) return n+1;
+ else return n;
+}
+
+static void fastshade_customdata(CustomData *fdata, int a, int j, Material *ma)
+{
+ CustomDataLayer *layer;
+ MTFace *mtface;
+ int index, n, needuv= ma->texco & TEXCO_UV;
+ char *vertcol;
+
+ shi.totuv= 0;
+ shi.totcol= 0;
+
+ for(index=0; index<fdata->totlayer; index++) {
+ layer= &fdata->layers[index];
+
+ if(needuv && layer->type == CD_MTFACE && shi.totuv < MAX_MTFACE) {
+ n= fastshade_customdata_layer_num(shi.totuv, layer->active_rnd);
+ mtface= &((MTFace*)layer->data)[a];
+
+ shi.uv[shi.totuv].uv[0]= 2.0f*mtface->uv[j][0]-1.0f;
+ shi.uv[shi.totuv].uv[1]= 2.0f*mtface->uv[j][1]-1.0f;
+ shi.uv[shi.totuv].uv[2]= 1.0f;
+
+ shi.uv[shi.totuv].name= layer->name;
+ shi.totuv++;
+ }
+ else if(layer->type == CD_MCOL && shi.totcol < MAX_MCOL) {
+ n= fastshade_customdata_layer_num(shi.totcol, layer->active_rnd);
+ vertcol= (char*)&((MCol*)layer->data)[a*4 + j];
+
+ shi.col[shi.totcol].col[0]= ((float)vertcol[3])/255.0f;
+ shi.col[shi.totcol].col[1]= ((float)vertcol[2])/255.0f;
+ shi.col[shi.totcol].col[2]= ((float)vertcol[1])/255.0f;
+
+ shi.col[shi.totcol].name= layer->name;
+ shi.totcol++;
+ }
+ }
+
+ if(needuv && shi.totuv == 0)
+ VECCOPY(shi.uv[0].uv, shi.lo);
+
+ if(shi.totcol)
+ VECCOPY(shi.vcol, shi.col[0].col);
+}
+
+static void fastshade(float *co, float *nor, float *orco, Material *ma, char *col1, char *col2)
+{
+ ShadeResult shr;
+ int a;
+
+ VECCOPY(shi.co, co);
+ shi.vn[0]= -nor[0];
+ shi.vn[1]= -nor[1];
+ shi.vn[2]= -nor[2];
+ VECCOPY(shi.vno, shi.vn);
+ VECCOPY(shi.facenor, shi.vn);
+
+ if(ma->texco) {
+ VECCOPY(shi.lo, orco);
+
+ if(ma->texco & TEXCO_GLOB) {
+ VECCOPY(shi.gl, shi.lo);
+ }
+ if(ma->texco & TEXCO_WINDOW) {
+ VECCOPY(shi.winco, shi.lo);
+ }
+ if(ma->texco & TEXCO_STICKY) {
+ VECCOPY(shi.sticky, shi.lo);
+ }
+ if(ma->texco & TEXCO_OBJECT) {
+ VECCOPY(shi.co, shi.lo);
+ }
+ if(ma->texco & TEXCO_NORM) {
+ VECCOPY(shi.orn, shi.vn);
+ }
+ if(ma->texco & TEXCO_REFL) {
+ float inp= 2.0*(shi.vn[2]);
+ shi.ref[0]= (inp*shi.vn[0]);
+ shi.ref[1]= (inp*shi.vn[1]);
+ shi.ref[2]= (-1.0+inp*shi.vn[2]);
+ }
+ }
+
+ shi.mat= ma; /* set each time... node shaders change it */
+ RE_shade_external(NULL, &shi, &shr);
+
+ a= 256.0f*(shr.combined[0]);
+ col1[0]= CLAMPIS(a, 0, 255);
+ a= 256.0f*(shr.combined[1]);
+ col1[1]= CLAMPIS(a, 0, 255);
+ a= 256.0f*(shr.combined[2]);
+ col1[2]= CLAMPIS(a, 0, 255);
+
+ if(col2) {
+ shi.vn[0]= -shi.vn[0];
+ shi.vn[1]= -shi.vn[1];
+ shi.vn[2]= -shi.vn[2];
+
+ shi.mat= ma; /* set each time... node shaders change it */
+ RE_shade_external(NULL, &shi, &shr);
+
+ a= 256.0f*(shr.combined[0]);
+ col2[0]= CLAMPIS(a, 0, 255);
+ a= 256.0f*(shr.combined[1]);
+ col2[1]= CLAMPIS(a, 0, 255);
+ a= 256.0f*(shr.combined[2]);
+ col2[2]= CLAMPIS(a, 0, 255);
+ }
+}
+
+static void init_fastshade_for_ob(Render *re, Object *ob, int *need_orco_r, float mat[4][4], float imat[3][3])
+{
+ float tmat[4][4];
+ float amb[3]= {0.0f, 0.0f, 0.0f};
+ int a;
+
+ /* initialize globals in render */
+ RE_shade_external(re, NULL, NULL);
+
+ /* initialize global here */
+ init_fastshade_shadeinput();
+
+ RE_DataBase_GetView(re, tmat);
+ Mat4MulMat4(mat, ob->obmat, tmat);
+
+ Mat4Invert(tmat, mat);
+ Mat3CpyMat4(imat, tmat);
+ if(ob->transflag & OB_NEG_SCALE) Mat3MulFloat((float *)imat, -1.0);
+
+ if (need_orco_r) *need_orco_r= 0;
+ for(a=0; a<ob->totcol; a++) {
+ Material *ma= give_current_material(ob, a+1);
+ if(ma) {
+ init_render_material(ma, 0, amb);
+
+ if(ma->texco & TEXCO_ORCO) {
+ if (need_orco_r) *need_orco_r= 1;
+ }
+ }
+ }
+}
+
+static void end_fastshade_for_ob(Object *ob)
+{
+ int a;
+
+ for(a=0; a<ob->totcol; a++) {
+ Material *ma= give_current_material(ob, a+1);
+ if(ma)
+ end_render_material(ma);
+ }
+}
+
+
+static void mesh_create_shadedColors(Render *re, Object *ob, int onlyForMesh, unsigned int **col1_r, unsigned int **col2_r)
+{
+ Mesh *me= ob->data;
+ DerivedMesh *dm;
+ MVert *mvert;
+ MFace *mface;
+ unsigned int *col1, *col2;
+ float *orco, *vnors, *nors, imat[3][3], mat[4][4], vec[3];
+ int a, i, need_orco, totface, totvert;
+ CustomDataMask dataMask = CD_MASK_BAREMESH | CD_MASK_MCOL
+ | CD_MASK_MTFACE | CD_MASK_NORMAL;
+
+ init_fastshade_for_ob(re, ob, &need_orco, mat, imat);
+
+ orco = (need_orco)? mesh_create_orco(ob): NULL;
+
+ if (onlyForMesh)
+ dm = mesh_get_derived_deform(ob, dataMask);
+ else
+ dm = mesh_get_derived_final(ob, dataMask);
+
+ mvert = dm->getVertArray(dm);
+ mface = dm->getFaceArray(dm);
+ nors = dm->getFaceDataArray(dm, CD_NORMAL);
+ totvert = dm->getNumVerts(dm);
+ totface = dm->getNumFaces(dm);
+
+ if (onlyForMesh) {
+ col1 = *col1_r;
+ col2 = NULL;
+ } else {
+ *col1_r = col1 = MEM_mallocN(sizeof(*col1)*totface*4, "col1");
+
+ if (col2_r && (me->flag & ME_TWOSIDED))
+ col2 = MEM_mallocN(sizeof(*col2)*totface*4, "col2");
+ else
+ col2 = NULL;
+
+ if (col2_r) *col2_r = col2;
+ }
+
+ /* vertexnormals */
+ vnors= MEM_mallocN(totvert*3*sizeof(float), "vnors disp");
+ for (a=0; a<totvert; a++) {
+ MVert *mv = &mvert[a];
+ float *vn= &vnors[a*3];
+ float xn= mv->no[0];
+ float yn= mv->no[1];
+ float zn= mv->no[2];
+
+ /* transpose ! */
+ vn[0]= imat[0][0]*xn+imat[0][1]*yn+imat[0][2]*zn;
+ vn[1]= imat[1][0]*xn+imat[1][1]*yn+imat[1][2]*zn;
+ vn[2]= imat[2][0]*xn+imat[2][1]*yn+imat[2][2]*zn;
+ Normalize(vn);
+ }
+
+ for (i=0; i<totface; i++) {
+ MFace *mf= &mface[i];
+ Material *ma= give_current_material(ob, mf->mat_nr+1);
+ int j, vidx[4], nverts= mf->v4?4:3;
+ unsigned char *col1base= (unsigned char*) &col1[i*4];
+ unsigned char *col2base= (unsigned char*) (col2?&col2[i*4]:NULL);
+ float nor[3], n1[3];
+
+ if(ma==NULL) ma= &defmaterial;
+
+ vidx[0]= mf->v1;
+ vidx[1]= mf->v2;
+ vidx[2]= mf->v3;
+ vidx[3]= mf->v4;
+
+ if (nors) {
+ VECCOPY(nor, &nors[i*3]);
+ } else {
+ if (mf->v4)
+ CalcNormFloat4(mvert[mf->v1].co, mvert[mf->v2].co, mvert[mf->v3].co, mvert[mf->v4].co, nor);
+ else
+ CalcNormFloat(mvert[mf->v1].co, mvert[mf->v2].co, mvert[mf->v3].co, nor);
+ }
+
+ n1[0]= imat[0][0]*nor[0]+imat[0][1]*nor[1]+imat[0][2]*nor[2];
+ n1[1]= imat[1][0]*nor[0]+imat[1][1]*nor[1]+imat[1][2]*nor[2];
+ n1[2]= imat[2][0]*nor[0]+imat[2][1]*nor[1]+imat[2][2]*nor[2];
+ Normalize(n1);
+
+ for (j=0; j<nverts; j++) {
+ MVert *mv= &mvert[vidx[j]];
+ char *col1= (char*)&col1base[j*4];
+ char *col2= (char*)(col2base?&col2base[j*4]:NULL);
+ float *vn = (mf->flag & ME_SMOOTH)?&vnors[3*vidx[j]]:n1;
+
+ VECCOPY(vec, mv->co);
+ Mat4MulVecfl(mat, vec);
+ vec[0]+= 0.001*vn[0];
+ vec[1]+= 0.001*vn[1];
+ vec[2]+= 0.001*vn[2];
+
+ fastshade_customdata(&dm->faceData, i, j, ma);
+ fastshade(vec, vn, orco?&orco[vidx[j]*3]:mv->co, ma, col1, col2);
+ }
+ }
+ MEM_freeN(vnors);
+
+ if (orco)
+ MEM_freeN(orco);
+
+ dm->release(dm);
+
+ end_fastshade_for_ob(ob);
+}
+
+void shadeMeshMCol(Object *ob, Mesh *me)
+{
+ int a;
+ char *cp;
+ unsigned int *mcol= (unsigned int*)me->mcol;
+
+ Render *re= fastshade_get_render();
+ mesh_create_shadedColors(re, ob, 1, &mcol, NULL);
+ me->mcol= (MCol*)mcol;
+
+ /* swap bytes */
+ for(cp= (char *)me->mcol, a= 4*me->totface; a>0; a--, cp+=4) {
+ SWAP(char, cp[0], cp[3]);
+ SWAP(char, cp[1], cp[2]);
+ }
+}
+
+/* has base pointer, to check for layer */
+/* called from drawobject.c */
+void shadeDispList(Base *base)
+{
+ Object *ob= base->object;
+ DispList *dl, *dlob;
+ Material *ma = NULL;
+ Curve *cu;
+ Render *re;
+ float imat[3][3], mat[4][4], vec[3];
+ float *fp, *nor, n1[3];
+ unsigned int *col1;
+ int a, need_orco;
+
+ re= fastshade_get_render();
+
+ dl = find_displist(&ob->disp, DL_VERTCOL);
+ if (dl) {
+ BLI_remlink(&ob->disp, dl);
+ free_disp_elem(dl);
+ }
+
+ if(ob->type==OB_MESH) {
+ dl= MEM_callocN(sizeof(DispList), "displistshade");
+ dl->type= DL_VERTCOL;
+
+ mesh_create_shadedColors(re, ob, 0, &dl->col1, &dl->col2);
+
+ /* add dl to ob->disp after mesh_create_shadedColors, because it
+ might indirectly free ob->disp */
+ BLI_addtail(&ob->disp, dl);
+ }
+ else {
+
+ init_fastshade_for_ob(re, ob, &need_orco, mat, imat);
+
+ if ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT) {
+
+ /* now we need the normals */
+ cu= ob->data;
+ dl= cu->disp.first;
+
+ while(dl) {
+ dlob= MEM_callocN(sizeof(DispList), "displistshade");
+ BLI_addtail(&ob->disp, dlob);
+ dlob->type= DL_VERTCOL;
+ dlob->parts= dl->parts;
+ dlob->nr= dl->nr;
+
+ if(dl->type==DL_INDEX3) {
+ col1= dlob->col1= MEM_mallocN(sizeof(int)*dl->nr, "col1");
+ }
+ else {
+ col1= dlob->col1= MEM_mallocN(sizeof(int)*dl->parts*dl->nr, "col1");
+ }
+
+
+ ma= give_current_material(ob, dl->col+1);
+ if(ma==NULL) ma= &defmaterial;
+
+ if(dl->type==DL_INDEX3) {
+ if(dl->nors) {
+ /* there's just one normal */
+ n1[0]= imat[0][0]*dl->nors[0]+imat[0][1]*dl->nors[1]+imat[0][2]*dl->nors[2];
+ n1[1]= imat[1][0]*dl->nors[0]+imat[1][1]*dl->nors[1]+imat[1][2]*dl->nors[2];
+ n1[2]= imat[2][0]*dl->nors[0]+imat[2][1]*dl->nors[1]+imat[2][2]*dl->nors[2];
+ Normalize(n1);
+
+ fp= dl->verts;
+
+ a= dl->nr;
+ while(a--) {
+ VECCOPY(vec, fp);
+ Mat4MulVecfl(mat, vec);
+
+ fastshade(vec, n1, fp, ma, (char *)col1, NULL);
+
+ fp+= 3; col1++;
+ }
+ }
+ }
+ else if(dl->type==DL_SURF) {
+ if(dl->nors) {
+ a= dl->nr*dl->parts;
+ fp= dl->verts;
+ nor= dl->nors;
+
+ while(a--) {
+ VECCOPY(vec, fp);
+ Mat4MulVecfl(mat, vec);
+
+ n1[0]= imat[0][0]*nor[0]+imat[0][1]*nor[1]+imat[0][2]*nor[2];
+ n1[1]= imat[1][0]*nor[0]+imat[1][1]*nor[1]+imat[1][2]*nor[2];
+ n1[2]= imat[2][0]*nor[0]+imat[2][1]*nor[1]+imat[2][2]*nor[2];
+ Normalize(n1);
+
+ fastshade(vec, n1, fp, ma, (char *)col1, NULL);
+
+ fp+= 3; nor+= 3; col1++;
+ }
+ }
+ }
+ dl= dl->next;
+ }
+ }
+ else if(ob->type==OB_MBALL) {
+ /* there are normals already */
+ dl= ob->disp.first;
+
+ while(dl) {
+
+ if(dl->type==DL_INDEX4) {
+ if(dl->nors) {
+
+ if(dl->col1) MEM_freeN(dl->col1);
+ col1= dl->col1= MEM_mallocN(sizeof(int)*dl->nr, "col1");
+
+ ma= give_current_material(ob, dl->col+1);
+ if(ma==NULL) ma= &defmaterial;
+
+ fp= dl->verts;
+ nor= dl->nors;
+
+ a= dl->nr;
+ while(a--) {
+ VECCOPY(vec, fp);
+ Mat4MulVecfl(mat, vec);
+
+ /* transpose ! */
+ n1[0]= imat[0][0]*nor[0]+imat[0][1]*nor[1]+imat[0][2]*nor[2];
+ n1[1]= imat[1][0]*nor[0]+imat[1][1]*nor[1]+imat[1][2]*nor[2];
+ n1[2]= imat[2][0]*nor[0]+imat[2][1]*nor[1]+imat[2][2]*nor[2];
+ Normalize(n1);
+
+ fastshade(vec, n1, fp, ma, (char *)col1, NULL);
+
+ fp+= 3; col1++; nor+= 3;
+ }
+ }
+ }
+ dl= dl->next;
+ }
+ }
+
+ end_fastshade_for_ob(ob);
+ }
+}
+
+/* frees render and shade part of displists */
+/* note: dont do a shade again, until a redraw happens */
+void reshadeall_displist(void)
+{
+ Base *base;
+ Object *ob;
+
+ fastshade_free_render();
+
+ for(base= G.scene->base.first; base; base= base->next) {
+ ob= base->object;
+ freedisplist(&ob->disp);
+ if(base->lay & G.scene->lay) {
+ /* Metaballs have standard displist at the Object */
+ if(ob->type==OB_MBALL) shadeDispList(base);
+ }
+ }
+}
+
+/* ****************** make displists ********************* */
+
+static void curve_to_displist(Curve *cu, ListBase *nubase, ListBase *dispbase)
+{
+ Nurb *nu;
+ DispList *dl;
+ BezTriple *bezt, *prevbezt;
+ BPoint *bp;
+ float *data, *v1, *v2;
+ int a, len, resolu;
+
+ nu= nubase->first;
+ while(nu) {
+ if(nu->hide==0) {
+
+ if(G.rendering && cu->resolu_ren!=0)
+ resolu= cu->resolu_ren;
+ else
+ resolu= nu->resolu;
+
+ if(nu->pntsu<2);
+ else if((nu->type & 7)==CU_BEZIER) {
+
+ /* count */
+ len= 0;
+ a= nu->pntsu-1;
+ if(nu->flagu & CU_CYCLIC) a++;
+
+ prevbezt= nu->bezt;
+ bezt= prevbezt+1;
+ while(a--) {
+ if(a==0 && (nu->flagu & CU_CYCLIC)) bezt= nu->bezt;
+
+ if(prevbezt->h2==HD_VECT && bezt->h1==HD_VECT) len++;
+ else len+= resolu;
+
+ if(a==0 && (nu->flagu & CU_CYCLIC)==0) len++;
+
+ prevbezt= bezt;
+ bezt++;
+ }
+
+ dl= MEM_callocN(sizeof(DispList), "makeDispListbez");
+ /* len+1 because of 'forward_diff_bezier' function */
+ dl->verts= MEM_callocN( (len+1)*3*sizeof(float), "dlverts");
+ BLI_addtail(dispbase, dl);
+ dl->parts= 1;
+ dl->nr= len;
+ dl->col= nu->mat_nr;
+ dl->charidx= nu->charidx;
+
+ data= dl->verts;
+
+ if(nu->flagu & 1) {
+ dl->type= DL_POLY;
+ a= nu->pntsu;
+ }
+ else {
+ dl->type= DL_SEGM;
+ a= nu->pntsu-1;
+ }
+
+ prevbezt= nu->bezt;
+ bezt= prevbezt+1;
+
+ while(a--) {
+ if(a==0 && dl->type== DL_POLY) bezt= nu->bezt;
+
+ if(prevbezt->h2==HD_VECT && bezt->h1==HD_VECT) {
+ VECCOPY(data, prevbezt->vec[1]);
+ data+= 3;
+ }
+ else {
+ v1= prevbezt->vec[1];
+ v2= bezt->vec[0];
+ forward_diff_bezier(v1[0], v1[3], v2[0], v2[3], data, resolu, 3);
+ forward_diff_bezier(v1[1], v1[4], v2[1], v2[4], data+1, resolu, 3);
+ forward_diff_bezier(v1[2], v1[5], v2[2], v2[5], data+2, resolu, 3);
+ data+= 3*resolu;
+ }
+
+ if(a==0 && dl->type==DL_SEGM) {
+ VECCOPY(data, bezt->vec[1]);
+ }
+
+ prevbezt= bezt;
+ bezt++;
+ }
+ }
+ else if((nu->type & 7)==CU_NURBS) {
+ len= nu->pntsu*resolu;
+ dl= MEM_callocN(sizeof(DispList), "makeDispListsurf");
+ dl->verts= MEM_callocN(len*3*sizeof(float), "dlverts");
+ BLI_addtail(dispbase, dl);
+ dl->parts= 1;
+ dl->nr= len;
+ dl->col= nu->mat_nr;
+ dl->charidx = nu->charidx;
+
+ data= dl->verts;
+ if(nu->flagu & 1) dl->type= DL_POLY;
+ else dl->type= DL_SEGM;
+ makeNurbcurve(nu, data, resolu, 3);
+ }
+ else if((nu->type & 7)==CU_POLY) {
+ len= nu->pntsu;
+ dl= MEM_callocN(sizeof(DispList), "makeDispListpoly");
+ dl->verts= MEM_callocN(len*3*sizeof(float), "dlverts");
+ BLI_addtail(dispbase, dl);
+ dl->parts= 1;
+ dl->nr= len;
+ dl->col= nu->mat_nr;
+ dl->charidx = nu->charidx;
+
+ data= dl->verts;
+ if(nu->flagu & 1) dl->type= DL_POLY;
+ else dl->type= DL_SEGM;
+
+ a= len;
+ bp= nu->bp;
+ while(a--) {
+ VECCOPY(data, bp->vec);
+ bp++;
+ data+= 3;
+ }
+ }
+ }
+ nu= nu->next;
+ }
+}
+
+
+void filldisplist(ListBase *dispbase, ListBase *to)
+{
+ EditVert *eve, *v1, *vlast;
+ EditFace *efa;
+ DispList *dlnew=0, *dl;
+ float *f1;
+ int colnr=0, charidx=0, cont=1, tot, a, *index;
+ long totvert;
+
+ if(dispbase==0) return;
+ if(dispbase->first==0) return;
+
+ while(cont) {
+ cont= 0;
+ totvert=0;
+
+ dl= dispbase->first;
+ while(dl) {
+
+ if(dl->type==DL_POLY) {
+ if(charidx<dl->charidx) cont= 1;
+ else if(charidx==dl->charidx) {
+
+ colnr= dl->col;
+ charidx= dl->charidx;
+
+ /* make editverts and edges */
+ f1= dl->verts;
+ a= dl->nr;
+ eve= v1= 0;
+
+ while(a--) {
+ vlast= eve;
+
+ eve= BLI_addfillvert(f1);
+ totvert++;
+
+ if(vlast==0) v1= eve;
+ else {
+ BLI_addfilledge(vlast, eve);
+ }
+ f1+=3;
+ }
+
+ if(eve!=0 && v1!=0) {
+ BLI_addfilledge(eve, v1);
+ }
+ }
+ }
+ dl= dl->next;
+ }
+
+ if(totvert && BLI_edgefill(0, (G.obedit && G.obedit->actcol)?(G.obedit->actcol-1):0)) {
+
+ /* count faces */
+ tot= 0;
+ efa= fillfacebase.first;
+ while(efa) {
+ tot++;
+ efa= efa->next;
+ }
+
+ if(tot) {
+ dlnew= MEM_callocN(sizeof(DispList), "filldisplist");
+ dlnew->type= DL_INDEX3;
+ dlnew->col= colnr;
+ dlnew->nr= totvert;
+ dlnew->parts= tot;
+
+ dlnew->index= MEM_mallocN(tot*3*sizeof(int), "dlindex");
+ dlnew->verts= MEM_mallocN(totvert*3*sizeof(float), "dlverts");
+
+ /* vert data */
+ f1= dlnew->verts;
+ totvert= 0;
+ eve= fillvertbase.first;
+ while(eve) {
+ VECCOPY(f1, eve->co);
+ f1+= 3;
+
+ /* index number */
+ eve->tmp.l = totvert;
+ totvert++;
+
+ eve= eve->next;
+ }
+
+ /* index data */
+ efa= fillfacebase.first;
+ index= dlnew->index;
+ while(efa) {
+ index[0]= (long)efa->v1->tmp.l;
+ index[1]= (long)efa->v2->tmp.l;
+ index[2]= (long)efa->v3->tmp.l;
+
+ index+= 3;
+ efa= efa->next;
+ }
+ }
+
+ BLI_addhead(to, dlnew);
+
+ }
+ BLI_end_edgefill();
+
+ charidx++;
+ }
+
+ /* do not free polys, needed for wireframe display */
+
+}
+
+static void bevels_to_filledpoly(Curve *cu, ListBase *dispbase)
+{
+ ListBase front, back;
+ DispList *dl, *dlnew;
+ float *fp, *fp1;
+ int a, dpoly;
+
+ front.first= front.last= back.first= back.last= 0;
+
+ dl= dispbase->first;
+ while(dl) {
+ if(dl->type==DL_SURF) {
+ if( (dl->flag & DL_CYCL_V) && (dl->flag & DL_CYCL_U)==0 ) {
+ if( (cu->flag & CU_BACK) && (dl->flag & DL_BACK_CURVE) ) {
+ dlnew= MEM_callocN(sizeof(DispList), "filldisp");
+ BLI_addtail(&front, dlnew);
+ dlnew->verts= fp1= MEM_mallocN(sizeof(float)*3*dl->parts, "filldisp1");
+ dlnew->nr= dl->parts;
+ dlnew->parts= 1;
+ dlnew->type= DL_POLY;
+ dlnew->col= dl->col;
+ dlnew->charidx = dl->charidx;
+
+ fp= dl->verts;
+ dpoly= 3*dl->nr;
+
+ a= dl->parts;
+ while(a--) {
+ VECCOPY(fp1, fp);
+ fp1+= 3;
+ fp+= dpoly;
+ }
+ }
+ if( (cu->flag & CU_FRONT) && (dl->flag & DL_FRONT_CURVE) ) {
+ dlnew= MEM_callocN(sizeof(DispList), "filldisp");
+ BLI_addtail(&back, dlnew);
+ dlnew->verts= fp1= MEM_mallocN(sizeof(float)*3*dl->parts, "filldisp1");
+ dlnew->nr= dl->parts;
+ dlnew->parts= 1;
+ dlnew->type= DL_POLY;
+ dlnew->col= dl->col;
+ dlnew->charidx= dl->charidx;
+
+ fp= dl->verts+3*(dl->nr-1);
+ dpoly= 3*dl->nr;
+
+ a= dl->parts;
+ while(a--) {
+ VECCOPY(fp1, fp);
+ fp1+= 3;
+ fp+= dpoly;
+ }
+ }
+ }
+ }
+ dl= dl->next;
+ }
+
+ filldisplist(&front, dispbase);
+ filldisplist(&back, dispbase);
+
+ freedisplist(&front);
+ freedisplist(&back);
+
+ filldisplist(dispbase, dispbase);
+
+}
+
+void curve_to_filledpoly(Curve *cu, ListBase *nurb, ListBase *dispbase)
+{
+ if(cu->flag & CU_3D) return;
+
+ if(dispbase->first && ((DispList*) dispbase->first)->type==DL_SURF) {
+ bevels_to_filledpoly(cu, dispbase);
+ }
+ else {
+ filldisplist(dispbase, dispbase);
+ }
+}
+
+/* taper rules:
+ - only 1 curve
+ - first point left, last point right
+ - based on subdivided points in original curve, not on points in taper curve (still)
+*/
+static float calc_taper(Object *taperobj, int cur, int tot)
+{
+ Curve *cu;
+ DispList *dl;
+
+ if(taperobj==NULL) return 1.0;
+
+ cu= taperobj->data;
+ dl= cu->disp.first;
+ if(dl==NULL) {
+ makeDispListCurveTypes(taperobj, 0);
+ dl= cu->disp.first;
+ }
+ if(dl) {
+ float fac= ((float)cur)/(float)(tot-1);
+ float minx, dx, *fp;
+ int a;
+
+ /* horizontal size */
+ minx= dl->verts[0];
+ dx= dl->verts[3*(dl->nr-1)] - minx;
+ if(dx>0.0) {
+
+ fp= dl->verts;
+ for(a=0; a<dl->nr; a++, fp+=3) {
+ if( (fp[0]-minx)/dx >= fac) {
+ /* interpolate with prev */
+ if(a>0) {
+ float fac1= (fp[-3]-minx)/dx;
+ float fac2= (fp[0]-minx)/dx;
+ if(fac1!=fac2)
+ return fp[1]*(fac1-fac)/(fac1-fac2) + fp[-2]*(fac-fac2)/(fac1-fac2);
+ }
+ return fp[1];
+ }
+ }
+ return fp[-2]; // last y coord
+ }
+ }
+
+ return 1.0;
+}
+
+void makeDispListMBall(Object *ob)
+{
+ if(!ob || ob->type!=OB_MBALL) return;
+
+ freedisplist(&(ob->disp));
+
+ if(ob->type==OB_MBALL) {
+ if(ob==find_basis_mball(ob)) {
+ metaball_polygonize(ob);
+ tex_space_mball(ob);
+
+ object_deform_mball(ob);
+ }
+ }
+
+ boundbox_displist(ob);
+}
+
+static ModifierData *curve_get_tesselate_point(Object *ob, int forRender, int editmode)
+{
+ ModifierData *md = modifiers_getVirtualModifierList(ob);
+ ModifierData *preTesselatePoint;
+ int required_mode;
+
+ if(forRender) required_mode = eModifierMode_Render;
+ else required_mode = eModifierMode_Realtime;
+
+ if(editmode) required_mode |= eModifierMode_Editmode;
+
+ preTesselatePoint = NULL;
+ for (; md; md=md->next) {
+ ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ if ((md->mode & required_mode) != required_mode) continue;
+ if (mti->isDisabled && mti->isDisabled(md)) continue;
+
+ if (md->type==eModifierType_Hook || md->type==eModifierType_Softbody) {
+ preTesselatePoint = md;
+ }
+ }
+
+ return preTesselatePoint;
+}
+
+void curve_calc_modifiers_pre(Object *ob, ListBase *nurb, int forRender, float (**originalVerts_r)[3], float (**deformedVerts_r)[3], int *numVerts_r)
+{
+ int editmode = (!forRender && ob==G.obedit);
+ ModifierData *md = modifiers_getVirtualModifierList(ob);
+ ModifierData *preTesselatePoint = curve_get_tesselate_point(ob, forRender, editmode);
+ int numVerts = 0;
+ float (*originalVerts)[3] = NULL;
+ float (*deformedVerts)[3] = NULL;
+ int required_mode;
+
+ if(forRender) required_mode = eModifierMode_Render;
+ else required_mode = eModifierMode_Realtime;
+
+ if(editmode) required_mode |= eModifierMode_Editmode;
+
+ if(ob!=G.obedit && do_ob_key(ob)) {
+ deformedVerts = curve_getVertexCos(ob->data, nurb, &numVerts);
+ originalVerts = MEM_dupallocN(deformedVerts);
+ }
+
+ if (preTesselatePoint) {
+ for (; md; md=md->next) {
+ ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ if ((md->mode & required_mode) != required_mode) continue;
+ if (mti->isDisabled && mti->isDisabled(md)) continue;
+ if (mti->type!=eModifierTypeType_OnlyDeform) continue;
+
+ if (!deformedVerts) {
+ deformedVerts = curve_getVertexCos(ob->data, nurb, &numVerts);
+ originalVerts = MEM_dupallocN(deformedVerts);
+ }
+
+ mti->deformVerts(md, ob, NULL, deformedVerts, numVerts);
+
+ if (md==preTesselatePoint)
+ break;
+ }
+ }
+
+ if (deformedVerts) {
+ curve_applyVertexCos(ob->data, nurb, deformedVerts);
+ }
+
+ *originalVerts_r = originalVerts;
+ *deformedVerts_r = deformedVerts;
+ *numVerts_r = numVerts;
+}
+
+void curve_calc_modifiers_post(Object *ob, ListBase *nurb, ListBase *dispbase, int forRender, float (*originalVerts)[3], float (*deformedVerts)[3])
+{
+ int editmode = (!forRender && ob==G.obedit);
+ ModifierData *md = modifiers_getVirtualModifierList(ob);
+ ModifierData *preTesselatePoint = curve_get_tesselate_point(ob, forRender, editmode);
+ DispList *dl;
+ int required_mode;
+
+ if(forRender) required_mode = eModifierMode_Render;
+ else required_mode = eModifierMode_Realtime;
+
+ if(editmode) required_mode |= eModifierMode_Editmode;
+
+ if (preTesselatePoint) {
+ md = preTesselatePoint->next;
+ }
+
+ for (; md; md=md->next) {
+ ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ if ((md->mode & required_mode) != required_mode) continue;
+ if (mti->isDisabled && mti->isDisabled(md)) continue;
+ if (mti->type!=eModifierTypeType_OnlyDeform) continue;
+
+ for (dl=dispbase->first; dl; dl=dl->next) {
+ mti->deformVerts(md, ob, NULL, (float(*)[3]) dl->verts, (dl->type==DL_INDEX3)?dl->nr:dl->parts*dl->nr);
+ }
+ }
+
+ if (deformedVerts) {
+ curve_applyVertexCos(ob->data, nurb, originalVerts);
+ MEM_freeN(originalVerts);
+ MEM_freeN(deformedVerts);
+ }
+}
+
+static void displist_surf_indices(DispList *dl)
+{
+ int a, b, p1, p2, p3, p4;
+ int *index;
+
+ dl->totindex= 0;
+
+ index=dl->index= MEM_mallocN( 4*sizeof(int)*(dl->parts+1)*(dl->nr+1), "index array nurbs");
+
+ for(a=0; a<dl->parts; a++) {
+
+ DL_SURFINDEX(dl->flag & DL_CYCL_U, dl->flag & DL_CYCL_V, dl->nr, dl->parts);
+
+ for(; b<dl->nr; b++, index+=4) {
+ index[0]= p1;
+ index[1]= p2;
+ index[2]= p4;
+ index[3]= p3;
+
+ dl->totindex++;
+
+ p2= p1; p1++;
+ p4= p3; p3++;
+
+ }
+ }
+
+}
+
+void makeDispListSurf(Object *ob, ListBase *dispbase, int forRender)
+{
+ ListBase *nubase;
+ Nurb *nu;
+ Curve *cu = ob->data;
+ DispList *dl;
+ float *data;
+ int len;
+ int numVerts;
+ float (*originalVerts)[3];
+ float (*deformedVerts)[3];
+
+ if(!forRender && ob==G.obedit) {
+ nubase= &editNurb;
+ }
+ else {
+ nubase= &cu->nurb;
+ }
+
+ curve_calc_modifiers_pre(ob, nubase, forRender, &originalVerts, &deformedVerts, &numVerts);
+
+ for (nu=nubase->first; nu; nu=nu->next) {
+ if(forRender || nu->hide==0) {
+ if(nu->pntsv==1) {
+ len= nu->pntsu*nu->resolu;
+
+ dl= MEM_callocN(sizeof(DispList), "makeDispListsurf");
+ dl->verts= MEM_callocN(len*3*sizeof(float), "dlverts");
+
+ BLI_addtail(dispbase, dl);
+ dl->parts= 1;
+ dl->nr= len;
+ dl->col= nu->mat_nr;
+ dl->charidx= nu->charidx;
+ dl->rt= nu->flag;
+
+ data= dl->verts;
+ if(nu->flagu & 1) dl->type= DL_POLY;
+ else dl->type= DL_SEGM;
+
+ makeNurbcurve(nu, data, nu->resolu, 3);
+ }
+ else {
+ len= nu->resolu*nu->resolv;
+
+ dl= MEM_callocN(sizeof(DispList), "makeDispListsurf");
+ dl->verts= MEM_callocN(len*3*sizeof(float), "dlverts");
+ BLI_addtail(dispbase, dl);
+
+ dl->col= nu->mat_nr;
+ dl->charidx= nu->charidx;
+ dl->rt= nu->flag;
+
+ data= dl->verts;
+ dl->type= DL_SURF;
+
+ dl->parts= nu->resolu; /* in reverse, because makeNurbfaces works that way */
+ dl->nr= nu->resolv;
+ if(nu->flagv & CU_CYCLIC) dl->flag|= DL_CYCL_U; /* reverse too! */
+ if(nu->flagu & CU_CYCLIC) dl->flag|= DL_CYCL_V;
+
+ makeNurbfaces(nu, data, 0);
+
+ /* gl array drawing: using indices */
+ displist_surf_indices(dl);
+ }
+ }
+ }
+
+ if (!forRender) {
+ tex_space_curve(cu);
+ }
+
+ curve_calc_modifiers_post(ob, nubase, dispbase, forRender, originalVerts, deformedVerts);
+}
+
+void makeDispListCurveTypes(Object *ob, int forOrco)
+{
+ Curve *cu = ob->data;
+ ListBase *dispbase;
+
+ /* we do allow duplis... this is only displist on curve level */
+ if(!ELEM3(ob->type, OB_SURF, OB_CURVE, OB_FONT)) return;
+
+ freedisplist(&(ob->disp));
+ dispbase= &(cu->disp);
+ freedisplist(dispbase);
+
+ if(ob->type==OB_SURF) {
+ makeDispListSurf(ob, dispbase, 0);
+ }
+ else if ELEM(ob->type, OB_CURVE, OB_FONT) {
+ ListBase dlbev;
+ float (*originalVerts)[3];
+ float (*deformedVerts)[3];
+ int obedit= (G.obedit && G.obedit->data==ob->data && G.obedit->type==OB_CURVE);
+ ListBase *nubase = obedit?&editNurb:&cu->nurb;
+ int numVerts;
+
+ BLI_freelistN(&(cu->bev));
+
+ if(cu->path) free_path(cu->path);
+ cu->path= NULL;
+
+ if(ob->type==OB_FONT) text_to_curve(ob, 0);
+
+ if(!forOrco) curve_calc_modifiers_pre(ob, nubase, 0, &originalVerts, &deformedVerts, &numVerts);
+
+ makeBevelList(ob);
+
+ /* If curve has no bevel will return nothing */
+ makebevelcurve(ob, &dlbev);
+
+ /* no bevel or extrude, and no width correction? */
+ if (!dlbev.first && cu->width==1.0f) {
+ curve_to_displist(cu, nubase, dispbase);
+ } else {
+ float widfac= cu->width-1.0;
+ BevList *bl= cu->bev.first;
+ Nurb *nu= nubase->first;
+
+ for (; bl && nu; bl=bl->next,nu=nu->next) {
+ DispList *dl;
+ float *fp1, *data;
+ BevPoint *bevp;
+ int a,b;
+
+ /* exception handling; curve without bevel or extrude, with width correction */
+ if(dlbev.first==NULL) {
+ dl= MEM_callocN(sizeof(DispList), "makeDispListbev");
+ dl->verts= MEM_callocN(3*sizeof(float)*bl->nr, "dlverts");
+ BLI_addtail(dispbase, dl);
+
+ if(bl->poly!= -1) dl->type= DL_POLY;
+ else dl->type= DL_SEGM;
+
+ if(dl->type==DL_SEGM) dl->flag = (DL_FRONT_CURVE|DL_BACK_CURVE);
+
+ dl->parts= 1;
+ dl->nr= bl->nr;
+ dl->col= nu->mat_nr;
+ dl->charidx= nu->charidx;
+ dl->rt= nu->flag;
+
+ a= dl->nr;
+ bevp= (BevPoint *)(bl+1);
+ data= dl->verts;
+ while(a--) {
+ data[0]= bevp->x+widfac*bevp->sina;
+ data[1]= bevp->y+widfac*bevp->cosa;
+ data[2]= bevp->z;
+ bevp++;
+ data+=3;
+ }
+ }
+ else {
+ DispList *dlb;
+
+ for (dlb=dlbev.first; dlb; dlb=dlb->next) {
+
+ /* for each part of the bevel use a separate displblock */
+ dl= MEM_callocN(sizeof(DispList), "makeDispListbev1");
+ dl->verts= data= MEM_callocN(3*sizeof(float)*dlb->nr*bl->nr, "dlverts");
+ BLI_addtail(dispbase, dl);
+
+ dl->type= DL_SURF;
+
+ dl->flag= dlb->flag & (DL_FRONT_CURVE|DL_BACK_CURVE);
+ if(dlb->type==DL_POLY) dl->flag |= DL_CYCL_U;
+ if(bl->poly>=0) dl->flag |= DL_CYCL_V;
+
+ dl->parts= bl->nr;
+ dl->nr= dlb->nr;
+ dl->col= nu->mat_nr;
+ dl->charidx= nu->charidx;
+ dl->rt= nu->flag;
+ dl->bevelSplitFlag= MEM_callocN(sizeof(*dl->col2)*((bl->nr+0x1F)>>5), "col2");
+ bevp= (BevPoint *)(bl+1);
+
+ /* for each point of poly make a bevel piece */
+ bevp= (BevPoint *)(bl+1);
+ for(a=0; a<bl->nr; a++,bevp++) {
+ float fac=1.0;
+ if (cu->taperobj==NULL) {
+ if ( (cu->bevobj!=NULL) || !((cu->flag & CU_FRONT) || (cu->flag & CU_BACK)) )
+ fac = calc_curve_subdiv_radius(cu, nu, a);
+ } else {
+ fac = calc_taper(cu->taperobj, a, bl->nr);
+ }
+
+ if (bevp->f1) {
+ dl->bevelSplitFlag[a>>5] |= 1<<(a&0x1F);
+ }
+
+ /* rotate bevel piece and write in data */
+ fp1= dlb->verts;
+ for (b=0; b<dlb->nr; b++,fp1+=3,data+=3) {
+ if(cu->flag & CU_3D) {
+ float vec[3];
+
+ vec[0]= fp1[1]+widfac;
+ vec[1]= fp1[2];
+ vec[2]= 0.0;
+
+ Mat3MulVecfl(bevp->mat, vec);
+
+ data[0]= bevp->x+ fac*vec[0];
+ data[1]= bevp->y+ fac*vec[1];
+ data[2]= bevp->z+ fac*vec[2];
+ }
+ else {
+ data[0]= bevp->x+ fac*(widfac+fp1[1])*bevp->sina;
+ data[1]= bevp->y+ fac*(widfac+fp1[1])*bevp->cosa;
+ data[2]= bevp->z+ fac*fp1[2];
+ }
+ }
+ }
+
+ /* gl array drawing: using indices */
+ displist_surf_indices(dl);
+ }
+ }
+
+ }
+ freedisplist(&dlbev);
+ }
+
+ curve_to_filledpoly(cu, nubase, dispbase);
+
+ if(cu->flag & CU_PATH) calc_curvepath(ob);
+
+ if(!forOrco) curve_calc_modifiers_post(ob, nubase, &cu->disp, 0, originalVerts, deformedVerts);
+ tex_space_curve(cu);
+ }
+
+ boundbox_displist(ob);
+}
+
+void imagestodisplist(void)
+{
+ /* removed */
+}
+
+/* this is confusing, there's also min_max_object, appplying the obmat... */
+static void boundbox_displist(Object *ob)
+{
+ BoundBox *bb=0;
+ float min[3], max[3];
+ DispList *dl;
+ float *vert;
+ int a, tot=0;
+
+ INIT_MINMAX(min, max);
+
+ if(ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
+ Curve *cu= ob->data;
+ int doit= 0;
+
+ if(cu->bb==0) cu->bb= MEM_callocN(sizeof(BoundBox), "boundbox");
+ bb= cu->bb;
+
+ dl= cu->disp.first;
+
+ while (dl) {
+ if(dl->type==DL_INDEX3) tot= dl->nr;
+ else tot= dl->nr*dl->parts;
+
+ vert= dl->verts;
+ for(a=0; a<tot; a++, vert+=3) {
+ doit= 1;
+ DO_MINMAX(vert, min, max);
+ }
+
+ dl= dl->next;
+ }
+
+ if(!doit) {
+ min[0] = min[1] = min[2] = -1.0f;
+ max[0] = max[1] = max[2] = 1.0f;
+ }
+
+ }
+
+ if(bb) {
+ boundbox_set_from_min_max(bb, min, max);
+ }
+}
+
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
new file mode 100644
index 00000000000..07fe8bbee31
--- /dev/null
+++ b/source/blender/blenkernel/intern/effect.c
@@ -0,0 +1,2110 @@
+/* effect.c
+ *
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <math.h>
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_curve_types.h"
+#include "DNA_effect_types.h"
+#include "DNA_group_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_key_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_listBase.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_material_types.h"
+#include "DNA_object_types.h"
+#include "DNA_object_force.h"
+#include "DNA_texture_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+#include "BLI_jitter.h"
+#include "BLI_rand.h"
+
+#include "BKE_action.h"
+#include "BKE_anim.h" /* needed for where_on_path */
+#include "BKE_armature.h"
+#include "BKE_bad_level_calls.h"
+#include "BKE_blender.h"
+#include "BKE_constraint.h"
+#include "BKE_deform.h"
+#include "BKE_depsgraph.h"
+#include "BKE_displist.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_effect.h"
+#include "BKE_global.h"
+#include "BKE_group.h"
+#include "BKE_ipo.h"
+#include "BKE_key.h"
+#include "BKE_lattice.h"
+#include "BKE_mesh.h"
+#include "BKE_material.h"
+#include "BKE_main.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+#include "BKE_scene.h"
+#include "BKE_screen.h"
+#include "BKE_utildefines.h"
+
+#include "PIL_time.h"
+#include "RE_render_ext.h"
+
+/* fluid sim particle import */
+#ifndef DISABLE_ELBEEM
+#include "DNA_object_fluidsim.h"
+#include "LBM_fluidsim.h"
+#include "elbeem.h"
+#include <zlib.h>
+#include <string.h>
+#endif // DISABLE_ELBEEM
+
+/* temporal struct, used for reading return of mesh_get_mapped_verts_nors() */
+typedef struct VeNoCo {
+ float co[3], no[3];
+} VeNoCo;
+
+Effect *add_effect(int type)
+{
+ Effect *eff=0;
+ PartEff *paf;
+ int a;
+
+ switch(type) {
+ case EFF_PARTICLE:
+ paf= MEM_callocN(sizeof(PartEff), "neweff");
+ eff= (Effect *)paf;
+
+ paf->sta= 1.0;
+ paf->end= 100.0;
+ paf->lifetime= 50.0;
+ for(a=0; a<PAF_MAXMULT; a++) {
+ paf->life[a]= 50.0;
+ paf->child[a]= 4;
+ paf->mat[a]= 1;
+ }
+
+ paf->totpart= 1000;
+ paf->totkey= 8;
+ paf->staticstep= 5;
+ paf->defvec[2]= 1.0f;
+ paf->nabla= 0.05f;
+ paf->disp = 100;
+ paf->speedtex = 8;
+ paf->omat = 1;
+ paf->flag= PAF_FACE;
+
+ break;
+ }
+
+ eff->type= eff->buttype= type;
+ eff->flag |= SELECT;
+
+ return eff;
+}
+
+void free_effect(Effect *eff)
+{
+ PartEff *paf;
+
+ if(eff->type==EFF_PARTICLE) {
+ paf= (PartEff *)eff;
+ if(paf->keys) MEM_freeN(paf->keys);
+ }
+ MEM_freeN(eff);
+}
+
+
+void free_effects(ListBase *lb)
+{
+ Effect *eff;
+
+ eff= lb->first;
+ while(eff) {
+ BLI_remlink(lb, eff);
+ free_effect(eff);
+ eff= lb->first;
+ }
+}
+
+Effect *copy_effect(Effect *eff)
+{
+ Effect *effn;
+
+ effn= MEM_dupallocN(eff);
+ if(effn->type==EFF_PARTICLE) ((PartEff *)effn)->keys= 0;
+
+ return effn;
+}
+
+void copy_act_effect(Object *ob)
+{
+ /* return a copy of the active effect */
+ Effect *effn, *eff;
+
+ eff= ob->effect.first;
+ while(eff) {
+ if(eff->flag & SELECT) {
+
+ effn= copy_effect(eff);
+ BLI_addtail(&ob->effect, effn);
+
+ eff->flag &= ~SELECT;
+ return;
+
+ }
+ eff= eff->next;
+ }
+
+ /* when it comes here: add new effect */
+ eff= add_effect(EFF_PARTICLE);
+ BLI_addtail(&ob->effect, eff);
+
+}
+
+void copy_effects(ListBase *lbn, ListBase *lb)
+{
+ Effect *eff, *effn;
+
+ lbn->first= lbn->last= 0;
+
+ eff= lb->first;
+ while(eff) {
+ effn= copy_effect(eff);
+ BLI_addtail(lbn, effn);
+
+ eff= eff->next;
+ }
+
+}
+
+void deselectall_eff(Object *ob)
+{
+ Effect *eff= ob->effect.first;
+
+ while(eff) {
+ eff->flag &= ~SELECT;
+ eff= eff->next;
+ }
+}
+
+/* ***************** PARTICLES ***************** */
+
+static Particle *new_particle(PartEff *paf)
+{
+ static Particle *pa;
+ static int cur;
+
+ /* we agree: when paf->keys==0: alloc */
+ if(paf->keys==NULL) {
+ pa= paf->keys= MEM_callocN( paf->totkey*paf->totpart*sizeof(Particle), "particlekeys" );
+ cur= 0;
+ }
+ else {
+ if(cur && cur<paf->totpart) pa+=paf->totkey;
+ cur++;
+ }
+ return pa;
+}
+
+PartEff *give_parteff(Object *ob)
+{
+ PartEff *paf;
+
+ paf= ob->effect.first;
+ while(paf) {
+ if(paf->type==EFF_PARTICLE) return paf;
+ paf= paf->next;
+ }
+ return 0;
+}
+
+void where_is_particle(PartEff *paf, Particle *pa, float ctime, float *vec)
+{
+ Particle *p[4];
+ float dt, t[4];
+ int a;
+
+ if(paf->totkey==1 || ctime < pa->time) {
+ VECCOPY(vec, pa->co);
+ return;
+ }
+
+ /* first find the first particlekey */
+ a= (int)((paf->totkey-1)*(ctime-pa->time)/pa->lifetime);
+ if(a>=paf->totkey) a= paf->totkey-1;
+ else if(a<0) a= 0;
+
+ pa+= a;
+
+ if(a>0) p[0]= pa-1; else p[0]= pa;
+ p[1]= pa;
+
+ if(a+1<paf->totkey) p[2]= pa+1; else p[2]= pa;
+ if(a+2<paf->totkey) p[3]= pa+2; else p[3]= p[2];
+
+ if(p[1]==p[2] || p[2]->time == p[1]->time) dt= 0.0;
+ else dt= (ctime-p[1]->time)/(p[2]->time - p[1]->time);
+
+ if(paf->flag & PAF_BSPLINE) set_four_ipo(dt, t, KEY_BSPLINE);
+ else set_four_ipo(dt, t, KEY_CARDINAL);
+
+ vec[0]= t[0]*p[0]->co[0] + t[1]*p[1]->co[0] + t[2]*p[2]->co[0] + t[3]*p[3]->co[0];
+ vec[1]= t[0]*p[0]->co[1] + t[1]*p[1]->co[1] + t[2]*p[2]->co[1] + t[3]*p[3]->co[1];
+ vec[2]= t[0]*p[0]->co[2] + t[1]*p[1]->co[2] + t[2]*p[2]->co[2] + t[3]*p[3]->co[2];
+
+}
+
+static void particle_tex(MTex *mtex, PartEff *paf, float *co, float *no)
+{
+ float tin, tr, tg, tb, ta;
+ float old;
+
+ externtex(mtex, co, &tin, &tr, &tg, &tb, &ta);
+
+ if(paf->texmap==PAF_TEXINT) {
+ tin*= paf->texfac;
+ no[0]+= tin*paf->defvec[0];
+ no[1]+= tin*paf->defvec[1];
+ no[2]+= tin*paf->defvec[2];
+ }
+ else if(paf->texmap==PAF_TEXRGB) {
+ no[0]+= (tr-0.5f)*paf->texfac;
+ no[1]+= (tg-0.5f)*paf->texfac;
+ no[2]+= (tb-0.5f)*paf->texfac;
+ }
+ else { /* PAF_TEXGRAD */
+
+ old= tin;
+ co[0]+= paf->nabla;
+ externtex(mtex, co, &tin, &tr, &tg, &tb, &ta);
+ no[0]+= (old-tin)*paf->texfac;
+
+ co[0]-= paf->nabla;
+ co[1]+= paf->nabla;
+ externtex(mtex, co, &tin, &tr, &tg, &tb, &ta);
+ no[1]+= (old-tin)*paf->texfac;
+
+ co[1]-= paf->nabla;
+ co[2]+= paf->nabla;
+ externtex(mtex, co, &tin, &tr, &tg, &tb, &ta);
+ no[2]+= (old-tin)*paf->texfac;
+
+ }
+}
+
+/* -------------------------- Effectors ------------------ */
+
+static void add_to_effectorcache(ListBase *lb, Object *ob, Object *obsrc)
+{
+ pEffectorCache *ec;
+ PartDeflect *pd= ob->pd;
+
+ if(pd->forcefield == PFIELD_GUIDE) {
+ if(ob->type==OB_CURVE && obsrc->type==OB_MESH) { /* guides only do mesh particles */
+ Curve *cu= ob->data;
+ if(cu->flag & CU_PATH) {
+ if(cu->path==NULL || cu->path->data==NULL)
+ makeDispListCurveTypes(ob, 0);
+ if(cu->path && cu->path->data) {
+ ec= MEM_callocN(sizeof(pEffectorCache), "effector cache");
+ ec->ob= ob;
+ BLI_addtail(lb, ec);
+ }
+ }
+ }
+ }
+ else if(pd->forcefield) {
+ ec= MEM_callocN(sizeof(pEffectorCache), "effector cache");
+ ec->ob= ob;
+ BLI_addtail(lb, ec);
+ }
+}
+
+/* returns ListBase handle with objects taking part in the effecting */
+ListBase *pdInitEffectors(Object *obsrc, Group *group)
+{
+ static ListBase listb={NULL, NULL};
+ pEffectorCache *ec;
+ Base *base;
+ unsigned int layer= obsrc->lay;
+
+ if(group) {
+ GroupObject *go;
+
+ for(go= group->gobject.first; go; go= go->next) {
+ if( (go->ob->lay & layer) && go->ob->pd && go->ob!=obsrc) {
+ add_to_effectorcache(&listb, go->ob, obsrc);
+ }
+ }
+ }
+ else {
+ for(base = G.scene->base.first; base; base= base->next) {
+ if( (base->lay & layer) && base->object->pd && base->object!=obsrc) {
+ add_to_effectorcache(&listb, base->object, obsrc);
+ }
+ }
+ }
+
+ /* make a full copy */
+ for(ec= listb.first; ec; ec= ec->next) {
+ ec->obcopy= *(ec->ob);
+ }
+
+ if(listb.first)
+ return &listb;
+
+ return NULL;
+}
+
+void pdEndEffectors(ListBase *lb)
+{
+ if(lb) {
+ pEffectorCache *ec;
+ /* restore full copy */
+ for(ec= lb->first; ec; ec= ec->next)
+ *(ec->ob)= ec->obcopy;
+
+ BLI_freelistN(lb);
+ }
+}
+
+/* local for this c file, only for guides now */
+static void precalc_effectors(Object *ob, PartEff *paf, Particle *pa, ListBase *lb)
+{
+ pEffectorCache *ec;
+
+ for(ec= lb->first; ec; ec= ec->next) {
+ PartDeflect *pd= ec->ob->pd;
+
+ ec->oldspeed[0]= ec->oldspeed[1]= ec->oldspeed[2]= 0.0f;
+
+ if(pd->forcefield==PFIELD_GUIDE && ec->ob->type==OB_CURVE) {
+ float vec[4], dir[3];
+
+ if(!(paf->flag & PAF_STATIC))
+ where_is_object_time(ec->ob, pa->time);
+
+ /* scale corrects speed vector to curve size */
+ if(paf->totkey>1) ec->scale= (paf->totkey-1)/pa->lifetime;
+ else ec->scale= 1.0f;
+
+ /* time_scale is for random life */
+ if(pa->lifetime>paf->lifetime)
+ ec->time_scale= paf->lifetime/pa->lifetime;
+ else
+ ec->time_scale= pa->lifetime/paf->lifetime;
+
+ /* distance of first path point to particle origin */
+ where_on_path(ec->ob, 0.0f, vec, dir);
+ VECCOPY(ec->oldloc, vec); /* store local coord for differences */
+ Mat4MulVecfl(ec->ob->obmat, vec);
+
+ /* for static we need to move to global space */
+ if(paf->flag & PAF_STATIC) {
+ VECCOPY(dir, pa->co);
+ Mat4MulVecfl(ob->obmat, dir);
+ ec->guide_dist= VecLenf(vec, dir);
+ }
+ else
+ ec->guide_dist= VecLenf(vec, pa->co);
+ }
+ }
+}
+
+
+/* -------- pdDoEffectors() --------
+ generic force/speed system, now used for particles and softbodies
+ lb = listbase with objects that take part in effecting
+ opco = global coord, as input
+ force = force accumulator
+ speed = actual current speed which can be altered
+ cur_time = "external" time in frames, is constant for static particles
+ loc_time = "local" time in frames, range <0-1> for the lifetime of particle
+ par_layer = layer the caller is in
+ flags = only used for softbody wind now
+ guide = old speed of particle
+
+*/
+void pdDoEffectors(ListBase *lb, float *opco, float *force, float *speed, float cur_time, float loc_time, unsigned int flags)
+{
+/*
+ Modifies the force on a particle according to its
+ relation with the effector object
+ Different kind of effectors include:
+ Forcefields: Gravity-like attractor
+ (force power is related to the inverse of distance to the power of a falloff value)
+ Vortex fields: swirling effectors
+ (particles rotate around Z-axis of the object. otherwise, same relation as)
+ (Forcefields, but this is not done through a force/acceleration)
+ Guide: particles on a path
+ (particles are guided along a curve bezier or old nurbs)
+ (is independent of other effectors)
+*/
+ Object *ob;
+ pEffectorCache *ec;
+ PartDeflect *pd;
+ float vect_to_vert[3];
+ float f_force, force_vec[3];
+ float *obloc;
+ float distance, force_val, ffall_val;
+ float guidecollect[3], guidedist= 0.0f;
+ int cur_frame;
+
+ guidecollect[0]= guidecollect[1]= guidecollect[2]=0.0f;
+
+ /* Cycle through collected objects, get total of (1/(gravity_strength * dist^gravity_power)) */
+ /* Check for min distance here? (yes would be cool to add that, ton) */
+
+ for(ec = lb->first; ec; ec= ec->next) {
+ /* object effectors were fully checked to be OK to evaluate! */
+ ob= ec->ob;
+ pd= ob->pd;
+
+ /* Get IPO force strength and fall off values here */
+ if (has_ipo_code(ob->ipo, OB_PD_FSTR))
+ force_val = IPO_GetFloatValue(ob->ipo, OB_PD_FSTR, cur_time);
+ else
+ force_val = pd->f_strength;
+
+ if (has_ipo_code(ob->ipo, OB_PD_FFALL))
+ ffall_val = IPO_GetFloatValue(ob->ipo, OB_PD_FFALL, cur_time);
+ else
+ ffall_val = pd->f_power;
+
+ /* Need to set r.cfra for paths (investigate, ton) (uses ob->ctime now, ton) */
+ if(ob->ctime!=cur_time) {
+ cur_frame = G.scene->r.cfra;
+ G.scene->r.cfra = (int)cur_time;
+ where_is_object_time(ob, cur_time);
+ G.scene->r.cfra = cur_frame;
+ }
+
+ /* use center of object for distance calculus */
+ obloc= ob->obmat[3];
+ VECSUB(vect_to_vert, obloc, opco);
+ distance = VecLength(vect_to_vert);
+
+ if((pd->flag & PFIELD_USEMAX) && distance>pd->maxdist && pd->forcefield != PFIELD_GUIDE)
+ ; /* don't do anything */
+ else if(pd->forcefield == PFIELD_WIND) {
+ VECCOPY(force_vec, ob->obmat[2]);
+
+ /* wind works harder perpendicular to normal, would be nice for softbody later (ton) */
+
+ /* Limit minimum distance to vertex so that */
+ /* the force is not too big */
+ if (distance < 0.001) distance = 0.001f;
+ f_force = (force_val)*(1/(1000 * (float)pow((double)distance, (double)ffall_val)));
+ /* this option for softbody only */
+ if(flags && PE_WIND_AS_SPEED){
+ speed[0] -= (force_vec[0] * f_force );
+ speed[1] -= (force_vec[1] * f_force );
+ speed[2] -= (force_vec[2] * f_force );
+ }
+ else{
+ force[0] += force_vec[0]*f_force;
+ force[1] += force_vec[1]*f_force;
+ force[2] += force_vec[2]*f_force;
+ }
+ }
+ else if(pd->forcefield == PFIELD_FORCE) {
+
+ /* only use center of object */
+ obloc= ob->obmat[3];
+
+ /* Now calculate the gravitational force */
+ VECSUB(vect_to_vert, obloc, opco);
+ distance = VecLength(vect_to_vert);
+
+ /* Limit minimum distance to vertex so that */
+ /* the force is not too big */
+ if (distance < 0.001) distance = 0.001f;
+ f_force = (force_val)*(1.0/(1000.0 * (float)pow((double)distance, (double)ffall_val)));
+ force[0] += (vect_to_vert[0] * f_force );
+ force[1] += (vect_to_vert[1] * f_force );
+ force[2] += (vect_to_vert[2] * f_force );
+ }
+ else if(pd->forcefield == PFIELD_VORTEX) {
+ float vortexvec[3];
+
+ /* only use center of object */
+ obloc= ob->obmat[3];
+
+ /* Now calculate the vortex force */
+ VECSUB(vect_to_vert, obloc, opco);
+ distance = VecLength(vect_to_vert);
+
+ Crossf(force_vec, ob->obmat[2], vect_to_vert);
+ Normalize(force_vec);
+
+ /* Limit minimum distance to vertex so that */
+ /* the force is not too big */
+ if (distance < 0.001) distance = 0.001f;
+ f_force = (force_val)*(1.0/(100.0 * (float)pow((double)distance, (double)ffall_val)));
+ vortexvec[0]= -(force_vec[0] * f_force );
+ vortexvec[1]= -(force_vec[1] * f_force );
+ vortexvec[2]= -(force_vec[2] * f_force );
+
+ /* this option for softbody only */
+ if(flags &&PE_WIND_AS_SPEED) {
+ speed[0]+= vortexvec[0];
+ speed[1]+= vortexvec[1];
+ speed[2]+= vortexvec[2];
+ }
+ else {
+ /* since vortex alters the speed, we have to correct for the previous vortex result */
+ speed[0]+= vortexvec[0] - ec->oldspeed[0];
+ speed[1]+= vortexvec[1] - ec->oldspeed[1];
+ speed[2]+= vortexvec[2] - ec->oldspeed[2];
+
+ VECCOPY(ec->oldspeed, vortexvec);
+ }
+ }
+ else if(pd->forcefield == PFIELD_GUIDE) {
+ float guidevec[4], guidedir[3];
+ float mindist= force_val; /* force_val is actually mindist in the UI */
+
+ distance= ec->guide_dist;
+
+ /* WARNING: bails out with continue here */
+ if((pd->flag & PFIELD_USEMAX) && distance>pd->maxdist) continue;
+
+ /* calculate contribution factor for this guide */
+ if(distance<=mindist) f_force= 1.0f;
+ else if(pd->flag & PFIELD_USEMAX) {
+ if(distance>pd->maxdist || mindist>=pd->maxdist) f_force= 0.0f;
+ else {
+ f_force= 1.0f - (distance-mindist)/(pd->maxdist - mindist);
+ if(ffall_val!=0.0f)
+ f_force = (float)pow(f_force, ffall_val+1.0);
+ }
+ }
+ else {
+ f_force= 1.0f/(1.0f + distance-mindist);
+ if(ffall_val!=0.0f)
+ f_force = (float)pow(f_force, ffall_val+1.0);
+ }
+
+ /* now derive path point from loc_time */
+ if(pd->flag & PFIELD_GUIDE_PATH_ADD)
+ where_on_path(ob, f_force*loc_time*ec->time_scale, guidevec, guidedir);
+ else
+ where_on_path(ob, loc_time*ec->time_scale, guidevec, guidedir);
+
+ VECSUB(guidedir, guidevec, ec->oldloc);
+ VECCOPY(ec->oldloc, guidevec);
+
+ Mat4Mul3Vecfl(ob->obmat, guidedir);
+ VecMulf(guidedir, ec->scale); /* correction for lifetime and speed */
+
+ /* we subtract the speed we gave it previous step */
+ VECCOPY(guidevec, guidedir);
+ VECSUB(guidedir, guidedir, ec->oldspeed);
+ VECCOPY(ec->oldspeed, guidevec);
+
+ /* if it fully contributes, we stop */
+ if(f_force==1.0) {
+ VECCOPY(guidecollect, guidedir);
+ guidedist= 1.0f;
+ break;
+ }
+ else if(guidedist<1.0f) {
+ VecMulf(guidedir, f_force);
+ VECADD(guidecollect, guidecollect, guidedir);
+ guidedist += f_force;
+ }
+ }
+ }
+
+ /* all guides are accumulated here */
+ if(guidedist!=0.0f) {
+ if(guidedist!=1.0f) VecMulf(guidecollect, 1.0f/guidedist);
+ VECADD(speed, speed, guidecollect);
+ }
+}
+
+static void cache_object_vertices(Object *ob)
+{
+ Mesh *me;
+ MVert *mvert;
+ float *fp;
+ int a;
+
+ me= ob->data;
+ if(me->totvert==0) return;
+
+ fp= ob->sumohandle= MEM_mallocN(3*sizeof(float)*me->totvert, "cache particles");
+ mvert= me->mvert;
+ a= me->totvert;
+ while(a--) {
+ VECCOPY(fp, mvert->co);
+ Mat4MulVecfl(ob->obmat, fp);
+ mvert++;
+ fp+= 3;
+ }
+}
+
+static int pdDoDeflection(RNG *rng, float opco[3], float npco[3], float opno[3],
+ float npno[3], float life, float force[3], int def_depth,
+ float cur_time, unsigned int par_layer, int *last_object,
+ int *last_face, int *same_face)
+{
+ /* Particle deflection code */
+ /* The code is in two sections: the first part checks whether a particle has */
+ /* intersected a face of a deflector mesh, given its old and new co-ords, opco and npco */
+ /* and which face it hit first */
+ /* The second part calculates the new co-ordinates given that collision and updates */
+ /* the new co-ordinates accordingly */
+ Base *base;
+ Object *ob, *deflection_object = NULL;
+ Mesh *def_mesh;
+ MFace *mface, *deflection_face = NULL;
+ float *v1, *v2, *v3, *v4, *vcache=NULL;
+ float nv1[3], nv2[3], nv3[3], nv4[3], edge1[3], edge2[3];
+ float dv1[3] = {0}, dv2[3] = {0}, dv3[3] = {0};
+ float vect_to_int[3], refl_vel[3];
+ float d_intersect_co[3], d_intersect_vect[3], d_nvect[3], d_i_co_above[3];
+ float forcec[3];
+ float k_point3, dist_to_plane;
+ float first_dist, ref_plane_mag;
+ float dk_plane=0, dk_point1=0;
+ float icalctop, icalcbot, n_mag;
+ float mag_iv, x_m,y_m,z_m;
+ float damping, perm_thresh;
+ float perm_val, rdamp_val;
+ int a, deflected=0, deflected_now=0;
+ float t,t2, min_t;
+ float mat[3][3], obloc[3] = {0};
+ int cur_frame;
+ float time_before, time_after;
+ float force_mag_norm;
+ int d_object=0, d_face=0, ds_object=0, ds_face=0;
+
+ first_dist = 200000;
+ min_t = 200000;
+
+ /* The first part of the code, finding the first intersected face*/
+ base= G.scene->base.first;
+ while (base) {
+ /*Only proceed for mesh object in same layer */
+ if(base->object->type==OB_MESH && (base->lay & par_layer)) {
+ ob= base->object;
+ /* only with deflecting set */
+ if(ob->pd && ob->pd->deflect) {
+ def_mesh= ob->data;
+
+ d_object = d_object + 1;
+
+ d_face = d_face + 1;
+ mface= def_mesh->mface;
+ a = def_mesh->totface;
+
+
+ if(ob->parent==NULL && ob->ipo==NULL) { // static
+ if(ob->sumohandle==NULL) cache_object_vertices(ob);
+ vcache= ob->sumohandle;
+ }
+ else {
+ /*Find out where the object is at this time*/
+ cur_frame = G.scene->r.cfra;
+ G.scene->r.cfra = (int)cur_time;
+ where_is_object_time(ob, cur_time);
+ G.scene->r.cfra = cur_frame;
+
+ /*Pass the values from ob->obmat to mat*/
+ /*and the location values to obloc */
+ Mat3CpyMat4(mat,ob->obmat);
+ obloc[0] = ob->obmat[3][0];
+ obloc[1] = ob->obmat[3][1];
+ obloc[2] = ob->obmat[3][2];
+ vcache= NULL;
+
+ }
+
+ while (a--) {
+
+ if(vcache) {
+ v1= vcache+ 3*(mface->v1);
+ VECCOPY(nv1, v1);
+ v1= vcache+ 3*(mface->v2);
+ VECCOPY(nv2, v1);
+ v1= vcache+ 3*(mface->v3);
+ VECCOPY(nv3, v1);
+ v1= vcache+ 3*(mface->v4);
+ VECCOPY(nv4, v1);
+ }
+ else {
+ /* Calculate the global co-ordinates of the vertices*/
+ v1= (def_mesh->mvert+(mface->v1))->co;
+ v2= (def_mesh->mvert+(mface->v2))->co;
+ v3= (def_mesh->mvert+(mface->v3))->co;
+ v4= (def_mesh->mvert+(mface->v4))->co;
+
+ VECCOPY(nv1, v1);
+ VECCOPY(nv2, v2);
+ VECCOPY(nv3, v3);
+ VECCOPY(nv4, v4);
+
+ /*Apply the objects deformation matrix*/
+ Mat3MulVecfl(mat, nv1);
+ Mat3MulVecfl(mat, nv2);
+ Mat3MulVecfl(mat, nv3);
+ Mat3MulVecfl(mat, nv4);
+
+ VECADD(nv1, nv1, obloc);
+ VECADD(nv2, nv2, obloc);
+ VECADD(nv3, nv3, obloc);
+ VECADD(nv4, nv4, obloc);
+ }
+
+ deflected_now = 0;
+
+
+
+// t= 0.5; // this is labda of line, can use it optimize quad intersection
+// sorry but no .. see below (BM)
+ if( LineIntersectsTriangle(opco, npco, nv1, nv2, nv3, &t) ) {
+ if (t < min_t) {
+ deflected = 1;
+ deflected_now = 1;
+ }
+ }
+// else if (mface->v4 && (t>=0.0 && t<=1.0)) {
+// no, you can't skip testing the other triangle
+// it might give a smaller t on (close to) the edge .. this is numerics not esoteric maths :)
+// note: the 2 triangles don't need to share a plane ! (BM)
+ if (mface->v4) {
+ if( LineIntersectsTriangle(opco, npco, nv1, nv3, nv4, &t2) ) {
+ if (t2 < min_t) {
+ deflected = 1;
+ deflected_now = 2;
+ }
+ }
+ }
+
+ if ((deflected_now > 0) && ((t < min_t) ||(t2 < min_t))) {
+ min_t = t;
+ ds_object = d_object;
+ ds_face = d_face;
+ deflection_object = ob;
+ deflection_face = mface;
+ if (deflected_now==1) {
+ min_t = t;
+ VECCOPY(dv1, nv1);
+ VECCOPY(dv2, nv2);
+ VECCOPY(dv3, nv3);
+ }
+ else {
+ min_t = t2;
+ VECCOPY(dv1, nv1);
+ VECCOPY(dv2, nv3);
+ VECCOPY(dv3, nv4);
+ }
+ }
+ mface++;
+ }
+ }
+ }
+ base = base->next;
+ }
+
+
+ /* Here's the point to do the permeability calculation */
+ /* Set deflected to 0 if a random number is below the value */
+ /* Get the permeability IPO here*/
+ if (deflected) {
+
+ if (has_ipo_code(deflection_object->ipo, OB_PD_PERM))
+ perm_val = IPO_GetFloatValue(deflection_object->ipo, OB_PD_PERM, cur_time);
+ else
+ perm_val = deflection_object->pd->pdef_perm;
+
+ perm_thresh = rng_getFloat(rng) - perm_val;
+ if (perm_thresh < 0 ) {
+ deflected = 0;
+ }
+ }
+
+ /* Now for the second part of the deflection code - work out the new speed */
+ /* and position of the particle if a collision occurred */
+ if (deflected) {
+ VECSUB(edge1, dv1, dv2);
+ VECSUB(edge2, dv3, dv2);
+ Crossf(d_nvect, edge2, edge1);
+ n_mag = Normalize(d_nvect);
+ dk_plane = INPR(d_nvect, nv1);
+ dk_point1 = INPR(d_nvect,opco);
+
+ VECSUB(d_intersect_vect, npco, opco);
+
+ d_intersect_co[0] = opco[0] + (min_t * (npco[0] - opco[0]));
+ d_intersect_co[1] = opco[1] + (min_t * (npco[1] - opco[1]));
+ d_intersect_co[2] = opco[2] + (min_t * (npco[2] - opco[2]));
+
+ d_i_co_above[0] = (d_intersect_co[0] + (0.001f * d_nvect[0]));
+ d_i_co_above[1] = (d_intersect_co[1] + (0.001f * d_nvect[1]));
+ d_i_co_above[2] = (d_intersect_co[2] + (0.001f * d_nvect[2]));
+ mag_iv = Normalize(d_intersect_vect);
+ VECCOPY(npco, d_intersect_co);
+
+ VECSUB(vect_to_int, opco, d_intersect_co);
+ first_dist = Normalize(vect_to_int);
+
+ /* Work out the lengths of time before and after collision*/
+ time_before = (life*(first_dist / (mag_iv)));
+ time_after = (life*((mag_iv - first_dist) / (mag_iv)));
+
+ /* We have to recalculate what the speed would have been at the */
+ /* point of collision, not the key frame time */
+ npno[0]= opno[0] + time_before*force[0];
+ npno[1]= opno[1] + time_before*force[1];
+ npno[2]= opno[2] + time_before*force[2];
+
+
+ /* Reflect the speed vector in the face */
+ x_m = (2 * npno[0] * d_nvect[0]);
+ y_m = (2 * npno[1] * d_nvect[1]);
+ z_m = (2 * npno[2] * d_nvect[2]);
+ refl_vel[0] = npno[0] - (d_nvect[0] * (x_m + y_m + z_m));
+ refl_vel[1] = npno[1] - (d_nvect[1] * (x_m + y_m + z_m));
+ refl_vel[2] = npno[2] - (d_nvect[2] * (x_m + y_m + z_m));
+
+ /*A random variation in the damping factor........ */
+ /*Get the IPO values for damping here*/
+
+ if (has_ipo_code(deflection_object->ipo, OB_PD_SDAMP))
+ damping = IPO_GetFloatValue(deflection_object->ipo, OB_PD_SDAMP, cur_time);
+ else
+ damping = deflection_object->pd->pdef_damp;
+
+ if (has_ipo_code(deflection_object->ipo, OB_PD_RDAMP))
+ rdamp_val = IPO_GetFloatValue(deflection_object->ipo, OB_PD_RDAMP, cur_time);
+ else
+ rdamp_val = deflection_object->pd->pdef_rdamp;
+
+ damping = damping + ((1.0f - damping) * rng_getFloat(rng) *rdamp_val);
+ damping = damping * damping;
+ ref_plane_mag = INPR(refl_vel,d_nvect);
+
+ if (damping > 0.999) damping = 0.999f;
+
+ /* Now add in the damping force - only damp in the direction of */
+ /* the faces normal vector */
+ npno[0] = (refl_vel[0] - (d_nvect[0] * ref_plane_mag * damping));
+ npno[1] = (refl_vel[1] - (d_nvect[1] * ref_plane_mag * damping));
+ npno[2] = (refl_vel[2] - (d_nvect[2] * ref_plane_mag * damping));
+
+ /* Now reset opno */
+ VECCOPY(opno,npno);
+ VECCOPY(forcec, force);
+
+ /* If the particle has bounced more than four times on the same */
+ /* face within this cycle (depth > 4, same face > 4 ) */
+ /* Then set the force to be only that component of the force */
+ /* in the same direction as the face normal */
+ /* i.e. subtract the component of the force in the direction */
+ /* of the face normal from the actual force */
+ if ((ds_object == *last_object) && (ds_face == *last_face)) {
+ /* Increment same_face */
+ *same_face = *same_face + 1;
+ if ((*same_face > 3) && (def_depth > 3)) {
+ force_mag_norm = INPR(forcec, d_nvect);
+ forcec[0] = forcec[0] - (d_nvect[0] * force_mag_norm);
+ forcec[1] = forcec[1] - (d_nvect[1] * force_mag_norm);
+ forcec[2] = forcec[2] - (d_nvect[2] * force_mag_norm);
+ }
+ }
+ else *same_face = 1;
+
+ *last_object = ds_object;
+ *last_face = ds_face;
+
+ /* We have the particles speed at the point of collision */
+ /* Now we want the particles speed at the current key frame */
+
+ npno[0]= npno[0] + time_after*forcec[0];
+ npno[1]= npno[1] + time_after*forcec[1];
+ npno[2]= npno[2] + time_after*forcec[2];
+
+ /* Now we have to recalculate pa->co for the remainder*/
+ /* of the time since the intersect*/
+ npco[0]= npco[0] + time_after*npno[0];
+ npco[1]= npco[1] + time_after*npno[1];
+ npco[2]= npco[2] + time_after*npno[2];
+
+ /* And set the old co-ordinates back to the point just above the intersection */
+ VECCOPY(opco, d_i_co_above);
+
+ /* Finally update the time */
+ life = time_after;
+ cur_time += time_before;
+
+ /* The particle may have fallen through the face again by now!!*/
+ /* So check if the particle has changed sides of the plane compared*/
+ /* the co-ordinates at the last keyframe*/
+ /* But only do this as a last resort, if we've got to the end of the */
+ /* number of collisions allowed */
+ if (def_depth==9) {
+ k_point3 = INPR(d_nvect,npco);
+ if (((dk_plane > k_point3) && (dk_plane < dk_point1))||((dk_plane < k_point3) && (dk_plane > dk_point1))) {
+
+ /* Yup, the pesky particle may have fallen through a hole!!! */
+ /* So we'll cheat a bit and move the particle along the normal vector */
+ /* until it's just the other side of the plane */
+ icalctop = (dk_plane - d_nvect[0]*npco[0] - d_nvect[1]*npco[1] - d_nvect[2]*npco[2]);
+ icalcbot = (d_nvect[0]*d_nvect[0] + d_nvect[1]*d_nvect[1] + d_nvect[2]*d_nvect[2]);
+ dist_to_plane = icalctop / icalcbot;
+
+ /* Now just increase the distance a little to place */
+ /* the point the other side of the plane */
+ dist_to_plane *= 1.1f;
+ npco[0]= npco[0] + (dist_to_plane * d_nvect[0]);
+ npco[1]= npco[1] + (dist_to_plane * d_nvect[1]);
+ npco[2]= npco[2] + (dist_to_plane * d_nvect[2]);
+
+ }
+ }
+ }
+ return deflected;
+}
+
+/*
+ rng= random number generator
+ ob = object that spawns the particles
+ depth = for fireworks
+ nr = index nr of current particle
+ paf = the particle system
+ part = current particle
+ force = force vector
+ deform = flag to indicate lattice deform
+ */
+static void make_particle_keys(RNG *rng, Object *ob, int depth, int nr, PartEff *paf, Particle *part, float *force, int deform, MTex *mtex, ListBase *effectorbase)
+{
+ Particle *pa, *opa = NULL;
+ float damp, deltalife, life;
+ float cur_time, maxspeed= paf->maxlen/(float)paf->totkey;
+ float opco[3], opno[3], npco[3], npno[3], new_force[3], new_speed[3];
+ int b, rt1, rt2, deflected, deflection, finish_defs, def_count;
+ int last_ob, last_fc, same_fc;
+
+ damp= 1.0f-paf->damp;
+ pa= part;
+
+ /* start speed: random */
+ if(paf->randfac!=0.0) {
+ pa->no[0]+= paf->randfac*(rng_getFloat(rng) - 0.5f);
+ pa->no[1]+= paf->randfac*(rng_getFloat(rng) - 0.5f);
+ pa->no[2]+= paf->randfac*(rng_getFloat(rng) - 0.5f);
+ }
+
+ /* start speed: texture */
+ if(mtex && paf->texfac!=0.0) {
+ particle_tex(mtex, paf, pa->co, pa->no);
+ }
+
+ /* effectors here? */
+ if(effectorbase)
+ precalc_effectors(ob, paf, pa, effectorbase);
+
+ if(paf->totkey>1) deltalife= pa->lifetime/(paf->totkey-1);
+ else deltalife= pa->lifetime;
+
+ /* longer lifetime results in longer distance covered */
+ VecMulf(pa->no, deltalife);
+
+ opa= pa;
+ pa++;
+
+ for(b=1; b<paf->totkey; b++) {
+
+ /* new time */
+ pa->time= opa->time+deltalife;
+ cur_time = pa->time;
+
+ /* set initial variables */
+ VECCOPY(opco, opa->co);
+ VECCOPY(new_force, force);
+ VECCOPY(new_speed, opa->no);
+ VecMulf(new_speed, 1.0f/deltalife);
+ //new_speed[0] = new_speed[1] = new_speed[2] = 0.0f;
+
+ /* handle differences between static (local coords, fixed frame) and dynamic */
+ if(effectorbase) {
+ float loc_time= ((float)b)/(float)(paf->totkey-1);
+
+ if(paf->flag & PAF_STATIC) {
+ float opco1[3], new_force1[3];
+
+ /* move co and force to global coords */
+ VECCOPY(opco1, opco);
+ Mat4MulVecfl(ob->obmat, opco1);
+ VECCOPY(new_force1, new_force);
+ Mat4Mul3Vecfl(ob->obmat, new_force1);
+ Mat4Mul3Vecfl(ob->obmat, new_speed);
+
+ cur_time = G.scene->r.cfra;
+
+ /* force fields */
+ pdDoEffectors(effectorbase, opco1, new_force1, new_speed, cur_time, loc_time, 0);
+
+ /* move co, force and newspeed back to local */
+ VECCOPY(opco, opco1);
+ Mat4MulVecfl(ob->imat, opco);
+ VECCOPY(new_force, new_force1);
+ Mat4Mul3Vecfl(ob->imat, new_force);
+ Mat4Mul3Vecfl(ob->imat, new_speed);
+ }
+ else {
+ /* force fields */
+ pdDoEffectors(effectorbase, opco, new_force, new_speed, cur_time, loc_time, 0);
+ }
+ }
+
+ /* new speed */
+ pa->no[0]= deltalife * (new_speed[0] + new_force[0]);
+ pa->no[1]= deltalife * (new_speed[1] + new_force[1]);
+ pa->no[2]= deltalife * (new_speed[2] + new_force[2]);
+
+ /* speed limitor */
+ if((paf->flag & PAF_STATIC) && maxspeed!=0.0f) {
+ float len= VecLength(pa->no);
+ if(len > maxspeed)
+ VecMulf(pa->no, maxspeed/len);
+ }
+
+ /* new location */
+ pa->co[0]= opa->co[0] + pa->no[0];
+ pa->co[1]= opa->co[1] + pa->no[1];
+ pa->co[2]= opa->co[2] + pa->no[2];
+
+ /* Particle deflection code */
+ if((paf->flag & PAF_STATIC)==0) {
+ deflection = 0;
+ finish_defs = 1;
+ def_count = 0;
+
+ VECCOPY(opno, opa->no);
+ VECCOPY(npco, pa->co);
+ VECCOPY(npno, pa->no);
+
+ life = deltalife;
+ cur_time -= deltalife;
+
+ last_ob = -1;
+ last_fc = -1;
+ same_fc = 0;
+
+ /* First call the particle deflection check for the particle moving */
+ /* between the old co-ordinates and the new co-ordinates */
+ /* If a deflection occurs, call the code again, this time between the */
+ /* intersection point and the updated new co-ordinates */
+ /* Bail out if we've done the calculation 10 times - this seems ok */
+ /* for most scenes I've tested */
+ while (finish_defs) {
+ deflected = pdDoDeflection(rng, opco, npco, opno, npno, life, new_force,
+ def_count, cur_time, ob->lay,
+ &last_ob, &last_fc, &same_fc);
+ if (deflected) {
+ def_count = def_count + 1;
+ deflection = 1;
+ if (def_count==10) finish_defs = 0;
+ }
+ else {
+ finish_defs = 0;
+ }
+ }
+
+ /* Only update the particle positions and speed if we had a deflection */
+ if (deflection) {
+ pa->co[0] = npco[0];
+ pa->co[1] = npco[1];
+ pa->co[2] = npco[2];
+ pa->no[0] = npno[0];
+ pa->no[1] = npno[1];
+ pa->no[2] = npno[2];
+ }
+ }
+
+ /* speed: texture */
+ if(mtex && paf->texfac!=0.0) {
+ particle_tex(mtex, paf, pa->co, pa->no);
+ }
+ if(damp!=1.0) {
+ pa->no[0]*= damp;
+ pa->no[1]*= damp;
+ pa->no[2]*= damp;
+ }
+
+ opa= pa;
+ pa++;
+ /* opa is used later on too! */
+ }
+
+ if(deform) {
+ /* deform all keys */
+ pa= part;
+ b= paf->totkey;
+ while(b--) {
+ calc_latt_deform(pa->co, 1.0f);
+ pa++;
+ }
+ }
+
+ /* the big multiplication */
+ if(depth<PAF_MAXMULT && paf->mult[depth]!=0.0) {
+
+ /* new 'child' emerges from an average 'mult' part from
+ the particles */
+ damp = (float)nr;
+ rt1= (int)(damp*paf->mult[depth]);
+ rt2= (int)((damp+1.0)*paf->mult[depth]);
+ if(rt1!=rt2) {
+
+ for(b=0; b<paf->child[depth]; b++) {
+ pa= new_particle(paf);
+ *pa= *opa;
+ pa->lifetime= paf->life[depth];
+ if(paf->randlife!=0.0) {
+ pa->lifetime*= 1.0f + paf->randlife*(rng_getFloat(rng) - 0.5f);
+ }
+ pa->mat_nr= paf->mat[depth];
+
+ make_particle_keys(rng, ob, depth+1, b, paf, pa, force, deform, mtex, effectorbase);
+ }
+ }
+ }
+}
+
+static void init_mv_jit(float *jit, int num, int seed2)
+{
+ RNG *rng;
+ float *jit2, x, rad1, rad2, rad3;
+ int i, num2;
+
+ if(num==0) return;
+
+ rad1= (float)(1.0/sqrt((float)num));
+ rad2= (float)(1.0/((float)num));
+ rad3= (float)sqrt((float)num)/((float)num);
+
+ rng = rng_new(31415926 + num + seed2);
+ x= 0;
+ num2 = 2 * num;
+ for(i=0; i<num2; i+=2) {
+
+ jit[i]= x + rad1*(0.5f - rng_getFloat(rng));
+ jit[i+1]= i/(2.0f*num) + rad1*(0.5f - rng_getFloat(rng));
+
+ jit[i]-= (float)floor(jit[i]);
+ jit[i+1]-= (float)floor(jit[i+1]);
+
+ x+= rad3;
+ x -= (float)floor(x);
+ }
+
+ jit2= MEM_mallocN(12 + 2*sizeof(float)*num, "initjit");
+
+ for (i=0 ; i<4 ; i++) {
+ BLI_jitterate1(jit, jit2, num, rad1);
+ BLI_jitterate1(jit, jit2, num, rad1);
+ BLI_jitterate2(jit, jit2, num, rad2);
+ }
+ MEM_freeN(jit2);
+ rng_free(rng);
+}
+
+#define JIT_RAND 32
+
+/* for a position within a face, tot is total amount of faces */
+static void give_mesh_particle_coord(PartEff *paf, VeNoCo *noco, MFace *mface, int partnr, int subnr, float *co, float *no)
+{
+ static float *jit= NULL;
+ static float *trands= NULL;
+ static int jitlevel= 1;
+ float *v1, *v2, *v3, *v4;
+ float u, v;
+ float *n1, *n2, *n3, *n4;
+
+ /* free signal */
+ if(paf==NULL) {
+ if(jit) MEM_freeN(jit);
+ jit= NULL;
+ if(trands) MEM_freeN(trands);
+ trands= NULL;
+ return;
+ }
+
+ /* first time initialize jitter or trand, partnr then is total amount of particles, subnr total amount of faces */
+ if(trands==NULL && jit==NULL) {
+ RNG *rng = rng_new(31415926 + paf->seed);
+ int i, tot;
+
+ if(paf->flag & PAF_TRAND)
+ tot= partnr;
+ else
+ tot= JIT_RAND; /* arbitrary... allows JIT_RAND times more particles in a face for jittered distro */
+
+ trands= MEM_callocN(2+2*tot*sizeof(float), "trands");
+ for(i=0; i<tot; i++) {
+ trands[2*i]= rng_getFloat(rng);
+ trands[2*i+1]= rng_getFloat(rng);
+ }
+ rng_free(rng);
+
+ if((paf->flag & PAF_TRAND)==0) {
+ jitlevel= paf->userjit;
+
+ if(jitlevel == 0) {
+ jitlevel= partnr/subnr;
+ if(paf->flag & PAF_EDISTR) jitlevel*= 2; /* looks better in general, not very scietific */
+ if(jitlevel<3) jitlevel= 3;
+ if(jitlevel>100) jitlevel= 100;
+ }
+
+ jit= MEM_callocN(2+ jitlevel*2*sizeof(float), "jit");
+ init_mv_jit(jit, jitlevel, paf->seed);
+ BLI_array_randomize(jit, 2*sizeof(float), jitlevel, paf->seed); /* for custom jit or even distribution */
+ }
+ return;
+ }
+
+ if(paf->flag & PAF_TRAND) {
+ u= trands[2*partnr];
+ v= trands[2*partnr+1];
+ }
+ else {
+ /* jittered distribution gets fixed random offset */
+ if(subnr>=jitlevel) {
+ int jitrand= (subnr/jitlevel) % JIT_RAND;
+
+ subnr %= jitlevel;
+ u= jit[2*subnr] + trands[2*jitrand];
+ v= jit[2*subnr+1] + trands[2*jitrand+1];
+ if(u > 1.0f) u-= 1.0f;
+ if(v > 1.0f) v-= 1.0f;
+ }
+ else {
+ u= jit[2*subnr];
+ v= jit[2*subnr+1];
+ }
+ }
+
+ v1= (noco+(mface->v1))->co;
+ v2= (noco+(mface->v2))->co;
+ v3= (noco+(mface->v3))->co;
+ n1= (noco+(mface->v1))->no;
+ n2= (noco+(mface->v2))->no;
+ n3= (noco+(mface->v3))->no;
+
+ if(mface->v4) {
+ float uv= u*v;
+ float muv= (1.0f-u)*(v);
+ float umv= (u)*(1.0f-v);
+ float mumv= (1.0f-u)*(1.0f-v);
+
+ v4= (noco+(mface->v4))->co;
+ n4= (noco+(mface->v4))->no;
+
+ co[0]= mumv*v1[0] + muv*v2[0] + uv*v3[0] + umv*v4[0];
+ co[1]= mumv*v1[1] + muv*v2[1] + uv*v3[1] + umv*v4[1];
+ co[2]= mumv*v1[2] + muv*v2[2] + uv*v3[2] + umv*v4[2];
+
+ no[0]= mumv*n1[0] + muv*n2[0] + uv*n3[0] + umv*n4[0];
+ no[1]= mumv*n1[1] + muv*n2[1] + uv*n3[1] + umv*n4[1];
+ no[2]= mumv*n1[2] + muv*n2[2] + uv*n3[2] + umv*n4[2];
+ }
+ else {
+ /* mirror triangle uv coordinates when on other side */
+ if(u + v > 1.0f) {
+ u= 1.0f-u;
+ v= 1.0f-v;
+ }
+ co[0]= v1[0] + u*(v3[0]-v1[0]) + v*(v2[0]-v1[0]);
+ co[1]= v1[1] + u*(v3[1]-v1[1]) + v*(v2[1]-v1[1]);
+ co[2]= v1[2] + u*(v3[2]-v1[2]) + v*(v2[2]-v1[2]);
+
+ no[0]= n1[0] + u*(n3[0]-n1[0]) + v*(n2[0]-n1[0]);
+ no[1]= n1[1] + u*(n3[1]-n1[1]) + v*(n2[1]-n1[1]);
+ no[2]= n1[2] + u*(n3[2]-n1[2]) + v*(n2[2]-n1[2]);
+ }
+}
+
+
+/* Gets a MDeformVert's weight in group (0 if not in group) */
+/* note; this call could be in mesh.c or deform.c, but OK... it's in armature.c too! (ton) */
+static float vert_weight(MDeformVert *dvert, int group)
+{
+ MDeformWeight *dw;
+ int i;
+
+ if(dvert) {
+ dw= dvert->dw;
+ for(i= dvert->totweight; i>0; i--, dw++) {
+ if(dw->def_nr == group) return dw->weight;
+ if(i==1) break; /*otherwise dw will point to somewhere it shouldn't*/
+ }
+ }
+ return 0.0;
+}
+
+/* Gets a faces average weight in a group, helper for below, face and weights are always set */
+static float face_weight(MFace *face, float *weights)
+{
+ float tweight;
+
+ tweight = weights[face->v1] + weights[face->v2] + weights[face->v3];
+
+ if(face->v4) {
+ tweight += weights[face->v4];
+ tweight /= 4.0;
+ }
+ else {
+ tweight /= 3.0;
+ }
+
+ return tweight;
+}
+
+/* helper function for build_particle_system() */
+static void make_weight_tables(PartEff *paf, Mesh *me, int totpart, VeNoCo *vertlist, int totvert, MFace *facelist, int totface, float **vweights, float **fweights)
+{
+ MFace *mface;
+ float *foweights=NULL, *voweights=NULL;
+ float totvweight=0.0f, totfweight=0.0f;
+ int a;
+
+ if((paf->flag & PAF_FACE)==0) totface= 0;
+
+ /* collect emitting vertices & faces if vert groups used */
+ if(paf->vertgroup && me->dvert) {
+
+ /* allocate weights array for all vertices, also for lookup of faces later on. note it's a malloc */
+ *vweights= voweights= MEM_mallocN( totvert*sizeof(float), "pafvoweights" );
+ totvweight= 0.0f;
+ for(a=0; a<totvert; a++) {
+ voweights[a]= vert_weight(me->dvert+a, paf->vertgroup-1);
+ totvweight+= voweights[a];
+ }
+
+ if(totface) {
+ /* allocate weights array for faces, note it's a malloc */
+ *fweights= foweights= MEM_mallocN(totface*sizeof(float), "paffoweights" );
+ for(a=0, mface=facelist; a<totface; a++, mface++) {
+ foweights[a] = face_weight(mface, voweights);
+ }
+ }
+ }
+
+ /* make weights for faces or for even area distribution */
+ if(totface && (paf->flag & PAF_EDISTR)) {
+ float maxfarea= 0.0f, curfarea;
+
+ /* two cases for area distro, second case we already have group weights */
+ if(foweights==NULL) {
+ /* allocate weights array for faces, note it's a malloc */
+ *fweights= foweights= MEM_mallocN(totface*sizeof(float), "paffoweights" );
+
+ for(a=0, mface=facelist; a<totface; a++, mface++) {
+ if (mface->v4)
+ curfarea= AreaQ3Dfl(vertlist[mface->v1].co, vertlist[mface->v2].co, vertlist[mface->v3].co, vertlist[mface->v4].co);
+ else
+ curfarea= AreaT3Dfl(vertlist[mface->v1].co, vertlist[mface->v2].co, vertlist[mface->v3].co);
+ if(curfarea>maxfarea)
+ maxfarea = curfarea;
+ foweights[a]= curfarea;
+ }
+ }
+ else {
+ for(a=0, mface=facelist; a<totface; a++, mface++) {
+ if(foweights[a]!=0.0f) {
+ if (mface->v4)
+ curfarea= AreaQ3Dfl(vertlist[mface->v1].co, vertlist[mface->v2].co, vertlist[mface->v3].co, vertlist[mface->v4].co);
+ else
+ curfarea= AreaT3Dfl(vertlist[mface->v1].co, vertlist[mface->v2].co, vertlist[mface->v3].co);
+ if(curfarea>maxfarea)
+ maxfarea = curfarea;
+ foweights[a]*= curfarea;
+ }
+ }
+ }
+
+ /* normalize weights for max face area, calculate tot */
+ if(maxfarea!=0.0f) {
+ maxfarea= 1.0f/maxfarea;
+ for(a=0; a< totface; a++) {
+ if(foweights[a]!=0.0) {
+ foweights[a] *= maxfarea;
+ totfweight+= foweights[a];
+ }
+ }
+ }
+ }
+ else if(foweights) {
+ /* only add totfweight value */
+ for(a=0; a< totface; a++) {
+ if(foweights[a]!=0.0) {
+ totfweight+= foweights[a];
+ }
+ }
+ }
+
+ /* if weight arrays, we turn these arrays into the amount of particles */
+ if(totvert && voweights) {
+ float mult= (float)totpart/totvweight;
+
+ for(a=0; a< totvert; a++) {
+ if(voweights[a]!=0.0)
+ voweights[a] *= mult;
+ }
+ }
+
+ if(totface && foweights) {
+ float mult= (float)totpart/totfweight;
+
+ for(a=0; a< totface; a++) {
+ if(foweights[a]!=0.0)
+ foweights[a] *= mult;
+ }
+ }
+}
+
+/* helper function for build_particle_system() */
+static void make_length_tables(PartEff *paf, Mesh *me, int totvert, MFace *facelist, int totface, float **vlengths, float **flengths)
+{
+ MFace *mface;
+ float *folengths=NULL, *volengths=NULL;
+ int a;
+
+ if((paf->flag & PAF_FACE)==0) totface= 0;
+
+ /* collect emitting vertices & faces if vert groups used */
+ if(paf->vertgroup_v && me->dvert) {
+
+ /* allocate lengths array for all vertices, also for lookup of faces later on. note it's a malloc */
+ *vlengths= volengths= MEM_mallocN( totvert*sizeof(float), "pafvolengths" );
+ for(a=0; a<totvert; a++) {
+ volengths[a]= vert_weight(me->dvert+a, paf->vertgroup_v-1);
+ }
+
+ if(totface) {
+ /* allocate lengths array for faces, note it's a malloc */
+ *flengths= folengths= MEM_mallocN(totface*sizeof(float), "paffolengths" );
+ for(a=0, mface=facelist; a<totface; a++, mface++) {
+ folengths[a] = face_weight(mface, volengths);
+ }
+ }
+ }
+}
+
+
+/* for paf start to end, store all matrices for objects */
+typedef struct pMatrixCache {
+ float obmat[4][4];
+ float imat[3][3];
+} pMatrixCache;
+
+
+/* WARN: this function stores data in ob->id.idnew! */
+/* error: this function changes ob->recalc of other objects... */
+static pMatrixCache *cache_object_matrices(Object *ob, int start, int end)
+{
+ pMatrixCache *mcache, *mc;
+ Group *group= NULL;
+ Object *obcopy;
+ Base *base;
+ float framelenold, cfrao, sfo;
+
+ /* object can be linked in group... stupid exception */
+ if(NULL==object_in_scene(ob, G.scene))
+ group= find_group(ob);
+
+ mcache= mc= MEM_mallocN( (end-start+1)*sizeof(pMatrixCache), "ob matrix cache");
+
+ framelenold= G.scene->r.framelen;
+ G.scene->r.framelen= 1.0f;
+ cfrao= G.scene->r.cfra;
+ sfo= ob->sf;
+ ob->sf= 0.0f;
+
+ /* clear storage, copy recalc tag (bad loop) */
+ for(obcopy= G.main->object.first; obcopy; obcopy= obcopy->id.next) {
+ obcopy->id.newid= NULL;
+ obcopy->recalco= obcopy->recalc;
+ obcopy->recalc= 0;
+ }
+
+ /* all objects get tagged recalc that influence this object (does group too) */
+ /* note that recalco has the real recalc tags, set by callers of this function */
+ ob->recalc |= OB_RECALC_OB; /* make sure a recalc gets flushed */
+ DAG_object_update_flags(G.scene, ob, -1);
+
+ for(G.scene->r.cfra= start; G.scene->r.cfra<=end; G.scene->r.cfra++, mc++) {
+
+ if(group) {
+ GroupObject *go;
+
+ for(go= group->gobject.first; go; go= go->next) {
+ if(go->ob->recalc) {
+ where_is_object(go->ob);
+
+ do_ob_key(go->ob);
+ if(go->ob->type==OB_ARMATURE) {
+ do_all_pose_actions(go->ob); // only does this object actions
+ where_is_pose(go->ob);
+ }
+ }
+ }
+ }
+ else {
+ for(base= G.scene->base.first; base; base= base->next) {
+ if(base->object->recalc) {
+ if(base->object->id.newid==NULL)
+ base->object->id.newid= MEM_dupallocN(base->object);
+
+ where_is_object(base->object);
+
+ do_ob_key(base->object);
+ if(base->object->type==OB_ARMATURE) {
+ do_all_pose_actions(base->object); // only does this object actions
+ where_is_pose(base->object);
+ }
+ }
+ }
+ }
+ Mat4CpyMat4(mc->obmat, ob->obmat);
+ Mat4Invert(ob->imat, ob->obmat);
+ Mat3CpyMat4(mc->imat, ob->imat);
+ Mat3Transp(mc->imat);
+ }
+
+ /* restore */
+ G.scene->r.cfra= cfrao;
+ G.scene->r.framelen= framelenold;
+ ob->sf= sfo;
+
+ if(group) {
+ GroupObject *go;
+
+ for(go= group->gobject.first; go; go= go->next) {
+ if(go->ob->recalc) {
+ where_is_object(go->ob);
+
+ do_ob_key(go->ob);
+ if(go->ob->type==OB_ARMATURE) {
+ do_all_pose_actions(go->ob); // only does this object actions
+ where_is_pose(go->ob);
+ }
+ }
+ }
+ }
+ else {
+ for(base= G.scene->base.first; base; base= base->next) {
+ if(base->object->recalc) {
+
+ if(base->object->id.newid) {
+ obcopy= (Object *)base->object->id.newid;
+ *(base->object) = *(obcopy);
+ MEM_freeN(obcopy);
+ base->object->id.newid= NULL;
+ }
+
+ do_ob_key(base->object);
+ if(base->object->type==OB_ARMATURE) {
+ do_all_pose_actions(base->object); // only does this object actions
+ where_is_pose(base->object);
+ }
+ }
+ }
+ }
+
+ /* copy recalc tag (bad loop) */
+ for(obcopy= G.main->object.first; obcopy; obcopy= obcopy->id.next)
+ obcopy->recalc= obcopy->recalco;
+
+ return mcache;
+}
+
+/* for fluidsim win32 debug messages */
+#if defined(WIN32) && (!(defined snprintf))
+#define snprintf _snprintf
+#endif
+
+/* main particle building function
+ one day particles should become dynamic (realtime) with the current method as a 'bake' (ton) */
+void build_particle_system(Object *ob)
+{
+ RNG *rng;
+ PartEff *paf;
+ Particle *pa;
+ Mesh *me;
+ Base *base;
+ MTex *mtexmove=0, *mtextime=0;
+ Material *ma;
+ MFace *facelist= NULL;
+ pMatrixCache *mcache=NULL, *mcnow, *mcprev;
+ ListBase *effectorbase;
+ VeNoCo *vertexcosnos;
+ double startseconds= PIL_check_seconds_timer();
+ float ftime, dtime, force[3], vec[3], fac, co[3], no[3];
+ float *voweights= NULL, *foweights= NULL, maxw=1.0f;
+ float *volengths= NULL, *folengths= NULL;
+ int deform=0, a, totpart, paf_sta, paf_end;
+ int waitcursor_set= 0, totvert, totface, curface, curvert;
+#ifndef DISABLE_ELBEEM
+ int readMask, activeParts, fileParts;
+#endif
+
+ /* return conditions */
+ if(ob->type!=OB_MESH) return;
+ me= ob->data;
+
+ paf= give_parteff(ob);
+ if(paf==NULL) return;
+
+ if(G.rendering==0 && paf->disp==0) return;
+
+ if(paf->keys) MEM_freeN(paf->keys); /* free as early as possible, for returns */
+ paf->keys= NULL;
+
+ //printf("build particles\n");
+
+ /* fluid sim particle import handling, actual loading of particles from file */
+ #ifndef DISABLE_ELBEEM
+ if( (1) && (ob->fluidsimFlag & OB_FLUIDSIM_ENABLE) && // broken, disabled for now!
+ (ob->fluidsimSettings) &&
+ (ob->fluidsimSettings->type == OB_FLUIDSIM_PARTICLE)) {
+ char *suffix = "fluidsurface_particles_#";
+ char *suffix2 = ".gz";
+ char filename[256];
+ char debugStrBuffer[256];
+ int curFrame = G.scene->r.cfra -1; // warning - sync with derived mesh fsmesh loading
+ int j, numFileParts;
+ gzFile gzf;
+ float vel[3];
+
+ if(ob==G.obedit) { // off...
+ paf->totpart = 0; // 1 or 0?
+ return;
+ }
+
+ // ok, start loading
+ strcpy(filename, ob->fluidsimSettings->surfdataPath);
+ strcat(filename, suffix);
+ BLI_convertstringcode(filename, G.sce, curFrame); // fixed #frame-no
+ strcat(filename, suffix2);
+
+ gzf = gzopen(filename, "rb");
+ if (!gzf) {
+ snprintf(debugStrBuffer,256,"readFsPartData::error - Unable to open file for reading '%s' \n", filename);
+ //elbeemDebugOut(debugStrBuffer);
+ paf->totpart = 0;
+ return;
+ }
+
+ gzread(gzf, &totpart, sizeof(totpart));
+ numFileParts = totpart;
+ totpart = (G.rendering)?totpart:(paf->disp*totpart)/100;
+ paf->totpart= totpart;
+ paf->totkey= 1;
+ /* initialize particles */
+ new_particle(paf);
+ ftime = 0.0; // unused...
+
+ // set up reading mask
+ readMask = ob->fluidsimSettings->typeFlags;
+ activeParts=0;
+ fileParts=0;
+
+ for(a=0; a<totpart; a++) {
+ int ptype=0;
+ short shsize=0;
+ float convertSize=0.0;
+ gzread(gzf, &ptype, sizeof( ptype ));
+ if(ptype&readMask) {
+ activeParts++;
+ pa= new_particle(paf);
+ pa->time= ftime;
+ pa->lifetime= ftime + 10000.; // add large number to make sure they are displayed, G.scene->r.efra +1.0;
+ pa->co[0] = 0.0;
+ pa->co[1] =
+ pa->co[2] = 1.0*(float)a / (float)totpart;
+ pa->no[0] = pa->no[1] = pa->no[2] = 0.0;
+ pa->mat_nr= paf->omat;
+ gzread(gzf, &convertSize, sizeof( float ));
+ // convert range of 1.0-10.0 to shorts 1000-10000)
+ shsize = (short)(convertSize*1000.0);
+ pa->rt = shsize;
+
+ for(j=0; j<3; j++) {
+ float wrf;
+ gzread(gzf, &wrf, sizeof( wrf ));
+ pa->co[j] = wrf;
+ //fprintf(stderr,"Rj%d ",j);
+ }
+ for(j=0; j<3; j++) {
+ float wrf;
+ gzread(gzf, &wrf, sizeof( wrf ));
+ vel[j] = wrf;
+ }
+ //if(a<25) fprintf(stderr,"FSPARTICLE debug set %s , a%d = %f,%f,%f , life=%f \n", filename, a, pa->co[0],pa->co[1],pa->co[2], pa->lifetime );
+ } else {
+ // skip...
+ for(j=0; j<2*3+1; j++) {
+ float wrf; gzread(gzf, &wrf, sizeof( wrf ));
+ }
+ }
+ fileParts++;
+ }
+ gzclose( gzf );
+
+ totpart = paf->totpart = activeParts;
+ snprintf(debugStrBuffer,256,"readFsPartData::done - particles:%d, active:%d, file:%d, mask:%d \n", paf->totpart,activeParts,fileParts,readMask);
+ elbeemDebugOut(debugStrBuffer);
+ return;
+ } // fluid sim particles done
+ #endif // DISABLE_ELBEEM
+
+ if(paf->end < paf->sta) return;
+
+ if( (paf->flag & PAF_OFACE) && (paf->flag & PAF_FACE)==0) return;
+
+ if(me->totvert==0) return;
+
+ if(ob==G.obedit) return;
+ totpart= (G.rendering)?paf->totpart:(paf->disp*paf->totpart)/100;
+ if(totpart==0) return;
+
+ /* No returns after this line! */
+
+ /* material */
+ ma= give_current_material(ob, paf->omat);
+ if(ma) {
+ if(paf->speedtex)
+ mtexmove= ma->mtex[paf->speedtex-1];
+ mtextime= ma->mtex[paf->timetex-1];
+ }
+
+ disable_speed_curve(1); /* check this... */
+
+ /* initialize particles */
+ new_particle(paf);
+
+ /* reset deflector cache, sumohandle is free, but its still sorta abuse... (ton) */
+ for(base= G.scene->base.first; base; base= base->next)
+ base->object->sumohandle= NULL;
+
+ /* all object positions from start to end */
+ paf_sta= (int)floor(paf->sta);
+ paf_end= (int)ceil(paf->end);
+ if((paf->flag & PAF_STATIC)==0)
+ mcache= cache_object_matrices(ob, paf_sta, paf_end);
+
+ /* mult generations? */
+ for(a=0; a<PAF_MAXMULT; a++) {
+ if(paf->mult[a]!=0.0) {
+ /* interesting formula! this way after 'x' generations the total is paf->totpart */
+ totpart= (int)(totpart / (1.0+paf->mult[a]*paf->child[a]));
+ }
+ else break;
+ }
+
+ /* for static particles, calculate system on current frame (? ton) */
+ if(ma) do_mat_ipo(ma);
+
+ /* matrix invert for static too */
+ Mat4Invert(ob->imat, ob->obmat);
+ Mat4CpyMat4(paf->imat, ob->imat); /* used for duplicators */
+
+ /* new random generator */
+ rng = rng_new(paf->seed);
+
+ /* otherwise it goes way too fast */
+ force[0]= paf->force[0]*0.05f;
+ force[1]= paf->force[1]*0.05f;
+ force[2]= paf->force[2]*0.05f;
+
+ if( paf->flag & PAF_STATIC ) deform= 0;
+ else {
+ Object *parlatt= modifiers_isDeformedByLattice(ob);
+ if(parlatt) {
+ deform= 1;
+ init_latt_deform(parlatt, 0);
+ }
+ }
+
+ /* get the effectors */
+ effectorbase= pdInitEffectors(ob, paf->group);
+
+ /* init geometry, return is 6 x float * me->totvert in size */
+ vertexcosnos= (VeNoCo *)mesh_get_mapped_verts_nors(ob);
+ facelist= me->mface;
+ totvert= me->totvert;
+ totface= me->totface;
+
+ /* if vertexweights or even distribution, it makes weight tables, also checks where it emits from */
+ make_weight_tables(paf, me, totpart, vertexcosnos, totvert, facelist, totface, &voweights, &foweights);
+
+ /* vertexweights can define lengths too */
+ make_length_tables(paf, me, totvert, facelist, totface, &volengths, &folengths);
+
+ /* now define where to emit from, if there are face weights we skip vertices */
+ if(paf->flag & PAF_OFACE) totvert= 0;
+ if((paf->flag & PAF_FACE)==0) totface= 0;
+ if(foweights) totvert= 0;
+
+ /* initialize give_mesh_particle_coord */
+ if(totface)
+ give_mesh_particle_coord(paf, vertexcosnos, facelist, totpart, totface, NULL, NULL);
+
+ /* correction for face timing when using weighted average */
+ if(totface && foweights) {
+ maxw= (paf->end-paf->sta)/foweights[0];
+ }
+ else if(totvert && voweights) {
+ maxw= (paf->end-paf->sta)/voweights[0];
+ }
+
+ /* for loop below */
+ if (paf->flag & PAF_STATIC) {
+ ftime = G.scene->r.cfra;
+ dtime= 0.0f;
+ } else {
+ ftime= paf->sta;
+ dtime= (paf->end - paf->sta)/(float)totpart;
+ }
+
+ curface= curvert= 0;
+ for(a=0; a<totpart; a++, ftime+=dtime) {
+
+ /* we set waitcursor only when a half second expired, particles now are realtime updated */
+ if(waitcursor_set==0 && (a % 256)==255) {
+ double seconds= PIL_check_seconds_timer();
+ if(seconds - startseconds > 0.5) {
+ waitcursor(1);
+ waitcursor_set= 1;
+ }
+ }
+
+ pa= new_particle(paf);
+ pa->time= ftime;
+
+ /* get coordinates from faces, only when vertices set to zero */
+ if(totvert==0 && totface) {
+ int curjit;
+
+ /* use weight table, we have to do faces in order to be able to use jitter table... */
+ if(foweights) {
+
+ if(foweights[curface] < 1.0f) {
+ float remainder= 0.0f;
+
+ while(remainder + foweights[curface] < 1.0f && curface<totface-1) {
+ remainder += foweights[curface];
+ curface++;
+ }
+ /* if this is the last face, the foweights[] can be zero, so we don't add a particle extra */
+ if(curface!=totface-1)
+ foweights[curface] += remainder;
+
+ maxw= (paf->end-paf->sta)/foweights[curface];
+ }
+
+ if(foweights[curface]==0.0f)
+ break; /* WARN skips here out of particle generating */
+ else {
+ if(foweights[curface] >= 1.0f) /* note the >= here, this because of the < 1.0f above, it otherwise will stick to 1 face forever */
+ foweights[curface] -= 1.0f;
+
+ curjit= (int) foweights[curface];
+ give_mesh_particle_coord(paf, vertexcosnos, facelist+curface, a, curjit, co, no);
+
+ /* time correction to make particles appear evenly, maxw does interframe (0-1) */
+ pa->time= paf->sta + maxw*foweights[curface];
+ }
+ }
+ else {
+ curface= a % totface;
+ curjit= a/totface;
+ give_mesh_particle_coord(paf, vertexcosnos, facelist+curface, a, curjit, co, no);
+ }
+ }
+ /* get coordinates from vertices */
+ if(totvert) {
+ /* use weight table */
+ if(voweights) {
+
+ if(voweights[curvert] < 1.0f) {
+ float remainder= 0.0f;
+
+ while(remainder + voweights[curvert] < 1.0f && curvert<totvert-1) {
+ remainder += voweights[curvert];
+ curvert++;
+ }
+ voweights[curvert] += remainder;
+ maxw= (paf->end-paf->sta)/voweights[curvert];
+ }
+
+ if(voweights[curvert]==0.0f)
+ break; /* WARN skips here out of particle generating */
+ else {
+ if(voweights[curvert] > 1.0f)
+ voweights[curvert] -= 1.0f;
+
+ /* time correction to make particles appear evenly */
+ pa->time= paf->sta + maxw*voweights[curvert];
+ }
+ }
+ else {
+ curvert= a % totvert;
+ if(a >= totvert && totface)
+ totvert= 0;
+ }
+
+ VECCOPY(co, vertexcosnos[curvert].co);
+ VECCOPY(no, vertexcosnos[curvert].no);
+ }
+
+ VECCOPY(pa->co, co);
+
+ /* dynamic options */
+ if((paf->flag & PAF_STATIC)==0) {
+ int cur;
+
+ /* particle retiming with texture */
+ if(mtextime && (paf->flag2 & PAF_TEXTIME)) {
+ float tin, tr, tg, tb, ta, orco[3];
+
+ /* calculate normalized orco */
+ orco[0] = (co[0]-me->loc[0])/me->size[0];
+ orco[1] = (co[1]-me->loc[1])/me->size[1];
+ orco[2] = (co[2]-me->loc[2])/me->size[2];
+ externtex(mtextime, orco, &tin, &tr, &tg, &tb, &ta);
+
+ if(paf->flag2neg & PAF_TEXTIME)
+ pa->time = paf->sta + (paf->end - paf->sta)*tin;
+ else
+ pa->time = paf->sta + (paf->end - paf->sta)*(1.0f-tin);
+ }
+
+ /* set ob at correct time, we use cached matrices */
+ cur= (int)floor(pa->time) + 1 ; /* + 1 has a reason: (obmat/prevobmat) otherwise comet-tails start too late */
+
+ if(cur <= paf_end) mcnow= mcache + cur - paf_sta;
+ else mcnow= mcache + paf_end - paf_sta;
+
+ if(cur > paf_sta) mcprev= mcnow-1;
+ else mcprev= mcache;
+
+ /* move to global space */
+ Mat4MulVecfl(mcnow->obmat, pa->co);
+
+ VECCOPY(vec, co);
+ Mat4MulVecfl(mcprev->obmat, vec);
+
+ /* first start speed: object */
+ VECSUB(pa->no, pa->co, vec);
+
+ VecMulf(pa->no, paf->obfac);
+
+ /* calculate the correct inter-frame */
+ fac= (pa->time- (float)floor(pa->time));
+ pa->co[0]= fac*pa->co[0] + (1.0f-fac)*vec[0];
+ pa->co[1]= fac*pa->co[1] + (1.0f-fac)*vec[1];
+ pa->co[2]= fac*pa->co[2] + (1.0f-fac)*vec[2];
+
+ /* start speed: normal */
+ if(paf->normfac!=0.0) {
+ /* imat is transpose ! */
+ VECCOPY(vec, no);
+ Mat3MulVecfl(mcnow->imat, vec);
+
+ Normalize(vec);
+ VecMulf(vec, paf->normfac);
+ VECADD(pa->no, pa->no, vec);
+ }
+ }
+ else {
+ if(paf->normfac!=0.0) {
+ VECCOPY(pa->no, no);
+ Normalize(pa->no);
+ VecMulf(pa->no, paf->normfac);
+ }
+ }
+
+ pa->lifetime= paf->lifetime;
+ if(paf->randlife!=0.0) {
+ pa->lifetime*= 1.0f + paf->randlife*(rng_getFloat(rng) - 0.5f);
+ }
+ pa->mat_nr= paf->omat;
+
+ if(folengths)
+ pa->lifetime*= folengths[curface];
+
+ make_particle_keys(rng, ob, 0, a, paf, pa, force, deform, mtexmove, effectorbase);
+ }
+
+ /* free stuff */
+ give_mesh_particle_coord(NULL, NULL, NULL, 0, 0, NULL, NULL);
+ MEM_freeN(vertexcosnos);
+ if(voweights) MEM_freeN(voweights);
+ if(foweights) MEM_freeN(foweights);
+ if(volengths) MEM_freeN(volengths);
+ if(folengths) MEM_freeN(folengths);
+ if(mcache) MEM_freeN(mcache);
+ rng_free(rng);
+
+ if(deform) end_latt_deform();
+
+ if(effectorbase)
+ pdEndEffectors(effectorbase);
+
+ /* reset deflector cache */
+ for(base= G.scene->base.first; base; base= base->next) {
+ if(base->object->sumohandle) {
+
+ MEM_freeN(base->object->sumohandle);
+ base->object->sumohandle= NULL;
+ }
+ }
+
+ disable_speed_curve(0);
+
+ if(waitcursor_set) waitcursor(0);
+}
+
diff --git a/source/blender/blenkernel/intern/exotic.c b/source/blender/blenkernel/intern/exotic.c
new file mode 100644
index 00000000000..0f1f8c6078a
--- /dev/null
+++ b/source/blender/blenkernel/intern/exotic.c
@@ -0,0 +1,4943 @@
+/* exotic.c
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s):
+ * - Martin DeMello
+ * Added dxf_read_arc, dxf_read_ellipse and dxf_read_lwpolyline
+ * Copyright (C) 2004 by Etheract Software Labs
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * eigen videoscape formaat:
+ *
+ *
+ * lamp:
+ * 3DG2
+ aantal_lampen
+
+ type
+ spsi spbl
+ r, g, b, energy
+ locx, locy, locz
+ vecx, vecy, vecz
+
+
+ curve / nurbs:
+ 3DG3
+ 5 of 11 (curve of surf)
+ aantal_nurbs
+ extr1 extr2
+
+ mat[0][0] mat[0][1] mat[0][2] mat[0][3]
+ mat[1][0] mat[1][1] mat[1][2] mat[1][3]
+ ...
+
+ type
+ pntsu, pntsv
+ resolu, resolv
+ orderu, orderv
+ flagu, flagv
+
+ (als type==nurb) x y z w
+ x y z w
+ ...
+ (als type==bez) xyz xyz xyz h1 h2 h3
+ xyz xyz xyz h1 h2 h3
+ ...
+ *
+ *
+ */
+
+
+#include <ctype.h> /* isdigit, isspace */
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+
+#ifndef WIN32
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_material_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_image_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BKE_bad_level_calls.h"
+#include "BKE_utildefines.h"
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_editVert.h"
+
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_mesh.h"
+#include "BKE_library.h"
+#include "BKE_global.h"
+#include "BKE_object.h"
+#include "BKE_material.h"
+#include "BKE_exotic.h"
+/* #include "BKE_error.h" */
+#include "BKE_screen.h"
+#include "BKE_displist.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_curve.h"
+#include "BKE_customdata.h"
+
+#include "BPY_extern.h"
+
+#include "blendef.h"
+
+#include "zlib.h"
+
+static int is_dxf(char *str);
+static void dxf_read(char *filename);
+static int is_stl(char *str);
+
+static int is_stl_ascii(char *str)
+{
+ FILE *fpSTL;
+ char buffer[1000];
+ int numread, i;
+
+ fpSTL = fopen(str, "rb");
+ if ( (numread = fread( (void *) buffer, sizeof(char), 1000, fpSTL)) <= 0 )
+ { fclose(fpSTL); return 0; }
+
+ for (i=0; i < numread; ++i) {
+ /* if bit 8 is set we assume binary */
+ if (buffer[i] & 0x80)
+ { fclose(fpSTL); return 0; }
+ }
+
+ buffer[5] = '\0';
+ if ( !(strstr(buffer, "solid")) && !(strstr(buffer, "SOLID")) )
+ { fclose(fpSTL); return 0; }
+
+ fclose(fpSTL);
+
+ return 1;
+}
+
+static int is_stl(char *str)
+{
+ int i;
+ i = strlen(str) - 3;
+ if ( (str[i] !='s') && (str[i] !='S'))
+ return 0;
+ i++;
+ if ( (str[i] !='t') && (str[i] !='T'))
+ return 0;
+ i++;
+ if ( (str[i] !='l') && (str[i] !='L'))
+ return 0;
+
+ return 1;
+}
+
+#define READSTLVERT { \
+ if (fread(mvert->co, sizeof(float), 3, fpSTL) != 3) { \
+ char error_msg[255]; \
+ MEM_freeN(vertdata); \
+ MEM_freeN(facedata); \
+ fclose(fpSTL); \
+ sprintf(error_msg, "Problems reading face %d!", i); \
+ error(error_msg); \
+ return; \
+ } \
+ else { \
+ if (G.order==B_ENDIAN) { \
+ SWITCH_INT(mvert->co[0]); \
+ SWITCH_INT(mvert->co[1]); \
+ SWITCH_INT(mvert->co[2]); \
+ } \
+ } \
+}
+
+static void simple_vertex_normal_blend(short *no, short *ble)
+{
+ if(no[0]==0 && no[1]==0 && no[2]==0) {
+ VECCOPY(no, ble);
+ }
+ else {
+ no[0]= (2*no[0] + ble[0])/3;
+ no[1]= (2*no[1] + ble[1])/3;
+ no[2]= (2*no[2] + ble[2])/3;
+ }
+}
+
+static void mesh_add_normals_flags(Mesh *me)
+{
+ MVert *v1, *v2, *v3, *v4;
+ MFace *mface;
+ float nor[3];
+ int a;
+ short sno[3];
+
+ mface= me->mface;
+ for(a=0; a<me->totface; a++, mface++) {
+ v1= me->mvert+mface->v1;
+ v2= me->mvert+mface->v2;
+ v3= me->mvert+mface->v3;
+ v4= me->mvert+mface->v4;
+
+ CalcNormFloat(v1->co, v2->co, v3->co, nor);
+ sno[0]= 32767.0*nor[0];
+ sno[1]= 32767.0*nor[1];
+ sno[2]= 32767.0*nor[2];
+
+ simple_vertex_normal_blend(v1->no, sno);
+ simple_vertex_normal_blend(v2->no, sno);
+ simple_vertex_normal_blend(v3->no, sno);
+ if(mface->v4) {
+ simple_vertex_normal_blend(v4->no, sno);
+ }
+ mface->edcode= ME_V1V2|ME_V2V3;
+ }
+}
+
+static void read_stl_mesh_binary(char *str)
+{
+ FILE *fpSTL;
+ Object *ob;
+ Mesh *me;
+ MVert *mvert, *vertdata;
+ MFace *mface, *facedata;
+ unsigned int numfacets = 0, i, j, vertnum;
+ unsigned int maxmeshsize, nummesh, lastmeshsize;
+ unsigned int totvert, totface;
+
+ fpSTL= fopen(str, "rb");
+ if(fpSTL==NULL) {
+ error("Can't read file");
+ return;
+ }
+
+ fseek(fpSTL, 80, SEEK_SET);
+ fread(&numfacets, 4*sizeof(char), 1, fpSTL);
+ if (G.order==B_ENDIAN) {
+ SWITCH_INT(numfacets);
+ }
+
+ maxmeshsize = MESH_MAX_VERTS/3;
+
+ nummesh = (numfacets / maxmeshsize) + 1;
+ lastmeshsize = numfacets % maxmeshsize;
+
+ if (numfacets) {
+ for (j=0; j < nummesh; ++j) {
+ /* new object */
+ if (j == nummesh-1) {
+ totface = lastmeshsize;
+ }
+ else {
+ totface = maxmeshsize;
+ }
+ totvert = 3 * totface;
+
+ vertdata = MEM_callocN(totvert*sizeof(MVert), "mverts");
+ facedata = MEM_callocN(totface*sizeof(MFace), "mface");
+
+ vertnum = 0;
+ mvert= vertdata;
+ mface = facedata;
+ for (i=0; i < totface; i++) {
+ fseek(fpSTL, 12, SEEK_CUR); /* skip the face normal */
+ READSTLVERT;
+ mvert++;
+ READSTLVERT;
+ mvert++;
+ READSTLVERT;
+ mvert++;
+
+ mface->v1 = vertnum++;
+ mface->v2 = vertnum++;
+ mface->v3 = vertnum++;
+ mface++;
+
+ fseek(fpSTL, 2, SEEK_CUR);
+ }
+
+ ob= add_object(OB_MESH);
+ me= ob->data;
+ me->totvert = totvert;
+ me->totface = totface;
+ me->mvert = CustomData_add_layer(&me->vdata, CD_MVERT, CD_ASSIGN,
+ vertdata, totvert);
+ me->mface = CustomData_add_layer(&me->fdata, CD_MFACE, CD_ASSIGN,
+ facedata, totface);
+
+ mesh_add_normals_flags(me);
+ make_edges(me, 0);
+ }
+ waitcursor(1);
+ }
+ fclose(fpSTL);
+
+}
+#undef READSTLVERT
+
+#define STLALLOCERROR { \
+ char error_msg[255]; \
+ fclose(fpSTL); \
+ sprintf(error_msg, "Can't allocate storage for %d faces!", \
+ numtenthousand * 10000); \
+ error(error_msg); \
+ return; \
+}
+
+#define STLBAILOUT(message) { \
+ char error_msg[255]; \
+ fclose(fpSTL); \
+ free(vertdata); \
+ sprintf(error_msg, "Line %d: %s", linenum, message); \
+ error(message); \
+ return; \
+}
+
+#define STLREADLINE { \
+ if (!fgets(buffer, 2048, fpSTL)) STLBAILOUT("Can't read line!"); \
+ linenum++; \
+}
+
+#define STLREADVERT { \
+ STLREADLINE; \
+ if ( !(cp = strstr(buffer, "vertex")) && \
+ !(cp = strstr(buffer, "VERTEX")) ) STLBAILOUT("Bad vertex!"); \
+ vp = vertdata + 3 * totvert; \
+ if (sscanf(cp + 6, "%f %f %f", vp, vp+1, vp+2) != 3) \
+ STLBAILOUT("Bad vertex!"); \
+ ++totvert; \
+}
+static void read_stl_mesh_ascii(char *str)
+{
+ FILE *fpSTL;
+ char buffer[2048], *cp;
+ Object *ob;
+ Mesh *me;
+ MVert *mvert;
+ MFace *mface;
+ float *vertdata, *vp;
+ unsigned int numtenthousand, linenum;
+ unsigned int i, vertnum;
+ unsigned int totvert, totface;
+
+ /* ASCII stl sucks ... we don't really know how many faces there
+ are until the file is done, so lets allocate faces 10000 at a time */
+
+ fpSTL= fopen(str, "r");
+ if(fpSTL==NULL) {
+ error("Can't read file");
+ return;
+ }
+
+ /* we'll use the standard malloc/realloc for now ...
+ * lets allocate enough storage to hold 10000 triangles,
+ * i.e. 30000 verts, i.e., 90000 floats.
+ */
+ numtenthousand = 1;
+ vertdata = malloc(numtenthousand*3*30000*sizeof(float)); // uses realloc!
+ if (!vertdata) STLALLOCERROR;
+
+ linenum = 1;
+ /* Get rid of the first line */
+ STLREADLINE;
+
+ totvert = 0;
+ totface = 0;
+ while(1) {
+ /* Read in the next line */
+ STLREADLINE;
+
+ /* lets check if this is the end of the file */
+ if ( strstr(buffer, "endsolid") || strstr(buffer, "ENDSOLID") )
+ break;
+
+ /* Well, guess that wasn't the end, so lets make
+ * sure we have enough storage for some more faces
+ */
+ if ( (totface) && ( (totface % 10000) == 0 ) ) {
+ ++numtenthousand;
+ vertdata = realloc(vertdata,
+ numtenthousand*3*30000*sizeof(float));
+ if (!vertdata) STLALLOCERROR;
+ }
+
+ /* Don't read normal, but check line for proper syntax anyway
+ */
+ if ( !(cp = strstr(buffer, "facet")) &&
+ !(cp = strstr(buffer, "FACET")) ) STLBAILOUT("Bad normal line!");
+ if ( !(strstr(cp+5, "normal")) &&
+ !(strstr(cp+5, "NORMAL")) ) STLBAILOUT("Bad normal line!");
+
+ /* Read in what should be the outer loop line
+ */
+ STLREADLINE;
+ if ( !(cp = strstr(buffer, "outer")) &&
+ !(cp = strstr(buffer, "OUTER")) ) STLBAILOUT("Bad outer loop!");
+ if ( !(strstr(cp+5, "loop")) &&
+ !(strstr(cp+5, "LOOP")) ) STLBAILOUT("Bad outer loop!");
+
+ /* Read in the face */
+ STLREADVERT;
+ STLREADVERT;
+ STLREADVERT;
+
+ /* Read in what should be the endloop line
+ */
+ STLREADLINE;
+ if ( !strstr(buffer, "endloop") && !strstr(buffer, "ENDLOOP") )
+ STLBAILOUT("Bad endloop!");
+
+ /* Read in what should be the endfacet line
+ */
+ STLREADLINE;
+ if ( !strstr(buffer, "endfacet") && !strstr(buffer, "ENDFACET") )
+ STLBAILOUT("Bad endfacet!");
+
+ /* Made it this far? Increment face count */
+ ++totface;
+ }
+ fclose(fpSTL);
+
+ /* OK, lets create our mesh */
+ ob = add_object(OB_MESH);
+ me = ob->data;
+
+ me->totface = totface;
+ me->totvert = totvert;
+ me->mvert = CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC,
+ NULL, totvert);
+ me->mface = CustomData_add_layer(&me->fdata, CD_MFACE, CD_CALLOC,
+ NULL, totface);
+
+ /* Copy vert coords and create topology */
+ mvert = me->mvert;
+ mface = me->mface;
+ vertnum = 0;
+ for (i=0; i < totface; ++i) {
+ memcpy(mvert->co, vertdata+3*vertnum, 3*sizeof(float) );
+ mface->v1 = vertnum;
+ mvert++;
+ vertnum++;
+
+ memcpy(mvert->co, vertdata+3*vertnum, 3*sizeof(float) );
+ mface->v2 = vertnum;
+ mvert++;
+ vertnum++;
+
+ memcpy(mvert->co, vertdata+3*vertnum, 3*sizeof(float) );
+ mface->v3 = vertnum;
+ mvert++;
+ vertnum++;
+
+ mface++;
+ }
+ free(vertdata);
+
+ mesh_add_normals_flags(me);
+ make_edges(me, 0);
+
+ waitcursor(1);
+}
+
+#undef STLALLOCERROR
+#undef STLBAILOUT
+#undef STLREADLINE
+#undef STLREADVERT
+
+static void read_videoscape_mesh(char *str)
+{
+ Object *ob;
+ Mesh *me;
+ MVert *mvert;
+ MFace *mface;
+ Material *ma;
+ FILE *fp;
+ float *vertdata, *vd, min[3], max[3], cent[3], ftemp;
+ unsigned int color[32], col;
+ int totcol, a, b, verts, tottria=0, totquad=0, totedge=0, poly, nr0, nr, first;
+ int end;
+ char s[50];
+
+ fp= fopen(str, "rb");
+ if(fp==NULL) {
+ error("Can't read file");
+ return;
+ }
+
+ fscanf(fp, "%40s", s);
+
+ fscanf(fp, "%d\n", &verts);
+ if(verts<=0) {
+ fclose(fp);
+ error("Read error");
+ return;
+ }
+
+ if(verts>MESH_MAX_VERTS) {
+ error("too many vertices");
+ fclose(fp);
+ return;
+ }
+
+ INIT_MINMAX(min, max);
+ vd= vertdata= MEM_mallocN(sizeof(float)*3*verts, "videoscapelezer");
+
+ for(a=0; a<verts; a++) {
+ fscanf(fp, "%f %f %f", vd, vd+1, vd+2);
+ DO_MINMAX(vd, min, max);
+ vd+=3;
+ }
+
+ /* count faces and colors */
+ for(a=0; a<32; a++) color[a]= 0;
+ totcol= 0;
+ end= 1;
+ while(end>0) {
+ end= fscanf(fp,"%d", &poly);
+ if(end<=0) break;
+
+ if(poly==3) tottria++;
+ else if(poly==4) totquad++;
+ else totedge+= poly;
+
+ for(a=0;a<poly;a++) {
+ end= fscanf(fp,"%d", &nr);
+ if(end<=0) break;
+ }
+ if(end<=0) break;
+
+ end= fscanf(fp,"%i\n", &col);
+ col &= 0xF0F0F0;
+ for(a=0; a<totcol; a++) {
+ if(color[a]==col) break;
+ }
+ if(a>=totcol && totcol<32) {
+ color[totcol]= col;
+ totcol++;
+ }
+ }
+
+ /* new object */
+ ob= add_object(OB_MESH);
+ me= ob->data;
+ me->totvert= verts;
+ me->totface= totedge+tottria+totquad;
+
+ me->mvert= CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC,
+ NULL, me->totvert);
+ me->mface= CustomData_add_layer(&me->fdata, CD_MFACE, CD_CALLOC,
+ NULL, me->totface);
+
+ /* colors */
+ if(totcol) {
+ ob->mat= MEM_callocN(sizeof(void *)*totcol, "ob->mat");
+ me->mat= MEM_callocN(sizeof(void *)*totcol, "me->mat");
+ me->totcol= totcol;
+ ob->totcol= (unsigned char) me->totcol;
+ ob->actcol= 1;
+ }
+
+ /* materials */
+ for(a=0; a<totcol; a++) {
+ ma= G.main->mat.first;
+ while(ma) {
+ if(ma->mtex[0]==0) {
+ col= rgb_to_cpack(ma->r, ma->g, ma->b);
+ if(color[a]==col) {
+ me->mat[a]= ma;
+ ma->id.us++;
+ break;
+ }
+ }
+ ma= ma->id.next;
+ }
+ if(ma==0) {
+ ma= add_material("ext");
+ me->mat[a]= ma;
+ cpack_to_rgb(color[a], cent, cent+1, cent+2);
+ ma->r= cent[0];
+ ma->g= cent[1];
+ ma->b= cent[2];
+ automatname(ma);
+ }
+ }
+
+ /* verts */
+
+ cent[0]= (min[0]+max[0])/2.0f;
+ cent[1]= (min[1]+max[1])/2.0f;
+ cent[2]= (min[2]+max[2])/2.0f;
+ VECCOPY(ob->loc, cent);
+
+ a= me->totvert;
+ vd= vertdata;
+ mvert= me->mvert;
+ while(a--) {
+ VecSubf(mvert->co, vd, cent);
+ mvert++;
+ vd+= 3;
+ }
+
+ /* faces */
+ if(me->totface) {
+ rewind(fp);
+
+ fscanf(fp, "%40s", s);
+ fscanf(fp, "%d\n", &verts);
+ /* fake read */
+ for(a=0;a<verts;a++) {
+ fscanf(fp, "%f %f %f", &ftemp, &ftemp, &ftemp);
+ }
+
+ a= me->totface;
+ mface= me->mface;
+ while(a--) {
+ end= fscanf(fp,"%d", &poly);
+ if(end<=0) break;
+
+ if(poly==3 || poly==4) {
+ fscanf(fp,"%d", &nr);
+ mface->v1= MIN2(nr, me->totvert-1);
+ fscanf(fp,"%d", &nr);
+ mface->v2= MIN2(nr, me->totvert-1);
+ fscanf(fp,"%d", &nr);
+ mface->v3= MIN2(nr, me->totvert-1);
+ if(poly==4) {
+ if( fscanf(fp,"%d", &nr) <=0 ) break;
+ mface->v4= MIN2(nr, me->totvert-1);
+ }
+
+ test_index_face(mface, NULL, 0, poly);
+
+ mface++;
+ }
+ else {
+ if( fscanf(fp,"%d", &nr0) <=0) break;
+ first= nr0;
+ for(b=1; b<poly; b++) {
+ end= fscanf(fp,"%d", &nr);
+ if(end<=0) break;
+ nr= MIN2(nr, me->totvert-1);
+ mface->v1= nr;
+ mface->v2= nr0;
+ nr0= nr;
+ mface++;
+ a--;
+ }
+ mface->v1= first;
+ mface->v2= nr;
+ mface++;
+ if(end<=0) break;
+ }
+ end= fscanf(fp,"%i", &col);
+ col &= 0xF0F0F0;
+ if(end<=0) break;
+
+ for(b=0; b<totcol; b++) {
+ if(color[b]==col) {
+ (mface-1)->mat_nr= b;
+ break;
+ }
+ }
+ }
+ }
+
+ fclose(fp);
+ MEM_freeN(vertdata);
+
+ mesh_add_normals_flags(me);
+ make_edges(me, 0);
+
+ waitcursor(1);
+}
+
+static void read_radiogour(char *str)
+{
+ Object *ob;
+ Mesh *me;
+ MVert *mvert;
+ MFace *mface;
+ FILE *fp;
+ float *vertdata, *vd, min[3], max[3], cent[3], ftemp;
+ unsigned int *colv, *colf, *colvertdata;
+ int itemp, a, b, verts, tottria=0, totquad=0, totedge=0, poly, nr0, nr, first;
+ int end;
+ char s[50];
+
+ fp= fopen(str, "rb");
+ if(fp==NULL) {
+ error("Can't read file");
+ return;
+ }
+
+ fscanf(fp, "%40s", s);
+
+ fscanf(fp, "%d\n", &verts);
+ if(verts<=0) {
+ fclose(fp);
+ error("Read error");
+ return;
+ }
+
+ if(verts>MESH_MAX_VERTS) {
+ error("too many vertices");
+ fclose(fp);
+ return;
+ }
+
+ INIT_MINMAX(min, max);
+ vd= vertdata= MEM_mallocN(sizeof(float)*3*verts, "videoscapelezer");
+ colv= colvertdata= MEM_mallocN(verts*sizeof(float), "coldata");
+
+ for(a=0; a<verts; a++) {
+ fscanf(fp, "%f %f %f %i", vd, vd+1, vd+2, colv);
+ DO_MINMAX(vd, min, max);
+ vd+=3;
+ colv++;
+ }
+
+ /* count faces */
+ end= 1;
+ while(end>0) {
+ end= fscanf(fp,"%d", &poly);
+ if(end<=0) break;
+
+ if(poly==3) tottria++;
+ else if(poly==4) totquad++;
+ else totedge+= poly;
+
+ for(a=0;a<poly;a++) {
+ end= fscanf(fp,"%d", &nr);
+ if(end<=0) break;
+ }
+ if(end<=0) break;
+
+ }
+
+ if(totedge+tottria+totquad>MESH_MAX_VERTS) {
+ printf(" var1: %d, var2: %d, var3: %d \n", totedge, tottria, totquad);
+ error("too many faces");
+ MEM_freeN(vertdata);
+ MEM_freeN(colvertdata);
+ fclose(fp);
+ return;
+ }
+
+ /* new object */
+ ob= add_object(OB_MESH);
+ me= ob->data;
+ me->totvert= verts;
+ me->totface= totedge+tottria+totquad;
+ me->flag= 0;
+
+ me->mvert= CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC,
+ NULL, me->totvert);
+ me->mface= CustomData_add_layer(&me->fdata, CD_MFACE, CD_CALLOC,
+ NULL, me->totface);
+
+ /* verts */
+
+ cent[0]= (min[0]+max[0])/2.0f;
+ cent[1]= (min[1]+max[1])/2.0f;
+ cent[2]= (min[2]+max[2])/2.0f;
+ VECCOPY(ob->loc, cent);
+
+ a= me->totvert;
+ vd= vertdata;
+ mvert= me->mvert;
+ while(a--) {
+ VecSubf(mvert->co, vd, cent);
+ mvert++;
+ vd+= 3;
+ }
+
+ /* faces */
+ if(me->totface) {
+ rewind(fp);
+
+ fscanf(fp, "%40s", s);
+ fscanf(fp, "%d\n", &verts);
+ for(a=0;a<verts;a++) {
+ fscanf(fp, "%f %f %f %i", &ftemp, &ftemp, &ftemp, &itemp);
+ }
+
+ a= me->totface;
+ mface= me->mface;
+ while(a--) {
+ end= fscanf(fp,"%d", &poly);
+ if(end<=0) break;
+
+ if(poly==3 || poly==4) {
+ fscanf(fp,"%d", &nr);
+ mface->v1= MIN2(nr, me->totvert-1);
+ fscanf(fp,"%d", &nr);
+ mface->v2= MIN2(nr, me->totvert-1);
+ fscanf(fp,"%d", &nr);
+ mface->v3= MIN2(nr, me->totvert-1);
+ if(poly==4) {
+ if( fscanf(fp,"%d", &nr) <=0 ) break;
+ mface->v4= MIN2(nr, me->totvert-1);
+ }
+
+ test_index_face(mface, NULL, 0, poly);
+
+ mface++;
+ }
+ else {
+ if( fscanf(fp,"%d", &nr0) <=0) break;
+ first= nr0;
+ for(b=1; b<poly; b++) {
+ end= fscanf(fp,"%d", &nr);
+ if(end<=0) break;
+ nr= MIN2(nr, me->totvert-1);
+ mface->v1= nr;
+ mface->v2= nr0;
+ nr0= nr;
+ mface++;
+ a--;
+ }
+ mface->v1= first;
+ mface->v2= nr;
+ mface->flag= ME_SMOOTH;
+
+ mface++;
+ if(end<=0) break;
+ }
+ }
+
+ /* mcol is 4 colors per face */
+ me->mcol= MEM_mallocN(4*sizeof(int)*me->totface, "mcol");
+ colf= (unsigned int *)me->mcol;
+
+ a= me->totface;
+ mface= me->mface;
+ while(a--) {
+
+ colf[0]= colvertdata[mface->v1];
+ colf[1]= colvertdata[mface->v2];
+ colf[2]= colvertdata[mface->v3];
+ colf[3]= colvertdata[mface->v4];
+
+ colf+= 4;
+ mface++;
+ }
+
+ MEM_freeN(colvertdata);
+ }
+
+ fclose(fp);
+ MEM_freeN(vertdata);
+
+ mesh_add_normals_flags(me);
+ make_edges(me, 0);
+
+ waitcursor(1);
+}
+
+
+static void read_videoscape_lamp(char *str)
+{
+ Object *ob;
+ Lamp *la;
+ FILE *fp;
+ float vec[3], *q1;
+ int tot, val;
+ char s[50];
+
+ fp= fopen(str, "rb");
+ if(fp==NULL) {
+ error("Can't read file");
+ return;
+ }
+
+ fscanf(fp, "%40s", s);
+ fscanf(fp, "%d\n", &tot);
+
+ while(tot--) {
+ ob= add_object(OB_LAMP);
+ la= ob->data;
+
+ fscanf(fp, "%d\n", &val);
+ la->type= val;
+ if(la->type==1) la->type= LA_SPOT;
+ else if(la->type==2) la->type= LA_SUN;
+
+ fscanf(fp, "%f %f\n", &la->spotsize, &la->spotblend);
+
+ fscanf(fp, "%f %f %f %f\n", &la->r, &la->g, &la->b, &la->energy);
+
+ fscanf(fp, "%f %f %f\n", ob->loc, ob->loc+1, ob->loc+2);
+ val= fscanf(fp, "%f %f %f\n", vec, vec+1, vec+2);
+ q1= vectoquat(vec, 5, 2);
+ QuatToEul(q1, ob->rot);
+
+ if(val<=0) break;
+
+ }
+ fclose(fp);
+}
+
+static void read_videoscape_nurbs(char *str)
+{
+ Object *ob;
+ Curve *cu;
+ Nurb *nu;
+ BezTriple *bezt;
+ BPoint *bp;
+ FILE *fp;
+ float tmat[4][4], omat[3][3], imat[3][3], mat[3][3];
+ int a, tot, type, val;
+ char s[50];
+
+ fp= fopen(str, "rb");
+ if(fp==NULL) {
+ error("Can't read file");
+ return;
+ }
+
+ fscanf(fp, "%40s", s);
+ fscanf(fp, "%d\n", &type);
+
+ if(type==5) ob= add_object(OB_SURF);
+ else ob= add_object(OB_CURVE);
+ cu= ob->data;
+
+ fscanf(fp, "%d\n", &tot);
+ fscanf(fp, "%d %d\n", &type, &val);
+
+ cu->ext1= 0.002f*type;
+ cu->ext2= 0.002f*val;
+
+ for(a=0; a<4; a++) fscanf(fp, "%e %e %e %e\n", tmat[a], tmat[a]+1, tmat[a]+2, tmat[a]+3);
+
+ VECCOPY(ob->loc, tmat[3]);
+
+ Mat3CpyMat4(omat, tmat);
+ Mat3ToEul(omat, ob->rot);
+ EulToMat3(ob->rot, mat);
+ Mat3Inv(imat, mat);
+ Mat3MulMat3((float ( * )[3])tmat, imat, omat);
+
+ while(tot--) {
+ nu= (Nurb*)MEM_callocN(sizeof(Nurb),"nu from exotic");
+ BLI_addtail(&cu->nurb, nu);
+
+ fscanf(fp, "%d\n", &type);
+ nu->type= type;
+
+ fscanf(fp, "%d %d\n", &type, &val);
+ nu->pntsu= type; nu->pntsv= val;
+ fscanf(fp, "%d %d\n", &type, &val);
+ nu->resolu= type; nu->resolv= val;
+ fscanf(fp, "%d %d\n", &type, &val);
+ nu->orderu= type; nu->orderv= val;
+ fscanf(fp, "%d %d\n", &type, &val);
+ nu->flagu= type; nu->flagv= val;
+
+ if( (nu->type & 7)==CU_BEZIER) {
+ a= nu->pntsu;
+ nu->bezt= bezt= MEM_callocN(a*sizeof(BezTriple), "bezt from exotic");
+ while(a--) {
+ fscanf(fp, "%f %f %f ", bezt->vec[0], bezt->vec[0]+1, bezt->vec[0]+2);
+ Mat4MulVecfl(tmat, bezt->vec[0]);
+ fscanf(fp, "%f %f %f ", bezt->vec[1], bezt->vec[1]+1, bezt->vec[1]+2);
+ Mat4MulVecfl(tmat, bezt->vec[1]);
+ fscanf(fp, "%f %f %f ", bezt->vec[2], bezt->vec[2]+1, bezt->vec[2]+2);
+ Mat4MulVecfl(tmat, bezt->vec[2]);
+ fscanf(fp, "%d %d\n", &type, &val);
+ bezt->h1= type;
+ bezt->h2= val;
+ bezt++;
+ }
+ }
+ else {
+ a= nu->pntsu*nu->pntsv;
+ if(a) {
+ nu->bp= bp= MEM_callocN(a*sizeof(BPoint), "bp from exotic");
+ while(a--) {
+ fscanf(fp, "%f %f %f %f\n", bp->vec, bp->vec+1, bp->vec+2, bp->vec+3);
+ Mat4MulVecfl(tmat, bp->vec);
+ bp++;
+ }
+
+ val= KNOTSU(nu);
+ nu->knotsu= MEM_mallocN(sizeof(float)*val, "knots");
+ for(a=0; a<val; a++) fscanf(fp, "%f\n", nu->knotsu+a);
+
+ if(nu->pntsv>1) {
+ val= KNOTSV(nu);
+ nu->knotsv= MEM_mallocN(sizeof(float)*val, "knots");
+ for(a=0; a<val; a++) fscanf(fp, "%f\n", nu->knotsv+a);
+ }
+ }
+ else {
+ BLI_remlink(&cu->nurb, nu);
+ MEM_freeN(nu);
+ }
+ }
+ }
+ fclose(fp);
+}
+
+static void read_videoscape(char *str)
+{
+ int file, type;
+ unsigned int val;
+ unsigned short numlen;
+ char name[FILE_MAXDIR+FILE_MAXFILE], head[FILE_MAXDIR+FILE_MAXFILE], tail[FILE_MAXFILE];
+
+ strcpy(name, str);
+
+ while( TRUE ) {
+ file= open(name, O_BINARY|O_RDONLY);
+ if(file<=0) break;
+ else {
+ read(file, &type, 4);
+ close(file);
+
+ if(type==DDG1) read_videoscape_mesh(name);
+ else if(type==DDG2) read_videoscape_lamp(name);
+ else if(type==DDG3) read_videoscape_nurbs(name);
+ }
+
+ val = BLI_stringdec(name, head, tail, &numlen);
+ BLI_stringenc(name, head, tail, numlen, val + 1);
+
+ }
+}
+
+
+/* ***************** INVENTOR ******************* */
+
+
+#define IV_MAXSTACK 3000000
+#define IV_MAXFIELD 10
+#define IV_MAXCOL 16
+
+static float *iv_data_stack;
+static float ivcolors[IV_MAXCOL][3];
+static Object *ivsurf;
+static ListBase ivbase;
+
+struct IvNode {
+ struct IvNode *next, *prev;
+ char *nodename;
+ char *fieldname[IV_MAXFIELD];
+ int datalen[IV_MAXFIELD];
+ float *data[IV_MAXFIELD];
+};
+
+static int iv_curcol=0;
+
+static int iv_colornumber(struct IvNode *iv)
+{
+ float *fp, fr = 0.0, fg = 0.0, fb = 0.0;
+ int a;
+ char *cp;
+
+ /* search back to last material */
+ while(iv) {
+ if( strcmp(iv->nodename, "Material")==0) {
+ fp= iv->data[0];
+ if(fp==0) fp= iv->data[1];
+ if(fp) {
+ fr= fp[0];
+ fg= fp[1];
+ fb= fp[2];
+ }
+ break;
+ }
+ else if( strcmp(iv->nodename, "BaseColor")==0) {
+ fp= iv->data[0];
+ fr= fp[0];
+ fg= fp[1];
+ fb= fp[2];
+ break;
+ }
+ else if( strcmp(iv->nodename, "PackedColor")==0) {
+ cp= (char *)iv->data[0];
+ fr= cp[3]/255.0f;
+ fg= cp[2]/255.0f;
+ fb= cp[1]/255.0f;
+ break;
+ }
+ iv= iv->prev;
+
+ }
+ if(iv==0) return 0;
+ if(iv->datalen[0]<3) return 0;
+
+ for(a=0; a<iv_curcol; a++) {
+
+ if(ivcolors[a][0]== fr)
+ if(ivcolors[a][1]== fg)
+ if(ivcolors[a][2]== fb) return a+1
+ ;
+ }
+
+ if(a>=IV_MAXCOL) a= IV_MAXCOL-1;
+ iv_curcol= a+1;
+ ivcolors[a][0]= fr;
+ ivcolors[a][1]= fg;
+ ivcolors[a][2]= fb;
+
+ return iv_curcol;
+}
+
+static int iv_finddata(struct IvNode *iv, char *field, int fieldnr)
+{
+ /* search for "field", count data size and make datablock. return skipdata */
+ float *fp;
+ int len, stackcount, skipdata=0;
+ char *cpa, terminator, str[64];
+ long i;
+
+ len= strlen(field);
+
+ cpa= iv->nodename+1;
+ while( *cpa != '}' ) {
+
+ if( *cpa == *field ) {
+ if( strncmp(cpa, field, len)==0 ) {
+ iv->fieldname[fieldnr]= cpa;
+
+ /* read until first character */
+ cpa+= len;
+ skipdata+= len;
+ *cpa= 0;
+ cpa++;
+ skipdata++;
+
+ while( *cpa==32 || *cpa==13 || *cpa==10 || *cpa==9) cpa++;
+ if( *cpa=='[' ) {
+ terminator= ']';
+ cpa++;
+ skipdata++;
+ }
+ else terminator= 13;
+
+ stackcount= 0;
+ fp= iv_data_stack;
+
+ while( *cpa!=terminator && *cpa != '}' ) {
+
+ /* in fact, isdigit should include the dot and minus */
+ if( (isdigit(*cpa) || *cpa=='.' || *cpa=='-') && (isspace(cpa[-1]) || cpa[-1]==0 || cpa[-1]==',') ) {
+ if(cpa[1]=='x') {
+ memcpy(str, cpa, 16);
+ str[16]= 0;
+
+ sscanf(str, "%x", (int *)fp);
+ }
+ else {
+ /* atof doesn't stop after the first float
+ * in a long string at Windows... so we copy
+ * the float to a new string then atof... */
+ char *cpa_temp = strpbrk(cpa, ", \n");
+ i = cpa_temp - cpa;
+
+ if (i>63) *fp= 0.0;
+ else {
+ memcpy(str, cpa, i);
+ str[i]=0;
+
+ *fp= (float) atof(str);
+ }
+ }
+
+ stackcount++;
+ if(stackcount>=IV_MAXSTACK) {
+ printf("stackoverflow in IV read\n");
+ break;
+ }
+ fp++;
+ }
+ cpa++;
+ skipdata++;
+ }
+
+ iv->datalen[fieldnr]= stackcount;
+ if(stackcount) {
+ iv->data[fieldnr]= MEM_mallocN(sizeof(float)*stackcount, "iv_finddata");
+ memcpy(iv->data[fieldnr], iv_data_stack, sizeof(float)*stackcount);
+ }
+ else iv->data[fieldnr]= 0;
+
+ return skipdata;
+ }
+ }
+ cpa++;
+ skipdata++;
+ }
+
+ return skipdata;
+}
+
+static void read_iv_index(float *data, float *baseadr, float *index, int nr, int coordtype)
+{
+ /* write in data: baseadr with offset index (and number nr) */
+ float *fp;
+ int ofs;
+
+ while(nr--) {
+ ofs= (int) *index;
+ fp= baseadr+coordtype*ofs;
+ VECCOPY(data, fp);
+ data+= 3;
+ index++;
+ }
+}
+
+
+
+static void read_inventor(char *str, struct ListBase *listb)
+{
+ struct IvNode *iv, *ivp, *ivn;
+ char *maindata, *md, *cpa;
+ float *index, *data, *fp;
+ int file, filelen, count, lll, face, nr = 0;
+ int skipdata, ok, a, b, tot, first, colnr, coordtype, polytype, *idata;
+ struct DispList *dl;
+
+ ivbase.first= ivbase.last= 0;
+ iv_curcol= 0;
+ ivsurf= 0;
+
+ file= open(str, O_BINARY|O_RDONLY);
+ if(file== -1) {
+ error("Can't read file\n");
+ return;
+ }
+
+ filelen= BLI_filesize(file);
+ if(filelen < 1) {
+ close(file);
+ return;
+ }
+
+ maindata= MEM_mallocN(filelen, "leesInventor");
+ read(file, maindata, filelen);
+ close(file);
+
+ iv_data_stack= MEM_mallocN(sizeof(float)*IV_MAXSTACK, "ivstack");
+
+ /* preprocess: remove comments */
+ md= maindata+20;
+ count= 20;
+ while(count<filelen) {
+ if( *md=='#' ) { /* comment */
+ while( *md!=13 && *md!=10) { /* enters */
+ *md= 32;
+ md++;
+ count++;
+ if(count>=filelen) break;
+ }
+ }
+ md++;
+ count++;
+ }
+
+
+ /* now time to collect: which are the nodes and fields? */
+ md= maindata;
+ count= 0;
+ while(count<filelen) {
+ if( *md=='{' ) { /* read back */
+
+ cpa= md-1;
+ while( *cpa==32 || *cpa==13 || *cpa==10 || *cpa==9) { /* remove spaces/enters/tab */
+ *cpa= 0;
+ cpa--;
+ }
+
+ while( *cpa>32 && *cpa<128) cpa--;
+ cpa++;
+ *md= 0;
+
+ ok= 0;
+ skipdata= 0;
+ iv= MEM_callocN(sizeof(struct IvNode), "leesInventor");
+ iv->nodename= cpa;
+
+ if(strcmp(cpa, "Coordinate3")==0 || strcmp(cpa, "Coordinate4")==0) {
+ skipdata= iv_finddata(iv, "point", 0);
+ ok= 1;
+ }
+ else if(strcmp(cpa, "VertexProperty")==0) {
+ skipdata= iv_finddata(iv, "vertex", 0);
+ ok= 1;
+ }
+ else if(strcmp(cpa, "IndexedLineSet")==0) {
+ skipdata= iv_finddata(iv, "coordIndex", 0);
+ ok= 1;
+ }
+ else if(strcmp(cpa, "IndexedTriangleMesh")==0) {
+ skipdata= iv_finddata(iv, "coordIndex", 0);
+ ok= 1;
+ }
+ else if(strcmp(cpa, "IndexedFaceSet")==0) {
+ skipdata= iv_finddata(iv, "coordIndex", 0);
+ ok= 1;
+ }
+ else if(strcmp(cpa, "FaceSet")==0) {
+ skipdata= iv_finddata(iv, "numVertices", 0);
+ ok= 1;
+ }
+ else if(strcmp(cpa, "Material")==0) {
+ iv_finddata(iv, "diffuseColor", 0);
+ iv_finddata(iv, "ambientColor", 1);
+ ok= 1;
+ }
+ else if(strcmp(cpa, "BaseColor")==0) {
+ iv_finddata(iv, "rgb", 0);
+ ok= 1;
+ }
+ else if(strcmp(cpa, "PackedColor")==0) {
+ iv_finddata(iv, "rgba", 0);
+ ok= 1;
+ }
+ else if(strcmp(cpa, "QuadMesh")==0) {
+ iv_finddata(iv, "verticesPerColumn", 0);
+ iv_finddata(iv, "verticesPerRow", 1);
+
+ ok= 1;
+ }
+ else if(strcmp(cpa, "IndexedTriangleStripSet")==0) {
+ skipdata= iv_finddata(iv, "coordIndex", 0);
+ ok= 1;
+ }
+ else if(strcmp(cpa, "TriangleStripSet")==0) {
+ skipdata= iv_finddata(iv, "numVertices", 0);
+ ok= 1;
+ }
+ else if(strcmp(cpa, "IndexedNurbsSurface")==0 || strcmp(cpa, "NurbsSurface")==0) {
+ iv_finddata(iv, "numUControlPoints", 0);
+ iv_finddata(iv, "numVControlPoints", 1);
+ iv_finddata(iv, "uKnotVector", 2);
+ iv_finddata(iv, "vKnotVector", 3);
+ ok= 1;
+ }
+ else {
+ /* to the end */
+ while( *md != '}') {
+ md++;
+ count++;
+ if(count<filelen) break;
+ }
+ }
+
+
+ if(ok) {
+ BLI_addtail(&ivbase, iv);
+ md+= skipdata;
+ count+= skipdata;
+ }
+ else MEM_freeN(iv);
+
+ }
+ md++;
+ count++;
+ }
+
+ /* join nodes */
+ iv= ivbase.first;
+
+ while(iv) {
+ ivn= iv->next;
+
+ if( strncmp(iv->nodename, "Indexed", 7)==0) {
+ /* seek back: same name? */
+
+ ivp= iv->prev;
+ while(ivp) {
+ if(strcmp(iv->nodename, ivp->nodename)==0) break;
+
+ if(strcmp(ivp->nodename, "Coordinate3")==0 ||
+ strcmp(ivp->nodename, "Coordinate4")==0 ||
+ strcmp(ivp->nodename, "VertexProperty")==0) {
+ ivp= 0;
+ break;
+ }
+ ivp= ivp->prev;
+ }
+
+ if(ivp) {
+ /* add iv to ivp */
+
+ tot= iv->datalen[0] + ivp->datalen[0];
+ if(tot) {
+ data= MEM_mallocN(tot*sizeof(float), "samenvoeg iv");
+ memcpy(data, ivp->data[0], sizeof(float)*ivp->datalen[0]);
+ memcpy(data+ivp->datalen[0], iv->data[0], sizeof(float)*iv->datalen[0]);
+
+ ivp->datalen[0]+= iv->datalen[0];
+ MEM_freeN(ivp->data[0]);
+ ivp->data[0]= data;
+
+ BLI_remlink(&ivbase, iv);
+ MEM_freeN(iv->data[0]);
+ MEM_freeN(iv);
+ }
+ }
+ }
+
+ iv= ivn;
+ }
+
+
+ /* convert Nodes to DispLists */
+ iv= ivbase.first;
+ while(iv) {
+
+ /* printf(" Node: %s\n", iv->nodename); */
+ /* if(iv->fieldname[0]) printf(" Field: %s len %d\n", iv->fieldname[0], iv->datalen[0]); */
+ coordtype= 3;
+
+ if( strcmp(iv->nodename, "IndexedLineSet")==0 ) {
+
+ colnr= iv_colornumber(iv);
+
+ /* seek back to data */
+ ivp= iv;
+ while(ivp->prev) {
+ ivp= ivp->prev;
+ if( strcmp(ivp->nodename, "Coordinate3")==0 ) {
+ coordtype= 3;
+ break;
+ }
+ if( strcmp(ivp->nodename, "Coordinate4")==0 ) {
+ coordtype= 4;
+ break;
+ }
+ }
+ if(ivp) {
+
+ /* count the nr of lines */
+ tot= 0;
+ index= iv->data[0];
+ lll = iv->datalen[0]-1;
+ for(a=0; a<lll; a++) {
+ if(index[0]!= -1 && index[1]!= -1) tot++;
+ index++;
+ }
+
+ tot*= 2; /* nr of vertices */
+ dl= MEM_callocN(sizeof(struct DispList)+tot*3*sizeof(float), "leesInventor1");
+ BLI_addtail(listb, dl);
+ dl->type= DL_SEGM;
+ dl->nr= 2;
+ dl->parts= tot/2;
+ dl->col= colnr;
+ data= (float *)(dl+1);
+
+ index= iv->data[0];
+ for(a=0; a<lll; a++) {
+ if(index[0]!= -1 && index[1]!= -1) {
+ read_iv_index(data, ivp->data[0], index, 2, coordtype);
+ data+= 6;
+ }
+ index++;
+ }
+ }
+ }
+ else if( strcmp(iv->nodename, "FaceSet")==0 ) {
+
+ colnr= iv_colornumber(iv);
+
+ /* seek back to data */
+ ivp= iv;
+ while(ivp->prev) {
+ ivp= ivp->prev;
+ if( strcmp(ivp->nodename, "Coordinate3")==0 ) {
+ coordtype= 3;
+ break;
+ }
+ if( strcmp(ivp->nodename, "Coordinate4")==0 ) {
+ coordtype= 4;
+ break;
+ }
+ }
+
+ if(ivp) {
+ /* count triangles */
+ tot= 0;
+
+ index= iv->data[0];
+ polytype= (int) index[0];
+
+ for(a=0; a<iv->datalen[0]; a++) {
+ if(index[0]== polytype) tot++; /* one kind? */
+ index++;
+ }
+
+
+ tot*= polytype; /* nr of vertices */
+ dl= MEM_callocN(sizeof(struct DispList)+tot*3*sizeof(float), "leesInventor4");
+ BLI_addtail(listb, dl);
+ dl->type= DL_POLY;
+ dl->nr= polytype;
+ dl->parts= tot/polytype;
+ dl->col= colnr;
+ data= (float *)(dl+1);
+
+ index= ivp->data[0];
+ first= 1;
+ for(a=0; a<iv->datalen[0]; a++) {
+
+ VECCOPY(data, index);
+ data+= 3;
+ index+= 3;
+
+ VECCOPY(data, index);
+ data+= 3;
+ index+= 3;
+
+ VECCOPY(data, index);
+ data+= 3;
+ index+= 3;
+
+ if(polytype==4) {
+ VECCOPY(data, index);
+ data+= 3;
+ index+= 3;
+ }
+ }
+ }
+ }
+ else if( strcmp(iv->nodename, "TriangleStripSet")==0 ) {
+
+ colnr= iv_colornumber(iv);
+
+ /* seek back to data */
+ ivp= iv;
+ while(ivp->prev) {
+ ivp= ivp->prev;
+ if( strcmp(ivp->nodename, "Coordinate3")==0 ) {
+ coordtype= 3;
+ break;
+ }
+ if( strcmp(ivp->nodename, "Coordinate4")==0 ) {
+ coordtype= 4;
+ break;
+ }
+ }
+
+ if(ivp) {
+ /* count triangles */
+ tot= 0;
+ face= 0;
+
+ index= iv->data[0]; /* strip size */
+
+ for(a=0; a<iv->datalen[0]; a++) {
+ tot+= (int) index[0];
+ face+= ((int) index[0]) - 2;
+ index++;
+ }
+
+ dl= MEM_callocN(sizeof(struct DispList), "leesInventor4");
+ dl->verts= MEM_callocN( tot*3*sizeof(float), "dl verts");
+ dl->index= MEM_callocN( face*3*sizeof(int), "dl index");
+
+ dl->type= DL_INDEX3;
+ dl->nr= tot;
+ dl->parts= face;
+
+ BLI_addtail(listb, dl);
+ dl->col= colnr;
+
+ index= iv->data[0]; /* strip size */
+ fp= ivp->data[0]; /* vertices */
+ data= dl->verts;
+ idata= dl->index;
+ first= 0;
+
+ for(a=0; a<iv->datalen[0]; a++) {
+
+ /* vertices */
+ for(b=0; b<index[0]; b++) {
+ VECCOPY(data, fp);
+ data+= 3;
+ fp+= coordtype;
+ }
+
+ /* indices */
+ lll = index[0] - 2;
+ for(b=0; b<lll; b++) {
+ idata[0]= first;
+ idata[1]= first+1;
+ idata[2]= first+2;
+ first++;
+ idata+= 3;
+ }
+ first+= 2;
+
+ index++;
+ }
+ }
+ }
+ else if( strcmp(iv->nodename, "IndexedFaceSet")==0 ) {
+
+ colnr= iv_colornumber(iv);
+
+ /* seek back to data */
+ ivp= iv;
+ while(ivp->prev) {
+ ivp= ivp->prev;
+ if( strcmp(ivp->nodename, "Coordinate3")==0 ) {
+ coordtype= 3;
+ break;
+ }
+ if( strcmp(ivp->nodename, "Coordinate4")==0 ) {
+ coordtype= 4;
+ break;
+ }
+ }
+ if(ivp) {
+
+ /* count triangles */
+ face= 0;
+ index= iv->data[0];
+ lll = iv->datalen[0]-2;
+ for(a=0; a<lll; a++) {
+ if(index[0]!= -1 && index[1]!= -1 && index[2]!= -1) face++;
+ index++;
+ }
+
+ /*number of vertices */
+ tot= ivp->datalen[0]/coordtype;
+
+ if(tot) {
+ dl= MEM_callocN(sizeof(struct DispList), "leesInventor5");
+ BLI_addtail(listb, dl);
+ dl->type= DL_INDEX3;
+ dl->nr= tot;
+ dl->parts= face;
+ dl->col= colnr;
+
+ dl->verts= MEM_callocN( tot*3*sizeof(float), "dl verts");
+ dl->index= MEM_callocN(sizeof(int)*3*face, "dl index");
+
+ /* vertices */
+ fp= ivp->data[0];
+ data= dl->verts;
+ for(b=tot; b>0; b--) {
+ VECCOPY(data, fp);
+ data+= 3;
+ fp+= coordtype;
+ }
+
+ /* indices */
+ index= iv->data[0];
+ idata= dl->index;
+ first= 1;
+ lll=iv->datalen[0]-2;
+ for(a=0; a<lll; a++) {
+
+ if(index[0]!= -1 && index[1]!= -1 && index[2]!= -1) {
+
+ /* this trick is to fill poly's with more than 3 vertices correctly */
+ if(first) {
+ nr= (int) index[0];
+ first= 0;
+ }
+ idata[0]= nr;
+ idata[1]= (int) index[1];
+ idata[2]= (int) index[2];
+ idata+= 3;
+ }
+ else first= 1;
+
+ index++;
+ }
+ }
+ }
+ }
+ else if( strcmp(iv->nodename, "IndexedTriangleMesh")==0 ||
+ strcmp(iv->nodename, "IndexedTriangleStripSet")==0 ) {
+
+ colnr= iv_colornumber(iv);
+
+ /* seek back to data */
+ ivp= iv;
+ while(ivp->prev) {
+ ivp= ivp->prev;
+ if( strcmp(ivp->nodename, "Coordinate3")==0 ) {
+ coordtype= 3;
+ break;
+ }
+ if( strcmp(ivp->nodename, "Coordinate4")==0 ) {
+ coordtype= 4;
+ break;
+ }
+ }
+ if(ivp) {
+
+ /* count triangles */
+ face= 0;
+ index= iv->data[0];
+ lll=iv->datalen[0]-2;
+ for(a=0; a<lll; a++) {
+ if(index[0]!= -1 && index[1]!= -1 && index[2]!= -1) face++;
+ index++;
+ }
+
+ /* nr of vertices */
+ tot= ivp->datalen[0]/coordtype;
+
+ dl= MEM_callocN(sizeof(struct DispList), "leesInventor6");
+ BLI_addtail(listb, dl);
+ dl->type= DL_INDEX3;
+ dl->nr= tot;
+ dl->parts= face;
+ dl->col= colnr;
+
+ dl->verts= MEM_callocN( tot*3*sizeof(float), "dl verts");
+ dl->index= MEM_callocN(sizeof(int)*3*face, "dl index");
+
+ /* vertices */
+ fp= ivp->data[0];
+ data= dl->verts;
+ for(b=tot; b>0; b--) {
+ VECCOPY(data, fp);
+ data+= 3;
+ fp+= coordtype;
+ }
+
+ /* indices */
+ index= iv->data[0];
+ idata= dl->index;
+
+ lll=iv->datalen[0]-2;
+ for(a=lll; a>0; a--) {
+
+ if(index[0]!= -1 && index[1]!= -1 && index[2]!= -1) {
+ idata[0]= (int) index[0];
+ idata[1]= (int) index[1];
+ idata[2]= (int) index[2];
+ idata+= 3;
+ }
+ index++;
+ }
+ }
+ }
+ else if( strcmp(iv->nodename, "QuadMesh")==0 ) {
+
+ colnr= iv_colornumber(iv);
+
+ /* seek back to data */
+ ivp= iv;
+ while(ivp->prev) {
+ ivp= ivp->prev;
+ if( strcmp(ivp->nodename, "Coordinate3")==0 ) {
+ coordtype= 3;
+ break;
+ }
+ if( strcmp(ivp->nodename, "VertexProperty")==0 ) {
+ coordtype= 3;
+ break;
+ }
+ if( strcmp(ivp->nodename, "Coordinate4")==0 ) {
+ coordtype= 4;
+ break;
+ }
+ }
+
+ if(ivp) {
+ tot= (int) (floor(*(iv->data[0])+0.5) * floor(*(iv->data[1])+0.5));
+
+ if(tot>0) {
+ dl= MEM_callocN(sizeof(struct DispList)+tot*3*sizeof(float), "leesInventor8");
+ BLI_addtail(listb, dl);
+ dl->type= DL_SURF;
+ dl->parts= (int) floor(*(iv->data[0])+0.5);
+ dl->nr= (int) floor(*(iv->data[1])+0.5);
+ dl->col= colnr;
+ data= (float *)(dl+1);
+ memcpy(data, ivp->data[0], tot*3*sizeof(float));
+ }
+ }
+ }
+ else if(strcmp(iv->nodename, "IndexedNurbsSurface")==0 || strcmp(iv->nodename, "NurbsSurface")==0) {
+
+ colnr= iv_colornumber(iv);
+
+ /* sek back to data */
+ ivp= iv;
+ while(ivp->prev) {
+ ivp= ivp->prev;
+ if( strcmp(ivp->nodename, "Coordinate3")==0 ) {
+ coordtype= 3;
+ break;
+ }
+ if( strcmp(ivp->nodename, "Coordinate4")==0 ) {
+ coordtype= 4;
+ break;
+ }
+ }
+ if(ivp) {
+ a= (int) *(iv->data[0]);
+ b= (int) *(iv->data[1]);
+
+ tot= a*b;
+
+ if( (a>=4 || b>=4) && tot>6) {
+ Object *ob;
+ Curve *cu;
+ Nurb *nu;
+ BPoint *bp;
+
+ if(ivsurf==0) {
+ ob= add_object(OB_SURF);
+ ivsurf= ob;
+ }
+ else ob= ivsurf;
+ cu= ob->data;
+ nu = (Nurb*) MEM_callocN(sizeof(Nurb),"addNurbprim") ;
+ BLI_addtail(&cu->nurb, nu);
+ nu->type= CU_NURBS;
+
+ nu->pntsu= a;
+ nu->pntsv= b;
+ nu->resolu= 2*a;
+ nu->resolv= 2*b;
+
+ nu->flagu= 0;
+ nu->flagv= 0;
+
+ nu->bp = bp =
+ (BPoint*)MEM_callocN(tot * sizeof(BPoint), "addNurbprim3");
+ a= tot;
+ data= ivp->data[0];
+ while(a--) {
+ VECCOPY(bp->vec, data);
+ if(coordtype==4) {
+ bp->vec[3]= data[3];
+ VecMulf(bp->vec, 1.0f/data[3]);
+ }
+ else bp->vec[3]= 1.0;
+ data+= coordtype;
+ bp++;
+ }
+
+ /* iv->datalen[2] / [3] is number of knots */
+ nu->orderu= iv->datalen[2] - nu->pntsu;
+ nu->orderv= iv->datalen[3] - nu->pntsv;
+
+ nu->knotsu= MEM_mallocN( sizeof(float)*(iv->datalen[2]), "knots");
+ memcpy(nu->knotsu, iv->data[2], sizeof(float)*(iv->datalen[2]));
+ nu->knotsv= MEM_mallocN( sizeof(float)*(iv->datalen[3]), "knots");
+ memcpy(nu->knotsv, iv->data[3], sizeof(float)*(iv->datalen[3]));
+
+ switchdirectionNurb(nu);
+
+ }
+ else {
+ dl= MEM_callocN(sizeof(struct DispList)+tot*3*sizeof(float), "leesInventor3");
+ BLI_addtail(listb, dl);
+ dl->type= DL_SURF;
+ dl->nr= (int) *(iv->data[0]);
+ dl->parts= (int) *(iv->data[1]);
+ dl->col= colnr;
+ data= (float *)(dl+1);
+
+ a= tot;
+ fp= ivp->data[0];
+ while(a--) {
+ VECCOPY(data, fp);
+ fp+= coordtype;
+ data+= 3;
+ }
+ }
+ }
+ }
+ iv= iv->next;
+ }
+
+ /* free */
+ iv= ivbase.first;
+ while(iv) {
+ for(a=0; a<IV_MAXFIELD; a++) {
+ if(iv->data[a]) MEM_freeN(iv->data[a]);
+ }
+ iv= iv->next;
+ }
+
+ BLI_freelistN(&ivbase);
+ MEM_freeN(maindata);
+ MEM_freeN(iv_data_stack);
+
+}
+
+/* ************************************************************ */
+
+static void displist_to_mesh(DispList *dlfirst)
+{
+ Object *ob;
+ Mesh *me;
+ Material *ma;
+ DispList *dl;
+ MVert *mvert;
+ MFace *mface;
+ float *data, vec[3], min[3], max[3];
+ int a, b, startve, *idata, totedge=0, tottria=0, totquad=0, totvert=0, totface, totcol=0, colnr;
+ int p1, p2, p3, p4;
+ unsigned int maxvertidx;
+
+ /* count first */
+ INIT_MINMAX(min, max);
+
+ dl= dlfirst;
+ while(dl) {
+
+ /* PATCH 1 (polyfill) can't be done, there's no listbase here. do that first! */
+ /* PATCH 2 */
+ if(dl->type==DL_SEGM && dl->nr>2) {
+ data= (float *)(dl+1);
+ if(data[0]==data[3*(dl->nr-1)]) {
+ if(data[1]==data[3*(dl->nr-1)+1]) {
+ if(data[2]==data[3*(dl->nr-1)+2]) {
+ dl->type= DL_POLY;
+ dl->nr--;
+ }
+ }
+ }
+ }
+
+ /* colors */
+ if(dl->col > totcol) totcol= dl->col;
+
+ /* size and count */
+ if(dl->type==DL_SURF) {
+ a= dl->nr;
+ b= dl->parts;
+ if(dl->flag & DL_CYCL_U) a++;
+ if(dl->flag & DL_CYCL_V) b++;
+
+ totquad+= a*b;
+
+ totvert+= dl->nr*dl->parts;
+
+ data= (float *)(dl+1);
+ for(a= dl->nr*dl->parts; a>0; a--) {
+ DO_MINMAX(data, min, max);
+ data+= 3;
+ }
+ }
+ else if(dl->type==DL_POLY) {
+ if(dl->nr==3 || dl->nr==4) {
+ if(dl->nr==3) tottria+= dl->parts;
+ else totquad+= dl->parts;
+
+ totvert+= dl->nr*dl->parts;
+
+ data= (float *)(dl+1);
+ for(a= dl->nr*dl->parts; a>0; a--) {
+ DO_MINMAX(data, min, max);
+ data+= 3;
+ }
+ }
+ else if(dl->nr>4) {
+
+ tottria+= dl->nr*dl->parts;
+ totvert+= dl->nr*dl->parts;
+
+ data= (float *)(dl+1);
+ for(a= dl->nr*dl->parts; a>0; a--) {
+ DO_MINMAX(data, min, max);
+ data+= 3;
+ }
+
+ }
+ }
+ else if(dl->type==DL_INDEX3) {
+ tottria+= dl->parts;
+ totvert+= dl->nr;
+
+ data= dl->verts;
+ for(a= dl->nr; a>0; a--) {
+ DO_MINMAX(data, min, max);
+ data+= 3;
+ }
+ }
+ else if(dl->type==DL_SEGM) {
+
+ tottria+= (dl->nr-1)*dl->parts;
+ totvert+= dl->nr*dl->parts;
+
+ data= (float *)(dl+1);
+ for(a= dl->nr*dl->parts; a>0; a--) {
+ DO_MINMAX(data, min, max);
+ data+= 3;
+ }
+ }
+
+ dl= dl->next;
+ }
+
+ if(totvert==0) {
+ return;
+ }
+
+ if(totcol>16) {
+ error("Found more than 16 different colors");
+ totcol= 16;
+ }
+
+ vec[0]= (min[0]+max[0])/2;
+ vec[1]= (min[1]+max[1])/2;
+ vec[2]= (min[2]+max[2])/2;
+
+ ob= add_object(OB_MESH);
+ VECCOPY(ob->loc, vec);
+ where_is_object(ob);
+
+ me= ob->data;
+
+ /* colors */
+ if(totcol) {
+ ob->mat= MEM_callocN(sizeof(void *)*totcol, "ob->mat");
+ me->mat= MEM_callocN(sizeof(void *)*totcol, "me->mat");
+ me->totcol= totcol;
+ ob->totcol= (unsigned char) me->totcol;
+ ob->actcol= 1;
+ }
+
+ /* materials */
+ for(a=0; a<totcol; a++) {
+ ma= G.main->mat.first;
+ while(ma) {
+ if(ma->mtex[0]==0) {
+ if(ivcolors[a][0]==ma->r && ivcolors[a][1]==ma->g && ivcolors[a][2]==ma->b) {
+ me->mat[a]= ma;
+ ma->id.us++;
+ break;
+ }
+ }
+ ma= ma->id.next;
+ }
+ if(ma==0) {
+ ma= add_material("ext");
+ me->mat[a]= ma;
+ ma->r= ivcolors[a][0];
+ ma->g= ivcolors[a][1];
+ ma->b= ivcolors[a][2];
+ automatname(ma);
+ }
+ }
+
+ totface= totquad+tottria+totedge;
+
+ printf("Import: %d vertices %d faces\n", totvert, totface);
+
+ me->totvert= totvert;
+ me->totface= totface;
+ me->mvert= CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC,
+ NULL, me->totvert);
+ me->mface= CustomData_add_layer(&me->fdata, CD_MFACE, CD_CALLOC,
+ NULL, me->totface);
+ maxvertidx= totvert-1;
+
+ mvert= me->mvert;
+ mface= me->mface;
+
+ startve= 0;
+
+ dl= dlfirst;
+ while(dl) {
+
+ colnr= (dl->col>15 ? 15: dl->col);
+ if(colnr) colnr--;
+
+ if(dl->type==DL_SURF) {
+ data= (float *)(dl+1);
+
+ for(a=dl->parts*dl->nr; a>0; a--) {
+ mvert->co[0]= data[0] -vec[0];
+ mvert->co[1]= data[1] -vec[1];
+ mvert->co[2]= data[2] -vec[2];
+
+ data+=3;
+ mvert++;
+ }
+
+ for(a=0; a<dl->parts; a++) {
+
+ DL_SURFINDEX(dl->flag & DL_CYCL_U, dl->flag & DL_CYCL_V, dl->nr, dl->parts);
+ p1+= startve;
+ p2+= startve;
+ p3+= startve;
+ p4+= startve;
+
+ for(; b<dl->nr; b++) {
+
+ mface->v1= p1;
+ mface->v2= p2;
+ mface->v3= p4;
+ mface->v4= p3;
+
+ mface->mat_nr= colnr;
+ test_index_face(mface, NULL, 0, 4);
+
+ mface++;
+
+ p4= p3;
+ p3++;
+ p2= p1;
+ p1++;
+ }
+ }
+
+ startve += dl->parts*dl->nr;
+
+ }
+ else if(dl->type==DL_POLY) {
+
+ if(dl->nr==3 || dl->nr==4) {
+ data= (float *)(dl+1);
+
+ for(a=dl->parts*dl->nr; a>0; a--) {
+ mvert->co[0]= data[0] -vec[0];
+ mvert->co[1]= data[1] -vec[1];
+ mvert->co[2]= data[2] -vec[2];
+ data+=3;
+ mvert++;
+ }
+
+ for(a=0; a<dl->parts; a++) {
+ if(dl->nr==3) {
+ mface->v1= startve+a*dl->nr;
+ mface->v2= startve+a*dl->nr+1;
+ mface->v3= startve+a*dl->nr+2;
+ mface->mat_nr= colnr;
+ test_index_face(mface, NULL, 0, 3);
+ mface++;
+ }
+ else {
+ mface->v1= startve+a*dl->nr;
+ mface->v2= startve+a*dl->nr+1;
+ mface->v3= startve+a*dl->nr+2;
+ mface->v4= startve+a*dl->nr+3;
+ mface->mat_nr= colnr;
+ test_index_face(mface, NULL, 0, 4);
+ mface++;
+ }
+ }
+ startve += dl->parts*dl->nr;
+ }
+ else if(dl->nr>4) {
+ data= (float *)(dl+1);
+
+ for(a=dl->parts*dl->nr; a>0; a--) {
+ mvert->co[0]= data[0] -vec[0];
+ mvert->co[1]= data[1] -vec[1];
+ mvert->co[2]= data[2] -vec[2];
+
+ data+=3;
+ mvert++;
+ }
+
+ for(b=0; b<dl->parts; b++) {
+ for(a=0; a<dl->nr; a++) {
+ mface->v1= startve+a;
+
+ if(a==dl->nr-1) mface->v2= startve;
+ else mface->v2= startve+a+1;
+
+ mface->mat_nr= colnr;
+
+ mface++;
+ }
+ startve += dl->nr;
+ }
+ }
+ }
+ else if(dl->type==DL_INDEX3) {
+ data= dl->verts;
+
+ for(a=dl->nr; a>0; a--) {
+ mvert->co[0]= data[0] -vec[0];
+ mvert->co[1]= data[1] -vec[1];
+ mvert->co[2]= data[2] -vec[2];
+ data+=3;
+ mvert++;
+ }
+
+ idata= dl->index;
+ for(b=dl->parts; b>0; b--) {
+ mface->v1= startve+idata[0];
+ mface->v2= startve+idata[1];
+ mface->v3= startve+idata[2];
+ mface->mat_nr= colnr;
+
+ if (mface->v1>maxvertidx) mface->v1= maxvertidx;
+ if (mface->v2>maxvertidx) mface->v2= maxvertidx;
+ if (mface->v3>maxvertidx) mface->v3= maxvertidx;
+
+ test_index_face(mface, NULL, 0, 3);
+ mface++;
+ idata+= 3;
+ }
+ startve += dl->nr;
+ }
+ else if(dl->type==DL_SEGM) {
+ data= (float *)(dl+1);
+
+ for(a=dl->parts*dl->nr; a>0; a--) {
+ mvert->co[0]= data[0] -vec[0];
+ mvert->co[1]= data[1] -vec[1];
+ mvert->co[2]= data[2] -vec[2];
+ data+=3;
+ mvert++;
+ }
+
+ for(b=0; b<dl->parts; b++) {
+ for(a=0; a<dl->nr-1; a++) {
+ mface->v1= startve+a;
+ mface->v2= startve+a+1;
+ mface->mat_nr= colnr;
+ mface++;
+ }
+ startve += dl->nr;
+ }
+ }
+ dl= dl->next;
+ }
+
+ mesh_add_normals_flags(me);
+ make_edges(me, 0);
+}
+
+static void displist_to_objects(ListBase *lbase)
+{
+ DispList *dl, *first, *prev, *next;
+ ListBase tempbase;
+ int maxaantal, curcol, totvert=0, vert;
+
+ /* irst this: is still active */
+ if(ivsurf) {
+ where_is_object(ivsurf);
+ docenter_new();
+ }
+
+ dl= lbase->first;
+ while(dl) {
+ next= dl->next;
+
+ /* PATCH 1: polyfill */
+ if(dl->type==DL_POLY && dl->nr>4) {
+ /* solution: put them together in separate listbase */
+ ;
+ }
+ /* PATCH 2: poly's of 2 points */
+ if(dl->type==DL_POLY && dl->nr==2) dl->type= DL_SEGM;
+
+ dl= next;
+ }
+
+ /* count vertices */
+
+ dl= lbase->first;
+ while(dl) {
+
+ if(dl->type==DL_SURF) totvert+= dl->nr*dl->parts;
+ else if(dl->type==DL_POLY) {
+ if(dl->nr==3 || dl->nr==4) totvert+= dl->nr*dl->parts;
+ else if(dl->nr>4) totvert+= dl->nr*dl->parts;
+ }
+ else if(dl->type==DL_INDEX3) totvert+= dl->nr;
+ else if(dl->type==DL_SEGM) totvert+= dl->nr*dl->parts;
+
+ dl= dl->next;
+ }
+
+ if(totvert==0) {
+
+ if(ivsurf==0) error("Found no data");
+ if(lbase->first) BLI_freelistN(lbase);
+
+ return;
+ }
+
+ maxaantal= 32000;
+
+ if(totvert>maxaantal) {
+
+ /* try to put colors together */
+ curcol= 0;
+ tempbase.first= tempbase.last= 0;
+
+ while(lbase->first) {
+ dl= lbase->first;
+ while(dl) {
+ next= dl->next;
+ if(dl->col==curcol) {
+ BLI_remlink(lbase, dl);
+ BLI_addtail(&tempbase, dl);
+ dl->col= 0;
+ }
+
+ dl= next;
+ }
+
+ /* in tempbase are all 'curcol' */
+ totvert= 0;
+ dl= first= tempbase.first;
+ while(dl) {
+ vert= 0;
+
+ if(dl->type==DL_SURF) vert= dl->nr*dl->parts;
+ else if(dl->type==DL_POLY) {
+ if(dl->nr==3 || dl->nr==4) vert= dl->nr*dl->parts;
+ else if(dl->nr>4) vert= dl->nr*dl->parts;
+ }
+ else if(dl->type==DL_INDEX3) totvert+= dl->nr;
+ else if(dl->type==DL_SEGM) vert= dl->nr*dl->parts;
+
+ totvert+= vert;
+ if(totvert > maxaantal || dl->next==0) {
+ if(dl->next==0) {
+ displist_to_mesh(first);
+ }
+ else if(dl->prev) {
+ prev= dl->prev;
+ prev->next= 0;
+ displist_to_mesh(first);
+ prev->next= dl;
+ first= dl;
+ totvert= 0;
+ }
+ }
+
+ dl= dl->next;
+ }
+
+ freedisplist(&tempbase);
+
+ curcol++;
+ }
+ }
+ else displist_to_mesh(lbase->first);
+
+ freedisplist(lbase);
+
+}
+
+int BKE_read_exotic(char *name)
+{
+ ListBase lbase={0, 0};
+ int len;
+ gzFile gzfile;
+ char str[32];
+ int *s0 = (int*) str;
+ int retval = 0;
+
+ // make sure we're not trying to read a directory....
+
+ len= strlen(name);
+ if (name[len-1] !='/' && name[len-1] != '\\') {
+ gzfile = gzopen(name,"rb");
+
+ if (NULL == gzfile ) {
+ error("Can't open file: %s", name);
+ retval= -1;
+ } else {
+ gzread(gzfile, str, 31);
+ gzclose(gzfile);
+
+ if ((*s0 != FORM) && (strncmp(str, "BLEN", 4) != 0) && !BLI_testextensie(name,".blend.gz")) {
+
+ waitcursor(1);
+
+ if(*s0==GOUR) {
+ if(G.obedit) {
+ error("Unable to perform function in EditMode");
+ } else {
+ read_radiogour(name);
+ retval = 1;
+ }
+ }
+ else if ELEM4(*s0, DDG1, DDG2, DDG3, DDG4) {
+ if(G.obedit) {
+ error("Unable to perform function in EditMode");
+ } else {
+ read_videoscape(name);
+ retval = 1;
+ }
+ }
+ else if(strncmp(str, "#Inventor V1.0", 14)==0) {
+ if( strncmp(str+15, "ascii", 5)==0) {
+ read_inventor(name, &lbase);
+ displist_to_objects(&lbase);
+ retval = 1;
+ } else {
+ error("Can only read Inventor 1.0 ascii");
+ }
+ }
+ else if((strncmp(str, "#VRML V1.0 asc", 14)==0)) {
+ read_inventor(name, &lbase);
+ displist_to_objects(&lbase);
+ retval = 1;
+ }
+ else if(is_dxf(name)) {
+ dxf_read(name);
+ retval = 1;
+ }
+ else if(is_stl(name)) {
+ if (is_stl_ascii(name))
+ read_stl_mesh_ascii(name);
+ else
+ read_stl_mesh_binary(name);
+ retval = 1;
+ }
+ // TODO: this should not be in the kernel...
+ else { // unknown format, call Python importloader
+ if (BPY_call_importloader(name)) {
+ retval = 1;
+ } else {
+ error("Unknown file type or error, check console");
+ }
+
+ }
+ waitcursor(0);
+ }
+ }
+ }
+
+ return (retval);
+}
+
+
+/* ************************ WRITE ************************** */
+
+
+char temp_dir[160]= {0, 0};
+
+static void write_vert_stl(Object *ob, MVert *verts, int index, FILE *fpSTL)
+{
+ float vert[3];
+
+ VECCOPY(vert, verts[(index)].co);
+ Mat4MulVecfl(ob->obmat, vert);
+
+ if (G.order==B_ENDIAN) {
+ SWITCH_INT(vert[0]);
+ SWITCH_INT(vert[1]);
+ SWITCH_INT(vert[2]);
+ }
+
+ fwrite(vert, sizeof(float), 3, fpSTL);
+}
+
+static int write_derivedmesh_stl(FILE *fpSTL, Object *ob, DerivedMesh *dm)
+{
+ MVert *mvert = dm->getVertArray(dm);
+ MFace *mface = dm->getFaceArray(dm);
+ int i, numfacets = 0, totface = dm->getNumFaces(dm);
+ float zero[3] = {0.0f, 0.0f, 0.0f};
+
+ for (i=0; i<totface; i++, mface++) {
+ fwrite(zero, sizeof(float), 3, fpSTL);
+ write_vert_stl(ob, mvert, mface->v1, fpSTL);
+ write_vert_stl(ob, mvert, mface->v2, fpSTL);
+ write_vert_stl(ob, mvert, mface->v3, fpSTL);
+ fprintf(fpSTL, " ");
+ numfacets++;
+
+ if(mface->v4) { /* quad = 2 tri's */
+ fwrite(zero, sizeof(float), 3, fpSTL);
+ write_vert_stl(ob, mvert, mface->v1, fpSTL);
+ write_vert_stl(ob, mvert, mface->v3, fpSTL);
+ write_vert_stl(ob, mvert, mface->v4, fpSTL);
+ fprintf(fpSTL, " ");
+ numfacets++;
+ }
+ }
+
+ return numfacets;
+}
+
+static int write_object_stl(FILE *fpSTL, Object *ob, Mesh *me)
+{
+ int numfacets = 0;
+ DerivedMesh *dm = mesh_get_derived_final(ob, CD_MASK_BAREMESH);
+
+ numfacets += write_derivedmesh_stl(fpSTL, ob, dm);
+
+ dm->release(dm);
+
+ return numfacets;
+}
+
+void write_stl(char *str)
+{
+ Object *ob;
+ Mesh *me;
+ Base *base;
+ FILE *fpSTL;
+ int numfacets = 0;
+
+ if(BLI_testextensie(str,".blend")) str[ strlen(str)-6]= 0;
+ if(BLI_testextensie(str,".ble")) str[ strlen(str)-4]= 0;
+ if(BLI_testextensie(str,".stl")==0) strcat(str, ".stl");
+
+ if (!during_script()) {
+ if (BLI_exists(str))
+ if(saveover(str)==0)
+ return;
+ }
+
+ fpSTL= fopen(str, "wb");
+
+ if(fpSTL==NULL) {
+ if (!during_script()) error("Can't write file");
+ return;
+ }
+ strcpy(temp_dir, str);
+
+ waitcursor(1);
+
+ /* The header part of the STL */
+ /* First 80 characters are a title or whatever you want.
+ Lets make the first 32 of those spam and the rest the filename.
+ Those first 80 characters will be followed by 4 bytes
+ which will be overwritten later with an integer holding
+ how many facets are written (we set them to ' ' for now).
+ */
+ fprintf(fpSTL, "Binary STL output from Blender: %-48.48s ", str);
+
+ /* Write all selected mesh objects */
+ base= G.scene->base.first;
+ while(base) {
+ if (base->flag & SELECT) {
+ ob = base->object;
+ if (ob->type == OB_MESH) {
+ me = ob->data;
+ if (me)
+ numfacets += write_object_stl(fpSTL, ob, me);
+ }
+ }
+ base= base->next;
+ }
+
+ /* time to write the number of facets in the 4 bytes
+ starting at byte 81
+ */
+ fseek(fpSTL, 80, SEEK_SET);
+
+ if (G.order==B_ENDIAN) {
+ SWITCH_INT(numfacets);
+ }
+ fwrite(&numfacets, 4*sizeof(char), 1, fpSTL);
+
+ fclose(fpSTL);
+
+ waitcursor(0);
+}
+
+static void write_videoscape_mesh(Object *ob, char *str)
+{
+ EditMesh *em = G.editMesh;
+ Mesh *me;
+ Material *ma;
+ MFace *mface;
+ FILE *fp;
+ EditVert *eve;
+ EditFace *evl;
+ unsigned int kleur[32];
+ float co[3];
+ int a;
+ long tot;
+ char *cp;
+
+ if(ob && ob->type==OB_MESH);
+ else {
+ return;
+ }
+
+ kleur[0]= 0x00C0C0C0;
+
+ cp= (char *)kleur;
+ for(a=0; a<ob->totcol; a++, cp+=4) {
+
+ ma= give_current_material(ob, a+1);
+ if(ma) {
+ cp[0]= (unsigned char) (255.0*ma->emit);
+ cp[1]= (unsigned char) (255.0*ma->b);
+ cp[2]= (unsigned char) (255.0*ma->g);
+ cp[3]= (unsigned char) (255.0*ma->r);
+ if(G.order==L_ENDIAN) SWITCH_INT(kleur[a]);
+ }
+ else kleur[a]= 0x00C0C0C0;
+
+ if(a>30) break;
+ }
+
+ fp= fopen(str, "wb");
+ if(fp==NULL) return;
+
+ fprintf(fp,"3DG1\n");
+
+ if(G.obedit) {
+
+ fprintf(fp, "%d\n", G.totvert);
+
+ tot= 0;
+ eve= em->verts.first;
+ while(eve) {
+ VECCOPY(co, eve->co);
+ Mat4MulVecfl(ob->obmat, co);
+ fprintf(fp, "%f %f %f\n", co[0], co[1], co[2] );
+ eve->tmp.l = tot;
+ tot++;
+ eve= eve->next;
+ }
+ evl= em->faces.first;
+ while(evl) {
+
+ if(evl->v4==0) {
+ fprintf(fp, "3 %ld %ld %ld 0x%x\n",
+ evl->v1->tmp.l,
+ evl->v2->tmp.l,
+ evl->v3->tmp.l,
+ kleur[evl->mat_nr]);
+ }
+ else {
+ fprintf(fp, "4 %ld %ld %ld %ld 0x%x\n",
+ evl->v1->tmp.l,
+ evl->v2->tmp.l,
+ evl->v3->tmp.l,
+ evl->v4->tmp.l,
+ kleur[evl->mat_nr]);
+ }
+ evl= evl->next;
+ }
+ }
+ else {
+ DerivedMesh *dm = mesh_get_derived_deform(ob, CD_MASK_BAREMESH);
+
+ me= ob->data;
+
+ fprintf(fp, "%d\n", me->totvert);
+
+ mface= me->mface;
+ for(a=0; a<me->totvert; a++) {
+ dm->getVertCo(dm, a, co);
+ Mat4MulVecfl(ob->obmat, co);
+ fprintf(fp, "%f %f %f\n", co[0], co[1], co[2] );
+ }
+ for(a=0; a<me->totface; a++, mface++) {
+ if(mface->v4==0) {
+ fprintf(fp, "3 %d %d %d 0x%x\n", mface->v1, mface->v2, mface->v3, kleur[mface->mat_nr]);
+ }
+ else {
+ fprintf(fp, "4 %d %d %d %d 0x%x\n", mface->v1, mface->v2, mface->v3, mface->v4, kleur[mface->mat_nr]);
+ }
+ }
+
+ dm->release(dm);
+ }
+
+ fclose(fp);
+
+}
+
+
+void write_videoscape(char *str)
+{
+ Base *base;
+ int file, val, lampdone=0;
+ unsigned short numlen;
+ char head[FILE_MAXFILE], tail[FILE_MAXFILE];
+
+ if(BLI_testextensie(str,".trace")) str[ strlen(str)-6]= 0;
+ if(BLI_testextensie(str,".blend")) str[ strlen(str)-6]= 0;
+ if(BLI_testextensie(str,".ble")) str[ strlen(str)-4]= 0;
+ if(BLI_testextensie(str,".obj")==0) strcat(str, ".obj");
+
+ file= open(str,O_BINARY|O_RDONLY);
+ close(file);
+ if(file>-1) if(!during_script() && saveover(str)==0) return;
+
+ strcpy(temp_dir, str);
+
+ base= G.scene->base.first;
+ while(base) {
+ if((base->flag & SELECT) && (base->lay & G.scene->lay)) {
+ if(base->object->type==OB_MESH) {
+ write_videoscape_mesh(base->object, str);
+ val = BLI_stringdec(str, head, tail, &numlen);
+ BLI_stringenc(str, head, tail, numlen, val + 1);
+ }
+ else if(base->object->type==OB_CURVE || base->object->type==OB_SURF) {
+ /* write_videoscape_nurbs(base->object, str); */
+ /* val = stringdec(str, head, tail, &numlen); */
+ /* stringenc(str, head, tail, numlen, val + 1); */
+ }
+ else if(lampdone==0 && base->object->type==OB_LAMP) {
+ /* lampdone= 1; */
+ /* write_videoscape_lamps(str); */
+ /* val = stringdec(str, head, tail, &numlen); */
+ /* stringenc(str, head, tail, numlen, val + 1); */
+ }
+ }
+ base= base->next;
+ }
+
+
+ /* remove when higher numbers exist */
+ while(remove(str)==0) {
+
+ val = BLI_stringdec(str, head, tail, &numlen);
+ BLI_stringenc(str, head, tail, numlen, val + 1);
+ }
+}
+
+/* ******************************* WRITE VRML ***************************** */
+
+static void replace_chars(char *str1, char *str2)
+{
+ int a= strlen(str2);
+
+ str1[a]= 0;
+ while(a--) {
+ if(str2[a]=='.' || str2[a]==' ') str1[a]= '_';
+ else str1[a]= str2[a];
+ }
+}
+
+
+static void write_material_vrml(FILE *fp, Material *ma)
+{
+ char str[32];
+
+ replace_chars(str, ma->id.name+2);
+
+ fprintf(fp, "\tDEF %s\n", str);
+ fprintf(fp, "\tMaterial {\n");
+
+ fprintf(fp, "\t\tdiffuseColor %f %f %f\n", ma->r, ma->g, ma->b);
+ fprintf(fp, "\t\tspecularColor %f %f %f\n", ma->specr, ma->specg, ma->specb);
+ fprintf(fp, "\t\tshininess %f \n", ((float)ma->har)/100.0);
+ fprintf(fp, "\t\ttransparency %f \n", 1.0-ma->alpha);
+
+ fprintf(fp, "\t}\n");
+
+}
+
+unsigned int *mcol_to_vcol(Mesh *me)
+{
+ MFace *mface;
+ unsigned int *mcol, *mcoln, *mcolmain;
+ int a;
+
+ if(me->totface==0 || me->mcol==0) return 0;
+
+ mcoln= mcolmain= MEM_mallocN(sizeof(int)*me->totvert, "mcoln");
+ mcol = (unsigned int *)me->mcol;
+ mface= me->mface;
+
+ for(a=me->totface; a>0; a--, mface++) {
+ mcoln[mface->v1]= mcol[0];
+ mcoln[mface->v2]= mcol[1];
+ mcoln[mface->v3]= mcol[2];
+ if(mface->v4) mcoln[mface->v4]= mcol[3];
+
+ mcol+= 4;
+ }
+
+ return mcolmain;
+}
+
+void mcol_to_rgba(unsigned int col, float *r, float *g, float *b, float *a)
+{
+ char *cp;
+
+ cp = (char *)&col;
+
+ *r= cp[3];
+ *r /= 255.0;
+
+ *g= cp[2];
+ *g /= 255.0;
+
+ *b= cp[1];
+ *b /= 255.0;
+
+ *a= cp[0];
+ *a /= 255.0;
+}
+
+static void write_mesh_vrml(FILE *fp, Mesh *me)
+{
+ Material *ma;
+ MVert *mvert;
+ MFace *mface;
+ MTFace *tface;
+ Image *ima;
+ int a, b, totcol, texind;
+ char str[32];
+
+ replace_chars(str, me->id.name+2);
+
+ fprintf(fp, "\tDEF %s\n", str);
+ fprintf(fp, "\tSeparator {\n");
+
+ if(me->mtface) {
+ ima= ((MTFace *)me->mtface)->tpage;
+ if(ima) {
+ fprintf(fp, "\t\tTexture2 {\n");
+ fprintf(fp, "\t\t\tfilename %s\n", ima->name);
+ fprintf(fp, "\t\t\twrapS REPEAT \n");
+ fprintf(fp, "\t\t\twrapT REPEAT \n");
+ fprintf(fp, "\t\t}\n");
+ }
+ }
+
+ if(me->mcol) {
+ unsigned int *mcol, *mcolmain;
+ float r, g, b, cola;
+
+ fprintf(fp, "\t\tMaterial {\n");
+ fprintf(fp, "\t\t\tdiffuseColor [\n");
+
+ a= me->totvert;
+ mcol= mcolmain= mcol_to_vcol(me);
+ if(mcol) {
+ while(a--) {
+ mcol_to_rgba(*mcol, &r, &g, &b, &cola);
+ fprintf(fp, "\t\t\t\t %f %f %f,\n", r, g, b);
+ mcol++;
+ }
+ MEM_freeN(mcolmain);
+ }
+ fprintf(fp, "\t\t\t]\n");
+ fprintf(fp, "\t\t}\n");
+
+ fprintf(fp, "\t\tMaterialBinding { value PER_VERTEX_INDEXED }\n");
+ }
+
+
+ fprintf(fp, "\t\tCoordinate3 {\n");
+ fprintf(fp, "\t\t\tpoint [\n");
+
+ a= me->totvert;
+ mvert= me->mvert;
+ while(a--) {
+ fprintf(fp, "\t\t\t\t %f %f %f,\n", mvert->co[0], mvert->co[1], mvert->co[2]);
+ mvert++;
+ }
+ fprintf(fp, "\t\t\t]\n");
+ fprintf(fp, "\t\t}\n");
+
+
+ totcol= me->totcol;
+ if(totcol==0) totcol= 1;
+ texind= 0; // index for uv coords
+
+ for(b=0; b<totcol; b++) {
+
+ if(me->mcol==0) {
+ if(me->mat) {
+ ma= me->mat[b];
+ if(ma) {
+ replace_chars(str, ma->id.name+2);
+
+ fprintf(fp, "\t\tUSE %s\n\n", str);
+ }
+ }
+ }
+
+ if(me->mtface) {
+ fprintf(fp, "\t\tTextureCoordinate2 {\n");
+ fprintf(fp, "\t\t\tpoint [\n");
+
+ a= me->totface;
+ mface= me->mface;
+ tface= me->mtface;
+ while(a--) {
+ if(mface->mat_nr==b) {
+ fprintf(fp, "\t\t\t\t %f %f,\n", tface->uv[0][0], tface->uv[0][1]);
+ fprintf(fp, "\t\t\t\t %f %f,\n", tface->uv[1][0], tface->uv[1][1]);
+ fprintf(fp, "\t\t\t\t %f %f,\n", tface->uv[2][0], tface->uv[2][1]);
+ if(mface->v4) fprintf(fp, "\t\t\t\t %f %f,\n", tface->uv[3][0], tface->uv[3][1]);
+ }
+ mface++;
+ tface++;
+ }
+ fprintf(fp, "\t\t\t]\n");
+ fprintf(fp, "\t\t}\n");
+ }
+
+ fprintf(fp, "\t\tIndexedFaceSet {\n");
+ fprintf(fp, "\t\t\tcoordIndex [\n");
+
+ a= me->totface;
+ mface= me->mface;
+ while(a--) {
+ if(mface->mat_nr==b) {
+ if(mface->v4) fprintf(fp, "\t\t\t\t %d, %d, %d, %d, -1,\n", mface->v1, mface->v2, mface->v3, mface->v4);
+ else fprintf(fp, "\t\t\t\t %d, %d, %d, -1,\n", mface->v1, mface->v2, mface->v3);
+ }
+ mface++;
+ }
+ fprintf(fp, "\t\t\t]\n");
+
+ if(me->mtface) {
+ fprintf(fp, "\t\t\ttextureCoordIndex [\n");
+
+ a= me->totface;
+ mface= me->mface;
+ while(a--) {
+ if(mface->mat_nr==b) {
+ if(mface->v4) {
+ fprintf(fp, "\t\t\t\t %d, %d, %d, %d, -1,\n", texind, texind+1, texind+2, texind+3);
+ texind+= 4;
+ }
+ else {
+ fprintf(fp, "\t\t\t\t %d, %d, %d, -1,\n", texind, texind+1, texind+2);
+ texind+= 3;
+ }
+ }
+ mface++;
+ }
+ fprintf(fp, "\t\t\t]\n");
+ }
+ fprintf(fp, "\t\t}\n");
+ }
+
+ fprintf(fp, "\t}\n");
+}
+
+static void write_camera_vrml(FILE *fp, Object *ob)
+{
+ Camera *cam;
+
+ if(ob==0) return;
+ Mat4Invert(ob->imat, ob->obmat);
+
+ fprintf(fp, "\tMatrixTransform {\n");
+
+ fprintf(fp, "\tmatrix \n");
+
+ fprintf(fp, "\t\t%f %f %f %f\n", ob->imat[0][0], ob->imat[0][1], ob->imat[0][2], ob->imat[0][3]);
+ fprintf(fp, "\t\t%f %f %f %f\n", ob->imat[1][0], ob->imat[1][1], ob->imat[1][2], ob->imat[1][3]);
+ fprintf(fp, "\t\t%f %f %f %f\n", ob->imat[2][0], ob->imat[2][1], ob->imat[2][2], ob->imat[2][3]);
+ fprintf(fp, "\t\t%f %f %f %f\n", ob->imat[3][0], ob->imat[3][1], ob->imat[3][2], ob->imat[3][3]);
+
+ fprintf(fp, "\t}\n");
+
+ cam= ob->data;
+
+ fprintf(fp, "\tPerspectiveCamera {\n");
+ fprintf(fp, "\t\tfocalDistance %f\n", cam->lens/10.0);
+
+ fprintf(fp, "\t}\n");
+
+}
+
+static void write_object_vrml(FILE *fp, Object *ob)
+{
+ ID *id;
+ char str[32];
+
+ fprintf(fp, "\tSeparator {\n");
+ fprintf(fp, "\t\tMatrixTransform {\n");
+
+ fprintf(fp, "\t\tmatrix \n");
+
+ fprintf(fp, "\t\t\t%f %f %f %f\n", ob->obmat[0][0], ob->obmat[0][1], ob->obmat[0][2], ob->obmat[0][3]);
+ fprintf(fp, "\t\t\t%f %f %f %f\n", ob->obmat[1][0], ob->obmat[1][1], ob->obmat[1][2], ob->obmat[1][3]);
+ fprintf(fp, "\t\t\t%f %f %f %f\n", ob->obmat[2][0], ob->obmat[2][1], ob->obmat[2][2], ob->obmat[2][3]);
+ fprintf(fp, "\t\t\t%f %f %f %f\n", ob->obmat[3][0], ob->obmat[3][1], ob->obmat[3][2], ob->obmat[3][3]);
+
+ fprintf(fp, "\t\t}\n");
+
+ id= ob->data;
+
+ replace_chars(str, id->name+2);
+
+ fprintf(fp, "\t\tUSE %s\n", str);
+ fprintf(fp, "\t}\n");
+}
+
+
+void write_vrml(char *str)
+{
+ Mesh *me;
+ Material *ma;
+ Base *base;
+ FILE *fp;
+
+ if(BLI_testextensie(str,".blend")) str[ strlen(str)-6]= 0;
+ if(BLI_testextensie(str,".ble")) str[ strlen(str)-4]= 0;
+ if(BLI_testextensie(str,".wrl")==0) strcat(str, ".wrl");
+
+ if(!during_script() && saveover(str)==0) return;
+
+ fp= fopen(str, "w");
+
+ if(fp==NULL && !during_script()) {
+ error("Can't write file");
+ return;
+ }
+ strcpy(temp_dir, str);
+
+ waitcursor(1);
+
+ /* FIRST: write all the datablocks */
+
+ fprintf(fp, "#VRML V1.0 ascii\n\n# Blender V%d\n\n# 'Switch' is used as a hack, to ensure it is not part of the drawing\n\n", G.version);
+ fprintf(fp, "Separator {\n");
+ fprintf(fp, "Switch {\n");
+
+ ma= G.main->mat.first;
+ while(ma) {
+ if(ma->id.us) {
+ write_material_vrml(fp, ma);
+ }
+ ma= ma->id.next;
+ }
+
+ /* only write meshes we're using in this scene */
+ flag_listbase_ids(&G.main->mesh, LIB_DOIT, 0);
+
+ for(base= G.scene->base.first; base; base= base->next)
+ if(base->object->type== OB_MESH)
+ ((ID *)base->object->data)->flag |= LIB_DOIT;
+
+ me= G.main->mesh.first;
+ while(me) {
+ if(me->id.flag & LIB_DOIT) { /* is the mesh used in this scene ? */
+ write_mesh_vrml(fp, me);
+ }
+ me= me->id.next;
+ }
+
+ /* THEN:Hidden Objects */
+ fprintf(fp, "\n\t# Hidden Objects, in invisible layers\n\n");
+ base= G.scene->base.first;
+ while(base) {
+ if(base->object->type== OB_MESH) {
+ if( (base->lay & G.scene->lay)==0 ) {
+ write_object_vrml(fp, base->object);
+ }
+ }
+ base= base->next;
+ }
+
+ fprintf(fp, "}\n");
+ fprintf(fp, "\n# Visible Objects\n\n");
+ fprintf(fp, "Separator {\n");
+
+ /* The camera */
+
+ write_camera_vrml(fp, G.scene->camera);
+
+ /* THEN:The Objects */
+
+ base= G.scene->base.first;
+ while(base) {
+ if(base->object->type== OB_MESH) {
+ if(base->lay & G.scene->lay) {
+ write_object_vrml(fp, base->object);
+ }
+ }
+ base= base->next;
+ }
+
+ fprintf(fp, "}\n");
+ fprintf(fp, "}\n");
+
+ fclose(fp);
+
+ waitcursor(0);
+}
+
+
+/* ******************************* WRITE DXF ***************************** */
+
+#define write_group(id,data) fprintf(fp, "%d\n%s\n", id, data)
+
+/* A completely wacky function to try and make good
+indexed (AutoCAD index) values out of straight rgb
+ones... crazy */
+
+static int rgb_to_dxf_col (float rf, float gf, float bf)
+{
+ int r= (int) (rf*255.0f);
+ int g= (int) (gf*255.0f);
+ int b= (int) (bf*255.0f);
+ float h,s,v;
+ int ret;
+
+ /* Grayscale value */
+ if (((int)r/10)==((int)g/10) && ((int)g/10)==((int)b/10)) ret= 250+((int)r/51);
+ /* A nice chroma value */
+ else {
+ rgb_to_hsv (rf,gf,bf,&h,&s,&v);
+
+ ret= (int) (10.0f + (h*239.0f));
+ CLAMP(ret,10,249);
+
+ /* If its whitish make the index odd */
+ if (s<.5 || v>.5) if(ret%2) ret++;
+ }
+
+ return ret;
+}
+
+/* And its completely wacky complement */
+
+static void dxf_col_to_rgb (int cid, float *rf, float *gf, float *bf)
+{
+ float h, s, v;
+
+ /* Grayscale values */
+ if (cid>=250 && cid <= 255) {
+ *rf= *gf= *bf= (float) ((cid-250)*51)/255;
+ CLAMP(*rf, 0.0, 1.0);
+ CLAMP(*gf, 0.0, 1.0);
+ CLAMP(*bf, 0.0, 1.0);
+
+ /* Pure values */
+ } else if (cid<10) {
+ switch (cid) {
+ case 1:
+ *rf=1.0;
+ *gf=0.0;
+ *bf=0.0;
+ break;
+ case 2:
+ *rf=1.0;
+ *gf=1.0;
+ *bf=0.0;
+ break;
+ case 3:
+ *gf=1.0;
+ *rf=0.0;
+ *bf=0.0;
+ break;
+ case 4:
+ *rf=0.0;
+ *gf=1.0;
+ *bf=1.0;
+ break;
+ case 5:
+ *rf=0.0;
+ *gf=0.0;
+ *bf=1.0;
+ break;
+ case 6:
+ *rf=1.0;
+ *gf=0.0;
+ *bf=1.0;
+ break;
+ case 7:
+ default:
+ *rf= *gf= *bf= 1.0;
+ break;
+ }
+ } else {
+ /* Get chroma values */
+
+ h= (float) (cid-10)/239;
+ CLAMP(h, 0.0, 1.0);
+
+ /* If its odd make it a bit whitish */
+ if (cid%2) { s=.75; v= 0.25;
+ } else { s= 0.25; v= 0.75;}
+
+ hsv_to_rgb (h, s, v, rf, gf, bf);
+ }
+}
+
+static void write_mesh_dxf(FILE *fp, Mesh *me)
+{
+ Material *ma;
+ MVert *mvert;
+ MFace *mface;
+ int a;
+ char str[32];
+
+ replace_chars(str, me->id.name+2);
+
+ write_group(0, "BLOCK");
+
+ write_group(2, str); /* The name */
+
+ write_group(8, "Meshes"); /* DXF Layer */
+ write_group(70, "64"); /* DXF block flags */
+
+ write_group(10, "0.0"); /* X of base */
+ write_group(20, "0.0"); /* Y of base */
+ write_group(30, "0.0"); /* Z of base */
+
+ write_group(3, str); /* The name (again) */
+
+ write_group(0, "POLYLINE"); /* Start the mesh */
+ write_group(66, "1"); /* Vertices follow flag */
+ write_group(8,"Meshes"); /* DXF Layer */
+
+ if (me->totcol) {
+ ma= me->mat[0];
+ if(ma) {
+ sprintf(str,"%d",rgb_to_dxf_col(ma->r,ma->g,ma->b));
+ write_group(62, str); /* Color index */
+ }
+ }
+
+ write_group(70, "64"); /* Polymesh mesh flag */
+
+ fprintf(fp, "71\n%d\n", me->totvert); /* Total vertices */
+ fprintf(fp, "72\n%d\n", me->totface); /* Total faces */
+
+ /* Write the vertices */
+ a= me->totvert;
+ mvert= me->mvert;
+ while(a--) {
+ write_group(0, "VERTEX"); /* Start a new vertex */
+ write_group(8, "Meshes"); /* DXF Layer */
+ fprintf (fp, "10\n%f\n", mvert->co[0]); /* X cord */
+ fprintf (fp, "20\n%f\n", mvert->co[1]); /* Y cord */
+ fprintf (fp, "30\n%f\n", mvert->co[2]); /* Z cord */
+ write_group(70, "192"); /* Polymesh vertex flag */
+
+ mvert++;
+ }
+
+ /* Write the face entries */
+ a= me->totface;
+ mface= me->mface;
+ while(a--) {
+ write_group(0, "VERTEX"); /* Start a new face */
+ write_group(8, "Meshes");
+
+ /* Write a face color */
+ if (me->totcol) {
+ ma= me->mat[mface->mat_nr];
+ if(ma) {
+ sprintf(str,"%d",rgb_to_dxf_col(ma->r,ma->g,ma->b));
+ write_group(62, str); /* Color index */
+ }
+ }
+ else write_group(62, "254"); /* Color Index */
+
+ /* Not sure what this really corresponds too */
+ write_group(10, "0.0"); /* X of base */
+ write_group(20, "0.0"); /* Y of base */
+ write_group(30, "0.0"); /* Z of base */
+
+ write_group(70, "128"); /* Polymesh face flag */
+
+ if(mface->v4) {
+ fprintf (fp, "71\n%d\n", mface->v1+1);
+ fprintf (fp, "72\n%d\n", mface->v2+1);
+ fprintf (fp, "73\n%d\n", mface->v3+1);
+ fprintf (fp, "74\n%d\n", mface->v4+1);
+ } else {
+ fprintf (fp, "71\n%d\n", mface->v1+1);
+ fprintf (fp, "72\n%d\n", mface->v2+1);
+ fprintf (fp, "73\n%d\n", mface->v3+1);
+ }
+ mface++;
+ }
+
+ write_group(0, "SEQEND");
+
+ write_group(0, "ENDBLK");
+}
+
+static void write_object_dxf(FILE *fp, Object *ob, int layer)
+{
+ ID *id;
+ char str[32];
+
+ id= ob->data;
+
+ write_group(0, "INSERT"); /* Start an insert group */
+
+ sprintf(str, "%d", layer);
+ write_group(8, str);
+
+ replace_chars(str, id->name+2);
+ write_group(2, str);
+
+ fprintf (fp, "10\n%f\n", ob->loc[0]); /* X of base */
+ fprintf (fp, "20\n%f\n", ob->loc[1]); /* Y of base */
+ fprintf (fp, "30\n%f\n", ob->loc[2]); /* Z of base */
+
+ fprintf (fp, "41\n%f\n", ob->size[0]); /* X scale */
+ fprintf (fp, "42\n%f\n", ob->size[1]); /* Y scale */
+ fprintf (fp, "43\n%f\n", ob->size[2]); /* Z scale */
+
+ fprintf (fp, "50\n%f\n", (float) ob->rot[2]*180/M_PI); /* Can only write the Z rot */
+}
+
+void write_dxf(char *str)
+{
+ Mesh *me;
+ Base *base;
+ FILE *fp;
+
+ if(BLI_testextensie(str,".blend")) str[ strlen(str)-6]= 0;
+ if(BLI_testextensie(str,".ble")) str[ strlen(str)-4]= 0;
+ if(BLI_testextensie(str,".dxf")==0) strcat(str, ".dxf");
+
+ if (!during_script()) {
+ if (BLI_exists(str))
+ if(saveover(str)==0)
+ return;
+ }
+
+ fp= fopen(str, "w");
+
+ if(fp==NULL && !during_script()) {
+ error("Can't write file");
+ return;
+ }
+ strcpy(temp_dir, str);
+
+ waitcursor(1);
+
+ /* The header part of the DXF */
+
+ write_group(0, "SECTION");
+ write_group(2, "HEADER");
+ write_group(0, "ENDSEC");
+
+ /* The blocks part of the DXF */
+
+ write_group(0, "SECTION");
+ write_group(2, "BLOCKS");
+
+
+ /* only write meshes we're using in this scene */
+ flag_listbase_ids(&G.main->mesh, LIB_DOIT, 0);
+
+ for(base= G.scene->base.first; base; base= base->next)
+ if(base->object->type== OB_MESH)
+ ((ID *)base->object->data)->flag |= LIB_DOIT;
+
+ /* Write all the meshes */
+ me= G.main->mesh.first;
+ while(me) {
+ if(me->id.flag & LIB_DOIT) { /* is the mesh used in this scene ? */
+ write_mesh_dxf(fp, me);
+ }
+ me= me->id.next;
+ }
+
+ write_group(0, "ENDSEC");
+
+ /* The entities part of the DXF */
+
+ write_group(0, "SECTION");
+ write_group(2, "ENTITIES");
+
+ /* Write all the mesh objects */
+ base= G.scene->base.first;
+ while(base) {
+ if(base->object->type== OB_MESH) {
+ write_object_dxf(fp, base->object, base->lay);
+ }
+ base= base->next;
+ }
+
+ write_group(0, "ENDSEC");
+
+ /* Thats all */
+
+ write_group(0, "EOF");
+ fclose(fp);
+
+ waitcursor(0);
+}
+
+
+static int dxf_line= 0;
+static FILE *dxf_fp= NULL;
+
+/* exotic.c(2863) : note C6311: c:/Program Files/Microsoft Visual
+ * Studio/VC98/include\ctype.h(268) : see previous definition of
+ * 'iswspace' */
+#define ton_iswspace(c) (c==' '||c=='\n'||c=='\t')
+
+static void clean_wspace (char *str)
+{
+ char *from, *to;
+ char t;
+
+ from= str;
+ to=str;
+
+ while (*from!=0) {
+ t= *from;
+ *to= t;
+
+ if(!ton_iswspace(*from)) to++;
+ from++;
+ }
+ *to=0;
+}
+
+static int all_wspace(char *str)
+{
+ while(*str != 0) {
+ if (!ton_iswspace(*str)) return 0;
+ str++;
+ }
+
+ return 1;
+}
+
+static int all_digits(char *str)
+{
+ while(*str != 0) {
+ if (!isdigit(*str)) return 0;
+ str++;
+ }
+
+ return 1;
+}
+
+static int dxf_get_layer_col(char *layer)
+{
+ return 1;
+}
+
+static int dxf_get_layer_num(char *layer)
+{
+ int ret = 0;
+
+ if (all_digits(layer) && atoi(layer)<(1<<20)) ret= atoi(layer);
+ if (ret == 0) ret = G.scene->lay;
+
+ return ret;
+}
+
+static void dos_clean(char *str)
+{
+ while (*str) {
+ if (*str == 0x0d) {
+ *str='\n';
+ *(++str)= 0;
+ break;
+ }
+ str++;
+ }
+}
+
+static void myfgets(char *str, int len, FILE *fp)
+{
+ char c;
+
+ while(len>0 && (c=getc(dxf_fp)) ) {
+ *str= c;
+ str++;
+ len--;
+ /* three types of enters, \n \r and \r\n */
+ if(c == '\n') break;
+ if(c=='\r') {
+ c= getc(dxf_fp); // read the linefeed from stream
+ if(c != 10) ungetc(c, dxf_fp); // put back, if it's not one...
+ break;
+ }
+ }
+}
+
+static int read_groupf(char *str)
+{
+ short c;
+ int ret=-1;
+ char tmp[256];
+
+ strcpy(str, " ");
+
+ while ((c=getc(dxf_fp)) && ton_iswspace(c));
+ ungetc(c, dxf_fp);
+ if (c==EOF) return -1;
+
+ myfgets(tmp, 255, dxf_fp);
+
+ dos_clean(tmp);
+
+ if(sscanf(tmp, "%d\n", &ret)!=1) return -2;
+
+ myfgets(tmp, 255, dxf_fp);
+
+ dos_clean(tmp);
+
+ if (!all_wspace(tmp)) {
+ if (sscanf(tmp, "%s\n", str)!=1) return -2;
+ }
+
+ clean_wspace(str);
+ dxf_line+=2;
+
+ return ret;
+}
+
+#define id_test(id) if(id<0) {char errmsg[128];fclose(dxf_fp); if(id==-1) sprintf(errmsg, "Error inputting dxf, near line %d", dxf_line); else if(id==-2) sprintf(errmsg, "Error reading dxf, near line %d", dxf_line);error(errmsg); return;}
+
+#define read_group(id,str) {id= read_groupf(str); id_test(id);}
+
+#define group_is(idtst,str) (id==idtst&&strcmp(val,str)==0)
+#define group_isnt(idtst,str) (id!=idtst||strcmp(val,str)!=0)
+#define id_check(idtst,str) if(group_isnt(idtst,str)) { fclose(dxf_fp); error("Error parsing dxf, near line %d", dxf_line); return;}
+
+static int id;
+static char val[256];
+
+static short error_exit=0;
+static short hasbumped=0;
+
+static int is_dxf(char *str)
+{
+ dxf_line=0;
+
+ dxf_fp= fopen(str, "r");
+ if (dxf_fp==NULL) return 0;
+
+ id= read_groupf(val);
+ if ((id==0 && strcmp(val, "SECTION")==0)||id==999) return 1;
+
+ fclose(dxf_fp);
+
+ return 0;
+}
+
+/* NOTES ON THE READER */
+/*
+ --
+ It turns out that most DXF writers like (LOVE) to
+ write meshes as a long string of 3DFACE entities.
+ This means the natural way to read a DXF file
+ (every entity corresponds to an object) is completely
+ unusable, reading in 10,000 faces each as an
+ object just doesn't cut it. Thus the 3DFACE
+ entry reader holds state, and only finalizes to
+ an object when a) the layer name changes, b) the
+ entry type changes, c) we are done reading.
+
+ PS... I decided to do the same thing with LINES,
+ apparently the same thing happens sometimes as
+ well.
+
+ PPS... I decided to do the same thing with everything.
+ Now it is all really nasty and should be rewritten.
+ --
+
+ Added circular and elliptical arcs and lwpolylines.
+ These are all self-contained and have the size known
+ in advance, and so I haven't used the held state. -- martin
+*/
+
+static void dxf_add_mat (Object *ob, Mesh *me, float color[3], char *layer)
+{
+ Material *ma;
+
+ if (!me) return;
+
+ if(ob) ob->mat= MEM_callocN(sizeof(void *)*1, "ob->mat");
+ if(ob) ob->actcol= 1;
+
+ me->totcol= 1;
+ me->mat= MEM_callocN(sizeof(void *)*1, "me->mat");
+
+ if (color[0]<0) {
+ if (strlen(layer)) dxf_col_to_rgb(dxf_get_layer_col(layer), &color[0], &color[1], &color[2]);
+ color[0]= color[1]= color[2]= 0.8f;
+ }
+
+ ma= G.main->mat.first;
+ while(ma) {
+ if(ma->mtex[0]==0) {
+ if(color[0]==ma->r && color[1]==ma->g && color[2]==ma->b) {
+ me->mat[0]= ma;
+ ma->id.us++;
+ break;
+ }
+ }
+ ma= ma->id.next;
+ }
+ if(ma==0) {
+ ma= add_material("ext");
+ me->mat[0]= ma;
+ ma->r= color[0];
+ ma->g= color[1];
+ ma->b= color[2];
+ automatname(ma);
+ }
+}
+
+ /* General DXF vars */
+static float cent[3]={0.0, 0.0, 0.0};
+static char layname[32]="";
+static char entname[32]="";
+static float color[3]={-1.0, -1.0, -1.0};
+static float *vcenter;
+static float zerovec[3]= {0.0, 0.0, 0.0};
+
+#define reset_vars cent[0]= cent[1]= cent[2]=0.0; strcpy(layname, ""); color[0]= color[1]= color[2]= -1.0
+
+
+static void dxf_get_mesh(Mesh** m, Object** o, int noob)
+{
+ Mesh *me = NULL;
+ Object *ob;
+
+ if (!noob) {
+ *o = add_object(OB_MESH);
+ ob = *o;
+
+ if (strlen(entname)) new_id(&G.main->object, (ID *)ob, entname);
+ else if (strlen(layname)) new_id(&G.main->object, (ID *)ob, layname);
+
+ if (strlen(layname)) ob->lay= dxf_get_layer_num(layname);
+ else ob->lay= G.scene->lay;
+ // not nice i know... but add_object() sets active base, which needs layer setting too (ton)
+ G.scene->basact->lay= ob->lay;
+
+ *m = ob->data;
+ me= *m;
+
+ vcenter= ob->loc;
+ }
+ else {
+ *o = NULL;
+ *m = add_mesh("Mesh"); G.totmesh++;
+
+ me = *m;
+ ob = *o;
+
+ ((ID *)me)->us=0;
+
+ if (strlen(entname)) new_id(&G.main->mesh, (ID *)me, entname);
+ else if (strlen(layname)) new_id(&G.main->mesh, (ID *)me, layname);
+
+ vcenter = zerovec;
+ }
+ me->totvert=0;
+ me->totface=0;
+ me->mvert= CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, 0);
+ me->mface= CustomData_add_layer(&me->fdata, CD_MFACE, CD_CALLOC, NULL, 0);
+}
+
+static void dxf_read_point(int noob) {
+ /* Blender vars */
+ Object *ob;
+ Mesh *me;
+ MVert *mvert;
+
+ reset_vars;
+
+ read_group(id, val);
+ while(id!=0) {
+ if (id==8) {
+ BLI_strncpy(layname, val, sizeof(layname));
+ } else if (id==10) {
+ cent[0]= (float) atof(val);
+ } else if (id==20) {
+ cent[1]= (float) atof(val);
+ } else if (id==30) {
+ cent[2]= (float) atof(val);
+ } else if (id==60) {
+ /* short invisible= atoi(val); */
+ } else if (id==62) {
+ int colorid= atoi(val);
+
+ CLAMP(colorid, 1, 255);
+ dxf_col_to_rgb(colorid, &color[0], &color[1], &color[2]);
+ }
+ read_group(id, val);
+ }
+
+ dxf_get_mesh(&me, &ob, noob);
+ me->totvert= 1;
+ me->mvert= MEM_callocN(me->totvert*sizeof(MVert), "mverts");
+ CustomData_set_layer(&me->vdata, CD_MVERT, me->mvert);
+
+ dxf_add_mat (ob, me, color, layname);
+
+ mvert= me->mvert;
+ mvert->co[0]= mvert->co[1]= mvert->co[2]= 0;
+
+ if (ob) VECCOPY(ob->loc, cent);
+
+ hasbumped=1;
+}
+
+ /* Line state vars */
+static Object *linehold=NULL;
+static Mesh *linemhold=NULL;
+
+static char oldllay[32];
+static short lwasline=0; /* last was face 3d? */
+
+static void dxf_close_line(void)
+{
+ linemhold=NULL;
+ if (linehold==NULL) return;
+
+ linehold=NULL;
+}
+
+static void dxf_read_line(int noob) {
+ /* Entity specific vars */
+ float epoint[3]={0.0, 0.0, 0.0};
+ short vspace=0; /* Whether or not coords are relative */
+
+ /* Blender vars */
+ Object *ob;
+ Mesh *me;
+ MVert *mvert, *vtmp;
+ MFace *mface, *ftmp;
+
+ reset_vars;
+
+ read_group(id, val);
+ while(id!=0) {
+ if (id==8) {
+ BLI_strncpy(layname, val, sizeof(layname));
+ } else if (id==10) {
+ cent[0]= (float) atof(val);
+ } else if (id==20) {
+ cent[1]= (float) atof(val);
+ } else if (id==30) {
+ cent[2]= (float) atof(val);
+ } else if (id==11) {
+ epoint[0]= (float) atof(val);
+ } else if (id==21) {
+ epoint[1]= (float) atof(val);
+ } else if (id==31) {
+ epoint[2]= (float) atof(val);
+ } else if (id==60) {
+ /* short invisible= atoi(val); */
+ } else if (id==62) {
+ int colorid= atoi(val);
+
+ CLAMP(colorid, 1, 255);
+ dxf_col_to_rgb(colorid, &color[0], &color[1], &color[2]);
+ } else if (id==67) {
+ vspace= atoi(val);
+ }
+ read_group(id, val);
+ }
+
+ /* Check to see if we need to make a new object */
+
+ if(!lwasline || strcmp(layname, oldllay)!=0)
+ dxf_close_line();
+ if(linemhold != NULL && linemhold->totvert>MESH_MAX_VERTS)
+ dxf_close_line();
+
+ if (linemhold==NULL) {
+ dxf_get_mesh(&me, &ob, noob);
+
+ if(ob) VECCOPY(ob->loc, cent);
+
+ dxf_add_mat (ob, me, color, layname);
+
+ linehold= ob;
+ linemhold= me;
+ } else {
+ ob= linehold;
+ me= linemhold;
+ }
+
+ me->totvert+= 2;
+ me->totface++;
+
+ vtmp= MEM_callocN(me->totvert*sizeof(MVert), "mverts");
+ ftmp= MEM_callocN(me->totface*sizeof(MFace), "mface");
+
+ if(me->mvert) {
+ memcpy(vtmp, me->mvert, (me->totvert-2)*sizeof(MVert));
+ MEM_freeN(me->mvert);
+ }
+ me->mvert= CustomData_set_layer(&me->vdata, CD_MVERT, vtmp);
+ vtmp=NULL;
+
+ if(me->mface) {
+ memcpy(ftmp, me->mface, (me->totface-1)*sizeof(MFace));
+ MEM_freeN(me->mface);
+ }
+ me->mface= CustomData_set_layer(&me->fdata, CD_MFACE, ftmp);
+ ftmp=NULL;
+
+ mvert= &me->mvert[(me->totvert-2)];
+
+ VecSubf(mvert->co, cent, vcenter);
+ mvert++;
+ if (vspace) { VECCOPY(mvert->co, epoint);
+ } else VecSubf(mvert->co, epoint, vcenter);
+
+ mface= &(((MFace*)me->mface)[me->totface-1]);
+ mface->v1= me->totvert-2;
+ mface->v2= me->totvert-1;
+ mface->mat_nr= 0;
+
+ hasbumped=1;
+}
+
+ /* 2D Polyline state vars */
+static Object *p2dhold=NULL;
+static Mesh *p2dmhold=NULL;
+static char oldplay[32];
+static short lwasp2d=0;
+
+static void dxf_close_2dpoly(void)
+{
+ p2dmhold= NULL;
+ if (p2dhold==NULL) return;
+
+ p2dhold=NULL;
+}
+
+static void dxf_read_ellipse(int noob)
+{
+
+ /*
+ * The Parameter option of the ELLIPSE command uses the following equation to define an elliptical arc.
+ *
+ * p(u)=c+a*cos(u)+b*sin(u)
+ *
+ * The variables a, b, c are determined when you select the endpoints for the
+ * first axis and the distance for the second axis. a is the negative of 1/2
+ * of the major axis length, b is the negative of 1/2 the minor axis length,
+ * and c is the center point (2-D) of the ellipse.
+ *
+ * Because this is actually a vector equation and the variable c is actually
+ * a point with X and Y values, it really should be written as:
+ *
+ * p(u)=(Cx+a*cos(u))*i+(Cy+b*sin(u))*j
+ *
+ * where
+ *
+ * Cx is the X value of the point c
+ * Cy is the Y value of the point c
+ * a is -(1/2 of the major axis length)
+ * b is -(1/2 of the minor axis length)
+ * i and j represent unit vectors in the X and Y directions
+ *
+ * http://astronomy.swin.edu.au/~pbourke/geomformats/dxf2000/ellipse_command39s_parameter_option_dxf_06.htm
+ * (reproduced with permission)
+ *
+ * NOTE: The start and end angles ('parameters') are in radians, whereas those for the circular arc are
+ * in degrees. The 'sense' of u appears to be determined by the extrusion direction (see more detailed comment
+ * in the code)
+ *
+ * TODO: The code is specific to ellipses in the x-y plane right now.
+ *
+ */
+
+ /* Entity specific vars */
+ float epoint[3]={0.0, 0.0, 0.0};
+ float center[3]={0.0, 0.0, 0.0};
+ float extrusion[3]={0.0, 0.0, 1.0};
+ float axis_endpoint[3] = {0.0, 0.0, 0.0}; /* major axis endpoint */
+ short vspace=0; /* Whether or not coords are relative */
+ float a, b, x, y, z;
+ float phid = 0.0f, phi = 0.0f, theta = 0.0f;
+ float start_angle = 0.0f;
+ float end_angle = 2*M_PI;
+ float axis_ratio = 1.0f;
+ float temp;
+ int v, tot;
+ int isArc=0;
+ /* Blender vars */
+ Object *ob;
+ Mesh *me;
+ MVert *mvert;
+ MFace *mface;
+
+ reset_vars;
+ read_group(id, val);
+ while(id!=0) {
+ if (id==8) {
+ BLI_strncpy(layname, val, sizeof(layname));
+ } else if (id==10) {
+ center[0]= (float) atof(val);
+ } else if (id==20) {
+ center[1]= (float) atof(val);
+ } else if (id==30) {
+ center[2]= (float) atof(val);
+ } else if (id==11) {
+ axis_endpoint[0]= (float) atof(val);
+ } else if (id==21) {
+ axis_endpoint[1]= (float) atof(val);
+ } else if (id==31) {
+ axis_endpoint[2]= (float) atof(val);
+ } else if (id==40) {
+ axis_ratio = (float) atof(val);
+ } else if (id==41) {
+ printf("dxf: start = %f", atof(val) * 180/M_PI);
+ start_angle = -atof(val) + M_PI_2;
+ } else if (id==42) {
+ printf("dxf: end = %f", atof(val) * 180/M_PI);
+ end_angle = -atof(val) + M_PI_2;
+ } else if (id==62) {
+ int colorid= atoi(val);
+ CLAMP(colorid, 1, 255);
+ dxf_col_to_rgb(colorid, &color[0], &color[1], &color[2]);
+ } else if (id==67) {
+ vspace= atoi(val);
+ } else if (id==100) {
+ isArc = 1;
+ } else if (id==210) {
+ extrusion[0] = atof(val);
+ } else if (id==220) {
+ extrusion[1] = atof(val);
+ } else if (id==230) {
+ extrusion[2] = atof(val);
+ }
+ read_group(id, val);
+ }
+
+ if(!lwasline || strcmp(layname, oldllay)!=0) dxf_close_line();
+ if(linemhold != NULL && linemhold->totvert>MESH_MAX_VERTS)
+ dxf_close_line();
+
+ /* The 'extrusion direction' seems akin to a face normal,
+ * insofar as it determines the direction of increasing phi.
+ * This is again x-y plane specific; it should be fixed at
+ * some point. */
+
+ if (extrusion[2] < 0) {
+ temp = start_angle;
+ start_angle = M_PI - end_angle;
+ end_angle = M_PI - temp;
+ }
+
+ if(end_angle > start_angle)
+ end_angle -= 2 * M_PI;
+
+ phi = start_angle;
+
+ x = axis_endpoint[0];
+ y = axis_endpoint[1];
+ z = axis_endpoint[2];
+ a = sqrt(x*x + y*y + z*z);
+ b = a * axis_ratio;
+
+ theta = atan2(y, x);
+
+ x = a * sin(phi);
+ y = b * cos(phi);
+
+#ifndef DEBUG_CENTER
+ epoint[0] = center[0] + x*cos(theta) - y*sin(theta);
+ epoint[1] = center[1] + x*sin(theta) + y*cos(theta);
+ epoint[2] = center[2];
+
+
+ cent[0]= epoint[0];
+ cent[1]= epoint[1];
+ cent[2]= epoint[2];
+#else
+ cent[0]= center[0];
+ cent[1]= center[1];
+ cent[2]= center[2];
+#endif
+
+ dxf_get_mesh(&me, &ob, noob);
+ strcpy(oldllay, layname);
+ if(ob) VECCOPY(ob->loc, cent);
+ dxf_add_mat (ob, me, color, layname);
+
+ tot = 32; /* # of line segments to divide the arc into */
+
+ phid = (end_angle - start_angle)/tot;
+
+ me->totvert += tot+1;
+ me->totface += tot+1;
+
+ me->mvert = (MVert*) MEM_callocN(me->totvert*sizeof(MVert), "mverts");
+ me->mface = (MFace*) MEM_callocN(me->totface*sizeof(MVert), "mface");
+
+ CustomData_set_layer(&me->vdata, CD_MVERT, me->mvert);
+ CustomData_set_layer(&me->fdata, CD_MFACE, me->mface);
+
+ printf("vertex and face buffers allocated\n");
+
+ for(v = 0; v <= tot; v++) {
+
+ x = a * sin(phi);
+ y = b * cos(phi);
+ epoint[0] = center[0] + x*cos(theta) - y*sin(theta);
+ epoint[1] = center[1] + x*sin(theta) + y*cos(theta);
+ epoint[2] = center[2];
+
+ mvert= &me->mvert[v];
+
+ if (vspace) {
+ VECCOPY(mvert->co, epoint);
+ } else {
+ VecSubf(mvert->co, epoint, vcenter);
+ }
+
+ if (v > 0) {
+ mface= &(((MFace*)me->mface)[v-1]);
+ mface->v1 = v-1;
+ mface->v2 = v;
+ mface->mat_nr = 0;
+ }
+
+ hasbumped = 1;
+
+ VECCOPY(cent, epoint);
+ phi+=phid;
+ }
+}
+
+static void dxf_read_arc(int noob)
+{
+ /* Entity specific vars */
+ float epoint[3]={0.0, 0.0, 0.0};
+ float center[3]={0.0, 0.0, 0.0};
+ float extrusion[3]={0.0, 0.0, 1.0};
+ short vspace=0; /* Whether or not coords are relative */
+ float dia = 0.0f;
+ float phid = 0.0f, phi = 0.0f;
+ float start_angle = 0.0f;
+ float end_angle = 2*M_PI;
+ float temp;
+ int v, tot = 32;
+ int isArc=0;
+ /* Blender vars */
+ Object *ob;
+ Mesh *me;
+ MVert *mvert;
+ MFace *mface;
+
+ reset_vars;
+ read_group(id, val);
+ while(id!=0) {
+ if (id==8) {
+ BLI_strncpy(layname, val, sizeof(layname));
+ } else if (id==10) {
+ center[0]= (float) atof(val);
+ } else if (id==20) {
+ center[1]= (float) atof(val);
+ } else if (id==30) {
+ center[2]= (float) atof(val);
+ } else if (id==40) {
+ dia = (float) atof(val);
+ } else if (id==62) {
+ int colorid= atoi(val);
+
+ CLAMP(colorid, 1, 255);
+ dxf_col_to_rgb(colorid, &color[0], &color[1], &color[2]);
+ } else if (id==67) {
+ vspace= atoi(val);
+ } else if (id==100) {
+ isArc = 1;
+ } else if (id==50) {
+ start_angle = (90 - atoi(val)) * M_PI/180.0;
+ } else if (id==51) {
+ end_angle = (90 - atoi(val)) * M_PI/180.0;
+ } else if (id==210) {
+ extrusion[0] = atof(val);
+ } else if (id==220) {
+ extrusion[1] = atof(val);
+ } else if (id==230) {
+ extrusion[2] = atof(val);
+ }
+ read_group(id, val);
+ }
+
+ if(!lwasline || strcmp(layname, oldllay)!=0) dxf_close_line();
+ if(linemhold != NULL && linemhold->totvert>MESH_MAX_VERTS)
+ dxf_close_line();
+
+ /* Same xy-plane-specific extrusion direction code as in read_ellipse
+ * (read_arc and read_ellipse should ideally be rewritten to share code)
+ */
+
+ if (extrusion[2] < 0) {
+ temp = start_angle;
+ start_angle = M_PI - end_angle;
+ end_angle = M_PI - temp;
+ }
+
+ phi = start_angle;
+ if(end_angle > start_angle)
+ end_angle -= 2 * M_PI;
+
+ cent[0]= center[0]+dia*sin(phi);
+ cent[1]= center[1]+dia*cos(phi);
+ cent[2]= center[2];
+
+ dxf_get_mesh(&me, &ob, noob);
+ strcpy(oldllay, layname);
+ if(ob) VECCOPY(ob->loc, cent);
+ dxf_add_mat (ob, me, color, layname);
+
+ tot = 32; /* # of line segments to divide the arc into */
+ phid = (end_angle - start_angle)/tot; /* fix so that arcs have the same 'resolution' as circles? */
+
+ me->totvert += tot+1;
+ me->totface += tot+1;
+
+ me->mvert = (MVert*) MEM_callocN(me->totvert*sizeof(MVert), "mverts");
+ me->mface = (MFace*) MEM_callocN(me->totface*sizeof(MVert), "mface");
+
+ CustomData_set_layer(&me->vdata, CD_MVERT, me->mvert);
+ CustomData_set_layer(&me->fdata, CD_MFACE, me->mface);
+
+ for(v = 0; v <= tot; v++) {
+
+ epoint[0]= center[0]+dia*sin(phi);
+ epoint[1]= center[1]+dia*cos(phi);
+ epoint[2]= center[2];
+
+ mvert= &me->mvert[v];
+
+ if (vspace) {
+ VECCOPY(mvert->co, epoint);
+ } else {
+ VecSubf(mvert->co, epoint, vcenter);
+ }
+
+ if (v > 0) {
+ mface= &(((MFace*)me->mface)[v-1]);
+ mface->v1 = v-1;
+ mface->v2 = v;
+ mface->mat_nr = 0;
+ }
+
+ hasbumped=1;
+
+ VECCOPY(cent, epoint);
+ phi+=phid;
+ }
+}
+
+static void dxf_read_polyline(int noob) {
+ /* Entity specific vars */
+ short vspace=0; /* Whether or not coords are relative */
+ int flag=0;
+ int vflags=0;
+ int vids[4];
+ int nverts;
+
+ /* Blender vars */
+ Object *ob;
+ Mesh *me;
+ float vert[3];
+
+ MVert *mvert, *vtmp;
+ MFace *mface, *ftmp;
+
+ reset_vars;
+
+ read_group(id, val);
+ while(id!=0) {
+ if (id==8) {
+ BLI_strncpy(layname, val, sizeof(layname));
+ } else if (id==10) {
+ cent[0]= (float) atof(val);
+ } else if (id==20) {
+ cent[1]= (float) atof(val);
+ } else if (id==30) {
+ cent[2]= (float) atof(val);
+ } else if (id==60) {
+ /* short invisible= atoi(val); */
+ } else if (id==62) {
+ int colorid= atoi(val);
+
+ CLAMP(colorid, 1, 255);
+ dxf_col_to_rgb(colorid, &color[0], &color[1], &color[2]);
+ } else if (id==67) {
+ vspace= atoi(val);
+ } else if (id==70) {
+ flag= atoi(val);
+ }
+ read_group(id, val);
+ }
+
+ if (flag & 9) { // 1= closed curve, 8= 3d curve
+ if(!lwasp2d || strcmp(layname, oldplay)!=0) dxf_close_2dpoly();
+ if(p2dmhold != NULL && p2dmhold->totvert>MESH_MAX_VERTS)
+ dxf_close_2dpoly();
+
+ if (p2dmhold==NULL) {
+ dxf_get_mesh(&me, &ob, noob);
+
+ strcpy(oldplay, layname);
+
+ if(ob) VECCOPY(ob->loc, cent);
+
+ dxf_add_mat (ob, me, color, layname);
+
+ p2dhold= ob;
+ p2dmhold= me;
+ }
+ else {
+ ob= p2dhold;
+ me= p2dmhold;
+ }
+
+ nverts=0;
+ while (group_is(0, "VERTEX")) {
+ read_group(id, val);
+ while(id!=0) {
+ if (id==10) {
+ vert[0]= (float) atof(val);
+ } else if (id==20) {
+ vert[1]= (float) atof(val);
+ } else if (id==30) {
+ vert[2]= (float) atof(val);
+ }
+ read_group(id, val);
+ }
+ nverts++;
+ me->totvert++;
+
+ vtmp= MEM_callocN(me->totvert*sizeof(MVert), "mverts");
+
+ if (me->mvert) {
+ memcpy (vtmp, me->mvert, (me->totvert-1)*sizeof(MVert));
+ MEM_freeN(me->mvert);
+ }
+ me->mvert= CustomData_set_layer(&me->vdata, CD_MVERT, vtmp);
+ vtmp= NULL;
+
+ mvert= &me->mvert[me->totvert-1];
+
+ if (vspace) { VECCOPY(mvert->co, vert);
+ } else VecSubf(mvert->co, vert, vcenter);
+ }
+
+ /* make edges */
+ if(nverts>1) {
+ int a, oldtotface;
+
+ oldtotface= me->totface;
+ me->totface+= nverts-1;
+
+ ftmp= MEM_callocN(me->totface*sizeof(MFace), "mface");
+
+ if(me->mface) {
+ memcpy(ftmp, me->mface, oldtotface*sizeof(MFace));
+ MEM_freeN(me->mface);
+ }
+ me->mface= CustomData_set_layer(&me->fdata, CD_MFACE, ftmp);
+ ftmp=NULL;
+
+ mface= me->mface;
+ mface+= oldtotface;
+
+ for(a=1; a<nverts; a++, mface++) {
+ mface->v1= (me->totvert-nverts)+a-1;
+ mface->v2= (me->totvert-nverts)+a;
+ mface->mat_nr= 0;
+ }
+ }
+
+ lwasp2d=1;
+ }
+ else if (flag&64) {
+ dxf_get_mesh(&me, &ob, noob);
+
+ if(ob) VECCOPY(ob->loc, cent);
+
+ dxf_add_mat (ob, me, color, layname);
+
+ while (group_is(0, "VERTEX")) {
+ vflags= 0;
+ vids[0]= vids[1]= vids[2]= vids[3]= 0;
+
+ vflags=0;
+ read_group(id, val);
+ while(id!=0) {
+ if(id==8) {
+ ; /* Layer def, skip */
+ } else if (id==10) {
+ vert[0]= (float) atof(val);
+ } else if (id==20) {
+ vert[1]= (float) atof(val);
+ } else if (id==30) {
+ vert[2]= (float) atof(val);
+ } else if (id==70) {
+ vflags= atoi(val);
+ } else if (id==71) {
+ vids[0]= abs(atoi(val));
+ } else if (id==72) {
+ vids[1]= abs(atoi(val));
+ } else if (id==73) {
+ vids[2]= abs(atoi(val));
+ } else if (id==74) {
+ vids[3]= abs(atoi(val));
+ }
+ read_group(id, val);
+ }
+
+ if (vflags & 128 && vflags & 64) {
+ me->totvert++;
+
+ /* If we are nearing the limit scan to the next entry */
+ if(me->totvert > MESH_MAX_VERTS)
+ while(group_isnt(0, "SEQEND")) read_group(id, val);
+
+ vtmp= MEM_callocN(me->totvert*sizeof(MVert), "mverts");
+
+ if(me->mvert) {
+ memcpy(vtmp, me->mvert, (me->totvert-1)*sizeof(MVert));
+ MEM_freeN(me->mvert);
+ }
+ me->mvert= CustomData_set_layer(&me->vdata, CD_MVERT, vtmp);
+ vtmp=NULL;
+
+ mvert= &me->mvert[(me->totvert-1)];
+
+ if (vspace) { VECCOPY(mvert->co, vert);
+ } else VecSubf(mvert->co, vert, vcenter);
+
+ } else if (vflags & 128) {
+ if(vids[2]==0) {
+ error("(PL) Error parsing dxf, not enough vertices near line %d", dxf_line);
+
+ error_exit=1;
+ fclose(dxf_fp);
+ return;
+ }
+
+ me->totface++;
+
+ ftmp= MEM_callocN(me->totface*sizeof(MFace), "mfaces");
+
+ if(me->mface) {
+ memcpy(ftmp, me->mface, (me->totface-1)*sizeof(MFace));
+ MEM_freeN(me->mface);
+ }
+ me->mface= CustomData_set_layer(&me->fdata, CD_MFACE, ftmp);
+ ftmp=NULL;
+
+ mface= &(((MFace*)me->mface)[me->totface-1]);
+ mface->v1= vids[0]-1;
+ mface->v2= vids[1]-1;
+ mface->v3= vids[2]-1;
+
+ if(vids[3] && vids[3]!=vids[0]) {
+ mface->v4= vids[3]-1;
+ test_index_face(mface, NULL, 0, 4);
+ }
+ else test_index_face(mface, NULL, 0, 3);
+
+ mface->mat_nr= 0;
+
+ } else {
+ error("Error parsing dxf, unknown polyline information near %d", dxf_line);
+
+ error_exit=1;
+ fclose(dxf_fp);
+ return;
+ }
+
+ }
+ }
+}
+
+static void dxf_read_lwpolyline(int noob) {
+ /* Entity specific vars */
+ short vspace=0; /* Whether or not coords are relative */
+ int flag=0;
+ int nverts=0;
+ int v;
+
+ /* Blender vars */
+ Object *ob;
+ Mesh *me;
+ float vert[3];
+
+ MVert *mvert;
+ MFace *mface;
+
+ reset_vars;
+
+ id = -1;
+
+ /* block structure is
+ * {...}
+ * 90 => nverts
+ * 70 => flags
+ * nverts.times { 10 => x, 20 => y }
+ */
+ while(id!=70) {
+ read_group(id, val);
+ if (id==8) {
+ BLI_strncpy(layname, val, sizeof(layname));
+ } else if (id==38) {
+ vert[2]= (float) atof(val);
+ } else if (id==60) {
+ /* short invisible= atoi(val); */
+ } else if (id==62) {
+ int colorid= atoi(val);
+
+ CLAMP(colorid, 1, 255);
+ dxf_col_to_rgb(colorid, &color[0], &color[1], &color[2]);
+ } else if (id==67) {
+ vspace= atoi(val);
+ } else if (id==70) {
+ flag= atoi(val);
+ } else if (id==90) {
+ nverts= atoi(val);
+ }
+ }
+ printf("nverts %d\n", nverts);
+ if (nverts == 0)
+ return;
+
+ dxf_get_mesh(&me, &ob, noob);
+ strcpy(oldllay, layname);
+ if(ob) VECCOPY(ob->loc, cent);
+ dxf_add_mat (ob, me, color, layname);
+
+ me->totvert += nverts;
+ me->totface += nverts;
+
+ me->mvert = (MVert*) MEM_callocN(me->totvert*sizeof(MVert), "mverts");
+ me->mface = (MFace*) MEM_callocN(me->totface*sizeof(MVert), "mface");
+
+ CustomData_set_layer(&me->vdata, CD_MVERT, me->mvert);
+ CustomData_set_layer(&me->fdata, CD_MFACE, me->mface);
+
+ for (v = 0; v < nverts; v++) {
+ read_group(id,val);
+ if (id == 10) {
+ vert[0]= (float) atof(val);
+ } else {
+ error("Error parsing dxf, expected (10, <x>) at line %d", dxf_line);
+ }
+
+ read_group(id,val);
+ if (id == 20) {
+ vert[1]= (float) atof(val);
+ } else {
+ error("Error parsing dxf, expected (20, <y>) at line %d", dxf_line);
+ }
+
+ mvert = &me->mvert[v];
+
+ if (vspace) {
+ VECCOPY(mvert->co, vert);
+ } else {
+ VecSubf(mvert->co, vert, vcenter);
+ }
+
+ if (v > 0) {
+ mface= &(((MFace*)me->mface)[v-1]);
+ mface->v1 = v-1;
+ mface->v2 = v;
+ mface->mat_nr = 0;
+ }
+ }
+
+ /* flag & 1 -> closed polyline
+ * TODO: give the polyline actual 2D faces if it is closed */
+
+ if (flag&1) {
+ if(me->mface) {
+ mface= &(((MFace*)me->mface)[nverts - 1]);
+ mface->v1 = nverts-1;
+ mface->v2 = 0;
+ mface->mat_nr = 0;
+ }
+ }
+}
+
+
+ /* 3D Face state vars */
+static Object *f3dhold=NULL;
+static Mesh *f3dmhold=NULL;
+static char oldflay[32];
+static short lwasf3d=0; /* last was face 3d? */
+
+/* how can this function do anything useful (ton)? */
+static void dxf_close_3dface(void)
+{
+ f3dmhold= NULL;
+ if (f3dhold==NULL) return;
+
+ f3dhold=NULL;
+}
+
+static void dxf_read_3dface(int noob)
+{
+ /* Entity specific vars */
+ float vert2[3]={0.0, 0.0, 0.0};
+ float vert3[3]={0.0, 0.0, 0.0};
+ float vert4[3]={0.0, 0.0, 0.0};
+ short vspace=0;
+
+ int nverts=0;
+
+ /* Blender vars */
+ Object *ob;
+ Mesh *me;
+ MVert *mvert, *vtmp;
+ MFace *mface, *ftmp;
+
+ reset_vars;
+
+ read_group(id, val);
+ while(id!=0) {
+ if (id==8) {
+ BLI_strncpy(layname, val, sizeof(layname));
+
+ /* First vert/origin */
+ } else if (id==10) {
+ cent[0]= (float) atof(val);
+ if (nverts<1)nverts++;
+ } else if (id==20) {
+ cent[1]= (float) atof(val);
+ if (nverts<1)nverts++;
+ } else if (id==30) {
+ cent[2]= (float) atof(val);
+ if (nverts<1)nverts++;
+
+ /* Second vert */
+ } else if (id==11) {
+ vert2[0]= (float) atof(val);
+ if (nverts<2)nverts++;
+ } else if (id==21) {
+ vert2[1]= (float) atof(val);
+ if (nverts<2)nverts++;
+ } else if (id==31) {
+ vert2[2]= (float) atof(val);
+ if (nverts<2)nverts++;
+
+ /* Third vert */
+ } else if (id==12) {
+ vert3[0]= (float) atof(val);
+ if (nverts<3)nverts++;
+ } else if (id==22) {
+ vert3[1]= (float) atof(val);
+ if (nverts<3)nverts++;
+ } else if (id==32) {
+ vert3[2]= (float) atof(val);
+ if (nverts<3)nverts++;
+
+ /* Fourth vert */
+ } else if (id==13) {
+ vert4[0]= (float) atof(val);
+ if (nverts<4)nverts++;
+ } else if (id==23) {
+ vert4[1]= (float) atof(val);
+ if (nverts<4)nverts++;
+ } else if (id==33) {
+ vert4[2]= (float) atof(val);
+ if (nverts<4)nverts++;
+
+ /* Other */
+ } else if (id==60) {
+ /* short invisible= atoi(val); */
+ } else if (id==62) {
+ int colorid= atoi(val);
+
+ CLAMP(colorid, 1, 255);
+ dxf_col_to_rgb(colorid, &color[0], &color[1], &color[2]);
+ } else if (id==67) {
+ vspace= atoi(val);
+ }
+ read_group(id, val);
+ }
+
+ /* Check to see if we need to make a new object */
+
+ if(!lwasf3d || strcmp(layname, oldflay)!=0) dxf_close_3dface();
+ if(f3dmhold != NULL && f3dmhold->totvert>MESH_MAX_VERTS)
+ dxf_close_3dface();
+
+ if(nverts<3) {
+ error("(3DF) Error parsing dxf, not enough vertices near line %d", dxf_line);
+
+ error_exit=1;
+ fclose(dxf_fp);
+ return;
+ }
+
+ if (f3dmhold==NULL) {
+ dxf_get_mesh(&me, &ob, noob);
+
+ strcpy(oldflay, layname);
+
+ if(ob) VECCOPY(ob->loc, cent);
+
+ dxf_add_mat (ob, me, color, layname);
+
+ f3dhold= ob;
+ f3dmhold= me;
+ } else {
+ ob= f3dhold;
+ me= f3dmhold;
+ }
+
+ me->totvert+= nverts;
+ me->totface++;
+
+ vtmp= MEM_callocN(me->totvert*sizeof(MVert), "mverts");
+ ftmp= MEM_callocN(me->totface*sizeof(MFace), "mface");
+
+ if(me->mvert) {
+ memcpy(vtmp, me->mvert, (me->totvert-nverts)*sizeof(MVert));
+ MEM_freeN(me->mvert);
+ }
+ me->mvert= CustomData_set_layer(&me->vdata, CD_MVERT, vtmp);
+ vtmp=NULL;
+
+ if(me->mface) {
+ memcpy(ftmp, me->mface, (me->totface-1)*sizeof(MFace));
+ MEM_freeN(me->mface);
+ }
+ me->mface= CustomData_set_layer(&me->fdata, CD_MFACE, ftmp);
+ ftmp=NULL;
+
+ mvert= &me->mvert[(me->totvert-nverts)];
+ VecSubf(mvert->co, cent, vcenter);
+
+ mvert++;
+ if (vspace) { VECCOPY(mvert->co, vert2);
+ } else VecSubf(mvert->co, vert2, vcenter);
+
+ mvert++;
+ if (vspace) { VECCOPY(mvert->co, vert3);
+ } else VecSubf(mvert->co, vert3, vcenter);
+
+ if (nverts==4) {
+ mvert++;
+ if (vspace) { VECCOPY(mvert->co, vert4);
+ } else VecSubf(mvert->co, vert4, vcenter);
+ }
+
+ mface= &(((MFace*)me->mface)[me->totface-1]);
+ mface->v1= (me->totvert-nverts)+0;
+ mface->v2= (me->totvert-nverts)+1;
+ mface->v3= (me->totvert-nverts)+2;
+
+ if (nverts==4)
+ mface->v4= (me->totvert-nverts)+3;
+
+ mface->mat_nr= 0;
+
+ test_index_face(mface, NULL, 0, nverts);
+
+ hasbumped=1;
+}
+
+static void dxf_read(char *filename)
+{
+ Mesh *lastMe = G.main->mesh.last;
+
+ /* clear ugly global variables, that can hang because on error the code
+ below returns... tsk (ton) */
+ dxf_line=0;
+ dxf_close_3dface();
+ dxf_close_2dpoly();
+ dxf_close_line();
+
+ dxf_fp= fopen(filename, "r");
+ if (dxf_fp==NULL) return;
+
+ while (1) {
+ read_group(id, val);
+ if (group_is(0, "EOF")) break;
+
+ if (id==999) continue;
+ id_check(0, "SECTION");
+
+ read_group(id, val);
+ if (group_is(2, "HEADER")) {
+ } else if (group_is(2, "TABLES")) {
+ } else if (group_is(2, "OBJECTS")) {
+ } else if (group_is(2, "CLASSES")) {
+ } else if (group_is(2, "BLOCKS")) {
+ while(1) {
+ read_group(id, val);
+ if (group_is(0, "BLOCK")) {
+ while(group_isnt(0, "ENDBLK")) {
+ read_group(id, val);
+
+ if(id==2) {
+ BLI_strncpy(entname, val, sizeof(entname));
+ } else if (id==3) {
+ /* Now the object def should follow */
+ if(strlen(entname)==0) {
+ error("Error parsing dxf, no mesh name near %d", dxf_line);
+ fclose(dxf_fp);
+ return;
+ }
+
+ /* Now the object def should follow */
+ while(group_isnt(0, "ENDBLK")) {
+ read_group(id, val);
+
+ if(group_is(0, "POLYLINE")) {
+ dxf_read_polyline(1);
+ if(error_exit) return;
+ lwasf3d=0;
+ lwasline=0;
+
+ while(group_isnt(0, "SEQEND")) read_group(id, val);
+
+ } else if(group_is(0, "LWPOLYLINE")) {
+ dxf_read_lwpolyline(1);
+ if(error_exit) return;
+ lwasf3d=0;
+ lwasline=0;
+
+ while(group_isnt(0, "SEQEND")) read_group(id, val);
+ } else if(group_is(0, "ATTRIB")) {
+ while(group_isnt(0, "SEQEND")) read_group(id, val);
+ lwasf3d=0;
+ lwasp2d=0;
+ lwasline=0;
+ } else if(group_is(0, "POINT")) {
+ dxf_read_point(1);
+ if(error_exit) return;
+ lwasf3d=0;
+ lwasp2d=0;
+ lwasline=0;
+ } else if(group_is(0, "LINE")) {
+ dxf_read_line(1);
+ if(error_exit) return;
+ lwasline=1;
+ lwasp2d=0;
+ lwasf3d=0;
+ } else if(group_is(0, "3DFACE")) {
+ dxf_read_3dface(1);
+ if(error_exit) return;
+ lwasf3d=1;
+ lwasp2d=0;
+ lwasline=0;
+ } else if (group_is(0, "CIRCLE")) {
+ dxf_read_arc(1);
+ } else if (group_is(0, "ELLIPSE")) {
+ dxf_read_ellipse(1);
+ } else if (group_is(0, "ENDBLK")) {
+ break;
+ }
+ }
+ } else if (group_is(0, "ENDBLK")) {
+ break;
+ }
+ }
+ while(id!=0) read_group(id, val);
+
+ } else if(group_is(0, "ENDSEC")) {
+ break;
+ }
+ }
+ } else if (group_is(2, "ENTITIES")) {
+ while(group_isnt(0, "ENDSEC")) {
+ char obname[32]="";
+ char layname[32]="";
+ float cent[3]={0.0, 0.0, 0.0};
+ float obsize[3]={1.0, 1.0, 1.0};
+ float obrot[3]={0.0, 0.0, 0.0};
+
+ if(!hasbumped) read_group(id, val);
+ hasbumped=0;
+ if (group_is(0, "INSERT")) {
+ Base *base;
+ Object *ob;
+ void *obdata;
+
+ read_group(id, val);
+
+ while(id!=0) {
+ if(id==2) {
+ BLI_strncpy(obname, val, sizeof(obname));
+ } else if (id==8) {
+ BLI_strncpy(layname, val, sizeof(layname));
+ } else if (id==10) {
+ cent[0]= (float) atof(val);
+ } else if (id==20) {
+ cent[1]= (float) atof(val);
+ } else if (id==30) {
+ cent[2]= (float) atof(val);
+ } else if (id==41) {
+ obsize[0]= (float) atof(val);
+ } else if (id==42) {
+ obsize[1]= (float) atof(val);
+ } else if (id==43) {
+ obsize[2]= (float) atof(val);
+ } else if (id==50) {
+ obrot[2]= (float) (atof(val)*M_PI/180.0);
+ } else if (id==60) {
+ /* short invisible= atoi(val); */
+ }
+
+ read_group(id, val);
+
+ }
+
+ if(strlen(obname)==0) {
+ error("Error parsing dxf, no object name near %d", dxf_line);
+ fclose(dxf_fp);
+ return;
+ }
+
+ obdata= find_id("ME", obname);
+
+ if (obdata) {
+ ob= alloc_libblock(&G.main->object, ID_OB, obname);
+
+ ob->type= OB_MESH;
+
+ ob->dt= OB_SHADED;
+ if(U.flag & USER_MAT_ON_OB) ob->colbits= -1;
+
+ ob->trackflag= OB_POSY;
+ ob->upflag= OB_POSZ;
+
+ ob->ipoflag = OB_OFFS_OB+OB_OFFS_PARENT;
+
+ ob->dupon= 1; ob->dupoff= 0;
+ ob->dupsta= 1; ob->dupend= 100;
+ ob->recalc= OB_RECALC; /* needed because of weird way of adding libdata directly */
+
+ G.totobj++;
+
+ ob->data= obdata;
+ ((ID*)ob->data)->us++;
+
+ VECCOPY(ob->loc, cent);
+ VECCOPY(ob->size, obsize);
+ VECCOPY(ob->rot, obrot);
+
+ ob->mat= MEM_callocN(sizeof(void *)*1, "ob->mat");
+ ob->totcol= (unsigned char) ((Mesh*)ob->data)->totcol;
+ ob->actcol= 1;
+
+ /* note: materials are either linked to mesh or object, if both then
+ you have to increase user counts. below line is not needed.
+ I leave it commented out here as warning (ton) */
+ //for (i=0; i<ob->totcol; i++) ob->mat[i]= ((Mesh*)ob->data)->mat[i];
+
+ if (strlen(layname)) ob->lay= dxf_get_layer_num(layname);
+ else ob->lay= G.scene->lay;
+
+ /* link to scene */
+ base= MEM_callocN( sizeof(Base), "add_base");
+ BLI_addhead(&G.scene->base, base);
+
+ base->lay= ob->lay;
+
+ base->object= ob;
+ }
+
+ hasbumped=1;
+
+ lwasf3d=0;
+ lwasp2d=0;
+ lwasline=0;
+ } else if(group_is(0, "POLYLINE")) {
+ dxf_read_polyline(0);
+ if(error_exit) return;
+ lwasf3d=0;
+ lwasline=0;
+
+ while(group_isnt(0, "SEQEND")) read_group(id, val);
+
+ } else if(group_is(0, "LWPOLYLINE")) {
+ dxf_read_lwpolyline(0);
+ if(error_exit) return;
+ lwasf3d=0;
+ lwasline=0;
+ //while(group_isnt(0, "SEQEND")) read_group(id, val);
+
+ } else if(group_is(0, "ATTRIB")) {
+ while(group_isnt(0, "SEQEND")) read_group(id, val);
+ lwasf3d=0;
+ lwasp2d=0;
+ lwasline=0;
+ } else if(group_is(0, "POINT")) {
+ dxf_read_point(0);
+ if(error_exit) return;
+ lwasf3d=0;
+ lwasp2d=0;
+ lwasline=0;
+ } else if(group_is(0, "LINE")) {
+ dxf_read_line(0);
+ if(error_exit) return;
+ lwasline=1;
+ lwasp2d=0;
+ lwasf3d=0;
+ } else if(group_is(0, "3DFACE")) {
+ dxf_read_3dface(0);
+ if(error_exit) return;
+ lwasline=0;
+ lwasp2d=0;
+ lwasf3d=1;
+ } else if (group_is(0, "CIRCLE") || group_is(0, "ARC")) {
+ dxf_read_arc(0);
+ } else if (group_is(0, "ELLIPSE")) {
+ dxf_read_ellipse(0);
+ } else if(group_is(0, "ENDSEC")) {
+ break;
+ }
+ }
+ }
+
+ while(group_isnt(0, "ENDSEC")) read_group(id, val);
+ }
+ id_check(0, "EOF");
+
+ fclose (dxf_fp);
+
+ /* Close any remaining state held stuff */
+ dxf_close_3dface();
+ dxf_close_2dpoly();
+ dxf_close_line();
+
+ if (lastMe) {
+ lastMe = lastMe->id.next;
+ } else {
+ lastMe = G.main->mesh.first;
+ }
+ for (; lastMe; lastMe=lastMe->id.next) {
+ mesh_add_normals_flags(lastMe);
+ make_edges(lastMe, 0);
+ }
+}
diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c
new file mode 100644
index 00000000000..fc11b3d234d
--- /dev/null
+++ b/source/blender/blenkernel/intern/font.c
@@ -0,0 +1,1189 @@
+/* font.c
+ *
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <stdlib.h>
+#include <wchar.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+#include "BLI_vfontdata.h"
+
+#include "DNA_packedFile_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_object_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_vfont_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_bad_level_calls.h"
+
+#include "BKE_packedFile.h"
+
+#include "BKE_library.h"
+#include "BKE_font.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_screen.h"
+#include "BKE_anim.h"
+#include "BKE_curve.h"
+#include "BKE_displist.h"
+
+#define callocstructN(x,y,name) (x*)MEM_callocN((y)* sizeof(x),name)
+
+struct SelBox *selboxes= NULL;
+
+/* UTF-8 <-> wchar transformations */
+void
+chtoutf8(unsigned long c, char *o)
+{
+ // Variables and initialization
+/* memset(o, 0, 16); */
+
+ // Create the utf-8 string
+ if (c < 0x80)
+ {
+ o[0] = (char) c;
+ }
+ else if (c < 0x800)
+ {
+ o[0] = (0xC0 | (c>>6));
+ o[1] = (0x80 | (c & 0x3f));
+ }
+ else if (c < 0x10000)
+ {
+ o[0] = (0xe0 | (c >> 12));
+ o[1] = (0x80 | (c >>6 & 0x3f));
+ o[2] = (0x80 | (c & 0x3f));
+ }
+ else if (c < 0x200000)
+ {
+ o[0] = (0xf0 | (c>>18));
+ o[1] = (0x80 | (c >>12 & 0x3f));
+ o[2] = (0x80 | (c >> 6 & 0x3f));
+ o[3] = (0x80 | (c & 0x3f));
+ }
+}
+
+void
+wcs2utf8s(char *dst, wchar_t *src)
+{
+ char ch[5];
+
+ while(*src)
+ {
+ memset(ch, 0, 5);
+ chtoutf8(*src++, ch);
+ strcat(dst, ch);
+ }
+}
+
+int
+wcsleninu8(wchar_t *src)
+{
+ char ch[16];
+ int len = 0;
+
+ while(*src)
+ {
+ memset(ch, 0, 16);
+ chtoutf8(*src++, ch);
+ len = len + strlen(ch);
+ }
+
+ return len;
+}
+
+int
+utf8slen(char *src)
+{
+ int size = 0, index = 0;
+ unsigned char c;
+
+ c = src[index++];
+ while(c)
+ {
+ if((c & 0x80) == 0)
+ {
+ index += 0;
+ }
+ else if((c & 0xe0) == 0xe0)
+ {
+ index += 2;
+ }
+ else
+ {
+ index += 1;
+ }
+ size += 1;
+ c = src[index++];
+ }
+
+ return size;
+}
+
+int utf8towchar_(wchar_t *w, char *c)
+{
+ int len=0;
+ if(w==NULL || c==NULL) return(0);
+ //printf("%s\n",c);
+ while(*c)
+ {
+ if(*c & 0x80)
+ {
+ if(*c & 0x40)
+ {
+ if(*c & 0x20)
+ {
+ if(*c & 0x10)
+ {
+ *w=(c[0] & 0x0f)<<18 | (c[1]&0x1f)<<12 | (c[2]&0x3f)<<6 | (c[3]&0x7f);
+ c++;
+ }
+ else
+ *w=(c[0] & 0x1f)<<12 | (c[1]&0x3f)<<6 | (c[2]&0x7f);
+ c++;
+ }
+ else
+ *w=(((c[0] &0x3f)<<6) | (c[1]&0x7f));
+ c++;
+ }
+ else
+ *w=(c[0] & 0x7f);
+ }
+ else
+ *w=(c[0] & 0x7f);
+ c++;
+ w++;
+ len++;
+ }
+ return len;
+}
+
+/* The vfont code */
+void free_vfont(struct VFont *vf)
+{
+ if (vf == 0) return;
+
+ if (vf->data) {
+ while(vf->data->characters.first)
+ {
+ VChar *che = vf->data->characters.first;
+
+ while (che->nurbsbase.first) {
+ Nurb *nu = che->nurbsbase.first;
+ if (nu->bezt) MEM_freeN(nu->bezt);
+ BLI_freelinkN(&che->nurbsbase, nu);
+ }
+
+ BLI_freelinkN(&vf->data->characters, che);
+ }
+
+ MEM_freeN(vf->data);
+ vf->data = NULL;
+ }
+
+ if (vf->packedfile) {
+ freePackedFile(vf->packedfile);
+ vf->packedfile = NULL;
+ }
+}
+
+static void *builtin_font_data= NULL;
+static int builtin_font_size= 0;
+
+void BKE_font_register_builtin(void *mem, int size)
+{
+ builtin_font_data= mem;
+ builtin_font_size= size;
+}
+
+static PackedFile *get_builtin_packedfile(void)
+{
+ if (!builtin_font_data) {
+ printf("Internal error, builtin font not loaded\n");
+
+ return NULL;
+ } else {
+ void *mem= MEM_mallocN(builtin_font_size, "vfd_builtin");
+
+ memcpy(mem, builtin_font_data, builtin_font_size);
+
+ return newPackedFileMemory(mem, builtin_font_size);
+ }
+}
+
+static VFontData *vfont_get_data(VFont *vfont)
+{
+ struct TmpFont *tmpfnt = NULL;
+ PackedFile *tpf;
+
+ if(vfont==NULL) return NULL;
+
+ // Try finding the font from font list
+ tmpfnt = G.ttfdata.first;
+
+ while(tmpfnt)
+ {
+ if(tmpfnt->vfont == vfont)
+ break;
+ tmpfnt = tmpfnt->next;
+ }
+
+ // And then set the data
+ if (!vfont->data) {
+ PackedFile *pf;
+
+ if (BLI_streq(vfont->name, "<builtin>")) {
+ pf= get_builtin_packedfile();
+ } else {
+ if (vfont->packedfile) {
+ pf= vfont->packedfile;
+
+ // We need to copy a tmp font to memory unless it is already there
+ if(!tmpfnt)
+ {
+ tpf= MEM_callocN(sizeof(*tpf), "PackedFile");
+ tpf->data= MEM_mallocN(pf->size, "packFile");
+ tpf->size= pf->size;
+ memcpy(tpf->data, pf->data, pf->size);
+
+ // Add temporary packed file to globals
+ tmpfnt= (struct TmpFont *) MEM_callocN(sizeof(struct TmpFont), "temp_font");
+ tmpfnt->pf= tpf;
+ tmpfnt->vfont= vfont;
+ BLI_addtail(&G.ttfdata, tmpfnt);
+ }
+ } else {
+ pf= newPackedFile(vfont->name);
+
+ if(!tmpfnt)
+ {
+ tpf= newPackedFile(vfont->name);
+
+ // Add temporary packed file to globals
+ tmpfnt= (struct TmpFont *) MEM_callocN(sizeof(struct TmpFont), "temp_font");
+ tmpfnt->pf= tpf;
+ tmpfnt->vfont= vfont;
+ BLI_addtail(&G.ttfdata, tmpfnt);
+ }
+ }
+ if(!pf) {
+ printf("Font file doesn't exist: %s\n", vfont->name);
+
+ strcpy(vfont->name, "<builtin>");
+ pf= get_builtin_packedfile();
+ }
+ }
+
+ if (pf) {
+#ifdef WITH_FREETYPE2
+ vfont->data= BLI_vfontdata_from_freetypefont(pf);
+#else
+ vfont->data= BLI_vfontdata_from_psfont(pf);
+#endif
+ if (pf != vfont->packedfile) {
+ freePackedFile(pf);
+ }
+ }
+ }
+
+ return vfont->data;
+}
+
+VFont *load_vfont(char *name)
+{
+ char filename[FILE_MAXFILE];
+ VFont *vfont= NULL;
+ PackedFile *pf;
+ PackedFile *tpf = NULL;
+ int is_builtin;
+ struct TmpFont *tmpfnt;
+
+ if (BLI_streq(name, "<builtin>")) {
+ strcpy(filename, name);
+
+ pf= get_builtin_packedfile();
+ is_builtin= 1;
+ } else {
+ char dir[FILE_MAXDIR];
+
+ strcpy(dir, name);
+ BLI_splitdirstring(dir, filename);
+
+ pf= newPackedFile(name);
+ tpf= newPackedFile(name);
+
+ is_builtin= 0;
+ }
+
+ if (pf) {
+ VFontData *vfd;
+
+ waitcursor(1);
+
+#ifdef WITH_FREETYPE2
+ vfd= BLI_vfontdata_from_freetypefont(pf);
+#else
+ vfd= BLI_vfontdata_from_psfont(pf);
+#endif
+
+ if (vfd) {
+ vfont = alloc_libblock(&G.main->vfont, ID_VF, filename);
+ vfont->data = vfd;
+
+ BLI_strncpy(vfont->name, name, sizeof(vfont->name));
+
+ // if autopack is on store the packedfile in de font structure
+ if (!is_builtin && (G.fileflags & G_AUTOPACK)) {
+ vfont->packedfile = pf;
+ }
+
+ // Do not add <builtin> to temporary listbase
+ if(strcmp(filename, "<builtin>"))
+ {
+ tmpfnt= (struct TmpFont *) MEM_callocN(sizeof(struct TmpFont), "temp_font");
+ tmpfnt->pf= tpf;
+ tmpfnt->vfont= vfont;
+ BLI_addtail(&G.ttfdata, tmpfnt);
+ }
+ }
+
+ // Free the packed file
+ if (!vfont || vfont->packedfile != pf) {
+ freePackedFile(pf);
+ }
+
+ waitcursor(0);
+ }
+
+ return vfont;
+}
+
+static VFont *which_vfont(Curve *cu, CharInfo *info)
+{
+ switch(info->flag & CU_STYLE) {
+ case CU_BOLD:
+ if (cu->vfontb) return(cu->vfontb); else return(cu->vfont);
+ case CU_ITALIC:
+ if (cu->vfonti) return(cu->vfonti); else return(cu->vfont);
+ case (CU_BOLD|CU_ITALIC):
+ if (cu->vfontbi) return(cu->vfontbi); else return(cu->vfont);
+ default:
+ return(cu->vfont);
+ }
+}
+
+static void build_underline(Curve *cu, float x1, float y1, float x2, float y2, int charidx, short mat_nr)
+{
+ Nurb *nu2;
+ BPoint *bp;
+
+ nu2 =(Nurb*) MEM_callocN(sizeof(Nurb),"underline_nurb");
+ if (nu2 == NULL) return;
+ nu2->resolu= cu->resolu;
+ nu2->bezt = NULL;
+ nu2->knotsu = nu2->knotsv = 0;
+ nu2->flag= 0;
+ nu2->charidx = charidx+1000;
+ if (mat_nr > 0) nu2->mat_nr= mat_nr-1;
+ nu2->pntsu = 4;
+ nu2->pntsv = 1;
+ nu2->orderu = 4;
+ nu2->orderv = 1;
+ nu2->flagu = CU_CYCLIC;
+
+ bp = (BPoint*)MEM_callocN(4 * sizeof(BPoint),"underline_bp");
+ if (bp == 0){
+ MEM_freeN(nu2);
+ return;
+ }
+ nu2->bp = bp;
+
+ nu2->bp[0].vec[0] = x1;
+ nu2->bp[0].vec[1] = y1;
+ nu2->bp[0].vec[2] = 0;
+ nu2->bp[0].vec[3] = 1.0;
+ nu2->bp[1].vec[0] = x2;
+ nu2->bp[1].vec[1] = y1;
+ nu2->bp[1].vec[2] = 0;
+ nu2->bp[1].vec[3] = 1.0;
+ nu2->bp[2].vec[0] = x2;
+ nu2->bp[2].vec[1] = y2;
+ nu2->bp[2].vec[2] = 0;
+ nu2->bp[2].vec[3] = 1.0;
+ nu2->bp[3].vec[0] = x1;
+ nu2->bp[3].vec[1] = y2;
+ nu2->bp[3].vec[2] = 0;
+ nu2->bp[3].vec[3] = 1.0;
+
+ nu2->type = CU_2D;
+ BLI_addtail(&(cu->nurb), nu2);
+
+}
+
+static void buildchar(Curve *cu, unsigned long character, CharInfo *info, float ofsx, float ofsy, float rot, int charidx)
+{
+ BezTriple *bezt1, *bezt2;
+ Nurb *nu1 = NULL, *nu2 = NULL;
+ float *fp, fsize, shear, x, si, co;
+ VFontData *vfd = NULL;
+ VChar *che = NULL;
+ int i, sel=0;
+
+ vfd= vfont_get_data(which_vfont(cu, info));
+ if (!vfd) return;
+
+ if (cu->selend < cu->selstart) {
+ if ((charidx >= (cu->selend)) && (charidx <= (cu->selstart-2)))
+ sel= 1;
+ }
+ else {
+ if ((charidx >= (cu->selstart-1)) && (charidx <= (cu->selend-1)))
+ sel= 1;
+ }
+
+ /* make a copy at distance ofsx,ofsy with shear*/
+ fsize= cu->fsize;
+ shear= cu->shear;
+ si= (float)sin(rot);
+ co= (float)cos(rot);
+
+ // Find the correct character from the font
+ che = vfd->characters.first;
+ while(che)
+ {
+ if(che->index == character)
+ break;
+ che = che->next;
+ }
+
+ // Select the glyph data
+ if(che)
+ nu1 = che->nurbsbase.first;
+
+ // Create the character
+ while(nu1)
+ {
+ bezt1 = nu1->bezt;
+ if (bezt1){
+ nu2 =(Nurb*) MEM_mallocN(sizeof(Nurb),"duplichar_nurb");
+ if (nu2 == 0) break;
+ memcpy(nu2, nu1, sizeof(struct Nurb));
+ nu2->resolu= cu->resolu;
+ nu2->bp = 0;
+ nu2->knotsu = nu2->knotsv = 0;
+ nu2->flag= CU_SMOOTH;
+ nu2->charidx = charidx;
+ if (info->mat_nr) {
+ nu2->mat_nr= info->mat_nr-1;
+ }
+ else {
+ nu2->mat_nr= 0;
+ }
+ /* nu2->trim.first = 0; */
+ /* nu2->trim.last = 0; */
+ i = nu2->pntsu;
+
+ bezt2 = (BezTriple*)MEM_mallocN(i * sizeof(BezTriple),"duplichar_bezt2");
+ if (bezt2 == 0){
+ MEM_freeN(nu2);
+ break;
+ }
+ memcpy(bezt2, bezt1, i * sizeof(struct BezTriple));
+ nu2->bezt = bezt2;
+
+ if (shear != 0.0) {
+ bezt2 = nu2->bezt;
+
+ for (i= nu2->pntsu; i > 0; i--) {
+ bezt2->vec[0][0] += shear * bezt2->vec[0][1];
+ bezt2->vec[1][0] += shear * bezt2->vec[1][1];
+ bezt2->vec[2][0] += shear * bezt2->vec[2][1];
+ bezt2++;
+ }
+ }
+ if(rot!=0.0) {
+ bezt2= nu2->bezt;
+ for (i=nu2->pntsu; i > 0; i--) {
+ fp= bezt2->vec[0];
+
+ x= fp[0];
+ fp[0]= co*x + si*fp[1];
+ fp[1]= -si*x + co*fp[1];
+ x= fp[3];
+ fp[3]= co*x + si*fp[4];
+ fp[4]= -si*x + co*fp[4];
+ x= fp[6];
+ fp[6]= co*x + si*fp[7];
+ fp[7]= -si*x + co*fp[7];
+
+ bezt2++;
+ }
+ }
+ bezt2 = nu2->bezt;
+
+ for (i= nu2->pntsu; i > 0; i--) {
+ fp= bezt2->vec[0];
+
+ fp[0]= (fp[0]+ofsx)*fsize;
+ fp[1]= (fp[1]+ofsy)*fsize;
+ fp[3]= (fp[3]+ofsx)*fsize;
+ fp[4]= (fp[4]+ofsy)*fsize;
+ fp[6]= (fp[6]+ofsx)*fsize;
+ fp[7]= (fp[7]+ofsy)*fsize;
+ bezt2++;
+ }
+
+ BLI_addtail(&(cu->nurb), nu2);
+ }
+
+ nu1 = nu1->next;
+ }
+}
+
+int getselection(int *start, int *end)
+{
+ Curve *cu;
+
+ if (G.obedit==NULL || G.obedit->type != OB_FONT) return 0;
+
+ cu= G.obedit->data;
+
+ if (cu->selstart == 0) return 0;
+ if (cu->selstart <= cu->selend) {
+ *start = cu->selstart-1;
+ *end = cu->selend-1;
+ return 1;
+ }
+ else {
+ *start = cu->selend;
+ *end = cu->selstart-2;
+ return -1;
+ }
+}
+
+struct chartrans *text_to_curve(Object *ob, int mode)
+{
+ VFont *vfont, *oldvfont;
+ VFontData *vfd= NULL;
+ Curve *cu, *cucu;
+ struct chartrans *chartransdata=NULL, *ct;
+ float distfac, tabfac, ctime, dtime, tvec[4], vec[4], rotvec[3], minx, maxx, miny, maxy;
+ float cmat[3][3], timeofs, si, co, sizefac;
+ float *f, maxlen=0, xof, yof, xtrax, linedist, *linedata, *linedata2, *linedata3, *linedata4;
+ int i, slen, oldflag, j;
+ short cnr=0, lnr=0, wsnr= 0;
+ wchar_t *mem, *tmp, ascii;
+ int outta;
+ float vecyo[3], curofs;
+ CharInfo *info;
+ float wsfac;
+ float ulwidth, uloverlap;
+ TextBox *tb;
+ int curbox;
+ int selstart, selend;
+ SelBox *sb= NULL; /* to please gcc */
+ VChar *che;
+ float twidth;
+ int utf8len;
+
+ /* renark: do calculations including the trailing '\0' of a string
+ because the cursor can be at that location */
+
+ if(ob->type!=OB_FONT) return 0;
+
+ // Set font data
+ cu= (Curve *) ob->data;
+ vfont= cu->vfont;
+
+ if(cu->str == 0) return 0;
+ if(vfont == 0) return 0;
+
+ // Create unicode string
+ utf8len = utf8slen(cu->str);
+ tmp = mem = MEM_callocN(((utf8len + 1) * sizeof(wchar_t)), "convertedmem");
+
+ utf8towchar_(mem, cu->str);
+
+ // Count the wchar_t string length
+ slen = wcslen(mem);
+
+ if (cu->ulheight == 0.0) cu->ulheight = 0.05;
+ if (cu->strinfo==NULL) { /* old file */
+ cu->strinfo = MEM_callocN((slen+1) * sizeof(CharInfo), "strinfo compat");
+ }
+ if (cu->tb==NULL) {
+ cu->tb= MEM_callocN(MAXTEXTBOX*sizeof(TextBox), "TextBox compat");
+ }
+
+ vfd= vfont_get_data(vfont);
+
+ /* The VFont Data can not be found */
+ if(!vfd)
+ {
+ if(mem)
+ MEM_freeN(mem);
+ return 0;
+ }
+
+ /* calc offset and rotation of each char */
+ ct = chartransdata =
+ (struct chartrans*)MEM_callocN((slen+1)* sizeof(struct chartrans),"buildtext");
+
+ /* We assume the worst case: 1 character per line (is freed at end anyway) */
+
+ linedata= MEM_mallocN(sizeof(float)*(slen+2),"buildtext2");
+ linedata2= MEM_mallocN(sizeof(float)*(slen+2),"buildtext3");
+ linedata3= MEM_callocN(sizeof(float)*(slen+2),"buildtext4");
+ linedata4= MEM_callocN(sizeof(float)*(slen+2),"buildtext5");
+
+ linedist= cu->linedist;
+
+ xof= cu->xof + (cu->tb[0].x/cu->fsize);
+ yof= cu->yof + (cu->tb[0].y/cu->fsize);
+
+ xtrax= 0.5f*cu->spacing-0.5f;
+
+ oldvfont = NULL;
+
+ for (i=0; i<slen; i++) cu->strinfo[i].flag &= ~CU_WRAP;
+
+ if (selboxes) MEM_freeN(selboxes);
+ selboxes = NULL;
+ if (getselection(&selstart, &selend))
+ selboxes = MEM_callocN((selend-selstart+1)*sizeof(SelBox), "font selboxes");
+
+ tb = &(cu->tb[0]);
+ curbox= 0;
+ for (i = 0 ; i<=slen ; i++) {
+ makebreak:
+ // Characters in the list
+ che = vfd->characters.first;
+ ascii = mem[i];
+ info = &(cu->strinfo[i]);
+ vfont = which_vfont(cu, info);
+
+ if(vfont==NULL) break;
+
+ // Find the character
+ while(che)
+ {
+ if(che->index == ascii)
+ break;
+ che = che->next;
+ }
+
+#ifdef WITH_FREETYPE2
+ // The character wasn't in the current curve base so load it
+ // But if the font is <builtin> then do not try loading since whole font is in the memory already
+ if(che == NULL && strcmp(vfont->name, "<builtin>"))
+ {
+ BLI_vfontchar_from_freetypefont(vfont, ascii);
+ }
+
+ // Try getting the character again from the list
+ che = vfd->characters.first;
+ while(che)
+ {
+ if(che->index == ascii)
+ break;
+ che = che->next;
+ }
+#endif
+
+ /* No VFont found */
+ if (vfont==0)
+ {
+ if(mem)
+ MEM_freeN(mem);
+ MEM_freeN(chartransdata);
+ return 0;
+ }
+
+ if (vfont != oldvfont) {
+ vfd= vfont_get_data(vfont);
+ oldvfont = vfont;
+ }
+
+ /* VFont Data for VFont couldn't be found */
+ if (!vfd)
+ {
+ if(mem)
+ MEM_freeN(mem);
+ MEM_freeN(chartransdata);
+ return 0;
+ }
+
+ // The character wasn't found, propably ascii = 0, then the width shall be 0 as well
+ if(!che)
+ {
+ twidth = 0;
+ }
+ else
+ {
+ twidth = che->width;
+ }
+
+ // Calculate positions
+ if((tb->w != 0.0) && (ct->dobreak==0) && ((xof-(tb->x/cu->fsize)+twidth)*cu->fsize) > tb->w) {
+ // fprintf(stderr, "linewidth exceeded: %c%c%c...\n", mem[i], mem[i+1], mem[i+2]);
+ for (j=i; j && (mem[j] != '\n') && (mem[j] != '\r') && (chartransdata[j].dobreak==0); j--) {
+ if (mem[j]==' ' || mem[j]=='-') {
+ ct -= (i-(j-1));
+ cnr -= (i-(j-1));
+ if (mem[j] == ' ') wsnr--;
+ if (mem[j] == '-') wsnr++;
+ i = j-1;
+ xof = ct->xof;
+ ct[1].dobreak = 1;
+ cu->strinfo[i+1].flag |= CU_WRAP;
+ goto makebreak;
+ }
+ if (chartransdata[j].dobreak) {
+ // fprintf(stderr, "word too long: %c%c%c...\n", mem[j], mem[j+1], mem[j+2]);
+ ct->dobreak= 1;
+ cu->strinfo[i+1].flag |= CU_WRAP;
+ ct -= 1;
+ cnr -= 1;
+ i--;
+ xof = ct->xof;
+ goto makebreak;
+ }
+ }
+ }
+ if(ascii== '\n' || ascii== '\r' || ascii==0 || ct->dobreak) {
+ ct->xof= xof;
+ ct->yof= yof;
+ ct->linenr= lnr;
+ ct->charnr= cnr;
+
+ yof-= linedist;
+
+ maxlen= MAX2(maxlen, (xof-tb->x/cu->fsize));
+ linedata[lnr]= xof-tb->x/cu->fsize;
+ linedata2[lnr]= cnr;
+ linedata3[lnr]= tb->w/cu->fsize;
+ linedata4[lnr]= wsnr;
+
+ if ( (tb->h != 0.0) &&
+ ((-(yof-(tb->y/cu->fsize))) > ((tb->h/cu->fsize)-(linedist*cu->fsize))) &&
+ (cu->totbox > (curbox+1)) ) {
+ maxlen= 0;
+ tb++;
+ curbox++;
+ yof= cu->yof + tb->y/cu->fsize;
+ }
+
+ if(ascii == '\n' || ascii == '\r')
+ xof = cu->xof;
+ else
+ xof= cu->xof + (tb->x/cu->fsize);
+
+ xof= cu->xof + (tb->x/cu->fsize);
+ lnr++;
+ cnr= 0;
+ wsnr= 0;
+ }
+ else if(ascii==9) { /* TAB */
+ ct->xof= xof;
+ ct->yof= yof;
+ ct->linenr= lnr;
+ ct->charnr= cnr++;
+
+ tabfac= (xof-cu->xof+0.01f);
+ tabfac= (float)(2.0*ceil(tabfac/2.0));
+ xof= cu->xof+tabfac;
+ }
+ else {
+ ct->xof= xof;
+ ct->yof= yof;
+ ct->linenr= lnr;
+ ct->charnr= cnr++;
+
+ if (selboxes && (i>=selstart) && (i<=selend)) {
+ sb = &(selboxes[i-selstart]);
+ sb->y = yof*cu->fsize-linedist*cu->fsize*0.1;
+ sb->h = linedist*cu->fsize;
+ sb->w = xof*cu->fsize;
+ }
+
+ if (ascii==32) {
+ wsfac = cu->wordspace;
+ wsnr++;
+ } else wsfac = 1.0;
+ // Set the width of the character
+ if(!che)
+ {
+ twidth = 0;
+ }
+ else
+ {
+ twidth = che->width;
+ }
+ xof += (twidth*wsfac*(1.0+(info->kern/40.0)) ) + xtrax;
+
+ if (selboxes && (i>=selstart) && (i<=selend)) sb->w = (xof*cu->fsize) - sb->w;
+ }
+ ct++;
+ }
+
+
+
+ cu->lines= 1;
+ ct= chartransdata;
+ tmp = mem;
+ for (i= 0; i<=slen; i++, tmp++, ct++) {
+ ascii = *tmp;
+ if(ascii== '\n' || ascii== '\r' || ct->dobreak) cu->lines++;
+ }
+
+ // linedata is now: width of line
+ // linedata2 is now: number of characters
+ // linedata3 is now: maxlen of that line
+ // linedata4 is now: number of whitespaces of line
+
+ if(cu->spacemode!=CU_LEFT) {
+ ct= chartransdata;
+
+ if(cu->spacemode==CU_RIGHT) {
+ for(i=0;i<lnr;i++) linedata[i]= linedata3[i]-linedata[i];
+ for (i=0; i<=slen; i++) {
+ ct->xof+= linedata[ct->linenr];
+ ct++;
+ }
+ } else if(cu->spacemode==CU_MIDDLE) {
+ for(i=0;i<lnr;i++) linedata[i]= (linedata3[i]-linedata[i])/2;
+ for (i=0; i<=slen; i++) {
+ ct->xof+= linedata[ct->linenr];
+ ct++;
+ }
+ } else if((cu->spacemode==CU_FLUSH) &&
+ (cu->tb[0].w != 0.0)) {
+ for(i=0;i<lnr;i++)
+ if(linedata2[i]>1)
+ linedata[i]= (linedata3[i]-linedata[i])/(linedata2[i]-1);
+ for (i=0; i<=slen; i++) {
+ for (j=i; (mem[j]) && (mem[j]!='\n') &&
+ (mem[j]!='\r') && (chartransdata[j].dobreak==0) && (j<slen); j++);
+// if ((mem[j]!='\r') && (mem[j]!='\n') && (mem[j])) {
+ ct->xof+= ct->charnr*linedata[ct->linenr];
+// }
+ ct++;
+ }
+ } else if((cu->spacemode==CU_JUSTIFY) &&
+ (cu->tb[0].w != 0.0)) {
+ curofs= 0;
+ for (i=0; i<=slen; i++) {
+ for (j=i; (mem[j]) && (mem[j]!='\n') &&
+ (mem[j]!='\r') && (chartransdata[j].dobreak==0) && (j<slen); j++);
+ if ((mem[j]!='\r') && (mem[j]!='\n') &&
+ ((chartransdata[j].dobreak!=0))) {
+ if (mem[i]==' ') curofs += (linedata3[ct->linenr]-linedata[ct->linenr])/linedata4[ct->linenr];
+ ct->xof+= curofs;
+ }
+ if (mem[i]=='\n' || mem[i]=='\r' || chartransdata[i].dobreak) curofs= 0;
+ ct++;
+ }
+ }
+ }
+
+ /* TEXT ON CURVE */
+ if(cu->textoncurve) {
+ cucu= cu->textoncurve->data;
+
+ oldflag= cucu->flag;
+ cucu->flag |= (CU_PATH+CU_FOLLOW);
+
+ if(cucu->path==NULL) makeDispListCurveTypes(cu->textoncurve, 0);
+ if(cucu->path) {
+ float imat[4][4], imat3[3][3];
+ Mat4Invert(imat, ob->obmat);
+ Mat3CpyMat4(imat3, imat);
+
+ Mat3CpyMat4(cmat, cu->textoncurve->obmat);
+ Mat3MulMat3(cmat, cmat, imat3);
+ sizefac= Normalize(cmat[0])/cu->fsize;
+
+ minx=miny= 1.0e20f;
+ maxx=maxy= -1.0e20f;
+ ct= chartransdata;
+ for (i=0; i<=slen; i++, ct++) {
+ if(minx>ct->xof) minx= ct->xof;
+ if(maxx<ct->xof) maxx= ct->xof;
+ if(miny>ct->yof) miny= ct->yof;
+ if(maxy<ct->yof) maxy= ct->yof;
+ }
+
+ /* we put the x-coordinaat exact at the curve, the y is rotated */
+
+ /* length correction */
+ distfac= sizefac*cucu->path->totdist/(maxx-minx);
+ timeofs= 0.0;
+
+ if(distfac > 1.0) {
+ /* path longer than text: spacemode involves */
+ distfac= 1.0f/distfac;
+
+ if(cu->spacemode==CU_RIGHT) {
+ timeofs= 1.0f-distfac;
+ }
+ else if(cu->spacemode==CU_MIDDLE) {
+ timeofs= (1.0f-distfac)/2.0f;
+ }
+ else if(cu->spacemode==CU_FLUSH) distfac= 1.0f;
+
+ }
+ else distfac= 1.0;
+
+ distfac/= (maxx-minx);
+
+ timeofs+= distfac*cu->xof; /* not cyclic */
+
+ ct= chartransdata;
+ for (i=0; i<=slen; i++, ct++) {
+
+ /* rotate around center character */
+ ascii = mem[i];
+
+ // Find the character
+ che = vfd->characters.first;
+ while(che)
+ {
+ if(che->index == ascii)
+ break;
+ che = che->next;
+ }
+
+ if(che)
+ {
+ twidth = che->width;
+ }
+ else
+ {
+ twidth = 0;
+ }
+
+ dtime= distfac*0.35f*twidth; /* why not 0.5? */
+ dtime= distfac*0.5f*twidth; /* why not 0.5? */
+
+ ctime= timeofs + distfac*( ct->xof - minx);
+ CLAMP(ctime, 0.0, 1.0);
+
+ /* calc the right loc AND the right rot separately */
+ /* vec, tvec need 4 items */
+ where_on_path(cu->textoncurve, ctime, vec, tvec);
+ where_on_path(cu->textoncurve, ctime+dtime, tvec, rotvec);
+
+ VecMulf(vec, sizefac);
+
+ ct->rot= (float)(M_PI-atan2(rotvec[1], rotvec[0]));
+
+ si= (float)sin(ct->rot);
+ co= (float)cos(ct->rot);
+
+ yof= ct->yof;
+
+ ct->xof= vec[0] + si*yof;
+ ct->yof= vec[1] + co*yof;
+
+ }
+ cucu->flag= oldflag;
+ }
+ }
+
+ if (selboxes) {
+ ct= chartransdata;
+ for (i=0; i<=selend; i++, ct++) {
+ if (i>=selstart) {
+ selboxes[i-selstart].x = ct->xof*cu->fsize;
+ selboxes[i-selstart].y = ct->yof*cu->fsize;
+ }
+ }
+ }
+
+ if(mode==FO_CURSUP || mode==FO_CURSDOWN || mode==FO_PAGEUP || mode==FO_PAGEDOWN) {
+ /* 2: curs up
+ 3: curs down */
+ ct= chartransdata+cu->pos;
+
+ if((mode==FO_CURSUP || mode==FO_PAGEUP) && ct->linenr==0);
+ else if((mode==FO_CURSDOWN || mode==FO_PAGEDOWN) && ct->linenr==lnr);
+ else {
+ switch(mode) {
+ case FO_CURSUP: lnr= ct->linenr-1; break;
+ case FO_CURSDOWN: lnr= ct->linenr+1; break;
+ case FO_PAGEUP: lnr= ct->linenr-10; break;
+ case FO_PAGEDOWN: lnr= ct->linenr+10; break;
+ }
+ cnr= ct->charnr;
+ /* seek for char with lnr en cnr */
+ cu->pos= 0;
+ ct= chartransdata;
+ for (i= 0; i<slen; i++) {
+ if(ct->linenr==lnr) {
+ if(ct->charnr==cnr) break;
+ if( (ct+1)->charnr==0) break;
+ }
+ else if(ct->linenr>lnr) break;
+ cu->pos++;
+ ct++;
+ }
+ }
+ }
+
+ /* cursor first */
+ if(ob==G.obedit) {
+ ct= chartransdata+cu->pos;
+ si= (float)sin(ct->rot);
+ co= (float)cos(ct->rot);
+
+ f= G.textcurs[0];
+
+ f[0]= cu->fsize*(-0.1f*co + ct->xof);
+ f[1]= cu->fsize*(0.1f*si + ct->yof);
+
+ f[2]= cu->fsize*(0.1f*co + ct->xof);
+ f[3]= cu->fsize*(-0.1f*si + ct->yof);
+
+ f[4]= cu->fsize*( 0.1f*co + 0.8f*si + ct->xof);
+ f[5]= cu->fsize*(-0.1f*si + 0.8f*co + ct->yof);
+
+ f[6]= cu->fsize*(-0.1f*co + 0.8f*si + ct->xof);
+ f[7]= cu->fsize*( 0.1f*si + 0.8f*co + ct->yof);
+
+ }
+
+ MEM_freeN(linedata);
+ MEM_freeN(linedata2);
+ MEM_freeN(linedata3);
+ MEM_freeN(linedata4);
+
+ if (mode == FO_SELCHANGE) {
+ MEM_freeN(chartransdata);
+ MEM_freeN(mem);
+ return NULL;
+ }
+
+ if(mode==0) {
+ /* make nurbdata */
+ unsigned long cha;
+
+ freeNurblist(&cu->nurb);
+
+ ct= chartransdata;
+ if (cu->sepchar==0) {
+ for (i= 0; i<slen; i++) {
+ cha = (unsigned long) mem[i];
+ info = &(cu->strinfo[i]);
+ if (info->mat_nr > (ob->totcol)) {
+ /* printf("Error: Illegal material index (%d) in text object, setting to 0\n", info->mat_nr); */
+ info->mat_nr = 0;
+ }
+ // We do not want to see any character for \n or \r
+ if(cha != '\n' && cha != '\r')
+ buildchar(cu, cha, info, ct->xof, ct->yof, ct->rot, i);
+ if ((info->flag & CU_UNDERLINE) && (cu->textoncurve == NULL) && (cha != '\n') && (cha != '\r')) {
+ uloverlap = 0;
+ if ( (i<(slen-1)) && (mem[i+1] != '\n') && (mem[i+1] != '\r') &&
+ ((mem[i+1] != ' ') || (cu->strinfo[i+1].flag & CU_UNDERLINE)) && ((cu->strinfo[i+1].flag & CU_WRAP)==0)
+ ) {
+ uloverlap = xtrax + 0.1;
+ }
+ // Find the character, the characters has to be in the memory already
+ // since character checking has been done earlier already.
+ che = vfd->characters.first;
+ while(che)
+ {
+ if(che->index == cha)
+ break;
+ che = che->next;
+ }
+
+ if(!che) twidth =0; else twidth=che->width;
+ ulwidth = cu->fsize * ((twidth* (1.0+(info->kern/40.0)))+uloverlap);
+ build_underline(cu, ct->xof*cu->fsize, ct->yof*cu->fsize + (cu->ulpos-0.05)*cu->fsize,
+ ct->xof*cu->fsize + ulwidth,
+ ct->yof*cu->fsize + (cu->ulpos-0.05)*cu->fsize - cu->ulheight*cu->fsize,
+ i, info->mat_nr);
+ }
+ ct++;
+ }
+ }
+ else {
+ outta = 0;
+ for (i= 0; (i<slen) && (outta==0); i++) {
+ ascii = mem[i];
+ info = &(cu->strinfo[i]);
+ if (cu->sepchar == (i+1)) {
+ mem[0] = ascii;
+ mem[1] = 0;
+ cu->strinfo[0]= *info;
+ cu->pos = 1;
+ cu->len = 1;
+ vecyo[0] = ct->xof;
+ vecyo[1] = ct->yof;
+ vecyo[2] = 0;
+ Mat4MulVecfl(ob->obmat, vecyo);
+ VECCOPY(ob->loc, vecyo);
+ outta = 1;
+ cu->sepchar = 0;
+ }
+ ct++;
+ }
+ }
+ }
+
+ if(mode==FO_DUPLI) {
+ MEM_freeN(mem);
+ return chartransdata;
+ }
+
+ if(mem)
+ MEM_freeN(mem);
+
+ MEM_freeN(chartransdata);
+ return 0;
+}
+
+
diff --git a/source/blender/blenkernel/intern/group.c b/source/blender/blenkernel/intern/group.c
new file mode 100644
index 00000000000..201d93220f9
--- /dev/null
+++ b/source/blender/blenkernel/intern/group.c
@@ -0,0 +1,327 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_action_types.h"
+#include "DNA_effect_types.h"
+#include "DNA_group_types.h"
+#include "DNA_ID.h"
+#include "DNA_ipo_types.h"
+#include "DNA_material_types.h"
+#include "DNA_object_types.h"
+#include "DNA_nla_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_blenlib.h"
+
+#include "BKE_global.h"
+#include "BKE_group.h"
+#include "BKE_ipo.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_object.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+void free_group_object(GroupObject *go)
+{
+ MEM_freeN(go);
+}
+
+
+void free_group(Group *group)
+{
+ /* don't free group itself */
+ GroupObject *go;
+
+ while(group->gobject.first) {
+ go= group->gobject.first;
+ BLI_remlink(&group->gobject, go);
+ free_group_object(go);
+ }
+}
+
+void unlink_group(Group *group)
+{
+ Material *ma;
+ Object *ob;
+
+ for(ma= G.main->mat.first; ma; ma= ma->id.next) {
+ if(ma->group==group)
+ ma->group= NULL;
+ }
+ for(ob= G.main->object.first; ob; ob= ob->id.next) {
+ bActionStrip *strip;
+ PartEff *paf;
+
+ if(ob->dup_group==group) {
+ ob->dup_group= NULL;
+
+ /* duplicator strips use a group object, we remove it */
+ for(strip= ob->nlastrips.first; strip; strip= strip->next) {
+ if(strip->object)
+ strip->object= NULL;
+ }
+ }
+ for(paf= ob->effect.first; paf; paf= paf->next) {
+ if(paf->type==EFF_PARTICLE) {
+ if(paf->group)
+ paf->group= NULL;
+ }
+ }
+ }
+ group->id.us= 0;
+}
+
+Group *add_group(char *name)
+{
+ Group *group;
+
+ group = alloc_libblock(&G.main->group, ID_GR, name);
+ group->layer= (1<<20)-1;
+ return group;
+}
+
+/* external */
+void add_to_group(Group *group, Object *ob)
+{
+ GroupObject *go;
+
+ if(group==NULL || ob==NULL) return;
+
+ /* check if the object has been added already */
+ for(go= group->gobject.first; go; go= go->next) {
+ if(go->ob==ob) return;
+ }
+
+ go= MEM_callocN(sizeof(GroupObject), "groupobject");
+ BLI_addtail( &group->gobject, go);
+
+ go->ob= ob;
+
+}
+
+/* also used for ob==NULL */
+void rem_from_group(Group *group, Object *ob)
+{
+ GroupObject *go, *gon;
+
+ if(group==NULL) return;
+
+ go= group->gobject.first;
+ while(go) {
+ gon= go->next;
+ if(go->ob==ob) {
+ BLI_remlink(&group->gobject, go);
+ free_group_object(go);
+ }
+ go= gon;
+ }
+}
+
+int object_in_group(Object *ob, Group *group)
+{
+ GroupObject *go;
+
+ if(group==NULL || ob==NULL) return 0;
+
+ for(go= group->gobject.first; go; go= go->next) {
+ if(go->ob==ob)
+ return 1;
+ }
+ return 0;
+}
+
+Group *find_group(Object *ob)
+{
+ Group *group= G.main->group.first;
+
+ while(group) {
+ if(object_in_group(ob, group))
+ return group;
+ group= group->id.next;
+ }
+ return NULL;
+}
+
+void group_tag_recalc(Group *group)
+{
+ GroupObject *go;
+
+ if(group==NULL) return;
+
+ for(go= group->gobject.first; go; go= go->next) {
+ if(go->ob)
+ go->ob->recalc= go->recalc;
+ }
+}
+
+/* only replaces object strips or action when parent nla instructs it */
+/* keep checking nla.c though, in case internal structure of strip changes */
+static void group_replaces_nla(Object *parent, Object *target, char mode)
+{
+ static ListBase nlastrips={NULL, NULL};
+ static bAction *action= NULL;
+ static int done= 0;
+ bActionStrip *strip, *nstrip;
+
+ if(mode=='s') {
+
+ for(strip= parent->nlastrips.first; strip; strip= strip->next) {
+ if(strip->object==target) {
+ if(done==0) {
+ /* clear nla & action from object */
+ nlastrips= target->nlastrips;
+ target->nlastrips.first= target->nlastrips.last= NULL;
+ action= target->action;
+ target->action= NULL;
+ target->nlaflag |= OB_NLA_OVERRIDE;
+ done= 1;
+ }
+ nstrip= MEM_dupallocN(strip);
+ BLI_addtail(&target->nlastrips, nstrip);
+ }
+ }
+ }
+ else if(mode=='e') {
+ if(done) {
+ BLI_freelistN(&target->nlastrips);
+ target->nlastrips= nlastrips;
+ target->action= action;
+
+ nlastrips.first= nlastrips.last= NULL; /* not needed, but yah... :) */
+ action= NULL;
+ done= 0;
+ }
+ }
+}
+
+
+/* puts all group members in local timing system, after this call
+you can draw everything, leaves tags in objects to signal it needs further updating */
+
+/* note: does not work for derivedmesh and render... it recreates all again in convertblender.c */
+void group_handle_recalc_and_update(Object *parent, Group *group)
+{
+ GroupObject *go;
+
+ /* if animated group... */
+ if(parent->sf != 0.0f || parent->nlastrips.first) {
+ int cfrao;
+
+ /* switch to local time */
+ cfrao= G.scene->r.cfra;
+ G.scene->r.cfra -= (int)parent->sf;
+
+ /* we need a DAG per group... */
+ for(go= group->gobject.first; go; go= go->next) {
+ if(go->ob && go->recalc) {
+ go->ob->recalc= go->recalc;
+
+ group_replaces_nla(parent, go->ob, 's');
+ object_handle_update(go->ob);
+ group_replaces_nla(parent, go->ob, 'e');
+
+ /* leave recalc tags in case group members are in normal scene */
+ go->ob->recalc= go->recalc;
+ }
+ }
+
+ /* restore */
+ G.scene->r.cfra= cfrao;
+ }
+ else {
+ /* only do existing tags, as set by regular depsgraph */
+ for(go= group->gobject.first; go; go= go->next) {
+ if(go->ob) {
+ if(go->ob->recalc) {
+ object_handle_update(go->ob);
+ }
+ }
+ }
+ }
+}
+
+Object *group_get_member_with_action(Group *group, bAction *act)
+{
+ GroupObject *go;
+
+ if(group==NULL || act==NULL) return NULL;
+
+ for(go= group->gobject.first; go; go= go->next) {
+ if(go->ob) {
+ if(go->ob->action==act)
+ return go->ob;
+ if(go->ob->nlastrips.first) {
+ bActionStrip *strip;
+
+ for(strip= go->ob->nlastrips.first; strip; strip= strip->next) {
+ if(strip->act==act)
+ return go->ob;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+/* if group has NLA, we try to map the used objects in NLA to group members */
+/* this assuming that object has received a new group link */
+void group_relink_nla_objects(Object *ob)
+{
+ Group *group;
+ GroupObject *go;
+ bActionStrip *strip;
+
+ if(ob==NULL || ob->dup_group==NULL) return;
+ group= ob->dup_group;
+
+ for(strip= ob->nlastrips.first; strip; strip= strip->next) {
+ if(strip->object) {
+ for(go= group->gobject.first; go; go= go->next) {
+ if(go->ob) {
+ if(strcmp(go->ob->id.name, strip->object->id.name)==0)
+ break;
+ }
+ }
+ if(go)
+ strip->object= go->ob;
+ else
+ strip->object= NULL;
+ }
+
+ }
+}
+
diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c
new file mode 100644
index 00000000000..f144d2badd1
--- /dev/null
+++ b/source/blender/blenkernel/intern/icons.c
@@ -0,0 +1,302 @@
+/**
+* $Id$
+*
+* ***** BEGIN GPL LICENSE BLOCK *****
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*
+* The Original Code is Copyright (C) 2006-2007 Blender Foundation.
+* All rights reserved.
+*
+* The Original Code is: all of this file.
+*
+* Contributor(s): none yet.
+*
+* ***** END GPL LICENSE BLOCK *****
+*
+*/
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_ID.h"
+#include "DNA_image_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_material_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_world_types.h"
+
+#include "BLI_ghash.h"
+
+#include "BKE_icons.h"
+
+#define GS(a) (*((short *)(a)))
+
+/* GLOBALS */
+
+static GHash* gIcons = NULL;
+
+static int gNextIconId = 1;
+
+static int gFirstIconId = 1;
+
+
+static void icon_free(void *val)
+{
+ Icon* icon = val;
+
+ if (icon)
+ {
+ if (icon->drawinfo_free) {
+ icon->drawinfo_free(icon->drawinfo);
+ }
+ else if (icon->drawinfo) {
+ MEM_freeN(icon->drawinfo);
+ }
+ MEM_freeN(icon);
+ }
+}
+
+/* create an id for a new icon and make sure that ids from deleted icons get reused
+ after the integer number range is used up */
+static int get_next_free_id()
+{
+ int startId = gFirstIconId;
+
+ /* if we haven't used up the int number range, we just return the next int */
+ if (gNextIconId>=gFirstIconId)
+ return gNextIconId++;
+
+ /* now we try to find the smallest icon id not stored in the gIcons hash */
+ while (BLI_ghash_lookup(gIcons, (void *)startId) && startId>=gFirstIconId)
+ startId++;
+
+ /* if we found a suitable one that isnt used yet, return it */
+ if (startId>=gFirstIconId)
+ return startId;
+
+ /* fail */
+ return 0;
+}
+
+void BKE_icons_init(int first_dyn_id)
+{
+ gNextIconId = first_dyn_id;
+ gFirstIconId = first_dyn_id;
+
+ if (!gIcons)
+ gIcons = BLI_ghash_new(BLI_ghashutil_inthash, BLI_ghashutil_intcmp);
+}
+
+void BKE_icons_free()
+{
+ if(gIcons)
+ BLI_ghash_free(gIcons, 0, icon_free);
+ gIcons = NULL;
+}
+
+struct PreviewImage* BKE_previewimg_create()
+{
+ PreviewImage* prv_img = NULL;
+ int i;
+
+ prv_img = MEM_callocN(sizeof(PreviewImage), "img_prv");
+
+ for (i=0; i<PREVIEW_MIPMAPS; ++i) {
+ prv_img->changed[i] = 1;
+ }
+ return prv_img;
+}
+
+void BKE_previewimg_free(PreviewImage **prv)
+{
+ if(prv && (*prv)) {
+ int i;
+
+ for (i=0; i<PREVIEW_MIPMAPS;++i) {
+ if ((*prv)->rect[i]) {
+ MEM_freeN((*prv)->rect[i]);
+ (*prv)->rect[i] = NULL;
+ }
+ }
+ MEM_freeN((*prv));
+ *prv = NULL;
+ }
+}
+
+struct PreviewImage* BKE_previewimg_copy(PreviewImage *prv)
+{
+ PreviewImage* prv_img = NULL;
+ int i;
+
+ if (prv) {
+ prv_img = MEM_dupallocN(prv);
+ for (i=0; i < PREVIEW_MIPMAPS; ++i) {
+ if (prv->rect[i]) {
+ prv_img->rect[i] = MEM_dupallocN(prv->rect[i]);
+ } else {
+ prv_img->rect[i] = NULL;
+ }
+ }
+ }
+ return prv_img;
+}
+
+void BKE_previewimg_free_id(ID *id)
+{
+ if (GS(id->name) == ID_MA) {
+ Material *mat = (Material*)id;
+ BKE_previewimg_free(&mat->preview);
+ } else if (GS(id->name) == ID_TE) {
+ Tex *tex = (Tex*)id;
+ BKE_previewimg_free(&tex->preview);
+ } else if (GS(id->name) == ID_WO) {
+ World *wo = (World*)id;
+ BKE_previewimg_free(&wo->preview);
+ } else if (GS(id->name) == ID_LA) {
+ Lamp *la = (Lamp*)id;
+ BKE_previewimg_free(&la->preview);
+ } else if (GS(id->name) == ID_IM) {
+ Image *img = (Image*)id;
+ BKE_previewimg_free(&img->preview);
+ }
+}
+
+PreviewImage* BKE_previewimg_get(ID *id)
+{
+ PreviewImage* prv_img = NULL;
+
+ if (GS(id->name) == ID_MA) {
+ Material *mat = (Material*)id;
+ if (!mat->preview) mat->preview = BKE_previewimg_create();
+ prv_img = mat->preview;
+ } else if (GS(id->name) == ID_TE) {
+ Tex *tex = (Tex*)id;
+ if (!tex->preview) tex->preview = BKE_previewimg_create();
+ prv_img = tex->preview;
+ } else if (GS(id->name) == ID_WO) {
+ World *wo = (World*)id;
+ if (!wo->preview) wo->preview = BKE_previewimg_create();
+ prv_img = wo->preview;
+ } else if (GS(id->name) == ID_LA) {
+ Lamp *la = (Lamp*)id;
+ if (!la->preview) la->preview = BKE_previewimg_create();
+ prv_img = la->preview;
+ } else if (GS(id->name) == ID_IM) {
+ Image *img = (Image*)id;
+ if (!img->preview) img->preview = BKE_previewimg_create();
+ prv_img = img->preview;
+ }
+
+ return prv_img;
+}
+
+void BKE_icon_changed(int id)
+{
+ Icon* icon = 0;
+
+ if (!id) return;
+
+ icon = BLI_ghash_lookup(gIcons, (void *)id);
+
+ if (icon)
+ {
+ PreviewImage *prv = BKE_previewimg_get((ID*)icon->obj);
+
+ /* all previews changed */
+ if (prv) {
+ int i;
+ for (i=0; i<PREVIEW_MIPMAPS; ++i) {
+ prv->changed[i] = 1;
+ }
+ }
+ }
+}
+
+int BKE_icon_getid(struct ID* id)
+{
+ Icon* new_icon = 0;
+
+ if (!id)
+ return 0;
+
+ if (id->icon_id)
+ return id->icon_id;
+
+ id->icon_id = get_next_free_id();
+
+ if (!id->icon_id){
+ printf("BKE_icon_getid: Internal error - not enough IDs\n");
+ return 0;
+ }
+
+ new_icon = MEM_callocN(sizeof(Icon), "texicon");
+
+ new_icon->obj = id;
+ new_icon->type = GS(id->name);
+
+ /* next two lines make sure image gets created */
+ new_icon->drawinfo = 0;
+ new_icon->drawinfo_free = 0;
+
+ BLI_ghash_insert(gIcons, (void *)id->icon_id, new_icon);
+
+ return id->icon_id;
+}
+
+Icon* BKE_icon_get(int icon_id)
+{
+ Icon* icon = 0;
+
+ icon = BLI_ghash_lookup(gIcons, (void*)icon_id);
+
+ if (!icon) {
+ printf("BKE_icon_get: Internal error, no icon for icon ID: %d\n", icon_id);
+ return 0;
+ }
+
+ return icon;
+}
+
+void BKE_icon_set(int icon_id, struct Icon* icon)
+{
+ Icon* old_icon = 0;
+
+ old_icon = BLI_ghash_lookup(gIcons, (void*)icon_id);
+
+ if (old_icon)
+ {
+ printf("BKE_icon_set: Internal error, icon already set: %d\n", icon_id);
+ return;
+ }
+
+ BLI_ghash_insert(gIcons, (void *)icon_id, icon);
+}
+
+void BKE_icon_delete(struct ID* id)
+{
+
+ if (!id->icon_id) return; /* no icon defined for library object */
+
+ BLI_ghash_remove(gIcons, (void*)id->icon_id, 0, icon_free);
+ id->icon_id = 0;
+}
diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c
new file mode 100644
index 00000000000..bf2a3aae11a
--- /dev/null
+++ b/source/blender/blenkernel/intern/idprop.c
@@ -0,0 +1,443 @@
+/**
+ * $Id: idprop.c
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Joseph Eagar
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "DNA_listBase.h"
+#include "DNA_ID.h"
+
+#include "BKE_idprop.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_utildefines.h"
+
+#include "BLI_blenlib.h"
+
+#include "MEM_guardedalloc.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define BSTR_EQ(a, b) (*(a) == *(b) && !strcmp(a, b))
+
+/* IDPropertyTemplate is a union in DNA_ID.h */
+
+/*local size table.*/
+static char idp_size_table[] = {
+ 1, /*strings*/
+ sizeof(int),
+ sizeof(float),
+ sizeof(float)*3, /*Vector type, deprecated*/
+ sizeof(float)*16, /*Matrix type, deprecated*/
+ 0, /*arrays don't have a fixed size*/
+ sizeof(ListBase), /*Group type*/
+ sizeof(void*)
+};
+
+
+/* ----------- Array Type ----------- */
+
+/*this function works for strings too!*/
+void IDP_ResizeArray(IDProperty *prop, int newlen)
+{
+ void *newarr;
+ int newsize=newlen;
+
+ /*first check if the array buffer size has room*/
+ /*if newlen is 200 chars less then totallen, reallocate anyway*/
+ if (newlen <= prop->totallen && prop->totallen - newlen < 200) {
+ prop->len = newlen;
+ return;
+ }
+
+ /* - Note: This code comes from python, here's the corrusponding comment. - */
+ /* This over-allocates proportional to the list size, making room
+ * for additional growth. The over-allocation is mild, but is
+ * enough to give linear-time amortized behavior over a long
+ * sequence of appends() in the presence of a poorly-performing
+ * system realloc().
+ * The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
+ */
+ newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize;
+
+ newarr = MEM_callocN(idp_size_table[prop->type]*newsize, "idproperty array resized");
+ /*newlen is bigger*/
+ if (newlen >= prop->len) memcpy(newarr, prop->data.pointer, prop->len*idp_size_table[prop->type]);
+ /*newlen is smaller*/
+ else memcpy(newarr, prop->data.pointer, newlen*prop->len*idp_size_table[prop->type]);
+
+ MEM_freeN(prop->data.pointer);
+ prop->data.pointer = newarr;
+ prop->len = newlen;
+ prop->totallen = newsize;
+}
+
+ void IDP_FreeArray(IDProperty *prop)
+{
+ if (prop->data.pointer)
+ MEM_freeN(prop->data.pointer);
+}
+
+
+ static IDProperty *idp_generic_copy(IDProperty *prop)
+ {
+ IDProperty *newp = MEM_callocN(sizeof(IDProperty), "IDProperty array dup");
+
+ strncpy(newp->name, prop->name, MAX_IDPROP_NAME);
+ newp->type = prop->type;
+ newp->flag = prop->flag;
+ newp->data.val = prop->data.val;
+
+ return newp;
+ }
+
+IDProperty *IDP_CopyArray(IDProperty *prop)
+{
+ IDProperty *newp = idp_generic_copy(prop);
+
+ if (prop->data.pointer) newp->data.pointer = MEM_dupallocN(prop->data.pointer);
+ newp->len = prop->len;
+ newp->subtype = prop->subtype;
+ newp->totallen = prop->totallen;
+
+ return newp;
+}
+
+/*taken from readfile.c*/
+#define SWITCH_LONGINT(a) { \
+ char s_i, *p_i; \
+ p_i= (char *)&(a); \
+ s_i=p_i[0]; p_i[0]=p_i[7]; p_i[7]=s_i; \
+ s_i=p_i[1]; p_i[1]=p_i[6]; p_i[6]=s_i; \
+ s_i=p_i[2]; p_i[2]=p_i[5]; p_i[5]=s_i; \
+ s_i=p_i[3]; p_i[3]=p_i[4]; p_i[4]=s_i; }
+
+
+
+/* ---------- String Type ------------ */
+IDProperty *IDP_CopyString(IDProperty *prop)
+{
+ IDProperty *newp = idp_generic_copy(prop);
+
+ if (prop->data.pointer) newp->data.pointer = MEM_dupallocN(prop->data.pointer);
+ newp->len = prop->len;
+ newp->subtype = prop->subtype;
+ newp->totallen = prop->totallen;
+
+ return newp;
+}
+
+
+void IDP_AssignString(IDProperty *prop, char *st)
+{
+ int stlen;
+
+ stlen = strlen(st);
+
+ IDP_ResizeArray(prop, stlen+1); /*make room for null byte :) */
+ strcpy(prop->data.pointer, st);
+}
+
+void IDP_ConcatStringC(IDProperty *prop, char *st)
+{
+ int newlen;
+
+ newlen = prop->len + strlen(st);
+ /*we have to remember that prop->len includes the null byte for strings.
+ so there's no need to add +1 to the resize function.*/
+ IDP_ResizeArray(prop, newlen);
+ strcat(prop->data.pointer, st);
+}
+
+void IDP_ConcatString(IDProperty *str1, IDProperty *append)
+{
+ int newlen;
+
+ /*since ->len for strings includes the NULL byte, we have to subtract one or
+ we'll get an extra null byte after each concatination operation.*/
+ newlen = str1->len + append->len - 1;
+ IDP_ResizeArray(str1, newlen);
+ strcat(str1->data.pointer, append->data.pointer);
+}
+
+void IDP_FreeString(IDProperty *prop)
+{
+ MEM_freeN(prop->data.pointer);
+}
+
+
+/*-------- ID Type, not in use yet -------*/
+
+void IDP_LinkID(IDProperty *prop, ID *id)
+{
+ if (prop->data.pointer) ((ID*)prop->data.pointer)->us--;
+ prop->data.pointer = id;
+ id_us_plus(id);
+}
+
+void IDP_UnlinkID(IDProperty *prop)
+{
+ ((ID*)prop->data.pointer)->us--;
+}
+
+/*-------- Group Functions -------*/
+
+/*checks if a property with the same name as prop exists, and if so replaces it.*/
+IDProperty *IDP_CopyGroup(IDProperty *prop)
+{
+ IDProperty *newp = idp_generic_copy(prop), *link;
+
+ for (link=prop->data.group.first; link; link=link->next) {
+ BLI_addtail(&newp->data.group, IDP_CopyProperty(link));
+ }
+
+ return newp;
+}
+
+void IDP_ReplaceInGroup(IDProperty *group, IDProperty *prop)
+{
+ IDProperty *loop;
+ for (loop=group->data.group.first; loop; loop=loop->next) {
+ if (BSTR_EQ(loop->name, prop->name)) {
+ if (loop->next) BLI_insertlinkbefore(&group->data.group, loop->next, prop);
+ else BLI_addtail(&group->data.group, prop);
+ BLI_remlink(&group->data.group, loop);
+ IDP_FreeProperty(loop);
+ MEM_freeN(loop);
+ group->len++;
+ return;
+ }
+ }
+
+ group->len++;
+ BLI_addtail(&group->data.group, prop);
+}
+
+/*returns 0 if an id property with the same name exists and it failed,
+ or 1 if it succeeded in adding to the group.*/
+int IDP_AddToGroup(IDProperty *group, IDProperty *prop)
+{
+ IDProperty *loop;
+ for (loop=group->data.group.first; loop; loop=loop->next) {
+ if (BSTR_EQ(loop->name, prop->name)) return 0;
+ }
+
+ group->len++;
+ BLI_addtail(&group->data.group, prop);
+
+ return 1;
+}
+
+int IDP_InsertToGroup(IDProperty *group, IDProperty *previous, IDProperty *pnew)
+{
+ IDProperty *loop;
+ for (loop=group->data.group.first; loop; loop=loop->next) {
+ if (BSTR_EQ(loop->name, pnew->name)) return 0;
+ }
+
+ group->len++;
+
+ BLI_insertlink(&group->data.group, previous, pnew);
+ return 1;
+}
+
+void IDP_RemFromGroup(IDProperty *group, IDProperty *prop)
+{
+ group->len--;
+ BLI_remlink(&group->data.group, prop);
+}
+
+IDProperty *IDP_GetPropertyFromGroup(IDProperty *prop, char *name)
+{
+ IDProperty *loop;
+ for (loop=prop->data.group.first; loop; loop=loop->next) {
+ if (strcmp(loop->name, name)==0) return loop;
+ }
+ return NULL;
+}
+
+typedef struct IDPIter {
+ void *next;
+ IDProperty *parent;
+} IDPIter;
+
+void *IDP_GetGroupIterator(IDProperty *prop)
+{
+ IDPIter *iter = MEM_callocN(sizeof(IDPIter), "IDPIter");
+ iter->next = prop->data.group.first;
+ iter->parent = prop;
+ return (void*) iter;
+}
+
+IDProperty *IDP_GroupIterNext(void *vself)
+{
+ IDPIter *self = (IDPIter*) vself;
+ Link *next = (Link*) self->next;
+ if (self->next == NULL) {
+ MEM_freeN(self);
+ return NULL;
+ }
+
+ self->next = next->next;
+ return (void*) next;
+}
+
+void IDP_FreeIterBeforeEnd(void *vself)
+{
+ MEM_freeN(vself);
+}
+
+/*Ok, the way things work, Groups free the ID Property structs of their children.
+ This is because all ID Property freeing functions free only direct data (not the ID Property
+ struct itself), but for Groups the child properties *are* considered
+ direct data.*/
+void IDP_FreeGroup(IDProperty *prop)
+{
+ IDProperty *loop, *next;
+ for (loop=prop->data.group.first; loop; loop=next)
+ {
+ next = loop->next;
+ BLI_remlink(&prop->data.group, loop);
+ IDP_FreeProperty(loop);
+ MEM_freeN(loop);
+ }
+}
+
+
+/*-------- Main Functions --------*/
+IDProperty *IDP_CopyProperty(IDProperty *prop)
+{
+ switch (prop->type) {
+ case IDP_GROUP: return IDP_CopyGroup(prop);
+ case IDP_STRING: return IDP_CopyString(prop);
+ case IDP_ARRAY: return IDP_CopyArray(prop);
+ default: return idp_generic_copy(prop);
+ }
+}
+
+IDProperty *IDP_GetProperties(ID *id, int create_if_needed)
+{
+ if (id->properties) return id->properties;
+ else {
+ if (create_if_needed) {
+ id->properties = MEM_callocN(sizeof(IDProperty), "IDProperty");
+ id->properties->type = IDP_GROUP;
+ }
+ return id->properties;
+ }
+}
+
+IDProperty *IDP_New(int type, IDPropertyTemplate val, char *name)
+{
+ IDProperty *prop=NULL;
+
+ switch (type) {
+ case IDP_INT:
+ prop = MEM_callocN(sizeof(IDProperty), "IDProperty int");
+ prop->data.val = val.i;
+ break;
+ case IDP_FLOAT:
+ prop = MEM_callocN(sizeof(IDProperty), "IDProperty float");
+ *(float*)&prop->data.val = val.f;
+ break;
+ case IDP_ARRAY:
+ {
+ /*for now, we only support float and int arrays*/
+ if (val.array.type == IDP_FLOAT || val.array.type == IDP_INT) {
+ prop = MEM_callocN(sizeof(IDProperty), "IDProperty array");
+ prop->len = prop->totallen = val.array.len;
+ prop->subtype = val.array.type;
+ prop->data.pointer = MEM_callocN(idp_size_table[val.array.type]*val.array.len, "id property array");
+ break;
+ } else {
+ return NULL;
+ }
+ }
+ case IDP_STRING:
+ {
+ char *st = val.str;
+ int stlen;
+
+ prop = MEM_callocN(sizeof(IDProperty), "IDProperty string");
+ if (st == NULL) {
+ prop->data.pointer = MEM_callocN(DEFAULT_ALLOC_FOR_NULL_STRINGS, "id property string 1");
+ prop->totallen = DEFAULT_ALLOC_FOR_NULL_STRINGS;
+ prop->len = 1; /*NULL string, has len of 1 to account for null byte.*/
+ } else {
+ stlen = strlen(st) + 1;
+ prop->data.pointer = MEM_callocN(stlen, "id property string 2");
+ prop->len = prop->totallen = stlen;
+ strcpy(prop->data.pointer, st);
+ }
+ break;
+ }
+ case IDP_GROUP:
+ {
+ prop = MEM_callocN(sizeof(IDProperty), "IDProperty group");
+ /* heh I think all needed values are set properly by calloc anyway :) */
+ break;
+ }
+ default:
+ {
+ prop = MEM_callocN(sizeof(IDProperty), "IDProperty array");
+ break;
+ }
+ }
+
+ prop->type = type;
+ strncpy(prop->name, name, MAX_IDPROP_NAME);
+ return prop;
+}
+
+/*NOTE: this will free all child properties of list arrays and groups!
+ Also, note that this does NOT unlink anything! Plus it doesn't free
+ the actual IDProperty struct either.*/
+void IDP_FreeProperty(IDProperty *prop)
+{
+ switch (prop->type) {
+ case IDP_ARRAY:
+ IDP_FreeArray(prop);
+ break;
+ case IDP_STRING:
+ IDP_FreeString(prop);
+ break;
+ case IDP_GROUP:
+ IDP_FreeGroup(prop);
+ break;
+ }
+}
+
+/*Unlinks any IDProperty<->ID linkage that might be going on.*/
+void IDP_UnlinkProperty(IDProperty *prop)
+{
+ switch (prop->type) {
+ case IDP_ID:
+ IDP_UnlinkID(prop);
+ }
+}
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
new file mode 100644
index 00000000000..17a4dfd3db9
--- /dev/null
+++ b/source/blender/blenkernel/intern/image.c
@@ -0,0 +1,1805 @@
+/* image.c
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Blender Foundation, 2006
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <math.h>
+#ifndef WIN32
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+
+#include <time.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#ifdef WITH_OPENEXR
+#include "intern/openexr/openexr_multi.h"
+#endif
+
+#include "DNA_image_types.h"
+#include "DNA_packedFile_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+#include "BLI_threads.h"
+
+#include "BKE_bmfont.h"
+#include "BKE_global.h"
+#include "BKE_icons.h"
+#include "BKE_image.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_packedFile.h"
+#include "BKE_scene.h"
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
+
+#include "PIL_time.h"
+
+#include "RE_pipeline.h"
+
+/* bad level; call to free_realtime_image */
+#include "BKE_bad_level_calls.h"
+
+/* for stamp drawing to an image */
+#include "BMF_Api.h"
+
+#include "blendef.h"
+#include "BSE_time.h"
+
+/* max int, to indicate we don't store sequences in ibuf */
+#define IMA_NO_INDEX 0x7FEFEFEF
+
+/* quick lookup: supports 1 million frames, thousand passes */
+#define IMA_MAKE_INDEX(frame, index) ((frame)<<10)+index
+#define IMA_INDEX_FRAME(index) (index>>10)
+
+/* ******** IMAGE PROCESSING ************* */
+
+/* used by sequencer */
+void converttopremul(struct ImBuf *ibuf)
+{
+ int x, y, val;
+ char *cp;
+
+ if(ibuf==0) return;
+ if(ibuf->depth==24) { /* put alpha at 255 */
+
+ cp= (char *)(ibuf->rect);
+ for(y=0; y<ibuf->y; y++) {
+ for(x=0; x<ibuf->x; x++, cp+=4) {
+ cp[3]= 255;
+ }
+ }
+ return;
+ }
+
+ cp= (char *)(ibuf->rect);
+ for(y=0; y<ibuf->y; y++) {
+ for(x=0; x<ibuf->x; x++, cp+=4) {
+ if(cp[3]==0) {
+ cp[0]= cp[1]= cp[2]= 0;
+ }
+ else if(cp[3]!=255) {
+ val= cp[3];
+ cp[0]= (cp[0]*val)>>8;
+ cp[1]= (cp[1]*val)>>8;
+ cp[2]= (cp[2]*val)>>8;
+ }
+ }
+ }
+}
+
+static void de_interlace_ng(struct ImBuf *ibuf) /* neogeo fields */
+{
+ struct ImBuf * tbuf1, * tbuf2;
+
+ if (ibuf == 0) return;
+ if (ibuf->flags & IB_fields) return;
+ ibuf->flags |= IB_fields;
+
+ if (ibuf->rect) {
+ /* make copies */
+ tbuf1 = IMB_allocImBuf(ibuf->x, (short)(ibuf->y >> 1), (unsigned char)32, (int)IB_rect, (unsigned char)0);
+ tbuf2 = IMB_allocImBuf(ibuf->x, (short)(ibuf->y >> 1), (unsigned char)32, (int)IB_rect, (unsigned char)0);
+
+ ibuf->x *= 2;
+
+ IMB_rectcpy(tbuf1, ibuf, 0, 0, 0, 0, ibuf->x, ibuf->y);
+ IMB_rectcpy(tbuf2, ibuf, 0, 0, tbuf2->x, 0, ibuf->x, ibuf->y);
+
+ ibuf->x /= 2;
+ IMB_rectcpy(ibuf, tbuf1, 0, 0, 0, 0, tbuf1->x, tbuf1->y);
+ IMB_rectcpy(ibuf, tbuf2, 0, tbuf2->y, 0, 0, tbuf2->x, tbuf2->y);
+
+ IMB_freeImBuf(tbuf1);
+ IMB_freeImBuf(tbuf2);
+ }
+ ibuf->y /= 2;
+}
+
+static void de_interlace_st(struct ImBuf *ibuf) /* standard fields */
+{
+ struct ImBuf * tbuf1, * tbuf2;
+
+ if (ibuf == 0) return;
+ if (ibuf->flags & IB_fields) return;
+ ibuf->flags |= IB_fields;
+
+ if (ibuf->rect) {
+ /* make copies */
+ tbuf1 = IMB_allocImBuf(ibuf->x, (short)(ibuf->y >> 1), (unsigned char)32, IB_rect, 0);
+ tbuf2 = IMB_allocImBuf(ibuf->x, (short)(ibuf->y >> 1), (unsigned char)32, IB_rect, 0);
+
+ ibuf->x *= 2;
+
+ IMB_rectcpy(tbuf1, ibuf, 0, 0, 0, 0, ibuf->x, ibuf->y);
+ IMB_rectcpy(tbuf2, ibuf, 0, 0, tbuf2->x, 0, ibuf->x, ibuf->y);
+
+ ibuf->x /= 2;
+ IMB_rectcpy(ibuf, tbuf2, 0, 0, 0, 0, tbuf2->x, tbuf2->y);
+ IMB_rectcpy(ibuf, tbuf1, 0, tbuf2->y, 0, 0, tbuf1->x, tbuf1->y);
+
+ IMB_freeImBuf(tbuf1);
+ IMB_freeImBuf(tbuf2);
+ }
+ ibuf->y /= 2;
+}
+
+void image_de_interlace(Image *ima, int odd)
+{
+ ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL);
+ if(ibuf) {
+ if(odd)
+ de_interlace_st(ibuf);
+ else
+ de_interlace_ng(ibuf);
+ }
+}
+
+/* ***************** ALLOC & FREE, DATA MANAGING *************** */
+
+static void image_free_buffers(Image *ima)
+{
+ ImBuf *ibuf;
+
+ while((ibuf = ima->ibufs.first)) {
+ BLI_remlink(&ima->ibufs, ibuf);
+
+ if (ibuf->userdata) {
+ MEM_freeN(ibuf->userdata);
+ ibuf->userdata = NULL;
+ }
+ IMB_freeImBuf(ibuf);
+ }
+
+ if(ima->anim) IMB_free_anim(ima->anim);
+ ima->anim= NULL;
+
+ if(ima->rr) {
+ RE_FreeRenderResult(ima->rr);
+ ima->rr= NULL;
+ }
+
+ free_realtime_image(ima);
+
+ ima->ok= IMA_OK;
+}
+
+/* called by library too, do not free ima itself */
+void free_image(Image *ima)
+{
+
+ image_free_buffers(ima);
+ if (ima->packedfile) {
+ freePackedFile(ima->packedfile);
+ ima->packedfile = NULL;
+ }
+ BKE_icon_delete(&ima->id);
+ ima->id.icon_id = 0;
+ if (ima->preview) {
+ BKE_previewimg_free(&ima->preview);
+ }
+
+}
+
+/* only image block itself */
+static Image *image_alloc(const char *name, short source, short type)
+{
+ Image *ima;
+
+ ima= alloc_libblock(&G.main->image, ID_IM, name);
+ if(ima) {
+ ima->ok= IMA_OK;
+
+ ima->xrep= ima->yrep= 1;
+ ima->aspx= ima->aspy= 1.0;
+ ima->gen_x= 256; ima->gen_y= 256;
+ ima->gen_type= 1; /* no defines yet? */
+
+ ima->source= source;
+ ima->type= type;
+ }
+ return ima;
+}
+
+/* get the ibuf from an image cache, local use here only */
+static ImBuf *image_get_ibuf(Image *ima, int index, int frame)
+{
+ if(index==IMA_NO_INDEX)
+ return ima->ibufs.first;
+ else {
+ ImBuf *ibuf;
+
+ index= IMA_MAKE_INDEX(frame, index);
+ for(ibuf= ima->ibufs.first; ibuf; ibuf= ibuf->next)
+ if(ibuf->index==index)
+ return ibuf;
+ return NULL;
+ }
+}
+
+/* no ima->ibuf anymore, but listbase */
+static void image_remove_ibuf(Image *ima, ImBuf *ibuf)
+{
+ if(ibuf) {
+ BLI_remlink(&ima->ibufs, ibuf);
+ IMB_freeImBuf(ibuf);
+ }
+}
+
+
+/* no ima->ibuf anymore, but listbase */
+static void image_assign_ibuf(Image *ima, ImBuf *ibuf, int index, int frame)
+{
+ if(ibuf) {
+ ImBuf *link;
+
+ if(index!=IMA_NO_INDEX)
+ index= IMA_MAKE_INDEX(frame, index);
+
+ /* insert based on index */
+ for(link= ima->ibufs.first; link; link= link->next)
+ if(link->index>=index)
+ break;
+ /* now we don't want copies? */
+ if(link && ibuf->index==link->index) {
+ ImBuf *prev= ibuf->prev;
+ image_remove_ibuf(ima, link);
+ link= prev;
+ }
+
+ /* this function accepts link==NULL */
+ BLI_insertlinkbefore(&ima->ibufs, link, ibuf);
+
+ ibuf->index= index;
+ }
+
+}
+
+/* checks if image was already loaded, then returns same image */
+/* otherwise creates new. */
+/* does not load ibuf itself */
+Image *BKE_add_image_file(const char *name)
+{
+ Image *ima;
+ int file, len;
+ const char *libname;
+ char str[FILE_MAX], strtest[FILE_MAX];
+
+ /* escape when name is directory */
+ len= strlen(name);
+ if(len) {
+ if(name[len-1]=='/' || name[len-1]=='\\')
+ return NULL;
+ }
+
+ BLI_strncpy(str, name, sizeof(str));
+ BLI_convertstringcode(str, G.sce, G.scene->r.cfra);
+
+ /* exists? */
+ file= open(str, O_BINARY|O_RDONLY);
+ if(file== -1) return NULL;
+ close(file);
+
+ /* first search an identical image */
+ for(ima= G.main->image.first; ima; ima= ima->id.next) {
+ if(ima->source!=IMA_SRC_VIEWER) {
+ BLI_strncpy(strtest, ima->name, sizeof(ima->name));
+ BLI_convertstringcode(strtest, G.sce, G.scene->r.cfra);
+
+ if( strcmp(strtest, str)==0 ) {
+ if(ima->anim==NULL || ima->id.us==0) {
+ BLI_strncpy(ima->name, name, sizeof(ima->name)); /* for stringcode */
+ ima->id.us++; /* officially should not, it doesn't link here! */
+ if(ima->ok==0)
+ ima->ok= IMA_OK;
+ /* RETURN! */
+ return ima;
+ }
+ }
+ }
+ }
+ /* add new image */
+
+ /* create a short library name */
+ len= strlen(name);
+
+ while (len > 0 && name[len - 1] != '/' && name[len - 1] != '\\') len--;
+ libname= name+len;
+
+ ima= image_alloc(libname, IMA_SRC_FILE, IMA_TYPE_IMAGE);
+ BLI_strncpy(ima->name, name, sizeof(ima->name));
+
+ /* do a wild guess! */
+ if(BLI_testextensie(name, ".avi") || BLI_testextensie(name, ".mov")
+ || BLI_testextensie(name, ".mpg") || BLI_testextensie(name, ".mp4"))
+ ima->source= IMA_SRC_MOVIE;
+
+ return ima;
+}
+
+static ImBuf *add_ibuf_size(int width, int height, char *name, short uvtestgrid, float color[4])
+{
+ ImBuf *ibuf;
+ float h=0.0, hoffs=0.0, hue=0.0, s=0.9, v=0.9, r, g, b;
+ unsigned char *rect;
+ int x, y;
+ int checkerwidth=21, dark=1;
+
+ ibuf= IMB_allocImBuf(width, height, 24, IB_rect, 0);
+ strcpy(ibuf->name, "Untitled");
+ ibuf->userflags |= IB_BITMAPDIRTY;
+
+ rect= (unsigned char*)ibuf->rect;
+
+ if (uvtestgrid) {
+ /* these two passes could be combined into one, but it's more readable and
+ * easy to tweak like this, speed isn't really that much of an issue in this situation... */
+
+ /* checkers */
+ for(y=0; y<ibuf->y; y++) {
+ dark = pow(-1, floor(y / checkerwidth));
+
+ for(x=0; x<ibuf->x; x++, rect+=4) {
+ if (x % checkerwidth == 0) dark *= -1;
+
+ if (dark > 0) {
+ rect[0] = rect[1] = rect[2] = 64;
+ rect[3] = 255;
+ } else {
+ rect[0] = rect[1] = rect[2] = 150;
+ rect[3] = 255;
+ }
+ }
+ }
+
+ /* 2nd pass, colored + */
+ rect= (unsigned char*)ibuf->rect;
+
+ for(y=0; y<ibuf->y; y++) {
+ hoffs = 0.125 * floor(y / checkerwidth);
+
+ for(x=0; x<ibuf->x; x++, rect+=4) {
+ h = 0.125 * floor(x / checkerwidth);
+
+ if ((fabs((x % checkerwidth) - (checkerwidth / 2)) < 4) &&
+ (fabs((y % checkerwidth) - (checkerwidth / 2)) < 4)) {
+
+ if ((fabs((x % checkerwidth) - (checkerwidth / 2)) < 1) ||
+ (fabs((y % checkerwidth) - (checkerwidth / 2)) < 1)) {
+
+ hue = fmod(fabs(h-hoffs), 1.0);
+ hsv_to_rgb(hue, s, v, &r, &g, &b);
+
+ rect[0]= (char)(r * 255.0);
+ rect[1]= (char)(g * 255.0);
+ rect[2]= (char)(b * 255.0);
+ rect[3]= 255;
+ }
+ }
+
+ }
+ }
+ } else { /* blank image */
+ for(y=0; y<ibuf->y; y++) {
+ for(x=0; x<ibuf->x; x++, rect+=4) {
+ rect[0]= (char)(color[0] * 255.0);
+ rect[1]= (char)(color[1] * 255.0);
+ rect[2]= (char)(color[2] * 255.0);
+ rect[3]= (char)(color[3] * 255.0);
+ }
+ }
+ }
+ return ibuf;
+}
+
+/* adds new image block, creates ImBuf and initializes color */
+Image *BKE_add_image_size(int width, int height, char *name, short uvtestgrid, float color[4])
+{
+ Image *ima;
+
+ /* on save, type is changed to FILE in editsima.c */
+ ima= image_alloc(name, IMA_SRC_GENERATED, IMA_TYPE_UV_TEST);
+
+ if (ima) {
+ ImBuf *ibuf;
+
+ BLI_strncpy(ima->name, name, FILE_MAX);
+ ima->gen_x= width;
+ ima->gen_y= height;
+ ima->gen_type= uvtestgrid;
+
+ ibuf= add_ibuf_size(width, height, name, uvtestgrid, color);
+ image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0);
+
+ ima->ok= IMA_OK_LOADED;
+ }
+
+ return ima;
+}
+
+/* packs rect from memory as PNG */
+void BKE_image_memorypack(Image *ima)
+{
+ ImBuf *ibuf= image_get_ibuf(ima, IMA_NO_INDEX, 0);
+
+ if(ibuf==NULL)
+ return;
+ if (ima->packedfile) {
+ freePackedFile(ima->packedfile);
+ ima->packedfile = NULL;
+ }
+
+ ibuf->ftype= PNG;
+ ibuf->depth= 32;
+
+ IMB_saveiff(ibuf, ibuf->name, IB_rect | IB_mem);
+ if(ibuf->encodedbuffer==NULL) {
+ printf("memory save for pack error\n");
+ }
+ else {
+ PackedFile *pf = MEM_callocN(sizeof(*pf), "PackedFile");
+
+ pf->data = ibuf->encodedbuffer;
+ pf->size = ibuf->encodedsize;
+ ima->packedfile= pf;
+ ibuf->encodedbuffer= NULL;
+ ibuf->encodedsize= 0;
+ ibuf->userflags &= ~IB_BITMAPDIRTY;
+
+ if(ima->source==IMA_SRC_GENERATED) {
+ ima->source= IMA_SRC_FILE;
+ ima->type= IMA_TYPE_IMAGE;
+ }
+ }
+}
+
+void tag_image_time(Image *ima)
+{
+ if (ima)
+ ima->lastused = (int)PIL_check_seconds_timer();
+}
+
+void tag_all_images_time()
+{
+ Image *ima;
+ int ctime = (int)PIL_check_seconds_timer();
+
+ ima= G.main->image.first;
+ while(ima) {
+ if(ima->bindcode || ima->repbind || ima->ibufs.first) {
+ ima->lastused = ctime;
+ }
+ }
+}
+
+void free_old_images()
+{
+ Image *ima;
+ static int lasttime = 0;
+ int ctime = (int)PIL_check_seconds_timer();
+
+ /*
+ Run garbage collector once for every collecting period of time
+ if textimeout is 0, that's the option to NOT run the collector
+ */
+ if (U.textimeout == 0 || ctime % U.texcollectrate || ctime == lasttime)
+ return;
+
+ lasttime = ctime;
+
+ ima= G.main->image.first;
+ while(ima) {
+ if((ima->flag & IMA_NOCOLLECT)==0 && ctime - ima->lastused > U.textimeout) {
+ /*
+ If it's in GL memory, deallocate and set time tag to current time
+ This gives textures a "second chance" to be used before dying.
+ */
+ if(ima->bindcode || ima->repbind) {
+ free_realtime_image(ima);
+ ima->lastused = ctime;
+ }
+ /* Otherwise, just kill the buffers */
+ else if (ima->ibufs.first) {
+ image_free_buffers(ima);
+ }
+ }
+ ima = ima->id.next;
+ }
+}
+
+void BKE_image_free_all_textures(void)
+{
+ Tex *tex;
+ Image *ima;
+ unsigned int totsize= 0;
+
+ for(ima= G.main->image.first; ima; ima= ima->id.next)
+ ima->id.flag &= ~LIB_DOIT;
+
+ for(tex= G.main->tex.first; tex; tex= tex->id.next)
+ if(tex->ima)
+ tex->ima->id.flag |= LIB_DOIT;
+
+ for(ima= G.main->image.first; ima; ima= ima->id.next) {
+ if(ima->ibufs.first && (ima->id.flag & LIB_DOIT)) {
+ ImBuf *ibuf;
+ for(ibuf= ima->ibufs.first; ibuf; ibuf= ibuf->next) {
+ if(ibuf->mipmap[0])
+ totsize+= 1.33*ibuf->x*ibuf->y*4;
+ else
+ totsize+= ibuf->x*ibuf->y*4;
+ }
+ image_free_buffers(ima);
+ }
+ }
+ /* printf("freed total %d MB\n", totsize/(1024*1024)); */
+}
+
+/* except_frame is weak, only works for seqs without offset... */
+void BKE_image_free_anim_ibufs(Image *ima, int except_frame)
+{
+ ImBuf *ibuf, *nbuf;
+
+ for(ibuf= ima->ibufs.first; ibuf; ibuf= nbuf) {
+ nbuf= ibuf->next;
+ if(ibuf->userflags & IB_BITMAPDIRTY)
+ continue;
+ if(ibuf->index==IMA_NO_INDEX)
+ continue;
+ if(except_frame!=IMA_INDEX_FRAME(ibuf->index)) {
+ BLI_remlink(&ima->ibufs, ibuf);
+
+ if (ibuf->userdata) {
+ MEM_freeN(ibuf->userdata);
+ ibuf->userdata = NULL;
+ }
+ IMB_freeImBuf(ibuf);
+ }
+ }
+}
+
+void BKE_image_all_free_anim_ibufs(int cfra)
+{
+ Image *ima;
+
+ for(ima= G.main->image.first; ima; ima= ima->id.next)
+ if(ELEM(ima->source, IMA_SRC_SEQUENCE, IMA_SRC_MOVIE))
+ BKE_image_free_anim_ibufs(ima, cfra);
+}
+
+
+/* *********** READ AND WRITE ************** */
+
+int BKE_imtype_to_ftype(int imtype)
+{
+ if(imtype==0)
+ return TGA;
+ else if(imtype== R_IRIS)
+ return IMAGIC;
+ else if (imtype==R_RADHDR)
+ return RADHDR;
+ else if (imtype==R_PNG)
+ return PNG;
+#ifdef WITH_DDS
+ else if (imtype==R_DDS)
+ return DDS;
+#endif
+ else if (imtype==R_BMP)
+ return BMP;
+ else if (imtype==R_TIFF)
+ return TIF;
+ else if (imtype==R_OPENEXR || imtype==R_MULTILAYER)
+ return OPENEXR;
+ else if (imtype==R_CINEON)
+ return CINEON;
+ else if (imtype==R_DPX)
+ return DPX;
+ else if (imtype==R_TARGA)
+ return TGA;
+ else if(imtype==R_RAWTGA)
+ return RAWTGA;
+ else if(imtype==R_HAMX)
+ return AN_hamx;
+ else
+ return JPG|90;
+}
+
+int BKE_ftype_to_imtype(int ftype)
+{
+ if(ftype==0)
+ return TGA;
+ else if(ftype == IMAGIC)
+ return R_IRIS;
+ else if (ftype & RADHDR)
+ return R_RADHDR;
+ else if (ftype & PNG)
+ return R_PNG;
+#ifdef WITH_DDS
+ else if (ftype & DDS)
+ return R_DDS;
+#endif
+ else if (ftype & BMP)
+ return R_BMP;
+ else if (ftype & TIF)
+ return R_TIFF;
+ else if (ftype & OPENEXR)
+ return R_OPENEXR;
+ else if (ftype & CINEON)
+ return R_CINEON;
+ else if (ftype & DPX)
+ return R_DPX;
+ else if (ftype & TGA)
+ return R_TARGA;
+ else if(ftype & RAWTGA)
+ return R_RAWTGA;
+ else if(ftype == AN_hamx)
+ return R_HAMX;
+ else
+ return R_JPEG90;
+}
+
+
+int BKE_imtype_is_movie(int imtype)
+{
+ switch(imtype) {
+ case R_MOVIE:
+ case R_AVIRAW:
+ case R_AVIJPEG:
+ case R_AVICODEC:
+ case R_QUICKTIME:
+ case R_FFMPEG:
+ case R_FRAMESERVER:
+ return 1;
+ }
+ return 0;
+}
+
+void BKE_add_image_extension(char *string, int imtype)
+{
+ char *extension="";
+
+ if(G.scene->r.imtype== R_IRIS) {
+ if(!BLI_testextensie(string, ".rgb"))
+ extension= ".rgb";
+ }
+ else if(imtype==R_IRIZ) {
+ if(!BLI_testextensie(string, ".rgb"))
+ extension= ".rgb";
+ }
+ else if(imtype==R_RADHDR) {
+ if(!BLI_testextensie(string, ".hdr"))
+ extension= ".hdr";
+ }
+ else if(imtype==R_PNG) {
+ if(!BLI_testextensie(string, ".png"))
+ extension= ".png";
+ }
+#ifdef WITH_DDS
+ else if(imtype==R_DDS) {
+ if(!BLI_testextensie(string, ".dds"))
+ extension= ".dds";
+ }
+#endif
+ else if(imtype==R_RAWTGA) {
+ if(!BLI_testextensie(string, ".tga"))
+ extension= ".tga";
+ }
+ else if(ELEM5(imtype, R_MOVIE, R_AVICODEC, R_AVIRAW, R_AVIJPEG, R_JPEG90)) {
+ if(!BLI_testextensie(string, ".jpg"))
+ extension= ".jpg";
+ }
+ else if(imtype==R_BMP) {
+ if(!BLI_testextensie(string, ".bmp"))
+ extension= ".bmp";
+ }
+ else if(G.have_libtiff && (imtype==R_TIFF)) {
+ if(!BLI_testextensie(string, ".tif"))
+ extension= ".tif";
+ }
+#ifdef WITH_OPENEXR
+ else if( ELEM(imtype, R_OPENEXR, R_MULTILAYER)) {
+ if(!BLI_testextensie(string, ".exr"))
+ extension= ".exr";
+ }
+#endif
+ else if(imtype==R_CINEON){
+ if (!BLI_testextensie(string, ".cin"))
+ extension= ".cin";
+ }
+ else if(imtype==R_DPX){
+ if (!BLI_testextensie(string, ".dpx"))
+ extension= ".dpx";
+ }
+ else { /* targa default */
+ if(!BLI_testextensie(string, ".tga"))
+ extension= ".tga";
+ }
+
+ strcat(string, extension);
+}
+
+/* could allow access externally */
+typedef struct StampData {
+ char file[512];
+ char note[512];
+ char date[512];
+ char marker[512];
+ char time[512];
+ char frame[512];
+ char camera[512];
+ char scene[512];
+} StampData;
+
+static void stampdata(StampData *stamp_data, int do_prefix)
+{
+ char text[256];
+
+#ifndef WIN32
+ struct tm *tl;
+ time_t t;
+#else
+ char sdate[9];
+#endif /* WIN32 */
+
+ if (do_prefix) sprintf(stamp_data->file, "File %s", G.sce);
+ else sprintf(stamp_data->file, "%s", G.sce);
+
+ if (G.scene->r.stamp & R_STAMP_NOTE) {
+ if (do_prefix) sprintf(stamp_data->note, "Note %s", G.scene->r.stamp_udata);
+ else sprintf(stamp_data->note, "%s", G.scene->r.stamp_udata);
+ } else {
+ stamp_data->note[0] = '\0';
+ }
+
+ if (G.scene->r.stamp & R_STAMP_DATE) {
+#ifdef WIN32
+ _strdate (sdate);
+ sprintf (text, "%s", sdate);
+#else
+ t = time (NULL);
+ tl = localtime (&t);
+ sprintf (text, "%04d-%02d-%02d", tl->tm_year+1900, tl->tm_mon+1, tl->tm_mday);
+#endif /* WIN32 */
+ if (do_prefix) sprintf(stamp_data->date, "Date %s", text);
+ else sprintf(stamp_data->date, "%s", text);
+ } else {
+ stamp_data->date[0] = '\0';
+ }
+
+ if (G.scene->r.stamp & R_STAMP_MARKER) {
+ TimeMarker *marker = get_frame_marker(CFRA);
+
+ if (marker) strcpy(text, marker->name);
+ else strcpy(text, "<none>");
+
+ if (do_prefix) sprintf(stamp_data->marker, "Marker %s", text);
+ else sprintf(stamp_data->marker, "%s", text);
+ } else {
+ stamp_data->marker[0] = '\0';
+ }
+
+ if (G.scene->r.stamp & R_STAMP_TIME) {
+ int h, m, s, f;
+ h= m= s= f= 0;
+ f = (int)(G.scene->r.cfra % G.scene->r.frs_sec);
+ s = (int)(G.scene->r.cfra / G.scene->r.frs_sec);
+
+ if (s) {
+ m = (int)(s / 60);
+ s %= 60;
+
+ if (m) {
+ h = (int)(m / 60);
+ m %= 60;
+ }
+ }
+
+ if (G.scene->r.frs_sec < 100)
+ sprintf (text, "%02d:%02d:%02d.%02d", h, m, s, f);
+ else
+ sprintf (text, "%02d:%02d:%02d.%03d", h, m, s, f);
+
+ if (do_prefix) sprintf(stamp_data->time, "Time %s", text);
+ else sprintf(stamp_data->time, "%s", text);
+ } else {
+ stamp_data->time[0] = '\0';
+ }
+
+ if (G.scene->r.stamp & R_STAMP_FRAME) {
+ char format[32];
+ if (do_prefix) sprintf(format, "Frame %%0%di\n", 1 + (int) log10(G.scene->r.efra));
+ else sprintf(format, "%%0%di\n", 1 + (int) log10(G.scene->r.efra));
+ sprintf (stamp_data->frame, format, G.scene->r.cfra);
+ } else {
+ stamp_data->frame[0] = '\0';
+ }
+
+ if (G.scene->r.stamp & R_STAMP_CAMERA) {
+ if (do_prefix) sprintf(stamp_data->camera, "Camera %s", ((Camera *) G.scene->camera)->id.name+2);
+ else sprintf(stamp_data->camera, "%s", ((Camera *) G.scene->camera)->id.name+2);
+ } else {
+ stamp_data->camera[0] = '\0';
+ }
+
+ if (G.scene->r.stamp & R_STAMP_SCENE) {
+ if (do_prefix) sprintf(stamp_data->scene, "Scene %s", G.scene->id.name+2);
+ else sprintf(stamp_data->scene, "%s", G.scene->id.name+2);
+ } else {
+ stamp_data->scene[0] = '\0';
+ }
+}
+
+void BKE_stamp_buf(unsigned char *rect, float *rectf, int width, int height)
+{
+ struct StampData stamp_data;
+
+ int x=1,y=1;
+ int font_height;
+ int text_width;
+ int text_pad;
+ struct BMF_Font *font;
+
+ if (!rect && !rectf)
+ return;
+
+ stampdata(&stamp_data, 1);
+
+ switch (G.scene->r.stamp_font_id) {
+ case 1: /* tiny */
+ font = BMF_GetFont(BMF_kHelveticaBold8);
+ break;
+ case 2: /* small */
+ font = BMF_GetFont(BMF_kHelveticaBold10);
+ break;
+ case 3: /* medium */
+ font = BMF_GetFont(BMF_kScreen12);
+ break;
+ case 0: /* large - default */
+ font = BMF_GetFont(BMF_kScreen15);
+ break;
+ case 4: /* huge */
+ font = BMF_GetFont(BMF_kHelveticaBold14);
+ break;
+ default:
+ font = NULL;
+ break;
+ }
+
+ font_height = BMF_GetFontHeight(font);
+ /* All texts get halfspace+1 pixel on each side and 1 pix
+ above and below as padding against their backing rectangles */
+ text_pad = BMF_GetStringWidth(font, " ");
+
+
+ if (stamp_data.file[0]) {
+ /* Top left corner */
+ x = 1; /* Inits for everyone, text position, so 1 for padding, not 0 */
+ y = height - font_height - 1; /* Also inits for everyone, notice padding pixel */
+ text_width = BMF_GetStringWidth(font, stamp_data.file);
+ buf_rectfill_area(rect, rectf, width, height, G.scene->r.bg_stamp, x-1, y-1, x+text_width+text_pad+1, y+font_height+1);
+ BMF_DrawStringBuf(font, stamp_data.file, x+(text_pad/2), y, G.scene->r.fg_stamp, rect, rectf, width, height);
+ y -= font_height+2; /* Top and bottom 1 pix padding each */
+ }
+
+ /* Top left corner, below File */
+ if (stamp_data.note[0]) {
+ text_width = BMF_GetStringWidth(font, stamp_data.note);
+ buf_rectfill_area(rect, rectf, width, height, G.scene->r.bg_stamp, x-1, y-1, x+text_width+text_pad+1, y+font_height+1);
+ BMF_DrawStringBuf(font, stamp_data.note, x+(text_pad/2), y, G.scene->r.fg_stamp, rect, rectf, width, height);
+ y -= font_height+2; /* Top and bottom 1 pix padding each */
+ }
+
+ /* Top left corner, below File (or Note) */
+ if (stamp_data.date[0]) {
+ text_width = BMF_GetStringWidth(font, stamp_data.date);
+ buf_rectfill_area(rect, rectf, width, height, G.scene->r.bg_stamp, x-1, y-1, x+text_width+text_pad+1, y+font_height+1);
+ BMF_DrawStringBuf(font, stamp_data.date, x+(text_pad/2), y, G.scene->r.fg_stamp, rect, rectf, width, height);
+ }
+
+ /* Bottom left corner, leaving space for timing */
+ if (stamp_data.marker[0]) {
+ x = 1;
+ y = font_height+2+1; /* 2 for padding in TIME|FRAME fields below and 1 for padding in this one */
+ text_width = BMF_GetStringWidth(font, stamp_data.marker);
+ buf_rectfill_area(rect, rectf, width, height, G.scene->r.bg_stamp, x-1, y-1, x+text_width+text_pad+1, y+font_height+1);
+ BMF_DrawStringBuf(font, stamp_data.marker, x+(text_pad/2), y, G.scene->r.fg_stamp, rect, rectf, width, height);
+ }
+
+ /* Left bottom corner */
+ if (stamp_data.time[0]) {
+ x = 1;
+ y = 1;
+ text_width = BMF_GetStringWidth(font, stamp_data.time);
+ buf_rectfill_area(rect, rectf, width, height, G.scene->r.bg_stamp, x-1, y-1, x+text_width+text_pad+1, y+font_height+1);
+ BMF_DrawStringBuf(font, stamp_data.time, x+(text_pad/2), y, G.scene->r.fg_stamp, rect, rectf, width, height);
+ x += text_width+text_pad+2; /* Both sides have 1 pix additional padding each */
+ }
+
+ if (stamp_data.frame[0]) {
+ text_width = BMF_GetStringWidth(font, stamp_data.frame);
+ /* Left bottom corner (after SMPTE if exists) */
+ if (!stamp_data.time[0]) x = 1;
+ y = 1;
+ buf_rectfill_area(rect, rectf, width, height, G.scene->r.bg_stamp, x-1, y-1, x+text_width+text_pad+1, y+font_height+1);
+ BMF_DrawStringBuf(font, stamp_data.frame, x+(text_pad/2), y, G.scene->r.fg_stamp, rect, rectf, width, height);
+ }
+
+ if (stamp_data.camera[0]) {
+ text_width = BMF_GetStringWidth(font, stamp_data.camera);
+ /* Center of bottom edge */
+ x = (width/2) - (BMF_GetStringWidth(font, stamp_data.camera)/2);
+ y = 1;
+ buf_rectfill_area(rect, rectf, width, height, G.scene->r.bg_stamp, x-1, y-1, x+text_width+text_pad+1, y+font_height+1);
+ BMF_DrawStringBuf(font, stamp_data.camera, x+(text_pad/2), y, G.scene->r.fg_stamp, rect, rectf, width, height);
+ }
+
+ if (stamp_data.scene[0]) {
+ text_width = BMF_GetStringWidth(font, stamp_data.scene);
+ /* Bottom right corner */
+ x = width - (text_width+1+text_pad);
+ y = 1;
+ buf_rectfill_area(rect, rectf, width, height, G.scene->r.bg_stamp, x-1, y-1, x+text_width+text_pad+1, y+font_height+1);
+ BMF_DrawStringBuf(font, stamp_data.scene, x+(text_pad/2), y, G.scene->r.fg_stamp, rect, rectf, width, height);
+ }
+}
+
+
+void BKE_stamp_info(struct ImBuf *ibuf)
+{
+ struct StampData stamp_data;
+
+ if (!ibuf) return;
+
+ /* fill all the data values, no prefix */
+ stampdata(&stamp_data, 0);
+
+ if (stamp_data.file[0]) IMB_imginfo_change_field (ibuf, "File", stamp_data.file);
+ if (stamp_data.note[0]) IMB_imginfo_change_field (ibuf, "Note", stamp_data.note);
+ if (stamp_data.date[0]) IMB_imginfo_change_field (ibuf, "Date", stamp_data.date);
+ if (stamp_data.marker[0]) IMB_imginfo_change_field (ibuf, "Marker", stamp_data.marker);
+ if (stamp_data.time[0]) IMB_imginfo_change_field (ibuf, "Time", stamp_data.time);
+ if (stamp_data.frame[0]) IMB_imginfo_change_field (ibuf, "Frame", stamp_data.frame);
+ if (stamp_data.camera[0]) IMB_imginfo_change_field (ibuf, "Camera", stamp_data.camera);
+ if (stamp_data.scene[0]) IMB_imginfo_change_field (ibuf, "Scene", stamp_data.scene);
+}
+
+int BKE_write_ibuf(ImBuf *ibuf, char *name, int imtype, int subimtype, int quality)
+{
+ int ok;
+
+ if(imtype==0);
+ else if(imtype== R_IRIS)
+ ibuf->ftype= IMAGIC;
+ else if ((imtype==R_RADHDR)) {
+ ibuf->ftype= RADHDR;
+ }
+ else if ((imtype==R_PNG)) {
+ ibuf->ftype= PNG;
+ }
+#ifdef WITH_DDS
+ else if ((imtype==R_DDS)) {
+ ibuf->ftype= DDS;
+ }
+#endif
+ else if ((imtype==R_BMP)) {
+ ibuf->ftype= BMP;
+ }
+ else if ((G.have_libtiff) && (imtype==R_TIFF)) {
+ ibuf->ftype= TIF;
+ }
+#ifdef WITH_OPENEXR
+ else if (imtype==R_OPENEXR || imtype==R_MULTILAYER) {
+ ibuf->ftype= OPENEXR;
+ if(subimtype & R_OPENEXR_HALF)
+ ibuf->ftype |= OPENEXR_HALF;
+ ibuf->ftype |= (quality & OPENEXR_COMPRESS);
+
+ if(!(subimtype & R_OPENEXR_ZBUF))
+ ibuf->zbuf_float = NULL; /* signal for exr saving */
+
+ }
+#endif
+ else if (imtype==R_CINEON) {
+ ibuf->ftype = CINEON;
+ }
+ else if (imtype==R_DPX) {
+ ibuf->ftype = DPX;
+ }
+ else if (imtype==R_TARGA) {
+ ibuf->ftype= TGA;
+ }
+ else if(imtype==R_RAWTGA) {
+ ibuf->ftype= RAWTGA;
+ }
+ else if(imtype==R_HAMX) {
+ ibuf->ftype= AN_hamx;
+ }
+ else {
+ /* R_JPEG90, R_MOVIE, etc. default we save jpegs */
+ if(quality < 10) quality= 90;
+ ibuf->ftype= JPG|quality;
+ if(ibuf->depth==32) ibuf->depth= 24; /* unsupported feature only confuses other s/w */
+ }
+
+ BLI_make_existing_file(name);
+
+ if(G.scene->r.scemode & R_STAMP_INFO)
+ BKE_stamp_info(ibuf);
+
+ ok = IMB_saveiff(ibuf, name, IB_rect | IB_zbuf | IB_zbuffloat);
+ if (ok == 0) {
+ perror(name);
+ }
+
+ return(ok);
+}
+
+
+void BKE_makepicstring(char *string, char *base, int frame, int imtype)
+{
+ short i, len, digits= 4; /* digits in G.scene? */
+ char num[10];
+
+ if (string==NULL) return;
+
+ BLI_strncpy(string, base, FILE_MAX - 10); /* weak assumption */
+ BLI_convertstringcode(string, G.sce, frame);
+
+ len= strlen(string);
+
+ i= digits - sprintf(num, "%d", frame);
+ for(; i>0; i--){
+ string[len]= '0';
+ len++;
+ }
+ string[len]= 0;
+ strcat(string, num);
+
+ if(G.scene->r.scemode & R_EXTENSION)
+ BKE_add_image_extension(string, imtype);
+
+}
+
+/* used by sequencer too */
+struct anim *openanim(char *name, int flags)
+{
+ struct anim *anim;
+ struct ImBuf *ibuf;
+
+ anim = IMB_open_anim(name, flags);
+ if (anim == NULL) return(0);
+
+ ibuf = IMB_anim_absolute(anim, 0);
+ if (ibuf == NULL) {
+ printf("not an anim; %s\n", name);
+ IMB_free_anim(anim);
+ return(0);
+ }
+ IMB_freeImBuf(ibuf);
+
+ return(anim);
+}
+
+/* ************************* New Image API *************** */
+
+
+/* Notes about Image storage
+- packedfile
+ -> written in .blend
+- filename
+ -> written in .blend
+- movie
+ -> comes from packedfile or filename
+- renderresult
+ -> comes from packedfile or filename
+- listbase
+ -> ibufs from exrhandle
+- flipbook array
+ -> ibufs come from movie, temporary renderresult or sequence
+- ibuf
+ -> comes from packedfile or filename or generated
+
+*/
+
+
+/* forces existance of 1 Image for renderout or nodes, returns Image */
+/* name is only for default, when making new one */
+Image *BKE_image_verify_viewer(int type, const char *name)
+{
+ Image *ima;
+
+ for(ima=G.main->image.first; ima; ima= ima->id.next)
+ if(ima->source==IMA_SRC_VIEWER)
+ if(ima->type==type)
+ break;
+
+ if(ima==NULL)
+ ima= image_alloc(name, IMA_SRC_VIEWER, type);
+
+ /* happens on reload, imagewindow cannot be image user when hidden*/
+ if(ima->id.us==0)
+ id_us_plus(&ima->id);
+
+ return ima;
+}
+
+void BKE_image_assign_ibuf(Image *ima, ImBuf *ibuf)
+{
+ image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0);
+}
+
+void BKE_image_signal(Image *ima, ImageUser *iuser, int signal)
+{
+ if(ima==NULL)
+ return;
+
+ switch(signal) {
+ case IMA_SIGNAL_FREE:
+ image_free_buffers(ima);
+ if(iuser)
+ iuser->ok= 1;
+ break;
+ case IMA_SIGNAL_SRC_CHANGE:
+ if(ima->type==IMA_TYPE_MULTILAYER)
+ image_free_buffers(ima);
+ else if(ima->source==IMA_SRC_GENERATED) {
+ if(ima->gen_x==0 || ima->gen_y==0) {
+ ImBuf *ibuf= image_get_ibuf(ima, IMA_NO_INDEX, 0);
+ if(ibuf) {
+ ima->gen_x= ibuf->x;
+ ima->gen_y= ibuf->y;
+ }
+ }
+ }
+ ima->ok= 1;
+ if(iuser)
+ iuser->ok= 1;
+ break;
+
+ case IMA_SIGNAL_RELOAD:
+ /* try to repack file */
+ if(ima->packedfile) {
+ PackedFile *pf;
+ pf = newPackedFile(ima->name);
+ if (pf) {
+ freePackedFile(ima->packedfile);
+ ima->packedfile = pf;
+ image_free_buffers(ima);
+ } else {
+ printf("ERROR: Image not available. Keeping packed image\n");
+ }
+ }
+ else
+ image_free_buffers(ima);
+
+ if(iuser)
+ iuser->ok= 1;
+
+ break;
+ case IMA_SIGNAL_USER_NEW_IMAGE:
+ if(iuser) {
+ iuser->ok= 1;
+ if(ima->source==IMA_SRC_FILE || ima->source==IMA_SRC_SEQUENCE) {
+ if(ima->type==IMA_TYPE_MULTILAYER) {
+ iuser->multi_index= 0;
+ iuser->layer= iuser->pass= 0;
+ }
+ }
+ }
+ break;
+ }
+}
+
+/* if layer or pass changes, we need an index for the imbufs list */
+/* note it is called for rendered results, but it doesnt use the index! */
+/* and because rendered results use fake layer/passes, don't correct for wrong indices here */
+RenderPass *BKE_image_multilayer_index(RenderResult *rr, ImageUser *iuser)
+{
+ RenderLayer *rl;
+ RenderPass *rpass= NULL;
+
+ if(rr==NULL)
+ return NULL;
+
+ if(iuser) {
+ short index= 0, rl_index= 0, rp_index;
+
+ for(rl= rr->layers.first; rl; rl= rl->next, rl_index++) {
+ rp_index= 0;
+ for(rpass= rl->passes.first; rpass; rpass= rpass->next, index++, rp_index++)
+ if(iuser->layer==rl_index && iuser->pass==rp_index)
+ break;
+ if(rpass)
+ break;
+ }
+
+ if(rpass)
+ iuser->multi_index= index;
+ else
+ iuser->multi_index= 0;
+ }
+ if(rpass==NULL) {
+ rl= rr->layers.first;
+ if(rl)
+ rpass= rl->passes.first;
+ }
+
+ return rpass;
+}
+
+RenderResult *BKE_image_get_renderresult(Image *ima)
+{
+ if(ima->rr)
+ return ima->rr;
+ if(ima->type==IMA_TYPE_R_RESULT)
+ return RE_GetResult(RE_GetRender(G.scene->id.name));
+ return NULL;
+}
+
+/* after imbuf load, openexr type can return with a exrhandle open */
+/* in that case we have to build a render-result */
+static void image_create_multilayer(Image *ima, ImBuf *ibuf, int framenr)
+{
+
+ ima->rr= RE_MultilayerConvert(ibuf->userdata, ibuf->x, ibuf->y);
+
+#ifdef WITH_OPENEXR
+ IMB_exr_close(ibuf->userdata);
+#endif
+
+ ibuf->userdata= NULL;
+ if(ima->rr)
+ ima->rr->framenr= framenr;
+}
+
+/* common stuff to do with images after loading */
+static void image_initialize_after_load(Image *ima, ImBuf *ibuf)
+{
+
+
+ /* preview is NULL when it has never been used as an icon before */
+ if(G.background==0 && ima->preview==NULL)
+ BKE_icon_changed(BKE_icon_getid(&ima->id));
+
+ /* stringcodes also in ibuf, ibuf->name is used to retrieve original (buttons) */
+ BLI_strncpy(ibuf->name, ima->name, FILE_MAX);
+
+ /* fields */
+ if (ima->flag & IMA_FIELDS) {
+ if(ima->flag & IMA_STD_FIELD) de_interlace_st(ibuf);
+ else de_interlace_ng(ibuf);
+ }
+ /* timer */
+ ima->lastused = clock() / CLOCKS_PER_SEC;
+
+ ima->ok= IMA_OK_LOADED;
+
+}
+
+static ImBuf *image_load_sequence_file(Image *ima, ImageUser *iuser, int frame)
+{
+ struct ImBuf *ibuf;
+ unsigned short numlen;
+ char name[FILE_MAX], head[FILE_MAX], tail[FILE_MAX];
+
+ ima->lastframe= frame;
+
+ BLI_stringdec(ima->name, head, tail, &numlen);
+ BLI_stringenc(ima->name, head, tail, numlen, frame);
+ BLI_strncpy(name, ima->name, sizeof(name));
+
+ if(ima->id.lib)
+ BLI_convertstringcode(name, ima->id.lib->filename, frame);
+ else
+ BLI_convertstringcode(name, G.sce, frame);
+
+ /* read ibuf */
+ ibuf = IMB_loadiffname(name, IB_rect|IB_multilayer);
+ if(G.f & G_DEBUG) printf("loaded %s\n", name);
+
+ if (ibuf) {
+#ifdef WITH_OPENEXR
+ /* handle multilayer case, don't assign ibuf. will be handled in BKE_image_get_ibuf */
+ if (ibuf->ftype==OPENEXR && ibuf->userdata) {
+ image_create_multilayer(ima, ibuf, frame);
+ ima->type= IMA_TYPE_MULTILAYER;
+ IMB_freeImBuf(ibuf);
+ ibuf= NULL;
+ }
+ else {
+ image_assign_ibuf(ima, ibuf, 0, frame);
+ image_initialize_after_load(ima, ibuf);
+ }
+#else
+ image_assign_ibuf(ima, ibuf, 0, frame);
+ image_initialize_after_load(ima, ibuf);
+#endif
+ }
+ else
+ ima->ok= 0;
+
+ if(iuser)
+ iuser->ok= ima->ok;
+
+ return ibuf;
+}
+
+static ImBuf *image_load_sequence_multilayer(Image *ima, ImageUser *iuser, int frame)
+{
+ struct ImBuf *ibuf= NULL;
+
+ /* either we load from RenderResult, or we have to load a new one */
+
+ /* check for new RenderResult */
+ if(ima->rr==NULL || frame!=ima->rr->framenr) {
+ /* copy to survive not found multilayer image */
+ RenderResult *oldrr= ima->rr;
+
+ ima->rr= NULL;
+ ibuf = image_load_sequence_file(ima, iuser, frame);
+
+ if(ibuf) { /* actually an error */
+ ima->type= IMA_TYPE_IMAGE;
+ printf("error, multi is normal image\n");
+ }
+ // printf("loaded new result %p\n", ima->rr);
+ /* free result if new one found */
+ if(ima->rr) {
+ // if(oldrr) printf("freed previous result %p\n", oldrr);
+ if(oldrr) RE_FreeRenderResult(oldrr);
+ }
+ else
+ ima->rr= oldrr;
+
+ }
+ if(ima->rr) {
+ RenderPass *rpass= BKE_image_multilayer_index(ima->rr, iuser);
+
+ if(rpass) {
+ // printf("load from pass %s\n", rpass->name);
+ /* since we free render results, we copy the rect */
+ ibuf= IMB_allocImBuf(ima->rr->rectx, ima->rr->recty, 32, 0, 0);
+ ibuf->rect_float= MEM_dupallocN(rpass->rect);
+ ibuf->flags |= IB_rectfloat;
+ ibuf->mall= IB_rectfloat;
+ ibuf->channels= rpass->channels;
+
+ image_assign_ibuf(ima, ibuf, iuser->multi_index, frame);
+ image_initialize_after_load(ima, ibuf);
+
+ }
+ // else printf("pass not found\n");
+ }
+ else
+ ima->ok= 0;
+
+ if(iuser)
+ iuser->ok= ima->ok;
+
+ return ibuf;
+}
+
+
+static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame)
+{
+ struct ImBuf *ibuf= NULL;
+
+ ima->lastframe= frame;
+
+ if(ima->anim==NULL) {
+ char str[FILE_MAX];
+
+ BLI_strncpy(str, ima->name, FILE_MAX);
+ if(ima->id.lib)
+ BLI_convertstringcode(str, ima->id.lib->filename, 0);
+ else
+ BLI_convertstringcode(str, G.sce, 0);
+
+ ima->anim = openanim(str, IB_cmap | IB_rect);
+
+ /* let's initialize this user */
+ if(ima->anim && iuser && iuser->frames==0)
+ iuser->frames= IMB_anim_get_duration(ima->anim);
+ }
+
+ if(ima->anim) {
+ int dur = IMB_anim_get_duration(ima->anim);
+ int fra= frame-1;
+
+ if(fra<0) fra = 0;
+ if(fra>(dur-1)) fra= dur-1;
+ ibuf = IMB_anim_absolute(ima->anim, fra);
+
+ if(ibuf) {
+ image_assign_ibuf(ima, ibuf, 0, frame);
+ image_initialize_after_load(ima, ibuf);
+ }
+ else
+ ima->ok= 0;
+ }
+ else
+ ima->ok= 0;
+
+ if(iuser)
+ iuser->ok= ima->ok;
+
+ return ibuf;
+}
+
+/* cfra used for # code, Image can only have this # for all its users */
+static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra)
+{
+ struct ImBuf *ibuf;
+ char str[FILE_MAX];
+
+ /* always ensure clean ima */
+ image_free_buffers(ima);
+
+ /* is there a PackedFile with this image ? */
+ if (ima->packedfile) {
+ ibuf = IMB_ibImageFromMemory((int *) ima->packedfile->data, ima->packedfile->size, IB_rect|IB_multilayer);
+ }
+ else {
+
+ /* get the right string */
+ BLI_strncpy(str, ima->name, sizeof(str));
+ if(ima->id.lib)
+ BLI_convertstringcode(str, ima->id.lib->filename, cfra);
+ else
+ BLI_convertstringcode(str, G.sce, cfra);
+
+ /* read ibuf */
+ ibuf = IMB_loadiffname(str, IB_rect|IB_multilayer|IB_imginfo);
+ }
+
+ if (ibuf) {
+ /* handle multilayer case, don't assign ibuf. will be handled in BKE_image_get_ibuf */
+ if (ibuf->ftype==OPENEXR && ibuf->userdata) {
+ image_create_multilayer(ima, ibuf, cfra);
+ ima->type= IMA_TYPE_MULTILAYER;
+ IMB_freeImBuf(ibuf);
+ ibuf= NULL;
+ }
+ else {
+ image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0);
+ image_initialize_after_load(ima, ibuf);
+
+ /* check if the image is a font image... */
+ detectBitmapFont(ibuf);
+
+ /* make packed file for autopack */
+ if ((ima->packedfile == NULL) && (G.fileflags & G_AUTOPACK))
+ ima->packedfile = newPackedFile(str);
+ }
+ }
+ else
+ ima->ok= 0;
+
+ if(iuser)
+ iuser->ok= ima->ok;
+
+ return ibuf;
+}
+
+static ImBuf *image_get_ibuf_multilayer(Image *ima, ImageUser *iuser)
+{
+ ImBuf *ibuf= NULL;
+
+ if(ima->rr==NULL) {
+ ibuf = image_load_image_file(ima, iuser, 0);
+ if(ibuf) { /* actually an error */
+ ima->type= IMA_TYPE_IMAGE;
+ return ibuf;
+ }
+ }
+ if(ima->rr) {
+ RenderPass *rpass= BKE_image_multilayer_index(ima->rr, iuser);
+
+ if(rpass) {
+ ibuf= IMB_allocImBuf(ima->rr->rectx, ima->rr->recty, 32, 0, 0);
+
+ image_assign_ibuf(ima, ibuf, iuser?iuser->multi_index:IMA_NO_INDEX, 0);
+ image_initialize_after_load(ima, ibuf);
+
+ ibuf->rect_float= rpass->rect;
+ ibuf->flags |= IB_rectfloat;
+ ibuf->channels= rpass->channels;
+ }
+ }
+
+ if(ibuf==NULL)
+ ima->ok= 0;
+ if(iuser)
+ iuser->ok= ima->ok;
+
+ return ibuf;
+}
+
+
+/* showing RGBA result itself (from compo/sequence) or
+ like exr, using layers etc */
+static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser)
+{
+ RenderResult *rr= RE_GetResult(RE_GetRender(G.scene->id.name));
+
+ if(rr && iuser) {
+ RenderResult rres;
+ float *rectf;
+ unsigned int *rect;
+ int channels= 4, layer= iuser->layer;
+
+ /* this gives active layer, composite or seqence result */
+ RE_GetResultImage(RE_GetRender(G.scene->id.name), &rres);
+ rect= (unsigned int *)rres.rect32;
+ rectf= rres.rectf;
+
+ /* get compo/seq result by default */
+ if(rr->rectf && layer==0);
+ else if(rr->layers.first) {
+ RenderLayer *rl= BLI_findlink(&rr->layers, iuser->layer-(rr->rectf?1:0));
+ if(rl) {
+ /* there's no combined pass, is in renderlayer itself */
+ if(iuser->pass==0) {
+ rectf= rl->rectf;
+ }
+ else {
+ RenderPass *rpass= BLI_findlink(&rl->passes, iuser->pass-1);
+ if(rpass) {
+ channels= rpass->channels;
+ rectf= rpass->rect;
+ }
+ }
+ }
+ }
+
+ if(rectf || rect) {
+ ImBuf *ibuf= image_get_ibuf(ima, IMA_NO_INDEX, 0);
+
+ /* make ibuf if needed, and initialize it */
+ if(ibuf==NULL) {
+ ibuf= IMB_allocImBuf(rr->rectx, rr->recty, 32, 0, 0);
+ image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0);
+ }
+ ibuf->x= rr->rectx;
+ ibuf->y= rr->recty;
+
+ if(ibuf->rect_float!=rectf || rect) /* ensure correct redraw */
+ imb_freerectImBuf(ibuf);
+ if(rect)
+ ibuf->rect= rect;
+
+ ibuf->rect_float= rectf;
+ ibuf->flags |= IB_rectfloat;
+ ibuf->channels= channels;
+
+ ima->ok= IMA_OK_LOADED;
+ return ibuf;
+ }
+ }
+
+ return NULL;
+}
+
+/* Checks optional ImageUser and verifies/creates ImBuf. */
+/* returns ibuf */
+ImBuf *BKE_image_get_ibuf(Image *ima, ImageUser *iuser)
+{
+ ImBuf *ibuf= NULL;
+ float color[] = {0, 0, 0, 1};
+
+ /* quick reject tests */
+ if(ima==NULL)
+ return NULL;
+ if(iuser) {
+ if(iuser->ok==0)
+ return NULL;
+ }
+ else if(ima->ok==0)
+ return NULL;
+
+ BLI_lock_thread(LOCK_IMAGE);
+
+ /* handle image source and types */
+ if(ima->source==IMA_SRC_MOVIE) {
+ /* source is from single file, use flipbook to store ibuf */
+ int frame= iuser?iuser->framenr:ima->lastframe;
+
+ ibuf= image_get_ibuf(ima, 0, frame);
+ if(ibuf==NULL)
+ ibuf= image_load_movie_file(ima, iuser, frame);
+ }
+ else if(ima->source==IMA_SRC_SEQUENCE) {
+
+ if(ima->type==IMA_TYPE_IMAGE) {
+ /* regular files, ibufs in flipbook, allows saving */
+ int frame= iuser?iuser->framenr:ima->lastframe;
+
+ ibuf= image_get_ibuf(ima, 0, frame);
+ if(ibuf==NULL)
+ ibuf= image_load_sequence_file(ima, iuser, frame);
+ else
+ BLI_strncpy(ima->name, ibuf->name, sizeof(ima->name));
+ }
+ /* no else; on load the ima type can change */
+ if(ima->type==IMA_TYPE_MULTILAYER) {
+ /* only 1 layer/pass stored in imbufs, no exrhandle anim storage, no saving */
+ int frame= iuser?iuser->framenr:ima->lastframe;
+ int index= iuser?iuser->multi_index:IMA_NO_INDEX;
+
+ ibuf= image_get_ibuf(ima, index, frame);
+ if(G.rt) printf("seq multi fra %d id %d ibuf %p %s\n", frame, index, ibuf, ima->id.name);
+ if(ibuf==NULL)
+ ibuf= image_load_sequence_multilayer(ima, iuser, frame);
+ else
+ BLI_strncpy(ima->name, ibuf->name, sizeof(ima->name));
+ }
+
+ }
+ else if(ima->source==IMA_SRC_FILE) {
+
+ if(ima->type==IMA_TYPE_IMAGE) {
+ ibuf= image_get_ibuf(ima, IMA_NO_INDEX, 0);
+ if(ibuf==NULL)
+ ibuf= image_load_image_file(ima, iuser, G.scene->r.cfra); /* cfra only for '#', this global is OK */
+ }
+ /* no else; on load the ima type can change */
+ if(ima->type==IMA_TYPE_MULTILAYER) {
+ /* keeps render result, stores ibufs in listbase, allows saving */
+ ibuf= image_get_ibuf(ima, iuser?iuser->multi_index:IMA_NO_INDEX, 0);
+ if(ibuf==NULL)
+ ibuf= image_get_ibuf_multilayer(ima, iuser);
+ }
+
+ }
+ else if(ima->source == IMA_SRC_GENERATED) {
+ /* generated is: ibuf is allocated dynamically */
+ ibuf= image_get_ibuf(ima, IMA_NO_INDEX, 0);
+
+ if(ibuf==NULL) {
+ if(ima->type==IMA_TYPE_VERSE) {
+ /* todo */
+ }
+ else { /* always fall back to IMA_TYPE_UV_TEST */
+ /* UV testgrid or black or solid etc */
+ if(ima->gen_x==0) ima->gen_x= 256;
+ if(ima->gen_y==0) ima->gen_y= 256;
+ ibuf= add_ibuf_size(ima->gen_x, ima->gen_y, ima->name, ima->gen_type, color);
+ image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0);
+ ima->ok= IMA_OK_LOADED;
+ }
+ }
+ }
+ else if(ima->source == IMA_SRC_VIEWER) {
+ if(ima->type==IMA_TYPE_R_RESULT) {
+ /* always verify entirely */
+ ibuf= image_get_render_result(ima, iuser);
+ }
+ else if(ima->type==IMA_TYPE_COMPOSITE) {
+ int frame= iuser?iuser->framenr:0;
+
+ /* Composite Viewer, all handled in compositor */
+ ibuf= image_get_ibuf(ima, 0, frame);
+ if(ibuf==NULL) {
+ /* fake ibuf, will be filled in compositor */
+ ibuf= IMB_allocImBuf(256, 256, 32, IB_rect, 0);
+ image_assign_ibuf(ima, ibuf, 0, frame);
+ }
+ }
+ }
+
+ if(G.rendering==0)
+ tag_image_time(ima);
+
+ BLI_unlock_thread(LOCK_IMAGE);
+
+ return ibuf;
+}
+
+
+void BKE_image_user_calc_imanr(ImageUser *iuser, int cfra, int fieldnr)
+{
+ int imanr, len;
+
+ /* here (+fie_ima/2-1) makes sure that division happens correctly */
+ len= (iuser->fie_ima*iuser->frames)/2;
+
+ if(len==0) {
+ iuser->framenr= 0;
+ }
+ else {
+ cfra= cfra - iuser->sfra+1;
+
+ /* cyclic */
+ if(iuser->cycl) {
+ cfra= ( (cfra) % len );
+ if(cfra < 0) cfra+= len;
+ if(cfra==0) cfra= len;
+ }
+
+ if(cfra<1) cfra= 1;
+ else if(cfra>len) cfra= len;
+
+ /* convert current frame to current field */
+ cfra= 2*(cfra);
+ if(fieldnr) cfra++;
+
+ /* transform to images space */
+ imanr= (cfra+iuser->fie_ima-2)/iuser->fie_ima;
+ if(imanr>iuser->frames) imanr= iuser->frames;
+ imanr+= iuser->offset;
+
+ if(iuser->cycl) {
+ imanr= ( (imanr) % len );
+ while(imanr < 0) imanr+= len;
+ if(imanr==0) imanr= len;
+ }
+
+ /* allows image users to handle redraws */
+ if(iuser->flag & IMA_ANIM_ALWAYS)
+ if(imanr!=iuser->framenr)
+ iuser->flag |= IMA_ANIM_REFRESHED;
+
+ iuser->framenr= imanr;
+ if(iuser->ok==0) iuser->ok= 1;
+ }
+}
+
diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c
new file mode 100644
index 00000000000..107633eda64
--- /dev/null
+++ b/source/blender/blenkernel/intern/ipo.c
@@ -0,0 +1,2432 @@
+/* ipo.c
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_action_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_key_types.h"
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_object_types.h"
+#include "DNA_object_force.h"
+#include "DNA_sequence_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_sound_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_world_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "BKE_bad_level_calls.h"
+#include "BKE_utildefines.h"
+
+#include "BKE_action.h"
+#include "BKE_blender.h"
+#include "BKE_curve.h"
+#include "BKE_constraint.h"
+#include "BKE_global.h"
+#include "BKE_ipo.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BPY_extern.h" /* for BPY_pydriver_eval() */
+
+#define SMALL -1.0e-10
+
+/* This array concept was meant to make sure that defines such as OB_LOC_X
+ don't have to be enumerated, also for backward compatibility, future changes,
+ and to enable it all can be accessed with a for-next loop.
+*/
+
+int co_ar[CO_TOTIPO]= {
+ CO_ENFORCE
+};
+
+int ob_ar[OB_TOTIPO]= {
+ OB_LOC_X, OB_LOC_Y, OB_LOC_Z, OB_DLOC_X, OB_DLOC_Y, OB_DLOC_Z,
+ OB_ROT_X, OB_ROT_Y, OB_ROT_Z, OB_DROT_X, OB_DROT_Y, OB_DROT_Z,
+ OB_SIZE_X, OB_SIZE_Y, OB_SIZE_Z, OB_DSIZE_X, OB_DSIZE_Y, OB_DSIZE_Z,
+ OB_LAY, OB_TIME, OB_COL_R, OB_COL_G, OB_COL_B, OB_COL_A,
+ OB_PD_FSTR, OB_PD_FFALL, OB_PD_SDAMP, OB_PD_RDAMP, OB_PD_PERM
+};
+
+int ac_ar[AC_TOTIPO]= {
+ AC_LOC_X, AC_LOC_Y, AC_LOC_Z,
+ AC_QUAT_W, AC_QUAT_X, AC_QUAT_Y, AC_QUAT_Z,
+ AC_SIZE_X, AC_SIZE_Y, AC_SIZE_Z
+};
+
+int ma_ar[MA_TOTIPO]= {
+ MA_COL_R, MA_COL_G, MA_COL_B,
+ MA_SPEC_R, MA_SPEC_G, MA_SPEC_B,
+ MA_MIR_R, MA_MIR_G, MA_MIR_B,
+ MA_REF, MA_ALPHA, MA_EMIT, MA_AMB,
+ MA_SPEC, MA_HARD, MA_SPTR, MA_IOR,
+ MA_MODE, MA_HASIZE, MA_TRANSLU, MA_RAYM,
+ MA_FRESMIR, MA_FRESMIRI, MA_FRESTRA, MA_FRESTRAI, MA_ADD,
+
+ MA_MAP1+MAP_OFS_X, MA_MAP1+MAP_OFS_Y, MA_MAP1+MAP_OFS_Z,
+ MA_MAP1+MAP_SIZE_X, MA_MAP1+MAP_SIZE_Y, MA_MAP1+MAP_SIZE_Z,
+ MA_MAP1+MAP_R, MA_MAP1+MAP_G, MA_MAP1+MAP_B,
+ MA_MAP1+MAP_DVAR, MA_MAP1+MAP_COLF, MA_MAP1+MAP_NORF, MA_MAP1+MAP_VARF, MA_MAP1+MAP_DISP
+};
+
+int te_ar[TE_TOTIPO] ={
+
+ TE_NSIZE, TE_NDEPTH, TE_NTYPE, TE_TURB,
+
+ TE_VNW1, TE_VNW2, TE_VNW3, TE_VNW4,
+ TE_VNMEXP, TE_VN_COLT, TE_VN_DISTM,
+
+ TE_ISCA, TE_DISTA,
+
+ TE_MG_TYP, TE_MGH, TE_MG_LAC, TE_MG_OCT, TE_MG_OFF, TE_MG_GAIN,
+
+ TE_N_BAS1, TE_N_BAS2,
+
+ TE_COL_R, TE_COL_G, TE_COL_B, TE_BRIGHT, TE_CONTRA
+};
+
+int seq_ar[SEQ_TOTIPO]= {
+ SEQ_FAC1
+};
+
+int cu_ar[CU_TOTIPO]= {
+ CU_SPEED
+};
+
+int wo_ar[WO_TOTIPO]= {
+ WO_HOR_R, WO_HOR_G, WO_HOR_B, WO_ZEN_R, WO_ZEN_G, WO_ZEN_B,
+ WO_EXPOS, WO_MISI, WO_MISTDI, WO_MISTSTA, WO_MISTHI,
+ WO_STAR_R, WO_STAR_G, WO_STAR_B, WO_STARDIST, WO_STARSIZE,
+
+ MA_MAP1+MAP_OFS_X, MA_MAP1+MAP_OFS_Y, MA_MAP1+MAP_OFS_Z,
+ MA_MAP1+MAP_SIZE_X, MA_MAP1+MAP_SIZE_Y, MA_MAP1+MAP_SIZE_Z,
+ MA_MAP1+MAP_R, MA_MAP1+MAP_G, MA_MAP1+MAP_B,
+ MA_MAP1+MAP_DVAR, MA_MAP1+MAP_COLF, MA_MAP1+MAP_NORF, MA_MAP1+MAP_VARF
+};
+
+int la_ar[LA_TOTIPO]= {
+ LA_ENERGY, LA_COL_R, LA_COL_G, LA_COL_B,
+ LA_DIST, LA_SPOTSI, LA_SPOTBL,
+ LA_QUAD1, LA_QUAD2, LA_HALOINT,
+
+ MA_MAP1+MAP_OFS_X, MA_MAP1+MAP_OFS_Y, MA_MAP1+MAP_OFS_Z,
+ MA_MAP1+MAP_SIZE_X, MA_MAP1+MAP_SIZE_Y, MA_MAP1+MAP_SIZE_Z,
+ MA_MAP1+MAP_R, MA_MAP1+MAP_G, MA_MAP1+MAP_B,
+ MA_MAP1+MAP_DVAR, MA_MAP1+MAP_COLF
+};
+
+/* yafray: aperture & focal distance curves added */
+/* qdn: FDIST now available to Blender as well for defocus node */
+int cam_ar[CAM_TOTIPO]= {
+ CAM_LENS, CAM_STA, CAM_END, CAM_YF_APERT, CAM_YF_FDIST, CAM_SHIFT_X, CAM_SHIFT_Y
+};
+
+int snd_ar[SND_TOTIPO]= {
+ SND_VOLUME, SND_PITCH, SND_PANNING, SND_ATTEN
+};
+
+int fluidsim_ar[FLUIDSIM_TOTIPO]= {
+ FLUIDSIM_VISC, FLUIDSIM_TIME,
+ FLUIDSIM_GRAV_X , FLUIDSIM_GRAV_Y , FLUIDSIM_GRAV_Z ,
+ FLUIDSIM_VEL_X , FLUIDSIM_VEL_Y , FLUIDSIM_VEL_Z ,
+ FLUIDSIM_ACTIVE
+};
+
+
+
+float frame_to_float(int cfra) /* see also bsystem_time in object.c */
+{
+ extern float bluroffs; /* bad stuff borrowed from object.c */
+ extern float fieldoffs;
+ float ctime;
+
+ ctime= (float)cfra;
+ ctime+= bluroffs+fieldoffs;
+ ctime*= G.scene->r.framelen;
+
+ return ctime;
+}
+
+/* includes ipo curve itself */
+void free_ipo_curve(IpoCurve *icu)
+{
+ if(icu->bezt) MEM_freeN(icu->bezt);
+ if(icu->bp) MEM_freeN(icu->bp);
+ if(icu->driver) MEM_freeN(icu->driver);
+ MEM_freeN(icu);
+}
+
+/* do not free ipo itself */
+void free_ipo(Ipo *ipo)
+{
+ IpoCurve *icu;
+
+ while( (icu= ipo->curve.first) ) {
+ BLI_remlink(&ipo->curve, icu);
+ free_ipo_curve(icu);
+ }
+}
+
+/* on adding new ipos, or for empty views */
+void ipo_default_v2d_cur(int blocktype, rctf *cur)
+{
+ if(blocktype==ID_CA) {
+ cur->xmin= G.scene->r.sfra;
+ cur->xmax= G.scene->r.efra;
+ cur->ymin= 0.0;
+ cur->ymax= 100.0;
+ }
+ else if ELEM5(blocktype, ID_MA, ID_CU, ID_WO, ID_LA, ID_CO) {
+ cur->xmin= (float)G.scene->r.sfra-0.1;
+ cur->xmax= G.scene->r.efra;
+ cur->ymin= (float)-0.1;
+ cur->ymax= (float)+1.1;
+ }
+ else if(blocktype==ID_TE) {
+ cur->xmin= (float)G.scene->r.sfra-0.1;
+ cur->xmax= G.scene->r.efra;
+ cur->ymin= (float)-0.1;
+ cur->ymax= (float)+1.1;
+ }
+ else if(blocktype==ID_SEQ) {
+ cur->xmin= -5.0;
+ cur->xmax= 105.0;
+ cur->ymin= (float)-0.1;
+ cur->ymax= (float)+1.1;
+ }
+ else if(blocktype==ID_KE) {
+ cur->xmin= (float)G.scene->r.sfra-0.1;
+ cur->xmax= G.scene->r.efra;
+ cur->ymin= (float)-0.1;
+ cur->ymax= (float)+2.1;
+ }
+ else { /* ID_OB and everything else */
+ cur->xmin= G.scene->r.sfra;
+ cur->xmax= G.scene->r.efra;
+ cur->ymin= -5.0;
+ cur->ymax= +5.0;
+ }
+}
+
+
+Ipo *add_ipo(char *name, int idcode)
+{
+ Ipo *ipo;
+
+ ipo= alloc_libblock(&G.main->ipo, ID_IP, name);
+ ipo->blocktype= idcode;
+ ipo_default_v2d_cur(idcode, &ipo->cur);
+
+ return ipo;
+}
+
+Ipo *copy_ipo(Ipo *ipo)
+{
+ Ipo *ipon;
+ IpoCurve *icu;
+
+ if(ipo==NULL) return 0;
+
+ ipon= copy_libblock(ipo);
+
+ duplicatelist(&(ipon->curve), &(ipo->curve));
+
+ for(icu= ipo->curve.first; icu; icu= icu->next) {
+ icu->bezt= MEM_dupallocN(icu->bezt);
+ if(icu->driver) icu->driver= MEM_dupallocN(icu->driver);
+ }
+
+ return ipon;
+}
+
+/* uses id->newid to match pointers with other copied data */
+void ipo_idnew(Ipo *ipo)
+{
+ if(ipo) {
+ IpoCurve *icu;
+
+ for(icu= ipo->curve.first; icu; icu= icu->next) {
+ if(icu->driver) {
+ ID_NEW(icu->driver->ob);
+ }
+ }
+ }
+}
+
+void make_local_obipo(Ipo *ipo)
+{
+ Object *ob;
+ Ipo *ipon;
+ int local=0, lib=0;
+
+ /* - only lib users: do nothing
+ * - only local users: set flag
+ * - mixed: make copy
+ */
+
+ ob= G.main->object.first;
+ while(ob) {
+ if(ob->ipo==ipo) {
+ if(ob->id.lib) lib= 1;
+ else local= 1;
+ }
+ ob= ob->id.next;
+ }
+
+ if(local && lib==0) {
+ ipo->id.lib= 0;
+ ipo->id.flag= LIB_LOCAL;
+ new_id(0, (ID *)ipo, 0);
+ }
+ else if(local && lib) {
+ ipon= copy_ipo(ipo);
+ ipon->id.us= 0;
+
+ ob= G.main->object.first;
+ while(ob) {
+ if(ob->ipo==ipo) {
+
+ if(ob->id.lib==NULL) {
+ ob->ipo= ipon;
+ ipon->id.us++;
+ ipo->id.us--;
+ }
+ }
+ ob= ob->id.next;
+ }
+ }
+}
+
+void make_local_matipo(Ipo *ipo)
+{
+ Material *ma;
+ Ipo *ipon;
+ int local=0, lib=0;
+
+ /* - only lib users: do nothing
+ * - only local users: set flag
+ * - mixed: make copy
+ */
+
+ ma= G.main->mat.first;
+ while(ma) {
+ if(ma->ipo==ipo) {
+ if(ma->id.lib) lib= 1;
+ else local= 1;
+ }
+ ma= ma->id.next;
+ }
+
+ if(local && lib==0) {
+ ipo->id.lib= 0;
+ ipo->id.flag= LIB_LOCAL;
+ new_id(0, (ID *)ipo, 0);
+ }
+ else if(local && lib) {
+ ipon= copy_ipo(ipo);
+ ipon->id.us= 0;
+
+ ma= G.main->mat.first;
+ while(ma) {
+ if(ma->ipo==ipo) {
+
+ if(ma->id.lib==NULL) {
+ ma->ipo= ipon;
+ ipon->id.us++;
+ ipo->id.us--;
+ }
+ }
+ ma= ma->id.next;
+ }
+ }
+}
+
+void make_local_keyipo(Ipo *ipo)
+{
+ Key *key;
+ Ipo *ipon;
+ int local=0, lib=0;
+
+ /* - only lib users: do nothing
+ * - only local users: set flag
+ * - mixed: make copy
+ */
+
+ key= G.main->key.first;
+ while(key) {
+ if(key->ipo==ipo) {
+ if(key->id.lib) lib= 1;
+ else local= 1;
+ }
+ key= key->id.next;
+ }
+
+ if(local && lib==0) {
+ ipo->id.lib= 0;
+ ipo->id.flag= LIB_LOCAL;
+ new_id(0, (ID *)ipo, 0);
+ }
+ else if(local && lib) {
+ ipon= copy_ipo(ipo);
+ ipon->id.us= 0;
+
+ key= G.main->key.first;
+ while(key) {
+ if(key->ipo==ipo) {
+
+ if(key->id.lib==NULL) {
+ key->ipo= ipon;
+ ipon->id.us++;
+ ipo->id.us--;
+ }
+ }
+ key= key->id.next;
+ }
+ }
+}
+
+
+void make_local_ipo(Ipo *ipo)
+{
+
+ if(ipo->id.lib==NULL) return;
+ if(ipo->id.us==1) {
+ ipo->id.lib= 0;
+ ipo->id.flag= LIB_LOCAL;
+ new_id(0, (ID *)ipo, 0);
+ return;
+ }
+
+ if(ipo->blocktype==ID_OB) make_local_obipo(ipo);
+ else if(ipo->blocktype==ID_MA) make_local_matipo(ipo);
+ else if(ipo->blocktype==ID_KE) make_local_keyipo(ipo);
+
+}
+
+IpoCurve *find_ipocurve(Ipo *ipo, int adrcode)
+{
+ if(ipo) {
+ IpoCurve *icu;
+ for(icu= ipo->curve.first; icu; icu= icu->next) {
+ if(icu->adrcode==adrcode) return icu;
+ }
+ }
+ return NULL;
+}
+
+void calchandles_ipocurve(IpoCurve *icu)
+{
+ BezTriple *bezt, *prev, *next;
+ int a;
+
+ a= icu->totvert;
+
+ /* IPO_CONST doesn't have handles */
+ if(a<2 || icu->ipo==IPO_CONST) return;
+
+ bezt= icu->bezt;
+ prev= 0;
+ next= bezt+1;
+
+ while(a--) {
+
+ if(bezt->vec[0][0]>bezt->vec[1][0]) bezt->vec[0][0]= bezt->vec[1][0];
+ if(bezt->vec[2][0]<bezt->vec[1][0]) bezt->vec[2][0]= bezt->vec[1][0];
+
+ if(icu->flag & IPO_AUTO_HORIZ)
+ calchandleNurb(bezt, prev, next, 2); /* 2==special autohandle && keep extrema horizontal */
+ else
+ calchandleNurb(bezt, prev, next, 1); /* 1==special autohandle */
+
+ prev= bezt;
+ if(a==1) {
+ next= 0;
+ }
+ else next++;
+
+ /* for automatic ease in and out */
+ if(bezt->h1==HD_AUTO && bezt->h2==HD_AUTO) {
+ if(a==0 || a==icu->totvert-1) {
+ if(icu->extrap==IPO_HORIZ) {
+ bezt->vec[0][1]= bezt->vec[2][1]= bezt->vec[1][1];
+ }
+ }
+ }
+
+ bezt++;
+ }
+}
+
+void testhandles_ipocurve(IpoCurve *icu)
+{
+ /* use when something has changed with handles.
+ it treats all BezTriples with the following rules:
+ PHASE 1: do types have to be altered?
+ Auto handles: become aligned when selection status is NOT(000 || 111)
+ Vector handles: become 'nothing' when (one half selected AND other not)
+ PHASE 2: recalculate handles
+ */
+ BezTriple *bezt;
+ int flag, a;
+
+ bezt= icu->bezt;
+ if(bezt==NULL) return;
+
+ a= icu->totvert;
+ while(a--) {
+ flag= 0;
+ if(bezt->f1 & 1) flag++;
+ if(bezt->f2 & 1) flag += 2;
+ if(bezt->f3 & 1) flag += 4;
+
+ if( !(flag==0 || flag==7) ) {
+ if(bezt->h1==HD_AUTO) { /* auto */
+ bezt->h1= HD_ALIGN;
+ }
+ if(bezt->h2==HD_AUTO) { /* auto */
+ bezt->h2= HD_ALIGN;
+ }
+
+ if(bezt->h1==HD_VECT) { /* vector */
+ if(flag < 4) bezt->h1= 0;
+ }
+ if(bezt->h2==HD_VECT) { /* vector */
+ if( flag > 3) bezt->h2= 0;
+ }
+ }
+ bezt++;
+ }
+
+ calchandles_ipocurve(icu);
+}
+
+
+void sort_time_ipocurve(IpoCurve *icu)
+{
+ BezTriple *bezt;
+ int a, ok= 1;
+
+ while(ok) {
+ ok= 0;
+
+ if(icu->bezt) {
+ bezt= icu->bezt;
+ a= icu->totvert;
+ while(a--) {
+ if(a>0) {
+ if( bezt->vec[1][0] > (bezt+1)->vec[1][0]) {
+ SWAP(BezTriple, *bezt, *(bezt+1));
+ ok= 1;
+ }
+ }
+ if(bezt->vec[0][0]>bezt->vec[1][0] && bezt->vec[2][0]<bezt->vec[1][0]) {
+ SWAP(float, bezt->vec[0][0], bezt->vec[2][0]);
+ SWAP(float, bezt->vec[0][1], bezt->vec[2][1]);
+ }
+ else {
+ if(bezt->vec[0][0]>bezt->vec[1][0]) bezt->vec[0][0]= bezt->vec[1][0];
+ if(bezt->vec[2][0]<bezt->vec[1][0]) bezt->vec[2][0]= bezt->vec[1][0];
+ }
+ bezt++;
+ }
+ }
+ else {
+
+ }
+ }
+}
+
+int test_time_ipocurve(IpoCurve *icu)
+{
+ BezTriple *bezt;
+ int a;
+
+ if(icu->bezt) {
+ bezt= icu->bezt;
+ a= icu->totvert-1;
+ while(a--) {
+ if( bezt->vec[1][0] > (bezt+1)->vec[1][0]) {
+ return 1;
+ }
+ bezt++;
+ }
+ }
+ else {
+
+ }
+
+ return 0;
+}
+
+void correct_bezpart(float *v1, float *v2, float *v3, float *v4)
+{
+ /* the total length of the handles is not allowed to be more
+ * than the horizontal distance between (v1-v4)
+ * this to prevent curve loops
+ */
+ float h1[2], h2[2], len1, len2, len, fac;
+
+ h1[0]= v1[0]-v2[0];
+ h1[1]= v1[1]-v2[1];
+ h2[0]= v4[0]-v3[0];
+ h2[1]= v4[1]-v3[1];
+
+ len= v4[0]- v1[0];
+ len1= (float)fabs(h1[0]);
+ len2= (float)fabs(h2[0]);
+
+ if(len1+len2==0.0) return;
+ if(len1+len2 > len) {
+ fac= len/(len1+len2);
+
+ v2[0]= (v1[0]-fac*h1[0]);
+ v2[1]= (v1[1]-fac*h1[1]);
+
+ v3[0]= (v4[0]-fac*h2[0]);
+ v3[1]= (v4[1]-fac*h2[1]);
+
+ }
+}
+
+/* *********************** ARITH *********************** */
+
+int findzero(float x, float q0, float q1, float q2, float q3, float *o)
+{
+ double c0, c1, c2, c3, a, b, c, p, q, d, t, phi;
+ int nr= 0;
+
+ c0= q0-x;
+ c1= 3*(q1-q0);
+ c2= 3*(q0-2*q1+q2);
+ c3= q3-q0+3*(q1-q2);
+
+ if(c3!=0.0) {
+ a= c2/c3;
+ b= c1/c3;
+ c= c0/c3;
+ a= a/3;
+
+ p= b/3-a*a;
+ q= (2*a*a*a-a*b+c)/2;
+ d= q*q+p*p*p;
+
+ if(d>0.0) {
+ t= sqrt(d);
+ o[0]= (float)(Sqrt3d(-q+t)+Sqrt3d(-q-t)-a);
+ if(o[0]>= SMALL && o[0]<=1.000001) return 1;
+ else return 0;
+ }
+ else if(d==0.0) {
+ t= Sqrt3d(-q);
+ o[0]= (float)(2*t-a);
+ if(o[0]>=SMALL && o[0]<=1.000001) nr++;
+ o[nr]= (float)(-t-a);
+ if(o[nr]>=SMALL && o[nr]<=1.000001) return nr+1;
+ else return nr;
+ }
+ else {
+ phi= acos(-q/sqrt(-(p*p*p)));
+ t= sqrt(-p);
+ p= cos(phi/3);
+ q= sqrt(3-3*p*p);
+ o[0]= (float)(2*t*p-a);
+ if(o[0]>=SMALL && o[0]<=1.000001) nr++;
+ o[nr]= (float)(-t*(p+q)-a);
+ if(o[nr]>=SMALL && o[nr]<=1.000001) nr++;
+ o[nr]= (float)(-t*(p-q)-a);
+ if(o[nr]>=SMALL && o[nr]<=1.000001) return nr+1;
+ else return nr;
+ }
+ }
+ else {
+ a=c2;
+ b=c1;
+ c=c0;
+
+ if(a!=0.0) {
+ p=b*b-4*a*c;
+ if(p>0) {
+ p= sqrt(p);
+ o[0]= (float)((-b-p)/(2*a));
+ if(o[0]>=SMALL && o[0]<=1.000001) nr++;
+ o[nr]= (float)((-b+p)/(2*a));
+ if(o[nr]>=SMALL && o[nr]<=1.000001) return nr+1;
+ else return nr;
+ }
+ else if(p==0) {
+ o[0]= (float)(-b/(2*a));
+ if(o[0]>=SMALL && o[0]<=1.000001) return 1;
+ else return 0;
+ }
+ }
+ else if(b!=0.0) {
+ o[0]= (float)(-c/b);
+ if(o[0]>=SMALL && o[0]<=1.000001) return 1;
+ else return 0;
+ }
+ else if(c==0.0) {
+ o[0]= 0.0;
+ return 1;
+ }
+ return 0;
+ }
+}
+
+void berekeny(float f1, float f2, float f3, float f4, float *o, int b)
+{
+ float t, c0, c1, c2, c3;
+ int a;
+
+ c0= f1;
+ c1= 3.0f*(f2 - f1);
+ c2= 3.0f*(f1 - 2.0f*f2 + f3);
+ c3= f4 - f1 + 3.0f*(f2-f3);
+
+ for(a=0; a<b; a++) {
+ t= o[a];
+ o[a]= c0+t*c1+t*t*c2+t*t*t*c3;
+ }
+}
+
+void berekenx(float *f, float *o, int b)
+{
+ float t, c0, c1, c2, c3;
+ int a;
+
+ c0= f[0];
+ c1= 3*(f[3]-f[0]);
+ c2= 3*(f[0]-2*f[3]+f[6]);
+ c3= f[9]-f[0]+3*(f[3]-f[6]);
+ for(a=0; a<b; a++) {
+ t= o[a];
+ o[a]= c0+t*c1+t*t*c2+t*t*t*c3;
+ }
+}
+
+#define TFM_WITHOUT_BONE 1
+
+static void posechannel_get_local_transform(bPoseChannel *pchan, float *quat, float *eul, float *size, int flag)
+{
+ float pose_mat[3][3];
+ float diff_mat[3][3], ipar_mat[3][3];
+
+ /* we need the local transform = current transform - (parent transform + bone transform) */
+
+ Mat3CpyMat4(pose_mat, pchan->pose_mat);
+
+ if (pchan->parent) {
+
+ if(flag & TFM_WITHOUT_BONE) {
+ float par_mat[3][3];
+ Mat3CpyMat4(par_mat, pchan->parent->pose_mat);
+ Mat3MulMat3(diff_mat, par_mat, pchan->bone->bone_mat);
+ }
+ else
+ Mat3CpyMat4(diff_mat, pchan->parent->pose_mat);
+
+ Mat3Inv(ipar_mat, diff_mat);
+ }
+ else {
+ if(flag & TFM_WITHOUT_BONE)
+ Mat3Inv(ipar_mat, pchan->bone->bone_mat);
+ else
+ Mat3One(ipar_mat);
+ }
+
+ Mat3MulMat3(diff_mat, ipar_mat, pose_mat);
+
+ if(quat)
+ Mat3ToQuat(diff_mat, quat);
+ if(eul)
+ Mat3ToEul(diff_mat, eul);
+ if(size)
+ Mat3ToSize(diff_mat, size);
+}
+
+/* has to return a float value */
+static float eval_driver(IpoDriver *driver, float ipotime)
+{
+
+ if(driver->type == IPO_DRIVER_TYPE_PYTHON) {
+ /* check for empty or invalid expression */
+ if ((driver->name[0] == '\0') ||
+ (driver->flag & IPO_DRIVER_FLAG_INVALID))
+ return 0.0f;
+ /* this evals the expression and returns its result:
+ * (on errors it reports, then returns 0.0f) */
+ return BPY_pydriver_eval(driver);
+ }
+ else {
+ Object *ob= driver->ob;
+
+ if(ob==NULL) return 0.0f;
+ if(ob->proxy_from)
+ ob= ob->proxy_from;
+
+ if(driver->blocktype==ID_OB) {
+ /* depsgraph failure; ob ipos are calculated in where_is_object, this might get called too late */
+ if(ob->ipo && ob->ctime!=ipotime) {
+ calc_ipo_spec(ob->ipo, driver->adrcode, &ipotime);
+ return ipotime;
+ }
+
+ switch(driver->adrcode) {
+ case OB_LOC_X:
+ return ob->loc[0];
+ case OB_LOC_Y:
+ return ob->loc[1];
+ case OB_LOC_Z:
+ return ob->loc[2];
+ case OB_ROT_X:
+ return ob->rot[0]/(M_PI_2/9.0);
+ case OB_ROT_Y:
+ return ob->rot[1]/(M_PI_2/9.0);
+ case OB_ROT_Z:
+ return ob->rot[2]/(M_PI_2/9.0);
+ case OB_SIZE_X:
+ return ob->size[0];
+ case OB_SIZE_Y:
+ return ob->size[1];
+ case OB_SIZE_Z:
+ return ob->size[2];
+ }
+ }
+ else { /* ID_AR */
+ bPoseChannel *pchan= get_pose_channel(ob->pose, driver->name);
+ if(pchan && pchan->bone) {
+
+ /* rotation difference is not a simple driver (i.e. value drives value), but the angle between 2 bones is driving stuff... which is useful */
+ if(driver->adrcode==OB_ROT_DIFF) {
+ bPoseChannel *pchan2= get_pose_channel(ob->pose, driver->name+DRIVER_NAME_OFFS);
+ if(pchan2 && pchan2->bone) {
+ float q1[4], q2[4], quat[4], angle;
+
+ Mat4ToQuat(pchan->pose_mat, q1);
+ Mat4ToQuat(pchan2->pose_mat, q2);
+ // posechannel_get_local_transform(pchan , q1, NULL, NULL, 0);
+ // posechannel_get_local_transform(pchan2, q2, NULL, NULL, 0);
+
+ QuatInv(q1);
+ QuatMul(quat, q1, q2);
+ angle = 2.0f * (saacos(quat[0]));
+ angle= ABS(angle);
+
+ return angle>M_PI?2.0f*M_PI-angle:angle;
+ }
+ }
+ else {
+ float eul[3], size[3];
+
+ posechannel_get_local_transform(pchan, NULL, eul, size, TFM_WITHOUT_BONE);
+
+ switch(driver->adrcode) {
+ case OB_LOC_X:
+ return pchan->loc[0];
+ case OB_LOC_Y:
+ return pchan->loc[1];
+ case OB_LOC_Z:
+ return pchan->loc[2];
+ case OB_ROT_X:
+ return eul[0]/(M_PI_2/9.0);
+ case OB_ROT_Y:
+ return eul[1]/(M_PI_2/9.0);
+ case OB_ROT_Z:
+ return eul[2]/(M_PI_2/9.0);
+ case OB_SIZE_X:
+ return size[0];
+ case OB_SIZE_Y:
+ return size[1];
+ case OB_SIZE_Z:
+ return size[2];
+ }
+ }
+ }
+ }
+ }
+ return 0.0f;
+}
+
+float eval_icu(IpoCurve *icu, float ipotime)
+{
+ BezTriple *bezt, *prevbezt;
+ float v1[2], v2[2], v3[2], v4[2], opl[32], dx, fac;
+ float cycdx, cycdy, ofs, cycyofs, cvalue = 0.0;
+ int a, b;
+
+ cycyofs= 0.0;
+
+ if(icu->driver) {
+ /* ipotime now serves as input for the curve */
+ ipotime= cvalue= eval_driver(icu->driver, ipotime);
+ }
+ if(icu->bezt) {
+ prevbezt= icu->bezt;
+ bezt= prevbezt+1;
+ a= icu->totvert-1;
+
+ /* cyclic? */
+ if(icu->extrap & IPO_CYCL) {
+ ofs= icu->bezt->vec[1][0];
+ cycdx= (icu->bezt+icu->totvert-1)->vec[1][0] - ofs;
+ cycdy= (icu->bezt+icu->totvert-1)->vec[1][1] - icu->bezt->vec[1][1];
+ if(cycdx!=0.0) {
+
+ if(icu->extrap & IPO_DIR) {
+ cycyofs= (float)floor((ipotime-ofs)/cycdx);
+ cycyofs*= cycdy;
+ }
+
+ ipotime= (float)(fmod(ipotime-ofs, cycdx)+ofs);
+ if(ipotime<ofs) ipotime+= cycdx;
+ }
+ }
+
+ /* endpoints? */
+
+ if(prevbezt->vec[1][0]>=ipotime) {
+ if( (icu->extrap & IPO_DIR) && icu->ipo!=IPO_CONST) {
+ dx= prevbezt->vec[1][0]-ipotime;
+ fac= prevbezt->vec[1][0]-prevbezt->vec[0][0];
+ if(fac!=0.0) {
+ fac= (prevbezt->vec[1][1]-prevbezt->vec[0][1])/fac;
+ cvalue= prevbezt->vec[1][1]-fac*dx;
+ }
+ else cvalue= prevbezt->vec[1][1];
+ }
+ else cvalue= prevbezt->vec[1][1];
+
+ cvalue+= cycyofs;
+ }
+ else if( (prevbezt+a)->vec[1][0]<=ipotime) {
+ if( (icu->extrap & IPO_DIR) && icu->ipo!=IPO_CONST) {
+ prevbezt+= a;
+ dx= ipotime-prevbezt->vec[1][0];
+ fac= prevbezt->vec[2][0]-prevbezt->vec[1][0];
+
+ if(fac!=0) {
+ fac= (prevbezt->vec[2][1]-prevbezt->vec[1][1])/fac;
+ cvalue= prevbezt->vec[1][1]+fac*dx;
+ }
+ else cvalue= prevbezt->vec[1][1];
+ }
+ else cvalue= (prevbezt+a)->vec[1][1];
+
+ cvalue+= cycyofs;
+ }
+ else {
+ while(a--) {
+ if(prevbezt->vec[1][0]<=ipotime && bezt->vec[1][0]>=ipotime) {
+ if(icu->ipo==IPO_CONST) {
+ cvalue= prevbezt->vec[1][1]+cycyofs;
+ }
+ else if(icu->ipo==IPO_LIN) {
+ fac= bezt->vec[1][0]-prevbezt->vec[1][0];
+ if(fac==0) cvalue= cycyofs+prevbezt->vec[1][1];
+ else {
+ fac= (ipotime-prevbezt->vec[1][0])/fac;
+ cvalue= cycyofs+prevbezt->vec[1][1]+ fac*(bezt->vec[1][1]-prevbezt->vec[1][1]);
+ }
+ }
+ else {
+ v1[0]= prevbezt->vec[1][0];
+ v1[1]= prevbezt->vec[1][1];
+ v2[0]= prevbezt->vec[2][0];
+ v2[1]= prevbezt->vec[2][1];
+
+ v3[0]= bezt->vec[0][0];
+ v3[1]= bezt->vec[0][1];
+ v4[0]= bezt->vec[1][0];
+ v4[1]= bezt->vec[1][1];
+
+ correct_bezpart(v1, v2, v3, v4);
+
+ b= findzero(ipotime, v1[0], v2[0], v3[0], v4[0], opl);
+ if(b) {
+ berekeny(v1[1], v2[1], v3[1], v4[1], opl, 1);
+ cvalue= opl[0]+cycyofs;
+ break;
+ }
+ }
+ }
+ prevbezt= bezt;
+ bezt++;
+ }
+ }
+ }
+
+ if(icu->ymin < icu->ymax) {
+ if(cvalue < icu->ymin) cvalue= icu->ymin;
+ else if(cvalue > icu->ymax) cvalue= icu->ymax;
+ }
+
+ return cvalue;
+}
+
+void calc_icu(IpoCurve *icu, float ctime)
+{
+ icu->curval= eval_icu(icu, ctime);
+}
+
+float calc_ipo_time(Ipo *ipo, float ctime)
+{
+
+ if(ipo && ipo->blocktype==ID_OB) {
+ IpoCurve *icu= ipo->curve.first;
+
+ while(icu) {
+ if (icu->adrcode==OB_TIME) {
+ calc_icu(icu, ctime);
+ return 10.0f*icu->curval;
+ }
+ icu= icu->next;
+ }
+ }
+
+ return ctime;
+}
+
+void calc_ipo(Ipo *ipo, float ctime)
+{
+ IpoCurve *icu;
+
+ if(ipo==NULL) return;
+ if(ipo->muteipo) return;
+
+ for(icu= ipo->curve.first; icu; icu= icu->next) {
+ if(icu->driver || (icu->flag & IPO_LOCK)==0) {
+ if((icu->flag & IPO_MUTE)==0)
+ calc_icu(icu, ctime);
+ }
+ }
+}
+
+/* ************************************** */
+/* DO THE IPO! */
+/* ************************************** */
+
+void write_ipo_poin(void *poin, int type, float val)
+{
+
+ switch(type) {
+ case IPO_FLOAT:
+ *( (float *)poin)= val;
+ break;
+ case IPO_FLOAT_DEGR:
+ *( (float *)poin)= (float)(val*M_PI_2/9.0);
+ break;
+ case IPO_INT:
+ case IPO_INT_BIT:
+ case IPO_LONG:
+ *( (int *)poin)= (int)val;
+ break;
+ case IPO_SHORT:
+ case IPO_SHORT_BIT:
+ *( (short *)poin)= (short)val;
+ break;
+ case IPO_CHAR:
+ case IPO_CHAR_BIT:
+ *( (char *)poin)= (char)val;
+ break;
+ }
+}
+
+float read_ipo_poin(void *poin, int type)
+{
+ float val = 0.0;
+
+ switch(type) {
+ case IPO_FLOAT:
+ val= *( (float *)poin);
+ break;
+ case IPO_FLOAT_DEGR:
+ val= *( (float *)poin);
+ val = (float)(val/(M_PI_2/9.0));
+ break;
+ case IPO_INT:
+ case IPO_INT_BIT:
+ case IPO_LONG:
+ val= (float)(*( (int *)poin));
+ break;
+ case IPO_SHORT:
+ case IPO_SHORT_BIT:
+ val= *( (short *)poin);
+ break;
+ case IPO_CHAR:
+ case IPO_CHAR_BIT:
+ val= *( (char *)poin);
+ break;
+ }
+ return val;
+}
+
+static void *give_tex_poin(Tex *tex, int adrcode, int *type )
+{
+ void *poin=0;
+
+ switch(adrcode) {
+ case TE_NSIZE:
+ poin= &(tex->noisesize); break;
+ case TE_TURB:
+ poin= &(tex->turbul); break;
+ case TE_NDEPTH:
+ poin= &(tex->noisedepth); *type= IPO_SHORT; break;
+ case TE_NTYPE:
+ poin= &(tex->noisetype); *type= IPO_SHORT; break;
+ case TE_VNW1:
+ poin= &(tex->vn_w1); break;
+ case TE_VNW2:
+ poin= &(tex->vn_w2); break;
+ case TE_VNW3:
+ poin= &(tex->vn_w3); break;
+ case TE_VNW4:
+ poin= &(tex->vn_w4); break;
+ case TE_VNMEXP:
+ poin= &(tex->vn_mexp); break;
+ case TE_ISCA:
+ poin= &(tex->ns_outscale); break;
+ case TE_DISTA:
+ poin= &(tex->dist_amount); break;
+ case TE_VN_COLT:
+ poin= &(tex->vn_coltype); *type= IPO_SHORT; break;
+ case TE_VN_DISTM:
+ poin= &(tex->vn_distm); *type= IPO_SHORT; break;
+ case TE_MG_TYP:
+ poin= &(tex->stype); *type= IPO_SHORT; break;
+ case TE_MGH:
+ poin= &(tex->mg_H); break;
+ case TE_MG_LAC:
+ poin= &(tex->mg_lacunarity); break;
+ case TE_MG_OCT:
+ poin= &(tex->mg_octaves); break;
+ case TE_MG_OFF:
+ poin= &(tex->mg_offset); break;
+ case TE_MG_GAIN:
+ poin= &(tex->mg_gain); break;
+ case TE_N_BAS1:
+ poin= &(tex->noisebasis); *type= IPO_SHORT; break;
+ case TE_N_BAS2:
+ poin= &(tex->noisebasis2); *type= IPO_SHORT; break;
+ case TE_COL_R:
+ poin= &(tex->rfac); break;
+ case TE_COL_G:
+ poin= &(tex->gfac); break;
+ case TE_COL_B:
+ poin= &(tex->bfac); break;
+ case TE_BRIGHT:
+ poin= &(tex->bright); break;
+ case TE_CONTRA:
+ poin= &(tex->contrast); break;
+
+ }
+
+ return poin;
+}
+
+void *give_mtex_poin(MTex *mtex, int adrcode )
+{
+ void *poin=0;
+
+ switch(adrcode) {
+ case MAP_OFS_X:
+ poin= &(mtex->ofs[0]); break;
+ case MAP_OFS_Y:
+ poin= &(mtex->ofs[1]); break;
+ case MAP_OFS_Z:
+ poin= &(mtex->ofs[2]); break;
+ case MAP_SIZE_X:
+ poin= &(mtex->size[0]); break;
+ case MAP_SIZE_Y:
+ poin= &(mtex->size[1]); break;
+ case MAP_SIZE_Z:
+ poin= &(mtex->size[2]); break;
+ case MAP_R:
+ poin= &(mtex->r); break;
+ case MAP_G:
+ poin= &(mtex->g); break;
+ case MAP_B:
+ poin= &(mtex->b); break;
+ case MAP_DVAR:
+ poin= &(mtex->def_var); break;
+ case MAP_COLF:
+ poin= &(mtex->colfac); break;
+ case MAP_NORF:
+ poin= &(mtex->norfac); break;
+ case MAP_VARF:
+ poin= &(mtex->varfac); break;
+ case MAP_DISP:
+ poin= &(mtex->dispfac); break;
+ }
+
+ return poin;
+}
+
+/* GS reads the memory pointed at in a specific ordering. There are,
+ * however two definitions for it. I have jotted them down here, both,
+ * but I think the first one is actually used. The thing is that
+ * big-endian systems might read this the wrong way round. OTOH, we
+ * constructed the IDs that are read out with this macro explicitly as
+ * well. I expect we'll sort it out soon... */
+
+/* from blendef: */
+#define GS(a) (*((short *)(a)))
+
+/* from misc_util: flip the bytes from x */
+/* #define GS(x) (((unsigned char *)(x))[0] << 8 | ((unsigned char *)(x))[1]) */
+
+void *get_ipo_poin(ID *id, IpoCurve *icu, int *type)
+{
+ void *poin= NULL;
+ Object *ob;
+ Material *ma;
+ MTex *mtex;
+ Tex *tex;
+ Lamp *la;
+ Sequence *seq;
+ World *wo;
+
+ *type= IPO_FLOAT;
+
+ if( GS(id->name)==ID_OB) {
+
+ ob= (Object *)id;
+
+ switch(icu->adrcode) {
+ case OB_LOC_X:
+ poin= &(ob->loc[0]); break;
+ case OB_LOC_Y:
+ poin= &(ob->loc[1]); break;
+ case OB_LOC_Z:
+ poin= &(ob->loc[2]); break;
+ case OB_DLOC_X:
+ poin= &(ob->dloc[0]); break;
+ case OB_DLOC_Y:
+ poin= &(ob->dloc[1]); break;
+ case OB_DLOC_Z:
+ poin= &(ob->dloc[2]); break;
+
+ case OB_ROT_X:
+ poin= &(ob->rot[0]); *type= IPO_FLOAT_DEGR; break;
+ case OB_ROT_Y:
+ poin= &(ob->rot[1]); *type= IPO_FLOAT_DEGR; break;
+ case OB_ROT_Z:
+ poin= &(ob->rot[2]); *type= IPO_FLOAT_DEGR; break;
+ case OB_DROT_X:
+ poin= &(ob->drot[0]); *type= IPO_FLOAT_DEGR; break;
+ case OB_DROT_Y:
+ poin= &(ob->drot[1]); *type= IPO_FLOAT_DEGR; break;
+ case OB_DROT_Z:
+ poin= &(ob->drot[2]); *type= IPO_FLOAT_DEGR; break;
+
+ case OB_SIZE_X:
+ poin= &(ob->size[0]); break;
+ case OB_SIZE_Y:
+ poin= &(ob->size[1]); break;
+ case OB_SIZE_Z:
+ poin= &(ob->size[2]); break;
+ case OB_DSIZE_X:
+ poin= &(ob->dsize[0]); break;
+ case OB_DSIZE_Y:
+ poin= &(ob->dsize[1]); break;
+ case OB_DSIZE_Z:
+ poin= &(ob->dsize[2]); break;
+
+ case OB_LAY:
+ poin= &(ob->lay); *type= IPO_INT_BIT; break;
+
+ case OB_COL_R:
+ poin= &(ob->col[0]);
+ break;
+ case OB_COL_G:
+ poin= &(ob->col[1]);
+ break;
+ case OB_COL_B:
+ poin= &(ob->col[2]);
+ break;
+ case OB_COL_A:
+ poin= &(ob->col[3]);
+ break;
+ case OB_PD_FSTR:
+ if(ob->pd) poin= &(ob->pd->f_strength);
+ break;
+ case OB_PD_FFALL:
+ if(ob->pd) poin= &(ob->pd->f_power);
+ break;
+ case OB_PD_SDAMP:
+ if(ob->pd) poin= &(ob->pd->pdef_damp);
+ break;
+ case OB_PD_RDAMP:
+ if(ob->pd) poin= &(ob->pd->pdef_rdamp);
+ break;
+ case OB_PD_PERM:
+ if(ob->pd) poin= &(ob->pd->pdef_perm);
+ break;
+ }
+ }
+ else if( GS(id->name)==ID_MA) {
+
+ ma= (Material *)id;
+
+ switch(icu->adrcode) {
+ case MA_COL_R:
+ poin= &(ma->r); break;
+ case MA_COL_G:
+ poin= &(ma->g); break;
+ case MA_COL_B:
+ poin= &(ma->b); break;
+ case MA_SPEC_R:
+ poin= &(ma->specr); break;
+ case MA_SPEC_G:
+ poin= &(ma->specg); break;
+ case MA_SPEC_B:
+ poin= &(ma->specb); break;
+ case MA_MIR_R:
+ poin= &(ma->mirr); break;
+ case MA_MIR_G:
+ poin= &(ma->mirg); break;
+ case MA_MIR_B:
+ poin= &(ma->mirb); break;
+ case MA_REF:
+ poin= &(ma->ref); break;
+ case MA_ALPHA:
+ poin= &(ma->alpha); break;
+ case MA_EMIT:
+ poin= &(ma->emit); break;
+ case MA_AMB:
+ poin= &(ma->amb); break;
+ case MA_SPEC:
+ poin= &(ma->spec); break;
+ case MA_HARD:
+ poin= &(ma->har); *type= IPO_SHORT; break;
+ case MA_SPTR:
+ poin= &(ma->spectra); break;
+ case MA_IOR:
+ poin= &(ma->ang); break;
+ case MA_MODE:
+ poin= &(ma->mode); *type= IPO_INT_BIT; break;
+ case MA_HASIZE:
+ poin= &(ma->hasize); break;
+ case MA_TRANSLU:
+ poin= &(ma->translucency); break;
+ case MA_RAYM:
+ poin= &(ma->ray_mirror); break;
+ case MA_FRESMIR:
+ poin= &(ma->fresnel_mir); break;
+ case MA_FRESMIRI:
+ poin= &(ma->fresnel_mir_i); break;
+ case MA_FRESTRA:
+ poin= &(ma->fresnel_tra); break;
+ case MA_FRESTRAI:
+ poin= &(ma->fresnel_tra_i); break;
+ case MA_ADD:
+ poin= &(ma->add); break;
+ }
+
+ if(poin==NULL) {
+ mtex= 0;
+ if(icu->adrcode & MA_MAP1) mtex= ma->mtex[0];
+ else if(icu->adrcode & MA_MAP2) mtex= ma->mtex[1];
+ else if(icu->adrcode & MA_MAP3) mtex= ma->mtex[2];
+ else if(icu->adrcode & MA_MAP4) mtex= ma->mtex[3];
+ else if(icu->adrcode & MA_MAP5) mtex= ma->mtex[4];
+ else if(icu->adrcode & MA_MAP6) mtex= ma->mtex[5];
+ else if(icu->adrcode & MA_MAP7) mtex= ma->mtex[6];
+ else if(icu->adrcode & MA_MAP8) mtex= ma->mtex[7];
+ else if(icu->adrcode & MA_MAP9) mtex= ma->mtex[8];
+ else if(icu->adrcode & MA_MAP10) mtex= ma->mtex[9];
+
+ if(mtex) {
+ poin= give_mtex_poin(mtex, icu->adrcode & (MA_MAP1-1) );
+ }
+ }
+ }
+ else if( GS(id->name)==ID_TE) {
+ tex= (Tex *)id;
+
+ if(tex) poin= give_tex_poin(tex, icu->adrcode, type);
+ }
+ else if( GS(id->name)==ID_SEQ) {
+ seq= (Sequence *)id;
+
+ switch(icu->adrcode) {
+ case SEQ_FAC1:
+ poin= &(seq->facf0); break;
+ }
+ }
+ else if( GS(id->name)==ID_CU) {
+
+ poin= &(icu->curval);
+
+ }
+ else if( GS(id->name)==ID_KE) {
+ KeyBlock *kb= ((Key *)id)->block.first;
+
+ for(; kb; kb= kb->next)
+ if(kb->adrcode==icu->adrcode)
+ break;
+ if(kb)
+ poin= &(kb->curval);
+
+ }
+ else if(GS(id->name)==ID_WO) {
+
+ wo= (World *)id;
+
+ switch(icu->adrcode) {
+ case WO_HOR_R:
+ poin= &(wo->horr); break;
+ case WO_HOR_G:
+ poin= &(wo->horg); break;
+ case WO_HOR_B:
+ poin= &(wo->horb); break;
+ case WO_ZEN_R:
+ poin= &(wo->zenr); break;
+ case WO_ZEN_G:
+ poin= &(wo->zeng); break;
+ case WO_ZEN_B:
+ poin= &(wo->zenb); break;
+
+ case WO_EXPOS:
+ poin= &(wo->exposure); break;
+
+ case WO_MISI:
+ poin= &(wo->misi); break;
+ case WO_MISTDI:
+ poin= &(wo->mistdist); break;
+ case WO_MISTSTA:
+ poin= &(wo->miststa); break;
+ case WO_MISTHI:
+ poin= &(wo->misthi); break;
+
+ case WO_STAR_R:
+ poin= &(wo->starr); break;
+ case WO_STAR_G:
+ poin= &(wo->starg); break;
+ case WO_STAR_B:
+ poin= &(wo->starb); break;
+
+ case WO_STARDIST:
+ poin= &(wo->stardist); break;
+ case WO_STARSIZE:
+ poin= &(wo->starsize); break;
+ }
+
+ if(poin==NULL) {
+ mtex= 0;
+ if(icu->adrcode & MA_MAP1) mtex= wo->mtex[0];
+ else if(icu->adrcode & MA_MAP2) mtex= wo->mtex[1];
+ else if(icu->adrcode & MA_MAP3) mtex= wo->mtex[2];
+ else if(icu->adrcode & MA_MAP4) mtex= wo->mtex[3];
+ else if(icu->adrcode & MA_MAP5) mtex= wo->mtex[4];
+ else if(icu->adrcode & MA_MAP6) mtex= wo->mtex[5];
+ else if(icu->adrcode & MA_MAP7) mtex= wo->mtex[6];
+ else if(icu->adrcode & MA_MAP8) mtex= wo->mtex[7];
+ else if(icu->adrcode & MA_MAP9) mtex= wo->mtex[8];
+ else if(icu->adrcode & MA_MAP10) mtex= wo->mtex[9];
+
+ if(mtex) {
+ poin= give_mtex_poin(mtex, icu->adrcode & (MA_MAP1-1) );
+ }
+ }
+ }
+ else if( GS(id->name)==ID_LA) {
+
+ la= (Lamp *)id;
+
+ switch(icu->adrcode) {
+ case LA_ENERGY:
+ poin= &(la->energy); break;
+ case LA_COL_R:
+ poin= &(la->r); break;
+ case LA_COL_G:
+ poin= &(la->g); break;
+ case LA_COL_B:
+ poin= &(la->b); break;
+ case LA_DIST:
+ poin= &(la->dist); break;
+ case LA_SPOTSI:
+ poin= &(la->spotsize); break;
+ case LA_SPOTBL:
+ poin= &(la->spotblend); break;
+ case LA_QUAD1:
+ poin= &(la->att1); break;
+ case LA_QUAD2:
+ poin= &(la->att2); break;
+ case LA_HALOINT:
+ poin= &(la->haint); break;
+ }
+
+ if(poin==NULL) {
+ mtex= 0;
+ if(icu->adrcode & MA_MAP1) mtex= la->mtex[0];
+ else if(icu->adrcode & MA_MAP2) mtex= la->mtex[1];
+ else if(icu->adrcode & MA_MAP3) mtex= la->mtex[2];
+ else if(icu->adrcode & MA_MAP4) mtex= la->mtex[3];
+ else if(icu->adrcode & MA_MAP5) mtex= la->mtex[4];
+ else if(icu->adrcode & MA_MAP6) mtex= la->mtex[5];
+ else if(icu->adrcode & MA_MAP7) mtex= la->mtex[6];
+ else if(icu->adrcode & MA_MAP8) mtex= la->mtex[7];
+ else if(icu->adrcode & MA_MAP9) mtex= la->mtex[8];
+ else if(icu->adrcode & MA_MAP10) mtex= la->mtex[9];
+
+ if(mtex) {
+ poin= give_mtex_poin(mtex, icu->adrcode & (MA_MAP1-1) );
+ }
+ }
+ }
+ else if(GS(id->name)==ID_CA) {
+ Camera *ca= (Camera *)id;
+
+ /* yafray: aperture & focal distance params */
+ switch(icu->adrcode) {
+ case CAM_LENS:
+ if(ca->type==CAM_ORTHO)
+ poin= &(ca->ortho_scale);
+ else
+ poin= &(ca->lens);
+ break;
+ case CAM_STA:
+ poin= &(ca->clipsta); break;
+ case CAM_END:
+ poin= &(ca->clipend); break;
+ case CAM_YF_APERT:
+ poin= &(ca->YF_aperture); break;
+ case CAM_YF_FDIST:
+ poin= &(ca->YF_dofdist); break;
+ case CAM_SHIFT_X:
+ poin= &(ca->shiftx); break;
+ case CAM_SHIFT_Y:
+ poin= &(ca->shifty); break;
+ }
+ }
+ else if(GS(id->name)==ID_SO) {
+ bSound *snd= (bSound *)id;
+
+ switch(icu->adrcode) {
+ case SND_VOLUME:
+ poin= &(snd->volume); break;
+ case SND_PITCH:
+ poin= &(snd->pitch); break;
+ case SND_PANNING:
+ poin= &(snd->panning); break;
+ case SND_ATTEN:
+ poin= &(snd->attenuation); break;
+ }
+ }
+
+ return poin;
+}
+
+void set_icu_vars(IpoCurve *icu)
+{
+ /* defaults. 0.0 for y-extents makes these ignored */
+ icu->ymin= icu->ymax= 0.0;
+ icu->ipo= IPO_BEZ;
+
+ if(icu->blocktype==ID_OB) {
+
+ if(icu->adrcode==OB_LAY) {
+ icu->ipo= IPO_CONST;
+ icu->vartype= IPO_BITS;
+ }
+
+ }
+ else if(icu->blocktype==ID_MA) {
+
+ if(icu->adrcode < MA_MAP1) {
+ switch(icu->adrcode) {
+ case MA_HASIZE:
+ icu->ymax= 10000.0; break;
+ case MA_HARD:
+ icu->ymax= 511.0; break;
+ case MA_SPEC:
+ icu->ymax= 2.0; break;
+ case MA_MODE:
+ icu->ipo= IPO_CONST;
+ icu->vartype= IPO_BITS; break;
+ case MA_RAYM:
+ icu->ymax= 1.0; break;
+ case MA_TRANSLU:
+ icu->ymax= 1.0; break;
+ case MA_IOR:
+ icu->ymin= 1.0;
+ icu->ymax= 3.0; break;
+ case MA_FRESMIR:
+ icu->ymax= 5.0; break;
+ case MA_FRESMIRI:
+ icu->ymin= 1.0;
+ icu->ymax= 5.0; break;
+ case MA_FRESTRA:
+ icu->ymax= 5.0; break;
+ case MA_FRESTRAI:
+ icu->ymin= 1.0;
+ icu->ymax= 5.0; break;
+ case MA_ADD:
+ icu->ymax= 1.0; break;
+ default:
+ icu->ymax= 1.0; break;
+ }
+ }
+ else {
+ switch(icu->adrcode & (MA_MAP1-1)) {
+ case MAP_OFS_X:
+ case MAP_OFS_Y:
+ case MAP_OFS_Z:
+ case MAP_SIZE_X:
+ case MAP_SIZE_Y:
+ case MAP_SIZE_Z:
+ icu->ymax= 1000.0;
+ icu->ymin= -1000.0;
+
+ break;
+ case MAP_R:
+ case MAP_G:
+ case MAP_B:
+ case MAP_DVAR:
+ case MAP_COLF:
+ case MAP_VARF:
+ case MAP_DISP:
+ icu->ymax= 1.0;
+ break;
+ case MAP_NORF:
+ icu->ymax= 25.0;
+ break;
+ }
+ }
+ }
+ else if(icu->blocktype==ID_TE) {
+ switch(icu->adrcode & (MA_MAP1-1)) {
+ case TE_NSIZE:
+ icu->ymin= 0.0001;
+ icu->ymax= 2.0; break;
+ case TE_NDEPTH:
+ icu->vartype= IPO_SHORT;
+ icu->ipo= IPO_CONST;
+ icu->ymax= 6.0; break;
+ case TE_NTYPE:
+ icu->vartype= IPO_SHORT;
+ icu->ipo= IPO_CONST;
+ icu->ymax= 1.0; break;
+ case TE_TURB:
+ icu->ymax= 200.0; break;
+ case TE_VNW1:
+ case TE_VNW2:
+ case TE_VNW3:
+ case TE_VNW4:
+ icu->ymax= 2.0;
+ icu->ymin= -2.0; break;
+ case TE_VNMEXP:
+ icu->ymax= 10.0;
+ icu->ymin= 0.01; break;
+ case TE_VN_DISTM:
+ icu->vartype= IPO_SHORT;
+ icu->ipo= IPO_CONST;
+ icu->ymax= 6.0; break;
+ case TE_VN_COLT:
+ icu->vartype= IPO_SHORT;
+ icu->ipo= IPO_CONST;
+ icu->ymax= 3.0; break;
+ case TE_ISCA:
+ icu->ymax= 10.0;
+ icu->ymin= 0.01; break;
+ case TE_DISTA:
+ icu->ymax= 10.0; break;
+ case TE_MG_TYP:
+ icu->vartype= IPO_SHORT;
+ icu->ipo= IPO_CONST;
+ icu->ymax= 6.0; break;
+ case TE_MGH:
+ icu->ymin= 0.0001;
+ icu->ymax= 2.0; break;
+ case TE_MG_LAC:
+ case TE_MG_OFF:
+ case TE_MG_GAIN:
+ icu->ymax= 6.0; break;
+ case TE_MG_OCT:
+ icu->ymax= 8.0; break;
+ case TE_N_BAS1:
+ case TE_N_BAS2:
+ icu->vartype= IPO_SHORT;
+ icu->ipo= IPO_CONST;
+ icu->ymax= 8.0; break;
+ case TE_COL_R:
+ icu->ymax= 0.0; break;
+ case TE_COL_G:
+ icu->ymax= 2.0; break;
+ case TE_COL_B:
+ icu->ymax= 2.0; break;
+ case TE_BRIGHT:
+ icu->ymax= 2.0; break;
+ case TE_CONTRA:
+ icu->ymax= 5.0; break;
+
+ }
+ }
+ else if(icu->blocktype==ID_SEQ) {
+
+ icu->ymax= 1.0;
+
+ }
+ else if(icu->blocktype==ID_CU) {
+
+ icu->ymax= 1.0;
+
+ }
+ else if(icu->blocktype==ID_WO) {
+
+ if(icu->adrcode < MA_MAP1) {
+ switch(icu->adrcode) {
+ case WO_EXPOS:
+ icu->ymax= 5.0; break;
+ case WO_MISTDI:
+ case WO_MISTSTA:
+ case WO_MISTHI:
+ case WO_STARDIST:
+ case WO_STARSIZE:
+ break;
+
+ default:
+ icu->ymax= 1.0;
+ break;
+ }
+ }
+ else {
+ switch(icu->adrcode & (MA_MAP1-1)) {
+ case MAP_OFS_X:
+ case MAP_OFS_Y:
+ case MAP_OFS_Z:
+ case MAP_SIZE_X:
+ case MAP_SIZE_Y:
+ case MAP_SIZE_Z:
+ icu->ymax= 100.0;
+ icu->ymin= -100.0;
+
+ break;
+ case MAP_R:
+ case MAP_G:
+ case MAP_B:
+ case MAP_DVAR:
+ case MAP_COLF:
+ case MAP_NORF:
+ case MAP_VARF:
+ case MAP_DISP:
+ icu->ymax= 1.0;
+ }
+ }
+ }
+ else if(icu->blocktype==ID_LA) {
+ if(icu->adrcode < MA_MAP1) {
+ switch(icu->adrcode) {
+ case LA_ENERGY:
+ case LA_DIST:
+ break;
+
+ case LA_COL_R:
+ case LA_COL_G:
+ case LA_COL_B:
+ case LA_SPOTBL:
+ case LA_QUAD1:
+ case LA_QUAD2:
+ icu->ymax= 1.0; break;
+ case LA_SPOTSI:
+ icu->ymax= 180.0; break;
+ case LA_HALOINT:
+ icu->ymax= 5.0; break;
+ }
+ }
+ else {
+ switch(icu->adrcode & (MA_MAP1-1)) {
+ case MAP_OFS_X:
+ case MAP_OFS_Y:
+ case MAP_OFS_Z:
+ case MAP_SIZE_X:
+ case MAP_SIZE_Y:
+ case MAP_SIZE_Z:
+ icu->ymax= 100.0;
+ icu->ymin= -100.0;
+ break;
+ case MAP_R:
+ case MAP_G:
+ case MAP_B:
+ case MAP_DVAR:
+ case MAP_COLF:
+ case MAP_NORF:
+ case MAP_VARF:
+ case MAP_DISP:
+ icu->ymax= 1.0;
+ }
+ }
+ }
+ else if(icu->blocktype==ID_CA) {
+
+ /* yafray: aperture & focal distance params */
+ switch(icu->adrcode) {
+ case CAM_LENS:
+ icu->ymin= 5.0;
+ icu->ymax= 1000.0;
+ break;
+ case CAM_STA:
+ icu->ymin= 0.001f;
+ break;
+ case CAM_END:
+ icu->ymin= 0.1f;
+ break;
+ case CAM_YF_APERT:
+ icu->ymin = 0.0;
+ icu->ymax = 2.0;
+ break;
+ case CAM_YF_FDIST:
+ icu->ymin = 0.0;
+ icu->ymax = 5000.0;
+ break;
+
+ case CAM_SHIFT_X:
+ case CAM_SHIFT_Y:
+ icu->ymin= -2.0f;
+ icu->ymax= 2.0f;
+ break;
+ }
+ }
+ else if(icu->blocktype==ID_SO) {
+
+ switch(icu->adrcode) {
+ case SND_VOLUME:
+ icu->ymin= 0.0;
+ icu->ymax= 1.0;
+ break;
+ case SND_PITCH:
+ icu->ymin= -12.0;
+ icu->ymin= 12.0;
+ break;
+ case SND_PANNING:
+ icu->ymin= 0.0;
+ icu->ymax= 1.0;
+ break;
+ case SND_ATTEN:
+ icu->ymin= 0.0;
+ icu->ymin= 1.0;
+ break;
+ }
+ }
+ else if(icu->blocktype==ID_CO) {
+ icu->ymin= 0.0;
+ icu->ymax= 1.0f;
+ }
+
+ /* by default, slider limits will be icu->ymin and icu->ymax */
+ icu->slide_min= icu->ymin;
+ icu->slide_max= icu->ymax;
+}
+
+/* not for actions or constraints! */
+void execute_ipo(ID *id, Ipo *ipo)
+{
+ IpoCurve *icu;
+ void *poin;
+ int type;
+
+ if(ipo==NULL) return;
+
+ for(icu= ipo->curve.first; icu; icu= icu->next) {
+ poin= get_ipo_poin(id, icu, &type);
+ if(poin) write_ipo_poin(poin, type, icu->curval);
+ }
+}
+
+void *get_pchan_ipo_poin(bPoseChannel *pchan, int adrcode)
+{
+ void *poin= NULL;
+
+ switch (adrcode) {
+ case AC_QUAT_W:
+ poin= &(pchan->quat[0]);
+ pchan->flag |= POSE_ROT;
+ break;
+ case AC_QUAT_X:
+ poin= &(pchan->quat[1]);
+ pchan->flag |= POSE_ROT;
+ break;
+ case AC_QUAT_Y:
+ poin= &(pchan->quat[2]);
+ pchan->flag |= POSE_ROT;
+ break;
+ case AC_QUAT_Z:
+ poin= &(pchan->quat[3]);
+ pchan->flag |= POSE_ROT;
+ break;
+ case AC_LOC_X:
+ poin= &(pchan->loc[0]);
+ pchan->flag |= POSE_LOC;
+ break;
+ case AC_LOC_Y:
+ poin= &(pchan->loc[1]);
+ pchan->flag |= POSE_LOC;
+ break;
+ case AC_LOC_Z:
+ poin= &(pchan->loc[2]);
+ pchan->flag |= POSE_LOC;
+ break;
+ case AC_SIZE_X:
+ poin= &(pchan->size[0]);
+ pchan->flag |= POSE_SIZE;
+ break;
+ case AC_SIZE_Y:
+ poin= &(pchan->size[1]);
+ pchan->flag |= POSE_SIZE;
+ break;
+ case AC_SIZE_Z:
+ poin= &(pchan->size[2]);
+ pchan->flag |= POSE_SIZE;
+ break;
+ }
+ return poin;
+}
+
+void execute_action_ipo(bActionChannel *achan, bPoseChannel *pchan)
+{
+
+ if(achan && achan->ipo) {
+ IpoCurve *icu;
+ for(icu= achan->ipo->curve.first; icu; icu= icu->next) {
+ void *poin= get_pchan_ipo_poin(pchan, icu->adrcode);
+ if(poin) {
+ write_ipo_poin(poin, IPO_FLOAT, icu->curval);
+ //printf("execute_action_ipo wrote_ipo_poin: %f\n", icu->curval);
+ //printf("%s has poin %p value %f\n", achan->name, poin, icu->curval);
+ }
+ }
+ }
+}
+
+/* exception: it does calc for objects...
+ * now find out why this routine was used anyway!
+ */
+void do_ipo_nocalc(Ipo *ipo)
+{
+ Object *ob;
+ Material *ma;
+ Tex *tex;
+ World *wo;
+ Lamp *la;
+ Camera *ca;
+ bSound *snd;
+
+ if(ipo==NULL) return;
+
+ switch(ipo->blocktype) {
+ case ID_OB:
+ ob= G.main->object.first;
+ while(ob) {
+ if(ob->ipo==ipo) {
+ do_ob_ipo(ob);
+ /* execute_ipo((ID *)ob, ipo); */
+ }
+ ob= ob->id.next;
+ }
+ break;
+ case ID_MA:
+ ma= G.main->mat.first;
+ while(ma) {
+ if(ma->ipo==ipo) execute_ipo((ID *)ma, ipo);
+ ma= ma->id.next;
+ }
+ break;
+ case ID_TE:
+ tex= G.main->tex.first;
+ while(tex) {
+ if(tex->ipo==ipo) execute_ipo((ID *)tex, ipo);
+ tex=tex->id.next;
+ }
+ break;
+ case ID_WO:
+ wo= G.main->world.first;
+ while(wo) {
+ if(wo->ipo==ipo) execute_ipo((ID *)wo, ipo);
+ wo= wo->id.next;
+ }
+ break;
+ case ID_LA:
+ la= G.main->lamp.first;
+ while(la) {
+ if(la->ipo==ipo) execute_ipo((ID *)la, ipo);
+ la= la->id.next;
+ }
+ break;
+ case ID_CA:
+ ca= G.main->camera.first;
+ while(ca) {
+ if(ca->ipo==ipo) execute_ipo((ID *)ca, ipo);
+ ca= ca->id.next;
+ }
+ break;
+ case ID_SO:
+ snd= G.main->sound.first;
+ while(snd) {
+ if(snd->ipo==ipo) execute_ipo((ID *)snd, ipo);
+ snd= snd->id.next;
+ }
+ break;
+ }
+}
+
+void do_ipo(Ipo *ipo)
+{
+ if(ipo) {
+ float ctime= frame_to_float(G.scene->r.cfra);
+ calc_ipo(ipo, ctime);
+
+ do_ipo_nocalc(ipo);
+ }
+}
+
+
+
+void do_mat_ipo(Material *ma)
+{
+ float ctime;
+
+ if(ma==NULL || ma->ipo==NULL) return;
+
+ ctime= frame_to_float(G.scene->r.cfra);
+ /* if(ob->ipoflag & OB_OFFS_OB) ctime-= ob->sf; */
+
+ calc_ipo(ma->ipo, ctime);
+
+ execute_ipo((ID *)ma, ma->ipo);
+}
+
+void do_ob_ipo(Object *ob)
+{
+ float ctime;
+ unsigned int lay;
+
+ if(ob->ipo==NULL) return;
+
+ /* do not set ob->ctime here: for example when parent in invisible layer */
+
+ ctime= bsystem_time(ob, (float) G.scene->r.cfra, 0.0);
+
+ calc_ipo(ob->ipo, ctime);
+
+ /* Patch: remember localview */
+ lay= ob->lay & 0xFF000000;
+
+ execute_ipo((ID *)ob, ob->ipo);
+
+ ob->lay |= lay;
+ if(ob->id.name[2]=='S' && ob->id.name[3]=='C' && ob->id.name[4]=='E') {
+ if(strcmp(G.scene->id.name+2, ob->id.name+6)==0) {
+ G.scene->lay= ob->lay;
+ copy_view3d_lock(0);
+ /* no redraw here! creates too many calls */
+ }
+ }
+}
+
+void do_ob_ipodrivers(Object *ob, Ipo *ipo, float ctime)
+{
+ IpoCurve *icu;
+ void *poin;
+ int type;
+
+ for(icu= ipo->curve.first; icu; icu= icu->next) {
+ if(icu->driver) {
+ icu->curval= eval_icu(icu, ctime);
+ poin= get_ipo_poin((ID *)ob, icu, &type);
+ if(poin) write_ipo_poin(poin, type, icu->curval);
+ }
+ }
+}
+
+void do_seq_ipo(Sequence *seq)
+{
+ float ctime, div;
+
+ /* seq_ipo has an exception: calc both fields immediately */
+
+ if(seq->ipo) {
+ if((seq->flag & SEQ_IPO_FRAME_LOCKED) != 0) {
+ ctime = frame_to_float(G.scene->r.cfra);
+ div = 1.0;
+ } else {
+ ctime= frame_to_float(G.scene->r.cfra
+ - seq->startdisp);
+ div= (seq->enddisp - seq->startdisp)/100.0f;
+ if(div==0.0) return;
+ }
+
+ /* 2nd field */
+ calc_ipo(seq->ipo, (ctime+0.5f)/div);
+ execute_ipo((ID *)seq, seq->ipo);
+ seq->facf1= seq->facf0;
+
+ /* 1st field */
+ calc_ipo(seq->ipo, ctime/div);
+ execute_ipo((ID *)seq, seq->ipo);
+
+ }
+ else seq->facf1= seq->facf0= 1.0f;
+}
+
+int has_ipo_code(Ipo *ipo, int code)
+{
+ IpoCurve *icu;
+
+ if(ipo==NULL) return 0;
+
+ for(icu= ipo->curve.first; icu; icu= icu->next) {
+ if(icu->adrcode==code) return 1;
+ }
+ return 0;
+}
+
+void do_all_data_ipos()
+{
+ Material *ma;
+ Tex *tex;
+ World *wo;
+ Ipo *ipo;
+ Lamp *la;
+ Key *key;
+ Camera *ca;
+ bSound *snd;
+ Sequence *seq;
+ Editing *ed;
+ Base *base;
+ float ctime;
+
+ ctime= frame_to_float(G.scene->r.cfra);
+
+ /* this exception cannot be depgraphed yet... what todo with objects in other layers?... */
+ for(base= G.scene->base.first; base; base= base->next) {
+ /* only update layer when an ipo */
+ if( has_ipo_code(base->object->ipo, OB_LAY) ) {
+ do_ob_ipo(base->object);
+ base->lay= base->object->lay;
+ }
+ }
+
+ /* layers for the set...*/
+ if(G.scene->set) {
+ for(base= G.scene->set->base.first; base; base= base->next) {
+ if( has_ipo_code(base->object->ipo, OB_LAY) ) {
+ do_ob_ipo(base->object);
+ base->lay= base->object->lay;
+ }
+ }
+ }
+
+
+ ipo= G.main->ipo.first;
+ while(ipo) {
+ if(ipo->id.us && ipo->blocktype!=ID_OB) {
+ calc_ipo(ipo, ctime);
+ }
+ ipo= ipo->id.next;
+ }
+
+ for(tex= G.main->tex.first; tex; tex= tex->id.next) {
+ if(tex->ipo) execute_ipo((ID *)tex, tex->ipo);
+ }
+
+ for(ma= G.main->mat.first; ma; ma= ma->id.next) {
+ if(ma->ipo) execute_ipo((ID *)ma, ma->ipo);
+ }
+
+ for(wo= G.main->world.first; wo; wo= wo->id.next) {
+ if(wo->ipo) execute_ipo((ID *)wo, wo->ipo);
+ }
+
+ for(key= G.main->key.first; key; key= key->id.next) {
+ if(key->ipo) execute_ipo((ID *)key, key->ipo);
+ }
+
+ la= G.main->lamp.first;
+ while(la) {
+ if(la->ipo) execute_ipo((ID *)la, la->ipo);
+ la= la->id.next;
+ }
+
+ ca= G.main->camera.first;
+ while(ca) {
+ if(ca->ipo) execute_ipo((ID *)ca, ca->ipo);
+ ca= ca->id.next;
+ }
+
+ snd= G.main->sound.first;
+ while(snd) {
+ if(snd->ipo) execute_ipo((ID *)snd, snd->ipo);
+ snd= snd->id.next;
+ }
+
+ /* process FAC Ipos used as volume envelopes */
+ ed= G.scene->ed;
+ if (ed) {
+ seq= ed->seqbasep->first;
+ while(seq) {
+ if ((seq->type == SEQ_RAM_SOUND
+ || seq->type == SEQ_HD_SOUND) && (seq->ipo) &&
+ (seq->startdisp<=G.scene->r.cfra+2) &&
+ (seq->enddisp>G.scene->r.cfra))
+ do_seq_ipo(seq);
+ seq= seq->next;
+ }
+ }
+
+}
+
+
+int calc_ipo_spec(Ipo *ipo, int adrcode, float *ctime)
+{
+ IpoCurve *icu;
+
+ if(ipo==NULL) return 0;
+
+ for(icu= ipo->curve.first; icu; icu= icu->next) {
+ if(icu->adrcode == adrcode) {
+ if(icu->flag & IPO_LOCK);
+ else calc_icu(icu, *ctime);
+
+ *ctime= icu->curval;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+/* ************************** */
+
+void clear_delta_obipo(Ipo *ipo)
+{
+ Object *ob;
+
+ if(ipo==NULL) return;
+
+ ob= G.main->object.first;
+ while(ob) {
+ if(ob->id.lib==NULL) {
+ if(ob->ipo==ipo) {
+ memset(&ob->dloc, 0, 12);
+ memset(&ob->drot, 0, 12);
+ memset(&ob->dsize, 0, 12);
+ }
+ }
+ ob= ob->id.next;
+ }
+}
+
+void add_to_cfra_elem(ListBase *lb, BezTriple *bezt)
+{
+ CfraElem *ce, *cen;
+
+ ce= lb->first;
+ while(ce) {
+
+ if( ce->cfra==bezt->vec[1][0] ) {
+ /* do because of double keys */
+ if(bezt->f2 & 1) ce->sel= bezt->f2;
+ return;
+ }
+ else if(ce->cfra > bezt->vec[1][0]) break;
+
+ ce= ce->next;
+ }
+
+ cen= MEM_callocN(sizeof(CfraElem), "add_to_cfra_elem");
+ if(ce) BLI_insertlinkbefore(lb, ce, cen);
+ else BLI_addtail(lb, cen);
+
+ cen->cfra= bezt->vec[1][0];
+ cen->sel= bezt->f2;
+}
+
+
+
+void make_cfra_list(Ipo *ipo, ListBase *elems)
+{
+ IpoCurve *icu;
+ BezTriple *bezt;
+ int a;
+
+ if(ipo->blocktype==ID_OB) {
+ for(icu= ipo->curve.first; icu; icu= icu->next) {
+ if(icu->flag & IPO_VISIBLE) {
+ switch(icu->adrcode) {
+ case OB_DLOC_X:
+ case OB_DLOC_Y:
+ case OB_DLOC_Z:
+ case OB_DROT_X:
+ case OB_DROT_Y:
+ case OB_DROT_Z:
+ case OB_DSIZE_X:
+ case OB_DSIZE_Y:
+ case OB_DSIZE_Z:
+
+ case OB_LOC_X:
+ case OB_LOC_Y:
+ case OB_LOC_Z:
+ case OB_ROT_X:
+ case OB_ROT_Y:
+ case OB_ROT_Z:
+ case OB_SIZE_X:
+ case OB_SIZE_Y:
+ case OB_SIZE_Z:
+ case OB_PD_FSTR:
+ case OB_PD_FFALL:
+ case OB_PD_SDAMP:
+ case OB_PD_RDAMP:
+ case OB_PD_PERM:
+ bezt= icu->bezt;
+ if(bezt) {
+ a= icu->totvert;
+ while(a--) {
+ add_to_cfra_elem(elems, bezt);
+ bezt++;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+ else if(ipo->blocktype==ID_AC) {
+ for(icu= ipo->curve.first; icu; icu= icu->next) {
+ if(icu->flag & IPO_VISIBLE) {
+ switch(icu->adrcode) {
+ case AC_LOC_X:
+ case AC_LOC_Y:
+ case AC_LOC_Z:
+ case AC_SIZE_X:
+ case AC_SIZE_Y:
+ case AC_SIZE_Z:
+ case AC_QUAT_W:
+ case AC_QUAT_X:
+ case AC_QUAT_Y:
+ case AC_QUAT_Z:
+ bezt= icu->bezt;
+ if(bezt) {
+ a= icu->totvert;
+ while(a--) {
+ add_to_cfra_elem(elems, bezt);
+ bezt++;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+ else {
+ for(icu= ipo->curve.first; icu; icu= icu->next) {
+ if(icu->flag & IPO_VISIBLE) {
+ bezt= icu->bezt;
+ if(bezt) {
+ a= icu->totvert;
+ while(a--) {
+ add_to_cfra_elem(elems, bezt);
+ bezt++;
+ }
+ }
+ }
+ }
+ }
+
+ /* what's the point of this little block of code? */
+#if 0
+ if(ipo->showkey==0) {
+ /* deselect all keys */
+ ce= elems->first;
+ while(ce) {
+ ce->sel= 0;
+ ce= ce->next;
+ }
+ }
+#endif
+}
+
+/* *********************** INTERFACE FOR KETSJI ********** */
+
+
+int IPO_GetChannels(Ipo *ipo, IPO_Channel *channels)
+{
+ /* channels is max 32 items, allocated by calling function */
+
+ IpoCurve *icu;
+ int total=0;
+
+ if(ipo==NULL) return 0;
+
+ for(icu= ipo->curve.first; icu; icu= icu->next) {
+ channels[total]= icu->adrcode;
+ total++;
+ if(total>31) break;
+ }
+
+ return total;
+}
+
+
+
+/* Get the float value for channel 'channel' at time 'ctime' */
+
+float IPO_GetFloatValue(Ipo *ipo, IPO_Channel channel, float ctime)
+{
+ if(ipo==NULL) return 0;
+
+ calc_ipo_spec(ipo, channel, &ctime);
+
+ if (OB_ROT_X <= channel && channel <= OB_DROT_Z) {
+ ctime *= (float)(M_PI_2/9.0);
+ }
+
+ return ctime;
+}
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
new file mode 100644
index 00000000000..8da3ea0b994
--- /dev/null
+++ b/source/blender/blenkernel/intern/key.c
@@ -0,0 +1,1408 @@
+
+/* key.c
+ *
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <math.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_curve_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_key_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_action.h"
+#include "BKE_bad_level_calls.h"
+#include "BKE_blender.h"
+#include "BKE_curve.h"
+#include "BKE_global.h"
+#include "BKE_ipo.h"
+#include "BKE_key.h"
+#include "BKE_lattice.h"
+#include "BKE_library.h"
+#include "BKE_mesh.h"
+#include "BKE_main.h"
+#include "BKE_object.h"
+#include "BKE_utildefines.h"
+
+#include "BLI_blenlib.h"
+
+#include "blendef.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define KEY_BPOINT 1
+#define KEY_BEZTRIPLE 2
+
+int slurph_opt= 1;
+
+
+void free_key(Key *key)
+{
+ KeyBlock *kb;
+
+ if(key->ipo) key->ipo->id.us--;
+
+
+ while( (kb= key->block.first) ) {
+
+ if(kb->data) MEM_freeN(kb->data);
+
+ BLI_remlink(&key->block, kb);
+ MEM_freeN(kb);
+ }
+
+}
+
+/* GS reads the memory pointed at in a specific ordering. There are,
+ * however two definitions for it. I have jotted them down here, both,
+ * but I think the first one is actually used. The thing is that
+ * big-endian systems might read this the wrong way round. OTOH, we
+ * constructed the IDs that are read out with this macro explicitly as
+ * well. I expect we'll sort it out soon... */
+
+/* from blendef: */
+#define GS(a) (*((short *)(a)))
+
+/* from misc_util: flip the bytes from x */
+/* #define GS(x) (((unsigned char *)(x))[0] << 8 | ((unsigned char *)(x))[1]) */
+
+Key *add_key(ID *id) /* common function */
+{
+ Key *key;
+ char *el;
+
+ key= alloc_libblock(&G.main->key, ID_KE, "Key");
+
+ key->type= KEY_NORMAL;
+ key->from= id;
+
+ if( GS(id->name)==ID_ME) {
+ el= key->elemstr;
+
+ el[0]= 3;
+ el[1]= IPO_FLOAT;
+ el[2]= 0;
+
+ key->elemsize= 12;
+ }
+ else if( GS(id->name)==ID_LT) {
+ el= key->elemstr;
+
+ el[0]= 3;
+ el[1]= IPO_FLOAT;
+ el[2]= 0;
+
+ key->elemsize= 12;
+ }
+ else if( GS(id->name)==ID_CU) {
+ el= key->elemstr;
+
+ el[0]= 4;
+ el[1]= IPO_BPOINT;
+ el[2]= 0;
+
+ key->elemsize= 16;
+ }
+
+ return key;
+}
+
+Key *copy_key(Key *key)
+{
+ Key *keyn;
+ KeyBlock *kbn, *kb;
+
+ if(key==0) return 0;
+
+ keyn= copy_libblock(key);
+
+ keyn->ipo= copy_ipo(key->ipo);
+
+ duplicatelist(&keyn->block, &key->block);
+
+ kb= key->block.first;
+ kbn= keyn->block.first;
+ while(kbn) {
+
+ if(kbn->data) kbn->data= MEM_dupallocN(kbn->data);
+ if( kb==key->refkey ) keyn->refkey= kbn;
+
+ kbn= kbn->next;
+ kb= kb->next;
+ }
+
+ return keyn;
+}
+
+void make_local_key(Key *key)
+{
+
+ /* - only lib users: do nothing
+ * - only local users: set flag
+ * - mixed: make copy
+ */
+ if(key==0) return;
+
+ key->id.lib= 0;
+ new_id(0, (ID *)key, 0);
+ make_local_ipo(key->ipo);
+}
+
+/*
+ * Sort shape keys and Ipo curves after a change. This assumes that at most
+ * one key was moved, which is a valid assumption for the places it's
+ * currently being called.
+ */
+
+void sort_keys(Key *key)
+{
+ KeyBlock *kb;
+ short i, adrcode;
+ IpoCurve *icu = NULL;
+ KeyBlock *kb2;
+
+ /* locate the key which is out of position */
+ for( kb= key->block.first; kb; kb= kb->next )
+ if( kb->next && kb->pos > kb->next->pos )
+ break;
+
+ /* if we find a key, move it */
+ if( kb ) {
+ kb = kb->next; /* next key is the out-of-order one */
+ BLI_remlink(&key->block, kb);
+
+ /* find the right location and insert before */
+ for( kb2=key->block.first; kb2; kb2= kb2->next ) {
+ if( kb2->pos > kb->pos ) {
+ BLI_insertlink(&key->block, kb2->prev, kb);
+ break;
+ }
+ }
+
+ /* if more than one Ipo curve, see if this key had a curve */
+
+ if(key->ipo && key->ipo->curve.first != key->ipo->curve.last ) {
+ for(icu= key->ipo->curve.first; icu; icu= icu->next) {
+ /* if we find the curve, remove it and reinsert in the
+ right place */
+ if(icu->adrcode==kb->adrcode) {
+ IpoCurve *icu2;
+ BLI_remlink(&key->ipo->curve, icu);
+ for(icu2= key->ipo->curve.first; icu2; icu2= icu2->next) {
+ if(icu2->adrcode >= kb2->adrcode) {
+ BLI_insertlink(&key->ipo->curve, icu2->prev, icu);
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ /* kb points at the moved key, icu at the moved ipo (if it exists).
+ * go back now and renumber adrcodes */
+
+ /* first new code */
+ adrcode = kb2->adrcode;
+ for( i = kb->adrcode - adrcode; i >= 0; --i, ++adrcode ) {
+ /* if the next ipo curve matches the current key, renumber it */
+ if(icu && icu->adrcode == kb->adrcode ) {
+ icu->adrcode = adrcode;
+ icu = icu->next;
+ }
+ /* renumber the shape key */
+ kb->adrcode = adrcode;
+ kb = kb->next;
+ }
+ }
+
+ /* new rule; first key is refkey, this to match drawing channels... */
+ key->refkey= key->block.first;
+}
+
+/**************** do the key ****************/
+
+
+void set_four_ipo(float d, float *data, int type)
+{
+ float d2, d3, fc;
+
+ if(type==KEY_LINEAR) {
+ data[0]= 0.0f;
+ data[1]= 1.0f-d;
+ data[2]= d;
+ data[3]= 0.0f;
+ }
+ else {
+ d2= d*d;
+ d3= d2*d;
+
+ if(type==KEY_CARDINAL) {
+
+ fc= 0.71f;
+
+ data[0]= -fc*d3 +2.0f*fc*d2 -fc*d;
+ data[1]= (2.0f-fc)*d3 +(fc-3.0f)*d2 +1.0f;
+ data[2]= (fc-2.0f)*d3 +(3.0f-2.0f*fc)*d2 +fc*d;
+ data[3]= fc*d3 -fc*d2;
+ }
+ else if(type==KEY_BSPLINE) {
+
+ data[0]= -0.1666f*d3 +0.5f*d2 -0.5f*d +0.16666f;
+ data[1]= 0.5f*d3 -d2 +0.6666f;
+ data[2]= -0.5f*d3 +0.5f*d2 +0.5f*d +0.1666f;
+ data[3]= 0.1666f*d3 ;
+ }
+ }
+}
+
+void set_afgeleide_four_ipo(float d, float *data, int type)
+{
+ float d2, fc;
+
+ if(type==KEY_LINEAR) {
+
+ }
+ else {
+ d2= d*d;
+
+ if(type==KEY_CARDINAL) {
+
+ fc= 0.71f;
+
+ data[0]= -3.0f*fc*d2 +4.0f*fc*d -fc;
+ data[1]= 3.0f*(2.0f-fc)*d2 +2.0f*(fc-3.0f)*d;
+ data[2]= 3.0f*(fc-2.0f)*d2 +2.0f*(3.0f-2.0f*fc)*d +fc;
+ data[3]= 3.0f*fc*d2 -2.0f*fc*d;
+ }
+ else if(type==KEY_BSPLINE) {
+
+ data[0]= -0.1666f*3.0f*d2 +d -0.5f;
+ data[1]= 1.5f*d2 -2.0f*d;
+ data[2]= -1.5f*d2 +d +0.5f;
+ data[3]= 0.1666f*3.0f*d2 ;
+ }
+ }
+}
+
+static int setkeys(float fac, ListBase *lb, KeyBlock *k[], float *t, int cycl)
+{
+ /* return 1 means k[2] is the position, return 0 means interpolate */
+ KeyBlock *k1, *firstkey;
+ float d, dpos, ofs=0, lastpos, temp, fval[4];
+ short bsplinetype;
+
+ firstkey= lb->first;
+ k1= lb->last;
+ lastpos= k1->pos;
+ dpos= lastpos - firstkey->pos;
+
+ if(fac < firstkey->pos) fac= firstkey->pos;
+ else if(fac > k1->pos) fac= k1->pos;
+
+ k1=k[0]=k[1]=k[2]=k[3]= firstkey;
+ t[0]=t[1]=t[2]=t[3]= k1->pos;
+
+ /* if(fac<0.0 || fac>1.0) return 1; */
+
+ if(k1->next==0) return 1;
+
+ if(cycl) { /* pre-sort */
+ k[2]= k1->next;
+ k[3]= k[2]->next;
+ if(k[3]==0) k[3]=k1;
+ while(k1) {
+ if(k1->next==0) k[0]=k1;
+ k1=k1->next;
+ }
+ k1= k[1];
+ t[0]= k[0]->pos;
+ t[1]+= dpos;
+ t[2]= k[2]->pos + dpos;
+ t[3]= k[3]->pos + dpos;
+ fac+= dpos;
+ ofs= dpos;
+ if(k[3]==k[1]) {
+ t[3]+= dpos;
+ ofs= 2.0f*dpos;
+ }
+ if(fac<t[1]) fac+= dpos;
+ k1= k[3];
+ }
+ else { /* pre-sort */
+ k[2]= k1->next;
+ t[2]= k[2]->pos;
+ k[3]= k[2]->next;
+ if(k[3]==0) k[3]= k[2];
+ t[3]= k[3]->pos;
+ k1= k[3];
+ }
+
+ while( t[2]<fac ) { /* find correct location */
+ if(k1->next==0) {
+ if(cycl) {
+ k1= firstkey;
+ ofs+= dpos;
+ }
+ else if(t[2]==t[3]) break;
+ }
+ else k1= k1->next;
+
+ t[0]= t[1];
+ k[0]= k[1];
+ t[1]= t[2];
+ k[1]= k[2];
+ t[2]= t[3];
+ k[2]= k[3];
+ t[3]= k1->pos+ofs;
+ k[3]= k1;
+
+ if(ofs>2.1+lastpos) break;
+ }
+
+ bsplinetype= 0;
+ if(k[1]->type==KEY_BSPLINE || k[2]->type==KEY_BSPLINE) bsplinetype= 1;
+
+
+ if(cycl==0) {
+ if(bsplinetype==0) { /* B spline doesn't go through the control points */
+ if(fac<=t[1]) { /* fac for 1st key */
+ t[2]= t[1];
+ k[2]= k[1];
+ return 1;
+ }
+ if(fac>=t[2] ) { /* fac after 2nd key */
+ return 1;
+ }
+ }
+ else if(fac>t[2]) { /* last key */
+ fac= t[2];
+ k[3]= k[2];
+ t[3]= t[2];
+ }
+ }
+
+ d= t[2]-t[1];
+ if(d==0.0) {
+ if(bsplinetype==0) {
+ return 1; /* both keys equal */
+ }
+ }
+ else d= (fac-t[1])/d;
+
+ /* interpolation */
+
+ set_four_ipo(d, t, k[1]->type);
+
+ if(k[1]->type != k[2]->type) {
+ set_four_ipo(d, fval, k[2]->type);
+
+ temp= 1.0f-d;
+ t[0]= temp*t[0]+ d*fval[0];
+ t[1]= temp*t[1]+ d*fval[1];
+ t[2]= temp*t[2]+ d*fval[2];
+ t[3]= temp*t[3]+ d*fval[3];
+ }
+
+ return 0;
+
+}
+
+static void flerp(int aantal, float *in, float *f0, float *f1, float *f2, float *f3, float *t)
+{
+ int a;
+
+ for(a=0; a<aantal; a++) {
+ in[a]= t[0]*f0[a]+t[1]*f1[a]+t[2]*f2[a]+t[3]*f3[a];
+ }
+}
+
+static void rel_flerp(int aantal, float *in, float *ref, float *out, float fac)
+{
+ int a;
+
+ for(a=0; a<aantal; a++) {
+ in[a]-= fac*(ref[a]-out[a]);
+ }
+}
+
+static void cp_key(int start, int end, int tot, char *poin, Key *key, KeyBlock *k, float *weights, int mode)
+{
+ float ktot = 0.0, kd = 0.0;
+ int elemsize, poinsize = 0, a, *ofsp, ofs[32], flagflo=0;
+ char *k1, *kref;
+ char *cp, elemstr[8];
+
+ if(key->from==NULL) return;
+
+ if( GS(key->from->name)==ID_ME ) {
+ ofs[0]= sizeof(MVert);
+ ofs[1]= 0;
+ poinsize= ofs[0];
+ }
+ else if( GS(key->from->name)==ID_LT ) {
+ ofs[0]= sizeof(BPoint);
+ ofs[1]= 0;
+ poinsize= ofs[0];
+ }
+ else if( GS(key->from->name)==ID_CU ) {
+ if(mode==KEY_BPOINT) ofs[0]= sizeof(BPoint);
+ else ofs[0]= sizeof(BezTriple);
+
+ ofs[1]= 0;
+ poinsize= ofs[0];
+ }
+
+
+ if(end>tot) end= tot;
+
+ k1= k->data;
+ kref= key->refkey->data;
+
+ if(tot != k->totelem) {
+ ktot= 0.0;
+ flagflo= 1;
+ if(k->totelem) {
+ kd= k->totelem/(float)tot;
+ }
+ else return;
+ }
+
+ /* this exception is needed for slurphing */
+ if(start!=0) {
+
+ poin+= poinsize*start;
+
+ if(flagflo) {
+ ktot+= start*kd;
+ a= (int)floor(ktot);
+ if(a) {
+ ktot-= a;
+ k1+= a*key->elemsize;
+ }
+ }
+ else k1+= start*key->elemsize;
+ }
+
+ if(mode==KEY_BEZTRIPLE) {
+ elemstr[0]= 1;
+ elemstr[1]= IPO_BEZTRIPLE;
+ elemstr[2]= 0;
+ }
+
+ /* just do it here, not above! */
+ elemsize= key->elemsize;
+ if(mode==KEY_BEZTRIPLE) elemsize*= 3;
+
+ for(a=start; a<end; a++) {
+ cp= key->elemstr;
+ if(mode==KEY_BEZTRIPLE) cp= elemstr;
+
+ ofsp= ofs;
+
+ while( cp[0] ) {
+
+ switch(cp[1]) {
+ case IPO_FLOAT:
+
+ if(weights) {
+ memcpy(poin, kref, 4*cp[0]);
+ if(*weights!=0.0f)
+ rel_flerp(cp[0], (float *)poin, (float *)kref, (float *)k1, *weights);
+ weights++;
+ }
+ else
+ memcpy(poin, k1, 4*cp[0]);
+
+ poin+= ofsp[0];
+
+ break;
+ case IPO_BPOINT:
+ memcpy(poin, k1, 3*4);
+ memcpy(poin+16, k1+12, 4);
+
+ poin+= ofsp[0];
+
+ break;
+ case IPO_BEZTRIPLE:
+ memcpy(poin, k1, 4*12);
+ poin+= ofsp[0];
+
+ break;
+ }
+
+ cp+= 2; ofsp++;
+ }
+
+ /* are we going to be nasty? */
+ if(flagflo) {
+ ktot+= kd;
+ while(ktot>=1.0) {
+ ktot-= 1.0;
+ k1+= elemsize;
+ kref+= elemsize;
+ }
+ }
+ else {
+ k1+= elemsize;
+ kref+= elemsize;
+ }
+
+ if(mode==KEY_BEZTRIPLE) a+=2;
+ }
+}
+
+void cp_cu_key(Curve *cu, KeyBlock *kb, int start, int end)
+{
+ Nurb *nu;
+ int a, step = 0, tot, a1, a2;
+ char *poin;
+
+ tot= count_curveverts(&cu->nurb);
+ nu= cu->nurb.first;
+ a= 0;
+ while(nu) {
+ if(nu->bp) {
+
+ step= nu->pntsu*nu->pntsv;
+
+ /* exception because keys prefer to work with complete blocks */
+ poin= (char *)nu->bp->vec;
+ poin -= a*sizeof(BPoint);
+
+ a1= MAX2(a, start);
+ a2= MIN2(a+step, end);
+
+ if(a1<a2) cp_key(a1, a2, tot, poin, cu->key, kb, NULL, KEY_BPOINT);
+ }
+ else if(nu->bezt) {
+
+ step= 3*nu->pntsu;
+
+ poin= (char *)nu->bezt->vec;
+ poin -= a*sizeof(BezTriple);
+
+ a1= MAX2(a, start);
+ a2= MIN2(a+step, end);
+
+ if(a1<a2) cp_key(a1, a2, tot, poin, cu->key, kb, NULL, KEY_BEZTRIPLE);
+
+ }
+ a+= step;
+ nu=nu->next;
+ }
+}
+
+
+static void do_rel_key(int start, int end, int tot, char *basispoin, Key *key, int mode)
+{
+ KeyBlock *kb;
+ int *ofsp, ofs[3], elemsize, b;
+ char *cp, *poin, *reffrom, *from, elemstr[8];
+
+ if(key->from==NULL) return;
+
+ if( GS(key->from->name)==ID_ME ) {
+ ofs[0]= sizeof(MVert);
+ ofs[1]= 0;
+ }
+ else if( GS(key->from->name)==ID_LT ) {
+ ofs[0]= sizeof(BPoint);
+ ofs[1]= 0;
+ }
+ else if( GS(key->from->name)==ID_CU ) {
+ if(mode==KEY_BPOINT) ofs[0]= sizeof(BPoint);
+ else ofs[0]= sizeof(BezTriple);
+
+ ofs[1]= 0;
+ }
+
+ if(end>tot) end= tot;
+
+ /* in case of beztriple */
+ elemstr[0]= 1; /* nr of ipofloats */
+ elemstr[1]= IPO_BEZTRIPLE;
+ elemstr[2]= 0;
+
+ /* just here, not above! */
+ elemsize= key->elemsize;
+ if(mode==KEY_BEZTRIPLE) elemsize*= 3;
+
+ /* step 1 init */
+ cp_key(start, end, tot, basispoin, key, key->refkey, NULL, mode);
+
+ /* step 2: do it */
+
+ kb= key->block.first;
+ while(kb) {
+
+ if(kb!=key->refkey) {
+ float icuval= kb->curval;
+
+ /* only with value, and no difference allowed */
+ if(icuval!=0.0f && kb->totelem==tot) {
+ float weight, *weights= kb->weights;
+
+ poin= basispoin;
+ reffrom= key->refkey->data;
+ from= kb->data;
+
+ poin+= start*ofs[0];
+ reffrom+= key->elemsize*start; // key elemsize yes!
+ from+= key->elemsize*start;
+
+ for(b=start; b<end; b++) {
+
+ if(weights)
+ weight= *weights * icuval;
+ else
+ weight= icuval;
+
+ cp= key->elemstr;
+ if(mode==KEY_BEZTRIPLE) cp= elemstr;
+
+ ofsp= ofs;
+
+ while( cp[0] ) { /* cp[0]==amount */
+
+ switch(cp[1]) {
+ case IPO_FLOAT:
+ rel_flerp(cp[0], (float *)poin, (float *)reffrom, (float *)from, weight);
+
+ break;
+ case IPO_BPOINT:
+ rel_flerp(3, (float *)poin, (float *)reffrom, (float *)from, icuval);
+ rel_flerp(1, (float *)(poin+16), (float *)(reffrom+16), (float *)(from+16), icuval);
+
+ break;
+ case IPO_BEZTRIPLE:
+ rel_flerp(9, (float *)poin, (float *)reffrom, (float *)from, icuval);
+
+ break;
+ }
+
+ poin+= ofsp[0];
+
+ cp+= 2;
+ ofsp++;
+ }
+
+ reffrom+= elemsize;
+ from+= elemsize;
+
+ if(mode==KEY_BEZTRIPLE) b+= 2;
+ if(weights) weights++;
+ }
+ }
+ }
+ kb= kb->next;
+ }
+}
+
+
+static void do_key(int start, int end, int tot, char *poin, Key *key, KeyBlock **k, float *t, int mode)
+{
+ float k1tot = 0.0, k2tot = 0.0, k3tot = 0.0, k4tot = 0.0;
+ float k1d = 0.0, k2d = 0.0, k3d = 0.0, k4d = 0.0;
+ int a, ofs[32], *ofsp;
+ int flagdo= 15, flagflo=0, elemsize, poinsize=0;
+ char *k1, *k2, *k3, *k4;
+ char *cp, elemstr[8];;
+
+ if(key->from==0) return;
+
+ if( GS(key->from->name)==ID_ME ) {
+ ofs[0]= sizeof(MVert);
+ ofs[1]= 0;
+ poinsize= ofs[0];
+ }
+ else if( GS(key->from->name)==ID_LT ) {
+ ofs[0]= sizeof(BPoint);
+ ofs[1]= 0;
+ poinsize= ofs[0];
+ }
+ else if( GS(key->from->name)==ID_CU ) {
+ if(mode==KEY_BPOINT) ofs[0]= sizeof(BPoint);
+ else ofs[0]= sizeof(BezTriple);
+
+ ofs[1]= 0;
+ poinsize= ofs[0];
+ }
+
+ if(end>tot) end= tot;
+
+ k1= k[0]->data;
+ k2= k[1]->data;
+ k3= k[2]->data;
+ k4= k[3]->data;
+
+ /* test for more or less points (per key!) */
+ if(tot != k[0]->totelem) {
+ k1tot= 0.0;
+ flagflo |= 1;
+ if(k[0]->totelem) {
+ k1d= k[0]->totelem/(float)tot;
+ }
+ else flagdo -= 1;
+ }
+ if(tot != k[1]->totelem) {
+ k2tot= 0.0;
+ flagflo |= 2;
+ if(k[0]->totelem) {
+ k2d= k[1]->totelem/(float)tot;
+ }
+ else flagdo -= 2;
+ }
+ if(tot != k[2]->totelem) {
+ k3tot= 0.0;
+ flagflo |= 4;
+ if(k[0]->totelem) {
+ k3d= k[2]->totelem/(float)tot;
+ }
+ else flagdo -= 4;
+ }
+ if(tot != k[3]->totelem) {
+ k4tot= 0.0;
+ flagflo |= 8;
+ if(k[0]->totelem) {
+ k4d= k[3]->totelem/(float)tot;
+ }
+ else flagdo -= 8;
+ }
+
+ /* this exception needed for slurphing */
+ if(start!=0) {
+
+ poin+= poinsize*start;
+
+ if(flagdo & 1) {
+ if(flagflo & 1) {
+ k1tot+= start*k1d;
+ a= (int)floor(k1tot);
+ if(a) {
+ k1tot-= a;
+ k1+= a*key->elemsize;
+ }
+ }
+ else k1+= start*key->elemsize;
+ }
+ if(flagdo & 2) {
+ if(flagflo & 2) {
+ k2tot+= start*k2d;
+ a= (int)floor(k2tot);
+ if(a) {
+ k2tot-= a;
+ k2+= a*key->elemsize;
+ }
+ }
+ else k2+= start*key->elemsize;
+ }
+ if(flagdo & 4) {
+ if(flagflo & 4) {
+ k3tot+= start*k3d;
+ a= (int)floor(k3tot);
+ if(a) {
+ k3tot-= a;
+ k3+= a*key->elemsize;
+ }
+ }
+ else k3+= start*key->elemsize;
+ }
+ if(flagdo & 8) {
+ if(flagflo & 8) {
+ k4tot+= start*k4d;
+ a= (int)floor(k4tot);
+ if(a) {
+ k4tot-= a;
+ k4+= a*key->elemsize;
+ }
+ }
+ else k4+= start*key->elemsize;
+ }
+
+ }
+
+ /* in case of beztriple */
+ elemstr[0]= 1; /* nr of ipofloats */
+ elemstr[1]= IPO_BEZTRIPLE;
+ elemstr[2]= 0;
+
+ /* only here, not above! */
+ elemsize= key->elemsize;
+ if(mode==KEY_BEZTRIPLE) elemsize*= 3;
+
+ for(a=start; a<end; a++) {
+
+ cp= key->elemstr;
+ if(mode==KEY_BEZTRIPLE) cp= elemstr;
+
+ ofsp= ofs;
+
+ while( cp[0] ) { /* cp[0]==amount */
+
+ switch(cp[1]) {
+ case IPO_FLOAT:
+ flerp(cp[0], (float *)poin, (float *)k1, (float *)k2, (float *)k3, (float *)k4, t);
+ poin+= ofsp[0];
+
+ break;
+ case IPO_BPOINT:
+ flerp(3, (float *)poin, (float *)k1, (float *)k2, (float *)k3, (float *)k4, t);
+ flerp(1, (float *)(poin+16), (float *)(k1+12), (float *)(k2+12), (float *)(k3+12), (float *)(k4+12), t);
+
+ poin+= ofsp[0];
+
+ break;
+ case IPO_BEZTRIPLE:
+ flerp(9, (void *)poin, (void *)k1, (void *)k2, (void *)k3, (void *)k4, t);
+ flerp(1, (float *)(poin+36), (float *)(k1+36), (float *)(k2+36), (float *)(k3+36), (float *)(k4+36), t);
+ poin+= ofsp[0];
+
+ break;
+ }
+
+
+ cp+= 2;
+ ofsp++;
+ }
+ /* lets do it the difficult way: when keys have a different size */
+ if(flagdo & 1) {
+ if(flagflo & 1) {
+ k1tot+= k1d;
+ while(k1tot>=1.0) {
+ k1tot-= 1.0;
+ k1+= elemsize;
+ }
+ }
+ else k1+= elemsize;
+ }
+ if(flagdo & 2) {
+ if(flagflo & 2) {
+ k2tot+= k2d;
+ while(k2tot>=1.0) {
+ k2tot-= 1.0;
+ k2+= elemsize;
+ }
+ }
+ else k2+= elemsize;
+ }
+ if(flagdo & 4) {
+ if(flagflo & 4) {
+ k3tot+= k3d;
+ while(k3tot>=1.0) {
+ k3tot-= 1.0;
+ k3+= elemsize;
+ }
+ }
+ else k3+= elemsize;
+ }
+ if(flagdo & 8) {
+ if(flagflo & 8) {
+ k4tot+= k4d;
+ while(k4tot>=1.0) {
+ k4tot-= 1.0;
+ k4+= elemsize;
+ }
+ }
+ else k4+= elemsize;
+ }
+
+ if(mode==KEY_BEZTRIPLE) a+= 2;
+ }
+}
+
+static float *get_weights_array(Object *ob, char *vgroup)
+{
+ bDeformGroup *curdef;
+ MDeformVert *dvert= NULL;
+ int totvert= 0, index= 0;
+
+ /* no vgroup string set? */
+ if(vgroup[0]==0) return NULL;
+
+ /* gather dvert and totvert */
+ if(ob->type==OB_MESH) {
+ Mesh *me= ob->data;
+ dvert= me->dvert;
+ totvert= me->totvert;
+ }
+ else if(ob->type==OB_LATTICE) {
+ Lattice *lt= ob->data;
+ dvert= lt->dvert;
+ totvert= lt->pntsu*lt->pntsv*lt->pntsw;
+ }
+
+ if(dvert==NULL) return NULL;
+
+ /* find the group (weak loop-in-loop) */
+ for (curdef = ob->defbase.first; curdef; curdef=curdef->next, index++)
+ if (!strcmp(curdef->name, vgroup))
+ break;
+
+ if(curdef) {
+ float *weights;
+ int i, j;
+
+ weights= MEM_callocN(totvert*sizeof(float), "weights");
+
+ for (i=0; i < totvert; i++, dvert++) {
+ for(j=0; j<dvert->totweight; j++) {
+ if (dvert->dw[j].def_nr == index) {
+ weights[i]= dvert->dw[j].weight;
+ break;
+ }
+ }
+ }
+ return weights;
+ }
+ return NULL;
+}
+
+static int do_mesh_key(Object *ob, Mesh *me)
+{
+ KeyBlock *k[4];
+ float cfra, ctime, t[4], delta, loc[3], size[3];
+ int a, flag = 0, step;
+
+ if(me->totvert==0) return 0;
+ if(me->key==NULL) return 0;
+ if(me->key->block.first==NULL) return 0;
+
+ /* prevent python from screwing this up? anyhoo, the from pointer could be dropped */
+ me->key->from= (ID *)me;
+
+ if(me->key->slurph && me->key->type!=KEY_RELATIVE ) {
+ delta= me->key->slurph;
+ delta/= me->totvert;
+
+ step= 1;
+ if(me->totvert>100 && slurph_opt) {
+ step= me->totvert/50;
+ delta*= step;
+ /* in do_key and cp_key the case a>tot is handled */
+ }
+
+ cfra= G.scene->r.cfra;
+
+ for(a=0; a<me->totvert; a+=step, cfra+= delta) {
+
+ ctime= bsystem_time(0, cfra, 0.0);
+ if(calc_ipo_spec(me->key->ipo, KEY_SPEED, &ctime)==0) {
+ ctime /= 100.0;
+ CLAMP(ctime, 0.0, 1.0);
+ }
+
+ flag= setkeys(ctime, &me->key->block, k, t, 0);
+ if(flag==0) {
+
+ do_key(a, a+step, me->totvert, (char *)me->mvert->co, me->key, k, t, 0);
+ }
+ else {
+ cp_key(a, a+step, me->totvert, (char *)me->mvert->co, me->key, k[2], NULL, 0);
+ }
+ }
+
+ if(flag && k[2]==me->key->refkey) tex_space_mesh(me);
+ else boundbox_mesh(me, loc, size);
+ }
+ else {
+
+ if(me->key->type==KEY_RELATIVE) {
+ KeyBlock *kb;
+
+ for(kb= me->key->block.first; kb; kb= kb->next)
+ kb->weights= get_weights_array(ob, kb->vgroup);
+
+ do_rel_key(0, me->totvert, me->totvert, (char *)me->mvert->co, me->key, 0);
+
+ for(kb= me->key->block.first; kb; kb= kb->next) {
+ if(kb->weights) MEM_freeN(kb->weights);
+ kb->weights= NULL;
+ }
+ }
+ else {
+ ctime= bsystem_time(ob, G.scene->r.cfra, 0.0);
+
+ if(calc_ipo_spec(me->key->ipo, KEY_SPEED, &ctime)==0) {
+ ctime /= 100.0;
+ CLAMP(ctime, 0.0, 1.0);
+ }
+
+ flag= setkeys(ctime, &me->key->block, k, t, 0);
+ if(flag==0) {
+ do_key(0, me->totvert, me->totvert, (char *)me->mvert->co, me->key, k, t, 0);
+ }
+ else {
+ cp_key(0, me->totvert, me->totvert, (char *)me->mvert->co, me->key, k[2], NULL, 0);
+ }
+
+ if(flag && k[2]==me->key->refkey) tex_space_mesh(me);
+ else boundbox_mesh(me, loc, size);
+ }
+ }
+ return 1;
+}
+
+static void do_cu_key(Curve *cu, KeyBlock **k, float *t)
+{
+ Nurb *nu;
+ int a, step = 0, tot;
+ char *poin;
+
+ tot= count_curveverts(&cu->nurb);
+ nu= cu->nurb.first;
+ a= 0;
+
+ while(nu) {
+ if(nu->bp) {
+
+ step= nu->pntsu*nu->pntsv;
+
+ /* exception because keys prefer to work with complete blocks */
+ poin= (char *)nu->bp->vec;
+ poin -= a*sizeof(BPoint);
+
+ do_key(a, a+step, tot, poin, cu->key, k, t, KEY_BPOINT);
+ }
+ else if(nu->bezt) {
+
+ step= 3*nu->pntsu;
+
+ poin= (char *)nu->bezt->vec;
+ poin -= a*sizeof(BezTriple);
+
+ do_key(a, a+step, tot, poin, cu->key, k, t, KEY_BEZTRIPLE);
+
+ }
+ a+= step;
+ nu=nu->next;
+ }
+}
+
+static void do_rel_cu_key(Curve *cu, float ctime)
+{
+ Nurb *nu;
+ int a, step = 0, tot;
+ char *poin;
+
+ tot= count_curveverts(&cu->nurb);
+ nu= cu->nurb.first;
+ a= 0;
+ while(nu) {
+ if(nu->bp) {
+
+ step= nu->pntsu*nu->pntsv;
+
+ /* exception because keys prefer to work with complete blocks */
+ poin= (char *)nu->bp->vec;
+ poin -= a*sizeof(BPoint);
+
+ do_rel_key(a, a+step, tot, poin, cu->key, KEY_BPOINT);
+ }
+ else if(nu->bezt) {
+
+ step= 3*nu->pntsu;
+
+ poin= (char *)nu->bezt->vec;
+ poin -= a*sizeof(BezTriple);
+
+ do_rel_key(a, a+step, tot, poin, cu->key, KEY_BEZTRIPLE);
+ }
+ a+= step;
+
+ nu=nu->next;
+ }
+}
+
+static int do_curve_key(Curve *cu)
+{
+ KeyBlock *k[4];
+ float cfra, ctime, t[4], delta;
+ int a, flag = 0, step = 0, tot;
+
+ tot= count_curveverts(&cu->nurb);
+
+ if(tot==0) return 0;
+ if(cu->key==NULL) return 0;
+ if(cu->key->block.first==NULL) return 0;
+
+ if(cu->key->slurph) {
+ delta= cu->key->slurph;
+ delta/= tot;
+
+ step= 1;
+ if(tot>100 && slurph_opt) {
+ step= tot/50;
+ delta*= step;
+ /* in do_key and cp_key the case a>tot has been handled */
+ }
+
+ cfra= G.scene->r.cfra;
+
+ for(a=0; a<tot; a+=step, cfra+= delta) {
+
+ ctime= bsystem_time(0, cfra, 0.0);
+ if(calc_ipo_spec(cu->key->ipo, KEY_SPEED, &ctime)==0) {
+ ctime /= 100.0;
+ CLAMP(ctime, 0.0, 1.0);
+ }
+
+ flag= setkeys(ctime, &cu->key->block, k, t, 0);
+ if(flag==0) {
+
+ /* do_key(a, a+step, tot, (char *)cu->mvert->co, cu->key, k, t, 0); */
+ }
+ else {
+ /* cp_key(a, a+step, tot, (char *)cu->mvert->co, cu->key, k[2],0); */
+ }
+ }
+
+ if(flag && k[2]==cu->key->refkey) tex_space_curve(cu);
+
+
+ }
+ else {
+
+ ctime= bsystem_time(NULL, (float)G.scene->r.cfra, 0.0);
+
+ if(cu->key->type==KEY_RELATIVE) {
+ do_rel_cu_key(cu, ctime);
+ }
+ else {
+ if(calc_ipo_spec(cu->key->ipo, KEY_SPEED, &ctime)==0) {
+ ctime /= 100.0;
+ CLAMP(ctime, 0.0, 1.0);
+ }
+
+ flag= setkeys(ctime, &cu->key->block, k, t, 0);
+
+ if(flag==0) do_cu_key(cu, k, t);
+ else cp_cu_key(cu, k[2], 0, tot);
+
+ if(flag && k[2]==cu->key->refkey) tex_space_curve(cu);
+ }
+ }
+
+ return 1;
+}
+
+static int do_latt_key(Object *ob, Lattice *lt)
+{
+ KeyBlock *k[4];
+ float delta, cfra, ctime, t[4];
+ int a, tot, flag;
+
+ if(lt->key==NULL) return 0;
+ if(lt->key->block.first==NULL) return 0;
+
+ tot= lt->pntsu*lt->pntsv*lt->pntsw;
+
+ if(lt->key->slurph) {
+ delta= lt->key->slurph;
+ delta/= (float)tot;
+
+ cfra= G.scene->r.cfra;
+
+ for(a=0; a<tot; a++, cfra+= delta) {
+
+ ctime= bsystem_time(0, cfra, 0.0);
+ if(calc_ipo_spec(lt->key->ipo, KEY_SPEED, &ctime)==0) {
+ ctime /= 100.0;
+ CLAMP(ctime, 0.0, 1.0);
+ }
+
+ flag= setkeys(ctime, &lt->key->block, k, t, 0);
+ if(flag==0) {
+
+ do_key(a, a+1, tot, (char *)lt->def->vec, lt->key, k, t, 0);
+ }
+ else {
+ cp_key(a, a+1, tot, (char *)lt->def->vec, lt->key, k[2], NULL, 0);
+ }
+ }
+ }
+ else {
+ ctime= bsystem_time(NULL, (float)G.scene->r.cfra, 0.0);
+
+ if(lt->key->type==KEY_RELATIVE) {
+ KeyBlock *kb;
+
+ for(kb= lt->key->block.first; kb; kb= kb->next)
+ kb->weights= get_weights_array(ob, kb->vgroup);
+
+ do_rel_key(0, tot, tot, (char *)lt->def->vec, lt->key, 0);
+
+ for(kb= lt->key->block.first; kb; kb= kb->next) {
+ if(kb->weights) MEM_freeN(kb->weights);
+ kb->weights= NULL;
+ }
+ }
+ else {
+ if(calc_ipo_spec(lt->key->ipo, KEY_SPEED, &ctime)==0) {
+ ctime /= 100.0;
+ CLAMP(ctime, 0.0, 1.0);
+ }
+
+ flag= setkeys(ctime, &lt->key->block, k, t, 0);
+ if(flag==0) {
+ do_key(0, tot, tot, (char *)lt->def->vec, lt->key, k, t, 0);
+ }
+ else {
+ cp_key(0, tot, tot, (char *)lt->def->vec, lt->key, k[2], NULL, 0);
+ }
+ }
+ }
+
+ if(lt->flag & LT_OUTSIDE) outside_lattice(lt);
+
+ return 1;
+}
+
+/* returns 1 when key applied */
+int do_ob_key(Object *ob)
+{
+ Key *key= ob_get_key(ob);
+
+ if(key==NULL)
+ return 0;
+
+ if(ob->shapeflag & (OB_SHAPE_LOCK|OB_SHAPE_TEMPLOCK)) {
+ KeyBlock *kb= BLI_findlink(&key->block, ob->shapenr-1);
+
+ if(kb==NULL) {
+ kb= key->block.first;
+ ob->shapenr= 1;
+ }
+
+ if(ob->type==OB_MESH) {
+ Mesh *me= ob->data;
+ float *weights= get_weights_array(ob, kb->vgroup);
+
+ cp_key(0, me->totvert, me->totvert, (char *)me->mvert->co, key, kb, weights, 0);
+
+ if(weights) MEM_freeN(weights);
+ }
+ else if(ob->type==OB_LATTICE) {
+ Lattice *lt= ob->data;
+ float *weights= get_weights_array(ob, kb->vgroup);
+ int tot= lt->pntsu*lt->pntsv*lt->pntsw;
+
+ cp_key(0, tot, tot, (char *)lt->def->vec, key, kb, weights, 0);
+
+ if(weights) MEM_freeN(weights);
+ }
+ else if ELEM(ob->type, OB_CURVE, OB_SURF) {
+ Curve *cu= ob->data;
+ int tot= count_curveverts(&cu->nurb);
+
+ cp_cu_key(cu, kb, 0, tot);
+ }
+ return 1;
+ }
+ else {
+ if(ob->ipoflag & OB_ACTION_KEY)
+ do_all_object_actions(ob);
+ else {
+ calc_ipo(key->ipo, bsystem_time(ob, G.scene->r.cfra, 0.0));
+ execute_ipo((ID *)key, key->ipo);
+ }
+
+ if(ob->type==OB_MESH) return do_mesh_key(ob, ob->data);
+ else if(ob->type==OB_CURVE) return do_curve_key( ob->data);
+ else if(ob->type==OB_SURF) return do_curve_key( ob->data);
+ else if(ob->type==OB_LATTICE) return do_latt_key(ob, ob->data);
+ }
+
+ return 0;
+}
+
+Key *ob_get_key(Object *ob)
+{
+ if(ob==NULL) return NULL;
+
+ if(ob->type==OB_MESH) {
+ Mesh *me= ob->data;
+ return me->key;
+ }
+ else if ELEM(ob->type, OB_CURVE, OB_SURF) {
+ Curve *cu= ob->data;
+ return cu->key;
+ }
+ else if(ob->type==OB_LATTICE) {
+ Lattice *lt= ob->data;
+ return lt->key;
+ }
+ return NULL;
+}
+
+/* only the active keyblock */
+KeyBlock *ob_get_keyblock(Object *ob)
+{
+ Key *key= ob_get_key(ob);
+
+ if (key) {
+ KeyBlock *kb= BLI_findlink(&key->block, ob->shapenr-1);
+ return kb;
+ }
+
+ return NULL;
+}
+
+/* get the appropriate KeyBlock given an index */
+KeyBlock *key_get_keyblock(Key *key, int index)
+{
+ KeyBlock *kb;
+ int i;
+
+ if (key) {
+ kb= key->block.first;
+
+ for (i= 1; i < key->totkey; i++) {
+ kb= kb->next;
+
+ if (index==i)
+ return kb;
+ }
+ }
+
+ return NULL;
+}
diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c
new file mode 100644
index 00000000000..64c081c27a6
--- /dev/null
+++ b/source/blender/blenkernel/intern/lattice.c
@@ -0,0 +1,915 @@
+/**
+ * lattice.c
+ *
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "DNA_armature_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_key_types.h"
+
+#include "BKE_anim.h"
+#include "BKE_armature.h"
+#include "BKE_curve.h"
+#include "BKE_cdderivedmesh.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_deform.h"
+#include "BKE_displist.h"
+#include "BKE_global.h"
+#include "BKE_ipo.h"
+#include "BKE_key.h"
+#include "BKE_lattice.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+#include "BKE_screen.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_editdeform.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "blendef.h"
+
+Lattice *editLatt=0;
+static Lattice *deformLatt=0;
+
+static float *latticedata=0, latmat[4][4];
+
+void calc_lat_fudu(int flag, int res, float *fu, float *du)
+{
+ if(res==1) {
+ *fu= 0.0;
+ *du= 0.0;
+ }
+ else if(flag & LT_GRID) {
+ *fu= -0.5f*(res-1);
+ *du= 1.0f;
+ }
+ else {
+ *fu= -1.0f;
+ *du= 2.0f/(res-1);
+ }
+}
+
+void resizelattice(Lattice *lt, int uNew, int vNew, int wNew, Object *ltOb)
+{
+ BPoint *bp;
+ int i, u, v, w;
+ float fu, fv, fw, uc, vc, wc, du=0.0, dv=0.0, dw=0.0;
+ float *co, (*vertexCos)[3] = NULL;
+
+ /* vertex weight groups are just freed all for now */
+ if(lt->dvert) {
+ free_dverts(lt->dvert, lt->pntsu*lt->pntsv*lt->pntsw);
+ lt->dvert= NULL;
+ }
+
+ while(uNew*vNew*wNew > 32000) {
+ if( uNew>=vNew && uNew>=wNew) uNew--;
+ else if( vNew>=uNew && vNew>=wNew) vNew--;
+ else wNew--;
+ }
+
+ vertexCos = MEM_mallocN(sizeof(*vertexCos)*uNew*vNew*wNew, "tmp_vcos");
+
+ calc_lat_fudu(lt->flag, uNew, &fu, &du);
+ calc_lat_fudu(lt->flag, vNew, &fv, &dv);
+ calc_lat_fudu(lt->flag, wNew, &fw, &dw);
+
+ /* If old size is different then resolution changed in interface,
+ * try to do clever reinit of points. Pretty simply idea, we just
+ * deform new verts by old lattice, but scaling them to match old
+ * size first.
+ */
+ if (ltOb) {
+ if (uNew!=1 && lt->pntsu!=1) {
+ fu = lt->fu;
+ du = (lt->pntsu-1)*lt->du/(uNew-1);
+ }
+
+ if (vNew!=1 && lt->pntsv!=1) {
+ fv = lt->fv;
+ dv = (lt->pntsv-1)*lt->dv/(vNew-1);
+ }
+
+ if (wNew!=1 && lt->pntsw!=1) {
+ fw = lt->fw;
+ dw = (lt->pntsw-1)*lt->dw/(wNew-1);
+ }
+ }
+
+ co = vertexCos[0];
+ for(w=0,wc=fw; w<wNew; w++,wc+=dw) {
+ for(v=0,vc=fv; v<vNew; v++,vc+=dv) {
+ for(u=0,uc=fu; u<uNew; u++,co+=3,uc+=du) {
+ co[0] = uc;
+ co[1] = vc;
+ co[2] = wc;
+ }
+ }
+ }
+
+ if (ltOb) {
+ float mat[4][4];
+ int typeu = lt->typeu, typev = lt->typev, typew = lt->typew;
+
+ /* works best if we force to linear type (endpoints match) */
+ lt->typeu = lt->typev = lt->typew = KEY_LINEAR;
+
+ /* prevent using deformed locations */
+ freedisplist(&ltOb->disp);
+
+ Mat4CpyMat4(mat, ltOb->obmat);
+ Mat4One(ltOb->obmat);
+ lattice_deform_verts(ltOb, NULL, NULL, vertexCos, uNew*vNew*wNew, NULL);
+ Mat4CpyMat4(ltOb->obmat, mat);
+
+ lt->typeu = typeu;
+ lt->typev = typev;
+ lt->typew = typew;
+ }
+
+ lt->fu = fu;
+ lt->fv = fv;
+ lt->fw = fw;
+ lt->du = du;
+ lt->dv = dv;
+ lt->dw = dw;
+
+ lt->pntsu = uNew;
+ lt->pntsv = vNew;
+ lt->pntsw = wNew;
+
+ MEM_freeN(lt->def);
+ lt->def= MEM_callocN(lt->pntsu*lt->pntsv*lt->pntsw*sizeof(BPoint), "lattice bp");
+
+ bp= lt->def;
+
+ for (i=0; i<lt->pntsu*lt->pntsv*lt->pntsw; i++,bp++) {
+ VECCOPY(bp->vec, vertexCos[i]);
+ }
+
+ MEM_freeN(vertexCos);
+}
+
+Lattice *add_lattice(char *name)
+{
+ Lattice *lt;
+
+ lt= alloc_libblock(&G.main->latt, ID_LT, name);
+
+ lt->flag= LT_GRID;
+
+ lt->typeu= lt->typev= lt->typew= KEY_BSPLINE;
+
+ lt->def= MEM_callocN(sizeof(BPoint), "lattvert"); /* temporary */
+ resizelattice(lt, 2, 2, 2, NULL); /* creates a uniform lattice */
+
+ return lt;
+}
+
+Lattice *copy_lattice(Lattice *lt)
+{
+ Lattice *ltn;
+
+ ltn= copy_libblock(lt);
+ ltn->def= MEM_dupallocN(lt->def);
+
+ id_us_plus((ID *)ltn->ipo);
+
+ ltn->key= copy_key(ltn->key);
+ if(ltn->key) ltn->key->from= (ID *)ltn;
+
+ if(lt->dvert) {
+ int tot= lt->pntsu*lt->pntsv*lt->pntsw;
+ ltn->dvert = MEM_mallocN (sizeof (MDeformVert)*tot, "Lattice MDeformVert");
+ copy_dverts(ltn->dvert, lt->dvert, tot);
+ }
+
+ return ltn;
+}
+
+void free_lattice(Lattice *lt)
+{
+ if(lt->def) MEM_freeN(lt->def);
+ if(lt->dvert) free_dverts(lt->dvert, lt->pntsu*lt->pntsv*lt->pntsw);
+}
+
+
+void make_local_lattice(Lattice *lt)
+{
+ Object *ob;
+ Lattice *ltn;
+ int local=0, lib=0;
+
+ /* - only lib users: do nothing
+ * - only local users: set flag
+ * - mixed: make copy
+ */
+
+ if(lt->id.lib==0) return;
+ if(lt->id.us==1) {
+ lt->id.lib= 0;
+ lt->id.flag= LIB_LOCAL;
+ new_id(0, (ID *)lt, 0);
+ return;
+ }
+
+ ob= G.main->object.first;
+ while(ob) {
+ if(ob->data==lt) {
+ if(ob->id.lib) lib= 1;
+ else local= 1;
+ }
+ ob= ob->id.next;
+ }
+
+ if(local && lib==0) {
+ lt->id.lib= 0;
+ lt->id.flag= LIB_LOCAL;
+ new_id(0, (ID *)lt, 0);
+ }
+ else if(local && lib) {
+ ltn= copy_lattice(lt);
+ ltn->id.us= 0;
+
+ ob= G.main->object.first;
+ while(ob) {
+ if(ob->data==lt) {
+
+ if(ob->id.lib==0) {
+ ob->data= ltn;
+ ltn->id.us++;
+ lt->id.us--;
+ }
+ }
+ ob= ob->id.next;
+ }
+ }
+}
+
+void init_latt_deform(Object *oblatt, Object *ob)
+{
+ /* we make an array with all differences */
+ Lattice *lt = deformLatt = (oblatt==G.obedit)?editLatt:oblatt->data;
+ BPoint *bp = lt->def;
+ DispList *dl = find_displist(&oblatt->disp, DL_VERTS);
+ float *co = dl?dl->verts:NULL;
+ float *fp, imat[4][4];
+ float fu, fv, fw;
+ int u, v, w;
+
+ fp= latticedata= MEM_mallocN(sizeof(float)*3*deformLatt->pntsu*deformLatt->pntsv*deformLatt->pntsw, "latticedata");
+
+ /* for example with a particle system: ob==0 */
+ if(ob==0) {
+ /* in deformspace, calc matrix */
+ Mat4Invert(latmat, oblatt->obmat);
+
+ /* back: put in deform array */
+ Mat4Invert(imat, latmat);
+ }
+ else {
+ /* in deformspace, calc matrix */
+ Mat4Invert(imat, oblatt->obmat);
+ Mat4MulMat4(latmat, ob->obmat, imat);
+
+ /* back: put in deform array */
+ Mat4Invert(imat, latmat);
+ }
+
+ for(w=0,fw=lt->fw; w<lt->pntsw; w++,fw+=lt->dw) {
+ for(v=0,fv=lt->fv; v<lt->pntsv; v++, fv+=lt->dv) {
+ for(u=0,fu=lt->fu; u<lt->pntsu; u++, bp++, co+=3, fp+=3, fu+=lt->du) {
+ if (dl) {
+ fp[0] = co[0] - fu;
+ fp[1] = co[1] - fv;
+ fp[2] = co[2] - fw;
+ } else {
+ fp[0] = bp->vec[0] - fu;
+ fp[1] = bp->vec[1] - fv;
+ fp[2] = bp->vec[2] - fw;
+ }
+
+ Mat4Mul3Vecfl(imat, fp);
+ }
+ }
+ }
+}
+
+void calc_latt_deform(float *co, float weight)
+{
+ Lattice *lt;
+ float u, v, w, tu[4], tv[4], tw[4];
+ float *fpw, *fpv, *fpu, vec[3];
+ int ui, vi, wi, uu, vv, ww;
+
+ if(latticedata==0) return;
+
+ lt= deformLatt; /* just for shorter notation! */
+
+ /* co is in local coords, treat with latmat */
+
+ VECCOPY(vec, co);
+ Mat4MulVecfl(latmat, vec);
+
+ /* u v w coords */
+
+ if(lt->pntsu>1) {
+ u= (vec[0]-lt->fu)/lt->du;
+ ui= (int)floor(u);
+ u -= ui;
+ set_four_ipo(u, tu, lt->typeu);
+ }
+ else {
+ tu[0]= tu[2]= tu[3]= 0.0; tu[1]= 1.0;
+ ui= 0;
+ }
+
+ if(lt->pntsv>1) {
+ v= (vec[1]-lt->fv)/lt->dv;
+ vi= (int)floor(v);
+ v -= vi;
+ set_four_ipo(v, tv, lt->typev);
+ }
+ else {
+ tv[0]= tv[2]= tv[3]= 0.0; tv[1]= 1.0;
+ vi= 0;
+ }
+
+ if(lt->pntsw>1) {
+ w= (vec[2]-lt->fw)/lt->dw;
+ wi= (int)floor(w);
+ w -= wi;
+ set_four_ipo(w, tw, lt->typew);
+ }
+ else {
+ tw[0]= tw[2]= tw[3]= 0.0; tw[1]= 1.0;
+ wi= 0;
+ }
+
+ for(ww= wi-1; ww<=wi+2; ww++) {
+ w= tw[ww-wi+1];
+
+ if(w!=0.0) {
+ if(ww>0) {
+ if(ww<lt->pntsw) fpw= latticedata + 3*ww*lt->pntsu*lt->pntsv;
+ else fpw= latticedata + 3*(lt->pntsw-1)*lt->pntsu*lt->pntsv;
+ }
+ else fpw= latticedata;
+
+ for(vv= vi-1; vv<=vi+2; vv++) {
+ v= w*tv[vv-vi+1];
+
+ if(v!=0.0) {
+ if(vv>0) {
+ if(vv<lt->pntsv) fpv= fpw + 3*vv*lt->pntsu;
+ else fpv= fpw + 3*(lt->pntsv-1)*lt->pntsu;
+ }
+ else fpv= fpw;
+
+ for(uu= ui-1; uu<=ui+2; uu++) {
+ u= weight*v*tu[uu-ui+1];
+
+ if(u!=0.0) {
+ if(uu>0) {
+ if(uu<lt->pntsu) fpu= fpv + 3*uu;
+ else fpu= fpv + 3*(lt->pntsu-1);
+ }
+ else fpu= fpv;
+
+ co[0]+= u*fpu[0];
+ co[1]+= u*fpu[1];
+ co[2]+= u*fpu[2];
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void end_latt_deform()
+{
+
+ MEM_freeN(latticedata);
+ latticedata= 0;
+}
+
+ /* calculations is in local space of deformed object
+ so we store in latmat transform from path coord inside object
+ */
+typedef struct {
+ float dmin[3], dmax[3], dsize, dloc[3];
+ float curvespace[4][4], objectspace[4][4], objectspace3[3][3];
+ int no_rot_axis;
+} CurveDeform;
+
+static void init_curve_deform(Object *par, Object *ob, CurveDeform *cd, int dloc)
+{
+ Mat4Invert(ob->imat, ob->obmat);
+ Mat4MulMat4(cd->objectspace, par->obmat, ob->imat);
+ Mat4Invert(cd->curvespace, cd->objectspace);
+ Mat3CpyMat4(cd->objectspace3, cd->objectspace);
+
+ // offset vector for 'no smear'
+ if(dloc) {
+ Mat4Invert(par->imat, par->obmat);
+ VecMat4MulVecfl(cd->dloc, par->imat, ob->obmat[3]);
+ }
+ else cd->dloc[0]=cd->dloc[1]=cd->dloc[2]= 0.0f;
+
+ cd->no_rot_axis= 0;
+}
+
+/* this makes sure we can extend for non-cyclic. *vec needs 4 items! */
+static int where_on_path_deform(Object *ob, float ctime, float *vec, float *dir) /* returns OK */
+{
+ Curve *cu= ob->data;
+ BevList *bl;
+ float ctime1;
+ int cycl=0;
+
+ /* test for cyclic */
+ bl= cu->bev.first;
+ if(bl && bl->poly> -1) cycl= 1;
+
+ if(cycl==0) {
+ ctime1= CLAMPIS(ctime, 0.0, 1.0);
+ }
+ else ctime1= ctime;
+
+ /* vec needs 4 items */
+ if(where_on_path(ob, ctime1, vec, dir)) {
+
+ if(cycl==0) {
+ Path *path= cu->path;
+ float dvec[3];
+
+ if(ctime < 0.0) {
+ VecSubf(dvec, path->data+4, path->data);
+ VecMulf(dvec, ctime*(float)path->len);
+ VECADD(vec, vec, dvec);
+ }
+ else if(ctime > 1.0) {
+ VecSubf(dvec, path->data+4*path->len-4, path->data+4*path->len-8);
+ VecMulf(dvec, (ctime-1.0)*(float)path->len);
+ VECADD(vec, vec, dvec);
+ }
+ }
+ return 1;
+ }
+ return 0;
+}
+
+ /* for each point, rotate & translate to curve */
+ /* use path, since it has constant distances */
+ /* co: local coord, result local too */
+ /* returns quaternion for rotation, using cd->no_rot_axis */
+ /* axis is using another define!!! */
+static float *calc_curve_deform(Object *par, float *co, short axis, CurveDeform *cd)
+{
+ Curve *cu= par->data;
+ float fac, loc[4], dir[3], cent[3];
+ short upflag, index;
+
+ if(axis==MOD_CURVE_POSX || axis==MOD_CURVE_NEGX) {
+ upflag= OB_POSZ;
+ cent[0]= 0.0;
+ cent[1]= co[1];
+ cent[2]= co[2];
+ index= 0;
+ }
+ else if(axis==MOD_CURVE_POSY || axis==MOD_CURVE_NEGY) {
+ upflag= OB_POSZ;
+ cent[0]= co[0];
+ cent[1]= 0.0;
+ cent[2]= co[2];
+ index= 1;
+ }
+ else {
+ upflag= OB_POSY;
+ cent[0]= co[0];
+ cent[1]= co[1];
+ cent[2]= 0.0;
+ index= 2;
+ }
+ /* to be sure, mostly after file load */
+ if(cu->path==NULL) {
+ makeDispListCurveTypes(par, 0);
+ if(cu->path==NULL) return NULL; // happens on append...
+ }
+
+ /* options */
+ if(ELEM3(axis, OB_NEGX, OB_NEGY, OB_NEGZ)) {
+ if(cu->flag & CU_STRETCH)
+ fac= (-co[index]-cd->dmax[index])/(cd->dmax[index] - cd->dmin[index]);
+ else
+ fac= (cd->dloc[index])/(cu->path->totdist) - (co[index]-cd->dmax[index])/(cu->path->totdist);
+ }
+ else {
+ if(cu->flag & CU_STRETCH)
+ fac= (co[index]-cd->dmin[index])/(cd->dmax[index] - cd->dmin[index]);
+ else
+ fac= (cd->dloc[index])/(cu->path->totdist) + (co[index]-cd->dmin[index])/(cu->path->totdist);
+ }
+
+ /* we want the ipo to work on the default 100 frame range, because there's no
+ actual time involved in path position */
+ if(cu->ipo) {
+ fac*= 100.0f;
+ if(calc_ipo_spec(cu->ipo, CU_SPEED, &fac)==0)
+ fac/= 100.0;
+ }
+
+ if( where_on_path_deform(par, fac, loc, dir)) { /* returns OK */
+ float q[4], mat[3][3];
+ float *quat;
+
+ if(cd->no_rot_axis) /* set by caller */
+ dir[cd->no_rot_axis-1]= 0.0f;
+
+ /* -1 for compatibility with old track defines */
+ quat= vectoquat(dir, axis-1, upflag); /* gives static quat */
+
+ /* the tilt */
+ if(loc[3]!=0.0) {
+ Normalize(dir);
+ q[0]= (float)cos(0.5*loc[3]);
+ fac= (float)sin(0.5*loc[3]);
+ q[1]= -fac*dir[0];
+ q[2]= -fac*dir[1];
+ q[3]= -fac*dir[2];
+ QuatMul(quat, q, quat);
+ }
+ QuatToMat3(quat, mat);
+
+ /* local rotation */
+ Mat3MulVecfl(mat, cent);
+
+ /* translation */
+ VECADD(co, cent, loc);
+
+ return quat;
+ }
+ return NULL;
+}
+
+void curve_deform_verts(Object *cuOb, Object *target, DerivedMesh *dm, float (*vertexCos)[3], int numVerts, char *vgroup, short defaxis)
+{
+ Curve *cu = cuOb->data;
+ int a, flag = cu->flag;
+ CurveDeform cd;
+ int use_vgroups;
+
+ cu->flag |= (CU_PATH|CU_FOLLOW); // needed for path & bevlist
+
+ init_curve_deform(cuOb, target, &cd, (cu->flag & CU_STRETCH)==0);
+
+ /* check whether to use vertex groups (only possible if target is a Mesh)
+ * we want either a Mesh with no derived data, or derived data with
+ * deformverts
+ */
+ if(target && target->type==OB_MESH) {
+ /* if there's derived data without deformverts, don't use vgroups */
+ if(dm && !dm->getVertData(dm, 0, CD_MDEFORMVERT))
+ use_vgroups = 0;
+ else
+ use_vgroups = 1;
+ } else
+ use_vgroups = 0;
+
+ if(vgroup && vgroup[0] && use_vgroups) {
+ bDeformGroup *curdef;
+ Mesh *me= target->data;
+ int index;
+
+ /* find the group (weak loop-in-loop) */
+ for(index = 0, curdef = target->defbase.first; curdef;
+ curdef = curdef->next, index++)
+ if (!strcmp(curdef->name, vgroup))
+ break;
+
+ if(curdef && (me->dvert || dm)) {
+ MDeformVert *dvert = me->dvert;
+ float vec[3];
+ int j;
+
+ INIT_MINMAX(cd.dmin, cd.dmax);
+
+ for(a = 0; a < numVerts; a++, dvert++) {
+ if(dm) dvert = dm->getVertData(dm, a, CD_MDEFORMVERT);
+
+ for(j = 0; j < dvert->totweight; j++) {
+ if(dvert->dw[j].def_nr == index) {
+ Mat4MulVecfl(cd.curvespace, vertexCos[a]);
+ DO_MINMAX(vertexCos[a], cd.dmin, cd.dmax);
+ break;
+ }
+ }
+ }
+
+ dvert = me->dvert;
+ for(a = 0; a < numVerts; a++, dvert++) {
+ if(dm) dvert = dm->getVertData(dm, a, CD_MDEFORMVERT);
+
+ for(j = 0; j < dvert->totweight; j++) {
+ if(dvert->dw[j].def_nr == index) {
+ VECCOPY(vec, vertexCos[a]);
+ calc_curve_deform(cuOb, vec, defaxis, &cd);
+ VecLerpf(vertexCos[a], vertexCos[a], vec,
+ dvert->dw[j].weight);
+ Mat4MulVecfl(cd.objectspace, vertexCos[a]);
+ break;
+ }
+ }
+ }
+ }
+ } else {
+ INIT_MINMAX(cd.dmin, cd.dmax);
+
+ for(a = 0; a < numVerts; a++) {
+ Mat4MulVecfl(cd.curvespace, vertexCos[a]);
+ DO_MINMAX(vertexCos[a], cd.dmin, cd.dmax);
+ }
+
+ for(a = 0; a < numVerts; a++) {
+ calc_curve_deform(cuOb, vertexCos[a], defaxis, &cd);
+ Mat4MulVecfl(cd.objectspace, vertexCos[a]);
+ }
+ }
+ cu->flag = flag;
+}
+
+/* input vec and orco = local coord in armature space */
+/* orco is original not-animated or deformed reference point */
+/* result written in vec and mat */
+void curve_deform_vector(Object *cuOb, Object *target, float *orco, float *vec, float mat[][3], int no_rot_axis)
+{
+ CurveDeform cd;
+ float *quat;
+
+ init_curve_deform(cuOb, target, &cd, 0); /* 0 no dloc */
+ cd.no_rot_axis= no_rot_axis; /* option to only rotate for XY, for example */
+
+ VECCOPY(cd.dmin, orco);
+ VECCOPY(cd.dmax, orco);
+
+ Mat4MulVecfl(cd.curvespace, vec);
+
+ quat= calc_curve_deform(cuOb, vec, target->trackflag+1, &cd);
+ if(quat) {
+ float qmat[3][3];
+
+ QuatToMat3(quat, qmat);
+ Mat3MulMat3(mat, qmat, cd.objectspace3);
+ }
+ else
+ Mat3One(mat);
+
+ Mat4MulVecfl(cd.objectspace, vec);
+
+}
+
+void lattice_deform_verts(Object *laOb, Object *target, DerivedMesh *dm,
+ float (*vertexCos)[3], int numVerts, char *vgroup)
+{
+ int a;
+ int use_vgroups;
+
+ init_latt_deform(laOb, target);
+
+ /* check whether to use vertex groups (only possible if target is a Mesh)
+ * we want either a Mesh with no derived data, or derived data with
+ * deformverts
+ */
+ if(target && target->type==OB_MESH) {
+ /* if there's derived data without deformverts, don't use vgroups */
+ if(dm && !dm->getVertData(dm, 0, CD_MDEFORMVERT))
+ use_vgroups = 0;
+ else
+ use_vgroups = 1;
+ } else
+ use_vgroups = 0;
+
+ if(vgroup && vgroup[0] && use_vgroups) {
+ bDeformGroup *curdef;
+ Mesh *me = target->data;
+ int index = 0;
+
+ /* find the group (weak loop-in-loop) */
+ for(curdef = target->defbase.first; curdef;
+ curdef = curdef->next, index++)
+ if(!strcmp(curdef->name, vgroup)) break;
+
+ if(curdef && (me->dvert || dm)) {
+ MDeformVert *dvert = me->dvert;
+ int j;
+
+ for(a = 0; a < numVerts; a++, dvert++) {
+ if(dm) dvert = dm->getVertData(dm, a, CD_MDEFORMVERT);
+ for(j = 0; j < dvert->totweight; j++) {
+ if (dvert->dw[j].def_nr == index) {
+ calc_latt_deform(vertexCos[a], dvert->dw[j].weight);
+ }
+ }
+ }
+ }
+ } else {
+ for(a = 0; a < numVerts; a++) {
+ calc_latt_deform(vertexCos[a], 1.0f);
+ }
+ }
+ end_latt_deform();
+}
+
+int object_deform_mball(Object *ob)
+{
+ if(ob->parent && ob->parent->type==OB_LATTICE && ob->partype==PARSKEL) {
+ DispList *dl;
+
+ for (dl=ob->disp.first; dl; dl=dl->next) {
+ lattice_deform_verts(ob->parent, ob, NULL,
+ (float(*)[3]) dl->verts, dl->nr, NULL);
+ }
+
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static BPoint *latt_bp(Lattice *lt, int u, int v, int w)
+{
+ return lt->def+ u + v*lt->pntsu + w*lt->pntsu*lt->pntsv;
+}
+
+void outside_lattice(Lattice *lt)
+{
+ BPoint *bp, *bp1, *bp2;
+ int u, v, w;
+ float fac1, du=0.0, dv=0.0, dw=0.0;
+
+ bp= lt->def;
+
+ if(lt->pntsu>1) du= 1.0f/((float)lt->pntsu-1);
+ if(lt->pntsv>1) dv= 1.0f/((float)lt->pntsv-1);
+ if(lt->pntsw>1) dw= 1.0f/((float)lt->pntsw-1);
+
+ for(w=0; w<lt->pntsw; w++) {
+
+ for(v=0; v<lt->pntsv; v++) {
+
+ for(u=0; u<lt->pntsu; u++, bp++) {
+ if(u==0 || v==0 || w==0 || u==lt->pntsu-1 || v==lt->pntsv-1 || w==lt->pntsw-1);
+ else {
+
+ bp->hide= 1;
+ bp->f1 &= ~SELECT;
+
+ /* u extrema */
+ bp1= latt_bp(lt, 0, v, w);
+ bp2= latt_bp(lt, lt->pntsu-1, v, w);
+
+ fac1= du*u;
+ bp->vec[0]= (1.0f-fac1)*bp1->vec[0] + fac1*bp2->vec[0];
+ bp->vec[1]= (1.0f-fac1)*bp1->vec[1] + fac1*bp2->vec[1];
+ bp->vec[2]= (1.0f-fac1)*bp1->vec[2] + fac1*bp2->vec[2];
+
+ /* v extrema */
+ bp1= latt_bp(lt, u, 0, w);
+ bp2= latt_bp(lt, u, lt->pntsv-1, w);
+
+ fac1= dv*v;
+ bp->vec[0]+= (1.0f-fac1)*bp1->vec[0] + fac1*bp2->vec[0];
+ bp->vec[1]+= (1.0f-fac1)*bp1->vec[1] + fac1*bp2->vec[1];
+ bp->vec[2]+= (1.0f-fac1)*bp1->vec[2] + fac1*bp2->vec[2];
+
+ /* w extrema */
+ bp1= latt_bp(lt, u, v, 0);
+ bp2= latt_bp(lt, u, v, lt->pntsw-1);
+
+ fac1= dw*w;
+ bp->vec[0]+= (1.0f-fac1)*bp1->vec[0] + fac1*bp2->vec[0];
+ bp->vec[1]+= (1.0f-fac1)*bp1->vec[1] + fac1*bp2->vec[1];
+ bp->vec[2]+= (1.0f-fac1)*bp1->vec[2] + fac1*bp2->vec[2];
+
+ VecMulf(bp->vec, 0.3333333f);
+
+ }
+ }
+
+ }
+
+ }
+
+}
+
+float (*lattice_getVertexCos(struct Object *ob, int *numVerts_r))[3]
+{
+ Lattice *lt = (G.obedit==ob)?editLatt:ob->data;
+ int i, numVerts = *numVerts_r = lt->pntsu*lt->pntsv*lt->pntsw;
+ float (*vertexCos)[3] = MEM_mallocN(sizeof(*vertexCos)*numVerts,"lt_vcos");
+
+ for (i=0; i<numVerts; i++) {
+ VECCOPY(vertexCos[i], lt->def[i].vec);
+ }
+
+ return vertexCos;
+}
+
+void lattice_applyVertexCos(struct Object *ob, float (*vertexCos)[3])
+{
+ Lattice *lt = ob->data;
+ int i, numVerts = lt->pntsu*lt->pntsv*lt->pntsw;
+
+ for (i=0; i<numVerts; i++) {
+ VECCOPY(lt->def[i].vec, vertexCos[i]);
+ }
+}
+
+void lattice_calc_modifiers(Object *ob)
+{
+ float (*vertexCos)[3] = NULL;
+ ModifierData *md = modifiers_getVirtualModifierList(ob);
+ int numVerts, editmode = G.obedit==ob;
+
+ freedisplist(&ob->disp);
+
+ if (!editmode) {
+ do_ob_key(ob);
+ }
+
+ for (; md; md=md->next) {
+ ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ if (!(md->mode&eModifierMode_Realtime)) continue;
+ if (editmode && !(md->mode&eModifierMode_Editmode)) continue;
+ if (mti->isDisabled && mti->isDisabled(md)) continue;
+ if (mti->type!=eModifierTypeType_OnlyDeform) continue;
+
+ if (!vertexCos) vertexCos = lattice_getVertexCos(ob, &numVerts);
+ mti->deformVerts(md, ob, NULL, vertexCos, numVerts);
+ }
+
+ if (vertexCos) {
+ DispList *dl = MEM_callocN(sizeof(*dl), "lt_dl");
+ dl->type = DL_VERTS;
+ dl->parts = 1;
+ dl->nr = numVerts;
+ dl->verts = (float*) vertexCos;
+
+ BLI_addtail(&ob->disp, dl);
+ }
+}
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
new file mode 100644
index 00000000000..28a6aad7b4d
--- /dev/null
+++ b/source/blender/blenkernel/intern/library.c
@@ -0,0 +1,1098 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/*
+ * Contains management of ID's and libraries
+ * allocate and free of all library data
+ *
+ */
+
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+/* all types are needed here, in order to do memory operations */
+#include "DNA_ID.h"
+#include "DNA_listBase.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_material_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_image_types.h"
+#include "DNA_wave_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_key_types.h"
+#include "DNA_world_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_vfont_types.h"
+#include "DNA_text_types.h"
+#include "DNA_sound_types.h"
+#include "DNA_group_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_action_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_node_types.h"
+#include "DNA_nla_types.h"
+#include "DNA_effect_types.h"
+#include "DNA_brush_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_dynstr.h"
+
+#include "BKE_bad_level_calls.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_global.h"
+#include "BKE_sound.h"
+#include "BKE_object.h"
+#include "BKE_screen.h"
+#include "BKE_script.h"
+#include "BKE_mesh.h"
+#include "BKE_material.h"
+#include "BKE_curve.h"
+#include "BKE_mball.h"
+#include "BKE_text.h"
+#include "BKE_texture.h"
+#include "BKE_scene.h"
+#include "BKE_icons.h"
+#include "BKE_image.h"
+#include "BKE_ipo.h"
+#include "BKE_key.h"
+#include "BKE_world.h"
+#include "BKE_font.h"
+#include "BKE_group.h"
+#include "BKE_lattice.h"
+#include "BKE_armature.h"
+#include "BKE_action.h"
+#include "BKE_node.h"
+#include "BKE_effect.h"
+#include "BKE_brush.h"
+#include "BKE_idprop.h"
+
+#include "BPI_script.h"
+
+#define MAX_IDPUP 60 /* was 24 */
+
+/* ************* general ************************ */
+
+void id_lib_extern(ID *id)
+{
+ if(id) {
+ if(id->flag & LIB_INDIRECT) {
+ id->flag -= LIB_INDIRECT;
+ id->flag |= LIB_EXTERN;
+ }
+ }
+}
+
+void id_us_plus(ID *id)
+{
+ if(id) {
+ id->us++;
+ if(id->flag & LIB_INDIRECT) {
+ id->flag -= LIB_INDIRECT;
+ id->flag |= LIB_EXTERN;
+ }
+ }
+}
+
+ListBase *wich_libbase(Main *mainlib, short type)
+{
+ switch( type ) {
+ case ID_SCE:
+ return &(mainlib->scene);
+ case ID_LI:
+ return &(mainlib->library);
+ case ID_OB:
+ return &(mainlib->object);
+ case ID_ME:
+ return &(mainlib->mesh);
+ case ID_CU:
+ return &(mainlib->curve);
+ case ID_MB:
+ return &(mainlib->mball);
+ case ID_MA:
+ return &(mainlib->mat);
+ case ID_TE:
+ return &(mainlib->tex);
+ case ID_IM:
+ return &(mainlib->image);
+ case ID_WV:
+ return &(mainlib->wave);
+ case ID_LT:
+ return &(mainlib->latt);
+ case ID_LA:
+ return &(mainlib->lamp);
+ case ID_CA:
+ return &(mainlib->camera);
+ case ID_IP:
+ return &(mainlib->ipo);
+ case ID_KE:
+ return &(mainlib->key);
+ case ID_WO:
+ return &(mainlib->world);
+ case ID_SCR:
+ return &(mainlib->screen);
+ case ID_VF:
+ return &(mainlib->vfont);
+ case ID_TXT:
+ return &(mainlib->text);
+ case ID_SCRIPT:
+ return &(mainlib->script);
+ case ID_SO:
+ return &(mainlib->sound);
+ case ID_GR:
+ return &(mainlib->group);
+ case ID_AR:
+ return &(mainlib->armature);
+ case ID_AC:
+ return &(mainlib->action);
+ case ID_NT:
+ return &(mainlib->nodetree);
+ case ID_BR:
+ return &(mainlib->brush);
+ }
+ return 0;
+}
+
+/* Flag all ids in listbase */
+void flag_listbase_ids(ListBase *lb, short flag, short value)
+{
+ ID *id;
+ if (value) {
+ for(id= lb->first; id; id= id->next) id->flag |= flag;
+ } else {
+ flag = ~flag;
+ for(id= lb->first; id; id= id->next) id->flag &= flag;
+ }
+}
+
+/* Flag all ids in listbase */
+void flag_all_listbases_ids(short flag, short value)
+{
+ ListBase *lbarray[MAX_LIBARRAY];
+ int a;
+ a= set_listbasepointers(G.main, lbarray);
+ while(a--) flag_listbase_ids(lbarray[a], flag, value);
+}
+
+
+/* note: MAX_LIBARRAY define should match this code */
+int set_listbasepointers(Main *main, ListBase **lb)
+{
+ /* BACKWARDS! also watch order of free-ing! (mesh<->mat) */
+
+ lb[0]= &(main->ipo);
+ lb[1]= &(main->key);
+ lb[2]= &(main->image);
+ lb[3]= &(main->tex);
+ lb[4]= &(main->mat);
+ lb[5]= &(main->vfont);
+
+ /* Important!: When adding a new object type,
+ * the specific data should be inserted here
+ */
+
+ lb[6]= &(main->armature);
+ lb[7]= &(main->action);
+
+ lb[8]= &(main->mesh);
+ lb[9]= &(main->curve);
+ lb[10]= &(main->mball);
+
+ lb[11]= &(main->wave);
+ lb[12]= &(main->latt);
+ lb[13]= &(main->lamp);
+ lb[14]= &(main->camera);
+
+ lb[15]= &(main->text);
+ lb[16]= &(main->sound);
+ lb[17]= &(main->group);
+ lb[18]= &(main->nodetree);
+ lb[19]= &(main->brush);
+ lb[20]= &(main->script);
+
+ lb[21]= &(main->world);
+ lb[22]= &(main->screen);
+ lb[23]= &(main->object);
+ lb[24]= &(main->scene);
+ lb[25]= &(main->library);
+
+ lb[26]= NULL;
+
+ return 26;
+}
+
+/* *********** ALLOC AND FREE *****************
+
+free_libblock(ListBase *lb, ID *id )
+ provide a list-basis and datablock, but only ID is read
+
+void *alloc_libblock(ListBase *lb, type, name)
+ inserts in list and returns a new ID
+
+ ***************************** */
+
+static ID *alloc_libblock_notest(short type)
+{
+ ID *id= NULL;
+
+ switch( type ) {
+ case ID_SCE:
+ id= MEM_callocN(sizeof(Scene), "scene");
+ break;
+ case ID_LI:
+ id= MEM_callocN(sizeof(Library), "library");
+ break;
+ case ID_OB:
+ id= MEM_callocN(sizeof(Object), "object");
+ break;
+ case ID_ME:
+ id= MEM_callocN(sizeof(Mesh), "mesh");
+ break;
+ case ID_CU:
+ id= MEM_callocN(sizeof(Curve), "curve");
+ break;
+ case ID_MB:
+ id= MEM_callocN(sizeof(MetaBall), "mball");
+ break;
+ case ID_MA:
+ id= MEM_callocN(sizeof(Material), "mat");
+ break;
+ case ID_TE:
+ id= MEM_callocN(sizeof(Tex), "tex");
+ break;
+ case ID_IM:
+ id= MEM_callocN(sizeof(Image), "image");
+ break;
+ case ID_WV:
+ id= MEM_callocN(sizeof(Wave), "wave");
+ break;
+ case ID_LT:
+ id= MEM_callocN(sizeof(Lattice), "latt");
+ break;
+ case ID_LA:
+ id= MEM_callocN(sizeof(Lamp), "lamp");
+ break;
+ case ID_CA:
+ id= MEM_callocN(sizeof(Camera), "camera");
+ break;
+ case ID_IP:
+ id= MEM_callocN(sizeof(Ipo), "ipo");
+ break;
+ case ID_KE:
+ id= MEM_callocN(sizeof(Key), "key");
+ break;
+ case ID_WO:
+ id= MEM_callocN(sizeof(World), "world");
+ break;
+ case ID_SCR:
+ id= MEM_callocN(sizeof(bScreen), "screen");
+ break;
+ case ID_VF:
+ id= MEM_callocN(sizeof(VFont), "vfont");
+ break;
+ case ID_TXT:
+ id= MEM_callocN(sizeof(Text), "text");
+ break;
+ case ID_SCRIPT:
+ id= MEM_callocN(sizeof(Script), "script");
+ break;
+ case ID_SO:
+ id= MEM_callocN(sizeof(bSound), "sound");
+ break;
+ case ID_GR:
+ id= MEM_callocN(sizeof(Group), "group");
+ break;
+ case ID_AR:
+ id = MEM_callocN(sizeof(bArmature), "armature");
+ break;
+ case ID_AC:
+ id = MEM_callocN(sizeof(bAction), "action");
+ break;
+ case ID_NT:
+ id = MEM_callocN(sizeof(bNodeTree), "nodetree");
+ break;
+ case ID_BR:
+ id = MEM_callocN(sizeof(Brush), "brush");
+ break;
+ }
+ return id;
+}
+
+/* used everywhere in blenkernel and text.c */
+void *alloc_libblock(ListBase *lb, short type, const char *name)
+{
+ ID *id= NULL;
+
+ id= alloc_libblock_notest(type);
+ if(id) {
+ BLI_addtail(lb, id);
+ id->us= 1;
+ id->icon_id = 0;
+ *( (short *)id->name )= type;
+ new_id(lb, id, name);
+ /* alphabetic insterion: is in new_id */
+ }
+ return id;
+}
+
+/* GS reads the memory pointed at in a specific ordering.
+ only use this definition, makes little and big endian systems
+ work fine, in conjunction with MAKE_ID */
+
+/* from blendef: */
+#define GS(a) (*((short *)(a)))
+
+/* used everywhere in blenkernel and text.c */
+void *copy_libblock(void *rt)
+{
+ ID *idn, *id;
+ ListBase *lb;
+ char *cp, *cpn;
+ int idn_len;
+
+ id= rt;
+
+ lb= wich_libbase(G.main, GS(id->name));
+ idn= alloc_libblock(lb, GS(id->name), id->name+2);
+
+ idn_len= MEM_allocN_len(idn);
+ if(idn_len - sizeof(ID) > 0) {
+ cp= (char *)id;
+ cpn= (char *)idn;
+ memcpy(cpn+sizeof(ID), cp+sizeof(ID), idn_len - sizeof(ID));
+ }
+
+ id->newid= idn;
+ idn->flag |= LIB_NEW;
+ if (id->properties) idn->properties = IDP_CopyProperty(id->properties);
+
+ return idn;
+}
+
+static void free_library(Library *lib)
+{
+ /* no freeing needed for libraries yet */
+}
+
+/* used in headerbuttons.c image.c mesh.c screen.c sound.c and library.c */
+void free_libblock(ListBase *lb, void *idv)
+{
+ ID *id= idv;
+
+ switch( GS(id->name) ) { /* GetShort from util.h */
+ case ID_SCE:
+ free_scene((Scene *)id);
+ break;
+ case ID_LI:
+ free_library((Library *)id);
+ break;
+ case ID_OB:
+ free_object((Object *)id);
+ break;
+ case ID_ME:
+ free_mesh((Mesh *)id);
+ break;
+ case ID_CU:
+ free_curve((Curve *)id);
+ break;
+ case ID_MB:
+ free_mball((MetaBall *)id);
+ break;
+ case ID_MA:
+ free_material((Material *)id);
+ break;
+ case ID_TE:
+ free_texture((Tex *)id);
+ break;
+ case ID_IM:
+ free_image((Image *)id);
+ break;
+ case ID_WV:
+ /* free_wave(id); */
+ break;
+ case ID_LT:
+ free_lattice((Lattice *)id);
+ break;
+ case ID_LA:
+ free_lamp((Lamp *)id);
+ break;
+ case ID_CA:
+ free_camera((Camera*) id);
+ break;
+ case ID_IP:
+ free_ipo((Ipo *)id);
+ break;
+ case ID_KE:
+ free_key((Key *)id);
+ break;
+ case ID_WO:
+ free_world((World *)id);
+ break;
+ case ID_SCR:
+ free_screen((bScreen *)id);
+ break;
+ case ID_VF:
+ free_vfont((VFont *)id);
+ break;
+ case ID_TXT:
+ free_text((Text *)id);
+ break;
+ case ID_SCRIPT:
+ free_script((Script *)id);
+ break;
+ case ID_SO:
+ sound_free_sound((bSound *)id);
+ break;
+ case ID_GR:
+ free_group((Group *)id);
+ break;
+ case ID_AR:
+ free_armature((bArmature *)id);
+ break;
+ case ID_AC:
+ free_action((bAction *)id);
+ break;
+ case ID_NT:
+ ntreeFreeTree((bNodeTree *)id);
+ break;
+ case ID_BR:
+ free_brush((Brush *)id);
+ break;
+ }
+
+ if (id->properties) {
+ IDP_FreeProperty(id->properties);
+ MEM_freeN(id->properties);
+ }
+ BLI_remlink(lb, id);
+ MEM_freeN(id);
+
+}
+
+void free_libblock_us(ListBase *lb, void *idv) /* test users */
+{
+ ID *id= idv;
+
+ id->us--;
+
+ if(id->us<0) {
+ if(id->lib) printf("ERROR block %s %s users %d\n", id->lib->name, id->name, id->us);
+ else printf("ERROR block %s users %d\n", id->name, id->us);
+ }
+ if(id->us==0) {
+ if( GS(id->name)==ID_OB ) unlink_object((Object *)id);
+
+ free_libblock(lb, id);
+ }
+}
+
+
+void free_main(Main *mainvar)
+{
+ /* also call when reading a file, erase all, etc */
+ ListBase *lbarray[MAX_LIBARRAY];
+ int a;
+
+ a= set_listbasepointers(mainvar, lbarray);
+ while(a--) {
+ ListBase *lb= lbarray[a];
+ ID *id;
+
+ while ( (id= lb->first) ) {
+ free_libblock(lb, id);
+ }
+ }
+
+ MEM_freeN(mainvar);
+}
+
+/* ***************** ID ************************ */
+
+
+ID *find_id(char *type, char *name) /* type: "OB" or "MA" etc */
+{
+ ID *id;
+ ListBase *lb;
+
+ lb= wich_libbase(G.main, GS(type));
+
+ id= lb->first;
+ while(id) {
+ if(id->name[2]==name[0] && strcmp(id->name+2, name)==0 )
+ return id;
+ id= id->next;
+ }
+ return 0;
+}
+
+static void get_flags_for_id(ID *id, char *buf)
+{
+ int isfake= id->flag & LIB_FAKEUSER;
+ int isnode=0;
+ /* Writeout the flags for the entry, note there
+ * is a small hack that writes 5 spaces instead
+ * of 4 if no flags are displayed... this makes
+ * things usually line up ok - better would be
+ * to have that explicit, oh well - zr
+ */
+
+ if(GS(id->name)==ID_MA)
+ isnode= ((Material *)id)->use_nodes;
+
+ if (id->us<0)
+ sprintf(buf, "-1W ");
+ else if (!id->lib && !isfake && id->us && !isnode)
+ sprintf(buf, " ");
+ else if(isnode)
+ sprintf(buf, "%c%cN%c ", id->lib?'L':' ', isfake?'F':' ', (id->us==0)?'O':' ');
+ else
+ sprintf(buf, "%c%c%c ", id->lib?'L':' ', isfake?'F':' ', (id->us==0)?'O':' ');
+}
+
+#define IDPUP_NO_VIEWER 1
+
+static void IDnames_to_dyn_pupstring(DynStr *pupds, ListBase *lb, ID *link, short *nr, int hideflag)
+{
+ int i, nids= BLI_countlist(lb);
+
+ if (nr) *nr= -1;
+
+ if (nr && nids>MAX_IDPUP) {
+ BLI_dynstr_append(pupds, "DataBrowse %x-2");
+ *nr= -2;
+ } else {
+ ID *id;
+
+ for (i=0, id= lb->first; id; id= id->next, i++) {
+ char buf[32];
+
+ if (nr && id==link) *nr= i+1;
+
+ if (U.uiflag & USER_HIDE_DOT && id->name[2]=='.')
+ continue;
+ if (hideflag & IDPUP_NO_VIEWER)
+ if (GS(id->name)==ID_IM)
+ if ( ((Image *)id)->source==IMA_SRC_VIEWER )
+ continue;
+
+ get_flags_for_id(id, buf);
+
+ BLI_dynstr_append(pupds, buf);
+ BLI_dynstr_append(pupds, id->name+2);
+ sprintf(buf, "%%x%d", i+1);
+ BLI_dynstr_append(pupds, buf);
+
+ /* icon */
+ switch(GS(id->name))
+ {
+ case ID_MA: /* fall through */
+ case ID_TE: /* fall through */
+ case ID_IM: /* fall through */
+ case ID_WO: /* fall through */
+ case ID_LA: /* fall through */
+ sprintf(buf, "%%i%d", BKE_icon_getid(id) );
+ BLI_dynstr_append(pupds, buf);
+ break;
+ default:
+ break;
+ }
+
+ if(id->next)
+ BLI_dynstr_append(pupds, "|");
+ }
+ }
+}
+
+ /* Silly routine, the only difference between the one
+ * above is that it only adds items with a matching
+ * blocktype... this should be unified somehow... - zr
+ */
+static void IPOnames_to_dyn_pupstring(DynStr *pupds, ListBase *lb, ID *link, short *nr, int blocktype)
+{
+ ID *id;
+ int i, nids;
+
+ for (id= lb->first, nids= 0; id; id= id->next) {
+ Ipo *ipo= (Ipo*) id;
+
+ if (ipo->blocktype==blocktype)
+ nids++;
+ }
+
+ if (nids>MAX_IDPUP) {
+ BLI_dynstr_append(pupds, "DataBrowse %x-2");
+ } else {
+ for (i=0, id= lb->first; id; id= id->next) {
+ Ipo *ipo= (Ipo*) id;
+
+ if (ipo->blocktype==blocktype) {
+ char buf[32];
+
+ if (id==link)
+ *nr= i+1;
+
+ if (U.uiflag & USER_HIDE_DOT && id->name[2]=='.')
+ continue;
+
+ get_flags_for_id(id, buf);
+
+ BLI_dynstr_append(pupds, buf);
+ BLI_dynstr_append(pupds, id->name+2);
+ sprintf(buf, "%%x%d", i+1);
+ BLI_dynstr_append(pupds, buf);
+
+ if(id->next)
+ BLI_dynstr_append(pupds, "|");
+
+ i++;
+ }
+ }
+ }
+}
+
+/* used by headerbuttons.c buttons.c editobject.c editseq.c */
+/* if nr==NULL no MAX_IDPUP, this for non-header browsing */
+void IDnames_to_pupstring(char **str, char *title, char *extraops, ListBase *lb, ID *link, short *nr)
+{
+ DynStr *pupds= BLI_dynstr_new();
+
+ if (title) {
+ BLI_dynstr_append(pupds, title);
+ BLI_dynstr_append(pupds, "%t|");
+ }
+
+ if (extraops) {
+ BLI_dynstr_append(pupds, extraops);
+ if (BLI_dynstr_get_len(pupds))
+ BLI_dynstr_append(pupds, "|");
+ }
+
+ IDnames_to_dyn_pupstring(pupds, lb, link, nr, 0);
+
+ *str= BLI_dynstr_get_cstring(pupds);
+ BLI_dynstr_free(pupds);
+}
+
+/* skips viewer images */
+void IMAnames_to_pupstring(char **str, char *title, char *extraops, ListBase *lb, ID *link, short *nr)
+{
+ DynStr *pupds= BLI_dynstr_new();
+
+ if (title) {
+ BLI_dynstr_append(pupds, title);
+ BLI_dynstr_append(pupds, "%t|");
+ }
+
+ if (extraops) {
+ BLI_dynstr_append(pupds, extraops);
+ if (BLI_dynstr_get_len(pupds))
+ BLI_dynstr_append(pupds, "|");
+ }
+
+ IDnames_to_dyn_pupstring(pupds, lb, link, nr, IDPUP_NO_VIEWER);
+
+ *str= BLI_dynstr_get_cstring(pupds);
+ BLI_dynstr_free(pupds);
+}
+
+
+/* only used by headerbuttons.c */
+void IPOnames_to_pupstring(char **str, char *title, char *extraops, ListBase *lb, ID *link, short *nr, int blocktype)
+{
+ DynStr *pupds= BLI_dynstr_new();
+
+ if (title) {
+ BLI_dynstr_append(pupds, title);
+ BLI_dynstr_append(pupds, "%t|");
+ }
+
+ if (extraops) {
+ BLI_dynstr_append(pupds, extraops);
+ if (BLI_dynstr_get_len(pupds))
+ BLI_dynstr_append(pupds, "|");
+ }
+
+ IPOnames_to_dyn_pupstring(pupds, lb, link, nr, blocktype);
+
+ *str= BLI_dynstr_get_cstring(pupds);
+ BLI_dynstr_free(pupds);
+}
+
+/* used by buttons.c library.c mball.c */
+void splitIDname(char *name, char *left, int *nr)
+{
+ int a;
+
+ *nr= 0;
+ strncpy(left, name, 21);
+
+ a= strlen(name);
+ if(a>1 && name[a-1]=='.') return;
+
+ while(a--) {
+ if( name[a]=='.' ) {
+ left[a]= 0;
+ *nr= atol(name+a+1);
+ return;
+ }
+ if( isdigit(name[a])==0 ) break;
+
+ left[a]= 0;
+ }
+ strcpy(left, name);
+}
+
+static void sort_alpha_id(ListBase *lb, ID *id)
+{
+ ID *idtest;
+
+ /* insert alphabetically */
+ if(lb->first!=lb->last) {
+ BLI_remlink(lb, id);
+
+ idtest= lb->first;
+ while(idtest) {
+ if(BLI_strcasecmp(idtest->name, id->name)>0 || idtest->lib) {
+ BLI_insertlinkbefore(lb, idtest, id);
+ break;
+ }
+ idtest= idtest->next;
+ }
+ /* as last */
+ if(idtest==0) {
+ BLI_addtail(lb, id);
+ }
+ }
+
+}
+
+/*
+ * Check to see if an ID name is already used, and find a new one if so.
+ * Return 1 if created a new name (returned in name).
+ *
+ * Normally the ID that's being check is already in the ListBase, so ID *id
+ * points at the new entry. The Python Library module needs to know what
+ * the name of a datablock will be before it is appended; in this case ID *id
+ * id is NULL;
+ */
+
+int check_for_dupid(ListBase *lb, ID *id, char *name)
+{
+ ID *idtest;
+ int nr= 0, nrtest, a;
+ const int maxtest=32;
+ char left[32], leftest[32], in_use[32];
+
+ /* make sure input name is terminated properly */
+ if( strlen(name) > 21 ) name[21]= 0;
+
+ while (1) {
+
+ /* phase 1: id already exists? */
+ for( idtest = lb->first; idtest; idtest = idtest->next ) {
+ /* if idtest is not a lib */
+ if( id != idtest && idtest->lib == NULL ) {
+ /* do not test alphabetic! */
+ /* optimized */
+ if( idtest->name[2] == name[0] ) {
+ if(strcmp(name, idtest->name+2)==0) break;
+ }
+ }
+ }
+
+ /* if there is no double, done */
+ if( idtest == NULL ) return 0;
+
+ /* we have a dup; need to make a new name */
+ /* quick check so we can reuse one of first 32 ids if vacant */
+ memset(in_use, 0, maxtest);
+
+ /* get name portion, number portion ("name.number") */
+ splitIDname( name, left, &nr);
+
+ /* if new name will be too long, truncate it */
+ if(nr>999 && strlen(left)>16) left[16]= 0;
+ else if(strlen(left)>17) left[17]= 0;
+
+ for( idtest = lb->first; idtest; idtest = idtest->next ) {
+ if( id != idtest && idtest->lib == NULL ) {
+ splitIDname(idtest->name+2, leftest, &nrtest);
+ /* if base names match... */
+ /* optimized */
+ if( *left == *leftest && strcmp(left, leftest)==0 ) {
+ if(nrtest < maxtest)
+ in_use[nrtest]= 1; /* mark as used */
+ if(nr <= nrtest)
+ nr= nrtest+1; /* track largest unused */
+ }
+ }
+ }
+
+ /* decide which value of nr to use */
+ for(a=0; a<maxtest; a++) {
+ if(a>=nr) break; /* stop when we've check up to biggest */
+ if( in_use[a]==0 ) { /* found an unused value */
+ nr = a;
+ break;
+ }
+ }
+
+ /* if non-numbered name was not in use, reuse it */
+ if(nr==0) strcpy( name, left );
+ else {
+ if(nr > 999 && strlen(left) > 16) {
+ /* this would overflow name buffer */
+ left[16] = 0;
+ strcpy( name, left );
+ continue;
+ }
+ /* this format specifier is from hell... */
+ sprintf(name, "%s.%.3d", left, nr);
+ }
+ return 1;
+ }
+}
+
+/*
+ * Only for local blocks: external en indirect blocks already have a
+ * unique ID.
+ *
+ * return 1: created a new name
+ */
+
+int new_id(ListBase *lb, ID *id, const char *tname)
+{
+ int result;
+ char name[22];
+
+ /* if library, don't rename */
+ if(id->lib) return 0;
+
+ /* if no libdata given, look up based on ID */
+ if(lb==NULL) lb= wich_libbase(G.main, GS(id->name));
+
+ if(tname==0) { /* if no name given, use name of current ID */
+ strncpy(name, id->name+2, 21);
+ result= strlen(id->name+2);
+ }
+ else { /* else make a copy (tname args can be const) */
+ strncpy(name, tname, 21);
+ result= strlen(tname);
+ }
+
+ /* if result > 21, strncpy don't put the final '\0' to name. */
+ if( result > 21 ) name[21]= 0;
+
+ result = check_for_dupid( lb, id, name );
+ strcpy( id->name+2, name );
+
+ /* This was in 2.43 and previous releases
+ * however all data in blender should be sorted, not just duplicate names
+ * sorting should not hurt, but noting just incause it alters the way other
+ * functions work, so sort every time */
+ /* if( result )
+ sort_alpha_id(lb, id);*/
+
+ sort_alpha_id(lb, id);
+
+ return result;
+}
+
+/* next to indirect usage in read/writefile also in editobject.c scene.c */
+void clear_id_newpoins()
+{
+ ListBase *lbarray[MAX_LIBARRAY];
+ ID *id;
+ int a;
+
+ a= set_listbasepointers(G.main, lbarray);
+ while(a--) {
+ id= lbarray[a]->first;
+ while(id) {
+ id->newid= 0;
+ id->flag &= ~LIB_NEW;
+ id= id->next;
+ }
+ }
+}
+
+/* only for library fixes */
+static void image_fix_relative_path(Image *ima)
+{
+ if(ima->id.lib==NULL) return;
+ if(strncmp(ima->name, "//", 2)==0) {
+ BLI_convertstringcode(ima->name, ima->id.lib->filename, 0);
+ BLI_makestringcode(G.sce, ima->name);
+ }
+}
+
+#define LIBTAG(a) if(a && a->id.lib) {a->id.flag &=~LIB_INDIRECT; a->id.flag |= LIB_EXTERN;}
+
+static void lib_indirect_test_id(ID *id)
+{
+
+ if(id->lib)
+ return;
+
+ if(GS(id->name)==ID_OB) {
+ Object *ob= (Object *)id;
+ bActionStrip *strip;
+ Mesh *me;
+ PartEff *paf;
+ int a;
+
+ for (strip=ob->nlastrips.first; strip; strip=strip->next){
+ LIBTAG(strip->object);
+ LIBTAG(strip->act);
+ LIBTAG(strip->ipo);
+ }
+
+ for(a=0; a<ob->totcol; a++) {
+ LIBTAG(ob->mat[a]);
+ }
+
+ paf = give_parteff(ob);
+ if (paf)
+ LIBTAG(paf->group);
+
+ LIBTAG(ob->dup_group);
+ LIBTAG(ob->proxy);
+
+ me= ob->data;
+ LIBTAG(me);
+ }
+}
+
+
+/* if lib!=NULL, only all from lib local */
+void all_local(Library *lib, int untagged_only)
+{
+ ListBase *lbarray[MAX_LIBARRAY], tempbase={0, 0};
+ ID *id, *idn;
+ int a;
+
+ a= set_listbasepointers(G.main, lbarray);
+ while(a--) {
+ id= lbarray[a]->first;
+
+ while(id) {
+ id->newid= NULL;
+ idn= id->next; /* id is possibly being inserted again */
+
+ /* The check on the second line (LIB_APPEND_TAG) is done so its
+ * possible to tag data you dont want to be made local, used for
+ * appending data, so any libdata alredy linked wont become local
+ * (very nasty to discover all your links are lost after appending)
+ * */
+ if(id->flag & (LIB_EXTERN|LIB_INDIRECT|LIB_NEW) &&
+ (untagged_only==0 || !(id->flag & LIB_APPEND_TAG)))
+ {
+ if(lib==NULL || id->lib==lib) {
+ id->flag &= ~(LIB_EXTERN|LIB_INDIRECT|LIB_NEW);
+
+ if(id->lib) {
+ /* relative file patch */
+ if(GS(id->name)==ID_IM)
+ image_fix_relative_path((Image *)id);
+
+ id->lib= NULL;
+ new_id(lbarray[a], id, 0); /* new_id only does it with double names */
+ sort_alpha_id(lbarray[a], id);
+ }
+ }
+ }
+ id= idn;
+ }
+
+ /* patch2: make it aphabetically */
+ while( (id=tempbase.first) ) {
+ BLI_remlink(&tempbase, id);
+ BLI_addtail(lbarray[a], id);
+ new_id(lbarray[a], id, 0);
+ }
+ }
+
+ /* patch 3: make sure library data isn't indirect falsely... */
+ a= set_listbasepointers(G.main, lbarray);
+ while(a--) {
+ for(id= lbarray[a]->first; id; id=id->next)
+ lib_indirect_test_id(id);
+ }
+}
+
+
+void test_idbutton(char *name)
+{
+ /* called from buttons: when name already exists: call new_id */
+ ListBase *lb;
+ ID *idtest;
+
+
+ lb= wich_libbase(G.main, GS(name-2) );
+ if(lb==0) return;
+
+ /* search for id */
+ idtest= lb->first;
+ while(idtest) {
+ if( strcmp(idtest->name+2, name)==0) break;
+ idtest= idtest->next;
+ }
+
+ if(idtest) if( new_id(lb, idtest, name)==0 ) sort_alpha_id(lb, idtest);
+}
+
+void rename_id(ID *id, char *name)
+{
+ ListBase *lb;
+
+ strncpy(id->name+2, name, 21);
+ lb= wich_libbase(G.main, GS(id->name) );
+
+ new_id(lb, id, name);
+}
+
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
new file mode 100644
index 00000000000..49d3021090e
--- /dev/null
+++ b/source/blender/blenkernel/intern/material.c
@@ -0,0 +1,1110 @@
+
+/* material.c
+ *
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <string.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_curve_types.h"
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_texture_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "BKE_bad_level_calls.h"
+#include "BKE_blender.h"
+#include "BKE_displist.h"
+#include "BKE_global.h"
+#include "BKE_icons.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_mesh.h"
+#include "BKE_node.h"
+#include "BKE_utildefines.h"
+
+#include "BPY_extern.h"
+
+/* used in UI and render */
+Material defmaterial;
+
+/* called on startup, creator.c */
+void init_def_material(void)
+{
+ init_material(&defmaterial);
+}
+
+/* not material itself */
+void free_material(Material *ma)
+{
+ MTex *mtex;
+ int a;
+
+ BPY_free_scriptlink(&ma->scriptlink);
+
+ for(a=0; a<MAX_MTEX; a++) {
+ mtex= ma->mtex[a];
+ if(mtex && mtex->tex) mtex->tex->id.us--;
+ if(mtex) MEM_freeN(mtex);
+ }
+
+ if(ma->ramp_col) MEM_freeN(ma->ramp_col);
+ if(ma->ramp_spec) MEM_freeN(ma->ramp_spec);
+
+ BKE_previewimg_free(&ma->preview);
+ BKE_icon_delete((struct ID*)ma);
+ ma->id.icon_id = 0;
+
+ /* is no lib link block, but material extension */
+ if(ma->nodetree) {
+ ntreeFreeTree(ma->nodetree);
+ MEM_freeN(ma->nodetree);
+ }
+}
+
+void init_material(Material *ma)
+{
+ ma->r= ma->g= ma->b= ma->ref= 0.8;
+ ma->specr= ma->specg= ma->specb= 1.0;
+ ma->mirr= ma->mirg= ma->mirb= 1.0;
+ ma->spectra= 1.0;
+ ma->amb= 0.5;
+ ma->alpha= 1.0;
+ ma->spec= ma->hasize= 0.5;
+ ma->har= 50;
+ ma->starc= ma->ringc= 4;
+ ma->linec= 12;
+ ma->flarec= 1;
+ ma->flaresize= ma->subsize= 1.0;
+ ma->flareboost= 1;
+ ma->seed2= 6;
+ ma->friction= 0.5;
+ ma->refrac= 4.0;
+ ma->roughness= 0.5;
+ ma->param[0]= 0.5;
+ ma->param[1]= 0.1;
+ ma->param[2]= 0.5;
+ ma->param[3]= 0.1;
+ ma->rms= 0.1;
+ ma->darkness= 1.0;
+
+ ma->strand_sta= ma->strand_end= 1.0f;
+
+ ma->ang= 1.0;
+ ma->ray_depth= 2;
+ ma->ray_depth_tra= 2;
+ ma->fresnel_mir= 0.0;
+ ma->fresnel_tra= 0.0;
+ ma->fresnel_tra_i= 1.25;
+ ma->fresnel_mir_i= 1.25;
+ ma->tx_limit= 0.0;
+ ma->tx_falloff= 1.0;
+ ma->shad_alpha= 1.0f;
+
+ ma->gloss_mir = ma->gloss_tra= 1.0;
+ ma->samp_gloss_mir = ma->samp_gloss_tra= 18;
+ ma->adapt_thresh_mir = ma->adapt_thresh_tra = 0.005;
+ ma->dist_mir = 0.0;
+ ma->fadeto_mir = MA_RAYMIR_FADETOSKY;
+
+ ma->rampfac_col= 1.0;
+ ma->rampfac_spec= 1.0;
+ ma->pr_lamp= 3; /* two lamps, is bits */
+ ma->pr_type= MA_SPHERE;
+
+ ma->sss_radius[0]= 1.0f;
+ ma->sss_radius[1]= 1.0f;
+ ma->sss_radius[2]= 1.0f;
+ ma->sss_col[0]= 0.8f;
+ ma->sss_col[1]= 0.8f;
+ ma->sss_col[2]= 0.8f;
+ ma->sss_error= 0.05f;
+ ma->sss_scale= 0.1f;
+ ma->sss_ior= 1.3f;
+ ma->sss_colfac= 1.0f;
+ ma->sss_texfac= 0.0f;
+ ma->sss_front= 1.0f;
+ ma->sss_back= 1.0f;
+
+ ma->mode= MA_TRACEBLE|MA_SHADBUF|MA_SHADOW|MA_RADIO|MA_RAYBIAS|MA_TANGENT_STR;
+
+ ma->preview = NULL;
+}
+
+Material *add_material(char *name)
+{
+ Material *ma;
+
+ ma= alloc_libblock(&G.main->mat, ID_MA, name);
+
+ init_material(ma);
+
+ return ma;
+}
+
+Material *copy_material(Material *ma)
+{
+ Material *man;
+ int a;
+
+ man= copy_libblock(ma);
+
+ id_us_plus((ID *)man->ipo);
+ id_us_plus((ID *)man->group);
+
+
+ for(a=0; a<MAX_MTEX; a++) {
+ if(ma->mtex[a]) {
+ man->mtex[a]= MEM_mallocN(sizeof(MTex), "copymaterial");
+ memcpy(man->mtex[a], ma->mtex[a], sizeof(MTex));
+ id_us_plus((ID *)man->mtex[a]->tex);
+ }
+ }
+
+ BPY_copy_scriptlink(&ma->scriptlink);
+
+ if(ma->ramp_col) man->ramp_col= MEM_dupallocN(ma->ramp_col);
+ if(ma->ramp_spec) man->ramp_spec= MEM_dupallocN(ma->ramp_spec);
+
+ if (ma->preview) man->preview = BKE_previewimg_copy(ma->preview);
+
+ if(ma->nodetree) {
+ man->nodetree= ntreeCopyTree(ma->nodetree, 0); /* 0 == full new tree */
+ }
+
+ return man;
+}
+
+void make_local_material(Material *ma)
+{
+ Object *ob;
+ Mesh *me;
+ Curve *cu;
+ MetaBall *mb;
+ Material *man;
+ int a, local=0, lib=0;
+
+ /* - only lib users: do nothing
+ * - only local users: set flag
+ * - mixed: make copy
+ */
+
+ if(ma->id.lib==0) return;
+ if(ma->id.us==1) {
+ ma->id.lib= 0;
+ ma->id.flag= LIB_LOCAL;
+ new_id(0, (ID *)ma, 0);
+ for(a=0; a<MAX_MTEX; a++) {
+ if(ma->mtex[a]) id_lib_extern((ID *)ma->mtex[a]->tex);
+ }
+
+ return;
+ }
+
+ /* test objects */
+ ob= G.main->object.first;
+ while(ob) {
+ if(ob->mat) {
+ for(a=0; a<ob->totcol; a++) {
+ if(ob->mat[a]==ma) {
+ if(ob->id.lib) lib= 1;
+ else local= 1;
+ }
+ }
+ }
+ ob= ob->id.next;
+ }
+ /* test meshes */
+ me= G.main->mesh.first;
+ while(me) {
+ if(me->mat) {
+ for(a=0; a<me->totcol; a++) {
+ if(me->mat[a]==ma) {
+ if(me->id.lib) lib= 1;
+ else local= 1;
+ }
+ }
+ }
+ me= me->id.next;
+ }
+ /* test curves */
+ cu= G.main->curve.first;
+ while(cu) {
+ if(cu->mat) {
+ for(a=0; a<cu->totcol; a++) {
+ if(cu->mat[a]==ma) {
+ if(cu->id.lib) lib= 1;
+ else local= 1;
+ }
+ }
+ }
+ cu= cu->id.next;
+ }
+ /* test mballs */
+ mb= G.main->mball.first;
+ while(mb) {
+ if(mb->mat) {
+ for(a=0; a<mb->totcol; a++) {
+ if(mb->mat[a]==ma) {
+ if(mb->id.lib) lib= 1;
+ else local= 1;
+ }
+ }
+ }
+ mb= mb->id.next;
+ }
+
+ if(local && lib==0) {
+ ma->id.lib= 0;
+ ma->id.flag= LIB_LOCAL;
+
+ for(a=0; a<MAX_MTEX; a++) {
+ if(ma->mtex[a]) id_lib_extern((ID *)ma->mtex[a]->tex);
+ }
+
+ new_id(0, (ID *)ma, 0);
+ }
+ else if(local && lib) {
+
+ man= copy_material(ma);
+ man->id.us= 0;
+
+ /* do objects */
+ ob= G.main->object.first;
+ while(ob) {
+ if(ob->mat) {
+ for(a=0; a<ob->totcol; a++) {
+ if(ob->mat[a]==ma) {
+ if(ob->id.lib==0) {
+ ob->mat[a]= man;
+ man->id.us++;
+ ma->id.us--;
+ }
+ }
+ }
+ }
+ ob= ob->id.next;
+ }
+ /* do meshes */
+ me= G.main->mesh.first;
+ while(me) {
+ if(me->mat) {
+ for(a=0; a<me->totcol; a++) {
+ if(me->mat[a]==ma) {
+ if(me->id.lib==0) {
+ me->mat[a]= man;
+ man->id.us++;
+ ma->id.us--;
+ }
+ }
+ }
+ }
+ me= me->id.next;
+ }
+ /* do curves */
+ cu= G.main->curve.first;
+ while(cu) {
+ if(cu->mat) {
+ for(a=0; a<cu->totcol; a++) {
+ if(cu->mat[a]==ma) {
+ if(cu->id.lib==0) {
+ cu->mat[a]= man;
+ man->id.us++;
+ ma->id.us--;
+ }
+ }
+ }
+ }
+ cu= cu->id.next;
+ }
+ /* do mballs */
+ mb= G.main->mball.first;
+ while(mb) {
+ if(mb->mat) {
+ for(a=0; a<mb->totcol; a++) {
+ if(mb->mat[a]==ma) {
+ if(mb->id.lib==0) {
+ mb->mat[a]= man;
+ man->id.us++;
+ ma->id.us--;
+ }
+ }
+ }
+ }
+ mb= mb->id.next;
+ }
+ }
+}
+
+Material ***give_matarar(Object *ob)
+{
+ Mesh *me;
+ Curve *cu;
+ MetaBall *mb;
+
+ if(ob->type==OB_MESH) {
+ me= ob->data;
+ return &(me->mat);
+ }
+ else if ELEM3(ob->type, OB_CURVE, OB_FONT, OB_SURF) {
+ cu= ob->data;
+ return &(cu->mat);
+ }
+ else if(ob->type==OB_MBALL) {
+ mb= ob->data;
+ return &(mb->mat);
+ }
+ return NULL;
+}
+
+short *give_totcolp(Object *ob)
+{
+ Mesh *me;
+ Curve *cu;
+ MetaBall *mb;
+
+ if(ob->type==OB_MESH) {
+ me= ob->data;
+ return &(me->totcol);
+ }
+ else if ELEM3(ob->type, OB_CURVE, OB_FONT, OB_SURF) {
+ cu= ob->data;
+ return &(cu->totcol);
+ }
+ else if(ob->type==OB_MBALL) {
+ mb= ob->data;
+ return &(mb->totcol);
+ }
+ return NULL;
+}
+
+Material *give_current_material(Object *ob, int act)
+{
+ Material ***matarar, *ma;
+ short *totcolp;
+
+ if(ob==NULL) return NULL;
+
+ /* if object cannot have material, totcolp==NULL */
+ totcolp= give_totcolp(ob);
+ if(totcolp==NULL || ob->totcol==0) return NULL;
+
+ if(act>ob->totcol) act= ob->totcol;
+ else if(act<=0) act= 1;
+
+ if( BTST(ob->colbits, act-1) ) { /* in object */
+ ma= ob->mat[act-1];
+ }
+ else { /* in data */
+
+ /* check for inconsistancy */
+ if(*totcolp < ob->totcol)
+ ob->totcol= *totcolp;
+ if(act>ob->totcol) act= ob->totcol;
+
+ matarar= give_matarar(ob);
+
+ if(matarar && *matarar) ma= (*matarar)[act-1];
+ else ma= 0;
+
+ }
+
+ return ma;
+}
+
+ID *material_from(Object *ob, int act)
+{
+
+ if(ob==0) return 0;
+
+ if(ob->totcol==0) return ob->data;
+ if(act==0) act= 1;
+
+ if( BTST(ob->colbits, act-1) ) return (ID *)ob;
+ else return ob->data;
+}
+
+/* GS reads the memory pointed at in a specific ordering. There are,
+ * however two definitions for it. I have jotted them down here, both,
+ * but I think the first one is actually used. The thing is that
+ * big-endian systems might read this the wrong way round. OTOH, we
+ * constructed the IDs that are read out with this macro explicitly as
+ * well. I expect we'll sort it out soon... */
+
+/* from blendef: */
+#define GS(a) (*((short *)(a)))
+
+/* from misc_util: flip the bytes from x */
+/* #define GS(x) (((unsigned char *)(x))[0] << 8 | ((unsigned char *)(x))[1]) */
+
+void test_object_materials(ID *id)
+{
+ /* make the ob mat-array same size as 'ob->data' mat-array */
+ Object *ob;
+ Mesh *me;
+ Curve *cu;
+ MetaBall *mb;
+ Material **newmatar;
+ int totcol=0;
+
+ if(id==0) return;
+
+ if( GS(id->name)==ID_ME ) {
+ me= (Mesh *)id;
+ totcol= me->totcol;
+ }
+ else if( GS(id->name)==ID_CU ) {
+ cu= (Curve *)id;
+ totcol= cu->totcol;
+ }
+ else if( GS(id->name)==ID_MB ) {
+ mb= (MetaBall *)id;
+ totcol= mb->totcol;
+ }
+ else return;
+
+ ob= G.main->object.first;
+ while(ob) {
+
+ if(ob->data==id) {
+
+ if(totcol==0) {
+ if(ob->totcol) {
+ MEM_freeN(ob->mat);
+ ob->mat= 0;
+ }
+ }
+ else if(ob->totcol<totcol) {
+ newmatar= MEM_callocN(sizeof(void *)*totcol, "newmatar");
+ if(ob->totcol) {
+ memcpy(newmatar, ob->mat, sizeof(void *)*ob->totcol);
+ MEM_freeN(ob->mat);
+ }
+ ob->mat= newmatar;
+ }
+ ob->totcol= totcol;
+ if(ob->totcol && ob->actcol==0) ob->actcol= 1;
+ if(ob->actcol>ob->totcol) ob->actcol= ob->totcol;
+ }
+ ob= ob->id.next;
+ }
+}
+
+
+void assign_material(Object *ob, Material *ma, int act)
+{
+ Material *mao, **matar, ***matarar;
+ short *totcolp;
+
+ if(act>MAXMAT) return;
+ if(act<1) act= 1;
+
+ /* test arraylens */
+
+ totcolp= give_totcolp(ob);
+ matarar= give_matarar(ob);
+
+ if(totcolp==0 || matarar==0) return;
+
+ if( act > *totcolp) {
+ matar= MEM_callocN(sizeof(void *)*act, "matarray1");
+ if( *totcolp) {
+ memcpy(matar, *matarar, sizeof(void *)*( *totcolp ));
+ MEM_freeN(*matarar);
+ }
+ *matarar= matar;
+ *totcolp= act;
+ }
+
+ if(act > ob->totcol) {
+ matar= MEM_callocN(sizeof(void *)*act, "matarray2");
+ if( ob->totcol) {
+ memcpy(matar, ob->mat, sizeof(void *)*( ob->totcol ));
+ MEM_freeN(ob->mat);
+ }
+ ob->mat= matar;
+ ob->totcol= act;
+ }
+
+ /* do it */
+
+ if( BTST(ob->colbits, act-1) ) { /* in object */
+ mao= ob->mat[act-1];
+ if(mao) mao->id.us--;
+ ob->mat[act-1]= ma;
+ }
+ else { /* in data */
+ mao= (*matarar)[act-1];
+ if(mao) mao->id.us--;
+ (*matarar)[act-1]= ma;
+ }
+ id_us_plus((ID *)ma);
+ test_object_materials(ob->data);
+}
+
+void new_material_to_objectdata(Object *ob)
+{
+ Material *ma;
+
+ if(ob==0) return;
+ if(ob->totcol>=MAXMAT) return;
+
+ ma= give_current_material(ob, ob->actcol);
+ if(ma==NULL)
+ ma= add_material("Material");
+ else
+ ma= copy_material(ma);
+
+ ma->id.us= 0; /* eeh... */
+
+ if(ob->actcol) {
+ if( BTST(ob->colbits, ob->actcol-1) ) {
+ ob->colbits= BSET(ob->colbits, ob->totcol);
+ }
+ }
+
+ assign_material(ob, ma, ob->totcol+1);
+ ob->actcol= ob->totcol;
+}
+
+static void do_init_render_material(Material *ma, int r_mode, float *amb)
+{
+ MTex *mtex;
+ int a, needuv=0;
+
+ if(ma->flarec==0) ma->flarec= 1;
+
+ /* add all texcoflags from mtex */
+ ma->texco= 0;
+ ma->mapto= 0;
+ for(a=0; a<MAX_MTEX; a++) {
+
+ /* separate tex switching */
+ if(ma->septex & (1<<a)) continue;
+
+ mtex= ma->mtex[a];
+ if(mtex && mtex->tex && mtex->tex->type) {
+
+ ma->texco |= mtex->texco;
+ ma->mapto |= mtex->mapto;
+ if(r_mode & R_OSA) {
+ if ELEM3(mtex->tex->type, TEX_IMAGE, TEX_PLUGIN, TEX_ENVMAP) ma->texco |= TEXCO_OSA;
+ }
+
+ if(ma->texco & (TEXCO_ORCO|TEXCO_REFL|TEXCO_NORM|TEXCO_STRAND|TEXCO_STRESS)) needuv= 1;
+ else if(ma->texco & (TEXCO_GLOB|TEXCO_UV|TEXCO_OBJECT|TEXCO_SPEED)) needuv= 1;
+ else if(ma->texco & (TEXCO_LAVECTOR|TEXCO_VIEW|TEXCO_STICKY)) needuv= 1;
+ }
+ }
+
+ if(r_mode & R_RADIO)
+ if(ma->mode & MA_RADIO) needuv= 1;
+
+ if(ma->mode & (MA_VERTEXCOL|MA_VERTEXCOLP|MA_FACETEXTURE)) {
+ needuv= 1;
+ if(r_mode & R_OSA) ma->texco |= TEXCO_OSA; /* for texfaces */
+ }
+ if(needuv) ma->texco |= NEED_UV;
+
+ /* since the raytracer doesnt recalc O structs for each ray, we have to preset them all */
+ if(r_mode & R_RAYTRACE) {
+ if(ma->mode & (MA_RAYMIRROR|MA_RAYTRANSP|MA_SHADOW_TRA)) {
+ ma->texco |= NEED_UV|TEXCO_ORCO|TEXCO_REFL|TEXCO_NORM;
+ if(r_mode & R_OSA) ma->texco |= TEXCO_OSA;
+ }
+ }
+
+ if(amb) {
+ ma->ambr= ma->amb*amb[0];
+ ma->ambg= ma->amb*amb[1];
+ ma->ambb= ma->amb*amb[2];
+ }
+ /* will become or-ed result of all node modes */
+ ma->mode_l= ma->mode;
+ ma->mode_l &= ~MA_SHLESS;
+}
+
+static void init_render_nodetree(bNodeTree *ntree, Material *basemat, int r_mode, float *amb)
+{
+ bNode *node;
+
+ for(node=ntree->nodes.first; node; node= node->next) {
+ if(node->id) {
+ if(GS(node->id->name)==ID_MA) {
+ Material *ma= (Material *)node->id;
+ if(ma!=basemat) {
+ do_init_render_material(ma, r_mode, amb);
+ basemat->texco |= ma->texco;
+ basemat->mode_l |= ma->mode_l;
+ }
+ }
+ else if(node->type==NODE_GROUP)
+ init_render_nodetree((bNodeTree *)node->id, basemat, r_mode, amb);
+ }
+ }
+ /* parses the geom+tex nodes */
+ ntreeShaderGetTexcoMode(ntree, r_mode, &basemat->texco, &basemat->mode_l);
+}
+
+void init_render_material(Material *mat, int r_mode, float *amb)
+{
+
+ do_init_render_material(mat, r_mode, amb);
+
+ if(mat->nodetree && mat->use_nodes) {
+ init_render_nodetree(mat->nodetree, mat, r_mode, amb);
+
+ ntreeBeginExecTree(mat->nodetree); /* has internal flag to detect it only does it once */
+ }
+}
+
+void init_render_materials(int r_mode, float *amb)
+{
+ Material *ma;
+
+ /* two steps, first initialize, then or the flags for layers */
+ for(ma= G.main->mat.first; ma; ma= ma->id.next) {
+ /* is_used flag comes back in convertblender.c */
+ ma->flag &= ~MA_IS_USED;
+ if(ma->id.us)
+ init_render_material(ma, r_mode, amb);
+ }
+
+ do_init_render_material(&defmaterial, r_mode, amb);
+}
+
+/* only needed for nodes now */
+void end_render_material(Material *mat)
+{
+ if(mat && mat->nodetree && mat->use_nodes)
+ ntreeEndExecTree(mat->nodetree); /* has internal flag to detect it only does it once */
+}
+
+void end_render_materials(void)
+{
+ Material *ma;
+ for(ma= G.main->mat.first; ma; ma= ma->id.next)
+ if(ma->id.us)
+ end_render_material(ma);
+}
+
+static int material_in_nodetree(bNodeTree *ntree, Material *mat)
+{
+ bNode *node;
+
+ for(node=ntree->nodes.first; node; node= node->next) {
+ if(node->id && GS(node->id->name)==ID_MA) {
+ if(node->id==(ID*)mat)
+ return 1;
+ }
+ else if(node->type==NODE_GROUP)
+ if(material_in_nodetree((bNodeTree*)node->id, mat))
+ return 1;
+ }
+
+ return 0;
+}
+
+int material_in_material(Material *parmat, Material *mat)
+{
+ if(parmat==mat)
+ return 1;
+ else if(parmat->nodetree && parmat->use_nodes)
+ return material_in_nodetree(parmat->nodetree, mat);
+ else
+ return 0;
+}
+
+/* ****************** */
+
+char colname_array[125][20]= {
+"Black","DarkRed","HalfRed","Red","Red",
+"DarkGreen","DarkOlive","Brown","Chocolate","OrangeRed",
+"HalfGreen","GreenOlive","DryOlive","Goldenrod","DarkOrange",
+"LightGreen","Chartreuse","YellowGreen","Yellow","Gold",
+"Green","LawnGreen","GreenYellow","LightOlive","Yellow",
+"DarkBlue","DarkPurple","HotPink","VioletPink","RedPink",
+"SlateGray","DarkGrey","PalePurple","IndianRed","Tomato",
+"SeaGreen","PaleGreen","GreenKhaki","LightBrown","LightSalmon",
+"SpringGreen","PaleGreen","MediumOlive","YellowBrown","LightGold",
+"LightGreen","LightGreen","LightGreen","GreenYellow","PaleYellow",
+"HalfBlue","DarkSky","HalfMagenta","VioletRed","DeepPink",
+"SteelBlue","SkyBlue","Orchid","LightHotPink","HotPink",
+"SeaGreen","SlateGray","MediumGrey","Burlywood","LightPink",
+"SpringGreen","Aquamarine","PaleGreen","Khaki","PaleOrange",
+"SpringGreen","SeaGreen","PaleGreen","PaleWhite","YellowWhite",
+"LightBlue","Purple","MediumOrchid","Magenta","Magenta",
+"RoyalBlue","SlateBlue","MediumOrchid","Orchid","Magenta",
+"DeepSkyBlue","LightSteelBlue","LightSkyBlue","Violet","LightPink",
+"Cyan","DarkTurquoise","SkyBlue","Grey","Snow",
+"Mint","Mint","Aquamarine","MintCream","Ivory",
+"Blue","Blue","DarkMagenta","DarkOrchid","Magenta",
+"SkyBlue","RoyalBlue","LightSlateBlue","MediumOrchid","Magenta",
+"DodgerBlue","SteelBlue","MediumPurple","PalePurple","Plum",
+"DeepSkyBlue","PaleBlue","LightSkyBlue","PalePurple","Thistle",
+"Cyan","ColdBlue","PaleTurquoise","GhostWhite","White"
+};
+
+void automatname(Material *ma)
+{
+ int nr, r, g, b;
+ float ref;
+
+ if(ma==0) return;
+ if(ma->mode & MA_SHLESS) ref= 1.0;
+ else ref= ma->ref;
+
+ r= (int)(4.99*(ref*ma->r));
+ g= (int)(4.99*(ref*ma->g));
+ b= (int)(4.99*(ref*ma->b));
+ nr= r + 5*g + 25*b;
+ if(nr>124) nr= 124;
+ new_id(&G.main->mat, (ID *)ma, colname_array[nr]);
+
+}
+
+
+void delete_material_index()
+{
+ Material *mao, ***matarar;
+ Object *ob, *obt;
+ Curve *cu;
+ Nurb *nu;
+ short *totcolp;
+ int a, actcol;
+
+ if(G.obedit) {
+ error("Unable to perform function in EditMode");
+ return;
+ }
+ ob= ((G.scene->basact)? (G.scene->basact->object) : 0) ;
+ if(ob==0 || ob->totcol==0) return;
+
+ /* take a mesh/curve/mball as starting point, remove 1 index,
+ * AND with all objects that share the ob->data
+ *
+ * after that check indices in mesh/curve/mball!!!
+ */
+
+ totcolp= give_totcolp(ob);
+ matarar= give_matarar(ob);
+
+ /* we delete the actcol */
+ if(ob->totcol) {
+ mao= (*matarar)[ob->actcol-1];
+ if(mao) mao->id.us--;
+ }
+
+ for(a=ob->actcol; a<ob->totcol; a++) {
+ (*matarar)[a-1]= (*matarar)[a];
+ }
+ (*totcolp)--;
+
+ if(*totcolp==0) {
+ MEM_freeN(*matarar);
+ *matarar= 0;
+ }
+
+ actcol= ob->actcol;
+ obt= G.main->object.first;
+ while(obt) {
+
+ if(obt->data==ob->data) {
+
+ /* WATCH IT: do not use actcol from ob or from obt (can become zero) */
+ mao= obt->mat[actcol-1];
+ if(mao) mao->id.us--;
+
+ for(a=actcol; a<obt->totcol; a++) obt->mat[a-1]= obt->mat[a];
+ obt->totcol--;
+ if(obt->actcol > obt->totcol) obt->actcol= obt->totcol;
+
+ if(obt->totcol==0) {
+ MEM_freeN(obt->mat);
+ obt->mat= 0;
+ }
+ }
+ obt= obt->id.next;
+ }
+
+ /* check indices from mesh */
+
+ if(ob->type==OB_MESH) {
+ Mesh *me= get_mesh(ob);
+ mesh_delete_material_index(me, actcol-1);
+ freedisplist(&ob->disp);
+ }
+ else if ELEM(ob->type, OB_CURVE, OB_SURF) {
+ cu= ob->data;
+ nu= cu->nurb.first;
+
+ while(nu) {
+ if(nu->mat_nr && nu->mat_nr>=actcol-1) {
+ nu->mat_nr--;
+ if (ob->type == OB_CURVE) nu->charidx--;
+ }
+ nu= nu->next;
+ }
+ freedisplist(&ob->disp);
+ }
+}
+
+
+/* r g b = current value, col = new value, fac==0 is no change */
+/* if g==NULL, it only does r channel */
+void ramp_blend(int type, float *r, float *g, float *b, float fac, float *col)
+{
+ float tmp, facm= 1.0-fac;
+
+ switch (type) {
+ case MA_RAMP_BLEND:
+ *r = facm*(*r) + fac*col[0];
+ if(g) {
+ *g = facm*(*g) + fac*col[1];
+ *b = facm*(*b) + fac*col[2];
+ }
+ break;
+ case MA_RAMP_ADD:
+ *r += fac*col[0];
+ if(g) {
+ *g += fac*col[1];
+ *b += fac*col[2];
+ }
+ break;
+ case MA_RAMP_MULT:
+ *r *= (facm + fac*col[0]);
+ if(g) {
+ *g *= (facm + fac*col[1]);
+ *b *= (facm + fac*col[2]);
+ }
+ break;
+ case MA_RAMP_SCREEN:
+ *r = 1.0 - (facm + fac*(1.0 - col[0])) * (1.0 - *r);
+ if(g) {
+ *g = 1.0 - (facm + fac*(1.0 - col[1])) * (1.0 - *g);
+ *b = 1.0 - (facm + fac*(1.0 - col[2])) * (1.0 - *b);
+ }
+ break;
+ case MA_RAMP_OVERLAY:
+ if(*r < 0.5f)
+ *r *= (facm + 2.0f*fac*col[0]);
+ else
+ *r = 1.0 - (facm + 2.0f*fac*(1.0 - col[0])) * (1.0 - *r);
+ if(g) {
+ if(*g < 0.5f)
+ *g *= (facm + 2.0f*fac*col[1]);
+ else
+ *g = 1.0 - (facm + 2.0f*fac*(1.0 - col[1])) * (1.0 - *g);
+ if(*b < 0.5f)
+ *b *= (facm + 2.0f*fac*col[2]);
+ else
+ *b = 1.0 - (facm + 2.0f*fac*(1.0 - col[2])) * (1.0 - *b);
+ }
+ break;
+ case MA_RAMP_SUB:
+ *r -= fac*col[0];
+ if(g) {
+ *g -= fac*col[1];
+ *b -= fac*col[2];
+ }
+ break;
+ case MA_RAMP_DIV:
+ if(col[0]!=0.0)
+ *r = facm*(*r) + fac*(*r)/col[0];
+ if(g) {
+ if(col[1]!=0.0)
+ *g = facm*(*g) + fac*(*g)/col[1];
+ if(col[2]!=0.0)
+ *b = facm*(*b) + fac*(*b)/col[2];
+ }
+ break;
+ case MA_RAMP_DIFF:
+ *r = facm*(*r) + fac*fabs(*r-col[0]);
+ if(g) {
+ *g = facm*(*g) + fac*fabs(*g-col[1]);
+ *b = facm*(*b) + fac*fabs(*b-col[2]);
+ }
+ break;
+ case MA_RAMP_DARK:
+ tmp= fac*col[0];
+ if(tmp < *r) *r= tmp;
+ if(g) {
+ tmp= fac*col[1];
+ if(tmp < *g) *g= tmp;
+ tmp= fac*col[2];
+ if(tmp < *b) *b= tmp;
+ }
+ break;
+ case MA_RAMP_LIGHT:
+ tmp= fac*col[0];
+ if(tmp > *r) *r= tmp;
+ if(g) {
+ tmp= fac*col[1];
+ if(tmp > *g) *g= tmp;
+ tmp= fac*col[2];
+ if(tmp > *b) *b= tmp;
+ }
+ break;
+ case MA_RAMP_DODGE:
+
+
+ if(*r !=0.0){
+ tmp = 1.0 - fac*col[0];
+ if(tmp <= 0.0)
+ *r = 1.0;
+ else if ((tmp = (*r) / tmp)> 1.0)
+ *r = 1.0;
+ else
+ *r = tmp;
+ }
+ if(g) {
+ if(*g !=0.0){
+ tmp = 1.0 - fac*col[1];
+ if(tmp <= 0.0 )
+ *g = 1.0;
+ else if ((tmp = (*g) / tmp) > 1.0 )
+ *g = 1.0;
+ else
+ *g = tmp;
+ }
+ if(*b !=0.0){
+ tmp = 1.0 - fac*col[2];
+ if(tmp <= 0.0)
+ *b = 1.0;
+ else if ((tmp = (*b) / tmp) > 1.0 )
+ *b = 1.0;
+ else
+ *b = tmp;
+ }
+
+ }
+ break;
+ case MA_RAMP_BURN:
+
+ tmp = facm + fac*col[0];
+
+ if(tmp <= 0.0)
+ *r = 0.0;
+ else if (( tmp = (1.0 - (1.0 - (*r)) / tmp )) < 0.0)
+ *r = 0.0;
+ else if (tmp > 1.0)
+ *r=1.0;
+ else
+ *r = tmp;
+
+ if(g) {
+ tmp = facm + fac*col[1];
+ if(tmp <= 0.0)
+ *g = 0.0;
+ else if (( tmp = (1.0 - (1.0 - (*g)) / tmp )) < 0.0 )
+ *g = 0.0;
+ else if(tmp >1.0)
+ *g=1.0;
+ else
+ *g = tmp;
+
+ tmp = facm + fac*col[2];
+ if(tmp <= 0.0)
+ *b = 0.0;
+ else if (( tmp = (1.0 - (1.0 - (*b)) / tmp )) < 0.0 )
+ *b = 0.0;
+ else if(tmp >1.0)
+ *b= 1.0;
+ else
+ *b = tmp;
+ }
+ break;
+ case MA_RAMP_HUE:
+ if(g){
+ float rH,rS,rV;
+ float colH,colS,colV;
+ float tmpr,tmpg,tmpb;
+ rgb_to_hsv(col[0],col[1],col[2],&colH,&colS,&colV);
+ if(colS!=0 ){
+ rgb_to_hsv(*r,*g,*b,&rH,&rS,&rV);
+ hsv_to_rgb( colH , rS, rV, &tmpr, &tmpg, &tmpb);
+ *r = facm*(*r) + fac*tmpr;
+ *g = facm*(*g) + fac*tmpg;
+ *b = facm*(*b) + fac*tmpb;
+ }
+ }
+ break;
+ case MA_RAMP_SAT:
+ if(g){
+ float rH,rS,rV;
+ float colH,colS,colV;
+ rgb_to_hsv(*r,*g,*b,&rH,&rS,&rV);
+ if(rS!=0){
+ rgb_to_hsv(col[0],col[1],col[2],&colH,&colS,&colV);
+ hsv_to_rgb( rH, (facm*rS +fac*colS), rV, r, g, b);
+ }
+ }
+ break;
+ case MA_RAMP_VAL:
+ if(g){
+ float rH,rS,rV;
+ float colH,colS,colV;
+ rgb_to_hsv(*r,*g,*b,&rH,&rS,&rV);
+ rgb_to_hsv(col[0],col[1],col[2],&colH,&colS,&colV);
+ hsv_to_rgb( rH, rS, (facm*rV +fac*colV), r, g, b);
+ }
+ break;
+ case MA_RAMP_COLOR:
+ if(g){
+ float rH,rS,rV;
+ float colH,colS,colV;
+ float tmpr,tmpg,tmpb;
+ rgb_to_hsv(col[0],col[1],col[2],&colH,&colS,&colV);
+ if(colS!=0){
+ rgb_to_hsv(*r,*g,*b,&rH,&rS,&rV);
+ hsv_to_rgb( colH, colS, rV, &tmpr, &tmpg, &tmpb);
+ *r = facm*(*r) + fac*tmpr;
+ *g = facm*(*g) + fac*tmpg;
+ *b = facm*(*b) + fac*tmpb;
+ }
+ }
+ break;
+ }
+
+}
+
+
diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c
new file mode 100644
index 00000000000..e731f0fdfe0
--- /dev/null
+++ b/source/blender/blenkernel/intern/mball.c
@@ -0,0 +1,2088 @@
+/** mball.c
+ *
+ * MetaBalls are created from a single Object (with a name without number in it),
+ * here the DispList and BoundBox also is located.
+ * All objects with the same name (but with a number in it) are added to this.
+ *
+ * texture coordinates are patched within the displist
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Jiri Hnidek <jiri.hnidek@vslib.cz>.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <float.h>
+#include "MEM_guardedalloc.h"
+
+#include "DNA_material_types.h"
+#include "DNA_object_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_scene_types.h"
+
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_bad_level_calls.h"
+
+#include "BKE_global.h"
+#include "BKE_main.h"
+
+/* #include "BKE_object.h" */
+#include "BKE_scene.h"
+#include "BKE_blender.h"
+#include "BKE_library.h"
+#include "BKE_displist.h"
+#include "BKE_mball.h"
+#include "BKE_object.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* Global variables */
+
+float thresh= 0.6f;
+int totelem=0;
+MetaElem **mainb;
+octal_tree *metaball_tree = NULL;
+/* Functions */
+
+void unlink_mball(MetaBall *mb)
+{
+ int a;
+
+ for(a=0; a<mb->totcol; a++) {
+ if(mb->mat[a]) mb->mat[a]->id.us--;
+ mb->mat[a]= 0;
+ }
+}
+
+
+/* do not free mball itself */
+void free_mball(MetaBall *mb)
+{
+ unlink_mball(mb);
+
+ if(mb->mat) MEM_freeN(mb->mat);
+ if(mb->bb) MEM_freeN(mb->bb);
+ BLI_freelistN(&mb->elems);
+ if(mb->disp.first) freedisplist(&mb->disp);
+}
+
+MetaBall *add_mball(char *name)
+{
+ MetaBall *mb;
+
+ mb= alloc_libblock(&G.main->mball, ID_MB, name);
+
+ mb->size[0]= mb->size[1]= mb->size[2]= 1.0;
+ mb->texflag= MB_AUTOSPACE;
+
+ mb->wiresize= 0.4f;
+ mb->rendersize= 0.2f;
+ mb->thresh= 0.6f;
+
+ return mb;
+}
+
+MetaBall *copy_mball(MetaBall *mb)
+{
+ MetaBall *mbn;
+ int a;
+
+ mbn= copy_libblock(mb);
+
+ duplicatelist(&mbn->elems, &mb->elems);
+
+ mbn->mat= MEM_dupallocN(mb->mat);
+ for(a=0; a<mbn->totcol; a++) {
+ id_us_plus((ID *)mbn->mat[a]);
+ }
+ mbn->bb= MEM_dupallocN(mb->bb);
+
+ return mbn;
+}
+
+void make_local_mball(MetaBall *mb)
+{
+ Object *ob;
+ MetaBall *mbn;
+ int local=0, lib=0;
+
+ /* - only lib users: do nothing
+ * - only local users: set flag
+ * - mixed: make copy
+ */
+
+ if(mb->id.lib==0) return;
+ if(mb->id.us==1) {
+ mb->id.lib= 0;
+ mb->id.flag= LIB_LOCAL;
+ return;
+ }
+
+ ob= G.main->object.first;
+ while(ob) {
+ if(ob->data==mb) {
+ if(ob->id.lib) lib= 1;
+ else local= 1;
+ }
+ ob= ob->id.next;
+ }
+
+ if(local && lib==0) {
+ mb->id.lib= 0;
+ mb->id.flag= LIB_LOCAL;
+ }
+ else if(local && lib) {
+ mbn= copy_mball(mb);
+ mbn->id.us= 0;
+
+ ob= G.main->object.first;
+ while(ob) {
+ if(ob->data==mb) {
+
+ if(ob->id.lib==0) {
+ ob->data= mbn;
+ mbn->id.us++;
+ mb->id.us--;
+ }
+ }
+ ob= ob->id.next;
+ }
+ }
+}
+/** Compute bounding box of all MetaElems/MetaBalls.
+ *
+ * Bounding box is computed from polygonized surface. Object *ob is
+ * basic MetaBall (usaualy with name Meta). All other MetaBalls (whith
+ * names Meta.001, Meta.002, etc) are included in this Bounding Box.
+ */
+void tex_space_mball(Object *ob)
+{
+ DispList *dl;
+ BoundBox *bb;
+ float *data, min[3], max[3], loc[3], size[3];
+ int tot, doit=0;
+
+ if(ob->bb==0) ob->bb= MEM_callocN(sizeof(BoundBox), "mb boundbox");
+ bb= ob->bb;
+
+ /* Weird one, this. */
+/* INIT_MINMAX(min, max); */
+ (min)[0]= (min)[1]= (min)[2]= 1.0e30f;
+ (max)[0]= (max)[1]= (max)[2]= -1.0e30f;
+
+ dl= ob->disp.first;
+ while(dl) {
+ tot= dl->nr;
+ if(tot) doit= 1;
+ data= dl->verts;
+ while(tot--) {
+ /* Also weird... but longer. From utildefines. */
+ DO_MINMAX(data, min, max);
+ data+= 3;
+ }
+ dl= dl->next;
+ }
+
+ if(!doit) {
+ min[0] = min[1] = min[2] = -1.0f;
+ max[0] = max[1] = max[2] = 1.0f;
+ }
+
+ loc[0]= (min[0]+max[0])/2.0f;
+ loc[1]= (min[1]+max[1])/2.0f;
+ loc[2]= (min[2]+max[2])/2.0f;
+
+ size[0]= (max[0]-min[0])/2.0f;
+ size[1]= (max[1]-min[1])/2.0f;
+ size[2]= (max[2]-min[2])/2.0f;
+
+ boundbox_set_from_min_max(bb, min, max);
+}
+
+void make_orco_mball(Object *ob)
+{
+ BoundBox *bb;
+ DispList *dl;
+ float *data;
+ float loc[3], size[3];
+ int a;
+
+ /* restore size and loc */
+ bb= ob->bb;
+ loc[0]= (bb->vec[0][0]+bb->vec[4][0])/2.0f;
+ size[0]= bb->vec[4][0]-loc[0];
+ loc[1]= (bb->vec[0][1]+bb->vec[2][1])/2.0f;
+ size[1]= bb->vec[2][1]-loc[1];
+ loc[2]= (bb->vec[0][2]+bb->vec[1][2])/2.0f;
+ size[2]= bb->vec[1][2]-loc[2];
+
+ dl= ob->disp.first;
+ data= dl->verts;
+ a= dl->nr;
+ while(a--) {
+ data[0]= (data[0]-loc[0])/size[0];
+ data[1]= (data[1]-loc[1])/size[1];
+ data[2]= (data[2]-loc[2])/size[2];
+
+ data+= 3;
+ }
+}
+/** \brief Test, if Object *ob is basic MetaBall.
+ *
+ * It test last character of Object ID name. If last character
+ * is digit it return 0, else it return 1.
+ */
+int is_basis_mball(Object *ob)
+{
+ int len;
+
+ /* just a quick test */
+ len= strlen(ob->id.name);
+ if( isdigit(ob->id.name[len-1]) ) return 0;
+ return 1;
+}
+
+/** \brief This function finds basic MetaBall.
+ *
+ * Basic MetaBall doesn't include any number at the end of
+ * its name. All MetaBalls with same base of name can be
+ * blended. MetaBalls with different basic name can't be
+ * blended.
+ */
+Object *find_basis_mball(Object *basis)
+{
+ Base *base;
+ Object *ob,*bob= basis;
+ MetaElem *ml=NULL;
+ int basisnr, obnr;
+ char basisname[32], obname[32];
+
+ splitIDname(basis->id.name+2, basisname, &basisnr);
+ totelem= 0;
+
+ next_object(0, 0, 0);
+ while(next_object(1, &base, &ob)) {
+
+ if (ob->type==OB_MBALL) {
+ if(ob==bob){
+ /* if bob object is in edit mode, then dynamic list of all MetaElems
+ * is stored in editelems */
+ if(ob==G.obedit) ml= editelems.first;
+ /* keep track of linked data too! */
+ else if(G.obedit && G.obedit->data==ob->data) ml= editelems.first;
+ /* if bob object is in object mode */
+ else ml= ((MetaBall*)ob->data)->elems.first;
+ }
+ else{
+ splitIDname(ob->id.name+2, obname, &obnr);
+
+ /* object ob has to be in same "group" ... it means, that it has to have
+ * same base of its name */
+ if(strcmp(obname, basisname)==0){
+ /* if object is in edit mode, then dynamic list of all MetaElems
+ * is stored in editelems */
+ if(ob==G.obedit) ml= editelems.first;
+ /* keep track of linked data too! */
+ else if(bob==G.obedit && bob->data==ob->data) ml= editelems.first;
+ /* object is in object mode */
+ else ml= ((MetaBall*)ob->data)->elems.first;
+
+ if(obnr<basisnr){
+ if(!(ob->flag & OB_FROMDUPLI)){
+ basis= ob;
+ basisnr= obnr;
+ }
+ }
+ }
+ }
+
+ while(ml){
+ if(!(ml->flag & MB_HIDE)) totelem++;
+ ml= ml->next;
+ }
+ }
+ }
+
+ return basis;
+}
+
+
+/* ******************** ARITH ************************* */
+
+/* BASED AT CODE (but mostly rewritten) :
+ * C code from the article
+ * "An Implicit Surface Polygonizer"
+ * by Jules Bloomenthal, jbloom@beauty.gmu.edu
+ * in "Graphics Gems IV", Academic Press, 1994
+
+ * Authored by Jules Bloomenthal, Xerox PARC.
+ * Copyright (c) Xerox Corporation, 1991. All rights reserved.
+ * Permission is granted to reproduce, use and distribute this code for
+ * any and all purposes, provided that this notice appears in all copies. */
+
+#define RES 12 /* # converge iterations */
+
+#define L 0 /* left direction: -x, -i */
+#define R 1 /* right direction: +x, +i */
+#define B 2 /* bottom direction: -y, -j */
+#define T 3 /* top direction: +y, +j */
+#define N 4 /* near direction: -z, -k */
+#define F 5 /* far direction: +z, +k */
+#define LBN 0 /* left bottom near corner */
+#define LBF 1 /* left bottom far corner */
+#define LTN 2 /* left top near corner */
+#define LTF 3 /* left top far corner */
+#define RBN 4 /* right bottom near corner */
+#define RBF 5 /* right bottom far corner */
+#define RTN 6 /* right top near corner */
+#define RTF 7 /* right top far corner */
+
+/* the LBN corner of cube (i, j, k), corresponds with location
+ * (start.x+(i-0.5)*size, start.y+(j-0.5)*size, start.z+(k-0.5)*size) */
+
+#define HASHBIT (5)
+#define HASHSIZE (size_t)(1<<(3*HASHBIT)) /*! < hash table size (32768) */
+
+#define HASH(i,j,k) ((((( (i) & 31)<<5) | ( (j) & 31))<<5 ) | ( (k) & 31) )
+
+#define MB_BIT(i, bit) (((i)>>(bit))&1)
+#define FLIP(i,bit) ((i)^1<<(bit)) /* flip the given bit of i */
+
+
+/* **************** POLYGONIZATION ************************ */
+
+void calc_mballco(MetaElem *ml, float *vec)
+{
+ if(ml->mat) {
+ Mat4MulVecfl((float ( * )[4])ml->mat, vec);
+ }
+}
+
+float densfunc(MetaElem *ball, float x, float y, float z)
+{
+ float dist2 = 0.0, dx, dy, dz;
+ float vec[3];
+
+ vec[0]= x;
+ vec[1]= y;
+ vec[2]= z;
+ Mat4MulVecfl((float ( * )[4])ball->imat, vec);
+ dx= vec[0];
+ dy= vec[1];
+ dz= vec[2];
+
+ if(ball->type==MB_BALL) {
+ }
+ else if(ball->type==MB_TUBEX) {
+ if( dx > ball->len) dx-= ball->len;
+ else if(dx< -ball->len) dx+= ball->len;
+ else dx= 0.0;
+ }
+ else if(ball->type==MB_TUBEY) {
+ if( dy > ball->len) dy-= ball->len;
+ else if(dy< -ball->len) dy+= ball->len;
+ else dy= 0.0;
+ }
+ else if(ball->type==MB_TUBEZ) {
+ if( dz > ball->len) dz-= ball->len;
+ else if(dz< -ball->len) dz+= ball->len;
+ else dz= 0.0;
+ }
+ else if(ball->type==MB_TUBE) {
+ if( dx > ball->expx) dx-= ball->expx;
+ else if(dx< -ball->expx) dx+= ball->expx;
+ else dx= 0.0;
+ }
+ else if(ball->type==MB_PLANE) {
+ if( dx > ball->expx) dx-= ball->expx;
+ else if(dx< -ball->expx) dx+= ball->expx;
+ else dx= 0.0;
+ if( dy > ball->expy) dy-= ball->expy;
+ else if(dy< -ball->expy) dy+= ball->expy;
+ else dy= 0.0;
+ }
+ else if(ball->type==MB_ELIPSOID) {
+ dx *= 1/ball->expx;
+ dy *= 1/ball->expy;
+ dz *= 1/ball->expz;
+ }
+ else if(ball->type==MB_CUBE) {
+ if( dx > ball->expx) dx-= ball->expx;
+ else if(dx< -ball->expx) dx+= ball->expx;
+ else dx= 0.0;
+ if( dy > ball->expy) dy-= ball->expy;
+ else if(dy< -ball->expy) dy+= ball->expy;
+ else dy= 0.0;
+ if( dz > ball->expz) dz-= ball->expz;
+ else if(dz< -ball->expz) dz+= ball->expz;
+ else dz= 0.0;
+ }
+
+ dist2= (dx*dx + dy*dy + dz*dz);
+
+ if(ball->flag & MB_NEGATIVE) {
+ dist2= 1.0f-(dist2/ball->rad2);
+ if(dist2 < 0.0) return 0.5f;
+
+ return 0.5f-ball->s*dist2*dist2*dist2;
+ }
+ else {
+ dist2= 1.0f-(dist2/ball->rad2);
+ if(dist2 < 0.0) return -0.5f;
+
+ return ball->s*dist2*dist2*dist2 -0.5f;
+ }
+}
+
+octal_node* find_metaball_octal_node(octal_node *node, float x, float y, float z, short depth)
+{
+ if(!depth) return node;
+
+ if(z < node->z){
+ if(y < node->y){
+ if(x < node->x){
+ if(node->nodes[0])
+ return find_metaball_octal_node(node->nodes[0],x,y,z,depth--);
+ else
+ return node;
+ }
+ else{
+ if(node->nodes[1])
+ return find_metaball_octal_node(node->nodes[1],x,y,z,depth--);
+ else
+ return node;
+ }
+ }
+ else{
+ if(x < node->x){
+ if(node->nodes[3])
+ return find_metaball_octal_node(node->nodes[3],x,y,z,depth--);
+ else
+ return node;
+ }
+ else{
+ if(node->nodes[2])
+ return find_metaball_octal_node(node->nodes[2],x,y,z,depth--);
+ else
+ return node;
+ }
+ }
+ }
+ else{
+ if(y < node->y){
+ if(x < node->x){
+ if(node->nodes[4])
+ return find_metaball_octal_node(node->nodes[4],x,y,z,depth--);
+ else
+ return node;
+ }
+ else{
+ if(node->nodes[5])
+ return find_metaball_octal_node(node->nodes[5],x,y,z,depth--);
+ else
+ return node;
+ }
+ }
+ else{
+ if(x < node->x){
+ if(node->nodes[7])
+ return find_metaball_octal_node(node->nodes[7],x,y,z,depth--);
+ else
+ return node;
+ }
+ else{
+ if(node->nodes[6])
+ return find_metaball_octal_node(node->nodes[6],x,y,z,depth--);
+ else
+ return node;
+ }
+ }
+ }
+
+ return node;
+}
+
+float metaball(float x, float y, float z)
+/* float x, y, z; */
+{
+ struct octal_node *node;
+ struct ml_pointer *ml_p;
+ float dens=0;
+ int a;
+
+ if(totelem > 1){
+ node= find_metaball_octal_node(metaball_tree->first, x, y, z, metaball_tree->depth);
+ if(node){
+ ml_p= node->elems.first;
+
+ while(ml_p){
+ dens+=densfunc(ml_p->ml, x, y, z);
+ ml_p= ml_p->next;
+ }
+
+ dens+= -0.5*(metaball_tree->pos - node->pos);
+ dens+= 0.5*(metaball_tree->neg - node->neg);
+ }
+ else{
+ for(a=0; a<totelem; a++) {
+ dens+= densfunc( mainb[a], x, y, z);
+ }
+ }
+ }
+ else{
+ dens+= densfunc( mainb[0], x, y, z);
+ }
+
+ return thresh - dens;
+}
+
+/* ******************************************** */
+
+int *indices=NULL;
+int totindex, curindex;
+
+
+void accum_mballfaces(int i1, int i2, int i3, int i4)
+{
+ int *newi, *cur;
+ /* static int i=0; I would like to delete altogether, but I don't dare to, yet */
+
+ if(totindex==curindex) {
+ totindex+= 256;
+ newi= MEM_mallocN(4*sizeof(int)*totindex, "vertindex");
+
+ if(indices) {
+ memcpy(newi, indices, 4*sizeof(int)*(totindex-256));
+ MEM_freeN(indices);
+ }
+ indices= newi;
+ }
+
+ cur= indices+4*curindex;
+
+ /* diplists now support array drawing, we treat trias as fake quad */
+
+ cur[0]= i1;
+ cur[1]= i2;
+ cur[2]= i3;
+ if(i4==0)
+ cur[3]= i3;
+ else
+ cur[3]= i4;
+
+ curindex++;
+
+}
+
+/* ******************* MEMORY MANAGEMENT *********************** */
+void *new_pgn_element(int size)
+{
+ /* during polygonize 1000s of elements are allocated
+ * and never freed inbetween. Freeing only done at the end.
+ */
+ int blocksize= 16384;
+ static int offs= 0; /* the current free address */
+ static struct pgn_elements *cur= 0;
+ static ListBase lb= {0, 0};
+ void *adr;
+
+ if(size>10000 || size==0) {
+ printf("incorrect use of new_pgn_element\n");
+ }
+ else if(size== -1) {
+ cur= lb.first;
+ while(cur) {
+ MEM_freeN(cur->data);
+ cur= cur->next;
+ }
+ BLI_freelistN(&lb);
+
+ return NULL;
+ }
+
+ size= 4*( (size+3)/4 );
+
+ if(cur) {
+ if(size+offs < blocksize) {
+ adr= (void *) (cur->data+offs);
+ offs+= size;
+ return adr;
+ }
+ }
+
+ cur= MEM_callocN( sizeof(struct pgn_elements), "newpgn");
+ cur->data= MEM_callocN(blocksize, "newpgn");
+ BLI_addtail(&lb, cur);
+
+ offs= size;
+ return cur->data;
+}
+
+void freepolygonize(PROCESS *p)
+{
+ MEM_freeN(p->corners);
+ MEM_freeN(p->edges);
+ MEM_freeN(p->centers);
+
+ new_pgn_element(-1);
+
+ if(p->vertices.ptr) MEM_freeN(p->vertices.ptr);
+}
+
+/**** Cubical Polygonization (optional) ****/
+
+#define LB 0 /* left bottom edge */
+#define LT 1 /* left top edge */
+#define LN 2 /* left near edge */
+#define LF 3 /* left far edge */
+#define RB 4 /* right bottom edge */
+#define RT 5 /* right top edge */
+#define RN 6 /* right near edge */
+#define RF 7 /* right far edge */
+#define BN 8 /* bottom near edge */
+#define BF 9 /* bottom far edge */
+#define TN 10 /* top near edge */
+#define TF 11 /* top far edge */
+
+static INTLISTS *cubetable[256];
+
+/* edge: LB, LT, LN, LF, RB, RT, RN, RF, BN, BF, TN, TF */
+static int corner1[12] = {
+ LBN,LTN,LBN,LBF,RBN,RTN,RBN,RBF,LBN,LBF,LTN,LTF};
+static int corner2[12] = {
+ LBF,LTF,LTN,LTF,RBF,RTF,RTN,RTF,RBN,RBF,RTN,RTF};
+static int leftface[12] = {
+ B, L, L, F, R, T, N, R, N, B, T, F};
+/* face on left when going corner1 to corner2 */
+static int rightface[12] = {
+ L, T, N, L, B, R, R, F, B, F, N, T};
+/* face on right when going corner1 to corner2 */
+
+
+/* docube: triangulate the cube directly, without decomposition */
+
+void docube(CUBE *cube, PROCESS *p, MetaBall *mb)
+{
+ INTLISTS *polys;
+ CORNER *c1, *c2;
+ int i, index = 0, count, indexar[8];
+
+ for (i = 0; i < 8; i++) if (cube->corners[i]->value > 0.0) index += (1<<i);
+
+ for (polys = cubetable[index]; polys; polys = polys->next) {
+ INTLIST *edges;
+
+ count = 0;
+
+ for (edges = polys->list; edges; edges = edges->next) {
+ c1 = cube->corners[corner1[edges->i]];
+ c2 = cube->corners[corner2[edges->i]];
+
+ indexar[count] = vertid(c1, c2, p, mb);
+ count++;
+ }
+ if(count>2) {
+ switch(count) {
+ case 3:
+ accum_mballfaces(indexar[2], indexar[1], indexar[0], 0);
+ break;
+ case 4:
+ if(indexar[0]==0) accum_mballfaces(indexar[0], indexar[3], indexar[2], indexar[1]);
+ else accum_mballfaces(indexar[3], indexar[2], indexar[1], indexar[0]);
+ break;
+ case 5:
+ if(indexar[0]==0) accum_mballfaces(indexar[0], indexar[3], indexar[2], indexar[1]);
+ else accum_mballfaces(indexar[3], indexar[2], indexar[1], indexar[0]);
+
+ accum_mballfaces(indexar[4], indexar[3], indexar[0], 0);
+ break;
+ case 6:
+ if(indexar[0]==0) {
+ accum_mballfaces(indexar[0], indexar[3], indexar[2], indexar[1]);
+ accum_mballfaces(indexar[0], indexar[5], indexar[4], indexar[3]);
+ }
+ else {
+ accum_mballfaces(indexar[3], indexar[2], indexar[1], indexar[0]);
+ accum_mballfaces(indexar[5], indexar[4], indexar[3], indexar[0]);
+ }
+ break;
+ case 7:
+ if(indexar[0]==0) {
+ accum_mballfaces(indexar[0], indexar[3], indexar[2], indexar[1]);
+ accum_mballfaces(indexar[0], indexar[5], indexar[4], indexar[3]);
+ }
+ else {
+ accum_mballfaces(indexar[3], indexar[2], indexar[1], indexar[0]);
+ accum_mballfaces(indexar[5], indexar[4], indexar[3], indexar[0]);
+ }
+
+ accum_mballfaces(indexar[6], indexar[5], indexar[0], 0);
+
+ break;
+ }
+ }
+ }
+}
+
+
+/* testface: given cube at lattice (i, j, k), and four corners of face,
+ * if surface crosses face, compute other four corners of adjacent cube
+ * and add new cube to cube stack */
+
+void testface(int i, int j, int k, CUBE* old, int bit, int c1, int c2, int c3, int c4, PROCESS *p)
+{
+ CUBE newc;
+ CUBES *oldcubes = p->cubes;
+ CORNER *corn1, *corn2, *corn3, *corn4;
+ int n, pos;
+
+ corn1= old->corners[c1];
+ corn2= old->corners[c2];
+ corn3= old->corners[c3];
+ corn4= old->corners[c4];
+
+ pos = corn1->value > 0.0 ? 1 : 0;
+
+ /* test if no surface crossing */
+ if( (corn2->value > 0) == pos && (corn3->value > 0) == pos && (corn4->value > 0) == pos) return;
+ /* test if cube out of bounds */
+ /*if ( abs(i) > p->bounds || abs(j) > p->bounds || abs(k) > p->bounds) return;*/
+ /* test if already visited (always as last) */
+ if (setcenter(p->centers, i, j, k)) return;
+
+
+ /* create new cube and add cube to top of stack: */
+ p->cubes = (CUBES *) new_pgn_element(sizeof(CUBES));
+ p->cubes->next = oldcubes;
+
+ newc.i = i;
+ newc.j = j;
+ newc.k = k;
+ for (n = 0; n < 8; n++) newc.corners[n] = NULL;
+
+ newc.corners[FLIP(c1, bit)] = corn1;
+ newc.corners[FLIP(c2, bit)] = corn2;
+ newc.corners[FLIP(c3, bit)] = corn3;
+ newc.corners[FLIP(c4, bit)] = corn4;
+
+ if(newc.corners[0]==0) newc.corners[0] = setcorner(p, i, j, k);
+ if(newc.corners[1]==0) newc.corners[1] = setcorner(p, i, j, k+1);
+ if(newc.corners[2]==0) newc.corners[2] = setcorner(p, i, j+1, k);
+ if(newc.corners[3]==0) newc.corners[3] = setcorner(p, i, j+1, k+1);
+ if(newc.corners[4]==0) newc.corners[4] = setcorner(p, i+1, j, k);
+ if(newc.corners[5]==0) newc.corners[5] = setcorner(p, i+1, j, k+1);
+ if(newc.corners[6]==0) newc.corners[6] = setcorner(p, i+1, j+1, k);
+ if(newc.corners[7]==0) newc.corners[7] = setcorner(p, i+1, j+1, k+1);
+
+ p->cubes->cube= newc;
+}
+
+/* setcorner: return corner with the given lattice location
+ set (and cache) its function value */
+
+CORNER *setcorner (PROCESS* p, int i, int j, int k)
+{
+ /* for speed, do corner value caching here */
+ CORNER *c;
+ int index;
+
+ /* does corner exist? */
+ index = HASH(i, j, k);
+ c = p->corners[index];
+
+ for (; c != NULL; c = c->next) {
+ if (c->i == i && c->j == j && c->k == k) {
+ return c;
+ }
+ }
+
+ c = (CORNER *) new_pgn_element(sizeof(CORNER));
+
+ c->i = i;
+ c->x = p->start.x+((float)i-0.5f)*p->size;
+ c->j = j;
+ c->y = p->start.y+((float)j-0.5f)*p->size;
+ c->k = k;
+ c->z = p->start.z+((float)k-0.5f)*p->size;
+ c->value = p->function(c->x, c->y, c->z);
+
+ c->next = p->corners[index];
+ p->corners[index] = c;
+
+ return c;
+}
+
+
+/* nextcwedge: return next clockwise edge from given edge around given face */
+
+int nextcwedge (int edge, int face)
+{
+ switch (edge) {
+ case LB:
+ return (face == L)? LF : BN;
+ case LT:
+ return (face == L)? LN : TF;
+ case LN:
+ return (face == L)? LB : TN;
+ case LF:
+ return (face == L)? LT : BF;
+ case RB:
+ return (face == R)? RN : BF;
+ case RT:
+ return (face == R)? RF : TN;
+ case RN:
+ return (face == R)? RT : BN;
+ case RF:
+ return (face == R)? RB : TF;
+ case BN:
+ return (face == B)? RB : LN;
+ case BF:
+ return (face == B)? LB : RF;
+ case TN:
+ return (face == T)? LT : RN;
+ case TF:
+ return (face == T)? RT : LF;
+ }
+ return 0;
+}
+
+
+/* otherface: return face adjoining edge that is not the given face */
+
+int otherface (int edge, int face)
+{
+ int other = leftface[edge];
+ return face == other? rightface[edge] : other;
+}
+
+
+/* makecubetable: create the 256 entry table for cubical polygonization */
+
+void makecubetable (void)
+{
+ static int isdone= 0;
+ int i, e, c, done[12], pos[8];
+
+ if(isdone) return;
+ isdone= 1;
+
+ for (i = 0; i < 256; i++) {
+ for (e = 0; e < 12; e++) done[e] = 0;
+ for (c = 0; c < 8; c++) pos[c] = MB_BIT(i, c);
+ for (e = 0; e < 12; e++)
+ if (!done[e] && (pos[corner1[e]] != pos[corner2[e]])) {
+ INTLIST *ints = 0;
+ INTLISTS *lists = (INTLISTS *) MEM_callocN(sizeof(INTLISTS), "mball_intlist");
+ int start = e, edge = e;
+
+ /* get face that is to right of edge from pos to neg corner: */
+ int face = pos[corner1[e]]? rightface[e] : leftface[e];
+
+ while (1) {
+ edge = nextcwedge(edge, face);
+ done[edge] = 1;
+ if (pos[corner1[edge]] != pos[corner2[edge]]) {
+ INTLIST *tmp = ints;
+
+ ints = (INTLIST *) MEM_callocN(sizeof(INTLIST), "mball_intlist");
+ ints->i = edge;
+ ints->next = tmp; /* add edge to head of list */
+
+ if (edge == start) break;
+ face = otherface(edge, face);
+ }
+ }
+ lists->list = ints; /* add ints to head of table entry */
+ lists->next = cubetable[i];
+ cubetable[i] = lists;
+ }
+ }
+}
+
+void BKE_freecubetable(void)
+{
+ int i;
+ INTLISTS *lists, *nlists;
+ INTLIST *ints, *nints;
+
+ for (i = 0; i < 256; i++) {
+ lists= cubetable[i];
+ while(lists) {
+ nlists= lists->next;
+
+ ints= lists->list;
+ while(ints) {
+ nints= ints->next;
+ MEM_freeN(ints);
+ ints= nints;
+ }
+
+ MEM_freeN(lists);
+ lists= nlists;
+ }
+ cubetable[i]= 0;
+ }
+}
+
+/**** Storage ****/
+
+/* setcenter: set (i,j,k) entry of table[]
+ * return 1 if already set; otherwise, set and return 0 */
+
+int setcenter(CENTERLIST *table[], int i, int j, int k)
+{
+ int index;
+ CENTERLIST *newc, *l, *q;
+
+ index= HASH(i, j, k);
+ q= table[index];
+
+ for (l = q; l != NULL; l = l->next) {
+ if (l->i == i && l->j == j && l->k == k) return 1;
+ }
+
+ newc = (CENTERLIST *) new_pgn_element(sizeof(CENTERLIST));
+ newc->i = i;
+ newc->j = j;
+ newc->k = k;
+ newc->next = q;
+ table[index] = newc;
+
+ return 0;
+}
+
+
+/* setedge: set vertex id for edge */
+
+void setedge (EDGELIST *table[],
+ int i1, int j1,
+ int k1, int i2,
+ int j2, int k2,
+ int vid)
+{
+ unsigned int index;
+ EDGELIST *newe;
+
+ if (i1>i2 || (i1==i2 && (j1>j2 || (j1==j2 && k1>k2)))) {
+ int t=i1;
+ i1=i2;
+ i2=t;
+ t=j1;
+ j1=j2;
+ j2=t;
+ t=k1;
+ k1=k2;
+ k2=t;
+ }
+ index = HASH(i1, j1, k1) + HASH(i2, j2, k2);
+ newe = (EDGELIST *) new_pgn_element(sizeof(EDGELIST));
+ newe->i1 = i1;
+ newe->j1 = j1;
+ newe->k1 = k1;
+ newe->i2 = i2;
+ newe->j2 = j2;
+ newe->k2 = k2;
+ newe->vid = vid;
+ newe->next = table[index];
+ table[index] = newe;
+}
+
+
+/* getedge: return vertex id for edge; return -1 if not set */
+
+int getedge (EDGELIST *table[],
+ int i1, int j1, int k1,
+ int i2, int j2, int k2)
+{
+ EDGELIST *q;
+
+ if (i1>i2 || (i1==i2 && (j1>j2 || (j1==j2 && k1>k2)))) {
+ int t=i1;
+ i1=i2;
+ i2=t;
+ t=j1;
+ j1=j2;
+ j2=t;
+ t=k1;
+ k1=k2;
+ k2=t;
+ }
+ q = table[HASH(i1, j1, k1)+HASH(i2, j2, k2)];
+ for (; q != NULL; q = q->next)
+ if (q->i1 == i1 && q->j1 == j1 && q->k1 == k1 &&
+ q->i2 == i2 && q->j2 == j2 && q->k2 == k2)
+ return q->vid;
+ return -1;
+}
+
+
+/**** Vertices ****/
+
+#undef R
+
+
+
+/* vertid: return index for vertex on edge:
+ * c1->value and c2->value are presumed of different sign
+ * return saved index if any; else compute vertex and save */
+
+/* addtovertices: add v to sequence of vertices */
+
+void addtovertices (VERTICES *vertices, VERTEX v)
+{
+ if (vertices->count == vertices->max) {
+ int i;
+ VERTEX *newv;
+ vertices->max = vertices->count == 0 ? 10 : 2*vertices->count;
+ newv = (VERTEX *) MEM_callocN(vertices->max * sizeof(VERTEX), "addtovertices");
+
+ for (i = 0; i < vertices->count; i++) newv[i] = vertices->ptr[i];
+
+ if (vertices->ptr != NULL) MEM_freeN(vertices->ptr);
+ vertices->ptr = newv;
+ }
+ vertices->ptr[vertices->count++] = v;
+}
+
+/* vnormal: compute unit length surface normal at point */
+
+void vnormal (MB_POINT *point, PROCESS *p, MB_POINT *v)
+{
+ float delta= 0.2f*p->delta;
+ float f = p->function(point->x, point->y, point->z);
+
+ v->x = p->function(point->x+delta, point->y, point->z)-f;
+ v->y = p->function(point->x, point->y+delta, point->z)-f;
+ v->z = p->function(point->x, point->y, point->z+delta)-f;
+ f = (float)sqrt(v->x*v->x + v->y*v->y + v->z*v->z);
+
+ if (f != 0.0) {
+ v->x /= f;
+ v->y /= f;
+ v->z /= f;
+ }
+
+ if(FALSE) {
+ MB_POINT temp;
+
+ delta*= 2.0;
+
+ f = p->function(point->x, point->y, point->z);
+
+ temp.x = p->function(point->x+delta, point->y, point->z)-f;
+ temp.y = p->function(point->x, point->y+delta, point->z)-f;
+ temp.z = p->function(point->x, point->y, point->z+delta)-f;
+ f = (float)sqrt(temp.x*temp.x + temp.y*temp.y + temp.z*temp.z);
+
+ if (f != 0.0) {
+ temp.x /= f;
+ temp.y /= f;
+ temp.z /= f;
+
+ v->x+= temp.x;
+ v->y+= temp.y;
+ v->z+= temp.z;
+
+ f = (float)sqrt(v->x*v->x + v->y*v->y + v->z*v->z);
+
+ if (f != 0.0) {
+ v->x /= f;
+ v->y /= f;
+ v->z /= f;
+ }
+ }
+ }
+
+}
+
+
+int vertid (CORNER *c1, CORNER *c2, PROCESS *p, MetaBall *mb)
+{
+ VERTEX v;
+ MB_POINT a, b;
+ int vid = getedge(p->edges, c1->i, c1->j, c1->k, c2->i, c2->j, c2->k);
+
+ if (vid != -1) return vid; /* previously computed */
+ a.x = c1->x;
+ a.y = c1->y;
+ a.z = c1->z;
+ b.x = c2->x;
+ b.y = c2->y;
+ b.z = c2->z;
+
+ converge(&a, &b, c1->value, c2->value, p->function, &v.position, mb, 1); /* position */
+ vnormal(&v.position, p, &v.normal);
+
+ addtovertices(&p->vertices, v); /* save vertex */
+ vid = p->vertices.count-1;
+ setedge(p->edges, c1->i, c1->j, c1->k, c2->i, c2->j, c2->k, vid);
+
+ return vid;
+}
+
+
+
+
+/* converge: from two points of differing sign, converge to zero crossing */
+/* watch it: p1 and p2 are used to calculate */
+void converge (MB_POINT *p1, MB_POINT *p2, float v1, float v2,
+ float (*function)(float, float, float), MB_POINT *p, MetaBall *mb, int f)
+{
+ int i = 0;
+ MB_POINT pos, neg;
+ float positive = 0.0f, negative = 0.0f;
+ float dx = 0.0f ,dy = 0.0f ,dz = 0.0f;
+
+ if (v1 < 0) {
+ pos= *p2;
+ neg= *p1;
+ positive = v2;
+ negative = v1;
+ }
+ else {
+ pos= *p1;
+ neg= *p2;
+ positive = v1;
+ negative = v2;
+ }
+
+ dx = pos.x - neg.x;
+ dy = pos.y - neg.y;
+ dz = pos.z - neg.z;
+
+/* Aproximation by linear interpolation is faster then binary subdivision,
+ * but it results sometimes (mb->thresh < 0.2) into the strange results */
+ if((mb->thresh >0.2) && (f==1)){
+ if((dy == 0.0f) && (dz == 0.0f)){
+ p->x = neg.x - negative*dx/(positive-negative);
+ p->y = neg.y;
+ p->z = neg.z;
+ return;
+ }
+ if((dx == 0.0f) && (dz == 0.0f)){
+ p->x = neg.x;
+ p->y = neg.y - negative*dy/(positive-negative);
+ p->z = neg.z;
+ return;
+ }
+ if((dx == 0.0f) && (dy == 0.0f)){
+ p->x = neg.x;
+ p->y = neg.y;
+ p->z = neg.z - negative*dz/(positive-negative);
+ return;
+ }
+ }
+
+ if((dy == 0.0f) && (dz == 0.0f)){
+ p->y = neg.y;
+ p->z = neg.z;
+ while (1) {
+ p->x = 0.5f*(pos.x + neg.x);
+ if (i++ == RES) return;
+ if ((function(p->x,p->y,p->z)) > 0.0) pos.x = p->x; else neg.x = p->x;
+ }
+ }
+
+ if((dx == 0.0f) && (dz == 0.0f)){
+ p->x = neg.x;
+ p->z = neg.z;
+ while (1) {
+ p->y = 0.5f*(pos.y + neg.y);
+ if (i++ == RES) return;
+ if ((function(p->x,p->y,p->z)) > 0.0) pos.y = p->y; else neg.y = p->y;
+ }
+ }
+
+ if((dx == 0.0f) && (dy == 0.0f)){
+ p->x = neg.x;
+ p->y = neg.y;
+ while (1) {
+ p->z = 0.5f*(pos.z + neg.z);
+ if (i++ == RES) return;
+ if ((function(p->x,p->y,p->z)) > 0.0) pos.z = p->z; else neg.z = p->z;
+ }
+ }
+
+ /* This is necessary to find start point */
+ while (1) {
+ p->x = 0.5f*(pos.x + neg.x);
+ p->y = 0.5f*(pos.y + neg.y);
+ p->z = 0.5f*(pos.z + neg.z);
+
+ if (i++ == RES) return;
+
+ if ((function(p->x, p->y, p->z)) > 0.0){
+ pos.x = p->x;
+ pos.y = p->y;
+ pos.z = p->z;
+ }
+ else{
+ neg.x = p->x;
+ neg.y = p->y;
+ neg.z = p->z;
+ }
+ }
+}
+
+/* ************************************** */
+void add_cube(PROCESS *mbproc, int i, int j, int k, int count)
+{
+ CUBES *ncube;
+ int n;
+ int a, b, c;
+
+ /* hmmm, not only one, but eight cube will be added on the stack
+ * ... */
+ for(a=i-1; a<i+count; a++)
+ for(b=j-1; b<j+count; b++)
+ for(c=k-1; c<k+count; c++) {
+ /* test if cube has been found before */
+ if( setcenter(mbproc->centers, a, b, c)==0 ) {
+ /* push cube on stack: */
+ ncube= (CUBES *) new_pgn_element(sizeof(CUBES));
+ ncube->next= mbproc->cubes;
+ mbproc->cubes= ncube;
+
+ ncube->cube.i= a;
+ ncube->cube.j= b;
+ ncube->cube.k= c;
+
+ /* set corners of initial cube: */
+ for (n = 0; n < 8; n++)
+ ncube->cube.corners[n] = setcorner(mbproc, a+MB_BIT(n,2), b+MB_BIT(n,1), c+MB_BIT(n,0));
+ }
+ }
+}
+
+
+void find_first_points(PROCESS *mbproc, MetaBall *mb, int a)
+{
+ MB_POINT IN, in, OUT, out; /*point;*/
+ MetaElem *ml;
+ int i, j, k, c_i, c_j, c_k;
+ int index[3]={1,0,-1};
+ float f =0.0f;
+ float in_v, out_v;
+
+ ml = mainb[a];
+
+ f = 1-(mb->thresh/ml->s);
+
+ /* Skip, when Stiffness of MetaElement is too small ... MetaElement can't be
+ * visible alone ... but still can influence others MetaElements :-) */
+ if(f > 0.0) {
+ OUT.x = IN.x = in.x= 0.0;
+ OUT.y = IN.y = in.y= 0.0;
+ OUT.z = IN.z = in.z= 0.0;
+
+ calc_mballco(ml, (float *)&in);
+ in_v = mbproc->function(in.x, in.y, in.z);
+
+ for(i=0;i<3;i++){
+ switch (ml->type) {
+ case MB_BALL:
+ OUT.x = out.x= IN.x + index[i]*ml->rad;
+ break;
+ case MB_TUBE:
+ case MB_PLANE:
+ case MB_ELIPSOID:
+ case MB_CUBE:
+ OUT.x = out.x= IN.x + index[i]*(ml->expx + ml->rad);
+ break;
+ }
+
+ for(j=0;j<3;j++) {
+ switch (ml->type) {
+ case MB_BALL:
+ OUT.y = out.y= IN.y + index[j]*ml->rad;
+ break;
+ case MB_TUBE:
+ case MB_PLANE:
+ case MB_ELIPSOID:
+ case MB_CUBE:
+ OUT.y = out.y= IN.y + index[j]*(ml->expy + ml->rad);
+ break;
+ }
+
+ for(k=0;k<3;k++) {
+ out.x = OUT.x;
+ out.y = OUT.y;
+ switch (ml->type) {
+ case MB_BALL:
+ case MB_TUBE:
+ case MB_PLANE:
+ out.z= IN.z + index[k]*ml->rad;
+ break;
+ case MB_ELIPSOID:
+ case MB_CUBE:
+ out.z= IN.z + index[k]*(ml->expz + ml->rad);
+ break;
+ }
+
+ calc_mballco(ml, (float *)&out);
+
+ out_v = mbproc->function(out.x, out.y, out.z);
+
+ /* find "first point" on Implicit Surface of MetaElemnt ml */
+ converge(&in, &out, in_v, out_v, mbproc->function, &mbproc->start, mb, 0);
+
+ /* indexes of CUBE, which includes "first point" */
+ c_i= (int)floor(mbproc->start.x/mbproc->size );
+ c_j= (int)floor(mbproc->start.y/mbproc->size );
+ c_k= (int)floor(mbproc->start.z/mbproc->size );
+
+ mbproc->start.x= mbproc->start.y= mbproc->start.z= 0.0;
+
+ /* add CUBE (with indexes c_i, c_j, c_k) to the stack,
+ * this cube includes found point of Implicit Surface */
+ if (ml->flag & MB_NEGATIVE)
+ add_cube(mbproc, c_i, c_j, c_k, 2);
+ else
+ add_cube(mbproc, c_i, c_j, c_k, 1);
+
+
+ }
+ }
+ }
+ }
+}
+
+void polygonize(PROCESS *mbproc, MetaBall *mb)
+{
+ CUBE c;
+ int a;
+
+ mbproc->vertices.count = mbproc->vertices.max = 0;
+ mbproc->vertices.ptr = NULL;
+
+ /* allocate hash tables and build cube polygon table: */
+ mbproc->centers = MEM_callocN(HASHSIZE * sizeof(CENTERLIST *), "mbproc->centers");
+ mbproc->corners = MEM_callocN(HASHSIZE * sizeof(CORNER *), "mbproc->corners");
+ mbproc->edges = MEM_callocN(2*HASHSIZE * sizeof(EDGELIST *), "mbproc->edges");
+ makecubetable();
+
+ for(a=0; a<totelem; a++) {
+
+ /* try to find 8 points on the surface for each MetaElem */
+ find_first_points(mbproc, mb, a);
+ }
+
+ /* polygonize all MetaElems of current MetaBall */
+ while (mbproc->cubes != NULL) { /* process active cubes till none left */
+ c = mbproc->cubes->cube;
+
+ /* polygonize the cube directly: */
+ docube(&c, mbproc, mb);
+
+ /* pop current cube from stack */
+ mbproc->cubes = mbproc->cubes->next;
+
+ /* test six face directions, maybe add to stack: */
+ testface(c.i-1, c.j, c.k, &c, 2, LBN, LBF, LTN, LTF, mbproc);
+ testface(c.i+1, c.j, c.k, &c, 2, RBN, RBF, RTN, RTF, mbproc);
+ testface(c.i, c.j-1, c.k, &c, 1, LBN, LBF, RBN, RBF, mbproc);
+ testface(c.i, c.j+1, c.k, &c, 1, LTN, LTF, RTN, RTF, mbproc);
+ testface(c.i, c.j, c.k-1, &c, 0, LBN, LTN, RBN, RTN, mbproc);
+ testface(c.i, c.j, c.k+1, &c, 0, LBF, LTF, RBF, RTF, mbproc);
+ }
+}
+
+float init_meta(Object *ob) /* return totsize */
+{
+ Base *base;
+ Object *bob;
+ MetaBall *mb;
+ MetaElem *ml;
+ float size, totsize, (*mat)[4] = NULL, (*imat)[4] = NULL, obinv[4][4], obmat[4][4], vec[3];
+ float temp1[4][4], temp2[4][4], temp3[4][4]; //max=0.0;
+ int a, obnr, zero_size=0;
+ char obname[32];
+
+ Mat4CpyMat4(obmat, ob->obmat); /* to cope with duplicators from next_object */
+ Mat4Invert(obinv, ob->obmat);
+ a= 0;
+
+ splitIDname(ob->id.name+2, obname, &obnr);
+
+ /* make main array */
+
+ next_object(0, 0, 0);
+ while(next_object(1, &base, &bob)) {
+
+ if(bob->type==OB_MBALL) {
+ zero_size= 0;
+ ml= NULL;
+
+ if(bob==ob && (base->flag & OB_FROMDUPLI)==0) {
+ mat= imat= 0;
+ mb= ob->data;
+
+ if(ob==G.obedit) ml= editelems.first;
+ else if(G.obedit && G.obedit->type==OB_MBALL && G.obedit->data==mb) ml= editelems.first;
+ else ml= mb->elems.first;
+ }
+ else {
+ char name[32];
+ int nr;
+
+ splitIDname(bob->id.name+2, name, &nr);
+ if( strcmp(obname, name)==0 ) {
+ mb= bob->data;
+ if(G.obedit && G.obedit->type==OB_MBALL && G.obedit->data==mb)
+ ml= editelems.first;
+ else ml= mb->elems.first;
+ }
+ }
+
+ /* when metaball object hase zero scale, then MetaElem ot this MetaBall
+ * will not be put to mainb array */
+ if(bob->size[0]==0.0 || bob->size[1]==0.0 || bob->size[2]==0.0) {
+ zero_size= 1;
+ }
+ else if(bob->parent) {
+ struct Object *pob=bob->parent;
+ while(pob) {
+ if(pob->size[0]==0.0 || pob->size[1]==0.0 || pob->size[2]==0.0) {
+ zero_size= 1;
+ break;
+ }
+ pob= pob->parent;
+ }
+ }
+
+ if (zero_size) {
+ unsigned int ml_count=0;
+ while(ml) {
+ ml_count++;
+ ml= ml->next;
+ }
+ totelem -= ml_count;
+ }
+ else {
+ while(ml) {
+ if(!(ml->flag & MB_HIDE)) {
+ int i;
+ float max_x, max_y, max_z, min_x, min_y, min_z;
+
+ max_x = max_y = max_z = -3.4e38;
+ min_x = min_y = min_z = 3.4e38;
+
+ /* too big stiffness seems only ugly due to linear interpolation
+ * no need to have possibility for too big stiffness */
+ if(ml->s > 10.0) ml->s = 10.0;
+
+ /* Rotation of MetaElem is stored in quat */
+ QuatToMat4(ml->quat, temp3);
+
+ /* Translation of MetaElem */
+ Mat4One(temp2);
+ temp2[3][0]= ml->x;
+ temp2[3][1]= ml->y;
+ temp2[3][2]= ml->z;
+
+ Mat4MulMat4(temp1, temp3, temp2);
+
+ /* make a copy because of duplicates */
+ mainb[a]= new_pgn_element(sizeof(MetaElem));
+ *(mainb[a])= *ml;
+ mainb[a]->bb = new_pgn_element(sizeof(BoundBox));
+
+ mat= new_pgn_element(4*4*sizeof(float));
+ imat= new_pgn_element(4*4*sizeof(float));
+
+ /* mat is the matrix to transform from mball into the basis-mball */
+ Mat4Invert(obinv, obmat);
+ Mat4MulMat4(temp2, bob->obmat, obinv);
+ /* MetaBall transformation */
+ Mat4MulMat4(mat, temp1, temp2);
+
+ Mat4Invert(imat,mat);
+
+ mainb[a]->rad2= ml->rad*ml->rad;
+
+ mainb[a]->mat= (float*) mat;
+ mainb[a]->imat= (float*) imat;
+
+ /* untransformed Bounding Box of MetaElem */
+ /* 0 */
+ mainb[a]->bb->vec[0][0]= -ml->expx;
+ mainb[a]->bb->vec[0][1]= -ml->expy;
+ mainb[a]->bb->vec[0][2]= -ml->expz;
+ /* 1 */
+ mainb[a]->bb->vec[1][0]= ml->expx;
+ mainb[a]->bb->vec[1][1]= -ml->expy;
+ mainb[a]->bb->vec[1][2]= -ml->expz;
+ /* 2 */
+ mainb[a]->bb->vec[2][0]= ml->expx;
+ mainb[a]->bb->vec[2][1]= ml->expy;
+ mainb[a]->bb->vec[2][2]= -ml->expz;
+ /* 3 */
+ mainb[a]->bb->vec[3][0]= -ml->expx;
+ mainb[a]->bb->vec[3][1]= ml->expy;
+ mainb[a]->bb->vec[3][2]= -ml->expz;
+ /* 4 */
+ mainb[a]->bb->vec[4][0]= -ml->expx;
+ mainb[a]->bb->vec[4][1]= -ml->expy;
+ mainb[a]->bb->vec[4][2]= ml->expz;
+ /* 5 */
+ mainb[a]->bb->vec[5][0]= ml->expx;
+ mainb[a]->bb->vec[5][1]= -ml->expy;
+ mainb[a]->bb->vec[5][2]= ml->expz;
+ /* 6 */
+ mainb[a]->bb->vec[6][0]= ml->expx;
+ mainb[a]->bb->vec[6][1]= ml->expy;
+ mainb[a]->bb->vec[6][2]= ml->expz;
+ /* 7 */
+ mainb[a]->bb->vec[7][0]= -ml->expx;
+ mainb[a]->bb->vec[7][1]= ml->expy;
+ mainb[a]->bb->vec[7][2]= ml->expz;
+
+ /* transformation of Metalem bb */
+ for(i=0; i<8; i++)
+ Mat4MulVecfl((float ( * )[4])mat, mainb[a]->bb->vec[i]);
+
+ /* find max and min of transformed bb */
+ for(i=0; i<8; i++){
+ /* find maximums */
+ if(mainb[a]->bb->vec[i][0] > max_x) max_x = mainb[a]->bb->vec[i][0];
+ if(mainb[a]->bb->vec[i][1] > max_y) max_y = mainb[a]->bb->vec[i][1];
+ if(mainb[a]->bb->vec[i][2] > max_z) max_z = mainb[a]->bb->vec[i][2];
+ /* find minimums */
+ if(mainb[a]->bb->vec[i][0] < min_x) min_x = mainb[a]->bb->vec[i][0];
+ if(mainb[a]->bb->vec[i][1] < min_y) min_y = mainb[a]->bb->vec[i][1];
+ if(mainb[a]->bb->vec[i][2] < min_z) min_z = mainb[a]->bb->vec[i][2];
+ }
+
+ /* create "new" bb, only point 0 and 6, which are
+ * neccesary for octal tree filling */
+ mainb[a]->bb->vec[0][0] = min_x - ml->rad;
+ mainb[a]->bb->vec[0][1] = min_y - ml->rad;
+ mainb[a]->bb->vec[0][2] = min_z - ml->rad;
+
+ mainb[a]->bb->vec[6][0] = max_x + ml->rad;
+ mainb[a]->bb->vec[6][1] = max_y + ml->rad;
+ mainb[a]->bb->vec[6][2] = max_z + ml->rad;
+
+ a++;
+ }
+ ml= ml->next;
+ }
+ }
+ }
+ }
+
+
+ /* totsize (= 'manhattan' radius) */
+ totsize= 0.0;
+ for(a=0; a<totelem; a++) {
+
+ vec[0]= mainb[a]->x + mainb[a]->rad + mainb[a]->expx;
+ vec[1]= mainb[a]->y + mainb[a]->rad + mainb[a]->expy;
+ vec[2]= mainb[a]->z + mainb[a]->rad + mainb[a]->expz;
+
+ calc_mballco(mainb[a], vec);
+
+ size= (float)fabs( vec[0] );
+ if( size > totsize ) totsize= size;
+ size= (float)fabs( vec[1] );
+ if( size > totsize ) totsize= size;
+ size= (float)fabs( vec[2] );
+ if( size > totsize ) totsize= size;
+
+ vec[0]= mainb[a]->x - mainb[a]->rad;
+ vec[1]= mainb[a]->y - mainb[a]->rad;
+ vec[2]= mainb[a]->z - mainb[a]->rad;
+
+ calc_mballco(mainb[a], vec);
+
+ size= (float)fabs( vec[0] );
+ if( size > totsize ) totsize= size;
+ size= (float)fabs( vec[1] );
+ if( size > totsize ) totsize= size;
+ size= (float)fabs( vec[2] );
+ if( size > totsize ) totsize= size;
+ }
+
+ for(a=0; a<totelem; a++) {
+ thresh+= densfunc( mainb[a], 2.0f*totsize, 2.0f*totsize, 2.0f*totsize);
+ }
+
+ return totsize;
+}
+
+/* if MetaElem lies in node, then node includes MetaElem pointer (ml_p)
+ * pointing at MetaElem (ml)
+ */
+void fill_metaball_octal_node(octal_node *node, MetaElem *ml, short i)
+{
+ ml_pointer *ml_p;
+
+ ml_p= MEM_mallocN(sizeof(ml_pointer), "ml_pointer");
+ ml_p->ml= ml;
+ BLI_addtail(&(node->nodes[i]->elems), ml_p);
+ node->count++;
+
+ if(ml->flag & MB_NEGATIVE) {
+ node->nodes[i]->neg++;
+ }
+ else{
+ node->nodes[i]->pos++;
+ }
+}
+
+/* Node is subdivided as is ilustrated on the following figure:
+ *
+ * +------+------+
+ * / / /|
+ * +------+------+ |
+ * / / /| +
+ * +------+------+ |/|
+ * | | | + |
+ * | | |/| +
+ * +------+------+ |/
+ * | | | +
+ * | | |/
+ * +------+------+
+ *
+ */
+void subdivide_metaball_octal_node(octal_node *node, float *size, short depth)
+{
+ MetaElem *ml;
+ ml_pointer *ml_p;
+ float x,y,z;
+ int a,i;
+
+ if(depth==0) return;
+
+ /* create new nodes */
+ for(a=0;a<8;a++){
+ node->nodes[a]= MEM_mallocN(sizeof(octal_node),"octal_node");
+ for(i=0;i<8;i++)
+ node->nodes[a]->nodes[i]= NULL;
+ node->nodes[a]->parent= node;
+ node->nodes[a]->elems.first= NULL;
+ node->nodes[a]->elems.last= NULL;
+ node->nodes[a]->count= 0;
+ node->nodes[a]->neg= 0;
+ node->nodes[a]->pos= 0;
+ }
+
+ size[0]/=2; size[1]/=2; size[2]/=2;
+
+ /* center of node */
+ node->x= x= node->x_min + size[0];
+ node->y= y= node->y_min + size[1];
+ node->z= z= node->z_min + size[2];
+
+ /* setting up of border points of new nodes */
+ node->nodes[0]->x_min= node->x_min;
+ node->nodes[0]->y_min= node->y_min;
+ node->nodes[0]->z_min= node->z_min;
+
+ node->nodes[1]->x_min= x;
+ node->nodes[1]->y_min= node->y_min;
+ node->nodes[1]->z_min= node->z_min;
+
+ node->nodes[2]->x_min= x;
+ node->nodes[2]->y_min= y;
+ node->nodes[2]->z_min= node->z_min;
+
+ node->nodes[3]->x_min= node->x_min;
+ node->nodes[3]->y_min= y;
+ node->nodes[3]->z_min= node->z_min;
+
+ node->nodes[4]->x_min= node->x_min;
+ node->nodes[4]->y_min= node->y_min;
+ node->nodes[4]->z_min= z;
+
+ node->nodes[5]->x_min= x;
+ node->nodes[5]->y_min= node->y_min;
+ node->nodes[5]->z_min= z;
+
+ node->nodes[6]->x_min= x;
+ node->nodes[6]->y_min= y;
+ node->nodes[6]->z_min= z;
+
+ node->nodes[7]->x_min= node->x_min;
+ node->nodes[7]->y_min= y;
+ node->nodes[7]->z_min= z;
+
+ ml_p= node->elems.first;
+
+ /* setting up references of MetaElems for new nodes */
+ while(ml_p){
+ ml= ml_p->ml;
+ if(ml->bb->vec[0][2] < z){
+ if(ml->bb->vec[0][1] < y){
+ /* vec[0][0] lies in first octant */
+ if(ml->bb->vec[0][0] < x){
+ /* ml belongs to the (0)1st node */
+ fill_metaball_octal_node(node, ml, 0);
+
+ /* ml belongs to the (3)4th node */
+ if(ml->bb->vec[6][1] >= y){
+ fill_metaball_octal_node(node, ml, 3);
+
+ /* ml belongs to the (7)8th node */
+ if(ml->bb->vec[6][2] >= z){
+ fill_metaball_octal_node(node, ml, 7);
+ }
+ }
+
+ /* ml belongs to the (1)2nd node */
+ if(ml->bb->vec[6][0] >= x){
+ fill_metaball_octal_node(node, ml, 1);
+
+ /* ml belongs to the (5)6th node */
+ if(ml->bb->vec[6][2] >= z){
+ fill_metaball_octal_node(node, ml, 5);
+ }
+ }
+
+ /* ml belongs to the (2)3th node */
+ if((ml->bb->vec[6][0] >= x) && (ml->bb->vec[6][1] >= y)){
+ fill_metaball_octal_node(node, ml, 2);
+
+ /* ml belong to the (6)7th node */
+ if(ml->bb->vec[6][2] >= z){
+ fill_metaball_octal_node(node, ml, 6);
+ }
+
+ }
+
+ /* ml belongs to the (4)5th node too */
+ if(ml->bb->vec[6][2] >= z){
+ fill_metaball_octal_node(node, ml, 4);
+ }
+
+
+
+ }
+ /* vec[0][0] is in the (1)second octant */
+ else{
+ /* ml belong to the (1)2nd node */
+ fill_metaball_octal_node(node, ml, 1);
+
+ /* ml belongs to the (2)3th node */
+ if(ml->bb->vec[6][1] >= y){
+ fill_metaball_octal_node(node, ml, 2);
+
+ /* ml belongs to the (6)7th node */
+ if(ml->bb->vec[6][2] >= z){
+ fill_metaball_octal_node(node, ml, 6);
+ }
+
+ }
+
+ /* ml belongs to the (5)6th node */
+ if(ml->bb->vec[6][2] >= z){
+ fill_metaball_octal_node(node, ml, 5);
+ }
+ }
+ }
+ else{
+ /* vec[0][0] is in the (3)4th octant */
+ if(ml->bb->vec[0][0] < x){
+ /* ml belongs to the (3)4nd node */
+ fill_metaball_octal_node(node, ml, 3);
+
+ /* ml belongs to the (7)8th node */
+ if(ml->bb->vec[6][2] >= z){
+ fill_metaball_octal_node(node, ml, 7);
+ }
+
+
+ /* ml belongs to the (2)3th node */
+ if(ml->bb->vec[6][0] >= x){
+ fill_metaball_octal_node(node, ml, 2);
+
+ /* ml belongs to the (6)7th node */
+ if(ml->bb->vec[6][2] >= z){
+ fill_metaball_octal_node(node, ml, 6);
+ }
+ }
+ }
+
+ }
+
+ /* vec[0][0] is in the (2)3th octant */
+ if((ml->bb->vec[0][0] >= x) && (ml->bb->vec[0][1] >= y)){
+ /* ml belongs to the (2)3th node */
+ fill_metaball_octal_node(node, ml, 2);
+
+ /* ml belongs to the (6)7th node */
+ if(ml->bb->vec[6][2] >= z){
+ fill_metaball_octal_node(node, ml, 6);
+ }
+ }
+ }
+ else{
+ if(ml->bb->vec[0][1] < y){
+ /* vec[0][0] lies in (4)5th octant */
+ if(ml->bb->vec[0][0] < x){
+ /* ml belongs to the (4)5th node */
+ fill_metaball_octal_node(node, ml, 4);
+
+ if(ml->bb->vec[6][0] >= x){
+ fill_metaball_octal_node(node, ml, 5);
+ }
+
+ if(ml->bb->vec[6][1] >= y){
+ fill_metaball_octal_node(node, ml, 7);
+ }
+
+ if((ml->bb->vec[6][0] >= x) && (ml->bb->vec[6][1] >= y)){
+ fill_metaball_octal_node(node, ml, 6);
+ }
+ }
+ /* vec[0][0] lies in (5)6th octant */
+ else{
+ fill_metaball_octal_node(node, ml, 5);
+
+ if(ml->bb->vec[6][1] >= y){
+ fill_metaball_octal_node(node, ml, 6);
+ }
+ }
+ }
+ else{
+ /* vec[0][0] lies in (7)8th octant */
+ if(ml->bb->vec[0][0] < x){
+ fill_metaball_octal_node(node, ml, 7);
+
+ if(ml->bb->vec[6][0] >= x){
+ fill_metaball_octal_node(node, ml, 6);
+ }
+ }
+
+ }
+
+ /* vec[0][0] lies in (6)7th octant */
+ if((ml->bb->vec[0][0] >= x) && (ml->bb->vec[0][1] >= y)){
+ fill_metaball_octal_node(node, ml, 6);
+ }
+ }
+ ml_p= ml_p->next;
+ }
+
+ /* free references of MetaElems for curent node (it is not needed anymore) */
+ BLI_freelistN(&node->elems);
+
+ depth--;
+
+ if(depth>0){
+ for(a=0;a<8;a++){
+ if(node->nodes[a]->count > 0) /* if node is not empty, then it is subdivided */
+ subdivide_metaball_octal_node(node->nodes[a], size, depth);
+ }
+ }
+}
+
+/* free all octal nodes recursively */
+void free_metaball_octal_node(octal_node *node)
+{
+ int a;
+ for(a=0;a<8;a++){
+ if(node->nodes[a]!=NULL) free_metaball_octal_node(node->nodes[a]);
+ }
+ BLI_freelistN(&node->elems);
+ MEM_freeN(node);
+}
+
+/* If scene include more then one MetaElem, then octree is used */
+void init_metaball_octal_tree(int depth)
+{
+ struct octal_node *node;
+ ml_pointer *ml_p;
+ float size[3];
+ int a;
+
+ metaball_tree= MEM_mallocN(sizeof(octal_tree), "metaball_octal_tree");
+ metaball_tree->first= node= MEM_mallocN(sizeof(octal_node), "metaball_octal_node");
+ /* maximal depth of octree */
+ metaball_tree->depth= depth;
+
+ metaball_tree->neg= node->neg=0;
+ metaball_tree->pos= node->pos=0;
+
+ node->elems.first= NULL;
+ node->elems.last= NULL;
+ node->count=0;
+
+ for(a=0;a<8;a++)
+ node->nodes[a]=NULL;
+
+ node->x_min= node->y_min= node->z_min= FLT_MAX;
+ node->x_max= node->y_max= node->z_max= -FLT_MAX;
+
+ /* size of octal tree scene */
+ for(a=0;a<totelem;a++) {
+ if(mainb[a]->bb->vec[0][0] < node->x_min) node->x_min= mainb[a]->bb->vec[0][0];
+ if(mainb[a]->bb->vec[0][1] < node->y_min) node->y_min= mainb[a]->bb->vec[0][1];
+ if(mainb[a]->bb->vec[0][2] < node->z_min) node->z_min= mainb[a]->bb->vec[0][2];
+
+ if(mainb[a]->bb->vec[6][0] > node->x_max) node->x_max= mainb[a]->bb->vec[6][0];
+ if(mainb[a]->bb->vec[6][1] > node->y_max) node->y_max= mainb[a]->bb->vec[6][1];
+ if(mainb[a]->bb->vec[6][2] > node->z_max) node->z_max= mainb[a]->bb->vec[6][2];
+
+ ml_p= MEM_mallocN(sizeof(ml_pointer), "ml_pointer");
+ ml_p->ml= mainb[a];
+ BLI_addtail(&node->elems, ml_p);
+
+ if(mainb[a]->flag & MB_NEGATIVE) {
+ /* number of negative MetaElem in scene */
+ metaball_tree->neg++;
+ }
+ else{
+ /* number of positive MetaElem in scene */
+ metaball_tree->pos++;
+ }
+ }
+
+ /* size of first node */
+ size[0]= node->x_max - node->x_min;
+ size[1]= node->y_max - node->y_min;
+ size[2]= node->z_max - node->z_min;
+
+ /* first node is subdivided recursively */
+ subdivide_metaball_octal_node(node, size, metaball_tree->depth);
+}
+
+void metaball_polygonize(Object *ob)
+{
+ PROCESS mbproc;
+ MetaBall *mb;
+ DispList *dl;
+ int a, nr_cubes;
+ float *ve, *no, totsize, width;
+
+ mb= ob->data;
+
+ if(totelem==0) return;
+ if(!(G.rendering) && (mb->flag==MB_UPDATE_NEVER)) return;
+ if(G.moving && mb->flag==MB_UPDATE_FAST) return;
+
+ freedisplist(&ob->disp);
+ curindex= totindex= 0;
+ indices= 0;
+ thresh= mb->thresh;
+
+ /* total number of MetaElems (totelem) is precomputed in find_basis_mball() function */
+ mainb= MEM_mallocN(sizeof(void *)*totelem, "mainb");
+
+ /* initialize all mainb (MetaElems) */
+ totsize= init_meta(ob);
+
+ if(metaball_tree){
+ free_metaball_octal_node(metaball_tree->first);
+ MEM_freeN(metaball_tree);
+ metaball_tree= NULL;
+ }
+
+ /* if scene includes more then one MetaElem, then octal tree optimalisation is used */
+ if((totelem > 1) && (totelem <= 64)) init_metaball_octal_tree(1);
+ if((totelem > 64) && (totelem <= 128)) init_metaball_octal_tree(2);
+ if((totelem > 128) && (totelem <= 512)) init_metaball_octal_tree(3);
+ if((totelem > 512) && (totelem <= 1024)) init_metaball_octal_tree(4);
+ if(totelem > 1024) init_metaball_octal_tree(5);
+
+ /* don't polygonize metaballs with too high resolution (base mball to small) */
+ if(metaball_tree) {
+ if(ob->size[0]<=0.0001f*(metaball_tree->first->x_max - metaball_tree->first->x_min) ||
+ ob->size[1]<=0.0001f*(metaball_tree->first->y_max - metaball_tree->first->y_min) ||
+ ob->size[2]<=0.0001f*(metaball_tree->first->z_max - metaball_tree->first->z_min))
+ {
+ MEM_freeN(mainb);
+ return;
+ }
+ }
+
+ /* width is size per polygonize cube */
+ if(G.rendering) width= mb->rendersize;
+ else {
+ width= mb->wiresize;
+ if(G.moving && mb->flag==MB_UPDATE_HALFRES) width*= 2;
+ }
+ /* nr_cubes is just for safety, minimum is totsize */
+ nr_cubes= (int)(0.5+totsize/width);
+
+ /* init process */
+ mbproc.function = metaball;
+ mbproc.size = width;
+ mbproc.bounds = nr_cubes;
+ mbproc.cubes= 0;
+ mbproc.delta = width/(float)(RES*RES);
+
+ polygonize(&mbproc, mb);
+
+ MEM_freeN(mainb);
+
+ /* free octal tree */
+ if(totelem > 1){
+ free_metaball_octal_node(metaball_tree->first);
+ MEM_freeN(metaball_tree);
+ metaball_tree= NULL;
+ }
+
+ if(curindex) {
+
+ dl= MEM_callocN(sizeof(DispList), "mbaldisp");
+ BLI_addtail(&ob->disp, dl);
+ dl->type= DL_INDEX4;
+ dl->nr= mbproc.vertices.count;
+ dl->parts= curindex;
+
+ dl->index= indices;
+ indices= 0;
+
+ a= mbproc.vertices.count;
+ dl->verts= ve= MEM_mallocN(sizeof(float)*3*a, "mballverts");
+ dl->nors= no= MEM_mallocN(sizeof(float)*3*a, "mballnors");
+
+ for(a=0; a<mbproc.vertices.count; a++, no+=3, ve+=3) {
+ ve[0]= mbproc.vertices.ptr[a].position.x;
+ ve[1]= mbproc.vertices.ptr[a].position.y;
+ ve[2]= mbproc.vertices.ptr[a].position.z;
+
+ no[0]= mbproc.vertices.ptr[a].normal.x;
+ no[1]= mbproc.vertices.ptr[a].normal.y;
+ no[2]= mbproc.vertices.ptr[a].normal.z;
+ }
+ }
+
+ freepolygonize(&mbproc);
+}
+
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
new file mode 100644
index 00000000000..4e551e28885
--- /dev/null
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -0,0 +1,1250 @@
+
+/* mesh.c
+ *
+ *
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_ID.h"
+#include "DNA_curve_types.h"
+#include "DNA_material_types.h"
+#include "DNA_object_types.h"
+#include "DNA_image_types.h"
+#include "DNA_key_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_ipo_types.h"
+
+#include "BDR_sculptmode.h"
+
+#include "BKE_customdata.h"
+#include "BKE_depsgraph.h"
+#include "BKE_main.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_global.h"
+#include "BKE_mesh.h"
+#include "BKE_subsurf.h"
+#include "BKE_displist.h"
+#include "BKE_library.h"
+#include "BKE_material.h"
+#include "BKE_key.h"
+/* these 2 are only used by conversion functions */
+#include "BKE_curve.h"
+/* -- */
+#include "BKE_object.h"
+#include "BKE_utildefines.h"
+#include "BKE_bad_level_calls.h"
+
+#ifdef WITH_VERSE
+#include "BKE_verse.h"
+#endif
+
+#include "BLI_blenlib.h"
+#include "BLI_editVert.h"
+#include "BLI_arithb.h"
+
+#include "multires.h"
+
+int update_realtime_texture(MTFace *tface, double time)
+{
+ Image *ima;
+ int inc = 0;
+ float diff;
+ int newframe;
+
+ ima = tface->tpage;
+
+ if (!ima)
+ return 0;
+
+ if (ima->lastupdate<0)
+ ima->lastupdate = 0;
+
+ if (ima->lastupdate>time)
+ ima->lastupdate=(float)time;
+
+ if(ima->tpageflag & IMA_TWINANIM) {
+ if(ima->twend >= ima->xrep*ima->yrep) ima->twend= ima->xrep*ima->yrep-1;
+
+ /* check: is the bindcode not in the array? Then free. (still to do) */
+
+ diff = (float)(time-ima->lastupdate);
+
+ inc = (int)(diff*(float)ima->animspeed);
+
+ ima->lastupdate+=((float)inc/(float)ima->animspeed);
+
+ newframe = ima->lastframe+inc;
+
+ if (newframe > (int)ima->twend)
+ newframe = (int)ima->twsta-1 + (newframe-ima->twend)%(ima->twend-ima->twsta);
+
+ ima->lastframe = newframe;
+ }
+ return inc;
+}
+
+void mesh_update_customdata_pointers(Mesh *me)
+{
+ me->mvert = CustomData_get_layer(&me->vdata, CD_MVERT);
+ me->dvert = CustomData_get_layer(&me->vdata, CD_MDEFORMVERT);
+ me->msticky = CustomData_get_layer(&me->vdata, CD_MSTICKY);
+
+ me->medge = CustomData_get_layer(&me->edata, CD_MEDGE);
+
+ me->mface = CustomData_get_layer(&me->fdata, CD_MFACE);
+ me->mcol = CustomData_get_layer(&me->fdata, CD_MCOL);
+ me->mtface = CustomData_get_layer(&me->fdata, CD_MTFACE);
+}
+
+/* Note: unlinking is called when me->id.us is 0, question remains how
+ * much unlinking of Library data in Mesh should be done... probably
+ * we need a more generic method, like the expand() functions in
+ * readfile.c */
+
+void unlink_mesh(Mesh *me)
+{
+ int a;
+
+ if(me==0) return;
+
+ for(a=0; a<me->totcol; a++) {
+ if(me->mat[a]) me->mat[a]->id.us--;
+ me->mat[a]= 0;
+ }
+
+ if(me->key) {
+ me->key->id.us--;
+ if (me->key->id.us == 0 && me->key->ipo )
+ me->key->ipo->id.us--;
+ }
+ me->key= 0;
+
+ if(me->texcomesh) me->texcomesh= 0;
+}
+
+
+/* do not free mesh itself */
+void free_mesh(Mesh *me)
+{
+ unlink_mesh(me);
+
+ if(me->pv) {
+ if(me->pv->vert_map) MEM_freeN(me->pv->vert_map);
+ if(me->pv->edge_map) MEM_freeN(me->pv->edge_map);
+ if(me->pv->old_faces) MEM_freeN(me->pv->old_faces);
+ if(me->pv->old_edges) MEM_freeN(me->pv->old_edges);
+ me->totvert= me->pv->totvert;
+ me->totedge= me->pv->totedge;
+ me->totface= me->pv->totface;
+ MEM_freeN(me->pv);
+ }
+
+ CustomData_free(&me->vdata, me->totvert);
+ CustomData_free(&me->edata, me->totedge);
+ CustomData_free(&me->fdata, me->totface);
+
+ if(me->mat) MEM_freeN(me->mat);
+
+ if(me->bb) MEM_freeN(me->bb);
+ if(me->mselect) MEM_freeN(me->mselect);
+
+ if(me->mr) multires_free(me->mr);
+}
+
+void copy_dverts(MDeformVert *dst, MDeformVert *src, int copycount)
+{
+ /* Assumes dst is already set up */
+ int i;
+
+ if (!src || !dst)
+ return;
+
+ memcpy (dst, src, copycount * sizeof(MDeformVert));
+
+ for (i=0; i<copycount; i++){
+ if (src[i].dw){
+ dst[i].dw = MEM_callocN (sizeof(MDeformWeight)*src[i].totweight, "copy_deformWeight");
+ memcpy (dst[i].dw, src[i].dw, sizeof (MDeformWeight)*src[i].totweight);
+ }
+ }
+
+}
+
+void free_dverts(MDeformVert *dvert, int totvert)
+{
+ /* Instead of freeing the verts directly,
+ call this function to delete any special
+ vert data */
+ int i;
+
+ if (!dvert)
+ return;
+
+ /* Free any special data from the verts */
+ for (i=0; i<totvert; i++){
+ if (dvert[i].dw) MEM_freeN (dvert[i].dw);
+ }
+ MEM_freeN (dvert);
+}
+
+Mesh *add_mesh(char *name)
+{
+ Mesh *me;
+
+ me= alloc_libblock(&G.main->mesh, ID_ME, name);
+
+ me->size[0]= me->size[1]= me->size[2]= 1.0;
+ me->smoothresh= 30;
+ me->texflag= AUTOSPACE;
+ me->flag= ME_TWOSIDED;
+ me->bb= unit_boundbox();
+
+#ifdef WITH_VERSE
+ me->vnode = NULL;
+#endif
+
+ return me;
+}
+
+Mesh *copy_mesh(Mesh *me)
+{
+ Mesh *men;
+ MTFace *tface;
+ int a, i;
+
+ men= copy_libblock(me);
+
+ men->mat= MEM_dupallocN(me->mat);
+ for(a=0; a<men->totcol; a++) {
+ id_us_plus((ID *)men->mat[a]);
+ }
+ id_us_plus((ID *)men->texcomesh);
+
+ CustomData_copy(&me->vdata, &men->vdata, CD_MASK_MESH, CD_DUPLICATE, men->totvert);
+ CustomData_copy(&me->edata, &men->edata, CD_MASK_MESH, CD_DUPLICATE, men->totedge);
+ CustomData_copy(&me->fdata, &men->fdata, CD_MASK_MESH, CD_DUPLICATE, men->totface);
+ mesh_update_customdata_pointers(men);
+
+ /* ensure indirect linked data becomes lib-extern */
+ for(i=0; i<me->fdata.totlayer; i++) {
+ if(me->fdata.layers[i].type == CD_MTFACE) {
+ tface= (MTFace*)me->fdata.layers[i].data;
+
+ for(a=0; a<me->totface; a++, tface++)
+ if(tface->tpage)
+ id_lib_extern((ID*)tface->tpage);
+ }
+ }
+
+ if(me->mr)
+ men->mr= multires_copy(me->mr);
+
+ men->mselect= NULL;
+
+ men->bb= MEM_dupallocN(men->bb);
+
+ men->key= copy_key(me->key);
+ if(men->key) men->key->from= (ID *)men;
+
+#ifdef WITH_VERSE
+ men->vnode = NULL;
+#endif
+
+ return men;
+}
+
+void make_local_tface(Mesh *me)
+{
+ MTFace *tface;
+ Image *ima;
+ int a, i;
+
+ for(i=0; i<me->fdata.totlayer; i++) {
+ if(me->fdata.layers[i].type == CD_MTFACE) {
+ tface= (MTFace*)me->fdata.layers[i].data;
+
+ for(a=0; a<me->totface; a++, tface++) {
+ /* special case: ima always local immediately */
+ if(tface->tpage) {
+ ima= tface->tpage;
+ if(ima->id.lib) {
+ ima->id.lib= 0;
+ ima->id.flag= LIB_LOCAL;
+ new_id(0, (ID *)ima, 0);
+ }
+ }
+ }
+ }
+ }
+}
+
+void make_local_mesh(Mesh *me)
+{
+ Object *ob;
+ Mesh *men;
+ int local=0, lib=0;
+
+ /* - only lib users: do nothing
+ * - only local users: set flag
+ * - mixed: make copy
+ */
+
+ if(me->id.lib==0) return;
+ if(me->id.us==1) {
+ me->id.lib= 0;
+ me->id.flag= LIB_LOCAL;
+ new_id(0, (ID *)me, 0);
+
+ if(me->mtface) make_local_tface(me);
+
+ return;
+ }
+
+ ob= G.main->object.first;
+ while(ob) {
+ if( me==get_mesh(ob) ) {
+ if(ob->id.lib) lib= 1;
+ else local= 1;
+ }
+ ob= ob->id.next;
+ }
+
+ if(local && lib==0) {
+ me->id.lib= 0;
+ me->id.flag= LIB_LOCAL;
+ new_id(0, (ID *)me, 0);
+
+ if(me->mtface) make_local_tface(me);
+
+ }
+ else if(local && lib) {
+ men= copy_mesh(me);
+ men->id.us= 0;
+
+ ob= G.main->object.first;
+ while(ob) {
+ if( me==get_mesh(ob) ) {
+ if(ob->id.lib==0) {
+ set_mesh(ob, men);
+ }
+ }
+ ob= ob->id.next;
+ }
+ }
+}
+
+void boundbox_mesh(Mesh *me, float *loc, float *size)
+{
+ MVert *mvert;
+ BoundBox *bb;
+ float min[3], max[3];
+ float mloc[3], msize[3];
+ int a;
+
+ if(me->bb==0) me->bb= MEM_callocN(sizeof(BoundBox), "boundbox");
+ bb= me->bb;
+
+ INIT_MINMAX(min, max);
+
+ if (!loc) loc= mloc;
+ if (!size) size= msize;
+
+ mvert= me->mvert;
+ for(a=0; a<me->totvert; a++, mvert++) {
+ DO_MINMAX(mvert->co, min, max);
+ }
+
+ if(!me->totvert) {
+ min[0] = min[1] = min[2] = -1.0f;
+ max[0] = max[1] = max[2] = 1.0f;
+ }
+
+ loc[0]= (min[0]+max[0])/2.0f;
+ loc[1]= (min[1]+max[1])/2.0f;
+ loc[2]= (min[2]+max[2])/2.0f;
+
+ size[0]= (max[0]-min[0])/2.0f;
+ size[1]= (max[1]-min[1])/2.0f;
+ size[2]= (max[2]-min[2])/2.0f;
+
+ boundbox_set_from_min_max(bb, min, max);
+}
+
+void tex_space_mesh(Mesh *me)
+{
+ KeyBlock *kb;
+ float *fp, loc[3], size[3], min[3], max[3];
+ int a;
+
+ boundbox_mesh(me, loc, size);
+
+ if(me->texflag & AUTOSPACE) {
+ if(me->key) {
+ kb= me->key->refkey;
+ if (kb) {
+
+ INIT_MINMAX(min, max);
+
+ fp= kb->data;
+ for(a=0; a<kb->totelem; a++, fp+=3) {
+ DO_MINMAX(fp, min, max);
+ }
+ if(kb->totelem) {
+ loc[0]= (min[0]+max[0])/2.0f; loc[1]= (min[1]+max[1])/2.0f; loc[2]= (min[2]+max[2])/2.0f;
+ size[0]= (max[0]-min[0])/2.0f; size[1]= (max[1]-min[1])/2.0f; size[2]= (max[2]-min[2])/2.0f;
+ }
+ else {
+ loc[0]= loc[1]= loc[2]= 0.0;
+ size[0]= size[1]= size[2]= 0.0;
+ }
+
+ }
+ }
+
+ for (a=0; a<3; a++) {
+ if(size[a]==0.0) size[a]= 1.0;
+ else if(size[a]>0.0 && size[a]<0.00001) size[a]= 0.00001;
+ else if(size[a]<0.0 && size[a]> -0.00001) size[a]= -0.00001;
+ }
+
+ VECCOPY(me->loc, loc);
+ VECCOPY(me->size, size);
+ me->rot[0]= me->rot[1]= me->rot[2]= 0.0;
+ }
+}
+
+BoundBox *mesh_get_bb(Mesh *me)
+{
+ if (!me->bb) {
+ tex_space_mesh(me);
+ }
+
+ return me->bb;
+}
+
+void mesh_get_texspace(Mesh *me, float *loc_r, float *rot_r, float *size_r)
+{
+ if (!me->bb) {
+ tex_space_mesh(me);
+ }
+
+ if (loc_r) VECCOPY(loc_r, me->loc);
+ if (rot_r) VECCOPY(rot_r, me->rot);
+ if (size_r) VECCOPY(size_r, me->size);
+}
+
+static float *make_orco_mesh_internal(Object *ob, int render)
+{
+ Mesh *me = ob->data;
+ float (*orcoData)[3];
+ int a, totvert;
+ float loc[3], size[3];
+ DerivedMesh *dm;
+ float (*vcos)[3] = NULL;
+
+ /* Get appropriate vertex coordinates */
+
+ if(me->key && me->texcomesh==0 && me->key->refkey) {
+ vcos= mesh_getRefKeyCos(me, &totvert);
+ }
+ else {
+ MultiresLevel *lvl = NULL;
+ MVert *mvert = NULL;
+
+ if(me->mr) {
+ lvl = multires_level_n(me->mr, me->mr->pinlvl);
+ vcos = MEM_callocN(sizeof(*vcos)*lvl->totvert, "orco mr mesh");
+ mvert = me->mr->verts;
+ totvert = lvl->totvert;
+ }
+ else {
+ Mesh *tme = me->texcomesh?me->texcomesh:me;
+ vcos = MEM_callocN(sizeof(*vcos)*me->totvert, "orco mesh");
+ mvert = tme->mvert;
+ totvert = MIN2(tme->totvert, me->totvert);
+ }
+
+ for(a=0; a<totvert; a++, mvert++) {
+ vcos[a][0]= mvert->co[0];
+ vcos[a][1]= mvert->co[1];
+ vcos[a][2]= mvert->co[2];
+ }
+ }
+
+ /* Apply orco-changing modifiers */
+
+ if (render) {
+ dm = mesh_create_derived_no_deform_render(ob, vcos, CD_MASK_BAREMESH);
+ } else {
+ dm = mesh_create_derived_no_deform(ob, vcos, CD_MASK_BAREMESH);
+ }
+ totvert = dm->getNumVerts(dm);
+
+ orcoData = MEM_mallocN(sizeof(*orcoData)*totvert, "orcoData");
+ dm->getVertCos(dm, orcoData);
+ dm->release(dm);
+ MEM_freeN(vcos);
+
+ mesh_get_texspace(me->texcomesh?me->texcomesh:me, loc, NULL, size);
+
+ for(a=0; a<totvert; a++) {
+ float *co = orcoData[a];
+ co[0] = (co[0]-loc[0])/size[0];
+ co[1] = (co[1]-loc[1])/size[1];
+ co[2] = (co[2]-loc[2])/size[2];
+ }
+
+ return (float*) orcoData;
+}
+
+float *mesh_create_orco_render(Object *ob)
+{
+ return make_orco_mesh_internal(ob, 1);
+}
+
+float *mesh_create_orco(Object *ob)
+{
+ return make_orco_mesh_internal(ob, 0);
+}
+
+/* rotates the vertices of a face in case v[2] or v[3] (vertex index) is = 0.
+ this is necessary to make the if(mface->v4) check for quads work */
+void test_index_face(MFace *mface, CustomData *fdata, int mfindex, int nr)
+{
+ /* first test if the face is legal */
+ if(mface->v3 && mface->v3==mface->v4) {
+ mface->v4= 0;
+ nr--;
+ }
+ if(mface->v2 && mface->v2==mface->v3) {
+ mface->v3= mface->v4;
+ mface->v4= 0;
+ nr--;
+ }
+ if(mface->v1==mface->v2) {
+ mface->v2= mface->v3;
+ mface->v3= mface->v4;
+ mface->v4= 0;
+ nr--;
+ }
+
+ /* prevent a zero at wrong index location */
+ if(nr==3) {
+ if(mface->v3==0) {
+ static int corner_indices[4] = {1, 2, 0, 3};
+
+ SWAP(int, mface->v1, mface->v2);
+ SWAP(int, mface->v2, mface->v3);
+
+ if(fdata)
+ CustomData_swap(fdata, mfindex, corner_indices);
+ }
+ }
+ else if(nr==4) {
+ if(mface->v3==0 || mface->v4==0) {
+ static int corner_indices[4] = {2, 3, 0, 1};
+
+ SWAP(int, mface->v1, mface->v3);
+ SWAP(int, mface->v2, mface->v4);
+
+ if(fdata)
+ CustomData_swap(fdata, mfindex, corner_indices);
+ }
+ }
+}
+
+Mesh *get_mesh(Object *ob)
+{
+
+ if(ob==0) return 0;
+ if(ob->type==OB_MESH) return ob->data;
+ else return 0;
+}
+
+void set_mesh(Object *ob, Mesh *me)
+{
+ Mesh *old=0;
+
+ if(ob==0) return;
+
+ if(ob->type==OB_MESH) {
+ old= ob->data;
+ old->id.us--;
+ ob->data= me;
+ id_us_plus((ID *)me);
+ }
+
+ test_object_materials((ID *)me);
+}
+
+/* ************** make edges in a Mesh, for outside of editmode */
+
+struct edgesort {
+ int v1, v2;
+ short is_loose, is_draw;
+};
+
+/* edges have to be added with lowest index first for sorting */
+static void to_edgesort(struct edgesort *ed, int v1, int v2, short is_loose, short is_draw)
+{
+ if(v1<v2) {
+ ed->v1= v1; ed->v2= v2;
+ }
+ else {
+ ed->v1= v2; ed->v2= v1;
+ }
+ ed->is_loose= is_loose;
+ ed->is_draw= is_draw;
+}
+
+static int vergedgesort(const void *v1, const void *v2)
+{
+ const struct edgesort *x1=v1, *x2=v2;
+
+ if( x1->v1 > x2->v1) return 1;
+ else if( x1->v1 < x2->v1) return -1;
+ else if( x1->v2 > x2->v2) return 1;
+ else if( x1->v2 < x2->v2) return -1;
+
+ return 0;
+}
+
+void make_edges(Mesh *me, int old)
+{
+ MFace *mface;
+ MEdge *medge;
+ struct edgesort *edsort, *ed;
+ int a, totedge=0, final=0;
+
+ /* we put all edges in array, sort them, and detect doubles that way */
+
+ for(a= me->totface, mface= me->mface; a>0; a--, mface++) {
+ if(mface->v4) totedge+=4;
+ else if(mface->v3) totedge+=3;
+ else totedge+=1;
+ }
+
+ if(totedge==0) {
+ /* flag that mesh has edges */
+ me->medge = MEM_callocN(0, "make mesh edges");
+ me->totedge = 0;
+ return;
+ }
+
+ ed= edsort= MEM_mallocN(totedge*sizeof(struct edgesort), "edgesort");
+
+ for(a= me->totface, mface= me->mface; a>0; a--, mface++) {
+ to_edgesort(ed++, mface->v1, mface->v2, !mface->v3, mface->edcode & ME_V1V2);
+ if(mface->v4) {
+ to_edgesort(ed++, mface->v2, mface->v3, 0, mface->edcode & ME_V2V3);
+ to_edgesort(ed++, mface->v3, mface->v4, 0, mface->edcode & ME_V3V4);
+ to_edgesort(ed++, mface->v4, mface->v1, 0, mface->edcode & ME_V4V1);
+ }
+ else if(mface->v3) {
+ to_edgesort(ed++, mface->v2, mface->v3, 0, mface->edcode & ME_V2V3);
+ to_edgesort(ed++, mface->v3, mface->v1, 0, mface->edcode & ME_V3V1);
+ }
+ }
+
+ qsort(edsort, totedge, sizeof(struct edgesort), vergedgesort);
+
+ /* count final amount */
+ for(a=totedge, ed=edsort; a>1; a--, ed++) {
+ /* edge is unique when it differs from next edge, or is last */
+ if(ed->v1 != (ed+1)->v1 || ed->v2 != (ed+1)->v2) final++;
+ }
+ final++;
+
+
+ medge= CustomData_add_layer(&me->edata, CD_MEDGE, CD_CALLOC, NULL, final);
+ me->medge= medge;
+ me->totedge= final;
+
+ for(a=totedge, ed=edsort; a>1; a--, ed++) {
+ /* edge is unique when it differs from next edge, or is last */
+ if(ed->v1 != (ed+1)->v1 || ed->v2 != (ed+1)->v2) {
+ medge->v1= ed->v1;
+ medge->v2= ed->v2;
+ if(old==0 || ed->is_draw) medge->flag= ME_EDGEDRAW|ME_EDGERENDER;
+ if(ed->is_loose) medge->flag|= ME_LOOSEEDGE;
+ medge++;
+ }
+ else {
+ /* equal edge, we merge the drawflag */
+ (ed+1)->is_draw |= ed->is_draw;
+ }
+ }
+ /* last edge */
+ medge->v1= ed->v1;
+ medge->v2= ed->v2;
+ medge->flag= ME_EDGEDRAW;
+ if(ed->is_loose) medge->flag|= ME_LOOSEEDGE;
+ medge->flag |= ME_EDGERENDER;
+
+ MEM_freeN(edsort);
+
+ mesh_strip_loose_faces(me);
+}
+
+void mesh_strip_loose_faces(Mesh *me)
+{
+ int a,b;
+
+ for (a=b=0; a<me->totface; a++) {
+ if (me->mface[a].v3) {
+ if (a!=b) {
+ memcpy(&me->mface[b],&me->mface[a],sizeof(me->mface[b]));
+ CustomData_copy_data(&me->fdata, &me->fdata, a, b, 1);
+ CustomData_free_elem(&me->fdata, a, 1);
+ }
+ b++;
+ }
+ }
+ me->totface = b;
+}
+
+
+void mball_to_mesh(ListBase *lb, Mesh *me)
+{
+ DispList *dl;
+ MVert *mvert;
+ MFace *mface;
+ float *nors, *verts;
+ int a, *index;
+
+ dl= lb->first;
+ if(dl==0) return;
+
+ if(dl->type==DL_INDEX4) {
+ me->flag= ME_NOPUNOFLIP;
+ me->totvert= dl->nr;
+ me->totface= dl->parts;
+
+ mvert= CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, dl->nr);
+ mface= CustomData_add_layer(&me->fdata, CD_MFACE, CD_CALLOC, NULL, dl->parts);
+ me->mvert= mvert;
+ me->mface= mface;
+
+ a= dl->nr;
+ nors= dl->nors;
+ verts= dl->verts;
+ while(a--) {
+ VECCOPY(mvert->co, verts);
+ mvert->no[0]= (short int)(nors[0]*32767.0);
+ mvert->no[1]= (short int)(nors[1]*32767.0);
+ mvert->no[2]= (short int)(nors[2]*32767.0);
+ mvert++;
+ nors+= 3;
+ verts+= 3;
+ }
+
+ a= dl->parts;
+ index= dl->index;
+ while(a--) {
+ mface->v1= index[0];
+ mface->v2= index[1];
+ mface->v3= index[2];
+ mface->v4= index[3];
+ mface->flag= ME_SMOOTH;
+
+ if(mface->v3==mface->v4)
+ mface->v4= 0;
+
+ mface++;
+ index+= 4;
+ }
+
+ make_edges(me, 0); // all edges
+ }
+}
+
+/* this may fail replacing ob->data, be sure to check ob->type */
+void nurbs_to_mesh(Object *ob)
+{
+ Object *ob1;
+ DispList *dl;
+ Mesh *me;
+ Curve *cu;
+ MVert *mvert;
+ MFace *mface;
+ float *data;
+ int a, b, ofs, vertcount, startvert, totvert=0, totvlak=0;
+ int p1, p2, p3, p4, *index;
+
+ cu= ob->data;
+
+ /* count */
+ dl= cu->disp.first;
+ while(dl) {
+ if(dl->type==DL_SEGM) {
+ totvert+= dl->parts*dl->nr;
+ totvlak+= dl->parts*(dl->nr-1);
+ }
+ else if(dl->type==DL_POLY) {
+ /* cyclic polys are filled. except when 3D */
+ if(cu->flag & CU_3D) {
+ totvert+= dl->parts*dl->nr;
+ totvlak+= dl->parts*dl->nr;
+ }
+ }
+ else if(dl->type==DL_SURF) {
+ totvert+= dl->parts*dl->nr;
+ totvlak+= (dl->parts-1+((dl->flag & DL_CYCL_V)==2))*(dl->nr-1+(dl->flag & DL_CYCL_U));
+ }
+ else if(dl->type==DL_INDEX3) {
+ totvert+= dl->nr;
+ totvlak+= dl->parts;
+ }
+ dl= dl->next;
+ }
+ if(totvert==0) {
+ /* error("can't convert"); */
+ /* Make Sure you check ob->data is a curve */
+ return;
+ }
+
+ /* make mesh */
+ me= add_mesh("Mesh");
+ me->totvert= totvert;
+ me->totface= totvlak;
+
+ me->totcol= cu->totcol;
+ me->mat= cu->mat;
+ cu->mat= 0;
+ cu->totcol= 0;
+
+ mvert= CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, me->totvert);
+ mface= CustomData_add_layer(&me->fdata, CD_MFACE, CD_CALLOC, NULL, me->totface);
+ me->mvert= mvert;
+ me->mface= mface;
+
+ /* verts and faces */
+ vertcount= 0;
+
+ dl= cu->disp.first;
+ while(dl) {
+ if(dl->type==DL_SEGM) {
+ startvert= vertcount;
+ a= dl->parts*dl->nr;
+ data= dl->verts;
+ while(a--) {
+ VECCOPY(mvert->co, data);
+ data+=3;
+ vertcount++;
+ mvert++;
+ }
+
+ for(a=0; a<dl->parts; a++) {
+ ofs= a*dl->nr;
+ for(b=1; b<dl->nr; b++) {
+ mface->v1= startvert+ofs+b-1;
+ mface->v2= startvert+ofs+b;
+ mface++;
+ }
+ }
+
+ }
+ else if(dl->type==DL_POLY) {
+ /* 3d polys are not filled */
+ if(cu->flag & CU_3D) {
+ startvert= vertcount;
+ a= dl->parts*dl->nr;
+ data= dl->verts;
+ while(a--) {
+ VECCOPY(mvert->co, data);
+ data+=3;
+ vertcount++;
+ mvert++;
+ }
+
+ for(a=0; a<dl->parts; a++) {
+ ofs= a*dl->nr;
+ for(b=0; b<dl->nr; b++) {
+ mface->v1= startvert+ofs+b;
+ if(b==dl->nr-1) mface->v2= startvert+ofs;
+ else mface->v2= startvert+ofs+b+1;
+ mface++;
+ }
+ }
+ }
+ }
+ else if(dl->type==DL_INDEX3) {
+ startvert= vertcount;
+ a= dl->nr;
+ data= dl->verts;
+ while(a--) {
+ VECCOPY(mvert->co, data);
+ data+=3;
+ vertcount++;
+ mvert++;
+ }
+
+ a= dl->parts;
+ index= dl->index;
+ while(a--) {
+ mface->v1= startvert+index[0];
+ mface->v2= startvert+index[2];
+ mface->v3= startvert+index[1];
+ mface->v4= 0;
+ test_index_face(mface, NULL, 0, 3);
+
+ mface++;
+ index+= 3;
+ }
+
+
+ }
+ else if(dl->type==DL_SURF) {
+ startvert= vertcount;
+ a= dl->parts*dl->nr;
+ data= dl->verts;
+ while(a--) {
+ VECCOPY(mvert->co, data);
+ data+=3;
+ vertcount++;
+ mvert++;
+ }
+
+ for(a=0; a<dl->parts; a++) {
+
+ if( (dl->flag & DL_CYCL_V)==0 && a==dl->parts-1) break;
+
+ if(dl->flag & DL_CYCL_U) { /* p2 -> p1 -> */
+ p1= startvert+ dl->nr*a; /* p4 -> p3 -> */
+ p2= p1+ dl->nr-1; /* -----> next row */
+ p3= p1+ dl->nr;
+ p4= p2+ dl->nr;
+ b= 0;
+ }
+ else {
+ p2= startvert+ dl->nr*a;
+ p1= p2+1;
+ p4= p2+ dl->nr;
+ p3= p1+ dl->nr;
+ b= 1;
+ }
+ if( (dl->flag & DL_CYCL_V) && a==dl->parts-1) {
+ p3-= dl->parts*dl->nr;
+ p4-= dl->parts*dl->nr;
+ }
+
+ for(; b<dl->nr; b++) {
+ mface->v1= p1;
+ mface->v2= p3;
+ mface->v3= p4;
+ mface->v4= p2;
+ mface->mat_nr= (unsigned char)dl->col;
+ test_index_face(mface, NULL, 0, 4);
+ mface++;
+
+ p4= p3;
+ p3++;
+ p2= p1;
+ p1++;
+ }
+ }
+
+ }
+
+ dl= dl->next;
+ }
+
+ make_edges(me, 0); // all edges
+ mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
+
+ if(ob->data) {
+ free_libblock(&G.main->curve, ob->data);
+ }
+ ob->data= me;
+ ob->type= OB_MESH;
+
+ /* other users */
+ ob1= G.main->object.first;
+ while(ob1) {
+ if(ob1->data==cu) {
+ ob1->type= OB_MESH;
+
+ ob1->data= ob->data;
+ id_us_plus((ID *)ob->data);
+ }
+ ob1= ob1->id.next;
+ }
+
+}
+
+void mesh_delete_material_index(Mesh *me, int index) {
+ int i;
+
+ for (i=0; i<me->totface; i++) {
+ MFace *mf = &((MFace*) me->mface)[i];
+ if (mf->mat_nr && mf->mat_nr>=index)
+ mf->mat_nr--;
+ }
+}
+
+void mesh_set_smooth_flag(Object *meshOb, int enableSmooth) {
+ Mesh *me = meshOb->data;
+ int i;
+
+ for (i=0; i<me->totface; i++) {
+ MFace *mf = &((MFace*) me->mface)[i];
+
+ if (enableSmooth) {
+ mf->flag |= ME_SMOOTH;
+ } else {
+ mf->flag &= ~ME_SMOOTH;
+ }
+ }
+
+ DAG_object_flush_update(G.scene, meshOb, OB_RECALC_DATA);
+}
+
+void mesh_calc_normals(MVert *mverts, int numVerts, MFace *mfaces, int numFaces, float **faceNors_r)
+{
+ float (*tnorms)[3]= MEM_callocN(numVerts*sizeof(*tnorms), "tnorms");
+ float *fnors= MEM_mallocN(sizeof(*fnors)*3*numFaces, "meshnormals");
+ int i;
+
+ for (i=0; i<numFaces; i++) {
+ MFace *mf= &mfaces[i];
+ float *f_no= &fnors[i*3];
+
+ if (mf->v4)
+ CalcNormFloat4(mverts[mf->v1].co, mverts[mf->v2].co, mverts[mf->v3].co, mverts[mf->v4].co, f_no);
+ else
+ CalcNormFloat(mverts[mf->v1].co, mverts[mf->v2].co, mverts[mf->v3].co, f_no);
+
+ VecAddf(tnorms[mf->v1], tnorms[mf->v1], f_no);
+ VecAddf(tnorms[mf->v2], tnorms[mf->v2], f_no);
+ VecAddf(tnorms[mf->v3], tnorms[mf->v3], f_no);
+ if (mf->v4)
+ VecAddf(tnorms[mf->v4], tnorms[mf->v4], f_no);
+ }
+ for (i=0; i<numVerts; i++) {
+ MVert *mv= &mverts[i];
+ float *no= tnorms[i];
+
+ if (Normalize(no)==0.0) {
+ VECCOPY(no, mv->co);
+ Normalize(no);
+ }
+
+ mv->no[0]= (short)(no[0]*32767.0);
+ mv->no[1]= (short)(no[1]*32767.0);
+ mv->no[2]= (short)(no[2]*32767.0);
+ }
+
+ MEM_freeN(tnorms);
+
+ if (faceNors_r) {
+ *faceNors_r = fnors;
+ } else {
+ MEM_freeN(fnors);
+ }
+}
+
+float (*mesh_getVertexCos(Mesh *me, int *numVerts_r))[3]
+{
+#ifdef WITH_VERSE
+ if(me->vnode) {
+ struct VLayer *vlayer;
+ struct VerseVert *vvert;
+ unsigned int i, numVerts;
+ float (*cos)[3];
+
+ vlayer = find_verse_layer_type((VGeomData*)((VNode*)me->vnode)->data, VERTEX_LAYER);
+
+ vvert = vlayer->dl.lb.first;
+ numVerts = vlayer->dl.da.count;
+ cos = MEM_mallocN(sizeof(*cos)*numVerts, "verse_vertexcos");
+
+ for(i=0; i<numVerts && vvert; vvert = vvert->next, i++) {
+ VECCOPY(cos[i], vvert->co);
+ }
+
+ return cos;
+ }
+ else {
+#endif
+ int i, numVerts = me->totvert;
+ float (*cos)[3] = MEM_mallocN(sizeof(*cos)*numVerts, "vertexcos1");
+
+ if (numVerts_r) *numVerts_r = numVerts;
+ for (i=0; i<numVerts; i++)
+ VECCOPY(cos[i], me->mvert[i].co);
+
+ return cos;
+#ifdef WITH_VERSE
+ }
+#endif
+}
+
+float (*mesh_getRefKeyCos(Mesh *me, int *numVerts_r))[3]
+{
+ KeyBlock *kb;
+ float (*cos)[3] = NULL;
+ int totvert;
+
+ if(me->key && me->key->refkey) {
+ if(numVerts_r) *numVerts_r= me->totvert;
+ cos= MEM_mallocN(sizeof(*cos)*me->totvert, "vertexcos1");
+
+ kb= me->key->refkey;
+ totvert= MIN2(kb->totelem, me->totvert);
+
+ memcpy(cos, kb->data, sizeof(*cos)*totvert);
+ }
+
+ return cos;
+}
+
+UvVertMap *make_uv_vert_map(struct MFace *mface, struct MTFace *tface, unsigned int totface, unsigned int totvert, int selected, float *limit)
+{
+ UvVertMap *vmap;
+ UvMapVert *buf;
+ MFace *mf;
+ MTFace *tf;
+ unsigned int a;
+ int i, totuv, nverts;
+
+ totuv = 0;
+
+ /* generate UvMapVert array */
+ mf= mface;
+ tf= tface;
+ for(a=0; a<totface; a++, mf++, tf++)
+ if(!selected || (!(mf->flag & ME_HIDE) && (mf->flag & ME_FACE_SEL)))
+ totuv += (mf->v4)? 4: 3;
+
+ if(totuv==0)
+ return NULL;
+
+ vmap= (UvVertMap*)MEM_mallocN(sizeof(*vmap), "UvVertMap");
+ if (!vmap)
+ return NULL;
+
+ vmap->vert= (UvMapVert**)MEM_callocN(sizeof(*vmap->vert)*totvert, "UvMapVert*");
+ buf= vmap->buf= (UvMapVert*)MEM_mallocN(sizeof(*vmap->buf)*totuv, "UvMapVert");
+
+ if (!vmap->vert || !vmap->buf) {
+ free_uv_vert_map(vmap);
+ return NULL;
+ }
+
+ mf= mface;
+ tf= tface;
+ for(a=0; a<totface; a++, mf++, tf++) {
+ if(!selected || (!(mf->flag & ME_HIDE) && (mf->flag & ME_FACE_SEL))) {
+ nverts= (mf->v4)? 4: 3;
+
+ for(i=0; i<nverts; i++) {
+ buf->tfindex= i;
+ buf->f= a;
+ buf->separate = 0;
+ buf->next= vmap->vert[*(&mf->v1 + i)];
+ vmap->vert[*(&mf->v1 + i)]= buf;
+ buf++;
+ }
+ }
+ }
+
+ /* sort individual uvs for each vert */
+ tf= tface;
+ for(a=0; a<totvert; a++) {
+ UvMapVert *newvlist= NULL, *vlist=vmap->vert[a];
+ UvMapVert *iterv, *v, *lastv, *next;
+ float *uv, *uv2, uvdiff[2];
+
+ while(vlist) {
+ v= vlist;
+ vlist= vlist->next;
+ v->next= newvlist;
+ newvlist= v;
+
+ uv= (tf+v->f)->uv[v->tfindex];
+ lastv= NULL;
+ iterv= vlist;
+
+ while(iterv) {
+ next= iterv->next;
+
+ uv2= (tf+iterv->f)->uv[iterv->tfindex];
+ Vec2Subf(uvdiff, uv2, uv);
+
+
+ if(fabs(uv[0]-uv2[0]) < limit[0] && fabs(uv[1]-uv2[1]) < limit[1]) {
+ if(lastv) lastv->next= next;
+ else vlist= next;
+ iterv->next= newvlist;
+ newvlist= iterv;
+ }
+ else
+ lastv=iterv;
+
+ iterv= next;
+ }
+
+ newvlist->separate = 1;
+ }
+
+ vmap->vert[a]= newvlist;
+ }
+
+ return vmap;
+}
+
+UvMapVert *get_uv_map_vert(UvVertMap *vmap, unsigned int v)
+{
+ return vmap->vert[v];
+}
+
+void free_uv_vert_map(UvVertMap *vmap)
+{
+ if (vmap) {
+ if (vmap->vert) MEM_freeN(vmap->vert);
+ if (vmap->buf) MEM_freeN(vmap->buf);
+ MEM_freeN(vmap);
+ }
+}
+
diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c
new file mode 100644
index 00000000000..743926ed91b
--- /dev/null
+++ b/source/blender/blenkernel/intern/modifier.c
@@ -0,0 +1,5765 @@
+/*
+* $Id$
+*
+* ***** BEGIN GPL LICENSE BLOCK *****
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*
+* The Original Code is Copyright (C) 2005 by the Blender Foundation.
+* All rights reserved.
+*
+* The Original Code is: all of this file.
+*
+* Contributor(s): Daniel Dunbar
+* Ton Roosendaal,
+* Ben Batt,
+* Brecht Van Lommel,
+* Campbell Barton
+*
+* ***** END GPL LICENSE BLOCK *****
+*
+* Modifier stack implementation.
+*
+* BKE_modifier.h contains the function prototypes for this file.
+*
+*/
+
+#include "string.h"
+#include "stdarg.h"
+#include "math.h"
+#include "float.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_rand.h"
+#include "BLI_arithb.h"
+#include "BLI_linklist.h"
+#include "BLI_edgehash.h"
+#include "BLI_ghash.h"
+#include "BLI_memarena.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_armature_types.h"
+#include "DNA_effect_types.h"
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_object_force.h"
+#include "DNA_scene_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_camera_types.h"
+
+#include "BLI_editVert.h"
+
+#include "MTC_matrixops.h"
+#include "MTC_vectorops.h"
+
+#include "BKE_main.h"
+#include "BKE_anim.h"
+#include "BKE_bad_level_calls.h"
+#include "BKE_customdata.h"
+#include "BKE_global.h"
+#include "BKE_utildefines.h"
+#include "BKE_cdderivedmesh.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_booleanops.h"
+#include "BKE_displist.h"
+#include "BKE_modifier.h"
+#include "BKE_lattice.h"
+#include "BKE_subsurf.h"
+#include "BKE_object.h"
+#include "BKE_mesh.h"
+#include "BKE_softbody.h"
+#include "BKE_material.h"
+#include "depsgraph_private.h"
+
+#include "LOD_DependKludge.h"
+#include "LOD_decimation.h"
+
+#include "CCGSubSurf.h"
+
+#include "RE_shader_ext.h"
+
+/***/
+
+static int noneModifier_isDisabled(ModifierData *md)
+{
+ return 1;
+}
+
+/* Curve */
+
+static void curveModifier_initData(ModifierData *md)
+{
+ CurveModifierData *cmd = (CurveModifierData*) md;
+
+ cmd->defaxis = MOD_CURVE_POSX;
+}
+
+static void curveModifier_copyData(ModifierData *md, ModifierData *target)
+{
+ CurveModifierData *cmd = (CurveModifierData*) md;
+ CurveModifierData *tcmd = (CurveModifierData*) target;
+
+ tcmd->defaxis = cmd->defaxis;
+ tcmd->object = cmd->object;
+ strncpy(tcmd->name, cmd->name, 32);
+}
+
+CustomDataMask curveModifier_requiredDataMask(ModifierData *md)
+{
+ CurveModifierData *cmd = (CurveModifierData *)md;
+ CustomDataMask dataMask = 0;
+
+ /* ask for vertexgroups if we need them */
+ if(cmd->name[0]) dataMask |= (1 << CD_MDEFORMVERT);
+
+ return dataMask;
+}
+
+static int curveModifier_isDisabled(ModifierData *md)
+{
+ CurveModifierData *cmd = (CurveModifierData*) md;
+
+ return !cmd->object;
+}
+
+static void curveModifier_foreachObjectLink(
+ ModifierData *md, Object *ob,
+ void (*walk)(void *userData, Object *ob, Object **obpoin),
+ void *userData)
+{
+ CurveModifierData *cmd = (CurveModifierData*) md;
+
+ walk(userData, ob, &cmd->object);
+}
+
+static void curveModifier_updateDepgraph(
+ ModifierData *md, DagForest *forest,
+ Object *ob, DagNode *obNode)
+{
+ CurveModifierData *cmd = (CurveModifierData*) md;
+
+ if (cmd->object) {
+ DagNode *curNode = dag_get_node(forest, cmd->object);
+
+ dag_add_relation(forest, curNode, obNode,
+ DAG_RL_DATA_DATA | DAG_RL_OB_DATA);
+ }
+}
+
+static void curveModifier_deformVerts(
+ ModifierData *md, Object *ob, DerivedMesh *derivedData,
+ float (*vertexCos)[3], int numVerts)
+{
+ CurveModifierData *cmd = (CurveModifierData*) md;
+
+ curve_deform_verts(cmd->object, ob, derivedData, vertexCos, numVerts,
+ cmd->name, cmd->defaxis);
+}
+
+static void curveModifier_deformVertsEM(
+ ModifierData *md, Object *ob, EditMesh *editData,
+ DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
+{
+ DerivedMesh *dm = derivedData;
+
+ if(!derivedData) dm = CDDM_from_editmesh(editData, ob->data);
+
+ curveModifier_deformVerts(md, ob, dm, vertexCos, numVerts);
+
+ if(!derivedData) dm->release(dm);
+}
+
+/* Lattice */
+
+static void latticeModifier_copyData(ModifierData *md, ModifierData *target)
+{
+ LatticeModifierData *lmd = (LatticeModifierData*) md;
+ LatticeModifierData *tlmd = (LatticeModifierData*) target;
+
+ tlmd->object = lmd->object;
+ strncpy(tlmd->name, lmd->name, 32);
+}
+
+CustomDataMask latticeModifier_requiredDataMask(ModifierData *md)
+{
+ LatticeModifierData *lmd = (LatticeModifierData *)md;
+ CustomDataMask dataMask = 0;
+
+ /* ask for vertexgroups if we need them */
+ if(lmd->name[0]) dataMask |= (1 << CD_MDEFORMVERT);
+
+ return dataMask;
+}
+
+static int latticeModifier_isDisabled(ModifierData *md)
+{
+ LatticeModifierData *lmd = (LatticeModifierData*) md;
+
+ return !lmd->object;
+}
+
+static void latticeModifier_foreachObjectLink(
+ ModifierData *md, Object *ob,
+ void (*walk)(void *userData, Object *ob, Object **obpoin),
+ void *userData)
+{
+ LatticeModifierData *lmd = (LatticeModifierData*) md;
+
+ walk(userData, ob, &lmd->object);
+}
+
+static void latticeModifier_updateDepgraph(ModifierData *md, DagForest *forest,
+ Object *ob, DagNode *obNode)
+{
+ LatticeModifierData *lmd = (LatticeModifierData*) md;
+
+ if(lmd->object) {
+ DagNode *latNode = dag_get_node(forest, lmd->object);
+
+ dag_add_relation(forest, latNode, obNode,
+ DAG_RL_DATA_DATA | DAG_RL_OB_DATA);
+ }
+}
+
+static void latticeModifier_deformVerts(
+ ModifierData *md, Object *ob, DerivedMesh *derivedData,
+ float (*vertexCos)[3], int numVerts)
+{
+ LatticeModifierData *lmd = (LatticeModifierData*) md;
+
+ lattice_deform_verts(lmd->object, ob, derivedData,
+ vertexCos, numVerts, lmd->name);
+}
+
+static void latticeModifier_deformVertsEM(
+ ModifierData *md, Object *ob, EditMesh *editData,
+ DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
+{
+ DerivedMesh *dm = derivedData;
+
+ if(!derivedData) dm = CDDM_from_editmesh(editData, ob->data);
+
+ latticeModifier_deformVerts(md, ob, dm, vertexCos, numVerts);
+
+ if(!derivedData) dm->release(dm);
+}
+
+/* Subsurf */
+
+static void subsurfModifier_initData(ModifierData *md)
+{
+ SubsurfModifierData *smd = (SubsurfModifierData*) md;
+
+ smd->levels = 1;
+ smd->renderLevels = 2;
+ smd->flags |= eSubsurfModifierFlag_SubsurfUv;
+}
+
+static void subsurfModifier_copyData(ModifierData *md, ModifierData *target)
+{
+ SubsurfModifierData *smd = (SubsurfModifierData*) md;
+ SubsurfModifierData *tsmd = (SubsurfModifierData*) target;
+
+ tsmd->flags = smd->flags;
+ tsmd->levels = smd->levels;
+ tsmd->renderLevels = smd->renderLevels;
+ tsmd->subdivType = smd->subdivType;
+}
+
+static void subsurfModifier_freeData(ModifierData *md)
+{
+ SubsurfModifierData *smd = (SubsurfModifierData*) md;
+
+ if(smd->mCache) {
+ ccgSubSurf_free(smd->mCache);
+ }
+ if(smd->emCache) {
+ ccgSubSurf_free(smd->emCache);
+ }
+}
+
+static DerivedMesh *subsurfModifier_applyModifier(
+ ModifierData *md, Object *ob, DerivedMesh *derivedData,
+ int useRenderParams, int isFinalCalc)
+{
+ SubsurfModifierData *smd = (SubsurfModifierData*) md;
+ DerivedMesh *result;
+
+ result = subsurf_make_derived_from_derived(derivedData, smd,
+ useRenderParams, NULL,
+ isFinalCalc, 0);
+
+ return result;
+}
+
+static DerivedMesh *subsurfModifier_applyModifierEM(
+ ModifierData *md, Object *ob, EditMesh *editData,
+ DerivedMesh *derivedData)
+{
+ SubsurfModifierData *smd = (SubsurfModifierData*) md;
+ DerivedMesh *result;
+
+ result = subsurf_make_derived_from_derived(derivedData, smd, 0,
+ NULL, 0, 1);
+
+ return result;
+}
+
+/* Build */
+
+static void buildModifier_initData(ModifierData *md)
+{
+ BuildModifierData *bmd = (BuildModifierData*) md;
+
+ bmd->start = 1.0;
+ bmd->length = 100.0;
+}
+
+static void buildModifier_copyData(ModifierData *md, ModifierData *target)
+{
+ BuildModifierData *bmd = (BuildModifierData*) md;
+ BuildModifierData *tbmd = (BuildModifierData*) target;
+
+ tbmd->start = bmd->start;
+ tbmd->length = bmd->length;
+ tbmd->randomize = bmd->randomize;
+ tbmd->seed = bmd->seed;
+}
+
+static int buildModifier_dependsOnTime(ModifierData *md)
+{
+ return 1;
+}
+
+static DerivedMesh *buildModifier_applyModifier(ModifierData *md, Object *ob,
+ DerivedMesh *derivedData,
+ int useRenderParams, int isFinalCalc)
+{
+ DerivedMesh *dm = derivedData;
+ DerivedMesh *result;
+ BuildModifierData *bmd = (BuildModifierData*) md;
+ int i;
+ int numFaces, numEdges;
+ int maxVerts, maxEdges, maxFaces;
+ int *vertMap, *edgeMap, *faceMap;
+ float frac;
+ GHashIterator *hashIter;
+ /* maps vert indices in old mesh to indices in new mesh */
+ GHash *vertHash = BLI_ghash_new(BLI_ghashutil_inthash,
+ BLI_ghashutil_intcmp);
+ /* maps edge indices in new mesh to indices in old mesh */
+ GHash *edgeHash = BLI_ghash_new(BLI_ghashutil_inthash,
+ BLI_ghashutil_intcmp);
+
+ maxVerts = dm->getNumVerts(dm);
+ vertMap = MEM_callocN(sizeof(*vertMap) * maxVerts,
+ "build modifier vertMap");
+ for(i = 0; i < maxVerts; ++i) vertMap[i] = i;
+
+ maxEdges = dm->getNumEdges(dm);
+ edgeMap = MEM_callocN(sizeof(*edgeMap) * maxEdges,
+ "build modifier edgeMap");
+ for(i = 0; i < maxEdges; ++i) edgeMap[i] = i;
+
+ maxFaces = dm->getNumFaces(dm);
+ faceMap = MEM_callocN(sizeof(*faceMap) * maxFaces,
+ "build modifier faceMap");
+ for(i = 0; i < maxFaces; ++i) faceMap[i] = i;
+
+ if (ob) {
+ frac = bsystem_time(ob, (float)G.scene->r.cfra,
+ bmd->start - 1.0f) / bmd->length;
+ } else {
+ frac = G.scene->r.cfra - bmd->start / bmd->length;
+ }
+ CLAMP(frac, 0.0, 1.0);
+
+ numFaces = dm->getNumFaces(dm) * frac;
+ numEdges = dm->getNumEdges(dm) * frac;
+
+ /* if there's at least one face, build based on faces */
+ if(numFaces) {
+ int maxEdges;
+
+ if(bmd->randomize)
+ BLI_array_randomize(faceMap, sizeof(*faceMap),
+ maxFaces, bmd->seed);
+
+ /* get the set of all vert indices that will be in the final mesh,
+ * mapped to the new indices
+ */
+ for(i = 0; i < numFaces; ++i) {
+ MFace mf;
+ dm->getFace(dm, faceMap[i], &mf);
+
+ if(!BLI_ghash_haskey(vertHash, (void *)mf.v1))
+ BLI_ghash_insert(vertHash, (void *)mf.v1,
+ (void *)BLI_ghash_size(vertHash));
+ if(!BLI_ghash_haskey(vertHash, (void *)mf.v2))
+ BLI_ghash_insert(vertHash, (void *)mf.v2,
+ (void *)BLI_ghash_size(vertHash));
+ if(!BLI_ghash_haskey(vertHash, (void *)mf.v3))
+ BLI_ghash_insert(vertHash, (void *)mf.v3,
+ (void *)BLI_ghash_size(vertHash));
+ if(mf.v4 && !BLI_ghash_haskey(vertHash, (void *)mf.v4))
+ BLI_ghash_insert(vertHash, (void *)mf.v4,
+ (void *)BLI_ghash_size(vertHash));
+ }
+
+ /* get the set of edges that will be in the new mesh (i.e. all edges
+ * that have both verts in the new mesh)
+ */
+ maxEdges = dm->getNumEdges(dm);
+ for(i = 0; i < maxEdges; ++i) {
+ MEdge me;
+ dm->getEdge(dm, i, &me);
+
+ if(BLI_ghash_haskey(vertHash, (void *)me.v1)
+ && BLI_ghash_haskey(vertHash, (void *)me.v2))
+ BLI_ghash_insert(edgeHash,
+ (void *)BLI_ghash_size(edgeHash), (void *)i);
+ }
+ } else if(numEdges) {
+ if(bmd->randomize)
+ BLI_array_randomize(edgeMap, sizeof(*edgeMap),
+ maxEdges, bmd->seed);
+
+ /* get the set of all vert indices that will be in the final mesh,
+ * mapped to the new indices
+ */
+ for(i = 0; i < numEdges; ++i) {
+ MEdge me;
+ dm->getEdge(dm, edgeMap[i], &me);
+
+ if(!BLI_ghash_haskey(vertHash, (void *)me.v1))
+ BLI_ghash_insert(vertHash, (void *)me.v1,
+ (void *)BLI_ghash_size(vertHash));
+ if(!BLI_ghash_haskey(vertHash, (void *)me.v2))
+ BLI_ghash_insert(vertHash, (void *)me.v2,
+ (void *)BLI_ghash_size(vertHash));
+ }
+
+ /* get the set of edges that will be in the new mesh
+ */
+ for(i = 0; i < numEdges; ++i) {
+ MEdge me;
+ dm->getEdge(dm, edgeMap[i], &me);
+
+ BLI_ghash_insert(edgeHash, (void *)BLI_ghash_size(edgeHash),
+ (void *)edgeMap[i]);
+ }
+ } else {
+ int numVerts = dm->getNumVerts(dm) * frac;
+
+ if(bmd->randomize)
+ BLI_array_randomize(vertMap, sizeof(*vertMap),
+ maxVerts, bmd->seed);
+
+ /* get the set of all vert indices that will be in the final mesh,
+ * mapped to the new indices
+ */
+ for(i = 0; i < numVerts; ++i)
+ BLI_ghash_insert(vertHash, (void *)vertMap[i], (void *)i);
+ }
+
+ /* now we know the number of verts, edges and faces, we can create
+ * the mesh
+ */
+ result = CDDM_from_template(dm, BLI_ghash_size(vertHash),
+ BLI_ghash_size(edgeHash), numFaces);
+
+ /* copy the vertices across */
+ for(hashIter = BLI_ghashIterator_new(vertHash);
+ !BLI_ghashIterator_isDone(hashIter);
+ BLI_ghashIterator_step(hashIter)) {
+ MVert source;
+ MVert *dest;
+ int oldIndex = (int)BLI_ghashIterator_getKey(hashIter);
+ int newIndex = (int)BLI_ghashIterator_getValue(hashIter);
+
+ dm->getVert(dm, oldIndex, &source);
+ dest = CDDM_get_vert(result, newIndex);
+
+ DM_copy_vert_data(dm, result, oldIndex, newIndex, 1);
+ *dest = source;
+ }
+ BLI_ghashIterator_free(hashIter);
+
+ /* copy the edges across, remapping indices */
+ for(i = 0; i < BLI_ghash_size(edgeHash); ++i) {
+ MEdge source;
+ MEdge *dest;
+ int oldIndex = (int)BLI_ghash_lookup(edgeHash, (void *)i);
+
+ dm->getEdge(dm, oldIndex, &source);
+ dest = CDDM_get_edge(result, i);
+
+ source.v1 = (int)BLI_ghash_lookup(vertHash, (void *)source.v1);
+ source.v2 = (int)BLI_ghash_lookup(vertHash, (void *)source.v2);
+
+ DM_copy_edge_data(dm, result, oldIndex, i, 1);
+ *dest = source;
+ }
+
+ /* copy the faces across, remapping indices */
+ for(i = 0; i < numFaces; ++i) {
+ MFace source;
+ MFace *dest;
+ int orig_v4;
+
+ dm->getFace(dm, faceMap[i], &source);
+ dest = CDDM_get_face(result, i);
+
+ orig_v4 = source.v4;
+
+ source.v1 = (int)BLI_ghash_lookup(vertHash, (void *)source.v1);
+ source.v2 = (int)BLI_ghash_lookup(vertHash, (void *)source.v2);
+ source.v3 = (int)BLI_ghash_lookup(vertHash, (void *)source.v3);
+ if(source.v4)
+ source.v4 = (int)BLI_ghash_lookup(vertHash, (void *)source.v4);
+
+ DM_copy_face_data(dm, result, faceMap[i], i, 1);
+ *dest = source;
+
+ test_index_face(dest, &result->faceData, i, (orig_v4 ? 4 : 3));
+ }
+
+ CDDM_calc_normals(result);
+
+ BLI_ghash_free(vertHash, NULL, NULL);
+ BLI_ghash_free(edgeHash, NULL, NULL);
+
+ MEM_freeN(vertMap);
+ MEM_freeN(edgeMap);
+ MEM_freeN(faceMap);
+
+ return result;
+}
+
+/* Array */
+/* Array modifier: duplicates the object multiple times along an axis
+*/
+
+static void arrayModifier_initData(ModifierData *md)
+{
+ ArrayModifierData *amd = (ArrayModifierData*) md;
+
+ /* default to 2 duplicates distributed along the x-axis by an
+ offset of 1 object-width
+ */
+ amd->start_cap = amd->end_cap = amd->curve_ob = amd->offset_ob = NULL;
+ amd->count = 2;
+ amd->offset[0] = amd->offset[1] = amd->offset[2] = 0;
+ amd->scale[0] = 1;
+ amd->scale[1] = amd->scale[2] = 0;
+ amd->length = 0;
+ amd->merge_dist = 0.01;
+ amd->fit_type = MOD_ARR_FIXEDCOUNT;
+ amd->offset_type = MOD_ARR_OFF_RELATIVE;
+ amd->flags = 0;
+}
+
+static void arrayModifier_copyData(ModifierData *md, ModifierData *target)
+{
+ ArrayModifierData *amd = (ArrayModifierData*) md;
+ ArrayModifierData *tamd = (ArrayModifierData*) target;
+
+ tamd->start_cap = amd->start_cap;
+ tamd->end_cap = amd->end_cap;
+ tamd->curve_ob = amd->curve_ob;
+ tamd->offset_ob = amd->offset_ob;
+ tamd->count = amd->count;
+ VECCOPY(tamd->offset, amd->offset);
+ VECCOPY(tamd->scale, amd->scale);
+ tamd->length = amd->length;
+ tamd->merge_dist = amd->merge_dist;
+ tamd->fit_type = amd->fit_type;
+ tamd->offset_type = amd->offset_type;
+ tamd->flags = amd->flags;
+}
+
+static void arrayModifier_foreachObjectLink(
+ ModifierData *md, Object *ob,
+ void (*walk)(void *userData, Object *ob, Object **obpoin),
+ void *userData)
+{
+ ArrayModifierData *amd = (ArrayModifierData*) md;
+
+ walk(userData, ob, &amd->start_cap);
+ walk(userData, ob, &amd->end_cap);
+ walk(userData, ob, &amd->curve_ob);
+ walk(userData, ob, &amd->offset_ob);
+}
+
+static void arrayModifier_updateDepgraph(ModifierData *md, DagForest *forest,
+ Object *ob, DagNode *obNode)
+{
+ ArrayModifierData *amd = (ArrayModifierData*) md;
+
+ if (amd->start_cap) {
+ DagNode *curNode = dag_get_node(forest, amd->start_cap);
+
+ dag_add_relation(forest, curNode, obNode,
+ DAG_RL_DATA_DATA | DAG_RL_OB_DATA);
+ }
+ if (amd->end_cap) {
+ DagNode *curNode = dag_get_node(forest, amd->end_cap);
+
+ dag_add_relation(forest, curNode, obNode,
+ DAG_RL_DATA_DATA | DAG_RL_OB_DATA);
+ }
+ if (amd->curve_ob) {
+ DagNode *curNode = dag_get_node(forest, amd->curve_ob);
+
+ dag_add_relation(forest, curNode, obNode,
+ DAG_RL_DATA_DATA | DAG_RL_OB_DATA);
+ }
+ if (amd->offset_ob) {
+ DagNode *curNode = dag_get_node(forest, amd->offset_ob);
+
+ dag_add_relation(forest, curNode, obNode,
+ DAG_RL_DATA_DATA | DAG_RL_OB_DATA);
+ }
+}
+
+float vertarray_size(MVert *mvert, int numVerts, int axis)
+{
+ int i;
+ float min_co, max_co;
+
+ /* if there are no vertices, width is 0 */
+ if(numVerts == 0) return 0;
+
+ /* find the minimum and maximum coordinates on the desired axis */
+ min_co = max_co = mvert->co[axis];
+ ++mvert;
+ for(i = 1; i < numVerts; ++i, ++mvert) {
+ if(mvert->co[axis] < min_co) min_co = mvert->co[axis];
+ if(mvert->co[axis] > max_co) max_co = mvert->co[axis];
+ }
+
+ return max_co - min_co;
+}
+
+typedef struct IndexMapEntry {
+ /* the new vert index that this old vert index maps to */
+ int new;
+ /* -1 if this vert isn't merged, otherwise the old vert index it
+ * should be replaced with
+ */
+ int merge;
+ /* 1 if this vert's first copy is merged with the last copy of its
+ * merge target, otherwise 0
+ */
+ short merge_final;
+} IndexMapEntry;
+
+/* indexMap - an array of IndexMap entries
+ * oldIndex - the old index to map
+ * copyNum - the copy number to map to (original = 0, first copy = 1, etc.)
+ */
+static int calc_mapping(IndexMapEntry *indexMap, int oldIndex, int copyNum)
+{
+ if(indexMap[oldIndex].merge < 0) {
+ /* vert wasn't merged, so use copy of this vert */
+ return indexMap[oldIndex].new + copyNum;
+ } else if(indexMap[oldIndex].merge == oldIndex) {
+ /* vert was merged with itself */
+ return indexMap[oldIndex].new;
+ } else {
+ /* vert was merged with another vert */
+ /* follow the chain of merges to the end, or until we've passed
+ * a number of vertices equal to the copy number
+ */
+ if(copyNum <= 0)
+ return indexMap[oldIndex].new;
+ else
+ return calc_mapping(indexMap, indexMap[oldIndex].merge,
+ copyNum - 1);
+ }
+}
+
+static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
+ Object *ob, DerivedMesh *dm,
+ int initFlags)
+{
+ int i, j;
+ /* offset matrix */
+ float offset[4][4];
+ float final_offset[4][4];
+ float tmp_mat[4][4];
+ float length = amd->length;
+ int count = amd->count;
+ int numVerts, numEdges, numFaces;
+ int maxVerts, maxEdges, maxFaces;
+ int finalVerts, finalEdges, finalFaces;
+ DerivedMesh *result, *start_cap = NULL, *end_cap = NULL;
+ MVert *mvert, *src_mvert;
+ MEdge *medge;
+ MFace *mface;
+
+ IndexMapEntry *indexMap;
+
+ EdgeHash *edges;
+
+ /* need to avoid infinite recursion here */
+ if(amd->start_cap && amd->start_cap != ob)
+ start_cap = mesh_get_derived_final(amd->start_cap, CD_MASK_MESH);
+ if(amd->end_cap && amd->end_cap != ob)
+ end_cap = mesh_get_derived_final(amd->end_cap, CD_MASK_MESH);
+
+ MTC_Mat4One(offset);
+
+ indexMap = MEM_callocN(sizeof(*indexMap) * dm->getNumVerts(dm),
+ "indexmap");
+
+ src_mvert = dm->getVertArray(dm);
+
+ maxVerts = dm->getNumVerts(dm);
+
+ if(amd->offset_type & MOD_ARR_OFF_CONST)
+ VecAddf(offset[3], offset[3], amd->offset);
+ if(amd->offset_type & MOD_ARR_OFF_RELATIVE) {
+ for(j = 0; j < 3; j++)
+ offset[3][j] += amd->scale[j] * vertarray_size(src_mvert,
+ maxVerts, j);
+ }
+
+ if((amd->offset_type & MOD_ARR_OFF_OBJ) && (amd->offset_ob)) {
+ float obinv[4][4];
+ float result_mat[4][4];
+
+ if(ob)
+ MTC_Mat4Invert(obinv, ob->obmat);
+ else
+ MTC_Mat4One(obinv);
+
+ MTC_Mat4MulSerie(result_mat, offset,
+ obinv, amd->offset_ob->obmat,
+ NULL, NULL, NULL, NULL, NULL);
+ MTC_Mat4CpyMat4(offset, result_mat);
+ }
+
+ if(amd->fit_type == MOD_ARR_FITCURVE && amd->curve_ob) {
+ Curve *cu = amd->curve_ob->data;
+ if(cu) {
+ if(!cu->path) {
+ cu->flag |= CU_PATH; // needed for path & bevlist
+ makeDispListCurveTypes(amd->curve_ob, 0);
+ }
+ if(cu->path)
+ length = cu->path->totdist;
+ }
+ }
+
+ /* calculate the maximum number of copies which will fit within the
+ prescribed length */
+ if(amd->fit_type == MOD_ARR_FITLENGTH
+ || amd->fit_type == MOD_ARR_FITCURVE) {
+ float dist = sqrt(MTC_dot3Float(offset[3], offset[3]));
+
+ if(dist > FLT_EPSILON)
+ /* this gives length = first copy start to last copy end
+ add a tiny offset for floating point rounding errors */
+ count = (length + FLT_EPSILON) / dist;
+ else
+ /* if the offset has no translation, just make one copy */
+ count = 1;
+ }
+
+ if(count < 1)
+ count = 1;
+
+ /* allocate memory for count duplicates (including original) plus
+ * start and end caps
+ */
+ finalVerts = dm->getNumVerts(dm) * count;
+ finalEdges = dm->getNumEdges(dm) * count;
+ finalFaces = dm->getNumFaces(dm) * count;
+ if(start_cap) {
+ finalVerts += start_cap->getNumVerts(start_cap);
+ finalEdges += start_cap->getNumEdges(start_cap);
+ finalFaces += start_cap->getNumFaces(start_cap);
+ }
+ if(end_cap) {
+ finalVerts += end_cap->getNumVerts(end_cap);
+ finalEdges += end_cap->getNumEdges(end_cap);
+ finalFaces += end_cap->getNumFaces(end_cap);
+ }
+ result = CDDM_from_template(dm, finalVerts, finalEdges, finalFaces);
+
+ /* calculate the offset matrix of the final copy (for merging) */
+ MTC_Mat4One(final_offset);
+
+ for(j=0; j < count - 1; j++) {
+ MTC_Mat4MulMat4(tmp_mat, final_offset, offset);
+ MTC_Mat4CpyMat4(final_offset, tmp_mat);
+ }
+
+ numVerts = numEdges = numFaces = 0;
+ mvert = CDDM_get_verts(result);
+
+ for (i = 0; i < maxVerts; i++) {
+ MVert *inMV;
+ MVert *mv = &mvert[numVerts];
+ MVert *mv2;
+ float co[3];
+
+ inMV = &src_mvert[i];
+
+ DM_copy_vert_data(dm, result, i, numVerts, 1);
+ *mv = *inMV;
+ numVerts++;
+
+ indexMap[i].new = numVerts - 1;
+ indexMap[i].merge = -1; /* default to no merge */
+ indexMap[i].merge_final = 0; /* default to no merge */
+
+ VECCOPY(co, mv->co);
+
+ /* Attempts to merge verts from one duplicate with verts from the
+ * next duplicate which are closer than amd->merge_dist.
+ * Only the first such vert pair is merged.
+ * If verts are merged in the first duplicate pair, they are merged
+ * in all pairs.
+ */
+ if((count > 1) && (amd->flags & MOD_ARR_MERGE)) {
+ float tmp_co[3];
+ VECCOPY(tmp_co, mv->co);
+ MTC_Mat4MulVecfl(offset, tmp_co);
+
+ for(j = 0; j < maxVerts; j++) {
+ inMV = &src_mvert[j];
+ /* if this vert is within merge limit, merge */
+ if(VecLenCompare(tmp_co, inMV->co, amd->merge_dist)) {
+ indexMap[i].merge = j;
+
+ /* test for merging with final copy of merge target */
+ if(amd->flags & MOD_ARR_MERGEFINAL) {
+ VECCOPY(tmp_co, inMV->co);
+ inMV = &src_mvert[i];
+ MTC_Mat4MulVecfl(final_offset, tmp_co);
+ if(VecLenCompare(tmp_co, inMV->co, amd->merge_dist))
+ indexMap[i].merge_final = 1;
+ }
+ break;
+ }
+ }
+ }
+
+ /* if no merging, generate copies of this vert */
+ if(indexMap[i].merge < 0) {
+ for(j=0; j < count - 1; j++) {
+ mv2 = &mvert[numVerts];
+
+ DM_copy_vert_data(result, result, numVerts - 1, numVerts, 1);
+ *mv2 = *mv;
+ numVerts++;
+
+ MTC_Mat4MulVecfl(offset, co);
+ VECCOPY(mv2->co, co);
+ }
+ } else if(indexMap[i].merge != i && indexMap[i].merge_final) {
+ /* if this vert is not merging with itself, and it is merging
+ * with the final copy of its merge target, remove the first copy
+ */
+ numVerts--;
+ DM_free_vert_data(result, numVerts, 1);
+ }
+ }
+
+ /* make a hashtable so we can avoid duplicate edges from merging */
+ edges = BLI_edgehash_new();
+
+ maxEdges = dm->getNumEdges(dm);
+ medge = CDDM_get_edges(result);
+ for(i = 0; i < maxEdges; i++) {
+ MEdge inMED;
+ MEdge med;
+ MEdge *med2;
+ int vert1, vert2;
+
+ dm->getEdge(dm, i, &inMED);
+
+ med = inMED;
+ med.v1 = indexMap[inMED.v1].new;
+ med.v2 = indexMap[inMED.v2].new;
+
+ /* if vertices are to be merged with the final copies of their
+ * merge targets, calculate that final copy
+ */
+ if(indexMap[inMED.v1].merge_final) {
+ med.v1 = calc_mapping(indexMap, indexMap[inMED.v1].merge,
+ count - 1);
+ }
+ if(indexMap[inMED.v2].merge_final) {
+ med.v2 = calc_mapping(indexMap, indexMap[inMED.v2].merge,
+ count - 1);
+ }
+
+ if (initFlags) {
+ med.flag |= ME_EDGEDRAW | ME_EDGERENDER;
+ }
+
+ if(!BLI_edgehash_haskey(edges, med.v1, med.v2)) {
+ DM_copy_edge_data(dm, result, i, numEdges, 1);
+ medge[numEdges] = med;
+ numEdges++;
+
+ BLI_edgehash_insert(edges, med.v1, med.v2, NULL);
+ }
+
+ for(j = 1; j < count; j++)
+ {
+ vert1 = calc_mapping(indexMap, inMED.v1, j);
+ vert2 = calc_mapping(indexMap, inMED.v2, j);
+ /* avoid duplicate edges */
+ if(!BLI_edgehash_haskey(edges, vert1, vert2)) {
+ med2 = &medge[numEdges];
+
+ DM_copy_edge_data(dm, result, i, numEdges, 1);
+ *med2 = med;
+ numEdges++;
+
+ med2->v1 = vert1;
+ med2->v2 = vert2;
+
+ BLI_edgehash_insert(edges, med2->v1, med2->v2, NULL);
+ }
+ }
+ }
+
+ maxFaces = dm->getNumFaces(dm);
+ mface = CDDM_get_faces(result);
+ for (i=0; i < maxFaces; i++) {
+ MFace inMF;
+ MFace *mf = &mface[numFaces];
+
+ dm->getFace(dm, i, &inMF);
+
+ DM_copy_face_data(dm, result, i, numFaces, 1);
+ *mf = inMF;
+
+ mf->v1 = indexMap[inMF.v1].new;
+ mf->v2 = indexMap[inMF.v2].new;
+ mf->v3 = indexMap[inMF.v3].new;
+ if(inMF.v4)
+ mf->v4 = indexMap[inMF.v4].new;
+
+ /* if vertices are to be merged with the final copies of their
+ * merge targets, calculate that final copy
+ */
+ if(indexMap[inMF.v1].merge_final)
+ mf->v1 = calc_mapping(indexMap, indexMap[inMF.v1].merge, count-1);
+ if(indexMap[inMF.v2].merge_final)
+ mf->v2 = calc_mapping(indexMap, indexMap[inMF.v2].merge, count-1);
+ if(indexMap[inMF.v3].merge_final)
+ mf->v3 = calc_mapping(indexMap, indexMap[inMF.v3].merge, count-1);
+ if(inMF.v4 && indexMap[inMF.v4].merge_final)
+ mf->v4 = calc_mapping(indexMap, indexMap[inMF.v4].merge, count-1);
+
+ test_index_face(mf, &result->faceData, numFaces, inMF.v4?4:3);
+ numFaces++;
+
+ /* if the face has fewer than 3 vertices, don't create it */
+ if(mf->v3 == 0) {
+ numFaces--;
+ DM_free_face_data(result, numFaces, 1);
+ }
+
+ for(j = 1; j < count; j++)
+ {
+ MFace *mf2 = &mface[numFaces];
+
+ DM_copy_face_data(dm, result, i, numFaces, 1);
+ *mf2 = *mf;
+
+ mf2->v1 = calc_mapping(indexMap, inMF.v1, j);
+ mf2->v2 = calc_mapping(indexMap, inMF.v2, j);
+ mf2->v3 = calc_mapping(indexMap, inMF.v3, j);
+ if (inMF.v4)
+ mf2->v4 = calc_mapping(indexMap, inMF.v4, j);
+
+ test_index_face(mf2, &result->faceData, numFaces, inMF.v4?4:3);
+ numFaces++;
+
+ /* if the face has fewer than 3 vertices, don't create it */
+ if(mf2->v3 == 0) {
+ numFaces--;
+ DM_free_face_data(result, numFaces, 1);
+ }
+ }
+ }
+
+ /* add start and end caps */
+ if(start_cap) {
+ float startoffset[4][4];
+ MVert *cap_mvert;
+ MEdge *cap_medge;
+ MFace *cap_mface;
+ int *origindex;
+ int *vert_map;
+ int capVerts, capEdges, capFaces;
+
+ capVerts = start_cap->getNumVerts(start_cap);
+ capEdges = start_cap->getNumEdges(start_cap);
+ capFaces = start_cap->getNumFaces(start_cap);
+ cap_mvert = start_cap->getVertArray(start_cap);
+ cap_medge = start_cap->getEdgeArray(start_cap);
+ cap_mface = start_cap->getFaceArray(start_cap);
+
+ Mat4Invert(startoffset, offset);
+
+ vert_map = MEM_callocN(sizeof(*vert_map) * capVerts,
+ "arrayModifier_doArray vert_map");
+
+ origindex = result->getVertDataArray(result, CD_ORIGINDEX);
+ for(i = 0; i < capVerts; i++) {
+ MVert *mv = &cap_mvert[i];
+ short merged = 0;
+
+ if(amd->flags & MOD_ARR_MERGE) {
+ float tmp_co[3];
+ MVert *in_mv;
+ int j;
+
+ VECCOPY(tmp_co, mv->co);
+ Mat4MulVecfl(startoffset, tmp_co);
+
+ for(j = 0; j < maxVerts; j++) {
+ in_mv = &src_mvert[j];
+ /* if this vert is within merge limit, merge */
+ if(VecLenCompare(tmp_co, in_mv->co, amd->merge_dist)) {
+ vert_map[i] = calc_mapping(indexMap, j, 0);
+ merged = 1;
+ break;
+ }
+ }
+ }
+
+ if(!merged) {
+ DM_copy_vert_data(start_cap, result, i, numVerts, 1);
+ mvert[numVerts] = *mv;
+ Mat4MulVecfl(startoffset, mvert[numVerts].co);
+ origindex[numVerts] = ORIGINDEX_NONE;
+
+ vert_map[i] = numVerts;
+
+ numVerts++;
+ }
+ }
+ origindex = result->getEdgeDataArray(result, CD_ORIGINDEX);
+ for(i = 0; i < capEdges; i++) {
+ int v1, v2;
+
+ v1 = vert_map[cap_medge[i].v1];
+ v2 = vert_map[cap_medge[i].v2];
+
+ if(!BLI_edgehash_haskey(edges, v1, v2)) {
+ DM_copy_edge_data(start_cap, result, i, numEdges, 1);
+ medge[numEdges] = cap_medge[i];
+ medge[numEdges].v1 = v1;
+ medge[numEdges].v2 = v2;
+ origindex[numEdges] = ORIGINDEX_NONE;
+
+ numEdges++;
+ }
+ }
+ origindex = result->getFaceDataArray(result, CD_ORIGINDEX);
+ for(i = 0; i < capFaces; i++) {
+ DM_copy_face_data(start_cap, result, i, numFaces, 1);
+ mface[numFaces] = cap_mface[i];
+ mface[numFaces].v1 = vert_map[mface[numFaces].v1];
+ mface[numFaces].v2 = vert_map[mface[numFaces].v2];
+ mface[numFaces].v3 = vert_map[mface[numFaces].v3];
+ if(mface[numFaces].v4)
+ mface[numFaces].v4 = vert_map[mface[numFaces].v4];
+ origindex[numFaces] = ORIGINDEX_NONE;
+
+ numFaces++;
+ }
+
+ MEM_freeN(vert_map);
+ start_cap->release(start_cap);
+ }
+
+ if(end_cap) {
+ float endoffset[4][4];
+ MVert *cap_mvert;
+ MEdge *cap_medge;
+ MFace *cap_mface;
+ int *origindex;
+ int *vert_map;
+ int capVerts, capEdges, capFaces;
+
+ capVerts = end_cap->getNumVerts(end_cap);
+ capEdges = end_cap->getNumEdges(end_cap);
+ capFaces = end_cap->getNumFaces(end_cap);
+ cap_mvert = end_cap->getVertArray(end_cap);
+ cap_medge = end_cap->getEdgeArray(end_cap);
+ cap_mface = end_cap->getFaceArray(end_cap);
+
+ Mat4MulMat4(endoffset, final_offset, offset);
+
+ vert_map = MEM_callocN(sizeof(*vert_map) * capVerts,
+ "arrayModifier_doArray vert_map");
+
+ origindex = result->getVertDataArray(result, CD_ORIGINDEX);
+ for(i = 0; i < capVerts; i++) {
+ MVert *mv = &cap_mvert[i];
+ short merged = 0;
+
+ if(amd->flags & MOD_ARR_MERGE) {
+ float tmp_co[3];
+ MVert *in_mv;
+ int j;
+
+ VECCOPY(tmp_co, mv->co);
+ Mat4MulVecfl(offset, tmp_co);
+
+ for(j = 0; j < maxVerts; j++) {
+ in_mv = &src_mvert[j];
+ /* if this vert is within merge limit, merge */
+ if(VecLenCompare(tmp_co, in_mv->co, amd->merge_dist)) {
+ vert_map[i] = calc_mapping(indexMap, j, count - 1);
+ merged = 1;
+ break;
+ }
+ }
+ }
+
+ if(!merged) {
+ DM_copy_vert_data(end_cap, result, i, numVerts, 1);
+ mvert[numVerts] = *mv;
+ Mat4MulVecfl(endoffset, mvert[numVerts].co);
+ origindex[numVerts] = ORIGINDEX_NONE;
+
+ vert_map[i] = numVerts;
+
+ numVerts++;
+ }
+ }
+ origindex = result->getEdgeDataArray(result, CD_ORIGINDEX);
+ for(i = 0; i < capEdges; i++) {
+ int v1, v2;
+
+ v1 = vert_map[cap_medge[i].v1];
+ v2 = vert_map[cap_medge[i].v2];
+
+ if(!BLI_edgehash_haskey(edges, v1, v2)) {
+ DM_copy_edge_data(end_cap, result, i, numEdges, 1);
+ medge[numEdges] = cap_medge[i];
+ medge[numEdges].v1 = v1;
+ medge[numEdges].v2 = v2;
+ origindex[numEdges] = ORIGINDEX_NONE;
+
+ numEdges++;
+ }
+ }
+ origindex = result->getFaceDataArray(result, CD_ORIGINDEX);
+ for(i = 0; i < capFaces; i++) {
+ DM_copy_face_data(end_cap, result, i, numFaces, 1);
+ mface[numFaces] = cap_mface[i];
+ mface[numFaces].v1 = vert_map[mface[numFaces].v1];
+ mface[numFaces].v2 = vert_map[mface[numFaces].v2];
+ mface[numFaces].v3 = vert_map[mface[numFaces].v3];
+ if(mface[numFaces].v4)
+ mface[numFaces].v4 = vert_map[mface[numFaces].v4];
+ origindex[numFaces] = ORIGINDEX_NONE;
+
+ numFaces++;
+ }
+
+ MEM_freeN(vert_map);
+ end_cap->release(end_cap);
+ }
+
+ BLI_edgehash_free(edges, NULL);
+ MEM_freeN(indexMap);
+
+ CDDM_lower_num_verts(result, numVerts);
+ CDDM_lower_num_edges(result, numEdges);
+ CDDM_lower_num_faces(result, numFaces);
+
+ return result;
+}
+
+static DerivedMesh *arrayModifier_applyModifier(
+ ModifierData *md, Object *ob, DerivedMesh *derivedData,
+ int useRenderParams, int isFinalCalc)
+{
+ DerivedMesh *result;
+ ArrayModifierData *amd = (ArrayModifierData*) md;
+
+ result = arrayModifier_doArray(amd, ob, derivedData, 0);
+
+ CDDM_calc_normals(result);
+
+ return result;
+}
+
+static DerivedMesh *arrayModifier_applyModifierEM(
+ ModifierData *md, Object *ob, EditMesh *editData,
+ DerivedMesh *derivedData)
+{
+ return arrayModifier_applyModifier(md, ob, derivedData, 0, 1);
+}
+
+/* Mirror */
+
+static void mirrorModifier_initData(ModifierData *md)
+{
+ MirrorModifierData *mmd = (MirrorModifierData*) md;
+
+ mmd->flag |= MOD_MIR_AXIS_X;
+ mmd->tolerance = 0.001;
+}
+
+static void mirrorModifier_copyData(ModifierData *md, ModifierData *target)
+{
+ MirrorModifierData *mmd = (MirrorModifierData*) md;
+ MirrorModifierData *tmmd = (MirrorModifierData*) target;
+
+ tmmd->axis = mmd->axis;
+ tmmd->flag = mmd->flag;
+ tmmd->tolerance = mmd->tolerance;
+}
+
+static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd,
+ DerivedMesh *dm,
+ int initFlags,
+ int axis)
+{
+ int i;
+ float tolerance = mmd->tolerance;
+ DerivedMesh *result;
+ int numVerts, numEdges, numFaces;
+ int maxVerts = dm->getNumVerts(dm);
+ int maxEdges = dm->getNumEdges(dm);
+ int maxFaces = dm->getNumFaces(dm);
+ int (*indexMap)[2];
+
+ numVerts = numEdges = numFaces = 0;
+
+ indexMap = MEM_mallocN(sizeof(*indexMap) * maxVerts, "indexmap");
+
+ result = CDDM_from_template(dm, maxVerts * 2, maxEdges * 2, maxFaces * 2);
+
+ for(i = 0; i < maxVerts; i++) {
+ MVert inMV;
+ MVert *mv = CDDM_get_vert(result, numVerts);
+ int isShared;
+
+ dm->getVert(dm, i, &inMV);
+ isShared = ABS(inMV.co[axis])<=tolerance;
+
+ /* Because the topology result (# of vertices) must be the same if
+ * the mesh data is overridden by vertex cos, have to calc sharedness
+ * based on original coordinates. This is why we test before copy.
+ */
+ DM_copy_vert_data(dm, result, i, numVerts, 1);
+ *mv = inMV;
+ numVerts++;
+
+ indexMap[i][0] = numVerts - 1;
+ indexMap[i][1] = !isShared;
+
+ if(isShared) {
+ mv->co[axis] = 0;
+ mv->flag |= ME_VERT_MERGED;
+ } else {
+ MVert *mv2 = CDDM_get_vert(result, numVerts);
+
+ DM_copy_vert_data(dm, result, i, numVerts, 1);
+ *mv2 = *mv;
+ numVerts++;
+
+ mv2->co[axis] = -mv2->co[axis];
+ }
+ }
+
+ for(i = 0; i < maxEdges; i++) {
+ MEdge inMED;
+ MEdge *med = CDDM_get_edge(result, numEdges);
+
+ dm->getEdge(dm, i, &inMED);
+
+ DM_copy_edge_data(dm, result, i, numEdges, 1);
+ *med = inMED;
+ numEdges++;
+
+ med->v1 = indexMap[inMED.v1][0];
+ med->v2 = indexMap[inMED.v2][0];
+ if(initFlags)
+ med->flag |= ME_EDGEDRAW | ME_EDGERENDER;
+
+ if(indexMap[inMED.v1][1] || indexMap[inMED.v2][1]) {
+ MEdge *med2 = CDDM_get_edge(result, numEdges);
+
+ DM_copy_edge_data(dm, result, i, numEdges, 1);
+ *med2 = *med;
+ numEdges++;
+
+ med2->v1 += indexMap[inMED.v1][1];
+ med2->v2 += indexMap[inMED.v2][1];
+ }
+ }
+
+ for(i = 0; i < maxFaces; i++) {
+ MFace inMF;
+ MFace *mf = CDDM_get_face(result, numFaces);
+
+ dm->getFace(dm, i, &inMF);
+
+ DM_copy_face_data(dm, result, i, numFaces, 1);
+ *mf = inMF;
+ numFaces++;
+
+ mf->v1 = indexMap[inMF.v1][0];
+ mf->v2 = indexMap[inMF.v2][0];
+ mf->v3 = indexMap[inMF.v3][0];
+ mf->v4 = indexMap[inMF.v4][0];
+
+ if(indexMap[inMF.v1][1]
+ || indexMap[inMF.v2][1]
+ || indexMap[inMF.v3][1]
+ || (mf->v4 && indexMap[inMF.v4][1])) {
+ MFace *mf2 = CDDM_get_face(result, numFaces);
+ static int corner_indices[4] = {2, 1, 0, 3};
+
+ DM_copy_face_data(dm, result, i, numFaces, 1);
+ *mf2 = *mf;
+
+ mf2->v1 += indexMap[inMF.v1][1];
+ mf2->v2 += indexMap[inMF.v2][1];
+ mf2->v3 += indexMap[inMF.v3][1];
+ if(inMF.v4) mf2->v4 += indexMap[inMF.v4][1];
+
+ /* mirror UVs if enabled */
+ if(mmd->flag & (MOD_MIR_MIRROR_U | MOD_MIR_MIRROR_V)) {
+ MTFace *tf = result->getFaceData(result, numFaces, CD_MTFACE);
+ if(tf) {
+ int j;
+ for(j = 0; j < 4; ++j) {
+ if(mmd->flag & MOD_MIR_MIRROR_U)
+ tf->uv[j][0] = 1.0f - tf->uv[j][0];
+ if(mmd->flag & MOD_MIR_MIRROR_V)
+ tf->uv[j][1] = 1.0f - tf->uv[j][1];
+ }
+ }
+ }
+
+ /* Flip face normal */
+ SWAP(int, mf2->v1, mf2->v3);
+ DM_swap_face_data(result, numFaces, corner_indices);
+
+ test_index_face(mf2, &result->faceData, numFaces, inMF.v4?4:3);
+ numFaces++;
+ }
+ }
+
+ MEM_freeN(indexMap);
+
+ CDDM_lower_num_verts(result, numVerts);
+ CDDM_lower_num_edges(result, numEdges);
+ CDDM_lower_num_faces(result, numFaces);
+
+ return result;
+}
+
+static DerivedMesh *mirrorModifier__doMirror(MirrorModifierData *mmd,
+ DerivedMesh *dm,
+ int initFlags)
+{
+ DerivedMesh *result = dm;
+
+ /* check which axes have been toggled and mirror accordingly */
+ if(mmd->flag & MOD_MIR_AXIS_X) {
+ result = doMirrorOnAxis(mmd, result, initFlags, 0);
+ }
+ if(mmd->flag & MOD_MIR_AXIS_Y) {
+ DerivedMesh *tmp = result;
+ result = doMirrorOnAxis(mmd, result, initFlags, 1);
+ if(tmp != dm) tmp->release(tmp); /* free intermediate results */
+ }
+ if(mmd->flag & MOD_MIR_AXIS_Z) {
+ DerivedMesh *tmp = result;
+ result = doMirrorOnAxis(mmd, result, initFlags, 2);
+ if(tmp != dm) tmp->release(tmp); /* free intermediate results */
+ }
+
+ return result;
+}
+
+static DerivedMesh *mirrorModifier_applyModifier(
+ ModifierData *md, Object *ob, DerivedMesh *derivedData,
+ int useRenderParams, int isFinalCalc)
+{
+ DerivedMesh *result;
+ MirrorModifierData *mmd = (MirrorModifierData*) md;
+
+ result = mirrorModifier__doMirror(mmd, derivedData, 0);
+
+ CDDM_calc_normals(result);
+
+ return result;
+}
+
+static DerivedMesh *mirrorModifier_applyModifierEM(
+ ModifierData *md, Object *ob, EditMesh *editData,
+ DerivedMesh *derivedData)
+{
+ return mirrorModifier_applyModifier(md, ob, derivedData, 0, 1);
+}
+
+/* EdgeSplit */
+/* EdgeSplit modifier: Splits edges in the mesh according to sharpness flag
+ * or edge angle (can be used to achieve autosmoothing)
+*/
+#if 0
+#define EDGESPLIT_DEBUG_3
+#define EDGESPLIT_DEBUG_2
+#define EDGESPLIT_DEBUG_1
+#define EDGESPLIT_DEBUG_0
+#endif
+
+static void edgesplitModifier_initData(ModifierData *md)
+{
+ EdgeSplitModifierData *emd = (EdgeSplitModifierData*) md;
+
+ /* default to 30-degree split angle, sharpness from both angle & flag
+ */
+ emd->split_angle = 30;
+ emd->flags = MOD_EDGESPLIT_FROMANGLE | MOD_EDGESPLIT_FROMFLAG;
+}
+
+static void edgesplitModifier_copyData(ModifierData *md, ModifierData *target)
+{
+ EdgeSplitModifierData *emd = (EdgeSplitModifierData*) md;
+ EdgeSplitModifierData *temd = (EdgeSplitModifierData*) target;
+
+ temd->split_angle = emd->split_angle;
+ temd->flags = emd->flags;
+}
+
+/* Mesh data for edgesplit operation */
+typedef struct SmoothVert {
+ LinkNode *faces; /* all faces which use this vert */
+ int oldIndex; /* the index of the original DerivedMesh vert */
+ int newIndex; /* the index of the new DerivedMesh vert */
+} SmoothVert;
+
+#define SMOOTHEDGE_NUM_VERTS 2
+
+typedef struct SmoothEdge {
+ SmoothVert *verts[SMOOTHEDGE_NUM_VERTS]; /* the verts used by this edge */
+ LinkNode *faces; /* all faces which use this edge */
+ int oldIndex; /* the index of the original DerivedMesh edge */
+ int newIndex; /* the index of the new DerivedMesh edge */
+ short flag; /* the flags from the original DerivedMesh edge */
+} SmoothEdge;
+
+#define SMOOTHFACE_MAX_EDGES 4
+
+typedef struct SmoothFace {
+ SmoothEdge *edges[SMOOTHFACE_MAX_EDGES]; /* nonexistent edges == NULL */
+ int flip[SMOOTHFACE_MAX_EDGES]; /* 1 = flip edge dir, 0 = don't flip */
+ float normal[3]; /* the normal of this face */
+ int oldIndex; /* the index of the original DerivedMesh face */
+ int newIndex; /* the index of the new DerivedMesh face */
+} SmoothFace;
+
+typedef struct SmoothMesh {
+ SmoothVert *verts;
+ SmoothEdge *edges;
+ SmoothFace *faces;
+ int num_verts, num_edges, num_faces;
+ int max_verts, max_edges, max_faces;
+ DerivedMesh *dm;
+ float threshold; /* the cosine of the smoothing angle */
+ int flags;
+} SmoothMesh;
+
+static SmoothVert *smoothvert_copy(SmoothVert *vert, SmoothMesh *mesh)
+{
+ SmoothVert *copy = &mesh->verts[mesh->num_verts];
+
+ if(mesh->num_verts >= mesh->max_verts) {
+ printf("Attempted to add a SmoothMesh vert beyond end of array\n");
+ return NULL;
+ }
+
+ *copy = *vert;
+ copy->faces = NULL;
+ copy->newIndex = mesh->num_verts;
+ ++mesh->num_verts;
+
+#ifdef EDGESPLIT_DEBUG_2
+ printf("copied vert %4d to vert %4d\n", vert->newIndex, copy->newIndex);
+#endif
+ return copy;
+}
+
+static SmoothEdge *smoothedge_copy(SmoothEdge *edge, SmoothMesh *mesh)
+{
+ SmoothEdge *copy = &mesh->edges[mesh->num_edges];
+
+ if(mesh->num_edges >= mesh->max_edges) {
+ printf("Attempted to add a SmoothMesh edge beyond end of array\n");
+ return NULL;
+ }
+
+ *copy = *edge;
+ copy->faces = NULL;
+ copy->newIndex = mesh->num_edges;
+ ++mesh->num_edges;
+
+#ifdef EDGESPLIT_DEBUG_2
+ printf("copied edge %4d to edge %4d\n", edge->newIndex, copy->newIndex);
+#endif
+ return copy;
+}
+
+static int smoothedge_has_vert(SmoothEdge *edge, SmoothVert *vert)
+{
+ int i;
+ for(i = 0; i < SMOOTHEDGE_NUM_VERTS; i++)
+ if(edge->verts[i] == vert) return 1;
+
+ return 0;
+}
+
+static SmoothMesh *smoothmesh_new(int num_verts, int num_edges, int num_faces,
+ int max_verts, int max_edges, int max_faces)
+{
+ SmoothMesh *mesh = MEM_callocN(sizeof(*mesh), "smoothmesh");
+ mesh->verts = MEM_callocN(sizeof(*mesh->verts) * max_verts,
+ "SmoothMesh.verts");
+ mesh->edges = MEM_callocN(sizeof(*mesh->edges) * max_edges,
+ "SmoothMesh.edges");
+ mesh->faces = MEM_callocN(sizeof(*mesh->faces) * max_faces,
+ "SmoothMesh.faces");
+
+ mesh->num_verts = num_verts;
+ mesh->num_edges = num_edges;
+ mesh->num_faces = num_faces;
+
+ mesh->max_verts = max_verts;
+ mesh->max_edges = max_edges;
+ mesh->max_faces = max_faces;
+
+ return mesh;
+}
+
+static void smoothmesh_free(SmoothMesh *mesh)
+{
+ int i;
+
+ for(i = 0; i < mesh->num_verts; ++i)
+ BLI_linklist_free(mesh->verts[i].faces, NULL);
+
+ for(i = 0; i < mesh->num_edges; ++i)
+ BLI_linklist_free(mesh->edges[i].faces, NULL);
+
+ MEM_freeN(mesh->verts);
+ MEM_freeN(mesh->edges);
+ MEM_freeN(mesh->faces);
+ MEM_freeN(mesh);
+}
+
+static void smoothmesh_resize_verts(SmoothMesh *mesh, int max_verts)
+{
+ int i;
+ SmoothVert *tmp;
+
+ if(max_verts <= mesh->max_verts) return;
+
+ tmp = MEM_callocN(sizeof(*tmp) * max_verts, "SmoothMesh.verts");
+
+ memcpy(tmp, mesh->verts, sizeof(*tmp) * mesh->num_verts);
+
+ /* remap vert pointers in edges */
+ for(i = 0; i < mesh->num_edges; ++i) {
+ int j;
+ SmoothEdge *edge = &mesh->edges[i];
+
+ for(j = 0; j < SMOOTHEDGE_NUM_VERTS; ++j)
+ /* pointer arithmetic to get vert array index */
+ edge->verts[j] = &tmp[edge->verts[j] - mesh->verts];
+ }
+
+ MEM_freeN(mesh->verts);
+ mesh->verts = tmp;
+ mesh->max_verts = max_verts;
+}
+
+static void smoothmesh_resize_edges(SmoothMesh *mesh, int max_edges)
+{
+ int i;
+ SmoothEdge *tmp;
+
+ if(max_edges <= mesh->max_edges) return;
+
+ tmp = MEM_callocN(sizeof(*tmp) * max_edges, "SmoothMesh.edges");
+
+ memcpy(tmp, mesh->edges, sizeof(*tmp) * mesh->num_edges);
+
+ /* remap edge pointers in faces */
+ for(i = 0; i < mesh->num_faces; ++i) {
+ int j;
+ SmoothFace *face = &mesh->faces[i];
+
+ for(j = 0; j < SMOOTHFACE_MAX_EDGES; ++j)
+ if(face->edges[j])
+ /* pointer arithmetic to get edge array index */
+ face->edges[j] = &tmp[face->edges[j] - mesh->edges];
+ }
+
+ MEM_freeN(mesh->edges);
+ mesh->edges = tmp;
+ mesh->max_edges = max_edges;
+}
+
+#ifdef EDGESPLIT_DEBUG_0
+static void smoothmesh_print(SmoothMesh *mesh)
+{
+ int i, j;
+ DerivedMesh *dm = mesh->dm;
+
+ printf("--- SmoothMesh ---\n");
+ printf("--- Vertices ---\n");
+ for(i = 0; i < mesh->num_verts; i++) {
+ SmoothVert *vert = &mesh->verts[i];
+ LinkNode *node;
+ MVert mv;
+
+ dm->getVert(dm, vert->oldIndex, &mv);
+
+ printf("%3d: ind={%3d, %3d}, pos={% 5.1f, % 5.1f, % 5.1f}",
+ i, vert->oldIndex, vert->newIndex,
+ mv.co[0], mv.co[1], mv.co[2]);
+ printf(", faces={");
+ for(node = vert->faces; node != NULL; node = node->next) {
+ printf(" %d", ((SmoothFace *)node->link)->newIndex);
+ }
+ printf("}\n");
+ }
+
+ printf("\n--- Edges ---\n");
+ for(i = 0; i < mesh->num_edges; i++) {
+ SmoothEdge *edge = &mesh->edges[i];
+ LinkNode *node;
+
+ printf("%4d: indices={%4d, %4d}, verts={%4d, %4d}",
+ i,
+ edge->oldIndex, edge->newIndex,
+ edge->verts[0]->newIndex, edge->verts[1]->newIndex);
+ if(edge->verts[0] == edge->verts[1]) printf(" <- DUPLICATE VERTEX");
+ printf(", faces={");
+ for(node = edge->faces; node != NULL; node = node->next) {
+ printf(" %d", ((SmoothFace *)node->link)->newIndex);
+ }
+ printf("}\n");
+ }
+
+ printf("\n--- Faces ---\n");
+ for(i = 0; i < mesh->num_faces; i++) {
+ SmoothFace *face = &mesh->faces[i];
+
+ printf("%4d: indices={%4d, %4d}, edges={", i,
+ face->oldIndex, face->newIndex);
+ for(j = 0; j < SMOOTHFACE_MAX_EDGES && face->edges[j]; j++) {
+ if(face->flip[j])
+ printf(" -%-2d", face->edges[j]->newIndex);
+ else
+ printf(" %-2d", face->edges[j]->newIndex);
+ }
+ printf("}, verts={");
+ for(j = 0; j < SMOOTHFACE_MAX_EDGES && face->edges[j]; j++) {
+ printf(" %d", face->edges[j]->verts[face->flip[j]]->newIndex);
+ }
+ printf("}\n");
+ }
+}
+#endif
+
+static SmoothMesh *smoothmesh_from_derivedmesh(DerivedMesh *dm)
+{
+ SmoothMesh *mesh;
+ EdgeHash *edges = BLI_edgehash_new();
+ int i;
+ int totvert, totedge, totface;
+
+ totvert = dm->getNumVerts(dm);
+ totedge = dm->getNumEdges(dm);
+ totface = dm->getNumFaces(dm);
+
+ mesh = smoothmesh_new(totvert, totedge, totface,
+ totvert, totedge, totface);
+
+ mesh->dm = dm;
+
+ for(i = 0; i < totvert; i++) {
+ SmoothVert *vert = &mesh->verts[i];
+
+ vert->oldIndex = vert->newIndex = i;
+ }
+
+ for(i = 0; i < totedge; i++) {
+ SmoothEdge *edge = &mesh->edges[i];
+ MEdge med;
+
+ dm->getEdge(dm, i, &med);
+ edge->verts[0] = &mesh->verts[med.v1];
+ edge->verts[1] = &mesh->verts[med.v2];
+ edge->oldIndex = edge->newIndex = i;
+ edge->flag = med.flag;
+
+ BLI_edgehash_insert(edges, med.v1, med.v2, edge);
+ }
+
+ for(i = 0; i < totface; i++) {
+ SmoothFace *face = &mesh->faces[i];
+ MFace mf;
+ MVert v1, v2, v3;
+ int j;
+
+ dm->getFace(dm, i, &mf);
+
+ dm->getVert(dm, mf.v1, &v1);
+ dm->getVert(dm, mf.v2, &v2);
+ dm->getVert(dm, mf.v3, &v3);
+ face->edges[0] = BLI_edgehash_lookup(edges, mf.v1, mf.v2);
+ if(face->edges[0]->verts[1]->oldIndex == mf.v1) face->flip[0] = 1;
+ face->edges[1] = BLI_edgehash_lookup(edges, mf.v2, mf.v3);
+ if(face->edges[1]->verts[1]->oldIndex == mf.v2) face->flip[1] = 1;
+ if(mf.v4) {
+ MVert v4;
+ dm->getVert(dm, mf.v4, &v4);
+ face->edges[2] = BLI_edgehash_lookup(edges, mf.v3, mf.v4);
+ if(face->edges[2]->verts[1]->oldIndex == mf.v3) face->flip[2] = 1;
+ face->edges[3] = BLI_edgehash_lookup(edges, mf.v4, mf.v1);
+ if(face->edges[3]->verts[1]->oldIndex == mf.v4) face->flip[3] = 1;
+ CalcNormFloat4(v1.co, v2.co, v3.co, v4.co, face->normal);
+ } else {
+ face->edges[2] = BLI_edgehash_lookup(edges, mf.v3, mf.v1);
+ if(face->edges[2]->verts[1]->oldIndex == mf.v3) face->flip[2] = 1;
+ face->edges[3] = NULL;
+ CalcNormFloat(v1.co, v2.co, v3.co, face->normal);
+ }
+
+ for(j = 0; j < SMOOTHFACE_MAX_EDGES && face->edges[j]; j++) {
+ SmoothEdge *edge = face->edges[j];
+ BLI_linklist_prepend(&edge->faces, face);
+ BLI_linklist_prepend(&edge->verts[face->flip[j]]->faces, face);
+ }
+
+ face->oldIndex = face->newIndex = i;
+ }
+
+ BLI_edgehash_free(edges, NULL);
+
+ return mesh;
+}
+
+static DerivedMesh *CDDM_from_smoothmesh(SmoothMesh *mesh)
+{
+ DerivedMesh *result = CDDM_from_template(mesh->dm,
+ mesh->num_verts,
+ mesh->num_edges,
+ mesh->num_faces);
+ MVert *new_verts = CDDM_get_verts(result);
+ MEdge *new_edges = CDDM_get_edges(result);
+ MFace *new_faces = CDDM_get_faces(result);
+ int i;
+
+ for(i = 0; i < mesh->num_verts; ++i) {
+ SmoothVert *vert = &mesh->verts[i];
+ MVert *newMV = &new_verts[vert->newIndex];
+
+ DM_copy_vert_data(mesh->dm, result,
+ vert->oldIndex, vert->newIndex, 1);
+ mesh->dm->getVert(mesh->dm, vert->oldIndex, newMV);
+ }
+
+ for(i = 0; i < mesh->num_edges; ++i) {
+ SmoothEdge *edge = &mesh->edges[i];
+ MEdge *newME = &new_edges[edge->newIndex];
+
+ DM_copy_edge_data(mesh->dm, result,
+ edge->oldIndex, edge->newIndex, 1);
+ mesh->dm->getEdge(mesh->dm, edge->oldIndex, newME);
+ newME->v1 = edge->verts[0]->newIndex;
+ newME->v2 = edge->verts[1]->newIndex;
+ }
+
+ for(i = 0; i < mesh->num_faces; ++i) {
+ SmoothFace *face = &mesh->faces[i];
+ MFace *newMF = &new_faces[face->newIndex];
+
+ DM_copy_face_data(mesh->dm, result,
+ face->oldIndex, face->newIndex, 1);
+ mesh->dm->getFace(mesh->dm, face->oldIndex, newMF);
+
+ newMF->v1 = face->edges[0]->verts[face->flip[0]]->newIndex;
+ newMF->v2 = face->edges[1]->verts[face->flip[1]]->newIndex;
+ newMF->v3 = face->edges[2]->verts[face->flip[2]]->newIndex;
+
+ if(face->edges[3]) {
+ newMF->v4 = face->edges[3]->verts[face->flip[3]]->newIndex;
+ } else {
+ newMF->v4 = 0;
+ }
+ }
+
+ return result;
+}
+
+/* returns the other vert in the given edge
+ */
+static SmoothVert *other_vert(SmoothEdge *edge, SmoothVert *vert)
+{
+ if(edge->verts[0] == vert) return edge->verts[1];
+ else return edge->verts[0];
+}
+
+/* returns the other edge in the given face that uses the given vert
+ * returns NULL if no other edge in the given face uses the given vert
+ * (this should never happen)
+ */
+static SmoothEdge *other_edge(SmoothFace *face, SmoothVert *vert,
+ SmoothEdge *edge)
+{
+ int i,j;
+ for(i = 0; i < SMOOTHFACE_MAX_EDGES && face->edges[i]; i++) {
+ SmoothEdge *tmp_edge = face->edges[i];
+ if(tmp_edge == edge) continue;
+
+ for(j = 0; j < SMOOTHEDGE_NUM_VERTS; j++)
+ if(tmp_edge->verts[j] == vert) return tmp_edge;
+ }
+
+ /* if we get to here, something's wrong (there should always be 2 edges
+ * which use the same vert in a face)
+ */
+ return NULL;
+}
+
+/* returns a face attached to the given edge which is not the given face.
+ * returns NULL if no other faces use this edge.
+ */
+static SmoothFace *other_face(SmoothEdge *edge, SmoothFace *face)
+{
+ LinkNode *node;
+
+ for(node = edge->faces; node != NULL; node = node->next)
+ if(node->link != face) return node->link;
+
+ return NULL;
+}
+
+#if 0
+/* copies source list to target, overwriting target (target is not freed)
+ * nodes in the copy will be in the same order as in source
+ */
+static void linklist_copy(LinkNode **target, LinkNode *source)
+{
+ LinkNode *node = NULL;
+ *target = NULL;
+
+ for(; source; source = source->next) {
+ if(node) {
+ node->next = MEM_mallocN(sizeof(*node->next), "nlink_copy");
+ node = node->next;
+ } else {
+ node = *target = MEM_mallocN(sizeof(**target), "nlink_copy");
+ }
+ node->link = source->link;
+ node->next = NULL;
+ }
+}
+#endif
+
+/* appends source to target if it's not already in target */
+static void linklist_append_unique(LinkNode **target, void *source)
+{
+ LinkNode *node;
+ LinkNode *prev = NULL;
+
+ /* check if source value is already in the list */
+ for(node = *target; node; prev = node, node = node->next)
+ if(node->link == source) return;
+
+ node = MEM_mallocN(sizeof(*node), "nlink");
+ node->next = NULL;
+ node->link = source;
+
+ if(prev) prev->next = node;
+ else *target = node;
+}
+
+/* appends elements of source which aren't already in target to target */
+static void linklist_append_list_unique(LinkNode **target, LinkNode *source)
+{
+ for(; source; source = source->next)
+ linklist_append_unique(target, source->link);
+}
+
+#if 0 /* this is no longer used, it should possibly be removed */
+/* prepends prepend to list - doesn't copy nodes, just joins the lists */
+static void linklist_prepend_linklist(LinkNode **list, LinkNode *prepend)
+{
+ if(prepend) {
+ LinkNode *node = prepend;
+ while(node->next) node = node->next;
+
+ node->next = *list;
+ *list = prepend;
+ }
+}
+#endif
+
+/* returns 1 if the linked list contains the given pointer, 0 otherwise
+ */
+static int linklist_contains(LinkNode *list, void *ptr)
+{
+ LinkNode *node;
+
+ for(node = list; node; node = node->next)
+ if(node->link == ptr) return 1;
+
+ return 0;
+}
+
+/* returns 1 if the first linked list is a subset of the second (comparing
+ * pointer values), 0 if not
+ */
+static int linklist_subset(LinkNode *list1, LinkNode *list2)
+{
+ for(; list1; list1 = list1->next)
+ if(!linklist_contains(list2, list1->link))
+ return 0;
+
+ return 1;
+}
+
+#if 0
+/* empties the linked list
+ * frees pointers with freefunc if freefunc is not NULL
+ */
+static void linklist_empty(LinkNode **list, LinkNodeFreeFP freefunc)
+{
+ BLI_linklist_free(*list, freefunc);
+ *list = NULL;
+}
+#endif
+
+/* removes the first instance of value from the linked list
+ * frees the pointer with freefunc if freefunc is not NULL
+ */
+static void linklist_remove_first(LinkNode **list, void *value,
+ LinkNodeFreeFP freefunc)
+{
+ LinkNode *node = *list;
+ LinkNode *prev = NULL;
+
+ while(node && node->link != value) {
+ prev = node;
+ node = node->next;
+ }
+
+ if(node) {
+ if(prev)
+ prev->next = node->next;
+ else
+ *list = node->next;
+
+ if(freefunc)
+ freefunc(node->link);
+
+ MEM_freeN(node);
+ }
+}
+
+/* removes all elements in source from target */
+static void linklist_remove_list(LinkNode **target, LinkNode *source,
+ LinkNodeFreeFP freefunc)
+{
+ for(; source; source = source->next)
+ linklist_remove_first(target, source->link, freefunc);
+}
+
+#ifdef EDGESPLIT_DEBUG_0
+static void print_ptr(void *ptr)
+{
+ printf("%p\n", ptr);
+}
+
+static void print_edge(void *ptr)
+{
+ SmoothEdge *edge = ptr;
+ printf(" %4d", edge->newIndex);
+}
+
+static void print_face(void *ptr)
+{
+ SmoothFace *face = ptr;
+ printf(" %4d", face->newIndex);
+}
+#endif
+
+typedef struct ReplaceData {
+ void *find;
+ void *replace;
+} ReplaceData;
+
+static void edge_replace_vert(void *ptr, void *userdata)
+{
+ SmoothEdge *edge = ptr;
+ SmoothVert *find = ((ReplaceData *)userdata)->find;
+ SmoothVert *replace = ((ReplaceData *)userdata)->replace;
+ int i;
+
+#ifdef EDGESPLIT_DEBUG_3
+ printf("replacing vert %4d with %4d in edge %4d",
+ find->newIndex, replace->newIndex, edge->newIndex);
+ printf(": {%4d, %4d}", edge->verts[0]->newIndex, edge->verts[1]->newIndex);
+#endif
+
+ for(i = 0; i < SMOOTHEDGE_NUM_VERTS; i++) {
+ if(edge->verts[i] == find) {
+ linklist_append_list_unique(&replace->faces, edge->faces);
+ linklist_remove_list(&find->faces, edge->faces, NULL);
+
+ edge->verts[i] = replace;
+ }
+ }
+
+#ifdef EDGESPLIT_DEBUG_3
+ printf(" -> {%4d, %4d}\n", edge->verts[0]->newIndex, edge->verts[1]->newIndex);
+#endif
+}
+
+static void face_replace_vert(void *ptr, void *userdata)
+{
+ SmoothFace *face = ptr;
+ int i;
+
+ for(i = 0; i < SMOOTHFACE_MAX_EDGES && face->edges[i]; i++)
+ edge_replace_vert(face->edges[i], userdata);
+}
+
+static void face_replace_edge(void *ptr, void *userdata)
+{
+ SmoothFace *face = ptr;
+ SmoothEdge *find = ((ReplaceData *)userdata)->find;
+ SmoothEdge *replace = ((ReplaceData *)userdata)->replace;
+ int i;
+
+#ifdef EDGESPLIT_DEBUG_3
+ printf("replacing edge %4d with %4d in face %4d",
+ find->newIndex, replace->newIndex, face->newIndex);
+ if(face->edges[3])
+ printf(": {%2d %2d %2d %2d}",
+ face->edges[0]->newIndex, face->edges[1]->newIndex,
+ face->edges[2]->newIndex, face->edges[3]->newIndex);
+ else
+ printf(": {%2d %2d %2d}",
+ face->edges[0]->newIndex, face->edges[1]->newIndex,
+ face->edges[2]->newIndex);
+#endif
+
+ for(i = 0; i < SMOOTHFACE_MAX_EDGES && face->edges[i]; i++) {
+ if(face->edges[i] == find) {
+ linklist_remove_first(&face->edges[i]->faces, face, NULL);
+ BLI_linklist_prepend(&replace->faces, face);
+ face->edges[i] = replace;
+ }
+ }
+
+#ifdef EDGESPLIT_DEBUG_3
+ if(face->edges[3])
+ printf(" -> {%2d %2d %2d %2d}\n",
+ face->edges[0]->newIndex, face->edges[1]->newIndex,
+ face->edges[2]->newIndex, face->edges[3]->newIndex);
+ else
+ printf(" -> {%2d %2d %2d}\n",
+ face->edges[0]->newIndex, face->edges[1]->newIndex,
+ face->edges[2]->newIndex);
+#endif
+}
+
+static int edge_is_loose(SmoothEdge *edge)
+{
+ return !(edge->faces && edge->faces->next);
+}
+
+static int edge_is_sharp(SmoothEdge *edge, int flags,
+ float threshold)
+{
+#ifdef EDGESPLIT_DEBUG_1
+ printf("edge %d: ", edge->newIndex);
+#endif
+ if(edge->flag & ME_SHARP) {
+ /* edge can only be sharp if it has at least 2 faces */
+ if(!edge_is_loose(edge)) {
+#ifdef EDGESPLIT_DEBUG_1
+ printf("sharp\n");
+#endif
+ return 1;
+ } else {
+ /* edge is loose, so it can't be sharp */
+ edge->flag &= ~ME_SHARP;
+ }
+ }
+
+#ifdef EDGESPLIT_DEBUG_1
+ printf("not sharp\n");
+#endif
+ return 0;
+}
+
+/* finds another sharp edge which uses vert, by traversing faces around the
+ * vert until it does one of the following:
+ * - hits a loose edge (the edge is returned)
+ * - hits a sharp edge (the edge is returned)
+ * - returns to the start edge (NULL is returned)
+ */
+static SmoothEdge *find_other_sharp_edge(SmoothVert *vert, SmoothEdge *edge,
+ LinkNode **visited_faces, float threshold, int flags)
+{
+ SmoothFace *face = NULL;
+ SmoothEdge *edge2 = NULL;
+ /* holds the edges we've seen so we can avoid looping indefinitely */
+ LinkNode *visited_edges = NULL;
+#ifdef EDGESPLIT_DEBUG_1
+ printf("=== START === find_other_sharp_edge(edge = %4d, vert = %4d)\n",
+ edge->newIndex, vert->newIndex);
+#endif
+
+ /* get a face on which to start */
+ if(edge->faces) face = edge->faces->link;
+ else return NULL;
+
+ /* record this edge as visited */
+ BLI_linklist_prepend(&visited_edges, edge);
+
+ /* get the next edge */
+ edge2 = other_edge(face, vert, edge);
+
+ /* record this face as visited */
+ if(visited_faces)
+ BLI_linklist_prepend(visited_faces, face);
+
+ /* search until we hit a loose edge or a sharp edge or an edge we've
+ * seen before
+ */
+ while(face && !edge_is_sharp(edge2, flags, threshold)
+ && !linklist_contains(visited_edges, edge2)) {
+#ifdef EDGESPLIT_DEBUG_3
+ printf("current face %4d; current edge %4d\n", face->newIndex,
+ edge2->newIndex);
+#endif
+ /* get the next face */
+ face = other_face(edge2, face);
+
+ /* if face == NULL, edge2 is a loose edge */
+ if(face) {
+ /* record this face as visited */
+ if(visited_faces)
+ BLI_linklist_prepend(visited_faces, face);
+
+ /* record this edge as visited */
+ BLI_linklist_prepend(&visited_edges, edge2);
+
+ /* get the next edge */
+ edge2 = other_edge(face, vert, edge2);
+#ifdef EDGESPLIT_DEBUG_3
+ printf("next face %4d; next edge %4d\n",
+ face->newIndex, edge2->newIndex);
+ } else {
+ printf("loose edge: %4d\n", edge2->newIndex);
+#endif
+ }
+ }
+
+ /* either we came back to the start edge or we found a sharp/loose edge */
+ if(linklist_contains(visited_edges, edge2))
+ /* we came back to the start edge */
+ edge2 = NULL;
+
+ BLI_linklist_free(visited_edges, NULL);
+
+#ifdef EDGESPLIT_DEBUG_1
+ printf("=== END === find_other_sharp_edge(edge = %4d, vert = %4d), "
+ "returning edge %d\n",
+ edge->newIndex, vert->newIndex, edge2 ? edge2->newIndex : -1);
+#endif
+ return edge2;
+}
+
+static void split_single_vert(SmoothVert *vert, SmoothFace *face,
+ SmoothMesh *mesh)
+{
+ SmoothVert *copy_vert;
+ ReplaceData repdata;
+
+ copy_vert = smoothvert_copy(vert, mesh);
+
+ repdata.find = vert;
+ repdata.replace = copy_vert;
+ face_replace_vert(face, &repdata);
+}
+
+static void split_edge(SmoothEdge *edge, SmoothVert *vert, SmoothMesh *mesh);
+
+static void propagate_split(SmoothEdge *edge, SmoothVert *vert,
+ SmoothMesh *mesh)
+{
+ SmoothEdge *edge2;
+ LinkNode *visited_faces = NULL;
+#ifdef EDGESPLIT_DEBUG_1
+ printf("=== START === propagate_split(edge = %4d, vert = %4d)\n",
+ edge->newIndex, vert->newIndex);
+#endif
+
+ edge2 = find_other_sharp_edge(vert, edge, &visited_faces,
+ mesh->threshold, mesh->flags);
+
+ if(!edge2) {
+ /* didn't find a sharp or loose edge, so we've hit a dead end */
+ } else if(!edge_is_loose(edge2)) {
+ /* edge2 is not loose, so it must be sharp */
+ if(edge_is_loose(edge)) {
+ /* edge is loose, so we can split edge2 at this vert */
+ split_edge(edge2, vert, mesh);
+ } else if(edge_is_sharp(edge, mesh->flags, mesh->threshold)) {
+ /* both edges are sharp, so we can split the pair at vert */
+ split_edge(edge, vert, mesh);
+ } else {
+ /* edge is not sharp, so try to split edge2 at its other vert */
+ split_edge(edge2, other_vert(edge2, vert), mesh);
+ }
+ } else { /* edge2 is loose */
+ if(edge_is_loose(edge)) {
+ SmoothVert *vert2;
+ ReplaceData repdata;
+
+ /* can't split edge, what should we do with vert? */
+ if(linklist_subset(vert->faces, visited_faces)) {
+ /* vert has only one fan of faces attached; don't split it */
+ } else {
+ /* vert has more than one fan of faces attached; split it */
+ vert2 = smoothvert_copy(vert, mesh);
+
+ /* replace vert with its copy in visited_faces */
+ repdata.find = vert;
+ repdata.replace = vert2;
+ BLI_linklist_apply(visited_faces, face_replace_vert, &repdata);
+ }
+ } else {
+ /* edge is not loose, so it must be sharp; split it */
+ split_edge(edge, vert, mesh);
+ }
+ }
+
+ BLI_linklist_free(visited_faces, NULL);
+#ifdef EDGESPLIT_DEBUG_1
+ printf("=== END === propagate_split(edge = %4d, vert = %4d)\n",
+ edge->newIndex, vert->newIndex);
+#endif
+}
+
+static void split_edge(SmoothEdge *edge, SmoothVert *vert, SmoothMesh *mesh)
+{
+ SmoothEdge *edge2;
+ SmoothVert *vert2;
+ ReplaceData repdata;
+ /* the list of faces traversed while looking for a sharp edge */
+ LinkNode *visited_faces = NULL;
+#ifdef EDGESPLIT_DEBUG_1
+ printf("=== START === split_edge(edge = %4d, vert = %4d)\n",
+ edge->newIndex, vert->newIndex);
+#endif
+
+ edge2 = find_other_sharp_edge(vert, edge, &visited_faces,
+ mesh->threshold, mesh->flags);
+
+ if(!edge2) {
+ /* didn't find a sharp or loose edge, so try the other vert */
+ vert2 = other_vert(edge, vert);
+ propagate_split(edge, vert2, mesh);
+ } else if(!edge_is_loose(edge2)) {
+ /* edge2 is not loose, so it must be sharp */
+ SmoothEdge *copy_edge = smoothedge_copy(edge, mesh);
+ SmoothEdge *copy_edge2 = smoothedge_copy(edge2, mesh);
+ SmoothVert *vert2;
+
+ /* replace edge with its copy in visited_faces */
+ repdata.find = edge;
+ repdata.replace = copy_edge;
+ BLI_linklist_apply(visited_faces, face_replace_edge, &repdata);
+
+ /* replace edge2 with its copy in visited_faces */
+ repdata.find = edge2;
+ repdata.replace = copy_edge2;
+ BLI_linklist_apply(visited_faces, face_replace_edge, &repdata);
+
+ vert2 = smoothvert_copy(vert, mesh);
+
+ /* replace vert with its copy in visited_faces (must be done after
+ * edge replacement so edges have correct vertices)
+ */
+ repdata.find = vert;
+ repdata.replace = vert2;
+ BLI_linklist_apply(visited_faces, face_replace_vert, &repdata);
+
+ /* all copying and replacing is done; the mesh should be consistent.
+ * now propagate the split to the vertices at either end
+ */
+ propagate_split(copy_edge, other_vert(copy_edge, vert2), mesh);
+ propagate_split(copy_edge2, other_vert(copy_edge2, vert2), mesh);
+
+ if(smoothedge_has_vert(edge, vert))
+ propagate_split(edge, vert, mesh);
+ } else {
+ /* edge2 is loose */
+ SmoothEdge *copy_edge = smoothedge_copy(edge, mesh);
+ SmoothVert *vert2;
+
+ /* replace edge with its copy in visited_faces */
+ repdata.find = edge;
+ repdata.replace = copy_edge;
+ BLI_linklist_apply(visited_faces, face_replace_edge, &repdata);
+
+ vert2 = smoothvert_copy(vert, mesh);
+
+ /* replace vert with its copy in visited_faces (must be done after
+ * edge replacement so edges have correct vertices)
+ */
+ repdata.find = vert;
+ repdata.replace = vert2;
+ BLI_linklist_apply(visited_faces, face_replace_vert, &repdata);
+
+ /* copying and replacing is done; the mesh should be consistent.
+ * now propagate the split to the vertex at the other end
+ */
+ propagate_split(copy_edge, other_vert(copy_edge, vert2), mesh);
+
+ if(smoothedge_has_vert(edge, vert))
+ propagate_split(edge, vert, mesh);
+ }
+
+ BLI_linklist_free(visited_faces, NULL);
+#ifdef EDGESPLIT_DEBUG_1
+ printf("=== END === split_edge(edge = %4d, vert = %4d)\n",
+ edge->newIndex, vert->newIndex);
+#endif
+}
+
+static void tag_and_count_extra_edges(SmoothMesh *mesh, float split_angle,
+ int flags, int *extra_edges)
+{
+ /* if normal1 dot normal2 < threshold, angle is greater, so split */
+ /* FIXME not sure if this always works */
+ /* 0.00001 added for floating-point rounding */
+ float threshold = cos((split_angle + 0.00001) * M_PI / 180.0);
+ int i;
+
+ *extra_edges = 0;
+
+ /* loop through edges, counting potential new ones */
+ for(i = 0; i < mesh->num_edges; i++) {
+ SmoothEdge *edge = &mesh->edges[i];
+ int sharp = 0;
+
+ /* treat all non-manifold edges (3 or more faces) as sharp */
+ if(edge->faces && edge->faces->next && edge->faces->next->next) {
+ LinkNode *node;
+
+ /* this edge is sharp */
+ sharp = 1;
+
+ /* add an extra edge for every face beyond the first */
+ *extra_edges += 2;
+ for(node = edge->faces->next->next->next; node; node = node->next)
+ (*extra_edges)++;
+ } else if((flags & (MOD_EDGESPLIT_FROMANGLE | MOD_EDGESPLIT_FROMFLAG))
+ && !edge_is_loose(edge)) {
+ /* (the edge can only be sharp if we're checking angle or flag,
+ * and it has at least 2 faces) */
+
+ /* if we're checking the sharp flag and it's set, good */
+ if((flags & MOD_EDGESPLIT_FROMFLAG) && (edge->flag & ME_SHARP)) {
+ /* this edge is sharp */
+ sharp = 1;
+
+ (*extra_edges)++;
+ } else if(flags & MOD_EDGESPLIT_FROMANGLE) {
+ /* we know the edge has 2 faces, so check the angle */
+ SmoothFace *face1 = edge->faces->link;
+ SmoothFace *face2 = edge->faces->next->link;
+ float edge_angle_cos = MTC_dot3Float(face1->normal,
+ face2->normal);
+
+ if(edge_angle_cos < threshold) {
+ /* this edge is sharp */
+ sharp = 1;
+
+ (*extra_edges)++;
+ }
+ }
+ }
+
+ /* set/clear sharp flag appropriately */
+ if(sharp) edge->flag |= ME_SHARP;
+ else edge->flag &= ~ME_SHARP;
+ }
+}
+
+static void split_sharp_edges(SmoothMesh *mesh, float split_angle, int flags)
+{
+ int i;
+ /* if normal1 dot normal2 < threshold, angle is greater, so split */
+ /* FIXME not sure if this always works */
+ /* 0.00001 added for floating-point rounding */
+ mesh->threshold = cos((split_angle + 0.00001) * M_PI / 180.0);
+ mesh->flags = flags;
+
+ /* loop through edges, splitting sharp ones */
+ /* can't use an iterator here, because we'll be adding edges */
+ for(i = 0; i < mesh->num_edges; i++) {
+ SmoothEdge *edge = &mesh->edges[i];
+
+ if(edge_is_sharp(edge, flags, mesh->threshold))
+ split_edge(edge, edge->verts[0], mesh);
+ }
+
+}
+
+static int count_bridge_verts(SmoothMesh *mesh)
+{
+ int i, j, count = 0;
+
+ for(i = 0; i < mesh->num_faces; i++) {
+ SmoothFace *face = &mesh->faces[i];
+
+ for(j = 0; j < SMOOTHFACE_MAX_EDGES && face->edges[j]; j++) {
+ SmoothEdge *edge = face->edges[j];
+ SmoothEdge *next_edge;
+ SmoothVert *vert = edge->verts[1 - face->flip[j]];
+ int next = (j + 1) % SMOOTHFACE_MAX_EDGES;
+
+ /* wrap next around if at last edge */
+ if(!face->edges[next]) next = 0;
+
+ next_edge = face->edges[next];
+
+ /* if there are other faces sharing this vertex but not
+ * these edges, the vertex will be split, so count it
+ */
+ /* vert has to have at least one face (this one), so faces != 0 */
+ if(!edge->faces->next && !next_edge->faces->next
+ && vert->faces->next) {
+ count++;
+ }
+ }
+ }
+
+ /* each bridge vert will be counted once per face that uses it,
+ * so count is too high, but it's ok for now
+ */
+ return count;
+}
+
+static void split_bridge_verts(SmoothMesh *mesh)
+{
+ int i,j;
+
+ for(i = 0; i < mesh->num_faces; i++) {
+ SmoothFace *face = &mesh->faces[i];
+
+ for(j = 0; j < SMOOTHFACE_MAX_EDGES && face->edges[j]; j++) {
+ SmoothEdge *edge = face->edges[j];
+ SmoothEdge *next_edge;
+ SmoothVert *vert = edge->verts[1 - face->flip[j]];
+ int next = (j + 1) % SMOOTHFACE_MAX_EDGES;
+
+ /* wrap next around if at last edge */
+ if(!face->edges[next]) next = 0;
+
+ next_edge = face->edges[next];
+
+ /* if there are other faces sharing this vertex but not
+ * these edges, split the vertex
+ */
+ /* vert has to have at least one face (this one), so faces != 0 */
+ if(!edge->faces->next && !next_edge->faces->next
+ && vert->faces->next)
+ /* FIXME this needs to find all faces that share edges with
+ * this one and split off together
+ */
+ split_single_vert(vert, face, mesh);
+ }
+ }
+}
+
+static DerivedMesh *edgesplitModifier_do(EdgeSplitModifierData *emd,
+ Object *ob, DerivedMesh *dm)
+{
+ SmoothMesh *mesh;
+ DerivedMesh *result;
+ int max_verts, max_edges;
+
+ if(!(emd->flags & (MOD_EDGESPLIT_FROMANGLE | MOD_EDGESPLIT_FROMFLAG)))
+ return dm;
+
+ /* 1. make smoothmesh with initial number of elements */
+ mesh = smoothmesh_from_derivedmesh(dm);
+
+ /* 2. count max number of elements to add */
+ tag_and_count_extra_edges(mesh, emd->split_angle, emd->flags, &max_edges);
+ max_verts = max_edges * 2 + mesh->max_verts;
+ max_verts += count_bridge_verts(mesh);
+ max_edges += mesh->max_edges;
+
+ /* 3. reallocate smoothmesh arrays & copy elements across */
+ /* 4. remap copied elements' pointers to point into the new arrays */
+ smoothmesh_resize_verts(mesh, max_verts);
+ smoothmesh_resize_edges(mesh, max_edges);
+
+#ifdef EDGESPLIT_DEBUG_1
+ printf("********** Pre-split **********\n");
+ smoothmesh_print(mesh);
+#endif
+
+ split_sharp_edges(mesh, emd->split_angle, emd->flags);
+#ifdef EDGESPLIT_DEBUG_1
+ printf("********** Post-edge-split **********\n");
+ smoothmesh_print(mesh);
+#endif
+
+ split_bridge_verts(mesh);
+
+#ifdef EDGESPLIT_DEBUG_1
+ printf("********** Post-vert-split **********\n");
+ smoothmesh_print(mesh);
+#endif
+
+#ifdef EDGESPLIT_DEBUG_0
+ printf("Edgesplit: Estimated %d verts & %d edges, "
+ "found %d verts & %d edges\n", max_verts, max_edges,
+ mesh->num_verts, mesh->num_edges);
+#endif
+
+ result = CDDM_from_smoothmesh(mesh);
+ smoothmesh_free(mesh);
+
+ return result;
+}
+
+static DerivedMesh *edgesplitModifier_applyModifier(
+ ModifierData *md, Object *ob, DerivedMesh *derivedData,
+ int useRenderParams, int isFinalCalc)
+{
+ DerivedMesh *result;
+ EdgeSplitModifierData *emd = (EdgeSplitModifierData*) md;
+
+ result = edgesplitModifier_do(emd, ob, derivedData);
+
+ CDDM_calc_normals(result);
+
+ return result;
+}
+
+static DerivedMesh *edgesplitModifier_applyModifierEM(
+ ModifierData *md, Object *ob, EditMesh *editData,
+ DerivedMesh *derivedData)
+{
+ return edgesplitModifier_applyModifier(md, ob, derivedData, 0, 1);
+}
+
+/* Displace */
+
+static void displaceModifier_initData(ModifierData *md)
+{
+ DisplaceModifierData *dmd = (DisplaceModifierData*) md;
+
+ dmd->texture = NULL;
+ dmd->strength = 1;
+ dmd->direction = MOD_DISP_DIR_NOR;
+ dmd->midlevel = 0.5;
+}
+
+static void displaceModifier_copyData(ModifierData *md, ModifierData *target)
+{
+ DisplaceModifierData *dmd = (DisplaceModifierData*) md;
+ DisplaceModifierData *tdmd = (DisplaceModifierData*) target;
+
+ tdmd->texture = dmd->texture;
+ tdmd->strength = dmd->strength;
+ tdmd->direction = dmd->direction;
+ strncpy(tdmd->defgrp_name, dmd->defgrp_name, 32);
+ tdmd->midlevel = dmd->midlevel;
+ tdmd->texmapping = dmd->texmapping;
+ tdmd->map_object = dmd->map_object;
+ strncpy(tdmd->uvlayer_name, dmd->uvlayer_name, 32);
+}
+
+CustomDataMask displaceModifier_requiredDataMask(ModifierData *md)
+{
+ DisplaceModifierData *dmd = (DisplaceModifierData *)md;
+ CustomDataMask dataMask = 0;
+
+ /* ask for vertexgroups if we need them */
+ if(dmd->defgrp_name[0]) dataMask |= (1 << CD_MDEFORMVERT);
+
+ /* ask for UV coordinates if we need them */
+ if(dmd->texmapping == MOD_DISP_MAP_UV) dataMask |= (1 << CD_MTFACE);
+
+ return dataMask;
+}
+
+static void displaceModifier_foreachObjectLink(ModifierData *md, Object *ob,
+ ObjectWalkFunc walk, void *userData)
+{
+ DisplaceModifierData *dmd = (DisplaceModifierData*) md;
+
+ walk(userData, ob, &dmd->map_object);
+}
+
+static void displaceModifier_foreachIDLink(ModifierData *md, Object *ob,
+ IDWalkFunc walk, void *userData)
+{
+ DisplaceModifierData *dmd = (DisplaceModifierData*) md;
+
+ walk(userData, ob, (ID **)&dmd->texture);
+
+ displaceModifier_foreachObjectLink(md, ob, (ObjectWalkFunc) walk, userData);
+}
+
+static int displaceModifier_isDisabled(ModifierData *md)
+{
+ DisplaceModifierData *dmd = (DisplaceModifierData*) md;
+
+ return !dmd->texture;
+}
+
+static void displaceModifier_updateDepgraph(
+ ModifierData *md, DagForest *forest,
+ Object *ob, DagNode *obNode)
+{
+ DisplaceModifierData *dmd = (DisplaceModifierData*) md;
+
+ if(dmd->map_object) {
+ DagNode *curNode = dag_get_node(forest, dmd->map_object);
+
+ dag_add_relation(forest, curNode, obNode,
+ DAG_RL_DATA_DATA | DAG_RL_OB_DATA);
+ }
+}
+
+static void validate_layer_name(const CustomData *data, int type, char *name)
+{
+ int index = -1;
+
+ /* if a layer name was given, try to find that layer */
+ if(name[0])
+ index = CustomData_get_named_layer_index(data, CD_MTFACE, name);
+
+ if(index < 0) {
+ /* either no layer was specified, or the layer we want has been
+ * deleted, so assign the active layer to name
+ */
+ index = CustomData_get_active_layer_index(data, CD_MTFACE);
+ strcpy(name, data->layers[index].name);
+ }
+}
+
+static void get_texture_coords(DisplaceModifierData *dmd, Object *ob,
+ DerivedMesh *dm,
+ float (*co)[3], float (*texco)[3],
+ int numVerts)
+{
+ int i;
+ int texmapping = dmd->texmapping;
+
+ if(texmapping == MOD_DISP_MAP_OBJECT) {
+ if(dmd->map_object)
+ Mat4Invert(dmd->map_object->imat, dmd->map_object->obmat);
+ else /* if there is no map object, default to local */
+ texmapping = MOD_DISP_MAP_LOCAL;
+ }
+
+ /* UVs need special handling, since they come from faces */
+ if(texmapping == MOD_DISP_MAP_UV) {
+ if(dm->getFaceDataArray(dm, CD_MTFACE)) {
+ MFace *mface = dm->getFaceArray(dm);
+ MFace *mf;
+ char *done = MEM_callocN(sizeof(*done) * numVerts,
+ "get_texture_coords done");
+ int numFaces = dm->getNumFaces(dm);
+ MTFace *tf;
+
+ validate_layer_name(&dm->faceData, CD_MTFACE, dmd->uvlayer_name);
+
+ tf = CustomData_get_layer_named(&dm->faceData, CD_MTFACE,
+ dmd->uvlayer_name);
+
+ /* verts are given the UV from the first face that uses them */
+ for(i = 0, mf = mface; i < numFaces; ++i, ++mf, ++tf) {
+ if(!done[mf->v1]) {
+ texco[mf->v1][0] = tf->uv[0][0];
+ texco[mf->v1][1] = tf->uv[0][1];
+ texco[mf->v1][2] = 0;
+ done[mf->v1] = 1;
+ }
+ if(!done[mf->v2]) {
+ texco[mf->v2][0] = tf->uv[1][0];
+ texco[mf->v2][1] = tf->uv[1][1];
+ texco[mf->v2][2] = 0;
+ done[mf->v2] = 1;
+ }
+ if(!done[mf->v3]) {
+ texco[mf->v3][0] = tf->uv[2][0];
+ texco[mf->v3][1] = tf->uv[2][1];
+ texco[mf->v3][2] = 0;
+ done[mf->v3] = 1;
+ }
+ if(!done[mf->v4]) {
+ texco[mf->v4][0] = tf->uv[3][0];
+ texco[mf->v4][1] = tf->uv[3][1];
+ texco[mf->v4][2] = 0;
+ done[mf->v4] = 1;
+ }
+ }
+
+ /* remap UVs from [0, 1] to [-1, 1] */
+ for(i = 0; i < numVerts; ++i) {
+ texco[i][0] = texco[i][0] * 2 - 1;
+ texco[i][1] = texco[i][1] * 2 - 1;
+ }
+
+ MEM_freeN(done);
+ return;
+ } else /* if there are no UVs, default to local */
+ texmapping = MOD_DISP_MAP_LOCAL;
+ }
+
+ for(i = 0; i < numVerts; ++i, ++co, ++texco) {
+ switch(texmapping) {
+ case MOD_DISP_MAP_LOCAL:
+ VECCOPY(*texco, *co);
+ break;
+ case MOD_DISP_MAP_GLOBAL:
+ VECCOPY(*texco, *co);
+ Mat4MulVecfl(ob->obmat, *texco);
+ break;
+ case MOD_DISP_MAP_OBJECT:
+ VECCOPY(*texco, *co);
+ Mat4MulVecfl(ob->obmat, *texco);
+ Mat4MulVecfl(dmd->map_object->imat, *texco);
+ break;
+ }
+ }
+}
+
+static void get_texture_value(Tex *texture, float *tex_co, TexResult *texres)
+{
+ int result_type;
+
+ result_type = multitex_ext(texture, tex_co, NULL,
+ NULL, 1, texres);
+
+ /* if the texture gave an RGB value, we assume it didn't give a valid
+ * intensity, so calculate one (formula from do_material_tex).
+ * if the texture didn't give an RGB value, copy the intensity across
+ */
+ if(result_type & TEX_RGB)
+ texres->tin = (0.35 * texres->tr + 0.45 * texres->tg
+ + 0.2 * texres->tb);
+ else
+ texres->tr = texres->tg = texres->tb = texres->tin;
+}
+
+/* dm must be a CDDerivedMesh */
+static void displaceModifier_do(
+ DisplaceModifierData *dmd, Object *ob,
+ DerivedMesh *dm, float (*vertexCos)[3], int numVerts)
+{
+ int i;
+ MVert *mvert;
+ MDeformVert *dvert = NULL;
+ int defgrp_index;
+ float (*tex_co)[3];
+
+ if(!dmd->texture) return;
+
+ defgrp_index = -1;
+
+ if(dmd->defgrp_name[0]) {
+ bDeformGroup *def;
+ for(i = 0, def = ob->defbase.first; def; def = def->next, i++) {
+ if(!strcmp(def->name, dmd->defgrp_name)) {
+ defgrp_index = i;
+ break;
+ }
+ }
+ }
+
+ mvert = CDDM_get_verts(dm);
+ if(defgrp_index >= 0)
+ dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
+
+ tex_co = MEM_callocN(sizeof(*tex_co) * numVerts,
+ "displaceModifier_do tex_co");
+ get_texture_coords(dmd, ob, dm, vertexCos, tex_co, numVerts);
+
+ for(i = 0; i < numVerts; ++i) {
+ TexResult texres;
+ float delta = 0, strength = dmd->strength;
+ MDeformWeight *def_weight = NULL;
+
+ if(dvert) {
+ int j;
+ for(j = 0; j < dvert[i].totweight; ++j) {
+ if(dvert[i].dw[j].def_nr == defgrp_index) {
+ def_weight = &dvert[i].dw[j];
+ break;
+ }
+ }
+ if(!def_weight) continue;
+ }
+
+ texres.nor = NULL;
+ get_texture_value(dmd->texture, tex_co[i], &texres);
+
+ delta = texres.tin - dmd->midlevel;
+
+ if(def_weight) strength *= def_weight->weight;
+
+ delta *= strength;
+
+ switch(dmd->direction) {
+ case MOD_DISP_DIR_X:
+ vertexCos[i][0] += delta;
+ break;
+ case MOD_DISP_DIR_Y:
+ vertexCos[i][1] += delta;
+ break;
+ case MOD_DISP_DIR_Z:
+ vertexCos[i][2] += delta;
+ break;
+ case MOD_DISP_DIR_RGB_XYZ:
+ vertexCos[i][0] += (texres.tr - dmd->midlevel) * strength;
+ vertexCos[i][1] += (texres.tg - dmd->midlevel) * strength;
+ vertexCos[i][2] += (texres.tb - dmd->midlevel) * strength;
+ break;
+ case MOD_DISP_DIR_NOR:
+ vertexCos[i][0] += delta * mvert[i].no[0] / 32767.0f;
+ vertexCos[i][1] += delta * mvert[i].no[1] / 32767.0f;
+ vertexCos[i][2] += delta * mvert[i].no[2] / 32767.0f;
+ break;
+ }
+ }
+
+ MEM_freeN(tex_co);
+}
+
+static void displaceModifier_deformVerts(
+ ModifierData *md, Object *ob, DerivedMesh *derivedData,
+ float (*vertexCos)[3], int numVerts)
+{
+ DerivedMesh *dm;
+
+ if(derivedData) dm = CDDM_copy(derivedData);
+ else if(ob->type==OB_MESH) dm = CDDM_from_mesh(ob->data, ob);
+ else return;
+
+ CDDM_apply_vert_coords(dm, vertexCos);
+ CDDM_calc_normals(dm);
+
+ displaceModifier_do((DisplaceModifierData *)md, ob, dm,
+ vertexCos, numVerts);
+
+ dm->release(dm);
+}
+
+static void displaceModifier_deformVertsEM(
+ ModifierData *md, Object *ob, EditMesh *editData,
+ DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
+{
+ DerivedMesh *dm;
+
+ if(derivedData) dm = CDDM_copy(derivedData);
+ else dm = CDDM_from_editmesh(editData, ob->data);
+
+ CDDM_apply_vert_coords(dm, vertexCos);
+ CDDM_calc_normals(dm);
+
+ displaceModifier_do((DisplaceModifierData *)md, ob, dm,
+ vertexCos, numVerts);
+
+ dm->release(dm);
+}
+
+/* UVProject */
+/* UV Project modifier: Generates UVs projected from an object
+*/
+
+static void uvprojectModifier_initData(ModifierData *md)
+{
+ UVProjectModifierData *umd = (UVProjectModifierData*) md;
+ int i;
+
+ for(i = 0; i < MOD_UVPROJECT_MAXPROJECTORS; ++i)
+ umd->projectors[i] = NULL;
+ umd->image = NULL;
+ umd->flags = 0;
+ umd->num_projectors = 1;
+ umd->aspectx = umd->aspecty = 1.0f;
+}
+
+static void uvprojectModifier_copyData(ModifierData *md, ModifierData *target)
+{
+ UVProjectModifierData *umd = (UVProjectModifierData*) md;
+ UVProjectModifierData *tumd = (UVProjectModifierData*) target;
+ int i;
+
+ for(i = 0; i < MOD_UVPROJECT_MAXPROJECTORS; ++i)
+ tumd->projectors[i] = umd->projectors[i];
+ tumd->image = umd->image;
+ tumd->flags = umd->flags;
+ tumd->num_projectors = umd->num_projectors;
+ tumd->aspectx = umd->aspectx;
+ tumd->aspecty = umd->aspecty;
+}
+
+CustomDataMask uvprojectModifier_requiredDataMask(ModifierData *md)
+{
+ CustomDataMask dataMask = 0;
+
+ /* ask for UV coordinates */
+ dataMask |= (1 << CD_MTFACE);
+
+ return dataMask;
+}
+
+static void uvprojectModifier_foreachObjectLink(ModifierData *md, Object *ob,
+ ObjectWalkFunc walk, void *userData)
+{
+ UVProjectModifierData *umd = (UVProjectModifierData*) md;
+ int i;
+
+ for(i = 0; i < MOD_UVPROJECT_MAXPROJECTORS; ++i)
+ walk(userData, ob, &umd->projectors[i]);
+}
+
+static void uvprojectModifier_foreachIDLink(ModifierData *md, Object *ob,
+ IDWalkFunc walk, void *userData)
+{
+ UVProjectModifierData *umd = (UVProjectModifierData*) md;
+
+ walk(userData, ob, (ID **)&umd->image);
+
+ uvprojectModifier_foreachObjectLink(md, ob, (ObjectWalkFunc)walk,
+ userData);
+}
+
+static void uvprojectModifier_updateDepgraph(ModifierData *md,
+ DagForest *forest, Object *ob, DagNode *obNode)
+{
+ UVProjectModifierData *umd = (UVProjectModifierData*) md;
+ int i;
+
+ for(i = 0; i < umd->num_projectors; ++i) {
+ if(umd->projectors[i]) {
+ DagNode *curNode = dag_get_node(forest, umd->projectors[i]);
+
+ dag_add_relation(forest, curNode, obNode,
+ DAG_RL_DATA_DATA | DAG_RL_OB_DATA);
+ }
+ }
+}
+
+typedef struct Projector {
+ Object *ob; /* object this projector is derived from */
+ float projmat[4][4]; /* projection matrix */
+ float normal[3]; /* projector normal in world space */
+} Projector;
+
+static DerivedMesh *uvprojectModifier_do(UVProjectModifierData *umd,
+ Object *ob, DerivedMesh *dm)
+{
+ float (*coords)[3], (*co)[3];
+ MTFace *tface;
+ int i, numVerts, numFaces;
+ Image *image = umd->image;
+ MFace *mface, *mf;
+ int override_image = ((umd->flags & MOD_UVPROJECT_OVERRIDEIMAGE) != 0);
+ Projector projectors[MOD_UVPROJECT_MAXPROJECTORS];
+ int num_projectors = 0;
+ float aspect;
+
+ if(umd->aspecty != 0) aspect = umd->aspectx / umd->aspecty;
+ else aspect = 1.0f;
+
+ for(i = 0; i < umd->num_projectors; ++i)
+ if(umd->projectors[i])
+ projectors[num_projectors++].ob = umd->projectors[i];
+
+ if(num_projectors == 0) return dm;
+
+ /* make sure there are UV layers available */
+ if(!dm->getFaceDataArray(dm, CD_MTFACE)) return dm;
+
+ /* make sure we're using an existing layer */
+ validate_layer_name(&dm->faceData, CD_MTFACE, umd->uvlayer_name);
+
+ /* make sure we are not modifying the original UV layer */
+ tface = CustomData_duplicate_referenced_layer_named(&dm->faceData,
+ CD_MTFACE,
+ umd->uvlayer_name);
+
+ numVerts = dm->getNumVerts(dm);
+
+ coords = MEM_callocN(sizeof(*coords) * numVerts,
+ "uvprojectModifier_do coords");
+ dm->getVertCos(dm, coords);
+
+ /* convert coords to world space */
+ for(i = 0, co = coords; i < numVerts; ++i, ++co)
+ Mat4MulVecfl(ob->obmat, *co);
+
+ /* calculate a projection matrix and normal for each projector */
+ for(i = 0; i < num_projectors; ++i) {
+ float tmpmat[4][4];
+ float offsetmat[4][4];
+
+ /* calculate projection matrix */
+ Mat4Invert(projectors[i].projmat, projectors[i].ob->obmat);
+
+ if(projectors[i].ob->type == OB_CAMERA) {
+ Camera *cam = (Camera *)projectors[i].ob->data;
+ if(cam->type == CAM_PERSP) {
+ float perspmat[4][4];
+ float xmax;
+ float xmin;
+ float ymax;
+ float ymin;
+ float pixsize = cam->clipsta * 32.0 / cam->lens;
+
+ if(aspect > 1.0f) {
+ xmax = 0.5f * pixsize;
+ ymax = xmax / aspect;
+ } else {
+ ymax = 0.5f * pixsize;
+ xmax = ymax * aspect;
+ }
+ xmin = -xmax;
+ ymin = -ymax;
+
+ i_window(xmin, xmax, ymin, ymax,
+ cam->clipsta, cam->clipend, perspmat);
+ Mat4MulMat4(tmpmat, projectors[i].projmat, perspmat);
+ } else if(cam->type == CAM_ORTHO) {
+ float orthomat[4][4];
+ float xmax;
+ float xmin;
+ float ymax;
+ float ymin;
+
+ if(aspect > 1.0f) {
+ xmax = 0.5f * cam->ortho_scale;
+ ymax = xmax / aspect;
+ } else {
+ ymax = 0.5f * cam->ortho_scale;
+ xmax = ymax * aspect;
+ }
+ xmin = -xmax;
+ ymin = -ymax;
+
+ i_ortho(xmin, xmax, ymin, ymax,
+ cam->clipsta, cam->clipend, orthomat);
+ Mat4MulMat4(tmpmat, projectors[i].projmat, orthomat);
+ }
+ } else {
+ Mat4CpyMat4(tmpmat, projectors[i].projmat);
+ }
+
+ Mat4One(offsetmat);
+ Mat4MulFloat3(offsetmat[0], 0.5);
+ offsetmat[3][0] = offsetmat[3][1] = offsetmat[3][2] = 0.5;
+ Mat4MulMat4(projectors[i].projmat, tmpmat, offsetmat);
+
+ /* calculate worldspace projector normal (for best projector test) */
+ projectors[i].normal[0] = 0;
+ projectors[i].normal[1] = 0;
+ projectors[i].normal[2] = 1;
+ Mat4Mul3Vecfl(projectors[i].ob->obmat, projectors[i].normal);
+ }
+
+ /* if only one projector, project coords to UVs */
+ if(num_projectors == 1)
+ for(i = 0, co = coords; i < numVerts; ++i, ++co)
+ Mat4MulVec3Project(projectors[0].projmat, *co);
+
+ mface = dm->getFaceArray(dm);
+ numFaces = dm->getNumFaces(dm);
+
+ /* apply coords as UVs, and apply image if tfaces are new */
+ for(i = 0, mf = mface; i < numFaces; ++i, ++mf, ++tface) {
+ if(override_image || !image || tface->tpage == image) {
+ if(num_projectors == 1) {
+ /* apply transformed coords as UVs */
+ tface->uv[0][0] = coords[mf->v1][0];
+ tface->uv[0][1] = coords[mf->v1][1];
+ tface->uv[1][0] = coords[mf->v2][0];
+ tface->uv[1][1] = coords[mf->v2][1];
+ tface->uv[2][0] = coords[mf->v3][0];
+ tface->uv[2][1] = coords[mf->v3][1];
+ if(mf->v4) {
+ tface->uv[3][0] = coords[mf->v4][0];
+ tface->uv[3][1] = coords[mf->v4][1];
+ }
+ } else {
+ /* multiple projectors, select the closest to face normal
+ * direction
+ */
+ float co1[3], co2[3], co3[3], co4[3];
+ float face_no[3];
+ int j;
+ Projector *best_projector;
+ float best_dot;
+
+ VECCOPY(co1, coords[mf->v1]);
+ VECCOPY(co2, coords[mf->v2]);
+ VECCOPY(co3, coords[mf->v3]);
+
+ /* get the untransformed face normal */
+ if(mf->v4) {
+ VECCOPY(co4, coords[mf->v4]);
+ CalcNormFloat4(co1, co2, co3, co4, face_no);
+ } else {
+ CalcNormFloat(co1, co2, co3, face_no);
+ }
+
+ /* find the projector which the face points at most directly
+ * (projector normal with largest dot product is best)
+ */
+ best_dot = MTC_dot3Float(projectors[0].normal, face_no);
+ best_projector = &projectors[0];
+
+ for(j = 1; j < num_projectors; ++j) {
+ float tmp_dot = MTC_dot3Float(projectors[j].normal,
+ face_no);
+ if(tmp_dot > best_dot) {
+ best_dot = tmp_dot;
+ best_projector = &projectors[j];
+ }
+ }
+
+ Mat4MulVec3Project(best_projector->projmat, co1);
+ Mat4MulVec3Project(best_projector->projmat, co2);
+ Mat4MulVec3Project(best_projector->projmat, co3);
+ if(mf->v4)
+ Mat4MulVec3Project(best_projector->projmat, co4);
+
+ /* apply transformed coords as UVs */
+ tface->uv[0][0] = co1[0];
+ tface->uv[0][1] = co1[1];
+ tface->uv[1][0] = co2[0];
+ tface->uv[1][1] = co2[1];
+ tface->uv[2][0] = co3[0];
+ tface->uv[2][1] = co3[1];
+ if(mf->v4) {
+ tface->uv[3][0] = co4[0];
+ tface->uv[3][1] = co4[1];
+ }
+ }
+ }
+
+ if(override_image) {
+ tface->mode = TF_TEX;
+ tface->tpage = image;
+ }
+ }
+
+ MEM_freeN(coords);
+
+ return dm;
+}
+
+static DerivedMesh *uvprojectModifier_applyModifier(
+ ModifierData *md, Object *ob, DerivedMesh *derivedData,
+ int useRenderParams, int isFinalCalc)
+{
+ DerivedMesh *result;
+ UVProjectModifierData *umd = (UVProjectModifierData*) md;
+
+ result = uvprojectModifier_do(umd, ob, derivedData);
+
+ return result;
+}
+
+static DerivedMesh *uvprojectModifier_applyModifierEM(
+ ModifierData *md, Object *ob, EditMesh *editData,
+ DerivedMesh *derivedData)
+{
+ return uvprojectModifier_applyModifier(md, ob, derivedData, 0, 1);
+}
+
+/* Decimate */
+
+static void decimateModifier_initData(ModifierData *md)
+{
+ DecimateModifierData *dmd = (DecimateModifierData*) md;
+
+ dmd->percent = 1.0;
+}
+
+static void decimateModifier_copyData(ModifierData *md, ModifierData *target)
+{
+ DecimateModifierData *dmd = (DecimateModifierData*) md;
+ DecimateModifierData *tdmd = (DecimateModifierData*) target;
+
+ tdmd->percent = dmd->percent;
+}
+
+static DerivedMesh *decimateModifier_applyModifier(
+ ModifierData *md, Object *ob, DerivedMesh *derivedData,
+ int useRenderParams, int isFinalCalc)
+{
+ DecimateModifierData *dmd = (DecimateModifierData*) md;
+ DerivedMesh *dm = derivedData, *result = NULL;
+ MVert *mvert;
+ MFace *mface;
+ LOD_Decimation_Info lod;
+ int totvert, totface;
+ int a, numTris;
+
+ mvert = dm->getVertArray(dm);
+ mface = dm->getFaceArray(dm);
+ totvert = dm->getNumVerts(dm);
+ totface = dm->getNumFaces(dm);
+
+ numTris = 0;
+ for (a=0; a<totface; a++) {
+ MFace *mf = &mface[a];
+ numTris++;
+ if (mf->v4) numTris++;
+ }
+
+ if(numTris<3) {
+ modifier_setError(md,
+ "There must be more than 3 input faces (triangles).");
+ goto exit;
+ }
+
+ lod.vertex_buffer= MEM_mallocN(3*sizeof(float)*totvert, "vertices");
+ lod.vertex_normal_buffer= MEM_mallocN(3*sizeof(float)*totvert, "normals");
+ lod.triangle_index_buffer= MEM_mallocN(3*sizeof(int)*numTris, "trias");
+ lod.vertex_num= totvert;
+ lod.face_num= numTris;
+
+ for(a=0; a<totvert; a++) {
+ MVert *mv = &mvert[a];
+ float *vbCo = &lod.vertex_buffer[a*3];
+ float *vbNo = &lod.vertex_normal_buffer[a*3];
+
+ VECCOPY(vbCo, mv->co);
+
+ vbNo[0] = mv->no[0]/32767.0f;
+ vbNo[1] = mv->no[1]/32767.0f;
+ vbNo[2] = mv->no[2]/32767.0f;
+ }
+
+ numTris = 0;
+ for(a=0; a<totface; a++) {
+ MFace *mf = &mface[a];
+ int *tri = &lod.triangle_index_buffer[3*numTris++];
+ tri[0]= mf->v1;
+ tri[1]= mf->v2;
+ tri[2]= mf->v3;
+
+ if(mf->v4) {
+ tri = &lod.triangle_index_buffer[3*numTris++];
+ tri[0]= mf->v1;
+ tri[1]= mf->v3;
+ tri[2]= mf->v4;
+ }
+ }
+
+ dmd->faceCount = 0;
+ if(LOD_LoadMesh(&lod) ) {
+ if( LOD_PreprocessMesh(&lod) ) {
+ /* we assume the decim_faces tells how much to reduce */
+
+ while(lod.face_num > numTris*dmd->percent) {
+ if( LOD_CollapseEdge(&lod)==0) break;
+ }
+
+ if(lod.vertex_num>2) {
+ result = CDDM_new(lod.vertex_num, 0, lod.face_num);
+ dmd->faceCount = lod.face_num;
+ }
+ else
+ result = CDDM_new(lod.vertex_num, 0, 0);
+
+ mvert = CDDM_get_verts(result);
+ for(a=0; a<lod.vertex_num; a++) {
+ MVert *mv = &mvert[a];
+ float *vbCo = &lod.vertex_buffer[a*3];
+
+ VECCOPY(mv->co, vbCo);
+ }
+
+ if(lod.vertex_num>2) {
+ mface = CDDM_get_faces(result);
+ for(a=0; a<lod.face_num; a++) {
+ MFace *mf = &mface[a];
+ int *tri = &lod.triangle_index_buffer[a*3];
+ mf->v1 = tri[0];
+ mf->v2 = tri[1];
+ mf->v3 = tri[2];
+ test_index_face(mf, NULL, 0, 3);
+ }
+ }
+
+ CDDM_calc_edges(result);
+ CDDM_calc_normals(result);
+ }
+ else
+ modifier_setError(md, "Out of memory.");
+
+ LOD_FreeDecimationData(&lod);
+ }
+ else
+ modifier_setError(md, "Non-manifold mesh as input.");
+
+ MEM_freeN(lod.vertex_buffer);
+ MEM_freeN(lod.vertex_normal_buffer);
+ MEM_freeN(lod.triangle_index_buffer);
+
+exit:
+ return result;
+}
+
+/* Smooth */
+
+static void smoothModifier_initData(ModifierData *md)
+{
+ SmoothModifierData *smd = (SmoothModifierData*) md;
+
+ smd->fac = 0.5f;
+ smd->repeat = 1;
+ smd->flag = MOD_SMOOTH_X | MOD_SMOOTH_Y | MOD_SMOOTH_Z;
+ smd->defgrp_name[0] = '\0';
+}
+
+static void smoothModifier_copyData(ModifierData *md, ModifierData *target)
+{
+ SmoothModifierData *smd = (SmoothModifierData*) md;
+ SmoothModifierData *tsmd = (SmoothModifierData*) target;
+
+ tsmd->fac = smd->fac;
+ tsmd->repeat = smd->repeat;
+ tsmd->flag = smd->flag;
+ strncpy(tsmd->defgrp_name, smd->defgrp_name, 32);
+}
+
+int smoothModifier_isDisabled(ModifierData *md)
+{
+ SmoothModifierData *smd = (SmoothModifierData*) md;
+ short flag;
+
+ flag = smd->flag & (MOD_SMOOTH_X|MOD_SMOOTH_Y|MOD_SMOOTH_Z);
+
+ /* disable if modifier is off for X, Y and Z or if factor is 0 */
+ if((smd->fac == 0.0f) || flag == 0) return 1;
+
+ return 0;
+}
+
+CustomDataMask smoothModifier_requiredDataMask(ModifierData *md)
+{
+ SmoothModifierData *smd = (SmoothModifierData *)md;
+ CustomDataMask dataMask = 0;
+
+ /* ask for vertexgroups if we need them */
+ if(smd->defgrp_name[0]) dataMask |= (1 << CD_MDEFORMVERT);
+
+ return dataMask;
+}
+
+static void smoothModifier_do(
+ SmoothModifierData *smd, Object *ob, DerivedMesh *dm,
+ float (*vertexCos)[3], int numVerts)
+{
+ MDeformVert *dvert = NULL;
+ MEdge *medges = NULL;
+
+ int i, j, numDMEdges, defgrp_index;
+ unsigned char *uctmp;
+ float *ftmp, fac, facm;
+
+ ftmp = (float*)MEM_callocN(3*sizeof(float)*numVerts,
+ "smoothmodifier_f");
+ if (!ftmp) return;
+ uctmp = (unsigned char*)MEM_callocN(sizeof(unsigned char)*numVerts,
+ "smoothmodifier_uc");
+ if (!uctmp) {
+ if (ftmp) MEM_freeN(ftmp);
+ return;
+ }
+
+ fac = smd->fac;
+ facm = 1 - fac;
+
+ medges = CDDM_get_edges(dm);
+ numDMEdges = dm->getNumEdges(dm);
+
+ defgrp_index = -1;
+
+ if (smd->defgrp_name[0]) {
+ bDeformGroup *def;
+
+ for (i = 0, def = ob->defbase.first; def; def = def->next, i++) {
+ if (!strcmp(def->name, smd->defgrp_name)) {
+ defgrp_index = i;
+ break;
+ }
+ }
+ }
+
+ if (defgrp_index >= 0)
+ dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
+
+ /* NOTICE: this can be optimized a little bit by moving the
+ * if (dvert) out of the loop, if needed */
+ for (j = 0; j < smd->repeat; j++) {
+ for (i = 0; i < numDMEdges; i++) {
+ float fvec[3];
+ float *v1, *v2;
+ unsigned int idx1, idx2;
+
+ idx1 = medges[i].v1;
+ idx2 = medges[i].v2;
+
+ v1 = vertexCos[idx1];
+ v2 = vertexCos[idx2];
+
+ fvec[0] = (v1[0] + v2[0]) / 2.0;
+ fvec[1] = (v1[1] + v2[1]) / 2.0;
+ fvec[2] = (v1[2] + v2[2]) / 2.0;
+
+ v1 = &ftmp[idx1*3];
+ v2 = &ftmp[idx2*3];
+
+ if (uctmp[idx1] < 255) {
+ uctmp[idx1]++;
+ VecAddf(v1, v1, fvec);
+ }
+ if (uctmp[idx2] < 255) {
+ uctmp[idx2]++;
+ VecAddf(v2, v2, fvec);
+ }
+ }
+
+ if (dvert) {
+ for (i = 0; i < numVerts; i++) {
+ MDeformWeight *dw = NULL;
+ float f, fm, facw, *fp, *v;
+ int k;
+ short flag = smd->flag;
+
+ v = vertexCos[i];
+ fp = &ftmp[i*3];
+
+ for (k = 0; k < dvert[i].totweight; ++k) {
+ if(dvert[i].dw[k].def_nr == defgrp_index) {
+ dw = &dvert[i].dw[k];
+ break;
+ }
+ }
+ if (!dw) continue;
+
+ f = fac * dw->weight;
+ fm = 1.0f - f;
+
+ /* fp is the sum of uctmp[i] verts, so must be averaged */
+ facw = 0.0f;
+ if (uctmp[i])
+ facw = f / (float)uctmp[i];
+
+ if (flag & MOD_SMOOTH_X)
+ v[0] = fm * v[0] + facw * fp[0];
+ if (flag & MOD_SMOOTH_Y)
+ v[1] = fm * v[1] + facw * fp[1];
+ if (flag & MOD_SMOOTH_Z)
+ v[2] = fm * v[2] + facw * fp[2];
+ }
+ }
+ else { /* no vertex group */
+ for (i = 0; i < numVerts; i++) {
+ float facw, *fp, *v;
+ short flag = smd->flag;
+
+ v = vertexCos[i];
+ fp = &ftmp[i*3];
+
+ /* fp is the sum of uctmp[i] verts, so must be averaged */
+ facw = 0.0f;
+ if (uctmp[i])
+ facw = fac / (float)uctmp[i];
+
+ if (flag & MOD_SMOOTH_X)
+ v[0] = facm * v[0] + facw * fp[0];
+ if (flag & MOD_SMOOTH_Y)
+ v[1] = facm * v[1] + facw * fp[1];
+ if (flag & MOD_SMOOTH_Z)
+ v[2] = facm * v[2] + facw * fp[2];
+ }
+
+ }
+
+ memset(ftmp, 0, 3*sizeof(float)*numVerts);
+ memset(uctmp, 0, sizeof(unsigned char)*numVerts);
+ }
+
+ MEM_freeN(ftmp);
+ MEM_freeN(uctmp);
+}
+
+static void smoothModifier_deformVerts(
+ ModifierData *md, Object *ob, DerivedMesh *derivedData,
+ float (*vertexCos)[3], int numVerts)
+{
+ DerivedMesh *dm;
+
+ if(derivedData) dm = CDDM_copy(derivedData);
+ else dm = CDDM_from_mesh(ob->data, ob);
+
+ CDDM_apply_vert_coords(dm, vertexCos);
+ CDDM_calc_normals(dm);
+
+ smoothModifier_do((SmoothModifierData *)md, ob, dm,
+ vertexCos, numVerts);
+
+ dm->release(dm);
+}
+
+static void smoothModifier_deformVertsEM(
+ ModifierData *md, Object *ob, EditMesh *editData,
+ DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
+{
+ DerivedMesh *dm;
+
+ if(derivedData) dm = CDDM_copy(derivedData);
+ else dm = CDDM_from_editmesh(editData, ob->data);
+
+ CDDM_apply_vert_coords(dm, vertexCos);
+ CDDM_calc_normals(dm);
+
+ smoothModifier_do((SmoothModifierData *)md, ob, dm,
+ vertexCos, numVerts);
+
+ dm->release(dm);
+}
+
+/* Cast */
+
+static void castModifier_initData(ModifierData *md)
+{
+ CastModifierData *cmd = (CastModifierData*) md;
+
+ cmd->fac = 0.5f;
+ cmd->radius = 0.0f;
+ cmd->size = 0.0f;
+ cmd->flag = MOD_CAST_X | MOD_CAST_Y | MOD_CAST_Z
+ | MOD_CAST_SIZE_FROM_RADIUS;
+ cmd->type = MOD_CAST_TYPE_SPHERE;
+ cmd->defgrp_name[0] = '\0';
+ cmd->object = NULL;
+}
+
+
+static void castModifier_copyData(ModifierData *md, ModifierData *target)
+{
+ CastModifierData *cmd = (CastModifierData*) md;
+ CastModifierData *tcmd = (CastModifierData*) target;
+
+ tcmd->fac = cmd->fac;
+ tcmd->radius = cmd->radius;
+ tcmd->size = cmd->size;
+ tcmd->flag = cmd->flag;
+ tcmd->type = cmd->type;
+ tcmd->object = cmd->object;
+ strncpy(tcmd->defgrp_name, cmd->defgrp_name, 32);
+}
+
+int castModifier_isDisabled(ModifierData *md)
+{
+ CastModifierData *cmd = (CastModifierData*) md;
+ short flag;
+
+ flag = cmd->flag & (MOD_CAST_X|MOD_CAST_Y|MOD_CAST_Z);
+
+ if((cmd->fac == 0.0f) || flag == 0) return 1;
+
+ return 0;
+}
+
+CustomDataMask castModifier_requiredDataMask(ModifierData *md)
+{
+ CastModifierData *cmd = (CastModifierData *)md;
+ CustomDataMask dataMask = 0;
+
+ /* ask for vertexgroups if we need them */
+ if(cmd->defgrp_name[0]) dataMask |= (1 << CD_MDEFORMVERT);
+
+ return dataMask;
+}
+
+static void castModifier_foreachObjectLink(
+ ModifierData *md, Object *ob,
+ void (*walk)(void *userData, Object *ob, Object **obpoin),
+ void *userData)
+{
+ CastModifierData *cmd = (CastModifierData*) md;
+
+ walk (userData, ob, &cmd->object);
+}
+
+static void castModifier_updateDepgraph(
+ ModifierData *md, DagForest *forest, Object *ob,
+ DagNode *obNode)
+{
+ CastModifierData *cmd = (CastModifierData*) md;
+
+ if (cmd->object) {
+ DagNode *curNode = dag_get_node(forest, cmd->object);
+
+ dag_add_relation(forest, curNode, obNode, DAG_RL_OB_DATA);
+ }
+}
+
+static void castModifier_sphere_do(
+ CastModifierData *cmd, Object *ob, DerivedMesh *dm,
+ float (*vertexCos)[3], int numVerts)
+{
+ MDeformVert *dvert = NULL;
+
+ Object *ctrl_ob = NULL;
+
+ int i, defgrp_index = -1;
+ int has_radius = 0;
+ short flag, type;
+ float fac, facm, len = 0.0f;
+ float vec[3], center[3] = {0.0f, 0.0f, 0.0f};
+ float mat[4][4], imat[4][4];
+
+ fac = cmd->fac;
+ facm = 1.0f - fac;
+
+ flag = cmd->flag;
+ type = cmd->type; /* projection type: sphere or cylinder */
+
+ if (type == MOD_CAST_TYPE_CYLINDER)
+ flag &= ~MOD_CAST_Z;
+
+ ctrl_ob = cmd->object;
+
+ /* spherify's center is {0, 0, 0} (the ob's own center in its local
+ * space), by default, but if the user defined a control object,
+ * we use its location, transformed to ob's local space */
+ if (ctrl_ob) {
+ if(flag & MOD_CAST_USE_OB_TRANSFORM) {
+ Mat4Invert(ctrl_ob->imat, ctrl_ob->obmat);
+ Mat4MulMat4(mat, ob->obmat, ctrl_ob->imat);
+ Mat4Invert(imat, mat);
+ }
+
+ Mat4Invert(ob->imat, ob->obmat);
+ VECCOPY(center, ctrl_ob->obmat[3]);
+ Mat4MulVecfl(ob->imat, center);
+ }
+
+ /* now we check which options the user wants */
+
+ /* 1) (flag was checked in the "if (ctrl_ob)" block above) */
+ /* 2) cmd->radius > 0.0f: only the vertices within this radius from
+ * the center of the effect should be deformed */
+ if (cmd->radius > FLT_EPSILON) has_radius = 1;
+
+ /* 3) if we were given a vertex group name,
+ * only those vertices should be affected */
+ if (cmd->defgrp_name[0]) {
+ bDeformGroup *def;
+
+ for (i = 0, def = ob->defbase.first; def; def = def->next, i++) {
+ if (!strcmp(def->name, cmd->defgrp_name)) {
+ defgrp_index = i;
+ break;
+ }
+ }
+ }
+
+ if ((ob->type == OB_MESH) && dm && defgrp_index >= 0)
+ dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
+
+ if(flag & MOD_CAST_SIZE_FROM_RADIUS) {
+ len = cmd->radius;
+ }
+ else {
+ len = cmd->size;
+ }
+
+ if(len <= 0) {
+ for (i = 0; i < numVerts; i++) {
+ len += VecLenf(center, vertexCos[i]);
+ }
+ len /= numVerts;
+
+ if (len == 0.0f) len = 10.0f;
+ }
+
+ /* ready to apply the effect, one vertex at a time;
+ * tiny optimization: the code is separated (with parts repeated)
+ * in two possible cases:
+ * with or w/o a vgroup. With lots of if's in the code below,
+ * further optimizations are possible, if needed */
+ if (dvert) { /* with a vgroup */
+ float fac_orig = fac;
+ for (i = 0; i < numVerts; i++) {
+ MDeformWeight *dw = NULL;
+ int j;
+ float tmp_co[3];
+
+ VECCOPY(tmp_co, vertexCos[i]);
+ if(ctrl_ob) {
+ if(flag & MOD_CAST_USE_OB_TRANSFORM) {
+ Mat4MulVecfl(mat, tmp_co);
+ } else {
+ VecSubf(tmp_co, tmp_co, center);
+ }
+ }
+
+ VECCOPY(vec, tmp_co);
+
+ if (type == MOD_CAST_TYPE_CYLINDER)
+ vec[2] = 0.0f;
+
+ if (has_radius) {
+ if (VecLength(vec) > cmd->radius) continue;
+ }
+
+ for (j = 0; j < dvert[i].totweight; ++j) {
+ if(dvert[i].dw[j].def_nr == defgrp_index) {
+ dw = &dvert[i].dw[j];
+ break;
+ }
+ }
+ if (!dw) continue;
+
+ fac = fac_orig * dw->weight;
+ facm = 1.0f - fac;
+
+ Normalize(vec);
+
+ if (flag & MOD_CAST_X)
+ tmp_co[0] = fac*vec[0]*len + facm*tmp_co[0];
+ if (flag & MOD_CAST_Y)
+ tmp_co[1] = fac*vec[1]*len + facm*tmp_co[1];
+ if (flag & MOD_CAST_Z)
+ tmp_co[2] = fac*vec[2]*len + facm*tmp_co[2];
+
+ if(ctrl_ob) {
+ if(flag & MOD_CAST_USE_OB_TRANSFORM) {
+ Mat4MulVecfl(imat, tmp_co);
+ } else {
+ VecAddf(tmp_co, tmp_co, center);
+ }
+ }
+
+ VECCOPY(vertexCos[i], tmp_co);
+ }
+ return;
+ }
+
+ /* no vgroup */
+ for (i = 0; i < numVerts; i++) {
+ float tmp_co[3];
+
+ VECCOPY(tmp_co, vertexCos[i]);
+ if(ctrl_ob) {
+ if(flag & MOD_CAST_USE_OB_TRANSFORM) {
+ Mat4MulVecfl(mat, tmp_co);
+ } else {
+ VecSubf(tmp_co, tmp_co, center);
+ }
+ }
+
+ VECCOPY(vec, tmp_co);
+
+ if (type == MOD_CAST_TYPE_CYLINDER)
+ vec[2] = 0.0f;
+
+ if (has_radius) {
+ if (VecLength(vec) > cmd->radius) continue;
+ }
+
+ Normalize(vec);
+
+ if (flag & MOD_CAST_X)
+ tmp_co[0] = fac*vec[0]*len + facm*tmp_co[0];
+ if (flag & MOD_CAST_Y)
+ tmp_co[1] = fac*vec[1]*len + facm*tmp_co[1];
+ if (flag & MOD_CAST_Z)
+ tmp_co[2] = fac*vec[2]*len + facm*tmp_co[2];
+
+ if(ctrl_ob) {
+ if(flag & MOD_CAST_USE_OB_TRANSFORM) {
+ Mat4MulVecfl(imat, tmp_co);
+ } else {
+ VecAddf(tmp_co, tmp_co, center);
+ }
+ }
+
+ VECCOPY(vertexCos[i], tmp_co);
+ }
+}
+
+static void castModifier_cuboid_do(
+ CastModifierData *cmd, Object *ob, DerivedMesh *dm,
+ float (*vertexCos)[3], int numVerts)
+{
+ MDeformVert *dvert = NULL;
+ Object *ctrl_ob = NULL;
+
+ int i, defgrp_index = -1;
+ int has_radius = 0;
+ short flag;
+ float fac, facm;
+ float min[3], max[3], bb[8][3];
+ float center[3] = {0.0f, 0.0f, 0.0f};
+ float mat[4][4], imat[4][4];
+
+ fac = cmd->fac;
+ facm = 1.0f - fac;
+
+ flag = cmd->flag;
+
+ ctrl_ob = cmd->object;
+
+ /* now we check which options the user wants */
+
+ /* 1) (flag was checked in the "if (ctrl_ob)" block above) */
+ /* 2) cmd->radius > 0.0f: only the vertices within this radius from
+ * the center of the effect should be deformed */
+ if (cmd->radius > FLT_EPSILON) has_radius = 1;
+
+ /* 3) if we were given a vertex group name,
+ * only those vertices should be affected */
+ if (cmd->defgrp_name[0]) {
+ bDeformGroup *def;
+
+ for (i = 0, def = ob->defbase.first; def; def = def->next, i++) {
+ if (!strcmp(def->name, cmd->defgrp_name)) {
+ defgrp_index = i;
+ break;
+ }
+ }
+ }
+
+ if ((ob->type == OB_MESH) && dm && defgrp_index >= 0)
+ dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
+
+ if (ctrl_ob) {
+ if(flag & MOD_CAST_USE_OB_TRANSFORM) {
+ Mat4Invert(ctrl_ob->imat, ctrl_ob->obmat);
+ Mat4MulMat4(mat, ob->obmat, ctrl_ob->imat);
+ Mat4Invert(imat, mat);
+ }
+
+ Mat4Invert(ob->imat, ob->obmat);
+ VECCOPY(center, ctrl_ob->obmat[3]);
+ Mat4MulVecfl(ob->imat, center);
+ }
+
+ if((flag & MOD_CAST_SIZE_FROM_RADIUS) && has_radius) {
+ for(i = 0; i < 3; i++) {
+ min[i] = -cmd->radius;
+ max[i] = cmd->radius;
+ }
+ } else if(!(flag & MOD_CAST_SIZE_FROM_RADIUS) && cmd->size > 0) {
+ for(i = 0; i < 3; i++) {
+ min[i] = -cmd->size;
+ max[i] = cmd->size;
+ }
+ } else {
+ /* get bound box */
+ /* We can't use the object's bound box because other modifiers
+ * may have changed the vertex data. */
+ INIT_MINMAX(min, max);
+
+ /* Cast's center is the ob's own center in its local space,
+ * by default, but if the user defined a control object, we use
+ * its location, transformed to ob's local space. */
+ if (ctrl_ob) {
+ float vec[3];
+
+ /* let the center of the ctrl_ob be part of the bound box: */
+ DO_MINMAX(center, min, max);
+
+ for (i = 0; i < numVerts; i++) {
+ VecSubf(vec, vertexCos[i], center);
+ DO_MINMAX(vec, min, max);
+ }
+ }
+ else {
+ for (i = 0; i < numVerts; i++) {
+ DO_MINMAX(vertexCos[i], min, max);
+ }
+ }
+
+ /* we want a symmetric bound box around the origin */
+ if (fabs(min[0]) > fabs(max[0])) max[0] = fabs(min[0]);
+ if (fabs(min[1]) > fabs(max[1])) max[1] = fabs(min[1]);
+ if (fabs(min[2]) > fabs(max[2])) max[2] = fabs(min[2]);
+ min[0] = -max[0];
+ min[1] = -max[1];
+ min[2] = -max[2];
+ }
+
+ /* building our custom bounding box */
+ bb[0][0] = bb[2][0] = bb[4][0] = bb[6][0] = min[0];
+ bb[1][0] = bb[3][0] = bb[5][0] = bb[7][0] = max[0];
+ bb[0][1] = bb[1][1] = bb[4][1] = bb[5][1] = min[1];
+ bb[2][1] = bb[3][1] = bb[6][1] = bb[7][1] = max[1];
+ bb[0][2] = bb[1][2] = bb[2][2] = bb[3][2] = min[2];
+ bb[4][2] = bb[5][2] = bb[6][2] = bb[7][2] = max[2];
+
+ /* ready to apply the effect, one vertex at a time;
+ * tiny optimization: the code is separated (with parts repeated)
+ * in two possible cases:
+ * with or w/o a vgroup. With lots of if's in the code below,
+ * further optimizations are possible, if needed */
+ if (dvert) { /* with a vgroup */
+ float fac_orig = fac;
+ for (i = 0; i < numVerts; i++) {
+ MDeformWeight *dw = NULL;
+ int j, octant, coord;
+ float d[3], dmax, apex[3], fbb;
+ float tmp_co[3];
+
+ VECCOPY(tmp_co, vertexCos[i]);
+ if(ctrl_ob) {
+ if(flag & MOD_CAST_USE_OB_TRANSFORM) {
+ Mat4MulVecfl(mat, tmp_co);
+ } else {
+ VecSubf(tmp_co, tmp_co, center);
+ }
+ }
+
+ if (has_radius) {
+ if (fabs(tmp_co[0]) > cmd->radius ||
+ fabs(tmp_co[1]) > cmd->radius ||
+ fabs(tmp_co[2]) > cmd->radius) continue;
+ }
+
+ for (j = 0; j < dvert[i].totweight; ++j) {
+ if(dvert[i].dw[j].def_nr == defgrp_index) {
+ dw = &dvert[i].dw[j];
+ break;
+ }
+ }
+ if (!dw) continue;
+
+ fac = fac_orig * dw->weight;
+ facm = 1.0f - fac;
+
+ /* The algo used to project the vertices to their
+ * bounding box (bb) is pretty simple:
+ * for each vertex v:
+ * 1) find in which octant v is in;
+ * 2) find which outer "wall" of that octant is closer to v;
+ * 3) calculate factor (var fbb) to project v to that wall;
+ * 4) project. */
+
+ /* find in which octant this vertex is in */
+ octant = 0;
+ if (tmp_co[0] > 0.0f) octant += 1;
+ if (tmp_co[1] > 0.0f) octant += 2;
+ if (tmp_co[2] > 0.0f) octant += 4;
+
+ /* apex is the bb's vertex at the chosen octant */
+ VecCopyf(apex, bb[octant]);
+
+ /* find which bb plane is closest to this vertex ... */
+ d[0] = tmp_co[0] / apex[0];
+ d[1] = tmp_co[1] / apex[1];
+ d[2] = tmp_co[2] / apex[2];
+
+ /* ... (the closest has the higher (closer to 1) d value) */
+ dmax = d[0];
+ coord = 0;
+ if (d[1] > dmax) {
+ dmax = d[1];
+ coord = 1;
+ }
+ if (d[2] > dmax) {
+ /* dmax = d[2]; */ /* commented, we don't need it */
+ coord = 2;
+ }
+
+ /* ok, now we know which coordinate of the vertex to use */
+
+ if (fabs(tmp_co[coord]) < FLT_EPSILON) /* avoid division by zero */
+ continue;
+
+ /* finally, this is the factor we wanted, to project the vertex
+ * to its bounding box (bb) */
+ fbb = apex[coord] / tmp_co[coord];
+
+ /* calculate the new vertex position */
+ if (flag & MOD_CAST_X)
+ tmp_co[0] = facm * tmp_co[0] + fac * tmp_co[0] * fbb;
+ if (flag & MOD_CAST_Y)
+ tmp_co[1] = facm * tmp_co[1] + fac * tmp_co[1] * fbb;
+ if (flag & MOD_CAST_Z)
+ tmp_co[2] = facm * tmp_co[2] + fac * tmp_co[2] * fbb;
+
+ if(ctrl_ob) {
+ if(flag & MOD_CAST_USE_OB_TRANSFORM) {
+ Mat4MulVecfl(imat, tmp_co);
+ } else {
+ VecAddf(tmp_co, tmp_co, center);
+ }
+ }
+
+ VECCOPY(vertexCos[i], tmp_co);
+ }
+ return;
+ }
+
+ /* no vgroup (check previous case for comments about the code) */
+ for (i = 0; i < numVerts; i++) {
+ int octant, coord;
+ float d[3], dmax, fbb, apex[3];
+ float tmp_co[3];
+
+ VECCOPY(tmp_co, vertexCos[i]);
+ if(ctrl_ob) {
+ if(flag & MOD_CAST_USE_OB_TRANSFORM) {
+ Mat4MulVecfl(mat, tmp_co);
+ } else {
+ VecSubf(tmp_co, tmp_co, center);
+ }
+ }
+
+ if (has_radius) {
+ if (fabs(tmp_co[0]) > cmd->radius ||
+ fabs(tmp_co[1]) > cmd->radius ||
+ fabs(tmp_co[2]) > cmd->radius) continue;
+ }
+
+ octant = 0;
+ if (tmp_co[0] > 0.0f) octant += 1;
+ if (tmp_co[1] > 0.0f) octant += 2;
+ if (tmp_co[2] > 0.0f) octant += 4;
+
+ VecCopyf(apex, bb[octant]);
+
+ d[0] = tmp_co[0] / apex[0];
+ d[1] = tmp_co[1] / apex[1];
+ d[2] = tmp_co[2] / apex[2];
+
+ dmax = d[0];
+ coord = 0;
+ if (d[1] > dmax) {
+ dmax = d[1];
+ coord = 1;
+ }
+ if (d[2] > dmax) {
+ /* dmax = d[2]; */ /* commented, we don't need it */
+ coord = 2;
+ }
+
+ if (fabs(tmp_co[coord]) < FLT_EPSILON)
+ continue;
+
+ fbb = apex[coord] / tmp_co[coord];
+
+ if (flag & MOD_CAST_X)
+ tmp_co[0] = facm * tmp_co[0] + fac * tmp_co[0] * fbb;
+ if (flag & MOD_CAST_Y)
+ tmp_co[1] = facm * tmp_co[1] + fac * tmp_co[1] * fbb;
+ if (flag & MOD_CAST_Z)
+ tmp_co[2] = facm * tmp_co[2] + fac * tmp_co[2] * fbb;
+
+ if(ctrl_ob) {
+ if(flag & MOD_CAST_USE_OB_TRANSFORM) {
+ Mat4MulVecfl(imat, tmp_co);
+ } else {
+ VecAddf(tmp_co, tmp_co, center);
+ }
+ }
+
+ VECCOPY(vertexCos[i], tmp_co);
+ }
+}
+
+static void castModifier_deformVerts(
+ ModifierData *md, Object *ob, DerivedMesh *derivedData,
+ float (*vertexCos)[3], int numVerts)
+{
+ DerivedMesh *dm = derivedData;
+ CastModifierData *cmd = (CastModifierData *)md;
+
+ if (!dm && ob->type == OB_MESH)
+ dm = CDDM_from_mesh(ob->data, ob);
+
+ if (cmd->type == MOD_CAST_TYPE_CUBOID) {
+ castModifier_cuboid_do(cmd, ob, dm, vertexCos, numVerts);
+ } else { /* MOD_CAST_TYPE_SPHERE or MOD_CAST_TYPE_CYLINDER */
+ castModifier_sphere_do(cmd, ob, dm, vertexCos, numVerts);
+ }
+
+ if (!derivedData && dm) dm->release(dm);
+}
+
+static void castModifier_deformVertsEM(
+ ModifierData *md, Object *ob, EditMesh *editData,
+ DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
+{
+ DerivedMesh *dm = derivedData;
+ CastModifierData *cmd = (CastModifierData *)md;
+
+ if (!dm && ob->type == OB_MESH)
+ dm = CDDM_from_editmesh(editData, ob->data);
+
+ if (cmd->type == MOD_CAST_TYPE_CUBOID) {
+ castModifier_cuboid_do(cmd, ob, dm, vertexCos, numVerts);
+ } else { /* MOD_CAST_TYPE_SPHERE or MOD_CAST_TYPE_CYLINDER */
+ castModifier_sphere_do(cmd, ob, dm, vertexCos, numVerts);
+ }
+
+ if (!derivedData && dm) dm->release(dm);
+}
+
+/* Wave */
+
+static void waveModifier_initData(ModifierData *md)
+{
+ WaveModifierData *wmd = (WaveModifierData*) md; // whadya know, moved here from Iraq
+
+ wmd->flag |= (MOD_WAVE_X | MOD_WAVE_Y | MOD_WAVE_CYCL
+ | MOD_WAVE_NORM_X | MOD_WAVE_NORM_Y | MOD_WAVE_NORM_Z);
+
+ wmd->objectcenter = NULL;
+ wmd->texture = NULL;
+ wmd->map_object = NULL;
+ wmd->height= 0.5f;
+ wmd->width= 1.5f;
+ wmd->speed= 0.5f;
+ wmd->narrow= 1.5f;
+ wmd->lifetime= 0.0f;
+ wmd->damp= 10.0f;
+ wmd->texmapping = MOD_WAV_MAP_LOCAL;
+ wmd->defgrp_name[0] = 0;
+}
+
+static void waveModifier_copyData(ModifierData *md, ModifierData *target)
+{
+ WaveModifierData *wmd = (WaveModifierData*) md;
+ WaveModifierData *twmd = (WaveModifierData*) target;
+
+ twmd->damp = wmd->damp;
+ twmd->flag = wmd->flag;
+ twmd->height = wmd->height;
+ twmd->lifetime = wmd->lifetime;
+ twmd->narrow = wmd->narrow;
+ twmd->speed = wmd->speed;
+ twmd->startx = wmd->startx;
+ twmd->starty = wmd->starty;
+ twmd->timeoffs = wmd->timeoffs;
+ twmd->width = wmd->width;
+ twmd->objectcenter = wmd->objectcenter;
+ twmd->texture = wmd->texture;
+ twmd->map_object = wmd->map_object;
+ twmd->texmapping = wmd->texmapping;
+ strncpy(twmd->defgrp_name, wmd->defgrp_name, 32);
+}
+
+static int waveModifier_dependsOnTime(ModifierData *md)
+{
+ return 1;
+}
+
+static void waveModifier_foreachObjectLink(
+ ModifierData *md, Object *ob,
+ ObjectWalkFunc walk, void *userData)
+{
+ WaveModifierData *wmd = (WaveModifierData*) md;
+
+ walk(userData, ob, &wmd->objectcenter);
+ walk(userData, ob, &wmd->map_object);
+}
+
+static void waveModifier_foreachIDLink(ModifierData *md, Object *ob,
+ IDWalkFunc walk, void *userData)
+{
+ WaveModifierData *wmd = (WaveModifierData*) md;
+
+ walk(userData, ob, (ID **)&wmd->texture);
+
+ waveModifier_foreachObjectLink(md, ob, (ObjectWalkFunc)walk, userData);
+}
+
+static void waveModifier_updateDepgraph(
+ ModifierData *md, DagForest *forest, Object *ob,
+ DagNode *obNode)
+{
+ WaveModifierData *wmd = (WaveModifierData*) md;
+
+ if(wmd->objectcenter) {
+ DagNode *curNode = dag_get_node(forest, wmd->objectcenter);
+
+ dag_add_relation(forest, curNode, obNode, DAG_RL_OB_DATA);
+ }
+
+ if(wmd->map_object) {
+ DagNode *curNode = dag_get_node(forest, wmd->map_object);
+
+ dag_add_relation(forest, curNode, obNode, DAG_RL_OB_DATA);
+ }
+}
+
+CustomDataMask waveModifier_requiredDataMask(ModifierData *md)
+{
+ WaveModifierData *wmd = (WaveModifierData *)md;
+ CustomDataMask dataMask = 0;
+
+
+ /* ask for UV coordinates if we need them */
+ if(wmd->texture && wmd->texmapping == MOD_WAV_MAP_UV)
+ dataMask |= (1 << CD_MTFACE);
+
+ /* ask for vertexgroups if we need them */
+ if(wmd->defgrp_name[0])
+ dataMask |= (1 << CD_MDEFORMVERT);
+
+ return dataMask;
+}
+
+static void wavemod_get_texture_coords(WaveModifierData *wmd, Object *ob,
+ DerivedMesh *dm,
+ float (*co)[3], float (*texco)[3],
+ int numVerts)
+{
+ int i;
+ int texmapping = wmd->texmapping;
+
+ if(texmapping == MOD_WAV_MAP_OBJECT) {
+ if(wmd->map_object)
+ Mat4Invert(wmd->map_object->imat, wmd->map_object->obmat);
+ else /* if there is no map object, default to local */
+ texmapping = MOD_WAV_MAP_LOCAL;
+ }
+
+ /* UVs need special handling, since they come from faces */
+ if(texmapping == MOD_WAV_MAP_UV) {
+ if(dm->getFaceDataArray(dm, CD_MTFACE)) {
+ MFace *mface = dm->getFaceArray(dm);
+ MFace *mf;
+ char *done = MEM_callocN(sizeof(*done) * numVerts,
+ "get_texture_coords done");
+ int numFaces = dm->getNumFaces(dm);
+ MTFace *tf;
+
+ validate_layer_name(&dm->faceData, CD_MTFACE, wmd->uvlayer_name);
+
+ tf = CustomData_get_layer_named(&dm->faceData, CD_MTFACE,
+ wmd->uvlayer_name);
+
+ /* verts are given the UV from the first face that uses them */
+ for(i = 0, mf = mface; i < numFaces; ++i, ++mf, ++tf) {
+ if(!done[mf->v1]) {
+ texco[mf->v1][0] = tf->uv[0][0];
+ texco[mf->v1][1] = tf->uv[0][1];
+ texco[mf->v1][2] = 0;
+ done[mf->v1] = 1;
+ }
+ if(!done[mf->v2]) {
+ texco[mf->v2][0] = tf->uv[1][0];
+ texco[mf->v2][1] = tf->uv[1][1];
+ texco[mf->v2][2] = 0;
+ done[mf->v2] = 1;
+ }
+ if(!done[mf->v3]) {
+ texco[mf->v3][0] = tf->uv[2][0];
+ texco[mf->v3][1] = tf->uv[2][1];
+ texco[mf->v3][2] = 0;
+ done[mf->v3] = 1;
+ }
+ if(!done[mf->v4]) {
+ texco[mf->v4][0] = tf->uv[3][0];
+ texco[mf->v4][1] = tf->uv[3][1];
+ texco[mf->v4][2] = 0;
+ done[mf->v4] = 1;
+ }
+ }
+
+ /* remap UVs from [0, 1] to [-1, 1] */
+ for(i = 0; i < numVerts; ++i) {
+ texco[i][0] = texco[i][0] * 2 - 1;
+ texco[i][1] = texco[i][1] * 2 - 1;
+ }
+
+ MEM_freeN(done);
+ return;
+ } else /* if there are no UVs, default to local */
+ texmapping = MOD_WAV_MAP_LOCAL;
+ }
+
+ for(i = 0; i < numVerts; ++i, ++co, ++texco) {
+ switch(texmapping) {
+ case MOD_WAV_MAP_LOCAL:
+ VECCOPY(*texco, *co);
+ break;
+ case MOD_WAV_MAP_GLOBAL:
+ VECCOPY(*texco, *co);
+ Mat4MulVecfl(ob->obmat, *texco);
+ break;
+ case MOD_WAV_MAP_OBJECT:
+ VECCOPY(*texco, *co);
+ Mat4MulVecfl(ob->obmat, *texco);
+ Mat4MulVecfl(wmd->map_object->imat, *texco);
+ break;
+ }
+ }
+}
+
+static void waveModifier_do(
+ WaveModifierData *md, Object *ob, DerivedMesh *dm,
+ float (*vertexCos)[3], int numVerts)
+{
+ WaveModifierData *wmd = (WaveModifierData*) md;
+ MVert *mvert = NULL;
+ MDeformVert *dvert = NULL;
+ int defgrp_index;
+ float ctime = bsystem_time(ob, (float)G.scene->r.cfra, 0.0);
+ float minfac =
+ (float)(1.0 / exp(wmd->width * wmd->narrow * wmd->width * wmd->narrow));
+ float lifefac = wmd->height;
+ float (*tex_co)[3] = NULL;
+
+ if(wmd->flag & MOD_WAVE_NORM && ob->type == OB_MESH)
+ mvert = dm->getVertArray(dm);
+
+ if(wmd->objectcenter){
+ float mat[4][4];
+ /* get the control object's location in local coordinates */
+ Mat4Invert(ob->imat, ob->obmat);
+ Mat4MulMat4(mat, wmd->objectcenter->obmat, ob->imat);
+
+ wmd->startx = mat[3][0];
+ wmd->starty = mat[3][1];
+ }
+
+ /* get the index of the deform group */
+ defgrp_index = -1;
+
+ if(wmd->defgrp_name[0]) {
+ int i;
+ bDeformGroup *def;
+ for(i = 0, def = ob->defbase.first; def; def = def->next, i++) {
+ if(!strcmp(def->name, wmd->defgrp_name)) {
+ defgrp_index = i;
+ break;
+ }
+ }
+ }
+
+ if(defgrp_index >= 0){
+ dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
+ }
+
+ if(wmd->damp == 0) wmd->damp = 10.0f;
+
+ if(wmd->lifetime != 0.0) {
+ float x = ctime - wmd->timeoffs;
+
+ if(x > wmd->lifetime) {
+ lifefac = x - wmd->lifetime;
+
+ if(lifefac > wmd->damp) lifefac = 0.0;
+ else lifefac =
+ (float)(wmd->height * (1.0 - sqrt(lifefac / wmd->damp)));
+ }
+ }
+
+ if(wmd->texture) {
+ tex_co = MEM_mallocN(sizeof(*tex_co) * numVerts,
+ "waveModifier_do tex_co");
+ wavemod_get_texture_coords(wmd, ob, dm, vertexCos, tex_co, numVerts);
+ }
+
+ if(lifefac != 0.0) {
+ int i;
+
+ for(i = 0; i < numVerts; i++) {
+ float *co = vertexCos[i];
+ float x = co[0] - wmd->startx;
+ float y = co[1] - wmd->starty;
+ float amplit= 0.0f;
+ TexResult texres;
+ MDeformWeight *def_weight = NULL;
+
+ /* get weights */
+ if(dvert) {
+ int j;
+ for(j = 0; j < dvert[i].totweight; ++j) {
+ if(dvert[i].dw[j].def_nr == defgrp_index) {
+ def_weight = &dvert[i].dw[j];
+ break;
+ }
+ }
+
+ /* if this vert isn't in the vgroup, don't deform it */
+ if(!def_weight) continue;
+ }
+
+ if(wmd->texture) {
+ texres.nor = NULL;
+ get_texture_value(wmd->texture, tex_co[i], &texres);
+ }
+
+
+ if(wmd->flag & MOD_WAVE_X) {
+ if(wmd->flag & MOD_WAVE_Y) amplit = (float)sqrt(x*x + y*y);
+ else amplit = x;
+ }
+ else if(wmd->flag & MOD_WAVE_Y)
+ amplit= y;
+
+ /* this way it makes nice circles */
+ amplit -= (ctime - wmd->timeoffs) * wmd->speed;
+
+ if(wmd->flag & MOD_WAVE_CYCL) {
+ amplit = (float)fmod(amplit - wmd->width, 2.0 * wmd->width)
+ + wmd->width;
+ }
+
+ /* GAUSSIAN */
+ if(amplit > -wmd->width && amplit < wmd->width) {
+ amplit = amplit * wmd->narrow;
+ amplit = (float)(1.0 / exp(amplit * amplit) - minfac);
+ if(wmd->texture)
+ amplit = amplit * texres.tin;
+
+ if(def_weight)
+ amplit = amplit * def_weight->weight;
+
+ if(mvert) {
+ /* move along normals */
+ if(wmd->flag & MOD_WAVE_NORM_X) {
+ co[0] += (lifefac * amplit) * mvert[i].no[0] / 32767.0f;
+ }
+ if(wmd->flag & MOD_WAVE_NORM_Y) {
+ co[1] += (lifefac * amplit) * mvert[i].no[1] / 32767.0f;
+ }
+ if(wmd->flag & MOD_WAVE_NORM_Z) {
+ co[2] += (lifefac * amplit) * mvert[i].no[2] / 32767.0f;
+ }
+ }
+ else {
+ /* move along local z axis */
+ co[2] += lifefac * amplit;
+ }
+ }
+ }
+ }
+
+ if(wmd->texture) MEM_freeN(tex_co);
+}
+
+static void waveModifier_deformVerts(
+ ModifierData *md, Object *ob, DerivedMesh *derivedData,
+ float (*vertexCos)[3], int numVerts)
+{
+ DerivedMesh *dm;
+ WaveModifierData *wmd = (WaveModifierData *)md;
+
+ if(!wmd->texture && !wmd->defgrp_name[0] && !(wmd->flag & MOD_WAVE_NORM))
+ dm = derivedData;
+ else if(derivedData) dm = derivedData;
+ else if(ob->type == OB_MESH) dm = CDDM_from_mesh(ob->data, ob);
+ else return;
+
+ if(wmd->flag & MOD_WAVE_NORM) {
+ CDDM_apply_vert_coords(dm, vertexCos);
+ CDDM_calc_normals(dm);
+ }
+
+ waveModifier_do(wmd, ob, dm, vertexCos, numVerts);
+
+ if(dm != derivedData) dm->release(dm);
+}
+
+static void waveModifier_deformVertsEM(
+ ModifierData *md, Object *ob, EditMesh *editData,
+ DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
+{
+ DerivedMesh *dm;
+ WaveModifierData *wmd = (WaveModifierData *)md;
+
+ if(!wmd->texture && !wmd->defgrp_name[0] && !(wmd->flag & MOD_WAVE_NORM))
+ dm = derivedData;
+ else if(derivedData) dm = derivedData;
+ else dm = CDDM_from_editmesh(editData, ob->data);
+
+ if(wmd->flag & MOD_WAVE_NORM) {
+ CDDM_apply_vert_coords(dm, vertexCos);
+ CDDM_calc_normals(dm);
+ }
+
+ waveModifier_do(wmd, ob, dm, vertexCos, numVerts);
+
+ if(dm != derivedData) dm->release(dm);
+}
+
+/* Armature */
+
+static void armatureModifier_initData(ModifierData *md)
+{
+ ArmatureModifierData *amd = (ArmatureModifierData*) md;
+
+ amd->deformflag = ARM_DEF_ENVELOPE | ARM_DEF_VGROUP;
+}
+
+static void armatureModifier_copyData(ModifierData *md, ModifierData *target)
+{
+ ArmatureModifierData *amd = (ArmatureModifierData*) md;
+ ArmatureModifierData *tamd = (ArmatureModifierData*) target;
+
+ tamd->object = amd->object;
+ tamd->deformflag = amd->deformflag;
+ strncpy(tamd->defgrp_name, amd->defgrp_name, 32);
+}
+
+CustomDataMask armatureModifier_requiredDataMask(ModifierData *md)
+{
+ CustomDataMask dataMask = 0;
+
+ /* ask for vertexgroups */
+ dataMask |= (1 << CD_MDEFORMVERT);
+
+ return dataMask;
+}
+
+static int armatureModifier_isDisabled(ModifierData *md)
+{
+ ArmatureModifierData *amd = (ArmatureModifierData*) md;
+
+ return !amd->object;
+}
+
+static void armatureModifier_foreachObjectLink(
+ ModifierData *md, Object *ob,
+ void (*walk)(void *userData, Object *ob, Object **obpoin),
+ void *userData)
+{
+ ArmatureModifierData *amd = (ArmatureModifierData*) md;
+
+ walk(userData, ob, &amd->object);
+}
+
+static void armatureModifier_updateDepgraph(
+ ModifierData *md, DagForest *forest, Object *ob,
+ DagNode *obNode)
+{
+ ArmatureModifierData *amd = (ArmatureModifierData*) md;
+
+ if (amd->object) {
+ DagNode *curNode = dag_get_node(forest, amd->object);
+
+ dag_add_relation(forest, curNode, obNode,
+ DAG_RL_DATA_DATA | DAG_RL_OB_DATA);
+ }
+}
+
+static void armatureModifier_deformVerts(
+ ModifierData *md, Object *ob, DerivedMesh *derivedData,
+ float (*vertexCos)[3], int numVerts)
+{
+ ArmatureModifierData *amd = (ArmatureModifierData*) md;
+
+ armature_deform_verts(amd->object, ob, derivedData, vertexCos, NULL,
+ numVerts, amd->deformflag, amd->defgrp_name);
+}
+
+static void armatureModifier_deformVertsEM(
+ ModifierData *md, Object *ob, EditMesh *editData,
+ DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
+{
+ ArmatureModifierData *amd = (ArmatureModifierData*) md;
+ DerivedMesh *dm = derivedData;
+
+ if(!derivedData) dm = CDDM_from_editmesh(editData, ob->data);
+
+ armature_deform_verts(amd->object, ob, dm, vertexCos, NULL, numVerts,
+ amd->deformflag, amd->defgrp_name);
+
+ if(!derivedData) dm->release(dm);
+}
+
+static void armatureModifier_deformMatricesEM(
+ ModifierData *md, Object *ob, EditMesh *editData,
+ DerivedMesh *derivedData, float (*vertexCos)[3],
+ float (*defMats)[3][3], int numVerts)
+{
+ ArmatureModifierData *amd = (ArmatureModifierData*) md;
+ DerivedMesh *dm = derivedData;
+
+ if(!derivedData) dm = CDDM_from_editmesh(editData, ob->data);
+
+ armature_deform_verts(amd->object, ob, dm, vertexCos, defMats, numVerts,
+ amd->deformflag, amd->defgrp_name);
+
+ if(!derivedData) dm->release(dm);
+}
+
+/* Hook */
+
+static void hookModifier_initData(ModifierData *md)
+{
+ HookModifierData *hmd = (HookModifierData*) md;
+
+ hmd->force= 1.0;
+}
+
+static void hookModifier_copyData(ModifierData *md, ModifierData *target)
+{
+ HookModifierData *hmd = (HookModifierData*) md;
+ HookModifierData *thmd = (HookModifierData*) target;
+
+ VECCOPY(thmd->cent, hmd->cent);
+ thmd->falloff = hmd->falloff;
+ thmd->force = hmd->force;
+ thmd->object = hmd->object;
+ thmd->totindex = hmd->totindex;
+ thmd->indexar = MEM_dupallocN(hmd->indexar);
+ memcpy(thmd->parentinv, hmd->parentinv, sizeof(hmd->parentinv));
+ strncpy(thmd->name, hmd->name, 32);
+}
+
+CustomDataMask hookModifier_requiredDataMask(ModifierData *md)
+{
+ HookModifierData *hmd = (HookModifierData *)md;
+ CustomDataMask dataMask = 0;
+
+ /* ask for vertexgroups if we need them */
+ if(!hmd->indexar && hmd->name[0]) dataMask |= (1 << CD_MDEFORMVERT);
+
+ return dataMask;
+}
+
+static void hookModifier_freeData(ModifierData *md)
+{
+ HookModifierData *hmd = (HookModifierData*) md;
+
+ if (hmd->indexar) MEM_freeN(hmd->indexar);
+}
+
+static int hookModifier_isDisabled(ModifierData *md)
+{
+ HookModifierData *hmd = (HookModifierData*) md;
+
+ return !hmd->object;
+}
+
+static void hookModifier_foreachObjectLink(
+ ModifierData *md, Object *ob,
+ void (*walk)(void *userData, Object *ob, Object **obpoin),
+ void *userData)
+{
+ HookModifierData *hmd = (HookModifierData*) md;
+
+ walk(userData, ob, &hmd->object);
+}
+
+static void hookModifier_updateDepgraph(ModifierData *md, DagForest *forest,
+ Object *ob, DagNode *obNode)
+{
+ HookModifierData *hmd = (HookModifierData*) md;
+
+ if (hmd->object) {
+ DagNode *curNode = dag_get_node(forest, hmd->object);
+
+ dag_add_relation(forest, curNode, obNode, DAG_RL_OB_DATA);
+ }
+}
+
+static void hookModifier_deformVerts(
+ ModifierData *md, Object *ob, DerivedMesh *derivedData,
+ float (*vertexCos)[3], int numVerts)
+{
+ HookModifierData *hmd = (HookModifierData*) md;
+ float vec[3], mat[4][4];
+ int i;
+ DerivedMesh *dm = derivedData;
+
+ Mat4Invert(ob->imat, ob->obmat);
+ Mat4MulSerie(mat, ob->imat, hmd->object->obmat, hmd->parentinv,
+ NULL, NULL, NULL, NULL, NULL);
+
+ /* vertex indices? */
+ if(hmd->indexar) {
+ for(i = 0; i < hmd->totindex; i++) {
+ int index = hmd->indexar[i];
+
+ /* This should always be true and I don't generally like
+ * "paranoid" style code like this, but old files can have
+ * indices that are out of range because old blender did
+ * not correct them on exit editmode. - zr
+ */
+ if(index < numVerts) {
+ float *co = vertexCos[index];
+ float fac = hmd->force;
+
+ /* if DerivedMesh is present and has original index data,
+ * use it
+ */
+ if(dm && dm->getVertData(dm, 0, CD_ORIGINDEX)) {
+ int j;
+ int orig_index;
+ for(j = 0; j < numVerts; ++j) {
+ fac = hmd->force;
+ orig_index = *(int *)dm->getVertData(dm, j,
+ CD_ORIGINDEX);
+ if(orig_index == index) {
+ co = vertexCos[j];
+ if(hmd->falloff != 0.0) {
+ float len = VecLenf(co, hmd->cent);
+ if(len > hmd->falloff) fac = 0.0;
+ else if(len > 0.0)
+ fac *= sqrt(1.0 - len / hmd->falloff);
+ }
+
+ if(fac != 0.0) {
+ VecMat4MulVecfl(vec, mat, co);
+ VecLerpf(co, co, vec, fac);
+ }
+ }
+ }
+ } else {
+ if(hmd->falloff != 0.0) {
+ float len = VecLenf(co, hmd->cent);
+ if(len > hmd->falloff) fac = 0.0;
+ else if(len > 0.0)
+ fac *= sqrt(1.0 - len / hmd->falloff);
+ }
+
+ if(fac != 0.0) {
+ VecMat4MulVecfl(vec, mat, co);
+ VecLerpf(co, co, vec, fac);
+ }
+ }
+ }
+ }
+ } else { /* vertex group hook */
+ bDeformGroup *curdef;
+ Mesh *me = ob->data;
+ int index = 0;
+ int use_dverts;
+ int maxVerts = 0;
+
+ /* find the group (weak loop-in-loop) */
+ for(curdef = ob->defbase.first; curdef; curdef = curdef->next, index++)
+ if(!strcmp(curdef->name, hmd->name)) break;
+
+ if(dm)
+ if(dm->getVertData(dm, 0, CD_MDEFORMVERT)) {
+ use_dverts = 1;
+ maxVerts = dm->getNumVerts(dm);
+ } else use_dverts = 0;
+ else if(me->dvert) {
+ use_dverts = 1;
+ maxVerts = me->totvert;
+ } else use_dverts = 0;
+
+ if(curdef && use_dverts) {
+ MDeformVert *dvert = me->dvert;
+ int i, j;
+
+ for(i = 0; i < maxVerts; i++, dvert++) {
+ if(dm) dvert = dm->getVertData(dm, i, CD_MDEFORMVERT);
+ for(j = 0; j < dvert->totweight; j++) {
+ if(dvert->dw[j].def_nr == index) {
+ float fac = hmd->force*dvert->dw[j].weight;
+ float *co = vertexCos[i];
+
+ if(hmd->falloff != 0.0) {
+ float len = VecLenf(co, hmd->cent);
+ if(len > hmd->falloff) fac = 0.0;
+ else if(len > 0.0)
+ fac *= sqrt(1.0 - len / hmd->falloff);
+ }
+
+ VecMat4MulVecfl(vec, mat, co);
+ VecLerpf(co, co, vec, fac);
+ }
+ }
+ }
+ }
+ }
+}
+
+static void hookModifier_deformVertsEM(
+ ModifierData *md, Object *ob, EditMesh *editData,
+ DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
+{
+ DerivedMesh *dm = derivedData;
+
+ if(!derivedData) dm = CDDM_from_editmesh(editData, ob->data);
+
+ hookModifier_deformVerts(md, ob, derivedData, vertexCos, numVerts);
+
+ if(!derivedData) dm->release(dm);
+}
+
+/* Softbody */
+
+static void softbodyModifier_deformVerts(
+ ModifierData *md, Object *ob, DerivedMesh *derivedData,
+ float (*vertexCos)[3], int numVerts)
+{
+ sbObjectStep(ob, (float)G.scene->r.cfra, vertexCos, numVerts);
+}
+
+/* Boolean */
+
+static void booleanModifier_copyData(ModifierData *md, ModifierData *target)
+{
+ BooleanModifierData *bmd = (BooleanModifierData*) md;
+ BooleanModifierData *tbmd = (BooleanModifierData*) target;
+
+ tbmd->object = bmd->object;
+ tbmd->operation = bmd->operation;
+}
+
+static int booleanModifier_isDisabled(ModifierData *md)
+{
+ BooleanModifierData *bmd = (BooleanModifierData*) md;
+
+ return !bmd->object;
+}
+
+static void booleanModifier_foreachObjectLink(
+ ModifierData *md, Object *ob,
+ void (*walk)(void *userData, Object *ob, Object **obpoin),
+ void *userData)
+{
+ BooleanModifierData *bmd = (BooleanModifierData*) md;
+
+ walk(userData, ob, &bmd->object);
+}
+
+static void booleanModifier_updateDepgraph(
+ ModifierData *md, DagForest *forest, Object *ob,
+ DagNode *obNode)
+{
+ BooleanModifierData *bmd = (BooleanModifierData*) md;
+
+ if(bmd->object) {
+ DagNode *curNode = dag_get_node(forest, bmd->object);
+
+ dag_add_relation(forest, curNode, obNode,
+ DAG_RL_DATA_DATA | DAG_RL_OB_DATA);
+ }
+}
+
+static DerivedMesh *booleanModifier_applyModifier(
+ ModifierData *md, Object *ob, DerivedMesh *derivedData,
+ int useRenderParams, int isFinalCalc)
+{
+ // XXX doesn't handle derived data
+ BooleanModifierData *bmd = (BooleanModifierData*) md;
+
+ /* we do a quick sanity check */
+ if(((Mesh *)ob->data)->totface > 3
+ && bmd->object && ((Mesh *)bmd->object->data)->totface > 3) {
+ DerivedMesh *result = NewBooleanDerivedMesh(bmd->object, ob,
+ 1 + bmd->operation);
+
+ /* if new mesh returned, return it; otherwise there was
+ * an error, so delete the modifier object */
+ if(result)
+ return result;
+ else
+ bmd->object = NULL;
+ }
+
+ return derivedData;
+}
+
+/* MeshDeform */
+
+static void meshdeformModifier_initData(ModifierData *md)
+{
+ MeshDeformModifierData *mmd = (MeshDeformModifierData*) md;
+
+ mmd->gridsize= 5;
+}
+
+static void meshdeformModifier_freeData(ModifierData *md)
+{
+ MeshDeformModifierData *mmd = (MeshDeformModifierData*) md;
+
+ if (mmd->bindweights) MEM_freeN(mmd->bindweights);
+ if (mmd->bindcos) MEM_freeN(mmd->bindcos);
+}
+
+static void meshdeformModifier_copyData(ModifierData *md, ModifierData *target)
+{
+ MeshDeformModifierData *mmd = (MeshDeformModifierData*) md;
+ MeshDeformModifierData *tmmd = (MeshDeformModifierData*) target;
+
+ tmmd->gridsize = mmd->gridsize;
+ tmmd->object = mmd->object;
+}
+
+CustomDataMask meshdeformModifier_requiredDataMask(ModifierData *md)
+{
+ MeshDeformModifierData *mmd = (MeshDeformModifierData *)md;
+ CustomDataMask dataMask = 0;
+
+ /* ask for vertexgroups if we need them */
+ if(mmd->defgrp_name[0]) dataMask |= (1 << CD_MDEFORMVERT);
+
+ return dataMask;
+}
+
+static int meshdeformModifier_isDisabled(ModifierData *md)
+{
+ MeshDeformModifierData *mmd = (MeshDeformModifierData*) md;
+
+ return !mmd->object;
+}
+
+static void meshdeformModifier_foreachObjectLink(
+ ModifierData *md, Object *ob,
+ void (*walk)(void *userData, Object *ob, Object **obpoin),
+ void *userData)
+{
+ MeshDeformModifierData *mmd = (MeshDeformModifierData*) md;
+
+ walk(userData, ob, &mmd->object);
+}
+
+static void meshdeformModifier_updateDepgraph(
+ ModifierData *md, DagForest *forest, Object *ob,
+ DagNode *obNode)
+{
+ MeshDeformModifierData *mmd = (MeshDeformModifierData*) md;
+
+ if (mmd->object) {
+ DagNode *curNode = dag_get_node(forest, mmd->object);
+
+ dag_add_relation(forest, curNode, obNode,
+ DAG_RL_DATA_DATA|DAG_RL_OB_DATA|DAG_RL_DATA_OB|DAG_RL_OB_OB);
+ }
+}
+
+static void meshdeformModifier_do(
+ ModifierData *md, Object *ob, DerivedMesh *dm,
+ float (*vertexCos)[3], int numVerts)
+{
+ MeshDeformModifierData *mmd = (MeshDeformModifierData*) md;
+ float imat[4][4], cagemat[4][4], icagemat[4][4], icmat[3][3];
+ float weight, totweight, fac, co[3], *weights, (*dco)[3], (*bindcos)[3];
+ int a, b, totvert, totcagevert, defgrp_index;
+ DerivedMesh *tmpdm, *cagedm;
+ MDeformVert *dvert = NULL;
+ MDeformWeight *dw;
+ MVert *cagemvert;
+
+ if(!mmd->object || (!mmd->bindweights && !mmd->needbind))
+ return;
+
+ /* get cage derivedmesh */
+ if(mmd->object == G.obedit) {
+ tmpdm= editmesh_get_derived_cage_and_final(&cagedm, 0);
+ if(tmpdm)
+ tmpdm->release(tmpdm);
+ }
+ else
+ cagedm= mesh_get_derived_final(mmd->object, CD_MASK_BAREMESH);
+
+ /* TODO: this could give inifinite loop for circular dependency */
+ if(!cagedm)
+ return;
+
+ /* compute matrices to go in and out of cage object space */
+ Mat4Invert(imat, mmd->object->obmat);
+ Mat4MulMat4(cagemat, ob->obmat, imat);
+ Mat4Invert(icagemat, cagemat);
+ Mat3CpyMat4(icmat, icagemat);
+
+ /* bind weights if needed */
+ if(!mmd->bindweights)
+ harmonic_coordinates_bind(mmd, vertexCos, numVerts, cagemat);
+
+ /* verify we have compatible weights */
+ totvert= numVerts;
+ totcagevert= cagedm->getNumVerts(cagedm);
+
+ if(mmd->totvert!=totvert || mmd->totcagevert!=totcagevert || !mmd->bindweights) {
+ cagedm->release(cagedm);
+ return;
+ }
+
+ /* setup deformation data */
+ cagemvert= cagedm->getVertArray(cagedm);
+ weights= mmd->bindweights;
+ bindcos= (float(*)[3])mmd->bindcos;
+
+ dco= MEM_callocN(sizeof(*dco)*totcagevert, "MDefDco");
+ for(a=0; a<totcagevert; a++) {
+ VECCOPY(co, cagemvert[a].co);
+ Mat4MulVecfl(mmd->object->obmat, co);
+ VECSUB(dco[a], co, bindcos[a]);
+ }
+
+ defgrp_index = -1;
+
+ if(mmd->defgrp_name[0]) {
+ bDeformGroup *def;
+
+ for(a=0, def=ob->defbase.first; def; def=def->next, a++) {
+ if(!strcmp(def->name, mmd->defgrp_name)) {
+ defgrp_index= a;
+ break;
+ }
+ }
+
+ if (defgrp_index >= 0)
+ dvert= dm->getVertDataArray(dm, CD_MDEFORMVERT);
+ }
+
+ /* do deformation */
+ fac= 1.0f;
+
+ for(b=0; b<totvert; b++) {
+ if(dvert) {
+ for(dw=NULL, a=0; a<dvert[b].totweight; a++) {
+ if(dvert[b].dw[a].def_nr == defgrp_index) {
+ dw = &dvert[b].dw[a];
+ break;
+ }
+ }
+
+ if(mmd->flag & MOD_MDEF_INVERT_VGROUP) {
+ if(!dw) fac= 1.0f;
+ else if(dw->weight == 1.0f) continue;
+ else fac=1.0f-dw->weight;
+ }
+ else {
+ if(!dw) continue;
+ else fac= dw->weight;
+ }
+ }
+
+ totweight= 0.0f;
+ co[0]= co[1]= co[2]= 0.0f;
+
+ for(a=0; a<totcagevert; a++) {
+ weight= weights[a + b*totcagevert];
+ co[0]+= weight*dco[a][0];
+ co[1]+= weight*dco[a][1];
+ co[2]+= weight*dco[a][2];
+ totweight += weight;
+ }
+
+ if(totweight > 0.0f) {
+ VecMulf(co, fac/totweight);
+ Mat3MulVecfl(icmat, co);
+ VECADD(vertexCos[b], vertexCos[b], co);
+ }
+ }
+
+ /* release cage derivedmesh */
+ MEM_freeN(dco);
+ cagedm->release(cagedm);
+}
+
+static void meshdeformModifier_deformVerts(
+ ModifierData *md, Object *ob, DerivedMesh *derivedData,
+ float (*vertexCos)[3], int numVerts)
+{
+ DerivedMesh *dm;
+
+ if(!derivedData && ob->type==OB_MESH)
+ dm= CDDM_from_mesh(ob->data, ob);
+ else
+ dm= derivedData;
+
+ meshdeformModifier_do(md, ob, dm, vertexCos, numVerts);
+
+ if(dm != derivedData)
+ dm->release(dm);
+}
+
+static void meshdeformModifier_deformVertsEM(
+ ModifierData *md, Object *ob, EditMesh *editData,
+ DerivedMesh *derivedData, float (*vertexCos)[3], int numVerts)
+{
+ DerivedMesh *dm;
+
+ if(!derivedData && ob->type == OB_MESH)
+ dm = CDDM_from_editmesh(editData, ob->data);
+ else
+ dm = derivedData;
+
+ meshdeformModifier_do(md, ob, dm, vertexCos, numVerts);
+
+ if(dm != derivedData)
+ dm->release(dm);
+}
+
+/***/
+
+static ModifierTypeInfo typeArr[NUM_MODIFIER_TYPES];
+static int typeArrInit = 1;
+
+ModifierTypeInfo *modifierType_getInfo(ModifierType type)
+{
+ if (typeArrInit) {
+ ModifierTypeInfo *mti;
+
+ memset(typeArr, 0, sizeof(typeArr));
+
+ /* Initialize and return the appropriate type info structure,
+ * assumes that modifier has:
+ * name == typeName,
+ * structName == typeName + 'ModifierData'
+ */
+#define INIT_TYPE(typeName) \
+ (strcpy(typeArr[eModifierType_##typeName].name, #typeName), \
+ strcpy(typeArr[eModifierType_##typeName].structName, \
+ #typeName "ModifierData"), \
+ typeArr[eModifierType_##typeName].structSize = \
+ sizeof(typeName##ModifierData), \
+ &typeArr[eModifierType_##typeName])
+
+ mti = &typeArr[eModifierType_None];
+ strcpy(mti->name, "None");
+ strcpy(mti->structName, "ModifierData");
+ mti->structSize = sizeof(ModifierData);
+ mti->type = eModifierType_None;
+ mti->flags = eModifierTypeFlag_AcceptsMesh
+ | eModifierTypeFlag_AcceptsCVs;
+ mti->isDisabled = noneModifier_isDisabled;
+
+ mti = INIT_TYPE(Curve);
+ mti->type = eModifierTypeType_OnlyDeform;
+ mti->flags = eModifierTypeFlag_AcceptsCVs
+ | eModifierTypeFlag_SupportsEditmode;
+ mti->initData = curveModifier_initData;
+ mti->copyData = curveModifier_copyData;
+ mti->requiredDataMask = curveModifier_requiredDataMask;
+ mti->isDisabled = curveModifier_isDisabled;
+ mti->foreachObjectLink = curveModifier_foreachObjectLink;
+ mti->updateDepgraph = curveModifier_updateDepgraph;
+ mti->deformVerts = curveModifier_deformVerts;
+ mti->deformVertsEM = curveModifier_deformVertsEM;
+
+ mti = INIT_TYPE(Lattice);
+ mti->type = eModifierTypeType_OnlyDeform;
+ mti->flags = eModifierTypeFlag_AcceptsCVs
+ | eModifierTypeFlag_SupportsEditmode;
+ mti->copyData = latticeModifier_copyData;
+ mti->requiredDataMask = latticeModifier_requiredDataMask;
+ mti->isDisabled = latticeModifier_isDisabled;
+ mti->foreachObjectLink = latticeModifier_foreachObjectLink;
+ mti->updateDepgraph = latticeModifier_updateDepgraph;
+ mti->deformVerts = latticeModifier_deformVerts;
+ mti->deformVertsEM = latticeModifier_deformVertsEM;
+
+ mti = INIT_TYPE(Subsurf);
+ mti->type = eModifierTypeType_Constructive;
+ mti->flags = eModifierTypeFlag_AcceptsMesh
+ | eModifierTypeFlag_SupportsMapping
+ | eModifierTypeFlag_SupportsEditmode
+ | eModifierTypeFlag_EnableInEditmode;
+ mti->initData = subsurfModifier_initData;
+ mti->copyData = subsurfModifier_copyData;
+ mti->freeData = subsurfModifier_freeData;
+ mti->applyModifier = subsurfModifier_applyModifier;
+ mti->applyModifierEM = subsurfModifier_applyModifierEM;
+
+ mti = INIT_TYPE(Build);
+ mti->type = eModifierTypeType_Nonconstructive;
+ mti->flags = eModifierTypeFlag_AcceptsMesh;
+ mti->initData = buildModifier_initData;
+ mti->copyData = buildModifier_copyData;
+ mti->dependsOnTime = buildModifier_dependsOnTime;
+ mti->applyModifier = buildModifier_applyModifier;
+
+ mti = INIT_TYPE(Array);
+ mti->type = eModifierTypeType_Constructive;
+ mti->flags = eModifierTypeFlag_AcceptsMesh
+ | eModifierTypeFlag_SupportsMapping
+ | eModifierTypeFlag_SupportsEditmode
+ | eModifierTypeFlag_EnableInEditmode;
+ mti->initData = arrayModifier_initData;
+ mti->copyData = arrayModifier_copyData;
+ mti->foreachObjectLink = arrayModifier_foreachObjectLink;
+ mti->updateDepgraph = arrayModifier_updateDepgraph;
+ mti->applyModifier = arrayModifier_applyModifier;
+ mti->applyModifierEM = arrayModifier_applyModifierEM;
+
+ mti = INIT_TYPE(Mirror);
+ mti->type = eModifierTypeType_Constructive;
+ mti->flags = eModifierTypeFlag_AcceptsMesh
+ | eModifierTypeFlag_SupportsMapping
+ | eModifierTypeFlag_SupportsEditmode
+ | eModifierTypeFlag_EnableInEditmode;
+ mti->initData = mirrorModifier_initData;
+ mti->copyData = mirrorModifier_copyData;
+ mti->applyModifier = mirrorModifier_applyModifier;
+ mti->applyModifierEM = mirrorModifier_applyModifierEM;
+
+ mti = INIT_TYPE(EdgeSplit);
+ mti->type = eModifierTypeType_Constructive;
+ mti->flags = eModifierTypeFlag_AcceptsMesh
+ | eModifierTypeFlag_SupportsMapping
+ | eModifierTypeFlag_SupportsEditmode
+ | eModifierTypeFlag_EnableInEditmode;
+ mti->initData = edgesplitModifier_initData;
+ mti->copyData = edgesplitModifier_copyData;
+ mti->applyModifier = edgesplitModifier_applyModifier;
+ mti->applyModifierEM = edgesplitModifier_applyModifierEM;
+
+ mti = INIT_TYPE(Displace);
+ mti->type = eModifierTypeType_OnlyDeform;
+ mti->flags = eModifierTypeFlag_AcceptsMesh|eModifierTypeFlag_SupportsEditmode;
+ mti->initData = displaceModifier_initData;
+ mti->copyData = displaceModifier_copyData;
+ mti->requiredDataMask = displaceModifier_requiredDataMask;
+ mti->foreachObjectLink = displaceModifier_foreachObjectLink;
+ mti->foreachIDLink = displaceModifier_foreachIDLink;
+ mti->updateDepgraph = displaceModifier_updateDepgraph;
+ mti->isDisabled = displaceModifier_isDisabled;
+ mti->deformVerts = displaceModifier_deformVerts;
+ mti->deformVertsEM = displaceModifier_deformVertsEM;
+
+ mti = INIT_TYPE(UVProject);
+ mti->type = eModifierTypeType_Nonconstructive;
+ mti->flags = eModifierTypeFlag_AcceptsMesh
+ | eModifierTypeFlag_SupportsMapping
+ | eModifierTypeFlag_SupportsEditmode
+ | eModifierTypeFlag_EnableInEditmode;
+ mti->initData = uvprojectModifier_initData;
+ mti->copyData = uvprojectModifier_copyData;
+ mti->requiredDataMask = uvprojectModifier_requiredDataMask;
+ mti->foreachObjectLink = uvprojectModifier_foreachObjectLink;
+ mti->foreachIDLink = uvprojectModifier_foreachIDLink;
+ mti->updateDepgraph = uvprojectModifier_updateDepgraph;
+ mti->applyModifier = uvprojectModifier_applyModifier;
+ mti->applyModifierEM = uvprojectModifier_applyModifierEM;
+
+ mti = INIT_TYPE(Decimate);
+ mti->type = eModifierTypeType_Nonconstructive;
+ mti->flags = eModifierTypeFlag_AcceptsMesh;
+ mti->initData = decimateModifier_initData;
+ mti->copyData = decimateModifier_copyData;
+ mti->applyModifier = decimateModifier_applyModifier;
+
+ mti = INIT_TYPE(Smooth);
+ mti->type = eModifierTypeType_OnlyDeform;
+ mti->flags = eModifierTypeFlag_AcceptsMesh
+ | eModifierTypeFlag_SupportsEditmode;
+ mti->initData = smoothModifier_initData;
+ mti->copyData = smoothModifier_copyData;
+ mti->requiredDataMask = smoothModifier_requiredDataMask;
+ mti->deformVerts = smoothModifier_deformVerts;
+ mti->deformVertsEM = smoothModifier_deformVertsEM;
+
+ mti = INIT_TYPE(Cast);
+ mti->type = eModifierTypeType_OnlyDeform;
+ mti->flags = eModifierTypeFlag_AcceptsCVs
+ | eModifierTypeFlag_SupportsEditmode;
+ mti->initData = castModifier_initData;
+ mti->copyData = castModifier_copyData;
+ mti->requiredDataMask = castModifier_requiredDataMask;
+ mti->foreachObjectLink = castModifier_foreachObjectLink;
+ mti->updateDepgraph = castModifier_updateDepgraph;
+ mti->deformVerts = castModifier_deformVerts;
+ mti->deformVertsEM = castModifier_deformVertsEM;
+
+ mti = INIT_TYPE(Wave);
+ mti->type = eModifierTypeType_OnlyDeform;
+ mti->flags = eModifierTypeFlag_AcceptsCVs
+ | eModifierTypeFlag_SupportsEditmode;
+ mti->initData = waveModifier_initData;
+ mti->copyData = waveModifier_copyData;
+ mti->dependsOnTime = waveModifier_dependsOnTime;
+ mti->requiredDataMask = waveModifier_requiredDataMask;
+ mti->foreachObjectLink = waveModifier_foreachObjectLink;
+ mti->foreachIDLink = waveModifier_foreachIDLink;
+ mti->updateDepgraph = waveModifier_updateDepgraph;
+ mti->deformVerts = waveModifier_deformVerts;
+ mti->deformVertsEM = waveModifier_deformVertsEM;
+
+ mti = INIT_TYPE(Armature);
+ mti->type = eModifierTypeType_OnlyDeform;
+ mti->flags = eModifierTypeFlag_AcceptsCVs
+ | eModifierTypeFlag_SupportsEditmode;
+ mti->initData = armatureModifier_initData;
+ mti->copyData = armatureModifier_copyData;
+ mti->requiredDataMask = armatureModifier_requiredDataMask;
+ mti->isDisabled = armatureModifier_isDisabled;
+ mti->foreachObjectLink = armatureModifier_foreachObjectLink;
+ mti->updateDepgraph = armatureModifier_updateDepgraph;
+ mti->deformVerts = armatureModifier_deformVerts;
+ mti->deformVertsEM = armatureModifier_deformVertsEM;
+ mti->deformMatricesEM = armatureModifier_deformMatricesEM;
+
+ mti = INIT_TYPE(Hook);
+ mti->type = eModifierTypeType_OnlyDeform;
+ mti->flags = eModifierTypeFlag_AcceptsCVs
+ | eModifierTypeFlag_SupportsEditmode;
+ mti->initData = hookModifier_initData;
+ mti->copyData = hookModifier_copyData;
+ mti->requiredDataMask = hookModifier_requiredDataMask;
+ mti->freeData = hookModifier_freeData;
+ mti->isDisabled = hookModifier_isDisabled;
+ mti->foreachObjectLink = hookModifier_foreachObjectLink;
+ mti->updateDepgraph = hookModifier_updateDepgraph;
+ mti->deformVerts = hookModifier_deformVerts;
+ mti->deformVertsEM = hookModifier_deformVertsEM;
+
+ mti = INIT_TYPE(Softbody);
+ mti->type = eModifierTypeType_OnlyDeform;
+ mti->flags = eModifierTypeFlag_AcceptsCVs
+ | eModifierTypeFlag_RequiresOriginalData;
+ mti->deformVerts = softbodyModifier_deformVerts;
+
+ mti = INIT_TYPE(Boolean);
+ mti->type = eModifierTypeType_Nonconstructive;
+ mti->flags = eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_RequiresOriginalData;
+ mti->copyData = booleanModifier_copyData;
+ mti->isDisabled = booleanModifier_isDisabled;
+ mti->applyModifier = booleanModifier_applyModifier;
+ mti->foreachObjectLink = booleanModifier_foreachObjectLink;
+ mti->updateDepgraph = booleanModifier_updateDepgraph;
+
+ mti = INIT_TYPE(MeshDeform);
+ mti->type = eModifierTypeType_OnlyDeform;
+ mti->flags = eModifierTypeFlag_AcceptsCVs
+ | eModifierTypeFlag_SupportsEditmode;
+ mti->initData = meshdeformModifier_initData;
+ mti->freeData = meshdeformModifier_freeData;
+ mti->copyData = meshdeformModifier_copyData;
+ mti->requiredDataMask = meshdeformModifier_requiredDataMask;
+ mti->isDisabled = meshdeformModifier_isDisabled;
+ mti->foreachObjectLink = meshdeformModifier_foreachObjectLink;
+ mti->updateDepgraph = meshdeformModifier_updateDepgraph;
+ mti->deformVerts = meshdeformModifier_deformVerts;
+ mti->deformVertsEM = meshdeformModifier_deformVertsEM;
+
+ typeArrInit = 0;
+#undef INIT_TYPE
+ }
+
+ if (type>=0 && type<NUM_MODIFIER_TYPES && typeArr[type].name[0]!='\0') {
+ return &typeArr[type];
+ } else {
+ return NULL;
+ }
+}
+
+/***/
+
+ModifierData *modifier_new(int type)
+{
+ ModifierTypeInfo *mti = modifierType_getInfo(type);
+ ModifierData *md = MEM_callocN(mti->structSize, mti->structName);
+
+ strcpy(md->name, mti->name);
+
+ md->type = type;
+ md->mode = eModifierMode_Realtime
+ | eModifierMode_Render | eModifierMode_Expanded;
+
+ if (mti->flags & eModifierTypeFlag_EnableInEditmode)
+ md->mode |= eModifierMode_Editmode;
+
+ if (mti->initData) mti->initData(md);
+
+ return md;
+}
+
+void modifier_free(ModifierData *md)
+{
+ ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ if (mti->freeData) mti->freeData(md);
+ if (md->error) MEM_freeN(md->error);
+
+ MEM_freeN(md);
+}
+
+int modifier_dependsOnTime(ModifierData *md)
+{
+ ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ return mti->dependsOnTime && mti->dependsOnTime(md);
+}
+
+int modifier_supportsMapping(ModifierData *md)
+{
+ ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ return ( (mti->flags & eModifierTypeFlag_SupportsEditmode) &&
+ ( (mti->type==eModifierTypeType_OnlyDeform ||
+ (mti->flags & eModifierTypeFlag_SupportsMapping))) );
+}
+
+ModifierData *modifiers_findByType(Object *ob, ModifierType type)
+{
+ ModifierData *md = ob->modifiers.first;
+
+ for (; md; md=md->next)
+ if (md->type==type)
+ break;
+
+ return md;
+}
+
+void modifiers_clearErrors(Object *ob)
+{
+ ModifierData *md = ob->modifiers.first;
+ int qRedraw = 0;
+
+ for (; md; md=md->next) {
+ if (md->error) {
+ MEM_freeN(md->error);
+ md->error = NULL;
+
+ qRedraw = 1;
+ }
+ }
+
+ if (qRedraw) allqueue(REDRAWBUTSEDIT, 0);
+}
+
+void modifiers_foreachObjectLink(Object *ob, ObjectWalkFunc walk,
+ void *userData)
+{
+ ModifierData *md = ob->modifiers.first;
+
+ for (; md; md=md->next) {
+ ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ if (mti->foreachObjectLink)
+ mti->foreachObjectLink(md, ob, walk, userData);
+ }
+}
+
+void modifiers_foreachIDLink(Object *ob, IDWalkFunc walk, void *userData)
+{
+ ModifierData *md = ob->modifiers.first;
+
+ for (; md; md=md->next) {
+ ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ if(mti->foreachIDLink) mti->foreachIDLink(md, ob, walk, userData);
+ else if(mti->foreachObjectLink) {
+ /* each Object can masquerade as an ID, so this should be OK */
+ ObjectWalkFunc fp = (ObjectWalkFunc)walk;
+ mti->foreachObjectLink(md, ob, fp, userData);
+ }
+ }
+}
+
+void modifier_copyData(ModifierData *md, ModifierData *target)
+{
+ ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ target->mode = md->mode;
+
+ if (mti->copyData)
+ mti->copyData(md, target);
+}
+
+int modifier_couldBeCage(ModifierData *md)
+{
+ ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ return ( (md->mode & eModifierMode_Realtime) &&
+ (md->mode & eModifierMode_Editmode) &&
+ (!mti->isDisabled || !mti->isDisabled(md)) &&
+ modifier_supportsMapping(md));
+}
+
+void modifier_setError(ModifierData *md, char *format, ...)
+{
+ char buffer[2048];
+ va_list ap;
+
+ va_start(ap, format);
+ vsprintf(buffer, format, ap);
+ va_end(ap);
+
+ if (md->error)
+ MEM_freeN(md->error);
+
+ md->error = BLI_strdup(buffer);
+
+ allqueue(REDRAWBUTSEDIT, 0);
+}
+
+/* used for buttons, to find out if the 'draw deformed in editmode' option is
+ * there
+ *
+ * also used in transform_conversion.c, to detect CrazySpace [tm] (2nd arg
+ * then is NULL)
+ */
+int modifiers_getCageIndex(Object *ob, int *lastPossibleCageIndex_r)
+{
+ ModifierData *md = ob->modifiers.first;
+ int i, cageIndex = -1;
+
+ /* Find the last modifier acting on the cage. */
+ for (i=0; md; i++,md=md->next) {
+ ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ if (!(md->mode & eModifierMode_Realtime)) continue;
+ if (!(md->mode & eModifierMode_Editmode)) continue;
+ if (mti->isDisabled && mti->isDisabled(md)) continue;
+ if (!(mti->flags & eModifierTypeFlag_SupportsEditmode)) continue;
+ if (md->mode & eModifierMode_DisableTemporary) continue;
+
+ if (!modifier_supportsMapping(md))
+ break;
+
+ if (lastPossibleCageIndex_r) *lastPossibleCageIndex_r = i;
+ if (md->mode & eModifierMode_OnCage)
+ cageIndex = i;
+ }
+
+ return cageIndex;
+}
+
+
+int modifiers_isSoftbodyEnabled(Object *ob)
+{
+ ModifierData *md = modifiers_findByType(ob, eModifierType_Softbody);
+
+ return (md && md->mode & (eModifierMode_Realtime | eModifierMode_Render));
+}
+
+LinkNode *modifiers_calcDataMasks(ModifierData *md, CustomDataMask dataMask)
+{
+ LinkNode *dataMasks = NULL;
+ LinkNode *curr, *prev;
+
+ /* build a list of modifier data requirements in reverse order */
+ for(; md; md = md->next) {
+ ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ CustomDataMask mask = 0;
+
+ if(mti->requiredDataMask) mask = mti->requiredDataMask(md);
+
+ BLI_linklist_prepend(&dataMasks, (void *)mask);
+ }
+
+ /* build the list of required data masks - each mask in the list must
+ * include all elements of the masks that follow it
+ *
+ * note the list is currently in reverse order, so "masks that follow it"
+ * actually means "masks that precede it" at the moment
+ */
+ for(curr = dataMasks, prev = NULL; curr; prev = curr, curr = curr->next) {
+ if(prev) {
+ CustomDataMask prev_mask = (CustomDataMask)prev->link;
+ CustomDataMask curr_mask = (CustomDataMask)curr->link;
+
+ curr->link = (void *)(curr_mask | prev_mask);
+ } else {
+ CustomDataMask curr_mask = (CustomDataMask)curr->link;
+
+ curr->link = (void *)(curr_mask | dataMask);
+ }
+ }
+
+ /* reverse the list so it's in the correct order */
+ BLI_linklist_reverse(&dataMasks);
+
+ return dataMasks;
+}
+
+ModifierData *modifiers_getVirtualModifierList(Object *ob)
+{
+ /* Kinda hacky, but should be fine since we are never
+ * reentrant and avoid free hassles.
+ */
+ static ArmatureModifierData amd;
+ static CurveModifierData cmd;
+ static LatticeModifierData lmd;
+ static int init = 1;
+
+ if (init) {
+ ModifierData *md;
+
+ md = modifier_new(eModifierType_Armature);
+ amd = *((ArmatureModifierData*) md);
+ modifier_free(md);
+
+ md = modifier_new(eModifierType_Curve);
+ cmd = *((CurveModifierData*) md);
+ modifier_free(md);
+
+ md = modifier_new(eModifierType_Lattice);
+ lmd = *((LatticeModifierData*) md);
+ modifier_free(md);
+
+ amd.modifier.mode |= eModifierMode_Virtual;
+ cmd.modifier.mode |= eModifierMode_Virtual;
+ lmd.modifier.mode |= eModifierMode_Virtual;
+
+ init = 0;
+ }
+
+ if (ob->parent) {
+ if(ob->parent->type==OB_ARMATURE && ob->partype==PARSKEL) {
+ amd.object = ob->parent;
+ amd.modifier.next = ob->modifiers.first;
+ amd.deformflag= ((bArmature *)(ob->parent->data))->deformflag;
+ return &amd.modifier;
+ } else if(ob->parent->type==OB_CURVE && ob->partype==PARSKEL) {
+ cmd.object = ob->parent;
+ cmd.defaxis = ob->trackflag + 1;
+ cmd.modifier.next = ob->modifiers.first;
+ return &cmd.modifier;
+ } else if(ob->parent->type==OB_LATTICE && ob->partype==PARSKEL) {
+ lmd.object = ob->parent;
+ lmd.modifier.next = ob->modifiers.first;
+ return &lmd.modifier;
+ }
+ }
+
+ return ob->modifiers.first;
+}
+/* Takes an object and returns its first selected armature, else just its
+ * armature
+ * This should work for multiple armatures per object
+ */
+Object *modifiers_isDeformedByArmature(Object *ob)
+{
+ ModifierData *md = modifiers_getVirtualModifierList(ob);
+ ArmatureModifierData *amd= NULL;
+
+ /* return the first selected armature, this lets us use multiple armatures
+ */
+ for (; md; md=md->next) {
+ if (md->type==eModifierType_Armature) {
+ amd = (ArmatureModifierData*) md;
+ if (amd->object && (amd->object->flag & SELECT))
+ return amd->object;
+ }
+ }
+
+ if (amd) /* if were still here then return the last armature */
+ return amd->object;
+
+ return NULL;
+}
+
+/* Takes an object and returns its first selected lattice, else just its
+* armature
+* This should work for multiple armatures per object
+*/
+Object *modifiers_isDeformedByLattice(Object *ob)
+{
+ ModifierData *md = modifiers_getVirtualModifierList(ob);
+ LatticeModifierData *lmd= NULL;
+
+ /* return the first selected armature, this lets us use multiple armatures
+ */
+ for (; md; md=md->next) {
+ if (md->type==eModifierType_Lattice) {
+ lmd = (LatticeModifierData*) md;
+ if (lmd->object && (lmd->object->flag & SELECT))
+ return lmd->object;
+ }
+ }
+
+ if (lmd) /* if were still here then return the last lattice */
+ return lmd->object;
+
+ return NULL;
+}
+
+
+
+int modifiers_usesArmature(Object *ob, bArmature *arm)
+{
+ ModifierData *md = modifiers_getVirtualModifierList(ob);
+
+ for (; md; md=md->next) {
+ if (md->type==eModifierType_Armature) {
+ ArmatureModifierData *amd = (ArmatureModifierData*) md;
+ if (amd->object && amd->object->data==arm)
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+int modifier_isDeformer(ModifierData *md)
+{
+ if (md->type==eModifierType_Armature)
+ return 1;
+ if (md->type==eModifierType_Curve)
+ return 1;
+ if (md->type==eModifierType_Lattice)
+ return 1;
+
+ return 0;
+}
+
+int modifiers_isDeformed(Object *ob)
+{
+ ModifierData *md = modifiers_getVirtualModifierList(ob);
+
+ for (; md; md=md->next) {
+ if(ob==G.obedit && (md->mode & eModifierMode_Editmode)==0);
+ else if(modifier_isDeformer(md))
+ return 1;
+ }
+ return 0;
+}
+
diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c
new file mode 100644
index 00000000000..961ea21d088
--- /dev/null
+++ b/source/blender/blenkernel/intern/nla.c
@@ -0,0 +1,190 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+
+#include "DNA_space_types.h"
+#include "DNA_nla_types.h"
+#include "DNA_action_types.h"
+#include "DNA_ID.h"
+#include "DNA_ipo_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_nla.h"
+#include "BKE_action.h"
+#include "BKE_blender.h"
+#include "BKE_library.h"
+#include "BKE_object.h" /* for convert_action_to_strip(ob) */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* NOTE: in group.c the strips get copied for group-nla override, this assumes
+ that strips are one single block, without additional data to be copied */
+
+void copy_actionstrip (bActionStrip **dst, bActionStrip **src){
+ bActionStrip *dstrip;
+ bActionStrip *sstrip = *src;
+
+ if (!*src){
+ *dst=NULL;
+ return;
+ }
+
+ *dst = MEM_dupallocN(sstrip);
+
+ dstrip = *dst;
+ if (dstrip->act)
+ dstrip->act->id.us++;
+
+ if (dstrip->ipo)
+ dstrip->ipo->id.us++;
+
+ if (dstrip->modifiers.first) {
+ duplicatelist (&dstrip->modifiers, &sstrip->modifiers);
+ }
+
+}
+
+void copy_nlastrips (ListBase *dst, ListBase *src)
+{
+ bActionStrip *strip;
+
+ dst->first=dst->last=NULL;
+
+ duplicatelist (dst, src);
+
+ /* Update specific data */
+ if (!dst->first)
+ return;
+
+ for (strip = dst->first; strip; strip=strip->next){
+ if (strip->act)
+ strip->act->id.us++;
+ if (strip->ipo)
+ strip->ipo->id.us++;
+ if (strip->modifiers.first) {
+ ListBase listb;
+ duplicatelist (&listb, &strip->modifiers);
+ strip->modifiers= listb;
+ }
+ }
+}
+
+/* from editnla, for convert_action_to_strip -- no UI code so should be ok here.. */
+void find_stridechannel(Object *ob, bActionStrip *strip)
+{
+ if(ob && ob->pose) {
+ bPoseChannel *pchan;
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next)
+ if(pchan->flag & POSE_STRIDE)
+ break;
+ if(pchan)
+ BLI_strncpy(strip->stridechannel, pchan->name, 32);
+ else
+ strip->stridechannel[0]= 0;
+ }
+}
+
+//called by convert_nla / bpy api with an object with the action to be converted to a new strip
+bActionStrip *convert_action_to_strip (Object *ob)
+{
+ bActionStrip *nstrip;
+
+ /* Make new actionstrip */
+ nstrip = MEM_callocN(sizeof(bActionStrip), "bActionStrip");
+
+ /* Link the action to the nstrip */
+ nstrip->act = ob->action;
+ id_us_plus(&nstrip->act->id);
+ calc_action_range(nstrip->act, &nstrip->actstart, &nstrip->actend, 1);
+ nstrip->start = nstrip->actstart;
+ nstrip->end = nstrip->actend;
+ nstrip->flag = ACTSTRIP_SELECT|ACTSTRIP_LOCK_ACTION;
+
+ find_stridechannel(ob, nstrip);
+ //set_active_strip(ob, nstrip); /* is in editnla as does UI calls */
+
+ nstrip->repeat = 1.0;
+
+ if(ob->nlastrips.first == NULL)
+ ob->nlaflag |= OB_NLA_OVERRIDE;
+
+ BLI_addtail(&ob->nlastrips, nstrip);
+ return nstrip; /* is created, malloced etc. here so is safe to just return the pointer?
+ this is needed for setting this active in UI, and probably useful for API too */
+
+}
+
+
+/* not strip itself! */
+void free_actionstrip(bActionStrip* strip)
+{
+ if (!strip)
+ return;
+
+ if (strip->act){
+ strip->act->id.us--;
+ strip->act = NULL;
+ }
+ if (strip->ipo){
+ strip->ipo->id.us--;
+ strip->ipo = NULL;
+ }
+ if (strip->modifiers.first) {
+ BLI_freelistN(&strip->modifiers);
+ }
+
+}
+
+void free_nlastrips (ListBase *nlalist)
+{
+ bActionStrip *strip;
+
+ if (!nlalist->first)
+ return;
+
+ /* Do any specific freeing */
+ for (strip=nlalist->first; strip; strip=strip->next)
+ {
+ free_actionstrip (strip);
+ };
+
+ /* Free the whole list */
+ BLI_freelistN(nlalist);
+}
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
new file mode 100644
index 00000000000..651115b7180
--- /dev/null
+++ b/source/blender/blenkernel/intern/node.c
@@ -0,0 +1,2414 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "DNA_ID.h"
+#include "DNA_image_types.h"
+#include "DNA_node_types.h"
+#include "DNA_material_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_blender.h"
+#include "BKE_colortools.h"
+#include "BKE_global.h"
+#include "BKE_image.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_node.h"
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+#include "BLI_rand.h"
+#include "BLI_threads.h"
+
+#include "PIL_time.h"
+
+#include "MEM_guardedalloc.h"
+#include "IMB_imbuf.h"
+
+#include "RE_pipeline.h"
+#include "RE_shader_ext.h" /* <- TexResult */
+#include "RE_render_ext.h" /* <- ibuf_sample() */
+
+#include "CMP_node.h"
+#include "SHD_node.h"
+
+/* not very important, but the stack solver likes to know a maximum */
+#define MAX_SOCKET 64
+
+static ListBase empty_list = {NULL, NULL};
+ListBase node_all_composit = {NULL, NULL};
+ListBase node_all_shaders = {NULL, NULL};
+
+/* ************** Type stuff ********** */
+
+static bNodeType *node_get_type(bNodeTree *ntree, int type, bNodeTree *ngroup)
+{
+ if(type==NODE_GROUP) {
+ if(ngroup && GS(ngroup->id.name)==ID_NT) {
+ return ngroup->owntype;
+ }
+ return NULL;
+ }
+ else {
+ bNodeType *ntype = ntree->alltypes.first;
+ for(; ntype; ntype= ntype->next)
+ if(ntype->type==type)
+ return ntype;
+
+ return NULL;
+ }
+}
+
+void ntreeInitTypes(bNodeTree *ntree)
+{
+ bNode *node, *next;
+
+ if(ntree->type==NTREE_SHADER)
+ ntree->alltypes= node_all_shaders;
+ else if(ntree->type==NTREE_COMPOSIT)
+ ntree->alltypes= node_all_composit;
+ else {
+ ntree->alltypes= empty_list;
+ printf("Error: no type definitions for nodes\n");
+ }
+
+ for(node= ntree->nodes.first; node; node= next) {
+ next= node->next;
+ node->typeinfo= node_get_type(ntree, node->type, (bNodeTree *)node->id);
+ if(node->typeinfo==NULL) {
+ printf("Error: Node type %s doesn't exist anymore, removed\n", node->name);
+ nodeFreeNode(ntree, node);
+ }
+ }
+
+ ntree->init |= NTREE_TYPE_INIT;
+}
+
+/* only used internal... we depend on type definitions! */
+static bNodeSocket *node_add_socket_type(ListBase *lb, bNodeSocketType *stype)
+{
+ bNodeSocket *sock= MEM_callocN(sizeof(bNodeSocket), "sock");
+
+ BLI_strncpy(sock->name, stype->name, NODE_MAXSTR);
+ if(stype->limit==0) sock->limit= 0xFFF;
+ else sock->limit= stype->limit;
+ sock->type= stype->type;
+
+ sock->to_index= stype->own_index;
+ sock->tosock= stype->internsock;
+
+ sock->ns.vec[0]= stype->val1;
+ sock->ns.vec[1]= stype->val2;
+ sock->ns.vec[2]= stype->val3;
+ sock->ns.vec[3]= stype->val4;
+ sock->ns.min= stype->min;
+ sock->ns.max= stype->max;
+
+ if(lb)
+ BLI_addtail(lb, sock);
+
+ return sock;
+}
+
+static void node_rem_socket(bNodeTree *ntree, ListBase *lb, bNodeSocket *sock)
+{
+ bNodeLink *link, *next;
+
+ for(link= ntree->links.first; link; link= next) {
+ next= link->next;
+ if(link->fromsock==sock || link->tosock==sock) {
+ nodeRemLink(ntree, link);
+ }
+ }
+
+ BLI_remlink(lb, sock);
+ MEM_freeN(sock);
+}
+
+static bNodeSocket *verify_socket(ListBase *lb, bNodeSocketType *stype)
+{
+ bNodeSocket *sock;
+
+ for(sock= lb->first; sock; sock= sock->next) {
+ /* both indices are zero for non-groups, otherwise it's a unique index */
+ if(sock->to_index==stype->own_index)
+ if(strncmp(sock->name, stype->name, NODE_MAXSTR)==0)
+ break;
+ }
+ if(sock) {
+ sock->type= stype->type; /* in future, read this from tydefs! */
+ if(stype->limit==0) sock->limit= 0xFFF;
+ else sock->limit= stype->limit;
+ sock->ns.min= stype->min;
+ sock->ns.max= stype->max;
+ sock->tosock= stype->internsock;
+
+ BLI_remlink(lb, sock);
+
+ return sock;
+ }
+ else {
+ return node_add_socket_type(NULL, stype);
+ }
+}
+
+static void verify_socket_list(bNodeTree *ntree, ListBase *lb, bNodeSocketType *stype_first)
+{
+ bNodeSocketType *stype;
+
+ /* no inputs anymore? */
+ if(stype_first==NULL) {
+ while(lb->first)
+ node_rem_socket(ntree, lb, lb->first);
+ }
+ else {
+ /* step by step compare */
+ stype= stype_first;
+ while(stype->type != -1) {
+ stype->sock= verify_socket(lb, stype);
+ stype++;
+ }
+ /* leftovers are removed */
+ while(lb->first)
+ node_rem_socket(ntree, lb, lb->first);
+ /* and we put back the verified sockets */
+ stype= stype_first;
+ while(stype->type != -1) {
+ BLI_addtail(lb, stype->sock);
+ stype++;
+ }
+ }
+}
+
+void nodeVerifyType(bNodeTree *ntree, bNode *node)
+{
+ bNodeType *ntype= node->typeinfo;
+
+ if(ntype) {
+ /* might add some other verify stuff here */
+
+ verify_socket_list(ntree, &node->inputs, ntype->inputs);
+ verify_socket_list(ntree, &node->outputs, ntype->outputs);
+ }
+}
+
+void ntreeVerifyTypes(bNodeTree *ntree)
+{
+ bNode *node;
+
+ /* if((ntree->init & NTREE_TYPE_INIT)==0) */
+ ntreeInitTypes(ntree);
+
+ /* check inputs and outputs, and remove or insert them */
+ for(node= ntree->nodes.first; node; node= node->next)
+ nodeVerifyType(ntree, node);
+
+}
+
+/* ************** Group stuff ********** */
+
+bNodeType node_group_typeinfo= {
+ /* next,prev */ NULL, NULL,
+ /* type code */ NODE_GROUP,
+ /* name */ "Group",
+ /* width+range */ 120, 60, 200,
+ /* class+opts */ NODE_CLASS_GROUP, NODE_OPTIONS,
+ /* input sock */ NULL,
+ /* output sock */ NULL,
+ /* storage */ "",
+ /* execfunc */ NULL,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+};
+
+/* tag internal sockets */
+static void group_tag_internal_sockets(bNodeTree *ngroup)
+{
+ bNode *node;
+ bNodeSocket *sock;
+ bNodeLink *link;
+
+ /* clear intern tag, but check already for hidden sockets */
+ for(node= ngroup->nodes.first; node; node= node->next) {
+ for(sock= node->inputs.first; sock; sock= sock->next)
+ sock->intern= sock->flag & SOCK_HIDDEN;
+ for(sock= node->outputs.first; sock; sock= sock->next)
+ sock->intern= sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL);
+ }
+ /* set tag */
+ for(link= ngroup->links.first; link; link= link->next) {
+ link->fromsock->intern= 1;
+ link->tosock->intern= 1;
+ }
+
+ /* remove link pointer to external links (only happens on create group) */
+ for(node= ngroup->nodes.first; node; node= node->next) {
+ for(sock= node->inputs.first; sock; sock= sock->next)
+ if(sock->intern==0)
+ sock->link= NULL;
+ }
+
+ /* set all intern sockets to own_index zero, makes sure that later use won't mixup */
+ for(node= ngroup->nodes.first; node; node= node->next) {
+ for(sock= node->inputs.first; sock; sock= sock->next)
+ if(sock->intern)
+ sock->own_index= 0;
+ for(sock= node->outputs.first; sock; sock= sock->next)
+ if(sock->intern)
+ sock->own_index= 0;
+ }
+}
+
+/* after editing group, new sockets are zero */
+/* this routine ensures unique identifiers for zero sockets that are exposed */
+static void group_verify_own_indices(bNodeTree *ngroup)
+{
+ bNode *node;
+ bNodeSocket *sock;
+
+ for(node= ngroup->nodes.first; node; node= node->next) {
+ for(sock= node->inputs.first; sock; sock= sock->next)
+ if(sock->own_index==0 && sock->intern==0)
+ sock->own_index= ++(ngroup->cur_index);
+ for(sock= node->outputs.first; sock; sock= sock->next)
+ if(sock->own_index==0 && sock->intern==0)
+ sock->own_index= ++(ngroup->cur_index);
+ }
+ //printf("internal index %d\n", ngroup->cur_index);
+}
+
+
+/* nodetrees can be used as groups, so we need typeinfo structs generated */
+void ntreeMakeOwnType(bNodeTree *ngroup)
+{
+ bNode *node;
+ bNodeSocket *sock;
+ int totin= 0, totout=0, a;
+
+ /* tags socket when internal linked */
+ group_tag_internal_sockets(ngroup);
+
+ /* ensure all sockets have own unique id */
+ group_verify_own_indices(ngroup);
+
+ /* counting stats */
+ for(node= ngroup->nodes.first; node; node= node->next) {
+ if(node->type==NODE_GROUP)
+ break;
+ for(sock= node->inputs.first; sock; sock= sock->next)
+ if(sock->intern==0)
+ totin++;
+ for(sock= node->outputs.first; sock; sock= sock->next)
+ if(sock->intern==0)
+ totout++;
+ }
+ /* debug: nodetrees in nodetrees not handled yet */
+ if(node) {
+ printf("group in group, not supported yet\n");
+ return;
+ }
+
+ /* free own type struct */
+ if(ngroup->owntype) {
+ if(ngroup->owntype->inputs)
+ MEM_freeN(ngroup->owntype->inputs);
+ if(ngroup->owntype->outputs)
+ MEM_freeN(ngroup->owntype->outputs);
+ MEM_freeN(ngroup->owntype);
+ }
+
+ /* make own type struct */
+ ngroup->owntype= MEM_callocN(sizeof(bNodeType), "group type");
+ *ngroup->owntype= node_group_typeinfo; /* copy data, for init */
+
+ /* input type arrays */
+ if(totin) {
+ bNodeSocketType *stype;
+ bNodeSocketType *inputs= MEM_callocN(sizeof(bNodeSocketType)*(totin+1), "bNodeSocketType");
+ a= 0;
+
+ for(node= ngroup->nodes.first; node; node= node->next) {
+ /* nodes are presumed fully verified, stype and socket list are in sync */
+ stype= node->typeinfo->inputs;
+ for(sock= node->inputs.first; sock; sock= sock->next, stype++) {
+ if(sock->intern==0) {
+ /* debug only print */
+ if(stype==NULL || stype->type==-1) printf("group verification error %s\n", ngroup->id.name);
+
+ inputs[a]= *stype;
+ inputs[a].own_index= sock->own_index;
+ inputs[a].internsock= sock;
+ a++;
+ }
+ }
+ }
+ inputs[a].type= -1; /* terminator code */
+ ngroup->owntype->inputs= inputs;
+ }
+
+ /* output type arrays */
+ if(totout) {
+ bNodeSocketType *stype;
+ bNodeSocketType *outputs= MEM_callocN(sizeof(bNodeSocketType)*(totout+1), "bNodeSocketType");
+ a= 0;
+
+ for(node= ngroup->nodes.first; node; node= node->next) {
+ /* nodes are presumed fully verified, stype and socket list are in sync */
+ stype= node->typeinfo->outputs;
+ for(sock= node->outputs.first; sock; sock= sock->next, stype++) {
+ if(sock->intern==0) {
+ /* debug only print */
+ if(stype==NULL || stype->type==-1) printf("group verification error %s\n", ngroup->id.name);
+
+ outputs[a]= *stype;
+ outputs[a].own_index= sock->own_index;
+ outputs[a].internsock= sock;
+ a++;
+ }
+ }
+ }
+ outputs[a].type= -1; /* terminator code */
+ ngroup->owntype->outputs= outputs;
+ }
+
+ /* voila, the nodetree has the full definition for generating group-node instances! */
+}
+
+
+static bNodeSocket *groupnode_find_tosock(bNode *gnode, int index)
+{
+ bNodeSocket *sock;
+
+ for(sock= gnode->inputs.first; sock; sock= sock->next)
+ if(sock->to_index==index)
+ return sock;
+ return NULL;
+}
+
+static bNodeSocket *groupnode_find_fromsock(bNode *gnode, int index)
+{
+ bNodeSocket *sock;
+
+ for(sock= gnode->outputs.first; sock; sock= sock->next)
+ if(sock->to_index==index)
+ return sock;
+ return NULL;
+}
+
+bNode *nodeMakeGroupFromSelected(bNodeTree *ntree)
+{
+ bNodeLink *link, *linkn;
+ bNode *node, *gnode, *nextn;
+ bNodeSocket *sock;
+ bNodeTree *ngroup;
+ float min[2], max[2];
+ int totnode=0;
+
+ INIT_MINMAX2(min, max);
+
+ /* is there something to group? also do some clearing */
+ for(node= ntree->nodes.first; node; node= node->next) {
+ if(node->flag & NODE_SELECT) {
+ /* no groups in groups */
+ if(node->type==NODE_GROUP)
+ return NULL;
+ DO_MINMAX2( (&node->locx), min, max);
+ totnode++;
+ }
+ node->done= 0;
+ }
+ if(totnode==0) return NULL;
+
+ /* check if all connections are OK, no unselected node has both
+ inputs and outputs to a selection */
+ for(link= ntree->links.first; link; link= link->next) {
+ if(link->fromnode->flag & NODE_SELECT)
+ link->tonode->done |= 1;
+ if(link->tonode->flag & NODE_SELECT)
+ link->fromnode->done |= 2;
+ }
+
+ for(node= ntree->nodes.first; node; node= node->next) {
+ if((node->flag & NODE_SELECT)==0)
+ if(node->done==3)
+ break;
+ }
+ if(node)
+ return NULL;
+
+ /* OK! new nodetree */
+ ngroup= alloc_libblock(&G.main->nodetree, ID_NT, "NodeGroup");
+ ngroup->type= ntree->type;
+ ngroup->alltypes= ntree->alltypes;
+
+ /* move nodes over */
+ for(node= ntree->nodes.first; node; node= nextn) {
+ nextn= node->next;
+ if(node->flag & NODE_SELECT) {
+ BLI_remlink(&ntree->nodes, node);
+ BLI_addtail(&ngroup->nodes, node);
+ node->locx-= 0.5f*(min[0]+max[0]);
+ node->locy-= 0.5f*(min[1]+max[1]);
+ }
+ }
+
+ /* move links over */
+ for(link= ntree->links.first; link; link= linkn) {
+ linkn= link->next;
+ if(link->fromnode->flag & link->tonode->flag & NODE_SELECT) {
+ BLI_remlink(&ntree->links, link);
+ BLI_addtail(&ngroup->links, link);
+ }
+ }
+
+ /* now we can make own group typeinfo */
+ ntreeMakeOwnType(ngroup);
+
+ /* make group node */
+ gnode= nodeAddNodeType(ntree, NODE_GROUP, ngroup);
+ gnode->locx= 0.5f*(min[0]+max[0]);
+ gnode->locy= 0.5f*(min[1]+max[1]);
+
+ /* relink external sockets */
+ for(link= ntree->links.first; link; link= linkn) {
+ linkn= link->next;
+
+ if(link->tonode->flag & NODE_SELECT) {
+ link->tonode= gnode;
+ sock= groupnode_find_tosock(gnode, link->tosock->own_index);
+ if(sock==NULL) {
+ nodeRemLink(ntree, link);
+ printf("Removed link, cannot mix internal and external sockets in group\n");
+ }
+ else link->tosock= sock;
+ }
+ else if(link->fromnode->flag & NODE_SELECT) {
+ link->fromnode= gnode;
+ sock= groupnode_find_fromsock(gnode, link->fromsock->own_index);
+ if(sock==NULL) {
+ nodeRemLink(ntree, link);
+ printf("Removed link, cannot mix internal and external sockets in group\n");
+ }
+ else link->fromsock= sock;
+ }
+ }
+
+ /* initialize variables of unused input sockets */
+ for(node= ngroup->nodes.first; node; node= node->next) {
+ for(sock= node->inputs.first; sock; sock= sock->next) {
+ if(sock->intern==0) {
+ bNodeSocket *nsock= groupnode_find_tosock(gnode, sock->own_index);
+ if(nsock) {
+ QUATCOPY(nsock->ns.vec, sock->ns.vec);
+ }
+ }
+ }
+ }
+ return gnode;
+}
+
+/* note: ungroup: group_indices zero! */
+
+/* here's a nasty little one, need to check users... */
+/* should become callbackable... */
+void nodeVerifyGroup(bNodeTree *ngroup)
+{
+
+ /* group changed, so we rebuild the type definition */
+ ntreeMakeOwnType(ngroup);
+
+ if(ngroup->type==NTREE_SHADER) {
+ Material *ma;
+ for(ma= G.main->mat.first; ma; ma= ma->id.next) {
+ if(ma->nodetree) {
+ bNode *node;
+
+ /* find if group is in tree */
+ for(node= ma->nodetree->nodes.first; node; node= node->next)
+ if(node->id == (ID *)ngroup)
+ break;
+
+ if(node) {
+ /* set all type pointers OK */
+ ntreeInitTypes(ma->nodetree);
+
+ for(node= ma->nodetree->nodes.first; node; node= node->next)
+ if(node->id == (ID *)ngroup)
+ nodeVerifyType(ma->nodetree, node);
+ }
+ }
+ }
+ }
+ else if(ngroup->type==NTREE_COMPOSIT) {
+ Scene *sce;
+ for(sce= G.main->scene.first; sce; sce= sce->id.next) {
+ if(sce->nodetree) {
+ bNode *node;
+
+ /* find if group is in tree */
+ for(node= sce->nodetree->nodes.first; node; node= node->next)
+ if(node->id == (ID *)ngroup)
+ break;
+
+ if(node) {
+ /* set all type pointers OK */
+ ntreeInitTypes(sce->nodetree);
+
+ for(node= sce->nodetree->nodes.first; node; node= node->next)
+ if(node->id == (ID *)ngroup)
+ nodeVerifyType(sce->nodetree, node);
+ }
+ }
+ }
+ }
+}
+
+/* also to check all users of groups. Now only used in editor for hide/unhide */
+/* should become callbackable? */
+void nodeGroupSocketUseFlags(bNodeTree *ngroup)
+{
+ bNode *node;
+ bNodeSocket *sock;
+
+ /* clear flags */
+ for(node= ngroup->nodes.first; node; node= node->next) {
+ for(sock= node->inputs.first; sock; sock= sock->next)
+ sock->flag &= ~SOCK_IN_USE;
+ for(sock= node->outputs.first; sock; sock= sock->next)
+ sock->flag &= ~SOCK_IN_USE;
+ }
+
+ /* tag all thats in use */
+ if(ngroup->type==NTREE_SHADER) {
+ Material *ma;
+ for(ma= G.main->mat.first; ma; ma= ma->id.next) {
+ if(ma->nodetree) {
+ for(node= ma->nodetree->nodes.first; node; node= node->next) {
+ if(node->id==(ID *)ngroup) {
+ for(sock= node->inputs.first; sock; sock= sock->next)
+ if(sock->link)
+ if(sock->tosock)
+ sock->tosock->flag |= SOCK_IN_USE;
+ for(sock= node->outputs.first; sock; sock= sock->next)
+ if(nodeCountSocketLinks(ma->nodetree, sock))
+ if(sock->tosock)
+ sock->tosock->flag |= SOCK_IN_USE;
+ }
+ }
+ }
+ }
+ }
+ else if(ngroup->type==NTREE_COMPOSIT) {
+ Scene *sce;
+ for(sce= G.main->scene.first; sce; sce= sce->id.next) {
+ if(sce->nodetree) {
+ for(node= sce->nodetree->nodes.first; node; node= node->next) {
+ if(node->id==(ID *)ngroup) {
+ for(sock= node->inputs.first; sock; sock= sock->next)
+ if(sock->link)
+ if(sock->tosock)
+ sock->tosock->flag |= SOCK_IN_USE;
+ for(sock= node->outputs.first; sock; sock= sock->next)
+ if(nodeCountSocketLinks(sce->nodetree, sock))
+ if(sock->tosock)
+ sock->tosock->flag |= SOCK_IN_USE;
+ }
+ }
+ }
+ }
+ }
+}
+
+static void find_node_with_socket(bNodeTree *ntree, bNodeSocket *sock, bNode **nodep, int *sockindex)
+{
+ bNode *node;
+ bNodeSocket *tsock;
+ int index= 0;
+
+ for(node= ntree->nodes.first; node; node= node->next) {
+ for(index=0, tsock= node->inputs.first; tsock; tsock= tsock->next, index++)
+ if(tsock==sock)
+ break;
+ if(tsock)
+ break;
+ for(index=0, tsock= node->outputs.first; tsock; tsock= tsock->next, index++)
+ if(tsock==sock)
+ break;
+ if(tsock)
+ break;
+ }
+ if(node) {
+ *nodep= node;
+ *sockindex= index;
+ }
+ else {
+ *nodep= NULL;
+ }
+}
+
+/* returns 1 if its OK */
+int nodeGroupUnGroup(bNodeTree *ntree, bNode *gnode)
+{
+ bNodeLink *link, *linkn;
+ bNode *node, *nextn;
+ bNodeTree *ngroup, *wgroup;
+ int index;
+
+ ngroup= (bNodeTree *)gnode->id;
+ if(ngroup==NULL) return 0;
+
+ /* clear new pointers, set in copytree */
+ for(node= ntree->nodes.first; node; node= node->next)
+ node->new_node= NULL;
+
+ wgroup= ntreeCopyTree(ngroup, 0);
+
+ /* add the nodes into the ntree */
+ for(node= wgroup->nodes.first; node; node= nextn) {
+ nextn= node->next;
+ BLI_remlink(&wgroup->nodes, node);
+ BLI_addtail(&ntree->nodes, node);
+ node->locx+= gnode->locx;
+ node->locy+= gnode->locy;
+ node->flag |= NODE_SELECT;
+ }
+ /* and the internal links */
+ for(link= wgroup->links.first; link; link= linkn) {
+ linkn= link->next;
+ BLI_remlink(&wgroup->links, link);
+ BLI_addtail(&ntree->links, link);
+ }
+
+ /* restore links to and from the gnode */
+ for(link= ntree->links.first; link; link= link->next) {
+ if(link->tonode==gnode) {
+ /* link->tosock->tosock is on the node we look for */
+ find_node_with_socket(ngroup, link->tosock->tosock, &nextn, &index);
+ if(nextn==NULL) printf("wrong stuff!\n");
+ else if(nextn->new_node==NULL) printf("wrong stuff too!\n");
+ else {
+ link->tonode= nextn->new_node;
+ link->tosock= BLI_findlink(&link->tonode->inputs, index);
+ }
+ }
+ else if(link->fromnode==gnode) {
+ /* link->fromsock->tosock is on the node we look for */
+ find_node_with_socket(ngroup, link->fromsock->tosock, &nextn, &index);
+ if(nextn==NULL) printf("1 wrong stuff!\n");
+ else if(nextn->new_node==NULL) printf("1 wrong stuff too!\n");
+ else {
+ link->fromnode= nextn->new_node;
+ link->fromsock= BLI_findlink(&link->fromnode->outputs, index);
+ }
+ }
+ }
+
+ /* remove the gnode & work tree */
+ free_libblock(&G.main->nodetree, wgroup);
+
+ nodeFreeNode(ntree, gnode);
+
+ /* solve order goes fine, but the level tags not... doing it twice works for now. solve this once */
+ ntreeSolveOrder(ntree);
+ ntreeSolveOrder(ntree);
+
+ return 1;
+}
+
+/* ************** Add stuff ********** */
+
+bNode *nodeAddNodeType(bNodeTree *ntree, int type, bNodeTree *ngroup)
+{
+ bNode *node;
+ bNodeType *ntype= node_get_type(ntree, type, ngroup);
+ bNodeSocketType *stype;
+
+ node= MEM_callocN(sizeof(bNode), "new node");
+ BLI_addtail(&ntree->nodes, node);
+ node->typeinfo= ntype;
+
+ if(ngroup)
+ BLI_strncpy(node->name, ngroup->id.name+2, NODE_MAXSTR);
+ else
+ BLI_strncpy(node->name, ntype->name, NODE_MAXSTR);
+ node->type= ntype->type;
+ node->flag= NODE_SELECT|ntype->flag;
+ node->width= ntype->width;
+ node->miniwidth= 42.0f; /* small value only, allows print of first chars */
+
+ if(type==NODE_GROUP)
+ node->id= (ID *)ngroup;
+
+ if(ntype->inputs) {
+ stype= ntype->inputs;
+ while(stype->type != -1) {
+ node_add_socket_type(&node->inputs, stype);
+ stype++;
+ }
+ }
+ if(ntype->outputs) {
+ stype= ntype->outputs;
+ while(stype->type != -1) {
+ node_add_socket_type(&node->outputs, stype);
+ stype++;
+ }
+ }
+
+ /* need init handler later? */
+ /* got it-bob*/
+ if(ntype->initfunc!=NULL)
+ ntype->initfunc(node);
+
+ return node;
+}
+
+/* keep socket listorder identical, for copying links */
+/* ntree is the target tree */
+bNode *nodeCopyNode(struct bNodeTree *ntree, struct bNode *node)
+{
+ bNode *nnode= MEM_callocN(sizeof(bNode), "dupli node");
+ bNodeSocket *sock;
+
+ *nnode= *node;
+ BLI_addtail(&ntree->nodes, nnode);
+
+ duplicatelist(&nnode->inputs, &node->inputs);
+ for(sock= nnode->inputs.first; sock; sock= sock->next)
+ sock->own_index= 0;
+
+ duplicatelist(&nnode->outputs, &node->outputs);
+ for(sock= nnode->outputs.first; sock; sock= sock->next) {
+ sock->own_index= 0;
+ sock->stack_index= 0;
+ sock->ns.data= NULL;
+ }
+
+ if(nnode->id)
+ nnode->id->us++;
+
+ if(node->typeinfo->copystoragefunc)
+ node->typeinfo->copystoragefunc(node, nnode);
+
+ node->new_node= nnode;
+ nnode->new_node= NULL;
+ nnode->preview= NULL;
+
+ return nnode;
+}
+
+bNodeLink *nodeAddLink(bNodeTree *ntree, bNode *fromnode, bNodeSocket *fromsock, bNode *tonode, bNodeSocket *tosock)
+{
+ bNodeLink *link= MEM_callocN(sizeof(bNodeLink), "link");
+
+ BLI_addtail(&ntree->links, link);
+ link->fromnode= fromnode;
+ link->fromsock= fromsock;
+ link->tonode= tonode;
+ link->tosock= tosock;
+
+ return link;
+}
+
+void nodeRemLink(bNodeTree *ntree, bNodeLink *link)
+{
+ BLI_remlink(&ntree->links, link);
+ if(link->tosock)
+ link->tosock->link= NULL;
+ MEM_freeN(link);
+}
+
+
+bNodeTree *ntreeAddTree(int type)
+{
+ bNodeTree *ntree= MEM_callocN(sizeof(bNodeTree), "new node tree");
+ ntree->type= type;
+ ntree->alltypes.first = NULL;
+ ntree->alltypes.last = NULL;
+
+ ntreeInitTypes(ntree);
+ return ntree;
+}
+
+bNodeTree *ntreeCopyTree(bNodeTree *ntree, int internal_select)
+{
+ bNodeTree *newtree;
+ bNode *node, *nnode, *last;
+ bNodeLink *link, *nlink;
+ bNodeSocket *sock;
+ int a;
+
+ if(ntree==NULL) return NULL;
+
+ if(internal_select==0) {
+ /* is ntree part of library? */
+ for(newtree=G.main->nodetree.first; newtree; newtree= newtree->id.next)
+ if(newtree==ntree) break;
+ if(newtree)
+ newtree= copy_libblock(ntree);
+ else
+ newtree= MEM_dupallocN(ntree);
+ newtree->nodes.first= newtree->nodes.last= NULL;
+ newtree->links.first= newtree->links.last= NULL;
+ }
+ else
+ newtree= ntree;
+
+ last= ntree->nodes.last;
+ for(node= ntree->nodes.first; node; node= node->next) {
+
+ node->new_node= NULL;
+ if(internal_select==0 || (node->flag & NODE_SELECT)) {
+ nnode= nodeCopyNode(newtree, node); /* sets node->new */
+ if(internal_select) {
+ node->flag &= ~NODE_SELECT;
+ nnode->flag |= NODE_SELECT;
+ }
+ node->flag &= ~NODE_ACTIVE;
+ }
+ if(node==last) break;
+ }
+
+ /* check for copying links */
+ for(link= ntree->links.first; link; link= link->next) {
+ if(link->fromnode->new_node && link->tonode->new_node) {
+ nlink= nodeAddLink(newtree, link->fromnode->new_node, NULL, link->tonode->new_node, NULL);
+ /* sockets were copied in order */
+ for(a=0, sock= link->fromnode->outputs.first; sock; sock= sock->next, a++) {
+ if(sock==link->fromsock)
+ break;
+ }
+ nlink->fromsock= BLI_findlink(&link->fromnode->new_node->outputs, a);
+
+ for(a=0, sock= link->tonode->inputs.first; sock; sock= sock->next, a++) {
+ if(sock==link->tosock)
+ break;
+ }
+ nlink->tosock= BLI_findlink(&link->tonode->new_node->inputs, a);
+ }
+ }
+
+ /* own type definition for group usage */
+ if(internal_select==0) {
+ if(ntree->owntype) {
+ newtree->owntype= MEM_dupallocN(ntree->owntype);
+ if(ntree->owntype->inputs)
+ newtree->owntype->inputs= MEM_dupallocN(ntree->owntype->inputs);
+ if(ntree->owntype->outputs)
+ newtree->owntype->outputs= MEM_dupallocN(ntree->owntype->outputs);
+ }
+ }
+ /* weird this is required... there seem to be link pointers wrong still? */
+ /* anyhoo, doing this solves crashes on copying entire tree (copy scene) and delete nodes */
+ ntreeSolveOrder(newtree);
+
+ return newtree;
+}
+
+/* ************** Free stuff ********** */
+
+/* goes over entire tree */
+static void node_unlink_node(bNodeTree *ntree, bNode *node)
+{
+ bNodeLink *link, *next;
+ bNodeSocket *sock;
+ ListBase *lb;
+
+ for(link= ntree->links.first; link; link= next) {
+ next= link->next;
+
+ if(link->fromnode==node) {
+ lb= &node->outputs;
+ NodeTagChanged(ntree, link->tonode);
+ }
+ else if(link->tonode==node)
+ lb= &node->inputs;
+ else
+ lb= NULL;
+
+ if(lb) {
+ for(sock= lb->first; sock; sock= sock->next) {
+ if(link->fromsock==sock || link->tosock==sock)
+ break;
+ }
+ if(sock) {
+ nodeRemLink(ntree, link);
+ }
+ }
+ }
+}
+
+static void composit_free_node_cache(bNode *node)
+{
+ bNodeSocket *sock;
+
+ for(sock= node->outputs.first; sock; sock= sock->next) {
+ if(sock->ns.data) {
+ free_compbuf(sock->ns.data);
+ sock->ns.data= NULL;
+ }
+ }
+}
+
+void nodeFreeNode(bNodeTree *ntree, bNode *node)
+{
+ node_unlink_node(ntree, node);
+ BLI_remlink(&ntree->nodes, node);
+
+ /* since it is called while free database, node->id is undefined */
+
+ if(ntree->type==NTREE_COMPOSIT)
+ composit_free_node_cache(node);
+ BLI_freelistN(&node->inputs);
+ BLI_freelistN(&node->outputs);
+
+ if(node->preview) {
+ if(node->preview->rect)
+ MEM_freeN(node->preview->rect);
+ MEM_freeN(node->preview);
+ }
+ if(node->typeinfo && node->typeinfo->freestoragefunc) {
+ node->typeinfo->freestoragefunc(node);
+ }
+ MEM_freeN(node);
+}
+
+/* do not free ntree itself here, free_libblock calls this function too */
+void ntreeFreeTree(bNodeTree *ntree)
+{
+ bNode *node, *next;
+
+ if(ntree==NULL) return;
+
+ ntreeEndExecTree(ntree); /* checks for if it is still initialized */
+
+ BLI_freelistN(&ntree->links); /* do first, then unlink_node goes fast */
+
+ for(node= ntree->nodes.first; node; node= next) {
+ next= node->next;
+ nodeFreeNode(ntree, node);
+ }
+
+ if(ntree->owntype) {
+ if(ntree->owntype->inputs)
+ MEM_freeN(ntree->owntype->inputs);
+ if(ntree->owntype->outputs)
+ MEM_freeN(ntree->owntype->outputs);
+ MEM_freeN(ntree->owntype);
+ }
+}
+
+void ntreeFreeCache(bNodeTree *ntree)
+{
+ bNode *node;
+
+ if(ntree==NULL) return;
+
+ if(ntree->type==NTREE_COMPOSIT)
+ for(node= ntree->nodes.first; node; node= node->next)
+ composit_free_node_cache(node);
+
+}
+
+void ntreeMakeLocal(bNodeTree *ntree)
+{
+ int local=0, lib=0;
+
+ /* - only lib users: do nothing
+ * - only local users: set flag
+ * - mixed: make copy
+ */
+
+ if(ntree->id.lib==NULL) return;
+ if(ntree->id.us==1) {
+ ntree->id.lib= 0;
+ ntree->id.flag= LIB_LOCAL;
+ new_id(0, (ID *)ntree, 0);
+ return;
+ }
+
+ /* now check users of groups... again typedepending, callback... */
+ if(ntree->type==NTREE_SHADER) {
+ Material *ma;
+ for(ma= G.main->mat.first; ma; ma= ma->id.next) {
+ if(ma->nodetree) {
+ bNode *node;
+
+ /* find if group is in tree */
+ for(node= ma->nodetree->nodes.first; node; node= node->next) {
+ if(node->id == (ID *)ntree) {
+ if(ma->id.lib) lib= 1;
+ else local= 1;
+ }
+ }
+ }
+ }
+ }
+ else if(ntree->type==NTREE_COMPOSIT) {
+ Scene *sce;
+ for(sce= G.main->scene.first; sce; sce= sce->id.next) {
+ if(sce->nodetree) {
+ bNode *node;
+
+ /* find if group is in tree */
+ for(node= sce->nodetree->nodes.first; node; node= node->next) {
+ if(node->id == (ID *)ntree) {
+ if(sce->id.lib) lib= 1;
+ else local= 1;
+ }
+ }
+ }
+ }
+ }
+
+ /* if all users are local, we simply make tree local */
+ if(local && lib==0) {
+ ntree->id.lib= NULL;
+ ntree->id.flag= LIB_LOCAL;
+ new_id(0, (ID *)ntree, 0);
+ }
+ else if(local && lib) {
+ /* this is the mixed case, we copy the tree and assign it to local users */
+ bNodeTree *newtree= ntreeCopyTree(ntree, 0);
+
+ newtree->id.us= 0;
+
+ if(ntree->type==NTREE_SHADER) {
+ Material *ma;
+ for(ma= G.main->mat.first; ma; ma= ma->id.next) {
+ if(ma->nodetree) {
+ bNode *node;
+
+ /* find if group is in tree */
+ for(node= ma->nodetree->nodes.first; node; node= node->next) {
+ if(node->id == (ID *)ntree) {
+ if(ma->id.lib==NULL) {
+ node->id= &newtree->id;
+ newtree->id.us++;
+ ntree->id.us--;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if(ntree->type==NTREE_COMPOSIT) {
+ Scene *sce;
+ for(sce= G.main->scene.first; sce; sce= sce->id.next) {
+ if(sce->nodetree) {
+ bNode *node;
+
+ /* find if group is in tree */
+ for(node= sce->nodetree->nodes.first; node; node= node->next) {
+ if(node->id == (ID *)ntree) {
+ if(sce->id.lib==NULL) {
+ node->id= &newtree->id;
+ newtree->id.us++;
+ ntree->id.us--;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+
+/* ************ find stuff *************** */
+
+static int ntreeHasType(bNodeTree *ntree, int type)
+{
+ bNode *node;
+
+ if(ntree)
+ for(node= ntree->nodes.first; node; node= node->next)
+ if(node->type == type)
+ return 1;
+ return 0;
+}
+
+bNodeLink *nodeFindLink(bNodeTree *ntree, bNodeSocket *from, bNodeSocket *to)
+{
+ bNodeLink *link;
+
+ for(link= ntree->links.first; link; link= link->next) {
+ if(link->fromsock==from && link->tosock==to)
+ return link;
+ if(link->fromsock==to && link->tosock==from) /* hrms? */
+ return link;
+ }
+ return NULL;
+}
+
+int nodeCountSocketLinks(bNodeTree *ntree, bNodeSocket *sock)
+{
+ bNodeLink *link;
+ int tot= 0;
+
+ for(link= ntree->links.first; link; link= link->next) {
+ if(link->fromsock==sock || link->tosock==sock)
+ tot++;
+ }
+ return tot;
+}
+
+bNode *nodeGetActive(bNodeTree *ntree)
+{
+ bNode *node;
+
+ if(ntree==NULL) return NULL;
+
+ for(node= ntree->nodes.first; node; node= node->next)
+ if(node->flag & NODE_ACTIVE)
+ break;
+ return node;
+}
+
+/* two active flags, ID nodes have special flag for buttons display */
+bNode *nodeGetActiveID(bNodeTree *ntree, short idtype)
+{
+ bNode *node;
+
+ if(ntree==NULL) return NULL;
+
+ for(node= ntree->nodes.first; node; node= node->next)
+ if(node->id && GS(node->id->name)==idtype)
+ if(node->flag & NODE_ACTIVE_ID)
+ break;
+ return node;
+}
+
+/* two active flags, ID nodes have special flag for buttons display */
+void nodeClearActiveID(bNodeTree *ntree, short idtype)
+{
+ bNode *node;
+
+ if(ntree==NULL) return;
+
+ for(node= ntree->nodes.first; node; node= node->next)
+ if(node->id && GS(node->id->name)==idtype)
+ node->flag &= ~NODE_ACTIVE_ID;
+}
+
+/* two active flags, ID nodes have special flag for buttons display */
+void nodeSetActive(bNodeTree *ntree, bNode *node)
+{
+ bNode *tnode;
+
+ /* make sure only one node is active, and only one per ID type */
+ for(tnode= ntree->nodes.first; tnode; tnode= tnode->next) {
+ tnode->flag &= ~NODE_ACTIVE;
+
+ if(node->id && tnode->id) {
+ if(GS(node->id->name) == GS(tnode->id->name))
+ tnode->flag &= ~NODE_ACTIVE_ID;
+ }
+ }
+
+ node->flag |= NODE_ACTIVE;
+ if(node->id)
+ node->flag |= NODE_ACTIVE_ID;
+}
+
+/* use flags are not persistant yet, groups might need different tagging, so we do it each time
+ when we need to get this info */
+void ntreeSocketUseFlags(bNodeTree *ntree)
+{
+ bNode *node;
+ bNodeSocket *sock;
+ bNodeLink *link;
+
+ /* clear flags */
+ for(node= ntree->nodes.first; node; node= node->next) {
+ for(sock= node->inputs.first; sock; sock= sock->next)
+ sock->flag &= ~SOCK_IN_USE;
+ for(sock= node->outputs.first; sock; sock= sock->next)
+ sock->flag &= ~SOCK_IN_USE;
+ }
+
+ /* tag all thats in use */
+ for(link= ntree->links.first; link; link= link->next) {
+ link->fromsock->flag |= SOCK_IN_USE;
+ link->tosock->flag |= SOCK_IN_USE;
+ }
+}
+
+/* ************** dependency stuff *********** */
+
+/* node is guaranteed to be not checked before */
+static int node_recurs_check(bNode *node, bNode ***nsort, int level)
+{
+ bNode *fromnode;
+ bNodeSocket *sock;
+ int has_inputlinks= 0;
+
+ node->done= 1;
+ level++;
+
+ for(sock= node->inputs.first; sock; sock= sock->next) {
+ if(sock->link) {
+ has_inputlinks= 1;
+ fromnode= sock->link->fromnode;
+ if(fromnode->done==0) {
+ fromnode->level= node_recurs_check(fromnode, nsort, level);
+ }
+ }
+ }
+// printf("node sort %s level %d\n", node->name, level);
+ **nsort= node;
+ (*nsort)++;
+
+ if(has_inputlinks)
+ return level;
+ else
+ return 0xFFF;
+}
+
+void ntreeSolveOrder(bNodeTree *ntree)
+{
+ bNode *node, **nodesort, **nsort;
+ bNodeSocket *sock;
+ bNodeLink *link;
+ int a, totnode=0;
+
+ /* the solve-order is called on each tree change, so we should be sure no exec can be running */
+ ntreeEndExecTree(ntree);
+
+ /* set links pointers the input sockets, to find dependencies */
+ /* first clear data */
+ for(node= ntree->nodes.first; node; node= node->next) {
+ node->done= 0;
+ totnode++;
+ for(sock= node->inputs.first; sock; sock= sock->next)
+ sock->link= NULL;
+ }
+ if(totnode==0)
+ return;
+
+ for(link= ntree->links.first; link; link= link->next) {
+ link->tosock->link= link;
+ }
+
+ nsort= nodesort= MEM_callocN(totnode*sizeof(void *), "sorted node array");
+
+ /* recursive check */
+ for(node= ntree->nodes.first; node; node= node->next) {
+ if(node->done==0) {
+ node->level= node_recurs_check(node, &nsort, 0);
+ }
+ }
+
+ /* re-insert nodes in order, first a paranoia check */
+ for(a=0; a<totnode; a++) {
+ if(nodesort[a]==NULL)
+ break;
+ }
+ if(a<totnode)
+ printf("sort error in node tree");
+ else {
+ ntree->nodes.first= ntree->nodes.last= NULL;
+ for(a=0; a<totnode; a++)
+ BLI_addtail(&ntree->nodes, nodesort[a]);
+ }
+
+ MEM_freeN(nodesort);
+
+ /* find the active outputs, might become tree type dependant handler */
+ for(node= ntree->nodes.first; node; node= node->next) {
+ if(node->typeinfo->nclass==NODE_CLASS_OUTPUT) {
+ bNode *tnode;
+ int output= 0;
+
+ /* we need a check for which output node should be tagged like this, below an exception */
+ if(node->type==CMP_NODE_OUTPUT_FILE)
+ continue;
+
+ /* there is more types having output class, each one is checked */
+ for(tnode= ntree->nodes.first; tnode; tnode= tnode->next) {
+ if(tnode->typeinfo->nclass==NODE_CLASS_OUTPUT) {
+ if(tnode->type==node->type) {
+ if(tnode->flag & NODE_DO_OUTPUT) {
+ output++;
+ if(output>1)
+ tnode->flag &= ~NODE_DO_OUTPUT;
+ }
+ }
+ }
+ }
+ if(output==0)
+ node->flag |= NODE_DO_OUTPUT;
+ }
+ }
+
+ /* here we could recursively set which nodes have to be done,
+ might be different for editor or for "real" use... */
+}
+
+/* should be callback! */
+void NodeTagChanged(bNodeTree *ntree, bNode *node)
+{
+ if(ntree->type==NTREE_COMPOSIT) {
+ bNodeSocket *sock;
+
+ for(sock= node->outputs.first; sock; sock= sock->next) {
+ if(sock->ns.data) {
+ free_compbuf(sock->ns.data);
+ sock->ns.data= NULL;
+
+ //if(node->preview && node->preview->rect) {
+ // MEM_freeN(node->preview->rect);
+ // node->preview->rect= NULL;
+ //}
+
+ }
+ }
+ node->need_exec= 1;
+ }
+}
+
+void NodeTagIDChanged(bNodeTree *ntree, ID *id)
+{
+ if(id==NULL)
+ return;
+
+ if(ntree->type==NTREE_COMPOSIT) {
+ bNode *node;
+
+ for(node= ntree->nodes.first; node; node= node->next)
+ if(node->id==id)
+ NodeTagChanged(ntree, node);
+ }
+}
+
+
+/* *************** preview *********** */
+
+/* if node->preview, then we assume the rect to exist */
+
+static void nodeInitPreview(bNode *node, int xsize, int ysize)
+{
+
+ if(node->preview==NULL) {
+ node->preview= MEM_callocN(sizeof(bNodePreview), "node preview");
+// printf("added preview %s\n", node->name);
+ }
+
+ /* node previews can get added with variable size this way */
+ if(xsize==0 || ysize==0)
+ return;
+
+ /* sanity checks & initialize */
+ if(node->preview->rect) {
+ if(node->preview->xsize!=xsize && node->preview->ysize!=ysize) {
+ MEM_freeN(node->preview->rect);
+ node->preview->rect= NULL;
+ }
+ }
+
+ if(node->preview->rect==NULL) {
+ node->preview->rect= MEM_callocN(4*xsize + xsize*ysize*sizeof(float)*4, "node preview rect");
+ node->preview->xsize= xsize;
+ node->preview->ysize= ysize;
+ }
+}
+
+void ntreeInitPreview(bNodeTree *ntree, int xsize, int ysize)
+{
+ bNode *node;
+
+ if(ntree==NULL)
+ return;
+
+ for(node= ntree->nodes.first; node; node= node->next) {
+ if(node->typeinfo->flag & NODE_PREVIEW) /* hrms, check for closed nodes? */
+ nodeInitPreview(node, xsize, ysize);
+ if(node->type==NODE_GROUP && (node->flag & NODE_GROUP_EDIT))
+ ntreeInitPreview((bNodeTree *)node->id, xsize, ysize);
+ }
+}
+
+static void nodeClearPreview(bNode *node)
+{
+ if(node->preview && node->preview->rect)
+ memset(node->preview->rect, 0, MEM_allocN_len(node->preview->rect));
+}
+
+/* use it to enforce clear */
+void ntreeClearPreview(bNodeTree *ntree)
+{
+ bNode *node;
+
+ if(ntree==NULL)
+ return;
+
+ for(node= ntree->nodes.first; node; node= node->next) {
+ if(node->typeinfo->flag & NODE_PREVIEW)
+ nodeClearPreview(node);
+ if(node->type==NODE_GROUP && (node->flag & NODE_GROUP_EDIT))
+ ntreeClearPreview((bNodeTree *)node->id);
+ }
+}
+
+/* hack warning! this function is only used for shader previews, and
+ since it gets called multiple times per pixel for Ztransp we only
+ add the color once. Preview gets cleared before it starts render though */
+void nodeAddToPreview(bNode *node, float *col, int x, int y)
+{
+ bNodePreview *preview= node->preview;
+ if(preview) {
+ if(x>=0 && y>=0) {
+ if(x<preview->xsize && y<preview->ysize) {
+ float *tar= preview->rect+ 4*((preview->xsize*y) + x);
+ if(tar[0]==0.0f) {
+ QUATCOPY(tar, col);
+ }
+ }
+ //else printf("prv out bound x y %d %d\n", x, y);
+ }
+ //else printf("prv out bound x y %d %d\n", x, y);
+ }
+}
+
+
+
+/* ******************* executing ************* */
+
+/* see notes at ntreeBeginExecTree */
+static void group_node_get_stack(bNode *node, bNodeStack *stack, bNodeStack **in, bNodeStack **out, bNodeStack **gin, bNodeStack **gout)
+{
+ bNodeSocket *sock;
+
+ /* build pointer stack */
+ for(sock= node->inputs.first; sock; sock= sock->next) {
+ if(sock->intern) {
+ /* yep, intern can have link or is hidden socket */
+ if(sock->link)
+ *(in++)= stack + sock->link->fromsock->stack_index;
+ else
+ *(in++)= &sock->ns;
+ }
+ else
+ *(in++)= gin[sock->stack_index_ext];
+ }
+
+ for(sock= node->outputs.first; sock; sock= sock->next) {
+ if(sock->intern)
+ *(out++)= stack + sock->stack_index;
+ else
+ *(out++)= gout[sock->stack_index_ext];
+ }
+}
+
+static void node_group_execute(bNodeStack *stack, void *data, bNode *gnode, bNodeStack **in, bNodeStack **out)
+{
+ bNode *node;
+ bNodeTree *ntree= (bNodeTree *)gnode->id;
+ bNodeStack *nsin[MAX_SOCKET]; /* arbitrary... watch this */
+ bNodeStack *nsout[MAX_SOCKET]; /* arbitrary... watch this */
+
+ if(ntree==NULL) return;
+
+ stack+= gnode->stack_index;
+
+ for(node= ntree->nodes.first; node; node= node->next) {
+ if(node->typeinfo->execfunc) {
+ group_node_get_stack(node, stack, nsin, nsout, in, out);
+
+ /* for groups, only execute outputs for edited group */
+ if(node->typeinfo->nclass==NODE_CLASS_OUTPUT) {
+ if(gnode->flag & NODE_GROUP_EDIT)
+ if(node->flag & NODE_DO_OUTPUT)
+ node->typeinfo->execfunc(data, node, nsin, nsout);
+ }
+ else
+ node->typeinfo->execfunc(data, node, nsin, nsout);
+ }
+ }
+
+ /* free internal group output nodes */
+ if(ntree->type==NTREE_COMPOSIT) {
+ for(node= ntree->nodes.first; node; node= node->next) {
+ if(node->typeinfo->execfunc) {
+ bNodeSocket *sock;
+
+ for(sock= node->outputs.first; sock; sock= sock->next) {
+ if(sock->intern) {
+ bNodeStack *ns= stack + sock->stack_index;
+ if(ns->data) {
+ free_compbuf(ns->data);
+ ns->data= NULL;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+/* recursively called for groups */
+/* we set all trees on own local indices, but put a total counter
+ in the groups, so each instance of a group has own stack */
+static int ntree_begin_exec_tree(bNodeTree *ntree)
+{
+ bNode *node;
+ bNodeSocket *sock;
+ int index= 0, index_in= 0, index_out= 0;
+
+ if((ntree->init & NTREE_TYPE_INIT)==0)
+ ntreeInitTypes(ntree);
+
+ /* create indices for stack, check preview */
+ for(node= ntree->nodes.first; node; node= node->next) {
+
+ for(sock= node->inputs.first; sock; sock= sock->next) {
+ if(sock->intern==0)
+ sock->stack_index_ext= index_in++;
+ }
+
+ for(sock= node->outputs.first; sock; sock= sock->next) {
+ sock->stack_index= index++;
+ if(sock->intern==0)
+ sock->stack_index_ext= index_out++;
+ }
+
+ if(node->type==NODE_GROUP) {
+ if(node->id) {
+ node->stack_index= index;
+ index+= ntree_begin_exec_tree((bNodeTree *)node->id);
+ }
+ }
+ }
+
+ return index;
+}
+
+/* copy socket compbufs to stack, initialize usage of curve nodes */
+static void composit_begin_exec(bNodeTree *ntree, int is_group)
+{
+ bNode *node;
+ bNodeSocket *sock;
+
+ for(node= ntree->nodes.first; node; node= node->next) {
+
+ /* initialize needed for groups */
+ node->exec= 0;
+
+ if(is_group==0) {
+ for(sock= node->outputs.first; sock; sock= sock->next) {
+ bNodeStack *ns= ntree->stack[0] + sock->stack_index;
+
+ if(sock->ns.data) {
+ ns->data= sock->ns.data;
+ sock->ns.data= NULL;
+ }
+ }
+ }
+ /* cannot initialize them while using in threads */
+ if(ELEM3(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB)) {
+ curvemapping_initialize(node->storage);
+ if(node->type==CMP_NODE_CURVE_RGB)
+ curvemapping_premultiply(node->storage, 0);
+ }
+ if(node->type==NODE_GROUP)
+ composit_begin_exec((bNodeTree *)node->id, 1);
+
+ }
+}
+
+/* copy stack compbufs to sockets */
+static void composit_end_exec(bNodeTree *ntree, int is_group)
+{
+ extern void print_compbuf(char *str, struct CompBuf *cbuf);
+ bNode *node;
+ bNodeStack *ns;
+ int a;
+
+ for(node= ntree->nodes.first; node; node= node->next) {
+ if(is_group==0) {
+ bNodeSocket *sock;
+
+ for(sock= node->outputs.first; sock; sock= sock->next) {
+ ns= ntree->stack[0] + sock->stack_index;
+ if(ns->data) {
+ sock->ns.data= ns->data;
+ ns->data= NULL;
+ }
+ }
+ }
+ if(node->type==CMP_NODE_CURVE_RGB)
+ curvemapping_premultiply(node->storage, 1);
+
+ if(node->type==NODE_GROUP)
+ composit_end_exec((bNodeTree *)node->id, 1);
+
+ node->need_exec= 0;
+ }
+
+ if(is_group==0) {
+ /* internally, group buffers are not stored */
+ for(ns= ntree->stack[0], a=0; a<ntree->stacksize; a++, ns++) {
+ if(ns->data) {
+ printf("freed leftover buffer from stack\n");
+ free_compbuf(ns->data);
+ }
+ }
+ }
+}
+
+static void group_tag_used_outputs(bNode *gnode, bNodeStack *stack)
+{
+ bNodeTree *ntree= (bNodeTree *)gnode->id;
+ bNode *node;
+
+ stack+= gnode->stack_index;
+
+ for(node= ntree->nodes.first; node; node= node->next) {
+ if(node->typeinfo->execfunc) {
+ bNodeSocket *sock;
+
+ for(sock= node->inputs.first; sock; sock= sock->next) {
+ if(sock->intern) {
+ if(sock->link) {
+ bNodeStack *ns= stack + sock->link->fromsock->stack_index;
+ ns->hasoutput= 1;
+ ns->sockettype= sock->link->fromsock->type;
+ }
+ else
+ sock->ns.sockettype= sock->type;
+ }
+ }
+ }
+ }
+}
+
+/* stack indices make sure all nodes only write in allocated data, for making it thread safe */
+/* only root tree gets the stack, to enable instances to have own stack entries */
+/* only two threads now! */
+/* per tree (and per group) unique indices are created */
+/* the index_ext we need to be able to map from groups to the group-node own stack */
+
+void ntreeBeginExecTree(bNodeTree *ntree)
+{
+ /* let's make it sure */
+ if(ntree->init & NTREE_EXEC_INIT)
+ return;
+
+ /* allocate the stack pointer array */
+ ntree->stack= MEM_callocN(BLENDER_MAX_THREADS*sizeof(void *), "stack array");
+
+ /* goes recursive over all groups */
+ ntree->stacksize= ntree_begin_exec_tree(ntree);
+
+ if(ntree->stacksize) {
+ bNode *node;
+ bNodeStack *ns;
+ int a;
+
+ /* allocate the base stack */
+ ns=ntree->stack[0]= MEM_callocN(ntree->stacksize*sizeof(bNodeStack), "node stack");
+
+ /* tag inputs, the get_stack() gives own socket stackdata if not in use */
+ for(a=0; a<ntree->stacksize; a++, ns++) ns->hasinput= 1;
+
+ /* tag used outputs, so we know when we can skip operations */
+ for(node= ntree->nodes.first; node; node= node->next) {
+ bNodeSocket *sock;
+ for(sock= node->inputs.first; sock; sock= sock->next) {
+ if(sock->link) {
+ ns= ntree->stack[0] + sock->link->fromsock->stack_index;
+ ns->hasoutput= 1;
+ ns->sockettype= sock->link->fromsock->type;
+ }
+ else
+ sock->ns.sockettype= sock->type;
+ }
+ if(node->type==NODE_GROUP && node->id)
+ group_tag_used_outputs(node, ntree->stack[0]);
+ }
+
+ /* composite does 1 node per thread, so no multiple stacks needed */
+ if(ntree->type==NTREE_COMPOSIT)
+ composit_begin_exec(ntree, 0);
+ else {
+ for(a=1; a<BLENDER_MAX_THREADS; a++)
+ ntree->stack[a]= MEM_dupallocN(ntree->stack[0]);
+ }
+ }
+
+ ntree->init |= NTREE_EXEC_INIT;
+}
+
+void ntreeEndExecTree(bNodeTree *ntree)
+{
+
+ if(ntree->init & NTREE_EXEC_INIT) {
+ int a;
+
+ /* another callback candidate! */
+ if(ntree->type==NTREE_COMPOSIT)
+ composit_end_exec(ntree, 0);
+
+ if(ntree->stack) {
+ for(a=0; a<BLENDER_MAX_THREADS; a++)
+ if(ntree->stack[a])
+ MEM_freeN(ntree->stack[a]);
+
+ MEM_freeN(ntree->stack);
+ ntree->stack= NULL;
+ }
+
+ ntree->init &= ~NTREE_EXEC_INIT;
+ }
+}
+
+static void node_get_stack(bNode *node, bNodeStack *stack, bNodeStack **in, bNodeStack **out)
+{
+ bNodeSocket *sock;
+
+ /* build pointer stack */
+ for(sock= node->inputs.first; sock; sock= sock->next) {
+ if(sock->link)
+ *(in++)= stack + sock->link->fromsock->stack_index;
+ else
+ *(in++)= &sock->ns;
+ }
+
+ for(sock= node->outputs.first; sock; sock= sock->next) {
+ *(out++)= stack + sock->stack_index;
+ }
+}
+
+/* nodes are presorted, so exec is in order of list */
+void ntreeExecTree(bNodeTree *ntree, void *callerdata, int thread)
+{
+ bNode *node;
+ bNodeStack *nsin[MAX_SOCKET]; /* arbitrary... watch this */
+ bNodeStack *nsout[MAX_SOCKET]; /* arbitrary... watch this */
+ bNodeStack *stack;
+
+ /* only when initialized */
+ if((ntree->init & NTREE_EXEC_INIT)==0)
+ ntreeBeginExecTree(ntree);
+
+ stack= ntree->stack[thread];
+
+ for(node= ntree->nodes.first; node; node= node->next) {
+ if(node->typeinfo->execfunc) {
+ node_get_stack(node, stack, nsin, nsout);
+ node->typeinfo->execfunc(callerdata, node, nsin, nsout);
+ }
+ else if(node->type==NODE_GROUP && node->id) {
+ node_get_stack(node, stack, nsin, nsout);
+ node_group_execute(stack, callerdata, node, nsin, nsout);
+ }
+ }
+}
+
+
+/* ***************************** threaded version for execute composite nodes ************* */
+
+/* not changing info, for thread callback */
+typedef struct ThreadData {
+ bNodeStack *stack;
+ RenderData *rd;
+} ThreadData;
+
+static void *exec_composite_node(void *node_v)
+{
+ bNodeStack *nsin[MAX_SOCKET]; /* arbitrary... watch this */
+ bNodeStack *nsout[MAX_SOCKET]; /* arbitrary... watch this */
+ bNode *node= node_v;
+ ThreadData *thd= (ThreadData *)node->new_node; /* abuse */
+
+ node_get_stack(node, thd->stack, nsin, nsout);
+
+ if(node->typeinfo->execfunc) {
+ node->typeinfo->execfunc(thd->rd, node, nsin, nsout);
+ }
+ else if(node->type==NODE_GROUP && node->id) {
+ node_group_execute(thd->stack, thd->rd, node, nsin, nsout);
+ }
+
+ node->exec |= NODE_READY;
+ return 0;
+}
+
+/* these are nodes without input, only giving values */
+/* or nodes with only value inputs */
+static int node_only_value(bNode *node)
+{
+ bNodeSocket *sock;
+
+ if(ELEM3(node->type, CMP_NODE_TIME, CMP_NODE_VALUE, CMP_NODE_RGB))
+ return 1;
+
+ /* doing this for all node types goes wrong. memory free errors */
+ if(node->inputs.first && node->type==CMP_NODE_MAP_VALUE) {
+ int retval= 1;
+ for(sock= node->inputs.first; sock; sock= sock->next) {
+ if(sock->link)
+ retval &= node_only_value(sock->link->fromnode);
+ }
+ return retval;
+ }
+ return 0;
+}
+
+/* return total of executable nodes, for timecursor */
+/* only compositor uses it */
+static int setExecutableNodes(bNodeTree *ntree, ThreadData *thd)
+{
+ bNodeStack *nsin[MAX_SOCKET]; /* arbitrary... watch this */
+ bNodeStack *nsout[MAX_SOCKET]; /* arbitrary... watch this */
+ bNode *node;
+ bNodeSocket *sock;
+ int totnode= 0, group_edit= 0;
+
+ /* note; do not add a dependency sort here, the stack was created already */
+
+ /* if we are in group edit, viewer nodes get skipped when group has viewer */
+ for(node= ntree->nodes.first; node; node= node->next)
+ if(node->type==NODE_GROUP && (node->flag & NODE_GROUP_EDIT))
+ if(ntreeHasType((bNodeTree *)node->id, CMP_NODE_VIEWER))
+ group_edit= 1;
+
+ for(node= ntree->nodes.first; node; node= node->next) {
+ int a;
+
+ node_get_stack(node, thd->stack, nsin, nsout);
+
+ /* test the outputs */
+ /* skip value-only nodes (should be in type!) */
+ if(!node_only_value(node)) {
+ for(a=0, sock= node->outputs.first; sock; sock= sock->next, a++) {
+ if(nsout[a]->data==NULL && nsout[a]->hasoutput) {
+ node->need_exec= 1;
+ break;
+ }
+ }
+ }
+
+ /* test the inputs */
+ for(a=0, sock= node->inputs.first; sock; sock= sock->next, a++) {
+ /* skip viewer nodes in bg render or group edit */
+ if( ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER) && (G.background || group_edit))
+ node->need_exec= 0;
+ /* is sock in use? */
+ else if(sock->link) {
+ bNodeLink *link= sock->link;
+ /* this is the test for a cyclic case */
+ if(link->fromnode->level >= link->tonode->level && link->tonode->level!=0xFFF) {
+ if(link->fromnode->need_exec) {
+ node->need_exec= 1;
+ break;
+ }
+ }
+ else {
+ node->need_exec= 0;
+ printf("Node %s skipped, cyclic dependency\n", node->name);
+ }
+ }
+ }
+
+ if(node->need_exec) {
+
+ /* free output buffers */
+ for(a=0, sock= node->outputs.first; sock; sock= sock->next, a++) {
+ if(nsout[a]->data) {
+ free_compbuf(nsout[a]->data);
+ nsout[a]->data= NULL;
+ }
+ }
+ totnode++;
+ /* printf("node needs exec %s\n", node->name); */
+
+ /* tag for getExecutableNode() */
+ node->exec= 0;
+ }
+ else {
+ /* tag for getExecutableNode() */
+ node->exec= NODE_READY|NODE_FINISHED;
+
+ }
+ }
+
+ /* last step: set the stack values for only-value nodes */
+ /* just does all now, compared to a full buffer exec this is nothing */
+ if(totnode) {
+ for(node= ntree->nodes.first; node; node= node->next) {
+ if(node->need_exec==0 && node_only_value(node)) {
+ if(node->typeinfo->execfunc) {
+ node_get_stack(node, thd->stack, nsin, nsout);
+ node->typeinfo->execfunc(thd->rd, node, nsin, nsout);
+ }
+ }
+ }
+ }
+
+ return totnode;
+}
+
+/* while executing tree, free buffers from nodes that are not needed anymore */
+static void freeExecutableNode(bNodeTree *ntree)
+{
+ /* node outputs can be freed when:
+ - not a render result or image node
+ - when node outputs go to nodes all being set NODE_FINISHED
+ */
+ bNode *node;
+ bNodeSocket *sock;
+
+ /* set exec flag for finished nodes that might need freed */
+ for(node= ntree->nodes.first; node; node= node->next) {
+ if(node->type!=CMP_NODE_R_LAYERS)
+ if(node->exec & NODE_FINISHED)
+ node->exec |= NODE_FREEBUFS;
+ }
+ /* clear this flag for input links that are not done yet */
+ for(node= ntree->nodes.first; node; node= node->next) {
+ if((node->exec & NODE_FINISHED)==0) {
+ for(sock= node->inputs.first; sock; sock= sock->next)
+ if(sock->link)
+ sock->link->fromnode->exec &= ~NODE_FREEBUFS;
+ }
+ }
+ /* now we can free buffers */
+ for(node= ntree->nodes.first; node; node= node->next) {
+ if(node->exec & NODE_FREEBUFS) {
+ for(sock= node->outputs.first; sock; sock= sock->next) {
+ bNodeStack *ns= ntree->stack[0] + sock->stack_index;
+ if(ns->data) {
+ free_compbuf(ns->data);
+ ns->data= NULL;
+ // printf("freed buf node %s \n", node->name);
+ }
+ }
+ }
+ }
+}
+
+static bNode *getExecutableNode(bNodeTree *ntree)
+{
+ bNode *node;
+ bNodeSocket *sock;
+
+ for(node= ntree->nodes.first; node; node= node->next) {
+ if(node->exec==0) {
+
+ /* input sockets should be ready */
+ for(sock= node->inputs.first; sock; sock= sock->next) {
+ if(sock->link)
+ if((sock->link->fromnode->exec & NODE_READY)==0)
+ break;
+ }
+ if(sock==NULL)
+ return node;
+ }
+ }
+ return NULL;
+}
+
+
+/* optimized tree execute test for compositing */
+void ntreeCompositExecTree(bNodeTree *ntree, RenderData *rd, int do_preview)
+{
+ bNode *node;
+ ListBase threads;
+ ThreadData thdata;
+ int totnode, rendering= 1;
+
+ if(ntree==NULL) return;
+
+ if(do_preview)
+ ntreeInitPreview(ntree, 0, 0);
+
+ ntreeBeginExecTree(ntree);
+
+ /* prevent unlucky accidents */
+ if(G.background)
+ rd->scemode &= ~R_COMP_CROP;
+
+ /* setup callerdata for thread callback */
+ thdata.rd= rd;
+ thdata.stack= ntree->stack[0];
+
+ /* fixed seed, for example noise texture */
+ BLI_srandom(rd->cfra);
+
+ /* sets need_exec tags in nodes */
+ totnode= setExecutableNodes(ntree, &thdata);
+
+ BLI_init_threads(&threads, exec_composite_node, rd->threads);
+
+ while(rendering) {
+
+ if(BLI_available_threads(&threads)) {
+ node= getExecutableNode(ntree);
+ if(node) {
+
+ if(ntree->timecursor)
+ ntree->timecursor(totnode);
+ if(ntree->stats_draw) {
+ char str[64];
+ sprintf(str, "Compositing %d %s", totnode, node->name);
+ ntree->stats_draw(str);
+ }
+ totnode--;
+
+ node->new_node = (bNode *)&thdata;
+ node->exec= NODE_PROCESSING;
+ BLI_insert_thread(&threads, node);
+ }
+ else
+ PIL_sleep_ms(50);
+ }
+ else
+ PIL_sleep_ms(50);
+
+ rendering= 0;
+ /* test for ESC */
+ if(ntree->test_break && ntree->test_break()) {
+ for(node= ntree->nodes.first; node; node= node->next)
+ node->exec |= NODE_READY;
+ }
+
+ /* check for ready ones, and if we need to continue */
+ for(node= ntree->nodes.first; node; node= node->next) {
+ if(node->exec & NODE_READY) {
+ if((node->exec & NODE_FINISHED)==0) {
+ BLI_remove_thread(&threads, node); /* this waits for running thread to finish btw */
+ node->exec |= NODE_FINISHED;
+
+ /* freeing unused buffers */
+ if(rd->scemode & R_COMP_FREE)
+ freeExecutableNode(ntree);
+ }
+ }
+ else rendering= 1;
+ }
+ }
+
+
+ BLI_end_threads(&threads);
+
+ ntreeEndExecTree(ntree);
+}
+
+
+/* **************** call to switch lamploop for material node ************ */
+
+void (*node_shader_lamp_loop)(struct ShadeInput *, struct ShadeResult *);
+
+void set_node_shader_lamp_loop(void (*lamp_loop_func)(ShadeInput *, ShadeResult *))
+{
+ node_shader_lamp_loop= lamp_loop_func;
+}
+
+/* clumsy checking... should do dynamic outputs once */
+static void force_hidden_passes(bNode *node, int passflag)
+{
+ bNodeSocket *sock;
+
+ for(sock= node->outputs.first; sock; sock= sock->next)
+ sock->flag &= ~SOCK_UNAVAIL;
+
+ sock= BLI_findlink(&node->outputs, RRES_OUT_Z);
+ if(!(passflag & SCE_PASS_Z)) sock->flag |= SOCK_UNAVAIL;
+ sock= BLI_findlink(&node->outputs, RRES_OUT_NORMAL);
+ if(!(passflag & SCE_PASS_NORMAL)) sock->flag |= SOCK_UNAVAIL;
+ sock= BLI_findlink(&node->outputs, RRES_OUT_VEC);
+ if(!(passflag & SCE_PASS_VECTOR)) sock->flag |= SOCK_UNAVAIL;
+ sock= BLI_findlink(&node->outputs, RRES_OUT_UV);
+ if(!(passflag & SCE_PASS_UV)) sock->flag |= SOCK_UNAVAIL;
+ sock= BLI_findlink(&node->outputs, RRES_OUT_RGBA);
+ if(!(passflag & SCE_PASS_RGBA)) sock->flag |= SOCK_UNAVAIL;
+ sock= BLI_findlink(&node->outputs, RRES_OUT_DIFF);
+ if(!(passflag & SCE_PASS_DIFFUSE)) sock->flag |= SOCK_UNAVAIL;
+ sock= BLI_findlink(&node->outputs, RRES_OUT_SPEC);
+ if(!(passflag & SCE_PASS_SPEC)) sock->flag |= SOCK_UNAVAIL;
+ sock= BLI_findlink(&node->outputs, RRES_OUT_SHADOW);
+ if(!(passflag & SCE_PASS_SHADOW)) sock->flag |= SOCK_UNAVAIL;
+ sock= BLI_findlink(&node->outputs, RRES_OUT_AO);
+ if(!(passflag & SCE_PASS_AO)) sock->flag |= SOCK_UNAVAIL;
+ sock= BLI_findlink(&node->outputs, RRES_OUT_REFLECT);
+ if(!(passflag & SCE_PASS_REFLECT)) sock->flag |= SOCK_UNAVAIL;
+ sock= BLI_findlink(&node->outputs, RRES_OUT_REFRACT);
+ if(!(passflag & SCE_PASS_REFRACT)) sock->flag |= SOCK_UNAVAIL;
+ sock= BLI_findlink(&node->outputs, RRES_OUT_RADIO);
+ if(!(passflag & SCE_PASS_RADIO)) sock->flag |= SOCK_UNAVAIL;
+ sock= BLI_findlink(&node->outputs, RRES_OUT_INDEXOB);
+ if(!(passflag & SCE_PASS_INDEXOB)) sock->flag |= SOCK_UNAVAIL;
+
+}
+
+/* based on rules, force sockets hidden always */
+void ntreeCompositForceHidden(bNodeTree *ntree)
+{
+ bNode *node;
+
+ if(ntree==NULL) return;
+
+ for(node= ntree->nodes.first; node; node= node->next) {
+ if( node->type==CMP_NODE_R_LAYERS) {
+ Scene *sce= node->id?(Scene *)node->id:G.scene; /* G.scene is WEAK! */
+ SceneRenderLayer *srl= BLI_findlink(&sce->r.layers, node->custom1);
+ if(srl)
+ force_hidden_passes(node, srl->passflag);
+ }
+ else if( node->type==CMP_NODE_IMAGE) {
+ Image *ima= (Image *)node->id;
+ if(ima) {
+ if(ima->rr) {
+ ImageUser *iuser= node->storage;
+ RenderLayer *rl= BLI_findlink(&ima->rr->layers, iuser->layer);
+ if(rl)
+ force_hidden_passes(node, rl->passflag);
+ else
+ force_hidden_passes(node, 0);
+ }
+ else if(ima->type!=IMA_TYPE_MULTILAYER) { /* if ->rr not yet read we keep inputs */
+ force_hidden_passes(node, RRES_OUT_Z);
+ }
+ else
+ force_hidden_passes(node, 0);
+ }
+ else
+ force_hidden_passes(node, 0);
+ }
+ }
+
+}
+
+/* called from render pipeline, to tag render input and output */
+/* need to do all scenes, to prevent errors when you re-render 1 scene */
+void ntreeCompositTagRender(Scene *curscene)
+{
+ Scene *sce;
+
+ for(sce= G.main->scene.first; sce; sce= sce->id.next) {
+ if(sce->nodetree) {
+ bNode *node;
+
+ for(node= sce->nodetree->nodes.first; node; node= node->next) {
+ if(node->id==(ID *)curscene || node->type==CMP_NODE_COMPOSITE)
+ NodeTagChanged(sce->nodetree, node);
+ }
+ }
+ }
+}
+
+/* tags nodes that have animation capabilities */
+int ntreeCompositTagAnimated(bNodeTree *ntree)
+{
+ bNode *node;
+ int tagged= 0;
+
+ if(ntree==NULL) return 0;
+
+ for(node= ntree->nodes.first; node; node= node->next) {
+ if(node->type==CMP_NODE_IMAGE) {
+ Image *ima= (Image *)node->id;
+ if(ima && ELEM(ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) {
+ NodeTagChanged(ntree, node);
+ tagged= 1;
+ }
+ }
+ else if(node->type==CMP_NODE_TIME) {
+ NodeTagChanged(ntree, node);
+ tagged= 1;
+ }
+ else if(node->type==CMP_NODE_R_LAYERS) {
+ NodeTagChanged(ntree, node);
+ tagged= 1;
+ }
+ else if(node->type==NODE_GROUP) {
+ if( ntreeCompositTagAnimated((bNodeTree *)node->id) ) {
+ NodeTagChanged(ntree, node);
+ }
+ }
+ }
+
+ return tagged;
+}
+
+
+/* called from image window preview */
+void ntreeCompositTagGenerators(bNodeTree *ntree)
+{
+ bNode *node;
+
+ if(ntree==NULL) return;
+
+ for(node= ntree->nodes.first; node; node= node->next) {
+ if( ELEM(node->type, CMP_NODE_R_LAYERS, CMP_NODE_IMAGE))
+ NodeTagChanged(ntree, node);
+ }
+}
+
+/* ************* node definition init ********** */
+
+static bNodeType *is_nodetype_registered(ListBase *typelist, int type)
+{
+ bNodeType *ntype= typelist->first;
+
+ for(;ntype; ntype= ntype->next )
+ if(ntype->type==type)
+ return ntype;
+
+ return NULL;
+}
+
+/* type can be from a static array, we make copy for duplicate types (like group) */
+void nodeRegisterType(ListBase *typelist, const bNodeType *ntype)
+{
+ bNodeType *found= is_nodetype_registered(typelist, ntype->type);
+
+ if(found==NULL) {
+ bNodeType *ntypen= MEM_mallocN(sizeof(bNodeType), "node type");
+ *ntypen= *ntype;
+ BLI_addtail(typelist, ntypen);
+ }
+}
+
+static void registerCompositNodes(ListBase *ntypelist)
+{
+ nodeRegisterType(ntypelist, &node_group_typeinfo);
+ nodeRegisterType(ntypelist, &cmp_node_rlayers);
+ nodeRegisterType(ntypelist, &cmp_node_image);
+ nodeRegisterType(ntypelist, &cmp_node_texture);
+ nodeRegisterType(ntypelist, &cmp_node_value);
+ nodeRegisterType(ntypelist, &cmp_node_rgb);
+ nodeRegisterType(ntypelist, &cmp_node_curve_time);
+
+ nodeRegisterType(ntypelist, &cmp_node_composite);
+ nodeRegisterType(ntypelist, &cmp_node_viewer);
+ nodeRegisterType(ntypelist, &cmp_node_splitviewer);
+ nodeRegisterType(ntypelist, &cmp_node_output_file);
+
+ nodeRegisterType(ntypelist, &cmp_node_curve_rgb);
+ nodeRegisterType(ntypelist, &cmp_node_mix_rgb);
+ nodeRegisterType(ntypelist, &cmp_node_hue_sat);
+ nodeRegisterType(ntypelist, &cmp_node_brightcontrast);
+ nodeRegisterType(ntypelist, &cmp_node_gamma);
+ nodeRegisterType(ntypelist, &cmp_node_invert);
+ nodeRegisterType(ntypelist, &cmp_node_alphaover);
+ nodeRegisterType(ntypelist, &cmp_node_zcombine);
+
+ nodeRegisterType(ntypelist, &cmp_node_normal);
+ nodeRegisterType(ntypelist, &cmp_node_curve_vec);
+ nodeRegisterType(ntypelist, &cmp_node_map_value);
+ nodeRegisterType(ntypelist, &cmp_node_normalize);
+
+ nodeRegisterType(ntypelist, &cmp_node_filter);
+ nodeRegisterType(ntypelist, &cmp_node_blur);
+ nodeRegisterType(ntypelist, &cmp_node_vecblur);
+ nodeRegisterType(ntypelist, &cmp_node_dilateerode);
+ nodeRegisterType(ntypelist, &cmp_node_defocus);
+
+ nodeRegisterType(ntypelist, &cmp_node_valtorgb);
+ nodeRegisterType(ntypelist, &cmp_node_rgbtobw);
+ nodeRegisterType(ntypelist, &cmp_node_setalpha);
+ nodeRegisterType(ntypelist, &cmp_node_idmask);
+ nodeRegisterType(ntypelist, &cmp_node_math);
+ nodeRegisterType(ntypelist, &cmp_node_seprgba);
+ nodeRegisterType(ntypelist, &cmp_node_combrgba);
+ nodeRegisterType(ntypelist, &cmp_node_sephsva);
+ nodeRegisterType(ntypelist, &cmp_node_combhsva);
+ nodeRegisterType(ntypelist, &cmp_node_sepyuva);
+ nodeRegisterType(ntypelist, &cmp_node_combyuva);
+ nodeRegisterType(ntypelist, &cmp_node_sepycca);
+ nodeRegisterType(ntypelist, &cmp_node_combycca);
+
+ nodeRegisterType(ntypelist, &cmp_node_diff_matte);
+ nodeRegisterType(ntypelist, &cmp_node_chroma);
+ nodeRegisterType(ntypelist, &cmp_node_channel_matte);
+ nodeRegisterType(ntypelist, &cmp_node_color_spill);
+ nodeRegisterType(ntypelist, &cmp_node_luma_matte);
+
+ nodeRegisterType(ntypelist, &cmp_node_translate);
+ nodeRegisterType(ntypelist, &cmp_node_rotate);
+ nodeRegisterType(ntypelist, &cmp_node_scale);
+ nodeRegisterType(ntypelist, &cmp_node_flip);
+ nodeRegisterType(ntypelist, &cmp_node_crop);
+ nodeRegisterType(ntypelist, &cmp_node_displace);
+ nodeRegisterType(ntypelist, &cmp_node_mapuv);
+
+ nodeRegisterType(ntypelist, &cmp_node_glare);
+ nodeRegisterType(ntypelist, &cmp_node_tonemap);
+ nodeRegisterType(ntypelist, &cmp_node_lensdist);
+}
+
+static void registerShaderNodes(ListBase *ntypelist)
+{
+ nodeRegisterType(ntypelist, &node_group_typeinfo);
+ nodeRegisterType(ntypelist, &sh_node_output);
+ nodeRegisterType(ntypelist, &sh_node_mix_rgb);
+ nodeRegisterType(ntypelist, &sh_node_valtorgb);
+ nodeRegisterType(ntypelist, &sh_node_rgbtobw);
+ nodeRegisterType(ntypelist, &sh_node_normal);
+ nodeRegisterType(ntypelist, &sh_node_geom);
+ nodeRegisterType(ntypelist, &sh_node_mapping);
+ nodeRegisterType(ntypelist, &sh_node_curve_vec);
+ nodeRegisterType(ntypelist, &sh_node_curve_rgb);
+ nodeRegisterType(ntypelist, &sh_node_math);
+ nodeRegisterType(ntypelist, &sh_node_vect_math);
+ nodeRegisterType(ntypelist, &sh_node_squeeze);
+ nodeRegisterType(ntypelist, &sh_node_camera);
+ nodeRegisterType(ntypelist, &sh_node_material);
+ nodeRegisterType(ntypelist, &sh_node_material_ext);
+ nodeRegisterType(ntypelist, &sh_node_value);
+ nodeRegisterType(ntypelist, &sh_node_rgb);
+ nodeRegisterType(ntypelist, &sh_node_texture);
+ nodeRegisterType(ntypelist, &sh_node_invert);
+ nodeRegisterType(ntypelist, &sh_node_seprgb);
+ nodeRegisterType(ntypelist, &sh_node_combrgb);
+ nodeRegisterType(ntypelist, &sh_node_hue_sat);
+}
+
+void init_nodesystem(void)
+{
+ registerCompositNodes(&node_all_composit);
+ registerShaderNodes(&node_all_shaders);
+}
+
+void free_nodesystem(void)
+{
+ BLI_freelistN(&node_all_composit);
+ BLI_freelistN(&node_all_shaders);
+}
+
+
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
new file mode 100644
index 00000000000..7d707813c65
--- /dev/null
+++ b/source/blender/blenkernel/intern/object.c
@@ -0,0 +1,2080 @@
+/* object.c
+ *
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <string.h>
+#include <math.h>
+#include <stdio.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_action_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_group_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_nla_types.h"
+#include "DNA_object_types.h"
+#include "DNA_object_force.h"
+#include "DNA_object_fluidsim.h"
+#include "DNA_oops_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_world_types.h"
+
+#include "BKE_armature.h"
+#include "BKE_action.h"
+#include "BKE_colortools.h"
+#include "BKE_deform.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_nla.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_editVert.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_bad_level_calls.h"
+
+#include "BKE_main.h"
+#include "BKE_global.h"
+
+#include "BKE_anim.h"
+#include "BKE_blender.h"
+#include "BKE_constraint.h"
+#include "BKE_curve.h"
+#include "BKE_displist.h"
+#include "BKE_effect.h"
+#include "BKE_group.h"
+#include "BKE_icons.h"
+#include "BKE_ipo.h"
+#include "BKE_key.h"
+#include "BKE_lattice.h"
+#include "BKE_library.h"
+#include "BKE_mesh.h"
+#include "BKE_mball.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+#include "BKE_property.h"
+#include "BKE_sca.h"
+#include "BKE_scene.h"
+#include "BKE_screen.h"
+#include "BKE_softbody.h"
+
+#include "LBM_fluidsim.h"
+
+#include "BPY_extern.h"
+
+/* Local function protos */
+static void solve_parenting (Object *ob, Object *par, float obmat[][4], float slowmat[][4], int simul);
+
+float originmat[3][3]; /* after where_is_object(), can be used in other functions (bad!) */
+Object workob;
+
+void clear_workob(void)
+{
+ memset(&workob, 0, sizeof(Object));
+
+ workob.size[0]= workob.size[1]= workob.size[2]= 1.0;
+
+}
+
+void copy_baseflags()
+{
+ Base *base= G.scene->base.first;
+
+ while(base) {
+ base->object->flag= base->flag;
+ base= base->next;
+ }
+}
+
+void copy_objectflags()
+{
+ Base *base= G.scene->base.first;
+
+ while(base) {
+ base->flag= base->object->flag;
+ base= base->next;
+ }
+}
+
+void update_base_layer(Object *ob)
+{
+ Base *base= G.scene->base.first;
+
+ while (base) {
+ if (base->object == ob) base->lay= ob->lay;
+ base= base->next;
+ }
+}
+
+void object_free_modifiers(Object *ob)
+{
+ while (ob->modifiers.first) {
+ ModifierData *md = ob->modifiers.first;
+
+ BLI_remlink(&ob->modifiers, md);
+
+ modifier_free(md);
+ }
+}
+
+/* here we will collect all local displist stuff */
+/* also (ab)used in depsgraph */
+void object_free_display(Object *ob)
+{
+ if(ob->derivedDeform) {
+ ob->derivedDeform->needsFree = 1;
+ ob->derivedDeform->release(ob->derivedDeform);
+ ob->derivedDeform= NULL;
+ }
+ if(ob->derivedFinal) {
+ ob->derivedFinal->needsFree = 1;
+ ob->derivedFinal->release(ob->derivedFinal);
+ ob->derivedFinal= NULL;
+ }
+
+ freedisplist(&ob->disp);
+}
+
+/* do not free object itself */
+void free_object(Object *ob)
+{
+ int a;
+
+ object_free_display(ob);
+
+ /* disconnect specific data */
+ if(ob->data) {
+ ID *id= ob->data;
+ id->us--;
+ if(id->us==0) {
+ if(ob->type==OB_MESH) unlink_mesh(ob->data);
+ else if(ob->type==OB_CURVE) unlink_curve(ob->data);
+ else if(ob->type==OB_MBALL) unlink_mball(ob->data);
+ }
+ ob->data= 0;
+ }
+
+ for(a=0; a<ob->totcol; a++) {
+ if(ob->mat[a]) ob->mat[a]->id.us--;
+ }
+ if(ob->mat) MEM_freeN(ob->mat);
+ ob->mat= 0;
+ if(ob->bb) MEM_freeN(ob->bb);
+ ob->bb= 0;
+ if(ob->path) free_path(ob->path);
+ ob->path= 0;
+ if(ob->ipo) ob->ipo->id.us--;
+ if(ob->action) ob->action->id.us--;
+ if(ob->dup_group) ob->dup_group->id.us--;
+ if(ob->defbase.first)
+ BLI_freelistN(&ob->defbase);
+ if(ob->pose) {
+ free_pose_channels(ob->pose);
+ MEM_freeN(ob->pose);
+ }
+ free_effects(&ob->effect);
+ free_properties(&ob->prop);
+ object_free_modifiers(ob);
+
+ free_sensors(&ob->sensors);
+ free_controllers(&ob->controllers);
+ free_actuators(&ob->actuators);
+
+ free_constraints(&ob->constraints);
+ free_constraint_channels(&ob->constraintChannels);
+ free_nlastrips(&ob->nlastrips);
+
+ BPY_free_scriptlink(&ob->scriptlink);
+
+ if(ob->pd) MEM_freeN(ob->pd);
+ if(ob->soft) sbFree(ob->soft);
+ if(ob->fluidsimSettings) fluidsimSettingsFree(ob->fluidsimSettings);
+}
+
+static void unlink_object__unlinkModifierLinks(void *userData, Object *ob, Object **obpoin)
+{
+ Object *unlinkOb = userData;
+
+ if (*obpoin==unlinkOb) {
+ *obpoin = NULL;
+ ob->recalc |= OB_RECALC;
+ }
+}
+void unlink_object(Object *ob)
+{
+ Object *obt;
+ Material *mat;
+ World *wrld;
+ bScreen *sc;
+ Scene *sce;
+ Curve *cu;
+ Tex *tex;
+ Ipo *ipo;
+ Group *group;
+ Camera *camera;
+ bConstraint *con;
+ bActionStrip *strip;
+ int a;
+
+ unlink_controllers(&ob->controllers);
+ unlink_actuators(&ob->actuators);
+
+ /* check all objects: parents en bevels and fields, also from libraries */
+ obt= G.main->object.first;
+ while(obt) {
+ if(obt->proxy==ob)
+ obt->proxy= NULL;
+ if(obt->proxy_from==ob) {
+ obt->proxy_from= NULL;
+ obt->recalc |= OB_RECALC_OB;
+ }
+ if(obt->proxy_group==ob)
+ obt->proxy_group= NULL;
+
+ if(obt->parent==ob) {
+ obt->parent= NULL;
+ obt->recalc |= OB_RECALC;
+ }
+
+ if(obt->track==ob) {
+ obt->track= NULL;
+ obt->recalc |= OB_RECALC_OB;
+ }
+
+ modifiers_foreachObjectLink(obt, unlink_object__unlinkModifierLinks, ob);
+
+ if ELEM(obt->type, OB_CURVE, OB_FONT) {
+ cu= obt->data;
+
+ if(cu->bevobj==ob) {
+ cu->bevobj= NULL;
+ obt->recalc |= OB_RECALC;
+ }
+ if(cu->taperobj==ob) {
+ cu->taperobj= NULL;
+ obt->recalc |= OB_RECALC;
+ }
+ if(cu->textoncurve==ob) {
+ cu->textoncurve= NULL;
+ obt->recalc |= OB_RECALC;
+ }
+ }
+ else if(obt->type==OB_ARMATURE && obt->pose) {
+ bPoseChannel *pchan;
+ for(pchan= obt->pose->chanbase.first; pchan; pchan= pchan->next) {
+ for (con = pchan->constraints.first; con; con=con->next) {
+ bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+
+ if (cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(con, &targets);
+
+ for (ct= targets.first; ct; ct= ct->next) {
+ if (ct->tar == ob) {
+ ct->tar = NULL;
+ strcpy(ct->subtarget, "");
+ obt->recalc |= OB_RECALC_DATA;
+ }
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(con, &targets, 0);
+ }
+ }
+ if(pchan->custom==ob)
+ pchan->custom= NULL;
+ }
+ }
+
+ sca_remove_ob_poin(obt, ob);
+
+ for (con = obt->constraints.first; con; con=con->next) {
+ bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+
+ if (cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(con, &targets);
+
+ for (ct= targets.first; ct; ct= ct->next) {
+ if (ct->tar == ob) {
+ ct->tar = NULL;
+ strcpy(ct->subtarget, "");
+ obt->recalc |= OB_RECALC_DATA;
+ }
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(con, &targets, 0);
+ }
+ }
+
+ /* object is deflector or field */
+ if(ob->pd) {
+ if(give_parteff(obt))
+ obt->recalc |= OB_RECALC_DATA;
+ else if(obt->soft)
+ obt->recalc |= OB_RECALC_DATA;
+ }
+
+ /* strips */
+ for(strip= obt->nlastrips.first; strip; strip= strip->next) {
+ if(strip->object==ob)
+ strip->object= NULL;
+
+ if(strip->modifiers.first) {
+ bActionModifier *amod;
+ for(amod= strip->modifiers.first; amod; amod= amod->next)
+ if(amod->ob==ob)
+ amod->ob= NULL;
+ }
+ }
+
+ obt= obt->id.next;
+ }
+
+ /* materials */
+ mat= G.main->mat.first;
+ while(mat) {
+
+ for(a=0; a<MAX_MTEX; a++) {
+ if(mat->mtex[a] && ob==mat->mtex[a]->object) {
+ /* actually, test for lib here... to do */
+ mat->mtex[a]->object= NULL;
+ }
+ }
+
+ mat= mat->id.next;
+ }
+
+ /* textures */
+ tex= G.main->tex.first;
+ while(tex) {
+ if(tex->env) {
+ if(tex->env->object == ob) tex->env->object= NULL;
+ }
+ tex= tex->id.next;
+ }
+
+ /* mballs */
+ if(ob->type==OB_MBALL) {
+ obt= find_basis_mball(ob);
+ if(obt) freedisplist(&obt->disp);
+ }
+
+ /* worlds */
+ wrld= G.main->world.first;
+ while(wrld) {
+ if(wrld->id.lib==NULL) {
+ for(a=0; a<MAX_MTEX; a++) {
+ if(wrld->mtex[a] && ob==wrld->mtex[a]->object)
+ wrld->mtex[a]->object= NULL;
+ }
+ }
+
+ wrld= wrld->id.next;
+ }
+
+ /* scenes */
+ sce= G.main->scene.first;
+ while(sce) {
+ if(sce->id.lib==NULL) {
+ if(sce->camera==ob) sce->camera= NULL;
+ }
+ sce= sce->id.next;
+ }
+ /* ipos */
+ ipo= G.main->ipo.first;
+ while(ipo) {
+ if(ipo->id.lib==NULL) {
+ IpoCurve *icu;
+ for(icu= ipo->curve.first; icu; icu= icu->next) {
+ if(icu->driver && icu->driver->ob==ob)
+ icu->driver->ob= NULL;
+ }
+ }
+ ipo= ipo->id.next;
+ }
+
+ /* screens */
+ sc= G.main->screen.first;
+ while(sc) {
+ ScrArea *sa= sc->areabase.first;
+ while(sa) {
+ SpaceLink *sl;
+
+ for (sl= sa->spacedata.first; sl; sl= sl->next) {
+ if(sl->spacetype==SPACE_VIEW3D) {
+ View3D *v3d= (View3D*) sl;
+
+ if(v3d->camera==ob) {
+ v3d->camera= NULL;
+ if(v3d->persp>1) v3d->persp= 1;
+ }
+ if(v3d->localvd && v3d->localvd->camera==ob ) {
+ v3d->localvd->camera= NULL;
+ if(v3d->localvd->persp>1) v3d->localvd->persp= 1;
+ }
+ }
+ else if(sl->spacetype==SPACE_IPO) {
+ SpaceIpo *sipo= (SpaceIpo *)sl;
+ if(sipo->from == (ID *)ob) sipo->from= NULL;
+ }
+ else if(sl->spacetype==SPACE_OOPS) {
+ SpaceOops *so= (SpaceOops *)sl;
+ Oops *oops;
+
+ oops= so->oops.first;
+ while(oops) {
+ if(oops->id==(ID *)ob) oops->id= NULL;
+ oops= oops->next;
+ }
+ if(so->treestore) {
+ TreeStoreElem *tselem= so->treestore->data;
+ int a;
+ for(a=0; a<so->treestore->usedelem; a++, tselem++) {
+ if(tselem->id==(ID *)ob) tselem->id= NULL;
+ }
+ }
+ so->lockpoin= NULL;
+ }
+ }
+
+ sa= sa->next;
+ }
+ sc= sc->id.next;
+ }
+
+ /* groups */
+ group= G.main->group.first;
+ while(group) {
+ rem_from_group(group, ob);
+ group= group->id.next;
+ }
+
+ /* cameras */
+ camera= G.main->camera.first;
+ while(camera) {
+ if (camera->dof_ob==ob) {
+ camera->dof_ob = NULL;
+ }
+ camera= camera->id.next;
+ }
+}
+
+int exist_object(Object *obtest)
+{
+ Object *ob;
+
+ if(obtest==NULL) return 0;
+
+ ob= G.main->object.first;
+ while(ob) {
+ if(ob==obtest) return 1;
+ ob= ob->id.next;
+ }
+ return 0;
+}
+
+void *add_camera(char *name)
+{
+ Camera *cam;
+
+ cam= alloc_libblock(&G.main->camera, ID_CA, name);
+
+ cam->lens= 35.0f;
+ cam->angle= 49.14f;
+ cam->clipsta= 0.1f;
+ cam->clipend= 100.0f;
+ cam->drawsize= 0.5f;
+ cam->ortho_scale= 6.0;
+ cam->flag |= CAM_SHOWTITLESAFE;
+ cam->passepartalpha = 0.2f;
+
+ return cam;
+}
+
+Camera *copy_camera(Camera *cam)
+{
+ Camera *camn;
+
+ camn= copy_libblock(cam);
+ id_us_plus((ID *)camn->ipo);
+
+ BPY_copy_scriptlink(&camn->scriptlink);
+
+ return camn;
+}
+
+
+
+void make_local_camera(Camera *cam)
+{
+ Object *ob;
+ Camera *camn;
+ int local=0, lib=0;
+
+ /* - only lib users: do nothing
+ * - only local users: set flag
+ * - mixed: make copy
+ */
+
+ if(cam->id.lib==0) return;
+ if(cam->id.us==1) {
+ cam->id.lib= 0;
+ cam->id.flag= LIB_LOCAL;
+ new_id(0, (ID *)cam, 0);
+ return;
+ }
+
+ ob= G.main->object.first;
+ while(ob) {
+ if(ob->data==cam) {
+ if(ob->id.lib) lib= 1;
+ else local= 1;
+ }
+ ob= ob->id.next;
+ }
+
+ if(local && lib==0) {
+ cam->id.lib= 0;
+ cam->id.flag= LIB_LOCAL;
+ new_id(0, (ID *)cam, 0);
+ }
+ else if(local && lib) {
+ camn= copy_camera(cam);
+ camn->id.us= 0;
+
+ ob= G.main->object.first;
+ while(ob) {
+ if(ob->data==cam) {
+
+ if(ob->id.lib==0) {
+ ob->data= camn;
+ camn->id.us++;
+ cam->id.us--;
+ }
+ }
+ ob= ob->id.next;
+ }
+ }
+}
+
+/* get the camera's dof value, takes the dof object into account */
+float dof_camera(Object *ob)
+{
+ Camera *cam = (Camera *)ob->data;
+ if (ob->type != OB_CAMERA)
+ return 0.0;
+ if (cam->dof_ob) {
+ /* too simple, better to return the distance on the view axis only
+ * return VecLenf(ob->obmat[3], cam->dof_ob->obmat[3]); */
+
+ float mat[4][4];
+ Mat4Invert(ob->imat, ob->obmat);
+ Mat4MulMat4(mat, cam->dof_ob->obmat, ob->imat);
+ return fabs(mat[3][2]);
+ }
+ return cam->YF_dofdist;
+}
+
+void *add_lamp(char *name)
+{
+ Lamp *la;
+
+ la= alloc_libblock(&G.main->lamp, ID_LA, name);
+
+ la->r= la->g= la->b= la->k= 1.0;
+ la->haint= la->energy= 1.0;
+ la->dist= 20.0;
+ la->spotsize= 45.0;
+ la->spotblend= 0.15;
+ la->att2= 1.0;
+ la->mode= LA_SHAD_BUF;
+ la->bufsize= 512;
+ la->clipsta= 0.5;
+ la->clipend= 40.0;
+ la->shadspotsize= 45.0;
+ la->samp= 3;
+ la->bias= 1.0;
+ la->soft= 3.0;
+ la->ray_samp= la->ray_sampy= la->ray_sampz= 1;
+ la->area_size=la->area_sizey=la->area_sizez= 1.0;
+ la->buffers= 1;
+ la->buftype= LA_SHADBUF_HALFWAY;
+ la->ray_samp_method = LA_SAMP_HALTON;
+ la->adapt_thresh = 0.001;
+ la->preview=NULL;
+ la->falloff_type = LA_FALLOFF_INVLINEAR;
+ la->curfalloff = curvemapping_add(1, 0.0f, 1.0f, 1.0f, 0.0f);
+ curvemapping_initialize(la->curfalloff);
+ return la;
+}
+
+Lamp *copy_lamp(Lamp *la)
+{
+ Lamp *lan;
+ int a;
+
+ lan= copy_libblock(la);
+
+ for(a=0; a<MAX_MTEX; a++) {
+ if(lan->mtex[a]) {
+ lan->mtex[a]= MEM_mallocN(sizeof(MTex), "copylamptex");
+ memcpy(lan->mtex[a], la->mtex[a], sizeof(MTex));
+ id_us_plus((ID *)lan->mtex[a]->tex);
+ }
+ }
+
+ lan->curfalloff = curvemapping_copy(la->curfalloff);
+
+ id_us_plus((ID *)lan->ipo);
+
+ if (la->preview) lan->preview = BKE_previewimg_copy(la->preview);
+
+ BPY_copy_scriptlink(&la->scriptlink);
+
+ return lan;
+}
+
+void make_local_lamp(Lamp *la)
+{
+ Object *ob;
+ Lamp *lan;
+ int local=0, lib=0;
+
+ /* - only lib users: do nothing
+ * - only local users: set flag
+ * - mixed: make copy
+ */
+
+ if(la->id.lib==0) return;
+ if(la->id.us==1) {
+ la->id.lib= 0;
+ la->id.flag= LIB_LOCAL;
+ new_id(0, (ID *)la, 0);
+ return;
+ }
+
+ ob= G.main->object.first;
+ while(ob) {
+ if(ob->data==la) {
+ if(ob->id.lib) lib= 1;
+ else local= 1;
+ }
+ ob= ob->id.next;
+ }
+
+ if(local && lib==0) {
+ la->id.lib= 0;
+ la->id.flag= LIB_LOCAL;
+ new_id(0, (ID *)la, 0);
+ }
+ else if(local && lib) {
+ lan= copy_lamp(la);
+ lan->id.us= 0;
+
+ ob= G.main->object.first;
+ while(ob) {
+ if(ob->data==la) {
+
+ if(ob->id.lib==0) {
+ ob->data= lan;
+ lan->id.us++;
+ la->id.us--;
+ }
+ }
+ ob= ob->id.next;
+ }
+ }
+}
+
+void free_camera(Camera *ca)
+{
+ BPY_free_scriptlink(&ca->scriptlink);
+}
+
+void free_lamp(Lamp *la)
+{
+ MTex *mtex;
+ int a;
+
+ /* scriptlinks */
+
+ BPY_free_scriptlink(&la->scriptlink);
+
+ for(a=0; a<MAX_MTEX; a++) {
+ mtex= la->mtex[a];
+ if(mtex && mtex->tex) mtex->tex->id.us--;
+ if(mtex) MEM_freeN(mtex);
+ }
+ la->ipo= 0;
+
+ curvemapping_free(la->curfalloff);
+
+ BKE_previewimg_free(&la->preview);
+ BKE_icon_delete(&la->id);
+ la->id.icon_id = 0;
+}
+
+void *add_wave()
+{
+ return 0;
+}
+
+
+/* *************************************************** */
+
+static void *add_obdata_from_type(int type)
+{
+ switch (type) {
+ case OB_MESH: G.totmesh++; return add_mesh("Mesh");
+ case OB_CURVE: G.totcurve++; return add_curve("Curve", OB_CURVE);
+ case OB_SURF: G.totcurve++; return add_curve("Surf", OB_SURF);
+ case OB_FONT: return add_curve("Text", OB_FONT);
+ case OB_MBALL: return add_mball("Meta");
+ case OB_CAMERA: return add_camera("Camera");
+ case OB_LAMP: G.totlamp++; return add_lamp("Lamp");
+ case OB_LATTICE: return add_lattice("Lattice");
+ case OB_WAVE: return add_wave();
+ case OB_ARMATURE: return add_armature("Armature");
+ case OB_EMPTY: return NULL;
+ default:
+ printf("add_obdata_from_type: Internal error, bad type: %d\n", type);
+ return NULL;
+ }
+}
+
+static char *get_obdata_defname(int type)
+{
+ switch (type) {
+ case OB_MESH: return "Mesh";
+ case OB_CURVE: return "Curve";
+ case OB_SURF: return "Surf";
+ case OB_FONT: return "Font";
+ case OB_MBALL: return "Mball";
+ case OB_CAMERA: return "Camera";
+ case OB_LAMP: return "Lamp";
+ case OB_LATTICE: return "Lattice";
+ case OB_WAVE: return "Wave";
+ case OB_ARMATURE: return "Armature";
+ case OB_EMPTY: return "Empty";
+ default:
+ printf("get_obdata_defname: Internal error, bad type: %d\n", type);
+ return "Empty";
+ }
+}
+
+/* more general add: creates minimum required data, but without vertices etc. */
+Object *add_only_object(int type, char *name)
+{
+ Object *ob;
+
+ ob= alloc_libblock(&G.main->object, ID_OB, name);
+ G.totobj++;
+
+ /* default object vars */
+ ob->type= type;
+ /* ob->transflag= OB_QUAT; */
+
+ QuatOne(ob->quat);
+ QuatOne(ob->dquat);
+
+ ob->col[0]= ob->col[1]= ob->col[2]= 0.0;
+ ob->col[3]= 1.0;
+
+ ob->loc[0]= ob->loc[1]= ob->loc[2]= 0.0;
+ ob->rot[0]= ob->rot[1]= ob->rot[2]= 0.0;
+ ob->size[0]= ob->size[1]= ob->size[2]= 1.0;
+
+ Mat4One(ob->constinv);
+ Mat4One(ob->parentinv);
+ Mat4One(ob->obmat);
+ ob->dt= OB_SHADED;
+ if(U.flag & USER_MAT_ON_OB) ob->colbits= -1;
+ ob->empty_drawtype= OB_ARROWS;
+ ob->empty_drawsize= 1.0;
+
+ if(type==OB_CAMERA || type==OB_LAMP) {
+ ob->trackflag= OB_NEGZ;
+ ob->upflag= OB_POSY;
+ }
+ else {
+ ob->trackflag= OB_POSY;
+ ob->upflag= OB_POSZ;
+ }
+ ob->ipoflag = OB_OFFS_OB+OB_OFFS_PARENT;
+ ob->ipowin= ID_OB; /* the ipowin shown */
+ ob->dupon= 1; ob->dupoff= 0;
+ ob->dupsta= 1; ob->dupend= 100;
+
+ /* Game engine defaults*/
+ ob->mass= ob->inertia= 1.0f;
+ ob->formfactor= 0.4f;
+ ob->damping= 0.04f;
+ ob->rdamping= 0.1f;
+ ob->anisotropicFriction[0] = 1.0f;
+ ob->anisotropicFriction[1] = 1.0f;
+ ob->anisotropicFriction[2] = 1.0f;
+ ob->gameflag= OB_PROP;
+
+ /* NT fluid sim defaults */
+ ob->fluidsimFlag = 0;
+ ob->fluidsimSettings = NULL;
+
+ return ob;
+}
+
+/* general add: to G.scene, with layer from area and default name */
+/* creates minimum required data, but without vertices etc. */
+Object *add_object(int type)
+{
+ Object *ob;
+ Base *base;
+ char name[32];
+
+ strcpy(name, get_obdata_defname(type));
+ ob = add_only_object(type, name);
+
+ ob->data= add_obdata_from_type(type);
+
+ ob->lay= G.scene->lay;
+
+ base= scene_add_base(G.scene, ob);
+ scene_select_base(G.scene, base);
+ ob->recalc |= OB_RECALC;
+
+ return ob;
+}
+
+void base_init_from_view3d(Base *base, View3D *v3d)
+{
+ Object *ob= base->object;
+
+ if (!v3d) {
+ /* no 3d view, this wont happen often */
+ base->lay = 1;
+ VECCOPY(ob->loc, G.scene->cursor);
+
+ /* return now because v3d->viewquat isnt available */
+ return;
+ } else if (v3d->localview) {
+ base->lay= ob->lay= v3d->layact + v3d->lay;
+ VECCOPY(ob->loc, v3d->cursor);
+ } else {
+ base->lay= ob->lay= v3d->layact;
+ VECCOPY(ob->loc, G.scene->cursor);
+ }
+
+ if (U.flag & USER_ADD_VIEWALIGNED) {
+ v3d->viewquat[0]= -v3d->viewquat[0];
+ if (ob->transflag & OB_QUAT) {
+ QUATCOPY(ob->quat, v3d->viewquat);
+ } else {
+ QuatToEul(v3d->viewquat, ob->rot);
+ }
+ v3d->viewquat[0]= -v3d->viewquat[0];
+ }
+}
+
+SoftBody *copy_softbody(SoftBody *sb)
+{
+ SoftBody *sbn;
+
+ if (sb==NULL) return(NULL);
+
+ sbn= MEM_dupallocN(sb);
+ sbn->totspring= sbn->totpoint= 0;
+ sbn->bpoint= NULL;
+ sbn->bspring= NULL;
+ sbn->ctime= 0.0f;
+
+ sbn->keys= NULL;
+ sbn->totkey= sbn->totpointkey= 0;
+
+ sbn->scratch= NULL;
+ return sbn;
+}
+
+static void copy_object_pose(Object *obn, Object *ob)
+{
+ bPoseChannel *chan;
+
+ copy_pose(&obn->pose, ob->pose, 1);
+
+ for (chan = obn->pose->chanbase.first; chan; chan=chan->next){
+ bConstraint *con;
+
+ chan->flag &= ~(POSE_LOC|POSE_ROT|POSE_SIZE);
+
+ for (con= chan->constraints.first; con; con= con->next) {
+ bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+
+ if (cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(con, &targets);
+
+ for (ct= targets.first; ct; ct= ct->next) {
+ if (ct->tar == ob)
+ ct->tar = obn;
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(con, &targets, 0);
+ }
+ }
+ }
+}
+
+Object *copy_object(Object *ob)
+{
+ Object *obn;
+ ModifierData *md;
+ int a;
+
+ obn= copy_libblock(ob);
+
+ if(ob->totcol) {
+ obn->mat= MEM_dupallocN(ob->mat);
+ }
+
+ if(ob->bb) obn->bb= MEM_dupallocN(ob->bb);
+ obn->path= NULL;
+ obn->flag &= ~OB_FROMGROUP;
+
+ copy_effects(&obn->effect, &ob->effect);
+ obn->modifiers.first = obn->modifiers.last= NULL;
+
+ for (md=ob->modifiers.first; md; md=md->next) {
+ ModifierData *nmd = modifier_new(md->type);
+ modifier_copyData(md, nmd);
+ BLI_addtail(&obn->modifiers, nmd);
+ }
+
+ BPY_copy_scriptlink(&ob->scriptlink);
+
+ copy_properties(&obn->prop, &ob->prop);
+ copy_sensors(&obn->sensors, &ob->sensors);
+ copy_controllers(&obn->controllers, &ob->controllers);
+ copy_actuators(&obn->actuators, &ob->actuators);
+
+ if(ob->pose) {
+ copy_object_pose(obn, ob);
+ /* backwards compat... non-armatures can get poses in older files? */
+ if(ob->type==OB_ARMATURE)
+ armature_rebuild_pose(obn, obn->data);
+ }
+ copy_defgroups(&obn->defbase, &ob->defbase);
+ copy_nlastrips(&obn->nlastrips, &ob->nlastrips);
+ copy_constraints (&obn->constraints, &ob->constraints);
+
+ clone_constraint_channels (&obn->constraintChannels, &ob->constraintChannels);
+
+ /* increase user numbers */
+ id_us_plus((ID *)obn->data);
+ id_us_plus((ID *)obn->ipo);
+ id_us_plus((ID *)obn->action);
+ id_us_plus((ID *)obn->dup_group);
+
+ for(a=0; a<obn->totcol; a++) id_us_plus((ID *)obn->mat[a]);
+
+ obn->disp.first= obn->disp.last= NULL;
+
+ if(ob->pd) obn->pd= MEM_dupallocN(ob->pd);
+ obn->soft= copy_softbody(ob->soft);
+
+ /* NT copy fluid sim setting memory */
+ if(obn->fluidsimSettings) {
+ obn->fluidsimSettings = fluidsimSettingsCopy(ob->fluidsimSettings);
+ /* copying might fail... */
+ if(obn->fluidsimSettings) {
+ obn->fluidsimSettings->orgMesh = (Mesh *)obn->data;
+ }
+ }
+
+ obn->derivedDeform = NULL;
+ obn->derivedFinal = NULL;
+
+#ifdef WITH_VERSE
+ obn->vnode = NULL;
+#endif
+
+
+ return obn;
+}
+
+void expand_local_object(Object *ob)
+{
+ bActionStrip *strip;
+ int a;
+
+ id_lib_extern((ID *)ob->action);
+ id_lib_extern((ID *)ob->ipo);
+ id_lib_extern((ID *)ob->data);
+
+ for(a=0; a<ob->totcol; a++) {
+ id_lib_extern((ID *)ob->mat[a]);
+ }
+ for (strip=ob->nlastrips.first; strip; strip=strip->next) {
+ id_lib_extern((ID *)strip->act);
+ }
+
+}
+
+void make_local_object(Object *ob)
+{
+ Object *obn;
+ Scene *sce;
+ Base *base;
+ int local=0, lib=0;
+
+ /* - only lib users: do nothing
+ * - only local users: set flag
+ * - mixed: make copy
+ */
+
+ if(ob->id.lib==NULL) return;
+
+ ob->proxy= ob->proxy_from= NULL;
+
+ if(ob->id.us==1) {
+ ob->id.lib= NULL;
+ ob->id.flag= LIB_LOCAL;
+ new_id(0, (ID *)ob, 0);
+
+ }
+ else {
+ sce= G.main->scene.first;
+ while(sce) {
+ base= sce->base.first;
+ while(base) {
+ if(base->object==ob) {
+ if(sce->id.lib) lib++;
+ else local++;
+ break;
+ }
+ base= base->next;
+ }
+ sce= sce->id.next;
+ }
+
+ if(local && lib==0) {
+ ob->id.lib= 0;
+ ob->id.flag= LIB_LOCAL;
+ new_id(0, (ID *)ob, 0);
+ }
+ else if(local && lib) {
+ obn= copy_object(ob);
+ obn->id.us= 0;
+
+ sce= G.main->scene.first;
+ while(sce) {
+ if(sce->id.lib==0) {
+ base= sce->base.first;
+ while(base) {
+ if(base->object==ob) {
+ base->object= obn;
+ obn->id.us++;
+ ob->id.us--;
+ }
+ base= base->next;
+ }
+ }
+ sce= sce->id.next;
+ }
+ }
+ }
+
+ expand_local_object(ob);
+}
+
+/* *************** PROXY **************** */
+
+/* proxy rule: lib_object->proxy_from == the one we borrow from, set temporally while object_update */
+/* local_object->proxy == pointer to library object, saved in files and read */
+/* local_object->proxy_group == pointer to group dupli-object, saved in files and read */
+
+void object_make_proxy(Object *ob, Object *target, Object *gob)
+{
+ /* paranoia checks */
+ if(ob->id.lib || target->id.lib==NULL) {
+ printf("cannot make proxy\n");
+ return;
+ }
+
+ ob->proxy= target;
+ ob->proxy_group= gob;
+ id_lib_extern(&target->id);
+
+ ob->recalc= target->recalc= OB_RECALC;
+
+ /* copy transform */
+ if(gob) {
+ VECCOPY(ob->loc, gob->loc);
+ VECCOPY(ob->rot, gob->rot);
+ VECCOPY(ob->size, gob->size);
+ }
+ else {
+ VECCOPY(ob->loc, target->loc);
+ VECCOPY(ob->rot, target->rot);
+ VECCOPY(ob->size, target->size);
+ }
+
+ ob->parent= target->parent; /* libdata */
+ Mat4CpyMat4(ob->parentinv, target->parentinv);
+ ob->ipo= target->ipo; /* libdata */
+
+ /* skip constraints, constraintchannels, nla? */
+
+ ob->type= target->type;
+ ob->data= target->data;
+ id_us_plus((ID *)ob->data); /* ensures lib data becomes LIB_EXTERN */
+
+ /* type conversions */
+ if(target->type == OB_ARMATURE) {
+ copy_object_pose(ob, target); /* data copy, object pointers in constraints */
+ rest_pose(ob->pose); /* clear all transforms in channels */
+ armature_rebuild_pose(ob, ob->data); /* set all internal links */
+ }
+}
+
+
+/* *************** CALC ****************** */
+
+/* there is also a timing calculation in drawobject() */
+
+float bluroffs= 0.0f, fieldoffs= 0.0f;
+int no_speed_curve= 0;
+
+/* ugly calls from render */
+void set_mblur_offs(float blur)
+{
+ bluroffs= blur;
+}
+
+void set_field_offs(float field)
+{
+ fieldoffs= field;
+}
+
+void disable_speed_curve(int val)
+{
+ no_speed_curve= val;
+}
+
+/* ob can be NULL */
+float bsystem_time(Object *ob, float cfra, float ofs)
+{
+ /* returns float ( see frame_to_float in ipo.c) */
+
+ /* bluroffs and fieldoffs are ugly globals that are set by render */
+ cfra+= bluroffs+fieldoffs;
+
+ /* global time */
+ cfra*= G.scene->r.framelen;
+
+ if (ob) {
+ if (no_speed_curve==0 && ob->ipo)
+ cfra= calc_ipo_time(ob->ipo, cfra);
+
+ /* ofset frames */
+ if ((ob->ipoflag & OB_OFFS_PARENT) && (ob->partype & PARSLOW)==0)
+ cfra-= ob->sf;
+ }
+
+ cfra-= ofs;
+
+ return cfra;
+}
+
+void object_to_mat3(Object *ob, float mat[][3]) /* no parent */
+{
+ float smat[3][3], vec[3];
+ float rmat[3][3];
+ float q1[4];
+
+ /* size */
+ if(ob->ipo) {
+ vec[0]= ob->size[0]+ob->dsize[0];
+ vec[1]= ob->size[1]+ob->dsize[1];
+ vec[2]= ob->size[2]+ob->dsize[2];
+ SizeToMat3(vec, smat);
+ }
+ else {
+ SizeToMat3(ob->size, smat);
+ }
+
+ /* rot */
+ if(ob->transflag & OB_QUAT) {
+ if(ob->ipo) {
+ QuatMul(q1, ob->quat, ob->dquat);
+ QuatToMat3(q1, rmat);
+ }
+ else {
+ QuatToMat3(ob->quat, rmat);
+ }
+ }
+ else {
+ if(ob->ipo) {
+ vec[0]= ob->rot[0]+ob->drot[0];
+ vec[1]= ob->rot[1]+ob->drot[1];
+ vec[2]= ob->rot[2]+ob->drot[2];
+ EulToMat3(vec, rmat);
+ }
+ else {
+ EulToMat3(ob->rot, rmat);
+ }
+ }
+ Mat3MulMat3(mat, rmat, smat);
+}
+
+void object_to_mat4(Object *ob, float mat[][4])
+{
+ float tmat[3][3];
+
+ object_to_mat3(ob, tmat);
+
+ Mat4CpyMat3(mat, tmat);
+
+ VECCOPY(mat[3], ob->loc);
+ if(ob->ipo) {
+ mat[3][0]+= ob->dloc[0];
+ mat[3][1]+= ob->dloc[1];
+ mat[3][2]+= ob->dloc[2];
+ }
+}
+
+int enable_cu_speed= 1;
+
+static void ob_parcurve(Object *ob, Object *par, float mat[][4])
+{
+ Curve *cu;
+ float q[4], vec[4], dir[3], *quat, x1, ctime;
+ float timeoffs= 0.0;
+
+ Mat4One(mat);
+
+ cu= par->data;
+ if(cu->path==NULL || cu->path->data==NULL) /* only happens on reload file, but violates depsgraph still... fix! */
+ makeDispListCurveTypes(par, 0);
+ if(cu->path==NULL) return;
+
+ /* exception, timeoffset is regarded as distance offset */
+ if(cu->flag & CU_OFFS_PATHDIST) {
+ SWAP(float, timeoffs, ob->sf);
+ }
+
+ /* catch exceptions: feature for nla stride editing */
+ if(ob->ipoflag & OB_DISABLE_PATH) {
+ ctime= 0.0f;
+ }
+ /* catch exceptions: curve paths used as a duplicator */
+ else if(enable_cu_speed) {
+ ctime= bsystem_time(ob, (float)G.scene->r.cfra, 0.0);
+
+ if(calc_ipo_spec(cu->ipo, CU_SPEED, &ctime)==0) {
+ ctime /= cu->pathlen;
+ CLAMP(ctime, 0.0, 1.0);
+ }
+ }
+ else {
+ ctime= G.scene->r.cfra - ob->sf;
+ ctime /= cu->pathlen;
+
+ CLAMP(ctime, 0.0, 1.0);
+ }
+
+ /* time calculus is correct, now apply distance offset */
+ if(cu->flag & CU_OFFS_PATHDIST) {
+ ctime += timeoffs/cu->path->totdist;
+
+ /* restore */
+ SWAP(float, timeoffs, ob->sf);
+ }
+
+
+ /* vec: 4 items! */
+ if( where_on_path(par, ctime, vec, dir) ) {
+
+ if(cu->flag & CU_FOLLOW) {
+ quat= vectoquat(dir, ob->trackflag, ob->upflag);
+
+ /* the tilt */
+ Normalize(dir);
+ q[0]= (float)cos(0.5*vec[3]);
+ x1= (float)sin(0.5*vec[3]);
+ q[1]= -x1*dir[0];
+ q[2]= -x1*dir[1];
+ q[3]= -x1*dir[2];
+ QuatMul(quat, q, quat);
+
+ QuatToMat4(quat, mat);
+ }
+
+ VECCOPY(mat[3], vec);
+
+ }
+}
+
+static void ob_parbone(Object *ob, Object *par, float mat[][4])
+{
+ bPoseChannel *pchan;
+ bArmature *arm;
+ float vec[3];
+
+ arm=get_armature(par);
+ if (!arm) {
+ Mat4One(mat);
+ return;
+ }
+
+ /* Make sure the bone is still valid */
+ pchan= get_pose_channel(par->pose, ob->parsubstr);
+ if (!pchan){
+ printf ("Object %s with Bone parent: bone %s doesn't exist\n", ob->id.name+2, ob->parsubstr);
+ Mat4One(mat);
+ return;
+ }
+
+ /* get bone transform */
+ Mat4CpyMat4(mat, pchan->pose_mat);
+
+ /* but for backwards compatibility, the child has to move to the tail */
+ VECCOPY(vec, mat[1]);
+ VecMulf(vec, pchan->bone->length);
+ VecAddf(mat[3], mat[3], vec);
+}
+
+static void give_parvert(Object *par, int nr, float *vec)
+{
+ int a, count;
+
+ vec[0]=vec[1]=vec[2]= 0.0f;
+
+ if(par->type==OB_MESH) {
+ if(G.obedit && (par->data==G.obedit->data)) {
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+
+ for(eve= em->verts.first; eve; eve= eve->next) {
+ if(eve->keyindex==nr) {
+ memcpy(vec, eve->co, 12);
+ break;
+ }
+ }
+ }
+ else {
+ DerivedMesh *dm = par->derivedFinal;
+
+ if(dm) {
+ int i, count = 0, numVerts = dm->getNumVerts(dm);
+ int *index = (int *)dm->getVertDataArray(dm, CD_ORIGINDEX);
+ float co[3];
+
+ /* get the average of all verts with (original index == nr) */
+ for(i = 0; i < numVerts; ++i, ++index) {
+ if(*index == nr) {
+ dm->getVertCo(dm, i, co);
+ VecAddf(vec, vec, co);
+ count++;
+ }
+ }
+
+ if(count > 0) {
+ VecMulf(vec, 1.0f / count);
+ } else {
+ dm->getVertCo(dm, 0, vec);
+ }
+ }
+ }
+ }
+ else if ELEM(par->type, OB_CURVE, OB_SURF) {
+ Nurb *nu;
+ Curve *cu;
+ BPoint *bp;
+ BezTriple *bezt;
+
+ cu= par->data;
+ nu= cu->nurb.first;
+ if(par==G.obedit) nu= editNurb.first;
+
+ count= 0;
+ while(nu) {
+ if((nu->type & 7)==CU_BEZIER) {
+ bezt= nu->bezt;
+ a= nu->pntsu;
+ while(a--) {
+ if(count==nr) {
+ VECCOPY(vec, bezt->vec[1]);
+ break;
+ }
+ count++;
+ bezt++;
+ }
+ }
+ else {
+ bp= nu->bp;
+ a= nu->pntsu*nu->pntsv;
+ while(a--) {
+ if(count==nr) {
+ memcpy(vec, bp->vec, 12);
+ break;
+ }
+ count++;
+ bp++;
+ }
+ }
+ nu= nu->next;
+ }
+
+ }
+ else if(par->type==OB_LATTICE) {
+ Lattice *latt= par->data;
+ BPoint *bp;
+ DispList *dl = find_displist(&par->disp, DL_VERTS);
+ float *co = dl?dl->verts:NULL;
+
+ if(par==G.obedit) latt= editLatt;
+
+ a= latt->pntsu*latt->pntsv*latt->pntsw;
+ count= 0;
+ bp= latt->def;
+ while(a--) {
+ if(count==nr) {
+ if(co)
+ memcpy(vec, co, 3*sizeof(float));
+ else
+ memcpy(vec, bp->vec, 3*sizeof(float));
+ break;
+ }
+ count++;
+ if(co) co+= 3;
+ else bp++;
+ }
+ }
+}
+
+static void ob_parvert3(Object *ob, Object *par, float mat[][4])
+{
+ float cmat[3][3], v1[3], v2[3], v3[3], q[4];
+
+ /* in local ob space */
+ Mat4One(mat);
+
+ if ELEM4(par->type, OB_MESH, OB_SURF, OB_CURVE, OB_LATTICE) {
+
+ give_parvert(par, ob->par1, v1);
+ give_parvert(par, ob->par2, v2);
+ give_parvert(par, ob->par3, v3);
+
+ triatoquat(v1, v2, v3, q);
+ QuatToMat3(q, cmat);
+ Mat4CpyMat3(mat, cmat);
+
+ if(ob->type==OB_CURVE) {
+ VECCOPY(mat[3], v1);
+ }
+ else {
+ VecAddf(mat[3], v1, v2);
+ VecAddf(mat[3], mat[3], v3);
+ VecMulf(mat[3], 0.3333333f);
+ }
+ }
+}
+
+static int no_parent_ipo=0;
+void set_no_parent_ipo(int val)
+{
+ no_parent_ipo= val;
+}
+
+static int during_script_flag=0;
+void disable_where_script(short on)
+{
+ during_script_flag= on;
+}
+
+int during_script(void) {
+ return during_script_flag;
+}
+
+static int during_scriptlink_flag=0;
+void disable_where_scriptlink(short on)
+{
+ during_scriptlink_flag= on;
+}
+
+int during_scriptlink(void) {
+ return during_scriptlink_flag;
+}
+
+void where_is_object_time(Object *ob, float ctime)
+{
+ float *fp1, *fp2, slowmat[4][4] = MAT4_UNITY;
+ float stime, fac1, fac2, vec[3];
+ int a;
+ int pop;
+
+ /* new version: correct parent+vertexparent and track+parent */
+ /* this one only calculates direct attached parent and track */
+ /* is faster, but should keep track of timeoffs */
+
+ if(ob==NULL) return;
+
+ /* this is needed to be able to grab objects with ipos, otherwise it always freezes them */
+ stime= bsystem_time(ob, ctime, 0.0);
+ if(stime != ob->ctime) {
+
+ ob->ctime= stime;
+
+ if(ob->ipo) {
+ calc_ipo(ob->ipo, stime);
+ execute_ipo((ID *)ob, ob->ipo);
+ }
+ else
+ do_all_object_actions(ob);
+
+ /* do constraint ipos ..., note it needs stime (0 = all ipos) */
+ do_constraint_channels(&ob->constraints, &ob->constraintChannels, stime, 0);
+ }
+ else {
+ /* but, the drivers have to be done */
+ if(ob->ipo) do_ob_ipodrivers(ob, ob->ipo, stime);
+ /* do constraint ipos ..., note it needs stime (1 = only drivers ipos) */
+ do_constraint_channels(&ob->constraints, &ob->constraintChannels, stime, 1);
+ }
+
+ if(ob->parent) {
+ Object *par= ob->parent;
+
+ if(ob->ipoflag & OB_OFFS_PARENT) ctime-= ob->sf;
+
+ /* hurms, code below conflicts with depgraph... (ton) */
+ /* and even worse, it gives bad effects for NLA stride too (try ctime != par->ctime, with MBlur) */
+ pop= 0;
+ if(no_parent_ipo==0 && stime != par->ctime) {
+
+ // only for ipo systems?
+ pushdata(par, sizeof(Object));
+ pop= 1;
+
+ if(par->proxy_from); // was a copied matrix, no where_is! bad...
+ else where_is_object_time(par, ctime);
+ }
+
+ solve_parenting(ob, par, ob->obmat, slowmat, 0);
+
+ if(pop) {
+ poplast(par);
+ }
+
+ if(ob->partype & PARSLOW) {
+ // include framerate
+
+ fac1= (1.0f/(1.0f+ fabs(ob->sf)));
+ if(fac1>=1.0) return;
+ fac2= 1.0f-fac1;
+
+ fp1= ob->obmat[0];
+ fp2= slowmat[0];
+ for(a=0; a<16; a++, fp1++, fp2++) {
+ fp1[0]= fac1*fp1[0] + fac2*fp2[0];
+ }
+ }
+
+ }
+ else {
+ object_to_mat4(ob, ob->obmat);
+ }
+
+ /* Handle tracking */
+ if(ob->track) {
+ if( ctime != ob->track->ctime) where_is_object_time(ob->track, ctime);
+ solve_tracking (ob, ob->track->obmat);
+
+ }
+
+ /* solve constraints */
+ if (ob->constraints.first) {
+ bConstraintOb *cob;
+
+ cob= constraints_make_evalob(ob, NULL, CONSTRAINT_OBTYPE_OBJECT);
+
+ /* constraints need ctime, not stime. Some call where_is_object_time and bsystem_time */
+ solve_constraints (&ob->constraints, cob, ctime);
+
+ constraints_clear_evalob(cob);
+ }
+
+ if(ob->scriptlink.totscript && !during_script()) {
+ if (G.f & G_DOSCRIPTLINKS) BPY_do_pyscript((ID *)ob, SCRIPT_REDRAW);
+ }
+
+ /* set negative scale flag in object */
+ Crossf(vec, ob->obmat[0], ob->obmat[1]);
+ if( Inpf(vec, ob->obmat[2]) < 0.0 ) ob->transflag |= OB_NEG_SCALE;
+ else ob->transflag &= ~OB_NEG_SCALE;
+}
+
+static void solve_parenting (Object *ob, Object *par, float obmat[][4], float slowmat[][4], int simul)
+{
+ float totmat[4][4];
+ float tmat[4][4];
+ float locmat[4][4];
+ float vec[3];
+ int ok;
+
+ object_to_mat4(ob, locmat);
+
+ if(ob->partype & PARSLOW) Mat4CpyMat4(slowmat, obmat);
+
+
+ switch(ob->partype & PARTYPE) {
+ case PAROBJECT:
+ ok= 0;
+ if(par->type==OB_CURVE) {
+ if( ((Curve *)par->data)->flag & CU_PATH ) {
+ ob_parcurve(ob, par, tmat);
+ ok= 1;
+ }
+ }
+
+ if(ok) Mat4MulSerie(totmat, par->obmat, tmat,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+ else Mat4CpyMat4(totmat, par->obmat);
+
+ break;
+ case PARBONE:
+ ob_parbone(ob, par, tmat);
+ Mat4MulSerie(totmat, par->obmat, tmat,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+ break;
+
+ case PARVERT1:
+ Mat4One(totmat);
+ if (simul){
+ VECCOPY(totmat[3], par->obmat[3]);
+ }
+ else{
+ give_parvert(par, ob->par1, vec);
+ VecMat4MulVecfl(totmat[3], par->obmat, vec);
+ }
+ break;
+ case PARVERT3:
+ ob_parvert3(ob, par, tmat);
+
+ Mat4MulSerie(totmat, par->obmat, tmat,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+ break;
+
+ case PARSKEL:
+ Mat4CpyMat4(totmat, par->obmat);
+ break;
+ }
+
+ // total
+ Mat4MulSerie(tmat, totmat, ob->parentinv,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+ Mat4MulSerie(obmat, tmat, locmat,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+
+ if (simul) {
+
+ }
+ else{
+ // external usable originmat
+ Mat3CpyMat4(originmat, tmat);
+
+ // origin, voor help line
+ if( (ob->partype & 15)==PARSKEL ) {
+ VECCOPY(ob->orig, par->obmat[3]);
+ }
+ else {
+ VECCOPY(ob->orig, totmat[3]);
+ }
+ }
+
+}
+void solve_tracking (Object *ob, float targetmat[][4])
+{
+ float *quat;
+ float vec[3];
+ float totmat[3][3];
+ float tmat[4][4];
+
+ VecSubf(vec, ob->obmat[3], targetmat[3]);
+ quat= vectoquat(vec, ob->trackflag, ob->upflag);
+ QuatToMat3(quat, totmat);
+
+ if(ob->parent && (ob->transflag & OB_POWERTRACK)) {
+ /* 'temporal' : clear parent info */
+ object_to_mat4(ob, tmat);
+ tmat[0][3]= ob->obmat[0][3];
+ tmat[1][3]= ob->obmat[1][3];
+ tmat[2][3]= ob->obmat[2][3];
+ tmat[3][0]= ob->obmat[3][0];
+ tmat[3][1]= ob->obmat[3][1];
+ tmat[3][2]= ob->obmat[3][2];
+ tmat[3][3]= ob->obmat[3][3];
+ }
+ else Mat4CpyMat4(tmat, ob->obmat);
+
+ Mat4MulMat34(ob->obmat, totmat, tmat);
+
+}
+
+void where_is_object(Object *ob)
+{
+ where_is_object_time(ob, (float)G.scene->r.cfra);
+}
+
+
+void where_is_object_simul(Object *ob)
+/* was written for the old game engine (until 2.04) */
+/* It seems that this function is only called
+for a lamp that is the child of another object */
+{
+ Object *par;
+ Ipo *ipo;
+ float *fp1, *fp2;
+ float slowmat[4][4];
+ float fac1, fac2;
+ int a;
+
+ /* NO TIMEOFFS */
+
+ /* no ipo! (because of dloc and realtime-ipos) */
+ ipo= ob->ipo;
+ ob->ipo= NULL;
+
+ if(ob->parent) {
+ par= ob->parent;
+
+ solve_parenting(ob, par, ob->obmat, slowmat, 1);
+
+ if(ob->partype & PARSLOW) {
+
+ fac1= (float)(1.0/(1.0+ fabs(ob->sf)));
+ fac2= 1.0f-fac1;
+ fp1= ob->obmat[0];
+ fp2= slowmat[0];
+ for(a=0; a<16; a++, fp1++, fp2++) {
+ fp1[0]= fac1*fp1[0] + fac2*fp2[0];
+ }
+ }
+
+ }
+ else {
+ object_to_mat4(ob, ob->obmat);
+ }
+
+ if(ob->track)
+ solve_tracking(ob, ob->track->obmat);
+
+ /* solve constraints */
+ if (ob->constraints.first) {
+ bConstraintOb *cob;
+
+ cob= constraints_make_evalob(ob, NULL, CONSTRAINT_OBTYPE_OBJECT);
+ solve_constraints (&ob->constraints, cob, G.scene->r.cfra);
+ constraints_clear_evalob(cob);
+ }
+
+ /* WATCH IT!!! */
+ ob->ipo= ipo;
+}
+
+/* for calculation of the inverse parent transform, only used for editor */
+void what_does_parent(Object *ob)
+{
+ clear_workob();
+ Mat4One(workob.obmat);
+ Mat4One(workob.parentinv);
+ Mat4One(workob.constinv);
+ workob.parent= ob->parent;
+ workob.track= ob->track;
+
+ workob.trackflag= ob->trackflag;
+ workob.upflag= ob->upflag;
+
+ workob.partype= ob->partype;
+ workob.par1= ob->par1;
+ workob.par2= ob->par2;
+ workob.par3= ob->par3;
+
+ workob.constraints.first = ob->constraints.first;
+ workob.constraints.last = ob->constraints.last;
+
+ strcpy(workob.parsubstr, ob->parsubstr);
+
+ where_is_object(&workob);
+}
+
+BoundBox *unit_boundbox()
+{
+ BoundBox *bb;
+ float min[3] = {-1,-1,-1}, max[3] = {-1,-1,-1};
+
+ bb= MEM_mallocN(sizeof(BoundBox), "bb");
+ boundbox_set_from_min_max(bb, min, max);
+
+ return bb;
+}
+
+void boundbox_set_from_min_max(BoundBox *bb, float min[3], float max[3])
+{
+ bb->vec[0][0]=bb->vec[1][0]=bb->vec[2][0]=bb->vec[3][0]= min[0];
+ bb->vec[4][0]=bb->vec[5][0]=bb->vec[6][0]=bb->vec[7][0]= max[0];
+
+ bb->vec[0][1]=bb->vec[1][1]=bb->vec[4][1]=bb->vec[5][1]= min[1];
+ bb->vec[2][1]=bb->vec[3][1]=bb->vec[6][1]=bb->vec[7][1]= max[1];
+
+ bb->vec[0][2]=bb->vec[3][2]=bb->vec[4][2]=bb->vec[7][2]= min[2];
+ bb->vec[1][2]=bb->vec[2][2]=bb->vec[5][2]=bb->vec[6][2]= max[2];
+}
+
+BoundBox *object_get_boundbox(Object *ob)
+{
+ BoundBox *bb= NULL;
+
+ if(ob->type==OB_MESH) {
+ bb = mesh_get_bb(ob->data);
+ }
+ else if ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT) {
+ bb= ( (Curve *)ob->data )->bb;
+ }
+ else if(ob->type==OB_MBALL) {
+ bb= ob->bb;
+ }
+ return bb;
+}
+
+/* used to temporally disable/enable boundbox */
+void object_boundbox_flag(Object *ob, int flag, int set)
+{
+ BoundBox *bb= object_get_boundbox(ob);
+ if(bb) {
+ if(set) bb->flag |= flag;
+ else bb->flag &= ~flag;
+ }
+}
+
+void minmax_object(Object *ob, float *min, float *max)
+{
+ BoundBox bb;
+ Mesh *me;
+ Curve *cu;
+ float vec[3];
+ int a;
+
+ switch(ob->type) {
+
+ case OB_CURVE:
+ case OB_FONT:
+ case OB_SURF:
+ cu= ob->data;
+
+ if(cu->bb==NULL) tex_space_curve(cu);
+ bb= *(cu->bb);
+
+ for(a=0; a<8; a++) {
+ Mat4MulVecfl(ob->obmat, bb.vec[a]);
+ DO_MINMAX(bb.vec[a], min, max);
+ }
+ break;
+ case OB_ARMATURE:
+ if(ob->pose) {
+ bPoseChannel *pchan;
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ VECCOPY(vec, pchan->pose_head);
+ Mat4MulVecfl(ob->obmat, vec);
+ DO_MINMAX(vec, min, max);
+ VECCOPY(vec, pchan->pose_tail);
+ Mat4MulVecfl(ob->obmat, vec);
+ DO_MINMAX(vec, min, max);
+ }
+ break;
+ }
+ /* no break, get_mesh will give NULL and it passes on to default */
+ case OB_MESH:
+ me= get_mesh(ob);
+
+ if(me) {
+ bb = *mesh_get_bb(me);
+
+ for(a=0; a<8; a++) {
+ Mat4MulVecfl(ob->obmat, bb.vec[a]);
+ DO_MINMAX(bb.vec[a], min, max);
+ }
+ }
+ if(min[0] < max[0] ) break;
+
+ /* else here no break!!!, mesh can be zero sized */
+
+ default:
+ DO_MINMAX(ob->obmat[3], min, max);
+
+ VECCOPY(vec, ob->obmat[3]);
+ VecAddf(vec, vec, ob->size);
+ DO_MINMAX(vec, min, max);
+
+ VECCOPY(vec, ob->obmat[3]);
+ VecSubf(vec, vec, ob->size);
+ DO_MINMAX(vec, min, max);
+ break;
+ }
+}
+
+/* TODO - use dupli objects bounding boxes */
+void minmax_object_duplis(Object *ob, float *min, float *max)
+{
+ if ((ob->transflag & OB_DUPLI)==0) {
+ return;
+ } else {
+ ListBase *lb;
+ DupliObject *dob;
+
+ lb= object_duplilist(G.scene, ob);
+ for(dob= lb->first; dob; dob= dob->next) {
+ if(dob->no_draw);
+ else {
+ /* should really use bound box of dup object */
+ DO_MINMAX(dob->mat[3], min, max);
+ }
+ }
+ free_object_duplilist(lb); /* does restore */
+ }
+}
+
+
+/* proxy rule: lib_object->proxy_from == the one we borrow from, only set temporal and cleared here */
+/* local_object->proxy == pointer to library object, saved in files and read */
+
+/* function below is polluted with proxy exceptions, cleanup will follow! */
+
+/* the main object update call, for object matrix, constraints, keys and displist (modifiers) */
+/* requires flags to be set! */
+void object_handle_update(Object *ob)
+{
+ if(ob->recalc & OB_RECALC) {
+
+ if(ob->recalc & OB_RECALC_OB) {
+
+ // printf("recalcob %s\n", ob->id.name+2);
+
+ /* handle proxy copy for target */
+ if(ob->id.lib && ob->proxy_from) {
+ // printf("ob proxy copy, lib ob %s proxy %s\n", ob->id.name, ob->proxy_from->id.name);
+ if(ob->proxy_from->proxy_group) {/* transform proxy into group space */
+ Object *obg= ob->proxy_from->proxy_group;
+ Mat4Invert(obg->imat, obg->obmat);
+ Mat4MulMat4(ob->obmat, ob->proxy_from->obmat, obg->imat);
+ }
+ else
+ Mat4CpyMat4(ob->obmat, ob->proxy_from->obmat);
+ }
+ else
+ where_is_object(ob);
+ }
+
+ if(ob->recalc & OB_RECALC_DATA) {
+
+ // printf("recalcdata %s\n", ob->id.name+2);
+
+ /* includes all keys and modifiers */
+ if(ob->type==OB_MESH) {
+ makeDerivedMesh(ob, get_viewedit_datamask());
+ }
+ else if(ob->type==OB_MBALL) {
+ makeDispListMBall(ob);
+ }
+ else if(ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
+ makeDispListCurveTypes(ob, 0);
+ }
+ else if(ob->type==OB_LATTICE) {
+ lattice_calc_modifiers(ob);
+ }
+ else if(ob->type==OB_ARMATURE) {
+ /* this happens for reading old files and to match library armatures with poses */
+ if(ob->pose==NULL || (ob->pose->flag & POSE_RECALC))
+ armature_rebuild_pose(ob, ob->data);
+
+ if(ob->id.lib && ob->proxy_from) {
+ copy_pose_result(ob->pose, ob->proxy_from->pose);
+ // printf("pose proxy copy, lib ob %s proxy %s\n", ob->id.name, ob->proxy_from->id.name);
+ }
+ else {
+ do_all_pose_actions(ob);
+ where_is_pose(ob);
+ }
+ }
+ }
+
+ /* the no-group proxy case, we call update */
+ if(ob->proxy && ob->proxy_group==NULL) {
+ /* set pointer in library proxy target, for copying, but restore it */
+ ob->proxy->proxy_from= ob;
+ // printf("call update, lib ob %s proxy %s\n", ob->proxy->id.name, ob->id.name);
+ object_handle_update(ob->proxy);
+ }
+
+ ob->recalc &= ~OB_RECALC;
+ }
+
+ /* the case when this is a group proxy, object_update is called in group.c */
+ if(ob->proxy) {
+ ob->proxy->proxy_from= ob;
+ // printf("set proxy pointer for later group stuff %s\n", ob->id.name);
+ }
+}
diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c
new file mode 100644
index 00000000000..bd33fafe23c
--- /dev/null
+++ b/source/blender/blenkernel/intern/packedFile.c
@@ -0,0 +1,614 @@
+/**
+ * blenkernel/packedFile.c - (cleaned up mar-01 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef WIN32
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+#include <string.h>
+#include "MEM_guardedalloc.h"
+
+#include "DNA_image_types.h"
+#include "DNA_sound_types.h"
+#include "DNA_vfont_types.h"
+#include "DNA_packedFile_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_blenlib.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_screen.h"
+#include "BKE_sound.h"
+#include "BKE_image.h"
+#include "BKE_font.h"
+#include "BKE_packedFile.h"
+#include "BKE_bad_level_calls.h" /* <- waitcursor */
+
+int seekPackedFile(PackedFile * pf, int offset, int whence)
+{
+ int oldseek = -1, seek = 0;
+
+ if (pf) {
+ oldseek = pf->seek;
+ switch(whence) {
+ case SEEK_CUR:
+ seek = oldseek + offset;
+ break;
+ case SEEK_END:
+ seek = pf->size + offset;
+ break;
+ case SEEK_SET:
+ seek = offset;
+ break;
+ default:
+ oldseek = -1;
+ }
+ if (seek < 0) {
+ seek = 0;
+ } else if (seek > pf->size) {
+ seek = pf->size;
+ }
+ pf->seek = seek;
+ }
+
+ return(oldseek);
+}
+
+void rewindPackedFile(PackedFile * pf)
+{
+ seekPackedFile(pf, 0, SEEK_SET);
+}
+
+int readPackedFile(PackedFile * pf, void * data, int size)
+{
+ if ((pf != NULL) && (size >= 0) && (data != NULL)) {
+ if (size + pf->seek > pf->size) {
+ size = pf->size - pf->seek;
+ }
+
+ if (size > 0) {
+ memcpy(data, ((char *) pf->data) + pf->seek, size);
+ } else {
+ size = 0;
+ }
+
+ pf->seek += size;
+ } else {
+ size = -1;
+ }
+
+ return(size);
+}
+
+int countPackedFiles()
+{
+ int count = 0;
+ Image *ima;
+ VFont *vf;
+ bSample *sample;
+
+ // let's check if there are packed files...
+ ima = G.main->image.first;
+ while (ima) {
+ if (ima->packedfile) {
+ count++;
+ }
+ ima= ima->id.next;
+ }
+
+ vf = G.main->vfont.first;
+ while (vf) {
+ if (vf->packedfile) {
+ count++;
+ }
+ vf = vf->id.next;
+ }
+
+ sample = samples->first;
+ while (sample) {
+ if (sample->packedfile) {
+ count++;
+ }
+ sample = sample->id.next;
+ }
+
+ return(count);
+}
+
+void freePackedFile(PackedFile * pf)
+{
+ if (pf) {
+ MEM_freeN(pf->data);
+ MEM_freeN(pf);
+ } else {
+ printf("freePackedFile: Trying to free a NULL pointer\n");
+ }
+}
+
+PackedFile * newPackedFileMemory(void *mem, int memlen)
+{
+ PackedFile * pf = MEM_callocN(sizeof(*pf), "PackedFile");
+ pf->data = mem;
+ pf->size = memlen;
+
+ return pf;
+}
+
+PackedFile * newPackedFile(char * filename)
+{
+ PackedFile * pf = NULL;
+ int file, filelen;
+ char name[FILE_MAXDIR+FILE_MAXFILE];
+ void * data;
+
+ waitcursor(1);
+
+ // convert relative filenames to absolute filenames
+
+ strcpy(name, filename);
+ BLI_convertstringcode(name, G.sce, G.scene->r.cfra);
+
+ // open the file
+ // and create a PackedFile structure
+
+ file= open(name, O_BINARY|O_RDONLY);
+ if (file <= 0) {
+ // error("Can't open file: %s", name);
+ } else {
+ filelen = BLI_filesize(file);
+
+ if (filelen == 0) {
+ // MEM_mallocN complains about MEM_mallocN(0, "bla");
+ // we don't care....
+ data = MEM_mallocN(1, "packFile");
+ } else {
+ data = MEM_mallocN(filelen, "packFile");
+ }
+ if (read(file, data, filelen) == filelen) {
+ pf = newPackedFileMemory(data, filelen);
+ }
+
+ close(file);
+ }
+
+ waitcursor(0);
+
+ return (pf);
+}
+
+void packAll()
+{
+ Image *ima;
+ VFont *vf;
+ bSample *sample;
+
+ ima = G.main->image.first;
+ while (ima) {
+ if (ima->packedfile == NULL) {
+ ima->packedfile = newPackedFile(ima->name);
+ }
+ ima= ima->id.next;
+ }
+
+ vf = G.main->vfont.first;
+ while (vf) {
+ if (vf->packedfile == NULL) {
+ vf->packedfile = newPackedFile(vf->name);
+ }
+ vf = vf->id.next;
+ }
+
+
+ sample = samples->first;
+ while (sample) {
+ if (sample->packedfile == NULL) {
+ sound_set_packedfile(sample, newPackedFile(sample->name));
+ }
+ sample = sample->id.next;
+ }
+}
+
+
+/*
+
+// attempt to create a function that generates an unique filename
+// this will work when all funtions in fileops.c understand relative filenames...
+
+char * find_new_name(char * name)
+{
+ char tempname[FILE_MAXDIR + FILE_MAXFILE];
+ char * newname;
+
+ if (fop_exists(name)) {
+ for (number = 1; number <= 999; number++) {
+ sprintf(tempname, "%s.%03d", name, number);
+ if (! fop_exists(tempname)) {
+ break;
+ }
+ }
+ }
+
+ newname = mallocN(strlen(tempname) + 1, "find_new_name");
+ strcpy(newname, tempname);
+
+ return(newname);
+}
+
+*/
+
+int writePackedFile(char * filename, PackedFile *pf, int guimode)
+{
+ int file, number, remove_tmp = FALSE;
+ int ret_value = RET_OK;
+ char name[FILE_MAXDIR + FILE_MAXFILE];
+ char tempname[FILE_MAXDIR + FILE_MAXFILE];
+/* void * data; */
+
+ if (guimode) waitcursor(1);
+
+ strcpy(name, filename);
+ BLI_convertstringcode(name, G.sce, G.scene->r.cfra);
+
+ if (BLI_exists(name)) {
+ for (number = 1; number <= 999; number++) {
+ sprintf(tempname, "%s.%03d_", name, number);
+ if (! BLI_exists(tempname)) {
+ if (BLI_copy_fileops(name, tempname) == RET_OK) {
+ remove_tmp = TRUE;
+ }
+ break;
+ }
+ }
+ }
+
+ // make sure the path to the file exists...
+ BLI_make_existing_file(name);
+
+ file = open(name, O_BINARY + O_WRONLY + O_CREAT + O_TRUNC, 0666);
+ if (file >= 0) {
+ if (write(file, pf->data, pf->size) != pf->size) {
+ if(guimode) error("Error writing file: %s", name);
+ ret_value = RET_ERROR;
+ }
+ close(file);
+ } else {
+ if(guimode) error("Error creating file: %s", name);
+ ret_value = RET_ERROR;
+ }
+
+ if (remove_tmp) {
+ if (ret_value == RET_ERROR) {
+ if (BLI_rename(tempname, name) == RET_ERROR) {
+ if(guimode) error("Error restoring tempfile. Check files: '%s' '%s'", tempname, name);
+ }
+ } else {
+ if (BLI_delete(tempname, 0, 0) == RET_ERROR) {
+ if(guimode) error("Error deleting '%s' (ignored)");
+ }
+ }
+ }
+
+ if(guimode) waitcursor(0);
+
+ return (ret_value);
+}
+
+/*
+
+This function compares a packed file to a 'real' file.
+It returns an integer indicating if:
+
+PF_EQUAL - the packed file and original file are identical
+PF_DIFFERENT - the packed file and original file differ
+PF_NOFILE - the original file doens't exist
+
+*/
+
+int checkPackedFile(char * filename, PackedFile * pf)
+{
+ struct stat st;
+ int ret_val, i, len, file;
+ char buf[4096];
+ char name[FILE_MAXDIR + FILE_MAXFILE];
+
+ strcpy(name, filename);
+ BLI_convertstringcode(name, G.sce, G.scene->r.cfra);
+
+ if (stat(name, &st)) {
+ ret_val = PF_NOFILE;
+ } else if (st.st_size != pf->size) {
+ ret_val = PF_DIFFERS;
+ } else {
+ // we'll have to compare the two...
+
+ file = open(name, O_BINARY | O_RDONLY);
+ if (file < 0) {
+ ret_val = PF_NOFILE;
+ } else {
+ ret_val = PF_EQUAL;
+
+ for (i = 0; i < pf->size; i += sizeof(buf)) {
+ len = pf->size - i;
+ if (len > sizeof(buf)) {
+ len = sizeof(buf);
+ }
+
+ if (read(file, buf, len) != len) {
+ // read error ...
+ ret_val = PF_DIFFERS;
+ break;
+ } else {
+ if (memcmp(buf, ((char *)pf->data) + i, len)) {
+ ret_val = PF_DIFFERS;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return(ret_val);
+}
+
+/*
+
+unpackFile() looks at the existing files (abs_name, local_name) and a packed file.
+If how == PF_ASK it offers the user a couple of options what to do with the packed file.
+
+It returns a char * to the existing file name / new file name or NULL when
+there was an error or when the user desides to cancel the operation.
+
+*/
+
+char *unpackFile(char * abs_name, char * local_name, PackedFile * pf, int how)
+{
+ char menu[6 * (FILE_MAXDIR + FILE_MAXFILE + 100)];
+ char line[FILE_MAXDIR + FILE_MAXFILE + 100];
+ char * newname = NULL, * temp = NULL;
+
+ // char newabs[FILE_MAXDIR + FILE_MAXFILE];
+ // char newlocal[FILE_MAXDIR + FILE_MAXFILE];
+
+ if (pf != NULL) {
+ if (how == PF_ASK) {
+ sprintf(menu, "UnPack file%%t|Remove Pack %%x%d", PF_REMOVE);
+
+ if (strcmp(abs_name, local_name)) {
+ switch (checkPackedFile(local_name, pf)) {
+ case PF_NOFILE:
+ sprintf(line, "|Create %s%%x%d", local_name, PF_WRITE_LOCAL);
+ strcat(menu, line);
+ break;
+ case PF_EQUAL:
+ sprintf(line, "|Use %s (identical)%%x%d", local_name, PF_USE_LOCAL);
+ strcat(menu, line);
+ break;
+ case PF_DIFFERS:
+ sprintf(line, "|Use %s (differs)%%x%d", local_name, PF_USE_LOCAL);
+ strcat(menu, line);
+ sprintf(line, "|Overwrite %s%%x%d", local_name, PF_WRITE_LOCAL);
+ strcat(menu, line);
+ break;
+ }
+ // sprintf(line, "|%%x%d", PF_INVALID);
+ // strcat(menu, line);
+ }
+
+ switch (checkPackedFile(abs_name, pf)) {
+ case PF_NOFILE:
+ sprintf(line, "|Create %s%%x%d", abs_name, PF_WRITE_ORIGINAL);
+ strcat(menu, line);
+ break;
+ case PF_EQUAL:
+ sprintf(line, "|Use %s (identical)%%x%d", abs_name, PF_USE_ORIGINAL);
+ strcat(menu, line);
+ break;
+ case PF_DIFFERS:
+ sprintf(line, "|Use %s (differs)%%x%d", abs_name, PF_USE_ORIGINAL);
+ strcat(menu, line);
+ sprintf(line, "|Overwrite %s%%x%d", abs_name, PF_WRITE_ORIGINAL);
+ strcat(menu, line);
+ break;
+ }
+
+ how = pupmenu(menu);
+ }
+
+ switch (how) {
+ case -1:
+ case PF_KEEP:
+ break;
+ case PF_REMOVE:
+ temp= abs_name;
+ break;
+ case PF_USE_LOCAL:
+ // if file exists use it
+ if (BLI_exists(local_name)) {
+ temp = local_name;
+ break;
+ }
+ // else fall through and create it
+ case PF_WRITE_LOCAL:
+ if (writePackedFile(local_name, pf, 1) == RET_OK) {
+ temp = local_name;
+ }
+ break;
+ case PF_USE_ORIGINAL:
+ // if file exists use it
+ if (BLI_exists(abs_name)) {
+ temp = abs_name;
+ break;
+ }
+ // else fall through and create it
+ case PF_WRITE_ORIGINAL:
+ if (writePackedFile(abs_name, pf, 1) == RET_OK) {
+ temp = abs_name;
+ }
+ break;
+ default:
+ printf("unpackFile: unknown return_value %d\n", how);
+ break;
+ }
+
+ if (temp) {
+ newname = MEM_mallocN(strlen(temp) + 1, "unpack_file newname");
+ strcpy(newname, temp);
+ }
+ }
+
+ return (newname);
+}
+
+
+int unpackVFont(VFont * vfont, int how)
+{
+ char localname[FILE_MAXDIR + FILE_MAXFILE], fi[FILE_MAXFILE];
+ char * newname;
+ int ret_value = RET_ERROR;
+
+ if (vfont != NULL) {
+ strcpy(localname, vfont->name);
+ BLI_splitdirstring(localname, fi);
+
+ sprintf(localname, "//fonts/%s", fi);
+
+ newname = unpackFile(vfont->name, localname, vfont->packedfile, how);
+ if (newname != NULL) {
+ ret_value = RET_OK;
+ freePackedFile(vfont->packedfile);
+ vfont->packedfile = 0;
+ strcpy(vfont->name, newname);
+ MEM_freeN(newname);
+ }
+ }
+
+ return (ret_value);
+}
+
+int unpackSample(bSample *sample, int how)
+{
+ char localname[FILE_MAXDIR + FILE_MAX], fi[FILE_MAX];
+ char * newname;
+ int ret_value = RET_ERROR;
+ PackedFile *pf;
+
+ if (sample != NULL) {
+ strcpy(localname, sample->name);
+ BLI_splitdirstring(localname, fi);
+ sprintf(localname, "//samples/%s", fi);
+
+ newname = unpackFile(sample->name, localname, sample->packedfile, how);
+ if (newname != NULL) {
+ strcpy(sample->name, newname);
+ MEM_freeN(newname);
+
+ pf = sample->packedfile;
+ // because samples and sounds can point to the
+ // same packedfile we have to check them all
+ sound_set_packedfile(sample, NULL);
+ freePackedFile(pf);
+
+ ret_value = RET_OK;
+ }
+ }
+
+ return(ret_value);
+}
+
+int unpackImage(Image * ima, int how)
+{
+ char localname[FILE_MAXDIR + FILE_MAX], fi[FILE_MAX];
+ char * newname;
+ int ret_value = RET_ERROR;
+
+ if (ima != NULL) {
+ strcpy(localname, ima->name);
+ BLI_splitdirstring(localname, fi);
+ sprintf(localname, "//textures/%s", fi);
+
+ newname = unpackFile(ima->name, localname, ima->packedfile, how);
+ if (newname != NULL) {
+ ret_value = RET_OK;
+ freePackedFile(ima->packedfile);
+ ima->packedfile = NULL;
+ strcpy(ima->name, newname);
+ MEM_freeN(newname);
+ BKE_image_signal(ima, NULL, IMA_SIGNAL_RELOAD);
+ }
+ }
+
+ return(ret_value);
+}
+
+void unpackAll(int how)
+{
+ Image *ima;
+ VFont *vf;
+ bSample *sample;
+
+ ima = G.main->image.first;
+ while (ima) {
+ if (ima->packedfile) {
+ unpackImage(ima, how);
+ }
+ ima= ima->id.next;
+ }
+
+ vf = G.main->vfont.first;
+ while (vf) {
+ if (vf->packedfile) {
+ unpackVFont(vf, how);
+ }
+ vf = vf->id.next;
+ }
+
+ sample = samples->first;
+ while (sample) {
+ if (sample->packedfile) {
+ unpackSample(sample, how);
+ }
+ sample = sample->id.next;
+ }
+}
diff --git a/source/blender/blenkernel/intern/property.c b/source/blender/blenkernel/intern/property.c
new file mode 100644
index 00000000000..a60c03c4840
--- /dev/null
+++ b/source/blender/blenkernel/intern/property.c
@@ -0,0 +1,269 @@
+
+/* property.c june 2000
+ *
+ * ton roosendaal
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_property_types.h"
+#include "DNA_object_types.h"
+#include "DNA_listBase.h"
+
+
+#include "BLI_blenlib.h"
+#include "BKE_bad_level_calls.h"
+#include "BKE_property.h"
+
+void free_property(bProperty *prop)
+{
+
+ if(prop->poin && prop->poin != &prop->data) MEM_freeN(prop->poin);
+ MEM_freeN(prop);
+
+}
+
+void free_properties(ListBase *lb)
+{
+ bProperty *prop;
+
+ while( (prop= lb->first) ) {
+ BLI_remlink(lb, prop);
+ free_property(prop);
+ }
+}
+
+bProperty *copy_property(bProperty *prop)
+{
+ bProperty *propn;
+
+ propn= MEM_dupallocN(prop);
+ if(prop->poin && prop->poin != &prop->data) {
+ propn->poin= MEM_dupallocN(prop->poin);
+ }
+ else propn->poin= &propn->data;
+
+ return propn;
+}
+
+void copy_properties(ListBase *lbn, ListBase *lbo)
+{
+ bProperty *prop, *propn;
+
+ lbn->first= lbn->last= 0;
+ prop= lbo->first;
+ while(prop) {
+ propn= copy_property(prop);
+ BLI_addtail(lbn, propn);
+ prop= prop->next;
+ }
+
+
+}
+
+void init_property(bProperty *prop)
+{
+ /* also use when property changes type */
+
+ if(prop->poin && prop->poin != &prop->data) MEM_freeN(prop->poin);
+ prop->poin= 0;
+
+ prop->otype= prop->type;
+ prop->data= 0;
+
+ switch(prop->type) {
+ case PROP_BOOL:
+ prop->poin= &prop->data;
+ break;
+ case PROP_INT:
+ prop->poin= &prop->data;
+ break;
+ case PROP_FLOAT:
+ prop->poin= &prop->data;
+ break;
+ case PROP_STRING:
+ prop->poin= MEM_callocN(MAX_PROPSTRING, "property string");
+ break;
+ case PROP_TIME:
+ prop->poin= &prop->data;
+ break;
+ }
+}
+
+
+bProperty *new_property(int type)
+{
+ bProperty *prop;
+
+ prop= MEM_callocN(sizeof(bProperty), "property");
+ prop->type= type;
+
+ init_property(prop);
+
+ strcpy(prop->name, "prop");
+
+ return prop;
+}
+
+bProperty *get_property(Object *ob, char *name)
+{
+ bProperty *prop;
+
+ prop= ob->prop.first;
+ while(prop) {
+ if( strcmp(prop->name, name)==0 ) return prop;
+ prop= prop->next;
+ }
+ return NULL;
+}
+
+/* negative: prop is smaller
+ * positive: prop is larger
+ */
+int compare_property(bProperty *prop, char *str)
+{
+// extern int Gdfra; /* sector.c */
+ float fvalue, ftest;
+
+ switch(prop->type) {
+ case PROP_BOOL:
+ if(BLI_strcasecmp(str, "true")==0) {
+ if(prop->data==1) return 0;
+ else return 1;
+ }
+ else if(BLI_strcasecmp(str, "false")==0) {
+ if(prop->data==0) return 0;
+ else return 1;
+ }
+ /* no break, do prop_int too! */
+
+ case PROP_INT:
+ return prop->data - atoi(str);
+
+ case PROP_FLOAT:
+ case PROP_TIME:
+ // WARNING: untested for PROP_TIME
+ // function isn't used currently
+ fvalue= *((float *)&prop->data);
+ ftest= (float)atof(str);
+ if( fvalue > ftest) return 1;
+ else if( fvalue < ftest) return -1;
+ return 0;
+
+ case PROP_STRING:
+ return strcmp(prop->poin, str);
+ }
+
+ return 0;
+}
+
+void set_property(bProperty *prop, char *str)
+{
+// extern int Gdfra; /* sector.c */
+
+ switch(prop->type) {
+ case PROP_BOOL:
+ if(BLI_strcasecmp(str, "true")==0) prop->data= 1;
+ else if(BLI_strcasecmp(str, "false")==0) prop->data= 0;
+ else prop->data= (atoi(str)!=0);
+ break;
+ case PROP_INT:
+ prop->data= atoi(str);
+ break;
+ case PROP_FLOAT:
+ case PROP_TIME:
+ *((float *)&prop->data)= (float)atof(str);
+ break;
+ case PROP_STRING:
+ strcpy(prop->poin, str);
+ break;
+ }
+
+}
+
+void add_property(bProperty *prop, char *str)
+{
+// extern int Gdfra; /* sector.c */
+
+ switch(prop->type) {
+ case PROP_BOOL:
+ case PROP_INT:
+ prop->data+= atoi(str);
+ break;
+ case PROP_FLOAT:
+ case PROP_TIME:
+ *((float *)&prop->data)+= (float)atof(str);
+ break;
+ case PROP_STRING:
+ /* strcpy(prop->poin, str); */
+ break;
+ }
+}
+
+/* reads value of property, sets it in chars in str */
+void set_property_valstr(bProperty *prop, char *str)
+{
+// extern int Gdfra; /* sector.c */
+
+ if(str == NULL) return;
+
+ switch(prop->type) {
+ case PROP_BOOL:
+ case PROP_INT:
+ sprintf(str, "%d", prop->data);
+ break;
+ case PROP_FLOAT:
+ case PROP_TIME:
+ sprintf(str, "%f", *((float *)&prop->data));
+ break;
+ case PROP_STRING:
+ BLI_strncpy(str, prop->poin, MAX_PROPSTRING);
+ break;
+ }
+}
+
+void cp_property(bProperty *prop1, bProperty *prop2)
+{
+ char str[128];
+
+ set_property_valstr(prop2, str);
+
+ set_property(prop1, str);
+}
diff --git a/source/blender/blenkernel/intern/sca.c b/source/blender/blenkernel/intern/sca.c
new file mode 100644
index 00000000000..e772a3bcdb4
--- /dev/null
+++ b/source/blender/blenkernel/intern/sca.c
@@ -0,0 +1,638 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * these all are linked to objects (listbase)
+ * all data is 'direct data', not Blender lib data.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include "MEM_guardedalloc.h"
+
+#include "nla.h" /* For __NLA: Important, do not remove */
+#include "DNA_text_types.h"
+#include "DNA_controller_types.h"
+#include "DNA_sensor_types.h"
+#include "DNA_actuator_types.h"
+#include "DNA_object_types.h"
+
+#include "BLI_blenlib.h"
+#include "BKE_bad_level_calls.h"
+#include "BKE_utildefines.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_blender.h"
+#include "BKE_sca.h"
+
+void free_text_controllers(Text *txt)
+{
+ Object *ob;
+ bController *cont;
+
+ ob= G.main->object.first;
+ while(ob) {
+ cont= ob->controllers.first;
+ while(cont) {
+ if(cont->type==CONT_PYTHON) {
+ bPythonCont *pc;
+
+ pc= cont->data;
+ if(pc->text==txt) pc->text= NULL;
+ }
+ cont= cont->next;
+ }
+ ob= ob->id.next;
+ }
+}
+
+
+/* ******************* SENSORS ************************ */
+
+void free_sensor(bSensor *sens)
+{
+ if(sens->links) MEM_freeN(sens->links);
+ if(sens->data) MEM_freeN(sens->data);
+ MEM_freeN(sens);
+
+}
+
+void free_sensors(ListBase *lb)
+{
+ bSensor *sens;
+
+ while((sens= lb->first)) {
+ BLI_remlink(lb, sens);
+ free_sensor(sens);
+ }
+}
+
+bSensor *copy_sensor(bSensor *sens)
+{
+ bSensor *sensn;
+
+ sensn= MEM_dupallocN(sens);
+ sensn->flag |= SENS_NEW;
+ if(sens->data) {
+ sensn->data= MEM_dupallocN(sens->data);
+ }
+
+ if(sens->links) sensn->links= MEM_dupallocN(sens->links);
+
+ return sensn;
+}
+
+void copy_sensors(ListBase *lbn, ListBase *lbo)
+{
+ bSensor *sens, *sensn;
+
+ lbn->first= lbn->last= 0;
+ sens= lbo->first;
+ while(sens) {
+ sensn= copy_sensor(sens);
+ BLI_addtail(lbn, sensn);
+ sens= sens->next;
+ }
+}
+
+void init_sensor(bSensor *sens)
+{
+ /* also use when sensor changes type */
+ bNearSensor *ns;
+ bMouseSensor *ms;
+
+ if(sens->data) MEM_freeN(sens->data);
+ sens->data= NULL;
+ sens->pulse = 0;
+
+ switch(sens->type) {
+ case SENS_ALWAYS:
+ sens->pulse = 1;
+ break;
+ case SENS_TOUCH:
+ sens->data= MEM_callocN(sizeof(bTouchSensor), "touchsens");
+ break;
+ case SENS_NEAR:
+ ns=sens->data= MEM_callocN(sizeof(bNearSensor), "nearsens");
+ ns->dist= 1.0;
+ ns->resetdist= 2.0;
+ break;
+ case SENS_KEYBOARD:
+ sens->data= MEM_callocN(sizeof(bKeyboardSensor), "keysens");
+ break;
+ case SENS_PROPERTY:
+ sens->data= MEM_callocN(sizeof(bPropertySensor), "propsens");
+ break;
+ case SENS_MOUSE:
+ ms=sens->data= MEM_callocN(sizeof(bMouseSensor), "mousesens");
+ ms->type= LEFTMOUSE;
+ break;
+ case SENS_COLLISION:
+ sens->data= MEM_callocN(sizeof(bCollisionSensor), "colsens");
+ break;
+ case SENS_RADAR:
+ sens->data= MEM_callocN(sizeof(bRadarSensor), "radarsens");
+ break;
+ case SENS_RANDOM:
+ sens->data= MEM_callocN(sizeof(bRandomSensor), "randomsens");
+ break;
+ case SENS_RAY:
+ sens->data= MEM_callocN(sizeof(bRaySensor), "raysens");
+ break;
+ case SENS_MESSAGE:
+ sens->data= MEM_callocN(sizeof(bMessageSensor), "messagesens");
+ break;
+ case SENS_JOYSTICK:
+ sens->data= MEM_callocN(sizeof(bJoystickSensor), "joysticksens");
+ break;
+ default:
+ ; /* this is very severe... I cannot make any memory for this */
+ /* logic brick... */
+ }
+}
+
+bSensor *new_sensor(int type)
+{
+ bSensor *sens;
+
+ sens= MEM_callocN(sizeof(bSensor), "Sensor");
+ sens->type= type;
+ sens->flag= SENS_SHOW;
+
+ init_sensor(sens);
+
+ strcpy(sens->name, "sensor");
+ make_unique_prop_names(sens->name);
+
+ return sens;
+}
+
+/* ******************* CONTROLLERS ************************ */
+
+void unlink_controller(bController *cont)
+{
+ bSensor *sens;
+ Object *ob;
+ int a, removed;
+
+ /* check for controller pointers in sensors */
+ ob= G.main->object.first;
+ while(ob) {
+ sens= ob->sensors.first;
+ while(sens) {
+ removed= 0;
+ for(a=0; a<sens->totlinks; a++) {
+ if(removed) (sens->links)[a-1] = (sens->links)[a];
+ else if((sens->links)[a] == cont) removed= 1;
+ }
+ if(removed) {
+ sens->totlinks--;
+
+ if(sens->totlinks==0) {
+ MEM_freeN(sens->links);
+ sens->links= NULL;
+ }
+ }
+ sens= sens->next;
+ }
+ ob= ob->id.next;
+ }
+}
+
+void unlink_controllers(ListBase *lb)
+{
+ bController *cont;
+
+ for (cont= lb->first; cont; cont= cont->next)
+ unlink_controller(cont);
+}
+
+void free_controller(bController *cont)
+{
+ if(cont->links) MEM_freeN(cont->links);
+
+ /* the controller itself */
+ if(cont->data) MEM_freeN(cont->data);
+ MEM_freeN(cont);
+
+}
+
+void free_controllers(ListBase *lb)
+{
+ bController *cont;
+
+ while((cont= lb->first)) {
+ BLI_remlink(lb, cont);
+ if(cont->slinks) MEM_freeN(cont->slinks);
+ free_controller(cont);
+ }
+}
+
+bController *copy_controller(bController *cont)
+{
+ bController *contn;
+
+ cont->mynew=contn= MEM_dupallocN(cont);
+ contn->flag |= CONT_NEW;
+ if(cont->data) {
+ contn->data= MEM_dupallocN(cont->data);
+ }
+
+ if(cont->links) contn->links= MEM_dupallocN(cont->links);
+ contn->slinks= NULL;
+ contn->totslinks= 0;
+
+ return contn;
+}
+
+void copy_controllers(ListBase *lbn, ListBase *lbo)
+{
+ bController *cont, *contn;
+
+ lbn->first= lbn->last= 0;
+ cont= lbo->first;
+ while(cont) {
+ contn= copy_controller(cont);
+ BLI_addtail(lbn, contn);
+ cont= cont->next;
+ }
+}
+
+void init_controller(bController *cont)
+{
+ /* also use when controller changes type, leave actuators... */
+
+ if(cont->data) MEM_freeN(cont->data);
+ cont->data= 0;
+
+ switch(cont->type) {
+ case CONT_EXPRESSION:
+ cont->data= MEM_callocN(sizeof(bExpressionCont), "expcont");
+ break;
+ case CONT_PYTHON:
+ cont->data= MEM_callocN(sizeof(bPythonCont), "pycont");
+ break;
+ }
+}
+
+bController *new_controller(int type)
+{
+ bController *cont;
+
+ cont= MEM_callocN(sizeof(bController), "Controller");
+ cont->type= type;
+ cont->flag= CONT_SHOW;
+
+ init_controller(cont);
+
+ strcpy(cont->name, "cont");
+ make_unique_prop_names(cont->name);
+
+ return cont;
+}
+
+/* ******************* ACTUATORS ************************ */
+
+void unlink_actuator(bActuator *act)
+{
+ bController *cont;
+ Object *ob;
+ int a, removed;
+
+ /* check for actuator pointers in controllers */
+ ob= G.main->object.first;
+ while(ob) {
+ cont= ob->controllers.first;
+ while(cont) {
+ removed= 0;
+ for(a=0; a<cont->totlinks; a++) {
+ if(removed) (cont->links)[a-1] = (cont->links)[a];
+ else if((cont->links)[a] == act) removed= 1;
+ }
+ if(removed) {
+ cont->totlinks--;
+
+ if(cont->totlinks==0) {
+ MEM_freeN(cont->links);
+ cont->links= NULL;
+ }
+ }
+ cont= cont->next;
+ }
+ ob= ob->id.next;
+ }
+}
+
+void unlink_actuators(ListBase *lb)
+{
+ bActuator *act;
+
+ for (act= lb->first; act; act= act->next)
+ unlink_actuator(act);
+}
+
+void free_actuator(bActuator *act)
+{
+ if(act->data) MEM_freeN(act->data);
+ MEM_freeN(act);
+}
+
+void free_actuators(ListBase *lb)
+{
+ bActuator *act;
+
+ while((act= lb->first)) {
+ BLI_remlink(lb, act);
+ free_actuator(act);
+ }
+}
+
+bActuator *copy_actuator(bActuator *act)
+{
+ bActuator *actn;
+
+ act->mynew=actn= MEM_dupallocN(act);
+ actn->flag |= ACT_NEW;
+ if(act->data) {
+ actn->data= MEM_dupallocN(act->data);
+ }
+
+ return actn;
+}
+
+void copy_actuators(ListBase *lbn, ListBase *lbo)
+{
+ bActuator *act, *actn;
+
+ lbn->first= lbn->last= 0;
+ act= lbo->first;
+ while(act) {
+ actn= copy_actuator(act);
+ BLI_addtail(lbn, actn);
+ act= act->next;
+ }
+}
+
+void init_actuator(bActuator *act)
+{
+ /* also use when actuator changes type */
+ bObjectActuator *oa;
+
+ if(act->data) MEM_freeN(act->data);
+ act->data= 0;
+
+ switch(act->type) {
+#ifdef __NLA
+ case ACT_ACTION:
+ act->data= MEM_callocN(sizeof(bActionActuator), "actionact");
+ break;
+#endif
+ case ACT_SOUND:
+ act->data= MEM_callocN(sizeof(bSoundActuator), "soundact");
+ break;
+ case ACT_CD:
+ act->data= MEM_callocN(sizeof(bCDActuator), "cdact");
+ break;
+ case ACT_OBJECT:
+ act->data= MEM_callocN(sizeof(bObjectActuator), "objectact");
+ oa= act->data;
+ oa->flag= 15;
+ break;
+ case ACT_IPO:
+ act->data= MEM_callocN(sizeof(bIpoActuator), "ipoact");
+ break;
+ case ACT_PROPERTY:
+ act->data= MEM_callocN(sizeof(bPropertyActuator), "propact");
+ break;
+ case ACT_CAMERA:
+ act->data= MEM_callocN(sizeof(bCameraActuator), "camact");
+ break;
+ case ACT_EDIT_OBJECT:
+ act->data= MEM_callocN(sizeof(bEditObjectActuator), "editobact");
+ break;
+ case ACT_CONSTRAINT:
+ act->data= MEM_callocN(sizeof(bConstraintActuator), "cons act");
+ break;
+ case ACT_SCENE:
+ act->data= MEM_callocN(sizeof(bSceneActuator), "scene act");
+ break;
+ case ACT_GROUP:
+ act->data= MEM_callocN(sizeof(bGroupActuator), "group act");
+ break;
+ case ACT_RANDOM:
+ act->data= MEM_callocN(sizeof(bRandomActuator), "random act");
+ break;
+ case ACT_MESSAGE:
+ act->data= MEM_callocN(sizeof(bMessageActuator), "message act");
+ break;
+ case ACT_GAME:
+ act->data= MEM_callocN(sizeof(bGameActuator), "game act");
+ break;
+ case ACT_VISIBILITY:
+ act->data= MEM_callocN(sizeof(bVisibilityActuator), "visibility act");
+ break;
+ default:
+ ; /* this is very severe... I cannot make any memory for this */
+ /* logic brick... */
+ }
+}
+
+bActuator *new_actuator(int type)
+{
+ bActuator *act;
+
+ act= MEM_callocN(sizeof(bActuator), "Actuator");
+ act->type= type;
+ act->flag= ACT_SHOW;
+
+ init_actuator(act);
+
+ strcpy(act->name, "act");
+ make_unique_prop_names(act->name);
+
+ return act;
+}
+
+/* ******************** GENERAL ******************* */
+
+void clear_sca_new_poins_ob(Object *ob)
+{
+ bSensor *sens;
+ bController *cont;
+ bActuator *act;
+
+ sens= ob->sensors.first;
+ while(sens) {
+ sens->flag &= ~SENS_NEW;
+ sens= sens->next;
+ }
+ cont= ob->controllers.first;
+ while(cont) {
+ cont->mynew= NULL;
+ cont->flag &= ~CONT_NEW;
+ cont= cont->next;
+ }
+ act= ob->actuators.first;
+ while(act) {
+ act->mynew= NULL;
+ act->flag &= ~ACT_NEW;
+ act= act->next;
+ }
+}
+
+void clear_sca_new_poins()
+{
+ Object *ob;
+
+ ob= G.main->object.first;
+ while(ob) {
+ clear_sca_new_poins_ob(ob);
+ ob= ob->id.next;
+ }
+}
+
+void set_sca_new_poins_ob(Object *ob)
+{
+ bSensor *sens;
+ bController *cont;
+ bActuator *act;
+ int a;
+
+ sens= ob->sensors.first;
+ while(sens) {
+ if(sens->flag & SENS_NEW) {
+ for(a=0; a<sens->totlinks; a++) {
+ if(sens->links[a] && sens->links[a]->mynew)
+ sens->links[a]= sens->links[a]->mynew;
+ }
+ }
+ sens= sens->next;
+ }
+
+ cont= ob->controllers.first;
+ while(cont) {
+ if(cont->flag & CONT_NEW) {
+ for(a=0; a<cont->totlinks; a++) {
+ if( cont->links[a] && cont->links[a]->mynew)
+ cont->links[a]= cont->links[a]->mynew;
+ }
+ }
+ cont= cont->next;
+ }
+
+
+ act= ob->actuators.first;
+ while(act) {
+ if(act->flag & ACT_NEW) {
+ if(act->type==ACT_EDIT_OBJECT) {
+ bEditObjectActuator *eoa= act->data;
+ ID_NEW(eoa->ob);
+ }
+ else if(act->type==ACT_SCENE) {
+ bSceneActuator *sca= act->data;
+ ID_NEW(sca->camera);
+ }
+ else if(act->type==ACT_CAMERA) {
+ bCameraActuator *ca= act->data;
+ ID_NEW(ca->ob);
+ }
+ else if(act->type==ACT_SCENE) {
+ bSceneActuator *sca= act->data;
+ ID_NEW(sca->camera);
+ }
+ }
+ act= act->next;
+ }
+}
+
+
+void set_sca_new_poins()
+{
+ Object *ob;
+
+ ob= G.main->object.first;
+ while(ob) {
+ set_sca_new_poins_ob(ob);
+ ob= ob->id.next;
+ }
+}
+
+void sca_remove_ob_poin(Object *obt, Object *ob)
+{
+ bSensor *sens;
+ bMessageSensor *ms;
+ bActuator *act;
+ bCameraActuator *ca;
+ bSceneActuator *sa;
+ bEditObjectActuator *eoa;
+ bPropertyActuator *pa;
+ bMessageActuator *ma;
+
+ sens= obt->sensors.first;
+ while(sens) {
+ switch(sens->type) {
+ case SENS_MESSAGE:
+ ms= sens->data;
+ if(ms->fromObject==ob) ms->fromObject= NULL;
+ }
+ sens= sens->next;
+ }
+
+ act= obt->actuators.first;
+ while(act) {
+ switch(act->type) {
+ case ACT_CAMERA:
+ ca= act->data;
+ if(ca->ob==ob) ca->ob= NULL;
+ break;
+ case ACT_PROPERTY:
+ pa= act->data;
+ if(pa->ob==ob) pa->ob= NULL;
+ break;
+ case ACT_SCENE:
+ sa= act->data;
+ if(sa->camera==ob) sa->camera= NULL;
+ break;
+ case ACT_EDIT_OBJECT:
+ eoa= act->data;
+ if(eoa->ob==ob) eoa->ob= NULL;
+ break;
+ case ACT_MESSAGE:
+ ma= act->data;
+ if(ma->toObject==ob) ma->toObject= NULL;
+ break;
+
+ }
+ act= act->next;
+ }
+}
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
new file mode 100644
index 00000000000..88de43fa85d
--- /dev/null
+++ b/source/blender/blenkernel/intern/scene.c
@@ -0,0 +1,564 @@
+/* scene.c
+ *
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef WIN32
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+#include "MEM_guardedalloc.h"
+
+#include "DNA_armature_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_group_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_material_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_scriptlink_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BKE_action.h"
+#include "BKE_anim.h"
+#include "BKE_armature.h"
+#include "BKE_bad_level_calls.h"
+#include "BKE_constraint.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_group.h"
+#include "BKE_ipo.h"
+#include "BKE_image.h"
+#include "BKE_key.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_node.h"
+#include "BKE_object.h"
+#include "BKE_scene.h"
+#include "BKE_world.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_previewrender.h"
+#include "BDR_sculptmode.h"
+
+#include "BPY_extern.h"
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+
+#include "nla.h"
+
+#ifdef WIN32
+#else
+#include <sys/time.h>
+#endif
+
+void free_avicodecdata(AviCodecData *acd)
+{
+ if (acd) {
+ if (acd->lpFormat){
+ MEM_freeN(acd->lpFormat);
+ acd->lpFormat = NULL;
+ acd->cbFormat = 0;
+ }
+ if (acd->lpParms){
+ MEM_freeN(acd->lpParms);
+ acd->lpParms = NULL;
+ acd->cbParms = 0;
+ }
+ }
+}
+
+void free_qtcodecdata(QuicktimeCodecData *qcd)
+{
+ if (qcd) {
+ if (qcd->cdParms){
+ MEM_freeN(qcd->cdParms);
+ qcd->cdParms = NULL;
+ qcd->cdSize = 0;
+ }
+ }
+}
+
+/* copy_scene moved to src/header_info.c... should be back */
+
+/* do not free scene itself */
+void free_scene(Scene *sce)
+{
+ Base *base;
+
+ base= sce->base.first;
+ while(base) {
+ base->object->id.us--;
+ base= base->next;
+ }
+ /* do not free objects! */
+
+ BLI_freelistN(&sce->base);
+ free_editing(sce->ed);
+ if(sce->radio) MEM_freeN(sce->radio);
+ sce->radio= 0;
+
+ BPY_free_scriptlink(&sce->scriptlink);
+ if (sce->r.avicodecdata) {
+ free_avicodecdata(sce->r.avicodecdata);
+ MEM_freeN(sce->r.avicodecdata);
+ sce->r.avicodecdata = NULL;
+ }
+ if (sce->r.qtcodecdata) {
+ free_qtcodecdata(sce->r.qtcodecdata);
+ MEM_freeN(sce->r.qtcodecdata);
+ sce->r.qtcodecdata = NULL;
+ }
+
+ BLI_freelistN(&sce->markers);
+ BLI_freelistN(&sce->r.layers);
+
+ if(sce->toolsettings){
+ MEM_freeN(sce->toolsettings);
+ sce->toolsettings = NULL;
+ }
+
+ if (sce->theDag) {
+ free_forest(sce->theDag);
+ MEM_freeN(sce->theDag);
+ }
+
+ if(sce->nodetree) {
+ ntreeFreeTree(sce->nodetree);
+ MEM_freeN(sce->nodetree);
+ }
+
+ sculptmode_free_all(sce);
+}
+
+Scene *add_scene(char *name)
+{
+ Scene *sce;
+
+ sce= alloc_libblock(&G.main->scene, ID_SCE, name);
+ sce->lay= 1;
+ sce->selectmode= SCE_SELECT_VERTEX;
+ sce->editbutsize= 0.1;
+
+ sce->r.mode= R_GAMMA;
+ sce->r.cfra= 1;
+ sce->r.sfra= 1;
+ sce->r.efra= 250;
+ sce->r.xsch= 320;
+ sce->r.ysch= 256;
+ sce->r.xasp= 1;
+ sce->r.yasp= 1;
+ sce->r.xparts= 4;
+ sce->r.yparts= 4;
+ sce->r.size= 100;
+ sce->r.planes= 24;
+ sce->r.quality= 90;
+ sce->r.framapto= 100;
+ sce->r.images= 100;
+ sce->r.framelen= 1.0;
+ sce->r.frs_sec= 25;
+ sce->r.frs_sec_base= 1;
+ sce->r.ocres = 128;
+
+ sce->r.bake_mode= 1; /* prevent to include render stuff here */
+ sce->r.bake_filter= 2;
+ sce->r.bake_osa= 5;
+ sce->r.bake_flag= R_BAKE_CLEAR;
+
+ sce->r.xplay= 640;
+ sce->r.yplay= 480;
+ sce->r.freqplay= 60;
+ sce->r.depth= 32;
+
+ sce->r.threads= 1;
+
+ sce->r.stereomode = 1; // no stereo
+
+ sce->toolsettings = MEM_callocN(sizeof(struct ToolSettings),"Tool Settings Struct");
+ sce->toolsettings->cornertype=1;
+ sce->toolsettings->degr = 90;
+ sce->toolsettings->step = 9;
+ sce->toolsettings->turn = 1;
+ sce->toolsettings->extr_offs = 1;
+ sce->toolsettings->doublimit = 0.001;
+ sce->toolsettings->segments = 32;
+ sce->toolsettings->rings = 32;
+ sce->toolsettings->vertices = 32;
+ sce->toolsettings->editbutflag = 1;
+ sce->toolsettings->uvcalc_radius = 1.0f;
+ sce->toolsettings->uvcalc_cubesize = 1.0f;
+ sce->toolsettings->uvcalc_mapdir = 1;
+ sce->toolsettings->uvcalc_mapalign = 1;
+ sce->toolsettings->unwrapper = 1;
+ sce->toolsettings->select_thresh= 0.01f;
+ sce->toolsettings->jointrilimit = 0.8f;
+
+ sce->jumpframe = 10;
+ sce->audio.mixrate = 44100;
+
+ strcpy(sce->r.backbuf, "//backbuf");
+ strcpy(sce->r.pic, U.renderdir);
+ strcpy(sce->r.ftype, "//ftype");
+
+ BLI_init_rctf(&sce->r.safety, 0.1f, 0.9f, 0.1f, 0.9f);
+ sce->r.osa= 8;
+
+ sculptmode_init(sce);
+
+ /* note; in header_info.c the scene copy happens..., if you add more to renderdata it has to be checked there */
+ scene_add_render_layer(sce);
+
+ return sce;
+}
+
+Base *object_in_scene(Object *ob, Scene *sce)
+{
+ Base *base;
+
+ base= sce->base.first;
+ while(base) {
+ if(base->object == ob) return base;
+ base= base->next;
+ }
+ return NULL;
+}
+
+void set_scene_bg(Scene *sce)
+{
+ Base *base;
+ Object *ob;
+ Group *group;
+ GroupObject *go;
+ int flag;
+
+ G.scene= sce;
+
+ /* check for cyclic sets, for reading old files but also for definite security (py?) */
+ scene_check_setscene(G.scene);
+
+ /* deselect objects (for dataselect) */
+ for(ob= G.main->object.first; ob; ob= ob->id.next)
+ ob->flag &= ~(SELECT|OB_FROMGROUP);
+
+ /* group flags again */
+ for(group= G.main->group.first; group; group= group->id.next) {
+ go= group->gobject.first;
+ while(go) {
+ if(go->ob) go->ob->flag |= OB_FROMGROUP;
+ go= go->next;
+ }
+ }
+
+ /* sort baselist */
+ DAG_scene_sort(sce);
+
+ /* ensure dags are built for sets */
+ for(sce= sce->set; sce; sce= sce->set)
+ if(sce->theDag==NULL)
+ DAG_scene_sort(sce);
+
+ /* copy layers and flags from bases to objects */
+ for(base= G.scene->base.first; base; base= base->next) {
+ ob= base->object;
+ ob->lay= base->lay;
+
+ /* group patch... */
+ base->flag &= ~(OB_FROMGROUP);
+ flag= ob->flag & (OB_FROMGROUP);
+ base->flag |= flag;
+
+ /* not too nice... for recovering objects with lost data */
+ if(ob->pose==NULL) base->flag &= ~OB_POSEMODE;
+ ob->flag= base->flag;
+
+ ob->ctime= -1234567.0; /* force ipo to be calculated later */
+ }
+ /* no full animation update, this to enable render code to work (render code calls own animation updates) */
+
+ /* do we need FRAMECHANGED in set_scene? */
+// if (G.f & G_DOSCRIPTLINKS) BPY_do_all_scripts(SCRIPT_FRAMECHANGED);
+}
+
+/* called from creator.c */
+void set_scene_name(char *name)
+{
+ Scene *sce;
+
+ for (sce= G.main->scene.first; sce; sce= sce->id.next) {
+ if (BLI_streq(name, sce->id.name+2)) {
+ set_scene_bg(sce);
+ return;
+ }
+ }
+
+ error("Can't find scene: %s", name);
+}
+
+/* used by metaballs
+ * doesnt return the original duplicated object, only dupli's
+ */
+int next_object(int val, Base **base, Object **ob)
+{
+ static ListBase *duplilist= NULL;
+ static DupliObject *dupob;
+ static int fase;
+ int run_again=1;
+
+ /* init */
+ if(val==0) {
+ fase= F_START;
+ dupob= NULL;
+ }
+ else {
+
+ /* run_again is set when a duplilist has been ended */
+ while(run_again) {
+ run_again= 0;
+
+ /* the first base */
+ if(fase==F_START) {
+ *base= G.scene->base.first;
+ if(*base) {
+ *ob= (*base)->object;
+ fase= F_SCENE;
+ }
+ else {
+ /* exception: empty scene */
+ if(G.scene->set && G.scene->set->base.first) {
+ *base= G.scene->set->base.first;
+ *ob= (*base)->object;
+ fase= F_SET;
+ }
+ }
+ }
+ else {
+ if(*base && fase!=F_DUPLI) {
+ *base= (*base)->next;
+ if(*base) *ob= (*base)->object;
+ else {
+ if(fase==F_SCENE) {
+ /* scene is finished, now do the set */
+ if(G.scene->set && G.scene->set->base.first) {
+ *base= G.scene->set->base.first;
+ *ob= (*base)->object;
+ fase= F_SET;
+ }
+ }
+ }
+ }
+ }
+
+ if(*base == NULL) fase= F_START;
+ else {
+ if(fase!=F_DUPLI) {
+ if( (*base)->object->transflag & OB_DUPLI) {
+ /* groups cannot be duplicated for mballs yet,
+ this enters eternal loop because of
+ makeDispListMBall getting called inside of group_duplilist */
+ if((*base)->object->dup_group == NULL) {
+ duplilist= object_duplilist(G.scene, (*base)->object);
+
+ dupob= duplilist->first;
+ }
+ }
+ }
+ /* handle dupli's */
+ if(dupob) {
+
+ Mat4CpyMat4(dupob->ob->obmat, dupob->mat);
+
+ (*base)->flag |= OB_FROMDUPLI;
+ *ob= dupob->ob;
+ fase= F_DUPLI;
+
+ dupob= dupob->next;
+ }
+ else if(fase==F_DUPLI) {
+ fase= F_SCENE;
+ (*base)->flag &= ~OB_FROMDUPLI;
+
+ for(dupob= duplilist->first; dupob; dupob= dupob->next) {
+ Mat4CpyMat4(dupob->ob->obmat, dupob->omat);
+ }
+
+ free_object_duplilist(duplilist);
+ duplilist= NULL;
+ run_again= 1;
+ }
+ }
+ }
+ }
+
+ return fase;
+}
+
+Object *scene_find_camera(Scene *sc)
+{
+ Base *base;
+
+ for (base= sc->base.first; base; base= base->next)
+ if (base->object->type==OB_CAMERA)
+ return base->object;
+
+ return NULL;
+}
+
+
+Base *scene_add_base(Scene *sce, Object *ob)
+{
+ Base *b= MEM_callocN(sizeof(*b), "scene_add_base");
+ BLI_addhead(&sce->base, b);
+
+ b->object= ob;
+ b->flag= ob->flag;
+ b->lay= ob->lay;
+
+ return b;
+}
+
+void scene_deselect_all(Scene *sce)
+{
+ Base *b;
+
+ for (b= sce->base.first; b; b= b->next) {
+ b->flag&= ~SELECT;
+ b->object->flag= b->flag;
+ }
+}
+
+void scene_select_base(Scene *sce, Base *selbase)
+{
+ scene_deselect_all(sce);
+
+ selbase->flag |= SELECT;
+ selbase->object->flag= selbase->flag;
+
+ sce->basact= selbase;
+}
+
+/* checks for cycle, returns 1 if it's all OK */
+int scene_check_setscene(Scene *sce)
+{
+ Scene *scene;
+
+ if(sce->set==NULL) return 1;
+
+ /* LIB_DOIT is the free flag to tag library data */
+ for(scene= G.main->scene.first; scene; scene= scene->id.next)
+ scene->id.flag &= ~LIB_DOIT;
+
+ scene= sce;
+ while(scene->set) {
+ scene->id.flag |= LIB_DOIT;
+ /* when set has flag set, we got a cycle */
+ if(scene->set->id.flag & LIB_DOIT)
+ break;
+ scene= scene->set;
+ }
+
+ if(scene->set) {
+ /* the tested scene gets zero'ed, that's typically current scene */
+ sce->set= NULL;
+ return 0;
+ }
+ return 1;
+}
+
+static void scene_update(Scene *sce, unsigned int lay)
+{
+ Base *base;
+ Object *ob;
+
+ if(sce->theDag==NULL)
+ DAG_scene_sort(sce);
+
+ DAG_scene_update_flags(sce, lay); // only stuff that moves or needs display still
+
+ for(base= sce->base.first; base; base= base->next) {
+ ob= base->object;
+
+ object_handle_update(ob); // bke_object.h
+
+ /* only update layer when an ipo */
+ if(ob->ipo && has_ipo_code(ob->ipo, OB_LAY) ) {
+ base->lay= ob->lay;
+ }
+ }
+}
+
+/* applies changes right away, does all sets too */
+void scene_update_for_newframe(Scene *sce, unsigned int lay)
+{
+ Scene *scene= sce;
+
+ /* clears all BONE_UNKEYED flags for every pose's pchans */
+ framechange_poses_clear_unkeyed();
+
+ /* object ipos are calculated in where_is_object */
+ do_all_data_ipos();
+
+ if (G.f & G_DOSCRIPTLINKS) BPY_do_all_scripts(SCRIPT_FRAMECHANGED);
+
+ /* sets first, we allow per definition current scene to have dependencies on sets */
+ for(sce= sce->set; sce; sce= sce->set)
+ scene_update(sce, lay);
+
+ scene_update(scene, lay);
+}
+
+/* return default layer, also used to patch old files */
+void scene_add_render_layer(Scene *sce)
+{
+ SceneRenderLayer *srl;
+ int tot= 1 + BLI_countlist(&sce->r.layers);
+
+ srl= MEM_callocN(sizeof(SceneRenderLayer), "new render layer");
+ sprintf(srl->name, "%d RenderLayer", tot);
+ BLI_addtail(&sce->r.layers, srl);
+
+ /* note, this is also in render, pipeline.c, to make layer when scenedata doesnt have it */
+ srl->lay= (1<<20) -1;
+ srl->layflag= 0x7FFF; /* solid ztra halo edge strand */
+ srl->passflag= SCE_PASS_COMBINED|SCE_PASS_Z;
+}
+
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
new file mode 100644
index 00000000000..5e8735147c3
--- /dev/null
+++ b/source/blender/blenkernel/intern/screen.c
@@ -0,0 +1,57 @@
+
+/* screen.c
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+
+#include "DNA_screen_types.h"
+#include "BKE_bad_level_calls.h"
+#include "BLI_blenlib.h"
+
+#include "BKE_screen.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* don't free screen itself */
+void free_screen(bScreen *sc)
+{
+ unlink_screen(sc);
+
+ BLI_freelistN(&sc->vertbase);
+ BLI_freelistN(&sc->edgebase);
+ BLI_freelistN(&sc->areabase);
+}
diff --git a/source/blender/blenkernel/intern/script.c b/source/blender/blenkernel/intern/script.c
new file mode 100644
index 00000000000..b99c2c51441
--- /dev/null
+++ b/source/blender/blenkernel/intern/script.c
@@ -0,0 +1,71 @@
+/* blenkernel/script.c
+ *
+ *
+ * $Id$
+ *
+ * Function(s) related to struct script management.
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "BKE_script.h"
+#include "BPI_script.h"
+
+#include "MEM_guardedalloc.h"
+#include "BKE_bad_level_calls.h" /* for BPY_clear_script */
+
+/*
+#include "BLI_blenlib.h"
+#include "BKE_utildefines.h"
+#include "BKE_library.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+
+#include "BPY_extern.h" // Blender Python library
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+*/
+
+/* XXX this function and so also the file should not be needed anymore,
+ * since we have to force clearing all Python related data before freeing
+ * Blender's library. Still testing, will decide later (Willian). */
+void free_script (Script *script)
+{
+ if (!script) return;
+
+ if (script->py_globaldict || script->py_button ||
+ script->py_event || script->py_draw)
+ {
+ BPY_clear_script(script);
+ }
+
+ return;
+}
diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c
new file mode 100644
index 00000000000..19dcee676cb
--- /dev/null
+++ b/source/blender/blenkernel/intern/softbody.c
@@ -0,0 +1,3420 @@
+/* softbody.c
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/*
+******
+variables on the UI for now
+
+ float mediafrict; friction to env
+ float nodemass; softbody mass of *vertex*
+ float grav; softbody amount of gravitaion to apply
+
+ float goalspring; softbody goal springs
+ float goalfrict; softbody goal springs friction
+ float mingoal; quick limits for goal
+ float maxgoal;
+
+ float inspring; softbody inner springs
+ float infrict; softbody inner springs friction
+
+*****
+*/
+
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+/* types */
+#include "DNA_curve_types.h"
+#include "DNA_object_types.h"
+#include "DNA_object_force.h" /* here is the softbody struct */
+#include "DNA_key_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_ghash.h"
+#include "BKE_curve.h"
+#include "BKE_effect.h"
+#include "BKE_global.h"
+#include "BKE_key.h"
+#include "BKE_object.h"
+#include "BKE_softbody.h"
+#include "BKE_utildefines.h"
+#include "BKE_DerivedMesh.h"
+
+#include "BIF_editdeform.h"
+#include "BIF_graphics.h"
+#include "PIL_time.h"
+
+/* callbacks for errors and interrupts and some goo */
+static int (*SB_localInterruptCallBack)(void) = NULL;
+
+
+/* ********** soft body engine ******* */
+
+
+
+typedef struct BodyPoint {
+ float origS[3], origE[3], origT[3], pos[3], vec[3], force[3];
+ float goal;
+ float prevpos[3], prevvec[3], prevdx[3], prevdv[3]; /* used for Heun integration */
+ int nofsprings; int *springs;
+ float choke;
+ float colball;
+ short flag;
+ char octantflag;
+} BodyPoint;
+
+typedef struct BodySpring {
+ int v1, v2;
+ float len, strength, cf;
+ float ext_force[3]; /* edges colliding and sailing */
+ short order;
+ short flag;
+} BodySpring;
+
+typedef struct BodyFace {
+ int v1, v2, v3 ,v4;
+ float ext_force[3]; /* edges colliding and sailing */
+ short flag;
+} BodyFace;
+
+
+/*private scratch pad for caching and other data only needed when alive*/
+typedef struct SBScratch {
+ GHash *colliderhash;
+ short needstobuildcollider;
+ short flag;
+ BodyFace *bodyface;
+ int totface;
+ float aabbmin[3],aabbmax[3];
+}SBScratch;
+
+#define SOFTGOALSNAP 0.999f
+/* if bp-> goal is above make it a *forced follow original* and skip all ODE stuff for this bp
+ removes *unnecessary* stiffnes from ODE system
+*/
+#define HEUNWARNLIMIT 1 /* 500 would be fine i think for detecting severe *stiff* stuff */
+
+
+#define BSF_INTERSECT 1 /* edge intersects collider face */
+#define SBF_DOFUZZY 1 /* edge intersects collider face */
+#define BFF_INTERSECT 1 /* edge intersects collider face */
+
+
+float SoftHeunTol = 1.0f; /* humm .. this should be calculated from sb parameters and sizes */
+
+/* local prototypes */
+static void free_softbody_intern(SoftBody *sb);
+/* aye this belongs to arith.c */
+static void Vec3PlusStVec(float *v, float s, float *v1);
+
+/*+++ frame based timing +++*/
+
+/*physical unit of force is [kg * m / sec^2]*/
+
+static float sb_grav_force_scale(Object *ob)
+/* since unit of g is [m/sec^2] and F = mass * g we rescale unit mass of node to 1 gramm
+ put it to a function here, so we can add user options later without touching simulation code
+*/
+{
+ return (0.001f);
+}
+
+static float sb_fric_force_scale(Object *ob)
+/* rescaling unit of drag [1 / sec] to somehow reasonable
+ put it to a function here, so we can add user options later without touching simulation code
+*/
+{
+ return (0.01f);
+}
+
+static float sb_time_scale(Object *ob)
+/* defining the frames to *real* time relation */
+{
+ SoftBody *sb= ob->soft; /* is supposed to be there */
+ if (sb){
+ return(sb->physics_speed);
+ /*hrms .. this could be IPO as well :)
+ estimated range [0.001 sluggish slug - 100.0 very fast (i hope ODE solver can handle that)]
+ 1 approx = a unit 1 pendulum at g = 9.8 [earth conditions] has period 65 frames
+ theory would give a 50 frames period .. so there must be something inaccurate .. looking for that (BM)
+ */
+ }
+ return (1.0f);
+ /*
+ this would be frames/sec independant timing assuming 25 fps is default
+ but does not work very well with NLA
+ return (25.0f/G.scene->r.frs_sec)
+ */
+}
+/*--- frame based timing ---*/
+
+/*+++ collider caching and dicing +++*/
+
+/********************
+for each target object/face the axis aligned bounding box (AABB) is stored
+faces paralell to global axes
+so only simple "value" in [min,max] ckecks are used
+float operations still
+*/
+
+/* just an ID here to reduce the prob for killing objects
+** ob->sumohandle points to we should not kill :)
+*/
+const int CCD_SAVETY = 190561;
+
+typedef struct ccdf_minmax{
+float minx,miny,minz,maxx,maxy,maxz;
+}ccdf_minmax;
+
+
+
+typedef struct ccd_Mesh {
+ int totvert, totface;
+ MVert *mvert;
+ MVert *mprevvert;
+ MFace *mface;
+ int savety;
+ ccdf_minmax *mima;
+ /* Axis Aligned Bounding Box AABB */
+ float bbmin[3];
+ float bbmax[3];
+}ccd_Mesh;
+
+
+
+
+ccd_Mesh *ccd_mesh_make(Object *ob, DerivedMesh *dm)
+{
+ ccd_Mesh *pccd_M = NULL;
+ ccdf_minmax *mima =NULL;
+ MFace *mface=NULL;
+ float v[3],hull;
+ int i;
+
+ /* first some paranoia checks */
+ if (!dm) return NULL;
+ if (!dm->getNumVerts(dm) || !dm->getNumFaces(dm)) return NULL;
+
+ pccd_M = MEM_mallocN(sizeof(ccd_Mesh),"ccd_Mesh");
+ pccd_M->totvert = dm->getNumVerts(dm);
+ pccd_M->totface = dm->getNumFaces(dm);
+ pccd_M->savety = CCD_SAVETY;
+ pccd_M->bbmin[0]=pccd_M->bbmin[1]=pccd_M->bbmin[2]=1e30f;
+ pccd_M->bbmax[0]=pccd_M->bbmax[1]=pccd_M->bbmax[2]=-1e30f;
+ pccd_M->mprevvert=NULL;
+
+
+ /* blow it up with forcefield ranges */
+ hull = MAX2(ob->pd->pdef_sbift,ob->pd->pdef_sboft);
+
+ /* alloc and copy verts*/
+ pccd_M->mvert = dm->dupVertArray(dm);
+ /* ah yeah, put the verices to global coords once */
+ /* and determine the ortho BB on the fly */
+ for(i=0; i < pccd_M->totvert; i++){
+ Mat4MulVecfl(ob->obmat, pccd_M->mvert[i].co);
+
+ /* evaluate limits */
+ VECCOPY(v,pccd_M->mvert[i].co);
+ pccd_M->bbmin[0] = MIN2(pccd_M->bbmin[0],v[0]-hull);
+ pccd_M->bbmin[1] = MIN2(pccd_M->bbmin[1],v[1]-hull);
+ pccd_M->bbmin[2] = MIN2(pccd_M->bbmin[2],v[2]-hull);
+
+ pccd_M->bbmax[0] = MAX2(pccd_M->bbmax[0],v[0]+hull);
+ pccd_M->bbmax[1] = MAX2(pccd_M->bbmax[1],v[1]+hull);
+ pccd_M->bbmax[2] = MAX2(pccd_M->bbmax[2],v[2]+hull);
+
+ }
+ /* alloc and copy faces*/
+ pccd_M->mface = dm->dupFaceArray(dm);
+
+ /* OBBs for idea1 */
+ pccd_M->mima = MEM_mallocN(sizeof(ccdf_minmax)*pccd_M->totface,"ccd_Mesh_Faces_mima");
+ mima = pccd_M->mima;
+ mface = pccd_M->mface;
+
+
+ /* anyhoo we need to walk the list of faces and find OBB they live in */
+ for(i=0; i < pccd_M->totface; i++){
+ mima->minx=mima->miny=mima->minz=1e30f;
+ mima->maxx=mima->maxy=mima->maxz=-1e30f;
+
+ VECCOPY(v,pccd_M->mvert[mface->v1].co);
+ mima->minx = MIN2(mima->minx,v[0]-hull);
+ mima->miny = MIN2(mima->miny,v[1]-hull);
+ mima->minz = MIN2(mima->minz,v[2]-hull);
+ mima->maxx = MAX2(mima->maxx,v[0]+hull);
+ mima->maxy = MAX2(mima->maxy,v[1]+hull);
+ mima->maxz = MAX2(mima->maxz,v[2]+hull);
+
+ VECCOPY(v,pccd_M->mvert[mface->v2].co);
+ mima->minx = MIN2(mima->minx,v[0]-hull);
+ mima->miny = MIN2(mima->miny,v[1]-hull);
+ mima->minz = MIN2(mima->minz,v[2]-hull);
+ mima->maxx = MAX2(mima->maxx,v[0]+hull);
+ mima->maxy = MAX2(mima->maxy,v[1]+hull);
+ mima->maxz = MAX2(mima->maxz,v[2]+hull);
+
+ VECCOPY(v,pccd_M->mvert[mface->v3].co);
+ mima->minx = MIN2(mima->minx,v[0]-hull);
+ mima->miny = MIN2(mima->miny,v[1]-hull);
+ mima->minz = MIN2(mima->minz,v[2]-hull);
+ mima->maxx = MAX2(mima->maxx,v[0]+hull);
+ mima->maxy = MAX2(mima->maxy,v[1]+hull);
+ mima->maxz = MAX2(mima->maxz,v[2]+hull);
+
+ if(mface->v4){
+ VECCOPY(v,pccd_M->mvert[mface->v4].co);
+ mima->minx = MIN2(mima->minx,v[0]-hull);
+ mima->miny = MIN2(mima->miny,v[1]-hull);
+ mima->minz = MIN2(mima->minz,v[2]-hull);
+ mima->maxx = MAX2(mima->maxx,v[0]+hull);
+ mima->maxy = MAX2(mima->maxy,v[1]+hull);
+ mima->maxz = MAX2(mima->maxz,v[2]+hull);
+ }
+
+
+ mima++;
+ mface++;
+
+ }
+ return pccd_M;
+}
+void ccd_mesh_update(Object *ob,ccd_Mesh *pccd_M, DerivedMesh *dm)
+{
+ ccdf_minmax *mima =NULL;
+ MFace *mface=NULL;
+ float v[3],hull;
+ int i;
+
+ /* first some paranoia checks */
+ if (!dm) return ;
+ if (!dm->getNumVerts(dm) || !dm->getNumFaces(dm)) return ;
+
+ if ((pccd_M->totvert != dm->getNumVerts(dm)) ||
+ (pccd_M->totface != dm->getNumFaces(dm))) return;
+
+ pccd_M->bbmin[0]=pccd_M->bbmin[1]=pccd_M->bbmin[2]=1e30f;
+ pccd_M->bbmax[0]=pccd_M->bbmax[1]=pccd_M->bbmax[2]=-1e30f;
+
+
+ /* blow it up with forcefield ranges */
+ hull = MAX2(ob->pd->pdef_sbift,ob->pd->pdef_sboft);
+
+ /* rotate current to previous */
+ if(pccd_M->mprevvert) MEM_freeN(pccd_M->mprevvert);
+ pccd_M->mprevvert = pccd_M->mvert;
+ /* alloc and copy verts*/
+ pccd_M->mvert = dm->dupVertArray(dm);
+ /* ah yeah, put the verices to global coords once */
+ /* and determine the ortho BB on the fly */
+ for(i=0; i < pccd_M->totvert; i++){
+ Mat4MulVecfl(ob->obmat, pccd_M->mvert[i].co);
+
+ /* evaluate limits */
+ VECCOPY(v,pccd_M->mvert[i].co);
+ pccd_M->bbmin[0] = MIN2(pccd_M->bbmin[0],v[0]-hull);
+ pccd_M->bbmin[1] = MIN2(pccd_M->bbmin[1],v[1]-hull);
+ pccd_M->bbmin[2] = MIN2(pccd_M->bbmin[2],v[2]-hull);
+
+ pccd_M->bbmax[0] = MAX2(pccd_M->bbmax[0],v[0]+hull);
+ pccd_M->bbmax[1] = MAX2(pccd_M->bbmax[1],v[1]+hull);
+ pccd_M->bbmax[2] = MAX2(pccd_M->bbmax[2],v[2]+hull);
+
+ /* evaluate limits */
+ VECCOPY(v,pccd_M->mprevvert[i].co);
+ pccd_M->bbmin[0] = MIN2(pccd_M->bbmin[0],v[0]-hull);
+ pccd_M->bbmin[1] = MIN2(pccd_M->bbmin[1],v[1]-hull);
+ pccd_M->bbmin[2] = MIN2(pccd_M->bbmin[2],v[2]-hull);
+
+ pccd_M->bbmax[0] = MAX2(pccd_M->bbmax[0],v[0]+hull);
+ pccd_M->bbmax[1] = MAX2(pccd_M->bbmax[1],v[1]+hull);
+ pccd_M->bbmax[2] = MAX2(pccd_M->bbmax[2],v[2]+hull);
+
+ }
+
+ mima = pccd_M->mima;
+ mface = pccd_M->mface;
+
+
+ /* anyhoo we need to walk the list of faces and find OBB they live in */
+ for(i=0; i < pccd_M->totface; i++){
+ mima->minx=mima->miny=mima->minz=1e30f;
+ mima->maxx=mima->maxy=mima->maxz=-1e30f;
+
+ VECCOPY(v,pccd_M->mvert[mface->v1].co);
+ mima->minx = MIN2(mima->minx,v[0]-hull);
+ mima->miny = MIN2(mima->miny,v[1]-hull);
+ mima->minz = MIN2(mima->minz,v[2]-hull);
+ mima->maxx = MAX2(mima->maxx,v[0]+hull);
+ mima->maxy = MAX2(mima->maxy,v[1]+hull);
+ mima->maxz = MAX2(mima->maxz,v[2]+hull);
+
+ VECCOPY(v,pccd_M->mvert[mface->v2].co);
+ mima->minx = MIN2(mima->minx,v[0]-hull);
+ mima->miny = MIN2(mima->miny,v[1]-hull);
+ mima->minz = MIN2(mima->minz,v[2]-hull);
+ mima->maxx = MAX2(mima->maxx,v[0]+hull);
+ mima->maxy = MAX2(mima->maxy,v[1]+hull);
+ mima->maxz = MAX2(mima->maxz,v[2]+hull);
+
+ VECCOPY(v,pccd_M->mvert[mface->v3].co);
+ mima->minx = MIN2(mima->minx,v[0]-hull);
+ mima->miny = MIN2(mima->miny,v[1]-hull);
+ mima->minz = MIN2(mima->minz,v[2]-hull);
+ mima->maxx = MAX2(mima->maxx,v[0]+hull);
+ mima->maxy = MAX2(mima->maxy,v[1]+hull);
+ mima->maxz = MAX2(mima->maxz,v[2]+hull);
+
+ if(mface->v4){
+ VECCOPY(v,pccd_M->mvert[mface->v4].co);
+ mima->minx = MIN2(mima->minx,v[0]-hull);
+ mima->miny = MIN2(mima->miny,v[1]-hull);
+ mima->minz = MIN2(mima->minz,v[2]-hull);
+ mima->maxx = MAX2(mima->maxx,v[0]+hull);
+ mima->maxy = MAX2(mima->maxy,v[1]+hull);
+ mima->maxz = MAX2(mima->maxz,v[2]+hull);
+ }
+
+
+ VECCOPY(v,pccd_M->mprevvert[mface->v1].co);
+ mima->minx = MIN2(mima->minx,v[0]-hull);
+ mima->miny = MIN2(mima->miny,v[1]-hull);
+ mima->minz = MIN2(mima->minz,v[2]-hull);
+ mima->maxx = MAX2(mima->maxx,v[0]+hull);
+ mima->maxy = MAX2(mima->maxy,v[1]+hull);
+ mima->maxz = MAX2(mima->maxz,v[2]+hull);
+
+ VECCOPY(v,pccd_M->mprevvert[mface->v2].co);
+ mima->minx = MIN2(mima->minx,v[0]-hull);
+ mima->miny = MIN2(mima->miny,v[1]-hull);
+ mima->minz = MIN2(mima->minz,v[2]-hull);
+ mima->maxx = MAX2(mima->maxx,v[0]+hull);
+ mima->maxy = MAX2(mima->maxy,v[1]+hull);
+ mima->maxz = MAX2(mima->maxz,v[2]+hull);
+
+ VECCOPY(v,pccd_M->mprevvert[mface->v3].co);
+ mima->minx = MIN2(mima->minx,v[0]-hull);
+ mima->miny = MIN2(mima->miny,v[1]-hull);
+ mima->minz = MIN2(mima->minz,v[2]-hull);
+ mima->maxx = MAX2(mima->maxx,v[0]+hull);
+ mima->maxy = MAX2(mima->maxy,v[1]+hull);
+ mima->maxz = MAX2(mima->maxz,v[2]+hull);
+
+ if(mface->v4){
+ VECCOPY(v,pccd_M->mprevvert[mface->v4].co);
+ mima->minx = MIN2(mima->minx,v[0]-hull);
+ mima->miny = MIN2(mima->miny,v[1]-hull);
+ mima->minz = MIN2(mima->minz,v[2]-hull);
+ mima->maxx = MAX2(mima->maxx,v[0]+hull);
+ mima->maxy = MAX2(mima->maxy,v[1]+hull);
+ mima->maxz = MAX2(mima->maxz,v[2]+hull);
+ }
+
+
+ mima++;
+ mface++;
+
+ }
+ return ;
+}
+
+void ccd_mesh_free(ccd_Mesh *ccdm)
+{
+ if(ccdm && (ccdm->savety == CCD_SAVETY )){ /*make sure we're not nuking objects we don't know*/
+ MEM_freeN(ccdm->mface);
+ MEM_freeN(ccdm->mvert);
+ if (ccdm->mprevvert) MEM_freeN(ccdm->mprevvert);
+ MEM_freeN(ccdm->mima);
+ MEM_freeN(ccdm);
+ ccdm = NULL;
+ }
+}
+
+void ccd_build_deflector_hache(Object *vertexowner,GHash *hash)
+{
+ Base *base;
+ Object *ob;
+ base= G.scene->base.first;
+ base= G.scene->base.first;
+ if (!hash) return;
+ while (base) {
+ /*Only proceed for mesh object in same layer */
+ if(base->object->type==OB_MESH && (base->lay & vertexowner->lay)) {
+ ob= base->object;
+ if((vertexowner) && (ob == vertexowner)){
+ /* if vertexowner is given we don't want to check collision with owner object */
+ base = base->next;
+ continue;
+ }
+
+ /*+++ only with deflecting set */
+ if(ob->pd && ob->pd->deflect && BLI_ghash_lookup(hash, ob) == 0) {
+ DerivedMesh *dm= NULL;
+
+ if(ob->softflag & OB_SB_COLLFINAL) { /* so maybe someone wants overkill to collide with subsurfed */
+ dm = mesh_get_derived_final(ob, CD_MASK_BAREMESH);
+ } else {
+ dm = mesh_get_derived_deform(ob, CD_MASK_BAREMESH);
+ }
+
+ if(dm){
+ ccd_Mesh *ccdmesh = ccd_mesh_make(ob, dm);
+ BLI_ghash_insert(hash, ob, ccdmesh);
+
+ /* we did copy & modify all we need so give 'em away again */
+ dm->release(dm);
+
+ }
+ }/*--- only with deflecting set */
+
+ }/* mesh && layer*/
+ base = base->next;
+ } /* while (base) */
+}
+
+void ccd_update_deflector_hache(Object *vertexowner,GHash *hash)
+{
+ Base *base;
+ Object *ob;
+ base= G.scene->base.first;
+ base= G.scene->base.first;
+ if ((!hash) || (!vertexowner)) return;
+ while (base) {
+ /*Only proceed for mesh object in same layer */
+ if(base->object->type==OB_MESH && (base->lay & vertexowner->lay)) {
+ ob= base->object;
+ if(ob == vertexowner){
+ /* if vertexowner is given we don't want to check collision with owner object */
+ base = base->next;
+ continue;
+ }
+
+ /*+++ only with deflecting set */
+ if(ob->pd && ob->pd->deflect) {
+ DerivedMesh *dm= NULL;
+
+ if(ob->softflag & OB_SB_COLLFINAL) { /* so maybe someone wants overkill to collide with subsurfed */
+ dm = mesh_get_derived_final(ob, CD_MASK_BAREMESH);
+ } else {
+ dm = mesh_get_derived_deform(ob, CD_MASK_BAREMESH);
+ }
+ if(dm){
+ ccd_Mesh *ccdmesh = BLI_ghash_lookup(hash,ob);
+ if (ccdmesh)
+ ccd_mesh_update(ob,ccdmesh,dm);
+
+ /* we did copy & modify all we need so give 'em away again */
+ dm->release(dm);
+ }
+ }/*--- only with deflecting set */
+
+ }/* mesh && layer*/
+ base = base->next;
+ } /* while (base) */
+}
+
+
+
+
+/*--- collider caching and dicing ---*/
+
+
+static int count_mesh_quads(Mesh *me)
+{
+ int a,result = 0;
+ MFace *mface= me->mface;
+
+ if(mface) {
+ for(a=me->totface; a>0; a--, mface++) {
+ if(mface->v4) result++;
+ }
+ }
+ return result;
+}
+
+static void add_mesh_quad_diag_springs(Object *ob)
+{
+ Mesh *me= ob->data;
+ MFace *mface= me->mface;
+ BodyPoint *bp;
+ BodySpring *bs, *bs_new;
+ int a ;
+
+ if (ob->soft){
+ int nofquads;
+
+ nofquads = count_mesh_quads(me);
+ if (nofquads) {
+ /* resize spring-array to hold additional quad springs */
+ bs_new= MEM_callocN( (ob->soft->totspring + nofquads *2 )*sizeof(BodySpring), "bodyspring");
+ memcpy(bs_new,ob->soft->bspring,(ob->soft->totspring )*sizeof(BodySpring));
+
+ if(ob->soft->bspring)
+ MEM_freeN(ob->soft->bspring); /* do this before reassigning the pointer or have a 1st class memory leak */
+ ob->soft->bspring = bs_new;
+
+ /* fill the tail */
+ a = 0;
+ bs = bs_new+ob->soft->totspring;
+ bp= ob->soft->bpoint;
+ if(mface ) {
+ for(a=me->totface; a>0; a--, mface++) {
+ if(mface->v4) {
+ bs->v1= mface->v1;
+ bs->v2= mface->v3;
+ bs->strength= 1.0;
+ bs->order =2;
+ bs++;
+ bs->v1= mface->v2;
+ bs->v2= mface->v4;
+ bs->strength= 1.0;
+ bs->order =2;
+ bs++;
+
+ }
+ }
+ }
+
+ /* now we can announce new springs */
+ ob->soft->totspring += nofquads *2;
+ }
+ }
+}
+
+static void add_2nd_order_roller(Object *ob,float stiffness,int *counter, int addsprings)
+{
+ /*assume we have a softbody*/
+ SoftBody *sb= ob->soft; /* is supposed to be there */
+ BodyPoint *bp,*bpo;
+ BodySpring *bs,*bs2,*bs3= NULL;
+ int a,b,c,notthis= 0,v0;
+ if (!sb->bspring){return;} /* we are 2nd order here so 1rst should have been build :) */
+ /* first run counting second run adding */
+ *counter = 0;
+ if (addsprings) bs3 = ob->soft->bspring+ob->soft->totspring;
+ for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
+ /*scan for neighborhood*/
+ bpo = NULL;
+ v0 = (sb->totpoint-a);
+ for(b=bp->nofsprings;b>0;b--){
+ bs = sb->bspring + bp->springs[b-1];
+ /*nasty thing here that springs have two ends
+ so here we have to make sure we examine the other */
+ if (( v0 == bs->v1) ){
+ bpo =sb->bpoint+bs->v2;
+ notthis = bs->v2;
+ }
+ else {
+ if (( v0 == bs->v2) ){
+ bpo =sb->bpoint+bs->v1;
+ notthis = bs->v1;
+ }
+ else {printf("oops we should not get here - add_2nd_order_springs");}
+ }
+ if (bpo){/* so now we have a 2nd order humpdidump */
+ for(c=bpo->nofsprings;c>0;c--){
+ bs2 = sb->bspring + bpo->springs[c-1];
+ if ((bs2->v1 != notthis) && (bs2->v1 > v0)){
+ (*counter)++;/*hit */
+ if (addsprings){
+ bs3->v1= v0;
+ bs3->v2= bs2->v1;
+ bs3->strength= stiffness;
+ bs3->order=2;
+ bs3++;
+ }
+ }
+ if ((bs2->v2 !=notthis)&&(bs2->v2 > v0)){
+ (*counter)++;/*hit */
+ if (addsprings){
+ bs3->v1= v0;
+ bs3->v2= bs2->v2;
+ bs3->strength= stiffness;
+ bs3->order=2;
+ bs3++;
+ }
+
+ }
+ }
+
+ }
+
+ }
+ /*scan for neighborhood done*/
+ }
+}
+
+
+static void add_2nd_order_springs(Object *ob,float stiffness)
+{
+ int counter = 0;
+ BodySpring *bs_new;
+
+ add_2nd_order_roller(ob,stiffness,&counter,0); /* counting */
+ if (counter) {
+ /* resize spring-array to hold additional springs */
+ bs_new= MEM_callocN( (ob->soft->totspring + counter )*sizeof(BodySpring), "bodyspring");
+ memcpy(bs_new,ob->soft->bspring,(ob->soft->totspring )*sizeof(BodySpring));
+
+ if(ob->soft->bspring)
+ MEM_freeN(ob->soft->bspring);
+ ob->soft->bspring = bs_new;
+
+ add_2nd_order_roller(ob,stiffness,&counter,1); /* adding */
+ ob->soft->totspring +=counter ;
+ }
+}
+
+static void add_bp_springlist(BodyPoint *bp,int springID)
+{
+ int *newlist;
+
+ if (bp->springs == NULL) {
+ bp->springs = MEM_callocN( sizeof(int), "bpsprings");
+ bp->springs[0] = springID;
+ bp->nofsprings = 1;
+ }
+ else {
+ bp->nofsprings++;
+ newlist = MEM_callocN(bp->nofsprings * sizeof(int), "bpsprings");
+ memcpy(newlist,bp->springs,(bp->nofsprings-1)* sizeof(int));
+ MEM_freeN(bp->springs);
+ bp->springs = newlist;
+ bp->springs[bp->nofsprings-1] = springID;
+ }
+}
+
+/* do this once when sb is build
+it is O(N^2) so scanning for springs every iteration is too expensive
+*/
+static void build_bps_springlist(Object *ob)
+{
+ SoftBody *sb= ob->soft; /* is supposed to be there */
+ BodyPoint *bp;
+ BodySpring *bs;
+ int a,b;
+
+ if (sb==NULL) return; /* paranoya check */
+
+ for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
+ /* throw away old list */
+ if (bp->springs) {
+ MEM_freeN(bp->springs);
+ bp->springs=NULL;
+ }
+ /* scan for attached inner springs */
+ for(b=sb->totspring, bs= sb->bspring; b>0; b--, bs++) {
+ if (( (sb->totpoint-a) == bs->v1) ){
+ add_bp_springlist(bp,sb->totspring -b);
+ }
+ if (( (sb->totpoint-a) == bs->v2) ){
+ add_bp_springlist(bp,sb->totspring -b);
+ }
+ }/*for springs*/
+ }/*for bp*/
+}
+
+static void calculate_collision_balls(Object *ob)
+{
+ SoftBody *sb= ob->soft; /* is supposed to be there */
+ BodyPoint *bp;
+ BodySpring *bs;
+ int a,b,akku_count;
+ float min,max,akku;
+
+ if (sb==NULL) return; /* paranoya check */
+
+ for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
+ bp->colball=0;
+ akku =0.0f;
+ akku_count=0;
+ min = 1e22f;
+ max = -1e22f;
+ /* first estimation based on attached */
+ for(b=bp->nofsprings;b>0;b--){
+ bs = sb->bspring + bp->springs[b-1];
+ if (bs->order == 1){
+ akku += bs->len;
+ akku_count++,
+ min = MIN2(bs->len,min);
+ max = MAX2(bs->len,max);
+ }
+ }
+
+ if (akku_count > 0) {
+ if (sb->sbc_mode == 0){
+ bp->colball=sb->colball;
+ }
+ if (sb->sbc_mode == 1){
+ bp->colball = akku/(float)akku_count*sb->colball;
+ }
+ if (sb->colball == 2){
+ bp->colball=min*sb->colball;
+ }
+ if (sb->colball == 3){
+ bp->colball=max*sb->colball;
+ }
+ if (sb->colball == 4){
+ bp->colball = (min + max)/2.0f*sb->colball;
+ }
+ }
+ else bp->colball=0;
+ }/*for bp*/
+}
+
+
+char set_octant_flags(float *ce, float *pos, float ball)
+{
+ float x,y,z;
+ char res = 0;
+ int a;
+
+ for (a=0;a<7;a++){
+ switch(a){
+ case 0: x=pos[0]; y=pos[1]; z=pos[2]; break;
+ case 1: x=pos[0]+ball; y=pos[1]; z=pos[2]; break;
+ case 2: x=pos[0]-ball; y=pos[1]; z=pos[2]; break;
+ case 3: x=pos[0]; y=pos[1]+ball; z=pos[2]; break;
+ case 4: x=pos[0]; y=pos[1]-ball; z=pos[2]; break;
+ case 5: x=pos[0]; y=pos[1]; z=pos[2]+ball; break;
+ case 6: x=pos[0]; y=pos[1]; z=pos[2]-ball; break;
+ }
+
+ x=pos[0]; y=pos[1]; z=pos[2];
+
+ if (x > ce[0]){
+ if (y > ce[1]){
+ if (z > ce[2]) res|= 1;
+ else res|= 2;
+ }
+ else{
+ if (z > ce[2]) res|= 4;
+ else res|= 8;
+ }
+ }
+
+ else{
+ if (y > ce[1]){
+ if (z > ce[2]) res|= 16;
+ else res|= 32;
+ }
+ else{
+ if (z > ce[2]) res|= 64;
+ else res|= 128;
+ }
+ }
+ }
+ return res;
+}
+
+/* creates new softbody if didn't exist yet, makes new points and springs arrays */
+static void renew_softbody(Object *ob, int totpoint, int totspring)
+{
+ SoftBody *sb;
+ int i;
+
+ if(ob->soft==NULL) ob->soft= sbNew();
+ else free_softbody_intern(ob->soft);
+ sb= ob->soft;
+
+ if(totpoint) {
+ sb->totpoint= totpoint;
+ sb->totspring= totspring;
+
+ sb->bpoint= MEM_mallocN( totpoint*sizeof(BodyPoint), "bodypoint");
+ if(totspring)
+ sb->bspring= MEM_mallocN( totspring*sizeof(BodySpring), "bodyspring");
+
+ /* initialise BodyPoint array */
+ for (i=0; i<totpoint; i++) {
+ BodyPoint *bp = &sb->bpoint[i];
+
+ if(ob->softflag & OB_SB_GOAL) {
+ bp->goal= ob->soft->defgoal;
+ }
+ else {
+ bp->goal= 0.0f;
+ /* so this will definily be below SOFTGOALSNAP */
+ }
+
+ bp->nofsprings= 0;
+ bp->springs= NULL;
+ bp->choke = 0.0f;
+ bp->colball = 0.0f;
+ bp->flag = 0;
+
+ }
+ }
+}
+
+static void free_softbody_baked(SoftBody *sb)
+{
+ SBVertex *key;
+ int k;
+
+ for(k=0; k<sb->totkey; k++) {
+ key= *(sb->keys + k);
+ if(key) MEM_freeN(key);
+ }
+ if(sb->keys) MEM_freeN(sb->keys);
+
+ sb->keys= NULL;
+ sb->totkey= 0;
+
+}
+static void free_scratch(SoftBody *sb)
+{
+ if(sb->scratch){
+ /* todo make sure everything is cleaned up nicly */
+ if (sb->scratch->colliderhash){
+ BLI_ghash_free(sb->scratch->colliderhash, NULL,
+ (GHashValFreeFP) ccd_mesh_free); /*this hoepfully will free all caches*/
+ sb->scratch->colliderhash = NULL;
+ }
+ if (sb->scratch->bodyface){
+ MEM_freeN(sb->scratch->bodyface);
+ }
+ MEM_freeN(sb->scratch);
+ sb->scratch = NULL;
+ }
+
+}
+
+/* only frees internal data */
+static void free_softbody_intern(SoftBody *sb)
+{
+ if(sb) {
+ int a;
+ BodyPoint *bp;
+
+ if(sb->bpoint){
+ for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
+ /* free spring list */
+ if (bp->springs != NULL) {
+ MEM_freeN(bp->springs);
+ }
+ }
+ MEM_freeN(sb->bpoint);
+ }
+
+ if(sb->bspring) MEM_freeN(sb->bspring);
+
+ sb->totpoint= sb->totspring= 0;
+ sb->bpoint= NULL;
+ sb->bspring= NULL;
+
+ free_scratch(sb);
+ free_softbody_baked(sb);
+ }
+}
+
+
+/* ************ dynamics ********** */
+
+/* the most general (micro physics correct) way to do collision
+** (only needs the current particle position)
+**
+** it actually checks if the particle intrudes a short range force field generated
+** by the faces of the target object and returns a force to drive the particel out
+** the strenght of the field grows exponetially if the particle is on the 'wrong' side of the face
+** 'wrong' side : projection to the face normal is negative (all referred to a vertex in the face)
+**
+** flaw of this: 'fast' particles as well as 'fast' colliding faces
+** give a 'tunnel' effect such that the particle passes through the force field
+** without ever 'seeing' it
+** this is fully compliant to heisenberg: h >= fuzzy(location) * fuzzy(time)
+** besides our h is way larger than in QM because forces propagate way slower here
+** we have to deal with fuzzy(time) in the range of 1/25 seconds (typical frame rate)
+** yup collision targets are not known here any better
+** and 1/25 second is looong compared to real collision events
+** Q: why not use 'simple' collision here like bouncing back a particle
+** --> reverting is velocity on the face normal
+** A: because our particles are not alone here
+** and need to tell their neighbours exactly what happens via spring forces
+** unless sbObjectStep( .. ) is called on sub frame timing level
+** BTW that also questions the use of a 'implicit' solvers on softbodies
+** since that would only valid for 'slow' moving collision targets and dito particles
+*/
+
+/* aye this belongs to arith.c */
+static void Vec3PlusStVec(float *v, float s, float *v1)
+{
+ v[0] += s*v1[0];
+ v[1] += s*v1[1];
+ v[2] += s*v1[2];
+}
+
+/* +++ dependancy information functions*/
+static int are_there_deflectors(unsigned int layer)
+{
+ Base *base;
+
+ for(base = G.scene->base.first; base; base= base->next) {
+ if( (base->lay & layer) && base->object->pd) {
+ if(base->object->pd->deflect)
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int query_external_colliders(Object *me)
+{
+ return(are_there_deflectors(me->lay));
+}
+
+#if 0
+static int query_external_forces(Object *me)
+{
+/* silly but true: we need to create effector cache to see if anything is in it */
+ ListBase *ec = pdInitEffectors(me,NULL);
+ int result = 0;
+ if (ec){
+ result = 1;
+ pdEndEffectors(ec); /* sorry ec, yes i'm an idiot, but i needed to know if you were there */
+ }
+ return result;
+}
+
+/*
+any of that external objects may have an IPO or something alike ..
+so unless we can ask them if they are moving we have to assume they do
+*/
+static int query_external_time(Object *me)
+{
+ if (query_external_colliders(me)) return 1;
+ if (query_external_forces(me)) return 1;
+ return 0;
+}
+static int query_internal_time(Object *me)
+{
+ if (me->softflag & OB_SB_GOAL) return 1;
+ return 0;
+}
+#endif
+/* --- dependancy information functions*/
+
+/* +++ the aabb "force" section*/
+int sb_detect_aabb_collisionCached( float force[3], unsigned int par_layer,struct Object *vertexowner,float time)
+{
+ Object *ob;
+ SoftBody *sb=vertexowner->soft;
+ GHash *hash;
+ GHashIterator *ihash;
+ float aabbmin[3],aabbmax[3];
+ int a, deflected=0;
+
+ if ((sb == NULL) || (sb->scratch ==NULL)) return 0;
+ VECCOPY(aabbmin,sb->scratch->aabbmin);
+ VECCOPY(aabbmax,sb->scratch->aabbmax);
+
+ hash = vertexowner->soft->scratch->colliderhash;
+ ihash = BLI_ghashIterator_new(hash);
+ while (!BLI_ghashIterator_isDone(ihash) ) {
+
+ ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash);
+ ob = BLI_ghashIterator_getKey (ihash);
+ /* only with deflecting set */
+ if(ob->pd && ob->pd->deflect) {
+ MFace *mface= NULL;
+ MVert *mvert= NULL;
+ MVert *mprevvert= NULL;
+ ccdf_minmax *mima= NULL;
+ if(ccdm){
+ mface= ccdm->mface;
+ mvert= ccdm->mvert;
+ mprevvert= ccdm->mprevvert;
+ mima= ccdm->mima;
+ a = ccdm->totface;
+
+ if ((aabbmax[0] < ccdm->bbmin[0]) ||
+ (aabbmax[1] < ccdm->bbmin[1]) ||
+ (aabbmax[2] < ccdm->bbmin[2]) ||
+ (aabbmin[0] > ccdm->bbmax[0]) ||
+ (aabbmin[1] > ccdm->bbmax[1]) ||
+ (aabbmin[2] > ccdm->bbmax[2]) ) {
+ /* boxes dont intersect */
+ BLI_ghashIterator_step(ihash);
+ continue;
+ }
+
+ /* so now we have the 2 boxes overlapping */
+ /* forces actually not used */
+ deflected = 2;
+
+ }
+ else{
+ /*aye that should be cached*/
+ printf("missing cache error \n");
+ BLI_ghashIterator_step(ihash);
+ continue;
+ }
+ } /* if(ob->pd && ob->pd->deflect) */
+ BLI_ghashIterator_step(ihash);
+ } /* while () */
+ BLI_ghashIterator_free(ihash);
+ return deflected;
+}
+/* --- the aabb section*/
+
+
+/* +++ the face external section*/
+
+int sb_detect_face_collisionCached(float face_v1[3],float face_v2[3],float face_v3[3],float *damp,
+ float force[3], unsigned int par_layer,struct Object *vertexowner,float time)
+{
+ Object *ob;
+ GHash *hash;
+ GHashIterator *ihash;
+ float nv1[3], nv2[3], nv3[3], nv4[3], edge1[3], edge2[3], d_nvect[3], aabbmin[3],aabbmax[3];
+ float t;
+ int a, deflected=0;
+
+ aabbmin[0] = MIN3(face_v1[0],face_v2[0],face_v3[0]);
+ aabbmin[1] = MIN3(face_v1[1],face_v2[1],face_v3[1]);
+ aabbmin[2] = MIN3(face_v1[2],face_v2[2],face_v3[2]);
+ aabbmax[0] = MAX3(face_v1[0],face_v2[0],face_v3[0]);
+ aabbmax[1] = MAX3(face_v1[1],face_v2[1],face_v3[1]);
+ aabbmax[2] = MAX3(face_v1[2],face_v2[2],face_v3[2]);
+
+ hash = vertexowner->soft->scratch->colliderhash;
+ ihash = BLI_ghashIterator_new(hash);
+ while (!BLI_ghashIterator_isDone(ihash) ) {
+
+ ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash);
+ ob = BLI_ghashIterator_getKey (ihash);
+ /* only with deflecting set */
+ if(ob->pd && ob->pd->deflect) {
+ MFace *mface= NULL;
+ MVert *mvert= NULL;
+ MVert *mprevvert= NULL;
+ ccdf_minmax *mima= NULL;
+ if(ccdm){
+ mface= ccdm->mface;
+ mvert= ccdm->mvert;
+ mprevvert= ccdm->mprevvert;
+ mima= ccdm->mima;
+ a = ccdm->totface;
+
+ if ((aabbmax[0] < ccdm->bbmin[0]) ||
+ (aabbmax[1] < ccdm->bbmin[1]) ||
+ (aabbmax[2] < ccdm->bbmin[2]) ||
+ (aabbmin[0] > ccdm->bbmax[0]) ||
+ (aabbmin[1] > ccdm->bbmax[1]) ||
+ (aabbmin[2] > ccdm->bbmax[2]) ) {
+ /* boxes dont intersect */
+ BLI_ghashIterator_step(ihash);
+ continue;
+ }
+
+ }
+ else{
+ /*aye that should be cached*/
+ printf("missing cache error \n");
+ BLI_ghashIterator_step(ihash);
+ continue;
+ }
+
+
+ /* use mesh*/
+ while (a--) {
+ if (
+ (aabbmax[0] < mima->minx) ||
+ (aabbmin[0] > mima->maxx) ||
+ (aabbmax[1] < mima->miny) ||
+ (aabbmin[1] > mima->maxy) ||
+ (aabbmax[2] < mima->minz) ||
+ (aabbmin[2] > mima->maxz)
+ ) {
+ mface++;
+ mima++;
+ continue;
+ }
+
+
+ if (mvert){
+
+ VECCOPY(nv1,mvert[mface->v1].co);
+ VECCOPY(nv2,mvert[mface->v2].co);
+ VECCOPY(nv3,mvert[mface->v3].co);
+ if (mface->v4){
+ VECCOPY(nv4,mvert[mface->v4].co);
+ }
+ if (mprevvert){
+ VecMulf(nv1,time);
+ Vec3PlusStVec(nv1,(1.0f-time),mprevvert[mface->v1].co);
+
+ VecMulf(nv2,time);
+ Vec3PlusStVec(nv2,(1.0f-time),mprevvert[mface->v2].co);
+
+ VecMulf(nv3,time);
+ Vec3PlusStVec(nv3,(1.0f-time),mprevvert[mface->v3].co);
+
+ if (mface->v4){
+ VecMulf(nv4,time);
+ Vec3PlusStVec(nv4,(1.0f-time),mprevvert[mface->v4].co);
+ }
+ }
+ }
+
+ /* switch origin to be nv2*/
+ VECSUB(edge1, nv1, nv2);
+ VECSUB(edge2, nv3, nv2);
+ Crossf(d_nvect, edge2, edge1);
+ Normalize(d_nvect);
+ if (
+ LineIntersectsTriangle(nv1, nv2, face_v1, face_v2, face_v3, &t) ||
+ LineIntersectsTriangle(nv2, nv3, face_v1, face_v2, face_v3, &t) ||
+ LineIntersectsTriangle(nv3, nv1, face_v1, face_v2, face_v3, &t) ){
+ Vec3PlusStVec(force,-1.0f,d_nvect);
+ *damp=ob->pd->pdef_sbdamp;
+ deflected = 2;
+ }
+ if (mface->v4){ /* quad */
+ /* switch origin to be nv4 */
+ VECSUB(edge1, nv3, nv4);
+ VECSUB(edge2, nv1, nv4);
+ Crossf(d_nvect, edge2, edge1);
+ Normalize(d_nvect);
+ if (
+ LineIntersectsTriangle(nv1, nv3, face_v1, face_v2, face_v3, &t) ||
+ LineIntersectsTriangle(nv3, nv4, face_v1, face_v2, face_v3, &t) ||
+ LineIntersectsTriangle(nv4, nv1, face_v1, face_v2, face_v3, &t) ){
+ Vec3PlusStVec(force,-1.0f,d_nvect);
+ *damp=ob->pd->pdef_sbdamp;
+ deflected = 2;
+ }
+ }
+ mface++;
+ mima++;
+ }/* while a */
+ } /* if(ob->pd && ob->pd->deflect) */
+ BLI_ghashIterator_step(ihash);
+ } /* while () */
+ BLI_ghashIterator_free(ihash);
+ return deflected;
+}
+
+
+
+void scan_for_ext_face_forces(Object *ob,float timenow)
+{
+ SoftBody *sb = ob->soft;
+ BodyFace *bf;
+ int a;
+ float damp;
+ float tune = -10.0f;
+ float feedback[3];
+
+ if (sb && sb->scratch->totface){
+
+
+ bf = sb->scratch->bodyface;
+ for(a=0; a<sb->scratch->totface; a++, bf++) {
+ bf->ext_force[0]=bf->ext_force[1]=bf->ext_force[2]=0.0f;
+ feedback[0]=feedback[1]=feedback[2]=0.0f;
+ bf->flag &= ~BFF_INTERSECT;
+
+ if (sb_detect_face_collisionCached(sb->bpoint[bf->v1].pos,sb->bpoint[bf->v2].pos, sb->bpoint[bf->v3].pos,
+ &damp, feedback, ob->lay ,ob , timenow)){
+ Vec3PlusStVec(bf->ext_force,tune,feedback);
+ bf->flag |= BFF_INTERSECT;
+ }
+
+ feedback[0]=feedback[1]=feedback[2]=0.0f;
+ if ((bf->v4) && (sb_detect_face_collisionCached(sb->bpoint[bf->v1].pos,sb->bpoint[bf->v3].pos, sb->bpoint[bf->v4].pos,
+ &damp, feedback, ob->lay ,ob , timenow))){
+ Vec3PlusStVec(bf->ext_force,tune,feedback);
+ bf->flag |= BFF_INTERSECT;
+ }
+ }
+
+
+
+ bf = sb->scratch->bodyface;
+ for(a=0; a<sb->scratch->totface; a++, bf++) {
+ if ( bf->flag & BFF_INTERSECT)
+ {
+ VECADD(sb->bpoint[bf->v1].force,sb->bpoint[bf->v1].force,bf->ext_force);
+ VECADD(sb->bpoint[bf->v2].force,sb->bpoint[bf->v2].force,bf->ext_force);
+ VECADD(sb->bpoint[bf->v3].force,sb->bpoint[bf->v3].force,bf->ext_force);
+ if (bf->v4){
+ VECADD(sb->bpoint[bf->v4].force,sb->bpoint[bf->v4].force,bf->ext_force);
+ }
+
+ }
+
+ }
+
+
+
+
+ }
+}
+
+/* --- the face external section*/
+
+
+/* +++ the spring external section*/
+
+int sb_detect_edge_collisionCached(float edge_v1[3],float edge_v2[3],float *damp,
+ float force[3], unsigned int par_layer,struct Object *vertexowner,float time)
+{
+ Object *ob;
+ GHash *hash;
+ GHashIterator *ihash;
+ float nv1[3], nv2[3], nv3[3], nv4[3], edge1[3], edge2[3], d_nvect[3], aabbmin[3],aabbmax[3];
+ float t,el;
+ int a, deflected=0;
+
+ aabbmin[0] = MIN2(edge_v1[0],edge_v2[0]);
+ aabbmin[1] = MIN2(edge_v1[1],edge_v2[1]);
+ aabbmin[2] = MIN2(edge_v1[2],edge_v2[2]);
+ aabbmax[0] = MAX2(edge_v1[0],edge_v2[0]);
+ aabbmax[1] = MAX2(edge_v1[1],edge_v2[1]);
+ aabbmax[2] = MAX2(edge_v1[2],edge_v2[2]);
+
+ el = VecLenf(edge_v1,edge_v2);
+
+ hash = vertexowner->soft->scratch->colliderhash;
+ ihash = BLI_ghashIterator_new(hash);
+ while (!BLI_ghashIterator_isDone(ihash) ) {
+
+ ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash);
+ ob = BLI_ghashIterator_getKey (ihash);
+ /* only with deflecting set */
+ if(ob->pd && ob->pd->deflect) {
+ MFace *mface= NULL;
+ MVert *mvert= NULL;
+ MVert *mprevvert= NULL;
+ ccdf_minmax *mima= NULL;
+ if(ccdm){
+ mface= ccdm->mface;
+ mvert= ccdm->mvert;
+ mprevvert= ccdm->mprevvert;
+ mima= ccdm->mima;
+ a = ccdm->totface;
+
+ if ((aabbmax[0] < ccdm->bbmin[0]) ||
+ (aabbmax[1] < ccdm->bbmin[1]) ||
+ (aabbmax[2] < ccdm->bbmin[2]) ||
+ (aabbmin[0] > ccdm->bbmax[0]) ||
+ (aabbmin[1] > ccdm->bbmax[1]) ||
+ (aabbmin[2] > ccdm->bbmax[2]) ) {
+ /* boxes dont intersect */
+ BLI_ghashIterator_step(ihash);
+ continue;
+ }
+
+ }
+ else{
+ /*aye that should be cached*/
+ printf("missing cache error \n");
+ BLI_ghashIterator_step(ihash);
+ continue;
+ }
+
+
+ /* use mesh*/
+ while (a--) {
+ if (
+ (aabbmax[0] < mima->minx) ||
+ (aabbmin[0] > mima->maxx) ||
+ (aabbmax[1] < mima->miny) ||
+ (aabbmin[1] > mima->maxy) ||
+ (aabbmax[2] < mima->minz) ||
+ (aabbmin[2] > mima->maxz)
+ ) {
+ mface++;
+ mima++;
+ continue;
+ }
+
+
+ if (mvert){
+
+ VECCOPY(nv1,mvert[mface->v1].co);
+ VECCOPY(nv2,mvert[mface->v2].co);
+ VECCOPY(nv3,mvert[mface->v3].co);
+ if (mface->v4){
+ VECCOPY(nv4,mvert[mface->v4].co);
+ }
+ if (mprevvert){
+ VecMulf(nv1,time);
+ Vec3PlusStVec(nv1,(1.0f-time),mprevvert[mface->v1].co);
+
+ VecMulf(nv2,time);
+ Vec3PlusStVec(nv2,(1.0f-time),mprevvert[mface->v2].co);
+
+ VecMulf(nv3,time);
+ Vec3PlusStVec(nv3,(1.0f-time),mprevvert[mface->v3].co);
+
+ if (mface->v4){
+ VecMulf(nv4,time);
+ Vec3PlusStVec(nv4,(1.0f-time),mprevvert[mface->v4].co);
+ }
+ }
+ }
+
+ /* switch origin to be nv2*/
+ VECSUB(edge1, nv1, nv2);
+ VECSUB(edge2, nv3, nv2);
+
+ Crossf(d_nvect, edge2, edge1);
+ Normalize(d_nvect);
+ if ( LineIntersectsTriangle(edge_v1, edge_v2, nv1, nv2, nv3, &t)){
+ float v1[3],v2[3];
+ float intrusiondepth,i1,i2;
+ VECSUB(v1, edge_v1, nv2);
+ VECSUB(v2, edge_v2, nv2);
+ i1 = Inpf(v1,d_nvect);
+ i2 = Inpf(v2,d_nvect);
+ intrusiondepth = -MIN2(i1,i2)/el;
+ Vec3PlusStVec(force,intrusiondepth,d_nvect);
+ *damp=ob->pd->pdef_sbdamp;
+ deflected = 2;
+ }
+ if (mface->v4){ /* quad */
+ /* switch origin to be nv4 */
+ VECSUB(edge1, nv3, nv4);
+ VECSUB(edge2, nv1, nv4);
+
+ Crossf(d_nvect, edge2, edge1);
+ Normalize(d_nvect);
+ if (LineIntersectsTriangle( edge_v1, edge_v2,nv1, nv3, nv4, &t)){
+ float v1[3],v2[3];
+ float intrusiondepth,i1,i2;
+ VECSUB(v1, edge_v1, nv4);
+ VECSUB(v2, edge_v2, nv4);
+ i1 = Inpf(v1,d_nvect);
+ i2 = Inpf(v2,d_nvect);
+ intrusiondepth = -MIN2(i1,i2)/el;
+
+
+ Vec3PlusStVec(force,intrusiondepth,d_nvect);
+ *damp=ob->pd->pdef_sbdamp;
+ deflected = 2;
+ }
+ }
+ mface++;
+ mima++;
+ }/* while a */
+ } /* if(ob->pd && ob->pd->deflect) */
+ BLI_ghashIterator_step(ihash);
+ } /* while () */
+ BLI_ghashIterator_free(ihash);
+ return deflected;
+}
+
+
+void scan_for_ext_spring_forces(Object *ob,float timenow)
+{
+ SoftBody *sb = ob->soft;
+ ListBase *do_effector;
+ int a;
+ float damp;
+ float feedback[3];
+ do_effector= pdInitEffectors(ob,NULL);
+
+ if (sb && sb->totspring){
+ for(a=0; a<sb->totspring; a++) {
+ BodySpring *bs = &sb->bspring[a];
+ bs->ext_force[0]=bs->ext_force[1]=bs->ext_force[2]=0.0f;
+ feedback[0]=feedback[1]=feedback[2]=0.0f;
+ bs->flag &= ~BSF_INTERSECT;
+
+ if (bs->order ==1){
+ /* +++ springs colliding */
+ if (ob->softflag & OB_SB_EDGECOLL){
+ if ( sb_detect_edge_collisionCached (sb->bpoint[bs->v1].pos , sb->bpoint[bs->v2].pos,
+ &damp,feedback,ob->lay,ob,timenow)){
+ VecAddf(bs->ext_force,bs->ext_force,feedback);
+ bs->flag |= BSF_INTERSECT;
+ //bs->cf=damp;
+ bs->cf=sb->choke*0.01f;
+
+ }
+ }
+ /* ---- springs colliding */
+
+ /* +++ springs seeing wind ... n stuff depending on their orientation*/
+ /* note we don't use sb->mediafrict but use sb->aeroedge for magnitude of effect*/
+ if(sb->aeroedge){
+ float vel[3],sp[3],pr[3],force[3];
+ float f,windfactor = 250.0f;
+ /*see if we have wind*/
+ if(do_effector) {
+ float speed[3]={0.0f,0.0f,0.0f};
+ float pos[3];
+ VecMidf(pos, sb->bpoint[bs->v1].pos , sb->bpoint[bs->v2].pos);
+ VecMidf(vel, sb->bpoint[bs->v1].vec , sb->bpoint[bs->v2].vec);
+ pdDoEffectors(do_effector, pos, force, speed, (float)G.scene->r.cfra, 0.0f, PE_WIND_AS_SPEED);
+ VecMulf(speed,windfactor);
+ VecAddf(vel,vel,speed);
+ }
+ /* media in rest */
+ else{
+ VECADD(vel, sb->bpoint[bs->v1].vec , sb->bpoint[bs->v2].vec);
+ }
+ f = Normalize(vel);
+ f = -0.0001f*f*f*sb->aeroedge;
+ /* todo add a nice angle dependant function */
+ /* look up one at bergman scheafer */
+
+ VECSUB(sp, sb->bpoint[bs->v1].pos , sb->bpoint[bs->v2].pos);
+ Projf(pr,vel,sp);
+ VECSUB(vel,vel,pr);
+ Normalize(vel);
+ Vec3PlusStVec(bs->ext_force,f,vel);
+ }
+ /* --- springs seeing wind */
+ }
+ }
+ }
+ if(do_effector)
+ pdEndEffectors(do_effector);
+}
+/* --- the spring external section*/
+
+int choose_winner(float*w, float* pos,float*a,float*b,float*c,float*ca,float*cb,float*cc)
+{
+ float mindist,cp;
+ int winner =1;
+ mindist = ABS(Inpf(pos,a));
+
+ cp = ABS(Inpf(pos,b));
+ if ( mindist < cp ){
+ mindist = cp;
+ winner =2;
+ }
+
+ cp = ABS(Inpf(pos,c));
+ if (mindist < cp ){
+ mindist = cp;
+ winner =3;
+ }
+ switch (winner){
+ case 1: VECCOPY(w,ca); break;
+ case 2: VECCOPY(w,cb); break;
+ case 3: VECCOPY(w,cc);
+ }
+ return(winner);
+}
+
+
+
+int sb_detect_vertex_collisionCached(float opco[3], float facenormal[3], float *damp,
+ float force[3], unsigned int par_layer,struct Object *vertexowner,
+ float time,float vel[3], float *intrusion)
+{
+ Object *ob= NULL;
+ GHash *hash;
+ GHashIterator *ihash;
+ float nv1[3], nv2[3], nv3[3], nv4[3], edge1[3], edge2[3],d_nvect[3], dv1[3],ve[3],avel[3],
+ vv1[3], vv2[3], vv3[3], vv4[3], coledge[3], mindistedge = 1000.0f,
+ outerforceaccu[3],innerforceaccu[3],
+ facedist,n_mag,force_mag_norm,minx,miny,minz,maxx,maxy,maxz,
+ innerfacethickness = -0.5f, outerfacethickness = 0.2f,
+ ee = 5.0f, ff = 0.1f, fa=1;
+ int a, deflected=0, cavel=0,ci=0;
+/* init */
+ *intrusion = 0.0f;
+ hash = vertexowner->soft->scratch->colliderhash;
+ ihash = BLI_ghashIterator_new(hash);
+ outerforceaccu[0]=outerforceaccu[1]=outerforceaccu[2]=0.0f;
+ innerforceaccu[0]=innerforceaccu[1]=innerforceaccu[2]=0.0f;
+/* go */
+ while (!BLI_ghashIterator_isDone(ihash) ) {
+
+ ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash);
+ ob = BLI_ghashIterator_getKey (ihash);
+ /* only with deflecting set */
+ if(ob->pd && ob->pd->deflect) {
+ MFace *mface= NULL;
+ MVert *mvert= NULL;
+ MVert *mprevvert= NULL;
+ ccdf_minmax *mima= NULL;
+
+ if(ccdm){
+ mface= ccdm->mface;
+ mvert= ccdm->mvert;
+ mprevvert= ccdm->mprevvert;
+ mima= ccdm->mima;
+ a = ccdm->totface;
+
+ minx =ccdm->bbmin[0];
+ miny =ccdm->bbmin[1];
+ minz =ccdm->bbmin[2];
+
+ maxx =ccdm->bbmax[0];
+ maxy =ccdm->bbmax[1];
+ maxz =ccdm->bbmax[2];
+
+ if ((opco[0] < minx) ||
+ (opco[1] < miny) ||
+ (opco[2] < minz) ||
+ (opco[0] > maxx) ||
+ (opco[1] > maxy) ||
+ (opco[2] > maxz) ) {
+ /* outside the padded boundbox --> collision object is too far away */
+ BLI_ghashIterator_step(ihash);
+ continue;
+ }
+ }
+ else{
+ /*aye that should be cached*/
+ printf("missing cache error \n");
+ BLI_ghashIterator_step(ihash);
+ continue;
+ }
+
+ /* do object level stuff */
+ /* need to have user control for that since it depends on model scale */
+ innerfacethickness =-ob->pd->pdef_sbift;
+ outerfacethickness =ob->pd->pdef_sboft;
+ fa = (ff*outerfacethickness-outerfacethickness);
+ fa *= fa;
+ fa = 1.0f/fa;
+ avel[0]=avel[1]=avel[2]=0.0f;
+ /* use mesh*/
+ while (a--) {
+ if (
+ (opco[0] < mima->minx) ||
+ (opco[0] > mima->maxx) ||
+ (opco[1] < mima->miny) ||
+ (opco[1] > mima->maxy) ||
+ (opco[2] < mima->minz) ||
+ (opco[2] > mima->maxz)
+ ) {
+ mface++;
+ mima++;
+ continue;
+ }
+
+ if (mvert){
+
+ VECCOPY(nv1,mvert[mface->v1].co);
+ VECCOPY(nv2,mvert[mface->v2].co);
+ VECCOPY(nv3,mvert[mface->v3].co);
+ if (mface->v4){
+ VECCOPY(nv4,mvert[mface->v4].co);
+ }
+
+ if (mprevvert){
+ /* grab the average speed of the collider vertices
+ before we spoil nvX
+ humm could be done once a SB steps but then we' need to store that too
+ since the AABB reduced propabitlty to get here drasticallly
+ it might be a nice tradeof CPU <--> memory
+ */
+ VECSUB(vv1,nv1,mprevvert[mface->v1].co);
+ VECSUB(vv2,nv2,mprevvert[mface->v2].co);
+ VECSUB(vv3,nv3,mprevvert[mface->v3].co);
+ if (mface->v4){
+ VECSUB(vv4,nv4,mprevvert[mface->v4].co);
+ }
+
+ VecMulf(nv1,time);
+ Vec3PlusStVec(nv1,(1.0f-time),mprevvert[mface->v1].co);
+
+ VecMulf(nv2,time);
+ Vec3PlusStVec(nv2,(1.0f-time),mprevvert[mface->v2].co);
+
+ VecMulf(nv3,time);
+ Vec3PlusStVec(nv3,(1.0f-time),mprevvert[mface->v3].co);
+
+ if (mface->v4){
+ VecMulf(nv4,time);
+ Vec3PlusStVec(nv4,(1.0f-time),mprevvert[mface->v4].co);
+ }
+ }
+ }
+
+ /* switch origin to be nv2*/
+ VECSUB(edge1, nv1, nv2);
+ VECSUB(edge2, nv3, nv2);
+ VECSUB(dv1,opco,nv2); /* abuse dv1 to have vertex in question at *origin* of triangle */
+
+ Crossf(d_nvect, edge2, edge1);
+ n_mag = Normalize(d_nvect);
+ facedist = Inpf(dv1,d_nvect);
+ // so rules are
+ //
+
+ if ((facedist > innerfacethickness) && (facedist < outerfacethickness)){
+ if (point_in_tri_prism(opco, nv1, nv2, nv3) ){
+ force_mag_norm =(float)exp(-ee*facedist);
+ if (facedist > outerfacethickness*ff)
+ force_mag_norm =(float)force_mag_norm*fa*(facedist - outerfacethickness)*(facedist - outerfacethickness);
+ *damp=ob->pd->pdef_sbdamp;
+ if (facedist > 0.0f){
+ *damp *= (1.0f - facedist/outerfacethickness);
+ Vec3PlusStVec(outerforceaccu,force_mag_norm,d_nvect);
+ deflected = 3;
+
+ }
+ else {
+ Vec3PlusStVec(innerforceaccu,force_mag_norm,d_nvect);
+ if (deflected < 2) deflected = 2;
+ }
+ if ((mprevvert) && (*damp > 0.0f)){
+ choose_winner(ve,opco,nv1,nv2,nv3,vv1,vv2,vv3);
+ VECADD(avel,avel,ve);
+ cavel ++;
+ }
+ *intrusion += facedist;
+ ci++;
+ }
+ }
+ if (mface->v4){ /* quad */
+ /* switch origin to be nv4 */
+ VECSUB(edge1, nv3, nv4);
+ VECSUB(edge2, nv1, nv4);
+ VECSUB(dv1,opco,nv4); /* abuse dv1 to have vertex in question at *origin* of triangle */
+
+ Crossf(d_nvect, edge2, edge1);
+ n_mag = Normalize(d_nvect);
+ facedist = Inpf(dv1,d_nvect);
+
+ if ((facedist > innerfacethickness) && (facedist < outerfacethickness)){
+ if (point_in_tri_prism(opco, nv1, nv3, nv4) ){
+ force_mag_norm =(float)exp(-ee*facedist);
+ if (facedist > outerfacethickness*ff)
+ force_mag_norm =(float)force_mag_norm*fa*(facedist - outerfacethickness)*(facedist - outerfacethickness);
+ *damp=ob->pd->pdef_sbdamp;
+ if (facedist > 0.0f){
+ *damp *= (1.0f - facedist/outerfacethickness);
+ Vec3PlusStVec(outerforceaccu,force_mag_norm,d_nvect);
+ deflected = 3;
+
+ }
+ else {
+ Vec3PlusStVec(innerforceaccu,force_mag_norm,d_nvect);
+ if (deflected < 2) deflected = 2;
+ }
+
+ if ((mprevvert) && (*damp > 0.0f)){
+ choose_winner(ve,opco,nv1,nv3,nv4,vv1,vv3,vv4);
+ VECADD(avel,avel,ve);
+ cavel ++;
+ }
+ *intrusion += facedist;
+ ci++;
+ }
+
+ }
+ if ((deflected < 2)&& (G.rt != 444)) // we did not hit a face until now
+ { // see if 'outer' hits an edge
+ float dist;
+
+ PclosestVL3Dfl(ve, opco, nv1, nv2);
+ VECSUB(ve,opco,ve);
+ dist = Normalize(ve);
+ if ((dist < outerfacethickness)&&(dist < mindistedge )){
+ VECCOPY(coledge,ve);
+ mindistedge = dist,
+ deflected=1;
+ }
+
+ PclosestVL3Dfl(ve, opco, nv2, nv3);
+ VECSUB(ve,opco,ve);
+ dist = Normalize(ve);
+ if ((dist < outerfacethickness)&&(dist < mindistedge )){
+ VECCOPY(coledge,ve);
+ mindistedge = dist,
+ deflected=1;
+ }
+
+ PclosestVL3Dfl(ve, opco, nv3, nv1);
+ VECSUB(ve,opco,ve);
+ dist = Normalize(ve);
+ if ((dist < outerfacethickness)&&(dist < mindistedge )){
+ VECCOPY(coledge,ve);
+ mindistedge = dist,
+ deflected=1;
+ }
+ if (mface->v4){ /* quad */
+ PclosestVL3Dfl(ve, opco, nv3, nv4);
+ VECSUB(ve,opco,ve);
+ dist = Normalize(ve);
+ if ((dist < outerfacethickness)&&(dist < mindistedge )){
+ VECCOPY(coledge,ve);
+ mindistedge = dist,
+ deflected=1;
+ }
+
+ PclosestVL3Dfl(ve, opco, nv1, nv4);
+ VECSUB(ve,opco,ve);
+ dist = Normalize(ve);
+ if ((dist < outerfacethickness)&&(dist < mindistedge )){
+ VECCOPY(coledge,ve);
+ mindistedge = dist,
+ deflected=1;
+ }
+
+ }
+
+
+ }
+ }
+ mface++;
+ mima++;
+ }/* while a */
+ } /* if(ob->pd && ob->pd->deflect) */
+ BLI_ghashIterator_step(ihash);
+ } /* while () */
+
+ if (deflected == 1){ // no face but 'outer' edge cylinder sees vert
+ force_mag_norm =(float)exp(-ee*mindistedge);
+ if (mindistedge > outerfacethickness*ff)
+ force_mag_norm =(float)force_mag_norm*fa*(mindistedge - outerfacethickness)*(mindistedge - outerfacethickness);
+ Vec3PlusStVec(force,force_mag_norm,coledge);
+ *damp=ob->pd->pdef_sbdamp;
+ if (mindistedge > 0.0f){
+ *damp *= (1.0f - mindistedge/outerfacethickness);
+ }
+
+ }
+ if (deflected == 2){ // face inner detected
+ VECADD(force,force,innerforceaccu);
+ }
+ if (deflected == 3){ // face outer detected
+ VECADD(force,force,outerforceaccu);
+ }
+
+ BLI_ghashIterator_free(ihash);
+ if (cavel) VecMulf(avel,1.0f/(float)cavel);
+ VECCOPY(vel,avel);
+ if (ci) *intrusion /= ci;
+ if (deflected){
+ VECCOPY(facenormal,force);
+ Normalize(facenormal);
+ }
+ return deflected;
+}
+
+/* not complete yet ..
+ try to find a pos resolving all inside collisions
+*/
+#if 0 //mute it for now
+int sb_detect_vertex_collisionCachedEx(float opco[3], float facenormal[3], float *damp,
+ float force[3], unsigned int par_layer,struct Object *vertexowner,
+ float time,float vel[3], float *intrusion)
+{
+ Object *ob;
+ GHash *hash;
+ GHashIterator *ihash;
+ float nv1[3], nv2[3], nv3[3], nv4[3], edge1[3], edge2[3],d_nvect[3], dv1[3],ve[3],avel[3],
+ vv1[3], vv2[3], vv3[3], vv4[3],
+ facedist,n_mag,force_mag_norm,minx,miny,minz,maxx,maxy,maxz,
+ innerfacethickness,outerfacethickness,
+ closestinside,
+ ee = 5.0f, ff = 0.1f, fa;
+ int a, deflected=0, cavel=0;
+/* init */
+ *intrusion = 0.0f;
+ hash = vertexowner->soft->scratch->colliderhash;
+ ihash = BLI_ghashIterator_new(hash);
+/* go */
+ while (!BLI_ghashIterator_isDone(ihash) ) {
+
+ ccd_Mesh *ccdm = BLI_ghashIterator_getValue (ihash);
+ ob = BLI_ghashIterator_getKey (ihash);
+ /* only with deflecting set */
+ if(ob->pd && ob->pd->deflect) {
+ MFace *mface= NULL;
+ MVert *mvert= NULL;
+ MVert *mprevvert= NULL;
+ ccdf_minmax *mima= NULL;
+
+ if(ccdm){
+ mface= ccdm->mface;
+ mvert= ccdm->mvert;
+ mprevvert= ccdm->mprevvert;
+ mima= ccdm->mima;
+ a = ccdm->totface;
+
+ minx =ccdm->bbmin[0];
+ miny =ccdm->bbmin[1];
+ minz =ccdm->bbmin[2];
+
+ maxx =ccdm->bbmax[0];
+ maxy =ccdm->bbmax[1];
+ maxz =ccdm->bbmax[2];
+
+ if ((opco[0] < minx) ||
+ (opco[1] < miny) ||
+ (opco[2] < minz) ||
+ (opco[0] > maxx) ||
+ (opco[1] > maxy) ||
+ (opco[2] > maxz) ) {
+ /* outside the padded boundbox --> collision object is too far away */
+ BLI_ghashIterator_step(ihash);
+ continue;
+ }
+ }
+ else{
+ /*aye that should be cached*/
+ printf("missing cache error \n");
+ BLI_ghashIterator_step(ihash);
+ continue;
+ }
+
+ /* do object level stuff */
+ /* need to have user control for that since it depends on model scale */
+ innerfacethickness =-ob->pd->pdef_sbift;
+ outerfacethickness =ob->pd->pdef_sboft;
+ closestinside = innerfacethickness;
+ fa = (ff*outerfacethickness-outerfacethickness);
+ fa *= fa;
+ fa = 1.0f/fa;
+ avel[0]=avel[1]=avel[2]=0.0f;
+ /* use mesh*/
+ while (a--) {
+ if (
+ (opco[0] < mima->minx) ||
+ (opco[0] > mima->maxx) ||
+ (opco[1] < mima->miny) ||
+ (opco[1] > mima->maxy) ||
+ (opco[2] < mima->minz) ||
+ (opco[2] > mima->maxz)
+ ) {
+ mface++;
+ mima++;
+ continue;
+ }
+
+ if (mvert){
+
+ VECCOPY(nv1,mvert[mface->v1].co);
+ VECCOPY(nv2,mvert[mface->v2].co);
+ VECCOPY(nv3,mvert[mface->v3].co);
+ if (mface->v4){
+ VECCOPY(nv4,mvert[mface->v4].co);
+ }
+
+ if (mprevvert){
+ /* grab the average speed of the collider vertices
+ before we spoil nvX
+ humm could be done once a SB steps but then we' need to store that too
+ since the AABB reduced propabitlty to get here drasticallly
+ it might be a nice tradeof CPU <--> memory
+ */
+ VECSUB(vv1,nv1,mprevvert[mface->v1].co);
+ VECSUB(vv2,nv2,mprevvert[mface->v2].co);
+ VECSUB(vv3,nv3,mprevvert[mface->v3].co);
+ if (mface->v4){
+ VECSUB(vv4,nv4,mprevvert[mface->v4].co);
+ }
+
+ VecMulf(nv1,time);
+ Vec3PlusStVec(nv1,(1.0f-time),mprevvert[mface->v1].co);
+
+ VecMulf(nv2,time);
+ Vec3PlusStVec(nv2,(1.0f-time),mprevvert[mface->v2].co);
+
+ VecMulf(nv3,time);
+ Vec3PlusStVec(nv3,(1.0f-time),mprevvert[mface->v3].co);
+
+ if (mface->v4){
+ VecMulf(nv4,time);
+ Vec3PlusStVec(nv4,(1.0f-time),mprevvert[mface->v4].co);
+ }
+ }
+ }
+
+ /* switch origin to be nv2*/
+ VECSUB(edge1, nv1, nv2);
+ VECSUB(edge2, nv3, nv2);
+ VECSUB(dv1,opco,nv2); /* abuse dv1 to have vertex in question at *origin* of triangle */
+
+ Crossf(d_nvect, edge2, edge1);
+ n_mag = Normalize(d_nvect);
+ facedist = Inpf(dv1,d_nvect);
+
+ if ((facedist > closestinside) && (facedist < outerfacethickness)){
+// if ((facedist > innerfacethickness) && (facedist < outerfacethickness)){
+ if (point_in_tri_prism(opco, nv1, nv2, nv3) ){
+ force_mag_norm =(float)exp(-ee*facedist);
+ if (facedist > outerfacethickness*ff)
+ force_mag_norm =(float)force_mag_norm*fa*(facedist - outerfacethickness)*(facedist - outerfacethickness);
+ *damp=ob->pd->pdef_sbdamp;
+
+ if (facedist > 0.0f){
+ *damp *= (1.0f - facedist/outerfacethickness);
+ Vec3PlusStVec(force,force_mag_norm,d_nvect);
+ if (deflected < 2){
+ deflected = 1;
+ if ((mprevvert) && (*damp > 0.0f)){
+ choose_winner(ve,opco,nv1,nv2,nv3,vv1,vv2,vv3);
+ VECADD(avel,avel,ve);
+ cavel ++;
+ }
+ }
+
+ }
+ else{
+ Vec3PlusStVec(force,force_mag_norm,d_nvect);
+ VECCOPY(facenormal,d_nvect);
+ if ((mprevvert) && (*damp > 0.0f)){
+ choose_winner(avel,opco,nv1,nv2,nv3,vv1,vv2,vv3);
+ cavel = 1;
+ deflected = 2;
+ closestinside = facedist;
+ }
+ }
+ *intrusion = facedist;
+ }
+ }
+ if (mface->v4){ /* quad */
+ /* switch origin to be nv4 */
+ VECSUB(edge1, nv3, nv4);
+ VECSUB(edge2, nv1, nv4);
+ VECSUB(dv1,opco,nv4); /* abuse dv1 to have vertex in question at *origin* of triangle */
+
+ Crossf(d_nvect, edge2, edge1);
+ n_mag = Normalize(d_nvect);
+ facedist = Inpf(dv1,d_nvect);
+
+ if ((facedist > innerfacethickness) && (facedist < outerfacethickness)){
+ if (point_in_tri_prism(opco, nv1, nv3, nv4) ){
+ force_mag_norm =(float)exp(-ee*facedist);
+ if (facedist > outerfacethickness*ff)
+ force_mag_norm =(float)force_mag_norm*fa*(facedist - outerfacethickness)*(facedist - outerfacethickness);
+ Vec3PlusStVec(force,force_mag_norm,d_nvect);
+ *damp=ob->pd->pdef_sbdamp;
+
+ if (facedist > 0.0f){
+ *damp *= (1.0f - facedist/outerfacethickness);
+ Vec3PlusStVec(force,force_mag_norm,d_nvect);
+ if (deflected < 2){
+ deflected = 1;
+ if ((mprevvert) && (*damp > 0.0f)){
+ choose_winner(ve,opco,nv1,nv3,nv4,vv1,vv3,vv4);
+ VECADD(avel,avel,ve);
+ cavel ++;
+ }
+ }
+
+ }
+ else{
+ Vec3PlusStVec(force,force_mag_norm,d_nvect);
+ VECCOPY(facenormal,d_nvect);
+ if ((mprevvert) && (*damp > 0.0f)){
+ choose_winner(avel,opco,nv1,nv3,nv4,vv1,vv3,vv4);
+ cavel = 1;
+ deflected = 2;
+ closestinside = facedist;
+ }
+ }
+
+
+
+ *intrusion = facedist;
+ }
+
+ }
+ }
+ mface++;
+ mima++;
+ }/* while a */
+ } /* if(ob->pd && ob->pd->deflect) */
+ BLI_ghashIterator_step(ihash);
+ } /* while () */
+ BLI_ghashIterator_free(ihash);
+ if (cavel) VecMulf(avel,1.0f/(float)cavel);
+ VECCOPY(vel,avel);
+
+ /* we did stay "outside" but have some close to contact forces
+ just to be complete fake a face normal
+ */
+ if (deflected ==1){
+ VECCOPY(facenormal,force);
+ Normalize(facenormal);
+ }
+ else{
+ facenormal[0] = facenormal[1] = facenormal[2] = 0.0f;
+ }
+ return deflected;
+}
+#endif
+
+
+
+/* sandbox to plug in various deflection algos */
+static int sb_deflect_face(Object *ob,float *actpos,float *facenormal,float *force,float *cf,float time,float *vel,float *intrusion)
+{
+ float s_actpos[3];
+ int deflected;
+ VECCOPY(s_actpos,actpos);
+ deflected= sb_detect_vertex_collisionCached(s_actpos, facenormal, cf, force , ob->lay, ob,time,vel,intrusion);
+ //deflected= sb_detect_vertex_collisionCachedEx(s_actpos, facenormal, cf, force , ob->lay, ob,time,vel,intrusion);
+ return(deflected);
+}
+
+
+static void softbody_calc_forces(Object *ob, float forcetime, float timenow)
+{
+/* rule we never alter free variables :bp->vec bp->pos in here !
+ * this will ruin adaptive stepsize AKA heun! (BM)
+ */
+ SoftBody *sb= ob->soft; /* is supposed to be there */
+ BodyPoint *bp;
+ BodyPoint *bproot;
+ BodySpring *bs;
+ ListBase *do_effector;
+ float iks, ks, kd, gravity, actspringlen, forcefactor, sd[3];
+ float fieldfactor = 1000.0f, windfactor = 250.0f;
+ float tune = sb->ballstiff;
+ int a, b, do_deflector,do_selfcollision,do_springcollision,do_aero;
+
+
+ gravity = sb->grav * sb_grav_force_scale(ob);
+
+ /* check conditions for various options */
+ do_deflector= query_external_colliders(ob);
+ do_effector= pdInitEffectors(ob,NULL);
+ do_selfcollision=((ob->softflag & OB_SB_EDGES) && (sb->bspring)&& (ob->softflag & OB_SB_SELF));
+ do_springcollision=do_deflector && (ob->softflag & OB_SB_EDGES) &&(ob->softflag & OB_SB_EDGECOLL);
+ do_aero=((sb->aeroedge)&& (ob->softflag & OB_SB_EDGES));
+
+ iks = 1.0f/(1.0f-sb->inspring)-1.0f ;/* inner spring constants function */
+ bproot= sb->bpoint; /* need this for proper spring addressing */
+
+
+
+ if (do_springcollision || do_aero) scan_for_ext_spring_forces(ob,timenow);
+ if (do_deflector) {
+ float defforce[3];
+ do_deflector = sb_detect_aabb_collisionCached(defforce,ob->lay,ob,timenow);
+ }
+
+ if (do_selfcollision ){
+ float ce[3];
+ VecMidf(ce,sb->scratch->aabbmax,sb->scratch->aabbmin);
+ for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
+ bp->octantflag = set_octant_flags(ce,bp->pos,bp->colball);
+ }
+ }
+
+ for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
+ /* clear forces accumulator */
+ bp->force[0]= bp->force[1]= bp->force[2]= 0.0;
+
+ /* naive ball self collision */
+ /* needs to be done if goal snaps or not */
+ if(do_selfcollision){
+ int attached;
+ BodyPoint *obp;
+ int c,b;
+ float velcenter[3],dvel[3],def[3];
+ float distance;
+ float compare;
+
+ for(c=sb->totpoint, obp= sb->bpoint; c>=a; c--, obp++) {
+
+ if ((bp->octantflag & obp->octantflag) == 0) continue;
+
+ compare = (obp->colball + bp->colball);
+ VecSubf(def, bp->pos, obp->pos);
+
+ /* rather check the AABBoxes before ever calulating the real distance */
+ /* mathematically it is completly nuts, but performace is pretty much (3) times faster */
+ if ((ABS(def[0]) > compare) || (ABS(def[1]) > compare) || (ABS(def[2]) > compare)) continue;
+
+ distance = Normalize(def);
+ if (distance < compare ){
+ /* exclude body points attached with a spring */
+ attached = 0;
+ for(b=obp->nofsprings;b>0;b--){
+ bs = sb->bspring + obp->springs[b-1];
+ if (( sb->totpoint-a == bs->v2) || ( sb->totpoint-a == bs->v1)){
+ attached=1;
+ continue;}
+ }
+ if (!attached){
+ float f = tune/(distance) + tune/(compare*compare)*distance - 2.0f*tune/compare ;
+
+ VecMidf(velcenter, bp->vec, obp->vec);
+ VecSubf(dvel,velcenter,bp->vec);
+ VecMulf(dvel,sb->nodemass);
+
+ Vec3PlusStVec(bp->force,sb->balldamp,dvel);
+ Vec3PlusStVec(bp->force,f*(1.0f-sb->balldamp),def);
+ /* exploit force(a,b) == -force(b,a) part2/2 */
+ VecSubf(dvel,velcenter,obp->vec);
+ VecMulf(dvel,sb->nodemass);
+
+ Vec3PlusStVec(obp->force,sb->balldamp,dvel);
+ Vec3PlusStVec(obp->force,-f*(1.0f-sb->balldamp),def);
+
+ }
+ }
+ }
+ }
+ /* naive ball self collision done */
+
+ if(bp->goal < SOFTGOALSNAP){ /* ommit this bp when it snaps */
+ float auxvect[3];
+ float velgoal[3];
+ float absvel =0, projvel= 0;
+
+ /* do goal stuff */
+ if(ob->softflag & OB_SB_GOAL) {
+ /* true elastic goal */
+ VecSubf(auxvect,bp->origT,bp->pos);
+ ks = 1.0f/(1.0f- bp->goal*sb->goalspring)-1.0f ;
+ bp->force[0]+= ks*(auxvect[0]);
+ bp->force[1]+= ks*(auxvect[1]);
+ bp->force[2]+= ks*(auxvect[2]);
+ /* calulate damping forces generated by goals*/
+ VecSubf(velgoal,bp->origS, bp->origE);
+ kd = sb->goalfrict * sb_fric_force_scale(ob) ;
+
+ if (forcetime > 0.0 ) { /* make sure friction does not become rocket motor on time reversal */
+ bp->force[0]-= kd * (velgoal[0] + bp->vec[0]);
+ bp->force[1]-= kd * (velgoal[1] + bp->vec[1]);
+ bp->force[2]-= kd * (velgoal[2] + bp->vec[2]);
+ }
+ else {
+ bp->force[0]-= kd * (velgoal[0] - bp->vec[0]);
+ bp->force[1]-= kd * (velgoal[1] - bp->vec[1]);
+ bp->force[2]-= kd * (velgoal[2] - bp->vec[2]);
+ }
+ }
+ /* done goal stuff */
+
+
+ /* gravitation */
+ bp->force[2]-= gravity*sb->nodemass; /* individual mass of node here */
+
+
+ /* particle field & vortex */
+ if(do_effector) {
+ float force[3]= {0.0f, 0.0f, 0.0f};
+ float speed[3]= {0.0f, 0.0f, 0.0f};
+ float eval_sb_fric_force_scale = sb_fric_force_scale(ob); /* just for calling function once */
+
+ pdDoEffectors(do_effector, bp->pos, force, speed, (float)G.scene->r.cfra, 0.0f, PE_WIND_AS_SPEED);
+
+ /* apply forcefield*/
+ VecMulf(force,fieldfactor* eval_sb_fric_force_scale);
+ VECADD(bp->force, bp->force, force);
+
+ /* BP friction in moving media */
+ kd= sb->mediafrict* eval_sb_fric_force_scale;
+ bp->force[0] -= kd * (bp->vec[0] + windfactor*speed[0]/eval_sb_fric_force_scale);
+ bp->force[1] -= kd * (bp->vec[1] + windfactor*speed[1]/eval_sb_fric_force_scale);
+ bp->force[2] -= kd * (bp->vec[2] + windfactor*speed[2]/eval_sb_fric_force_scale);
+ /* now we'll have nice centrifugal effect for vortex */
+
+ }
+ else {
+ /* BP friction in media (not) moving*/
+ kd= sb->mediafrict* sb_fric_force_scale(ob);
+ /* assume it to be proportional to actual velocity */
+ bp->force[0]-= bp->vec[0]*kd;
+ bp->force[1]-= bp->vec[1]*kd;
+ bp->force[2]-= bp->vec[2]*kd;
+ /* friction in media done */
+ }
+ /* +++cached collision targets */
+ bp->choke = 0.0f;
+ bp->flag &= ~SBF_DOFUZZY;
+ if(do_deflector) {
+ float cfforce[3],defforce[3] ={0.0f,0.0f,0.0f}, vel[3] = {0.0f,0.0f,0.0f}, facenormal[3], cf = 1.0f,intrusion;
+ kd = 1.0f;
+
+ if (sb_deflect_face(ob,bp->pos,facenormal,defforce,&cf,timenow,vel,&intrusion)){
+ if (intrusion < 0.0f){
+ /*bjornmose: uugh.. what an evil hack
+ violation of the 'don't touch bp->pos in here' rule
+ but works nice, like this-->
+ we predict the solution beeing out of the collider
+ in heun step No1 and leave the heun step No2 adapt to it
+ so we kind of introduced a implicit solver for this case
+ */
+ Vec3PlusStVec(bp->pos,-intrusion,facenormal);
+
+ sb->scratch->flag |= SBF_DOFUZZY;
+ bp->flag |= SBF_DOFUZZY;
+ bp->choke = sb->choke*0.01f;
+ }
+ else{
+ VECSUB(cfforce,bp->vec,vel);
+ Vec3PlusStVec(bp->force,-cf*50.0f,cfforce);
+ }
+
+ Vec3PlusStVec(bp->force,kd,defforce);
+ }
+
+ }
+ /* ---cached collision targets */
+
+ /* +++springs */
+ if(ob->softflag & OB_SB_EDGES) {
+ if (sb->bspring){ /* spring list exists at all ? */
+ for(b=bp->nofsprings;b>0;b--){
+ bs = sb->bspring + bp->springs[b-1];
+ if (do_springcollision || do_aero){
+ VecAddf(bp->force,bp->force,bs->ext_force);
+ if (bs->flag & BSF_INTERSECT)
+ bp->choke = bs->cf;
+
+ }
+
+ if (( (sb->totpoint-a) == bs->v1) ){
+ actspringlen= VecLenf( (bproot+bs->v2)->pos, bp->pos);
+ VecSubf(sd,(bproot+bs->v2)->pos, bp->pos);
+ Normalize(sd);
+
+ /* friction stuff V1 */
+ VecSubf(velgoal,bp->vec,(bproot+bs->v2)->vec);
+ kd = sb->infrict * sb_fric_force_scale(ob);
+ absvel = Normalize(velgoal);
+ projvel = ABS(Inpf(sd,velgoal));
+ kd *= absvel * projvel;
+ Vec3PlusStVec(bp->force,-kd,velgoal);
+
+ if(bs->len > 0.0f) /* check for degenerated springs */
+ forcefactor = (bs->len - actspringlen)/bs->len * iks;
+ else
+ forcefactor = actspringlen * iks;
+ forcefactor *= bs->strength;
+
+ Vec3PlusStVec(bp->force,-forcefactor,sd);
+
+ }
+
+ if (( (sb->totpoint-a) == bs->v2) ){
+ actspringlen= VecLenf( (bproot+bs->v1)->pos, bp->pos);
+ VecSubf(sd,bp->pos,(bproot+bs->v1)->pos);
+ Normalize(sd);
+
+ /* friction stuff V2 */
+ VecSubf(velgoal,bp->vec,(bproot+bs->v1)->vec);
+ kd = sb->infrict * sb_fric_force_scale(ob);
+ absvel = Normalize(velgoal);
+ projvel = ABS(Inpf(sd,velgoal));
+ kd *= absvel * projvel;
+ Vec3PlusStVec(bp->force,-kd,velgoal);
+
+ if(bs->len > 0.0)
+ forcefactor = (bs->len - actspringlen)/bs->len * iks;
+ else
+ forcefactor = actspringlen * iks;
+ forcefactor *= bs->strength;
+ Vec3PlusStVec(bp->force,+forcefactor,sd);
+ }
+ }/* loop springs */
+ }/* existing spring list */
+ }/*any edges*/
+ /* ---springs */
+ }/*omit on snap */
+ }/*loop all bp's*/
+
+
+ /* finally add forces caused by face collision */
+ if (ob->softflag & OB_SB_FACECOLL) scan_for_ext_face_forces(ob,timenow);
+ /* cleanup */
+ if(do_effector) pdEndEffectors(do_effector);
+}
+
+
+
+static void softbody_apply_forces(Object *ob, float forcetime, int mode, float *err)
+{
+ /* time evolution */
+ /* actually does an explicit euler step mode == 0 */
+ /* or heun ~ 2nd order runge-kutta steps, mode 1,2 */
+ SoftBody *sb= ob->soft; /* is supposed to be there */
+ BodyPoint *bp;
+ float dx[3],dv[3],aabbmin[3],aabbmax[3],cm[3]={0.0f,0.0f,0.0f};
+ float timeovermass;
+ float maxerrpos= 0.0f,maxerrvel = 0.0f;
+ int a,fuzzy=0;
+
+ forcetime *= sb_time_scale(ob);
+
+ aabbmin[0]=aabbmin[1]=aabbmin[2] = 1e20f;
+ aabbmax[0]=aabbmax[1]=aabbmax[2] = -1e20f;
+
+ /* claim a minimum mass for vertex */
+ if (sb->nodemass > 0.009999f) timeovermass = forcetime/sb->nodemass;
+ else timeovermass = forcetime/0.009999f;
+
+ for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
+ if(bp->goal < SOFTGOALSNAP){
+
+ /* so here is (v)' = a(cceleration) = sum(F_springs)/m + gravitation + some friction forces + more forces*/
+ /* the ( ... )' operator denotes derivate respective time */
+ /* the euler step for velocity then becomes */
+ /* v(t + dt) = v(t) + a(t) * dt */
+ bp->force[0]*= timeovermass; /* individual mass of node here */
+ bp->force[1]*= timeovermass;
+ bp->force[2]*= timeovermass;
+ /* some nasty if's to have heun in here too */
+ VECCOPY(dv,bp->force);
+
+ if (mode == 1){
+ VECCOPY(bp->prevvec, bp->vec);
+ VECCOPY(bp->prevdv, dv);
+ }
+
+ if (mode ==2){
+ /* be optimistic and execute step */
+ bp->vec[0] = bp->prevvec[0] + 0.5f * (dv[0] + bp->prevdv[0]);
+ bp->vec[1] = bp->prevvec[1] + 0.5f * (dv[1] + bp->prevdv[1]);
+ bp->vec[2] = bp->prevvec[2] + 0.5f * (dv[2] + bp->prevdv[2]);
+ /* compare euler to heun to estimate error for step sizing */
+ maxerrvel = MAX2(maxerrvel,ABS(dv[0] - bp->prevdv[0]));
+ maxerrvel = MAX2(maxerrvel,ABS(dv[1] - bp->prevdv[1]));
+ maxerrvel = MAX2(maxerrvel,ABS(dv[2] - bp->prevdv[2]));
+ }
+ else {VECADD(bp->vec, bp->vec, bp->force);}
+
+ /* so here is (x)'= v(elocity) */
+ /* the euler step for location then becomes */
+ /* x(t + dt) = x(t) + v(t) * dt */
+
+ VECCOPY(dx,bp->vec);
+ dx[0]*=forcetime;
+ dx[1]*=forcetime;
+ dx[2]*=forcetime;
+ /* again some nasty if's to have heun in here too */
+ if (mode ==1){
+ VECCOPY(bp->prevpos,bp->pos);
+ VECCOPY(bp->prevdx ,dx);
+ }
+
+ if (mode ==2){
+ bp->pos[0] = bp->prevpos[0] + 0.5f * ( dx[0] + bp->prevdx[0]);
+ bp->pos[1] = bp->prevpos[1] + 0.5f * ( dx[1] + bp->prevdx[1]);
+ bp->pos[2] = bp->prevpos[2] + 0.5f* ( dx[2] + bp->prevdx[2]);
+ maxerrpos = MAX2(maxerrpos,ABS(dx[0] - bp->prevdx[0]));
+ maxerrpos = MAX2(maxerrpos,ABS(dx[1] - bp->prevdx[1]));
+ maxerrpos = MAX2(maxerrpos,ABS(dx[2] - bp->prevdx[2]));
+
+/* bp->choke is set when we need to pull a vertex or edge out of the collider.
+ the collider object signals to get out by pushing hard. on the other hand
+ we don't want to end up in deep space so we add some <viscosity>
+ to balance that out */
+ if (bp->choke > 0.0f){
+ bp->vec[0] = bp->vec[0]*(1.0f - bp->choke);
+ bp->vec[1] = bp->vec[1]*(1.0f - bp->choke);
+ bp->vec[2] = bp->vec[2]*(1.0f - bp->choke);
+ }
+
+ }
+ else { VECADD(bp->pos, bp->pos, dx);}
+ }/*snap*/
+ /* so while we are looping BPs anyway do statistics on the fly */
+ aabbmin[0] = MIN2(aabbmin[0],bp->pos[0]);
+ aabbmin[1] = MIN2(aabbmin[1],bp->pos[1]);
+ aabbmin[2] = MIN2(aabbmin[2],bp->pos[2]);
+ aabbmax[0] = MAX2(aabbmax[0],bp->pos[0]);
+ aabbmax[1] = MAX2(aabbmax[1],bp->pos[1]);
+ aabbmax[2] = MAX2(aabbmax[2],bp->pos[2]);
+ if (bp->flag & SBF_DOFUZZY) fuzzy =1;
+ } /*for*/
+
+ if (sb->totpoint) VecMulf(cm,1.0f/sb->totpoint);
+ if (sb->scratch){
+ VECCOPY(sb->scratch->aabbmin,aabbmin);
+ VECCOPY(sb->scratch->aabbmax,aabbmax);
+ }
+
+ if (err){ /* so step size will be controlled by biggest difference in slope */
+ if (sb->solverflags & SBSO_OLDERR)
+ *err = MAX2(maxerrpos,maxerrvel);
+ else
+ *err = maxerrpos;
+ //printf("EP %f EV %f \n",maxerrpos,maxerrvel);
+ if (fuzzy){
+ *err /= sb->fuzzyness;
+ }
+ }
+}
+
+/* used by heun when it overshoots */
+static void softbody_restore_prev_step(Object *ob)
+{
+ SoftBody *sb= ob->soft; /* is supposed to be there*/
+ BodyPoint *bp;
+ int a;
+
+ for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
+ VECCOPY(bp->vec, bp->prevvec);
+ VECCOPY(bp->pos, bp->prevpos);
+ }
+}
+
+/* care for bodypoints taken out of the 'ordinary' solver step
+** because they are screwed to goal by bolts
+** they just need to move along with the goal in time
+** we need to adjust them on sub frame timing in solver
+** so now when frame is done .. put 'em to the position at the end of frame
+*/
+static void softbody_apply_goalsnap(Object *ob)
+{
+ SoftBody *sb= ob->soft; /* is supposed to be there */
+ BodyPoint *bp;
+ int a;
+
+ for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
+ if (bp->goal >= SOFTGOALSNAP){
+ VECCOPY(bp->prevpos,bp->pos);
+ VECCOPY(bp->pos,bp->origT);
+ }
+ }
+}
+
+/* expects full initialized softbody */
+static void interpolate_exciter(Object *ob, int timescale, int time)
+{
+ SoftBody *sb= ob->soft;
+ BodyPoint *bp;
+ float f;
+ int a;
+
+ f = (float)time/(float)timescale;
+
+ for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++) {
+ bp->origT[0] = bp->origS[0] + f*(bp->origE[0] - bp->origS[0]);
+ bp->origT[1] = bp->origS[1] + f*(bp->origE[1] - bp->origS[1]);
+ bp->origT[2] = bp->origS[2] + f*(bp->origE[2] - bp->origS[2]);
+ if (bp->goal >= SOFTGOALSNAP){
+ bp->vec[0] = bp->origE[0] - bp->origS[0];
+ bp->vec[1] = bp->origE[1] - bp->origS[1];
+ bp->vec[2] = bp->origE[2] - bp->origS[2];
+ }
+ }
+
+}
+
+
+/* ************ convertors ********** */
+
+/* for each object type we need;
+ - xxxx_to_softbody(Object *ob) : a full (new) copy, creates SB geometry
+*/
+
+static void get_scalar_from_vertexgroup(Object *ob, int vertID, short groupindex, float *target)
+/* result 0 on success, else indicates error number
+-- kind of *inverse* result defintion,
+-- but this way we can signal error condition to caller
+-- and yes this function must not be here but in a *vertex group module*
+*/
+{
+ MDeformVert *dv= NULL;
+ int i;
+
+ /* spot the vert in deform vert list at mesh */
+ if(ob->type==OB_MESH) {
+ Mesh *me= ob->data;
+ if (me->dvert)
+ dv = me->dvert + vertID;
+ }
+ else if(ob->type==OB_LATTICE) { /* not yet supported in softbody btw */
+ Lattice *lt= ob->data;
+ if (lt->dvert)
+ dv = lt->dvert + vertID;
+ }
+ if(dv) {
+ /* Lets see if this vert is in the weight group */
+ for (i=0; i<dv->totweight; i++){
+ if (dv->dw[i].def_nr == groupindex){
+ *target= dv->dw[i].weight; /* got it ! */
+ break;
+ }
+ }
+ }
+}
+
+/* Resetting a Mesh SB object's springs */
+/* Spring lenght are caculted from'raw' mesh vertices that are NOT altered by modifier stack. */
+static void springs_from_mesh(Object *ob)
+{
+ SoftBody *sb;
+ Mesh *me= ob->data;
+ BodyPoint *bp;
+ int a;
+ float scale =1.0f;
+
+ sb= ob->soft;
+ if (me && sb)
+ {
+ /* using bp->origS as a container for spring calcualtions here
+ ** will be overwritten sbObjectStep() to receive
+ ** actual modifier stack positions
+ */
+ if(me->totvert) {
+ bp= ob->soft->bpoint;
+ for(a=0; a<me->totvert; a++, bp++) {
+ VECCOPY(bp->origS, me->mvert[a].co);
+ Mat4MulVecfl(ob->obmat, bp->origS);
+ }
+
+ }
+ /* recalculate spring length for meshes here */
+ /* special hidden feature! shrink to fit */
+ if (G.rt > 500){
+ scale = (G.rt - 500) / 100.0f;
+ }
+ for(a=0; a<sb->totspring; a++) {
+ BodySpring *bs = &sb->bspring[a];
+ bs->len= scale*VecLenf(sb->bpoint[bs->v1].origS, sb->bpoint[bs->v2].origS);
+ }
+ }
+}
+
+
+/* makes totally fresh start situation */
+static void mesh_to_softbody(Object *ob)
+{
+ SoftBody *sb;
+ Mesh *me= ob->data;
+ MEdge *medge= me->medge;
+ BodyPoint *bp;
+ BodySpring *bs;
+ float goalfac;
+ int a, totedge;
+ if (ob->softflag & OB_SB_EDGES) totedge= me->totedge;
+ else totedge= 0;
+
+ /* renew ends with ob->soft with points and edges, also checks & makes ob->soft */
+ renew_softbody(ob, me->totvert, totedge);
+
+ /* we always make body points */
+ sb= ob->soft;
+ bp= sb->bpoint;
+ goalfac= ABS(sb->maxgoal - sb->mingoal);
+
+ for(a=0; a<me->totvert; a++, bp++) {
+ /* get scalar values needed *per vertex* from vertex group functions,
+ so we can *paint* them nicly ..
+ they are normalized [0.0..1.0] so may be we need amplitude for scale
+ which can be done by caller but still .. i'd like it to go this way
+ */
+
+ if((ob->softflag & OB_SB_GOAL) && sb->vertgroup) {
+ get_scalar_from_vertexgroup(ob, a,(short) (sb->vertgroup-1), &bp->goal);
+ /* do this always, regardless successfull read from vertex group */
+ bp->goal= sb->mingoal + bp->goal*goalfac;
+ }
+ /* a little ad hoc changing the goal control to be less *sharp* */
+ bp->goal = (float)pow(bp->goal, 4.0f);
+
+ /* to proove the concept
+ this would enable per vertex *mass painting*
+ strcpy(name,"SOFTMASS");
+ error = get_scalar_from_named_vertexgroup(ob,name, a,&temp);
+ if (!error) bp->mass = temp * ob->rangeofmass;
+ */
+ }
+
+ /* but we only optionally add body edge springs */
+ if (ob->softflag & OB_SB_EDGES) {
+ if(medge) {
+ bs= sb->bspring;
+ for(a=me->totedge; a>0; a--, medge++, bs++) {
+ bs->v1= medge->v1;
+ bs->v2= medge->v2;
+ bs->strength= 1.0;
+ bs->order=1;
+ }
+
+
+ /* insert *diagonal* springs in quads if desired */
+ if (ob->softflag & OB_SB_QUADS) {
+ add_mesh_quad_diag_springs(ob);
+ }
+
+ build_bps_springlist(ob); /* scan for springs attached to bodypoints ONCE */
+ /* insert *other second order* springs if desired */
+ if (sb->secondspring > 0.0000001f) {
+ add_2nd_order_springs(ob,sb->secondspring); /* exploits the the first run of build_bps_springlist(ob);*/
+ build_bps_springlist(ob); /* yes we need to do it again*/
+ }
+ springs_from_mesh(ob); /* write the 'rest'-lenght of the springs */
+ if (ob->softflag & OB_SB_SELF) {calculate_collision_balls(ob);}
+
+ }
+
+ }
+
+}
+
+static void mesh_faces_to_scratch(Object *ob)
+{
+ SoftBody *sb= ob->soft;
+ Mesh *me= ob->data;
+ MFace *mface;
+ BodyFace *bodyface;
+ int a;
+ /* alloc and copy faces*/
+
+ bodyface = sb->scratch->bodyface = MEM_mallocN(sizeof(BodyFace)*me->totface,"SB_body_Faces");
+ //memcpy(sb->scratch->mface,me->mface,sizeof(MFace)*me->totface);
+ mface = me->mface;
+ for(a=0; a<me->totface; a++, mface++, bodyface++) {
+ bodyface->v1 = mface->v1;
+ bodyface->v2 = mface->v2;
+ bodyface->v3 = mface->v3;
+ bodyface->v4 = mface->v4;
+ bodyface->ext_force[0] = bodyface->ext_force[1] = bodyface->ext_force[2] = 0.0f;
+ bodyface->flag =0;
+ }
+ sb->scratch->totface = me->totface;
+}
+
+/*
+helper function to get proper spring length
+when object is rescaled
+*/
+float globallen(float *v1,float *v2,Object *ob)
+{
+ float p1[3],p2[3];
+ VECCOPY(p1,v1);
+ Mat4MulVecfl(ob->obmat, p1);
+ VECCOPY(p2,v2);
+ Mat4MulVecfl(ob->obmat, p2);
+ return VecLenf(p1,p2);
+}
+
+static void makelatticesprings(Lattice *lt, BodySpring *bs, int dostiff,Object *ob)
+{
+ BPoint *bp=lt->def, *bpu;
+ int u, v, w, dv, dw, bpc=0, bpuc;
+
+ dv= lt->pntsu;
+ dw= dv*lt->pntsv;
+
+ for(w=0; w<lt->pntsw; w++) {
+
+ for(v=0; v<lt->pntsv; v++) {
+
+ for(u=0, bpuc=0, bpu=NULL; u<lt->pntsu; u++, bp++, bpc++) {
+
+ if(w) {
+ bs->v1 = bpc;
+ bs->v2 = bpc-dw;
+ bs->strength= 1.0;
+ bs->order=1;
+ bs->len= globallen((bp-dw)->vec, bp->vec,ob);
+ bs++;
+ }
+ if(v) {
+ bs->v1 = bpc;
+ bs->v2 = bpc-dv;
+ bs->strength= 1.0;
+ bs->order=1;
+ bs->len= globallen((bp-dv)->vec, bp->vec,ob);
+ bs++;
+ }
+ if(u) {
+ bs->v1 = bpuc;
+ bs->v2 = bpc;
+ bs->strength= 1.0;
+ bs->order=1;
+ bs->len= globallen((bpu)->vec, bp->vec,ob);
+ bs++;
+ }
+
+ if (dostiff) {
+
+ if(w){
+ if( v && u ) {
+ bs->v1 = bpc;
+ bs->v2 = bpc-dw-dv-1;
+ bs->strength= 1.0;
+ bs->order=2;
+ bs->len= globallen((bp-dw-dv-1)->vec, bp->vec,ob);
+ bs++;
+ }
+ if( (v < lt->pntsv-1) && (u) ) {
+ bs->v1 = bpc;
+ bs->v2 = bpc-dw+dv-1;
+ bs->strength= 1.0;
+ bs->order=2;
+ bs->len= globallen((bp-dw+dv-1)->vec, bp->vec,ob);
+ bs++;
+ }
+ }
+
+ if(w < lt->pntsw -1){
+ if( v && u ) {
+ bs->v1 = bpc;
+ bs->v2 = bpc+dw-dv-1;
+ bs->strength= 1.0;
+ bs->order=2;
+ bs->len= globallen((bp+dw-dv-1)->vec, bp->vec,ob);
+ bs++;
+ }
+ if( (v < lt->pntsv-1) && (u) ) {
+ bs->v1 = bpc;
+ bs->v2 = bpc+dw+dv-1;
+ bs->strength= 1.0;
+ bs->order=2;
+ bs->len= globallen((bp+dw+dv-1)->vec, bp->vec,ob);
+ bs++;
+ }
+ }
+ }
+ bpu = bp;
+ bpuc = bpc;
+ }
+ }
+ }
+}
+
+
+/* makes totally fresh start situation */
+static void lattice_to_softbody(Object *ob)
+{
+ Lattice *lt= ob->data;
+ SoftBody *sb;
+ int totvert, totspring = 0;
+
+ totvert= lt->pntsu*lt->pntsv*lt->pntsw;
+
+ if (ob->softflag & OB_SB_EDGES){
+ totspring = ((lt->pntsu -1) * lt->pntsv
+ + (lt->pntsv -1) * lt->pntsu) * lt->pntsw
+ +lt->pntsu*lt->pntsv*(lt->pntsw -1);
+ if (ob->softflag & OB_SB_QUADS){
+ totspring += 4*(lt->pntsu -1) * (lt->pntsv -1) * (lt->pntsw-1);
+ }
+ }
+
+
+ /* renew ends with ob->soft with points and edges, also checks & makes ob->soft */
+ renew_softbody(ob, totvert, totspring);
+ sb= ob->soft; /* can be created in renew_softbody() */
+
+ /* weights from bpoints, same code used as for mesh vertices */
+ if((ob->softflag & OB_SB_GOAL) && sb->vertgroup) {
+ BodyPoint *bp= sb->bpoint;
+ BPoint *bpnt= lt->def;
+ float goalfac= ABS(sb->maxgoal - sb->mingoal);
+ int a;
+
+ for(a=0; a<totvert; a++, bp++, bpnt++) {
+ bp->goal= sb->mingoal + bpnt->weight*goalfac;
+ /* a little ad hoc changing the goal control to be less *sharp* */
+ bp->goal = (float)pow(bp->goal, 4.0f);
+ }
+ }
+
+ /* create some helper edges to enable SB lattice to be usefull at all */
+ if (ob->softflag & OB_SB_EDGES){
+ makelatticesprings(lt,ob->soft->bspring,ob->softflag & OB_SB_QUADS,ob);
+ build_bps_springlist(ob); /* link bps to springs */
+ }
+}
+
+/* makes totally fresh start situation */
+static void curve_surf_to_softbody(Object *ob)
+{
+ Curve *cu= ob->data;
+ SoftBody *sb;
+ BodyPoint *bp;
+ BodySpring *bs;
+ Nurb *nu;
+ BezTriple *bezt;
+ BPoint *bpnt;
+ float goalfac;
+ int a, curindex=0;
+ int totvert, totspring = 0, setgoal=0;
+
+ totvert= count_curveverts(&cu->nurb);
+
+ if (ob->softflag & OB_SB_EDGES){
+ if(ob->type==OB_CURVE) {
+ totspring= totvert - BLI_countlist(&cu->nurb);
+ }
+ }
+
+ /* renew ends with ob->soft with points and edges, also checks & makes ob->soft */
+ renew_softbody(ob, totvert, totspring);
+ sb= ob->soft; /* can be created in renew_softbody() */
+
+ /* set vars now */
+ goalfac= ABS(sb->maxgoal - sb->mingoal);
+ bp= sb->bpoint;
+ bs= sb->bspring;
+
+ /* weights from bpoints, same code used as for mesh vertices */
+ if((ob->softflag & OB_SB_GOAL) && sb->vertgroup)
+ setgoal= 1;
+
+ for(nu= cu->nurb.first; nu; nu= nu->next) {
+ if(nu->bezt) {
+ for(bezt=nu->bezt, a=0; a<nu->pntsu; a++, bezt++, bp+=3, curindex+=3) {
+ if(setgoal) {
+ bp->goal= sb->mingoal + bezt->weight*goalfac;
+ /* a little ad hoc changing the goal control to be less *sharp* */
+ bp->goal = (float)pow(bp->goal, 4.0f);
+
+ /* all three triples */
+ (bp+1)->goal= bp->goal;
+ (bp+2)->goal= bp->goal;
+ }
+
+ if(totspring) {
+ if(a>0) {
+ bs->v1= curindex-1;
+ bs->v2= curindex;
+ bs->strength= 1.0;
+ bs->order=1;
+ bs->len= globallen( (bezt-1)->vec[2], bezt->vec[0], ob );
+ bs++;
+ }
+ bs->v1= curindex;
+ bs->v2= curindex+1;
+ bs->strength= 1.0;
+ bs->order=1;
+ bs->len= globallen( bezt->vec[0], bezt->vec[1], ob );
+ bs++;
+
+ bs->v1= curindex+1;
+ bs->v2= curindex+2;
+ bs->strength= 1.0;
+ bs->order=1;
+ bs->len= globallen( bezt->vec[1], bezt->vec[2], ob );
+ bs++;
+ }
+ }
+ }
+ else {
+ for(bpnt=nu->bp, a=0; a<nu->pntsu*nu->pntsv; a++, bpnt++, bp++, curindex++) {
+ if(setgoal) {
+ bp->goal= sb->mingoal + bpnt->weight*goalfac;
+ /* a little ad hoc changing the goal control to be less *sharp* */
+ bp->goal = (float)pow(bp->goal, 4.0f);
+ }
+ if(totspring && a>0) {
+ bs->v1= curindex-1;
+ bs->v2= curindex;
+ bs->strength= 1.0;
+ bs->order=1;
+ bs->len= globallen( (bpnt-1)->vec, bpnt->vec , ob );
+ bs++;
+ }
+ }
+ }
+ }
+
+ if(totspring)
+ {
+ build_bps_springlist(ob); /* link bps to springs */
+ if (ob->softflag & OB_SB_SELF) {calculate_collision_balls(ob);}
+ }
+}
+
+
+/* copies softbody result back in object */
+static void softbody_to_object(Object *ob, float (*vertexCos)[3], int numVerts, int local)
+{
+ BodyPoint *bp= ob->soft->bpoint;
+ int a;
+
+ /* inverse matrix is not uptodate... */
+ Mat4Invert(ob->imat, ob->obmat);
+
+ for(a=0; a<numVerts; a++, bp++) {
+ VECCOPY(vertexCos[a], bp->pos);
+ if(local==0)
+ Mat4MulVecfl(ob->imat, vertexCos[a]); /* softbody is in global coords, baked optionally not */
+ }
+}
+
+/* return 1 if succesfully baked and applied step */
+static int softbody_baked_step(Object *ob, float framenr, float (*vertexCos)[3], int numVerts)
+{
+ SoftBody *sb= ob->soft;
+ SBVertex *key0, *key1, *key2, *key3;
+ BodyPoint *bp;
+ float data[4], sfra, efra, cfra, dfra, fac; /* start, end, current, delta */
+ int ofs1, a;
+
+ /* precondition check */
+ if(sb==NULL || sb->keys==NULL || sb->totkey==0) return 0;
+ /* so we got keys, but no bodypoints... even without simul we need it for the bake */
+ if(sb->bpoint==NULL) sb->bpoint= MEM_callocN( sb->totpoint*sizeof(BodyPoint), "bodypoint");
+
+ /* convert cfra time to system time */
+ sfra= (float)sb->sfra;
+ cfra= bsystem_time(ob, framenr, 0.0);
+ efra= (float)sb->efra;
+ dfra= (float)sb->interval;
+
+ /* offset in keys array */
+ ofs1= (int)floor( (cfra-sfra)/dfra );
+
+ if(ofs1 < 0) {
+ key0=key1=key2=key3= *sb->keys;
+ }
+ else if(ofs1 >= sb->totkey-1) {
+ key0=key1=key2=key3= *(sb->keys+sb->totkey-1);
+ }
+ else {
+ key1= *(sb->keys+ofs1);
+ key2= *(sb->keys+ofs1+1);
+
+ if(ofs1>0) key0= *(sb->keys+ofs1-1);
+ else key0= key1;
+
+ if(ofs1<sb->totkey-2) key3= *(sb->keys+ofs1+2);
+ else key3= key2;
+ }
+
+ sb->ctime= cfra; /* needed? */
+
+ /* timing */
+ fac= ((cfra-sfra)/dfra) - (float)ofs1;
+ CLAMP(fac, 0.0, 1.0);
+ set_four_ipo(fac, data, KEY_BSPLINE);
+ if (key0&&key1&&key2&&key3) // may be null because we SHIFT_ESCAPED
+ for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++, key0++, key1++, key2++, key3++) {
+ bp->pos[0]= data[0]*key0->vec[0] + data[1]*key1->vec[0] + data[2]*key2->vec[0] + data[3]*key3->vec[0];
+ bp->pos[1]= data[0]*key0->vec[1] + data[1]*key1->vec[1] + data[2]*key2->vec[1] + data[3]*key3->vec[1];
+ bp->pos[2]= data[0]*key0->vec[2] + data[1]*key1->vec[2] + data[2]*key2->vec[2] + data[3]*key3->vec[2];
+ }
+
+ softbody_to_object(ob, vertexCos, numVerts, sb->local);
+
+ return 1;
+}
+
+/* only gets called after succesfully doing softbody_step */
+/* already checked for OB_SB_BAKE flag */
+static void softbody_baked_add(Object *ob, float framenr)
+{
+ SoftBody *sb= ob->soft;
+ SBVertex *key;
+ BodyPoint *bp;
+ float sfra, efra, cfra, dfra, fac1; /* start, end, current, delta */
+ int ofs1, a;
+
+ /* convert cfra time to system time */
+ sfra= (float)sb->sfra;
+ fac1= ob->sf; ob->sf= 0.0f; /* disable startframe */
+ cfra= bsystem_time(ob, framenr, 0.0);
+ ob->sf= fac1;
+ efra= (float)sb->efra;
+ dfra= (float)sb->interval;
+
+ if(sb->totkey==0) {
+ if(sb->sfra >= sb->efra) return; /* safety, UI or py setting allows */
+ if(sb->interval<1) sb->interval= 1; /* just be sure */
+
+ sb->totkey= 1 + (int)(ceil( (efra-sfra)/dfra ) );
+ sb->keys= MEM_callocN( sizeof(void *)*sb->totkey, "sb keys");
+ }
+
+ /* inverse matrix might not be uptodate... */
+ Mat4Invert(ob->imat, ob->obmat);
+
+ /* now find out if we have to store a key */
+
+ /* offset in keys array */
+ if(cfra>=(efra)) {
+ ofs1= sb->totkey-1;
+ fac1= 0.0;
+ }
+ else {
+ ofs1= (int)floor( (cfra-sfra)/dfra );
+ fac1= ((cfra-sfra)/dfra) - (float)ofs1;
+ }
+ if( fac1 < 1.0/dfra ) {
+
+ key= *(sb->keys+ofs1);
+ if(key == NULL) {
+ *(sb->keys+ofs1)= key= MEM_mallocN(sb->totpoint*sizeof(SBVertex), "softbody key");
+
+ for(a=sb->totpoint, bp= sb->bpoint; a>0; a--, bp++, key++) {
+ VECCOPY(key->vec, bp->pos);
+ if(sb->local)
+ Mat4MulVecfl(ob->imat, key->vec);
+ }
+ }
+ }
+}
+/* +++ ************ maintaining scratch *************** */
+void sb_new_scratch(SoftBody *sb)
+{
+ if (!sb) return;
+ sb->scratch = MEM_callocN(sizeof(SBScratch), "SBScratch");
+ sb->scratch->colliderhash = BLI_ghash_new(BLI_ghashutil_ptrhash,BLI_ghashutil_ptrcmp);
+ sb->scratch->bodyface = NULL;
+ sb->scratch->totface = 0;
+ sb->scratch->aabbmax[0]=sb->scratch->aabbmax[1]=sb->scratch->aabbmax[2] = 1.0e30f;
+ sb->scratch->aabbmin[0]=sb->scratch->aabbmin[1]=sb->scratch->aabbmin[2] = -1.0e30f;
+
+}
+/* --- ************ maintaining scratch *************** */
+
+/* ************ Object level, exported functions *************** */
+
+/* allocates and initializes general main data */
+SoftBody *sbNew(void)
+{
+ SoftBody *sb;
+
+ sb= MEM_callocN(sizeof(SoftBody), "softbody");
+
+ sb->mediafrict= 0.5f;
+ sb->nodemass= 1.0f;
+ sb->grav= 9.8f;
+ sb->physics_speed= 1.0f;
+ sb->rklimit= 0.1f;
+
+ sb->goalspring= 0.5f;
+ sb->goalfrict= 0.0f;
+ sb->mingoal= 0.0f;
+ sb->maxgoal= 1.0f;
+ sb->defgoal= 0.7f;
+
+ sb->inspring= 0.5f;
+ sb->infrict= 0.5f;
+
+ sb->interval= 10;
+ sb->sfra= G.scene->r.sfra;
+ sb->efra= G.scene->r.efra;
+
+ sb->colball = 0.49f;
+ sb->balldamp = 0.50f;
+ sb->ballstiff= 1.0f;
+ sb->sbc_mode = 1;
+
+
+ sb->minloops = 10;
+
+ sb->choke = 3;
+ sb_new_scratch(sb);
+ return sb;
+}
+
+/* frees all */
+void sbFree(SoftBody *sb)
+{
+ free_softbody_intern(sb);
+ MEM_freeN(sb);
+}
+
+
+/* makes totally fresh start situation */
+void sbObjectToSoftbody(Object *ob)
+{
+ ob->softflag |= OB_SB_REDO;
+
+ free_softbody_intern(ob->soft);
+}
+
+static int object_has_edges(Object *ob)
+{
+ if(ob->type==OB_MESH) {
+ return ((Mesh*) ob->data)->totedge;
+ }
+ else if(ob->type==OB_LATTICE) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
+
+/* SB global visible functions */
+void sbSetInterruptCallBack(int (*f)(void))
+{
+ SB_localInterruptCallBack = f;
+}
+
+
+/* simulates one step. framenr is in frames */
+void sbObjectStep(Object *ob, float framenr, float (*vertexCos)[3], int numVerts)
+{
+ SoftBody *sb;
+ BodyPoint *bp;
+ int a;
+ float dtime,ctime,forcetime,err;
+
+ /* baking works with global time */
+ if(!(ob->softflag & OB_SB_BAKEDO) )
+ if(softbody_baked_step(ob, framenr, vertexCos, numVerts) ) return;
+
+
+ /* This part only sets goals and springs, based on original mesh/curve/lattice data.
+ Copying coordinates happens in next chunk by setting softbody flag OB_SB_RESET */
+ /* remake softbody if: */
+ if( (ob->softflag & OB_SB_REDO) || /* signal after weightpainting */
+ (ob->soft==NULL) || /* just to be nice we allow full init */
+ (ob->soft->bpoint==NULL) || /* after reading new file, or acceptable as signal to refresh */
+ (numVerts!=ob->soft->totpoint) || /* should never happen, just to be safe */
+ ((ob->softflag & OB_SB_EDGES) && !ob->soft->bspring && object_has_edges(ob))) /* happens when in UI edges was set */
+ {
+ switch(ob->type) {
+ case OB_MESH:
+ mesh_to_softbody(ob);
+ break;
+ case OB_LATTICE:
+ lattice_to_softbody(ob);
+ break;
+ case OB_CURVE:
+ case OB_SURF:
+ curve_surf_to_softbody(ob);
+ break;
+ default:
+ renew_softbody(ob, numVerts, 0);
+ break;
+ }
+
+ /* still need to update to correct vertex locations, happens on next step */
+ ob->softflag |= OB_SB_RESET;
+ ob->softflag &= ~OB_SB_REDO;
+ }
+
+ sb= ob->soft;
+
+ /* still no points? go away */
+ if(sb->totpoint==0) return;
+
+
+ /* checking time: */
+
+ ctime= bsystem_time(ob, framenr, 0.0);
+
+ if (ob->softflag&OB_SB_RESET) {
+ dtime = 0.0;
+ } else {
+ dtime= ctime - sb->ctime;
+ }
+
+ /* the simulator */
+
+ /* update the vertex locations */
+ if (dtime!=0.0) {
+ for(a=0,bp=sb->bpoint; a<numVerts; a++, bp++) {
+ /* store where goals are now */
+ VECCOPY(bp->origS, bp->origE);
+ /* copy the position of the goals at desired end time */
+ VECCOPY(bp->origE, vertexCos[a]);
+ /* vertexCos came from local world, go global */
+ Mat4MulVecfl(ob->obmat, bp->origE);
+ /* just to be save give bp->origT a defined value
+ will be calulated in interpolate_exciter()*/
+ VECCOPY(bp->origT, bp->origE);
+ }
+ }
+
+ if((ob->softflag&OB_SB_RESET) || /* got a reset signal */
+ (dtime<0.0) || /* back in time */
+ (dtime>=9.9*G.scene->r.framelen) /* too far forward in time --> goals won't be accurate enough */
+ )
+ {
+ for(a=0,bp=sb->bpoint; a<numVerts; a++, bp++) {
+ VECCOPY(bp->pos, vertexCos[a]);
+ Mat4MulVecfl(ob->obmat, bp->pos); /* yep, sofbody is global coords*/
+ VECCOPY(bp->origS, bp->pos);
+ VECCOPY(bp->origE, bp->pos);
+ VECCOPY(bp->origT, bp->pos);
+ bp->vec[0]= bp->vec[1]= bp->vec[2]= 0.0f;
+
+ /* the bp->prev*'s are for rolling back from a canceled try to propagate in time
+ adaptive step size algo in a nutshell:
+ 1. set sheduled time step to new dtime
+ 2. try to advance the sheduled time step, beeing optimistic execute it
+ 3. check for success
+ 3.a we 're fine continue, may be we can increase sheduled time again ?? if so, do so!
+ 3.b we did exceed error limit --> roll back, shorten the sheduled time and try again at 2.
+ 4. check if we did reach dtime
+ 4.a nope we need to do some more at 2.
+ 4.b yup we're done
+ */
+
+ VECCOPY(bp->prevpos, bp->pos);
+ VECCOPY(bp->prevvec, bp->vec);
+ VECCOPY(bp->prevdx, bp->vec);
+ VECCOPY(bp->prevdv, bp->vec);
+ }
+ /* make a nice clean scratch struc */
+ free_scratch(sb); /* clear if any */
+ sb_new_scratch(sb); /* make a new */
+ sb->scratch->needstobuildcollider=1;
+
+
+ /* copy some info to scratch */
+ switch(ob->type) {
+ case OB_MESH:
+ if (ob->softflag & OB_SB_FACECOLL) mesh_faces_to_scratch(ob);
+ break;
+ case OB_LATTICE:
+ break;
+ case OB_CURVE:
+ case OB_SURF:
+ break;
+ default:
+ break;
+ }
+
+
+
+ ob->softflag &= ~OB_SB_RESET;
+ }
+ else if(dtime>0.0) {
+ double sct,sst=PIL_check_seconds_timer();
+ ccd_update_deflector_hache(ob,sb->scratch->colliderhash);
+
+
+ if(sb->scratch->needstobuildcollider){
+ if (query_external_colliders(ob)){
+ ccd_build_deflector_hache(ob,sb->scratch->colliderhash);
+ }
+ sb->scratch->needstobuildcollider=0;
+ }
+
+
+ if (TRUE) { /* */
+ /* special case of 2nd order Runge-Kutta type AKA Heun */
+ float forcetimemax = 1.0f;
+ float forcetimemin = 0.001f;
+ float timedone =0.0; /* how far did we get without violating error condition */
+ /* loops = counter for emergency brake
+ * we don't want to lock up the system if physics fail
+ */
+ int loops =0 ;
+ SoftHeunTol = sb->rklimit; /* humm .. this should be calculated from sb parameters and sizes */
+ if (sb->minloops > 0) forcetimemax = 1.0f / sb->minloops;
+
+ if (sb->maxloops > 0) forcetimemin = 1.0f / sb->maxloops;
+
+
+ //forcetime = dtime; /* hope for integrating in one step */
+ forcetime =forcetimemax; /* hope for integrating in one step */
+ while ( (ABS(timedone) < ABS(dtime)) && (loops < 2000) )
+ {
+ /* set goals in time */
+ interpolate_exciter(ob,200,(int)(200.0*(timedone/dtime)));
+
+ sb->scratch->flag &= ~SBF_DOFUZZY;
+ /* do predictive euler step */
+ softbody_calc_forces(ob, forcetime,timedone/dtime);
+ softbody_apply_forces(ob, forcetime, 1, NULL);
+
+
+ /* crop new slope values to do averaged slope step */
+ softbody_calc_forces(ob, forcetime,timedone/dtime);
+ softbody_apply_forces(ob, forcetime, 2, &err);
+
+ softbody_apply_goalsnap(ob);
+
+ if (err > SoftHeunTol) { /* error needs to be scaled to some quantity */
+
+ if (forcetime > forcetimemin){
+ forcetime = MAX2(forcetime / 2.0f,forcetimemin);
+ softbody_restore_prev_step(ob);
+ //printf("down,");
+ }
+ else {
+ timedone += forcetime;
+ }
+ }
+ else {
+ float newtime = forcetime * 1.1f; /* hope for 1.1 times better conditions in next step */
+
+ if (sb->scratch->flag & SBF_DOFUZZY){
+ //if (err > SoftHeunTol/(2.0f*sb->fuzzyness)) { /* stay with this stepsize unless err really small */
+ newtime = forcetime;
+ //}
+ }
+ else {
+ if (err > SoftHeunTol/2.0f) { /* stay with this stepsize unless err really small */
+ newtime = forcetime;
+ }
+ }
+ timedone += forcetime;
+ newtime=MIN2(forcetimemax,MAX2(newtime,forcetimemin));
+ //if (newtime > forcetime) printf("up,");
+ if (forcetime > 0.0)
+ forcetime = MIN2(dtime - timedone,newtime);
+ else
+ forcetime = MAX2(dtime - timedone,newtime);
+ }
+ loops++;
+ if(sb->solverflags & SBSO_MONITOR ){
+ sct=PIL_check_seconds_timer();
+ if (sct-sst > 0.5f) printf("%3.0f%% \r",100.0f*timedone);
+ }
+ if (SB_localInterruptCallBack && SB_localInterruptCallBack()) break;
+
+ }
+ /* move snapped to final position */
+ interpolate_exciter(ob, 2, 2);
+ softbody_apply_goalsnap(ob);
+
+ // if(G.f & G_DEBUG){
+ if(sb->solverflags & SBSO_MONITOR ){
+ if (loops > HEUNWARNLIMIT) /* monitor high loop counts */
+ printf("\r needed %d steps/frame ",loops);
+ }
+
+ }
+ else{
+ /* do brute force explicit euler */
+ /* removed but left this branch for better integrators / solvers (BM) */
+ /* yah! Nicholas Guttenberg (NichG) here is the place to plug in */
+ }
+ if(sb->solverflags & SBSO_MONITOR ){
+ sct=PIL_check_seconds_timer();
+ if (sct-sst > 0.5f) printf(" solver time %f %s \r",sct-sst,ob->id.name);
+ }
+ }
+
+ softbody_to_object(ob, vertexCos, numVerts, 0);
+ sb->ctime= ctime;
+
+
+ if(ob->softflag & OB_SB_BAKEDO) softbody_baked_add(ob, framenr);
+}
+
diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c
new file mode 100644
index 00000000000..3b14cb8adac
--- /dev/null
+++ b/source/blender/blenkernel/intern/sound.c
@@ -0,0 +1,138 @@
+/**
+ * sound.c (mar-2001 nzc)
+ *
+ * $Id$
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_sound_types.h"
+#include "DNA_packedFile_types.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_sound.h"
+#include "BKE_packedFile.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+ListBase _samples = {0,0}, *samples = &_samples;
+
+void sound_free_sound(bSound *sound)
+{
+ /* when sounds have been loaded, but not played, the packedfile was not copied
+ to sample block and not freed otherwise */
+ if(sound->sample==NULL) {
+ if (sound->newpackedfile) {
+ freePackedFile(sound->newpackedfile);
+ sound->newpackedfile = NULL;
+ }
+ }
+ if (sound->stream) free(sound->stream);
+}
+
+void sound_free_sample(bSample *sample)
+{
+ if (sample) {
+ if (sample->data != &sample->fakedata[0] && sample->data != NULL) {
+ MEM_freeN(sample->data);
+ sample->data = &sample->fakedata[0];
+ }
+
+ if (sample->packedfile) {
+ freePackedFile(sample->packedfile); //FIXME: crashes sometimes
+ sample->packedfile = NULL;
+ }
+
+ if (sample->alindex != SAMPLE_INVALID) {
+// AUD_free_sample(sample->snd_sample);
+ sample->alindex = SAMPLE_INVALID;
+ }
+
+ sample->type = SAMPLE_INVALID;
+ }
+}
+
+/* this is called after file reading or undos */
+void sound_free_all_samples(void)
+{
+ bSample *sample;
+ bSound *sound;
+
+ /* ensure no sample pointers exist, and check packedfile */
+ for(sound= G.main->sound.first; sound; sound= sound->id.next) {
+ if(sound->sample && sound->sample->packedfile==sound->newpackedfile)
+ sound->newpackedfile= NULL;
+ sound->sample= NULL;
+ }
+
+ /* now free samples */
+ for(sample= samples->first; sample; sample= sample->id.next)
+ sound_free_sample(sample);
+ BLI_freelistN(samples);
+
+}
+
+void sound_set_packedfile(bSample *sample, PackedFile *pf)
+{
+ bSound *sound;
+
+ if (sample) {
+ sample->packedfile = pf;
+ sound = G.main->sound.first;
+ while (sound) {
+ if (sound->sample == sample) {
+ sound->newpackedfile = pf;
+ if (pf == NULL) {
+ strcpy(sound->name, sample->name);
+ }
+ }
+ sound = sound->id.next;
+ }
+ }
+}
+
+PackedFile* sound_find_packedfile(bSound *sound)
+{
+ bSound *search;
+ PackedFile *pf = NULL;
+ char soundname[FILE_MAXDIR + FILE_MAXFILE], searchname[FILE_MAXDIR + FILE_MAXFILE];
+
+ // convert sound->name to abolute filename
+ strcpy(soundname, sound->name);
+ BLI_convertstringcode(soundname, G.sce, G.scene->r.cfra);
+
+ search = G.main->sound.first;
+ while (search) {
+ if (search->sample && search->sample->packedfile) {
+ strcpy(searchname, search->sample->name);
+ BLI_convertstringcode(searchname, G.sce, G.scene->r.cfra);
+
+ if (BLI_streq(searchname, soundname)) {
+ pf = search->sample->packedfile;
+ break;
+ }
+ }
+
+ if (search->newpackedfile) {
+ strcpy(searchname, search->name);
+ BLI_convertstringcode(searchname, G.sce, G.scene->r.cfra);
+ if (BLI_streq(searchname, soundname)) {
+ pf = search->newpackedfile;
+ break;
+ }
+ }
+ search = search->id.next;
+ }
+
+ return (pf);
+}
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
new file mode 100644
index 00000000000..0b1563beced
--- /dev/null
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -0,0 +1,2540 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+#include <float.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_bad_level_calls.h"
+#include "BKE_cdderivedmesh.h"
+#include "BKE_customdata.h"
+#include "BKE_utildefines.h"
+#include "BKE_global.h"
+#include "BKE_mesh.h"
+#include "BKE_subsurf.h"
+#include "BKE_displist.h"
+#include "BKE_DerivedMesh.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_editVert.h"
+#include "BLI_arithb.h"
+#include "BLI_linklist.h"
+#include "BLI_memarena.h"
+#include "BLI_edgehash.h"
+
+#include "BIF_gl.h"
+
+#include "CCGSubSurf.h"
+
+typedef struct _VertData {
+ float co[3];
+ float no[3];
+} VertData;
+
+struct CCGDerivedMesh {
+ DerivedMesh dm;
+
+ CCGSubSurf *ss;
+ int drawInteriorEdges, useSubsurfUv;
+
+ struct {int startVert; CCGVert *vert;} *vertMap;
+ struct {int startVert; int startEdge; CCGEdge *edge;} *edgeMap;
+ struct {int startVert; int startEdge;
+ int startFace; CCGFace *face;} *faceMap;
+};
+
+typedef struct CCGDerivedMesh CCGDerivedMesh;
+
+static int ccgDM_getVertMapIndex(CCGDerivedMesh *ccgdm, CCGSubSurf *ss, CCGVert *v);
+static int ccgDM_getEdgeMapIndex(CCGDerivedMesh *ccgdm, CCGSubSurf *ss, CCGEdge *e);
+static int ccgDM_getFaceMapIndex(CCGDerivedMesh *ccgdm, CCGSubSurf *ss, CCGFace *f);
+
+///
+
+static void *arena_alloc(CCGAllocatorHDL a, int numBytes) {
+ return BLI_memarena_alloc(a, numBytes);
+}
+static void *arena_realloc(CCGAllocatorHDL a, void *ptr, int newSize, int oldSize) {
+ void *p2 = BLI_memarena_alloc(a, newSize);
+ if (ptr) {
+ memcpy(p2, ptr, oldSize);
+ }
+ return p2;
+}
+static void arena_free(CCGAllocatorHDL a, void *ptr) {
+}
+static void arena_release(CCGAllocatorHDL a) {
+ BLI_memarena_free(a);
+}
+
+static CCGSubSurf *_getSubSurf(CCGSubSurf *prevSS, int subdivLevels, int useAging, int useArena, int useFlatSubdiv) {
+ CCGMeshIFC ifc;
+ CCGSubSurf *ccgSS;
+
+ /* subdivLevels==0 is not allowed */
+ subdivLevels = MAX2(subdivLevels, 1);
+
+ if (prevSS) {
+ int oldUseAging;
+
+ useAging = !!useAging;
+ ccgSubSurf_getUseAgeCounts(prevSS, &oldUseAging, NULL, NULL, NULL);
+
+ if (oldUseAging!=useAging) {
+ ccgSubSurf_free(prevSS);
+ } else {
+ ccgSubSurf_setSubdivisionLevels(prevSS, subdivLevels);
+
+ return prevSS;
+ }
+ }
+
+ if (useAging) {
+ ifc.vertUserSize = ifc.edgeUserSize = ifc.faceUserSize = 12;
+ } else {
+ ifc.vertUserSize = ifc.edgeUserSize = ifc.faceUserSize = 8;
+ }
+ ifc.vertDataSize = sizeof(VertData);
+
+ if (useArena) {
+ CCGAllocatorIFC allocatorIFC;
+ CCGAllocatorHDL allocator = BLI_memarena_new((1<<16));
+
+ allocatorIFC.alloc = arena_alloc;
+ allocatorIFC.realloc = arena_realloc;
+ allocatorIFC.free = arena_free;
+ allocatorIFC.release = arena_release;
+
+ ccgSS = ccgSubSurf_new(&ifc, subdivLevels, &allocatorIFC, allocator);
+ } else {
+ ccgSS = ccgSubSurf_new(&ifc, subdivLevels, NULL, NULL);
+ }
+
+ if (useAging) {
+ ccgSubSurf_setUseAgeCounts(ccgSS, 1, 8, 8, 8);
+ }
+
+ ccgSubSurf_setCalcVertexNormals(ccgSS, 1, BLI_STRUCT_OFFSET(VertData, no));
+
+ return ccgSS;
+}
+
+static int getEdgeIndex(CCGSubSurf *ss, CCGEdge *e, int x, int edgeSize) {
+ CCGVert *v0 = ccgSubSurf_getEdgeVert0(ss, e);
+ CCGVert *v1 = ccgSubSurf_getEdgeVert1(ss, e);
+ int v0idx = *((int*) ccgSubSurf_getVertUserData(ss, v0));
+ int v1idx = *((int*) ccgSubSurf_getVertUserData(ss, v1));
+ int edgeBase = *((int*) ccgSubSurf_getEdgeUserData(ss, e));
+
+ if (x==0) {
+ return v0idx;
+ } else if (x==edgeSize-1) {
+ return v1idx;
+ } else {
+ return edgeBase + x-1;
+ }
+}
+static int getFaceIndex(CCGSubSurf *ss, CCGFace *f, int S, int x, int y, int edgeSize, int gridSize) {
+ int faceBase = *((int*) ccgSubSurf_getFaceUserData(ss, f));
+ int numVerts = ccgSubSurf_getFaceNumVerts(ss, f);
+
+ if (x==gridSize-1 && y==gridSize-1) {
+ CCGVert *v = ccgSubSurf_getFaceVert(ss, f, S);
+ return *((int*) ccgSubSurf_getVertUserData(ss, v));
+ } else if (x==gridSize-1) {
+ CCGVert *v = ccgSubSurf_getFaceVert(ss, f, S);
+ CCGEdge *e = ccgSubSurf_getFaceEdge(ss, f, S);
+ int edgeBase = *((int*) ccgSubSurf_getEdgeUserData(ss, e));
+ if (v==ccgSubSurf_getEdgeVert0(ss, e)) {
+ return edgeBase + (gridSize-1-y)-1;
+ } else {
+ return edgeBase + (edgeSize-2-1)-((gridSize-1-y)-1);
+ }
+ } else if (y==gridSize-1) {
+ CCGVert *v = ccgSubSurf_getFaceVert(ss, f, S);
+ CCGEdge *e = ccgSubSurf_getFaceEdge(ss, f, (S+numVerts-1)%numVerts);
+ int edgeBase = *((int*) ccgSubSurf_getEdgeUserData(ss, e));
+ if (v==ccgSubSurf_getEdgeVert0(ss, e)) {
+ return edgeBase + (gridSize-1-x)-1;
+ } else {
+ return edgeBase + (edgeSize-2-1)-((gridSize-1-x)-1);
+ }
+ } else if (x==0 && y==0) {
+ return faceBase;
+ } else if (x==0) {
+ S = (S+numVerts-1)%numVerts;
+ return faceBase + 1 + (gridSize-2)*S + (y-1);
+ } else if (y==0) {
+ return faceBase + 1 + (gridSize-2)*S + (x-1);
+ } else {
+ return faceBase + 1 + (gridSize-2)*numVerts + S*(gridSize-2)*(gridSize-2) + (y-1)*(gridSize-2) + (x-1);
+ }
+}
+
+static void get_face_uv_map_vert(UvVertMap *vmap, struct MFace *mf, int fi, CCGVertHDL *fverts) {
+ unsigned int *fv = &mf->v1;
+ UvMapVert *v, *nv;
+ int j, nverts= mf->v4? 4: 3;
+
+ for (j=0; j<nverts; j++, fv++) {
+ for (nv=v=get_uv_map_vert(vmap, *fv); v; v=v->next) {
+ if (v->separate)
+ nv= v;
+ if (v->f == fi)
+ break;
+ }
+
+ fverts[j]= (CCGVertHDL)(nv->f*4 + nv->tfindex);
+ }
+}
+
+static int ss_sync_from_uv(CCGSubSurf *ss, CCGSubSurf *origss, DerivedMesh *dm, MTFace *tface) {
+ MFace *mface = dm->getFaceArray(dm);
+ MVert *mvert = dm->getVertArray(dm);
+ int totvert = dm->getNumVerts(dm);
+ int totface = dm->getNumFaces(dm);
+ int i, j, seam;
+ UvMapVert *v;
+ UvVertMap *vmap;
+ float limit[2];
+ CCGVertHDL fverts[4];
+ EdgeHash *ehash;
+ float creaseFactor = (float)ccgSubSurf_getSubdivisionLevels(ss);
+
+ limit[0]= limit[1]= 0.0001f;
+ vmap= make_uv_vert_map(mface, tface, totface, totvert, 0, limit);
+ if (!vmap)
+ return 0;
+
+ ccgSubSurf_initFullSync(ss);
+
+ /* create vertices */
+ for (i=0; i<totvert; i++) {
+ if (!get_uv_map_vert(vmap, i))
+ continue;
+
+ for (v=get_uv_map_vert(vmap, i)->next; v; v=v->next)
+ if (v->separate)
+ break;
+
+ seam = (v != NULL) || ((mvert+i)->flag & ME_VERT_MERGED);
+
+ for (v=get_uv_map_vert(vmap, i); v; v=v->next) {
+ if (v->separate) {
+ CCGVert *ssv;
+ CCGVertHDL vhdl = (CCGVertHDL)(v->f*4 + v->tfindex);
+ float uv[3];
+
+ uv[0]= (tface+v->f)->uv[v->tfindex][0];
+ uv[1]= (tface+v->f)->uv[v->tfindex][1];
+ uv[2]= 0.0f;
+
+ ccgSubSurf_syncVert(ss, vhdl, uv, seam, &ssv);
+ }
+ }
+ }
+
+ /* create edges */
+ ehash = BLI_edgehash_new();
+
+ for (i=0; i<totface; i++) {
+ MFace *mf = &((MFace*) mface)[i];
+ int nverts= mf->v4? 4: 3;
+ CCGFace *origf= ccgSubSurf_getFace(origss, (CCGFaceHDL)i);
+ unsigned int *fv = &mf->v1;
+
+ get_face_uv_map_vert(vmap, mf, i, fverts);
+
+ for (j=0; j<nverts; j++) {
+ int v0 = (int)fverts[j];
+ int v1 = (int)fverts[(j+1)%nverts];
+ MVert *mv0 = mvert + *(fv+j);
+ MVert *mv1 = mvert + *(fv+((j+1)%nverts));
+
+ if (!BLI_edgehash_haskey(ehash, v0, v1)) {
+ CCGEdge *e, *orige= ccgSubSurf_getFaceEdge(origss, origf, j);
+ CCGEdgeHDL ehdl= (CCGEdgeHDL)(i*4 + j);
+ float crease;
+
+ if ((mv0->flag&mv1->flag) & ME_VERT_MERGED)
+ crease = creaseFactor;
+ else
+ crease = ccgSubSurf_getEdgeCrease(origss, orige);
+
+ ccgSubSurf_syncEdge(ss, ehdl, fverts[j], fverts[(j+1)%nverts], crease, &e);
+ BLI_edgehash_insert(ehash, v0, v1, NULL);
+ }
+ }
+ }
+
+ BLI_edgehash_free(ehash, NULL);
+
+ /* create faces */
+ for (i=0; i<totface; i++) {
+ MFace *mf = &((MFace*) mface)[i];
+ int nverts= mf->v4? 4: 3;
+ CCGFace *f;
+
+ get_face_uv_map_vert(vmap, mf, i, fverts);
+ ccgSubSurf_syncFace(ss, (CCGFaceHDL)i, nverts, fverts, &f);
+ }
+
+ free_uv_vert_map(vmap);
+ ccgSubSurf_processSync(ss);
+
+ return 1;
+}
+
+static void set_subsurf_uv(CCGSubSurf *ss, DerivedMesh *dm, DerivedMesh *result, int n)
+{
+ CCGSubSurf *uvss;
+ CCGFace **faceMap;
+ MTFace *tf;
+ CCGFaceIterator *fi;
+ int index, gridSize, gridFaces, edgeSize, totface, x, y, S;
+ MTFace *dmtface = CustomData_get_layer_n(&dm->faceData, CD_MTFACE, n);
+ MTFace *tface = CustomData_get_layer_n(&result->faceData, CD_MTFACE, n);
+
+ if(!dmtface || !tface)
+ return;
+
+ /* create a CCGSubsurf from uv's */
+ uvss = _getSubSurf(NULL, ccgSubSurf_getSubdivisionLevels(ss), 0, 1, 0);
+
+ if(!ss_sync_from_uv(uvss, ss, dm, dmtface)) {
+ ccgSubSurf_free(uvss);
+ return;
+ }
+
+ /* get some info from CCGSubsurf */
+ totface = ccgSubSurf_getNumFaces(uvss);
+ edgeSize = ccgSubSurf_getEdgeSize(uvss);
+ gridSize = ccgSubSurf_getGridSize(uvss);
+ gridFaces = gridSize - 1;
+
+ /* make a map from original faces to CCGFaces */
+ faceMap = MEM_mallocN(totface*sizeof(*faceMap), "facemapuv");
+
+ fi = ccgSubSurf_getFaceIterator(uvss);
+ for(; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) {
+ CCGFace *f = ccgFaceIterator_getCurrent(fi);
+ faceMap[(int) ccgSubSurf_getFaceFaceHandle(uvss, f)] = f;
+ }
+ ccgFaceIterator_free(fi);
+
+ /* load coordinates from uvss into tface */
+ tf= tface;
+
+ for(index = 0; index < totface; index++) {
+ CCGFace *f = faceMap[index];
+ int numVerts = ccgSubSurf_getFaceNumVerts(uvss, f);
+
+ for (S=0; S<numVerts; S++) {
+ VertData *faceGridData= ccgSubSurf_getFaceGridDataArray(uvss, f, S);
+
+ for(y = 0; y < gridFaces; y++) {
+ for(x = 0; x < gridFaces; x++) {
+ float *a = faceGridData[(y + 0)*gridSize + x + 0].co;
+ float *b = faceGridData[(y + 0)*gridSize + x + 1].co;
+ float *c = faceGridData[(y + 1)*gridSize + x + 1].co;
+ float *d = faceGridData[(y + 1)*gridSize + x + 0].co;
+
+ tf->uv[0][0] = a[0]; tf->uv[0][1] = a[1];
+ tf->uv[1][0] = d[0]; tf->uv[1][1] = d[1];
+ tf->uv[2][0] = c[0]; tf->uv[2][1] = c[1];
+ tf->uv[3][0] = b[0]; tf->uv[3][1] = b[1];
+
+ tf++;
+ }
+ }
+ }
+ }
+
+ ccgSubSurf_free(uvss);
+ MEM_freeN(faceMap);
+}
+
+#if 0
+static unsigned int ss_getEdgeFlags(CCGSubSurf *ss, CCGEdge *e, int ssFromEditmesh, DispListMesh *dlm, MEdge *medge, MTFace *tface)
+{
+ unsigned int flags = 0;
+ int N = ccgSubSurf_getEdgeNumFaces(ss, e);
+
+ if (!N) flags |= ME_LOOSEEDGE;
+
+ if (ssFromEditmesh) {
+ EditEdge *eed = ccgSubSurf_getEdgeEdgeHandle(ss, e);
+
+ flags |= ME_EDGEDRAW|ME_EDGERENDER;
+ if (eed->seam) {
+ flags |= ME_SEAM;
+ }
+ } else {
+ if (edgeIdx!=-1) {
+ MEdge *origMed = &medge[edgeIdx];
+
+ if (dlm) {
+ flags |= origMed->flag&~ME_EDGE_STEPINDEX;
+ } else {
+ flags |= (origMed->flag&ME_SEAM)|ME_EDGEDRAW|ME_EDGERENDER;
+ }
+ }
+ }
+
+ return flags;
+}
+#endif
+
+/* face weighting */
+static void calc_ss_weights(int gridFaces,
+ FaceVertWeight **qweight, FaceVertWeight **tweight)
+{
+ FaceVertWeight *qw, *tw;
+ int x, y, j;
+ int numWeights = gridFaces * gridFaces;
+
+ *tweight = MEM_mallocN(sizeof(**tweight) * numWeights, "ssTriWeight");
+ *qweight = MEM_mallocN(sizeof(**qweight) * numWeights, "ssQuadWeight");
+
+ qw = *qweight;
+ tw = *tweight;
+
+ for (y = 0; y < gridFaces; y++) {
+ for (x = 0; x < gridFaces; x++) {
+ for (j = 0; j < 4; j++) {
+ int fx = x + (j == 2 || j == 3);
+ int fy = y + (j == 1 || j == 2);
+ float x_v = (float) fx / gridFaces;
+ float y_v = (float) fy / gridFaces;
+ float tx_v = (1.0f - x_v), ty_v = (1.0f - y_v);
+ float center = (1.0f / 3.0f) * tx_v * ty_v;
+
+ (*tw)[j][0] = center + 0.5f * tx_v * y_v;
+ (*tw)[j][2] = center + 0.5f * x_v * ty_v;
+ (*tw)[j][1] = 1.0f - (*tw)[j][0] - (*tw)[j][2];
+ (*tw)[j][3] = 0.0f;
+
+ tx_v *= 0.5f;
+ ty_v *= 0.5f;
+
+ (*qw)[j][3] = tx_v * ty_v;
+ (*qw)[j][0] = (*qw)[j][3] + tx_v * y_v;
+ (*qw)[j][2] = (*qw)[j][3] + x_v * ty_v;
+ (*qw)[j][1] = 1.0f - (*qw)[j][0] - (*qw)[j][2] - (*qw)[j][3];
+
+ }
+ tw++;
+ qw++;
+ }
+ }
+}
+
+DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh,
+ int drawInteriorEdges, int useSubsurfUv,
+ DerivedMesh *dm)
+{
+ DerivedMesh *result;
+ int edgeSize = ccgSubSurf_getEdgeSize(ss);
+ int gridSize = ccgSubSurf_getGridSize(ss);
+ int gridFaces = gridSize - 1;
+ int edgeBase, faceBase;
+ int i, j, k, S, x, y, index;
+ int vertBase = 0;
+ CCGVertIterator *vi;
+ CCGEdgeIterator *ei;
+ CCGFaceIterator *fi;
+ CCGFace **faceMap2;
+ CCGEdge **edgeMap2;
+ CCGVert **vertMap2;
+ int totvert, totedge, totface;
+ MVert *mvert;
+ MEdge *med;
+ MFace *mf;
+ int *origIndex;
+ FaceVertWeight *qweight, *tweight;
+
+ calc_ss_weights(gridFaces, &qweight, &tweight);
+
+ /* vert map */
+ totvert = ccgSubSurf_getNumVerts(ss);
+ vertMap2 = MEM_mallocN(totvert*sizeof(*vertMap2), "vertmap");
+ vi = ccgSubSurf_getVertIterator(ss);
+ for(; !ccgVertIterator_isStopped(vi); ccgVertIterator_next(vi)) {
+ CCGVert *v = ccgVertIterator_getCurrent(vi);
+
+ vertMap2[(int) ccgSubSurf_getVertVertHandle(ss, v)] = v;
+ }
+ ccgVertIterator_free(vi);
+
+ totedge = ccgSubSurf_getNumEdges(ss);
+ edgeMap2 = MEM_mallocN(totedge*sizeof(*edgeMap2), "edgemap");
+ ei = ccgSubSurf_getEdgeIterator(ss);
+ for(; !ccgEdgeIterator_isStopped(ei); ccgEdgeIterator_next(ei)) {
+ CCGEdge *e = ccgEdgeIterator_getCurrent(ei);
+
+ edgeMap2[(int) ccgSubSurf_getEdgeEdgeHandle(ss, e)] = e;
+ }
+
+ totface = ccgSubSurf_getNumFaces(ss);
+ faceMap2 = MEM_mallocN(totface*sizeof(*faceMap2), "facemap");
+ fi = ccgSubSurf_getFaceIterator(ss);
+ for(; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) {
+ CCGFace *f = ccgFaceIterator_getCurrent(fi);
+
+ faceMap2[(int) ccgSubSurf_getFaceFaceHandle(ss, f)] = f;
+ }
+ ccgFaceIterator_free(fi);
+
+ if(dm) {
+ result = CDDM_from_template(dm, ccgSubSurf_getNumFinalVerts(ss),
+ ccgSubSurf_getNumFinalEdges(ss),
+ ccgSubSurf_getNumFinalFaces(ss));
+ } else {
+ result = CDDM_new(ccgSubSurf_getNumFinalVerts(ss),
+ ccgSubSurf_getNumFinalEdges(ss),
+ ccgSubSurf_getNumFinalFaces(ss));
+ }
+
+ // load verts
+ faceBase = i = 0;
+ mvert = CDDM_get_verts(result);
+ origIndex = result->getVertData(result, 0, CD_ORIGINDEX);
+
+ for(index = 0; index < totface; index++) {
+ CCGFace *f = faceMap2[index];
+ int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(ss, f);
+ FaceVertWeight *weight = (numVerts == 4) ? qweight : tweight;
+ int vertIdx[4];
+
+ for(S = 0; S < numVerts; S++) {
+ CCGVert *v = ccgSubSurf_getFaceVert(ss, f, S);
+
+ vertIdx[S] = (int)ccgSubSurf_getVertVertHandle(ss, v);
+ }
+
+ DM_interp_vert_data(dm, result, vertIdx, weight[0][0], numVerts, i);
+ VecCopyf(mvert->co, ccgSubSurf_getFaceCenterData(ss, f));
+ *origIndex = ORIGINDEX_NONE;
+ ++mvert;
+ ++origIndex;
+ i++;
+
+ for(S = 0; S < numVerts; S++) {
+ int prevS = (S - 1 + numVerts) % numVerts;
+ int nextS = (S + 1) % numVerts;
+ int otherS = (numVerts == 4) ? (S + 2) % numVerts : 3;
+ for(x = 1; x < gridFaces; x++) {
+ float w[4];
+ w[prevS] = weight[x][0][0];
+ w[S] = weight[x][0][1];
+ w[nextS] = weight[x][0][2];
+ w[otherS] = weight[x][0][3];
+ DM_interp_vert_data(dm, result, vertIdx, w, numVerts, i);
+ VecCopyf(mvert->co,
+ ccgSubSurf_getFaceGridEdgeData(ss, f, S, x));
+ *origIndex = ORIGINDEX_NONE;
+ ++mvert;
+ ++origIndex;
+ i++;
+ }
+ }
+
+ for(S = 0; S < numVerts; S++) {
+ int prevS = (S - 1 + numVerts) % numVerts;
+ int nextS = (S + 1) % numVerts;
+ int otherS = (numVerts == 4) ? (S + 2) % numVerts : 3;
+ for(y = 1; y < gridFaces; y++) {
+ for(x = 1; x < gridFaces; x++) {
+ float w[4];
+ w[prevS] = weight[y * gridFaces + x][0][0];
+ w[S] = weight[y * gridFaces + x][0][1];
+ w[nextS] = weight[y * gridFaces + x][0][2];
+ w[otherS] = weight[y * gridFaces + x][0][3];
+ DM_interp_vert_data(dm, result, vertIdx, w, numVerts, i);
+ VecCopyf(mvert->co,
+ ccgSubSurf_getFaceGridData(ss, f, S, x, y));
+ *origIndex = ORIGINDEX_NONE;
+ ++mvert;
+ ++origIndex;
+ i++;
+ }
+ }
+ }
+
+ *((int*)ccgSubSurf_getFaceUserData(ss, f)) = faceBase;
+ faceBase += 1 + numVerts * ((gridSize-2) + (gridSize-2) * (gridSize-2));
+ }
+
+ edgeBase = i;
+ for(index = 0; index < totedge; index++) {
+ CCGEdge *e = edgeMap2[index];
+ int x;
+ int vertIdx[2];
+
+ CCGVert *v;
+ v = ccgSubSurf_getEdgeVert0(ss, e);
+ vertIdx[0] = (int)ccgSubSurf_getVertVertHandle(ss, v);
+ v = ccgSubSurf_getEdgeVert1(ss, e);
+ vertIdx[1] = (int)ccgSubSurf_getVertVertHandle(ss, v);
+
+ for(x = 1; x < edgeSize - 1; x++) {
+ float w[2];
+ w[1] = (float) x / (edgeSize - 1);
+ w[0] = 1 - w[1];
+ DM_interp_vert_data(dm, result, vertIdx, w, 2, i);
+ VecCopyf(mvert->co, ccgSubSurf_getEdgeData(ss, e, x));
+ *origIndex = ORIGINDEX_NONE;
+ ++mvert;
+ ++origIndex;
+ i++;
+ }
+
+ *((int*)ccgSubSurf_getEdgeUserData(ss, e)) = edgeBase;
+ edgeBase += edgeSize-2;
+ }
+
+ vertBase = i;
+ for(index = 0; index < totvert; index++) {
+ CCGVert *v = vertMap2[index];
+ int vertIdx;
+
+ vertIdx = (int)ccgSubSurf_getVertVertHandle(ss, v);
+
+ DM_copy_vert_data(dm, result, vertIdx, i, 1);
+ VecCopyf(mvert->co, ccgSubSurf_getVertData(ss, v));
+
+ *((int*)ccgSubSurf_getVertUserData(ss, v)) = i;
+ *origIndex = ccgDM_getVertMapIndex(NULL, ss, v);
+ ++mvert;
+ ++origIndex;
+ i++;
+ }
+
+ // load edges
+ i = 0;
+ med = CDDM_get_edges(result);
+ origIndex = result->getEdgeData(result, 0, CD_ORIGINDEX);
+
+ for(index = 0; index < totface; index++) {
+ CCGFace *f = faceMap2[index];
+ int numVerts = ccgSubSurf_getFaceNumVerts(ss, f);
+
+ for(k = 0; k < numVerts; k++) {
+ for(x = 0; x < gridFaces; x++) {
+ if(drawInteriorEdges) med->flag = ME_EDGEDRAW | ME_EDGERENDER;
+ med->v1 = getFaceIndex(ss, f, k, x, 0, edgeSize, gridSize);
+ med->v2 = getFaceIndex(ss, f, k, x+1, 0, edgeSize, gridSize);
+ *origIndex = ORIGINDEX_NONE;
+ ++med;
+ ++origIndex;
+ i++;
+ }
+
+ for(x = 1; x < gridFaces; x++) {
+ for(y = 0; y < gridFaces; y++) {
+ if(drawInteriorEdges)
+ med->flag = ME_EDGEDRAW | ME_EDGERENDER;
+ med->v1 = getFaceIndex(ss, f, k, x, y, edgeSize, gridSize);
+ med->v2 = getFaceIndex(ss, f, k, x, y + 1,
+ edgeSize, gridSize);
+ *origIndex = ORIGINDEX_NONE;
+ ++med;
+ ++origIndex;
+ i++;
+
+ if(drawInteriorEdges)
+ med->flag = ME_EDGEDRAW | ME_EDGERENDER;
+ med->v1 = getFaceIndex(ss, f, k, y, x, edgeSize, gridSize);
+ med->v2 = getFaceIndex(ss, f, k, y + 1, x,
+ edgeSize, gridSize);
+ *origIndex = ORIGINDEX_NONE;
+ ++med;
+ ++origIndex;
+ i++;
+ }
+ }
+ }
+ }
+
+ for(index = 0; index < totedge; index++) {
+ CCGEdge *e = edgeMap2[index];
+ unsigned int flags = 0;
+ int edgeIdx = (int)ccgSubSurf_getEdgeEdgeHandle(ss, e);
+
+ if(!ccgSubSurf_getEdgeNumFaces(ss, e)) flags |= ME_LOOSEEDGE;
+
+
+ if(edgeIdx != -1 && dm) {
+ MEdge origMed;
+ dm->getEdge(dm, edgeIdx, &origMed);
+
+ flags |= origMed.flag;
+ }
+
+ for(x = 0; x < edgeSize - 1; x++) {
+ med->v1 = getEdgeIndex(ss, e, x, edgeSize);
+ med->v2 = getEdgeIndex(ss, e, x + 1, edgeSize);
+ med->flag = flags;
+ *origIndex = ccgDM_getEdgeMapIndex(NULL, ss, e);
+ ++med;
+ ++origIndex;
+ i++;
+ }
+ }
+
+ // load faces
+ i = 0;
+ mf = CDDM_get_faces(result);
+ origIndex = result->getFaceData(result, 0, CD_ORIGINDEX);
+
+ for(index = 0; index < totface; index++) {
+ CCGFace *f = faceMap2[index];
+ int numVerts = ccgSubSurf_getFaceNumVerts(ss, f);
+ int mat_nr;
+ int flag;
+ int mapIndex = ccgDM_getFaceMapIndex(NULL, ss, f);
+ int faceIdx = (int)ccgSubSurf_getFaceFaceHandle(ss, f);
+
+ if(!ssFromEditmesh) {
+ MFace origMFace;
+ dm->getFace(dm, faceIdx, &origMFace);
+
+ mat_nr = origMFace.mat_nr;
+ flag = origMFace.flag;
+ } else {
+ EditFace *ef = ccgSubSurf_getFaceFaceHandle(ss, f);
+ mat_nr = ef->mat_nr;
+ flag = ef->flag;
+ }
+
+ for(S = 0; S < numVerts; S++) {
+ FaceVertWeight *weight = (numVerts == 4) ? qweight : tweight;
+
+ for(y = 0; y < gridFaces; y++) {
+ for(x = 0; x < gridFaces; x++) {
+ mf->v1 = getFaceIndex(ss, f, S, x + 0, y + 0,
+ edgeSize, gridSize);
+ mf->v2 = getFaceIndex(ss, f, S, x + 0, y + 1,
+ edgeSize, gridSize);
+ mf->v3 = getFaceIndex(ss, f, S, x + 1, y + 1,
+ edgeSize, gridSize);
+ mf->v4 = getFaceIndex(ss, f, S, x + 1, y + 0,
+ edgeSize, gridSize);
+ mf->mat_nr = mat_nr;
+ mf->flag = flag;
+
+ if(dm) {
+ int prevS = (S - 1 + numVerts) % numVerts;
+ int nextS = (S + 1) % numVerts;
+ int otherS = (numVerts == 4) ? (S + 2) % numVerts : 3;
+ FaceVertWeight w;
+
+ for(j = 0; j < 4; ++j) {
+ w[j][prevS] = (*weight)[j][0];
+ w[j][S] = (*weight)[j][1];
+ w[j][nextS] = (*weight)[j][2];
+ w[j][otherS] = (*weight)[j][3];
+ }
+
+ DM_interp_face_data(dm, result, &faceIdx, NULL,
+ &w, 1, i);
+ weight++;
+ }
+
+ *origIndex = mapIndex;
+ ++mf;
+ ++origIndex;
+ i++;
+ }
+ }
+ }
+ }
+
+ MEM_freeN(faceMap2);
+ MEM_freeN(edgeMap2);
+ MEM_freeN(vertMap2);
+
+ MEM_freeN(tweight);
+ MEM_freeN(qweight);
+
+ if(useSubsurfUv) {
+ CustomData *fdata = &result->faceData;
+ CustomData *dmfdata = &dm->faceData;
+ int numlayer = CustomData_number_of_layers(fdata, CD_MTFACE);
+ int dmnumlayer = CustomData_number_of_layers(dmfdata, CD_MTFACE);
+
+ for (i=0; i<numlayer && i<dmnumlayer; i++)
+ set_subsurf_uv(ss, dm, result, i);
+ }
+
+ CDDM_calc_normals(result);
+
+ return result;
+}
+
+static void ss_sync_from_derivedmesh(CCGSubSurf *ss, DerivedMesh *dm,
+ float (*vertexCos)[3], int useFlatSubdiv)
+{
+ float creaseFactor = (float) ccgSubSurf_getSubdivisionLevels(ss);
+ CCGVertHDL fVerts[4];
+ int totvert = dm->getNumVerts(dm);
+ int totedge = dm->getNumEdges(dm);
+ int totface = dm->getNumFaces(dm);
+ int i;
+ int *index;
+ MVert *mvert = dm->getVertArray(dm);
+ MEdge *medge = dm->getEdgeArray(dm);
+ MFace *mface = dm->getFaceArray(dm);
+ MVert *mv;
+ MEdge *me;
+ MFace *mf;
+
+ ccgSubSurf_initFullSync(ss);
+
+ mv = mvert;
+ index = (int *)dm->getVertDataArray(dm, CD_ORIGINDEX);
+ for(i = 0; i < totvert; i++, mv++, index++) {
+ CCGVert *v;
+
+ if(vertexCos) {
+ ccgSubSurf_syncVert(ss, (CCGVertHDL)i, vertexCos[i], 0, &v);
+ } else {
+ ccgSubSurf_syncVert(ss, (CCGVertHDL)i, mv->co, 0, &v);
+ }
+
+ ((int*)ccgSubSurf_getVertUserData(ss, v))[1] = *index;
+ }
+
+ me = medge;
+ index = (int *)dm->getEdgeDataArray(dm, CD_ORIGINDEX);
+ for(i = 0; i < totedge; i++, me++, index++) {
+ CCGEdge *e;
+ float crease;
+
+ crease = useFlatSubdiv ? creaseFactor :
+ me->crease * creaseFactor / 255.0f;
+
+ ccgSubSurf_syncEdge(ss, (CCGEdgeHDL)i, (CCGVertHDL)me->v1,
+ (CCGVertHDL)me->v2, crease, &e);
+
+ ((int*)ccgSubSurf_getEdgeUserData(ss, e))[1] = *index;
+ }
+
+ mf = mface;
+ index = (int *)dm->getFaceDataArray(dm, CD_ORIGINDEX);
+ for (i = 0; i < totface; i++, mf++, index++) {
+ CCGFace *f;
+
+ fVerts[0] = (CCGVertHDL) mf->v1;
+ fVerts[1] = (CCGVertHDL) mf->v2;
+ fVerts[2] = (CCGVertHDL) mf->v3;
+ fVerts[3] = (CCGVertHDL) mf->v4;
+
+ // this is very bad, means mesh is internally consistent.
+ // it is not really possible to continue without modifying
+ // other parts of code significantly to handle missing faces.
+ // since this really shouldn't even be possible we just bail.
+ if(ccgSubSurf_syncFace(ss, (CCGFaceHDL)i, fVerts[3] ? 4 : 3,
+ fVerts, &f) == eCCGError_InvalidValue) {
+ static int hasGivenError = 0;
+
+ if(!hasGivenError) {
+ error("Unrecoverable error in SubSurf calculation,"
+ " mesh is inconsistent.");
+
+ hasGivenError = 1;
+ }
+
+ return;
+ }
+
+ ((int*)ccgSubSurf_getFaceUserData(ss, f))[1] = *index;
+ }
+
+ ccgSubSurf_processSync(ss);
+}
+
+/***/
+
+static int ccgDM_getVertMapIndex(CCGDerivedMesh *ccgdm, CCGSubSurf *ss, CCGVert *v) {
+ return ((int*) ccgSubSurf_getVertUserData(ss, v))[1];
+}
+
+static int ccgDM_getEdgeMapIndex(CCGDerivedMesh *ccgdm, CCGSubSurf *ss, CCGEdge *e) {
+ return ((int*) ccgSubSurf_getEdgeUserData(ss, e))[1];
+}
+
+static int ccgDM_getFaceMapIndex(CCGDerivedMesh *ccgdm, CCGSubSurf *ss, CCGFace *f) {
+ return ((int*) ccgSubSurf_getFaceUserData(ss, f))[1];
+}
+
+static void ccgDM_getMinMax(DerivedMesh *dm, float min_r[3], float max_r[3]) {
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
+ CCGSubSurf *ss = ccgdm->ss;
+ CCGVertIterator *vi = ccgSubSurf_getVertIterator(ss);
+ CCGEdgeIterator *ei = ccgSubSurf_getEdgeIterator(ss);
+ CCGFaceIterator *fi = ccgSubSurf_getFaceIterator(ss);
+ int i, edgeSize = ccgSubSurf_getEdgeSize(ss);
+ int gridSize = ccgSubSurf_getGridSize(ss);
+
+ if (!ccgSubSurf_getNumVerts(ss))
+ min_r[0] = min_r[1] = min_r[2] = max_r[0] = max_r[1] = max_r[2] = 0.0;
+
+ for (; !ccgVertIterator_isStopped(vi); ccgVertIterator_next(vi)) {
+ CCGVert *v = ccgVertIterator_getCurrent(vi);
+ float *co = ccgSubSurf_getVertData(ss, v);
+
+ DO_MINMAX(co, min_r, max_r);
+ }
+
+ for (; !ccgEdgeIterator_isStopped(ei); ccgEdgeIterator_next(ei)) {
+ CCGEdge *e = ccgEdgeIterator_getCurrent(ei);
+ VertData *edgeData = ccgSubSurf_getEdgeDataArray(ss, e);
+
+ for (i=0; i<edgeSize; i++)
+ DO_MINMAX(edgeData[i].co, min_r, max_r);
+ }
+
+ for (; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) {
+ CCGFace *f = ccgFaceIterator_getCurrent(fi);
+ int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(ss, f);
+
+ for (S=0; S<numVerts; S++) {
+ VertData *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S);
+
+ for (y=0; y<gridSize; y++)
+ for (x=0; x<gridSize; x++)
+ DO_MINMAX(faceGridData[y*gridSize + x].co, min_r, max_r);
+ }
+ }
+
+ ccgFaceIterator_free(fi);
+ ccgEdgeIterator_free(ei);
+ ccgVertIterator_free(vi);
+}
+static int ccgDM_getNumVerts(DerivedMesh *dm) {
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
+
+ return ccgSubSurf_getNumFinalVerts(ccgdm->ss);
+}
+static int ccgDM_getNumEdges(DerivedMesh *dm) {
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
+
+ return ccgSubSurf_getNumFinalEdges(ccgdm->ss);
+}
+static int ccgDM_getNumFaces(DerivedMesh *dm) {
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
+
+ return ccgSubSurf_getNumFinalFaces(ccgdm->ss);
+}
+
+static void ccgDM_getFinalVert(DerivedMesh *dm, int vertNum, MVert *mv)
+{
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
+ CCGSubSurf *ss = ccgdm->ss;
+ int i;
+
+ memset(mv, 0, sizeof(*mv));
+
+ if(vertNum < ccgdm->edgeMap[0].startVert) {
+ /* this vert comes from face data */
+ int lastface = ccgSubSurf_getNumFaces(ss) - 1;
+ CCGFace *f;
+ int x, y, grid, numVerts;
+ int offset;
+ int gridSize = ccgSubSurf_getGridSize(ss);
+ int gridSideVerts;
+ int gridInternalVerts;
+ int gridSideEnd;
+ int gridInternalEnd;
+
+ i = 0;
+ while(i < lastface && vertNum >= ccgdm->faceMap[i + 1].startVert)
+ ++i;
+
+ f = ccgdm->faceMap[i].face;
+ numVerts = ccgSubSurf_getFaceNumVerts(ss, f);
+
+ gridSideVerts = gridSize - 2;
+ gridInternalVerts = gridSideVerts * gridSideVerts;
+
+ gridSideEnd = 1 + numVerts * gridSideVerts;
+ gridInternalEnd = gridSideEnd + numVerts * gridInternalVerts;
+
+ offset = vertNum - ccgdm->faceMap[i].startVert;
+ if(offset < 1) {
+ VecCopyf(mv->co, ccgSubSurf_getFaceCenterData(ss, f));
+ } else if(offset < gridSideEnd) {
+ offset -= 1;
+ grid = offset / gridSideVerts;
+ x = offset % gridSideVerts + 1;
+ VecCopyf(mv->co, ccgSubSurf_getFaceGridEdgeData(ss, f, grid, x));
+ } else if(offset < gridInternalEnd) {
+ offset -= gridSideEnd;
+ grid = offset / gridInternalVerts;
+ offset %= gridInternalVerts;
+ y = offset / gridSideVerts + 1;
+ x = offset % gridSideVerts + 1;
+ VecCopyf(mv->co, ccgSubSurf_getFaceGridData(ss, f, grid, x, y));
+ }
+ } else if(vertNum < ccgdm->vertMap[0].startVert) {
+ /* this vert comes from edge data */
+ CCGEdge *e;
+ int lastedge = ccgSubSurf_getNumEdges(ss) - 1;
+ int x;
+
+ i = 0;
+ while(i < lastedge && vertNum >= ccgdm->edgeMap[i + 1].startVert)
+ ++i;
+
+ e = ccgdm->edgeMap[i].edge;
+
+ x = vertNum - ccgdm->edgeMap[i].startVert + 1;
+ VecCopyf(mv->co, ccgSubSurf_getEdgeData(ss, e, x));
+ } else {
+ /* this vert comes from vert data */
+ CCGVert *v;
+ i = vertNum - ccgdm->vertMap[0].startVert;
+
+ v = ccgdm->vertMap[i].vert;
+ VecCopyf(mv->co, ccgSubSurf_getVertData(ss, v));
+ }
+}
+
+static void ccgDM_getFinalEdge(DerivedMesh *dm, int edgeNum, MEdge *med)
+{
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
+ CCGSubSurf *ss = ccgdm->ss;
+ int i;
+
+ memset(med, 0, sizeof(*med));
+
+ if(edgeNum < ccgdm->edgeMap[0].startEdge) {
+ /* this edge comes from face data */
+ int lastface = ccgSubSurf_getNumFaces(ss) - 1;
+ CCGFace *f;
+ int x, y, grid, numVerts;
+ int offset;
+ int gridSize = ccgSubSurf_getGridSize(ss);
+ int edgeSize = ccgSubSurf_getEdgeSize(ss);
+ int gridSideEdges;
+ int gridInternalEdges;
+
+ i = 0;
+ while(i < lastface && edgeNum >= ccgdm->faceMap[i + 1].startEdge)
+ ++i;
+
+ f = ccgdm->faceMap[i].face;
+ numVerts = ccgSubSurf_getFaceNumVerts(ss, f);
+
+ gridSideEdges = gridSize - 1;
+ gridInternalEdges = (gridSideEdges - 1) * gridSideEdges * 2;
+
+ offset = edgeNum - ccgdm->faceMap[i].startEdge;
+ grid = offset / (gridSideEdges + gridInternalEdges);
+ offset %= (gridSideEdges + gridInternalEdges);
+
+ if(offset < gridSideEdges) {
+ x = offset;
+ med->v1 = getFaceIndex(ss, f, grid, x, 0, edgeSize, gridSize);
+ med->v2 = getFaceIndex(ss, f, grid, x+1, 0, edgeSize, gridSize);
+ } else {
+ offset -= gridSideEdges;
+ x = (offset / 2) / gridSideEdges + 1;
+ y = (offset / 2) % gridSideEdges;
+ if(offset % 2 == 0) {
+ med->v1 = getFaceIndex(ss, f, grid, x, y, edgeSize, gridSize);
+ med->v2 = getFaceIndex(ss, f, grid, x, y+1, edgeSize, gridSize);
+ } else {
+ med->v1 = getFaceIndex(ss, f, grid, y, x, edgeSize, gridSize);
+ med->v2 = getFaceIndex(ss, f, grid, y+1, x, edgeSize, gridSize);
+ }
+ }
+ } else {
+ /* this vert comes from edge data */
+ CCGEdge *e;
+ int edgeSize = ccgSubSurf_getEdgeSize(ss);
+ int x, *edgeFlag;
+ unsigned int flags = 0;
+
+ i = (edgeNum - ccgdm->edgeMap[0].startEdge) / (edgeSize - 1);
+
+ e = ccgdm->edgeMap[i].edge;
+
+ if(!ccgSubSurf_getEdgeNumFaces(ss, e)) flags |= ME_LOOSEEDGE;
+
+ x = edgeNum - ccgdm->edgeMap[i].startEdge;
+
+ med->v1 = getEdgeIndex(ss, e, x, edgeSize);
+ med->v2 = getEdgeIndex(ss, e, x+1, edgeSize);
+
+ edgeFlag = dm->getEdgeData(dm, edgeNum, CD_FLAGS);
+ if(edgeFlag)
+ flags |= (*edgeFlag & (ME_SEAM | ME_SHARP))
+ | ME_EDGEDRAW | ME_EDGERENDER;
+ else
+ flags |= ME_EDGEDRAW | ME_EDGERENDER;
+
+ med->flag = flags;
+ }
+}
+
+static void ccgDM_getFinalFace(DerivedMesh *dm, int faceNum, MFace *mf)
+{
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
+ CCGSubSurf *ss = ccgdm->ss;
+ int gridSize = ccgSubSurf_getGridSize(ss);
+ int edgeSize = ccgSubSurf_getEdgeSize(ss);
+ int gridSideEdges = gridSize - 1;
+ int gridFaces = gridSideEdges * gridSideEdges;
+ int i;
+ CCGFace *f;
+ int numVerts;
+ int offset;
+ int grid;
+ int x, y;
+ int lastface = ccgSubSurf_getNumFaces(ss) - 1;
+ char *faceFlags = dm->getFaceDataArray(dm, CD_FLAGS);
+
+ memset(mf, 0, sizeof(*mf));
+
+ i = 0;
+ while(i < lastface && faceNum >= ccgdm->faceMap[i + 1].startFace)
+ ++i;
+
+ f = ccgdm->faceMap[i].face;
+ numVerts = ccgSubSurf_getFaceNumVerts(ss, f);
+
+ offset = faceNum - ccgdm->faceMap[i].startFace;
+ grid = offset / gridFaces;
+ offset %= gridFaces;
+ y = offset / gridSideEdges;
+ x = offset % gridSideEdges;
+
+ mf->v1 = getFaceIndex(ss, f, grid, x+0, y+0, edgeSize, gridSize);
+ mf->v2 = getFaceIndex(ss, f, grid, x+0, y+1, edgeSize, gridSize);
+ mf->v3 = getFaceIndex(ss, f, grid, x+1, y+1, edgeSize, gridSize);
+ mf->v4 = getFaceIndex(ss, f, grid, x+1, y+0, edgeSize, gridSize);
+
+ if(faceFlags) mf->flag = faceFlags[i*4];
+ else mf->flag = ME_SMOOTH;
+}
+
+static void ccgDM_copyFinalVertArray(DerivedMesh *dm, MVert *mvert)
+{
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
+ CCGSubSurf *ss = ccgdm->ss;
+ int index;
+ int totvert, totedge, totface;
+ int gridSize = ccgSubSurf_getGridSize(ss);
+ int edgeSize = ccgSubSurf_getEdgeSize(ss);
+ int i = 0;
+
+ totface = ccgSubSurf_getNumFaces(ss);
+ for(index = 0; index < totface; index++) {
+ CCGFace *f = ccgdm->faceMap[index].face;
+ int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(ss, f);
+
+ VecCopyf(mvert[i++].co, ccgSubSurf_getFaceCenterData(ss, f));
+
+ for(S = 0; S < numVerts; S++) {
+ for(x = 1; x < gridSize - 1; x++) {
+ VecCopyf(mvert[i++].co,
+ ccgSubSurf_getFaceGridEdgeData(ss, f, S, x));
+ }
+ }
+
+ for(S = 0; S < numVerts; S++) {
+ for(y = 1; y < gridSize - 1; y++) {
+ for(x = 1; x < gridSize - 1; x++) {
+ VecCopyf(mvert[i++].co,
+ ccgSubSurf_getFaceGridData(ss, f, S, x, y));
+ }
+ }
+ }
+ }
+
+ totedge = ccgSubSurf_getNumEdges(ss);
+ for(index = 0; index < totedge; index++) {
+ CCGEdge *e = ccgdm->edgeMap[index].edge;
+ int x;
+
+ for(x = 1; x < edgeSize - 1; x++) {
+ VecCopyf(mvert[i++].co, ccgSubSurf_getEdgeData(ss, e, x));
+ }
+ }
+
+ totvert = ccgSubSurf_getNumVerts(ss);
+ for(index = 0; index < totvert; index++) {
+ CCGVert *v = ccgdm->vertMap[index].vert;
+
+ VecCopyf(mvert[i].co, ccgSubSurf_getVertData(ss, v));
+
+ i++;
+ }
+}
+
+static void ccgDM_copyFinalEdgeArray(DerivedMesh *dm, MEdge *medge)
+{
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
+ CCGSubSurf *ss = ccgdm->ss;
+ int index;
+ int totedge, totface;
+ int gridSize = ccgSubSurf_getGridSize(ss);
+ int edgeSize = ccgSubSurf_getEdgeSize(ss);
+ int i = 0;
+ int *edgeFlags = dm->getEdgeDataArray(dm, CD_FLAGS);
+
+ totface = ccgSubSurf_getNumFaces(ss);
+ for(index = 0; index < totface; index++) {
+ CCGFace *f = ccgdm->faceMap[index].face;
+ int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(ss, f);
+
+ for(S = 0; S < numVerts; S++) {
+ for(x = 0; x < gridSize - 1; x++) {
+ MEdge *med = &medge[i];
+
+ if(ccgdm->drawInteriorEdges)
+ med->flag = ME_EDGEDRAW | ME_EDGERENDER;
+ med->v1 = getFaceIndex(ss, f, S, x, 0, edgeSize, gridSize);
+ med->v2 = getFaceIndex(ss, f, S, x + 1, 0, edgeSize, gridSize);
+ i++;
+ }
+
+ for(x = 1; x < gridSize - 1; x++) {
+ for(y = 0; y < gridSize - 1; y++) {
+ MEdge *med;
+
+ med = &medge[i];
+ if(ccgdm->drawInteriorEdges)
+ med->flag = ME_EDGEDRAW | ME_EDGERENDER;
+ med->v1 = getFaceIndex(ss, f, S, x, y,
+ edgeSize, gridSize);
+ med->v2 = getFaceIndex(ss, f, S, x, y + 1,
+ edgeSize, gridSize);
+ i++;
+
+ med = &medge[i];
+ if(ccgdm->drawInteriorEdges)
+ med->flag = ME_EDGEDRAW | ME_EDGERENDER;
+ med->v1 = getFaceIndex(ss, f, S, y, x,
+ edgeSize, gridSize);
+ med->v2 = getFaceIndex(ss, f, S, y + 1, x,
+ edgeSize, gridSize);
+ i++;
+ }
+ }
+ }
+ }
+
+ totedge = ccgSubSurf_getNumEdges(ss);
+ for(index = 0; index < totedge; index++) {
+ CCGEdge *e = ccgdm->edgeMap[index].edge;
+ unsigned int flags = 0;
+ int x;
+ int edgeIdx = (int)ccgSubSurf_getEdgeEdgeHandle(ss, e);
+
+ if(!ccgSubSurf_getEdgeNumFaces(ss, e)) flags |= ME_LOOSEEDGE;
+
+ if(edgeFlags) {
+ if(edgeIdx != -1) {
+ flags |= (edgeFlags[i] & (ME_SEAM | ME_SHARP))
+ | ME_EDGEDRAW | ME_EDGERENDER;
+ }
+ } else {
+ flags |= ME_EDGEDRAW | ME_EDGERENDER;
+ }
+
+ for(x = 0; x < edgeSize - 1; x++) {
+ MEdge *med = &medge[i];
+ med->v1 = getEdgeIndex(ss, e, x, edgeSize);
+ med->v2 = getEdgeIndex(ss, e, x + 1, edgeSize);
+ med->flag = flags;
+ i++;
+ }
+ }
+}
+
+static void ccgDM_copyFinalFaceArray(DerivedMesh *dm, MFace *mface)
+{
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
+ CCGSubSurf *ss = ccgdm->ss;
+ int index;
+ int totface;
+ int gridSize = ccgSubSurf_getGridSize(ss);
+ int edgeSize = ccgSubSurf_getEdgeSize(ss);
+ int i = 0;
+ char *faceFlags = dm->getFaceDataArray(dm, CD_FLAGS);
+
+ totface = ccgSubSurf_getNumFaces(ss);
+ for(index = 0; index < totface; index++) {
+ CCGFace *f = ccgdm->faceMap[index].face;
+ int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(ss, f);
+ int mat_nr = 0;
+ int flag = ME_SMOOTH; /* assume face is smooth by default */
+
+ for(S = 0; S < numVerts; S++) {
+ for(y = 0; y < gridSize - 1; y++) {
+ for(x = 0; x < gridSize - 1; x++) {
+ MFace *mf = &mface[i];
+ mf->v1 = getFaceIndex(ss, f, S, x + 0, y + 0,
+ edgeSize, gridSize);
+ mf->v2 = getFaceIndex(ss, f, S, x + 0, y + 1,
+ edgeSize, gridSize);
+ mf->v3 = getFaceIndex(ss, f, S, x + 1, y + 1,
+ edgeSize, gridSize);
+ mf->v4 = getFaceIndex(ss, f, S, x + 1, y + 0,
+ edgeSize, gridSize);
+ mf->mat_nr = mat_nr;
+ if(faceFlags) mf->flag = faceFlags[index*4];
+ else mf->flag = flag;
+
+ i++;
+ }
+ }
+ }
+ }
+}
+
+static void ccgdm_getVertCos(DerivedMesh *dm, float (*cos)[3]) {
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
+ CCGSubSurf *ss = ccgdm->ss;
+ int edgeSize = ccgSubSurf_getEdgeSize(ss);
+ int gridSize = ccgSubSurf_getGridSize(ss);
+ int i;
+ CCGVertIterator *vi;
+ CCGEdgeIterator *ei;
+ CCGFaceIterator *fi;
+ CCGFace **faceMap2;
+ CCGEdge **edgeMap2;
+ CCGVert **vertMap2;
+ int index, totvert, totedge, totface;
+
+ totvert = ccgSubSurf_getNumVerts(ss);
+ vertMap2 = MEM_mallocN(totvert*sizeof(*vertMap2), "vertmap");
+ vi = ccgSubSurf_getVertIterator(ss);
+ for (; !ccgVertIterator_isStopped(vi); ccgVertIterator_next(vi)) {
+ CCGVert *v = ccgVertIterator_getCurrent(vi);
+
+ vertMap2[(int) ccgSubSurf_getVertVertHandle(ss, v)] = v;
+ }
+ ccgVertIterator_free(vi);
+
+ totedge = ccgSubSurf_getNumEdges(ss);
+ edgeMap2 = MEM_mallocN(totedge*sizeof(*edgeMap2), "edgemap");
+ ei = ccgSubSurf_getEdgeIterator(ss);
+ for (i=0; !ccgEdgeIterator_isStopped(ei); i++,ccgEdgeIterator_next(ei)) {
+ CCGEdge *e = ccgEdgeIterator_getCurrent(ei);
+
+ edgeMap2[(int) ccgSubSurf_getEdgeEdgeHandle(ss, e)] = e;
+ }
+
+ totface = ccgSubSurf_getNumFaces(ss);
+ faceMap2 = MEM_mallocN(totface*sizeof(*faceMap2), "facemap");
+ fi = ccgSubSurf_getFaceIterator(ss);
+ for (; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) {
+ CCGFace *f = ccgFaceIterator_getCurrent(fi);
+
+ faceMap2[(int) ccgSubSurf_getFaceFaceHandle(ss, f)] = f;
+ }
+ ccgFaceIterator_free(fi);
+
+ i = 0;
+ for (index=0; index<totface; index++) {
+ CCGFace *f = faceMap2[index];
+ int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(ss, f);
+
+ VecCopyf(cos[i++], ccgSubSurf_getFaceCenterData(ss, f));
+
+ for (S=0; S<numVerts; S++) {
+ for (x=1; x<gridSize-1; x++) {
+ VecCopyf(cos[i++], ccgSubSurf_getFaceGridEdgeData(ss, f, S, x));
+ }
+ }
+
+ for (S=0; S<numVerts; S++) {
+ for (y=1; y<gridSize-1; y++) {
+ for (x=1; x<gridSize-1; x++) {
+ VecCopyf(cos[i++], ccgSubSurf_getFaceGridData(ss, f, S, x, y));
+ }
+ }
+ }
+ }
+
+ for (index=0; index<totedge; index++) {
+ CCGEdge *e= edgeMap2[index];
+ int x;
+
+ for (x=1; x<edgeSize-1; x++) {
+ VecCopyf(cos[i++], ccgSubSurf_getEdgeData(ss, e, x));
+ }
+ }
+
+ for (index=0; index<totvert; index++) {
+ CCGVert *v = vertMap2[index];
+ VecCopyf(cos[i++], ccgSubSurf_getVertData(ss, v));
+ }
+
+ MEM_freeN(vertMap2);
+ MEM_freeN(edgeMap2);
+ MEM_freeN(faceMap2);
+}
+static void ccgDM_foreachMappedVert(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no_f, short *no_s), void *userData) {
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
+ CCGVertIterator *vi = ccgSubSurf_getVertIterator(ccgdm->ss);
+
+ for (; !ccgVertIterator_isStopped(vi); ccgVertIterator_next(vi)) {
+ CCGVert *v = ccgVertIterator_getCurrent(vi);
+ VertData *vd = ccgSubSurf_getVertData(ccgdm->ss, v);
+ int index = ccgDM_getVertMapIndex(ccgdm, ccgdm->ss, v);
+
+ if (index!=-1)
+ func(userData, index, vd->co, vd->no, NULL);
+ }
+
+ ccgVertIterator_free(vi);
+}
+static void ccgDM_foreachMappedEdge(DerivedMesh *dm, void (*func)(void *userData, int index, float *v0co, float *v1co), void *userData) {
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
+ CCGSubSurf *ss = ccgdm->ss;
+ CCGEdgeIterator *ei = ccgSubSurf_getEdgeIterator(ss);
+ int i, edgeSize = ccgSubSurf_getEdgeSize(ss);
+
+ for (; !ccgEdgeIterator_isStopped(ei); ccgEdgeIterator_next(ei)) {
+ CCGEdge *e = ccgEdgeIterator_getCurrent(ei);
+ VertData *edgeData = ccgSubSurf_getEdgeDataArray(ss, e);
+ int index = ccgDM_getEdgeMapIndex(ccgdm, ss, e);
+
+ if (index!=-1) {
+ for (i=0; i<edgeSize-1; i++)
+ func(userData, index, edgeData[i].co, edgeData[i+1].co);
+ }
+ }
+
+ ccgEdgeIterator_free(ei);
+}
+
+static void ccgDM_drawVerts(DerivedMesh *dm) {
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
+ CCGSubSurf *ss = ccgdm->ss;
+ int edgeSize = ccgSubSurf_getEdgeSize(ss);
+ int gridSize = ccgSubSurf_getGridSize(ss);
+ CCGVertIterator *vi;
+ CCGEdgeIterator *ei;
+ CCGFaceIterator *fi;
+
+ glBegin(GL_POINTS);
+ vi = ccgSubSurf_getVertIterator(ss);
+ for (; !ccgVertIterator_isStopped(vi); ccgVertIterator_next(vi)) {
+ CCGVert *v = ccgVertIterator_getCurrent(vi);
+ glVertex3fv(ccgSubSurf_getVertData(ss, v));
+ }
+ ccgVertIterator_free(vi);
+
+ ei = ccgSubSurf_getEdgeIterator(ss);
+ for (; !ccgEdgeIterator_isStopped(ei); ccgEdgeIterator_next(ei)) {
+ CCGEdge *e = ccgEdgeIterator_getCurrent(ei);
+ int x;
+
+ for (x=1; x<edgeSize-1; x++)
+ glVertex3fv(ccgSubSurf_getEdgeData(ss, e, x));
+ }
+ ccgEdgeIterator_free(ei);
+
+ fi = ccgSubSurf_getFaceIterator(ss);
+ for (; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) {
+ CCGFace *f = ccgFaceIterator_getCurrent(fi);
+ int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(ss, f);
+
+ glVertex3fv(ccgSubSurf_getFaceCenterData(ss, f));
+ for (S=0; S<numVerts; S++)
+ for (x=1; x<gridSize-1; x++)
+ glVertex3fv(ccgSubSurf_getFaceGridEdgeData(ss, f, S, x));
+ for (S=0; S<numVerts; S++)
+ for (y=1; y<gridSize-1; y++)
+ for (x=1; x<gridSize-1; x++)
+ glVertex3fv(ccgSubSurf_getFaceGridData(ss, f, S, x, y));
+ }
+ ccgFaceIterator_free(fi);
+ glEnd();
+}
+static void ccgDM_drawEdges(DerivedMesh *dm, int drawLooseEdges) {
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
+ CCGSubSurf *ss = ccgdm->ss;
+ CCGEdgeIterator *ei = ccgSubSurf_getEdgeIterator(ss);
+ CCGFaceIterator *fi = ccgSubSurf_getFaceIterator(ss);
+ int i, edgeSize = ccgSubSurf_getEdgeSize(ss);
+ int gridSize = ccgSubSurf_getGridSize(ss);
+ int useAging;
+
+ ccgSubSurf_getUseAgeCounts(ss, &useAging, NULL, NULL, NULL);
+
+ for (; !ccgEdgeIterator_isStopped(ei); ccgEdgeIterator_next(ei)) {
+ CCGEdge *e = ccgEdgeIterator_getCurrent(ei);
+ VertData *edgeData = ccgSubSurf_getEdgeDataArray(ss, e);
+
+ if (!drawLooseEdges && !ccgSubSurf_getEdgeNumFaces(ss, e))
+ continue;
+
+ if (useAging && !(G.f&G_BACKBUFSEL)) {
+ int ageCol = 255-ccgSubSurf_getEdgeAge(ss, e)*4;
+ glColor3ub(0, ageCol>0?ageCol:0, 0);
+ }
+
+ glBegin(GL_LINE_STRIP);
+ for (i=0; i<edgeSize-1; i++) {
+ glVertex3fv(edgeData[i].co);
+ glVertex3fv(edgeData[i+1].co);
+ }
+ glEnd();
+ }
+
+ if (useAging && !(G.f&G_BACKBUFSEL)) {
+ glColor3ub(0, 0, 0);
+ }
+
+ if (ccgdm->drawInteriorEdges) {
+ for (; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) {
+ CCGFace *f = ccgFaceIterator_getCurrent(fi);
+ int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(ss, f);
+
+ for (S=0; S<numVerts; S++) {
+ VertData *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S);
+
+ glBegin(GL_LINE_STRIP);
+ for (x=0; x<gridSize; x++)
+ glVertex3fv(faceGridData[x].co);
+ glEnd();
+ for (y=1; y<gridSize-1; y++) {
+ glBegin(GL_LINE_STRIP);
+ for (x=0; x<gridSize; x++)
+ glVertex3fv(faceGridData[y*gridSize + x].co);
+ glEnd();
+ }
+ for (x=1; x<gridSize-1; x++) {
+ glBegin(GL_LINE_STRIP);
+ for (y=0; y<gridSize; y++)
+ glVertex3fv(faceGridData[y*gridSize + x].co);
+ glEnd();
+ }
+ }
+ }
+ }
+
+ ccgFaceIterator_free(fi);
+ ccgEdgeIterator_free(ei);
+}
+static void ccgDM_drawLooseEdges(DerivedMesh *dm) {
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
+ CCGSubSurf *ss = ccgdm->ss;
+ CCGEdgeIterator *ei = ccgSubSurf_getEdgeIterator(ss);
+ int i, edgeSize = ccgSubSurf_getEdgeSize(ss);
+
+ for (; !ccgEdgeIterator_isStopped(ei); ccgEdgeIterator_next(ei)) {
+ CCGEdge *e = ccgEdgeIterator_getCurrent(ei);
+ VertData *edgeData = ccgSubSurf_getEdgeDataArray(ss, e);
+
+ if (!ccgSubSurf_getEdgeNumFaces(ss, e)) {
+ glBegin(GL_LINE_STRIP);
+ for (i=0; i<edgeSize-1; i++) {
+ glVertex3fv(edgeData[i].co);
+ glVertex3fv(edgeData[i+1].co);
+ }
+ glEnd();
+ }
+ }
+
+ ccgEdgeIterator_free(ei);
+}
+
+static void ccgDM_glNormalFast(float *a, float *b, float *c, float *d)
+{
+ float a_cX = c[0]-a[0], a_cY = c[1]-a[1], a_cZ = c[2]-a[2];
+ float b_dX = d[0]-b[0], b_dY = d[1]-b[1], b_dZ = d[2]-b[2];
+ float no[3];
+
+ no[0] = b_dY*a_cZ - b_dZ*a_cY;
+ no[1] = b_dZ*a_cX - b_dX*a_cZ;
+ no[2] = b_dX*a_cY - b_dY*a_cX;
+
+ /* don't normalize, GL_NORMALIZE is be enabled */
+ glNormal3fv(no);
+}
+
+ /* Only used by non-editmesh types */
+static void ccgDM_drawFacesSolid(DerivedMesh *dm, int (*setMaterial)(int)) {
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
+ CCGSubSurf *ss = ccgdm->ss;
+ CCGFaceIterator *fi = ccgSubSurf_getFaceIterator(ss);
+ int gridSize = ccgSubSurf_getGridSize(ss);
+ char *faceFlags = DM_get_face_data_layer(dm, CD_FLAGS);
+
+ for (; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) {
+ CCGFace *f = ccgFaceIterator_getCurrent(fi);
+ int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(ss, f);
+ int index = (int) ccgSubSurf_getFaceFaceHandle(ss, f);
+ int drawSmooth, mat_nr;
+
+ if(faceFlags) {
+ drawSmooth = (faceFlags[index*4] & ME_SMOOTH);
+ mat_nr= faceFlags[index*4 + 1];
+ }
+ else {
+ drawSmooth = 1;
+ mat_nr= 0;
+ }
+
+ if (!setMaterial(mat_nr+1))
+ continue;
+
+ glShadeModel(drawSmooth? GL_SMOOTH: GL_FLAT);
+ for (S=0; S<numVerts; S++) {
+ VertData *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S);
+
+ if (drawSmooth) {
+ for (y=0; y<gridSize-1; y++) {
+ glBegin(GL_QUAD_STRIP);
+ for (x=0; x<gridSize; x++) {
+ VertData *a = &faceGridData[(y+0)*gridSize + x];
+ VertData *b = &faceGridData[(y+1)*gridSize + x];
+
+ glNormal3fv(a->no);
+ glVertex3fv(a->co);
+ glNormal3fv(b->no);
+ glVertex3fv(b->co);
+ }
+ glEnd();
+ }
+ } else {
+ glBegin(GL_QUADS);
+ for (y=0; y<gridSize-1; y++) {
+ for (x=0; x<gridSize-1; x++) {
+ float *a = faceGridData[(y+0)*gridSize + x].co;
+ float *b = faceGridData[(y+0)*gridSize + x + 1].co;
+ float *c = faceGridData[(y+1)*gridSize + x + 1].co;
+ float *d = faceGridData[(y+1)*gridSize + x].co;
+
+ ccgDM_glNormalFast(a, b, c, d);
+
+ glVertex3fv(d);
+ glVertex3fv(c);
+ glVertex3fv(b);
+ glVertex3fv(a);
+ }
+ }
+ glEnd();
+ }
+ }
+ }
+
+ ccgFaceIterator_free(fi);
+}
+static void ccgDM_drawFacesColored(DerivedMesh *dm, int useTwoSided, unsigned char *col1, unsigned char *col2) {
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
+ CCGSubSurf *ss = ccgdm->ss;
+ CCGFaceIterator *fi = ccgSubSurf_getFaceIterator(ss);
+ int gridSize = ccgSubSurf_getGridSize(ss);
+ unsigned char *cp1, *cp2;
+ int useTwoSide=1;
+
+ cp1= col1;
+ if(col2) {
+ cp2= col2;
+ } else {
+ cp2= NULL;
+ useTwoSide= 0;
+ }
+
+ glShadeModel(GL_SMOOTH);
+ if(col1 && col2)
+ glEnable(GL_CULL_FACE);
+
+ glBegin(GL_QUADS);
+ for (; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) {
+ CCGFace *f = ccgFaceIterator_getCurrent(fi);
+ int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(ss, f);
+
+ for (S=0; S<numVerts; S++) {
+ VertData *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S);
+ for (y=0; y<gridSize-1; y++) {
+ for (x=0; x<gridSize-1; x++) {
+ float *a = faceGridData[(y+0)*gridSize + x].co;
+ float *b = faceGridData[(y+0)*gridSize + x + 1].co;
+ float *c = faceGridData[(y+1)*gridSize + x + 1].co;
+ float *d = faceGridData[(y+1)*gridSize + x].co;
+
+ glColor3ub(cp1[3], cp1[2], cp1[1]);
+ glVertex3fv(d);
+ glColor3ub(cp1[7], cp1[6], cp1[5]);
+ glVertex3fv(c);
+ glColor3ub(cp1[11], cp1[10], cp1[9]);
+ glVertex3fv(b);
+ glColor3ub(cp1[15], cp1[14], cp1[13]);
+ glVertex3fv(a);
+
+ if (useTwoSide) {
+ glColor3ub(cp2[15], cp2[14], cp2[13]);
+ glVertex3fv(a);
+ glColor3ub(cp2[11], cp2[10], cp2[9]);
+ glVertex3fv(b);
+ glColor3ub(cp2[7], cp2[6], cp2[5]);
+ glVertex3fv(c);
+ glColor3ub(cp2[3], cp2[2], cp2[1]);
+ glVertex3fv(d);
+ }
+
+ if (cp2) cp2+=16;
+ cp1+=16;
+ }
+ }
+ }
+ }
+ glEnd();
+
+ ccgFaceIterator_free(fi);
+}
+
+static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
+ int (*drawParams)(MTFace *tface, MCol *mcol, int matnr),
+ int (*drawParamsMapped)(void *userData, int index),
+ void *userData)
+{
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
+ CCGSubSurf *ss = ccgdm->ss;
+ MCol *mcol = DM_get_face_data_layer(dm, CD_MCOL);
+ MTFace *tf = DM_get_face_data_layer(dm, CD_MTFACE);
+ char *faceFlags = DM_get_face_data_layer(dm, CD_FLAGS);
+ int i, totface, flag, gridSize = ccgSubSurf_getGridSize(ss);
+ int gridFaces = gridSize - 1;
+
+ totface = ccgSubSurf_getNumFaces(ss);
+ for(i = 0; i < totface; i++) {
+ CCGFace *f = ccgdm->faceMap[i].face;
+ int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(ss, f);
+ int drawSmooth, index = ccgDM_getFaceMapIndex(ccgdm, ss, f);
+ int origIndex = (int)ccgSubSurf_getFaceFaceHandle(ss, f);
+ unsigned char *cp= NULL;
+ int mat_nr;
+
+ if(faceFlags) {
+ drawSmooth = (faceFlags[origIndex*4] & ME_SMOOTH);
+ mat_nr= faceFlags[origIndex*4 + 1];
+ }
+ else {
+ drawSmooth = 1;
+ mat_nr= 0;
+ }
+
+ if(drawParams)
+ flag = drawParams(tf, mcol, mat_nr);
+ else
+ flag= (drawParamsMapped)? drawParamsMapped(userData, index): 1;
+
+ if (flag == 0) { /* flag 0 == the face is hidden or invisible */
+ if(tf) tf += gridFaces*gridFaces*numVerts;
+ if(mcol) mcol += gridFaces*gridFaces*numVerts*4;
+ continue;
+ }
+
+ /* flag 1 == use vertex colors */
+ if(mcol) {
+ if(flag==1) cp= (unsigned char*)mcol;
+ mcol += gridFaces*gridFaces*numVerts*4;
+ }
+
+ for (S=0; S<numVerts; S++) {
+ VertData *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S);
+ VertData *a, *b;
+
+ if (drawSmooth) {
+ glShadeModel(GL_SMOOTH);
+ for (y=0; y<gridFaces; y++) {
+ glBegin(GL_QUAD_STRIP);
+ for (x=0; x<gridFaces; x++) {
+ a = &faceGridData[(y+0)*gridSize + x];
+ b = &faceGridData[(y+1)*gridSize + x];
+
+ if(tf) glTexCoord2fv(tf->uv[0]);
+ if(cp) glColor3ub(cp[3], cp[2], cp[1]);
+ glNormal3fv(a->no);
+ glVertex3fv(a->co);
+
+ if(tf) glTexCoord2fv(tf->uv[1]);
+ if(cp) glColor3ub(cp[7], cp[6], cp[5]);
+ glNormal3fv(b->no);
+ glVertex3fv(b->co);
+
+ if(x != gridFaces-1) {
+ if(tf) tf++;
+ if(cp) cp += 16;
+ }
+ }
+
+ a = &faceGridData[(y+0)*gridSize + x];
+ b = &faceGridData[(y+1)*gridSize + x];
+
+ if(tf) glTexCoord2fv(tf->uv[3]);
+ if(cp) glColor3ub(cp[15], cp[14], cp[13]);
+ glNormal3fv(a->no);
+ glVertex3fv(a->co);
+
+ if(tf) glTexCoord2fv(tf->uv[2]);
+ if(cp) glColor3ub(cp[11], cp[10], cp[9]);
+ glNormal3fv(b->no);
+ glVertex3fv(b->co);
+
+ if(tf) tf++;
+ if(cp) cp += 16;
+
+ glEnd();
+ }
+ } else {
+ glShadeModel(GL_FLAT);
+ glBegin(GL_QUADS);
+ for (y=0; y<gridFaces; y++) {
+ for (x=0; x<gridFaces; x++) {
+ float *a = faceGridData[(y+0)*gridSize + x].co;
+ float *b = faceGridData[(y+0)*gridSize + x + 1].co;
+ float *c = faceGridData[(y+1)*gridSize + x + 1].co;
+ float *d = faceGridData[(y+1)*gridSize + x].co;
+
+ ccgDM_glNormalFast(a, b, c, d);
+
+ if(tf) glTexCoord2fv(tf->uv[1]);
+ if(cp) glColor3ub(cp[7], cp[6], cp[5]);
+ glVertex3fv(d);
+
+ if(tf) glTexCoord2fv(tf->uv[2]);
+ if(cp) glColor3ub(cp[11], cp[10], cp[9]);
+ glVertex3fv(c);
+
+ if(tf) glTexCoord2fv(tf->uv[3]);
+ if(cp) glColor3ub(cp[15], cp[14], cp[13]);
+ glVertex3fv(b);
+
+ if(tf) glTexCoord2fv(tf->uv[0]);
+ if(cp) glColor3ub(cp[3], cp[2], cp[1]);
+ glVertex3fv(a);
+
+ if(tf) tf++;
+ if(cp) cp += 16;
+ }
+ }
+ glEnd();
+ }
+ }
+ }
+}
+
+static void ccgDM_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tface, MCol *mcol, int matnr))
+{
+ ccgDM_drawFacesTex_common(dm, setDrawOptions, NULL, NULL);
+}
+
+static void ccgDM_drawMappedFacesTex(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData)
+{
+ ccgDM_drawFacesTex_common(dm, NULL, setDrawOptions, userData);
+}
+
+static void ccgDM_drawUVEdges(DerivedMesh *dm)
+{
+
+ MFace *mf = dm->getFaceArray(dm);
+ MTFace *tf = DM_get_face_data_layer(dm, CD_MTFACE);
+ int i;
+
+ if (tf) {
+ glBegin(GL_LINES);
+ for(i = 0; i < dm->numFaceData; i++, mf++, tf++) {
+ if(!(mf->flag&ME_HIDE)) {
+ glVertex2fv(tf->uv[0]);
+ glVertex2fv(tf->uv[1]);
+
+ glVertex2fv(tf->uv[1]);
+ glVertex2fv(tf->uv[2]);
+
+ if(!mf->v4) {
+ glVertex2fv(tf->uv[2]);
+ glVertex2fv(tf->uv[0]);
+ } else {
+ glVertex2fv(tf->uv[2]);
+ glVertex2fv(tf->uv[3]);
+
+ glVertex2fv(tf->uv[3]);
+ glVertex2fv(tf->uv[0]);
+ }
+ }
+ }
+ glEnd();
+ }
+}
+
+static void ccgDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int useColors) {
+ GLubyte act_face_stipple[32*32/8] = DM_FACE_STIPPLE;
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
+ CCGSubSurf *ss = ccgdm->ss;
+ CCGFaceIterator *fi = ccgSubSurf_getFaceIterator(ss);
+ int i, gridSize = ccgSubSurf_getGridSize(ss);
+ char *faceFlags = dm->getFaceDataArray(dm, CD_FLAGS);
+
+ for (i=0; !ccgFaceIterator_isStopped(fi); i++,ccgFaceIterator_next(fi)) {
+ CCGFace *f = ccgFaceIterator_getCurrent(fi);
+ int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(ss, f);
+ int drawSmooth, index = ccgDM_getFaceMapIndex(ccgdm, ss, f);
+ int origIndex;
+
+ origIndex = (int)ccgSubSurf_getFaceFaceHandle(ss, f);
+
+ if(faceFlags) drawSmooth = (faceFlags[origIndex*4] & ME_SMOOTH);
+ else drawSmooth = 1;
+
+ if (index!=-1) {
+ int draw;
+ draw = setDrawOptions==NULL ? 1 : setDrawOptions(userData, index, &drawSmooth);
+
+ if (draw) {
+ if (draw==2) {
+ glEnable(GL_POLYGON_STIPPLE);
+ glPolygonStipple(act_face_stipple);
+ }
+
+ for (S=0; S<numVerts; S++) {
+ VertData *faceGridData = ccgSubSurf_getFaceGridDataArray(ss, f, S);
+ if (drawSmooth) {
+ glShadeModel(GL_SMOOTH);
+ for (y=0; y<gridSize-1; y++) {
+ glBegin(GL_QUAD_STRIP);
+ for (x=0; x<gridSize; x++) {
+ VertData *a = &faceGridData[(y+0)*gridSize + x];
+ VertData *b = &faceGridData[(y+1)*gridSize + x];
+
+ glNormal3fv(a->no);
+ glVertex3fv(a->co);
+ glNormal3fv(b->no);
+ glVertex3fv(b->co);
+ }
+ glEnd();
+ }
+ } else {
+ glShadeModel(GL_FLAT);
+ glBegin(GL_QUADS);
+ for (y=0; y<gridSize-1; y++) {
+ for (x=0; x<gridSize-1; x++) {
+ float *a = faceGridData[(y+0)*gridSize + x].co;
+ float *b = faceGridData[(y+0)*gridSize + x + 1].co;
+ float *c = faceGridData[(y+1)*gridSize + x + 1].co;
+ float *d = faceGridData[(y+1)*gridSize + x].co;
+ float a_cX = c[0]-a[0], a_cY = c[1]-a[1], a_cZ = c[2]-a[2];
+ float b_dX = d[0]-b[0], b_dY = d[1]-b[1], b_dZ = d[2]-b[2];
+ float no[3];
+
+ no[0] = b_dY*a_cZ - b_dZ*a_cY;
+ no[1] = b_dZ*a_cX - b_dX*a_cZ;
+ no[2] = b_dX*a_cY - b_dY*a_cX;
+ glNormal3fv(no);
+
+ glVertex3fv(d);
+ glVertex3fv(c);
+ glVertex3fv(b);
+ glVertex3fv(a);
+ }
+ }
+ glEnd();
+ }
+ }
+ if (draw==2)
+ glDisable(GL_POLYGON_STIPPLE);
+ }
+ }
+ }
+
+ ccgFaceIterator_free(fi);
+}
+static void ccgDM_drawMappedEdges(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData) {
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
+ CCGSubSurf *ss = ccgdm->ss;
+ CCGEdgeIterator *ei = ccgSubSurf_getEdgeIterator(ss);
+ int i, useAging, edgeSize = ccgSubSurf_getEdgeSize(ss);
+
+ ccgSubSurf_getUseAgeCounts(ss, &useAging, NULL, NULL, NULL);
+
+ for (; !ccgEdgeIterator_isStopped(ei); ccgEdgeIterator_next(ei)) {
+ CCGEdge *e = ccgEdgeIterator_getCurrent(ei);
+ VertData *edgeData = ccgSubSurf_getEdgeDataArray(ss, e);
+ int index = ccgDM_getEdgeMapIndex(ccgdm, ss, e);
+
+ glBegin(GL_LINE_STRIP);
+ if (index!=-1 && (!setDrawOptions || setDrawOptions(userData, index))) {
+ if (useAging && !(G.f&G_BACKBUFSEL)) {
+ int ageCol = 255-ccgSubSurf_getEdgeAge(ss, e)*4;
+ glColor3ub(0, ageCol>0?ageCol:0, 0);
+ }
+
+ for (i=0; i<edgeSize-1; i++) {
+ glVertex3fv(edgeData[i].co);
+ glVertex3fv(edgeData[i+1].co);
+ }
+ }
+ glEnd();
+ }
+
+ ccgEdgeIterator_free(ei);
+}
+static void ccgDM_drawMappedEdgesInterp(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void (*setDrawInterpOptions)(void *userData, int index, float t), void *userData) {
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
+ CCGSubSurf *ss = ccgdm->ss;
+ CCGEdgeIterator *ei = ccgSubSurf_getEdgeIterator(ss);
+ int i, useAging, edgeSize = ccgSubSurf_getEdgeSize(ss);
+
+ ccgSubSurf_getUseAgeCounts(ss, &useAging, NULL, NULL, NULL);
+
+ for (; !ccgEdgeIterator_isStopped(ei); ccgEdgeIterator_next(ei)) {
+ CCGEdge *e = ccgEdgeIterator_getCurrent(ei);
+ VertData *edgeData = ccgSubSurf_getEdgeDataArray(ss, e);
+ int index = ccgDM_getEdgeMapIndex(ccgdm, ss, e);
+
+ glBegin(GL_LINE_STRIP);
+ if (index!=-1 && (!setDrawOptions || setDrawOptions(userData, index))) {
+ for (i=0; i<edgeSize; i++) {
+ setDrawInterpOptions(userData, index, (float) i/(edgeSize-1));
+
+ if (useAging && !(G.f&G_BACKBUFSEL)) {
+ int ageCol = 255-ccgSubSurf_getEdgeAge(ss, e)*4;
+ glColor3ub(0, ageCol>0?ageCol:0, 0);
+ }
+
+ glVertex3fv(edgeData[i].co);
+ }
+ }
+ glEnd();
+ }
+
+ ccgEdgeIterator_free(ei);
+}
+static void ccgDM_foreachMappedFaceCenter(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no), void *userData) {
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
+ CCGSubSurf *ss = ccgdm->ss;
+ CCGFaceIterator *fi = ccgSubSurf_getFaceIterator(ss);
+
+ for (; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) {
+ CCGFace *f = ccgFaceIterator_getCurrent(fi);
+ int index = ccgDM_getFaceMapIndex(ccgdm, ss, f);
+
+ if (index!=-1) {
+ /* Face center data normal isn't updated atm. */
+ VertData *vd = ccgSubSurf_getFaceGridData(ss, f, 0, 0, 0);
+
+ func(userData, index, vd->co, vd->no);
+ }
+ }
+
+ ccgFaceIterator_free(fi);
+}
+
+static void ccgDM_release(DerivedMesh *dm) {
+ CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
+
+ if (DM_release(dm)) {
+ MEM_freeN(ccgdm->vertMap);
+ MEM_freeN(ccgdm->edgeMap);
+ MEM_freeN(ccgdm->faceMap);
+ MEM_freeN(ccgdm);
+ }
+}
+
+static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
+ int drawInteriorEdges,
+ int useSubsurfUv,
+ DerivedMesh *dm)
+{
+ CCGDerivedMesh *ccgdm = MEM_callocN(sizeof(*ccgdm), "ccgdm");
+ CCGVertIterator *vi;
+ CCGEdgeIterator *ei;
+ CCGFaceIterator *fi;
+ int index, totvert, totedge, totface;
+ int i;
+ int vertNum, edgeNum, faceNum;
+ int *vertOrigIndex, *edgeOrigIndex, *faceOrigIndex;
+ int *edgeFlags;
+ char *faceFlags;
+ int edgeSize;
+ int gridSize;
+ int gridFaces;
+ int gridSideVerts;
+ int gridInternalVerts;
+ int gridSideEdges;
+ int gridInternalEdges;
+ MVert *mvert = NULL;
+ MEdge *medge = NULL;
+ MFace *mface = NULL;
+ FaceVertWeight *qweight, *tweight;
+
+ DM_from_template(&ccgdm->dm, dm, ccgSubSurf_getNumFinalVerts(ss),
+ ccgSubSurf_getNumFinalEdges(ss),
+ ccgSubSurf_getNumFinalFaces(ss));
+ DM_add_face_layer(&ccgdm->dm, CD_FLAGS, CD_CALLOC, NULL);
+ DM_add_edge_layer(&ccgdm->dm, CD_FLAGS, CD_CALLOC, NULL);
+
+ CustomData_set_layer_flag(&ccgdm->dm.faceData, CD_FLAGS, CD_FLAG_NOCOPY);
+ CustomData_set_layer_flag(&ccgdm->dm.edgeData, CD_FLAGS, CD_FLAG_NOCOPY);
+
+ ccgdm->dm.getMinMax = ccgDM_getMinMax;
+ ccgdm->dm.getNumVerts = ccgDM_getNumVerts;
+ ccgdm->dm.getNumFaces = ccgDM_getNumFaces;
+
+ ccgdm->dm.getNumEdges = ccgDM_getNumEdges;
+ ccgdm->dm.getVert = ccgDM_getFinalVert;
+ ccgdm->dm.getEdge = ccgDM_getFinalEdge;
+ ccgdm->dm.getFace = ccgDM_getFinalFace;
+ ccgdm->dm.copyVertArray = ccgDM_copyFinalVertArray;
+ ccgdm->dm.copyEdgeArray = ccgDM_copyFinalEdgeArray;
+ ccgdm->dm.copyFaceArray = ccgDM_copyFinalFaceArray;
+ ccgdm->dm.getVertData = DM_get_vert_data;
+ ccgdm->dm.getEdgeData = DM_get_edge_data;
+ ccgdm->dm.getFaceData = DM_get_face_data;
+ ccgdm->dm.getVertDataArray = DM_get_vert_data_layer;
+ ccgdm->dm.getEdgeDataArray = DM_get_edge_data_layer;
+ ccgdm->dm.getFaceDataArray = DM_get_face_data_layer;
+
+ ccgdm->dm.getVertCos = ccgdm_getVertCos;
+ ccgdm->dm.foreachMappedVert = ccgDM_foreachMappedVert;
+ ccgdm->dm.foreachMappedEdge = ccgDM_foreachMappedEdge;
+ ccgdm->dm.foreachMappedFaceCenter = ccgDM_foreachMappedFaceCenter;
+
+ ccgdm->dm.drawVerts = ccgDM_drawVerts;
+ ccgdm->dm.drawEdges = ccgDM_drawEdges;
+ ccgdm->dm.drawLooseEdges = ccgDM_drawLooseEdges;
+ ccgdm->dm.drawFacesSolid = ccgDM_drawFacesSolid;
+ ccgdm->dm.drawFacesColored = ccgDM_drawFacesColored;
+ ccgdm->dm.drawFacesTex = ccgDM_drawFacesTex;
+ ccgdm->dm.drawMappedFaces = ccgDM_drawMappedFaces;
+ ccgdm->dm.drawMappedFacesTex = ccgDM_drawMappedFacesTex;
+ ccgdm->dm.drawUVEdges = ccgDM_drawUVEdges;
+
+ ccgdm->dm.drawMappedEdgesInterp = ccgDM_drawMappedEdgesInterp;
+ ccgdm->dm.drawMappedEdges = ccgDM_drawMappedEdges;
+
+ ccgdm->dm.release = ccgDM_release;
+
+ ccgdm->ss = ss;
+ ccgdm->drawInteriorEdges = drawInteriorEdges;
+ ccgdm->useSubsurfUv = useSubsurfUv;
+
+ totvert = ccgSubSurf_getNumVerts(ss);
+ ccgdm->vertMap = MEM_mallocN(totvert * sizeof(*ccgdm->vertMap), "vertMap");
+ vi = ccgSubSurf_getVertIterator(ss);
+ for(; !ccgVertIterator_isStopped(vi); ccgVertIterator_next(vi)) {
+ CCGVert *v = ccgVertIterator_getCurrent(vi);
+
+ ccgdm->vertMap[(int) ccgSubSurf_getVertVertHandle(ss, v)].vert = v;
+ }
+ ccgVertIterator_free(vi);
+
+ totedge = ccgSubSurf_getNumEdges(ss);
+ ccgdm->edgeMap = MEM_mallocN(totedge * sizeof(*ccgdm->edgeMap), "edgeMap");
+ ei = ccgSubSurf_getEdgeIterator(ss);
+ for(; !ccgEdgeIterator_isStopped(ei); ccgEdgeIterator_next(ei)) {
+ CCGEdge *e = ccgEdgeIterator_getCurrent(ei);
+
+ ccgdm->edgeMap[(int) ccgSubSurf_getEdgeEdgeHandle(ss, e)].edge = e;
+ }
+
+ totface = ccgSubSurf_getNumFaces(ss);
+ ccgdm->faceMap = MEM_mallocN(totface * sizeof(*ccgdm->faceMap), "faceMap");
+ fi = ccgSubSurf_getFaceIterator(ss);
+ for(; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) {
+ CCGFace *f = ccgFaceIterator_getCurrent(fi);
+
+ ccgdm->faceMap[(int) ccgSubSurf_getFaceFaceHandle(ss, f)].face = f;
+ }
+ ccgFaceIterator_free(fi);
+
+ edgeSize = ccgSubSurf_getEdgeSize(ss);
+ gridSize = ccgSubSurf_getGridSize(ss);
+ gridFaces = gridSize - 1;
+ gridSideVerts = gridSize - 2;
+ gridInternalVerts = gridSideVerts * gridSideVerts;
+ gridSideEdges = gridSize - 1;
+ gridInternalEdges = (gridSideEdges - 1) * gridSideEdges * 2;
+
+ calc_ss_weights(gridFaces, &qweight, &tweight);
+
+ vertNum = 0;
+ edgeNum = 0;
+ faceNum = 0;
+
+ mvert = dm->getVertArray(dm);
+ medge = dm->getEdgeArray(dm);
+ mface = dm->getFaceArray(dm);
+
+ vertOrigIndex = DM_get_vert_data_layer(&ccgdm->dm, CD_ORIGINDEX);
+ edgeOrigIndex = DM_get_edge_data_layer(&ccgdm->dm, CD_ORIGINDEX);
+ faceOrigIndex = DM_get_face_data_layer(&ccgdm->dm, CD_ORIGINDEX);
+
+ faceFlags = DM_get_face_data_layer(&ccgdm->dm, CD_FLAGS);
+
+ for(index = 0; index < totface; ++index) {
+ CCGFace *f = ccgdm->faceMap[index].face;
+ int numVerts = ccgSubSurf_getFaceNumVerts(ss, f);
+ int numFinalEdges = numVerts * (gridSideEdges + gridInternalEdges);
+ int mapIndex = ccgDM_getFaceMapIndex(ccgdm, ss, f);
+ int origIndex = (int)ccgSubSurf_getFaceFaceHandle(ss, f);
+ FaceVertWeight *weight = (numVerts == 4) ? qweight : tweight;
+ int S, x, y;
+ int vertIdx[4];
+
+ ccgdm->faceMap[index].startVert = vertNum;
+ ccgdm->faceMap[index].startEdge = edgeNum;
+ ccgdm->faceMap[index].startFace = faceNum;
+
+ /* set the face base vert */
+ *((int*)ccgSubSurf_getFaceUserData(ss, f)) = vertNum;
+
+ for(S = 0; S < numVerts; S++) {
+ CCGVert *v = ccgSubSurf_getFaceVert(ss, f, S);
+
+ vertIdx[S] = (int)ccgSubSurf_getVertVertHandle(ss, v);
+ }
+
+ DM_interp_vert_data(dm, &ccgdm->dm, vertIdx, weight[0][0],
+ numVerts, vertNum);
+ *vertOrigIndex = ORIGINDEX_NONE;
+ ++vertOrigIndex;
+ ++vertNum;
+
+ for(S = 0; S < numVerts; S++) {
+ int prevS = (S - 1 + numVerts) % numVerts;
+ int nextS = (S + 1) % numVerts;
+ int otherS = (numVerts == 4) ? (S + 2) % numVerts : 3;
+ for(x = 1; x < gridFaces; x++) {
+ float w[4];
+ w[prevS] = weight[x][0][0];
+ w[S] = weight[x][0][1];
+ w[nextS] = weight[x][0][2];
+ w[otherS] = weight[x][0][3];
+ DM_interp_vert_data(dm, &ccgdm->dm, vertIdx, w,
+ numVerts, vertNum);
+ *vertOrigIndex = ORIGINDEX_NONE;
+ ++vertOrigIndex;
+ ++vertNum;
+ }
+ }
+
+ for(S = 0; S < numVerts; S++) {
+ int prevS = (S - 1 + numVerts) % numVerts;
+ int nextS = (S + 1) % numVerts;
+ int otherS = (numVerts == 4) ? (S + 2) % numVerts : 3;
+ for(y = 1; y < gridFaces; y++) {
+ for(x = 1; x < gridFaces; x++) {
+ float w[4];
+ w[prevS] = weight[y * gridFaces + x][0][0];
+ w[S] = weight[y * gridFaces + x][0][1];
+ w[nextS] = weight[y * gridFaces + x][0][2];
+ w[otherS] = weight[y * gridFaces + x][0][3];
+ DM_interp_vert_data(dm, &ccgdm->dm, vertIdx, w,
+ numVerts, vertNum);
+ *vertOrigIndex = ORIGINDEX_NONE;
+ ++vertOrigIndex;
+ ++vertNum;
+ }
+ }
+ }
+
+ for(i = 0; i < numFinalEdges; ++i)
+ *(int *)DM_get_edge_data(&ccgdm->dm, edgeNum + i,
+ CD_ORIGINDEX) = ORIGINDEX_NONE;
+
+ for(S = 0; S < numVerts; S++) {
+ int prevS = (S - 1 + numVerts) % numVerts;
+ int nextS = (S + 1) % numVerts;
+ int otherS = (numVerts == 4) ? (S + 2) % numVerts : 3;
+
+ weight = (numVerts == 4) ? qweight : tweight;
+
+ for(y = 0; y < gridFaces; y++) {
+ for(x = 0; x < gridFaces; x++) {
+ FaceVertWeight w;
+ int j;
+
+ for(j = 0; j < 4; ++j) {
+ w[j][prevS] = (*weight)[j][0];
+ w[j][S] = (*weight)[j][1];
+ w[j][nextS] = (*weight)[j][2];
+ w[j][otherS] = (*weight)[j][3];
+ }
+
+ DM_interp_face_data(dm, &ccgdm->dm, &origIndex, NULL,
+ &w, 1, faceNum);
+ weight++;
+
+ *faceOrigIndex = mapIndex;
+
+ ++faceOrigIndex;
+ ++faceNum;
+ }
+ }
+ }
+
+ faceFlags[index*4] = mface[origIndex].flag;
+ faceFlags[index*4 + 1] = mface[origIndex].mat_nr;
+
+ edgeNum += numFinalEdges;
+ }
+
+ if(useSubsurfUv) {
+ CustomData *fdata = &ccgdm->dm.faceData;
+ CustomData *dmfdata = &dm->faceData;
+ int numlayer = CustomData_number_of_layers(fdata, CD_MTFACE);
+ int dmnumlayer = CustomData_number_of_layers(dmfdata, CD_MTFACE);
+
+ for (i=0; i<numlayer && i<dmnumlayer; i++)
+ set_subsurf_uv(ss, dm, &ccgdm->dm, i);
+ }
+
+ edgeFlags = DM_get_edge_data_layer(&ccgdm->dm, CD_FLAGS);
+
+ for(index = 0; index < totedge; ++index) {
+ CCGEdge *e = ccgdm->edgeMap[index].edge;
+ int numFinalEdges = edgeSize - 1;
+ int mapIndex = ccgDM_getEdgeMapIndex(ccgdm, ss, e);
+ int x;
+ int vertIdx[2];
+ int edgeIdx = (int)ccgSubSurf_getEdgeEdgeHandle(ss, e);
+
+ CCGVert *v;
+ v = ccgSubSurf_getEdgeVert0(ss, e);
+ vertIdx[0] = (int)ccgSubSurf_getVertVertHandle(ss, v);
+ v = ccgSubSurf_getEdgeVert1(ss, e);
+ vertIdx[1] = (int)ccgSubSurf_getVertVertHandle(ss, v);
+
+ ccgdm->edgeMap[index].startVert = vertNum;
+ ccgdm->edgeMap[index].startEdge = edgeNum;
+
+ /* set the edge base vert */
+ *((int*)ccgSubSurf_getEdgeUserData(ss, e)) = vertNum;
+
+ for(x = 1; x < edgeSize - 1; x++) {
+ float w[2];
+ w[1] = (float) x / (edgeSize - 1);
+ w[0] = 1 - w[1];
+ DM_interp_vert_data(dm, &ccgdm->dm, vertIdx, w, 2, vertNum);
+ *vertOrigIndex = ORIGINDEX_NONE;
+ ++vertOrigIndex;
+ ++vertNum;
+ }
+
+ for(i = 0; i < numFinalEdges; ++i) {
+ if(edgeIdx >= 0 && edgeFlags)
+ edgeFlags[edgeNum + i] = medge[edgeIdx].flag;
+
+ *(int *)DM_get_edge_data(&ccgdm->dm, edgeNum + i,
+ CD_ORIGINDEX) = mapIndex;
+ }
+
+ edgeNum += numFinalEdges;
+ }
+
+ for(index = 0; index < totvert; ++index) {
+ CCGVert *v = ccgdm->vertMap[index].vert;
+ int mapIndex = ccgDM_getVertMapIndex(ccgdm, ccgdm->ss, v);
+ int vertIdx;
+
+ vertIdx = (int)ccgSubSurf_getVertVertHandle(ss, v);
+
+ ccgdm->vertMap[index].startVert = vertNum;
+
+ /* set the vert base vert */
+ *((int*) ccgSubSurf_getVertUserData(ss, v)) = vertNum;
+
+ DM_copy_vert_data(dm, &ccgdm->dm, vertIdx, vertNum, 1);
+
+ *vertOrigIndex = mapIndex;
+ ++vertOrigIndex;
+ ++vertNum;
+ }
+
+ MEM_freeN(qweight);
+ MEM_freeN(tweight);
+
+ return ccgdm;
+}
+
+/***/
+
+struct DerivedMesh *subsurf_make_derived_from_derived(
+ struct DerivedMesh *dm,
+ struct SubsurfModifierData *smd,
+ int useRenderParams, float (*vertCos)[3],
+ int isFinalCalc, int editMode)
+{
+ int useSimple = smd->subdivType == ME_SIMPLE_SUBSURF;
+ int useAging = smd->flags & eSubsurfModifierFlag_DebugIncr;
+ int useSubsurfUv = smd->flags & eSubsurfModifierFlag_SubsurfUv;
+ int drawInteriorEdges = !(smd->flags & eSubsurfModifierFlag_ControlEdges);
+ DerivedMesh *result;
+
+ if(editMode) {
+ smd->emCache = _getSubSurf(smd->emCache, smd->levels, useAging, 0,
+ useSimple);
+ ss_sync_from_derivedmesh(smd->emCache, dm, vertCos, useSimple);
+
+ return (DerivedMesh *)getCCGDerivedMesh(smd->emCache,
+ drawInteriorEdges,
+ useSubsurfUv, dm);
+ } else if(useRenderParams) {
+ /* Do not use cache in render mode. */
+ CCGSubSurf *ss = _getSubSurf(NULL, smd->renderLevels, 0, 1, useSimple);
+
+ ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple);
+
+ result = ss_to_cdderivedmesh(ss, 0, drawInteriorEdges,
+ useSubsurfUv, dm);
+
+ ccgSubSurf_free(ss);
+
+ return result;
+ } else {
+ int useIncremental = (smd->flags & eSubsurfModifierFlag_Incremental);
+ int useAging = smd->flags & eSubsurfModifierFlag_DebugIncr;
+ CCGSubSurf *ss;
+
+ /* It is quite possible there is a much better place to do this. It
+ * depends a bit on how rigourously we expect this function to never
+ * be called in editmode. In semi-theory we could share a single
+ * cache, but the handles used inside and outside editmode are not
+ * the same so we would need some way of converting them. Its probably
+ * not worth the effort. But then why am I even writing this long
+ * comment that no one will read? Hmmm. - zr
+ */
+ if(smd->emCache) {
+ ccgSubSurf_free(smd->emCache);
+ smd->emCache = NULL;
+ }
+
+ if(useIncremental && isFinalCalc) {
+ smd->mCache = ss = _getSubSurf(smd->mCache, smd->levels,
+ useAging, 0, useSimple);
+
+ ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple);
+
+
+ return ss_to_cdderivedmesh(ss, 0, drawInteriorEdges,
+ useSubsurfUv, dm);
+
+ /*return (DerivedMesh *)getCCGDerivedMesh(smd->mCache,
+ drawInteriorEdges,
+ useSubsurfUv, dm);*/
+ } else {
+ if (smd->mCache && isFinalCalc) {
+ ccgSubSurf_free(smd->mCache);
+ smd->mCache = NULL;
+ }
+
+ ss = _getSubSurf(NULL, smd->levels, 0, 1, useSimple);
+ ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple);
+
+ /*smd->mCache = ss;
+ result = (DerivedMesh *)getCCGDerivedMesh(smd->mCache,
+ drawInteriorEdges,
+ useSubsurfUv, dm);*/
+
+ result = ss_to_cdderivedmesh(ss, 0, drawInteriorEdges,
+ useSubsurfUv, dm);
+
+ ccgSubSurf_free(ss);
+
+ return result;
+ }
+ }
+}
+
+void subsurf_calculate_limit_positions(Mesh *me, float (*positions_r)[3])
+{
+ /* Finds the subsurf limit positions for the verts in a mesh
+ * and puts them in an array of floats. Please note that the
+ * calculated vert positions is incorrect for the verts
+ * on the boundary of the mesh.
+ */
+ CCGSubSurf *ss = _getSubSurf(NULL, 1, 0, 1, 0);
+ float edge_sum[3], face_sum[3];
+ CCGVertIterator *vi;
+ DerivedMesh *dm = CDDM_from_mesh(me, NULL);
+
+ ss_sync_from_derivedmesh(ss, dm, NULL, 0);
+
+ vi = ccgSubSurf_getVertIterator(ss);
+ for (; !ccgVertIterator_isStopped(vi); ccgVertIterator_next(vi)) {
+ CCGVert *v = ccgVertIterator_getCurrent(vi);
+ int idx = (int) ccgSubSurf_getVertVertHandle(ss, v);
+ int N = ccgSubSurf_getVertNumEdges(ss, v);
+ int numFaces = ccgSubSurf_getVertNumFaces(ss, v);
+ float *co;
+ int i;
+
+ edge_sum[0]= edge_sum[1]= edge_sum[2]= 0.0;
+ face_sum[0]= face_sum[1]= face_sum[2]= 0.0;
+
+ for (i=0; i<N; i++) {
+ CCGEdge *e = ccgSubSurf_getVertEdge(ss, v, i);
+ VecAddf(edge_sum, edge_sum, ccgSubSurf_getEdgeData(ss, e, 1));
+ }
+ for (i=0; i<numFaces; i++) {
+ CCGFace *f = ccgSubSurf_getVertFace(ss, v, i);
+ VecAddf(face_sum, face_sum, ccgSubSurf_getFaceCenterData(ss, f));
+ }
+
+ /* ad-hoc correction for boundary vertices, to at least avoid them
+ moving completely out of place (brecht) */
+ if(numFaces && numFaces != N)
+ VecMulf(face_sum, (float)N/(float)numFaces);
+
+ co = ccgSubSurf_getVertData(ss, v);
+ positions_r[idx][0] = (co[0]*N*N + edge_sum[0]*4 + face_sum[0])/(N*(N+5));
+ positions_r[idx][1] = (co[1]*N*N + edge_sum[1]*4 + face_sum[1])/(N*(N+5));
+ positions_r[idx][2] = (co[2]*N*N + edge_sum[2]*4 + face_sum[2])/(N*(N+5));
+ }
+ ccgVertIterator_free(vi);
+
+ ccgSubSurf_free(ss);
+
+ dm->release(dm);
+}
+
diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c
new file mode 100644
index 00000000000..ea0dabe1e81
--- /dev/null
+++ b/source/blender/blenkernel/intern/text.c
@@ -0,0 +1,2393 @@
+/* text.c
+ *
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <string.h> /* strstr */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_text_types.h"
+
+#include "BKE_bad_level_calls.h"
+#include "BKE_utildefines.h"
+#include "BKE_text.h"
+#include "BKE_library.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+
+#include "BPY_extern.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/***************/ /*
+
+How Texts should work
+--
+A text should relate to a file as follows -
+(Text *)->name should be the place where the
+ file will or has been saved.
+
+(Text *)->flags has the following bits
+ TXT_ISDIRTY - should always be set if the file in mem. differs from
+ the file on disk, or if there is no file on disk.
+ TXT_ISTMP - should always be set if the (Text *)->name file has not
+ been written before, and attempts to save should result
+ in "Save over?"
+ TXT_ISMEM - should always be set if the Text has not been mapped to
+ a file, in which case (Text *)->name may be NULL or garbage.
+ TXT_ISEXT - should always be set if the Text is not to be written into
+ the .blend
+ TXT_ISSCRIPT - should be set if the user has designated the text
+ as a script. (NEW: this was unused, but now it is needed by
+ space handler script links (see header_view3d.c, for example)
+
+->>> see also: /makesdna/DNA_text_types.h
+
+Display
+--
+The st->top determines at what line the top of the text is displayed.
+If the user moves the cursor the st containing that cursor should
+be popped ... other st's retain their own top location.
+
+*/ /***************/
+
+
+/****************/ /*
+ Undo
+
+Undo/Redo works by storing
+events in a queue, and a pointer
+to the current position in the
+queue...
+
+Events are stored using an
+arbitrary op-code system
+to keep track of
+a) the two cursors (normal and selected)
+b) input (visible and control (ie backspace))
+
+input data is stored as its
+ASCII value, the opcodes are
+then selected to not conflict.
+
+opcodes with data in between are
+written at the beginning and end
+of the data to allow undo and redo
+to simply check the code at the current
+undo position
+
+*/ /***************/
+
+/***/
+
+static void txt_pop_first(Text *text);
+static void txt_pop_last(Text *text);
+static void txt_undo_add_op(Text *text, int op);
+static void txt_undo_add_block(Text *text, int op, char *buf);
+static void txt_delete_line(Text *text, TextLine *line);
+
+/***/
+
+static char *txt_cut_buffer= NULL;
+static unsigned char undoing;
+
+/* allow to switch off undoing externally */
+void txt_set_undostate(int u)
+{
+ undoing = u;
+}
+
+int txt_get_undostate(void)
+{
+ return undoing;
+}
+
+void free_text(Text *text)
+{
+ TextLine *tmp;
+
+ for (tmp= text->lines.first; tmp; tmp= tmp->next) {
+ MEM_freeN(tmp->line);
+ if (tmp->format)
+ MEM_freeN(tmp->format);
+ }
+
+ BLI_freelistN(&text->lines);
+
+ if(text->name) MEM_freeN(text->name);
+ MEM_freeN(text->undo_buf);
+ if (text->compiled) BPY_free_compiled_text(text);
+}
+
+Text *add_empty_text(char *name)
+{
+ Text *ta;
+ TextLine *tmp;
+
+ ta= alloc_libblock(&G.main->text, ID_TXT, name);
+ ta->id.us= 1;
+
+ ta->name= NULL;
+
+ ta->undo_pos= -1;
+ ta->undo_len= TXT_INIT_UNDO;
+ ta->undo_buf= MEM_mallocN(ta->undo_len, "undo buf");
+
+ ta->nlines=1;
+ ta->flags= TXT_ISDIRTY | TXT_ISTMP | TXT_ISMEM;
+
+ ta->lines.first= ta->lines.last= NULL;
+
+ tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
+ tmp->line= (char*) MEM_mallocN(1, "textline_string");
+ tmp->format= (char*) MEM_mallocN(2, "Syntax_format");
+
+ tmp->line[0]=0;
+ tmp->len= 0;
+
+ tmp->next= NULL;
+ tmp->prev= NULL;
+
+ BLI_addhead(&ta->lines, tmp);
+
+ ta->curl= ta->lines.first;
+ ta->curc= 0;
+ ta->sell= ta->lines.first;
+ ta->selc= 0;
+
+ return ta;
+}
+
+// this function removes any control characters from
+// a textline
+
+static void cleanup_textline(TextLine * tl)
+{
+ int i;
+
+ for (i = 0; i < tl->len; i++ ) {
+ if (tl->line[i] < ' ' && tl->line[i] != '\t') {
+ memmove(tl->line + i, tl->line + i + 1, tl->len - i);
+ tl->len--;
+ i--;
+ }
+ }
+}
+
+int reopen_text(Text *text)
+{
+ FILE *fp;
+ int i, llen, len;
+ unsigned char *buffer;
+ TextLine *tmp;
+ char sdir[FILE_MAXDIR];
+ char sfile[FILE_MAXFILE];
+ char str[FILE_MAXDIR+FILE_MAXFILE];
+
+ if (!text || !text->name) return 0;
+
+ BLI_strncpy(str, text->name, FILE_MAXDIR+FILE_MAXFILE);
+ BLI_convertstringcode(str, G.sce, G.scene->r.cfra);
+ BLI_split_dirfile(str, sdir, sfile);
+
+ fp= fopen(str, "r");
+ if(fp==NULL) return 0;
+
+ /* free memory: */
+
+ for (tmp= text->lines.first; tmp; tmp= tmp->next) {
+ MEM_freeN(tmp->line);
+ if (tmp->format) MEM_freeN(tmp->format);
+ }
+
+ BLI_freelistN(&text->lines);
+
+ text->lines.first= text->lines.last= NULL;
+ text->curl= text->sell= NULL;
+
+ /* clear undo buffer */
+ MEM_freeN(text->undo_buf);
+ text->undo_pos= -1;
+ text->undo_len= TXT_INIT_UNDO;
+ text->undo_buf= MEM_mallocN(text->undo_len, "undo buf");
+
+ text->flags= TXT_ISDIRTY | TXT_ISTMP;
+
+ fseek(fp, 0L, SEEK_END);
+ len= ftell(fp);
+ fseek(fp, 0L, SEEK_SET);
+
+ text->undo_pos= -1;
+
+ buffer= MEM_mallocN(len, "text_buffer");
+ // under windows fread can return less then len bytes because
+ // of CR stripping
+ len = fread(buffer, 1, len, fp);
+
+ fclose(fp);
+
+ text->nlines=0;
+ i=0;
+ llen=0;
+ for(i=0; i<len; i++) {
+ if (buffer[i]=='\n') {
+ tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
+ tmp->line= (char*) MEM_mallocN(llen+1, "textline_string");
+ tmp->format= (char*) MEM_mallocN(llen+2, "Syntax_format");
+
+ if(llen) memcpy(tmp->line, &buffer[i-llen], llen);
+ tmp->line[llen]=0;
+ tmp->len= llen;
+
+ cleanup_textline(tmp);
+
+ BLI_addtail(&text->lines, tmp);
+ text->nlines++;
+
+ llen=0;
+ continue;
+ }
+ llen++;
+ }
+
+ if (llen!=0 || text->nlines==0) {
+ tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
+ tmp->line= (char*) MEM_mallocN(llen+1, "textline_string");
+ tmp->format= (char*) MEM_mallocN(llen+2, "Syntax_format");
+
+ if(llen) memcpy(tmp->line, &buffer[i-llen], llen);
+
+ tmp->line[llen]=0;
+ tmp->len= llen;
+
+ cleanup_textline(tmp);
+
+ BLI_addtail(&text->lines, tmp);
+ text->nlines++;
+ }
+
+ text->curl= text->sell= text->lines.first;
+ text->curc= text->selc= 0;
+
+ MEM_freeN(buffer);
+ return 1;
+}
+
+Text *add_text(char *file)
+{
+ FILE *fp;
+ int i, llen, len;
+ unsigned char *buffer;
+ TextLine *tmp;
+ Text *ta;
+ char sdir[FILE_MAXDIR];
+ char sfile[FILE_MAXFILE];
+ char str[FILE_MAXDIR+FILE_MAXFILE];
+
+ BLI_strncpy(str, file, FILE_MAXDIR+FILE_MAXFILE);
+ if (G.scene) /* can be NULL (bg mode) */
+ BLI_convertstringcode(str, G.sce, G.scene->r.cfra);
+ BLI_split_dirfile(str, sdir, sfile);
+
+ fp= fopen(str, "r");
+ if(fp==NULL) return NULL;
+
+ ta= alloc_libblock(&G.main->text, ID_TXT, sfile);
+ ta->id.us= 1;
+
+ ta->lines.first= ta->lines.last= NULL;
+ ta->curl= ta->sell= NULL;
+
+/* ta->flags= TXT_ISTMP | TXT_ISEXT; */
+ ta->flags= TXT_ISTMP;
+
+ fseek(fp, 0L, SEEK_END);
+ len= ftell(fp);
+ fseek(fp, 0L, SEEK_SET);
+
+ ta->name= MEM_mallocN(strlen(file)+1, "text_name");
+ strcpy(ta->name, file);
+
+ ta->undo_pos= -1;
+ ta->undo_len= TXT_INIT_UNDO;
+ ta->undo_buf= MEM_mallocN(ta->undo_len, "undo buf");
+
+ buffer= MEM_mallocN(len, "text_buffer");
+ // under windows fread can return less then len bytes because
+ // of CR stripping
+ len = fread(buffer, 1, len, fp);
+
+ fclose(fp);
+
+ ta->nlines=0;
+ i=0;
+ llen=0;
+ for(i=0; i<len; i++) {
+ if (buffer[i]=='\n') {
+ tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
+ tmp->line= (char*) MEM_mallocN(llen+1, "textline_string");
+ tmp->format= (char*) MEM_mallocN(llen+2, "Syntax_format");
+
+ if(llen) memcpy(tmp->line, &buffer[i-llen], llen);
+ tmp->line[llen]=0;
+ tmp->len= llen;
+
+ cleanup_textline(tmp);
+
+ BLI_addtail(&ta->lines, tmp);
+ ta->nlines++;
+
+ llen=0;
+ continue;
+ }
+ llen++;
+ }
+
+ if (llen!=0 || ta->nlines==0) {
+ tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
+ tmp->line= (char*) MEM_mallocN(llen+1, "textline_string");
+ tmp->format= (char*) MEM_mallocN(llen+2, "Syntax_format");
+
+ if(llen) memcpy(tmp->line, &buffer[i-llen], llen);
+
+ tmp->line[llen]=0;
+ tmp->len= llen;
+
+ cleanup_textline(tmp);
+
+ BLI_addtail(&ta->lines, tmp);
+ ta->nlines++;
+ }
+
+ ta->curl= ta->sell= ta->lines.first;
+ ta->curc= ta->selc= 0;
+
+ MEM_freeN(buffer);
+
+ return ta;
+}
+
+Text *copy_text(Text *ta)
+{
+ Text *tan;
+ TextLine *line, *tmp;
+
+ tan= copy_libblock(ta);
+
+ tan->name= MEM_mallocN(strlen(ta->name)+1, "text_name");
+ strcpy(tan->name, ta->name);
+
+ tan->flags = ta->flags | TXT_ISDIRTY | TXT_ISTMP;
+
+ tan->lines.first= tan->lines.last= NULL;
+ tan->curl= tan->sell= NULL;
+
+ tan->nlines= ta->nlines;
+
+ line= ta->lines.first;
+ /* Walk down, reconstructing */
+ while (line) {
+ tmp= (TextLine*) MEM_mallocN(sizeof(TextLine), "textline");
+ tmp->line= MEM_mallocN(line->len+1, "textline_string");
+ tmp->format= MEM_mallocN(line->len+2, "Syntax_format");
+
+ strcpy(tmp->line, line->line);
+
+ tmp->len= line->len;
+
+ BLI_addtail(&tan->lines, tmp);
+
+ line= line->next;
+ }
+
+ tan->curl= tan->sell= tan->lines.first;
+ tan->curc= tan->selc= 0;
+
+ return tan;
+}
+
+/*****************************/
+/* Editing utility functions */
+/*****************************/
+
+static void make_new_line (TextLine *line, char *newline, char *newformat)
+{
+ if (line->line) MEM_freeN(line->line);
+ if (line->format) MEM_freeN(line->format);
+
+ line->line= newline;
+ line->len= strlen(newline);
+ line->format= newformat;
+}
+
+static TextLine *txt_new_line(char *str)
+{
+ TextLine *tmp;
+
+ if(!str) str= "";
+
+ tmp= (TextLine *) MEM_mallocN(sizeof(TextLine), "textline");
+ tmp->line= MEM_mallocN(strlen(str)+1, "textline_string");
+ tmp->format= MEM_mallocN(strlen(str)+2, "Syntax_format");
+
+ strcpy(tmp->line, str);
+
+ tmp->len= strlen(str);
+ tmp->next= tmp->prev= NULL;
+
+ return tmp;
+}
+
+static TextLine *txt_new_linen(char *str, int n)
+{
+ TextLine *tmp;
+
+ if(!str) str= "";
+
+ tmp= (TextLine *) MEM_mallocN(sizeof(TextLine), "textline");
+ tmp->line= MEM_mallocN(n+1, "textline_string");
+ tmp->format= MEM_mallocN(n+2, "Syntax_format");
+
+ BLI_strncpy(tmp->line, str, n+1);
+
+ tmp->len= strlen(tmp->line);
+ tmp->next= tmp->prev= NULL;
+
+ return tmp;
+}
+
+void txt_clean_text (Text *text)
+{
+ TextLine **top, **bot;
+
+ if (!text) return;
+
+ if (!text->lines.first) {
+ if (text->lines.last) text->lines.first= text->lines.last;
+ else text->lines.first= text->lines.last= txt_new_line(NULL);
+ }
+
+ if (!text->lines.last) text->lines.last= text->lines.first;
+
+ top= (TextLine **) &text->lines.first;
+ bot= (TextLine **) &text->lines.last;
+
+ while ((*top)->prev) *top= (*top)->prev;
+ while ((*bot)->next) *bot= (*bot)->next;
+
+ if(!text->curl) {
+ if(text->sell) text->curl= text->sell;
+ else text->curl= text->lines.first;
+ text->curc= 0;
+ }
+
+ if(!text->sell) {
+ text->sell= text->curl;
+ text->selc= 0;
+ }
+}
+
+int txt_get_span (TextLine *from, TextLine *to)
+{
+ int ret=0;
+ TextLine *tmp= from;
+
+ if (!to || !from) return 0;
+ if (from==to) return 0;
+
+ /* Look forwards */
+ while (tmp) {
+ if (tmp == to) return ret;
+ ret++;
+ tmp= tmp->next;
+ }
+
+ /* Look backwards */
+ if (!tmp) {
+ tmp= from;
+ ret=0;
+ while(tmp) {
+ if (tmp == to) break;
+ ret--;
+ tmp= tmp->prev;
+ }
+ if(!tmp) ret=0;
+ }
+
+ return ret;
+}
+
+static void txt_make_dirty (Text *text)
+{
+ text->flags |= TXT_ISDIRTY;
+ if (text->compiled) BPY_free_compiled_text(text);
+}
+
+/****************************/
+/* Cursor utility functions */
+/****************************/
+
+static void txt_curs_cur (Text *text, TextLine ***linep, int **charp)
+{
+ *linep= &text->curl; *charp= &text->curc;
+}
+
+static void txt_curs_sel (Text *text, TextLine ***linep, int **charp)
+{
+ *linep= &text->sell; *charp= &text->selc;
+}
+
+static void txt_curs_first (Text *text, TextLine **linep, int *charp)
+{
+ if (text->curl==text->sell) {
+ *linep= text->curl;
+ if (text->curc<text->selc) *charp= text->curc;
+ else *charp= text->selc;
+ } else if (txt_get_span(text->lines.first, text->curl)<txt_get_span(text->lines.first, text->sell)) {
+ *linep= text->curl;
+ *charp= text->curc;
+ } else {
+ *linep= text->sell;
+ *charp= text->selc;
+ }
+}
+
+/****************************/
+/* Cursor movement functions */
+/****************************/
+
+void txt_move_up(Text *text, short sel)
+{
+ TextLine **linep;
+ int *charp, old;
+
+ if (!text) return;
+ if(sel) txt_curs_sel(text, &linep, &charp);
+ else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); }
+ if (!*linep) return;
+ old= *charp;
+
+ if((*linep)->prev) {
+ *linep= (*linep)->prev;
+ if (*charp > (*linep)->len) {
+ *charp= (*linep)->len;
+ if(!undoing) txt_undo_add_toop(text, sel?UNDO_STO:UNDO_CTO, txt_get_span(text->lines.first, (*linep)->next), old, txt_get_span(text->lines.first, *linep), (unsigned short) *charp);
+ } else {
+ if(!undoing) txt_undo_add_op(text, sel?UNDO_SUP:UNDO_CUP);
+ }
+ } else {
+ *charp= 0;
+ if(!undoing) txt_undo_add_op(text, sel?UNDO_SUP:UNDO_CUP);
+ }
+
+ if(!sel) txt_pop_sel(text);
+}
+
+void txt_move_down(Text *text, short sel)
+{
+ TextLine **linep;
+ int *charp, old;
+
+ if (!text) return;
+ if(sel) txt_curs_sel(text, &linep, &charp);
+ else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); }
+ if (!*linep) return;
+ old= *charp;
+
+ if((*linep)->next) {
+ *linep= (*linep)->next;
+ if (*charp > (*linep)->len) {
+ *charp= (*linep)->len;
+ if(!undoing) txt_undo_add_toop(text, sel?UNDO_STO:UNDO_CTO, txt_get_span(text->lines.first, (*linep)->prev), old, txt_get_span(text->lines.first, *linep), (unsigned short)*charp);
+ } else
+ if(!undoing) txt_undo_add_op(text, sel?UNDO_SDOWN:UNDO_CDOWN);
+ } else {
+ *charp= (*linep)->len;
+ if(!undoing) txt_undo_add_op(text, sel?UNDO_SDOWN:UNDO_CDOWN);
+ }
+
+ if(!sel) txt_pop_sel(text);
+}
+
+void txt_move_left(Text *text, short sel)
+{
+ TextLine **linep;
+ int *charp, oundoing= undoing;
+
+ if (!text) return;
+ if(sel) txt_curs_sel(text, &linep, &charp);
+ else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); }
+ if (!*linep) return;
+
+ undoing= 1;
+ if (*charp== 0) {
+ if ((*linep)->prev) {
+ txt_move_up(text, sel);
+ *charp= (*linep)->len;
+ }
+ } else {
+ (*charp)--;
+ }
+ undoing= oundoing;
+ if(!undoing) txt_undo_add_op(text, sel?UNDO_SLEFT:UNDO_CLEFT);
+
+ if(!sel) txt_pop_sel(text);
+}
+
+void txt_move_right(Text *text, short sel)
+{
+ TextLine **linep;
+ int *charp, oundoing= undoing;
+
+ if (!text) return;
+ if(sel) txt_curs_sel(text, &linep, &charp);
+ else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); }
+ if (!*linep) return;
+
+ undoing= 1;
+ if (*charp== (*linep)->len) {
+ if ((*linep)->next) {
+ txt_move_down(text, sel);
+ *charp= 0;
+ }
+ } else {
+ (*charp)++;
+ }
+ undoing= oundoing;
+ if(!undoing) txt_undo_add_op(text, sel?UNDO_SRIGHT:UNDO_CRIGHT);
+
+ if(!sel) txt_pop_sel(text);
+}
+
+void txt_move_bol (Text *text, short sel)
+{
+ TextLine **linep;
+ int *charp, old;
+
+ if (!text) return;
+ if(sel) txt_curs_sel(text, &linep, &charp);
+ else txt_curs_cur(text, &linep, &charp);
+ if (!*linep) return;
+ old= *charp;
+
+ *charp= 0;
+
+ if(!sel) txt_pop_sel(text);
+ if(!undoing) txt_undo_add_toop(text, sel?UNDO_STO:UNDO_CTO, txt_get_span(text->lines.first, *linep), old, txt_get_span(text->lines.first, *linep), (unsigned short)*charp);
+}
+
+void txt_move_eol (Text *text, short sel)
+{
+ TextLine **linep;
+ int *charp, old;
+
+ if (!text) return;
+ if(sel) txt_curs_sel(text, &linep, &charp);
+ else txt_curs_cur(text, &linep, &charp);
+ if (!*linep) return;
+ old= *charp;
+
+ *charp= (*linep)->len;
+
+ if(!sel) txt_pop_sel(text);
+ if(!undoing) txt_undo_add_toop(text, sel?UNDO_STO:UNDO_CTO, txt_get_span(text->lines.first, *linep), old, txt_get_span(text->lines.first, *linep), (unsigned short)*charp);
+}
+
+void txt_move_bof (Text *text, short sel)
+{
+ TextLine **linep;
+ int *charp, old;
+
+ if (!text) return;
+ if(sel) txt_curs_sel(text, &linep, &charp);
+ else txt_curs_cur(text, &linep, &charp);
+ if (!*linep) return;
+ old= *charp;
+
+ *linep= text->lines.first;
+ *charp= 0;
+
+ if(!sel) txt_pop_sel(text);
+ if(!undoing) txt_undo_add_toop(text, sel?UNDO_STO:UNDO_CTO, txt_get_span(text->lines.first, *linep), old, txt_get_span(text->lines.first, *linep), (unsigned short)*charp);
+}
+
+void txt_move_eof (Text *text, short sel)
+{
+ TextLine **linep;
+ int *charp, old;
+
+ if (!text) return;
+ if(sel) txt_curs_sel(text, &linep, &charp);
+ else txt_curs_cur(text, &linep, &charp);
+ if (!*linep) return;
+ old= *charp;
+
+ *linep= text->lines.last;
+ *charp= (*linep)->len;
+
+ if(!sel) txt_pop_sel(text);
+ if(!undoing) txt_undo_add_toop(text, sel?UNDO_STO:UNDO_CTO, txt_get_span(text->lines.first, *linep), old, txt_get_span(text->lines.first, *linep), (unsigned short)*charp);
+}
+
+void txt_move_toline (Text *text, unsigned int line, short sel)
+{
+ TextLine **linep, *oldl;
+ int *charp, oldc;
+ unsigned int i;
+
+ if (!text) return;
+ if(sel) txt_curs_sel(text, &linep, &charp);
+ else txt_curs_cur(text, &linep, &charp);
+ if (!*linep) return;
+ oldc= *charp;
+ oldl= *linep;
+
+ *linep= text->lines.first;
+ for (i=0; i<line; i++) {
+ if ((*linep)->next) *linep= (*linep)->next;
+ else break;
+ }
+ *charp= 0;
+
+ if(!sel) txt_pop_sel(text);
+ if(!undoing) txt_undo_add_toop(text, sel?UNDO_STO:UNDO_CTO, txt_get_span(text->lines.first, oldl), oldc, txt_get_span(text->lines.first, *linep), (unsigned short)*charp);
+}
+
+/****************************/
+/* Text selection functions */
+/****************************/
+
+static void txt_curs_swap (Text *text)
+{
+ TextLine *tmpl;
+ int tmpc;
+
+ tmpl= text->curl;
+ text->curl= text->sell;
+ text->sell= tmpl;
+
+ tmpc= text->curc;
+ text->curc= text->selc;
+ text->selc= tmpc;
+
+ if(!undoing) txt_undo_add_op(text, UNDO_SWAP);
+}
+
+static void txt_pop_first (Text *text)
+{
+
+ if (txt_get_span(text->curl, text->sell)<0 ||
+ (text->curl==text->sell && text->curc>text->selc)) {
+ txt_curs_swap(text);
+ }
+
+ if(!undoing) txt_undo_add_toop(text, UNDO_STO,
+ txt_get_span(text->lines.first, text->sell),
+ text->selc,
+ txt_get_span(text->lines.first, text->curl),
+ text->curc);
+
+ txt_pop_sel(text);
+}
+
+static void txt_pop_last (Text *text)
+{
+ if (txt_get_span(text->curl, text->sell)>0 ||
+ (text->curl==text->sell && text->curc<text->selc)) {
+ txt_curs_swap(text);
+ }
+
+ if(!undoing) txt_undo_add_toop(text, UNDO_STO,
+ txt_get_span(text->lines.first, text->sell),
+ text->selc,
+ txt_get_span(text->lines.first, text->curl),
+ text->curc);
+
+ txt_pop_sel(text);
+}
+
+/* never used: CVS 1.19 */
+/* static void txt_pop_selr (Text *text) */
+
+void txt_pop_sel (Text *text)
+{
+ text->sell= text->curl;
+ text->selc= text->curc;
+}
+
+void txt_order_cursors(Text *text)
+{
+ if (!text) return;
+ if (!text->curl) return;
+ if (!text->sell) return;
+
+ /* Flip so text->curl is before text->sell */
+ if (txt_get_span(text->curl, text->sell)<0 ||
+ (text->curl==text->sell && text->curc>text->selc))
+ txt_curs_swap(text);
+}
+
+int txt_has_sel(Text *text)
+{
+ return ((text->curl!=text->sell) || (text->curc!=text->selc));
+}
+
+static void txt_delete_sel (Text *text)
+{
+ TextLine *tmpl;
+ char *buf, *format;
+
+ if (!text) return;
+ if (!text->curl) return;
+ if (!text->sell) return;
+
+ if (!txt_has_sel(text)) return;
+
+ txt_order_cursors(text);
+
+ if(!undoing) {
+ buf= txt_sel_to_buf(text);
+ txt_undo_add_block(text, UNDO_DBLOCK, buf);
+ MEM_freeN(buf);
+ }
+
+ buf= MEM_mallocN(text->curc+(text->sell->len - text->selc)+1, "textline_string");
+ format= MEM_mallocN(text->curc+(text->sell->len - text->selc)+2, "Syntax_format");
+
+ strncpy(buf, text->curl->line, text->curc);
+ strcpy(buf+text->curc, text->sell->line + text->selc);
+ buf[text->curc+(text->sell->len - text->selc)]=0;
+
+ make_new_line(text->curl, buf, format);
+
+ tmpl= text->sell;
+ while (tmpl != text->curl) {
+ tmpl= tmpl->prev;
+ if (!tmpl) break;
+
+ txt_delete_line(text, tmpl->next);
+ }
+
+ text->sell= text->curl;
+ text->selc= text->curc;
+}
+
+void txt_sel_all (Text *text)
+{
+ if (!text) return;
+
+ text->curl= text->lines.first;
+ text->curc= 0;
+
+ text->sell= text->lines.last;
+ text->selc= text->sell->len;
+}
+
+void txt_sel_line (Text *text)
+{
+ if (!text) return;
+ if (!text->curl) return;
+
+ text->curc= 0;
+ text->sell= text->curl;
+ text->selc= text->sell->len;
+}
+
+/***************************/
+/* Cut and paste functions */
+/***************************/
+
+void txt_print_cutbuffer (void)
+{
+ printf ("Cut buffer\n--\n%s\n--\n", txt_cut_buffer);
+}
+
+char *txt_to_buf (Text *text)
+{
+ int length;
+ TextLine *tmp, *linef, *linel;
+ int charf, charl;
+ char *buf;
+
+ if (!text) return NULL;
+ if (!text->curl) return NULL;
+ if (!text->sell) return NULL;
+
+ linef= text->lines.first;
+ charf= 0;
+
+ linel= text->lines.last;
+ charl= linel->len;
+
+ if (linef == text->lines.last) {
+ length= charl-charf;
+
+ buf= MEM_mallocN(length+2, "text buffer");
+
+ BLI_strncpy(buf, linef->line + charf, length+1);
+ buf[length]=0;
+ } else {
+ length= linef->len - charf;
+ length+= charl;
+ length+= 2; /* For the 2 '\n' */
+
+ tmp= linef->next;
+ while (tmp && tmp!= linel) {
+ length+= tmp->len+1;
+ tmp= tmp->next;
+ }
+
+ buf= MEM_mallocN(length+1, "cut buffer");
+
+ strncpy(buf, linef->line + charf, linef->len-charf);
+ length= linef->len - charf;
+
+ buf[length++]='\n';
+
+ tmp= linef->next;
+ while (tmp && tmp!=linel) {
+ strncpy(buf+length, tmp->line, tmp->len);
+ length+= tmp->len;
+
+ buf[length++]='\n';
+
+ tmp= tmp->next;
+ }
+ strncpy(buf+length, linel->line, charl);
+ length+= charl;
+
+ /* python compiler wants an empty end line */
+ buf[length++]='\n';
+ buf[length]=0;
+ }
+
+ return buf;
+}
+
+int txt_find_string(Text *text, char *findstr)
+{
+ TextLine *tl, *startl;
+ char *s= NULL;
+
+ if (!text || !text->curl || !text->sell) return 0;
+
+ txt_order_cursors(text);
+
+ tl= startl= text->sell;
+
+ s= strstr(&tl->line[text->selc], findstr);
+ while (!s) {
+ tl= tl->next;
+ if (!tl)
+ tl= text->lines.first;
+
+ s= strstr(tl->line, findstr);
+ if (tl==startl)
+ break;
+ }
+
+ if (s) {
+ text->curl= text->sell= tl;
+ text->curc= (int) (s-tl->line);
+ text->selc= text->curc + strlen(findstr);
+
+ return 1;
+ } else
+ return 0;
+}
+
+void txt_cut_sel (Text *text)
+{
+ txt_copy_sel(text);
+
+ txt_delete_sel(text);
+ txt_make_dirty(text);
+}
+
+char *txt_sel_to_buf (Text *text)
+{
+ char *buf;
+ int length=0;
+ TextLine *tmp, *linef, *linel;
+ int charf, charl;
+
+ if (!text) return NULL;
+ if (!text->curl) return NULL;
+ if (!text->sell) return NULL;
+
+ if (text->curl==text->sell) {
+ linef= linel= text->curl;
+
+ if (text->curc < text->selc) {
+ charf= text->curc;
+ charl= text->selc;
+ } else{
+ charf= text->selc;
+ charl= text->curc;
+ }
+ } else if (txt_get_span(text->curl, text->sell)<0) {
+ linef= text->sell;
+ linel= text->curl;
+
+ charf= text->selc;
+ charl= text->curc;
+ } else {
+ linef= text->curl;
+ linel= text->sell;
+
+ charf= text->curc;
+ charl= text->selc;
+ }
+
+ if (linef == linel) {
+ length= charl-charf;
+
+ buf= MEM_mallocN(length+1, "sel buffer");
+
+ BLI_strncpy(buf, linef->line + charf, length+1);
+ } else {
+ length+= linef->len - charf;
+ length+= charl;
+ length++; /* For the '\n' */
+
+ tmp= linef->next;
+ while (tmp && tmp!= linel) {
+ length+= tmp->len+1;
+ tmp= tmp->next;
+ }
+
+ buf= MEM_mallocN(length+1, "sel buffer");
+
+ strncpy(buf, linef->line+ charf, linef->len-charf);
+ length= linef->len-charf;
+
+ buf[length++]='\n';
+
+ tmp= linef->next;
+ while (tmp && tmp!=linel) {
+ strncpy(buf+length, tmp->line, tmp->len);
+ length+= tmp->len;
+
+ buf[length++]='\n';
+
+ tmp= tmp->next;
+ }
+ strncpy(buf+length, linel->line, charl);
+ length+= charl;
+
+ buf[length]=0;
+ }
+
+ return buf;
+}
+
+void txt_copy_sel (Text *text)
+{
+ int length=0;
+ TextLine *tmp, *linef, *linel;
+ int charf, charl;
+
+ if (!text) return;
+ if (!text->curl) return;
+ if (!text->sell) return;
+
+ if (!txt_has_sel(text)) return;
+
+ if (txt_cut_buffer) MEM_freeN(txt_cut_buffer);
+ txt_cut_buffer= NULL;
+
+ if (text->curl==text->sell) {
+ linef= linel= text->curl;
+
+ if (text->curc < text->selc) {
+ charf= text->curc;
+ charl= text->selc;
+ } else{
+ charf= text->selc;
+ charl= text->curc;
+ }
+ } else if (txt_get_span(text->curl, text->sell)<0) {
+ linef= text->sell;
+ linel= text->curl;
+
+ charf= text->selc;
+ charl= text->curc;
+ } else {
+ linef= text->curl;
+ linel= text->sell;
+
+ charf= text->curc;
+ charl= text->selc;
+ }
+
+ if (linef == linel) {
+ length= charl-charf;
+
+ txt_cut_buffer= MEM_mallocN(length+1, "cut buffera");
+
+ BLI_strncpy(txt_cut_buffer, linef->line + charf, length+1);
+ } else {
+ length+= linef->len - charf;
+ length+= charl;
+ length++; /* For the '\n' */
+
+ tmp= linef->next;
+ while (tmp && tmp!= linel) {
+ length+= tmp->len+1;
+ tmp= tmp->next;
+ }
+
+ txt_cut_buffer= MEM_mallocN(length+1, "cut bufferb");
+
+ strncpy(txt_cut_buffer, linef->line+ charf, linef->len-charf);
+ length= linef->len-charf;
+
+ txt_cut_buffer[length++]='\n';
+
+ tmp= linef->next;
+ while (tmp && tmp!=linel) {
+ strncpy(txt_cut_buffer+length, tmp->line, tmp->len);
+ length+= tmp->len;
+
+ txt_cut_buffer[length++]='\n';
+
+ tmp= tmp->next;
+ }
+ strncpy(txt_cut_buffer+length, linel->line, charl);
+ length+= charl;
+
+ txt_cut_buffer[length]=0;
+ }
+}
+
+void txt_insert_buf(Text *text, char *in_buffer)
+{
+ int i=0, l=0, j, u, len;
+ TextLine *add;
+
+ if (!text) return;
+ if (!in_buffer) return;
+
+ txt_delete_sel(text);
+
+ if(!undoing) txt_undo_add_block (text, UNDO_IBLOCK, in_buffer);
+
+ u= undoing;
+ undoing= 1;
+
+ /* Read the first line (or as close as possible */
+ while (in_buffer[i] && in_buffer[i]!='\n') {
+ txt_add_char(text, in_buffer[i]);
+ i++;
+ }
+
+ if (in_buffer[i]=='\n') txt_split_curline(text);
+ else { undoing = u; return; }
+ i++;
+
+ /* Read as many full lines as we can */
+ len= strlen(in_buffer);
+
+ while (i<len) {
+ l=0;
+
+ while (in_buffer[i] && in_buffer[i]!='\n') {
+ i++; l++;
+ }
+
+ if(in_buffer[i]=='\n') {
+ add= txt_new_linen(in_buffer +(i-l), l);
+ BLI_insertlinkbefore(&text->lines, text->curl, add);
+ i++;
+ } else {
+ for (j= i-l; j<i && j<(int)strlen(in_buffer); j++) {
+ txt_add_char(text, in_buffer[j]);
+ }
+ break;
+ }
+ }
+
+ undoing= u;
+}
+
+void txt_free_cut_buffer(void)
+{
+ if (txt_cut_buffer) MEM_freeN(txt_cut_buffer);
+}
+
+void txt_paste(Text *text)
+{
+ txt_insert_buf(text, txt_cut_buffer);
+}
+
+/******************/
+/* Undo functions */
+/******************/
+
+#define MAX_UNDO_TEST(x) \
+ while (text->undo_pos+x >= text->undo_len) { \
+ if(text->undo_len*2 > TXT_MAX_UNDO) { \
+ error("Undo limit reached, buffer cleared\n"); \
+ MEM_freeN(text->undo_buf); \
+ text->undo_len= TXT_INIT_UNDO; \
+ text->undo_buf= MEM_mallocN(text->undo_len, "undo buf"); \
+ text->undo_pos=-1; \
+ return; \
+ } else { \
+ void *tmp= text->undo_buf; \
+ text->undo_buf= MEM_callocN(text->undo_len*2, "undo buf"); \
+ memcpy(text->undo_buf, tmp, text->undo_len); \
+ text->undo_len*=2; \
+ MEM_freeN(tmp); \
+ } \
+ }
+
+static void dump_buffer(Text *text)
+{
+ int i= 0;
+
+ while (i++<text->undo_pos) printf("%d: %d %c\n", i, text->undo_buf[i], text->undo_buf[i]);
+}
+
+void txt_print_undo(Text *text)
+{
+ int i= 0;
+ int op;
+ char *ops;
+ int linep, charp;
+
+ dump_buffer(text);
+
+ printf ("---< Undo Buffer >---\n");
+
+ printf ("UndoPosition is %d\n", text->undo_pos);
+
+ while (i<=text->undo_pos) {
+ op= text->undo_buf[i];
+
+ if (op==UNDO_CLEFT) {
+ ops= "Cursor left";
+ } else if (op==UNDO_CRIGHT) {
+ ops= "Cursor right";
+ } else if (op==UNDO_CUP) {
+ ops= "Cursor up";
+ } else if (op==UNDO_CDOWN) {
+ ops= "Cursor down";
+ } else if (op==UNDO_SLEFT) {
+ ops= "Selection left";
+ } else if (op==UNDO_SRIGHT) {
+ ops= "Selection right";
+ } else if (op==UNDO_SUP) {
+ ops= "Selection up";
+ } else if (op==UNDO_SDOWN) {
+ ops= "Selection down";
+ } else if (op==UNDO_STO) {
+ ops= "Selection ";
+ } else if (op==UNDO_CTO) {
+ ops= "Cursor ";
+ } else if (op==UNDO_INSERT) {
+ ops= "Insert";
+ } else if (op==UNDO_BS) {
+ ops= "Backspace";
+ } else if (op==UNDO_DEL) {
+ ops= "Delete";
+ } else if (op==UNDO_SWAP) {
+ ops= "Cursor swap";
+ } else if (op==UNDO_DBLOCK) {
+ ops= "Delete text block";
+ } else if (op==UNDO_IBLOCK) {
+ ops= "Insert text block";
+ } else if (op==UNDO_INDENT) {
+ ops= "Indent ";
+ } else if (op==UNDO_UNINDENT) {
+ ops= "Unindent ";
+ } else if (op==UNDO_COMMENT) {
+ ops= "Comment ";
+ } else if (op==UNDO_UNCOMMENT) {
+ ops= "Uncomment ";
+ } else {
+ ops= "Unknown";
+ }
+
+ printf ("Op (%o) at %d = %s", op, i, ops);
+ if (op==UNDO_INSERT || op==UNDO_BS || op==UNDO_DEL) {
+ i++;
+ printf (" - Char is %c", text->undo_buf[i]);
+ i++;
+ } else if (op==UNDO_STO || op==UNDO_CTO) {
+ i++;
+
+ charp= text->undo_buf[i]; i++;
+ charp= charp+(text->undo_buf[i]<<8); i++;
+
+ linep= text->undo_buf[i]; i++;
+ linep= linep+(text->undo_buf[i]<<8); i++;
+ linep= linep+(text->undo_buf[i]<<16); i++;
+ linep= linep+(text->undo_buf[i]<<24); i++;
+
+ printf ("to <%d, %d> ", linep, charp);
+
+ charp= text->undo_buf[i]; i++;
+ charp= charp+(text->undo_buf[i]<<8); i++;
+
+ linep= text->undo_buf[i]; i++;
+ linep= linep+(text->undo_buf[i]<<8); i++;
+ linep= linep+(text->undo_buf[i]<<16); i++;
+ linep= linep+(text->undo_buf[i]<<24); i++;
+
+ printf ("from <%d, %d>", linep, charp);
+ } else if (op==UNDO_DBLOCK || op==UNDO_IBLOCK) {
+ i++;
+
+ linep= text->undo_buf[i]; i++;
+ linep= linep+(text->undo_buf[i]<<8); i++;
+ linep= linep+(text->undo_buf[i]<<16); i++;
+ linep= linep+(text->undo_buf[i]<<24); i++;
+
+ printf (" (length %d) <", linep);
+
+ while (linep>0) {
+ putchar(text->undo_buf[i]);
+ linep--; i++;
+ }
+
+ linep= text->undo_buf[i]; i++;
+ linep= linep+(text->undo_buf[i]<<8); i++;
+ linep= linep+(text->undo_buf[i]<<16); i++;
+ linep= linep+(text->undo_buf[i]<<24); i++;
+ printf ("> (%d)", linep);
+ } else if (op==UNDO_INDENT || op==UNDO_UNINDENT) {
+ i++;
+
+ charp= text->undo_buf[i]; i++;
+ charp= charp+(text->undo_buf[i]<<8); i++;
+
+ linep= text->undo_buf[i]; i++;
+ linep= linep+(text->undo_buf[i]<<8); i++;
+ linep= linep+(text->undo_buf[i]<<16); i++;
+ linep= linep+(text->undo_buf[i]<<24); i++;
+
+ printf ("to <%d, %d> ", linep, charp);
+
+ charp= text->undo_buf[i]; i++;
+ charp= charp+(text->undo_buf[i]<<8); i++;
+
+ linep= text->undo_buf[i]; i++;
+ linep= linep+(text->undo_buf[i]<<8); i++;
+ linep= linep+(text->undo_buf[i]<<16); i++;
+ linep= linep+(text->undo_buf[i]<<24); i++;
+
+ printf ("from <%d, %d>", linep, charp);
+ }
+
+ printf (" %d\n", i);
+ i++;
+ }
+}
+
+static void txt_undo_add_op(Text *text, int op)
+{
+ MAX_UNDO_TEST(2);
+
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= op;
+ text->undo_buf[text->undo_pos+1]= 0;
+}
+
+static void txt_undo_add_block(Text *text, int op, char *buf)
+{
+ int length;
+
+ length= strlen(buf);
+
+ MAX_UNDO_TEST(length+11);
+
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= op;
+
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= (length)&0xff;
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= (length>>8)&0xff;
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= (length>>16)&0xff;
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= (length>>24)&0xff;
+
+ text->undo_pos++;
+ strncpy(text->undo_buf+text->undo_pos, buf, length);
+ text->undo_pos+=length;
+
+ text->undo_buf[text->undo_pos]= (length)&0xff;
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= (length>>8)&0xff;
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= (length>>16)&0xff;
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= (length>>24)&0xff;
+
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= op;
+
+ text->undo_buf[text->undo_pos+1]= 0;
+}
+
+void txt_undo_add_toop(Text *text, int op, unsigned int froml, unsigned short fromc, unsigned int tol, unsigned short toc)
+{
+ MAX_UNDO_TEST(15);
+
+ if (froml==tol && fromc==toc) return;
+
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= op;
+
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= (fromc)&0xff;
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= (fromc>>8)&0xff;
+
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= (froml)&0xff;
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= (froml>>8)&0xff;
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= (froml>>16)&0xff;
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= (froml>>24)&0xff;
+
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= (toc)&0xff;
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= (toc>>8)&0xff;
+
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= (tol)&0xff;
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= (tol>>8)&0xff;
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= (tol>>16)&0xff;
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= (tol>>24)&0xff;
+
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= op;
+
+ text->undo_buf[text->undo_pos+1]= 0;
+}
+
+static void txt_undo_add_charop(Text *text, int op, char c)
+{
+ MAX_UNDO_TEST(4);
+
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= op;
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= c;
+ text->undo_pos++;
+ text->undo_buf[text->undo_pos]= op;
+ text->undo_buf[text->undo_pos+1]= 0;
+}
+
+void txt_do_undo(Text *text)
+{
+ int op= text->undo_buf[text->undo_pos];
+ unsigned int linep, i;
+ unsigned short charp;
+ TextLine *holdl;
+ int holdc, holdln;
+ char *buf;
+
+ if (text->undo_pos<0) {
+ return;
+ }
+
+ text->undo_pos--;
+
+ undoing= 1;
+
+ switch(op) {
+ case UNDO_CLEFT:
+ txt_move_right(text, 0);
+ break;
+
+ case UNDO_CRIGHT:
+ txt_move_left(text, 0);
+ break;
+
+ case UNDO_CUP:
+ txt_move_down(text, 0);
+ break;
+
+ case UNDO_CDOWN:
+ txt_move_up(text, 0);
+ break;
+
+ case UNDO_SLEFT:
+ txt_move_right(text, 1);
+ break;
+
+ case UNDO_SRIGHT:
+ txt_move_left(text, 1);
+ break;
+
+ case UNDO_SUP:
+ txt_move_down(text, 1);
+ break;
+
+ case UNDO_SDOWN:
+ txt_move_up(text, 1);
+ break;
+
+ case UNDO_CTO:
+ case UNDO_STO:
+ text->undo_pos--;
+ text->undo_pos--;
+ text->undo_pos--;
+ text->undo_pos--;
+
+ text->undo_pos--;
+ text->undo_pos--;
+
+ linep= text->undo_buf[text->undo_pos]; text->undo_pos--;
+ linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
+ linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
+ linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
+
+ charp= text->undo_buf[text->undo_pos]; text->undo_pos--;
+ charp= (charp<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
+
+ if (op==UNDO_CTO) {
+ txt_move_toline(text, linep, 0);
+ text->curc= charp;
+ txt_pop_sel(text);
+ } else {
+ txt_move_toline(text, linep, 1);
+ text->selc= charp;
+ }
+
+ text->undo_pos--;
+ break;
+
+ case UNDO_INSERT:
+ txt_backspace_char(text);
+ text->undo_pos--;
+ text->undo_pos--;
+ break;
+
+ case UNDO_BS:
+ txt_add_char(text, text->undo_buf[text->undo_pos]);
+ text->undo_pos--;
+ text->undo_pos--;
+ break;
+
+ case UNDO_DEL:
+ txt_add_char(text, text->undo_buf[text->undo_pos]);
+ txt_move_left(text, 0);
+ text->undo_pos--;
+ text->undo_pos--;
+ break;
+
+ case UNDO_SWAP:
+ txt_curs_swap(text);
+ txt_do_undo(text); /* swaps should appear transparent */
+ break;
+
+ case UNDO_DBLOCK:
+ linep= text->undo_buf[text->undo_pos]; text->undo_pos--;
+ linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
+ linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
+ linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
+
+ buf= MEM_mallocN(linep+1, "dblock buffer");
+ for (i=0; i < linep; i++){
+ buf[(linep-1)-i]= text->undo_buf[text->undo_pos];
+ text->undo_pos--;
+ }
+ buf[i]= 0;
+
+ txt_curs_first(text, &holdl, &holdc);
+ holdln= txt_get_span(text->lines.first, holdl);
+
+ txt_insert_buf(text, buf);
+ MEM_freeN(buf);
+
+ text->curl= text->lines.first;
+ while (holdln>0) {
+ if(text->curl->next)
+ text->curl= text->curl->next;
+
+ holdln--;
+ }
+ text->curc= holdc;
+
+ linep= text->undo_buf[text->undo_pos]; text->undo_pos--;
+ linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
+ linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
+ linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
+
+ text->undo_pos--;
+
+ break;
+
+ case UNDO_IBLOCK:
+ linep= text->undo_buf[text->undo_pos]; text->undo_pos--;
+ linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
+ linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
+ linep= (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
+
+ txt_delete_sel(text);
+ while (linep>0) {
+ txt_backspace_char(text);
+ text->undo_pos--;
+ linep--;
+ }
+
+ text->undo_pos--;
+ text->undo_pos--;
+ text->undo_pos--;
+ text->undo_pos--;
+
+ text->undo_pos--;
+
+ break;
+ case UNDO_INDENT:
+ case UNDO_UNINDENT:
+ case UNDO_COMMENT:
+ case UNDO_UNCOMMENT:
+ linep= text->undo_buf[text->undo_pos]; text->undo_pos--;
+ linep = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
+ linep = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
+ linep = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
+ //linep is now the end line of the selection
+
+ charp = text->undo_buf[text->undo_pos]; text->undo_pos--;
+ charp = (charp<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
+ //charp is the last char selected or text->line->len
+ //set the selcetion for this now
+ text->selc = charp;
+ text->sell = text->lines.first;
+ for (i= 0; i < linep; i++) {
+ text->sell = text->sell->next;
+ }
+
+ linep= text->undo_buf[text->undo_pos]; text->undo_pos--;
+ linep = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
+ linep = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
+ linep = (linep<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
+ //first line to be selected
+
+ charp = text->undo_buf[text->undo_pos]; text->undo_pos--;
+ charp = (charp<<8)+text->undo_buf[text->undo_pos]; text->undo_pos--;
+ //first postion to be selected
+ text->curc = charp;
+ text->curl = text->lines.first;
+ for (i = 0; i < linep; i++) {
+ text->curl = text->curl->next;
+ }
+
+
+ if (op==UNDO_INDENT) {
+ unindent(text);
+ } else if (op== UNDO_UNINDENT) {
+ indent(text);
+ } else if (op == UNDO_COMMENT) {
+ uncomment(text);
+ } else if (op == UNDO_UNCOMMENT) {
+ comment(text);
+ }
+
+ text->undo_pos--;
+ break;
+ default:
+ error("Undo buffer error - resetting");
+ text->undo_pos= -1;
+
+ break;
+ }
+
+ undoing= 0;
+}
+
+void txt_do_redo(Text *text)
+{
+ char op;
+ unsigned int linep, i;
+ unsigned short charp;
+ char *buf;
+
+ text->undo_pos++;
+ op= text->undo_buf[text->undo_pos];
+
+ if (!op) {
+ text->undo_pos--;
+ return;
+ }
+
+ undoing= 1;
+
+ switch(op) {
+ case UNDO_CLEFT:
+ txt_move_left(text, 0);
+ break;
+
+ case UNDO_CRIGHT:
+ txt_move_right(text, 0);
+ break;
+
+ case UNDO_CUP:
+ txt_move_up(text, 0);
+ break;
+
+ case UNDO_CDOWN:
+ txt_move_down(text, 0);
+ break;
+
+ case UNDO_SLEFT:
+ txt_move_left(text, 1);
+ break;
+
+ case UNDO_SRIGHT:
+ txt_move_right(text, 1);
+ break;
+
+ case UNDO_SUP:
+ txt_move_up(text, 1);
+ break;
+
+ case UNDO_SDOWN:
+ txt_move_down(text, 1);
+ break;
+
+ case UNDO_INSERT:
+ text->undo_pos++;
+ txt_add_char(text, text->undo_buf[text->undo_pos]);
+ text->undo_pos++;
+ break;
+
+ case UNDO_BS:
+ text->undo_pos++;
+ txt_backspace_char(text);
+ text->undo_pos++;
+ break;
+
+ case UNDO_DEL:
+ text->undo_pos++;
+ txt_delete_char(text);
+ text->undo_pos++;
+ break;
+
+ case UNDO_SWAP:
+ txt_curs_swap(text);
+ txt_do_undo(text); /* swaps should appear transparent a*/
+ break;
+
+ case UNDO_CTO:
+ case UNDO_STO:
+ text->undo_pos++;
+ text->undo_pos++;
+
+ text->undo_pos++;
+ text->undo_pos++;
+ text->undo_pos++;
+ text->undo_pos++;
+
+ text->undo_pos++;
+
+ charp= text->undo_buf[text->undo_pos];
+ text->undo_pos++;
+ charp= charp+(text->undo_buf[text->undo_pos]<<8);
+
+ text->undo_pos++;
+ linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
+ linep= linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
+ linep= linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
+ linep= linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
+
+ if (op==UNDO_CTO) {
+ txt_move_toline(text, linep, 0);
+ text->curc= charp;
+ txt_pop_sel(text);
+ } else {
+ txt_move_toline(text, linep, 1);
+ text->selc= charp;
+ }
+
+ break;
+
+ case UNDO_DBLOCK:
+ text->undo_pos++;
+ linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
+ linep= linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
+ linep= linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
+ linep= linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
+
+ txt_delete_sel(text);
+ text->undo_pos+=linep;
+
+ text->undo_pos++;
+ text->undo_pos++;
+ text->undo_pos++;
+ text->undo_pos++;
+
+ break;
+
+ case UNDO_IBLOCK:
+ text->undo_pos++;
+ linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
+ linep= linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
+ linep= linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
+ linep= linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
+
+ buf= MEM_mallocN(linep+1, "iblock buffer");
+ memcpy (buf, &text->undo_buf[text->undo_pos], linep);
+ text->undo_pos+= linep;
+ buf[linep]= 0;
+
+ txt_insert_buf(text, buf);
+ MEM_freeN(buf);
+
+ linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
+ linep= linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
+ linep= linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
+ linep= linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
+
+ break;
+ case UNDO_INDENT:
+ case UNDO_UNINDENT:
+ case UNDO_COMMENT:
+ case UNDO_UNCOMMENT:
+ text->undo_pos++;
+ charp = text->undo_buf[text->undo_pos]; text->undo_pos++;
+ charp = charp+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
+ //charp is the first char selected or 0
+
+ linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
+ linep = linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
+ linep = linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
+ linep = linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
+ //linep is now the first line of the selection
+ //set the selcetion for this now
+ text->curc = charp;
+ text->curl = text->lines.first;
+ for (i= 0; i < linep; i++) {
+ text->curl = text->curl->next;
+ }
+
+ charp = text->undo_buf[text->undo_pos]; text->undo_pos++;
+ charp = charp+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
+ //last postion to be selected
+ linep= text->undo_buf[text->undo_pos]; text->undo_pos++;
+ linep = linep+(text->undo_buf[text->undo_pos]<<8); text->undo_pos++;
+ linep = linep+(text->undo_buf[text->undo_pos]<<16); text->undo_pos++;
+ linep = linep+(text->undo_buf[text->undo_pos]<<24); text->undo_pos++;
+ //Last line to be selected
+
+ text->selc = charp;
+ text->sell = text->lines.first;
+ for (i = 0; i < linep; i++) {
+ text->sell = text->sell->next;
+ }
+
+ if (op==UNDO_INDENT) {
+ indent(text);
+ } else if (op== UNDO_UNINDENT) {
+ unindent(text);
+ } else if (op == UNDO_COMMENT) {
+ comment(text);
+ } else if (op == UNDO_UNCOMMENT) {
+ uncomment(text);
+ }
+ break;
+ default:
+ error("Undo buffer error - resetting");
+ text->undo_pos= -1;
+
+ break;
+ }
+
+ undoing= 0;
+}
+
+/**************************/
+/* Line editing functions */
+/**************************/
+
+void txt_split_curline (Text *text)
+{
+ TextLine *ins;
+ char *left, *right, *fleft, *fright;
+
+ if (!text) return;
+ if (!text->curl) return;
+
+ txt_delete_sel(text);
+
+ /* Make the two half strings */
+
+ left= MEM_mallocN(text->curc+1, "textline_string");
+ fleft= MEM_mallocN(text->curc+2, "Syntax_format");
+ if (text->curc) memcpy(left, text->curl->line, text->curc);
+ left[text->curc]=0;
+
+ right= MEM_mallocN(text->curl->len - text->curc+1, "textline_string");
+ fright= MEM_mallocN(text->curl->len - text->curc+2, "Syntax_format");
+ if (text->curl->len - text->curc) memcpy(right, text->curl->line+text->curc, text->curl->len-text->curc);
+ right[text->curl->len - text->curc]=0;
+
+ MEM_freeN(text->curl->line);
+ if (text->curl->format) MEM_freeN(text->curl->format);
+
+ /* Make the new TextLine */
+
+ ins= MEM_mallocN(sizeof(TextLine), "textline");
+ ins->line= left;
+ ins->format= fleft;
+ ins->len= text->curc;
+
+ text->curl->line= right;
+ text->curl->format= fright;
+ text->curl->len= text->curl->len - text->curc;
+
+ BLI_insertlinkbefore(&text->lines, text->curl, ins);
+
+ text->curc=0;
+
+ txt_make_dirty(text);
+ txt_clean_text(text);
+
+ txt_pop_sel(text);
+ if(!undoing) txt_undo_add_charop(text, UNDO_INSERT, '\n');
+}
+
+static void txt_delete_line (Text *text, TextLine *line)
+{
+ if (!text) return;
+ if (!text->curl) return;
+
+ BLI_remlink (&text->lines, line);
+
+ if (line->line) MEM_freeN(line->line);
+ if (line->format) MEM_freeN(line->format);
+
+ MEM_freeN(line);
+
+ txt_make_dirty(text);
+ txt_clean_text(text);
+}
+
+static void txt_combine_lines (Text *text, TextLine *linea, TextLine *lineb)
+{
+ char *tmp, *format;
+
+ if (!text) return;
+
+ if(!linea || !lineb) return;
+
+ tmp= MEM_mallocN(linea->len+lineb->len+1, "textline_string");
+ format= MEM_mallocN(linea->len+lineb->len+1, "Syntax_format");
+
+ strcpy(tmp, linea->line);
+ strcat(tmp, lineb->line);
+
+ make_new_line(linea, tmp, format);
+
+ txt_delete_line(text, lineb);
+
+ txt_make_dirty(text);
+ txt_clean_text(text);
+}
+
+void txt_delete_char (Text *text)
+{
+ char c='\n';
+
+ if (!text) return;
+ if (!text->curl) return;
+
+ if (txt_has_sel(text)) { /* deleting a selection */
+ txt_delete_sel(text);
+ }
+ else if (text->curc== text->curl->len) { /* Appending two lines */
+ if (text->curl->next) {
+ txt_combine_lines(text, text->curl, text->curl->next);
+ txt_pop_sel(text);
+ }
+ } else { /* Just deleting a char */
+ int i= text->curc;
+
+ c= text->curl->line[i];
+ while(i< text->curl->len) {
+ text->curl->line[i]= text->curl->line[i+1];
+ i++;
+ }
+ text->curl->len--;
+
+ txt_pop_sel(text);
+ }
+
+ txt_make_dirty(text);
+ txt_clean_text(text);
+
+ if(!undoing) txt_undo_add_charop(text, UNDO_DEL, c);
+}
+
+void txt_backspace_char (Text *text)
+{
+ char c='\n';
+
+ if (!text) return;
+ if (!text->curl) return;
+
+ if (txt_has_sel(text)) { /* deleting a selection */
+ txt_delete_sel(text);
+ }
+ else if (text->curc==0) { /* Appending two lines */
+ if (text->curl->prev) {
+ text->curl= text->curl->prev;
+ text->curc= text->curl->len;
+
+ txt_combine_lines(text, text->curl, text->curl->next);
+ txt_pop_sel(text);
+ }
+ }
+ else { /* Just backspacing a char */
+ int i= text->curc-1;
+
+ c= text->curl->line[i];
+ while(i< text->curl->len) {
+ text->curl->line[i]= text->curl->line[i+1];
+ i++;
+ }
+ text->curl->len--;
+ text->curc--;
+
+ txt_pop_sel(text);
+ }
+
+ txt_make_dirty(text);
+ txt_clean_text(text);
+
+ if(!undoing) txt_undo_add_charop(text, UNDO_BS, c);
+}
+
+int txt_add_char (Text *text, char add)
+{
+ int len;
+ char *tmp, *format;
+
+ if (!text) return 0;
+ if (!text->curl) return 0;
+
+ if (add=='\n') {
+ txt_split_curline(text);
+ return 1;
+ }
+
+ txt_delete_sel(text);
+
+ tmp= MEM_mallocN(text->curl->len+2, "textline_string");
+ format= MEM_mallocN(text->curl->len+4, "Syntax_format");
+
+ if(text->curc) memcpy(tmp, text->curl->line, text->curc);
+ tmp[text->curc]= add;
+
+ len= text->curl->len - text->curc;
+ if(len>0) memcpy(tmp+text->curc+1, text->curl->line+text->curc, len);
+ tmp[text->curl->len+1]=0;
+ make_new_line(text->curl, tmp, format);
+
+ text->curc++;
+
+ txt_pop_sel(text);
+
+ txt_make_dirty(text);
+ txt_clean_text(text);
+
+ if(!undoing) txt_undo_add_charop(text, UNDO_INSERT, add);
+ return 1;
+}
+
+void indent(Text *text)
+{
+ int len, num;
+ char *tmp, *format;
+ char add = '\t';
+
+ if (!text) return;
+ if (!text->curl) return;
+ if (!text->sell) return;
+
+ num = 0;
+ while (TRUE)
+ {
+ tmp= MEM_mallocN(text->curl->len+2, "textline_string");
+ format= MEM_mallocN(text->curl->len+3, "Syntax_format");
+
+ text->curc = 0;
+ if(text->curc) memcpy(tmp, text->curl->line, text->curc);
+ tmp[text->curc]= add;
+
+ len= text->curl->len - text->curc;
+ if(len>0) memcpy(tmp+text->curc+1, text->curl->line+text->curc, len);
+ tmp[text->curl->len+1]=0;
+
+ make_new_line(text->curl, tmp, format);
+
+ text->curc++;
+
+ txt_make_dirty(text);
+ txt_clean_text(text);
+
+ if(text->curl == text->sell)
+ {
+ text->selc = text->sell->len;
+ break;
+ } else {
+ text->curl = text->curl->next;
+ num++;
+ }
+ }
+ text->curc = 0;
+ while( num > 0 )
+ {
+ text->curl = text->curl->prev;
+ num--;
+ }
+
+ if(!undoing)
+ {
+ txt_undo_add_toop(text, UNDO_INDENT, txt_get_span(text->lines.first, text->curl), text->curc, txt_get_span(text->lines.first, text->sell), text->selc);
+ }
+}
+
+void unindent(Text *text)
+{
+ int num = 0;
+ char remove = '\t';
+
+ if (!text) return;
+ if (!text->curl) return;
+ if (!text->sell) return;
+
+ while(TRUE)
+ {
+ int i = 0;
+
+ if (text->curl->line[i] == remove)
+ {
+ while(i< text->curl->len) {
+ text->curl->line[i]= text->curl->line[i+1];
+ i++;
+ }
+ text->curl->len--;
+ }
+
+
+ txt_make_dirty(text);
+ txt_clean_text(text);
+
+ if(text->curl == text->sell)
+ {
+ text->selc = text->sell->len;
+ break;
+ } else {
+ text->curl = text->curl->next;
+ num++;
+ }
+
+ }
+ text->curc = 0;
+ while( num > 0 )
+ {
+ text->curl = text->curl->prev;
+ num--;
+ }
+
+ if(!undoing)
+ {
+ txt_undo_add_toop(text, UNDO_UNINDENT, txt_get_span(text->lines.first, text->curl), text->curc, txt_get_span(text->lines.first, text->sell), text->selc);
+ }
+}
+
+void comment(Text *text)
+{
+ int len, num;
+ char *tmp, *format;
+ char add = '#';
+
+ if (!text) return;
+ if (!text->curl) return;
+ if (!text->sell) return;// Need to change this need to check if only one line is selected ot more then one
+
+ num = 0;
+ while (TRUE)
+ {
+ tmp= MEM_mallocN(text->curl->len+2, "textline_string");
+ format = MEM_mallocN(text->curl->len+3, "Syntax_format");
+
+ text->curc = 0;
+ if(text->curc) memcpy(tmp, text->curl->line, text->curc);
+ tmp[text->curc]= add;
+
+ len= text->curl->len - text->curc;
+ if(len>0) memcpy(tmp+text->curc+1, text->curl->line+text->curc, len);
+ tmp[text->curl->len+1]=0;
+
+ make_new_line(text->curl, tmp, format);
+
+ text->curc++;
+
+ txt_make_dirty(text);
+ txt_clean_text(text);
+
+ if(text->curl == text->sell)
+ {
+ text->selc = text->sell->len;
+ break;
+ } else {
+ text->curl = text->curl->next;
+ num++;
+ }
+ }
+ text->curc = 0;
+ while( num > 0 )
+ {
+ text->curl = text->curl->prev;
+ num--;
+ }
+
+ if(!undoing)
+ {
+ txt_undo_add_toop(text, UNDO_COMMENT, txt_get_span(text->lines.first, text->curl), text->curc, txt_get_span(text->lines.first, text->sell), text->selc);
+ }
+}
+
+void uncomment(Text *text)
+{
+ int num = 0;
+ char remove = '#';
+
+ if (!text) return;
+ if (!text->curl) return;
+ if (!text->sell) return;
+
+ while(TRUE)
+ {
+ int i = 0;
+
+ if (text->curl->line[i] == remove)
+ {
+ while(i< text->curl->len) {
+ text->curl->line[i]= text->curl->line[i+1];
+ i++;
+ }
+ text->curl->len--;
+ }
+
+
+ txt_make_dirty(text);
+ txt_clean_text(text);
+
+ if(text->curl == text->sell)
+ {
+ text->selc = text->sell->len;
+ break;
+ } else {
+ text->curl = text->curl->next;
+ num++;
+ }
+
+ }
+ text->curc = 0;
+ while( num > 0 )
+ {
+ text->curl = text->curl->prev;
+ num--;
+ }
+
+ if(!undoing)
+ {
+ txt_undo_add_toop(text, UNDO_UNCOMMENT, txt_get_span(text->lines.first, text->curl), text->curc, txt_get_span(text->lines.first, text->sell), text->selc);
+ }
+}
+
+int setcurr_tab (Text *text)
+{
+ int i = 0;
+ int test = 0;
+ char *word = ":";
+ char *comm = "#";
+ char back_words[3][7] = {"return", "break", "pass"};
+ if (!text) return 0;
+ if (!text->curl) return 0;
+
+ while (text->curl->line[i] == '\t')
+ {
+ //we only count thos tabs that are before any text or before the curs;
+ if (i == text->curc)
+ {
+ return i;
+ } else {
+ i++;
+ }
+ }
+ if(strstr(text->curl->line, word))
+ {
+ //if we find a : then add a tab but not if it is in a comment
+ if(strcspn(text->curl->line, word) < strcspn(text->curl->line, comm))
+ {
+ i++;
+
+ }
+ }
+
+ while(test < 3)
+ {
+ //if there are these 3 key words then remove a tab because we are done with the block
+ if(strstr(text->curl->line, back_words[test]) && i > 0)
+ {
+ if(strcspn(text->curl->line, back_words[test]) < strcspn(text->curl->line, comm))
+ {
+ i--;
+ }
+ }
+ test++;
+ }
+ return i;
+}
+
diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c
new file mode 100644
index 00000000000..a53db265c52
--- /dev/null
+++ b/source/blender/blenkernel/intern/texture.c
@@ -0,0 +1,820 @@
+/* texture.c
+ *
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "PIL_dynlib.h"
+
+#include "MTC_matrixops.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_rand.h"
+
+#include "DNA_texture_types.h"
+#include "DNA_key_types.h"
+#include "DNA_object_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_material_types.h"
+#include "DNA_image_types.h"
+#include "DNA_world_types.h"
+#include "DNA_brush_types.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "BKE_plugin_types.h"
+
+#include "BKE_bad_level_calls.h"
+#include "BKE_utildefines.h"
+
+#include "BKE_global.h"
+#include "BKE_main.h"
+
+#include "BKE_library.h"
+#include "BKE_image.h"
+#include "BKE_material.h"
+#include "BKE_texture.h"
+#include "BKE_key.h"
+#include "BKE_icons.h"
+#include "BKE_ipo.h"
+#include "BKE_brush.h"
+
+
+/* ------------------------------------------------------------------------- */
+
+/* All support for plugin textures: */
+int test_dlerr(const char *name, const char *symbol)
+{
+ char *err;
+
+ err= PIL_dynlib_get_error_as_string(NULL);
+ if(err) {
+ printf("var1: %s, var2: %s, var3: %s\n", name, symbol, err);
+ return 1;
+ }
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+void open_plugin_tex(PluginTex *pit)
+{
+ int (*version)(void);
+
+ /* init all the happy variables */
+ pit->doit= 0;
+ pit->pname= 0;
+ pit->stnames= 0;
+ pit->varstr= 0;
+ pit->result= 0;
+ pit->cfra= 0;
+ pit->version= 0;
+
+ /* clear the error list */
+ PIL_dynlib_get_error_as_string(NULL);
+
+ /* no PIL_dynlib_close! multiple opened plugins... */
+ /* if(pit->handle) PIL_dynlib_close(pit->handle); */
+ /* pit->handle= 0; */
+
+ /* open the needed object */
+ pit->handle= PIL_dynlib_open(pit->name);
+ if(test_dlerr(pit->name, pit->name)) return;
+
+ if (pit->handle != 0) {
+ /* find the address of the version function */
+ version= (int (*)(void)) PIL_dynlib_find_symbol(pit->handle, "plugin_tex_getversion");
+ if (test_dlerr(pit->name, "plugin_tex_getversion")) return;
+
+ if (version != 0) {
+ pit->version= version();
+ if (pit->version>=2 && pit->version<=5) {
+ int (*info_func)(PluginInfo *);
+ PluginInfo *info= (PluginInfo*) MEM_mallocN(sizeof(PluginInfo), "plugin_info");
+
+ info_func= (int (*)(PluginInfo *))PIL_dynlib_find_symbol(pit->handle, "plugin_getinfo");
+ if (!test_dlerr(pit->name, "plugin_getinfo")) {
+ info->instance_init = NULL;
+
+ info_func(info);
+
+ pit->doit= (int(*)(void)) info->tex_doit;
+ pit->callback= (void(*)(unsigned short)) info->callback;
+ pit->stypes= info->stypes;
+ pit->vars= info->nvars;
+ pit->pname= info->name;
+ pit->stnames= info->snames;
+ pit->varstr= info->varstr;
+ pit->result= info->result;
+ pit->cfra= info->cfra;
+ pit->instance_init = info->instance_init;
+ if (info->init) info->init();
+ }
+ MEM_freeN(info);
+ } else {
+ printf ("Plugin returned unrecognized version number\n");
+ return;
+ }
+ }
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* very badlevel define to bypass linking with BIF_interface.h */
+#define INT 96
+#define FLO 128
+
+PluginTex *add_plugin_tex(char *str)
+{
+ PluginTex *pit;
+ VarStruct *varstr;
+ int a;
+
+ pit= MEM_callocN(sizeof(PluginTex), "plugintex");
+
+ strcpy(pit->name, str);
+ open_plugin_tex(pit);
+
+ if(pit->doit==0) {
+ if(pit->handle==0) error("no plugin: %s", str);
+ else error("in plugin: %s", str);
+ MEM_freeN(pit);
+ return NULL;
+ }
+
+ varstr= pit->varstr;
+ for(a=0; a<pit->vars; a++, varstr++) {
+ if( (varstr->type & FLO)==FLO)
+ pit->data[a]= varstr->def;
+ else if( (varstr->type & INT)==INT)
+ *((int *)(pit->data+a))= (int) varstr->def;
+ }
+
+ if (pit->instance_init)
+ pit->instance_init((void *) pit->data);
+
+ return pit;
+}
+
+/* ------------------------------------------------------------------------- */
+
+void free_plugin_tex(PluginTex *pit)
+{
+ if(pit==0) return;
+
+ /* no PIL_dynlib_close: same plugin can be opened multiple times, 1 handle */
+ MEM_freeN(pit);
+}
+
+/* ****************** Mapping ******************* */
+
+TexMapping *add_mapping(void)
+{
+ TexMapping *texmap= MEM_callocN(sizeof(TexMapping), "Tex map");
+
+ texmap->size[0]= texmap->size[1]= texmap->size[2]= 1.0f;
+ texmap->max[0]= texmap->max[1]= texmap->max[2]= 1.0f;
+ Mat4One(texmap->mat);
+
+ return texmap;
+}
+
+void init_mapping(TexMapping *texmap)
+{
+ float eul[3], smat[3][3], rmat[3][3], mat[3][3];
+
+ SizeToMat3(texmap->size, smat);
+
+ eul[0]= (M_PI/180.0f)*texmap->rot[0];
+ eul[1]= (M_PI/180.0f)*texmap->rot[1];
+ eul[2]= (M_PI/180.0f)*texmap->rot[2];
+ EulToMat3(eul, rmat);
+
+ Mat3MulMat3(mat, rmat, smat);
+
+ Mat4CpyMat3(texmap->mat, mat);
+ VECCOPY(texmap->mat[3], texmap->loc);
+
+}
+
+/* ****************** COLORBAND ******************* */
+
+void init_colorband(ColorBand *coba, int rangetype)
+{
+ int a;
+
+ coba->data[0].pos= 0.0;
+ coba->data[1].pos= 1.0;
+
+ if(rangetype==0) {
+ coba->data[0].r= 0.0;
+ coba->data[0].g= 0.0;
+ coba->data[0].b= 0.0;
+ coba->data[0].a= 0.0;
+
+ coba->data[1].r= 0.0;
+ coba->data[1].g= 1.0;
+ coba->data[1].b= 1.0;
+ coba->data[1].a= 1.0;
+ }
+ else {
+ coba->data[0].r= 0.0;
+ coba->data[0].g= 0.0;
+ coba->data[0].b= 0.0;
+ coba->data[0].a= 1.0;
+
+ coba->data[1].r= 1.0;
+ coba->data[1].g= 1.0;
+ coba->data[1].b= 1.0;
+ coba->data[1].a= 1.0;
+ }
+
+ for(a=2; a<MAXCOLORBAND; a++) {
+ coba->data[a].r= 0.5;
+ coba->data[a].g= 0.5;
+ coba->data[a].b= 0.5;
+ coba->data[a].a= 1.0;
+ coba->data[a].pos= 0.5;
+ }
+
+ coba->tot= 2;
+
+}
+
+ColorBand *add_colorband(int rangetype)
+{
+ ColorBand *coba;
+
+ coba= MEM_callocN( sizeof(ColorBand), "colorband");
+ init_colorband(coba, rangetype);
+
+ return coba;
+}
+
+/* ------------------------------------------------------------------------- */
+
+int do_colorband(ColorBand *coba, float in, float out[4])
+{
+ CBData *cbd1, *cbd2, *cbd0, *cbd3;
+ float fac, mfac, t[4];
+ int a;
+
+ if(coba==NULL || coba->tot==0) return 0;
+
+ cbd1= coba->data;
+ if(coba->tot==1) {
+ out[0]= cbd1->r;
+ out[1]= cbd1->g;
+ out[2]= cbd1->b;
+ out[3]= cbd1->a;
+ }
+ else {
+ if(in <= cbd1->pos && coba->ipotype<2) {
+ out[0]= cbd1->r;
+ out[1]= cbd1->g;
+ out[2]= cbd1->b;
+ out[3]= cbd1->a;
+ }
+ else {
+ CBData left, right;
+
+ /* we're looking for first pos > in */
+ for(a=0; a<coba->tot; a++, cbd1++) if(cbd1->pos > in) break;
+
+ if(a==coba->tot) {
+ cbd2= cbd1-1;
+ right= *cbd2;
+ right.pos= 1.0f;
+ cbd1= &right;
+ }
+ else if(a==0) {
+ left= *cbd1;
+ left.pos= 0.0f;
+ cbd2= &left;
+ }
+ else cbd2= cbd1-1;
+
+ if(in >= cbd1->pos && coba->ipotype<2) {
+ out[0]= cbd1->r;
+ out[1]= cbd1->g;
+ out[2]= cbd1->b;
+ out[3]= cbd1->a;
+ }
+ else {
+
+ if(cbd2->pos!=cbd1->pos)
+ fac= (in-cbd1->pos)/(cbd2->pos-cbd1->pos);
+ else
+ fac= 0.0f;
+
+ if(coba->ipotype>=2) {
+ /* ipo from right to left: 3 2 1 0 */
+
+ if(a>=coba->tot-1) cbd0= cbd1;
+ else cbd0= cbd1+1;
+ if(a<2) cbd3= cbd2;
+ else cbd3= cbd2-1;
+
+ CLAMP(fac, 0.0f, 1.0f);
+
+ if(coba->ipotype==3)
+ set_four_ipo(fac, t, KEY_CARDINAL);
+ else
+ set_four_ipo(fac, t, KEY_BSPLINE);
+
+ out[0]= t[3]*cbd3->r +t[2]*cbd2->r +t[1]*cbd1->r +t[0]*cbd0->r;
+ out[1]= t[3]*cbd3->g +t[2]*cbd2->g +t[1]*cbd1->g +t[0]*cbd0->g;
+ out[2]= t[3]*cbd3->b +t[2]*cbd2->b +t[1]*cbd1->b +t[0]*cbd0->b;
+ out[3]= t[3]*cbd3->a +t[2]*cbd2->a +t[1]*cbd1->a +t[0]*cbd0->a;
+ CLAMP(out[0], 0.0, 1.0);
+ CLAMP(out[1], 0.0, 1.0);
+ CLAMP(out[2], 0.0, 1.0);
+ CLAMP(out[3], 0.0, 1.0);
+ }
+ else {
+
+ if(coba->ipotype==1) { /* EASE */
+ mfac= fac*fac;
+ fac= 3.0f*mfac-2.0f*mfac*fac;
+ }
+ mfac= 1.0f-fac;
+
+ out[0]= mfac*cbd1->r + fac*cbd2->r;
+ out[1]= mfac*cbd1->g + fac*cbd2->g;
+ out[2]= mfac*cbd1->b + fac*cbd2->b;
+ out[3]= mfac*cbd1->a + fac*cbd2->a;
+ }
+ }
+ }
+ }
+ return 1; /* OK */
+}
+
+/* ******************* TEX ************************ */
+
+void free_texture(Tex *tex)
+{
+ free_plugin_tex(tex->plugin);
+ if(tex->coba) MEM_freeN(tex->coba);
+ if(tex->env) BKE_free_envmap(tex->env);
+ BKE_previewimg_free(&tex->preview);
+ BKE_icon_delete((struct ID*)tex);
+ tex->id.icon_id = 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+void default_tex(Tex *tex)
+{
+ PluginTex *pit;
+ VarStruct *varstr;
+ int a;
+
+ tex->stype= 0;
+ tex->flag= TEX_CHECKER_ODD;
+ tex->imaflag= TEX_INTERPOL+TEX_MIPMAP;
+ tex->extend= TEX_REPEAT;
+ tex->cropxmin= tex->cropymin= 0.0;
+ tex->cropxmax= tex->cropymax= 1.0;
+ tex->xrepeat= tex->yrepeat= 1;
+ tex->fie_ima= 2;
+ tex->sfra= 1;
+ tex->frames= 0;
+ tex->offset= 0;
+ tex->noisesize= 0.25;
+ tex->noisedepth= 2;
+ tex->turbul= 5.0;
+ tex->nabla= 0.025; // also in do_versions
+ tex->bright= 1.0;
+ tex->contrast= tex->filtersize= 1.0;
+ tex->rfac= 1.0;
+ tex->gfac= 1.0;
+ tex->bfac= 1.0;
+ /* newnoise: init. */
+ tex->noisebasis = 0;
+ tex->noisebasis2 = 0;
+ /* musgrave */
+ tex->mg_H = 1.0;
+ tex->mg_lacunarity = 2.0;
+ tex->mg_octaves = 2.0;
+ tex->mg_offset = 1.0;
+ tex->mg_gain = 1.0;
+ tex->ns_outscale = 1.0;
+ /* distnoise */
+ tex->dist_amount = 1.0;
+ /* voronoi */
+ tex->vn_w1 = 1.0;
+ tex->vn_w2 = tex->vn_w3 = tex->vn_w4 = 0.0;
+ tex->vn_mexp = 2.5;
+ tex->vn_distm = 0;
+ tex->vn_coltype = 0;
+
+ if (tex->env) {
+ tex->env->stype=ENV_STATIC;
+ tex->env->clipsta=0.1;
+ tex->env->clipend=100;
+ tex->env->cuberes=100;
+ tex->env->depth=0;
+ }
+
+ pit = tex->plugin;
+ if (pit) {
+ varstr= pit->varstr;
+ if(varstr) {
+ for(a=0; a<pit->vars; a++, varstr++) {
+ pit->data[a] = varstr->def;
+ }
+ }
+ }
+
+ tex->iuser.fie_ima= 2;
+ tex->iuser.ok= 1;
+ tex->iuser.frames= 100;
+
+ tex->preview = NULL;
+}
+
+/* ------------------------------------------------------------------------- */
+
+Tex *add_texture(char *name)
+{
+ Tex *tex;
+
+ tex= alloc_libblock(&G.main->tex, ID_TE, name);
+
+ default_tex(tex);
+
+ return tex;
+}
+
+/* ------------------------------------------------------------------------- */
+
+void default_mtex(MTex *mtex)
+{
+ mtex->texco= TEXCO_ORCO;
+ mtex->mapto= MAP_COL;
+ mtex->object= 0;
+ mtex->projx= PROJ_X;
+ mtex->projy= PROJ_Y;
+ mtex->projz= PROJ_Z;
+ mtex->mapping= MTEX_FLAT;
+ mtex->ofs[0]= 0.0;
+ mtex->ofs[1]= 0.0;
+ mtex->ofs[2]= 0.0;
+ mtex->size[0]= 1.0;
+ mtex->size[1]= 1.0;
+ mtex->size[2]= 1.0;
+ mtex->tex= 0;
+ mtex->texflag= 0;
+ mtex->colormodel= 0;
+ mtex->r= 1.0;
+ mtex->g= 0.0;
+ mtex->b= 1.0;
+ mtex->k= 1.0;
+ mtex->def_var= 1.0;
+ mtex->blendtype= MTEX_BLEND;
+ mtex->colfac= 1.0;
+ mtex->norfac= 0.5;
+ mtex->varfac= 1.0;
+ mtex->dispfac=0.2;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+MTex *add_mtex()
+{
+ MTex *mtex;
+
+ mtex= MEM_callocN(sizeof(MTex), "add_mtex");
+
+ default_mtex(mtex);
+
+ return mtex;
+}
+
+/* ------------------------------------------------------------------------- */
+
+Tex *copy_texture(Tex *tex)
+{
+ Tex *texn;
+
+ texn= copy_libblock(tex);
+ if(texn->type==TEX_IMAGE) id_us_plus((ID *)texn->ima);
+ else texn->ima= 0;
+
+ if(texn->plugin) {
+ texn->plugin= MEM_dupallocN(texn->plugin);
+ open_plugin_tex(texn->plugin);
+ }
+
+ if(texn->coba) texn->coba= MEM_dupallocN(texn->coba);
+ if(texn->env) texn->env= BKE_copy_envmap(texn->env);
+
+ if(tex->preview) texn->preview = BKE_previewimg_copy(tex->preview);
+
+ return texn;
+}
+
+/* ------------------------------------------------------------------------- */
+
+void make_local_texture(Tex *tex)
+{
+ Tex *texn;
+ Material *ma;
+ World *wrld;
+ Lamp *la;
+ Brush *br;
+ int a, local=0, lib=0;
+
+ /* - only lib users: do nothing
+ * - only local users: set flag
+ * - mixed: make copy
+ */
+
+ if(tex->id.lib==0) return;
+
+ /* special case: ima always local immediately */
+ if(tex->ima) {
+ tex->ima->id.lib= 0;
+ tex->ima->id.flag= LIB_LOCAL;
+ new_id(0, (ID *)tex->ima, 0);
+ }
+
+ if(tex->id.us==1) {
+ tex->id.lib= 0;
+ tex->id.flag= LIB_LOCAL;
+ new_id(0, (ID *)tex, 0);
+
+ return;
+ }
+
+ ma= G.main->mat.first;
+ while(ma) {
+ for(a=0; a<MAX_MTEX; a++) {
+ if(ma->mtex[a] && ma->mtex[a]->tex==tex) {
+ if(ma->id.lib) lib= 1;
+ else local= 1;
+ }
+ }
+ ma= ma->id.next;
+ }
+ la= G.main->lamp.first;
+ while(la) {
+ for(a=0; a<MAX_MTEX; a++) {
+ if(la->mtex[a] && la->mtex[a]->tex==tex) {
+ if(la->id.lib) lib= 1;
+ else local= 1;
+ }
+ }
+ la= la->id.next;
+ }
+ wrld= G.main->world.first;
+ while(wrld) {
+ for(a=0; a<MAX_MTEX; a++) {
+ if(wrld->mtex[a] && wrld->mtex[a]->tex==tex) {
+ if(wrld->id.lib) lib= 1;
+ else local= 1;
+ }
+ }
+ wrld= wrld->id.next;
+ }
+ br= G.main->brush.first;
+ while(br) {
+ for(a=0; a<MAX_MTEX; a++) {
+ if(br->mtex[a] && br->mtex[a]->tex==tex) {
+ if(br->id.lib) lib= 1;
+ else local= 1;
+ }
+ }
+ br= br->id.next;
+ }
+
+ if(local && lib==0) {
+ tex->id.lib= 0;
+ tex->id.flag= LIB_LOCAL;
+ new_id(0, (ID *)tex, 0);
+ }
+ else if(local && lib) {
+ texn= copy_texture(tex);
+ texn->id.us= 0;
+
+ ma= G.main->mat.first;
+ while(ma) {
+ for(a=0; a<MAX_MTEX; a++) {
+ if(ma->mtex[a] && ma->mtex[a]->tex==tex) {
+ if(ma->id.lib==0) {
+ ma->mtex[a]->tex= texn;
+ texn->id.us++;
+ tex->id.us--;
+ }
+ }
+ }
+ ma= ma->id.next;
+ }
+ la= G.main->lamp.first;
+ while(la) {
+ for(a=0; a<MAX_MTEX; a++) {
+ if(la->mtex[a] && la->mtex[a]->tex==tex) {
+ if(la->id.lib==0) {
+ la->mtex[a]->tex= texn;
+ texn->id.us++;
+ tex->id.us--;
+ }
+ }
+ }
+ la= la->id.next;
+ }
+ wrld= G.main->world.first;
+ while(wrld) {
+ for(a=0; a<MAX_MTEX; a++) {
+ if(wrld->mtex[a] && wrld->mtex[a]->tex==tex) {
+ if(wrld->id.lib==0) {
+ wrld->mtex[a]->tex= texn;
+ texn->id.us++;
+ tex->id.us--;
+ }
+ }
+ }
+ wrld= wrld->id.next;
+ }
+ br= G.main->brush.first;
+ while(br) {
+ for(a=0; a<MAX_MTEX; a++) {
+ if(br->mtex[a] && br->mtex[a]->tex==tex) {
+ if(br->id.lib==0) {
+ br->mtex[a]->tex= texn;
+ texn->id.us++;
+ tex->id.us--;
+ }
+ }
+ }
+ br= br->id.next;
+ }
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+void autotexname(Tex *tex)
+{
+/* extern char texstr[20][12]; *//* buttons.c, already in bad lev calls*/
+ Image *ima;
+ char di[FILE_MAXDIR], fi[FILE_MAXFILE];
+
+ if(tex) {
+ if(tex->type==TEX_IMAGE) {
+ ima= tex->ima;
+ if(ima) {
+ strcpy(di, ima->name);
+ BLI_splitdirstring(di, fi);
+ strcpy(di, "I.");
+ strcat(di, fi);
+ new_id(&G.main->tex, (ID *)tex, di);
+ }
+ else new_id(&G.main->tex, (ID *)tex, texstr[tex->type]);
+ }
+ else if(tex->type==TEX_PLUGIN && tex->plugin) new_id(&G.main->tex, (ID *)tex, tex->plugin->pname);
+ else new_id(&G.main->tex, (ID *)tex, texstr[tex->type]);
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+Tex *give_current_texture(Object *ob, int act)
+{
+ Material ***matarar, *ma;
+ Lamp *la = 0;
+ MTex *mtex = 0;
+ Tex *tex = 0;
+
+ if(ob==0) return 0;
+ if(ob->totcol==0) return 0;
+
+ if(ob->type==OB_LAMP) {
+ la=(Lamp *)ob->data;
+ if(la) {
+ mtex= la->mtex[(int)(la->texact)];
+ if(mtex) tex= mtex->tex;
+ }
+ else tex= 0;
+ } else {
+ if(act>ob->totcol) act= ob->totcol;
+ else if(act==0) act= 1;
+
+ if( BTST(ob->colbits, act-1) ) { /* in object */
+ ma= ob->mat[act-1];
+ }
+ else { /* in data */
+ matarar= give_matarar(ob);
+
+ if(matarar && *matarar) ma= (*matarar)[act-1];
+ else ma= 0;
+
+ }
+ if(ma) {
+ mtex= ma->mtex[(int)(ma->texact)];
+ if(mtex) tex= mtex->tex;
+ }
+ else tex= 0;
+ }
+
+ return tex;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+EnvMap *BKE_add_envmap(void)
+{
+ EnvMap *env;
+
+ env= MEM_callocN(sizeof(EnvMap), "envmap");
+ env->type= ENV_CUBE;
+ env->stype= ENV_STATIC;
+ env->clipsta= 0.1;
+ env->clipend= 100.0;
+ env->cuberes= 100;
+
+ return env;
+}
+
+/* ------------------------------------------------------------------------- */
+
+EnvMap *BKE_copy_envmap(EnvMap *env)
+{
+ EnvMap *envn;
+ int a;
+
+ envn= MEM_dupallocN(env);
+ envn->ok= 0;
+ for(a=0; a<6; a++) envn->cube[a]= NULL;
+ if(envn->ima) id_us_plus((ID *)envn->ima);
+
+ return envn;
+}
+
+/* ------------------------------------------------------------------------- */
+
+void BKE_free_envmapdata(EnvMap *env)
+{
+ unsigned int part;
+
+ for(part=0; part<6; part++) {
+ if(env->cube[part])
+ IMB_freeImBuf(env->cube[part]);
+ env->cube[part]= NULL;
+ }
+ env->ok= 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+void BKE_free_envmap(EnvMap *env)
+{
+
+ BKE_free_envmapdata(env);
+ MEM_freeN(env);
+
+}
+
+/* ------------------------------------------------------------------------- */
diff --git a/source/blender/blenkernel/intern/verse_bitmap_node.c b/source/blender/blenkernel/intern/verse_bitmap_node.c
new file mode 100644
index 00000000000..5f2c48b5221
--- /dev/null
+++ b/source/blender/blenkernel/intern/verse_bitmap_node.c
@@ -0,0 +1,451 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributor(s): Jiri Hnidek.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifdef WITH_VERSE
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+
+#include "BLI_dynamiclist.h"
+#include "BLI_blenlib.h"
+
+#include "BIF_verse.h"
+
+#include "BKE_verse.h"
+
+#include "verse.h"
+
+/* function prototypes of static functions */
+static void cb_b_dimension_set(void *user_data, VNodeID node_id, uint16 width, uint16 height, uint16 depth);
+static void cb_b_layer_create(void *user_data, VNodeID node_id, VLayerID layer_id, const char *name, VNBLayerType type);
+static void cb_b_layer_destroy(void *user_data, VNodeID node_id, VLayerID layer_id);
+static void cb_b_tile_set(void *user_data, VNodeID node_id, VLayerID layer_id, uint16 tile_x, uint16 tile_y, uint16 z, VNBLayerType type, const VNBTile *tile);
+
+static void change_layer_dimension(
+ VBitmapLayer *vblayer,
+ unsigned int old_width,
+ unsigned int old_height,
+ unsigned int t_old_width,
+ unsigned int t_old_height);
+static void *alloc_verse_bitmap_layer_data(struct VBitmapLayer *vblayer);
+
+/*
+ * resize/crop verse bitmap layer
+ */
+static void change_layer_dimension(
+ VBitmapLayer *vblayer,
+ unsigned int old_width,
+ unsigned int old_height,
+ unsigned int t_old_width,
+ unsigned int t_old_height)
+{
+ struct VNode *vnode = vblayer->vnode;
+ unsigned int t_width = ((VBitmapData*)(vnode->data))->t_width;
+ unsigned int width = ((VBitmapData*)(vnode->data))->width;
+ unsigned int height = ((VBitmapData*)(vnode->data))->height;
+ unsigned int x, y, i, j;
+
+ i = j = 0;
+
+ /* "copy" old data to new data */
+ if(vblayer->type==VN_B_LAYER_UINT8) {
+ unsigned char *data = (unsigned char*)vblayer->data;
+ /* allocate new verse bitmap layer data */
+ unsigned char *new_data = (unsigned char*)alloc_verse_bitmap_layer_data(vblayer);
+ for(y=0; y<old_height && y<height; y++, i=y*t_width, j=y*t_old_width) {
+ for(x=0; x<old_width && y<width; x++, i++, j++) {
+ new_data[i] = data[j];
+ }
+ }
+ MEM_freeN(vblayer->data);
+ vblayer->data = new_data;
+ }
+}
+
+/*
+ * free data stored in verse bitmap layer
+ */
+void free_bitmap_layer_data(VBitmapLayer *vblayer)
+{
+ struct VerseSession *session = vblayer->vnode->session;
+
+ /* free name of bitmap layer */
+ MEM_freeN(vblayer->name);
+
+ /* unsubscribe from verse bitmap layer */
+ if(session->flag & VERSE_CONNECTED)
+ verse_send_b_layer_unsubscribe(vblayer->vnode->id, vblayer->id);
+
+ /* free image data of bitmap layer */
+ if(vblayer->data) MEM_freeN(vblayer->data);
+}
+
+/*
+ * allocate data of verse bitmap layer
+ */
+static void *alloc_verse_bitmap_layer_data(VBitmapLayer *vblayer)
+{
+ struct VNode *vnode = vblayer->vnode;
+ unsigned int t_width = ((VBitmapData*)(vnode->data))->t_width;
+ unsigned int t_height = ((VBitmapData*)(vnode->data))->t_height;
+ unsigned int size;
+ void *data;
+
+ size = t_width*t_height;
+
+ /* allocation of own data stored in verse bitmap layer */
+ switch (vblayer->type) {
+ case VN_B_LAYER_UINT1:
+ data = (void*)MEM_mallocN(sizeof(unsigned char)*size, "VBLayer data uint1");
+ break;
+ case VN_B_LAYER_UINT8:
+ data = (void*)MEM_mallocN(sizeof(unsigned char)*size, "VBLayer data uint8");
+ break;
+ case VN_B_LAYER_UINT16:
+ data = (void*)MEM_mallocN(sizeof(unsigned int)*size, "VBLayer data uint16");
+ break;
+ case VN_B_LAYER_REAL32:
+ data = (void*)MEM_mallocN(sizeof(float)*size, "VBLayer data float16");
+ break;
+ case VN_B_LAYER_REAL64:
+ data = (void*)MEM_mallocN(sizeof(double)*size, "VBLayer data float32");
+ break;
+ default:
+ data = NULL;
+ break;
+ }
+
+ return data;
+}
+
+/*
+ * create verse bitmap layer
+ */
+VBitmapLayer *create_bitmap_layer(
+ VNode *vnode,
+ VLayerID layer_id,
+ const char *name,
+ VNBLayerType type)
+{
+ struct VBitmapLayer *vblayer;
+ unsigned int width = ((VBitmapData*)(vnode->data))->width;
+ unsigned int height = ((VBitmapData*)(vnode->data))->height;
+
+ /* allocate memory for own verse bitmap layer */
+ vblayer = (VBitmapLayer*)MEM_mallocN(sizeof(VBitmapLayer), "Verse Bitmap Layer");
+
+ /* verse bitmap layer will include pointer at parent verse node and own id */
+ vblayer->vnode = vnode;
+ vblayer->id = layer_id;
+
+ /* name of verse layer */
+ vblayer->name = (char*)MEM_mallocN(sizeof(char)*(strlen(name)+1), "Verse Bitmap Layer name");
+ vblayer->name[0] = '\0';
+ strcpy(vblayer->name, name);
+
+ /* type of data stored in verse bitmap layer */
+ vblayer->type = type;
+
+ /* we can allocate memory for layer data, when we know dimmension of layers; when
+ * we don't know it, then we will allocate this data when we will receive dimmension */
+ if(width==0 || height==0)
+ vblayer->data = NULL;
+ else
+ vblayer->data = alloc_verse_bitmap_layer_data(vblayer);
+
+ vblayer->flag = 0;
+
+ return vblayer;
+}
+
+/*
+ * free data of bitmap node
+ */
+void free_bitmap_node_data(VNode *vnode)
+{
+ if(vnode->data) {
+ struct VBitmapLayer *vblayer = (VBitmapLayer*)((VBitmapData*)(vnode->data))->layers.lb.first;
+
+ /* free all VerseLayer data */
+ while(vblayer) {
+ free_bitmap_layer_data(vblayer);
+ vblayer = vblayer->next;
+ }
+
+ /* free all VerseLayers */
+ BLI_dlist_destroy(&(((VGeomData*)vnode->data)->layers));
+ }
+}
+
+/*
+ * create data of bitmap node
+ */
+VBitmapData *create_bitmap_data()
+{
+ struct VBitmapData *vbitmap;
+
+ vbitmap = (VBitmapData*)MEM_mallocN(sizeof(VBitmapData), "Verse Bitmap Data");
+
+ BLI_dlist_init(&(vbitmap->layers));
+ vbitmap->queue.first = vbitmap->queue.last = NULL;
+
+ vbitmap->width = 0;
+ vbitmap->height = 0;
+ vbitmap->depth = 0;
+
+ vbitmap->image = NULL;
+
+ vbitmap->post_bitmap_dimension_set = post_bitmap_dimension_set;
+ vbitmap->post_bitmap_layer_create = post_bitmap_layer_create;
+ vbitmap->post_bitmap_layer_destroy = post_bitmap_layer_destroy;
+ vbitmap->post_bitmap_tile_set = post_bitmap_tile_set;
+
+ return vbitmap;
+}
+
+/*
+ * callback function, dimension of image was changed, it is neccessary to
+ * crop all layers
+ */
+static void cb_b_dimension_set(
+ void *user_data,
+ VNodeID node_id,
+ uint16 width,
+ uint16 height,
+ uint16 depth)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VBitmapLayer *vblayer;
+ unsigned int old_width, old_height, t_old_width, t_old_height;
+
+ if(!session) return;
+
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ if(!vnode) return;
+
+#ifdef VERSE_DEBUG_PRINT
+ printf("\t cb_b_dimension_set()\n");
+#endif
+
+ /* backup old width and height */
+ old_width = ((VBitmapData*)(vnode->data))->width;
+ old_height = ((VBitmapData*)(vnode->data))->height;
+ t_old_width = ((VBitmapData*)(vnode->data))->t_width;
+ t_old_height = ((VBitmapData*)(vnode->data))->t_height;
+
+ /* set up new dimension of layers */
+ ((VBitmapData*)(vnode->data))->width = width;
+ ((VBitmapData*)(vnode->data))->height = height;
+ ((VBitmapData*)(vnode->data))->depth = depth;
+
+ /* we cache t_width because tiles aren't one pixel width */
+ if((width % VN_B_TILE_SIZE)!=0)
+ ((VBitmapData*)(vnode->data))->t_width = (width/VN_B_TILE_SIZE + 1)*VN_B_TILE_SIZE;
+ else
+ ((VBitmapData*)(vnode->data))->t_width = width;
+
+ /* we cache t_height because tiles aren't one pixel height */
+ if((height % VN_B_TILE_SIZE)!=0)
+ ((VBitmapData*)(vnode->data))->t_height = (height/VN_B_TILE_SIZE + 1)*VN_B_TILE_SIZE;
+ else
+ ((VBitmapData*)(vnode->data))->t_height = height;
+
+ /* crop resize all layers */
+ vblayer = ((VBitmapData*)vnode->data)->layers.lb.first;
+
+ while(vblayer) {
+ /* when this callback function received after cb_b_layer_create,
+ * then we have to allocate memory for verse bitmap layer data */
+ if(!vblayer->data) vblayer->data = alloc_verse_bitmap_layer_data(vblayer);
+ /* crop/resize all verse bitmap layers */
+ else change_layer_dimension(vblayer, old_width, old_height, t_old_width, t_old_height);
+
+ vblayer = vblayer->next;
+ }
+
+ /* post callback function */
+ ((VBitmapData*)(vnode->data))->post_bitmap_dimension_set(vnode);
+}
+
+/*
+ * callback function, new layer channel of image was created
+ */
+static void cb_b_layer_create(
+ void *user_data,
+ VNodeID node_id,
+ VLayerID layer_id,
+ const char *name,
+ VNBLayerType type)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VBitmapLayer *vblayer;
+
+ if(!session) return;
+
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ if(!vnode) return;
+
+#ifdef VERSE_DEBUG_PRINT
+ printf("\t cb_b_layer_create()\n");
+#endif
+
+ /* when no layer exists, then new layer will be created */
+ vblayer = create_bitmap_layer(vnode, layer_id, name, type);
+
+ /* add verse bitmap layer to list of layers */
+ BLI_dlist_add_item_index(&((VBitmapData*)vnode->data)->layers, vblayer, layer_id);
+
+ /* post callback function */
+ ((VBitmapData*)(vnode->data))->post_bitmap_layer_create(vblayer);
+
+}
+
+/*
+ * callback function, existing layer of image was destroyed
+ */
+static void cb_b_layer_destroy(
+ void *user_data,
+ VNodeID node_id,
+ VLayerID layer_id)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VBitmapLayer *vblayer;
+
+ if(!session) return;
+
+ /* find node of this layer*/
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ if(!vnode) return;
+
+ vblayer = (VBitmapLayer*)BLI_dlist_find_link(&(((VBitmapData*)vnode->data)->layers), layer_id);
+ if(!vblayer) return;
+
+#ifdef VERSE_DEBUG_PRINT
+ printf("\t cb_b_layer_destroy()\n");
+#endif
+
+ /* remove verse bitmap layer from list of layers */
+ BLI_dlist_rem_item(&(((VBitmapData*)vnode->data)->layers), layer_id);
+
+ /* post callback function */
+ ((VBitmapData*)(vnode->data))->post_bitmap_layer_destroy(vblayer);
+
+ /* free data of verse bitmap layer */
+ free_bitmap_layer_data(vblayer);
+
+ /* free verse bitmap layer */
+ MEM_freeN(vblayer);
+}
+
+/*
+ * callback function, small part (8x8 pixels) was changed
+ */
+static void cb_b_tile_set(
+ void *user_data,
+ VNodeID node_id,
+ VLayerID layer_id,
+ uint16 tile_x,
+ uint16 tile_y,
+ uint16 z,
+ VNBLayerType type,
+ const VNBTile *tile)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VBitmapLayer *vblayer;
+ unsigned int x, y, xs, ys, width, height, t_height, t_width, i, j;
+
+ if(!session) return;
+
+ /* try to find verse node in dynamic list nodes */
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ if(!vnode) return;
+
+ /* try to find verse bitmap layer in list of layers */
+ vblayer = (VBitmapLayer*)BLI_dlist_find_link(&(((VBitmapData*)vnode->data)->layers), layer_id);
+ if(!vblayer) return;
+
+ /* we have to have allocated memory for bitmap layer */
+ if(!vblayer->data) return;
+
+ width = ((VBitmapData*)vnode->data)->width;
+ height = ((VBitmapData*)vnode->data)->height;
+
+ /* width of verse image including all tiles */
+ t_height = ((VBitmapData*)vnode->data)->t_height;
+ /* height of verse image including all tiles */
+ t_width = ((VBitmapData*)vnode->data)->t_width;
+
+#ifdef VERSE_DEBUG_PRINT
+ printf("\t cb_b_tile_set()\n");
+#endif
+
+ xs = tile_x*VN_B_TILE_SIZE;
+ ys = tile_y*VN_B_TILE_SIZE;
+
+ /* initial position in one dimension vblayer->data (y_start*width + x_start) */
+ i = ys*t_width + xs;
+ /* intial position in one dimension tile array */
+ j = 0;
+
+ if(type==VN_B_LAYER_UINT8) {
+ unsigned char *data = (unsigned char*)vblayer->data;
+ for(y=ys; y<ys+VN_B_TILE_SIZE && y<height; y++, i=y*t_width+xs)
+ for(x=xs; x<xs+VN_B_TILE_SIZE && x<width; x++, i++, j++)
+ data[i] = (unsigned char)tile->vuint8[j];
+ }
+
+ /* post callback function */
+ ((VBitmapData*)(vnode->data))->post_bitmap_tile_set(vblayer, xs, ys);
+}
+
+/*
+ * set up all callbacks functions for image nodes
+ */
+void set_bitmap_callbacks(void)
+{
+ /* dimension (size) of bitmap was set up or changes (image will be croped) */
+ verse_callback_set(verse_send_b_dimensions_set, cb_b_dimension_set, NULL);
+
+ /* new layer (chanell) of image was added or created */
+ verse_callback_set(verse_send_b_layer_create, cb_b_layer_create, NULL);
+
+ /* existing layer was destroyed */
+ verse_callback_set(verse_send_b_layer_destroy, cb_b_layer_destroy, NULL);
+
+ /* some tile (small part 8x8 pixels of image was changed) */
+ verse_callback_set(verse_send_b_tile_set, cb_b_tile_set, NULL);
+}
+
+#endif
+
diff --git a/source/blender/blenkernel/intern/verse_geometry_node.c b/source/blender/blenkernel/intern/verse_geometry_node.c
new file mode 100644
index 00000000000..613d4eadbec
--- /dev/null
+++ b/source/blender/blenkernel/intern/verse_geometry_node.c
@@ -0,0 +1,2101 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributor(s): Jiri Hnidek.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifdef WITH_VERSE
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+
+#include "BLI_dynamiclist.h"
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "BKE_verse.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_verse.h"
+
+#include "verse.h"
+
+/* function prototypes of static functions */
+
+/* test functions for callback functions */
+static char test_polygon_set_corner_uint32(uint32 v0, uint32 v1, uint32 v2, uint32 v3);
+
+/* callback functions */
+static void cb_g_layer_create(void *user_data, VNodeID node_id, VLayerID layer_id, const char *name, VNGLayerType type, uint32 def_integer, real64 def_real);
+static void cb_g_layer_destroy(void *user_data, VNodeID node_id, VLayerID layer_id);
+static void cb_g_vertex_set_xyz_real32(void *user_data, VNodeID node_id, VLayerID layer_id, uint32 vertex_id, real32 x, real32 y, real32 z);
+static void cb_g_polygon_set_corner_uint32(void *user_data, VNodeID node_id, VLayerID layer_id, uint32 polygon_id, uint32 v0, uint32 v1, uint32 v2, uint32 v3);
+static void cb_g_vertex_delete_real32(void *user_data, VNodeID node_id, uint32 vertex_id);
+static void cb_g_polygon_delete(void *user_data, VNodeID node_id, uint32 polygon_id);
+static void cb_g_crease_set_edge(void *user_data, VNodeID node_id, const char *layer, uint32 def_crease);
+static void cb_g_crease_set_vertex(void *user_data, VNodeID node_id, const char *layer, uint32 def_crease);
+
+/* other static functions */
+
+static void free_unneeded_verseverts_of_verseface(struct VNode *vnode, struct VerseFace *vface);
+static void free_verse_vertex(struct VLayer *vlayer, struct VerseVert *vvert);
+static void free_verse_face(struct VLayer *vlayer, struct VerseFace *vface);
+static void free_verse_layer_data(struct VNode *vnode, struct VLayer *vlayer);
+
+static void send_verse_face(struct VerseFace *vface);
+
+static VerseVert* find_verse_vert_in_queue(struct VLayer *vlayer, VNodeID node_id, uint32 vertex_id, real32 x, real32 y, real32 z);
+static VerseFace* find_verse_face_in_queue(struct VLayer *vlayer, VNodeID node_id, uint32 polygon_id, uint32 v0, uint32 v1, uint32 v2, uint32 v3);
+
+static unsigned short test_incoming_verseface(struct VGeomData *geom, struct VerseFace *vface);
+static void find_unsent_faces(struct VNode *vnode, struct VerseVert *vvert);
+static void find_vlayer_orphans(struct VNode *vnode, struct VerseVert *vvert);
+static void move_face_orphan_to_dlist(struct VNode *vnode, struct VLayer *vlayer, struct VerseFace *vface);
+static void increase_verse_verts_references(struct VerseFace *vface);
+static void recalculate_verseface_normals(struct VNode *vnode);
+
+/* verse edge functions */
+static VerseEdge* find_verse_edge(struct VNode *vnode, uint32 v0, uint32 v1);
+static void insert_verse_edgehash(struct VNode *vnode, struct VerseEdge *vedge);
+static void remove_verse_edgehash(struct VNode *vnode, struct VerseEdge *vedge);
+static void remove_verse_edge(struct VNode *vnode, uint32 v0, uint32 v1);
+static void add_verse_edge(struct VNode *vnode, uint32 v0, uint32 v1);
+static void update_edgehash_of_deleted_verseface(struct VNode *vnode, struct VerseFace *vface);
+static void update_edgehash_of_changed_verseface(struct VNode *vnode, struct VerseFace *vface, uint32 v0, uint32 v1, uint32 v2, uint32 v3);
+static void update_edgehash_of_new_verseface(struct VNode *vnode, uint32 v0, uint32 v1, uint32 v2, uint32 v3);
+
+/*
+ * recalcute normals of all VerseFaces
+ */
+static void recalculate_verseface_normals(VNode *vnode)
+{
+ struct VLayer *vert_layer, *face_layer;
+ struct VerseFace *vface;
+ struct VerseVert *vvert;
+
+ if(vnode->type != V_NT_GEOMETRY) return;
+
+ vert_layer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER);
+ face_layer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER);
+
+ vvert = vert_layer->dl.lb.first;
+ while(vvert) {
+ vvert->no[0] = vvert->no[1] = vvert->no[2] = 0.0;
+ vvert = vvert->next;
+ }
+
+ vface = face_layer->dl.lb.first;
+ while(vface) {
+ /* calculate face normals */
+ if(vface->vvert3) {
+ CalcNormFloat4(vface->vvert0->co, vface->vvert1->co,
+ vface->vvert2->co, vface->vvert3->co, vface->no);
+ VecAddf(vface->vvert3->no, vface->vvert3->no, vface->no);
+ }
+ else
+ CalcNormFloat(vface->vvert0->co, vface->vvert1->co,
+ vface->vvert2->co, vface->no);
+
+ /* calculate vertex normals ... it is averadge of all face normals using the vertex */
+ VecAddf(vface->vvert0->no, vface->vvert0->no, vface->no);
+ VecAddf(vface->vvert1->no, vface->vvert1->no, vface->no);
+ VecAddf(vface->vvert2->no, vface->vvert2->no, vface->no);
+
+ vface = vface->next;
+ }
+
+ /* we have to normalize all vertex normals */
+ vvert = vert_layer->dl.lb.first;
+ while(vvert) {
+ Normalize(vvert->no);
+ vvert = vvert->next;
+ }
+}
+
+/*
+ * add created item to the queue and send it if possible
+ */
+void add_item_to_send_queue(ListBase *lb, void *item, short type)
+{
+ struct VNode *vnode;
+ struct VLayer *vlayer;
+ struct VerseVert *vvert;
+ struct VerseFace *vface;
+
+ /* this prevent from adding duplicated faces */
+ if(type==VERSE_FACE) {
+ struct Link *link = (Link*)lb->first;
+ while(link) {
+ if(link==item) {
+ if(((VerseFace*)item)->flag & FACE_SENT) {
+/* printf("\tverse face %d marked as OBSOLETE\n", ((VerseFace*)item)->id);*/
+ ((VerseFace*)item)->flag |= FACE_OBSOLETE;
+ }
+ return;
+ }
+ link = link->next;
+ }
+ }
+
+ /* add item to sending queue (two way dynamic list) */
+ BLI_addtail(lb, item);
+
+ /* send item, when it is possible */
+ switch (type) {
+ case VERSE_NODE: /* only first node in queue can be sent */
+ if(lb->first==lb->last)
+ send_verse_node((VNode*)item);
+ break;
+ case VERSE_LINK: /* both object between have to exist */
+ if(((VLink*)item)->flag & LINK_SEND_READY)
+ send_verse_link((VLink*)item);
+ break;
+ case VERSE_LAYER:
+ if(((VLayer*)item)->vnode->flag & NODE_RECEIVED)
+ send_verse_layer((VLayer*)item);
+ break;
+ case VERSE_VERT:
+ if(((VerseVert*)item)->vlayer->flag & LAYER_RECEIVED)
+ send_verse_vertex((VerseVert*)item);
+ break;
+ case VERSE_FACE: /* all vertexes of face have to be received */
+ if(((VerseFace*)item)->flag & FACE_SEND_READY)
+ send_verse_face((VerseFace*)item);
+ break;
+ case VERSE_TAG:
+ send_verse_tag((VTag*)item);
+ break;
+ case VERSE_TAG_GROUP:
+ send_verse_taggroup((VTagGroup*)item);
+ break;
+ case VERSE_VERT_UINT32: /* parent item has to exist */
+ vnode = (((uint32_item*)item)->vlayer)->vnode;
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 0 );
+ vvert = (VerseVert*)BLI_dlist_find_link(&(vlayer->dl), ((uint32_item*)item)->id );
+ if(vvert != NULL)
+ send_verse_vert_uint32((uint32_item*)item, type);
+ break;
+ case VERSE_VERT_REAL32: /* parent item has to exist */
+ vnode = (((real32_item*)item)->vlayer)->vnode;
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 0 );
+ vvert = (VerseVert*)BLI_dlist_find_link(&(vlayer->dl), ((real32_item*)item)->id );
+ if( vvert != NULL)
+ send_verse_vert_real32((real32_item*)item, type);
+ break;
+ case VERSE_VERT_VEC_REAL32: /* parent item has to exist */
+ vnode = (((vec_real32_item*)item)->vlayer)->vnode;
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 0 );
+ vvert = (VerseVert*)BLI_dlist_find_link(&(vlayer->dl), ((vec_real32_item*)item)->id );
+ if(vvert != NULL)
+ send_verse_vert_vec_real32((vec_real32_item*)item, type);
+ break;
+ case VERSE_FACE_UINT8: /* parent item has to exist */
+ vnode = (((uint8_item*)item)->vlayer)->vnode;
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 1 );
+ vface = (VerseFace*)BLI_dlist_find_link(&(vlayer->dl), ((uint8_item*)item)->id );
+ if(vface != NULL)
+ send_verse_face_uint8((uint8_item*)item, type);
+ break;
+ case VERSE_FACE_UINT32: /* parent item has to exist */
+ vnode = (((uint32_item*)item)->vlayer)->vnode;
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 1 );
+ vface = (VerseFace*)BLI_dlist_find_link(&(vlayer->dl), ((uint32_item*)item)->id );
+ if(vface != NULL)
+ send_verse_face_uint32((uint32_item*)item, type);
+ break;
+ case VERSE_FACE_REAL32: /* parent item has to exist */
+ vnode = (((real32_item*)item)->vlayer)->vnode;
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 1 );
+ vface = (VerseFace*)BLI_dlist_find_link(&(vlayer->dl), ((real32_item*)item)->id );
+ if(vface != NULL)
+ send_verse_face_real32((real32_item*)item, type);
+ break;
+ case VERSE_FACE_QUAT_UINT32: /* parent item has to exist */
+ vnode = (((quat_uint32_item*)item)->vlayer)->vnode;
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 1 );
+ vface = (VerseFace*)BLI_dlist_find_link(&(vlayer->dl), ((quat_uint32_item*)item)->id );
+ if(vface != NULL)
+ send_verse_face_corner_quat_uint32((quat_uint32_item*)item, type);
+ break;
+ case VERSE_FACE_QUAT_REAL32: /* parent item has to exist */
+ vnode = (((quat_real32_item*)item)->vlayer)->vnode;
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), 1 );
+ vface = (VerseFace*)BLI_dlist_find_link(&(vlayer->dl), ((quat_real32_item*)item)->id );
+ if(vface != NULL)
+ send_verse_face_corner_quat_real32((quat_real32_item*)item, type);
+ break;
+ }
+}
+
+/*
+ * return VerseLayer with certain content (vertexes, polygons, in the
+ * future: weight, red color, etc.)
+ */
+VLayer* find_verse_layer_type(VGeomData *geom, short content)
+{
+ struct VLayer *vlayer = NULL;
+
+ switch(content) {
+ case VERTEX_LAYER:
+ /* VERTEX_LAYER equals 0 and vertex layer is
+ * always in 1st layer */
+ vlayer = geom->layers.da.items[VERTEX_LAYER];
+ break;
+ case POLYGON_LAYER:
+ /* POLYGON_LAYER equals 1 and vertex layer is
+ * always in 2nd layer */
+ vlayer = geom->layers.da.items[POLYGON_LAYER];
+ break;
+ }
+
+ return vlayer;
+}
+
+/*
+ * increase references of VerseVerts of new VerseFace
+ */
+static void increase_verse_verts_references(VerseFace *vface)
+{
+ if(vface->vvert0) vface->vvert0->counter++;
+ if(vface->vvert1) vface->vvert1->counter++;
+ if(vface->vvert2) vface->vvert2->counter++;
+ if(vface->vvert3) vface->vvert3->counter++;
+}
+
+/*
+ * move VerseFace from list of orphans to dlist of VerseFaces (if VerseFace was only changed
+ * then this VerseFace is only removed from list of orphans)
+ */
+static void move_face_orphan_to_dlist(VNode *vnode, VLayer *vlayer, VerseFace *vface)
+{
+ /* remove vface from list of orphans */
+ BLI_remlink(&(vlayer->orphans), vface);
+ /* increase references of all vertexes beying part of this face*/
+ increase_verse_verts_references(vface);
+
+ if(vface->flag & FACE_RECEIVED) {
+ /* set up vface flag */
+ vface->flag &= ~FACE_RECEIVED;
+ /* move vface to dynamic list of faces */
+ BLI_dlist_add_item_index(&(vlayer->dl), (void*)vface, vface->id);
+ /* recalculate all vertex and faces normals */
+ recalculate_verseface_normals(vnode);
+ /* post create action (change local data) */
+ ((VGeomData*)vnode->data)->post_polygon_create(vface);
+ }
+ else if(vface->flag & FACE_CHANGED) {
+ /* set up vface flag */
+ vface->flag &= ~FACE_CHANGED;
+ /* move vface to dynamic list of faces */
+ BLI_dlist_add_item_index(&(vlayer->dl), (void*)vface, vface->id);
+ /* recalculate all vertex and faces normals */
+ recalculate_verseface_normals(vnode);
+ /* post create action (change local data) */
+ ((VGeomData*)vnode->data)->post_polygon_set_corner(vface);
+ }
+}
+
+/*
+ * find all VerseFaces waiting in queue, which needs id of new VerseVert
+ */
+static void find_unsent_faces(VNode *vnode, VerseVert *vvert)
+{
+ VLayer *vlayer;
+ VerseFace *vface, *next_vface;
+
+ vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER);
+
+ if(vlayer) {
+ vface = vlayer->queue.first;
+ while(vface) {
+ next_vface = vface->next;
+ if(vface->vvert0==vvert) {
+ vface->v0 = vvert->id;
+ vface->counter--;
+ }
+ else if(vface->vvert1==vvert) {
+ vface->v1 = vvert->id;
+ vface->counter--;
+ }
+ else if(vface->vvert2==vvert) {
+ vface->v2 = vvert->id;
+ vface->counter--;
+ }
+ else if(vface->vvert3==vvert){
+ vface->v3 = vvert->id;
+ vface->counter--;
+ }
+
+ if(vface->counter<1 && !(vface->flag & FACE_SENT))
+ send_verse_face(vface);
+
+ vface = next_vface;
+ }
+ }
+}
+
+/*
+ * find all VerseFace orphans, which needs incoming VerseVert
+ */
+static void find_vlayer_orphans(VNode *vnode, VerseVert *vvert)
+{
+ VLayer *vlayer;
+ VerseFace *vface, *next_vface;
+ unsigned int vertex_id = vvert->id;
+
+ vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER);
+
+ if(vlayer) {
+ vface = vlayer->orphans.first;
+ while(vface){
+ next_vface = vface->next;
+ if(vface->v0 == vertex_id) {
+ vface->vvert0 = vvert;
+ vface->counter--;
+ }
+ else if(vface->v1 == vertex_id) {
+ vface->vvert1 = vvert;
+ vface->counter--;
+ }
+ else if(vface->v2 == vertex_id) {
+ vface->vvert2 = vvert;
+ vface->counter--;
+ }
+ else if(vface->v3 == vertex_id) {
+ vface->vvert3 = vvert;
+ vface->counter--;
+ }
+ if(vface->counter<1) {
+ /* moving VerseFace orphan to dlist */
+ move_face_orphan_to_dlist(vnode, vlayer, vface);
+ }
+ vface = next_vface;
+ }
+ }
+}
+
+/*
+ * return number of VerseVerts missing to incoming VerseFace, set up pointers
+ * at VerseVerts
+ */
+static unsigned short test_incoming_verseface(VGeomData *geom, VerseFace *vface)
+{
+ struct VLayer *vert_layer;
+ struct VerseVert *vvert;
+ int counter=0;
+
+ vert_layer = find_verse_layer_type(geom, VERTEX_LAYER);
+
+ if(vface->v0 != -1){
+ vvert = BLI_dlist_find_link(&(vert_layer->dl), vface->v0);
+ if(vvert==NULL) counter++;
+ else vface->vvert0 = vvert;
+ }
+ if(vface->v1 != -1){
+ vvert = BLI_dlist_find_link(&(vert_layer->dl), vface->v1);
+ if(vvert==NULL) counter++;
+ else vface->vvert1 = vvert;
+ }
+ if(vface->v2 != -1){
+ vvert = BLI_dlist_find_link(&(vert_layer->dl), vface->v2);
+ if(vvert==NULL) counter++;
+ else vface->vvert2 = vvert;
+ }
+ if(vface->v3 != -1){
+ vvert = BLI_dlist_find_link(&(vert_layer->dl), vface->v3);
+ if(vvert==NULL) counter++;
+ else vface->vvert3 = vvert;
+ }
+
+ return counter;
+}
+
+/*
+ * try to find changed VerseFace in sending queue
+ */
+static VerseFace* find_changed_verse_face_in_queue(VLayer *vlayer, uint32 polygon_id)
+{
+ struct VerseFace *vface = vlayer->queue.first;
+
+ while(vface){
+ if(vface->id == polygon_id && vface->flag & FACE_CHANGED) {
+ return vface;
+ }
+ vface = vface->next;
+ }
+ return NULL;
+}
+
+/*
+ * try to find VerseFace in queue
+ */
+static VerseFace* find_verse_face_in_queue(
+ VLayer *vlayer,
+ VNodeID node_id,
+ uint32 polygon_id,
+ uint32 v0,
+ uint32 v1,
+ uint32 v2,
+ uint32 v3)
+{
+ struct VerseFace *vface = vlayer->queue.first;
+
+ while(vface){
+ if((vface->v0==v0) && (vface->v1==v1) && (vface->v2==v2) && (vface->v3==v3)){
+ vface->id = polygon_id;
+ vface->vlayer = vlayer;
+ return vface;
+ }
+ vface = vface->next;
+ }
+ return NULL;
+}
+
+/*
+ * try to find VerseVert in queue
+ */
+static VerseVert* find_verse_vert_in_queue(
+ VLayer *vlayer,
+ VNodeID node_id,
+ uint32 vertex_id,
+ real32 x,
+ real32 y,
+ real32 z)
+{
+ struct VerseVert *vvert = vlayer->queue.first;
+
+ while(vvert){
+ if((vvert->vlayer->vnode->id == node_id) && (vvert->co[0] == x) && (vvert->co[1] == y) && (vvert->co[2] == z))
+ {
+ vvert->id = vertex_id;
+ vvert->vlayer = vlayer;
+
+ return vvert;
+ }
+ vvert = vvert->next;
+ }
+
+ return NULL;
+}
+
+
+/*
+ * send quat of float values to verse server (4x32 bits)
+ */
+void send_verse_face_corner_quat_real32(quat_real32_item *item, short type)
+{
+ verse_send_g_polygon_set_corner_real32(
+ item->vlayer->vnode->id,
+ item->vlayer->id,
+ item->id,
+ item->value[0],
+ item->value[1],
+ item->value[2],
+ item->value[3]);
+}
+
+/*
+ * send quat of unsigned int values to verse server (4x32 bits)
+ */
+void send_verse_face_corner_quat_uint32(quat_uint32_item *item, short type)
+{
+ verse_send_g_polygon_set_corner_uint32(
+ item->vlayer->vnode->id,
+ item->vlayer->id,
+ item->id,
+ item->value[0],
+ item->value[1],
+ item->value[2],
+ item->value[3]);
+}
+
+/*
+ * send float value (32 bits) to verse server
+ */
+void send_verse_face_real32(real32_item *item, short type)
+{
+ verse_send_g_polygon_set_face_real32(
+ item->vlayer->vnode->id,
+ item->vlayer->id,
+ item->id,
+ item->value);
+}
+
+/*
+ * send unsigned integer (32 bits) to verse server
+ */
+void send_verse_face_uint32(uint32_item *item, short type)
+{
+ verse_send_g_polygon_set_face_uint32(
+ item->vlayer->vnode->id,
+ item->vlayer->id,
+ item->id,
+ item->value);
+}
+
+/*
+ * send unsigned char (8 bits) to verse server
+ */
+void send_verse_face_uint8(uint8_item *item, short type)
+{
+ verse_send_g_polygon_set_face_uint8(
+ item->vlayer->vnode->id,
+ item->vlayer->id,
+ item->id,
+ item->value);
+}
+
+/*
+ * send vector of float values to verse server (3x32 bits)
+ */
+void send_verse_vert_vec_real32(vec_real32_item *item, short type)
+{
+ verse_send_g_vertex_set_xyz_real32(
+ item->vlayer->vnode->id,
+ item->vlayer->id,
+ item->id,
+ item->value[0],
+ item->value[1],
+ item->value[2]);
+}
+
+/*
+ * send float value (32 bits) to verse server
+ */
+void send_verse_vert_real32(real32_item *item, short type)
+{
+ verse_send_g_vertex_set_real32(
+ item->vlayer->vnode->id,
+ item->vlayer->id,
+ item->id,
+ item->value);
+}
+
+/*
+ * send unsigned integer (32 bits) to verse server
+ */
+void send_verse_vert_uint32(uint32_item *item, short type)
+{
+ verse_send_g_vertex_set_uint32(
+ item->vlayer->vnode->id,
+ item->vlayer->id,
+ item->id,
+ item->value);
+}
+
+/*
+ * send delete command to verse server
+ */
+void send_verse_vertex_delete(VerseVert *vvert)
+{
+ verse_session_set(vvert->vlayer->vnode->session->vsession);
+
+ vvert->flag |= VERT_OBSOLETE;
+
+ verse_send_g_vertex_delete_real32(vvert->vlayer->vnode->id, vvert->id);
+}
+
+/*
+ * send VerseLayer to verse server
+ */
+void send_verse_layer(VLayer *vlayer)
+{
+ verse_session_set(vlayer->vnode->session->vsession);
+
+ verse_send_g_layer_create(
+ vlayer->vnode->id,
+ vlayer->id,
+ vlayer->name,
+ vlayer->type,
+ vlayer->def_int,
+ vlayer->def_real);
+}
+
+/*
+ * send VerseVert to verse server
+ */
+void send_verse_vertex(VerseVert *vvert)
+{
+ /* new vertex position will not be sent, when vertex was deleted */
+ if(vvert->flag & VERT_OBSOLETE) return;
+
+ verse_session_set(vvert->vlayer->vnode->session->vsession);
+
+ verse_send_g_vertex_set_xyz_real32(
+ vvert->vlayer->vnode->id,
+ vvert->vlayer->id,
+ vvert->id,
+ vvert->co[0],
+ vvert->co[2],
+ -vvert->co[1]);
+}
+
+/*
+ * send delete command to verse server
+ */
+void send_verse_face_delete(VerseFace *vface)
+{
+ verse_session_set(vface->vlayer->vnode->session->vsession);
+
+ vface->flag |= FACE_DELETED;
+
+ verse_send_g_polygon_delete(vface->vlayer->vnode->id, vface->id);
+}
+
+/*
+ * send VerseFace to verse server
+ */
+static void send_verse_face(VerseFace *vface)
+{
+ verse_session_set(vface->vlayer->vnode->session->vsession);
+
+ vface->flag |= FACE_SENT;
+
+ if(vface->v3 != -1) {
+ verse_send_g_polygon_set_corner_uint32(
+ vface->vlayer->vnode->id,
+ vface->vlayer->id,
+ vface->id,
+ vface->v0,
+ vface->v3, /* verse use clock-wise winding */
+ vface->v2,
+ vface->v1); /* verse use clock-wise winding */
+ }
+ else {
+ verse_send_g_polygon_set_corner_uint32(
+ vface->vlayer->vnode->id,
+ vface->vlayer->id,
+ vface->id,
+ vface->v0,
+ vface->v2, /* verse use clock-wise winding */
+ vface->v1, /* verse use clock-wise winding */
+ vface->v3);
+ }
+}
+
+/*
+ * free VerseVert
+ */
+static void free_verse_vertex(VLayer *vlayer, VerseVert *vvert)
+{
+ /* free VerseVert */
+ BLI_freelinkN(&(vlayer->orphans), vvert);
+}
+
+/*
+ * free VerseFace (and blender face)
+ */
+static void free_verse_face(VLayer *vlayer, VerseFace *vface)
+{
+ /* free VerseFace */
+ BLI_dlist_free_item(&(vlayer->dl), (unsigned int)vface->id);
+}
+
+/*
+ * free VerseLayer data
+ */
+static void free_verse_layer_data(VNode *vnode, VLayer *vlayer)
+{
+ struct VerseFace *vface;
+ struct VerseVert *vvert;
+
+ /* set up EditVert->vvert and EditFace->vface pointers to NULL */
+ switch(vlayer->content) {
+ case VERTEX_LAYER:
+ vvert = (VerseVert*)vlayer->dl.lb.first;
+ while(vvert) {
+ ((VGeomData*)vnode->data)->post_vertex_free_constraint(vvert);
+ vvert = vvert->next;
+ }
+ break;
+ case POLYGON_LAYER:
+ vface = (VerseFace*)vlayer->dl.lb.first;
+ while(vface) {
+ ((VGeomData*)vnode->data)->post_polygon_free_constraint(vface);
+ vface = vface->next;
+ }
+ break;
+ default:
+ break;
+ }
+ /* free Verse Layer name */
+ MEM_freeN(vlayer->name);
+ /* destroy VerseLayer data (vertexes, polygons, etc.) */
+ BLI_dlist_destroy(&(vlayer->dl));
+ /* free unsent data */
+ BLI_freelistN(&(vlayer->queue));
+ /* free orphans */
+ BLI_freelistN(&(vlayer->orphans));
+}
+
+/*
+ * free all unneeded VerseVerts waiting for deleting
+ */
+static void free_unneeded_verseverts_of_verseface(VNode *vnode, VerseFace *vface)
+{
+ struct VLayer *vert_vlayer;
+
+ /* find layer containing vertexes */
+ vert_vlayer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER);
+
+ /* free all "deleted" VerseVert waiting for deleting this VerseFace */
+
+ if((vface->vvert0->counter < 1) && (vface->vvert0->flag & VERT_DELETED)) {
+ ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert0);
+ free_verse_vertex(vert_vlayer, vface->vvert0);
+ vface->vvert0 = NULL;
+ }
+ if((vface->vvert1->counter < 1) && (vface->vvert1->flag & VERT_DELETED)) {
+ ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert1);
+ free_verse_vertex(vert_vlayer, vface->vvert1);
+ vface->vvert1 = NULL;
+ }
+ if((vface->vvert2->counter < 1) && (vface->vvert2->flag & VERT_DELETED)) {
+ ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert2);
+ free_verse_vertex(vert_vlayer, vface->vvert2);
+ vface->vvert2 = NULL;
+ }
+ if((vface->vvert3) && (vface->vvert3->counter < 1) && (vface->vvert3->flag & VERT_DELETED)) {
+ ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert3);
+ free_verse_vertex(vert_vlayer, vface->vvert3);
+ vface->vvert3 = NULL;
+ }
+}
+
+/*
+ * This function create VerseVert and returns pointer on this vertex
+ */
+VerseVert* create_verse_vertex(
+ VLayer *vlayer,
+ uint32 vertex_id,
+ real32 x,
+ real32 y,
+ real32 z)
+{
+ struct VerseVert *vvert;
+
+ vvert = (VerseVert*)MEM_mallocN(sizeof(VerseVert), "VerseVert");
+
+ /* set up pointer on parent node */
+ vvert->vlayer = vlayer;
+ vvert->id = vertex_id;
+ /* position */
+ vvert->co[0] = x;
+ vvert->co[1] = y;
+ vvert->co[2] = z;
+ /* normal */
+ vvert->no[0] = vvert->no[1] = vvert->no[2] = 0.0;
+ /* blender internals */
+ vvert->flag = 0;
+ vvert->counter = 0;
+ vvert->vertex = NULL;
+
+ /* increase layer counter of vertexes */
+ vlayer->counter++;
+
+ return vvert;
+}
+
+/*
+ * this function creates fake VerseEdge and returns pointer at this edge
+ */
+VerseEdge *create_verse_edge(uint32 v0, uint32 v1)
+{
+ struct VerseEdge *vedge;
+
+ vedge = (VerseEdge*)MEM_mallocN(sizeof(VerseEdge), "VerseEdge");
+
+ vedge->v0 = v0;
+ vedge->v1 = v1;
+ vedge->counter = 0;
+
+ return vedge;
+}
+
+/*
+ * this function will create new VerseFace and will return pointer on such Face
+ */
+VerseFace* create_verse_face(
+ VLayer *vlayer,
+ uint32 polygon_id,
+ uint32 v0,
+ uint32 v1,
+ uint32 v2,
+ uint32 v3)
+{
+ struct VerseFace *vface;
+
+ vface = (VerseFace*)MEM_mallocN(sizeof(VerseFace), "VerseFace");
+
+ /* verse data */
+ vface->vlayer = vlayer;
+ vface->id = polygon_id;
+
+ vface->vvert0 = NULL;
+ vface->vvert1 = NULL;
+ vface->vvert2 = NULL;
+ vface->vvert3 = NULL;
+
+ vface->v0 = v0;
+ vface->v1 = v1;
+ vface->v2 = v2;
+ vface->v3 = v3;
+
+ /* blender data */
+ vface->face = NULL;
+ vface->flag = 0;
+ vface->counter = 4;
+
+ /* increase layer counter of faces */
+ vlayer->counter++;
+
+ return vface;
+}
+
+/*
+ * create and return VerseLayer
+ */
+VLayer *create_verse_layer(
+ VNode *vnode,
+ VLayerID layer_id,
+ const char *name,
+ VNGLayerType type,
+ uint32 def_integer,
+ real64 def_real)
+{
+ struct VLayer *vlayer;
+
+ /* add layer to the DynamicList */
+ vlayer = (VLayer*)MEM_mallocN(sizeof(VLayer), "VerseLayer");
+
+ /* store all relevant info to the vlayer and set up vlayer */
+ vlayer->vnode = vnode;
+ vlayer->id = layer_id;
+ vlayer->name = (char*)MEM_mallocN(sizeof(char)*(sizeof(name)+1),"Verse Layer name");
+ strcpy(vlayer->name, name);
+ vlayer->type = type;
+ vlayer->def_int = def_integer;
+ vlayer->def_real = def_real;
+
+ if((type == VN_G_LAYER_VERTEX_XYZ) && (layer_id == 0))
+ vlayer->content = VERTEX_LAYER;
+ else if((type == VN_G_LAYER_POLYGON_CORNER_UINT32) && (layer_id == 1))
+ vlayer->content = POLYGON_LAYER;
+ else
+ vlayer->content = -1;
+
+ /* initialize DynamicList in the vlayer (vertexes, polygons, etc.)*/
+ BLI_dlist_init(&(vlayer->dl));
+ /* initialization of queue of layer */
+ vlayer->queue.first = vlayer->queue.last = NULL;
+ /* initialization of list of orphans */
+ vlayer->orphans.first = vlayer->orphans.last = NULL;
+ /* initialize number of sent items (vertexes, faces, etc) */
+ vlayer->counter = 0;
+ /* initialize flag */
+ vlayer->flag = 0;
+
+ /* set up methods */
+ vlayer->post_layer_create = post_layer_create;
+ vlayer->post_layer_destroy = post_layer_destroy;
+
+ return vlayer;
+}
+
+/*
+ * create geometry data
+ */
+VGeomData *create_geometry_data(void)
+{
+ struct VGeomData *geom;
+
+ geom = (VGeomData*)MEM_mallocN(sizeof(VGeomData), "VerseGeometryData");
+ BLI_dlist_init(&(geom->layers));
+ geom->vlink = NULL;
+ geom->queue.first = geom->queue.last = NULL;
+ geom->mesh = NULL;
+ geom->editmesh = NULL;
+
+ /* initialize list of fake verse edges and initialize verse edge hash */
+ geom->edges.first = geom->edges.last = NULL;
+ geom->hash = MEM_callocN(VEDHASHSIZE*sizeof(HashVerseEdge), "verse hashedge tab");
+
+ /* set up methods */
+ geom->post_vertex_create = post_vertex_create;
+ geom->post_vertex_set_xyz = post_vertex_set_xyz;
+ geom->post_vertex_delete = post_vertex_delete;
+ geom->post_vertex_free_constraint = post_vertex_free_constraint;
+ geom->post_polygon_create = post_polygon_create;
+ geom->post_polygon_set_corner = post_polygon_set_corner;
+ geom->post_polygon_delete = post_polygon_delete;
+ geom->post_polygon_free_constraint = post_polygon_free_constraint;
+ geom->post_geometry_free_constraint = post_geometry_free_constraint;
+ geom->post_polygon_set_uint8 = post_polygon_set_uint8;
+
+ return geom;
+}
+
+/* Create item containing 4 floats */
+static quat_real32_item *create_quat_real32_item(
+ VLayer *vlayer,
+ uint32 item_id,
+ real32 v0,
+ real32 v1,
+ real32 v2,
+ real32 v3)
+{
+ struct quat_real32_item *item;
+
+ item = (quat_real32_item*)MEM_mallocN(sizeof(quat_real32_item), "quat_real32_item");
+
+ item->vlayer = vlayer;
+ item->id = item_id;
+ item->value[0] = v0;
+ item->value[1] = v1;
+ item->value[2] = v2;
+ item->value[3] = v3;
+
+ return item;
+}
+
+/* Create item containing 1 float */
+static real32_item *create_real32_item(VLayer *vlayer, uint32 item_id, real32 value)
+{
+ struct real32_item *item;
+
+ item = (real32_item*)MEM_mallocN(sizeof(real32_item), "real32_item");
+
+ item->vlayer = vlayer;
+ item->id = item_id;
+ item->value = value;
+
+ return item;
+}
+
+/* Create item containing 1 integer */
+static uint32_item *create_uint32_item(VLayer *vlayer, uint32 item_id, uint32 value)
+{
+ struct uint32_item *item;
+
+ item = (uint32_item*)MEM_mallocN(sizeof(uint32_item), "uint32_item");
+
+ item->vlayer = vlayer;
+ item->id = item_id;
+ item->value = value;
+
+ return item;
+}
+
+/* Create item containing 1 byte */
+static uint8_item *create_uint8_item(VLayer *vlayer, uint32 item_id, uint8 value)
+{
+ struct uint8_item *item;
+
+ item = (uint8_item*)MEM_mallocN(sizeof(uint8_item), "uint8_item");
+
+ item->vlayer = vlayer;
+ item->id = item_id;
+ item->value = value;
+
+ return item;
+}
+
+/*
+ * callback function: vertex crease was set
+ */
+static void cb_g_crease_set_vertex(
+ void *user_data,
+ VNodeID node_id,
+ const char *layer,
+ uint32 def_crease)
+{
+}
+
+/*
+ * we have to test corretness of incoming data from verse server
+ * no two vertexes can have the same index
+ */
+static char test_polygon_set_corner_uint32(
+ uint32 v0,
+ uint32 v1,
+ uint32 v2,
+ uint32 v3)
+{
+ if((v0==v1) || (v0==v2) || (v0==v3) || (v1==v2) || (v1==v3) || (v2==v3))
+ return 0;
+ else
+ return 1;
+}
+
+/*
+ * try to find verse layer in sending queue of verse geometry node
+ */
+static VLayer *find_vlayer_in_sending_queue(VNode *vnode, VLayerID layer_id)
+{
+ struct VLayer *vlayer;
+
+ /* try to find verse layyer in sending queue */
+ vlayer = ((VGeomData*)vnode->data)->queue.first;
+ while(vlayer) {
+ if(vlayer->id==layer_id) return vlayer;
+ vlayer = vlayer->next;
+ }
+
+ return NULL;
+}
+
+/*
+ * this function will find edge in hash table, hash function isn't too optimal (it needs
+ * lot of memory for every verse node), but it works without any bug
+ */
+static VerseEdge* find_verse_edge(VNode *vnode, uint32 v0, uint32 v1)
+{
+ struct HashVerseEdge *hve;
+
+ if(((VGeomData*)vnode->data)->hash==NULL)
+ ((VGeomData*)vnode->data)->hash = MEM_callocN(VEDHASHSIZE*sizeof(HashVerseEdge), "verse hashedge tab");
+
+ hve = ((VGeomData*)vnode->data)->hash + VEDHASH(v0, v1);;
+ while(hve) {
+ /* edge v0---v1 is the same edge as v1---v0 */
+ if(hve->vedge && ((hve->vedge->v0==v0 && hve->vedge->v1==v1) || (hve->vedge->v0==v1 && hve->vedge->v1==v0))) return hve->vedge;
+ hve = hve->next;
+ }
+
+ return NULL;
+}
+
+/*
+ * insert hash of verse edge to hash table
+ */
+static void insert_verse_edgehash(VNode *vnode, VerseEdge *vedge)
+{
+ struct HashVerseEdge *first, *hve;
+
+ if(((VGeomData*)vnode->data)->hash==NULL)
+ ((VGeomData*)vnode->data)->hash = MEM_callocN(VEDHASHSIZE*sizeof(HashVerseEdge), "verse hashedge tab");
+
+ first = ((VGeomData*)vnode->data)->hash + VEDHASH(vedge->v0, vedge->v1);
+
+ if(first->vedge==NULL) {
+ first->vedge = vedge;
+ }
+ else {
+ hve = &(vedge->hash);
+ hve->vedge = vedge;
+ hve->next = first->next;
+ first->next = hve;
+ }
+}
+
+/*
+ * remove hash of verse edge from hash table
+ */
+static void remove_verse_edgehash(VNode *vnode, VerseEdge *vedge)
+{
+ struct HashVerseEdge *first, *hve, *prev;
+
+ hve = first = ((VGeomData*)vnode->data)->hash + VEDHASH(vedge->v0, vedge->v1);
+
+ while(hve) {
+ if(hve->vedge == vedge) {
+ if(hve==first) {
+ if(first->next) {
+ hve = first->next;
+ first->vedge = hve->vedge;
+ first->next = hve->next;
+ }
+ else {
+ hve->vedge = NULL;
+ }
+ }
+ else {
+ prev->next = hve->next;
+ }
+ return;
+ }
+ prev = hve;
+ hve = hve->next;
+ }
+}
+
+/*
+ * this function will try to remove existing fake verse edge, when this verse
+ * edge is still used by some faces, then counter will be only decremented
+ */
+static void remove_verse_edge(VNode *vnode, uint32 v0, uint32 v1)
+{
+ struct VerseEdge *vedge;
+
+ vedge = find_verse_edge(vnode, v0, v1);
+ if(vedge) {
+ vedge->counter--;
+ if(vedge->counter==0) {
+ remove_verse_edgehash(vnode, vedge);
+ BLI_freelinkN(&(((VGeomData*)vnode->data)->edges), vedge);
+ }
+ }
+ else {
+ printf("error: remove_verse_edge %d, %d\n", v0, v1);
+ }
+}
+
+/*
+ * this function will try to add new fake verse edge, when no such edge exist,
+ * when such edge exist, then only counter of edge will be incremented
+ */
+static void add_verse_edge(VNode *vnode, uint32 v0, uint32 v1)
+{
+ struct VerseEdge *vedge;
+
+ vedge = find_verse_edge(vnode, v0, v1);
+ if(!vedge) {
+ if(v0!=v1) {
+ vedge = create_verse_edge(v0, v1);
+ BLI_addtail(&(((VGeomData*)vnode->data)->edges), vedge);
+ insert_verse_edgehash(vnode, vedge);
+ }
+ else {
+ printf("error:add_verse_edge: %d, %d\n", v0, v1);
+ return;
+ }
+ }
+ vedge->counter++;
+}
+
+/*
+ * verse face was deleted ... update edge hash
+ */
+static void update_edgehash_of_deleted_verseface(VNode *vnode, VerseFace *vface)
+{
+ uint32 v0, v1, v2, v3; /* verse vertex indexes of deleted verse face */
+
+ v0 = vface->vvert0->id;
+ v1 = vface->vvert1->id;
+ v2 = vface->vvert2->id;
+ v3 = vface->vvert3 ? vface->vvert3->id : -1;
+
+ remove_verse_edge(vnode, v0, v1);
+ remove_verse_edge(vnode, v1, v2);
+ if(v3!=-1) {
+ remove_verse_edge(vnode, v2, v3);
+ remove_verse_edge(vnode, v3, v0);
+ }
+ else {
+ remove_verse_edge(vnode, v2, v0);
+ }
+}
+
+/*
+ * existing verse face was changed ... update edge hash
+ */
+static void update_edgehash_of_changed_verseface(
+ VNode *vnode,
+ VerseFace *vface,
+ uint32 v0,
+ uint32 v1,
+ uint32 v2,
+ uint32 v3)
+{
+ uint32 ov0, ov1, ov2, ov3; /* old indexes at verse vertexes*/
+
+ ov0 = vface->vvert0->id;
+ ov1 = vface->vvert1->id;
+ ov2 = vface->vvert2->id;
+ ov3 = vface->vvert3 ? vface->vvert3->id : -1;
+
+ /* 1st edge */
+ if(v0!=ov0 || v1!=ov1) {
+ remove_verse_edge(vnode, ov0, ov1);
+ add_verse_edge(vnode, v0, v1);
+ }
+
+ /* 2nd edge */
+ if(v1!=ov1 || v2!=ov2) {
+ remove_verse_edge(vnode, ov1, ov2);
+ add_verse_edge(vnode, v1, v2);
+ }
+
+ /* 3rd edge */
+ if(v2!=ov2 || v3!=ov3 || v0!=ov0) {
+ if(ov3!=-1) {
+ remove_verse_edge(vnode, ov2, ov3);
+ if(v3!=-1) {
+ add_verse_edge(vnode, v2, v3); /* new 3rd edge (quat->quat) */
+ }
+ else {
+ remove_verse_edge(vnode, ov3, ov0); /* old edge v3,v0 of quat have to be removed */
+ add_verse_edge(vnode, v2, v0); /* new 3rd edge (quat->triangle) */
+ }
+ }
+ else {
+ remove_verse_edge(vnode, ov2, ov0);
+ if(v3!=-1) {
+ add_verse_edge(vnode, v2, v3); /* new 3rd edge (triangle->quat) */
+ }
+ else {
+ add_verse_edge(vnode, v2, v0); /* new 3rd edge (triangle->triangle) */
+ }
+ }
+ }
+
+ /* 4th edge */
+ if(v3!=-1 && (v3!=ov3 || v0!=ov0)) {
+ remove_verse_edge(vnode, ov3, ov0);
+ add_verse_edge(vnode, v3, v0);
+ }
+}
+
+/*
+ * new verse face was created ... update list of edges and edge has
+ */
+static void update_edgehash_of_new_verseface(
+ VNode *vnode,
+ uint32 v0,
+ uint32 v1,
+ uint32 v2,
+ uint32 v3)
+{
+ /* when edge already exists, then only its counter is incremented,
+ * look at commentary of add_verse_edge() function */
+ add_verse_edge(vnode, v0, v1);
+ add_verse_edge(vnode, v1, v2);
+ if(v3!=-1) {
+ add_verse_edge(vnode, v2, v3);
+ add_verse_edge(vnode, v3, v0);
+ }
+ else {
+ add_verse_edge(vnode, v2, v0);
+ }
+}
+
+/*
+ * callback function: edge crease was set
+ */
+static void cb_g_crease_set_edge(
+ void *user_data,
+ VNodeID node_id,
+ const char *layer,
+ uint32 def_crease)
+{
+}
+
+/*
+ * callback function: float value for polygon was set up
+ */
+static void cb_g_polygon_set_face_real32(
+ void *user_def,
+ VNodeID node_id,
+ VLayerID layer_id,
+ uint32 polygon_id,
+ real32 value)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VLayer *vlayer;
+ struct real32_item *item;
+
+ if(!session) return;
+
+ /* find needed node (we can be sure, that it is geometry node) */
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ /* find layer containing uint_8 data */
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id);
+
+ /* try to find item*/
+ item = BLI_dlist_find_link(&(vlayer->dl), polygon_id);
+
+ if(item) {
+ item->value = value;
+ }
+ else {
+ item = create_real32_item(vlayer, polygon_id, value);
+ BLI_dlist_add_item_index(&(vlayer->dl), item, item->id);
+ }
+}
+
+/*
+ * callback function: int values for polygon was set up
+ */
+static void cb_g_polygon_set_face_uint32(
+ void *user_def,
+ VNodeID node_id,
+ VLayerID layer_id,
+ uint32 polygon_id,
+ uint32 value)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VLayer *vlayer;
+ struct uint32_item *item;
+
+ if(!session) return;
+
+ /* find needed node (we can be sure, that it is geometry node) */
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ /* find layer containing uint_8 data */
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id);
+
+ /* try to find item*/
+ item = BLI_dlist_find_link(&(vlayer->dl), polygon_id);
+
+ if(item) {
+ item->value = value;
+ }
+ else {
+ item = create_uint32_item(vlayer, polygon_id, value);
+ BLI_dlist_add_item_index(&(vlayer->dl), item, item->id);
+ }
+}
+
+/*
+ * callback function: uint8 value for polygon was set up
+ */
+static void cb_g_polygon_set_face_uint8(
+ void *user_def,
+ VNodeID node_id,
+ VLayerID layer_id,
+ uint32 polygon_id,
+ uint8 value)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VLayer *vlayer;
+ struct uint8_item *item;
+
+ if(!session) return;
+
+ /* find needed node (we can be sure, that it is geometry node) */
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ /* find layer containing uint_8 data */
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id);
+
+ /* try to find item*/
+ item = BLI_dlist_find_link(&(vlayer->dl), polygon_id);
+
+ if(item) {
+ item->value = value;
+ }
+ else {
+ item = create_uint8_item(vlayer, polygon_id, value);
+ BLI_dlist_add_item_index(&(vlayer->dl), item, item->id);
+ }
+}
+
+/*
+ * callback function: float value for polygon corner was set up
+ */
+static void cb_g_polygon_set_corner_real32(
+ void *user_def,
+ VNodeID node_id,
+ VLayerID layer_id,
+ uint32 polygon_id,
+ real32 v0,
+ real32 v1,
+ real32 v2,
+ real32 v3)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VLayer *vlayer;
+ struct quat_real32_item *item;
+
+ if(!session) return;
+
+ /* find needed node (we can be sure, that it is geometry node) */
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ /* find layer containing uint_8 data */
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id);
+
+ /* try to find item*/
+ item = BLI_dlist_find_link(&(vlayer->dl), polygon_id);
+
+ if(item) {
+ item->value[0] = v0;
+ item->value[1] = v1;
+ item->value[2] = v2;
+ item->value[3] = v3;
+ }
+ else {
+ item = create_quat_real32_item(vlayer, polygon_id, v0, v1, v2, v3);
+ BLI_dlist_add_item_index(&(vlayer->dl), item, item->id);
+ }
+}
+
+/*
+ * callback function: polygon is deleted
+ */
+static void cb_g_polygon_delete(
+ void *user_data,
+ VNodeID node_id,
+ uint32 polygon_id)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ VNode *vnode;
+ VLayer *vlayer;
+ VerseFace *vface;
+
+ if(!session) return;
+
+ /* find needed node (we can be sure, that it is geometry node) */
+ vnode = BLI_dlist_find_link(&(session->nodes), node_id);
+
+ /* find layer containing faces */
+ vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER);
+
+ /* find wanted VerseFace */
+ vface = BLI_dlist_find_link(&(vlayer->dl), polygon_id);
+
+ if(!vface) return;
+
+ /* update edge hash */
+ update_edgehash_of_deleted_verseface(vnode, vface);
+
+ ((VGeomData*)vnode->data)->post_polygon_delete(vface);
+
+ /* decrease references at coresponding VerseVertexes */
+ vface->vvert0->counter--;
+ vface->vvert1->counter--;
+ vface->vvert2->counter--;
+ if(vface->vvert3) vface->vvert3->counter--;
+
+ /* delete unneeded VerseVertexes */
+ free_unneeded_verseverts_of_verseface(vnode, vface);
+
+ free_verse_face(vlayer, vface);
+}
+
+/*
+ * callback function: new polygon (face) created or existing polygon was changed
+ */
+static void cb_g_polygon_set_corner_uint32(
+ void *user_data,
+ VNodeID node_id,
+ VLayerID layer_id,
+ uint32 polygon_id,
+ uint32 v0,
+ uint32 v1,
+ uint32 v2,
+ uint32 v3)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VLayer *vlayer;
+ struct VerseFace *vface=NULL;
+
+ if(!session) return;
+
+ /* try to find VerseNode */
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ if(!vnode) return;
+
+ /* try to find VerseLayer */
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id);
+ if(!vlayer) return;
+
+ /* we have to test coretness of incoming data */
+ if(!test_polygon_set_corner_uint32(v0, v1, v2, v3)) return;
+
+ /* Blender uses different order of vertexes */
+ if(v3!=-1) { /* quat swap */
+ unsigned int v; v = v1; v1 = v3; v3 = v;
+ }
+ else { /* triangle swap */
+ unsigned int v; v = v1; v1 = v2; v2 = v;
+ }
+
+ /* try to find VerseFace */
+ vface = (VerseFace*)BLI_dlist_find_link(&(vlayer->dl), (unsigned int)polygon_id);
+
+ /* try to find modified VerseFace */
+ if(!vface) {
+ vface = find_changed_verse_face_in_queue(vlayer, polygon_id);
+ if(vface) {
+ BLI_remlink(&(vlayer->queue), (void*)vface);
+ BLI_dlist_add_item_index(&(vlayer->dl), (void*)vface, (unsigned int)polygon_id);
+ }
+ }
+
+ if(!vface) {
+ /* try to find VerseFace in list of VerseVaces created by me and set up polygon and
+ * layer ids */
+ vface = find_verse_face_in_queue(vlayer, node_id, polygon_id, v0, v1, v2, v3);
+
+ /* update edge hash */
+ update_edgehash_of_new_verseface(vnode, v0, v1, v2, v3);
+
+ if(vface){
+ /* I creeated this face ... remove VerseFace from queue */
+ BLI_remlink(&(vlayer->queue), (void*)vface);
+ }
+ else {
+ /* some other client created this face*/
+ vface = create_verse_face(vlayer, polygon_id, v0, v1, v2, v3);
+ }
+
+ vface->flag &= ~FACE_SENT;
+
+ /* return number of missing verse vertexes */
+ vface->counter = test_incoming_verseface((VGeomData*)vnode->data, vface);
+
+ if(vface->counter < 1) {
+ /* when VerseFace received all needed VerseFaces, then it is moved
+ * to list of VerseFaces */
+ BLI_dlist_add_item_index(&(vlayer->dl), (void*)vface, (unsigned int)polygon_id);
+ increase_verse_verts_references(vface);
+ recalculate_verseface_normals(vnode);
+ ((VGeomData*)vnode->data)->post_polygon_create(vface);
+ }
+ else {
+ /* when all needed VerseVertexes weren't received, then VerseFace is moved to
+ * the list of orphans waiting on needed vertexes */
+ vface->flag |= FACE_RECEIVED;
+ BLI_addtail(&(vlayer->orphans), (void*)vface);
+ }
+ }
+ else {
+ VLayer *vert_vlayer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER);
+ /* VerseVertexes of existing VerseFace were changed (VerseFace will use some different
+ * VerseVertexes or it will use them in different order) */
+
+ /* update fake verse edges */
+ update_edgehash_of_changed_verseface(vnode, vface, v0, v1, v2, v3);
+
+ /* initialize count of unreceived vertexes needed for this face */
+ vface->counter = 4;
+
+ /* 1st corner */
+ if(vface->vvert0->id != v0) {
+ /* decrease references of obsolete vertexes*/
+ vface->vvert0->counter--;
+ /* delete this vertex, when it isn't used by any face and it was marked as deleted */
+ if((vface->vvert0->counter < 1) && (vface->vvert0->flag & VERT_DELETED)) {
+ ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert0);
+ free_verse_vertex(vert_vlayer, vface->vvert0);
+ }
+ /* try to set up new pointer at verse vertex */
+ vface->v0 = v0;
+ vface->vvert0 = BLI_dlist_find_link(&(vert_vlayer->dl), vface->v0);
+ if(vface->vvert0) {
+ /* increase references at new vertex */
+ vface->vvert0->counter++;
+ /* decrease count of needed vertex to receive */
+ vface->counter--;
+ }
+
+ }
+ else
+ /* this corner wasn't changed */
+ vface->counter--;
+
+ /* 2nd corner */
+ if(vface->vvert1->id != v1) {
+ vface->vvert1->counter--;
+ if((vface->vvert1->counter < 1) && (vface->vvert1->flag & VERT_DELETED)) {
+ ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert1);
+ free_verse_vertex(vert_vlayer, vface->vvert1);
+ }
+ vface->v1 = v1;
+ vface->vvert1 = BLI_dlist_find_link(&(vert_vlayer->dl), vface->v1);
+ if(vface->vvert1) {
+ vface->vvert1->counter++;
+ vface->counter--;
+ }
+ }
+ else
+ vface->counter--;
+
+ /* 3rd corner */
+ if(vface->vvert2->id != v2) {
+ vface->vvert2->counter--;
+ if((vface->vvert2->counter < 1) && (vface->vvert2->flag & VERT_DELETED)) {
+ ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert2);
+ free_verse_vertex(vert_vlayer, vface->vvert2);
+ }
+ vface->v2 = v2;
+ vface->vvert2 = BLI_dlist_find_link(&(vert_vlayer->dl), vface->v2);
+ if(vface->vvert2) {
+ vface->vvert2->counter++;
+ vface->counter--;
+ }
+ }
+ else
+ vface->counter--;
+
+ /* 4th corner */
+ if(vface->vvert3) {
+ if(vface->vvert3->id != v3) {
+ vface->vvert3->counter--;
+ if((vface->vvert3->counter < 1) && (vface->vvert3->flag & VERT_DELETED)) {
+ ((VGeomData*)vnode->data)->post_vertex_delete(vface->vvert3);
+ free_verse_vertex(vert_vlayer, vface->vvert3);
+ }
+ vface->v3 = v3;
+ if(v3 != -1) {
+ vface->vvert3 = BLI_dlist_find_link(&(vert_vlayer->dl), vface->v3);
+ if(vface->vvert3) {
+ vface->vvert3->counter++;
+ vface->counter--;
+ }
+ }
+ else {
+ /* this is some special case, this face hase now only 3 corners
+ * quat -> triangle */
+ vface->vvert3 = NULL;
+ vface->counter--;
+ }
+ }
+ }
+ else if(v3 != -1)
+ /* this is some special case, 4th corner of this polygon was created
+ * triangle -> quat */
+ vface->v3 = v3;
+ vface->vvert3 = BLI_dlist_find_link(&(vert_vlayer->dl), vface->v3);
+ if(vface->vvert3) {
+ vface->vvert3->counter++;
+ vface->counter--;
+ }
+ else {
+ vface->v3 = -1;
+ vface->counter--;
+ }
+
+ vface->flag &= ~FACE_SENT;
+ vface->flag |= FACE_CHANGED;
+
+ if(vface->counter<1) {
+ vface->flag &= ~FACE_CHANGED;
+ recalculate_verseface_normals(vnode);
+ ((VGeomData*)vnode->data)->post_polygon_set_corner(vface);
+ }
+ else {
+ /* when all needed VerseVertexes weren't received, then VerseFace is added to
+ * the list of orphans waiting on needed vertexes */
+ BLI_dlist_rem_item(&(vlayer->dl), vface->id);
+ BLI_addtail(&(vlayer->orphans), (void*)vface);
+ }
+ }
+}
+
+/*
+ * callback function: float value was set up for VerseVert with vertex_id
+ */
+static void cb_g_vertex_set_real32(
+ void *user_def,
+ VNodeID node_id,
+ VLayerID layer_id,
+ uint32 vertex_id,
+ real32 value)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VLayer *vlayer;
+ struct real32_item *item;
+
+ if(!session) return;
+
+ /* find needed node (we can be sure, that it is geometry node) */
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ /* find layer containing uint_8 data */
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id);
+
+ /* try to find item*/
+ item = BLI_dlist_find_link(&(vlayer->dl), vertex_id);
+
+ if(item) {
+ item->value = value;
+ }
+ else {
+ item = create_real32_item(vlayer, vertex_id, value);
+ BLI_dlist_add_item_index(&(vlayer->dl), item, item->id);
+ }
+}
+
+/*
+ * callback function: int value was set up for VerseVert with vertex_id
+ */
+static void cb_g_vertex_set_uint32(
+ void *user_def,
+ VNodeID node_id,
+ VLayerID layer_id,
+ uint32 vertex_id,
+ uint32 value)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VLayer *vlayer;
+ struct uint32_item *item;
+
+ if(!session) return;
+
+ /* find needed node (we can be sure, that it is geometry node) */
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ /* find layer containing uint_8 data */
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id);
+
+ /* try to find item*/
+ item = BLI_dlist_find_link(&(vlayer->dl), vertex_id);
+
+ if(item) {
+ item->value = value;
+ }
+ else {
+ item = create_uint32_item(vlayer, vertex_id, value);
+ BLI_dlist_add_item_index(&(vlayer->dl), item, item->id);
+ }
+}
+
+/*
+ * callback function: polygon was deleted
+ */
+static void cb_g_vertex_delete_real32(
+ void *user_data,
+ VNodeID node_id,
+ uint32 vertex_id)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ VNode *vnode=NULL;
+ VLayer *vert_vlayer=NULL;
+ VerseVert *vvert=NULL;
+
+ if(!session) return;
+
+ vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ vert_vlayer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER);
+
+ vvert = BLI_dlist_find_link(&(vert_vlayer->dl), (unsigned int)vertex_id);
+
+ if(!vvert) return;
+
+ if(vvert->counter < 1) {
+ ((VGeomData*)vnode->data)->post_vertex_delete(vvert);
+ BLI_dlist_free_item(&(vert_vlayer->dl), (unsigned int)vertex_id);
+ }
+ else {
+ /* some VerseFace(s) still need VerseVert, remove verse vert from
+ * list verse vertexes and put it to list of orphans */
+ vvert->flag |= VERT_DELETED;
+ BLI_dlist_rem_item(&(vert_vlayer->dl), (unsigned int)vertex_id);
+ BLI_addtail(&(vert_vlayer->orphans), vvert);
+ }
+}
+
+/*
+ * callback function: position of one vertex was changed or new vertex was created
+ */
+static void cb_g_vertex_set_xyz_real32(
+ void *user_data,
+ VNodeID node_id,
+ VLayerID layer_id,
+ uint32 vertex_id,
+ real32 x,
+ real32 y,
+ real32 z)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode = NULL;
+ struct VLayer *vlayer = NULL;
+ struct VerseVert *vvert = NULL;
+ real32 tmp;
+
+ if(!session) return;
+
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ if(!vnode)return;
+
+ vlayer = (VLayer*)BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), (unsigned int)layer_id);
+ if(!vlayer) return;
+
+ /* switch axis orientation */
+ tmp = y;
+ y = -z;
+ z = tmp;
+
+ if(vlayer->id == 0) {
+ /* try to pick up verse vert from DynamicList */
+ vvert = (VerseVert*)BLI_dlist_find_link(&(vlayer->dl), (unsigned int)vertex_id);
+
+ if(vvert) {
+ if(vvert->flag & VERT_OBSOLETE) return;
+
+ if (vvert->flag & VERT_LOCKED) {
+ /* this application changed position of this vertex */
+ if((vvert->co[0]==x) && (vvert->co[1]==y) && (vvert->co[2]==z)) {
+ /* unlock vertex position */
+ vvert->flag &= ~VERT_LOCKED;
+ /* call post_vertex_set_xyz only, when position of vertex is
+ * obsolete ... the new vertex position will be sent to
+ * verse server */
+ if (vvert->flag & VERT_POS_OBSOLETE) {
+ ((VGeomData*)vnode->data)->post_vertex_set_xyz(vvert);
+ }
+ }
+ }
+ else {
+ /* somebody else changed position of this vertex*/
+ if((vvert->co[0]!=x) || (vvert->co[1]!=y) || (vvert->co[2]!=z)) {
+ vvert->co[0] = x;
+ vvert->co[1] = y;
+ vvert->co[2] = z;
+ recalculate_verseface_normals(vnode);
+ ((VGeomData*)vnode->data)->post_vertex_set_xyz(vvert);
+ }
+ }
+ }
+ else {
+ /* create new verse vert */
+
+ /* test if we are authors of this vertex :-) */
+ vvert = find_verse_vert_in_queue(vlayer, node_id, vertex_id, x, y, z);
+
+ if(vvert) {
+ /* remove vert from queue */
+ BLI_remlink(&(vlayer->queue), (void*)vvert);
+ /* add vvert to the dynamic list */
+ BLI_dlist_add_item_index(&(vlayer->dl), (void*)vvert, (unsigned int)vertex_id);
+ /* set VerseVert flags */
+ vvert->flag |= VERT_RECEIVED;
+ if(!(vvert->flag & VERT_POS_OBSOLETE))
+ vvert->flag &= ~VERT_LOCKED;
+ /* find VerseFaces orphans */
+ find_vlayer_orphans(vnode, vvert);
+ /* find unsent VerseFaces */
+ find_unsent_faces(vnode, vvert);
+ }
+ else {
+ /* create new VerseVert */
+ vvert = create_verse_vertex(vlayer, vertex_id, x, y, z);
+ /* add VerseVert to list of VerseVerts */
+ BLI_dlist_add_item_index(&(vlayer->dl), (void*)vvert, (unsigned int)vertex_id);
+ /* set VerseVert flags */
+ vvert->flag |= VERT_RECEIVED;
+ /* find VerseFaces orphans */
+ find_vlayer_orphans(vnode, vvert);
+ }
+
+ ((VGeomData*)vnode->data)->post_vertex_create(vvert);
+ }
+ }
+}
+
+/*
+ * callback function for destroyng of verse layer
+ */
+static void cb_g_layer_destroy(
+ void *user_data,
+ VNodeID node_id,
+ VLayerID layer_id)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VLayer *vlayer;
+
+ if(!session) return;
+
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), node_id);
+ if(!vnode) return;
+
+ vlayer = (VLayer*) BLI_dlist_find_link(&(((VGeomData*)vnode->data)->layers), layer_id);
+
+ if(vlayer){
+ /* free VerseLayer data */
+ free_verse_layer_data(vnode, vlayer);
+ /* remove VerseLayer from list of verse layers */
+ BLI_dlist_rem_item(&(((VGeomData*)vnode->data)->layers), layer_id);
+ /* do client dependent actions */
+ vlayer->post_layer_destroy(vlayer);
+ /* free vlayer itself */
+ MEM_freeN(vlayer);
+ }
+
+}
+
+/*
+ * callback function: new layer was created
+ */
+static void cb_g_layer_create(
+ void *user_data,
+ VNodeID node_id,
+ VLayerID layer_id,
+ const char *name,
+ VNGLayerType type,
+ uint32 def_integer,
+ real64 def_real)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode=NULL;
+ struct VLayer *vlayer=NULL;
+
+ if(!session) return;
+
+ /* find node of this layer*/
+ vnode = BLI_dlist_find_link(&(session->nodes), node_id);
+ if(!vnode) return;
+
+ /* when we created this layer, then subscribe to this layer */
+ if(vnode->owner_id == VN_OWNER_MINE || session->flag & VERSE_AUTOSUBSCRIBE)
+ verse_send_g_layer_subscribe(node_id, layer_id, 0);
+
+ /* try to find */
+ if(vnode->owner_id == VN_OWNER_MINE)
+ vlayer = find_vlayer_in_sending_queue(vnode, layer_id);
+
+ if(vlayer) {
+ /* remove vlayer form sending queue add verse layer to list of verse layers */
+ BLI_remlink(&((VGeomData*)vnode->data)->queue, vlayer);
+ BLI_dlist_add_item_index(&((VGeomData*)vnode->data)->layers, (void*)vlayer, (unsigned int)vlayer->id);
+ /* send all not sent vertexes to verse server
+ * other items waiting in sending queue will be automaticaly sent to verse server,
+ * when verse vertexes will be received from verse server */
+ if((vlayer->type == VN_G_LAYER_VERTEX_XYZ) && (layer_id==0)) {
+ struct VerseVert *vvert = (VerseVert*)vlayer->queue.first;
+ while(vvert) {
+ send_verse_vertex(vvert);
+ vvert = vvert->next;
+ }
+ }
+ }
+ else {
+ /* create new VerseLayer */
+ vlayer = create_verse_layer(vnode, layer_id, name, type, def_integer, def_real);
+ /* add layer to the list of VerseLayers */
+ BLI_dlist_add_item_index(&(((VGeomData*)vnode->data)->layers), (void*)vlayer, (unsigned int)layer_id);
+ }
+
+ vlayer->flag |= LAYER_RECEIVED;
+
+ /* post callback function */
+ vlayer->post_layer_create(vlayer);
+}
+
+/*
+ * this function will send destroy commands for all VerseVertexes and
+ * VerseFaces to verse server, but it will not send destroy commands
+ * for VerseLayers or geometry node, it can be used in other functions
+ * (undo, destroy geom node, some edit mesh commands, ... ), parameter of
+ * this function has to be geometry verse node
+ */
+void destroy_geometry(VNode *vnode)
+{
+ struct VLayer *vert_vlayer, *face_vlayer;
+ struct VerseFace *vface;
+ struct VerseVert *vvert;
+
+ if(vnode->type != V_NT_GEOMETRY) return;
+
+ face_vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER);
+ vface = face_vlayer->dl.lb.first;
+
+ while(vface) {
+ send_verse_face_delete(vface);
+ vface = vface->next;
+ }
+
+ vert_vlayer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER);
+ vvert = vert_vlayer->dl.lb.first;
+
+ while(vvert) {
+ send_verse_vertex_delete(vvert);
+ vvert = vvert->next;
+ }
+
+ /* own destruction of local verse date will be executed, when client will
+ * receive apropriate callback commands from verse server */
+}
+
+/*
+ * free VGeomData
+ */
+void free_geom_data(VNode *vnode)
+{
+ struct VerseSession *session = vnode->session;
+ struct VLayer *vlayer;
+
+ if(vnode->data){
+ vlayer = (VLayer*)((VGeomData*)vnode->data)->layers.lb.first;
+ while(vlayer){
+ /* unsubscribe from layer */
+ if(session->flag & VERSE_CONNECTED)
+ verse_send_g_layer_unsubscribe(vnode->id, vlayer->id);
+ /* free VerseLayer data */
+ free_verse_layer_data(vnode, vlayer);
+ /* next layer */
+ vlayer = vlayer->next;
+ }
+ /* free constraint between vnode and mesh */
+ ((VGeomData*)vnode->data)->post_geometry_free_constraint(vnode);
+ /* free all VerseLayers */
+ BLI_dlist_destroy(&(((VGeomData*)vnode->data)->layers));
+ /* free fake verse edges */
+ BLI_freelistN(&((VGeomData*)vnode->data)->edges);
+ /* free edge hash */
+ MEM_freeN(((VGeomData*)vnode->data)->hash);
+ }
+}
+
+void set_geometry_callbacks(void)
+{
+ /* new layer created */
+ verse_callback_set(verse_send_g_layer_create, cb_g_layer_create, NULL);
+ /* layer was destroyed */
+ verse_callback_set(verse_send_g_layer_destroy, cb_g_layer_destroy, NULL);
+
+ /* position of vertex was changed */
+ verse_callback_set(verse_send_g_vertex_set_xyz_real32, cb_g_vertex_set_xyz_real32, NULL);
+ /* vertex was deleted */
+ verse_callback_set(verse_send_g_vertex_delete_real32, cb_g_vertex_delete_real32, NULL);
+
+ /* callback functions for values being associated with vertexes */
+ verse_callback_set(verse_send_g_vertex_set_uint32, cb_g_vertex_set_uint32, NULL);
+ verse_callback_set(verse_send_g_vertex_set_real32, cb_g_vertex_set_real32, NULL);
+
+ /* new polygon was created / vertex(es) of polygon was set */
+ verse_callback_set(verse_send_g_polygon_set_corner_uint32, cb_g_polygon_set_corner_uint32, NULL);
+ /* polygon was deleted */
+ verse_callback_set(verse_send_g_polygon_delete, cb_g_polygon_delete, NULL);
+
+ /* callback functions for values being associated with polygon corners */
+ verse_callback_set(verse_send_g_polygon_set_corner_real32, cb_g_polygon_set_corner_real32, NULL);
+ /* callback functions for values being associated with faces */
+ verse_callback_set(verse_send_g_polygon_set_face_uint8, cb_g_polygon_set_face_uint8, NULL);
+ verse_callback_set(verse_send_g_polygon_set_face_uint32, cb_g_polygon_set_face_uint32, NULL);
+ verse_callback_set(verse_send_g_polygon_set_face_real32, cb_g_polygon_set_face_real32, NULL);
+
+ /* crease of vertex was set */
+ verse_callback_set(verse_send_g_crease_set_vertex, cb_g_crease_set_vertex, NULL);
+ /* crease of edge was set */
+ verse_callback_set(verse_send_g_crease_set_edge, cb_g_crease_set_edge, NULL);
+}
+
+#endif
diff --git a/source/blender/blenkernel/intern/verse_method.c b/source/blender/blenkernel/intern/verse_method.c
new file mode 100644
index 00000000000..89b5282acfd
--- /dev/null
+++ b/source/blender/blenkernel/intern/verse_method.c
@@ -0,0 +1,523 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributor(s): Nathan Letwory.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifdef WITH_VERSE
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+#include "DNA_userdef_types.h"
+#include "DNA_text_types.h"
+
+#include "BLI_dynamiclist.h"
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "BIF_verse.h"
+
+#include "BKE_bad_level_calls.h"
+#include "BKE_library.h"
+#include "BKE_text.h"
+#include "BKE_verse.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+
+#include "verse.h"
+
+/* helper struct for creating method descriptions */
+typedef struct VMethodInfo {
+ const char *name;
+ uint8 param_count;
+ const VNOParamType param_type[4];
+ const char *param_name[4];
+ uint16 id;
+} VMethodInfo;
+
+#ifdef VERSECHAT
+/* array with methods for verse chat */
+static VMethodInfo vmethod_info[] = {
+ { "join", 1, { VN_O_METHOD_PTYPE_STRING }, { "channel"}},
+ { "leave", 1, { VN_O_METHOD_PTYPE_STRING }, { "channel"}},
+ { "hear", 3, { VN_O_METHOD_PTYPE_STRING, VN_O_METHOD_PTYPE_STRING, VN_O_METHOD_PTYPE_STRING }, { "channel", "from", "msg"}}
+};
+#endif
+
+/* lookup a method group based on its name */
+struct VMethodGroup *lookup_vmethodgroup_name(ListBase *lb, const char *name) {
+ struct VMethodGroup *vmg;
+
+ for(vmg= lb->first; vmg; vmg= vmg->next)
+ if(strcmp(vmg->name,name)==0) break;
+
+ return vmg;
+}
+
+/* lookup a method group based on its group_id */
+struct VMethodGroup *lookup_vmethodgroup(ListBase *lb, uint16 group_id) {
+ struct VMethodGroup *vmg;
+
+ for(vmg= lb->first; vmg; vmg= vmg->next)
+ if(vmg->group_id==group_id) break;
+
+ return vmg;
+}
+
+/* lookup a method based on its name */
+struct VMethod *lookup_vmethod_name(ListBase *lb, const char *name) {
+ struct VMethod *vm;
+ for(vm= lb->first; vm; vm= vm->next)
+ if(strcmp(vm->name,name)==0) break;
+
+ return vm;
+}
+
+/* lookup a method based on its method_id */
+struct VMethod *lookup_vmethod(ListBase *lb, uint8 method_id) {
+ struct VMethod *vm;
+ for(vm= lb->first; vm; vm= vm->next)
+ if(vm->id==method_id) break;
+
+ return vm;
+}
+
+#ifdef VERSECHAT
+/*
+ * send say command
+ */
+void send_say(const char *chan, const char *utter)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VMethodGroup *vmg;
+ struct VMethod *vm;
+ VNOPackedParams *utterpack;
+ VNOParam args[2];
+
+ vnode= (VNode *)(session->nodes.lb.first);
+
+ for( ; vnode; vnode= vnode->next) {
+ if(strcmp(vnode->name, "tawksrv")==0) {
+ vmg= lookup_vmethodgroup_name(&(vnode->methodgroups), "tawk");
+ if(!vmg) break;
+ vm= lookup_vmethod_name(&(vmg->methods), "say");
+ if(!vm) break;
+ args[0].vstring= (char *)chan;
+ args[1].vstring= (char *)utter;
+ if((utterpack= verse_method_call_pack(vm->param_count, vm->param_type, args))!=NULL) {
+ verse_send_o_method_call(vnode->id, vmg->group_id, vm->id, vnode->session->avatar, utterpack);
+ }
+ break;
+ }
+
+ }
+}
+
+/*
+ * send logout command
+ */
+void send_logout(VNode *vnode)
+{
+ struct VMethodGroup *vmg;
+ struct VMethod *vm;
+ VNOPackedParams *pack;
+
+ vnode->chat_flag = CHAT_LOGGED;
+ vmg= lookup_vmethodgroup_name(&(vnode->methodgroups), "tawk");
+ if(!vmg) return;
+ vm= lookup_vmethod_name(&(vmg->methods), "logout");
+ if(!vm) return;
+
+ if((pack= verse_method_call_pack(vm->param_count, vm->param_type, NULL))!=NULL) {
+ verse_send_o_method_call(vnode->id, vmg->group_id, vm->id, vnode->session->avatar, pack);
+ }
+ vnode->chat_flag = CHAT_NOTLOGGED;
+}
+
+/*
+ * send join command
+ */
+void send_join(VNode *vnode, const char *chan)
+{
+ struct VMethodGroup *vmg;
+ struct VMethod *vm;
+ VNOPackedParams *join;
+ VNOParam channel[1];
+
+ vmg= lookup_vmethodgroup_name(&(vnode->methodgroups), "tawk");
+ if(!vmg) return;
+ vm= lookup_vmethod_name(&(vmg->methods), "join");
+ if(!vm) return;
+
+ channel[0].vstring= (char *)chan;
+ if((join= verse_method_call_pack(vm->param_count, vm->param_type, channel))!=NULL) {
+ verse_send_o_method_call(vnode->id, vmg->group_id, vm->id, vnode->session->avatar, join);
+ }
+}
+
+/*
+ * send leave command
+ */
+void send_leave(VNode *vnode, const char *chan)
+{
+ struct VMethodGroup *vmg;
+ struct VMethod *vm;
+ VNOPackedParams *leave;
+ VNOParam channel[1];
+
+ vmg= lookup_vmethodgroup_name(&(vnode->methodgroups), "tawk");
+ if(!vmg) return;
+ vm= lookup_vmethod_name(&(vmg->methods), "leave");
+ if(!vm) return;
+
+ channel[0].vstring= (char *)chan;
+ if((leave= verse_method_call_pack(vm->param_count, vm->param_type, channel))!=NULL) {
+ verse_send_o_method_call(vnode->id, vmg->group_id, vm->id, vnode->session->avatar, leave);
+ }
+}
+
+/*
+ * send login command
+ */
+void send_login(VNode *vnode)
+{
+ struct VMethodGroup *vmg;
+ struct VMethod *vm;
+ VNOPackedParams *login;
+ VNOParam param[1];
+
+ vnode->chat_flag = CHAT_LOGGED;
+ vmg= lookup_vmethodgroup_name(&(vnode->methodgroups), "tawk");
+ if(!vmg) return;
+ vm= lookup_vmethod_name(&(vmg->methods), "login");
+ if(!vm) return;
+
+ param[0].vstring= U.verseuser;
+
+ if((login= verse_method_call_pack(vm->param_count, vm->param_type, param))!=NULL) {
+ verse_send_o_method_call(vnode->id, vmg->group_id, vm->id, vnode->session->avatar, login);
+ }
+ vnode->chat_flag = CHAT_LOGGED;
+
+ vnode= lookup_vnode(vnode->session, vnode->session->avatar);
+ vmg= lookup_vmethodgroup_name(&(vnode->methodgroups), "tawk-client");
+ if(!vmg)
+ verse_send_o_method_group_create(vnode->session->avatar, ~0, "tawk-client");
+}
+#endif
+
+/*
+ * Free a VMethod
+ */
+void free_verse_method(VMethod *vm) {
+ if(!vm) return;
+
+ MEM_freeN(vm->param_type);
+}
+
+/*
+ * Free methods for VMethodGroup
+ */
+void free_verse_methodgroup(VMethodGroup *vmg)
+{
+ struct VMethod *vm, *tmpvm;
+
+ if(!vmg) return;
+
+ vm= vmg->methods.first;
+ while(vm) {
+ tmpvm=vm->next;
+ free_verse_method(vm);
+ vm= tmpvm;
+ }
+ BLI_freelistN(&(vmg->methods));
+}
+
+/* callback for method group creation */
+static void cb_o_method_group_create(
+ void *user_data,
+ VNodeID node_id,
+ uint16 group_id,
+ const char *name)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VMethodGroup *vmg;
+
+ if(!session) return;
+
+ vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ vmg = lookup_vmethodgroup(&(vnode->methodgroups), group_id);
+
+ /* create method group holder in node node_id */
+ if(!vmg) {
+ vmg= MEM_mallocN(sizeof(VMethodGroup), "VMethodGroup");
+ vmg->group_id = group_id;
+ vmg->methods.first = vmg->methods.last = NULL;
+ BLI_addtail(&(vnode->methodgroups), vmg);
+ printf("new method group with name %s (group_id %d) for node %u created\n", name, group_id, node_id);
+ }
+
+ /* this ensures name of an existing group gets updated, in case it is changed */
+ BLI_strncpy(vmg->name, (char *)name, 16);
+
+ /* subscribe to method group */
+ verse_send_o_method_group_subscribe(node_id, group_id);
+
+#ifdef VERSECHAT
+ /* if this is our own method group, register our methods */
+ if(node_id==session->avatar) {
+ verse_send_o_method_create(node_id, group_id, (uint8)~0u, vmethod_info[0].name,
+ vmethod_info[0].param_count,
+ (VNOParamType *)vmethod_info[0].param_type,
+ (const char **)vmethod_info[0].param_name);
+ b_verse_update();
+ verse_send_o_method_create(node_id, group_id, (uint8)~0u, vmethod_info[1].name,
+ vmethod_info[1].param_count,
+ (VNOParamType *)vmethod_info[1].param_type,
+ (const char **)vmethod_info[1].param_name);
+ b_verse_update();
+ verse_send_o_method_create(node_id, group_id, (uint8)~0u, vmethod_info[2].name,
+ vmethod_info[2].param_count,
+ (VNOParamType *)vmethod_info[2].param_type,
+ (const char **)vmethod_info[2].param_name);
+ b_verse_update();
+ }
+#endif
+}
+
+/* callback for method group destruction */
+static void cb_o_method_group_destroy(
+ void *user_data,
+ VNodeID node_id,
+ uint16 group_id,
+ const char *name)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VMethodGroup *vmg;
+ struct VMethod *vm;
+
+ printf("method group %d destroyed\n", group_id);
+
+ if(!session) return;
+
+ vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ for(vmg= vnode->methodgroups.first; vmg; vmg= vmg->next)
+ if(vmg->group_id==group_id) break;
+
+ if(!vmg) return; /* method group doesn't exist? */
+
+ vmg->group_id = 0;
+ vmg->name[0] = '\0';
+ vm= vmg->methods.first;
+ while(vm) {
+ /* free vm */
+
+ }
+
+ /* TODO: unsubscribe from method group */
+ BLI_remlink(&(vnode->methodgroups),vmg);
+ MEM_freeN(vmg);
+}
+
+/* callback for method creation */
+static void cb_o_method_create(
+ void *user_data,
+ VNodeID node_id,
+ uint16 group_id,
+ uint16 method_id,
+ const char *name,
+ uint8 param_count,
+ const VNOParamType *param_type,
+ const char *param_name[])
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VMethodGroup *vmg;
+ struct VMethod *vm;
+ unsigned int size;
+ unsigned int i;
+ char *put;
+
+ if(!session) return;
+
+ vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ vmg= lookup_vmethodgroup((&vnode->methodgroups), group_id);
+
+ if(!vmg) return;
+
+ vm= lookup_vmethod((&vmg->methods), method_id);
+
+ if(!vm) {
+ vm= MEM_mallocN(sizeof(VMethod), "VMethod");
+ vm->id= method_id;
+ vm->param_count= param_count;
+ size= param_count* (sizeof(*vm->param_type) + sizeof(*vm->param_name));
+ for(i= 0; i <param_count; i++) {
+ size+=strlen(param_name[i])+1;
+ }
+ vm->param_type= MEM_mallocN(size, "param_type and param_name");
+ memcpy(vm->param_type, param_type, sizeof(VNOParamType)*param_count);
+ vm->param_name= (char **)(vm->param_type + param_count);
+ put= (char *)(vm->param_name + param_count);
+ for(i= 0; i < param_count; i++) {
+ vm->param_name[i]= put;
+ strcpy(put, param_name[i]);
+ put += strlen(param_name[i]) + 1;
+ }
+
+ BLI_addtail(&(vmg->methods), vm);
+#ifdef VERSECHAT
+ if(strcmp(vmethod_info[0].name, name)==0) {
+ vmethod_info[0].id = method_id;
+ }
+#endif
+ printf("method %s in group %d of node %u created\n", name, group_id, node_id);
+ }
+
+ BLI_strncpy(vm->name, (char *)name, 500);
+}
+
+/* callback for method destruction */
+static void cb_o_method_destroy(
+ void *user_data,
+ VNodeID node_id,
+ uint16 group_id,
+ uint16 method_id,
+ const char *name,
+ uint8 param_count,
+ const VNOParamType *param_type,
+ const char *param_name[])
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VMethodGroup *vmg;
+ struct VMethod *vm;
+
+ if(!session) return;
+
+ vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ for(vmg= vnode->methodgroups.first; vmg; vmg= vmg->next)
+ if(vmg->group_id==group_id) break;
+
+ if(!vmg) return; /* method group doesn't exist? */
+
+ for(vm= vmg->methods.first; vm; vm= vm->next)
+ if(vm->id==method_id) break;
+
+ if(!vm) return;
+
+ BLI_remlink(&(vmg->methods), vm);
+ MEM_freeN(vm->param_type);
+ MEM_freeN(vm);
+}
+
+/* callback for method calls */
+static void cb_o_method_call(void *user_data, VNodeID node_id, uint8 group_id, uint8 method_id, VNodeID sender, VNOPackedParams *params)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VMethodGroup *vmg;
+ struct VMethod *vm;
+ Text *text;
+ int method_idx= -1;
+
+ VNOParam arg[3];
+
+ if(!session) return;
+
+ if(session->avatar!=node_id) return;
+
+ vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ vmg= lookup_vmethodgroup(&(vnode->methodgroups), group_id);
+ if(!vmg) return;
+
+ vm= lookup_vmethod(&(vmg->methods), method_id);
+ if(!vm) return;
+#ifdef VERSECHAT
+ if(strcmp(vm->name, "join")==0) method_idx=0;
+ if(strcmp(vm->name, "leave")==0) method_idx=1;
+ if(strcmp(vm->name, "hear")==0) method_idx=2;
+ if(method_idx>-1)
+ verse_method_call_unpack(params, vmethod_info[method_idx].param_count, vmethod_info[method_idx].param_type, arg);
+
+ switch(method_idx) {
+ case 0:
+ printf("Joining channel %s\n",arg[0].vstring);
+ text=add_empty_text();
+ text->flags |= TXT_ISCHAT;
+ rename_id(&(text->id), arg[0].vstring);
+ break;
+ case 1:
+ printf("Leaving channel %s\n",arg[0].vstring);
+ break;
+ case 2:
+ {
+ ListBase lb = G.main->text;
+ ID *id= (ID *)lb.first;
+ char showstr[1024];
+ showstr[0]='\0';
+ text = NULL;
+ sprintf(showstr, "%s: %s\n", arg[1].vstring, arg[2].vstring);
+ for(; id; id= id->next) {
+ if(strcmp(id->name+2, arg[0].vstring)==0 && strcmp(arg[0].vstring, "#server")!=0) {
+ text = (Text *)id;
+ break;
+ }
+ }
+ if(text) {
+ txt_insert_buf(text, showstr);
+ txt_move_eof(text, 0);
+ allqueue(REDRAWCHAT, 0);
+ } else {
+ printf("%s> %s: %s\n",arg[0].vstring, arg[1].vstring, arg[2].vstring);
+ }
+ }
+ break;
+ }
+#endif
+}
+
+void set_method_callbacks(void)
+{
+ /* create and destroy method groups */
+ verse_callback_set(verse_send_o_method_group_create, cb_o_method_group_create, NULL);
+ verse_callback_set(verse_send_o_method_group_destroy, cb_o_method_group_destroy, NULL);
+
+ /* create and destroy methods */
+ verse_callback_set(verse_send_o_method_create, cb_o_method_create, NULL);
+ verse_callback_set(verse_send_o_method_destroy, cb_o_method_destroy, NULL);
+
+ /* call methods */
+ verse_callback_set(verse_send_o_method_call, cb_o_method_call, NULL);
+}
+
+#endif
diff --git a/source/blender/blenkernel/intern/verse_node.c b/source/blender/blenkernel/intern/verse_node.c
new file mode 100644
index 00000000000..fd5a25598d3
--- /dev/null
+++ b/source/blender/blenkernel/intern/verse_node.c
@@ -0,0 +1,750 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributor(s): Jiri Hnidek.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifdef WITH_VERSE
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+#include "DNA_userdef_types.h"
+
+#include "BLI_dynamiclist.h"
+#include "BLI_blenlib.h"
+
+#include "BIF_verse.h"
+
+#include "BKE_verse.h"
+
+#include "verse.h"
+
+/* function prototypes of static functions */
+ /* for tags */
+static void free_verse_tag_data(struct VTag *vtag);
+static struct VTag *find_tag_in_queue(struct VTagGroup *vtaggroup, const char *name);
+static struct VTag *create_verse_tag(struct VTagGroup *vtaggroup, uint16 tag_id, const char *name, VNTagType type, const VNTag *tag);
+ /* for verse tag groups */
+static void free_verse_taggroup_data(struct VTagGroup *taggroup);
+static struct VTagGroup *find_taggroup_in_queue(struct VNode *vnode, const char *name);
+static struct VTagGroup *create_verse_taggroup(VNode *vnode, uint16 group_id, const char *name);
+ /* for verse nodes */
+static void move_verse_node_to_dlist(struct VerseSession *session, VNodeID vnode_id);
+ /* function prototypes of node callback functions */
+static void cb_tag_destroy(void *user_data, VNodeID node_id, uint16 group_id, uint16 tag_id);
+static void cb_tag_create(void *user_data, VNodeID node_id, uint16 group_id, uint16 tag_id, const char *name, VNTagType type, const VNTag *tag);
+static void cb_tag_group_destroy(void *user_data, VNodeID node_id, uint16 group_id);
+static void cb_tag_group_create(void *user_data, VNodeID node_id, uint16 group_id, const char *name);
+static void cb_node_name_set(void *user_data, VNodeID node_id, const char *name);
+static void cb_node_destroy(void *user_data, VNodeID node_id);
+static void cb_node_create(void *user_data, VNodeID node_id, uint8 type, VNodeID owner_id);
+
+/*
+ * send new tag to verse server
+ */
+void send_verse_tag(VTag *vtag)
+{
+ verse_send_tag_create(vtag->vtaggroup->vnode->id,
+ vtag->vtaggroup->id,
+ vtag->id,
+ vtag->name,
+ vtag->type,
+ vtag->tag);
+}
+
+/*
+ * free tag data
+ */
+static void free_verse_tag_data(VTag *vtag)
+{
+ /* free name of verse tag */
+ MEM_freeN(vtag->name);
+ /* free value of tag */
+ MEM_freeN(vtag->tag);
+}
+
+/*
+ * try to find tag in sending queue ... if tag will be found, then
+ * this function will removed tag from queue and will return pointer
+ * at this tag
+ */
+static VTag *find_tag_in_queue(VTagGroup *vtaggroup, const char *name)
+{
+ struct VTag *vtag;
+
+ vtag = vtaggroup->queue.first;
+
+ while(vtag) {
+ if(strcmp(vtag->name, name)==0) {
+ BLI_remlink(&(vtaggroup->queue), vtag);
+ break;
+ }
+ vtag = vtag->next;
+ }
+
+ return vtag;
+}
+
+/*
+ * create new verse tag
+ */
+static VTag *create_verse_tag(
+ VTagGroup *vtaggroup,
+ uint16 tag_id,
+ const char *name,
+ VNTagType type,
+ const VNTag *tag)
+{
+ struct VTag *vtag;
+
+ vtag = (VTag*)MEM_mallocN(sizeof(VTag), "VTag");
+
+ vtag->vtaggroup = vtaggroup;
+ vtag->id = tag_id;
+ vtag->name = (char*)MEM_mallocN(sizeof(char)*(strlen(name)+1), "VTag name");
+ strcpy(vtag->name, name);
+ vtag->type = type;
+
+ vtag->tag = (VNTag*)MEM_mallocN(sizeof(VNTag), "VNTag");
+ *vtag->tag = *tag;
+
+ vtag->value = NULL;
+
+ return vtag;
+}
+
+/*
+ * send taggroup to verse server
+ */
+void send_verse_taggroup(VTagGroup *vtaggroup)
+{
+ verse_send_tag_group_create(
+ vtaggroup->vnode->id,
+ vtaggroup->id,
+ vtaggroup->name);
+}
+
+/*
+ * free taggroup data
+ */
+static void free_verse_taggroup_data(VTagGroup *taggroup)
+{
+ struct VerseSession *session = taggroup->vnode->session;
+ struct VTag *vtag;
+
+ vtag = taggroup->tags.lb.first;
+
+ while(vtag) {
+ free_verse_tag_data(vtag);
+ vtag = vtag->next;
+ }
+
+ /* unsubscribe from taggroup */
+ if(session->flag & VERSE_CONNECTED)
+ verse_send_tag_group_unsubscribe(taggroup->vnode->id, taggroup->id);
+
+ BLI_dlist_destroy(&(taggroup->tags));
+ MEM_freeN(taggroup->name);
+}
+
+/*
+ * move taggroup from queue to dynamic list with access array,
+ * set up taggroup id and return pointer at this taggroup
+ */
+static VTagGroup *find_taggroup_in_queue(VNode *vnode, const char *name)
+{
+ struct VTagGroup *vtaggroup;
+
+ vtaggroup = vnode->queue.first;
+
+ while(vtaggroup) {
+ if(strcmp(vtaggroup->name, name)==0) {
+ BLI_remlink(&(vnode->queue), vtaggroup);
+ break;
+ }
+ vtaggroup = vtaggroup->next;
+ }
+
+ return vtaggroup;
+}
+
+/*
+ * create new verse group of tags
+ */
+static VTagGroup *create_verse_taggroup(VNode *vnode, uint16 group_id, const char *name)
+{
+ struct VTagGroup *taggroup;
+
+ taggroup = (VTagGroup*)MEM_mallocN(sizeof(VTagGroup), "VTagGroup");
+
+ taggroup->vnode = vnode;
+ taggroup->id = group_id;
+ taggroup->name = (char*)MEM_mallocN(sizeof(char)*(strlen(name)+1), "VTagGroup name");
+ strcpy(taggroup->name, name);
+
+ BLI_dlist_init(&(taggroup->tags));
+ taggroup->queue.first = taggroup->queue.last = NULL;
+
+ taggroup->post_tag_change = post_tag_change;
+ taggroup->post_taggroup_create = post_taggroup_create;
+
+ return taggroup;
+}
+
+/*
+ * move first VerseNode waiting in sending queue to dynamic list of VerseNodes
+ * (it usually happens, when "our" VerseNode was received from verse server)
+ */
+static void move_verse_node_to_dlist(VerseSession *session, VNodeID vnode_id)
+{
+ VNode *vnode;
+
+ vnode = session->queue.first;
+
+ if(vnode) {
+ BLI_remlink(&(session->queue), vnode);
+ BLI_dlist_add_item_index(&(session->nodes), (void*)vnode, vnode_id);
+ }
+}
+
+/*
+ * send VerseNode to verse server
+ */
+void send_verse_node(VNode *vnode)
+{
+ verse_send_node_create(
+ vnode->id,
+ vnode->type,
+ vnode->session->avatar);
+}
+
+/*
+ * free Verse Node data
+ */
+void free_verse_node_data(VNode *vnode)
+{
+ struct VerseSession *session = vnode->session;
+ struct VTagGroup *vtaggroup;
+
+ /* free node data (object, geometry, etc.) */
+ switch(vnode->type){
+ case V_NT_OBJECT:
+ free_object_data(vnode);
+ break;
+ case V_NT_GEOMETRY:
+ free_geom_data(vnode);
+ break;
+ case V_NT_BITMAP:
+ free_bitmap_node_data(vnode);
+ break;
+ default:
+ break;
+ }
+
+ /* free all tag groups in dynamic list with access array */
+ vtaggroup = vnode->taggroups.lb.first;
+ while(vtaggroup) {
+ free_verse_taggroup_data(vtaggroup);
+ vtaggroup = vtaggroup->next;
+ }
+ BLI_dlist_destroy(&(vnode->taggroups));
+
+ /* free all tag groups still waiting in queue */
+ vtaggroup = vnode->queue.first;
+ while(vtaggroup) {
+ free_verse_taggroup_data(vtaggroup);
+ vtaggroup = vtaggroup->next;
+ }
+ BLI_freelistN(&(vnode->queue));
+
+ /* unsubscribe from node */
+ if(session->flag & VERSE_CONNECTED)
+ verse_send_node_unsubscribe(vnode->id);
+
+ /* free node name */
+ MEM_freeN(vnode->name);
+ vnode->name = NULL;
+
+ /* free node data */
+ MEM_freeN(vnode->data);
+ vnode->data = NULL;
+
+}
+
+/*
+ * free VerseNode
+ */
+void free_verse_node(VNode *vnode)
+{
+ free_verse_node_data(vnode);
+
+ BLI_dlist_free_item(&(vnode->session->nodes), vnode->id);
+}
+
+/*
+ * Find a Verse Node from session
+ */
+VNode* lookup_vnode(VerseSession *session, VNodeID node_id)
+{
+ struct VNode *vnode;
+ vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ return vnode;
+}
+
+/*
+ * create new Verse Node
+ */
+VNode* create_verse_node(VerseSession *session, VNodeID node_id, uint8 type, VNodeID owner_id)
+{
+ struct VNode *vnode;
+
+ vnode = (VNode*)MEM_mallocN(sizeof(VNode), "VerseNode");
+
+ vnode->session = session;
+ vnode->id = node_id;
+ vnode->owner_id = owner_id;
+ vnode->name = NULL;
+ vnode->type = type;
+
+ BLI_dlist_init(&(vnode->taggroups));
+ vnode->queue.first = vnode->queue.last = NULL;
+ vnode->methodgroups.first = vnode->methodgroups.last = NULL;
+
+ vnode->data = NULL;
+
+ vnode->counter = 0;
+
+ vnode->flag = 0;
+#ifdef VERSECHAT
+ vnode->chat_flag = CHAT_NOTLOGGED;
+#endif
+
+ vnode->post_node_create = post_node_create;
+ vnode->post_node_destroy = post_node_destroy;
+ vnode->post_node_name_set = post_node_name_set;
+
+ return vnode;
+}
+
+/*
+ * callback function: tag was destroyed
+ */
+static void cb_tag_destroy(
+ void *user_data,
+ VNodeID node_id,
+ uint16 group_id,
+ uint16 tag_id)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VTagGroup *vtaggroup;
+ struct VTag *vtag;
+
+ if(!session) return;
+
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ if(!vnode) return;
+
+ /* try to find tag group in list of tag groups */
+ vtaggroup = BLI_dlist_find_link(&(vnode->taggroups), group_id);
+
+ if(!vtaggroup) return;
+
+ /* try to find verse tag in dynamic list of tags in tag group */
+ vtag = (VTag*)BLI_dlist_find_link(&(vtaggroup->tags), tag_id);
+
+ if(vtag) {
+ free_verse_tag_data(vtag);
+ BLI_dlist_free_item(&(vtaggroup->tags), vtag->id);
+ }
+}
+
+/*
+ * callback function: new tag was created
+ */
+static void cb_tag_create(
+ void *user_data,
+ VNodeID node_id,
+ uint16 group_id,
+ uint16 tag_id,
+ const char *name,
+ VNTagType type,
+ const VNTag *tag)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VTagGroup *vtaggroup;
+ struct VTag *vtag;
+
+ if(!session) return;
+
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ if(!vnode) return;
+
+ /* try to find tag group in list of tag groups */
+ vtaggroup = BLI_dlist_find_link(&(vnode->taggroups), group_id);
+
+ if(!vtaggroup) return;
+
+ /* try to find verse tag in dynamic list of tags in tag group */
+ vtag = (VTag*)BLI_dlist_find_link(&(vtaggroup->tags), tag_id);
+
+ if(!vtag) {
+ /* we will try to find vtag in sending queue */
+ vtag = find_tag_in_queue(vtaggroup, name);
+
+ /* when we didn't create this tag, then we will have to create one */
+ if(!vtag) vtag = create_verse_tag(vtaggroup, tag_id, name, type, tag);
+ else vtag->id = tag_id;
+
+ /* add tag to the list of tags in tag group */
+ BLI_dlist_add_item_index(&(vtaggroup->tags), vtag, tag_id);
+
+ /* post change/create method */
+ vtaggroup->post_tag_change(vtag);
+ }
+ else {
+ /* this tag exists, then we will propably change value of this tag */
+ if((vtag->type != type) || (strcmp(vtag->name, name)!=0)) {
+ /* changes of type or name are not allowed and such
+ * stupid changes will be returned back */
+ send_verse_tag(vtag);
+ }
+ else {
+ /* post change/create method */
+ vtaggroup->post_tag_change(vtag);
+ }
+ }
+}
+
+/*
+ * callback function: tag group was destroyed
+ */
+static void cb_tag_group_destroy(
+ void *user_data,
+ VNodeID node_id,
+ uint16 group_id)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VTagGroup *vtaggroup;
+
+ if(!session) return;
+
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ if(!vnode) return;
+
+ vtaggroup = BLI_dlist_find_link(&(vnode->taggroups), group_id);
+
+ if(vtaggroup) {
+ free_verse_taggroup_data(vtaggroup);
+ BLI_dlist_free_item(&(vnode->taggroups), vtaggroup->id);
+ }
+}
+
+/*
+ * callback function: new tag group was created
+ */
+static void cb_tag_group_create(
+ void *user_data,
+ VNodeID node_id,
+ uint16 group_id,
+ const char *name)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VTagGroup *vtaggroup;
+
+ if(!session) return;
+
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ if(!vnode) return;
+
+ /* name of taggroup has to begin with string "blender:" */
+ if(strncmp("blender:", name, 8)) return;
+
+ /* try to find tag group in list of tag groups */
+ vtaggroup = BLI_dlist_find_link(&(vnode->taggroups), group_id);
+
+ if(!vtaggroup) {
+ /* subscribe to tag group (when new tag will be created, then blender will
+ * receive command about it) */
+ verse_send_tag_group_subscribe(vnode->id, group_id);
+ verse_callback_update(0);
+
+ /* try to find taggroup in waiting queue */
+ vtaggroup = find_taggroup_in_queue(vnode, name);
+
+ /* if no taggroup exist, then new has to be created */
+ if(!vtaggroup) vtaggroup = create_verse_taggroup(vnode, group_id, name);
+ else vtaggroup->id = group_id;
+
+ /* add tag group to dynamic list with access array */
+ BLI_dlist_add_item_index(&(vnode->taggroups), (void*)vtaggroup, (unsigned int)group_id);
+
+ /* post create method */
+ vtaggroup->post_taggroup_create(vtaggroup);
+ }
+ else {
+ /* this taggroup exist and somebody try to change its name */
+ if(strcmp(vtaggroup->name, name)!=0) {
+ /* blender doesn't allow such stupid and dangerous things */
+ send_verse_taggroup(vtaggroup);
+ }
+ }
+}
+
+/*
+ * callback function: change name of node
+ */
+static void cb_node_name_set(
+ void *user_data,
+ VNodeID node_id,
+ const char *name)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+
+ if(!session) return;
+
+ vnode = (VNode*)BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ if(vnode && name) {
+ if(!vnode->name) {
+ vnode->name = (char*)MEM_mallocN(sizeof(char)*(strlen(name)+1), "VerseNode name");
+ }
+ else if(strlen(name) > strlen(vnode->name)) {
+ MEM_freeN(vnode->name);
+ vnode->name = (char*)MEM_mallocN(sizeof(char)*(strlen(name)+1), "VerseNode name");
+ }
+ strcpy(vnode->name, name);
+
+ vnode->post_node_name_set(vnode);
+ }
+}
+
+/*
+ * callback function for deleting node
+ */
+static void cb_node_destroy(
+ void *user_data,
+ VNodeID node_id)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+
+ if(!session) return;
+
+ vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ if(vnode) {
+ /* remove VerseNode from dynamic list */
+ BLI_dlist_rem_item(&(session->nodes), (unsigned int)node_id);
+ /* do post destroy operations */
+ vnode->post_node_destroy(vnode);
+ /* free verse data */
+ free_verse_node_data(vnode);
+ /* free VerseNode */
+ MEM_freeN(vnode);
+ };
+}
+
+
+/*
+ * callback function for new created node
+ */
+static void cb_node_create(
+ void *user_data,
+ VNodeID node_id,
+ uint8 type,
+ VNodeID owner_id)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode = NULL;
+
+ if(!session) return;
+
+ /* subscribe to node */
+ if((type==V_NT_OBJECT) || (type==V_NT_GEOMETRY) || (type==V_NT_BITMAP))
+ verse_send_node_subscribe(node_id);
+ else
+ return;
+
+ switch(type){
+ case V_NT_OBJECT :
+ if(owner_id==VN_OWNER_MINE) {
+ struct VLink *vlink;
+ /* collect VerseNode from VerseNode queue */
+ move_verse_node_to_dlist(session, node_id);
+ /* send next VerseNode waiting in queue */
+ if(session->queue.first) send_verse_node(session->queue.first);
+ /* get received VerseNode from list of VerseNodes */
+ vnode = BLI_dlist_find_link(&(session->nodes), node_id);
+ /* set up ID */
+ vnode->id = node_id;
+ /* set up flags */
+ vnode->flag |= NODE_RECEIVED;
+ /* find unsent link pointing at this VerseNode */
+ vlink = find_unsent_child_vlink(session, vnode);
+ /* send VerseLink */
+ if(vlink) send_verse_link(vlink);
+ /* send name of object node */
+ verse_send_node_name_set(node_id, vnode->name);
+ /* subscribe to changes of object node transformations */
+ verse_send_o_transform_subscribe(node_id, 0);
+ /* send object transformation matrix */
+ send_verse_object_position(vnode);
+ send_verse_object_rotation(vnode);
+ send_verse_object_scale(vnode);
+ }
+ else {
+ /* create new VerseNode */
+ vnode = create_verse_node(session, node_id, type, owner_id);
+ /* add VerseNode to list of nodes */
+ BLI_dlist_add_item_index(&(session->nodes), (void*)vnode, (unsigned int)node_id);
+ /* set up flags */
+ vnode->flag |= NODE_RECEIVED;
+ /* create object data */
+ vnode->data = create_object_data();
+ /* set up avatar's name */
+ if(node_id == session->avatar) {
+ verse_send_node_name_set(node_id, U.verseuser);
+ }
+ else if(session->flag & VERSE_AUTOSUBSCRIBE) {
+ /* subscribe to changes of object node transformations */
+ verse_send_o_transform_subscribe(node_id, 0);
+ }
+ }
+ break;
+ case V_NT_GEOMETRY :
+ if(owner_id==VN_OWNER_MINE){
+ struct VLink *vlink;
+ struct VLayer *vlayer;
+ /* collect VerseNode from VerseNode queue */
+ move_verse_node_to_dlist(session, node_id);
+ /* send next VerseNode waiting in queue */
+ if(session->queue.first) send_verse_node(session->queue.first);
+ /* get received VerseNode from list of VerseNodes */
+ vnode = BLI_dlist_find_link(&(session->nodes), node_id);
+ /* set up ID */
+ vnode->id = node_id;
+ /* set up flags */
+ vnode->flag |= NODE_RECEIVED;
+ /* find unsent link pointing at this VerseNode */
+ vlink = find_unsent_parent_vlink(session, vnode);
+ /* send VerseLink */
+ if(vlink) send_verse_link(vlink);
+ /* send name of geometry node */
+ verse_send_node_name_set(node_id, vnode->name);
+ /* send all not sent layer to verse server */
+ vlayer = (VLayer*)((VGeomData*)vnode->data)->queue.first;
+ if(vlayer) {
+ while(vlayer) {
+ send_verse_layer(vlayer);
+ vlayer = vlayer->next;
+ }
+ }
+ else {
+ /* send two verse layers to verse server */
+/* verse_send_g_layer_create(node_id, 0, "vertex", VN_G_LAYER_VERTEX_XYZ, 0, 0);
+ verse_send_g_layer_create(node_id, 1, "polygon", VN_G_LAYER_POLYGON_CORNER_UINT32, 0, 0);*/
+ }
+ }
+ else {
+ /* create new VerseNode*/
+ vnode = create_verse_node(session, node_id, type, owner_id);
+ /* add VerseNode to dlist of nodes */
+ BLI_dlist_add_item_index(&(session->nodes), (void*)vnode, (unsigned int)node_id);
+ /* set up flags */
+ vnode->flag |= NODE_RECEIVED;
+ /* create geometry data */
+ vnode->data = (void*)create_geometry_data();
+ }
+ break;
+ case V_NT_BITMAP :
+ if(owner_id==VN_OWNER_MINE) {
+ /* collect VerseNode from VerseNode queue */
+ move_verse_node_to_dlist(session, node_id);
+ /* send next VerseNode waiting in queue */
+ if(session->queue.first) send_verse_node(session->queue.first);
+ /* get received VerseNode from list of VerseNodes */
+ vnode = BLI_dlist_find_link(&(session->nodes), node_id);
+ /* set up ID */
+ vnode->id = node_id;
+ /* set up flags */
+ vnode->flag |= NODE_RECEIVED;
+ /* send name of object node */
+ verse_send_node_name_set(node_id, vnode->name);
+ /* send dimension of image to verse server */
+ verse_send_b_dimensions_set(node_id,
+ ((VBitmapData*)vnode->data)->width,
+ ((VBitmapData*)vnode->data)->height,
+ ((VBitmapData*)vnode->data)->depth);
+ }
+ else {
+ /* create new VerseNode*/
+ vnode = create_verse_node(session, node_id, type, owner_id);
+ /* add VerseNode to dlist of nodes */
+ BLI_dlist_add_item_index(&(session->nodes), (void*)vnode, (unsigned int)node_id);
+ /* set up flags */
+ vnode->flag |= NODE_RECEIVED;
+ /* create bitmap data */
+ vnode->data = (void*)create_bitmap_data();
+ }
+ break;
+ default:
+ vnode = NULL;
+ break;
+ }
+
+ if(vnode) vnode->post_node_create(vnode);
+}
+
+/*
+ * set up all callbacks for verse nodes
+ */
+void set_node_callbacks(void)
+{
+ /* new node created */
+ verse_callback_set(verse_send_node_create, cb_node_create, NULL);
+ /* node was deleted */
+ verse_callback_set(verse_send_node_destroy, cb_node_destroy, NULL);
+ /* name of node was set */
+ verse_callback_set(verse_send_node_name_set, cb_node_name_set, NULL);
+
+ /* new tag group was created */
+ verse_callback_set(verse_send_tag_group_create, cb_tag_group_create, NULL);
+ /* tag group was destroy */
+ verse_callback_set(verse_send_tag_group_destroy, cb_tag_group_destroy, NULL);
+
+ /* new tag was created */
+ verse_callback_set(verse_send_tag_create, cb_tag_create, NULL);
+ /* tag was destroy */
+ verse_callback_set(verse_send_tag_destroy, cb_tag_destroy, NULL);
+}
+
+#endif
diff --git a/source/blender/blenkernel/intern/verse_object_node.c b/source/blender/blenkernel/intern/verse_object_node.c
new file mode 100644
index 00000000000..d8be38cd00f
--- /dev/null
+++ b/source/blender/blenkernel/intern/verse_object_node.c
@@ -0,0 +1,620 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributor(s): Jiri Hnidek.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifdef WITH_VERSE
+
+#include <string.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+#include "DNA_userdef_types.h"
+
+#include "BLI_dynamiclist.h"
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "BIF_verse.h"
+
+#include "BKE_verse.h"
+#include "BKE_utildefines.h"
+
+#include "verse.h"
+
+/* function prototypes of static functions */
+
+/* callback functions */
+static void cb_o_transform_pos_real32(void *user_data, VNodeID node_id, uint32 time_s, uint32 time_f, const real32 *pos, const real32 *speed, const real32 *accelerate, const real32 *drag_normal, real32 drag);
+static void cb_o_transform_rot_real32(void *user_data, VNodeID node_id, uint32 time_s, uint32 time_f, const VNQuat32 *temp, const VNQuat32 *speed, const VNQuat32 *accelerate, const VNQuat32 *drag_normal, real32 drag);
+static void cb_o_transform_scale_real32(void *user_data, VNodeID node_id, real32 scale_x, real32 scale_y, real32 scale_z);
+static void cb_o_link_set(void *user_data, VNodeID node_id, uint16 link_id, VNodeID link, const char *label, uint32 target_id);
+static void cb_o_link_destroy(void *user_data, VNodeID node_id,uint16 link_id);
+
+/* other functions */
+static void set_target_node_link_pointer(struct VNode *vnode, struct VLink *vlink);
+static void free_verse_link_data(struct VLink *vlink);
+
+/*
+ * find noy sent VerseLink in queue
+ */
+VLink *find_unsent_child_vlink(VerseSession *session, VNode *vnode)
+{
+ struct VLink *vlink;
+
+ if(vnode->type!=V_NT_OBJECT) return NULL;
+
+ vlink = ((VObjectData*)vnode->data)->queue.first;
+ while(vlink) {
+ if(vlink->target->id != -1) {
+ printf("\t vlink found, vnode target id %d\n", vlink->target->id);
+ return vlink;
+ }
+ vlink = vlink->next;
+ }
+ return NULL;
+}
+
+/*
+ * find unsent VerseLink "pointing at this VerseNode"
+ */
+VLink *find_unsent_parent_vlink(VerseSession *session, VNode *vnode)
+{
+ struct VNode *tmp;
+ struct VLink *vlink;
+
+ tmp = session->nodes.lb.first;
+
+ while(tmp) {
+ if(tmp->type==V_NT_OBJECT) {
+ vlink = ((VObjectData*)tmp->data)->queue.first;
+ while(vlink) {
+ if(vlink->target == vnode)
+ return vlink;
+ vlink = vlink->next;
+ }
+ }
+ tmp = tmp->next;
+ }
+ return NULL;
+}
+
+/*
+ * send object position to verse server
+ */
+void send_verse_object_position(VNode *vnode)
+{
+ float tmp;
+
+ ((VObjectData*)vnode->data)->flag &= ~POS_SEND_READY;
+
+ /* we have to do rotation around x axis (+pi/2) to be
+ compatible with other verse applications */
+ tmp = -((VObjectData*)vnode->data)->pos[1];
+ ((VObjectData*)vnode->data)->pos[1] = ((VObjectData*)vnode->data)->pos[2];
+ ((VObjectData*)vnode->data)->pos[2] = tmp;
+
+ verse_send_o_transform_pos_real32(
+ vnode->id, /* node id */
+ 0, /* time_s ... no interpolation */
+ 0, /* time_f ... no interpolation */
+ ((VObjectData*)vnode->data)->pos,
+ NULL, /* speed ... no interpolation */
+ NULL, /* accelerate ... no interpolation */
+ NULL, /* drag normal ... no interpolation */
+ 0.0); /* drag ... no interpolation */
+}
+
+/*
+ * send object rotation to verse server
+ */
+void send_verse_object_rotation(VNode *vnode)
+{
+ VNQuat32 quat;
+ float q[4] = {cos(-M_PI/4), -sin(-M_PI/4), 0, 0}, v[4], tmp[4];
+
+ /* inverse transformation to transformation in function cb_o_transform_rot_real32 */
+ QuatMul(v, ((VObjectData*)vnode->data)->quat, q);
+ q[1]= sin(-M_PI/4);
+ QuatMul(tmp, q, v);
+
+ quat.x = tmp[1];
+ quat.y = tmp[2];
+ quat.z = tmp[3];
+ quat.w = tmp[0];
+
+ ((VObjectData*)vnode->data)->flag &= ~ROT_SEND_READY;
+
+ verse_send_o_transform_rot_real32(
+ vnode->id, /* node id */
+ 0, /* time_s ... no interpolation */
+ 0, /* time_f ... no interpolation */
+ &quat,
+ NULL, /* speed ... no interpolation */
+ NULL, /* accelerate ... no interpolation */
+ NULL, /* drag normal ... no interpolation */
+ 0.0); /* drag ... no interpolation */
+}
+
+/*
+ * send object rotation to verse server
+ */
+void send_verse_object_scale(VNode *vnode)
+{
+ float tmp;
+
+ ((VObjectData*)vnode->data)->flag &= ~SCALE_SEND_READY;
+
+ /* we have to do rotation around x axis (+pi/2) to be
+ compatible with other verse applications */
+ tmp = ((VObjectData*)vnode->data)->scale[1];
+ ((VObjectData*)vnode->data)->scale[1] = ((VObjectData*)vnode->data)->scale[2];
+ ((VObjectData*)vnode->data)->scale[2] = tmp;
+
+ verse_send_o_transform_scale_real32(
+ vnode->id,
+ ((VObjectData*)vnode->data)->scale[0],
+ ((VObjectData*)vnode->data)->scale[1],
+ ((VObjectData*)vnode->data)->scale[2]);
+}
+
+/*
+ * send VerseLink to verse server
+ */
+void send_verse_link(VLink *vlink)
+{
+ verse_session_set(vlink->session->vsession);
+
+ verse_send_o_link_set(
+ vlink->source->id,
+ vlink->id,
+ vlink->target->id,
+ vlink->label,
+ vlink->target_id);
+}
+
+/*
+ * set up pointer at VerseLink of target node (geometry node, material node, etc.)
+ */
+static void set_target_node_link_pointer(VNode *vnode, VLink *vlink)
+{
+ switch (vnode->type) {
+ case V_NT_GEOMETRY:
+ ((VGeomData*)vnode->data)->vlink = vlink;
+ break;
+ default:
+ break;
+ }
+}
+
+/*
+ * free VerseLink and it's label
+ */
+static void free_verse_link_data(VLink *vlink)
+{
+ MEM_freeN(vlink->label);
+}
+
+/*
+ * create new VerseLink
+ */
+VLink *create_verse_link(
+ VerseSession *session,
+ VNode *source,
+ VNode *target,
+ uint16 link_id,
+ uint32 target_id,
+ const char *label)
+{
+ struct VLink *vlink;
+
+ vlink = (VLink*)MEM_mallocN(sizeof(VLink), "VerseLink");
+ vlink->session = session;
+ vlink->source = source;
+ vlink->target = target;
+ vlink->id = link_id;
+ vlink->target_id = target_id;
+
+ set_target_node_link_pointer(target, vlink);
+
+ vlink->label = (char*)MEM_mallocN(sizeof(char)*(strlen(label)+1), "VerseLink label");
+ vlink->label[0] = '\0';
+ strcat(vlink->label, label);
+
+ vlink->flag = 0;
+
+ vlink->post_link_set = post_link_set;
+ vlink->post_link_destroy = post_link_destroy;
+
+ return vlink;
+}
+
+/*
+ * free ObjectData (links, links in queue and lables of links)
+ */
+void free_object_data(VNode *vnode)
+{
+ struct VerseSession *session = vnode->session;
+ struct VObjectData *obj = (VObjectData*)vnode->data;
+ struct VLink *vlink;
+ struct VMethodGroup *vmg;
+
+ if(!obj) return;
+
+ /* free all labels of links in dlist */
+ vlink = obj->links.lb.first;
+ while(vlink){
+ free_verse_link_data(vlink);
+ vlink = vlink->next;
+ }
+
+ /* free all labels of links waiting in queue */
+ vlink = obj->queue.first;
+ while(vlink){
+ free_verse_link_data(vlink);
+ vlink = vlink->next;
+ }
+ /* free dynamic list and sendig queue of links */
+ BLI_dlist_destroy(&(obj->links));
+ BLI_freelistN(&(obj->queue));
+
+ /* free method groups and their methods */
+ for(vmg = vnode->methodgroups.first; vmg; vmg= vmg->next) {
+ free_verse_methodgroup(vmg);
+ }
+ BLI_freelistN(&(vnode->methodgroups));
+
+ /* free constraint between VerseNode and Object */
+ obj->post_object_free_constraint(vnode);
+
+ /* unsubscribe from receiving changes of transformation matrix */
+ if(session->flag & VERSE_CONNECTED)
+ verse_send_o_transform_unsubscribe(vnode->id, 0);
+}
+
+/*
+ * create new object data
+ */
+VObjectData *create_object_data(void)
+{
+ VObjectData *obj;
+
+ obj = (VObjectData*)MEM_mallocN(sizeof(VObjectData), "VerseObjectData");
+ obj->object = NULL;
+ BLI_dlist_init(&(obj->links));
+ obj->queue.first = obj->queue.last = NULL;
+ obj->flag = 0;
+
+ /* transformation matrix */
+ obj->pos[0] = obj->pos[1] = obj->pos[2] = 0.0;
+ obj->quat[0] = obj->quat[1] = obj->quat[2] = 0.0; obj->quat[3] = 1;
+ obj->scale[0] = obj->scale[1] = obj->scale[2] = 1.0;
+
+ /* transformation flags */
+ obj->flag |= POS_SEND_READY;
+ obj->flag |= ROT_SEND_READY;
+ obj->flag |= SCALE_SEND_READY;
+
+ /* set up pointers at post callback functions */
+/* obj->post_transform = post_transform;*/
+ obj->post_transform_pos = post_transform_pos;
+ obj->post_transform_rot = post_transform_rot;
+ obj->post_transform_scale = post_transform_scale;
+ obj->post_object_free_constraint = post_object_free_constraint;
+
+ return obj;
+}
+
+/*
+ * callback function:
+ */
+static void cb_o_transform_pos_real32(
+ void *user_data,
+ VNodeID node_id,
+ uint32 time_s,
+ uint32 time_f,
+ const real32 *pos,
+ const real32 *speed,
+ const real32 *accelerate,
+ const real32 *drag_normal,
+ real32 drag)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ float vec[3], dt, tmp;
+
+ if(!session) return;
+
+ vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ ((VObjectData*)vnode->data)->flag |= POS_SEND_READY;
+
+ /* verse server sends automaticaly some stupid default values ...
+ * we have to ignore these values, when we created this object node */
+ if( (vnode->owner_id==VN_OWNER_MINE) && !(((VObjectData*)vnode->data)->flag & POS_RECEIVE_READY) ) {
+ ((VObjectData*)vnode->data)->flag |= POS_RECEIVE_READY;
+ return;
+ }
+
+ dt = time_s + time_f/(0xffff);
+
+ if(pos) {
+ vec[0] = pos[0];
+ vec[1] = pos[1];
+ vec[2] = pos[2];
+ }
+ else {
+ vec[0] = 0.0f;
+ vec[1] = 0.0f;
+ vec[2] = 0.0f;
+ }
+
+ if(speed) {
+ vec[0] += speed[0]*dt;
+ vec[1] += speed[1]*dt;
+ vec[2] += speed[2]*dt;
+ }
+
+ if(accelerate) {
+ vec[0] += accelerate[0]*dt*dt/2;
+ vec[1] += accelerate[1]*dt*dt/2;
+ vec[2] += accelerate[2]*dt*dt/2;
+ }
+
+ /* we have to do rotation around x axis (+pi/2) to be
+ compatible with other verse applications */
+ tmp = vec[1];
+ vec[1] = -vec[2];
+ vec[2] = tmp;
+
+ if( (((VObjectData*)vnode->data)->pos[0] != vec[0]) ||
+ (((VObjectData*)vnode->data)->pos[1] != vec[1]) ||
+ (((VObjectData*)vnode->data)->pos[2] != vec[2]))
+ {
+ ((VObjectData*)vnode->data)->pos[0] = vec[0];
+ ((VObjectData*)vnode->data)->pos[1] = vec[1];
+ ((VObjectData*)vnode->data)->pos[2] = vec[2];
+
+ ((VObjectData*)vnode->data)->post_transform_pos(vnode);
+ }
+}
+
+/*
+ * callback function:
+ */
+static void cb_o_transform_rot_real32(
+ void *user_data,
+ VNodeID node_id,
+ uint32 time_s,
+ uint32 time_f,
+ const VNQuat32 *quat,
+ const VNQuat32 *speed,
+ const VNQuat32 *accelerate,
+ const VNQuat32 *drag_normal,
+ real32 drag)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ float temp[4]={0, 0, 0, 0}, v[4], dt; /* temporary quaternions */
+ float q[4]={cos(M_PI/4), -sin(M_PI/4), 0, 0}; /* conjugate quaternion (represents rotation
+ around x-axis +90 degrees) */
+
+ if(!session) return;
+
+ vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ ((VObjectData*)vnode->data)->flag |= ROT_SEND_READY;
+
+ /* verse server sends automaticaly some stupid default values ...
+ * we have to ignore these values, when we created this object node */
+ if( (vnode->owner_id==VN_OWNER_MINE) && !(((VObjectData*)vnode->data)->flag & ROT_RECEIVE_READY) ) {
+ ((VObjectData*)vnode->data)->flag |= ROT_RECEIVE_READY;
+ return;
+ }
+
+ dt = time_s + time_f/(0xffff);
+
+ if(quat) {
+ temp[1] = quat->x;
+ temp[2] = quat->y;
+ temp[3] = quat->z;
+ temp[0] = quat->w;
+ }
+
+ if(speed) {
+ temp[1] += speed->x*dt;
+ temp[2] += speed->y*dt;
+ temp[3] += speed->z*dt;
+ temp[0] += speed->w*dt;
+ }
+
+ if(accelerate) {
+ temp[1] += accelerate->x*dt*dt/2;
+ temp[2] += accelerate->y*dt*dt/2;
+ temp[3] += accelerate->z*dt*dt/2;
+ temp[0] += accelerate->w*dt*dt/2;
+ }
+
+ /* following matematical operation transform rotation:
+ *
+ * v' = quaternion * v * conjugate_quaternion
+ *
+ *, where v is original representation of rotation */
+
+ QuatMul(v, temp, q);
+ q[1]= sin(M_PI/4); /* normal quaternion */
+ QuatMul(temp, q, v);
+
+ if( (((VObjectData*)vnode->data)->quat[0] != temp[0]) ||
+ (((VObjectData*)vnode->data)->quat[1] != temp[1]) ||
+ (((VObjectData*)vnode->data)->quat[2] != temp[2]) ||
+ (((VObjectData*)vnode->data)->quat[3] != temp[3]))
+ {
+ QUATCOPY(((VObjectData*)vnode->data)->quat, temp);
+
+ ((VObjectData*)vnode->data)->post_transform_rot(vnode);
+ }
+}
+
+/*
+ * callback function:
+ */
+static void cb_o_transform_scale_real32(
+ void *user_data,
+ VNodeID node_id,
+ real32 scale_x,
+ real32 scale_y,
+ real32 scale_z)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ real32 tmp;
+
+ if(!session) return;
+
+ vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ ((VObjectData*)vnode->data)->flag |= SCALE_SEND_READY;
+
+ /* verse server sends automaticaly some stupid default values ...
+ * we have to ignore these values, when we created this object node */
+ if( (vnode->owner_id==VN_OWNER_MINE) && !(((VObjectData*)vnode->data)->flag & SCALE_RECEIVE_READY) ) {
+ ((VObjectData*)vnode->data)->flag |= SCALE_RECEIVE_READY;
+ return;
+ }
+
+ /* flip axis (verse spec) */
+ tmp = scale_y;
+ scale_y = scale_z;
+ scale_z = tmp;
+
+ /* z and y axis are flipped here too */
+ if( (((VObjectData*)vnode->data)->scale[0] != scale_x) ||
+ (((VObjectData*)vnode->data)->scale[1] != scale_y) ||
+ (((VObjectData*)vnode->data)->scale[2] != scale_z))
+ {
+ ((VObjectData*)vnode->data)->scale[0] = scale_x;
+ ((VObjectData*)vnode->data)->scale[1] = scale_y;
+ ((VObjectData*)vnode->data)->scale[2] = scale_z;
+
+ ((VObjectData*)vnode->data)->post_transform_scale(vnode);
+ }
+}
+
+/*
+ * callback function: link between object node and some other node was created
+ */
+static void cb_o_link_set(
+ void *user_data,
+ VNodeID node_id,
+ uint16 link_id,
+ VNodeID link,
+ const char *label,
+ uint32 target_id)
+{
+ struct VLink *vlink;
+ struct VNode *source;
+ struct VNode *target;
+
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+
+ if(!session) return;
+
+ source = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+ target = BLI_dlist_find_link(&(session->nodes), (unsigned int)link);
+
+ if(!(source && target)) return;
+
+ vlink = ((VObjectData*)source->data)->queue.first;
+
+ if(vlink && (vlink->source==source) && (vlink->target==target)) {
+ /* remove VerseLink from sending queue */
+ BLI_remlink(&(((VObjectData*)source->data)->queue), vlink);
+ /* add VerseLink to dynamic list of VerseLinks */
+ BLI_dlist_add_item_index(&(((VObjectData*)source->data)->links), vlink, (unsigned int)link_id);
+ /* send next link from sending queue */
+ if(((VObjectData*)source->data)->queue.first)
+ send_verse_link(((VObjectData*)source->data)->queue.first);
+ /* set up VerseLink variables */
+ vlink->flag = 0;
+ vlink->id = link_id;
+ vlink->target_id = target_id;
+ }
+ else {
+ /* create new VerseLink */
+ vlink = create_verse_link(session, source, target, link_id, target_id, label);
+ /* add VerseLink to dynamic list of VerseLinks */
+ BLI_dlist_add_item_index(&(((VObjectData*)source->data)->links), vlink, (unsigned int)link_id);
+ }
+
+ target->counter++;
+
+ vlink->post_link_set(vlink);
+}
+
+/*
+ * callback function: destroy link between two VerseNodes
+ */
+static void cb_o_link_destroy(
+ void *user_data,
+ VNodeID node_id,
+ uint16 link_id)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VNode *vnode;
+ struct VLink *vlink;
+
+ if(!session) return;
+
+ vnode = BLI_dlist_find_link(&(session->nodes), (unsigned int)node_id);
+
+ vlink = BLI_dlist_find_link(&(((VObjectData*)vnode->data)->links), link_id);
+
+ if(vlink) {
+ vlink->target->counter--;
+ free_verse_link_data(vlink);
+ BLI_dlist_free_item(&(((VObjectData*)vnode->data)->links), link_id);
+ }
+
+ vlink->post_link_destroy(vlink);
+}
+
+void set_object_callbacks(void)
+{
+ /* position of object was changed */
+ verse_callback_set(verse_send_o_transform_pos_real32, cb_o_transform_pos_real32, NULL);
+ /* rotation of object was changed */
+ verse_callback_set(verse_send_o_transform_rot_real32, cb_o_transform_rot_real32, NULL);
+ /* size of object was changed */
+ verse_callback_set(verse_send_o_transform_scale_real32, cb_o_transform_scale_real32, NULL);
+ /* new link between nodes was created */
+ verse_callback_set(verse_send_o_link_set, cb_o_link_set, NULL);
+ /* link between nodes was destroyed */
+ verse_callback_set(verse_send_o_link_destroy, cb_o_link_destroy, NULL);
+}
+
+#endif
diff --git a/source/blender/blenkernel/intern/verse_session.c b/source/blender/blenkernel/intern/verse_session.c
new file mode 100644
index 00000000000..1226fffd929
--- /dev/null
+++ b/source/blender/blenkernel/intern/verse_session.c
@@ -0,0 +1,480 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributor(s): Jiri Hnidek.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifdef WITH_VERSE
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h" /* temp */
+#include "DNA_listBase.h"
+#include "DNA_screen_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BLI_dynamiclist.h"
+#include "BLI_blenlib.h"
+
+#include "BIF_screen.h"
+#include "BIF_verse.h"
+
+#include "BKE_global.h"
+#include "BKE_verse.h"
+
+struct ListBase session_list={NULL, NULL};
+struct ListBase server_list={NULL, NULL};
+
+static int cb_ping_registered = 0;
+
+/* list of static function prototypes */
+static void cb_connect_terminate(const char *address, const char *bye);
+static void cb_connect_accept(void *user_data, uint32 avatar, void *address, void *connection, const uint8 *host_id);
+static void set_all_callbacks(void);
+static void free_verse_session_data(struct VerseSession *session);
+static void add_verse_server(VMSServer *server);
+static void check_connection_state(struct VerseServer *server);
+
+static void check_connection_state(struct VerseServer *server)
+{
+ struct VerseSession *session;
+ session = session_list.first;
+ while(session) {
+ if(strcmp(server->ip,session->address)==0) {
+ server->flag = session->flag;
+ return;
+ }
+ session = session->next;
+ }
+}
+/*
+ * add verse server to server_list. Prevents duplicate
+ * entries
+ */
+static void add_verse_server(VMSServer *server)
+{
+ struct VerseServer *iter, *niter;
+ VerseServer *newserver;
+ const char *name = verse_ms_field_value(server, "DE");
+ iter = server_list.first;
+
+ while(iter) {
+ niter = iter->next;
+ if(strcmp(iter->ip, server->ip)==0) {
+ return;
+ }
+ iter = niter;
+ }
+
+ newserver = (VerseServer *)MEM_mallocN(sizeof(VerseServer), "VerseServer");
+ newserver->ip = (char *)MEM_mallocN(sizeof(char)*(strlen(server->ip)+1), "VerseServer ip");
+ strcpy(newserver->ip, server->ip);
+
+ if(name) {
+ newserver->name = (char *)MEM_mallocN(sizeof(char)*(strlen(name)+strlen(newserver->ip)+4), "VerseServer name");
+ strcpy(newserver->name, name);
+ strcat(newserver->name, " (");
+ strcat(newserver->name, newserver->ip);
+ strcat(newserver->name, ")");
+ }
+
+ newserver->flag = 0;
+ check_connection_state(newserver);
+
+ printf("Adding new verse server: %s at %s\n", newserver->name, newserver->ip);
+
+ BLI_addtail(&server_list, newserver);
+ post_server_add();
+}
+
+/*
+ * callback function for ping
+ */
+static void cb_ping(void *user, const char *address, const char *message)
+{
+ VMSServer **servers = verse_ms_list_parse(message);
+ if(servers != NULL)
+ {
+ int i;
+
+ for(i = 0; servers[i] != NULL; i++)
+ add_verse_server(servers[i]);
+
+ free(servers);
+ }
+}
+
+/*
+ * callback function for connection terminated
+ */
+static void cb_connect_terminate(const char *address, const char *bye)
+{
+ VerseSession *session = (VerseSession*)current_verse_session();
+
+ if(!session) return;
+
+ /* remove session from list of session */
+ BLI_remlink(&session_list, session);
+ /* do post connect operations */
+ session->post_connect_terminated(session);
+ /* free session data */
+ free_verse_session_data(session);
+ /* free session */
+ MEM_freeN(session);
+}
+
+/*
+ * callback function for accepted connection to verse server
+ */
+static void cb_connect_accept(
+ void *user_data,
+ uint32 avatar,
+ void *address,
+ void *connection,
+ const uint8 *host_id)
+{
+ struct VerseSession *session = (VerseSession*)current_verse_session();
+ struct VerseServer *server = server_list.first;
+ uint32 i, mask=0;
+
+ if(!session) return;
+
+ session->flag |= VERSE_CONNECTED;
+ session->flag &= ~VERSE_CONNECTING;
+
+ while(server) {
+ if(strcmp(session->address, server->ip)==0) {
+ server->flag |= VERSE_CONNECTED;
+ server->flag &= ~VERSE_CONNECTING;
+ server->session = session;
+ break;
+ }
+ server = server->next;
+ }
+
+ printf("\tBlender is connected to verse server: %s\n", (char*)address);
+ printf("\tVerseSession->counter: %d\n", session->counter);
+
+ session->avatar = avatar;
+
+ session->post_connect_accept(session);
+
+ for(i = 0; i < V_NT_NUM_TYPES; i++)
+ mask = mask | (1 << i);
+ verse_send_node_index_subscribe(mask);
+ verse_send_node_subscribe(session->avatar); /* subscribe to avatar node, as well */
+
+ /* create our own method group and method */
+ /*verse_send_o_method_group_create(session->avatar, ~0, "tawk-client");*/
+}
+
+/*
+ * set up all callbacks for sessions
+ */
+void set_verse_session_callbacks(void)
+{
+ /* connection */
+ verse_callback_set(verse_send_connect_accept, cb_connect_accept, NULL);
+ /* connection was terminated */
+ verse_callback_set(verse_send_connect_terminate, cb_connect_terminate, NULL);
+
+}
+
+/*
+ * set all callbacks used in Blender
+ */
+static void set_all_callbacks(void)
+{
+ /* set up all callbacks for sessions */
+ set_verse_session_callbacks();
+
+ /* set up callbacks for nodes */
+ set_node_callbacks();
+
+ /* set up all callbacks for object nodes */
+ set_object_callbacks();
+
+ /* set up all callbacks for geometry nodes */
+ set_geometry_callbacks();
+
+ /* set up all callbacks for bitmap nodes */
+ set_bitmap_callbacks();
+
+ /* set up all callbacks for method groups and methods */
+ set_method_callbacks();
+}
+
+/*
+ * this function sends and receive all packets for all sessions
+ */
+void b_verse_update(void)
+{
+ VerseSession *session, *next_session;
+
+ session = session_list.first;
+ while(session){
+ next_session = session->next;
+ verse_session_set(session->vsession);
+ if((session->flag & VERSE_CONNECTED) || (session->flag & VERSE_CONNECTING)) {
+ verse_callback_update(10);
+ session->post_connect_update(session);
+ }
+ session = next_session;
+ }
+ if(cb_ping_registered>0) {
+ verse_callback_update(10);
+ }
+}
+
+/*
+ * returns VerseSession coresponding to vsession pointer
+ */
+VerseSession *versesession_from_vsession(VSession *vsession)
+{
+ struct VerseSession *session;
+
+ session = session_list.first;
+
+ while(session) {
+ if(session->vsession==vsession) return session;
+ session = session->next;
+ }
+
+ return session;
+}
+
+/*
+ * returns pointer at current VerseSession
+ */
+VerseSession *current_verse_session(void)
+{
+ struct VerseSession *session;
+ VSession vsession = verse_session_get();
+
+ session = session_list.first;
+
+ while(session){
+ if(session->vsession == vsession)
+ return session;
+ session = session->next;
+ }
+
+ printf("error: non-existing SESSION occured!\n");
+ return NULL;
+}
+
+/*
+ * free VerseSession
+ */
+static void free_verse_session_data(VerseSession *session)
+{
+ struct VNode *vnode;
+
+ /* free data of all nodes */
+ vnode = session->nodes.lb.first;
+ while(vnode){
+ free_verse_node_data(vnode);
+ vnode = vnode->next;
+ }
+
+ /* free data of nodes waiting in queue */
+ vnode = session->queue.first;
+ while(vnode){
+ free_verse_node_data(vnode);
+ vnode = vnode->next;
+ }
+
+ /* free all VerseNodes */
+ BLI_dlist_destroy(&(session->nodes));
+ /* free all VerseNodes waiting in queque */
+ BLI_freelistN(&(session->queue));
+
+ /* free name of verse host for this session */
+ MEM_freeN(session->address);
+}
+
+/*
+ * free VerseSession
+ */
+void free_verse_session(VerseSession *session)
+{
+ /* remove session from session list*/
+ BLI_remlink(&session_list, session);
+ /* do post terminated operations */
+ session->post_connect_terminated(session);
+ /* free session data (nodes, layers) */
+ free_verse_session_data(session);
+ /* free session */
+ MEM_freeN(session);
+}
+
+/*
+ * create new verse session and return coresponding data structure
+ */
+VerseSession *create_verse_session(
+ const char *name,
+ const char *pass,
+ const char *address,
+ uint8 *expected_key)
+{
+ struct VerseSession *session;
+ VSession *vsession;
+
+ vsession = verse_send_connect(name, pass, address, expected_key);
+
+ if(!vsession) return NULL;
+
+ session = (VerseSession*)MEM_mallocN(sizeof(VerseSession), "VerseSession");
+
+ session->flag = VERSE_CONNECTING;
+
+ session->vsession = vsession;
+ session->avatar = -1;
+
+ session->address = (char*)MEM_mallocN(sizeof(char)*(strlen(address)+1),"session adress name");
+ strcpy(session->address, address);
+
+ session->connection = NULL;
+ session->host_id = NULL;
+ session->counter = 0;
+
+ /* initialize dynamic list of nodes and node queue */
+ BLI_dlist_init(&(session->nodes));
+ session->queue.first = session->queue.last = NULL;
+
+ /* set up all client dependent functions */
+ session->post_connect_accept = post_connect_accept;
+ session->post_connect_terminated = post_connect_terminated;
+ session->post_connect_update = post_connect_update;
+
+ post_server_add();
+
+ return session;
+}
+
+/*
+ * end verse session and free all session data
+ */
+void end_verse_session(VerseSession *session)
+{
+ /* send terminate command to verse server */
+ verse_send_connect_terminate(session->address, "blender: bye bye");
+ /* update callbacks */
+ verse_callback_update(1000);
+ /* send destroy session command to verse server */
+ verse_session_destroy(session->vsession);
+ /* set up flag of verse session */
+ session->flag &= ~VERSE_CONNECTED;
+ /* do post connect operations */
+ session->post_connect_terminated(session);
+ /* free structure of verse session */
+ free_verse_session(session);
+}
+
+void free_all_servers(void)
+{
+ VerseServer *server, *nextserver;
+
+ server = server_list.first;
+
+ while(server) {
+ nextserver = server->next;
+ BLI_remlink(&server_list, server);
+ MEM_freeN(server->name);
+ MEM_freeN(server->ip);
+ MEM_freeN(server);
+ server = nextserver;
+ }
+
+ BLI_freelistN(&server_list);
+}
+
+/*
+ * end connection to all verse hosts (servers) ... free all VerseSessions
+ * free all VerseServers
+ */
+void end_all_verse_sessions(void)
+{
+ VerseSession *session,*nextsession;
+
+ session = session_list.first;
+
+ while(session) {
+ nextsession= session->next;
+ end_verse_session(session);
+ /* end next session */
+ session = nextsession;
+ }
+
+ BLI_freelistN(&session_list);
+
+ free_all_servers();
+}
+
+/*
+ * do a get from ms
+ */
+void b_verse_ms_get(void)
+{
+ if(cb_ping_registered==0) {
+ /* handle ping messages (for master server) */
+ verse_callback_set(verse_send_ping, cb_ping, NULL);
+ add_screenhandler(G.curscreen, SCREEN_HANDLER_VERSE, 1);
+ cb_ping_registered++;
+ }
+ free_all_servers();
+
+ verse_ms_get_send(U.versemaster, VERSE_MS_FIELD_DESCRIPTION, NULL);
+ verse_callback_update(10);
+}
+
+/*
+ * connect to verse host, set up all callbacks, create session
+ */
+void b_verse_connect(char *address)
+{
+ VerseSession *session = NULL;
+
+ /* if no session was created before, then set up all callbacks */
+ if((session_list.first==NULL) && (session_list.last==NULL))
+ set_all_callbacks();
+
+ /* create new session */
+ if(address)
+ session = create_verse_session("Blender", "pass", address, NULL);
+
+ if(session) {
+ /* add new session to the list of sessions */
+ BLI_addtail(&session_list, session);
+
+ /* add verse handler if this is first session */
+ if(session_list.first == session_list.last)
+ add_screenhandler(G.curscreen, SCREEN_HANDLER_VERSE, 1);
+
+ }
+}
+
+#endif
diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c
new file mode 100644
index 00000000000..625ca57dbf3
--- /dev/null
+++ b/source/blender/blenkernel/intern/world.c
@@ -0,0 +1,187 @@
+
+/* world.c
+ *
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <string.h>
+#include <math.h>
+#include "MEM_guardedalloc.h"
+
+#include "DNA_world_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_scriptlink_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_camera_types.h"
+
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "BKE_bad_level_calls.h"
+#include "BKE_utildefines.h"
+
+#include "BKE_library.h"
+#include "BKE_world.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_icons.h"
+
+#include "BPY_extern.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+void free_world(World *wrld)
+{
+ MTex *mtex;
+ int a;
+
+ BPY_free_scriptlink(&wrld->scriptlink);
+
+ for(a=0; a<MAX_MTEX; a++) {
+ mtex= wrld->mtex[a];
+ if(mtex && mtex->tex) mtex->tex->id.us--;
+ if(mtex) MEM_freeN(mtex);
+ }
+ BKE_previewimg_free(&wrld->preview);
+
+ wrld->ipo= 0;
+ BKE_icon_delete((struct ID*)wrld);
+ wrld->id.icon_id = 0;
+}
+
+
+World *add_world(char *name)
+{
+ World *wrld;
+
+ wrld= alloc_libblock(&G.main->world, ID_WO, name);
+
+ wrld->horb= 0.6f;
+ wrld->skytype= WO_SKYBLEND;
+ wrld->stardist= 15.0f;
+ wrld->starsize= 2.0f;
+ wrld->gravity= 9.8f;
+
+ wrld->exp= 0.0f;
+ wrld->exposure=wrld->range= 1.0f;
+
+ wrld->aodist= 5.0;
+ wrld->aosamp= 5;
+ wrld->aoenergy= 1.0;
+ wrld->aobias= 0.05;
+ wrld->ao_samp_method = WO_AOSAMP_HAMMERSLEY;
+
+
+ wrld->physicsEngine= WOPHY_BULLET;//WOPHY_SUMO; Bullet by default
+ wrld->preview = NULL;
+
+ return wrld;
+}
+
+World *copy_world(World *wrld)
+{
+ World *wrldn;
+ int a;
+
+ wrldn= copy_libblock(wrld);
+
+ for(a=0; a<MAX_MTEX; a++) {
+ if(wrld->mtex[a]) {
+ wrldn->mtex[a]= MEM_mallocN(sizeof(MTex), "copymaterial");
+ memcpy(wrldn->mtex[a], wrld->mtex[a], sizeof(MTex));
+ id_us_plus((ID *)wrldn->mtex[a]->tex);
+ }
+ }
+
+ if (wrld->preview) wrldn->preview = BKE_previewimg_copy(wrld->preview);
+
+ BPY_copy_scriptlink(&wrld->scriptlink);
+
+ id_us_plus((ID *)wrldn->ipo);
+
+ return wrldn;
+}
+
+void make_local_world(World *wrld)
+{
+ Scene *sce;
+ World *wrldn;
+ int local=0, lib=0;
+
+ /* - only lib users: do nothing
+ * - only local users: set flag
+ * - mixed: make copy
+ */
+
+ if(wrld->id.lib==0) return;
+ if(wrld->id.us==1) {
+ wrld->id.lib= 0;
+ wrld->id.flag= LIB_LOCAL;
+ new_id(0, (ID *)wrld, 0);
+ return;
+ }
+
+ sce= G.main->scene.first;
+ while(sce) {
+ if(sce->world==wrld) {
+ if(sce->id.lib) lib= 1;
+ else local= 1;
+ }
+ sce= sce->id.next;
+ }
+
+ if(local && lib==0) {
+ wrld->id.lib= 0;
+ wrld->id.flag= LIB_LOCAL;
+ new_id(0, (ID *)wrld, 0);
+ }
+ else if(local && lib) {
+ wrldn= copy_world(wrld);
+ wrldn->id.us= 0;
+
+ sce= G.main->scene.first;
+ while(sce) {
+ if(sce->world==wrld) {
+ if(sce->id.lib==0) {
+ sce->world= wrldn;
+ wrldn->id.us++;
+ wrld->id.us--;
+ }
+ }
+ sce= sce->id.next;
+ }
+ }
+}
diff --git a/source/blender/blenkernel/intern/writeavi.c b/source/blender/blenkernel/intern/writeavi.c
new file mode 100644
index 00000000000..bd6859973b1
--- /dev/null
+++ b/source/blender/blenkernel/intern/writeavi.c
@@ -0,0 +1,223 @@
+/**
+ * Functions for writing avi-format files.
+ * Added interface for generic movie support (ton)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Robert Wenzlaff
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ *
+ */
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_scene_types.h"
+
+#include "BLI_blenlib.h"
+
+#include "BKE_global.h"
+#include "BKE_writeavi.h"
+#include "AVI_avi.h"
+
+
+/* ********************** general blender movie support ***************************** */
+
+#ifdef WITH_QUICKTIME
+#include "quicktime_export.h"
+#endif
+
+#if defined(_WIN32) && !defined(FREE_WINDOWS)
+#include "BIF_writeavicodec.h"
+#endif
+
+#ifdef WITH_FFMPEG
+#include "BKE_writeffmpeg.h"
+#endif
+
+#include "BKE_writeframeserver.h"
+
+bMovieHandle *BKE_get_movie_handle(int imtype)
+{
+ static bMovieHandle mh;
+
+ /* set the default handle, as builtin */
+ mh.start_movie= start_avi;
+ mh.append_movie= append_avi;
+ mh.end_movie= end_avi;
+ mh.get_next_frame = 0;
+
+ /* do the platform specific handles */
+#ifdef __sgi
+ if (imtype == R_MOVIE) {
+
+ }
+#endif
+#if defined(_WIN32) && !defined(FREE_WINDOWS)
+ if (imtype == R_AVICODEC) {
+ mh.start_movie= start_avi_codec;
+ mh.append_movie= append_avi_codec;
+ mh.end_movie= end_avi_codec;
+ }
+#endif
+#ifdef WITH_QUICKTIME
+ if (imtype == R_QUICKTIME) {
+ mh.start_movie= start_qt;
+ mh.append_movie= append_qt;
+ mh.end_movie= end_qt;
+ }
+#endif
+#ifdef WITH_FFMPEG
+ if (imtype == R_FFMPEG) {
+ mh.start_movie = start_ffmpeg;
+ mh.append_movie = append_ffmpeg;
+ mh.end_movie = end_ffmpeg;
+ }
+#endif
+ if (imtype == R_FRAMESERVER) {
+ mh.start_movie = start_frameserver;
+ mh.append_movie = append_frameserver;
+ mh.end_movie = end_frameserver;
+ mh.get_next_frame = frameserver_loop;
+ }
+
+ return &mh;
+}
+
+/* ****************************************************************** */
+
+
+static AviMovie *avi=NULL;
+static int sframe;
+
+void makeavistring (RenderData *rd, char *string)
+{
+ char txt[64];
+
+ if (string==0) return;
+
+ strcpy(string, rd->pic);
+ BLI_convertstringcode(string, G.sce, rd->cfra);
+
+ BLI_make_existing_file(string);
+
+ if (BLI_strcasecmp(string + strlen(string) - 4, ".avi")) {
+ sprintf(txt, "%04d_%04d.avi", (rd->sfra) , (rd->efra) );
+ strcat(string, txt);
+ }
+}
+
+void start_avi(RenderData *rd, int rectx, int recty)
+{
+ int x, y;
+ char name[256];
+ AviFormat format;
+ int quality;
+ double framerate;
+
+ makeavistring(rd, name);
+
+ sframe = (rd->sfra);
+ x = rectx;
+ y = recty;
+
+ quality= rd->quality;
+ framerate= (double) rd->frs_sec / (double) rd->frs_sec_base;
+
+ avi = MEM_mallocN (sizeof(AviMovie), "avimovie");
+
+ /* RPW 11-21-2002
+ if (rd->imtype != AVI_FORMAT_MJPEG) format = AVI_FORMAT_AVI_RGB;
+ */
+ if (rd->imtype != R_AVIJPEG ) format = AVI_FORMAT_AVI_RGB;
+ else format = AVI_FORMAT_MJPEG;
+
+ if (AVI_open_compress (name, avi, 1, format) != AVI_ERROR_NONE) {
+ printf("cannot open or start AVI movie file");
+ MEM_freeN (avi);
+ avi = NULL;
+ return;
+ }
+
+ AVI_set_compress_option (avi, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_WIDTH, &x);
+ AVI_set_compress_option (avi, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_HEIGHT, &y);
+ AVI_set_compress_option (avi, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_QUALITY, &quality);
+ AVI_set_compress_option (avi, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_FRAMERATE, &framerate);
+
+ avi->interlace= 0;
+ avi->odd_fields= 0;
+/* avi->interlace= rd->mode & R_FIELDS; */
+/* avi->odd_fields= (rd->mode & R_ODDFIELD)?1:0; */
+
+ printf("Created avi: %s\n", name);
+}
+
+void append_avi(int frame, int *pixels, int rectx, int recty)
+{
+ unsigned int *rt1, *rt2, *rectot;
+ int x, y;
+ char *cp, rt;
+
+ if (avi == NULL) {
+ G.afbreek = 1;
+ return;
+ }
+
+ /* note that libavi free's the buffer... stupid interface - zr */
+ rectot= MEM_mallocN(rectx*recty*sizeof(int), "rectot");
+ rt1= rectot;
+ rt2= (unsigned int*)pixels + (recty-1)*rectx;
+ /* flip y and convert to abgr */
+ for (y=0; y < recty; y++, rt1+= rectx, rt2-= rectx) {
+ memcpy (rt1, rt2, rectx*sizeof(int));
+
+ cp= (char *)rt1;
+ for(x= rectx; x>0; x--) {
+ rt= cp[0];
+ cp[0]= cp[3];
+ cp[3]= rt;
+ rt= cp[1];
+ cp[1]= cp[2];
+ cp[2]= rt;
+ cp+= 4;
+ }
+ }
+
+ AVI_write_frame (avi, (frame-sframe), AVI_FORMAT_RGB32, rectot, rectx*recty*4);
+// printf ("added frame %3d (frame %3d in avi): ", frame, frame-sframe);
+}
+
+void end_avi(void)
+{
+ if (avi == NULL) return;
+
+ AVI_close_compress (avi);
+ MEM_freeN (avi);
+ avi= NULL;
+}
diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c
new file mode 100644
index 00000000000..cbaf1f8c605
--- /dev/null
+++ b/source/blender/blenkernel/intern/writeffmpeg.c
@@ -0,0 +1,827 @@
+/*
+ * ffmpeg-write support
+ *
+ * Partial Copyright (c) 2006 Peter Schlaile
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+
+#ifdef WITH_FFMPEG
+#include <string.h>
+#include <stdio.h>
+
+#if defined(_WIN32) && defined(_DEBUG) && !defined(__MINGW32__) && !defined(__CYGWIN__)
+/* This does not seem necessary or present on MSVC 8, but may be needed in earlier versions? */
+#if _MSC_VER < 1400
+#include <stdint.h>
+#endif
+#endif
+
+#include <stdlib.h>
+
+#include <ffmpeg/avformat.h>
+#include <ffmpeg/avcodec.h>
+#include <ffmpeg/rational.h>
+#include <ffmpeg/swscale.h>
+
+#if LIBAVFORMAT_VERSION_INT < (49 << 16)
+#define FFMPEG_OLD_FRAME_RATE 1
+#else
+#define FFMPEG_CODEC_IS_POINTER 1
+#define FFMPEG_CODEC_TIME_BASE 1
+#endif
+
+#if defined(WIN32) && (!(defined snprintf))
+#define snprintf _snprintf
+#endif
+
+#include "BKE_writeffmpeg.h"
+
+#include "MEM_guardedalloc.h"
+#include "BLI_blenlib.h"
+
+#include "BKE_bad_level_calls.h"
+#include "BKE_global.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "BSE_seqaudio.h"
+
+#include "DNA_scene_types.h"
+#include "blendef.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+extern void do_init_ffmpeg();
+void makeffmpegstring(char* string);
+
+static int ffmpeg_type = 0;
+static int ffmpeg_codec = CODEC_ID_MPEG4;
+static int ffmpeg_audio_codec = CODEC_ID_MP2;
+static int ffmpeg_video_bitrate = 1150;
+static int ffmpeg_audio_bitrate = 128;
+static int ffmpeg_gop_size = 12;
+static int ffmpeg_multiplex_audio = 1;
+static int ffmpeg_autosplit = 0;
+static int ffmpeg_autosplit_count = 0;
+
+static AVFormatContext* outfile = 0;
+static AVStream* video_stream = 0;
+static AVStream* audio_stream = 0;
+static AVFrame* current_frame = 0;
+static struct SwsContext *img_convert_ctx = 0;
+
+static uint8_t* video_buffer = 0;
+static int video_buffersize = 0;
+
+static uint8_t* audio_input_buffer = 0;
+static int audio_input_frame_size = 0;
+static uint8_t* audio_output_buffer = 0;
+static int audio_outbuf_size = 0;
+
+static RenderData *ffmpeg_renderdata = 0;
+
+#define FFMPEG_AUTOSPLIT_SIZE 2000000000
+
+/* Delete a picture buffer */
+
+static void delete_picture(AVFrame* f)
+{
+ if (f) {
+ if (f->data[0]) MEM_freeN(f->data[0]);
+ av_free(f);
+ }
+}
+
+#ifdef FFMPEG_CODEC_IS_POINTER
+static AVCodecContext* get_codec_from_stream(AVStream* stream)
+{
+ return stream->codec;
+}
+#else
+static AVCodecContext* get_codec_from_stream(AVStream* stream)
+{
+ return &stream->codec;
+}
+#endif
+
+static int write_audio_frame(void)
+{
+ AVCodecContext* c = NULL;
+ AVPacket pkt;
+
+ c = get_codec_from_stream(audio_stream);
+
+ audiostream_fill(audio_input_buffer,
+ audio_input_frame_size
+ * sizeof(short) * c->channels);
+
+ av_init_packet(&pkt);
+
+ pkt.size = avcodec_encode_audio(c, audio_output_buffer,
+ audio_outbuf_size,
+ (short*) audio_input_buffer);
+ pkt.data = audio_output_buffer;
+#ifdef FFMPEG_CODEC_TIME_BASE
+ pkt.pts = av_rescale_q(c->coded_frame->pts,
+ c->time_base, audio_stream->time_base);
+#else
+ pkt.pts = c->coded_frame->pts;
+#endif
+ fprintf(stderr, "Audio Frame PTS: %lld\n", pkt.pts);
+
+ pkt.stream_index = audio_stream->index;
+ pkt.flags |= PKT_FLAG_KEY;
+ if (av_interleaved_write_frame(outfile, &pkt) != 0) {
+ error("Error writing audio packet");
+ return -1;
+ }
+ return 0;
+}
+
+/* Allocate a temporary frame */
+static AVFrame* alloc_picture(int pix_fmt, int width, int height)
+{
+ AVFrame* f;
+ uint8_t* buf;
+ int size;
+
+ /* allocate space for the struct */
+ f = avcodec_alloc_frame();
+ if (!f) return NULL;
+ size = avpicture_get_size(pix_fmt, width, height);
+ /* allocate the actual picture buffer */
+ buf = MEM_mallocN(size, "AVFrame buffer");
+ if (!buf) {
+ free(f);
+ return NULL;
+ }
+ avpicture_fill((AVPicture*)f, buf, pix_fmt, width, height);
+ return f;
+}
+
+/* Get the correct file extensions for the requested format,
+ first is always desired guess_format parameter */
+static const char** get_file_extensions(int format)
+{
+ switch(format) {
+ case FFMPEG_DV: {
+ static const char * rv[] = { ".dv", NULL };
+ return rv;
+ }
+ case FFMPEG_MPEG1: {
+ static const char * rv[] = { ".mpg", ".mpeg", NULL };
+ return rv;
+ }
+ case FFMPEG_MPEG2: {
+ static const char * rv[] = { ".dvd", ".vob", ".mpg", ".mpeg",
+ NULL };
+ return rv;
+ }
+ case FFMPEG_MPEG4: {
+ static const char * rv[] = { ".mp4", ".mpg", ".mpeg", NULL };
+ return rv;
+ }
+ case FFMPEG_AVI: {
+ static const char * rv[] = { ".avi", NULL };
+ return rv;
+ }
+ case FFMPEG_MOV: {
+ static const char * rv[] = { ".mov", NULL };
+ return rv;
+ }
+ case FFMPEG_H264: {
+ /* FIXME: avi for now... */
+ static const char * rv[] = { ".avi", NULL };
+ return rv;
+ }
+
+ case FFMPEG_XVID: {
+ /* FIXME: avi for now... */
+ static const char * rv[] = { ".avi", NULL };
+ return rv;
+ }
+ default:
+ return NULL;
+ }
+}
+
+/* Write a frame to the output file */
+static void write_video_frame(AVFrame* frame)
+{
+ int outsize = 0;
+ int ret;
+ AVCodecContext* c = get_codec_from_stream(video_stream);
+#ifdef FFMPEG_CODEC_TIME_BASE
+ frame->pts = G.scene->r.cfra - G.scene->r.sfra;
+#endif
+
+ outsize = avcodec_encode_video(c, video_buffer, video_buffersize,
+ frame);
+ if (outsize != 0) {
+ AVPacket packet;
+ av_init_packet(&packet);
+
+#ifdef FFMPEG_CODEC_TIME_BASE
+ packet.pts = av_rescale_q(c->coded_frame->pts,
+ c->time_base,
+ video_stream->time_base);
+#else
+ packet.pts = c->coded_frame->pts;
+#endif
+ fprintf(stderr, "Video Frame PTS: %lld\n", packet.pts);
+ if (c->coded_frame->key_frame)
+ packet.flags |= PKT_FLAG_KEY;
+ packet.stream_index = video_stream->index;
+ packet.data = video_buffer;
+ packet.size = outsize;
+ ret = av_interleaved_write_frame(outfile, &packet);
+ } else ret = 0;
+ if (ret != 0) {
+ G.afbreek = 1;
+ error("Error writing frame");
+ }
+}
+
+/* read and encode a frame of audio from the buffer */
+static AVFrame* generate_video_frame(uint8_t* pixels)
+{
+ uint8_t* rendered_frame;
+
+ AVCodecContext* c = get_codec_from_stream(video_stream);
+ int width = c->width;
+ int height = c->height;
+ AVFrame* rgb_frame;
+
+ if (c->pix_fmt != PIX_FMT_RGBA32) {
+ rgb_frame = alloc_picture(PIX_FMT_RGBA32, width, height);
+ if (!rgb_frame) {
+ G.afbreek=1;
+ error("Couldn't allocate temporary frame");
+ return NULL;
+ }
+ } else {
+ rgb_frame = current_frame;
+ }
+
+ rendered_frame = pixels;
+
+ /* Do RGBA-conversion and flipping in one step depending
+ on CPU-Endianess */
+
+ if (G.order == L_ENDIAN) {
+ int y;
+ for (y = 0; y < height; y++) {
+ uint8_t* target = rgb_frame->data[0]
+ + width * 4 * (height - y - 1);
+ uint8_t* src = rendered_frame + width * 4 * y;
+ uint8_t* end = src + width * 4;
+ while (src != end) {
+ target[3] = src[3];
+ target[2] = src[0];
+ target[1] = src[1];
+ target[0] = src[2];
+
+ target += 4;
+ src += 4;
+ }
+ }
+ } else {
+ int y;
+ for (y = 0; y < height; y++) {
+ uint8_t* target = rgb_frame->data[0]
+ + width * 4 * (height - y - 1);
+ uint8_t* src = rendered_frame + width * 4 * y;
+ uint8_t* end = src + width * 4;
+ while (src != end) {
+ target[3] = src[2];
+ target[2] = src[1];
+ target[1] = src[0];
+ target[0] = src[3];
+
+ target += 4;
+ src += 4;
+ }
+ }
+ }
+
+ if (c->pix_fmt != PIX_FMT_RGBA32) {
+ sws_scale(img_convert_ctx, rgb_frame->data,
+ rgb_frame->linesize, 0, c->height,
+ current_frame->data, current_frame->linesize);
+ delete_picture(rgb_frame);
+ }
+ return current_frame;
+}
+
+/* prepare a video stream for the output file */
+
+static AVStream* alloc_video_stream(int codec_id, AVFormatContext* of,
+ int rectx, int recty)
+{
+ AVStream* st;
+ AVCodecContext* c;
+ AVCodec* codec;
+ st = av_new_stream(of, 0);
+ if (!st) return NULL;
+
+ /* Set up the codec context */
+
+ c = get_codec_from_stream(st);
+ c->codec_id = codec_id;
+ c->codec_type = CODEC_TYPE_VIDEO;
+
+
+ /* Get some values from the current render settings */
+
+ c->width = rectx;
+ c->height = recty;
+
+#ifdef FFMPEG_CODEC_TIME_BASE
+ /* FIXME: Really bad hack (tm) for NTSC support */
+ if (ffmpeg_type == FFMPEG_DV && G.scene->r.frs_sec != 25) {
+ c->time_base.den = 2997;
+ c->time_base.num = 100;
+ } else if ((double) ((int) G.scene->r.frs_sec_base) ==
+ G.scene->r.frs_sec_base) {
+ c->time_base.den = G.scene->r.frs_sec;
+ c->time_base.num = (int) G.scene->r.frs_sec_base;
+ } else {
+ c->time_base.den = G.scene->r.frs_sec * 100000;
+ c->time_base.num = ((double) G.scene->r.frs_sec_base) * 100000;
+ }
+#else
+ /* FIXME: Really bad hack (tm) for NTSC support */
+ if (ffmpeg_type == FFMPEG_DV && G.scene->r.frs_sec != 25) {
+ c->frame_rate = 2997;
+ c->frame_rate_base = 100;
+ } else if ((double) ((int) G.scene->r.frs_sec_base) ==
+ G.scene->r.frs_sec_base) {
+ c->frame_rate = G.scene->r.frs_sec;
+ c->frame_rate_base = G.scene->r.frs_sec_base;
+ } else {
+ c->frame_rate = G.scene->r.frs_sec * 100000;
+ c->frame_rate_base = ((double) G.scene->r.frs_sec_base)*100000;
+ }
+#endif
+
+ c->gop_size = ffmpeg_gop_size;
+ c->bit_rate = ffmpeg_video_bitrate*1000;
+ c->rc_max_rate = G.scene->r.ffcodecdata.rc_max_rate*1000;
+ c->rc_min_rate = G.scene->r.ffcodecdata.rc_min_rate*1000;
+ c->rc_buffer_size = G.scene->r.ffcodecdata.rc_buffer_size * 1024;
+ c->rc_initial_buffer_occupancy
+ = G.scene->r.ffcodecdata.rc_buffer_size*3/4;
+ c->rc_buffer_aggressivity = 1.0;
+ c->me_method = ME_EPZS;
+
+ codec = avcodec_find_encoder(c->codec_id);
+ if (!codec) return NULL;
+
+ /* Be sure to use the correct pixel format(e.g. RGB, YUV) */
+
+ if (codec->pix_fmts) {
+ c->pix_fmt = codec->pix_fmts[0];
+ } else {
+ /* makes HuffYUV happy ... */
+ c->pix_fmt = PIX_FMT_YUV422P;
+ }
+
+ if (codec_id == CODEC_ID_XVID) {
+ /* arghhhh ... */
+ c->pix_fmt = PIX_FMT_YUV420P;
+ }
+
+ if (!strcmp(of->oformat->name, "mp4") ||
+ !strcmp(of->oformat->name, "mov") ||
+ !strcmp(of->oformat->name, "3gp")) {
+ fprintf(stderr, "Using global header\n");
+ c->flags |= CODEC_FLAG_GLOBAL_HEADER;
+ }
+
+ /* Determine whether we are encoding interlaced material or not */
+ if (G.scene->r.mode & (1 << 6)) {
+ fprintf(stderr, "Encoding interlaced video\n");
+ c->flags |= CODEC_FLAG_INTERLACED_DCT;
+ c->flags |= CODEC_FLAG_INTERLACED_ME;
+ }
+ c->sample_aspect_ratio.num = G.scene->r.xasp;
+ c->sample_aspect_ratio.den = G.scene->r.yasp;
+
+ if (avcodec_open(c, codec) < 0) {
+ error("Couldn't initialize codec");
+ return NULL;
+ }
+
+ video_buffersize = 2000000;
+ video_buffer = (uint8_t*)MEM_mallocN(video_buffersize,
+ "FFMPEG video buffer");
+
+ current_frame = alloc_picture(c->pix_fmt, c->width, c->height);
+
+ img_convert_ctx = sws_getContext(c->width, c->height,
+ PIX_FMT_RGBA32,
+ c->width, c->height,
+ c->pix_fmt,
+ SWS_BICUBIC,
+ NULL, NULL, NULL);
+ return st;
+}
+
+/* Prepare an audio stream for the output file */
+
+static AVStream* alloc_audio_stream(int codec_id, AVFormatContext* of)
+{
+ AVStream* st;
+ AVCodecContext* c;
+ AVCodec* codec;
+
+ st = av_new_stream(of, 1);
+ if (!st) return NULL;
+
+ c = get_codec_from_stream(st);
+ c->codec_id = codec_id;
+ c->codec_type = CODEC_TYPE_AUDIO;
+
+ c->sample_rate = G.scene->audio.mixrate;
+ c->bit_rate = ffmpeg_audio_bitrate*1000;
+ c->channels = 2;
+ codec = avcodec_find_encoder(c->codec_id);
+ if (!codec) {
+ error("Couldn't find a valid audio codec");
+ return NULL;
+ }
+ if (avcodec_open(c, codec) < 0) {
+ error("Couldn't initialize audio codec");
+ return NULL;
+ }
+
+ /* FIXME: Should be user configurable */
+ if (ffmpeg_type == FFMPEG_DV) {
+ /* this is a hack around the poor ffmpeg dv multiplexer. */
+ /* only fixes PAL for now
+ (NTSC is a lot more complicated here...)! */
+ audio_outbuf_size = 7680;
+ } else {
+ audio_outbuf_size = 10000;
+ }
+ audio_output_buffer = (uint8_t*)MEM_mallocN(
+ audio_outbuf_size, "FFMPEG audio encoder input buffer");
+
+ /* ugly hack for PCM codecs */
+
+ if (c->frame_size <= 1) {
+ audio_input_frame_size = audio_outbuf_size / c->channels;
+ switch(c->codec_id) {
+ case CODEC_ID_PCM_S16LE:
+ case CODEC_ID_PCM_S16BE:
+ case CODEC_ID_PCM_U16LE:
+ case CODEC_ID_PCM_U16BE:
+ audio_input_frame_size >>= 1;
+ break;
+ default:
+ break;
+ }
+ } else {
+ audio_input_frame_size = c->frame_size;
+ }
+
+ audio_input_buffer = (uint8_t*)MEM_mallocN(
+ audio_input_frame_size * sizeof(short) * c->channels,
+ "FFMPEG audio encoder output buffer");
+
+ return st;
+}
+/* essential functions -- start, append, end */
+
+void start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty)
+{
+ /* Handle to the output file */
+ AVFormatContext* of;
+ AVOutputFormat* fmt;
+ char name[256];
+ const char ** exts;
+
+ ffmpeg_type = rd->ffcodecdata.type;
+ ffmpeg_codec = rd->ffcodecdata.codec;
+ ffmpeg_audio_codec = rd->ffcodecdata.audio_codec;
+ ffmpeg_video_bitrate = rd->ffcodecdata.video_bitrate;
+ ffmpeg_audio_bitrate = rd->ffcodecdata.audio_bitrate;
+ ffmpeg_gop_size = rd->ffcodecdata.gop_size;
+ ffmpeg_multiplex_audio = rd->ffcodecdata.flags
+ & FFMPEG_MULTIPLEX_AUDIO;
+ ffmpeg_autosplit = rd->ffcodecdata.flags
+ & FFMPEG_AUTOSPLIT_OUTPUT;
+
+ do_init_ffmpeg();
+
+ /* Determine the correct filename */
+ makeffmpegstring(name);
+ fprintf(stderr, "Starting output to %s(ffmpeg)...\n"
+ " Using type=%d, codec=%d, audio_codec=%d,\n"
+ " video_bitrate=%d, audio_bitrate=%d,\n"
+ " gop_size=%d, multiplex=%d, autosplit=%d\n"
+ " render width=%d, render height=%d\n",
+ name, ffmpeg_type, ffmpeg_codec, ffmpeg_audio_codec,
+ ffmpeg_video_bitrate, ffmpeg_audio_bitrate,
+ ffmpeg_gop_size, ffmpeg_multiplex_audio,
+ ffmpeg_autosplit, rectx, recty);
+
+ exts = get_file_extensions(ffmpeg_type);
+ if (!exts) {
+ G.afbreek = 1; /* Abort render */
+ error("No valid formats found");
+ return;
+ }
+ fmt = guess_format(NULL, exts[0], NULL);
+ if (!fmt) {
+ G.afbreek = 1; /* Abort render */
+ error("No valid formats found");
+ return;
+ }
+
+ of = av_alloc_format_context();
+ if (!of) {
+ G.afbreek = 1;
+ error("Error opening output file");
+ return;
+ }
+
+ of->oformat = fmt;
+ of->packet_size= G.scene->r.ffcodecdata.mux_packet_size;
+ if (ffmpeg_multiplex_audio) {
+ of->mux_rate = G.scene->r.ffcodecdata.mux_rate;
+ } else {
+ of->mux_rate = 0;
+ }
+
+ of->preload = (int)(0.5*AV_TIME_BASE);
+ of->max_delay = (int)(0.7*AV_TIME_BASE);
+
+ snprintf(of->filename, sizeof(of->filename), "%s", name);
+ /* set the codec to the user's selection */
+ switch(ffmpeg_type) {
+ case FFMPEG_AVI:
+ case FFMPEG_MOV:
+ fmt->video_codec = ffmpeg_codec;
+ break;
+ case FFMPEG_DV:
+ fmt->video_codec = CODEC_ID_DVVIDEO;
+ break;
+ case FFMPEG_MPEG1:
+ fmt->video_codec = CODEC_ID_MPEG1VIDEO;
+ break;
+ case FFMPEG_MPEG2:
+ fmt->video_codec = CODEC_ID_MPEG2VIDEO;
+ break;
+ case FFMPEG_H264:
+ fmt->video_codec = CODEC_ID_H264;
+ break;
+ case FFMPEG_XVID:
+ fmt->video_codec = CODEC_ID_XVID;
+ break;
+ case FFMPEG_MPEG4:
+ default:
+ fmt->video_codec = CODEC_ID_MPEG4;
+ break;
+ }
+ if (fmt->video_codec == CODEC_ID_DVVIDEO) {
+ if (rectx != 720) {
+ G.afbreek = 1;
+ error("Render width has to be 720 pixels for DV!");
+ return;
+ }
+ if (G.scene->r.frs_sec != 25 && recty != 480) {
+ G.afbreek = 1;
+ error("Render height has to be 480 pixels "
+ "for DV-NTSC!");
+ return;
+
+ }
+ if (G.scene->r.frs_sec == 25 && recty != 576) {
+ G.afbreek = 1;
+ error("Render height has to be 576 pixels "
+ "for DV-PAL!");
+ return;
+ }
+ }
+ if (ffmpeg_type == FFMPEG_DV) {
+ fmt->audio_codec = CODEC_ID_PCM_S16LE;
+ if (ffmpeg_multiplex_audio
+ && G.scene->audio.mixrate != 48000) {
+ G.afbreek = 1;
+ error("FFMPEG only supports 48khz / stereo "
+ "audio for DV!");
+ return;
+ }
+ }
+
+ video_stream = alloc_video_stream(fmt->video_codec, of, rectx, recty);
+ if (!video_stream) {
+ G.afbreek = 1;
+ error("Error initializing video stream");
+ return;
+ }
+
+ if (ffmpeg_multiplex_audio) {
+ audio_stream = alloc_audio_stream(fmt->audio_codec, of);
+ if (!audio_stream) {
+ G.afbreek = 1;
+ error("Error initializing audio stream");
+ return;
+ }
+ audiostream_play(SFRA, 0, 1);
+ }
+ if (av_set_parameters(of, NULL) < 0) {
+ G.afbreek = 1;
+ error("Error setting output parameters");
+ return;
+ }
+ if (!(fmt->flags & AVFMT_NOFILE)) {
+ if (url_fopen(&of->pb, name, URL_WRONLY) < 0) {
+ G.afbreek = 1;
+ error("Could not open file for writing");
+ return;
+ }
+ }
+
+ av_write_header(of);
+ outfile = of;
+ dump_format(of, 0, name, 1);
+}
+
+/* **********************************************************************
+ * public interface
+ ********************************************************************** */
+
+/* Get the output filename-- similar to the other output formats */
+void makeffmpegstring(char* string) {
+
+ char txt[FILE_MAXDIR+FILE_MAXFILE];
+ char autosplit[20];
+
+ const char ** exts = get_file_extensions(G.scene->r.ffcodecdata.type);
+ const char ** fe = exts;
+
+ if (!string || !exts) return;
+
+ strcpy(string, G.scene->r.pic);
+ BLI_convertstringcode(string, G.sce, G.scene->r.cfra);
+
+ BLI_make_existing_file(string);
+
+ autosplit[0] = 0;
+
+ if ((G.scene->r.ffcodecdata.flags & FFMPEG_AUTOSPLIT_OUTPUT) != 0) {
+ sprintf(autosplit, "_%03d", ffmpeg_autosplit_count);
+ }
+
+ while (*fe) {
+ if (BLI_strcasecmp(string + strlen(string) - strlen(*fe),
+ *fe) == 0) {
+ break;
+ }
+ fe++;
+ }
+
+ if (!*fe) {
+ strcat(string, autosplit);
+ sprintf(txt, "%04d_%04d%s", (G.scene->r.sfra),
+ (G.scene->r.efra), *exts);
+ strcat(string, txt);
+ } else {
+ *(string + strlen(string) - strlen(*fe)) = 0;
+ strcat(string, autosplit);
+ strcat(string, *fe);
+ }
+}
+
+
+void start_ffmpeg(RenderData *rd, int rectx, int recty)
+{
+ ffmpeg_autosplit_count = 0;
+
+ ffmpeg_renderdata = rd;
+
+ start_ffmpeg_impl(rd, rectx, recty);
+}
+
+void end_ffmpeg(void);
+
+static void write_audio_frames()
+{
+ int finished = 0;
+
+ while (ffmpeg_multiplex_audio && !finished) {
+ double a_pts = ((double)audio_stream->pts.val
+ * audio_stream->time_base.num
+ / audio_stream->time_base.den);
+ double v_pts = ((double)video_stream->pts.val
+ * video_stream->time_base.num
+ / video_stream->time_base.den);
+
+ if (a_pts < v_pts) {
+ write_audio_frame();
+ } else {
+ finished = 1;
+ }
+ }
+}
+
+void append_ffmpeg(int frame, int *pixels, int rectx, int recty)
+{
+ fprintf(stderr, "Writing frame %i, "
+ "render width=%d, render height=%d\n", frame,
+ rectx, recty);
+
+ write_audio_frames();
+ write_video_frame(generate_video_frame((unsigned char*) pixels));
+
+ if (ffmpeg_autosplit) {
+ if (url_ftell(&outfile->pb) > FFMPEG_AUTOSPLIT_SIZE) {
+ end_ffmpeg();
+ ffmpeg_autosplit_count++;
+ start_ffmpeg_impl(ffmpeg_renderdata,
+ rectx, recty);
+ }
+ }
+}
+
+
+void end_ffmpeg(void)
+{
+ int i;
+
+ fprintf(stderr, "Closing ffmpeg...\n");
+
+ if (audio_stream) {
+ write_audio_frames();
+ }
+
+ if (outfile) {
+ av_write_trailer(outfile);
+ }
+
+ /* Close the video codec */
+
+ if (video_stream && get_codec_from_stream(video_stream)) {
+ avcodec_close(get_codec_from_stream(video_stream));
+ video_stream = 0;
+ }
+
+
+ /* Close the output file */
+ if (outfile) {
+ for (i = 0; i < outfile->nb_streams; i++) {
+ if (&outfile->streams[i]) {
+ av_freep(&outfile->streams[i]);
+ }
+ }
+ }
+ /* free the temp buffer */
+ if (current_frame) {
+ delete_picture(current_frame);
+ current_frame = 0;
+ }
+ if (outfile && outfile->oformat) {
+ if (!(outfile->oformat->flags & AVFMT_NOFILE)) {
+ url_fclose(&outfile->pb);
+ }
+ }
+ if (outfile) {
+ av_free(outfile);
+ outfile = 0;
+ }
+ if (video_buffer) {
+ MEM_freeN(video_buffer);
+ video_buffer = 0;
+ }
+ if (audio_output_buffer) {
+ MEM_freeN(audio_output_buffer);
+ audio_output_buffer = 0;
+ }
+ if (audio_input_buffer) {
+ MEM_freeN(audio_input_buffer);
+ audio_input_buffer = 0;
+ }
+
+ if (img_convert_ctx) {
+ sws_freeContext(img_convert_ctx);
+ img_convert_ctx = 0;
+ }
+}
+#endif
+
diff --git a/source/blender/blenkernel/intern/writeframeserver.c b/source/blender/blenkernel/intern/writeframeserver.c
new file mode 100644
index 00000000000..6b38d7deadb
--- /dev/null
+++ b/source/blender/blenkernel/intern/writeframeserver.c
@@ -0,0 +1,381 @@
+/*
+ * Frameserver
+ * Makes Blender accessible from TMPGenc directly using VFAPI (you can
+ * use firefox too ;-)
+ *
+ * Copyright (c) 2006 Peter Schlaile
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+
+#include <string.h>
+#include <stdio.h>
+
+#if defined(_WIN32)
+#include <winsock2.h>
+#include <windows.h>
+#include <winbase.h>
+#include <direct.h>
+#else
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <netdb.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/un.h>
+#include <fcntl.h>
+#endif
+
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+#include "BLI_blenlib.h"
+#include "DNA_userdef_types.h"
+
+#include "BKE_bad_level_calls.h"
+#include "BKE_global.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "DNA_scene_types.h"
+#include "blendef.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+static int sock;
+static int connsock;
+static int write_ppm;
+static int render_width;
+static int render_height;
+
+
+#if defined(_WIN32)
+static int startup_socket_system()
+{
+ WSADATA wsa;
+ return (WSAStartup(MAKEWORD(2,0),&wsa) == 0);
+}
+
+static void shutdown_socket_system()
+{
+ WSACleanup();
+}
+static int select_was_interrupted_by_signal()
+{
+ return (WSAGetLastError() == WSAEINTR);
+}
+#else
+static int startup_socket_system()
+{
+ return 1;
+}
+
+static void shutdown_socket_system()
+{
+}
+
+static int select_was_interrupted_by_signal()
+{
+ return (errno == EINTR);
+}
+
+static int closesocket(int fd)
+{
+ return close(fd);
+}
+#endif
+
+void start_frameserver(RenderData *rd, int rectx, int recty)
+{
+ struct sockaddr_in addr;
+ int arg = 1;
+
+ if (!startup_socket_system()) {
+ G.afbreek = 1;
+ error("Can't startup socket system");
+ return;
+ }
+
+ if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ shutdown_socket_system();
+ G.afbreek = 1; /* Abort render */
+ error("Can't open socket");
+ return;
+ }
+
+ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
+ (char*) &arg, sizeof(arg));
+
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(U.frameserverport);
+ addr.sin_addr.s_addr = INADDR_ANY;
+
+ if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ shutdown_socket_system();
+ G.afbreek = 1; /* Abort render */
+ error("Can't bind to socket");
+ return;
+ }
+
+ if (listen(sock, SOMAXCONN) < 0) {
+ shutdown_socket_system();
+ G.afbreek = 1; /* Abort render */
+ error("Can't establish listen backlog");
+ return;
+ }
+ connsock = -1;
+
+ render_width = rectx;
+ render_height = recty;
+}
+
+static char index_page[]
+=
+"HTTP/1.1 200 OK\n"
+"Content-Type: text/html\n\n"
+"<html><head><title>Blender Frameserver</title></head>\n"
+"<body><pre>\n"
+"<H2>Blender Frameserver</H2>\n"
+"<A HREF=info.txt>Render Info</A><br>\n"
+"<A HREF=close.txt>Stop Rendering</A><br>\n"
+"\n"
+"Images can be found here\n"
+"\n"
+"images/ppm/%d.ppm\n"
+"\n"
+"</pre></body></html>\n";
+
+static char good_bye[]
+= "HTTP/1.1 200 OK\n"
+"Content-Type: text/html\n\n"
+"<html><head><title>Blender Frameserver</title></head>\n"
+"<body><pre>\n"
+"Render stopped. Goodbye</pre></body></html>";
+
+static int safe_write(char * s, int tosend)
+{
+ int total = tosend;
+ do {
+ int got = send(connsock, s, tosend, 0);
+ if (got < 0) {
+ return got;
+ }
+ tosend -= got;
+ s += got;
+ } while (tosend > 0);
+
+ return total;
+}
+
+static int safe_puts(char * s)
+{
+ return safe_write(s, strlen(s));
+}
+
+static int handle_request(char * req)
+{
+ char * p;
+ char * path;
+ int pathlen;
+
+ if (memcmp(req, "GET ", 4) != 0) {
+ return -1;
+ }
+
+ p = req + 4;
+ path = p;
+
+ while (*p != ' ' && *p) p++;
+
+ *p = 0;
+
+ if (strcmp(path, "/index.html") == 0
+ || strcmp(path, "/") == 0) {
+ safe_puts(index_page);
+ return -1;
+ }
+
+ write_ppm = 0;
+ pathlen = strlen(path);
+
+ if (pathlen > 12 && memcmp(path, "/images/ppm/", 12) == 0) {
+ write_ppm = 1;
+ return atoi(path + 12);
+ }
+ if (strcmp(path, "/info.txt") == 0) {
+ char buf[4096];
+
+ sprintf(buf,
+ "HTTP/1.1 200 OK\n"
+ "Content-Type: text/html\n\n"
+ "start %d\n"
+ "end %d\n"
+ "width %d\n"
+ "height %d\n"
+ "rate %d\n"
+ "ratescale %d\n",
+ G.scene->r.sfra,
+ G.scene->r.efra,
+ render_width,
+ render_height,
+ G.scene->r.frs_sec,
+ 1
+ );
+
+ safe_puts(buf);
+ return -1;
+ }
+ if (strcmp(path, "/close.txt") == 0) {
+ safe_puts(good_bye);
+ G.afbreek = 1; /* Abort render */
+ return -1;
+ }
+ return -1;
+}
+
+int frameserver_loop()
+{
+ fd_set readfds;
+ struct timeval tv;
+ struct sockaddr_in addr;
+ int len, rval;
+ unsigned int socklen;
+ char buf[4096];
+
+ if (connsock != -1) {
+ closesocket(connsock);
+ connsock = -1;
+ }
+
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+
+ FD_ZERO(&readfds);
+ FD_SET(sock, &readfds);
+
+ rval = select(sock + 1, &readfds, NULL, NULL, &tv);
+ if (rval < 0) {
+ return -1;
+ }
+
+ if (rval == 0) { /* nothing to be done */
+ return -1;
+ }
+
+ socklen = sizeof(addr);
+
+ if ((connsock = accept(sock, (struct sockaddr *)&addr, &socklen)) < 0) {
+ return -1;
+ }
+
+ FD_ZERO(&readfds);
+ FD_SET(connsock, &readfds);
+
+ for (;;) {
+ /* give 10 seconds for telnet testing... */
+ tv.tv_sec = 10;
+ tv.tv_usec = 0;
+
+ rval = select(connsock + 1, &readfds, NULL, NULL, &tv);
+ if (rval > 0) {
+ break;
+ } else if (rval == 0) {
+ return -1;
+ } else if (rval < 0) {
+ if (!select_was_interrupted_by_signal()) {
+ return -1;
+ }
+ }
+ }
+
+ len = recv(connsock, buf, 4095, 0);
+
+ if (len < 0) {
+ return -1;
+ }
+
+ buf[len] = 0;
+
+ return handle_request(buf);
+}
+
+static void serve_ppm(int *pixels, int rectx, int recty)
+{
+ unsigned char* rendered_frame;
+ unsigned char* row = (unsigned char*) malloc(render_width * 3);
+ int y;
+ char header[1024];
+
+ sprintf(header,
+ "HTTP/1.1 200 OK\n"
+ "Content-Type: image/ppm\n"
+ "Connection: close\n\n"
+ "P6\n"
+ "# Creator: blender frameserver v0.0.1\n"
+ "%d %d\n"
+ "255\n",
+ rectx, recty);
+
+ safe_puts(header);
+
+ rendered_frame = (unsigned char *)pixels;
+
+ for (y = recty - 1; y >= 0; y--) {
+ unsigned char* target = row;
+ unsigned char* src = rendered_frame + rectx * 4 * y;
+ unsigned char* end = src + rectx * 4;
+ while (src != end) {
+ target[2] = src[2];
+ target[1] = src[1];
+ target[0] = src[0];
+
+ target += 3;
+ src += 4;
+ }
+ safe_write((char*)row, 3 * rectx);
+ }
+ free(row);
+ closesocket(connsock);
+ connsock = -1;
+}
+
+void append_frameserver(int frame, int *pixels, int rectx, int recty)
+{
+ fprintf(stderr, "Serving frame: %d\n", frame);
+ if (write_ppm) {
+ serve_ppm(pixels, rectx, recty);
+ }
+ if (connsock != -1) {
+ closesocket(connsock);
+ connsock = -1;
+ }
+}
+
+void end_frameserver()
+{
+ if (connsock != -1) {
+ closesocket(connsock);
+ connsock = -1;
+ }
+ closesocket(sock);
+ shutdown_socket_system();
+}
+
diff --git a/source/blender/blenlib/BLI_arithb.h b/source/blender/blenlib/BLI_arithb.h
new file mode 100644
index 00000000000..d5e7447ff66
--- /dev/null
+++ b/source/blender/blenlib/BLI_arithb.h
@@ -0,0 +1,385 @@
+#undef TEST_ACTIVE
+//#define ACTIVE 1
+/**
+ * blenlib/BLI_arithb.h mar 2001 Nzc
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * */
+
+#ifndef BLI_ARITHB_H
+#define BLI_ARITHB_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+#ifndef M_PI_2
+#define M_PI_2 1.57079632679489661923
+#endif
+#ifndef M_SQRT2
+#define M_SQRT2 1.41421356237309504880
+#endif
+#ifndef M_SQRT1_2
+#define M_SQRT1_2 0.70710678118654752440
+#endif
+
+#define MAT4_UNITY {{ 1.0, 0.0, 0.0, 0.0},\
+ { 0.0, 1.0, 0.0, 0.0},\
+ { 0.0, 0.0, 1.0, 0.0},\
+ { 0.0, 0.0, 0.0, 1.0}}
+
+#define MAT3_UNITY {{ 1.0, 0.0, 0.0},\
+ { 0.0, 1.0, 0.0},\
+ { 0.0, 0.0, 1.0}}
+
+
+void CalcCent3f(float *cent, float *v1, float *v2, float *v3);
+void CalcCent4f(float *cent, float *v1, float *v2, float *v3, float *v4);
+
+void Crossf(float *c, float *a, float *b);
+void Projf(float *c, float *v1, float *v2);
+
+float Inpf(float *v1, float *v2);
+float Inp2f(float *v1, float *v2);
+
+float Normalize(float *n);
+float Normalize2(float *n);
+
+float Sqrt3f(float f);
+double Sqrt3d(double d);
+
+float saacos(float fac);
+float saasin(float fac);
+float sasqrt(float fac);
+
+int FloatCompare(float *v1, float *v2, float limit);
+float FloatLerpf(float target, float origin, float fac);
+
+float CalcNormFloat(float *v1, float *v2, float *v3, float *n);
+float CalcNormFloat4(float *v1, float *v2, float *v3, float *v4, float *n);
+
+void CalcNormLong(int *v1, int *v2, int *v3, float *n);
+/* CalcNormShort: is ook uitprodukt - (translates as 'is also out/cross product') */
+void CalcNormShort(short *v1, short *v2, short *v3, float *n);
+
+
+/**
+ * @section Euler conversion routines
+ */
+
+void EulToMat3(float *eul, float mat[][3]);
+void EulToMat4(float *eul, float mat[][4]);
+
+void Mat3ToEul(float tmat[][3], float *eul);
+void Mat4ToEul(float tmat[][4],float *eul);
+
+void EulToQuat(float *eul, float *quat);
+
+void compatible_eul(float *eul, float *oldrot);
+
+void Mat3ToCompatibleEul(float mat[][3], float *eul, float *oldrot);
+
+
+/**
+ * @section Quaternion arithmetic routines
+ */
+
+void QuatToEul(float *quat, float *eul);
+void QuatOne(float *);
+void QuatMul(float *, float *, float *);
+void QuatMulVecf(float *q, float *v);
+
+void NormalQuat(float *);
+void VecRotToQuat(float *vec, float phi, float *quat);
+
+void QuatSub(float *q, float *q1, float *q2);
+void QuatConj(float *q);
+void QuatInv(float *q);
+void QuatMulf(float *q, float f);
+float QuatDot(float *q1, float *q2);
+void QuatCopy(float *q1, float *q2);
+
+void printquat(char *str, float q[4]);
+
+void QuatInterpol(float *result, float *quat1, float *quat2, float t);
+void QuatAdd(float *result, float *quat1, float *quat2, float t);
+
+
+/**
+ * @section matrix multiplication and copying routines
+ */
+
+void Mat3MulFloat(float *m, float f);
+void Mat4MulFloat(float *m, float f);
+void Mat4MulFloat3(float *m, float f);
+
+void Mat3Transp(float mat[][3]);
+void Mat4Transp(float mat[][4]);
+
+int Mat4Invert(float inverse[][4], float mat[][4]);
+void Mat4InvertSimp(float inverse[][4], float mat[][4]);
+void Mat4Inv(float *m1, float *m2);
+void Mat4InvGG(float out[][4], float in[][4]);
+void Mat3Inv(float m1[][3], float m2[][3]);
+
+void Mat3CpyMat4(float m1[][3],float m2[][4]);
+void Mat4CpyMat3(float m1[][4], float m2[][3]);
+
+void Mat4BlendMat4(float out[][4], float dst[][4], float src[][4], float srcweight);
+
+float Det2x2(float a,float b,float c, float d);
+
+float Det3x3(
+ float a1, float a2, float a3,
+ float b1, float b2, float b3,
+ float c1, float c2, float c3
+);
+
+float Det4x4(float m[][4]);
+
+void Mat3Adj(float m1[][3], float m[][3]);
+void Mat4Adj(float out[][4], float in[][4]);
+
+void Mat4MulMat4(float m1[][4], float m2[][4], float m3[][4]);
+void subMat4MulMat4(float *m1, float *m2, float *m3);
+#ifndef TEST_ACTIVE
+void Mat3MulMat3(float m1[][3], float m3[][3], float m2[][3]);
+#else
+void Mat3MulMat3(float *m1, float *m3, float *m2);
+#endif
+void Mat4MulMat34(float (*m1)[4], float (*m3)[3], float (*m2)[4]);
+void Mat4CpyMat4(float m1[][4], float m2[][4]);
+void Mat4SwapMat4(float *m1, float *m2);
+void Mat3CpyMat3(float m1[][3], float m2[][3]);
+
+void Mat3MulSerie(float answ[][3],
+ float m1[][3], float m2[][3], float m3[][3],
+ float m4[][3], float m5[][3], float m6[][3],
+ float m7[][3], float m8[][3]
+);
+
+void Mat4MulSerie(float answ[][4], float m1[][4],
+ float m2[][4], float m3[][4], float m4[][4],
+ float m5[][4], float m6[][4], float m7[][4],
+ float m8[][4]
+);
+
+void Mat4Clr(float *m);
+void Mat3Clr(float *m);
+
+void Mat3One(float m[][3]);
+void Mat4One(float m[][4]);
+
+void Mat3Ortho(float mat[][3]);
+void Mat4Ortho(float mat[][4]);
+
+void VecMat4MulVecfl(float *in, float mat[][4], float *vec);
+void Mat4MulMat43(float (*m1)[4], float (*m3)[4], float (*m2)[3]);
+void Mat3IsMat3MulMat4(float m1[][3], float m2[][3], float m3[][4]);
+
+void Mat4MulVec(float mat[][4],int *vec);
+void Mat4MulVecfl(float mat[][4], float *vec);
+void Mat4Mul3Vecfl(float mat[][4], float *vec);
+void Mat4MulVec3Project(float mat[][4],float *vec);
+void Mat4MulVec4fl(float mat[][4], float *vec);
+void Mat3MulVec(float mat[][3],int *vec);
+void Mat3MulVecfl(float mat[][3], float *vec);
+void Mat3MulVecd(float mat[][3], double *vec);
+void Mat3TransMulVecfl(float mat[][3], float *vec);
+
+void Mat3AddMat3(float m1[][3], float m2[][3], float m3[][3]);
+void Mat4AddMat4(float m1[][4], float m2[][4], float m3[][4]);
+
+void VecUpMat3old(float *vec, float mat[][3], short axis);
+void VecUpMat3(float *vec, float mat[][3], short axis);
+void VecRotToMat3(float *vec, float phi, float mat[][3]);
+void VecRotToMat4(float *vec, float phi, float mat[][4]);
+
+void VecCopyf(float *v1, float *v2);
+int VecLen(int *v1, int *v2);
+float VecLenf(float *v1, float *v2);
+float VecLength(float *v);
+void VecMulf(float *v1, float f);
+
+int VecLenCompare(float *v1, float *v2, float limit);
+int VecCompare(float *v1, float *v2, float limit);
+int VecEqual(float *v1, float *v2);
+
+void printvecf(char *str,float v[3]);
+void printvec4f(char *str, float v[4]);
+
+void VecAddf(float *v, float *v1, float *v2);
+void VecSubf(float *v, float *v1, float *v2);
+void VecLerpf(float *target, float *a, float *b, float t);
+void VecMidf(float *v, float *v1, float *v2);
+
+void VecOrthoBasisf(float *v, float *v1, float *v2);
+
+float Vec2Lenf(float *v1, float *v2);
+void Vec2Mulf(float *v1, float f);
+void Vec2Addf(float *v, float *v1, float *v2);
+void Vec2Subf(float *v, float *v1, float *v2);
+void Vec2Copyf(float *v1, float *v2);
+
+float *vectoquat(float *vec, short axis, short upflag);
+
+float VecAngle2(float *v1, float *v2);
+float VecAngle3(float *v1, float *v2, float *v3);
+float NormalizedVecAngle2(float *v1, float *v2);
+
+void euler_rot(float *beul, float ang, char axis);
+
+
+float DistVL2Dfl(float *v1, float *v2, float *v3);
+float PdistVL2Dfl(float *v1, float *v2, float *v3);
+float PdistVL3Dfl(float *v1, float *v2, float *v3);
+void PclosestVL3Dfl(float *closest, float *v1, float *v2, float *v3);
+float AreaF2Dfl(float *v1, float *v2, float *v3);
+float AreaQ3Dfl(float *v1, float *v2, float *v3, float *v4);
+float AreaT3Dfl(float *v1, float *v2, float *v3);
+float AreaPoly3Dfl(int nr, float *verts, float *normal);
+
+/* intersect Line-Line
+ return:
+ -1: colliniar
+ 0: no intersection of segments
+ 1: exact intersection of segments
+ 2: cross-intersection of segments
+*/
+extern short IsectLL2Df(float *v1, float *v2, float *v3, float *v4);
+extern short IsectLL2Ds(short *v1, short *v2, short *v3, short *v4);
+
+/* interpolation weights of point in a triangle or quad, v4 may be NULL */
+void InterpWeightsQ3Dfl(float *v1, float *v2, float *v3, float *v4, float *co, float *w);
+/* interpolation weights of point in a polygon with >= 3 vertices */
+void MeanValueWeights(float v[][3], int n, float *co, float *w);
+
+void i_lookat(
+ float vx, float vy,
+ float vz, float px,
+ float py, float pz,
+ float twist, float mat[][4]
+);
+
+void i_window(
+ float left, float right,
+ float bottom, float top,
+ float nearClip, float farClip,
+ float mat[][4]
+);
+
+void hsv_to_rgb(float h, float s, float v, float *r, float *g, float *b);
+void hex_to_rgb(char *hexcol, float *r, float *g, float *b);
+void rgb_to_yuv(float r, float g, float b, float *ly, float *lu, float *lv);
+void yuv_to_rgb(float y, float u, float v, float *lr, float *lg, float *lb);
+void ycc_to_rgb(float y, float cb, float cr, float *lr, float *lg, float *lb);
+void rgb_to_ycc(float r, float g, float b, float *ly, float *lcb, float *lcr);
+void rgb_to_hsv(float r, float g, float b, float *lh, float *ls, float *lv);
+unsigned int hsv_to_cpack(float h, float s, float v);
+unsigned int rgb_to_cpack(float r, float g, float b);
+void cpack_to_rgb(unsigned int col, float *r, float *g, float *b);
+void MinMaxRGB(short c[]);
+
+
+
+void VecStar(float mat[][3],float *vec);
+
+short EenheidsMat(float mat[][3]);
+
+void QuatToMat3(float *q, float m[][3]);
+void QuatToMat4(float *q, float m[][4]);
+
+void Mat3ToQuat_is_ok(float wmat[][3], float *q);
+
+void i_ortho(float left, float right, float bottom, float top, float nearClip, float farClip, float matrix[][4]);
+void i_polarview(float dist, float azimuth, float incidence, float twist, float Vm[][4]);
+void i_translate(float Tx, float Ty, float Tz, float mat[][4]);
+void i_multmatrix(float icand[][4], float Vm[][4]);
+void i_rotate(float angle, char axis, float mat[][4]);
+
+
+
+
+
+void MinMax3(float *min, float *max, float *vec);
+void SizeToMat3(float *size, float mat[][3]);
+void SizeToMat4(float *size, float mat[][4]);
+
+float Mat3ToScalef(float mat[][3]);
+float Mat4ToScalef(float mat[][4]);
+
+void printmatrix3(char *str, float m[][3]);
+void printmatrix4(char *str, float m[][4]);
+
+/* uit Sig.Proc.85 pag 253 */
+void Mat3ToQuat(float wmat[][3], float *q);
+void Mat4ToQuat(float m[][4], float *q);
+
+void Mat3ToSize(float mat[][3], float *size);
+void Mat4ToSize(float mat[][4], float *size);
+
+void triatoquat(float *v1, float *v2, float *v3, float *quat);
+
+void LocEulSizeToMat4(float mat[][4], float loc[3], float eul[3], float size[3]);
+void LocQuatSizeToMat4(float mat[][4], float loc[3], float quat[4], float size[3]);
+
+void tubemap(float x, float y, float z, float *u, float *v);
+void spheremap(float x, float y, float z, float *u, float *v);
+
+int LineIntersectsTriangle(float p1[3], float p2[3], float v0[3], float v1[3], float v2[3], float *lambda);
+int point_in_tri_prism(float p[3], float v1[3], float v2[3], float v3[3]);
+
+float lambda_cp_line_ex(float p[3], float l1[3], float l2[3], float cp[3]);
+
+typedef struct DualQuat {
+ float quat[4];
+ float trans[4];
+
+ float scale[4][4];
+ float scale_weight;
+} DualQuat;
+
+void Mat4ToDQuat(float basemat[][4], float mat[][4], DualQuat *dq);
+void DQuatToMat4(DualQuat *dq, float mat[][4]);
+void DQuatAddWeighted(DualQuat *dqsum, DualQuat *dq, float weight);
+void DQuatNormalize(DualQuat *dq, float totweight, float factor);
+void DQuatMulVecfl(DualQuat *dq, float *co, float mat[][3]);
+void DQuatCpyDQuat(DualQuat *dq1, DualQuat *dq2);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/source/blender/blenlib/BLI_blenlib.h b/source/blender/blenlib/BLI_blenlib.h
new file mode 100644
index 00000000000..57248fb1d68
--- /dev/null
+++ b/source/blender/blenlib/BLI_blenlib.h
@@ -0,0 +1,406 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * @mainpage BLI - Blender LIbrary external interface
+ *
+ * @section about About the BLI module
+ *
+ * This is the external interface of the Blender Library. If you find
+ * a call to a BLI function that is not prototyped here, please add a
+ * prototype here. The library offers mathematical operations (mainly
+ * vector and matrix calculus), an abstraction layer for file i/o,
+ * functions for calculating Perlin noise, scanfilling services for
+ * triangles, and a system for guarded memory
+ * allocation/deallocation. There is also a patch to make MS Windows
+ * behave more or less Posix-compliant.
+ *
+ * @section issues Known issues with BLI
+ *
+ * - blenlib is written in C.
+ * - The posix-compliancy may move to a separate lib that deals with
+ * platform dependencies. (There are other platform-dependent
+ * fixes as well.)
+ * - The file i/o has some redundant code. It should be cleaned.
+ * - arithb.c is a very messy matrix library. We need a better
+ * solution.
+ * - vectorops.c is close to superfluous. It may disappear in the
+ * near future.
+ *
+ * @section dependencies Dependencies
+ *
+ * - The blenlib uses type defines from makesdna/, and functions from
+ * standard libraries.
+ *
+ * $Id$
+*/
+
+#ifndef BLI_BLENLIB_H
+#define BLI_BLENLIB_H
+
+/* braindamage for the masses... needed
+ because fillfacebase and fillvertbase are used outside */
+#include "DNA_listBase.h"
+
+#include <stdlib.h>
+
+extern ListBase fillfacebase;
+extern ListBase fillvertbase;
+/**
+ * @attention Defined in scanfill.c
+ */
+extern ListBase filledgebase;
+extern int totblock;
+
+struct chardesc;
+struct direntry;
+struct rctf;
+struct rcti;
+struct EditVert;
+struct PackedFile;
+struct LinkNode;
+struct DynamicList;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* BLI_util.h */
+char *BLI_gethome(void);
+void BLI_make_file_string(const char *relabase, char *string, const char *dir, const char *file);
+void BLI_make_exist(char *dir);
+void BLI_make_existing_file(char *name);
+void BLI_split_dirfile(const char *string, char *dir, char *file);
+void BLI_join_dirfile(char *string, const char *dir, const char *file);
+int BLI_testextensie(const char *str, const char *ext);
+void addlisttolist(ListBase *list1, ListBase *list2);
+void BLI_insertlink(struct ListBase *listbase, void *vprevlink, void *vnewlink);
+void *BLI_findlink(struct ListBase *listbase, int number);
+int BLI_findindex(struct ListBase *listbase, void *vlink);
+void BLI_freelistN(struct ListBase *listbase);
+void BLI_addtail(struct ListBase *listbase, void *vlink);
+void BLI_remlink(struct ListBase *listbase, void *vlink);
+void BLI_newname(char * name, int add);
+int BLI_stringdec(char *string, char *kop, char *start, unsigned short *numlen);
+void BLI_stringenc(char *string, char *kop, char *start, unsigned short numlen, int pic);
+void BLI_addhead(struct ListBase *listbase, void *vlink);
+void BLI_insertlinkbefore(struct ListBase *listbase, void *vnextlink, void *vnewlink);
+void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink);
+void BLI_sortlist(struct ListBase *listbase, int (*cmp)(void *, void *));
+void BLI_freelist(struct ListBase *listbase);
+int BLI_countlist(struct ListBase *listbase);
+void BLI_freelinkN(ListBase *listbase, void *vlink);
+void BLI_splitdirstring(char *di,char *fi);
+
+struct DynamicList *BLI_dlist_from_listbase(struct ListBase *lb);
+struct ListBase *BLI_listbase_from_dlist(struct DynamicList *dlist, struct ListBase *lb);
+void * BLI_dlist_find_link(struct DynamicList *dlist, unsigned int index);
+unsigned int BLI_count_items(struct DynamicList *dlist);
+void BLI_dlist_free_item(struct DynamicList *dlist, unsigned int index);
+void BLI_dlist_rem_item(struct DynamicList *dlist, unsigned int index);
+void * BLI_dlist_add_item_index(struct DynamicList *dlist, void *item, unsigned int index);
+void BLI_dlist_destroy(struct DynamicList *dlist);
+void BLI_dlist_init(struct DynamicList *dlist);
+void BLI_dlist_reinit(struct DynamicList *dlist);
+
+ /**
+ * dir can be any input, like from buttons, and this function
+ * converts it to a regular full path.
+ * Also removes garbage from directory paths, like /../ or double slashes etc
+ */
+void BLI_cleanup_dir(const char *relabase, char *dir);
+
+ /**
+ * Blender's path code replacement function.
+ * Bases @a path strings leading with "//" by the
+ * directory @a basepath, and replaces instances of
+ * '#' with the @a framenum. Results are written
+ * back into @a path.
+ *
+ * @a path The path to convert
+ * @a basepath The directory to base relative paths with.
+ * @a framenum The framenumber to replace the frame code with.
+ * @retval Returns true if the path was relative (started with "//").
+ */
+int BLI_convertstringcode(char *path, const char *basepath, int framenum);
+
+void BLI_makestringcode(const char *relfile, char *file);
+
+ /**
+ * Change every @a from in @a string into @a to. The
+ * result will be in @a string
+ *
+ * @a string The string to work on
+ * @a from The character to replace
+ * @a to The character to replace with
+ */
+void BLI_char_switch(char *string, char from, char to);
+
+ /**
+ * Makes sure @a path has platform-specific slashes.
+ *
+ * @a path The path to 'clean'
+ */
+void BLI_clean(char *path);
+ /**
+ * Duplicates the cstring @a str into a newly mallocN'd
+ * string and returns it.
+ *
+ * @param str The string to be duplicated
+ * @retval Returns the duplicated string
+ */
+char *BLI_strdup(const char *str);
+
+ /**
+ * Duplicates the first @a len bytes of cstring @a str
+ * into a newly mallocN'd string and returns it. @a str
+ * is assumed to be at least len bytes long.
+ *
+ * @param str The string to be duplicated
+ * @param len The number of bytes to duplicate
+ * @retval Returns the duplicated string
+ */
+char *BLI_strdupn(const char *str, int len);
+
+ /**
+ * Like strncpy but ensures dst is always
+ * '\0' terminated.
+ *
+ * @param dst Destination for copy
+ * @param src Source string to copy
+ * @param maxncpy Maximum number of characters to copy (generally
+ * the size of dst)
+ * @retval Returns dst
+ */
+char *BLI_strncpy(char *dst, const char *src, int maxncpy);
+
+ /*
+ * Replacement for snprintf
+ */
+int BLI_snprintf(char *buffer, size_t count, const char *format, ...);
+
+ /**
+ * Compare two strings
+ *
+ * @retval True if the strings are equal, false otherwise.
+ */
+int BLI_streq(char *a, char *b);
+
+ /**
+ * Compare two strings without regard to case.
+ *
+ * @retval True if the strings are equal, false otherwise.
+ */
+int BLI_strcaseeq(char *a, char *b);
+
+/* in util.c */
+#ifdef WITH_ICONV
+void BLI_string_to_utf8(char *original, char *utf_8, char *code);
+#endif
+
+ /**
+ * Read a file as ASCII lines. An empty list is
+ * returned if the file cannot be opened or read.
+ *
+ * @attention The returned list should be free'd with
+ * BLI_free_file_lines.
+ *
+ * @param name The name of the file to read.
+ * @retval A list of strings representing the file lines.
+ */
+struct LinkNode *BLI_read_file_as_lines(char *name);
+
+ /**
+ * Free the list returned by BLI_read_file_as_lines.
+ */
+void BLI_free_file_lines(struct LinkNode *lines);
+
+ /**
+ * Checks if name is a fully qualified filename to an executable.
+ * If not it searches $PATH for the file. On Windows it also
+ * adds the correct extension (.com .exe etc) from
+ * $PATHEXT if necessary. Also on Windows it translates
+ * the name to its 8.3 version to prevent problems with
+ * spaces and stuff. Final result is returned in fullname.
+ *
+ * @param fullname The full path and full name of the executable
+ * @param name The name of the executable (usually argv[0]) to be checked
+ */
+void BLI_where_am_i(char *fullname, char *name);
+
+ /**
+ * determines the full path to the application bundle on OS X
+ *
+ * @return path to application bundle
+ */
+#ifdef __APPLE__
+char* BLI_getbundle(void);
+#endif
+
+#ifdef WIN32
+int BLI_getInstallationDir(char *str);
+#endif
+
+/* BLI_storage.h */
+int BLI_filesize(int file);
+double BLI_diskfree(char *dir);
+char *BLI_getwdN(char *dir);
+void BLI_hide_dot_files(int set);
+unsigned int BLI_getdir(char *dirname, struct direntry **filelist);
+
+/**
+ * @attention Do not confuse with BLI_exists
+ */
+int BLI_exist(char *name);
+
+/* BLI_fileops.h */
+void BLI_recurdir_fileops(char *dirname);
+int BLI_link(char *file, char *to);
+int BLI_backup(char *file, char *from, char *to);
+int BLI_is_writable(char *filename);
+
+/**
+ * @attention Do not confuse with BLI_exist
+ */
+int BLI_exists(char *file);
+int BLI_copy_fileops(char *file, char *to);
+int BLI_rename(char *from, char *to);
+int BLI_gzip(char *from, char *to);
+int BLI_delete(char *file, int dir, int recursive);
+int BLI_move(char *file, char *to);
+int BLI_touch(char *file);
+char *BLI_last_slash(char *string);
+
+/* BLI_rct.c */
+/**
+ * Determine if a rect is empty. An empty
+ * rect is one with a zero (or negative)
+ * width or height.
+ *
+ * @return True if @a rect is empty.
+ */
+int BLI_rcti_is_empty(struct rcti *rect);
+void BLI_init_rctf(struct rctf *rect, float xmin, float xmax, float ymin, float ymax);
+void BLI_init_rcti(struct rcti *rect, int xmin, int xmax, int ymin, int ymax);
+void BLI_translate_rctf(struct rctf *rect, float x, float y);
+void BLI_translate_rcti(struct rcti *rect, int x, int y);
+int BLI_in_rcti(struct rcti *rect, int x, int y);
+int BLI_in_rctf(struct rctf *rect, float x, float y);
+int BLI_isect_rctf(struct rctf *src1, struct rctf *src2, struct rctf *dest);
+int BLI_isect_rcti(struct rcti *src1, struct rcti *src2, struct rcti *dest);
+void BLI_union_rctf(struct rctf *rcta, struct rctf *rctb);
+
+/* scanfill.c: used in displist only... */
+struct EditVert *BLI_addfillvert(float *vec);
+struct EditEdge *BLI_addfilledge(struct EditVert *v1, struct EditVert *v2);
+int BLI_edgefill(int mode, int mat_nr);
+void BLI_end_edgefill(void);
+
+/* noise.h: */
+float BLI_hnoise(float noisesize, float x, float y, float z);
+float BLI_hnoisep(float noisesize, float x, float y, float z);
+float BLI_turbulence(float noisesize, float x, float y, float z, int nr);
+float BLI_turbulence1(float noisesize, float x, float y, float z, int nr);
+/* newnoise: generic noise & turbulence functions to replace the above BLI_hnoise/p & BLI_turbulence/1.
+ * This is done so different noise basis functions can be used */
+float BLI_gNoise(float noisesize, float x, float y, float z, int hard, int noisebasis);
+float BLI_gTurbulence(float noisesize, float x, float y, float z, int oct, int hard, int noisebasis);
+/* newnoise: musgrave functions */
+float mg_fBm(float x, float y, float z, float H, float lacunarity, float octaves, int noisebasis);
+float mg_MultiFractal(float x, float y, float z, float H, float lacunarity, float octaves, int noisebasis);
+float mg_VLNoise(float x, float y, float z, float distortion, int nbas1, int nbas2);
+float mg_HeteroTerrain(float x, float y, float z, float H, float lacunarity, float octaves, float offset, int noisebasis);
+float mg_HybridMultiFractal(float x, float y, float z, float H, float lacunarity, float octaves, float offset, float gain, int noisebasis);
+float mg_RidgedMultiFractal(float x, float y, float z, float H, float lacunarity, float octaves, float offset, float gain, int noisebasis);
+/* newnoise: voronoi */
+void voronoi(float x, float y, float z, float* da, float* pa, float me, int dtype);
+/* newnoise: cellNoise & cellNoiseV (for vector/point/color) */
+float cellNoise(float x, float y, float z);
+void cellNoiseV(float x, float y, float z, float *ca);
+
+/* These callbacks are needed to make the lib finction properly */
+
+/**
+ * Set a function taking a char* as argument to flag errors. If the
+ * callback is not set, the error is discarded.
+ * @param f The function to use as callback
+ * @attention used in creator.c
+ */
+void BLI_setErrorCallBack(void (*f)(char*));
+
+/**
+ * Set a function to be able to interrupt the execution of processing
+ * in this module. If the function returns true, the execution will
+ * terminate gracefully. If the callback is not set, interruption is
+ * not possible.
+ * @param f The function to use as callback
+ * @attention used in creator.c
+ */
+void BLI_setInterruptCallBack(int (*f)(void));
+
+char *BLI_strcasestr(const char *s, const char *find);
+int BLI_strcasecmp(const char *s1, const char *s2);
+int BLI_strncasecmp(const char *s1, const char *s2, int n);
+void BLI_timestr(double time, char *str);
+
+/**
+ * Trick to address 32 GB with an int (only for malloced pointers)
+ */
+int BLI_int_from_pointer(void *poin);
+void *BLI_pointer_from_int(int val);
+
+
+#define PRNTSUB(type,arg) printf(#arg ": %" #type " ", arg)
+
+#ifndef PRINT
+#define PRINT(t,v) {PRNTSUB(t,v); printf("\n");}
+#define PRINT2(t1,v1,t2,v2) {PRNTSUB(t1,v1); PRNTSUB(t2,v2); printf("\n");}
+#define PRINT3(t1,v1,t2,v2,t3,v3) {PRNTSUB(t1,v1); PRNTSUB(t2,v2); PRNTSUB(t3,v3); printf("\n");}
+#define PRINT4(t1,v1,t2,v2,t3,v3,t4,v4) {PRNTSUB(t1,v1); PRNTSUB(t2,v2); PRNTSUB(t3,v3); PRNTSUB(t4,v4); printf("\n");}
+#endif
+
+/**
+ * @param array The array in question
+ * @retval The number of elements in the array.
+ */
+#define BLI_ARRAY_NELEMS(array) (sizeof((array))/sizeof((array)[0]))
+
+/**
+ * @param strct The structure of interest
+ * @param member The name of a member field of @a strct
+ * @retval The offset in bytes of @a member within @a strct
+ */
+#define BLI_STRUCT_OFFSET(strct, member) ((int) &((strct*) 0)->member)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/source/blender/blenlib/BLI_boxpack2d.h b/source/blender/blenlib/BLI_boxpack2d.h
new file mode 100644
index 00000000000..b5cf9cd81e9
--- /dev/null
+++ b/source/blender/blenlib/BLI_boxpack2d.h
@@ -0,0 +1,69 @@
+/**
+ *
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Campbell Barton
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * The old math stuff from Ton. These will slowly phase out in favour
+ * of MTC calls. (or even MoTO :) )
+ * */
+
+/* Box Packer */
+
+/* verts, internal use only */
+typedef struct boxVert {
+ float x;
+ float y;
+ short free;
+
+ struct boxPack *trb; /* top right box */
+ struct boxPack *blb; /* bottom left box */
+ struct boxPack *brb; /* bottom right box */
+ struct boxPack *tlb; /* top left box */
+
+ /* Store last intersecting boxes here
+ * speedup intersection testing */
+ struct boxPack *isect_cache[4];
+
+ int index;
+} boxVert;
+
+typedef struct boxPack {
+ float x;
+ float y;
+ float w;
+ float h;
+ int index;
+
+ /* Verts this box uses
+ * (BL,TR,TL,BR) / 0,1,2,3 */
+ boxVert *v[4];
+} boxPack;
+
+void boxPack2D(boxPack *boxarray, int len, float *tot_width, float *tot_height);
+
diff --git a/source/blender/blenlib/BLI_dynamiclist.h b/source/blender/blenlib/BLI_dynamiclist.h
new file mode 100644
index 00000000000..89e27743054
--- /dev/null
+++ b/source/blender/blenlib/BLI_dynamiclist.h
@@ -0,0 +1,58 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributor(s): Jiri Hnidek.
+ *
+ * Documentation of Two way dynamic list with access array can be found at:
+ *
+ * http://wiki.blender.org/bin/view.pl/Blenderwiki/DynamicListWithAccessArray
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef B_DYNAMIC_LIST_H
+#define B_DYNAMIC_LIST_H
+
+#define PAGE_SIZE 4
+
+struct ListBase;
+
+/*
+ * Access array using realloc
+ */
+typedef struct DynamicArray{
+ unsigned int count; /* count of items in list */
+ unsigned int max_item_index; /* max available index */
+ unsigned int last_item_index; /* max used index */
+ void **items; /* dynamicaly allocated array of pointers
+ pointing at items in list */
+} DynamicArray;
+
+/*
+ * Two way dynamic list with access array
+ */
+typedef struct DynamicList {
+ struct DynamicArray da; /* access array */
+ struct ListBase lb; /* two way linked dynamic list */
+} DynamicList;
+
+#endif
diff --git a/source/blender/blenlib/BLI_dynstr.h b/source/blender/blenlib/BLI_dynstr.h
new file mode 100644
index 00000000000..7e8cc140964
--- /dev/null
+++ b/source/blender/blenlib/BLI_dynstr.h
@@ -0,0 +1,90 @@
+/**
+ * @file BLI_dynstr.h
+ *
+ * A dynamically sized string ADT.
+ * This ADT is designed purely for dynamic string creation
+ * through appending, not for general usage, the intent is
+ * to build up dynamic strings using a DynStr object, then
+ * convert it to a c-string and work with that.
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BLI_DYNSTR_H
+#define BLI_DYNSTR_H
+
+struct DynStr;
+
+ /** The abstract DynStr type */
+typedef struct DynStr DynStr;
+
+ /**
+ * Create a new DynStr.
+ *
+ * @return Pointer to a new DynStr.
+ */
+DynStr* BLI_dynstr_new (void);
+
+ /**
+ * Append a c-string to a DynStr.
+ *
+ * @param ds The DynStr to append to.
+ * @param cstr The c-string to append.
+ */
+void BLI_dynstr_append (DynStr *ds, char *cstr);
+
+ /**
+ * Find the length of a DynStr.
+ *
+ * @param ds The DynStr of interest.
+ * @return The length of @a ds.
+ */
+int BLI_dynstr_get_len (DynStr *ds);
+
+ /**
+ * Get a DynStr's contents as a c-string.
+ * <i> The returned c-string should be free'd
+ * using BLI_freeN. </i>
+ *
+ * @param ds The DynStr of interest.
+ * @return The contents of @a ds as a c-string.
+ */
+char* BLI_dynstr_get_cstring (DynStr *ds);
+
+ /**
+ * Free the DynStr
+ *
+ * @param ds The DynStr to free.
+ */
+void BLI_dynstr_free (DynStr *ds);
+
+#endif
+
diff --git a/source/blender/blenlib/BLI_edgehash.h b/source/blender/blenlib/BLI_edgehash.h
new file mode 100644
index 00000000000..6b7eaedea2f
--- /dev/null
+++ b/source/blender/blenlib/BLI_edgehash.h
@@ -0,0 +1,99 @@
+/**
+ * A general unordered 2-int pair hash table ADT
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: none of this file.
+ *
+ * Contributor(s): Daniel Dunbar
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BLI_EDGEHASH_H
+#define BLI_EDGEHASH_H
+
+struct EdgeHash;
+struct EdgeHashIterator;
+typedef struct EdgeHash EdgeHash;
+typedef struct EdgeHashIterator EdgeHashIterator;
+
+typedef void (*EdgeHashFreeFP)(void *key);
+
+EdgeHash* BLI_edgehash_new (void);
+void BLI_edgehash_free (EdgeHash *eh, EdgeHashFreeFP valfreefp);
+
+ /* Insert edge (v0,v1) into hash with given value, does
+ * not check for duplicates.
+ */
+void BLI_edgehash_insert (EdgeHash *eh, int v0, int v1, void *val);
+
+ /* Return value for given edge (v0,v1), or NULL if
+ * if key does not exist in hash. (If need exists
+ * to differentiate between key-value being NULL and
+ * lack of key then see BLI_edgehash_lookup_p().
+ */
+void* BLI_edgehash_lookup (EdgeHash *eh, int v0, int v1);
+
+ /* Return pointer to value for given edge (v0,v1),
+ * or NULL if key does not exist in hash.
+ */
+void** BLI_edgehash_lookup_p (EdgeHash *eh, int v0, int v1);
+
+ /* Return boolean true/false if edge (v0,v1) in hash. */
+int BLI_edgehash_haskey (EdgeHash *eh, int v0, int v1);
+
+ /* Return number of keys in hash. */
+int BLI_edgehash_size (EdgeHash *eh);
+
+ /* Remove all edges from hash. */
+void BLI_edgehash_clear (EdgeHash *eh, EdgeHashFreeFP valfreefp);
+
+/***/
+
+ /**
+ * Create a new EdgeHashIterator. The hash table must not be mutated
+ * while the iterator is in use, and the iterator will step exactly
+ * BLI_edgehash_size(gh) times before becoming done.
+ */
+EdgeHashIterator* BLI_edgehashIterator_new (EdgeHash *eh);
+
+ /* Free an EdgeHashIterator. */
+void BLI_edgehashIterator_free (EdgeHashIterator *ehi);
+
+ /* Retrieve the key from an iterator. */
+void BLI_edgehashIterator_getKey (EdgeHashIterator *ehi, int *v0_r, int *v1_r);
+
+ /* Retrieve the value from an iterator. */
+void* BLI_edgehashIterator_getValue (EdgeHashIterator *ehi);
+
+ /* Steps the iterator to the next index. */
+void BLI_edgehashIterator_step (EdgeHashIterator *ehi);
+
+ /* Determine if an iterator is done. */
+int BLI_edgehashIterator_isDone (EdgeHashIterator *ehi);
+
+#endif
+
diff --git a/source/blender/blenlib/BLI_editVert.h b/source/blender/blenlib/BLI_editVert.h
new file mode 100644
index 00000000000..795f6781894
--- /dev/null
+++ b/source/blender/blenlib/BLI_editVert.h
@@ -0,0 +1,190 @@
+/**
+ * blenlib/BLI_editVert.h mar 2001 Nzc
+ *
+ * Some editing types needed in the lib (unfortunately) for
+ * scanfill.c
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BLI_EDITVERT_H
+#define BLI_EDITVERT_H
+
+#include "DNA_customdata_types.h"
+#include "DNA_mesh_types.h"
+
+struct DerivedMesh;
+struct RetopoPaintData;
+
+/* note; changing this also might affect the undo copy in editmesh.c */
+typedef struct EditVert
+{
+ struct EditVert *next, *prev;
+ union {
+ /* some lean storage for temporary usage
+ * in editmesh routines
+ */
+ struct EditVert *v;
+ struct EditEdge *e;
+ struct EditFace *f;
+ void *p;
+ long l;
+ float fp;
+ } tmp;
+ float no[3]; /*vertex normal */
+ float co[3]; /*vertex location */
+ short xs, ys; /* used to store a screenspace 2d projection of the verts */
+
+ /* f stores selection eg. if (eve->f & SELECT) {...
+ h for hidden. if (!eve->h) {...
+ f1 and f2 can be used for temp data, clear them first*/
+ unsigned char f, h, f1, f2;
+ short fast; /* only 0 or 1, for editmesh_fastmalloc, do not store temp data here! */
+ int hash;
+ int keyindex; /* original index #, for restoring key information */
+/*#ifdef WITH_VERSE*/
+ void *vvert;
+/*#endif*/
+
+ void *data; /* custom vertex data */
+} EditVert;
+
+struct EditEdge;
+
+typedef struct HashEdge {
+ struct EditEdge *eed;
+ struct HashEdge *next;
+} HashEdge;
+
+/* note; changing this also might affect the undo copy in editmesh.c */
+typedef struct EditEdge
+{
+ struct EditEdge *next, *prev;
+ struct EditVert *v1, *v2;
+ union {
+ /* some lean storage for temporary usage
+ * in editmesh routines
+ */
+ struct EditVert *v;
+ struct EditEdge *e;
+ struct EditFace *f;
+ void *p;
+ long l;
+ float fp;
+ } tmp;
+ short f1, f2; /* short, f1 is (ab)used in subdiv */
+ unsigned char f, h, dir, seam, sharp;
+ float crease;
+ short fast; /* only 0 or 1, for editmesh_fastmalloc */
+ short fgoni; /* index for fgon, for search */
+ HashEdge hash;
+ void *data; /*custom edge data*/
+} EditEdge;
+
+/* note; changing this also might affect the undo copy in editmesh.c */
+typedef struct EditFace
+{
+ struct EditFace *next, *prev;
+ struct EditVert *v1, *v2, *v3, *v4;
+ struct EditEdge *e1, *e2, *e3, *e4;
+ union {
+ /* some lean storage for temporary usage
+ * in editmesh routines
+ */
+ struct EditVert *v;
+ struct EditEdge *e;
+ struct EditFace *f;
+ void *p;
+ long l;
+ float fp;
+ } tmp;
+ float n[3], cent[3];
+ unsigned char mat_nr, flag;
+ unsigned char f, f1, h;
+ unsigned char fast; /* only 0 or 1, for editmesh_fastmalloc */
+ unsigned char fgonf; /* flag for fgon options */
+/*#ifdef WITH_VERSE*/
+ void *vface;
+/*#endif*/
+ void *data; /* custom face data */
+} EditFace;
+
+
+/*selection types*/
+#define EDITVERT 0
+#define EDITEDGE 1
+#define EDITFACE 2
+
+typedef struct EditSelection
+{
+ struct EditSelection *next, *prev;
+ short type;
+ void *data;
+} EditSelection;
+
+
+typedef struct EditMesh
+{
+ ListBase verts, edges, faces;
+ ListBase selected; /*EditSelections. Used to store the order in which things are selected.*/
+ HashEdge *hashedgetab;
+
+ /* this is for the editmesh_fastmalloc */
+ EditVert *allverts, *curvert;
+ EditEdge *alledges, *curedge;
+ EditFace *allfaces, *curface;
+ /* DerivedMesh caches... note that derived cage can be equivalent
+ * to derived final, care should be taken on release.
+ */
+
+ /* used for keeping track of the last clicked on face - so the space image
+ * when using the last selected face - (EditSelection) the space image flickered too much
+ *
+ * never access this directly, use EM_set_actFace and EM_get_actFace */
+ EditFace *act_face;
+
+ struct DerivedMesh *derivedCage, *derivedFinal;
+ /* the custom data layer mask that was last used to calculate
+ * derivedCage and derivedFinal
+ */
+ int lastDataMask;
+
+ struct RetopoPaintData *retopo_paint_data;
+
+ CustomData vdata, edata, fdata;
+
+#ifdef WITH_VERSE
+ void *vnode;
+#endif
+} EditMesh;
+
+#endif
+
diff --git a/source/blender/blenlib/BLI_ghash.h b/source/blender/blenlib/BLI_ghash.h
new file mode 100644
index 00000000000..ce5be5fc311
--- /dev/null
+++ b/source/blender/blenlib/BLI_ghash.h
@@ -0,0 +1,118 @@
+/**
+ * A general (pointer -> pointer) hash table ADT
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BLI_GHASH_H
+#define BLI_GHASH_H
+
+struct GHash;
+typedef struct GHash GHash;
+typedef struct GHashIterator GHashIterator;
+
+typedef unsigned int (*GHashHashFP) (void *key);
+typedef int (*GHashCmpFP) (void *a, void *b);
+typedef void (*GHashKeyFreeFP) (void *key);
+typedef void (*GHashValFreeFP) (void *val);
+
+GHash* BLI_ghash_new (GHashHashFP hashfp, GHashCmpFP cmpfp);
+void BLI_ghash_free (GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp);
+
+void BLI_ghash_insert (GHash *gh, void *key, void *val);
+int BLI_ghash_remove (GHash *gh, void *key, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp);
+void* BLI_ghash_lookup (GHash *gh, void *key);
+int BLI_ghash_haskey (GHash *gh, void *key);
+
+int BLI_ghash_size (GHash *gh);
+
+/* *** */
+
+ /**
+ * Create a new GHashIterator. The hash table must not be mutated
+ * while the iterator is in use, and the iterator will step exactly
+ * BLI_ghash_size(gh) times before becoming done.
+ *
+ * @param gh The GHash to iterate over.
+ * @return Pointer to a new DynStr.
+ */
+GHashIterator* BLI_ghashIterator_new (GHash *gh);
+ /**
+ * Free a GHashIterator.
+ *
+ * @param ghi The iterator to free.
+ */
+void BLI_ghashIterator_free (GHashIterator *ghi);
+
+ /**
+ * Retrieve the key from an iterator.
+ *
+ * @param ghi The iterator.
+ * @return The key at the current index, or NULL if the
+ * iterator is done.
+ */
+void* BLI_ghashIterator_getKey (GHashIterator *ghi);
+ /**
+ * Retrieve the value from an iterator.
+ *
+ * @param ghi The iterator.
+ * @return The value at the current index, or NULL if the
+ * iterator is done.
+ */
+void* BLI_ghashIterator_getValue (GHashIterator *ghi);
+ /**
+ * Steps the iterator to the next index.
+ *
+ * @param ghi The iterator.
+ */
+void BLI_ghashIterator_step (GHashIterator *ghi);
+ /**
+ * Determine if an iterator is done (has reached the end of
+ * the hash table).
+ *
+ * @param ghi The iterator.
+ * @return True if done, False otherwise.
+ */
+int BLI_ghashIterator_isDone (GHashIterator *ghi);
+
+/* *** */
+
+unsigned int BLI_ghashutil_ptrhash (void *key);
+int BLI_ghashutil_ptrcmp (void *a, void *b);
+
+unsigned int BLI_ghashutil_strhash (void *key);
+int BLI_ghashutil_strcmp (void *a, void *b);
+
+unsigned int BLI_ghashutil_inthash (void *ptr);
+int BLI_ghashutil_intcmp(void *a, void *b);
+
+#endif
+
diff --git a/source/blender/blenlib/BLI_gsqueue.h b/source/blender/blenlib/BLI_gsqueue.h
new file mode 100644
index 00000000000..5180d3d8bbc
--- /dev/null
+++ b/source/blender/blenlib/BLI_gsqueue.h
@@ -0,0 +1,96 @@
+/*
+ * A generic structure queue (a queue for fixed length
+ * (generally small) structures.
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BLI_GSQUEUE_H
+#define BLI_GSQUEUE_H
+
+typedef struct _GSQueue GSQueue;
+
+ /**
+ * Create a new GSQueue.
+ *
+ * @param elem_size The size of the structures in the queue.
+ * @retval The new queue
+ */
+GSQueue* BLI_gsqueue_new (int elem_size);
+
+ /**
+ * Query if the queue is empty
+ */
+int BLI_gsqueue_is_empty(GSQueue *gq);
+
+ /**
+ * Access the item at the head of the queue
+ * without removing it.
+ *
+ * @param item_r A pointer to an appropriatly
+ * sized structure (the size passed to BLI_gsqueue_new)
+ */
+void BLI_gsqueue_peek (GSQueue *gq, void *item_r);
+
+ /**
+ * Access the item at the head of the queue
+ * and remove it.
+ *
+ * @param item_r A pointer to an appropriatly
+ * sized structure (the size passed to BLI_gsqueue_new).
+ * Can be NULL if desired.
+ */
+void BLI_gsqueue_pop (GSQueue *gq, void *item_r);
+
+ /**
+ * Push an element onto the tail of the queue.
+ *
+ * @param item A pointer to an appropriatly
+ * sized structure (the size passed to BLI_gsqueue_new).
+ */
+void BLI_gsqueue_push (GSQueue *gq, void *item);
+
+ /**
+ * Push an element back onto the head of the queue (so
+ * it would be returned from the next call to BLI_gsqueue_pop).
+ *
+ * @param item A pointer to an appropriatly
+ * sized structure (the size passed to BLI_gsqueue_new).
+ */
+void BLI_gsqueue_pushback (GSQueue *gq, void *item);
+
+ /**
+ * Free the queue
+ */
+void BLI_gsqueue_free (GSQueue *gq);
+
+#endif /* BLI_GSQUEUE_H */
+
diff --git a/source/blender/blenlib/BLI_heap.h b/source/blender/blenlib/BLI_heap.h
new file mode 100644
index 00000000000..8ebb6ad269f
--- /dev/null
+++ b/source/blender/blenlib/BLI_heap.h
@@ -0,0 +1,74 @@
+/**
+ * A heap / priority queue ADT
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: none of this file.
+ *
+ * Contributor(s): Brecht Van Lommel
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BLI_HEAP_H
+#define BLI_HEAP_H
+
+struct Heap;
+struct HeapNode;
+typedef struct Heap Heap;
+typedef struct HeapNode HeapNode;
+
+typedef void (*HeapFreeFP)(void *ptr);
+
+/* Creates a new heap. BLI_memarena is used for allocating nodes. Removed nodes
+ are recycled, so memory usage will not shrink. */
+Heap* BLI_heap_new (void);
+void BLI_heap_free (Heap *heap, HeapFreeFP ptrfreefp);
+
+/* Insert heap node with a value (often a 'cost') and pointer into the heap,
+ duplicate values are allowed. */
+HeapNode* BLI_heap_insert (Heap *heap, float value, void *ptr);
+
+/* Remove a heap node. */
+void BLI_heap_remove (Heap *heap, HeapNode *node);
+
+/* Return 0 if the heap is empty, 1 otherwise. */
+int BLI_heap_empty (Heap *heap);
+
+/* Return the size of the heap. */
+int BLI_heap_size (Heap *heap);
+
+/* Return the top node of the heap. This is the node with the lowest value. */
+HeapNode* BLI_heap_top (Heap *heap);
+
+/* Pop the top node off the heap and return it's pointer. */
+void* BLI_heap_popmin (Heap *heap);
+
+/* Return the value or pointer of a heap node. */
+float BLI_heap_node_value (HeapNode *heap);
+void* BLI_heap_node_ptr (HeapNode *heap);
+
+#endif
+
diff --git a/source/blender/blenlib/BLI_jitter.h b/source/blender/blenlib/BLI_jitter.h
new file mode 100644
index 00000000000..1cd4880d0b7
--- /dev/null
+++ b/source/blender/blenlib/BLI_jitter.h
@@ -0,0 +1,40 @@
+/*
+ * jitter.h
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef BLI_JITTER_H
+#define BLI_JITTER_H
+
+extern void BLI_initjit(float *jitarr, int num);
+extern void BLI_jitterate1(float *jit1, float *jit2, int num, float rad1);
+extern void BLI_jitterate2(float *jit1, float *jit2, int num, float rad2);
+
+#endif
+
diff --git a/source/blender/blenlib/BLI_linklist.h b/source/blender/blenlib/BLI_linklist.h
new file mode 100644
index 00000000000..9982047ec9e
--- /dev/null
+++ b/source/blender/blenlib/BLI_linklist.h
@@ -0,0 +1,62 @@
+/*
+ * Routines for working with singly linked lists
+ * of 'links' - pointers to other data.
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BLI_LINKLIST_H
+#define BLI_LINKLIST_H
+
+struct MemArena;
+
+typedef void (*LinkNodeFreeFP)(void *link);
+typedef void (*LinkNodeApplyFP)(void *link, void *userdata);
+
+struct LinkNode;
+typedef struct LinkNode {
+ struct LinkNode *next;
+ void *link;
+} LinkNode;
+
+int BLI_linklist_length (struct LinkNode *list);
+
+void BLI_linklist_reverse (struct LinkNode **listp);
+
+void BLI_linklist_prepend (struct LinkNode **listp, void *ptr);
+void BLI_linklist_append (struct LinkNode **listp, void *ptr);
+void BLI_linklist_prepend_arena (struct LinkNode **listp, void *ptr, struct MemArena *ma);
+
+void BLI_linklist_free (struct LinkNode *list, LinkNodeFreeFP freefunc);
+void BLI_linklist_apply (struct LinkNode *list, LinkNodeApplyFP applyfunc, void *userdata);
+
+#endif
+
diff --git a/source/blender/blenlib/BLI_memarena.h b/source/blender/blenlib/BLI_memarena.h
new file mode 100644
index 00000000000..420995e3b11
--- /dev/null
+++ b/source/blender/blenlib/BLI_memarena.h
@@ -0,0 +1,61 @@
+/*
+ * Memory arena ADT
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * Memory arena's are commonly used when the program
+ * needs to quickly allocate lots of little bits of
+ * data, which are all freed at the same moment.
+ *
+ */
+
+#ifndef BLI_MEMARENA_H
+#define BLI_MEMARENA_H
+
+ /* A reasonable standard buffer size, big
+ * enough to not cause much internal fragmentation,
+ * small enough not to waste resources
+ */
+#define BLI_MEMARENA_STD_BUFSIZE (1<<14)
+
+struct MemArena;
+typedef struct MemArena MemArena;
+
+
+struct MemArena* BLI_memarena_new (int bufsize);
+void BLI_memarena_free (struct MemArena *ma);
+
+void BLI_memarena_use_calloc (struct MemArena *ma);
+
+void* BLI_memarena_alloc (struct MemArena *ma, int size);
+
+#endif
+
diff --git a/source/blender/blenlib/BLI_rand.h b/source/blender/blenlib/BLI_rand.h
new file mode 100644
index 00000000000..da2ecb79651
--- /dev/null
+++ b/source/blender/blenlib/BLI_rand.h
@@ -0,0 +1,99 @@
+/**
+ * @file BLI_rand.h
+ *
+ * Random number functions.
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BLI_RAND_H
+#define BLI_RAND_H
+
+ /* RNG is just an abstract random number generator
+ * type that avoids using globals, otherwise identical
+ * to BLI_rand functions below.
+ */
+struct RNG;
+typedef struct RNG RNG;
+
+struct RNG* rng_new (unsigned int seed);
+void rng_free (struct RNG* rng);
+
+void rng_seed (struct RNG* rng, unsigned int seed);
+int rng_getInt (struct RNG* rng);
+double rng_getDouble (struct RNG* rng);
+float rng_getFloat (struct RNG* rng);
+void rng_shuffleArray(struct RNG *rng, void *data, int elemSize, int numElems);
+
+ /** Seed the random number generator */
+void BLI_srand (unsigned int seed);
+
+ /** Better seed for the random number generator, using noise.c hash[] */
+void BLI_srandom (unsigned int seed);
+
+ /** Return a pseudo-random number N where 0<=N<(2^31) */
+int BLI_rand (void);
+
+ /** Return a pseudo-random number N where 0.0<=N<1.0 */
+double BLI_drand (void);
+
+ /** Return a pseudo-random number N where 0.0f<=N<1.0f */
+float BLI_frand (void);
+
+ /** Fills a block of memory starting at @a addr
+ * and extending @a len bytes with pseudo-random
+ * contents. This routine does not use nor modify
+ * the state of the BLI random number generator.
+ */
+void BLI_fillrand (void *addr, int len);
+
+ /** Shuffle an array randomly using the given seed.
+ * contents. This routine does not use nor modify
+ * the state of the BLI random number generator.
+ */
+void BLI_array_randomize (void *data, int elemSize, int numElems, unsigned int seed);
+
+
+ /** Better seed for the random number generator, using noise.c hash[] */
+ /** Allows up to 16 threads to address */
+void BLI_thread_srandom (int thread, unsigned int seed);
+
+ /** Return a pseudo-random number N where 0<=N<(2^31) */
+ /** Allows up to 16 threads to address */
+int BLI_thread_rand (int thread);
+
+ /** Return a pseudo-random number N where 0.0f<=N<1.0f */
+ /** Allows up to 16 threads to address */
+float BLI_thread_frand (int thread);
+
+
+
+#endif
+
diff --git a/source/blender/blenlib/BLI_storage_types.h b/source/blender/blenlib/BLI_storage_types.h
new file mode 100644
index 00000000000..ebce33852a1
--- /dev/null
+++ b/source/blender/blenlib/BLI_storage_types.h
@@ -0,0 +1,83 @@
+/**
+ * blenlib/BLI_storage_types.h
+ *
+ * Some types for dealing with directories
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BLI_STORAGE_TYPES_H
+#define BLI_STORAGE_TYPES_H
+
+#include <sys/stat.h>
+
+#define HDRSIZE 512
+#define NAMSIZE 200
+
+struct header{
+ char name[NAMSIZE];
+ unsigned int size;
+ unsigned int chksum;
+ char fill[HDRSIZE-NAMSIZE-2*sizeof(unsigned int)];
+};
+
+#if defined(WIN32) && !defined(FREE_WINDOWS)
+typedef unsigned int mode_t;
+#endif
+
+struct ImBuf;
+
+struct direntry{
+ char *string;
+ mode_t type;
+ char *relname;
+ struct stat s;
+ unsigned int flags;
+ char size[16];
+ char mode1[4];
+ char mode2[4];
+ char mode3[4];
+ char owner[16];
+ char time[8];
+ char date[16];
+ char extra[16];
+ void *poin;
+ int nr;
+ struct ImBuf *image;
+};
+
+struct dirlink
+{
+ struct dirlink *next,*prev;
+ char *name;
+};
+
+#endif /* BLI_STORAGE_TYPES_H */
+
diff --git a/source/blender/blenlib/BLI_threads.h b/source/blender/blenlib/BLI_threads.h
new file mode 100644
index 00000000000..60ecce3f9d8
--- /dev/null
+++ b/source/blender/blenlib/BLI_threads.h
@@ -0,0 +1,54 @@
+/*
+ *
+ * $Id:
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef BLI_THREADS_H
+#define BLI_THREADS_H
+
+/* one custom lock available now. can be extended */
+#define LOCK_IMAGE 0
+#define LOCK_CUSTOM1 1
+
+/* for tables, button in UI, etc */
+#define BLENDER_MAX_THREADS 8
+
+struct ListBase;
+
+void BLI_init_threads (struct ListBase *threadbase, void *(*do_thread)(void *), int tot);
+int BLI_available_threads(struct ListBase *threadbase);
+int BLI_available_thread_index(struct ListBase *threadbase);
+void BLI_insert_thread (struct ListBase *threadbase, void *callerdata);
+void BLI_remove_thread (struct ListBase *threadbase, void *callerdata);
+void BLI_end_threads (struct ListBase *threadbase);
+
+void BLI_lock_thread (int type);
+void BLI_unlock_thread (int type);
+
+#endif
+
diff --git a/source/blender/blenlib/BLI_vfontdata.h b/source/blender/blenlib/BLI_vfontdata.h
new file mode 100644
index 00000000000..ce800111afb
--- /dev/null
+++ b/source/blender/blenlib/BLI_vfontdata.h
@@ -0,0 +1,103 @@
+/**
+ * @file BLI_vfontdata.h
+ *
+ * A structure to represent vector fonts,
+ * and to load them from PostScript fonts.
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BLI_VFONTDATA_H
+#define BLI_VFONTDATA_H
+
+#include "DNA_listBase.h"
+
+struct PackedFile;
+struct VFont;
+
+#define MAX_VF_CHARS 256
+
+typedef struct VFontData {
+ ListBase characters;
+ // ListBase nurbsbase[MAX_VF_CHARS];
+ // float resol[MAX_VF_CHARS];
+ // float width[MAX_VF_CHARS];
+ // float *points[MAX_VF_CHARS];
+ char name[128];
+} VFontData;
+
+typedef struct VChar {
+ struct VChar *next, *prev;
+ ListBase nurbsbase;
+ unsigned long index;
+ float resol;
+ float width;
+ float *points;
+} VChar;
+
+struct TmpFont
+{
+ struct TmpFont *next, *prev;
+ struct PackedFile *pf;
+ struct VFont *vfont;
+};
+
+
+/**
+ * Construct a new VFontData structure from
+ * PostScript font data in a PackedFile.
+ *
+ * @param pf The font data.
+ * @retval A new VFontData structure, or NULL
+ * if unable to load.
+ */
+ VFontData*
+BLI_vfontdata_from_psfont(
+ struct PackedFile *pf);
+
+/**
+ * Construct a new VFontData structure from
+ * Freetype font data in a PackedFile.
+ *
+ * @param pf The font data.
+ * @retval A new VFontData structure, or NULL
+ * if unable to load.
+ */
+ VFontData*
+BLI_vfontdata_from_freetypefont(
+ struct PackedFile *pf);
+
+ int
+BLI_vfontchar_from_freetypefont(
+ struct VFont *vfont, unsigned long character);
+
+#endif
+
diff --git a/source/blender/blenlib/BLI_winstuff.h b/source/blender/blenlib/BLI_winstuff.h
new file mode 100644
index 00000000000..0f39d37c31f
--- /dev/null
+++ b/source/blender/blenlib/BLI_winstuff.h
@@ -0,0 +1,119 @@
+/**
+ * Compatibility-like things for windows.
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#pragma warning(once: 4761 4305 4244 4018)
+
+#define WIN32_LEAN_AND_MEAN
+
+#ifndef WIN32_SKIP_HKEY_PROTECTION
+#define HKEY WIN32_HKEY // prevent competing definitions
+#include <windows.h>
+#undef HKEY
+#else
+#include <windows.h>
+#endif
+
+#undef near
+#undef far
+#undef rad
+#undef rad1
+#undef rad2
+#undef rad3
+#undef vec
+#undef rect
+#undef rct1
+#undef rct2
+
+#define near clipsta
+#define far clipend
+
+#undef small
+
+#ifndef __WINSTUFF_H__
+#define __WINSTUFF_H__
+
+ // These definitions are also in arithb for simplicity
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+#ifndef M_PI_2
+#define M_PI_2 1.57079632679489661923
+#endif
+#ifndef M_SQRT2
+#define M_SQRT2 1.41421356237309504880
+#endif
+#ifndef M_SQRT1_2
+#define M_SQRT1_2 0.70710678118654752440
+#endif
+
+#define MAXPATHLEN MAX_PATH
+
+#ifndef S_ISREG
+#define S_ISREG(x) ((x&S_IFMT) == S_IFREG)
+#endif
+#ifndef S_ISDIR
+#define S_ISDIR(x) ((x&S_IFMT) == S_IFDIR)
+#endif
+
+#ifndef FREE_WINDOWS
+typedef unsigned int mode_t;
+#endif
+
+struct dirent {
+ int d_ino;
+ int d_off;
+ unsigned short d_reclen;
+ char *d_name;
+};
+
+typedef struct _DIR {
+ HANDLE handle;
+ WIN32_FIND_DATA data;
+ char path[MAX_PATH];
+ long dd_loc;
+ long dd_size;
+ char dd_buf[4096];
+ void *dd_direct;
+
+ struct dirent direntry;
+} DIR;
+
+void RegisterBlendExtension(char * str);
+DIR *opendir (const char *path);
+struct dirent *readdir(DIR *dp);
+int closedir (DIR *dp);
+void get_default_root(char* root);
+
+#endif /* __WINSTUFF_H__ */
+
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
new file mode 100644
index 00000000000..4812cad033d
--- /dev/null
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -0,0 +1,56 @@
+# $Id$
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2006, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Jacques Beaurain.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+
+FILE(GLOB SRC intern/*.c)
+
+SET(INC
+ . ../makesdna ../blenkernel ../../../intern/guardedalloc ../include
+ ${FREETYPE_INC}
+ ${SDL_INC}
+ ${ZLIB_INC}
+)
+
+IF(WITH_VERSE)
+ ADD_DEFINITIONS(-DWITH_VERSE)
+ SET(INC ${INC} ${VERSE_INC})
+ENDIF(WITH_VERSE)
+
+IF(WITH_INTERNATIONAL)
+ ADD_DEFINITIONS(-DWITH_FREETYPE2)
+ENDIF(WITH_INTERNATIONAL)
+
+IF(WIN32)
+ SET(INC ${INC} ${PTHREADS_INC})
+ENDIF(WIN32)
+
+BLENDERLIB(bf_blenlib "${SRC}" "${INC}")
+#if env['OURPLATFORM'] == 'linux2':
+# cflags='-pthread'
+#
+#env.BlenderLib ( 'bf_blenlib', sources, Split(incs), Split(defs), libtype=['core','player'], priority = [85,195], compileflags =cflags )
diff --git a/source/blender/blenlib/MTC_matrixops.h b/source/blender/blenlib/MTC_matrixops.h
new file mode 100644
index 00000000000..27b5bb1ca95
--- /dev/null
+++ b/source/blender/blenlib/MTC_matrixops.h
@@ -0,0 +1,165 @@
+/*
+ * matrixops.h
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef MATRIXOPS_H
+#define MATRIXOPS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ------------------------------------------------------------------------- */
+/* need rewriting: */
+/**
+ * copy the left upp3 3 by 3 of m2 to m1
+ */
+void MTC_Mat3CpyMat4(float m1[][3], float m2[][4]);
+
+/* ------------------------------------------------------------------------- */
+/* operations based on 4 by 4 matrices */
+
+/**
+ * Copy m1 to m2
+ */
+void MTC_Mat4CpyMat4(float m1[][4], float m2[][4]);
+
+/**
+ * Multiply all matrices after the first, leave the result in the
+ * first argument
+ */
+void MTC_Mat4MulSerie(float answ[][4],
+ float m1[][4], float m2[][4], float m3[][4],
+ float m4[][4], float m5[][4], float m6[][4],
+ float m7[][4], float m8[][4]);
+
+/**
+ * m1 = m2 matprod m3
+ */
+void MTC_Mat4MulMat4(float m1[][4], float m2[][4], float m3[][4]);
+
+/**
+ * Do vec^t prod mat, result in vec. Ignore vec[3] (vec is a
+ * float[3])
+ */
+void MTC_Mat4MulVecfl(float mat[][4], float *vec);
+
+/**
+ * Invert mat, result in inverse. Always returns 1
+ */
+int MTC_Mat4Invert(float inverse[][4], float mat[][4]);
+
+/**
+ * Make the set of mat orthonormal (mat should already be orthogonal)?
+ * (doesn't appear to normalize properly?)
+ */
+void MTC_Mat4Ortho(float mat[][4]);
+
+/**
+ * vec = mat prod vec, result in vec, ignore fourth component entirely
+ * (4th component is _not_ accessed!!! vec is 3d)
+ */
+void MTC_Mat4Mul3Vecfl(float mat[][4], float *vec);
+
+/**
+ * vec = mat prod vec, result in vec
+ */
+void MTC_Mat4MulVec4fl(float mat[][4], float *vec);
+
+/**
+ * Set <m> to the 4-D unity matrix
+ */
+void MTC_Mat4One(float m[][4]);
+
+/**
+ * Swap matrices m1 and m2
+ */
+void MTC_Mat4SwapMat4(float m1[][4], float m2[][4]);
+
+/**
+ * Copy m2 to the top-left 3x3 of m1, don't touch the remaining elements.
+ */
+void MTC_Mat4CpyMat3nc(float m1[][4], float m2[][3]);
+
+/**
+ * m1 = m2 * m3, but only the top-left 3x3
+ */
+void MTC_Mat4MulMat33(float m1[][3], float m2[][4], float m3[][3]);
+
+/* ------------------------------------------------------------------------- */
+/* Operations based on 3 by 3 matrices */
+/**
+ * Do vec^t prod mat, result in vec.(vex is 3d)
+ */
+void MTC_Mat3MulVecfl(float mat[][3], float *vec);
+
+/**
+ * Copy m1 to m2
+ */
+void MTC_Mat3CpyMat3(float m1[][3], float m2[][3]);
+
+/**
+ * m1 = m2 prod m3
+ */
+void MTC_Mat3MulMat3(float m1[][3], float m3[][3], float m2[][3]);
+
+/**
+ * vec = vec prod mat
+ */
+void MTC_Mat3MulVecd(float mat[][3], double *vec);
+
+/**
+ * Guess: invert matrix
+ * result goes to m1
+ */
+void MTC_Mat3Inv(float m1[][3], float m2[][3]);
+
+/**
+ * Sort of a determinant matrix? Doesn't seem very adjoint to me...
+ * result goes to m1
+ */
+void MTC_Mat3Adj(float m1[][3], float m[][3]);
+
+/**
+ * Set <m> to the 3D unity matrix
+ */
+void MTC_Mat3One(float m[][3]);
+
+/* ------------------------------------------------------------------------- */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MATRIXOPS_H */
+
diff --git a/source/blender/blenlib/MTC_vectorops.h b/source/blender/blenlib/MTC_vectorops.h
new file mode 100644
index 00000000000..64b2c312eb4
--- /dev/null
+++ b/source/blender/blenlib/MTC_vectorops.h
@@ -0,0 +1,61 @@
+/*
+ * vectorops.h
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef VECTOROPS_H
+#define VECTOROPS_H
+
+/* ------------------------------------------------------------------------- */
+
+void MTC_diff3Int(int v1[3], int v2[3], int v3[3]);
+void MTC_cross3Int(int v1[3], int v2[3], int v3[3]);
+int MTC_dot3Int(int v1[3], int v2[3]);
+
+void MTC_diff3Float(float v1[3], float v2[3], float v3[3]);
+void MTC_cross3Float(float v1[3], float v2[3], float v3[3]);
+float MTC_dot3Float(float v1[3], float v2[3]);
+void MTC_cp3Float(float v1[3], float v2[3]);
+/**
+ * Copy vector with a minus sign (so a = -b)
+ */
+void MTC_cp3FloatInv(float v1[3], float v2[3]);
+
+void MTC_swapInt(int *i1, int *i2);
+
+void MTC_diff3DFF(double v1[3], float v2[3], float v3[3]);
+void MTC_cross3Double(double v1[3], double v2[3], double v3[3]);
+float MTC_normalize3DF(float n[3]);
+
+/* ------------------------------------------------------------------------- */
+#endif /* VECTOROPS_H */
+
diff --git a/source/blender/blenlib/Makefile b/source/blender/blenlib/Makefile
new file mode 100644
index 00000000000..12ee8c5ad8c
--- /dev/null
+++ b/source/blender/blenlib/Makefile
@@ -0,0 +1,37 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+# Bounces make to subdirectories.
+
+SOURCEDIR = source/blender/blenlib
+DIRS = intern
+
+include nan_subdirs.mk
diff --git a/source/blender/blenlib/PIL_dynlib.h b/source/blender/blenlib/PIL_dynlib.h
new file mode 100644
index 00000000000..26e1b2f9ac4
--- /dev/null
+++ b/source/blender/blenlib/PIL_dynlib.h
@@ -0,0 +1,55 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef __PIL_DYNLIB_H__
+#define __PIL_DYNLIB_H__
+
+typedef struct PILdynlib PILdynlib;
+
+ PILdynlib*
+PIL_dynlib_open(
+ char *name);
+
+ void*
+PIL_dynlib_find_symbol(
+ PILdynlib* lib,
+ char *symname);
+
+ char*
+PIL_dynlib_get_error_as_string(
+ PILdynlib* lib);
+
+ void
+PIL_dynlib_close(
+ PILdynlib* lib);
+
+#endif /* __PIL_DYNLIB_H__ */
+
diff --git a/source/blender/blenlib/PIL_time.h b/source/blender/blenlib/PIL_time.h
new file mode 100644
index 00000000000..190a116d658
--- /dev/null
+++ b/source/blender/blenlib/PIL_time.h
@@ -0,0 +1,62 @@
+/**
+ * @file PIL_time.h
+ *
+ * Platform independant time functions.
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef PIL_TIME_H
+#define PIL_TIME_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern
+ /** Return an indication of time, expressed as
+ * seconds since some fixed point. Successive calls
+ * are guarenteed to generate values greator than or
+ * equal to the last call.
+ */
+double PIL_check_seconds_timer (void);
+
+ /**
+ * Platform-independant sleep function.
+ * @param ms Number of milliseconds to sleep
+ */
+void PIL_sleep_ms (int ms);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/source/blender/blenlib/SConscript b/source/blender/blenlib/SConscript
new file mode 100644
index 00000000000..e11934d968e
--- /dev/null
+++ b/source/blender/blenlib/SConscript
@@ -0,0 +1,26 @@
+#!/usr/bin/python
+Import ('env')
+
+sources = env.Glob('intern/*.c')
+
+cflags=''
+incs = '. ../makesdna ../blenkernel #/intern/guardedalloc ../include'
+incs += ' ' + env['BF_FREETYPE_INC']
+incs += ' ' + env['BF_ZLIB_INC']
+incs += ' ' + env['BF_SDL_INC']
+defs = ''
+
+if env['WITH_BF_INTERNATIONAL'] == 1:
+ defs = 'WITH_FREETYPE2'
+
+if env['WITH_BF_VERSE']:
+ defs += ' WITH_VERSE'
+ incs += ' ' + env['BF_VERSE_INCLUDE']
+
+if env['OURPLATFORM'] == 'linux2':
+ cflags='-pthread'
+
+if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw'):
+ incs += ' ' + env['BF_PTHREADS_INC']
+
+env.BlenderLib ( 'bf_blenlib', sources, Split(incs), Split(defs), libtype=['core','player'], priority = [85,195], compileflags =cflags )
diff --git a/source/blender/blenlib/intern/BLI_callbacks.h b/source/blender/blenlib/intern/BLI_callbacks.h
new file mode 100644
index 00000000000..1f854764a59
--- /dev/null
+++ b/source/blender/blenlib/intern/BLI_callbacks.h
@@ -0,0 +1,44 @@
+/**
+ * blenlib/BLI_editVert.h mar 2001 Nzc
+ *
+ * These callbacks are needed in the lib
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BLI_CALLBACKS_H
+#define BLI_CALLBACKS_H
+
+// This is blenlib internal only
+void callLocalErrorCallBack(char* msg);
+
+#endif
+
diff --git a/source/blender/blenlib/intern/BLI_dynstr.c b/source/blender/blenlib/intern/BLI_dynstr.c
new file mode 100644
index 00000000000..8bde670eef5
--- /dev/null
+++ b/source/blender/blenlib/intern/BLI_dynstr.c
@@ -0,0 +1,118 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * Dynamically sized string ADT
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+#include "BLI_blenlib.h"
+#include "BLI_dynstr.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/***/
+
+typedef struct DynStrElem DynStrElem;
+struct DynStrElem {
+ DynStrElem *next;
+
+ char *str;
+};
+
+struct DynStr {
+ DynStrElem *elems, *last;
+ int curlen;
+};
+
+/***/
+
+DynStr *BLI_dynstr_new(void) {
+ DynStr *ds= MEM_mallocN(sizeof(*ds), "DynStr");
+ ds->elems= ds->last= NULL;
+ ds->curlen= 0;
+
+ return ds;
+}
+
+void BLI_dynstr_append(DynStr *ds, char *cstr) {
+ DynStrElem *dse= malloc(sizeof(*dse));
+ int cstrlen= strlen(cstr);
+
+ dse->str= malloc(cstrlen+1);
+ memcpy(dse->str, cstr, cstrlen+1);
+ dse->next= NULL;
+
+ if (!ds->last)
+ ds->last= ds->elems= dse;
+ else
+ ds->last= ds->last->next= dse;
+
+ ds->curlen+= cstrlen;
+}
+
+int BLI_dynstr_get_len(DynStr *ds) {
+ return ds->curlen;
+}
+
+char *BLI_dynstr_get_cstring(DynStr *ds) {
+ char *s, *rets= MEM_mallocN(ds->curlen+1, "dynstr_cstring");
+ DynStrElem *dse;
+
+ for (s= rets, dse= ds->elems; dse; dse= dse->next) {
+ int slen= strlen(dse->str);
+
+ memcpy(s, dse->str, slen);
+
+ s+= slen;
+ }
+ rets[ds->curlen]= '\0';
+
+ return rets;
+}
+
+void BLI_dynstr_free(DynStr *ds) {
+ DynStrElem *dse;
+
+ for (dse= ds->elems; dse; ) {
+ DynStrElem *n= dse->next;
+
+ free(dse->str);
+ free(dse);
+
+ dse= n;
+ }
+
+ MEM_freeN(ds);
+}
diff --git a/source/blender/blenlib/intern/BLI_fileops.h b/source/blender/blenlib/intern/BLI_fileops.h
new file mode 100644
index 00000000000..622706a32e9
--- /dev/null
+++ b/source/blender/blenlib/intern/BLI_fileops.h
@@ -0,0 +1,50 @@
+/**
+ * blenlib/BLI_listBase.h mar 2001 Nzc
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * More low-level fileops from Daniel Dunbar. Two functions were also
+ * defined in storage.c. These are the old fop_ prefixes. There is
+ * definitely some redundancy here!
+ * */
+
+#ifndef BLI_FILEOPS_H
+#define BLI_FILEOPS_H
+
+char *first_slash(char *string);
+
+/* only for the sane unix world: direct calls to system functions :( */
+#ifndef WIN32
+void BLI_setCmdCallBack(int (*f)(char*));
+#endif
+
+#endif
+
diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c
new file mode 100644
index 00000000000..5846bbda40e
--- /dev/null
+++ b/source/blender/blenlib/intern/BLI_ghash.c
@@ -0,0 +1,295 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * A general (pointer -> pointer) hash table ADT
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+#include "BLI_ghash.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/***/
+
+static unsigned int hashsizes[]= {
+ 1, 3, 5, 11, 17, 37, 67, 131, 257, 521, 1031, 2053, 4099, 8209,
+ 16411, 32771, 65537, 131101, 262147, 524309, 1048583, 2097169,
+ 4194319, 8388617, 16777259, 33554467, 67108879, 134217757,
+ 268435459
+};
+
+/***/
+
+typedef struct Entry Entry;
+struct Entry {
+ Entry *next;
+
+ void *key, *val;
+};
+
+struct GHash {
+ GHashHashFP hashfp;
+ GHashCmpFP cmpfp;
+
+ Entry **buckets;
+ int nbuckets, nentries, cursize;
+};
+
+/***/
+
+GHash *BLI_ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp) {
+ GHash *gh= MEM_mallocN(sizeof(*gh), "GHash");
+ gh->hashfp= hashfp;
+ gh->cmpfp= cmpfp;
+
+ gh->cursize= 0;
+ gh->nentries= 0;
+ gh->nbuckets= hashsizes[gh->cursize];
+
+ gh->buckets= malloc(gh->nbuckets*sizeof(*gh->buckets));
+ memset(gh->buckets, 0, gh->nbuckets*sizeof(*gh->buckets));
+
+ return gh;
+}
+
+void BLI_ghash_insert(GHash *gh, void *key, void *val) {
+ unsigned int hash= gh->hashfp(key)%gh->nbuckets;
+ Entry *e= malloc(sizeof(*e));
+
+ e->key= key;
+ e->val= val;
+ e->next= gh->buckets[hash];
+ gh->buckets[hash]= e;
+
+ if (++gh->nentries>gh->nbuckets*3) {
+ Entry *e, **old= gh->buckets;
+ int i, nold= gh->nbuckets;
+
+ gh->nbuckets= hashsizes[++gh->cursize];
+ gh->buckets= malloc(gh->nbuckets*sizeof(*gh->buckets));
+ memset(gh->buckets, 0, gh->nbuckets*sizeof(*gh->buckets));
+
+ for (i=0; i<nold; i++) {
+ for (e= old[i]; e;) {
+ Entry *n= e->next;
+
+ hash= gh->hashfp(e->key)%gh->nbuckets;
+ e->next= gh->buckets[hash];
+ gh->buckets[hash]= e;
+
+ e= n;
+ }
+ }
+
+ free(old);
+ }
+}
+
+void* BLI_ghash_lookup(GHash *gh, void *key) {
+ unsigned int hash= gh->hashfp(key)%gh->nbuckets;
+ Entry *e;
+
+ for (e= gh->buckets[hash]; e; e= e->next)
+ if (gh->cmpfp(key, e->key)==0)
+ return e->val;
+
+ return NULL;
+}
+
+int BLI_ghash_remove (GHash *gh, void *key, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
+{
+ unsigned int hash= gh->hashfp(key)%gh->nbuckets;
+ Entry *e;
+ Entry *p = 0;
+
+ for (e= gh->buckets[hash]; e; e= e->next) {
+ if (gh->cmpfp(key, e->key)==0) {
+ Entry *n= e->next;
+
+ if (keyfreefp) keyfreefp(e->key);
+ if (valfreefp) valfreefp(e->val);
+ free(e);
+
+
+ e= n;
+ if (p)
+ p->next = n;
+ else
+ gh->buckets[hash] = n;
+
+ --gh->nentries;
+ return 1;
+ }
+ p = e;
+ }
+
+ return 0;
+}
+
+int BLI_ghash_haskey(GHash *gh, void *key) {
+ unsigned int hash= gh->hashfp(key)%gh->nbuckets;
+ Entry *e;
+
+ for (e= gh->buckets[hash]; e; e= e->next)
+ if (gh->cmpfp(key, e->key)==0)
+ return 1;
+
+ return 0;
+}
+
+int BLI_ghash_size(GHash *gh) {
+ return gh->nentries;
+}
+
+void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp) {
+ int i;
+
+ for (i=0; i<gh->nbuckets; i++) {
+ Entry *e;
+
+ for (e= gh->buckets[i]; e; ) {
+ Entry *n= e->next;
+
+ if (keyfreefp) keyfreefp(e->key);
+ if (valfreefp) valfreefp(e->val);
+ free(e);
+
+ e= n;
+ }
+ }
+
+ free(gh->buckets);
+ gh->buckets = 0;
+ gh->nentries = 0;
+ gh->nbuckets = 0;
+ MEM_freeN(gh);
+}
+
+/***/
+
+struct GHashIterator {
+ GHash *gh;
+ int curBucket;
+ Entry *curEntry;
+};
+
+GHashIterator *BLI_ghashIterator_new(GHash *gh) {
+ GHashIterator *ghi= malloc(sizeof(*ghi));
+ ghi->gh= gh;
+ ghi->curEntry= NULL;
+ ghi->curBucket= -1;
+ while (!ghi->curEntry) {
+ ghi->curBucket++;
+ if (ghi->curBucket==ghi->gh->nbuckets)
+ break;
+ ghi->curEntry= ghi->gh->buckets[ghi->curBucket];
+ }
+ return ghi;
+}
+void BLI_ghashIterator_free(GHashIterator *ghi) {
+ free(ghi);
+}
+
+void *BLI_ghashIterator_getKey(GHashIterator *ghi) {
+ return ghi->curEntry?ghi->curEntry->key:NULL;
+}
+void *BLI_ghashIterator_getValue(GHashIterator *ghi) {
+ return ghi->curEntry?ghi->curEntry->val:NULL;
+}
+
+void BLI_ghashIterator_step(GHashIterator *ghi) {
+ if (ghi->curEntry) {
+ ghi->curEntry= ghi->curEntry->next;
+ while (!ghi->curEntry) {
+ ghi->curBucket++;
+ if (ghi->curBucket==ghi->gh->nbuckets)
+ break;
+ ghi->curEntry= ghi->gh->buckets[ghi->curBucket];
+ }
+ }
+}
+int BLI_ghashIterator_isDone(GHashIterator *ghi) {
+ return !ghi->curEntry;
+}
+
+/***/
+
+unsigned int BLI_ghashutil_ptrhash(void *key) {
+ return (unsigned int) key;
+}
+int BLI_ghashutil_ptrcmp(void *a, void *b) {
+ if (a==b)
+ return 0;
+ else
+ return (a<b)?-1:1;
+}
+
+unsigned int BLI_ghashutil_inthash(void *ptr) {
+#if defined(_WIN64)
+ unsigned __int64 key = (unsigned __int64)ptr;
+#else
+ unsigned long key = (unsigned long)ptr;
+#endif
+
+ key += ~(key << 16);
+ key ^= (key >> 5);
+ key += (key << 3);
+ key ^= (key >> 13);
+ key += ~(key << 9);
+ key ^= (key >> 17);
+
+ return (unsigned int)(key & 0xffffffff);
+}
+
+int BLI_ghashutil_intcmp(void *a, void *b) {
+ if (a==b)
+ return 0;
+ else
+ return (a<b)?-1:1;
+}
+
+unsigned int BLI_ghashutil_strhash(void *ptr) {
+ char *s= ptr;
+ unsigned int i= 0;
+ unsigned char c;
+
+ while ( (c= *s++) )
+ i= i*37 + c;
+
+ return i;
+}
+int BLI_ghashutil_strcmp(void *a, void *b) {
+ return strcmp(a, b);
+}
diff --git a/source/blender/blenlib/intern/BLI_heap.c b/source/blender/blenlib/intern/BLI_heap.c
new file mode 100644
index 00000000000..4d8a5179645
--- /dev/null
+++ b/source/blender/blenlib/intern/BLI_heap.c
@@ -0,0 +1,220 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: none of this file.
+ *
+ * Contributor(s): Brecht Van Lommel
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * A heap / priority queue ADT.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+#include "BLI_memarena.h"
+#include "BLI_heap.h"
+
+/***/
+
+struct HeapNode {
+ void *ptr;
+ float value;
+ int index;
+};
+
+struct Heap {
+ unsigned int size;
+ unsigned int bufsize;
+ MemArena *arena;
+ HeapNode *freenodes;
+ HeapNode *nodes;
+ HeapNode **tree;
+};
+
+#define SWAP(type, a, b) \
+ { type sw_ap; sw_ap=(a); (a)=(b); (b)=sw_ap; }
+#define HEAP_PARENT(i) ((i-1)>>1)
+#define HEAP_LEFT(i) ((i<<1)+1)
+#define HEAP_RIGHT(i) ((i<<1)+2)
+#define HEAP_COMPARE(a, b) (a->value < b->value)
+#define HEAP_EQUALS(a, b) (a->value == b->value)
+#define HEAP_SWAP(heap, i, j) \
+ { SWAP(int, heap->tree[i]->index, heap->tree[j]->index); \
+ SWAP(HeapNode*, heap->tree[i], heap->tree[j]); }
+
+/***/
+
+Heap *BLI_heap_new()
+{
+ Heap *heap = (Heap*)MEM_callocN(sizeof(Heap), "BLIHeap");
+ heap->bufsize = 1;
+ heap->tree = (HeapNode**)MEM_mallocN(sizeof(HeapNode*), "BLIHeapTree");
+ heap->arena = BLI_memarena_new(1<<16);
+
+ return heap;
+}
+
+void BLI_heap_free(Heap *heap, HeapFreeFP ptrfreefp)
+{
+ int i;
+
+ if (ptrfreefp)
+ for (i = 0; i < heap->size; i++)
+ ptrfreefp(heap->tree[i]->ptr);
+
+ MEM_freeN(heap->tree);
+ BLI_memarena_free(heap->arena);
+ MEM_freeN(heap);
+}
+
+static void BLI_heap_down(Heap *heap, int i)
+{
+ while (1) {
+ int size = heap->size, smallest;
+ int l = HEAP_LEFT(i);
+ int r = HEAP_RIGHT(i);
+
+ smallest = ((l < size) && HEAP_COMPARE(heap->tree[l], heap->tree[i]))? l: i;
+
+ if ((r < size) && HEAP_COMPARE(heap->tree[r], heap->tree[smallest]))
+ smallest = r;
+
+ if (smallest == i)
+ break;
+
+ HEAP_SWAP(heap, i, smallest);
+ i = smallest;
+ }
+}
+
+static void BLI_heap_up(Heap *heap, int i)
+{
+ while (i > 0) {
+ int p = HEAP_PARENT(i);
+
+ if (HEAP_COMPARE(heap->tree[p], heap->tree[i]))
+ break;
+
+ HEAP_SWAP(heap, p, i);
+ i = p;
+ }
+}
+
+HeapNode *BLI_heap_insert(Heap *heap, float value, void *ptr)
+{
+ HeapNode *node;
+
+ if ((heap->size + 1) > heap->bufsize) {
+ int newsize = heap->bufsize*2;
+ HeapNode **newtree;
+
+ newtree = (HeapNode**)MEM_mallocN(newsize*sizeof(*newtree), "BLIHeapTree");
+ memcpy(newtree, heap->tree, sizeof(HeapNode*)*heap->size);
+ MEM_freeN(heap->tree);
+
+ heap->tree = newtree;
+ heap->bufsize = newsize;
+ }
+
+ if (heap->freenodes) {
+ node = heap->freenodes;
+ heap->freenodes = (HeapNode*)(((HeapNode*)heap->freenodes)->ptr);
+ }
+ else
+ node = (HeapNode*)BLI_memarena_alloc(heap->arena, sizeof *node);
+
+ node->value = value;
+ node->ptr = ptr;
+ node->index = heap->size;
+
+ heap->tree[node->index] = node;
+
+ heap->size++;
+
+ BLI_heap_up(heap, heap->size-1);
+
+ return node;
+}
+
+int BLI_heap_empty(Heap *heap)
+{
+ return (heap->size == 0);
+}
+
+int BLI_heap_size(Heap *heap)
+{
+ return heap->size;
+}
+
+HeapNode *BLI_heap_top(Heap *heap)
+{
+ return heap->tree[0];
+}
+
+void *BLI_heap_popmin(Heap *heap)
+{
+ void *ptr = heap->tree[0]->ptr;
+
+ heap->tree[0]->ptr = heap->freenodes;
+ heap->freenodes = heap->tree[0];
+
+ if (heap->size == 1)
+ heap->size--;
+ else {
+ HEAP_SWAP(heap, 0, heap->size-1);
+ heap->size--;
+
+ BLI_heap_down(heap, 0);
+ }
+
+ return ptr;
+}
+
+void BLI_heap_remove(Heap *heap, HeapNode *node)
+{
+ int i = node->index;
+
+ while (i > 0) {
+ int p = HEAP_PARENT(i);
+
+ HEAP_SWAP(heap, p, i);
+ i = p;
+ }
+
+ BLI_heap_popmin(heap);
+}
+
+float BLI_heap_node_value(HeapNode *node)
+{
+ return node->value;
+}
+
+void *BLI_heap_node_ptr(HeapNode *node)
+{
+ return node->ptr;
+}
+
diff --git a/source/blender/blenlib/intern/BLI_linklist.c b/source/blender/blenlib/intern/BLI_linklist.c
new file mode 100644
index 00000000000..6bb828a44bf
--- /dev/null
+++ b/source/blender/blenlib/intern/BLI_linklist.c
@@ -0,0 +1,119 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * Support for linked lists.
+ */
+
+#include "MEM_guardedalloc.h"
+#include "BLI_blenlib.h"
+#include "BLI_linklist.h"
+#include "BLI_memarena.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+int BLI_linklist_length(LinkNode *list) {
+ if (0) {
+ return list?(1+BLI_linklist_length(list->next)):0;
+ } else {
+ int len;
+
+ for (len=0; list; list= list->next)
+ len++;
+
+ return len;
+ }
+}
+
+void BLI_linklist_reverse(LinkNode **listp) {
+ LinkNode *rhead= NULL, *cur= *listp;
+
+ while (cur) {
+ LinkNode *next= cur->next;
+
+ cur->next= rhead;
+ rhead= cur;
+
+ cur= next;
+ }
+
+ *listp= rhead;
+}
+
+void BLI_linklist_prepend(LinkNode **listp, void *ptr) {
+ LinkNode *nlink= MEM_mallocN(sizeof(*nlink), "nlink");
+ nlink->link= ptr;
+
+ nlink->next= *listp;
+ *listp= nlink;
+}
+
+void BLI_linklist_append(LinkNode **listp, void *ptr) {
+ LinkNode *nlink= MEM_mallocN(sizeof(*nlink), "nlink");
+ LinkNode *node = *listp;
+
+ nlink->link = ptr;
+ nlink->next = NULL;
+
+ if(node == NULL){
+ *listp = nlink;
+ } else {
+ while(node->next != NULL){
+ node = node->next;
+ }
+ node->next = nlink;
+ }
+}
+
+void BLI_linklist_prepend_arena(LinkNode **listp, void *ptr, MemArena *ma) {
+ LinkNode *nlink= BLI_memarena_alloc(ma, sizeof(*nlink));
+ nlink->link= ptr;
+
+ nlink->next= *listp;
+ *listp= nlink;
+}
+
+void BLI_linklist_free(LinkNode *list, LinkNodeFreeFP freefunc) {
+ while (list) {
+ LinkNode *next= list->next;
+
+ if (freefunc)
+ freefunc(list->link);
+ MEM_freeN(list);
+
+ list= next;
+ }
+}
+
+void BLI_linklist_apply(LinkNode *list, LinkNodeApplyFP applyfunc, void *userdata) {
+ for (; list; list= list->next)
+ applyfunc(list->link, userdata);
+}
diff --git a/source/blender/blenlib/intern/BLI_memarena.c b/source/blender/blenlib/intern/BLI_memarena.c
new file mode 100644
index 00000000000..c42ff3610fd
--- /dev/null
+++ b/source/blender/blenlib/intern/BLI_memarena.c
@@ -0,0 +1,96 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * Efficient memory allocation for lots of similar small chunks.
+ */
+
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_memarena.h"
+#include "BLI_linklist.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+struct MemArena {
+ unsigned char *curbuf;
+ int bufsize, cursize;
+
+ int use_calloc;
+
+ LinkNode *bufs;
+};
+
+MemArena *BLI_memarena_new(int bufsize) {
+ MemArena *ma= MEM_callocN(sizeof(*ma), "memarena");
+ ma->bufsize= bufsize;
+
+ return ma;
+}
+
+void BLI_memarena_use_calloc(MemArena *ma) {
+ ma->use_calloc= 1;
+}
+
+void BLI_memarena_free(MemArena *ma) {
+ BLI_linklist_free(ma->bufs, (void(*)(void*)) MEM_freeN);
+ MEM_freeN(ma);
+}
+
+ /* amt must be power of two */
+#define PADUP(num, amt) ((num+(amt-1))&~(amt-1))
+
+void *BLI_memarena_alloc(MemArena *ma, int size) {
+ void *ptr;
+
+ /* ensure proper alignment by rounding
+ * size up to multiple of 8 */
+ size= PADUP(size, 8);
+
+ if (size>ma->cursize) {
+ ma->cursize= (size>ma->bufsize)?size:ma->bufsize;
+ if(ma->use_calloc)
+ ma->curbuf= MEM_callocN(ma->cursize, "memarena calloc");
+ else
+ ma->curbuf= MEM_mallocN(ma->cursize, "memarena malloc");
+
+ BLI_linklist_prepend(&ma->bufs, ma->curbuf);
+ }
+
+ ptr= ma->curbuf;
+ ma->curbuf+= size;
+ ma->cursize-= size;
+
+ return ptr;
+}
diff --git a/source/blender/blenlib/intern/BLI_scanfill.h b/source/blender/blenlib/intern/BLI_scanfill.h
new file mode 100644
index 00000000000..cc02d76ad69
--- /dev/null
+++ b/source/blender/blenlib/intern/BLI_scanfill.h
@@ -0,0 +1,41 @@
+/**
+ * blenlib/BLI_scanfill.h mar 2001 Nzc
+ *
+ * Filling meshes.
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BLI_SCANFILL_H
+#define BLI_SCANFILL_H
+
+#endif
+
diff --git a/source/blender/blenlib/intern/BLI_storage.h b/source/blender/blenlib/intern/BLI_storage.h
new file mode 100644
index 00000000000..5e9c377c410
--- /dev/null
+++ b/source/blender/blenlib/intern/BLI_storage.h
@@ -0,0 +1,41 @@
+/* $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BLI_STORAGE_H
+#define BLI_STORAGE_H
+
+#include "BLI_storage_types.h"
+
+void BLI_adddirstrings(void);
+void BLI_builddir(char *dirname, char *relname);
+int BLI_compare(struct direntry *entry1, struct direntry *entry2);
+
+#endif /* BLI_STORAGE_H */
+
diff --git a/source/blender/blenlib/intern/BLI_util.h b/source/blender/blenlib/intern/BLI_util.h
new file mode 100644
index 00000000000..b033c89a0c9
--- /dev/null
+++ b/source/blender/blenlib/intern/BLI_util.h
@@ -0,0 +1,45 @@
+/**
+ * blenlib/BLI_storage_types.h
+ *
+ * Some types for dealing with directories
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BLI_UTIL_H
+#define BLI_UTIL_H
+
+#define mallocstructN(x,y,name) (x*)MEM_mallocN((y)* sizeof(x),name)
+#define callocstructN(x,y,name) (x*)MEM_callocN((y)* sizeof(x),name)
+
+struct ListBase;
+
+#endif
+
diff --git a/source/blender/blenlib/intern/Makefile b/source/blender/blenlib/intern/Makefile
new file mode 100644
index 00000000000..68148a1eb37
--- /dev/null
+++ b/source/blender/blenlib/intern/Makefile
@@ -0,0 +1,61 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+#
+
+LIBNAME = blenlib
+DIR = $(OCGDIR)/blender/$(LIBNAME)
+
+include nan_compile.mk
+
+# CPPFLAGS += $(LEVEL_2_CPP_WARNINGS)
+
+# path to SDNA types
+CPPFLAGS += -I../../makesdna
+# path to our own external headerfiles
+CPPFLAGS += -I..
+# path to the guarded memory allocator
+CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
+# path to freetype font stuff
+CPPFLAGS += -I$(NAN_FREETYPE)/include
+CPPFLAGS += -I$(NAN_FREETYPE)/include/freetype2
+# path to blenkernel
+CPPFLAGS += -I$(SRCHOME)/blender/blenkernel
+CPPFLAGS += -I../../include/
+# path to zlib
+CPPFLAGS += -I$(NAN_ZLIB)/include
+
+ifdef NAN_PTHREADS
+ CPPFLAGS += -I$(NAN_PTHREADS)/include
+endif
+ifeq ($(WITH_FREETYPE2), true)
+ CPPFLAGS += -DWITH_FREETYPE2
+endif
diff --git a/source/blender/blenlib/intern/arithb.c b/source/blender/blenlib/intern/arithb.c
new file mode 100644
index 00000000000..721df3a1a0c
--- /dev/null
+++ b/source/blender/blenlib/intern/arithb.c
@@ -0,0 +1,3672 @@
+/* arithb.c
+ *
+ * simple math for blender code
+ *
+ * sort of cleaned up mar-01 nzc
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/* ************************ FUNKTIES **************************** */
+
+#include <math.h>
+#include <sys/types.h>
+#include <string.h>
+#include <float.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if defined(__sun__) || defined( __sun ) || defined (__sparc) || defined (__sparc__)
+#include <strings.h>
+#endif
+
+#if !defined(__sgi) && !defined(WIN32)
+#include <sys/time.h>
+#include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include "BLI_arithb.h"
+
+/* A few small defines. Keep'em local! */
+#define SMALL_NUMBER 1.e-8
+#define ABS(x) ((x) < 0 ? -(x) : (x))
+#define SWAP(type, a, b) { type sw_ap; sw_ap=(a); (a)=(b); (b)=sw_ap; }
+
+
+#if defined(WIN32) || defined(__APPLE__)
+#include <stdlib.h>
+#define M_PI 3.14159265358979323846
+#define M_SQRT2 1.41421356237309504880
+
+#endif /* defined(WIN32) || defined(__APPLE__) */
+
+
+float saacos(float fac)
+{
+ if(fac<= -1.0f) return (float)M_PI;
+ else if(fac>=1.0f) return 0.0;
+ else return (float)acos(fac);
+}
+
+float saasin(float fac)
+{
+ if(fac<= -1.0f) return (float)-M_PI/2.0f;
+ else if(fac>=1.0f) return (float)M_PI/2.0f;
+ else return (float)asin(fac);
+}
+
+float sasqrt(float fac)
+{
+ if(fac<=0.0) return 0.0;
+ return (float)sqrt(fac);
+}
+
+float Normalize(float *n)
+{
+ float d;
+
+ d= n[0]*n[0]+n[1]*n[1]+n[2]*n[2];
+ /* A larger value causes normalize errors in a scaled down models with camera xtreme close */
+ if(d>1.0e-35F) {
+ d= (float)sqrt(d);
+
+ n[0]/=d;
+ n[1]/=d;
+ n[2]/=d;
+ } else {
+ n[0]=n[1]=n[2]= 0.0;
+ d= 0.0;
+ }
+ return d;
+}
+
+void Crossf(float *c, float *a, float *b)
+{
+ c[0] = a[1] * b[2] - a[2] * b[1];
+ c[1] = a[2] * b[0] - a[0] * b[2];
+ c[2] = a[0] * b[1] - a[1] * b[0];
+}
+
+/* Inpf returns the dot product, also called the scalar product and inner product */
+float Inpf( float *v1, float *v2)
+{
+ return v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2];
+}
+
+/* Project v1 on v2 */
+void Projf(float *c, float *v1, float *v2)
+{
+ float mul;
+ mul = Inpf(v1, v2) / Inpf(v2, v2);
+
+ c[0] = mul * v2[0];
+ c[1] = mul * v2[1];
+ c[2] = mul * v2[2];
+}
+
+void Mat3Transp(float mat[][3])
+{
+ float t;
+
+ t = mat[0][1] ;
+ mat[0][1] = mat[1][0] ;
+ mat[1][0] = t;
+ t = mat[0][2] ;
+ mat[0][2] = mat[2][0] ;
+ mat[2][0] = t;
+ t = mat[1][2] ;
+ mat[1][2] = mat[2][1] ;
+ mat[2][1] = t;
+}
+
+void Mat4Transp(float mat[][4])
+{
+ float t;
+
+ t = mat[0][1] ;
+ mat[0][1] = mat[1][0] ;
+ mat[1][0] = t;
+ t = mat[0][2] ;
+ mat[0][2] = mat[2][0] ;
+ mat[2][0] = t;
+ t = mat[0][3] ;
+ mat[0][3] = mat[3][0] ;
+ mat[3][0] = t;
+
+ t = mat[1][2] ;
+ mat[1][2] = mat[2][1] ;
+ mat[2][1] = t;
+ t = mat[1][3] ;
+ mat[1][3] = mat[3][1] ;
+ mat[3][1] = t;
+
+ t = mat[2][3] ;
+ mat[2][3] = mat[3][2] ;
+ mat[3][2] = t;
+}
+
+
+/*
+ * invertmat -
+ * computes the inverse of mat and puts it in inverse. Returns
+ * TRUE on success (i.e. can always find a pivot) and FALSE on failure.
+ * Uses Gaussian Elimination with partial (maximal column) pivoting.
+ *
+ * Mark Segal - 1992
+ */
+
+int Mat4Invert(float inverse[][4], float mat[][4])
+{
+ int i, j, k;
+ double temp;
+ float tempmat[4][4];
+ float max;
+ int maxj;
+
+ /* Set inverse to identity */
+ for (i=0; i<4; i++)
+ for (j=0; j<4; j++)
+ inverse[i][j] = 0;
+ for (i=0; i<4; i++)
+ inverse[i][i] = 1;
+
+ /* Copy original matrix so we don't mess it up */
+ for(i = 0; i < 4; i++)
+ for(j = 0; j <4; j++)
+ tempmat[i][j] = mat[i][j];
+
+ for(i = 0; i < 4; i++) {
+ /* Look for row with max pivot */
+ max = ABS(tempmat[i][i]);
+ maxj = i;
+ for(j = i + 1; j < 4; j++) {
+ if(ABS(tempmat[j][i]) > max) {
+ max = ABS(tempmat[j][i]);
+ maxj = j;
+ }
+ }
+ /* Swap rows if necessary */
+ if (maxj != i) {
+ for( k = 0; k < 4; k++) {
+ SWAP(float, tempmat[i][k], tempmat[maxj][k]);
+ SWAP(float, inverse[i][k], inverse[maxj][k]);
+ }
+ }
+
+ temp = tempmat[i][i];
+ if (temp == 0)
+ return 0; /* No non-zero pivot */
+ for(k = 0; k < 4; k++) {
+ tempmat[i][k] = (float)(tempmat[i][k]/temp);
+ inverse[i][k] = (float)(inverse[i][k]/temp);
+ }
+ for(j = 0; j < 4; j++) {
+ if(j != i) {
+ temp = tempmat[j][i];
+ for(k = 0; k < 4; k++) {
+ tempmat[j][k] -= (float)(tempmat[i][k]*temp);
+ inverse[j][k] -= (float)(inverse[i][k]*temp);
+ }
+ }
+ }
+ }
+ return 1;
+}
+#ifdef TEST_ACTIVE
+void Mat4InvertSimp(float inverse[][4], float mat[][4])
+{
+ /* only for Matrices that have a rotation */
+ /* based at GG IV pag 205 */
+ float scale;
+
+ scale= mat[0][0]*mat[0][0] + mat[1][0]*mat[1][0] + mat[2][0]*mat[2][0];
+ if(scale==0.0) return;
+
+ scale= 1.0/scale;
+
+ /* transpose and scale */
+ inverse[0][0]= scale*mat[0][0];
+ inverse[1][0]= scale*mat[0][1];
+ inverse[2][0]= scale*mat[0][2];
+ inverse[0][1]= scale*mat[1][0];
+ inverse[1][1]= scale*mat[1][1];
+ inverse[2][1]= scale*mat[1][2];
+ inverse[0][2]= scale*mat[2][0];
+ inverse[1][2]= scale*mat[2][1];
+ inverse[2][2]= scale*mat[2][2];
+
+ inverse[3][0]= -(inverse[0][0]*mat[3][0] + inverse[1][0]*mat[3][1] + inverse[2][0]*mat[3][2]);
+ inverse[3][1]= -(inverse[0][1]*mat[3][0] + inverse[1][1]*mat[3][1] + inverse[2][1]*mat[3][2]);
+ inverse[3][2]= -(inverse[0][2]*mat[3][0] + inverse[1][2]*mat[3][1] + inverse[2][2]*mat[3][2]);
+
+ inverse[0][3]= inverse[1][3]= inverse[2][3]= 0.0;
+ inverse[3][3]= 1.0;
+}
+#endif
+/* struct Matrix4; */
+
+#ifdef TEST_ACTIVE
+/* this seems to be unused.. */
+
+void Mat4Inv(float *m1, float *m2)
+{
+
+/* This gets me into trouble: */
+ float mat1[3][3], mat2[3][3];
+
+/* void Mat3Inv(); */
+/* void Mat3CpyMat4(); */
+/* void Mat4CpyMat3(); */
+
+ Mat3CpyMat4((float*)mat2,m2);
+ Mat3Inv((float*)mat1, (float*) mat2);
+ Mat4CpyMat3(m1, mat1);
+
+}
+#endif
+
+
+float Det2x2(float a,float b,float c,float d)
+{
+
+ return a*d - b*c;
+}
+
+
+
+float Det3x3(float a1, float a2, float a3,
+ float b1, float b2, float b3,
+ float c1, float c2, float c3 )
+{
+ float ans;
+
+ ans = a1 * Det2x2( b2, b3, c2, c3 )
+ - b1 * Det2x2( a2, a3, c2, c3 )
+ + c1 * Det2x2( a2, a3, b2, b3 );
+
+ return ans;
+}
+
+float Det4x4(float m[][4])
+{
+ float ans;
+ float a1,a2,a3,a4,b1,b2,b3,b4,c1,c2,c3,c4,d1,d2,d3,d4;
+
+ a1= m[0][0];
+ b1= m[0][1];
+ c1= m[0][2];
+ d1= m[0][3];
+
+ a2= m[1][0];
+ b2= m[1][1];
+ c2= m[1][2];
+ d2= m[1][3];
+
+ a3= m[2][0];
+ b3= m[2][1];
+ c3= m[2][2];
+ d3= m[2][3];
+
+ a4= m[3][0];
+ b4= m[3][1];
+ c4= m[3][2];
+ d4= m[3][3];
+
+ ans = a1 * Det3x3( b2, b3, b4, c2, c3, c4, d2, d3, d4)
+ - b1 * Det3x3( a2, a3, a4, c2, c3, c4, d2, d3, d4)
+ + c1 * Det3x3( a2, a3, a4, b2, b3, b4, d2, d3, d4)
+ - d1 * Det3x3( a2, a3, a4, b2, b3, b4, c2, c3, c4);
+
+ return ans;
+}
+
+
+void Mat4Adj(float out[][4], float in[][4]) /* out = ADJ(in) */
+{
+ float a1, a2, a3, a4, b1, b2, b3, b4;
+ float c1, c2, c3, c4, d1, d2, d3, d4;
+
+ a1= in[0][0];
+ b1= in[0][1];
+ c1= in[0][2];
+ d1= in[0][3];
+
+ a2= in[1][0];
+ b2= in[1][1];
+ c2= in[1][2];
+ d2= in[1][3];
+
+ a3= in[2][0];
+ b3= in[2][1];
+ c3= in[2][2];
+ d3= in[2][3];
+
+ a4= in[3][0];
+ b4= in[3][1];
+ c4= in[3][2];
+ d4= in[3][3];
+
+
+ out[0][0] = Det3x3( b2, b3, b4, c2, c3, c4, d2, d3, d4);
+ out[1][0] = - Det3x3( a2, a3, a4, c2, c3, c4, d2, d3, d4);
+ out[2][0] = Det3x3( a2, a3, a4, b2, b3, b4, d2, d3, d4);
+ out[3][0] = - Det3x3( a2, a3, a4, b2, b3, b4, c2, c3, c4);
+
+ out[0][1] = - Det3x3( b1, b3, b4, c1, c3, c4, d1, d3, d4);
+ out[1][1] = Det3x3( a1, a3, a4, c1, c3, c4, d1, d3, d4);
+ out[2][1] = - Det3x3( a1, a3, a4, b1, b3, b4, d1, d3, d4);
+ out[3][1] = Det3x3( a1, a3, a4, b1, b3, b4, c1, c3, c4);
+
+ out[0][2] = Det3x3( b1, b2, b4, c1, c2, c4, d1, d2, d4);
+ out[1][2] = - Det3x3( a1, a2, a4, c1, c2, c4, d1, d2, d4);
+ out[2][2] = Det3x3( a1, a2, a4, b1, b2, b4, d1, d2, d4);
+ out[3][2] = - Det3x3( a1, a2, a4, b1, b2, b4, c1, c2, c4);
+
+ out[0][3] = - Det3x3( b1, b2, b3, c1, c2, c3, d1, d2, d3);
+ out[1][3] = Det3x3( a1, a2, a3, c1, c2, c3, d1, d2, d3);
+ out[2][3] = - Det3x3( a1, a2, a3, b1, b2, b3, d1, d2, d3);
+ out[3][3] = Det3x3( a1, a2, a3, b1, b2, b3, c1, c2, c3);
+}
+
+void Mat4InvGG(float out[][4], float in[][4]) /* from Graphic Gems I, out= INV(in) */
+{
+ int i, j;
+ float det;
+
+ /* calculate the adjoint matrix */
+
+ Mat4Adj(out,in);
+
+ det = Det4x4(out);
+
+ if ( fabs( det ) < SMALL_NUMBER) {
+ return;
+ }
+
+ /* scale the adjoint matrix to get the inverse */
+
+ for (i=0; i<4; i++)
+ for(j=0; j<4; j++)
+ out[i][j] = out[i][j] / det;
+
+ /* the last factor is not always 1. For that reason an extra division should be implemented? */
+}
+
+
+void Mat3Inv(float m1[][3], float m2[][3])
+{
+ short a,b;
+ float det;
+
+ /* calc adjoint */
+ Mat3Adj(m1,m2);
+
+ /* then determinant old matrix! */
+ det= m2[0][0]* (m2[1][1]*m2[2][2] - m2[1][2]*m2[2][1])
+ -m2[1][0]* (m2[0][1]*m2[2][2] - m2[0][2]*m2[2][1])
+ +m2[2][0]* (m2[0][1]*m2[1][2] - m2[0][2]*m2[1][1]);
+
+ if(det==0) det=1;
+ det= 1/det;
+ for(a=0;a<3;a++) {
+ for(b=0;b<3;b++) {
+ m1[a][b]*=det;
+ }
+ }
+}
+
+void Mat3Adj(float m1[][3], float m[][3])
+{
+ m1[0][0]=m[1][1]*m[2][2]-m[1][2]*m[2][1];
+ m1[0][1]= -m[0][1]*m[2][2]+m[0][2]*m[2][1];
+ m1[0][2]=m[0][1]*m[1][2]-m[0][2]*m[1][1];
+
+ m1[1][0]= -m[1][0]*m[2][2]+m[1][2]*m[2][0];
+ m1[1][1]=m[0][0]*m[2][2]-m[0][2]*m[2][0];
+ m1[1][2]= -m[0][0]*m[1][2]+m[0][2]*m[1][0];
+
+ m1[2][0]=m[1][0]*m[2][1]-m[1][1]*m[2][0];
+ m1[2][1]= -m[0][0]*m[2][1]+m[0][1]*m[2][0];
+ m1[2][2]=m[0][0]*m[1][1]-m[0][1]*m[1][0];
+}
+
+void Mat4MulMat4(float m1[][4], float m2[][4], float m3[][4])
+{
+ /* matrix product: m1[j][k] = m2[j][i].m3[i][k] */
+
+ m1[0][0] = m2[0][0]*m3[0][0] + m2[0][1]*m3[1][0] + m2[0][2]*m3[2][0] + m2[0][3]*m3[3][0];
+ m1[0][1] = m2[0][0]*m3[0][1] + m2[0][1]*m3[1][1] + m2[0][2]*m3[2][1] + m2[0][3]*m3[3][1];
+ m1[0][2] = m2[0][0]*m3[0][2] + m2[0][1]*m3[1][2] + m2[0][2]*m3[2][2] + m2[0][3]*m3[3][2];
+ m1[0][3] = m2[0][0]*m3[0][3] + m2[0][1]*m3[1][3] + m2[0][2]*m3[2][3] + m2[0][3]*m3[3][3];
+
+ m1[1][0] = m2[1][0]*m3[0][0] + m2[1][1]*m3[1][0] + m2[1][2]*m3[2][0] + m2[1][3]*m3[3][0];
+ m1[1][1] = m2[1][0]*m3[0][1] + m2[1][1]*m3[1][1] + m2[1][2]*m3[2][1] + m2[1][3]*m3[3][1];
+ m1[1][2] = m2[1][0]*m3[0][2] + m2[1][1]*m3[1][2] + m2[1][2]*m3[2][2] + m2[1][3]*m3[3][2];
+ m1[1][3] = m2[1][0]*m3[0][3] + m2[1][1]*m3[1][3] + m2[1][2]*m3[2][3] + m2[1][3]*m3[3][3];
+
+ m1[2][0] = m2[2][0]*m3[0][0] + m2[2][1]*m3[1][0] + m2[2][2]*m3[2][0] + m2[2][3]*m3[3][0];
+ m1[2][1] = m2[2][0]*m3[0][1] + m2[2][1]*m3[1][1] + m2[2][2]*m3[2][1] + m2[2][3]*m3[3][1];
+ m1[2][2] = m2[2][0]*m3[0][2] + m2[2][1]*m3[1][2] + m2[2][2]*m3[2][2] + m2[2][3]*m3[3][2];
+ m1[2][3] = m2[2][0]*m3[0][3] + m2[2][1]*m3[1][3] + m2[2][2]*m3[2][3] + m2[2][3]*m3[3][3];
+
+ m1[3][0] = m2[3][0]*m3[0][0] + m2[3][1]*m3[1][0] + m2[3][2]*m3[2][0] + m2[3][3]*m3[3][0];
+ m1[3][1] = m2[3][0]*m3[0][1] + m2[3][1]*m3[1][1] + m2[3][2]*m3[2][1] + m2[3][3]*m3[3][1];
+ m1[3][2] = m2[3][0]*m3[0][2] + m2[3][1]*m3[1][2] + m2[3][2]*m3[2][2] + m2[3][3]*m3[3][2];
+ m1[3][3] = m2[3][0]*m3[0][3] + m2[3][1]*m3[1][3] + m2[3][2]*m3[2][3] + m2[3][3]*m3[3][3];
+
+}
+#ifdef TEST_ACTIVE
+void subMat4MulMat4(float *m1, float *m2, float *m3)
+{
+
+ m1[0]= m2[0]*m3[0] + m2[1]*m3[4] + m2[2]*m3[8];
+ m1[1]= m2[0]*m3[1] + m2[1]*m3[5] + m2[2]*m3[9];
+ m1[2]= m2[0]*m3[2] + m2[1]*m3[6] + m2[2]*m3[10];
+ m1[3]= m2[0]*m3[3] + m2[1]*m3[7] + m2[2]*m3[11] + m2[3];
+ m1+=4;
+ m2+=4;
+ m1[0]= m2[0]*m3[0] + m2[1]*m3[4] + m2[2]*m3[8];
+ m1[1]= m2[0]*m3[1] + m2[1]*m3[5] + m2[2]*m3[9];
+ m1[2]= m2[0]*m3[2] + m2[1]*m3[6] + m2[2]*m3[10];
+ m1[3]= m2[0]*m3[3] + m2[1]*m3[7] + m2[2]*m3[11] + m2[3];
+ m1+=4;
+ m2+=4;
+ m1[0]= m2[0]*m3[0] + m2[1]*m3[4] + m2[2]*m3[8];
+ m1[1]= m2[0]*m3[1] + m2[1]*m3[5] + m2[2]*m3[9];
+ m1[2]= m2[0]*m3[2] + m2[1]*m3[6] + m2[2]*m3[10];
+ m1[3]= m2[0]*m3[3] + m2[1]*m3[7] + m2[2]*m3[11] + m2[3];
+}
+#endif
+
+#ifndef TEST_ACTIVE
+void Mat3MulMat3(float m1[][3], float m3[][3], float m2[][3])
+#else
+void Mat3MulMat3(float *m1, float *m3, float *m2)
+#endif
+{
+ /* m1[i][j] = m2[i][k]*m3[k][j], args are flipped! */
+#ifndef TEST_ACTIVE
+ m1[0][0]= m2[0][0]*m3[0][0] + m2[0][1]*m3[1][0] + m2[0][2]*m3[2][0];
+ m1[0][1]= m2[0][0]*m3[0][1] + m2[0][1]*m3[1][1] + m2[0][2]*m3[2][1];
+ m1[0][2]= m2[0][0]*m3[0][2] + m2[0][1]*m3[1][2] + m2[0][2]*m3[2][2];
+
+ m1[1][0]= m2[1][0]*m3[0][0] + m2[1][1]*m3[1][0] + m2[1][2]*m3[2][0];
+ m1[1][1]= m2[1][0]*m3[0][1] + m2[1][1]*m3[1][1] + m2[1][2]*m3[2][1];
+ m1[1][2]= m2[1][0]*m3[0][2] + m2[1][1]*m3[1][2] + m2[1][2]*m3[2][2];
+
+ m1[2][0]= m2[2][0]*m3[0][0] + m2[2][1]*m3[1][0] + m2[2][2]*m3[2][0];
+ m1[2][1]= m2[2][0]*m3[0][1] + m2[2][1]*m3[1][1] + m2[2][2]*m3[2][1];
+ m1[2][2]= m2[2][0]*m3[0][2] + m2[2][1]*m3[1][2] + m2[2][2]*m3[2][2];
+#else
+ m1[0]= m2[0]*m3[0] + m2[1]*m3[3] + m2[2]*m3[6];
+ m1[1]= m2[0]*m3[1] + m2[1]*m3[4] + m2[2]*m3[7];
+ m1[2]= m2[0]*m3[2] + m2[1]*m3[5] + m2[2]*m3[8];
+ m1+=3;
+ m2+=3;
+ m1[0]= m2[0]*m3[0] + m2[1]*m3[3] + m2[2]*m3[6];
+ m1[1]= m2[0]*m3[1] + m2[1]*m3[4] + m2[2]*m3[7];
+ m1[2]= m2[0]*m3[2] + m2[1]*m3[5] + m2[2]*m3[8];
+ m1+=3;
+ m2+=3;
+ m1[0]= m2[0]*m3[0] + m2[1]*m3[3] + m2[2]*m3[6];
+ m1[1]= m2[0]*m3[1] + m2[1]*m3[4] + m2[2]*m3[7];
+ m1[2]= m2[0]*m3[2] + m2[1]*m3[5] + m2[2]*m3[8];
+#endif
+} /* end of void Mat3MulMat3(float m1[][3], float m3[][3], float m2[][3]) */
+
+void Mat4MulMat43(float (*m1)[4], float (*m3)[4], float (*m2)[3])
+{
+ m1[0][0]= m2[0][0]*m3[0][0] + m2[0][1]*m3[1][0] + m2[0][2]*m3[2][0];
+ m1[0][1]= m2[0][0]*m3[0][1] + m2[0][1]*m3[1][1] + m2[0][2]*m3[2][1];
+ m1[0][2]= m2[0][0]*m3[0][2] + m2[0][1]*m3[1][2] + m2[0][2]*m3[2][2];
+ m1[1][0]= m2[1][0]*m3[0][0] + m2[1][1]*m3[1][0] + m2[1][2]*m3[2][0];
+ m1[1][1]= m2[1][0]*m3[0][1] + m2[1][1]*m3[1][1] + m2[1][2]*m3[2][1];
+ m1[1][2]= m2[1][0]*m3[0][2] + m2[1][1]*m3[1][2] + m2[1][2]*m3[2][2];
+ m1[2][0]= m2[2][0]*m3[0][0] + m2[2][1]*m3[1][0] + m2[2][2]*m3[2][0];
+ m1[2][1]= m2[2][0]*m3[0][1] + m2[2][1]*m3[1][1] + m2[2][2]*m3[2][1];
+ m1[2][2]= m2[2][0]*m3[0][2] + m2[2][1]*m3[1][2] + m2[2][2]*m3[2][2];
+}
+/* m1 = m2 * m3, ignore the elements on the 4th row/column of m3*/
+void Mat3IsMat3MulMat4(float m1[][3], float m2[][3], float m3[][4])
+{
+ /* m1[i][j] = m2[i][k] * m3[k][j] */
+ m1[0][0] = m2[0][0] * m3[0][0] + m2[0][1] * m3[1][0] +m2[0][2] * m3[2][0];
+ m1[0][1] = m2[0][0] * m3[0][1] + m2[0][1] * m3[1][1] +m2[0][2] * m3[2][1];
+ m1[0][2] = m2[0][0] * m3[0][2] + m2[0][1] * m3[1][2] +m2[0][2] * m3[2][2];
+
+ m1[1][0] = m2[1][0] * m3[0][0] + m2[1][1] * m3[1][0] +m2[1][2] * m3[2][0];
+ m1[1][1] = m2[1][0] * m3[0][1] + m2[1][1] * m3[1][1] +m2[1][2] * m3[2][1];
+ m1[1][2] = m2[1][0] * m3[0][2] + m2[1][1] * m3[1][2] +m2[1][2] * m3[2][2];
+
+ m1[2][0] = m2[2][0] * m3[0][0] + m2[2][1] * m3[1][0] +m2[2][2] * m3[2][0];
+ m1[2][1] = m2[2][0] * m3[0][1] + m2[2][1] * m3[1][1] +m2[2][2] * m3[2][1];
+ m1[2][2] = m2[2][0] * m3[0][2] + m2[2][1] * m3[1][2] +m2[2][2] * m3[2][2];
+}
+
+
+
+void Mat4MulMat34(float (*m1)[4], float (*m3)[3], float (*m2)[4])
+{
+ m1[0][0]= m2[0][0]*m3[0][0] + m2[0][1]*m3[1][0] + m2[0][2]*m3[2][0];
+ m1[0][1]= m2[0][0]*m3[0][1] + m2[0][1]*m3[1][1] + m2[0][2]*m3[2][1];
+ m1[0][2]= m2[0][0]*m3[0][2] + m2[0][1]*m3[1][2] + m2[0][2]*m3[2][2];
+ m1[1][0]= m2[1][0]*m3[0][0] + m2[1][1]*m3[1][0] + m2[1][2]*m3[2][0];
+ m1[1][1]= m2[1][0]*m3[0][1] + m2[1][1]*m3[1][1] + m2[1][2]*m3[2][1];
+ m1[1][2]= m2[1][0]*m3[0][2] + m2[1][1]*m3[1][2] + m2[1][2]*m3[2][2];
+ m1[2][0]= m2[2][0]*m3[0][0] + m2[2][1]*m3[1][0] + m2[2][2]*m3[2][0];
+ m1[2][1]= m2[2][0]*m3[0][1] + m2[2][1]*m3[1][1] + m2[2][2]*m3[2][1];
+ m1[2][2]= m2[2][0]*m3[0][2] + m2[2][1]*m3[1][2] + m2[2][2]*m3[2][2];
+}
+
+void Mat4CpyMat4(float m1[][4], float m2[][4])
+{
+ memcpy(m1, m2, 4*4*sizeof(float));
+}
+
+void Mat4SwapMat4(float *m1, float *m2)
+{
+ float t;
+ int i;
+
+ for(i=0;i<16;i++) {
+ t= *m1;
+ *m1= *m2;
+ *m2= t;
+ m1++;
+ m2++;
+ }
+}
+
+typedef float Mat3Row[3];
+typedef float Mat4Row[4];
+
+#ifdef TEST_ACTIVE
+void Mat3CpyMat4(float *m1p, float *m2p)
+#else
+void Mat3CpyMat4(float m1[][3], float m2[][4])
+#endif
+{
+#ifdef TEST_ACTIVE
+ int i, j;
+ Mat3Row *m1= (Mat3Row *)m1p;
+ Mat4Row *m2= (Mat4Row *)m2p;
+ for ( i = 0; i++; i < 3) {
+ for (j = 0; j++; j < 3) {
+ m1p[3*i + j] = m2p[4*i + j];
+ }
+ }
+#endif
+ m1[0][0]= m2[0][0];
+ m1[0][1]= m2[0][1];
+ m1[0][2]= m2[0][2];
+
+ m1[1][0]= m2[1][0];
+ m1[1][1]= m2[1][1];
+ m1[1][2]= m2[1][2];
+
+ m1[2][0]= m2[2][0];
+ m1[2][1]= m2[2][1];
+ m1[2][2]= m2[2][2];
+}
+
+/* Butched. See .h for comment */
+/* void Mat4CpyMat3(float m1[][4], float m2[][3]) */
+#ifdef TEST_ACTIVE
+void Mat4CpyMat3(float* m1, float *m2)
+{
+ int i;
+ for (i = 0; i < 3; i++) {
+ m1[(4*i)] = m2[(3*i)];
+ m1[(4*i) + 1]= m2[(3*i) + 1];
+ m1[(4*i) + 2]= m2[(3*i) + 2];
+ m1[(4*i) + 3]= 0.0;
+ i++;
+ }
+
+ m1[12]=m1[13]= m1[14]= 0.0;
+ m1[15]= 1.0;
+}
+#else
+
+void Mat4CpyMat3(float m1[][4], float m2[][3]) /* no clear */
+{
+ m1[0][0]= m2[0][0];
+ m1[0][1]= m2[0][1];
+ m1[0][2]= m2[0][2];
+
+ m1[1][0]= m2[1][0];
+ m1[1][1]= m2[1][1];
+ m1[1][2]= m2[1][2];
+
+ m1[2][0]= m2[2][0];
+ m1[2][1]= m2[2][1];
+ m1[2][2]= m2[2][2];
+
+ /* Reevan's Bugfix */
+ m1[0][3]=0.0F;
+ m1[1][3]=0.0F;
+ m1[2][3]=0.0F;
+
+ m1[3][0]=0.0F;
+ m1[3][1]=0.0F;
+ m1[3][2]=0.0F;
+ m1[3][3]=1.0F;
+
+
+}
+#endif
+
+void Mat3CpyMat3(float m1[][3], float m2[][3])
+{
+ /* destination comes first: */
+ memcpy(&m1[0], &m2[0], 9*sizeof(float));
+}
+
+void Mat3MulSerie(float answ[][3],
+ float m1[][3], float m2[][3], float m3[][3],
+ float m4[][3], float m5[][3], float m6[][3],
+ float m7[][3], float m8[][3])
+{
+ float temp[3][3];
+
+ if(m1==0 || m2==0) return;
+
+
+ Mat3MulMat3(answ, m2, m1);
+ if(m3) {
+ Mat3MulMat3(temp, m3, answ);
+ if(m4) {
+ Mat3MulMat3(answ, m4, temp);
+ if(m5) {
+ Mat3MulMat3(temp, m5, answ);
+ if(m6) {
+ Mat3MulMat3(answ, m6, temp);
+ if(m7) {
+ Mat3MulMat3(temp, m7, answ);
+ if(m8) {
+ Mat3MulMat3(answ, m8, temp);
+ }
+ else Mat3CpyMat3(answ, temp);
+ }
+ }
+ else Mat3CpyMat3(answ, temp);
+ }
+ }
+ else Mat3CpyMat3(answ, temp);
+ }
+}
+
+void Mat4MulSerie(float answ[][4], float m1[][4],
+ float m2[][4], float m3[][4], float m4[][4],
+ float m5[][4], float m6[][4], float m7[][4],
+ float m8[][4])
+{
+ float temp[4][4];
+
+ if(m1==0 || m2==0) return;
+
+ Mat4MulMat4(answ, m2, m1);
+ if(m3) {
+ Mat4MulMat4(temp, m3, answ);
+ if(m4) {
+ Mat4MulMat4(answ, m4, temp);
+ if(m5) {
+ Mat4MulMat4(temp, m5, answ);
+ if(m6) {
+ Mat4MulMat4(answ, m6, temp);
+ if(m7) {
+ Mat4MulMat4(temp, m7, answ);
+ if(m8) {
+ Mat4MulMat4(answ, m8, temp);
+ }
+ else Mat4CpyMat4(answ, temp);
+ }
+ }
+ else Mat4CpyMat4(answ, temp);
+ }
+ }
+ else Mat4CpyMat4(answ, temp);
+ }
+}
+
+void Mat4BlendMat4(float out[][4], float dst[][4], float src[][4], float srcweight)
+{
+ float squat[4], dquat[4], fquat[4];
+ float ssize[3], dsize[3], fsize[4];
+ float sloc[3], dloc[3], floc[3];
+
+ Mat4ToQuat(dst, dquat);
+ Mat4ToSize(dst, dsize);
+ VecCopyf(dloc, dst[3]);
+
+ Mat4ToQuat(src, squat);
+ Mat4ToSize(src, ssize);
+ VecCopyf(sloc, src[3]);
+
+ /* do blending */
+ VecLerpf(floc, dloc, sloc, srcweight);
+ QuatInterpol(fquat, dquat, squat, srcweight);
+ VecLerpf(fsize, dsize, ssize, srcweight);
+
+ /* compose new matrix */
+ LocQuatSizeToMat4(out, floc, fquat, fsize);
+}
+
+void Mat4Clr(float *m)
+{
+ memset(m, 0, 4*4*sizeof(float));
+}
+
+void Mat3Clr(float *m)
+{
+ memset(m, 0, 3*3*sizeof(float));
+}
+
+void Mat4One(float m[][4])
+{
+
+ m[0][0]= m[1][1]= m[2][2]= m[3][3]= 1.0;
+ m[0][1]= m[0][2]= m[0][3]= 0.0;
+ m[1][0]= m[1][2]= m[1][3]= 0.0;
+ m[2][0]= m[2][1]= m[2][3]= 0.0;
+ m[3][0]= m[3][1]= m[3][2]= 0.0;
+}
+
+void Mat3One(float m[][3])
+{
+
+ m[0][0]= m[1][1]= m[2][2]= 1.0;
+ m[0][1]= m[0][2]= 0.0;
+ m[1][0]= m[1][2]= 0.0;
+ m[2][0]= m[2][1]= 0.0;
+}
+
+void Mat4MulVec( float mat[][4], int *vec)
+{
+ int x,y;
+
+ x=vec[0];
+ y=vec[1];
+ vec[0]=(int)(x*mat[0][0] + y*mat[1][0] + mat[2][0]*vec[2] + mat[3][0]);
+ vec[1]=(int)(x*mat[0][1] + y*mat[1][1] + mat[2][1]*vec[2] + mat[3][1]);
+ vec[2]=(int)(x*mat[0][2] + y*mat[1][2] + mat[2][2]*vec[2] + mat[3][2]);
+}
+
+void Mat4MulVecfl( float mat[][4], float *vec)
+{
+ float x,y;
+
+ x=vec[0];
+ y=vec[1];
+ vec[0]=x*mat[0][0] + y*mat[1][0] + mat[2][0]*vec[2] + mat[3][0];
+ vec[1]=x*mat[0][1] + y*mat[1][1] + mat[2][1]*vec[2] + mat[3][1];
+ vec[2]=x*mat[0][2] + y*mat[1][2] + mat[2][2]*vec[2] + mat[3][2];
+}
+
+void VecMat4MulVecfl(float *in, float mat[][4], float *vec)
+{
+ float x,y;
+
+ x=vec[0];
+ y=vec[1];
+ in[0]= x*mat[0][0] + y*mat[1][0] + mat[2][0]*vec[2] + mat[3][0];
+ in[1]= x*mat[0][1] + y*mat[1][1] + mat[2][1]*vec[2] + mat[3][1];
+ in[2]= x*mat[0][2] + y*mat[1][2] + mat[2][2]*vec[2] + mat[3][2];
+}
+
+void Mat4Mul3Vecfl( float mat[][4], float *vec)
+{
+ float x,y;
+
+ x= vec[0];
+ y= vec[1];
+ vec[0]= x*mat[0][0] + y*mat[1][0] + mat[2][0]*vec[2];
+ vec[1]= x*mat[0][1] + y*mat[1][1] + mat[2][1]*vec[2];
+ vec[2]= x*mat[0][2] + y*mat[1][2] + mat[2][2]*vec[2];
+}
+
+void Mat4MulVec3Project(float mat[][4], float *vec)
+{
+ float w;
+
+ w = vec[0]*mat[0][3] + vec[1]*mat[1][3] + vec[2]*mat[2][3] + mat[3][3];
+ Mat4MulVecfl(mat, vec);
+
+ vec[0] /= w;
+ vec[1] /= w;
+ vec[2] /= w;
+}
+
+void Mat4MulVec4fl( float mat[][4], float *vec)
+{
+ float x,y,z;
+
+ x=vec[0];
+ y=vec[1];
+ z= vec[2];
+ vec[0]=x*mat[0][0] + y*mat[1][0] + z*mat[2][0] + mat[3][0]*vec[3];
+ vec[1]=x*mat[0][1] + y*mat[1][1] + z*mat[2][1] + mat[3][1]*vec[3];
+ vec[2]=x*mat[0][2] + y*mat[1][2] + z*mat[2][2] + mat[3][2]*vec[3];
+ vec[3]=x*mat[0][3] + y*mat[1][3] + z*mat[2][3] + mat[3][3]*vec[3];
+}
+
+void Mat3MulVec( float mat[][3], int *vec)
+{
+ int x,y;
+
+ x=vec[0];
+ y=vec[1];
+ vec[0]= (int)(x*mat[0][0] + y*mat[1][0] + mat[2][0]*vec[2]);
+ vec[1]= (int)(x*mat[0][1] + y*mat[1][1] + mat[2][1]*vec[2]);
+ vec[2]= (int)(x*mat[0][2] + y*mat[1][2] + mat[2][2]*vec[2]);
+}
+
+void Mat3MulVecfl( float mat[][3], float *vec)
+{
+ float x,y;
+
+ x=vec[0];
+ y=vec[1];
+ vec[0]= x*mat[0][0] + y*mat[1][0] + mat[2][0]*vec[2];
+ vec[1]= x*mat[0][1] + y*mat[1][1] + mat[2][1]*vec[2];
+ vec[2]= x*mat[0][2] + y*mat[1][2] + mat[2][2]*vec[2];
+}
+
+void Mat3MulVecd( float mat[][3], double *vec)
+{
+ double x,y;
+
+ x=vec[0];
+ y=vec[1];
+ vec[0]= x*mat[0][0] + y*mat[1][0] + mat[2][0]*vec[2];
+ vec[1]= x*mat[0][1] + y*mat[1][1] + mat[2][1]*vec[2];
+ vec[2]= x*mat[0][2] + y*mat[1][2] + mat[2][2]*vec[2];
+}
+
+void Mat3TransMulVecfl( float mat[][3], float *vec)
+{
+ float x,y;
+
+ x=vec[0];
+ y=vec[1];
+ vec[0]= x*mat[0][0] + y*mat[0][1] + mat[0][2]*vec[2];
+ vec[1]= x*mat[1][0] + y*mat[1][1] + mat[1][2]*vec[2];
+ vec[2]= x*mat[2][0] + y*mat[2][1] + mat[2][2]*vec[2];
+}
+
+void Mat3MulFloat(float *m, float f)
+{
+ int i;
+
+ for(i=0;i<9;i++) m[i]*=f;
+}
+
+void Mat4MulFloat(float *m, float f)
+{
+ int i;
+
+ for(i=0;i<16;i++) m[i]*=f; /* count to 12: without vector component */
+}
+
+
+void Mat4MulFloat3(float *m, float f) /* only scale component */
+{
+ int i,j;
+
+ for(i=0; i<3; i++) {
+ for(j=0; j<3; j++) {
+
+ m[4*i+j] *= f;
+ }
+ }
+}
+
+void Mat3AddMat3(float m1[][3], float m2[][3], float m3[][3])
+{
+ int i, j;
+
+ for(i=0;i<3;i++)
+ for(j=0;j<3;j++)
+ m1[i][j]= m2[i][j] + m3[i][j];
+}
+
+void Mat4AddMat4(float m1[][4], float m2[][4], float m3[][4])
+{
+ int i, j;
+
+ for(i=0;i<4;i++)
+ for(j=0;j<4;j++)
+ m1[i][j]= m2[i][j] + m3[i][j];
+}
+
+void VecStar(float mat[][3], float *vec)
+{
+
+ mat[0][0]= mat[1][1]= mat[2][2]= 0.0;
+ mat[0][1]= -vec[2];
+ mat[0][2]= vec[1];
+ mat[1][0]= vec[2];
+ mat[1][2]= -vec[0];
+ mat[2][0]= -vec[1];
+ mat[2][1]= vec[0];
+
+}
+#ifdef TEST_ACTIVE
+short EenheidsMat(float mat[][3])
+{
+
+ if(mat[0][0]==1.0 && mat[0][1]==0.0 && mat[0][2]==0.0)
+ if(mat[1][0]==0.0 && mat[1][1]==1.0 && mat[1][2]==0.0)
+ if(mat[2][0]==0.0 && mat[2][1]==0.0 && mat[2][2]==1.0)
+ return 1;
+ return 0;
+}
+#endif
+
+int FloatCompare( float *v1, float *v2, float limit)
+{
+
+ if( fabs(v1[0]-v2[0])<limit ) {
+ if( fabs(v1[1]-v2[1])<limit ) {
+ if( fabs(v1[2]-v2[2])<limit ) return 1;
+ }
+ }
+ return 0;
+}
+
+float FloatLerpf( float target, float origin, float fac)
+{
+ return (fac*target) + (1.0f-fac)*origin;
+}
+
+void printvecf( char *str, float v[3])
+{
+ printf("%s: %.3f %.3f %.3f\n", str, v[0], v[1], v[2]);
+
+}
+
+void printquat( char *str, float q[4])
+{
+ printf("%s: %.3f %.3f %.3f %.3f\n", str, q[0], q[1], q[2], q[3]);
+
+}
+
+void printvec4f( char *str, float v[4])
+{
+ printf("%s\n", str);
+ printf("%f %f %f %f\n",v[0],v[1],v[2], v[3]);
+ printf("\n");
+
+}
+
+void printmatrix4( char *str, float m[][4])
+{
+ printf("%s\n", str);
+ printf("%f %f %f %f\n",m[0][0],m[1][0],m[2][0],m[3][0]);
+ printf("%f %f %f %f\n",m[0][1],m[1][1],m[2][1],m[3][1]);
+ printf("%f %f %f %f\n",m[0][2],m[1][2],m[2][2],m[3][2]);
+ printf("%f %f %f %f\n",m[0][3],m[1][3],m[2][3],m[3][3]);
+ printf("\n");
+
+}
+
+void printmatrix3( char *str, float m[][3])
+{
+ printf("%s\n", str);
+ printf("%f %f %f\n",m[0][0],m[1][0],m[2][0]);
+ printf("%f %f %f\n",m[0][1],m[1][1],m[2][1]);
+ printf("%f %f %f\n",m[0][2],m[1][2],m[2][2]);
+ printf("\n");
+
+}
+
+/* **************** QUATERNIONS ********** */
+
+
+void QuatMul(float *q, float *q1, float *q2)
+{
+ float t0,t1,t2;
+
+ t0= q1[0]*q2[0]-q1[1]*q2[1]-q1[2]*q2[2]-q1[3]*q2[3];
+ t1= q1[0]*q2[1]+q1[1]*q2[0]+q1[2]*q2[3]-q1[3]*q2[2];
+ t2= q1[0]*q2[2]+q1[2]*q2[0]+q1[3]*q2[1]-q1[1]*q2[3];
+ q[3]= q1[0]*q2[3]+q1[3]*q2[0]+q1[1]*q2[2]-q1[2]*q2[1];
+ q[0]=t0;
+ q[1]=t1;
+ q[2]=t2;
+}
+
+/* Assumes a unit quaternion */
+void QuatMulVecf(float *q, float *v)
+{
+ float t0, t1, t2;
+
+ t0= -q[1]*v[0]-q[2]*v[1]-q[3]*v[2];
+ t1= q[0]*v[0]+q[2]*v[2]-q[3]*v[1];
+ t2= q[0]*v[1]+q[3]*v[0]-q[1]*v[2];
+ v[2]= q[0]*v[2]+q[1]*v[1]-q[2]*v[0];
+ v[0]=t1;
+ v[1]=t2;
+
+ t1= t0*-q[1]+v[0]*q[0]-v[1]*q[3]+v[2]*q[2];
+ t2= t0*-q[2]+v[1]*q[0]-v[2]*q[1]+v[0]*q[3];
+ v[2]= t0*-q[3]+v[2]*q[0]-v[0]*q[2]+v[1]*q[1];
+ v[0]=t1;
+ v[1]=t2;
+}
+
+void QuatConj(float *q)
+{
+ q[1] = -q[1];
+ q[2] = -q[2];
+ q[3] = -q[3];
+}
+
+float QuatDot(float *q1, float *q2)
+{
+ return q1[0]*q2[0] + q1[1]*q2[1] + q1[2]*q2[2] + q1[3]*q2[3];
+}
+
+void QuatInv(float *q)
+{
+ float f = QuatDot(q, q);
+
+ if (f == 0.0f)
+ return;
+
+ QuatConj(q);
+ QuatMulf(q, 1.0f/f);
+}
+
+void QuatMulf(float *q, float f)
+{
+ q[0] *= f;
+ q[1] *= f;
+ q[2] *= f;
+ q[3] *= f;
+}
+
+void QuatSub(float *q, float *q1, float *q2)
+{
+ q2[0]= -q2[0];
+ QuatMul(q, q1, q2);
+ q2[0]= -q2[0];
+}
+
+
+void QuatToMat3( float *q, float m[][3])
+{
+ double q0, q1, q2, q3, qda,qdb,qdc,qaa,qab,qac,qbb,qbc,qcc;
+
+ q0= M_SQRT2 * q[0];
+ q1= M_SQRT2 * q[1];
+ q2= M_SQRT2 * q[2];
+ q3= M_SQRT2 * q[3];
+
+ 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;
+
+ m[0][0]= (float)(1.0-qbb-qcc);
+ m[0][1]= (float)(qdc+qab);
+ m[0][2]= (float)(-qdb+qac);
+
+ m[1][0]= (float)(-qdc+qab);
+ m[1][1]= (float)(1.0-qaa-qcc);
+ m[1][2]= (float)(qda+qbc);
+
+ m[2][0]= (float)(qdb+qac);
+ m[2][1]= (float)(-qda+qbc);
+ m[2][2]= (float)(1.0-qaa-qbb);
+}
+
+
+void QuatToMat4( float *q, float m[][4])
+{
+ double q0, q1, q2, q3, qda,qdb,qdc,qaa,qab,qac,qbb,qbc,qcc;
+
+ q0= M_SQRT2 * q[0];
+ q1= M_SQRT2 * q[1];
+ q2= M_SQRT2 * q[2];
+ q3= M_SQRT2 * q[3];
+
+ 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;
+
+ m[0][0]= (float)(1.0-qbb-qcc);
+ m[0][1]= (float)(qdc+qab);
+ m[0][2]= (float)(-qdb+qac);
+ m[0][3]= 0.0f;
+
+ m[1][0]= (float)(-qdc+qab);
+ m[1][1]= (float)(1.0-qaa-qcc);
+ m[1][2]= (float)(qda+qbc);
+ m[1][3]= 0.0f;
+
+ m[2][0]= (float)(qdb+qac);
+ m[2][1]= (float)(-qda+qbc);
+ m[2][2]= (float)(1.0-qaa-qbb);
+ m[2][3]= 0.0f;
+
+ m[3][0]= m[3][1]= m[3][2]= 0.0f;
+ m[3][3]= 1.0f;
+}
+
+void Mat3ToQuat( float wmat[][3], float *q) /* from Sig.Proc.85 pag 253 */
+{
+ double tr, s;
+ float mat[3][3];
+
+ /* work on a copy */
+ Mat3CpyMat3(mat, wmat);
+ Mat3Ortho(mat); /* this is needed AND a NormalQuat in the end */
+
+ tr= 0.25*(1.0+mat[0][0]+mat[1][1]+mat[2][2]);
+
+ if(tr>FLT_EPSILON) {
+ s= sqrt( tr);
+ q[0]= (float)s;
+ s*= 4.0;
+ q[1]= (float)((mat[1][2]-mat[2][1])/s);
+ q[2]= (float)((mat[2][0]-mat[0][2])/s);
+ q[3]= (float)((mat[0][1]-mat[1][0])/s);
+ }
+ else {
+ q[0]= 0.0f;
+ s= -0.5*(mat[1][1]+mat[2][2]);
+
+ if(s>FLT_EPSILON) {
+ s= sqrt(s);
+ q[1]= (float)s;
+ q[2]= (float)(mat[0][1]/(2*s));
+ q[3]= (float)(mat[0][2]/(2*s));
+ }
+ else {
+ q[1]= 0.0f;
+ s= 0.5*(1.0-mat[2][2]);
+
+ if(s>FLT_EPSILON) {
+ s= sqrt(s);
+ q[2]= (float)s;
+ q[3]= (float)(mat[1][2]/(2*s));
+ }
+ else {
+ q[2]= 0.0f;
+ q[3]= 1.0f;
+ }
+ }
+ }
+ NormalQuat(q);
+}
+
+void Mat3ToQuat_is_ok( float wmat[][3], float *q)
+{
+ float mat[3][3], matr[3][3], matn[3][3], q1[4], q2[4], angle, si, co, nor[3];
+
+ /* work on a copy */
+ Mat3CpyMat3(mat, wmat);
+ Mat3Ortho(mat);
+
+ /* rotate z-axis of matrix to z-axis */
+
+ nor[0] = mat[2][1]; /* cross product with (0,0,1) */
+ nor[1] = -mat[2][0];
+ nor[2] = 0.0;
+ Normalize(nor);
+
+ co= mat[2][2];
+ angle= 0.5f*saacos(co);
+
+ co= (float)cos(angle);
+ si= (float)sin(angle);
+ q1[0]= co;
+ q1[1]= -nor[0]*si; /* negative here, but why? */
+ q1[2]= -nor[1]*si;
+ q1[3]= -nor[2]*si;
+
+ /* rotate back x-axis from mat, using inverse q1 */
+ QuatToMat3(q1, matr);
+ Mat3Inv(matn, matr);
+ Mat3MulVecfl(matn, mat[0]);
+
+ /* and align x-axes */
+ angle= (float)(0.5*atan2(mat[0][1], mat[0][0]));
+
+ co= (float)cos(angle);
+ si= (float)sin(angle);
+ q2[0]= co;
+ q2[1]= 0.0f;
+ q2[2]= 0.0f;
+ q2[3]= si;
+
+ QuatMul(q, q1, q2);
+}
+
+
+void Mat4ToQuat( float m[][4], float *q)
+{
+ float mat[3][3];
+
+ Mat3CpyMat4(mat, m);
+ Mat3ToQuat(mat, q);
+
+}
+
+void QuatOne(float *q)
+{
+ q[0]= q[2]= q[3]= 0.0;
+ q[1]= 1.0;
+}
+
+void NormalQuat(float *q)
+{
+ float len;
+
+ len= (float)sqrt(q[0]*q[0]+q[1]*q[1]+q[2]*q[2]+q[3]*q[3]);
+ if(len!=0.0) {
+ q[0]/= len;
+ q[1]/= len;
+ q[2]/= len;
+ q[3]/= len;
+ } else {
+ q[1]= 1.0f;
+ q[0]= q[2]= q[3]= 0.0f;
+ }
+}
+
+float *vectoquat( float *vec, short axis, short upflag)
+{
+ static float q1[4];
+ float q2[4], nor[3], *fp, mat[3][3], angle, si, co, x2, y2, z2, len1;
+
+ /* first rotate to axis */
+ if(axis>2) {
+ x2= vec[0] ; y2= vec[1] ; z2= vec[2];
+ axis-= 3;
+ }
+ else {
+ x2= -vec[0] ; y2= -vec[1] ; z2= -vec[2];
+ }
+
+ q1[0]=1.0;
+ q1[1]=q1[2]=q1[3]= 0.0;
+
+ len1= (float)sqrt(x2*x2+y2*y2+z2*z2);
+ if(len1 == 0.0) return(q1);
+
+ /* nasty! I need a good routine for this...
+ * problem is a rotation of an Y axis to the negative Y-axis for example.
+ */
+
+ if(axis==0) { /* x-axis */
+ nor[0]= 0.0;
+ nor[1]= -z2;
+ nor[2]= y2;
+
+ if( fabs(y2)+fabs(z2)<0.0001 ) {
+ nor[1]= 1.0;
+ }
+
+ co= x2;
+ }
+ else if(axis==1) { /* y-axis */
+ nor[0]= z2;
+ nor[1]= 0.0;
+ nor[2]= -x2;
+
+ if( fabs(x2)+fabs(z2)<0.0001 ) {
+ nor[2]= 1.0;
+ }
+
+ co= y2;
+ }
+ else { /* z-axis */
+ nor[0]= -y2;
+ nor[1]= x2;
+ nor[2]= 0.0;
+
+ if( fabs(x2)+fabs(y2)<0.0001 ) {
+ nor[0]= 1.0;
+ }
+
+ co= z2;
+ }
+ co/= len1;
+
+ Normalize(nor);
+
+ angle= 0.5f*saacos(co);
+ si= (float)sin(angle);
+ q1[0]= (float)cos(angle);
+ q1[1]= nor[0]*si;
+ q1[2]= nor[1]*si;
+ q1[3]= nor[2]*si;
+
+ if(axis!=upflag) {
+ QuatToMat3(q1, mat);
+
+ fp= mat[2];
+ if(axis==0) {
+ if(upflag==1) angle= (float)(0.5*atan2(fp[2], fp[1]));
+ else angle= (float)(-0.5*atan2(fp[1], fp[2]));
+ }
+ else if(axis==1) {
+ if(upflag==0) angle= (float)(-0.5*atan2(fp[2], fp[0]));
+ else angle= (float)(0.5*atan2(fp[0], fp[2]));
+ }
+ else {
+ if(upflag==0) angle= (float)(0.5*atan2(-fp[1], -fp[0]));
+ else angle= (float)(-0.5*atan2(-fp[0], -fp[1]));
+ }
+
+ co= (float)cos(angle);
+ si= (float)(sin(angle)/len1);
+ q2[0]= co;
+ q2[1]= x2*si;
+ q2[2]= y2*si;
+ q2[3]= z2*si;
+
+ QuatMul(q1,q2,q1);
+ }
+
+ return(q1);
+}
+
+void VecUpMat3old( float *vec, float mat[][3], short axis)
+{
+ float inp, up[3];
+ short cox = 0, coy = 0, coz = 0;
+
+ /* using different up's is not useful, infact there is no real 'up'!
+ */
+
+ up[0]= 0.0;
+ up[1]= 0.0;
+ up[2]= 1.0;
+
+ if(axis==0) {
+ cox= 0; coy= 1; coz= 2; /* Y up Z tr */
+ }
+ if(axis==1) {
+ cox= 1; coy= 2; coz= 0; /* Z up X tr */
+ }
+ if(axis==2) {
+ cox= 2; coy= 0; coz= 1; /* X up Y tr */
+ }
+ if(axis==3) {
+ cox= 0; coy= 2; coz= 1; /* */
+ }
+ if(axis==4) {
+ cox= 1; coy= 0; coz= 2; /* */
+ }
+ if(axis==5) {
+ cox= 2; coy= 1; coz= 0; /* Y up X tr */
+ }
+
+ mat[coz][0]= vec[0];
+ mat[coz][1]= vec[1];
+ mat[coz][2]= vec[2];
+ Normalize((float *)mat[coz]);
+
+ inp= mat[coz][0]*up[0] + mat[coz][1]*up[1] + mat[coz][2]*up[2];
+ mat[coy][0]= up[0] - inp*mat[coz][0];
+ mat[coy][1]= up[1] - inp*mat[coz][1];
+ mat[coy][2]= up[2] - inp*mat[coz][2];
+
+ Normalize((float *)mat[coy]);
+
+ Crossf(mat[cox], mat[coy], mat[coz]);
+
+}
+
+void VecUpMat3(float *vec, float mat[][3], short axis)
+{
+ float inp;
+ short cox = 0, coy = 0, coz = 0;
+
+ /* using different up's is not useful, infact there is no real 'up'!
+ */
+
+ if(axis==0) {
+ cox= 0; coy= 1; coz= 2; /* Y up Z tr */
+ }
+ if(axis==1) {
+ cox= 1; coy= 2; coz= 0; /* Z up X tr */
+ }
+ if(axis==2) {
+ cox= 2; coy= 0; coz= 1; /* X up Y tr */
+ }
+ if(axis==3) {
+ cox= 0; coy= 1; coz= 2; /* Y op -Z tr */
+ vec[0]= -vec[0];
+ vec[1]= -vec[1];
+ vec[2]= -vec[2];
+ }
+ if(axis==4) {
+ cox= 1; coy= 0; coz= 2; /* */
+ }
+ if(axis==5) {
+ cox= 2; coy= 1; coz= 0; /* Y up X tr */
+ }
+
+ mat[coz][0]= vec[0];
+ mat[coz][1]= vec[1];
+ mat[coz][2]= vec[2];
+ Normalize((float *)mat[coz]);
+
+ inp= mat[coz][2];
+ mat[coy][0]= - inp*mat[coz][0];
+ mat[coy][1]= - inp*mat[coz][1];
+ mat[coy][2]= 1.0f - inp*mat[coz][2];
+
+ Normalize((float *)mat[coy]);
+
+ Crossf(mat[cox], mat[coy], mat[coz]);
+
+}
+
+/* A & M Watt, Advanced animation and rendering techniques, 1992 ACM press */
+void QuatInterpolW(float *, float *, float *, float );
+
+void QuatInterpolW(float *result, float *quat1, float *quat2, float t)
+{
+ float omega, cosom, sinom, sc1, sc2;
+
+ cosom = quat1[0]*quat2[0] + quat1[1]*quat2[1] + quat1[2]*quat2[2] + quat1[3]*quat2[3] ;
+
+ /* rotate around shortest angle */
+ if ((1.0 + cosom) > 0.0001) {
+
+ if ((1.0 - cosom) > 0.0001) {
+ omega = acos(cosom);
+ sinom = sin(omega);
+ sc1 = sin((1.0 - t) * omega) / sinom;
+ sc2 = sin(t * omega) / sinom;
+ }
+ else {
+ sc1 = 1.0 - t;
+ sc2 = t;
+ }
+ result[0] = sc1*quat1[0] + sc2*quat2[0];
+ result[1] = sc1*quat1[1] + sc2*quat2[1];
+ result[2] = sc1*quat1[2] + sc2*quat2[2];
+ result[3] = sc1*quat1[3] + sc2*quat2[3];
+ }
+ else {
+ result[0] = quat2[3];
+ result[1] = -quat2[2];
+ result[2] = quat2[1];
+ result[3] = -quat2[0];
+
+ sc1 = sin((1.0 - t)*M_PI_2);
+ sc2 = sin(t*M_PI_2);
+
+ result[0] = sc1*quat1[0] + sc2*result[0];
+ result[1] = sc1*quat1[1] + sc2*result[1];
+ result[2] = sc1*quat1[2] + sc2*result[2];
+ result[3] = sc1*quat1[3] + sc2*result[3];
+ }
+}
+
+void QuatInterpol(float *result, float *quat1, float *quat2, float t)
+{
+ float quat[4], omega, cosom, sinom, sc1, sc2;
+
+ cosom = quat1[0]*quat2[0] + quat1[1]*quat2[1] + quat1[2]*quat2[2] + quat1[3]*quat2[3] ;
+
+ /* rotate around shortest angle */
+ if (cosom < 0.0) {
+ cosom = -cosom;
+ quat[0]= -quat1[0];
+ quat[1]= -quat1[1];
+ quat[2]= -quat1[2];
+ quat[3]= -quat1[3];
+ }
+ else {
+ quat[0]= quat1[0];
+ quat[1]= quat1[1];
+ quat[2]= quat1[2];
+ quat[3]= quat1[3];
+ }
+
+ if ((1.0 - cosom) > 0.0001) {
+ omega = acos(cosom);
+ sinom = sin(omega);
+ sc1 = sin((1 - t) * omega) / sinom;
+ sc2 = sin(t * omega) / sinom;
+ } else {
+ sc1= 1.0 - t;
+ sc2= t;
+ }
+
+ result[0] = sc1 * quat[0] + sc2 * quat2[0];
+ result[1] = sc1 * quat[1] + sc2 * quat2[1];
+ result[2] = sc1 * quat[2] + sc2 * quat2[2];
+ result[3] = sc1 * quat[3] + sc2 * quat2[3];
+}
+
+void QuatAdd(float *result, float *quat1, float *quat2, float t)
+{
+ result[0]= quat1[0] + t*quat2[0];
+ result[1]= quat1[1] + t*quat2[1];
+ result[2]= quat1[2] + t*quat2[2];
+ result[3]= quat1[3] + t*quat2[3];
+}
+
+void QuatCopy(float *q1, float *q2)
+{
+ q1[0]= q2[0];
+ q1[1]= q2[1];
+ q1[2]= q2[2];
+ q1[3]= q2[3];
+}
+
+/* **************** DUAL QUATERNIONS ************** */
+
+/*
+ Conversion routines between (regular quaternion, translation) and
+ dual quaternion.
+
+ Version 1.0.0, February 7th, 2007
+
+ Copyright (C) 2006-2007 University of Dublin, Trinity College, All Rights
+ Reserved
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the author(s) 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.
+
+ Author: Ladislav Kavan, kavanl@cs.tcd.ie
+
+ Changes for Blender:
+ - renaming, style changes and optimizations
+ - added support for scaling
+*/
+
+void Mat4ToDQuat(float basemat[][4], float mat[][4], DualQuat *dq)
+{
+ float *t, *q, dscale[3], scale[3], basequat[4];
+ float baseRS[4][4], baseinv[4][4], baseR[4][4], baseRinv[4][4];
+ float R[4][4], S[4][4];
+
+ /* split scaling and rotation, there is probably a faster way to do
+ this, it's done like this now to correctly get negative scaling */
+ Mat4MulMat4(baseRS, basemat, mat);
+ Mat4ToSize(baseRS, scale);
+
+ VecCopyf(dscale, scale);
+ dscale[0] -= 1.0f; dscale[1] -= 1.0f; dscale[2] -= 1.0f;
+
+ if((Det4x4(mat) < 0.0f) || VecLength(dscale) > 1e-4) {
+ /* extract R and S */
+ Mat4ToQuat(baseRS, basequat);
+ QuatToMat4(basequat, baseR);
+ VecCopyf(baseR[3], baseRS[3]);
+
+ Mat4Invert(baseinv, basemat);
+ Mat4MulMat4(R, baseinv, baseR);
+
+ Mat4Invert(baseRinv, baseR);
+ Mat4MulMat4(S, baseRS, baseRinv);
+
+ /* set scaling part */
+ Mat4MulSerie(dq->scale, basemat, S, baseinv, 0, 0, 0, 0, 0);
+ dq->scale_weight= 1.0f;
+ }
+ else {
+ /* matrix does not contain scaling */
+ Mat4CpyMat4(R, mat);
+ dq->scale_weight= 0.0f;
+ }
+
+ /* non-dual part */
+ Mat4ToQuat(R, dq->quat);
+
+ /* dual part */
+ t= R[3];
+ q= dq->quat;
+ dq->trans[0]= -0.5f*( t[0]*q[1] + t[1]*q[2] + t[2]*q[3]);
+ dq->trans[1]= 0.5f*( t[0]*q[0] + t[1]*q[3] - t[2]*q[2]);
+ dq->trans[2]= 0.5f*(-t[0]*q[3] + t[1]*q[0] + t[2]*q[1]);
+ dq->trans[3]= 0.5f*( t[0]*q[2] - t[1]*q[1] + t[2]*q[0]);
+}
+
+void DQuatToMat4(DualQuat *dq, float mat[][4])
+{
+ float len, *t, q0[4];
+
+ /* regular quaternion */
+ QuatCopy(q0, dq->quat);
+
+ /* normalize */
+ len= sqrt(QuatDot(q0, q0));
+ if(len != 0.0f)
+ QuatMulf(q0, 1.0f/len);
+
+ /* rotation */
+ QuatToMat4(q0, mat);
+
+ /* translation */
+ t= dq->trans;
+ mat[3][0]= 2.0*(-t[0]*q0[1] + t[1]*q0[0] - t[2]*q0[3] + t[3]*q0[2]);
+ mat[3][1]= 2.0*(-t[0]*q0[2] + t[1]*q0[3] + t[2]*q0[0] - t[3]*q0[1]);
+ mat[3][2]= 2.0*(-t[0]*q0[3] - t[1]*q0[2] + t[2]*q0[1] + t[3]*q0[0]);
+
+ /* note: this does not handle scaling */
+}
+
+void DQuatAddWeighted(DualQuat *dqsum, DualQuat *dq, float weight)
+{
+ /* make sure we interpolate quats in the right direction */
+ if (QuatDot(dq->quat, dqsum->quat) < 0)
+ weight = -weight;
+
+ /* interpolate rotation and translation */
+ dqsum->quat[0] += weight*dq->quat[0];
+ dqsum->quat[1] += weight*dq->quat[1];
+ dqsum->quat[2] += weight*dq->quat[2];
+ dqsum->quat[3] += weight*dq->quat[3];
+
+ dqsum->trans[0] += weight*dq->trans[0];
+ dqsum->trans[1] += weight*dq->trans[1];
+ dqsum->trans[2] += weight*dq->trans[2];
+ dqsum->trans[3] += weight*dq->trans[3];
+
+ /* interpolate scale - but only if needed */
+ if (dq->scale_weight) {
+ float wmat[4][4];
+
+ Mat4CpyMat4(wmat, dq->scale);
+ Mat4MulFloat((float*)wmat, weight);
+ Mat4AddMat4(dqsum->scale, dqsum->scale, wmat);
+ dqsum->scale_weight += weight;
+ }
+}
+
+void DQuatNormalize(DualQuat *dq, float totweight, float factor)
+{
+ float scale= factor/totweight;
+
+ QuatMulf(dq->quat, scale);
+ QuatMulf(dq->trans, scale);
+
+ if(dq->scale_weight) {
+ float addweight= totweight - dq->scale_weight;
+
+ if(addweight) {
+ dq->scale[0][0] += addweight;
+ dq->scale[1][1] += addweight;
+ dq->scale[2][2] += addweight;
+ dq->scale[3][3] += addweight;
+ }
+
+ Mat4MulFloat((float*)dq->scale, scale);
+ dq->scale_weight= 1.0f;
+ }
+}
+
+void DQuatMulVecfl(DualQuat *dq, float *co, float mat[][3])
+{
+ float M[3][3], t[3], scalemat[3][3], len2;
+ float w= dq->quat[0], x= dq->quat[1], y= dq->quat[2], z= dq->quat[3];
+ float t0= dq->trans[0], t1= dq->trans[1], t2= dq->trans[2], t3= dq->trans[3];
+
+ /* rotation matrix */
+ M[0][0]= w*w + x*x - y*y - z*z;
+ M[1][0]= 2*(x*y - w*z);
+ M[2][0]= 2*(x*z + w*y);
+
+ M[0][1]= 2*(x*y + w*z);
+ M[1][1]= w*w + y*y - x*x - z*z;
+ M[2][1]= 2*(y*z - w*x);
+
+ M[0][2]= 2*(x*z - w*y);
+ M[1][2]= 2*(y*z + w*x);
+ M[2][2]= w*w + z*z - x*x - y*y;
+
+ len2= QuatDot(dq->quat, dq->quat);
+ if(len2 > 0.0f)
+ len2= 1.0f/len2;
+
+ /* translation */
+ t[0]= 2*(-t0*x + w*t1 - t2*z + y*t3);
+ t[1]= 2*(-t0*y + t1*z - x*t3 + w*t2);
+ t[2]= 2*(-t0*z + x*t2 + w*t3 - t1*y);
+
+ /* apply scaling */
+ if(dq->scale_weight)
+ Mat4MulVecfl(dq->scale, co);
+
+ /* apply rotation and translation */
+ Mat3MulVecfl(M, co);
+ co[0]= (co[0] + t[0])*len2;
+ co[1]= (co[1] + t[1])*len2;
+ co[2]= (co[2] + t[2])*len2;
+
+ /* compute crazyspace correction mat */
+ if(mat) {
+ if(dq->scale_weight) {
+ Mat3CpyMat4(scalemat, dq->scale);
+ Mat3MulMat3(mat, M, scalemat);
+ }
+ else
+ Mat3CpyMat3(mat, M);
+ Mat3MulFloat((float*)mat, len2);
+ }
+}
+
+void DQuatCpyDQuat(DualQuat *dq1, DualQuat *dq2)
+{
+ memcpy(dq1, dq2, sizeof(DualQuat));
+}
+
+/* **************** VIEW / PROJECTION ******************************** */
+
+
+void i_ortho(
+ float left, float right,
+ float bottom, float top,
+ float nearClip, float farClip,
+ float matrix[][4]
+){
+ float Xdelta, Ydelta, Zdelta;
+
+ Xdelta = right - left;
+ Ydelta = top - bottom;
+ Zdelta = farClip - nearClip;
+ if (Xdelta == 0.0 || Ydelta == 0.0 || Zdelta == 0.0) {
+ return;
+ }
+ Mat4One(matrix);
+ matrix[0][0] = 2.0f/Xdelta;
+ matrix[3][0] = -(right + left)/Xdelta;
+ matrix[1][1] = 2.0f/Ydelta;
+ matrix[3][1] = -(top + bottom)/Ydelta;
+ matrix[2][2] = -2.0f/Zdelta; /* note: negate Z */
+ matrix[3][2] = -(farClip + nearClip)/Zdelta;
+}
+
+void i_window(
+ float left, float right,
+ float bottom, float top,
+ float nearClip, float farClip,
+ float mat[][4]
+){
+ float Xdelta, Ydelta, Zdelta;
+
+ Xdelta = right - left;
+ Ydelta = top - bottom;
+ Zdelta = farClip - nearClip;
+
+ if (Xdelta == 0.0 || Ydelta == 0.0 || Zdelta == 0.0) {
+ return;
+ }
+ mat[0][0] = nearClip * 2.0f/Xdelta;
+ mat[1][1] = nearClip * 2.0f/Ydelta;
+ mat[2][0] = (right + left)/Xdelta; /* note: negate Z */
+ mat[2][1] = (top + bottom)/Ydelta;
+ mat[2][2] = -(farClip + nearClip)/Zdelta;
+ mat[2][3] = -1.0f;
+ mat[3][2] = (-2.0f * nearClip * farClip)/Zdelta;
+ mat[0][1] = mat[0][2] = mat[0][3] =
+ mat[1][0] = mat[1][2] = mat[1][3] =
+ mat[3][0] = mat[3][1] = mat[3][3] = 0.0;
+
+}
+
+void i_translate(float Tx, float Ty, float Tz, float mat[][4])
+{
+ mat[3][0] += (Tx*mat[0][0] + Ty*mat[1][0] + Tz*mat[2][0]);
+ mat[3][1] += (Tx*mat[0][1] + Ty*mat[1][1] + Tz*mat[2][1]);
+ mat[3][2] += (Tx*mat[0][2] + Ty*mat[1][2] + Tz*mat[2][2]);
+}
+
+void i_multmatrix( float icand[][4], float Vm[][4])
+{
+ int row, col;
+ float temp[4][4];
+
+ for(row=0 ; row<4 ; row++)
+ for(col=0 ; col<4 ; col++)
+ temp[row][col] = icand[row][0] * Vm[0][col]
+ + icand[row][1] * Vm[1][col]
+ + icand[row][2] * Vm[2][col]
+ + icand[row][3] * Vm[3][col];
+ Mat4CpyMat4(Vm, temp);
+}
+
+void i_rotate(float angle, char axis, float mat[][4])
+{
+ int col;
+ float temp[4];
+ float cosine, sine;
+
+ for(col=0; col<4 ; col++) /* init temp to zero matrix */
+ temp[col] = 0;
+
+ angle = (float)(angle*(3.1415926535/180.0));
+ cosine = (float)cos(angle);
+ sine = (float)sin(angle);
+ switch(axis){
+ case 'x':
+ case 'X':
+ for(col=0 ; col<4 ; col++)
+ temp[col] = cosine*mat[1][col] + sine*mat[2][col];
+ for(col=0 ; col<4 ; col++) {
+ mat[2][col] = - sine*mat[1][col] + cosine*mat[2][col];
+ mat[1][col] = temp[col];
+ }
+ break;
+
+ case 'y':
+ case 'Y':
+ for(col=0 ; col<4 ; col++)
+ temp[col] = cosine*mat[0][col] - sine*mat[2][col];
+ for(col=0 ; col<4 ; col++) {
+ mat[2][col] = sine*mat[0][col] + cosine*mat[2][col];
+ mat[0][col] = temp[col];
+ }
+ break;
+
+ case 'z':
+ case 'Z':
+ for(col=0 ; col<4 ; col++)
+ temp[col] = cosine*mat[0][col] + sine*mat[1][col];
+ for(col=0 ; col<4 ; col++) {
+ mat[1][col] = - sine*mat[0][col] + cosine*mat[1][col];
+ mat[0][col] = temp[col];
+ }
+ break;
+ }
+}
+
+void i_polarview(float dist, float azimuth, float incidence, float twist, float Vm[][4])
+{
+
+ Mat4One(Vm);
+
+ i_translate(0.0, 0.0, -dist, Vm);
+ i_rotate(-twist,'z', Vm);
+ i_rotate(-incidence,'x', Vm);
+ i_rotate(-azimuth,'z', Vm);
+}
+
+void i_lookat(float vx, float vy, float vz, float px, float py, float pz, float twist, float mat[][4])
+{
+ float sine, cosine, hyp, hyp1, dx, dy, dz;
+ float mat1[4][4];
+
+ Mat4One(mat);
+ Mat4One(mat1);
+
+ i_rotate(-twist,'z', mat);
+
+ dx = px - vx;
+ dy = py - vy;
+ dz = pz - vz;
+ hyp = dx * dx + dz * dz; /* hyp squared */
+ hyp1 = (float)sqrt(dy*dy + hyp);
+ hyp = (float)sqrt(hyp); /* the real hyp */
+
+ if (hyp1 != 0.0) { /* rotate X */
+ sine = -dy / hyp1;
+ cosine = hyp /hyp1;
+ } else {
+ sine = 0;
+ cosine = 1.0f;
+ }
+ mat1[1][1] = cosine;
+ mat1[1][2] = sine;
+ mat1[2][1] = -sine;
+ mat1[2][2] = cosine;
+
+ i_multmatrix(mat1, mat);
+
+ mat1[1][1] = mat1[2][2] = 1.0f; /* be careful here to reinit */
+ mat1[1][2] = mat1[2][1] = 0.0; /* those modified by the last */
+
+ /* paragraph */
+ if (hyp != 0.0f) { /* rotate Y */
+ sine = dx / hyp;
+ cosine = -dz / hyp;
+ } else {
+ sine = 0;
+ cosine = 1.0f;
+ }
+ mat1[0][0] = cosine;
+ mat1[0][2] = -sine;
+ mat1[2][0] = sine;
+ mat1[2][2] = cosine;
+
+ i_multmatrix(mat1, mat);
+ i_translate(-vx,-vy,-vz, mat); /* translate viewpoint to origin */
+}
+
+
+
+
+
+/* ************************************************ */
+
+void Mat3Ortho(float mat[][3])
+{
+ Normalize(mat[0]);
+ Normalize(mat[1]);
+ Normalize(mat[2]);
+}
+
+void Mat4Ortho(float mat[][4])
+{
+ float len;
+
+ len= Normalize(mat[0]);
+ if(len!=0.0) mat[0][3]/= len;
+ len= Normalize(mat[1]);
+ if(len!=0.0) mat[1][3]/= len;
+ len= Normalize(mat[2]);
+ if(len!=0.0) mat[2][3]/= len;
+}
+
+void VecCopyf(float *v1, float *v2)
+{
+ v1[0]= v2[0];
+ v1[1]= v2[1];
+ v1[2]= v2[2];
+}
+
+int VecLen( int *v1, int *v2)
+{
+ float x,y,z;
+
+ x=(float)(v1[0]-v2[0]);
+ y=(float)(v1[1]-v2[1]);
+ z=(float)(v1[2]-v2[2]);
+ return (int)floor(sqrt(x*x+y*y+z*z));
+}
+
+float VecLenf( float *v1, float *v2)
+{
+ float x,y,z;
+
+ x=v1[0]-v2[0];
+ y=v1[1]-v2[1];
+ z=v1[2]-v2[2];
+ return (float)sqrt(x*x+y*y+z*z);
+}
+
+float VecLength(float *v)
+{
+ return (float) sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
+}
+
+void VecAddf(float *v, float *v1, float *v2)
+{
+ v[0]= v1[0]+ v2[0];
+ v[1]= v1[1]+ v2[1];
+ v[2]= v1[2]+ v2[2];
+}
+
+void VecSubf(float *v, float *v1, float *v2)
+{
+ v[0]= v1[0]- v2[0];
+ v[1]= v1[1]- v2[1];
+ v[2]= v1[2]- v2[2];
+}
+
+void VecLerpf(float *target, float *a, float *b, float t)
+{
+ float s = 1.0f-t;
+
+ target[0]= s*a[0] + t*b[0];
+ target[1]= s*a[1] + t*b[1];
+ target[2]= s*a[2] + t*b[2];
+}
+
+void VecMidf(float *v, float *v1, float *v2)
+{
+ v[0]= 0.5f*(v1[0]+ v2[0]);
+ v[1]= 0.5f*(v1[1]+ v2[1]);
+ v[2]= 0.5f*(v1[2]+ v2[2]);
+}
+
+void VecMulf(float *v1, float f)
+{
+
+ v1[0]*= f;
+ v1[1]*= f;
+ v1[2]*= f;
+}
+
+void VecOrthoBasisf(float *v, float *v1, float *v2)
+{
+ if (v[0] == 0.0f && v[1] == 0.0f)
+ {
+ // degenerate case
+ v1[0] = 0.0f; v1[1] = 1.0f; v1[2] = 0.0f;
+ if (v[2] > 0.0f) {
+ v2[0] = 1.0f; v2[1] = v2[2] = 0.0f;
+ }
+ else {
+ v2[0] = -1.0f; v2[1] = v2[2] = 0.0f;
+ }
+ }
+ else
+ {
+ float f = 1.0f/sqrt(v[0]*v[0] + v[1]*v[1]);
+ v1[0] = v[1]*f;
+ v1[1] = -v[0]*f;
+ v1[2] = 0.0f;
+
+ Crossf(v2, v, v1);
+ }
+}
+
+int VecLenCompare(float *v1, float *v2, float limit)
+{
+ float x,y,z;
+
+ x=v1[0]-v2[0];
+ y=v1[1]-v2[1];
+ z=v1[2]-v2[2];
+
+ return ((x*x + y*y + z*z) < (limit*limit));
+}
+
+int VecCompare( float *v1, float *v2, float limit)
+{
+ if( fabs(v1[0]-v2[0])<limit )
+ if( fabs(v1[1]-v2[1])<limit )
+ if( fabs(v1[2]-v2[2])<limit ) return 1;
+ return 0;
+}
+
+int VecEqual(float *v1, float *v2)
+{
+ return ((v1[0]==v2[0]) && (v1[1]==v2[1]) && (v1[2]==v2[2]));
+}
+
+void CalcNormShort( short *v1, short *v2, short *v3, float *n) /* is also cross product */
+{
+ float n1[3],n2[3];
+
+ n1[0]= (float)(v1[0]-v2[0]);
+ n2[0]= (float)(v2[0]-v3[0]);
+ n1[1]= (float)(v1[1]-v2[1]);
+ n2[1]= (float)(v2[1]-v3[1]);
+ n1[2]= (float)(v1[2]-v2[2]);
+ n2[2]= (float)(v2[2]-v3[2]);
+ n[0]= n1[1]*n2[2]-n1[2]*n2[1];
+ n[1]= n1[2]*n2[0]-n1[0]*n2[2];
+ n[2]= n1[0]*n2[1]-n1[1]*n2[0];
+ Normalize(n);
+}
+
+void CalcNormLong( int* v1, int*v2, int*v3, float *n)
+{
+ float n1[3],n2[3];
+
+ n1[0]= (float)(v1[0]-v2[0]);
+ n2[0]= (float)(v2[0]-v3[0]);
+ n1[1]= (float)(v1[1]-v2[1]);
+ n2[1]= (float)(v2[1]-v3[1]);
+ n1[2]= (float)(v1[2]-v2[2]);
+ n2[2]= (float)(v2[2]-v3[2]);
+ n[0]= n1[1]*n2[2]-n1[2]*n2[1];
+ n[1]= n1[2]*n2[0]-n1[0]*n2[2];
+ n[2]= n1[0]*n2[1]-n1[1]*n2[0];
+ Normalize(n);
+}
+
+float CalcNormFloat( float *v1, float *v2, float *v3, float *n)
+{
+ float n1[3],n2[3];
+
+ n1[0]= v1[0]-v2[0];
+ n2[0]= v2[0]-v3[0];
+ n1[1]= v1[1]-v2[1];
+ n2[1]= v2[1]-v3[1];
+ n1[2]= v1[2]-v2[2];
+ n2[2]= v2[2]-v3[2];
+ n[0]= n1[1]*n2[2]-n1[2]*n2[1];
+ n[1]= n1[2]*n2[0]-n1[0]*n2[2];
+ n[2]= n1[0]*n2[1]-n1[1]*n2[0];
+ return Normalize(n);
+}
+
+float CalcNormFloat4( float *v1, float *v2, float *v3, float *v4, float *n)
+{
+ /* real cross! */
+ float n1[3],n2[3];
+
+ n1[0]= v1[0]-v3[0];
+ n1[1]= v1[1]-v3[1];
+ n1[2]= v1[2]-v3[2];
+
+ n2[0]= v2[0]-v4[0];
+ n2[1]= v2[1]-v4[1];
+ n2[2]= v2[2]-v4[2];
+
+ n[0]= n1[1]*n2[2]-n1[2]*n2[1];
+ n[1]= n1[2]*n2[0]-n1[0]*n2[2];
+ n[2]= n1[0]*n2[1]-n1[1]*n2[0];
+
+ return Normalize(n);
+}
+
+
+void CalcCent3f(float *cent, float *v1, float *v2, float *v3)
+{
+
+ cent[0]= 0.33333f*(v1[0]+v2[0]+v3[0]);
+ cent[1]= 0.33333f*(v1[1]+v2[1]+v3[1]);
+ cent[2]= 0.33333f*(v1[2]+v2[2]+v3[2]);
+}
+
+void CalcCent4f(float *cent, float *v1, float *v2, float *v3, float *v4)
+{
+
+ cent[0]= 0.25f*(v1[0]+v2[0]+v3[0]+v4[0]);
+ cent[1]= 0.25f*(v1[1]+v2[1]+v3[1]+v4[1]);
+ cent[2]= 0.25f*(v1[2]+v2[2]+v3[2]+v4[2]);
+}
+
+float Sqrt3f(float f)
+{
+ if(f==0.0) return 0;
+ if(f<0) return (float)(-exp(log(-f)/3));
+ else return (float)(exp(log(f)/3));
+}
+
+double Sqrt3d(double d)
+{
+ if(d==0.0) return 0;
+ if(d<0) return -exp(log(-d)/3);
+ else return exp(log(d)/3);
+}
+
+/* distance v1 to line v2-v3 */
+/* using Hesse formula, NO LINE PIECE! */
+float DistVL2Dfl( float *v1, float *v2, float *v3) {
+ float a[2],deler;
+
+ a[0]= v2[1]-v3[1];
+ a[1]= v3[0]-v2[0];
+ deler= (float)sqrt(a[0]*a[0]+a[1]*a[1]);
+ if(deler== 0.0f) return 0;
+
+ return (float)(fabs((v1[0]-v2[0])*a[0]+(v1[1]-v2[1])*a[1])/deler);
+
+}
+
+/* distance v1 to line-piece v2-v3 */
+float PdistVL2Dfl( float *v1, float *v2, float *v3)
+{
+ float labda, rc[2], pt[2], len;
+
+ rc[0]= v3[0]-v2[0];
+ rc[1]= v3[1]-v2[1];
+ len= rc[0]*rc[0]+ rc[1]*rc[1];
+ if(len==0.0) {
+ rc[0]= v1[0]-v2[0];
+ rc[1]= v1[1]-v2[1];
+ return (float)(sqrt(rc[0]*rc[0]+ rc[1]*rc[1]));
+ }
+
+ labda= ( rc[0]*(v1[0]-v2[0]) + rc[1]*(v1[1]-v2[1]) )/len;
+ if(labda<=0.0) {
+ pt[0]= v2[0];
+ pt[1]= v2[1];
+ }
+ else if(labda>=1.0) {
+ pt[0]= v3[0];
+ pt[1]= v3[1];
+ }
+ else {
+ pt[0]= labda*rc[0]+v2[0];
+ pt[1]= labda*rc[1]+v2[1];
+ }
+
+ rc[0]= pt[0]-v1[0];
+ rc[1]= pt[1]-v1[1];
+ return (float)sqrt(rc[0]*rc[0]+ rc[1]*rc[1]);
+}
+
+float AreaF2Dfl( float *v1, float *v2, float *v3)
+{
+ return (float)(0.5*fabs( (v1[0]-v2[0])*(v2[1]-v3[1]) + (v1[1]-v2[1])*(v3[0]-v2[0]) ));
+}
+
+
+float AreaQ3Dfl( float *v1, float *v2, float *v3, float *v4) /* only convex Quadrilaterals */
+{
+ float len, vec1[3], vec2[3], n[3];
+
+ VecSubf(vec1, v2, v1);
+ VecSubf(vec2, v4, v1);
+ Crossf(n, vec1, vec2);
+ len= Normalize(n);
+
+ VecSubf(vec1, v4, v3);
+ VecSubf(vec2, v2, v3);
+ Crossf(n, vec1, vec2);
+ len+= Normalize(n);
+
+ return (len/2.0f);
+}
+
+float AreaT3Dfl( float *v1, float *v2, float *v3) /* Triangles */
+{
+ float len, vec1[3], vec2[3], n[3];
+
+ VecSubf(vec1, v3, v2);
+ VecSubf(vec2, v1, v2);
+ Crossf(n, vec1, vec2);
+ len= Normalize(n);
+
+ return (len/2.0f);
+}
+
+#define MAX2(x,y) ( (x)>(y) ? (x) : (y) )
+#define MAX3(x,y,z) MAX2( MAX2((x),(y)) , (z) )
+
+
+float AreaPoly3Dfl(int nr, float *verts, float *normal)
+{
+ float x, y, z, area, max;
+ float *cur, *prev;
+ int a, px=0, py=1;
+
+ /* first: find dominant axis: 0==X, 1==Y, 2==Z */
+ x= (float)fabs(normal[0]);
+ y= (float)fabs(normal[1]);
+ z= (float)fabs(normal[2]);
+ max = MAX3(x, y, z);
+ if(max==y) py=2;
+ else if(max==x) {
+ px=1;
+ py= 2;
+ }
+
+ /* The Trapezium Area Rule */
+ prev= verts+3*(nr-1);
+ cur= verts;
+ area= 0;
+ for(a=0; a<nr; a++) {
+ area+= (cur[px]-prev[px])*(cur[py]+prev[py]);
+ prev= cur;
+ cur+=3;
+ }
+
+ return (float)fabs(0.5*area/max);
+}
+
+/* intersect Line-Line, shorts */
+short IsectLL2Ds(short *v1, short *v2, short *v3, short *v4)
+{
+ /* return:
+ -1: colliniar
+ 0: no intersection of segments
+ 1: exact intersection of segments
+ 2: cross-intersection of segments
+ */
+ float div, labda, mu;
+
+ div= (v2[0]-v1[0])*(v4[1]-v3[1])-(v2[1]-v1[1])*(v4[0]-v3[0]);
+ if(div==0.0) return -1;
+
+ labda= ((float)(v1[1]-v3[1])*(v4[0]-v3[0])-(v1[0]-v3[0])*(v4[1]-v3[1]))/div;
+
+ mu= ((float)(v1[1]-v3[1])*(v2[0]-v1[0])-(v1[0]-v3[0])*(v2[1]-v1[1]))/div;
+
+ if(labda>=0.0 && labda<=1.0 && mu>=0.0 && mu<=1.0) {
+ if(labda==0.0 || labda==1.0 || mu==0.0 || mu==1.0) return 1;
+ return 2;
+ }
+ return 0;
+}
+
+/* intersect Line-Line, floats */
+short IsectLL2Df(float *v1, float *v2, float *v3, float *v4)
+{
+ /* return:
+ -1: colliniar
+0: no intersection of segments
+1: exact intersection of segments
+2: cross-intersection of segments
+ */
+ float div, labda, mu;
+
+ div= (v2[0]-v1[0])*(v4[1]-v3[1])-(v2[1]-v1[1])*(v4[0]-v3[0]);
+ if(div==0.0) return -1;
+
+ labda= ((float)(v1[1]-v3[1])*(v4[0]-v3[0])-(v1[0]-v3[0])*(v4[1]-v3[1]))/div;
+
+ mu= ((float)(v1[1]-v3[1])*(v2[0]-v1[0])-(v1[0]-v3[0])*(v2[1]-v1[1]))/div;
+
+ if(labda>=0.0 && labda<=1.0 && mu>=0.0 && mu<=1.0) {
+ if(labda==0.0 || labda==1.0 || mu==0.0 || mu==1.0) return 1;
+ return 2;
+ }
+ return 0;
+}
+
+void MinMax3(float *min, float *max, float *vec)
+{
+ if(min[0]>vec[0]) min[0]= vec[0];
+ if(min[1]>vec[1]) min[1]= vec[1];
+ if(min[2]>vec[2]) min[2]= vec[2];
+
+ if(max[0]<vec[0]) max[0]= vec[0];
+ if(max[1]<vec[1]) max[1]= vec[1];
+ if(max[2]<vec[2]) max[2]= vec[2];
+}
+
+static float TriSignedArea(float *v1, float *v2, float *v3, int i, int j)
+{
+ return 0.5f*((v1[i]-v2[i])*(v2[j]-v3[j]) + (v1[j]-v2[j])*(v3[i]-v2[i]));
+}
+
+static int BarycentricWeights(float *v1, float *v2, float *v3, float *co, float *n, float *w)
+{
+ float xn, yn, zn, a1, a2, a3, asum;
+ short i, j;
+
+ /* find best projection of face XY, XZ or YZ: barycentric weights of
+ the 2d projected coords are the same and faster to compute */
+ xn= fabs(n[0]);
+ yn= fabs(n[1]);
+ zn= fabs(n[2]);
+ if(zn>=xn && zn>=yn) {i= 0; j= 1;}
+ else if(yn>=xn && yn>=zn) {i= 0; j= 2;}
+ else {i= 1; j= 2;}
+
+ a1= TriSignedArea(v2, v3, co, i, j);
+ a2= TriSignedArea(v3, v1, co, i, j);
+ a3= TriSignedArea(v1, v2, co, i, j);
+
+ asum= a1 + a2 + a3;
+
+ if (fabs(asum) < FLT_EPSILON) {
+ /* zero area triangle */
+ w[0]= w[1]= w[2]= 1.0f/3.0f;
+ return 1;
+ }
+
+ asum= 1.0f/asum;
+ w[0]= a1*asum;
+ w[1]= a2*asum;
+ w[2]= a3*asum;
+
+ return 0;
+}
+
+void InterpWeightsQ3Dfl(float *v1, float *v2, float *v3, float *v4, float *co, float *w)
+{
+ float w2[3];
+
+ w[0]= w[1]= w[2]= w[3]= 0.0f;
+
+ /* first check for exact match */
+ if(VecEqual(co, v1))
+ w[0]= 1.0f;
+ else if(VecEqual(co, v2))
+ w[1]= 1.0f;
+ else if(VecEqual(co, v3))
+ w[2]= 1.0f;
+ else if(v4 && VecEqual(co, v4))
+ w[3]= 1.0f;
+ else {
+ /* otherwise compute barycentric interpolation weights */
+ float n1[3], n2[3], n[3];
+ int degenerate;
+
+ VecSubf(n1, v1, v3);
+ if (v4) {
+ VecSubf(n2, v2, v4);
+ }
+ else {
+ VecSubf(n2, v2, v3);
+ }
+ Crossf(n, n1, n2);
+
+ /* OpenGL seems to split this way, so we do too */
+ if (v4) {
+ degenerate= BarycentricWeights(v1, v2, v4, co, n, w);
+ SWAP(float, w[2], w[3]);
+
+ if(degenerate || (w[0] < 0.0f)) {
+ /* if w[1] is negative, co is on the other side of the v1-v3 edge,
+ so we interpolate using the other triangle */
+ degenerate= BarycentricWeights(v2, v3, v4, co, n, w2);
+
+ if(!degenerate) {
+ w[0]= 0.0f;
+ w[1]= w2[0];
+ w[2]= w2[1];
+ w[3]= w2[2];
+ }
+ }
+ }
+ else
+ BarycentricWeights(v1, v2, v3, co, n, w);
+ }
+}
+
+/* Mean value weights - smooth interpolation weights for polygons with
+ * more than 3 vertices */
+static float MeanValueHalfTan(float *v1, float *v2, float *v3)
+{
+ float d2[3], d3[3], cross[3], area, dot, len;
+
+ VecSubf(d2, v2, v1);
+ VecSubf(d3, v3, v1);
+ Crossf(cross, d2, d3);
+
+ area= VecLength(cross);
+ dot= Inpf(d2, d3);
+ len= VecLength(d2)*VecLength(d3);
+
+ if(area == 0.0f)
+ return 0.0f;
+ else
+ return (len - dot)/area;
+}
+
+void MeanValueWeights(float v[][3], int n, float *co, float *w)
+{
+ float totweight, t1, t2, len, *vmid, *vprev, *vnext;
+ int i;
+
+ totweight= 0.0f;
+
+ for(i=0; i<n; i++) {
+ vmid= v[i];
+ vprev= (i == 0)? v[n-1]: v[i-1];
+ vnext= (i == n-1)? v[0]: v[i+1];
+
+ t1= MeanValueHalfTan(co, vprev, vmid);
+ t2= MeanValueHalfTan(co, vmid, vnext);
+
+ len= VecLenf(co, vmid);
+ w[i]= (t1+t2)/len;
+ totweight += w[i];
+ }
+
+ if(totweight != 0.0f)
+ for(i=0; i<n; i++)
+ w[i] /= totweight;
+}
+
+
+/* ************ EULER *************** */
+
+void EulToMat3( float *eul, float mat[][3])
+{
+ double ci, cj, ch, si, sj, sh, cc, cs, sc, ss;
+
+ ci = cos(eul[0]);
+ cj = cos(eul[1]);
+ ch = cos(eul[2]);
+ si = sin(eul[0]);
+ sj = sin(eul[1]);
+ sh = sin(eul[2]);
+ cc = ci*ch;
+ cs = ci*sh;
+ sc = si*ch;
+ ss = si*sh;
+
+ mat[0][0] = (float)(cj*ch);
+ mat[1][0] = (float)(sj*sc-cs);
+ mat[2][0] = (float)(sj*cc+ss);
+ mat[0][1] = (float)(cj*sh);
+ mat[1][1] = (float)(sj*ss+cc);
+ mat[2][1] = (float)(sj*cs-sc);
+ mat[0][2] = (float)-sj;
+ mat[1][2] = (float)(cj*si);
+ mat[2][2] = (float)(cj*ci);
+
+}
+
+void EulToMat4( float *eul,float mat[][4])
+{
+ double ci, cj, ch, si, sj, sh, cc, cs, sc, ss;
+
+ ci = cos(eul[0]);
+ cj = cos(eul[1]);
+ ch = cos(eul[2]);
+ si = sin(eul[0]);
+ sj = sin(eul[1]);
+ sh = sin(eul[2]);
+ cc = ci*ch;
+ cs = ci*sh;
+ sc = si*ch;
+ ss = si*sh;
+
+ mat[0][0] = (float)(cj*ch);
+ mat[1][0] = (float)(sj*sc-cs);
+ mat[2][0] = (float)(sj*cc+ss);
+ mat[0][1] = (float)(cj*sh);
+ mat[1][1] = (float)(sj*ss+cc);
+ mat[2][1] = (float)(sj*cs-sc);
+ mat[0][2] = (float)-sj;
+ mat[1][2] = (float)(cj*si);
+ mat[2][2] = (float)(cj*ci);
+
+
+ mat[3][0]= mat[3][1]= mat[3][2]= mat[0][3]= mat[1][3]= mat[2][3]= 0.0f;
+ mat[3][3]= 1.0f;
+}
+
+/* returns two euler calculation methods, so we can pick the best */
+static void mat3_to_eul2(float tmat[][3], float *eul1, float *eul2)
+{
+ float cy, quat[4], mat[3][3];
+
+ Mat3ToQuat(tmat, quat);
+ QuatToMat3(quat, mat);
+ Mat3CpyMat3(mat, tmat);
+ Mat3Ortho(mat);
+
+ cy = (float)sqrt(mat[0][0]*mat[0][0] + mat[0][1]*mat[0][1]);
+
+ if (cy > 16.0*FLT_EPSILON) {
+
+ eul1[0] = (float)atan2(mat[1][2], mat[2][2]);
+ eul1[1] = (float)atan2(-mat[0][2], cy);
+ eul1[2] = (float)atan2(mat[0][1], mat[0][0]);
+
+ eul2[0] = (float)atan2(-mat[1][2], -mat[2][2]);
+ eul2[1] = (float)atan2(-mat[0][2], -cy);
+ eul2[2] = (float)atan2(-mat[0][1], -mat[0][0]);
+
+ } else {
+ eul1[0] = (float)atan2(-mat[2][1], mat[1][1]);
+ eul1[1] = (float)atan2(-mat[0][2], cy);
+ eul1[2] = 0.0f;
+
+ VecCopyf(eul2, eul1);
+ }
+}
+
+void Mat3ToEul(float tmat[][3], float *eul)
+{
+ float eul1[3], eul2[3];
+
+ mat3_to_eul2(tmat, eul1, eul2);
+
+ /* return best, which is just the one with lowest values it in */
+ if( fabs(eul1[0])+fabs(eul1[1])+fabs(eul1[2]) > fabs(eul2[0])+fabs(eul2[1])+fabs(eul2[2])) {
+ VecCopyf(eul, eul2);
+ }
+ else {
+ VecCopyf(eul, eul1);
+ }
+}
+
+void Mat4ToEul(float tmat[][4], float *eul)
+{
+ float tempMat[3][3];
+
+ Mat3CpyMat4 (tempMat, tmat);
+ Mat3Ortho(tempMat);
+ Mat3ToEul(tempMat, eul);
+}
+
+void QuatToEul( float *quat, float *eul)
+{
+ float mat[3][3];
+
+ QuatToMat3(quat, mat);
+ Mat3ToEul(mat, eul);
+}
+
+
+void EulToQuat( float *eul, float *quat)
+{
+ float ti, tj, th, ci, cj, ch, si, sj, sh, cc, cs, sc, ss;
+
+ ti = eul[0]*0.5f; tj = eul[1]*0.5f; th = eul[2]*0.5f;
+ ci = (float)cos(ti); cj = (float)cos(tj); ch = (float)cos(th);
+ si = (float)sin(ti); sj = (float)sin(tj); sh = (float)sin(th);
+ cc = ci*ch; cs = ci*sh; sc = si*ch; ss = si*sh;
+
+ quat[0] = cj*cc + sj*ss;
+ quat[1] = cj*sc - sj*cs;
+ quat[2] = cj*ss + sj*cc;
+ quat[3] = cj*cs - sj*sc;
+}
+
+void VecRotToMat3( float *vec, float phi, float mat[][3])
+{
+ /* rotation of phi radials around vec */
+ float vx, vx2, vy, vy2, vz, vz2, co, si;
+
+ vx= vec[0];
+ vy= vec[1];
+ vz= vec[2];
+ vx2= vx*vx;
+ vy2= vy*vy;
+ vz2= vz*vz;
+ co= (float)cos(phi);
+ si= (float)sin(phi);
+
+ mat[0][0]= vx2+co*(1.0f-vx2);
+ mat[0][1]= vx*vy*(1.0f-co)+vz*si;
+ mat[0][2]= vz*vx*(1.0f-co)-vy*si;
+ mat[1][0]= vx*vy*(1.0f-co)-vz*si;
+ mat[1][1]= vy2+co*(1.0f-vy2);
+ mat[1][2]= vy*vz*(1.0f-co)+vx*si;
+ mat[2][0]= vz*vx*(1.0f-co)+vy*si;
+ mat[2][1]= vy*vz*(1.0f-co)-vx*si;
+ mat[2][2]= vz2+co*(1.0f-vz2);
+
+}
+
+void VecRotToMat4( float *vec, float phi, float mat[][4])
+{
+ float tmat[3][3];
+
+ VecRotToMat3(vec, phi, tmat);
+ Mat4One(mat);
+ Mat4CpyMat3(mat, tmat);
+}
+
+void VecRotToQuat( float *vec, float phi, float *quat)
+{
+ /* rotation of phi radials around vec */
+ float si;
+
+ quat[1]= vec[0];
+ quat[2]= vec[1];
+ quat[3]= vec[2];
+
+ if( Normalize(quat+1) == 0.0) {
+ QuatOne(quat);
+ }
+ else {
+ quat[0]= (float)cos( phi/2.0 );
+ si= (float)sin( phi/2.0 );
+ quat[1] *= si;
+ quat[2] *= si;
+ quat[3] *= si;
+ }
+}
+
+/* Return the angle in degrees between vecs 1-2 and 2-3 in degrees
+ If v1 is a shoulder, v2 is the elbow and v3 is the hand,
+ this would return the angle at the elbow */
+float VecAngle3(float *v1, float *v2, float *v3)
+{
+ float vec1[3], vec2[3];
+
+ VecSubf(vec1, v2, v1);
+ VecSubf(vec2, v2, v3);
+ Normalize(vec1);
+ Normalize(vec2);
+
+ return NormalizedVecAngle2(vec1, vec2) * 180.0/M_PI;
+}
+
+/* Return the shortest angle in degrees between the 2 vectors */
+float VecAngle2(float *v1, float *v2)
+{
+ float vec1[3], vec2[3];
+
+ VecCopyf(vec1, v1);
+ VecCopyf(vec2, v2);
+ Normalize(vec1);
+ Normalize(vec2);
+
+ return NormalizedVecAngle2(vec1, vec2)* 180.0/M_PI;
+}
+
+float NormalizedVecAngle2(float *v1, float *v2)
+{
+ /* this is the same as acos(Inpf(v1, v2)), but more accurate */
+ if (Inpf(v1, v2) < 0.0f) {
+ float vec[3];
+
+ vec[0]= -v2[0];
+ vec[1]= -v2[1];
+ vec[2]= -v2[2];
+
+ return (float)M_PI - 2.0f*saasin(VecLenf(vec, v1)/2.0f);
+ }
+ else
+ return 2.0f*saasin(VecLenf(v2, v1)/2.0);
+}
+
+void euler_rot(float *beul, float ang, char axis)
+{
+ float eul[3], mat1[3][3], mat2[3][3], totmat[3][3];
+
+ eul[0]= eul[1]= eul[2]= 0.0;
+ if(axis=='x') eul[0]= ang;
+ else if(axis=='y') eul[1]= ang;
+ else eul[2]= ang;
+
+ EulToMat3(eul, mat1);
+ EulToMat3(beul, mat2);
+
+ Mat3MulMat3(totmat, mat2, mat1);
+
+ Mat3ToEul(totmat, beul);
+
+}
+
+/* exported to transform.c */
+void compatible_eul(float *eul, float *oldrot)
+{
+ float dx, dy, dz;
+
+ /* correct differences of about 360 degrees first */
+
+ dx= eul[0] - oldrot[0];
+ dy= eul[1] - oldrot[1];
+ dz= eul[2] - oldrot[2];
+
+ while( fabs(dx) > 5.1) {
+ if(dx > 0.0) eul[0] -= 2.0*M_PI; else eul[0]+= 2.0*M_PI;
+ dx= eul[0] - oldrot[0];
+ }
+ while( fabs(dy) > 5.1) {
+ if(dy > 0.0) eul[1] -= 2.0*M_PI; else eul[1]+= 2.0*M_PI;
+ dy= eul[1] - oldrot[1];
+ }
+ while( fabs(dz) > 5.1 ) {
+ if(dz > 0.0) eul[2] -= 2.0*M_PI; else eul[2]+= 2.0*M_PI;
+ dz= eul[2] - oldrot[2];
+ }
+
+ /* is 1 of the axis rotations larger than 180 degrees and the other small? NO ELSE IF!! */
+ if( fabs(dx) > 3.2 && fabs(dy)<1.6 && fabs(dz)<1.6 ) {
+ if(dx > 0.0) eul[0] -= 2.0*M_PI; else eul[0]+= 2.0*M_PI;
+ }
+ if( fabs(dy) > 3.2 && fabs(dz)<1.6 && fabs(dx)<1.6 ) {
+ if(dy > 0.0) eul[1] -= 2.0*M_PI; else eul[1]+= 2.0*M_PI;
+ }
+ if( fabs(dz) > 3.2 && fabs(dx)<1.6 && fabs(dy)<1.6 ) {
+ if(dz > 0.0) eul[2] -= 2.0*M_PI; else eul[2]+= 2.0*M_PI;
+ }
+
+ /* the method below was there from ancient days... but why! probably because the code sucks :)
+ */
+#if 0
+ /* calc again */
+ dx= eul[0] - oldrot[0];
+ dy= eul[1] - oldrot[1];
+ dz= eul[2] - oldrot[2];
+
+ /* special case, tested for x-z */
+
+ if( (fabs(dx) > 3.1 && fabs(dz) > 1.5 ) || ( fabs(dx) > 1.5 && fabs(dz) > 3.1 ) ) {
+ if(dx > 0.0) eul[0] -= M_PI; else eul[0]+= M_PI;
+ if(eul[1] > 0.0) eul[1]= M_PI - eul[1]; else eul[1]= -M_PI - eul[1];
+ if(dz > 0.0) eul[2] -= M_PI; else eul[2]+= M_PI;
+
+ }
+ else if( (fabs(dx) > 3.1 && fabs(dy) > 1.5 ) || ( fabs(dx) > 1.5 && fabs(dy) > 3.1 ) ) {
+ if(dx > 0.0) eul[0] -= M_PI; else eul[0]+= M_PI;
+ if(dy > 0.0) eul[1] -= M_PI; else eul[1]+= M_PI;
+ if(eul[2] > 0.0) eul[2]= M_PI - eul[2]; else eul[2]= -M_PI - eul[2];
+ }
+ else if( (fabs(dy) > 3.1 && fabs(dz) > 1.5 ) || ( fabs(dy) > 1.5 && fabs(dz) > 3.1 ) ) {
+ if(eul[0] > 0.0) eul[0]= M_PI - eul[0]; else eul[0]= -M_PI - eul[0];
+ if(dy > 0.0) eul[1] -= M_PI; else eul[1]+= M_PI;
+ if(dz > 0.0) eul[2] -= M_PI; else eul[2]+= M_PI;
+ }
+#endif
+}
+
+/* uses 2 methods to retrieve eulers, and picks the closest */
+void Mat3ToCompatibleEul(float mat[][3], float *eul, float *oldrot)
+{
+ float eul1[3], eul2[3];
+ float d1, d2;
+
+ mat3_to_eul2(mat, eul1, eul2);
+
+ compatible_eul(eul1, oldrot);
+ compatible_eul(eul2, oldrot);
+
+ d1= fabs(eul1[0]-oldrot[0]) + fabs(eul1[1]-oldrot[1]) + fabs(eul1[2]-oldrot[2]);
+ d2= fabs(eul2[0]-oldrot[0]) + fabs(eul2[1]-oldrot[1]) + fabs(eul2[2]-oldrot[2]);
+
+ /* return best, which is just the one with lowest difference */
+ if( d1 > d2) {
+ VecCopyf(eul, eul2);
+ }
+ else {
+ VecCopyf(eul, eul1);
+ }
+
+}
+
+/* ******************************************** */
+
+void SizeToMat3( float *size, float mat[][3])
+{
+ mat[0][0]= size[0];
+ mat[0][1]= 0.0;
+ mat[0][2]= 0.0;
+ mat[1][1]= size[1];
+ mat[1][0]= 0.0;
+ mat[1][2]= 0.0;
+ mat[2][2]= size[2];
+ mat[2][1]= 0.0;
+ mat[2][0]= 0.0;
+}
+
+void SizeToMat4( float *size, float mat[][4])
+{
+ float tmat[3][3];
+
+ SizeToMat3(size, tmat);
+ Mat4One(mat);
+ Mat4CpyMat3(mat, tmat);
+}
+
+void Mat3ToSize( float mat[][3], float *size)
+{
+ size[0]= VecLength(mat[0]);
+ size[1]= VecLength(mat[1]);
+ size[2]= VecLength(mat[2]);
+}
+
+void Mat4ToSize( float mat[][4], float *size)
+{
+ size[0]= VecLength(mat[0]);
+ size[1]= VecLength(mat[1]);
+ size[2]= VecLength(mat[2]);
+}
+
+/* this gets the average scale of a matrix, only use when your scaling
+ * data that has no idea of scale axis, examples are bone-envelope-radius
+ * and curve radius */
+float Mat3ToScalef(float mat[][3])
+{
+ /* unit length vector */
+ float unit_vec[3] = {0.577350269189626, 0.577350269189626, 0.577350269189626};
+ Mat3MulVecfl(mat, unit_vec);
+ return VecLength(unit_vec);
+}
+
+float Mat4ToScalef(float mat[][4])
+{
+ float tmat[3][3];
+ Mat3CpyMat4(tmat, mat);
+ return Mat3ToScalef(tmat);
+}
+
+
+/* ************* SPECIALS ******************* */
+
+void triatoquat( float *v1, float *v2, float *v3, float *quat)
+{
+ /* imaginary x-axis, y-axis triangle is being rotated */
+ float vec[3], q1[4], q2[4], n[3], si, co, angle, mat[3][3], imat[3][3];
+
+ /* move z-axis to face-normal */
+ CalcNormFloat(v1, v2, v3, vec);
+
+ n[0]= vec[1];
+ n[1]= -vec[0];
+ n[2]= 0.0;
+ Normalize(n);
+
+ if(n[0]==0.0 && n[1]==0.0) n[0]= 1.0;
+
+ angle= -0.5f*saacos(vec[2]);
+ co= (float)cos(angle);
+ si= (float)sin(angle);
+ q1[0]= co;
+ q1[1]= n[0]*si;
+ q1[2]= n[1]*si;
+ q1[3]= 0.0f;
+
+ /* rotate back line v1-v2 */
+ QuatToMat3(q1, mat);
+ Mat3Inv(imat, mat);
+ VecSubf(vec, v2, v1);
+ Mat3MulVecfl(imat, vec);
+
+ /* what angle has this line with x-axis? */
+ vec[2]= 0.0;
+ Normalize(vec);
+
+ angle= (float)(0.5*atan2(vec[1], vec[0]));
+ co= (float)cos(angle);
+ si= (float)sin(angle);
+ q2[0]= co;
+ q2[1]= 0.0f;
+ q2[2]= 0.0f;
+ q2[3]= si;
+
+ QuatMul(quat, q1, q2);
+}
+
+void MinMaxRGB(short c[])
+{
+ if(c[0]>255) c[0]=255;
+ else if(c[0]<0) c[0]=0;
+ if(c[1]>255) c[1]=255;
+ else if(c[1]<0) c[1]=0;
+ if(c[2]>255) c[2]=255;
+ else if(c[2]<0) c[2]=0;
+}
+
+float Vec2Lenf(float *v1, float *v2)
+{
+ float x, y;
+
+ x = v1[0]-v2[0];
+ y = v1[1]-v2[1];
+ return (float)sqrt(x*x+y*y);
+}
+
+void Vec2Mulf(float *v1, float f)
+{
+ v1[0]*= f;
+ v1[1]*= f;
+}
+
+void Vec2Addf(float *v, float *v1, float *v2)
+{
+ v[0]= v1[0]+ v2[0];
+ v[1]= v1[1]+ v2[1];
+}
+
+void Vec2Subf(float *v, float *v1, float *v2)
+{
+ v[0]= v1[0]- v2[0];
+ v[1]= v1[1]- v2[1];
+}
+
+void Vec2Copyf(float *v1, float *v2)
+{
+ v1[0]= v2[0];
+ v1[1]= v2[1];
+}
+
+float Inp2f(float *v1, float *v2)
+{
+ return v1[0]*v2[0]+v1[1]*v2[1];
+}
+
+float Normalize2(float *n)
+{
+ float d;
+
+ d= n[0]*n[0]+n[1]*n[1];
+
+ if(d>1.0e-35F) {
+ d= (float)sqrt(d);
+
+ n[0]/=d;
+ n[1]/=d;
+ } else {
+ n[0]=n[1]= 0.0;
+ d= 0.0;
+ }
+ return d;
+}
+
+void hsv_to_rgb(float h, float s, float v, float *r, float *g, float *b)
+{
+ int i;
+ float f, p, q, t;
+
+ h *= 360.0f;
+
+ if(s==0.0) {
+ *r = v;
+ *g = v;
+ *b = v;
+ }
+ else {
+ if(h==360) h = 0;
+
+ h /= 60;
+ i = (int)floor(h);
+ f = h - i;
+ p = v*(1.0f-s);
+ q = v*(1.0f-(s*f));
+ t = v*(1.0f-(s*(1.0f-f)));
+
+ switch (i) {
+ case 0 :
+ *r = v;
+ *g = t;
+ *b = p;
+ break;
+ case 1 :
+ *r = q;
+ *g = v;
+ *b = p;
+ break;
+ case 2 :
+ *r = p;
+ *g = v;
+ *b = t;
+ break;
+ case 3 :
+ *r = p;
+ *g = q;
+ *b = v;
+ break;
+ case 4 :
+ *r = t;
+ *g = p;
+ *b = v;
+ break;
+ case 5 :
+ *r = v;
+ *g = p;
+ *b = q;
+ break;
+ }
+ }
+}
+
+void rgb_to_yuv(float r, float g, float b, float *ly, float *lu, float *lv)
+{
+ float y, u, v;
+ y= 0.299*r + 0.587*g + 0.114*b;
+ u=-0.147*r - 0.289*g + 0.436*b;
+ v= 0.615*r - 0.515*g - 0.100*b;
+
+ *ly=y;
+ *lu=u;
+ *lv=v;
+}
+
+void yuv_to_rgb(float y, float u, float v, float *lr, float *lg, float *lb)
+{
+ float r, g, b;
+ r=y+1.140*v;
+ g=y-0.394*u - 0.581*v;
+ b=y+2.032*u;
+
+ *lr=r;
+ *lg=g;
+ *lb=b;
+}
+
+void rgb_to_ycc(float r, float g, float b, float *ly, float *lcb, float *lcr)
+{
+ float sr,sg, sb;
+ float y, cr, cb;
+
+ sr=255.0*r;
+ sg=255.0*g;
+ sb=255.0*b;
+
+
+ y=(0.257*sr)+(0.504*sg)+(0.098*sb)+16.0;
+ cb=(-0.148*sr)-(0.291*sg)+(0.439*sb)+128.0;
+ cr=(0.439*sr)-(0.368*sg)-(0.071*sb)+128.0;
+
+ *ly=y;
+ *lcb=cb;
+ *lcr=cr;
+}
+
+void ycc_to_rgb(float y, float cb, float cr, float *lr, float *lg, float *lb)
+{
+ float r,g,b;
+
+ r=1.164*(y-16)+1.596*(cr-128);
+ g=1.164*(y-16)-0.813*(cr-128)-0.392*(cb-128);
+ b=1.164*(y-16)+2.017*(cb-128);
+
+ *lr=r/255.0;
+ *lg=g/255.0;
+ *lb=b/255.0;
+}
+
+void hex_to_rgb(char *hexcol, float *r, float *g, float *b)
+{
+ unsigned int ri, gi, bi;
+
+ if (hexcol[0] == '#') hexcol++;
+
+ if (sscanf(hexcol, "%02x%02x%02x", &ri, &gi, &bi)) {
+ *r = ri / 255.0;
+ *g = gi / 255.0;
+ *b = bi / 255.0;
+ }
+}
+
+void rgb_to_hsv(float r, float g, float b, float *lh, float *ls, float *lv)
+{
+ float h, s, v;
+ float cmax, cmin, cdelta;
+ float rc, gc, bc;
+
+ cmax = r;
+ cmin = r;
+ cmax = (g>cmax ? g:cmax);
+ cmin = (g<cmin ? g:cmin);
+ cmax = (b>cmax ? b:cmax);
+ cmin = (b<cmin ? b:cmin);
+
+ v = cmax; /* value */
+ if (cmax!=0.0)
+ s = (cmax - cmin)/cmax;
+ else {
+ s = 0.0;
+ h = 0.0;
+ }
+ if (s == 0.0)
+ h = -1.0;
+ else {
+ cdelta = cmax-cmin;
+ rc = (cmax-r)/cdelta;
+ gc = (cmax-g)/cdelta;
+ bc = (cmax-b)/cdelta;
+ if (r==cmax)
+ h = bc-gc;
+ else
+ if (g==cmax)
+ h = 2.0f+rc-bc;
+ else
+ h = 4.0f+gc-rc;
+ h = h*60.0f;
+ if (h<0.0f)
+ h += 360.0f;
+ }
+
+ *ls = s;
+ *lh = h/360.0f;
+ if( *lh < 0.0) *lh= 0.0;
+ *lv = v;
+}
+
+
+/* we define a 'cpack' here as a (3 byte color code) number that can be expressed like 0xFFAA66 or so.
+ for that reason it is sensitive for endianness... with this function it works correctly
+*/
+
+unsigned int hsv_to_cpack(float h, float s, float v)
+{
+ short r, g, b;
+ float rf, gf, bf;
+ unsigned int col;
+
+ hsv_to_rgb(h, s, v, &rf, &gf, &bf);
+
+ r= (short)(rf*255.0f);
+ g= (short)(gf*255.0f);
+ b= (short)(bf*255.0f);
+
+ col= ( r + (g*256) + (b*256*256) );
+ return col;
+}
+
+
+unsigned int rgb_to_cpack(float r, float g, float b)
+{
+ int ir, ig, ib;
+
+ ir= (int)floor(255.0*r);
+ if(ir<0) ir= 0; else if(ir>255) ir= 255;
+ ig= (int)floor(255.0*g);
+ if(ig<0) ig= 0; else if(ig>255) ig= 255;
+ ib= (int)floor(255.0*b);
+ if(ib<0) ib= 0; else if(ib>255) ib= 255;
+
+ return (ir+ (ig*256) + (ib*256*256));
+}
+
+void cpack_to_rgb(unsigned int col, float *r, float *g, float *b)
+{
+
+ *r= (float)((col)&0xFF);
+ *r /= 255.0f;
+
+ *g= (float)(((col)>>8)&0xFF);
+ *g /= 255.0f;
+
+ *b= (float)(((col)>>16)&0xFF);
+ *b /= 255.0f;
+}
+
+
+/* *************** PROJECTIONS ******************* */
+
+void tubemap(float x, float y, float z, float *u, float *v)
+{
+ float len;
+
+ *v = (z + 1.0) / 2.0;
+
+ len= sqrt(x*x+y*y);
+ if(len>0) {
+ *u = (1.0 - (atan2(x/len,y/len) / M_PI)) / 2.0;
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+void spheremap(float x, float y, float z, float *u, float *v)
+{
+ float len;
+
+ len= sqrt(x*x+y*y+z*z);
+ if(len>0.0) {
+
+ if(x==0.0 && y==0.0) *u= 0.0; /* othwise domain error */
+ else *u = (1.0 - atan2(x,y)/M_PI )/2.0;
+
+ z/=len;
+ *v = 1.0- saacos(z)/M_PI;
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* ***************** m1 = m2 ***************** */
+void cpy_m3_m3(float m1[][3], float m2[][3])
+{
+ memcpy(m1[0], m2[0], 9*sizeof(float));
+}
+
+/* ***************** m1 = m2 ***************** */
+void cpy_m4_m4(float m1[][4], float m2[][4])
+{
+ memcpy(m1[0], m2[0], 16*sizeof(float));
+}
+
+/* ***************** identity matrix ***************** */
+void ident_m4(float m[][4])
+{
+
+ m[0][0]= m[1][1]= m[2][2]= m[3][3]= 1.0;
+ m[0][1]= m[0][2]= m[0][3]= 0.0;
+ m[1][0]= m[1][2]= m[1][3]= 0.0;
+ m[2][0]= m[2][1]= m[2][3]= 0.0;
+ m[3][0]= m[3][1]= m[3][2]= 0.0;
+}
+
+
+/* ***************** m1 = m2 (pre) * m3 (post) ***************** */
+void mul_m3_m3m3(float m1[][3], float m2[][3], float m3[][3])
+{
+ float m[3][3];
+
+ m[0][0]= m2[0][0]*m3[0][0] + m2[1][0]*m3[0][1] + m2[2][0]*m3[0][2];
+ m[0][1]= m2[0][1]*m3[0][0] + m2[1][1]*m3[0][1] + m2[2][1]*m3[0][2];
+ m[0][2]= m2[0][2]*m3[0][0] + m2[1][2]*m3[0][1] + m2[2][2]*m3[0][2];
+
+ m[1][0]= m2[0][0]*m3[1][0] + m2[1][0]*m3[1][1] + m2[2][0]*m3[1][2];
+ m[1][1]= m2[0][1]*m3[1][0] + m2[1][1]*m3[1][1] + m2[2][1]*m3[1][2];
+ m[1][2]= m2[0][2]*m3[1][0] + m2[1][2]*m3[1][1] + m2[2][2]*m3[1][2];
+
+ m[2][0]= m2[0][0]*m3[2][0] + m2[1][0]*m3[2][1] + m2[2][0]*m3[2][2];
+ m[2][1]= m2[0][1]*m3[2][0] + m2[1][1]*m3[2][1] + m2[2][1]*m3[2][2];
+ m[2][2]= m2[0][2]*m3[2][0] + m2[1][2]*m3[2][1] + m2[2][2]*m3[2][2];
+
+ cpy_m3_m3(m1, m2);
+}
+
+/* ***************** m1 = m2 (pre) * m3 (post) ***************** */
+void mul_m4_m4m4(float m1[][4], float m2[][4], float m3[][4])
+{
+ float m[4][4];
+
+ m[0][0]= m2[0][0]*m3[0][0] + m2[1][0]*m3[0][1] + m2[2][0]*m3[0][2] + m2[3][0]*m3[0][3];
+ m[0][1]= m2[0][1]*m3[0][0] + m2[1][1]*m3[0][1] + m2[2][1]*m3[0][2] + m2[3][1]*m3[0][3];
+ m[0][2]= m2[0][2]*m3[0][0] + m2[1][2]*m3[0][1] + m2[2][2]*m3[0][2] + m2[3][2]*m3[0][3];
+ m[0][3]= m2[0][3]*m3[0][0] + m2[1][3]*m3[0][1] + m2[2][3]*m3[0][2] + m2[3][3]*m3[0][3];
+
+ m[1][0]= m2[0][0]*m3[1][0] + m2[1][0]*m3[1][1] + m2[2][0]*m3[1][2] + m2[3][0]*m3[1][3];
+ m[1][1]= m2[0][1]*m3[1][0] + m2[1][1]*m3[1][1] + m2[2][1]*m3[1][2] + m2[3][1]*m3[1][3];
+ m[1][2]= m2[0][2]*m3[1][0] + m2[1][2]*m3[1][1] + m2[2][2]*m3[1][2] + m2[3][2]*m3[1][3];
+ m[1][3]= m2[0][3]*m3[1][0] + m2[1][3]*m3[1][1] + m2[2][3]*m3[1][2] + m2[3][3]*m3[1][3];
+
+ m[2][0]= m2[0][0]*m3[2][0] + m2[1][0]*m3[2][1] + m2[2][0]*m3[2][2] + m2[3][0]*m3[2][3];
+ m[2][1]= m2[0][1]*m3[2][0] + m2[1][1]*m3[2][1] + m2[2][1]*m3[2][2] + m2[3][1]*m3[2][3];
+ m[2][2]= m2[0][2]*m3[2][0] + m2[1][2]*m3[2][1] + m2[2][2]*m3[2][2] + m2[3][2]*m3[2][3];
+ m[2][3]= m2[0][3]*m3[2][0] + m2[1][3]*m3[2][1] + m2[2][3]*m3[2][2] + m2[3][3]*m3[2][3];
+
+ m[3][0]= m2[0][0]*m3[3][0] + m2[1][0]*m3[3][1] + m2[2][0]*m3[3][2] + m2[3][0]*m3[3][3];
+ m[3][1]= m2[0][1]*m3[3][0] + m2[1][1]*m3[3][1] + m2[2][1]*m3[3][2] + m2[3][1]*m3[3][3];
+ m[3][2]= m2[0][2]*m3[3][0] + m2[1][2]*m3[3][1] + m2[2][2]*m3[3][2] + m2[3][2]*m3[3][3];
+ m[3][3]= m2[0][3]*m3[3][0] + m2[1][3]*m3[3][1] + m2[2][3]*m3[3][2] + m2[3][3]*m3[3][3];
+
+ cpy_m4_m4(m1, m2);
+}
+
+/* ***************** m1 = inverse(m2) ***************** */
+void inv_m3_m3(float m1[][3], float m2[][3])
+{
+ short a,b;
+ float det;
+
+ /* calc adjoint */
+ Mat3Adj(m1, m2);
+
+ /* then determinant old matrix! */
+ det= m2[0][0]* (m2[1][1]*m2[2][2] - m2[1][2]*m2[2][1])
+ -m2[1][0]* (m2[0][1]*m2[2][2] - m2[0][2]*m2[2][1])
+ +m2[2][0]* (m2[0][1]*m2[1][2] - m2[0][2]*m2[1][1]);
+
+ if(det==0.0f) det=1.0f;
+ det= 1.0f/det;
+ for(a=0;a<3;a++) {
+ for(b=0;b<3;b++) {
+ m1[a][b]*=det;
+ }
+ }
+}
+
+/* ***************** m1 = inverse(m2) ***************** */
+int inv_m4_m4(float inverse[][4], float mat[][4])
+{
+ int i, j, k;
+ double temp;
+ float tempmat[4][4];
+ float max;
+ int maxj;
+
+ /* Set inverse to identity */
+ ident_m4(inverse);
+
+ /* Copy original matrix so we don't mess it up */
+ cpy_m4_m4(tempmat, mat);
+
+ for(i = 0; i < 4; i++) {
+ /* Look for row with max pivot */
+ max = ABS(tempmat[i][i]);
+ maxj = i;
+ for(j = i + 1; j < 4; j++) {
+ if(ABS(tempmat[j][i]) > max) {
+ max = ABS(tempmat[j][i]);
+ maxj = j;
+ }
+ }
+ /* Swap rows if necessary */
+ if (maxj != i) {
+ for( k = 0; k < 4; k++) {
+ SWAP(float, tempmat[i][k], tempmat[maxj][k]);
+ SWAP(float, inverse[i][k], inverse[maxj][k]);
+ }
+ }
+
+ temp = tempmat[i][i];
+ if (temp == 0)
+ return 0; /* No non-zero pivot */
+ for(k = 0; k < 4; k++) {
+ tempmat[i][k] = (float)(tempmat[i][k]/temp);
+ inverse[i][k] = (float)(inverse[i][k]/temp);
+ }
+ for(j = 0; j < 4; j++) {
+ if(j != i) {
+ temp = tempmat[j][i];
+ for(k = 0; k < 4; k++) {
+ tempmat[j][k] -= (float)(tempmat[i][k]*temp);
+ inverse[j][k] -= (float)(inverse[i][k]*temp);
+ }
+ }
+ }
+ }
+ return 1;
+}
+
+/* ***************** v1 = v2 * mat ***************** */
+void mul_v3_v3m4(float *v1, float *v2, float mat[][4])
+{
+ float x, y;
+
+ x= v2[0]; /* work with a copy, v1 can be same as v2 */
+ y= v2[1];
+ v1[0]= x*mat[0][0] + y*mat[1][0] + mat[2][0]*v2[2] + mat[3][0];
+ v1[1]= x*mat[0][1] + y*mat[1][1] + mat[2][1]*v2[2] + mat[3][1];
+ v1[2]= x*mat[0][2] + y*mat[1][2] + mat[2][2]*v2[2] + mat[3][2];
+
+}
+
+/* moved from effect.c
+ test if the line starting at p1 ending at p2 intersects the triangle v0..v2
+ return non zero if it does
+*/
+int LineIntersectsTriangle(float p1[3], float p2[3], float v0[3], float v1[3], float v2[3], float *lambda)
+{
+
+ float p[3], s[3], d[3], e1[3], e2[3], q[3];
+ float a, f, u, v;
+
+ VecSubf(e1, v1, v0);
+ VecSubf(e2, v2, v0);
+ VecSubf(d, p2, p1);
+
+ Crossf(p, d, e2);
+ a = Inpf(e1, p);
+ if ((a > -0.000001) && (a < 0.000001)) return 0;
+ f = 1.0f/a;
+
+ VecSubf(s, p1, v0);
+
+ Crossf(q, s, e1);
+ *lambda = f * Inpf(e2, q);
+ if ((*lambda < 0.0)||(*lambda > 1.0)) return 0;
+
+ u = f * Inpf(s, p);
+ if ((u < 0.0)||(u > 1.0)) return 0;
+
+ v = f * Inpf(d, q);
+ if ((v < 0.0)||((u + v) > 1.0)) return 0;
+
+ return 1;
+}
+
+
+/*
+find closest point to p on line through l1,l2
+and return lambda, where (0 <= lambda <= 1) when cp is in the line segement l1,l2
+*/
+float lambda_cp_line_ex(float p[3], float l1[3], float l2[3], float cp[3])
+{
+ float h[3],u[3],lambda;
+ VecSubf(u, l2, l1);
+ VecSubf(h, p, l1);
+ lambda =Inpf(u,h)/Inpf(u,u);
+ cp[0] = l1[0] + u[0] * lambda;
+ cp[1] = l1[1] + u[1] * lambda;
+ cp[2] = l1[2] + u[2] * lambda;
+ return lambda;
+}
+/* little sister we only need to know lambda */
+float lambda_cp_line(float p[3], float l1[3], float l2[3])
+{
+ float h[3],u[3];
+ VecSubf(u, l2, l1);
+ VecSubf(h, p, l1);
+ return(Inpf(u,h)/Inpf(u,u));
+}
+
+
+
+int point_in_slice(float p[3], float v1[3], float l1[3], float l2[3])
+{
+/*
+what is a slice ?
+some maths:
+a line including l1,l2 and a point not on the line
+define a subset of R3 delimeted by planes parallel to the line and orthogonal
+to the (point --> line) distance vector,one plane on the line one on the point,
+the room inside usually is rather small compared to R3 though still infinte
+useful for restricting (speeding up) searches
+e.g. all points of triangular prism are within the intersection of 3 'slices'
+onother trivial case : cube
+but see a 'spat' which is a deformed cube with paired parallel planes needs only 3 slices too
+*/
+ float h,rp[3],cp[3],q[3];
+
+ lambda_cp_line_ex(v1,l1,l2,cp);
+ VecSubf(q,cp,v1);
+
+ VecSubf(rp,p,v1);
+ h=Inpf(q,rp)/Inpf(q,q);
+ if (h < 0.0f || h > 1.0f) return 0;
+ return 1;
+}
+
+/*adult sister defining the slice planes by the origin and the normal
+NOTE |normal| may not be 1 but defining the thickness of the slice*/
+int point_in_slice_as(float p[3],float origin[3],float normal[3])
+{
+ float h,rp[3];
+ VecSubf(rp,p,origin);
+ h=Inpf(normal,rp)/Inpf(normal,normal);
+ if (h < 0.0f || h > 1.0f) return 0;
+ return 1;
+}
+
+/*mama (knowing the squared lenght of the normal)*/
+int point_in_slice_m(float p[3],float origin[3],float normal[3],float lns)
+{
+ float h,rp[3];
+ VecSubf(rp,p,origin);
+ h=Inpf(normal,rp)/lns;
+ if (h < 0.0f || h > 1.0f) return 0;
+ return 1;
+}
+
+
+int point_in_tri_prism(float p[3], float v1[3], float v2[3], float v3[3])
+{
+ if(!point_in_slice(p,v1,v2,v3)) return 0;
+ if(!point_in_slice(p,v2,v3,v1)) return 0;
+ if(!point_in_slice(p,v3,v1,v2)) return 0;
+ return 1;
+}
+
+/* point closest to v1 on line v2-v3 in 3D */
+void PclosestVL3Dfl(float *closest, float *v1, float *v2, float *v3)
+{
+ float lambda, cp[3];
+
+ lambda= lambda_cp_line_ex(v1, v2, v3, cp);
+
+ if(lambda <= 0.0f)
+ VecCopyf(closest, v2);
+ else if(lambda >= 1.0f)
+ VecCopyf(closest, v3);
+ else
+ VecCopyf(closest, cp);
+}
+
+/* distance v1 to line-piece v2-v3 in 3D */
+float PdistVL3Dfl(float *v1, float *v2, float *v3)
+{
+ float closest[3];
+
+ PclosestVL3Dfl(closest, v1, v2, v3);
+
+ return VecLenf(closest, v1);
+}
+
+/********************************************************/
+
+/* make a 4x4 matrix out of 3 transform components */
+/* matrices are made in the order: scale * rot * loc */
+void LocEulSizeToMat4(float mat[][4], float loc[3], float eul[3], float size[3])
+{
+ float rmat[3][3], smat[3][3], tmat[3][3];
+
+ /* initialise new matrix */
+ Mat4One(mat);
+
+ /* make rotation + scaling part */
+ EulToMat3(eul, rmat);
+ SizeToMat3(size, smat);
+ Mat3MulMat3(tmat, rmat, smat);
+
+ /* copy rot/scale part to output matrix*/
+ Mat4CpyMat3(mat, tmat);
+
+ /* copy location to matrix */
+ mat[3][0] = loc[0];
+ mat[3][1] = loc[1];
+ mat[3][2] = loc[2];
+}
+
+/* make a 4x4 matrix out of 3 transform components */
+/* matrices are made in the order: scale * rot * loc */
+void LocQuatSizeToMat4(float mat[][4], float loc[3], float quat[4], float size[3])
+{
+ float rmat[3][3], smat[3][3], tmat[3][3];
+
+ /* initialise new matrix */
+ Mat4One(mat);
+
+ /* make rotation + scaling part */
+ QuatToMat3(quat, rmat);
+ SizeToMat3(size, smat);
+ Mat3MulMat3(tmat, rmat, smat);
+
+ /* copy rot/scale part to output matrix*/
+ Mat4CpyMat3(mat, tmat);
+
+ /* copy location to matrix */
+ mat[3][0] = loc[0];
+ mat[3][1] = loc[1];
+ mat[3][2] = loc[2];
+}
diff --git a/source/blender/blenlib/intern/boxpack2d.c b/source/blender/blenlib/intern/boxpack2d.c
new file mode 100644
index 00000000000..42092bc54c3
--- /dev/null
+++ b/source/blender/blenlib/intern/boxpack2d.c
@@ -0,0 +1,416 @@
+/*
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Campbell barton
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+
+#include "BKE_utildefines.h"
+#include "MEM_guardedalloc.h"
+#include "BLI_boxpack2d.h"
+
+/* BoxPacker ported from Python by Campbell Barton
+ *
+ * The defined Below are for internal use only */
+
+/* free vert flags */
+#define eul 0.0000001
+#define BLF 1
+#define TRF 2
+#define TLF 4
+#define BRF 8
+#define BL 0
+#define TR 1
+#define TL 2
+#define BR 3
+
+#define BOXLEFT(b) b->v[BL]->x
+#define BOXRIGHT(b) b->v[TR]->x
+#define BOXBOTTOM(b) b->v[BL]->y
+#define BOXTOP(b) b->v[TR]->y
+#define BOXAREA(b) (b->w * b->h)
+
+#define UPDATE_V34X(b) b->v[TL]->x = b->v[BL]->x;\
+ b->v[BR]->x = b->v[TR]->x
+#define UPDATE_V34Y(b) b->v[TL]->y = b->v[TR]->y;\
+ b->v[BR]->y = b->v[BL]->y
+#define UPDATE_V34(b) UPDATE_V34X(b); UPDATE_V34Y(b)
+
+#define SET_BOXLEFT(b, f) b->v[TR]->x = f + b->w;\
+ b->v[BL]->x = f;\
+ UPDATE_V34X(b)
+#define SET_BOXRIGHT(b, f) b->v[BL]->x = f - b->w;\
+ b->v[TR]->x = f;\
+ UPDATE_V34X(b)
+#define SET_BOXBOTTOM(b, f) b->v[TR]->y = f + b->h;\
+ b->v[BL]->y = f;\
+ UPDATE_V34Y(b)
+#define SET_BOXTOP(b, f) b->v[BL]->y = f - b->h;\
+ b->v[TR]->y = f;\
+ UPDATE_V34Y(b)
+#define BOXINTERSECT(b1, b2)\
+ (!( BOXLEFT(b1)+eul>=BOXRIGHT(b2) ||\
+ BOXBOTTOM(b1)+eul>=BOXTOP(b2) ||\
+ BOXRIGHT(b1)-eul<=BOXLEFT(b2) ||\
+ BOXTOP(b1)-eul<=BOXBOTTOM(b2) ))
+
+/* #define BOXDEBUG(b)\
+ * printf("\tBox Debug i %i, w:%.3f h:%.3f x:%.3f y:%.3f\n",\
+ * b->index, b->w, b->h, b->x, b->y) */
+
+/* qsort function - sort largest to smallest */
+static int box_areasort(const void *p1, const void *p2)
+{
+ const boxPack *b1=p1, *b2=p2;
+ float a1, a2;
+
+ a1 = BOXAREA(b1);
+ a2 = BOXAREA(b2);
+
+ if ( a1 < a2 ) return 1;
+ else if ( a1 > a2 ) return -1;
+ return 0;
+}
+
+/* qsort vertex sorting function
+ * sorts from lower left to top right It uses the current box's width and height
+ * as offsets when sorting, this has the result of not placing boxes outside
+ * the bounds of the existing backed area where possible
+ * */
+static float box_width;
+static float box_height;
+static boxVert *vertarray;
+
+static int vertex_sort(const void *p1, const void *p2)
+{
+ boxVert *v1, *v2;
+ float a1, a2;
+
+ v1 = vertarray + ((int *) p1)[0];
+ v2 = vertarray + ((int *) p2)[0];
+
+ a1 = MAX2(v1->x+box_width, v1->y+box_height);
+ a2 = MAX2(v2->x+box_width, v2->y+box_height);
+
+ /* sort largest to smallest */
+ if ( a1 > a2 ) return 1;
+ else if ( a1 < a2 ) return -1;
+ return 0;
+}
+/* Main boxpacking function accessed from other functions
+ * This sets boxes x,y to positive values, sorting from 0,0 outwards.
+ * There is no limit to the space boxes may take, only that they will be packed
+ * tightly into the lower left hand corner (0,0)
+ *
+ * boxarray - a pre allocated array of boxes.
+ * only the 'box->x' and 'box->y' are set, 'box->w' and 'box->h' are used,
+ * 'box->index' is not used at all, the only reason its there
+ * is that the box array is sorted by area and programs need to be able
+ * to have some way of writing the boxes back to the original data.
+ * len - the number of boxes in teh array.
+ * tot_width and tot_height are set so you can normalize the data.
+ * */
+void boxPack2D(boxPack *boxarray, int len, float *tot_width, float *tot_height)
+{
+ boxVert *vert; /* the current vert */
+ int box_index, verts_pack_len, i, j, k, isect;
+ int quad_flags[4]= {BLF,TRF,TLF,BRF}; /* use for looping */
+ boxPack *box, *box_test; /*current box and another for intersection tests*/
+ int *vertex_pack_indicies; /*an array of indicies used for sorting verts*/
+
+ if (!len) {
+ *tot_width = 0.0;
+ *tot_height = 0.0;
+ return;
+ }
+
+ /* Sort boxes, biggest first */
+ qsort(boxarray, len, sizeof(boxPack), box_areasort);
+
+ /* add verts to the boxes, these are only used internally */
+ vert = vertarray = MEM_mallocN( len*4*sizeof(boxVert), "boxPack verts");
+ vertex_pack_indicies = MEM_mallocN( len*3*sizeof(int), "boxPack indicies");
+
+ for (box=boxarray, box_index=0, i=0; box_index < len; box_index++, box++) {
+
+ vert->blb = vert->brb = vert->tlb =\
+ vert->isect_cache[0] = vert->isect_cache[1] =\
+ vert->isect_cache[2] = vert->isect_cache[3] = NULL;
+ vert->free = 15 &~ TRF;
+ vert->trb = box;
+ vert->index = i; i++;
+ box->v[BL] = vert; vert++;
+
+ vert->trb= vert->brb = vert->tlb =\
+ vert->isect_cache[0] = vert->isect_cache[1] =\
+ vert->isect_cache[2] = vert->isect_cache[3] = NULL;
+ vert->free = 15 &~ BLF;
+ vert->blb = box;
+ vert->index = i; i++;
+ box->v[TR] = vert; vert++;
+
+ vert->trb = vert->blb = vert->tlb =\
+ vert->isect_cache[0] = vert->isect_cache[1] =\
+ vert->isect_cache[2] = vert->isect_cache[3] = NULL;
+ vert->free = 15 &~ BRF;
+ vert->brb = box;
+ vert->index = i; i++;
+ box->v[TL] = vert; vert++;
+
+ vert->trb = vert->blb = vert->brb =\
+ vert->isect_cache[0] = vert->isect_cache[1] =\
+ vert->isect_cache[2] = vert->isect_cache[3] = NULL;
+ vert->free = 15 &~ TLF;
+ vert->tlb = box;
+ vert->index = i; i++;
+ box->v[BR] = vert; vert++;
+ }
+ vert = NULL;
+
+
+ /* Pack the First box!
+ * then enter the main boxpacking loop */
+
+ box = boxarray; /* get the first box */
+ /* First time, no boxes packed */
+ box->v[BL]->free = 0; /* Cant use any if these */
+ box->v[BR]->free &= ~(BLF|BRF);
+ box->v[TL]->free &= ~(BLF|TLF);
+
+ *tot_width = box->w;
+ *tot_height = box->h;
+
+ /* This sets all the vertex locations */
+ SET_BOXLEFT(box, 0.0);
+ SET_BOXBOTTOM(box, 0.0);
+ box->x = box->y = 0.0;
+
+ for (i=0; i<3; i++)
+ vertex_pack_indicies[i] = box->v[i+1]->index;
+ verts_pack_len = 3;
+ box++; /* next box, needed for the loop below */
+ /* ...done packing the first box */
+
+ /* Main boxpacking loop */
+ for (box_index=1; box_index < len; box_index++, box++) {
+
+ /* Sort the verts, these constants are used in sorting */
+ box_width = box->w;
+ box_height = box->h;
+
+ qsort(vertex_pack_indicies, verts_pack_len, sizeof(int), vertex_sort);
+
+ /* Pack the box in with the others */
+ /* sort the verts */
+ isect = 1;
+
+ for (i=0; i<verts_pack_len && isect; i++) {
+ vert = vertarray + vertex_pack_indicies[i];
+ /* printf("\ttesting vert %i %i %i %f %f\n", i,
+ * vert->free, verts_pack_len, vert->x, vert->y); */
+
+ /* This vert has a free quaderent
+ * Test if we can place the box here
+ * vert->free & quad_flags[j] - Checks
+ * */
+
+ for (j=0; (j<4) && isect; j++) {
+ if (vert->free & quad_flags[j]) {
+ switch (j) {
+ case BL:
+ SET_BOXRIGHT(box, vert->x);
+ SET_BOXTOP(box, vert->y);
+ break;
+ case TR:
+ SET_BOXLEFT(box, vert->x);
+ SET_BOXBOTTOM(box, vert->y);
+ break;
+ case TL:
+ SET_BOXRIGHT(box, vert->x);
+ SET_BOXBOTTOM(box, vert->y);
+ break;
+ case BR:
+ SET_BOXLEFT(box, vert->x);
+ SET_BOXTOP(box, vert->y);
+ break;
+ }
+
+ /* Now we need to check that the box intersects
+ * with any other boxes
+ * Assume no intersection... */
+ isect = 0;
+
+ if (/* Constrain boxes to positive X/Y values */
+ BOXLEFT(box)<0.0 || BOXBOTTOM(box) < 0.0 ||
+ /* check for last intersected */
+ ( vert->isect_cache[j] &&
+ BOXINTERSECT(box, vert->isect_cache[j]) )
+ ) {
+ /* Here we check that the last intersected
+ * box will intersect with this one using
+ * isect_cache that can store a pointer to a
+ * box for each quaderent
+ * big speedup */
+ isect = 1;
+ } else {
+ /* do a full saech for colliding box
+ * this is realy slow, some spacialy divided
+ * datastructure would be better */
+ for (box_test=boxarray; box_test != box; box_test++) {
+ if BOXINTERSECT(box, box_test) {
+ /* Store the last intersecting here as cache
+ * for faster checking next time around */
+ vert->isect_cache[j] = box_test;
+ isect = 1;
+ break;
+ }
+ }
+ }
+
+ if (!isect) {
+
+ /* maintain the total width and height */
+ (*tot_width) = MAX2(BOXRIGHT(box), (*tot_width));
+ (*tot_height) = MAX2(BOXTOP(box), (*tot_height));
+
+ /* Place the box */
+ vert->free &= ~quad_flags[j];
+
+ switch (j) {
+ case TR:
+ box->v[BL]= vert;
+ vert->trb = box;
+ break;
+ case TL:
+ box->v[BR]= vert;
+ vert->tlb = box;
+ break;
+ case BR:
+ box->v[TL]= vert;
+ vert->brb = box;
+ break;
+ case BL:
+ box->v[TR]= vert;
+ vert->blb = box;
+ break;
+ }
+
+ /* Mask free flags for verts that are
+ * on the bottom or side so we dont get
+ * boxes outside the given rectangle ares
+ *
+ * We can do an else/if here because only the first
+ * box can be at the very bottom left corner */
+ if (BOXLEFT(box) <= 0) {
+ box->v[TL]->free &= ~(TLF|BLF);
+ box->v[BL]->free &= ~(TLF|BLF);
+ } else if (BOXBOTTOM(box) <= 0) {
+ box->v[BL]->free &= ~(BRF|BLF);
+ box->v[BR]->free &= ~(BRF|BLF);
+ }
+
+ /* The following block of code does a logical
+ * check with 2 adjacent boxes, its possible to
+ * flag verts on one or both of the boxes
+ * as being used by checking the width or
+ * height of both boxes */
+ if (vert->tlb && vert->trb &&
+ (box == vert->tlb || box == vert->trb)) {
+ if (vert->tlb->h > vert->trb->h) {
+ vert->trb->v[TL]->free &= ~(TLF|BLF);
+ } else if (vert->tlb->h < vert->trb->h) {
+ vert->tlb->v[TR]->free &= ~(TRF|BRF);
+ } else { /*same*/
+ vert->tlb->v[TR]->free &= ~BLF;
+ vert->trb->v[TL]->free &= ~BRF;
+ }
+ } else if (vert->blb && vert->brb &&
+ (box == vert->blb || box == vert->brb)) {
+ if (vert->blb->h > vert->brb->h) {
+ vert->brb->v[BL]->free &= ~(TLF|BLF);
+ } else if (vert->blb->h < vert->brb->h) {
+ vert->blb->v[BR]->free &= ~(TRF|BRF);
+ } else { /*same*/
+ vert->blb->v[BR]->free &= ~TRF;
+ vert->brb->v[BL]->free &= ~TLF;
+ }
+ }
+ /* Horizontal */
+ if (vert->tlb && vert->blb &&
+ (box == vert->tlb || box == vert->blb) ) {
+ if (vert->tlb->w > vert->blb->w) {
+ vert->blb->v[TL]->free &= ~(TLF|TRF);
+ } else if (vert->tlb->w < vert->blb->w) {
+ vert->tlb->v[BL]->free &= ~(BLF|BRF);
+ } else { /*same*/
+ vert->blb->v[TL]->free &= ~TRF;
+ vert->tlb->v[BL]->free &= ~BRF;
+ }
+ } else if ( vert->trb && vert->brb &&
+ (box == vert->trb || box == vert->brb) ) {
+ if (vert->trb->w > vert->brb->w) {
+ vert->brb->v[TR]->free &= ~(TRF|TRF);
+ } else if (vert->trb->w < vert->brb->w) {
+ vert->trb->v[BR]->free &= ~(BLF|BRF);
+ } else { /*same*/
+ vert->brb->v[TR]->free &= ~TLF;
+ vert->trb->v[BR]->free &= ~BLF;
+ }
+ }
+ /* End logical check */
+
+
+ for (k=0; k<4; k++) {
+ if (box->v[k] != vert) {
+ vertex_pack_indicies[verts_pack_len] =
+ box->v[k]->index;
+ verts_pack_len++;
+ }
+ }
+ /* The Box verts are only used interially
+ * Update the box x and y since thats what external
+ * functions will see */
+ box->x = BOXLEFT(box);
+ box->y = BOXBOTTOM(box);
+ }
+ }
+ }
+ }
+ }
+
+ /* free all the verts, not realy needed because they shouldebt be
+ * touched anymore but accessing the pointers woud crash blender */
+ for (box_index=0; box_index < len; box_index++) {
+ box = boxarray+box_index;
+ box->v[0] = box->v[1] = box->v[2] = box->v[3] = NULL;
+ }
+ MEM_freeN(vertex_pack_indicies);
+ MEM_freeN(vertarray);
+}
+
diff --git a/source/blender/blenlib/intern/dynlib.c b/source/blender/blenlib/intern/dynlib.c
new file mode 100644
index 00000000000..c455ba664ce
--- /dev/null
+++ b/source/blender/blenlib/intern/dynlib.c
@@ -0,0 +1,343 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file, with exception of below:
+ *
+ * Contributor(s): Peter O'Gorman
+ * The functions osxdlopen() and osxerror()
+ * are Copyright (c) 2002 Peter O'Gorman <ogorman@users.sourceforge.net>
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "../PIL_dynlib.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if !defined(CHAR_MAX)
+#define CHAR_MAX 255
+#endif
+
+/*
+ * XXX, should use mallocN so we can see
+ * handle's not being released. fixme zr
+ */
+
+#ifdef WIN32
+
+#include <windows.h>
+
+struct PILdynlib {
+ void *handle;
+};
+
+PILdynlib *PIL_dynlib_open(char *name) {
+ void *handle= LoadLibrary(name);
+
+ if (handle) {
+ PILdynlib *lib= malloc(sizeof(*lib));
+ lib->handle= handle;
+
+ return lib;
+ } else {
+ return NULL;
+ }
+}
+
+void *PIL_dynlib_find_symbol(PILdynlib* lib, char *symname) {
+ return GetProcAddress(lib->handle, symname);
+}
+
+char *PIL_dynlib_get_error_as_string(PILdynlib* lib) {
+ int err;
+
+ /* if lib is NULL reset the last error code */
+ if (!lib) {
+ SetLastError(ERROR_SUCCESS);
+ return NULL;
+ }
+
+ err= GetLastError();
+ if (err) {
+ static char buf[1024];
+
+ if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ err,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ buf,
+ sizeof(buf),
+ NULL))
+ return buf;
+ }
+
+ return NULL;
+}
+
+void PIL_dynlib_close(PILdynlib *lib) {
+ FreeLibrary(lib->handle);
+
+ free(lib);
+}
+
+#else
+#ifdef __APPLE__ /* MacOS X */
+
+#include <mach-o/dyld.h>
+#include <dlfcn.h>
+#include <stdarg.h>
+
+#define ERR_STR_LEN 256
+
+struct PILdynlib {
+ void *handle;
+};
+
+static char *osxerror(int setget, const char *str, ...)
+{
+ static char errstr[ERR_STR_LEN];
+ static int err_filled = 0;
+ char *retval;
+ NSLinkEditErrors ler;
+ int lerno;
+ const char *dylderrstr;
+ const char *file;
+ va_list arg;
+ if (setget <= 0)
+ {
+ va_start(arg, str);
+ strncpy(errstr, "dlsimple: ", ERR_STR_LEN);
+ vsnprintf(errstr + 10, ERR_STR_LEN - 10, str, arg);
+ va_end(arg);
+ /* We prefer to use the dyld error string if setget is 0 */
+ if (setget == 0) {
+ NSLinkEditError(&ler, &lerno, &file, &dylderrstr);
+// printf("dyld: %s\n",dylderrstr);
+ if (dylderrstr && strlen(dylderrstr))
+ strncpy(errstr,dylderrstr,ERR_STR_LEN);
+ }
+ err_filled = 1;
+ retval = NULL;
+ }
+ else
+ {
+ if (!err_filled)
+ retval = NULL;
+ else
+ retval = errstr;
+ err_filled = 0;
+ }
+ return retval;
+}
+
+static void *osxdlopen(const char *path, int mode)
+{
+ void *module = 0;
+ NSObjectFileImage ofi = 0;
+ NSObjectFileImageReturnCode ofirc;
+ static int (*make_private_module_public) (NSModule module) = 0;
+ unsigned int flags = NSLINKMODULE_OPTION_RETURN_ON_ERROR | NSLINKMODULE_OPTION_PRIVATE;
+
+ /* If we got no path, the app wants the global namespace, use -1 as the marker
+ in this case */
+ if (!path)
+ return (void *)-1;
+
+ /* Create the object file image, works for things linked with the -bundle arg to ld */
+ ofirc = NSCreateObjectFileImageFromFile(path, &ofi);
+ switch (ofirc)
+ {
+ case NSObjectFileImageSuccess:
+ /* It was okay, so use NSLinkModule to link in the image */
+ if (!(mode & RTLD_LAZY)) flags += NSLINKMODULE_OPTION_BINDNOW;
+ module = NSLinkModule(ofi, path,flags);
+ /* Don't forget to destroy the object file image, unless you like leaks */
+ NSDestroyObjectFileImage(ofi);
+ /* If the mode was global, then change the module, this avoids
+ multiply defined symbol errors to first load private then make
+ global. Silly, isn't it. */
+ if ((mode & RTLD_GLOBAL))
+ {
+ if (!make_private_module_public)
+ {
+ _dyld_func_lookup("__dyld_NSMakePrivateModulePublic",
+ (unsigned long *)&make_private_module_public);
+ }
+ make_private_module_public(module);
+ }
+ break;
+ case NSObjectFileImageInappropriateFile:
+ /* It may have been a dynamic library rather than a bundle, try to load it */
+ module = (void *)NSAddImage(path, NSADDIMAGE_OPTION_RETURN_ON_ERROR);
+ break;
+ case NSObjectFileImageFailure:
+ osxerror(0,"Object file setup failure : \"%s\"", path);
+ return 0;
+ case NSObjectFileImageArch:
+ osxerror(0,"No object for this architecture : \"%s\"", path);
+ return 0;
+ case NSObjectFileImageFormat:
+ osxerror(0,"Bad object file format : \"%s\"", path);
+ return 0;
+ case NSObjectFileImageAccess:
+ osxerror(0,"Can't read object file : \"%s\"", path);
+ return 0;
+ }
+ if (!module)
+ osxerror(0, "Can not open \"%s\"", path);
+ return module;
+}
+
+PILdynlib *PIL_dynlib_open(char *name) {
+ void *handle= osxdlopen(name, RTLD_LAZY);
+
+ if (handle) {
+ PILdynlib *lib= malloc(sizeof(*lib));
+ lib->handle= handle;
+
+ return lib;
+ } else {
+ return NULL;
+ }
+}
+
+void *PIL_dynlib_find_symbol(PILdynlib* lib, char *symname)
+{
+ int sym_len = strlen(symname);
+ void *value = NULL;
+ char *malloc_sym = NULL;
+ NSSymbol *nssym = 0;
+ malloc_sym = malloc(sym_len + 2);
+ if (malloc_sym)
+ {
+ sprintf(malloc_sym, "_%s", symname);
+ /* If the lib->handle is -1, if is the app global context */
+ if (lib->handle == (void *)-1)
+ {
+ /* Global context, use NSLookupAndBindSymbol */
+ if (NSIsSymbolNameDefined(malloc_sym))
+ {
+ nssym = NSLookupAndBindSymbol(malloc_sym);
+ }
+ }
+ /* Now see if the lib->handle is a struch mach_header* or not, use NSLookupSymbol in image
+ for libraries, and NSLookupSymbolInModule for bundles */
+ else
+ {
+ /* Check for both possible magic numbers depending on x86/ppc byte order */
+ if ((((struct mach_header *)lib->handle)->magic == MH_MAGIC) ||
+ (((struct mach_header *)lib->handle)->magic == MH_CIGAM))
+ {
+ if (NSIsSymbolNameDefinedInImage((struct mach_header *)lib->handle, malloc_sym))
+ {
+ nssym = NSLookupSymbolInImage((struct mach_header *)lib->handle,
+ malloc_sym,
+ NSLOOKUPSYMBOLINIMAGE_OPTION_BIND
+ | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
+ }
+
+ }
+ else
+ {
+ nssym = NSLookupSymbolInModule(lib->handle, malloc_sym);
+ }
+ }
+ if (!nssym)
+ {
+ osxerror(0, "symname \"%s\" Not found", symname);
+ }
+ value = NSAddressOfSymbol(nssym);
+ free(malloc_sym);
+ }
+ else
+ {
+ osxerror(-1, "Unable to allocate memory");
+ }
+ return value;
+}
+
+char *PIL_dynlib_get_error_as_string(PILdynlib* lib)
+{
+ return osxerror(1, (char *)NULL);
+}
+
+void PIL_dynlib_close(PILdynlib *lib)
+{
+ if ((((struct mach_header *)lib->handle)->magic == MH_MAGIC) ||
+ (((struct mach_header *)lib->handle)->magic == MH_CIGAM))
+ {
+ osxerror(-1, "Can't remove dynamic libraries on darwin");
+ }
+ if (!NSUnLinkModule(lib->handle, 0))
+ {
+ osxerror(0, "unable to unlink module %s", NSNameOfModule(lib->handle));
+ }
+
+ free(lib);
+}
+
+#else /* Unix */
+
+#include <dlfcn.h>
+
+struct PILdynlib {
+ void *handle;
+};
+
+PILdynlib *PIL_dynlib_open(char *name) {
+ void *handle= dlopen(name, RTLD_LAZY);
+
+ if (handle) {
+ PILdynlib *lib= malloc(sizeof(*lib));
+ lib->handle= handle;
+
+ return lib;
+ } else {
+ return NULL;
+ }
+}
+
+void *PIL_dynlib_find_symbol(PILdynlib* lib, char *symname) {
+ return dlsym(lib->handle, symname);
+}
+
+char *PIL_dynlib_get_error_as_string(PILdynlib* lib) {
+ return dlerror();
+}
+
+void PIL_dynlib_close(PILdynlib *lib) {
+ dlclose(lib->handle);
+
+ free(lib);
+}
+
+#endif
+#endif
diff --git a/source/blender/blenlib/intern/edgehash.c b/source/blender/blenlib/intern/edgehash.c
new file mode 100644
index 00000000000..8fae0f63746
--- /dev/null
+++ b/source/blender/blenlib/intern/edgehash.c
@@ -0,0 +1,220 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: none of this file.
+ *
+ * Contributor(s): Daniel Dunbar
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * A general (pointer -> pointer) hash table ADT
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+#include "BLI_edgehash.h"
+
+/***/
+
+static unsigned int hashsizes[]= {
+ 1, 3, 5, 11, 17, 37, 67, 131, 257, 521, 1031, 2053, 4099, 8209,
+ 16411, 32771, 65537, 131101, 262147, 524309, 1048583, 2097169,
+ 4194319, 8388617, 16777259, 33554467, 67108879, 134217757,
+ 268435459
+};
+
+#define EDGEHASH(v0,v1) ((v0*39)^(v1*31))
+
+/***/
+
+typedef struct Entry Entry;
+struct Entry {
+ Entry *next;
+ int v0, v1;
+ void *val;
+};
+
+struct EdgeHash {
+ Entry **buckets;
+ int nbuckets, nentries, cursize;
+};
+
+/***/
+
+EdgeHash *BLI_edgehash_new(void) {
+ EdgeHash *eh= MEM_mallocN(sizeof(*eh), "EdgeHash");
+ eh->cursize= 0;
+ eh->nentries= 0;
+ eh->nbuckets= hashsizes[eh->cursize];
+
+ eh->buckets= malloc(eh->nbuckets*sizeof(*eh->buckets));
+ memset(eh->buckets, 0, eh->nbuckets*sizeof(*eh->buckets));
+
+ return eh;
+}
+
+void BLI_edgehash_insert(EdgeHash *eh, int v0, int v1, void *val) {
+ unsigned int hash;
+ Entry *e= malloc(sizeof(*e));
+
+ if (v1<v0) v0 ^= v1 ^= v0 ^= v1;
+ hash = EDGEHASH(v0,v1)%eh->nbuckets;
+
+ e->v0 = v0;
+ e->v1 = v1;
+ e->val = val;
+ e->next= eh->buckets[hash];
+ eh->buckets[hash]= e;
+
+ if (++eh->nentries>eh->nbuckets*3) {
+ Entry *e, **old= eh->buckets;
+ int i, nold= eh->nbuckets;
+
+ eh->nbuckets= hashsizes[++eh->cursize];
+ eh->buckets= malloc(eh->nbuckets*sizeof(*eh->buckets));
+ memset(eh->buckets, 0, eh->nbuckets*sizeof(*eh->buckets));
+
+ for (i=0; i<nold; i++) {
+ for (e= old[i]; e;) {
+ Entry *n= e->next;
+
+ hash= EDGEHASH(e->v0,e->v1)%eh->nbuckets;
+ e->next= eh->buckets[hash];
+ eh->buckets[hash]= e;
+
+ e= n;
+ }
+ }
+
+ free(old);
+ }
+}
+
+void** BLI_edgehash_lookup_p(EdgeHash *eh, int v0, int v1) {
+ unsigned int hash;
+ Entry *e;
+
+ if (v1<v0) v0 ^= v1 ^= v0 ^= v1;
+ hash = EDGEHASH(v0,v1)%eh->nbuckets;
+ for (e= eh->buckets[hash]; e; e= e->next)
+ if (v0==e->v0 && v1==e->v1)
+ return &e->val;
+
+ return NULL;
+}
+
+void* BLI_edgehash_lookup(EdgeHash *eh, int v0, int v1) {
+ void **value_p = BLI_edgehash_lookup_p(eh,v0,v1);
+
+ return value_p?*value_p:NULL;
+}
+
+int BLI_edgehash_haskey(EdgeHash *eh, int v0, int v1) {
+ return BLI_edgehash_lookup_p(eh, v0, v1)!=NULL;
+}
+
+int BLI_edgehash_size(EdgeHash *eh) {
+ return eh->nentries;
+}
+
+void BLI_edgehash_clear(EdgeHash *eh, EdgeHashFreeFP valfreefp) {
+ int i;
+
+ for (i=0; i<eh->nbuckets; i++) {
+ Entry *e;
+
+ for (e= eh->buckets[i]; e; ) {
+ Entry *n= e->next;
+
+ if (valfreefp) valfreefp(e->val);
+ free(e);
+
+ e= n;
+ }
+ eh->buckets[i]= NULL;
+ }
+
+ eh->nentries= 0;
+}
+
+void BLI_edgehash_free(EdgeHash *eh, EdgeHashFreeFP valfreefp) {
+ BLI_edgehash_clear(eh, valfreefp);
+
+ free(eh->buckets);
+ MEM_freeN(eh);
+}
+
+
+/***/
+
+struct EdgeHashIterator {
+ EdgeHash *eh;
+ int curBucket;
+ Entry *curEntry;
+};
+
+EdgeHashIterator *BLI_edgehashIterator_new(EdgeHash *eh) {
+ EdgeHashIterator *ehi= malloc(sizeof(*ehi));
+ ehi->eh= eh;
+ ehi->curEntry= NULL;
+ ehi->curBucket= -1;
+ while (!ehi->curEntry) {
+ ehi->curBucket++;
+ if (ehi->curBucket==ehi->eh->nbuckets)
+ break;
+ ehi->curEntry= ehi->eh->buckets[ehi->curBucket];
+ }
+ return ehi;
+}
+void BLI_edgehashIterator_free(EdgeHashIterator *ehi) {
+ free(ehi);
+}
+
+void BLI_edgehashIterator_getKey(EdgeHashIterator *ehi, int *v0_r, int *v1_r) {
+ if (ehi->curEntry) {
+ *v0_r = ehi->curEntry->v0;
+ *v1_r = ehi->curEntry->v1;
+ }
+}
+void *BLI_edgehashIterator_getValue(EdgeHashIterator *ehi) {
+ return ehi->curEntry?ehi->curEntry->val:NULL;
+}
+
+void BLI_edgehashIterator_step(EdgeHashIterator *ehi) {
+ if (ehi->curEntry) {
+ ehi->curEntry= ehi->curEntry->next;
+ while (!ehi->curEntry) {
+ ehi->curBucket++;
+ if (ehi->curBucket==ehi->eh->nbuckets)
+ break;
+ ehi->curEntry= ehi->eh->buckets[ehi->curBucket];
+ }
+ }
+}
+int BLI_edgehashIterator_isDone(EdgeHashIterator *ehi) {
+ return !ehi->curEntry;
+}
+
diff --git a/source/blender/blenlib/intern/fileops.c b/source/blender/blenlib/intern/fileops.c
new file mode 100644
index 00000000000..fcea30982bd
--- /dev/null
+++ b/source/blender/blenlib/intern/fileops.c
@@ -0,0 +1,364 @@
+/*
+ * blenlib/fileops.h
+ *
+ * cleaned up (a bit) mar-01 nzc
+ *
+ * More low-level file things.
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "zlib.h"
+
+#ifdef WIN32
+#include "BLI_winstuff.h"
+#include <io.h>
+#else
+#include <sys/param.h>
+#endif
+
+#include "BLI_blenlib.h"
+#include "BLI_storage.h"
+#include "BLI_fileops.h"
+#include "BLI_callbacks.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "BKE_utildefines.h"
+#include <errno.h>
+
+/* implementations: */
+char *first_slash(char *string) {
+ char *ffslash, *fbslash;
+
+ ffslash= strchr(string, '/');
+ fbslash= strchr(string, '\\');
+
+ if (!ffslash) return fbslash;
+ else if (!fbslash) return ffslash;
+
+ if ((long)ffslash < (long)fbslash) return ffslash;
+ else return fbslash;
+}
+
+char *BLI_last_slash(char *string) {
+ char *lfslash, *lbslash;
+
+ lfslash= strrchr(string, '/');
+ lbslash= strrchr(string, '\\');
+
+ if (!lfslash) return lbslash;
+ else if (!lbslash) return lfslash;
+
+ if ((long)lfslash < (long)lbslash) return lbslash;
+ else return lfslash;
+}
+
+/* gzip the file in from and write it to "to".
+ return -1 if zlib fails, -2 if the originating file does not exist
+ note: will remove the "from" file
+ */
+int BLI_gzip(char *from, char *to) {
+ char buffer[10240];
+ int file;
+ int readsize = 0;
+
+ gzFile gzfile = gzopen(to,"wb");
+ if (NULL == gzfile) return -1;
+
+ file = open(from,O_BINARY|O_RDONLY);
+
+ if ( -1 == file ) return -2;
+
+ while ( 1 )
+ {
+ readsize = read(file, buffer, 10240);
+
+ if (readsize <= 0) break;
+
+ gzwrite(gzfile,buffer,readsize);
+ }
+
+ gzclose(gzfile);
+ close(file);
+
+ remove(from);
+
+ return 0;
+}
+
+/* return 1 when file can be written */
+int BLI_is_writable(char *filename)
+{
+ int file;
+
+ file = open(filename, O_BINARY | O_RDWR | O_CREAT | O_TRUNC, 0666);
+
+ if (file < 0)
+ return 0;
+ else {
+ close(file);
+ return 1;
+ }
+}
+
+#ifdef WIN32
+
+static char str[MAXPATHLEN+12];
+
+int BLI_delete(char *file, int dir, int recursive) {
+ int err;
+
+ if (recursive) {
+ callLocalErrorCallBack("Recursive delete is unsupported on Windows");
+ err= 1;
+ } else if (dir) {
+ err= !RemoveDirectory(file);
+ if (err) printf ("Unable to remove directory");
+ } else {
+ err= !DeleteFile(file);
+ if (err) callLocalErrorCallBack("Unable to delete file");
+ }
+
+ return err;
+}
+
+int BLI_touch(char *file) {
+ callLocalErrorCallBack("Touching files is unsupported on Windows");
+
+ return 1;
+}
+
+int BLI_move(char *file, char *to) {
+ int err;
+
+ // windows doesn't support moveing to a directory
+ // it has to be 'mv filename filename' and not
+ // 'mv filename destdir'
+
+ strcpy(str, to);
+ // points 'to' to a directory ?
+ if (BLI_last_slash(str) == (str + strlen(str) - 1)) {
+ if (BLI_last_slash(file) != NULL) {
+ strcat(str, BLI_last_slash(file) + 1);
+ }
+ }
+
+ err= !MoveFile(file, str);
+ if (err) {
+ callLocalErrorCallBack("Unable to move file");
+ printf(" Move from '%s' to '%s' failed\n", file, str);
+ }
+
+ return err;
+}
+
+
+int BLI_copy_fileops(char *file, char *to) {
+ int err;
+
+ // windows doesn't support copying to a directory
+ // it has to be 'cp filename filename' and not
+ // 'cp filename destdir'
+
+ strcpy(str, to);
+ // points 'to' to a directory ?
+ if (BLI_last_slash(str) == (str + strlen(str) - 1)) {
+ if (BLI_last_slash(file) != NULL) {
+ strcat(str, BLI_last_slash(file) + 1);
+ }
+ }
+
+ err= !CopyFile(file,str,FALSE);
+
+ if (err) {
+ callLocalErrorCallBack("Unable to copy file!");
+ printf(" Copy from '%s' to '%s' failed\n", file, str);
+ }
+
+ return err;
+}
+
+int BLI_link(char *file, char *to) {
+ callLocalErrorCallBack("Linking files is unsupported on Windows");
+
+ return 1;
+}
+
+int BLI_backup(char *file, char *from, char *to) {
+ callLocalErrorCallBack("Backing up files is unsupported on Windows");
+
+ return 1;
+}
+
+int BLI_exists(char *file) {
+ return (GetFileAttributes(file) != 0xFFFFFFFF);
+}
+
+void BLI_recurdir_fileops(char *dirname) {
+ char *lslash;
+ char tmp[MAXPATHLEN];
+
+ // First remove possible slash at the end of the dirname.
+ // This routine otherwise tries to create
+ // blah1/blah2/ (with slash) after creating
+ // blah1/blah2 (without slash)
+
+ strcpy(tmp, dirname);
+ lslash= BLI_last_slash(tmp);
+
+ if (lslash == tmp + strlen(tmp) - 1) {
+ *lslash = 0;
+ }
+
+ if (BLI_exists(tmp)) return;
+
+ lslash= BLI_last_slash(tmp);
+ if (lslash) {
+ /* Split about the last slash and recurse */
+ *lslash = 0;
+ BLI_recurdir_fileops(tmp);
+ }
+
+ if(dirname[0]) /* patch, this recursive loop tries to create a nameless directory */
+ if (!CreateDirectory(dirname, NULL))
+ callLocalErrorCallBack("Unable to create directory\n");
+}
+
+int BLI_rename(char *from, char *to) {
+ if (!BLI_exists(from)) return 0;
+
+ if (BLI_exists(to))
+ if(BLI_delete(to, 0, 0)) return 1;
+
+ return rename(from, to);
+}
+
+#else /* The sane UNIX world */
+
+/*
+ * but the sane UNIX world is tied to the interface, and the system
+ * timer, and... We implement a callback mechanism. The system will
+ * have to initialise the callback before the functions will work!
+ * */
+static char str[MAXPATHLEN+12];
+
+int BLI_delete(char *file, int dir, int recursive)
+{
+ if(strchr(file, '"')) {
+ printf("Error: not deleted file %s because of quote!\n", file);
+ }
+ else {
+ if (recursive) sprintf(str, "/bin/rm -rf \"%s\"", file);
+ else if (dir) sprintf(str, "/bin/rmdir \"%s\"", file);
+ else sprintf(str, "/bin/rm -f \"%s\"", file);
+
+ return system(str);
+ }
+ return -1;
+}
+
+int BLI_touch(char *file)
+{
+
+ if( BLI_exists("/bin/touch") )
+ sprintf(str, "/bin/touch %s", file);
+ else
+ sprintf(str, "/usr/bin/touch %s", file);
+
+ return system(str);
+}
+
+int BLI_move(char *file, char *to) {
+ sprintf(str, "/bin/mv -f \"%s\" \"%s\"", file, to);
+
+ return system(str);
+}
+
+int BLI_copy_fileops(char *file, char *to) {
+ sprintf(str, "/bin/cp -rf \"%s\" \"%s\"", file, to);
+
+ return system(str);
+}
+
+int BLI_link(char *file, char *to) {
+ sprintf(str, "/bin/ln -f \"%s\" \"%s\"", file, to);
+
+ return system(str);
+}
+
+int BLI_backup(char *file, char *from, char *to) {
+ sprintf(str, "/bin/su root -c 'cd %s; /bin/tar cf - \"%s\" | (/bin/cd %s; /bin/tar xf -)'", from, file, to);
+
+ return system(str);
+}
+
+int BLI_exists(char *file) {
+ return BLI_exist(file);
+}
+
+void BLI_recurdir_fileops(char *dirname) {
+ char *lslash;
+ char tmp[MAXPATHLEN];
+
+ if (BLI_exists(dirname)) return;
+
+ strcpy(tmp, dirname);
+
+ lslash= BLI_last_slash(tmp);
+ if (lslash) {
+ /* Split about the last slash and recurse */
+ *lslash = 0;
+ BLI_recurdir_fileops(tmp);
+ }
+
+ mkdir(dirname, 0777);
+}
+
+int BLI_rename(char *from, char *to) {
+ if (!BLI_exists(from)) return 0;
+
+ if (BLI_exists(to)) if(BLI_delete(to, 0, 0)) return 1;
+
+ return rename(from, to);
+}
+
+#endif
diff --git a/source/blender/blenlib/intern/freetypefont.c b/source/blender/blenlib/intern/freetypefont.c
new file mode 100644
index 00000000000..7fbd4bac485
--- /dev/null
+++ b/source/blender/blenlib/intern/freetypefont.c
@@ -0,0 +1,634 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is written by Rob Haarsma (phase)
+ * All rights reserved.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This code parses the Freetype font outline data to chains of Blender's beziertriples.
+ * Additional information can be found at the bottom of this file.
+ *
+ * Code that uses exotic character maps is present but commented out.
+ */
+
+#ifdef WITH_FREETYPE2
+
+#ifdef WIN32
+#pragma warning (disable:4244)
+#endif
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_GLYPH_H
+#include FT_BBOX_H
+#include FT_SIZES_H
+#include <freetype/ttnameid.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_vfontdata.h"
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "BIF_toolbox.h"
+
+#include "BKE_global.h"
+#include "BKE_utildefines.h"
+
+#include "DNA_vfont_types.h"
+#include "DNA_packedFile_types.h"
+#include "DNA_curve_types.h"
+
+#define myMIN_ASCII 32
+#define myMAX_ASCII 255
+
+/* local variables */
+static FT_Library library;
+static FT_Error err;
+
+
+void freetypechar_to_vchar(FT_Face face, FT_ULong charcode, VFontData *vfd)
+{
+ // Blender
+ struct Nurb *nu;
+ struct VChar *che;
+ struct BezTriple *bezt;
+
+ // Freetype2
+ FT_GlyphSlot glyph;
+ FT_UInt glyph_index;
+ FT_Outline ftoutline;
+ float scale, height;
+ float dx, dy;
+ int j,k,l,m=0;
+
+ // adjust font size
+ height= ((double) face->bbox.yMax - (double) face->bbox.yMin);
+ if(height != 0.0)
+ scale = 1.0 / height;
+ else
+ scale = 1.0 / 1000.0;
+
+ //
+ // Generate the character 3D data
+ //
+ // Get the FT Glyph index and load the Glyph
+ glyph_index= FT_Get_Char_Index(face, charcode);
+ err= FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP);
+
+ // If loading succeeded, convert the FT glyph to the internal format
+ if(!err)
+ {
+ int *npoints;
+ int *onpoints;
+
+ // First we create entry for the new character to the character list
+ che= (VChar *) MEM_callocN(sizeof(struct VChar), "objfnt_char");
+ BLI_addtail(&vfd->characters, che);
+
+ // Take some data for modifying purposes
+ glyph= face->glyph;
+ ftoutline= glyph->outline;
+
+ // Set the width and character code
+ che->index= charcode;
+ che->width= glyph->advance.x * scale;
+
+ // Start converting the FT data
+ npoints = (int *)MEM_callocN((ftoutline.n_contours)* sizeof(int),"endpoints") ;
+ onpoints = (int *)MEM_callocN((ftoutline.n_contours)* sizeof(int),"onpoints") ;
+
+ // calculate total points of each contour
+ for(j = 0; j < ftoutline.n_contours; j++) {
+ if(j == 0)
+ npoints[j] = ftoutline.contours[j] + 1;
+ else
+ npoints[j] = ftoutline.contours[j] - ftoutline.contours[j - 1];
+ }
+
+ // get number of on-curve points for beziertriples (including conic virtual on-points)
+ for(j = 0; j < ftoutline.n_contours; j++) {
+ l = 0;
+ for(k = 0; k < npoints[j]; k++) {
+ if(j > 0) l = k + ftoutline.contours[j - 1] + 1; else l = k;
+ if(ftoutline.tags[l] == FT_Curve_Tag_On)
+ onpoints[j]++;
+
+ if(k < npoints[j] - 1 )
+ if( ftoutline.tags[l] == FT_Curve_Tag_Conic &&
+ ftoutline.tags[l+1] == FT_Curve_Tag_Conic)
+ onpoints[j]++;
+ }
+ }
+
+ //contour loop, bezier & conic styles merged
+ for(j = 0; j < ftoutline.n_contours; j++) {
+ // add new curve
+ nu = (Nurb*)MEM_callocN(sizeof(struct Nurb),"objfnt_nurb");
+ bezt = (BezTriple*)MEM_callocN((onpoints[j])* sizeof(BezTriple),"objfnt_bezt") ;
+ BLI_addtail(&che->nurbsbase, nu);
+
+ nu->type= CU_BEZIER+CU_2D;
+ nu->pntsu = onpoints[j];
+ nu->resolu= 8;
+ nu->flagu= 1;
+ nu->bezt = bezt;
+
+ //individual curve loop, start-end
+ for(k = 0; k < npoints[j]; k++) {
+ if(j > 0) l = k + ftoutline.contours[j - 1] + 1; else l = k;
+ if(k == 0) m = l;
+
+ //virtual conic on-curve points
+ if(k < npoints[j] - 1 )
+ {
+ if( ftoutline.tags[l] == FT_Curve_Tag_Conic && ftoutline.tags[l+1] == FT_Curve_Tag_Conic) {
+ dx = (ftoutline.points[l].x + ftoutline.points[l+1].x)* scale / 2.0;
+ dy = (ftoutline.points[l].y + ftoutline.points[l+1].y)* scale / 2.0;
+
+ //left handle
+ bezt->vec[0][0] = (dx + (2 * ftoutline.points[l].x)* scale) / 3.0;
+ bezt->vec[0][1] = (dy + (2 * ftoutline.points[l].y)* scale) / 3.0;
+
+ //midpoint (virtual on-curve point)
+ bezt->vec[1][0] = dx;
+ bezt->vec[1][1] = dy;
+
+ //right handle
+ bezt->vec[2][0] = (dx + (2 * ftoutline.points[l+1].x)* scale) / 3.0;
+ bezt->vec[2][1] = (dy + (2 * ftoutline.points[l+1].y)* scale) / 3.0;
+
+ bezt->h1= bezt->h2= HD_ALIGN;
+ bezt++;
+ }
+ }
+
+ //on-curve points
+ if(ftoutline.tags[l] == FT_Curve_Tag_On) {
+ //left handle
+ if(k > 0) {
+ if(ftoutline.tags[l - 1] == FT_Curve_Tag_Cubic) {
+ bezt->vec[0][0] = ftoutline.points[l-1].x* scale;
+ bezt->vec[0][1] = ftoutline.points[l-1].y* scale;
+ bezt->h1= HD_FREE;
+ } else if(ftoutline.tags[l - 1] == FT_Curve_Tag_Conic) {
+ bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l - 1].x))* scale / 3.0;
+ bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l - 1].y))* scale / 3.0;
+ bezt->h1= HD_FREE;
+ } else {
+ bezt->vec[0][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[l-1].x)* scale / 3.0;
+ bezt->vec[0][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[l-1].y)* scale / 3.0;
+ bezt->h1= HD_VECT;
+ }
+ } else { //first point on curve
+ if(ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Cubic) {
+ bezt->vec[0][0] = ftoutline.points[ftoutline.contours[j]].x * scale;
+ bezt->vec[0][1] = ftoutline.points[ftoutline.contours[j]].y * scale;
+ bezt->h1= HD_FREE;
+ } else if(ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Conic) {
+ bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[ftoutline.contours[j]].x))* scale / 3.0 ;
+ bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[ftoutline.contours[j]].y))* scale / 3.0 ;
+ bezt->h1= HD_FREE;
+ } else {
+ bezt->vec[0][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[ftoutline.contours[j]].x)* scale / 3.0;
+ bezt->vec[0][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[ftoutline.contours[j]].y)* scale / 3.0;
+ bezt->h1= HD_VECT;
+ }
+ }
+
+ //midpoint (on-curve point)
+ bezt->vec[1][0] = ftoutline.points[l].x* scale;
+ bezt->vec[1][1] = ftoutline.points[l].y* scale;
+
+ //right handle
+ if(k < (npoints[j] - 1)) {
+ if(ftoutline.tags[l+1] == FT_Curve_Tag_Cubic) {
+ bezt->vec[2][0] = ftoutline.points[l+1].x* scale;
+ bezt->vec[2][1] = ftoutline.points[l+1].y* scale;
+ bezt->h2= HD_FREE;
+ } else if(ftoutline.tags[l+1] == FT_Curve_Tag_Conic) {
+ bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l+1].x))* scale / 3.0;
+ bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l+1].y))* scale / 3.0;
+ bezt->h2= HD_FREE;
+ } else {
+ bezt->vec[2][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[l+1].x)* scale / 3.0;
+ bezt->vec[2][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[l+1].y)* scale / 3.0;
+ bezt->h2= HD_VECT;
+ }
+ } else { //last point on curve
+ if(ftoutline.tags[m] == FT_Curve_Tag_Cubic) {
+ bezt->vec[2][0] = ftoutline.points[m].x* scale;
+ bezt->vec[2][1] = ftoutline.points[m].y* scale;
+ bezt->h2= HD_FREE;
+ } else if(ftoutline.tags[m] == FT_Curve_Tag_Conic) {
+ bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[m].x))* scale / 3.0 ;
+ bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[m].y))* scale / 3.0 ;
+ bezt->h2= HD_FREE;
+ } else {
+ bezt->vec[2][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[m].x)* scale / 3.0;
+ bezt->vec[2][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[m].y)* scale / 3.0;
+ bezt->h2= HD_VECT;
+ }
+ }
+
+ // get the handles that are aligned, tricky...
+ // DistVL2Dfl, check if the three beztriple points are on one line
+ // VecLenf, see if there's a distance between the three points
+ // VecLenf again, to check the angle between the handles
+ // finally, check if one of them is a vector handle
+ if((DistVL2Dfl(bezt->vec[0],bezt->vec[1],bezt->vec[2]) < 0.001) &&
+ (VecLenf(bezt->vec[0], bezt->vec[1]) > 0.0001) &&
+ (VecLenf(bezt->vec[1], bezt->vec[2]) > 0.0001) &&
+ (VecLenf(bezt->vec[0], bezt->vec[2]) > 0.0002) &&
+ (VecLenf(bezt->vec[0], bezt->vec[2]) > MAX2(VecLenf(bezt->vec[0], bezt->vec[1]), VecLenf(bezt->vec[1], bezt->vec[2]))) &&
+ bezt->h1 != HD_VECT && bezt->h2 != HD_VECT)
+ {
+ bezt->h1= bezt->h2= HD_ALIGN;
+ }
+ bezt++;
+ }
+ }
+ }
+ if(npoints) MEM_freeN(npoints);
+ if(onpoints) MEM_freeN(onpoints);
+ }
+}
+
+int objchr_to_ftvfontdata(VFont *vfont, FT_ULong charcode)
+{
+ // Freetype2
+ FT_Face face;
+ struct TmpFont *tf;
+
+ // Find the correct FreeType font
+ tf= G.ttfdata.first;
+ while(tf)
+ {
+ if(tf->vfont == vfont)
+ break;
+ tf= tf->next;
+ }
+
+ // What, no font found. Something strange here
+ if(!tf) return FALSE;
+
+ // Load the font to memory
+ if(tf->pf)
+ {
+ err= FT_New_Memory_Face( library,
+ tf->pf->data,
+ tf->pf->size,
+ 0,
+ &face);
+ }
+ else
+ err= TRUE;
+
+ // Read the char
+ freetypechar_to_vchar(face, charcode, vfont->data);
+
+ // And everything went ok
+ return TRUE;
+}
+
+
+static VFontData *objfnt_to_ftvfontdata(PackedFile * pf)
+{
+ // Variables
+ FT_Face face;
+ FT_ULong charcode = 0, lcode;
+ FT_UInt glyph_index;
+ const char *fontname;
+ VFontData *vfd;
+
+/*
+ FT_CharMap found = 0;
+ FT_CharMap charmap;
+ FT_UShort my_platform_id = TT_PLATFORM_MICROSOFT;
+ FT_UShort my_encoding_id = TT_MS_ID_UNICODE_CS;
+ int n;
+*/
+
+ // load the freetype font
+ err = FT_New_Memory_Face( library,
+ pf->data,
+ pf->size,
+ 0,
+ &face );
+
+ if(err) return NULL;
+/*
+ for ( n = 0; n < face->num_charmaps; n++ )
+ {
+ charmap = face->charmaps[n];
+ if ( charmap->platform_id == my_platform_id &&
+ charmap->encoding_id == my_encoding_id )
+ {
+ found = charmap;
+ break;
+ }
+ }
+
+ if ( !found ) { return NULL; }
+
+ // now, select the charmap for the face object
+ err = FT_Set_Charmap( face, found );
+ if ( err ) { return NULL; }
+*/
+
+ // allocate blender font
+ vfd= MEM_callocN(sizeof(*vfd), "FTVFontData");
+
+ // get the name
+ fontname = FT_Get_Postscript_Name(face);
+ strcpy(vfd->name, (fontname == NULL) ? "Fontname not available" : fontname);
+
+ // Extract the first 256 character from TTF
+ lcode= charcode= FT_Get_First_Char(face, &glyph_index);
+
+ // No charmap found from the ttf so we need to figure it out
+ if(glyph_index == 0)
+ {
+ FT_CharMap found = 0;
+ FT_CharMap charmap;
+ int n;
+
+ for ( n = 0; n < face->num_charmaps; n++ )
+ {
+ charmap = face->charmaps[n];
+ if (charmap->encoding == FT_ENCODING_APPLE_ROMAN)
+ {
+ found = charmap;
+ break;
+ }
+ }
+
+ err = FT_Set_Charmap( face, found );
+
+ if( err )
+ return NULL;
+
+ lcode= charcode= FT_Get_First_Char(face, &glyph_index);
+ }
+
+ // Load characters
+ while(charcode < 256)
+ {
+ // Generate the font data
+ freetypechar_to_vchar(face, charcode, vfd);
+
+ // Next glyph
+ charcode = FT_Get_Next_Char(face, charcode, &glyph_index);
+
+ // Check that we won't start infinite loop
+ if(charcode <= lcode)
+ break;
+ lcode = charcode;
+ }
+
+ err = FT_Set_Charmap( face, (FT_CharMap) FT_ENCODING_UNICODE );
+
+ return vfd;
+}
+
+
+static int check_freetypefont(PackedFile * pf)
+{
+ FT_Face face;
+ FT_GlyphSlot glyph;
+ FT_UInt glyph_index;
+/*
+ FT_CharMap charmap;
+ FT_CharMap found;
+ FT_UShort my_platform_id = TT_PLATFORM_MICROSOFT;
+ FT_UShort my_encoding_id = TT_MS_ID_UNICODE_CS;
+ int n;
+*/
+ int success = 0;
+
+ err = FT_New_Memory_Face( library,
+ pf->data,
+ pf->size,
+ 0,
+ &face );
+ if(err) {
+ success = 0;
+ error("This is not a valid font");
+ }
+ else {
+/*
+ for ( n = 0; n < face->num_charmaps; n++ )
+ {
+ charmap = face->charmaps[n];
+ if ( charmap->platform_id == my_platform_id &&
+ charmap->encoding_id == my_encoding_id )
+ {
+ found = charmap;
+ break;
+ }
+ }
+
+ if ( !found ) { return 0; }
+
+ // now, select the charmap for the face object
+ err = FT_Set_Charmap( face, found );
+ if ( err ) { return 0; }
+*/
+ glyph_index = FT_Get_Char_Index( face, 'A' );
+ err = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP);
+ if(err) success = 0;
+ else {
+ glyph = face->glyph;
+ if (glyph->format == ft_glyph_format_outline ) {
+ success = 1;
+ } else {
+ error("Selected Font has no outline data");
+ success = 0;
+ }
+ }
+ }
+
+ return success;
+}
+
+
+VFontData *BLI_vfontdata_from_freetypefont(PackedFile *pf)
+{
+ VFontData *vfd= NULL;
+ int success = 0;
+
+ //init Freetype
+ err = FT_Init_FreeType( &library);
+ if(err) {
+ error("Failed to load the Freetype font library");
+ return 0;
+ }
+
+ success = check_freetypefont(pf);
+
+ if (success) {
+ vfd= objfnt_to_ftvfontdata(pf);
+ }
+
+ //free Freetype
+ FT_Done_FreeType( library);
+
+ return vfd;
+}
+
+int BLI_vfontchar_from_freetypefont(VFont *vfont, unsigned long character)
+{
+ int success = FALSE;
+
+ if(!vfont) return FALSE;
+
+ // Init Freetype
+ err = FT_Init_FreeType(&library);
+ if(err) {
+ error("Failed to load the Freetype font library");
+ return 0;
+ }
+
+ // Load the character
+ success = objchr_to_ftvfontdata(vfont, character);
+ if(success == FALSE) return FALSE;
+
+ // Free Freetype
+ FT_Done_FreeType(library);
+
+ // Ahh everything ok
+ return TRUE;
+}
+
+#endif // WITH_FREETYPE2
+
+
+
+#if 0
+
+// Freetype2 Outline struct
+
+typedef struct FT_Outline_
+ {
+ short n_contours; /* number of contours in glyph */
+ short n_points; /* number of points in the glyph */
+
+ FT_Vector* points; /* the outline's points */
+ char* tags; /* the points flags */
+ short* contours; /* the contour end points */
+
+ int flags; /* outline masks */
+
+ } FT_Outline;
+
+#endif
+
+/***//*
+from: http://www.freetype.org/freetype2/docs/glyphs/glyphs-6.html#section-1
+
+Vectorial representation of Freetype glyphs
+
+The source format of outlines is a collection of closed paths called "contours". Each contour is
+made of a series of line segments and bezier arcs. Depending on the file format, these can be
+second-order or third-order polynomials. The former are also called quadratic or conic arcs, and
+they come from the TrueType format. The latter are called cubic arcs and mostly come from the
+Type1 format.
+
+Each arc is described through a series of start, end and control points. Each point of the outline
+has a specific tag which indicates wether it is used to describe a line segment or an arc.
+
+
+The following rules are applied to decompose the contour's points into segments and arcs :
+
+# two successive "on" points indicate a line segment joining them.
+
+# one conic "off" point amidst two "on" points indicates a conic bezier arc, the "off" point being
+ the control point, and the "on" ones the start and end points.
+
+# Two successive cubic "off" points amidst two "on" points indicate a cubic bezier arc. There must
+ be exactly two cubic control points and two on points for each cubic arc (using a single cubic
+ "off" point between two "on" points is forbidden, for example).
+
+# finally, two successive conic "off" points forces the rasterizer to create (during the scan-line
+ conversion process exclusively) a virtual "on" point amidst them, at their exact middle. This
+ greatly facilitates the definition of successive conic bezier arcs. Moreover, it's the way
+ outlines are described in the TrueType specification.
+
+Note that it is possible to mix conic and cubic arcs in a single contour, even though no current
+font driver produces such outlines.
+
+ * # on
+ * off
+ __---__
+ #-__ _-- -_
+ --__ _- -
+ --__ # \
+ --__ #
+ -#
+ Two "on" points
+ Two "on" points and one "conic" point
+ between them
+
+
+
+ *
+ # __ Two "on" points with two "conic"
+ \ - - points between them. The point
+ \ / \ marked '0' is the middle of the
+ - 0 \ "off" points, and is a 'virtual'
+ -_ _- # "on" point where the curve passes.
+ -- It does not appear in the point
+ list.
+ *
+
+
+
+
+ * # on
+ * * off
+ __---__
+ _-- -_
+ _- -
+ # \
+ #
+
+ Two "on" points
+ and two "cubic" point
+ between them
+
+
+Each glyph's original outline points are located on a grid of indivisible units. The points are stored
+in the font file as 16-bit integer grid coordinates, with the grid origin's being at (0,0); they thus
+range from -16384 to 16383.
+
+Convert conic to bezier arcs:
+Conic P0 P1 P2
+Bezier B0 B1 B2 B3
+B0=P0
+B1=(P0+2*P1)/3
+B2=(P2+2*P1)/3
+B3=P2
+
+*//****/
diff --git a/source/blender/blenlib/intern/gsqueue.c b/source/blender/blenlib/intern/gsqueue.c
new file mode 100644
index 00000000000..e52c573eec7
--- /dev/null
+++ b/source/blender/blenlib/intern/gsqueue.c
@@ -0,0 +1,122 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+#include "BLI_gsqueue.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+typedef struct _GSQueueElem GSQueueElem;
+struct _GSQueueElem {
+ GSQueueElem *next;
+};
+
+struct _GSQueue {
+ GSQueueElem *head;
+ GSQueueElem *tail;
+ int elem_size;
+};
+
+GSQueue *BLI_gsqueue_new(int elem_size)
+{
+ GSQueue *gq= MEM_mallocN(sizeof(*gq), "gqueue_new");
+ gq->head= gq->tail= NULL;
+ gq->elem_size= elem_size;
+
+ return gq;
+}
+
+int BLI_gsqueue_is_empty(GSQueue *gq)
+{
+ return (gq->head==NULL);
+}
+
+void BLI_gsqueue_peek(GSQueue *gq, void *item_r)
+{
+ memcpy(item_r, &gq->head[1], gq->elem_size);
+}
+void BLI_gsqueue_pop(GSQueue *gq, void *item_r)
+{
+ GSQueueElem *elem= gq->head;
+ if (elem==gq->tail) {
+ gq->head= gq->tail= NULL;
+ } else {
+ gq->head= gq->head->next;
+ }
+
+ if (item_r) memcpy(item_r, &elem[1], gq->elem_size);
+ MEM_freeN(elem);
+}
+void BLI_gsqueue_push(GSQueue *gq, void *item)
+{
+ GSQueueElem *elem;
+
+ /* compare: prevent events added double in row */
+ if (!BLI_gsqueue_is_empty(gq)) {
+ if(0==memcmp(item, &gq->head[1], gq->elem_size))
+ return;
+ }
+ elem= MEM_mallocN(sizeof(*elem)+gq->elem_size, "gqueue_push");
+ memcpy(&elem[1], item, gq->elem_size);
+ elem->next= NULL;
+
+ if (BLI_gsqueue_is_empty(gq)) {
+ gq->tail= gq->head= elem;
+ } else {
+ gq->tail= gq->tail->next= elem;
+ }
+}
+void BLI_gsqueue_pushback(GSQueue *gq, void *item)
+{
+ GSQueueElem *elem= MEM_mallocN(sizeof(*elem)+gq->elem_size, "gqueue_push");
+ memcpy(&elem[1], item, gq->elem_size);
+ elem->next= gq->head;
+
+ if (BLI_gsqueue_is_empty(gq)) {
+ gq->head= gq->tail= elem;
+ } else {
+ gq->head= elem;
+ }
+}
+
+void BLI_gsqueue_free(GSQueue *gq)
+{
+ while (gq->head) {
+ BLI_gsqueue_pop(gq, NULL);
+ }
+ MEM_freeN(gq);
+}
+
+
diff --git a/source/blender/blenlib/intern/jitter.c b/source/blender/blenlib/intern/jitter.c
new file mode 100644
index 00000000000..fd658765802
--- /dev/null
+++ b/source/blender/blenlib/intern/jitter.c
@@ -0,0 +1,178 @@
+/**
+ * Jitter offset table
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include "MEM_guardedalloc.h"
+
+#include "BLI_arithb.h"
+#include "BLI_rand.h"
+#include "BLI_jitter.h"
+
+
+void BLI_jitterate1(float *jit1, float *jit2, int num, float rad1)
+{
+ int i , j , k;
+ float vecx, vecy, dvecx, dvecy, x, y, len;
+
+ for (i = 2*num-2; i>=0 ; i-=2) {
+ dvecx = dvecy = 0.0;
+ x = jit1[i];
+ y = jit1[i+1];
+ for (j = 2*num-2; j>=0 ; j-=2) {
+ if (i != j){
+ vecx = jit1[j] - x - 1.0;
+ vecy = jit1[j+1] - y - 1.0;
+ for (k = 3; k>0 ; k--){
+ if( fabs(vecx)<rad1 && fabs(vecy)<rad1) {
+ len= sqrt(vecx*vecx + vecy*vecy);
+ if(len>0 && len<rad1) {
+ len= len/rad1;
+ dvecx += vecx/len;
+ dvecy += vecy/len;
+ }
+ }
+ vecx += 1.0;
+
+ if( fabs(vecx)<rad1 && fabs(vecy)<rad1) {
+ len= sqrt(vecx*vecx + vecy*vecy);
+ if(len>0 && len<rad1) {
+ len= len/rad1;
+ dvecx += vecx/len;
+ dvecy += vecy/len;
+ }
+ }
+ vecx += 1.0;
+
+ if( fabs(vecx)<rad1 && fabs(vecy)<rad1) {
+ len= sqrt(vecx*vecx + vecy*vecy);
+ if(len>0 && len<rad1) {
+ len= len/rad1;
+ dvecx += vecx/len;
+ dvecy += vecy/len;
+ }
+ }
+ vecx -= 2.0;
+ vecy += 1.0;
+ }
+ }
+ }
+
+ x -= dvecx/18.0 ;
+ y -= dvecy/18.0;
+ x -= floor(x) ;
+ y -= floor(y);
+ jit2[i] = x;
+ jit2[i+1] = y;
+ }
+ memcpy(jit1,jit2,2 * num * sizeof(float));
+}
+
+void BLI_jitterate2(float *jit1, float *jit2, int num, float rad2)
+{
+ int i, j;
+ float vecx, vecy, dvecx, dvecy, x, y;
+
+ for (i=2*num -2; i>= 0 ; i-=2){
+ dvecx = dvecy = 0.0;
+ x = jit1[i];
+ y = jit1[i+1];
+ for (j =2*num -2; j>= 0 ; j-=2){
+ if (i != j){
+ vecx = jit1[j] - x - 1.0;
+ vecy = jit1[j+1] - y - 1.0;
+
+ if( fabs(vecx)<rad2) dvecx+= vecx*rad2;
+ vecx += 1.0;
+ if( fabs(vecx)<rad2) dvecx+= vecx*rad2;
+ vecx += 1.0;
+ if( fabs(vecx)<rad2) dvecx+= vecx*rad2;
+
+ if( fabs(vecy)<rad2) dvecy+= vecy*rad2;
+ vecy += 1.0;
+ if( fabs(vecy)<rad2) dvecy+= vecy*rad2;
+ vecy += 1.0;
+ if( fabs(vecy)<rad2) dvecy+= vecy*rad2;
+
+ }
+ }
+
+ x -= dvecx/2 ;
+ y -= dvecy/2;
+ x -= floor(x) ;
+ y -= floor(y);
+ jit2[i] = x;
+ jit2[i+1] = y;
+ }
+ memcpy(jit1,jit2,2 * num * sizeof(float));
+}
+
+
+void BLI_initjit(float *jitarr, int num)
+{
+ float *jit2, x, rad1, rad2, rad3;
+ int i;
+
+ if(num==0) return;
+
+ jit2= MEM_mallocN(12 + 2*sizeof(float)*num, "initjit");
+ rad1= 1.0/sqrt((float)num);
+ rad2= 1.0/((float)num);
+ rad3= sqrt((float)num)/((float)num);
+
+ BLI_srand(31415926 + num);
+ x= 0;
+ for(i=0; i<2*num; i+=2) {
+ jitarr[i]= x+ rad1*(0.5-BLI_drand());
+ jitarr[i+1]= ((float)i/2)/num +rad1*(0.5-BLI_drand());
+ x+= rad3;
+ x -= floor(x);
+ }
+
+ for (i=0 ; i<24 ; i++) {
+ BLI_jitterate1(jitarr, jit2, num, rad1);
+ BLI_jitterate1(jitarr, jit2, num, rad1);
+ BLI_jitterate2(jitarr, jit2, num, rad2);
+ }
+
+ MEM_freeN(jit2);
+
+ /* finally, move jittertab to be centered around (0,0) */
+ for(i=0; i<2*num; i+=2) {
+ jitarr[i] -= 0.5;
+ jitarr[i+1] -= 0.5;
+ }
+
+}
+
+
+/* eof */
diff --git a/source/blender/blenlib/intern/matrixops.c b/source/blender/blenlib/intern/matrixops.c
new file mode 100644
index 00000000000..62098d5fa90
--- /dev/null
+++ b/source/blender/blenlib/intern/matrixops.c
@@ -0,0 +1,441 @@
+/*
+ *
+ * Some matrix operations.
+ *
+ * Always use
+ * - vector with x components : float x[3], int x[3], etc
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/* ------------------------------------------------------------------------- */
+#include <string.h>
+#include "MTC_matrixops.h"
+#include "MTC_vectorops.h"
+/* ------------------------------------------------------------------------- */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if defined(__sun__) || defined( __sun ) || defined (__sparc) || defined (__sparc__)
+#include <strings.h>
+#endif
+
+#define ABS(x) ((x) < 0 ? -(x) : (x))
+#define SWAP(type, a, b) { type sw_ap; sw_ap=(a); (a)=(b); (b)=sw_ap; }
+
+void MTC_Mat4CpyMat4(float m1[][4], float m2[][4])
+{
+ memcpy(m1, m2, 4*4*sizeof(float));
+}
+
+/* ------------------------------------------------------------------------- */
+
+void MTC_Mat4MulSerie(float answ[][4],
+ float m1[][4], float m2[][4], float m3[][4],
+ float m4[][4], float m5[][4], float m6[][4],
+ float m7[][4], float m8[][4])
+{
+ float temp[4][4];
+
+ if(m1==0 || m2==0) return;
+
+ MTC_Mat4MulMat4(answ, m2, m1);
+ if(m3) {
+ MTC_Mat4MulMat4(temp, m3, answ);
+ if(m4) {
+ MTC_Mat4MulMat4(answ, m4, temp);
+ if(m5) {
+ MTC_Mat4MulMat4(temp, m5, answ);
+ if(m6) {
+ MTC_Mat4MulMat4(answ, m6, temp);
+ if(m7) {
+ MTC_Mat4MulMat4(temp, m7, answ);
+ if(m8) {
+ MTC_Mat4MulMat4(answ, m8, temp);
+ }
+ else MTC_Mat4CpyMat4(answ, temp);
+ }
+ }
+ else MTC_Mat4CpyMat4(answ, temp);
+ }
+ }
+ else MTC_Mat4CpyMat4(answ, temp);
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+void MTC_Mat4MulMat4(float m1[][4], float m2[][4], float m3[][4])
+{
+ /* matrix product: c[j][k] = a[j][i].b[i][k] */
+
+ m1[0][0] = m2[0][0]*m3[0][0] + m2[0][1]*m3[1][0] + m2[0][2]*m3[2][0] + m2[0][3]*m3[3][0];
+ m1[0][1] = m2[0][0]*m3[0][1] + m2[0][1]*m3[1][1] + m2[0][2]*m3[2][1] + m2[0][3]*m3[3][1];
+ m1[0][2] = m2[0][0]*m3[0][2] + m2[0][1]*m3[1][2] + m2[0][2]*m3[2][2] + m2[0][3]*m3[3][2];
+ m1[0][3] = m2[0][0]*m3[0][3] + m2[0][1]*m3[1][3] + m2[0][2]*m3[2][3] + m2[0][3]*m3[3][3];
+
+ m1[1][0] = m2[1][0]*m3[0][0] + m2[1][1]*m3[1][0] + m2[1][2]*m3[2][0] + m2[1][3]*m3[3][0];
+ m1[1][1] = m2[1][0]*m3[0][1] + m2[1][1]*m3[1][1] + m2[1][2]*m3[2][1] + m2[1][3]*m3[3][1];
+ m1[1][2] = m2[1][0]*m3[0][2] + m2[1][1]*m3[1][2] + m2[1][2]*m3[2][2] + m2[1][3]*m3[3][2];
+ m1[1][3] = m2[1][0]*m3[0][3] + m2[1][1]*m3[1][3] + m2[1][2]*m3[2][3] + m2[1][3]*m3[3][3];
+
+ m1[2][0] = m2[2][0]*m3[0][0] + m2[2][1]*m3[1][0] + m2[2][2]*m3[2][0] + m2[2][3]*m3[3][0];
+ m1[2][1] = m2[2][0]*m3[0][1] + m2[2][1]*m3[1][1] + m2[2][2]*m3[2][1] + m2[2][3]*m3[3][1];
+ m1[2][2] = m2[2][0]*m3[0][2] + m2[2][1]*m3[1][2] + m2[2][2]*m3[2][2] + m2[2][3]*m3[3][2];
+ m1[2][3] = m2[2][0]*m3[0][3] + m2[2][1]*m3[1][3] + m2[2][2]*m3[2][3] + m2[2][3]*m3[3][3];
+
+ m1[3][0] = m2[3][0]*m3[0][0] + m2[3][1]*m3[1][0] + m2[3][2]*m3[2][0] + m2[3][3]*m3[3][0];
+ m1[3][1] = m2[3][0]*m3[0][1] + m2[3][1]*m3[1][1] + m2[3][2]*m3[2][1] + m2[3][3]*m3[3][1];
+ m1[3][2] = m2[3][0]*m3[0][2] + m2[3][1]*m3[1][2] + m2[3][2]*m3[2][2] + m2[3][3]*m3[3][2];
+ m1[3][3] = m2[3][0]*m3[0][3] + m2[3][1]*m3[1][3] + m2[3][2]*m3[2][3] + m2[3][3]*m3[3][3];
+
+}
+/* ------------------------------------------------------------------------- */
+
+void MTC_Mat4MulVecfl(float mat[][4], float *vec)
+{
+ float x,y;
+
+ x=vec[0];
+ y=vec[1];
+ vec[0]=x*mat[0][0] + y*mat[1][0] + mat[2][0]*vec[2] + mat[3][0];
+ vec[1]=x*mat[0][1] + y*mat[1][1] + mat[2][1]*vec[2] + mat[3][1];
+ vec[2]=x*mat[0][2] + y*mat[1][2] + mat[2][2]*vec[2] + mat[3][2];
+}
+
+/* ------------------------------------------------------------------------- */
+void MTC_Mat3MulVecfl(float mat[][3], float *vec)
+{
+ float x,y;
+
+ x=vec[0];
+ y=vec[1];
+ vec[0]= x*mat[0][0] + y*mat[1][0] + mat[2][0]*vec[2];
+ vec[1]= x*mat[0][1] + y*mat[1][1] + mat[2][1]*vec[2];
+ vec[2]= x*mat[0][2] + y*mat[1][2] + mat[2][2]*vec[2];
+}
+
+/* ------------------------------------------------------------------------- */
+
+int MTC_Mat4Invert(float inverse[][4], float mat[][4])
+{
+ int i, j, k;
+ double temp;
+ float tempmat[4][4];
+ float max;
+ int maxj;
+
+ /* Set inverse to identity */
+ for (i=0; i<4; i++)
+ for (j=0; j<4; j++)
+ inverse[i][j] = 0;
+ for (i=0; i<4; i++)
+ inverse[i][i] = 1;
+
+ /* Copy original matrix so we don't mess it up */
+ for(i = 0; i < 4; i++)
+ for(j = 0; j <4; j++)
+ tempmat[i][j] = mat[i][j];
+
+ for(i = 0; i < 4; i++) {
+ /* Look for row with max pivot */
+ max = ABS(tempmat[i][i]);
+ maxj = i;
+ for(j = i + 1; j < 4; j++) {
+ if(ABS(tempmat[j][i]) > max) {
+ max = ABS(tempmat[j][i]);
+ maxj = j;
+ }
+ }
+ /* Swap rows if necessary */
+ if (maxj != i) {
+ for( k = 0; k < 4; k++) {
+ SWAP(float, tempmat[i][k], tempmat[maxj][k]);
+ SWAP(float, inverse[i][k], inverse[maxj][k]);
+ }
+ }
+
+ temp = tempmat[i][i];
+ if (temp == 0)
+ return 0; /* No non-zero pivot */
+ for(k = 0; k < 4; k++) {
+ tempmat[i][k] /= temp;
+ inverse[i][k] /= temp;
+ }
+ for(j = 0; j < 4; j++) {
+ if(j != i) {
+ temp = tempmat[j][i];
+ for(k = 0; k < 4; k++) {
+ tempmat[j][k] -= tempmat[i][k]*temp;
+ inverse[j][k] -= inverse[i][k]*temp;
+ }
+ }
+ }
+ }
+ return 1;
+}
+
+/* ------------------------------------------------------------------------- */
+void MTC_Mat3CpyMat4(float m1[][3], float m2[][4])
+{
+
+ m1[0][0]= m2[0][0];
+ m1[0][1]= m2[0][1];
+ m1[0][2]= m2[0][2];
+
+ m1[1][0]= m2[1][0];
+ m1[1][1]= m2[1][1];
+ m1[1][2]= m2[1][2];
+
+ m1[2][0]= m2[2][0];
+ m1[2][1]= m2[2][1];
+ m1[2][2]= m2[2][2];
+}
+
+/* ------------------------------------------------------------------------- */
+
+void MTC_Mat3CpyMat3(float m1[][3], float m2[][3])
+{
+ memcpy(m1, m2, 3*3*sizeof(float));
+}
+
+/* ------------------------------------------------------------------------- */
+/* void Mat3MulMat3(float m1[][3], float m3[][3], float m2[][3]) */
+void MTC_Mat3MulMat3(float m1[][3], float m3[][3], float m2[][3])
+{
+ /* be careful about this rewrite... */
+ /* m1[i][j] = m2[i][k]*m3[k][j], args are flipped! */
+ m1[0][0]= m2[0][0]*m3[0][0] + m2[0][1]*m3[1][0] + m2[0][2]*m3[2][0];
+ m1[0][1]= m2[0][0]*m3[0][1] + m2[0][1]*m3[1][1] + m2[0][2]*m3[2][1];
+ m1[0][2]= m2[0][0]*m3[0][2] + m2[0][1]*m3[1][2] + m2[0][2]*m3[2][2];
+
+ m1[1][0]= m2[1][0]*m3[0][0] + m2[1][1]*m3[1][0] + m2[1][2]*m3[2][0];
+ m1[1][1]= m2[1][0]*m3[0][1] + m2[1][1]*m3[1][1] + m2[1][2]*m3[2][1];
+ m1[1][2]= m2[1][0]*m3[0][2] + m2[1][1]*m3[1][2] + m2[1][2]*m3[2][2];
+
+ m1[2][0]= m2[2][0]*m3[0][0] + m2[2][1]*m3[1][0] + m2[2][2]*m3[2][0];
+ m1[2][1]= m2[2][0]*m3[0][1] + m2[2][1]*m3[1][1] + m2[2][2]*m3[2][1];
+ m1[2][2]= m2[2][0]*m3[0][2] + m2[2][1]*m3[1][2] + m2[2][2]*m3[2][2];
+
+/* m1[0]= m2[0]*m3[0] + m2[1]*m3[3] + m2[2]*m3[6]; */
+/* m1[1]= m2[0]*m3[1] + m2[1]*m3[4] + m2[2]*m3[7]; */
+/* m1[2]= m2[0]*m3[2] + m2[1]*m3[5] + m2[2]*m3[8]; */
+/* m1+=3; */
+/* m2+=3; */
+/* m1[0]= m2[0]*m3[0] + m2[1]*m3[3] + m2[2]*m3[6]; */
+/* m1[1]= m2[0]*m3[1] + m2[1]*m3[4] + m2[2]*m3[7]; */
+/* m1[2]= m2[0]*m3[2] + m2[1]*m3[5] + m2[2]*m3[8]; */
+/* m1+=3; */
+/* m2+=3; */
+/* m1[0]= m2[0]*m3[0] + m2[1]*m3[3] + m2[2]*m3[6]; */
+/* m1[1]= m2[0]*m3[1] + m2[1]*m3[4] + m2[2]*m3[7]; */
+/* m1[2]= m2[0]*m3[2] + m2[1]*m3[5] + m2[2]*m3[8]; */
+} /* end of void Mat3MulMat3(float m1[][3], float m3[][3], float m2[][3]) */
+
+/* ------------------------------------------------------------------------- */
+
+void MTC_Mat4Ortho(float mat[][4])
+{
+ float len;
+
+ len= MTC_normalize3DF(mat[0]);
+ if(len!=0.0) mat[0][3]/= len;
+ len= MTC_normalize3DF(mat[1]);
+ if(len!=0.0) mat[1][3]/= len;
+ len= MTC_normalize3DF(mat[2]);
+ if(len!=0.0) mat[2][3]/= len;
+}
+
+/* ------------------------------------------------------------------------- */
+
+void MTC_Mat4Mul3Vecfl(float mat[][4], float *vec)
+{
+ float x,y;
+ /* vec = mat^T dot vec !!! or vec a row, then vec = vec dot mat*/
+
+ x= vec[0];
+ y= vec[1];
+ vec[0]= x*mat[0][0] + y*mat[1][0] + mat[2][0]*vec[2];
+ vec[1]= x*mat[0][1] + y*mat[1][1] + mat[2][1]*vec[2];
+ vec[2]= x*mat[0][2] + y*mat[1][2] + mat[2][2]*vec[2];
+}
+
+/* ------------------------------------------------------------------------- */
+
+void MTC_Mat4One(float m[][4])
+{
+
+ m[0][0]= m[1][1]= m[2][2]= m[3][3]= 1.0;
+ m[0][1]= m[0][2]= m[0][3]= 0.0;
+ m[1][0]= m[1][2]= m[1][3]= 0.0;
+ m[2][0]= m[2][1]= m[2][3]= 0.0;
+ m[3][0]= m[3][1]= m[3][2]= 0.0;
+}
+
+
+/* ------------------------------------------------------------------------- */
+/* Result is a 3-vector!*/
+void MTC_Mat3MulVecd(float mat[][3], double *vec)
+{
+ double x,y;
+
+ /* vec = mat^T dot vec !!! or vec a row, then vec = vec dot mat*/
+ x=vec[0];
+ y=vec[1];
+ vec[0]= x * mat[0][0] + y * mat[1][0] + mat[2][0] * vec[2];
+ vec[1]= x * mat[0][1] + y * mat[1][1] + mat[2][1] * vec[2];
+ vec[2]= x * mat[0][2] + y * mat[1][2] + mat[2][2] * vec[2];
+}
+
+/* ------------------------------------------------------------------------- */
+
+void MTC_Mat3Inv(float m1[][3], float m2[][3])
+{
+ short a,b;
+ float det;
+
+ /* first adjoint */
+ MTC_Mat3Adj(m1,m2);
+
+ /* then determinant old mat! */
+ det= m2[0][0]* (m2[1][1]*m2[2][2] - m2[1][2]*m2[2][1])
+ -m2[1][0]* (m2[0][1]*m2[2][2] - m2[0][2]*m2[2][1])
+ +m2[2][0]* (m2[0][1]*m2[1][2] - m2[0][2]*m2[1][1]);
+
+ if(det==0) det=1;
+ det= 1/det;
+ for(a=0;a<3;a++) {
+ for(b=0;b<3;b++) {
+ m1[a][b]*=det;
+ }
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+void MTC_Mat3Adj(float m1[][3], float m[][3])
+{
+ m1[0][0]=m[1][1]*m[2][2]-m[1][2]*m[2][1];
+ m1[0][1]= -m[0][1]*m[2][2]+m[0][2]*m[2][1];
+ m1[0][2]=m[0][1]*m[1][2]-m[0][2]*m[1][1];
+
+ m1[1][0]= -m[1][0]*m[2][2]+m[1][2]*m[2][0];
+ m1[1][1]=m[0][0]*m[2][2]-m[0][2]*m[2][0];
+ m1[1][2]= -m[0][0]*m[1][2]+m[0][2]*m[1][0];
+
+ m1[2][0]=m[1][0]*m[2][1]-m[1][1]*m[2][0];
+ m1[2][1]= -m[0][0]*m[2][1]+m[0][1]*m[2][0];
+ m1[2][2]=m[0][0]*m[1][1]-m[0][1]*m[1][0];
+}
+
+/* ------------------------------------------------------------------------- */
+
+void MTC_Mat3One(float m[][3])
+{
+
+ m[0][0]= m[1][1]= m[2][2]= 1.0;
+ m[0][1]= m[0][2]= 0.0;
+ m[1][0]= m[1][2]= 0.0;
+ m[2][0]= m[2][1]= 0.0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+void MTC_Mat4SwapMat4(float m1[][4], float m2[][4])
+{
+ float t;
+ int i, j;
+
+ for(i = 0; i < 4; i++) {
+ for (j = 0; j < 4; j++) {
+ t = m1[i][j];
+ m1[i][j] = m2[i][j];
+ m2[i][j] = t;
+ }
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+void MTC_Mat4MulVec4fl(float mat[][4], float *vec)
+{
+ float x,y,z;
+
+ x = vec[0];
+ y = vec[1];
+ z = vec[2];
+ vec[0] = x*mat[0][0] + y*mat[1][0] + z*mat[2][0] + mat[3][0]*vec[3];
+ vec[1] = x*mat[0][1] + y*mat[1][1] + z*mat[2][1] + mat[3][1]*vec[3];
+ vec[2] = x*mat[0][2] + y*mat[1][2] + z*mat[2][2] + mat[3][2]*vec[3];
+ vec[3] = x*mat[0][3] + y*mat[1][3] + z*mat[2][3] + mat[3][3]*vec[3];
+}
+
+/* ------------------------------------------------------------------------- */
+
+void MTC_Mat4CpyMat3nc(float m1[][4], float m2[][3]) /* no clear */
+{
+ m1[0][0]= m2[0][0];
+ m1[0][1]= m2[0][1];
+ m1[0][2]= m2[0][2];
+
+ m1[1][0]= m2[1][0];
+ m1[1][1]= m2[1][1];
+ m1[1][2]= m2[1][2];
+
+ m1[2][0]= m2[2][0];
+ m1[2][1]= m2[2][1];
+ m1[2][2]= m2[2][2];
+}
+
+/* ------------------------------------------------------------------------- */
+
+void MTC_Mat4MulMat33(float m1[][3], float m2[][4], float m3[][3])
+{
+ /* m1_i_j = m2_i_k * m3_k_j ? */
+
+ m1[0][0] = m2[0][0]*m3[0][0] + m2[0][1]*m3[1][0] + m2[0][2]*m3[2][0];
+ m1[0][1] = m2[0][0]*m3[0][1] + m2[0][1]*m3[1][1] + m2[0][2]*m3[2][1];
+ m1[0][2] = m2[0][0]*m3[0][2] + m2[0][1]*m3[1][2] + m2[0][2]*m3[2][2];
+
+ m1[1][0] = m2[1][0]*m3[0][0] + m2[1][1]*m3[1][0] + m2[1][2]*m3[2][0];
+ m1[1][1] = m2[1][0]*m3[0][1] + m2[1][1]*m3[1][1] + m2[1][2]*m3[2][1];
+ m1[1][2] = m2[1][0]*m3[0][2] + m2[1][1]*m3[1][2] + m2[1][2]*m3[2][2];
+
+ m1[2][0] = m2[2][0]*m3[0][0] + m2[2][1]*m3[1][0] + m2[2][2]*m3[2][0];
+ m1[2][1] = m2[2][0]*m3[0][1] + m2[2][1]*m3[1][1] + m2[2][2]*m3[2][1];
+ m1[2][2] = m2[2][0]*m3[0][2] + m2[2][1]*m3[1][2] + m2[2][2]*m3[2][2];
+
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* eof */
diff --git a/source/blender/blenlib/intern/noise.c b/source/blender/blenlib/intern/noise.c
new file mode 100644
index 00000000000..4fa2d1fdd48
--- /dev/null
+++ b/source/blender/blenlib/intern/noise.c
@@ -0,0 +1,1392 @@
+/*
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ *
+ */
+
+#ifdef _WIN32
+#pragma warning (disable : 4244) // "conversion from double to float"
+#pragma warning (disable : 4305) // "truncation from const double to float"
+#endif
+
+#include <math.h>
+#include "BLI_blenlib.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* local */
+float noise3_perlin(float vec[3]);
+float turbulence_perlin(float *point, float lofreq, float hifreq);
+float turbulencep(float noisesize, float x, float y, float z, int nr);
+
+#define HASHVEC(x,y,z) hashvectf+3*hash[ (hash[ (hash[(z) & 255]+(y)) & 255]+(x)) & 255]
+
+/* needed for voronoi */
+#define HASHPNT(x,y,z) hashpntf+3*hash[ (hash[ (hash[(z) & 255]+(y)) & 255]+(x)) & 255]
+static float hashpntf[768] = {0.536902, 0.020915, 0.501445, 0.216316, 0.517036, 0.822466, 0.965315,
+0.377313, 0.678764, 0.744545, 0.097731, 0.396357, 0.247202, 0.520897,
+0.613396, 0.542124, 0.146813, 0.255489, 0.810868, 0.638641, 0.980742,
+0.292316, 0.357948, 0.114382, 0.861377, 0.629634, 0.722530, 0.714103,
+0.048549, 0.075668, 0.564920, 0.162026, 0.054466, 0.411738, 0.156897,
+0.887657, 0.599368, 0.074249, 0.170277, 0.225799, 0.393154, 0.301348,
+0.057434, 0.293849, 0.442745, 0.150002, 0.398732, 0.184582, 0.915200,
+0.630984, 0.974040, 0.117228, 0.795520, 0.763238, 0.158982, 0.616211,
+0.250825, 0.906539, 0.316874, 0.676205, 0.234720, 0.667673, 0.792225,
+0.273671, 0.119363, 0.199131, 0.856716, 0.828554, 0.900718, 0.705960,
+0.635923, 0.989433, 0.027261, 0.283507, 0.113426, 0.388115, 0.900176,
+0.637741, 0.438802, 0.715490, 0.043692, 0.202640, 0.378325, 0.450325,
+0.471832, 0.147803, 0.906899, 0.524178, 0.784981, 0.051483, 0.893369,
+0.596895, 0.275635, 0.391483, 0.844673, 0.103061, 0.257322, 0.708390,
+0.504091, 0.199517, 0.660339, 0.376071, 0.038880, 0.531293, 0.216116,
+0.138672, 0.907737, 0.807994, 0.659582, 0.915264, 0.449075, 0.627128,
+0.480173, 0.380942, 0.018843, 0.211808, 0.569701, 0.082294, 0.689488,
+0.573060, 0.593859, 0.216080, 0.373159, 0.108117, 0.595539, 0.021768,
+0.380297, 0.948125, 0.377833, 0.319699, 0.315249, 0.972805, 0.792270,
+0.445396, 0.845323, 0.372186, 0.096147, 0.689405, 0.423958, 0.055675,
+0.117940, 0.328456, 0.605808, 0.631768, 0.372170, 0.213723, 0.032700,
+0.447257, 0.440661, 0.728488, 0.299853, 0.148599, 0.649212, 0.498381,
+0.049921, 0.496112, 0.607142, 0.562595, 0.990246, 0.739659, 0.108633,
+0.978156, 0.209814, 0.258436, 0.876021, 0.309260, 0.600673, 0.713597,
+0.576967, 0.641402, 0.853930, 0.029173, 0.418111, 0.581593, 0.008394,
+0.589904, 0.661574, 0.979326, 0.275724, 0.111109, 0.440472, 0.120839,
+0.521602, 0.648308, 0.284575, 0.204501, 0.153286, 0.822444, 0.300786,
+0.303906, 0.364717, 0.209038, 0.916831, 0.900245, 0.600685, 0.890002,
+0.581660, 0.431154, 0.705569, 0.551250, 0.417075, 0.403749, 0.696652,
+0.292652, 0.911372, 0.690922, 0.323718, 0.036773, 0.258976, 0.274265,
+0.225076, 0.628965, 0.351644, 0.065158, 0.080340, 0.467271, 0.130643,
+0.385914, 0.919315, 0.253821, 0.966163, 0.017439, 0.392610, 0.478792,
+0.978185, 0.072691, 0.982009, 0.097987, 0.731533, 0.401233, 0.107570,
+0.349587, 0.479122, 0.700598, 0.481751, 0.788429, 0.706864, 0.120086,
+0.562691, 0.981797, 0.001223, 0.192120, 0.451543, 0.173092, 0.108960,
+0.549594, 0.587892, 0.657534, 0.396365, 0.125153, 0.666420, 0.385823,
+0.890916, 0.436729, 0.128114, 0.369598, 0.759096, 0.044677, 0.904752,
+0.088052, 0.621148, 0.005047, 0.452331, 0.162032, 0.494238, 0.523349,
+0.741829, 0.698450, 0.452316, 0.563487, 0.819776, 0.492160, 0.004210,
+0.647158, 0.551475, 0.362995, 0.177937, 0.814722, 0.727729, 0.867126,
+0.997157, 0.108149, 0.085726, 0.796024, 0.665075, 0.362462, 0.323124,
+0.043718, 0.042357, 0.315030, 0.328954, 0.870845, 0.683186, 0.467922,
+0.514894, 0.809971, 0.631979, 0.176571, 0.366320, 0.850621, 0.505555,
+0.749551, 0.750830, 0.401714, 0.481216, 0.438393, 0.508832, 0.867971,
+0.654581, 0.058204, 0.566454, 0.084124, 0.548539, 0.902690, 0.779571,
+0.562058, 0.048082, 0.863109, 0.079290, 0.713559, 0.783496, 0.265266,
+0.672089, 0.786939, 0.143048, 0.086196, 0.876129, 0.408708, 0.229312,
+0.629995, 0.206665, 0.207308, 0.710079, 0.341704, 0.264921, 0.028748,
+0.629222, 0.470173, 0.726228, 0.125243, 0.328249, 0.794187, 0.741340,
+0.489895, 0.189396, 0.724654, 0.092841, 0.039809, 0.860126, 0.247701,
+0.655331, 0.964121, 0.672536, 0.044522, 0.690567, 0.837238, 0.631520,
+0.953734, 0.352484, 0.289026, 0.034152, 0.852575, 0.098454, 0.795529,
+0.452181, 0.826159, 0.186993, 0.820725, 0.440328, 0.922137, 0.704592,
+0.915437, 0.738183, 0.733461, 0.193798, 0.929213, 0.161390, 0.318547,
+0.888751, 0.430968, 0.740837, 0.193544, 0.872253, 0.563074, 0.274598,
+0.347805, 0.666176, 0.449831, 0.800991, 0.588727, 0.052296, 0.714761,
+0.420620, 0.570325, 0.057550, 0.210888, 0.407312, 0.662848, 0.924382,
+0.895958, 0.775198, 0.688605, 0.025721, 0.301913, 0.791408, 0.500602,
+0.831984, 0.828509, 0.642093, 0.494174, 0.525880, 0.446365, 0.440063,
+0.763114, 0.630358, 0.223943, 0.333806, 0.906033, 0.498306, 0.241278,
+0.427640, 0.772683, 0.198082, 0.225379, 0.503894, 0.436599, 0.016503,
+0.803725, 0.189878, 0.291095, 0.499114, 0.151573, 0.079031, 0.904618,
+0.708535, 0.273900, 0.067419, 0.317124, 0.936499, 0.716511, 0.543845,
+0.939909, 0.826574, 0.715090, 0.154864, 0.750150, 0.845808, 0.648108,
+0.556564, 0.644757, 0.140873, 0.799167, 0.632989, 0.444245, 0.471978,
+0.435910, 0.359793, 0.216241, 0.007633, 0.337236, 0.857863, 0.380247,
+0.092517, 0.799973, 0.919000, 0.296798, 0.096989, 0.854831, 0.165369,
+0.568475, 0.216855, 0.020457, 0.835511, 0.538039, 0.999742, 0.620226,
+0.244053, 0.060399, 0.323007, 0.294874, 0.988899, 0.384919, 0.735655,
+0.773428, 0.549776, 0.292882, 0.660611, 0.593507, 0.621118, 0.175269,
+0.682119, 0.794493, 0.868197, 0.632150, 0.807823, 0.509656, 0.482035,
+0.001780, 0.259126, 0.358002, 0.280263, 0.192985, 0.290367, 0.208111,
+0.917633, 0.114422, 0.925491, 0.981110, 0.255570, 0.974862, 0.016629,
+0.552599, 0.575741, 0.612978, 0.615965, 0.803615, 0.772334, 0.089745,
+0.838812, 0.634542, 0.113709, 0.755832, 0.577589, 0.667489, 0.529834,
+0.325660, 0.817597, 0.316557, 0.335093, 0.737363, 0.260951, 0.737073,
+0.049540, 0.735541, 0.988891, 0.299116, 0.147695, 0.417271, 0.940811,
+0.524160, 0.857968, 0.176403, 0.244835, 0.485759, 0.033353, 0.280319,
+0.750688, 0.755809, 0.924208, 0.095956, 0.962504, 0.275584, 0.173715,
+0.942716, 0.706721, 0.078464, 0.576716, 0.804667, 0.559249, 0.900611,
+0.646904, 0.432111, 0.927885, 0.383277, 0.269973, 0.114244, 0.574867,
+0.150703, 0.241855, 0.272871, 0.199950, 0.079719, 0.868566, 0.962833,
+0.789122, 0.320025, 0.905554, 0.234876, 0.991356, 0.061913, 0.732911,
+0.785960, 0.874074, 0.069035, 0.658632, 0.309901, 0.023676, 0.791603,
+0.764661, 0.661278, 0.319583, 0.829650, 0.117091, 0.903124, 0.982098,
+0.161631, 0.193576, 0.670428, 0.857390, 0.003760, 0.572578, 0.222162,
+0.114551, 0.420118, 0.530404, 0.470682, 0.525527, 0.764281, 0.040596,
+0.443275, 0.501124, 0.816161, 0.417467, 0.332172, 0.447565, 0.614591,
+0.559246, 0.805295, 0.226342, 0.155065, 0.714630, 0.160925, 0.760001,
+0.453456, 0.093869, 0.406092, 0.264801, 0.720370, 0.743388, 0.373269,
+0.403098, 0.911923, 0.897249, 0.147038, 0.753037, 0.516093, 0.739257,
+0.175018, 0.045768, 0.735857, 0.801330, 0.927708, 0.240977, 0.591870,
+0.921831, 0.540733, 0.149100, 0.423152, 0.806876, 0.397081, 0.061100,
+0.811630, 0.044899, 0.460915, 0.961202, 0.822098, 0.971524, 0.867608,
+0.773604, 0.226616, 0.686286, 0.926972, 0.411613, 0.267873, 0.081937,
+0.226124, 0.295664, 0.374594, 0.533240, 0.237876, 0.669629, 0.599083,
+0.513081, 0.878719, 0.201577, 0.721296, 0.495038, 0.079760, 0.965959,
+0.233090, 0.052496, 0.714748, 0.887844, 0.308724, 0.972885, 0.723337,
+0.453089, 0.914474, 0.704063, 0.823198, 0.834769, 0.906561, 0.919600,
+0.100601, 0.307564, 0.901977, 0.468879, 0.265376, 0.885188, 0.683875,
+0.868623, 0.081032, 0.466835, 0.199087, 0.663437, 0.812241, 0.311337,
+0.821361, 0.356628, 0.898054, 0.160781, 0.222539, 0.714889, 0.490287,
+0.984915, 0.951755, 0.964097, 0.641795, 0.815472, 0.852732, 0.862074,
+0.051108, 0.440139, 0.323207, 0.517171, 0.562984, 0.115295, 0.743103,
+0.977914, 0.337596, 0.440694, 0.535879, 0.959427, 0.351427, 0.704361,
+0.010826, 0.131162, 0.577080, 0.349572, 0.774892, 0.425796, 0.072697,
+0.500001, 0.267322, 0.909654, 0.206176, 0.223987, 0.937698, 0.323423,
+0.117501, 0.490308, 0.474372, 0.689943, 0.168671, 0.719417, 0.188928,
+0.330464, 0.265273, 0.446271, 0.171933, 0.176133, 0.474616, 0.140182,
+0.114246, 0.905043, 0.713870, 0.555261, 0.951333};
+
+unsigned char hash[512]= {
+0xA2,0xA0,0x19,0x3B,0xF8,0xEB,0xAA,0xEE,0xF3,0x1C,0x67,0x28,0x1D,0xED,0x0,0xDE,0x95,0x2E,0xDC,0x3F,0x3A,0x82,0x35,0x4D,0x6C,0xBA,0x36,0xD0,0xF6,0xC,0x79,0x32,0xD1,0x59,0xF4,0x8,0x8B,0x63,0x89,0x2F,0xB8,0xB4,0x97,0x83,0xF2,0x8F,0x18,0xC7,0x51,0x14,0x65,0x87,0x48,0x20,0x42,0xA8,0x80,0xB5,0x40,0x13,0xB2,0x22,0x7E,0x57,
+0xBC,0x7F,0x6B,0x9D,0x86,0x4C,0xC8,0xDB,0x7C,0xD5,0x25,0x4E,0x5A,0x55,0x74,0x50,0xCD,0xB3,0x7A,0xBB,0xC3,0xCB,0xB6,0xE2,0xE4,0xEC,0xFD,0x98,0xB,0x96,0xD3,0x9E,0x5C,0xA1,0x64,0xF1,0x81,0x61,0xE1,0xC4,0x24,0x72,0x49,0x8C,0x90,0x4B,0x84,0x34,0x38,0xAB,0x78,0xCA,0x1F,0x1,0xD7,0x93,0x11,0xC1,0x58,0xA9,0x31,0xF9,0x44,0x6D,
+0xBF,0x33,0x9C,0x5F,0x9,0x94,0xA3,0x85,0x6,0xC6,0x9A,0x1E,0x7B,0x46,0x15,0x30,0x27,0x2B,0x1B,0x71,0x3C,0x5B,0xD6,0x6F,0x62,0xAC,0x4F,0xC2,0xC0,0xE,0xB1,0x23,0xA7,0xDF,0x47,0xB0,0x77,0x69,0x5,0xE9,0xE6,0xE7,0x76,0x73,0xF,0xFE,0x6E,0x9B,0x56,0xEF,0x12,0xA5,0x37,0xFC,0xAE,0xD9,0x3,0x8E,0xDD,0x10,0xB9,0xCE,0xC9,0x8D,
+0xDA,0x2A,0xBD,0x68,0x17,0x9F,0xBE,0xD4,0xA,0xCC,0xD2,0xE8,0x43,0x3D,0x70,0xB7,0x2,0x7D,0x99,0xD8,0xD,0x60,0x8A,0x4,0x2C,0x3E,0x92,0xE5,0xAF,0x53,0x7,0xE0,0x29,0xA6,0xC5,0xE3,0xF5,0xF7,0x4A,0x41,0x26,0x6A,0x16,0x5E,0x52,0x2D,0x21,0xAD,0xF0,0x91,0xFF,0xEA,0x54,0xFA,0x66,0x1A,0x45,0x39,0xCF,0x75,0xA4,0x88,0xFB,0x5D,
+0xA2,0xA0,0x19,0x3B,0xF8,0xEB,0xAA,0xEE,0xF3,0x1C,0x67,0x28,0x1D,0xED,0x0,0xDE,0x95,0x2E,0xDC,0x3F,0x3A,0x82,0x35,0x4D,0x6C,0xBA,0x36,0xD0,0xF6,0xC,0x79,0x32,0xD1,0x59,0xF4,0x8,0x8B,0x63,0x89,0x2F,0xB8,0xB4,0x97,0x83,0xF2,0x8F,0x18,0xC7,0x51,0x14,0x65,0x87,0x48,0x20,0x42,0xA8,0x80,0xB5,0x40,0x13,0xB2,0x22,0x7E,0x57,
+0xBC,0x7F,0x6B,0x9D,0x86,0x4C,0xC8,0xDB,0x7C,0xD5,0x25,0x4E,0x5A,0x55,0x74,0x50,0xCD,0xB3,0x7A,0xBB,0xC3,0xCB,0xB6,0xE2,0xE4,0xEC,0xFD,0x98,0xB,0x96,0xD3,0x9E,0x5C,0xA1,0x64,0xF1,0x81,0x61,0xE1,0xC4,0x24,0x72,0x49,0x8C,0x90,0x4B,0x84,0x34,0x38,0xAB,0x78,0xCA,0x1F,0x1,0xD7,0x93,0x11,0xC1,0x58,0xA9,0x31,0xF9,0x44,0x6D,
+0xBF,0x33,0x9C,0x5F,0x9,0x94,0xA3,0x85,0x6,0xC6,0x9A,0x1E,0x7B,0x46,0x15,0x30,0x27,0x2B,0x1B,0x71,0x3C,0x5B,0xD6,0x6F,0x62,0xAC,0x4F,0xC2,0xC0,0xE,0xB1,0x23,0xA7,0xDF,0x47,0xB0,0x77,0x69,0x5,0xE9,0xE6,0xE7,0x76,0x73,0xF,0xFE,0x6E,0x9B,0x56,0xEF,0x12,0xA5,0x37,0xFC,0xAE,0xD9,0x3,0x8E,0xDD,0x10,0xB9,0xCE,0xC9,0x8D,
+0xDA,0x2A,0xBD,0x68,0x17,0x9F,0xBE,0xD4,0xA,0xCC,0xD2,0xE8,0x43,0x3D,0x70,0xB7,0x2,0x7D,0x99,0xD8,0xD,0x60,0x8A,0x4,0x2C,0x3E,0x92,0xE5,0xAF,0x53,0x7,0xE0,0x29,0xA6,0xC5,0xE3,0xF5,0xF7,0x4A,0x41,0x26,0x6A,0x16,0x5E,0x52,0x2D,0x21,0xAD,0xF0,0x91,0xFF,0xEA,0x54,0xFA,0x66,0x1A,0x45,0x39,0xCF,0x75,0xA4,0x88,0xFB,0x5D,
+};
+
+
+float hashvectf[768]= {
+0.33783,0.715698,-0.611206,-0.944031,-0.326599,-0.045624,-0.101074,-0.416443,-0.903503,0.799286,0.49411,-0.341949,-0.854645,0.518036,0.033936,0.42514,-0.437866,-0.792114,-0.358948,0.597046,0.717377,-0.985413,0.144714,0.089294,-0.601776,-0.33728,-0.723907,-0.449921,0.594513,0.666382,0.208313,-0.10791,
+0.972076,0.575317,0.060425,0.815643,0.293365,-0.875702,-0.383453,0.293762,0.465759,0.834686,-0.846008,-0.233398,-0.47934,-0.115814,0.143036,-0.98291,0.204681,-0.949036,-0.239532,0.946716,-0.263947,0.184326,-0.235596,0.573822,0.784332,0.203705,-0.372253,-0.905487,0.756989,-0.651031,0.055298,0.497803,
+0.814697,-0.297363,-0.16214,0.063995,-0.98468,-0.329254,0.834381,0.441925,0.703827,-0.527039,-0.476227,0.956421,0.266113,0.119781,0.480133,0.482849,0.7323,-0.18631,0.961212,-0.203125,-0.748474,-0.656921,-0.090393,-0.085052,-0.165253,0.982544,-0.76947,0.628174,-0.115234,0.383148,0.537659,0.751068,
+0.616486,-0.668488,-0.415924,-0.259979,-0.630005,0.73175,0.570953,-0.087952,0.816223,-0.458008,0.023254,0.888611,-0.196167,0.976563,-0.088287,-0.263885,-0.69812,-0.665527,0.437134,-0.892273,-0.112793,-0.621674,-0.230438,0.748566,0.232422,0.900574,-0.367249,0.22229,-0.796143,0.562744,-0.665497,-0.73764,
+0.11377,0.670135,0.704803,0.232605,0.895599,0.429749,-0.114655,-0.11557,-0.474243,0.872742,0.621826,0.604004,-0.498444,-0.832214,0.012756,0.55426,-0.702484,0.705994,-0.089661,-0.692017,0.649292,0.315399,-0.175995,-0.977997,0.111877,0.096954,-0.04953,0.994019,0.635284,-0.606689,-0.477783,-0.261261,
+-0.607422,-0.750153,0.983276,0.165436,0.075958,-0.29837,0.404083,-0.864655,-0.638672,0.507721,0.578156,0.388214,0.412079,0.824249,0.556183,-0.208832,0.804352,0.778442,0.562012,0.27951,-0.616577,0.781921,-0.091522,0.196289,0.051056,0.979187,-0.121216,0.207153,-0.970734,-0.173401,-0.384735,0.906555,
+0.161499,-0.723236,-0.671387,0.178497,-0.006226,-0.983887,-0.126038,0.15799,0.97934,0.830475,-0.024811,0.556458,-0.510132,-0.76944,0.384247,0.81424,0.200104,-0.544891,-0.112549,-0.393311,-0.912445,0.56189,0.152222,-0.813049,0.198914,-0.254517,-0.946381,-0.41217,0.690979,-0.593811,-0.407257,0.324524,
+0.853668,-0.690186,0.366119,-0.624115,-0.428345,0.844147,-0.322296,-0.21228,-0.297546,-0.930756,-0.273071,0.516113,0.811798,0.928314,0.371643,0.007233,0.785828,-0.479218,-0.390778,-0.704895,0.058929,0.706818,0.173248,0.203583,0.963562,0.422211,-0.904297,-0.062469,-0.363312,-0.182465,0.913605,0.254028,
+-0.552307,-0.793945,-0.28891,-0.765747,-0.574554,0.058319,0.291382,0.954803,0.946136,-0.303925,0.111267,-0.078156,0.443695,-0.892731,0.182098,0.89389,0.409515,-0.680298,-0.213318,0.701141,0.062469,0.848389,-0.525635,-0.72879,-0.641846,0.238342,-0.88089,0.427673,0.202637,-0.532501,-0.21405,0.818878,
+0.948975,-0.305084,0.07962,0.925446,0.374664,0.055817,0.820923,0.565491,0.079102,0.25882,0.099792,-0.960724,-0.294617,0.910522,0.289978,0.137115,0.320038,-0.937408,-0.908386,0.345276,-0.235718,-0.936218,0.138763,0.322754,0.366577,0.925934,-0.090637,0.309296,-0.686829,-0.657684,0.66983,0.024445,
+0.742065,-0.917999,-0.059113,-0.392059,0.365509,0.462158,-0.807922,0.083374,0.996399,-0.014801,0.593842,0.253143,-0.763672,0.974976,-0.165466,0.148285,0.918976,0.137299,0.369537,0.294952,0.694977,0.655731,0.943085,0.152618,-0.295319,0.58783,-0.598236,0.544495,0.203796,0.678223,0.705994,-0.478821,
+-0.661011,0.577667,0.719055,-0.1698,-0.673828,-0.132172,-0.965332,0.225006,-0.981873,-0.14502,0.121979,0.763458,0.579742,0.284546,-0.893188,0.079681,0.442474,-0.795776,-0.523804,0.303802,0.734955,0.67804,-0.007446,0.15506,0.986267,-0.056183,0.258026,0.571503,-0.778931,-0.681549,-0.702087,-0.206116,
+-0.96286,-0.177185,0.203613,-0.470978,-0.515106,0.716095,-0.740326,0.57135,0.354095,-0.56012,-0.824982,-0.074982,-0.507874,0.753204,0.417969,-0.503113,0.038147,0.863342,0.594025,0.673553,-0.439758,-0.119873,-0.005524,-0.992737,0.098267,-0.213776,0.971893,-0.615631,0.643951,0.454163,0.896851,-0.441071,
+0.032166,-0.555023,0.750763,-0.358093,0.398773,0.304688,0.864929,-0.722961,0.303589,0.620544,-0.63559,-0.621948,-0.457306,-0.293243,0.072327,0.953278,-0.491638,0.661041,-0.566772,-0.304199,-0.572083,-0.761688,0.908081,-0.398956,0.127014,-0.523621,-0.549683,-0.650848,-0.932922,-0.19986,0.299408,0.099426,
+0.140869,0.984985,-0.020325,-0.999756,-0.002319,0.952667,0.280853,-0.11615,-0.971893,0.082581,0.220337,0.65921,0.705292,-0.260651,0.733063,-0.175537,0.657043,-0.555206,0.429504,-0.712189,0.400421,-0.89859,0.179352,0.750885,-0.19696,0.630341,0.785675,-0.569336,0.241821,-0.058899,-0.464111,0.883789,
+0.129608,-0.94519,0.299622,-0.357819,0.907654,0.219238,-0.842133,-0.439117,-0.312927,-0.313477,0.84433,0.434479,-0.241211,0.053253,0.968994,0.063873,0.823273,0.563965,0.476288,0.862152,-0.172516,0.620941,-0.298126,0.724915,0.25238,-0.749359,-0.612122,-0.577545,0.386566,0.718994,-0.406342,-0.737976,
+0.538696,0.04718,0.556305,0.82959,-0.802856,0.587463,0.101166,-0.707733,-0.705963,0.026428,0.374908,0.68457,0.625092,0.472137,0.208405,-0.856506,-0.703064,-0.581085,-0.409821,-0.417206,-0.736328,0.532623,-0.447876,-0.20285,-0.870728,0.086945,-0.990417,0.107086,0.183685,0.018341,-0.982788,0.560638,
+-0.428864,0.708282,0.296722,-0.952576,-0.0672,0.135773,0.990265,0.030243,-0.068787,0.654724,0.752686,0.762604,-0.551758,0.337585,-0.819611,-0.407684,0.402466,-0.727844,-0.55072,-0.408539,-0.855774,-0.480011,0.19281,0.693176,-0.079285,0.716339,0.226013,0.650116,-0.725433,0.246704,0.953369,-0.173553,
+-0.970398,-0.239227,-0.03244,0.136383,-0.394318,0.908752,0.813232,0.558167,0.164368,0.40451,0.549042,-0.731323,-0.380249,-0.566711,0.730865,0.022156,0.932739,0.359741,0.00824,0.996552,-0.082306,0.956635,-0.065338,-0.283722,-0.743561,0.008209,0.668579,-0.859589,-0.509674,0.035767,-0.852234,0.363678,
+-0.375977,-0.201965,-0.970795,-0.12915,0.313477,0.947327,0.06546,-0.254028,-0.528259,0.81015,0.628052,0.601105,0.49411,-0.494385,0.868378,0.037933,0.275635,-0.086426,0.957336,-0.197937,0.468903,-0.860748,0.895599,0.399384,0.195801,0.560791,0.825012,-0.069214,0.304199,-0.849487,0.43103,0.096375,
+0.93576,0.339111,-0.051422,0.408966,-0.911072,0.330444,0.942841,-0.042389,-0.452362,-0.786407,0.420563,0.134308,-0.933472,-0.332489,0.80191,-0.566711,-0.188934,-0.987946,-0.105988,0.112518,-0.24408,0.892242,-0.379791,-0.920502,0.229095,-0.316376,0.7789,0.325958,0.535706,-0.912872,0.185211,-0.36377,
+-0.184784,0.565369,-0.803833,-0.018463,0.119537,0.992615,-0.259247,-0.935608,0.239532,-0.82373,-0.449127,-0.345947,-0.433105,0.659515,0.614349,-0.822754,0.378845,-0.423676,0.687195,-0.674835,-0.26889,-0.246582,-0.800842,0.545715,-0.729187,-0.207794,0.651978,0.653534,-0.610443,-0.447388,0.492584,-0.023346,
+0.869934,0.609039,0.009094,-0.79306,0.962494,-0.271088,-0.00885,0.2659,-0.004913,0.963959,0.651245,0.553619,-0.518951,0.280548,-0.84314,0.458618,-0.175293,-0.983215,0.049805,0.035339,-0.979919,0.196045,-0.982941,0.164307,-0.082245,0.233734,-0.97226,-0.005005,-0.747253,-0.611328,0.260437,0.645599,
+0.592773,0.481384,0.117706,-0.949524,-0.29068,-0.535004,-0.791901,-0.294312,-0.627167,-0.214447,0.748718,-0.047974,-0.813477,-0.57959,-0.175537,0.477264,-0.860992,0.738556,-0.414246,-0.53183,0.562561,-0.704071,0.433289,-0.754944,0.64801,-0.100586,0.114716,0.044525,-0.992371,0.966003,0.244873,-0.082764,
+};
+
+/**************************/
+/* IMPROVED PERLIN NOISE */
+/**************************/
+
+#define lerp(t, a, b) ((a)+(t)*((b)-(a)))
+#define npfade(t) ((t)*(t)*(t)*((t)*((t)*6-15)+10))
+
+static float grad(int hash, float x, float y, float z)
+{
+ int h = hash & 15; // CONVERT LO 4 BITS OF HASH CODE
+ float u = h<8 ? x : y, // INTO 12 GRADIENT DIRECTIONS.
+ v = h<4 ? y : h==12||h==14 ? x : z;
+ return ((h&1) == 0 ? u : -u) + ((h&2) == 0 ? v : -v);
+}
+
+/* instead of adding another permutation array, just use hash table defined above */
+static float newPerlin(float x, float y, float z)
+{
+ int A, AA, AB, B, BA, BB;
+ float u=floor(x), v=floor(y), w=floor(z);
+ int X=((int)u) & 255, Y=((int)v) & 255, Z=((int)w) & 255; // FIND UNIT CUBE THAT CONTAINS POINT
+ x -= u; // FIND RELATIVE X,Y,Z
+ y -= v; // OF POINT IN CUBE.
+ z -= w;
+ u = npfade(x); // COMPUTE FADE CURVES
+ v = npfade(y); // FOR EACH OF X,Y,Z.
+ w = npfade(z);
+ A = hash[X ]+Y; AA = hash[A]+Z; AB = hash[A+1]+Z; // HASH COORDINATES OF
+ B = hash[X+1]+Y; BA = hash[B]+Z; BB = hash[B+1]+Z; // THE 8 CUBE CORNERS,
+ return lerp(w, lerp(v, lerp(u, grad(hash[AA ], x , y , z ), // AND ADD
+ grad(hash[BA ], x-1, y , z )), // BLENDED
+ lerp(u, grad(hash[AB ], x , y-1, z ), // RESULTS
+ grad(hash[BB ], x-1, y-1, z ))),// FROM 8
+ lerp(v, lerp(u, grad(hash[AA+1], x , y , z-1 ), // CORNERS
+ grad(hash[BA+1], x-1, y , z-1 )), // OF CUBE
+ lerp(u, grad(hash[AB+1], x , y-1, z-1 ),
+ grad(hash[BB+1], x-1, y-1, z-1 ))));
+}
+
+/* for use with BLI_gNoise()/BLI_gTurbulence(), returns unsigned improved perlin noise */
+static float newPerlinU(float x, float y, float z)
+{
+ return (0.5+0.5*newPerlin(x, y, z));
+}
+
+
+/**************************/
+/* END OF IMPROVED PERLIN */
+/**************************/
+
+/* Was BLI_hnoise(), removed noisesize, so other functions can call it without scaling. */
+static float orgBlenderNoise(float x, float y, float z)
+{
+ register float cn1, cn2, cn3, cn4, cn5, cn6, i, *h;
+ float ox, oy, oz, jx, jy, jz;
+ float n= 0.5;
+ int ix, iy, iz, b00, b01, b10, b11, b20, b21;
+
+ ox= (x- (ix= (int)floor(x)) );
+ oy= (y- (iy= (int)floor(y)) );
+ oz= (z- (iz= (int)floor(z)) );
+
+ jx= ox-1;
+ jy= oy-1;
+ jz= oz-1;
+
+ cn1=ox*ox; cn2=oy*oy; cn3=oz*oz;
+ cn4=jx*jx; cn5=jy*jy; cn6=jz*jz;
+
+ cn1= 1.0-3.0*cn1+2.0*cn1*ox;
+ cn2= 1.0-3.0*cn2+2.0*cn2*oy;
+ cn3= 1.0-3.0*cn3+2.0*cn3*oz;
+ cn4= 1.0-3.0*cn4-2.0*cn4*jx;
+ cn5= 1.0-3.0*cn5-2.0*cn5*jy;
+ cn6= 1.0-3.0*cn6-2.0*cn6*jz;
+
+ b00= hash[ hash[ix & 255]+(iy & 255)];
+ b10= hash[ hash[(ix+1) & 255]+(iy & 255)];
+ b01= hash[ hash[ix & 255]+((iy+1) & 255)];
+ b11= hash[ hash[(ix+1) & 255]+((iy+1) & 255)];
+
+ b20=iz & 255; b21= (iz+1) & 255;
+
+ /* 0 */
+ i= (cn1*cn2*cn3);
+ h=hashvectf+ 3*hash[b20+b00];
+ n+= i*(h[0]*ox+h[1]*oy+h[2]*oz);
+ /* 1 */
+ i= (cn1*cn2*cn6);
+ h=hashvectf+ 3*hash[b21+b00];
+ n+= i*(h[0]*ox+h[1]*oy+h[2]*jz);
+ /* 2 */
+ i= (cn1*cn5*cn3);
+ h=hashvectf+ 3*hash[b20+b01];
+ n+= i*(h[0]*ox+h[1]*jy+h[2]*oz);
+ /* 3 */
+ i= (cn1*cn5*cn6);
+ h=hashvectf+ 3*hash[b21+b01];
+ n+= i*(h[0]*ox+h[1]*jy+h[2]*jz);
+ /* 4 */
+ i= cn4*cn2*cn3;
+ h=hashvectf+ 3*hash[b20+b10];
+ n+= i*(h[0]*jx+h[1]*oy+h[2]*oz);
+ /* 5 */
+ i= cn4*cn2*cn6;
+ h=hashvectf+ 3*hash[b21+b10];
+ n+= i*(h[0]*jx+h[1]*oy+h[2]*jz);
+ /* 6 */
+ i= cn4*cn5*cn3;
+ h=hashvectf+ 3*hash[b20+b11];
+ n+= i*(h[0]*jx+h[1]*jy+h[2]*oz);
+ /* 7 */
+ i= (cn4*cn5*cn6);
+ h=hashvectf+ 3*hash[b21+b11];
+ n+= i*(h[0]*jx+h[1]*jy+h[2]*jz);
+
+ if(n<0.0) n=0.0; else if(n>1.0) n=1.0;
+ return n;
+}
+
+/* as orgBlenderNoise(), returning signed noise */
+static float orgBlenderNoiseS(float x, float y, float z)
+{
+ return (2.0*orgBlenderNoise(x, y, z)-1.0);
+}
+
+/* separated from orgBlenderNoise above, with scaling */
+float BLI_hnoise(float noisesize, float x, float y, float z)
+{
+ if(noisesize==0.0) return 0.0;
+ x= (1.0+x)/noisesize;
+ y= (1.0+y)/noisesize;
+ z= (1.0+z)/noisesize;
+ return orgBlenderNoise(x, y, z);
+}
+
+
+/* original turbulence functions */
+float BLI_turbulence(float noisesize, float x, float y, float z, int nr)
+{
+ float s, d= 0.5, div=1.0;
+
+ s= BLI_hnoise(noisesize, x, y, z);
+
+ while(nr>0) {
+
+ s+= d*BLI_hnoise(noisesize*d, x, y, z);
+ div+= d;
+ d*= 0.5;
+
+ nr--;
+ }
+ return s/div;
+}
+
+float BLI_turbulence1(float noisesize, float x, float y, float z, int nr)
+{
+ float s, d= 0.5, div=1.0;
+
+ s= fabs( (-1.0+2.0*BLI_hnoise(noisesize, x, y, z)));
+
+ while(nr>0) {
+
+ s+= fabs(d* (-1.0+2.0*BLI_hnoise(noisesize*d, x, y, z)));
+ div+= d;
+ d*= 0.5;
+
+ nr--;
+ }
+ return s/div;
+}
+
+/* ********************* FROM PERLIN HIMSELF: ******************** */
+
+static char p[512+2]= {
+0xA2,0xA0,0x19,0x3B,0xF8,0xEB,0xAA,0xEE,0xF3,0x1C,0x67,0x28,0x1D,0xED,0x0,0xDE,0x95,0x2E,0xDC,0x3F,0x3A,0x82,0x35,0x4D,0x6C,0xBA,0x36,0xD0,0xF6,0xC,0x79,0x32,0xD1,0x59,0xF4,0x8,0x8B,0x63,0x89,0x2F,0xB8,0xB4,0x97,0x83,0xF2,0x8F,0x18,0xC7,0x51,0x14,0x65,0x87,0x48,0x20,0x42,0xA8,0x80,0xB5,0x40,0x13,0xB2,0x22,0x7E,0x57,
+0xBC,0x7F,0x6B,0x9D,0x86,0x4C,0xC8,0xDB,0x7C,0xD5,0x25,0x4E,0x5A,0x55,0x74,0x50,0xCD,0xB3,0x7A,0xBB,0xC3,0xCB,0xB6,0xE2,0xE4,0xEC,0xFD,0x98,0xB,0x96,0xD3,0x9E,0x5C,0xA1,0x64,0xF1,0x81,0x61,0xE1,0xC4,0x24,0x72,0x49,0x8C,0x90,0x4B,0x84,0x34,0x38,0xAB,0x78,0xCA,0x1F,0x1,0xD7,0x93,0x11,0xC1,0x58,0xA9,0x31,0xF9,0x44,0x6D,
+0xBF,0x33,0x9C,0x5F,0x9,0x94,0xA3,0x85,0x6,0xC6,0x9A,0x1E,0x7B,0x46,0x15,0x30,0x27,0x2B,0x1B,0x71,0x3C,0x5B,0xD6,0x6F,0x62,0xAC,0x4F,0xC2,0xC0,0xE,0xB1,0x23,0xA7,0xDF,0x47,0xB0,0x77,0x69,0x5,0xE9,0xE6,0xE7,0x76,0x73,0xF,0xFE,0x6E,0x9B,0x56,0xEF,0x12,0xA5,0x37,0xFC,0xAE,0xD9,0x3,0x8E,0xDD,0x10,0xB9,0xCE,0xC9,0x8D,
+0xDA,0x2A,0xBD,0x68,0x17,0x9F,0xBE,0xD4,0xA,0xCC,0xD2,0xE8,0x43,0x3D,0x70,0xB7,0x2,0x7D,0x99,0xD8,0xD,0x60,0x8A,0x4,0x2C,0x3E,0x92,0xE5,0xAF,0x53,0x7,0xE0,0x29,0xA6,0xC5,0xE3,0xF5,0xF7,0x4A,0x41,0x26,0x6A,0x16,0x5E,0x52,0x2D,0x21,0xAD,0xF0,0x91,0xFF,0xEA,0x54,0xFA,0x66,0x1A,0x45,0x39,0xCF,0x75,0xA4,0x88,0xFB,0x5D,
+0xA2,0xA0,0x19,0x3B,0xF8,0xEB,0xAA,0xEE,0xF3,0x1C,0x67,0x28,0x1D,0xED,0x0,0xDE,0x95,0x2E,0xDC,0x3F,0x3A,0x82,0x35,0x4D,0x6C,0xBA,0x36,0xD0,0xF6,0xC,0x79,0x32,0xD1,0x59,0xF4,0x8,0x8B,0x63,0x89,0x2F,0xB8,0xB4,0x97,0x83,0xF2,0x8F,0x18,0xC7,0x51,0x14,0x65,0x87,0x48,0x20,0x42,0xA8,0x80,0xB5,0x40,0x13,0xB2,0x22,0x7E,0x57,
+0xBC,0x7F,0x6B,0x9D,0x86,0x4C,0xC8,0xDB,0x7C,0xD5,0x25,0x4E,0x5A,0x55,0x74,0x50,0xCD,0xB3,0x7A,0xBB,0xC3,0xCB,0xB6,0xE2,0xE4,0xEC,0xFD,0x98,0xB,0x96,0xD3,0x9E,0x5C,0xA1,0x64,0xF1,0x81,0x61,0xE1,0xC4,0x24,0x72,0x49,0x8C,0x90,0x4B,0x84,0x34,0x38,0xAB,0x78,0xCA,0x1F,0x1,0xD7,0x93,0x11,0xC1,0x58,0xA9,0x31,0xF9,0x44,0x6D,
+0xBF,0x33,0x9C,0x5F,0x9,0x94,0xA3,0x85,0x6,0xC6,0x9A,0x1E,0x7B,0x46,0x15,0x30,0x27,0x2B,0x1B,0x71,0x3C,0x5B,0xD6,0x6F,0x62,0xAC,0x4F,0xC2,0xC0,0xE,0xB1,0x23,0xA7,0xDF,0x47,0xB0,0x77,0x69,0x5,0xE9,0xE6,0xE7,0x76,0x73,0xF,0xFE,0x6E,0x9B,0x56,0xEF,0x12,0xA5,0x37,0xFC,0xAE,0xD9,0x3,0x8E,0xDD,0x10,0xB9,0xCE,0xC9,0x8D,
+0xDA,0x2A,0xBD,0x68,0x17,0x9F,0xBE,0xD4,0xA,0xCC,0xD2,0xE8,0x43,0x3D,0x70,0xB7,0x2,0x7D,0x99,0xD8,0xD,0x60,0x8A,0x4,0x2C,0x3E,0x92,0xE5,0xAF,0x53,0x7,0xE0,0x29,0xA6,0xC5,0xE3,0xF5,0xF7,0x4A,0x41,0x26,0x6A,0x16,0x5E,0x52,0x2D,0x21,0xAD,0xF0,0x91,0xFF,0xEA,0x54,0xFA,0x66,0x1A,0x45,0x39,0xCF,0x75,0xA4,0x88,0xFB,0x5D,
+0xA2,0xA0};
+
+
+float g[512+2][3]= {
+0.33783,0.715698,-0.611206,-0.944031,-0.326599,-0.045624,-0.101074,-0.416443,-0.903503,0.799286,0.49411,-0.341949,-0.854645,0.518036,0.033936,0.42514,-0.437866,-0.792114,-0.358948,0.597046,0.717377,-0.985413,0.144714,0.089294,-0.601776,-0.33728,-0.723907,-0.449921,0.594513,0.666382,0.208313,-0.10791,
+0.972076,0.575317,0.060425,0.815643,0.293365,-0.875702,-0.383453,0.293762,0.465759,0.834686,-0.846008,-0.233398,-0.47934,-0.115814,0.143036,-0.98291,0.204681,-0.949036,-0.239532,0.946716,-0.263947,0.184326,-0.235596,0.573822,0.784332,0.203705,-0.372253,-0.905487,0.756989,-0.651031,0.055298,0.497803,
+0.814697,-0.297363,-0.16214,0.063995,-0.98468,-0.329254,0.834381,0.441925,0.703827,-0.527039,-0.476227,0.956421,0.266113,0.119781,0.480133,0.482849,0.7323,-0.18631,0.961212,-0.203125,-0.748474,-0.656921,-0.090393,-0.085052,-0.165253,0.982544,-0.76947,0.628174,-0.115234,0.383148,0.537659,0.751068,
+0.616486,-0.668488,-0.415924,-0.259979,-0.630005,0.73175,0.570953,-0.087952,0.816223,-0.458008,0.023254,0.888611,-0.196167,0.976563,-0.088287,-0.263885,-0.69812,-0.665527,0.437134,-0.892273,-0.112793,-0.621674,-0.230438,0.748566,0.232422,0.900574,-0.367249,0.22229,-0.796143,0.562744,-0.665497,-0.73764,
+0.11377,0.670135,0.704803,0.232605,0.895599,0.429749,-0.114655,-0.11557,-0.474243,0.872742,0.621826,0.604004,-0.498444,-0.832214,0.012756,0.55426,-0.702484,0.705994,-0.089661,-0.692017,0.649292,0.315399,-0.175995,-0.977997,0.111877,0.096954,-0.04953,0.994019,0.635284,-0.606689,-0.477783,-0.261261,
+-0.607422,-0.750153,0.983276,0.165436,0.075958,-0.29837,0.404083,-0.864655,-0.638672,0.507721,0.578156,0.388214,0.412079,0.824249,0.556183,-0.208832,0.804352,0.778442,0.562012,0.27951,-0.616577,0.781921,-0.091522,0.196289,0.051056,0.979187,-0.121216,0.207153,-0.970734,-0.173401,-0.384735,0.906555,
+0.161499,-0.723236,-0.671387,0.178497,-0.006226,-0.983887,-0.126038,0.15799,0.97934,0.830475,-0.024811,0.556458,-0.510132,-0.76944,0.384247,0.81424,0.200104,-0.544891,-0.112549,-0.393311,-0.912445,0.56189,0.152222,-0.813049,0.198914,-0.254517,-0.946381,-0.41217,0.690979,-0.593811,-0.407257,0.324524,
+0.853668,-0.690186,0.366119,-0.624115,-0.428345,0.844147,-0.322296,-0.21228,-0.297546,-0.930756,-0.273071,0.516113,0.811798,0.928314,0.371643,0.007233,0.785828,-0.479218,-0.390778,-0.704895,0.058929,0.706818,0.173248,0.203583,0.963562,0.422211,-0.904297,-0.062469,-0.363312,-0.182465,0.913605,0.254028,
+-0.552307,-0.793945,-0.28891,-0.765747,-0.574554,0.058319,0.291382,0.954803,0.946136,-0.303925,0.111267,-0.078156,0.443695,-0.892731,0.182098,0.89389,0.409515,-0.680298,-0.213318,0.701141,0.062469,0.848389,-0.525635,-0.72879,-0.641846,0.238342,-0.88089,0.427673,0.202637,-0.532501,-0.21405,0.818878,
+0.948975,-0.305084,0.07962,0.925446,0.374664,0.055817,0.820923,0.565491,0.079102,0.25882,0.099792,-0.960724,-0.294617,0.910522,0.289978,0.137115,0.320038,-0.937408,-0.908386,0.345276,-0.235718,-0.936218,0.138763,0.322754,0.366577,0.925934,-0.090637,0.309296,-0.686829,-0.657684,0.66983,0.024445,
+0.742065,-0.917999,-0.059113,-0.392059,0.365509,0.462158,-0.807922,0.083374,0.996399,-0.014801,0.593842,0.253143,-0.763672,0.974976,-0.165466,0.148285,0.918976,0.137299,0.369537,0.294952,0.694977,0.655731,0.943085,0.152618,-0.295319,0.58783,-0.598236,0.544495,0.203796,0.678223,0.705994,-0.478821,
+-0.661011,0.577667,0.719055,-0.1698,-0.673828,-0.132172,-0.965332,0.225006,-0.981873,-0.14502,0.121979,0.763458,0.579742,0.284546,-0.893188,0.079681,0.442474,-0.795776,-0.523804,0.303802,0.734955,0.67804,-0.007446,0.15506,0.986267,-0.056183,0.258026,0.571503,-0.778931,-0.681549,-0.702087,-0.206116,
+-0.96286,-0.177185,0.203613,-0.470978,-0.515106,0.716095,-0.740326,0.57135,0.354095,-0.56012,-0.824982,-0.074982,-0.507874,0.753204,0.417969,-0.503113,0.038147,0.863342,0.594025,0.673553,-0.439758,-0.119873,-0.005524,-0.992737,0.098267,-0.213776,0.971893,-0.615631,0.643951,0.454163,0.896851,-0.441071,
+0.032166,-0.555023,0.750763,-0.358093,0.398773,0.304688,0.864929,-0.722961,0.303589,0.620544,-0.63559,-0.621948,-0.457306,-0.293243,0.072327,0.953278,-0.491638,0.661041,-0.566772,-0.304199,-0.572083,-0.761688,0.908081,-0.398956,0.127014,-0.523621,-0.549683,-0.650848,-0.932922,-0.19986,0.299408,0.099426,
+0.140869,0.984985,-0.020325,-0.999756,-0.002319,0.952667,0.280853,-0.11615,-0.971893,0.082581,0.220337,0.65921,0.705292,-0.260651,0.733063,-0.175537,0.657043,-0.555206,0.429504,-0.712189,0.400421,-0.89859,0.179352,0.750885,-0.19696,0.630341,0.785675,-0.569336,0.241821,-0.058899,-0.464111,0.883789,
+0.129608,-0.94519,0.299622,-0.357819,0.907654,0.219238,-0.842133,-0.439117,-0.312927,-0.313477,0.84433,0.434479,-0.241211,0.053253,0.968994,0.063873,0.823273,0.563965,0.476288,0.862152,-0.172516,0.620941,-0.298126,0.724915,0.25238,-0.749359,-0.612122,-0.577545,0.386566,0.718994,-0.406342,-0.737976,
+0.538696,0.04718,0.556305,0.82959,-0.802856,0.587463,0.101166,-0.707733,-0.705963,0.026428,0.374908,0.68457,0.625092,0.472137,0.208405,-0.856506,-0.703064,-0.581085,-0.409821,-0.417206,-0.736328,0.532623,-0.447876,-0.20285,-0.870728,0.086945,-0.990417,0.107086,0.183685,0.018341,-0.982788,0.560638,
+-0.428864,0.708282,0.296722,-0.952576,-0.0672,0.135773,0.990265,0.030243,-0.068787,0.654724,0.752686,0.762604,-0.551758,0.337585,-0.819611,-0.407684,0.402466,-0.727844,-0.55072,-0.408539,-0.855774,-0.480011,0.19281,0.693176,-0.079285,0.716339,0.226013,0.650116,-0.725433,0.246704,0.953369,-0.173553,
+-0.970398,-0.239227,-0.03244,0.136383,-0.394318,0.908752,0.813232,0.558167,0.164368,0.40451,0.549042,-0.731323,-0.380249,-0.566711,0.730865,0.022156,0.932739,0.359741,0.00824,0.996552,-0.082306,0.956635,-0.065338,-0.283722,-0.743561,0.008209,0.668579,-0.859589,-0.509674,0.035767,-0.852234,0.363678,
+-0.375977,-0.201965,-0.970795,-0.12915,0.313477,0.947327,0.06546,-0.254028,-0.528259,0.81015,0.628052,0.601105,0.49411,-0.494385,0.868378,0.037933,0.275635,-0.086426,0.957336,-0.197937,0.468903,-0.860748,0.895599,0.399384,0.195801,0.560791,0.825012,-0.069214,0.304199,-0.849487,0.43103,0.096375,
+0.93576,0.339111,-0.051422,0.408966,-0.911072,0.330444,0.942841,-0.042389,-0.452362,-0.786407,0.420563,0.134308,-0.933472,-0.332489,0.80191,-0.566711,-0.188934,-0.987946,-0.105988,0.112518,-0.24408,0.892242,-0.379791,-0.920502,0.229095,-0.316376,0.7789,0.325958,0.535706,-0.912872,0.185211,-0.36377,
+-0.184784,0.565369,-0.803833,-0.018463,0.119537,0.992615,-0.259247,-0.935608,0.239532,-0.82373,-0.449127,-0.345947,-0.433105,0.659515,0.614349,-0.822754,0.378845,-0.423676,0.687195,-0.674835,-0.26889,-0.246582,-0.800842,0.545715,-0.729187,-0.207794,0.651978,0.653534,-0.610443,-0.447388,0.492584,-0.023346,
+0.869934,0.609039,0.009094,-0.79306,0.962494,-0.271088,-0.00885,0.2659,-0.004913,0.963959,0.651245,0.553619,-0.518951,0.280548,-0.84314,0.458618,-0.175293,-0.983215,0.049805,0.035339,-0.979919,0.196045,-0.982941,0.164307,-0.082245,0.233734,-0.97226,-0.005005,-0.747253,-0.611328,0.260437,0.645599,
+0.592773,0.481384,0.117706,-0.949524,-0.29068,-0.535004,-0.791901,-0.294312,-0.627167,-0.214447,0.748718,-0.047974,-0.813477,-0.57959,-0.175537,0.477264,-0.860992,0.738556,-0.414246,-0.53183,0.562561,-0.704071,0.433289,-0.754944,0.64801,-0.100586,0.114716,0.044525,-0.992371,0.966003,0.244873,-0.082764,
+0.33783,0.715698,-0.611206,-0.944031,-0.326599,-0.045624,-0.101074,-0.416443,-0.903503,0.799286,0.49411,-0.341949,-0.854645,0.518036,0.033936,0.42514,-0.437866,-0.792114,-0.358948,0.597046,0.717377,-0.985413,0.144714,0.089294,-0.601776,-0.33728,-0.723907,-0.449921,0.594513,0.666382,0.208313,-0.10791,
+0.972076,0.575317,0.060425,0.815643,0.293365,-0.875702,-0.383453,0.293762,0.465759,0.834686,-0.846008,-0.233398,-0.47934,-0.115814,0.143036,-0.98291,0.204681,-0.949036,-0.239532,0.946716,-0.263947,0.184326,-0.235596,0.573822,0.784332,0.203705,-0.372253,-0.905487,0.756989,-0.651031,0.055298,0.497803,
+0.814697,-0.297363,-0.16214,0.063995,-0.98468,-0.329254,0.834381,0.441925,0.703827,-0.527039,-0.476227,0.956421,0.266113,0.119781,0.480133,0.482849,0.7323,-0.18631,0.961212,-0.203125,-0.748474,-0.656921,-0.090393,-0.085052,-0.165253,0.982544,-0.76947,0.628174,-0.115234,0.383148,0.537659,0.751068,
+0.616486,-0.668488,-0.415924,-0.259979,-0.630005,0.73175,0.570953,-0.087952,0.816223,-0.458008,0.023254,0.888611,-0.196167,0.976563,-0.088287,-0.263885,-0.69812,-0.665527,0.437134,-0.892273,-0.112793,-0.621674,-0.230438,0.748566,0.232422,0.900574,-0.367249,0.22229,-0.796143,0.562744,-0.665497,-0.73764,
+0.11377,0.670135,0.704803,0.232605,0.895599,0.429749,-0.114655,-0.11557,-0.474243,0.872742,0.621826,0.604004,-0.498444,-0.832214,0.012756,0.55426,-0.702484,0.705994,-0.089661,-0.692017,0.649292,0.315399,-0.175995,-0.977997,0.111877,0.096954,-0.04953,0.994019,0.635284,-0.606689,-0.477783,-0.261261,
+-0.607422,-0.750153,0.983276,0.165436,0.075958,-0.29837,0.404083,-0.864655,-0.638672,0.507721,0.578156,0.388214,0.412079,0.824249,0.556183,-0.208832,0.804352,0.778442,0.562012,0.27951,-0.616577,0.781921,-0.091522,0.196289,0.051056,0.979187,-0.121216,0.207153,-0.970734,-0.173401,-0.384735,0.906555,
+0.161499,-0.723236,-0.671387,0.178497,-0.006226,-0.983887,-0.126038,0.15799,0.97934,0.830475,-0.024811,0.556458,-0.510132,-0.76944,0.384247,0.81424,0.200104,-0.544891,-0.112549,-0.393311,-0.912445,0.56189,0.152222,-0.813049,0.198914,-0.254517,-0.946381,-0.41217,0.690979,-0.593811,-0.407257,0.324524,
+0.853668,-0.690186,0.366119,-0.624115,-0.428345,0.844147,-0.322296,-0.21228,-0.297546,-0.930756,-0.273071,0.516113,0.811798,0.928314,0.371643,0.007233,0.785828,-0.479218,-0.390778,-0.704895,0.058929,0.706818,0.173248,0.203583,0.963562,0.422211,-0.904297,-0.062469,-0.363312,-0.182465,0.913605,0.254028,
+-0.552307,-0.793945,-0.28891,-0.765747,-0.574554,0.058319,0.291382,0.954803,0.946136,-0.303925,0.111267,-0.078156,0.443695,-0.892731,0.182098,0.89389,0.409515,-0.680298,-0.213318,0.701141,0.062469,0.848389,-0.525635,-0.72879,-0.641846,0.238342,-0.88089,0.427673,0.202637,-0.532501,-0.21405,0.818878,
+0.948975,-0.305084,0.07962,0.925446,0.374664,0.055817,0.820923,0.565491,0.079102,0.25882,0.099792,-0.960724,-0.294617,0.910522,0.289978,0.137115,0.320038,-0.937408,-0.908386,0.345276,-0.235718,-0.936218,0.138763,0.322754,0.366577,0.925934,-0.090637,0.309296,-0.686829,-0.657684,0.66983,0.024445,
+0.742065,-0.917999,-0.059113,-0.392059,0.365509,0.462158,-0.807922,0.083374,0.996399,-0.014801,0.593842,0.253143,-0.763672,0.974976,-0.165466,0.148285,0.918976,0.137299,0.369537,0.294952,0.694977,0.655731,0.943085,0.152618,-0.295319,0.58783,-0.598236,0.544495,0.203796,0.678223,0.705994,-0.478821,
+-0.661011,0.577667,0.719055,-0.1698,-0.673828,-0.132172,-0.965332,0.225006,-0.981873,-0.14502,0.121979,0.763458,0.579742,0.284546,-0.893188,0.079681,0.442474,-0.795776,-0.523804,0.303802,0.734955,0.67804,-0.007446,0.15506,0.986267,-0.056183,0.258026,0.571503,-0.778931,-0.681549,-0.702087,-0.206116,
+-0.96286,-0.177185,0.203613,-0.470978,-0.515106,0.716095,-0.740326,0.57135,0.354095,-0.56012,-0.824982,-0.074982,-0.507874,0.753204,0.417969,-0.503113,0.038147,0.863342,0.594025,0.673553,-0.439758,-0.119873,-0.005524,-0.992737,0.098267,-0.213776,0.971893,-0.615631,0.643951,0.454163,0.896851,-0.441071,
+0.032166,-0.555023,0.750763,-0.358093,0.398773,0.304688,0.864929,-0.722961,0.303589,0.620544,-0.63559,-0.621948,-0.457306,-0.293243,0.072327,0.953278,-0.491638,0.661041,-0.566772,-0.304199,-0.572083,-0.761688,0.908081,-0.398956,0.127014,-0.523621,-0.549683,-0.650848,-0.932922,-0.19986,0.299408,0.099426,
+0.140869,0.984985,-0.020325,-0.999756,-0.002319,0.952667,0.280853,-0.11615,-0.971893,0.082581,0.220337,0.65921,0.705292,-0.260651,0.733063,-0.175537,0.657043,-0.555206,0.429504,-0.712189,0.400421,-0.89859,0.179352,0.750885,-0.19696,0.630341,0.785675,-0.569336,0.241821,-0.058899,-0.464111,0.883789,
+0.129608,-0.94519,0.299622,-0.357819,0.907654,0.219238,-0.842133,-0.439117,-0.312927,-0.313477,0.84433,0.434479,-0.241211,0.053253,0.968994,0.063873,0.823273,0.563965,0.476288,0.862152,-0.172516,0.620941,-0.298126,0.724915,0.25238,-0.749359,-0.612122,-0.577545,0.386566,0.718994,-0.406342,-0.737976,
+0.538696,0.04718,0.556305,0.82959,-0.802856,0.587463,0.101166,-0.707733,-0.705963,0.026428,0.374908,0.68457,0.625092,0.472137,0.208405,-0.856506,-0.703064,-0.581085,-0.409821,-0.417206,-0.736328,0.532623,-0.447876,-0.20285,-0.870728,0.086945,-0.990417,0.107086,0.183685,0.018341,-0.982788,0.560638,
+-0.428864,0.708282,0.296722,-0.952576,-0.0672,0.135773,0.990265,0.030243,-0.068787,0.654724,0.752686,0.762604,-0.551758,0.337585,-0.819611,-0.407684,0.402466,-0.727844,-0.55072,-0.408539,-0.855774,-0.480011,0.19281,0.693176,-0.079285,0.716339,0.226013,0.650116,-0.725433,0.246704,0.953369,-0.173553,
+-0.970398,-0.239227,-0.03244,0.136383,-0.394318,0.908752,0.813232,0.558167,0.164368,0.40451,0.549042,-0.731323,-0.380249,-0.566711,0.730865,0.022156,0.932739,0.359741,0.00824,0.996552,-0.082306,0.956635,-0.065338,-0.283722,-0.743561,0.008209,0.668579,-0.859589,-0.509674,0.035767,-0.852234,0.363678,
+-0.375977,-0.201965,-0.970795,-0.12915,0.313477,0.947327,0.06546,-0.254028,-0.528259,0.81015,0.628052,0.601105,0.49411,-0.494385,0.868378,0.037933,0.275635,-0.086426,0.957336,-0.197937,0.468903,-0.860748,0.895599,0.399384,0.195801,0.560791,0.825012,-0.069214,0.304199,-0.849487,0.43103,0.096375,
+0.93576,0.339111,-0.051422,0.408966,-0.911072,0.330444,0.942841,-0.042389,-0.452362,-0.786407,0.420563,0.134308,-0.933472,-0.332489,0.80191,-0.566711,-0.188934,-0.987946,-0.105988,0.112518,-0.24408,0.892242,-0.379791,-0.920502,0.229095,-0.316376,0.7789,0.325958,0.535706,-0.912872,0.185211,-0.36377,
+-0.184784,0.565369,-0.803833,-0.018463,0.119537,0.992615,-0.259247,-0.935608,0.239532,-0.82373,-0.449127,-0.345947,-0.433105,0.659515,0.614349,-0.822754,0.378845,-0.423676,0.687195,-0.674835,-0.26889,-0.246582,-0.800842,0.545715,-0.729187,-0.207794,0.651978,0.653534,-0.610443,-0.447388,0.492584,-0.023346,
+0.869934,0.609039,0.009094,-0.79306,0.962494,-0.271088,-0.00885,0.2659,-0.004913,0.963959,0.651245,0.553619,-0.518951,0.280548,-0.84314,0.458618,-0.175293,-0.983215,0.049805,0.035339,-0.979919,0.196045,-0.982941,0.164307,-0.082245,0.233734,-0.97226,-0.005005,-0.747253,-0.611328,0.260437,0.645599,
+0.592773,0.481384,0.117706,-0.949524,-0.29068,-0.535004,-0.791901,-0.294312,-0.627167,-0.214447,0.748718,-0.047974,-0.813477,-0.57959,-0.175537,0.477264,-0.860992,0.738556,-0.414246,-0.53183,0.562561,-0.704071,0.433289,-0.754944,0.64801,-0.100586,0.114716,0.044525,-0.992371,0.966003,0.244873,-0.082764,
+0.33783,0.715698,-0.611206,-0.944031,-0.326599,-0.045624};
+
+
+
+#define DOT(a,b) (a[0] * b[0] + a[1] * b[1] + a[2] * b[2])
+
+#define setup(i,b0,b1,r0,r1) \
+ t = vec[i] + 10000.; \
+ b0 = ((int)t) & 255; \
+ b1 = (b0+1) & 255; \
+ r0 = t - (int)t; \
+ r1 = r0 - 1.;
+
+
+float noise3_perlin(float vec[3])
+{
+ int bx0, bx1, by0, by1, bz0, bz1, b00, b10, b01, b11;
+ float rx0, rx1, ry0, ry1, rz0, rz1, *q, sx, sy, sz, a, b, c, d, t, u, v;
+ register int i, j;
+
+
+ setup(0, bx0,bx1, rx0,rx1);
+ setup(1, by0,by1, ry0,ry1);
+ setup(2, bz0,bz1, rz0,rz1);
+
+ i = p[ bx0 ];
+ j = p[ bx1 ];
+
+ b00 = p[ i + by0 ];
+ b10 = p[ j + by0 ];
+ b01 = p[ i + by1 ];
+ b11 = p[ j + by1 ];
+
+#define at(rx,ry,rz) ( rx * q[0] + ry * q[1] + rz * q[2] )
+
+#define surve(t) ( t * t * (3. - 2. * t) )
+
+/* lerp moved to improved perlin above */
+
+ sx = surve(rx0);
+ sy = surve(ry0);
+ sz = surve(rz0);
+
+
+ q = g[ b00 + bz0 ] ;
+ u = at(rx0,ry0,rz0);
+ q = g[ b10 + bz0 ] ;
+ v = at(rx1,ry0,rz0);
+ a = lerp(sx, u, v);
+
+ q = g[ b01 + bz0 ] ;
+ u = at(rx0,ry1,rz0);
+ q = g[ b11 + bz0 ] ;
+ v = at(rx1,ry1,rz0);
+ b = lerp(sx, u, v);
+
+ c = lerp(sy, a, b); /* interpolate in y at lo x */
+
+ q = g[ b00 + bz1 ] ;
+ u = at(rx0,ry0,rz1);
+ q = g[ b10 + bz1 ] ;
+ v = at(rx1,ry0,rz1);
+ a = lerp(sx, u, v);
+
+ q = g[ b01 + bz1 ] ;
+ u = at(rx0,ry1,rz1);
+ q = g[ b11 + bz1 ] ;
+ v = at(rx1,ry1,rz1);
+ b = lerp(sx, u, v);
+
+ d = lerp(sy, a, b); /* interpolate in y at hi x */
+
+ return 1.5 * lerp(sz, c, d); /* interpolate in z */
+}
+
+float turbulence_perlin(float *point, float lofreq, float hifreq)
+{
+ float freq, t, p[3];
+
+ p[0] = point[0] + 123.456;
+ p[1] = point[1];
+ p[2] = point[2];
+
+ t = 0;
+ for (freq = lofreq ; freq < hifreq ; freq *= 2.) {
+ t += fabs(noise3_perlin(p)) / freq;
+ p[0] *= 2.;
+ p[1] *= 2.;
+ p[2] *= 2.;
+ }
+ return t - 0.3; /* readjust to make mean value = 0.0 */
+}
+
+/* for use with BLI_gNoise/gTurbulence, returns signed noise */
+static float orgPerlinNoise(float x, float y, float z)
+{
+ float v[3];
+
+ v[0] = x;
+ v[1] = y;
+ v[2] = z;
+ return noise3_perlin(v);
+}
+
+/* for use with BLI_gNoise/gTurbulence, returns unsigned noise */
+static float orgPerlinNoiseU(float x, float y, float z)
+{
+ float v[3];
+
+ v[0] = x;
+ v[1] = y;
+ v[2] = z;
+ return (0.5+0.5*noise3_perlin(v));
+}
+
+/* *************** CALL AS: *************** */
+
+float BLI_hnoisep(float noisesize, float x, float y, float z)
+{
+ float vec[3];
+
+ vec[0]= x/noisesize;
+ vec[1]= y/noisesize;
+ vec[2]= z/noisesize;
+
+ return noise3_perlin(vec);
+}
+
+float turbulencep(float noisesize, float x, float y, float z, int nr)
+{
+ float vec[3];
+
+ vec[0]= x/noisesize;
+ vec[1]= y/noisesize;
+ vec[2]= z/noisesize;
+ nr++;
+ return turbulence_perlin(vec, 1.0, (float)(1<<nr));
+}
+
+/******************/
+/* VORONOI/WORLEY */
+/******************/
+
+/* distance metrics for voronoi, e parameter only used in Minkovsky */
+/* Camberra omitted, didn't seem useful */
+
+/* distance squared */
+static float dist_Squared(float x, float y, float z, float e) { return (x*x + y*y + z*z); }
+/* real distance */
+static float dist_Real(float x, float y, float z, float e) { return sqrt(x*x + y*y + z*z); }
+/* manhattan/taxicab/cityblock distance */
+static float dist_Manhattan(float x, float y, float z, float e) { return (fabs(x) + fabs(y) + fabs(z)); }
+/* Chebychev */
+static float dist_Chebychev(float x, float y, float z, float e)
+{
+ float t;
+ x = fabs(x);
+ y = fabs(y);
+ z = fabs(z);
+ t = (x>y)?x:y;
+ return ((z>t)?z:t);
+}
+
+/* minkovsky preset exponent 0.5 */
+static float dist_MinkovskyH(float x, float y, float z, float e)
+{
+ float d = sqrt(fabs(x)) + sqrt(fabs(y)) + sqrt(fabs(z));
+ return (d*d);
+}
+
+/* minkovsky preset exponent 4 */
+static float dist_Minkovsky4(float x, float y, float z, float e)
+{
+ x *= x;
+ y *= y;
+ z *= z;
+ return sqrt(sqrt(x*x + y*y + z*z));
+}
+
+/* Minkovsky, general case, slow, maybe too slow to be useful */
+static float dist_Minkovsky(float x, float y, float z, float e)
+{
+ return pow(pow(fabs(x), e) + pow(fabs(y), e) + pow(fabs(z), e), 1.0/e);
+}
+
+
+/* Not 'pure' Worley, but the results are virtually the same.
+ Returns distances in da and point coords in pa */
+void voronoi(float x, float y, float z, float* da, float* pa, float me, int dtype)
+{
+ int xx, yy, zz, xi, yi, zi;
+ float xd, yd, zd, d, *p;
+
+ float (*distfunc)(float, float, float, float);
+ switch (dtype) {
+ case 1:
+ distfunc = dist_Squared;
+ break;
+ case 2:
+ distfunc = dist_Manhattan;
+ break;
+ case 3:
+ distfunc = dist_Chebychev;
+ break;
+ case 4:
+ distfunc = dist_MinkovskyH;
+ break;
+ case 5:
+ distfunc = dist_Minkovsky4;
+ break;
+ case 6:
+ distfunc = dist_Minkovsky;
+ break;
+ case 0:
+ default:
+ distfunc = dist_Real;
+ }
+
+ xi = (int)(floor(x));
+ yi = (int)(floor(y));
+ zi = (int)(floor(z));
+ da[0] = da[1] = da[2] = da[3] = 1e10f;
+ for (xx=xi-1;xx<=xi+1;xx++) {
+ for (yy=yi-1;yy<=yi+1;yy++) {
+ for (zz=zi-1;zz<=zi+1;zz++) {
+ p = HASHPNT(xx, yy, zz);
+ xd = x - (p[0] + xx);
+ yd = y - (p[1] + yy);
+ zd = z - (p[2] + zz);
+ d = distfunc(xd, yd, zd, me);
+ if (d<da[0]) {
+ da[3]=da[2]; da[2]=da[1]; da[1]=da[0]; da[0]=d;
+ pa[9]=pa[6]; pa[10]=pa[7]; pa[11]=pa[8];
+ pa[6]=pa[3]; pa[7]=pa[4]; pa[8]=pa[5];
+ pa[3]=pa[0]; pa[4]=pa[1]; pa[5]=pa[2];
+ pa[0]=p[0]+xx; pa[1]=p[1]+yy; pa[2]=p[2]+zz;
+ }
+ else if (d<da[1]) {
+ da[3]=da[2]; da[2]=da[1]; da[1]=d;
+ pa[9]=pa[6]; pa[10]=pa[7]; pa[11]=pa[8];
+ pa[6]=pa[3]; pa[7]=pa[4]; pa[8]=pa[5];
+ pa[3]=p[0]+xx; pa[4]=p[1]+yy; pa[5]=p[2]+zz;
+ }
+ else if (d<da[2]) {
+ da[3]=da[2]; da[2]=d;
+ pa[9]=pa[6]; pa[10]=pa[7]; pa[11]=pa[8];
+ pa[6]=p[0]+xx; pa[7]=p[1]+yy; pa[8]=p[2]+zz;
+ }
+ else if (d<da[3]) {
+ da[3]=d;
+ pa[9]=p[0]+xx; pa[10]=p[1]+yy; pa[11]=p[2]+zz;
+ }
+ }
+ }
+ }
+}
+
+/* returns different feature points for use in BLI_gNoise() */
+static float voronoi_F1(float x, float y, float z)
+{
+ float da[4], pa[12];
+ voronoi(x, y, z, da, pa, 1, 0);
+ return da[0];
+}
+
+static float voronoi_F2(float x, float y, float z)
+{
+ float da[4], pa[12];
+ voronoi(x, y, z, da, pa, 1, 0);
+ return da[1];
+}
+
+static float voronoi_F3(float x, float y, float z)
+{
+ float da[4], pa[12];
+ voronoi(x, y, z, da, pa, 1, 0);
+ return da[2];
+}
+
+static float voronoi_F4(float x, float y, float z)
+{
+ float da[4], pa[12];
+ voronoi(x, y, z, da, pa, 1, 0);
+ return da[3];
+}
+
+static float voronoi_F1F2(float x, float y, float z)
+{
+ float da[4], pa[12];
+ voronoi(x, y, z, da, pa, 1, 0);
+ return (da[1]-da[0]);
+}
+
+/* Crackle type pattern, just a scale/clamp of F2-F1 */
+static float voronoi_Cr(float x, float y, float z)
+{
+ float t = 10*voronoi_F1F2(x, y, z);
+ if (t>1.f) return 1.f;
+ return t;
+}
+
+
+/* Signed version of all 6 of the above, just 2x-1, not really correct though (range is potentially (0, sqrt(6)).
+ Used in the musgrave functions */
+static float voronoi_F1S(float x, float y, float z)
+{
+ float da[4], pa[12];
+ voronoi(x, y, z, da, pa, 1, 0);
+ return (2.0*da[0]-1.0);
+}
+
+static float voronoi_F2S(float x, float y, float z)
+{
+ float da[4], pa[12];
+ voronoi(x, y, z, da, pa, 1, 0);
+ return (2.0*da[1]-1.0);
+}
+
+static float voronoi_F3S(float x, float y, float z)
+{
+ float da[4], pa[12];
+ voronoi(x, y, z, da, pa, 1, 0);
+ return (2.0*da[2]-1.0);
+}
+
+static float voronoi_F4S(float x, float y, float z)
+{
+ float da[4], pa[12];
+ voronoi(x, y, z, da, pa, 1, 0);
+ return (2.0*da[3]-1.0);
+}
+
+static float voronoi_F1F2S(float x, float y, float z)
+{
+ float da[4], pa[12];
+ voronoi(x, y, z, da, pa, 1, 0);
+ return (2.0*(da[1]-da[0])-1.0);
+}
+
+/* Crackle type pattern, just a scale/clamp of F2-F1 */
+static float voronoi_CrS(float x, float y, float z)
+{
+ float t = 10*voronoi_F1F2(x, y, z);
+ if (t>1.f) return 1.f;
+ return (2.0*t-1.0);
+}
+
+
+/***************/
+/* voronoi end */
+/***************/
+
+/*************/
+/* CELLNOISE */
+/*************/
+
+/* returns unsigned cellnoise */
+static float cellNoiseU(float x, float y, float z)
+{
+ int xi = (int)(floor(x));
+ int yi = (int)(floor(y));
+ int zi = (int)(floor(z));
+ unsigned int n = xi + yi*1301 + zi*314159;
+ n ^= (n<<13);
+ return ((float)(n*(n*n*15731 + 789221) + 1376312589) / 4294967296.0);
+}
+
+/* idem, signed */
+float cellNoise(float x, float y, float z)
+{
+ return (2.0*cellNoiseU(x, y, z)-1.0);
+}
+
+/* returns a vector/point/color in ca, using point hasharray directly */
+void cellNoiseV(float x, float y, float z, float *ca)
+{
+ int xi = (int)(floor(x));
+ int yi = (int)(floor(y));
+ int zi = (int)(floor(z));
+ float *p = HASHPNT(xi, yi, zi);
+ ca[0] = p[0];
+ ca[1] = p[1];
+ ca[2] = p[2];
+}
+
+
+/*****************/
+/* end cellnoise */
+/*****************/
+
+/* newnoise: generic noise function for use with different noisebases */
+float BLI_gNoise(float noisesize, float x, float y, float z, int hard, int noisebasis)
+{
+ float (*noisefunc)(float, float, float);
+
+ switch (noisebasis) {
+ case 1:
+ noisefunc = orgPerlinNoiseU;
+ break;
+ case 2:
+ noisefunc = newPerlinU;
+ break;
+ case 3:
+ noisefunc = voronoi_F1;
+ break;
+ case 4:
+ noisefunc = voronoi_F2;
+ break;
+ case 5:
+ noisefunc = voronoi_F3;
+ break;
+ case 6:
+ noisefunc = voronoi_F4;
+ break;
+ case 7:
+ noisefunc = voronoi_F1F2;
+ break;
+ case 8:
+ noisefunc = voronoi_Cr;
+ break;
+ case 14:
+ noisefunc = cellNoiseU;
+ break;
+ case 0:
+ default: {
+ noisefunc = orgBlenderNoise;
+ /* add one to make return value same as BLI_hnoise */
+ x += 1;
+ y += 1;
+ z += 1;
+ }
+ }
+
+ if (noisesize!=0.0) {
+ noisesize = 1.0/noisesize;
+ x *= noisesize;
+ y *= noisesize;
+ z *= noisesize;
+ }
+
+ if (hard) return fabs(2.0*noisefunc(x, y, z)-1.0);
+ return noisefunc(x, y, z);
+}
+
+/* newnoise: generic turbulence function for use with different noisebasis */
+float BLI_gTurbulence(float noisesize, float x, float y, float z, int oct, int hard, int noisebasis)
+{
+ float (*noisefunc)(float, float, float);
+ float sum, t, amp=1, fscale=1;
+ int i;
+
+ switch (noisebasis) {
+ case 1:
+ noisefunc = orgPerlinNoiseU;
+ break;
+ case 2:
+ noisefunc = newPerlinU;
+ break;
+ case 3:
+ noisefunc = voronoi_F1;
+ break;
+ case 4:
+ noisefunc = voronoi_F2;
+ break;
+ case 5:
+ noisefunc = voronoi_F3;
+ break;
+ case 6:
+ noisefunc = voronoi_F4;
+ break;
+ case 7:
+ noisefunc = voronoi_F1F2;
+ break;
+ case 8:
+ noisefunc = voronoi_Cr;
+ break;
+ case 14:
+ noisefunc = cellNoiseU;
+ break;
+ case 0:
+ default:
+ noisefunc = orgBlenderNoise;
+ x += 1;
+ y += 1;
+ z += 1;
+ }
+
+ if (noisesize!=0.0) {
+ noisesize = 1.0/noisesize;
+ x *= noisesize;
+ y *= noisesize;
+ z *= noisesize;
+ }
+
+ sum = 0;
+ for (i=0;i<=oct;i++, amp*=0.5, fscale*=2) {
+ t = noisefunc(fscale*x, fscale*y, fscale*z);
+ if (hard) t = fabs(2.0*t-1.0);
+ sum += t * amp;
+ }
+
+ sum *= ((float)(1<<oct)/(float)((1<<(oct+1))-1));
+
+ return sum;
+
+}
+
+
+/*
+ * The following code is based on Ken Musgrave's explanations and sample
+ * source code in the book "Texturing and Modelling: A procedural approach"
+ */
+
+/*
+ * Procedural fBm evaluated at "point"; returns value stored in "value".
+ *
+ * Parameters:
+ * ``H'' is the fractal increment parameter
+ * ``lacunarity'' is the gap between successive frequencies
+ * ``octaves'' is the number of frequencies in the fBm
+ */
+float mg_fBm(float x, float y, float z, float H, float lacunarity, float octaves, int noisebasis)
+{
+ float rmd, value=0.0, pwr=1.0, pwHL=pow(lacunarity, -H);
+ int i;
+
+ float (*noisefunc)(float, float, float);
+ switch (noisebasis) {
+ case 1:
+ noisefunc = orgPerlinNoise;
+ break;
+ case 2:
+ noisefunc = newPerlin;
+ break;
+ case 3:
+ noisefunc = voronoi_F1S;
+ break;
+ case 4:
+ noisefunc = voronoi_F2S;
+ break;
+ case 5:
+ noisefunc = voronoi_F3S;
+ break;
+ case 6:
+ noisefunc = voronoi_F4S;
+ break;
+ case 7:
+ noisefunc = voronoi_F1F2S;
+ break;
+ case 8:
+ noisefunc = voronoi_CrS;
+ break;
+ case 14:
+ noisefunc = cellNoise;
+ break;
+ case 0:
+ default: {
+ noisefunc = orgBlenderNoiseS;
+ }
+ }
+
+ for (i=0; i<(int)octaves; i++) {
+ value += noisefunc(x, y, z) * pwr;
+ pwr *= pwHL;
+ x *= lacunarity;
+ y *= lacunarity;
+ z *= lacunarity;
+ }
+
+ rmd = octaves - floor(octaves);
+ if (rmd!=0.f) value += rmd * noisefunc(x, y, z) * pwr;
+
+ return value;
+
+} /* fBm() */
+
+
+/*
+ * Procedural multifractal evaluated at "point";
+ * returns value stored in "value".
+ *
+ * Parameters:
+ * ``H'' determines the highest fractal dimension
+ * ``lacunarity'' is gap between successive frequencies
+ * ``octaves'' is the number of frequencies in the fBm
+ * ``offset'' is the zero offset, which determines multifractality (NOT USED??)
+ */
+ /* this one is in fact rather confusing,
+ * there seem to be errors in the original source code (in all three versions of proc.text&mod),
+ * I modified it to something that made sense to me, so it might be wrong... */
+float mg_MultiFractal(float x, float y, float z, float H, float lacunarity, float octaves, int noisebasis)
+{
+ float rmd, value=1.0, pwr=1.0, pwHL=pow(lacunarity, -H);
+ int i;
+
+ float (*noisefunc)(float, float, float);
+ switch (noisebasis) {
+ case 1:
+ noisefunc = orgPerlinNoise;
+ break;
+ case 2:
+ noisefunc = newPerlin;
+ break;
+ case 3:
+ noisefunc = voronoi_F1S;
+ break;
+ case 4:
+ noisefunc = voronoi_F2S;
+ break;
+ case 5:
+ noisefunc = voronoi_F3S;
+ break;
+ case 6:
+ noisefunc = voronoi_F4S;
+ break;
+ case 7:
+ noisefunc = voronoi_F1F2S;
+ break;
+ case 8:
+ noisefunc = voronoi_CrS;
+ break;
+ case 14:
+ noisefunc = cellNoise;
+ break;
+ case 0:
+ default: {
+ noisefunc = orgBlenderNoiseS;
+ }
+ }
+
+ for (i=0; i<(int)octaves; i++) {
+ value *= (pwr * noisefunc(x, y, z) + 1.0);
+ pwr *= pwHL;
+ x *= lacunarity;
+ y *= lacunarity;
+ z *= lacunarity;
+ }
+ rmd = octaves - floor(octaves);
+ if (rmd!=0.0) value *= (rmd * noisefunc(x, y, z) * pwr + 1.0);
+
+ return value;
+
+} /* multifractal() */
+
+/*
+ * Heterogeneous procedural terrain function: stats by altitude method.
+ * Evaluated at "point"; returns value stored in "value".
+ *
+ * Parameters:
+ * ``H'' determines the fractal dimension of the roughest areas
+ * ``lacunarity'' is the gap between successive frequencies
+ * ``octaves'' is the number of frequencies in the fBm
+ * ``offset'' raises the terrain from `sea level'
+ */
+float mg_HeteroTerrain(float x, float y, float z, float H, float lacunarity, float octaves, float offset, int noisebasis)
+{
+ float value, increment, rmd;
+ int i;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL; /* starts with i=1 instead of 0 */
+
+ float (*noisefunc)(float, float, float);
+ switch (noisebasis) {
+ case 1:
+ noisefunc = orgPerlinNoise;
+ break;
+ case 2:
+ noisefunc = newPerlin;
+ break;
+ case 3:
+ noisefunc = voronoi_F1S;
+ break;
+ case 4:
+ noisefunc = voronoi_F2S;
+ break;
+ case 5:
+ noisefunc = voronoi_F3S;
+ break;
+ case 6:
+ noisefunc = voronoi_F4S;
+ break;
+ case 7:
+ noisefunc = voronoi_F1F2S;
+ break;
+ case 8:
+ noisefunc = voronoi_CrS;
+ break;
+ case 14:
+ noisefunc = cellNoise;
+ break;
+ case 0:
+ default: {
+ noisefunc = orgBlenderNoiseS;
+ }
+ }
+
+ /* first unscaled octave of function; later octaves are scaled */
+ value = offset + noisefunc(x, y, z);
+ x *= lacunarity;
+ y *= lacunarity;
+ z *= lacunarity;
+
+ for (i=1; i<(int)octaves; i++) {
+ increment = (noisefunc(x, y, z) + offset) * pwr * value;
+ value += increment;
+ pwr *= pwHL;
+ x *= lacunarity;
+ y *= lacunarity;
+ z *= lacunarity;
+ }
+
+ rmd = octaves - floor(octaves);
+ if (rmd!=0.0) {
+ increment = (noisefunc(x, y, z) + offset) * pwr * value;
+ value += rmd * increment;
+ }
+ return value;
+}
+
+
+/* Hybrid additive/multiplicative multifractal terrain model.
+ *
+ * Some good parameter values to start with:
+ *
+ * H: 0.25
+ * offset: 0.7
+ */
+float mg_HybridMultiFractal(float x, float y, float z, float H, float lacunarity, float octaves, float offset, float gain, int noisebasis)
+{
+ float result, signal, weight, rmd;
+ int i;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL; /* starts with i=1 instead of 0 */
+ float (*noisefunc)(float, float, float);
+
+ switch (noisebasis) {
+ case 1:
+ noisefunc = orgPerlinNoise;
+ break;
+ case 2:
+ noisefunc = newPerlin;
+ break;
+ case 3:
+ noisefunc = voronoi_F1S;
+ break;
+ case 4:
+ noisefunc = voronoi_F2S;
+ break;
+ case 5:
+ noisefunc = voronoi_F3S;
+ break;
+ case 6:
+ noisefunc = voronoi_F4S;
+ break;
+ case 7:
+ noisefunc = voronoi_F1F2S;
+ break;
+ case 8:
+ noisefunc = voronoi_CrS;
+ break;
+ case 14:
+ noisefunc = cellNoise;
+ break;
+ case 0:
+ default: {
+ noisefunc = orgBlenderNoiseS;
+ }
+ }
+
+ result = noisefunc(x, y, z) + offset;
+ weight = gain * result;
+ x *= lacunarity;
+ y *= lacunarity;
+ z *= lacunarity;
+
+ for (i=1; (weight>0.001) && (i<(int)octaves); i++) {
+ if (weight>1.0) weight=1.0;
+ signal = (noisefunc(x, y, z) + offset) * pwr;
+ pwr *= pwHL;
+ result += weight * signal;
+ weight *= gain * signal;
+ x *= lacunarity;
+ y *= lacunarity;
+ z *= lacunarity;
+ }
+
+ rmd = octaves - floor(octaves);
+ if (rmd!=0.f) result += rmd * ((noisefunc(x, y, z) + offset) * pwr);
+
+ return result;
+
+} /* HybridMultifractal() */
+
+
+/* Ridged multifractal terrain model.
+ *
+ * Some good parameter values to start with:
+ *
+ * H: 1.0
+ * offset: 1.0
+ * gain: 2.0
+ */
+float mg_RidgedMultiFractal(float x, float y, float z, float H, float lacunarity, float octaves, float offset, float gain, int noisebasis)
+{
+ float result, signal, weight;
+ int i;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL; /* starts with i=1 instead of 0 */
+
+ float (*noisefunc)(float, float, float);
+ switch (noisebasis) {
+ case 1:
+ noisefunc = orgPerlinNoise;
+ break;
+ case 2:
+ noisefunc = newPerlin;
+ break;
+ case 3:
+ noisefunc = voronoi_F1S;
+ break;
+ case 4:
+ noisefunc = voronoi_F2S;
+ break;
+ case 5:
+ noisefunc = voronoi_F3S;
+ break;
+ case 6:
+ noisefunc = voronoi_F4S;
+ break;
+ case 7:
+ noisefunc = voronoi_F1F2S;
+ break;
+ case 8:
+ noisefunc = voronoi_CrS;
+ break;
+ case 14:
+ noisefunc = cellNoise;
+ break;
+ case 0:
+ default: {
+ noisefunc = orgBlenderNoiseS;
+ }
+ }
+
+ signal = offset - fabs(noisefunc(x, y, z));
+ signal *= signal;
+ result = signal;
+ weight = 1.f;
+
+ for( i=1; i<(int)octaves; i++ ) {
+ x *= lacunarity;
+ y *= lacunarity;
+ z *= lacunarity;
+ weight = signal * gain;
+ if (weight>1.0) weight=1.0; else if (weight<0.0) weight=0.0;
+ signal = offset - fabs(noisefunc(x, y, z));
+ signal *= signal;
+ signal *= weight;
+ result += signal * pwr;
+ pwr *= pwHL;
+ }
+
+ return result;
+} /* RidgedMultifractal() */
+
+/* "Variable Lacunarity Noise"
+ * A distorted variety of Perlin noise.
+ */
+float mg_VLNoise(float x, float y, float z, float distortion, int nbas1, int nbas2)
+{
+ float rv[3];
+ float (*noisefunc1)(float, float, float);
+ float (*noisefunc2)(float, float, float);
+
+ switch (nbas1) {
+ case 1:
+ noisefunc1 = orgPerlinNoise;
+ break;
+ case 2:
+ noisefunc1 = newPerlin;
+ break;
+ case 3:
+ noisefunc1 = voronoi_F1S;
+ break;
+ case 4:
+ noisefunc1 = voronoi_F2S;
+ break;
+ case 5:
+ noisefunc1 = voronoi_F3S;
+ break;
+ case 6:
+ noisefunc1 = voronoi_F4S;
+ break;
+ case 7:
+ noisefunc1 = voronoi_F1F2S;
+ break;
+ case 8:
+ noisefunc1 = voronoi_CrS;
+ break;
+ case 14:
+ noisefunc1 = cellNoise;
+ break;
+ case 0:
+ default: {
+ noisefunc1 = orgBlenderNoiseS;
+ }
+ }
+
+ switch (nbas2) {
+ case 1:
+ noisefunc2 = orgPerlinNoise;
+ break;
+ case 2:
+ noisefunc2 = newPerlin;
+ break;
+ case 3:
+ noisefunc2 = voronoi_F1S;
+ break;
+ case 4:
+ noisefunc2 = voronoi_F2S;
+ break;
+ case 5:
+ noisefunc2 = voronoi_F3S;
+ break;
+ case 6:
+ noisefunc2 = voronoi_F4S;
+ break;
+ case 7:
+ noisefunc2 = voronoi_F1F2S;
+ break;
+ case 8:
+ noisefunc2 = voronoi_CrS;
+ break;
+ case 14:
+ noisefunc2 = cellNoise;
+ break;
+ case 0:
+ default: {
+ noisefunc2 = orgBlenderNoiseS;
+ }
+ }
+
+ /* get a random vector and scale the randomization */
+ rv[0] = noisefunc1(x+13.5, y+13.5, z+13.5) * distortion;
+ rv[1] = noisefunc1(x, y, z) * distortion;
+ rv[2] = noisefunc1(x-13.5, y-13.5, z-13.5) * distortion;
+ return noisefunc2(x+rv[0], y+rv[1], z+rv[2]); /* distorted-domain noise */
+}
+
+/****************/
+/* musgrave end */
+/****************/
diff --git a/source/blender/blenlib/intern/psfont.c b/source/blender/blenlib/intern/psfont.c
new file mode 100644
index 00000000000..941bf4204a8
--- /dev/null
+++ b/source/blender/blenlib/intern/psfont.c
@@ -0,0 +1,2126 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * fromtype1 - Convert an Adobe type 1 font into .of or .sf format.
+ * Paul Haeberli - 1990
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_vfontdata.h"
+#include "BLI_blenlib.h"
+
+#include "DNA_packedFile_types.h"
+#include "DNA_curve_types.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+ /* ObjFnt types */
+
+typedef struct chardesc {
+ short movex, movey; /* advance */
+ short llx, lly; /* bounding box */
+ short urx, ury;
+ short *data; /* char data */
+ long datalen;
+} chardesc;
+
+typedef struct objfnt {
+ struct objfnt *freeaddr; /* if freeaddr != 0, objfnt is one chunck */
+ short type;
+ short charmin, charmax;
+ short my_nchars;
+ short scale;
+ chardesc *my_chars;
+} objfnt;
+
+#define OFMAGIC 0x93339333
+
+#define TM_TYPE 1
+#define PO_TYPE 2
+#define SP_TYPE 3
+
+/* ops for tmesh characters */
+
+#define TM_BGNTMESH (1)
+#define TM_SWAPTMESH (2)
+#define TM_ENDBGNTMESH (3)
+#define TM_RETENDTMESH (4)
+#define TM_RET (5)
+
+/* ops for poly characters */
+
+#define PO_BGNLOOP (1)
+#define PO_ENDBGNLOOP (2)
+#define PO_RETENDLOOP (3)
+#define PO_RET (4)
+
+/* ops for spline characters */
+
+#define SP_MOVETO (1)
+#define SP_LINETO (2)
+#define SP_CURVETO (3)
+#define SP_CLOSEPATH (4)
+#define SP_RETCLOSEPATH (5)
+#define SP_RET (6)
+
+
+#define MIN_ASCII ' '
+#define MAX_ASCII '~'
+#define NASCII (256 - 32)
+
+#define NOBBOX (30000)
+
+typedef struct pschar {
+ char *name;
+ int code;
+ int prog;
+} pschar;
+
+ /***/
+
+#define SKIP 4
+#define LINELEN 2048
+#define NOTHEX (100)
+#define MC1 52845
+#define MC2 22719
+#define MAXSUBRS 4000
+#define MAXCHARS 4000
+#define MAXTRIES 30
+
+/* some local thingies */
+static void rcurveto( int dx1, int dy1, int dx2, int dy2, int dx3, int dy3);
+static void makeobjfont(int savesplines);
+static void drawchar(int c);
+static void runprog(void);
+static int chartoindex(objfnt *fnt, int c);
+static short STDtoISO(short c);
+static char * newfgets(char * s, int n, PackedFile * pf);
+static int readfontmatrix(PackedFile * pf, float mat[2][2]);
+static char mdecrypt(char cipher);
+static void decryptall(void);
+static int decodetype1(PackedFile * pf, char *outname);
+static void fakefopen(void);
+static char *fakefread(int n);
+static void setcharlist(void);
+static void initpcstack(void);
+static char *poppc(void);
+static void initstack(void);
+static void push(int val);
+static int pop(void);
+static void initretstack(void);
+static void retpush(int val);
+static int retpop(void);
+static void subr1(void);
+static void subr2(void);
+static void subr0(void);
+static void append_poly_offset(short ofsx, short ofsy, short * data);
+static void append_spline_offset(short ofsx, short ofsy, short * data);
+static void setwidth(int w, int x);
+static void poly_beginchar(void);
+static void poly_endchar(void);
+static void poly_close(void);
+static void poly_pnt(float x, float y);
+static void spline_beginchar(void);
+static void spline_endchar(void);
+static void spline_close(void);
+static void spline_line(float x0, float y0, float x1, float y1);
+static void spline_curveto(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3);
+static void savestart(int x, int y);
+static void sbpoint( int x, int y);
+static void rmoveto( int x, int y);
+static void drawline(float x0, float y0, float x1, float y1, float dx0, float dy0, float dx1, float dy1);
+static void rlineto( int x, int y);
+static void closepath(void);
+static void bezadapt( float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, float beztol);
+static void drawbez( float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3);
+static int docommand(int cmd);
+
+/* some local vars */
+static int startx, starty;
+static int curx, cury;
+static int nextx, nexty;
+static int delx, dely;
+static int started;
+
+
+/* postscript commands */
+#define HSTEM (1)
+#define VSTEM (3)
+#define VMOVETO (4)
+#define RLINETO (5)
+#define HLINETO (6)
+#define VLINETO (7)
+#define RRCURVETO (8)
+#define CLOSEPATH (9)
+#define CALLSUBR (10)
+#define RETURN (11)
+#define HSBW (13)
+#define ENDCHAR (14)
+#define RMOVETO (21)
+#define HMOVETO (22)
+#define VHCURVETO (30)
+#define HVCURVETO (31)
+#define DOTSECTION (256+0)
+#define VSTEM3 (256+1)
+#define HSTEM3 (256+2)
+#define SEAC (256+6)
+#define SBW (256+7)
+#define DIV (256+12)
+#define CALLOTHERSUBR (256+16)
+#define POP (256+17)
+#define SETCURRENTPOINT (256+33)
+#define WHAT0 (0)
+
+static char oneline[LINELEN];
+static objfnt *fnt;
+
+static unsigned short int mr;
+
+static char *bindat;
+static int datbytes;
+static int firsted;
+static short chardata[20000];
+static int nshorts;
+
+static int thecharwidth, thesidebearing;
+static int npnts, nloops;
+static int nvertpos;
+
+static int fakepos;
+static int fakemax;
+
+static float beztol = 100.0;
+
+/* extern: from libfm */
+
+static char *my_subrs[MAXSUBRS];
+static unsigned int my_sublen[MAXSUBRS];
+static char *my_chars[MAXCHARS];
+static unsigned int my_charlen[MAXCHARS];
+static char *my_charname[MAXCHARS];
+static int my_nsubrs, my_nchars;
+
+static short sidebearing[MAXCHARS];
+static char tok[LINELEN];
+static int sp_npnts, sp_nloops;
+
+/*
+ * interpreter globals
+ */
+
+
+static float mat[2][2];
+static char *pcstack[100];
+static char *pc;
+static int pcsp;
+static int coordpos;
+static int coordsave[7][2];
+static int incusp;
+static int retstack[1000];
+static int retsp;
+static int stack[1000];
+static int sp;
+static int savesplines = 1;
+
+static pschar ISOcharlist[NASCII] = {
+ "/space", 040, 0,
+ "/exclam", 041, 0,
+ "/quotedbl", 042, 0,
+ "/numbersign", 043, 0,
+ "/dollar", 044, 0,
+ "/percent", 045, 0,
+ "/ampersand", 046, 0,
+ "/quoteright", 047, 0,
+
+ "/parenleft", 050, 0,
+ "/parenright", 051, 0,
+ "/asterisk", 052, 0,
+ "/plus", 053, 0,
+ "/comma", 054, 0,
+ "/hyphen", 055, 0,
+ "/period", 056, 0,
+ "/slash", 057, 0,
+
+ "/zero", 060, 0,
+ "/one", 061, 0,
+ "/two", 062, 0,
+ "/three", 063, 0,
+ "/four", 064, 0,
+ "/five", 065, 0,
+ "/six", 066, 0,
+ "/seven", 067, 0,
+
+ "/eight", 070, 0,
+ "/nine", 071, 0,
+ "/colon", 072, 0,
+ "/semicolon", 073, 0,
+ "/less", 074, 0,
+ "/equal", 075, 0,
+ "/greater", 076, 0,
+ "/question", 077, 0,
+
+ "/at", 0100, 0,
+ "/A", 0101, 0,
+ "/B", 0102, 0,
+ "/C", 0103, 0,
+ "/D", 0104, 0,
+ "/E", 0105, 0,
+ "/F", 0106, 0,
+ "/G", 0107, 0,
+
+ "/H", 0110, 0,
+ "/I", 0111, 0,
+ "/J", 0112, 0,
+ "/K", 0113, 0,
+ "/L", 0114, 0,
+ "/M", 0115, 0,
+ "/N", 0116, 0,
+ "/O", 0117, 0,
+
+ "/P", 0120, 0,
+ "/Q", 0121, 0,
+ "/R", 0122, 0,
+ "/S", 0123, 0,
+ "/T", 0124, 0,
+ "/U", 0125, 0,
+ "/V", 0126, 0,
+ "/W", 0127, 0,
+
+ "/X", 0130, 0,
+ "/Y", 0131, 0,
+ "/Z", 0132, 0,
+ "/bracketleft", 0133, 0,
+ "/backslash", 0134, 0,
+ "/bracketright", 0135, 0,
+ "/asciicircum", 0136, 0,
+ "/underscore", 0137, 0,
+
+ "/quoteleft", 0140, 0,
+ "/a", 0141, 0,
+ "/b", 0142, 0,
+ "/c", 0143, 0,
+ "/d", 0144, 0,
+ "/e", 0145, 0,
+ "/f", 0146, 0,
+ "/g", 0147, 0,
+
+ "/h", 0150, 0,
+ "/i", 0151, 0,
+ "/j", 0152, 0,
+ "/k", 0153, 0,
+ "/l", 0154, 0,
+ "/m", 0155, 0,
+ "/n", 0156, 0,
+ "/o", 0157, 0,
+
+ "/p", 0160, 0,
+ "/q", 0161, 0,
+ "/r", 0162, 0,
+ "/s", 0163, 0,
+ "/t", 0164, 0,
+ "/u", 0165, 0,
+ "/v", 0166, 0,
+ "/w", 0167, 0,
+
+ "/x", 0170, 0,
+ "/y", 0171, 0,
+ "/z", 0172, 0,
+ "/braceleft", 0173, 0,
+ "/bar", 0174, 0,
+ "/braceright", 0175, 0,
+ "/asciitilde", 0176, 0,
+ "/", 0177, 0,
+
+
+ /* nonstandard defs */
+
+ "/quotedblleft", 0200, 0,
+ "/quotedblright", 0201, 0,
+ "/quotedblbase", 0202, 0,
+ "/quotesinglbase", 0203, 0,
+ "/guilsinglleft", 0204, 0,
+ "/guilsinglright", 0205, 0,
+ "/endash", 0206, 0,
+ "/dagger", 0207, 0,
+
+ "/daggerdbl", 0210, 0,
+ "/trademark", 0211, 0,
+ "/bullet", 0212, 0,
+ "/perthousand", 0213, 0,
+ "/Lslash", 0214, 0,
+ "/OE", 0215, 0,
+ "/lslash", 0216, 0,
+ "/oe", 0217, 0,
+
+ /* endnonstandard defs */
+
+ "/dotlessi", 0220, 0,
+ "/grave", 0221, 0,
+ "/acute", 0222, 0,
+ "/circumflex", 0223, 0,
+ "/tilde", 0224, 0,
+ "/", 0225, 0,
+ "/breve", 0226, 0,
+ "/dotaccent", 0227, 0,
+
+ "/", 0230, 0,
+ "/", 0231, 0,
+ "/ring", 0232, 0,
+ "/", 0233, 0,
+ "/", 0234, 0,
+ "/hungarumlaut", 0235, 0,
+ "/ogonek", 0236, 0,
+ "/caron", 0237, 0,
+
+ "/", 0240, 0,
+ "/exclamdown", 0241, 0,
+ "/cent", 0242, 0,
+ "/sterling", 0243, 0,
+ "/florin", 0244, 0,
+ "/yen", 0245, 0,
+ "/brokenbar", 0246, 0,
+ "/section", 0247, 0,
+
+ "/dieresis", 0250, 0,
+ "/copyright", 0251, 0,
+ "/ordfeminine", 0252, 0,
+ "/guillemotleft", 0253, 0,
+ "/logicalnot", 0254, 0,
+ "/hyphen", 0255, 0,
+ "/registered", 0256, 0,
+ "/macron", 0257, 0,
+
+ "/degree", 0260, 0,
+ "/plusminus", 0261, 0,
+ "/twosuperior", 0262, 0,
+ "/threesuperior", 0263, 0,
+ "/acute", 0264, 0,
+ "/mu", 0265, 0,
+ "/paragraph", 0266, 0,
+ "/periodcentered", 0267, 0,
+
+ "/cedilla", 0270, 0,
+ "/onesuperior", 0271, 0,
+ "/ordmasculine", 0272, 0,
+ "/guillemotright", 0273, 0,
+ "/onequarter", 0274, 0,
+ "/onehalf", 0275, 0,
+ "/threequarters", 0276, 0,
+ "/questiondown", 0277, 0,
+
+ "/Agrave", 0300, 0,
+ "/Aacute", 0301, 0,
+ "/Acircumflex", 0302, 0,
+ "/Atilde", 0303, 0,
+ "/Adieresis", 0304, 0,
+ "/Aring", 0305, 0,
+ "/AE", 0306, 0,
+ "/Ccedilla", 0307, 0,
+
+ "/Egrave", 0310, 0,
+ "/Eacute", 0311, 0,
+ "/Ecircumflex", 0312, 0,
+ "/Edieresis", 0313, 0,
+ "/Igrave", 0314, 0,
+ "/Iacute", 0315, 0,
+ "/Icircumflex", 0316, 0,
+ "/Idieresis", 0317, 0,
+
+ "/Eth", 0320, 0,
+ "/Ntilde", 0321, 0,
+ "/Ograve", 0322, 0,
+ "/Oacute", 0323, 0,
+ "/Ocircumflex", 0324, 0,
+ "/Otilde", 0325, 0,
+ "/Odieresis", 0326, 0,
+ "/multiply", 0327, 0,
+
+ "/Oslash", 0330, 0,
+ "/Ugrave", 0331, 0,
+ "/Uacute", 0332, 0,
+ "/Ucircumflex", 0333, 0,
+ "/Udieresis", 0334, 0,
+ "/Yacute", 0335, 0,
+ "/Thorn", 0336, 0,
+ "/germandbls", 0337, 0,
+
+ "/agrave", 0340, 0,
+ "/aacute", 0341, 0,
+ "/acircumflex", 0342, 0,
+ "/atilde", 0343, 0,
+ "/adieresis", 0344, 0,
+ "/aring", 0345, 0,
+ "/ae", 0346, 0,
+ "/ccedilla", 0347, 0,
+
+ "/egrave", 0350, 0,
+ "/eacute", 0351, 0,
+ "/ecircumflex", 0352, 0,
+ "/edieresis", 0353, 0,
+ "/igrave", 0354, 0,
+ "/iacute", 0355, 0,
+ "/icircumflex", 0356, 0,
+ "/idieresis", 0357, 0,
+
+ "/eth", 0360, 0,
+ "/ntilde", 0361, 0,
+ "/ograve", 0362, 0,
+ "/oacute", 0363, 0,
+ "/ocircumflex", 0364, 0,
+ "/otilde", 0365, 0,
+ "/odieresis", 0366, 0,
+ "/divide", 0367, 0,
+
+ "/oslash", 0370, 0,
+ "/ugrave", 0371, 0,
+ "/uacute", 0372, 0,
+ "/ucircumflex", 0373, 0,
+ "/udieresis", 0374, 0,
+ "/yacute", 0375, 0,
+ "/thorn", 0376, 0,
+ "/ydieresis", 0377, 0,
+};
+
+
+static short STDvsISO [][2] = {
+ 0341, 0306, /* AE */
+ 0351, 0330, /* Oslash */
+ 0302, 0222, /* acute */
+ 0361, 0346, /* ae */
+ 0306, 0226, /* breve */
+ 0317, 0237, /* caron */
+ 0313, 0270, /* cedilla */
+ 0303, 0223, /* circumflex */
+ 0250, 0244, /* currency */
+ 0310, 0250, /* dieresis */
+ 0307, 0227, /* dotaccent */
+ 0365, 0220, /* dotlessi */
+ 0373, 0337, /* germandbls */
+ 0301, 0221, /* grave */
+ 0315, 0235, /* hungarumlaut */
+ 0055, 0255, /* hyphen */
+ 0305, 0257, /* macron */
+ 0316, 0236, /* ogenek */
+ 0343, 0252, /* ordfeminine */
+ 0353, 0272, /* ordmasculine */
+ 0371, 0370, /* oslash */
+ 0264, 0267, /* periodcentered */
+ 0312, 0232, /* ring */
+ 0304, 0224, /* tilde */
+};
+
+/* from objfont.c, rest is in lfm_s !!*/
+
+/* START 5.2 */
+
+static int chartoindex(objfnt *fnt, int c)
+{
+ if(c<fnt->charmin)
+ return -1;
+ if(c>fnt->charmax)
+ return -1;
+ return c-fnt->charmin;
+}
+
+
+static chardesc *getchardesc(objfnt *fnt, int c)
+{
+ int index;
+
+ index = chartoindex(fnt,c);
+ if(index<0)
+ return 0;
+ return fnt->my_chars+index;
+}
+
+static objfnt *newobjfnt(int type, int charmin, int charmax, int fscale)
+{
+ objfnt *fnt;
+
+ fnt = (objfnt *)MEM_mallocN(sizeof(objfnt), "newobjfnt");
+ fnt->freeaddr = 0;
+ fnt->type = type;
+ fnt->charmin = charmin;
+ fnt->charmax = charmax;
+ fnt->my_nchars = fnt->charmax-fnt->charmin+1;
+ fnt->scale = fscale;
+ fnt->my_chars = (chardesc *)MEM_mallocN(fnt->my_nchars*sizeof(chardesc), "newobjfnt2");
+ memset(fnt->my_chars, 0, fnt->my_nchars*sizeof(chardesc));
+ return fnt;
+}
+
+
+static void addchardata (objfnt * fnt, int c, short * data, int nshorts)
+{
+ int index;
+ chardesc *cd;
+
+ index = chartoindex(fnt,c);
+ if(index<0) {
+ fprintf(stderr,"Addchardata bad poop\n");
+ return;
+ }
+ cd = fnt->my_chars+index;
+ fnt->freeaddr = 0;
+ cd->datalen = nshorts*sizeof(short);
+ cd->data = (short *)MEM_mallocN(cd->datalen, "addchardata");
+ memcpy(cd->data, data, cd->datalen);
+}
+
+static void addcharmetrics(objfnt *fnt, int c, int movex, int movey)
+{
+ int index;
+ chardesc *cd;
+
+ index = chartoindex(fnt,c);
+ if(index<0) {
+ fprintf(stderr,"Addcharmetrics bad poop\n");
+ return;
+ }
+ cd = fnt->my_chars+index;
+ cd->movex = movex;
+ cd->movey = movey;
+}
+
+
+static void fakechar(objfnt *fnt, int c, int width)
+{
+ short chardata[1];
+
+ chardata[0] = PO_RET;
+ addchardata(fnt,c,chardata,1);
+ addcharmetrics(fnt,c,width,0);
+}
+
+
+static void freeobjfnt(objfnt * fnt)
+{
+ int i;
+ chardesc *cd;
+
+ cd = fnt->my_chars;
+ for(i=0; i<fnt->my_nchars; i++) {
+ if(cd->data)
+ MEM_freeN(cd->data);
+ cd++;
+ }
+ MEM_freeN(fnt->my_chars);
+ MEM_freeN(fnt);
+}
+
+
+/* END 5.2 */
+
+static short STDtoISO(short c)
+{
+ short i = (sizeof(STDvsISO) / (2 * sizeof(short))) - 1;
+
+ for (;i >= 0; i--){
+ if (STDvsISO[i][0] == c) return (STDvsISO[i][1]);
+ }
+ return(c);
+}
+
+
+/*
+ * read the font matrix out of the font file
+ *
+ */
+
+static char * newfgets(char * s, int n, PackedFile * pf){
+ int c;
+ char * p;
+
+ p = s;
+ while (n > 0){
+ c = ((char *) pf->data)[pf->seek];
+ pf->seek++;
+ if (pf->seek > pf->size){
+ return (0);
+ }
+ if (c == 10 || c == 13){
+ *p = 0;
+ return(s);
+ }
+ *p++ = c;
+ n--;
+ }
+ *p = 0;
+ return(s);
+}
+
+static int readfontmatrix(PackedFile * pf, float mat[2][2])
+{
+ char *cptr;
+ float a, b, c, d, e, f;
+
+ pf->seek = 0;
+
+ /* look for the FontMatrix def */
+ while(1) {
+ if(!newfgets(oneline, LINELEN, pf)) {
+ fprintf(stderr,"fromtype1: no FontMatrix found\n");
+ return(-1);
+ }
+ cptr = strchr(oneline,'/');
+ if(cptr) {
+ if(strncmp(cptr,"/FontMatrix",11) == 0) {
+ cptr = strchr(cptr,'[');
+ if(!cptr) {
+ fprintf(stderr,"fromtype1: bad FontMatrix line\n");
+ return(-1);
+ }
+ sscanf(cptr+1,"%f %f %f %f %f %f\n",&a,&b,&c,&d,&e,&f);
+ break;
+ }
+ }
+ }
+
+ mat[0][0] = 1000.0*a;
+ mat[1][0] = 1000.0*b;
+ mat[0][1] = 1000.0*c;
+ mat[1][1] = 1000.0*d;
+
+ return(0);
+}
+
+/*
+ * Decryption support
+ *
+ *
+ */
+static void resetdecrypt(int n)
+{
+ mr = n;
+}
+
+
+
+/*
+ * decryption subroutines
+ *
+ */
+
+static char mdecrypt(char cipher)
+{
+ char plain;
+
+ plain = (cipher^(mr>>8));
+ mr = (cipher+mr)*MC1 + MC2;
+ return plain;
+}
+
+static void decryptdata(char * cptr, int n)
+{
+ while(n--) {
+ *cptr = mdecrypt(*cptr);
+ cptr++;
+ }
+}
+
+static int decryptprogram(char *buf, int len)
+{
+ int i;
+
+ resetdecrypt(4330);
+ for(i=0; i<len; i++) {
+ if(i<SKIP) {
+ mdecrypt(buf[i]);
+ }
+ else {
+ buf[i-SKIP] = mdecrypt(buf[i]);
+ }
+ }
+ return len-SKIP;
+}
+
+static void decryptall(void)
+{
+ int i;
+
+ for(i=0; i<my_nsubrs; i++)
+ my_sublen[i] = decryptprogram(my_subrs[i],my_sublen[i]);
+ for(i=0; i<my_nchars; i++)
+ my_charlen[i] = decryptprogram(my_chars[i],my_charlen[i]);
+}
+
+
+/*
+ * decode the eexec part of the file
+ *
+ */
+
+static int decodetype1(PackedFile * pf, char *outname)
+{
+ char *hptr, *bptr;
+ int i, totlen, hexbytes, c;
+ char *hexdat;
+ char hextab[256];
+
+ /* make hex table */
+ if(!firsted) {
+ for(i=0; i<256; i++) {
+ if(i>='0' && i<='9')
+ hextab[i] = i-'0';
+ else if(i>='a' && i<='f')
+ hextab[i] = 10+i-'a';
+ else if(i>='A' && i<='F')
+ hextab[i] = 10+i-'A';
+ else
+ hextab[i] = NOTHEX;
+ }
+ }
+
+ pf->seek = 0;
+
+ /* allocate buffers */
+ totlen = pf->size;
+ hexdat = (char *)MEM_mallocN(totlen, "hexdat");
+ bindat = (char *)MEM_mallocN(totlen, "bindat");
+
+ /* look for eexec part of file */
+ while(1) {
+ if(!newfgets(oneline, LINELEN, pf)) {
+ fprintf(stderr,"fromtype1: no currentfile eexec found\n");
+ return(-1);
+ }
+ oneline[16] = 0;
+ if(strcmp(oneline,"currentfile eexe") == 0)
+ break;
+ }
+
+ /* initialize decryption variables */
+ mr = 55665;
+
+ /* first byte == 0 for binary data (???) */
+
+ c = ((char *) pf->data)[pf->seek];
+
+ if (hextab[c] != NOTHEX){
+ /* read all the hex bytes into the hex buffer */
+ hexbytes = 0;
+ while(newfgets(oneline, LINELEN, pf)) {
+ hptr = (char *)oneline;
+ while(*hptr) {
+ if(hextab[*hptr] != NOTHEX)
+ hexdat[hexbytes++] = *hptr;
+ hptr++;
+ }
+ }
+
+ /* check number of hex bytes */
+ if(hexbytes & 1)
+ hexbytes--;
+ datbytes = hexbytes/2;
+
+ /* translate hex data to binary */
+ hptr = hexdat;
+ bptr = bindat;
+ c = datbytes;
+ while(c--) {
+ *bptr++ = (hextab[hptr[0]]<<4)+hextab[hptr[1]];
+ hptr += 2;
+ }
+
+ /* decrypt the data */
+ decryptdata(bindat,datbytes);
+
+ } else {
+ datbytes = pf->size - pf->seek;
+ memcpy(bindat, ((char *) pf->data) + pf->seek, datbytes);
+
+ if ((bindat[2] << (8 + bindat[3])) == 0x800){
+ /* order data (remove 6 bytes headers) */
+ i = datbytes;
+ hptr = bptr = bindat + 4;
+ hptr += 2;
+
+ while (i > 0){
+ if (i > 2046) c = 2046;
+ else c = i;
+
+ memcpy(bptr, hptr, c);
+ bptr += 2046;
+ hptr += 2046 + 6;
+ i -= 2046 + 6;
+ datbytes -= 6;
+ }
+
+ /* decrypt the data */
+ decryptdata(bindat+4,datbytes);
+ } else{
+ decryptdata(bindat+6,datbytes-6);
+ }
+ }
+
+#ifdef DEBUG
+ outf = fopen(outname,"wb");
+ fwrite(bindat,datbytes,1,outf);
+ fclose(outf);
+#endif
+
+ MEM_freeN(hexdat);
+
+ return 1;
+}
+
+/*
+ * fake file reading funcs
+ *
+ *
+ */
+
+static void fakefopen(void)
+{
+ fakepos = 0;
+ fakemax = datbytes;
+}
+
+
+static void fakegettoken(char *str)
+{
+ int c;
+ char *cptr;
+ char *start;
+
+ start = (char *) str;
+ cptr = bindat+fakepos;
+ c = *cptr++;
+ fakepos++;
+ if(c != '\n') {
+ while(isspace(c)) {
+ c = *cptr++;
+ fakepos++;
+ }
+ while (fakepos<fakemax && !isspace(c)) {
+ *str++ = c;
+ c = *cptr++;
+ fakepos++;
+ }
+ if(c == '\n')
+ fakepos--;
+ }
+ *str = 0;
+ if(fakepos>fakemax) {
+ fprintf(stderr,"fromtype1: unexpected eof\n");
+ strcpy(start, "end");
+ }
+}
+
+static int fakefgets(char *buf,int max)
+{
+ char *cptr;
+
+ cptr = (char *)(bindat+fakepos);
+ while(max--) {
+ *buf++ = *cptr;
+ fakepos++;
+ if(*cptr == 10 || *cptr == 13)
+ return 1;
+ cptr++;
+ if(fakepos>fakemax)
+ return 0;
+ }
+ return 0;
+}
+
+static char *fakefread(int n)
+{
+ fakepos += n;
+ return bindat+fakepos-n;
+}
+
+static void applymat(float mat[][2], float *x, float *y)
+{
+ float tx, ty;
+
+ tx = ((*x)*mat[0][0])+((*y)*mat[0][1]);
+ ty = ((*x)*mat[1][0])+((*y)*mat[1][1]);
+ *x = tx;
+ *y = ty;
+}
+
+static void setcharlist(void)
+{
+ char *name, found;
+ int i, j;
+
+ for(i=0; i<NASCII; i++) ISOcharlist[i].prog = -1;
+
+ for(j=0; j<my_nchars; j++) {
+ name = my_charname[j];
+ if(name) {
+ found = 0;
+ for(i=0; i<NASCII; i++) {
+ if(ISOcharlist[i].name && (strcmp(name,ISOcharlist[i].name) == 0)){
+ ISOcharlist[i].prog = j;
+ found = 1;
+ }
+ }
+ /*if (found == 0) printf("no match found for: %s\n", name);*/
+ MEM_freeN(name);
+ my_charname[j] = 0;
+ }
+ }
+}
+
+
+static objfnt * objfnt_from_psfont(PackedFile * pf)
+{
+ int i, k, index;
+ int nread, namelen;
+ char *cptr;
+
+ fnt = 0;
+ bindat = 0;
+
+ /* read the font matrix from the font */
+ if (readfontmatrix(pf,mat)) return(0);
+
+ /* decode the font data */
+ decodetype1(pf, "/usr/tmp/type1.dec");
+
+ /* open the input file */
+ fakefopen();
+
+ /* look for the /Subrs def and get my_nsubrs */
+ while(1) {
+ if(!fakefgets(oneline,LINELEN)) {
+ fprintf(stderr,"fromtype1: no /Subrs found\n");
+ my_nsubrs = 0;
+ fakefopen();
+ break;
+ }
+ cptr = strchr(oneline,'/');
+ if(cptr) {
+ if(strncmp(cptr,"/Subrs",6) == 0) {
+ my_nsubrs = atoi(cptr+6);
+ break;
+ }
+ }
+ }
+
+ /* read the Subrs in one by one */
+ for(i=0; i<my_nsubrs; i++)
+ my_sublen[i] = 0;
+ for(i=0; i<my_nsubrs; i++) {
+ for(k=0; k<MAXTRIES; k++) {
+ fakegettoken(tok);
+ if(strcmp(tok,"dup") == 0)
+ break;
+ }
+ if(k == MAXTRIES) {
+ fprintf(stderr,"dup for subr %d not found in range\n", i);
+ /*exit(1);*/
+ }
+
+ /* get the Subr index here */
+ fakegettoken(tok);
+ index = atoi(tok);
+
+ /* check to make sure it is in range */
+ if(index<0 || index>my_nsubrs) {
+ fprintf(stderr,"bad Subr index %d\n",index);
+ /*exit(1);*/
+ }
+
+ /* get the number of bytes to read */
+ fakegettoken(tok);
+ nread = atoi(tok);
+ fakegettoken(tok);
+
+ /* read in the subroutine */
+ my_sublen[index] = nread;
+ my_subrs[index] = fakefread(nread);
+ fakegettoken(tok);
+ }
+
+ /* look for the CharStrings */
+ while(1) {
+ fakegettoken(tok);
+ cptr = strchr(tok,'/');
+ if(cptr && strcmp(cptr,"/CharStrings") == 0)
+ break;
+ }
+
+ fakegettoken(tok); /* skip my_ncharscrings */
+ fakegettoken(tok); /* skip dict */
+ fakegettoken(tok); /* skip dup */
+ fakegettoken(tok); /* skip begin */
+ fakegettoken(tok); /* skip newline */
+
+ /* read the CharStrings one by one */
+ my_nchars = 0;
+ for(i=0; i<MAXCHARS; i++) {
+
+ /* check for end */
+ fakegettoken(tok);
+ if(strcmp(tok,"end") == 0)
+ break;
+
+ /* get the char name and allocate space for it */
+ namelen = strlen(tok);
+ my_charname[i] = (char *)MEM_mallocN(namelen+1, "my_charname");
+ strcpy(my_charname[i],tok);
+
+ /* get the number of bytes to read */
+ fakegettoken(tok);
+ nread = atoi(tok);
+ fakegettoken(tok);
+
+ /* read in the char description */
+ my_charlen[i] = nread;
+ my_chars[i] = fakefread(nread);
+
+ /* skip the end of line */
+ fakegettoken(tok);
+ fakegettoken(tok);
+ my_nchars++;
+ }
+
+ /* decrypt the character descriptions */
+ decryptall();
+ setcharlist();
+
+ /* make the obj font */
+ makeobjfont(savesplines);
+
+ if (bindat) MEM_freeN(bindat);
+ /* system("rm /usr/tmp/type1.dec"); */
+
+ return (fnt);
+}
+
+
+
+
+/*
+ * pc stack support
+ *
+ */
+
+static void initpcstack(void)
+{
+ pcsp = 0;
+}
+
+static void pushpc(char *pc)
+{
+ pcstack[pcsp] = pc;
+ pcsp++;
+}
+
+static char *poppc(void)
+{
+ pcsp--;
+ if(pcsp<0) {
+ fprintf(stderr,"\nYUCK: pc stack under flow\n");
+ pcsp = 0;
+ return 0;
+ }
+ return pcstack[pcsp];
+}
+
+/*
+ * Data stack support
+ *
+ */
+
+static void initstack(void)
+{
+ sp = 0;
+}
+
+static void push(int val)
+/* int val; */
+{
+ stack[sp] = val;
+ sp++;
+}
+
+static int pop(void)
+{
+ sp--;
+ if(sp<0) {
+ fprintf(stderr,"\nYUCK: stack under flow\n");
+ sp = 0;
+ return 0;
+ }
+ return stack[sp];
+}
+
+/*
+ * call/return data stack
+ *
+ */
+
+static void initretstack(void)
+{
+ retsp = 0;
+}
+
+static void retpush(int val)
+/* int val; */
+{
+ retstack[retsp] = val;
+ retsp++;
+}
+
+static int retpop(void)
+{
+ retsp--;
+ if(retsp<0) {
+ fprintf(stderr,"\nYUCK: ret stack under flow\n");
+ retsp = 0;
+ return 0;
+ }
+ return retstack[retsp];
+}
+
+
+/*
+ * execute the program:
+ *
+ *
+ */
+
+static void getmove(int *x, int *y)
+{
+ *x = delx;
+ *y = dely;
+ /* printf("ingetmove\n"); */
+}
+
+static void getpos(int *x, int *y)
+{
+ *x = curx;
+ *y = cury;
+}
+
+static void subr1(void)
+{
+ coordpos = 0;
+ incusp = 1;
+}
+
+static void subr2(void)
+{
+ int x, y;
+
+ getmove(&x,&y);
+ if(coordpos>=7) {
+ fprintf(stderr,"subr2: bad poop\n");
+ /*exit(1);*/
+ }
+ coordsave[coordpos][0] = x;
+ coordsave[coordpos][1] = y;
+ coordpos++;
+}
+
+static void subr0(void)
+{
+ int x0, y0;
+ int x1, y1;
+ int x2, y2;
+ int x3, y3;
+ int xpos, ypos, noise;
+
+ ypos = pop();
+ xpos = pop();
+ noise = pop();
+ if(coordpos!=7) {
+ fprintf(stderr,"subr0: bad poop\n");
+ /*exit(1);*/
+ }
+ x0 = coordsave[0][0];
+ y0 = coordsave[0][1];
+
+ x1 = coordsave[1][0]+x0;
+ y1 = coordsave[1][1]+y0;
+ x2 = coordsave[2][0];
+ y2 = coordsave[2][1];
+ x3 = coordsave[3][0];
+ y3 = coordsave[3][1];
+ rcurveto(x1,y1,x1+x2,y1+y2,x1+x2+x3,y1+y2+y3);
+ x1 = coordsave[4][0];
+ y1 = coordsave[4][1];
+ x2 = coordsave[5][0];
+ y2 = coordsave[5][1];
+ x3 = coordsave[6][0];
+ y3 = coordsave[6][1];
+ rcurveto(x1,y1,x1+x2,y1+y2,x1+x2+x3,y1+y2+y3);
+ getpos(&x0,&y0);
+ retpush(y0);
+ retpush(x0);
+ incusp = 0;
+}
+
+static void append_poly_offset(short ofsx, short ofsy, short * data)
+{
+ int nverts;
+
+ if (data == 0) return;
+
+ while(1) {
+ switch(chardata[nshorts++] = *data++) {
+ case PO_BGNLOOP:
+ nshorts --; /* for the first time */
+ break;
+ case PO_RETENDLOOP:
+ case PO_RET:
+ return;
+ }
+ nverts = chardata[nshorts++] = *data++;
+ while(nverts--) {
+ chardata[nshorts++] = (*data++) + ofsx;
+ chardata[nshorts++] = (*data++) + ofsy;
+ }
+ }
+}
+
+
+static void append_spline_offset(short ofsx, short ofsy, short * data)
+{
+ int nverts = 0;
+
+ if (data == 0) return;
+
+ while(1) {
+ switch(chardata[nshorts++] = *data++) {
+ case SP_MOVETO:
+ case SP_LINETO:
+ nverts = 1;
+ break;
+ case SP_CURVETO:
+ nverts = 3;
+ break;
+ case SP_RETCLOSEPATH:
+ case SP_RET:
+ return;
+ }
+
+ for (; nverts > 0; nverts--) {
+ chardata[nshorts++] = (*data++) + ofsx;
+ chardata[nshorts++] = (*data++) + ofsy;
+ }
+ }
+}
+
+
+
+/*
+ * graphics follows
+ *
+ *
+ */
+
+
+/* poly output stuff */
+
+static void setwidth(int w, int x)
+{
+ thecharwidth = w;
+ thesidebearing = x;
+}
+
+static void poly_beginchar(void)
+{
+ npnts = 0;
+ nloops = 0;
+}
+
+static void poly_endchar(void)
+{
+ if(nloops == 0)
+ chardata[nshorts++] = PO_RET;
+ else
+ chardata[nshorts++] = PO_RETENDLOOP;
+}
+
+static void poly_close(void)
+{
+ chardata[nvertpos] = npnts;
+ npnts = 0;
+}
+
+static void poly_pnt(float x, float y)
+{
+ int ix, iy;
+
+ applymat(mat,&x,&y);
+ ix = floor(x);
+ iy = floor(y);
+ if(npnts == 0) {
+ if(nloops == 0) {
+ chardata[nshorts++] = PO_BGNLOOP;
+ nvertpos = nshorts++;
+ } else {
+ chardata[nshorts++] = PO_ENDBGNLOOP;
+ nvertpos = nshorts++;
+ }
+ nloops++;
+ }
+ chardata[nshorts++] = ix;
+ chardata[nshorts++] = iy;
+ npnts++;
+
+}
+
+/* spline output stuff */
+
+static void spline_beginchar(void)
+{
+ sp_npnts = 0;
+ sp_nloops = 0;
+}
+
+static void spline_endchar(void)
+{
+ if(sp_nloops == 0)
+ chardata[nshorts++] = SP_RET;
+ else
+ chardata[nshorts++] = SP_RETCLOSEPATH;
+}
+
+static void spline_close(void)
+{
+ chardata[nshorts++] = SP_CLOSEPATH;
+ sp_npnts = 0;
+ sp_nloops = 0;
+}
+
+static void spline_line(float x0, float y0, float x1, float y1)
+{
+ applymat(mat,&x0,&y0);
+ applymat(mat,&x1,&y1);
+
+ if(sp_npnts == 0) {
+ chardata[nshorts++] = SP_MOVETO;
+ chardata[nshorts++] = floor(x0);
+ chardata[nshorts++] = floor(y0);
+ sp_npnts++;
+ sp_nloops++;
+ }
+ chardata[nshorts++] = SP_LINETO;
+ chardata[nshorts++] = floor(x1);
+ chardata[nshorts++] = floor(y1);
+ sp_npnts++;
+}
+
+static void spline_curveto(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3)
+{
+ applymat(mat,&x0,&y0);
+
+ applymat(mat,&x1,&y1);
+ applymat(mat,&x2,&y2);
+ applymat(mat,&x3,&y3);
+ if(sp_npnts == 0) {
+ chardata[nshorts++] = SP_MOVETO;
+ chardata[nshorts++] = floor(x0);
+ chardata[nshorts++] = floor(y0);
+ sp_npnts++;
+ sp_nloops++;
+ }
+ chardata[nshorts++] = SP_CURVETO;
+ chardata[nshorts++] = floor(x1);
+ chardata[nshorts++] = floor(y1);
+ chardata[nshorts++] = floor(x2);
+ chardata[nshorts++] = floor(y2);
+ chardata[nshorts++] = floor(x3);
+ chardata[nshorts++] = floor(y3);
+}
+
+static void savestart(int x, int y)
+{
+ startx = x;
+ starty = y;
+ started = 1;
+}
+
+static void sbpoint( int x, int y)
+{
+ curx = x;
+ cury = y;
+}
+
+static void rmoveto( int x, int y)
+{
+ if(incusp) {
+ delx = x;
+ dely = y;
+ } else {
+ curx += x;
+ cury += y;
+ savestart(curx,cury);
+ }
+}
+
+static void drawline(float x0, float y0, float x1, float y1, float dx0, float dy0, float dx1, float dy1)
+{
+ if(x0!=x1 || y0!=y1)
+ poly_pnt(x1,y1);
+}
+
+
+static void rlineto( int x, int y)
+{
+ float dx, dy;
+
+ nextx = curx + x;
+ nexty = cury + y;
+ dx = nextx-curx;
+ dy = nexty-cury;
+ if (savesplines) spline_line( curx, cury, nextx, nexty);
+ else drawline( curx, cury, nextx, nexty,dx,dy,dx,dy);
+ curx = nextx;
+ cury = nexty;
+}
+
+static void closepath(void)
+{
+ float dx, dy;
+
+ if(started) {
+ dx = startx-curx;
+ dy = starty-cury;
+ if (savesplines) {
+ spline_close();
+ } else {
+ drawline( curx, cury, startx, starty,dx,dy,dx,dy);
+ poly_close();
+ }
+ started = 0;
+ }
+}
+
+static void bezadapt( float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, float beztol)
+{
+ float ax0,ay0,ax1,ay1,ax2,ay2,ax3,ay3;
+ float bx0,by0,bx1,by1,bx2,by2,bx3,by3;
+ float midx, midy;
+ float linx, liny, dx, dy, mag;
+
+ midx = (x0+3*x1+3*x2+x3)/8.0;
+ midy = (y0+3*y1+3*y2+y3)/8.0;
+ linx = (x0+x3)/2.0;
+ liny = (y0+y3)/2.0;
+ dx = midx-linx;
+ dy = midy-liny;
+ mag = dx*dx+dy*dy;
+ if(mag<(beztol*beztol))
+ drawline(x0,y0,x3,y3,x1-x0,y1-y0,x3-x2,y3-y2);
+ else {
+ ax0 = x0;
+ ay0 = y0;
+ ax1 = (x0+x1)/2;
+ ay1 = (y0+y1)/2;
+ ax2 = (x0+2*x1+x2)/4;
+ ay2 = (y0+2*y1+y2)/4;
+ ax3 = midx;
+ ay3 = midy;
+ bezadapt(ax0,ay0,ax1,ay1,ax2,ay2,ax3,ay3,beztol);
+
+ bx0 = midx;
+ by0 = midy;
+ bx1 = (x1+2*x2+x3)/4;
+ by1 = (y1+2*y2+y3)/4;
+ bx2 = (x2+x3)/2;
+ by2 = (y2+y3)/2;
+ bx3 = x3;
+ by3 = y3;
+ bezadapt(bx0,by0,bx1,by1,bx2,by2,bx3,by3,beztol);
+ }
+}
+
+static void drawbez( float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3)
+{
+ bezadapt(x0,y0,x1,y1,x2,y2,x3,y3,beztol);
+}
+
+
+static void rcurveto( int dx1, int dy1, int dx2, int dy2, int dx3, int dy3)
+{
+ int x0, y0;
+ int x1, y1;
+ int x2, y2;
+ int x3, y3;
+
+ x0 = curx;
+ y0 = cury;
+ x1 = curx+dx1;
+ y1 = cury+dy1;
+ x2 = curx+dx2;
+ y2 = cury+dy2;
+ x3 = curx+dx3;
+ y3 = cury+dy3;
+
+ if (savesplines) {
+ spline_curveto( x0, y0, x1, y1, x2, y2, x3, y3);
+ } else{
+ drawbez( x0, y0, x1, y1, x2, y2, x3, y3);
+ }
+ curx = x3;
+ cury = y3;
+}
+
+/*
+ * saveobjfont -
+ * save an object font.
+ *
+ */
+
+/* generic routines */
+
+static void makeobjfont(int savesplines)
+{
+ int i, c;
+
+ if(savesplines)
+ fnt = newobjfnt(SP_TYPE, 32, 32+NASCII-1, 9840);
+ else
+ fnt = newobjfnt(PO_TYPE, 32, 32+NASCII-1, 9840);
+
+ for(i=0; i<NASCII; i++) {
+ c = i+32;
+ if(ISOcharlist[i].prog>=0) {
+ /*printf("decoding %s\n", ISOcharlist[i].name);*/
+
+ nshorts = 0;
+ drawchar(ISOcharlist[i].prog);
+ addchardata(fnt,c,chardata,nshorts);
+ addcharmetrics(fnt,c,thecharwidth,0);
+ sidebearing[c] = thesidebearing;
+ } else if(c == ' ') {
+ printf("faking space %d\n",i);
+ fakechar(fnt,' ',400);
+ }
+ }
+}
+
+/*
+ * run the character program
+ *
+ *
+ */
+
+static void drawchar(int c)
+{
+ if (savesplines) {
+ spline_beginchar();
+ } else {
+ poly_beginchar();
+ }
+ initstack();
+ initpcstack();
+ initretstack();
+ pc = my_chars[c];
+ runprog();
+ if (savesplines){
+ spline_endchar();
+ } else {
+ poly_endchar();
+ }
+}
+
+static int docommand(int cmd)
+{
+ int x, y, w, c1, c2;
+ int dx1, dy1;
+ int dx2, dy2;
+ int dx3, dy3;
+ float fdx1, fdy1;
+ int i, sub, n;
+ char *subpc;
+ chardesc *cd;
+ short *ndata;
+
+ switch(cmd) {
+ case WHAT0:
+ fprintf(stderr,"\nYUCK: WHAT0\n");
+ break;
+ case HSTEM:
+ pop();
+ pop();
+ /*printf("hstem: %d %d\n", pop(), pop());*/
+ break;
+ case VSTEM:
+ pop();
+ pop();
+ /*printf("vstem: %d %d\n", pop(), pop());*/
+ break;
+ case VMOVETO:
+ y = pop();
+ rmoveto(0,y);
+ break;
+ case RLINETO:
+ y = pop();
+ x = pop();
+ rlineto(x,y);
+ break;
+ case HLINETO:
+ x = pop();
+ rlineto(x,0);
+ break;
+ case VLINETO:
+ y = pop();
+ rlineto(0,y);
+ break;
+ case RRCURVETO:
+ dy3 = pop();
+ dx3 = pop();
+ dy2 = pop();
+ dx2 = pop();
+ dy1 = pop();
+ dx1 = pop();
+ rcurveto(dx1,dy1,dx1+dx2,dy1+dy2,dx1+dx2+dx3,dy1+dy2+dy3);
+ break;
+ case CLOSEPATH:
+ closepath();
+ break;
+ case CALLSUBR:
+ sub = pop();
+ subpc = my_subrs[sub];
+ if(!subpc) {
+ fprintf(stderr,"\nYUCK no sub addr\n");
+ }
+ pushpc(pc);
+ pc = subpc;
+ break;
+ case RETURN:
+ pc = poppc();
+ break;
+ case HSBW:
+ w = pop();
+ x = pop();
+ setwidth(w, x);
+ sbpoint(x,0);
+ break;
+ case ENDCHAR:
+ closepath();
+ break;
+ case RMOVETO:
+ y = pop();
+ x = pop();
+ rmoveto(x,y);
+ break;
+ case HMOVETO:
+ x = pop();
+ rmoveto(x,0);
+ break;
+ case VHCURVETO:
+ dy3 = 0;
+ dx3 = pop();
+ dy2 = pop();
+ dx2 = pop();
+ dy1 = pop();
+ dx1 = 0;
+ rcurveto(dx1,dy1,dx1+dx2,dy1+dy2,dx1+dx2+dx3,dy1+dy2+dy3);
+ break;
+ case HVCURVETO:
+ dy3 = pop();
+ dx3 = 0;
+ dy2 = pop();
+ dx2 = pop();
+ dy1 = 0;
+ dx1 = pop();
+ rcurveto(dx1,dy1,dx1+dx2,dy1+dy2,dx1+dx2+dx3,dy1+dy2+dy3);
+ break;
+ case DOTSECTION:
+ break;
+ case VSTEM3:
+ /*printf("vstem3\n");*/
+ pop();
+ pop();
+ pop();
+ pop();
+ pop();
+ pop();
+ break;
+ case HSTEM3:
+ /*printf("hstem3\n");*/
+ pop();
+ pop();
+ pop();
+ pop();
+ pop();
+ pop();
+ break;
+ case SEAC:
+ if (0) {
+ printf("seac: %3d %3d %3d %3d %3d\n", pop(), pop(), pop(), pop(), pop());
+ } else{
+ c2 = STDtoISO(pop()); /* accent */
+ c1 = STDtoISO(pop()); /* letter */
+
+ cd = getchardesc(fnt, c1);
+ if (cd) {
+ memcpy(chardata, cd->data, cd->datalen);
+ nshorts = cd->datalen / sizeof(short);
+ }
+
+ cd = getchardesc(fnt, c2);
+ if (cd && cd->data && cd->datalen) {
+ ndata = cd->data;
+
+ if (nshorts) {
+ if (savesplines) {
+ switch (chardata[nshorts - 1]){
+ case SP_RET:
+ nshorts--;
+ break;
+ case SP_RETCLOSEPATH:
+ chardata[nshorts - 1] = SP_CLOSEPATH;
+ break;
+ }
+ } else {
+ switch (chardata[nshorts - 1]){
+ case PO_RET:
+ printf("PO_RET in character disription ?\n");
+ nshorts--;
+ break;
+ case PO_RETENDLOOP:
+ if (ndata[0] == PO_BGNLOOP) {
+ chardata[nshorts - 1] = PO_ENDBGNLOOP;
+ } else {
+ printf("new character doesn't start with PO_BGNLOOP ?\n");
+ }
+ break;
+ }
+ }
+ }
+
+ /* instead of the sidebearing[c1] maybe thesidebearing should be used */
+
+ dy1 = pop();
+ dx1 = pop() + sidebearing[c1] - sidebearing[c2];
+ pop();
+
+ fdx1 = dx1;
+ fdy1 = dy1;
+ applymat(mat, &fdx1, &fdy1);
+ dx1 = floor(fdx1);
+ dy1 = floor(fdy1);
+
+ if (savesplines) {
+ append_spline_offset(dx1, dy1, ndata);
+ } else{
+ append_poly_offset(dx1, dy1, ndata);
+ }
+
+ /*printf("first: %d %d\n", cd->data[0], cd->data[1]);*/
+ }
+ fflush(stdout);
+ }
+ break;
+ case SBW:
+ w = pop();
+ y = pop();
+ fprintf(stderr,"sbw: width: %d %d\n",w,y);
+ y = pop();
+ x = pop();
+ fprintf(stderr,"sbw: side: %d %d\n",x,y);
+ setwidth(w, x);
+ sbpoint(x,y);
+ break;
+ case DIV:
+ x = pop();
+ y = pop();
+ push(x/y);
+ break;
+ case CALLOTHERSUBR:
+ sub = pop();
+ n = pop();
+ if(sub == 0)
+ subr0();
+ else if(sub == 1)
+ subr1();
+ else if(sub == 2)
+ subr2();
+ else {
+ for(i=0; i<n; i++) {
+ retpush(pop());
+ }
+ }
+ break;
+ case POP:
+ push(retpop());
+ break;
+ case SETCURRENTPOINT:
+ y = pop();
+ x = pop();
+ sbpoint(x,y);
+ break;
+ default:
+ /*fprintf(stderr,"\nYUCK bad instruction %d\n",cmd);*/
+ break;
+ }
+ if(pc == 0 || cmd == ENDCHAR || cmd == WHAT0 || cmd == SEAC)
+ return 0;
+ else
+ return 1;
+}
+
+
+/*
+ * Character interpreter
+ *
+ */
+
+static void runprog(void)
+{
+ int v, w, num, cmd;
+
+ while(1) {
+ v = *pc++;
+ if(v>=0 && v<=31) {
+ if(v == 12) {
+ w = *pc++;
+ cmd = 256+w;
+ } else
+ cmd = v;
+ if(!docommand(cmd)) {
+ return;
+ }
+ } else if(v>=32 && v<=246) {
+ num = v-139;
+ push(num);
+ } else if(v>=247 && v<=250) {
+ w = *pc++;
+ num = (v-247)*256+w+108;
+ push(num);
+ } else if(v>=251 && v<=254) {
+ w = *pc++;
+ num = -(v-251)*256-w-108;
+ push(num);
+ } else if(v == 255) {
+ num = *pc++;
+ num <<= 8;
+ num |= *pc++;
+ num <<= 8;
+ num |= *pc++;
+ num <<= 8;
+ num |= *pc++;
+ push(num);
+ }
+ }
+}
+
+/***/
+
+static VFontData *objfnt_to_vfontdata(objfnt *fnt)
+{
+ VFontData *vfd;
+ chardesc *cd;
+ short *_data, *data;
+ int a, i, count, stop, ready, meet;
+ short first[2], last[2];
+ struct Nurb *nu;
+ struct BezTriple *bezt, *bez2;
+ float scale, dx, dy;
+ struct VChar *che;
+
+ if (!fnt || (fnt->type!=SP_TYPE)) {
+ return NULL;
+ }
+
+ vfd= MEM_callocN(sizeof(*vfd), "VFontData");
+ scale = 10.0/(float)fnt->scale; /* after IRIX 6.2, scaling went wrong */
+
+ for (i = 0; i < MAX_VF_CHARS; i++) {
+ cd = getchardesc(fnt, i);
+ if (cd && cd->data && cd->datalen) {
+ che = (VChar *) MEM_callocN(sizeof(VChar), "objfnt_char");
+ BLI_addtail(&vfd->characters, che);
+ che->index = i;
+ che->width = scale * cd->movex;
+
+ _data = data = cd->data;
+
+ do{
+ /* count first */
+ _data = data;
+ count = 0;
+ ready = stop = 0;
+
+ do{
+ switch(*data++){
+ case SP_MOVETO:
+ first[0] = data[0];
+ first[1] = data[1];
+ case SP_LINETO:
+ count++;
+ last[0] = data[0];
+ last[1] = data[1];
+ data += 2;
+ break;
+ case SP_CURVETO:
+ count++;
+ last[0] = data[4];
+ last[1] = data[5];
+ data += 6;
+ break;
+ case SP_RET:
+ case SP_RETCLOSEPATH:
+ stop = 1;
+ ready = 1;
+ break;
+ case SP_CLOSEPATH:
+ stop = 1;
+ break;
+ }
+ } while (!stop);
+
+ if ((count>0) && last[0] == first[0] && last[1] == first[1]) meet = 1;
+ else meet = 0;
+
+ /* is there more than 1 unique point ?*/
+
+ if (count - meet > 0) {
+ data = _data;
+ nu = (Nurb*)MEM_callocN(sizeof(struct Nurb),"objfnt_nurb");
+ bezt = (BezTriple*)MEM_callocN((count)* sizeof(BezTriple),"objfnt_bezt") ;
+ if (nu != 0 && bezt != 0) {
+ BLI_addtail(&che->nurbsbase, nu);
+ nu->type= CU_BEZIER+CU_2D;
+ nu->pntsu = count;
+ nu->resolu= 8;
+ nu->flagu= 1;
+ nu->bezt = bezt;
+ stop = 0;
+
+ /* read points */
+ do {
+ switch(*data++){
+ case SP_MOVETO:
+ bezt->vec[1][0] = scale * *data++;
+ bezt->vec[1][1] = scale * *data++;
+
+ break;
+ case SP_LINETO:
+ bez2 = bezt++;
+ bezt->vec[1][0] = scale * *data++;
+ bezt->vec[1][1] = scale * *data++;
+ /* vector handles */
+ bezt->h1= HD_VECT;
+ bez2->h2= HD_VECT;
+ dx = (bezt->vec[1][0] - bez2->vec[1][0]) / 3.0;
+ dy = (bezt->vec[1][1] - bez2->vec[1][1]) / 3.0;
+ bezt->vec[0][0] = bezt->vec[1][0] - dx;
+ bezt->vec[0][1] = bezt->vec[1][1] - dy;
+ bez2->vec[2][0] = bez2->vec[1][0] + dx;
+ bez2->vec[2][1] = bez2->vec[1][1] + dy;
+ break;
+
+ case SP_CURVETO:
+ bezt->vec[2][0] = scale * *data++;
+ bezt->vec[2][1] = scale * *data++;
+ bezt->h2= HD_ALIGN;
+ bezt++;
+ bezt->vec[0][0] = scale * *data++;
+ bezt->vec[0][1] = scale * *data++;
+ bezt->vec[1][0] = scale * *data++;
+ bezt->vec[1][1] = scale * *data++;
+ bezt->h1= HD_ALIGN;
+ break;
+
+ case SP_RET:
+ case SP_RETCLOSEPATH:
+ stop = 1;
+ ready = 1;
+ break;
+ case SP_CLOSEPATH:
+ stop = 1;
+ break;
+ }
+ } while (stop == 0);
+
+ if (meet) {
+ /* copy handles */
+ nu->bezt->vec[0][0] = bezt->vec[0][0];
+ nu->bezt->vec[0][1] = bezt->vec[0][1];
+ /* and forget last point */
+ nu->pntsu--;
+ }
+ else {
+ /* vector handles */
+ bez2 = nu->bezt;
+ dx = (bezt->vec[1][0] - bez2->vec[1][0]) / 3.0;
+ dy = (bezt->vec[1][1] - bez2->vec[1][1]) / 3.0;
+ bezt->vec[2][0] = bezt->vec[1][0] - dx;
+ bezt->vec[2][1] = bezt->vec[1][1] - dy;
+ bez2->vec[0][0] = bez2->vec[1][0] + dx;
+ bez2->vec[0][1] = bez2->vec[1][1] + dy;
+ bezt->h2= bez2->h1= HD_VECT;
+ }
+
+ /* forbidden handle combinations */
+ a= nu->pntsu;
+ bezt= nu->bezt;
+ while(a--) {
+ if(bezt->h1!=HD_ALIGN && bezt->h2==HD_ALIGN) bezt->h2= 0;
+ else if(bezt->h2!=HD_ALIGN && bezt->h1==HD_ALIGN) bezt->h1= 0;
+ bezt++;
+ }
+
+ }
+ else {
+ if (nu) MEM_freeN(nu);
+ if (bezt) MEM_freeN(bezt);
+ }
+ }
+ _data = data;
+ } while (ready == 0);
+ }
+ }
+
+ return vfd;
+}
+
+VFontData *BLI_vfontdata_from_psfont(PackedFile *pf)
+{
+ objfnt *fnt= objfnt_from_psfont(pf);
+ VFontData *vfd= NULL;
+
+ if (fnt) {
+ vfd= objfnt_to_vfontdata(fnt);
+ freeobjfnt(fnt);
+ }
+
+ return vfd;
+}
diff --git a/source/blender/blenlib/intern/rand.c b/source/blender/blenlib/intern/rand.c
new file mode 100644
index 00000000000..df01288aab8
--- /dev/null
+++ b/source/blender/blenlib/intern/rand.c
@@ -0,0 +1,192 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "PIL_time.h"
+
+#include "BLI_threads.h"
+#include "BLI_rand.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if defined(WIN32) && !defined(FREE_WINDOWS)
+typedef unsigned __int64 r_uint64;
+
+#define MULTIPLIER 0x5DEECE66Di64
+#define MASK 0x0000FFFFFFFFFFFFi64
+#else
+typedef unsigned long long r_uint64;
+
+#define MULTIPLIER 0x5DEECE66Dll
+#define MASK 0x0000FFFFFFFFFFFFll
+#endif
+
+#define ADDEND 0xB
+
+#define LOWSEED 0x330E
+
+/***/
+
+struct RNG {
+ r_uint64 X;
+};
+
+RNG *rng_new(unsigned int seed)
+{
+ RNG *rng = MEM_mallocN(sizeof(*rng), "rng");
+
+ rng_seed(rng, seed);
+
+ return rng;
+}
+
+void rng_free(RNG* rng)
+{
+ MEM_freeN(rng);
+}
+
+void rng_seed(RNG *rng, unsigned int seed) {
+ rng->X= (((r_uint64) seed)<<16) | LOWSEED;
+}
+
+int rng_getInt(RNG *rng) {
+ rng->X= (MULTIPLIER*rng->X + ADDEND)&MASK;
+ return (int) (rng->X>>17);
+}
+
+double rng_getDouble(RNG *rng) {
+ return (double) rng_getInt(rng)/0x80000000;
+}
+
+float rng_getFloat(RNG *rng) {
+ return (float) rng_getInt(rng)/0x80000000;
+}
+
+void rng_shuffleArray(RNG *rng, void *data, int elemSize, int numElems)
+{
+ int i = numElems;
+ void *temp = malloc(elemSize);
+
+ while (--i) {
+ int j = rng_getInt(rng)%numElems;
+ if(i!=j) {
+ void *iElem = (unsigned char*)data + i*elemSize;
+ void *jElem = (unsigned char*)data + j*elemSize;
+ memcpy(temp, iElem, elemSize);
+ memcpy(iElem, jElem, elemSize);
+ memcpy(jElem, temp, elemSize);
+ }
+ }
+
+ free(temp);
+}
+
+/***/
+
+static RNG theBLI_rng = {0};
+
+/* note, this one creates periodical patterns */
+void BLI_srand(unsigned int seed) {
+ rng_seed(&theBLI_rng, seed);
+}
+
+/* using hash table to create better seed */
+void BLI_srandom(unsigned int seed) {
+ extern unsigned char hash[]; // noise.c
+
+ rng_seed(&theBLI_rng, seed + hash[seed & 255]);
+ seed= rng_getInt(&theBLI_rng);
+ rng_seed(&theBLI_rng, seed + hash[seed & 255]);
+ seed= rng_getInt(&theBLI_rng);
+ rng_seed(&theBLI_rng, seed + hash[seed & 255]);
+}
+
+int BLI_rand(void) {
+ return rng_getInt(&theBLI_rng);
+}
+
+double BLI_drand(void) {
+ return rng_getDouble(&theBLI_rng);
+}
+
+float BLI_frand(void) {
+ return rng_getFloat(&theBLI_rng);
+}
+
+void BLI_fillrand(void *addr, int len) {
+ RNG rng;
+ unsigned char *p= addr;
+
+ rng_seed(&rng, (unsigned int) (PIL_check_seconds_timer()*0x7FFFFFFF));
+ while (len--) *p++= rng_getInt(&rng)&0xFF;
+}
+
+void BLI_array_randomize(void *data, int elemSize, int numElems, unsigned int seed)
+{
+ RNG rng;
+
+ rng_seed(&rng, seed);
+ rng_shuffleArray(&rng, data, elemSize, numElems);
+}
+
+/* ********* for threaded random ************** */
+
+static RNG rng_tab[BLENDER_MAX_THREADS];
+
+void BLI_thread_srandom(int thread, unsigned int seed)
+{
+ extern unsigned char hash[]; // noise.c
+
+ if(thread >= BLENDER_MAX_THREADS)
+ thread= 0;
+
+ rng_seed(&rng_tab[thread], seed + hash[seed & 255]);
+ seed= rng_getInt(&rng_tab[thread]);
+ rng_seed(&rng_tab[thread], seed + hash[seed & 255]);
+ seed= rng_getInt(&rng_tab[thread]);
+ rng_seed(&rng_tab[thread], seed + hash[seed & 255]);
+}
+
+int BLI_thread_rand(int thread) {
+ return rng_getInt(&rng_tab[thread]);
+}
+
+float BLI_thread_frand(int thread) {
+ return rng_getFloat(&rng_tab[thread]);
+}
+
diff --git a/source/blender/blenlib/intern/rct.c b/source/blender/blenlib/intern/rct.c
new file mode 100644
index 00000000000..60d96922544
--- /dev/null
+++ b/source/blender/blenlib/intern/rct.c
@@ -0,0 +1,171 @@
+/*
+ *
+ * rct.c
+ *
+ * april 95
+ *
+ * $Id$
+ *
+ * A minimalist lib for functions doing stuff with rectangle structs.
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ *
+ */
+
+#include "DNA_vec_types.h"
+#include "BLI_blenlib.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+int BLI_rcti_is_empty(rcti * rect)
+{
+ return ((rect->xmax<=rect->xmin) ||
+ (rect->ymax<=rect->ymin));
+}
+
+int BLI_in_rcti(rcti * rect, int x, int y)
+{
+
+ if(x<rect->xmin) return 0;
+ if(x>rect->xmax) return 0;
+ if(y<rect->ymin) return 0;
+ if(y>rect->ymax) return 0;
+ return 1;
+}
+
+int BLI_in_rctf(rctf *rect, float x, float y)
+{
+
+ if(x<rect->xmin) return 0;
+ if(x>rect->xmax) return 0;
+ if(y<rect->ymin) return 0;
+ if(y>rect->ymax) return 0;
+ return 1;
+}
+
+void BLI_union_rctf(rctf *rct1, rctf *rct2)
+{
+
+ if(rct1->xmin>rct2->xmin) rct1->xmin= rct2->xmin;
+ if(rct1->xmax<rct2->xmax) rct1->xmax= rct2->xmax;
+ if(rct1->ymin>rct2->ymin) rct1->ymin= rct2->ymin;
+ if(rct1->ymax<rct2->ymax) rct1->ymax= rct2->ymax;
+}
+
+void BLI_init_rctf(rctf *rect, float xmin, float xmax, float ymin, float ymax)
+{
+ rect->xmin= xmin;
+ rect->xmax= xmax;
+ rect->ymin= ymin;
+ rect->ymax= ymax;
+}
+void BLI_init_rcti(rcti *rect, int xmin, int xmax, int ymin, int ymax)
+{
+ rect->xmin= xmin;
+ rect->xmax= xmax;
+ rect->ymin= ymin;
+ rect->ymax= ymax;
+}
+
+void BLI_translate_rcti(rcti *rect, int x, int y)
+{
+ rect->xmin += x;
+ rect->ymin += y;
+ rect->xmax += x;
+ rect->ymax += y;
+}
+void BLI_translate_rctf(rctf *rect, float x, float y)
+{
+ rect->xmin += x;
+ rect->ymin += y;
+ rect->xmax += x;
+ rect->ymax += y;
+}
+
+int BLI_isect_rctf(rctf *src1, rctf *src2, rctf *dest)
+{
+ float xmin, xmax;
+ float ymin, ymax;
+
+ xmin = (src1->xmin) > (src2->xmin) ? (src1->xmin) : (src2->xmin);
+ xmax = (src1->xmax) < (src2->xmax) ? (src1->xmax) : (src2->xmax);
+ ymin = (src1->ymin) > (src2->ymin) ? (src1->ymin) : (src2->ymin);
+ ymax = (src1->ymax) < (src2->ymax) ? (src1->ymax) : (src2->ymax);
+
+ if(xmax>=xmin && ymax>=ymin) {
+ if(dest) {
+ dest->xmin = xmin;
+ dest->xmax = xmax;
+ dest->ymin = ymin;
+ dest->ymax = ymax;
+ }
+ return 1;
+ }
+ else {
+ if(dest) {
+ dest->xmin = 0;
+ dest->xmax = 0;
+ dest->ymin = 0;
+ dest->ymax = 0;
+ }
+ return 0;
+ }
+}
+
+int BLI_isect_rcti(rcti *src1, rcti *src2, rcti *dest)
+{
+ int xmin, xmax;
+ int ymin, ymax;
+
+ xmin = (src1->xmin) > (src2->xmin) ? (src1->xmin) : (src2->xmin);
+ xmax = (src1->xmax) < (src2->xmax) ? (src1->xmax) : (src2->xmax);
+ ymin = (src1->ymin) > (src2->ymin) ? (src1->ymin) : (src2->ymin);
+ ymax = (src1->ymax) < (src2->ymax) ? (src1->ymax) : (src2->ymax);
+
+ if(xmax>=xmin && ymax>=ymin) {
+ if(dest) {
+ dest->xmin = xmin;
+ dest->xmax = xmax;
+ dest->ymin = ymin;
+ dest->ymax = ymax;
+ }
+ return 1;
+ }
+ else {
+ if(dest) {
+ dest->xmin = 0;
+ dest->xmax = 0;
+ dest->ymin = 0;
+ dest->ymax = 0;
+ }
+ return 0;
+ }
+}
diff --git a/source/blender/blenlib/intern/scanfill.c b/source/blender/blenlib/intern/scanfill.c
new file mode 100644
index 00000000000..3c0770e5e07
--- /dev/null
+++ b/source/blender/blenlib/intern/scanfill.c
@@ -0,0 +1,1056 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * (uit traces) maart 95
+ */
+
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+
+#include "BLI_util.h"
+#include "DNA_listBase.h"
+#include "DNA_mesh_types.h"
+#include "BLI_editVert.h"
+#include "BLI_arithb.h"
+#include "BLI_scanfill.h"
+#include "BLI_callbacks.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* callbacks for errors and interrupts and some goo */
+static void (*BLI_localErrorCallBack)(char*) = NULL;
+static int (*BLI_localInterruptCallBack)(void) = NULL;
+
+void BLI_setErrorCallBack(void (*f)(char*))
+{
+ BLI_localErrorCallBack = f;
+}
+
+void BLI_setInterruptCallBack(int (*f)(void))
+{
+ BLI_localInterruptCallBack = f;
+}
+
+/* just flush the error to /dev/null if the error handler is missing */
+void callLocalErrorCallBack(char* msg)
+{
+ if (BLI_localErrorCallBack) {
+ BLI_localErrorCallBack(msg);
+ }
+}
+
+#if 0
+/* ignore if the interrupt wasn't set */
+static int callLocalInterruptCallBack(void)
+{
+ if (BLI_localInterruptCallBack) {
+ return BLI_localInterruptCallBack();
+ } else {
+ return 0;
+ }
+}
+#endif
+
+/* local types */
+typedef struct PolyFill {
+ int edges,verts;
+ float min[3],max[3];
+ short f,nr;
+} PolyFill;
+
+typedef struct ScFillVert {
+ EditVert *v1;
+ EditEdge *first,*last;
+ short f,f1;
+} ScFillVert;
+
+
+/* local funcs */
+
+#define COMPLIMIT 0.00003
+
+static ScFillVert *scdata;
+
+ListBase fillvertbase = {0,0};
+ListBase filledgebase = {0,0};
+ListBase fillfacebase = {0,0};
+
+static short cox, coy;
+
+/* **** FUBCTIONS FOR QSORT *************************** */
+
+
+static int vergscdata(const void *a1, const void *a2)
+{
+ const ScFillVert *x1=a1,*x2=a2;
+
+ if( x1->v1->co[coy] < x2->v1->co[coy] ) return 1;
+ else if( x1->v1->co[coy] > x2->v1->co[coy]) return -1;
+ else if( x1->v1->co[cox] > x2->v1->co[cox] ) return 1;
+ else if( x1->v1->co[cox] < x2->v1->co[cox]) return -1;
+
+ return 0;
+}
+
+static int vergpoly(const void *a1, const void *a2)
+{
+ const PolyFill *x1=a1, *x2=a2;
+
+ if( x1->min[cox] > x2->min[cox] ) return 1;
+ else if( x1->min[cox] < x2->min[cox] ) return -1;
+ else if( x1->min[coy] > x2->min[coy] ) return 1;
+ else if( x1->min[coy] < x2->min[coy] ) return -1;
+
+ return 0;
+}
+
+/* ************* MEMORY MANAGEMENT ************* */
+
+struct mem_elements {
+ struct mem_elements *next, *prev;
+ char *data;
+};
+
+
+/* simple optimization for allocating thousands of small memory blocks
+ only to be used within loops, and not by one function at a time
+ free in the end, with argument '-1'
+*/
+
+static void *new_mem_element(int size)
+{
+ int blocksize= 16384;
+ static int offs= 0; /* the current free adress */
+ static struct mem_elements *cur= 0;
+ static ListBase lb= {0, 0};
+ void *adr;
+
+ if(size>10000 || size==0) {
+ printf("incorrect use of new_mem_element\n");
+ }
+ else if(size== -1) {
+ cur= lb.first;
+ while(cur) {
+ MEM_freeN(cur->data);
+ cur= cur->next;
+ }
+ BLI_freelistN(&lb);
+
+ return NULL;
+ }
+
+ size= 4*( (size+3)/4 );
+
+ if(cur) {
+ if(size+offs < blocksize) {
+ adr= (void *) (cur->data+offs);
+ offs+= size;
+ return adr;
+ }
+ }
+
+ cur= MEM_callocN( sizeof(struct mem_elements), "newmem");
+ cur->data= MEM_callocN(blocksize, "newmem");
+ BLI_addtail(&lb, cur);
+
+ offs= size;
+ return cur->data;
+}
+
+void BLI_end_edgefill(void)
+{
+ new_mem_element(-1);
+
+ fillvertbase.first= fillvertbase.last= 0;
+ filledgebase.first= filledgebase.last= 0;
+ fillfacebase.first= fillfacebase.last= 0;
+}
+
+/* **** FILL ROUTINES *************************** */
+
+EditVert *BLI_addfillvert(float *vec)
+{
+ EditVert *eve;
+
+ eve= new_mem_element(sizeof(EditVert));
+ BLI_addtail(&fillvertbase, eve);
+
+ eve->co[0] = vec[0];
+ eve->co[1] = vec[1];
+ eve->co[2] = vec[2];
+
+ return eve;
+}
+
+EditEdge *BLI_addfilledge(EditVert *v1, EditVert *v2)
+{
+ EditEdge *newed;
+
+ newed= new_mem_element(sizeof(EditEdge));
+ BLI_addtail(&filledgebase, newed);
+
+ newed->v1= v1;
+ newed->v2= v2;
+
+ return newed;
+}
+
+static void addfillface(EditVert *v1, EditVert *v2, EditVert *v3, int mat_nr)
+{
+ /* does not make edges */
+ EditFace *evl;
+
+ evl= new_mem_element(sizeof(EditFace));
+ BLI_addtail(&fillfacebase, evl);
+
+ evl->v1= v1;
+ evl->v2= v2;
+ evl->v3= v3;
+ evl->f= 2;
+ evl->mat_nr= mat_nr;
+}
+
+static int boundisect(PolyFill *pf2, PolyFill *pf1)
+{
+ /* has pf2 been touched (intersected) by pf1 ? with bounding box */
+ /* test first if polys exist */
+
+ if(pf1->edges==0 || pf2->edges==0) return 0;
+
+ if(pf2->max[cox] < pf1->min[cox] ) return 0;
+ if(pf2->max[coy] < pf1->min[coy] ) return 0;
+
+ if(pf2->min[cox] > pf1->max[cox] ) return 0;
+ if(pf2->min[coy] > pf1->max[coy] ) return 0;
+
+ /* join */
+ if(pf2->max[cox]<pf1->max[cox]) pf2->max[cox]= pf1->max[cox];
+ if(pf2->max[coy]<pf1->max[coy]) pf2->max[coy]= pf1->max[coy];
+
+ if(pf2->min[cox]>pf1->min[cox]) pf2->min[cox]= pf1->min[cox];
+ if(pf2->min[coy]>pf1->min[coy]) pf2->min[coy]= pf1->min[coy];
+
+ return 1;
+}
+
+
+static void mergepolysSimp(PolyFill *pf1, PolyFill *pf2) /* add pf2 to pf1 */
+{
+ EditVert *eve;
+ EditEdge *eed;
+
+ /* replace old poly numbers */
+ eve= fillvertbase.first;
+ while(eve) {
+ if(eve->xs== pf2->nr) eve->xs= pf1->nr;
+ eve= eve->next;
+ }
+ eed= filledgebase.first;
+ while(eed) {
+ if(eed->f1== pf2->nr) eed->f1= pf1->nr;
+ eed= eed->next;
+ }
+
+ pf1->verts+= pf2->verts;
+ pf1->edges+= pf2->edges;
+ pf2->verts= pf2->edges= 0;
+ pf1->f= (pf1->f | pf2->f);
+}
+
+static short testedgeside(float *v1, float *v2, float *v3)
+/* is v3 to the right of v1-v2 ? With exception: v3==v1 || v3==v2 */
+{
+ float inp;
+
+ inp= (v2[cox]-v1[cox])*(v1[coy]-v3[coy])
+ +(v1[coy]-v2[coy])*(v1[cox]-v3[cox]);
+
+ if(inp<0.0) return 0;
+ else if(inp==0) {
+ if(v1[cox]==v3[cox] && v1[coy]==v3[coy]) return 0;
+ if(v2[cox]==v3[cox] && v2[coy]==v3[coy]) return 0;
+ }
+ return 1;
+}
+
+static short addedgetoscanvert(ScFillVert *sc, EditEdge *eed)
+{
+ /* find first edge to the right of eed, and insert eed before that */
+ EditEdge *ed;
+ float fac,fac1,x,y;
+
+ if(sc->first==0) {
+ sc->first= sc->last= eed;
+ eed->prev= eed->next=0;
+ return 1;
+ }
+
+ x= eed->v1->co[cox];
+ y= eed->v1->co[coy];
+
+ fac1= eed->v2->co[coy]-y;
+ if(fac1==0.0) {
+ fac1= 1.0e10*(eed->v2->co[cox]-x);
+
+ }
+ else fac1= (x-eed->v2->co[cox])/fac1;
+
+ ed= sc->first;
+ while(ed) {
+
+ if(ed->v2==eed->v2) return 0;
+
+ fac= ed->v2->co[coy]-y;
+ if(fac==0.0) {
+ fac= 1.0e10*(ed->v2->co[cox]-x);
+
+ }
+ else fac= (x-ed->v2->co[cox])/fac;
+ if(fac>fac1) break;
+
+ ed= ed->next;
+ }
+ if(ed) BLI_insertlinkbefore((ListBase *)&(sc->first), ed, eed);
+ else BLI_addtail((ListBase *)&(sc->first),eed);
+
+ return 1;
+}
+
+
+static ScFillVert *addedgetoscanlist(EditEdge *eed, int len)
+{
+ /* inserts edge at correct location in ScFillVert list */
+ /* returns sc when edge already exists */
+ ScFillVert *sc,scsearch;
+ EditVert *eve;
+
+ /* which vert is left-top? */
+ if(eed->v1->co[coy] == eed->v2->co[coy]) {
+ if(eed->v1->co[cox] > eed->v2->co[cox]) {
+ eve= eed->v1;
+ eed->v1= eed->v2;
+ eed->v2= eve;
+ }
+ }
+ else if(eed->v1->co[coy] < eed->v2->co[coy]) {
+ eve= eed->v1;
+ eed->v1= eed->v2;
+ eed->v2= eve;
+ }
+ /* find location in list */
+ scsearch.v1= eed->v1;
+ sc= (ScFillVert *)bsearch(&scsearch,scdata,len,
+ sizeof(ScFillVert), vergscdata);
+
+ if(sc==0) printf("Error in search edge: %p\n",eed);
+ else if(addedgetoscanvert(sc,eed)==0) return sc;
+
+ return 0;
+}
+
+static short boundinsideEV(EditEdge *eed, EditVert *eve)
+/* is eve inside boundbox eed */
+{
+ float minx,maxx,miny,maxy;
+
+ if(eed->v1->co[cox]<eed->v2->co[cox]) {
+ minx= eed->v1->co[cox];
+ maxx= eed->v2->co[cox];
+ } else {
+ minx= eed->v2->co[cox];
+ maxx= eed->v1->co[cox];
+ }
+ if(eve->co[cox]>=minx && eve->co[cox]<=maxx) {
+ if(eed->v1->co[coy]<eed->v2->co[coy]) {
+ miny= eed->v1->co[coy];
+ maxy= eed->v2->co[coy];
+ } else {
+ miny= eed->v2->co[coy];
+ maxy= eed->v1->co[coy];
+ }
+ if(eve->co[coy]>=miny && eve->co[coy]<=maxy) return 1;
+ }
+ return 0;
+}
+
+
+static void testvertexnearedge(void)
+{
+ /* only vertices with ->h==1 are being tested for
+ being close to an edge, if true insert */
+
+ EditVert *eve;
+ EditEdge *eed,*ed1;
+ float dist,vec1[2],vec2[2],vec3[2];
+
+ eve= fillvertbase.first;
+ while(eve) {
+ if(eve->h==1) {
+ vec3[0]= eve->co[cox];
+ vec3[1]= eve->co[coy];
+ /* find the edge which has vertex eve */
+ ed1= filledgebase.first;
+ while(ed1) {
+ if(ed1->v1==eve || ed1->v2==eve) break;
+ ed1= ed1->next;
+ }
+ if(ed1->v1==eve) {
+ ed1->v1= ed1->v2;
+ ed1->v2= eve;
+ }
+ eed= filledgebase.first;
+ while(eed) {
+ if(eve!=eed->v1 && eve!=eed->v2 && eve->xs==eed->f1) {
+ if(FloatCompare(eve->co,eed->v1->co, COMPLIMIT)) {
+ ed1->v2= eed->v1;
+ eed->v1->h++;
+ eve->h= 0;
+ break;
+ }
+ else if(FloatCompare(eve->co,eed->v2->co, COMPLIMIT)) {
+ ed1->v2= eed->v2;
+ eed->v2->h++;
+ eve->h= 0;
+ break;
+ }
+ else {
+ vec1[0]= eed->v1->co[cox];
+ vec1[1]= eed->v1->co[coy];
+ vec2[0]= eed->v2->co[cox];
+ vec2[1]= eed->v2->co[coy];
+ if(boundinsideEV(eed,eve)) {
+ dist= DistVL2Dfl(vec1,vec2,vec3);
+ if(dist<COMPLIMIT) {
+ /* new edge */
+ ed1= BLI_addfilledge(eed->v1, eve);
+
+ /* printf("fill: vertex near edge %x\n",eve); */
+ ed1->f= ed1->h= 0;
+ ed1->f1= eed->f1;
+ eed->v1= eve;
+ eve->h= 3;
+ break;
+ }
+ }
+ }
+ }
+ eed= eed->next;
+ }
+ }
+ eve= eve->next;
+ }
+}
+
+static void splitlist(ListBase *tempve, ListBase *temped, short nr)
+{
+ /* everything is in templist, write only poly nr to fillist */
+ EditVert *eve,*nextve;
+ EditEdge *eed,*nexted;
+
+ addlisttolist(tempve,&fillvertbase);
+ addlisttolist(temped,&filledgebase);
+
+ eve= tempve->first;
+ while(eve) {
+ nextve= eve->next;
+ if(eve->xs==nr) {
+ BLI_remlink(tempve,eve);
+ BLI_addtail(&fillvertbase,eve);
+ }
+ eve= nextve;
+ }
+ eed= temped->first;
+ while(eed) {
+ nexted= eed->next;
+ if(eed->f1==nr) {
+ BLI_remlink(temped,eed);
+ BLI_addtail(&filledgebase,eed);
+ }
+ eed= nexted;
+ }
+}
+
+
+static void scanfill(PolyFill *pf, int mat_nr)
+{
+ ScFillVert *sc = NULL, *sc1;
+ EditVert *eve,*v1,*v2,*v3;
+ EditEdge *eed,*nexted,*ed1,*ed2,*ed3;
+ float miny = 0.0;
+ int a,b,verts, maxface, totface;
+ short nr, test, twoconnected=0;
+
+ nr= pf->nr;
+ verts= pf->verts;
+
+ /* PRINTS
+ eve= fillvertbase.first;
+ while(eve) {
+ printf("vert: %x co: %f %f\n",eve,eve->co[cox],eve->co[coy]);
+ eve= eve->next;
+ }
+ eed= filledgebase.first;
+ while(eed) {
+ printf("edge: %x verts: %x %x\n",eed,eed->v1,eed->v2);
+ eed= eed->next;
+ } */
+
+ /* STEP 0: remove zero sized edges */
+ eed= filledgebase.first;
+ while(eed) {
+ if(eed->v1->co[cox]==eed->v2->co[cox]) {
+ if(eed->v1->co[coy]==eed->v2->co[coy]) {
+ if(eed->v1->f==255 && eed->v2->f!=255) {
+ eed->v2->f= 255;
+ eed->v2->tmp.v= eed->v1->tmp.v;
+ }
+ else if(eed->v2->f==255 && eed->v1->f!=255) {
+ eed->v1->f= 255;
+ eed->v1->tmp.v= eed->v2->tmp.v;
+ }
+ else if(eed->v2->f==255 && eed->v1->f==255) {
+ eed->v1->tmp.v= eed->v2->tmp.v;
+ }
+ else {
+ eed->v2->f= 255;
+ eed->v2->tmp.v = eed->v1->tmp.v;
+ }
+ }
+ }
+ eed= eed->next;
+ }
+
+ /* STEP 1: make using FillVert and FillEdge lists a sorted
+ ScFillVert list
+ */
+ sc= scdata= (ScFillVert *)MEM_callocN(pf->verts*sizeof(ScFillVert),"Scanfill1");
+ eve= fillvertbase.first;
+ verts= 0;
+ while(eve) {
+ if(eve->xs==nr) {
+ if(eve->f!= 255) {
+ verts++;
+ eve->f= 0; /* flag for connectedges later on */
+ sc->v1= eve;
+ sc++;
+ }
+ }
+ eve= eve->next;
+ }
+
+ qsort(scdata, verts, sizeof(ScFillVert), vergscdata);
+
+ sc= scdata;
+ eed= filledgebase.first;
+ while(eed) {
+ nexted= eed->next;
+ eed->f= 0;
+ BLI_remlink(&filledgebase,eed);
+/* commented all of this out, this I have no idea for what it is for, probably from ancient past */
+/* it does crash blender, since it uses mixed original and new vertices (ton) */
+// if(eed->v1->f==255) {
+// v1= eed->v1;
+// while((eed->v1->f == 255) && (eed->v1->tmp.v != v1))
+// eed->v1 = eed->v1->tmp.v;
+// }
+// if(eed->v2->f==255) {
+// v2= eed->v2;
+// while((eed->v2->f == 255) && (eed->v2->tmp.v != v2))
+// eed->v2 = eed->v2->tmp.v;
+// }
+ if(eed->v1!=eed->v2) addedgetoscanlist(eed,verts);
+
+ eed= nexted;
+ }
+ /*
+ sc= scdata;
+ for(a=0;a<verts;a++) {
+ printf("\nscvert: %x\n",sc->v1);
+ eed= sc->first;
+ while(eed) {
+ printf(" ed %x %x %x\n",eed,eed->v1,eed->v2);
+ eed= eed->next;
+ }
+ sc++;
+ }*/
+
+
+ /* STEP 2: FILL LOOP */
+
+ if(pf->f==0) twoconnected= 1;
+
+ /* (temporal) security: never much more faces than vertices */
+ totface= 0;
+ maxface= 2*verts; /* 2*verts: based at a filled circle within a triangle */
+
+ sc= scdata;
+ for(a=0;a<verts;a++) {
+ /* printf("VERTEX %d %x\n",a,sc->v1); */
+ ed1= sc->first;
+ while(ed1) { /* set connectflags */
+ nexted= ed1->next;
+ if(ed1->v1->h==1 || ed1->v2->h==1) {
+ BLI_remlink((ListBase *)&(sc->first),ed1);
+ BLI_addtail(&filledgebase,ed1);
+ if(ed1->v1->h>1) ed1->v1->h--;
+ if(ed1->v2->h>1) ed1->v2->h--;
+ }
+ else ed1->v2->f= 1;
+
+ ed1= nexted;
+ }
+ while(sc->first) { /* for as long there are edges */
+ ed1= sc->first;
+ ed2= ed1->next;
+
+ /* commented out... the ESC here delivers corrupted memory (and doesnt work during grab) */
+ /* if(callLocalInterruptCallBack()) break; */
+ if(totface>maxface) {
+ /* printf("Fill error: endless loop. Escaped at vert %d, tot: %d.\n", a, verts); */
+ a= verts;
+ break;
+ }
+ if(ed2==0) {
+ sc->first=sc->last= 0;
+ /* printf("just 1 edge to vert\n"); */
+ BLI_addtail(&filledgebase,ed1);
+ ed1->v2->f= 0;
+ ed1->v1->h--;
+ ed1->v2->h--;
+ } else {
+ /* test rest of vertices */
+ v1= ed1->v2;
+ v2= ed1->v1;
+ v3= ed2->v2;
+ /* this happens with a serial of overlapping edges */
+ if(v1==v2 || v2==v3) break;
+ /* printf("test verts %x %x %x\n",v1,v2,v3); */
+ miny = ( (v1->co[coy])<(v3->co[coy]) ? (v1->co[coy]) : (v3->co[coy]) );
+ /* miny= MIN2(v1->co[coy],v3->co[coy]); */
+ sc1= sc+1;
+ test= 0;
+
+ for(b=a+1;b<verts;b++) {
+ if(sc1->v1->f==0) {
+ if(sc1->v1->co[coy] <= miny) break;
+
+ if(testedgeside(v1->co,v2->co,sc1->v1->co))
+ if(testedgeside(v2->co,v3->co,sc1->v1->co))
+ if(testedgeside(v3->co,v1->co,sc1->v1->co)) {
+ /* point in triangle */
+
+ test= 1;
+ break;
+ }
+ }
+ sc1++;
+ }
+ if(test) {
+ /* make new edge, and start over */
+ /* printf("add new edge %x %x and start again\n",v2,sc1->v1); */
+
+ ed3= BLI_addfilledge(v2, sc1->v1);
+ BLI_remlink(&filledgebase, ed3);
+ BLI_insertlinkbefore((ListBase *)&(sc->first), ed2, ed3);
+ ed3->v2->f= 1;
+ ed3->f= 2;
+ ed3->v1->h++;
+ ed3->v2->h++;
+ }
+ else {
+ /* new triangle */
+ /* printf("add face %x %x %x\n",v1,v2,v3); */
+ addfillface(v1, v2, v3, mat_nr);
+ totface++;
+ BLI_remlink((ListBase *)&(sc->first),ed1);
+ BLI_addtail(&filledgebase,ed1);
+ ed1->v2->f= 0;
+ ed1->v1->h--;
+ ed1->v2->h--;
+ /* ed2 can be removed when it's an old one */
+ if(ed2->f==0 && twoconnected) {
+ BLI_remlink((ListBase *)&(sc->first),ed2);
+ BLI_addtail(&filledgebase,ed2);
+ ed2->v2->f= 0;
+ ed2->v1->h--;
+ ed2->v2->h--;
+ }
+
+ /* new edge */
+ ed3= BLI_addfilledge(v1, v3);
+ BLI_remlink(&filledgebase, ed3);
+ ed3->f= 2;
+ ed3->v1->h++;
+ ed3->v2->h++;
+
+ /* printf("add new edge %x %x\n",v1,v3); */
+ sc1= addedgetoscanlist(ed3, verts);
+
+ if(sc1) { /* ed3 already exists: remove */
+ /* printf("Edge exists\n"); */
+ ed3->v1->h--;
+ ed3->v2->h--;
+
+ if(twoconnected) ed3= sc1->first;
+ else ed3= 0;
+ while(ed3) {
+ if( (ed3->v1==v1 && ed3->v2==v3) || (ed3->v1==v3 && ed3->v2==v1) ) {
+ BLI_remlink((ListBase *)&(sc1->first),ed3);
+ BLI_addtail(&filledgebase,ed3);
+ ed3->v1->h--;
+ ed3->v2->h--;
+ break;
+ }
+ ed3= ed3->next;
+ }
+ }
+
+ }
+ }
+ /* test for loose edges */
+ ed1= sc->first;
+ while(ed1) {
+ nexted= ed1->next;
+ if(ed1->v1->h<2 || ed1->v2->h<2) {
+ BLI_remlink((ListBase *)&(sc->first),ed1);
+ BLI_addtail(&filledgebase,ed1);
+ if(ed1->v1->h>1) ed1->v1->h--;
+ if(ed1->v2->h>1) ed1->v2->h--;
+ }
+
+ ed1= nexted;
+ }
+ }
+ sc++;
+ }
+
+ MEM_freeN(scdata);
+}
+
+
+
+int BLI_edgefill(int mode, int mat_nr)
+{
+ /*
+ - fill works with its own lists, so create that first (no faces!)
+ - for vertices, put in ->tmp.v the old pointer
+ - struct elements xs en ys are not used here: don't hide stuff in it
+ - edge flag ->f becomes 2 when it's a new edge
+ - mode: & 1 is check for crossings, then create edges (TO DO )
+ */
+ ListBase tempve, temped;
+ EditVert *eve;
+ EditEdge *eed,*nexted;
+ PolyFill *pflist,*pf;
+ float *minp, *maxp, *v1, *v2, norm[3], len;
+ short a,c,poly=0,ok=0,toggle=0;
+
+ /* reset variables */
+ eve= fillvertbase.first;
+ while(eve) {
+ eve->f= 0;
+ eve->xs= 0;
+ eve->h= 0;
+ eve= eve->next;
+ }
+
+ /* first test vertices if they are in edges */
+ /* including resetting of flags */
+ eed= filledgebase.first;
+ while(eed) {
+ eed->f= eed->f1= eed->h= 0;
+ eed->v1->f= 1;
+ eed->v2->f= 1;
+
+ eed= eed->next;
+ }
+
+ eve= fillvertbase.first;
+ while(eve) {
+ if(eve->f & 1) {
+ ok=1;
+ break;
+ }
+ eve= eve->next;
+ }
+
+ if(ok==0) return 0;
+
+ /* NEW NEW! define projection: with 'best' normal */
+ /* just use the first three different vertices */
+
+ /* THIS PART STILL IS PRETTY WEAK! (ton) */
+
+ eve= fillvertbase.last;
+ len= 0.0;
+ v1= eve->co;
+ v2= 0;
+ eve= fillvertbase.first;
+ while(eve) {
+ if(v2) {
+ if( FloatCompare(v2, eve->co, COMPLIMIT)==0) {
+ len= CalcNormFloat(v1, v2, eve->co, norm);
+ if(len != 0.0) break;
+ }
+ }
+ else if(FloatCompare(v1, eve->co, COMPLIMIT)==0) {
+ v2= eve->co;
+ }
+ eve= eve->next;
+ }
+
+ if(len==0.0) return 0; /* no fill possible */
+
+ norm[0]= fabs(norm[0]);
+ norm[1]= fabs(norm[1]);
+ norm[2]= fabs(norm[2]);
+
+ if(norm[2]>=norm[0] && norm[2]>=norm[1]) {
+ cox= 0; coy= 1;
+ }
+ else if(norm[1]>=norm[0] && norm[1]>=norm[2]) {
+ cox= 0; coy= 2;
+ }
+ else {
+ cox= 1; coy= 2;
+ }
+
+ /* STEP 1: COUNT POLYS */
+ eve= fillvertbase.first;
+ while(eve) {
+ /* get first vertex with no poly number */
+ if(eve->xs==0) {
+ poly++;
+ /* now a sortof select connected */
+ ok= 1;
+ eve->xs= poly;
+
+ while(ok) {
+
+ ok= 0;
+ toggle++;
+ if(toggle & 1) eed= filledgebase.first;
+ else eed= filledgebase.last;
+
+ while(eed) {
+ if(eed->v1->xs==0 && eed->v2->xs==poly) {
+ eed->v1->xs= poly;
+ eed->f1= poly;
+ ok= 1;
+ }
+ else if(eed->v2->xs==0 && eed->v1->xs==poly) {
+ eed->v2->xs= poly;
+ eed->f1= poly;
+ ok= 1;
+ }
+ else if(eed->f1==0) {
+ if(eed->v1->xs==poly && eed->v2->xs==poly) {
+ eed->f1= poly;
+ ok= 1;
+ }
+ }
+ if(toggle & 1) eed= eed->next;
+ else eed= eed->prev;
+ }
+ }
+ }
+ eve= eve->next;
+ }
+ /* printf("amount of poly's: %d\n",poly); */
+
+ /* STEP 2: remove loose edges and strings of edges */
+ eed= filledgebase.first;
+ while(eed) {
+ if(eed->v1->h++ >250) break;
+ if(eed->v2->h++ >250) break;
+ eed= eed->next;
+ }
+ if(eed) {
+ /* otherwise it's impossible to be sure you can clear vertices */
+ callLocalErrorCallBack("No vertices with 250 edges allowed!");
+ return 0;
+ }
+
+ /* does it only for vertices with ->h==1 */
+ testvertexnearedge();
+
+ ok= 1;
+ while(ok) {
+ ok= 0;
+ toggle++;
+ if(toggle & 1) eed= filledgebase.first;
+ else eed= filledgebase.last;
+ while(eed) {
+ if(toggle & 1) nexted= eed->next;
+ else nexted= eed->prev;
+ if(eed->v1->h==1) {
+ eed->v2->h--;
+ BLI_remlink(&fillvertbase,eed->v1);
+ BLI_remlink(&filledgebase,eed);
+ ok= 1;
+ }
+ else if(eed->v2->h==1) {
+ eed->v1->h--;
+ BLI_remlink(&fillvertbase,eed->v2);
+ BLI_remlink(&filledgebase,eed);
+ ok= 1;
+ }
+ eed= nexted;
+ }
+ }
+ if(filledgebase.first==0) {
+ /* printf("All edges removed\n"); */
+ return 0;
+ }
+
+
+ /* CURRENT STATUS:
+ - eve->f :1= availalble in edges
+ - eve->xs :polynumber
+ - eve->h :amount of edges connected to vertex
+ - eve->tmp.v :store! original vertex number
+
+ - eed->f :
+ - eed->f1 :poly number
+ */
+
+
+ /* STEP 3: MAKE POLYFILL STRUCT */
+ pflist= (PolyFill *)MEM_callocN(poly*sizeof(PolyFill),"edgefill");
+ pf= pflist;
+ for(a=1;a<=poly;a++) {
+ pf->nr= a;
+ pf->min[0]=pf->min[1]=pf->min[2]= 1.0e20;
+ pf->max[0]=pf->max[1]=pf->max[2]= -1.0e20;
+ pf++;
+ }
+ eed= filledgebase.first;
+ while(eed) {
+ pflist[eed->f1-1].edges++;
+ eed= eed->next;
+ }
+
+ eve= fillvertbase.first;
+ while(eve) {
+ pflist[eve->xs-1].verts++;
+ minp= pflist[eve->xs-1].min;
+ maxp= pflist[eve->xs-1].max;
+
+ minp[cox]= (minp[cox])<(eve->co[cox]) ? (minp[cox]) : (eve->co[cox]);
+ minp[coy]= (minp[coy])<(eve->co[coy]) ? (minp[coy]) : (eve->co[coy]);
+ maxp[cox]= (maxp[cox])>(eve->co[cox]) ? (maxp[cox]) : (eve->co[cox]);
+ maxp[coy]= (maxp[coy])>(eve->co[coy]) ? (maxp[coy]) : (eve->co[coy]);
+ if(eve->h>2) pflist[eve->xs-1].f= 1;
+
+ eve= eve->next;
+ }
+
+ /* STEP 4: FIND HOLES OR BOUNDS, JOIN THEM
+ * ( bounds just to divide it in pieces for optimization,
+ * the edgefill itself has good auto-hole detection)
+ * WATCH IT: ONLY WORKS WITH SORTED POLYS!!! */
+
+ if(poly>1) {
+ short *polycache, *pc;
+
+ /* so, sort first */
+ qsort(pflist, poly, sizeof(PolyFill), vergpoly);
+
+ /*pf= pflist;
+ for(a=1;a<=poly;a++) {
+ printf("poly:%d edges:%d verts:%d flag: %d\n",a,pf->edges,pf->verts,pf->f);
+ PRINT2(f, f, pf->min[0], pf->min[1]);
+ pf++;
+ }*/
+
+ polycache= pc= MEM_callocN(sizeof(short)*poly, "polycache");
+ pf= pflist;
+ for(a=0; a<poly; a++, pf++) {
+ for(c=a+1;c<poly;c++) {
+
+ /* if 'a' inside 'c': join (bbox too)
+ * Careful: 'a' can also be inside another poly.
+ */
+ if(boundisect(pf, pflist+c)) {
+ *pc= c;
+ pc++;
+ }
+ /* only for optimize! */
+ /* else if(pf->max[cox] < (pflist+c)->min[cox]) break; */
+
+ }
+ while(pc!=polycache) {
+ pc--;
+ mergepolysSimp(pf, pflist+ *pc);
+ }
+ }
+ MEM_freeN(polycache);
+ }
+
+ pf= pflist;
+ /* printf("after merge\n");
+ for(a=1;a<=poly;a++) {
+ printf("poly:%d edges:%d verts:%d flag: %d\n",a,pf->edges,pf->verts,pf->f);
+ pf++;
+ } */
+
+ /* STEP 5: MAKE TRIANGLES */
+
+ tempve.first= fillvertbase.first;
+ tempve.last= fillvertbase.last;
+ temped.first= filledgebase.first;
+ temped.last= filledgebase.last;
+ fillvertbase.first=fillvertbase.last= 0;
+ filledgebase.first=filledgebase.last= 0;
+
+ pf= pflist;
+ for(a=0;a<poly;a++) {
+ if(pf->edges>1) {
+ splitlist(&tempve,&temped,pf->nr);
+ scanfill(pf, mat_nr);
+ }
+ pf++;
+ }
+ addlisttolist(&fillvertbase,&tempve);
+ addlisttolist(&filledgebase,&temped);
+
+ /* FREE */
+
+ MEM_freeN(pflist);
+ return 1;
+
+}
diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c
new file mode 100644
index 00000000000..1d46679cbf2
--- /dev/null
+++ b/source/blender/blenlib/intern/storage.c
@@ -0,0 +1,540 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * Reorganised mar-01 nzc
+ * Some really low-level file thingies.
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef WIN32
+#include "BLI_winstuff.h"
+#include <sys/types.h>
+#include <io.h>
+#include <direct.h>
+#endif
+
+#ifndef WIN32
+#include <dirent.h>
+#endif
+
+#include <time.h>
+#include <sys/stat.h>
+
+#if !defined(linux) && (defined(__sgi) || defined(__sun__) || defined(__sun) || defined(__sparc) || defined(__sparc__))
+#include <sys/statfs.h>
+#endif
+
+#if defined (__FreeBSD__) || defined (__OpenBSD__) || defined (__NetBSD__)
+#include <sys/param.h>
+#include <sys/mount.h>
+#endif
+
+#if defined(linux) || defined(__CYGWIN32__) || defined(__hpux)
+#include <sys/vfs.h>
+#endif
+
+#ifdef __BeOS
+struct statfs {
+ int f_bsize;
+ int f_bfree;
+};
+#endif
+
+#ifdef __APPLE__
+/* For statfs */
+#include <sys/param.h>
+#include <sys/mount.h>
+#endif /* __APPLE__ */
+
+
+#include <fcntl.h>
+#if !defined(__BeOS) && !defined(WIN32)
+#include <sys/mtio.h> /* tape comando's */
+#endif
+#include <string.h> /* strcpy etc.. */
+
+#ifndef WIN32
+#include <sys/ioctl.h>
+#include <unistd.h> /* */
+#include <pwd.h>
+#endif
+
+#if !defined(__FreeBSD__) && !defined(__APPLE__)
+#include <malloc.h>
+#endif
+
+/* lib includes */
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+#include "BLI_blenlib.h"
+#include "BLI_storage.h"
+#include "BLI_storage_types.h"
+
+#include "BLI_util.h"
+#include "BLI_linklist.h"
+
+#include "BKE_utildefines.h"
+
+/* vars: */
+static int totnum,actnum;
+static struct direntry *files;
+
+static struct ListBase dirbase_={
+ 0,0};
+static struct ListBase *dirbase = &dirbase_;
+
+
+char *BLI_getwdN(char *dir)
+{
+ char *pwd;
+
+ if (dir) {
+ pwd = getenv("PWD");
+ if (pwd){
+ strcpy(dir, pwd);
+ return(dir);
+ }
+ /* 160 is FILE_MAXDIR in filesel.c */
+ return( getcwd(dir, 160) );
+ }
+ return(0);
+}
+
+
+int BLI_compare(struct direntry *entry1, struct direntry *entry2)
+{
+ /* type is equal to stat.st_mode */
+
+ if (S_ISDIR(entry1->type)){
+ if (S_ISDIR(entry2->type)==0) return (-1);
+ } else{
+ if (S_ISDIR(entry2->type)) return (1);
+ }
+ if (S_ISREG(entry1->type)){
+ if (S_ISREG(entry2->type)==0) return (-1);
+ } else{
+ if (S_ISREG(entry2->type)) return (1);
+ }
+ if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1);
+ if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1);
+
+ /* make sure "." and ".." are always first */
+ if( strcmp(entry1->relname, ".")==0 ) return (-1);
+ if( strcmp(entry2->relname, ".")==0 ) return (1);
+ if( strcmp(entry1->relname, "..")==0 ) return (-1);
+
+ return (BLI_strcasecmp(entry1->relname,entry2->relname));
+}
+
+
+double BLI_diskfree(char *dir)
+{
+#ifdef WIN32
+ DWORD sectorspc, bytesps, freec, clusters;
+ char tmp[4];
+
+ tmp[0]='\\'; tmp[1]=0; /* Just a failsafe */
+ if (dir[0]=='/' || dir[0]=='\\') {
+ tmp[0]='\\';
+ tmp[1]=0;
+ } else if (dir[1]==':') {
+ tmp[0]=dir[0];
+ tmp[1]=':';
+ tmp[2]='\\';
+ tmp[3]=0;
+ }
+
+ GetDiskFreeSpace(tmp,&sectorspc, &bytesps, &freec, &clusters);
+
+ return (double) (freec*bytesps*sectorspc);
+#else
+ struct statfs disk;
+ char name[FILE_MAXDIR],*slash;
+ int len = strlen(dir);
+
+ if (len >= FILE_MAXDIR) /* path too long */
+ return -1;
+
+ strcpy(name,dir);
+
+ if(len){
+ slash = strrchr(name,'/');
+ if (slash) slash[1] = 0;
+ } else strcpy(name,"/");
+
+#if defined (__FreeBSD__) || defined (linux) || defined (__OpenBSD__) || defined (__APPLE__)
+ if (statfs(name, &disk)) return(-1);
+#endif
+#ifdef __BeOS
+ return -1;
+#endif
+#if !defined(linux) && (defined (__sgi) || defined (__sun__) || defined (__sun) || defined(__sparc) || defined(__sparc__))
+
+ if (statfs(name, &disk, sizeof(struct statfs), 0)){
+ /* printf("diskfree: Couldn't get information about %s.\n",dir); */
+ return(-1);
+ }
+#endif
+
+ return ( ((double) disk.f_bsize) * ((double) disk.f_bfree));
+#endif
+}
+
+static int hide_dot= 0;
+
+void BLI_hide_dot_files(int set)
+{
+ if(set) hide_dot= 1;
+ else hide_dot= 0;
+}
+
+void BLI_builddir(char *dirname, char *relname)
+{
+ struct dirent *fname;
+ struct dirlink *dlink;
+ int rellen, newnum = 0, seen_ = 0, seen__ = 0;
+ char buf[256];
+ DIR *dir;
+
+ strcpy(buf,relname);
+ rellen=strlen(relname);
+
+ if (rellen){
+ buf[rellen]='/';
+ rellen++;
+ }
+
+ if (chdir(dirname) == -1){
+ perror(dirname);
+ return;
+ }
+
+ if ( (dir = (DIR *)opendir(".")) ){
+ while ((fname = (struct dirent*) readdir(dir)) != NULL) {
+
+ if(hide_dot && fname->d_name[0]=='.' && fname->d_name[1]!='.' && fname->d_name[1]!=0);
+ else {
+
+ dlink = (struct dirlink *)malloc(sizeof(struct dirlink));
+ if (dlink){
+ strcpy(buf+rellen,fname->d_name);
+
+ dlink->name = BLI_strdup(buf);
+
+ if (dlink->name[0] == '.') {
+ if (dlink->name[1] == 0) seen_ = 1;
+ else if (dlink->name[1] == '.') {
+ if (dlink->name[2] == 0) seen__ = 1;
+ }
+ }
+ BLI_addhead(dirbase,dlink);
+ newnum++;
+ }
+ }
+ }
+
+ if (newnum){
+#ifndef WIN32
+ if (seen_ == 0) { /* Cachefs PATCH */
+ dlink = (struct dirlink *)malloc(sizeof(struct dirlink));
+ strcpy(buf+rellen,"./.");
+ dlink->name = BLI_strdup(buf);
+ BLI_addhead(dirbase,dlink);
+ newnum++;
+ }
+ if (seen__ == 0) { /* MAC PATCH */
+ dlink = (struct dirlink *)malloc(sizeof(struct dirlink));
+ strcpy(buf+rellen,"./..");
+ dlink->name = BLI_strdup(buf);
+ BLI_addhead(dirbase,dlink);
+ newnum++;
+ }
+#else // WIN32
+ if (seen_ == 0) { /* should only happen for root paths like "C:\" */
+ dlink = (struct dirlink *)malloc(sizeof(struct dirlink));
+ strcpy(buf+rellen,".");
+ dlink->name = BLI_strdup(buf);
+ BLI_addhead(dirbase,dlink);
+ newnum++;
+ }
+#endif
+
+ if (files) files=(struct direntry *)realloc(files,(totnum+newnum) * sizeof(struct direntry));
+ else files=(struct direntry *)malloc(newnum * sizeof(struct direntry));
+
+ if (files){
+ dlink = (struct dirlink *) dirbase->first;
+ while(dlink){
+ memset(&files[actnum], 0 , sizeof(struct direntry));
+ files[actnum].relname = dlink->name;
+ stat(dlink->name,&files[actnum].s);
+ files[actnum].type=files[actnum].s.st_mode;
+ files[actnum].flags = 0;
+ totnum++;
+ actnum++;
+ dlink = dlink->next;
+ }
+ } else{
+ printf("Couldn't get memory for dir\n");
+ exit(1);
+ }
+
+ BLI_freelist(dirbase);
+ if (files) qsort(files, actnum, sizeof(struct direntry), (int (*)(const void *,const void*))BLI_compare);
+ } else {
+ printf("%s empty directory\n",dirname);
+ }
+
+ closedir(dir);
+ } else {
+ printf("%s non-existant directory\n",dirname);
+ }
+}
+
+void BLI_adddirstrings()
+{
+ char datum[100];
+ char buf[250];
+ char size[250];
+ static char * types[8] = {"---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx"};
+ int num, mode;
+ int num1, num2, num3, num4;
+#ifdef WIN32
+ __int64 st_size;
+#else
+ long long st_size;
+#endif
+
+ struct direntry * file;
+ struct tm *tm;
+ time_t zero= 0;
+
+ file = &files[0];
+
+ for(num=0;num<actnum;num++){
+#ifdef WIN32
+ mode = 0;
+ strcpy(file->mode1, types[0]);
+ strcpy(file->mode2, types[0]);
+ strcpy(file->mode3, types[0]);
+#else
+ mode = file->s.st_mode;
+
+ strcpy(file->mode1, types[(mode & 0700) >> 6]);
+ strcpy(file->mode2, types[(mode & 0070) >> 3]);
+ strcpy(file->mode3, types[(mode & 0007)]);
+
+ if (((mode & S_ISGID) == S_ISGID) && (file->mode2[2]=='-'))file->mode2[2]='l';
+
+ if (mode & (S_ISUID | S_ISGID)){
+ if (file->mode1[2]=='x') file->mode1[2]='s';
+ else file->mode1[2]='S';
+
+ if (file->mode2[2]=='x')file->mode2[2]='s';
+ }
+
+ if (mode & S_ISVTX){
+ if (file->mode3[2] == 'x') file->mode3[2] = 't';
+ else file->mode3[2] = 'T';
+ }
+#endif
+
+#ifdef WIN32
+ strcpy(files[num].owner,"user");
+#else
+ {
+ struct passwd *pwuser;
+ pwuser = getpwuid(files[num].s.st_uid);
+ if ( pwuser ) {
+ strcpy(files[num].owner, pwuser->pw_name);
+ } else {
+ sprintf(files[num].owner, "%d", files[num].s.st_uid);
+ }
+ }
+#endif
+
+ tm= localtime(&files[num].s.st_mtime);
+ // prevent impossible dates in windows
+ if(tm==NULL) tm= localtime(&zero);
+ strftime(files[num].time, 8, "%H:%M", tm);
+ strftime(files[num].date, 16, "%d-%b-%y", tm);
+
+ /*
+ * Seems st_size is signed 32-bit value in *nix and Windows. This
+ * will buy us some time until files get bigger than 4GB or until
+ * everyone starts using __USE_FILE_OFFSET64 or equivalent.
+ */
+ st_size= (unsigned int)files[num].s.st_size;
+
+ num1= st_size % 1000;
+ num2= st_size/1000;
+ num2= num2 % 1000;
+ num3= st_size/(1000*1000);
+ num3= num3 % 1000;
+ num4= st_size/(1000*1000*1000);
+ num4= num4 % 1000;
+
+ if(num4) sprintf(files[num].size, "%3d %03d %03d %03d", num4, num3, num2, num1);
+ else if(num3) sprintf(files[num].size, "%7d %03d %03d", num3, num2, num1);
+ else if(num2) sprintf(files[num].size, "%11d %03d", num2, num1);
+ else if(num1) sprintf(files[num].size, "%15d", num1);
+ else sprintf(files[num].size, "0");
+
+ strftime(datum, 32, "%d-%b-%y %H:%M", tm);
+
+ if (st_size < 1000) {
+ sprintf(size, "%10d", (int) st_size);
+ } else if (st_size < 1000 * 1000) {
+ sprintf(size, "%6d %03d", (int) (st_size / 1000), (int) (st_size % 1000));
+ } else if (st_size < 100 * 1000 * 1000) {
+ sprintf(size, "%2d %03d %03d", (int) (st_size / (1000 * 1000)), (int) ((st_size / 1000) % 1000), (int) ( st_size % 1000));
+ } else {
+ sprintf(size, "> %4.1f M", (double) (st_size / (1024.0 * 1024.0)));
+ sprintf(size, "%10d", (int) st_size);
+ }
+
+ sprintf(buf,"%s %s %10s %s", files[num].date, files[num].time, size,
+ files[num].relname);
+
+ sprintf(buf,"%s %s %s %7s %s %s %10s %s", file->mode1, file->mode2, file->mode3, files[num].owner, files[num].date, files[num].time, size,
+ files[num].relname);
+
+ files[num].string=MEM_mallocN(strlen(buf)+1, "filestring");
+ if (files[num].string){
+ strcpy(files[num].string,buf);
+ }
+
+ file++;
+ }
+}
+
+unsigned int BLI_getdir(char *dirname, struct direntry **filelist)
+{
+ // reset global variables
+ // memory stored in files is free()'d in
+ // filesel.c:freefilelist()
+
+ actnum = totnum = 0;
+ files = 0;
+
+ BLI_builddir(dirname,"");
+ BLI_adddirstrings();
+
+ if (files) {
+ *(filelist) = files;
+ } else {
+ // keep blender happy. Blender stores this in a variable
+ // where 0 has special meaning.....
+ *(filelist) = files = malloc(sizeof(struct direntry));
+ }
+
+ return(actnum);
+}
+
+
+int BLI_filesize(int file)
+{
+ struct stat buf;
+
+ if (file <= 0) return (-1);
+ fstat(file, &buf);
+ return (buf.st_size);
+}
+
+
+
+int BLI_exist(char *name)
+{
+ struct stat st;
+#ifdef WIN32
+ /* in Windows stat doesn't recognize dir ending on a slash
+ To not break code where the ending slash is expected we
+ don't mess with the argument name directly here - elubie */
+ char tmp[FILE_MAXDIR+FILE_MAXFILE];
+ int len;
+ BLI_strncpy(tmp, name, FILE_MAXDIR+FILE_MAXFILE);
+ len = strlen(tmp);
+ if (len > 3 && ( tmp[len-1]=='\\' || tmp[len-1]=='/') ) tmp[len-1] = '\0';
+ if (stat(tmp,&st)) return(0);
+#else
+ if (stat(name,&st)) return(0);
+#endif
+ return(st.st_mode);
+}
+
+LinkNode *BLI_read_file_as_lines(char *name)
+{
+ FILE *fp= fopen(name, "r");
+ LinkNode *lines= NULL;
+ char *buf;
+ int size;
+
+ if (!fp) return NULL;
+
+ fseek(fp, 0, SEEK_END);
+ size= ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+
+ buf= malloc(size);
+ if (buf) {
+ int i, last= 0;
+
+ /*
+ * size = because on win32 reading
+ * all the bytes in the file will return
+ * less bytes because of crnl changes.
+ */
+ size= fread(buf, 1, size, fp);
+ for (i=0; i<=size; i++) {
+ if (i==size || buf[i]=='\n') {
+ char *line= BLI_strdupn(&buf[last], i-last);
+
+ BLI_linklist_prepend(&lines, line);
+ last= i+1;
+ }
+ }
+
+ free(buf);
+ }
+
+ fclose(fp);
+
+ BLI_linklist_reverse(&lines);
+ return lines;
+}
+
+void BLI_free_file_lines(LinkNode *lines)
+{
+ BLI_linklist_free(lines, (void(*)(void*)) MEM_freeN);
+}
diff --git a/source/blender/blenlib/intern/threads.c b/source/blender/blenlib/intern/threads.c
new file mode 100644
index 00000000000..cb10185386a
--- /dev/null
+++ b/source/blender/blenlib/intern/threads.c
@@ -0,0 +1,221 @@
+/**
+ *
+ * $Id:
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_threads.h"
+
+
+/* ********** basic thread control API ************
+
+Many thread cases have an X amount of jobs, and only an Y amount of
+threads are useful (typically amount of cpus)
+
+This code can be used to start a maximum amount of 'thread slots', which
+then can be filled in a loop with an idle timer.
+
+A sample loop can look like this (pseudo c);
+
+ ListBase lb;
+ int maxthreads= 2;
+ int cont= 1;
+
+ BLI_init_threads(&lb, do_something_func, maxthreads);
+
+ while(cont) {
+ if(BLI_available_threads(&lb) && !(escape loop event)) {
+ // get new job (data pointer)
+ // tag job 'processed
+ BLI_insert_thread(&lb, job);
+ }
+ else PIL_sleep_ms(50);
+
+ // find if a job is ready, this the do_something_func() should write in job somewhere
+ cont= 0;
+ for(go over all jobs)
+ if(job is ready) {
+ if(job was not removed) {
+ BLI_remove_thread(&lb, job);
+ }
+ }
+ else cont= 1;
+ }
+ // conditions to exit loop
+ if(if escape loop event) {
+ if(BLI_available_threadslots(&lb)==maxthreads)
+ break;
+ }
+ }
+
+ BLI_end_threads(&lb);
+
+ ************************************************ */
+static pthread_mutex_t _malloc_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t _image_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t _custom1_lock = PTHREAD_MUTEX_INITIALIZER;
+static int thread_levels= 0; /* threads can be invoked inside threads */
+
+/* just a max for security reasons */
+#define RE_MAX_THREAD 8
+
+typedef struct ThreadSlot {
+ struct ThreadSlot *next, *prev;
+ void *(*do_thread)(void *);
+ void *callerdata;
+ pthread_t pthread;
+ int avail;
+} ThreadSlot;
+
+static void BLI_lock_malloc_thread(void)
+{
+ pthread_mutex_lock(&_malloc_lock);
+}
+
+static void BLI_unlock_malloc_thread(void)
+{
+ pthread_mutex_unlock(&_malloc_lock);
+}
+
+void BLI_init_threads(ListBase *threadbase, void *(*do_thread)(void *), int tot)
+{
+ int a;
+
+ if(threadbase==NULL)
+ return;
+ threadbase->first= threadbase->last= NULL;
+
+ if(tot>RE_MAX_THREAD) tot= RE_MAX_THREAD;
+ else if(tot<1) tot= 1;
+
+ for(a=0; a<tot; a++) {
+ ThreadSlot *tslot= MEM_callocN(sizeof(ThreadSlot), "threadslot");
+ BLI_addtail(threadbase, tslot);
+ tslot->do_thread= do_thread;
+ tslot->avail= 1;
+ }
+
+ MEM_set_lock_callback(BLI_lock_malloc_thread, BLI_unlock_malloc_thread);
+ thread_levels++;
+}
+
+/* amount of available threads */
+int BLI_available_threads(ListBase *threadbase)
+{
+ ThreadSlot *tslot;
+ int counter=0;
+
+ for(tslot= threadbase->first; tslot; tslot= tslot->next) {
+ if(tslot->avail)
+ counter++;
+ }
+ return counter;
+}
+
+/* returns thread number, for sample patterns or threadsafe tables */
+int BLI_available_thread_index(ListBase *threadbase)
+{
+ ThreadSlot *tslot;
+ int counter=0;
+
+ for(tslot= threadbase->first; tslot; tslot= tslot->next, counter++) {
+ if(tslot->avail)
+ return counter;
+ }
+ return 0;
+}
+
+
+void BLI_insert_thread(ListBase *threadbase, void *callerdata)
+{
+ ThreadSlot *tslot;
+
+ for(tslot= threadbase->first; tslot; tslot= tslot->next) {
+ if(tslot->avail) {
+ tslot->avail= 0;
+ tslot->callerdata= callerdata;
+ pthread_create(&tslot->pthread, NULL, tslot->do_thread, tslot->callerdata);
+ return;
+ }
+ }
+ printf("ERROR: could not insert thread slot\n");
+}
+
+void BLI_remove_thread(ListBase *threadbase, void *callerdata)
+{
+ ThreadSlot *tslot;
+
+ for(tslot= threadbase->first; tslot; tslot= tslot->next) {
+ if(tslot->callerdata==callerdata) {
+ tslot->callerdata= NULL;
+ pthread_join(tslot->pthread, NULL);
+ tslot->avail= 1;
+ }
+ }
+}
+
+void BLI_end_threads(ListBase *threadbase)
+{
+ ThreadSlot *tslot;
+
+ for(tslot= threadbase->first; tslot; tslot= tslot->next) {
+ if(tslot->avail==0) {
+ pthread_join(tslot->pthread, NULL);
+ }
+ }
+ BLI_freelistN(threadbase);
+
+ thread_levels--;
+ if(thread_levels==0)
+ MEM_set_lock_callback(NULL, NULL);
+}
+
+void BLI_lock_thread(int type)
+{
+ if (type==LOCK_IMAGE)
+ pthread_mutex_lock(&_image_lock);
+ else if (type==LOCK_CUSTOM1)
+ pthread_mutex_lock(&_custom1_lock);
+}
+
+void BLI_unlock_thread(int type)
+{
+ if (type==LOCK_IMAGE)
+ pthread_mutex_unlock(&_image_lock);
+ else if(type==LOCK_CUSTOM1)
+ pthread_mutex_unlock(&_custom1_lock);
+}
+
+/* eof */
diff --git a/source/blender/blenlib/intern/time.c b/source/blender/blenlib/intern/time.c
new file mode 100644
index 00000000000..47abca10b36
--- /dev/null
+++ b/source/blender/blenlib/intern/time.c
@@ -0,0 +1,105 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#include "PIL_time.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WIN32
+
+#include <windows.h>
+
+double PIL_check_seconds_timer(void)
+{
+ static int hasperfcounter= -1; /* -1==unknown */
+ static double perffreq;
+
+ if (hasperfcounter==-1) {
+ __int64 ifreq;
+ hasperfcounter= QueryPerformanceFrequency((LARGE_INTEGER*) &ifreq);
+ perffreq= (double) ifreq;
+ }
+
+ if (hasperfcounter) {
+ __int64 count;
+
+ QueryPerformanceCounter((LARGE_INTEGER*) &count);
+
+ return count/perffreq;
+ } else {
+ static double accum= 0.0;
+ static int ltick= 0;
+ int ntick= GetTickCount();
+
+ if (ntick<ltick) {
+ accum+= (0xFFFFFFFF-ltick+ntick)/1000.0;
+ } else {
+ accum+= (ntick-ltick)/1000.0;
+ }
+
+ ltick= ntick;
+ return accum;
+ }
+}
+
+void PIL_sleep_ms(int ms)
+{
+ Sleep(ms);
+}
+
+#else
+
+#include <unistd.h>
+#include <sys/time.h>
+
+double PIL_check_seconds_timer(void)
+{
+ struct timeval tv;
+ struct timezone tz;
+
+ gettimeofday(&tv, &tz);
+
+ return ((double) tv.tv_sec + tv.tv_usec/1000000.0);
+}
+
+void PIL_sleep_ms(int ms)
+{
+ if (ms>=1000) {
+ sleep(ms/1000);
+ ms= (ms%1000);
+ }
+
+ usleep(ms*1000);
+}
+
+#endif
diff --git a/source/blender/blenlib/intern/util.c b/source/blender/blenlib/intern/util.c
new file mode 100644
index 00000000000..8e396eec09d
--- /dev/null
+++ b/source/blender/blenlib/intern/util.c
@@ -0,0 +1,1691 @@
+/* util.c
+ *
+ * various string, file, list operations.
+ *
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ *
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "DNA_listBase.h"
+#include "BLI_storage.h"
+#include "BLI_storage_types.h"
+#include "BLI_dynamiclist.h"
+
+#include "BLI_util.h"
+#include "BKE_utildefines.h"
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef WIN32
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+
+#ifdef WIN32
+#include "BLI_winstuff.h"
+
+/* for duplicate_defgroup */
+#if !(defined vsnprintf)
+#define vsnprintf _vsnprintf
+#endif
+
+#endif
+
+
+#ifndef WIN32
+#include <sys/time.h>
+#endif
+
+#ifdef __APPLE__
+#include <sys/param.h>
+#include <CoreFoundation/CoreFoundation.h>
+#endif
+
+/* local */
+
+static int add_win32_extension(char *name);
+
+/* implementation */
+
+/* Ripped this from blender.c */
+void addlisttolist(ListBase *list1, ListBase *list2)
+{
+ if (list2->first==0) return;
+
+ if (list1->first==0) {
+ list1->first= list2->first;
+ list1->last= list2->last;
+ }
+ else {
+ ((Link *)list1->last)->next= list2->first;
+ ((Link *)list2->first)->prev= list1->last;
+ list1->last= list2->last;
+ }
+ list2->first= list2->last= 0;
+}
+
+int BLI_stringdec(char *string, char *kop, char *start, unsigned short *numlen)
+{
+ unsigned short len, len2, nums = 0, nume = 0;
+ short i, found = 0;
+
+ len2 = len = strlen(string);
+
+ if (len > 6) {
+ if (BLI_strncasecmp(string + len - 6, ".blend", 6) == 0) len -= 6;
+ else if (BLI_strncasecmp(string + len - 6, ".trace", 6) == 0) len -= 6;
+ }
+
+ if (len > 9) {
+ if (BLI_strncasecmp(string + len - 9, ".blend.gz", 9) == 0) len -= 9;
+ }
+
+ if (len == len2) {
+ if (len > 4) {
+ /* handle .jf0 en .jf1 for jstreams */
+ if (BLI_strncasecmp(string + len - 4, ".jf", 3) == 0) len -= 4;
+ else if (BLI_strncasecmp(string + len - 4, ".tga", 4) == 0) len -= 4;
+ else if (BLI_strncasecmp(string + len - 4, ".jpg", 4) == 0) len -= 4;
+ else if (BLI_strncasecmp(string + len - 4, ".png", 4) == 0) len -= 4;
+ else if (BLI_strncasecmp(string + len - 4, ".txt", 4) == 0) len -= 4;
+ else if (BLI_strncasecmp(string + len - 4, ".cyc", 4) == 0) len -= 4;
+ else if (BLI_strncasecmp(string + len - 4, ".enh", 4) == 0) len -= 4;
+ else if (BLI_strncasecmp(string + len - 4, ".rgb", 4) == 0) len -= 4;
+ else if (BLI_strncasecmp(string + len - 4, ".psx", 4) == 0) len -= 4;
+ else if (BLI_strncasecmp(string + len - 4, ".ble", 4) == 0) len -= 4;
+ else if (BLI_strncasecmp(string + len - 4, ".exr", 4) == 0) len -= 4;
+ }
+ }
+
+ for (i = len - 1; i >= 0; i--) {
+ if (string[i] == '/') break;
+ if (isdigit(string[i])) {
+ if (found){
+ nums = i;
+ }
+ else{
+ nume = i;
+ nums = i;
+ found = 1;
+ }
+ }
+ else {
+ if (found) break;
+ }
+ }
+ if (found){
+ if (start) strcpy(start,&string[nume+1]);
+ if (kop) {
+ strcpy(kop,string);
+ kop[nums]=0;
+ }
+ if (numlen) *numlen = nume-nums+1;
+ return ((int)atoi(&(string[nums])));
+ }
+ if (start) strcpy(start, string + len);
+ if (kop) {
+ strncpy(kop, string, len);
+ kop[len] = 0;
+ }
+ if (numlen) *numlen=0;
+ return 0;
+}
+
+
+void BLI_stringenc(char *string, char *kop, char *start, unsigned short numlen, int pic)
+{
+ char numstr[10]="";
+ unsigned short len,i;
+
+ strcpy(string,kop);
+
+ if (pic>0 || numlen==4) {
+ len= sprintf(numstr,"%d",pic);
+
+ for(i=len;i<numlen;i++){
+ strcat(string,"0");
+ }
+ strcat(string,numstr);
+ }
+ strcat(string, start);
+}
+
+
+void BLI_newname(char *name, int add)
+{
+ char head[128], tail[128];
+ int pic;
+ unsigned short digits;
+
+ pic = BLI_stringdec(name, head, tail, &digits);
+
+ /* are we going from 100 -> 99 or from 10 -> 9 */
+ if (add < 0 && digits < 4 && digits > 0) {
+ int i, exp;
+ exp = 1;
+ for (i = digits; i > 1; i--) exp *= 10;
+ if (pic >= exp && (pic + add) < exp) digits--;
+ }
+
+ pic += add;
+
+ if (digits==4 && pic<0) pic= 0;
+ BLI_stringenc(name, head, tail, digits, pic);
+}
+
+
+void BLI_addhead(ListBase *listbase, void *vlink)
+{
+ Link *link= vlink;
+
+ if (link == NULL) return;
+ if (listbase == NULL) return;
+
+ link->next = listbase->first;
+ link->prev = NULL;
+
+ if (listbase->first) ((Link *)listbase->first)->prev = link;
+ if (listbase->last == NULL) listbase->last = link;
+ listbase->first = link;
+}
+
+
+void BLI_addtail(ListBase *listbase, void *vlink)
+{
+ Link *link= vlink;
+
+ if (link == NULL) return;
+ if (listbase == NULL) return;
+
+ link->next = NULL;
+ link->prev = listbase->last;
+
+ if (listbase->last) ((Link *)listbase->last)->next = link;
+ if (listbase->first == 0) listbase->first = link;
+ listbase->last = link;
+}
+
+
+void BLI_remlink(ListBase *listbase, void *vlink)
+{
+ Link *link= vlink;
+
+ if (link == NULL) return;
+ if (listbase == NULL) return;
+
+ if (link->next) link->next->prev = link->prev;
+ if (link->prev) link->prev->next = link->next;
+
+ if (listbase->last == link) listbase->last = link->prev;
+ if (listbase->first == link) listbase->first = link->next;
+}
+
+
+void BLI_freelinkN(ListBase *listbase, void *vlink)
+{
+ Link *link= vlink;
+
+ if (link == NULL) return;
+ if (listbase == NULL) return;
+
+ BLI_remlink(listbase,link);
+ MEM_freeN(link);
+}
+
+
+void BLI_insertlink(ListBase *listbase, void *vprevlink, void *vnewlink)
+{
+ Link *prevlink= vprevlink;
+ Link *newlink= vnewlink;
+
+ /* newlink comes after prevlink */
+ if (newlink == NULL) return;
+ if (listbase == NULL) return;
+
+ /* empty list */
+ if (listbase->first == NULL) {
+
+ listbase->first= newlink;
+ listbase->last= newlink;
+ return;
+ }
+
+ /* insert before first element */
+ if (prevlink == NULL) {
+ newlink->next= listbase->first;
+ newlink->prev= 0;
+ newlink->next->prev= newlink;
+ listbase->first= newlink;
+ return;
+ }
+
+ /* at end of list */
+ if (listbase->last== prevlink)
+ listbase->last = newlink;
+
+ newlink->next= prevlink->next;
+ prevlink->next= newlink;
+ if (newlink->next) newlink->next->prev= newlink;
+ newlink->prev= prevlink;
+}
+
+/* This uses insertion sort, so NOT ok for large list */
+void BLI_sortlist(ListBase *listbase, int (*cmp)(void *, void *))
+{
+ Link *current = NULL;
+ Link *previous = NULL;
+ Link *next = NULL;
+
+ if (cmp == NULL) return;
+ if (listbase == NULL) return;
+
+ if (listbase->first != listbase->last)
+ {
+ for( previous = listbase->first, current = previous->next; current; previous = current, current = next )
+ {
+ next = current->next;
+
+ BLI_remlink(listbase, current);
+
+ while(previous && cmp(previous, current) == 1)
+ {
+ previous = previous->prev;
+ }
+
+ if (previous == NULL)
+ {
+ BLI_addhead(listbase, current);
+ }
+ else
+ {
+ BLI_insertlinkafter(listbase, previous, current);
+ }
+ }
+ }
+}
+
+void BLI_insertlinkafter(ListBase *listbase, void *vprevlink, void *vnewlink)
+{
+ Link *prevlink= vprevlink;
+ Link *newlink= vnewlink;
+
+ /* newlink before nextlink */
+ if (newlink == NULL) return;
+ if (listbase == NULL) return;
+
+ /* empty list */
+ if (listbase->first == NULL) {
+ listbase->first= newlink;
+ listbase->last= newlink;
+ return;
+ }
+
+ /* insert at head of list */
+ if (prevlink == NULL) {
+ newlink->prev = NULL;
+ newlink->next = listbase->first;
+ ((Link *)listbase->first)->prev = newlink;
+ listbase->first = newlink;
+ return;
+ }
+
+ /* at end of list */
+ if (listbase->last == prevlink)
+ listbase->last = newlink;
+
+ newlink->next = prevlink->next;
+ newlink->prev = prevlink;
+ prevlink->next = newlink;
+ if (newlink->next) newlink->next->prev = newlink;
+}
+
+void BLI_insertlinkbefore(ListBase *listbase, void *vnextlink, void *vnewlink)
+{
+ Link *nextlink= vnextlink;
+ Link *newlink= vnewlink;
+
+ /* newlink before nextlink */
+ if (newlink == NULL) return;
+ if (listbase == NULL) return;
+
+ /* empty list */
+ if (listbase->first == NULL) {
+ listbase->first= newlink;
+ listbase->last= newlink;
+ return;
+ }
+
+ /* insert at end of list */
+ if (nextlink == NULL) {
+ newlink->prev= listbase->last;
+ newlink->next= 0;
+ ((Link *)listbase->last)->next= newlink;
+ listbase->last= newlink;
+ return;
+ }
+
+ /* at beginning of list */
+ if (listbase->first== nextlink)
+ listbase->first = newlink;
+
+ newlink->next= nextlink;
+ newlink->prev= nextlink->prev;
+ nextlink->prev= newlink;
+ if (newlink->prev) newlink->prev->next= newlink;
+}
+
+
+void BLI_freelist(ListBase *listbase)
+{
+ Link *link, *next;
+
+ if (listbase == NULL)
+ return;
+
+ link= listbase->first;
+ while (link) {
+ next= link->next;
+ free(link);
+ link= next;
+ }
+
+ listbase->first= NULL;
+ listbase->last= NULL;
+}
+
+void BLI_freelistN(ListBase *listbase)
+{
+ Link *link, *next;
+
+ if (listbase == NULL) return;
+
+ link= listbase->first;
+ while (link) {
+ next= link->next;
+ MEM_freeN(link);
+ link= next;
+ }
+
+ listbase->first= NULL;
+ listbase->last= NULL;
+}
+
+
+int BLI_countlist(ListBase *listbase)
+{
+ Link *link;
+ int count = 0;
+
+ if (listbase) {
+ link = listbase->first;
+ while (link) {
+ count++;
+ link= link->next;
+ }
+ }
+ return count;
+}
+
+void *BLI_findlink(ListBase *listbase, int number)
+{
+ Link *link = NULL;
+
+ if (number >= 0) {
+ link = listbase->first;
+ while (link != NULL && number != 0) {
+ number--;
+ link = link->next;
+ }
+ }
+
+ return link;
+}
+
+int BLI_findindex(ListBase *listbase, void *vlink)
+{
+ Link *link= NULL;
+ int number= 0;
+
+ if (listbase == NULL) return -1;
+ if (vlink == NULL) return -1;
+
+ link= listbase->first;
+ while (link) {
+ if (link == vlink)
+ return number;
+
+ number++;
+ link= link->next;
+ }
+
+ return -1;
+}
+
+/*=====================================================================================*/
+/* Methods for access array (realloc) */
+/*=====================================================================================*/
+
+/* remove item with index */
+static void rem_array_item(struct DynamicArray *da, unsigned int index)
+{
+ da->items[index]=NULL;
+ da->count--;
+ if(index==da->last_item_index){
+ while((!da->items[da->last_item_index]) && (da->last_item_index>0)){
+ da->last_item_index--;
+ }
+ }
+}
+
+/* add array (if needed, then realloc) */
+static void add_array_item(struct DynamicArray *da, void *item, unsigned int index)
+{
+ /* realloc of access array */
+ if(da->max_item_index < index){
+ unsigned int i, max = da->max_item_index;
+ void **nitems;
+
+ do {
+ da->max_item_index += PAGE_SIZE; /* OS can allocate only PAGE_SIZE Bytes */
+ } while(da->max_item_index<=index);
+
+ nitems = (void**)MEM_mallocN(sizeof(void*)*(da->max_item_index+1), "dlist access array");
+ for(i=0;i<=max;i++)
+ nitems[i] = da->items[i];
+
+ /* set rest pointers to the NULL */
+ for(i=max+1; i<=da->max_item_index; i++)
+ nitems[i]=NULL;
+
+ MEM_freeN(da->items); /* free old access array */
+ da->items = nitems;
+ }
+
+ da->items[index] = item;
+ da->count++;
+ if(index > da->last_item_index) da->last_item_index = index;
+}
+
+/* free access array */
+static void destroy_array(DynamicArray *da)
+{
+ da->count=0;
+ da->last_item_index=0;
+ da->max_item_index=0;
+ MEM_freeN(da->items);
+ da->items = NULL;
+}
+
+/* initialize dynamic array */
+static void init_array(DynamicArray *da)
+{
+ unsigned int i;
+
+ da->count=0;
+ da->last_item_index=0;
+ da->max_item_index = PAGE_SIZE-1;
+ da->items = (void*)MEM_mallocN(sizeof(void*)*(da->max_item_index+1), "dlist access array");
+ for(i=0; i<=da->max_item_index; i++) da->items[i]=NULL;
+}
+
+/* reinitialize dynamic array */
+static void reinit_array(DynamicArray *da)
+{
+ destroy_array(da);
+ init_array(da);
+}
+
+/*=====================================================================================*/
+/* Methods for two way dynamic list with access array */
+/*=====================================================================================*/
+
+/* create new two way dynamic list with access array from two way dynamic list
+ * it doesn't copy any items to new array or something like this It is strongly
+ * recomended to use BLI_dlist_ methods for adding/removing items from dynamic list
+ * unless you can end with inconsistence system !!! */
+DynamicList *BLI_dlist_from_listbase(ListBase *lb)
+{
+ DynamicList *dlist;
+ Link *item;
+ int i=0, count;
+
+ if(!lb) return NULL;
+
+ count = BLI_countlist(lb);
+
+ dlist = MEM_mallocN(sizeof(DynamicList), "temp dynamic list");
+ /* ListBase stuff */
+ dlist->lb.first = lb->first;
+ dlist->lb.last = lb->last;
+ /* access array stuff */
+ dlist->da.count=count;
+ dlist->da.max_item_index = count-1;
+ dlist->da.last_item_index = count -1;
+ dlist->da.items = (void*)MEM_mallocN(sizeof(void*)*count, "temp dlist access array");
+
+ item = (Link*)lb->first;
+ while(item){
+ dlist->da.items[i] = (void*)item;
+ item = item->next;
+ i++;
+ }
+
+ /* to prevent you of using original ListBase :-) */
+ lb->first = lb->last = NULL;
+
+ return dlist;
+}
+
+/* take out ListBase from DynamicList and destroy all temporary structures of DynamicList */
+ListBase *BLI_listbase_from_dlist(DynamicList *dlist, ListBase *lb)
+{
+ if(!dlist) return NULL;
+
+ if(!lb) lb = (ListBase*)MEM_mallocN(sizeof(ListBase), "ListBase");
+
+ lb->first = dlist->lb.first;
+ lb->last = dlist->lb.last;
+
+ /* free all items of access array */
+ MEM_freeN(dlist->da.items);
+ /* free DynamicList*/
+ MEM_freeN(dlist);
+
+ return lb;
+}
+
+/* return pointer at item from th dynamic list with access array */
+void *BLI_dlist_find_link(DynamicList *dlist, unsigned int index)
+{
+ if(!dlist || !dlist->da.items) return NULL;
+
+ if((index <= dlist->da.last_item_index) && (index >= 0) && (dlist->da.count>0)){
+ return dlist->da.items[index];
+ }
+ else {
+ return NULL;
+ }
+}
+
+/* return count of items in the dynamic list with access array */
+unsigned int BLI_count_items(DynamicList *dlist)
+{
+ if(!dlist) return 0;
+
+ return dlist->da.count;
+}
+
+/* free item from the dynamic list with access array */
+void BLI_dlist_free_item(DynamicList *dlist, unsigned int index)
+{
+ if(!dlist || !dlist->da.items) return;
+
+ if((index <= dlist->da.last_item_index) && (dlist->da.items[index])){
+ BLI_freelinkN(&(dlist->lb), dlist->da.items[index]);
+ rem_array_item(&(dlist->da), index);
+ }
+}
+
+/* remove item from the dynamic list with access array */
+void BLI_dlist_rem_item(DynamicList *dlist, unsigned int index)
+{
+ if(!dlist || !dlist->da.items) return;
+
+ if((index <= dlist->da.last_item_index) && (dlist->da.items[index])){
+ BLI_remlink(&(dlist->lb), dlist->da.items[index]);
+ rem_array_item(&(dlist->da), index);
+ }
+}
+
+/* add item to the dynamic list with access array (index) */
+void* BLI_dlist_add_item_index(DynamicList *dlist, void *item, unsigned int index)
+{
+ if(!dlist || !dlist->da.items) return NULL;
+
+ if((index <= dlist->da.max_item_index) && (dlist->da.items[index])) {
+ /* you can't place item at used index */
+ return NULL;
+ }
+ else {
+ add_array_item(&(dlist->da), item, index);
+ BLI_addtail(&(dlist->lb), item);
+ return item;
+ }
+}
+
+/* destroy dynamic list with access array */
+void BLI_dlist_destroy(DynamicList *dlist)
+{
+ if(!dlist) return;
+
+ BLI_freelistN(&(dlist->lb));
+ destroy_array(&(dlist->da));
+}
+
+/* initialize dynamic list with access array */
+void BLI_dlist_init(DynamicList *dlist)
+{
+ if(!dlist) return;
+
+ dlist->lb.first = NULL;
+ dlist->lb.last = NULL;
+
+ init_array(&(dlist->da));
+}
+
+/* reinitialize dynamic list with acces array */
+void BLI_dlist_reinit(DynamicList *dlist)
+{
+ if(!dlist) return;
+
+ BLI_freelistN(&(dlist->lb));
+ reinit_array(&(dlist->da));
+}
+
+/*=====================================================================================*/
+
+char *BLI_strdupn(const char *str, int len) {
+ char *n= MEM_mallocN(len+1, "strdup");
+ memcpy(n, str, len);
+ n[len]= '\0';
+
+ return n;
+}
+char *BLI_strdup(const char *str) {
+ return BLI_strdupn(str, strlen(str));
+}
+
+char *BLI_strncpy(char *dst, const char *src, int maxncpy) {
+ int srclen= strlen(src);
+ int cpylen= (srclen>(maxncpy-1))?(maxncpy-1):srclen;
+
+ memcpy(dst, src, cpylen);
+ dst[cpylen]= '\0';
+
+ return dst;
+}
+
+int BLI_snprintf(char *buffer, size_t count, const char *format, ...)
+{
+ int n;
+ va_list arg;
+
+ va_start(arg, format);
+ n = vsnprintf(buffer, count, format, arg);
+
+ if (n != -1 && n < count) {
+ buffer[n] = '\0';
+ } else {
+ buffer[count-1] = '\0';
+ }
+
+ va_end(arg);
+ return n;
+}
+
+int BLI_streq(char *a, char *b) {
+ return (strcmp(a, b)==0);
+}
+int BLI_strcaseeq(char *a, char *b) {
+ return (BLI_strcasecmp(a, b)==0);
+}
+
+/* ******************** string encoding ***************** */
+
+/* This is quite an ugly function... its purpose is to
+ * take the dir name, make it absolute, and clean it up, replacing
+ * excess file entry stuff (like /tmp/../tmp/../)
+ * note that dir isn't protected for max string names...
+ */
+
+void BLI_cleanup_dir(const char *relabase, char *dir)
+{
+ short a;
+ char *start, *eind;
+
+ BLI_convertstringcode(dir, relabase, 0);
+
+#ifdef WIN32
+ if(dir[0]=='.') { /* happens for example in FILE_MAIN */
+ get_default_root(dir);
+ return;
+ }
+
+ while ( (start = strstr(dir, "\\..\\")) ) {
+ eind = start + strlen("\\..\\") - 1;
+ a = start-dir-1;
+ while (a>0) {
+ if (dir[a] == '\\') break;
+ a--;
+ }
+ strcpy(dir+a,eind);
+ }
+
+ while ( (start = strstr(dir,"\\.\\")) ){
+ eind = start + strlen("\\.\\") - 1;
+ strcpy(start,eind);
+ }
+
+ while ( (start = strstr(dir,"\\\\" )) ){
+ eind = start + strlen("\\\\") - 1;
+ strcpy(start,eind);
+ }
+
+ if((a = strlen(dir))){ /* remove the '\\' at the end */
+ while(a>0 && dir[a-1] == '\\'){
+ a--;
+ dir[a] = 0;
+ }
+ }
+
+ strcat(dir, "\\");
+#else
+ if(dir[0]=='.') { /* happens, for example in FILE_MAIN */
+ dir[0]= '/';
+ dir[1]= 0;
+ return;
+ }
+
+ while ( (start = strstr(dir, "/../")) ) {
+ eind = start + strlen("/../") - 1;
+ a = start-dir-1;
+ while (a>0) {
+ if (dir[a] == '/') break;
+ a--;
+ }
+ strcpy(dir+a,eind);
+ }
+
+ while ( (start = strstr(dir,"/./")) ){
+ eind = start + strlen("/./") - 1;
+ strcpy(start,eind);
+ }
+
+ while ( (start = strstr(dir,"//" )) ){
+ eind = start + strlen("//") - 1;
+ strcpy(start,eind);
+ }
+
+ if( (a = strlen(dir)) ){ /* remove all '/' at the end */
+ while(dir[a-1] == '/'){
+ a--;
+ dir[a] = 0;
+ if (a<=0) break;
+ }
+ }
+
+ strcat(dir, "/");
+#endif
+}
+
+
+void BLI_makestringcode(const char *relfile, char *file)
+{
+ char * p;
+ char * q;
+ char * lslash;
+ char temp[FILE_MAXDIR+FILE_MAXFILE];
+ char res[FILE_MAXDIR+FILE_MAXFILE];
+
+ /* if file is already relative, bail out */
+ if(file[0]=='/' && file[1]=='/') return;
+
+ /* also bail out if relative path is not set */
+ if (relfile[0] == 0) return;
+
+#ifdef WIN32
+ if (strlen(relfile) > 2 && relfile[1] != ':') {
+ char* ptemp;
+ /* fix missing volume name in relative base,
+ can happen with old .Blog files */
+ get_default_root(temp);
+ ptemp = &temp[2];
+ if (relfile[0] != '\\' && relfile[0] != '/') {
+ ptemp++;
+ }
+ BLI_strncpy(ptemp, relfile, FILE_MAXDIR + FILE_MAXFILE-3);
+ } else {
+ BLI_strncpy(temp, relfile, FILE_MAXDIR + FILE_MAXFILE);
+ }
+
+ if (strlen(file) > 2) {
+ if ( temp[1] == ':' && file[1] == ':' && temp[0] != file[0] )
+ return;
+ }
+#else
+ BLI_strncpy(temp, relfile, FILE_MAX);
+#endif
+
+ BLI_char_switch(temp, '\\', '/');
+ BLI_char_switch(file, '\\', '/');
+
+ /* the last slash in the file indicates where the path part ends */
+ lslash = BLI_last_slash(temp);
+
+ if (lslash)
+ {
+ /* find the prefix of the filename that is equal for both filenames.
+ This is replaced by the two slashes at the beginning */
+ p = temp;
+ q = file;
+ while (*p == *q) {
+ ++p; ++q;
+ }
+ /* we might have passed the slash when the beginning of a dir matches
+ so we rewind. Only check on the actual filename
+ */
+ if (*q != '/') {
+ while ( (q >= file) && (*q != '/') ) { --q; --p; }
+ }
+ else if (*p != '/') {
+ while ( (p >= temp) && (*p != '/') ) { --p; --q; }
+ }
+
+ strcpy(res, "//");
+
+ /* p now points to the slash that is at the beginning of the part
+ where the path is different from the relative path.
+ We count the number of directories we need to go up in the
+ hierarchy to arrive at the common 'prefix' of the path
+ */
+ while (p && p < lslash) {
+ if (*p == '/')
+ strcat(res, "../");
+ ++p;
+ }
+
+ strcat(res, q+1); /* don't copy the slash at the beginning */
+
+#ifdef WIN32
+ BLI_char_switch(res+2, '/', '\\');
+#endif
+ strcpy(file, res);
+ }
+}
+
+int BLI_convertstringcode(char *path, const char *basepath, int framenum)
+{
+ int len, wasrelative;
+ char tmp[FILE_MAXDIR+FILE_MAXFILE];
+ char base[FILE_MAXDIR];
+ char vol[3] = {'\0', '\0', '\0'};
+
+ BLI_strncpy(vol, path, 3);
+ wasrelative= (strncmp(vol, "//", 2)==0);
+
+#ifdef WIN32
+ /* we are checking here if we have an absolute path that is not in the current
+ blend file as a lib main - we are basically checking for the case that a
+ UNIX root '/' is passed.
+ */
+ if (!wasrelative && (vol[1] != ':' && (vol[0] == '\0' || vol[0] == '/' || vol[0] == '\\'))) {
+ char *p = path;
+ get_default_root(tmp);
+ // get rid of the slashes at the beginning of the path
+ while (*p == '\\' || *p == '/') {
+ p++;
+ }
+ strcat(tmp, p);
+ }
+ else {
+ strcpy(tmp, path);
+ }
+#else
+ strcpy(tmp, path);
+#endif
+
+ strcpy(base, basepath);
+
+ /* push slashes into unix mode - strings entering this part are
+ potentially messed up: having both back- and forward slashes.
+ Here we push into one conform direction, and at the end we
+ push them into the system specific dir. This ensures uniformity
+ of paths and solving some problems (and prevent potential future
+ ones) -jesterKing. */
+ BLI_char_switch(tmp, '\\', '/');
+ BLI_char_switch(base, '\\', '/');
+
+ if (tmp[0] == '/' && tmp[1] == '/') {
+ char *filepart= BLI_strdup(tmp+2); /* skip code */
+ char *lslash= BLI_last_slash(base);
+
+ if (lslash) {
+ int baselen= (int) (lslash-base) + 1;
+
+ memcpy(tmp, base, baselen);
+ strcpy(tmp+baselen, filepart);
+ } else {
+ strcpy(tmp, filepart);
+ }
+
+ MEM_freeN(filepart);
+ }
+
+ len= strlen(tmp);
+ if(len && tmp[len-1]=='#') {
+ sprintf(tmp+len-1, "%04d", framenum);
+ }
+
+ strcpy(path, tmp);
+#ifdef WIN32
+ /* skip first two chars, which in case of
+ absolute path will be drive:/blabla and
+ in case of relpath //blabla/. So relpath
+ // will be retained, rest will be nice and
+ shiny win32 backward slashes :) -jesterKing
+ */
+ BLI_char_switch(path+2, '/', '\\');
+#endif
+
+ return wasrelative;
+}
+
+void BLI_splitdirstring(char *di, char *fi)
+{
+ char *lslash= BLI_last_slash(di);
+
+ if (lslash) {
+ BLI_strncpy(fi, lslash+1, FILE_MAXFILE);
+ *(lslash+1)=0;
+ } else {
+ BLI_strncpy(fi, di, FILE_MAXFILE);
+ di[0]= 0;
+ }
+}
+
+char *BLI_gethome(void) {
+ #ifdef __BeOS
+ return "/boot/home/"; /* BeOS 4.5: doubleclick at icon doesnt give home env */
+
+ #elif !defined(WIN32)
+ return getenv("HOME");
+
+ #else /* Windows */
+ char * ret;
+ static char dir[512];
+
+ /* Check for %HOME% env var */
+
+ ret = getenv("HOME");
+ if(ret) {
+ sprintf(dir, "%s\\.blender", ret);
+ if (BLI_exists(dir)) return dir;
+ }
+
+ /* else, check install dir (path containing blender.exe) */
+
+ BLI_getInstallationDir(dir);
+
+ if (BLI_exists(dir))
+ {
+ strcat(dir,"\\.blender");
+ if (BLI_exists(dir)) return(dir);
+ }
+
+
+ /* add user profile support for WIN 2K / NT */
+ ret = getenv("USERPROFILE");
+ if (ret) {
+ if (BLI_exists(ret)) { /* from fop, also below... */
+ sprintf(dir, "%s\\Application Data\\Blender Foundation\\Blender", ret);
+ BLI_recurdir_fileops(dir);
+ if (BLI_exists(dir)) {
+ strcat(dir,"\\.blender");
+ if(BLI_exists(dir)) return(dir);
+ }
+ }
+ }
+
+ /*
+ Saving in the Windows dir is less than desirable.
+ Use as a last resort ONLY! (aphex)
+ */
+
+ ret = getenv("WINDOWS");
+ if (ret) {
+ if(BLI_exists(ret)) return ret;
+ }
+
+ ret = getenv("WINDIR");
+ if (ret) {
+ if(BLI_exists(ret)) return ret;
+ }
+
+ return "C:\\Temp"; /* sheesh! bad, bad, bad! (aphex) */
+ #endif
+}
+
+void BLI_clean(char *path)
+{
+ if(path==0) return;
+#ifdef WIN32
+ if(path && strlen(path)>2) {
+ BLI_char_switch(path+2, '/', '\\');
+ }
+#else
+ BLI_char_switch(path, '\\', '/');
+#endif
+}
+
+void BLI_char_switch(char *string, char from, char to)
+{
+ if(string==0) return;
+ while (*string != 0) {
+ if (*string == from) *string = to;
+ string++;
+ }
+}
+
+void BLI_make_exist(char *dir) {
+ int a;
+
+ #ifdef WIN32
+ BLI_char_switch(dir, '/', '\\');
+ #else
+ BLI_char_switch(dir, '\\', '/');
+ #endif
+
+ a = strlen(dir);
+
+#ifdef WIN32
+ while(BLI_exists(dir) == 0){
+ a --;
+ while(dir[a] != '\\'){
+ a--;
+ if (a <= 0) break;
+ }
+ if (a >= 0) dir[a+1] = 0;
+ else {
+ /* defaulting to drive (usually 'C:') of Windows installation */
+ get_default_root(dir);
+ break;
+ }
+ }
+#else
+ while(BLI_exist(dir) == 0){
+ a --;
+ while(dir[a] != '/'){
+ a--;
+ if (a <= 0) break;
+ }
+ if (a >= 0) dir[a+1] = 0;
+ else {
+ strcpy(dir,"/");
+ break;
+ }
+ }
+#endif
+}
+
+void BLI_make_existing_file(char *name)
+{
+ char di[FILE_MAXDIR], fi[FILE_MAXFILE];
+
+ strcpy(di, name);
+ BLI_splitdirstring(di, fi);
+
+ /* test exist */
+ if (BLI_exists(di) == 0) {
+ BLI_recurdir_fileops(di);
+ }
+}
+
+
+void BLI_make_file_string(const char *relabase, char *string, const char *dir, const char *file)
+{
+ int sl;
+
+ if (!string || !dir || !file) return; /* We don't want any NULLs */
+
+ string[0]= 0; /* ton */
+
+ /* we first push all slashes into unix mode, just to make sure we don't get
+ any mess with slashes later on. -jesterKing */
+ /* constant strings can be passed for those parameters - don't change them - elubie */
+ /*
+ BLI_char_switch(relabase, '\\', '/');
+ BLI_char_switch(dir, '\\', '/');
+ BLI_char_switch(file, '\\', '/');
+ */
+
+ /* Resolve relative references */
+ if (relabase && dir[0] == '/' && dir[1] == '/') {
+ char *lslash;
+
+ /* Get the file name, chop everything past the last slash (ie. the filename) */
+ strcpy(string, relabase);
+
+ lslash= (strrchr(string, '/')>strrchr(string, '\\'))?strrchr(string, '/'):strrchr(string, '\\');
+
+ if(lslash) *(lslash+1)= 0;
+
+ dir+=2; /* Skip over the relative reference */
+ }
+#ifdef WIN32
+ else {
+ if (strlen(dir) >= 2 && dir[1] == ':' ) {
+ BLI_strncpy(string, dir, 3);
+ dir += 2;
+ }
+ else { /* no drive specified */
+ /* first option: get the drive from the relabase if it has one */
+ if (relabase && strlen(relabase) >= 2 && relabase[1] == ':' ) {
+ BLI_strncpy(string, relabase, 3);
+ string[2] = '\\';
+ string[3] = '\0';
+ }
+ else { /* we're out of luck here, guessing the first valid drive, usually c:\ */
+ get_default_root(string);
+ }
+
+ /* ignore leading slashes */
+ while (*dir == '/' || *dir == '\\') dir++;
+ }
+ }
+#endif
+
+ strcat(string, dir);
+
+ /* Make sure string ends in one (and only one) slash */
+ /* first trim all slashes from the end of the string */
+ sl = strlen(string);
+ while (sl>0 && ( string[sl-1] == '/' || string[sl-1] == '\\') ) {
+ string[sl-1] = '\0';
+ sl--;
+ }
+ /* since we've now removed all slashes, put back one slash at the end. */
+ strcat(string, "/");
+
+ while (*file && (*file == '/' || *file == '\\')) /* Trim slashes from the front of file */
+ file++;
+
+ strcat (string, file);
+
+ /* Push all slashes to the system preferred direction */
+ BLI_clean(string);
+}
+
+int BLI_testextensie(const char *str, const char *ext)
+{
+ short a, b;
+ int retval;
+
+ a= strlen(str);
+ b= strlen(ext);
+
+ if(a==0 || b==0 || b>=a) {
+ retval = 0;
+ } else if (BLI_strcasecmp(ext, str + a - b)) {
+ retval = 0;
+ } else {
+ retval = 1;
+ }
+
+ return (retval);
+}
+
+
+
+void BLI_split_dirfile(const char *string, char *dir, char *file)
+{
+ int a;
+#ifdef WIN32
+ int sl;
+ short is_relative = 0;
+#endif
+
+ dir[0]= 0;
+ file[0]= 0;
+
+#ifdef WIN32
+ BLI_char_switch(string, '/', '\\'); /* make sure we have a valid path format */
+ sl = strlen(string);
+ if (sl) {
+ int len;
+ if (string[0] == '/' || string[0] == '\\') {
+ BLI_strncpy(dir, string, FILE_MAXDIR);
+ if (sl > 1 && string[0] == '\\' && string[1] == '\\') is_relative = 1;
+ } else if (sl > 2 && string[1] == ':' && string[2] == '\\') {
+ BLI_strncpy(dir, string, FILE_MAXDIR);
+ } else {
+ BLI_getwdN(dir);
+ strcat(dir,"\\");
+ strcat(dir,string);
+ BLI_strncpy(string,dir,FILE_MAXDIR+FILE_MAXFILE);
+ }
+
+ // BLI_exist doesn't recognize a slashed dirname as a dir
+ // check if a trailing slash exists, and remove it. Do not do this
+ // when we are already at root. -jesterKing
+ a = strlen(dir);
+ if(a>=4 && dir[a-1]=='\\') dir[a-1] = 0;
+
+ if (is_relative) {
+ printf("WARNING: BLI_split_dirfile needs absolute dir\n");
+ }
+ else {
+ BLI_make_exist(dir);
+ }
+
+ if (S_ISDIR(BLI_exist(dir))) {
+
+ /* copy from end of string into file, to ensure filename itself isn't truncated
+ if string is too long. (aphex) */
+
+ len = FILE_MAXFILE - strlen(string);
+
+ if (len < 0)
+ BLI_strncpy(file,string + abs(len),FILE_MAXFILE);
+ else
+ BLI_strncpy(file,string,FILE_MAXFILE);
+
+ if (strrchr(string,'\\')) {
+ BLI_strncpy(file,strrchr(string,'\\')+1,FILE_MAXFILE);
+ }
+
+ if ( (a = strlen(dir)) ) {
+ if (dir[a-1] != '\\') strcat(dir,"\\");
+ }
+ }
+ else {
+ a = strlen(dir) - 1;
+ while(a>0 && dir[a] != '\\') a--;
+ dir[a + 1] = 0;
+ BLI_strncpy(file, string + strlen(dir),FILE_MAXFILE);
+ }
+
+ }
+ else {
+ /* defaulting to first valid drive hoping it's not empty CD and DVD drives */
+ get_default_root(dir);
+ file[0]=0;
+ }
+#else
+ if (strlen(string)) {
+ if (string[0] == '/') {
+ strcpy(dir, string);
+ } else if (string[1] == ':' && string[2] == '\\') {
+ string+=2;
+ strcpy(dir, string);
+ } else {
+ BLI_getwdN(dir);
+ strcat(dir,"/");
+ strcat(dir,string);
+ strcpy((char *)string,dir);
+ }
+
+ BLI_make_exist(dir);
+
+ if (S_ISDIR(BLI_exist(dir))) {
+ strcpy(file,string + strlen(dir));
+
+ if (strrchr(file,'/')) strcpy(file,strrchr(file,'/')+1);
+
+ if ( (a = strlen(dir)) ) {
+ if (dir[a-1] != '/') strcat(dir,"/");
+ }
+ }
+ else {
+ a = strlen(dir) - 1;
+ while(dir[a] != '/') a--;
+ dir[a + 1] = 0;
+ strcpy(file, string + strlen(dir));
+ }
+ }
+ else {
+ BLI_getwdN(dir);
+ strcat(dir, "/");
+ file[0] = 0;
+ }
+#endif
+}
+
+/* simple appending of filename to dir, does not check for valid path! */
+void BLI_join_dirfile(char *string, const char *dir, const char *file)
+{
+ int sl_dir = strlen(dir);
+ BLI_strncpy(string, dir, FILE_MAX);
+ if (sl_dir > FILE_MAX-1) sl_dir = FILE_MAX-1;
+#ifdef WIN32
+ string[sl_dir] = '\\';
+#else
+ string[sl_dir] = '/';
+#endif
+ sl_dir++;
+ if (sl_dir <FILE_MAX) {
+ BLI_strncpy(string + sl_dir, file, FILE_MAX-sl_dir);
+ }
+}
+
+static int add_win32_extension(char *name)
+{
+ int retval = 0;
+ int type;
+
+ type = BLI_exist(name);
+ if ((type == 0) || S_ISDIR(type)) {
+#ifdef _WIN32
+ char filename[FILE_MAXDIR+FILE_MAXFILE];
+ char ext[FILE_MAXDIR+FILE_MAXFILE];
+ char *extensions = getenv("PATHEXT");
+ if (extensions) {
+ char *temp;
+ do {
+ strcpy(filename, name);
+ temp = strstr(extensions, ";");
+ if (temp) {
+ strncpy(ext, extensions, temp - extensions);
+ ext[temp - extensions] = 0;
+ extensions = temp + 1;
+ strcat(filename, ext);
+ } else {
+ strcat(filename, extensions);
+ }
+
+ type = BLI_exist(filename);
+ if (type && (! S_ISDIR(type))) {
+ retval = 1;
+ strcpy(name, filename);
+ break;
+ }
+ } while (temp);
+ }
+#endif
+ } else {
+ retval = 1;
+ }
+
+ return (retval);
+}
+
+void BLI_where_am_i(char *fullname, char *name)
+{
+ char filename[FILE_MAXDIR+FILE_MAXFILE];
+ char *path, *temp;
+ int len;
+#ifdef _WIN32
+ char *seperator = ";";
+ char *slash = "\\";
+#else
+ char *seperator = ":";
+ char *slash = "/";
+#endif
+
+ if (name && fullname && strlen(name)) {
+ strcpy(fullname, name);
+ if (name[0] == '.') {
+ // relative path, prepend cwd
+ BLI_getwdN(fullname);
+ len = strlen(fullname);
+ if (len && fullname[len -1] != slash[0]) {
+ strcat(fullname, slash);
+ }
+ strcat(fullname, name);
+ add_win32_extension(fullname);
+ } else if (BLI_last_slash(name)) {
+ // full path
+ strcpy(fullname, name);
+ add_win32_extension(fullname);
+ } else {
+ // search for binary in $PATH
+ path = getenv("PATH");
+ if (path) {
+ do {
+ temp = strstr(path, seperator);
+ if (temp) {
+ strncpy(filename, path, temp - path);
+ filename[temp - path] = 0;
+ path = temp + 1;
+ } else {
+ strncpy(filename, path, sizeof(filename));
+ }
+ len = strlen(filename);
+ if (len && filename[len - 1] != slash[0]) {
+ strcat(filename, slash);
+ }
+ strcat(filename, name);
+ if (add_win32_extension(filename)) {
+ strcpy(fullname, filename);
+ break;
+ }
+ } while (temp);
+ }
+ }
+#ifndef NDEBUG
+ if (strcmp(name, fullname)) {
+ printf("guessing '%s' == '%s'\n", name, fullname);
+ }
+#endif
+
+#ifdef _WIN32
+ // in windows change long filename to short filename because
+ // win2k doesn't know how to parse a commandline with lots of
+ // spaces and double-quotes. There's another solution to this
+ // with spawnv(P_WAIT, bprogname, argv) instead of system() but
+ // that's even uglier
+ GetShortPathName(fullname, fullname, FILE_MAXDIR+FILE_MAXFILE);
+#ifndef NDEBUG
+ printf("Shortname = '%s'\n", fullname);
+#endif
+#endif
+ }
+}
+
+/*
+ * returns absolute path to the app bundle
+ * only useful on OS X
+ */
+#ifdef __APPLE__
+char* BLI_getbundle(void) {
+ CFURLRef bundleURL;
+ CFStringRef pathStr;
+ static char path[MAXPATHLEN];
+ CFBundleRef mainBundle = CFBundleGetMainBundle();
+
+ bundleURL = CFBundleCopyBundleURL(mainBundle);
+ pathStr = CFURLCopyFileSystemPath(bundleURL, kCFURLPOSIXPathStyle);
+ CFStringGetCString(pathStr, path, MAXPATHLEN, kCFStringEncodingASCII);
+ return path;
+}
+#endif
+
+/* strcasestr not available in MSVC */
+char *BLI_strcasestr(const char *s, const char *find)
+{
+ register char c, sc;
+ register size_t len;
+
+ if ((c = *find++) != 0) {
+ c= tolower(c);
+ len = strlen(find);
+ do {
+ do {
+ if ((sc = *s++) == 0)
+ return (NULL);
+ sc= tolower(sc);
+ } while (sc != c);
+ } while (BLI_strncasecmp(s, find, len) != 0);
+ s--;
+ }
+ return ((char *) s);
+}
+
+
+int BLI_strcasecmp(const char *s1, const char *s2) {
+ int i;
+
+ for (i=0; ; i++) {
+ char c1 = tolower(s1[i]);
+ char c2 = tolower(s2[i]);
+
+ if (c1<c2) {
+ return -1;
+ } else if (c1>c2) {
+ return 1;
+ } else if (c1==0) {
+ break;
+ }
+ }
+
+ return 0;
+}
+
+int BLI_strncasecmp(const char *s1, const char *s2, int n) {
+ int i;
+
+ for (i=0; i<n; i++) {
+ char c1 = tolower(s1[i]);
+ char c2 = tolower(s2[i]);
+
+ if (c1<c2) {
+ return -1;
+ } else if (c1>c2) {
+ return 1;
+ } else if (c1==0) {
+ break;
+ }
+ }
+
+ return 0;
+}
+
+
+#ifdef WITH_ICONV
+#include "iconv.h"
+#include "localcharset.h"
+
+void BLI_string_to_utf8(char *original, char *utf_8, char *code)
+{
+ size_t inbytesleft=strlen(original);
+ size_t outbytesleft=512;
+ size_t rv=0;
+ iconv_t cd;
+
+ if (NULL == code) {
+ code = locale_charset();
+ }
+ cd=iconv_open("UTF-8", code);
+
+ if (cd == (iconv_t)(-1)) {
+ printf("iconv_open Error");
+ *utf_8='\0';
+ return ;
+ }
+ rv=iconv(cd, &original, &inbytesleft, &utf_8, &outbytesleft);
+ if (rv == (size_t) -1) {
+ printf("iconv Error\n");
+ return ;
+ }
+ *utf_8 = '\0';
+ iconv_close(cd);
+}
+#endif // WITH_ICONV
+
+void BLI_timestr(double time, char *str)
+{
+ /* format 00:00:00.00 (hr:min:sec) string has to be 12 long */
+ int hr= ((int) time) / (60*60);
+ int min= ( ((int) time) / 60 ) % 60;
+ int sec= ((int) (time)) % 60;
+ int hun= ((int) (time * 100.0)) % 100;
+
+ if (hr) {
+ sprintf(str, "%.2d:%.2d:%.2d.%.2d",hr,min,sec,hun);
+ } else {
+ sprintf(str, "%.2d:%.2d.%.2d",min,sec,hun);
+ }
+
+ str[11]=0;
+}
+
+/* ************** 64 bits magic, trick to support up to 32 gig of address space *************** */
+/* only works for malloced pointers (8 aligned) */
+
+#ifdef __LP64__
+
+#if defined(WIN32) && !defined(FREE_WINDOWS)
+#define PMASK 0x07FFFFFFFFi64
+#else
+#define PMASK 0x07FFFFFFFFll
+#endif
+
+
+int BLI_int_from_pointer(void *poin)
+{
+ long lval= (long)poin;
+
+ return (int)(lval>>3);
+}
+
+void *BLI_pointer_from_int(int val)
+{
+ static int firsttime= 1;
+ static long basevalue= 0;
+
+ if(firsttime) {
+ void *poin= malloc(10000);
+ basevalue= (long)poin;
+ basevalue &= ~PMASK;
+ printf("base: %d pointer %p\n", basevalue, poin); /* debug */
+ firsttime= 0;
+ free(poin);
+ }
+ return (void *)(basevalue | (((long)val)<<3));
+}
+
+#else
+
+int BLI_int_from_pointer(void *poin)
+{
+ return (int)poin;
+}
+void *BLI_pointer_from_int(int val)
+{
+ return (void *)val;
+}
+
+#endif
+
diff --git a/source/blender/blenlib/intern/vectorops.c b/source/blender/blenlib/intern/vectorops.c
new file mode 100644
index 00000000000..8c4ad5414db
--- /dev/null
+++ b/source/blender/blenlib/intern/vectorops.c
@@ -0,0 +1,169 @@
+/*
+ *
+ * Some vector operations.
+ *
+ * Always use
+ * - vector with x components : float x[3], int x[3], etc
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/* ------------------------------------------------------------------------- */
+/* General format: op(a, b, c): a = b op c */
+/* Copying is done cp <from, to> */
+/* ------------------------------------------------------------------------- */
+
+#include "MTC_vectorops.h"
+#include <math.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+void MTC_diff3Int(int v1[3], int v2[3], int v3[3])
+{
+ v1[0] = v2[0] - v3[0];
+ v1[1] = v2[1] - v3[1];
+ v1[2] = v2[2] - v3[2];
+}
+
+/* ------------------------------------------------------------------------- */
+void MTC_diff3Float(float v1[3], float v2[3], float v3[3])
+{
+ v1[0] = v2[0] - v3[0];
+ v1[1] = v2[1] - v3[1];
+ v1[2] = v2[2] - v3[2];
+}
+
+/* ------------------------------------------------------------------------- */
+
+void MTC_cross3Int(int v1[3], int v2[3], int v3[3])
+{
+ v1[0] = v2[1]*v3[2] - v2[2]*v3[1];
+ v1[1] = v2[2]*v3[0] - v2[0]*v3[2];
+ v1[2] = v2[0]*v3[1] - v2[1]*v3[0];
+}
+
+/* ------------------------------------------------------------------------- */
+
+void MTC_cross3Float(float v1[3], float v2[3], float v3[3])
+{
+ v1[0] = v2[1]*v3[2] - v2[2]*v3[1];
+ v1[1] = v2[2]*v3[0] - v2[0]*v3[2];
+ v1[2] = v2[0]*v3[1] - v2[1]*v3[0];
+}
+/* ------------------------------------------------------------------------- */
+
+void MTC_cross3Double(double v1[3], double v2[3], double v3[3])
+{
+ v1[0] = v2[1]*v3[2] - v2[2]*v3[1];
+ v1[1] = v2[2]*v3[0] - v2[0]*v3[2];
+ v1[2] = v2[0]*v3[1] - v2[1]*v3[0];
+}
+
+/* ------------------------------------------------------------------------- */
+
+int MTC_dot3Int(int v1[3], int v2[3])
+{
+ return (v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]);
+}
+
+/* ------------------------------------------------------------------------- */
+
+float MTC_dot3Float(float v1[3], float v2[3])
+{
+ return (v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]);
+}
+
+/* ------------------------------------------------------------------------- */
+
+void MTC_cp3Float(float v1[3], float v2[3])
+{
+ v2[0] = v1[0];
+ v2[1] = v1[1];
+ v2[2] = v1[2];
+}
+
+/* ------------------------------------------------------------------------- */
+
+void MTC_cp3FloatInv(float v1[3], float v2[3])
+{
+ v2[0] = -v1[0];
+ v2[1] = -v1[1];
+ v2[2] = -v1[2];
+}
+
+/* ------------------------------------------------------------------------- */
+
+void MTC_swapInt(int *i1, int *i2)
+{
+ int swap;
+ swap = *i1;
+ *i1 = *i2;
+ *i2 = swap;
+}
+
+/* ------------------------------------------------------------------------- */
+
+void MTC_diff3DFF(double v1[3], float v2[3], float v3[3])
+{
+ v1[0] = v2[0] - v3[0];
+ v1[1] = v2[1] - v3[1];
+ v1[2] = v2[2] - v3[2];
+}
+
+/* ------------------------------------------------------------------------- */
+float MTC_normalize3DF(float n[3])
+{
+ float d;
+
+ d= n[0]*n[0]+n[1]*n[1]+n[2]*n[2];
+ /* FLT_EPSILON is too large! A larger value causes normalize errors in */
+ /* a scaled down utah teapot */
+ if(d>0.0000000000001) {
+
+ /* d= sqrt(d); This _should_ be sqrt, but internally it's a double*/
+ /* anyway. This is safe. */
+ d = sqrt(d);
+
+ n[0]/=d;
+ n[1]/=d;
+ n[2]/=d;
+ } else {
+ n[0]=n[1]=n[2]= 0.0;
+ d= 0.0;
+ }
+ return d;
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* eof */
diff --git a/source/blender/blenlib/intern/winstuff.c b/source/blender/blenlib/intern/winstuff.c
new file mode 100644
index 00000000000..1a3dfa79516
--- /dev/null
+++ b/source/blender/blenlib/intern/winstuff.c
@@ -0,0 +1,209 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * Windows-posix compatibility layer, windows-specific functions.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WIN32
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_util.h"
+#define WIN32_SKIP_HKEY_PROTECTION // need to use HKEY
+#include "BLI_winstuff.h"
+
+#include "BKE_utildefines.h" /* FILE_MAXDIR + FILE_MAXFILE */
+
+int BLI_getInstallationDir( char * str ) {
+ char dir[FILE_MAXDIR];
+ char file[FILE_MAXFILE];
+ int a;
+
+ GetModuleFileName(NULL,str,FILE_MAXDIR+FILE_MAXFILE);
+ BLI_split_dirfile(str,dir,file); /* shouldn't be relative */
+ a = strlen(dir);
+ if(dir[a-1] == '\\') dir[a-1]=0;
+
+ strcpy(str,dir);
+
+ return 1;
+}
+
+
+void RegisterBlendExtension(char * str) {
+ LONG lresult;
+ HKEY hkey = 0;
+ DWORD dwd = 0;
+ char buffer[128];
+
+ lresult = RegCreateKeyEx(HKEY_CLASSES_ROOT, "blendfile\\shell\\open\\command", 0,
+ "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, &dwd);
+
+ if (lresult == ERROR_SUCCESS) {
+ sprintf(buffer, "\"%s\" \"%%1\"", str);
+ lresult = RegSetValueEx(hkey, NULL, 0, REG_SZ, buffer, strlen(buffer) + 1);
+ RegCloseKey(hkey);
+ }
+
+ lresult = RegCreateKeyEx(HKEY_CLASSES_ROOT, "blendfile\\DefaultIcon", 0,
+ "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, &dwd);
+
+ if (lresult == ERROR_SUCCESS) {
+ sprintf(buffer, "\"%s\",1", str);
+ lresult = RegSetValueEx(hkey, NULL, 0, REG_SZ, buffer, strlen(buffer) + 1);
+ RegCloseKey(hkey);
+ }
+
+ lresult = RegCreateKeyEx(HKEY_CLASSES_ROOT, ".blend", 0,
+ "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, &dwd);
+
+ if (lresult == ERROR_SUCCESS) {
+ sprintf(buffer, "%s", "blendfile");
+ lresult = RegSetValueEx(hkey, NULL, 0, REG_SZ, buffer, strlen(buffer) + 1);
+ RegCloseKey(hkey);
+ }
+}
+
+DIR *opendir (const char *path) {
+ if (GetFileAttributes(path) & FILE_ATTRIBUTE_DIRECTORY) {
+ DIR *newd= MEM_mallocN(sizeof(DIR), "opendir");
+
+ newd->handle = INVALID_HANDLE_VALUE;
+ sprintf(newd->path, "%s\\*",path);
+
+ newd->direntry.d_ino= 0;
+ newd->direntry.d_off= 0;
+ newd->direntry.d_reclen= 0;
+ newd->direntry.d_name= NULL;
+
+ return newd;
+ } else {
+ return NULL;
+ }
+}
+
+struct dirent *readdir(DIR *dp) {
+ if (dp->direntry.d_name) {
+ MEM_freeN(dp->direntry.d_name);
+ dp->direntry.d_name= NULL;
+ }
+
+ if (dp->handle==INVALID_HANDLE_VALUE) {
+ dp->handle= FindFirstFile(dp->path, &(dp->data));
+ if (dp->handle==INVALID_HANDLE_VALUE)
+ return NULL;
+
+ dp->direntry.d_name= BLI_strdup(dp->data.cFileName);
+
+ return &dp->direntry;
+ } else if (FindNextFile (dp->handle, &(dp->data))) {
+ dp->direntry.d_name= BLI_strdup(dp->data.cFileName);
+
+ return &dp->direntry;
+ } else {
+ return NULL;
+ }
+}
+
+int closedir (DIR *dp) {
+ if (dp->direntry.d_name) MEM_freeN(dp->direntry.d_name);
+ if (dp->handle!=INVALID_HANDLE_VALUE) FindClose(dp->handle);
+
+ MEM_freeN(dp);
+
+ return 0;
+}
+
+void get_default_root(char* root) {
+ char str[MAX_PATH+1];
+
+ /* the default drive to resolve a directory without a specified drive
+ should be the Windows installation drive, since this was what the OS
+ assumes. */
+ if (GetWindowsDirectory(str,MAX_PATH+1)) {
+ root[0] = str[0];
+ root[1] = ':';
+ root[2] = '\\';
+ root[3] = '\0';
+ } else {
+ /* if GetWindowsDirectory fails, something has probably gone wrong,
+ we are trying the blender install dir though */
+ if (GetModuleFileName(NULL,str,MAX_PATH+1)) {
+ printf("Error! Could not get the Windows Directory - Defaulting to Blender installation Dir!");
+ root[0] = str[0];
+ root[1] = ':';
+ root[2] = '\\';
+ root[3] = '\0';
+ } else {
+ DWORD tmp;
+ int i;
+ int rc = 0;
+ /* now something has gone really wrong - still trying our best guess */
+ printf("Error! Could not get the Windows Directory - Defaulting to first valid drive! Path might be invalid!");
+ tmp= GetLogicalDrives();
+ for (i=2; i < 26; i++) {
+ if ((tmp>>i) & 1) {
+ root[0] = 'a'+i;
+ root[1] = ':';
+ root[2] = '\\';
+ root[3] = '\0';
+ if (GetFileAttributes(root) != 0xFFFFFFFF) {
+ rc = i;
+ break;
+ }
+ }
+ }
+ if (0 == rc) {
+ printf("ERROR in 'get_default_root': can't find a valid drive!");
+ root[0] = 'C';
+ root[1] = ':';
+ root[2] = '\\';
+ root[3] = '\0';
+ }
+ }
+ }
+}
+
+#else
+
+static void BLI_WINSTUFF_C_IS_EMPTY_FOR_UNIX(void)
+{
+ /*intentionally empty*/
+}
+
+#endif
diff --git a/source/blender/blenloader/BLO_genfile.h b/source/blender/blenloader/BLO_genfile.h
new file mode 100644
index 00000000000..6549bafe89b
--- /dev/null
+++ b/source/blender/blenloader/BLO_genfile.h
@@ -0,0 +1,38 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * external genfile function prototypes
+ */
+
+#ifndef BLO_GENFILE_H
+#define BLO_GENFILE_H
+
+#endif
+
diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h
new file mode 100644
index 00000000000..09edfe90d02
--- /dev/null
+++ b/source/blender/blenloader/BLO_readfile.h
@@ -0,0 +1,250 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * external readfile function prototypes
+ */
+#ifndef BLO_READFILE_H
+#define BLO_READFILE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct SpaceFile;
+struct SpaceImaSel;
+struct FileList;
+struct LinkNode;
+struct Main;
+struct UserDef;
+struct bScreen;
+struct Scene;
+struct MemFile;
+struct direntry;
+
+typedef struct BlendHandle BlendHandle;
+
+typedef enum BlenFileType {
+ BLENFILETYPE_BLEND= 1,
+ BLENFILETYPE_PUB= 2,
+ BLENFILETYPE_RUNTIME= 3
+} BlenFileType;
+
+typedef enum {
+ BRE_NONE,
+
+ BRE_UNABLE_TO_OPEN,
+ BRE_UNABLE_TO_READ,
+
+ BRE_OUT_OF_MEMORY,
+ BRE_INTERNAL_ERROR,
+
+ BRE_NOT_A_BLEND,
+ BRE_NOT_A_PUBFILE,
+ BRE_INCOMPLETE,
+ BRE_CORRUPT,
+
+ BRE_TOO_NEW,
+ BRE_NOT_ALLOWED,
+
+ BRE_NO_SCREEN,
+ BRE_NO_SCENE,
+
+ BRE_INVALID
+} BlendReadError;
+
+typedef struct BlendFileData {
+ struct Main* main;
+ struct UserDef* user;
+
+ int winpos;
+ int fileflags;
+ int displaymode;
+ int globalf;
+
+ struct bScreen* curscreen;
+ struct Scene* curscene;
+
+ BlenFileType type;
+} BlendFileData;
+
+ /**
+ * Open a blender file from a pathname. The function
+ * returns NULL and sets the @a error_r argument if
+ * it cannot open the file.
+ *
+ * @param file The path of the file to open.
+ * @param error_r If the return value is NULL, an error
+ * code indicating the cause of the failure.
+ * @return The data of the file.
+ */
+BlendFileData* BLO_read_from_file (char *file, BlendReadError *error_r);
+
+ /**
+ * Open a blender file from memory. The function
+ * returns NULL and sets the @a error_r argument if
+ * it cannot open the file.
+ *
+ * @param mem The file data.
+ * @param memsize The length of @a mem.
+ * @param error_r If the return value is NULL, an error
+ * code indicating the cause of the failure.
+ * @return The data of the file.
+ */
+BlendFileData* BLO_read_from_memory(void *mem, int memsize, BlendReadError *error_r);
+
+/**
+ * file name is current file, only for retrieving library data */
+
+BlendFileData *BLO_read_from_memfile(const char *filename, struct MemFile *memfile, BlendReadError *error_r);
+
+/**
+ * Convert a BlendReadError to a human readable string.
+ * The string is static and does not need to be free'd.
+ *
+ * @param error The error to return a string for.
+ * @return A static human readable string representation
+ * of @a error.
+ */
+
+ char*
+BLO_bre_as_string(
+ BlendReadError error);
+
+/**
+ * Free's a BlendFileData structure and _all_ the
+ * data associated with it (the userdef data, and
+ * the main libblock data).
+ *
+ * @param bfd The structure to free.
+ */
+ void
+BLO_blendfiledata_free(
+ BlendFileData *bfd);
+
+/**
+ * Convert an idcode into a name.
+ *
+ * @param code The code to convert.
+ * @return A static string representing the name of
+ * the code.
+ */
+ char*
+BLO_idcode_to_name(
+ int code);
+
+/**
+ * Convert a name into an idcode (ie. ID_SCE)
+ *
+ * @param name The name to convert.
+ * @return The code for the name, or 0 if invalid.
+ */
+ int
+BLO_idcode_from_name(
+ char *name);
+
+/**
+ * Open a blendhandle from a file path.
+ *
+ * @param file The file path to open.
+ * @return A handle on success, or NULL on failure.
+ */
+ BlendHandle*
+BLO_blendhandle_from_file(
+ char *file);
+
+/**
+ * Gets the names of all the datablocks in a file
+ * of a certain type (ie. All the scene names in
+ * a file).
+ *
+ * @param bh The blendhandle to access.
+ * @param ofblocktype The type of names to get.
+ * @return A BLI_linklist of strings. The string links
+ * should be freed with malloc.
+ */
+ struct LinkNode*
+BLO_blendhandle_get_datablock_names(
+ BlendHandle *bh,
+ int ofblocktype);
+
+/**
+ * Gets the previews of all the datablocks in a file
+ * of a certain type (ie. All the scene names in
+ * a file).
+ *
+ * @param bh The blendhandle to access.
+ * @param ofblocktype The type of names to get.
+ * @return A BLI_linklist of PreviewImage. The PreviewImage links
+ * should be freed with malloc.
+ */
+ struct LinkNode*
+BLO_blendhandle_get_previews(
+ BlendHandle *bh,
+ int ofblocktype);
+
+/**
+ * Gets the names of all the datablock groups in a
+ * file. (ie. file contains Scene, Mesh, and Lamp
+ * datablocks).
+ *
+ * @param bh The blendhandle to access.
+ * @return A BLI_linklist of strings. The string links
+ * should be freed with malloc.
+ */
+ struct LinkNode*
+BLO_blendhandle_get_linkable_groups(
+ BlendHandle *bh);
+
+/**
+ * Close and free a blendhandle. The handle
+ * becomes invalid after this call.
+ *
+ * @param bh The handle to close.
+ */
+ void
+BLO_blendhandle_close(
+ BlendHandle *bh);
+
+ /***/
+
+char *BLO_gethome(void);
+int BLO_has_bfile_extension(char *str);
+void BLO_library_append(struct SpaceFile *sfile, char *dir, int idcode);
+void BLO_library_append_(BlendHandle **libfiledata, struct direntry* filelist, int totfile, char *dir, char* file, short flag, int idcode);
+void BLO_script_library_append(BlendHandle *bh, char *dir, char *name, int idcode, short flag, struct Scene *scene);
+
+BlendFileData* blo_read_blendafterruntime(int file, int actualsize, BlendReadError *error_r);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/source/blender/blenloader/BLO_soundfile.h b/source/blender/blenloader/BLO_soundfile.h
new file mode 100644
index 00000000000..3a8ff3fcb99
--- /dev/null
+++ b/source/blender/blenloader/BLO_soundfile.h
@@ -0,0 +1,44 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BLO_SOUNDFILE_H
+#define BLO_SOUNDFILE_H
+
+#include "DNA_sound_types.h"
+#include "DNA_packedFile_types.h"
+
+struct bSound;
+struct PackedFile;
+
+//void sound_read_wav_data(bSound * sound, PackedFile * pf);
+
+#endif
+
diff --git a/source/blender/blenloader/BLO_sys_types.h b/source/blender/blenloader/BLO_sys_types.h
new file mode 100644
index 00000000000..38dde20500e
--- /dev/null
+++ b/source/blender/blenloader/BLO_sys_types.h
@@ -0,0 +1,102 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * A platform-independent definition of [u]intXX_t
+ * Plus the accompanying header include for htonl/ntohl
+ *
+ * This file includes <sys/types.h> to define [u]intXX_t types, where
+ * XX can be 8, 16, 32 or 64. Unfortunately, not all systems have this
+ * file.
+ * - Windows uses __intXX compiler-builtin types. These are signed,
+ * so we have to flip the signs.
+ * For these rogue platforms, we make the typedefs ourselves.
+ *
+ */
+
+#ifndef BLO_SYS_TYPES_H
+#define BLO_SYS_TYPES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef FREE_WINDOWS
+typedef unsigned char uint8_t;
+typedef unsigned int uint32_t;
+#endif
+
+#if defined(_WIN32) && !defined(FREE_WINDOWS)
+
+/* The __intXX are built-in types of the visual complier! So we don't
+ * need to include anything else here. */
+
+typedef signed __int8 int8_t;
+typedef signed __int16 int16_t;
+typedef signed __int32 int32_t;
+typedef signed __int64 int64_t;
+
+typedef unsigned __int8 uint8_t;
+typedef unsigned __int16 uint16_t;
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int64 uint64_t;
+
+#elif defined(__linux__)
+
+ /* Linux-i386, Linux-Alpha, Linux-ppc */
+#include <stdint.h>
+
+#elif defined (__APPLE__)
+
+#include <inttypes.h>
+
+#else
+
+ /* FreeBSD, Irix, Solaris */
+#include <sys/types.h>
+
+#endif /* ifdef platform for types */
+
+#ifdef _WIN32
+#define htonl(x) correctByteOrder(x)
+#define ntohl(x) correctByteOrder(x)
+#elif defined (__FreeBSD__) || defined (__OpenBSD__)
+#include <sys/param.h>
+#elif defined (__APPLE__)
+#include <sys/types.h>
+#else /* irix sun linux */
+#include <netinet/in.h>
+#endif /* ifdef platform for htonl/ntohl */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* eof */
+
diff --git a/source/blender/blenloader/BLO_undofile.h b/source/blender/blenloader/BLO_undofile.h
new file mode 100644
index 00000000000..225b6bc15f5
--- /dev/null
+++ b/source/blender/blenloader/BLO_undofile.h
@@ -0,0 +1,58 @@
+/*
+ * $Id:
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * external writefile function prototypes
+ */
+
+#ifndef BLO_UNDOFILE_H
+#define BLO_UNDOFILE_H
+
+typedef struct {
+ void *next, *prev;
+
+ char *buf;
+ unsigned int ident, size;
+
+} MemFileChunk;
+
+typedef struct MemFile {
+ ListBase chunks;
+ unsigned int size;
+} MemFile;
+
+/* actually only used writefile.c */
+extern void add_memfilechunk(MemFile *compare, MemFile *current, char *buf, unsigned int size);
+
+/* exports */
+extern void BLO_free_memfile(MemFile *memfile);
+extern void BLO_merge_memfile(MemFile *first, MemFile *second);
+
+#endif
+
diff --git a/source/blender/blenloader/BLO_writefile.h b/source/blender/blenloader/BLO_writefile.h
new file mode 100644
index 00000000000..cfa2fd7b0f6
--- /dev/null
+++ b/source/blender/blenloader/BLO_writefile.h
@@ -0,0 +1,44 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * external writefile function prototypes
+ */
+
+#ifndef BLO_WRITEFILE_H
+#define BLO_WRITEFILE_H
+
+struct MemFile;
+
+extern int BLO_write_file(char *dir, int write_flags, char **error_r);
+extern int BLO_write_file_mem(struct MemFile *compare, struct MemFile *current, int write_flags, char **error_r);
+extern void BLO_write_runtime(char *file, char *exename);
+
+#endif
+
diff --git a/source/blender/blenloader/CMakeLists.txt b/source/blender/blenloader/CMakeLists.txt
new file mode 100644
index 00000000000..3e21c1dc318
--- /dev/null
+++ b/source/blender/blenloader/CMakeLists.txt
@@ -0,0 +1,46 @@
+# $Id$
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2006, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Jacques Beaurain.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+
+FILE(GLOB SRC intern/*.c)
+
+SET(INC
+ . ../../../intern/guardedalloc ../blenlib ../blenkernel
+ ../makesdna ../readblenfile ../include
+ ../python ../../kernel/gen_messaging
+ ../render/extern/include
+ ${ZLIB_INC}
+)
+
+IF(WITH_VERSE)
+ ADD_DEFINITIONS(-DWITH_VERSE)
+ SET(INC ${INC} ${VERSE_INC})
+ENDIF(WITH_VERSE)
+
+BLENDERLIB(bf_blenloader "${SRC}" "${INC}")
+#env.BlenderLib ( 'bf_blenloader', sources, Split(incs), Split(defs), libtype=['core','player'], priority = [70, 30] )
diff --git a/source/blender/blenloader/Makefile b/source/blender/blenloader/Makefile
new file mode 100644
index 00000000000..0d7cd16453e
--- /dev/null
+++ b/source/blender/blenloader/Makefile
@@ -0,0 +1,37 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+# Bounces make to subdirectories.
+
+SOURCEDIR = source/blender/blenloader
+DIRS = intern
+
+include nan_subdirs.mk
diff --git a/source/blender/blenloader/SConscript b/source/blender/blenloader/SConscript
new file mode 100644
index 00000000000..fb36b15e3e7
--- /dev/null
+++ b/source/blender/blenloader/SConscript
@@ -0,0 +1,18 @@
+#!/usr/bin/python
+Import ('env')
+
+sources = env.Glob('intern/*.c')
+
+incs = '. #/intern/guardedalloc ../blenlib ../blenkernel'
+incs += ' ../makesdna ../readblenfile ../include'
+incs += ' ../python ../../kernel/gen_messaging'
+incs += ' ../render/extern/include'
+
+incs += ' ' + env['BF_ZLIB_INC']
+
+defs = ''
+if env['WITH_BF_VERSE']:
+ defs += ' WITH_VERSE'
+ incs += ' ' + env['BF_VERSE_INCLUDE']
+
+env.BlenderLib ( 'bf_blenloader', sources, Split(incs), Split(defs), libtype=['core','player'], priority = [70, 30] )
diff --git a/source/blender/blenloader/intern/Makefile b/source/blender/blenloader/intern/Makefile
new file mode 100644
index 00000000000..4fcb0e8db47
--- /dev/null
+++ b/source/blender/blenloader/intern/Makefile
@@ -0,0 +1,76 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+#
+
+LIBNAME = blenloader
+DIR = $(OCGDIR)/blender/$(LIBNAME)
+
+include nan_compile.mk
+
+# CFLAGS += $(LEVEL_2_C_WARNINGS)
+
+# OpenGL and Python
+CPPFLAGS += $(OGL_CPPFLAGS)
+CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION)
+
+# zlib
+ifeq ($(OS),$(findstring $(OS), "solaris windows"))
+ CPPFLAGS += -I$(NAN_ZLIB)/include
+endif
+
+ifeq ($(WITH_VERSE), true)
+ CPPFLAGS += -DWITH_VERSE
+ CPPFLAGS += -I$(NAN_VERSE)/include
+endif
+
+# streaming write function
+CPPFLAGS += -I../../writestreamglue
+CPPFLAGS += -I../../readstreamglue
+
+# initiate a streaming read pipe
+CPPFLAGS += -I../../readblenfile
+
+# This mod uses the GEN, DNA, BLI and BKE modules
+CPPFLAGS += -I../../../kernel/gen_messaging
+CPPFLAGS += -I../../makesdna
+CPPFLAGS += -I../../blenlib
+# path to the guarded memory allocator
+CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
+CPPFLAGS += -I../../blenkernel
+CPPFLAGS += -I../../render/extern/include/
+CPPFLAGS += -I../../python
+
+# we still refer to /include a bit...
+CPPFLAGS += -I../../include
+
+# path to our own external headerfiles
+CPPFLAGS += -I..
diff --git a/source/blender/blenloader/intern/genfile.c b/source/blender/blenloader/intern/genfile.c
new file mode 100644
index 00000000000..b21185e84a0
--- /dev/null
+++ b/source/blender/blenloader/intern/genfile.c
@@ -0,0 +1,1102 @@
+/* genfile.c
+ *
+ * Functions for struct-dna, the genetic file dot c!
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * DNA handling
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef WIN32
+#include <unistd.h> // for read close
+#else
+#include <io.h> // for open close read
+#endif
+
+#include <string.h> // strncmp
+#include <stdio.h> // for printf
+#include <stdlib.h> // for atoi
+#include <fcntl.h> // for open O_RDONLY
+
+#include "MEM_guardedalloc.h" // for MEM_freeN MEM_mallocN MEM_callocN
+#include "BLI_blenlib.h" // for BLI_filesize
+
+#include "BKE_utildefines.h" // for O_BINARY TRUE MIN2
+
+#include "DNA_sdna_types.h" // for SDNA ;-)
+
+#include "BLO_writefile.h"
+#include "BLO_genfile.h"
+
+#include "genfile.h"
+
+/* gcc 4.1 on mingw was complaining that __int64 was alredy defined
+actually is saw the line below as typedef long long long long...
+Anyhow, since its alredy defined, its safe to do an ifndef here- Cambpell*/
+#ifdef FREE_WINDOWS
+#ifndef __int64
+typedef long long __int64;
+#endif
+#endif
+
+/*
+ * - please note: no builtin security to detect input of double structs
+ * - if you want a struct not to be in DNA file: add two hash marks above it (#<enter>#<enter>)
+
+Structure DNA data is added to each blender file and to each executable, this to detect
+in .blend files new veriables in structs, changed array sizes, etc. It's also used for
+converting endian and pointer size (32-64 bits)
+As an extra, Python uses a call to detect run-time the contents of a blender struct.
+
+Create a structDNA: only needed when one of the input include (.h) files change.
+File Syntax:
+ SDNA (4 bytes) (magic number)
+ NAME (4 bytes)
+ <nr> (4 bytes) amount of names (int)
+ <string>
+ <string>
+ ...
+ ...
+ TYPE (4 bytes)
+ <nr> amount of types (int)
+ <string>
+ <string>
+ ...
+ ...
+ TLEN (4 bytes)
+ <len> (short) the lengths of types
+ <len>
+ ...
+ ...
+ STRC (4 bytes)
+ <nr> amount of structs (int)
+ <typenr><nr_of_elems> <typenr><namenr> <typenr><namenr> ...
+
+!!Remember to read/write integer and short aligned!!
+
+ While writing a file, the names of a struct is indicated with a type number,
+ to be found with: type= findstruct_nr(SDNA *, char *)
+ The value of 'type' corresponds with the the index within the structs array
+
+ For the moment: the complete DNA file is included in a .blend file. For
+ the future we can think of smarter methods, like only included the used
+ structs. Only needed to keep a file short though...
+
+ALLOWED AND TESTED CHANGES IN STRUCTS:
+ - type change (a char to float will be divided by 255)
+ - location within a struct (everthing can be randomly mixed up)
+ - struct within struct (within struct etc), this is recursive
+ - adding new elements, will be default initialized zero
+ - remving elements
+ - change of array sizes
+ - change of a pointer type: when the name doesn't change the contents is copied
+
+NOT YET:
+ - array (vec[3]) to float struct (vec3f)
+
+DONE:
+ - endian compatibility
+ - pointer conversion (32-64 bits)
+
+IMPORTANT:
+ - do not use #defines in structs for array lenghts, this cannot be read by the dna functions
+ - do not use uint, but unsigned int instead, ushort and ulong are allowed
+ - only use a long in Blender if you want this to be the size of a pointer. so it is
+ 32 bits or 64 bits, dependant at the cpu architecture
+ - chars are always unsigned
+ - aligment of variables has to be done in such a way, that any system does
+ not create 'padding' (gaps) in structures. So make sure that:
+ - short: 2 aligned
+ - int: 4 aligned
+ - float: 4 aligned
+ - double: 8 aligned
+ - long: 8 aligned
+ - struct: 8 aligned
+ - the sdna functions have several error prints builtin, always check blender running from a console.
+
+*/
+
+/* local */
+static int le_int(int temp);
+static short le_short(short temp);
+
+/* ************************* ENDIAN STUFF ********************** */
+
+static short le_short(short temp)
+{
+ short new;
+ char *rt=(char *)&temp, *rtn=(char *)&new;
+
+ rtn[0]= rt[1];
+ rtn[1]= rt[0];
+
+ return new;
+}
+
+
+static int le_int(int temp)
+{
+ int new;
+ char *rt=(char *)&temp, *rtn=(char *)&new;
+
+ rtn[0]= rt[3];
+ rtn[1]= rt[2];
+ rtn[2]= rt[1];
+ rtn[3]= rt[0];
+
+ return new;
+}
+
+
+/* ************************* MAKE DNA ********************** */
+
+/* allowed duplicate code from makesdna.c */
+static int arraysize(char *astr, int len)
+{
+ int a, mul=1;
+ char str[100], *cp=0;
+
+ memcpy(str, astr, len+1);
+
+ for(a=0; a<len; a++) {
+ if( str[a]== '[' ) {
+ cp= &(str[a+1]);
+ }
+ else if( str[a]==']' && cp) {
+ str[a]= 0;
+ mul*= atoi(cp);
+ }
+ }
+
+ return mul;
+}
+
+/* ************************* END MAKE DNA ********************** */
+
+/* ************************* DIV ********************** */
+
+void dna_freestructDNA(struct SDNA *sdna)
+{
+ MEM_freeN(sdna->data);
+ MEM_freeN(sdna->names);
+ MEM_freeN(sdna->types);
+ MEM_freeN(sdna->structs);
+
+ MEM_freeN(sdna);
+}
+
+static int elementsize(struct SDNA *sdna, short type, short name)
+/* call with numbers from struct-array */
+{
+ int mul, namelen, len;
+ char *cp;
+
+ cp= sdna->names[name];
+ len= 0;
+
+ namelen= strlen(cp);
+ /* is it a pointer or function pointer? */
+ if(cp[0]=='*' || cp[1]=='*') {
+ /* has the naam an extra length? (array) */
+ mul= 1;
+ if( cp[namelen-1]==']') mul= arraysize(cp, namelen);
+
+ len= sdna->pointerlen*mul;
+ }
+ else if( sdna->typelens[type] ) {
+ /* has the naam an extra length? (array) */
+ mul= 1;
+ if( cp[namelen-1]==']') mul= arraysize(cp, namelen);
+
+ len= mul*sdna->typelens[type];
+
+ }
+
+ return len;
+}
+
+#if 0
+static void printstruct(struct SDNA *sdna, short strnr)
+{
+ /* is for debug */
+ int b, nr;
+ short *sp;
+
+ sp= sdna->structs[strnr];
+
+ printf("struct %s\n", sdna->types[ sp[0] ]);
+ nr= sp[1];
+ sp+= 2;
+
+ for(b=0; b< nr; b++, sp+= 2) {
+ printf(" %s %s\n", sdna->types[sp[0]], sdna->names[sp[1]]);
+ }
+}
+#endif
+
+static short *findstruct_name(struct SDNA *sdna, char *str)
+{
+ int a;
+ short *sp=0;
+
+
+ for(a=0; a<sdna->nr_structs; a++) {
+
+ sp= sdna->structs[a];
+
+ if(strcmp( sdna->types[ sp[0] ], str )==0) return sp;
+ }
+
+ return 0;
+}
+
+int dna_findstruct_nr(struct SDNA *sdna, char *str)
+{
+ short *sp=0;
+ int a;
+
+ if(sdna->lastfind<sdna->nr_structs) {
+ sp= sdna->structs[sdna->lastfind];
+ if(strcmp( sdna->types[ sp[0] ], str )==0) return sdna->lastfind;
+ }
+
+ for(a=0; a<sdna->nr_structs; a++) {
+
+ sp= sdna->structs[a];
+
+ if(strcmp( sdna->types[ sp[0] ], str )==0) {
+ sdna->lastfind= a;
+ return a;
+ }
+ }
+
+ return -1;
+}
+
+/* ************************* END DIV ********************** */
+
+/* ************************* READ DNA ********************** */
+
+static void init_structDNA(struct SDNA *sdna, int do_endian_swap)
+/* in sdna->data the data, now we convert that to something understandable */
+{
+ int *data, *verg;
+ long nr;
+ short *sp;
+ char str[8], *cp;
+
+ verg= (int *)str;
+ data= (int *)sdna->data;
+
+ strcpy(str, "SDNA");
+ if( *data == *verg ) {
+
+ data++;
+
+ /* load names array */
+ strcpy(str, "NAME");
+ if( *data == *verg ) {
+ data++;
+
+ if(do_endian_swap) sdna->nr_names= le_int(*data);
+ else sdna->nr_names= *data;
+
+ data++;
+ sdna->names= MEM_callocN( sizeof(void *)*sdna->nr_names, "sdnanames");
+ }
+ else {
+ printf("NAME error in SDNA file\n");
+ return;
+ }
+
+ nr= 0;
+ cp= (char *)data;
+ while(nr<sdna->nr_names) {
+ sdna->names[nr]= cp;
+ while( *cp) cp++;
+ cp++;
+ nr++;
+ }
+ nr= (long)cp; /* prevent BUS error */
+ nr= (nr+3) & ~3;
+ cp= (char *)nr;
+
+ /* load type names array */
+ data= (int *)cp;
+ strcpy(str, "TYPE");
+ if( *data == *verg ) {
+ data++;
+
+ if(do_endian_swap) sdna->nr_types= le_int(*data);
+ else sdna->nr_types= *data;
+
+ data++;
+ sdna->types= MEM_callocN( sizeof(void *)*sdna->nr_types, "sdnatypes");
+ }
+ else {
+ printf("TYPE error in SDNA file\n");
+ return;
+ }
+
+ nr= 0;
+ cp= (char *)data;
+ while(nr<sdna->nr_types) {
+ sdna->types[nr]= cp;
+
+ /* this is a patch, to change struct names without a confict with SDNA */
+ /* be careful to use it, in this case for a system-struct (opengl/X) */
+
+ if( *cp == 'b') {
+ /* struct Screen was already used by X, 'bScreen' replaces the old IrisGL 'Screen' struct */
+ if( strcmp("bScreen", cp)==0 ) sdna->types[nr]= cp+1;
+ }
+
+ while( *cp) cp++;
+ cp++;
+ nr++;
+ }
+ nr= (long)cp; /* prevent BUS error */
+ nr= (nr+3) & ~3;
+ cp= (char *)nr;
+
+ /* load typelen array */
+ data= (int *)cp;
+ strcpy(str, "TLEN");
+ if( *data == *verg ) {
+ data++;
+ sp= (short *)data;
+ sdna->typelens= sp;
+
+ if(do_endian_swap) {
+ short a, *spo= sp;
+
+ a= sdna->nr_types;
+ while(a--) {
+ spo[0]= le_short(spo[0]);
+ spo++;
+ }
+ }
+
+ sp+= sdna->nr_types;
+ }
+ else {
+ printf("TLEN error in SDNA file\n");
+ return;
+ }
+ if(sdna->nr_types & 1) sp++; /* prevent BUS error */
+
+ /* load struct array */
+ data= (int *)sp;
+ strcpy(str, "STRC");
+ if( *data == *verg ) {
+ data++;
+
+ if(do_endian_swap) sdna->nr_structs= le_int(*data);
+ else sdna->nr_structs= *data;
+
+ data++;
+ sdna->structs= MEM_callocN( sizeof(void *)*sdna->nr_structs, "sdnastrcs");
+ }
+ else {
+ printf("STRC error in SDNA file\n");
+ return;
+ }
+
+ nr= 0;
+ sp= (short *)data;
+ while(nr<sdna->nr_structs) {
+ sdna->structs[nr]= sp;
+
+ if(do_endian_swap) {
+ short a;
+
+ sp[0]= le_short(sp[0]);
+ sp[1]= le_short(sp[1]);
+
+ a= sp[1];
+ sp+= 2;
+ while(a--) {
+ sp[0]= le_short(sp[0]);
+ sp[1]= le_short(sp[1]);
+ sp+= 2;
+ }
+ }
+ else {
+ sp+= 2*sp[1]+2;
+ }
+
+ nr++;
+ }
+
+ /* finally pointerlen: use struct ListBase to test it, never change the size of it! */
+ sp= findstruct_name(sdna, "ListBase");
+ /* weird; i have no memory of that... I think I used sizeof(void *) before... (ton) */
+
+ sdna->pointerlen= sdna->typelens[ sp[0] ]/2;
+
+ if(sp[1]!=2 || (sdna->pointerlen!=4 && sdna->pointerlen!=8)) {
+ printf("ListBase struct error! Needs it to calculate pointerize.\n");
+ exit(0);
+ /* well, at least sizeof(ListBase) is error proof! (ton) */
+ }
+
+ }
+}
+
+struct SDNA *dna_sdna_from_data(void *data, int datalen, int do_endian_swap)
+{
+ struct SDNA *sdna= MEM_mallocN(sizeof(*sdna), "sdna");
+
+ sdna->lastfind= 0;
+
+ sdna->datalen= datalen;
+ sdna->data= MEM_mallocN(datalen, "sdna_data");
+ memcpy(sdna->data, data, datalen);
+
+ init_structDNA(sdna, do_endian_swap);
+
+ return sdna;
+}
+
+/* ******************** END READ DNA ********************** */
+
+/* ******************* HANDLE DNA ***************** */
+
+static void recurs_test_compflags(struct SDNA *sdna, char *compflags, int structnr)
+{
+ int a, b, typenr, elems;
+ short *sp;
+ char *cp;
+
+ /* check all structs, test if it's inside another struct */
+ sp= sdna->structs[structnr];
+ typenr= sp[0];
+
+ for(a=0; a<sdna->nr_structs; a++) {
+ if(a!=structnr && compflags[a]==1) {
+ sp= sdna->structs[a];
+ elems= sp[1];
+ sp+= 2;
+ for(b=0; b<elems; b++, sp+=2) {
+ if(sp[0]==typenr) {
+ cp= sdna->names[ sp[1] ];
+ if(cp[0]!= '*') {
+ compflags[a]= 2;
+ recurs_test_compflags(sdna, compflags, a);
+ }
+ }
+ }
+ }
+ }
+
+}
+
+ /* Unsure of exact function - compares the sdna argument to
+ * newsdna and sets up the information necessary to convert
+ * data written with a dna of oldsdna to inmemory data with a
+ * structure defined by the newsdna sdna (I think). -zr
+ */
+
+/* well, the function below is just a lookup table to speed
+ * up reading files. doh! -ton
+ */
+
+
+char *dna_get_structDNA_compareflags(struct SDNA *sdna, struct SDNA *newsdna)
+{
+ /* flag: 0: doesn't exist anymore (or not yet)
+ * 1: is equal
+ * 2: is different
+ */
+ int a, b;
+ short *spold, *spcur;
+ char *str1, *str2;
+ char *compflags;
+
+ if(sdna->nr_structs==0) {
+ printf("error: file without SDNA\n");
+ return NULL;
+ }
+
+ compflags= MEM_callocN(sdna->nr_structs, "compflags");
+
+ /* we check all structs in 'sdna' and compare them with
+ * the structs in 'newsdna'
+ */
+
+ for(a=0; a<sdna->nr_structs; a++) {
+ spold= sdna->structs[a];
+
+ /* search for type in cur */
+ spcur= findstruct_name(newsdna, sdna->types[spold[0]]);
+
+ if(spcur) {
+ compflags[a]= 2;
+
+ /* compare length and amount of elems */
+ if( spcur[1] == spold[1]) {
+ if( newsdna->typelens[spcur[0]] == sdna->typelens[spold[0]] ) {
+
+ /* same length, same amount of elems, now per type and name */
+ b= spold[1];
+ spold+= 2;
+ spcur+= 2;
+ while(b > 0) {
+ str1= newsdna->types[spcur[0]];
+ str2= sdna->types[spold[0]];
+ if(strcmp(str1, str2)!=0) break;
+
+ str1= newsdna->names[spcur[1]];
+ str2= sdna->names[spold[1]];
+ if(strcmp(str1, str2)!=0) break;
+
+ /* same type and same name, now pointersize */
+ if(str1[0]=='*') {
+ if(sdna->pointerlen!=newsdna->pointerlen) break;
+ }
+
+ b--;
+ spold+= 2;
+ spcur+= 2;
+ }
+ if(b==0) compflags[a]= 1;
+
+ }
+ }
+
+ }
+ }
+
+ /* first struct in util.h is struct Link, this is skipped in compflags (als # 0).
+ * was a bug, and this way dirty patched! Solve this later....
+ */
+ compflags[0]= 1;
+
+ /* Because structs can be inside structs, we recursively
+ * set flags when a struct is altered
+ */
+ for(a=0; a<sdna->nr_structs; a++) {
+ if(compflags[a]==2) recurs_test_compflags(sdna, compflags, a);
+ }
+
+/*
+ for(a=0; a<sdna->nr_structs; a++) {
+ if(compflags[a]==2) {
+ spold= sdna->structs[a];
+ printf("changed: %s\n", sdna->types[ spold[0] ]);
+ }
+ }
+*/
+
+ return compflags;
+}
+
+static void cast_elem(char *ctype, char *otype, char *name, char *curdata, char *olddata)
+{
+ double val = 0.0;
+ int arrlen, curlen=1, oldlen=1, ctypenr, otypenr;
+
+ arrlen= arraysize(name, strlen(name));
+
+ /* define otypenr */
+ if(strcmp(otype, "char")==0) otypenr= 0;
+ else if((strcmp(otype, "uchar")==0)||(strcmp(otype, "unsigned char")==0)) otypenr= 1;
+ else if(strcmp(otype, "short")==0) otypenr= 2;
+ else if((strcmp(otype, "ushort")==0)||(strcmp(otype, "unsigned short")==0)) otypenr= 3;
+ else if(strcmp(otype, "int")==0) otypenr= 4;
+ else if(strcmp(otype, "long")==0) otypenr= 5;
+ else if((strcmp(otype, "ulong")==0)||(strcmp(otype, "unsigned long")==0)) otypenr= 6;
+ else if(strcmp(otype, "float")==0) otypenr= 7;
+ else if(strcmp(otype, "double")==0) otypenr= 8;
+ else return;
+
+ /* define ctypenr */
+ if(strcmp(ctype, "char")==0) ctypenr= 0;
+ else if((strcmp(ctype, "uchar")==0)||(strcmp(ctype, "unsigned char")==0)) ctypenr= 1;
+ else if(strcmp(ctype, "short")==0) ctypenr= 2;
+ else if((strcmp(ctype, "ushort")==0)||(strcmp(ctype, "unsigned short")==0)) ctypenr= 3;
+ else if(strcmp(ctype, "int")==0) ctypenr= 4;
+ else if(strcmp(ctype, "long")==0) ctypenr= 5;
+ else if((strcmp(ctype, "ulong")==0)||(strcmp(ctype, "unsigned long")==0)) ctypenr= 6;
+ else if(strcmp(ctype, "float")==0) ctypenr= 7;
+ else if(strcmp(ctype, "double")==0) ctypenr= 8;
+ else return;
+
+ /* define lengths */
+ if(otypenr < 2) oldlen= 1;
+ else if(otypenr < 4) oldlen= 2;
+ else if(otypenr < 8) oldlen= 4;
+ else oldlen= 8;
+
+ if(ctypenr < 2) curlen= 1;
+ else if(ctypenr < 4) curlen= 2;
+ else if(ctypenr < 8) curlen= 4;
+ else curlen= 8;
+
+ while(arrlen>0) {
+ switch(otypenr) {
+ case 0:
+ val= *olddata; break;
+ case 1:
+ val= *( (unsigned char *)olddata); break;
+ case 2:
+ val= *( (short *)olddata); break;
+ case 3:
+ val= *( (unsigned short *)olddata); break;
+ case 4:
+ val= *( (int *)olddata); break;
+ case 5:
+ val= *( (int *)olddata); break;
+ case 6:
+ val= *( (unsigned int *)olddata); break;
+ case 7:
+ val= *( (float *)olddata); break;
+ case 8:
+ val= *( (double *)olddata); break;
+ }
+
+ switch(ctypenr) {
+ case 0:
+ *curdata= val; break;
+ case 1:
+ *( (unsigned char *)curdata)= val; break;
+ case 2:
+ *( (short *)curdata)= val; break;
+ case 3:
+ *( (unsigned short *)curdata)= val; break;
+ case 4:
+ *( (int *)curdata)= val; break;
+ case 5:
+ *( (int *)curdata)= val; break;
+ case 6:
+ *( (unsigned int *)curdata)= val; break;
+ case 7:
+ if(otypenr<2) val/= 255;
+ *( (float *)curdata)= val; break;
+ case 8:
+ if(otypenr<2) val/= 255;
+ *( (double *)curdata)= val; break;
+ }
+
+ olddata+= oldlen;
+ curdata+= curlen;
+ arrlen--;
+ }
+}
+
+static void cast_pointer(int curlen, int oldlen, char *name, char *curdata, char *olddata)
+{
+#ifdef WIN32
+ __int64 lval;
+#else
+ long long lval;
+#endif
+ int arrlen;
+
+ arrlen= arraysize(name, strlen(name));
+
+ while(arrlen>0) {
+
+ if(curlen==oldlen) {
+ memcpy(curdata, olddata, curlen);
+ }
+ else if(curlen==4 && oldlen==8) {
+#ifdef WIN32
+ lval= *( (__int64 *)olddata );
+#else
+ lval= *( (long long *)olddata );
+#endif
+ *((int *)curdata) = lval>>3; /* is of course gambling! */
+ }
+ else if(curlen==8 && oldlen==4) {
+#ifdef WIN32
+ *( (__int64 *)curdata ) = *((int *)olddata);
+#else
+ *( (long long *)curdata ) = *((int *)olddata);
+#endif
+ }
+ else {
+ /* for debug */
+ printf("errpr: illegal pointersize! \n");
+ }
+
+ olddata+= oldlen;
+ curdata+= curlen;
+ arrlen--;
+
+ }
+}
+
+static int elem_strcmp(char *name, char *oname)
+{
+ int a=0;
+
+ /* strcmp without array part */
+
+ while(TRUE) {
+ if(name[a] != oname[a]) return 1;
+ if(name[a]=='[') break;
+ if(name[a]==0) break;
+ a++;
+ }
+ if(name[a] != oname[a]) return 1;
+ return 0;
+}
+
+static char *find_elem(struct SDNA *sdna, char *type, char *name, short *old, char *olddata, short **sppo)
+{
+ int a, elemcount, len;
+ char *otype, *oname;
+
+ /* without arraypart, so names can differ: return old namenr and type */
+
+ /* in old is the old struct */
+ elemcount= old[1];
+ old+= 2;
+ for(a=0; a<elemcount; a++, old+=2) {
+
+ otype= sdna->types[old[0]];
+ oname= sdna->names[old[1]];
+
+ len= elementsize(sdna, old[0], old[1]);
+
+ if( elem_strcmp(name, oname)==0 ) { /* naam equal */
+ if( strcmp(type, otype)==0 ) { /* type equal */
+ if(sppo) *sppo= old;
+ return olddata;
+ }
+
+ return 0;
+ }
+
+ olddata+= len;
+ }
+ return 0;
+}
+
+static void reconstruct_elem(struct SDNA *newsdna, struct SDNA *oldsdna, char *type, char *name, char *curdata, short *old, char *olddata)
+{
+ /* rules: test for NAME:
+ - name equal:
+ - cast type
+ - name partially equal (array differs)
+ - type equal: memcpy
+ - types casten
+ (nzc 2-4-2001 I want the 'unsigned' bit to be parsed as well. Where
+ can I force this?)
+ */
+ int a, elemcount, len, array, oldsize, cursize, mul;
+ char *otype, *oname, *cp;
+
+ /* is 'name' an array? */
+ cp= name;
+ array= 0;
+ while( *cp && *cp!='[') {
+ cp++; array++;
+ }
+ if( *cp!= '[' ) array= 0;
+
+ /* in old is the old struct */
+ elemcount= old[1];
+ old+= 2;
+ for(a=0; a<elemcount; a++, old+=2) {
+ otype= oldsdna->types[old[0]];
+ oname= oldsdna->names[old[1]];
+ len= elementsize(oldsdna, old[0], old[1]);
+
+ if( strcmp(name, oname)==0 ) { /* name equal */
+
+ if( name[0]=='*') { /* pointer afhandelen */
+ cast_pointer(newsdna->pointerlen, oldsdna->pointerlen, name, curdata, olddata);
+ }
+ else if( strcmp(type, otype)==0 ) { /* type equal */
+ memcpy(curdata, olddata, len);
+ }
+ else cast_elem(type, otype, name, curdata, olddata);
+
+ return;
+ }
+ else if(array) { /* name is an array */
+
+ if(oname[array]=='[' && strncmp(name, oname, array)==0 ) { /* basis equal */
+
+ cursize= arraysize(name, strlen(name));
+ oldsize= arraysize(oname, strlen(oname));
+
+ if( name[0]=='*') { /* handle pointer */
+ if(cursize>oldsize) cast_pointer(newsdna->pointerlen, oldsdna->pointerlen, oname, curdata, olddata);
+ else cast_pointer(newsdna->pointerlen, oldsdna->pointerlen, name, curdata, olddata);
+ }
+ else if(name[0]=='*' || strcmp(type, otype)==0 ) { /* type equal */
+ mul= len/oldsize;
+ mul*= MIN2(cursize, oldsize);
+ memcpy(curdata, olddata, mul);
+ }
+ else {
+ if(cursize>oldsize) cast_elem(type, otype, oname, curdata, olddata);
+ else cast_elem(type, otype, name, curdata, olddata);
+ }
+ return;
+ }
+ }
+ olddata+= len;
+ }
+}
+
+static void reconstruct_struct(struct SDNA *newsdna, struct SDNA *oldsdna, char *compflags, int oldSDNAnr, char *data, int curSDNAnr, char *cur)
+{
+ /* Recursive!
+ * Per element from cur_struct, read data from old_struct.
+ * If element is a struct, call recursive.
+ */
+ int a, elemcount, elen, eleno, mul, mulo, firststructtypenr;
+ short *spo, *spc, *sppo;
+ char *name, *nameo, *type, *cpo, *cpc;
+
+ if(oldSDNAnr== -1) return;
+ if(curSDNAnr== -1) return;
+
+ if( compflags[oldSDNAnr]==1 ) { /* if recursive: test for equal */
+
+ spo= oldsdna->structs[oldSDNAnr];
+ elen= oldsdna->typelens[ spo[0] ];
+ memcpy( cur, data, elen);
+
+ return;
+ }
+
+ firststructtypenr= *(newsdna->structs[0]);
+
+ spo= oldsdna->structs[oldSDNAnr];
+ spc= newsdna->structs[curSDNAnr];
+
+ elemcount= spc[1];
+
+ spc+= 2;
+ cpc= cur;
+ for(a=0; a<elemcount; a++, spc+=2) {
+ type= newsdna->types[spc[0]];
+ name= newsdna->names[spc[1]];
+
+ elen= elementsize(newsdna, spc[0], spc[1]);
+
+ /* test: is type a struct? */
+ if(spc[0]>=firststructtypenr && name[0]!='*') {
+
+ /* where does the old struct data start (and is there an old one?) */
+ cpo= find_elem(oldsdna, type, name, spo, data, &sppo);
+
+ if(cpo) {
+ oldSDNAnr= dna_findstruct_nr(oldsdna, type);
+ curSDNAnr= dna_findstruct_nr(newsdna, type);
+
+ /* array! */
+ mul= arraysize(name, strlen(name));
+ nameo= oldsdna->names[sppo[1]];
+ mulo= arraysize(nameo, strlen(nameo));
+
+ eleno= elementsize(oldsdna, sppo[0], sppo[1]);
+
+ elen/= mul;
+ eleno/= mulo;
+
+ while(mul--) {
+ reconstruct_struct(newsdna, oldsdna, compflags, oldSDNAnr, cpo, curSDNAnr, cpc);
+ cpo+= eleno;
+ cpc+= elen;
+
+ /* new struct array larger than old */
+ mulo--;
+ if(mulo<=0) break;
+ }
+ }
+ else cpc+= elen;
+ }
+ else {
+
+ reconstruct_elem(newsdna, oldsdna, type, name, cpc, spo, data);
+ cpc+= elen;
+
+ }
+ }
+}
+
+void dna_switch_endian_struct(struct SDNA *oldsdna, int oldSDNAnr, char *data)
+{
+ /* Recursive!
+ * If element is a struct, call recursive.
+ */
+ int a, mul, elemcount, elen, elena, firststructtypenr;
+ short *spo, *spc, skip;
+ char *name, *type, *cpo, *cur, cval;
+
+ if(oldSDNAnr== -1) return;
+ firststructtypenr= *(oldsdna->structs[0]);
+
+ spo= spc= oldsdna->structs[oldSDNAnr];
+
+ elemcount= spo[1];
+
+ spc+= 2;
+ cur= data;
+
+ for(a=0; a<elemcount; a++, spc+=2) {
+ type= oldsdna->types[spc[0]];
+ name= oldsdna->names[spc[1]];
+
+ /* elementsize = including arraysize */
+ elen= elementsize(oldsdna, spc[0], spc[1]);
+
+ /* test: is type a struct? */
+ if(spc[0]>=firststructtypenr && name[0]!='*') {
+ /* where does the old data start (is there one?) */
+ cpo= find_elem(oldsdna, type, name, spo, data, 0);
+ if(cpo) {
+ oldSDNAnr= dna_findstruct_nr(oldsdna, type);
+
+ mul= arraysize(name, strlen(name));
+ elena= elen/mul;
+
+ while(mul--) {
+ dna_switch_endian_struct(oldsdna, oldSDNAnr, cpo);
+ cpo += elena;
+ }
+ }
+ }
+ else {
+
+ if( name[0]=='*' ) {
+ if(oldsdna->pointerlen==8) {
+
+ mul= arraysize(name, strlen(name));
+ cpo= cur;
+ while(mul--) {
+ cval= cpo[0]; cpo[0]= cpo[7]; cpo[7]= cval;
+ cval= cpo[1]; cpo[1]= cpo[6]; cpo[6]= cval;
+ cval= cpo[2]; cpo[2]= cpo[5]; cpo[5]= cval;
+ cval= cpo[3]; cpo[3]= cpo[4]; cpo[4]= cval;
+
+ cpo+= 8;
+ }
+
+ }
+ }
+ else {
+
+ if( spc[0]==2 || spc[0]==3 ) { /* short-ushort */
+
+ /* exception: variable called blocktype/ipowin: derived from ID_ */
+ skip= 0;
+ if(name[0]=='b' && name[1]=='l') {
+ if(strcmp(name, "blocktype")==0) skip= 1;
+ }
+ else if(name[0]=='i' && name[1]=='p') {
+ if(strcmp(name, "ipowin")==0) skip= 1;
+ }
+
+ if(skip==0) {
+ mul= arraysize(name, strlen(name));
+ cpo= cur;
+ while(mul--) {
+ cval= cpo[0];
+ cpo[0]= cpo[1];
+ cpo[1]= cval;
+ cpo+= 2;
+ }
+ }
+ }
+ else if(spc[0]>3 && spc[0]<8) { /* int-long-ulong-float */
+
+ mul= arraysize(name, strlen(name));
+ cpo= cur;
+ while(mul--) {
+ cval= cpo[0];
+ cpo[0]= cpo[3];
+ cpo[3]= cval;
+ cval= cpo[1];
+ cpo[1]= cpo[2];
+ cpo[2]= cval;
+ cpo+= 4;
+ }
+ }
+ }
+ }
+ cur+= elen;
+ }
+}
+
+void *dna_reconstruct(struct SDNA *newsdna, struct SDNA *oldsdna, char *compflags, int oldSDNAnr, int blocks, void *data)
+{
+ int a, curSDNAnr, curlen=0, oldlen;
+ short *spo, *spc;
+ char *cur, *type, *cpc, *cpo;
+
+ /* oldSDNAnr == structnr, we're looking for the corresponding 'cur' number */
+ spo= oldsdna->structs[oldSDNAnr];
+ type= oldsdna->types[ spo[0] ];
+ oldlen= oldsdna->typelens[ spo[0] ];
+ curSDNAnr= dna_findstruct_nr(newsdna, type);
+
+ /* init data and alloc */
+ if(curSDNAnr >= 0) {
+ spc= newsdna->structs[curSDNAnr];
+ curlen= newsdna->typelens[ spc[0] ];
+ }
+ if(curlen==0) {
+ return NULL;
+ }
+
+ cur= MEM_callocN( blocks*curlen, "reconstruct");
+ cpc= cur;
+ cpo= data;
+ for(a=0; a<blocks; a++) {
+ reconstruct_struct(newsdna, oldsdna, compflags, oldSDNAnr, cpo, curSDNAnr, cpc);
+ cpc+= curlen;
+ cpo+= oldlen;
+ }
+
+ return cur;
+}
+
+int dna_elem_offset(struct SDNA *sdna, char *stype, char *vartype, char *name)
+{
+
+ int SDNAnr= dna_findstruct_nr(sdna, stype);
+ short *spo= sdna->structs[SDNAnr];
+ char *cp= find_elem(sdna, vartype, name, spo, NULL, NULL);
+ return (int)((long)cp);
+}
+
+
+
diff --git a/source/blender/blenloader/intern/genfile.h b/source/blender/blenloader/intern/genfile.h
new file mode 100644
index 00000000000..f027c14ac7a
--- /dev/null
+++ b/source/blender/blenloader/intern/genfile.h
@@ -0,0 +1,49 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * blenloader genfile private function prototypes
+ */
+
+#ifndef GENFILE_H
+#define GENFILE_H
+
+struct SDNA;
+
+int dna_findstruct_nr(struct SDNA *sdna, char *str);
+char *dna_get_structDNA_compareflags(struct SDNA *sdna, struct SDNA *newsdna);
+void dna_switch_endian_struct(struct SDNA *oldsdna, int oldSDNAnr, char *data);
+void *dna_reconstruct(struct SDNA *newsdna, struct SDNA *oldsdna, char *compflags, int oldSDNAnr, int blocks, void *data);
+int dna_elem_offset(struct SDNA *sdna, char *stype, char *vartype, char *name);
+
+struct SDNA *dna_sdna_from_data(void *data, int datalen, int do_endian_swap);
+void dna_freestructDNA(struct SDNA *sdna);
+
+#endif
+
diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c
new file mode 100644
index 00000000000..ef287428a19
--- /dev/null
+++ b/source/blender/blenloader/intern/readblenentry.c
@@ -0,0 +1,456 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * .blend file reading entry point
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
+#include "BLI_linklist.h"
+
+#include "DNA_sdna_types.h"
+#include "DNA_space_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_ID.h"
+#include "DNA_material_types.h"
+
+#include "BKE_utildefines.h" // for ENDB
+
+#include "BKE_main.h"
+#include "BKE_global.h"
+#include "BKE_library.h" // for free_main
+
+#include "BLO_readfile.h"
+#include "BLO_undofile.h"
+
+#include "readfile.h"
+#include "genfile.h"
+
+#include "BLO_readblenfile.h"
+
+ /**
+ * IDType stuff, I plan to move this
+ * out into its own file + prefix, and
+ * make sure all IDType handling goes through
+ * these routines.
+ */
+
+typedef struct {
+ unsigned short code;
+ char *name;
+
+ int flags;
+#define IDTYPE_FLAGS_ISLINKABLE (1<<0)
+} IDType;
+
+static IDType idtypes[]= {
+ { ID_AC, "Action", IDTYPE_FLAGS_ISLINKABLE},
+ { ID_AR, "Armature", IDTYPE_FLAGS_ISLINKABLE},
+ { ID_BR, "Brush", IDTYPE_FLAGS_ISLINKABLE},
+ { ID_CA, "Camera", IDTYPE_FLAGS_ISLINKABLE},
+ { ID_CU, "Curve", IDTYPE_FLAGS_ISLINKABLE},
+ { ID_GR, "Group", IDTYPE_FLAGS_ISLINKABLE},
+ { ID_ID, "ID", 0},
+ { ID_IM, "Image", IDTYPE_FLAGS_ISLINKABLE},
+ { ID_IP, "Ipo", IDTYPE_FLAGS_ISLINKABLE},
+ { ID_KE, "Key", 0},
+ { ID_LA, "Lamp", IDTYPE_FLAGS_ISLINKABLE},
+ { ID_LF, "Life", 0},
+ { ID_LI, "Library", 0},
+ { ID_LT, "Lattice", IDTYPE_FLAGS_ISLINKABLE},
+ { ID_MA, "Material", IDTYPE_FLAGS_ISLINKABLE},
+ { ID_MB, "Metaball", IDTYPE_FLAGS_ISLINKABLE},
+ { ID_ME, "Mesh", IDTYPE_FLAGS_ISLINKABLE},
+ { ID_NT, "NodeTree", IDTYPE_FLAGS_ISLINKABLE},
+ { ID_OB, "Object", IDTYPE_FLAGS_ISLINKABLE},
+ { ID_SCE, "Scene", IDTYPE_FLAGS_ISLINKABLE},
+ { ID_SCR, "Screen", 0},
+ { ID_SEQ, "Sequence", 0},
+ { ID_SE, "Sector", 0},
+ { ID_SO, "Sound", IDTYPE_FLAGS_ISLINKABLE},
+ { ID_TE, "Texture", IDTYPE_FLAGS_ISLINKABLE},
+ { ID_TXT, "Text", IDTYPE_FLAGS_ISLINKABLE},
+ { ID_VF, "VFont", IDTYPE_FLAGS_ISLINKABLE},
+ { ID_WO, "World", IDTYPE_FLAGS_ISLINKABLE},
+ { ID_WV, "Wave", 0},
+};
+static int nidtypes= sizeof(idtypes)/sizeof(idtypes[0]);
+
+/* local prototypes --------------------- */
+void BLO_blendhandle_print_sizes(BlendHandle *, void *);
+
+
+static IDType *idtype_from_name(char *str)
+{
+ int i= nidtypes;
+
+ while (i--)
+ if (BLI_streq(str, idtypes[i].name))
+ return &idtypes[i];
+
+ return NULL;
+}
+static IDType *idtype_from_code(int code)
+{
+ int i= nidtypes;
+
+ while (i--)
+ if (code==idtypes[i].code)
+ return &idtypes[i];
+
+ return NULL;
+}
+
+static int bheadcode_is_idcode(int code)
+{
+ return idtype_from_code(code)?1:0;
+}
+
+static int idcode_is_linkable(int code) {
+ IDType *idt= idtype_from_code(code);
+ return idt?(idt->flags&IDTYPE_FLAGS_ISLINKABLE):0;
+}
+
+char *BLO_idcode_to_name(int code)
+{
+ IDType *idt= idtype_from_code(code);
+
+ return idt?idt->name:NULL;
+}
+
+int BLO_idcode_from_name(char *name)
+{
+ IDType *idt= idtype_from_name(name);
+
+ return idt?idt->code:0;
+}
+
+ /* Access routines used by filesel. */
+
+BlendHandle *BLO_blendhandle_from_file(char *file)
+{
+ BlendReadError err;
+
+ return (BlendHandle*) blo_openblenderfile(file, &err);
+}
+
+void BLO_blendhandle_print_sizes(BlendHandle *bh, void *fp)
+{
+ FileData *fd= (FileData*) bh;
+ BHead *bhead;
+
+ fprintf(fp, "[\n");
+ for (bhead= blo_firstbhead(fd); bhead; bhead= blo_nextbhead(fd, bhead)) {
+ if (bhead->code==ENDB)
+ break;
+ else {
+ short *sp= fd->filesdna->structs[bhead->SDNAnr];
+ char *name= fd->filesdna->types[ sp[0] ];
+ char buf[4];
+
+ buf[0]= (bhead->code>>24)&0xFF;
+ buf[1]= (bhead->code>>16)&0xFF;
+ buf[2]= (bhead->code>>8)&0xFF;
+ buf[3]= (bhead->code>>0)&0xFF;
+
+ buf[0]= buf[0]?buf[0]:' ';
+ buf[1]= buf[1]?buf[1]:' ';
+ buf[2]= buf[2]?buf[2]:' ';
+ buf[3]= buf[3]?buf[3]:' ';
+
+ fprintf(fp, "['%.4s', '%s', %d, %ld ], \n", buf, name, bhead->nr, (long)bhead->len+sizeof(BHead));
+ }
+ }
+ fprintf(fp, "]\n");
+}
+
+LinkNode *BLO_blendhandle_get_datablock_names(BlendHandle *bh, int ofblocktype)
+{
+ FileData *fd= (FileData*) bh;
+ LinkNode *names= NULL;
+ BHead *bhead;
+
+ for (bhead= blo_firstbhead(fd); bhead; bhead= blo_nextbhead(fd, bhead)) {
+ if (bhead->code==ofblocktype) {
+ char *idname= bhead_id_name(fd, bhead);
+
+ BLI_linklist_prepend(&names, strdup(idname+2));
+ } else if (bhead->code==ENDB)
+ break;
+ }
+
+ return names;
+}
+
+LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype)
+{
+ FileData *fd= (FileData*) bh;
+ LinkNode *previews= NULL;
+ BHead *bhead;
+ int looking=0;
+ int npreviews = 0;
+ PreviewImage* prv = NULL;
+ PreviewImage* new_prv = NULL;
+
+ for (bhead= blo_firstbhead(fd); bhead; bhead= blo_nextbhead(fd, bhead)) {
+ if (bhead->code==ofblocktype) {
+ ID *id= (ID*) (bhead+1);
+ if ( (GS(id->name) == ID_MA) || (GS(id->name) == ID_TE)) {
+ new_prv = MEM_callocN(sizeof(PreviewImage), "newpreview");
+ BLI_linklist_prepend(&previews, new_prv);
+ looking = 1;
+ }
+ } else if (bhead->code==DATA) {
+ if (looking) {
+ if (bhead->SDNAnr == dna_findstruct_nr(fd->filesdna, "PreviewImage") ) {
+ prv = (PreviewImage*) (bhead+1);
+ npreviews = 0;
+ memcpy(new_prv, prv, sizeof(PreviewImage));
+ if (prv->rect[0]) {
+ unsigned int *rect = NULL;
+ int rectlen = 0;
+ new_prv->rect[0] = MEM_callocN(new_prv->w[0]*new_prv->h[0]*sizeof(unsigned int), "prvrect");
+ bhead= blo_nextbhead(fd, bhead);
+ rect = (unsigned int*)(bhead+1);
+ rectlen = new_prv->w[0]*new_prv->h[0]*sizeof(unsigned int);
+ memcpy(new_prv->rect[0], rect, bhead->len);
+ } else {
+ new_prv->rect[0] = NULL;
+ }
+
+ if (prv->rect[1]) {
+ unsigned int *rect = NULL;
+ int rectlen = 0;
+ new_prv->rect[1] = MEM_callocN(new_prv->w[1]*new_prv->h[1]*sizeof(unsigned int), "prvrect");
+ bhead= blo_nextbhead(fd, bhead);
+ rect = (unsigned int*)(bhead+1);
+ rectlen = new_prv->w[1]*new_prv->h[1]*sizeof(unsigned int);
+ memcpy(new_prv->rect[1], rect, bhead->len);
+ } else {
+ new_prv->rect[1] = NULL;
+ }
+ }
+ }
+ } else if (bhead->code==ENDB) {
+ break;
+ } else if (bhead->code==DATA) {
+ /* DATA blocks between IDBlock and Preview */
+ } else {
+ looking = 0;
+ new_prv = NULL;
+ prv = NULL;
+ }
+
+ }
+
+ return previews;
+}
+
+LinkNode *BLO_blendhandle_get_linkable_groups(BlendHandle *bh)
+{
+ FileData *fd= (FileData*) bh;
+ GHash *gathered= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
+ LinkNode *names= NULL;
+ BHead *bhead;
+
+ for (bhead= blo_firstbhead(fd); bhead; bhead= blo_nextbhead(fd, bhead)) {
+ if (bhead->code==ENDB) {
+ break;
+ } else if (bheadcode_is_idcode(bhead->code)) {
+ if (idcode_is_linkable(bhead->code)) {
+ char *str= BLO_idcode_to_name(bhead->code);
+
+ if (!BLI_ghash_haskey(gathered, str)) {
+ BLI_linklist_prepend(&names, strdup(str));
+ BLI_ghash_insert(gathered, str, NULL);
+ }
+ }
+ }
+ }
+
+ BLI_ghash_free(gathered, NULL, NULL);
+
+ return names;
+}
+
+void BLO_blendhandle_close(BlendHandle *bh) {
+ FileData *fd= (FileData*) bh;
+
+ blo_freefiledata(fd);
+}
+
+ /**********/
+
+BlendFileData *BLO_read_from_file(char *file, BlendReadError *error_r)
+{
+ BlendFileData *bfd = NULL;
+ FileData *fd;
+
+ fd = blo_openblenderfile(file, error_r);
+ if (fd) {
+ bfd= blo_read_file_internal(fd, error_r);
+ if (bfd) {
+ bfd->type= BLENFILETYPE_BLEND;
+ strncpy(bfd->main->name, file, sizeof(bfd->main->name)-1);
+ }
+ blo_freefiledata(fd);
+ }
+
+ return bfd;
+}
+
+BlendFileData *BLO_read_from_memory(void *mem, int memsize, BlendReadError *error_r)
+{
+ BlendFileData *bfd = NULL;
+ FileData *fd;
+
+ fd = blo_openblendermemory(mem, memsize, error_r);
+ if (fd) {
+ bfd= blo_read_file_internal(fd, error_r);
+ if (bfd) {
+ bfd->type= BLENFILETYPE_BLEND;
+ strcpy(bfd->main->name, "");
+ }
+ blo_freefiledata(fd);
+ }
+
+ return bfd;
+}
+
+BlendFileData *BLO_read_from_memfile(const char *filename, MemFile *memfile, BlendReadError *error_r)
+{
+ BlendFileData *bfd = NULL;
+ FileData *fd;
+ ListBase mainlist;
+
+ fd = blo_openblendermemfile(memfile, error_r);
+ if (fd) {
+ strcpy(fd->filename, filename);
+
+ /* separate libraries from G.main */
+ blo_split_main(&mainlist, G.main);
+ /* add the library pointers in oldmap lookup */
+ blo_add_library_pointer_map(&mainlist, fd);
+
+ /* makes lookup of existing images in G.main */
+ blo_make_image_pointer_map(fd);
+
+ bfd= blo_read_file_internal(fd, error_r);
+ if (bfd) {
+ bfd->type= BLENFILETYPE_BLEND;
+ strcpy(bfd->main->name, "");
+ }
+
+ /* ensures relinked images are not freed */
+ blo_end_image_pointer_map(fd);
+
+ /* move libraries from G.main to new main */
+ if(bfd && mainlist.first!=mainlist.last) {
+
+ /* Library structs themselves */
+ bfd->main->library= G.main->library;
+ G.main->library.first= G.main->library.last= NULL;
+
+ /* add the Library mainlist to the new main */
+ BLI_remlink(&mainlist, G.main);
+ BLI_addhead(&mainlist, bfd->main);
+ }
+ blo_join_main(&mainlist);
+
+ blo_freefiledata(fd);
+ }
+
+ return bfd;
+}
+
+void BLO_blendfiledata_free(BlendFileData *bfd)
+{
+ if (bfd->main) {
+ free_main(bfd->main);
+ }
+
+ if (bfd->user) {
+ MEM_freeN(bfd->user);
+ }
+
+ MEM_freeN(bfd);
+}
+
+char *BLO_bre_as_string(BlendReadError error)
+{
+ switch (error) {
+ case BRE_NONE:
+ return "No error";
+
+ case BRE_UNABLE_TO_OPEN:
+ return "Unable to open";
+ case BRE_UNABLE_TO_READ:
+ return "Unable to read";
+
+ case BRE_OUT_OF_MEMORY:
+ return "Out of memory";
+ case BRE_INTERNAL_ERROR:
+ return "<internal error>";
+
+ case BRE_NOT_A_BLEND:
+ return "File is not a Blender file";
+ case BRE_NOT_A_PUBFILE:
+ return "File is not a compressed, locked or signed Blender file";
+ case BRE_INCOMPLETE:
+ return "File incomplete";
+ case BRE_CORRUPT:
+ return "File corrupt";
+
+ case BRE_TOO_NEW:
+ return "File needs newer Blender version, please upgrade";
+ case BRE_NOT_ALLOWED:
+ return "File is locked";
+
+ case BRE_NO_SCREEN:
+ return "File has no screen";
+ case BRE_NO_SCENE:
+ return "File has no scene";
+
+ default:
+ case BRE_INVALID:
+ return "<invalid read error>";
+ }
+}
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
new file mode 100644
index 00000000000..384a6d93480
--- /dev/null
+++ b/source/blender/blenloader/intern/readfile.c
@@ -0,0 +1,8134 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "zlib.h"
+
+#ifdef WIN32
+#include "winsock2.h"
+#include "BLI_winstuff.h"
+#endif
+
+#include <stdio.h> // for printf fopen fwrite fclose sprintf FILE
+#include <stdlib.h> // for getenv atoi
+#include <fcntl.h> // for open
+#include <string.h> // for strrchr strncmp strstr
+#include <math.h> // for fabs
+
+#ifndef WIN32
+ #include <unistd.h> // for read close
+ #include <sys/param.h> // for MAXPATHLEN
+#else
+ #include <io.h> // for open close read
+#endif
+
+#include "nla.h"
+
+#include "DNA_action_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_ID.h"
+#include "DNA_actuator_types.h"
+#include "DNA_brush_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_color_types.h"
+#include "DNA_controller_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_customdata_types.h"
+#include "DNA_effect_types.h"
+#include "DNA_fileglobal_types.h"
+#include "DNA_group_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_image_types.h"
+#include "DNA_key_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_nla_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_object_force.h"
+#include "DNA_object_fluidsim.h" // NT
+#include "DNA_oops_types.h"
+#include "DNA_object_force.h"
+#include "DNA_packedFile_types.h"
+#include "DNA_property_types.h"
+#include "DNA_text_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_sensor_types.h"
+#include "DNA_sdna_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_sequence_types.h"
+#include "DNA_sound_types.h"
+#include "DNA_space_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_vfont_types.h"
+#include "DNA_world_types.h"
+
+#include "MEM_guardedalloc.h"
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_storage_types.h" // for relname flags
+
+#include "BDR_sculptmode.h"
+
+#include "BKE_bad_level_calls.h" // for reopen_text build_seqar (from WHILE_SEQ) set_rects_butspace check_imasel_copy
+
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_colortools.h"
+#include "BKE_constraint.h"
+#include "BKE_curve.h"
+#include "BKE_customdata.h"
+#include "BKE_deform.h"
+#include "BKE_depsgraph.h"
+#include "BKE_effect.h" // for give_parteff
+#include "BKE_global.h" // for G
+#include "BKE_group.h"
+#include "BKE_image.h"
+#include "BKE_lattice.h"
+#include "BKE_library.h" // for wich_libbase
+#include "BKE_main.h" // for Main
+#include "BKE_mesh.h" // for ME_ defines (patching)
+#include "BKE_modifier.h"
+#include "BKE_node.h" // for tree type defines
+#include "BKE_object.h"
+#include "BKE_property.h" // for get_property
+#include "BKE_sca.h" // for init_actuator
+#include "BKE_scene.h"
+#include "BKE_softbody.h" // sbNew()
+#include "BKE_texture.h" // for open_plugin_tex
+#include "BKE_utildefines.h" // SWITCH_INT DATA ENDB DNA1 O_BINARY GLOB USER TEST REND
+#include "BKE_idprop.h"
+
+#include "BIF_butspace.h" // badlevel, for do_versions, patching event codes
+#include "BIF_filelist.h" // badlevel too, where to move this? - elubie
+#include "BIF_previewrender.h" // bedlelvel, for struct RenderInfo
+#include "BLO_readfile.h"
+#include "BLO_undofile.h"
+#include "BLO_readblenfile.h" // streaming read pipe, for BLO_readblenfile BLO_readblenfilememory
+
+#include "multires.h"
+
+#include "readfile.h"
+
+#include "genfile.h"
+
+#include "mydevice.h"
+#include "blendef.h"
+
+#include <errno.h>
+
+/*
+ Remark: still a weak point is the newadress() function, that doesnt solve reading from
+ multiple files at the same time
+
+ (added remark: oh, i thought that was solved? will look at that... (ton)
+
+READ
+- Existing Library (Main) push or free
+- allocate new Main
+- load file
+- read SDNA
+- for each LibBlock
+ - read LibBlock
+ - if a Library
+ - make a new Main
+ - attach ID's to it
+ - else
+ - read associated 'direct data'
+ - link direct data (internal and to LibBlock)
+- read FileGlobal
+- read USER data, only when indicated (file is ~/.B.blend)
+- free file
+- per Library (per Main)
+ - read file
+ - read SDNA
+ - find LibBlocks and attach IDs to Main
+ - if external LibBlock
+ - search all Main's
+ - or it's already read,
+ - or not read yet
+ - or make new Main
+ - per LibBlock
+ - read recursive
+ - read associated direct data
+ - link direct data (internal and to LibBlock)
+ - free file
+- per Library with unread LibBlocks
+ - read file
+ - read SDNA
+ - per LibBlock
+ - read recursive
+ - read associated direct data
+ - link direct data (internal and to LibBlock)
+ - free file
+- join all Mains
+- link all LibBlocks and indirect pointers to libblocks
+- initialize FileGlobal and copy pointers to Global
+*/
+
+/* also occurs in library.c */
+/* GS reads the memory pointed at in a specific ordering. There are,
+ * however two definitions for it. I have jotted them down here, both,
+ * but I think the first one is actually used. The thing is that
+ * big-endian systems might read this the wrong way round. OTOH, we
+ * constructed the IDs that are read out with this macro explicitly as
+ * well. I expect we'll sort it out soon... */
+
+/* from blendef: */
+#define GS(a) (*((short *)(a)))
+
+/* from misc_util: flip the bytes from x */
+/* #define GS(x) (((unsigned char *)(x))[0] << 8 | ((unsigned char *)(x))[1]) */
+
+// only used here in readfile.c
+#define SWITCH_LONGINT(a) { \
+ char s_i, *p_i; \
+ p_i= (char *)&(a); \
+ s_i=p_i[0]; p_i[0]=p_i[7]; p_i[7]=s_i; \
+ s_i=p_i[1]; p_i[1]=p_i[6]; p_i[6]=s_i; \
+ s_i=p_i[2]; p_i[2]=p_i[5]; p_i[5]=s_i; \
+ s_i=p_i[3]; p_i[3]=p_i[4]; p_i[4]=s_i; }
+
+/***/
+
+typedef struct OldNew {
+ void *old, *newp;
+ int nr;
+} OldNew;
+
+typedef struct OldNewMap {
+ OldNew *entries;
+ int nentries, entriessize;
+ int sorted;
+ int lasthit;
+} OldNewMap;
+
+
+/* local prototypes */
+static void *read_struct(FileData *fd, BHead *bh, char *blockname);
+
+
+static OldNewMap *oldnewmap_new(void)
+{
+ OldNewMap *onm= MEM_callocN(sizeof(*onm), "OldNewMap");
+
+ onm->entriessize= 1024;
+ onm->entries= MEM_mallocN(sizeof(*onm->entries)*onm->entriessize, "OldNewMap.entries");
+
+ return onm;
+}
+
+static int verg_oldnewmap(const void *v1, const void *v2)
+{
+ const struct OldNew *x1=v1, *x2=v2;
+
+ if( x1->old > x2->old) return 1;
+ else if( x1->old < x2->old) return -1;
+ return 0;
+}
+
+
+static void oldnewmap_sort(FileData *fd)
+{
+ qsort(fd->libmap->entries, fd->libmap->nentries, sizeof(OldNew), verg_oldnewmap);
+ fd->libmap->sorted= 1;
+}
+
+/* nr is zero for data, and ID code for libdata */
+static void oldnewmap_insert(OldNewMap *onm, void *oldaddr, void *newaddr, int nr)
+{
+ OldNew *entry;
+
+ if(oldaddr==NULL || newaddr==NULL) return;
+
+ if (onm->nentries==onm->entriessize) {
+ int osize= onm->entriessize;
+ OldNew *oentries= onm->entries;
+
+ onm->entriessize*= 2;
+ onm->entries= MEM_mallocN(sizeof(*onm->entries)*onm->entriessize, "OldNewMap.entries");
+
+ memcpy(onm->entries, oentries, sizeof(*oentries)*osize);
+ MEM_freeN(oentries);
+ }
+
+ entry= &onm->entries[onm->nentries++];
+ entry->old= oldaddr;
+ entry->newp= newaddr;
+ entry->nr= nr;
+}
+
+static void *oldnewmap_lookup_and_inc(OldNewMap *onm, void *addr)
+{
+ int i;
+
+ if (onm->lasthit<onm->nentries-1) {
+ OldNew *entry= &onm->entries[++onm->lasthit];
+
+ if (entry->old==addr) {
+ entry->nr++;
+ return entry->newp;
+ }
+ }
+
+ for (i=0; i<onm->nentries; i++) {
+ OldNew *entry= &onm->entries[i];
+
+ if (entry->old==addr) {
+ onm->lasthit= i;
+
+ entry->nr++;
+ return entry->newp;
+ }
+ }
+
+ return NULL;
+}
+
+/* for libdata, nr has ID code, no increment */
+static void *oldnewmap_liblookup(OldNewMap *onm, void *addr, void *lib)
+{
+ int i;
+
+ if(addr==NULL) return NULL;
+
+ /* lasthit works fine for non-libdata, linking there is done in same sequence as writing */
+ if(onm->sorted) {
+ OldNew entry_s, *entry;
+
+ entry_s.old= addr;
+
+ entry= bsearch(&entry_s, onm->entries, onm->nentries, sizeof(OldNew), verg_oldnewmap);
+ if(entry) {
+ ID *id= entry->newp;
+
+ if (id && (!lib || id->lib)) {
+ return entry->newp;
+ }
+ }
+ }
+
+ for (i=0; i<onm->nentries; i++) {
+ OldNew *entry= &onm->entries[i];
+
+ if (entry->old==addr) {
+ ID *id= entry->newp;
+
+ if (id && (!lib || id->lib)) {
+ return entry->newp;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static void oldnewmap_free_unused(OldNewMap *onm)
+{
+ int i;
+
+ for (i=0; i<onm->nentries; i++) {
+ OldNew *entry= &onm->entries[i];
+ if (entry->nr==0) {
+ MEM_freeN(entry->newp);
+ entry->newp= NULL;
+ }
+ }
+}
+
+static void oldnewmap_clear(OldNewMap *onm)
+{
+ onm->nentries= 0;
+ onm->lasthit= 0;
+}
+
+static void oldnewmap_free(OldNewMap *onm)
+{
+ MEM_freeN(onm->entries);
+ MEM_freeN(onm);
+}
+
+/***/
+
+static void read_libraries(FileData *basefd, ListBase *mainlist);
+
+/* ************ help functions ***************** */
+
+static void add_main_to_main(Main *mainvar, Main *from)
+{
+ ListBase *lbarray[MAX_LIBARRAY], *fromarray[MAX_LIBARRAY];
+ int a;
+
+ a= set_listbasepointers(mainvar, lbarray);
+ a= set_listbasepointers(from, fromarray);
+ while(a--) {
+ addlisttolist(lbarray[a], fromarray[a]);
+ }
+}
+
+void blo_join_main(ListBase *mainlist)
+{
+ Main *tojoin, *mainl;
+
+
+ mainl= mainlist->first;
+ while ((tojoin= mainl->next)) {
+ add_main_to_main(mainl, tojoin);
+ BLI_remlink(mainlist, tojoin);
+ MEM_freeN(tojoin);
+ }
+}
+
+static void split_libdata(ListBase *lb, Main *first)
+{
+ ListBase *lbn;
+ ID *id, *idnext;
+ Main *mainvar;
+
+ id= lb->first;
+ while(id) {
+ idnext= id->next;
+ if(id->lib) {
+ mainvar= first;
+ while(mainvar) {
+ if(mainvar->curlib==id->lib) {
+ lbn= wich_libbase(mainvar, GS(id->name));
+ BLI_remlink(lb, id);
+ BLI_addtail(lbn, id);
+ break;
+ }
+ mainvar= mainvar->next;
+ }
+ if(mainvar==0) printf("error split_libdata\n");
+ }
+ id= idnext;
+ }
+}
+
+void blo_split_main(ListBase *mainlist, Main *main)
+{
+ ListBase *lbarray[MAX_LIBARRAY];
+ Library *lib;
+ int i;
+
+ mainlist->first= mainlist->last= main;
+ main->next= NULL;
+
+ if(main->library.first==NULL)
+ return;
+
+ for (lib= main->library.first; lib; lib= lib->id.next) {
+ Main *libmain= MEM_callocN(sizeof(Main), "libmain");
+ libmain->curlib= lib;
+ BLI_addtail(mainlist, libmain);
+ }
+
+ i= set_listbasepointers(main, lbarray);
+ while(i--)
+ split_libdata(lbarray[i], main->next);
+}
+
+/* removes things like /blah/blah/../../blah/ etc, then writes in *name the full path */
+static void cleanup_path(const char *relabase, char *name)
+{
+ char filename[FILE_MAXFILE];
+
+ BLI_splitdirstring(name, filename);
+ BLI_cleanup_dir(relabase, name);
+ strcat(name, filename);
+}
+
+static Main *blo_find_main(ListBase *mainlist, const char *name, const char *relabase)
+{
+ Main *m;
+ Library *lib;
+ char name1[FILE_MAXDIR+FILE_MAXFILE];
+
+ strncpy(name1, name, sizeof(name1)-1);
+ cleanup_path(relabase, name1);
+// printf("blo_find_main: original in %s\n", name);
+// printf("blo_find_main: converted to %s\n", name1);
+
+ for (m= mainlist->first; m; m= m->next) {
+ char *libname= (m->curlib)?m->curlib->filename:m->name;
+
+ if (BLI_streq(name1, libname)) {
+ if(G.f & G_DEBUG) printf("blo_find_main: found library %s\n", libname);
+ return m;
+ }
+ }
+
+ m= MEM_callocN(sizeof(Main), "find_main");
+ BLI_addtail(mainlist, m);
+
+ lib= alloc_libblock(&m->library, ID_LI, "lib");
+ strncpy(lib->name, name, sizeof(lib->name)-1);
+ BLI_strncpy(lib->filename, name1, sizeof(lib->filename));
+
+ m->curlib= lib;
+
+ if(G.f & G_DEBUG) printf("blo_find_main: added new lib %s\n", name);
+ return m;
+}
+
+
+/* ************ FILE PARSING ****************** */
+
+static void switch_endian_bh4(BHead4 *bhead)
+{
+ /* the ID_.. codes */
+ if((bhead->code & 0xFFFF)==0) bhead->code >>=16;
+
+ if (bhead->code != ENDB) {
+ SWITCH_INT(bhead->len);
+ SWITCH_INT(bhead->SDNAnr);
+ SWITCH_INT(bhead->nr);
+ }
+}
+
+static void switch_endian_bh8(BHead8 *bhead)
+{
+ /* the ID_.. codes */
+ if((bhead->code & 0xFFFF)==0) bhead->code >>=16;
+
+ if (bhead->code != ENDB) {
+ SWITCH_INT(bhead->len);
+ SWITCH_INT(bhead->SDNAnr);
+ SWITCH_INT(bhead->nr);
+ }
+}
+
+static void bh4_from_bh8(BHead *bhead, BHead8 *bhead8, int do_endian_swap)
+{
+ BHead4 *bhead4 = (BHead4 *) bhead;
+#if defined(WIN32) && !defined(FREE_WINDOWS)
+ __int64 old;
+#else
+ long long old;
+#endif
+
+ bhead4->code= bhead8->code;
+ bhead4->len= bhead8->len;
+
+ if (bhead4->code != ENDB) {
+
+ // why is this here ??
+ if (do_endian_swap) {
+ SWITCH_LONGINT(bhead8->old);
+ }
+
+ /* this patch is to avoid a long long being read from not-eight aligned positions
+ is necessary on any modern 64bit architecture) */
+ memcpy(&old, &bhead8->old, 8);
+ bhead4->old = (int) (old >> 3);
+
+ bhead4->SDNAnr= bhead8->SDNAnr;
+ bhead4->nr= bhead8->nr;
+ }
+}
+
+static void bh8_from_bh4(BHead *bhead, BHead4 *bhead4)
+{
+ BHead8 *bhead8 = (BHead8 *) bhead;
+
+ bhead8->code= bhead4->code;
+ bhead8->len= bhead4->len;
+
+ if (bhead8->code != ENDB) {
+ bhead8->old= bhead4->old;
+ bhead8->SDNAnr= bhead4->SDNAnr;
+ bhead8->nr= bhead4->nr;
+ }
+}
+
+static BHeadN *get_bhead(FileData *fd)
+{
+ BHead8 bhead8;
+ BHead4 bhead4;
+ BHead bhead;
+ BHeadN *new_bhead = 0;
+ int readsize;
+
+ if (fd) {
+ if ( ! fd->eof) {
+
+ // First read the bhead structure.
+ // Depending on the platform the file was written on this can
+ // be a big or little endian BHead4 or BHead8 structure.
+
+ // As usual 'ENDB' (the last *partial* bhead of the file)
+ // needs some special handling. We don't want to EOF just yet.
+
+ if (fd->flags & FD_FLAGS_FILE_POINTSIZE_IS_4) {
+ bhead4.code = DATA;
+ readsize = fd->read(fd, &bhead4, sizeof(bhead4));
+
+ if (readsize == sizeof(bhead4) || bhead4.code == ENDB) {
+ if (fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
+ switch_endian_bh4(&bhead4);
+ }
+
+ if (fd->flags & FD_FLAGS_POINTSIZE_DIFFERS) {
+ bh8_from_bh4(&bhead, &bhead4);
+ } else {
+ memcpy(&bhead, &bhead4, sizeof(bhead));
+ }
+ } else {
+ fd->eof = 1;
+ bhead.len= 0;
+ }
+ } else {
+ bhead8.code = DATA;
+ readsize = fd->read(fd, &bhead8, sizeof(bhead8));
+
+ if (readsize == sizeof(bhead8) || bhead8.code == ENDB) {
+ if (fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
+ switch_endian_bh8(&bhead8);
+ }
+
+ if (fd->flags & FD_FLAGS_POINTSIZE_DIFFERS) {
+ bh4_from_bh8(&bhead, &bhead8, (fd->flags & FD_FLAGS_SWITCH_ENDIAN));
+ } else {
+ memcpy(&bhead, &bhead8, sizeof(bhead));
+ }
+ } else {
+ fd->eof = 1;
+ bhead.len= 0;
+ }
+ }
+
+ /* make sure people are not trying to pass bad blend files */
+ if (bhead.len < 0) fd->eof = 1;
+
+ // bhead now contains the (converted) bhead structure. Now read
+ // the associated data and put everything in a BHeadN (creative naming !)
+
+ if ( ! fd->eof) {
+ new_bhead = MEM_mallocN(sizeof(BHeadN) + bhead.len, "new_bhead");
+ if (new_bhead) {
+ new_bhead->next = new_bhead->prev = 0;
+ new_bhead->bhead = bhead;
+
+ readsize = fd->read(fd, new_bhead + 1, bhead.len);
+
+ if (readsize != bhead.len) {
+ fd->eof = 1;
+ MEM_freeN(new_bhead);
+ new_bhead = 0;
+ }
+ } else {
+ fd->eof = 1;
+ }
+ }
+ }
+ }
+
+ // We've read a new block. Now add it to the list
+ // of blocks.
+
+ if (new_bhead) {
+ BLI_addtail(&fd->listbase, new_bhead);
+ }
+
+ return(new_bhead);
+}
+
+BHead *blo_firstbhead(FileData *fd)
+{
+ BHeadN *new_bhead;
+ BHead *bhead = 0;
+
+ // Rewind the file
+ // Read in a new block if necessary
+
+ new_bhead = fd->listbase.first;
+ if (new_bhead == 0) {
+ new_bhead = get_bhead(fd);
+ }
+
+ if (new_bhead) {
+ bhead = &new_bhead->bhead;
+ }
+
+ return(bhead);
+}
+
+BHead *blo_prevbhead(FileData *fd, BHead *thisblock)
+{
+ BHeadN *bheadn= (BHeadN *) (((char *) thisblock) - (int) (&((BHeadN*)0)->bhead));
+ BHeadN *prev= bheadn->prev;
+
+ return prev?&prev->bhead:NULL;
+}
+
+BHead *blo_nextbhead(FileData *fd, BHead *thisblock)
+{
+ BHeadN *new_bhead = 0;
+ BHead *bhead = 0;
+
+ if (thisblock) {
+ // bhead is actually a sub part of BHeadN
+ // We calculate the BHeadN pointer from the BHead pointer below
+ new_bhead = (BHeadN *) (((char *) thisblock) - (int) (&((BHeadN*)0)->bhead));
+
+ // get the next BHeadN. If it doesn't exist we read in the next one
+ new_bhead = new_bhead->next;
+ if (new_bhead == 0) {
+ new_bhead = get_bhead(fd);
+ }
+ }
+
+ if (new_bhead) {
+ // here we do the reverse:
+ // go from the BHeadN pointer to the BHead pointer
+ bhead = &new_bhead->bhead;
+ }
+
+ return(bhead);
+}
+
+#if 0
+static void get_blender_subversion(FileData *fd)
+{
+ BHead *bhead;
+
+ for (bhead= blo_firstbhead(fd); bhead; bhead= blo_nextbhead(fd, bhead)) {
+ if (bhead->code==GLOB) {
+ FileGlobal *fg= read_struct(fd, bhead, "Global");
+ fd->filesubversion= fg->subversion;
+ fd->fileminversion= fg->minversion;
+ fd->fileminsubversion= fg->minsubversion;
+ MEM_freeN(fg);
+ return;
+ }
+ else if (bhead->code==ENDB)
+ break;
+ }
+}
+#endif
+
+static void decode_blender_header(FileData *fd)
+{
+ char header[SIZEOFBLENDERHEADER], num[4];
+ int readsize;
+
+ // read in the header data
+ readsize = fd->read(fd, header, sizeof(header));
+
+ if (readsize == sizeof(header)) {
+ if(strncmp(header, "BLENDER", 7) == 0) {
+ int remove_this_endian_test= 1;
+
+ fd->flags |= FD_FLAGS_FILE_OK;
+
+ // what size are pointers in the file ?
+ if(header[7]=='_') {
+ fd->flags |= FD_FLAGS_FILE_POINTSIZE_IS_4;
+ if (sizeof(void *) != 4) {
+ fd->flags |= FD_FLAGS_POINTSIZE_DIFFERS;
+ }
+ } else {
+ if (sizeof(void *) != 8) {
+ fd->flags |= FD_FLAGS_POINTSIZE_DIFFERS;
+ }
+ }
+
+ // is the file saved in a different endian
+ // than we need ?
+ if (((((char*)&remove_this_endian_test)[0]==1)?L_ENDIAN:B_ENDIAN) != ((header[8]=='v')?L_ENDIAN:B_ENDIAN)) {
+ fd->flags |= FD_FLAGS_SWITCH_ENDIAN;
+ }
+
+ // get the version number
+
+ memcpy(num, header+9, 3);
+ num[3] = 0;
+ fd->fileversion = atoi(num);
+ }
+ }
+}
+
+static int read_file_dna(FileData *fd)
+{
+ BHead *bhead;
+
+ for (bhead= blo_firstbhead(fd); bhead; bhead= blo_nextbhead(fd, bhead)) {
+ if (bhead->code==DNA1) {
+ int do_endian_swap= (fd->flags&FD_FLAGS_SWITCH_ENDIAN)?1:0;
+
+ fd->filesdna= dna_sdna_from_data(&bhead[1], bhead->len, do_endian_swap);
+ if (fd->filesdna) {
+
+ fd->compflags= dna_get_structDNA_compareflags(fd->filesdna, fd->memsdna);
+ /* used to retrieve ID names from (bhead+1) */
+ fd->id_name_offs= dna_elem_offset(fd->filesdna, "ID", "char", "name[]");
+ }
+
+ return 1;
+ } else if (bhead->code==ENDB)
+ break;
+ }
+
+ return 0;
+}
+
+static int fd_read_from_file(FileData *filedata, void *buffer, int size)
+{
+ int readsize = read(filedata->filedes, buffer, size);
+
+ if (readsize < 0) {
+ readsize = EOF;
+ } else {
+ filedata->seek += readsize;
+ }
+
+ return (readsize);
+}
+
+static int fd_read_gzip_from_file(FileData *filedata, void *buffer, int size)
+{
+ int readsize = gzread(filedata->gzfiledes, buffer, size);
+
+ if (readsize < 0) {
+ readsize = EOF;
+ } else {
+ filedata->seek += readsize;
+ }
+
+ return (readsize);
+}
+
+static int fd_read_from_memory(FileData *filedata, void *buffer, int size)
+{
+ // don't read more bytes then there are available in the buffer
+ int readsize = MIN2(size, filedata->buffersize - filedata->seek);
+
+ memcpy(buffer, filedata->buffer + filedata->seek, readsize);
+ filedata->seek += readsize;
+
+ return (readsize);
+}
+
+static int fd_read_from_memfile(FileData *filedata, void *buffer, int size)
+{
+ static unsigned int seek= 1<<30; /* the current position */
+ static unsigned int offset= 0; /* size of previous chunks */
+ static MemFileChunk *chunk=NULL;
+
+ if(size==0) return 0;
+
+ if(seek != (unsigned int)filedata->seek) {
+ chunk= filedata->memfile->chunks.first;
+ seek= 0;
+
+ while(chunk) {
+ if(seek + chunk->size > (unsigned) filedata->seek) break;
+ seek+= chunk->size;
+ chunk= chunk->next;
+ }
+ offset= seek;
+ seek= filedata->seek;
+ }
+
+ if(chunk) {
+ /* first check if it's on the end if current chunk */
+ if( seek-offset == chunk->size) {
+ offset+= chunk->size;
+ chunk= chunk->next;
+ }
+
+ /* debug, should never happen */
+ if(chunk==NULL) {
+ printf("illegal read, chunk zero\n");
+ return 0;
+ }
+ else if( (seek-offset)+size > chunk->size) {
+ size= chunk->size - (seek-offset);
+ printf("chunk too large, clipped to %d\n", size);
+ }
+
+ memcpy(buffer, chunk->buf + (seek-offset), size);
+ filedata->seek += size;
+ seek+= size;
+
+ return (size);
+
+ }
+ return 0;
+}
+
+static FileData *filedata_new(void)
+{
+ extern unsigned char DNAstr[]; /* DNA.c */
+ extern int DNAlen;
+ FileData *fd = MEM_callocN(sizeof(FileData), "FileData");
+
+ fd->filedes = -1;
+ fd->gzfiledes = NULL;
+
+ /* XXX, this doesn't need to be done all the time,
+ * but it keeps us reentrant, remove once we have
+ * a lib that provides a nice lock. - zr
+ */
+ fd->memsdna = dna_sdna_from_data(DNAstr, DNAlen, 0);
+
+ fd->datamap = oldnewmap_new();
+ fd->globmap = oldnewmap_new();
+ fd->libmap = oldnewmap_new();
+
+ return fd;
+}
+
+static FileData *blo_decode_and_check(FileData *fd, BlendReadError *error_r)
+{
+ decode_blender_header(fd);
+
+ if (fd->flags & FD_FLAGS_FILE_OK) {
+ if (!read_file_dna(fd)) {
+ *error_r = BRE_INCOMPLETE;
+ blo_freefiledata(fd);
+ fd= NULL;
+ }
+ }
+ else {
+ *error_r = BRE_NOT_A_BLEND;
+ blo_freefiledata(fd);
+ fd= NULL;
+ }
+
+ return fd;
+}
+
+/* cannot be called with relative paths anymore! */
+/* on each new library added, it now checks for the current FileData and expands relativeness */
+FileData *blo_openblenderfile(char *name, BlendReadError *error_r)
+{
+ gzFile gzfile;
+
+ gzfile= gzopen(name, "rb");
+
+ if (NULL == gzfile) {
+ *error_r = BRE_UNABLE_TO_OPEN;
+ return NULL;
+ } else {
+ FileData *fd = filedata_new();
+ fd->gzfiledes = gzfile;
+ BLI_strncpy(fd->filename, name, sizeof(fd->filename)); // now only in use by library append
+ fd->read = fd_read_gzip_from_file;
+
+ return blo_decode_and_check(fd, error_r);
+ }
+}
+
+FileData *blo_openblendermemory(void *mem, int memsize, BlendReadError *error_r)
+{
+ if (!mem || memsize<SIZEOFBLENDERHEADER) {
+ *error_r = mem?BRE_UNABLE_TO_READ:BRE_UNABLE_TO_OPEN;
+ return NULL;
+ } else {
+ FileData *fd= filedata_new();
+ fd->buffer= mem;
+ fd->buffersize= memsize;
+ fd->read= fd_read_from_memory;
+ fd->flags|= FD_FLAGS_NOT_MY_BUFFER;
+
+ return blo_decode_and_check(fd, error_r);
+ }
+}
+
+FileData *blo_openblendermemfile(MemFile *memfile, BlendReadError *error_r)
+{
+ if (!memfile) {
+ *error_r = BRE_UNABLE_TO_OPEN;
+ return NULL;
+ } else {
+ FileData *fd= filedata_new();
+ fd->memfile= memfile;
+
+ fd->read= fd_read_from_memfile;
+ fd->flags|= FD_FLAGS_NOT_MY_BUFFER;
+
+ return blo_decode_and_check(fd, error_r);
+ }
+}
+
+
+void blo_freefiledata(FileData *fd)
+{
+ if (fd) {
+
+ if (fd->filedes != -1) {
+ close(fd->filedes);
+ }
+
+ if (fd->gzfiledes != NULL)
+ {
+ gzclose(fd->gzfiledes);
+ }
+
+ if (fd->buffer && !(fd->flags & FD_FLAGS_NOT_MY_BUFFER)) {
+ MEM_freeN(fd->buffer);
+ fd->buffer = 0;
+ }
+
+ // Free all BHeadN data blocks
+ BLI_freelistN(&fd->listbase);
+
+ if (fd->memsdna)
+ dna_freestructDNA(fd->memsdna);
+ if (fd->filesdna)
+ dna_freestructDNA(fd->filesdna);
+ if (fd->compflags)
+ MEM_freeN(fd->compflags);
+
+ if (fd->datamap)
+ oldnewmap_free(fd->datamap);
+ if (fd->globmap)
+ oldnewmap_free(fd->globmap);
+ if (fd->imamap)
+ oldnewmap_free(fd->imamap);
+ if (fd->libmap && !(fd->flags & FD_FLAGS_NOT_MY_LIBMAP))
+ oldnewmap_free(fd->libmap);
+
+ MEM_freeN(fd);
+ }
+}
+
+/* ************ DIV ****************** */
+
+int BLO_has_bfile_extension(char *str)
+{
+ return (BLI_testextensie(str, ".ble") || BLI_testextensie(str, ".blend")||BLI_testextensie(str, ".blend.gz"));
+}
+
+/* ************** OLD POINTERS ******************* */
+
+static void *newdataadr(FileData *fd, void *adr) /* only direct databocks */
+{
+ return oldnewmap_lookup_and_inc(fd->datamap, adr);
+}
+
+static void *newglobadr(FileData *fd, void *adr) /* direct datablocks with global linking */
+{
+ return oldnewmap_lookup_and_inc(fd->globmap, adr);
+}
+
+static void *newimaadr(FileData *fd, void *adr) /* used to restore image data after undo */
+{
+ if(fd->imamap && adr)
+ return oldnewmap_lookup_and_inc(fd->imamap, adr);
+ return NULL;
+}
+
+
+static void *newlibadr(FileData *fd, void *lib, void *adr) /* only lib data */
+{
+ return oldnewmap_liblookup(fd->libmap, adr, lib);
+}
+
+static void *newlibadr_us(FileData *fd, void *lib, void *adr) /* increases user number */
+{
+ ID *id= newlibadr(fd, lib, adr);
+
+ if(id)
+ id->us++;
+
+ return id;
+}
+
+static void change_idid_adr_fd(FileData *fd, void *old, void *new)
+{
+ int i;
+
+ for (i=0; i<fd->libmap->nentries; i++) {
+ OldNew *entry= &fd->libmap->entries[i];
+
+ if (old==entry->newp && entry->nr==ID_ID) {
+ entry->newp= new;
+ if(new) entry->nr= GS( ((ID *)new)->name );
+ break;
+ }
+ }
+}
+
+static void change_idid_adr(ListBase *mainlist, FileData *basefd, void *old, void *new)
+{
+ Main *mainptr;
+
+ for(mainptr= mainlist->first; mainptr; mainptr= mainptr->next) {
+ FileData *fd;
+
+ if(mainptr->curlib) fd= mainptr->curlib->filedata;
+ else fd= basefd;
+
+ if(fd) {
+ change_idid_adr_fd(fd, old, new);
+ }
+ }
+}
+
+/* assumed; G.main still exists */
+void blo_make_image_pointer_map(FileData *fd)
+{
+ Image *ima= G.main->image.first;
+ Scene *sce= G.main->scene.first;
+
+ fd->imamap= oldnewmap_new();
+
+ for(;ima; ima= ima->id.next) {
+ Link *ibuf= ima->ibufs.first;
+ for(; ibuf; ibuf= ibuf->next)
+ oldnewmap_insert(fd->imamap, ibuf, ibuf, 0);
+ }
+ for(; sce; sce= sce->id.next) {
+ if(sce->nodetree) {
+ bNode *node;
+ for(node= sce->nodetree->nodes.first; node; node= node->next)
+ oldnewmap_insert(fd->imamap, node->preview, node->preview, 0);
+ }
+ }
+}
+
+/* set G.main image ibufs to zero if it has been restored */
+/* this works because freeing G.main only happens after this call */
+void blo_end_image_pointer_map(FileData *fd)
+{
+ OldNew *entry= fd->imamap->entries;
+ Image *ima= G.main->image.first;
+ Scene *sce= G.main->scene.first;
+ int i;
+
+ /* used entries were restored, so we put them to zero */
+ for (i=0; i<fd->imamap->nentries; i++, entry++) {
+ if (entry->nr>0)
+ entry->newp= NULL;
+ }
+
+ for(;ima; ima= ima->id.next) {
+ Link *ibuf, *next;
+
+ /* this mirrors direct_link_image */
+ for(ibuf= ima->ibufs.first; ibuf; ibuf= next) {
+ next= ibuf->next;
+ if(NULL==newimaadr(fd, ibuf)) { /* so was restored */
+ BLI_remlink(&ima->ibufs, ibuf);
+ ima->bindcode= 0;
+ }
+ }
+ }
+ for(; sce; sce= sce->id.next) {
+ if(sce->nodetree) {
+ bNode *node;
+ for(node= sce->nodetree->nodes.first; node; node= node->next)
+ node->preview= newimaadr(fd, node->preview);
+ }
+ }
+}
+
+/* undo file support: add all library pointers in lookup */
+void blo_add_library_pointer_map(ListBase *mainlist, FileData *fd)
+{
+ Main *ptr= mainlist->first;
+ ListBase *lbarray[MAX_LIBARRAY];
+
+ for(ptr= ptr->next; ptr; ptr= ptr->next) {
+ int i= set_listbasepointers(ptr, lbarray);
+ while(i--) {
+ ID *id;
+ for(id= lbarray[i]->first; id; id= id->next)
+ oldnewmap_insert(fd->libmap, id, id, GS(id->name));
+ }
+ }
+}
+
+
+/* ********** END OLD POINTERS ****************** */
+/* ********** READ FILE ****************** */
+
+static void switch_endian_structs(struct SDNA *filesdna, BHead *bhead)
+{
+ int blocksize, nblocks;
+ char *data;
+
+ data= (char *)(bhead+1);
+ blocksize= filesdna->typelens[ filesdna->structs[bhead->SDNAnr][0] ];
+
+ nblocks= bhead->nr;
+ while(nblocks--) {
+ dna_switch_endian_struct(filesdna, bhead->SDNAnr, data);
+
+ data+= blocksize;
+ }
+}
+
+static void *read_struct(FileData *fd, BHead *bh, char *blockname)
+{
+ void *temp= NULL;
+
+ if (bh->len) {
+ /* switch is based on file dna */
+ if (bh->SDNAnr && (fd->flags & FD_FLAGS_SWITCH_ENDIAN))
+ switch_endian_structs(fd->filesdna, bh);
+
+ if (fd->compflags[bh->SDNAnr]) { /* flag==0: doesn't exist anymore */
+ if(fd->compflags[bh->SDNAnr]==2) {
+ temp= dna_reconstruct(fd->memsdna, fd->filesdna, fd->compflags, bh->SDNAnr, bh->nr, (bh+1));
+ } else {
+ temp= MEM_mallocN(bh->len, blockname);
+ memcpy(temp, (bh+1), bh->len);
+ }
+ }
+ }
+
+ return temp;
+}
+
+static void link_list(FileData *fd, ListBase *lb) /* only direct data */
+{
+ Link *ln, *prev;
+
+ if(lb->first==NULL) return;
+
+ lb->first= newdataadr(fd, lb->first);
+ ln= lb->first;
+ prev= NULL;
+ while(ln) {
+ ln->next= newdataadr(fd, ln->next);
+ ln->prev= prev;
+ prev= ln;
+ ln= ln->next;
+ }
+ lb->last= prev;
+}
+
+static void link_glob_list(FileData *fd, ListBase *lb) /* for glob data */
+{
+ Link *ln, *prev;
+ void *poin;
+
+ if(lb->first==0) return;
+ poin= newdataadr(fd, lb->first);
+ if(lb->first) {
+ oldnewmap_insert(fd->globmap, lb->first, poin, 0);
+ }
+ lb->first= poin;
+
+ ln= lb->first;
+ prev= 0;
+ while(ln) {
+ poin= newdataadr(fd, ln->next);
+ if(ln->next) {
+ oldnewmap_insert(fd->globmap, ln->next, poin, 0);
+ }
+ ln->next= poin;
+ ln->prev= prev;
+ prev= ln;
+ ln= ln->next;
+ }
+ lb->last= prev;
+}
+
+static void test_pointer_array(FileData *fd, void **mat)
+{
+#if defined(WIN32) && !defined(FREE_WINDOWS)
+ __int64 *lpoin, *lmat;
+#else
+ long long *lpoin, *lmat;
+#endif
+ int len, *ipoin, *imat;
+
+ /* manually convert the pointer array in
+ * the old dna format to a pointer array in
+ * the new dna format.
+ */
+ if(*mat) {
+ len= MEM_allocN_len(*mat)/fd->filesdna->pointerlen;
+
+ if(fd->filesdna->pointerlen==8 && fd->memsdna->pointerlen==4) {
+ ipoin=imat= MEM_mallocN( len*4, "newmatar");
+ lpoin= *mat;
+
+ while(len-- > 0) {
+ if((fd->flags & FD_FLAGS_SWITCH_ENDIAN))
+ SWITCH_LONGINT(*lpoin);
+ *ipoin= (int) ((*lpoin) >> 3);
+ ipoin++;
+ lpoin++;
+ }
+ MEM_freeN(*mat);
+ *mat= imat;
+ }
+
+ if(fd->filesdna->pointerlen==4 && fd->memsdna->pointerlen==8) {
+ lpoin=lmat= MEM_mallocN( len*8, "newmatar");
+ ipoin= *mat;
+
+ while(len-- > 0) {
+ *lpoin= *ipoin;
+ ipoin++;
+ lpoin++;
+ }
+ MEM_freeN(*mat);
+ *mat= lmat;
+ }
+ }
+}
+
+/* ************ READ ID Properties *************** */
+
+void IDP_DirectLinkProperty(IDProperty *prop, int switch_endian, void *fd);
+void IDP_LibLinkProperty(IDProperty *prop, int switch_endian, void *fd);
+
+void IDP_DirectLinkArray(IDProperty *prop, int switch_endian, void *fd)
+{
+ int i;
+
+ /*since we didn't save the extra buffer, set totallen to len.*/
+ prop->totallen = prop->len;
+ prop->data.pointer = newdataadr(fd, prop->data.pointer);
+
+ if (switch_endian) {
+ for (i=0; i<prop->len; i++) {
+ SWITCH_INT(((int*)prop->data.pointer)[i]);
+ }
+ }
+}
+
+void IDP_DirectLinkString(IDProperty *prop, int switch_endian, void *fd)
+{
+ /*since we didn't save the extra string buffer, set totallen to len.*/
+ prop->totallen = prop->len;
+ prop->data.pointer = newdataadr(fd, prop->data.pointer);
+}
+
+void IDP_DirectLinkGroup(IDProperty *prop, int switch_endian, void *fd)
+{
+ ListBase *lb = &prop->data.group;
+ IDProperty *loop;
+
+ link_list(fd, lb);
+
+ /*Link child id properties now*/
+ for (loop=prop->data.group.first; loop; loop=loop->next) {
+ IDP_DirectLinkProperty(loop, switch_endian, fd);
+ }
+}
+
+void IDP_DirectLinkProperty(IDProperty *prop, int switch_endian, void *fd)
+{
+ switch (prop->type) {
+ case IDP_GROUP:
+ IDP_DirectLinkGroup(prop, switch_endian, fd);
+ break;
+ case IDP_STRING:
+ IDP_DirectLinkString(prop, switch_endian, fd);
+ break;
+ case IDP_ARRAY:
+ IDP_DirectLinkArray(prop, switch_endian, fd);
+ break;
+ }
+}
+
+/*stub function*/
+void IDP_LibLinkProperty(IDProperty *prop, int switch_endian, void *fd)
+{
+}
+
+/* ************ READ Brush *************** */
+/* library brush linking after fileread */
+static void lib_link_brush(FileData *fd, Main *main)
+{
+ Brush *brush;
+ MTex *mtex;
+ int a;
+
+ /* only link ID pointers */
+ for(brush= main->brush.first; brush; brush= brush->id.next) {
+ if(brush->id.flag & LIB_NEEDLINK) {
+ brush->id.flag -= LIB_NEEDLINK;
+
+ for(a=0; a<MAX_MTEX; a++) {
+ mtex= brush->mtex[a];
+ if(mtex)
+ mtex->tex= newlibadr_us(fd, brush->id.lib, mtex->tex);
+ }
+ }
+ }
+}
+
+static void direct_link_brush(FileData *fd, Brush *brush)
+{
+ /* brush itself has been read */
+ int a;
+
+ for(a=0; a<MAX_MTEX; a++)
+ brush->mtex[a]= newdataadr(fd, brush->mtex[a]);
+}
+
+/* ************ READ CurveMapping *************** */
+
+/* cuma itself has been read! */
+static void direct_link_curvemapping(FileData *fd, CurveMapping *cumap)
+{
+ int a;
+
+ /* flag seems to be able to hang? Maybe old files... not bad to clear anyway */
+ cumap->flag &= ~CUMA_PREMULLED;
+
+ for(a=0; a<CM_TOT; a++) {
+ cumap->cm[a].curve= newdataadr(fd, cumap->cm[a].curve);
+ cumap->cm[a].table= NULL;
+ }
+}
+
+/* ************ READ NODE TREE *************** */
+
+/* singe node tree (also used for material/scene trees), ntree is not NULL */
+static void lib_link_ntree(FileData *fd, ID *id, bNodeTree *ntree)
+{
+ bNode *node;
+
+ for(node= ntree->nodes.first; node; node= node->next)
+ node->id= newlibadr_us(fd, id->lib, node->id);
+}
+
+/* library ntree linking after fileread */
+static void lib_link_nodetree(FileData *fd, Main *main)
+{
+ bNodeTree *ntree;
+
+ /* only link ID pointers */
+ for(ntree= main->nodetree.first; ntree; ntree= ntree->id.next) {
+ if(ntree->id.flag & LIB_NEEDLINK) {
+ ntree->id.flag -= LIB_NEEDLINK;
+ lib_link_ntree(fd, &ntree->id, ntree);
+ }
+ }
+}
+
+/* verify types for nodes and groups, all data has to be read */
+static void lib_verify_nodetree(Main *main)
+{
+ Scene *sce;
+ Material *ma;
+ bNodeTree *ntree;
+
+ /* now create the own typeinfo structs an verify nodes */
+ /* here we still assume no groups in groups */
+ for(ntree= main->nodetree.first; ntree; ntree= ntree->id.next) {
+ ntreeVerifyTypes(ntree); /* internal nodes, no groups! */
+ ntreeMakeOwnType(ntree); /* for group usage */
+ }
+
+ /* now verify all types in material trees, groups are set OK now */
+ for(ma= main->mat.first; ma; ma= ma->id.next) {
+ if(ma->nodetree)
+ ntreeVerifyTypes(ma->nodetree);
+ }
+ /* and scene trees */
+ for(sce= main->scene.first; sce; sce= sce->id.next) {
+ if(sce->nodetree)
+ ntreeVerifyTypes(sce->nodetree);
+ }
+}
+
+
+
+/* ntree itself has been read! */
+static void direct_link_nodetree(FileData *fd, bNodeTree *ntree)
+{
+ /* note: writing and reading goes in sync, for speed */
+ bNode *node;
+ bNodeSocket *sock;
+ bNodeLink *link;
+
+ ntree->init= 0; /* to set callbacks and force setting types */
+ ntree->owntype= NULL;
+ ntree->timecursor= NULL;
+
+ link_list(fd, &ntree->nodes);
+ for(node= ntree->nodes.first; node; node= node->next) {
+ node->storage= newdataadr(fd, node->storage);
+ if(node->storage) {
+
+ /* could be handlerized at some point */
+ if(ntree->type==NTREE_SHADER && (node->type==SH_NODE_CURVE_VEC || node->type==SH_NODE_CURVE_RGB))
+ direct_link_curvemapping(fd, node->storage);
+ else if(ntree->type==NTREE_COMPOSIT) {
+ if( ELEM3(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB))
+ direct_link_curvemapping(fd, node->storage);
+ else if(ELEM3(node->type, CMP_NODE_IMAGE, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER))
+ ((ImageUser *)node->storage)->ok= 1;
+ }
+ }
+ link_list(fd, &node->inputs);
+ link_list(fd, &node->outputs);
+ }
+ link_list(fd, &ntree->links);
+
+ /* and we connect the rest */
+ for(node= ntree->nodes.first; node; node= node->next) {
+ node->preview= newimaadr(fd, node->preview);
+ node->lasty= 0;
+ for(sock= node->inputs.first; sock; sock= sock->next)
+ sock->link= newdataadr(fd, sock->link);
+ for(sock= node->outputs.first; sock; sock= sock->next)
+ sock->ns.data= NULL;
+ }
+ for(link= ntree->links.first; link; link= link->next) {
+ link->fromnode= newdataadr(fd, link->fromnode);
+ link->tonode= newdataadr(fd, link->tonode);
+ link->fromsock= newdataadr(fd, link->fromsock);
+ link->tosock= newdataadr(fd, link->tosock);
+ }
+
+ /* type verification is in lib-link */
+}
+
+/* ************ READ PACKEDFILE *************** */
+
+static PackedFile *direct_link_packedfile(FileData *fd, PackedFile *oldpf)
+{
+ PackedFile *pf= newdataadr(fd, oldpf);
+
+ if (pf) {
+ pf->data= newdataadr(fd, pf->data);
+ }
+
+ return pf;
+}
+
+/* ************ READ IMAGE PREVIEW *************** */
+
+static PreviewImage *direct_link_preview_image(FileData *fd, PreviewImage *old_prv)
+{
+ PreviewImage *prv= newdataadr(fd, old_prv);
+
+ if (prv) {
+ int i;
+ for (i=0; i < PREVIEW_MIPMAPS; ++i) {
+ if (prv->rect[i]) {
+ prv->rect[i] = newdataadr(fd, prv->rect[i]);
+ }
+ }
+ }
+
+ return prv;
+}
+
+/* ************ READ SCRIPTLINK *************** */
+
+static void lib_link_scriptlink(FileData *fd, ID *id, ScriptLink *slink)
+{
+ int i;
+
+ for(i=0; i<slink->totscript; i++) {
+ slink->scripts[i]= newlibadr(fd, id->lib, slink->scripts[i]);
+ }
+}
+
+static void direct_link_scriptlink(FileData *fd, ScriptLink *slink)
+{
+ slink->scripts= newdataadr(fd, slink->scripts);
+ test_pointer_array(fd, (void **)&slink->scripts);
+
+ slink->flag= newdataadr(fd, slink->flag);
+
+ if(fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
+ int a;
+
+ for(a=0; a<slink->totscript; a++) {
+ SWITCH_SHORT(slink->flag[a]);
+ }
+ }
+}
+
+/* ************ READ ARMATURE ***************** */
+
+static void lib_link_nlastrips(FileData *fd, ID *id, ListBase *striplist)
+{
+ bActionStrip *strip;
+ bActionModifier *amod;
+
+ for (strip=striplist->first; strip; strip=strip->next){
+ strip->object = newlibadr(fd, id->lib, strip->object);
+ strip->act = newlibadr_us(fd, id->lib, strip->act);
+ strip->ipo = newlibadr(fd, id->lib, strip->ipo);
+ for(amod= strip->modifiers.first; amod; amod= amod->next)
+ amod->ob= newlibadr(fd, id->lib, amod->ob);
+ }
+}
+
+static void lib_link_constraint_channels(FileData *fd, ID *id, ListBase *chanbase)
+{
+ bConstraintChannel *chan;
+
+ for (chan=chanbase->first; chan; chan=chan->next){
+ chan->ipo = newlibadr_us(fd, id->lib, chan->ipo);
+ }
+}
+
+static void lib_link_constraints(FileData *fd, ID *id, ListBase *conlist)
+{
+ bConstraint *con;
+
+ for (con = conlist->first; con; con=con->next) {
+ /* patch for error introduced by changing constraints (dunno how) */
+ /* if con->data type changes, dna cannot resolve the pointer! (ton) */
+ if(con->data==NULL) {
+ con->type= CONSTRAINT_TYPE_NULL;
+ }
+
+ switch (con->type) {
+ case CONSTRAINT_TYPE_PYTHON:
+ {
+ bPythonConstraint *data= (bPythonConstraint*)con->data;
+ bConstraintTarget *ct;
+
+ for (ct= data->targets.first; ct; ct= ct->next)
+ ct->tar = newlibadr(fd, id->lib, ct->tar);
+
+ data->text = newlibadr(fd, id->lib, data->text);
+ //IDP_LibLinkProperty(data->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ }
+ break;
+ case CONSTRAINT_TYPE_ACTION:
+ {
+ bActionConstraint *data;
+ data= ((bActionConstraint*)con->data);
+ data->tar = newlibadr(fd, id->lib, data->tar);
+ data->act = newlibadr(fd, id->lib, data->act);
+ }
+ break;
+ case CONSTRAINT_TYPE_LOCLIKE:
+ {
+ bLocateLikeConstraint *data;
+ data= ((bLocateLikeConstraint*)con->data);
+ data->tar = newlibadr(fd, id->lib, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_ROTLIKE:
+ {
+ bRotateLikeConstraint *data;
+ data= ((bRotateLikeConstraint*)con->data);
+ data->tar = newlibadr(fd, id->lib, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_SIZELIKE:
+ {
+ bSizeLikeConstraint *data;
+ data= ((bSizeLikeConstraint*)con->data);
+ data->tar = newlibadr(fd, id->lib, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_KINEMATIC:
+ {
+ bKinematicConstraint *data;
+ data = ((bKinematicConstraint*)con->data);
+ data->tar = newlibadr(fd, id->lib, data->tar);
+ data->poletar = newlibadr(fd, id->lib, data->poletar);
+ }
+ break;
+ case CONSTRAINT_TYPE_TRACKTO:
+ {
+ bTrackToConstraint *data;
+ data = ((bTrackToConstraint*)con->data);
+ data->tar = newlibadr(fd, id->lib, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_MINMAX:
+ {
+ bMinMaxConstraint *data;
+ data = ((bMinMaxConstraint*)con->data);
+ data->tar = newlibadr(fd, id->lib, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_LOCKTRACK:
+ {
+ bLockTrackConstraint *data;
+ data= ((bLockTrackConstraint*)con->data);
+ data->tar = newlibadr(fd, id->lib, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_FOLLOWPATH:
+ {
+ bFollowPathConstraint *data;
+ data= ((bFollowPathConstraint*)con->data);
+ data->tar = newlibadr(fd, id->lib, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_STRETCHTO:
+ {
+ bStretchToConstraint *data;
+ data= ((bStretchToConstraint*)con->data);
+ data->tar = newlibadr(fd, id->lib, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_RIGIDBODYJOINT:
+ {
+ bRigidBodyJointConstraint *data;
+ data= ((bRigidBodyJointConstraint*)con->data);
+ data->tar = newlibadr(fd, id->lib, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_CLAMPTO:
+ {
+ bClampToConstraint *data;
+ data= ((bClampToConstraint*)con->data);
+ data->tar = newlibadr(fd, id->lib, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_CHILDOF:
+ {
+ bChildOfConstraint *data;
+ data= ((bChildOfConstraint*)con->data);
+ data->tar = newlibadr(fd, id->lib, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_TRANSFORM:
+ {
+ bTransformConstraint *data;
+ data= ((bTransformConstraint*)con->data);
+ data->tar = newlibadr(fd, id->lib, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_NULL:
+ break;
+ }
+ }
+}
+
+static void direct_link_constraints(FileData *fd, ListBase *lb)
+{
+ bConstraint *cons;
+
+ link_list(fd, lb);
+ for (cons=lb->first; cons; cons=cons->next) {
+ cons->data = newdataadr(fd, cons->data);
+ if (cons->type == CONSTRAINT_TYPE_PYTHON) {
+ bPythonConstraint *data= cons->data;
+ link_list(fd, &data->targets);
+ data->prop = newdataadr(fd, data->prop);
+ IDP_DirectLinkProperty(data->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ }
+ }
+}
+
+static void lib_link_pose(FileData *fd, Object *ob, bPose *pose)
+{
+ bPoseChannel *pchan;
+ bArmature *arm= ob->data;
+ int rebuild;
+
+ if (!pose || !arm)
+ return;
+
+ /* always rebuild to match proxy or lib changes */
+ rebuild= ob->proxy || (ob->id.lib==NULL && arm->id.lib);
+
+ for (pchan = pose->chanbase.first; pchan; pchan=pchan->next) {
+ lib_link_constraints(fd, (ID *)ob, &pchan->constraints);
+
+ /* hurms... loop in a loop, but yah... later... (ton) */
+ pchan->bone= get_named_bone(arm, pchan->name);
+
+ pchan->custom= newlibadr(fd, arm->id.lib, pchan->custom);
+ if(pchan->bone==NULL)
+ rebuild= 1;
+ else if(ob->id.lib==NULL && arm->id.lib) {
+ /* local pose selection copied to armature, bit hackish */
+ pchan->bone->flag &= ~(BONE_SELECTED|BONE_ACTIVE);
+ pchan->bone->flag |= pchan->selectflag;
+ }
+ }
+
+ if(rebuild) {
+ ob->recalc= OB_RECALC;
+ pose->flag |= POSE_RECALC;
+ }
+}
+
+static void lib_link_armature(FileData *fd, Main *main)
+{
+ bArmature *arm;
+
+ arm= main->armature.first;
+
+ while(arm) {
+ if(arm->id.flag & LIB_NEEDLINK) {
+ arm->id.flag -= LIB_NEEDLINK;
+ }
+ arm= arm->id.next;
+ }
+}
+
+static void lib_link_action(FileData *fd, Main *main)
+{
+ bAction *act;
+ bActionChannel *chan;
+
+ act= main->action.first;
+ while(act) {
+ if(act->id.flag & LIB_NEEDLINK) {
+ act->id.flag -= LIB_NEEDLINK;
+
+ for (chan=act->chanbase.first; chan; chan=chan->next) {
+ chan->ipo= newlibadr_us(fd, act->id.lib, chan->ipo);
+ lib_link_constraint_channels(fd, &act->id, &chan->constraintChannels);
+ }
+
+ }
+ act= act->id.next;
+ }
+}
+
+static void direct_link_bones(FileData *fd, Bone* bone)
+{
+ Bone *child;
+
+ bone->parent= newdataadr(fd, bone->parent);
+
+ link_list(fd, &bone->childbase);
+
+ for (child=bone->childbase.first; child; child=child->next) {
+ direct_link_bones(fd, child);
+ }
+}
+
+
+static void direct_link_action(FileData *fd, bAction *act)
+{
+ bActionChannel *achan;
+
+ link_list(fd, &act->chanbase);
+
+ for (achan = act->chanbase.first; achan; achan=achan->next)
+ link_list(fd, &achan->constraintChannels);
+
+}
+
+static void direct_link_armature(FileData *fd, bArmature *arm)
+{
+ Bone *bone;
+
+ link_list(fd, &arm->bonebase);
+
+ bone=arm->bonebase.first;
+ while (bone) {
+ direct_link_bones(fd, bone);
+ bone=bone->next;
+ }
+}
+
+/* ************ READ CAMERA ***************** */
+
+static void lib_link_camera(FileData *fd, Main *main)
+{
+ Camera *ca;
+
+ ca= main->camera.first;
+ while(ca) {
+ if(ca->id.flag & LIB_NEEDLINK) {
+
+ ca->ipo= newlibadr_us(fd, ca->id.lib, ca->ipo);
+
+ ca->dof_ob= newlibadr_us(fd, ca->id.lib, ca->dof_ob);
+
+ lib_link_scriptlink(fd, &ca->id, &ca->scriptlink);
+
+ ca->id.flag -= LIB_NEEDLINK;
+ }
+ ca= ca->id.next;
+ }
+}
+
+static void direct_link_camera(FileData *fd, Camera *ca)
+{
+ direct_link_scriptlink(fd, &ca->scriptlink);
+}
+
+
+/* ************ READ LAMP ***************** */
+
+static void lib_link_lamp(FileData *fd, Main *main)
+{
+ Lamp *la;
+ MTex *mtex;
+ int a;
+
+ la= main->lamp.first;
+ while(la) {
+ if(la->id.flag & LIB_NEEDLINK) {
+
+ for(a=0; a<MAX_MTEX; a++) {
+ mtex= la->mtex[a];
+ if(mtex) {
+ mtex->tex= newlibadr_us(fd, la->id.lib, mtex->tex);
+ mtex->object= newlibadr(fd, la->id.lib, mtex->object);
+ }
+ }
+
+ la->ipo= newlibadr_us(fd, la->id.lib, la->ipo);
+
+ lib_link_scriptlink(fd, &la->id, &la->scriptlink);
+
+ la->id.flag -= LIB_NEEDLINK;
+ }
+ la= la->id.next;
+ }
+}
+
+static void direct_link_lamp(FileData *fd, Lamp *la)
+{
+ int a;
+
+ direct_link_scriptlink(fd, &la->scriptlink);
+
+ for(a=0; a<MAX_MTEX; a++) {
+ la->mtex[a]= newdataadr(fd, la->mtex[a]);
+ }
+
+ la->curfalloff= newdataadr(fd, la->curfalloff);
+ if(la->curfalloff)
+ direct_link_curvemapping(fd, la->curfalloff);
+
+ la->preview = direct_link_preview_image(fd, la->preview);
+}
+
+/* ************ READ keys ***************** */
+
+static void lib_link_key(FileData *fd, Main *main)
+{
+ Key *key;
+
+ key= main->key.first;
+ while(key) {
+ if(key->id.flag & LIB_NEEDLINK) {
+
+ key->ipo= newlibadr_us(fd, key->id.lib, key->ipo);
+ key->from= newlibadr(fd, key->id.lib, key->from);
+
+ key->id.flag -= LIB_NEEDLINK;
+ }
+ key= key->id.next;
+ }
+}
+
+static void switch_endian_keyblock(Key *key, KeyBlock *kb)
+{
+ int elemsize, a, b;
+ char *data, *poin, *cp;
+
+ elemsize= key->elemsize;
+ data= kb->data;
+
+ for(a=0; a<kb->totelem; a++) {
+
+ cp= key->elemstr;
+ poin= data;
+
+ while( cp[0] ) { /* cp[0]==amount */
+
+ switch(cp[1]) { /* cp[1]= type */
+ case IPO_FLOAT:
+ case IPO_BPOINT:
+ case IPO_BEZTRIPLE:
+ b= cp[0];
+ while(b--) {
+ SWITCH_INT((*poin));
+ poin+= 4;
+ }
+ break;
+ }
+
+ cp+= 2;
+
+ }
+ data+= elemsize;
+ }
+}
+
+static void direct_link_key(FileData *fd, Key *key)
+{
+ KeyBlock *kb;
+
+ link_list(fd, &(key->block));
+
+ key->refkey= newdataadr(fd, key->refkey);
+
+ kb= key->block.first;
+ while(kb) {
+
+ kb->data= newdataadr(fd, kb->data);
+
+ if(fd->flags & FD_FLAGS_SWITCH_ENDIAN)
+ switch_endian_keyblock(key, kb);
+
+ kb= kb->next;
+ }
+}
+
+/* ************ READ mball ***************** */
+
+static void lib_link_mball(FileData *fd, Main *main)
+{
+ MetaBall *mb;
+ int a;
+
+ mb= main->mball.first;
+ while(mb) {
+ if(mb->id.flag & LIB_NEEDLINK) {
+
+ for(a=0; a<mb->totcol; a++) mb->mat[a]= newlibadr_us(fd, mb->id.lib, mb->mat[a]);
+
+ mb->ipo= newlibadr_us(fd, mb->id.lib, mb->ipo);
+
+ mb->id.flag -= LIB_NEEDLINK;
+ }
+ mb= mb->id.next;
+ }
+}
+
+static void direct_link_mball(FileData *fd, MetaBall *mb)
+{
+ mb->mat= newdataadr(fd, mb->mat);
+ test_pointer_array(fd, (void **)&mb->mat);
+
+ link_list(fd, &(mb->elems));
+
+ mb->disp.first= mb->disp.last= 0;
+
+ mb->bb= 0;
+}
+
+/* ************ READ WORLD ***************** */
+
+static void lib_link_world(FileData *fd, Main *main)
+{
+ World *wrld;
+ MTex *mtex;
+ int a;
+
+ wrld= main->world.first;
+ while(wrld) {
+ if(wrld->id.flag & LIB_NEEDLINK) {
+
+ wrld->ipo= newlibadr_us(fd, wrld->id.lib, wrld->ipo);
+
+ for(a=0; a<MAX_MTEX; a++) {
+ mtex= wrld->mtex[a];
+ if(mtex) {
+ mtex->tex= newlibadr_us(fd, wrld->id.lib, mtex->tex);
+ mtex->object= newlibadr(fd, wrld->id.lib, mtex->object);
+ }
+ }
+
+ lib_link_scriptlink(fd, &wrld->id, &wrld->scriptlink);
+
+ wrld->id.flag -= LIB_NEEDLINK;
+ }
+ wrld= wrld->id.next;
+ }
+}
+
+static void direct_link_world(FileData *fd, World *wrld)
+{
+ int a;
+
+ direct_link_scriptlink(fd, &wrld->scriptlink);
+
+ for(a=0; a<MAX_MTEX; a++) {
+ wrld->mtex[a]= newdataadr(fd, wrld->mtex[a]);
+ }
+ wrld->preview = direct_link_preview_image(fd, wrld->preview);
+}
+
+
+/* ************ READ IPO ***************** */
+
+static void lib_link_ipo(FileData *fd, Main *main)
+{
+ Ipo *ipo;
+
+ ipo= main->ipo.first;
+ while(ipo) {
+ if(ipo->id.flag & LIB_NEEDLINK) {
+ IpoCurve *icu;
+ for(icu= ipo->curve.first; icu; icu= icu->next) {
+ if(icu->driver)
+ icu->driver->ob= newlibadr(fd, ipo->id.lib, icu->driver->ob);
+ }
+ ipo->id.flag -= LIB_NEEDLINK;
+ }
+ ipo= ipo->id.next;
+ }
+}
+
+static void direct_link_ipo(FileData *fd, Ipo *ipo)
+{
+ IpoCurve *icu;
+
+ link_list(fd, &(ipo->curve));
+ icu= ipo->curve.first;
+ while(icu) {
+ icu->bezt= newdataadr(fd, icu->bezt);
+ icu->bp= newdataadr(fd, icu->bp);
+ icu->driver= newdataadr(fd, icu->driver);
+ icu= icu->next;
+ }
+}
+
+/* ************ READ VFONT ***************** */
+
+static void lib_link_vfont(FileData *fd, Main *main)
+{
+ VFont *vf;
+
+ vf= main->vfont.first;
+ while(vf) {
+ if(vf->id.flag & LIB_NEEDLINK) {
+ vf->id.flag -= LIB_NEEDLINK;
+ }
+ vf= vf->id.next;
+ }
+}
+
+static void direct_link_vfont(FileData *fd, VFont *vf)
+{
+ vf->data= NULL;
+ vf->packedfile= direct_link_packedfile(fd, vf->packedfile);
+}
+
+/* ************ READ TEXT ****************** */
+
+static void lib_link_text(FileData *fd, Main *main)
+{
+ Text *text;
+
+ text= main->text.first;
+ while(text) {
+ if(text->id.flag & LIB_NEEDLINK) {
+ text->id.flag -= LIB_NEEDLINK;
+ }
+ text= text->id.next;
+ }
+}
+
+static void direct_link_text(FileData *fd, Text *text)
+{
+ TextLine *ln;
+
+ text->name= newdataadr(fd, text->name);
+
+ text->undo_pos= -1;
+ text->undo_len= TXT_INIT_UNDO;
+ text->undo_buf= MEM_mallocN(text->undo_len, "undo buf");
+
+ text->compiled= NULL;
+
+/*
+ if(text->flags & TXT_ISEXT) {
+ reopen_text(text);
+ } else {
+*/
+
+ link_list(fd, &text->lines);
+
+ text->curl= newdataadr(fd, text->curl);
+ text->sell= newdataadr(fd, text->sell);
+
+ ln= text->lines.first;
+ while(ln) {
+ ln->line= newdataadr(fd, ln->line);
+ ln->format= NULL;
+
+ if (ln->len != (int) strlen(ln->line)) {
+ printf("Error loading text, line lengths differ\n");
+ ln->len = strlen(ln->line);
+ }
+
+ ln= ln->next;
+ }
+
+ text->flags = (text->flags|TXT_ISTMP) & ~TXT_ISEXT;
+
+ text->id.us= 1;
+}
+
+/* ************ READ IMAGE ***************** */
+
+static void lib_link_image(FileData *fd, Main *main)
+{
+ Image *ima;
+
+ ima= main->image.first;
+ while (ima) {
+ if(ima->id.flag & LIB_NEEDLINK) {
+ if (ima->id.properties) IDP_LibLinkProperty(ima->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+
+ ima->id.flag -= LIB_NEEDLINK;
+ }
+ ima= ima->id.next;
+ }
+}
+
+static void link_ibuf_list(FileData *fd, ListBase *lb)
+{
+ Link *ln, *prev;
+
+ if(lb->first==NULL) return;
+
+ lb->first= newimaadr(fd, lb->first);
+ ln= lb->first;
+ prev= NULL;
+ while(ln) {
+ ln->next= newimaadr(fd, ln->next);
+ ln->prev= prev;
+ prev= ln;
+ ln= ln->next;
+ }
+ lb->last= prev;
+}
+
+static void direct_link_image(FileData *fd, Image *ima)
+{
+ /* for undo system, pointers could be restored */
+ if(fd->imamap)
+ link_ibuf_list(fd, &ima->ibufs);
+ else
+ ima->ibufs.first= ima->ibufs.last= NULL;
+
+ /* if not restored, we keep the binded opengl index */
+ if(ima->ibufs.first==NULL)
+ ima->bindcode= 0;
+
+ ima->anim= NULL;
+ ima->rr= NULL;
+ ima->repbind= NULL;
+
+ ima->packedfile = direct_link_packedfile(fd, ima->packedfile);
+ ima->preview = direct_link_preview_image(fd, ima->preview);
+ ima->ok= 1;
+}
+
+
+/* ************ READ CURVE ***************** */
+
+static void lib_link_curve(FileData *fd, Main *main)
+{
+ Curve *cu;
+ int a;
+
+ cu= main->curve.first;
+ while(cu) {
+ if(cu->id.flag & LIB_NEEDLINK) {
+
+ for(a=0; a<cu->totcol; a++) cu->mat[a]= newlibadr_us(fd, cu->id.lib, cu->mat[a]);
+
+ cu->bevobj= newlibadr(fd, cu->id.lib, cu->bevobj);
+ cu->taperobj= newlibadr(fd, cu->id.lib, cu->taperobj);
+ cu->textoncurve= newlibadr(fd, cu->id.lib, cu->textoncurve);
+ cu->vfont= newlibadr_us(fd, cu->id.lib, cu->vfont);
+ cu->vfontb= newlibadr_us(fd, cu->id.lib, cu->vfontb);
+ cu->vfonti= newlibadr_us(fd, cu->id.lib, cu->vfonti);
+ cu->vfontbi= newlibadr_us(fd, cu->id.lib, cu->vfontbi);
+
+ cu->ipo= newlibadr_us(fd, cu->id.lib, cu->ipo);
+ cu->key= newlibadr_us(fd, cu->id.lib, cu->key);
+
+ cu->id.flag -= LIB_NEEDLINK;
+ }
+ cu= cu->id.next;
+ }
+}
+
+
+static void switch_endian_knots(Nurb *nu)
+{
+ int len;
+
+ if(nu->knotsu) {
+ len= KNOTSU(nu);
+ while(len--) {
+ SWITCH_INT(nu->knotsu[len]);
+ }
+ }
+ if(nu->knotsv) {
+ len= KNOTSV(nu);
+ while(len--) {
+ SWITCH_INT(nu->knotsv[len]);
+ }
+ }
+}
+
+static void direct_link_curve(FileData *fd, Curve *cu)
+{
+ Nurb *nu;
+ TextBox *tb;
+
+ cu->mat= newdataadr(fd, cu->mat);
+ test_pointer_array(fd, (void **)&cu->mat);
+ cu->str= newdataadr(fd, cu->str);
+ cu->strinfo= newdataadr(fd, cu->strinfo);
+ cu->tb= newdataadr(fd, cu->tb);
+
+ if(cu->vfont==0) link_list(fd, &(cu->nurb));
+ else {
+ cu->nurb.first=cu->nurb.last= 0;
+
+ tb= MEM_callocN(MAXTEXTBOX*sizeof(TextBox), "TextBoxread");
+ if (cu->tb) {
+ memcpy(tb, cu->tb, cu->totbox*sizeof(TextBox));
+ MEM_freeN(cu->tb);
+ cu->tb= tb;
+ } else {
+ cu->totbox = 1;
+ cu->actbox = 1;
+ cu->tb = tb;
+ cu->tb[0].w = cu->linewidth;
+ }
+ if (cu->wordspace == 0.0) cu->wordspace = 1.0;
+ }
+
+ cu->bev.first=cu->bev.last= 0;
+ cu->disp.first=cu->disp.last= 0;
+ cu->path= 0;
+
+ nu= cu->nurb.first;
+ while(nu) {
+ nu->bezt= newdataadr(fd, nu->bezt);
+ nu->bp= newdataadr(fd, nu->bp);
+ nu->knotsu= newdataadr(fd, nu->knotsu);
+ nu->knotsv= newdataadr(fd, nu->knotsv);
+ if (cu->vfont==0) nu->charidx= nu->mat_nr;
+
+ if(fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
+ switch_endian_knots(nu);
+ }
+
+ nu= nu->next;
+ }
+ cu->bb= NULL;
+}
+
+/* ************ READ TEX ***************** */
+
+static void lib_link_texture(FileData *fd, Main *main)
+{
+ Tex *tex;
+
+ tex= main->tex.first;
+ while(tex) {
+ if(tex->id.flag & LIB_NEEDLINK) {
+
+ tex->ima= newlibadr_us(fd, tex->id.lib, tex->ima);
+ tex->ipo= newlibadr_us(fd, tex->id.lib, tex->ipo);
+ if(tex->env) tex->env->object= newlibadr(fd, tex->id.lib, tex->env->object);
+
+ tex->id.flag -= LIB_NEEDLINK;
+ }
+ tex= tex->id.next;
+ }
+}
+
+static void direct_link_texture(FileData *fd, Tex *tex)
+{
+ tex->plugin= newdataadr(fd, tex->plugin);
+ if(tex->plugin) {
+ tex->plugin->handle= 0;
+ open_plugin_tex(tex->plugin);
+ /* initialize data for this instance, if an initialization
+ * function exists.
+ */
+ if (tex->plugin->instance_init)
+ tex->plugin->instance_init((void *) tex->plugin->data);
+ }
+ tex->coba= newdataadr(fd, tex->coba);
+ tex->env= newdataadr(fd, tex->env);
+ if(tex->env) {
+ tex->env->ima= NULL;
+ memset(tex->env->cube, 0, 6*sizeof(void *));
+ tex->env->ok= 0;
+ }
+ tex->preview = direct_link_preview_image(fd, tex->preview);
+
+ tex->iuser.ok= 1;
+}
+
+
+
+/* ************ READ MATERIAL ***************** */
+
+static void lib_link_material(FileData *fd, Main *main)
+{
+ Material *ma;
+ MTex *mtex;
+ int a;
+
+ ma= main->mat.first;
+ while(ma) {
+ if(ma->id.flag & LIB_NEEDLINK) {
+ /*Link ID Properties -- and copy this comment EXACTLY for easy finding
+ of library blocks that implement this.*/
+ if (ma->id.properties) IDP_LibLinkProperty(ma->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+
+ ma->ipo= newlibadr_us(fd, ma->id.lib, ma->ipo);
+ ma->group= newlibadr_us(fd, ma->id.lib, ma->group);
+
+ for(a=0; a<MAX_MTEX; a++) {
+ mtex= ma->mtex[a];
+ if(mtex) {
+ mtex->tex= newlibadr_us(fd, ma->id.lib, mtex->tex);
+ mtex->object= newlibadr(fd, ma->id.lib, mtex->object);
+ }
+ }
+ lib_link_scriptlink(fd, &ma->id, &ma->scriptlink);
+
+ if(ma->nodetree)
+ lib_link_ntree(fd, &ma->id, ma->nodetree);
+
+ ma->id.flag -= LIB_NEEDLINK;
+ }
+ ma= ma->id.next;
+ }
+}
+
+static void direct_link_material(FileData *fd, Material *ma)
+{
+ int a;
+
+ for(a=0; a<MAX_MTEX; a++) {
+ ma->mtex[a]= newdataadr(fd, ma->mtex[a]);
+ }
+
+ ma->ramp_col= newdataadr(fd, ma->ramp_col);
+ ma->ramp_spec= newdataadr(fd, ma->ramp_spec);
+
+ direct_link_scriptlink(fd, &ma->scriptlink);
+
+ ma->nodetree= newdataadr(fd, ma->nodetree);
+ if(ma->nodetree)
+ direct_link_nodetree(fd, ma->nodetree);
+
+ ma->preview = direct_link_preview_image(fd, ma->preview);
+}
+
+/* ************ READ MESH ***************** */
+
+static void lib_link_mtface(FileData *fd, Mesh *me, MTFace *mtface, int totface)
+{
+ MTFace *tf= mtface;
+ int i;
+
+ for (i=0; i<totface; i++, tf++) {
+ tf->tpage= newlibadr(fd, me->id.lib, tf->tpage);
+ if(tf->tpage && tf->tpage->id.us==0)
+ tf->tpage->id.us= 1;
+ }
+}
+
+static void lib_link_customdata_mtface(FileData *fd, Mesh *me, CustomData *fdata, int totface)
+{
+ int i;
+ for(i=0; i<fdata->totlayer; i++) {
+ CustomDataLayer *layer = &fdata->layers[i];
+
+ if(layer->type == CD_MTFACE)
+ lib_link_mtface(fd, me, layer->data, totface);
+ }
+
+}
+
+static void lib_link_mesh(FileData *fd, Main *main)
+{
+ Mesh *me;
+
+ me= main->mesh.first;
+ while(me) {
+ if(me->id.flag & LIB_NEEDLINK) {
+ int i;
+
+ /*Link ID Properties -- and copy this comment EXACTLY for easy finding
+ of library blocks that implement this.*/
+ if (me->id.properties) IDP_LibLinkProperty(me->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+
+ /* this check added for python created meshes */
+ if(me->mat) {
+ for(i=0; i<me->totcol; i++) {
+ me->mat[i]= newlibadr_us(fd, me->id.lib, me->mat[i]);
+ }
+ }
+ else me->totcol= 0;
+
+ me->ipo= newlibadr_us(fd, me->id.lib, me->ipo);
+ me->key= newlibadr_us(fd, me->id.lib, me->key);
+ me->texcomesh= newlibadr_us(fd, me->id.lib, me->texcomesh);
+
+ lib_link_customdata_mtface(fd, me, &me->fdata, me->totface);
+ if(me->mr && me->mr->levels.first)
+ lib_link_customdata_mtface(fd, me, &me->mr->fdata,
+ ((MultiresLevel*)me->mr->levels.first)->totface);
+
+ me->id.flag -= LIB_NEEDLINK;
+ }
+ me= me->id.next;
+ }
+}
+
+static void direct_link_dverts(FileData *fd, int count, MDeformVert *mdverts)
+{
+ int i;
+
+ if (!mdverts)
+ return;
+
+ for (i=0; i<count; i++) {
+ mdverts[i].dw=newdataadr(fd, mdverts[i].dw);
+ if (!mdverts[i].dw)
+ mdverts[i].totweight=0;
+ }
+}
+
+static void direct_link_customdata(FileData *fd, CustomData *data, int count)
+{
+ int i = 0;
+
+ data->layers= newdataadr(fd, data->layers);
+
+ while (i < data->totlayer) {
+ CustomDataLayer *layer = &data->layers[i];
+
+ if (CustomData_verify_versions(data, i)) {
+ layer->data = newdataadr(fd, layer->data);
+ i++;
+ }
+ }
+}
+
+static void direct_link_mesh(FileData *fd, Mesh *mesh)
+{
+ mesh->mat= newdataadr(fd, mesh->mat);
+ test_pointer_array(fd, (void **)&mesh->mat);
+
+ mesh->mvert= newdataadr(fd, mesh->mvert);
+ mesh->medge= newdataadr(fd, mesh->medge);
+ mesh->mface= newdataadr(fd, mesh->mface);
+ mesh->tface= newdataadr(fd, mesh->tface);
+ mesh->mtface= newdataadr(fd, mesh->mtface);
+ mesh->mcol= newdataadr(fd, mesh->mcol);
+ mesh->msticky= newdataadr(fd, mesh->msticky);
+ mesh->dvert= newdataadr(fd, mesh->dvert);
+
+ /* Partial-mesh visibility (do this before using totvert, totface, or totedge!) */
+ mesh->pv= newdataadr(fd, mesh->pv);
+ if(mesh->pv) {
+ mesh->pv->vert_map= newdataadr(fd, mesh->pv->vert_map);
+ mesh->pv->edge_map= newdataadr(fd, mesh->pv->edge_map);
+ mesh->pv->old_faces= newdataadr(fd, mesh->pv->old_faces);
+ mesh->pv->old_edges= newdataadr(fd, mesh->pv->old_edges);
+ }
+
+ /* normally direct_link_dverts should be called in direct_link_customdata,
+ but for backwards compat in do_versions to work we do it here */
+ direct_link_dverts(fd, mesh->pv ? mesh->pv->totvert : mesh->totvert, mesh->dvert);
+
+ direct_link_customdata(fd, &mesh->vdata, mesh->pv ? mesh->pv->totvert : mesh->totvert);
+ direct_link_customdata(fd, &mesh->edata, mesh->pv ? mesh->pv->totedge : mesh->totedge);
+ direct_link_customdata(fd, &mesh->fdata, mesh->pv ? mesh->pv->totface : mesh->totface);
+
+ mesh->bb= NULL;
+ mesh->mselect = NULL;
+
+ /* Multires data */
+ mesh->mr= newdataadr(fd, mesh->mr);
+ if(mesh->mr) {
+ MultiresLevel *lvl;
+
+ link_list(fd, &mesh->mr->levels);
+ lvl= mesh->mr->levels.first;
+
+ direct_link_customdata(fd, &mesh->mr->vdata, lvl->totvert);
+ direct_link_dverts(fd, lvl->totvert, CustomData_get(&mesh->mr->vdata, 0, CD_MDEFORMVERT));
+ direct_link_customdata(fd, &mesh->mr->fdata, lvl->totface);
+
+ if(mesh->mr->edge_flags)
+ mesh->mr->edge_flags= newdataadr(fd, mesh->mr->edge_flags);
+ if(mesh->mr->edge_creases)
+ mesh->mr->edge_creases= newdataadr(fd, mesh->mr->edge_creases);
+
+ if(!mesh->mr->edge_flags)
+ mesh->mr->edge_flags= MEM_callocN(sizeof(short)*lvl->totedge, "Multires Edge Flags");
+ if(!mesh->mr->edge_creases)
+ mesh->mr->edge_creases= MEM_callocN(sizeof(char)*lvl->totedge, "Multires Edge Creases");
+
+ mesh->mr->verts = newdataadr(fd, mesh->mr->verts);
+
+ for(; lvl; lvl= lvl->next) {
+ lvl->verts= newdataadr(fd, lvl->verts);
+ lvl->faces= newdataadr(fd, lvl->faces);
+ lvl->edges= newdataadr(fd, lvl->edges);
+ lvl->colfaces= newdataadr(fd, lvl->colfaces);
+ lvl->edge_boundary_states= NULL;
+ lvl->vert_face_map = lvl->vert_edge_map = NULL;
+ lvl->map_mem= NULL;
+ }
+ }
+
+ if((fd->flags & FD_FLAGS_SWITCH_ENDIAN) && mesh->tface) {
+ TFace *tf= mesh->tface;
+ int i;
+
+ for (i=0; i< (mesh->pv ? mesh->pv->totface : mesh->totface); i++, tf++) {
+ SWITCH_INT(tf->col[0]);
+ SWITCH_INT(tf->col[1]);
+ SWITCH_INT(tf->col[2]);
+ SWITCH_INT(tf->col[3]);
+ }
+ }
+}
+
+/* ************ READ LATTICE ***************** */
+
+static void lib_link_latt(FileData *fd, Main *main)
+{
+ Lattice *lt;
+
+ lt= main->latt.first;
+ while(lt) {
+ if(lt->id.flag & LIB_NEEDLINK) {
+
+ lt->ipo= newlibadr_us(fd, lt->id.lib, lt->ipo);
+ lt->key= newlibadr_us(fd, lt->id.lib, lt->key);
+
+ lt->id.flag -= LIB_NEEDLINK;
+ }
+ lt= lt->id.next;
+ }
+}
+
+static void direct_link_latt(FileData *fd, Lattice *lt)
+{
+ lt->def= newdataadr(fd, lt->def);
+
+ lt->dvert= newdataadr(fd, lt->dvert);
+ direct_link_dverts(fd, lt->pntsu*lt->pntsv*lt->pntsw, lt->dvert);
+}
+
+
+/* ************ READ OBJECT ***************** */
+
+static void lib_link_modifiers__linkModifiers(void *userData, Object *ob,
+ ID **idpoin)
+{
+ FileData *fd = userData;
+
+ *idpoin = newlibadr(fd, ob->id.lib, *idpoin);
+ /* hardcoded bad exception; non-object modifier data gets user count (texture, displace) */
+ if(*idpoin && GS((*idpoin)->name)!=ID_OB)
+ (*idpoin)->us++;
+}
+static void lib_link_modifiers(FileData *fd, Object *ob)
+{
+ modifiers_foreachIDLink(ob, lib_link_modifiers__linkModifiers, fd);
+}
+
+static void lib_link_object(FileData *fd, Main *main)
+{
+ Object *ob;
+ PartEff *paf;
+ bSensor *sens;
+ bController *cont;
+ bActuator *act;
+ void *poin;
+ int warn=0, a;
+
+ ob= main->object.first;
+ while(ob) {
+ if(ob->id.flag & LIB_NEEDLINK) {
+ if (ob->id.properties) IDP_LibLinkProperty(ob->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+
+ ob->parent= newlibadr(fd, ob->id.lib, ob->parent);
+ ob->track= newlibadr(fd, ob->id.lib, ob->track);
+ ob->ipo= newlibadr_us(fd, ob->id.lib, ob->ipo);
+ ob->action = newlibadr_us(fd, ob->id.lib, ob->action);
+ ob->dup_group= newlibadr_us(fd, ob->id.lib, ob->dup_group);
+
+ ob->proxy= newlibadr_us(fd, ob->id.lib, ob->proxy);
+ if(ob->proxy) {
+ /* paranoia check, actually a proxy_from pointer should never be written... */
+ if(ob->proxy->id.lib==NULL) {
+ ob->proxy->proxy_from= NULL;
+ ob->proxy= NULL;
+ }
+ else {
+ /* this triggers object_update to always use a copy */
+ ob->proxy->proxy_from= ob;
+ /* force proxy updates after load/undo, a bit weak */
+ ob->recalc= ob->proxy->recalc= OB_RECALC;
+ }
+ }
+ ob->proxy_group= newlibadr(fd, ob->id.lib, ob->proxy_group);
+
+ poin= ob->data;
+ ob->data= newlibadr_us(fd, ob->id.lib, ob->data);
+
+ if(ob->data==NULL && poin!=NULL) {
+ ob->type= OB_EMPTY;
+ warn= 1;
+ if(ob->id.lib) printf("Can't find obdata of %s lib %s\n", ob->id.name+2, ob->id.lib->name);
+ else printf("Object %s lost data.", ob->id.name+2);
+
+ if(ob->pose) {
+ free_pose_channels(ob->pose);
+ MEM_freeN(ob->pose);
+ ob->pose= NULL;
+ ob->flag &= ~OB_POSEMODE;
+ }
+ }
+ for(a=0; a<ob->totcol; a++) ob->mat[a]= newlibadr_us(fd, ob->id.lib, ob->mat[a]);
+
+ ob->id.flag -= LIB_NEEDLINK;
+ /* if id.us==0 a new base will be created later on */
+
+ /* WARNING! Also check expand_object(), should reflect the stuff below. */
+ lib_link_pose(fd, ob, ob->pose);
+ lib_link_constraints(fd, &ob->id, &ob->constraints);
+ lib_link_nlastrips(fd, &ob->id, &ob->nlastrips);
+ lib_link_constraint_channels(fd, &ob->id, &ob->constraintChannels);
+
+ for(paf= ob->effect.first; paf; paf= paf->next) {
+ if(paf->type==EFF_PARTICLE) {
+ paf->group= newlibadr_us(fd, ob->id.lib, paf->group);
+ }
+ }
+
+ sens= ob->sensors.first;
+ while(sens) {
+ if(ob->id.lib==NULL) { // done in expand_main
+ for(a=0; a<sens->totlinks; a++) {
+ sens->links[a]= newglobadr(fd, sens->links[a]);
+ }
+ }
+ if(sens->type==SENS_TOUCH) {
+ bTouchSensor *ts= sens->data;
+ ts->ma= newlibadr(fd, ob->id.lib, ts->ma);
+ }
+ else if(sens->type==SENS_MESSAGE) {
+ bMessageSensor *ms= sens->data;
+ ms->fromObject=
+ newlibadr(fd, ob->id.lib, ms->fromObject);
+ }
+ sens= sens->next;
+ }
+
+ cont= ob->controllers.first;
+ while(cont) {
+ if(ob->id.lib==NULL) { // done in expand_main
+ for(a=0; a<cont->totlinks; a++) {
+ cont->links[a]= newglobadr(fd, cont->links[a]);
+ }
+ }
+ if(cont->type==CONT_PYTHON) {
+ bPythonCont *pc= cont->data;
+ pc->text= newlibadr(fd, ob->id.lib, pc->text);
+ }
+ cont->slinks= NULL;
+ cont->totslinks= 0;
+
+ cont= cont->next;
+ }
+
+ act= ob->actuators.first;
+ while(act) {
+ if(act->type==ACT_SOUND) {
+ bSoundActuator *sa= act->data;
+ sa->sound= newlibadr_us(fd, ob->id.lib, sa->sound);
+ }
+ else if(act->type==ACT_CD) {
+ /* bCDActuator *cda= act->data; */
+ }
+ else if(act->type==ACT_GAME) {
+ /* bGameActuator *ga= act->data; */
+ }
+ else if(act->type==ACT_CAMERA) {
+ bCameraActuator *ca= act->data;
+ ca->ob= newlibadr(fd, ob->id.lib, ca->ob);
+ }
+ /* leave this one, it's obsolete but necessary to read for conversion */
+ else if(act->type==ACT_ADD_OBJECT) {
+ bAddObjectActuator *eoa= act->data;
+ if(eoa) eoa->ob= newlibadr(fd, ob->id.lib, eoa->ob);
+ }
+ else if(act->type==ACT_EDIT_OBJECT) {
+ bEditObjectActuator *eoa= act->data;
+ if(eoa==NULL) {
+ init_actuator(act);
+ }
+ else {
+ eoa->ob= newlibadr(fd, ob->id.lib, eoa->ob);
+ eoa->me= newlibadr(fd, ob->id.lib, eoa->me);
+ }
+ }
+ else if(act->type==ACT_SCENE) {
+ bSceneActuator *sa= act->data;
+ sa->camera= newlibadr(fd, ob->id.lib, sa->camera);
+ sa->scene= newlibadr(fd, ob->id.lib, sa->scene);
+ }
+ else if(act->type==ACT_ACTION) {
+ bActionActuator *aa= act->data;
+ aa->act= newlibadr(fd, ob->id.lib, aa->act);
+ }
+ else if(act->type==ACT_PROPERTY) {
+ bPropertyActuator *pa= act->data;
+ pa->ob= newlibadr(fd, ob->id.lib, pa->ob);
+ }
+ else if(act->type==ACT_MESSAGE) {
+ bMessageActuator *ma= act->data;
+ ma->toObject= newlibadr(fd, ob->id.lib, ma->toObject);
+ }
+ act= act->next;
+ }
+
+ if(ob->fluidsimSettings) {
+ ob->fluidsimSettings->ipo = newlibadr_us(fd, ob->id.lib, ob->fluidsimSettings->ipo);
+ }
+
+ lib_link_scriptlink(fd, &ob->id, &ob->scriptlink);
+ lib_link_modifiers(fd, ob);
+ }
+ ob= ob->id.next;
+ }
+
+ if(warn) error("WARNING IN CONSOLE");
+}
+
+
+static void direct_link_pose(FileData *fd, bPose *pose) {
+
+ bPoseChannel *pchan;
+
+ if (!pose)
+ return;
+
+ link_list(fd, &pose->chanbase);
+
+ for (pchan = pose->chanbase.first; pchan; pchan=pchan->next) {
+ pchan->bone= NULL;
+ pchan->parent= newdataadr(fd, pchan->parent);
+ pchan->child= newdataadr(fd, pchan->child);
+ direct_link_constraints(fd, &pchan->constraints);
+ pchan->iktree.first= pchan->iktree.last= NULL;
+ pchan->path= NULL;
+ }
+
+}
+
+static void direct_link_modifiers(FileData *fd, ListBase *lb)
+{
+ ModifierData *md;
+
+ link_list(fd, lb);
+
+ for (md=lb->first; md; md=md->next) {
+ md->error = NULL;
+
+ /* if modifiers disappear, or for upward compatibility */
+ if(NULL==modifierType_getInfo(md->type))
+ md->type= eModifierType_None;
+
+ if (md->type==eModifierType_Subsurf) {
+ SubsurfModifierData *smd = (SubsurfModifierData*) md;
+
+ smd->emCache = smd->mCache = 0;
+ } else if (md->type==eModifierType_Hook) {
+ HookModifierData *hmd = (HookModifierData*) md;
+
+ hmd->indexar= newdataadr(fd, hmd->indexar);
+ if(fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
+ int a;
+ for(a=0; a<hmd->totindex; a++) {
+ SWITCH_INT(hmd->indexar[a]);
+ }
+ }
+ }
+ else if (md->type==eModifierType_MeshDeform) {
+ MeshDeformModifierData *mmd = (MeshDeformModifierData*) md;
+
+ mmd->bindweights= newdataadr(fd, mmd->bindweights);
+ mmd->bindcos= newdataadr(fd, mmd->bindcos);
+
+ if(fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
+ int a;
+
+ for(a=0; a<mmd->totcagevert*mmd->totvert; a++)
+ SWITCH_INT(mmd->bindweights[a])
+ for(a=0; a<mmd->totcagevert*3; a++)
+ SWITCH_INT(mmd->bindcos[a])
+ }
+ }
+ }
+}
+
+static void direct_link_nlastrips(FileData *fd, ListBase *strips)
+{
+ bActionStrip *strip;
+
+ link_list(fd, strips);
+
+ for(strip= strips->first; strip; strip= strip->next)
+ link_list(fd, &strip->modifiers);
+}
+
+static void direct_link_object(FileData *fd, Object *ob)
+{
+ PartEff *paf;
+ bProperty *prop;
+ bSensor *sens;
+ bController *cont;
+ bActuator *act;
+ int a;
+
+ /* weak weak... this was only meant as draw flag, now is used in give_base too */
+ ob->flag &= ~OB_FROMGROUP;
+
+ ob->disp.first=ob->disp.last= NULL;
+
+ ob->pose= newdataadr(fd, ob->pose);
+ direct_link_pose(fd, ob->pose);
+
+ link_list(fd, &ob->defbase);
+ direct_link_nlastrips(fd, &ob->nlastrips);
+ link_list(fd, &ob->constraintChannels);
+
+ direct_link_scriptlink(fd, &ob->scriptlink);
+
+ ob->mat= newdataadr(fd, ob->mat);
+ test_pointer_array(fd, (void **)&ob->mat);
+
+ /* do it here, below old data gets converted */
+ direct_link_modifiers(fd, &ob->modifiers);
+
+ link_list(fd, &ob->effect);
+ paf= ob->effect.first;
+ while(paf) {
+ if(paf->type==EFF_PARTICLE) {
+ paf->keys= NULL;
+ }
+ if(paf->type==EFF_WAVE) {
+ WaveEff *wav = (WaveEff*) paf;
+ PartEff *next = paf->next;
+ WaveModifierData *wmd = (WaveModifierData*) modifier_new(eModifierType_Wave);
+
+ wmd->damp = wav->damp;
+ wmd->flag = wav->flag;
+ wmd->height = wav->height;
+ wmd->lifetime = wav->lifetime;
+ wmd->narrow = wav->narrow;
+ wmd->speed = wav->speed;
+ wmd->startx = wav->startx;
+ wmd->starty = wav->startx;
+ wmd->timeoffs = wav->timeoffs;
+ wmd->width = wav->width;
+
+ BLI_addtail(&ob->modifiers, wmd);
+
+ BLI_remlink(&ob->effect, paf);
+ MEM_freeN(paf);
+
+ paf = next;
+ continue;
+ }
+ if(paf->type==EFF_BUILD) {
+ BuildEff *baf = (BuildEff*) paf;
+ PartEff *next = paf->next;
+ BuildModifierData *bmd = (BuildModifierData*) modifier_new(eModifierType_Build);
+
+ bmd->start = baf->sfra;
+ bmd->length = baf->len;
+ bmd->randomize = 0;
+ bmd->seed = 1;
+
+ BLI_addtail(&ob->modifiers, bmd);
+
+ BLI_remlink(&ob->effect, paf);
+ MEM_freeN(paf);
+
+ paf = next;
+ continue;
+ }
+ paf= paf->next;
+ }
+
+ ob->pd= newdataadr(fd, ob->pd);
+ ob->soft= newdataadr(fd, ob->soft);
+ if(ob->soft) {
+ SoftBody *sb= ob->soft;
+
+ sb->bpoint= NULL; // init pointers so it gets rebuilt nicely
+ sb->bspring= NULL;
+ sb->scratch= NULL;
+
+
+ sb->keys= newdataadr(fd, sb->keys);
+ test_pointer_array(fd, (void **)&sb->keys);
+ if(sb->keys) {
+ for(a=0; a<sb->totkey; a++) {
+ sb->keys[a]= newdataadr(fd, sb->keys[a]);
+ }
+ }
+ }
+ ob->fluidsimSettings= newdataadr(fd, ob->fluidsimSettings); /* NT */
+ if(ob->fluidsimSettings) {
+ // reinit mesh pointers
+ ob->fluidsimSettings->orgMesh = NULL; //ob->data;
+ ob->fluidsimSettings->meshSurface = NULL;
+ ob->fluidsimSettings->meshBB = NULL;
+ ob->fluidsimSettings->meshSurfNormals = NULL;
+ }
+
+ link_list(fd, &ob->prop);
+ prop= ob->prop.first;
+ while(prop) {
+ prop->poin= newdataadr(fd, prop->poin);
+ if(prop->poin==0) prop->poin= &prop->data;
+ prop= prop->next;
+ }
+
+ link_list(fd, &ob->sensors);
+ sens= ob->sensors.first;
+ while(sens) {
+ sens->data= newdataadr(fd, sens->data);
+ sens->links= newdataadr(fd, sens->links);
+ test_pointer_array(fd, (void **)&sens->links);
+ sens= sens->next;
+ }
+
+ direct_link_constraints(fd, &ob->constraints);
+
+ link_glob_list(fd, &ob->controllers);
+ cont= ob->controllers.first;
+ while(cont) {
+ cont->data= newdataadr(fd, cont->data);
+ cont->links= newdataadr(fd, cont->links);
+ test_pointer_array(fd, (void **)&cont->links);
+ cont= cont->next;
+ }
+
+ link_glob_list(fd, &ob->actuators);
+ act= ob->actuators.first;
+ while(act) {
+ act->data= newdataadr(fd, act->data);
+ act= act->next;
+ }
+
+ link_list(fd, &ob->hooks);
+ while (ob->hooks.first) {
+ ObHook *hook = ob->hooks.first;
+ HookModifierData *hmd = (HookModifierData*) modifier_new(eModifierType_Hook);
+
+ hook->indexar= newdataadr(fd, hook->indexar);
+ if(fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
+ int a;
+ for(a=0; a<hook->totindex; a++) {
+ SWITCH_INT(hook->indexar[a]);
+ }
+ }
+
+ /* Do conversion here because if we have loaded
+ * a hook we need to make sure it gets converted
+ * and free'd, regardless of version.
+ */
+ VECCOPY(hmd->cent, hook->cent);
+ hmd->falloff = hook->falloff;
+ hmd->force = hook->force;
+ hmd->indexar = hook->indexar;
+ hmd->object = hook->parent;
+ memcpy(hmd->parentinv, hook->parentinv, sizeof(hmd->parentinv));
+ hmd->totindex = hook->totindex;
+
+ BLI_addhead(&ob->modifiers, hmd);
+ BLI_remlink(&ob->hooks, hook);
+
+ MEM_freeN(hook);
+ }
+
+ ob->bb= NULL;
+ ob->derivedDeform= NULL;
+ ob->derivedFinal= NULL;
+}
+
+/* ************ READ SCENE ***************** */
+
+static void lib_link_scene(FileData *fd, Main *main)
+{
+ Scene *sce;
+ Base *base, *next;
+ Editing *ed;
+ Sequence *seq;
+ SceneRenderLayer *srl;
+ int a;
+
+ sce= main->scene.first;
+ while(sce) {
+ if(sce->id.flag & LIB_NEEDLINK) {
+ /*Link ID Properties -- and copy this comment EXACTLY for easy finding
+ of library blocks that implement this.*/
+ if (sce->id.properties) IDP_LibLinkProperty(sce->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+
+ sce->camera= newlibadr(fd, sce->id.lib, sce->camera);
+ sce->world= newlibadr_us(fd, sce->id.lib, sce->world);
+ sce->set= newlibadr(fd, sce->id.lib, sce->set);
+ sce->ima= newlibadr_us(fd, sce->id.lib, sce->ima);
+ sce->toolsettings->imapaint.brush=
+ newlibadr_us(fd, sce->id.lib, sce->toolsettings->imapaint.brush);
+
+ /* Sculptdata textures */
+ for(a=0; a<MAX_MTEX; ++a) {
+ MTex *mtex= sce->sculptdata.mtex[a];
+ if(mtex)
+ mtex->tex= newlibadr_us(fd, sce->id.lib, mtex->tex);
+ }
+
+ for(base= sce->base.first; base; base= next) {
+ next= base->next;
+
+ /* base->object= newlibadr_us(fd, sce->id.lib, base->object); */
+ base->object= newlibadr_us(fd, sce->id.lib, base->object);
+
+ /* when save during radiotool, needs cleared */
+ base->flag &= ~OB_RADIO;
+
+ if(base->object==NULL) {
+ printf("LIB ERROR: base removed\n");
+ BLI_remlink(&sce->base, base);
+ if(base==sce->basact) sce->basact= 0;
+ MEM_freeN(base);
+ }
+ }
+
+ ed= sce->ed;
+ if(ed) {
+ WHILE_SEQ(&ed->seqbase) {
+ if(seq->ipo) seq->ipo= newlibadr_us(fd, sce->id.lib, seq->ipo);
+ if(seq->scene) seq->scene= newlibadr(fd, sce->id.lib, seq->scene);
+ if(seq->sound) {
+ seq->sound= newlibadr(fd, sce->id.lib, seq->sound);
+ if (seq->sound) {
+ seq->sound->id.us++;
+ seq->sound->flags |= SOUND_FLAGS_SEQUENCE;
+ }
+ }
+ seq->anim= 0;
+ seq->hdaudio = 0;
+ }
+ END_SEQ
+ }
+
+ lib_link_scriptlink(fd, &sce->id, &sce->scriptlink);
+
+ if(sce->nodetree)
+ lib_link_ntree(fd, &sce->id, sce->nodetree);
+
+ for(srl= sce->r.layers.first; srl; srl= srl->next) {
+ srl->mat_override= newlibadr_us(fd, sce->id.lib, srl->mat_override);
+ srl->light_override= newlibadr_us(fd, sce->id.lib, srl->light_override);
+ }
+
+ sce->id.flag -= LIB_NEEDLINK;
+ }
+
+ sce= sce->id.next;
+ }
+}
+
+static void link_recurs_seq(FileData *fd, ListBase *lb)
+{
+ Sequence *seq;
+
+ link_list(fd, lb);
+ seq= lb->first;
+ while(seq) {
+ if(seq->seqbase.first) link_recurs_seq(fd, &seq->seqbase);
+ seq= seq->next;
+ }
+}
+
+static void direct_link_scene(FileData *fd, Scene *sce)
+{
+ Editing *ed;
+ Sequence *seq;
+ MetaStack *ms;
+ StripElem *se;
+ int a;
+
+ sce->theDag = NULL;
+ sce->dagisvalid = 0;
+ /* set users to one by default, not in lib-link, this will increase it for compo nodes */
+ sce->id.us= 1;
+
+ link_list(fd, &(sce->base));
+
+ sce->basact= newdataadr(fd, sce->basact);
+
+ sce->radio= newdataadr(fd, sce->radio);
+
+ sce->toolsettings= newdataadr(fd, sce->toolsettings);
+
+ sce->sculptdata.session= NULL;
+ /* SculptData textures */
+ for(a=0; a<MAX_MTEX; ++a)
+ sce->sculptdata.mtex[a]= newdataadr(fd,sce->sculptdata.mtex[a]);
+
+ if(sce->ed) {
+ ListBase *old_seqbasep= &((Editing *)sce->ed)->seqbase;
+
+ ed= sce->ed= newdataadr(fd, sce->ed);
+
+ /* recursive link sequences, lb will be correctly initialized */
+ link_recurs_seq(fd, &ed->seqbase);
+
+ WHILE_SEQ(&ed->seqbase) {
+ seq->seq1= newdataadr(fd, seq->seq1);
+ seq->seq2= newdataadr(fd, seq->seq2);
+ seq->seq3= newdataadr(fd, seq->seq3);
+ /* a patch: after introduction of effects with 3 input strips */
+ if(seq->seq3==0) seq->seq3= seq->seq2;
+
+ seq->curelem= 0;
+
+ seq->plugin= newdataadr(fd, seq->plugin);
+ seq->effectdata= newdataadr(fd, seq->effectdata);
+
+ if (seq->type & SEQ_EFFECT) {
+ seq->flag |= SEQ_EFFECT_NOT_LOADED;
+ }
+
+ seq->strip= newdataadr(fd, seq->strip);
+ if(seq->strip && seq->strip->done==0) {
+ seq->strip->done= 1;
+
+ /* standard: strips from effects/metas are not written, but are mallocced */
+
+ if(seq->type==SEQ_IMAGE) {
+ seq->strip->stripdata= newdataadr(fd, seq->strip->stripdata);
+ se= seq->strip->stripdata;
+ if(se) {
+ for(a=0; a<seq->strip->len; a++, se++) {
+ se->ok= 1;
+ se->ibuf= 0;
+ }
+ }
+ }
+ else if(seq->type==SEQ_MOVIE) {
+ /* only first stripelem is in file */
+ se= newdataadr(fd, seq->strip->stripdata);
+
+ if(se) {
+ seq->strip->stripdata= MEM_callocN(seq->len*sizeof(StripElem), "stripelem");
+ *seq->strip->stripdata= *se;
+ MEM_freeN(se);
+
+ se= seq->strip->stripdata;
+
+ for(a=0; a<seq->strip->len; a++, se++) {
+ se->ok= 1;
+ se->ibuf= 0;
+ se->nr= a + 1;
+ }
+ }
+ }
+ else if(seq->type==SEQ_RAM_SOUND
+ || seq->type == SEQ_HD_SOUND) {
+ /* only first stripelem is in file */
+ se= newdataadr(fd, seq->strip->stripdata);
+
+ if(se) {
+ seq->strip->stripdata= MEM_callocN(seq->len*sizeof(StripElem), "stripelem");
+ *seq->strip->stripdata= *se;
+ MEM_freeN(se);
+
+ se= seq->strip->stripdata;
+
+ for(a=0; a<seq->strip->len; a++, se++) {
+ se->ok= 2; /* why? */
+ se->ibuf= 0;
+ se->nr= a + 1;
+ }
+ }
+ }
+ else if(seq->len>0)
+ seq->strip->stripdata= MEM_callocN(seq->len*sizeof(StripElem), "stripelem");
+
+ }
+ }
+ END_SEQ
+
+ /* link metastack, slight abuse of structs here, have to restore pointer to internal part in struct */
+ {
+ Sequence temp;
+ char *poin;
+ long offset;
+
+ offset= ((long)&(temp.seqbase)) - ((long)&temp);
+
+ /* root pointer */
+ if(ed->seqbasep == old_seqbasep) {
+ ed->seqbasep= &ed->seqbase;
+ }
+ else {
+
+ poin= (char *)ed->seqbasep;
+ poin -= offset;
+
+ poin= newdataadr(fd, poin);
+ if(poin) ed->seqbasep= (ListBase *)(poin+offset);
+ else ed->seqbasep= &ed->seqbase;
+ }
+ /* stack */
+ link_list(fd, &(ed->metastack));
+
+ for(ms= ed->metastack.first; ms; ms= ms->next) {
+ ms->parseq= newdataadr(fd, ms->parseq);
+
+ if(ms->oldbasep == old_seqbasep)
+ ms->oldbasep= &ed->seqbase;
+ else {
+ poin= (char *)ms->oldbasep;
+ poin -= offset;
+ poin= newdataadr(fd, poin);
+ if(poin) ms->oldbasep= (ListBase *)(poin+offset);
+ else ms->oldbasep= &ed->seqbase;
+ }
+ }
+ }
+ }
+
+ direct_link_scriptlink(fd, &sce->scriptlink);
+
+ sce->r.avicodecdata = newdataadr(fd, sce->r.avicodecdata);
+ if (sce->r.avicodecdata) {
+ sce->r.avicodecdata->lpFormat = newdataadr(fd, sce->r.avicodecdata->lpFormat);
+ sce->r.avicodecdata->lpParms = newdataadr(fd, sce->r.avicodecdata->lpParms);
+ }
+
+ sce->r.qtcodecdata = newdataadr(fd, sce->r.qtcodecdata);
+ if (sce->r.qtcodecdata) {
+ sce->r.qtcodecdata->cdParms = newdataadr(fd, sce->r.qtcodecdata->cdParms);
+ }
+
+ link_list(fd, &(sce->markers));
+ link_list(fd, &(sce->r.layers));
+
+ sce->nodetree= newdataadr(fd, sce->nodetree);
+ if(sce->nodetree)
+ direct_link_nodetree(fd, sce->nodetree);
+
+}
+
+/* Nasty exception; IpoWindow stores a non-ID pointer in *from for sequence
+ strips... bad code warning!
+
+ We work around it by retrieving the missing pointer from the corresponding
+ Sequence-structure.
+
+ This is needed, to make Ipo-Pinning work for Sequence-Ipos...
+*/
+static Sequence * find_sequence_from_ipo_helper(Main * main, Ipo * ipo)
+{
+ Editing *ed;
+ Sequence *seq = NULL;
+
+ Scene * sce= main->scene.first;
+ while(sce) {
+ if(sce->ed) {
+ int found = 0;
+
+ ed= sce->ed;
+
+ WHILE_SEQ(&ed->seqbase) {
+ if (seq->ipo == ipo) {
+ found = 1;
+ break;
+ }
+ }
+ END_SEQ
+ if (found) {
+ break;
+ }
+ seq = NULL;
+ }
+ sce= sce->id.next;
+ }
+ if (seq)
+ return seq;
+ else
+ return NULL;
+}
+
+static void lib_link_screen_sequence_ipos(Main *main)
+{
+ bScreen *sc;
+ ScrArea *sa;
+
+ for(sc= main->screen.first; sc; sc= sc->id.next) {
+ for(sa= sc->areabase.first; sa; sa= sa->next) {
+ SpaceLink *sl;
+ for (sl= sa->spacedata.first; sl; sl= sl->next) {
+ if(sl->spacetype == SPACE_IPO) {
+ SpaceIpo *sipo= (SpaceIpo *)sl;
+ if(sipo->blocktype==ID_SEQ) {
+ sipo->from = (ID*) find_sequence_from_ipo_helper(main, sipo->ipo);
+ }
+ }
+ }
+ }
+ }
+}
+
+/* ************ READ SCREEN ***************** */
+
+/* note: file read without screens option G_FILE_NO_UI;
+ check lib pointers in call below */
+static void lib_link_screen(FileData *fd, Main *main)
+{
+ bScreen *sc;
+ ScrArea *sa;
+
+ for(sc= main->screen.first; sc; sc= sc->id.next) {
+ if(sc->id.flag & LIB_NEEDLINK) {
+ sc->id.us= 1;
+ sc->scene= newlibadr(fd, sc->id.lib, sc->scene);
+
+ sa= sc->areabase.first;
+ while(sa) {
+ SpaceLink *sl;
+
+ sa->full= newlibadr(fd, sc->id.lib, sa->full);
+
+ /* space handler scriptlinks */
+ lib_link_scriptlink(fd, &sc->id, &sa->scriptlink);
+
+ for (sl= sa->spacedata.first; sl; sl= sl->next) {
+ if(sl->spacetype==SPACE_VIEW3D) {
+ View3D *v3d= (View3D*) sl;
+
+ v3d->camera= newlibadr(fd, sc->id.lib, v3d->camera);
+ v3d->ob_centre= newlibadr(fd, sc->id.lib, v3d->ob_centre);
+
+ if(v3d->bgpic) {
+ v3d->bgpic->ima= newlibadr_us(fd, sc->id.lib, v3d->bgpic->ima);
+ }
+ if(v3d->localvd) {
+ v3d->localvd->camera= newlibadr(fd, sc->id.lib, v3d->localvd->camera);
+ }
+ v3d->depths= NULL;
+ v3d->ri= NULL;
+ }
+ else if(sl->spacetype==SPACE_IPO) {
+ SpaceIpo *sipo= (SpaceIpo *)sl;
+ sipo->editipo= 0;
+
+ if(sipo->blocktype==ID_SEQ) sipo->from= NULL; // no libdata
+ else sipo->from= newlibadr(fd, sc->id.lib, sipo->from);
+
+ sipo->ipokey.first= sipo->ipokey.last= 0;
+ sipo->ipo= newlibadr(fd, sc->id.lib, sipo->ipo);
+ }
+ else if(sl->spacetype==SPACE_BUTS) {
+ SpaceButs *sbuts= (SpaceButs *)sl;
+ sbuts->lockpoin= NULL;
+ sbuts->ri= NULL;
+ if(main->versionfile<132) set_rects_butspace(sbuts);
+ }
+ else if(sl->spacetype==SPACE_FILE) {
+ SpaceFile *sfile= (SpaceFile *)sl;
+
+ sfile->filelist= NULL;
+ sfile->libfiledata= NULL;
+ sfile->returnfunc= NULL;
+ sfile->menup= NULL;
+ sfile->pupmenu= NULL;
+ }
+ else if(sl->spacetype==SPACE_IMASEL) {
+ SpaceImaSel *simasel= (SpaceImaSel *)sl;
+
+ simasel->files = NULL;
+ simasel->returnfunc= NULL;
+ simasel->menup= NULL;
+ simasel->pupmenu= NULL;
+ simasel->img= NULL;
+ }
+ else if(sl->spacetype==SPACE_ACTION) {
+ SpaceAction *saction= (SpaceAction *)sl;
+ saction->action = newlibadr(fd, sc->id.lib, saction->action);
+ }
+ else if(sl->spacetype==SPACE_IMAGE) {
+ SpaceImage *sima= (SpaceImage *)sl;
+
+ sima->image= newlibadr_us(fd, sc->id.lib, sima->image);
+ }
+ else if(sl->spacetype==SPACE_NLA){
+ /* SpaceNla *snla= (SpaceNla *)sl; */
+ }
+ else if(sl->spacetype==SPACE_TEXT) {
+ SpaceText *st= (SpaceText *)sl;
+
+ st->text= newlibadr(fd, sc->id.lib, st->text);
+
+ }
+ else if(sl->spacetype==SPACE_SCRIPT) {
+ SpaceScript *sc= (SpaceScript *)sl;
+
+ sc->script = NULL;
+ }
+ else if(sl->spacetype==SPACE_OOPS) {
+ SpaceOops *so= (SpaceOops *)sl;
+ Oops *oops;
+ TreeStoreElem *tselem;
+ int a;
+
+ oops= so->oops.first;
+ while(oops) {
+ oops->id= newlibadr(fd, NULL, oops->id);
+ oops= oops->next;
+ }
+ so->lockpoin= NULL;
+ so->tree.first= so->tree.last= NULL;
+ so->search_tse.id= newlibadr(fd, NULL, so->search_tse.id);
+
+ if(so->treestore) {
+ tselem= so->treestore->data;
+ for(a=0; a<so->treestore->usedelem; a++, tselem++) {
+ tselem->id= newlibadr(fd, NULL, tselem->id);
+ }
+ }
+ }
+ else if(sl->spacetype==SPACE_SOUND) {
+ SpaceSound *ssound= (SpaceSound *)sl;
+
+ ssound->sound= newlibadr_us(fd, sc->id.lib, ssound->sound);
+ }
+ }
+ sa= sa->next;
+ }
+ sc->id.flag -= LIB_NEEDLINK;
+ }
+ }
+}
+
+/* Only for undo files, or to restore a screen after reading without UI... */
+static void *restore_pointer_by_name(Main *mainp, ID *id, int user)
+{
+
+ if(id) {
+ ListBase *lb= wich_libbase(mainp, GS(id->name));
+
+ if(lb) { // there's still risk of checking corrupt mem (freed Ids in oops)
+ ID *idn= lb->first;
+ char *name= id->name+2;
+
+ while(idn) {
+ if(idn->name[2]==name[0] && strcmp(idn->name+2, name)==0) {
+ if(idn->lib==id->lib) {
+ if(user && idn->us==0) idn->us++;
+ break;
+ }
+ }
+ idn= idn->next;
+ }
+ return idn;
+ }
+ }
+ return NULL;
+}
+
+/* called from kernel/blender.c */
+/* used to link a file (without UI) to the current UI */
+/* note that it assumes the old pointers in UI are still valid, so old Main is not freed */
+void lib_link_screen_restore(Main *newmain, Scene *curscene)
+{
+ bScreen *sc;
+ ScrArea *sa;
+
+ for(sc= newmain->screen.first; sc; sc= sc->id.next) {
+
+ sc->scene= curscene;
+
+ sa= sc->areabase.first;
+ while(sa) {
+ SpaceLink *sl;
+
+ if (sa->scriptlink.totscript) {
+ /* restore screen area script links */
+ ScriptLink *slink = &sa->scriptlink;
+ int script_idx;
+ for (script_idx = 0; script_idx < slink->totscript; script_idx++) {
+ slink->scripts[script_idx] = restore_pointer_by_name(newmain,
+ (ID *)slink->scripts[script_idx], 1);
+ }
+ }
+
+ for (sl= sa->spacedata.first; sl; sl= sl->next) {
+ if(sl->spacetype==SPACE_VIEW3D) {
+ View3D *v3d= (View3D*) sl;
+
+ v3d->camera= restore_pointer_by_name(newmain, (ID *)v3d->camera, 1);
+ if(v3d->camera==NULL)
+ v3d->camera= sc->scene->camera;
+ v3d->ob_centre= restore_pointer_by_name(newmain, (ID *)v3d->ob_centre, 1);
+
+ if(v3d->bgpic) {
+ v3d->bgpic->ima= restore_pointer_by_name(newmain, (ID *)v3d->bgpic->ima, 1);
+ }
+ if(v3d->localvd) {
+ Base *base;
+
+ v3d->localvd->camera= sc->scene->camera;
+
+ /* localview can become invalid during undo/redo steps, so we exit it when no could be found */
+ for(base= sc->scene->base.first; base; base= base->next) {
+ if(base->lay & v3d->lay) break;
+ }
+ if(base==NULL) {
+ v3d->lay= v3d->localvd->lay;
+ v3d->layact= v3d->localvd->layact;
+ MEM_freeN(v3d->localvd);
+ v3d->localvd= NULL;
+ v3d->localview= 0;
+ }
+ }
+ else if(v3d->scenelock) v3d->lay= sc->scene->lay;
+
+ /* not very nice, but could help */
+ if((v3d->layact & v3d->lay)==0) v3d->layact= v3d->lay;
+
+ }
+ else if(sl->spacetype==SPACE_IPO) {
+ SpaceIpo *sipo= (SpaceIpo *)sl;
+
+ if(sipo->blocktype==ID_SEQ) sipo->from= NULL; // no libdata
+ else sipo->from= restore_pointer_by_name(newmain, (ID *)sipo->from, 0);
+
+ // not free sipo->ipokey, creates dependency with src/
+ sipo->ipo= restore_pointer_by_name(newmain, (ID *)sipo->ipo, 0);
+ if(sipo->editipo) MEM_freeN(sipo->editipo);
+ sipo->editipo= NULL;
+ }
+ else if(sl->spacetype==SPACE_BUTS) {
+ SpaceButs *sbuts= (SpaceButs *)sl;
+ sbuts->lockpoin= NULL;
+ if (sbuts->ri) sbuts->ri->curtile = 0;
+ }
+ else if(sl->spacetype==SPACE_FILE) {
+ SpaceFile *sfile= (SpaceFile *)sl;
+ if(sfile->libfiledata)
+ BLO_blendhandle_close(sfile->libfiledata);
+ sfile->libfiledata= 0;
+ }
+ else if(sl->spacetype==SPACE_IMASEL) {
+ SpaceImaSel *simasel= (SpaceImaSel *)sl;
+ if (simasel->files) {
+ BIF_filelist_freelib(simasel->files);
+ }
+ }
+ else if(sl->spacetype==SPACE_ACTION) {
+ SpaceAction *saction= (SpaceAction *)sl;
+ saction->action = restore_pointer_by_name(newmain, (ID *)saction->action, 1);
+ }
+ else if(sl->spacetype==SPACE_IMAGE) {
+ SpaceImage *sima= (SpaceImage *)sl;
+
+ sima->image= restore_pointer_by_name(newmain, (ID *)sima->image, 1);
+ }
+ else if(sl->spacetype==SPACE_NLA){
+ /* SpaceNla *snla= (SpaceNla *)sl; */
+ }
+ else if(sl->spacetype==SPACE_TEXT) {
+ SpaceText *st= (SpaceText *)sl;
+
+ st->text= restore_pointer_by_name(newmain, (ID *)st->text, 1);
+ if(st->text==NULL) st->text= newmain->text.first;
+ }
+ else if(sl->spacetype==SPACE_SCRIPT) {
+ SpaceScript *sc= (SpaceScript *)sl;
+
+ sc->script = NULL;
+ }
+ else if(sl->spacetype==SPACE_OOPS) {
+ SpaceOops *so= (SpaceOops *)sl;
+ Oops *oops;
+ int a;
+
+ oops= so->oops.first;
+ while(oops) {
+ oops->id= restore_pointer_by_name(newmain, (ID *)oops->id, 0);
+ oops= oops->next;
+ }
+ so->lockpoin= NULL;
+ so->search_tse.id= restore_pointer_by_name(newmain, so->search_tse.id, 0);
+
+ if(so->treestore) {
+ TreeStore *ts= so->treestore;
+ TreeStoreElem *tselem=ts->data;
+ for(a=0; a<ts->usedelem; a++, tselem++) {
+ tselem->id= restore_pointer_by_name(newmain, tselem->id, 0);
+ }
+ }
+ }
+ else if(sl->spacetype==SPACE_SOUND) {
+ SpaceSound *ssound= (SpaceSound *)sl;
+
+ ssound->sound= restore_pointer_by_name(newmain, (ID *)ssound->sound, 1);
+ }
+ else if(sl->spacetype==SPACE_NODE) {
+ SpaceNode *snode= (SpaceNode *)sl;
+
+ snode->nodetree= snode->edittree= NULL;
+ snode->flag |= SNODE_DO_PREVIEW;
+ }
+ }
+ sa= sa->next;
+ }
+ }
+}
+
+static void direct_link_screen(FileData *fd, bScreen *sc)
+{
+ ScrArea *sa;
+ ScrVert *sv;
+ ScrEdge *se;
+ Oops *oops;
+ int a;
+
+ link_list(fd, &(sc->vertbase));
+ link_list(fd, &(sc->edgebase));
+ link_list(fd, &(sc->areabase));
+ sc->winakt= 0;
+
+ /* hacky patch... but people have been saving files with the verse-blender,
+ causing the handler to keep running for ever, with no means to disable it */
+ for(a=0; a<SCREEN_MAXHANDLER; a+=2) {
+ if( sc->handler[a]==SCREEN_HANDLER_VERSE) {
+ sc->handler[a]= 0;
+ break;
+ }
+ }
+
+ /* edges */
+ se= sc->edgebase.first;
+ while(se) {
+ se->v1= newdataadr(fd, se->v1);
+ se->v2= newdataadr(fd, se->v2);
+ if( (long)se->v1 > (long)se->v2) {
+ sv= se->v1;
+ se->v1= se->v2;
+ se->v2= sv;
+ }
+
+ if(se->v1==NULL) {
+ printf("error reading screen... file corrupt\n");
+ se->v1= se->v2;
+ }
+ se= se->next;
+ }
+
+ /* areas */
+ sa= sc->areabase.first;
+ while(sa) {
+ Panel *pa;
+ SpaceLink *sl;
+
+ link_list(fd, &(sa->spacedata));
+ link_list(fd, &(sa->panels));
+
+ /* accident can happen when read/save new file with older version */
+ if(sa->spacedata.first==NULL && sa->spacetype>SPACE_NLA)
+ sa->spacetype= SPACE_EMPTY;
+
+ for(pa= sa->panels.first; pa; pa=pa->next) {
+ pa->paneltab= newdataadr(fd, pa->paneltab);
+ pa->active= 0;
+ pa->sortcounter= 0;
+ }
+
+ for (sl= sa->spacedata.first; sl; sl= sl->next) {
+ if (sl->spacetype==SPACE_VIEW3D) {
+ View3D *v3d= (View3D*) sl;
+ v3d->bgpic= newdataadr(fd, v3d->bgpic);
+ if(v3d->bgpic)
+ v3d->bgpic->iuser.ok= 1;
+ v3d->localvd= newdataadr(fd, v3d->localvd);
+ v3d->afterdraw.first= v3d->afterdraw.last= NULL;
+ v3d->clipbb= newdataadr(fd, v3d->clipbb);
+ v3d->retopo_view_data= NULL;
+ v3d->properties_storage= NULL;
+ }
+ else if (sl->spacetype==SPACE_OOPS) {
+ SpaceOops *soops= (SpaceOops*) sl;
+
+ link_list(fd, &(soops->oops));
+ oops= soops->oops.first;
+ while(oops) {
+ oops->link.first= oops->link.last= 0;
+ oops= oops->next;
+ }
+
+ soops->treestore= newdataadr(fd, soops->treestore);
+ if(soops->treestore) {
+ soops->treestore->data= newdataadr(fd, soops->treestore->data);
+ /* we only saved what was used */
+ soops->treestore->totelem= soops->treestore->usedelem;
+ soops->storeflag |= SO_TREESTORE_CLEANUP; // at first draw
+ }
+ }
+ else if(sl->spacetype==SPACE_IMAGE) {
+ SpaceImage *sima= (SpaceImage *)sl;
+
+ sima->cumap= newdataadr(fd, sima->cumap);
+ if(sima->cumap)
+ direct_link_curvemapping(fd, sima->cumap);
+ sima->info_str= sima->info_spare= NULL;
+ sima->spare= NULL;
+ sima->iuser.ok= 1;
+ }
+ else if(sl->spacetype==SPACE_NODE) {
+ SpaceNode *snode= (SpaceNode *)sl;
+ snode->nodetree= snode->edittree= NULL;
+ snode->flag |= SNODE_DO_PREVIEW;
+ }
+ }
+
+ sa->v1= newdataadr(fd, sa->v1);
+ sa->v2= newdataadr(fd, sa->v2);
+ sa->v3= newdataadr(fd, sa->v3);
+ sa->v4= newdataadr(fd, sa->v4);
+
+ sa->win= sa->headwin= 0;
+
+ sa->uiblocks.first= sa->uiblocks.last= NULL;
+
+ /* space handler scriptlinks */
+ direct_link_scriptlink(fd, &sa->scriptlink);
+
+ sa= sa->next;
+ }
+}
+
+/* ********** READ LIBRARY *************** */
+
+
+static void direct_link_library(FileData *fd, Library *lib, Main *main)
+{
+ Main *newmain;
+
+ for(newmain= fd->mainlist.first; newmain; newmain= newmain->next) {
+ if(newmain->curlib) {
+ if(strcmp(newmain->curlib->filename, lib->filename)==0) {
+ printf("Fixed error in file; multiple instances of lib:\n %s\n", lib->filename);
+
+ change_idid_adr(&fd->mainlist, fd, lib, newmain->curlib);
+// change_idid_adr_fd(fd, lib, newmain->curlib);
+
+ BLI_remlink(&main->library, lib);
+ MEM_freeN(lib);
+
+ error("Library had multiple instances, save and reload!");
+ return;
+ }
+ }
+ }
+ /* make sure we have full path in lib->filename */
+ BLI_strncpy(lib->filename, lib->name, sizeof(lib->name));
+ cleanup_path(fd->filename, lib->filename);
+
+// printf("direct_link_library: name %s\n", lib->name);
+// printf("direct_link_library: filename %s\n", lib->filename);
+
+ /* new main */
+ newmain= MEM_callocN(sizeof(Main), "directlink");
+ BLI_addtail(&fd->mainlist, newmain);
+ newmain->curlib= lib;
+
+ lib->parent= NULL;
+}
+
+static void lib_link_library(FileData *fd, Main *main)
+{
+ Library *lib;
+
+ lib= main->library.first;
+ while(lib) {
+ lib->id.us= 1;
+ lib= lib->id.next;
+ }
+}
+
+/* ************** READ SOUND ******************* */
+
+static void direct_link_sound(FileData *fd, bSound *sound)
+{
+ sound->sample = NULL;
+ sound->snd_sound = NULL;
+
+ sound->packedfile = direct_link_packedfile(fd, sound->packedfile);
+ sound->newpackedfile = direct_link_packedfile(fd, sound->newpackedfile);
+}
+
+static void lib_link_sound(FileData *fd, Main *main)
+{
+ bSound *sound;
+
+ sound= main->sound.first;
+ while(sound) {
+ if(sound->id.flag & LIB_NEEDLINK) {
+ sound->id.flag -= LIB_NEEDLINK;
+ sound->ipo= newlibadr_us(fd, sound->id.lib, sound->ipo);
+ sound->stream = 0;
+ }
+ sound= sound->id.next;
+ }
+}
+/* ***************** READ GROUP *************** */
+
+static void direct_link_group(FileData *fd, Group *group)
+{
+ link_list(fd, &group->gobject);
+}
+
+static void lib_link_group(FileData *fd, Main *main)
+{
+ Group *group= main->group.first;
+ GroupObject *go;
+ int add_us;
+
+ while(group) {
+ if(group->id.flag & LIB_NEEDLINK) {
+ group->id.flag -= LIB_NEEDLINK;
+
+ add_us= 0;
+
+ go= group->gobject.first;
+ while(go) {
+ go->ob= newlibadr(fd, group->id.lib, go->ob);
+ if(go->ob) {
+ go->ob->flag |= OB_FROMGROUP;
+ /* if group has an object, it increments user... */
+ add_us= 1;
+ if(go->ob->id.us==0)
+ go->ob->id.us= 1;
+ }
+ go= go->next;
+ }
+ if(add_us) group->id.us++;
+ rem_from_group(group, NULL); /* removes NULL entries */
+ }
+ group= group->id.next;
+ }
+}
+
+/* ************** GENERAL & MAIN ******************** */
+
+
+static char *dataname(short id_code)
+{
+
+ switch( id_code ) {
+ case ID_OB: return "Data from OB";
+ case ID_ME: return "Data from ME";
+ case ID_IP: return "Data from IP";
+ case ID_SCE: return "Data from SCE";
+ case ID_MA: return "Data from MA";
+ case ID_TE: return "Data from TE";
+ case ID_CU: return "Data from CU";
+ case ID_GR: return "Data from GR";
+ case ID_AR: return "Data from AR";
+ case ID_AC: return "Data from AC";
+ case ID_LI: return "Data from LI";
+ case ID_MB: return "Data from MB";
+ case ID_IM: return "Data from IM";
+ case ID_LT: return "Data from LT";
+ case ID_LA: return "Data from LA";
+ case ID_CA: return "Data from CA";
+ case ID_KE: return "Data from KE";
+ case ID_WO: return "Data from WO";
+ case ID_SCR: return "Data from SCR";
+ case ID_VF: return "Data from VF";
+ case ID_TXT : return "Data from TXT";
+ case ID_SO: return "Data from SO";
+ case ID_NT: return "Data from NT";
+ case ID_BR: return "Data from BR";
+ }
+ return "Data from Lib Block";
+
+}
+
+static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID **id_r)
+{
+ /* this routine reads a libblock and its direct data. Use link functions
+ * to connect it all
+ */
+
+ ID *id;
+ ListBase *lb;
+ char *allocname;
+
+ /* read libblock */
+ id = read_struct(fd, bhead, "lib block");
+ if (id_r)
+ *id_r= id;
+ if (!id)
+ return blo_nextbhead(fd, bhead);
+
+ oldnewmap_insert(fd->libmap, bhead->old, id, bhead->code); /* for ID_ID check */
+
+ /* do after read_struct, for dna reconstruct */
+ if(bhead->code==ID_ID) {
+ lb= wich_libbase(main, GS(id->name));
+ }
+ else {
+ lb= wich_libbase(main, bhead->code);
+ }
+
+ BLI_addtail(lb, id);
+
+ /* clear first 8 bits */
+ id->flag= (id->flag & 0xFF00) | flag | LIB_NEEDLINK;
+ id->lib= main->curlib;
+ if(id->flag & LIB_FAKEUSER) id->us= 1;
+ else id->us= 0;
+ id->icon_id = 0;
+
+ /* this case cannot be direct_linked: it's just the ID part */
+ if(bhead->code==ID_ID) {
+ return blo_nextbhead(fd, bhead);
+ }
+
+ bhead = blo_nextbhead(fd, bhead);
+
+ /* need a name for the mallocN, just for debugging and sane prints on leaks */
+ allocname= dataname(GS(id->name));
+
+ /* read all data */
+ while(bhead && bhead->code==DATA) {
+ void *data= read_struct(fd, bhead, allocname);
+
+ if (data) {
+ oldnewmap_insert(fd->datamap, bhead->old, data, 0);
+ }
+
+ bhead = blo_nextbhead(fd, bhead);
+ }
+
+ /* init pointers direct data */
+ switch( GS(id->name) ) {
+ case ID_SCR:
+ direct_link_screen(fd, (bScreen *)id);
+ break;
+ case ID_SCE:
+ direct_link_scene(fd, (Scene *)id);
+ break;
+ case ID_OB:
+ direct_link_object(fd, (Object *)id);
+ break;
+ case ID_ME:
+ direct_link_mesh(fd, (Mesh *)id);
+ break;
+ case ID_CU:
+ direct_link_curve(fd, (Curve *)id);
+ break;
+ case ID_MB:
+ direct_link_mball(fd, (MetaBall *)id);
+ break;
+ case ID_MA:
+ direct_link_material(fd, (Material *)id);
+ break;
+ case ID_TE:
+ direct_link_texture(fd, (Tex *)id);
+ break;
+ case ID_IM:
+ direct_link_image(fd, (Image *)id);
+ break;
+ case ID_LA:
+ direct_link_lamp(fd, (Lamp *)id);
+ break;
+ case ID_VF:
+ direct_link_vfont(fd, (VFont *)id);
+ break;
+ case ID_TXT:
+ direct_link_text(fd, (Text *)id);
+ break;
+ case ID_IP:
+ direct_link_ipo(fd, (Ipo *)id);
+ break;
+ case ID_KE:
+ direct_link_key(fd, (Key *)id);
+ break;
+ case ID_LT:
+ direct_link_latt(fd, (Lattice *)id);
+ break;
+ case ID_WO:
+ direct_link_world(fd, (World *)id);
+ break;
+ case ID_LI:
+ direct_link_library(fd, (Library *)id, main);
+ break;
+ case ID_CA:
+ direct_link_camera(fd, (Camera *)id);
+ break;
+ case ID_SO:
+ direct_link_sound(fd, (bSound *)id);
+ break;
+ case ID_GR:
+ direct_link_group(fd, (Group *)id);
+ break;
+ case ID_AR:
+ direct_link_armature(fd, (bArmature*)id);
+ break;
+ case ID_AC:
+ direct_link_action(fd, (bAction*)id);
+ break;
+ case ID_NT:
+ direct_link_nodetree(fd, (bNodeTree*)id);
+ break;
+ case ID_BR:
+ direct_link_brush(fd, (Brush*)id);
+ break;
+ }
+
+ /*link direct data of ID properties*/
+ if (id->properties) {
+ id->properties = newdataadr(fd, id->properties);
+ IDP_DirectLinkProperty(id->properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
+ }
+
+ oldnewmap_free_unused(fd->datamap);
+ oldnewmap_clear(fd->datamap);
+
+ return (bhead);
+}
+
+static void link_global(FileData *fd, BlendFileData *bfd, FileGlobal *fg)
+{
+ // this is nonsense... make it struct once (ton)
+ bfd->winpos= fg->winpos;
+ bfd->fileflags= fg->fileflags;
+ bfd->displaymode= fg->displaymode;
+ bfd->globalf= fg->globalf;
+
+ bfd->curscreen= newlibadr(fd, 0, fg->curscreen);
+ bfd->curscene= newlibadr(fd, 0, fg->curscene);
+ // this happens in files older than 2.35
+ if(bfd->curscene==NULL) {
+ if(bfd->curscreen) bfd->curscene= bfd->curscreen->scene;
+ }
+}
+
+static void vcol_to_fcol(Mesh *me)
+{
+ MFace *mface;
+ unsigned int *mcol, *mcoln, *mcolmain;
+ int a;
+
+ if(me->totface==0 || me->mcol==0) return;
+
+ mcoln= mcolmain= MEM_mallocN(4*sizeof(int)*me->totface, "mcoln");
+ mcol = (unsigned int *)me->mcol;
+ mface= me->mface;
+ for(a=me->totface; a>0; a--, mface++) {
+ mcoln[0]= mcol[mface->v1];
+ mcoln[1]= mcol[mface->v2];
+ mcoln[2]= mcol[mface->v3];
+ mcoln[3]= mcol[mface->v4];
+ mcoln+= 4;
+ }
+
+ MEM_freeN(me->mcol);
+ me->mcol= (MCol *)mcolmain;
+}
+
+static int map_223_keybd_code_to_224_keybd_code(int code)
+{
+ switch (code) {
+ case 312: return F12KEY;
+ case 159: return PADSLASHKEY;
+ case 161: return PAD0;
+ case 154: return PAD1;
+ case 150: return PAD2;
+ case 155: return PAD3;
+ case 151: return PAD4;
+ case 156: return PAD5;
+ case 152: return PAD6;
+ case 157: return PAD7;
+ case 153: return PAD8;
+ case 158: return PAD9;
+ default: return code;
+ }
+}
+
+static void bone_version_238(ListBase *lb)
+{
+ Bone *bone;
+
+ for(bone= lb->first; bone; bone= bone->next) {
+ if(bone->rad_tail==0.0f && bone->rad_head==0.0f) {
+ bone->rad_head= 0.25f*bone->length;
+ bone->rad_tail= 0.1f*bone->length;
+
+ bone->dist-= bone->rad_head;
+ if(bone->dist<=0.0f) bone->dist= 0.0f;
+ }
+ bone_version_238(&bone->childbase);
+ }
+}
+
+static void bone_version_239(ListBase *lb)
+{
+ Bone *bone;
+
+ for(bone= lb->first; bone; bone= bone->next) {
+ if(bone->layer==0)
+ bone->layer= 1;
+ bone_version_239(&bone->childbase);
+ }
+}
+
+static void ntree_version_241(bNodeTree *ntree)
+{
+ bNode *node;
+
+ if(ntree->type==NTREE_COMPOSIT) {
+ for(node= ntree->nodes.first; node; node= node->next) {
+ if(node->type==CMP_NODE_BLUR) {
+ if(node->storage==NULL) {
+ NodeBlurData *nbd= MEM_callocN(sizeof(NodeBlurData), "node blur patch");
+ nbd->sizex= node->custom1;
+ nbd->sizey= node->custom2;
+ nbd->filtertype= R_FILTER_QUAD;
+ node->storage= nbd;
+ }
+ }
+ else if(node->type==CMP_NODE_VECBLUR) {
+ if(node->storage==NULL) {
+ NodeBlurData *nbd= MEM_callocN(sizeof(NodeBlurData), "node blur patch");
+ nbd->samples= node->custom1;
+ nbd->maxspeed= node->custom2;
+ nbd->fac= 1.0f;
+ node->storage= nbd;
+ }
+ }
+ }
+ }
+}
+
+static void ntree_version_242(bNodeTree *ntree)
+{
+ bNode *node;
+
+ if(ntree->type==NTREE_COMPOSIT) {
+ for(node= ntree->nodes.first; node; node= node->next) {
+ if(node->type==CMP_NODE_HUE_SAT) {
+ if(node->storage) {
+ NodeHueSat *nhs= node->storage;
+ if(nhs->val==0.0f) nhs->val= 1.0f;
+ }
+ }
+ }
+ }
+ else if(ntree->type==NTREE_SHADER) {
+ for(node= ntree->nodes.first; node; node= node->next)
+ if(node->type == SH_NODE_GEOMETRY && node->storage == NULL)
+ node->storage= MEM_callocN(sizeof(NodeGeometry), "NodeGeometry");
+ }
+
+}
+
+
+/* somehow, probably importing via python, keyblock adrcodes are not in order */
+static void sort_shape_fix(Main *main)
+{
+ Key *key;
+ KeyBlock *kb;
+ int sorted= 0;
+
+ while(sorted==0) {
+ sorted= 1;
+ for(key= main->key.first; key; key= key->id.next) {
+ for(kb= key->block.first; kb; kb= kb->next) {
+ if(kb->next && kb->adrcode>kb->next->adrcode) {
+ KeyBlock *next= kb->next;
+ BLI_remlink(&key->block, kb);
+ BLI_insertlink(&key->block, next, kb);
+ kb= next;
+ sorted= 0;
+ }
+ }
+ }
+ if(sorted==0) printf("warning, shape keys were sorted incorrect, fixed it!\n");
+ }
+}
+
+static void customdata_version_242(Mesh *me)
+{
+ CustomDataLayer *layer;
+ MTFace *mtf;
+ MCol *mcol;
+ TFace *tf;
+ int a, mtfacen, mcoln;
+
+ if (!me->vdata.totlayer) {
+ CustomData_add_layer(&me->vdata, CD_MVERT, CD_ASSIGN, me->mvert, me->totvert);
+
+ if (me->msticky)
+ CustomData_add_layer(&me->vdata, CD_MSTICKY, CD_ASSIGN, me->msticky, me->totvert);
+ if (me->dvert)
+ CustomData_add_layer(&me->vdata, CD_MDEFORMVERT, CD_ASSIGN, me->dvert, me->totvert);
+ }
+
+ if (!me->edata.totlayer)
+ CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, me->medge, me->totedge);
+
+ if (!me->fdata.totlayer) {
+ CustomData_add_layer(&me->fdata, CD_MFACE, CD_ASSIGN, me->mface, me->totface);
+
+ if (me->tface) {
+ if (me->mcol)
+ MEM_freeN(me->mcol);
+
+ me->mcol= CustomData_add_layer(&me->fdata, CD_MCOL, CD_CALLOC, NULL, me->totface);
+ me->mtface= CustomData_add_layer(&me->fdata, CD_MTFACE, CD_CALLOC, NULL, me->totface);
+
+ mtf= me->mtface;
+ mcol= me->mcol;
+ tf= me->tface;
+
+ for (a=0; a < me->totface; a++, mtf++, tf++, mcol+=4) {
+ memcpy(mcol, tf->col, sizeof(tf->col));
+ memcpy(mtf->uv, tf->uv, sizeof(tf->uv));
+
+ mtf->flag= tf->flag;
+ mtf->unwrap= tf->unwrap;
+ mtf->mode= tf->mode;
+ mtf->tile= tf->tile;
+ mtf->tpage= tf->tpage;
+ mtf->transp= tf->transp;
+ }
+
+ MEM_freeN(me->tface);
+ me->tface= NULL;
+ }
+ else if (me->mcol) {
+ me->mcol= CustomData_add_layer(&me->fdata, CD_MCOL, CD_ASSIGN, me->mcol, me->totface);
+ }
+ }
+
+ if (me->tface) {
+ MEM_freeN(me->tface);
+ me->tface= NULL;
+ }
+
+ for (a=0, mtfacen=0, mcoln=0; a < me->fdata.totlayer; a++) {
+ layer= &me->fdata.layers[a];
+
+ if (layer->type == CD_MTFACE) {
+ if (layer->name[0] == 0) {
+ if (mtfacen == 0) strcpy(layer->name, "UVTex");
+ else sprintf(layer->name, "UVTex.%.3d", mtfacen);
+ }
+ mtfacen++;
+ }
+ else if (layer->type == CD_MCOL) {
+ if (layer->name[0] == 0) {
+ if (mcoln == 0) strcpy(layer->name, "Col");
+ else sprintf(layer->name, "Col.%.3d", mcoln);
+ }
+ mcoln++;
+ }
+ }
+
+ mesh_update_customdata_pointers(me);
+}
+
+/*only copy render texface layer from active*/
+static void customdata_version_243(Mesh *me)
+{
+ CustomDataLayer *layer;
+ int a;
+
+ for (a=0; a < me->fdata.totlayer; a++) {
+ layer= &me->fdata.layers[a];
+ layer->active_rnd = layer->active;
+ }
+}
+
+/* struct NodeImageAnim moved to ImageUser, and we make it default available */
+static void do_version_ntree_242_2(bNodeTree *ntree)
+{
+ bNode *node;
+
+ if(ntree->type==NTREE_COMPOSIT) {
+ for(node= ntree->nodes.first; node; node= node->next) {
+ if(ELEM3(node->type, CMP_NODE_IMAGE, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) {
+ /* only image had storage */
+ if(node->storage) {
+ NodeImageAnim *nia= node->storage;
+ ImageUser *iuser= MEM_callocN(sizeof(ImageUser), "ima user node");
+
+ iuser->frames= nia->frames;
+ iuser->sfra= nia->sfra;
+ iuser->offset= nia->nr-1;
+ iuser->cycl= nia->cyclic;
+ iuser->fie_ima= 2;
+ iuser->ok= 1;
+
+ node->storage= iuser;
+ MEM_freeN(nia);
+ }
+ else {
+ ImageUser *iuser= node->storage= MEM_callocN(sizeof(ImageUser), "node image user");
+ iuser->sfra= 1;
+ iuser->fie_ima= 2;
+ iuser->ok= 1;
+ }
+ }
+ }
+ }
+}
+
+static void do_versions(FileData *fd, Library *lib, Main *main)
+{
+ /* WATCH IT!!!: pointers from libdata have not been converted */
+
+ if(G.f & G_DEBUG)
+ printf("read file %s\n Version %d sub %d\n", fd->filename, main->versionfile, main->subversionfile);
+
+ if(main->versionfile == 100) {
+ /* tex->extend and tex->imageflag have changed: */
+ Tex *tex = main->tex.first;
+ while(tex) {
+ if(tex->id.flag & LIB_NEEDLINK) {
+
+ if(tex->extend==0) {
+ if(tex->xrepeat || tex->yrepeat) tex->extend= TEX_REPEAT;
+ else {
+ tex->extend= TEX_EXTEND;
+ tex->xrepeat= tex->yrepeat= 1;
+ }
+ }
+
+ }
+ tex= tex->id.next;
+ }
+ }
+ if(main->versionfile <= 101) {
+ /* frame mapping */
+ Scene *sce = main->scene.first;
+ while(sce) {
+ sce->r.framapto= 100;
+ sce->r.images= 100;
+ sce->r.framelen= 1.0;
+ sce= sce->id.next;
+ }
+ }
+ if(main->versionfile <= 102) {
+ /* init halo's at 1.0 */
+ Material *ma = main->mat.first;
+ while(ma) {
+ ma->add= 1.0;
+ ma= ma->id.next;
+ }
+ }
+ if(main->versionfile <= 103) {
+ /* new variable in object: colbits */
+ Object *ob = main->object.first;
+ int a;
+ while(ob) {
+ ob->colbits= 0;
+ if(ob->totcol) {
+ for(a=0; a<ob->totcol; a++) {
+ if(ob->mat[a]) ob->colbits |= (1<<a);
+ }
+ }
+ ob= ob->id.next;
+ }
+ }
+ if(main->versionfile <= 104) {
+ /* timeoffs moved */
+ Object *ob = main->object.first;
+ while(ob) {
+ if(ob->transflag & 1) {
+ ob->transflag -= 1;
+ ob->ipoflag |= OB_OFFS_OB;
+ }
+ ob= ob->id.next;
+ }
+ }
+ if(main->versionfile <= 105) {
+ Object *ob = main->object.first;
+ while(ob) {
+ ob->dupon= 1; ob->dupoff= 0;
+ ob->dupsta= 1; ob->dupend= 100;
+ ob= ob->id.next;
+ }
+ }
+ if(main->versionfile <= 106) {
+ /* mcol changed */
+ Mesh *me = main->mesh.first;
+ while(me) {
+ if(me->mcol) vcol_to_fcol(me);
+ me= me->id.next;
+ }
+
+ }
+ if(main->versionfile <= 107) {
+ Object *ob;
+ Scene *sce = main->scene.first;
+ while(sce) {
+ sce->r.mode |= R_GAMMA;
+ sce= sce->id.next;
+ }
+ ob= main->object.first;
+ while(ob) {
+ ob->ipoflag |= OB_OFFS_PARENT;
+ if(ob->dt==0) ob->dt= OB_SOLID;
+ ob= ob->id.next;
+ }
+
+ }
+ if(main->versionfile <= 109) {
+ /* new variable: gridlines */
+ bScreen *sc = main->screen.first;
+ while(sc) {
+ ScrArea *sa= sc->areabase.first;
+ while(sa) {
+ SpaceLink *sl= sa->spacedata.first;
+ while (sl) {
+ if (sl->spacetype==SPACE_VIEW3D) {
+ View3D *v3d= (View3D*) sl;
+
+ if (v3d->gridlines==0) v3d->gridlines= 20;
+ }
+ sl= sl->next;
+ }
+ sa= sa->next;
+ }
+ sc= sc->id.next;
+ }
+ }
+ if(main->versionfile <= 112) {
+ Mesh *me = main->mesh.first;
+ while(me) {
+ me->cubemapsize= 1.0;
+ me= me->id.next;
+ }
+ }
+ if(main->versionfile <= 113) {
+ Material *ma = main->mat.first;
+ while(ma) {
+ if(ma->flaresize==0.0) ma->flaresize= 1.0;
+ ma->subsize= 1.0;
+ ma->flareboost= 1.0;
+ ma= ma->id.next;
+ }
+ }
+
+ if(main->versionfile <= 134) {
+ Tex *tex = main->tex.first;
+ while (tex) {
+ if ((tex->rfac == 0.0) &&
+ (tex->gfac == 0.0) &&
+ (tex->bfac == 0.0)) {
+ tex->rfac = 1.0;
+ tex->gfac = 1.0;
+ tex->bfac = 1.0;
+ tex->filtersize = 1.0;
+ }
+ tex = tex->id.next;
+ }
+ }
+ if(main->versionfile <= 140) {
+ /* r-g-b-fac in texure */
+ Tex *tex = main->tex.first;
+ while (tex) {
+ if ((tex->rfac == 0.0) &&
+ (tex->gfac == 0.0) &&
+ (tex->bfac == 0.0)) {
+ tex->rfac = 1.0;
+ tex->gfac = 1.0;
+ tex->bfac = 1.0;
+ tex->filtersize = 1.0;
+ }
+ tex = tex->id.next;
+ }
+ }
+ if(main->versionfile <= 153) {
+ Scene *sce = main->scene.first;
+ while(sce) {
+ if(sce->r.blurfac==0.0) sce->r.blurfac= 1.0;
+ sce= sce->id.next;
+ }
+ }
+ if(main->versionfile <= 163) {
+ Scene *sce = main->scene.first;
+ while(sce) {
+ if(sce->r.frs_sec==0) sce->r.frs_sec= 25;
+ sce= sce->id.next;
+ }
+ }
+ if(main->versionfile <= 164) {
+ Mesh *me= main->mesh.first;
+ while(me) {
+ me->smoothresh= 30;
+ me= me->id.next;
+ }
+ }
+ if(main->versionfile <= 165) {
+ Mesh *me= main->mesh.first;
+ TFace *tface;
+ int nr;
+ char *cp;
+
+ while(me) {
+ if(me->tface) {
+ nr= me->totface;
+ tface= me->tface;
+ while(nr--) {
+ cp= (char *)&tface->col[0];
+ if(cp[1]>126) cp[1]= 255; else cp[1]*=2;
+ if(cp[2]>126) cp[2]= 255; else cp[2]*=2;
+ if(cp[3]>126) cp[3]= 255; else cp[3]*=2;
+ cp= (char *)&tface->col[1];
+ if(cp[1]>126) cp[1]= 255; else cp[1]*=2;
+ if(cp[2]>126) cp[2]= 255; else cp[2]*=2;
+ if(cp[3]>126) cp[3]= 255; else cp[3]*=2;
+ cp= (char *)&tface->col[2];
+ if(cp[1]>126) cp[1]= 255; else cp[1]*=2;
+ if(cp[2]>126) cp[2]= 255; else cp[2]*=2;
+ if(cp[3]>126) cp[3]= 255; else cp[3]*=2;
+ cp= (char *)&tface->col[3];
+ if(cp[1]>126) cp[1]= 255; else cp[1]*=2;
+ if(cp[2]>126) cp[2]= 255; else cp[2]*=2;
+ if(cp[3]>126) cp[3]= 255; else cp[3]*=2;
+
+ tface++;
+ }
+ }
+ me= me->id.next;
+ }
+ }
+
+ if(main->versionfile <= 169) {
+ Mesh *me= main->mesh.first;
+ while(me) {
+ if(me->subdiv==0) me->subdiv= 1;
+ me= me->id.next;
+ }
+ }
+
+ if(main->versionfile <= 169) {
+ bScreen *sc= main->screen.first;
+ while(sc) {
+ ScrArea *sa= sc->areabase.first;
+ while(sa) {
+ SpaceLink *sl= sa->spacedata.first;
+ while(sl) {
+ if(sl->spacetype==SPACE_IPO) {
+ SpaceIpo *sipo= (SpaceIpo*) sl;
+ sipo->v2d.max[0]= 15000.0;
+ }
+ sl= sl->next;
+ }
+ sa= sa->next;
+ }
+ sc= sc->id.next;
+ }
+ }
+
+ if(main->versionfile <= 170) {
+ Object *ob = main->object.first;
+ PartEff *paf;
+ while (ob) {
+ paf = give_parteff(ob);
+ if (paf) {
+ if (paf->staticstep == 0) {
+ paf->staticstep= 5;
+ }
+ }
+ ob = ob->id.next;
+ }
+ }
+
+ if(main->versionfile <= 171) {
+ bScreen *sc= main->screen.first;
+ while(sc) {
+ ScrArea *sa= sc->areabase.first;
+ while(sa) {
+ SpaceLink *sl= sa->spacedata.first;
+ while(sl) {
+ if(sl->spacetype==SPACE_TEXT) {
+ SpaceText *st= (SpaceText*) sl;
+ if(st->font_id>1) {
+ st->font_id= 0;
+ st->lheight= 13;
+ }
+ }
+ sl= sl->next;
+ }
+ sa= sa->next;
+ }
+ sc= sc->id.next;
+ }
+ }
+
+ if(main->versionfile <= 173) {
+ int a, b;
+ Mesh *me= main->mesh.first;
+ while(me) {
+ if(me->tface) {
+ TFace *tface= me->tface;
+ for(a=0; a<me->totface; a++, tface++) {
+ for(b=0; b<4; b++) {
+ tface->uv[b][0]/= 32767.0;
+ tface->uv[b][1]/= 32767.0;
+ }
+ }
+ }
+ me= me->id.next;
+ }
+ }
+
+ if(main->versionfile <= 191) {
+ bScreen *sc= main->screen.first;
+ Object *ob= main->object.first;
+ Material *ma = main->mat.first;
+
+ /* let faces have default add factor of 0.0 */
+ while(ma) {
+ if (!(ma->mode & MA_HALO)) ma->add = 0.0;
+ ma = ma->id.next;
+ }
+
+ while(ob) {
+ ob->mass= 1.0f;
+ ob->damping= 0.1f;
+ ob->quat[1]= 1.0f;
+ ob= ob->id.next;
+ }
+
+ while(sc) {
+ ScrArea *sa= sc->areabase.first;
+ while(sa) {
+ SpaceLink *sl= sa->spacedata.first;
+ while(sl) {
+ if(sl->spacetype==SPACE_BUTS) {
+ SpaceButs *sbuts= (SpaceButs*) sl;
+ sbuts->scaflag= BUTS_SENS_LINK|BUTS_SENS_ACT|BUTS_CONT_ACT|BUTS_ACT_ACT|BUTS_ACT_LINK;
+ }
+ sl= sl->next;
+ }
+ sa= sa->next;
+ }
+ sc= sc->id.next;
+ }
+ }
+
+ if(main->versionfile <= 193) {
+ Object *ob= main->object.first;
+ while(ob) {
+ ob->inertia= 1.0f;
+ ob->rdamping= 0.1f;
+ ob= ob->id.next;
+ }
+ }
+
+ if(main->versionfile <= 196) {
+ Mesh *me= main->mesh.first;
+ int a, b;
+ while(me) {
+ if(me->tface) {
+ TFace *tface= me->tface;
+ for(a=0; a<me->totface; a++, tface++) {
+ for(b=0; b<4; b++) {
+ tface->mode |= TF_DYNAMIC;
+ tface->mode &= ~TF_INVISIBLE;
+ }
+ }
+ }
+ me= me->id.next;
+ }
+ }
+
+ if(main->versionfile <= 200) {
+ Object *ob= main->object.first;
+ while(ob) {
+ ob->scaflag = ob->gameflag & (64+128+256+512+1024+2048);
+ /* 64 is do_fh */
+ ob->gameflag &= ~(128+256+512+1024+2048);
+ ob = ob->id.next;
+ }
+ }
+
+ if(main->versionfile <= 201) {
+ /* add-object + end-object are joined to edit-object actuator */
+ Object *ob = main->object.first;
+ bProperty *prop;
+ bActuator *act;
+ bIpoActuator *ia;
+ bEditObjectActuator *eoa;
+ bAddObjectActuator *aoa;
+ while (ob) {
+ act = ob->actuators.first;
+ while (act) {
+ if(act->type==ACT_IPO) {
+ ia= act->data;
+ prop= get_property(ob, ia->name);
+ if(prop) {
+ ia->type= ACT_IPO_FROM_PROP;
+ }
+ }
+ else if(act->type==ACT_ADD_OBJECT) {
+ aoa= act->data;
+ eoa= MEM_callocN(sizeof(bEditObjectActuator), "edit ob act");
+ eoa->type= ACT_EDOB_ADD_OBJECT;
+ eoa->ob= aoa->ob;
+ eoa->time= aoa->time;
+ MEM_freeN(aoa);
+ act->data= eoa;
+ act->type= act->otype= ACT_EDIT_OBJECT;
+ }
+ else if(act->type==ACT_END_OBJECT) {
+ eoa= MEM_callocN(sizeof(bEditObjectActuator), "edit ob act");
+ eoa->type= ACT_EDOB_END_OBJECT;
+ act->data= eoa;
+ act->type= act->otype= ACT_EDIT_OBJECT;
+ }
+ act= act->next;
+ }
+ ob = ob->id.next;
+ }
+ }
+
+ if(main->versionfile <= 202) {
+ /* add-object and end-object are joined to edit-object
+ * actuator */
+ Object *ob= main->object.first;
+ bActuator *act;
+ bObjectActuator *oa;
+ while(ob) {
+ act= ob->actuators.first;
+ while(act) {
+ if(act->type==ACT_OBJECT) {
+ oa= act->data;
+ oa->flag &= ~(ACT_TORQUE_LOCAL|ACT_DROT_LOCAL); /* this actuator didn't do local/glob rot before */
+ }
+ act= act->next;
+ }
+ ob= ob->id.next;
+ }
+ }
+
+ if(main->versionfile <= 204) {
+ /* patches for new physics */
+ Object *ob= main->object.first;
+ bActuator *act;
+ bObjectActuator *oa;
+ bSound *sound;
+ while(ob) {
+
+ /* please check this for demo20 files like
+ * original Egypt levels etc. converted
+ * rotation factor of 50 is not workable */
+ act= ob->actuators.first;
+ while(act) {
+ if(act->type==ACT_OBJECT) {
+ oa= act->data;
+
+ oa->forceloc[0]*= 25.0;
+ oa->forceloc[1]*= 25.0;
+ oa->forceloc[2]*= 25.0;
+
+ oa->forcerot[0]*= 10.0;
+ oa->forcerot[1]*= 10.0;
+ oa->forcerot[2]*= 10.0;
+ }
+ act= act->next;
+ }
+ ob= ob->id.next;
+ }
+
+ sound = main->sound.first;
+ while (sound) {
+ if (sound->volume < 0.01) {
+ sound->volume = 1.0;
+ }
+ sound = sound->id.next;
+ }
+ }
+
+ if(main->versionfile <= 205) {
+ /* patches for new physics */
+ Object *ob= main->object.first;
+ bActuator *act;
+ bSensor *sens;
+ bEditObjectActuator *oa;
+ bRaySensor *rs;
+ bCollisionSensor *cs;
+ while(ob) {
+ /* Set anisotropic friction off for old objects,
+ * values to 1.0. */
+ ob->gameflag &= ~OB_ANISOTROPIC_FRICTION;
+ ob->anisotropicFriction[0] = 1.0;
+ ob->anisotropicFriction[1] = 1.0;
+ ob->anisotropicFriction[2] = 1.0;
+
+ act= ob->actuators.first;
+ while(act) {
+ if(act->type==ACT_EDIT_OBJECT) {
+ /* Zero initial velocity for newly
+ * added objects */
+ oa= act->data;
+ oa->linVelocity[0] = 0.0;
+ oa->linVelocity[1] = 0.0;
+ oa->linVelocity[2] = 0.0;
+ oa->localflag = 0;
+ }
+ act= act->next;
+ }
+
+ sens= ob->sensors.first;
+ while (sens) {
+ /* Extra fields for radar sensors. */
+ if(sens->type == SENS_RADAR) {
+ bRadarSensor *s = sens->data;
+ s->range = 10000.0;
+ }
+
+ /* Pulsing: defaults for new sensors. */
+ if(sens->type != SENS_ALWAYS) {
+ sens->pulse = 0;
+ sens->freq = 0;
+ } else {
+ sens->pulse = 1;
+ }
+
+ /* Invert: off. */
+ sens->invert = 0;
+
+ /* Collision and ray: default = trigger
+ * on property. The material field can
+ * remain empty. */
+ if(sens->type == SENS_COLLISION) {
+ cs = (bCollisionSensor*) sens->data;
+ cs->mode = 0;
+ }
+ if(sens->type == SENS_RAY) {
+ rs = (bRaySensor*) sens->data;
+ rs->mode = 0;
+ }
+ sens = sens->next;
+ }
+ ob= ob->id.next;
+ }
+ /* have to check the exact multiplier */
+ }
+
+ if(main->versionfile <= 211) {
+ /* Render setting: per scene, the applicable gamma value
+ * can be set. Default is 1.0, which means no
+ * correction. */
+ bActuator *act;
+ bObjectActuator *oa;
+ Object *ob;
+
+ /* added alpha in obcolor */
+ ob= main->object.first;
+ while(ob) {
+ ob->col[3]= 1.0;
+ ob= ob->id.next;
+ }
+
+ /* added alpha in obcolor */
+ ob= main->object.first;
+ while(ob) {
+ act= ob->actuators.first;
+ while(act) {
+ if (act->type==ACT_OBJECT) {
+ /* multiply velocity with 50 in old files */
+ oa= act->data;
+ if (fabs(oa->linearvelocity[0]) >= 0.01f)
+ oa->linearvelocity[0] *= 50.0;
+ if (fabs(oa->linearvelocity[1]) >= 0.01f)
+ oa->linearvelocity[1] *= 50.0;
+ if (fabs(oa->linearvelocity[2]) >= 0.01f)
+ oa->linearvelocity[2] *= 50.0;
+ if (fabs(oa->angularvelocity[0])>=0.01f)
+ oa->angularvelocity[0] *= 50.0;
+ if (fabs(oa->angularvelocity[1])>=0.01f)
+ oa->angularvelocity[1] *= 50.0;
+ if (fabs(oa->angularvelocity[2])>=0.01f)
+ oa->angularvelocity[2] *= 50.0;
+ }
+ act= act->next;
+ }
+ ob= ob->id.next;
+ }
+ }
+
+ if(main->versionfile <= 212) {
+
+ bSound* sound;
+ bProperty *prop;
+ Object *ob;
+ Mesh *me;
+
+ sound = main->sound.first;
+ while (sound)
+ {
+ sound->max_gain = 1.0;
+ sound->min_gain = 0.0;
+ sound->distance = 1.0;
+
+ if (sound->attenuation > 0.0)
+ sound->flags |= SOUND_FLAGS_3D;
+ else
+ sound->flags &= ~SOUND_FLAGS_3D;
+
+ sound = sound->id.next;
+ }
+
+ ob = main->object.first;
+
+ while (ob) {
+ prop= ob->prop.first;
+ while(prop) {
+ if (prop->type == PROP_TIME) {
+ // convert old PROP_TIME values from int to float
+ *((float *)&prop->data) = (float) prop->data;
+ }
+
+ prop= prop->next;
+ }
+ ob = ob->id.next;
+ }
+
+ /* me->subdiv changed to reflect the actual reparametization
+ * better, and smeshes were removed - if it was a smesh make
+ * it a subsurf, and reset the subdiv level because subsurf
+ * takes a lot more work to calculate.
+ */
+ for (me= main->mesh.first; me; me= me->id.next) {
+ if (me->flag&ME_SMESH) {
+ me->flag&= ~ME_SMESH;
+ me->flag|= ME_SUBSURF;
+
+ me->subdiv= 1;
+ } else {
+ if (me->subdiv<2)
+ me->subdiv= 1;
+ else
+ me->subdiv--;
+ }
+ }
+ }
+
+ if(main->versionfile <= 220) {
+ Object *ob;
+ Mesh *me;
+
+ ob = main->object.first;
+
+ /* adapt form factor in order to get the 'old' physics
+ * behaviour back...*/
+
+ while (ob) {
+ /* in future, distinguish between different
+ * object bounding shapes */
+ ob->formfactor = 0.4f;
+ /* patch form factor , note that inertia equiv radius
+ * of a rotation symmetrical obj */
+ if (ob->inertia != 1.0) {
+ ob->formfactor /= ob->inertia * ob->inertia;
+ }
+ ob = ob->id.next;
+ }
+
+ /* Began using alpha component of vertex colors, but
+ * old file vertex colors are undefined, reset them
+ * to be fully opaque. -zr
+ */
+ for (me= main->mesh.first; me; me= me->id.next) {
+ if (me->mcol) {
+ int i;
+
+ for (i=0; i<me->totface*4; i++) {
+ MCol *mcol= &me->mcol[i];
+ mcol->a= 255;
+ }
+ }
+ if (me->tface) {
+ int i, j;
+
+ for (i=0; i<me->totface; i++) {
+ TFace *tf= &((TFace*) me->tface)[i];
+
+ for (j=0; j<4; j++) {
+ char *col= (char*) &tf->col[j];
+
+ col[0]= 255;
+ }
+ }
+ }
+ }
+ }
+ if(main->versionfile <= 221) {
+ Scene *sce= main->scene.first;
+
+ // new variables for std-alone player and runtime
+ while(sce) {
+
+ sce->r.xplay= 640;
+ sce->r.yplay= 480;
+ sce->r.freqplay= 60;
+
+ sce= sce->id.next;
+ }
+
+ }
+ if(main->versionfile <= 222) {
+ Scene *sce= main->scene.first;
+
+ // new variables for std-alone player and runtime
+ while(sce) {
+
+ sce->r.depth= 32;
+
+ sce= sce->id.next;
+ }
+ }
+
+
+ if(main->versionfile <= 223) {
+ VFont *vf;
+ Image *ima;
+ Object *ob;
+
+ for (vf= main->vfont.first; vf; vf= vf->id.next) {
+ if (BLI_streq(vf->name+strlen(vf->name)-6, ".Bfont")) {
+ strcpy(vf->name, "<builtin>");
+ }
+ }
+
+ /* Old textures animate at 25 FPS */
+ for (ima = main->image.first; ima; ima=ima->id.next){
+ ima->animspeed = 25;
+ }
+
+ /* Zr remapped some keyboard codes to be linear (stupid zr) */
+ for (ob= main->object.first; ob; ob= ob->id.next) {
+ bSensor *sens;
+
+ for (sens= ob->sensors.first; sens; sens= sens->next) {
+ if (sens->type==SENS_KEYBOARD) {
+ bKeyboardSensor *ks= sens->data;
+
+ ks->key= map_223_keybd_code_to_224_keybd_code(ks->key);
+ ks->qual= map_223_keybd_code_to_224_keybd_code(ks->qual);
+ ks->qual2= map_223_keybd_code_to_224_keybd_code(ks->qual2);
+ }
+ }
+ }
+ }
+ if(main->versionfile <= 224) {
+ bSound* sound;
+ Scene *sce;
+ Mesh *me;
+ bScreen *sc;
+
+ for (sound=main->sound.first; sound; sound=sound->id.next) {
+ if (sound->packedfile) {
+ if (sound->newpackedfile == NULL) {
+ sound->newpackedfile = sound->packedfile;
+ }
+ sound->packedfile = NULL;
+ }
+ }
+ /* Make sure that old subsurf meshes don't have zero subdivision level for rendering */
+ for (me=main->mesh.first; me; me=me->id.next){
+ if ((me->flag & ME_SUBSURF) && (me->subdivr==0))
+ me->subdivr=me->subdiv;
+ }
+
+ for (sce= main->scene.first; sce; sce= sce->id.next) {
+ sce->r.stereomode = 1; // no stereo
+ }
+
+ /* some oldfile patch, moved from set_func_space */
+ for (sc= main->screen.first; sc; sc= sc->id.next) {
+ ScrArea *sa;
+
+ for (sa= sc->areabase.first; sa; sa= sa->next) {
+ SpaceLink *sl;
+
+ for (sl= sa->spacedata.first; sl; sl= sl->next) {
+ if (sl->spacetype==SPACE_IPO) {
+ SpaceSeq *sseq= (SpaceSeq*) sl;
+ sseq->v2d.keeptot= 0;
+ }
+ }
+ }
+ }
+
+ }
+
+
+ if(main->versionfile <= 225) {
+ World *wo;
+ /* Use Sumo for old games */
+ for (wo = main->world.first; wo; wo= wo->id.next) {
+ wo->physicsEngine = 2;
+ }
+ }
+
+ if(main->versionfile <= 227) {
+ Scene *sce;
+ Material *ma;
+ bScreen *sc;
+ Object *ob;
+
+ /* As of now, this insures that the transition from the old Track system
+ to the new full constraint Track is painless for everyone. - theeth
+ */
+ ob = main->object.first;
+
+ while (ob) {
+ ListBase *list;
+ list = &ob->constraints;
+
+ /* check for already existing TrackTo constraint
+ set their track and up flag correctly */
+
+ if (list){
+ bConstraint *curcon;
+ for (curcon = list->first; curcon; curcon=curcon->next){
+ if (curcon->type == CONSTRAINT_TYPE_TRACKTO){
+ bTrackToConstraint *data = curcon->data;
+ data->reserved1 = ob->trackflag;
+ data->reserved2 = ob->upflag;
+ }
+ }
+ }
+
+ if (ob->type == OB_ARMATURE) {
+ if (ob->pose){
+ bConstraint *curcon;
+ bPoseChannel *pchan;
+ for (pchan = ob->pose->chanbase.first;
+ pchan; pchan=pchan->next){
+ for (curcon = pchan->constraints.first;
+ curcon; curcon=curcon->next){
+ if (curcon->type == CONSTRAINT_TYPE_TRACKTO){
+ bTrackToConstraint *data = curcon->data;
+ data->reserved1 = ob->trackflag;
+ data->reserved2 = ob->upflag;
+ }
+ }
+ }
+ }
+ }
+
+ /* Change Ob->Track in real TrackTo constraint */
+
+ if (ob->track){
+ bConstraint *con;
+ bConstraintTypeInfo *cti;
+ bTrackToConstraint *data;
+ void *cdata;
+
+ list = &ob->constraints;
+ if (list)
+ {
+ con = MEM_callocN(sizeof(bConstraint), "constraint");
+ strcpy (con->name, "AutoTrack");
+ unique_constraint_name(con, list);
+ con->flag |= CONSTRAINT_EXPAND;
+ con->enforce=1.0F;
+ con->type = CONSTRAINT_TYPE_TRACKTO;
+
+ cti= get_constraint_typeinfo(CONSTRAINT_TYPE_TRACKTO);
+ cdata= MEM_callocN(cti->size, cti->structName);
+ cti->new_data(cdata);
+ data = (bTrackToConstraint *)cdata;
+
+ data->tar = ob->track;
+ data->reserved1 = ob->trackflag;
+ data->reserved2 = ob->upflag;
+ con->data= (void*) data;
+ BLI_addtail(list, con);
+ }
+ ob->track = 0;
+ }
+
+ ob = ob->id.next;
+ }
+
+
+ for (sce= main->scene.first; sce; sce= sce->id.next) {
+ sce->audio.mixrate = 44100;
+ sce->audio.flag |= AUDIO_SCRUB;
+ sce->r.mode |= R_ENVMAP;
+ }
+ // init new shader vars
+ for (ma= main->mat.first; ma; ma= ma->id.next) {
+ ma->refrac= 4.0f;
+ ma->roughness= 0.5f;
+ ma->param[0]= 0.5f;
+ ma->param[1]= 0.1f;
+ ma->param[2]= 0.1f;
+ ma->param[3]= 0.05f;
+ }
+ // patch for old wrong max view2d settings, allows zooming out more
+ for (sc= main->screen.first; sc; sc= sc->id.next) {
+ ScrArea *sa;
+
+ for (sa= sc->areabase.first; sa; sa= sa->next) {
+ SpaceLink *sl;
+
+ for (sl= sa->spacedata.first; sl; sl= sl->next) {
+ if (sl->spacetype==SPACE_ACTION) {
+ SpaceAction *sac= (SpaceAction *) sl;
+ sac->v2d.max[0]= 32000;
+ }
+ else if (sl->spacetype==SPACE_NLA) {
+ SpaceNla *sla= (SpaceNla *) sl;
+ sla->v2d.max[0]= 32000;
+ }
+ }
+ }
+ }
+ }
+ if(main->versionfile <= 228) {
+ Scene *sce;
+ bScreen *sc;
+ Object *ob;
+
+
+ /* As of now, this insures that the transition from the old Track system
+ to the new full constraint Track is painless for everyone.*/
+ ob = main->object.first;
+
+ while (ob) {
+ ListBase *list;
+ list = &ob->constraints;
+
+ /* check for already existing TrackTo constraint
+ set their track and up flag correctly */
+
+ if (list){
+ bConstraint *curcon;
+ for (curcon = list->first; curcon; curcon=curcon->next){
+ if (curcon->type == CONSTRAINT_TYPE_TRACKTO){
+ bTrackToConstraint *data = curcon->data;
+ data->reserved1 = ob->trackflag;
+ data->reserved2 = ob->upflag;
+ }
+ }
+ }
+
+ if (ob->type == OB_ARMATURE) {
+ if (ob->pose){
+ bConstraint *curcon;
+ bPoseChannel *pchan;
+ for (pchan = ob->pose->chanbase.first;
+ pchan; pchan=pchan->next){
+ for (curcon = pchan->constraints.first;
+ curcon; curcon=curcon->next){
+ if (curcon->type == CONSTRAINT_TYPE_TRACKTO){
+ bTrackToConstraint *data = curcon->data;
+ data->reserved1 = ob->trackflag;
+ data->reserved2 = ob->upflag;
+ }
+ }
+ }
+ }
+ }
+
+ ob = ob->id.next;
+ }
+
+ for (sce= main->scene.first; sce; sce= sce->id.next) {
+ sce->r.mode |= R_ENVMAP;
+ }
+
+ // convert old mainb values for new button panels
+ for (sc= main->screen.first; sc; sc= sc->id.next) {
+ ScrArea *sa;
+
+ for (sa= sc->areabase.first; sa; sa= sa->next) {
+ SpaceLink *sl;
+
+ for (sl= sa->spacedata.first; sl; sl= sl->next) {
+ if (sl->spacetype==SPACE_BUTS) {
+ SpaceButs *sbuts= (SpaceButs *) sl;
+
+ sbuts->v2d.maxzoom= 1.2f;
+ sbuts->align= 1; /* horizontal default */
+
+ if(sbuts->mainb==BUTS_LAMP) {
+ sbuts->mainb= CONTEXT_SHADING;
+ sbuts->tab[CONTEXT_SHADING]= TAB_SHADING_LAMP;
+ }
+ else if(sbuts->mainb==BUTS_MAT) {
+ sbuts->mainb= CONTEXT_SHADING;
+ sbuts->tab[CONTEXT_SHADING]= TAB_SHADING_MAT;
+ }
+ else if(sbuts->mainb==BUTS_TEX) {
+ sbuts->mainb= CONTEXT_SHADING;
+ sbuts->tab[CONTEXT_SHADING]= TAB_SHADING_TEX;
+ }
+ else if(sbuts->mainb==BUTS_ANIM) {
+ sbuts->mainb= CONTEXT_OBJECT;
+ }
+ else if(sbuts->mainb==BUTS_WORLD) {
+ sbuts->mainb= CONTEXT_SCENE;
+ sbuts->tab[CONTEXT_SCENE]= TAB_SCENE_WORLD;
+ }
+ else if(sbuts->mainb==BUTS_RENDER) {
+ sbuts->mainb= CONTEXT_SCENE;
+ sbuts->tab[CONTEXT_SCENE]= TAB_SCENE_RENDER;
+ }
+ else if(sbuts->mainb==BUTS_GAME) {
+ sbuts->mainb= CONTEXT_LOGIC;
+ }
+ else if(sbuts->mainb==BUTS_FPAINT) {
+ sbuts->mainb= CONTEXT_EDITING;
+ }
+ else if(sbuts->mainb==BUTS_RADIO) {
+ sbuts->mainb= CONTEXT_SHADING;
+ sbuts->tab[CONTEXT_SHADING]= TAB_SHADING_RAD;
+ }
+ else if(sbuts->mainb==BUTS_CONSTRAINT) {
+ sbuts->mainb= CONTEXT_OBJECT;
+ }
+ else if(sbuts->mainb==BUTS_SCRIPT) {
+ sbuts->mainb= CONTEXT_OBJECT;
+ }
+ else if(sbuts->mainb==BUTS_EDIT) {
+ sbuts->mainb= CONTEXT_EDITING;
+ }
+ else sbuts->mainb= CONTEXT_SCENE;
+ }
+ }
+ }
+ }
+ }
+ /* ton: made this 230 instead of 229,
+ to be sure (tuho files) and this is a reliable check anyway
+ nevertheless, we might need to think over a fitness (initialize)
+ check apart from the do_versions() */
+
+ if(main->versionfile <= 230) {
+ bScreen *sc;
+
+ // new variable blockscale, for panels in any area
+ for (sc= main->screen.first; sc; sc= sc->id.next) {
+ ScrArea *sa;
+
+ for (sa= sc->areabase.first; sa; sa= sa->next) {
+ SpaceLink *sl;
+
+ for (sl= sa->spacedata.first; sl; sl= sl->next) {
+ if(sl->blockscale==0.0) sl->blockscale= 0.7f;
+ /* added: 5x better zoom in for action */
+ if(sl->spacetype==SPACE_ACTION) {
+ SpaceAction *sac= (SpaceAction *)sl;
+ sac->v2d.maxzoom= 50;
+ }
+ }
+ }
+ }
+ }
+ if(main->versionfile <= 231) {
+ /* new bit flags for showing/hiding grid floor and axes */
+ bScreen *sc = main->screen.first;
+ while(sc) {
+ ScrArea *sa= sc->areabase.first;
+ while(sa) {
+ SpaceLink *sl= sa->spacedata.first;
+ while (sl) {
+ if (sl->spacetype==SPACE_VIEW3D) {
+ View3D *v3d= (View3D*) sl;
+
+ if (v3d->gridflag==0) {
+ v3d->gridflag |= V3D_SHOW_X;
+ v3d->gridflag |= V3D_SHOW_Y;
+ v3d->gridflag |= V3D_SHOW_FLOOR;
+ v3d->gridflag &= ~V3D_SHOW_Z;
+ }
+ }
+ sl= sl->next;
+ }
+ sa= sa->next;
+ }
+ sc= sc->id.next;
+ }
+ }
+ if(main->versionfile <= 231) {
+ Material *ma= main->mat.first;
+ bScreen *sc = main->screen.first;
+ Scene *sce;
+ Lamp *la;
+ World *wrld;
+
+ /* introduction of raytrace */
+ while(ma) {
+ if(ma->fresnel_tra_i==0.0) ma->fresnel_tra_i= 1.25;
+ if(ma->fresnel_mir_i==0.0) ma->fresnel_mir_i= 1.25;
+
+ ma->ang= 1.0;
+ ma->ray_depth= 2;
+ ma->ray_depth_tra= 2;
+ ma->fresnel_tra= 0.0;
+ ma->fresnel_mir= 0.0;
+
+ ma= ma->id.next;
+ }
+ sce= main->scene.first;
+ while(sce) {
+ if(sce->r.gauss==0.0) sce->r.gauss= 1.0;
+ sce= sce->id.next;
+ }
+ la= main->lamp.first;
+ while(la) {
+ if(la->k==0.0) la->k= 1.0;
+ if(la->ray_samp==0) la->ray_samp= 1;
+ if(la->ray_sampy==0) la->ray_sampy= 1;
+ if(la->ray_sampz==0) la->ray_sampz= 1;
+ if(la->area_size==0.0) la->area_size= 1.0;
+ if(la->area_sizey==0.0) la->area_sizey= 1.0;
+ if(la->area_sizez==0.0) la->area_sizez= 1.0;
+ la= la->id.next;
+ }
+ wrld= main->world.first;
+ while(wrld) {
+ if(wrld->range==0.0) {
+ wrld->range= 1.0f/wrld->exposure;
+ }
+ wrld= wrld->id.next;
+ }
+
+ /* new bit flags for showing/hiding grid floor and axes */
+
+ while(sc) {
+ ScrArea *sa= sc->areabase.first;
+ while(sa) {
+ SpaceLink *sl= sa->spacedata.first;
+ while (sl) {
+ if (sl->spacetype==SPACE_VIEW3D) {
+ View3D *v3d= (View3D*) sl;
+
+ if (v3d->gridflag==0) {
+ v3d->gridflag |= V3D_SHOW_X;
+ v3d->gridflag |= V3D_SHOW_Y;
+ v3d->gridflag |= V3D_SHOW_FLOOR;
+ v3d->gridflag &= ~V3D_SHOW_Z;
+ }
+ }
+ sl= sl->next;
+ }
+ sa= sa->next;
+ }
+ sc= sc->id.next;
+ }
+ }
+ if(main->versionfile <= 232) {
+ Tex *tex= main->tex.first;
+ World *wrld= main->world.first;
+ bScreen *sc;
+ Scene *sce;
+
+ while(tex) {
+ if((tex->flag & (TEX_CHECKER_ODD+TEX_CHECKER_EVEN))==0) {
+ tex->flag |= TEX_CHECKER_ODD;
+ }
+ /* copied from kernel texture.c */
+ if(tex->ns_outscale==0.0) {
+ /* musgrave */
+ tex->mg_H = 1.0f;
+ tex->mg_lacunarity = 2.0f;
+ tex->mg_octaves = 2.0f;
+ tex->mg_offset = 1.0f;
+ tex->mg_gain = 1.0f;
+ tex->ns_outscale = 1.0f;
+ /* distnoise */
+ tex->dist_amount = 1.0f;
+ /* voronoi */
+ tex->vn_w1 = 1.0f;
+ tex->vn_mexp = 2.5f;
+ }
+ tex= tex->id.next;
+ }
+
+ while(wrld) {
+ if(wrld->aodist==0.0) {
+ wrld->aodist= 10.0f;
+ wrld->aobias= 0.05f;
+ }
+ if(wrld->aosamp==0.0) wrld->aosamp= 5;
+ if(wrld->aoenergy==0.0) wrld->aoenergy= 1.0;
+ wrld= wrld->id.next;
+ }
+
+
+ // new variable blockscale, for panels in any area, do again because new
+ // areas didnt initialize it to 0.7 yet
+ for (sc= main->screen.first; sc; sc= sc->id.next) {
+ ScrArea *sa;
+ for (sa= sc->areabase.first; sa; sa= sa->next) {
+ SpaceLink *sl;
+ for (sl= sa->spacedata.first; sl; sl= sl->next) {
+ if(sl->blockscale==0.0) sl->blockscale= 0.7f;
+
+ /* added: 5x better zoom in for nla */
+ if(sl->spacetype==SPACE_NLA) {
+ SpaceNla *snla= (SpaceNla *)sl;
+ snla->v2d.maxzoom= 50;
+ }
+ }
+ }
+ }
+ sce= main->scene.first;
+ while(sce) {
+ if(sce->r.ocres==0) sce->r.ocres= 64;
+ sce= sce->id.next;
+ }
+
+ }
+ if(main->versionfile <= 233) {
+ bScreen *sc;
+ Material *ma= main->mat.first;
+ Object *ob= main->object.first;
+
+ while(ma) {
+ if(ma->rampfac_col==0.0) ma->rampfac_col= 1.0;
+ if(ma->rampfac_spec==0.0) ma->rampfac_spec= 1.0;
+ if(ma->pr_lamp==0) ma->pr_lamp= 3;
+ ma= ma->id.next;
+ }
+
+ /* this should have been done loooong before! */
+ while(ob) {
+ if(ob->ipowin==0) ob->ipowin= ID_OB;
+ ob= ob->id.next;
+ }
+
+ for (sc= main->screen.first; sc; sc= sc->id.next) {
+ ScrArea *sa;
+ for (sa= sc->areabase.first; sa; sa= sa->next) {
+ SpaceLink *sl;
+ for (sl= sa->spacedata.first; sl; sl= sl->next) {
+ if(sl->spacetype==SPACE_VIEW3D) {
+ View3D *v3d= (View3D *)sl;
+ v3d->flag |= V3D_SELECT_OUTLINE;
+ }
+ }
+ }
+ }
+ }
+
+
+
+
+ if(main->versionfile <= 234) {
+ Scene *sce;
+ World *wo;
+ bScreen *sc;
+ int set_zbuf_sel=0;
+
+ // force sumo engine to be active
+ for (wo = main->world.first; wo; wo= wo->id.next) {
+ if(wo->physicsEngine==0) wo->physicsEngine = 2;
+ }
+
+ for (sce= main->scene.first; sce; sce= sce->id.next) {
+ if(sce->selectmode==0) {
+ sce->selectmode= SCE_SELECT_VERTEX;
+ set_zbuf_sel= 1;
+ }
+ }
+ for (sc= main->screen.first; sc; sc= sc->id.next) {
+ ScrArea *sa;
+ for (sa= sc->areabase.first; sa; sa= sa->next) {
+ SpaceLink *sl;
+ for (sl= sa->spacedata.first; sl; sl= sl->next) {
+ if(sl->spacetype==SPACE_VIEW3D) {
+ View3D *v3d= (View3D *)sl;
+ if(set_zbuf_sel) v3d->flag |= V3D_ZBUF_SELECT;
+ }
+ else if(sl->spacetype==SPACE_TEXT) {
+ SpaceText *st= (SpaceText *)sl;
+ if(st->tabnumber==0) st->tabnumber= 2;
+ }
+ }
+ }
+ }
+ }
+ if(main->versionfile <= 235) {
+ Tex *tex= main->tex.first;
+ Scene *sce= main->scene.first;
+ Sequence *seq;
+ Editing *ed;
+
+ while(tex) {
+ if(tex->nabla==0.0) tex->nabla= 0.025f;
+ tex= tex->id.next;
+ }
+ while(sce) {
+ ed= sce->ed;
+ if(ed) {
+ WHILE_SEQ(&ed->seqbase) {
+ if(seq->type==SEQ_IMAGE || seq->type==SEQ_MOVIE) seq->flag |= SEQ_MAKE_PREMUL;
+ }
+ END_SEQ
+ }
+
+ sce= sce->id.next;
+ }
+ }
+ if(main->versionfile <= 236) {
+ Object *ob;
+ Scene *sce= main->scene.first;
+ Camera *cam= main->camera.first;
+ Material *ma;
+ bScreen *sc;
+
+ while(sce) {
+ if(sce->editbutsize==0.0) sce->editbutsize= 0.1f;
+
+ sce= sce->id.next;
+ }
+ while(cam) {
+ if(cam->ortho_scale==0.0) {
+ cam->ortho_scale= 256.0f/cam->lens;
+ if(cam->type==CAM_ORTHO) printf("NOTE: ortho render has changed, tweak new Camera 'scale' value.\n");
+ }
+ cam= cam->id.next;
+ }
+ /* set manipulator type */
+ /* force oops draw if depgraph was set*/
+ /* set time line var */
+ for (sc= main->screen.first; sc; sc= sc->id.next) {
+ ScrArea *sa;
+ for (sa= sc->areabase.first; sa; sa= sa->next) {
+ SpaceLink *sl;
+ for (sl= sa->spacedata.first; sl; sl= sl->next) {
+ if(sl->spacetype==SPACE_VIEW3D) {
+ View3D *v3d= (View3D *)sl;
+ if(v3d->twtype==0) v3d->twtype= V3D_MANIP_TRANSLATE;
+ }
+#ifndef SHOWDEPGRAPH
+ else if(sl->spacetype==SPACE_OOPS) {
+ if ( ((SpaceOops *)sl)->type==SO_DEPSGRAPH)
+ ((SpaceOops *)sl)->type=SO_OOPS;
+ }
+#endif
+ else if(sl->spacetype==SPACE_TIME) {
+ SpaceTime *stime= (SpaceTime *)sl;
+ if(stime->redraws==0)
+ stime->redraws= TIME_ALL_3D_WIN|TIME_ALL_ANIM_WIN;
+ }
+ }
+ }
+ }
+ // init new shader vars
+ for (ma= main->mat.first; ma; ma= ma->id.next) {
+ if(ma->darkness==0.0) {
+ ma->rms=0.1f;
+ ma->darkness=1.0f;
+ }
+ }
+
+ /* softbody init new vars */
+ for(ob= main->object.first; ob; ob= ob->id.next) {
+ if(ob->soft) {
+ if(ob->soft->defgoal==0.0) ob->soft->defgoal= 0.7f;
+ if(ob->soft->physics_speed==0.0) ob->soft->physics_speed= 1.0f;
+
+ if(ob->soft->interval==0) {
+ ob->soft->interval= 2;
+ ob->soft->sfra= 1;
+ ob->soft->efra= 100;
+ }
+ }
+ if(ob->soft && ob->soft->vertgroup==0) {
+ bDeformGroup *locGroup = get_named_vertexgroup(ob, "SOFTGOAL");
+ if(locGroup){
+ /* retrieve index for that group */
+ ob->soft->vertgroup = 1 + get_defgroup_num(ob, locGroup);
+ }
+ }
+ }
+ }
+ if(main->versionfile <= 237) {
+ bArmature *arm;
+ bConstraint *con;
+ Object *ob;
+
+ // armature recode checks
+ for(arm= main->armature.first; arm; arm= arm->id.next) {
+ where_is_armature(arm);
+ }
+ for(ob= main->object.first; ob; ob= ob->id.next) {
+ if(ob->parent) {
+ Object *parent= newlibadr(fd, lib, ob->parent);
+ if (parent && parent->type==OB_LATTICE)
+ ob->partype = PARSKEL;
+ }
+
+ // btw. armature_rebuild_pose is further only called on leave editmode
+ if(ob->type==OB_ARMATURE) {
+ if(ob->pose)
+ ob->pose->flag |= POSE_RECALC;
+ ob->recalc |= OB_RECALC; // cannot call stuff now (pointers!), done in setup_app_data
+
+ /* new generic xray option */
+ arm= newlibadr(fd, lib, ob->data);
+ if(arm->flag & ARM_DRAWXRAY) {
+ ob->dtx |= OB_DRAWXRAY;
+ }
+ } else if (ob->type==OB_MESH) {
+ Mesh *me = newlibadr(fd, lib, ob->data);
+
+ if ((me->flag&ME_SUBSURF)) {
+ SubsurfModifierData *smd = (SubsurfModifierData*) modifier_new(eModifierType_Subsurf);
+
+ smd->levels = MAX2(1, me->subdiv);
+ smd->renderLevels = MAX2(1, me->subdivr);
+ smd->subdivType = me->subsurftype;
+
+ smd->modifier.mode = 0;
+ if (me->subdiv!=0)
+ smd->modifier.mode |= 1;
+ if (me->subdivr!=0)
+ smd->modifier.mode |= 2;
+ if (me->flag&ME_OPT_EDGES)
+ smd->flags |= eSubsurfModifierFlag_ControlEdges;
+
+ BLI_addtail(&ob->modifiers, smd);
+ }
+ }
+
+ // follow path constraint needs to set the 'path' option in curves...
+ for(con=ob->constraints.first; con; con= con->next) {
+ if(con->type==CONSTRAINT_TYPE_FOLLOWPATH) {
+ bFollowPathConstraint *data = con->data;
+ Object *obc= newlibadr(fd, lib, data->tar);
+
+ if(obc && obc->type==OB_CURVE) {
+ Curve *cu= newlibadr(fd, lib, obc->data);
+ if(cu) cu->flag |= CU_PATH;
+ }
+ }
+ }
+ }
+ }
+ if(main->versionfile <= 238) {
+ Lattice *lt;
+ Object *ob;
+ bArmature *arm;
+ Mesh *me;
+ Key *key;
+ Scene *sce= main->scene.first;
+
+ while(sce){
+ if(sce->toolsettings == NULL){
+ sce->toolsettings = MEM_callocN(sizeof(struct ToolSettings),"Tool Settings Struct");
+ sce->toolsettings->cornertype=0;
+ sce->toolsettings->degr = 90;
+ sce->toolsettings->step = 9;
+ sce->toolsettings->turn = 1;
+ sce->toolsettings->extr_offs = 1;
+ sce->toolsettings->doublimit = 0.001f;
+ sce->toolsettings->segments = 32;
+ sce->toolsettings->rings = 32;
+ sce->toolsettings->vertices = 32;
+ sce->toolsettings->editbutflag =1;
+ }
+ sce= sce->id.next;
+ }
+
+ for (lt=main->latt.first; lt; lt=lt->id.next) {
+ if (lt->fu==0.0 && lt->fv==0.0 && lt->fw==0.0) {
+ calc_lat_fudu(lt->flag, lt->pntsu, &lt->fu, &lt->du);
+ calc_lat_fudu(lt->flag, lt->pntsv, &lt->fv, &lt->dv);
+ calc_lat_fudu(lt->flag, lt->pntsw, &lt->fw, &lt->dw);
+ }
+ }
+
+ for(ob=main->object.first; ob; ob= ob->id.next) {
+ ModifierData *md;
+ PartEff *paf;
+
+ for (md=ob->modifiers.first; md; md=md->next) {
+ if (md->type==eModifierType_Subsurf) {
+ SubsurfModifierData *smd = (SubsurfModifierData*) md;
+
+ smd->flags &= ~(eSubsurfModifierFlag_Incremental|eSubsurfModifierFlag_DebugIncr);
+ }
+ }
+
+ if ((ob->softflag&OB_SB_ENABLE) && !modifiers_findByType(ob, eModifierType_Softbody)) {
+ if (ob->softflag&OB_SB_POSTDEF) {
+ md = ob->modifiers.first;
+
+ while (md && modifierType_getInfo(md->type)->type==eModifierTypeType_OnlyDeform) {
+ md = md->next;
+ }
+
+ BLI_insertlinkbefore(&ob->modifiers, md, modifier_new(eModifierType_Softbody));
+ } else {
+ BLI_addhead(&ob->modifiers, modifier_new(eModifierType_Softbody));
+ }
+
+ ob->softflag &= ~OB_SB_ENABLE;
+ }
+ if(ob->pose) {
+ bPoseChannel *pchan;
+ bConstraint *con;
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ // note, pchan->bone is also lib-link stuff
+ if (pchan->limitmin[0] == 0.0f && pchan->limitmax[0] == 0.0f) {
+ pchan->limitmin[0]= pchan->limitmin[1]= pchan->limitmin[2]= -180.0f;
+ pchan->limitmax[0]= pchan->limitmax[1]= pchan->limitmax[2]= 180.0f;
+
+ for(con= pchan->constraints.first; con; con= con->next) {
+ if(con->type == CONSTRAINT_TYPE_KINEMATIC) {
+ bKinematicConstraint *data = (bKinematicConstraint*)con->data;
+ data->weight = 1.0f;
+ data->orientweight = 1.0f;
+ data->flag &= ~CONSTRAINT_IK_ROT;
+
+ /* enforce conversion from old IK_TOPARENT to rootbone index */
+ data->rootbone= -1;
+
+ /* update_pose_etc handles rootbone==-1 */
+ ob->pose->flag |= POSE_RECALC;
+ }
+ }
+ }
+ }
+ }
+
+ paf = give_parteff(ob);
+ if (paf) {
+ if(paf->disp == 0)
+ paf->disp = 100;
+ if(paf->speedtex == 0)
+ paf->speedtex = 8;
+ if(paf->omat == 0)
+ paf->omat = 1;
+ }
+ }
+
+ for(arm=main->armature.first; arm; arm= arm->id.next) {
+ bone_version_238(&arm->bonebase);
+ arm->deformflag |= ARM_DEF_VGROUP;
+ }
+
+ for(me=main->mesh.first; me; me= me->id.next) {
+ if (!me->medge) {
+ make_edges(me, 1); /* 1 = use mface->edcode */
+ } else {
+ mesh_strip_loose_faces(me);
+ }
+ }
+
+ for(key= main->key.first; key; key= key->id.next) {
+ KeyBlock *kb;
+ int index= 1;
+
+ /* trick to find out if we already introduced adrcode */
+ for(kb= key->block.first; kb; kb= kb->next)
+ if(kb->adrcode) break;
+
+ if(kb==NULL) {
+ for(kb= key->block.first; kb; kb= kb->next) {
+ if(kb==key->refkey) {
+ if(kb->name[0]==0)
+ strcpy(kb->name, "Basis");
+ }
+ else {
+ if(kb->name[0]==0)
+ sprintf(kb->name, "Key %d", index);
+ kb->adrcode= index++;
+ }
+ }
+ }
+ }
+ }
+ if(main->versionfile <= 239) {
+ bArmature *arm;
+ Object *ob;
+ Scene *sce= main->scene.first;
+ Camera *cam= main->camera.first;
+ Material *ma= main->mat.first;
+ int set_passepartout= 0;
+
+ /* deformflag is local in modifier now */
+ for(ob=main->object.first; ob; ob= ob->id.next) {
+ ModifierData *md;
+
+ for (md=ob->modifiers.first; md; md=md->next) {
+ if (md->type==eModifierType_Armature) {
+ ArmatureModifierData *amd = (ArmatureModifierData*) md;
+ if(amd->object && amd->deformflag==0) {
+ Object *oba= newlibadr(fd, lib, amd->object);
+ bArmature *arm= newlibadr(fd, lib, oba->data);
+ amd->deformflag= arm->deformflag;
+ }
+ }
+ }
+ }
+
+ /* updating stepsize for ghost drawing */
+ for(arm= main->armature.first; arm; arm= arm->id.next) {
+ if (arm->ghostsize==0) arm->ghostsize=1;
+ bone_version_239(&arm->bonebase);
+ if(arm->layer==0) arm->layer= 1;
+ }
+
+ for(;sce;sce= sce->id.next) {
+ /* make 'innervert' the default subdivide type, for backwards compat */
+ sce->toolsettings->cornertype=1;
+
+ if(sce->r.scemode & R_PASSEPARTOUT) {
+ set_passepartout= 1;
+ sce->r.scemode &= ~R_PASSEPARTOUT;
+ }
+ /* gauss is filter variable now */
+ if(sce->r.mode & R_GAUSS) {
+ sce->r.filtertype= R_FILTER_GAUSS;
+ sce->r.mode &= ~R_GAUSS;
+ }
+ }
+
+ for(;cam; cam= cam->id.next) {
+ if(set_passepartout)
+ cam->flag |= CAM_SHOWPASSEPARTOUT;
+
+ /* make sure old cameras have title safe on */
+ if (!(cam->flag & CAM_SHOWTITLESAFE))
+ cam->flag |= CAM_SHOWTITLESAFE;
+
+ /* set an appropriate camera passepartout alpha */
+ if (!(cam->passepartalpha)) cam->passepartalpha = 0.2f;
+ }
+
+ for(; ma; ma= ma->id.next) {
+ if(ma->strand_sta==0.0f) {
+ ma->strand_sta= ma->strand_end= 1.0f;
+ ma->mode |= MA_TANGENT_STR;
+ }
+ if(ma->mode & MA_TRACEBLE) ma->mode |= MA_SHADBUF;
+ }
+ }
+
+ if(main->versionfile <= 241) {
+ Object *ob;
+ Tex *tex;
+ Scene *sce;
+ World *wo;
+ Lamp *la;
+ Material *ma;
+ bArmature *arm;
+ bNodeTree *ntree;
+
+ for (wo = main->world.first; wo; wo= wo->id.next) {
+ /* Migrate to Bullet for games, except for the NaN versions */
+ /* People can still explicitely choose for Sumo (after 2.42 is out) */
+ if(main->versionfile > 225)
+ wo->physicsEngine = WOPHY_BULLET;
+ if(WO_AODIST == wo->aomode)
+ wo->aocolor= WO_AOPLAIN;
+ }
+
+ /* updating layers still */
+ for(arm= main->armature.first; arm; arm= arm->id.next) {
+ bone_version_239(&arm->bonebase);
+ if(arm->layer==0) arm->layer= 1;
+ }
+ for(sce= main->scene.first; sce; sce= sce->id.next) {
+ if(sce->jumpframe==0) sce->jumpframe= 10;
+ if(sce->audio.mixrate==0) sce->audio.mixrate= 44100;
+
+ if(sce->r.xparts<2) sce->r.xparts= 4;
+ if(sce->r.yparts<2) sce->r.yparts= 4;
+ /* adds default layer */
+ if(sce->r.layers.first==NULL)
+ scene_add_render_layer(sce);
+ else {
+ SceneRenderLayer *srl;
+ /* new layer flag for sky, was default for solid */
+ for(srl= sce->r.layers.first; srl; srl= srl->next) {
+ if(srl->layflag & SCE_LAY_SOLID)
+ srl->layflag |= SCE_LAY_SKY;
+ srl->passflag &= (SCE_PASS_COMBINED|SCE_PASS_Z|SCE_PASS_NORMAL|SCE_PASS_VECTOR);
+ }
+ }
+
+ /* node version changes */
+ if(sce->nodetree)
+ ntree_version_241(sce->nodetree);
+
+ /* uv calculation options moved to toolsettings */
+ if (sce->toolsettings->uvcalc_radius == 0.0) {
+ sce->toolsettings->uvcalc_radius = 1.0f;
+ sce->toolsettings->uvcalc_cubesize = 1.0f;
+ sce->toolsettings->uvcalc_mapdir = 1;
+ sce->toolsettings->uvcalc_mapalign = 1;
+ sce->toolsettings->uvcalc_flag = 1;
+ sce->toolsettings->unwrapper = 1;
+ }
+
+ if(sce->r.mode & R_PANORAMA) {
+ /* all these checks to ensure saved files with cvs version keep working... */
+ if(sce->r.xsch < sce->r.ysch) {
+ Object *obc= newlibadr(fd, lib, sce->camera);
+ if(obc && obc->type==OB_CAMERA) {
+ Camera *cam= newlibadr(fd, lib, obc->data);
+ if(cam->lens>=10.0f) {
+ sce->r.xsch*= sce->r.xparts;
+ cam->lens*= (float)sce->r.ysch/(float)sce->r.xsch;
+ }
+ }
+ }
+ }
+ }
+
+ for(ntree= main->nodetree.first; ntree; ntree= ntree->id.next)
+ ntree_version_241(ntree);
+
+ for(la= main->lamp.first; la; la= la->id.next)
+ if(la->buffers==0)
+ la->buffers= 1;
+
+ for(tex= main->tex.first; tex; tex= tex->id.next) {
+ if(tex->env && tex->env->viewscale==0.0f)
+ tex->env->viewscale= 1.0f;
+// tex->imaflag |= TEX_GAUSS_MIP;
+ }
+
+ /* for empty drawsize and drawtype */
+ for(ob=main->object.first; ob; ob= ob->id.next) {
+ if(ob->empty_drawsize==0.0f) {
+ ob->empty_drawtype = OB_ARROWS;
+ ob->empty_drawsize = 1.0;
+ }
+ }
+
+ for(ma= main->mat.first; ma; ma= ma->id.next) {
+ /* stucci returns intensity from now on */
+ int a;
+ for(a=0; a<MAX_MTEX; a++) {
+ if(ma->mtex[a] && ma->mtex[a]->tex) {
+ Tex *tex= newlibadr(fd, lib, ma->mtex[a]->tex);
+ if(tex && tex->type==TEX_STUCCI)
+ ma->mtex[a]->mapto &= ~(MAP_COL|MAP_SPEC|MAP_REF);
+ }
+ }
+ /* transmissivity defaults */
+ if(ma->tx_falloff==0.0) ma->tx_falloff= 1.0;
+ }
+
+ /* during 2.41 images with this name were used for viewer node output, lets fix that */
+ if(main->versionfile == 241) {
+ Image *ima;
+ for(ima= main->image.first; ima; ima= ima->id.next)
+ if(strcmp(ima->name, "Compositor")==0) {
+ strcpy(ima->id.name+2, "Viewer Node");
+ strcpy(ima->name, "Viewer Node");
+ }
+ }
+ }
+
+ if(main->versionfile <= 242) {
+ Scene *sce;
+ bScreen *sc;
+ Object *ob;
+ Curve *cu;
+ Material *ma;
+ Mesh *me;
+ Group *group;
+ Nurb *nu;
+ BezTriple *bezt;
+ BPoint *bp;
+ bNodeTree *ntree;
+ int a;
+
+ for(sc= main->screen.first; sc; sc= sc->id.next) {
+ ScrArea *sa;
+ sa= sc->areabase.first;
+ while(sa) {
+ SpaceLink *sl;
+
+ for (sl= sa->spacedata.first; sl; sl= sl->next) {
+ if(sl->spacetype==SPACE_VIEW3D) {
+ View3D *v3d= (View3D*) sl;
+ if (v3d->gridsubdiv == 0)
+ v3d->gridsubdiv = 10;
+ }
+ }
+ sa = sa->next;
+ }
+ }
+
+ for(sce= main->scene.first; sce; sce= sce->id.next) {
+ if (sce->toolsettings->select_thresh == 0.0f)
+ sce->toolsettings->select_thresh= 0.01f;
+ if (sce->toolsettings->clean_thresh == 0.0f)
+ sce->toolsettings->clean_thresh = 0.1f;
+
+ if (sce->r.threads==0) {
+ if (sce->r.mode & R_THREADS)
+ sce->r.threads= 2;
+ else
+ sce->r.threads= 1;
+ }
+ if(sce->nodetree)
+ ntree_version_242(sce->nodetree);
+ }
+
+ for(ntree= main->nodetree.first; ntree; ntree= ntree->id.next)
+ ntree_version_242(ntree);
+
+ /* add default radius values to old curve points */
+ for(cu= main->curve.first; cu; cu= cu->id.next) {
+ for(nu= cu->nurb.first; nu; nu= nu->next) {
+ if (nu) {
+ if(nu->bezt) {
+ for(bezt=nu->bezt, a=0; a<nu->pntsu; a++, bezt++) {
+ if (!bezt->radius) bezt->radius= 1.0;
+ }
+ }
+ else if(nu->bp) {
+ for(bp=nu->bp, a=0; a<nu->pntsu*nu->pntsv; a++, bp++) {
+ if(!bp->radius) bp->radius= 1.0;
+ }
+ }
+ }
+ }
+ }
+
+ for(ob = main->object.first; ob; ob= ob->id.next) {
+ ModifierData *md;
+ ListBase *list;
+ list = &ob->constraints;
+
+ /* check for already existing MinMax (floor) constraint
+ and update the sticky flagging */
+
+ if (list){
+ bConstraint *curcon;
+ for (curcon = list->first; curcon; curcon=curcon->next){
+ switch (curcon->type) {
+ case CONSTRAINT_TYPE_MINMAX:
+ {
+ bMinMaxConstraint *data = curcon->data;
+ if (data->sticky==1)
+ data->flag |= MINMAX_STICKY;
+ else
+ data->flag &= ~MINMAX_STICKY;
+ }
+ break;
+ case CONSTRAINT_TYPE_ROTLIKE:
+ {
+ bRotateLikeConstraint *data = curcon->data;
+
+ /* version patch from buttons_object.c */
+ if(data->flag==0)
+ data->flag = ROTLIKE_X|ROTLIKE_Y|ROTLIKE_Z;
+ }
+ break;
+ }
+ }
+ }
+
+ if (ob->type == OB_ARMATURE) {
+ if (ob->pose){
+ bConstraint *curcon;
+ bPoseChannel *pchan;
+ for (pchan = ob->pose->chanbase.first; pchan; pchan=pchan->next){
+ for (curcon = pchan->constraints.first; curcon; curcon=curcon->next){
+ switch (curcon->type) {
+ case CONSTRAINT_TYPE_MINMAX:
+ {
+ bMinMaxConstraint *data = curcon->data;
+ if (data->sticky==1)
+ data->flag |= MINMAX_STICKY;
+ else
+ data->flag &= ~MINMAX_STICKY;
+ }
+ break;
+ case CONSTRAINT_TYPE_KINEMATIC:
+ {
+ bKinematicConstraint *data = curcon->data;
+ if (!(data->flag & CONSTRAINT_IK_POS)) {
+ data->flag |= CONSTRAINT_IK_POS;
+ data->flag |= CONSTRAINT_IK_STRETCH;
+ }
+ }
+ break;
+ case CONSTRAINT_TYPE_ROTLIKE:
+ {
+ bRotateLikeConstraint *data = curcon->data;
+
+ /* version patch from buttons_object.c */
+ if(data->flag==0)
+ data->flag = ROTLIKE_X|ROTLIKE_Y|ROTLIKE_Z;
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /* copy old object level track settings to curve modifers */
+ for (md=ob->modifiers.first; md; md=md->next) {
+ if (md->type==eModifierType_Curve) {
+ CurveModifierData *cmd = (CurveModifierData*) md;
+
+ if (cmd->defaxis == 0) cmd->defaxis = ob->trackflag+1;
+ }
+ }
+
+ }
+
+ for(ma = main->mat.first; ma; ma= ma->id.next) {
+ if(ma->shad_alpha==0.0f)
+ ma->shad_alpha= 1.0f;
+ if(ma->nodetree)
+ ntree_version_242(ma->nodetree);
+ }
+
+ for(me=main->mesh.first; me; me=me->id.next)
+ customdata_version_242(me);
+
+ for(group= main->group.first; group; group= group->id.next)
+ if(group->layer==0)
+ group->layer= (1<<20)-1;
+
+ /* History fix (python?), shape key adrcode numbers have to be sorted */
+ sort_shape_fix(main);
+
+ /* now, subversion control! */
+ if(main->subversionfile < 3) {
+ bScreen *sc;
+ Image *ima;
+ Tex *tex;
+
+ /* Image refactor initialize */
+ for(ima= main->image.first; ima; ima= ima->id.next) {
+ ima->source= IMA_SRC_FILE;
+ ima->type= IMA_TYPE_IMAGE;
+
+ ima->gen_x= 256; ima->gen_y= 256;
+ ima->gen_type= 1;
+
+ if(0==strncmp(ima->id.name+2, "Viewer Node", sizeof(ima->id.name+2))) {
+ ima->source= IMA_SRC_VIEWER;
+ ima->type= IMA_TYPE_COMPOSITE;
+ }
+ if(0==strncmp(ima->id.name+2, "Render Result", sizeof(ima->id.name+2))) {
+ ima->source= IMA_SRC_VIEWER;
+ ima->type= IMA_TYPE_R_RESULT;
+ }
+
+ }
+ for(tex= main->tex.first; tex; tex= tex->id.next) {
+ if(tex->type==TEX_IMAGE && tex->ima) {
+ ima= newlibadr(fd, lib, tex->ima);
+ if(tex->imaflag & TEX_ANIM5_)
+ ima->source= IMA_SRC_MOVIE;
+ if(tex->imaflag & TEX_FIELDS_)
+ ima->flag |= IMA_FIELDS;
+ if(tex->imaflag & TEX_STD_FIELD_)
+ ima->flag |= IMA_STD_FIELD;
+ if(tex->imaflag & TEX_ANTIALI_)
+ ima->flag |= IMA_ANTIALI;
+ }
+ tex->iuser.frames= tex->frames;
+ tex->iuser.fie_ima= tex->fie_ima;
+ tex->iuser.offset= tex->offset;
+ tex->iuser.sfra= tex->sfra;
+ tex->iuser.cycl= (tex->imaflag & TEX_ANIMCYCLIC_)!=0;
+ }
+ for(sce= main->scene.first; sce; sce= sce->id.next) {
+ if(sce->nodetree)
+ do_version_ntree_242_2(sce->nodetree);
+ }
+ for(ntree= main->nodetree.first; ntree; ntree= ntree->id.next)
+ do_version_ntree_242_2(ntree);
+ for(ma = main->mat.first; ma; ma= ma->id.next)
+ if(ma->nodetree)
+ do_version_ntree_242_2(ma->nodetree);
+
+ for(sc= main->screen.first; sc; sc= sc->id.next) {
+ ScrArea *sa;
+ for(sa= sc->areabase.first; sa; sa= sa->next) {
+ SpaceLink *sl;
+ for (sl= sa->spacedata.first; sl; sl= sl->next) {
+ if(sl->spacetype==SPACE_IMAGE)
+ ((SpaceImage *)sl)->iuser.fie_ima= 2;
+ else if(sl->spacetype==SPACE_VIEW3D) {
+ View3D *v3d= (View3D *)sl;
+ if(v3d->bgpic)
+ v3d->bgpic->iuser.fie_ima= 2;
+ }
+ }
+ }
+ }
+ }
+
+ if(main->subversionfile < 4) {
+ for(sce= main->scene.first; sce; sce= sce->id.next) {
+ sce->r.bake_mode= 1; /* prevent to include render stuff here */
+ sce->r.bake_filter= 2;
+ sce->r.bake_osa= 5;
+ sce->r.bake_flag= R_BAKE_CLEAR;
+ }
+ }
+
+ if(main->subversionfile < 5) {
+ for(sce= main->scene.first; sce; sce= sce->id.next) {
+ /* improved triangle to quad conversion settings */
+ if(sce->toolsettings->jointrilimit==0.0f)
+ sce->toolsettings->jointrilimit= 0.8f;
+ }
+ }
+ }
+ if(main->versionfile <= 243) {
+ Object *ob= main->object.first;
+ Camera *cam = main->camera.first;
+ Material *ma;
+
+ for(; cam; cam= cam->id.next) {
+ cam->angle= 360.0f * atan(16.0f/cam->lens) / M_PI;
+ }
+
+ for(ma=main->mat.first; ma; ma= ma->id.next) {
+ if(ma->sss_scale==0.0f) {
+ ma->sss_radius[0]= 1.0f;
+ ma->sss_radius[1]= 1.0f;
+ ma->sss_radius[2]= 1.0f;
+ ma->sss_col[0]= 0.8f;
+ ma->sss_col[1]= 0.8f;
+ ma->sss_col[2]= 0.8f;
+ ma->sss_error= 0.05f;
+ ma->sss_scale= 0.1f;
+ ma->sss_ior= 1.3f;
+ ma->sss_colfac= 1.0f;
+ ma->sss_texfac= 0.0f;
+ }
+ if(ma->sss_front==0 && ma->sss_back==0) {
+ ma->sss_front= 1.0f;
+ ma->sss_back= 1.0f;
+ }
+ if(ma->sss_col[0]==0 && ma->sss_col[1]==0 && ma->sss_col[2]==0) {
+ ma->sss_col[0]= ma->r;
+ ma->sss_col[1]= ma->g;
+ ma->sss_col[2]= ma->b;
+ }
+ }
+
+ for(; ob; ob= ob->id.next) {
+ bDeformGroup *curdef;
+
+ for(curdef= ob->defbase.first; curdef; curdef=curdef->next) {
+ /* replace an empty-string name with unique name */
+ if (curdef->name[0] == '\0') {
+ unique_vertexgroup_name(curdef, ob);
+ }
+ }
+
+ if(main->versionfile < 243 || main->subversionfile < 1) {
+ ModifierData *md;
+
+ /* translate old mirror modifier axis values to new flags */
+ for (md=ob->modifiers.first; md; md=md->next) {
+ if (md->type==eModifierType_Mirror) {
+ MirrorModifierData *mmd = (MirrorModifierData*) md;
+
+ switch(mmd->axis)
+ {
+ case 0:
+ mmd->flag |= MOD_MIR_AXIS_X;
+ break;
+ case 1:
+ mmd->flag |= MOD_MIR_AXIS_Y;
+ break;
+ case 2:
+ mmd->flag |= MOD_MIR_AXIS_Z;
+ break;
+ }
+
+ mmd->axis = 0;
+ }
+ }
+ }
+ }
+
+ /* render layer added, this is not the active layer */
+ if(main->versionfile <= 243 || main->subversionfile < 2) {
+ Mesh *me;
+ for(me=main->mesh.first; me; me=me->id.next)
+ customdata_version_243(me);
+ }
+
+ }
+
+ if(main->versionfile <= 244) {
+ Scene *sce;
+ bScreen *sc;
+ Lamp *la;
+ World *wrld;
+
+ if(main->versionfile != 244 || main->subversionfile < 2) {
+ Mesh *me;
+
+ for(sce= main->scene.first; sce; sce= sce->id.next)
+ sce->r.mode |= R_SSS;
+
+ /* Copy over old per-level multires vertex data
+ into a single vertex array in struct Multires */
+
+ for(me = main->mesh.first; me; me=me->id.next) {
+ if(me->mr) {
+ MultiresLevel *lvl = me->mr->levels.last;
+ if(lvl) {
+ me->mr->verts = lvl->verts;
+ lvl->verts = NULL;
+ /* Don't need the other vert arrays */
+ for(lvl = lvl->prev; lvl; lvl = lvl->prev) {
+ MEM_freeN(lvl->verts);
+ lvl->verts = NULL;
+ }
+ }
+ }
+ }
+
+ /* correct older action editors - incorrect scrolling */
+ for(sc= main->screen.first; sc; sc= sc->id.next) {
+ ScrArea *sa;
+ sa= sc->areabase.first;
+ while(sa) {
+ SpaceLink *sl;
+
+ for (sl= sa->spacedata.first; sl; sl= sl->next) {
+ if(sl->spacetype==SPACE_ACTION) {
+ SpaceAction *saction= (SpaceAction*) sl;
+
+ saction->v2d.tot.ymin= -1000.0;
+ saction->v2d.tot.ymax= 0.0;
+
+ saction->v2d.cur.ymin= -75.0;
+ saction->v2d.cur.ymax= 5.0;
+ }
+ }
+ sa = sa->next;
+ }
+ }
+ }
+ if (main->versionfile != 244 || main->subversionfile < 3) {
+ /* constraints recode version patch used to be here. Moved to 245 now... */
+
+
+ for(wrld=main->world.first; wrld; wrld= wrld->id.next) {
+ if (wrld->mode & WO_AMB_OCC)
+ wrld->ao_samp_method = WO_AOSAMP_CONSTANT;
+ else
+ wrld->ao_samp_method = WO_AOSAMP_HAMMERSLEY;
+
+ wrld->ao_adapt_thresh = 0.005;
+ }
+
+ for(la=main->lamp.first; la; la= la->id.next) {
+ if (la->type == LA_AREA)
+ la->ray_samp_method = LA_SAMP_CONSTANT;
+ else
+ la->ray_samp_method = LA_SAMP_HALTON;
+
+ la->adapt_thresh = 0.001;
+ }
+ }
+ }
+ if(main->versionfile <= 245) {
+ bScreen *sc;
+ Object *ob;
+ Image *ima;
+ Lamp *la;
+ Material *ma;
+
+ /* unless the file was created 2.44.3 but not 2.45, update the constraints */
+ if ( !(main->versionfile==244 && main->subversionfile==3) &&
+ ((main->versionfile<245) || (main->versionfile==245 && main->subversionfile==0)) )
+ {
+ for (ob = main->object.first; ob; ob= ob->id.next) {
+ ListBase *list;
+ list = &ob->constraints;
+
+ /* fix up constraints due to constraint recode changes (originally at 2.44.3) */
+ if (list) {
+ bConstraint *curcon;
+ for (curcon = list->first; curcon; curcon=curcon->next) {
+ /* old CONSTRAINT_LOCAL check -> convert to CONSTRAINT_SPACE_LOCAL */
+ if (curcon->flag & 0x20) {
+ curcon->ownspace = CONSTRAINT_SPACE_LOCAL;
+ curcon->tarspace = CONSTRAINT_SPACE_LOCAL;
+ }
+
+ switch (curcon->type) {
+ case CONSTRAINT_TYPE_LOCLIMIT:
+ {
+ bLocLimitConstraint *data= (bLocLimitConstraint *)curcon->data;
+
+ /* old limit without parent option for objects */
+ if (data->flag2)
+ curcon->ownspace = CONSTRAINT_SPACE_LOCAL;
+ }
+ break;
+ case CONSTRAINT_TYPE_STRETCHTO:
+ {
+ bStretchToConstraint *data= (bStretchToConstraint *)curcon->data;
+
+ /* force recalc of rest-length */
+ data->orglength = 0;
+ }
+ break;
+ }
+ }
+ }
+
+ /* correctly initialise constinv matrix */
+ Mat4One(ob->constinv);
+
+ if (ob->type == OB_ARMATURE) {
+ if (ob->pose) {
+ bConstraint *curcon;
+ bPoseChannel *pchan;
+
+ for (pchan = ob->pose->chanbase.first; pchan; pchan=pchan->next) {
+ /* make sure constraints are all up to date */
+ for (curcon = pchan->constraints.first; curcon; curcon=curcon->next) {
+ /* old CONSTRAINT_LOCAL check -> convert to CONSTRAINT_SPACE_LOCAL */
+ if (curcon->flag & 0x20) {
+ curcon->ownspace = CONSTRAINT_SPACE_LOCAL;
+ curcon->tarspace = CONSTRAINT_SPACE_LOCAL;
+ }
+
+ switch (curcon->type) {
+ case CONSTRAINT_TYPE_ACTION:
+ {
+ bActionConstraint *data= (bActionConstraint *)curcon->data;
+
+ /* 'data->local' used to mean that target was in local-space */
+ if (data->local)
+ curcon->tarspace = CONSTRAINT_SPACE_LOCAL;
+ }
+ break;
+ case CONSTRAINT_TYPE_STRETCHTO:
+ {
+ bStretchToConstraint *data= (bStretchToConstraint *)curcon->data;
+
+ /* force recalc of rest-length */
+ data->orglength = 0;
+ }
+ break;
+ }
+ }
+
+ /* correctly initialise constinv matrix */
+ Mat4One(pchan->constinv);
+ }
+ }
+ }
+ }
+ }
+
+ /* fix all versions before 2.45 */
+ if (main->versionfile != 245) {
+
+ /* repair preview from 242 - 244*/
+ for(ima= main->image.first; ima; ima= ima->id.next) {
+ ima->preview = NULL;
+ }
+
+ /* repair imasel space - completely reworked */
+ for(sc= main->screen.first; sc; sc= sc->id.next) {
+ ScrArea *sa;
+ sa= sc->areabase.first;
+ while(sa) {
+ SpaceLink *sl;
+
+ for (sl= sa->spacedata.first; sl; sl= sl->next) {
+ if(sl->spacetype==SPACE_IMASEL) {
+ SpaceImaSel *simasel= (SpaceImaSel*) sl;
+ simasel->blockscale= 0.7;
+ /* view 2D */
+ simasel->v2d.tot.xmin= -10.0;
+ simasel->v2d.tot.ymin= -10.0;
+ simasel->v2d.tot.xmax= (float)sa->winx + 10.0f;
+ simasel->v2d.tot.ymax= (float)sa->winy + 10.0f;
+ simasel->v2d.cur.xmin= 0.0;
+ simasel->v2d.cur.ymin= 0.0;
+ simasel->v2d.cur.xmax= (float)sa->winx;
+ simasel->v2d.cur.ymax= (float)sa->winy;
+ simasel->v2d.min[0]= 1.0;
+ simasel->v2d.min[1]= 1.0;
+ simasel->v2d.max[0]= 32000.0f;
+ simasel->v2d.max[1]= 32000.0f;
+ simasel->v2d.minzoom= 0.5f;
+ simasel->v2d.maxzoom= 1.21f;
+ simasel->v2d.scroll= 0;
+ simasel->v2d.keepaspect= 1;
+ simasel->v2d.keepzoom= 1;
+ simasel->v2d.keeptot= 0;
+ simasel->prv_h = 96;
+ simasel->prv_w = 96;
+ simasel->flag = 7; /* ??? elubie */
+ strcpy (simasel->dir, U.textudir); /* TON */
+ strcpy (simasel->file, "");
+
+ simasel->returnfunc = 0;
+ simasel->title[0] = 0;
+ }
+ }
+ sa = sa->next;
+ }
+ }
+ }
+
+ if (main->versionfile != 245 || main->subversionfile < 1) {
+ for(la=main->lamp.first; la; la= la->id.next) {
+ if (la->mode & LA_QUAD) la->falloff_type = LA_FALLOFF_SLIDERS;
+ else la->falloff_type = LA_FALLOFF_INVLINEAR;
+
+ if (la->curfalloff == NULL) {
+ la->curfalloff = curvemapping_add(1, 0.0f, 1.0f, 1.0f, 0.0f);
+ curvemapping_initialize(la->curfalloff);
+ }
+ }
+ }
+
+ for(ma=main->mat.first; ma; ma= ma->id.next) {
+ if (ma->samp_gloss_mir == 0) {
+ ma->gloss_mir = ma->gloss_tra= 1.0;
+ ma->aniso_gloss_mir = 1.0;
+ ma->samp_gloss_mir = ma->samp_gloss_tra= 18;
+ ma->adapt_thresh_mir = ma->adapt_thresh_tra = 0.005;
+ ma->dist_mir = 0.0;
+ ma->fadeto_mir = MA_RAYMIR_FADETOSKY;
+ }
+ }
+
+ }
+
+ if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 2)) {
+ Image *ima;
+
+ /* initialize 1:1 Aspect */
+ for(ima= main->image.first; ima; ima= ima->id.next) {
+ ima->aspx = ima->aspy = 1.0f;
+ }
+
+ }
+
+ if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 4)) {
+ bArmature *arm;
+ ModifierData *md;
+ Object *ob;
+
+ for(arm= main->armature.first; arm; arm= arm->id.next)
+ arm->deformflag |= ARM_DEF_B_BONE_REST;
+
+ for(ob = main->object.first; ob; ob= ob->id.next) {
+ for(md=ob->modifiers.first; md; md=md->next) {
+ if(md->type==eModifierType_Armature)
+ ((ArmatureModifierData*)md)->deformflag |= ARM_DEF_B_BONE_REST;
+ }
+ }
+ }
+
+ if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 5)) {
+ /* foreground color needs to be somthing other then black */
+ Scene *sce;
+ for(sce= main->scene.first; sce; sce=sce->id.next) {
+ sce->r.fg_stamp[0] = sce->r.fg_stamp[1] = sce->r.fg_stamp[2] = 0.8;
+ sce->r.fg_stamp[3] = 1.0; /* dont use text alpha yet */
+ sce->r.bg_stamp[3] = 0.25; /* make sure the background has full alpha */
+ }
+ }
+
+
+ if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 6)) {
+ Scene *sce;
+ /* fix frs_sec_base */
+ for(sce= main->scene.first; sce; sce= sce->id.next) {
+ if (sce->r.frs_sec_base == 0) {
+ sce->r.frs_sec_base = 1;
+ }
+ }
+ }
+
+ if ((main->versionfile < 245) || (main->versionfile == 245 && main->subversionfile < 7)) {
+ Object *ob;
+ bPoseChannel *pchan;
+ bConstraint *con;
+ bConstraintTarget *ct;
+
+ for(ob = main->object.first; ob; ob= ob->id.next) {
+ if(ob->pose) {
+ for(pchan=ob->pose->chanbase.first; pchan; pchan=pchan->next) {
+ for(con=pchan->constraints.first; con; con=con->next) {
+ if(con->type==CONSTRAINT_TYPE_PYTHON) {
+ bPythonConstraint *data= (bPythonConstraint *)con->data;
+ if (data->tar) {
+ /* version patching needs to be done */
+ ct= MEM_callocN(sizeof(bConstraintTarget), "PyConTarget");
+
+ ct->tar = data->tar;
+ strcpy(ct->subtarget, data->subtarget);
+ ct->space = con->tarspace;
+
+ BLI_addtail(&data->targets, ct);
+ data->tarnum++;
+
+ /* clear old targets to avoid problems */
+ data->tar = NULL;
+ strcpy(data->subtarget, "");
+ }
+ }
+ }
+ }
+ }
+
+ for(con=ob->constraints.first; con; con=con->next) {
+ if(con->type==CONSTRAINT_TYPE_PYTHON) {
+ bPythonConstraint *data= (bPythonConstraint *)con->data;
+ if (data->tar) {
+ /* version patching needs to be done */
+ ct= MEM_callocN(sizeof(bConstraintTarget), "PyConTarget");
+
+ ct->tar = data->tar;
+ strcpy(ct->subtarget, data->subtarget);
+ ct->space = con->tarspace;
+
+ BLI_addtail(&data->targets, ct);
+ data->tarnum++;
+
+ /* clear old targets to avoid problems */
+ data->tar = NULL;
+ strcpy(data->subtarget, "");
+ }
+ }
+ }
+ }
+ }
+
+
+ /* WATCH IT!!!: pointers from libdata have not been converted yet here! */
+ /* WATCH IT 2!: Userdef struct init has to be in src/usiblender.c! */
+
+ /* don't forget to set version number in blender.c! */
+}
+
+static void lib_link_all(FileData *fd, Main *main)
+{
+ oldnewmap_sort(fd);
+
+ lib_link_screen(fd, main);
+ lib_link_scene(fd, main);
+ lib_link_object(fd, main);
+ lib_link_curve(fd, main);
+ lib_link_mball(fd, main);
+ lib_link_material(fd, main);
+ lib_link_texture(fd, main);
+ lib_link_image(fd, main);
+ lib_link_ipo(fd, main);
+ lib_link_key(fd, main);
+ lib_link_world(fd, main);
+ lib_link_lamp(fd, main);
+ lib_link_latt(fd, main);
+ lib_link_text(fd, main);
+ lib_link_camera(fd, main);
+ lib_link_sound(fd, main);
+ lib_link_group(fd, main);
+ lib_link_armature(fd, main);
+ lib_link_action(fd, main);
+ lib_link_vfont(fd, main);
+ lib_link_screen_sequence_ipos(main);
+ lib_link_nodetree(fd, main); /* has to be done after scene/materials, this will verify group nodes */
+ lib_link_brush(fd, main);
+
+ lib_link_mesh(fd, main); /* as last: tpage images with users at zero */
+
+ lib_link_library(fd, main); /* only init users */
+}
+
+static BHead *read_userdef(BlendFileData *bfd, FileData *fd, BHead *bhead)
+{
+ Link *link;
+
+ bfd->user= read_struct(fd, bhead, "user def");
+ bfd->user->themes.first= bfd->user->themes.last= NULL;
+
+ bhead = blo_nextbhead(fd, bhead);
+
+ /* read all attached data */
+ while(bhead && bhead->code==DATA) {
+ link= read_struct(fd, bhead, "user def data");
+ BLI_addtail(&bfd->user->themes, link);
+ bhead = blo_nextbhead(fd, bhead);
+ }
+
+ return bhead;
+}
+
+BlendFileData *blo_read_file_internal(FileData *fd, BlendReadError *error_r)
+{
+ BHead *bhead= blo_firstbhead(fd);
+ BlendFileData *bfd;
+ FileGlobal *fg = (FileGlobal *)NULL;
+
+ bfd= MEM_callocN(sizeof(BlendFileData), "blendfiledata");
+ bfd->main= MEM_callocN(sizeof(Main), "main");
+ BLI_addtail(&fd->mainlist, bfd->main);
+
+ bfd->main->versionfile= fd->fileversion;
+
+ while(bhead) {
+ switch(bhead->code) {
+ case GLOB:
+ case DATA:
+ case DNA1:
+ case TEST:
+ case REND:
+ if (bhead->code==GLOB) {
+ fg= read_struct(fd, bhead, "Global");
+ /* set right away */
+ bfd->main->subversionfile= fg->subversion;
+ bfd->main->minversionfile= fg->minversion;
+ bfd->main->minsubversionfile= fg->minsubversion;
+ }
+ bhead = blo_nextbhead(fd, bhead);
+ break;
+ case USER:
+ bhead= read_userdef(bfd, fd, bhead);
+ break;
+ case ENDB:
+ bhead = NULL;
+ break;
+
+ case ID_LI:
+ bhead = read_libblock(fd, bfd->main, bhead, LIB_LOCAL, NULL);
+ break;
+ case ID_ID:
+ /* always adds to the most recently loaded
+ * ID_LI block, see direct_link_library.
+ * this is part of the file format definition.
+ */
+ bhead = read_libblock(fd, fd->mainlist.last, bhead, LIB_READ+LIB_EXTERN, NULL);
+ break;
+
+ default:
+ bhead = read_libblock(fd, bfd->main, bhead, LIB_LOCAL, NULL);
+ }
+ }
+
+ /* do before read_libraries, but skip undo case */
+// if(fd->memfile==NULL) (the mesh shuffle hacks don't work yet? ton)
+ do_versions(fd, NULL, bfd->main);
+
+ read_libraries(fd, &fd->mainlist);
+
+ blo_join_main(&fd->mainlist);
+
+ lib_link_all(fd, bfd->main);
+ lib_verify_nodetree(bfd->main);
+
+ if(fg)
+ link_global(fd, bfd, fg); /* as last */
+
+ /* removed here: check for existance of curscreen/scene, moved to kernel setup_app */
+ MEM_freeN(fg);
+
+ return bfd;
+}
+
+/* ************* APPEND LIBRARY ************** */
+
+static BHead *find_previous_lib(FileData *fd, BHead *bhead)
+{
+ for (; bhead; bhead= blo_prevbhead(fd, bhead))
+ if (bhead->code==ID_LI)
+ break;
+
+ return bhead;
+}
+
+static BHead *find_bhead(FileData *fd, void *old)
+{
+ BHead *bhead;
+
+ if (!old)
+ return NULL;
+
+ for (bhead= blo_firstbhead(fd); bhead; bhead= blo_nextbhead(fd, bhead))
+ if (bhead->old==old)
+ return bhead;
+
+ return NULL;
+}
+
+char *bhead_id_name(FileData *fd, BHead *bhead)
+{
+ return ((char *)(bhead+1)) + fd->id_name_offs;
+}
+
+static ID *is_yet_read(FileData *fd, Main *mainvar, BHead *bhead)
+{
+ ListBase *lb;
+ char *idname= bhead_id_name(fd, bhead);
+
+ lb= wich_libbase(mainvar, GS(idname));
+
+ if(lb) {
+ ID *id= lb->first;
+ while(id) {
+ if( strcmp(id->name, idname)==0 )
+ return id;
+ id= id->next;
+ }
+ }
+ return NULL;
+}
+
+static void expand_doit(FileData *fd, Main *mainvar, void *old)
+{
+ BHead *bhead;
+ ID *id;
+
+ bhead= find_bhead(fd, old);
+ if(bhead) {
+ /* from another library? */
+ if(bhead->code==ID_ID) {
+ BHead *bheadlib= find_previous_lib(fd, bhead);
+
+ if(bheadlib) {
+ Library *lib= read_struct(fd, bheadlib, "Library");
+ Main *ptr= blo_find_main(&fd->mainlist, lib->name, fd->filename);
+
+ id= is_yet_read(fd, ptr, bhead);
+
+ if(id==NULL) {
+ read_libblock(fd, ptr, bhead, LIB_READ+LIB_INDIRECT, NULL);
+ if(G.f & G_DEBUG) printf("expand_doit: other lib %s\n", lib->name);
+
+ /* for outliner dependency only */
+ ptr->curlib->parent= mainvar->curlib;
+ }
+ else {
+ //oldnewmap_insert(fd->libmap, bhead->old, id, 1);
+
+ change_idid_adr_fd(fd, bhead->old, id);
+ if(G.f & G_DEBUG) printf("expand_doit: already linked: %s lib: %s\n", id->name, lib->name);
+ }
+
+ MEM_freeN(lib);
+ }
+ }
+ else {
+ id= is_yet_read(fd, mainvar, bhead);
+ if(id==NULL) {
+ read_libblock(fd, mainvar, bhead, LIB_TESTIND, NULL);
+ }
+ else {
+ /* this is actually only needed on UI call? when ID was already read before, and another append
+ happens which invokes same ID... in that case the lookup table needs this entry */
+ oldnewmap_insert(fd->libmap, bhead->old, id, 1);
+ if(G.f & G_DEBUG) printf("expand: already read %s\n", id->name);
+ }
+ }
+ }
+}
+
+static void expand_ipo(FileData *fd, Main *mainvar, Ipo *ipo)
+{
+ IpoCurve *icu;
+ for(icu= ipo->curve.first; icu; icu= icu->next) {
+ if(icu->driver)
+ expand_doit(fd, mainvar, icu->driver->ob);
+ }
+}
+
+static void expand_group(FileData *fd, Main *mainvar, Group *group)
+{
+ GroupObject *go;
+
+ for(go= group->gobject.first; go; go= go->next) {
+ expand_doit(fd, mainvar, go->ob);
+ }
+}
+
+static void expand_key(FileData *fd, Main *mainvar, Key *key)
+{
+ expand_doit(fd, mainvar, key->ipo);
+}
+
+
+static void expand_texture(FileData *fd, Main *mainvar, Tex *tex)
+{
+ expand_doit(fd, mainvar, tex->ima);
+ expand_doit(fd, mainvar, tex->ipo);
+}
+
+static void expand_brush(FileData *fd, Main *mainvar, Brush *brush)
+{
+ int a;
+
+ for(a=0; a<MAX_MTEX; a++)
+ if(brush->mtex[a])
+ expand_doit(fd, mainvar, brush->mtex[a]->tex);
+ expand_doit(fd, mainvar, brush->clone.image);
+}
+
+static void expand_nodetree(FileData *fd, Main *mainvar, bNodeTree *ntree)
+{
+ bNode *node;
+
+ for(node= ntree->nodes.first; node; node= node->next)
+ if(node->id && node->type!=CMP_NODE_R_LAYERS)
+ expand_doit(fd, mainvar, node->id);
+
+}
+
+static void expand_material(FileData *fd, Main *mainvar, Material *ma)
+{
+ int a;
+
+ for(a=0; a<MAX_MTEX; a++) {
+ if(ma->mtex[a]) {
+ expand_doit(fd, mainvar, ma->mtex[a]->tex);
+ expand_doit(fd, mainvar, ma->mtex[a]->object);
+ }
+ }
+
+ expand_doit(fd, mainvar, ma->ipo);
+
+ if(ma->nodetree)
+ expand_nodetree(fd, mainvar, ma->nodetree);
+}
+
+static void expand_lamp(FileData *fd, Main *mainvar, Lamp *la)
+{
+ int a;
+
+ for(a=0; a<MAX_MTEX; a++) {
+ if(la->mtex[a]) {
+ expand_doit(fd, mainvar, la->mtex[a]->tex);
+ expand_doit(fd, mainvar, la->mtex[a]->object);
+ }
+ }
+ expand_doit(fd, mainvar, la->ipo);
+}
+
+static void expand_lattice(FileData *fd, Main *mainvar, Lattice *lt)
+{
+ expand_doit(fd, mainvar, lt->ipo);
+ expand_doit(fd, mainvar, lt->key);
+}
+
+
+static void expand_world(FileData *fd, Main *mainvar, World *wrld)
+{
+ int a;
+
+ for(a=0; a<MAX_MTEX; a++) {
+ if(wrld->mtex[a]) {
+ expand_doit(fd, mainvar, wrld->mtex[a]->tex);
+ expand_doit(fd, mainvar, wrld->mtex[a]->object);
+ }
+ }
+ expand_doit(fd, mainvar, wrld->ipo);
+}
+
+
+static void expand_mball(FileData *fd, Main *mainvar, MetaBall *mb)
+{
+ int a;
+
+ for(a=0; a<mb->totcol; a++) {
+ expand_doit(fd, mainvar, mb->mat[a]);
+ }
+}
+
+static void expand_curve(FileData *fd, Main *mainvar, Curve *cu)
+{
+ int a;
+
+ for(a=0; a<cu->totcol; a++) {
+ expand_doit(fd, mainvar, cu->mat[a]);
+ }
+ expand_doit(fd, mainvar, cu->vfont);
+ expand_doit(fd, mainvar, cu->vfontb);
+ expand_doit(fd, mainvar, cu->vfonti);
+ expand_doit(fd, mainvar, cu->vfontbi);
+ expand_doit(fd, mainvar, cu->key);
+ expand_doit(fd, mainvar, cu->ipo);
+ expand_doit(fd, mainvar, cu->bevobj);
+ expand_doit(fd, mainvar, cu->taperobj);
+ expand_doit(fd, mainvar, cu->textoncurve);
+}
+
+static void expand_mesh(FileData *fd, Main *mainvar, Mesh *me)
+{
+ CustomDataLayer *layer;
+ MTFace *mtf;
+ TFace *tf;
+ int a, i;
+
+ for(a=0; a<me->totcol; a++) {
+ expand_doit(fd, mainvar, me->mat[a]);
+ }
+
+ expand_doit(fd, mainvar, me->key);
+ expand_doit(fd, mainvar, me->texcomesh);
+
+ if(me->tface) {
+ tf= me->tface;
+ for(i=0; i<me->totface; i++, tf++)
+ if(tf->tpage)
+ expand_doit(fd, mainvar, tf->tpage);
+ }
+
+ for(a=0; a<me->fdata.totlayer; a++) {
+ layer= &me->fdata.layers[a];
+
+ if(layer->type == CD_MTFACE) {
+ mtf= (MTFace*)layer->data;
+ for(i=0; i<me->totface; i++, mtf++)
+ if(mtf->tpage)
+ expand_doit(fd, mainvar, mtf->tpage);
+ }
+ }
+}
+
+static void expand_constraints(FileData *fd, Main *mainvar, ListBase *lb)
+{
+ bConstraint *curcon;
+
+ for (curcon=lb->first; curcon; curcon=curcon->next) {
+ switch (curcon->type) {
+ case CONSTRAINT_TYPE_NULL:
+ break;
+ case CONSTRAINT_TYPE_PYTHON:
+ {
+ bPythonConstraint *data = (bPythonConstraint*)curcon->data;
+ bConstraintTarget *ct;
+
+ for (ct= data->targets.first; ct; ct= ct->next)
+ expand_doit(fd, mainvar, ct->tar);
+
+ expand_doit(fd, mainvar, data->text);
+ }
+ break;
+ case CONSTRAINT_TYPE_ACTION:
+ {
+ bActionConstraint *data = (bActionConstraint*)curcon->data;
+ expand_doit(fd, mainvar, data->tar);
+ expand_doit(fd, mainvar, data->act);
+ }
+ break;
+ case CONSTRAINT_TYPE_LOCLIKE:
+ {
+ bLocateLikeConstraint *data = (bLocateLikeConstraint*)curcon->data;
+ expand_doit(fd, mainvar, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_ROTLIKE:
+ {
+ bRotateLikeConstraint *data = (bRotateLikeConstraint*)curcon->data;
+ expand_doit(fd, mainvar, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_SIZELIKE:
+ {
+ bSizeLikeConstraint *data = (bSizeLikeConstraint*)curcon->data;
+ expand_doit(fd, mainvar, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_KINEMATIC:
+ {
+ bKinematicConstraint *data = (bKinematicConstraint*)curcon->data;
+ expand_doit(fd, mainvar, data->tar);
+ expand_doit(fd, mainvar, data->poletar);
+ }
+ break;
+ case CONSTRAINT_TYPE_TRACKTO:
+ {
+ bTrackToConstraint *data = (bTrackToConstraint*)curcon->data;
+ expand_doit(fd, mainvar, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_MINMAX:
+ {
+ bMinMaxConstraint *data = (bMinMaxConstraint*)curcon->data;
+ expand_doit(fd, mainvar, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_LOCKTRACK:
+ {
+ bLockTrackConstraint *data = (bLockTrackConstraint*)curcon->data;
+ expand_doit(fd, mainvar, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_FOLLOWPATH:
+ {
+ bFollowPathConstraint *data = (bFollowPathConstraint*)curcon->data;
+ expand_doit(fd, mainvar, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_STRETCHTO:
+ {
+ bStretchToConstraint *data = (bStretchToConstraint*)curcon->data;
+ expand_doit(fd, mainvar, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_RIGIDBODYJOINT:
+ {
+ bRigidBodyJointConstraint *data = (bRigidBodyJointConstraint*)curcon->data;
+ expand_doit(fd, mainvar, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_CLAMPTO:
+ {
+ bClampToConstraint *data = (bClampToConstraint*)curcon->data;
+ expand_doit(fd, mainvar, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_CHILDOF:
+ {
+ bChildOfConstraint *data = (bChildOfConstraint*)curcon->data;
+ expand_doit(fd, mainvar, data->tar);
+ }
+ break;
+ case CONSTRAINT_TYPE_TRANSFORM:
+ {
+ bTransformConstraint *data = (bTransformConstraint*)curcon->data;
+ expand_doit(fd, mainvar, data->tar);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static void expand_bones(FileData *fd, Main *mainvar, Bone *bone)
+{
+ Bone *curBone;
+
+ for (curBone = bone->childbase.first; curBone; curBone=curBone->next) {
+ expand_bones(fd, mainvar, curBone);
+ }
+
+}
+
+static void expand_pose(FileData *fd, Main *mainvar, bPose *pose)
+{
+ bPoseChannel *chan;
+
+ if (!pose)
+ return;
+
+ for (chan = pose->chanbase.first; chan; chan=chan->next) {
+ expand_constraints(fd, mainvar, &chan->constraints);
+ expand_doit(fd, mainvar, chan->custom);
+ }
+}
+
+static void expand_armature(FileData *fd, Main *mainvar, bArmature *arm)
+{
+ Bone *curBone;
+
+ for (curBone = arm->bonebase.first; curBone; curBone=curBone->next) {
+ expand_bones(fd, mainvar, curBone);
+ }
+}
+
+static void expand_constraint_channels(FileData *fd, Main *mainvar, ListBase *chanbase)
+{
+ bConstraintChannel *chan;
+ for (chan=chanbase->first; chan; chan=chan->next){
+ expand_doit(fd, mainvar, chan->ipo);
+ }
+}
+
+static void expand_action(FileData *fd, Main *mainvar, bAction *act)
+{
+ bActionChannel *chan;
+ for (chan=act->chanbase.first; chan; chan=chan->next) {
+ expand_doit(fd, mainvar, chan->ipo);
+ expand_constraint_channels(fd, mainvar, &chan->constraintChannels);
+ }
+}
+
+static void expand_modifier(FileData *fd, Main *mainvar, ModifierData *md)
+{
+ if (md->type==eModifierType_Lattice) {
+ LatticeModifierData *lmd = (LatticeModifierData*) md;
+
+ expand_doit(fd, mainvar, lmd->object);
+ }
+ else if (md->type==eModifierType_Curve) {
+ CurveModifierData *cmd = (CurveModifierData*) md;
+
+ expand_doit(fd, mainvar, cmd->object);
+ }
+ else if (md->type==eModifierType_Array) {
+ ArrayModifierData *amd = (ArrayModifierData*) md;
+
+ expand_doit(fd, mainvar, amd->curve_ob);
+ expand_doit(fd, mainvar, amd->offset_ob);
+ }
+}
+
+static void expand_scriptlink(FileData *fd, Main *mainvar, ScriptLink *slink)
+{
+ int i;
+
+ for(i=0; i<slink->totscript; i++) {
+ expand_doit(fd, mainvar, slink->scripts[i]);
+ }
+}
+
+static void expand_object(FileData *fd, Main *mainvar, Object *ob)
+{
+ ModifierData *md;
+ bSensor *sens;
+ bController *cont;
+ bActuator *act;
+ bActionStrip *strip;
+ PartEff *paf;
+ int a;
+
+
+ expand_doit(fd, mainvar, ob->data);
+ expand_doit(fd, mainvar, ob->ipo);
+ expand_doit(fd, mainvar, ob->action);
+
+ for (md=ob->modifiers.first; md; md=md->next) {
+ expand_modifier(fd, mainvar, md);
+ }
+
+ expand_pose(fd, mainvar, ob->pose);
+ expand_constraints(fd, mainvar, &ob->constraints);
+ expand_constraint_channels(fd, mainvar, &ob->constraintChannels);
+
+ for (strip=ob->nlastrips.first; strip; strip=strip->next){
+ expand_doit(fd, mainvar, strip->object);
+ expand_doit(fd, mainvar, strip->act);
+ expand_doit(fd, mainvar, strip->ipo);
+ }
+
+ for(a=0; a<ob->totcol; a++) {
+ expand_doit(fd, mainvar, ob->mat[a]);
+ }
+
+ paf = give_parteff(ob);
+ if (paf && paf->group)
+ expand_doit(fd, mainvar, paf->group);
+
+ if(ob->dup_group)
+ expand_doit(fd, mainvar, ob->dup_group);
+
+ if(ob->proxy)
+ expand_doit(fd, mainvar, ob->proxy);
+ if(ob->proxy_group)
+ expand_doit(fd, mainvar, ob->proxy_group);
+
+ sens= ob->sensors.first;
+ while(sens) {
+ for(a=0; a<sens->totlinks; a++) {
+ sens->links[a]= newglobadr(fd, sens->links[a]);
+ }
+ if(sens->type==SENS_TOUCH) {
+ bTouchSensor *ts= sens->data;
+ expand_doit(fd, mainvar, ts->ma);
+ }
+ else if(sens->type==SENS_MESSAGE) {
+ bMessageSensor *ms= sens->data;
+ expand_doit(fd, mainvar, ms->fromObject);
+ }
+ sens= sens->next;
+ }
+
+ cont= ob->controllers.first;
+ while(cont) {
+ for(a=0; a<cont->totlinks; a++) {
+ cont->links[a]= newglobadr(fd, cont->links[a]);
+ }
+ if(cont->type==CONT_PYTHON) {
+ bPythonCont *pc= cont->data;
+ expand_doit(fd, mainvar, pc->text);
+ }
+ cont= cont->next;
+ }
+
+ act= ob->actuators.first;
+ while(act) {
+ if(act->type==ACT_SOUND) {
+ bSoundActuator *sa= act->data;
+ expand_doit(fd, mainvar, sa->sound);
+ }
+ else if(act->type==ACT_CAMERA) {
+ bCameraActuator *ca= act->data;
+ expand_doit(fd, mainvar, ca->ob);
+ }
+ else if(act->type==ACT_EDIT_OBJECT) {
+ bEditObjectActuator *eoa= act->data;
+ if(eoa) {
+ expand_doit(fd, mainvar, eoa->ob);
+ expand_doit(fd, mainvar, eoa->me);
+ }
+ }
+ else if(act->type==ACT_SCENE) {
+ bSceneActuator *sa= act->data;
+ expand_doit(fd, mainvar, sa->camera);
+ expand_doit(fd, mainvar, sa->scene);
+ }
+ else if(act->type==ACT_ACTION) {
+ bActionActuator *aa= act->data;
+ expand_doit(fd, mainvar, aa->act);
+ }
+ else if(act->type==ACT_PROPERTY) {
+ bPropertyActuator *pa= act->data;
+ expand_doit(fd, mainvar, pa->ob);
+ }
+ else if(act->type==ACT_MESSAGE) {
+ bMessageActuator *ma= act->data;
+ expand_doit(fd, mainvar, ma->toObject);
+ }
+ act= act->next;
+ }
+
+ expand_scriptlink(fd, mainvar, &ob->scriptlink);
+}
+
+static void expand_scene(FileData *fd, Main *mainvar, Scene *sce)
+{
+ Base *base;
+ SceneRenderLayer *srl;
+
+ for(base= sce->base.first; base; base= base->next) {
+ expand_doit(fd, mainvar, base->object);
+ }
+ expand_doit(fd, mainvar, sce->camera);
+ expand_doit(fd, mainvar, sce->world);
+
+ if(sce->nodetree)
+ expand_nodetree(fd, mainvar, sce->nodetree);
+
+ for(srl= sce->r.layers.first; srl; srl= srl->next) {
+ expand_doit(fd, mainvar, srl->mat_override);
+ expand_doit(fd, mainvar, srl->light_override);
+ }
+
+}
+
+static void expand_camera(FileData *fd, Main *mainvar, Camera *ca)
+{
+ expand_doit(fd, mainvar, ca->ipo);
+}
+
+static void expand_sound(FileData *fd, Main *mainvar, bSound *snd)
+{
+ expand_doit(fd, mainvar, snd->ipo);
+}
+
+
+static void expand_main(FileData *fd, Main *mainvar)
+{
+ ListBase *lbarray[MAX_LIBARRAY];
+ ID *id;
+ int a, doit= 1;
+
+ if(fd==0) return;
+
+ while(doit) {
+ doit= 0;
+
+ a= set_listbasepointers(mainvar, lbarray);
+ while(a--) {
+ id= lbarray[a]->first;
+
+ while(id) {
+ if(id->flag & LIB_TEST) {
+
+ switch(GS(id->name)) {
+
+ case ID_OB:
+ expand_object(fd, mainvar, (Object *)id);
+ break;
+ case ID_ME:
+ expand_mesh(fd, mainvar, (Mesh *)id);
+ break;
+ case ID_CU:
+ expand_curve(fd, mainvar, (Curve *)id);
+ break;
+ case ID_MB:
+ expand_mball(fd, mainvar, (MetaBall *)id);
+ break;
+ case ID_SCE:
+ expand_scene(fd, mainvar, (Scene *)id);
+ break;
+ case ID_MA:
+ expand_material(fd, mainvar, (Material *)id);
+ break;
+ case ID_TE:
+ expand_texture(fd, mainvar, (Tex *)id);
+ break;
+ case ID_WO:
+ expand_world(fd, mainvar, (World *)id);
+ break;
+ case ID_LT:
+ expand_lattice(fd, mainvar, (Lattice *)id);
+ break;
+ case ID_LA:
+ expand_lamp(fd, mainvar,(Lamp *)id);
+ break;
+ case ID_KE:
+ expand_key(fd, mainvar, (Key *)id);
+ break;
+ case ID_CA:
+ expand_camera(fd, mainvar, (Camera *)id);
+ break;
+ case ID_SO:
+ expand_sound(fd, mainvar, (bSound *)id);
+ break;
+ case ID_AR:
+ expand_armature(fd, mainvar, (bArmature *)id);
+ break;
+ case ID_AC:
+ expand_action(fd, mainvar, (bAction *)id);
+ break;
+ case ID_GR:
+ expand_group(fd, mainvar, (Group *)id);
+ break;
+ case ID_NT:
+ expand_nodetree(fd, mainvar, (bNodeTree *)id);
+ break;
+ case ID_BR:
+ expand_brush(fd, mainvar, (Brush *)id);
+ break;
+ case ID_IP:
+ expand_ipo(fd, mainvar, (Ipo *)id);
+ break;
+ }
+
+ doit= 1;
+ id->flag -= LIB_TEST;
+
+ }
+ id= id->next;
+ }
+ }
+ }
+}
+
+static int object_in_any_scene(Object *ob)
+{
+ Scene *sce;
+
+ for(sce= G.main->scene.first; sce; sce= sce->id.next)
+ if(object_in_scene(ob, sce))
+ return 1;
+ return 0;
+}
+
+/* when *lib set, it also does objects that were in the appended group */
+static void give_base_to_objects(Scene *sce, ListBase *lb, Library *lib)
+{
+ Object *ob;
+ Base *base;
+
+ /* give all objects which are LIB_INDIRECT a base, or for a group when *lib has been set */
+ for(ob= lb->first; ob; ob= ob->id.next) {
+
+ if( ob->id.flag & LIB_INDIRECT ) {
+ int do_it= 0;
+
+ if(ob->id.us==0)
+ do_it= 1;
+ else if(ob->id.us==1 && lib)
+ if(ob->id.lib==lib && (ob->flag & OB_FROMGROUP) && object_in_any_scene(ob)==0)
+ do_it= 1;
+
+ if(do_it) {
+ base= MEM_callocN( sizeof(Base), "add_ext_base");
+ BLI_addtail(&(sce->base), base);
+ base->lay= ob->lay;
+ base->object= ob;
+ base->flag= ob->flag;
+ ob->id.us= 1;
+
+ ob->id.flag -= LIB_INDIRECT;
+ ob->id.flag |= LIB_EXTERN;
+
+ }
+ }
+ }
+}
+
+
+static void append_named_part(FileData *fd, Main *mainvar, Scene *scene, char *name, int idcode, short flag)
+{
+ Object *ob;
+ Base *base;
+ BHead *bhead;
+ ID *id;
+ int endloop=0;
+
+ bhead = blo_firstbhead(fd);
+ while(bhead && endloop==0) {
+
+ if(bhead->code==ENDB) endloop= 1;
+ else if(bhead->code==idcode) {
+ char *idname= bhead_id_name(fd, bhead);
+
+ if(strcmp(idname+2, name)==0) {
+
+ id= is_yet_read(fd, mainvar, bhead);
+ if(id==NULL) {
+ read_libblock(fd, mainvar, bhead, LIB_TESTEXT, NULL);
+ }
+ else {
+ printf("append: already linked\n");
+ oldnewmap_insert(fd->libmap, bhead->old, id, 1);
+ if(id->flag & LIB_INDIRECT) {
+ id->flag -= LIB_INDIRECT;
+ id->flag |= LIB_EXTERN;
+ }
+ }
+
+ if(idcode==ID_OB) { /* loose object: give a base */
+ base= MEM_callocN( sizeof(Base), "app_nam_part");
+ BLI_addtail(&scene->base, base);
+
+ if(id==NULL) ob= mainvar->object.last;
+ else ob= (Object *)id;
+
+ /* this is bad code... G.vd nor G.scene should be used on this level... */
+ if((flag & FILE_ACTIVELAY)) {
+ if(G.vd) ob->lay= G.vd->layact;
+ else ob->lay = G.scene->lay;
+ }
+ base->lay= ob->lay;
+ base->object= ob;
+ ob->id.us++;
+
+ if(flag & FILE_AUTOSELECT) {
+ base->flag |= SELECT;
+ base->object->flag = base->flag;
+ /* do NOT make base active here! screws up GUI stuff, if you want it do it on src/ level */
+ }
+ }
+ endloop= 1;
+ }
+ }
+
+ bhead = blo_nextbhead(fd, bhead);
+ }
+}
+
+static void append_id_part(FileData *fd, Main *mainvar, ID *id, ID **id_r)
+{
+ BHead *bhead;
+
+ for (bhead= blo_firstbhead(fd); bhead; bhead= blo_nextbhead(fd, bhead)) {
+ if (bhead->code == GS(id->name)) {
+
+ if (BLI_streq(id->name, bhead_id_name(fd, bhead))) {
+ id->flag &= ~LIB_READ;
+ id->flag |= LIB_TEST;
+// printf("read lib block %s\n", id->name);
+ read_libblock(fd, mainvar, bhead, id->flag, id_r);
+
+ break;
+ }
+ } else if (bhead->code==ENDB)
+ break;
+ }
+}
+
+/* common routine to append/link something from a library */
+
+static Library* library_append( Scene *scene, char* file, char *dir, int idcode,
+ int totsel, FileData *fd, struct direntry* filelist, int totfile, short flag)
+{
+ Main *mainl;
+ Library *curlib;
+
+ /* make mains */
+ blo_split_main(&fd->mainlist, G.main);
+
+ /* which one do we need? */
+ mainl = blo_find_main(&fd->mainlist, dir, G.sce);
+
+ mainl->versionfile= fd->fileversion; /* needed for do_version */
+
+ curlib= mainl->curlib;
+
+ if(totsel==0) {
+ append_named_part(fd, mainl, scene, file, idcode, flag);
+ }
+ else {
+ int a;
+ for(a=0; a<totfile; a++) {
+ if(filelist[a].flags & ACTIVE) {
+ append_named_part(fd, mainl, scene, filelist[a].relname, idcode, flag);
+ }
+ }
+ }
+
+ /* make main consistant */
+ expand_main(fd, mainl);
+
+ /* do this when expand found other libs */
+ read_libraries(fd, &fd->mainlist);
+
+ if(flag & FILE_STRINGCODE) {
+
+ /* use the full path, this could have been read by other library even */
+ BLI_strncpy(mainl->curlib->name, mainl->curlib->filename, sizeof(mainl->curlib->name));
+
+ /* uses current .blend file as reference */
+ BLI_makestringcode(G.sce, mainl->curlib->name);
+ }
+
+ blo_join_main(&fd->mainlist);
+ G.main= fd->mainlist.first;
+
+ lib_link_all(fd, G.main);
+ lib_verify_nodetree(G.main);
+
+ /* give a base to loose objects. If group append, do it for objects too */
+ if(idcode==ID_GR)
+ give_base_to_objects(scene, &(G.main->object), (flag & FILE_LINK)?NULL:curlib);
+ else
+ give_base_to_objects(scene, &(G.main->object), NULL);
+
+ /* has been removed... erm, why? s..ton) */
+ /* 20040907: looks like they are give base already in append_named_part(); -Nathan L */
+ /* 20041208: put back. It only linked direct, not indirect objects (ton) */
+
+ /* patch to prevent switch_endian happens twice */
+ if(fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
+ blo_freefiledata( fd );
+ }
+
+ return curlib;
+}
+
+/* this is a version of BLO_library_append needed by the BPython API, so
+ * scripts can load data from .blend files -- see Blender.Library module.*/
+/* append to G.scene */
+/* this should probably be moved into the Python code anyway */
+
+void BLO_script_library_append(BlendHandle *bh, char *dir, char *name,
+ int idcode, short flag, Scene *scene )
+{
+ /* try to append the requested object */
+ library_append( scene, name, dir, idcode, 0, (FileData *)bh, NULL, 0, flag );
+
+ /* do we need to do this? */
+ DAG_scene_sort(G.scene);
+}
+
+/* append to G.scene */
+/* dir is a full path */
+void BLO_library_append(SpaceFile *sfile, char *dir, int idcode)
+{
+ BLO_library_append_(&sfile->libfiledata, sfile->filelist, sfile->totfile, dir, sfile->file, sfile->flag, idcode);
+}
+
+void BLO_library_append_(BlendHandle** libfiledata, struct direntry* filelist, int totfile, char *dir, char* file, short flag, int idcode)
+{
+ FileData *fd= (FileData*) (*libfiledata);
+ Library *curlib;
+ Base *centerbase;
+ Object *ob;
+ int a, totsel=0;
+
+ /* are there files selected? */
+ for(a=0; a<totfile; a++) {
+ if(filelist[a].flags & ACTIVE) {
+ totsel++;
+ }
+ }
+
+ if(totsel==0) {
+ /* is the indicated file in the filelist? */
+ if(file[0]) {
+ for(a=0; a<totfile; a++) {
+ if( strcmp(filelist[a].relname, file)==0) break;
+ }
+ if(a==totfile) {
+ error("Wrong indicated name");
+ return;
+ }
+ }
+ else {
+ error("Nothing indicated");
+ return;
+ }
+ }
+ /* now we have or selected, or an indicated file */
+
+ if(flag & FILE_AUTOSELECT) scene_deselect_all(G.scene);
+
+ curlib = library_append( G.scene, file, dir, idcode, totsel, fd, filelist, totfile,flag );
+
+ /* patch to prevent switch_endian happens twice */
+ if(fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
+ (*libfiledata)= 0;
+ }
+
+ /* when not linking (appending)... */
+ if((flag & FILE_LINK)==0) {
+ if(flag & FILE_ATCURSOR) {
+ float *curs, centerloc[3], vec[3], min[3], max[3];
+ int count= 0;
+
+ INIT_MINMAX(min, max);
+
+ centerbase= (G.scene->base.first);
+ while(centerbase) {
+ if(centerbase->object->id.lib==curlib && centerbase->object->parent==NULL) {
+ VECCOPY(vec, centerbase->object->loc);
+ DO_MINMAX(vec, min, max);
+ count++;
+ }
+ centerbase= centerbase->next;
+ }
+ if(count) {
+ centerloc[0]= (min[0]+max[0])/2;
+ centerloc[1]= (min[1]+max[1])/2;
+ centerloc[2]= (min[2]+max[2])/2;
+ curs = G.scene->cursor;
+ VECSUB(centerloc,curs,centerloc);
+
+ centerbase= (G.scene->base.first);
+ while(centerbase) {
+ if(centerbase->object->id.lib==curlib && centerbase->object->parent==NULL) {
+ ob= centerbase->object;
+ ob->loc[0] += centerloc[0];
+ ob->loc[1] += centerloc[1];
+ ob->loc[2] += centerloc[2];
+ }
+ centerbase= centerbase->next;
+ }
+ }
+ }
+ }
+}
+
+/* ************* READ LIBRARY ************** */
+
+static int mainvar_count_libread_blocks(Main *mainvar)
+{
+ ListBase *lbarray[MAX_LIBARRAY];
+ int a, tot= 0;
+
+ a= set_listbasepointers(mainvar, lbarray);
+ while(a--) {
+ ID *id= lbarray[a]->first;
+
+ for (id= lbarray[a]->first; id; id= id->next)
+ if (id->flag & LIB_READ)
+ tot++;
+ }
+ return tot;
+}
+
+static void read_libraries(FileData *basefd, ListBase *mainlist)
+{
+ Main *mainl= mainlist->first;
+ Main *mainptr;
+ ListBase *lbarray[MAX_LIBARRAY];
+ int a, doit= 1;
+
+ while(doit) {
+ doit= 0;
+
+ /* test 1: read libdata */
+ mainptr= mainl->next;
+ while(mainptr) {
+ int tot= mainvar_count_libread_blocks(mainptr);
+
+ // printf("found LIB_READ %s\n", mainptr->curlib->name);
+ if(tot) {
+ FileData *fd= mainptr->curlib->filedata;
+
+ if(fd==NULL) {
+ BlendReadError err;
+ printf("read library: lib %s\n", mainptr->curlib->name);
+ fd= blo_openblenderfile(mainptr->curlib->filename, &err);
+ if (fd) {
+ if (fd->libmap)
+ oldnewmap_free(fd->libmap);
+
+ fd->libmap = oldnewmap_new();
+
+ mainptr->curlib->filedata= fd;
+ mainptr->versionfile= fd->fileversion;
+ }
+ else mainptr->curlib->filedata= NULL;
+
+ if (fd==NULL)
+ printf("ERROR: can't find lib %s \n", mainptr->curlib->filename);
+ }
+ if(fd) {
+ doit= 1;
+ a= set_listbasepointers(mainptr, lbarray);
+ while(a--) {
+ ID *id= lbarray[a]->first;
+
+ while(id) {
+ ID *idn= id->next;
+ if(id->flag & LIB_READ) {
+ ID *realid= NULL;
+ BLI_remlink(lbarray[a], id);
+
+ append_id_part(fd, mainptr, id, &realid);
+ if (!realid)
+ printf("LIB ERROR: can't find %s\n", id->name);
+
+ change_idid_adr(mainlist, basefd, id, realid);
+
+ MEM_freeN(id);
+ }
+ id= idn;
+ }
+ }
+
+ expand_main(fd, mainptr);
+
+ /* dang FileData... now new libraries need to be appended to original filedata, it is not a good replacement for the old global (ton) */
+ while( fd->mainlist.first ) {
+ Main *mp= fd->mainlist.first;
+ BLI_remlink(&fd->mainlist, mp);
+ BLI_addtail(&basefd->mainlist, mp);
+ }
+ }
+ }
+
+ mainptr= mainptr->next;
+ }
+ }
+
+ /* test if there are unread libblocks */
+ for(mainptr= mainl->next; mainptr; mainptr= mainptr->next) {
+ a= set_listbasepointers(mainptr, lbarray);
+ while(a--) {
+ ID *id= lbarray[a]->first;
+ while(id) {
+ ID *idn= id->next;
+ if(id->flag & LIB_READ) {
+ BLI_remlink(lbarray[a], id);
+
+ printf("LIB ERROR: can't find %s\n", id->name);
+ change_idid_adr(mainlist, basefd, id, NULL);
+
+ MEM_freeN(id);
+ }
+ id= idn;
+ }
+ }
+ }
+
+ /* do versions, link, and free */
+ for(mainptr= mainl->next; mainptr; mainptr= mainptr->next) {
+ /* some mains still have to be read, then
+ * versionfile is still zero! */
+ if(mainptr->versionfile) {
+ if(mainptr->curlib->filedata) // can be zero... with shift+f1 append
+ do_versions(mainptr->curlib->filedata, mainptr->curlib, mainptr);
+ else
+ do_versions(basefd, NULL, mainptr);
+ }
+
+ if(mainptr->curlib->filedata)
+ lib_link_all(mainptr->curlib->filedata, mainptr);
+
+ if(mainptr->curlib->filedata) blo_freefiledata(mainptr->curlib->filedata);
+ mainptr->curlib->filedata= NULL;
+
+ }
+}
+
+/* reading runtime */
+
+BlendFileData *blo_read_blendafterruntime(int file, int actualsize, BlendReadError *error_r)
+{
+ BlendFileData *bfd = NULL;
+ FileData *fd = filedata_new();
+ fd->filedes = file;
+ fd->buffersize = actualsize;
+ fd->read = fd_read_from_file;
+
+ fd = blo_decode_and_check(fd, error_r);
+ if (!fd)
+ return NULL;
+
+ bfd= blo_read_file_internal(fd, error_r);
+ blo_freefiledata(fd);
+
+ return bfd;
+}
diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h
new file mode 100644
index 00000000000..79392023a56
--- /dev/null
+++ b/source/blender/blenloader/intern/readfile.h
@@ -0,0 +1,127 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * blenloader readfile private function prototypes
+ */
+#ifndef READFILE_H
+#define READFILE_H
+
+#include "zlib.h"
+
+struct OldNewMap;
+struct MemFile;
+
+typedef struct FileData {
+ // linked list of BHeadN's
+ ListBase listbase;
+ int flags;
+ int eof;
+ int buffersize;
+ int seek;
+ int (*read)(struct FileData *filedata, void *buffer, int size);
+
+ // variables needed for reading from memory / stream
+ char *buffer;
+ // variables needed for reading from memfile (undo)
+ struct MemFile *memfile;
+
+ // variables needed for reading from file
+ int filedes;
+ gzFile gzfiledes;
+
+ // now only in use for library appending
+ char filename[FILE_MAXDIR+FILE_MAXFILE];
+
+ // variables needed for reading from stream
+ char headerdone;
+ int inbuffer;
+
+ // general reading variables
+ struct SDNA *filesdna;
+ struct SDNA *memsdna;
+ char *compflags;
+
+ int fileversion;
+ int id_name_offs; /* used to retrieve ID names from (bhead+1) */
+
+ struct OldNewMap *datamap;
+ struct OldNewMap *globmap;
+ struct OldNewMap *libmap;
+ struct OldNewMap *imamap;
+
+ ListBase mainlist;
+
+ /* ick ick, used to return
+ * data through streamglue.
+ */
+ BlendFileData **bfd_r;
+ BlendReadError *error_r;
+} FileData;
+
+typedef struct BHeadN {
+ struct BHeadN *next, *prev;
+ struct BHead bhead;
+} BHeadN;
+
+
+#define FD_FLAGS_SWITCH_ENDIAN (1<<0)
+#define FD_FLAGS_FILE_POINTSIZE_IS_4 (1<<1)
+#define FD_FLAGS_POINTSIZE_DIFFERS (1<<2)
+#define FD_FLAGS_FILE_OK (1<<3)
+#define FD_FLAGS_NOT_MY_BUFFER (1<<4)
+#define FD_FLAGS_NOT_MY_LIBMAP (1<<5)
+
+#define SIZEOFBLENDERHEADER 12
+
+ /***/
+struct Main;
+void blo_join_main(ListBase *mainlist);
+void blo_split_main(ListBase *mainlist, struct Main *main);
+
+BlendFileData *blo_read_file_internal( FileData *fd, BlendReadError *error_r);
+
+FileData *blo_openblenderfile( char *name, BlendReadError *error_r);
+FileData *blo_openblendermemory( void *buffer, int buffersize, BlendReadError *error_r);
+FileData *blo_openblendermemfile(struct MemFile *memfile, BlendReadError *error_r);
+
+void blo_make_image_pointer_map(FileData *fd);
+void blo_end_image_pointer_map(FileData *fd);
+void blo_add_library_pointer_map(ListBase *mainlist, FileData *fd);
+
+void blo_freefiledata( FileData *fd);
+
+BHead *blo_firstbhead(FileData *fd);
+BHead *blo_nextbhead(FileData *fd, BHead *thisblock);
+BHead *blo_prevbhead(FileData *fd, BHead *thisblock);
+
+char *bhead_id_name(FileData *fd, BHead *bhead);
+
+#endif
+
diff --git a/source/blender/blenloader/intern/undofile.c b/source/blender/blenloader/intern/undofile.c
new file mode 100644
index 00000000000..c8c31f4f2ac
--- /dev/null
+++ b/source/blender/blenloader/intern/undofile.c
@@ -0,0 +1,146 @@
+/**
+ * $Id:
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * .blend file reading entry point
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+#include "DNA_userdef_types.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_global.h"
+
+#include "BLO_undofile.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_linklist.h"
+
+
+
+/* **************** support for memory-write, for undo buffers *************** */
+
+/* not memfile itself */
+void BLO_free_memfile(MemFile *memfile)
+{
+ MemFileChunk *chunk;
+
+ while( (chunk = (memfile->chunks.first) ) ) {
+ if(chunk->ident==0) MEM_freeN(chunk->buf);
+ BLI_remlink(&memfile->chunks, chunk);
+ MEM_freeN(chunk);
+ }
+ memfile->size= 0;
+}
+
+/* to keep list of memfiles consistant, 'first' is always first in list */
+/* result is that 'first' is being freed */
+void BLO_merge_memfile(MemFile *first, MemFile *second)
+{
+ MemFileChunk *fc, *sc;
+
+ fc= first->chunks.first;
+ sc= second->chunks.first;
+ while (fc || sc) {
+ if(fc && sc) {
+ if(sc->ident) {
+ sc->ident= 0;
+ fc->ident= 1;
+ }
+ }
+ if(fc) fc= fc->next;
+ if(sc) sc= sc->next;
+ }
+
+ BLO_free_memfile(first);
+}
+
+static int my_memcmp(int *mem1, int *mem2, int len)
+{
+ register int a= len, *mema= mem1, *memb= mem2;
+
+ while(a--) {
+ if( *mema != *memb) return 1;
+ mema++;
+ memb++;
+ }
+ return 0;
+}
+
+void add_memfilechunk(MemFile *compare, MemFile *current, char *buf, unsigned int size)
+{
+ static MemFileChunk *compchunk=NULL;
+ MemFileChunk *curchunk;
+
+ /* this function inits when compare != NULL or when current==NULL */
+ if(compare) {
+ compchunk= compare->chunks.first;
+ return;
+ }
+ if(current==NULL) {
+ compchunk= NULL;
+ return;
+ }
+
+ curchunk= MEM_mallocN(sizeof(MemFileChunk), "MemFileChunk");
+ curchunk->size= size;
+ curchunk->buf= NULL;
+ curchunk->ident= 0;
+ BLI_addtail(&current->chunks, curchunk);
+
+ /* we compare compchunk with buf */
+ if(compchunk) {
+ if(compchunk->size == curchunk->size) {
+ if( my_memcmp((int *)compchunk->buf, (int *)buf, size/4)==0) {
+ curchunk->buf= compchunk->buf;
+ curchunk->ident= 1;
+ }
+ }
+ compchunk= compchunk->next;
+ }
+
+ /* not equal... */
+ if(curchunk->buf==NULL) {
+ curchunk->buf= MEM_mallocN(size, "Chunk buffer");
+ memcpy(curchunk->buf, buf, size);
+ current->size += size;
+ }
+}
+
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
new file mode 100644
index 00000000000..43907a30ac2
--- /dev/null
+++ b/source/blender/blenloader/intern/writefile.c
@@ -0,0 +1,2202 @@
+/* writefile.c
+ *
+ * .blend file writing
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/*
+FILEFORMAT: IFF-style structure (but not IFF compatible!)
+
+start file:
+ BLENDER_V100 12 bytes (versie 1.00)
+ V = big endian, v = little endian
+ _ = 4 byte pointer, - = 8 byte pointer
+
+datablocks: also see struct BHead
+ <bh.code> 4 chars
+ <bh.len> int, len data after BHead
+ <bh.old> void, old pointer
+ <bh.SDNAnr> int
+ <bh.nr> int, in case of array: amount of structs
+ data
+ ...
+ ...
+
+Almost all data in Blender are structures. Each struct saved
+gets a BHead header. With BHead the struct can be linked again
+and compared with StructDNA .
+
+WRITE
+
+Preferred writing order: (not really a must, but why would you do it random?)
+Any case: direct data is ALWAYS after the lib block
+
+(Local file data)
+- for each LibBlock
+ - write LibBlock
+ - write associated direct data
+(External file data)
+- per library
+ - write library block
+ - per LibBlock
+ - write the ID of LibBlock
+- write FileGlobal (some global vars)
+- write SDNA
+- write USER if filename is ~/.B.blend
+*/
+
+/* for version 2.2+
+Important to know is that 'streaming' has been added to files, for Blender Publisher
+*/
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "zlib.h"
+
+#ifndef WIN32
+#include <unistd.h>
+#else
+#include "winsock2.h"
+#include "BLI_winstuff.h"
+#include <io.h>
+#include <process.h> // for getpid
+#endif
+
+#include <math.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "nla.h" // __NLA is defined
+
+#include "DNA_armature_types.h"
+#include "DNA_action_types.h"
+#include "DNA_actuator_types.h"
+#include "DNA_brush_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_color_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_controller_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_customdata_types.h"
+#include "DNA_effect_types.h"
+#include "DNA_group_types.h"
+#include "DNA_image_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_fileglobal_types.h"
+#include "DNA_key_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_listBase.h" /* for Listbase, the type of samples, ...*/
+#include "DNA_lamp_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_material_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_nla_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_object_force.h"
+#include "DNA_oops_types.h"
+#include "DNA_packedFile_types.h"
+#include "DNA_property_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_sdna_types.h"
+#include "DNA_sequence_types.h"
+#include "DNA_sensor_types.h"
+#include "DNA_space_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_sound_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_text_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_vfont_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_world_types.h"
+
+#include "MEM_guardedalloc.h" // MEM_freeN
+#include "BLI_blenlib.h"
+#include "BLI_linklist.h"
+
+#include "BKE_action.h"
+#include "BKE_bad_level_calls.h" // build_seqar (from WHILE_SEQ) free_oops error
+#include "BKE_blender.h"
+#include "BKE_curve.h"
+#include "BKE_customdata.h"
+#include "BKE_constraint.h"
+#include "BKE_global.h" // for G
+#include "BKE_library.h" // for set_listbasepointers
+#include "BKE_main.h" // G.main
+#include "BKE_node.h"
+#include "BKE_packedFile.h" // for packAll
+#include "BKE_screen.h" // for waitcursor
+#include "BKE_scene.h" // for do_seq
+#include "BKE_sound.h" /* ... and for samples */
+#include "BKE_utildefines.h" // for defines
+#include "BKE_modifier.h"
+#include "BKE_idprop.h"
+#ifdef WITH_VERSE
+#include "BKE_verse.h"
+#include "BIF_verse.h"
+#endif
+
+#include "GEN_messaging.h"
+
+#include "BLO_writefile.h"
+#include "BLO_readfile.h"
+#include "BLO_undofile.h"
+
+#include "readfile.h"
+#include "genfile.h"
+
+#include <errno.h>
+
+/* ********* my write, buffered writing with minimum 50k chunks ************ */
+
+typedef struct {
+ struct SDNA *sdna;
+
+ int file;
+ unsigned char *buf;
+ MemFile *compare, *current;
+
+ int tot, count, error, memsize;
+} WriteData;
+
+static WriteData *writedata_new(int file)
+{
+ extern unsigned char DNAstr[]; /* DNA.c */
+ extern int DNAlen;
+
+ WriteData *wd= MEM_callocN(sizeof(*wd), "writedata");
+
+ /* XXX, see note about this in readfile.c, remove
+ * once we have an xp lock - zr
+ */
+
+ if (wd == NULL) return NULL;
+
+ wd->sdna= dna_sdna_from_data(DNAstr, DNAlen, 0);
+
+ wd->file= file;
+
+ wd->buf= MEM_mallocN(100000, "wd->buf");
+
+ return wd;
+}
+
+static void writedata_do_write(WriteData *wd, void *mem, int memlen)
+{
+ if ((wd == NULL) || wd->error || (mem == NULL) || memlen < 1) return;
+ if (wd->error) return;
+
+ /* memory based save */
+ if(wd->current) {
+ add_memfilechunk(NULL, wd->current, mem, memlen);
+ }
+ else {
+ if (write(wd->file, mem, memlen) != memlen)
+ wd->error= 1;
+
+ }
+}
+
+static void writedata_free(WriteData *wd)
+{
+ dna_freestructDNA(wd->sdna);
+
+ MEM_freeN(wd->buf);
+ MEM_freeN(wd);
+}
+
+/***/
+
+int mywfile;
+
+/**
+ * Low level WRITE(2) wrapper that buffers data
+ * @param adr Pointer to new chunk of data
+ * @param len Length of new chunk of data
+ * @warning Talks to other functions with global parameters
+ */
+
+#define MYWRITE_FLUSH NULL
+
+static void mywrite( WriteData *wd, void *adr, int len)
+{
+ if (wd->error) return;
+
+ if(adr==MYWRITE_FLUSH) {
+ if(wd->count) {
+ writedata_do_write(wd, wd->buf, wd->count);
+ wd->count= 0;
+ }
+ return;
+ }
+
+ wd->tot+= len;
+
+ if(len>50000) {
+ if(wd->count) {
+ writedata_do_write(wd, wd->buf, wd->count);
+ wd->count= 0;
+ }
+ writedata_do_write(wd, adr, len);
+ return;
+ }
+ if(len+wd->count>99999) {
+ writedata_do_write(wd, wd->buf, wd->count);
+ wd->count= 0;
+ }
+ memcpy(&wd->buf[wd->count], adr, len);
+ wd->count+= len;
+
+}
+
+/**
+ * BeGiN initializer for mywrite
+ * @param file File descriptor
+ * @param write_flags Write parameters
+ * @warning Talks to other functions with global parameters
+ */
+static WriteData *bgnwrite(int file, MemFile *compare, MemFile *current, int write_flags)
+{
+ WriteData *wd= writedata_new(file);
+
+ if (wd == NULL) return NULL;
+
+ wd->compare= compare;
+ wd->current= current;
+ /* this inits comparing */
+ add_memfilechunk(compare, NULL, NULL, 0);
+
+ return wd;
+}
+
+/**
+ * END the mywrite wrapper
+ * @return 1 if write failed
+ * @return unknown global variable otherwise
+ * @warning Talks to other functions with global parameters
+ */
+static int endwrite(WriteData *wd)
+{
+ int err;
+
+ if (wd->count) {
+ writedata_do_write(wd, wd->buf, wd->count);
+ wd->count= 0;
+ }
+
+ err= wd->error;
+ writedata_free(wd);
+
+ return err;
+}
+
+/* ********** WRITE FILE ****************** */
+
+static void writestruct(WriteData *wd, int filecode, char *structname, int nr, void *adr)
+{
+ BHead bh;
+ short *sp;
+
+ if(adr==NULL || nr==0) return;
+
+ /* init BHead */
+ bh.code= filecode;
+ bh.old= adr;
+ bh.nr= nr;
+
+ bh.SDNAnr= dna_findstruct_nr(wd->sdna, structname);
+ if(bh.SDNAnr== -1) {
+ printf("error: can't find SDNA code <%s>\n", structname);
+ return;
+ }
+ sp= wd->sdna->structs[bh.SDNAnr];
+
+ bh.len= nr*wd->sdna->typelens[sp[0]];
+
+ if(bh.len==0) return;
+
+ mywrite(wd, &bh, sizeof(BHead));
+ mywrite(wd, adr, bh.len);
+}
+
+static void writedata(WriteData *wd, int filecode, int len, void *adr) /* do not use for structs */
+{
+ BHead bh;
+
+ if(adr==0) return;
+ if(len==0) return;
+
+ len+= 3;
+ len-= ( len % 4);
+
+ /* init BHead */
+ bh.code= filecode;
+ bh.old= adr;
+ bh.nr= 1;
+ bh.SDNAnr= 0;
+ bh.len= len;
+
+ mywrite(wd, &bh, sizeof(BHead));
+ if(len) mywrite(wd, adr, len);
+}
+
+/* *************** writing some direct data structs used in more code parts **************** */
+/*These functions are used by blender's .blend system for file saving/loading.*/
+void IDP_WriteProperty_OnlyData(IDProperty *prop, void *wd);
+void IDP_WriteProperty(IDProperty *prop, void *wd);
+
+void IDP_WriteArray(IDProperty *prop, void *wd)
+{
+ /*REMEMBER to set totalen to len in the linking code!!*/
+ if (prop->data.pointer) {
+ writedata(wd, DATA, MEM_allocN_len(prop->data.pointer), prop->data.pointer);
+ }
+}
+
+void IDP_WriteString(IDProperty *prop, void *wd)
+{
+ /*REMEMBER to set totalen to len in the linking code!!*/
+ writedata(wd, DATA, prop->len+1, prop->data.pointer);
+}
+
+void IDP_WriteGroup(IDProperty *prop, void *wd)
+{
+ IDProperty *loop;
+
+ for (loop=prop->data.group.first; loop; loop=loop->next) {
+ IDP_WriteProperty(loop, wd);
+ }
+}
+
+/* Functions to read/write ID Properties */
+void IDP_WriteProperty_OnlyData(IDProperty *prop, void *wd)
+{
+ switch (prop->type) {
+ case IDP_GROUP:
+ IDP_WriteGroup(prop, wd);
+ break;
+ case IDP_STRING:
+ IDP_WriteString(prop, wd);
+ break;
+ case IDP_ARRAY:
+ IDP_WriteArray(prop, wd);
+ break;
+ }
+}
+
+void IDP_WriteProperty(IDProperty *prop, void *wd)
+{
+ writestruct(wd, DATA, "IDProperty", 1, prop);
+ IDP_WriteProperty_OnlyData(prop, wd);
+}
+
+static void write_curvemapping(WriteData *wd, CurveMapping *cumap)
+{
+ int a;
+
+ writestruct(wd, DATA, "CurveMapping", 1, cumap);
+ for(a=0; a<CM_TOT; a++)
+ writestruct(wd, DATA, "CurveMapPoint", cumap->cm[a].totpoint, cumap->cm[a].curve);
+}
+
+/* this is only direct data, tree itself should have been written */
+static void write_nodetree(WriteData *wd, bNodeTree *ntree)
+{
+ bNode *node;
+ bNodeSocket *sock;
+ bNodeLink *link;
+
+ /* for link_list() speed, we write per list */
+
+ for(node= ntree->nodes.first; node; node= node->next)
+ writestruct(wd, DATA, "bNode", 1, node);
+
+ for(node= ntree->nodes.first; node; node= node->next) {
+ if(node->storage) {
+ /* could be handlerized at some point, now only 1 exception still */
+ if(ntree->type==NTREE_SHADER && (node->type==SH_NODE_CURVE_VEC || node->type==SH_NODE_CURVE_RGB))
+ write_curvemapping(wd, node->storage);
+ else if(ntree->type==NTREE_COMPOSIT && (node->type==CMP_NODE_TIME || node->type==CMP_NODE_CURVE_VEC || node->type==CMP_NODE_CURVE_RGB))
+ write_curvemapping(wd, node->storage);
+ else
+ writestruct(wd, DATA, node->typeinfo->storagename, 1, node->storage);
+ }
+ for(sock= node->inputs.first; sock; sock= sock->next)
+ writestruct(wd, DATA, "bNodeSocket", 1, sock);
+ for(sock= node->outputs.first; sock; sock= sock->next)
+ writestruct(wd, DATA, "bNodeSocket", 1, sock);
+ }
+
+ for(link= ntree->links.first; link; link= link->next)
+ writestruct(wd, DATA, "bNodeLink", 1, link);
+}
+
+static void write_scriptlink(WriteData *wd, ScriptLink *slink)
+{
+ writedata(wd, DATA, sizeof(void *)*slink->totscript, slink->scripts);
+ writedata(wd, DATA, sizeof(short)*slink->totscript, slink->flag);
+}
+
+static void write_renderinfo(WriteData *wd) /* for renderdeamon */
+{
+ Scene *sce;
+ int data[8];
+
+ sce= G.main->scene.first;
+ while(sce) {
+ if(sce->id.lib==0 && ( sce==G.scene || (sce->r.scemode & R_BG_RENDER)) ) {
+ data[0]= sce->r.sfra;
+ data[1]= sce->r.efra;
+
+ memset(data+2, 0, sizeof(int)*6);
+ strncpy((char *)(data+2), sce->id.name+2, 21);
+
+ writedata(wd, REND, 32, data);
+ }
+ sce= sce->id.next;
+ }
+}
+
+static void write_userdef(WriteData *wd)
+{
+ bTheme *btheme;
+
+ writestruct(wd, USER, "UserDef", 1, &U);
+
+ btheme= U.themes.first;
+ while(btheme) {
+ writestruct(wd, DATA, "bTheme", 1, btheme);
+ btheme= btheme->next;
+ }
+}
+
+static void write_effects(WriteData *wd, ListBase *lb)
+{
+ Effect *eff;
+
+ eff= lb->first;
+ while(eff) {
+
+ switch(eff->type) {
+ case EFF_PARTICLE:
+ writestruct(wd, DATA, "PartEff", 1, eff);
+ break;
+ default:
+ writedata(wd, DATA, MEM_allocN_len(eff), eff);
+ }
+
+ eff= eff->next;
+ }
+}
+
+static void write_properties(WriteData *wd, ListBase *lb)
+{
+ bProperty *prop;
+
+ prop= lb->first;
+ while(prop) {
+ writestruct(wd, DATA, "bProperty", 1, prop);
+
+ if(prop->poin && prop->poin != &prop->data)
+ writedata(wd, DATA, MEM_allocN_len(prop->poin), prop->poin);
+
+ prop= prop->next;
+ }
+}
+
+static void write_sensors(WriteData *wd, ListBase *lb)
+{
+ bSensor *sens;
+
+ sens= lb->first;
+ while(sens) {
+ writestruct(wd, DATA, "bSensor", 1, sens);
+
+ writedata(wd, DATA, sizeof(void *)*sens->totlinks, sens->links);
+
+ switch(sens->type) {
+ case SENS_NEAR:
+ writestruct(wd, DATA, "bNearSensor", 1, sens->data);
+ break;
+ case SENS_MOUSE:
+ writestruct(wd, DATA, "bMouseSensor", 1, sens->data);
+ break;
+ case SENS_TOUCH:
+ writestruct(wd, DATA, "bTouchSensor", 1, sens->data);
+ break;
+ case SENS_KEYBOARD:
+ writestruct(wd, DATA, "bKeyboardSensor", 1, sens->data);
+ break;
+ case SENS_PROPERTY:
+ writestruct(wd, DATA, "bPropertySensor", 1, sens->data);
+ break;
+ case SENS_COLLISION:
+ writestruct(wd, DATA, "bCollisionSensor", 1, sens->data);
+ break;
+ case SENS_RADAR:
+ writestruct(wd, DATA, "bRadarSensor", 1, sens->data);
+ break;
+ case SENS_RANDOM:
+ writestruct(wd, DATA, "bRandomSensor", 1, sens->data);
+ break;
+ case SENS_RAY:
+ writestruct(wd, DATA, "bRaySensor", 1, sens->data);
+ break;
+ case SENS_MESSAGE:
+ writestruct(wd, DATA, "bMessageSensor", 1, sens->data);
+ break;
+ case SENS_JOYSTICK:
+ writestruct(wd, DATA, "bJoystickSensor", 1, sens->data);
+ break;
+ default:
+ ; /* error: don't know how to write this file */
+ }
+
+ sens= sens->next;
+ }
+}
+
+static void write_controllers(WriteData *wd, ListBase *lb)
+{
+ bController *cont;
+
+ cont= lb->first;
+ while(cont) {
+ writestruct(wd, DATA, "bController", 1, cont);
+
+ writedata(wd, DATA, sizeof(void *)*cont->totlinks, cont->links);
+
+ switch(cont->type) {
+ case CONT_EXPRESSION:
+ writestruct(wd, DATA, "bExpressionCont", 1, cont->data);
+ break;
+ case CONT_PYTHON:
+ writestruct(wd, DATA, "bPythonCont", 1, cont->data);
+ break;
+ default:
+ ; /* error: don't know how to write this file */
+ }
+
+ cont= cont->next;
+ }
+}
+
+static void write_actuators(WriteData *wd, ListBase *lb)
+{
+ bActuator *act;
+
+ act= lb->first;
+ while(act) {
+ writestruct(wd, DATA, "bActuator", 1, act);
+
+ switch(act->type) {
+ case ACT_ACTION:
+ writestruct(wd, DATA, "bActionActuator", 1, act->data);
+ break;
+ case ACT_SOUND:
+ writestruct(wd, DATA, "bSoundActuator", 1, act->data);
+ break;
+ case ACT_CD:
+ writestruct(wd, DATA, "bCDActuator", 1, act->data);
+ break;
+ case ACT_OBJECT:
+ writestruct(wd, DATA, "bObjectActuator", 1, act->data);
+ break;
+ case ACT_IPO:
+ writestruct(wd, DATA, "bIpoActuator", 1, act->data);
+ break;
+ case ACT_PROPERTY:
+ writestruct(wd, DATA, "bPropertyActuator", 1, act->data);
+ break;
+ case ACT_CAMERA:
+ writestruct(wd, DATA, "bCameraActuator", 1, act->data);
+ break;
+ case ACT_CONSTRAINT:
+ writestruct(wd, DATA, "bConstraintActuator", 1, act->data);
+ break;
+ case ACT_EDIT_OBJECT:
+ writestruct(wd, DATA, "bEditObjectActuator", 1, act->data);
+ break;
+ case ACT_SCENE:
+ writestruct(wd, DATA, "bSceneActuator", 1, act->data);
+ break;
+ case ACT_GROUP:
+ writestruct(wd, DATA, "bGroupActuator", 1, act->data);
+ break;
+ case ACT_RANDOM:
+ writestruct(wd, DATA, "bRandomActuator", 1, act->data);
+ break;
+ case ACT_MESSAGE:
+ writestruct(wd, DATA, "bMessageActuator", 1, act->data);
+ break;
+ case ACT_GAME:
+ writestruct(wd, DATA, "bGameActuator", 1, act->data);
+ break;
+ case ACT_VISIBILITY:
+ writestruct(wd, DATA, "bVisibilityActuator", 1, act->data);
+ break;
+ default:
+ ; /* error: don't know how to write this file */
+ }
+
+ act= act->next;
+ }
+}
+
+static void write_nlastrips(WriteData *wd, ListBase *nlabase)
+{
+ bActionStrip *strip;
+ bActionModifier *amod;
+
+ for (strip=nlabase->first; strip; strip=strip->next)
+ writestruct(wd, DATA, "bActionStrip", 1, strip);
+ for (strip=nlabase->first; strip; strip=strip->next) {
+ for(amod= strip->modifiers.first; amod; amod= amod->next)
+ writestruct(wd, DATA, "bActionModifier", 1, amod);
+ }
+}
+
+static void write_constraints(WriteData *wd, ListBase *conlist)
+{
+ bConstraint *con;
+
+ for (con=conlist->first; con; con=con->next) {
+ bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
+
+ /* Write the specific data */
+ if (cti && con->data) {
+ /* firstly, just write the plain con->data struct */
+ writestruct(wd, DATA, cti->structName, 1, con->data);
+
+ /* do any constraint specific stuff */
+ switch (con->type) {
+ case CONSTRAINT_TYPE_PYTHON:
+ {
+ bPythonConstraint *data = (bPythonConstraint *)con->data;
+ bConstraintTarget *ct;
+
+ /* write targets */
+ for (ct= data->targets.first; ct; ct= ct->next)
+ writestruct(wd, DATA, "bConstraintTarget", 1, ct);
+
+ /* Write ID Properties -- and copy this comment EXACTLY for easy finding
+ of library blocks that implement this.*/
+ IDP_WriteProperty(data->prop, wd);
+ }
+ break;
+ }
+ }
+
+ /* Write the constraint */
+ writestruct(wd, DATA, "bConstraint", 1, con);
+ }
+}
+
+static void write_pose(WriteData *wd, bPose *pose)
+{
+ bPoseChannel *chan;
+
+ /* Write each channel */
+ if (!pose)
+ return;
+
+ /* Write channels */
+ for (chan=pose->chanbase.first; chan; chan=chan->next) {
+ write_constraints(wd, &chan->constraints);
+
+ /* prevent crashes with autosave, when a bone duplicated in editmode has not yet been assigned to its posechannel */
+ if (chan->bone)
+ chan->selectflag= chan->bone->flag & (BONE_SELECTED|BONE_ACTIVE); /* gets restored on read, for library armatures */
+
+ writestruct(wd, DATA, "bPoseChannel", 1, chan);
+ }
+
+ /* Write this pose */
+ writestruct(wd, DATA, "bPose", 1, pose);
+}
+
+static void write_defgroups(WriteData *wd, ListBase *defbase)
+{
+ bDeformGroup *defgroup;
+
+ for (defgroup=defbase->first; defgroup; defgroup=defgroup->next)
+ writestruct(wd, DATA, "bDeformGroup", 1, defgroup);
+}
+
+static void write_constraint_channels(WriteData *wd, ListBase *chanbase)
+{
+ bConstraintChannel *chan;
+
+ for (chan = chanbase->first; chan; chan=chan->next)
+ writestruct(wd, DATA, "bConstraintChannel", 1, chan);
+
+}
+
+static void write_modifiers(WriteData *wd, ListBase *modbase)
+{
+ ModifierData *md;
+
+ if (modbase == NULL) return;
+ for (md=modbase->first; md; md= md->next) {
+ ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ if (mti == NULL) return;
+
+ writestruct(wd, DATA, mti->structName, 1, md);
+
+ if (md->type==eModifierType_Hook) {
+ HookModifierData *hmd = (HookModifierData*) md;
+
+ writedata(wd, DATA, sizeof(int)*hmd->totindex, hmd->indexar);
+ }
+ else if (md->type==eModifierType_MeshDeform) {
+ MeshDeformModifierData *mmd = (MeshDeformModifierData*) md;
+
+ writedata(wd, DATA, sizeof(float)*mmd->totvert*mmd->totcagevert,
+ mmd->bindweights);
+ writedata(wd, DATA, sizeof(float)*3*mmd->totcagevert,
+ mmd->bindcos);
+ }
+ }
+}
+
+static void write_objects(WriteData *wd, ListBase *idbase)
+{
+ Object *ob;
+ int a;
+
+ ob= idbase->first;
+ while(ob) {
+ if(ob->id.us>0 || wd->current) {
+ /* write LibData */
+#ifdef WITH_VERSE
+ /* pointer at vnode stored in file have to be NULL */
+ struct VNode *vnode = (VNode*)ob->vnode;
+ if(vnode) ob->vnode = NULL;
+#endif
+ writestruct(wd, ID_OB, "Object", 1, ob);
+#ifdef WITH_VERSE
+ if(vnode) ob->vnode = (void*)vnode;
+#endif
+
+ /*Write ID Properties -- and copy this comment EXACTLY for easy finding
+ of library blocks that implement this.*/
+ if (ob->id.properties) IDP_WriteProperty(ob->id.properties, wd);
+
+ /* direct data */
+ writedata(wd, DATA, sizeof(void *)*ob->totcol, ob->mat);
+ write_effects(wd, &ob->effect);
+ write_properties(wd, &ob->prop);
+ write_sensors(wd, &ob->sensors);
+ write_controllers(wd, &ob->controllers);
+ write_actuators(wd, &ob->actuators);
+ write_scriptlink(wd, &ob->scriptlink);
+ write_pose(wd, ob->pose);
+ write_defgroups(wd, &ob->defbase);
+ write_constraints(wd, &ob->constraints);
+ write_constraint_channels(wd, &ob->constraintChannels);
+ write_nlastrips(wd, &ob->nlastrips);
+
+ writestruct(wd, DATA, "PartDeflect", 1, ob->pd);
+ writestruct(wd, DATA, "SoftBody", 1, ob->soft);
+ if(ob->soft) {
+ SoftBody *sb= ob->soft;
+ if(sb->keys) {
+ writedata(wd, DATA, sizeof(void *)*sb->totkey, sb->keys);
+ for(a=0; a<sb->totkey; a++) {
+ writestruct(wd, DATA, "SBVertex", sb->totpoint, sb->keys[a]);
+ }
+ }
+ }
+ writestruct(wd, DATA, "FluidsimSettings", 1, ob->fluidsimSettings); // NT
+
+ write_modifiers(wd, &ob->modifiers);
+ }
+ ob= ob->id.next;
+ }
+
+ /* flush helps the compression for undo-save */
+ mywrite(wd, MYWRITE_FLUSH, 0);
+}
+
+
+static void write_vfonts(WriteData *wd, ListBase *idbase)
+{
+ VFont *vf;
+ PackedFile * pf;
+
+ vf= idbase->first;
+ while(vf) {
+ if(vf->id.us>0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_VF, "VFont", 1, vf);
+ if (vf->id.properties) IDP_WriteProperty(vf->id.properties, wd);
+
+ /* direct data */
+
+ if (vf->packedfile) {
+ pf = vf->packedfile;
+ writestruct(wd, DATA, "PackedFile", 1, pf);
+ writedata(wd, DATA, pf->size, pf->data);
+ }
+ }
+
+ vf= vf->id.next;
+ }
+}
+
+static void write_ipos(WriteData *wd, ListBase *idbase)
+{
+ Ipo *ipo;
+ IpoCurve *icu;
+
+ ipo= idbase->first;
+ while(ipo) {
+ if(ipo->id.us>0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_IP, "Ipo", 1, ipo);
+ if (ipo->id.properties) IDP_WriteProperty(ipo->id.properties, wd);
+
+ /* direct data */
+ icu= ipo->curve.first;
+ while(icu) {
+ writestruct(wd, DATA, "IpoCurve", 1, icu);
+ icu= icu->next;
+ }
+
+ icu= ipo->curve.first;
+ while(icu) {
+ if(icu->bezt) writestruct(wd, DATA, "BezTriple", icu->totvert, icu->bezt);
+ if(icu->bp) writestruct(wd, DATA, "BPoint", icu->totvert, icu->bp);
+ if(icu->driver) writestruct(wd, DATA, "IpoDriver", 1, icu->driver);
+ icu= icu->next;
+ }
+ }
+
+ ipo= ipo->id.next;
+ }
+
+ /* flush helps the compression for undo-save */
+ mywrite(wd, MYWRITE_FLUSH, 0);
+}
+
+static void write_keys(WriteData *wd, ListBase *idbase)
+{
+ Key *key;
+ KeyBlock *kb;
+
+ key= idbase->first;
+ while(key) {
+ if(key->id.us>0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_KE, "Key", 1, key);
+ if (key->id.properties) IDP_WriteProperty(key->id.properties, wd);
+
+ /* direct data */
+ kb= key->block.first;
+ while(kb) {
+ writestruct(wd, DATA, "KeyBlock", 1, kb);
+ if(kb->data) writedata(wd, DATA, kb->totelem*key->elemsize, kb->data);
+ kb= kb->next;
+ }
+ }
+
+ key= key->id.next;
+ }
+ /* flush helps the compression for undo-save */
+ mywrite(wd, MYWRITE_FLUSH, 0);
+}
+
+static void write_cameras(WriteData *wd, ListBase *idbase)
+{
+ Camera *cam;
+
+ cam= idbase->first;
+ while(cam) {
+ if(cam->id.us>0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_CA, "Camera", 1, cam);
+ if (cam->id.properties) IDP_WriteProperty(cam->id.properties, wd);
+
+ /* direct data */
+ write_scriptlink(wd, &cam->scriptlink);
+ }
+
+ cam= cam->id.next;
+ }
+}
+
+static void write_mballs(WriteData *wd, ListBase *idbase)
+{
+ MetaBall *mb;
+ MetaElem *ml;
+
+ mb= idbase->first;
+ while(mb) {
+ if(mb->id.us>0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_MB, "MetaBall", 1, mb);
+ if (mb->id.properties) IDP_WriteProperty(mb->id.properties, wd);
+
+ /* direct data */
+ writedata(wd, DATA, sizeof(void *)*mb->totcol, mb->mat);
+
+ ml= mb->elems.first;
+ while(ml) {
+ writestruct(wd, DATA, "MetaElem", 1, ml);
+ ml= ml->next;
+ }
+ }
+ mb= mb->id.next;
+ }
+}
+
+int amount_of_chars(char *str)
+{
+ // Since the data is saved as UTF-8 to the cu->str
+ // The cu->len is not same as the strlen(cu->str)
+ return strlen(str);
+}
+
+static void write_curves(WriteData *wd, ListBase *idbase)
+{
+ Curve *cu;
+ Nurb *nu;
+
+ cu= idbase->first;
+ while(cu) {
+ if(cu->id.us>0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_CU, "Curve", 1, cu);
+
+ /* direct data */
+ writedata(wd, DATA, sizeof(void *)*cu->totcol, cu->mat);
+ if (cu->id.properties) IDP_WriteProperty(cu->id.properties, wd);
+
+ if(cu->vfont) {
+ writedata(wd, DATA, amount_of_chars(cu->str)+1, cu->str);
+ writestruct(wd, DATA, "CharInfo", cu->len, cu->strinfo);
+ writestruct(wd, DATA, "TextBox", cu->totbox, cu->tb);
+ }
+ else {
+ /* is also the order of reading */
+ nu= cu->nurb.first;
+ while(nu) {
+ writestruct(wd, DATA, "Nurb", 1, nu);
+ nu= nu->next;
+ }
+ nu= cu->nurb.first;
+ while(nu) {
+ if( (nu->type & 7)==CU_BEZIER)
+ writestruct(wd, DATA, "BezTriple", nu->pntsu, nu->bezt);
+ else {
+ writestruct(wd, DATA, "BPoint", nu->pntsu*nu->pntsv, nu->bp);
+ if(nu->knotsu) writedata(wd, DATA, KNOTSU(nu)*sizeof(float), nu->knotsu);
+ if(nu->knotsv) writedata(wd, DATA, KNOTSV(nu)*sizeof(float), nu->knotsv);
+ }
+ nu= nu->next;
+ }
+ }
+ }
+ cu= cu->id.next;
+ }
+
+ /* flush helps the compression for undo-save */
+ mywrite(wd, MYWRITE_FLUSH, 0);
+}
+
+static void write_dverts(WriteData *wd, int count, MDeformVert *dvlist)
+{
+ if (dvlist) {
+ int i;
+
+ /* Write the dvert list */
+ writestruct(wd, DATA, "MDeformVert", count, dvlist);
+
+ /* Write deformation data for each dvert */
+ for (i=0; i<count; i++) {
+ if (dvlist[i].dw)
+ writestruct(wd, DATA, "MDeformWeight", dvlist[i].totweight, dvlist[i].dw);
+ }
+ }
+}
+
+static void write_customdata(WriteData *wd, int count, CustomData *data, int partial_type, int partial_count)
+{
+ int i;
+
+ writestruct(wd, DATA, "CustomDataLayer", data->maxlayer, data->layers);
+
+ for (i=0; i<data->totlayer; i++) {
+ CustomDataLayer *layer= &data->layers[i];
+ char *structname;
+ int structnum, datasize;
+
+ if (layer->type == CD_MDEFORMVERT) {
+ /* layer types that allocate own memory need special handling */
+ write_dverts(wd, count, layer->data);
+ }
+ else {
+ CustomData_file_write_info(layer->type, &structname, &structnum);
+ if (structnum) {
+ /* when using partial visibility, the MEdge and MFace layers
+ are smaller than the original, so their type and count is
+ passed to make this work */
+ if (layer->type != partial_type) datasize= structnum*count;
+ else datasize= structnum*partial_count;
+
+ writestruct(wd, DATA, structname, datasize, layer->data);
+ }
+ else
+ printf("error: this CustomDataLayer must not be written to file\n");
+ }
+ }
+}
+
+static void write_meshs(WriteData *wd, ListBase *idbase)
+{
+ Mesh *mesh;
+ MultiresLevel *lvl;
+
+ mesh= idbase->first;
+ while(mesh) {
+ if(mesh->id.us>0 || wd->current) {
+ /* write LibData */
+#ifdef WITH_VERSE
+ struct VNode *vnode = (VNode*)mesh->vnode;
+ if(vnode) {
+ /* mesh has to be created from verse geometry node*/
+ create_meshdata_from_geom_node(mesh, vnode);
+ /* pointer at verse node can't be stored in file */
+ mesh->vnode = NULL;
+ }
+#endif
+
+ writestruct(wd, ID_ME, "Mesh", 1, mesh);
+#ifdef WITH_VERSE
+ if(vnode) mesh->vnode = (void*)vnode;
+#endif
+
+ /* direct data */
+ if (mesh->id.properties) IDP_WriteProperty(mesh->id.properties, wd);
+
+ writedata(wd, DATA, sizeof(void *)*mesh->totcol, mesh->mat);
+
+ if(mesh->pv) {
+ write_customdata(wd, mesh->pv->totvert, &mesh->vdata, -1, 0);
+ write_customdata(wd, mesh->pv->totedge, &mesh->edata,
+ CD_MEDGE, mesh->totedge);
+ write_customdata(wd, mesh->pv->totface, &mesh->fdata,
+ CD_MFACE, mesh->totface);
+ }
+ else {
+ write_customdata(wd, mesh->totvert, &mesh->vdata, -1, 0);
+ write_customdata(wd, mesh->totedge, &mesh->edata, -1, 0);
+ write_customdata(wd, mesh->totface, &mesh->fdata, -1, 0);
+ }
+
+ /* Multires data */
+ writestruct(wd, DATA, "Multires", 1, mesh->mr);
+ if(mesh->mr) {
+ lvl= mesh->mr->levels.first;
+ if(lvl) {
+ write_customdata(wd, lvl->totvert, &mesh->mr->vdata, -1, 0);
+ write_customdata(wd, lvl->totface, &mesh->mr->fdata, -1, 0);
+ writedata(wd, DATA, sizeof(short)*lvl->totedge, mesh->mr->edge_flags);
+ writedata(wd, DATA, sizeof(char)*lvl->totedge, mesh->mr->edge_creases);
+ }
+
+ for(; lvl; lvl= lvl->next) {
+ writestruct(wd, DATA, "MultiresLevel", 1, lvl);
+ writestruct(wd, DATA, "MultiresFace", lvl->totface, lvl->faces);
+ writestruct(wd, DATA, "MultiresEdge", lvl->totedge, lvl->edges);
+ writestruct(wd, DATA, "MultiresColFace", lvl->totface, lvl->colfaces);
+ }
+
+ lvl= mesh->mr->levels.last;
+ if(lvl)
+ writestruct(wd, DATA, "MVert", lvl->totvert, mesh->mr->verts);
+ }
+
+ /* PMV data */
+ if(mesh->pv) {
+ writestruct(wd, DATA, "PartialVisibility", 1, mesh->pv);
+ writedata(wd, DATA, sizeof(unsigned int)*mesh->pv->totvert, mesh->pv->vert_map);
+ writedata(wd, DATA, sizeof(int)*mesh->pv->totedge, mesh->pv->edge_map);
+ writestruct(wd, DATA, "MFace", mesh->pv->totface, mesh->pv->old_faces);
+ writestruct(wd, DATA, "MEdge", mesh->pv->totedge, mesh->pv->old_edges);
+ }
+ }
+ mesh= mesh->id.next;
+ }
+}
+
+static void write_lattices(WriteData *wd, ListBase *idbase)
+{
+ Lattice *lt;
+
+ lt= idbase->first;
+ while(lt) {
+ if(lt->id.us>0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_LT, "Lattice", 1, lt);
+ if (lt->id.properties) IDP_WriteProperty(lt->id.properties, wd);
+
+ /* direct data */
+ writestruct(wd, DATA, "BPoint", lt->pntsu*lt->pntsv*lt->pntsw, lt->def);
+
+ write_dverts(wd, lt->pntsu*lt->pntsv*lt->pntsw, lt->dvert);
+
+ }
+ lt= lt->id.next;
+ }
+}
+
+static void write_previews(WriteData *wd, PreviewImage *prv)
+{
+ if (prv) {
+ short w = prv->w[1];
+ short h = prv->h[1];
+ unsigned int *rect = prv->rect[1];
+ /* don't write out large previews if not requested */
+ if (!(U.flag & USER_SAVE_PREVIEWS) ) {
+ prv->w[1] = 0;
+ prv->h[1] = 0;
+ prv->rect[1] = NULL;
+ }
+ writestruct(wd, DATA, "PreviewImage", 1, prv);
+ if (prv->rect[0]) writedata(wd, DATA, prv->w[0]*prv->h[0]*sizeof(unsigned int), prv->rect[0]);
+ if (prv->rect[1]) writedata(wd, DATA, prv->w[1]*prv->h[1]*sizeof(unsigned int), prv->rect[1]);
+
+ /* restore preview, we still want to keep it in memory even if not saved to file */
+ if (!(U.flag & USER_SAVE_PREVIEWS) ) {
+ prv->w[1] = w;
+ prv->h[1] = h;
+ prv->rect[1] = rect;
+ }
+ }
+}
+
+static void write_images(WriteData *wd, ListBase *idbase)
+{
+ Image *ima;
+ PackedFile * pf;
+
+
+ ima= idbase->first;
+ while(ima) {
+ if(ima->id.us>0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_IM, "Image", 1, ima);
+ if (ima->id.properties) IDP_WriteProperty(ima->id.properties, wd);
+
+ if (ima->packedfile) {
+ pf = ima->packedfile;
+ writestruct(wd, DATA, "PackedFile", 1, pf);
+ writedata(wd, DATA, pf->size, pf->data);
+ }
+
+ write_previews(wd, ima->preview);
+
+ }
+ ima= ima->id.next;
+ }
+ /* flush helps the compression for undo-save */
+ mywrite(wd, MYWRITE_FLUSH, 0);
+}
+
+static void write_textures(WriteData *wd, ListBase *idbase)
+{
+ Tex *tex;
+
+ tex= idbase->first;
+ while(tex) {
+ if(tex->id.us>0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_TE, "Tex", 1, tex);
+ if (tex->id.properties) IDP_WriteProperty(tex->id.properties, wd);
+
+ /* direct data */
+ if(tex->plugin) writestruct(wd, DATA, "PluginTex", 1, tex->plugin);
+ if(tex->coba) writestruct(wd, DATA, "ColorBand", 1, tex->coba);
+ if(tex->env) writestruct(wd, DATA, "EnvMap", 1, tex->env);
+
+ write_previews(wd, tex->preview);
+ }
+ tex= tex->id.next;
+ }
+
+ /* flush helps the compression for undo-save */
+ mywrite(wd, MYWRITE_FLUSH, 0);
+}
+
+static void write_materials(WriteData *wd, ListBase *idbase)
+{
+ Material *ma;
+ int a;
+
+ ma= idbase->first;
+ while(ma) {
+ if(ma->id.us>0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_MA, "Material", 1, ma);
+
+ /*Write ID Properties -- and copy this comment EXACTLY for easy finding
+ of library blocks that implement this.*/
+ /*manually set head group property to IDP_GROUP, just in case it hadn't been
+ set yet :) */
+ if (ma->id.properties) IDP_WriteProperty(ma->id.properties, wd);
+
+ for(a=0; a<MAX_MTEX; a++) {
+ if(ma->mtex[a]) writestruct(wd, DATA, "MTex", 1, ma->mtex[a]);
+ }
+
+ if(ma->ramp_col) writestruct(wd, DATA, "ColorBand", 1, ma->ramp_col);
+ if(ma->ramp_spec) writestruct(wd, DATA, "ColorBand", 1, ma->ramp_spec);
+
+ write_scriptlink(wd, &ma->scriptlink);
+
+ /* nodetree is integral part of material, no libdata */
+ if(ma->nodetree) {
+ writestruct(wd, DATA, "bNodeTree", 1, ma->nodetree);
+ write_nodetree(wd, ma->nodetree);
+ }
+
+ write_previews(wd, ma->preview);
+ }
+ ma= ma->id.next;
+ }
+}
+
+static void write_worlds(WriteData *wd, ListBase *idbase)
+{
+ World *wrld;
+ int a;
+
+ wrld= idbase->first;
+ while(wrld) {
+ if(wrld->id.us>0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_WO, "World", 1, wrld);
+ if (wrld->id.properties) IDP_WriteProperty(wrld->id.properties, wd);
+
+ for(a=0; a<MAX_MTEX; a++) {
+ if(wrld->mtex[a]) writestruct(wd, DATA, "MTex", 1, wrld->mtex[a]);
+ }
+
+ write_scriptlink(wd, &wrld->scriptlink);
+
+ write_previews(wd, wrld->preview);
+
+ }
+ wrld= wrld->id.next;
+ }
+}
+
+static void write_lamps(WriteData *wd, ListBase *idbase)
+{
+ Lamp *la;
+ int a;
+
+ la= idbase->first;
+ while(la) {
+ if(la->id.us>0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_LA, "Lamp", 1, la);
+ if (la->id.properties) IDP_WriteProperty(la->id.properties, wd);
+
+ /* direct data */
+ for(a=0; a<MAX_MTEX; a++) {
+ if(la->mtex[a]) writestruct(wd, DATA, "MTex", 1, la->mtex[a]);
+ }
+
+ if(la->curfalloff)
+ write_curvemapping(wd, la->curfalloff);
+
+ write_scriptlink(wd, &la->scriptlink);
+
+ write_previews(wd, la->preview);
+
+ }
+ la= la->id.next;
+ }
+}
+
+
+static void write_scenes(WriteData *wd, ListBase *scebase)
+{
+ Scene *sce;
+ Base *base;
+ Editing *ed;
+ Sequence *seq;
+ MetaStack *ms;
+ Strip *strip;
+ TimeMarker *marker;
+ SceneRenderLayer *srl;
+ int a;
+
+ sce= scebase->first;
+ while(sce) {
+ /* write LibData */
+ writestruct(wd, ID_SCE, "Scene", 1, sce);
+ if (sce->id.properties) IDP_WriteProperty(sce->id.properties, wd);
+
+ /* direct data */
+ base= sce->base.first;
+ while(base) {
+ writestruct(wd, DATA, "Base", 1, base);
+ base= base->next;
+ }
+
+ writestruct(wd, DATA, "Radio", 1, sce->radio);
+ writestruct(wd, DATA, "ToolSettings", 1, sce->toolsettings);
+
+ for(a=0; a<MAX_MTEX; ++a)
+ writestruct(wd, DATA, "MTex", 1, sce->sculptdata.mtex[a]);
+
+ ed= sce->ed;
+ if(ed) {
+ writestruct(wd, DATA, "Editing", 1, ed);
+
+ /* reset write flags too */
+ WHILE_SEQ(&ed->seqbase) {
+ if(seq->strip) seq->strip->done= 0;
+ writestruct(wd, DATA, "Sequence", 1, seq);
+ }
+ END_SEQ
+
+ WHILE_SEQ(&ed->seqbase) {
+ if(seq->strip && seq->strip->done==0) {
+ /* write strip with 'done' at 0 because readfile */
+
+ if(seq->plugin) writestruct(wd, DATA, "PluginSeq", 1, seq->plugin);
+ if(seq->effectdata) {
+ switch(seq->type){
+ case SEQ_COLOR:
+ writestruct(wd, DATA, "SolidColorVars", 1, seq->effectdata);
+ break;
+ case SEQ_SPEED:
+ writestruct(wd, DATA, "SpeedControlVars", 1, seq->effectdata);
+ break;
+ case SEQ_WIPE:
+ writestruct(wd, DATA, "WipeVars", 1, seq->effectdata);
+ break;
+ case SEQ_GLOW:
+ writestruct(wd, DATA, "GlowVars", 1, seq->effectdata);
+ break;
+ case SEQ_TRANSFORM:
+ writestruct(wd, DATA, "TransformVars", 1, seq->effectdata);
+ break;
+ }
+ }
+
+ strip= seq->strip;
+ writestruct(wd, DATA, "Strip", 1, strip);
+
+ if(seq->type==SEQ_IMAGE)
+ writestruct(wd, DATA, "StripElem", strip->len, strip->stripdata);
+ else if(seq->type==SEQ_MOVIE || seq->type==SEQ_RAM_SOUND || seq->type == SEQ_HD_SOUND)
+ writestruct(wd, DATA, "StripElem", 1, strip->stripdata);
+
+ strip->done= 1;
+ }
+ }
+ END_SEQ
+
+ /* new; meta stack too, even when its nasty restore code */
+ for(ms= ed->metastack.first; ms; ms= ms->next) {
+ writestruct(wd, DATA, "MetaStack", 1, ms);
+ }
+ }
+
+ write_scriptlink(wd, &sce->scriptlink);
+
+ if (sce->r.avicodecdata) {
+ writestruct(wd, DATA, "AviCodecData", 1, sce->r.avicodecdata);
+ if (sce->r.avicodecdata->lpFormat) writedata(wd, DATA, sce->r.avicodecdata->cbFormat, sce->r.avicodecdata->lpFormat);
+ if (sce->r.avicodecdata->lpParms) writedata(wd, DATA, sce->r.avicodecdata->cbParms, sce->r.avicodecdata->lpParms);
+ }
+
+ if (sce->r.qtcodecdata) {
+ writestruct(wd, DATA, "QuicktimeCodecData", 1, sce->r.qtcodecdata);
+ if (sce->r.qtcodecdata->cdParms) writedata(wd, DATA, sce->r.qtcodecdata->cdSize, sce->r.qtcodecdata->cdParms);
+ }
+
+ /* writing dynamic list of TimeMarkers to the blend file */
+ for(marker= sce->markers.first; marker; marker= marker->next)
+ writestruct(wd, DATA, "TimeMarker", 1, marker);
+
+ for(srl= sce->r.layers.first; srl; srl= srl->next)
+ writestruct(wd, DATA, "SceneRenderLayer", 1, srl);
+
+ if(sce->nodetree) {
+ writestruct(wd, DATA, "bNodeTree", 1, sce->nodetree);
+ write_nodetree(wd, sce->nodetree);
+ }
+
+ sce= sce->id.next;
+ }
+ /* flush helps the compression for undo-save */
+ mywrite(wd, MYWRITE_FLUSH, 0);
+}
+
+static void write_screens(WriteData *wd, ListBase *scrbase)
+{
+ bScreen *sc;
+ ScrArea *sa;
+ ScrVert *sv;
+ ScrEdge *se;
+
+ sc= scrbase->first;
+ while(sc) {
+ /* write LibData */
+ writestruct(wd, ID_SCR, "Screen", 1, sc);
+ if (sc->id.properties) IDP_WriteProperty(sc->id.properties, wd);
+
+ /* direct data */
+ sv= sc->vertbase.first;
+ while(sv) {
+ writestruct(wd, DATA, "ScrVert", 1, sv);
+ sv= sv->next;
+ }
+
+ se= sc->edgebase.first;
+ while(se) {
+ writestruct(wd, DATA, "ScrEdge", 1, se);
+ se= se->next;
+ }
+
+ sa= sc->areabase.first;
+ while(sa) {
+ SpaceLink *sl;
+ Panel *pa;
+
+ writestruct(wd, DATA, "ScrArea", 1, sa);
+
+ pa= sa->panels.first;
+ while(pa) {
+ writestruct(wd, DATA, "Panel", 1, pa);
+ pa= pa->next;
+ }
+
+ /* space handler scriptlinks */
+ write_scriptlink(wd, &sa->scriptlink);
+
+ sl= sa->spacedata.first;
+ while(sl) {
+ if(sl->spacetype==SPACE_VIEW3D) {
+ View3D *v3d= (View3D*) sl;
+ writestruct(wd, DATA, "View3D", 1, v3d);
+ if(v3d->bgpic) writestruct(wd, DATA, "BGpic", 1, v3d->bgpic);
+ if(v3d->localvd) writestruct(wd, DATA, "View3D", 1, v3d->localvd);
+ if(v3d->clipbb) writestruct(wd, DATA, "BoundBox", 1, v3d->clipbb);
+ }
+ else if(sl->spacetype==SPACE_IPO) {
+ writestruct(wd, DATA, "SpaceIpo", 1, sl);
+ }
+ else if(sl->spacetype==SPACE_BUTS) {
+ writestruct(wd, DATA, "SpaceButs", 1, sl);
+ }
+ else if(sl->spacetype==SPACE_FILE) {
+ writestruct(wd, DATA, "SpaceFile", 1, sl);
+ }
+ else if(sl->spacetype==SPACE_SEQ) {
+ writestruct(wd, DATA, "SpaceSeq", 1, sl);
+ }
+ else if(sl->spacetype==SPACE_OOPS) {
+ SpaceOops *so= (SpaceOops *)sl;
+ Oops *oops;
+
+ /* cleanup */
+ oops= so->oops.first;
+ while(oops) {
+ Oops *oopsn= oops->next;
+ if(oops->id==0) {
+ BLI_remlink(&so->oops, oops);
+ free_oops(oops);
+ }
+ oops= oopsn;
+ }
+
+ /* ater cleanup, because of listbase! */
+ writestruct(wd, DATA, "SpaceOops", 1, so);
+
+ oops= so->oops.first;
+ while(oops) {
+ writestruct(wd, DATA, "Oops", 1, oops);
+ oops= oops->next;
+ }
+ /* outliner */
+ if(so->treestore) {
+ writestruct(wd, DATA, "TreeStore", 1, so->treestore);
+ if(so->treestore->data)
+ writestruct(wd, DATA, "TreeStoreElem", so->treestore->usedelem, so->treestore->data);
+ }
+ }
+ else if(sl->spacetype==SPACE_IMAGE) {
+ SpaceImage *sima= (SpaceImage *)sl;
+
+ writestruct(wd, DATA, "SpaceImage", 1, sl);
+ if(sima->cumap)
+ write_curvemapping(wd, sima->cumap);
+ }
+ else if(sl->spacetype==SPACE_IMASEL) {
+ writestruct(wd, DATA, "SpaceImaSel", 1, sl);
+ }
+ else if(sl->spacetype==SPACE_TEXT) {
+ writestruct(wd, DATA, "SpaceText", 1, sl);
+ }
+ else if(sl->spacetype==SPACE_SCRIPT) {
+ SpaceScript *sc = (SpaceScript*)sl;
+ sc->but_refs = NULL;
+ writestruct(wd, DATA, "SpaceScript", 1, sl);
+ }
+ else if(sl->spacetype==SPACE_ACTION) {
+ writestruct(wd, DATA, "SpaceAction", 1, sl);
+ }
+ else if(sl->spacetype==SPACE_SOUND) {
+ writestruct(wd, DATA, "SpaceSound", 1, sl);
+ }
+ else if(sl->spacetype==SPACE_NLA){
+ writestruct(wd, DATA, "SpaceNla", 1, sl);
+ }
+ else if(sl->spacetype==SPACE_TIME){
+ writestruct(wd, DATA, "SpaceTime", 1, sl);
+ }
+ else if(sl->spacetype==SPACE_NODE){
+ writestruct(wd, DATA, "SpaceNode", 1, sl);
+ }
+ sl= sl->next;
+ }
+
+ sa= sa->next;
+ }
+
+ sc= sc->id.next;
+ }
+}
+
+static void write_libraries(WriteData *wd, Main *main)
+{
+ ListBase *lbarray[30];
+ ID *id;
+ int a, tot, foundone;
+
+ for(; main; main= main->next) {
+
+ a=tot= set_listbasepointers(main, lbarray);
+
+ /* test: is lib being used */
+ foundone= 0;
+ while(tot--) {
+ for(id= lbarray[tot]->first; id; id= id->next) {
+ if(id->us>0 && (id->flag & LIB_EXTERN)) {
+ foundone= 1;
+ break;
+ }
+ }
+ if(foundone) break;
+ }
+
+ if(foundone) {
+ writestruct(wd, ID_LI, "Library", 1, main->curlib);
+
+ while(a--) {
+ for(id= lbarray[a]->first; id; id= id->next) {
+ if(id->us>0 && (id->flag & LIB_EXTERN)) {
+ writestruct(wd, ID_ID, "ID", 1, id);
+ }
+ }
+ }
+ }
+ }
+}
+
+static void write_bone(WriteData *wd, Bone* bone)
+{
+ Bone* cbone;
+
+ // PATCH for upward compatibility after 2.37+ armature recode
+ bone->size[0]= bone->size[1]= bone->size[2]= 1.0f;
+
+ // Write this bone
+ writestruct(wd, DATA, "Bone", 1, bone);
+
+ // Write Children
+ cbone= bone->childbase.first;
+ while(cbone) {
+ write_bone(wd, cbone);
+ cbone= cbone->next;
+ }
+}
+
+static void write_armatures(WriteData *wd, ListBase *idbase)
+{
+ bArmature *arm;
+ Bone *bone;
+
+ arm=idbase->first;
+ while (arm) {
+ if (arm->id.us>0 || wd->current) {
+ writestruct(wd, ID_AR, "bArmature", 1, arm);
+ if (arm->id.properties) IDP_WriteProperty(arm->id.properties, wd);
+
+ /* Direct data */
+ bone= arm->bonebase.first;
+ while(bone) {
+ write_bone(wd, bone);
+ bone=bone->next;
+ }
+ }
+ arm=arm->id.next;
+ }
+
+ /* flush helps the compression for undo-save */
+ mywrite(wd, MYWRITE_FLUSH, 0);
+}
+
+static void write_actions(WriteData *wd, ListBase *idbase)
+{
+ bAction *act;
+ bActionChannel *chan;
+
+ for(act=idbase->first; act; act= act->id.next) {
+ if (act->id.us>0 || wd->current) {
+ writestruct(wd, ID_AC, "bAction", 1, act);
+ if (act->id.properties) IDP_WriteProperty(act->id.properties, wd);
+
+ for (chan=act->chanbase.first; chan; chan=chan->next) {
+ writestruct(wd, DATA, "bActionChannel", 1, chan);
+ write_constraint_channels(wd, &chan->constraintChannels);
+ }
+ }
+ }
+}
+
+static void write_texts(WriteData *wd, ListBase *idbase)
+{
+ Text *text;
+ TextLine *tmp;
+
+ text= idbase->first;
+ while(text) {
+ if ( (text->flags & TXT_ISMEM) && (text->flags & TXT_ISEXT)) text->flags &= ~TXT_ISEXT;
+
+ /* write LibData */
+ writestruct(wd, ID_TXT, "Text", 1, text);
+ if(text->name) writedata(wd, DATA, strlen(text->name)+1, text->name);
+ if (text->id.properties) IDP_WriteProperty(text->id.properties, wd);
+
+ if(!(text->flags & TXT_ISEXT)) {
+ /* now write the text data, in two steps for optimization in the readfunction */
+ tmp= text->lines.first;
+ while (tmp) {
+ writestruct(wd, DATA, "TextLine", 1, tmp);
+ tmp= tmp->next;
+ }
+
+ tmp= text->lines.first;
+ while (tmp) {
+ writedata(wd, DATA, tmp->len+1, tmp->line);
+ tmp= tmp->next;
+ }
+ }
+ text= text->id.next;
+ }
+
+ /* flush helps the compression for undo-save */
+ mywrite(wd, MYWRITE_FLUSH, 0);
+}
+
+static void write_sounds(WriteData *wd, ListBase *idbase)
+{
+ bSound *sound;
+ bSample *sample;
+
+ PackedFile * pf;
+
+ // set all samples to unsaved status
+
+ sample = samples->first;
+ while (sample) {
+ sample->flags |= SAMPLE_NEEDS_SAVE;
+ sample = sample->id.next;
+ }
+
+ sound= idbase->first;
+ while(sound) {
+ if(sound->id.us>0 || wd->current) {
+ // do we need to save the packedfile as well ?
+ sample = sound->sample;
+ if (sample) {
+ if (sample->flags & SAMPLE_NEEDS_SAVE) {
+ sound->newpackedfile = sample->packedfile;
+ sample->flags &= ~SAMPLE_NEEDS_SAVE;
+ } else {
+ sound->newpackedfile = NULL;
+ }
+ }
+
+ /* write LibData */
+ writestruct(wd, ID_SO, "bSound", 1, sound);
+ if (sound->id.properties) IDP_WriteProperty(sound->id.properties, wd);
+
+ if (sound->newpackedfile) {
+ pf = sound->newpackedfile;
+ writestruct(wd, DATA, "PackedFile", 1, pf);
+ writedata(wd, DATA, pf->size, pf->data);
+ }
+
+ if (sample) {
+ sound->newpackedfile = sample->packedfile;
+ }
+ }
+ sound= sound->id.next;
+ }
+
+ /* flush helps the compression for undo-save */
+ mywrite(wd, MYWRITE_FLUSH, 0);
+}
+
+static void write_groups(WriteData *wd, ListBase *idbase)
+{
+ Group *group;
+ GroupObject *go;
+
+ for(group= idbase->first; group; group= group->id.next) {
+ if(group->id.us>0 || wd->current) {
+ /* write LibData */
+ writestruct(wd, ID_GR, "Group", 1, group);
+ if (group->id.properties) IDP_WriteProperty(group->id.properties, wd);
+
+ go= group->gobject.first;
+ while(go) {
+ writestruct(wd, DATA, "GroupObject", 1, go);
+ go= go->next;
+ }
+ }
+ }
+}
+
+static void write_nodetrees(WriteData *wd, ListBase *idbase)
+{
+ bNodeTree *ntree;
+
+ for(ntree=idbase->first; ntree; ntree= ntree->id.next) {
+ if (ntree->id.us>0 || wd->current) {
+ writestruct(wd, ID_NT, "bNodeTree", 1, ntree);
+ write_nodetree(wd, ntree);
+ if (ntree->id.properties) IDP_WriteProperty(ntree->id.properties, wd);
+ }
+ }
+}
+
+static void write_brushes(WriteData *wd, ListBase *idbase)
+{
+ Brush *brush;
+ int a;
+
+ for(brush=idbase->first; brush; brush= brush->id.next) {
+ if(brush->id.us>0 || wd->current) {
+ writestruct(wd, ID_BR, "Brush", 1, brush);
+ if (brush->id.properties) IDP_WriteProperty(brush->id.properties, wd);
+ for(a=0; a<MAX_MTEX; a++)
+ if(brush->mtex[a])
+ writestruct(wd, DATA, "MTex", 1, brush->mtex[a]);
+ }
+ }
+}
+
+static void write_global(WriteData *wd)
+{
+ FileGlobal fg;
+ char subvstr[8];
+
+ fg.curscreen= G.curscreen;
+ fg.curscene= G.scene;
+ fg.displaymode= G.displaymode;
+ fg.winpos= G.winpos;
+ fg.fileflags= (G.fileflags & ~G_FILE_NO_UI); // prevent to save this, is not good convention, and feature with concerns...
+ fg.globalf= G.f;
+
+ sprintf(subvstr, "%4d", BLENDER_SUBVERSION);
+ memcpy(fg.subvstr, subvstr, 4);
+
+ fg.subversion= BLENDER_SUBVERSION;
+ fg.minversion= BLENDER_MINVERSION;
+ fg.minsubversion= BLENDER_MINSUBVERSION;
+
+ writestruct(wd, GLOB, "FileGlobal", 1, &fg);
+}
+
+/* if MemFile * there's filesave to memory */
+static int write_file_handle(int handle, MemFile *compare, MemFile *current, int write_user_block, int write_flags)
+{
+ BHead bhead;
+ ListBase mainlist;
+ char buf[16];
+ WriteData *wd;
+
+ blo_split_main(&mainlist, G.main);
+
+ wd= bgnwrite(handle, compare, current, write_flags);
+
+ sprintf(buf, "BLENDER%c%c%.3d", (sizeof(void*)==8)?'-':'_', (G.order==B_ENDIAN)?'V':'v', G.version);
+ mywrite(wd, buf, 12);
+
+ write_renderinfo(wd);
+ write_global(wd);
+
+ if(current==NULL)
+ write_screens (wd, &G.main->screen); /* no UI save in undo */
+ write_scenes (wd, &G.main->scene);
+ write_curves (wd, &G.main->curve);
+ write_mballs (wd, &G.main->mball);
+ write_images (wd, &G.main->image);
+ write_cameras (wd, &G.main->camera);
+ write_lamps (wd, &G.main->lamp);
+ write_lattices (wd, &G.main->latt);
+ write_vfonts (wd, &G.main->vfont);
+ write_ipos (wd, &G.main->ipo);
+ write_keys (wd, &G.main->key);
+ write_worlds (wd, &G.main->world);
+ write_texts (wd, &G.main->text);
+ write_sounds (wd, &G.main->sound);
+ write_groups (wd, &G.main->group);
+ write_armatures(wd, &G.main->armature);
+ write_actions (wd, &G.main->action);
+ write_objects (wd, &G.main->object);
+ write_materials(wd, &G.main->mat);
+ write_textures (wd, &G.main->tex);
+ write_meshs (wd, &G.main->mesh);
+ write_nodetrees(wd, &G.main->nodetree);
+ write_brushes (wd, &G.main->brush);
+ if(current==NULL)
+ write_libraries(wd, G.main->next); /* no library save in undo */
+
+ if (write_user_block) {
+ write_userdef(wd);
+ }
+
+ /* dna as last, because (to be implemented) test for which structs are written */
+ writedata(wd, DNA1, wd->sdna->datalen, wd->sdna->data);
+
+ /* end of file */
+ memset(&bhead, 0, sizeof(BHead));
+ bhead.code= ENDB;
+ mywrite(wd, &bhead, sizeof(BHead));
+
+ blo_join_main(&mainlist);
+ G.main= mainlist.first;
+
+ return endwrite(wd);
+}
+
+/* return: success (1) */
+int BLO_write_file(char *dir, int write_flags, char **error_r)
+{
+ char userfilename[FILE_MAXDIR+FILE_MAXFILE];
+ char tempname[FILE_MAXDIR+FILE_MAXFILE];
+ int file, err, write_user_block;
+
+ sprintf(tempname, "%s@", dir);
+
+ file = open(tempname,O_BINARY+O_WRONLY+O_CREAT+O_TRUNC, 0666);
+ if(file == -1) {
+ *error_r= "Unable to open";
+ return 0;
+ }
+
+ BLI_make_file_string(G.sce, userfilename, BLI_gethome(), ".B.blend");
+
+ write_user_block= BLI_streq(dir, userfilename);
+
+ err= write_file_handle(file, NULL,NULL, write_user_block, write_flags);
+ close(file);
+
+ if(!err) {
+ if(write_flags & G_FILE_COMPRESS)
+ {
+ // compressed files have the same ending as regular files... only from 2.4!!!
+
+ int ret = BLI_gzip(tempname, dir);
+
+ if(-1==ret) {
+ *error_r= "Failed opening .gz file";
+ return 0;
+ }
+ if(-2==ret) {
+ *error_r= "Failed opening .blend file for compression";
+ return 0;
+ }
+ }
+ else
+ if(BLI_rename(tempname, dir) < 0) {
+ *error_r= "Can't change old file. File saved with @";
+ return 0;
+ }
+
+
+ } else {
+ *error_r= strerror(errno);
+ remove(tempname);
+
+ return 0;
+ }
+
+ return 1;
+}
+
+/* return: success (1) */
+int BLO_write_file_mem(MemFile *compare, MemFile *current, int write_flags, char **error_r)
+{
+ int err;
+
+ err= write_file_handle(0, compare, current, 0, write_flags);
+
+ if(err==0) return 1;
+ return 0;
+}
+
+
+ /* Runtime writing */
+
+#ifdef WIN32
+#define PATHSEPERATOR "\\"
+#else
+#define PATHSEPERATOR "/"
+#endif
+
+static char *get_install_dir(void) {
+ extern char bprogname[];
+ char *tmpname = BLI_strdup(bprogname);
+ char *cut;
+
+#ifdef __APPLE__
+ cut = strstr(tmpname, ".app");
+ if (cut) cut[0] = 0;
+#endif
+
+ cut = BLI_last_slash(tmpname);
+
+ if (cut) {
+ cut[0] = 0;
+ return tmpname;
+ } else {
+ MEM_freeN(tmpname);
+ return NULL;
+ }
+}
+
+static char *get_runtime_path(char *exename) {
+ char *installpath= get_install_dir();
+
+ if (!installpath) {
+ return NULL;
+ } else {
+ char *path= MEM_mallocN(strlen(installpath)+strlen(PATHSEPERATOR)+strlen(exename)+1, "runtimepath");
+
+ if (path == NULL) {
+ MEM_freeN(installpath);
+ return NULL;
+ }
+
+ strcpy(path, installpath);
+ strcat(path, PATHSEPERATOR);
+ strcat(path, exename);
+
+ MEM_freeN(installpath);
+
+ return path;
+ }
+}
+
+#ifdef __APPLE__
+
+static int recursive_copy_runtime(char *outname, char *exename, char **cause_r)
+{
+ char *cause = NULL, *runtime = get_runtime_path(exename);
+ char command[2 * (FILE_MAXDIR+FILE_MAXFILE) + 32];
+ int progfd = -1;
+
+ if (!runtime) {
+ cause= "Unable to find runtime";
+ goto cleanup;
+ }
+ //printf("runtimepath %s\n", runtime);
+
+ progfd= open(runtime, O_BINARY|O_RDONLY, 0);
+ if (progfd==-1) {
+ cause= "Unable to find runtime";
+ goto cleanup;
+ }
+
+ sprintf(command, "/bin/cp -R \"%s\" \"%s\"", runtime, outname);
+ //printf("command %s\n", command);
+ if (system(command) == -1) {
+ cause = "Couldn't copy runtime";
+ }
+
+cleanup:
+ if (progfd!=-1)
+ close(progfd);
+ if (runtime)
+ MEM_freeN(runtime);
+
+ if (cause) {
+ *cause_r= cause;
+ return 0;
+ } else
+ return 1;
+}
+
+void BLO_write_runtime(char *file, char *exename) {
+ char gamename[FILE_MAXDIR+FILE_MAXFILE];
+ int outfd = -1;
+ char *cause= NULL;
+
+ // remove existing file / bundle
+ //printf("Delete file %s\n", file);
+ BLI_delete(file, 0, TRUE);
+
+ if (!recursive_copy_runtime(file, exename, &cause))
+ goto cleanup;
+
+ strcpy(gamename, file);
+ strcat(gamename, "/Contents/Resources/game.blend");
+ //printf("gamename %s\n", gamename);
+ outfd= open(gamename, O_BINARY|O_WRONLY|O_CREAT|O_TRUNC, 0777);
+ if (outfd != -1) {
+
+ write_file_handle(outfd, NULL,NULL, 0, G.fileflags);
+
+ if (write(outfd, " ", 1) != 1) {
+ cause= "Unable to write to output file";
+ goto cleanup;
+ }
+ } else {
+ cause = "Unable to open blenderfile";
+ }
+
+cleanup:
+ if (outfd!=-1)
+ close(outfd);
+
+ if (cause)
+ error("Unable to make runtime: %s", cause);
+}
+
+#else /* !__APPLE__ */
+
+static int handle_append_runtime(int handle, char *exename, char **cause_r) {
+ char *cause= NULL, *runtime= get_runtime_path(exename);
+ unsigned char buf[1024];
+ int count, progfd= -1;
+
+ if (!runtime) {
+ cause= "Unable to find runtime";
+ goto cleanup;
+ }
+
+ progfd= open(runtime, O_BINARY|O_RDONLY, 0);
+ if (progfd==-1) {
+ cause= "Unable to find runtime";
+ goto cleanup;
+ }
+
+ while ((count= read(progfd, buf, sizeof(buf)))>0) {
+ if (write(handle, buf, count)!=count) {
+ cause= "Unable to write to output file";
+ goto cleanup;
+ }
+ }
+
+cleanup:
+ if (progfd!=-1)
+ close(progfd);
+ if (runtime)
+ MEM_freeN(runtime);
+
+ if (cause) {
+ *cause_r= cause;
+ return 0;
+ } else
+ return 1;
+}
+
+static int handle_write_msb_int(int handle, int i) {
+ unsigned char buf[4];
+ buf[0]= (i>>24)&0xFF;
+ buf[1]= (i>>16)&0xFF;
+ buf[2]= (i>>8)&0xFF;
+ buf[3]= (i>>0)&0xFF;
+
+ return (write(handle, buf, 4)==4);
+}
+
+void BLO_write_runtime(char *file, char *exename) {
+ int outfd= open(file, O_BINARY|O_WRONLY|O_CREAT|O_TRUNC, 0777);
+ char *cause= NULL;
+ int datastart;
+
+ if (!outfd) {
+ cause= "Unable to open output file";
+ goto cleanup;
+ }
+ if (!handle_append_runtime(outfd, exename, &cause))
+ goto cleanup;
+
+ datastart= lseek(outfd, 0, SEEK_CUR);
+
+ write_file_handle(outfd, NULL,NULL, 0, G.fileflags);
+
+ if (!handle_write_msb_int(outfd, datastart) || (write(outfd, "BRUNTIME", 8)!=8)) {
+ cause= "Unable to write to output file";
+ goto cleanup;
+ }
+
+cleanup:
+ if (outfd!=-1)
+ close(outfd);
+
+ if (cause)
+ error("Unable to make runtime: %s", cause);
+}
+
+#endif /* !__APPLE__ */
diff --git a/source/blender/blenpluginapi/CMakeLists.txt b/source/blender/blenpluginapi/CMakeLists.txt
new file mode 100644
index 00000000000..2afd3ebb121
--- /dev/null
+++ b/source/blender/blenpluginapi/CMakeLists.txt
@@ -0,0 +1,42 @@
+# $Id$
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2006, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Jacques Beaurain.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+
+FILE(GLOB SRC intern/*.c)
+
+SET(INC
+ . .. ../../../intern/guardedalloc ../blenlib ../imbuf ../makesdna
+)
+
+IF(WITH_QUICKTIME)
+ SET(INC ${INC} ${QUICKTIME_INC})
+ ADD_DEFINITIONS(-DWITH_QUICKTIME)
+ENDIF(WITH_QUICKTIME)
+
+BLENDERLIB(bf_blenpluginapi "${SRC}" "${INC}")
+#env.BlenderLib ( libname = 'bf_blenpluginapi', sources = sources, includes = Split(incs), defines = defs, libtype=['core', 'player'], priority = [75, 35] )
diff --git a/source/blender/blenpluginapi/Makefile b/source/blender/blenpluginapi/Makefile
new file mode 100644
index 00000000000..17c23c419a8
--- /dev/null
+++ b/source/blender/blenpluginapi/Makefile
@@ -0,0 +1,37 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+# Bounces make to subdirectories.
+
+SOURCEDIR = source/blender/blenpluginapi
+DIRS = intern
+
+include nan_subdirs.mk
diff --git a/source/blender/blenpluginapi/SConscript b/source/blender/blenpluginapi/SConscript
new file mode 100644
index 00000000000..d17a35e933e
--- /dev/null
+++ b/source/blender/blenpluginapi/SConscript
@@ -0,0 +1,14 @@
+#!/usr/bin/python
+Import ('env')
+
+sources = env.Glob('intern/*.c')
+
+incs = '. .. #/intern/guardedalloc ../blenlib ../imbuf ../makesdna'
+
+defs = []
+
+if env['WITH_BF_QUICKTIME'] == 1:
+ defs.append('WITH_QUICKTIME')
+ incs += ' ' + env['BF_QUICKTIME_INC']
+
+env.BlenderLib ( libname = 'bf_blenpluginapi', sources = sources, includes = Split(incs), defines = defs, libtype=['core', 'player'], priority = [75, 35] )
diff --git a/source/blender/blenpluginapi/documentation.h b/source/blender/blenpluginapi/documentation.h
new file mode 100644
index 00000000000..3bb9b33ee04
--- /dev/null
+++ b/source/blender/blenpluginapi/documentation.h
@@ -0,0 +1,72 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * @mainpage plugin API - the access point for texture and sequence
+ * plugins
+ *
+ * @section about About the plugin API
+ *
+ * This API wraps functions that are used by texture and sequence
+ * plugins. They are explicitly wrapped in order to make the
+ * dependencies to the rest of the system clear.
+ *
+ * @section issues Known issues with the plugin API
+ *
+ * - It can be difficult at times to get access to the API functions
+ * linked into the final executable. On gcc, the -fpic and -shared
+ * flags take care of this. On Irix, -shared is needed, but you also
+ * need a reference to the function to get the handle. This has
+ * momentarily been taken care of by pluginapi_force_ref().
+ *
+ * - Plugins need to define three functions that are needed for
+ * version bookkeeping and information. The plugin loading code
+ * explicitly checks for these functions. The nanes depend on whether
+ * it is a texture or sequence plugin.
+ *
+ * - The plugin loading occurs in sequence.c and texture.c. The
+ * following functions are involved:
+ * - open_plugin_seq() (used in readfile.c, editseq.c, sequence.c)
+ * - add_plugin_seq() (used in editseq.c, sequence.c)
+ * - free_plugin_seq() (used in editseq.c, sequence.c)
+ * - open_plugin_tex() (used in texture.c, readfile.c)
+ * - add_plugin_tex() (used in texture.c, buttons.c)
+ * - free_plugin_tex() (used in texture.c, buttons.c)
+ * - test_dlerr() (used in texture.c, sequence.c)
+ * Since the plugins are about to phase out, we will not sanitize this
+ * code. It will be removed as soon as the replacing system is in
+ * place.
+ *
+ * @section dependencies Dependencies
+ *
+ * The plugins wraps functions from IMB and BLI. In addition, they
+ * define some useful variables.
+ * */
+
diff --git a/source/blender/blenpluginapi/externdef.h b/source/blender/blenpluginapi/externdef.h
new file mode 100644
index 00000000000..7322841e608
--- /dev/null
+++ b/source/blender/blenpluginapi/externdef.h
@@ -0,0 +1,43 @@
+/* Copyright (c) 1999, Not a Number / NeoGeo b.v.
+ *
+ * All rights reserved.
+ *
+ * Contact: info@blender.org
+ * Information: http://www.blender.org
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 _EXTERNDEF_H
+#define _EXTERNDEF_H
+
+#ifdef WIN32
+ #ifdef PLUGIN_INTERN
+ #define LIBEXPORT __declspec(dllexport)
+ #else
+ #define LIBEXPORT extern __declspec(dllimport)
+ #endif
+#elif !defined(WIN32)
+ #define LIBEXPORT extern
+#endif
+
+#endif /* _EXTERNDEF_H */
diff --git a/source/blender/blenpluginapi/floatpatch.h b/source/blender/blenpluginapi/floatpatch.h
new file mode 100644
index 00000000000..8e6fab8a363
--- /dev/null
+++ b/source/blender/blenpluginapi/floatpatch.h
@@ -0,0 +1,90 @@
+/* Copyright (c) 1999, Not a Number / NeoGeo b.v.
+ * $Id$
+ *
+ * All rights reserved.
+ *
+ * Contact: info@blender.org
+ * Information: http://www.blender.org
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 FLOATPATCH_H
+#define FLOATPATCH_H
+
+/* floating point libs differ at systems... with these defines it comilies at all! */
+
+#ifdef MIPS1
+#else
+
+#define fabsf(a) fabs((double)(a))
+
+#define facos acosf
+#define acosf(a) acos((double)(a))
+
+#define fasin asinf
+#define asinf(a) asin((double)(a))
+
+#define fatan atanf
+#define atanf(a) atan((double)(a))
+
+#define fatan2 atan2f
+#define atan2f(a, b) atan2((double)(a), (double)(b))
+
+#define fmodf(a, b) fmod((double)(a), (double)(b))
+
+#define fcos cosf
+#define cosf(a) cos((double)(a))
+
+#define fsin sinf
+#define sinf(a) sin((double)(a))
+
+#define ftan tanf
+#define tanf(a) tan((double)(a))
+
+#define fexp expf
+#define expf(a) exp((double)(a))
+
+#define flog logf
+#define logf(a) log((double)(a))
+
+#define flog10 log10f
+#define log10f(a) log10((double)(a))
+
+#define fsqrt sqrtf
+#define sqrtf(a) sqrt((double)(a))
+
+#define fceil ceilf
+#define ceilf(a) ceil((double)(a))
+
+#define ffloor floorf
+#define floorf(a) floor((double)(a))
+
+#define fpow powf
+#define powf(a, b) pow((double)(a), (double)(b))
+
+/* #endif */
+
+#endif
+
+#endif /* FLOATPATCH_H */
+
diff --git a/source/blender/blenpluginapi/iff.h b/source/blender/blenpluginapi/iff.h
new file mode 100644
index 00000000000..5eb52158a1a
--- /dev/null
+++ b/source/blender/blenpluginapi/iff.h
@@ -0,0 +1,215 @@
+/* Copyright (c) 1999, Not a Number / NeoGeo b.v.
+ * $Id$
+ *
+ * All rights reserved.
+ *
+ * Contact: info@blender.org
+ * Information: http://www.blender.org
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 IFF_H
+#define IFF_H
+
+#include <sys/types.h>
+#include "util.h"
+#include "externdef.h"
+
+#define IB_rect (1 << 0)
+#define IB_planes (1 << 1)
+#define IB_cmap (1 << 2)
+#define IB_test (1 << 7)
+
+#define IB_fields (1 << 11)
+#define IB_yuv (1 << 12)
+#define IB_zbuf (1 << 13)
+#define IB_rgba (1 << 14)
+
+#define AMI (1 << 31)
+#define PNG (1 << 30)
+#define Anim (1 << 29)
+#define TGA (1 << 28)
+#define JPG (1 << 27)
+#define BMP (1 << 26)
+#ifdef WITH_QUICKTIME
+#define QUICKTIME (1 << 25)
+#endif
+#define RADHDR (1<<24)
+
+#define RAWTGA (TGA | 1)
+
+#define JPG_STD (JPG | (0 << 8))
+#define JPG_VID (JPG | (1 << 8))
+#define JPG_JST (JPG | (2 << 8))
+#define JPG_MAX (JPG | (3 << 8))
+#define JPG_MSK (0xffffff00)
+
+#define AM_ham (0x0800 | AMI)
+#define AM_hbrite (0x0080 | AMI)
+#define AM_lace (0x0004 | AMI)
+#define AM_hires (0x8000 | AMI)
+#define AM_hblace (AM_hbrite | AM_lace)
+#define AM_hilace (AM_hires | AM_lace)
+#define AM_hamlace (AM_ham | AM_lace)
+
+#define RGB888 1
+#define RGB555 2
+#define DYUV 3
+#define CLUT8 4
+#define CLUT7 5
+#define CLUT4 6
+#define CLUT3 7
+#define RL7 8
+#define RL3 9
+#define MPLTE 10
+
+#define DYUV1 0
+#define C233 1
+#define YUVX 2
+#define HAMX 3
+#define TANX 4
+
+#define AN_c233 (Anim | C233)
+#define AN_yuvx (Anim | YUVX)
+#define AN_hamx (Anim | HAMX)
+#define AN_tanx (Anim | TANX)
+
+#define IS_amiga(x) (x->ftype & AMI)
+#define IS_ham(x) ((x->ftype & AM_ham) == AM_ham)
+#define IS_hbrite(x) ((x->ftype & AM_hbrite) == AM_hbrite)
+
+#define IS_lace(x) ((x->ftype & AM_lace) == AM_lace)
+#define IS_hires(x) ((x->ftype & AM_hires) == AM_hires)
+#define IS_hblace(x) ((x->ftype & AM_hblace) == AM_hblace)
+#define IS_hilace(x) ((x->ftype & AM_hilace) == AM_hilace)
+#define IS_hamlace(x) ((x->ftype & AM_hamlace) == AM_hamlace)
+
+#define IS_anim(x) (x->ftype & Anim)
+#define IS_hamx(x) (x->ftype == AN_hamx)
+#define IS_tga(x) (x->ftype & TGA)
+#define IS_png(x) (x->ftype & PNG)
+#define IS_bmp(x) (x->ftype & BMP)
+#define IS_radhdr(x) (x->ftype & RADHDR)
+#define IS_tim(x) (x->ftype & TIM)
+#define IS_tiff(x) (x->ftype & TIFF)
+#define IS_openexr(x) (x->ftype & OPENEXR)
+
+
+#define IMAGIC 0732
+#define IS_iris(x) (x->ftype == IMAGIC)
+
+#define IS_jpg(x) (x->ftype & JPG)
+#define IS_stdjpg(x) ((x->ftype & JPG_MSK) == JPG_STD)
+#define IS_vidjpg(x) ((x->ftype & JPG_MSK) == JPG_VID)
+#define IS_jstjpg(x) ((x->ftype & JPG_MSK) == JPG_JST)
+#define IS_maxjpg(x) ((x->ftype & JPG_MSK) == JPG_MAX)
+
+#define AN_INIT an_stringdec = stringdec; an_stringenc = stringenc;
+
+#define IB_MIPMAP_LEVELS 10
+
+struct MEM_CacheLimiterHandle_s;
+
+typedef struct ImBuf {
+ struct ImBuf *next, *prev; /**< allow lists of ImBufs, for caches or flipbooks */
+ short x, y; /**< width and Height of our image buffer */
+ short skipx; /**< Width in ints to get to the next scanline */
+ unsigned char depth; /**< Active amount of bits/bitplanes */
+ unsigned char cbits; /**< Amount of active bits in cmap */
+ unsigned short mincol; /**< smallest color in colormap */
+ unsigned short maxcol; /**< Largest color in colormap */
+ int type; /**< 0=abgr, 1=bitplanes */
+ int ftype; /**< File type we are going to save as */
+ unsigned int *cmap; /**< Color map data. */
+ unsigned int *rect; /**< pixel values stored here */
+ unsigned int **planes; /**< bitplanes */
+ int flags; /**< Controls which components should exist. */
+ int mall; /**< what is malloced internal, and can be freed */
+ short xorig, yorig; /**< Cordinates of first pixel of an image used in some formats (example: targa) */
+ char name[1023]; /**< The file name assocated with this image */
+ char namenull; /**< Unused don't want to remove it thought messes things up */
+ int userflags; /**< Used to set imbuf to Dirty and other stuff */
+ int *zbuf; /**< z buffer data, original zbuffer */
+ float *zbuf_float; /**< z buffer data, camera coordinates */
+ void *userdata;
+ unsigned char *encodedbuffer; /**< Compressed image only used with png currently */
+ unsigned int encodedsize; /**< Size of data written to encodedbuffer */
+ unsigned int encodedbuffersize; /**< Size of encodedbuffer */
+
+ float *rect_float; /**< floating point Rect equivilant */
+ int channels; /**< amount of channels in rect_float (0 = 4 channel default) */
+ float dither; /**< random dither value, for conversion from float -> byte rect */
+
+ struct MEM_CacheLimiterHandle_s * c_handle; /**< handle for cache limiter */
+ int refcounter; /**< Refcounter for multiple users */
+ int index; /**< reference index for ImBuf lists */
+
+ struct ImBuf *mipmap[IB_MIPMAP_LEVELS]; /**< MipMap levels, a series of halved images */
+} ImBuf;
+
+LIBEXPORT struct ImBuf *allocImBuf(short,short,uchar,uint,uchar);
+LIBEXPORT struct ImBuf *dupImBuf(struct ImBuf *);
+LIBEXPORT void freeImBuf(struct ImBuf*);
+
+LIBEXPORT short converttocmap(struct ImBuf* ibuf);
+
+LIBEXPORT short saveiff(struct ImBuf *,char *,int);
+
+LIBEXPORT struct ImBuf *loadiffmem(int *,int);
+LIBEXPORT struct ImBuf *loadifffile(int,int);
+LIBEXPORT struct ImBuf *loadiffname(char *,int);
+LIBEXPORT struct ImBuf *testiffname(char *,int);
+
+LIBEXPORT struct ImBuf *onehalf(struct ImBuf *);
+LIBEXPORT struct ImBuf *onethird(struct ImBuf *);
+LIBEXPORT struct ImBuf *halflace(struct ImBuf *);
+LIBEXPORT struct ImBuf *half_x(struct ImBuf *);
+LIBEXPORT struct ImBuf *half_y(struct ImBuf *);
+LIBEXPORT struct ImBuf *double_x(struct ImBuf *);
+LIBEXPORT struct ImBuf *double_y(struct ImBuf *);
+LIBEXPORT struct ImBuf *double_fast_x(struct ImBuf *);
+LIBEXPORT struct ImBuf *double_fast_y(struct ImBuf *);
+
+LIBEXPORT int ispic(char *);
+
+LIBEXPORT void dit2(struct ImBuf *, short, short);
+LIBEXPORT void dit0(struct ImBuf *, short, short);
+
+LIBEXPORT struct ImBuf *scaleImBuf(struct ImBuf *, short, short);
+LIBEXPORT struct ImBuf *scalefastImBuf(struct ImBuf *, short, short);
+LIBEXPORT struct ImBuf *scalefieldImBuf(struct ImBuf *, short, short);
+LIBEXPORT struct ImBuf *scalefastfieldImBuf(struct ImBuf *, short, short);
+
+LIBEXPORT void de_interlace(struct ImBuf *ib);
+LIBEXPORT void interlace(struct ImBuf *ib);
+LIBEXPORT void gamwarp(struct ImBuf *ibuf, double gamma);
+
+LIBEXPORT void IMB_rectcpy(struct ImBuf *dbuf, struct ImBuf *sbuf,
+ int destx, int desty, int srcx, int srcy, int width, int height);
+
+LIBEXPORT void IMB_rectfill(struct ImBuf *drect, float col[4]);
+LIBEXPORT void IMB_rectfill_area(struct ImBuf *ibuf, float *col, int x1, int y1, int x2, int y2);
+LIBEXPORT void buf_rectfill_area(unsigned char *rect, float *rectf, int width, int height, float *col, int x1, int y1, int x2, int y2);
+
+#endif /* IFF_H */
+
diff --git a/source/blender/blenpluginapi/intern/Makefile b/source/blender/blenpluginapi/intern/Makefile
new file mode 100644
index 00000000000..e493ea40aa5
--- /dev/null
+++ b/source/blender/blenpluginapi/intern/Makefile
@@ -0,0 +1,57 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+#
+
+LIBNAME = blenpluginapi
+DIR = $(OCGDIR)/blender/$(LIBNAME)
+
+include nan_compile.mk
+
+ifeq ($(OS),$(findstring $(OS), "beos darwin freebsd linux openbsd solaris"))
+ CFLAGS += -shared
+endif
+
+CFLAGS += $(LEVEL_1_C_WARNINGS)
+
+# path to our own external headerfiles. On win2k this needs to be
+# longer, to avoid the util.h include problem
+CPPFLAGS += -I..
+CPPFLAGS += -I../..
+
+# also do dna
+CPPFLAGS += -I../../makesdna
+# path to blenlib
+CPPFLAGS += -I../../blenlib
+# path to imbuf
+CPPFLAGS += -I../../imbuf
+CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
+
diff --git a/source/blender/blenpluginapi/intern/pluginapi.c b/source/blender/blenpluginapi/intern/pluginapi.c
new file mode 100644
index 00000000000..43c4727cea1
--- /dev/null
+++ b/source/blender/blenpluginapi/intern/pluginapi.c
@@ -0,0 +1,365 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * Wrappers for the plugin api. This api is up for removal.
+ */
+
+/* There are four headers making up the plugin api:
+ * - floatpatch.h : Wraps math functions for mips platforms, no code
+ * required.
+ * - iff.h : Defines, macros and functions for dealing
+ * with image buffer things.
+ * - plugin.h : Wraps some plugin handling types, accesses noise
+ * functions.
+ * - util.h : Useful defines, memory management.
+ */
+
+#define PLUGIN_INTERN /* This tells the LIBEXPORT macro to compile with
+ dll export set on windows */
+
+#ifdef WIN32
+#include "blenpluginapi/util.h"
+#else
+#include "blenpluginapi/util.h"
+#endif
+#include "iff.h"
+#include "plugin.h"
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h" /* util and noise functions */
+#include "BLI_threads.h" /* For threadsfe guardedalloc malloc/calloc/free */
+#include "IMB_imbuf.h" /* image buffer stuff */
+
+/* -------------------------------------------------------------------------- */
+/* stuff from util.h */
+/* -------------------------------------------------------------------------- */
+
+LIBEXPORT void *mallocN(int len, char *str)
+{
+ return MEM_mallocN(len, str);
+}
+
+LIBEXPORT void *callocN(int len, char *str)
+{
+ return MEM_callocN(len, str);
+}
+
+LIBEXPORT short freeN(void *vmemh)
+{
+ return MEM_freeN(vmemh);
+}
+
+/* these are not needed anymore, mallocN/callocN/freeN is now threadsafe */
+LIBEXPORT void *mallocT(int len, char *str)
+{
+ return MEM_mallocN(len, str);
+}
+
+LIBEXPORT void *callocT(int len, char *str)
+{
+ return MEM_callocN(len, str);
+}
+
+LIBEXPORT void freeT(void *vmemh)
+{
+ MEM_freeN(vmemh);
+ return;
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* stuff from iff.h */
+/* -------------------------------------------------------------------------- */
+
+LIBEXPORT struct ImBuf *allocImBuf(short x,
+ short y,
+ uchar d,
+ uint flags,
+ uchar bitmap)
+{
+ return IMB_allocImBuf(x, y, d, flags, bitmap);
+}
+
+
+LIBEXPORT struct ImBuf *dupImBuf(struct ImBuf *ib)
+{
+ return IMB_dupImBuf(ib);
+}
+
+LIBEXPORT void freeImBuf(struct ImBuf* ib)
+{
+ IMB_freeImBuf(ib);
+}
+
+LIBEXPORT short converttocmap(struct ImBuf* ibuf)
+{
+ return IMB_converttocmap(ibuf);
+}
+
+LIBEXPORT short saveiff(struct ImBuf *ib,
+ char *c,
+ int i)
+{
+ return IMB_saveiff(ib, c, i);
+}
+
+LIBEXPORT struct ImBuf *loadiffmem(int *mem,int flags)
+{
+ return IMB_loadiffmem(mem, flags);
+}
+
+LIBEXPORT struct ImBuf *loadifffile(int a,
+ int b)
+{
+ return IMB_loadifffile(a, b);
+}
+
+LIBEXPORT struct ImBuf *loadiffname(char *n,
+ int flags)
+{
+ return IMB_loadiffname(n, flags);
+}
+
+LIBEXPORT struct ImBuf *testiffname(char *n,
+ int flags)
+{
+ return IMB_testiffname(n, flags);
+}
+
+LIBEXPORT struct ImBuf *onehalf(struct ImBuf *ib)
+{
+ return IMB_onehalf(ib);
+}
+
+LIBEXPORT struct ImBuf *onethird(struct ImBuf *ib)
+{
+ return IMB_onethird(ib);
+}
+
+LIBEXPORT struct ImBuf *halflace(struct ImBuf *ib)
+{
+ return IMB_halflace(ib);
+}
+
+LIBEXPORT struct ImBuf *half_x(struct ImBuf *ib)
+{
+ return IMB_half_x(ib);
+}
+
+LIBEXPORT struct ImBuf *half_y(struct ImBuf *ib)
+{
+ return IMB_half_y(ib);
+}
+
+LIBEXPORT struct ImBuf *double_x(struct ImBuf *ib)
+{
+ return IMB_double_x(ib);
+}
+
+LIBEXPORT struct ImBuf *double_y(struct ImBuf *ib)
+{
+ return IMB_double_y(ib);
+}
+
+LIBEXPORT struct ImBuf *double_fast_x(struct ImBuf *ib)
+{
+ return IMB_double_fast_x(ib);
+}
+
+LIBEXPORT struct ImBuf *double_fast_y(struct ImBuf *ib)
+{
+ return IMB_double_fast_y(ib);
+}
+
+LIBEXPORT int ispic(char * name)
+{
+ return IMB_ispic(name);
+}
+
+LIBEXPORT void dit2(struct ImBuf *ib,
+ short a,
+ short b)
+{
+ IMB_dit2(ib, a, b);
+}
+
+LIBEXPORT void dit0(struct ImBuf *ib,
+ short a,
+ short b)
+{
+ IMB_dit0(ib, a, b);
+}
+
+/* still the same name */
+/* void (*ditherfunc)(struct ImBuf *, short, short){} */
+
+LIBEXPORT struct ImBuf *scaleImBuf(struct ImBuf *ib,
+ short nx,
+ short ny)
+{
+ return IMB_scaleImBuf(ib, nx, ny);
+}
+
+LIBEXPORT struct ImBuf *scalefastImBuf(struct ImBuf *ib,
+ short x,
+ short y)
+{
+ return IMB_scalefastImBuf(ib, x, y);
+}
+
+
+LIBEXPORT struct ImBuf *scalefieldImBuf(struct ImBuf *ib,
+ short x,
+ short y)
+{
+ return IMB_scalefieldImBuf(ib, x, y);
+}
+
+LIBEXPORT struct ImBuf *scalefastfieldImBuf(struct ImBuf *ib,
+ short x,
+ short y)
+{
+ return IMB_scalefastfieldImBuf(ib, x, y);
+}
+
+ /* Extra ones that some NaN (read Ton) plugins use,
+ * even though they aren't in the header
+ */
+
+LIBEXPORT void interlace(struct ImBuf *ibuf)
+{
+ IMB_interlace(ibuf);
+}
+
+LIBEXPORT void gamwarp(struct ImBuf *ibuf, double gamma)
+{
+ IMB_gamwarp(ibuf,gamma);
+}
+
+LIBEXPORT void de_interlace(struct ImBuf *ib)
+{
+ IMB_de_interlace(ib);
+}
+
+/* -------------------------------------------------------------------------- */
+/* stuff from plugin.h */
+/* -------------------------------------------------------------------------- */
+
+/* These three need to be defined in the plugion itself. The plugin
+ * loader looks for these functions to check whether it can use the
+ * plugin. For sequences, something similar exists. */
+/* int plugin_tex_getversion(void); */
+/* int plugin_seq_getversion(void); */
+/* void plugin_getinfo(PluginInfo *); */
+
+LIBEXPORT float hnoise(float noisesize,
+ float x,
+ float y,
+ float z)
+{
+ return BLI_hnoise(noisesize, x, y, z);
+}
+
+LIBEXPORT float hnoisep(float noisesize,
+ float x,
+ float y,
+ float z)
+{
+ return BLI_hnoisep(noisesize, x, y, z);
+}
+
+LIBEXPORT float turbulence(float noisesize,
+ float x,
+ float y,
+ float z,
+ int depth)
+{
+ return BLI_turbulence(noisesize, x, y, z, depth);
+}
+
+LIBEXPORT float turbulence1(float noisesize,
+ float x,
+ float y,
+ float z,
+ int depth)
+{
+ return BLI_turbulence1(noisesize, x, y, z, depth);
+}
+
+/* -------------------------------------------------------------------------- */
+
+ /* Stupid hack - force the inclusion of all of the
+ * above functions in the binary by 'using' each one...
+ * Otherwise they will not be imported from the archive
+ * library on Unix. -zr
+ */
+int pluginapi_force_ref(void);
+
+int pluginapi_force_ref(void)
+{
+ return (int) mallocN +
+ (int) callocN +
+ (int) freeN +
+ (int) mallocT +
+ (int) callocT +
+ (int) freeT +
+ (int) allocImBuf +
+ (int) dupImBuf +
+ (int) freeImBuf +
+ (int) converttocmap +
+ (int) saveiff +
+ (int) loadiffmem +
+ (int) loadifffile +
+ (int) loadiffname +
+ (int) testiffname +
+ (int) onehalf +
+ (int) onethird +
+ (int) halflace +
+ (int) half_x +
+ (int) half_y +
+ (int) double_x +
+ (int) double_y +
+ (int) double_fast_x +
+ (int) double_fast_y +
+ (int) ispic +
+ (int) dit2 +
+ (int) dit0 +
+ (int) scaleImBuf +
+ (int) scalefastImBuf +
+ (int) scalefieldImBuf +
+ (int) scalefastfieldImBuf +
+ (int) hnoise +
+ (int) hnoisep +
+ (int) turbulence +
+ (int) turbulence1 +
+ (int) de_interlace +
+ (int) interlace +
+ (int) gamwarp;
+}
diff --git a/source/blender/blenpluginapi/plugin.DEF b/source/blender/blenpluginapi/plugin.DEF
new file mode 100644
index 00000000000..ae2692c7cff
--- /dev/null
+++ b/source/blender/blenpluginapi/plugin.DEF
@@ -0,0 +1,40 @@
+LIBRARY
+EXPORTS
+mallocN
+callocN
+freeN
+mallocT
+callocT
+freeT
+hnoise
+hnoisep
+turbulence
+turbulence1
+allocImBuf
+dupImBuf
+freeImBuf
+converttocmap
+saveiff
+loadiffmem
+loadifffile
+loadiffname
+testiffname
+onehalf
+onethird
+halflace
+half_x
+half_y
+double_x
+double_y
+double_fast_x
+double_fast_y
+ispic
+dit2
+dit0
+scaleImBuf
+scalefastImBuf
+scalefieldImBuf
+scalefastfieldImBuf
+de_interlace
+interlace
+gamwarp
diff --git a/source/blender/blenpluginapi/plugin.h b/source/blender/blenpluginapi/plugin.h
new file mode 100644
index 00000000000..1f6140130eb
--- /dev/null
+++ b/source/blender/blenpluginapi/plugin.h
@@ -0,0 +1,103 @@
+/* Copyright (c) 1999, Not a Number / NeoGeo b.v.
+ * $Id$
+ *
+ * All rights reserved.
+ *
+ * Contact: info@blender.org
+ * Information: http://www.blender.org
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 PLUGIN_H
+#define PLUGIN_H
+
+#include "externdef.h"
+#include "iff.h"
+#include "util.h"
+#include "floatpatch.h"
+
+#define B_PLUGIN_VERSION 5
+
+typedef int (*TexDoit)(int, void*, float*, float*, float*);
+typedef void (*SeqDoit)(void*, float, float, int, int, ImBuf*, ImBuf*, ImBuf*, ImBuf*);
+
+typedef struct VarStruct {
+ int type;
+ char name[16];
+ float def, min, max;
+ char tip[80];
+} VarStruct;
+
+typedef struct _PluginInfo {
+ char *name;
+ char *snames;
+
+ int stypes;
+ int nvars;
+ VarStruct *varstr;
+ float *result;
+ float *cfra;
+
+ void (*init)(void);
+ void (*callback)(int);
+ TexDoit tex_doit;
+ SeqDoit seq_doit;
+
+ void (*instance_init)(void *);
+} PluginInfo;
+
+int plugin_tex_getversion(void);
+int plugin_seq_getversion(void);
+void plugin_getinfo(PluginInfo *);
+
+/* *************** defines for button types ************** */
+
+#define CHA 32
+#define INT 96
+#define FLO 128
+
+#define TOG (3<<9)
+#define NUM (5<<9)
+#define LABEL (10<<9)
+#define NUMSLI (14<<9)
+#define COL (15<<9)
+
+/* return values (bitfield like) for textures (DNA_texture_types.h) */
+#define TEX_INT 0
+#define TEX_RGB 1
+#define TEX_NOR 2
+
+/* *************** API functions ******************** */
+
+ /* derived from the famous Perlin noise */
+LIBEXPORT float hnoise(float noisesize, float x, float y, float z);
+ /* the original Perlin noise */
+LIBEXPORT float hnoisep(float noisesize, float x, float y, float z);
+
+ /* soft turbulence */
+LIBEXPORT float turbulence(float noisesize, float x, float y, float z, int depth);
+ /* hard turbulence */
+LIBEXPORT float turbulence1(float noisesize, float x, float y, float z, int depth);
+
+#endif /* PLUGIN_H */
+
diff --git a/source/blender/blenpluginapi/util.h b/source/blender/blenpluginapi/util.h
new file mode 100644
index 00000000000..b0b5f3aae54
--- /dev/null
+++ b/source/blender/blenpluginapi/util.h
@@ -0,0 +1,100 @@
+/* Copyright (c) 1999, Not a Number / NeoGeo b.v.
+ * $Id$
+ *
+ * All rights reserved.
+ *
+ * Contact: info@blender.org
+ * Information: http://www.blender.org
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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_H
+#define UTIL_H
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
+#include "externdef.h"
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef ulong
+#define ulong unsigned long
+#endif
+
+#ifndef ushort
+#define ushort unsigned short
+#endif
+
+#ifndef uchar
+#define uchar unsigned char
+#endif
+
+#ifndef uint
+#define uint unsigned int
+#endif
+
+#define MIN2(x,y) ( (x)<(y) ? (x) : (y) )
+#define MIN3(x,y,z) MIN2( MIN2((x),(y)) , (z) )
+#define MIN4(x,y,z,a) MIN2( MIN2((x),(y)) , MIN2((z),(a)) )
+
+#define MAX2(x,y) ( (x)>(y) ? (x) : (y) )
+#define MAX3(x,y,z) MAX2( MAX2((x),(y)) , (z) )
+#define MAX4(x,y,z,a) MAX2( MAX2((x),(y)) , MAX2((z),(a)) )
+
+#define SWAP(type, a, b) { type sw_ap; sw_ap=(a); (a)=(b); (b)=sw_ap; }
+
+#define ABS(x) ((x) < 0 ? -(x) : (x))
+#define FLOOR(x) ((int)(x) - ((x) < 0 && (x) != (int)(x)))
+#define CEIL(x) ((int)(x) + ((x) > 0 && (x) != (int)(x)))
+#define STEP(a,b) ( (a)>(b) ? (1) : (0) )
+#define CLAMP(val, low, high) ((val>high)?high:((val<low)?low:val))
+#define LERP(t,x0,x1) ((x0) + (t)*((x1)-(x0)))
+#define PULSE(a,b,x) (STEP((a),(x)) - STEP((b),(x)))
+#define BOXSTEP(a,b,x) CLAMP(((x)-(a))/((b)-(a)),0,1)
+
+#define PRINT(d, var1) printf(# var1 ":%" # d "\n", var1)
+#define PRINT2(d, e, var1, var2) printf(# var1 ":%" # d " " # var2 ":%" # e "\n", var1, var2)
+#define PRINT3(d, e, f, var1, var2, var3) printf(# var1 ":%" # d " " # var2 ":%" # e " " # var3 ":%" # f "\n", var1, var2, var3)
+#define PRINT4(d, e, f, g, var1, var2, var3, var4) printf(# var1 ":%" # d " " # var2 ":%" # e " " # var3 ":%" # f " " # var4 ":%" # g "\n", var1, var2, var3, var4)
+
+LIBEXPORT void *mallocN(int len, char *str);
+LIBEXPORT void *callocN(int len, char *str);
+LIBEXPORT short freeN(void *vmemh);
+
+LIBEXPORT void *mallocT(int len, char *str);
+LIBEXPORT void *callocT(int len, char *str);
+LIBEXPORT void freeT(void *vmemh);
+
+#endif /* UTIL_H */
+
diff --git a/source/blender/ftfont/CMakeLists.txt b/source/blender/ftfont/CMakeLists.txt
new file mode 100644
index 00000000000..7b89416bbe1
--- /dev/null
+++ b/source/blender/ftfont/CMakeLists.txt
@@ -0,0 +1,46 @@
+# $Id$
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2006, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Jacques Beaurain.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+
+FILE(GLOB SRC intern/*.cpp)
+
+SET(INC
+ . intern ../blenkernel ../blenlib ../makesdna ../include
+ ${FTGL_INC}
+ ${FREETYPE_INC}
+ ${GETTEXT_INC}
+)
+
+ADD_DEFINITIONS(-DFTGL_LIBRARY_STATIC)
+
+IF(WIN32)
+ ADD_DEFINITIONS(-D_WIN32 -DUSE_GETTEXT_DLL)
+ENDIF(WIN32)
+
+BLENDERLIB(bf_ftfont "${SRC}" "${INC}")
+#env.BlenderLib ( 'bf_ftfont', sources, Split(incs), Split(defs), libtype=['international','player'], priority=[0, 205] )
diff --git a/source/blender/ftfont/FTF_Api.h b/source/blender/ftfont/FTF_Api.h
new file mode 100644
index 00000000000..0793c4b6dfb
--- /dev/null
+++ b/source/blender/ftfont/FTF_Api.h
@@ -0,0 +1,166 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef _FTF_API_H
+#define _FTF_API_H
+
+#define FTF_EXPORT
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#include "FTF_Settings.h"
+
+/**
+ * Set Font Size
+ * @param int size
+ */
+FTF_EXPORT void FTF_SetSize(int size);
+
+/**
+ * Get Font Size
+ * @return Font size
+ */
+FTF_EXPORT int FTF_GetSize(void);
+
+/**
+ * Ascender
+ * @return Ascend size
+ */
+FTF_EXPORT int FTF_Ascender(void);
+
+/**
+ * Descender
+ * @return Descend size
+ */
+FTF_EXPORT int FTF_Descender(void);
+
+/**
+ * String Translation and Code Conversion
+ * @param str source string
+ * @param ustr distnation string
+ * @param flag mode flag
+ */
+FTF_EXPORT void FTF_TransConvString(char* str, char* ustr, unsigned int flag);
+
+/**
+ * Draw a character at the current raster position.
+ * @param c the character to draw
+ * @param mode flag to forward to FTF_TransConvString()
+ * @return Width drawing
+ */
+//FTF_EXPORT float FTF_DrawCharacter(char c, unsigned int flag);
+
+/**
+ * Draws a string at the current raster postion.
+ * @param str The string to draw
+ * @param mode flag to forward to FTF_TransConvString()
+ * @return Width drawing
+ */
+FTF_EXPORT float FTF_DrawString(char* str, unsigned int flag);
+
+
+/**
+ * Get a character width
+ * @param mode flag to forward to FTF_TransConvString()
+ */
+FTF_EXPORT float FTF_GetCharacterWidth(char c, unsigned int flag);
+
+
+/**
+ * Get a string width
+ * @param mode flag to forward to FTF_TransConvString()
+ */
+FTF_EXPORT float FTF_GetStringWidth(char* str, unsigned int flag);
+
+/**
+ * Get Bounding Box
+ * @param llx Lower left near x coord
+ * @param lly Lower left near y coord
+ * @param llz Lower left near z coord
+ * @param urx Upper right far x coord
+ * @param ury Upper right far y coord
+ * @param urz Upper right far z coord
+ * @param mode flag to forward to FTF_TransConvString()
+ * not test yet.
+ */
+FTF_EXPORT void FTF_GetBoundingBox(char* str, float*llx, float *lly, float *llz, float *urx, float *ury, float *urz, unsigned int flag);
+
+/**
+ * Following stuff added by phase, ton
+ */
+
+/**
+ * SetFontSize
+ * @param size
+ */
+FTF_EXPORT void FTF_SetFontSize(char size);
+
+/**
+ * SetFont
+ * @param str
+ * @param size
+ */
+FTF_EXPORT int FTF_SetFont(const unsigned char* str, int datasize, int fontsize);
+
+/**
+ * SetLanguage
+ * @param str
+ * not test yet.
+ */
+FTF_EXPORT void FTF_SetLanguage(char* str);
+
+/**
+ * SetLanguage
+ * @param str
+ * not tested yet.
+ */
+FTF_EXPORT void FTF_SetEncoding(char* str);
+
+FTF_EXPORT void FTF_SetPosition(float x, float y);
+FTF_EXPORT void FTF_SetMode(int mode);
+FTF_EXPORT void FTF_SetScale(float fsize);
+
+FTF_EXPORT void FTF_End(void);
+
+/* Font preview functions */
+FTF_EXPORT int FTF_GetNewFont (const unsigned char *str, int datasize, int fontsize);
+FTF_EXPORT float FTF_DrawNewFontString(char* str, unsigned int flag);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __FTF_API_H */
+
diff --git a/source/blender/ftfont/FTF_Settings.h b/source/blender/ftfont/FTF_Settings.h
new file mode 100644
index 00000000000..dc325c1de41
--- /dev/null
+++ b/source/blender/ftfont/FTF_Settings.h
@@ -0,0 +1,49 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) 2002 Blender Foundation. All Rights Reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/**
+
+ * $Id$
+ * Copyright (C) 2001 NaN Technologies B.V.
+ * Allows you to determine which fonts to include in the library.
+ */
+
+#ifndef __FTF_SETTINGS_H
+#define __FTF_SETTINGS_H
+
+#define FTF_BIT(num) ((unsigned int)1 << (num))
+#define FTF_NO_TRANSCONV 0
+#define FTF_INPUT_SYSTEM_ENCODING FTF_BIT(1)
+#define FTF_USE_GETTEXT FTF_BIT(2)
+#define FTF_INPUT_UTF8 FTF_BIT(3)
+#define FTF_PIXMAPFONT 0
+#define FTF_TEXTUREFONT 1
+
+#endif /* __FTF_SETTINGS_H */
diff --git a/source/blender/ftfont/Makefile b/source/blender/ftfont/Makefile
new file mode 100644
index 00000000000..1717fa34853
--- /dev/null
+++ b/source/blender/ftfont/Makefile
@@ -0,0 +1,37 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+# Bounces make to subdirectories.
+
+SOURCEDIR = source/blender/ftfont
+DIRS = intern
+
+include nan_subdirs.mk
diff --git a/source/blender/ftfont/SConscript b/source/blender/ftfont/SConscript
new file mode 100644
index 00000000000..615b274677c
--- /dev/null
+++ b/source/blender/ftfont/SConscript
@@ -0,0 +1,16 @@
+#!/usr/bin/python
+import sys
+Import ('env')
+
+sources = env.Glob('intern/*.cpp')
+
+incs = '. intern ../blenkernel ../blenlib ../makesdna ../include'
+incs += ' ' + env['BF_FTGL_INC']
+incs += ' ' + env['BF_FREETYPE_INC']
+incs += ' ' + env['BF_GETTEXT_INC']
+
+defs = 'FTGL_STATIC_LIBRARY'
+if sys.platform == 'win32':
+ defs += ' _WIN32 USE_GETTEXT_DLL'
+
+env.BlenderLib ( 'bf_ftfont', sources, Split(incs), Split(defs), libtype=['international','player'], priority=[0, 205] )
diff --git a/source/blender/ftfont/intern/FTF_Api.cpp b/source/blender/ftfont/intern/FTF_Api.cpp
new file mode 100644
index 00000000000..bf6698a1cde
--- /dev/null
+++ b/source/blender/ftfont/intern/FTF_Api.cpp
@@ -0,0 +1,208 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) 2002 Blender Foundation. All Rights Reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/**
+
+ * $Id$
+ * Copyright (C) 2001 NaN Technologies B.V.
+ *
+ * Implementation of the API of FTGL library.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "../FTF_Api.h"
+#include "FTF_TTFont.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ #include "datatoc.h"
+#ifdef __cplusplus
+}
+#endif
+
+#define FTF_EXPORT
+
+FTF_TTFont *newfont= 0; // preview font
+
+static FTF_TTFont *_FTF_GetFont(void) {
+ static FTF_TTFont *theFont = NULL;
+
+ if (!theFont) {
+ theFont = new FTF_TTFont();
+ }
+
+ return theFont;
+}
+
+FTF_EXPORT int FTF_GetNewFont (const unsigned char *str, int datasize, int fontsize) {
+
+ if (newfont) delete newfont;
+ newfont= new FTF_TTFont();
+
+ if (!(newfont->SetFont((unsigned char*)str, datasize, fontsize))) {
+ newfont->SetFont((unsigned char*)datatoc_bfont_ttf, datatoc_bfont_ttf_size, fontsize);
+ return 0;
+ }
+ return 1;
+}
+
+FTF_EXPORT float FTF_DrawNewFontString(char* str, unsigned int flag)
+{
+ if (newfont)
+ return newfont->DrawString(str, flag);
+ return 0.0f;
+}
+
+FTF_EXPORT void FTF_End(void) {
+ delete _FTF_GetFont();
+ delete newfont;
+}
+
+FTF_EXPORT void FTF_SetSize(int size)
+{
+ _FTF_GetFont()->SetSize(size);
+}
+
+FTF_EXPORT int FTF_GetSize(void)
+{
+ return _FTF_GetFont()->GetSize();
+}
+
+/*
+FTF_EXPORT int FTF_Ascender(void)
+{
+ return _FTF_GetFont()->Ascender();
+}
+
+FTF_EXPORT int FTF_Descender(void)
+{
+ return _FTF_GetFont()->Descender();
+}
+*/
+
+FTF_EXPORT void FTF_TransConvString(char* str, char* ustr, unsigned int flag)
+{
+ _FTF_GetFont()->TransConvString(str, ustr, flag);
+}
+
+/*
+FTF_EXPORT float FTF_DrawCharacter(char c, unsigned int flag)
+{
+ char str[2] = {c, '\0'};
+ return FTF_DrawString(str, flag);
+}
+*/
+
+
+/* does color too, using glGet */
+FTF_EXPORT float FTF_DrawString(char* str, unsigned int flag)
+{
+ return _FTF_GetFont()->DrawString(str, flag);
+}
+
+
+/**
+ * not implemente yet.
+ */
+FTF_EXPORT float FTF_GetCharacterWidth(char c, unsigned int flag)
+{
+ char str[2] = {c, '\0'};
+ return FTF_GetStringWidth(str, flag);
+}
+
+
+/**
+ * not implemente yet.
+ */
+FTF_EXPORT float FTF_GetStringWidth(char* str, unsigned int flag)
+{
+ return _FTF_GetFont()->GetStringWidth(str, flag);
+}
+
+
+/**
+ * not implemente yet.
+ * ## This return string box!! ##
+ */
+FTF_EXPORT void FTF_GetBoundingBox(char* str, float *llx, float *lly, float *llz, float *urx, float *ury, float *urz, unsigned int flag)
+{
+ _FTF_GetFont()->GetBoundingBox(str, llx, lly, llz, urx, ury, urz, flag);
+}
+
+/**
+ * added by phase
+ * changed by ton; to allow both file load as memory load (datasize!=0)
+ */
+FTF_EXPORT int FTF_SetFont(const unsigned char* str, int datasize, int fontsize)
+{
+ return _FTF_GetFont()->SetFont(str, datasize, fontsize);
+}
+
+/* added by ton */
+
+FTF_EXPORT void FTF_SetFontSize(char size)
+{
+ _FTF_GetFont()->SetFontSize( size);
+}
+
+/**
+ * added by phase
+ *
+ */
+FTF_EXPORT void FTF_SetLanguage(char* str)
+{
+ _FTF_GetFont()->SetLanguage(str);
+}
+
+FTF_EXPORT void FTF_SetEncoding(char* str)
+{
+ _FTF_GetFont()->SetEncoding(str);
+}
+
+FTF_EXPORT void FTF_SetPosition(float x, float y)
+{
+ _FTF_GetFont()->SetPosition(x, y);
+}
+
+FTF_EXPORT void FTF_SetMode(int mode)
+{
+ _FTF_GetFont()->SetMode(mode);
+}
+
+FTF_EXPORT void FTF_SetScale(float fsize)
+{
+ _FTF_GetFont()->SetScale(fsize);
+}
+
+
diff --git a/source/blender/ftfont/intern/FTF_TTFont.cpp b/source/blender/ftfont/intern/FTF_TTFont.cpp
new file mode 100644
index 00000000000..34b22e5c9d2
--- /dev/null
+++ b/source/blender/ftfont/intern/FTF_TTFont.cpp
@@ -0,0 +1,448 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) 2002 Blender Foundation. All Rights Reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <locale.h>
+#include "libintl.h"
+#include "BLI_blenlib.h"
+
+#include "../FTF_Settings.h"
+
+#include "FTF_TTFont.h"
+
+#ifdef __APPLE__
+#include "BKE_utildefines.h"
+#endif
+
+#define DOMAIN_NAME "blender"
+
+#define SYSTEM_ENCODING_DEFAULT "UTF-8"
+#define FONT_SIZE_DEFAULT 12
+//#define FONT_PATH_DEFAULT ".bfont.ttf"
+
+#define FTF_MAX_STR_SIZE 512
+
+
+int utf8towchar(wchar_t *w, char *c)
+{
+ int len=0;
+ if(w==NULL || c==NULL) return(0);
+ //printf("%s\n",c);
+ while(*c)
+ {
+ //Converts Unicode to wchar:
+
+ if(*c & 0x80)
+ {
+ if(*c & 0x40)
+ {
+ if(*c & 0x20)
+ {
+ if(*c & 0x10)
+ {
+ *w=(c[0] & 0x0f)<<18 | (c[1]&0x1f)<<12 | (c[2]&0x3f)<<6 | (c[3]&0x7f);
+ c++;
+ }
+ else
+ *w=(c[0] & 0x1f)<<12 | (c[1]&0x3f)<<6 | (c[2]&0x7f);
+ c++;
+ }
+ else
+ *w=(c[0] &0x3f)<<6 | c[1]&0x7f;
+ c++;
+ }
+ else
+ *w=(c[0] & 0x7f);
+ }
+ else
+ *w=(c[0] & 0x7f);
+
+ c++;
+ w++;
+ len++;
+ }
+ return len;
+}
+
+
+FTF_TTFont::FTF_TTFont(void)
+{
+#ifdef __APPLE__
+ char *bundlepath;
+#endif
+
+ font=NULL;
+ fontm= fonts= fontl= NULL;
+ font_size=FONT_SIZE_DEFAULT;
+ mode = FTF_PIXMAPFONT;
+ fsize = 1.0;
+ strcpy(encoding_name, SYSTEM_ENCODING_DEFAULT);
+
+ //set messagepath directory
+
+#ifndef LOCALEDIR
+#define LOCALEDIR "/usr/share/locale"
+#endif
+
+ strcpy(messagepath, ".blender/locale");
+
+ if ( !BLI_exist(messagepath) ) { // locale not in current dir
+ BLI_make_file_string("/", messagepath, BLI_gethome(), ".blender/locale");
+
+ if( !BLI_exist(messagepath) ) { // locale not in home dir
+
+#ifdef WIN32
+ BLI_make_file_string("/", messagepath, BLI_gethome(), "/locale");
+ if( !BLI_exist(messagepath) ) {
+#endif
+#ifdef __APPLE__
+ /* message catalogs are stored inside the application bundle */
+ bundlepath = BLI_getbundle();
+ strcpy(messagepath, bundlepath);
+ strcat(messagepath, "/Contents/Resources/locale");
+ if( !BLI_exist(messagepath) ) { // locale not in bundle (now that's odd..)
+#endif
+ strcpy(messagepath, LOCALEDIR);
+
+ if( !BLI_exist(messagepath) ) { // locale not in LOCALEDIR
+ strcpy(messagepath, "message"); // old compatibility as last
+ }
+#ifdef WIN32
+ }
+#endif
+#ifdef __APPLE__
+ }
+#endif
+ }
+ }
+}
+
+
+FTF_TTFont::~FTF_TTFont(void)
+{
+ if (fonts) delete fonts;
+ if (fontm) delete fontm;
+ if (fontl) delete fontl;
+}
+
+void FTF_TTFont::SetFontSize(char size)
+{
+ if(size=='s') font=fonts;
+ else if(size=='l') font=fontl;
+ else font=fontm;
+}
+
+int FTF_TTFont::SetFont(const unsigned char* str, int datasize, int fontsize)
+{
+ int err = 0;
+ bool success = 0;
+
+ if (fonts) delete fonts;
+ if (fontm) delete fontm;
+ if (fontl) delete fontl;
+ fonts= NULL;
+ fontm= NULL;
+ fontl= NULL;
+
+ if(mode == FTF_PIXMAPFONT) {
+
+ if(datasize) font = new FTGLPixmapFont(str, datasize);
+ else font = new FTGLPixmapFont( (char *)str);
+
+ err = font->Error();
+
+ if(err) {
+ printf("Failed to open font %s\n", str);
+ return 0;
+ } else {
+
+ fontm= font;
+
+ if(datasize) fonts = new FTGLPixmapFont(str, datasize);
+ else fonts = new FTGLPixmapFont((char *)str);
+ if(datasize) fontl = new FTGLPixmapFont(str, datasize);
+ else fontl = new FTGLPixmapFont((char *)str);
+
+ success = fonts->FaceSize(fontsize-2<8?8:fontsize-2);
+ success = fontm->FaceSize(fontsize-1<8?8:fontsize-1);
+ success = fontl->FaceSize(fontsize);
+ if(!success) return 0;
+
+ success = fonts->CharMap(ft_encoding_unicode);
+ success = fontm->CharMap(ft_encoding_unicode);
+ success = fontl->CharMap(ft_encoding_unicode);
+ if(!success) return 0;
+
+ return 1;
+ }
+
+ } else if(mode == FTF_TEXTUREFONT) {
+
+ if(datasize) font = new FTGLTextureFont(str, datasize);
+ else font = new FTGLTextureFont( (char *)str);
+
+ err = font->Error();
+
+ if(err) {
+ printf("Failed to open font %s\n", str);
+ return 0;
+ } else {
+
+ fontm= font;
+
+ if(datasize) fonts = new FTGLTextureFont(str, datasize);
+ else fonts = new FTGLTextureFont((char *)str);
+ if(datasize) fontl = new FTGLTextureFont(str, datasize);
+ else fontl = new FTGLTextureFont((char *)str);
+
+ success = fonts->FaceSize(fontsize-2<8?8:fontsize-2);
+ success = fontm->FaceSize(fontsize-1<8?8:fontsize-1);
+ success = fontl->FaceSize(fontsize);
+// success = fonts->FaceSize(fontsize/2);
+// success = fontm->FaceSize(fontsize);
+// success = fontl->FaceSize(fontsize*2);
+ if(!success) return 0;
+
+ success = fonts->CharMap(ft_encoding_unicode);
+ success = fontm->CharMap(ft_encoding_unicode);
+ success = fontl->CharMap(ft_encoding_unicode);
+ if(!success) return 0;
+
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void FTF_TTFont::SetLanguage(char* str)
+{
+
+#if defined (_WIN32) || defined(__APPLE__)
+ char envstr[12];
+
+ sprintf(envstr, "LANG=%s", str);
+ envstr[strlen(envstr)]='\0';
+#ifdef _WIN32
+ gettext_putenv(envstr);
+#else
+ putenv(envstr);
+#endif
+#else
+ char *locreturn = setlocale(LC_ALL, str);
+ if (locreturn == NULL) {
+ char *lang;
+
+ lang = (char*)malloc(sizeof(char)*(strlen(str)+7));
+
+ lang[0] = '\0';
+ strcat(lang, str);
+ strcat(lang, ".UTF-8");
+
+ locreturn = setlocale(LC_ALL, lang);
+ if (locreturn == NULL) {
+ printf("could not change language to %s nor %s\n", str, lang);
+ }
+
+ free(lang);
+ }
+
+ setlocale(LC_NUMERIC, "C");
+#endif
+
+
+ bindtextdomain(DOMAIN_NAME, messagepath);
+// bind_textdomain_codeset(DOMAIN_NAME, encoding_name);
+ textdomain(DOMAIN_NAME);
+
+ strcpy(language, str);
+}
+
+
+void FTF_TTFont::SetEncoding(char* str)
+{
+ strcpy(encoding_name, str);
+// bind_textdomain_codeset(DOMAIN_NAME, encoding_name);
+}
+
+
+void FTF_TTFont::SetSize(int size)
+{
+ fonts->FaceSize(size-2<8?8:size-2);
+ fontm->FaceSize(size-1<8?8:size-1);
+ fontl->FaceSize(size);
+
+ font_size = size;
+}
+
+int FTF_TTFont::GetSize(void)
+{
+ return font_size;
+}
+
+/*
+int FTF_TTFont::Ascender(void)
+{
+ return (int)font->Ascender();
+}
+
+int FTF_TTFont::Descender(void)
+{
+ return (int)font->Descender();
+}
+
+*/
+int FTF_TTFont::TransConvString(char* str, char* ustr, unsigned int flag)
+{
+ return 0;
+}
+
+
+float FTF_TTFont::DrawString(char* str, unsigned int flag)
+{
+ float color[4];
+ wchar_t wstr[FTF_MAX_STR_SIZE-1]={'\0'};
+
+ /* note; this utf8towchar() function I totally don't understand... without using translations it
+ removes special characters completely. So, for now we just skip that then. (ton) */
+ if (FTF_USE_GETTEXT & flag)
+ utf8towchar(wstr, gettext(str));
+ else if (FTF_INPUT_UTF8 & flag)
+ utf8towchar(wstr, str);
+
+ glGetFloatv(GL_CURRENT_COLOR, color);
+
+ if(mode == FTF_PIXMAPFONT) {
+
+ glPixelTransferf(GL_RED_SCALE, color[0]);
+ glPixelTransferf(GL_GREEN_SCALE, color[1]);
+ glPixelTransferf(GL_BLUE_SCALE, color[2]);
+
+ if ((FTF_USE_GETTEXT | FTF_INPUT_UTF8) & flag)
+ font->Render(wstr);
+ else
+ font->Render(str);
+
+ glPixelTransferf(GL_RED_SCALE, 1.0);
+ glPixelTransferf(GL_GREEN_SCALE, 1.0);
+ glPixelTransferf(GL_BLUE_SCALE, 1.0);
+
+ } else if(mode == FTF_TEXTUREFONT) {
+
+ glEnable(GL_BLEND);
+ glEnable(GL_TEXTURE_2D);
+
+ glPushMatrix();
+ glTranslatef(pen_x, pen_y, 0.0);
+ glScalef(fsize, fsize, 1.0);
+
+ if ((FTF_USE_GETTEXT | FTF_INPUT_UTF8) & flag)
+ font->Render(wstr);
+ else
+ font->Render(str);
+
+ glPopMatrix();
+
+ glDisable(GL_BLEND);
+ glDisable(GL_TEXTURE_2D);
+ }
+
+ if ((FTF_USE_GETTEXT | FTF_INPUT_UTF8) & flag)
+ return font->Advance(wstr);
+ else
+ return font->Advance(str);
+}
+
+
+float FTF_TTFont::GetStringWidth(char* str, unsigned int flag)
+{
+ wchar_t wstr[FTF_MAX_STR_SIZE-1]={'\0'};
+ int len=0;
+
+ if (strlen(str)==0) return 0.0;
+
+ /* note; this utf8towchar() function I totally don't understand... without using translations it
+ removes special characters completely. So, for now we just skip that then. (ton) */
+
+ if (FTF_USE_GETTEXT & flag) {
+ len=utf8towchar(wstr, gettext(str));
+
+ if(mode == FTF_PIXMAPFONT) {
+ return font->Advance(wstr);
+ } else if(mode == FTF_TEXTUREFONT) {
+ return font->Advance(wstr);// * fsize;
+ }
+ }
+ else {
+ if(mode == FTF_PIXMAPFONT) {
+ return font->Advance(str);
+ } else if(mode == FTF_TEXTUREFONT) {
+ return font->Advance(str);// * fsize;
+ }
+ }
+
+ return 0.0;
+}
+
+
+void FTF_TTFont::GetBoundingBox(char* str, float *llx, float *lly, float *llz, float *urx, float *ury, float *urz, unsigned int flag)
+{
+ wchar_t wstr[FTF_MAX_STR_SIZE-1]={'\0'};
+ int len=0;
+
+ if (FTF_USE_GETTEXT & flag)
+ len=utf8towchar(wstr,gettext(str));
+ else
+ len=utf8towchar(wstr,str);
+
+ font->BBox(wstr, *llx, *lly, *llz, *urx, *ury, *urz);
+}
+
+
+void FTF_TTFont::SetPosition(float x, float y)
+{
+ pen_x = x;
+ pen_y = y;
+}
+
+
+void FTF_TTFont::SetMode(int m)
+{
+ mode = m;
+}
+
+
+void FTF_TTFont::SetScale(float size)
+{
+ fsize = size;
+}
+
+
diff --git a/source/blender/ftfont/intern/FTF_TTFont.h b/source/blender/ftfont/intern/FTF_TTFont.h
new file mode 100644
index 00000000000..b5ff1cc54bf
--- /dev/null
+++ b/source/blender/ftfont/intern/FTF_TTFont.h
@@ -0,0 +1,139 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) 2002 Blender Foundation. All Rights Reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/**
+
+ * $Id$
+ * Copyright (C) 2001 NaN Technologies B.V.
+ */
+
+#ifndef __FTF_TRUETYPE_FONT_H
+#define __FTF_TRUETYPE_FONT_H
+
+#include "FTGLPixmapFont.h"
+#include "FTGLTextureFont.h"
+
+#include <stdio.h>
+//#include <iconv.h>
+
+
+/**
+ * Base class for Using FTGL, iconv and gettext Library.
+ */
+class FTF_TTFont
+{
+public:
+ /**
+ * Default constructor.
+ */
+ FTF_TTFont(void);
+
+ /**
+ * Destructor.
+ */
+ virtual ~FTF_TTFont(void);
+
+
+ void SetSize(int size);
+ int GetSize(void);
+
+// int Ascender(void);
+// int Descender(void);
+
+ int TransConvString(char* str, char* ustr, unsigned int flag);
+
+ /**
+ * Draws a string at the current raster position in current opengl color.
+ * @param str The string to draw.
+ * @param flag Whether use gettext and UTF8 or system encoding.
+ */
+ float DrawString(char* str, unsigned int flag);
+
+ float GetStringWidth(char* str, unsigned int flag);
+
+ /**
+ * Get the bounding box for a string.
+ *
+ * @param str The string
+ * @param llx Lower left near x coord
+ * @param lly Lower left near y coord
+ * @param llz Lower left near z coord
+ * @param urx Upper right far x coord
+ * @param ury Upper right far y coord
+ * @param urz Upper right far z coord
+ */
+ void GetBoundingBox(char* str, float *llx, float *lly, float *llz, float *urx, float *ury, float *urz, unsigned int flag);
+
+ /**
+ * added by phase, ton
+ * functions to communicate with the preference menu
+ */
+ void SetFontSize(char size);
+
+ int SetFont(const unsigned char* str, int datasize, int fontsize);
+
+ void SetLanguage(char* str);
+
+ void SetEncoding(char* str);
+
+ /**
+ * functions to communicate with blender ui rasterpos
+ */
+ void SetPosition(float x, float y);
+ void SetMode(int mode);
+ void SetScale(float fsize);
+
+protected:
+ char messagepath[1024];
+
+ char language[32];
+ char encoding_name[32];
+ char font_name[128];
+ int font_size;
+
+ int mode; // 0 = pixmap, 1 = texture
+ float pen_x, pen_y; //rasterpos
+ float fsize;
+
+ /** FTGL's */
+ FTFont* font; /* active */
+
+ FTFont* fonts; /* opened, small medium and large */
+ FTFont* fontm;
+ FTFont* fontl;
+
+ /** from system encoding in .locale to UNICODE */
+// iconv_t cd;
+
+ /** from UTF-8 to UNICODE */
+// iconv_t ucd;
+};
+
+#endif // __FTF_TRUETYPE_FONT_H
diff --git a/source/blender/ftfont/intern/Makefile b/source/blender/ftfont/intern/Makefile
new file mode 100644
index 00000000000..064ec5dc597
--- /dev/null
+++ b/source/blender/ftfont/intern/Makefile
@@ -0,0 +1,59 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+#
+
+LIBNAME = ftfont
+DIR = $(OCGDIR)/blender/ftfont
+
+include nan_compile.mk
+
+CFLAGS += $(LEVEL_1_C_WARNINGS)
+
+#CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
+CPPFLAGS += -I../../makesdna
+CPPFLAGS += -I../../blenkernel
+CPPFLAGS += -I../../blenlib
+CPPFLAGS += -I../../include
+CPPFLAGS += -I$(NAN_FTGL)/include
+CPPFLAGS += -I$(NAN_FTGL)/include/FTGL
+CPPFLAGS += -I$(NAN_GETTEXT)/include
+CPPFLAGS += -I$(NAN_FREETYPE)/include
+ifeq ($(OS), windows)
+ CPPFLAGS += -I$(NAN_ICONV)/include
+ ifeq ($(FREE_WINDOWS), true)
+ CPPFLAGS += -I$(NAN_FREETYPE)/include/freetype2
+ CPPFLAGS += -DUSE_GETTEXT_DLL
+ endif
+else
+ CPPFLAGS += -I$(NAN_FREETYPE)/include/freetype2
+endif
+CPPFLAGS += -I..
diff --git a/source/blender/imbuf/CMakeLists.txt b/source/blender/imbuf/CMakeLists.txt
new file mode 100644
index 00000000000..146ec654c1e
--- /dev/null
+++ b/source/blender/imbuf/CMakeLists.txt
@@ -0,0 +1,61 @@
+# $Id$
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2006, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Jacques Beaurain.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+
+FILE(GLOB SRC intern/*.c)
+
+SET(INC
+ . ../makesdna ../../../intern/guardedalloc ../../../intern/memutil ../blenlib
+ ../avi ../quicktime ../blenkernel
+ ${JPEG_INC}
+ ${PNG_INC}
+ ${TIFF_INC}
+ ${ZLIB_INC}
+)
+
+IF(WITH_VERSE)
+ ADD_DEFINITIONS(-DWITH_VERSE)
+ SET(INC ${INC} VERSE_INC)
+ENDIF(WITH_VERSE)
+
+IF(WITH_OPENEXR)
+ ADD_DEFINITIONS(-DWITH_OPENEXR)
+ENDIF(WITH_OPENEXR)
+
+IF(WITH_QUICKTIME)
+ SET(INC ${INC} ${QUICKTIME_INC})
+ ADD_DEFINITIONS(-DWITH_QUICKTIME)
+ENDIF(WITH_QUICKTIME)
+
+IF(WITH_FFMPEG)
+ SET(INC ${INC} ${FFMPEG_INC})
+ ADD_DEFINITIONS(-DWITH_FFMPEG)
+ENDIF(WITH_FFMPEG)
+
+BLENDERLIB(bf_imbuf "${SRC}" "${INC}")
+#env.BlenderLib ( libname = 'bf_imbuf', sources = sources, includes = Split(incs), defines = defs, libtype=['core','player'], priority = [80, 40] )
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
new file mode 100644
index 00000000000..dbbddd2a070
--- /dev/null
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -0,0 +1,583 @@
+/**
+ * @file IMB_imbuf.h
+ * @brief IMage Buffer module.
+ *
+ * This module offers import/export of several graphical file formats.
+ * \ref IMB
+ * @ingroup imbuf
+ * @ingroup undoc
+ *
+ * @page IMB - Imbuf module external interface
+ *
+ *
+ * @section about About the IMB module
+ *
+ * External interface of the IMage Buffer module. This module offers
+ * import/export of several graphical file formats. It offers the
+ * ImBuf type as a common structure to refer to different graphical
+ * file formats, and to enable a uniform way of handling them.
+ *
+ * @section issues Known issues with IMB
+ *
+ * - imbuf is written in C.
+ * - Endianness issues are dealt with internally.
+ * - File I/O must be done externally. The module uses FILE*'s to
+ * direct input/output.
+ * - Platform dependency is limited. Some minor patches for
+ * amiga and Irix are present. A 'posix-compliancy-patch'
+ * provides the interface to windows.
+ *
+ * @section dependencies Dependencies
+ *
+ * IMB needs:
+ * - SDNA module
+ * The listbase types are used for handling the memory
+ * management.
+ * - blenlib module
+ * blenlib handles guarded memory management in blender-style.
+ * BLI_winstuff.h makes a few windows specific behaviours
+ * posix-compliant.
+ * - avi
+ * avi defines import/export to the avi format. Only anim.c
+ * needs this. It uses the following functions:
+ * - avi_close
+ * - avi_is_avi
+ * - avi_print_error
+ * - avi_open_movie
+ * - avi_read_frame
+ * - avi_get_stream
+ * Additionally, it needs the types from the avi module.
+ * - external jpeg library
+ * The jpeg lib defines import/export to the jpeg format.
+ * only jpeg.c needs these. Used functions are:
+ * - jpeg_destroy
+ * - jpeg_resync_to_restart
+ * - jpeg_set_marker_processor
+ * - jpeg_read_header
+ * - jpeg_start_decompress
+ * - jpeg_abort_decompress
+ * - jpeg_read_scanlines
+ * - jpeg_finish_decompress
+ * - jpeg_std_error
+ * - jpeg_create_decompress
+ * - jpeg_stdio_src
+ * - jpeg_start_compress
+ * - jpeg_write_marker
+ * - jpeg_write_scanlines
+ * - jpeg_finish_compress
+ * - jpeg_create_compress
+ * - jpeg_stdio_dest
+ * - jpeg_set_defaults
+ * - jpeg_set_quality
+ * - jpeg_destroy_compress
+ * Additionally, it needs the types from the jpeg lib.
+ */
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef IMB_IMBUF_H
+#define IMB_IMBUF_H
+
+/**
+ *
+ * @attention defined in ???
+ */
+struct ImBuf;
+
+/**
+ *
+ * @attention defined in ???
+ */
+struct anim;
+
+/**
+ *
+ * @attention Defined in cmap.c
+ */
+void IMB_freeImBufdata(void);
+
+/**
+ *
+ * @attention Defined in cmap.c
+ */
+void IMB_applycmap(struct ImBuf *ibuf);
+
+/**
+ *
+ * @attention Defined in cmap.c
+ */
+short IMB_converttocmap(struct ImBuf *ibuf);
+
+/**
+ *
+ * @attention Defined in cmap.c
+ */
+int IMB_alpha_to_col0(int value);
+
+/**
+ *
+ * @attention Defined in readimage.c
+ */
+struct ImBuf *IMB_ibImageFromMemory(int *mem, int size, int flags);
+
+/**
+ *
+ * @attention Defined in readimage.c
+ */
+struct ImBuf *IMB_testiffname(char *naam,int flags);
+
+/**
+ *
+ * @attention Defined in readimage.c
+ */
+struct ImBuf *IMB_loadiffname(const char *naam, int flags);
+
+/**
+ *
+ * @attention Defined in allocimbuf.c
+ */
+void IMB_freeImBuf(struct ImBuf * ibuf);
+
+/**
+ *
+ * @attention Defined in allocimbuf.c
+ */
+struct ImBuf *IMB_allocImBuf(short x, short y,
+ unsigned char d, unsigned int flags,
+ unsigned char bitmap);
+
+/**
+ *
+ * Increase reference count to imbuf
+ * (to delete an imbuf you have to call freeImBuf as many times as it
+ * is referenced)
+ *
+ * @attention Defined in allocimbuf.c
+ */
+
+void IMB_refImBuf(struct ImBuf * ibuf);
+
+/**
+ *
+ * @attention Defined in allocimbuf.c
+ */
+void IMB_cache_limiter_insert(struct ImBuf * i);
+void IMB_cache_limiter_unmanage(struct ImBuf * i);
+void IMB_cache_limiter_touch(struct ImBuf * i);
+void IMB_cache_limiter_ref(struct ImBuf * i);
+void IMB_cache_limiter_unref(struct ImBuf * i);
+int IMB_cache_limiter_get_refcount(struct ImBuf * i);
+
+/**
+ *
+ * @attention Defined in allocimbuf.c
+ */
+struct ImBuf *IMB_dupImBuf(struct ImBuf *ibuf1);
+
+/**
+ *
+ * @attention Defined in allocimbuf.c
+ */
+short addzbufImBuf(struct ImBuf * ibuf);
+short addzbuffloatImBuf(struct ImBuf * ibuf);
+
+/**
+ *
+ * @attention Defined in allocimbuf.c
+ */
+void IMB_freecmapImBuf(struct ImBuf * ibuf);
+
+/**
+ *
+ * @attention Defined in rectop.c
+ */
+
+typedef enum IMB_BlendMode {
+ IMB_BLEND_MIX = 0,
+ IMB_BLEND_ADD = 1,
+ IMB_BLEND_SUB = 2,
+ IMB_BLEND_MUL = 3,
+ IMB_BLEND_LIGHTEN = 4,
+ IMB_BLEND_DARKEN = 5,
+ IMB_BLEND_ERASE_ALPHA = 6,
+ IMB_BLEND_ADD_ALPHA = 7,
+
+ IMB_BLEND_COPY = 1000,
+ IMB_BLEND_COPY_RGB = 1001,
+ IMB_BLEND_COPY_ALPHA = 1002
+} IMB_BlendMode;
+
+unsigned int IMB_blend_color(unsigned int src1, unsigned int src2, int fac,
+ IMB_BlendMode mode);
+void IMB_blend_color_float(float *dst, float *src1, float *src2, float fac,
+ IMB_BlendMode mode);
+
+void IMB_rectclip(struct ImBuf *dbuf, struct ImBuf *sbuf, int *destx,
+ int *desty, int *srcx, int *srcy, int *width, int *height);
+void IMB_rectcpy(struct ImBuf *drect, struct ImBuf *srect, int destx,
+ int desty, int srcx, int srcy, int width, int height);
+void IMB_rectblend(struct ImBuf *dbuf, struct ImBuf *sbuf, int destx,
+ int desty, int srcx, int srcy, int width, int height, IMB_BlendMode mode);
+void IMB_rectblend_torus(struct ImBuf *dbuf, struct ImBuf *sbuf, int destx,
+ int desty, int srcx, int srcy, int width, int height, IMB_BlendMode mode);
+
+/**
+ * Return the length (in frames) of the given @a anim.
+ */
+int IMB_anim_get_duration(struct anim *anim);
+
+/**
+ *
+ * @attention Defined in anim.c
+ */
+struct anim * IMB_open_anim(const char * name, int ib_flags);
+void IMB_close_anim(struct anim * anim);
+
+/**
+ *
+ * @attention Defined in anim.c
+ */
+
+int ismovie(char *name);
+void IMB_anim_set_preseek(struct anim * anim, int preseek);
+int IMB_anim_get_preseek(struct anim * anim);
+
+/**
+ *
+ * @attention Defined in anim.c
+ */
+
+struct ImBuf * IMB_anim_absolute(struct anim * anim, int position);
+
+/**
+ *
+ * @attention Defined in anim.c
+ * fetches a define previewframe, usually half way into the movie
+ */
+struct ImBuf * IMB_anim_previewframe(struct anim * anim);
+
+/**
+ *
+ * @attention Defined in anim.c
+ */
+void IMB_free_anim_ibuf(struct anim * anim);
+
+/**
+ *
+ * @attention Defined in anim.c
+ */
+void IMB_free_anim(struct anim * anim);
+
+/**
+ *
+ * @attention Defined in anim.c
+ */
+struct ImBuf * IMB_anim_nextpic(struct anim * anim);
+
+
+/**
+ *
+ * @attention Defined in antialias.c
+ */
+void IMB_clever_double (struct ImBuf * ibuf);
+
+/**
+ *
+ * @attention Defined in antialias.c
+ */
+void IMB_antialias(struct ImBuf * ibuf);
+
+/**
+ *
+ * @attention Defined in filter.c
+ */
+void IMB_filter(struct ImBuf *ibuf);
+void IMB_filterN(struct ImBuf *out, struct ImBuf *in);
+void IMB_filter_extend(struct ImBuf *ibuf);
+void IMB_makemipmap(struct ImBuf *ibuf, int use_filter);
+
+/**
+ *
+ * @attention Defined in filter.c
+ */
+void IMB_filtery(struct ImBuf *ibuf);
+
+/**
+ *
+ * @attention Defined in scaling.c
+ */
+struct ImBuf *IMB_onehalf(struct ImBuf *ibuf1);
+
+/**
+ *
+ * @attention Defined in scaling.c
+ */
+struct ImBuf *IMB_scaleImBuf(struct ImBuf * ibuf, short newx, short newy);
+
+/**
+ *
+ * @attention Defined in scaling.c
+ */
+struct ImBuf *IMB_scalefieldImBuf(struct ImBuf *ibuf, short newx, short newy);
+
+/**
+ *
+ * @attention Defined in scaling.c
+ */
+struct ImBuf *IMB_scalefastImBuf(struct ImBuf *ibuf, short newx, short newy);
+
+/**
+ *
+ * @attention Defined in writeimage.c
+ */
+short IMB_saveiff(struct ImBuf *ibuf,char *naam,int flags);
+
+/**
+ * Encodes a png image from an ImBuf
+ *
+ * @attention Defined in png_encode.c
+ */
+short IMB_png_encode(struct ImBuf *ibuf, int file, int flags);
+
+/**
+ *
+ * @attention Defined in util.c
+ */
+int IMB_ispic(char *name);
+
+/**
+ *
+ * @attention Defined in util.c
+ */
+int IMB_isanim(char * name);
+
+/**
+ *
+ * @attention Defined in util.c
+ */
+int imb_get_anim_type(char * name);
+
+/**
+ *
+ * @attention Defined in divers.c
+ */
+void IMB_de_interlace(struct ImBuf *ibuf);
+void IMB_interlace(struct ImBuf *ibuf);
+void IMB_gamwarp(struct ImBuf *ibuf, double gamma);
+void IMB_rect_from_float(struct ImBuf *ibuf);
+void IMB_float_from_rect(struct ImBuf *ibuf);
+
+/**
+ * Change the ordering of the color bytes pointed to by rect from
+ * rgba to abgr. size * 4 color bytes are reordered.
+ *
+ * @attention Defined in imageprocess.c
+ */
+void IMB_convert_rgba_to_abgr(struct ImBuf *ibuf);
+/**
+ *
+ * @attention defined in imageprocess.c
+ */
+void bicubic_interpolation(struct ImBuf *in, struct ImBuf *out, float x, float y, int xout, int yout);
+void neareast_interpolation(struct ImBuf *in, struct ImBuf *out, float u, float v, int xout, int yout);
+void bilinear_interpolation(struct ImBuf *in, struct ImBuf *out, float u, float v, int xout, int yout);
+/**
+ * Change the ordering of the color bytes pointed to by rect from
+ * rgba to abgr. size * 4 color bytes are reordered.
+ *
+ * @attention Defined in imageprocess.c
+ */
+void IMB_convert_bgra_to_rgba(int size, unsigned int *rect);
+
+/**
+ *
+ * @attention defined in scaling.c
+ */
+struct ImBuf *IMB_scalefastfieldImBuf(struct ImBuf *ibuf,
+ short newx,
+ short newy);
+
+/**
+ *
+ * @attention defined in readimage.c
+ * @deprecated Only here for backwards compatibility of the
+ * @deprecated plugin system.
+ */
+struct ImBuf *IMB_loadiffmem(int *mem, int flags);
+
+/**
+ *
+ * @attention defined in readimage.c
+ * @deprecated Only here for backwards compatibility of the
+ * @deprecated plugin system.
+ */
+struct ImBuf *IMB_loadifffile(int file, int flags);
+
+/**
+ *
+ * @attention defined in scaling.c
+ */
+struct ImBuf *IMB_half_x(struct ImBuf *ibuf1);
+
+/**
+ *
+ * @attention defined in scaling.c
+ */
+struct ImBuf *IMB_double_fast_x(struct ImBuf *ibuf1);
+
+/**
+ *
+ * @attention defined in scaling.c
+ */
+struct ImBuf *IMB_double_x(struct ImBuf *ibuf1);
+
+/**
+ *
+ * @attention defined in scaling.c
+ */
+struct ImBuf *IMB_half_y(struct ImBuf *ibuf1);
+
+/**
+ *
+ * @attention defined in scaling.c
+ */
+struct ImBuf *IMB_double_fast_y(struct ImBuf *ibuf1);
+
+/**
+ *
+ * @attention defined in scaling.c
+ */
+struct ImBuf *IMB_double_y(struct ImBuf *ibuf1);
+
+/**
+ *
+ * @attention defined in scaling.c
+ */
+struct ImBuf *IMB_onethird(struct ImBuf *ibuf1);
+
+/**
+ *
+ * @attention defined in scaling.c
+ */
+struct ImBuf *IMB_halflace(struct ImBuf *ibuf1);
+
+/**
+ *
+ * @attention defined in dither.c
+ */
+void IMB_dit2(struct ImBuf * ibuf, short ofs, short bits);
+
+/**
+ *
+ * @attention defined in dither.c
+ */
+void IMB_dit0(struct ImBuf * ibuf, short ofs, short bits);
+
+/** Externally used vars: fortunately they do not use funny types */
+
+/**
+ * boolean toggle that tells whether or not to
+ * scale the color map in the y-direction.
+ *
+ * @attention declared in hamx.c
+ */
+extern int scalecmapY;
+
+/**
+ * This 'matrix' defines the transformation from rgb to bw color
+ * maps. You need to do a sort of dot-product for that. It is a matrix
+ * with fixed coefficients, extracted from some book.
+ *
+ * @attention Defined in matrix.h, only included in hamx.c
+ */
+extern float rgb_to_bw[4][4];
+
+/**
+ *
+ * @attention Defined in rotate.c
+ */
+void IMB_flipx(struct ImBuf *ibuf);
+void IMB_flipy(struct ImBuf * ibuf);
+
+/**
+ *
+ * @attention Defined in cspace.c
+ */
+void IMB_cspace(struct ImBuf *ibuf, float mat[][4]);
+
+/**
+ *
+ * @attention Defined in allocimbuf.c
+ */
+void IMB_freezbufImBuf(struct ImBuf * ibuf);
+void IMB_freezbuffloatImBuf(struct ImBuf * ibuf);
+
+/**
+ *
+ * @attention Defined in rectop.c
+ */
+void IMB_rectfill(struct ImBuf *drect, float col[4]);
+void IMB_rectfill_area(struct ImBuf *ibuf, float *col, int x1, int y1, int x2, int y2);
+
+/* this should not be here, really, we needed it for operating on render data, IMB_rectfill_area calls it */
+void buf_rectfill_area(unsigned char *rect, float *rectf, int width, int height, float *col, int x1, int y1, int x2, int y2);
+
+/* defined in imginfo.c */
+int IMB_imginfo_change_field(struct ImBuf *img, const char *key, const char *field);
+
+/* exported for image tools in blender, to quickly allocate 32 bits rect */
+short imb_addrectImBuf(struct ImBuf * ibuf);
+void imb_freerectImBuf(struct ImBuf * ibuf);
+
+short imb_addrectfloatImBuf(struct ImBuf * ibuf);
+void imb_freerectfloatImBuf(struct ImBuf * ibuf);
+void imb_freemipmapImBuf(struct ImBuf * ibuf);
+
+#ifdef WITH_QUICKTIME
+/**
+ *
+ * @attention Defined in quicktime_import.c
+ */
+void quicktime_init(void);
+
+/**
+ *
+ * @attention Defined in quicktime_import.c
+ */
+void quicktime_exit(void);
+
+#endif //WITH_QUICKTIME
+
+/* intern/dynlibtiff.c */
+void libtiff_init(void);
+void libtiff_exit(void);
+
+#endif
diff --git a/source/blender/imbuf/IMB_imbuf_types.h b/source/blender/imbuf/IMB_imbuf_types.h
new file mode 100644
index 00000000000..91ffa188fcc
--- /dev/null
+++ b/source/blender/imbuf/IMB_imbuf_types.h
@@ -0,0 +1,242 @@
+/**
+ * IMB_imbuf_types.h (mar-2001 nzc)
+ *
+ * Types needed for using the image buffer.
+ *
+ * Imbuf is external code, slightly adapted to live in the Blender
+ * context. It requires an external jpeg module, and the avi-module
+ * (also external code) in order to function correctly.
+ *
+ * This file contains types and some constants that go with them. Most
+ * are self-explanatory (e.g. IS_amiga tests whether the buffer
+ * contains an Amiga-format file).
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+/**
+ * \file IMB_imbuf_types.h
+ * \ingroup imbuf
+ * \brief Contains defines and structs used throughout the imbuf module.
+ * \todo Clean up includes.
+ */
+
+#ifndef IMB_IMBUF_TYPES_H
+#define IMB_IMBUF_TYPES_H
+
+#include <stdio.h> /* for size_t */
+#include "DNA_listBase.h" /* for ListBase */
+struct _AviMovie;
+struct Mdec;
+
+struct ImgInfo;
+
+#define IB_MIPMAP_LEVELS 10
+
+/**
+ * \brief The basic imbuf type
+ * \ingroup imbuf
+ * This is the abstraction of an image. ImBuf is the basic type used for all
+ * imbuf operations.
+ *
+ * REMINDER: if any changes take place, they need to be carried over
+ * to source/blender/blenpluginapi/iff.h too, OTHERWISE PLUGINS WON'T
+ * WORK CORRECTLY!
+ *
+ * Also; add new variables to the end to save pain!
+ *
+ * Also, that iff.h needs to be in the final release "plugins/include" dir, too!
+ */
+typedef struct ImBuf {
+ struct ImBuf *next, *prev; /**< allow lists of ImBufs, for caches or flipbooks */
+ short x, y; /**< width and Height of our image buffer */
+ short skipx; /**< Width in ints to get to the next scanline */
+ unsigned char depth; /**< Active amount of bits/bitplanes */
+ unsigned char cbits; /**< Amount of active bits in cmap */
+ unsigned short mincol; /**< smallest color in colormap */
+ unsigned short maxcol; /**< Largest color in colormap */
+ int type; /**< 0=abgr, 1=bitplanes */
+ int ftype; /**< File type we are going to save as */
+ unsigned int *cmap; /**< Color map data. */
+ unsigned int *rect; /**< pixel values stored here */
+ unsigned int **planes; /**< bitplanes */
+ int flags; /**< Controls which components should exist. */
+ int mall; /**< what is malloced internal, and can be freed */
+ short xorig, yorig; /**< Cordinates of first pixel of an image used in some formats (example: targa) */
+ char name[1023]; /**< The file name assocated with this image */
+ char namenull; /**< Unused don't want to remove it thought messes things up */
+ int userflags; /**< Used to set imbuf to Dirty and other stuff */
+ int *zbuf; /**< z buffer data, original zbuffer */
+ float *zbuf_float; /**< z buffer data, camera coordinates */
+ void *userdata;
+ unsigned char *encodedbuffer; /**< Compressed image only used with png currently */
+ unsigned int encodedsize; /**< Size of data written to encodedbuffer */
+ unsigned int encodedbuffersize; /**< Size of encodedbuffer */
+
+ float *rect_float; /**< floating point Rect equivilant */
+ int channels; /**< amount of channels in rect_float (0 = 4 channel default) */
+ float dither; /**< random dither value, for conversion from float -> byte rect */
+
+ struct MEM_CacheLimiterHandle_s * c_handle; /**< handle for cache limiter */
+ struct ImgInfo * img_info;
+ int refcounter; /**< Refcounter for multiple users */
+ int index; /**< reference index for ImBuf lists */
+
+ struct ImBuf *mipmap[IB_MIPMAP_LEVELS]; /**< MipMap levels, a series of halved images */
+} ImBuf;
+
+/* Moved from BKE_bmfont_types.h because it is a userflag bit mask. */
+/**
+ * \brief Flags used internally by blender for imagebuffers
+ */
+typedef enum {
+ IB_BITMAPFONT = 1 << 0, /* This image is a font */
+ IB_BITMAPDIRTY = 1 << 1 /* Image needs to be saved is not the same as filename */
+} ImBuf_userflagsMask;
+
+
+/* From iff.h. This was once moved away by Frank, now Nzc moves it
+ * back. Such is the way it is... It is a long list of defines, and
+ * there are a few external defines in the back. Most of the stuff is
+ * probably imbuf_intern only. This will need to be merged later
+ * on. */
+
+/**
+ * \name Imbuf Component flags
+ * \brief These flags determine the components of an ImBuf struct.
+ */
+/**@{*/
+/** \brief Flag defining the components of the ImBuf struct. */
+#define IB_rect (1 << 0)
+#define IB_planes (1 << 1)
+#define IB_cmap (1 << 2)
+
+#define IB_vert (1 << 4)
+#define IB_freem (1 << 6)
+#define IB_test (1 << 7)
+
+#define IB_ttob (1 << 8)
+#define IB_subdlta (1 << 9)
+#define IB_fields (1 << 11)
+#define IB_zbuf (1 << 13)
+
+#define IB_mem (1 << 14)
+#define IB_rectfloat (1 << 15)
+#define IB_zbuffloat (1 << 16)
+#define IB_multilayer (1 << 17)
+#define IB_imginfo (1 << 18)
+
+/*
+ * The bit flag is stored in the ImBuf.ftype variable.
+ * Note that the lower 10 bits is used for storing custom flags
+ */
+#define AMI (1 << 31)
+#define PNG (1 << 30)
+#define Anim (1 << 29)
+#define TGA (1 << 28)
+#define JPG (1 << 27)
+#define BMP (1 << 26)
+
+#ifdef WITH_QUICKTIME
+#define QUICKTIME (1 << 25)
+#endif
+
+#define RADHDR (1 << 24)
+#define TIF (1 << 23)
+
+#define OPENEXR (1 << 22)
+#define OPENEXR_HALF (1 << 8 )
+#define OPENEXR_COMPRESS (7)
+
+#define CINEON (1 << 21)
+#define DPX (1 << 20)
+
+#ifdef WITH_DDS
+#define DDS (1 << 19)
+#endif
+
+#define RAWTGA (TGA | 1)
+
+#define JPG_STD (JPG | (0 << 8))
+#define JPG_VID (JPG | (1 << 8))
+#define JPG_JST (JPG | (2 << 8))
+#define JPG_MAX (JPG | (3 << 8))
+#define JPG_MSK (0xffffff00)
+
+#define AM_ham (0x0800 | AMI)
+#define AM_hbrite (0x0080 | AMI)
+
+#define C233 1
+#define YUVX 2
+#define HAMX 3
+#define TANX 4
+
+#define AN_c233 (Anim | C233)
+#define AN_yuvx (Anim | YUVX)
+#define AN_hamx (Anim | HAMX)
+#define AN_tanx (Anim | TANX)
+/**@}*/
+
+/** \name Imbuf File Type Tests
+ * \brief These macros test if an ImBuf struct is the corresponding file type.
+ */
+/**@{*/
+/** \brief Tests the ImBuf.ftype variable for the file format. */
+#define IS_amiga(x) (x->ftype & AMI)
+#define IS_ham(x) ((x->ftype & AM_ham) == AM_ham)
+#define IS_hbrite(x) ((x->ftype & AM_hbrite) == AM_hbrite)
+
+#define IS_anim(x) (x->ftype & Anim)
+#define IS_hamx(x) (x->ftype == AN_hamx)
+#define IS_tga(x) (x->ftype & TGA)
+#define IS_png(x) (x->ftype & PNG)
+#define IS_openexr(x) (x->ftype & OPENEXR)
+#define IS_cineon(x) (x->ftype & CINEON)
+#define IS_dpx(x) (x->ftype & DPX)
+#define IS_bmp(x) (x->ftype & BMP)
+#define IS_tiff(x) (x->ftype & TIF)
+#define IS_radhdr(x) (x->ftype & RADHDR)
+
+#ifdef WITH_DDS
+#define IS_dds(x) (x->ftype & DDS)
+#endif
+
+#define IMAGIC 0732
+#define IS_iris(x) (x->ftype == IMAGIC)
+
+#define IS_jpg(x) (x->ftype & JPG)
+#define IS_stdjpg(x) ((x->ftype & JPG_MSK) == JPG_STD)
+#define IS_vidjpg(x) ((x->ftype & JPG_MSK) == JPG_VID)
+#define IS_jstjpg(x) ((x->ftype & JPG_MSK) == JPG_JST)
+#define IS_maxjpg(x) ((x->ftype & JPG_MSK) == JPG_MAX)
+/**@}*/
+
+#endif
+
diff --git a/source/blender/imbuf/IMB_thumbs.h b/source/blender/imbuf/IMB_thumbs.h
new file mode 100644
index 00000000000..4f4b77ff000
--- /dev/null
+++ b/source/blender/imbuf/IMB_thumbs.h
@@ -0,0 +1,74 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2007 Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Andrea Weikert.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef _IMB_THUMBS_H
+#define _IMB_THUMBS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct ImBuf;
+
+/** Thumbnail creation and retrieval according to the 'Thumbnail Management Standard'
+ * supported by Gimp, Gnome (Nautilus), KDE etc.
+ * Reference: http://jens.triq.net/thumbnail-spec/index.html
+ */
+
+
+typedef enum ThumbSize {
+ THB_NORMAL,
+ THB_LARGE,
+ THB_FAIL
+} ThumbSize;
+
+typedef enum ThumbSource {
+ THB_SOURCE_IMAGE,
+ THB_SOURCE_MOVIE
+} ThumbSource;
+
+// IB_imginfo
+
+/* create thumbnail for file and returns new imbuf for thumbnail */
+ImBuf* IMB_thumb_create(const char* dir, const char* file, ThumbSize size, ThumbSource source);
+
+/* read thumbnail for file and returns new imbuf for thumbnail */
+ImBuf* IMB_thumb_read(const char* dir, const char* file, ThumbSize size);
+
+/* delete all thumbs for the file */
+void IMB_thumb_delete(const char* dir, const char* file, ThumbSize size);
+
+/* return the state of the thumb, needed to determine how to manage the thumb */
+ImBuf* IMB_thumb_manage(const char* dir, const char* file, ThumbSize size, ThumbSource source);
+
+
+
+
+#endif /* _IMB_THUMBS_H */
+
diff --git a/source/blender/imbuf/Makefile b/source/blender/imbuf/Makefile
new file mode 100644
index 00000000000..66c1f06c870
--- /dev/null
+++ b/source/blender/imbuf/Makefile
@@ -0,0 +1,37 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+# Bounces make to subdirectories.
+
+SOURCEDIR = source/blender/imbuf
+DIRS = intern
+
+include nan_subdirs.mk
diff --git a/source/blender/imbuf/SConscript b/source/blender/imbuf/SConscript
new file mode 100644
index 00000000000..f9e46b20d9a
--- /dev/null
+++ b/source/blender/imbuf/SConscript
@@ -0,0 +1,34 @@
+#!/usr/bin/python
+Import ('env')
+
+sources = env.Glob('intern/*.c')
+
+incs = '. ../makesdna #/intern/guardedalloc #/intern/memutil ../blenlib'
+incs += ' ../avi ../quicktime ../blenkernel'
+
+incs += ' ' + env['BF_JPEG_INC']
+incs += ' ' + env['BF_PNG_INC']
+incs += ' ' + env['BF_TIFF_INC']
+incs += ' ' + env['BF_ZLIB_INC']
+
+defs = []
+
+if env['WITH_BF_VERSE']:
+ defs.append('WITH_VERSE')
+ incs += ' ' + env['BF_VERSE_INCLUDE']
+
+if env['WITH_BF_OPENEXR'] == 1:
+ defs.append('WITH_OPENEXR')
+
+if env['WITH_BF_DDS'] == 1:
+ defs.append('WITH_DDS')
+
+if env['WITH_BF_FFMPEG'] == 1:
+ defs.append('WITH_FFMPEG')
+ incs += ' ' + env['BF_FFMPEG_INC']
+
+if env['WITH_BF_QUICKTIME']==1:
+ incs += ' ' + env['BF_QUICKTIME_INC']
+ defs.append('WITH_QUICKTIME')
+
+env.BlenderLib ( libname = 'bf_imbuf', sources = sources, includes = Split(incs), defines = defs, libtype=['core','player'], priority = [80, 40] )
diff --git a/source/blender/imbuf/intern/IMB_allocimbuf.h b/source/blender/imbuf/intern/IMB_allocimbuf.h
new file mode 100644
index 00000000000..7ff44ef29f9
--- /dev/null
+++ b/source/blender/imbuf/intern/IMB_allocimbuf.h
@@ -0,0 +1,59 @@
+/*
+ * allocimbuf.h
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/**
+ * \file IMB_allocimbuf.h
+ * \ingroup imbuf
+ * \brief Header file for allocimbuf.c
+ */
+#ifndef IMB_ALLOCIMBUF_H
+#define IMB_ALLOCIMBUF_H
+
+struct ImBuf;
+
+short imb_addrectImBuf(struct ImBuf * ibuf);
+short imb_addrectfloatImBuf(struct ImBuf * ibuf);
+short imb_addplanesImBuf(struct ImBuf *ibuf);
+
+short imb_addencodedbufferImBuf(struct ImBuf *ibuf);
+short imb_enlargeencodedbufferImBuf(struct ImBuf *ibuf);
+
+void imb_freerectImBuf(struct ImBuf *ibuf);
+void imb_freerectfloatImBuf(struct ImBuf *ibuf);
+void imb_freeplanesImBuf(struct ImBuf *ibuf);
+
+short imb_addcmapImBuf(struct ImBuf *ibuf);
+
+#endif
+
diff --git a/source/blender/imbuf/intern/IMB_amiga.h b/source/blender/imbuf/intern/IMB_amiga.h
new file mode 100644
index 00000000000..39ca4035753
--- /dev/null
+++ b/source/blender/imbuf/intern/IMB_amiga.h
@@ -0,0 +1,50 @@
+/**
+ * IMB_amiga.h
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+/**
+ * \file IMB_amiga.h
+ * \ingroup imbuf
+ * \brief Function declarations for amiga.c
+ */
+
+#ifndef IMB_AMIGA_H
+#define IMB_AMIGA_H
+
+struct ImBuf;
+
+struct ImBuf *imb_loadamiga(int *iffmem,int flags);
+short imb_encodebodyh(struct ImBuf *ibuf, int file);
+short imb_encodebodyv(struct ImBuf *ibuf, int file);
+
+#endif
+
diff --git a/source/blender/imbuf/intern/IMB_anim.h b/source/blender/imbuf/intern/IMB_anim.h
new file mode 100644
index 00000000000..f3514a92ae4
--- /dev/null
+++ b/source/blender/imbuf/intern/IMB_anim.h
@@ -0,0 +1,193 @@
+/**
+ * allocimbuf.h
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef IMB_ANIM_H
+#define IMB_ANIM_H
+
+#ifdef _WIN32
+#define INC_OLE2
+#include <windows.h>
+#include <windowsx.h>
+#include <mmsystem.h>
+#include <memory.h>
+#include <commdlg.h>
+
+#ifndef FREE_WINDOWS
+#include <vfw.h>
+#endif
+
+#undef AVIIF_KEYFRAME // redefined in AVI_avi.h
+#undef AVIIF_LIST // redefined in AVI_avi.h
+
+#define FIXCC(fcc) if (fcc == 0) fcc = mmioFOURCC('N', 'o', 'n', 'e'); \
+ if (fcc == BI_RLE8) fcc = mmioFOURCC('R', 'l', 'e', '8');
+#endif
+
+#include <sys/types.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#ifndef _WIN32
+#include <dirent.h>
+#else
+#include <io.h>
+#endif
+
+#include "BLI_blenlib.h" /* BLI_remlink BLI_filesize BLI_addtail
+ BLI_countlist BLI_stringdec */
+
+#include "imbuf.h"
+#include "imbuf_patch.h"
+
+#include "AVI_avi.h"
+
+#ifdef WITH_QUICKTIME
+#if defined(_WIN32) || defined(__APPLE__)
+#include "quicktime_import.h"
+#endif /* _WIN32 || __APPLE__ */
+#endif /* WITH_QUICKTIME */
+
+#ifdef WITH_FFMPEG
+#include <ffmpeg/avformat.h>
+#include <ffmpeg/avcodec.h>
+#include <ffmpeg/swscale.h>
+#endif
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "IMB_allocimbuf.h"
+#include "IMB_bitplanes.h"
+
+
+
+/* actually hard coded endianness */
+#define GET_BIG_LONG(x) (((uchar *) (x))[0] << 24 | ((uchar *) (x))[1] << 16 | ((uchar *) (x))[2] << 8 | ((uchar *) (x))[3])
+#define GET_LITTLE_LONG(x) (((uchar *) (x))[3] << 24 | ((uchar *) (x))[2] << 16 | ((uchar *) (x))[1] << 8 | ((uchar *) (x))[0])
+#define SWAP_L(x) (((x << 24) & 0xff000000) | ((x << 8) & 0xff0000) | ((x >> 8) & 0xff00) | ((x >> 24) & 0xff))
+#define SWAP_S(x) (((x << 8) & 0xff00) | ((x >> 8) & 0xff))
+
+/* more endianness... should move to a separate file... */
+#if defined(__sgi) || defined (__sparc) || (__sparc__) || defined (__PPC__) || defined (__ppc__) || defined (__BIG_ENDIAN__)
+#define GET_ID GET_BIG_LONG
+#define LITTLE_LONG SWAP_LONG
+#else
+#define GET_ID GET_LITTLE_LONG
+#define LITTLE_LONG ENDIAN_NOP
+#endif
+
+/****/
+
+#define ANIM_NONE (0)
+#define ANIM_SEQUENCE (1 << 0)
+#define ANIM_DIR (1 << 1)
+#define ANIM_ANIM5 (1 << 2)
+#define ANIM_TGA (1 << 3)
+#define ANIM_MOVIE (1 << 4)
+#define ANIM_MDEC (1 << 5)
+#define ANIM_AVI (1 << 6)
+#define ANIM_QTIME (1 << 7)
+#define ANIM_FFMPEG (1 << 8)
+
+#define ANIM5_MMAP 0
+#define ANIM5_MALLOC 1
+#define ANIM5_SNGBUF 2
+#define ANIM5_XOR 4
+
+#define MAXNUMSTREAMS 50
+
+struct anim {
+ int ib_flags;
+ int curtype;
+ int curposition; /* index 0 = 1e, 1 = 2e, enz. */
+ int duration;
+ int x, y;
+
+ /* voor op nummer */
+ char name[256];
+ /* voor sequence */
+ char first[256];
+
+ /* anim5 */
+ struct ListBase anim5base;
+ void * anim5mmap;
+ int anim5len;
+ struct Anim5Delta *anim5curdlta;
+ void (*anim5decode)(struct ImBuf *, unsigned char *);
+ int anim5flags;
+
+ /* movie */
+ void *movie;
+ void *track;
+ void *params;
+ int orientation;
+ size_t framesize;
+ int interlacing;
+ int preseek;
+
+ /* data */
+ struct ImBuf * ibuf1, * ibuf2;
+
+ /* avi */
+ struct _AviMovie *avi;
+
+#if defined(_WIN32) && !defined(FREE_WINDOWS)
+ /* windows avi */
+ int avistreams;
+ int firstvideo;
+ int pfileopen;
+ PAVIFILE pfile;
+ PAVISTREAM pavi[MAXNUMSTREAMS]; // the current streams
+ PGETFRAME pgf;
+#endif
+
+#ifdef WITH_QUICKTIME
+ /* quicktime */
+ struct _QuicktimeMovie *qtime;
+#endif /* WITH_QUICKTIME */
+
+#ifdef WITH_FFMPEG
+ AVFormatContext *pFormatCtx;
+ AVCodecContext *pCodecCtx;
+ AVCodec *pCodec;
+ AVFrame *pFrameRGB;
+ AVFrame *pFrame;
+ struct SwsContext *img_convert_ctx;
+ int videoStream;
+#endif
+
+};
+
+#endif
+
diff --git a/source/blender/imbuf/intern/IMB_anim5.h b/source/blender/imbuf/intern/IMB_anim5.h
new file mode 100644
index 00000000000..245b3b9a9be
--- /dev/null
+++ b/source/blender/imbuf/intern/IMB_anim5.h
@@ -0,0 +1,20 @@
+/* IMB_anim.h */
+#ifndef IMB_ANIM5_H
+#define IMB_ANIM5_H
+
+struct anim;
+
+/**
+ *
+ * @attention Defined in anim5.c
+ */
+int nextanim5(struct anim * anim);
+int rewindanim5(struct anim * anim);
+int startanim5(struct anim * anim);
+void free_anim_anim5(struct anim * anim);
+struct ImBuf * anim5_fetchibuf(struct anim * anim);
+
+
+#endif
+
+
diff --git a/source/blender/imbuf/intern/IMB_bitplanes.h b/source/blender/imbuf/intern/IMB_bitplanes.h
new file mode 100644
index 00000000000..643c6d57a06
--- /dev/null
+++ b/source/blender/imbuf/intern/IMB_bitplanes.h
@@ -0,0 +1,50 @@
+/*
+ * IMB_bitplanes.h
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+/**
+ * \file IMB_bitplanes.h
+ * \ingroup imbuf
+ * \brief Function declarations for bitplanes.c
+ */
+
+#ifndef IMB_BITPLANES_H
+#define IMB_BITPLANES_H
+
+struct ImBuf;
+
+void imb_bptolong(struct ImBuf *ibuf);
+void imb_longtobp(struct ImBuf *ibuf);
+unsigned int **imb_copyplanelist(struct ImBuf *ibuf);
+
+#endif
+
diff --git a/source/blender/imbuf/intern/IMB_bmp.h b/source/blender/imbuf/intern/IMB_bmp.h
new file mode 100644
index 00000000000..7516c8b4add
--- /dev/null
+++ b/source/blender/imbuf/intern/IMB_bmp.h
@@ -0,0 +1,50 @@
+/*
+ * IMB_bmp.h
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+/**
+ * \file IMB_bmp.h
+ * \ingroup imbuf
+ * \brief Function declarations for bmp.c
+ */
+
+#ifndef IMB_BMP_H
+#define IMB_BMP_H
+
+struct ImBuf;
+
+int imb_is_a_bmp(void *buf);
+struct ImBuf *imb_bmp_decode(unsigned char *mem, int size, int flags);
+short imb_savebmp(struct ImBuf *ibuf, char *name, int flags);
+
+#endif
+
diff --git a/source/blender/imbuf/intern/IMB_cmap.h b/source/blender/imbuf/intern/IMB_cmap.h
new file mode 100644
index 00000000000..cf6c15ede91
--- /dev/null
+++ b/source/blender/imbuf/intern/IMB_cmap.h
@@ -0,0 +1,49 @@
+/*
+ * IMB_cmap.h
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+/**
+ * \file IMB_cmap.h
+ * \ingroup imbuf
+ * \brief Function declarations for cmap.c
+ */
+#ifndef IMB_CMAP_H
+#define IMB_CMAP_H
+
+struct ImBuf;
+
+void imb_makecolarray(struct ImBuf *ibuf, unsigned char *mem, short nocols);
+void imb_losecmapbits(struct ImBuf *ibuf, unsigned int *coltab);
+short *imb_coldeltatab(unsigned char *coltab, short mincol, short maxcol, short cbits);
+
+#endif
+
diff --git a/source/blender/imbuf/intern/IMB_divers.h b/source/blender/imbuf/intern/IMB_divers.h
new file mode 100644
index 00000000000..23d71d2c74d
--- /dev/null
+++ b/source/blender/imbuf/intern/IMB_divers.h
@@ -0,0 +1,48 @@
+/*
+ * divers.h
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+/**
+ * \file IMB_divers.h
+ * \ingroup imbuf
+ * \brief Function declarations for divers.c
+ */
+
+#ifndef IMB_DIVERS_H
+#define IMB_DIVERS_H
+
+struct ImBuf;
+
+void imb_checkncols(struct ImBuf *ibuf);
+
+#endif
+
diff --git a/source/blender/imbuf/intern/IMB_dpxcineon.h b/source/blender/imbuf/intern/IMB_dpxcineon.h
new file mode 100644
index 00000000000..9846d018214
--- /dev/null
+++ b/source/blender/imbuf/intern/IMB_dpxcineon.h
@@ -0,0 +1,47 @@
+/*
+ * IMB_dpxcineon.h
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+/**
+ * \file IMB_dpxcineon.h
+ * \ingroup imbuf
+ */
+#ifndef _IMB_DPX_CINEON_H
+#define _IMB_DPX_CINEON_H
+
+struct ImBuf;
+
+short imb_savecineon(struct ImBuf *buf, char *myfil, int flags);
+struct ImBuf *imb_loadcineon(unsigned char *mem, int size, int flags);
+int imb_is_cineon(void *buf);
+short imb_save_dpx(struct ImBuf *buf, char *myfile, int flags);
+struct ImBuf *imb_loaddpx(unsigned char *mem, int size, int flags);
+int imb_is_dpx(void *buf);
+
+#endif /*_IMB_DPX_CINEON_H*/
diff --git a/source/blender/imbuf/intern/IMB_filter.h b/source/blender/imbuf/intern/IMB_filter.h
new file mode 100644
index 00000000000..c544ae9a04c
--- /dev/null
+++ b/source/blender/imbuf/intern/IMB_filter.h
@@ -0,0 +1,48 @@
+/*
+ * filter.h
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+/**
+ * \file IMB_filter.h
+ * \ingroup imbuf
+ * \brief Function declarations for filter.c
+ */
+
+#ifndef IMB_FILTER_H
+#define IMB_FILTER_H
+
+struct ImBuf;
+
+void imb_filterx(struct ImBuf *ibuf);
+
+#endif
+
diff --git a/source/blender/imbuf/intern/IMB_ham.h b/source/blender/imbuf/intern/IMB_ham.h
new file mode 100644
index 00000000000..e3302542198
--- /dev/null
+++ b/source/blender/imbuf/intern/IMB_ham.h
@@ -0,0 +1,48 @@
+/*
+ * IMB_ham.h
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+/**
+ * \file IMB_ham.h
+ * \ingroup imbuf
+ * \brief Function declarations for ham.c
+ */
+
+#ifndef IMB_HAM_H
+#define IMB_HAM_H
+
+struct ImBuf;
+
+short imb_converttoham(struct ImBuf *ibuf);
+
+#endif
+
diff --git a/source/blender/imbuf/intern/IMB_hamx.h b/source/blender/imbuf/intern/IMB_hamx.h
new file mode 100644
index 00000000000..d5b23d4e685
--- /dev/null
+++ b/source/blender/imbuf/intern/IMB_hamx.h
@@ -0,0 +1,50 @@
+/*
+ * IMB_hamx.h
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+/**
+ * \file IMB_hamx.h
+ * \ingroup imbuf
+ * \brief Function declarations for hamx.c
+ */
+
+#ifndef IMB_HAMX_H
+#define IMB_HAMX_H
+
+struct ImBuf;
+
+struct ImBuf *imb_loadanim(int *iffmem, int flags);
+short imb_enc_anim(struct ImBuf *ibuf, int file);
+void imb_convhamx(struct ImBuf *ibuf, unsigned char *coltab, short *deltab);
+
+#endif
+
diff --git a/source/blender/imbuf/intern/IMB_iff.h b/source/blender/imbuf/intern/IMB_iff.h
new file mode 100644
index 00000000000..c65330bad95
--- /dev/null
+++ b/source/blender/imbuf/intern/IMB_iff.h
@@ -0,0 +1,49 @@
+/*
+ * IMB_iff.h
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+/**
+ * \file IMB_iff.h
+ * \ingroup imbuf
+ * \brief Function declarations for iff.c
+ */
+
+#ifndef IMB_IFF_H
+#define IMB_IFF_H
+
+struct ImBuf;
+
+unsigned short imb_start_iff(struct ImBuf *ibuf, int file);
+unsigned short imb_update_iff(int file, int code);
+
+#endif
+
diff --git a/source/blender/imbuf/intern/IMB_imginfo.h b/source/blender/imbuf/intern/IMB_imginfo.h
new file mode 100644
index 00000000000..e82cc5f32af
--- /dev/null
+++ b/source/blender/imbuf/intern/IMB_imginfo.h
@@ -0,0 +1,85 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Austin Benesh. Ton Roosendaal.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef _IMB_IMGINFO_H
+#define _IMB_IMGINFO_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct ImBuf;
+
+typedef struct ImgInfo {
+ struct ImgInfo *next, *prev;
+ char* key;
+ char* value;
+ int len;
+} ImgInfo;
+
+/** The imginfo is a list of key/value pairs (both char*) that can me
+ saved in the header of several image formats.
+ Apart from some common keys like
+ 'Software' and 'Description' (png standard) we'll use keys within the
+ Blender namespace, so should be called 'Blender::StampInfo' or 'Blender::FrameNum'
+ etc...
+*/
+
+
+/* free blender ImgInfo struct */
+void IMB_imginfo_free(struct ImBuf* img);
+
+/** read the field from the image info into the field
+ * @param img - the ImBuf that contains the image data
+ * @param key - the key of the field
+ * @param value - the data in the field, first one found with key is returned,
+ memory has to be allocated by user.
+ * @param len - length of value buffer allocated by user.
+ * @return - 1 (true) if ImageInfo present and value for the key found, 0 (false) otherwise
+ */
+int IMB_imginfo_get_field(struct ImBuf* img, const char* key, char* value, int len);
+
+/** set user data in the ImgInfo struct, which has to be allocated with IMB_imginfo_create
+ * before calling this function.
+ * @param img - the ImBuf that contains the image data
+ * @param key - the key of the field
+ * @param value - the data to be written to the field. zero terminated string
+ * @return - 1 (true) if ImageInfo present, 0 (false) otherwise
+ */
+int IMB_imginfo_add_field(struct ImBuf* img, const char* key, const char* field);
+
+/** delete the key/field par in the ImgInfo struct.
+ * @param img - the ImBuf that contains the image data
+ * @param key - the key of the field
+ * @return - 1 (true) if delete the key/field, 0 (false) otherwise
+ */
+int IMB_imginfo_del_field(struct ImBuf *img, const char *key);
+
+#endif /* _IMB_IMGINFO_H */
+
diff --git a/source/blender/imbuf/intern/IMB_iris.h b/source/blender/imbuf/intern/IMB_iris.h
new file mode 100644
index 00000000000..74126a1a166
--- /dev/null
+++ b/source/blender/imbuf/intern/IMB_iris.h
@@ -0,0 +1,49 @@
+/*
+ * IMB_iris.h
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+/**
+ * \file IMB_iris.h
+ * \ingroup imbuf
+ * \brief Function declarations for iris.c
+ */
+
+#ifndef IMB_IRIS_H
+#define IMB_IRIS_H
+
+struct ImBuf;
+
+struct ImBuf *imb_loadiris(unsigned char *mem, int flags);
+short imb_saveiris(struct ImBuf * ibuf, char *name, int flags);
+
+#endif
+
diff --git a/source/blender/imbuf/intern/IMB_jpeg.h b/source/blender/imbuf/intern/IMB_jpeg.h
new file mode 100644
index 00000000000..f78810d27ee
--- /dev/null
+++ b/source/blender/imbuf/intern/IMB_jpeg.h
@@ -0,0 +1,52 @@
+/*
+ * IMB_jpeg.h
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+/**
+ * \file IMB_jpeg.h
+ * \ingroup imbuf
+ * \brief Function declarations for jpeg.c
+ */
+
+#ifndef IMB_JPEG_H
+#define IMB_JPEG_H
+
+struct ImBuf;
+struct jpeg_compress_struct;
+
+int imb_is_a_jpeg(unsigned char *mem);
+int imb_savejpeg(struct ImBuf * ibuf, char * name, int flags);
+struct ImBuf * imb_ibJpegImageFromFilename (const char * filename, int flags);
+struct ImBuf * imb_ibJpegImageFromMemory (unsigned char * buffer, int size, int flags);
+
+#endif
+
diff --git a/source/blender/imbuf/intern/IMB_png.h b/source/blender/imbuf/intern/IMB_png.h
new file mode 100644
index 00000000000..6557bfb13a0
--- /dev/null
+++ b/source/blender/imbuf/intern/IMB_png.h
@@ -0,0 +1,51 @@
+/*
+ * IMB_png.h
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+/**
+ * \file IMB_png.h
+ * \ingroup imbuf
+ * \brief Function declarations for png.c
+ */
+
+#ifndef IMB_PNG_H
+#define IMB_PNG_H
+
+struct ImBuf;
+
+int imb_is_a_png(void *buf);
+struct ImBuf *imb_loadpng(unsigned char *mem, int size, int flags);
+
+short imb_savepng(struct ImBuf *ibuf, char *name, int flags);
+
+#endif
+
diff --git a/source/blender/imbuf/intern/IMB_radiance_hdr.h b/source/blender/imbuf/intern/IMB_radiance_hdr.h
new file mode 100644
index 00000000000..91a8f380557
--- /dev/null
+++ b/source/blender/imbuf/intern/IMB_radiance_hdr.h
@@ -0,0 +1,42 @@
+/*
+ * IMB_radiance_hdr.h
+ *
+ * $Id:
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef IMB_RADIANCE_HDR_H
+#define IMB_RADIANCE_HDR_H
+
+struct ImBuf;
+
+int imb_is_a_hdr(void *buf);
+
+struct ImBuf *imb_loadhdr(unsigned char *mem, int size, int flags);
+short imb_savehdr(struct ImBuf * ibuf, char *name, int flags);
+
+#endif
diff --git a/source/blender/imbuf/intern/IMB_targa.h b/source/blender/imbuf/intern/IMB_targa.h
new file mode 100644
index 00000000000..2d3b1ab3288
--- /dev/null
+++ b/source/blender/imbuf/intern/IMB_targa.h
@@ -0,0 +1,51 @@
+/*
+ * IMB_targa.h
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+/**
+ * \file IMB_targa.h
+ * \ingroup imbuf
+ * \brief Function declarations for targa.c
+ */
+
+#ifndef IMB_TARGA_H
+#define IMB_TARGA_H
+
+struct ImBuf;
+
+int imb_is_a_targa(void *buf);
+
+struct ImBuf *imb_loadtarga(unsigned char *mem, int flags);
+short imb_savetarga(struct ImBuf * ibuf, char *name, int flags);
+
+#endif
+
diff --git a/source/blender/imbuf/intern/IMB_tiff.h b/source/blender/imbuf/intern/IMB_tiff.h
new file mode 100644
index 00000000000..b633fbffd23
--- /dev/null
+++ b/source/blender/imbuf/intern/IMB_tiff.h
@@ -0,0 +1,48 @@
+/*
+ * IMB_tiff.h
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributor(s): Jonathan Merritt.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+/**
+ * \file IMB_tiff.h
+ * \ingroup imbuf
+ * \brief Function declarations for tiff.c
+ */
+
+#ifndef IMB_TIFF_H
+#define IMB_TIFF_H
+
+/* Foward declaration of ImBuf structure. */
+struct ImBuf;
+
+/* Declarations for tiff.c */
+int imb_is_a_tiff(void *buf);
+struct ImBuf *imb_loadtiff(unsigned char *mem, int size, int flags);
+short imb_savetiff(struct ImBuf *ibuf, char *name, int flags);
+void* libtiff_findsymbol(char *name);
+
+#endif /* IMB_TIFF_H */
+
diff --git a/source/blender/imbuf/intern/Makefile b/source/blender/imbuf/intern/Makefile
new file mode 100644
index 00000000000..09eb487b3a6
--- /dev/null
+++ b/source/blender/imbuf/intern/Makefile
@@ -0,0 +1,82 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+#
+
+LIBNAME = imbuf
+DIR = $(OCGDIR)/blender/imbuf
+SOURCEDIR = source/blender/imbuf/intern
+
+include nan_subdirs.mk
+include nan_compile.mk
+include nan_definitions.mk
+
+DIRS = cineon
+
+ifeq ($(WITH_OPENEXR), true)
+ DIRS += openexr
+ CFLAGS += -DWITH_OPENEXR
+endif
+
+ifeq ($(WITH_DDS), true)
+ DIRS += dds
+ CPPFLAGS += -DWITH_DDS
+endif
+
+CFLAGS += $(LEVEL_1_C_WARNINGS)
+
+CPPFLAGS += -I$(NAN_JPEG)/include
+CPPFLAGS += -I$(NAN_PNG)/include
+CPPFLAGS += -I$(NAN_ZLIB)/include
+CPPFLAGS += -I$(NAN_TIFF)/include
+CPPFLAGS += -I../../include
+CPPFLAGS += -I../../blenkernel
+CPPFLAGS += -I../../blenlib
+CPPFLAGS += -I../../avi
+CPPFLAGS += -I../../quicktime
+# path to the guarded memory allocator
+CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
+CPPFLAGS += -I$(NAN_MEMUTIL)/include
+# This is not really needed, but until /include is cleaned, it must be
+# there for proper compilation.
+# - No, it is also needed in antialias, for listbase (nzc)
+CPPFLAGS += -I../../makesdna
+# external interface of this module
+CPPFLAGS += -I..
+
+ifeq ($(WITH_QUICKTIME), true)
+ CPPFLAGS += -DWITH_QUICKTIME
+endif
+
+ifeq ($(WITH_FFMPEG), true)
+ CPPFLAGS += -DWITH_FFMPEG
+ CPPFLAGS += $(NAN_FFMPEGCFLAGS)
+endif
diff --git a/source/blender/imbuf/intern/allocimbuf.c b/source/blender/imbuf/intern/allocimbuf.c
new file mode 100644
index 00000000000..a5d404740cf
--- /dev/null
+++ b/source/blender/imbuf/intern/allocimbuf.c
@@ -0,0 +1,573 @@
+/*
+ * allocimbuf.c
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/* It's become a bit messy... Basically, only the IMB_ prefixed files
+ * should remain. */
+
+#include "IMB_imbuf_types.h"
+
+#include "imbuf.h"
+#include "imbuf_patch.h"
+#include "IMB_imbuf.h"
+
+#include "IMB_divers.h"
+#include "IMB_allocimbuf.h"
+#include "IMB_imginfo.h"
+#include "MEM_CacheLimiterC-Api.h"
+
+static unsigned int dfltcmap[16] = {
+ 0x00000000, 0xffffffff, 0x777777ff, 0xccccccff,
+ 0xcc3344ff, 0xdd8844ff, 0xccdd44ff, 0x888833ff,
+ 0x338844ff, 0x44dd44ff, 0x44ddccff, 0x3388ccff,
+ 0x8888ddff, 0x4433ccff, 0xcc33ccff, 0xcc88ddff
+};
+
+void imb_freeplanesImBuf(struct ImBuf * ibuf)
+{
+ if (ibuf==NULL) return;
+ if (ibuf->planes){
+ if (ibuf->mall & IB_planes) MEM_freeN(ibuf->planes);
+ }
+ ibuf->planes = 0;
+ ibuf->mall &= ~IB_planes;
+}
+
+void imb_freemipmapImBuf(struct ImBuf * ibuf)
+{
+ int a;
+
+ for(a=0; a<IB_MIPMAP_LEVELS; a++) {
+ if(ibuf->mipmap[a]) IMB_freeImBuf(ibuf->mipmap[a]);
+ ibuf->mipmap[a]= NULL;
+ }
+}
+
+/* any free rect frees mipmaps to be sure, creation is in render on first request */
+void imb_freerectfloatImBuf(struct ImBuf * ibuf)
+{
+ if (ibuf==NULL) return;
+
+ if (ibuf->rect_float) {
+ if (ibuf->mall & IB_rectfloat) {
+ MEM_freeN(ibuf->rect_float);
+ ibuf->rect_float=NULL;
+ }
+ }
+
+ imb_freemipmapImBuf(ibuf);
+
+ ibuf->rect_float= NULL;
+ ibuf->mall &= ~IB_rectfloat;
+}
+
+/* any free rect frees mipmaps to be sure, creation is in render on first request */
+void imb_freerectImBuf(struct ImBuf * ibuf)
+{
+ if (ibuf==NULL) return;
+
+ if (ibuf->rect) {
+ if (ibuf->mall & IB_rect) {
+ MEM_freeN(ibuf->rect);
+ }
+ }
+
+ imb_freemipmapImBuf(ibuf);
+
+ ibuf->rect= NULL;
+ ibuf->mall &= ~IB_rect;
+}
+
+static void freeencodedbufferImBuf(struct ImBuf * ibuf)
+{
+ if (ibuf==NULL) return;
+ if (ibuf->encodedbuffer){
+ if (ibuf->mall & IB_mem) MEM_freeN(ibuf->encodedbuffer);
+ }
+ ibuf->encodedbuffer = 0;
+ ibuf->encodedbuffersize = 0;
+ ibuf->encodedsize = 0;
+ ibuf->mall &= ~IB_mem;
+}
+
+void IMB_freezbufImBuf(struct ImBuf * ibuf)
+{
+ if (ibuf==NULL) return;
+ if (ibuf->zbuf){
+ if (ibuf->mall & IB_zbuf) MEM_freeN(ibuf->zbuf);
+ }
+ ibuf->zbuf= NULL;
+ ibuf->mall &= ~IB_zbuf;
+}
+
+void IMB_freezbuffloatImBuf(struct ImBuf * ibuf)
+{
+ if (ibuf==NULL) return;
+ if (ibuf->zbuf_float){
+ if (ibuf->mall & IB_zbuffloat) MEM_freeN(ibuf->zbuf_float);
+ }
+ ibuf->zbuf_float= NULL;
+ ibuf->mall &= ~IB_zbuffloat;
+}
+
+void IMB_freecmapImBuf(struct ImBuf * ibuf)
+{
+ if (ibuf==NULL) return;
+ if (ibuf->cmap){
+ if (ibuf->mall & IB_cmap) MEM_freeN(ibuf->cmap);
+ }
+ ibuf->cmap = 0;
+ ibuf->mall &= ~IB_cmap;
+}
+
+void IMB_freeImBuf(struct ImBuf * ibuf)
+{
+ if (ibuf){
+ if (ibuf->refcounter > 0) {
+ ibuf->refcounter--;
+ } else {
+ imb_freeplanesImBuf(ibuf);
+ imb_freerectImBuf(ibuf);
+ imb_freerectfloatImBuf(ibuf);
+ IMB_freezbufImBuf(ibuf);
+ IMB_freezbuffloatImBuf(ibuf);
+ IMB_freecmapImBuf(ibuf);
+ freeencodedbufferImBuf(ibuf);
+ IMB_cache_limiter_unmanage(ibuf);
+ IMB_imginfo_free(ibuf);
+ MEM_freeN(ibuf);
+ }
+ }
+}
+
+void IMB_refImBuf(struct ImBuf * ibuf)
+{
+ ibuf->refcounter++;
+}
+
+short addzbufImBuf(struct ImBuf * ibuf)
+{
+ int size;
+
+ if (ibuf==NULL) return(FALSE);
+
+ IMB_freezbufImBuf(ibuf);
+
+ size = ibuf->x * ibuf->y * sizeof(unsigned int);
+ if ( (ibuf->zbuf = MEM_mapallocN(size, "addzbufImBuf")) ){
+ ibuf->mall |= IB_zbuf;
+ ibuf->flags |= IB_zbuf;
+ return (TRUE);
+ }
+
+ return (FALSE);
+}
+
+short addzbuffloatImBuf(struct ImBuf * ibuf)
+{
+ int size;
+
+ if (ibuf==NULL) return(FALSE);
+
+ IMB_freezbuffloatImBuf(ibuf);
+
+ size = ibuf->x * ibuf->y * sizeof(float);
+ if ( (ibuf->zbuf_float = MEM_mapallocN(size, "addzbuffloatImBuf")) ){
+ ibuf->mall |= IB_zbuffloat;
+ ibuf->flags |= IB_zbuffloat;
+ return (TRUE);
+ }
+
+ return (FALSE);
+}
+
+
+short imb_addencodedbufferImBuf(struct ImBuf * ibuf)
+{
+ if (ibuf==NULL) return(FALSE);
+
+ freeencodedbufferImBuf(ibuf);
+
+ if (ibuf->encodedbuffersize == 0)
+ ibuf->encodedbuffersize = 10000;
+
+ ibuf->encodedsize = 0;
+
+ if ( (ibuf->encodedbuffer = MEM_mallocN(ibuf->encodedbuffersize, "addencodedbufferImBuf") )){
+ ibuf->mall |= IB_mem;
+ ibuf->flags |= IB_mem;
+ return (TRUE);
+ }
+
+ return (FALSE);
+}
+
+
+short imb_enlargeencodedbufferImBuf(struct ImBuf * ibuf)
+{
+ unsigned int newsize, encodedsize;
+ void *newbuffer;
+
+ if (ibuf==NULL) return(FALSE);
+
+ if (ibuf->encodedbuffersize < ibuf->encodedsize) {
+ printf("imb_enlargeencodedbufferImBuf: error in parameters\n");
+ return(FALSE);
+ }
+
+ newsize = 2 * ibuf->encodedbuffersize;
+ if (newsize < 10000) newsize = 10000;
+
+ newbuffer = MEM_mallocN(newsize, "enlargeencodedbufferImBuf");
+ if (newbuffer == NULL) return(FALSE);
+
+ if (ibuf->encodedbuffer) {
+ memcpy(newbuffer, ibuf->encodedbuffer, ibuf->encodedsize);
+ } else {
+ ibuf->encodedsize = 0;
+ }
+
+ encodedsize = ibuf->encodedsize;
+
+ freeencodedbufferImBuf(ibuf);
+
+ ibuf->encodedbuffersize = newsize;
+ ibuf->encodedsize = encodedsize;
+ ibuf->encodedbuffer = newbuffer;
+ ibuf->mall |= IB_mem;
+ ibuf->flags |= IB_mem;
+
+ return (TRUE);
+}
+
+short imb_addrectfloatImBuf(struct ImBuf * ibuf)
+{
+ int size;
+
+ if (ibuf==NULL) return(FALSE);
+
+ imb_freerectfloatImBuf(ibuf);
+
+ size = ibuf->x * ibuf->y;
+ size = size * 4 * sizeof(float);
+
+ if ( (ibuf->rect_float = MEM_mapallocN(size, "imb_addrectfloatImBuf")) ){
+ ibuf->mall |= IB_rectfloat;
+ ibuf->flags |= IB_rectfloat;
+ return (TRUE);
+ }
+
+ return (FALSE);
+}
+
+/* question; why also add zbuf? */
+short imb_addrectImBuf(struct ImBuf * ibuf)
+{
+ int size;
+
+ if (ibuf==NULL) return(FALSE);
+ imb_freerectImBuf(ibuf);
+
+ size = ibuf->x * ibuf->y;
+ size = size * sizeof(unsigned int);
+
+ if ( (ibuf->rect = MEM_mapallocN(size, "imb_addrectImBuf")) ){
+ ibuf->mall |= IB_rect;
+ ibuf->flags |= IB_rect;
+ if (ibuf->depth > 32) return (addzbufImBuf(ibuf));
+ else return (TRUE);
+ }
+
+ return (FALSE);
+}
+
+
+short imb_addcmapImBuf(struct ImBuf *ibuf)
+{
+ int min;
+
+ if (ibuf==NULL) return(FALSE);
+ IMB_freecmapImBuf(ibuf);
+
+ imb_checkncols(ibuf);
+ if (ibuf->maxcol == 0) return (TRUE);
+
+ if ( (ibuf->cmap = MEM_callocN(sizeof(unsigned int) * ibuf->maxcol, "imb_addcmapImBuf") ) ){
+ min = ibuf->maxcol * sizeof(unsigned int);
+ if (min > sizeof(dfltcmap)) min = sizeof(dfltcmap);
+ memcpy(ibuf->cmap, dfltcmap, min);
+ ibuf->mall |= IB_cmap;
+ ibuf->flags |= IB_cmap;
+ return (TRUE);
+ }
+
+ return (FALSE);
+}
+
+
+short imb_addplanesImBuf(struct ImBuf *ibuf)
+{
+ int size;
+ short skipx,d,y;
+ unsigned int **planes;
+ unsigned int *point2;
+
+ if (ibuf==NULL) return(FALSE);
+ imb_freeplanesImBuf(ibuf);
+
+ skipx = ((ibuf->x+31) >> 5);
+ ibuf->skipx=skipx;
+ y=ibuf->y;
+ d=ibuf->depth;
+
+ planes = MEM_mallocN( (d*skipx*y)*sizeof(int) + d*sizeof(int *), "imb_addplanesImBuf");
+
+ ibuf->planes = planes;
+ if (planes==0) return (FALSE);
+
+ point2 = (unsigned int *)(planes+d);
+ size = skipx*y;
+
+ for (;d>0;d--){
+ *(planes++) = point2;
+ point2 += size;
+ }
+ ibuf->mall |= IB_planes;
+ ibuf->flags |= IB_planes;
+
+ return (TRUE);
+}
+
+
+struct ImBuf *IMB_allocImBuf(short x, short y, uchar d, unsigned int flags, uchar bitmap)
+{
+ struct ImBuf *ibuf;
+
+ ibuf = MEM_callocN(sizeof(struct ImBuf), "ImBuf_struct");
+ if (bitmap) flags |= IB_planes;
+
+ if (ibuf){
+ ibuf->x= x;
+ ibuf->y= y;
+ ibuf->depth= d;
+ ibuf->ftype= TGA;
+ ibuf->channels= 4; /* float option, is set to other values when buffers get assigned */
+
+ if (flags & IB_rect){
+ if (imb_addrectImBuf(ibuf)==FALSE){
+ IMB_freeImBuf(ibuf);
+ return NULL;
+ }
+ }
+
+ if (flags & IB_rectfloat){
+ if (imb_addrectfloatImBuf(ibuf)==FALSE){
+ IMB_freeImBuf(ibuf);
+ return NULL;
+ }
+ }
+
+ if (flags & IB_zbuf){
+ if (addzbufImBuf(ibuf)==FALSE){
+ IMB_freeImBuf(ibuf);
+ return NULL;
+ }
+ }
+
+ if (flags & IB_zbuffloat){
+ if (addzbuffloatImBuf(ibuf)==FALSE){
+ IMB_freeImBuf(ibuf);
+ return NULL;
+ }
+ }
+
+ if (flags & IB_planes){
+ if (imb_addplanesImBuf(ibuf)==FALSE){
+ IMB_freeImBuf(ibuf);
+ return NULL;
+ }
+ }
+ }
+ return (ibuf);
+}
+
+/* does no zbuffers? */
+struct ImBuf *IMB_dupImBuf(struct ImBuf *ibuf1)
+{
+ struct ImBuf *ibuf2, tbuf;
+ int flags = 0;
+ int a, x, y;
+
+ if (ibuf1 == NULL) return NULL;
+
+ if (ibuf1->rect) flags |= IB_rect;
+ if (ibuf1->rect_float) flags |= IB_rectfloat;
+ if (ibuf1->planes) flags |= IB_planes;
+
+ x = ibuf1->x;
+ y = ibuf1->y;
+ if (ibuf1->flags & IB_fields) y *= 2;
+
+ ibuf2 = IMB_allocImBuf(x, y, ibuf1->depth, flags, 0);
+ if (ibuf2 == NULL) return NULL;
+
+ if (flags & IB_rect)
+ memcpy(ibuf2->rect, ibuf1->rect, x * y * sizeof(int));
+
+ if (flags & IB_rectfloat)
+ memcpy(ibuf2->rect_float, ibuf1->rect_float, 4 * x * y * sizeof(float));
+
+ if (flags & IB_planes)
+ memcpy(*(ibuf2->planes),*(ibuf1->planes),ibuf1->depth * ibuf1->skipx * y * sizeof(int));
+
+ if (ibuf1->encodedbuffer) {
+ ibuf2->encodedbuffersize = ibuf1->encodedbuffersize;
+ if (imb_addencodedbufferImBuf(ibuf2) == FALSE) {
+ IMB_freeImBuf(ibuf2);
+ return NULL;
+ }
+
+ memcpy(ibuf2->encodedbuffer, ibuf1->encodedbuffer, ibuf1->encodedsize);
+ }
+
+ /* silly trick to copy the entire contents of ibuf1 struct over to ibuf */
+ tbuf = *ibuf1;
+
+ // fix pointers
+ tbuf.rect = ibuf2->rect;
+ tbuf.rect_float = ibuf2->rect_float;
+ tbuf.planes = ibuf2->planes;
+ tbuf.cmap = ibuf2->cmap;
+ tbuf.encodedbuffer = ibuf2->encodedbuffer;
+ tbuf.zbuf= NULL;
+ tbuf.zbuf_float= NULL;
+ for(a=0; a<IB_MIPMAP_LEVELS; a++)
+ tbuf.mipmap[a]= NULL;
+
+ // set malloc flag
+ tbuf.mall = ibuf2->mall;
+ tbuf.c_handle = 0;
+
+ // for now don't duplicate image info
+ tbuf.img_info = 0;
+
+ *ibuf2 = tbuf;
+
+ if (ibuf1->cmap){
+ imb_addcmapImBuf(ibuf2);
+ if (ibuf2->cmap) memcpy(ibuf2->cmap,ibuf1->cmap,ibuf2->maxcol * sizeof(int));
+ }
+
+ return(ibuf2);
+}
+
+/* support for cache limiting */
+
+static void imbuf_cache_destructor(void * data)
+{
+ struct ImBuf * ibuf = (struct ImBuf*) data;
+
+ imb_freeplanesImBuf(ibuf);
+ imb_freerectImBuf(ibuf);
+ imb_freerectfloatImBuf(ibuf);
+ IMB_freezbufImBuf(ibuf);
+ IMB_freezbuffloatImBuf(ibuf);
+ IMB_freecmapImBuf(ibuf);
+ freeencodedbufferImBuf(ibuf);
+
+ ibuf->c_handle = 0;
+}
+
+static MEM_CacheLimiterC ** get_imbuf_cache_limiter()
+{
+ static MEM_CacheLimiterC * c = 0;
+ if (!c) {
+ c = new_MEM_CacheLimiter(imbuf_cache_destructor);
+ }
+ return &c;
+}
+
+void IMB_free_cache_limiter()
+{
+ delete_MEM_CacheLimiter(*get_imbuf_cache_limiter());
+ *get_imbuf_cache_limiter() = 0;
+}
+
+void IMB_cache_limiter_insert(struct ImBuf * i)
+{
+ if (!i->c_handle) {
+ i->c_handle = MEM_CacheLimiter_insert(
+ *get_imbuf_cache_limiter(), i);
+ MEM_CacheLimiter_ref(i->c_handle);
+ MEM_CacheLimiter_enforce_limits(
+ *get_imbuf_cache_limiter());
+ MEM_CacheLimiter_unref(i->c_handle);
+ }
+}
+
+void IMB_cache_limiter_unmanage(struct ImBuf * i)
+{
+ if (i->c_handle) {
+ MEM_CacheLimiter_unmanage(i->c_handle);
+ i->c_handle = 0;
+ }
+}
+
+void IMB_cache_limiter_touch(struct ImBuf * i)
+{
+ if (i->c_handle) {
+ MEM_CacheLimiter_touch(i->c_handle);
+ }
+}
+
+void IMB_cache_limiter_ref(struct ImBuf * i)
+{
+ if (i->c_handle) {
+ MEM_CacheLimiter_ref(i->c_handle);
+ }
+}
+
+void IMB_cache_limiter_unref(struct ImBuf * i)
+{
+ if (i->c_handle) {
+ MEM_CacheLimiter_unref(i->c_handle);
+ }
+}
+
+int IMB_cache_limiter_get_refcount(struct ImBuf * i)
+{
+ if (i->c_handle) {
+ return MEM_CacheLimiter_get_refcount(i->c_handle);
+ }
+ return 0;
+}
diff --git a/source/blender/imbuf/intern/amiga.c b/source/blender/imbuf/intern/amiga.c
new file mode 100644
index 00000000000..d0b794c23ec
--- /dev/null
+++ b/source/blender/imbuf/intern/amiga.c
@@ -0,0 +1,538 @@
+/**
+ * amiga.c
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifdef WIN32
+#include <io.h>
+#endif
+#include "imbuf.h"
+#include "imbuf_patch.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "BKE_global.h"
+
+#include "IMB_cmap.h"
+#include "IMB_allocimbuf.h"
+#include "IMB_bitplanes.h"
+#include "IMB_amiga.h"
+
+/* actually hard coded endianness */
+#define GET_BIG_LONG(x) (((uchar *) (x))[0] << 24 | ((uchar *) (x))[1] << 16 | ((uchar *) (x))[2] << 8 | ((uchar *) (x))[3])
+#define GET_LITTLE_LONG(x) (((uchar *) (x))[3] << 24 | ((uchar *) (x))[2] << 16 | ((uchar *) (x))[1] << 8 | ((uchar *) (x))[0])
+#define SWAP_L(x) (((x << 24) & 0xff000000) | ((x << 8) & 0xff0000) | ((x >> 8) & 0xff00) | ((x >> 24) & 0xff))
+#define SWAP_S(x) (((x << 8) & 0xff00) | ((x >> 8) & 0xff))
+
+/* more endianness... should move to a separate file... */
+#if defined(__sgi) || defined (__sparc) || defined (__sparc__) || defined (__PPC__) || defined (__ppc__) || defined (__BIG_ENDIAN__)
+#define GET_ID GET_BIG_LONG
+#define LITTLE_LONG SWAP_LONG
+#else
+#define GET_ID GET_LITTLE_LONG
+#define LITTLE_LONG ENDIAN_NOP
+#endif
+
+static uchar *decodebodyscanl(uchar *body, short bytes, uchar **list, short d)
+{
+ for (;d>0;d--){
+ uchar *point;
+ short todo;
+ uchar i,j;
+
+ point = *(list++);
+ todo=bytes;
+ while (todo>0){
+ i = *body++;
+
+ if (i & 128){ /* fill */
+ if (i==128) continue; /* nop */
+
+ i=257-i;
+ todo-=i;
+ j = *(body++);
+ do{
+ *(point++) = j;
+ i--;
+ }while (i);
+ } else{ /* copy */
+ i++;
+ todo-=i;
+
+ do{
+ *(point++) = *(body++);
+ i--;
+ }while (i);
+ }
+ }
+ if (todo) return (0);
+ }
+ return(body);
+}
+
+
+static uchar *decodebodyh(struct ImBuf *ibuf, uchar *body)
+{
+ if (ibuf->y==1) {
+ body=decodebodyscanl(body, WIDTHB(ibuf->x), (uchar **)ibuf->planes, ibuf->depth);
+ }
+ else {
+ unsigned int **list;
+ short skipx,i,bytes,y;
+
+ list = imb_copyplanelist(ibuf);
+ if (list == 0) return (0);
+
+ y=ibuf->y;
+ bytes = WIDTHB(ibuf->x);
+ skipx = ibuf->skipx;
+
+ for (;y>0;y--){
+ body=decodebodyscanl(body, bytes, (uchar **)list, ibuf->depth);
+ if (body == 0) return (0);
+
+ for (i=ibuf->depth-1;i>=0;i--){
+ list[i] += skipx;
+ }
+ }
+ free(list);
+ }
+ return(body);
+}
+
+
+static uchar *decodebodykolum(uchar *body, short bytes, uchar **list, short d, int next)
+{
+ for (;d>0;d--){
+ uchar *point;
+ short todo;
+ uchar i,j;
+
+ point = *(list++);
+ todo=bytes;
+ while (todo>0){
+ i = *body++;
+
+ if (i & 128){ /* fill */
+ if (i==128) continue; /* nop */
+
+ i=257-i;
+ todo-=i;
+ j = *body++;
+ do{
+ *point = j;
+ point += next;
+ i--;
+ }while (i);
+ }
+ else{ /* copy */
+ i++;
+ todo-=i;
+
+ do{
+ *point = *body++;
+ point += next;
+ i--;
+ }while (i);
+ }
+ }
+ if (todo) return (0);
+ }
+ return(body);
+}
+
+
+static uchar *decodebodyv(struct ImBuf *ibuf, uchar *body)
+{
+ uchar **list;
+ int skipx, i, bytes, times;
+
+ list = (uchar **)imb_copyplanelist(ibuf);
+ if (list == 0) return (0);
+
+ bytes = ibuf->y;
+ times = WIDTHB(ibuf->x);
+ skipx = ibuf->skipx << 2;
+
+ for (;times>0;times--){
+ body=decodebodykolum(body,bytes,list,ibuf->depth,skipx);
+ if (body == 0) return (0);
+
+ for (i=ibuf->depth-1;i>=0;i--){
+ list[i] += 1;
+ }
+ }
+ free(list);
+ return(body);
+}
+
+static uchar *makebody(uchar **planes, short bytes, short depth, uchar *buf)
+{
+ uchar *bitplstart,*temp;
+
+ register uchar last,this,*bitpl;
+ register short todo;
+ register int copy;
+
+ bytes--;
+ for (;depth>0;depth--){
+ bitpl = *(planes++);
+ bitplstart = bitpl;
+ todo = bytes;
+ last = *bitpl++;
+ this = *bitpl++;
+ copy = last^this;
+ while (todo>0){
+
+ if (copy){
+ do{
+ last = this;
+ this = *bitpl++;
+ if (last == this){
+ if (this == bitpl[-3]){ /* three identical ones? */
+ todo -= 1; /* set todo */
+ break;
+ }
+ }
+ }while (--todo != 0);
+
+ copy=bitpl-bitplstart;
+ copy -= 1;
+ if (todo) copy -= 2;
+
+ temp = bitpl;
+ bitpl = bitplstart;
+
+ while (copy){
+ last = copy;
+ if (copy>MAXDAT) last = MAXDAT;
+ copy -= last;
+ *buf++ = last-1;
+ do{
+ *buf++ = *bitpl++;
+ }while(--last != 0);
+ }
+ bitplstart = bitpl;
+ bitpl = temp;
+ last = this;
+
+ copy = FALSE;
+ }
+ else{
+ while (*bitpl++ == this){ /* search for first different bye */
+ if (--todo == 0) break; /* or end of line */
+ }
+ bitpl -= 1;
+ copy = bitpl-bitplstart;
+ bitplstart = bitpl;
+ todo -= 1;
+ this = *bitpl++;
+
+ while (copy){
+ if (copy>MAXRUN){
+ *buf++ = -(MAXRUN-1);
+ *buf++ = last;
+ copy -= MAXRUN;
+ }
+ else{
+ *buf++ = -(copy-1);
+ *buf++ = last;
+ break;
+ }
+ }
+ copy=TRUE;
+ }
+ }
+ }
+ return (buf);
+}
+
+
+short imb_encodebodyh(struct ImBuf *ibuf, int file)
+{
+ uchar *buf, *endbuf, *max;
+ int size, line, ok = TRUE;
+ unsigned int **list;
+ short skipx,i,y;
+
+ line = WIDTHB(ibuf->x) * ibuf->depth;
+ line += (line >> 6) + 10;
+ size = 16 * line;
+ if (size < 16384) size = 16384;
+
+ buf = (uchar *) malloc(size);
+ if (buf == 0) return (0);
+
+ max = buf + size - line;
+
+ list = imb_copyplanelist(ibuf);
+ if (list == 0){
+ free(buf);
+ return (0);
+ }
+
+ y=ibuf->y;
+ skipx = ibuf->skipx;
+ endbuf = buf;
+
+ for (y=ibuf->y;y>0;y--){
+ endbuf = makebody((uchar **)list, WIDTHB(ibuf->x), ibuf->depth, endbuf);
+ if (endbuf==0){
+ ok = -20;
+ break;
+ }
+ if (endbuf >= max || y == 1){
+ size = endbuf-buf;
+ if (write(file,buf,size)!=size) ok = -19;
+ endbuf = buf;
+ }
+ for (i=ibuf->depth-1;i>=0;i--){
+ list[i] += skipx;
+ }
+ if (ok != TRUE) break;
+ }
+ free(list);
+
+ free(buf);
+ return(ok);
+}
+
+
+short imb_encodebodyv(struct ImBuf *ibuf, int file)
+{
+ struct ImBuf *ibufv;
+ uchar *buf,*endbuf;
+ short x,offset;
+
+ buf = (uchar *) malloc((ibuf->y + (ibuf->y >> 6) + 10) * ibuf->depth);
+ if (buf == 0) return (0);
+
+ ibufv=IMB_allocImBuf((ibuf->y)<<3,1, ibuf->depth, 0, 1);
+ if (ibufv == 0){
+ free(buf);
+ return (0);
+ }
+
+ offset=0;
+
+ for(x = WIDTHB(ibuf->x);x>0;x--){
+ register short i;
+
+ for(i = ibuf->depth-1 ;i>=0;i--){
+ register uchar *p1,*p2;
+ register int skipx;
+ register short y;
+
+ skipx = (ibuf->skipx)*sizeof(int *);
+ p1=(uchar *)ibuf->planes[i];
+ p2=(uchar *)ibufv->planes[i];
+ p1 += offset;
+
+ for (y=ibuf->y;y>0;y--){
+ *(p2++) = *p1;
+ p1 += skipx;
+ }
+ }
+ offset += 1;
+
+ endbuf=makebody((uchar **)ibufv->planes, ibuf->y, ibuf->depth, buf);
+ if (endbuf==0) return (-20);
+ if (write(file,buf,endbuf-buf)!=endbuf-buf) return (-19);
+ }
+ free(buf);
+ IMB_freeImBuf(ibufv);
+ return (TRUE);
+}
+
+static uchar *readbody(struct ImBuf *ibuf, uchar *body)
+{
+ int skipbuf,skipbdy,depth,y,offset = 0;
+
+ skipbuf = ibuf->skipx;
+ skipbdy = WIDTHB(ibuf->x);
+
+ for (y = ibuf->y; y> 0; y--){
+ for( depth = 0; depth < ibuf->depth; depth ++){
+ memcpy(ibuf->planes[depth] + offset, body, skipbdy);
+ body += skipbdy;
+ }
+ offset += skipbuf;
+ }
+ return body;
+}
+
+struct ImBuf *imb_loadamiga(int *iffmem,int flags)
+{
+ int chunk,totlen,len,*cmap=0,cmaplen =0,*mem,ftype=0;
+ uchar *body=0;
+ struct BitMapHeader bmhd;
+ struct ImBuf *ibuf=0;
+
+ mem = iffmem;
+ bmhd.w = 0;
+
+ if (GET_ID(mem) != FORM) return (0);
+ if (GET_ID(mem+2) != ILBM) return (0);
+ totlen= (GET_BIG_LONG(mem+1) + 1) & ~1;
+ mem += 3;
+ totlen -= 4;
+
+
+ while(totlen > 0){
+ chunk = GET_ID(mem);
+ len= (GET_BIG_LONG(mem+1) + 1) & ~1;
+ mem += 2;
+
+ totlen -= len+8;
+
+ switch (chunk){
+ case BMHD:
+ memcpy(&bmhd, mem, sizeof(struct BitMapHeader));
+
+ bmhd.w = BIG_SHORT(bmhd.w);
+ bmhd.h = BIG_SHORT(bmhd.h);
+ bmhd.x = BIG_SHORT(bmhd.x);
+ bmhd.y = BIG_SHORT(bmhd.y);
+ bmhd.transparentColor = BIG_SHORT(bmhd.transparentColor);
+ bmhd.pageWidth = BIG_SHORT(bmhd.pageWidth);
+ bmhd.pageHeight = BIG_SHORT(bmhd.pageHeight);
+
+ break;
+ case BODY:
+ body = (uchar *)mem;
+ break;
+ case CMAP:
+ cmap = mem;
+ cmaplen = len/3;
+ break;
+ case CAMG:
+ ftype = GET_BIG_LONG(mem);
+ break;
+ }
+ mem = (int *)((uchar *)mem +len);
+ if (body) break;
+ }
+ if (bmhd.w == 0) return (0);
+ if (body == 0) return (0);
+
+ if (flags & IB_test) ibuf = IMB_allocImBuf(bmhd.w, bmhd.h, bmhd.nPlanes, 0, 0);
+ else ibuf = IMB_allocImBuf(bmhd.w, bmhd.h, bmhd.nPlanes + (bmhd.masking & 1),0,1);
+
+ if (ibuf == 0) return (0);
+
+ ibuf->ftype = (ftype | AMI);
+
+ if (cmap){
+ ibuf->mincol = 0;
+ ibuf->maxcol = cmaplen;
+ imb_addcmapImBuf(ibuf);
+ imb_makecolarray(ibuf, (uchar *)cmap, 0);
+ }
+
+ if (flags & IB_test){
+ if (flags & IB_freem) free(iffmem);
+ return(ibuf);
+ }
+
+ switch (bmhd.compression){
+ case 0:
+ body= readbody(ibuf, body);
+ break;
+ case 1:
+ body= decodebodyh(ibuf,body);
+ break;
+ case 2:
+ body= decodebodyv(ibuf,body);
+ ibuf->type |= IB_subdlta;
+ break;
+ }
+
+ if (flags & IB_freem) free(iffmem);
+
+ if (body == 0){
+ free (ibuf);
+ return(0);
+ }
+
+ /* forget stencil */
+ ibuf->depth = bmhd.nPlanes;
+
+ if (flags & IB_rect){
+ imb_addrectImBuf(ibuf);
+ imb_bptolong(ibuf);
+ imb_freeplanesImBuf(ibuf);
+ if (ibuf->cmap){
+ if ((flags & IB_cmap) == 0) IMB_applycmap(ibuf);
+ } else if (ibuf->depth == 18){
+ int i,col;
+ unsigned int *rect;
+
+ rect = ibuf->rect;
+ for(i=ibuf->x * ibuf->y ; i>0 ; i--){
+ col = *rect;
+ col = ((col & 0x3f000) << 6) + ((col & 0xfc0) << 4) + ((col & 0x3f) << 2);
+ col += (col & 0xc0c0c0) >> 6;
+ *rect++ = col;
+ }
+ ibuf->depth = 24;
+ } else if (ibuf->depth <= 8) { /* no colormap and no 24 bits: b&w */
+ uchar *rect;
+ int size, shift;
+
+ if (ibuf->depth < 8){
+ rect = (uchar *) ibuf->rect;
+ rect += 3;
+ shift = 8 - ibuf->depth;
+ for (size = ibuf->x * ibuf->y; size > 0; size --){
+ rect[0] <<= shift;
+ rect += 4;
+ }
+ }
+ rect = (uchar *) ibuf->rect;
+ for (size = ibuf->x * ibuf->y; size > 0; size --){
+ rect[1] = rect[2] = rect[3];
+ rect += 4;
+ }
+ ibuf->depth = 8;
+ }
+ }
+
+ if ((flags & IB_ttob) == 0) IMB_flipy(ibuf);
+
+ if (ibuf) {
+ if (ibuf->rect)
+ if (G.order == B_ENDIAN) IMB_convert_rgba_to_abgr(ibuf);
+ }
+
+ return (ibuf);
+}
diff --git a/source/blender/imbuf/intern/anim.c b/source/blender/imbuf/intern/anim.c
new file mode 100644
index 00000000000..e99c35e45ce
--- /dev/null
+++ b/source/blender/imbuf/intern/anim.c
@@ -0,0 +1,932 @@
+/**
+ * anim.c
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifdef _WIN32
+#define INC_OLE2
+#include <windows.h>
+#include <windowsx.h>
+#include <mmsystem.h>
+#include <memory.h>
+#include <commdlg.h>
+
+#ifndef FREE_WINDOWS
+#include <vfw.h>
+#endif
+
+#undef AVIIF_KEYFRAME // redefined in AVI_avi.h
+#undef AVIIF_LIST // redefined in AVI_avi.h
+
+#define FIXCC(fcc) if (fcc == 0) fcc = mmioFOURCC('N', 'o', 'n', 'e'); \
+ if (fcc == BI_RLE8) fcc = mmioFOURCC('R', 'l', 'e', '8');
+#endif
+
+#include <sys/types.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#ifndef _WIN32
+#include <dirent.h>
+#else
+#include <io.h>
+#endif
+
+#include "BLI_blenlib.h" /* BLI_remlink BLI_filesize BLI_addtail
+ BLI_countlist BLI_stringdec */
+#include "DNA_userdef_types.h"
+#include "BKE_global.h"
+
+#include "imbuf.h"
+#include "imbuf_patch.h"
+
+#include "AVI_avi.h"
+
+#ifdef WITH_QUICKTIME
+#if defined(_WIN32) || defined(__APPLE__)
+#include "quicktime_import.h"
+#endif /* _WIN32 || __APPLE__ */
+#endif /* WITH_QUICKTIME */
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "IMB_allocimbuf.h"
+#include "IMB_bitplanes.h"
+#include "IMB_anim.h"
+#include "IMB_anim5.h"
+
+#ifdef WITH_FFMPEG
+#include <ffmpeg/avformat.h>
+#include <ffmpeg/avcodec.h>
+#include <ffmpeg/rational.h>
+#include <ffmpeg/swscale.h>
+
+#if LIBAVFORMAT_VERSION_INT < (49 << 16)
+#define FFMPEG_OLD_FRAME_RATE 1
+#else
+#define FFMPEG_CODEC_IS_POINTER 1
+#endif
+
+#endif
+
+/****/
+
+#ifdef __sgi
+
+#include <dmedia/moviefile.h>
+
+static void movie_printerror(char * str) {
+ const char * errstr = mvGetErrorStr(mvGetErrno());
+
+ if (str) {
+ if (errstr) printf("%s: %s\n", str, errstr);
+ else printf("%s: returned error\n", str);
+ } else printf("%s\n", errstr);
+}
+
+static int startmovie(struct anim * anim) {
+ if (anim == 0) return(-1);
+
+ if ( mvOpenFile (anim->name, O_BINARY|O_RDONLY, &anim->movie ) != DM_SUCCESS ) {
+ printf("Can't open movie: %s\n", anim->name);
+ return(-1);
+ }
+ if ( mvFindTrackByMedium (anim->movie, DM_IMAGE, &anim->track) != DM_SUCCESS ) {
+ printf("No image track in movie: %s\n", anim->name);
+ mvClose(anim->movie);
+ return(-1);
+ }
+
+ anim->duration = mvGetTrackLength (anim->track);
+ anim->params = mvGetParams( anim->track );
+
+ anim->x = dmParamsGetInt( anim->params, DM_IMAGE_WIDTH);
+ anim->y = dmParamsGetInt( anim->params, DM_IMAGE_HEIGHT);
+ anim->interlacing = dmParamsGetEnum (anim->params, DM_IMAGE_INTERLACING);
+ anim->orientation = dmParamsGetEnum (anim->params, DM_IMAGE_ORIENTATION);
+ anim->framesize = dmImageFrameSize(anim->params);
+
+ anim->curposition = 0;
+ anim->preseek = 0;
+
+ /*printf("x:%d y:%d size:%d interl:%d dur:%d\n", anim->x, anim->y, anim->framesize, anim->interlacing, anim->duration);*/
+ return (0);
+}
+
+static ImBuf * movie_fetchibuf(struct anim * anim, int position) {
+ ImBuf * ibuf;
+/* extern rectcpy(); */
+ int size;
+ unsigned int *rect1, *rect2;
+
+ if (anim == 0) return (0);
+
+ ibuf = IMB_allocImBuf(anim->x, anim->y, 24, IB_rect, 0);
+
+ if ( mvReadFrames(anim->track, position, 1, ibuf->x * ibuf->y *
+ sizeof(int), ibuf->rect ) != DM_SUCCESS ) {
+ movie_printerror("mvReadFrames");
+ IMB_freeImBuf(ibuf);
+ return(0);
+ }
+
+/*
+ if (anim->interlacing == DM_IMAGE_INTERLACED_EVEN) {
+ rect1 = ibuf->rect + (ibuf->x * ibuf->y) - 1;
+ rect2 = rect1 - ibuf->x;
+
+ for (size = ibuf->x * (ibuf->y - 1); size > 0; size--){
+ *rect1-- = *rect2--;
+ }
+ }
+*/
+
+ if (anim->interlacing == DM_IMAGE_INTERLACED_EVEN)
+ {
+ rect1 = ibuf->rect;
+ rect2 = rect1 + ibuf->x;
+
+ for (size = ibuf->x * (ibuf->y - 1); size > 0; size--){
+ *rect1++ = *rect2++;
+ }
+ }
+ /*if (anim->orientation == DM_TOP_TO_BOTTOM) IMB_flipy(ibuf);*/
+
+
+ return(ibuf);
+}
+
+static void free_anim_movie(struct anim * anim) {
+ if (anim == NULL) return;
+
+ if (anim->movie) {
+ mvClose(anim->movie);
+ anim->movie = NULL;
+ }
+ anim->duration = 0;
+}
+
+int ismovie(char *name) {
+ return (mvIsMovieFile(name) == DM_TRUE);
+}
+
+#else
+
+int ismovie(char *name) {
+ return 0;
+}
+
+ /* never called, just keep the linker happy */
+static int startmovie(struct anim * anim) { return 1; }
+static ImBuf * movie_fetchibuf(struct anim * anim, int position) { return NULL; }
+static void free_anim_movie(struct anim * anim) { ; }
+
+#endif
+
+static int an_stringdec(char *string, char* kop, char *staart,unsigned short *numlen) {
+ unsigned short len,nume,nums=0;
+ short i,found=FALSE;
+
+ len=strlen(string);
+ nume = len;
+
+ for(i=len-1;i>=0;i--){
+ if (string[i]=='/') break;
+ if (isdigit(string[i])) {
+ if (found){
+ nums=i;
+ } else{
+ nume=i;
+ nums=i;
+ found=TRUE;
+ }
+ } else{
+ if (found) break;
+ }
+ }
+ if (found){
+ strcpy(staart,&string[nume+1]);
+ strcpy(kop,string);
+ kop[nums]=0;
+ *numlen=nume-nums+1;
+ return ((int)atoi(&(string[nums])));
+ }
+ staart[0]=0;
+ strcpy(kop,string);
+ *numlen=0;
+ return (1);
+}
+
+
+static void an_stringenc(char *string, char *kop, char *staart,
+unsigned short numlen, int pic) {
+ char numstr[10];
+ unsigned short len,i;
+
+ len=sprintf(numstr,"%d",pic);
+
+ strcpy(string,kop);
+ for(i=len;i<numlen;i++){
+ strcat(string,"0");
+ }
+ strcat(string,numstr);
+ strcat(string,staart);
+}
+
+
+static void free_anim_avi (struct anim *anim) {
+#if defined(_WIN32) && !defined(FREE_WINDOWS)
+ int i;
+#endif
+
+ if (anim == NULL) return;
+ if (anim->avi == NULL) return;
+
+ AVI_close (anim->avi);
+ MEM_freeN (anim->avi);
+ anim->avi = NULL;
+
+#if defined(_WIN32) && !defined(FREE_WINDOWS)
+
+ if (anim->pgf) {
+ AVIStreamGetFrameClose(anim->pgf);
+ anim->pgf = NULL;
+ }
+
+ for (i = 0; i < anim->avistreams; i++){
+ AVIStreamRelease(anim->pavi[i]);
+ }
+ anim->avistreams = 0;
+
+ if (anim->pfileopen) {
+ AVIFileRelease(anim->pfile);
+ anim->pfileopen = 0;
+ AVIFileExit();
+ }
+#endif
+
+ anim->duration = 0;
+}
+
+void IMB_free_anim_ibuf(struct anim * anim) {
+ if (anim == NULL) return;
+
+ if (anim->ibuf1) IMB_freeImBuf(anim->ibuf1);
+ if (anim->ibuf2) IMB_freeImBuf(anim->ibuf2);
+
+ anim->ibuf1 = anim->ibuf2 = NULL;
+}
+
+#ifdef WITH_FFMPEG
+static void free_anim_ffmpeg(struct anim * anim);
+#endif
+
+void IMB_free_anim(struct anim * anim) {
+ if (anim == NULL) {
+ printf("free anim, anim == NULL\n");
+ return;
+ }
+
+ IMB_free_anim_ibuf(anim);
+ free_anim_anim5(anim);
+ free_anim_movie(anim);
+ free_anim_avi(anim);
+
+#ifdef WITH_QUICKTIME
+ free_anim_quicktime(anim);
+#endif
+#ifdef WITH_FFMPEG
+ free_anim_ffmpeg(anim);
+#endif
+
+ free(anim);
+}
+
+void IMB_close_anim(struct anim * anim) {
+ if (anim == 0) return;
+
+ IMB_free_anim(anim);
+}
+
+
+struct anim * IMB_open_anim( const char * name, int ib_flags) {
+ struct anim * anim;
+
+ anim = (struct anim*)MEM_callocN(sizeof(struct anim), "anim struct");
+ if (anim != NULL) {
+ strcpy(anim->name, name); /* fixme: possible buffer overflow here? */
+ anim->ib_flags = ib_flags;
+ }
+ return(anim);
+}
+
+
+static int startavi (struct anim *anim) {
+
+ AviError avierror;
+#if defined(_WIN32) && !defined(FREE_WINDOWS)
+ HRESULT hr;
+ int i, firstvideo = -1;
+ BYTE abFormat[1024];
+ LONG l;
+ LPBITMAPINFOHEADER lpbi;
+ AVISTREAMINFO avis;
+#endif
+
+ anim->avi = MEM_callocN (sizeof(AviMovie),"animavi");
+
+ if (anim->avi == NULL) {
+ printf("Can't open avi: %s\n", anim->name);
+ return -1;
+ }
+
+ avierror = AVI_open_movie (anim->name, anim->avi);
+
+#if defined(_WIN32) && !defined(FREE_WINDOWS)
+ if (avierror == AVI_ERROR_COMPRESSION) {
+ AVIFileInit();
+ hr = AVIFileOpen(&anim->pfile, anim->name, OF_READ, 0L);
+ if (hr == 0) {
+ anim->pfileopen = 1;
+ for (i = 0; i < MAXNUMSTREAMS; i++) {
+ if (AVIFileGetStream(anim->pfile, &anim->pavi[i], 0L, i) != AVIERR_OK) {
+ break;
+ }
+
+ AVIStreamInfo(anim->pavi[i], &avis, sizeof(avis));
+ if ((avis.fccType == streamtypeVIDEO) && (firstvideo == -1)) {
+ anim->pgf = AVIStreamGetFrameOpen(anim->pavi[i], NULL);
+ if (anim->pgf) {
+ firstvideo = i;
+
+ // get stream length
+ anim->avi->header->TotalFrames = AVIStreamLength(anim->pavi[i]);
+
+ // get information about images inside the stream
+ l = sizeof(abFormat);
+ AVIStreamReadFormat(anim->pavi[i], 0, &abFormat, &l);
+ lpbi = (LPBITMAPINFOHEADER)abFormat;
+ anim->avi->header->Height = lpbi->biHeight;
+ anim->avi->header->Width = lpbi->biWidth;
+ } else {
+ FIXCC(avis.fccHandler);
+ FIXCC(avis.fccType);
+ printf("Can't find AVI decoder for type : %4.4hs/%4.4hs\n",
+ (LPSTR)&avis.fccType,
+ (LPSTR)&avis.fccHandler);
+ }
+ }
+ }
+
+ // register number of opened avistreams
+ anim->avistreams = i;
+
+ //
+ // Couldn't get any video streams out of this file
+ //
+ if ((anim->avistreams == 0) || (firstvideo == -1)) {
+ avierror = AVI_ERROR_FORMAT;
+ } else {
+ avierror = AVI_ERROR_NONE;
+ anim->firstvideo = firstvideo;
+ }
+ } else {
+ AVIFileExit();
+ }
+ }
+#endif
+
+ if (avierror != AVI_ERROR_NONE) {
+ AVI_print_error(avierror);
+ printf ("Error loading avi: %s\n", anim->name);
+ free_anim_avi(anim);
+ return -1;
+ }
+
+ anim->duration = anim->avi->header->TotalFrames;
+ anim->params = 0;
+
+ anim->x = anim->avi->header->Width;
+ anim->y = anim->avi->header->Height;
+ anim->interlacing = 0;
+ anim->orientation = 0;
+ anim->framesize = anim->x * anim->y * 4;
+
+ anim->curposition = 0;
+ anim->preseek = 0;
+
+ /* printf("x:%d y:%d size:%d interl:%d dur:%d\n", anim->x, anim->y, anim->framesize, anim->interlacing, anim->duration);*/
+
+ return 0;
+}
+
+static ImBuf * avi_fetchibuf (struct anim *anim, int position) {
+ ImBuf *ibuf = NULL;
+ int *tmp;
+ int y;
+
+ if (anim == NULL) return (NULL);
+
+#if defined(_WIN32) && !defined(FREE_WINDOWS)
+ if (anim->avistreams) {
+ LPBITMAPINFOHEADER lpbi;
+
+ if (anim->pgf) {
+ lpbi = AVIStreamGetFrame(anim->pgf, position + AVIStreamStart(anim->pavi[anim->firstvideo]));
+ if (lpbi) {
+ ibuf = IMB_ibImageFromMemory((int *) lpbi, 100, IB_rect);
+//Oh brother...
+ }
+ }
+ } else {
+#else
+ if (1) {
+#endif
+ ibuf = IMB_allocImBuf (anim->x, anim->y, 24, IB_rect, 0);
+
+ tmp = AVI_read_frame (anim->avi, AVI_FORMAT_RGB32, position,
+ AVI_get_stream(anim->avi, AVIST_VIDEO, 0));
+
+ if (tmp == NULL) {
+ printf ("Error reading frame from AVI");
+ IMB_freeImBuf (ibuf);
+ return NULL;
+ }
+
+ for (y=0; y < anim->y; y++) {
+ memcpy (&(ibuf->rect)[((anim->y-y)-1)*anim->x], &tmp[y*anim->x],
+ anim->x * 4);
+ }
+
+ MEM_freeN (tmp);
+ }
+
+ return ibuf;
+}
+
+#ifdef WITH_FFMPEG
+
+extern void do_init_ffmpeg();
+
+#ifdef FFMPEG_CODEC_IS_POINTER
+static AVCodecContext* get_codec_from_stream(AVStream* stream)
+{
+ return stream->codec;
+}
+#else
+static AVCodecContext* get_codec_from_stream(AVStream* stream)
+{
+ return &stream->codec;
+}
+#endif
+
+static int startffmpeg(struct anim * anim) {
+ int i, videoStream;
+
+ AVCodec *pCodec;
+ AVFormatContext *pFormatCtx;
+ AVCodecContext *pCodecCtx;
+
+ if (anim == 0) return(-1);
+
+ do_init_ffmpeg();
+
+ if(av_open_input_file(&pFormatCtx, anim->name, NULL, 0, NULL)!=0) {
+ return -1;
+ }
+
+ if(av_find_stream_info(pFormatCtx)<0) {
+ av_close_input_file(pFormatCtx);
+ return -1;
+ }
+
+ dump_format(pFormatCtx, 0, anim->name, 0);
+
+
+ /* Find the first video stream */
+ videoStream=-1;
+ for(i=0; i<pFormatCtx->nb_streams; i++)
+ if(get_codec_from_stream(pFormatCtx->streams[i])->codec_type
+ == CODEC_TYPE_VIDEO) {
+ videoStream=i;
+ break;
+ }
+
+ if(videoStream==-1) {
+ av_close_input_file(pFormatCtx);
+ return -1;
+ }
+
+ pCodecCtx = get_codec_from_stream(pFormatCtx->streams[videoStream]);
+
+ /* Find the decoder for the video stream */
+ pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
+ if(pCodec==NULL) {
+ av_close_input_file(pFormatCtx);
+ return -1;
+ }
+
+ pCodecCtx->workaround_bugs = 1;
+
+ if(avcodec_open(pCodecCtx, pCodec)<0) {
+ av_close_input_file(pFormatCtx);
+ return -1;
+ }
+
+#ifdef FFMPEG_OLD_FRAME_RATE
+ if(pCodecCtx->frame_rate>1000 && pCodecCtx->frame_rate_base==1)
+ pCodecCtx->frame_rate_base=1000;
+
+
+ anim->duration = pFormatCtx->duration * pCodecCtx->frame_rate
+ / pCodecCtx->frame_rate_base / AV_TIME_BASE;
+#else
+ anim->duration = pFormatCtx->duration
+ * av_q2d(pFormatCtx->streams[videoStream]->r_frame_rate)
+ / AV_TIME_BASE;
+
+#endif
+ anim->params = 0;
+
+ anim->x = pCodecCtx->width;
+ anim->y = pCodecCtx->height;
+ anim->interlacing = 0;
+ anim->orientation = 0;
+ anim->framesize = anim->x * anim->y * 4;
+
+ anim->curposition = -1;
+
+ anim->pFormatCtx = pFormatCtx;
+ anim->pCodecCtx = pCodecCtx;
+ anim->pCodec = pCodec;
+ anim->videoStream = videoStream;
+
+ anim->pFrame = avcodec_alloc_frame();
+ anim->pFrameRGB = avcodec_alloc_frame();
+
+ if (avpicture_get_size(PIX_FMT_RGBA32, anim->x, anim->y)
+ != anim->x * anim->y * 4) {
+ fprintf (stderr,
+ "ffmpeg has changed alloc scheme ... ARGHHH!\n");
+ avcodec_close(anim->pCodecCtx);
+ av_close_input_file(anim->pFormatCtx);
+ av_free(anim->pFrameRGB);
+ av_free(anim->pFrame);
+ return -1;
+ }
+
+ if (pCodecCtx->has_b_frames) {
+ anim->preseek = 25; /* FIXME: detect gopsize ... */
+ } else {
+ anim->preseek = 0;
+ }
+
+ anim->img_convert_ctx = sws_getContext(
+ anim->pCodecCtx->width,
+ anim->pCodecCtx->height,
+ anim->pCodecCtx->pix_fmt,
+ anim->pCodecCtx->width,
+ anim->pCodecCtx->height,
+ PIX_FMT_RGBA,
+ SWS_FAST_BILINEAR | SWS_PRINT_INFO,
+ NULL, NULL, NULL);
+
+ return (0);
+}
+
+static ImBuf * ffmpeg_fetchibuf(struct anim * anim, int position) {
+ ImBuf * ibuf;
+ int frameFinished;
+ AVPacket packet;
+ int64_t pts_to_search = 0;
+ int pos_found = 1;
+
+ if (anim == 0) return (0);
+
+ ibuf = IMB_allocImBuf(anim->x, anim->y, 24, IB_rect, 0);
+
+ avpicture_fill((AVPicture *)anim->pFrameRGB,
+ (unsigned char*) ibuf->rect,
+ PIX_FMT_RGBA32, anim->x, anim->y);
+
+ if (position != anim->curposition + 1) {
+ if (position > anim->curposition + 1
+ && anim->preseek
+ && position - (anim->curposition + 1) < anim->preseek) {
+ while(av_read_frame(anim->pFormatCtx, &packet)>=0) {
+ if (packet.stream_index == anim->videoStream) {
+ avcodec_decode_video(
+ anim->pCodecCtx,
+ anim->pFrame, &frameFinished,
+ packet.data, packet.size);
+
+ if (frameFinished) {
+ anim->curposition++;
+ }
+ }
+ av_free_packet(&packet);
+ if (position == anim->curposition+1) {
+ break;
+ }
+ }
+ }
+ }
+
+ if (position != anim->curposition + 1) {
+#ifdef FFMPEG_OLD_FRAME_RATE
+ double frame_rate =
+ (double) anim->pCodecCtx->frame_rate
+ / (double) anim->pCodecCtx->frame_rate_base;
+#else
+ double frame_rate =
+ av_q2d(anim->pFormatCtx->streams[anim->videoStream]
+ ->r_frame_rate);
+#endif
+ double time_base =
+ av_q2d(anim->pFormatCtx->streams[anim->videoStream]
+ ->time_base);
+ long long pos = (long long) (position - anim->preseek)
+ * AV_TIME_BASE / frame_rate;
+ long long st_time = anim->pFormatCtx
+ ->streams[anim->videoStream]->start_time;
+
+ if (pos < 0) {
+ pos = 0;
+ }
+
+ if (st_time != AV_NOPTS_VALUE) {
+ pos += st_time * AV_TIME_BASE * time_base;
+ }
+
+ av_seek_frame(anim->pFormatCtx, -1,
+ pos, AVSEEK_FLAG_BACKWARD);
+
+ pts_to_search = (long long)
+ (((double) position) / time_base / frame_rate);
+ if (st_time != AV_NOPTS_VALUE) {
+ pts_to_search += st_time;
+ }
+
+ pos_found = 0;
+ avcodec_flush_buffers(anim->pCodecCtx);
+ }
+
+ while(av_read_frame(anim->pFormatCtx, &packet)>=0) {
+ if(packet.stream_index == anim->videoStream) {
+ avcodec_decode_video(anim->pCodecCtx,
+ anim->pFrame, &frameFinished,
+ packet.data, packet.size);
+
+ if (frameFinished && !pos_found) {
+ if (packet.dts >= pts_to_search) {
+ pos_found = 1;
+ }
+ }
+
+ if(frameFinished && pos_found == 1) {
+ int * dstStride = anim->pFrameRGB->linesize;
+ uint8_t** dst = anim->pFrameRGB->data;
+ int dstStride2[4]= { -dstStride[0], 0, 0, 0 };
+ uint8_t* dst2[4]= {
+ dst[0] + (anim->y - 1)*dstStride[0],
+ 0, 0, 0 };
+
+ sws_scale(anim->img_convert_ctx,
+ anim->pFrame->data,
+ anim->pFrame->linesize,
+ 0,
+ anim->pCodecCtx->height,
+ dst2,
+ dstStride2);
+
+ av_free_packet(&packet);
+ break;
+ }
+ }
+
+ av_free_packet(&packet);
+ }
+
+ return(ibuf);
+}
+
+static void free_anim_ffmpeg(struct anim * anim) {
+ if (anim == NULL) return;
+
+ if (anim->pCodecCtx) {
+ avcodec_close(anim->pCodecCtx);
+ av_close_input_file(anim->pFormatCtx);
+ av_free(anim->pFrameRGB);
+ av_free(anim->pFrame);
+ sws_freeContext(anim->img_convert_ctx);
+ }
+ anim->duration = 0;
+}
+
+#endif
+
+
+/* probeer volgende plaatje te lezen */
+/* Geen plaatje, probeer dan volgende animatie te openen */
+/* gelukt, haal dan eerste plaatje van animatie */
+
+static struct ImBuf * anim_getnew(struct anim * anim) {
+ struct ImBuf *ibuf = 0;
+
+ if (anim == NULL) return(0);
+
+ free_anim_anim5(anim);
+ free_anim_movie(anim);
+ free_anim_avi(anim);
+#ifdef WITH_QUICKTIME
+ free_anim_quicktime(anim);
+#endif
+#ifdef WITH_FFMPEG
+ free_anim_ffmpeg(anim);
+#endif
+
+ if (anim->curtype != 0) return (0);
+ anim->curtype = imb_get_anim_type(anim->name);
+
+ switch (anim->curtype) {
+ case ANIM_ANIM5:
+ if (startanim5(anim)) return (0);
+ ibuf = anim5_fetchibuf(anim);
+ break;
+ case ANIM_SEQUENCE:
+ ibuf = IMB_loadiffname(anim->name, anim->ib_flags);
+ if (ibuf) {
+ strcpy(anim->first, anim->name);
+ anim->duration = 1;
+ }
+ break;
+ case ANIM_MOVIE:
+ if (startmovie(anim)) return (0);
+ ibuf = IMB_allocImBuf (anim->x, anim->y, 24, 0, 0); /* fake */
+ break;
+ case ANIM_AVI:
+ if (startavi(anim)) {
+ printf("couldnt start avi\n");
+ return (0);
+ }
+ ibuf = IMB_allocImBuf (anim->x, anim->y, 24, 0, 0);
+ break;
+#ifdef WITH_QUICKTIME
+ case ANIM_QTIME:
+ if (startquicktime(anim)) return (0);
+ ibuf = IMB_allocImBuf (anim->x, anim->y, 24, 0, 0);
+ break;
+#endif
+#ifdef WITH_FFMPEG
+ case ANIM_FFMPEG:
+ if (startffmpeg(anim)) return (0);
+ ibuf = IMB_allocImBuf (anim->x, anim->y, 24, 0, 0);
+ break;
+#endif
+ }
+
+ return(ibuf);
+}
+
+struct ImBuf * IMB_anim_previewframe(struct anim * anim) {
+ struct ImBuf * ibuf = 0;
+ int position = 0;
+
+ ibuf = IMB_anim_absolute(anim, 0);
+ if (ibuf) {
+ IMB_freeImBuf(ibuf);
+ position = anim->duration / 2;
+ ibuf = IMB_anim_absolute(anim, position);
+ }
+ return ibuf;
+}
+
+struct ImBuf * IMB_anim_absolute(struct anim * anim, int position) {
+ struct ImBuf * ibuf = 0;
+ char head[256], tail[256];
+ unsigned short digits;
+ int pic;
+
+ if (anim == NULL) return(0);
+
+ if (anim->curtype == 0) {
+ ibuf = anim_getnew(anim);
+ if (ibuf == NULL) {
+ return (0);
+ }
+ IMB_freeImBuf(ibuf); /* ???? */
+ }
+
+ if (position < 0) return(0);
+ if (position >= anim->duration) return(0);
+
+ switch(anim->curtype) {
+ case ANIM_ANIM5:
+ if (anim->curposition > position) rewindanim5(anim);
+ while (anim->curposition < position) {
+ if (nextanim5(anim)) return (0);
+ }
+ ibuf = anim5_fetchibuf(anim);
+ break;
+ case ANIM_SEQUENCE:
+ pic = an_stringdec(anim->first, head, tail, &digits);
+ pic += position;
+ an_stringenc(anim->name, head, tail, digits, pic);
+ ibuf = IMB_loadiffname(anim->name, LI_rect);
+ if (ibuf) {
+ anim->curposition = position;
+ /* patch... by freeing the cmap you prevent a double apply cmap... */
+ /* probably the IB_CMAP option isn't working proper
+ * after the abgr->rgba reconstruction
+ */
+ IMB_freecmapImBuf(ibuf);
+ }
+ break;
+ case ANIM_MOVIE:
+ ibuf = movie_fetchibuf(anim, position);
+ if (ibuf) {
+ anim->curposition = position;
+ IMB_convert_rgba_to_abgr(ibuf);
+ }
+ break;
+ case ANIM_AVI:
+ ibuf = avi_fetchibuf(anim, position);
+ if (ibuf) anim->curposition = position;
+ break;
+#ifdef WITH_QUICKTIME
+ case ANIM_QTIME:
+ ibuf = qtime_fetchibuf(anim, position);
+ if (ibuf) anim->curposition = position;
+ break;
+#endif
+#ifdef WITH_FFMPEG
+ case ANIM_FFMPEG:
+ ibuf = ffmpeg_fetchibuf(anim, position);
+ if (ibuf) anim->curposition = position;
+ break;
+#endif
+ }
+
+ if (ibuf) {
+ if (anim->ib_flags & IB_ttob) IMB_flipy(ibuf);
+ sprintf(ibuf->name, "%s.%04d", anim->name, anim->curposition + 1);
+
+ }
+ return(ibuf);
+}
+
+struct ImBuf * IMB_anim_nextpic(struct anim * anim) {
+ struct ImBuf * ibuf = 0;
+
+ if (anim == 0) return(0);
+
+ ibuf = IMB_anim_absolute(anim, anim->curposition + 1);
+
+ return(ibuf);
+}
+
+/***/
+
+int IMB_anim_get_duration(struct anim *anim) {
+ return anim->duration;
+}
+
+void IMB_anim_set_preseek(struct anim * anim, int preseek)
+{
+ anim->preseek = preseek;
+}
+
+int IMB_anim_get_preseek(struct anim * anim)
+{
+ return anim->preseek;
+}
diff --git a/source/blender/imbuf/intern/anim5.c b/source/blender/imbuf/intern/anim5.c
new file mode 100644
index 00000000000..89ddf177efe
--- /dev/null
+++ b/source/blender/imbuf/intern/anim5.c
@@ -0,0 +1,534 @@
+/**
+ * anim5.c
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): phase, code torn apart from anim.c
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "BLI_blenlib.h" /* BLI_remlink BLI_filesize BLI_addtail
+ BLI_countlist BLI_stringdec */
+#include "imbuf.h"
+#include "imbuf_patch.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "IMB_cmap.h"
+#include "IMB_allocimbuf.h"
+#include "IMB_bitplanes.h"
+#include "IMB_amiga.h"
+
+#include "IMB_anim.h"
+
+#include "IMB_anim5.h"
+
+typedef struct Anhd{
+ unsigned char type, mask;
+ unsigned short w, h;
+ unsigned short x, y;
+ unsigned short abs16, abs, reala6, real;
+ unsigned char interleave, pad0;
+ unsigned short bits16, bits;
+ unsigned char pad[16];
+}Anhd;
+
+typedef struct Anim5Delta {
+ struct Anim5Delta * next, * prev;
+ void * data;
+ int type;
+}Anim5Delta;
+
+
+/* om anim5's te kunnen lezen, moet een aantal gegevens bijgehouden worden:
+ * Een lijst van pointers naar delta's, in geheugen of ge'mmap'ed
+ *
+ * Mogelijk kan er ook een 'skiptab' aangelegd worden, om sneller
+ * sprongen te kunnen maken.
+ *
+ * Er moeten niet direct al plaatjes gegenereed worden, dit maakt de
+ * routines onbruikbaar om snel naar het goede plaatje te springen.
+ * Een routine voert dus de delta's uit, een andere routine maakt van
+ * voorgrondplaatje een ibuf;
+ */
+
+
+/*
+ een aantal functie pointers moet geinporteerd worden, zodat er niet
+ nog meer library's / objects meegelinkt hoeven te worden.
+
+ Dezelfde structuur moet ook gebruikt kunnen worden voor het wegschrijven
+ van animaties. Hoe geef je dit aan ?
+
+ Hoe snel kunnen 10 .dlta's gedecomprimeerd worden
+ (zonder omzetten naar rect).
+
+ 1 - zoek naar 1e plaatje, animatie die aan de eisen voldoet
+ 2 - probeer volgende plaatje te vinden:
+ anim5 - decomprimeer
+ sequence - teller ophogen
+ directory - volgende entry
+ 3 - geen succes ? ga naar 1.
+
+
+*/
+
+/*
+ 1. Initialiseer routine met toegestane reeksen, en eerste naam
+ - series op naam (.0001)
+ - directories
+ - anim5 animaties
+ - TGA delta's
+ - iff 24bits delta's (.delta)
+
+ 2. haal volgende (vorige ?) plaatje op.
+
+ 3. vrijgeven
+*/
+
+/* selectie volgorde is:
+ 1 - anim5()
+ 2 - name
+ 3 - dir
+*/
+
+void free_anim_anim5(struct anim * anim) {
+ ListBase * animbase;
+ Anim5Delta * delta, * next;
+
+ if (anim == NULL) return;
+
+ animbase = &anim->anim5base;
+ delta = animbase->first;
+
+ while (delta) {
+ next = delta->next;
+
+ if (delta->type == ANIM5_MALLOC) free(delta->data);
+ BLI_remlink(animbase, delta);
+ free(delta);
+
+ delta = next;
+ }
+
+ if (anim->anim5mmap && anim->anim5len) {
+ MEM_freeN(anim->anim5mmap);
+ }
+
+ anim->anim5mmap = NULL;
+ anim->anim5len = 0;
+ anim->anim5curdlta = 0;
+ anim->duration = 0;
+}
+
+static void planes_to_rect(struct ImBuf * ibuf, int flags) {
+ if (ibuf == 0) return;
+
+ /* dit komt regelrecht uit de amiga.c */
+
+ if (flags & IB_rect && ibuf->rect == 0) {
+ imb_addrectImBuf(ibuf);
+ imb_bptolong(ibuf);
+ IMB_flipy(ibuf);
+ imb_freeplanesImBuf(ibuf);
+
+ if (ibuf->cmap){
+ if ((flags & IB_cmap) == 0) {
+ IMB_applycmap(ibuf);
+ IMB_convert_rgba_to_abgr(ibuf);
+ }
+ } else if (ibuf->depth == 18){
+ int i,col;
+ unsigned int *rect;
+
+ rect = ibuf->rect;
+ for(i=ibuf->x * ibuf->y ; i>0 ; i--){
+ col = *rect;
+ col = ((col & 0x3f000) << 6) + ((col & 0xfc0) << 4)
+ + ((col & 0x3f) << 2);
+ col += (col & 0xc0c0c0) >> 6;
+ *rect++ = col;
+ }
+ ibuf->depth = 24;
+ } else if (ibuf->depth <= 8) {
+ /* geen colormap en geen 24 bits: zwartwit */
+ uchar *rect;
+ int size, shift;
+
+ if (ibuf->depth < 8){
+ rect = (uchar *) ibuf->rect;
+ rect += 3;
+ shift = 8 - ibuf->depth;
+ for (size = ibuf->x * ibuf->y; size > 0; size --){
+ rect[0] <<= shift;
+ rect += 4;
+ }
+ }
+ rect = (uchar *) ibuf->rect;
+ for (size = ibuf->x * ibuf->y; size > 0; size --){
+ rect[1] = rect[2] = rect[3];
+ rect += 4;
+ }
+ ibuf->depth = 8;
+ }
+ }
+}
+
+
+static void anim5decode(struct ImBuf * ibuf, uchar * dlta) {
+ uchar depth;
+ int skip;
+ int *ofspoint;
+ uchar **planes;
+
+ /* samenstelling delta:
+ lijst met ofsets voor delta's per bitplane (ofspoint)
+ per kolom in delta (point)
+ aantal handelingen (noops)
+ code
+ bijbehorende data
+ ...
+ ...
+ */
+
+ dlta += 8;
+
+ ofspoint = (int *)dlta;
+ skip = ibuf->skipx * sizeof(int *);
+ planes = (uchar **)ibuf->planes;
+
+ for(depth=ibuf->depth ; depth>0 ; depth--){
+ if (GET_BIG_LONG(ofspoint)){
+ uchar *planestart;
+ uchar *point;
+ uchar x;
+
+ point = dlta + GET_BIG_LONG(ofspoint);
+ planestart = planes[0];
+ x = (ibuf->x + 7) >> 3;
+
+ do{
+ uchar noop;
+
+ if ( (noop = *(point++)) ){
+ uchar *plane;
+ uchar code;
+
+ plane = planestart;
+ do{
+ if ((code = *(point++))==0){
+ uchar val;
+
+ code = *(point++);
+ val = *(point++);
+ do {
+ plane[0] = val;
+ plane += skip;
+ } while(--code);
+
+ } else if (code & 128){
+
+ code &= 0x7f;
+ do{
+ plane[0] = *(point++);
+ plane += skip;
+ } while(--code);
+
+ } else plane += code * skip;
+
+ } while(--noop);
+ }
+ planestart++;
+ } while(--x);
+ }
+ ofspoint++;
+ planes++;
+ }
+}
+
+
+static void anim5xordecode(struct ImBuf * ibuf, uchar * dlta) {
+ uchar depth;
+ int skip;
+ int *ofspoint;
+ uchar **planes;
+
+ /* samenstelling delta:
+ lijst met ofsets voor delta's per bitplane (ofspoint)
+ per kolom in delta (point)
+ aantal handelingen (noops)
+ code
+ bijbehorende data
+ ...
+ ...
+ */
+
+ dlta += 8;
+
+ ofspoint = (int *)dlta;
+ skip = ibuf->skipx * sizeof(int *);
+ planes = (uchar **)ibuf->planes;
+
+ for(depth=ibuf->depth ; depth>0 ; depth--){
+
+ if (GET_BIG_LONG(ofspoint)){
+ uchar *planestart;
+ uchar *point;
+ uchar x;
+
+ point = dlta + GET_BIG_LONG(ofspoint);
+ planestart = planes[0];
+ x = (ibuf->x + 7) >> 3;
+
+ do{
+ uchar noop;
+
+ if ( (noop = *(point++)) ){
+ uchar *plane;
+ uchar code;
+
+ plane = planestart;
+ do{
+ if ((code = *(point++))==0){
+ uchar val;
+
+ code = *(point++);
+ val = *(point++);
+ do{
+ plane[0] ^= val;
+ plane += skip;
+ }while(--code);
+
+ } else if (code & 128){
+
+ code &= 0x7f;
+ do{
+ plane[0] ^= *(point++);
+ plane += skip;
+ }while(--code);
+
+ } else plane += code * skip;
+
+ }while(--noop);
+ }
+ planestart++;
+ }while(--x);
+ }
+ ofspoint++;
+ planes++;
+ }
+}
+
+
+int nextanim5(struct anim * anim) {
+ Anim5Delta * delta;
+ struct ImBuf * ibuf;
+
+ if (anim == 0) return(-1);
+
+ delta = anim->anim5curdlta;
+
+ if (delta == 0) return (-1);
+
+ if (anim->anim5flags & ANIM5_SNGBUF) {
+ ibuf = anim->ibuf1;
+ if (ibuf == 0) return (0);
+ anim->anim5decode(ibuf, delta->data);
+ } else {
+ ibuf = anim->ibuf2;
+ if (ibuf == 0) return (0);
+ anim->anim5decode(ibuf, delta->data);
+ anim->ibuf2 = anim->ibuf1;
+ anim->ibuf1 = ibuf;
+ }
+
+ anim->anim5curdlta = anim->anim5curdlta->next;
+ anim->curposition++;
+
+ return(0);
+}
+
+int rewindanim5(struct anim * anim) {
+ Anim5Delta * delta;
+ struct ImBuf * ibuf;
+
+ if (anim == 0) return (-1);
+
+ IMB_free_anim_ibuf(anim);
+
+ delta = anim->anim5base.first;
+ if (delta == 0) return (-1);
+
+ ibuf = IMB_loadiffmem(delta->data, IB_planes);
+ if (ibuf == 0) return(-1);
+
+ anim->ibuf1 = ibuf;
+ if ((anim->anim5flags & ANIM5_SNGBUF) == 0) anim->ibuf2 = IMB_dupImBuf(ibuf);
+
+ anim->anim5curdlta = delta->next;
+ anim->curposition = 0;
+
+ return(0);
+}
+
+
+int startanim5(struct anim * anim) {
+ int file, buf[20], totlen;
+ unsigned int len;
+ short * mem;
+ ListBase * animbase;
+ Anim5Delta * delta;
+ Anhd anhd;
+
+ /* Controles */
+
+ if (anim == 0) return(-1);
+
+ file = open(anim->name,O_BINARY|O_RDONLY);
+ if (file < 0) return (-1);
+
+ if (read(file, buf, 24) != 24) {
+ close(file);
+ return(-1);
+ }
+
+ if ((GET_ID(buf) != FORM) || (GET_ID(buf + 2) != ANIM)
+ || (GET_ID(buf + 3) != FORM) || (GET_ID(buf + 5) != ILBM)){
+ printf("No anim5 file %s\n",anim->name);
+ close(file);
+ return (-1);
+ }
+
+ /* de hele file wordt in het geheugen gemapped */
+
+ totlen = BLI_filesize(file);
+ if (totlen && file>=0) {
+ lseek(file, 0L, SEEK_SET);
+
+ mem= MEM_mallocN(totlen, "mmap");
+ if (read(file, mem, totlen) != totlen) {
+ MEM_freeN(mem);
+ mem = NULL;
+ }
+ } else {
+ mem = NULL;
+ }
+ close (file);
+
+ if (!mem) return (-1);
+
+ anhd.interleave = 0;
+ anhd.bits = 0;
+ anhd.type = 5;
+
+ anim->anim5mmap = mem;
+ anim->anim5len = totlen;
+ anim->anim5flags = 0;
+ anim->duration = 0;
+
+ animbase = & anim->anim5base;
+ animbase->first = animbase->last = 0;
+
+ /* eerste plaatje inlezen */
+
+ mem = mem + 6;
+ totlen -= 12;
+
+ len = GET_BIG_LONG(mem + 2);
+ len = (len + 8 + 1) & ~1;
+ delta = NEW(Anim5Delta);
+
+ delta->data = mem;
+ delta->type = ANIM5_MMAP;
+
+ BLI_addtail(animbase, delta);
+
+ mem += (len >> 1);
+ totlen -= len;
+
+ while (totlen > 0) {
+ len = GET_BIG_LONG(mem + 2);
+ len = (len + 8 + 1) & ~1;
+
+ switch(GET_ID(mem)){
+ case FORM:
+ len = 12;
+ break;
+ case ANHD:
+ memcpy(&anhd, mem + 4, sizeof(Anhd));
+ break;
+ case DLTA:
+ delta = NEW(Anim5Delta);
+ delta->data = mem;
+ delta->type = ANIM5_MMAP;
+ BLI_addtail(animbase, delta);
+ break;
+ }
+
+ mem += (len >> 1);
+ totlen -= len;
+ }
+
+ if (anhd.interleave == 1) anim->anim5flags |= ANIM5_SNGBUF;
+ if (BIG_SHORT(anhd.bits) & 2) anim->anim5decode = anim5xordecode;
+ else anim->anim5decode = anim5decode;
+
+ /* laatste twee delta's wissen */
+
+ delta = animbase->last;
+ if (delta) {
+ BLI_remlink(animbase, delta);
+ free(delta);
+ }
+
+ if ((anim->anim5flags & ANIM5_SNGBUF) == 0) {
+ delta = animbase->last;
+ if (delta) {
+ BLI_remlink(animbase, delta);
+ free(delta);
+ }
+ }
+
+ anim->duration = BLI_countlist(animbase);
+
+ return(rewindanim5(anim));
+}
+
+
+struct ImBuf * anim5_fetchibuf(struct anim * anim) {
+ struct ImBuf * ibuf;
+
+ if (anim == 0) return (0);
+
+ ibuf = IMB_dupImBuf(anim->ibuf1);
+ planes_to_rect(ibuf, anim->ib_flags);
+
+ return(ibuf);
+}
+
diff --git a/source/blender/imbuf/intern/antialias.c b/source/blender/imbuf/intern/antialias.c
new file mode 100644
index 00000000000..bf8d0d17daf
--- /dev/null
+++ b/source/blender/imbuf/intern/antialias.c
@@ -0,0 +1,469 @@
+/**
+ * antialias.c
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "imbuf.h"
+
+#include "BLI_blenlib.h"
+#include "DNA_listBase.h"
+
+#include "imbuf_patch.h"
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+#include "IMB_allocimbuf.h"
+
+/* how it works:
+
+1 - seek for a transistion in a collumn
+2 - check the relationship with left and right,
+
+Is pixel above transition to the left or right equal to the top color, seek down
+
+Is pixel below transition to the left or right equal to the bottom color, seek up
+
+*/
+
+/* there should be a funcion * to indicate if two colors are
+ * equal or not.
+ * For now we use a define
+ */
+
+
+static unsigned int anti_mask = 0xffffffff;
+static int anti_a, anti_b, anti_g, anti_r;
+
+#define compare(x, y) ((x ^ y) & anti_mask)
+
+typedef struct Edge
+{
+ struct Edge * next, * prev;
+ short position;
+ int col1, col2;
+}Edge;
+
+static void anti_free_listarray(int count, ListBase * listarray)
+{
+ int i;
+
+ if (listarray == 0) return;
+
+ for (i = 0; i < count; i++) BLI_freelistN(listarray + i);
+ MEM_freeN(listarray);
+}
+
+static ListBase * scanimage(struct ImBuf * ibuf, int dir)
+{
+ int step, pixels, lines, nextline, x, y, col1, col2;
+ unsigned int * rect;
+ ListBase * listarray, * curlist;
+ Edge * edge;
+ int count;
+
+ switch (dir) {
+ case 'h':
+ step = 1; nextline = ibuf->x;
+ pixels = ibuf->x; lines = ibuf->y;
+ break;
+/* case 'v': changed so assured values for step etc.. */
+ default:
+ step = ibuf->x; nextline = 1;
+ pixels = ibuf->y; lines = ibuf->x;
+ }
+
+ listarray = (ListBase*)MEM_callocN((lines)* sizeof(ListBase), "listarray");
+ for (y = 0; y < lines; y++){
+ rect = ibuf->rect;
+ rect += y * nextline;
+ curlist = listarray + y;
+
+ col1 = rect[0];
+ count = 0;
+
+ for (x = 0; x < pixels; x++) {
+ col2 = rect[0];
+ if (compare(col1, col2)) {
+ edge = NEW(Edge);
+
+ if (edge == NULL) return(0);
+
+ edge->position = x;
+ edge->col1 = col1;
+ edge->col2 = col2;
+ BLI_addtail(curlist, edge);
+ col1 = col2;
+ count++;
+ if (count > 100) {
+ printf("\n\n%s: Aborting antialias !\n", ibuf->name);
+ printf("To many transitions.\nIs this a natural image ?\n\n"),
+ anti_free_listarray(lines, listarray);
+ return(0);
+ }
+ }
+ rect += step;
+ }
+ }
+
+ return(listarray);
+}
+
+
+static Edge * findmatch(Edge * first, Edge * edge)
+{
+ Edge * match = 0;
+ int in = 0, out = 65535;
+
+ if (edge->prev) in = edge->prev->position;
+ if (edge->next) out = edge->next->position;
+
+ while (first) {
+ if (first->position < edge->position) {
+ if (first->col1 == edge->col1) {
+ if (first->position >= in) match = first;
+ } else if (first->col2 == edge->col2) {
+ if (first->next == 0) match = first;
+ else if (first->next->position >= edge->position) match = first;
+ } else if (first->col2 == edge->col1) {
+ match = 0; /* at 'sig saw' situations this one can be wrongly set */
+ }
+ } else if (first->position == edge->position) {
+ if (first->col1 == edge->col1 || first->col2 == edge->col2) match = first;
+ } else {
+ if (match) break; /* there is one */
+
+ if (first->col1 == edge->col1) {
+ if (first->prev == 0) match = first;
+ else if (first->prev->position <= edge->position) match = first;
+ } else if (first->col2 == edge->col2) {
+ if (first->position <= out) match = first;
+ }
+ }
+
+ first = first->next;
+ }
+
+ return(match);
+}
+
+
+static void filterdraw(unsigned int * ldest, unsigned int * lsrce, int zero, int half, int step)
+{
+ uchar * src, * dst;
+ int count;
+ double weight, add;
+
+ /* we filter the pixels at ldest between in and out with pixels from lsrce
+ * weight values go from 0 to 1
+ */
+
+
+ count = half - zero;
+ if (count < 0) count = -count;
+ if (count <= 1) return;
+
+ if (zero < half) {
+ src = (uchar *) (lsrce + (step * zero));
+ dst = (uchar *) (ldest + (step * zero));
+ } else {
+ zero--;
+ src = (uchar *) (lsrce + (step * zero));
+ dst = (uchar *) (ldest + (step * zero));
+ step = -step;
+ }
+
+ step = 4 * step;
+
+ dst += step * (count >> 1);
+ src += step * (count >> 1);
+
+ count = (count + 1) >> 1;
+ add = 0.5 / count;
+ weight = 0.5 * add;
+
+ /* this of course gamma corrected */
+
+ for(; count > 0; count --) {
+ if (anti_a) dst[0] += weight * (src[0] - dst[0]);
+ if (anti_b) dst[1] += weight * (src[1] - dst[1]);
+ if (anti_g) dst[2] += weight * (src[2] - dst[2]);
+ if (anti_r) dst[3] += weight * (src[3] - dst[3]);
+ dst += step;
+ src += step;
+ weight += add;
+ }
+}
+
+static void filterimage(struct ImBuf * ibuf, struct ImBuf * cbuf, ListBase * listarray, int dir)
+{
+ int step, pixels, lines, nextline, y, pos, drawboth;
+ unsigned int * irect, * crect;
+ Edge * left, * middle, * right, temp, * any;
+
+ switch (dir) {
+ case 'h':
+ step = 1; nextline = ibuf->x;
+ pixels = ibuf->x; lines = ibuf->y;
+ break;
+/* case 'v': changed so have values */
+ default:
+ step = ibuf->x; nextline = 1;
+ pixels = ibuf->y; lines = ibuf->x;
+ }
+
+ for (y = 1; y < lines - 1; y++){
+ irect = ibuf->rect;
+ irect += y * nextline;
+ crect = cbuf->rect;
+ crect += y * nextline;
+
+ middle = listarray[y].first;
+ while (middle) {
+ left = findmatch(listarray[y - 1].first, middle);
+ right = findmatch(listarray[y + 1].first, middle);
+ drawboth = FALSE;
+
+ if (left == 0 || right == 0) {
+ /* edge */
+ any = left;
+ if (right) any = right;
+ if (any) {
+ /* mirroring */
+ pos = 2 * middle->position - any->position;
+
+ if (any->position < middle->position) {
+ if (pos > pixels - 1) pos = pixels - 1;
+ if (middle->next) {
+ if (pos > middle->next->position) pos = middle->next->position;
+ }
+/* if (any->next) {
+ if (pos > any->next->position) pos = any->next->position;
+ }
+*/ } else {
+ if (pos < 0) pos = 0;
+ if (middle->prev) {
+ if (pos < middle->prev->position) pos = middle->prev->position;
+ }
+/* if (any->prev) {
+ if (pos < any->prev->position) pos = any->prev->position;
+ }
+*/ }
+ temp.position = pos;
+ if (left) right = &temp;
+ else left = &temp;
+ drawboth = TRUE;
+ }
+ } else if (left->position == middle->position || right->position == middle->position) {
+ /* straight piece */
+ /* small corner, with one of the two at distance 2 (the other is at dist 0) ? */
+
+ if (abs(left->position - right->position) == 2) drawboth = TRUE;
+ } else if (left->position < middle->position && right->position > middle->position){
+ /* stair 1 */
+ drawboth = TRUE;
+ } else if (left->position > middle->position && right->position < middle->position){
+ /* stair 2 */
+ drawboth = TRUE;
+ } else {
+ /* a peek */
+ drawboth = TRUE;
+ }
+
+ if (drawboth) {
+ filterdraw(irect, crect - nextline, left->position, middle->position, step);
+ filterdraw(irect, crect + nextline, right->position, middle->position, step);
+ }
+
+ middle = middle->next;
+ }
+ }
+}
+
+
+void IMB_antialias(struct ImBuf * ibuf)
+{
+ struct ImBuf * cbuf;
+ ListBase * listarray;
+
+ if (ibuf == 0) return;
+ cbuf = IMB_dupImBuf(ibuf);
+ if (cbuf == 0) return;
+
+ anti_a = (anti_mask >> 24) & 0xff;
+ anti_b = (anti_mask >> 16) & 0xff;
+ anti_g = (anti_mask >> 8) & 0xff;
+ anti_r = (anti_mask >> 0) & 0xff;
+
+ listarray = scanimage(cbuf, 'h');
+ if (listarray) {
+ filterimage(ibuf, cbuf, listarray, 'h');
+ anti_free_listarray(ibuf->y, listarray);
+
+ listarray = scanimage(cbuf, 'v');
+ if (listarray) {
+ filterimage(ibuf, cbuf, listarray, 'v');
+ anti_free_listarray(ibuf->x, listarray);
+ }
+ }
+
+ IMB_freeImBuf(cbuf);
+}
+
+
+/* intelligent scaling */
+
+static void _intel_scale(struct ImBuf * ibuf, ListBase * listarray, int dir)
+{
+ int step, lines, nextline, x, y, col;
+ unsigned int * irect, * trect;
+ int start, end;
+ Edge * left, * right;
+ struct ImBuf * tbuf;
+
+ switch (dir) {
+ case 'h':
+ step = 1; nextline = ibuf->x;
+ lines = ibuf->y;
+ tbuf = IMB_double_fast_y(ibuf);
+ break;
+ case 'v':
+ step = 2 * ibuf->x; nextline = 1;
+ lines = ibuf->x;
+ tbuf = IMB_double_fast_x(ibuf);
+ break;
+ default:
+ return;
+ }
+
+ if (tbuf == NULL) return;
+
+ imb_freerectImBuf(ibuf);
+
+ ibuf->rect = tbuf->rect;
+ ibuf->mall |= IB_rect;
+
+ ibuf->x = tbuf->x;
+ ibuf->y = tbuf->y;
+ tbuf->rect = 0;
+ IMB_freeImBuf(tbuf);
+
+ for (y = 0; y < lines - 2; y++){
+ irect = ibuf->rect;
+ irect += ((2 * y) + 1) * nextline;
+
+ left = listarray[y].first;
+ while (left) {
+ right = findmatch(listarray[y + 1].first, left);
+ if (right) {
+ if (left->col2 == right->col2) {
+ if (left->next && right->next) {
+ if (left->next->position >= right->position) {
+ start = ((left->position + right->position) >> 1);
+ end = ((left->next->position + right->next->position) >> 1);
+ col = left->col2;
+ trect = irect + (start * step);
+ for (x = start; x < end; x++) {
+ *trect = col;
+ trect += step;
+ }
+ }
+ }
+ }
+
+ if (left->col1 == right->col1) {
+ if (left->prev && right->prev) {
+ if (left->prev->position <= right->position) {
+ end = ((left->position + right->position) >> 1);
+ start = ((left->prev->position + right->prev->position) >> 1);
+ col = left->col1;
+ trect = irect + (start * step);
+ for (x = start; x < end; x++) {
+ *trect = col;
+ trect += step;
+ }
+ }
+ }
+ }
+
+ }
+ left = left->next;
+ }
+ }
+}
+
+
+void IMB_clever_double(struct ImBuf * ibuf)
+{
+ ListBase * listarray, * curlist;
+ Edge * new;
+ int size;
+ int i;
+
+ if (ibuf == 0) return;
+
+ size = ibuf->x;
+ listarray = scanimage(ibuf, 'v');
+ if (listarray) {
+ for (i = 0; i < size; i++) {
+ curlist = listarray + i;
+ new = (Edge*)MEM_callocN(sizeof(Edge),"Edge");
+ new->col2 = ibuf->rect[i]; /* upper pixel */
+ new->col1 = new->col2 - 1;
+ BLI_addhead(curlist, new);
+ new = (Edge*)MEM_callocN(sizeof(Edge),"Edge");
+ new->position = ibuf->y - 1;
+ new->col1 = ibuf->rect[i + ((ibuf->y -1) * ibuf->x)]; /* bottom pixel */
+ new->col2 = new->col1 - 1;
+ BLI_addtail(curlist, new);
+ }
+ _intel_scale(ibuf, listarray, 'v');
+ anti_free_listarray(size, listarray);
+
+ size = ibuf->y;
+ listarray = scanimage(ibuf, 'h');
+ if (listarray) {
+ for (i = 0; i < size; i++) {
+ curlist = listarray + i;
+ new = (Edge*)MEM_callocN(sizeof(Edge),"Edge");
+ new->col2 = ibuf->rect[i * ibuf->x]; /* left pixel */
+ new->col1 = new->col2 - 1;
+ BLI_addhead(curlist, new);
+ new = (Edge*)MEM_callocN(sizeof(Edge),"Edge");
+ new->position = ibuf->x - 1;
+ new->col1 = ibuf->rect[((i + 1) * ibuf->x) - 1]; /* right pixel */
+ new->col2 = new->col1 - 1;
+ BLI_addtail(curlist, new);
+ }
+ _intel_scale(ibuf, listarray, 'h');
+ anti_free_listarray(size, listarray);
+ }
+ }
+}
diff --git a/source/blender/imbuf/intern/bitplanes.c b/source/blender/imbuf/intern/bitplanes.c
new file mode 100644
index 00000000000..b80e829da08
--- /dev/null
+++ b/source/blender/imbuf/intern/bitplanes.c
@@ -0,0 +1,359 @@
+/**
+ * bitplanes.c
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "imbuf.h"
+#include "BLI_blenlib.h"
+
+#include "imbuf_patch.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+#include "IMB_allocimbuf.h"
+#include "IMB_bitplanes.h"
+
+unsigned int **imb_copyplanelist(struct ImBuf *ibuf)
+{
+ int nobp,i;
+ unsigned int **listn,**listo;
+
+ nobp=ibuf->depth;
+ listn= malloc(nobp*sizeof(int *)); /* make copy of bitmap */
+ if (listn==0) return (0);
+
+ listo=ibuf->planes;
+ for (i=nobp;i>0;i--){
+ *(listn++) = *(listo++);
+ }
+ listn -= nobp;
+
+ return (listn);
+}
+
+static void bptolscanl(unsigned int *buf, int size, unsigned int **list, int nobp, int offset)
+{
+ /* converts bitplanes to a buffer with ints
+ by 4 dividiable amount of bitplanes,
+ the width of bitplanes is rounded at ints */
+
+ list += nobp;
+
+ for (;nobp>0;)
+ {
+ int todo,i;
+ register int bp1, bp2, bp3, bp4, data;
+ register unsigned int *point;
+ int loffset;
+ /*register unsigned int bp1, bp2, bp3, bp4;*/
+
+ bp1 = bp2 = bp3 = bp4 = todo = 0;
+ point = buf;
+ loffset = offset;
+
+ if (nobp & 1){
+ list -= 1;
+ nobp -= 1;
+ for(i=size;i>0;i--)
+ {
+ if (todo==0)
+ {
+ bp1 = BIG_LONG((list[0])[loffset]);
+ loffset++;
+ todo=32;
+ }
+
+ data = *point;
+ data<<=1;
+
+ if (bp1<0) data+=1;
+ bp1<<=1;
+
+ /* data += (bp1 >> 31);
+ bp1 <<= 1;
+ */
+ *(point++)=data;
+ todo--;
+ }
+ } else if (nobp & 2){
+ list -= 2;
+ nobp -= 2;
+ for(i=size;i>0;i--)
+ {
+ if (todo==0)
+ {
+ bp1 = BIG_LONG((list[0])[loffset]);
+ bp2 = BIG_LONG((list[1])[loffset]);
+ loffset++;
+ todo=32;
+ }
+
+ data = *point;
+ data<<=2;
+
+ if (bp1<0) data+=1;
+ bp1<<=1;
+ if (bp2<0) data+=2;
+ bp2<<=1;
+
+ /* data += (bp1 >> 31) + ((bp2 & 0x80000000) >> 30);
+ bp1 <<= 1; bp2 <<= 1;
+ */
+ *(point++)=data;
+ todo--;
+ }
+ } else{
+ list -= 4;
+ nobp -= 4;
+ for(i=size;i>0;i--)
+ {
+ if (todo==0) {
+ bp1 = BIG_LONG((list[0])[loffset]);
+ bp2 = BIG_LONG((list[1])[loffset]);
+ bp3 = BIG_LONG((list[2])[loffset]);
+ bp4 = BIG_LONG((list[3])[loffset]);
+ loffset++;
+ todo=32;
+ }
+
+ data = *point;
+ data<<=4;
+
+ if (bp1<0) data+=1;
+ bp1<<=1;
+ if (bp2<0) data+=2;
+ bp2<<=1;
+ if (bp3<0) data+=4;
+ bp3<<=1;
+ if (bp4<0) data+=8;
+ bp4<<=1;
+
+ /* data += (bp1 >> 31) \
+ + ((bp2 & 0x80000000) >> 30) \
+ + ((bp3 & 0x80000000) >> 29) \
+ + ((bp4 & 0x80000000) >> 28);
+
+ bp1 <<= 1; bp2 <<= 1;
+ bp3 <<= 1; bp4 <<= 1;
+ */
+
+ *(point++)=data;
+ todo--;
+ }
+ }
+ }
+}
+
+
+void imb_bptolong(struct ImBuf *ibuf)
+{
+ int nobp,i,x;
+ unsigned int *rect,offset;
+ float black[4] = {0.0,0.0,0.0,1.0};
+ float clear[4] = {0.0,0.0,0.0,0.0};
+
+ /* first clear all ints */
+
+ if (ibuf == 0) return;
+ if (ibuf->planes == 0) return;
+ if (ibuf->rect == 0) imb_addrectImBuf(ibuf);
+
+ nobp=ibuf->depth;
+ if (nobp != 32){
+ if (nobp == 24) IMB_rectfill(ibuf, black); /* set alpha */
+ else IMB_rectfill(ibuf, clear);
+ }
+
+ rect= ibuf->rect;
+ x= ibuf->x;
+ offset=0;
+
+ for (i= ibuf->y; i>0; i--){
+ bptolscanl(rect, x, ibuf->planes, nobp, offset);
+ rect += x;
+ offset += ibuf->skipx;
+ }
+}
+
+
+static void ltobpscanl(unsigned int *rect, int x, unsigned int **list, int nobp, int offset)
+{
+ /* converts a buffer with ints to bitplanes. Take care, buffer
+ will be destroyed !*/
+
+ if (nobp != 32)
+ {
+ int *rect2;
+ int todo,j;
+
+ rect2 = (int*)rect;
+
+ todo = 32-nobp;
+ for (j = x;j>0;j--){
+ *(rect2++) <<= todo;
+ }
+ }
+
+ list += nobp;
+ for (;nobp>0;){
+ register int bp1=0, bp2=0, bp3=0, data;
+ register unsigned int *point;
+ int i,todo;
+ int bp4=0,loffset;
+
+ point = rect;
+ todo=32;
+ loffset=offset;
+
+ if (nobp & 1){
+ list -= 1;
+ nobp -= 1;
+
+ for(i=x;i>0;i--){
+ data = *point;
+
+ bp1 <<= 1;
+ if (data<0) bp1 += 1;
+ data <<= 1;
+
+ *(point++) = data;
+
+ todo--;
+ if (todo == 0){
+ (list[0])[loffset] = bp1;
+ loffset++;
+ todo=32;
+ }
+ }
+ if (todo != 32)
+ {
+ bp1 <<= todo;
+ (list[0])[loffset] = bp1;
+ }
+ } else if (nobp & 2){
+ list -= 2;
+ nobp -= 2;
+ for(i=x;i>0;i--){
+ data = *point;
+
+ bp2 <<= 1;
+ if (data<0) bp2 += 1;
+ data <<= 1;
+ bp1 <<= 1;
+ if (data<0) bp1 += 1;
+ data <<= 1;
+
+ *(point++) = data;
+
+ todo--;
+ if (todo == 0){
+ (list[0])[loffset] = bp1;
+ (list[1])[loffset] = bp2;
+ loffset++;
+ todo=32;
+ }
+ }
+ if (todo != 32){
+ bp1 <<= todo;
+ bp2 <<= todo;
+ (list[0])[loffset] = bp1;
+ (list[1])[loffset] = bp2;
+ }
+ } else{
+ list -= 4;
+ nobp -= 4;
+ for(i=x;i>0;i--){
+ data = *point;
+
+ bp4 <<= 1;
+ if (data<0) bp4 += 1;
+ data <<= 1;
+ bp3 <<= 1;
+ if (data<0) bp3 += 1;
+ data <<= 1;
+ bp2 <<= 1;
+ if (data<0) bp2 += 1;
+ data <<= 1;
+ bp1 <<= 1;
+ if (data<0) bp1 += 1;
+ data <<= 1;
+
+ *(point++) = data;
+
+ todo--;
+ if (todo == 0){
+ (list[0])[loffset] = bp1;
+ (list[1])[loffset] = bp2;
+ (list[2])[loffset] = bp3;
+ (list[3])[loffset] = bp4;
+ loffset++;
+ todo=32;
+ }
+ }
+ if (todo != 32){
+ bp1 <<= todo;
+ bp2 <<= todo;
+ bp3 <<= todo;
+ bp4 <<= todo;
+ (list[0])[loffset] = bp1;
+ (list[1])[loffset] = bp2;
+ (list[2])[loffset] = bp3;
+ (list[3])[loffset] = bp4;
+ }
+ }
+ }
+}
+
+
+void imb_longtobp(struct ImBuf *ibuf)
+{
+ /* converts a buffer with ints to bitplanes. Take care, buffer
+ will be destroyed !*/
+
+ int nobp,i,x;
+ unsigned int *rect,offset,*buf;
+ ;
+
+ nobp = ibuf->depth;
+ rect=ibuf->rect;
+ x=ibuf->x;
+ offset=0;
+ if ((buf=malloc(x*sizeof(int)))==0) return;
+
+ for (i=ibuf->y;i>0;i--){
+ memcpy(buf, rect, x*sizeof(int));
+ rect +=x ;
+ ltobpscanl(buf, x, ibuf->planes, nobp, offset);
+ offset += ibuf->skipx;
+ }
+ free(buf);
+}
diff --git a/source/blender/imbuf/intern/bmp.c b/source/blender/imbuf/intern/bmp.c
new file mode 100644
index 00000000000..c14819c8bdf
--- /dev/null
+++ b/source/blender/imbuf/intern/bmp.c
@@ -0,0 +1,248 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "BLI_blenlib.h"
+
+#include "imbuf.h"
+#include "imbuf_patch.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+#include "IMB_allocimbuf.h"
+#include "IMB_cmap.h"
+#include "IMB_bmp.h"
+
+/* some code copied from article on microsoft.com, copied
+ here for enhanced BMP support in the future
+ http://www.microsoft.com/msj/defaultframe.asp?page=/msj/0197/mfcp1/mfcp1.htm&nav=/msj/0197/newnav.htm
+*/
+
+typedef struct BMPINFOHEADER{
+ unsigned int biSize;
+ unsigned int biWidth;
+ unsigned int biHeight;
+ unsigned short biPlanes;
+ unsigned short biBitCount;
+ unsigned int biCompression;
+ unsigned int biSizeImage;
+ unsigned int biXPelsPerMeter;
+ unsigned int biYPelsPerMeter;
+ unsigned int biClrUsed;
+ unsigned int biClrImportant;
+} BMPINFOHEADER;
+
+typedef struct BMPHEADER {
+ unsigned short biType;
+ unsigned int biSize;
+ unsigned short biRes1;
+ unsigned short biRes2;
+ unsigned int biOffBits;
+} BMPHEADER;
+
+#define BMP_FILEHEADER_SIZE 14
+
+static int checkbmp(unsigned char *mem)
+{
+ int ret_val = 0;
+ BMPINFOHEADER bmi;
+ unsigned int u;
+
+ if (mem) {
+ if ((mem[0] == 'B') && (mem[1] == 'M')) {
+ /* skip fileheader */
+ mem += BMP_FILEHEADER_SIZE;
+ } else {
+ }
+
+ /* for systems where an int needs to be 4 bytes aligned */
+ memcpy(&bmi, mem, sizeof(bmi));
+
+ u = LITTLE_LONG(bmi.biSize);
+ /* we only support uncompressed 24 or 32 bits images for now */
+ if (u >= sizeof(BMPINFOHEADER)) {
+ if ((bmi.biCompression == 0) && (bmi.biClrUsed == 0)) {
+ u = LITTLE_SHORT(bmi.biBitCount);
+ if (u >= 16) {
+ ret_val = 1;
+ }
+ }
+ }
+ }
+
+ return(ret_val);
+}
+
+int imb_is_a_bmp(void *buf) {
+
+ return checkbmp(buf);
+}
+
+struct ImBuf *imb_bmp_decode(unsigned char *mem, int size, int flags)
+{
+ struct ImBuf *ibuf = 0;
+ BMPINFOHEADER bmi;
+ int x, y, depth, skip, i;
+ unsigned char *bmp, *rect;
+ unsigned short col;
+
+ if (checkbmp(mem) == 0) return(0);
+
+ if ((mem[0] == 'B') && (mem[1] == 'M')) {
+ /* skip fileheader */
+ mem += BMP_FILEHEADER_SIZE;
+ }
+
+ /* for systems where an int needs to be 4 bytes aligned */
+ memcpy(&bmi, mem, sizeof(bmi));
+
+ skip = LITTLE_LONG(bmi.biSize);
+ x = LITTLE_LONG(bmi.biWidth);
+ y = LITTLE_LONG(bmi.biHeight);
+ depth = LITTLE_SHORT(bmi.biBitCount);
+
+ /* printf("skip: %d, x: %d y: %d, depth: %d (%x)\n", skip, x, y,
+ depth, bmi.biBitCount); */
+ /* printf("skip: %d, x: %d y: %d, depth: %d (%x)\n", skip, x, y,
+ depth, bmi.biBitCount); */
+ if (flags & IB_test) {
+ ibuf = IMB_allocImBuf(x, y, depth, 0, 0);
+ } else {
+ ibuf = IMB_allocImBuf(x, y, depth, IB_rect, 0);
+ bmp = mem + skip;
+ rect = (unsigned char *) ibuf->rect;
+
+ if (depth == 16) {
+ for (i = x * y; i > 0; i--) {
+ col = bmp[0] + (bmp[1] << 8);
+ rect[0] = ((col >> 10) & 0x1f) << 3;
+ rect[1] = ((col >> 5) & 0x1f) << 3;
+ rect[2] = ((col >> 0) & 0x1f) << 3;
+
+ rect[3] = 255;
+ rect += 4; bmp += 2;
+ }
+
+ } else if (depth == 24) {
+ for (i = y; i > 0; i--) {
+ int j;
+ for (j = x ; j > 0; j--) {
+ rect[0] = bmp[2];
+ rect[1] = bmp[1];
+ rect[2] = bmp[0];
+
+ rect[3] = 255;
+ rect += 4; bmp += 3;
+ }
+ /* for 24-bit images, rows are padded to multiples of 4 */
+ bmp += x % 4;
+ }
+ } else if (depth == 32) {
+ for (i = x * y; i > 0; i--) {
+ rect[0] = bmp[0];
+ rect[1] = bmp[1];
+ rect[2] = bmp[2];
+ rect[3] = bmp[3];
+ rect += 4; bmp += 4;
+ }
+ }
+ }
+
+ if (ibuf) {
+ ibuf->ftype = BMP;
+ }
+
+ return(ibuf);
+}
+
+/* Couple of helper functions for writing our data */
+static int putIntLSB(unsigned int ui,FILE *ofile) {
+ putc((ui>>0)&0xFF,ofile);
+ putc((ui>>8)&0xFF,ofile);
+ putc((ui>>16)&0xFF,ofile);
+ return putc((ui>>24)&0xFF,ofile);
+}
+
+static int putShortLSB(unsigned short us,FILE *ofile) {
+ putc((us>>0)&0xFF,ofile);
+ return putc((us>>8)&0xFF,ofile);
+}
+
+/* Found write info at http://users.ece.gatech.edu/~slabaugh/personal/c/bitmapUnix.c */
+short imb_savebmp(struct ImBuf *ibuf, char *name, int flags) {
+
+ BMPINFOHEADER infoheader;
+ int bytesize, extrabytes, x, y, t, ptr;
+ uchar *data;
+ FILE *ofile;
+
+ extrabytes = (4 - ibuf->x*3 % 4) % 4;
+ bytesize = (ibuf->x * 3 + extrabytes) * ibuf->y;
+
+ data = (uchar *) ibuf->rect;
+ ofile = fopen(name,"wb");
+ if (!ofile) return 0;
+
+ putShortLSB(19778,ofile); /* "BM" */
+ putIntLSB(0,ofile); /* This can be 0 for BI_RGB bitmaps */
+ putShortLSB(0,ofile); /* Res1 */
+ putShortLSB(0,ofile); /* Res2 */
+ putIntLSB(BMP_FILEHEADER_SIZE + sizeof(infoheader),ofile);
+
+ putIntLSB(sizeof(infoheader),ofile);
+ putIntLSB(ibuf->x,ofile);
+ putIntLSB(ibuf->y,ofile);
+ putShortLSB(1,ofile);
+ putShortLSB(24,ofile);
+ putIntLSB(0,ofile);
+ putIntLSB(bytesize + BMP_FILEHEADER_SIZE + sizeof(infoheader),ofile);
+ putIntLSB(0,ofile);
+ putIntLSB(0,ofile);
+ putIntLSB(0,ofile);
+ putIntLSB(0,ofile);
+
+ /* Need to write out padded image data in bgr format */
+ for (y=0;y<ibuf->y;y++) {
+ for (x=0;x<ibuf->x;x++) {
+ ptr=(x + y * ibuf->x) * 4;
+ if (putc(data[ptr+2],ofile) == EOF) return 0;
+ if (putc(data[ptr+1],ofile) == EOF) return 0;
+ if (putc(data[ptr],ofile) == EOF) return 0;
+ }
+ /* add padding here */
+ for (t=0;t<extrabytes;t++) if (putc(0,ofile) == EOF) return 0;
+ }
+ if (ofile) {
+ fflush(ofile);
+ fclose(ofile);
+ }
+ return 1;
+}
diff --git a/source/blender/imbuf/intern/cineon/CMakeLists.txt b/source/blender/imbuf/intern/cineon/CMakeLists.txt
new file mode 100644
index 00000000000..efaa36cf9ed
--- /dev/null
+++ b/source/blender/imbuf/intern/cineon/CMakeLists.txt
@@ -0,0 +1,44 @@
+# $Id$
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2006, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Jacques Beaurain.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+
+FILE(GLOB SRC *.c)
+
+SET(INC
+ .
+ ../../../blenkernel
+ ../../
+ ..
+ ../../../blenlib
+ intern/include
+ ../../../../../intern/guardedalloc
+ ../../../makesdna
+)
+
+BLENDERLIB(bf_cineon "${SRC}" "${INC}")
+#env.BlenderLib ('bf_cineon', source_files, incs, defs, libtype=['core','player'], priority = [90, 200])
diff --git a/source/blender/imbuf/intern/cineon/Makefile b/source/blender/imbuf/intern/cineon/Makefile
new file mode 100644
index 00000000000..e61c8dd59ed
--- /dev/null
+++ b/source/blender/imbuf/intern/cineon/Makefile
@@ -0,0 +1,60 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+#
+
+LIBNAME = cineon
+DIR = $(OCGDIR)/blender/imbuf/cineon
+SOURCEDIR = source/blender/imbuf/intern/cineon
+
+include nan_compile.mk
+include nan_definitions.mk
+
+CFLAGS += $(LEVEL_1_C_WARNINGS)
+
+CPPFLAGS += -I$(NAN_JPEG)/include
+CPPFLAGS += -I$(NAN_PNG)/include
+CPPFLAGS += -I$(NAN_ZLIB)/include
+CPPFLAGS += -I$(NAN_TIFF)/include
+CPPFLAGS += -I../../../include
+CPPFLAGS += -I../../../blenkernel
+CPPFLAGS += -I../../../blenlib
+CPPFLAGS += -I../../../avi
+CPPFLAGS += -I../../../quicktime
+# path to the guarded memory allocator
+CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
+CPPFLAGS += -I$(NAN_MEMUTIL)/include
+# This is not really needed, but until /include is cleaned, it must be
+# there for proper compilation.
+# - No, it is also needed in antialias, for listbase (nzc)
+CPPFLAGS += -I../../../makesdna
+# external interface of this module
+CPPFLAGS += -I../..
diff --git a/source/blender/imbuf/intern/cineon/README b/source/blender/imbuf/intern/cineon/README
new file mode 100644
index 00000000000..5554e857c81
--- /dev/null
+++ b/source/blender/imbuf/intern/cineon/README
@@ -0,0 +1,8 @@
+Files:
+
+logImageLib.h, logImageLib.c: combined cineon/dpx image library
+dpxlib.h, dpxlib.c: dpx specific library
+dpxfile.h: dpx file structure
+cineonlib.h, cineonlib.c: cineon specific library
+cineonfile.h: cineon file structure
+logImageCore.h, logImageCore.c: log image routines common to cineon amd dpx
diff --git a/source/blender/imbuf/intern/cineon/SConscript b/source/blender/imbuf/intern/cineon/SConscript
new file mode 100644
index 00000000000..7bfaa8dbdf2
--- /dev/null
+++ b/source/blender/imbuf/intern/cineon/SConscript
@@ -0,0 +1,17 @@
+#!/usr/bin/python
+Import ('env')
+
+source_files = env.Glob('*.c')
+
+incs = ['.',
+ '../../../blenkernel',
+ '../../',
+ '..',
+ '../../../blenlib',
+ 'intern/include',
+ '#/intern/guardedalloc',
+ '../../../makesdna']
+
+defs = []
+
+env.BlenderLib ('bf_cineon', source_files, incs, defs, libtype=['core','player'], priority = [90, 200])
diff --git a/source/blender/imbuf/intern/cineon/cin_debug_stuff.h b/source/blender/imbuf/intern/cineon/cin_debug_stuff.h
new file mode 100644
index 00000000000..5d7daa19c61
--- /dev/null
+++ b/source/blender/imbuf/intern/cineon/cin_debug_stuff.h
@@ -0,0 +1 @@
+#define d_printf printf
diff --git a/source/blender/imbuf/intern/cineon/cineon_dpx.c b/source/blender/imbuf/intern/cineon/cineon_dpx.c
new file mode 100644
index 00000000000..691b81745e0
--- /dev/null
+++ b/source/blender/imbuf/intern/cineon/cineon_dpx.c
@@ -0,0 +1,193 @@
+/**
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ * cineon.c
+ * contributors: joeedh
+ * I hearby donate this code and all rights to the Blender Foundation.
+ * $Id$
+ */
+
+#include <stdio.h>
+#include <string.h> /*for memcpy*/
+
+#include "logImageLib.h"
+#include "cineonlib.h"
+#include "dpxlib.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "MEM_guardedalloc.h"
+
+static struct ImBuf *imb_load_dpx_cineon(unsigned char *mem, int use_cineon, int size, int flags)
+{
+ ImBuf *ibuf;
+ LogImageFile *image;
+ int x, y;
+ unsigned short *row, *upix;
+ int width, height, depth;
+ float *frow;
+
+ image = logImageOpenFromMem(mem, size, use_cineon);
+
+ if (!image) {
+ printf("no image!\n");
+ return NULL;
+ }
+
+ logImageGetSize(image, &width, &height, &depth);
+
+ if (depth != 3) { /*need to do greyscale loading eventually.*/
+ logImageClose(image);
+ return NULL;
+ }
+
+ if (width == 0 && height == 0) {
+ logImageClose(image);
+ return NULL;
+ }
+
+ ibuf = IMB_allocImBuf(width, height, 32, IB_rectfloat | flags, 0);
+
+ row = MEM_mallocN(sizeof(unsigned short)*width*depth, "row in cineon_dpx.c");
+ frow = ibuf->rect_float+width*height*4;
+
+ for (y = 0; y < height; y++) {
+ logImageGetRowBytes(image, row, y);
+ upix = row;
+ frow -= width*4;
+
+ for (x=0; x<width; x++) {
+ *(frow++) = ((float)*(upix++)) / 65535.0f;
+ *(frow++) = ((float)*(upix++)) / 65535.0f;
+ *(frow++) = ((float)*(upix++)) / 65535.0f;
+ *(frow++) = 1.0f;
+ }
+ frow -= width*4;
+ }
+
+ MEM_freeN(row);
+ logImageClose(image);
+
+ if (flags & IB_rect) {
+ IMB_rect_from_float(ibuf);
+ }
+ return ibuf;
+}
+
+static int imb_save_dpx_cineon(ImBuf *buf, char *filename, int use_cineon, int flags)
+{
+ LogImageByteConversionParameters conversion;
+ int width, height, depth;
+ LogImageFile* logImage;
+ unsigned short* line, *pixel;
+ int i, j;
+ int index;
+ float *fline;
+
+ conversion.blackPoint = 95;
+ conversion.whitePoint = 685;
+ conversion.gamma = 1;
+ /*
+ * Get the drawable for the current image...
+ */
+
+ width = buf->x;
+ height = buf->y;
+ depth = 3;
+
+ if (!buf->rect_float) return 0;
+
+ logImageSetVerbose(0);
+ logImage = logImageCreate(filename, use_cineon, width, height, depth);
+
+ if (!logImage) return 0;
+
+ logImageSetByteConversion(logImage, &conversion);
+
+ index = 0;
+ line = MEM_mallocN(sizeof(unsigned short)*depth*width, "line");
+
+ /*note that image is flipped when sent to logImageSetRowBytes (see last passed parameter).*/
+ for (j = 0; j < height; ++j) {
+ fline = &buf->rect_float[width*j*4];
+ for (i=0; i<width; i++) {
+ float *fpix, fpix2[3];
+ /*we have to convert to cinepaint's 16-bit-per-channel here*/
+ pixel = &line[i*depth];
+ fpix = &fline[i*4];
+ memcpy(fpix2, fpix, sizeof(float)*3);
+
+ if (fpix2[0]>=1.0f) fpix2[0] = 1.0f; else if (fpix2[0]<0.0f) fpix2[0]= 0.0f;
+ if (fpix2[1]>=1.0f) fpix2[1] = 1.0f; else if (fpix2[1]<0.0f) fpix2[1]= 0.0f;
+ if (fpix2[2]>=1.0f) fpix2[2] = 1.0f; else if (fpix2[2]<0.0f) fpix2[2]= 0.0f;
+
+ pixel[0] = (unsigned short)(fpix2[0] * 65535.0f); /*float-float math is faster*/
+ pixel[1] = (unsigned short)(fpix2[1] * 65535.0f);
+ pixel[2] = (unsigned short)(fpix2[2] * 65535.0f);
+ }
+ logImageSetRowBytes(logImage, (const unsigned short*)line, height-1-j);
+ }
+ logImageClose(logImage);
+
+ MEM_freeN(line);
+ return 1;
+}
+
+short imb_savecineon(struct ImBuf *buf, char *myfile, int flags)
+{
+ return imb_save_dpx_cineon(buf, myfile, 1, flags);
+}
+
+
+int imb_is_cineon(void *buf)
+{
+ return cineonIsMemFileCineon(buf);
+}
+
+ImBuf *imb_loadcineon(unsigned char *mem, int size, int flags)
+{
+ if(imb_is_cineon(mem))
+ return imb_load_dpx_cineon(mem, 1, size, flags);
+ return NULL;
+}
+
+short imb_save_dpx(struct ImBuf *buf, char *myfile, int flags)
+{
+ return imb_save_dpx_cineon(buf, myfile, 0, flags);
+}
+
+int imb_is_dpx(void *buf)
+{
+ return dpxIsMemFileCineon(buf);
+}
+
+ImBuf *imb_loaddpx(unsigned char *mem, int size, int flags)
+{
+ if(imb_is_dpx(mem))
+ return imb_load_dpx_cineon(mem, 0, size, flags);
+ return NULL;
+}
diff --git a/source/blender/imbuf/intern/cineon/cineonfile.h b/source/blender/imbuf/intern/cineon/cineonfile.h
new file mode 100644
index 00000000000..7f6f1138902
--- /dev/null
+++ b/source/blender/imbuf/intern/cineon/cineonfile.h
@@ -0,0 +1,143 @@
+/*
+ * Cineon image file format library definitions.
+ * Cineon file format structures.
+ *
+ * This header file contains private details.
+ * User code should generally use cineonlib.h only.
+ *
+ * Copyright 1999,2000,2001 David Hodson <hodsond@acm.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef _CINEON_FILE_H_
+#define _CINEON_FILE_H_
+
+#include "logImageCore.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+ U32 magic_num; /* magic number */
+ U32 image_offset; /* offset to image data in bytes */
+ U32 gen_hdr_size; /* generic header length in bytes */
+ U32 ind_hdr_size; /* industry header length in bytes */
+ U32 user_data_size; /* user-defined data length in bytes */
+ U32 file_size; /* file size in bytes */
+ ASCII vers[8]; /* which header format version is being used (v4.5) */
+ ASCII file_name[100]; /* image file name */
+ ASCII create_date[12]; /* file creation date */
+ ASCII create_time[12]; /* file creation time */
+ ASCII Reserved[36]; /* reserved field TBD (need to pad) */
+} CineonFileInformation;
+
+typedef struct {
+ U8 designator1;
+ U8 designator2;
+ U8 bits_per_pixel;
+ U8 filler;
+ U32 pixels_per_line;
+ U32 lines_per_image;
+ U32 ref_low_data; /* reference low data code value */
+ R32 ref_low_quantity; /* reference low quantity represented */
+ U32 ref_high_data; /* reference high data code value */
+ R32 ref_high_quantity;/* reference high quantity represented */
+} CineonChannelInformation;
+
+typedef struct {
+ U8 orientation; /* image orientation */
+ U8 channels_per_image;
+ U16 filler;
+ CineonChannelInformation channel[8];
+ R32 white_point_x;
+ R32 white_point_y;
+ R32 red_primary_x;
+ R32 red_primary_y;
+ R32 green_primary_x;
+ R32 green_primary_y;
+ R32 blue_primary_x;
+ R32 blue_primary_y;
+ ASCII label[200];
+ ASCII reserved[28];
+} CineonImageInformation;
+
+typedef struct {
+ U8 interleave;
+ U8 packing;
+ U8 signage;
+ U8 sense;
+ U32 line_padding;
+ U32 channel_padding;
+ ASCII reserved[20];
+} CineonFormatInformation;
+
+typedef struct {
+ S32 x_offset;
+ S32 y_offset;
+ ASCII file_name[100];
+ ASCII create_date[12]; /* file creation date */
+ ASCII create_time[12]; /* file creation time */
+ ASCII input_device[64];
+ ASCII model_number[32];
+ ASCII serial_number[32];
+ R32 x_input_samples_per_mm;
+ R32 y_input_samples_per_mm;
+ R32 input_device_gamma;
+ ASCII reserved[40];
+} CineonOriginationInformation;
+
+typedef struct {
+ CineonFileInformation fileInfo;
+ CineonImageInformation imageInfo;
+ CineonFormatInformation formatInfo;
+ CineonOriginationInformation originInfo;
+} CineonGenericHeader;
+
+typedef struct {
+ U8 filmCode;
+ U8 filmType;
+ U8 perfOffset;
+ U8 filler;
+ U32 keycodePrefix;
+ U32 keycodeCount;
+ ASCII format[32];
+ U32 framePosition; /* in sequence */
+ R32 frameRate; /* frames per second */
+ ASCII attribute[32];
+ ASCII slate[200];
+ ASCII reserved[740];
+} CineonMPISpecificInformation;
+
+#if 0
+/* create CineonFile from data in header */
+/* return 0 for OK */
+int readCineonGenericHeader(CineonFile* cineon, CineonGenericHeader* header);
+
+/* create header from data in CineonFile */
+int initCineonGenericHeader(
+ CineonFile* cineon, CineonGenericHeader* header, const char* imagename);
+
+/* Note: dump routine assumes network byte order */
+void dumpCineonGenericHeader(CineonGenericHeader* header);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CINEON_FILE_H_ */
diff --git a/source/blender/imbuf/intern/cineon/cineonlib.c b/source/blender/imbuf/intern/cineon/cineonlib.c
new file mode 100644
index 00000000000..20f4e0d4de4
--- /dev/null
+++ b/source/blender/imbuf/intern/cineon/cineonlib.c
@@ -0,0 +1,802 @@
+/*
+ * Cineon image file format library routines.
+ *
+ * Copyright 1999,2000,2001 David Hodson <hodsond@acm.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "cineonlib.h"
+#include "cineonfile.h"
+
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <time.h> /* strftime() */
+#include <sys/types.h>
+#ifdef WIN32
+#include <winsock.h>
+#else
+#include <netinet/in.h> /* htonl() */
+#endif
+#include <string.h> /* memset */
+#include "cin_debug_stuff.h"
+#include "logmemfile.h"
+
+static void
+fillCineonFileInfo(CineonFile* cineon, CineonFileInformation* fileInfo, const char* filename) {
+
+ time_t fileClock;
+ struct tm* fileTime;
+
+ fileInfo->magic_num = htonl(CINEON_FILE_MAGIC);
+ fileInfo->image_offset = htonl(cineon->imageOffset);
+ fileInfo->gen_hdr_size = htonl(
+ sizeof(CineonFileInformation) +
+ sizeof(CineonImageInformation) +
+ sizeof(CineonFormatInformation) +
+ sizeof(CineonOriginationInformation));
+ fileInfo->ind_hdr_size = 0;
+ fileInfo->user_data_size = 0;
+ fileInfo->file_size = htonl(cineon->imageOffset + cineon->height * cineon->lineBufferLength);
+ strcpy(fileInfo->vers, "V4.5");
+ strncpy(fileInfo->file_name, filename, 99);
+ fileInfo->file_name[99] = 0;
+
+ fileClock = time(0);
+ fileTime = localtime(&fileClock);
+ strftime(fileInfo->create_date, 12, "%Y:%m:%d", fileTime);
+ /* Question: is %Z in strftime guaranteed to return 3 chars? */
+ strftime(fileInfo->create_time, 12, "%H:%M:%S%Z", fileTime);
+ fileInfo->create_time[11] = 0;
+}
+
+static void
+dumpCineonFileInfo(CineonFileInformation* fileInfo) {
+ d_printf("\n--File Information--\n");
+ d_printf("Magic: %8.8lX\n", (unsigned long)ntohl(fileInfo->magic_num));
+ d_printf("Image Offset %ld\n", (long)ntohl(fileInfo->image_offset));
+ d_printf("Generic Header size %ld\n", (long)ntohl(fileInfo->gen_hdr_size));
+ d_printf("Industry Header size %ld\n", (long)ntohl(fileInfo->ind_hdr_size));
+ d_printf("User Data size %ld\n", (long)ntohl(fileInfo->user_data_size));
+ d_printf("File size %ld\n", (long)ntohl(fileInfo->file_size));
+ d_printf("Version \"%s\"\n", fileInfo->vers);
+ d_printf("File name \"%s\"\n", fileInfo->file_name);
+ d_printf("Creation date \"%s\"\n", fileInfo->create_date);
+ d_printf("Creation time \"%s\"\n", fileInfo->create_time);
+}
+
+static void
+fillCineonChannelInfo(CineonFile* cineon, CineonChannelInformation* chan, int des) {
+
+ chan->designator1 = 0;
+ chan->designator2 = des;
+ chan->bits_per_pixel = 10;
+ chan->pixels_per_line = htonl(cineon->width);
+ chan->lines_per_image = htonl(cineon->height);
+ chan->ref_low_data = htonl(0);
+ chan->ref_low_quantity = htonf(0.0);
+ chan->ref_high_data = htonl(1023);
+ chan->ref_high_quantity = htonf(2.046);
+}
+
+static void
+dumpCineonChannelInfo(CineonChannelInformation* chan) {
+ d_printf(" Metric selector: %d", chan->designator1);
+ switch (chan->designator1) {
+ case 0: d_printf(" (Universal)\n"); break;
+ default: d_printf(" (Vendor specific)\n"); break;
+ }
+ d_printf(" Metric: %d,", chan->designator2);
+ switch (chan->designator2) {
+ case 0: d_printf(" B&W (printing density?)\n"); break;
+ case 1: d_printf(" Red printing density\n"); break;
+ case 2: d_printf(" Green printing density\n"); break;
+ case 3: d_printf(" Blue printing density\n"); break;
+ case 4: d_printf(" Red CCIR XA/11\n"); break;
+ case 5: d_printf(" Green CCIR XA/11\n"); break;
+ case 6: d_printf(" Blue CCIR XA/11\n"); break;
+ default: d_printf(" (unknown)\n"); break;
+ }
+ d_printf(" Bits per pixel %d\n", chan->bits_per_pixel);
+ d_printf(" Pixels per line %ld\n", (long)ntohl(chan->pixels_per_line));
+ d_printf(" Lines per image %ld\n", (long)ntohl(chan->lines_per_image));
+ d_printf(" Ref low data %ld\n", (long)ntohl(chan->ref_low_data));
+ d_printf(" Ref low quantity %f\n", ntohf(chan->ref_low_quantity));
+ d_printf(" Ref high data %ld\n", (long)ntohl(chan->ref_high_data));
+ d_printf(" Ref high quantity %f\n", ntohf(chan->ref_high_quantity));
+}
+
+static void
+fillCineonImageInfo(CineonFile* cineon, CineonImageInformation* imageInfo) {
+
+ imageInfo->orientation = 0;
+ imageInfo->channels_per_image = cineon->depth;
+
+ if (cineon->depth == 1) {
+ fillCineonChannelInfo(cineon, &imageInfo->channel[0], 0);
+
+ } else if (cineon->depth == 3) {
+ fillCineonChannelInfo(cineon, &imageInfo->channel[0], 1);
+ fillCineonChannelInfo(cineon, &imageInfo->channel[1], 2);
+ fillCineonChannelInfo(cineon, &imageInfo->channel[2], 3);
+ }
+
+ imageInfo->white_point_x = htonf(undefined());
+ imageInfo->white_point_y = htonf(undefined());
+ imageInfo->red_primary_x = htonf(undefined());
+ imageInfo->red_primary_y = htonf(undefined());
+ imageInfo->green_primary_x = htonf(undefined());
+ imageInfo->green_primary_y = htonf(undefined());
+ imageInfo->blue_primary_x = htonf(undefined());
+ imageInfo->blue_primary_y = htonf(undefined());
+
+ strcpy(imageInfo->label, "David's Cineon writer.");
+
+}
+
+static void
+dumpCineonImageInfo(CineonImageInformation* imageInfo) {
+
+ int i;
+ d_printf("\n--Image Information--\n");
+ d_printf("Image orientation %d,", imageInfo->orientation);
+ switch (imageInfo->orientation) {
+ case 0: d_printf(" LRTB\n"); break;
+ case 1: d_printf(" LRBT\n"); break;
+ case 2: d_printf(" RLTB\n"); break;
+ case 3: d_printf(" RLBT\n"); break;
+ case 4: d_printf(" TBLR\n"); break;
+ case 5: d_printf(" TBRL\n"); break;
+ case 6: d_printf(" BTLR\n"); break;
+ case 7: d_printf(" BTRL\n"); break;
+ default: d_printf(" (unknown)\n"); break;
+ }
+ d_printf("Channels %d\n", imageInfo->channels_per_image);
+ for (i = 0; i < imageInfo->channels_per_image; ++i) {
+ d_printf(" --Channel %d--\n", i);
+ dumpCineonChannelInfo(&imageInfo->channel[i]);
+ }
+
+ d_printf("White point x %f\n", ntohf(imageInfo->white_point_x));
+ d_printf("White point y %f\n", ntohf(imageInfo->white_point_y));
+ d_printf("Red primary x %f\n", ntohf(imageInfo->red_primary_x));
+ d_printf("Red primary y %f\n", ntohf(imageInfo->red_primary_y));
+ d_printf("Green primary x %f\n", ntohf(imageInfo->green_primary_x));
+ d_printf("Green primary y %f\n", ntohf(imageInfo->green_primary_y));
+ d_printf("Blue primary x %f\n", ntohf(imageInfo->blue_primary_x));
+ d_printf("Blue primary y %f\n", ntohf(imageInfo->blue_primary_y));
+ d_printf("Label \"%s\"\n", imageInfo->label);
+}
+
+static void
+fillCineonFormatInfo(CineonFile* cineon, CineonFormatInformation* formatInfo) {
+
+ formatInfo->interleave = 0;
+ formatInfo->packing = 5;
+ formatInfo->signage = 0;
+ formatInfo->sense = 0;
+ formatInfo->line_padding = htonl(0);
+ formatInfo->channel_padding = htonl(0);
+}
+
+static void
+dumpCineonFormatInfo(CineonFormatInformation* formatInfo) {
+ d_printf("\n--Format Information--\n");
+ d_printf("Interleave %d,", formatInfo->interleave);
+ switch (formatInfo->interleave) {
+ case 0: d_printf(" pixel interleave\n"); break;
+ case 1: d_printf(" line interleave\n"); break;
+ case 2: d_printf(" channel interleave\n"); break;
+ default: d_printf(" (unknown)\n"); break;
+ }
+ d_printf("Packing %d,", formatInfo->packing);
+ if (formatInfo->packing & 0x80) {
+ d_printf(" multi pixel,");
+ } else {
+ d_printf(" single pixel,");
+ }
+ switch (formatInfo->packing & 0x7F) {
+ case 0: d_printf(" tight\n"); break;
+ case 1: d_printf(" byte packed left\n"); break;
+ case 2: d_printf(" byte packed right\n"); break;
+ case 3: d_printf(" word packed left\n"); break;
+ case 4: d_printf(" word packed right\n"); break;
+ case 5: d_printf(" long packed left\n"); break;
+ case 6: d_printf(" long packed right\n"); break;
+ default: d_printf(" (unknown)\n"); break;
+ }
+ d_printf("Sign %d,", formatInfo->signage);
+ if (formatInfo->signage) {
+ d_printf(" signed\n");
+ } else {
+ d_printf(" unsigned\n");
+ }
+ d_printf("Sense %d,", formatInfo->signage);
+ if (formatInfo->signage) {
+ d_printf(" negative\n");
+ } else {
+ d_printf(" positive\n");
+ }
+ d_printf("End of line padding %ld\n", (long)ntohl(formatInfo->line_padding));
+ d_printf("End of channel padding %ld\n", (long)ntohl(formatInfo->channel_padding));
+}
+
+static void
+fillCineonOriginationInfo(CineonFile* cineon,
+ CineonOriginationInformation* originInfo, CineonFileInformation* fileInfo) {
+
+ originInfo->x_offset = htonl(0);
+ originInfo->y_offset = htonl(0);
+ strcpy(originInfo->file_name, fileInfo->file_name);
+ strcpy(originInfo->create_date, fileInfo->create_date);
+ strcpy(originInfo->create_time, fileInfo->create_time);
+ strncpy(originInfo->input_device, "David's Cineon writer", 64);
+ strncpy(originInfo->model_number, "Software", 32);
+ strncpy(originInfo->serial_number, "001", 32);
+ originInfo->x_input_samples_per_mm = htonf(undefined());
+ originInfo->y_input_samples_per_mm = htonf(undefined());
+ /* this should probably be undefined, too */
+ originInfo->input_device_gamma = htonf(1.0);
+}
+
+static void
+dumpCineonOriginationInfo(CineonOriginationInformation* originInfo) {
+ d_printf("\n--Origination Information--\n");
+ d_printf("X offset %ld\n", (long)ntohl(originInfo->x_offset));
+ d_printf("Y offset %ld\n", (long)ntohl(originInfo->y_offset));
+ d_printf("File name \"%s\"\n", originInfo->file_name);
+ d_printf("Creation date \"%s\"\n", originInfo->create_date);
+ d_printf("Creation time \"%s\"\n", originInfo->create_time);
+ d_printf("Input device \"%s\"\n", originInfo->input_device);
+ d_printf("Model number \"%s\"\n", originInfo->model_number);
+ d_printf("Serial number \"%s\"\n", originInfo->serial_number);
+ d_printf("Samples per mm in x %f\n", ntohf(originInfo->x_input_samples_per_mm));
+ d_printf("Samples per mm in y %f\n", ntohf(originInfo->y_input_samples_per_mm));
+ d_printf("Input device gamma %f\n", ntohf(originInfo->input_device_gamma));
+}
+
+int
+initCineonGenericHeader(CineonFile* cineon, CineonGenericHeader* header, const char* imagename) {
+
+ fillCineonFileInfo(cineon, &header->fileInfo, imagename);
+ fillCineonImageInfo(cineon, &header->imageInfo);
+ fillCineonFormatInfo(cineon, &header->formatInfo);
+ fillCineonOriginationInfo(cineon, &header->originInfo, &header->fileInfo);
+
+ return 0;
+}
+
+void
+dumpCineonGenericHeader(CineonGenericHeader* header) {
+ dumpCineonFileInfo(&header->fileInfo);
+ dumpCineonImageInfo(&header->imageInfo);
+ dumpCineonFormatInfo(&header->formatInfo);
+ dumpCineonOriginationInfo(&header->originInfo);
+}
+
+static int verbose = 0;
+void
+cineonSetVerbose(int verbosity) {
+ verbose = verbosity;
+}
+
+static void
+verboseMe(CineonFile* cineon) {
+
+ d_printf("size %d x %d x %d\n", cineon->width, cineon->height, cineon->depth);
+ d_printf("ImageStart %d, lineBufferLength %d, implied length %d\n",
+ cineon->imageOffset, cineon->lineBufferLength * 4,
+ cineon->imageOffset + cineon->lineBufferLength * 4 * cineon->height);
+}
+
+int
+cineonGetRowBytes(CineonFile* cineon, unsigned short* row, int y) {
+
+ int longsRead;
+ int pixelIndex;
+ int longIndex;
+ int numPixels = cineon->width * cineon->depth;
+
+
+ /* only seek if not reading consecutive lines */
+ if (y != cineon->fileYPos) {
+ int lineOffset = cineon->imageOffset + y * cineon->lineBufferLength * 4;
+ if (verbose) d_printf("Seek in getRowBytes\n");
+ if (logimage_fseek(cineon, lineOffset, SEEK_SET) != 0) {
+ if (verbose) d_printf("Couldn't seek to line %d at %d\n", y, lineOffset);
+ return 1;
+ }
+ cineon->fileYPos = y;
+ }
+
+ longsRead = logimage_fread(cineon->lineBuffer, 4, cineon->lineBufferLength, cineon);
+ if (longsRead != cineon->lineBufferLength) {
+ if (verbose)
+ { d_printf("Couldn't read line %d length %d\n", y, cineon->lineBufferLength * 4);
+ perror("cineonGetRowBytes");
+ }
+ return 1;
+ }
+
+ /* remember where we left the car, honey */
+ ++cineon->fileYPos;
+
+ /* convert longwords to pixels */
+ pixelIndex = 0;
+ for (longIndex = 0; longIndex < cineon->lineBufferLength; ++longIndex) {
+ unsigned int t = ntohl(cineon->lineBuffer[longIndex]);
+ t = t >> 2;
+ cineon->pixelBuffer[pixelIndex+2] = (unsigned short) t & 0x3ff;
+ t = t >> 10;
+ cineon->pixelBuffer[pixelIndex+1] = (unsigned short) t & 0x3ff;
+ t = t >> 10;
+ cineon->pixelBuffer[pixelIndex] = (unsigned short) t & 0x3ff;
+ pixelIndex += 3;
+ }
+
+ /* extract required pixels */
+ for (pixelIndex = 0; pixelIndex < numPixels; ++pixelIndex) {
+ /* row[pixelIndex] = cineon->lut10[cineon->pixelBuffer[pixelIndex]]; */
+ row[pixelIndex] = cineon->pixelBuffer[pixelIndex] << 6;
+ }
+
+ return 0;
+}
+
+int
+cineonSetRowBytes(CineonFile* cineon, const unsigned short* row, int y) {
+
+ int pixelIndex;
+ int numPixels = cineon->width * cineon->depth;
+ int longIndex;
+ int longsWritten;
+
+ /* put new pixels into pixelBuffer */
+ for (pixelIndex = 0; pixelIndex < numPixels; ++pixelIndex) {
+ /* cineon->pixelBuffer[pixelIndex] = cineon->lut8[row[pixelIndex]]; */
+ cineon->pixelBuffer[pixelIndex] = row[pixelIndex] >> 6;
+ }
+
+ /* pack into longwords */
+ pixelIndex = 0;
+ for (longIndex = 0; longIndex < cineon->lineBufferLength; ++longIndex) {
+ unsigned int t =
+ (cineon->pixelBuffer[pixelIndex] << 22) |
+ (cineon->pixelBuffer[pixelIndex+1] << 12) |
+ (cineon->pixelBuffer[pixelIndex+2] << 2);
+ cineon->lineBuffer[longIndex] = htonl(t);
+ pixelIndex += 3;
+ }
+
+ /* only seek if not reading consecutive lines */
+ if (y != cineon->fileYPos) {
+ int lineOffset = cineon->imageOffset + y * cineon->lineBufferLength * 4;
+ if (verbose) d_printf("Seek in setRowBytes\n");
+ if (logimage_fseek(cineon, lineOffset, SEEK_SET) != 0) {
+ if (verbose) d_printf("Couldn't seek to line %d at %d\n", y, lineOffset);
+ return 1;
+ }
+ cineon->fileYPos = y;
+ }
+
+ longsWritten = fwrite(cineon->lineBuffer, 4, cineon->lineBufferLength, cineon->file);
+ if (longsWritten != cineon->lineBufferLength) {
+ if (verbose) d_printf("Couldn't write line %d length %d\n", y, cineon->lineBufferLength * 4);
+ return 1;
+ }
+
+ ++cineon->fileYPos;
+
+ return 0;
+}
+
+int
+cineonGetRow(CineonFile* cineon, unsigned short* row, int y) {
+
+ int longsRead;
+ int pixelIndex;
+ int longIndex;
+/* int numPixels = cineon->width * cineon->depth;
+*/
+ /* only seek if not reading consecutive lines */
+ if (y != cineon->fileYPos) {
+ int lineOffset = cineon->imageOffset + y * cineon->lineBufferLength * 4;
+ if (verbose) d_printf("Seek in getRow\n");
+ if (logimage_fseek(cineon, lineOffset, SEEK_SET) != 0) {
+ if (verbose) d_printf("Couldn't seek to line %d at %d\n", y, lineOffset);
+ return 1;
+ }
+ cineon->fileYPos = y;
+ }
+
+ longsRead = logimage_fread(cineon->lineBuffer, 4, cineon->lineBufferLength, cineon);
+ if (longsRead != cineon->lineBufferLength) {
+ if (verbose) d_printf("Couldn't read line %d length %d\n", y, cineon->lineBufferLength * 4);
+ return 1;
+ }
+
+ /* remember where we left the car, honey */
+ ++cineon->fileYPos;
+
+ /* convert longwords to pixels */
+ pixelIndex = 0;
+ for (longIndex = 0; longIndex < cineon->lineBufferLength; ++longIndex) {
+ unsigned int t = ntohl(cineon->lineBuffer[longIndex]);
+ t = t >> 2;
+ row[pixelIndex+2] = (unsigned short) t & 0x3ff;
+ t = t >> 10;
+ row[pixelIndex+1] = (unsigned short) t & 0x3ff;
+ t = t >> 10;
+ row[pixelIndex] = (unsigned short) t & 0x3ff;
+ pixelIndex += 3;
+ }
+
+ return 0;
+}
+
+int
+cineonSetRow(CineonFile* cineon, const unsigned short* row, int y) {
+
+ int pixelIndex;
+/* int numPixels = cineon->width * cineon->depth;
+*/ int longIndex;
+ int longsWritten;
+
+ /* pack into longwords */
+ pixelIndex = 0;
+ for (longIndex = 0; longIndex < cineon->lineBufferLength; ++longIndex) {
+ unsigned int t =
+ (row[pixelIndex] << 22) |
+ (row[pixelIndex+1] << 12) |
+ (row[pixelIndex+2] << 2);
+ cineon->lineBuffer[longIndex] = htonl(t);
+ pixelIndex += 3;
+ }
+
+ /* only seek if not reading consecutive lines */
+ if (y != cineon->fileYPos) {
+ int lineOffset = cineon->imageOffset + y * cineon->lineBufferLength * 4;
+ if (verbose) d_printf("Seek in setRowBytes\n");
+ if (logimage_fseek(cineon, lineOffset, SEEK_SET) != 0) {
+ if (verbose) d_printf("Couldn't seek to line %d at %d\n", y, lineOffset);
+ return 1;
+ }
+ cineon->fileYPos = y;
+ }
+
+ longsWritten = fwrite(cineon->lineBuffer, 4, cineon->lineBufferLength, cineon->file);
+ if (longsWritten != cineon->lineBufferLength) {
+ if (verbose) d_printf("Couldn't write line %d length %d\n", y, cineon->lineBufferLength * 4);
+ return 1;
+ }
+
+ ++cineon->fileYPos;
+
+ return 0;
+}
+
+CineonFile*
+cineonOpen(const char* filename) {
+
+ CineonGenericHeader header;
+
+ CineonFile* cineon = (CineonFile* )malloc(sizeof(CineonFile));
+ if (cineon == 0) {
+ if (verbose) d_printf("Failed to malloc cineon file structure.\n");
+ return 0;
+ }
+
+ /* for close routine */
+ cineon->file = 0;
+ cineon->lineBuffer = 0;
+ cineon->pixelBuffer = 0;
+ cineon->membuffer = 0;
+ cineon->memcursor = 0;
+ cineon->membuffersize = 0;
+
+ cineon->file = fopen(filename, "rb");
+ if (cineon->file == 0) {
+ if (verbose) d_printf("Failed to open file \"%s\".\n", filename);
+ cineonClose(cineon);
+ return 0;
+ }
+ cineon->reading = 1;
+
+ if (logimage_fread(&header, sizeof(CineonGenericHeader), 1, cineon) == 0) {
+ if (verbose) d_printf("Not enough data for header in \"%s\".\n", filename);
+ cineonClose(cineon);
+ return 0;
+ }
+
+ /* let's assume cineon files are always network order */
+ if (header.fileInfo.magic_num != ntohl(CINEON_FILE_MAGIC)) {
+ if (verbose) d_printf("Bad magic number %8.8lX in \"%s\".\n",
+ (unsigned long)ntohl(header.fileInfo.magic_num), filename);
+ cineonClose(cineon);
+ return 0;
+ }
+
+ if (header.formatInfo.packing != 5) {
+ if (verbose) d_printf("Can't understand packing %d\n", header.formatInfo.packing);
+ cineonClose(cineon);
+ return 0;
+ }
+
+ cineon->width = ntohl(header.imageInfo.channel[0].pixels_per_line);
+ cineon->height = ntohl(header.imageInfo.channel[0].lines_per_image);
+ cineon->depth = header.imageInfo.channels_per_image;
+ /* cineon->bitsPerPixel = 10; */
+ cineon->bitsPerPixel = header.imageInfo.channel[0].bits_per_pixel;
+ cineon->imageOffset = ntohl(header.fileInfo.image_offset);
+
+ cineon->lineBufferLength = pixelsToLongs(cineon->width * cineon->depth);
+ cineon->lineBuffer = malloc(cineon->lineBufferLength * 4);
+ if (cineon->lineBuffer == 0) {
+ if (verbose) d_printf("Couldn't malloc line buffer of size %d\n", cineon->lineBufferLength * 4);
+ cineonClose(cineon);
+ return 0;
+ }
+
+ cineon->pixelBuffer = malloc(cineon->lineBufferLength * 3 * sizeof(unsigned short));
+ if (cineon->pixelBuffer == 0) {
+ if (verbose) d_printf("Couldn't malloc pixel buffer of size %d\n",
+ (cineon->width * cineon->depth) * sizeof(unsigned short));
+ cineonClose(cineon);
+ return 0;
+ }
+ cineon->pixelBufferUsed = 0;
+
+ if (logimage_fseek(cineon, cineon->imageOffset, SEEK_SET) != 0) {
+ if (verbose) d_printf("Couldn't seek to image data at %d\n", cineon->imageOffset);
+ cineonClose(cineon);
+ return 0;
+ }
+ cineon->fileYPos = 0;
+
+ logImageGetByteConversionDefaults(&cineon->params);
+ setupLut(cineon);
+
+ cineon->getRow = &cineonGetRowBytes;
+ cineon->setRow = 0;
+ cineon->close = &cineonClose;
+
+ if (verbose) {
+ verboseMe(cineon);
+ }
+
+ return cineon;
+}
+
+int cineonIsMemFileCineon(unsigned char *mem)
+{
+ unsigned int num;
+ memcpy(&num, mem, sizeof(unsigned int));
+
+ if (num != ntohl(CINEON_FILE_MAGIC)) {
+ return 0;
+ } else return 1;
+}
+
+CineonFile*
+cineonOpenFromMem(unsigned char *mem, unsigned int size) {
+
+ CineonGenericHeader header;
+ int i;
+
+ CineonFile* cineon = (CineonFile* )malloc(sizeof(CineonFile));
+ if (cineon == 0) {
+ if (verbose) d_printf("Failed to malloc cineon file structure.\n");
+ return 0;
+ }
+
+ /* for close routine */
+ cineon->file = 0;
+ cineon->lineBuffer = 0;
+ cineon->pixelBuffer = 0;
+ cineon->membuffer = mem;
+ cineon->membuffersize = size;
+ cineon->memcursor = mem;
+
+ cineon->file = 0;
+ cineon->reading = 1;
+ verbose = 1;
+ if (size < sizeof(CineonGenericHeader)) {
+ if (verbose) d_printf("Not enough data for header!\n");
+ cineonClose(cineon);
+ return 0;
+ }
+
+ logimage_fread(&header, sizeof(CineonGenericHeader), 1, cineon);
+
+ /* let's assume cineon files are always network order */
+ if (header.fileInfo.magic_num != ntohl(CINEON_FILE_MAGIC)) {
+ if (verbose) d_printf("Bad magic number %8.8lX in\n", (unsigned long)ntohl(header.fileInfo.magic_num));
+
+ cineonClose(cineon);
+ return 0;
+ }
+
+ if (header.formatInfo.packing != 5) {
+ if (verbose) d_printf("Can't understand packing %d\n", header.formatInfo.packing);
+ cineonClose(cineon);
+ return 0;
+ }
+
+ cineon->width = ntohl(header.imageInfo.channel[0].pixels_per_line);
+ cineon->height = ntohl(header.imageInfo.channel[0].lines_per_image);
+ cineon->depth = header.imageInfo.channels_per_image;
+ /* cineon->bitsPerPixel = 10; */
+ cineon->bitsPerPixel = header.imageInfo.channel[0].bits_per_pixel;
+ cineon->imageOffset = ntohl(header.fileInfo.image_offset);
+
+ cineon->lineBufferLength = pixelsToLongs(cineon->width * cineon->depth);
+ cineon->lineBuffer = malloc(cineon->lineBufferLength * 4);
+ if (cineon->lineBuffer == 0) {
+ if (verbose) d_printf("Couldn't malloc line buffer of size %d\n", cineon->lineBufferLength * 4);
+ cineonClose(cineon);
+ return 0;
+ }
+
+ cineon->pixelBuffer = malloc(cineon->lineBufferLength * 3 * sizeof(unsigned short));
+ if (cineon->pixelBuffer == 0) {
+ if (verbose) d_printf("Couldn't malloc pixel buffer of size %d\n",
+ (cineon->width * cineon->depth) * sizeof(unsigned short));
+ cineonClose(cineon);
+ return 0;
+ }
+ cineon->pixelBufferUsed = 0;
+
+ i = cineon->imageOffset;
+
+ if (logimage_fseek(cineon, cineon->imageOffset, SEEK_SET) != 0) {
+ if (verbose) d_printf("Couldn't seek to image data at %d\n", cineon->imageOffset);
+ cineonClose(cineon);
+ return 0;
+ }
+
+ cineon->fileYPos = 0;
+
+ logImageGetByteConversionDefaults(&cineon->params);
+ setupLut(cineon);
+
+ cineon->getRow = &cineonGetRowBytes;
+ cineon->setRow = 0;
+ cineon->close = &cineonClose;
+
+ if (verbose) {
+ verboseMe(cineon);
+ }
+
+ return cineon;
+}
+
+
+int
+cineonGetSize(const CineonFile* cineon, int* width, int* height, int* depth) {
+ *width = cineon->width;
+ *height = cineon->height;
+ *depth = cineon->depth;
+ return 0;
+}
+
+CineonFile*
+cineonCreate(const char* filename, int width, int height, int depth) {
+
+ /* Note: always write files in network order */
+ /* By the spec, it shouldn't matter, but ... */
+
+ CineonGenericHeader header;
+ const char* shortFilename = 0;
+
+ CineonFile* cineon = (CineonFile*)malloc(sizeof(CineonFile));
+ if (cineon == 0) {
+ if (verbose) d_printf("Failed to malloc cineon file structure.\n");
+ return 0;
+ }
+
+ memset(&header, 0, sizeof(header));
+
+ /* for close routine */
+ cineon->file = 0;
+ cineon->lineBuffer = 0;
+ cineon->pixelBuffer = 0;
+
+ cineon->file = fopen(filename, "wb");
+ if (cineon->file == 0) {
+ if (verbose) d_printf("Couldn't open file %s\n", filename);
+ cineonClose(cineon);
+ return 0;
+ }
+ cineon->reading = 0;
+
+ cineon->width = width;
+ cineon->height = height;
+ cineon->depth = depth;
+ cineon->bitsPerPixel = 10;
+ cineon->imageOffset = sizeof(CineonGenericHeader);
+
+ cineon->lineBufferLength = pixelsToLongs(cineon->width * cineon->depth);
+ cineon->lineBuffer = malloc(cineon->lineBufferLength * 4);
+ if (cineon->lineBuffer == 0) {
+ if (verbose) d_printf("Couldn't malloc line buffer of size %d\n", cineon->lineBufferLength * 4);
+ cineonClose(cineon);
+ return 0;
+ }
+
+ cineon->pixelBuffer = malloc(cineon->lineBufferLength * 3 * sizeof(unsigned short));
+ if (cineon->pixelBuffer == 0) {
+ if (verbose) d_printf("Couldn't malloc pixel buffer of size %d\n",
+ (cineon->width * cineon->depth) * sizeof(unsigned short));
+ cineonClose(cineon);
+ return 0;
+ }
+ cineon->pixelBufferUsed = 0;
+
+ /* find trailing part of filename */
+ shortFilename = strrchr(filename, '/');
+ if (shortFilename == 0) {
+ shortFilename = filename;
+ } else {
+ ++shortFilename;
+ }
+
+ if (initCineonGenericHeader(cineon, &header, shortFilename) != 0) {
+ cineonClose(cineon);
+ return 0;
+ }
+
+ if (fwrite(&header, sizeof(header), 1, cineon->file) == 0) {
+ if (verbose) d_printf("Couldn't write image header\n");
+ cineonClose(cineon);
+ return 0;
+ }
+ cineon->fileYPos = 0;
+
+ logImageGetByteConversionDefaults(&cineon->params);
+ setupLut(cineon);
+
+ cineon->getRow = 0;
+ cineon->setRow = &cineonSetRowBytes;
+ cineon->close = &cineonClose;
+
+ return cineon;
+}
+
+void
+cineonClose(CineonFile* cineon) {
+
+ if (cineon == 0) {
+ return;
+ }
+
+ if (cineon->file) {
+ fclose(cineon->file);
+ cineon->file = 0;
+ }
+
+ if (cineon->lineBuffer) {
+ free(cineon->lineBuffer);
+ cineon->lineBuffer = 0;
+ }
+
+ if (cineon->pixelBuffer) {
+ free(cineon->pixelBuffer);
+ cineon->pixelBuffer = 0;
+ }
+
+ free(cineon);
+}
diff --git a/source/blender/imbuf/intern/cineon/cineonlib.h b/source/blender/imbuf/intern/cineon/cineonlib.h
new file mode 100644
index 00000000000..87fc7add9a6
--- /dev/null
+++ b/source/blender/imbuf/intern/cineon/cineonlib.h
@@ -0,0 +1,68 @@
+/*
+ * Cineon image file format library definitions.
+ * Also handles DPX files (almost)
+ *
+ * Copyright 1999,2000,2001 David Hodson <hodsond@acm.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef _CINEON_LIB_H_
+#define _CINEON_LIB_H_
+
+#include "logImageCore.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Cineon image structure. You don't care what this is.
+ */
+
+typedef struct _Log_Image_File_t_ CineonFile;
+
+/* int functions return 0 for OK */
+
+void cineonSetVerbose(int);
+
+CineonFile* cineonOpenFromMem(unsigned char *mem, unsigned int size);
+
+CineonFile* cineonOpen(const char* filename);
+int cineonGetSize(const CineonFile* cineon, int* xsize, int* ysize, int* channels);
+CineonFile* cineonCreate(const char* filename, int xsize, int ysize, int channels);
+int cineonIsMemFileCineon(unsigned char *mem);
+
+/* get / set header block NYI */
+int cineonGetHeader(CineonFile*, int*, void**);
+int cineonSetHeader(CineonFile*, int, void*);
+
+/* get/set scanline of converted bytes */
+int cineonGetRowBytes(CineonFile* cineon, unsigned short* row, int y);
+int cineonSetRowBytes(CineonFile* cineon, const unsigned short* row, int y);
+
+/* get/set scanline of unconverted shorts */
+int cineonGetRow(CineonFile* cineon, unsigned short* row, int y);
+int cineonSetRow(CineonFile* cineon, const unsigned short* row, int y);
+
+/* closes file and deletes data */
+void cineonClose(CineonFile* cineon);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CINEON_LIB_H_ */
diff --git a/source/blender/imbuf/intern/cineon/dpxfile.h b/source/blender/imbuf/intern/cineon/dpxfile.h
new file mode 100644
index 00000000000..94145500910
--- /dev/null
+++ b/source/blender/imbuf/intern/cineon/dpxfile.h
@@ -0,0 +1,124 @@
+/*
+ * Cineon image file format library definitions.
+ * Dpx file format structures.
+ *
+ * This header file contains private details.
+ * User code should generally use cineonlib.h only.
+ *
+ * Copyright 1999,2000,2001 David Hodson <hodsond@acm.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef _DPX_FILE_H_
+#define _DPX_FILE_H_
+
+#include "logImageCore.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+ U32 magic_num; /* magic number */
+ U32 offset; /* offset to image data in bytes */
+ ASCII vers[8]; /* which header format version is being used (v1.0) */
+ U32 file_size; /* file size in bytes */
+ U32 ditto_key; /* I bet some people use this */
+ U32 gen_hdr_size; /* generic header length in bytes */
+ U32 ind_hdr_size; /* industry header length in bytes */
+ U32 user_data_size; /* user-defined data length in bytes */
+ ASCII file_name[100]; /* image file name */
+ ASCII create_date[24]; /* file creation date, yyyy:mm:dd:hh:mm:ss:LTZ */
+ ASCII creator[100];
+ ASCII project[200];
+ ASCII copyright[200];
+ U32 key; /* encryption key, FFFFFFF = unencrypted */
+ ASCII Reserved[104]; /* reserved field TBD (need to pad) */
+} DpxFileInformation;
+
+typedef struct {
+ U32 signage;
+ U32 ref_low_data; /* reference low data code value */
+ R32 ref_low_quantity; /* reference low quantity represented */
+ U32 ref_high_data; /* reference high data code value */
+ R32 ref_high_quantity;/* reference high quantity represented */
+ U8 designator1;
+ U8 transfer_characteristics;
+ U8 colourimetry;
+ U8 bits_per_pixel;
+ U16 packing;
+ U16 encoding;
+ U32 data_offset;
+ U32 line_padding;
+ U32 channel_padding;
+ ASCII description[32];
+} DpxChannelInformation;
+
+typedef struct {
+ U16 orientation;
+ U16 channels_per_image;
+ U32 pixels_per_line;
+ U32 lines_per_image;
+ DpxChannelInformation channel[8];
+ ASCII reserved[52];
+} DpxImageInformation;
+
+typedef struct {
+ U32 x_offset;
+ U32 y_offset;
+ R32 x_centre;
+ R32 y_centre;
+ U32 x_original_size;
+ U32 y_original_size;
+ ASCII file_name[100];
+ ASCII creation_time[24];
+ ASCII input_device[32];
+ ASCII input_serial_number[32];
+ U16 border_validity[4];
+ U32 pixel_aspect_ratio[2]; /* h:v */
+ ASCII reserved[28];
+} DpxOriginationInformation;
+
+typedef struct {
+ ASCII film_manufacturer_id[2];
+ ASCII film_type[2];
+ ASCII edge_code_perforation_offset[2];
+ ASCII edge_code_prefix[6];
+ ASCII edge_code_count[4];
+ ASCII film_format[32];
+ U32 frame_position;
+ U32 sequence_length;
+ U32 held_count;
+ R32 frame_rate;
+ R32 shutter_angle;
+ ASCII frame_identification[32];
+ ASCII slate_info[100];
+ ASCII reserved[56];
+} DpxMPIInformation;
+
+typedef struct {
+ DpxFileInformation fileInfo;
+ DpxImageInformation imageInfo;
+ DpxOriginationInformation originInfo;
+ DpxMPIInformation filmHeader;
+} DpxMainHeader;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DPX_FILE_H_ */
diff --git a/source/blender/imbuf/intern/cineon/dpxlib.c b/source/blender/imbuf/intern/cineon/dpxlib.c
new file mode 100644
index 00000000000..b769d1e6132
--- /dev/null
+++ b/source/blender/imbuf/intern/cineon/dpxlib.c
@@ -0,0 +1,625 @@
+/*
+ * Dpx image file format library routines.
+ *
+ * Copyright 1999 - 2002 David Hodson <hodsond@acm.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "dpxfile.h"
+#include "dpxlib.h"
+
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <time.h> /* strftime() */
+#include <sys/types.h>
+#ifdef WIN32
+#include <winsock.h>
+#else
+#include <netinet/in.h> /* htonl() */
+#endif
+#include <string.h> /* memset */
+#include "cin_debug_stuff.h"
+#include "logmemfile.h"
+
+static void
+fillDpxChannelInfo(DpxFile* dpx, DpxChannelInformation* chan, int des) {
+
+ chan->signage = 0;
+ chan->ref_low_data = htonl(0);
+ chan->ref_low_quantity = htonf(0.0);
+ chan->ref_high_data = htonl(1023);
+ chan->ref_high_quantity = htonf(2.046);
+ chan->designator1 = des;
+ chan->transfer_characteristics = 0;
+ chan->colourimetry = 0;
+ chan->bits_per_pixel = 10;
+ chan->packing = htons(1);
+ chan->encoding = 0;
+ chan->data_offset = 0;
+ chan->line_padding = htonl(0);
+ chan->channel_padding = htonl(0);
+ chan->description[0] = 0;
+}
+
+static void
+dumpDpxChannelInfo(DpxChannelInformation* chan) {
+ d_printf(" Signage %ld", (long)ntohl(chan->signage));
+ d_printf(" Ref low data %ld\n", (long)ntohl(chan->ref_low_data));
+ d_printf(" Ref low quantity %f\n", ntohf(chan->ref_low_quantity));
+ d_printf(" Ref high data %ld\n", (long)ntohl(chan->ref_high_data));
+ d_printf(" Ref high quantity %f\n", ntohf(chan->ref_high_quantity));
+ d_printf(" Designator1: %d,", chan->designator1);
+ d_printf(" Bits per pixel %d\n", chan->bits_per_pixel);
+ d_printf(" Packing: %d,", ntohs(chan->packing));
+ d_printf(" Data Offset: %ld,", (long)ntohl(chan->data_offset));
+}
+
+static void
+fillDpxFileInfo(
+ DpxFile* dpx, DpxFileInformation* fileInfo, const char* filename) {
+
+ time_t fileClock;
+ struct tm* fileTime;
+
+ /* Note: always write files in network order */
+ /* By the spec, it shouldn't matter, but ... */
+
+ fileInfo->magic_num = htonl(DPX_FILE_MAGIC);
+ fileInfo->offset = htonl(dpx->imageOffset);
+ strcpy(fileInfo->vers, "v1.0");
+ fileInfo->file_size = htonl(dpx->imageOffset +
+ pixelsToLongs(dpx->height * dpx->width * dpx->depth) * 4);
+ fileInfo->ditto_key = 0;
+ fileInfo->gen_hdr_size = htonl(
+ sizeof(DpxFileInformation) +
+ sizeof(DpxImageInformation) +
+ sizeof(DpxOriginationInformation));
+ fileInfo->ind_hdr_size = htonl(sizeof(DpxMPIInformation));
+ fileInfo->user_data_size = 0;
+ strncpy(fileInfo->file_name, filename, 99);
+ fileInfo->file_name[99] = 0;
+
+ fileClock = time(0);
+ fileTime = localtime(&fileClock);
+ strftime(fileInfo->create_date, 24, "%Y:%m:%d:%H:%M:%S%Z", fileTime);
+ /* Question: is %Z in strftime guaranteed to return 3 chars? */
+ fileInfo->create_date[23] = 0;
+
+ strcpy(fileInfo->creator, "David's DPX writer");
+ fileInfo->project[0] = 0;
+ fileInfo->copyright[0] = 0;
+ fileInfo->key = 0xFFFFFFFF; /* same in any byte order */
+}
+
+static void
+dumpDpxFileInfo(DpxFileInformation* fileInfo) {
+ d_printf("\n--File Information--\n");
+ d_printf("Magic: %8.8lX\n", (unsigned long)ntohl(fileInfo->magic_num));
+ d_printf("Image Offset %ld\n", (long)ntohl(fileInfo->offset));
+ d_printf("Version \"%s\"\n", fileInfo->vers);
+ d_printf("File size %ld\n", (long)ntohl(fileInfo->file_size));
+ d_printf("Ditto key %ld\n", (long)ntohl(fileInfo->ditto_key));
+ d_printf("Generic Header size %ld\n", (long)ntohl(fileInfo->gen_hdr_size));
+ d_printf("Industry Header size %ld\n", (long)ntohl(fileInfo->ind_hdr_size));
+ d_printf("User Data size %ld\n", (long)ntohl(fileInfo->user_data_size));
+ d_printf("File name \"%s\"\n", fileInfo->file_name);
+ d_printf("Creation date \"%s\"\n", fileInfo->create_date);
+ d_printf("Creator \"%s\"\n", fileInfo->creator);
+ d_printf("Project \"%s\"\n", fileInfo->project);
+ d_printf("Copyright \"%s\"\n", fileInfo->copyright);
+ d_printf("Key %ld\n", (long)ntohl(fileInfo->key));
+}
+
+static void
+fillDpxImageInfo(
+ DpxFile* dpx, DpxImageInformation* imageInfo) {
+ imageInfo->orientation = 0;
+ imageInfo->channels_per_image = htons(1);
+ imageInfo->pixels_per_line = htonl(dpx->width);
+ imageInfo->lines_per_image = htonl(dpx->height);
+
+ if (dpx->depth == 1) {
+ fillDpxChannelInfo(dpx, &imageInfo->channel[0], 0);
+
+ } else if (dpx->depth == 3) {
+ fillDpxChannelInfo(dpx, &imageInfo->channel[0], 50);
+ }
+}
+
+static void
+dumpDpxImageInfo(DpxImageInformation* imageInfo) {
+
+ int n;
+ int i;
+ d_printf("\n--Image Information--\n");
+ d_printf("Image orientation %d,", ntohs(imageInfo->orientation));
+ n = ntohs(imageInfo->channels_per_image);
+ d_printf("Channels %d\n", n);
+ d_printf("Pixels per line %ld\n", (long)ntohl(imageInfo->pixels_per_line));
+ d_printf("Lines per image %ld\n", (long)ntohl(imageInfo->lines_per_image));
+ for (i = 0; i < n; ++i) {
+ d_printf(" --Channel %d--\n", i);
+ dumpDpxChannelInfo(&imageInfo->channel[i]);
+ }
+}
+
+static void
+fillDpxOriginationInfo(
+ DpxFile* dpx, DpxOriginationInformation* originInfo, DpxFileInformation* fileInfo) {
+}
+
+static void
+dumpDpxOriginationInfo(DpxOriginationInformation* originInfo) {
+ d_printf("\n--Origination Information--\n");
+ d_printf("X offset %ld\n", (long)ntohl(originInfo->x_offset));
+ d_printf("Y offset %ld\n", (long)ntohl(originInfo->y_offset));
+ d_printf("X centre %f\n", ntohf(originInfo->x_centre));
+ d_printf("Y centre %f\n", ntohf(originInfo->y_centre));
+ d_printf("Original X %ld\n", (long)ntohl(originInfo->x_original_size));
+ d_printf("Original Y %ld\n", (long)ntohl(originInfo->y_original_size));
+ d_printf("File name \"%s\"\n", originInfo->file_name);
+ d_printf("Creation time \"%s\"\n", originInfo->creation_time);
+ d_printf("Input device \"%s\"\n", originInfo->input_device);
+ d_printf("Serial number \"%s\"\n", originInfo->input_serial_number);
+}
+
+static void
+initDpxMainHeader(DpxFile* dpx, DpxMainHeader* header, const char* shortFilename) {
+ memset(header, 0, sizeof(DpxMainHeader));
+ fillDpxFileInfo(dpx, &header->fileInfo, shortFilename);
+ fillDpxImageInfo(dpx, &header->imageInfo);
+ fillDpxOriginationInfo(dpx, &header->originInfo, &header->fileInfo);
+#if 0
+ fillDpxMPIInfo(dpx, &header->filmHeader);
+#endif
+}
+
+static void
+dumpDpxMainHeader(DpxMainHeader* header) {
+ dumpDpxFileInfo(&header->fileInfo);
+ dumpDpxImageInfo(&header->imageInfo);
+ dumpDpxOriginationInfo(&header->originInfo);
+#if 0
+ dumpDpxMPIInformation(&header->filmHeader);
+#endif
+}
+
+static int verbose = 0;
+void
+dpxSetVerbose(int verbosity) {
+ verbose = verbosity;
+}
+
+static void
+verboseMe(DpxFile* dpx) {
+
+ d_printf("size %d x %d x %d\n", dpx->width, dpx->height, dpx->depth);
+ d_printf("ImageStart %d, lineBufferLength %d, implied length %d\n",
+ dpx->imageOffset, dpx->lineBufferLength * 4,
+ dpx->imageOffset + pixelsToLongs(dpx->width * dpx->depth * dpx->height) * 4);
+}
+
+int
+dpxGetRowBytes(DpxFile* dpx, unsigned short* row, int y) {
+
+ /* Note: this code is bizarre because DPX files can wrap */
+ /* packed longwords across line boundaries!!!! */
+
+ size_t readLongs;
+ unsigned int longIndex;
+ int numPixels = dpx->width * dpx->depth;
+ int pixelIndex;
+
+ /* only seek if not reading consecutive lines */
+ /* this is not quite right yet, need to account for leftovers */
+ if (y != dpx->fileYPos) {
+ int lineOffset = pixelsToLongs(y * dpx->width * dpx->depth) * 4;
+ if (verbose) d_printf("Seek in getRowBytes\n");
+ if (logimage_fseek(dpx, dpx->imageOffset + lineOffset, SEEK_SET) != 0) {
+ if (verbose) d_printf("Couldn't seek to line %d at %d\n", y, dpx->imageOffset + lineOffset);
+ return 1;
+ }
+ dpx->fileYPos = y;
+ }
+
+ /* read enough longwords */
+ readLongs = pixelsToLongs(numPixels - dpx->pixelBufferUsed);
+ if (logimage_fread(dpx->lineBuffer, 4, readLongs, dpx) != readLongs) {
+ if (verbose) d_printf("Couldn't read line %d length %d\n", y, readLongs * 4);
+ return 1;
+ }
+ ++dpx->fileYPos;
+
+ /* convert longwords to pixels */
+ pixelIndex = dpx->pixelBufferUsed;
+
+ /* this is just strange */
+ if (dpx->depth == 1) {
+ for (longIndex = 0; longIndex < readLongs; ++longIndex) {
+ unsigned int t = ntohl(dpx->lineBuffer[longIndex]);
+ dpx->pixelBuffer[pixelIndex] = t & 0x3ff;
+ t = t >> 10;
+ dpx->pixelBuffer[pixelIndex+1] = t & 0x3ff;
+ t = t >> 10;
+ dpx->pixelBuffer[pixelIndex+2] = t & 0x3ff;
+ pixelIndex += 3;
+ }
+ } else /* if (dpx->depth == 3) */ {
+ for (longIndex = 0; longIndex < readLongs; ++longIndex) {
+ unsigned int t = ntohl(dpx->lineBuffer[longIndex]);
+ t = t >> 2;
+ dpx->pixelBuffer[pixelIndex+2] = t & 0x3ff;
+ t = t >> 10;
+ dpx->pixelBuffer[pixelIndex+1] = t & 0x3ff;
+ t = t >> 10;
+ dpx->pixelBuffer[pixelIndex] = t & 0x3ff;
+ pixelIndex += 3;
+ }
+ }
+ dpx->pixelBufferUsed = pixelIndex;
+
+ /* extract required pixels */
+ for (pixelIndex = 0; pixelIndex < numPixels; ++pixelIndex) {
+ /* row[pixelIndex] = dpx->lut10[dpx->pixelBuffer[pixelIndex]]; */
+ row[pixelIndex] = dpx->pixelBuffer[pixelIndex] << 6;
+ }
+
+ /* save remaining pixels */
+ while (pixelIndex < dpx->pixelBufferUsed) {
+ dpx->pixelBuffer[pixelIndex - numPixels] = dpx->pixelBuffer[pixelIndex];
+ ++pixelIndex;
+ }
+ dpx->pixelBufferUsed -= numPixels;
+
+ /* done! */
+ return 0;
+}
+
+int
+dpxSetRowBytes(DpxFile* dpx, const unsigned short* row, int y) {
+
+ /* Note: this code is bizarre because DPX files can wrap */
+ /* packed longwords across line boundaries!!!! */
+
+ size_t writeLongs;
+ int longIndex;
+ int numPixels = dpx->width * dpx->depth;
+ int pixelIndex;
+ int pixelIndex2;
+
+ /* only seek if not reading consecutive lines */
+ /* this is not quite right yet */
+ if (y != dpx->fileYPos) {
+ int lineOffset = pixelsToLongs(y * dpx->width * dpx->depth) * 4;
+ if (verbose) d_printf("Seek in getRowBytes\n");
+ if (logimage_fseek(dpx, dpx->imageOffset + lineOffset, SEEK_SET) != 0) {
+ if (verbose) d_printf("Couldn't seek to line %d at %d\n", y, dpx->imageOffset + lineOffset);
+ return 1;
+ }
+ dpx->fileYPos = y;
+ }
+
+ /* put new pixels into pixelBuffer */
+ for (pixelIndex = 0; pixelIndex < numPixels; ++pixelIndex) {
+ /* dpx->pixelBuffer[dpx->pixelBufferUsed + pixelIndex] = dpx->lut8[row[pixelIndex]]; */
+ dpx->pixelBuffer[dpx->pixelBufferUsed + pixelIndex] = row[pixelIndex] >> 6;
+ }
+ dpx->pixelBufferUsed += numPixels;
+
+ /* pack into longwords */
+ writeLongs = dpx->pixelBufferUsed / 3;
+ /* process whole line at image end */
+ if (dpx->fileYPos == (dpx->height - 1)) {
+ writeLongs = pixelsToLongs(dpx->pixelBufferUsed);
+ }
+ pixelIndex = 0;
+ if (dpx->depth == 1) {
+ for (longIndex = 0; longIndex < writeLongs; ++longIndex) {
+ unsigned int t = dpx->pixelBuffer[pixelIndex] |
+ (dpx->pixelBuffer[pixelIndex+1] << 10) |
+ (dpx->pixelBuffer[pixelIndex+2] << 20);
+ dpx->lineBuffer[longIndex] = htonl(t);
+ pixelIndex += 3;
+ }
+ } else {
+ for (longIndex = 0; longIndex < writeLongs; ++longIndex) {
+ unsigned int t = dpx->pixelBuffer[pixelIndex+2] << 2 |
+ (dpx->pixelBuffer[pixelIndex+1] << 12) |
+ (dpx->pixelBuffer[pixelIndex] << 22);
+ dpx->lineBuffer[longIndex] = htonl(t);
+ pixelIndex += 3;
+ }
+ }
+
+ /* write them */
+ if (fwrite(dpx->lineBuffer, 4, writeLongs, dpx->file) != writeLongs) {
+ if (verbose) d_printf("Couldn't write line %d length %d\n", y, writeLongs * 4);
+ return 1;
+ }
+ ++dpx->fileYPos;
+
+ /* save remaining pixels */
+ pixelIndex2 = 0;
+ while (pixelIndex < dpx->pixelBufferUsed) {
+ dpx->pixelBuffer[pixelIndex2] = dpx->pixelBuffer[pixelIndex];
+ ++pixelIndex;
+ ++pixelIndex2;
+ }
+ dpx->pixelBufferUsed = pixelIndex2;
+
+ return 0;
+}
+
+#define LFMEMFILE 0
+#define LFREALFILE 1
+
+static DpxFile*
+intern_dpxOpen(int mode, const char* bytestuff, int bufsize) {
+
+ DpxMainHeader header;
+ const char *filename = bytestuff;
+ DpxFile* dpx = (DpxFile*)malloc(sizeof(DpxFile));
+
+ if (dpx == 0) {
+ if (verbose) d_printf("Failed to malloc dpx file structure.\n");
+ return 0;
+ }
+
+ /* for close routine */
+ dpx->file = 0;
+ dpx->lineBuffer = 0;
+ dpx->pixelBuffer = 0;
+
+ if (mode == LFREALFILE) {
+ filename = bytestuff;
+ dpx->file = fopen(filename, "rb");
+ if (dpx->file == 0) {
+ if (verbose) d_printf("Failed to open file \"%s\".\n", filename);
+ dpxClose(dpx);
+ return 0;
+ }
+ dpx->membuffer = 0;
+ dpx->memcursor = 0;
+ dpx->membuffersize = 0;
+ } else if (mode == LFMEMFILE) {
+ dpx->membuffer = (unsigned char *)bytestuff;
+ dpx->memcursor = (unsigned char *)bytestuff;
+ dpx->membuffersize = bufsize;
+ }
+
+ dpx->reading = 1;
+
+ if (logimage_fread(&header, sizeof(header), 1, dpx) == 0) {
+ if (verbose) d_printf("Not enough data for header in \"%s\".\n", filename);
+ dpxClose(dpx);
+ return 0;
+ }
+
+ /* let's assume dpx files are always network order */
+ if (header.fileInfo.magic_num != ntohl(DPX_FILE_MAGIC)) {
+ if (verbose) d_printf("Bad magic number %8.8lX in \"%s\".\n",
+ (unsigned long)ntohl(header.fileInfo.magic_num), filename);
+ dpxClose(dpx);
+ return 0;
+ }
+
+ if (ntohs(header.imageInfo.channel[0].packing) != 1) {
+ if (verbose) d_printf("Unknown packing %d\n", header.imageInfo.channel[0].packing);
+ dpxClose(dpx);
+ return 0;
+ }
+
+
+ dpx->width = ntohl(header.imageInfo.pixels_per_line);
+ dpx->height = ntohl(header.imageInfo.lines_per_image);
+ dpx->depth = ntohs(header.imageInfo.channels_per_image);
+ /* Another DPX vs Cineon wierdness */
+ if (dpx->depth == 1) {
+ switch (header.imageInfo.channel[0].designator1) {
+ case 50: dpx->depth = 3; break;
+ case 51: dpx->depth = 4; break;
+ case 52: dpx->depth = 4; break;
+ default: break;
+ }
+ }
+ dpx->bitsPerPixel = 10;
+ /* dpx->bitsPerPixel = header.imageInfo.channel[0].bits_per_pixel; */
+ dpx->imageOffset = ntohl(header.fileInfo.offset);
+
+ dpx->lineBufferLength = pixelsToLongs(dpx->width * dpx->depth);
+ dpx->lineBuffer = malloc(dpx->lineBufferLength * 4);
+ if (dpx->lineBuffer == 0) {
+ if (verbose) d_printf("Couldn't malloc line buffer of size %d\n", dpx->lineBufferLength * 4);
+ dpxClose(dpx);
+ return 0;
+ }
+
+ /* could have 2 pixels left over */
+ dpx->pixelBuffer = malloc((dpx->lineBufferLength * 3 + 2) * sizeof(unsigned short));
+ if (dpx->pixelBuffer == 0) {
+ if (verbose) d_printf("Couldn't malloc pixel buffer of size %d\n",
+ (dpx->width * dpx->depth + 2 + 2) * sizeof(unsigned short));
+ dpxClose(dpx);
+ return 0;
+ }
+ dpx->pixelBufferUsed = 0;
+
+ if (logimage_fseek(dpx, dpx->imageOffset, SEEK_SET) != 0) {
+ if (verbose) d_printf("Couldn't seek to image data start at %d\n", dpx->imageOffset);
+ dpxClose(dpx);
+ return 0;
+ }
+ dpx->fileYPos = 0;
+
+ logImageGetByteConversionDefaults(&dpx->params);
+ setupLut(dpx);
+
+ dpx->getRow = &dpxGetRowBytes;
+ dpx->setRow = 0;
+ dpx->close = &dpxClose;
+
+ if (verbose) {
+ verboseMe(dpx);
+ }
+
+ return dpx;
+}
+
+DpxFile*
+dpxOpen(const char *filename) {
+ return intern_dpxOpen(LFREALFILE, filename, 0);
+}
+
+DpxFile*
+dpxOpenFromMem(unsigned char *buffer, unsigned int size) {
+ return intern_dpxOpen(LFMEMFILE, (const char *) buffer, size);
+}
+
+int
+dpxIsMemFileCineon(void *buffer) {
+ int magicnum = 0;
+ magicnum = *((int*)buffer);
+ if (magicnum == ntohl(DPX_FILE_MAGIC)) return 1;
+ else return 0;
+}
+
+DpxFile*
+dpxCreate(const char* filename, int width, int height, int depth) {
+
+ /* Note: always write files in network order */
+ /* By the spec, it shouldn't matter, but ... */
+
+ DpxMainHeader header;
+ const char* shortFilename = 0;
+
+ DpxFile* dpx = (DpxFile*)malloc(sizeof(DpxFile));
+ if (dpx == 0) {
+ if (verbose) d_printf("Failed to malloc dpx file structure.\n");
+ return 0;
+ }
+
+ memset(&header, 0, sizeof(header));
+
+ /* for close routine */
+ dpx->file = 0;
+ dpx->lineBuffer = 0;
+ dpx->pixelBuffer = 0;
+
+ dpx->file = fopen(filename, "wb");
+ if (dpx->file == 0) {
+ if (verbose) d_printf("Couldn't open file %s\n", filename);
+ dpxClose(dpx);
+ return 0;
+ }
+ dpx->reading = 0;
+
+ dpx->width = width;
+ dpx->height = height;
+ dpx->depth = depth;
+ dpx->bitsPerPixel = 10;
+ dpx->imageOffset = sizeof(DpxMainHeader);
+
+ dpx->lineBufferLength = pixelsToLongs(dpx->width * dpx->depth);
+ dpx->lineBuffer = malloc(dpx->lineBufferLength * 4);
+ if (dpx->lineBuffer == 0) {
+ if (verbose) d_printf("Couldn't malloc line buffer of size %d\n", dpx->lineBufferLength * 4);
+ dpxClose(dpx);
+ return 0;
+ }
+
+ dpx->pixelBuffer = malloc((dpx->lineBufferLength * 3 + 2) * sizeof(unsigned short));
+ if (dpx->pixelBuffer == 0) {
+ if (verbose) d_printf("Couldn't malloc pixel buffer of size %d\n",
+ (dpx->width * dpx->depth + 2 + 2) * sizeof(unsigned short));
+ dpxClose(dpx);
+ return 0;
+ }
+ dpx->pixelBufferUsed = 0;
+
+ /* find trailing part of filename */
+ shortFilename = strrchr(filename, '/');
+ if (shortFilename == 0) {
+ shortFilename = filename;
+ } else {
+ ++shortFilename;
+ }
+ initDpxMainHeader(dpx, &header, shortFilename);
+
+ if (fwrite(&header, sizeof(header), 1, dpx->file) == 0) {
+ if (verbose) d_printf("Couldn't write image header\n");
+ dpxClose(dpx);
+ return 0;
+ }
+ dpx->fileYPos = 0;
+
+ logImageGetByteConversionDefaults(&dpx->params);
+ setupLut(dpx);
+
+ dpx->getRow = 0;
+ dpx->setRow = &dpxSetRowBytes;
+ dpx->close = &dpxClose;
+
+ return dpx;
+}
+
+void
+dpxClose(DpxFile* dpx) {
+
+ if (dpx == 0) {
+ return;
+ }
+
+ if (dpx->file) {
+ fclose(dpx->file);
+ dpx->file = 0;
+ }
+
+ if (dpx->lineBuffer) {
+ free(dpx->lineBuffer);
+ dpx->lineBuffer = 0;
+ }
+
+ if (dpx->pixelBuffer) {
+ free(dpx->pixelBuffer);
+ dpx->pixelBuffer = 0;
+ }
+
+ free(dpx);
+}
+
+void
+dpxDump(const char* filename) {
+
+ DpxMainHeader header;
+ FILE* file;
+
+ file = fopen(filename, "rb");
+ if (file == 0) {
+ d_printf("Failed to open file \"%s\".\n", filename);
+ return;
+ }
+
+ if (fread(&header, sizeof(header), 1, file) == 0) {
+ d_printf("Not enough data for header in \"%s\".\n", filename);
+ fclose(file);
+ return;
+ }
+
+ fclose(file);
+ dumpDpxMainHeader(&header);
+}
diff --git a/source/blender/imbuf/intern/cineon/dpxlib.h b/source/blender/imbuf/intern/cineon/dpxlib.h
new file mode 100644
index 00000000000..25fe84e2296
--- /dev/null
+++ b/source/blender/imbuf/intern/cineon/dpxlib.h
@@ -0,0 +1,56 @@
+/*
+ * DPX image file format library definitions.
+ *
+ * Copyright 1999 - 2002 David Hodson <hodsond@acm.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef _DPX_LIB_H_
+#define _DPX_LIB_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "logImageCore.h"
+
+typedef struct _Log_Image_File_t_ DpxFile;
+
+/* int functions return 0 for OK */
+
+void dpxSetVerbose(int);
+
+DpxFile* dpxOpen(const char* filename);
+DpxFile* dpxCreate(const char* filename, int xsize, int ysize, int channels);
+DpxFile* dpxOpenFromMem(unsigned char *buffer, unsigned int size);
+int dpxIsMemFileCineon(void *buffer);
+
+/* get/set scanline of converted bytes */
+int dpxGetRowBytes(DpxFile* dpx, unsigned short* row, int y);
+int dpxSetRowBytes(DpxFile* dpx, const unsigned short* row, int y);
+
+/* closes file and deletes data */
+void dpxClose(DpxFile* dpx);
+
+/* dumps file to stdout */
+void dpxDump(const char* filename);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DPX_LIB_H_ */
diff --git a/source/blender/imbuf/intern/cineon/logImageCore.c b/source/blender/imbuf/intern/cineon/logImageCore.c
new file mode 100644
index 00000000000..e88e9241443
--- /dev/null
+++ b/source/blender/imbuf/intern/cineon/logImageCore.c
@@ -0,0 +1,212 @@
+/*
+ * Cineon image file format library routines.
+ *
+ * Copyright 1999,2000,2001 David Hodson <hodsond@acm.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "logImageCore.h"
+
+#include <time.h> /* strftime() */
+#include <math.h>
+/* Makes rint consistent in Windows and Linux: */
+#define rint(x) floor(x+0.5)
+
+#ifdef WIN32
+#include <winsock.h>
+#else
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/param.h>
+#endif
+
+#if defined(__hpux)
+/* These are macros in hpux */
+#ifdef htonl
+#undef htonl
+#undef htons
+#undef ntohl
+#undef ntohs
+#endif
+unsigned int htonl(h) unsigned int h; { return(h); }
+unsigned short htons(h) unsigned short h; { return(h); }
+unsigned int ntohl(n) unsigned int n; { return(n); }
+unsigned short ntohs(n) unsigned short n; { return(n); }
+#endif
+
+
+/* obscure LogImage conversion */
+/* from 10 bit int to 0.0 - 1.0 */
+/* magic numbers left intact */
+static double
+convertTo(int inp, int white, float gamma) {
+ /* return pow(pow(10.0, ((inp - white) * 0.002 / 0.6)), gamma); */
+ return pow(10.0, (inp - white) * gamma * 0.002 / 0.6);
+}
+
+static double
+convertFrom(double inp, int white, float gamma) {
+ return white + log10(inp) / (gamma * 0.002 / 0.6);
+}
+
+/* set up the 10 bit to 8 bit and 8 bit to 10 bit tables */
+void
+setupLut(LogImageFile *logImage) {
+
+ int i;
+ double f_black;
+ double scale;
+
+ f_black = convertTo(logImage->params.blackPoint, logImage->params.whitePoint, logImage->params.gamma);
+ scale = 255.0 / (1.0 - f_black);
+
+ for (i = 0; i <= logImage->params.blackPoint; ++i) {
+ logImage->lut10[i] = 0;
+ }
+ for (; i < logImage->params.whitePoint; ++i) {
+ double f_i;
+ f_i = convertTo(i, logImage->params.whitePoint, logImage->params.gamma);
+ logImage->lut10[i] = (int)rint(scale * (f_i - f_black));
+ }
+ for (; i < 1024; ++i) {
+ logImage->lut10[i] = 255;
+ }
+
+ for (i = 0; i < 256; ++i) {
+ double f_i = f_black + (i / 255.0) * (1.0 - f_black);
+ logImage->lut8[i] = convertFrom(f_i, logImage->params.whitePoint, logImage->params.gamma);
+ }
+}
+
+/* how many longwords to hold this many pixels? */
+int
+pixelsToLongs(int numPixels) {
+ return (numPixels + 2) / 3;
+}
+
+/* byte reversed float */
+
+typedef union {
+ U32 i;
+ R32 f;
+} Hack;
+
+R32
+htonf(R32 f) {
+ Hack hack;
+ hack.f = f;
+ hack.i = htonl(hack.i);
+ return hack.f;
+}
+
+R32
+ntohf(R32 f) {
+ Hack hack;
+ hack.f = f;
+ hack.i = ntohl(hack.i);
+ return hack.f;
+}
+
+#define UNDEF_FLOAT 0x7F800000
+
+R32
+undefined() {
+ Hack hack;
+ hack.i = UNDEF_FLOAT;
+ return hack.f;
+}
+
+/* reverse an endian-swapped U16 */
+U16
+reverseU16(U16 value) {
+
+ union {
+ U16 whole;
+ char part[2];
+ } buff;
+ char temp;
+ buff.whole = value;
+ temp = buff.part[0];
+ buff.part[0] = buff.part[1];
+ buff.part[1] = temp;
+ return buff.whole;
+}
+
+/* reverse an endian-swapped U32 */
+U32
+reverseU32(U32 value) {
+
+ union {
+ U32 whole;
+ char part[4];
+ } buff;
+ char temp;
+ buff.whole = value;
+ temp = buff.part[0];
+ buff.part[0] = buff.part[3];
+ buff.part[3] = temp;
+ temp = buff.part[1];
+ buff.part[1] = buff.part[2];
+ buff.part[2] = temp;
+ return buff.whole;
+}
+
+/* reverse an endian-swapped R32 */
+R32
+reverseR32(R32 value) {
+
+ union {
+ R32 whole;
+ char part[4];
+ } buff;
+ char temp;
+ buff.whole = value;
+ temp = buff.part[0];
+ buff.part[0] = buff.part[3];
+ buff.part[3] = temp;
+ temp = buff.part[1];
+ buff.part[1] = buff.part[2];
+ buff.part[2] = temp;
+ return buff.whole;
+}
+
+#if 0
+/* bytes per line for images packed 3 10 bit pixels to 32 bits, 32 bit aligned */
+int
+bytesPerLine_10_4(int numPixels) {
+ return ((numPixels + 2) / 3) * 4;
+}
+
+void
+seekLine_noPadding(LogImageFile* logImage, int lineNumber) {
+ int fileOffset = bytesPerLine_10_4(lineNumber * logImage->width * logImage->depth);
+ int filePos = logImage->imageOffset + fileOffset;
+ if (fseek(logImage->file, filePos, SEEK_SET) != 0) {
+ /* complain? */
+ }
+}
+
+void
+seekLine_padding(LogImageFile* logImage, int lineNumber) {
+ int fileOffset = lineNumber * bytesPerLine_10_4(logImage->width * logImage->depth);
+ int filePos = logImage->imageOffset + fileOffset;
+ if (fseek(logImage->file, filePos, SEEK_SET) != 0) {
+ /* complain? */
+ }
+}
+#endif
diff --git a/source/blender/imbuf/intern/cineon/logImageCore.h b/source/blender/imbuf/intern/cineon/logImageCore.h
new file mode 100644
index 00000000000..1af18d5e3b8
--- /dev/null
+++ b/source/blender/imbuf/intern/cineon/logImageCore.h
@@ -0,0 +1,109 @@
+/*
+ * Cineon image file format library definitions.
+ * Cineon and DPX common structures.
+ *
+ * This header file contains private details.
+ * User code should generally use cineonlib.h and dpxlib.h only.
+ * Hmm. I thought the two formats would have more in common!
+ *
+ * Copyright 1999,2000,2001 David Hodson <hodsond@acm.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef _LOG_IMAGE_CORE_H_
+#define _LOG_IMAGE_CORE_H_
+
+#include <stdio.h>
+#include "logImageLib.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef int (GetRowFn)(LogImageFile* logImage, unsigned short* row, int lineNum);
+typedef int (SetRowFn)(LogImageFile* logImage, const unsigned short* row, int lineNum);
+typedef void (CloseFn)(LogImageFile* logImage);
+
+struct _Log_Image_File_t_
+{
+ /* specified in header */
+ int width;
+ int height;
+ int depth;
+ int bitsPerPixel;
+ int imageOffset;
+
+ /* file buffer, measured in longwords (4 byte) */
+ int lineBufferLength;
+ unsigned int* lineBuffer;
+
+ /* pixel buffer, holds 10 bit pixel values */
+ unsigned short* pixelBuffer;
+ int pixelBufferUsed;
+
+ /* io stuff */
+ FILE* file;
+ int reading;
+ int fileYPos;
+
+ /* byte conversion stuff */
+ LogImageByteConversionParameters params;
+#if 0
+ float gamma;
+ int blackPoint;
+ int whitePoint;
+#endif
+ unsigned char lut10[1024];
+ unsigned short lut8[256];
+
+ /* pixel access functions */
+ GetRowFn* getRow;
+ SetRowFn* setRow;
+ CloseFn* close;
+
+ unsigned char *membuffer;
+ unsigned long membuffersize;
+ unsigned char *memcursor;
+};
+
+void setupLut(LogImageFile*);
+
+int pixelsToLongs(int numPixels);
+
+/* typedefs used in original docs */
+/* note size assumptions! */
+
+typedef unsigned int U32;
+typedef unsigned short U16;
+typedef unsigned char U8;
+typedef signed int S32;
+typedef float R32;
+typedef char ASCII;
+
+R32 htonf(R32 f);
+R32 ntohf(R32 f);
+R32 undefined();
+U16 reverseU16(U16 value);
+U32 reverseU32(U32 value);
+R32 reverseR32(R32 value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LOG_IMAGE_CORE_H_ */
diff --git a/source/blender/imbuf/intern/cineon/logImageLib.c b/source/blender/imbuf/intern/cineon/logImageLib.c
new file mode 100644
index 00000000000..ff209d5ebd0
--- /dev/null
+++ b/source/blender/imbuf/intern/cineon/logImageLib.c
@@ -0,0 +1,158 @@
+/*
+ * Cineon and DPX image file format library routines.
+ *
+ * Copyright 1999 - 2002 David Hodson <hodsond@acm.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "cineonlib.h"
+#include "dpxlib.h"
+
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <time.h> /* strftime() */
+#include <sys/types.h>
+#ifdef WIN32
+#include <winsock.h>
+#else
+#include <netinet/in.h> /* htonl() */
+#endif
+#include <string.h> /* memset */
+
+#define MIN_GAMMA 0.01
+#define MAX_GAMMA 99.9
+#define DEFAULT_GAMMA 1.0
+#define DEFAULT_BLACK_POINT 95
+#define DEFAULT_WHITE_POINT 685
+
+void
+logImageSetVerbose(int verbosity) {
+ cineonSetVerbose(verbosity);
+ dpxSetVerbose(verbosity);
+}
+
+LogImageFile*
+logImageOpen(const char* filename, int cineon) {
+ if (cineon) {
+ return cineonOpen(filename);
+ } else {
+ return dpxOpen(filename);
+ }
+ return 0;
+}
+
+LogImageFile*
+logImageOpenFromMem(unsigned char *buffer, unsigned int size, int cineon) {
+ if (cineon) {
+ return cineonOpenFromMem(buffer, size);
+ } else {
+ return dpxOpenFromMem(buffer, size);
+ }
+ return 0;
+}
+
+LogImageFile*
+logImageCreate(const char* filename, int cineon, int width, int height, int depth) {
+ if (cineon) {
+ return cineonCreate(filename, width, height, depth);
+ } else {
+ return dpxCreate(filename, width, height, depth);
+ }
+ return 0;
+}
+
+int
+logImageGetSize(const LogImageFile* logImage, int* width, int* height, int* depth) {
+ *width = logImage->width;
+ *height = logImage->height;
+ *depth = logImage->depth;
+ return 0;
+}
+
+int
+logImageGetByteConversionDefaults(LogImageByteConversionParameters* params) {
+ params->gamma = DEFAULT_GAMMA;
+ params->blackPoint = DEFAULT_BLACK_POINT;
+ params->whitePoint = DEFAULT_WHITE_POINT;
+ return 0;
+}
+
+int
+logImageGetByteConversion(const LogImageFile* logImage, LogImageByteConversionParameters* params) {
+ params->gamma = logImage->params.gamma;
+ params->blackPoint = logImage->params.blackPoint;
+ params->whitePoint = logImage->params.whitePoint;
+ return 0;
+}
+
+int
+logImageSetByteConversion(LogImageFile* logImage, const LogImageByteConversionParameters* params) {
+ if ((params->gamma >= MIN_GAMMA) &&
+ (params->gamma <= MAX_GAMMA) &&
+ (params->blackPoint >= 0) &&
+ (params->blackPoint < params->whitePoint) &&
+ (params->whitePoint <= 1023)) {
+ logImage->params.gamma = params->gamma;
+ logImage->params.blackPoint = params->blackPoint;
+ logImage->params.whitePoint = params->whitePoint;
+ setupLut(logImage);
+ return 0;
+ }
+ return 1;
+}
+
+int
+logImageGetRowBytes(LogImageFile* logImage, unsigned short* row, int y) {
+ return logImage->getRow(logImage, row, y);
+}
+
+int
+logImageSetRowBytes(LogImageFile* logImage, const unsigned short* row, int y) {
+ return logImage->setRow(logImage, row, y);
+}
+
+void
+logImageClose(LogImageFile* logImage) {
+ logImage->close(logImage);
+}
+
+void
+logImageDump(const char* filename) {
+
+ U32 magic;
+
+ FILE* foo = fopen(filename, "rb");
+ if (foo == 0) {
+ return;
+ }
+
+ if (fread(&magic, sizeof(magic), 1, foo) == 0) {
+ fclose(foo);
+ return;
+ }
+
+ fclose(foo);
+
+ if (magic == ntohl(CINEON_FILE_MAGIC)) {
+#if 0
+ cineonDump(filename);
+#endif
+ } else if (magic == ntohl(DPX_FILE_MAGIC)) {
+ dpxDump(filename);
+ }
+}
diff --git a/source/blender/imbuf/intern/cineon/logImageLib.h b/source/blender/imbuf/intern/cineon/logImageLib.h
new file mode 100644
index 00000000000..ea45c675fe2
--- /dev/null
+++ b/source/blender/imbuf/intern/cineon/logImageLib.h
@@ -0,0 +1,86 @@
+/*
+ * Common library definitions for Cineon and DPX image files.
+ *
+ * Copyright 1999,2000,2001 David Hodson <hodsond@acm.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef _LOG_IMAGE_LIB_H_
+#define _LOG_IMAGE_LIB_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Image structure. You don't care what this is.
+ */
+
+typedef struct _Log_Image_File_t_ LogImageFile;
+
+/*
+ * Magic numbers for normal and byte-swapped Cineon and Dpx files
+ */
+
+#define CINEON_FILE_MAGIC 0x802A5FD7
+#define DPX_FILE_MAGIC 0x53445058
+
+/*
+ * Image 8 bit <-> 10 bit conversion parameters.
+ */
+
+typedef struct {
+ float gamma;
+ int blackPoint;
+ int whitePoint;
+} LogImageByteConversionParameters;
+
+/* int functions return 0 for OK */
+
+void logImageSetVerbose(int);
+
+LogImageFile* logImageOpenFromMem(unsigned char *buffer, unsigned int size, int cineon);
+LogImageFile* logImageOpen(const char* filename, int cineon);
+int logImageGetSize(const LogImageFile* logImage, int* xsize, int* ysize, int* channels);
+LogImageFile* logImageCreate(const char* filename, int cineon, int xsize, int ysize, int channels);
+
+/* get / set header block NYI */
+int logImageGetHeader(LogImageFile*, int*, void**);
+int logImageSetHeader(LogImageFile*, int, void*);
+
+/* byte conversion routines for mapping logImage (usually) 10 bit values to 8 bit */
+/* see Kodak docs for details... */
+
+int logImageGetByteConversionDefaults(LogImageByteConversionParameters* params);
+int logImageGetByteConversion(const LogImageFile* logImage, LogImageByteConversionParameters* params);
+int logImageSetByteConversion(LogImageFile* logImage, const LogImageByteConversionParameters* params);
+
+/* get/set scanline of converted bytes */
+int logImageGetRowBytes(LogImageFile* logImage, unsigned short* row, int y);
+int logImageSetRowBytes(LogImageFile* logImage, const unsigned short* row, int y);
+
+/* closes file and deletes data */
+void logImageClose(LogImageFile* logImage);
+
+/* read file and dump header info */
+void logImageDump(const char* filename);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LOG_IMAGE_LIB_H_ */
diff --git a/source/blender/imbuf/intern/cineon/logmemfile.c b/source/blender/imbuf/intern/cineon/logmemfile.c
new file mode 100644
index 00000000000..20359335933
--- /dev/null
+++ b/source/blender/imbuf/intern/cineon/logmemfile.c
@@ -0,0 +1,77 @@
+/*
+ * Cineon image file format library routines.
+ *
+ * Copyright 2006 Joseph Eagar (joeedh@gmail.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "logImageCore.h"
+
+int logimage_fseek(void* logfile, long offsett, int origin)
+{
+ struct _Log_Image_File_t_ *file = (struct _Log_Image_File_t_*) logfile;
+ long offset = offsett;
+
+ if (file->file) fseek(file->file, offset, origin);
+ else { /*we're seeking in memory*/
+ if (origin==SEEK_SET) {
+ if (offset > file->membuffersize) return 1;
+ file->memcursor = file->membuffer + offset;
+ } else if (origin==SEEK_END) {
+ if (offset > file->membuffersize) return 1;
+ file->memcursor = (file->membuffer + file->membuffersize) - offset;
+ } else if (origin==SEEK_CUR) {
+ unsigned long pos = (unsigned long)file->membuffer - (unsigned long)file->memcursor;
+ if (pos + offset > file->membuffersize) return 1;
+ if (pos < 0) return 1;
+ file->memcursor += offset;
+ }
+ }
+ return 0;
+}
+
+int logimage_fwrite(void *buffer, unsigned int size, unsigned int count, void *logfile)
+{
+ struct _Log_Image_File_t_ *file = (struct _Log_Image_File_t_*) logfile;
+ if (file->file) return fwrite(buffer, size, count, file->file);
+ else { /*we're writing to memory*/
+ /*do nothing as this isn't supported yet*/
+ return count;
+ }
+}
+
+int logimage_fread(void *buffer, unsigned int size, unsigned int count, void *logfile)
+{
+ struct _Log_Image_File_t_ *file = (struct _Log_Image_File_t_*) logfile;
+ if (file->file) return fread(buffer, size, count, file->file);
+ else { /*we're reading from memory*/
+ int i;
+ /*we convert ot uchar just on the off chance some platform can't handle
+ pointer arithmetic with type (void*). */
+ unsigned char *buf = (unsigned char *) buffer;
+
+ for (i=0; i<count; i++) {
+ memcpy(buf, file->memcursor, size);
+ file->memcursor += size;
+ buf += size;
+ }
+ return count;
+ }
+}
diff --git a/source/blender/imbuf/intern/cineon/logmemfile.h b/source/blender/imbuf/intern/cineon/logmemfile.h
new file mode 100644
index 00000000000..6e82cf2b145
--- /dev/null
+++ b/source/blender/imbuf/intern/cineon/logmemfile.h
@@ -0,0 +1,29 @@
+/*
+ * Cineon image file format library routines.
+ *
+ * Copyright 2006 Joseph Eagar (joeedh@gmail.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef _LOGMEMFILE_H
+#define _LOGMEMFILE_H
+
+int logimage_fseek(void* logfile, long offsett, int origin);
+int logimage_fwrite(void *buffer, unsigned int size, unsigned int count, void *logfile);
+int logimage_fread(void *buffer, unsigned int size, unsigned int count, void *logfile);
+
+#endif /* _LOGMEMFILE_H */
diff --git a/source/blender/imbuf/intern/cmap.c b/source/blender/imbuf/intern/cmap.c
new file mode 100644
index 00000000000..7b4962d8837
--- /dev/null
+++ b/source/blender/imbuf/intern/cmap.c
@@ -0,0 +1,583 @@
+/**
+ * cmap.c
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <ctype.h>
+#include "BLI_blenlib.h"
+
+#include "imbuf.h"
+#include "imbuf_patch.h"
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "IMB_cmap.h"
+
+static short *lastcube = 0;
+static uchar *lastcoltab = 0;
+static short lastmaxcol;
+static short lastmincol;
+static short lastcbits;
+short alpha_col0 = FALSE;
+
+extern void IMB_free_cache_limiter();
+
+/*
+ * there still is a bug here. If you want to convert an image to a 1 bit colormap you get
+ * a black image. All conversion to less than 4 bits is too dark anyway.
+ */
+
+void IMB_freeImBufdata(void)
+{
+ if (lastcube) free(lastcube);
+ lastcube= 0;
+ if (lastcoltab) free(lastcoltab);
+ lastcoltab= 0;
+ IMB_free_cache_limiter();
+}
+
+
+int IMB_alpha_to_col0(int value)
+{
+ int old;
+
+ old = alpha_col0;
+ alpha_col0 = value;
+ return (old);
+}
+
+
+void imb_losecmapbits(struct ImBuf *ibuf, unsigned int *coltab)
+{
+ int i,bits;
+ unsigned int col, and1, and2, *rect;
+
+ if (ibuf == 0) return;
+ if (ibuf->rect == 0) return;
+ if (ibuf->cbits == 0) return;
+ if (ibuf->cbits >= 8) return;
+
+/*
+ bij cbits = 5:
+ and1 = 11100000;
+ bij cbits = 6:
+ and1 = 11000000;
+*/
+
+ bits = ibuf->cbits;
+ and1 = ((1 << (8-bits)) - 1) & 0xff;
+ and1 |= (and1 << 24) + (and1 << 16) + (and1 << 8);
+ and2 = ~and1;
+ and1 <<= bits;
+
+ rect = ibuf->rect;
+ for (i = ibuf->x * ibuf->y ; i > 0; i--) {
+ col = rect[0];
+ *rect++ = col - ((col & and1) >> bits);
+ }
+
+ if (coltab){
+ for (i = 0 ; i < ibuf->maxcol ; i++) {
+ col = coltab[i];
+ coltab[i] = (col - ((col & and1) >> bits)) & and2;
+ }
+ }
+}
+
+
+static void addcmapbits(struct ImBuf *ibuf)
+{
+ int i,bits;
+ int div,mul;
+ uchar * cmap;
+
+ if (ibuf == 0) return;
+ if (ibuf->cmap == 0) return;
+ if (ibuf->cbits == 0) return;
+ if (ibuf->cbits >= 8) return;
+
+ bits = ibuf->cbits;
+
+ /* bits = 4 -> div = 0xf0
+ * bits = 5 -> div = 0xf8
+ */
+
+ div = ((1 << bits) - 1) << (8 - bits);
+ mul = 0xffff / div;
+
+ if (ibuf->cmap){
+ cmap = (uchar *) ibuf->cmap;
+ for (i = 0 ; i < ibuf->maxcol ; i++){
+ cmap[1] = (mul * cmap[1]) >> 8;
+ cmap[2] = (mul * cmap[2]) >> 8;
+ cmap[3] = (mul * cmap[3]) >> 8;
+ cmap += 4;
+ }
+ }
+}
+
+
+static short addplanetocube(short *cube, short *plane, int minx, int miny, int sizep, int addcx, int addcy, int sizec, int col)
+{
+ short done = FALSE;
+ int x, numx, numy, skipc, skipp, temp;
+
+ /* clip first */
+
+ numx = numy = sizep;
+
+ temp = minx + sizep - 1;
+ if (temp > sizec) numx -= temp - sizec;
+
+ temp = miny + sizep - 1;
+ if (temp > sizec) numy -= temp - sizec;
+
+ if (minx < 0){
+ plane -= minx;
+ cube -= minx * addcx;
+ numx += minx;
+ }
+
+ if (miny < 0){
+ plane -= miny * sizep;
+ cube -= miny * addcy;
+ numy += miny;
+ }
+
+ skipc = addcy - (numx * addcx);
+ skipp = sizep - numx;
+
+ for (; numy > 0 ; numy--){
+ for (x = numx ; x > 0; x--) {
+
+ if (plane[0] < cube[1]) {
+
+ cube[0] = col;
+ cube[1] = plane[0];
+ done = TRUE;
+ }
+ plane ++;
+ cube += addcx;
+ }
+ plane += skipp;
+ cube += skipc;
+ }
+
+ return (done);
+}
+
+
+
+short *imb_coldeltatab(unsigned char *coltab, short mincol, short maxcol, short cbits)
+{
+ short max, *quadr, *_quadr, *_cube, *cube, *_plane, done, nocol;
+ unsigned int addcb, addcg, addcr, sizep;
+ uchar *_colp, *colp, *col;
+ int i, j, k, addcube;
+ int r, g, b;
+
+ max = (1 << cbits) - 1;
+ nocol = maxcol - mincol;
+ coltab += 4 * mincol;
+
+ /* reduce colors to the right amount of bits */
+
+ {
+ unsigned int * lctab, and;
+
+ lctab = (unsigned int *) coltab;
+ and = max << (8 - cbits);
+ and = and + (and << 8) + (and << 16) + (and << 24);
+ for (i=nocol-1 ; i >= 0 ; i--) lctab[i] = (lctab[i] & and) >> (8 - cbits);
+ }
+
+ /* is this data the same as previous ? */
+
+ if (lastcube){
+ if (mincol == lastmincol && maxcol == lastmaxcol && cbits == lastcbits){
+ if (lastcoltab){
+ if (memcmp(lastcoltab, coltab, 4 * nocol) == 0) return(lastcube);
+ }
+ }
+ }
+ if (lastcube) free(lastcube);
+ if (lastcoltab) free(lastcoltab);
+
+ lastcube = 0;
+ lastcoltab = 0;
+ _cube = malloc(2 * (1 << (3 * cbits)) * sizeof(short));
+ _plane = malloc((2 * max + 1) * (2 * max + 1) * sizeof(short));
+ _quadr = malloc((2 * max + 1) * sizeof(short));
+ _colp = malloc(6 * nocol);
+
+ if (_cube == 0 || _plane == 0 || _quadr == 0 || _colp == 0){
+ if (_cube) free(_cube);
+ if (_plane) free(_plane);
+ if (_quadr) free(_quadr);
+ if (_colp) free(_colp);
+ return(0);
+ }
+
+ lastcoltab = malloc(4 * nocol);
+ if (lastcoltab) memcpy(lastcoltab, coltab, 4 * nocol);
+ lastcube = _cube;
+ lastmincol = mincol;
+ lastmaxcol = maxcol;
+ lastcbits = cbits;
+
+ /* cube initialise */
+
+ cube = _cube;
+ for (i = (1 << (3 * cbits)); i > 0 ; i--){
+ cube[0] = 0;
+ cube[1] = 32767;
+ cube += 2;
+ }
+
+ /* mak error look up table */
+
+ {
+ unsigned int delta;
+
+ quadr = _quadr + max + 1;
+ quadr[0] = 0;
+ delta = 3;
+ for (i = 1 ; i <= max ; i++){
+ quadr[i] = quadr[-i] = delta;
+ delta += i + 3;
+ }
+ }
+
+ /* colorplane initialise */
+
+ for (i = 6 * nocol - 1; i >= 0; i--) _colp[i] = 1;
+
+ addcr = 2;
+ addcg = (addcr << cbits);
+ addcb = (addcg << cbits);
+
+ /* fill in first round */
+
+ {
+ unsigned int ofs;
+
+ col = coltab;
+ cube = _cube;
+
+ for (i = 0 ; i < nocol ; i++){
+ ofs = (col[3] * addcr) + (col[2] * addcg) + (col[1] * addcb);
+ /* color been filled in -> then skip */
+ if (cube[ofs + 1]) cube[ofs] = i + mincol;
+ cube[ofs + 1] = 0;
+ col += 4;
+ }
+ }
+
+ for (i = 1; i <= max ; i++){
+ colp = _colp;
+ col = coltab;
+ done = FALSE;
+ sizep = 2*i +1;
+
+ /* plane initialise */
+ {
+ unsigned int delta;
+ short *plane;
+
+ plane = _plane;
+ for (j = -i ; j <= i; j++){
+ delta = quadr[i] + quadr[j];
+ for (k = -i; k <= i; k++){
+ *plane++ = delta + quadr[k];
+ }
+ }
+ }
+
+ for (j = mincol; j < maxcol; j++){
+ b = col[1] - i;
+ g = col[2] - i;
+ r = col[3] - i;
+
+ addcube= (addcr * r) + (addcg * g) + (addcb * b);
+ /* PRINT4(d, d, d, d, addcube, r, g, b); */
+ /* if(addcube >= 2 * (1 << (3 * cbits))) { */
+ /* printf("maxerror: %d %d\n", addcube, 2 * (1 << (3 * cbits))); */
+ /* add_cube= 2 * (1 << (3 * cbits)) -1; */
+ /* } */
+ cube = _cube + addcube;
+
+ if (colp[0]){
+ if (b < 0) colp[0] = 0;
+ else done |= colp[0] = addplanetocube(cube, _plane, r, g, sizep, addcr, addcg, max, j);
+ }
+ if (colp[1]){
+ if (g < 0) colp[1] = 0;
+ else done |= colp[1] = addplanetocube(cube, _plane, r, b, sizep, addcr, addcb, max, j);
+ }
+ if (colp[2]){
+ if (r < 0) colp[2] = 0;
+ else done |= colp[2] = addplanetocube(cube, _plane, b, g, sizep, addcb, addcg, max, j);
+ }
+ if (colp[3]){
+ if ((b + sizep - 1) > max) colp[3] = 0;
+ else done |= colp[3] = addplanetocube(cube + (sizep -1) * addcb, _plane, r, g, sizep, addcr,
+ addcg, max, j);
+ }
+ if (colp[4]){
+ if ((g + sizep - 1) > max) colp[4] = 0;
+ else done |= colp[4] = addplanetocube(cube + (sizep -1) * addcg, _plane, r, b, sizep, addcr,
+ addcb, max, j);
+ }
+ if (colp[5]){
+ if ((r + sizep - 1) > max) colp[5] = 0;
+ else done |= colp[5] = addplanetocube(cube + (sizep -1) * addcr, _plane, b, g, sizep, addcb,
+ addcg, max, j);
+ }
+
+ colp += 6;
+ col += 4;
+ }
+ if (done == 0) break;
+ }
+
+ free(_quadr);
+ free(_plane);
+ free(_colp);
+ return(_cube);
+}
+
+
+static void convcmap(struct ImBuf* ibuf, short *deltab, short cbits)
+{
+ unsigned int *rect;
+ short x,y;
+ unsigned int col;
+ unsigned int bbits,gbits,rbits;
+ unsigned int bmask,gmask,rmask;
+
+ bbits = 24 - 3 * cbits - 1;
+ gbits = 16 - 2 * cbits - 1;
+ rbits = 8 - cbits - 1;
+
+ rmask = ((1 << cbits) - 1) << (8 - cbits);
+ gmask = rmask << 8;
+ bmask = gmask << 8;
+
+ rect =(unsigned int *)ibuf->rect;
+
+ for(y=ibuf->y;y>0;y--){
+ for(x=ibuf->x;x>0;x--){
+ col = *rect;
+ col = ((col & bmask) >> bbits) + ((col & gmask) >> gbits) + ((col & rmask) >> rbits);
+ *rect++ = deltab[col];
+ }
+ }
+}
+
+short IMB_converttocmap(struct ImBuf *ibuf)
+{
+ unsigned int *coltab;
+ short *deltab=0, cbits;
+ int i;
+ int mincol, mask = 0;
+ struct ImBuf * abuf = 0;
+ unsigned int * rect, * arect;
+
+ cbits = 5;
+ if (ibuf->cmap == 0) return(0);
+
+ if ((ibuf->cbits > 0) && (ibuf->cbits <8)) cbits = ibuf->cbits;
+
+ coltab = calloc(ibuf->maxcol, sizeof(unsigned int));
+ if (coltab == 0) return(0);
+ memcpy(coltab, ibuf->cmap, ibuf->maxcol * sizeof(unsigned int));
+
+ mincol = ibuf->mincol;
+ if (alpha_col0) {
+ if (mincol == 0) mincol = 1;
+ abuf = IMB_dupImBuf(ibuf);
+ }
+
+ imb_losecmapbits(ibuf, coltab);
+ deltab = imb_coldeltatab((uchar *) coltab, mincol ,ibuf->maxcol, cbits);
+
+ if (deltab == 0) {
+ free(coltab);
+ if (abuf) IMB_freeImBuf(abuf);
+ return(0);
+ }
+
+
+ IMB_dit0(ibuf,1,cbits);
+ IMB_dit0(ibuf,2,cbits);
+ IMB_dit0(ibuf,3,cbits);
+ convcmap(ibuf, deltab, cbits);
+
+ if (abuf) {
+ /* convert alpha to color 0 */
+ rect = ibuf->rect;
+ arect = abuf->rect;
+
+ if (alpha_col0 == 1) mask = 0xff000000; /* alpha == 0 -> 0 */
+ if (alpha_col0 == 2) mask = 0x80000000; /* alpha < 128 -> 0 */
+
+ for (i = ibuf->x * ibuf->y; i > 0; i--) {
+ if ((*arect++ & mask) == 0) rect[0] = 0;
+ rect++;
+ }
+
+ IMB_freeImBuf(abuf);
+ }
+
+ free(coltab);
+
+ return (TRUE);
+}
+
+
+void imb_makecolarray(struct ImBuf *ibuf, unsigned char *mem, short nocols)
+{
+ short i,bits = 0;
+ uchar *cmap;
+
+ /* what's the theory behind this? */
+
+ nocols = ibuf->maxcol;
+
+ if (ibuf->cmap){
+ cmap = (uchar *) ibuf->cmap;
+ for (i = 0; i < nocols; i++){
+ cmap[3] = mem[0];
+ cmap[2] = mem[1];
+ cmap[1] = mem[2];
+ cmap[0] = 0;
+
+ bits |= mem[0] | mem[1] | mem[2];
+ mem += 3;
+ cmap += 4;
+ }
+
+ /* patch voor AdPro II */
+ if (IS_ham(ibuf)){
+ i = ibuf->depth - 2;
+ bits = ((1 << i) - 1) << (8 - i);
+ for (i=0 ; i<nocols ; i++) ibuf->cmap[i] &= (bits << 24) + (bits << 16) + (bits << 8) + bits;
+ }
+
+ if ((bits & 0x1f) == 0){
+ ibuf->cbits = 3;
+ } else if ((bits & 0x0f) == 0){
+ ibuf->cbits = 4;
+ } else if ((bits & 0x07) == 0){
+ ibuf->cbits = 5;
+ } else if ((bits & 0x03) == 0){
+ ibuf->cbits = 6;
+ } else ibuf->cbits = 8;
+
+ addcmapbits(ibuf);
+
+ if (IS_hbrite(ibuf)){
+ for (i=31;i>=0;i--){
+ ibuf->cmap[i+32] = (ibuf->cmap[i] & 0xfefefefe) >> 1;
+ }
+ }
+
+ if (IS_amiga(ibuf)){
+ cmap = (uchar * ) (ibuf->cmap + 1);
+ for (i = 1; i < nocols; i++){
+ cmap[0] = 0xff;
+ cmap += 4;
+ }
+ }
+ }
+}
+
+/* temporal... rects now are rgba, cmaps are abgr */
+#define SWITCH_INT(a) {char s_i, *p_i; p_i= (char *)&(a); s_i= p_i[0]; p_i[0]= p_i[3]; p_i[3]= s_i; s_i= p_i[1]; p_i[1]= p_i[2]; p_i[2]= s_i; }
+
+void IMB_applycmap(struct ImBuf *ibuf)
+{
+ unsigned int *rect, *cmap;
+ int x, y, i, col, code;
+ int *mask = 0;
+
+ if (ibuf == 0) return;
+ if (ibuf->rect == 0 || ibuf->cmap == 0) return;
+
+ rect = ibuf->rect;
+ cmap = ibuf->cmap;
+
+ if (IS_ham(ibuf)){
+
+ /* generate mask of max (8 + 2) bits */
+ mask = malloc(1024 * 2 * sizeof(int));
+
+ x = 1 << (ibuf->depth - 2);
+ y = 65535 / (x - 1);
+
+ for (i = 0; i < x; i++){
+ mask[i] = 0;
+ mask[i + x] = 0x00ffff;
+ mask[i + x + x] = 0xffff00;
+ mask[i + x + x + x] = 0xff00ff;
+
+ col = (y * i) >> 8;
+
+ mask[i + 1024] = 0xff000000 | ibuf->cmap[i];
+ mask[i + x + 1024] = 0xff000000 | col << 16;
+ mask[i + x + x + 1024] = 0xff000000 | col;
+ mask[i + x + x + x + 1024] = 0xff000000 | col << 8;
+ }
+
+ /* only color 0 transparant */
+ mask[0+1024] =ibuf->cmap[0];
+
+ for (y = ibuf->y ; y>0 ; y--){
+ col = cmap[0];
+ for (x=ibuf->x ; x>0 ; x--){
+ code = *rect;
+ *rect++ = col = (col & mask[code]) | mask[code + 1024];
+ }
+ }
+ free(mask);
+ } else {
+
+ for(i = ibuf->x * ibuf->y; i>0; i--){
+ col = *rect;
+ if (col >= 0 && col < ibuf->maxcol) *rect = cmap[col];
+ rect++;
+
+ /* *(rect++) = cmap[*rect]; */
+ }
+ }
+}
+
diff --git a/source/blender/imbuf/intern/cspace.c b/source/blender/imbuf/intern/cspace.c
new file mode 100644
index 00000000000..4fbfeb9c3c7
--- /dev/null
+++ b/source/blender/imbuf/intern/cspace.c
@@ -0,0 +1,179 @@
+/**
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "BLI_blenlib.h"
+
+#include "imbuf.h"
+#include "imbuf_patch.h"
+#include "IMB_imbuf_types.h"
+
+void IMB_cspace(struct ImBuf *ibuf, float mat[][4]);
+
+/************************************************************************/
+/* COLORSPACE */
+/************************************************************************/
+
+static void fillmattab(double val, unsigned short *mattab)
+{
+ int tot,ival;
+ int i;
+
+ val *= (1 << 22);
+ ival = val;
+ tot = 32767; /* een half */
+
+ for(i = 256; i > 0; i--){
+ *(mattab) = (tot >> 16);
+ mattab += 3;
+ tot += ival;
+ }
+}
+
+
+static void cspfill(short *buf, unsigned short *fill, int x)
+{
+ unsigned short r,g,b;
+
+ b = fill[0];
+ g = fill[1];
+ r = fill[2];
+ for (;x>0;x--){
+ buf[0] = b;
+ buf[1] = g;
+ buf[2] = r;
+ buf += 3;
+ }
+}
+
+
+static void cspadd(short *buf, unsigned short *cont, unsigned char *rect, int x)
+{
+ short i;
+ for (;x>0;x--){
+ i = *(rect);
+ rect += 4;
+ buf[0] += cont[i*3];
+ buf[1] += cont[i*3 + 1];
+ buf[2] += cont[i*3 + 2];
+ buf += 3;
+ }
+}
+
+
+static void cspret(short *buf, unsigned char *rect, int x)
+{
+ int r,g,b;
+
+ for(; x > 0; x--){
+ b = buf[0];
+ g = buf[1];
+ r = buf[2];
+
+ if (b & 0x4000){
+ if (b<0) rect[2]=0;
+ else rect[2]=255;
+ } else rect[2] = b >> 6;
+
+ if (g & 0x4000){
+ if (g<0) rect[1]=0;
+ else rect[1]=255;
+ } else rect[1] = g >> 6;
+
+ if (r & 0x4000){
+ if (r<0) rect[0]=0;
+ else rect[0]=255;
+ } else rect[0] = r >> 6;
+
+ buf += 3;
+ rect += 4;
+ }
+}
+
+
+static void rotcspace(struct ImBuf *ibuf, unsigned short *cont_1, unsigned short *cont_2, unsigned short *cont_3, unsigned short *add)
+{
+ short x,y,*buf;
+ uchar *rect;
+
+ x=ibuf->x;
+ rect= (uchar *)ibuf->rect;
+
+ buf=(short *)malloc(x*3*sizeof(short));
+ if (buf){
+ for(y=ibuf->y;y>0;y--){
+ cspfill(buf,add,x);
+ cspadd(buf,cont_1,rect+0,x);
+ cspadd(buf,cont_2,rect+1,x);
+ cspadd(buf,cont_3,rect+2,x);
+ cspret(buf,rect,x);
+ rect += x<<2;
+ }
+ free(buf);
+ }
+}
+
+
+void IMB_cspace(struct ImBuf *ibuf, float mat[][4])
+{
+ unsigned short *cont_1,*cont_2,*cont_3,add[3];
+
+ cont_1=(unsigned short *)malloc(256*3*sizeof(short));
+ cont_2=(unsigned short *)malloc(256*3*sizeof(short));
+ cont_3=(unsigned short *)malloc(256*3*sizeof(short));
+
+ if (cont_1 && cont_2 && cont_3){
+
+ fillmattab(mat[0][0],cont_1);
+ fillmattab(mat[0][1],cont_1+1);
+ fillmattab(mat[0][2],cont_1+2);
+
+ fillmattab(mat[1][0],cont_2);
+ fillmattab(mat[1][1],cont_2+1);
+ fillmattab(mat[1][2],cont_2+2);
+
+ fillmattab(mat[2][0],cont_3);
+ fillmattab(mat[2][1],cont_3+1);
+ fillmattab(mat[2][2],cont_3+2);
+
+ add[0] = (mat[3][0] * 64.0) + .5;
+ add[1] = (mat[3][1] * 64.0) + .5;
+ add[2] = (mat[3][2] * 64.0) + .5;
+
+ rotcspace(ibuf, cont_1, cont_2, cont_3, add);
+ }
+
+ if (cont_1) free(cont_1);
+ if (cont_2) free(cont_2);
+ if (cont_3) free(cont_3);
+}
+
diff --git a/source/blender/imbuf/intern/data.c b/source/blender/imbuf/intern/data.c
new file mode 100644
index 00000000000..ad9194cb80e
--- /dev/null
+++ b/source/blender/imbuf/intern/data.c
@@ -0,0 +1,145 @@
+/**
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * data.c
+ *
+ * $Id$
+ */
+
+#include "imbuf.h"
+#include "matrix.h"
+
+/*
+static short quadbase[31] = {
+ 150,133,117,102,
+ 88,75,63,52,
+ 42,33,25,18,
+ 12,7,3,0,
+ 3,7,12,18,
+ 25,33,42,52,
+ 63,75,88,102,
+ 117,133,150,
+};
+
+short *quadr = quadbase+15;
+*/
+/*
+main()
+{
+ ushort _quadr[511], *quadr;
+ int i, delta;
+
+ quadr = _quadr + 255;
+
+ delta = 0;
+ for (i = 0 ; i <= 255 ; i++){
+ quadr[i] = quadr[-i] = delta;
+ delta += i + 3;
+ }
+
+ delta = 0;
+ for (i = 0; i < 511; i++){
+ printf("%6d, ", _quadr[i]);
+ delta++;
+ if (delta == 8){
+ delta = 0;
+ printf("\n");
+ }
+ }
+}
+*/
+
+static unsigned short quadbase[511] = {
+ 33150, 32893, 32637, 32382, 32128, 31875, 31623, 31372,
+ 31122, 30873, 30625, 30378, 30132, 29887, 29643, 29400,
+ 29158, 28917, 28677, 28438, 28200, 27963, 27727, 27492,
+ 27258, 27025, 26793, 26562, 26332, 26103, 25875, 25648,
+ 25422, 25197, 24973, 24750, 24528, 24307, 24087, 23868,
+ 23650, 23433, 23217, 23002, 22788, 22575, 22363, 22152,
+ 21942, 21733, 21525, 21318, 21112, 20907, 20703, 20500,
+ 20298, 20097, 19897, 19698, 19500, 19303, 19107, 18912,
+ 18718, 18525, 18333, 18142, 17952, 17763, 17575, 17388,
+ 17202, 17017, 16833, 16650, 16468, 16287, 16107, 15928,
+ 15750, 15573, 15397, 15222, 15048, 14875, 14703, 14532,
+ 14362, 14193, 14025, 13858, 13692, 13527, 13363, 13200,
+ 13038, 12877, 12717, 12558, 12400, 12243, 12087, 11932,
+ 11778, 11625, 11473, 11322, 11172, 11023, 10875, 10728,
+ 10582, 10437, 10293, 10150, 10008, 9867, 9727, 9588,
+ 9450, 9313, 9177, 9042, 8908, 8775, 8643, 8512,
+ 8382, 8253, 8125, 7998, 7872, 7747, 7623, 7500,
+ 7378, 7257, 7137, 7018, 6900, 6783, 6667, 6552,
+ 6438, 6325, 6213, 6102, 5992, 5883, 5775, 5668,
+ 5562, 5457, 5353, 5250, 5148, 5047, 4947, 4848,
+ 4750, 4653, 4557, 4462, 4368, 4275, 4183, 4092,
+ 4002, 3913, 3825, 3738, 3652, 3567, 3483, 3400,
+ 3318, 3237, 3157, 3078, 3000, 2923, 2847, 2772,
+ 2698, 2625, 2553, 2482, 2412, 2343, 2275, 2208,
+ 2142, 2077, 2013, 1950, 1888, 1827, 1767, 1708,
+ 1650, 1593, 1537, 1482, 1428, 1375, 1323, 1272,
+ 1222, 1173, 1125, 1078, 1032, 987, 943, 900,
+ 858, 817, 777, 738, 700, 663, 627, 592,
+ 558, 525, 493, 462, 432, 403, 375, 348,
+ 322, 297, 273, 250, 228, 207, 187, 168,
+ 150, 133, 117, 102, 88, 75, 63, 52,
+ 42, 33, 25, 18, 12, 7, 3, 0,
+ 3, 7, 12, 18, 25, 33, 42, 52,
+ 63, 75, 88, 102, 117, 133, 150, 168,
+ 187, 207, 228, 250, 273, 297, 322, 348,
+ 375, 403, 432, 462, 493, 525, 558, 592,
+ 627, 663, 700, 738, 777, 817, 858, 900,
+ 943, 987, 1032, 1078, 1125, 1173, 1222, 1272,
+ 1323, 1375, 1428, 1482, 1537, 1593, 1650, 1708,
+ 1767, 1827, 1888, 1950, 2013, 2077, 2142, 2208,
+ 2275, 2343, 2412, 2482, 2553, 2625, 2698, 2772,
+ 2847, 2923, 3000, 3078, 3157, 3237, 3318, 3400,
+ 3483, 3567, 3652, 3738, 3825, 3913, 4002, 4092,
+ 4183, 4275, 4368, 4462, 4557, 4653, 4750, 4848,
+ 4947, 5047, 5148, 5250, 5353, 5457, 5562, 5668,
+ 5775, 5883, 5992, 6102, 6213, 6325, 6438, 6552,
+ 6667, 6783, 6900, 7018, 7137, 7257, 7378, 7500,
+ 7623, 7747, 7872, 7998, 8125, 8253, 8382, 8512,
+ 8643, 8775, 8908, 9042, 9177, 9313, 9450, 9588,
+ 9727, 9867, 10008, 10150, 10293, 10437, 10582, 10728,
+ 10875, 11023, 11172, 11322, 11473, 11625, 11778, 11932,
+ 12087, 12243, 12400, 12558, 12717, 12877, 13038, 13200,
+ 13363, 13527, 13692, 13858, 14025, 14193, 14362, 14532,
+ 14703, 14875, 15048, 15222, 15397, 15573, 15750, 15928,
+ 16107, 16287, 16468, 16650, 16833, 17017, 17202, 17388,
+ 17575, 17763, 17952, 18142, 18333, 18525, 18718, 18912,
+ 19107, 19303, 19500, 19698, 19897, 20097, 20298, 20500,
+ 20703, 20907, 21112, 21318, 21525, 21733, 21942, 22152,
+ 22363, 22575, 22788, 23002, 23217, 23433, 23650, 23868,
+ 24087, 24307, 24528, 24750, 24973, 25197, 25422, 25648,
+ 25875, 26103, 26332, 26562, 26793, 27025, 27258, 27492,
+ 27727, 27963, 28200, 28438, 28677, 28917, 29158, 29400,
+ 29643, 29887, 30132, 30378, 30625, 30873, 31122, 31372,
+ 31623, 31875, 32128, 32382, 32637, 32893, 33150,
+};
+
+unsigned short *quadr = quadbase + 255;
diff --git a/source/blender/imbuf/intern/dds/BlockDXT.cpp b/source/blender/imbuf/intern/dds/BlockDXT.cpp
new file mode 100644
index 00000000000..5290a677678
--- /dev/null
+++ b/source/blender/imbuf/intern/dds/BlockDXT.cpp
@@ -0,0 +1,523 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributors: Amorilia (amorilia@gamebox.net)
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/*
+ * This file is based on a similar file from the NVIDIA texture tools
+ * (http://nvidia-texture-tools.googlecode.com/)
+ *
+ * Original license from NVIDIA follows.
+ */
+
+// Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+
+#include <Common.h>
+#include <Stream.h>
+#include <ColorBlock.h>
+#include <BlockDXT.h>
+
+/*----------------------------------------------------------------------------
+ BlockDXT1
+----------------------------------------------------------------------------*/
+
+unsigned int BlockDXT1::evaluatePalette(Color32 color_array[4]) const
+{
+ // Does bit expansion before interpolation.
+ color_array[0].b = (col0.b << 3) | (col0.b >> 2);
+ color_array[0].g = (col0.g << 2) | (col0.g >> 4);
+ color_array[0].r = (col0.r << 3) | (col0.r >> 2);
+ color_array[0].a = 0xFF;
+
+ // @@ Same as above, but faster?
+// Color32 c;
+// c.u = ((col0.u << 3) & 0xf8) | ((col0.u << 5) & 0xfc00) | ((col0.u << 8) & 0xf80000);
+// c.u |= (c.u >> 5) & 0x070007;
+// c.u |= (c.u >> 6) & 0x000300;
+// color_array[0].u = c.u;
+
+ color_array[1].r = (col1.r << 3) | (col1.r >> 2);
+ color_array[1].g = (col1.g << 2) | (col1.g >> 4);
+ color_array[1].b = (col1.b << 3) | (col1.b >> 2);
+ color_array[1].a = 0xFF;
+
+ // @@ Same as above, but faster?
+// c.u = ((col1.u << 3) & 0xf8) | ((col1.u << 5) & 0xfc00) | ((col1.u << 8) & 0xf80000);
+// c.u |= (c.u >> 5) & 0x070007;
+// c.u |= (c.u >> 6) & 0x000300;
+// color_array[1].u = c.u;
+
+ if( col0.u > col1.u ) {
+ // Four-color block: derive the other two colors.
+ color_array[2].r = (2 * color_array[0].r + color_array[1].r) / 3;
+ color_array[2].g = (2 * color_array[0].g + color_array[1].g) / 3;
+ color_array[2].b = (2 * color_array[0].b + color_array[1].b) / 3;
+ color_array[2].a = 0xFF;
+
+ color_array[3].r = (2 * color_array[1].r + color_array[0].r) / 3;
+ color_array[3].g = (2 * color_array[1].g + color_array[0].g) / 3;
+ color_array[3].b = (2 * color_array[1].b + color_array[0].b) / 3;
+ color_array[3].a = 0xFF;
+
+ return 4;
+ }
+ else {
+ // Three-color block: derive the other color.
+ color_array[2].r = (color_array[0].r + color_array[1].r) / 2;
+ color_array[2].g = (color_array[0].g + color_array[1].g) / 2;
+ color_array[2].b = (color_array[0].b + color_array[1].b) / 2;
+ color_array[2].a = 0xFF;
+
+ // Set all components to 0 to match DXT specs.
+ color_array[3].r = 0x00; // color_array[2].r;
+ color_array[3].g = 0x00; // color_array[2].g;
+ color_array[3].b = 0x00; // color_array[2].b;
+ color_array[3].a = 0x00;
+
+ return 3;
+ }
+}
+
+// Evaluate palette assuming 3 color block.
+void BlockDXT1::evaluatePalette3(Color32 color_array[4]) const
+{
+ color_array[0].b = (col0.b << 3) | (col0.b >> 2);
+ color_array[0].g = (col0.g << 2) | (col0.g >> 4);
+ color_array[0].r = (col0.r << 3) | (col0.r >> 2);
+ color_array[0].a = 0xFF;
+
+ color_array[1].r = (col1.r << 3) | (col1.r >> 2);
+ color_array[1].g = (col1.g << 2) | (col1.g >> 4);
+ color_array[1].b = (col1.b << 3) | (col1.b >> 2);
+ color_array[1].a = 0xFF;
+
+ // Three-color block: derive the other color.
+ color_array[2].r = (color_array[0].r + color_array[1].r) / 2;
+ color_array[2].g = (color_array[0].g + color_array[1].g) / 2;
+ color_array[2].b = (color_array[0].b + color_array[1].b) / 2;
+ color_array[2].a = 0xFF;
+
+ // Set all components to 0 to match DXT specs.
+ color_array[3].r = 0x00; // color_array[2].r;
+ color_array[3].g = 0x00; // color_array[2].g;
+ color_array[3].b = 0x00; // color_array[2].b;
+ color_array[3].a = 0x00;
+}
+
+// Evaluate palette assuming 4 color block.
+void BlockDXT1::evaluatePalette4(Color32 color_array[4]) const
+{
+ color_array[0].b = (col0.b << 3) | (col0.b >> 2);
+ color_array[0].g = (col0.g << 2) | (col0.g >> 4);
+ color_array[0].r = (col0.r << 3) | (col0.r >> 2);
+ color_array[0].a = 0xFF;
+
+ color_array[1].r = (col1.r << 3) | (col1.r >> 2);
+ color_array[1].g = (col1.g << 2) | (col1.g >> 4);
+ color_array[1].b = (col1.b << 3) | (col1.b >> 2);
+ color_array[1].a = 0xFF;
+
+ // Four-color block: derive the other two colors.
+ color_array[2].r = (2 * color_array[0].r + color_array[1].r) / 3;
+ color_array[2].g = (2 * color_array[0].g + color_array[1].g) / 3;
+ color_array[2].b = (2 * color_array[0].b + color_array[1].b) / 3;
+ color_array[2].a = 0xFF;
+
+ color_array[3].r = (2 * color_array[1].r + color_array[0].r) / 3;
+ color_array[3].g = (2 * color_array[1].g + color_array[0].g) / 3;
+ color_array[3].b = (2 * color_array[1].b + color_array[0].b) / 3;
+ color_array[3].a = 0xFF;
+}
+
+void BlockDXT1::decodeBlock(ColorBlock * block) const
+{
+ // Decode color block.
+ Color32 color_array[4];
+ evaluatePalette(color_array);
+
+ // Write color block.
+ for( unsigned int j = 0; j < 4; j++ ) {
+ for( unsigned int i = 0; i < 4; i++ ) {
+ unsigned int idx = (row[j] >> (2 * i)) & 3;
+ block->color(i, j) = color_array[idx];
+ }
+ }
+}
+
+void BlockDXT1::setIndices(int * idx)
+{
+ indices = 0;
+ for(unsigned int i = 0; i < 16; i++) {
+ indices |= (idx[i] & 3) << (2 * i);
+ }
+}
+
+
+/// Flip DXT1 block vertically.
+inline void BlockDXT1::flip4()
+{
+ unsigned char tmp;
+ swap(row[0], row[3], tmp);
+ swap(row[1], row[2], tmp);
+}
+
+/// Flip half DXT1 block vertically.
+inline void BlockDXT1::flip2()
+{
+ unsigned char tmp;
+ swap(row[0], row[1], tmp);
+}
+
+
+/*----------------------------------------------------------------------------
+ BlockDXT3
+----------------------------------------------------------------------------*/
+
+void BlockDXT3::decodeBlock(ColorBlock * block) const
+{
+ // Decode color.
+ color.decodeBlock(block);
+
+ // Decode alpha.
+ alpha.decodeBlock(block);
+}
+
+void AlphaBlockDXT3::decodeBlock(ColorBlock * block) const
+{
+ block->color(0x0).a = (alpha0 << 4) | alpha0;
+ block->color(0x1).a = (alpha1 << 4) | alpha1;
+ block->color(0x2).a = (alpha2 << 4) | alpha2;
+ block->color(0x3).a = (alpha3 << 4) | alpha3;
+ block->color(0x4).a = (alpha4 << 4) | alpha4;
+ block->color(0x5).a = (alpha5 << 4) | alpha5;
+ block->color(0x6).a = (alpha6 << 4) | alpha6;
+ block->color(0x7).a = (alpha7 << 4) | alpha7;
+ block->color(0x8).a = (alpha8 << 4) | alpha8;
+ block->color(0x9).a = (alpha9 << 4) | alpha9;
+ block->color(0xA).a = (alphaA << 4) | alphaA;
+ block->color(0xB).a = (alphaB << 4) | alphaB;
+ block->color(0xC).a = (alphaC << 4) | alphaC;
+ block->color(0xD).a = (alphaD << 4) | alphaD;
+ block->color(0xE).a = (alphaE << 4) | alphaE;
+ block->color(0xF).a = (alphaF << 4) | alphaF;
+}
+
+/// Flip DXT3 alpha block vertically.
+void AlphaBlockDXT3::flip4()
+{
+ unsigned short tmp;
+ swap(row[0], row[3], tmp);
+ swap(row[1], row[2], tmp);
+}
+
+/// Flip half DXT3 alpha block vertically.
+void AlphaBlockDXT3::flip2()
+{
+ unsigned short tmp;
+ swap(row[0], row[1], tmp);
+}
+
+/// Flip DXT3 block vertically.
+void BlockDXT3::flip4()
+{
+ alpha.flip4();
+ color.flip4();
+}
+
+/// Flip half DXT3 block vertically.
+void BlockDXT3::flip2()
+{
+ alpha.flip2();
+ color.flip2();
+}
+
+
+/*----------------------------------------------------------------------------
+ BlockDXT5
+----------------------------------------------------------------------------*/
+
+void AlphaBlockDXT5::evaluatePalette(unsigned char alpha[8]) const
+{
+ if (alpha0 > alpha1) {
+ evaluatePalette8(alpha);
+ }
+ else {
+ evaluatePalette6(alpha);
+ }
+}
+
+void AlphaBlockDXT5::evaluatePalette8(unsigned char alpha[8]) const
+{
+ // 8-alpha block: derive the other six alphas.
+ // Bit code 000 = alpha0, 001 = alpha1, others are interpolated.
+ alpha[0] = alpha0;
+ alpha[1] = alpha1;
+ alpha[2] = (6 * alpha0 + 1 * alpha1) / 7; // bit code 010
+ alpha[3] = (5 * alpha0 + 2 * alpha1) / 7; // bit code 011
+ alpha[4] = (4 * alpha0 + 3 * alpha1) / 7; // bit code 100
+ alpha[5] = (3 * alpha0 + 4 * alpha1) / 7; // bit code 101
+ alpha[6] = (2 * alpha0 + 5 * alpha1) / 7; // bit code 110
+ alpha[7] = (1 * alpha0 + 6 * alpha1) / 7; // bit code 111
+}
+
+void AlphaBlockDXT5::evaluatePalette6(unsigned char alpha[8]) const
+{
+ // 6-alpha block.
+ // Bit code 000 = alpha0, 001 = alpha1, others are interpolated.
+ alpha[0] = alpha0;
+ alpha[1] = alpha1;
+ alpha[2] = (4 * alpha0 + 1 * alpha1) / 5; // Bit code 010
+ alpha[3] = (3 * alpha0 + 2 * alpha1) / 5; // Bit code 011
+ alpha[4] = (2 * alpha0 + 3 * alpha1) / 5; // Bit code 100
+ alpha[5] = (1 * alpha0 + 4 * alpha1) / 5; // Bit code 101
+ alpha[6] = 0x00; // Bit code 110
+ alpha[7] = 0xFF; // Bit code 111
+}
+
+void AlphaBlockDXT5::indices(unsigned char index_array[16]) const
+{
+ index_array[0x0] = bits0;
+ index_array[0x1] = bits1;
+ index_array[0x2] = bits2;
+ index_array[0x3] = bits3;
+ index_array[0x4] = bits4;
+ index_array[0x5] = bits5;
+ index_array[0x6] = bits6;
+ index_array[0x7] = bits7;
+ index_array[0x8] = bits8;
+ index_array[0x9] = bits9;
+ index_array[0xA] = bitsA;
+ index_array[0xB] = bitsB;
+ index_array[0xC] = bitsC;
+ index_array[0xD] = bitsD;
+ index_array[0xE] = bitsE;
+ index_array[0xF] = bitsF;
+}
+
+unsigned int AlphaBlockDXT5::index(unsigned int index) const
+{
+ int offset = (3 * index + 16);
+ return (this->u >> offset) & 0x7;
+}
+
+void AlphaBlockDXT5::setIndex(unsigned int index, unsigned int value)
+{
+ int offset = (3 * index + 16);
+ unsigned long long mask = ((unsigned long long)(0x7)) << offset;
+ this->u = (this->u & ~mask) | (((unsigned long long)(value)) << offset);
+}
+
+void AlphaBlockDXT5::decodeBlock(ColorBlock * block) const
+{
+ unsigned char alpha_array[8];
+ evaluatePalette(alpha_array);
+
+ unsigned char index_array[16];
+ indices(index_array);
+
+ for(unsigned int i = 0; i < 16; i++) {
+ block->color(i).a = alpha_array[index_array[i]];
+ }
+}
+
+void AlphaBlockDXT5::flip4()
+{
+ unsigned long long * b = (unsigned long long *)this;
+
+ // @@ The masks might have to be byte swapped.
+ unsigned long long tmp = (*b & (unsigned long long)(0x000000000000FFFFLL));
+ tmp |= (*b & (unsigned long long)(0x000000000FFF0000LL)) << 36;
+ tmp |= (*b & (unsigned long long)(0x000000FFF0000000LL)) << 12;
+ tmp |= (*b & (unsigned long long)(0x000FFF0000000000LL)) >> 12;
+ tmp |= (*b & (unsigned long long)(0xFFF0000000000000LL)) >> 36;
+
+ *b = tmp;
+}
+
+void AlphaBlockDXT5::flip2()
+{
+ unsigned int * b = (unsigned int *)this;
+
+ // @@ The masks might have to be byte swapped.
+ unsigned int tmp = (*b & 0xFF000000);
+ tmp |= (*b & 0x00000FFF) << 12;
+ tmp |= (*b & 0x00FFF000) >> 12;
+
+ *b = tmp;
+}
+
+void BlockDXT5::decodeBlock(ColorBlock * block) const
+{
+ // Decode color.
+ color.decodeBlock(block);
+
+ // Decode alpha.
+ alpha.decodeBlock(block);
+}
+
+/// Flip DXT5 block vertically.
+void BlockDXT5::flip4()
+{
+ alpha.flip4();
+ color.flip4();
+}
+
+/// Flip half DXT5 block vertically.
+void BlockDXT5::flip2()
+{
+ alpha.flip2();
+ color.flip2();
+}
+
+
+/// Decode ATI1 block.
+void BlockATI1::decodeBlock(ColorBlock * block) const
+{
+ unsigned char alpha_array[8];
+ alpha.evaluatePalette(alpha_array);
+
+ unsigned char index_array[16];
+ alpha.indices(index_array);
+
+ for(unsigned int i = 0; i < 16; i++) {
+ Color32 & c = block->color(i);
+ c.b = c.g = c.r = alpha_array[index_array[i]];
+ c.a = 255;
+ }
+}
+
+/// Flip ATI1 block vertically.
+void BlockATI1::flip4()
+{
+ alpha.flip4();
+}
+
+/// Flip half ATI1 block vertically.
+void BlockATI1::flip2()
+{
+ alpha.flip2();
+}
+
+
+/// Decode ATI2 block.
+void BlockATI2::decodeBlock(ColorBlock * block) const
+{
+ unsigned char alpha_array[8];
+ unsigned char index_array[16];
+
+ x.evaluatePalette(alpha_array);
+ x.indices(index_array);
+
+ for(unsigned int i = 0; i < 16; i++) {
+ Color32 & c = block->color(i);
+ c.r = alpha_array[index_array[i]];
+ }
+
+ y.evaluatePalette(alpha_array);
+ y.indices(index_array);
+
+ for(unsigned int i = 0; i < 16; i++) {
+ Color32 & c = block->color(i);
+ c.g = alpha_array[index_array[i]];
+ c.b = 0;
+ c.a = 255;
+ }
+}
+
+/// Flip ATI2 block vertically.
+void BlockATI2::flip4()
+{
+ x.flip4();
+ y.flip4();
+}
+
+/// Flip half ATI2 block vertically.
+void BlockATI2::flip2()
+{
+ x.flip2();
+ y.flip2();
+}
+
+void mem_read(Stream & mem, BlockDXT1 & block)
+{
+ mem_read(mem, block.col0.u);
+ mem_read(mem, block.col1.u);
+ mem_read(mem, block.indices);
+}
+
+void mem_read(Stream & mem, AlphaBlockDXT3 & block)
+{
+ for (unsigned int i = 0; i < 4; i++) mem_read(mem, block.row[i]);
+}
+
+void mem_read(Stream & mem, BlockDXT3 & block)
+{
+ mem_read(mem, block.alpha);
+ mem_read(mem, block.color);
+}
+
+void mem_read(Stream & mem, AlphaBlockDXT5 & block)
+{
+ mem_read(mem, block.u);
+}
+
+void mem_read(Stream & mem, BlockDXT5 & block)
+{
+ mem_read(mem, block.alpha);
+ mem_read(mem, block.color);
+}
+
+void mem_read(Stream & mem, BlockATI1 & block)
+{
+ mem_read(mem, block.alpha);
+}
+
+void mem_read(Stream & mem, BlockATI2 & block)
+{
+ mem_read(mem, block.x);
+ mem_read(mem, block.y);
+}
+
diff --git a/source/blender/imbuf/intern/dds/BlockDXT.h b/source/blender/imbuf/intern/dds/BlockDXT.h
new file mode 100644
index 00000000000..1f710360c3c
--- /dev/null
+++ b/source/blender/imbuf/intern/dds/BlockDXT.h
@@ -0,0 +1,227 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributors: Amorilia (amorilia@gamebox.net)
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/*
+ * This file is based on a similar file from the NVIDIA texture tools
+ * (http://nvidia-texture-tools.googlecode.com/)
+ *
+ * Original license from NVIDIA follows.
+ */
+
+// Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+
+#ifndef _DDS_BLOCKDXT_H
+#define _DDS_BLOCKDXT_H
+
+#include <Color.h>
+#include <ColorBlock.h>
+#include <Stream.h>
+
+/// DXT1 block.
+struct BlockDXT1
+{
+ Color16 col0;
+ Color16 col1;
+ union {
+ unsigned char row[4];
+ unsigned int indices;
+ };
+
+ bool isFourColorMode() const;
+
+ unsigned int evaluatePalette(Color32 color_array[4]) const;
+ unsigned int evaluatePaletteFast(Color32 color_array[4]) const;
+ void evaluatePalette3(Color32 color_array[4]) const;
+ void evaluatePalette4(Color32 color_array[4]) const;
+
+ void decodeBlock(ColorBlock * block) const;
+
+ void setIndices(int * idx);
+
+ void flip4();
+ void flip2();
+};
+
+/// Return true if the block uses four color mode, false otherwise.
+inline bool BlockDXT1::isFourColorMode() const
+{
+ return col0.u >= col1.u; // @@ > or >= ?
+}
+
+
+/// DXT3 alpha block with explicit alpha.
+struct AlphaBlockDXT3
+{
+ union {
+ struct {
+ unsigned int alpha0 : 4;
+ unsigned int alpha1 : 4;
+ unsigned int alpha2 : 4;
+ unsigned int alpha3 : 4;
+ unsigned int alpha4 : 4;
+ unsigned int alpha5 : 4;
+ unsigned int alpha6 : 4;
+ unsigned int alpha7 : 4;
+ unsigned int alpha8 : 4;
+ unsigned int alpha9 : 4;
+ unsigned int alphaA : 4;
+ unsigned int alphaB : 4;
+ unsigned int alphaC : 4;
+ unsigned int alphaD : 4;
+ unsigned int alphaE : 4;
+ unsigned int alphaF : 4;
+ };
+ unsigned short row[4];
+ };
+
+ void decodeBlock(ColorBlock * block) const;
+
+ void flip4();
+ void flip2();
+};
+
+
+/// DXT3 block.
+struct BlockDXT3
+{
+ AlphaBlockDXT3 alpha;
+ BlockDXT1 color;
+
+ void decodeBlock(ColorBlock * block) const;
+
+ void flip4();
+ void flip2();
+};
+
+
+/// DXT5 alpha block.
+struct AlphaBlockDXT5
+{
+ union {
+ struct {
+ unsigned int alpha0 : 8; // 8
+ unsigned int alpha1 : 8; // 16
+ unsigned int bits0 : 3; // 3 - 19
+ unsigned int bits1 : 3; // 6 - 22
+ unsigned int bits2 : 3; // 9 - 25
+ unsigned int bits3 : 3; // 12 - 28
+ unsigned int bits4 : 3; // 15 - 31
+ unsigned int bits5 : 3; // 18 - 34
+ unsigned int bits6 : 3; // 21 - 37
+ unsigned int bits7 : 3; // 24 - 40
+ unsigned int bits8 : 3; // 27 - 43
+ unsigned int bits9 : 3; // 30 - 46
+ unsigned int bitsA : 3; // 33 - 49
+ unsigned int bitsB : 3; // 36 - 52
+ unsigned int bitsC : 3; // 39 - 55
+ unsigned int bitsD : 3; // 42 - 58
+ unsigned int bitsE : 3; // 45 - 61
+ unsigned int bitsF : 3; // 48 - 64
+ };
+ unsigned long long u;
+ };
+
+ void evaluatePalette(unsigned char alpha[8]) const;
+ void evaluatePalette8(unsigned char alpha[8]) const;
+ void evaluatePalette6(unsigned char alpha[8]) const;
+ void indices(unsigned char index_array[16]) const;
+
+ unsigned int index(unsigned int index) const;
+ void setIndex(unsigned int index, unsigned int value);
+
+ void decodeBlock(ColorBlock * block) const;
+
+ void flip4();
+ void flip2();
+};
+
+
+/// DXT5 block.
+struct BlockDXT5
+{
+ AlphaBlockDXT5 alpha;
+ BlockDXT1 color;
+
+ void decodeBlock(ColorBlock * block) const;
+
+ void flip4();
+ void flip2();
+};
+
+/// ATI1 block.
+struct BlockATI1
+{
+ AlphaBlockDXT5 alpha;
+
+ void decodeBlock(ColorBlock * block) const;
+
+ void flip4();
+ void flip2();
+};
+
+/// ATI2 block.
+struct BlockATI2
+{
+ AlphaBlockDXT5 x;
+ AlphaBlockDXT5 y;
+
+ void decodeBlock(ColorBlock * block) const;
+
+ void flip4();
+ void flip2();
+};
+
+void mem_read(Stream & mem, BlockDXT1 & block);
+void mem_read(Stream & mem, AlphaBlockDXT3 & block);
+void mem_read(Stream & mem, BlockDXT3 & block);
+void mem_read(Stream & mem, AlphaBlockDXT5 & block);
+void mem_read(Stream & mem, BlockDXT5 & block);
+void mem_read(Stream & mem, BlockATI1 & block);
+void mem_read(Stream & mem, BlockATI2 & block);
+
+#endif // _DDS_BLOCKDXT_H
diff --git a/source/blender/imbuf/intern/dds/Color.h b/source/blender/imbuf/intern/dds/Color.h
new file mode 100644
index 00000000000..f8055afdfc9
--- /dev/null
+++ b/source/blender/imbuf/intern/dds/Color.h
@@ -0,0 +1,99 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributors: Amorilia (amorilia@gamebox.net)
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/*
+ * This file is based on a similar file from the NVIDIA texture tools
+ * (http://nvidia-texture-tools.googlecode.com/)
+ *
+ * Original license from NVIDIA follows.
+ */
+
+// This code is in the public domain -- castanyo@yahoo.es
+
+#ifndef _DDS_COLOR_H
+#define _DDS_COLOR_H
+
+/// 32 bit color stored as BGRA.
+class Color32
+{
+public:
+ Color32() { }
+ Color32(const Color32 & c) : u(c.u) { }
+ Color32(unsigned char R, unsigned char G, unsigned char B) { setRGBA(R, G, B, 0xFF); }
+ Color32(unsigned char R, unsigned char G, unsigned char B, unsigned char A) { setRGBA( R, G, B, A); }
+ //Color32(unsigned char c[4]) { setRGBA(c[0], c[1], c[2], c[3]); }
+ //Color32(float R, float G, float B) { setRGBA(uint(R*255), uint(G*255), uint(B*255), 0xFF); }
+ //Color32(float R, float G, float B, float A) { setRGBA(uint(R*255), uint(G*255), uint(B*255), uint(A*255)); }
+ Color32(unsigned int U) : u(U) { }
+
+ void setRGBA(unsigned char R, unsigned char G, unsigned char B, unsigned char A)
+ {
+ r = R;
+ g = G;
+ b = B;
+ a = A;
+ }
+
+ void setBGRA(unsigned char B, unsigned char G, unsigned char R, unsigned char A = 0xFF)
+ {
+ r = R;
+ g = G;
+ b = B;
+ a = A;
+ }
+
+ operator unsigned int () const {
+ return u;
+ }
+
+ union {
+ struct {
+ unsigned char b, g, r, a;
+ };
+ unsigned int u;
+ };
+};
+
+/// 16 bit 565 BGR color.
+class Color16
+{
+public:
+ Color16() { }
+ Color16(const Color16 & c) : u(c.u) { }
+ explicit Color16(unsigned short U) : u(U) { }
+
+ union {
+ struct {
+ unsigned short b : 5;
+ unsigned short g : 6;
+ unsigned short r : 5;
+ };
+ unsigned short u;
+ };
+};
+
+#endif // _DDS_COLOR_H
diff --git a/source/blender/imbuf/intern/dds/ColorBlock.cpp b/source/blender/imbuf/intern/dds/ColorBlock.cpp
new file mode 100644
index 00000000000..63997f93c8c
--- /dev/null
+++ b/source/blender/imbuf/intern/dds/ColorBlock.cpp
@@ -0,0 +1,310 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributors: Amorilia (amorilia@gamebox.net)
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/*
+ * This file is based on a similar file from the NVIDIA texture tools
+ * (http://nvidia-texture-tools.googlecode.com/)
+ *
+ * Original license from NVIDIA follows.
+ */
+
+// This code is in the public domain -- castanyo@yahoo.es
+
+#include <ColorBlock.h>
+#include <Image.h>
+#include <Common.h>
+
+ // Get approximate luminance.
+ inline static unsigned int colorLuminance(Color32 c)
+ {
+ return c.r + c.g + c.b;
+ }
+
+ // Get the euclidean distance between the given colors.
+ inline static unsigned int colorDistance(Color32 c0, Color32 c1)
+ {
+ return (c0.r - c1.r) * (c0.r - c1.r) + (c0.g - c1.g) * (c0.g - c1.g) + (c0.b - c1.b) * (c0.b - c1.b);
+ }
+
+
+/// Default constructor.
+ColorBlock::ColorBlock()
+{
+}
+
+/// Init the color block with the contents of the given block.
+ColorBlock::ColorBlock(const ColorBlock & block)
+{
+ for(unsigned int i = 0; i < 16; i++) {
+ color(i) = block.color(i);
+ }
+}
+
+
+/// Initialize this color block.
+ColorBlock::ColorBlock(const Image * img, unsigned int x, unsigned int y)
+{
+ init(img, x, y);
+}
+
+void ColorBlock::init(const Image * img, unsigned int x, unsigned int y)
+{
+ const unsigned int bw = min(img->width() - x, 4U);
+ const unsigned int bh = min(img->height() - y, 4U);
+
+ static int remainder[] = {
+ 0, 0, 0, 0,
+ 0, 1, 0, 1,
+ 0, 1, 2, 0,
+ 0, 1, 2, 3,
+ };
+
+ // Blocks that are smaller than 4x4 are handled by repeating the pixels.
+ // @@ Thats only correct when block size is 1, 2 or 4, but not with 3. :(
+
+ for(unsigned int i = 0; i < 4; i++) {
+ //const int by = i % bh;
+ const int by = remainder[(bh - 1) * 4 + i];
+ for(unsigned int e = 0; e < 4; e++) {
+ //const int bx = e % bw;
+ const int bx = remainder[(bw - 1) * 4 + e];
+ color(e, i) = img->pixel(x + bx, y + by);
+ }
+ }
+}
+
+
+void ColorBlock::swizzleDXT5n()
+{
+ for(int i = 0; i < 16; i++)
+ {
+ Color32 c = m_color[i];
+ m_color[i] = Color32(0, c.g, 0, c.r);
+ }
+}
+
+void ColorBlock::splatX()
+{
+ for(int i = 0; i < 16; i++)
+ {
+ unsigned char x = m_color[i].r;
+ m_color[i] = Color32(x, x, x, x);
+ }
+}
+
+void ColorBlock::splatY()
+{
+ for(int i = 0; i < 16; i++)
+ {
+ unsigned char y = m_color[i].g;
+ m_color[i] = Color32(y, y, y, y);
+ }
+}
+
+
+/// Count number of unique colors in this color block.
+unsigned int ColorBlock::countUniqueColors() const
+{
+ unsigned int count = 0;
+
+ // @@ This does not have to be o(n^2)
+ for(int i = 0; i < 16; i++)
+ {
+ bool unique = true;
+ for(int j = 0; j < i; j++) {
+ if( m_color[i] != m_color[j] ) {
+ unique = false;
+ }
+ }
+
+ if( unique ) {
+ count++;
+ }
+ }
+
+ return count;
+}
+
+/// Get average color of the block.
+Color32 ColorBlock::averageColor() const
+{
+ unsigned int r, g, b, a;
+ r = g = b = a = 0;
+
+ for(unsigned int i = 0; i < 16; i++) {
+ r += m_color[i].r;
+ g += m_color[i].g;
+ b += m_color[i].b;
+ a += m_color[i].a;
+ }
+
+ return Color32((unsigned char)(r / 16), (unsigned char)(g / 16), (unsigned char)(b / 16), (unsigned char)(a / 16));
+}
+
+
+/// Get diameter color range.
+void ColorBlock::diameterRange(Color32 * start, Color32 * end) const
+{
+ Color32 c0, c1;
+ unsigned int best_dist = 0;
+
+ for(int i = 0; i < 16; i++) {
+ for (int j = i+1; j < 16; j++) {
+ unsigned int dist = colorDistance(m_color[i], m_color[j]);
+ if( dist > best_dist ) {
+ best_dist = dist;
+ c0 = m_color[i];
+ c1 = m_color[j];
+ }
+ }
+ }
+
+ *start = c0;
+ *end = c1;
+}
+
+/// Get luminance color range.
+void ColorBlock::luminanceRange(Color32 * start, Color32 * end) const
+{
+ Color32 minColor, maxColor;
+ unsigned int minLuminance, maxLuminance;
+
+ maxLuminance = minLuminance = colorLuminance(m_color[0]);
+
+ for(unsigned int i = 1; i < 16; i++)
+ {
+ unsigned int luminance = colorLuminance(m_color[i]);
+
+ if (luminance > maxLuminance) {
+ maxLuminance = luminance;
+ maxColor = m_color[i];
+ }
+ else if (luminance < minLuminance) {
+ minLuminance = luminance;
+ minColor = m_color[i];
+ }
+ }
+
+ *start = minColor;
+ *end = maxColor;
+}
+
+/// Get color range based on the bounding box.
+void ColorBlock::boundsRange(Color32 * start, Color32 * end) const
+{
+ Color32 minColor(255, 255, 255);
+ Color32 maxColor(0, 0, 0);
+
+ for(unsigned int i = 0; i < 16; i++)
+ {
+ if (m_color[i].r < minColor.r) { minColor.r = m_color[i].r; }
+ if (m_color[i].g < minColor.g) { minColor.g = m_color[i].g; }
+ if (m_color[i].b < minColor.b) { minColor.b = m_color[i].b; }
+ if (m_color[i].r > maxColor.r) { maxColor.r = m_color[i].r; }
+ if (m_color[i].g > maxColor.g) { maxColor.g = m_color[i].g; }
+ if (m_color[i].b > maxColor.b) { maxColor.b = m_color[i].b; }
+ }
+
+ // Offset range by 1/16 of the extents
+ Color32 inset;
+ inset.r = (maxColor.r - minColor.r) >> 4;
+ inset.g = (maxColor.g - minColor.g) >> 4;
+ inset.b = (maxColor.b - minColor.b) >> 4;
+
+ minColor.r = (minColor.r + inset.r <= 255) ? minColor.r + inset.r : 255;
+ minColor.g = (minColor.g + inset.g <= 255) ? minColor.g + inset.g : 255;
+ minColor.b = (minColor.b + inset.b <= 255) ? minColor.b + inset.b : 255;
+
+ maxColor.r = (maxColor.r >= inset.r) ? maxColor.r - inset.r : 0;
+ maxColor.g = (maxColor.g >= inset.g) ? maxColor.g - inset.g : 0;
+ maxColor.b = (maxColor.b >= inset.b) ? maxColor.b - inset.b : 0;
+
+ *start = minColor;
+ *end = maxColor;
+}
+
+/// Get color range based on the bounding box.
+void ColorBlock::boundsRangeAlpha(Color32 * start, Color32 * end) const
+{
+ Color32 minColor(255, 255, 255, 255);
+ Color32 maxColor(0, 0, 0, 0);
+
+ for(unsigned int i = 0; i < 16; i++)
+ {
+ if (m_color[i].r < minColor.r) { minColor.r = m_color[i].r; }
+ if (m_color[i].g < minColor.g) { minColor.g = m_color[i].g; }
+ if (m_color[i].b < minColor.b) { minColor.b = m_color[i].b; }
+ if (m_color[i].a < minColor.a) { minColor.a = m_color[i].a; }
+ if (m_color[i].r > maxColor.r) { maxColor.r = m_color[i].r; }
+ if (m_color[i].g > maxColor.g) { maxColor.g = m_color[i].g; }
+ if (m_color[i].b > maxColor.b) { maxColor.b = m_color[i].b; }
+ if (m_color[i].a > maxColor.a) { maxColor.a = m_color[i].a; }
+ }
+
+ // Offset range by 1/16 of the extents
+ Color32 inset;
+ inset.r = (maxColor.r - minColor.r) >> 4;
+ inset.g = (maxColor.g - minColor.g) >> 4;
+ inset.b = (maxColor.b - minColor.b) >> 4;
+ inset.a = (maxColor.a - minColor.a) >> 4;
+
+ minColor.r = (minColor.r + inset.r <= 255) ? minColor.r + inset.r : 255;
+ minColor.g = (minColor.g + inset.g <= 255) ? minColor.g + inset.g : 255;
+ minColor.b = (minColor.b + inset.b <= 255) ? minColor.b + inset.b : 255;
+ minColor.a = (minColor.a + inset.a <= 255) ? minColor.a + inset.a : 255;
+
+ maxColor.r = (maxColor.r >= inset.r) ? maxColor.r - inset.r : 0;
+ maxColor.g = (maxColor.g >= inset.g) ? maxColor.g - inset.g : 0;
+ maxColor.b = (maxColor.b >= inset.b) ? maxColor.b - inset.b : 0;
+ maxColor.a = (maxColor.a >= inset.a) ? maxColor.a - inset.a : 0;
+
+ *start = minColor;
+ *end = maxColor;
+}
+
+/// Sort colors by abosolute value in their 16 bit representation.
+void ColorBlock::sortColorsByAbsoluteValue()
+{
+ // Dummy selection sort.
+ for( unsigned int a = 0; a < 16; a++ ) {
+ unsigned int max = a;
+ Color16 cmax(m_color[a]);
+
+ for( unsigned int b = a+1; b < 16; b++ ) {
+ Color16 cb(m_color[b]);
+
+ if( cb.u > cmax.u ) {
+ max = b;
+ cmax = cb;
+ }
+ }
+ Color32 tmp;
+ swap( m_color[a], m_color[max], tmp );
+ }
+}
+
+
diff --git a/source/blender/imbuf/intern/dds/ColorBlock.h b/source/blender/imbuf/intern/dds/ColorBlock.h
new file mode 100644
index 00000000000..eba372768ad
--- /dev/null
+++ b/source/blender/imbuf/intern/dds/ColorBlock.h
@@ -0,0 +1,115 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributors: Amorilia (amorilia@gamebox.net)
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/*
+ * This file is based on a similar file from the NVIDIA texture tools
+ * (http://nvidia-texture-tools.googlecode.com/)
+ *
+ * Original license from NVIDIA follows.
+ */
+
+// This code is in the public domain -- castanyo@yahoo.es
+
+#ifndef _DDS_COLORBLOCK_H
+#define _DDS_COLORBLOCK_H
+
+#include <Color.h>
+#include <Image.h>
+
+/// Uncompressed 4x4 color block.
+struct ColorBlock
+{
+ ColorBlock();
+ ColorBlock(const ColorBlock & block);
+ ColorBlock(const Image * img, unsigned int x, unsigned int y);
+
+ void init(const Image * img, unsigned int x, unsigned int y);
+
+ void swizzleDXT5n();
+ void splatX();
+ void splatY();
+
+ unsigned int countUniqueColors() const;
+ Color32 averageColor() const;
+
+ void diameterRange(Color32 * start, Color32 * end) const;
+ void luminanceRange(Color32 * start, Color32 * end) const;
+ void boundsRange(Color32 * start, Color32 * end) const;
+ void boundsRangeAlpha(Color32 * start, Color32 * end) const;
+ void bestFitRange(Color32 * start, Color32 * end) const;
+
+ void sortColorsByAbsoluteValue();
+
+ float volume() const;
+
+ // Accessors
+ const Color32 * colors() const;
+
+ Color32 color(unsigned int i) const;
+ Color32 & color(unsigned int i);
+
+ Color32 color(unsigned int x, unsigned int y) const;
+ Color32 & color(unsigned int x, unsigned int y);
+
+private:
+
+ Color32 m_color[4*4];
+
+};
+
+
+/// Get pointer to block colors.
+inline const Color32 * ColorBlock::colors() const
+{
+ return m_color;
+}
+
+/// Get block color.
+inline Color32 ColorBlock::color(unsigned int i) const
+{
+ return m_color[i];
+}
+
+/// Get block color.
+inline Color32 & ColorBlock::color(unsigned int i)
+{
+ return m_color[i];
+}
+
+/// Get block color.
+inline Color32 ColorBlock::color(unsigned int x, unsigned int y) const
+{
+ return m_color[y * 4 + x];
+}
+
+/// Get block color.
+inline Color32 & ColorBlock::color(unsigned int x, unsigned int y)
+{
+ return m_color[y * 4 + x];
+}
+
+#endif // _DDS_COLORBLOCK_H
diff --git a/source/blender/imbuf/intern/dds/Common.h b/source/blender/imbuf/intern/dds/Common.h
new file mode 100644
index 00000000000..5aa8972e437
--- /dev/null
+++ b/source/blender/imbuf/intern/dds/Common.h
@@ -0,0 +1,44 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributors: Amorilia (amorilia@gamebox.net)
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef _DDS_COMMON_H
+#define _DDS_COMMON_H
+
+#ifndef min
+#define min(a,b) ((a) <= (b) ? (a) : (b))
+#endif
+#ifndef max
+#define max(a,b) ((a) >= (b) ? (a) : (b))
+#endif
+#ifndef clamp
+#define clamp(x,a,b) min(max((x), (a)), (b))
+#endif
+#ifndef swap
+#define swap(a,b,tmp) tmp=a; a=b; b=tmp;
+#endif
+
+#endif
diff --git a/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp b/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp
new file mode 100644
index 00000000000..c28f8b5b72d
--- /dev/null
+++ b/source/blender/imbuf/intern/dds/DirectDrawSurface.cpp
@@ -0,0 +1,924 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributors: Amorilia (amorilia@gamebox.net)
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/*
+ * This file is based on a similar file from the NVIDIA texture tools
+ * (http://nvidia-texture-tools.googlecode.com/)
+ *
+ * Original license from NVIDIA follows.
+ */
+
+// Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+
+#include <Common.h>
+#include <DirectDrawSurface.h>
+#include <BlockDXT.h>
+
+#include <stdio.h> // printf
+#include <math.h> // sqrt
+
+/*** declarations ***/
+
+#if !defined(MAKEFOURCC)
+# define MAKEFOURCC(ch0, ch1, ch2, ch3) \
+ ((unsigned int)((unsigned char)(ch0)) | \
+ ((unsigned int)((unsigned char)(ch1)) << 8) | \
+ ((unsigned int)((unsigned char)(ch2)) << 16) | \
+ ((unsigned int)((unsigned char)(ch3)) << 24 ))
+#endif
+
+static const unsigned int FOURCC_DDS = MAKEFOURCC('D', 'D', 'S', ' ');
+static const unsigned int FOURCC_DXT1 = MAKEFOURCC('D', 'X', 'T', '1');
+static const unsigned int FOURCC_DXT2 = MAKEFOURCC('D', 'X', 'T', '2');
+static const unsigned int FOURCC_DXT3 = MAKEFOURCC('D', 'X', 'T', '3');
+static const unsigned int FOURCC_DXT4 = MAKEFOURCC('D', 'X', 'T', '4');
+static const unsigned int FOURCC_DXT5 = MAKEFOURCC('D', 'X', 'T', '5');
+static const unsigned int FOURCC_RXGB = MAKEFOURCC('R', 'X', 'G', 'B');
+static const unsigned int FOURCC_ATI1 = MAKEFOURCC('A', 'T', 'I', '1');
+static const unsigned int FOURCC_ATI2 = MAKEFOURCC('A', 'T', 'I', '2');
+
+// RGB formats.
+static const unsigned int D3DFMT_R8G8B8 = 20;
+static const unsigned int D3DFMT_A8R8G8B8 = 21;
+static const unsigned int D3DFMT_X8R8G8B8 = 22;
+static const unsigned int D3DFMT_R5G6B5 = 23;
+static const unsigned int D3DFMT_X1R5G5B5 = 24;
+static const unsigned int D3DFMT_A1R5G5B5 = 25;
+static const unsigned int D3DFMT_A4R4G4B4 = 26;
+static const unsigned int D3DFMT_R3G3B2 = 27;
+static const unsigned int D3DFMT_A8 = 28;
+static const unsigned int D3DFMT_A8R3G3B2 = 29;
+static const unsigned int D3DFMT_X4R4G4B4 = 30;
+static const unsigned int D3DFMT_A2B10G10R10 = 31;
+static const unsigned int D3DFMT_A8B8G8R8 = 32;
+static const unsigned int D3DFMT_X8B8G8R8 = 33;
+static const unsigned int D3DFMT_G16R16 = 34;
+static const unsigned int D3DFMT_A2R10G10B10 = 35;
+static const unsigned int D3DFMT_A16B16G16R16 = 36;
+
+// Palette formats.
+static const unsigned int D3DFMT_A8P8 = 40;
+static const unsigned int D3DFMT_P8 = 41;
+
+// Luminance formats.
+static const unsigned int D3DFMT_L8 = 50;
+static const unsigned int D3DFMT_A8L8 = 51;
+static const unsigned int D3DFMT_A4L4 = 52;
+
+// Floating point formats
+static const unsigned int D3DFMT_R16F = 111;
+static const unsigned int D3DFMT_G16R16F = 112;
+static const unsigned int D3DFMT_A16B16G16R16F = 113;
+static const unsigned int D3DFMT_R32F = 114;
+static const unsigned int D3DFMT_G32R32F = 115;
+static const unsigned int D3DFMT_A32B32G32R32F = 116;
+
+static const unsigned int DDSD_CAPS = 0x00000001U;
+static const unsigned int DDSD_PIXELFORMAT = 0x00001000U;
+static const unsigned int DDSD_WIDTH = 0x00000004U;
+static const unsigned int DDSD_HEIGHT = 0x00000002U;
+static const unsigned int DDSD_PITCH = 0x00000008U;
+static const unsigned int DDSD_MIPMAPCOUNT = 0x00020000U;
+static const unsigned int DDSD_LINEARSIZE = 0x00080000U;
+static const unsigned int DDSD_DEPTH = 0x00800000U;
+
+static const unsigned int DDSCAPS_COMPLEX = 0x00000008U;
+static const unsigned int DDSCAPS_TEXTURE = 0x00001000U;
+static const unsigned int DDSCAPS_MIPMAP = 0x00400000U;
+static const unsigned int DDSCAPS2_VOLUME = 0x00200000U;
+static const unsigned int DDSCAPS2_CUBEMAP = 0x00000200U;
+
+static const unsigned int DDSCAPS2_CUBEMAP_POSITIVEX = 0x00000400U;
+static const unsigned int DDSCAPS2_CUBEMAP_NEGATIVEX = 0x00000800U;
+static const unsigned int DDSCAPS2_CUBEMAP_POSITIVEY = 0x00001000U;
+static const unsigned int DDSCAPS2_CUBEMAP_NEGATIVEY = 0x00002000U;
+static const unsigned int DDSCAPS2_CUBEMAP_POSITIVEZ = 0x00004000U;
+static const unsigned int DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x00008000U;
+static const unsigned int DDSCAPS2_CUBEMAP_ALL_FACES = 0x0000FC00U;
+
+static const unsigned int DDPF_ALPHAPIXELS = 0x00000001U;
+static const unsigned int DDPF_ALPHA = 0x00000002U;
+static const unsigned int DDPF_FOURCC = 0x00000004U;
+static const unsigned int DDPF_RGB = 0x00000040U;
+static const unsigned int DDPF_PALETTEINDEXED1 = 0x00000800U;
+static const unsigned int DDPF_PALETTEINDEXED2 = 0x00001000U;
+static const unsigned int DDPF_PALETTEINDEXED4 = 0x00000008U;
+static const unsigned int DDPF_PALETTEINDEXED8 = 0x00000020U;
+static const unsigned int DDPF_LUMINANCE = 0x00020000U;
+static const unsigned int DDPF_ALPHAPREMULT = 0x00008000U;
+static const unsigned int DDPF_NORMAL = 0x80000000U; // @@ Custom nv flag.
+
+/*** implementation ***/
+
+void mem_read(Stream & mem, DDSPixelFormat & pf)
+{
+ mem_read(mem, pf.size);
+ mem_read(mem, pf.flags);
+ mem_read(mem, pf.fourcc);
+ mem_read(mem, pf.bitcount);
+ mem_read(mem, pf.rmask);
+ mem_read(mem, pf.gmask);
+ mem_read(mem, pf.bmask);
+ mem_read(mem, pf.amask);
+}
+
+void mem_read(Stream & mem, DDSCaps & caps)
+{
+ mem_read(mem, caps.caps1);
+ mem_read(mem, caps.caps2);
+ mem_read(mem, caps.caps3);
+ mem_read(mem, caps.caps4);
+}
+
+void mem_read(Stream & mem, DDSHeader & header)
+{
+ mem_read(mem, header.fourcc);
+ mem_read(mem, header.size);
+ mem_read(mem, header.flags);
+ mem_read(mem, header.height);
+ mem_read(mem, header.width);
+ mem_read(mem, header.pitch);
+ mem_read(mem, header.depth);
+ mem_read(mem, header.mipmapcount);
+ for (unsigned int i = 0; i < 11; i++) mem_read(mem, header.reserved[i]);
+ mem_read(mem, header.pf);
+ mem_read(mem, header.caps);
+ mem_read(mem, header.notused);
+}
+
+DDSHeader::DDSHeader()
+{
+ this->fourcc = FOURCC_DDS;
+ this->size = 124;
+ this->flags = (DDSD_CAPS|DDSD_PIXELFORMAT);
+ this->height = 0;
+ this->width = 0;
+ this->pitch = 0;
+ this->depth = 0;
+ this->mipmapcount = 0;
+ for (unsigned int i = 0; i < 11; i++) this->reserved[i] = 0;
+
+ // Store version information on the reserved header attributes.
+ this->reserved[9] = MAKEFOURCC('N', 'V', 'T', 'T');
+ this->reserved[10] = (0 << 16) | (9 << 8) | (3); // major.minor.revision
+
+ this->pf.size = 32;
+ this->pf.flags = 0;
+ this->pf.fourcc = 0;
+ this->pf.bitcount = 0;
+ this->pf.rmask = 0;
+ this->pf.gmask = 0;
+ this->pf.bmask = 0;
+ this->pf.amask = 0;
+ this->caps.caps1 = DDSCAPS_TEXTURE;
+ this->caps.caps2 = 0;
+ this->caps.caps3 = 0;
+ this->caps.caps4 = 0;
+ this->notused = 0;
+}
+
+void DDSHeader::setWidth(unsigned int w)
+{
+ this->flags |= DDSD_WIDTH;
+ this->width = w;
+}
+
+void DDSHeader::setHeight(unsigned int h)
+{
+ this->flags |= DDSD_HEIGHT;
+ this->height = h;
+}
+
+void DDSHeader::setDepth(unsigned int d)
+{
+ this->flags |= DDSD_DEPTH;
+ this->height = d;
+}
+
+void DDSHeader::setMipmapCount(unsigned int count)
+{
+ if (count == 0)
+ {
+ this->flags &= ~DDSD_MIPMAPCOUNT;
+ this->mipmapcount = 0;
+
+ if (this->caps.caps2 == 0) {
+ this->caps.caps1 = DDSCAPS_TEXTURE;
+ }
+ else {
+ this->caps.caps1 = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX;
+ }
+ }
+ else
+ {
+ this->flags |= DDSD_MIPMAPCOUNT;
+ this->mipmapcount = count;
+
+ this->caps.caps1 |= DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
+ }
+}
+
+void DDSHeader::setTexture2D()
+{
+ // nothing to do here.
+}
+
+void DDSHeader::setTexture3D()
+{
+ this->caps.caps2 = DDSCAPS2_VOLUME;
+}
+
+void DDSHeader::setTextureCube()
+{
+ this->caps.caps1 |= DDSCAPS_COMPLEX;
+ this->caps.caps2 = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_ALL_FACES;
+}
+
+void DDSHeader::setLinearSize(unsigned int size)
+{
+ this->flags &= ~DDSD_PITCH;
+ this->flags |= DDSD_LINEARSIZE;
+ this->pitch = size;
+}
+
+void DDSHeader::setPitch(unsigned int pitch)
+{
+ this->flags &= ~DDSD_LINEARSIZE;
+ this->flags |= DDSD_PITCH;
+ this->pitch = pitch;
+}
+
+void DDSHeader::setFourCC(unsigned char c0, unsigned char c1, unsigned char c2, unsigned char c3)
+{
+ // set fourcc pixel format.
+ this->pf.flags = DDPF_FOURCC;
+ this->pf.fourcc = MAKEFOURCC(c0, c1, c2, c3);
+ this->pf.bitcount = 0;
+ this->pf.rmask = 0;
+ this->pf.gmask = 0;
+ this->pf.bmask = 0;
+ this->pf.amask = 0;
+}
+
+void DDSHeader::setPixelFormat(unsigned int bitcount, unsigned int rmask, unsigned int gmask, unsigned int bmask, unsigned int amask)
+{
+ // Make sure the masks are correct.
+ if ((rmask & gmask) || \
+ (rmask & bmask) || \
+ (rmask & amask) || \
+ (gmask & bmask) || \
+ (gmask & amask) || \
+ (bmask & amask)) {
+ printf("DDS: bad RGBA masks, pixel format not set\n");
+ return;
+ }
+
+ this->pf.flags = DDPF_RGB;
+
+ if (amask != 0) {
+ this->pf.flags |= DDPF_ALPHAPIXELS;
+ }
+
+ if (bitcount == 0)
+ {
+ // Compute bit count from the masks.
+ unsigned int total = rmask | gmask | bmask | amask;
+ while(total != 0) {
+ bitcount++;
+ total >>= 1;
+ }
+ // @@ Align to 8?
+ }
+
+ this->pf.fourcc = 0;
+ this->pf.bitcount = bitcount;
+ this->pf.rmask = rmask;
+ this->pf.gmask = gmask;
+ this->pf.bmask = bmask;
+ this->pf.amask = amask;
+}
+
+void DDSHeader::setNormalFlag(bool b)
+{
+ if (b) this->pf.flags |= DDPF_NORMAL;
+ else this->pf.flags &= ~DDPF_NORMAL;
+}
+
+/*
+void DDSHeader::swapBytes()
+{
+ this->fourcc = POSH_LittleU32(this->fourcc);
+ this->size = POSH_LittleU32(this->size);
+ this->flags = POSH_LittleU32(this->flags);
+ this->height = POSH_LittleU32(this->height);
+ this->width = POSH_LittleU32(this->width);
+ this->pitch = POSH_LittleU32(this->pitch);
+ this->depth = POSH_LittleU32(this->depth);
+ this->mipmapcount = POSH_LittleU32(this->mipmapcount);
+
+ for(int i = 0; i < 11; i++) {
+ this->reserved[i] = POSH_LittleU32(this->reserved[i]);
+ }
+
+ this->pf.size = POSH_LittleU32(this->pf.size);
+ this->pf.flags = POSH_LittleU32(this->pf.flags);
+ this->pf.fourcc = POSH_LittleU32(this->pf.fourcc);
+ this->pf.bitcount = POSH_LittleU32(this->pf.bitcount);
+ this->pf.rmask = POSH_LittleU32(this->pf.rmask);
+ this->pf.gmask = POSH_LittleU32(this->pf.gmask);
+ this->pf.bmask = POSH_LittleU32(this->pf.bmask);
+ this->pf.amask = POSH_LittleU32(this->pf.amask);
+ this->caps.caps1 = POSH_LittleU32(this->caps.caps1);
+ this->caps.caps2 = POSH_LittleU32(this->caps.caps2);
+ this->caps.caps3 = POSH_LittleU32(this->caps.caps3);
+ this->caps.caps4 = POSH_LittleU32(this->caps.caps4);
+ this->notused = POSH_LittleU32(this->notused);
+}
+*/
+
+
+DirectDrawSurface::DirectDrawSurface(unsigned char *mem, unsigned int size) : stream(mem, size), header()
+{
+ mem_read(stream, header);
+}
+
+DirectDrawSurface::~DirectDrawSurface()
+{
+}
+
+bool DirectDrawSurface::isValid() const
+{
+ if (header.fourcc != FOURCC_DDS || header.size != 124)
+ {
+ return false;
+ }
+
+ const unsigned int required = (DDSD_WIDTH|DDSD_HEIGHT|DDSD_CAPS|DDSD_PIXELFORMAT);
+ if( (header.flags & required) != required ) {
+ return false;
+ }
+
+ if (header.pf.size != 32) {
+ return false;
+ }
+
+ /* in some files DDSCAPS_TEXTURE is missing: silently ignore */
+ /*
+ if( !(header.caps.caps1 & DDSCAPS_TEXTURE) ) {
+ return false;
+ }
+ */
+
+ return true;
+}
+
+bool DirectDrawSurface::isSupported() const
+{
+ if (header.pf.flags & DDPF_FOURCC)
+ {
+ if (header.pf.fourcc != FOURCC_DXT1 &&
+ header.pf.fourcc != FOURCC_DXT2 &&
+ header.pf.fourcc != FOURCC_DXT3 &&
+ header.pf.fourcc != FOURCC_DXT4 &&
+ header.pf.fourcc != FOURCC_DXT5 &&
+ header.pf.fourcc != FOURCC_RXGB &&
+ header.pf.fourcc != FOURCC_ATI1 &&
+ header.pf.fourcc != FOURCC_ATI2)
+ {
+ // Unknown fourcc code.
+ return false;
+ }
+ }
+ else if (header.pf.flags & DDPF_RGB)
+ {
+ if (header.pf.bitcount == 24)
+ {
+ return true;
+ }
+ else if (header.pf.bitcount == 32)
+ {
+ return true;
+ }
+ else
+ {
+ // Unsupported pixel format.
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+
+ if (isTextureCube() && (header.caps.caps2 & DDSCAPS2_CUBEMAP_ALL_FACES) != DDSCAPS2_CUBEMAP_ALL_FACES)
+ {
+ // Cubemaps must contain all faces.
+ return false;
+ }
+
+ if (isTexture3D())
+ {
+ // @@ 3D textures not supported yet.
+ return false;
+ }
+
+ return true;
+}
+
+
+unsigned int DirectDrawSurface::mipmapCount() const
+{
+ if (header.flags & DDSD_MIPMAPCOUNT) return header.mipmapcount;
+ else return 0;
+}
+
+
+unsigned int DirectDrawSurface::width() const
+{
+ if (header.flags & DDSD_WIDTH) return header.width;
+ else return 1;
+}
+
+unsigned int DirectDrawSurface::height() const
+{
+ if (header.flags & DDSD_HEIGHT) return header.height;
+ else return 1;
+}
+
+unsigned int DirectDrawSurface::depth() const
+{
+ if (header.flags & DDSD_DEPTH) return header.depth;
+ else return 1;
+}
+
+bool DirectDrawSurface::hasAlpha() const
+{
+ if ((header.pf.flags & DDPF_RGB) && (header.pf.amask == 0))
+ {
+ return false;
+ }
+ else if (header.pf.fourcc == FOURCC_DXT1)
+ {
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+}
+
+bool DirectDrawSurface::isTexture2D() const
+{
+ return !isTexture3D() && !isTextureCube();
+}
+
+bool DirectDrawSurface::isTexture3D() const
+{
+ return (header.caps.caps2 & DDSCAPS2_VOLUME) != 0;
+}
+
+bool DirectDrawSurface::isTextureCube() const
+{
+ return (header.caps.caps2 & DDSCAPS2_CUBEMAP) != 0;
+}
+
+void DirectDrawSurface::mipmap(Image * img, unsigned int face, unsigned int mipmap)
+{
+ stream.seek(offset(face, mipmap));
+
+ unsigned int w = width();
+ unsigned int h = height();
+
+ // Compute width and height.
+ for (unsigned int m = 0; m < mipmap; m++)
+ {
+ w = max(w/2, 1U);
+ h = max(h/2, 1U);
+ }
+
+ img->allocate(w, h);
+
+ if (header.pf.flags & DDPF_RGB)
+ {
+ readLinearImage(img);
+ }
+ else if (header.pf.flags & DDPF_FOURCC)
+ {
+ readBlockImage(img);
+ }
+}
+
+/* helper function for readLinearImage */
+void maskShiftAndSize(unsigned int mask, unsigned int * shift, unsigned int * size)
+{
+ if (!mask)
+ {
+ *shift = 0;
+ *size = 0;
+ return;
+ }
+
+ *shift = 0;
+ while((mask & 1) == 0) {
+ ++(*shift);
+ mask >>= 1;
+ }
+
+ *size = 0;
+ while((mask & 1) == 1) {
+ ++(*size);
+ mask >>= 1;
+ }
+}
+
+/* helper function for readLinearImage */
+unsigned int convert(unsigned int c, unsigned int inbits, unsigned int outbits)
+{
+ if (inbits == 0) {
+ return 0;
+ }
+ else if (inbits == outbits)
+ {
+ return c;
+ }
+ else if (inbits > outbits)
+ {
+ // truncate
+ return c >> (inbits - outbits);
+ }
+ else
+ {
+ // bitexpand
+ return (c << (outbits - inbits)) | convert(c, inbits, outbits - inbits);
+ }
+}
+
+void DirectDrawSurface::readLinearImage(Image * img)
+{
+ const unsigned int w = img->width();
+ const unsigned int h = img->height();
+
+ unsigned int rshift, rsize;
+ maskShiftAndSize(header.pf.rmask, &rshift, &rsize);
+
+ unsigned int gshift, gsize;
+ maskShiftAndSize(header.pf.gmask, &gshift, &gsize);
+
+ unsigned int bshift, bsize;
+ maskShiftAndSize(header.pf.bmask, &bshift, &bsize);
+
+ unsigned int ashift, asize;
+ maskShiftAndSize(header.pf.amask, &ashift, &asize);
+
+ unsigned int byteCount = (header.pf.bitcount + 7) / 8;
+ if (byteCount > 4)
+ {
+ /* just in case... we could have segfaults later on if byteCount > 4 */
+ printf("DDS: bitcount too large (file corrupt?)");
+ return;
+ }
+
+ if (header.pf.amask != 0)
+ {
+ img->setFormat(Image::Format_ARGB);
+ }
+
+ // Read linear RGB images.
+ for (unsigned int y = 0; y < h; y++)
+ {
+ for (unsigned int x = 0; x < w; x++)
+ {
+ unsigned int c = 0;
+ mem_read(stream, (unsigned char *)(&c), byteCount);
+
+ Color32 pixel(0, 0, 0, 0xFF);
+ pixel.r = convert(c >> rshift, rsize, 8);
+ pixel.g = convert(c >> gshift, gsize, 8);
+ pixel.b = convert(c >> bshift, bsize, 8);
+ pixel.a = convert(c >> ashift, asize, 8);
+
+ img->pixel(x, y) = pixel;
+ }
+ }
+}
+
+void DirectDrawSurface::readBlockImage(Image * img)
+{
+ const unsigned int w = img->width();
+ const unsigned int h = img->height();
+
+ const unsigned int bw = (w + 3) / 4;
+ const unsigned int bh = (h + 3) / 4;
+
+ for (unsigned int by = 0; by < bh; by++)
+ {
+ for (unsigned int bx = 0; bx < bw; bx++)
+ {
+ ColorBlock block;
+
+ // Read color block.
+ readBlock(&block);
+
+ // Write color block.
+ for (unsigned int y = 0; y < min(4U, h-4*by); y++)
+ {
+ for (unsigned int x = 0; x < min(4U, w-4*bx); x++)
+ {
+ img->pixel(4*bx+x, 4*by+y) = block.color(x, y);
+ }
+ }
+ }
+ }
+}
+
+static Color32 buildNormal(unsigned char x, unsigned char y)
+{
+ float nx = 2 * (x / 255) - 1;
+ float ny = 2 * (x / 255) - 1;
+ float nz = sqrt(1 - nx*nx - ny*ny);
+ unsigned char z = clamp(int(255 * (nz + 1) / 2), 0, 255);
+
+ return Color32(x, y, z);
+}
+
+
+void DirectDrawSurface::readBlock(ColorBlock * rgba)
+{
+ if (header.pf.fourcc == FOURCC_DXT1)
+ {
+ BlockDXT1 block;
+ mem_read(stream, block);
+ block.decodeBlock(rgba);
+ }
+ else if (header.pf.fourcc == FOURCC_DXT2 ||
+ header.pf.fourcc == FOURCC_DXT3)
+ {
+ BlockDXT3 block;
+ mem_read(stream, block);
+ block.decodeBlock(rgba);
+ }
+ else if (header.pf.fourcc == FOURCC_DXT4 ||
+ header.pf.fourcc == FOURCC_DXT5 ||
+ header.pf.fourcc == FOURCC_RXGB)
+ {
+ BlockDXT5 block;
+ mem_read(stream, block);
+ block.decodeBlock(rgba);
+
+ if (header.pf.fourcc == FOURCC_RXGB)
+ {
+ // Swap R & A.
+ for (int i = 0; i < 16; i++)
+ {
+ Color32 & c = rgba->color(i);
+ unsigned int tmp = c.r;
+ c.r = c.a;
+ c.a = tmp;
+ }
+ }
+ }
+ else if (header.pf.fourcc == FOURCC_ATI1)
+ {
+ BlockATI1 block;
+ mem_read(stream, block);
+ block.decodeBlock(rgba);
+ }
+ else if (header.pf.fourcc == FOURCC_ATI2)
+ {
+ BlockATI2 block;
+ mem_read(stream, block);
+ block.decodeBlock(rgba);
+ }
+
+ // If normal flag set, convert to normal.
+ if (header.pf.flags & DDPF_NORMAL)
+ {
+ if (header.pf.fourcc == FOURCC_ATI2)
+ {
+ for (int i = 0; i < 16; i++)
+ {
+ Color32 & c = rgba->color(i);
+ c = buildNormal(c.r, c.g);
+ }
+ }
+ else if (header.pf.fourcc == FOURCC_DXT5)
+ {
+ for (int i = 0; i < 16; i++)
+ {
+ Color32 & c = rgba->color(i);
+ c = buildNormal(c.g, c.a);
+ }
+ }
+ }
+}
+
+
+unsigned int DirectDrawSurface::blockSize() const
+{
+ switch(header.pf.fourcc)
+ {
+ case FOURCC_DXT1:
+ case FOURCC_ATI1:
+ return 8;
+ case FOURCC_DXT2:
+ case FOURCC_DXT3:
+ case FOURCC_DXT4:
+ case FOURCC_DXT5:
+ case FOURCC_RXGB:
+ case FOURCC_ATI2:
+ return 16;
+ };
+
+ // Not a block image.
+ return 0;
+}
+
+unsigned int DirectDrawSurface::mipmapSize(unsigned int mipmap) const
+{
+ unsigned int w = width();
+ unsigned int h = height();
+ unsigned int d = depth();
+
+ for (unsigned int m = 0; m < mipmap; m++)
+ {
+ w = max(1U, w / 2);
+ h = max(1U, h / 2);
+ d = max(1U, d / 2);
+ }
+
+ if (header.pf.flags & DDPF_FOURCC)
+ {
+ // @@ How are 3D textures aligned?
+ w = (w + 3) / 4;
+ h = (h + 3) / 4;
+ return blockSize() * w * h;
+ }
+ else if (header.pf.flags & DDPF_RGB)
+ {
+ // Align pixels to bytes.
+ unsigned int byteCount = (header.pf.bitcount + 7) / 8;
+
+ // Align pitch to 4 bytes.
+ unsigned int pitch = 4 * ((w * byteCount + 3) / 4);
+
+ return pitch * h * d;
+ }
+ else {
+ printf("DDS: mipmap format not supported\n");
+ return(0);
+ };
+}
+
+unsigned int DirectDrawSurface::faceSize() const
+{
+ const unsigned int count = mipmapCount();
+ unsigned int size = 0;
+
+ for (unsigned int m = 0; m < count; m++)
+ {
+ size += mipmapSize(m);
+ }
+
+ return size;
+}
+
+unsigned int DirectDrawSurface::offset(const unsigned int face, const unsigned int mipmap)
+{
+ unsigned int size = sizeof(DDSHeader);
+
+ if (face != 0)
+ {
+ size += face * faceSize();
+ }
+
+ for (unsigned int m = 0; m < mipmap; m++)
+ {
+ size += mipmapSize(m);
+ }
+
+ return size;
+}
+
+
+void DirectDrawSurface::printInfo() const
+{
+ /* printf("FOURCC: %c%c%c%c\n", ((unsigned char *)&header.fourcc)[0], ((unsigned char *)&header.fourcc)[1], ((unsigned char *)&header.fourcc)[2], ((unsigned char *)&header.fourcc)[3]); */
+ printf("Flags: 0x%.8X\n", header.flags);
+ if (header.flags & DDSD_CAPS) printf("\tDDSD_CAPS\n");
+ if (header.flags & DDSD_PIXELFORMAT) printf("\tDDSD_PIXELFORMAT\n");
+ if (header.flags & DDSD_WIDTH) printf("\tDDSD_WIDTH\n");
+ if (header.flags & DDSD_HEIGHT) printf("\tDDSD_HEIGHT\n");
+ if (header.flags & DDSD_DEPTH) printf("\tDDSD_DEPTH\n");
+ if (header.flags & DDSD_PITCH) printf("\tDDSD_PITCH\n");
+ if (header.flags & DDSD_LINEARSIZE) printf("\tDDSD_LINEARSIZE\n");
+ if (header.flags & DDSD_MIPMAPCOUNT) printf("\tDDSD_MIPMAPCOUNT\n");
+
+ printf("Height: %d\n", header.height);
+ printf("Width: %d\n", header.width);
+ printf("Depth: %d\n", header.depth);
+ if (header.flags & DDSD_PITCH) printf("Pitch: %d\n", header.pitch);
+ else if (header.flags & DDSD_LINEARSIZE) printf("Linear size: %d\n", header.pitch);
+ printf("Mipmap count: %d\n", header.mipmapcount);
+
+ printf("Pixel Format:\n");
+ /* printf("\tSize: %d\n", header.pf.size); */
+ printf("\tFlags: 0x%.8X\n", header.pf.flags);
+ if (header.pf.flags & DDPF_RGB) printf("\t\tDDPF_RGB\n");
+ if (header.pf.flags & DDPF_FOURCC) printf("\t\tDDPF_FOURCC\n");
+ if (header.pf.flags & DDPF_ALPHAPIXELS) printf("\t\tDDPF_ALPHAPIXELS\n");
+ if (header.pf.flags & DDPF_ALPHA) printf("\t\tDDPF_ALPHA\n");
+ if (header.pf.flags & DDPF_PALETTEINDEXED1) printf("\t\tDDPF_PALETTEINDEXED1\n");
+ if (header.pf.flags & DDPF_PALETTEINDEXED2) printf("\t\tDDPF_PALETTEINDEXED2\n");
+ if (header.pf.flags & DDPF_PALETTEINDEXED4) printf("\t\tDDPF_PALETTEINDEXED4\n");
+ if (header.pf.flags & DDPF_PALETTEINDEXED8) printf("\t\tDDPF_PALETTEINDEXED8\n");
+ if (header.pf.flags & DDPF_ALPHAPREMULT) printf("\t\tDDPF_ALPHAPREMULT\n");
+ if (header.pf.flags & DDPF_NORMAL) printf("\t\tDDPF_NORMAL\n");
+
+ printf("\tFourCC: '%c%c%c%c'\n", ((header.pf.fourcc >> 0) & 0xFF), ((header.pf.fourcc >> 8) & 0xFF), ((header.pf.fourcc >> 16) & 0xFF), ((header.pf.fourcc >> 24) & 0xFF));
+ printf("\tBit count: %d\n", header.pf.bitcount);
+ printf("\tRed mask: 0x%.8X\n", header.pf.rmask);
+ printf("\tGreen mask: 0x%.8X\n", header.pf.gmask);
+ printf("\tBlue mask: 0x%.8X\n", header.pf.bmask);
+ printf("\tAlpha mask: 0x%.8X\n", header.pf.amask);
+
+ printf("Caps:\n");
+ printf("\tCaps 1: 0x%.8X\n", header.caps.caps1);
+ if (header.caps.caps1 & DDSCAPS_COMPLEX) printf("\t\tDDSCAPS_COMPLEX\n");
+ if (header.caps.caps1 & DDSCAPS_TEXTURE) printf("\t\tDDSCAPS_TEXTURE\n");
+ if (header.caps.caps1 & DDSCAPS_MIPMAP) printf("\t\tDDSCAPS_MIPMAP\n");
+
+ printf("\tCaps 2: 0x%.8X\n", header.caps.caps2);
+ if (header.caps.caps2 & DDSCAPS2_VOLUME) printf("\t\tDDSCAPS2_VOLUME\n");
+ else if (header.caps.caps2 & DDSCAPS2_CUBEMAP)
+ {
+ printf("\t\tDDSCAPS2_CUBEMAP\n");
+ if ((header.caps.caps2 & DDSCAPS2_CUBEMAP_ALL_FACES) == DDSCAPS2_CUBEMAP_ALL_FACES) printf("\t\tDDSCAPS2_CUBEMAP_ALL_FACES\n");
+ else {
+ if (header.caps.caps2 & DDSCAPS2_CUBEMAP_POSITIVEX) printf("\t\tDDSCAPS2_CUBEMAP_POSITIVEX\n");
+ if (header.caps.caps2 & DDSCAPS2_CUBEMAP_NEGATIVEX) printf("\t\tDDSCAPS2_CUBEMAP_NEGATIVEX\n");
+ if (header.caps.caps2 & DDSCAPS2_CUBEMAP_POSITIVEY) printf("\t\tDDSCAPS2_CUBEMAP_POSITIVEY\n");
+ if (header.caps.caps2 & DDSCAPS2_CUBEMAP_NEGATIVEY) printf("\t\tDDSCAPS2_CUBEMAP_NEGATIVEY\n");
+ if (header.caps.caps2 & DDSCAPS2_CUBEMAP_POSITIVEZ) printf("\t\tDDSCAPS2_CUBEMAP_POSITIVEZ\n");
+ if (header.caps.caps2 & DDSCAPS2_CUBEMAP_NEGATIVEZ) printf("\t\tDDSCAPS2_CUBEMAP_NEGATIVEZ\n");
+ }
+ }
+
+ printf("\tCaps 3: 0x%.8X\n", header.caps.caps3);
+ printf("\tCaps 4: 0x%.8X\n", header.caps.caps4);
+
+ if (header.reserved[9] == MAKEFOURCC('N', 'V', 'T', 'T'))
+ {
+ int major = (header.reserved[10] >> 16) & 0xFF;
+ int minor = (header.reserved[10] >> 8) & 0xFF;
+ int revision= header.reserved[10] & 0xFF;
+
+ printf("Version:\n");
+ printf("\tNVIDIA Texture Tools %d.%d.%d\n", major, minor, revision);
+ }
+}
+
diff --git a/source/blender/imbuf/intern/dds/DirectDrawSurface.h b/source/blender/imbuf/intern/dds/DirectDrawSurface.h
new file mode 100644
index 00000000000..2b3319d05a1
--- /dev/null
+++ b/source/blender/imbuf/intern/dds/DirectDrawSurface.h
@@ -0,0 +1,162 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributors: Amorilia (amorilia@gamebox.net)
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/*
+ * This file is based on a similar file from the NVIDIA texture tools
+ * (http://nvidia-texture-tools.googlecode.com/)
+ *
+ * Original license from NVIDIA follows.
+ */
+
+// Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+
+#ifndef _DDS_DIRECTDRAWSURFACE_H
+#define _DDS_DIRECTDRAWSURFACE_H
+
+#include <Stream.h>
+#include <ColorBlock.h>
+#include <Image.h>
+
+struct DDSPixelFormat {
+ unsigned int size;
+ unsigned int flags;
+ unsigned int fourcc;
+ unsigned int bitcount;
+ unsigned int rmask;
+ unsigned int gmask;
+ unsigned int bmask;
+ unsigned int amask;
+};
+
+struct DDSCaps {
+ unsigned int caps1;
+ unsigned int caps2;
+ unsigned int caps3;
+ unsigned int caps4;
+};
+
+/// DDS file header.
+struct DDSHeader {
+ unsigned int fourcc;
+ unsigned int size;
+ unsigned int flags;
+ unsigned int height;
+ unsigned int width;
+ unsigned int pitch;
+ unsigned int depth;
+ unsigned int mipmapcount;
+ unsigned int reserved[11];
+ DDSPixelFormat pf;
+ DDSCaps caps;
+ unsigned int notused;
+
+ // Helper methods.
+ DDSHeader();
+
+ void setWidth(unsigned int w);
+ void setHeight(unsigned int h);
+ void setDepth(unsigned int d);
+ void setMipmapCount(unsigned int count);
+ void setTexture2D();
+ void setTexture3D();
+ void setTextureCube();
+ void setLinearSize(unsigned int size);
+ void setPitch(unsigned int pitch);
+ void setFourCC(unsigned char c0, unsigned char c1, unsigned char c2, unsigned char c3);
+ void setPixelFormat(unsigned int bitcount, unsigned int rmask, unsigned int gmask, unsigned int bmask, unsigned int amask);
+ void setNormalFlag(bool b);
+
+ /* void swapBytes(); */
+};
+
+/// DirectDraw Surface. (DDS)
+class DirectDrawSurface
+{
+public:
+ DirectDrawSurface(unsigned char *mem, unsigned int size);
+ ~DirectDrawSurface();
+
+ bool isValid() const;
+ bool isSupported() const;
+
+ unsigned int mipmapCount() const;
+ unsigned int width() const;
+ unsigned int height() const;
+ unsigned int depth() const;
+ bool isTexture2D() const;
+ bool isTexture3D() const;
+ bool isTextureCube() const;
+ bool hasAlpha() const; /* false for DXT1, true for all others */
+
+ void mipmap(Image * img, unsigned int f, unsigned int m);
+
+ void printInfo() const;
+
+private:
+
+ unsigned int blockSize() const;
+ unsigned int faceSize() const;
+ unsigned int mipmapSize(unsigned int m) const;
+
+ unsigned int offset(unsigned int f, unsigned int m);
+
+ void readLinearImage(Image * img);
+ void readBlockImage(Image * img);
+ void readBlock(ColorBlock * rgba);
+
+
+private:
+ Stream stream; // memory where DDS file resides
+ DDSHeader header;
+};
+
+void mem_read(Stream & mem, DDSPixelFormat & pf);
+void mem_read(Stream & mem, DDSCaps & caps);
+void mem_read(Stream & mem, DDSHeader & header);
+
+#endif // _DDS_DIRECTDRAWSURFACE_H
diff --git a/source/blender/imbuf/intern/dds/Image.cpp b/source/blender/imbuf/intern/dds/Image.cpp
new file mode 100644
index 00000000000..f3e6fa38955
--- /dev/null
+++ b/source/blender/imbuf/intern/dds/Image.cpp
@@ -0,0 +1,132 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributors: Amorilia (amorilia@gamebox.net)
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/*
+ * This file is based on a similar file from the NVIDIA texture tools
+ * (http://nvidia-texture-tools.googlecode.com/)
+ *
+ * Original license from NVIDIA follows.
+ */
+
+// This code is in the public domain -- castanyo@yahoo.es
+
+#include <Color.h>
+#include <Image.h>
+
+#include <stdio.h> // printf
+
+Image::Image() : m_width(0), m_height(0), m_format(Format_RGB), m_data(0)
+{
+}
+
+Image::~Image()
+{
+ free();
+}
+
+void Image::allocate(unsigned int w, unsigned int h)
+{
+ free();
+ m_width = w;
+ m_height = h;
+ m_data = new Color32[w * h];
+}
+
+void Image::free()
+{
+ if (m_data) delete [] m_data;
+ m_data = 0;
+}
+
+
+unsigned int Image::width() const
+{
+ return m_width;
+}
+
+unsigned int Image::height() const
+{
+ return m_height;
+}
+
+const Color32 * Image::scanline(unsigned int h) const
+{
+ if (h >= m_height) {
+ printf("DDS: scanline beyond dimensions of image");
+ return m_data;
+ }
+ return m_data + h * m_width;
+}
+
+Color32 * Image::scanline(unsigned int h)
+{
+ if (h >= m_height) {
+ printf("DDS: scanline beyond dimensions of image");
+ return m_data;
+ }
+ return m_data + h * m_width;
+}
+
+const Color32 * Image::pixels() const
+{
+ return m_data;
+}
+
+Color32 * Image::pixels()
+{
+ return m_data;
+}
+
+const Color32 & Image::pixel(unsigned int idx) const
+{
+ if (idx >= m_width * m_height) {
+ printf("DDS: pixel beyond dimensions of image");
+ return m_data[0];
+ }
+ return m_data[idx];
+}
+
+Color32 & Image::pixel(unsigned int idx)
+{
+ if (idx >= m_width * m_height) {
+ printf("DDS: pixel beyond dimensions of image");
+ return m_data[0];
+ }
+ return m_data[idx];
+}
+
+
+Image::Format Image::format() const
+{
+ return m_format;
+}
+
+void Image::setFormat(Image::Format f)
+{
+ m_format = f;
+}
+
diff --git a/source/blender/imbuf/intern/dds/Image.h b/source/blender/imbuf/intern/dds/Image.h
new file mode 100644
index 00000000000..10356774777
--- /dev/null
+++ b/source/blender/imbuf/intern/dds/Image.h
@@ -0,0 +1,103 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributors: Amorilia (amorilia@gamebox.net)
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/*
+ * This file is based on a similar file from the NVIDIA texture tools
+ * (http://nvidia-texture-tools.googlecode.com/)
+ *
+ * Original license from NVIDIA follows.
+ */
+
+// This code is in the public domain -- castanyo@yahoo.es
+
+#ifndef _DDS_IMAGE_H
+#define _DDS_IMAGE_H
+
+#include <Color.h>
+
+/// 32 bit RGBA image.
+class Image
+{
+public:
+
+ enum Format
+ {
+ Format_RGB,
+ Format_ARGB,
+ };
+
+ Image();
+ ~Image();
+
+ void allocate(unsigned int w, unsigned int h);
+ /*
+ bool load(const char * name);
+
+ void wrap(void * data, unsigned int w, unsigned int h);
+ void unwrap();
+ */
+
+ unsigned int width() const;
+ unsigned int height() const;
+
+ const Color32 * scanline(unsigned int h) const;
+ Color32 * scanline(unsigned int h);
+
+ const Color32 * pixels() const;
+ Color32 * pixels();
+
+ const Color32 & pixel(unsigned int idx) const;
+ Color32 & pixel(unsigned int idx);
+
+ const Color32 & pixel(unsigned int x, unsigned int y) const;
+ Color32 & pixel(unsigned int x, unsigned int y);
+
+ Format format() const;
+ void setFormat(Format f);
+
+private:
+ void free();
+
+private:
+ unsigned int m_width;
+ unsigned int m_height;
+ Format m_format;
+ Color32 * m_data;
+};
+
+
+inline const Color32 & Image::pixel(unsigned int x, unsigned int y) const
+{
+ return pixel(y * width() + x);
+}
+
+inline Color32 & Image::pixel(unsigned int x, unsigned int y)
+{
+ return pixel(y * width() + x);
+}
+
+#endif // _DDS_IMAGE_H
diff --git a/source/blender/imbuf/intern/dds/Makefile b/source/blender/imbuf/intern/dds/Makefile
new file mode 100644
index 00000000000..88d59080a47
--- /dev/null
+++ b/source/blender/imbuf/intern/dds/Makefile
@@ -0,0 +1,63 @@
+#
+# $Id: Makefile 7037 2006-03-12 14:11:23Z ton $
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+#
+
+LIBNAME = dds
+DIR = $(OCGDIR)/blender/imbuf/dds
+SOURCEDIR = source/blender/imbuf/intern/dds
+
+include nan_compile.mk
+include nan_definitions.mk
+
+CFLAGS += $(LEVEL_1_C_WARNINGS)
+
+CPPFLAGS += -I$(NAN_JPEG)/include
+CPPFLAGS += -I$(NAN_PNG)/include
+CPPFLAGS += -I$(NAN_ZLIB)/include
+CPPFLAGS += -I$(NAN_TIFF)/include
+CPPFLAGS += -I../../../include
+CPPFLAGS += -I../../../blenkernel
+CPPFLAGS += -I../../../blenlib
+CPPFLAGS += -I../../../avi
+CPPFLAGS += -I../../../quicktime
+# path to the guarded memory allocator
+CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
+CPPFLAGS += -I$(NAN_MEMUTIL)/include
+# This is not really needed, but until /include is cleaned, it must be
+# there for proper compilation.
+# - No, it is also needed in antialias, for listbase (nzc)
+CPPFLAGS += -I../../../makesdna
+# external interface of this module
+CPPFLAGS += -I../..
+CPPFLAGS += -I..
+CPPFLAGS += -I.
+CPPFLAGS += -DWITH_DDS
diff --git a/source/blender/imbuf/intern/dds/SConscript b/source/blender/imbuf/intern/dds/SConscript
new file mode 100644
index 00000000000..d005bae02be
--- /dev/null
+++ b/source/blender/imbuf/intern/dds/SConscript
@@ -0,0 +1,19 @@
+#!/usr/bin/python
+Import ('env')
+
+source_files = ['dds_api.cpp', 'DirectDrawSurface.cpp', 'Stream.cpp', 'BlockDXT.cpp', 'ColorBlock.cpp', 'Image.cpp']
+
+incs = ['.',
+ '../../',
+ '../..',
+ '..',
+ '../../../makesdna',
+ '../../../blenkernel',
+ '../../../blenlib',
+ 'intern/include',
+ '#/intern/guardedalloc']
+
+
+defs = ['WITH_DDS']
+
+env.BlenderLib ('bf_dds', source_files, incs, defs, libtype=['core','player'], priority = [90, 200])
diff --git a/source/blender/imbuf/intern/dds/Stream.cpp b/source/blender/imbuf/intern/dds/Stream.cpp
new file mode 100644
index 00000000000..2340598b4fa
--- /dev/null
+++ b/source/blender/imbuf/intern/dds/Stream.cpp
@@ -0,0 +1,99 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributors: Amorilia (amorilia@gamebox.net)
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <Stream.h>
+
+#include <stdio.h> // printf
+#include <string.h> // memcpy
+
+unsigned int Stream::seek(unsigned int p)
+{
+ if (p > size) {
+ printf("DDS: trying to seek beyond end of stream (corrupt file?)");
+ }
+ else {
+ pos = p;
+ }
+
+ return pos;
+}
+
+unsigned int mem_read(Stream & mem, unsigned long long & i)
+{
+ if (mem.pos + 8 > mem.size) {
+ printf("DDS: trying to read beyond end of stream (corrupt file?)");
+ return(0);
+ };
+ memcpy(&i, mem.mem + mem.pos, 8); // @@ todo: make sure little endian
+ mem.pos += 8;
+ return(8);
+}
+
+unsigned int mem_read(Stream & mem, unsigned int & i)
+{
+ if (mem.pos + 4 > mem.size) {
+ printf("DDS: trying to read beyond end of stream (corrupt file?)");
+ return(0);
+ };
+ memcpy(&i, mem.mem + mem.pos, 4); // @@ todo: make sure little endian
+ mem.pos += 4;
+ return(4);
+}
+
+unsigned int mem_read(Stream & mem, unsigned short & i)
+{
+ if (mem.pos + 2 > mem.size) {
+ printf("DDS: trying to read beyond end of stream (corrupt file?)");
+ return(0);
+ };
+ memcpy(&i, mem.mem + mem.pos, 2); // @@ todo: make sure little endian
+ mem.pos += 2;
+ return(2);
+}
+
+unsigned int mem_read(Stream & mem, unsigned char & i)
+{
+ if (mem.pos + 1 > mem.size) {
+ printf("DDS: trying to read beyond end of stream (corrupt file?)");
+ return(0);
+ };
+ i = (mem.mem + mem.pos)[0];
+ mem.pos += 1;
+ return(1);
+}
+
+unsigned int mem_read(Stream & mem, unsigned char *i, unsigned int cnt)
+{
+ if (mem.pos + cnt > mem.size) {
+ printf("DDS: trying to read beyond end of stream (corrupt file?)");
+ return(0);
+ };
+ memcpy(i, mem.mem + mem.pos, cnt);
+ mem.pos += cnt;
+ return(cnt);
+}
+
diff --git a/source/blender/imbuf/intern/dds/Stream.h b/source/blender/imbuf/intern/dds/Stream.h
new file mode 100644
index 00000000000..373e68db44e
--- /dev/null
+++ b/source/blender/imbuf/intern/dds/Stream.h
@@ -0,0 +1,49 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributors: Amorilia (amorilia@gamebox.net)
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/* simple memory stream functions with buffer overflow check */
+
+#ifndef _STREAM_H
+#define _STREAM_H
+
+struct Stream
+{
+ unsigned char *mem; // location in memory
+ unsigned int size; // size
+ unsigned int pos; // current position
+ Stream(unsigned char *m, unsigned int s) : mem(m), size(s), pos(0) {};
+ unsigned int seek(unsigned int p);
+};
+
+unsigned int mem_read(Stream & mem, unsigned long long & i);
+unsigned int mem_read(Stream & mem, unsigned int & i);
+unsigned int mem_read(Stream & mem, unsigned short & i);
+unsigned int mem_read(Stream & mem, unsigned char & i);
+unsigned int mem_read(Stream & mem, unsigned char *i, unsigned int cnt);
+
+#endif // _STREAM_H
+
diff --git a/source/blender/imbuf/intern/dds/dds_api.cpp b/source/blender/imbuf/intern/dds/dds_api.cpp
new file mode 100644
index 00000000000..3de30b9f183
--- /dev/null
+++ b/source/blender/imbuf/intern/dds/dds_api.cpp
@@ -0,0 +1,132 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributors: Amorilia (amorilia@gamebox.net)
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <dds_api.h>
+#include <Stream.h>
+#include <DirectDrawSurface.h>
+#include <stdio.h> // printf
+#include <fstream>
+
+extern "C" {
+
+#include "imbuf.h"
+#include "imbuf_patch.h"
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+#include "IMB_allocimbuf.h"
+
+
+short imb_save_dds(struct ImBuf * ibuf, char *name, int flags)
+{
+ return(0); /* todo: finish this function */
+
+ /* check image buffer */
+ if (ibuf == 0) return (0);
+ if (ibuf->rect == 0) return (0);
+
+ /* open file for writing */
+ std::ofstream fildes(name);
+
+ /* write header */
+ fildes << "DDS ";
+ fildes.close();
+
+ return(1);
+}
+
+int imb_is_a_dds(unsigned char *mem) // note: use at most first 32 bytes
+{
+ /* heuristic check to see if mem contains a DDS file */
+ /* header.fourcc == FOURCC_DDS */
+ if ((mem[0] != 'D') || (mem[1] != 'D') || (mem[2] != 'S') || (mem[3] != ' ')) return(0);
+ /* header.size == 124 */
+ if ((mem[4] != 124) || mem[5] || mem[6] || mem[7]) return(0);
+ return(1);
+}
+
+struct ImBuf *imb_load_dds(unsigned char *mem, int size, int flags)
+{
+ struct ImBuf * ibuf = 0;
+ DirectDrawSurface dds(mem, size); /* reads header */
+ unsigned char bits_per_pixel;
+ unsigned int *rect;
+ Image img;
+ unsigned int numpixels = 0;
+ int col;
+ unsigned char *cp = (unsigned char *) &col;
+ Color32 pixel;
+ Color32 *pixels = 0;
+
+ /* check if DDS is valid and supported */
+ if (!dds.isValid()) {
+ printf("DDS: not valid; header follows\n");
+ dds.printInfo();
+ return(0);
+ }
+ if (!dds.isSupported()) {
+ printf("DDS: format not supported\n");
+ return(0);
+ }
+ if ((dds.width() > 65535) || (dds.height() > 65535)) {
+ printf("DDS: dimensions too large\n");
+ return(0);
+ }
+
+ /* convert DDS into ImBuf */
+ if (dds.hasAlpha()) bits_per_pixel = 32;
+ else bits_per_pixel = 24;
+ ibuf = IMB_allocImBuf(dds.width(), dds.height(), bits_per_pixel, 0, 0);
+ if (ibuf == 0) return(0); /* memory allocation failed */
+
+ ibuf->ftype = DDS;
+
+ if ((flags & IB_test) == 0) {
+ if (!imb_addrectImBuf(ibuf)) return(ibuf);
+ if (ibuf->rect == 0) return(ibuf);
+
+ rect = ibuf->rect;
+ dds.mipmap(&img, 0, 0); /* load first face, first mipmap */
+ pixels = img.pixels();
+ numpixels = dds.width() * dds.height();
+ cp[3] = 0xff; /* default alpha if alpha channel is not present */
+
+ for (unsigned int i = 0; i < numpixels; i++) {
+ pixel = pixels[i];
+ cp[0] = pixel.r; /* set R component of col */
+ cp[1] = pixel.g; /* set G component of col */
+ cp[2] = pixel.b; /* set B component of col */
+ if (bits_per_pixel == 32)
+ cp[3] = pixel.a; /* set A component of col */
+ rect[i] = col;
+ }
+ IMB_flipy(ibuf);
+ }
+
+ return(ibuf);
+}
+
+} // extern "C"
diff --git a/source/blender/imbuf/intern/dds/dds_api.h b/source/blender/imbuf/intern/dds/dds_api.h
new file mode 100644
index 00000000000..8a0f966dd68
--- /dev/null
+++ b/source/blender/imbuf/intern/dds/dds_api.h
@@ -0,0 +1,43 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributors: Amorilia (amorilia@gamebox.net)
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef _DDS_API_H
+#define _DDS_API_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+short imb_save_dds(struct ImBuf *ibuf, char *name, int flags);
+int imb_is_a_dds(unsigned char *mem); /* use only first 32 bytes of mem */
+struct ImBuf *imb_load_dds(unsigned char *mem, int size, int flags);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __DDS_API_H */
diff --git a/source/blender/imbuf/intern/dither.c b/source/blender/imbuf/intern/dither.c
new file mode 100644
index 00000000000..608332af244
--- /dev/null
+++ b/source/blender/imbuf/intern/dither.c
@@ -0,0 +1,133 @@
+/**
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * dither.c
+ *
+ * $Id$
+ */
+
+#include "BLI_blenlib.h"
+
+#include "imbuf.h"
+#include "imbuf_patch.h"
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+void IMB_dit0(struct ImBuf * ibuf, short ofs, short bits)
+{
+ int x, y, and, add, pix;
+ uchar *rect;
+
+ rect= (uchar *)ibuf->rect;
+ rect +=ofs;
+
+ bits = 8 - bits;
+ and = ~((1 << bits)-1);
+ add = 1 << (bits - 1);
+
+ for (y = ibuf->y; y > 0; y--){
+ for (x = ibuf->x; x > 0; x--) {
+ pix = *rect + add;
+ if (pix > 255) pix = 255;
+ *rect = pix & and;
+ rect += 4;
+ }
+ }
+}
+
+void IMB_dit2(struct ImBuf * ibuf, short ofs, short bits)
+{
+ short x,y,pix,and,add1,add2;
+ uchar *rect;
+ uchar dit[4];
+
+ rect= (uchar *)ibuf->rect;
+ rect +=ofs;
+
+ bits = 8 - bits;
+ and = ~((1<<bits)-1);
+ bits -= 2;
+
+ ofs = 0;
+
+ switch(ofs){
+ case 3:
+ break;
+ case 2:
+ dit[0]=0;
+ dit[1]=1;
+ dit[2]=2;
+ dit[3]=3;
+ break;
+ case 1:
+ dit[0]=3;
+ dit[1]=1;
+ dit[2]=0;
+ dit[3]=2;
+ break;
+ case 0:
+ dit[0]=0;
+ dit[1]=2;
+ dit[2]=3;
+ dit[3]=1;
+ break;
+ }
+
+ if (bits < 0){
+ dit[0] >>= -bits;
+ dit[1] >>= -bits;
+ dit[2] >>= -bits;
+ dit[3] >>= -bits;
+ } else{
+ dit[0] <<= bits;
+ dit[1] <<= bits;
+ dit[2] <<= bits;
+ dit[3] <<= bits;
+ }
+
+ for(y=ibuf->y;y>0;y--){
+ if(y & 1){
+ add1=dit[0];
+ add2=dit[1];
+ }
+ else{
+ add1=dit[2];
+ add2=dit[3];
+ }
+ for(x=ibuf->x;x>0;x--){
+ pix = *rect;
+ if (x & 1) pix += add1;
+ else pix += add2;
+
+ if (pix>255) pix=255;
+ *rect = pix & and;
+ rect += 4;
+ }
+ }
+}
diff --git a/source/blender/imbuf/intern/divers.c b/source/blender/imbuf/intern/divers.c
new file mode 100644
index 00000000000..8db07f581f5
--- /dev/null
+++ b/source/blender/imbuf/intern/divers.c
@@ -0,0 +1,258 @@
+/**
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * allocimbuf.c
+ *
+ * $Id$
+ */
+
+#include "BLI_blenlib.h"
+#include "BLI_rand.h"
+
+#include "imbuf.h"
+#include "imbuf_patch.h"
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+#include "IMB_allocimbuf.h"
+#include "IMB_divers.h"
+
+void imb_checkncols(struct ImBuf *ibuf)
+{
+ unsigned int i;
+
+ if (ibuf==0) return;
+
+ if (IS_amiga(ibuf)){
+ if (IS_ham(ibuf)){
+ if (ibuf->depth == 0) ibuf->depth = 6;
+ ibuf->mincol = 0;
+ ibuf->maxcol = 1 << (ibuf->depth - 2);
+ /*printf("%d %d\n", ibuf->maxcol, ibuf->depth);*/
+ return;
+ } else if (IS_hbrite(ibuf)){
+ ibuf->mincol = 0;
+ ibuf->maxcol = 64;
+ ibuf->depth = 6;
+ return;
+ }
+ }
+
+ if (ibuf->maxcol == 0){
+ if (ibuf->depth <= 8){
+ ibuf->mincol = 0;
+ ibuf->maxcol = (1 << ibuf->depth);
+ return;
+ } else if (ibuf->depth == 0){
+ ibuf->depth = 5;
+ ibuf->mincol = 0;
+ ibuf->maxcol = 32;
+ }
+ return;
+ } else {
+ /* ibuf->maxcol defines the depth */
+ for (i=1 ; ibuf->maxcol > (1 << i); i++);
+ ibuf->depth = i;
+ return;
+ }
+}
+
+
+void IMB_de_interlace(struct ImBuf *ibuf)
+{
+ struct ImBuf * tbuf1, * tbuf2;
+
+ if (ibuf == 0) return;
+ if (ibuf->flags & IB_fields) return;
+ ibuf->flags |= IB_fields;
+
+ if (ibuf->rect) {
+ /* make copies */
+ tbuf1 = IMB_allocImBuf(ibuf->x, ibuf->y / 2, 32, IB_rect, 0);
+ tbuf2 = IMB_allocImBuf(ibuf->x, ibuf->y / 2, 32, IB_rect, 0);
+
+ ibuf->x *= 2;
+ IMB_rectcpy(tbuf1, ibuf, 0, 0, 0, 0, ibuf->x, ibuf->y);
+ IMB_rectcpy(tbuf2, ibuf, 0, 0, tbuf2->x, 0, ibuf->x, ibuf->y);
+
+ ibuf->x /= 2;
+ IMB_rectcpy(ibuf, tbuf1, 0, 0, 0, 0, tbuf1->x, tbuf1->y);
+ IMB_rectcpy(ibuf, tbuf2, 0, tbuf2->y, 0, 0, tbuf2->x, tbuf2->y);
+
+ IMB_freeImBuf(tbuf1);
+ IMB_freeImBuf(tbuf2);
+ }
+ ibuf->y /= 2;
+}
+
+void IMB_interlace(struct ImBuf *ibuf)
+{
+ struct ImBuf * tbuf1, * tbuf2;
+
+ if (ibuf == 0) return;
+ ibuf->flags &= ~IB_fields;
+
+ ibuf->y *= 2;
+
+ if (ibuf->rect) {
+ /* make copies */
+ tbuf1 = IMB_allocImBuf(ibuf->x, ibuf->y / 2, 32, IB_rect, 0);
+ tbuf2 = IMB_allocImBuf(ibuf->x, ibuf->y / 2, 32, IB_rect, 0);
+
+ IMB_rectcpy(tbuf1, ibuf, 0, 0, 0, 0, ibuf->x, ibuf->y);
+ IMB_rectcpy(tbuf2, ibuf, 0, 0, 0, tbuf2->y, ibuf->x, ibuf->y);
+
+ ibuf->x *= 2;
+ IMB_rectcpy(ibuf, tbuf1, 0, 0, 0, 0, tbuf1->x, tbuf1->y);
+ IMB_rectcpy(ibuf, tbuf2, tbuf2->x, 0, 0, 0, tbuf2->x, tbuf2->y);
+ ibuf->x /= 2;
+
+ IMB_freeImBuf(tbuf1);
+ IMB_freeImBuf(tbuf2);
+ }
+}
+
+
+void IMB_gamwarp(struct ImBuf *ibuf, double gamma)
+{
+ uchar gam[256];
+ int i;
+ uchar *rect;
+ float *rectf;
+
+ if (ibuf == 0) return;
+ if (gamma == 1.0) return;
+
+ rect = (uchar *) ibuf->rect;
+ rectf = ibuf->rect_float;
+
+ gamma = 1.0 / gamma;
+
+ if (rect) {
+ for (i = 255 ; i >= 0 ; i--)
+ gam[i] = (255.0 * pow(i / 255.0 ,
+ gamma)) + 0.5;
+
+ for (i = ibuf->x * ibuf->y ; i>0 ; i--, rect+=4){
+ rect[0] = gam[rect[0]];
+ rect[1] = gam[rect[1]];
+ rect[2] = gam[rect[2]];
+ }
+ }
+
+ if (rectf) {
+ for (i = ibuf->x * ibuf->y ; i>0 ; i--, rectf+=4){
+ rectf[0] = pow(rectf[0] / 255.0, gamma);
+ rectf[1] = pow(rectf[1] / 255.0, gamma);
+ rectf[2] = pow(rectf[2] / 255.0, gamma);
+ }
+ }
+}
+
+#define FTOCHAR(val) val<=0.0f?0: (val>=1.0f?255: (char)(255.99f*val))
+
+void IMB_rect_from_float(struct ImBuf *ibuf)
+{
+ /* quick method to convert floatbuf to byte */
+ float *tof = ibuf->rect_float;
+ float dither= ibuf->dither;
+ int i, channels= ibuf->channels;
+ unsigned char *to = (unsigned char *) ibuf->rect;
+
+ if(tof==NULL) return;
+ if(to==NULL) {
+ imb_addrectImBuf(ibuf);
+ to = (unsigned char *) ibuf->rect;
+ }
+
+ if(dither==0.0f || channels!=4) {
+ if(channels==1) {
+ for (i = ibuf->x * ibuf->y; i > 0; i--, to+=4, tof++)
+ to[1]= to[2]= to[3]= to[0] = FTOCHAR(tof[0]);
+ }
+ else if(channels==3) {
+ for (i = ibuf->x * ibuf->y; i > 0; i--, to+=4, tof+=3) {
+ to[0] = FTOCHAR(tof[0]);
+ to[1] = FTOCHAR(tof[1]);
+ to[2] = FTOCHAR(tof[2]);
+ to[3] = 255;
+ }
+ }
+ else {
+ for (i = ibuf->x * ibuf->y; i > 0; i--, to+=4, tof+=4) {
+ to[0] = FTOCHAR(tof[0]);
+ to[1] = FTOCHAR(tof[1]);
+ to[2] = FTOCHAR(tof[2]);
+ to[3] = FTOCHAR(tof[3]);
+ }
+ }
+ }
+ else {
+ float dither_value, col;
+ dither= dither/255.0f;
+ for (i = ibuf->x * ibuf->y; i > 0; i--) {
+ dither_value = (BLI_frand()-0.5)*dither;
+ col= tof[0] + dither_value;
+ to[0] = FTOCHAR(col);
+ col= tof[1] + dither_value;
+ to[1] = FTOCHAR(col);
+ col= tof[2] + dither_value;
+ to[2] = FTOCHAR(col);
+ col= tof[3] + dither_value;
+ to[3] = FTOCHAR(col);
+
+ to += 4;
+ tof += 4;
+ }
+ }
+}
+
+void IMB_float_from_rect(struct ImBuf *ibuf)
+{
+ /* quick method to convert byte to floatbuf */
+ float *tof = ibuf->rect_float;
+ int i;
+ unsigned char *to = (unsigned char *) ibuf->rect;
+
+ if(to==NULL) return;
+ if(tof==NULL) {
+ imb_addrectfloatImBuf(ibuf);
+ tof = ibuf->rect_float;
+ }
+
+ for (i = ibuf->x * ibuf->y; i > 0; i--)
+ {
+ tof[0] = ((float)to[0])*(1.0f/255.0f);
+ tof[1] = ((float)to[1])*(1.0f/255.0f);
+ tof[2] = ((float)to[2])*(1.0f/255.0f);
+ tof[3] = ((float)to[3])*(1.0f/255.0f);
+ to += 4;
+ tof += 4;
+ }
+}
+
diff --git a/source/blender/imbuf/intern/dynlibtiff.c b/source/blender/imbuf/intern/dynlibtiff.c
new file mode 100644
index 00000000000..cdcb995bcff
--- /dev/null
+++ b/source/blender/imbuf/intern/dynlibtiff.c
@@ -0,0 +1,197 @@
+/**
+ * Dynamically loaded libtiff support.
+ *
+ * This file is automatically generated by the gen_dynlibtiff.py script.
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributor(s): Jonathan Merritt.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/**
+ * To use the dynamic libtiff support, you must initialize the library using:
+ * libtiff_init()
+ * This attempts to load libtiff dynamically at runtime. G.have_libtiff will
+ * be set to indicate whether or not libtiff is available. If libtiff is
+ * not available, Blender can proceed with no ill effects, provided that
+ * it does not attempt to use any of the libtiff_ functions. When you're
+ * finished, close the library with:
+ * libtiff_exit()
+ * These functions are both declared in IMB_imbuf.h
+ *
+ * The functions provided by dyn_libtiff.h are the same as those in the
+ * normal static / shared libtiff, except that they are prefixed by the
+ * string "libtiff_" to indicate that they belong to a dynamically-loaded
+ * version.
+ */
+#include "dynlibtiff.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "BLI_blenlib.h"
+
+#include "imbuf.h"
+#include "imbuf_patch.h"
+#include "IMB_imbuf.h"
+
+#include "BKE_global.h"
+#include "PIL_dynlib.h"
+
+/*********************
+ * LOCAL DEFINITIONS *
+ *********************/
+PILdynlib *libtiff = NULL;
+void libtiff_loadlibtiff(void);
+void* libtiff_findsymbol(char*);
+int libtiff_load_symbols(void);
+
+
+/**************************
+ * LIBRARY INITIALIZATION *
+ **************************/
+
+void libtiff_loadlibtiff(void)
+{
+ char *filename;
+ libtiff = NULL;
+
+ filename = getenv("BF_TIFF_LIB");
+ if (filename) libtiff = PIL_dynlib_open(filename);
+ if (libtiff != NULL) return;
+
+ /* Try to find libtiff in a couple of standard places */
+ libtiff = PIL_dynlib_open("libtiff.so");
+ if (libtiff != NULL) return;
+ libtiff = PIL_dynlib_open("libtiff.dll");
+ if (libtiff != NULL) return;
+ libtiff = PIL_dynlib_open("/usr/lib/libtiff.so");
+ if (libtiff != NULL) return;
+ /* OSX has version specific library */
+ libtiff = PIL_dynlib_open("/usr/lib/libtiff.so.3");
+ if (libtiff != NULL) return;
+ libtiff = PIL_dynlib_open("/usr/local/lib/libtiff.so");
+ if (libtiff != NULL) return;
+ /* For solaris */
+ libtiff = PIL_dynlib_open("/usr/openwin/lib/libtiff.so");
+
+}
+
+void *libtiff_findsymbol(char *name)
+{
+ void *symbol = NULL;
+ assert(libtiff != NULL);
+ symbol = PIL_dynlib_find_symbol(libtiff, name);
+ if (symbol == NULL) {
+ printf("libtiff_findsymbol: error %s\n",
+ PIL_dynlib_get_error_as_string(libtiff));
+ libtiff = NULL;
+ G.have_libtiff = (0);
+ return NULL;
+ }
+ return symbol;
+}
+
+void libtiff_init(void)
+{
+ if (libtiff != NULL) {
+ printf("libtiff_init: Attempted to load libtiff twice!\n");
+ return;
+ }
+ libtiff_loadlibtiff();
+ G.have_libtiff = ((libtiff != NULL) && (libtiff_load_symbols()));
+}
+
+void libtiff_exit(void)
+{
+ if (libtiff != NULL) {
+ PIL_dynlib_close(libtiff);
+ libtiff = NULL;
+ }
+}
+
+
+int libtiff_load_symbols(void)
+{
+ /* Attempt to load TIFFClientOpen */
+ libtiff_TIFFClientOpen = libtiff_findsymbol("TIFFClientOpen");
+ if (libtiff_TIFFClientOpen == NULL) {
+ return (0);
+ }
+ /* Attempt to load TIFFClose */
+ libtiff_TIFFClose = libtiff_findsymbol("TIFFClose");
+ if (libtiff_TIFFClose == NULL) {
+ return (0);
+ }
+ /* Attempt to load TIFFGetField */
+ libtiff_TIFFGetField = libtiff_findsymbol("TIFFGetField");
+ if (libtiff_TIFFGetField == NULL) {
+ return (0);
+ }
+ /* Attempt to load TIFFOpen */
+ libtiff_TIFFOpen = libtiff_findsymbol("TIFFOpen");
+ if (libtiff_TIFFOpen == NULL) {
+ return (0);
+ }
+ /* Attempt to load TIFFReadRGBAImage */
+ libtiff_TIFFReadRGBAImage = libtiff_findsymbol("TIFFReadRGBAImage");
+ if (libtiff_TIFFReadRGBAImage == NULL) {
+ return (0);
+ }
+ /* Attempt to load TIFFSetField */
+ libtiff_TIFFSetField = libtiff_findsymbol("TIFFSetField");
+ if (libtiff_TIFFSetField == NULL) {
+ return (0);
+ }
+ /* Attempt to load TIFFWriteEncodedStrip */
+ libtiff_TIFFWriteEncodedStrip = libtiff_findsymbol("TIFFWriteEncodedStrip");
+ if (libtiff_TIFFWriteEncodedStrip == NULL) {
+ return (0);
+ }
+ /* Attempt to load _TIFFfree */
+ libtiff__TIFFfree = libtiff_findsymbol("_TIFFfree");
+ if (libtiff__TIFFfree == NULL) {
+ return (0);
+ }
+ /* Attempt to load _TIFFmalloc */
+ libtiff__TIFFmalloc = libtiff_findsymbol("_TIFFmalloc");
+ if (libtiff__TIFFmalloc == NULL) {
+ return (0);
+ }
+ return (1);
+}
+
+
+/*******************
+ * SYMBOL POINTERS *
+ *******************/
+
+TIFF* (*libtiff_TIFFClientOpen)(const char*, const char*, thandle_t, TIFFReadWriteProc, TIFFReadWriteProc, TIFFSeekProc, TIFFCloseProc, TIFFSizeProc, TIFFMapFileProc, TIFFUnmapFileProc) = NULL;
+void (*libtiff_TIFFClose)(TIFF*) = NULL;
+int (*libtiff_TIFFGetField)(TIFF*, ttag_t, ...) = NULL;
+TIFF* (*libtiff_TIFFOpen)(const char*, const char*) = NULL;
+int (*libtiff_TIFFReadRGBAImage)(TIFF*, uint32, uint32, uint32*, int) = NULL;
+int (*libtiff_TIFFSetField)(TIFF*, ttag_t, ...) = NULL;
+tsize_t (*libtiff_TIFFWriteEncodedStrip)(TIFF*, tstrip_t, tdata_t, tsize_t) = NULL;
+void (*libtiff__TIFFfree)(tdata_t) = NULL;
+tdata_t (*libtiff__TIFFmalloc)(tsize_t) = NULL;
diff --git a/source/blender/imbuf/intern/dynlibtiff.h b/source/blender/imbuf/intern/dynlibtiff.h
new file mode 100644
index 00000000000..8d61ee3ca87
--- /dev/null
+++ b/source/blender/imbuf/intern/dynlibtiff.h
@@ -0,0 +1,58 @@
+/**
+ * Dynamically loaded libtiff support.
+ *
+ * This file is automatically generated by the gen_dynlibtiff.py script.
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributor(s): Jonathan Merritt.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/**
+ * To use the dynamic libtiff support, you must initialize the library using:
+ * libtiff_init()
+ * This attempts to load libtiff dynamically at runtime. G.have_libtiff will
+ * be set to indicate whether or not libtiff is available. If libtiff is
+ * not available, Blender can proceed with no ill effects, provided that
+ * it does not attempt to use any of the libtiff_ functions. When you're
+ * finished, close the library with:
+ * libtiff_exit()
+ * These functions are both declared in IMB_imbuf.h
+ *
+ * The functions provided by dyn_libtiff.h are the same as those in the
+ * normal static / shared libtiff, except that they are prefixed by the
+ * string "libtiff_" to indicate that they belong to a dynamically-loaded
+ * version.
+ */
+#ifndef DYN_LIBTIFF_H
+#include "tiffio.h"
+extern TIFF* (*libtiff_TIFFClientOpen)(const char*, const char*, thandle_t, TIFFReadWriteProc, TIFFReadWriteProc, TIFFSeekProc, TIFFCloseProc, TIFFSizeProc, TIFFMapFileProc, TIFFUnmapFileProc);
+extern void (*libtiff_TIFFClose)(TIFF*);
+extern int (*libtiff_TIFFGetField)(TIFF*, ttag_t, ...);
+extern TIFF* (*libtiff_TIFFOpen)(const char*, const char*);
+extern int (*libtiff_TIFFReadRGBAImage)(TIFF*, uint32, uint32, uint32*, int);
+extern int (*libtiff_TIFFSetField)(TIFF*, ttag_t, ...);
+extern tsize_t (*libtiff_TIFFWriteEncodedStrip)(TIFF*, tstrip_t, tdata_t, tsize_t);
+extern void (*libtiff__TIFFfree)(tdata_t);
+extern tdata_t (*libtiff__TIFFmalloc)(tsize_t);
+#endif /* DYN_LIBTIFF_H */
+
diff --git a/source/blender/imbuf/intern/filter.c b/source/blender/imbuf/intern/filter.c
new file mode 100644
index 00000000000..fd9dac1af2b
--- /dev/null
+++ b/source/blender/imbuf/intern/filter.c
@@ -0,0 +1,329 @@
+/**
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * filter.c
+ *
+ * $Id$
+ */
+
+#include "BLI_blenlib.h"
+
+#include "imbuf.h"
+#include "imbuf_patch.h"
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+#include "IMB_filter.h"
+
+
+/************************************************************************/
+/* FILTERS */
+/************************************************************************/
+
+static void filtrow(unsigned char *point, int x)
+{
+ unsigned int c1,c2,c3,error;
+
+ if (x>1){
+ c1 = c2 = *point;
+ error = 2;
+ for(x--;x>0;x--){
+ c3 = point[4];
+ c1 += (c2<<1) + c3 + error;
+ error = c1 & 3;
+ *point = c1 >> 2;
+ point += 4;
+ c1=c2;
+ c2=c3;
+ }
+ *point = (c1 + (c2<<1) + c2 + error) >> 2;
+ }
+}
+
+static void filtrowf(float *point, int x)
+{
+ float c1,c2,c3;
+
+ if (x>1){
+ c1 = c2 = *point;
+ for(x--;x>0;x--){
+ c3 = point[4];
+ c1 += (c2 * 2) + c3;
+ *point = 0.25f*c1;
+ point += 4;
+ c1=c2;
+ c2=c3;
+ }
+ *point = 0.25f*(c1 + (c2 * 2) + c2);
+ }
+}
+
+
+
+static void filtcolum(unsigned char *point, int y, int skip)
+{
+ unsigned int c1,c2,c3,error;
+ unsigned char *point2;
+
+ if (y>1){
+ c1 = c2 = *point;
+ point2 = point;
+ error = 2;
+ for(y--;y>0;y--){
+ point2 += skip;
+ c3 = *point2;
+ c1 += (c2<<1) + c3 +error;
+ error = c1 & 3;
+ *point = c1 >> 2;
+ point=point2;
+ c1=c2;
+ c2=c3;
+ }
+ *point = (c1 + (c2<<1) + c2 + error) >> 2;
+ }
+}
+
+static void filtcolumf(float *point, int y, int skip)
+{
+ float c1,c2,c3, *point2;
+
+ if (y>1){
+ c1 = c2 = *point;
+ point2 = point;
+ for(y--;y>0;y--){
+ point2 += skip;
+ c3 = *point2;
+ c1 += (c2 * 2) + c3;
+ *point = 0.25f*c1;
+ point=point2;
+ c1=c2;
+ c2=c3;
+ }
+ *point = 0.25f*(c1 + (c2 * 2) + c2);
+ }
+}
+
+void IMB_filtery(struct ImBuf *ibuf)
+{
+ unsigned char *point;
+ float *pointf;
+ int x, y, skip;
+
+ point = (unsigned char *)ibuf->rect;
+ pointf = ibuf->rect_float;
+
+ x = ibuf->x;
+ y = ibuf->y;
+ skip = x<<2;
+
+ for (;x>0;x--){
+ if (point) {
+ if (ibuf->depth > 24) filtcolum(point,y,skip);
+ point++;
+ filtcolum(point,y,skip);
+ point++;
+ filtcolum(point,y,skip);
+ point++;
+ filtcolum(point,y,skip);
+ point++;
+ }
+ if (pointf) {
+ if (ibuf->depth > 24) filtcolumf(pointf,y,skip);
+ pointf++;
+ filtcolumf(pointf,y,skip);
+ pointf++;
+ filtcolumf(pointf,y,skip);
+ pointf++;
+ filtcolumf(pointf,y,skip);
+ pointf++;
+ }
+ }
+}
+
+
+void imb_filterx(struct ImBuf *ibuf)
+{
+ unsigned char *point;
+ float *pointf;
+ int x, y, skip;
+
+ point = (unsigned char *)ibuf->rect;
+ pointf = ibuf->rect_float;
+
+ x = ibuf->x;
+ y = ibuf->y;
+ skip = (x<<2) - 3;
+
+ for (;y>0;y--){
+ if (point) {
+ if (ibuf->depth > 24) filtrow(point,x);
+ point++;
+ filtrow(point,x);
+ point++;
+ filtrow(point,x);
+ point++;
+ filtrow(point,x);
+ point+=skip;
+ }
+ if (pointf) {
+ if (ibuf->depth > 24) filtrowf(pointf,x);
+ pointf++;
+ filtrowf(pointf,x);
+ pointf++;
+ filtrowf(pointf,x);
+ pointf++;
+ filtrowf(pointf,x);
+ pointf+=skip;
+ }
+ }
+}
+
+void IMB_filterN(ImBuf *out, ImBuf *in)
+{
+ register char *row1, *row2, *row3;
+ register char *cp;
+ int rowlen, x, y;
+
+ rowlen= in->x;
+
+ for(y=2; y<in->y; y++) {
+ /* setup rows */
+ row1= (char *)(in->rect + (y-2)*rowlen);
+ row2= row1 + 4*rowlen;
+ row3= row2 + 4*rowlen;
+
+ cp= (char *)(out->rect + (y-1)*rowlen);
+ cp[0]= row2[0];
+ cp[1]= row2[1];
+ cp[2]= row2[2];
+ cp[3]= row2[3];
+ cp+= 4;
+
+ for(x=2; x<rowlen; x++) {
+ cp[0]= (row1[0] + 2*row1[4] + row1[8] + 2*row2[0] + 4*row2[4] + 2*row2[8] + row3[0] + 2*row3[4] + row3[8])>>4;
+ cp[1]= (row1[1] + 2*row1[5] + row1[9] + 2*row2[1] + 4*row2[5] + 2*row2[9] + row3[1] + 2*row3[5] + row3[9])>>4;
+ cp[2]= (row1[2] + 2*row1[6] + row1[10] + 2*row2[2] + 4*row2[6] + 2*row2[10] + row3[2] + 2*row3[6] + row3[10])>>4;
+ cp[3]= (row1[3] + 2*row1[7] + row1[11] + 2*row2[3] + 4*row2[7] + 2*row2[11] + row3[3] + 2*row3[7] + row3[11])>>4;
+ cp+=4; row1+=4; row2+=4; row3+=4;
+ }
+ }
+}
+
+void IMB_filter(struct ImBuf *ibuf)
+{
+ IMB_filtery(ibuf);
+ imb_filterx(ibuf);
+}
+
+#define EXTEND_PIXEL(a, w) if((a)[3]) {r+= w*(a)[0]; g+= w*(a)[1]; b+= w*(a)[2]; tot+=w;}
+
+/* if alpha is zero, it checks surrounding pixels and averages color. sets new alphas to 255 */
+void IMB_filter_extend(struct ImBuf *ibuf)
+{
+ register char *row1, *row2, *row3;
+ register char *cp;
+ int rowlen, x, y;
+
+ rowlen= ibuf->x;
+
+ if(ibuf->rect) {
+ int *temprect;
+
+ /* make a copy, to prevent flooding */
+ temprect= MEM_dupallocN(ibuf->rect);
+
+ for(y=1; y<=ibuf->y; y++) {
+ /* setup rows */
+ row1= (char *)(temprect + (y-2)*rowlen);
+ row2= row1 + 4*rowlen;
+ row3= row2 + 4*rowlen;
+ if(y==1)
+ row1= row2;
+ else if(y==ibuf->y)
+ row3= row2;
+
+ cp= (char *)(ibuf->rect + (y-1)*rowlen);
+
+ for(x=0; x<rowlen; x++) {
+ if(cp[3]==0) {
+ int tot= 0, r=0, g=0, b=0;
+
+ EXTEND_PIXEL(row1, 1);
+ EXTEND_PIXEL(row2, 2);
+ EXTEND_PIXEL(row3, 1);
+ EXTEND_PIXEL(row1+4, 2);
+ EXTEND_PIXEL(row3+4, 2);
+ if(x!=rowlen-1) {
+ EXTEND_PIXEL(row1+8, 1);
+ EXTEND_PIXEL(row2+8, 2);
+ EXTEND_PIXEL(row3+8, 1);
+ }
+ if(tot) {
+ cp[0]= r/tot;
+ cp[1]= g/tot;
+ cp[2]= b/tot;
+ cp[3]= 255;
+ }
+ }
+ cp+=4;
+
+ if(x!=0) {
+ row1+=4; row2+=4; row3+=4;
+ }
+ }
+ }
+
+ MEM_freeN(temprect);
+ }
+}
+
+void IMB_makemipmap(ImBuf *ibuf, int use_filter)
+{
+ ImBuf *hbuf= ibuf;
+ int minsize, curmap=0;
+
+ minsize= ibuf->x<ibuf->y?ibuf->x:ibuf->y;
+
+ while(minsize>10 && curmap<IB_MIPMAP_LEVELS) {
+ if(use_filter) {
+ ImBuf *nbuf= IMB_allocImBuf(hbuf->x, hbuf->y, 32, IB_rect, 0);
+ IMB_filterN(nbuf, hbuf);
+ ibuf->mipmap[curmap]= IMB_onehalf(nbuf);
+ IMB_freeImBuf(nbuf);
+ }
+ else {
+ ibuf->mipmap[curmap]= IMB_onehalf(hbuf);
+ }
+ hbuf= ibuf->mipmap[curmap];
+
+ curmap++;
+ minsize= hbuf->x<hbuf->y?hbuf->x:hbuf->y;
+ }
+}
+
+
diff --git a/source/blender/imbuf/intern/gen_dynlibtiff.py b/source/blender/imbuf/intern/gen_dynlibtiff.py
new file mode 100755
index 00000000000..1ee0275854a
--- /dev/null
+++ b/source/blender/imbuf/intern/gen_dynlibtiff.py
@@ -0,0 +1,254 @@
+#!/usr/bin/env python
+
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# Contributor(s): Jonathan Merritt.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+
+#
+# This script generates a C source file and a header file that implement
+# dynamic loading functionality for libtiff.
+# If you need to make more functions from libtiff available, then simply add
+# them to the tiff_functions[] list below.
+#
+
+
+FILENAME = 'dynlibtiff'
+C_FILENAME = '%s.c' % FILENAME
+H_FILENAME = '%s.h' % FILENAME
+
+
+COMMENT = \
+"""/**
+ * Dynamically loaded libtiff support.
+ *
+ * This file is automatically generated by the gen_dynlibtiff.py script.
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributor(s): Jonathan Merritt.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/**
+ * To use the dynamic libtiff support, you must initialize the library using:
+ * libtiff_init()
+ * This attempts to load libtiff dynamically at runtime. G.have_libtiff will
+ * be set to indicate whether or not libtiff is available. If libtiff is
+ * not available, Blender can proceed with no ill effects, provided that
+ * it does not attempt to use any of the libtiff_ functions. When you're
+ * finished, close the library with:
+ * libtiff_exit()
+ * These functions are both declared in IMB_imbuf.h
+ *
+ * The functions provided by dyn_libtiff.h are the same as those in the
+ * normal static / shared libtiff, except that they are prefixed by the
+ * string "libtiff_" to indicate that they belong to a dynamically-loaded
+ * version.
+ */
+"""
+
+
+C_EXTRA = \
+"""
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "BLI_blenlib.h"
+
+#include "imbuf.h"
+#include "imbuf_patch.h"
+#include "IMB_imbuf.h"
+
+#include "BKE_global.h"
+#include "PIL_dynlib.h"
+
+/*********************
+ * LOCAL DEFINITIONS *
+ *********************/
+PILdynlib *libtiff = NULL;
+void libtiff_loadlibtiff(void);
+void* libtiff_findsymbol(char*);
+int libtiff_load_symbols(void);
+
+
+/**************************
+ * LIBRARY INITIALIZATION *
+ **************************/
+
+void libtiff_loadlibtiff(void)
+{
+ char *filename;
+ libtiff = NULL;
+
+ filename = getenv("BF_TIFF_LIB");
+ if (filename) libtiff = PIL_dynlib_open(filename);
+ if (libtiff != NULL) return;
+
+ /* Try to find libtiff in a couple of standard places */
+ libtiff = PIL_dynlib_open("libtiff.so");
+ if (libtiff != NULL) return;
+ libtiff = PIL_dynlib_open("libtiff.dll");
+ if (libtiff != NULL) return;
+ libtiff = PIL_dynlib_open("/usr/lib/libtiff.so");
+ if (libtiff != NULL) return;
+ /* OSX has version specific library */
+ libtiff = PIL_dynlib_open("/usr/lib/libtiff.so.3");
+ if (libtiff != NULL) return;
+ libtiff = PIL_dynlib_open("/usr/local/lib/libtiff.so");
+ if (libtiff != NULL) return;
+ /* For solaris */
+ libtiff = PIL_dynlib_open("/usr/openwin/lib/libtiff.so");
+
+}
+
+void *libtiff_findsymbol(char *name)
+{
+ void *symbol = NULL;
+ assert(libtiff != NULL);
+ symbol = PIL_dynlib_find_symbol(libtiff, name);
+ if (symbol == NULL) {
+ printf("libtiff_findsymbol: error %s\\n",
+ PIL_dynlib_get_error_as_string(libtiff));
+ libtiff = NULL;
+ G.have_libtiff = (0);
+ return NULL;
+ }
+ return symbol;
+}
+
+void libtiff_init(void)
+{
+ if (libtiff != NULL) {
+ printf("libtiff_init: Attempted to load libtiff twice!\\n");
+ return;
+ }
+ libtiff_loadlibtiff();
+ G.have_libtiff = ((libtiff != NULL) && (libtiff_load_symbols()));
+}
+
+void libtiff_exit(void)
+{
+ if (libtiff != NULL) {
+ PIL_dynlib_close(libtiff);
+ libtiff = NULL;
+ }
+}
+
+
+"""
+
+
+class CFun:
+ def __init__(self, name, retType, args):
+ self.name = name
+ self.retType = retType
+ self.args = args
+ def getDynamicName(self):
+ return ('libtiff_%s' % self.name)
+ def getDynamicDecl(self):
+ argstr = (('%s, '*len(self.args)) % tuple(self.args))[:-2]
+ return ('%s (*%s)(%s)' % (self.retType,
+ self.getDynamicName(), argstr))
+ def getLoadSymbol(self):
+ dname = self.getDynamicName()
+ return (
+ """\t/* Attempt to load %s */
+ %s = libtiff_findsymbol("%s");
+ if (%s == NULL) {
+ return (0);
+ }\n""" % (self.name, dname, self.name, dname))
+
+
+# If you need more functions, add them to the list below, based upon entries
+# in either tiffio.h or tiff.h.
+tiff_functions = [
+ CFun('TIFFClientOpen', 'TIFF*', ['const char*', 'const char*',
+ 'thandle_t', 'TIFFReadWriteProc', 'TIFFReadWriteProc',
+ 'TIFFSeekProc', 'TIFFCloseProc', 'TIFFSizeProc',
+ 'TIFFMapFileProc', 'TIFFUnmapFileProc']),
+ CFun('TIFFClose', 'void', ['TIFF*']),
+ CFun('TIFFGetField', 'int', ['TIFF*', 'ttag_t', '...']),
+ CFun('TIFFOpen', 'TIFF*', ['const char*', 'const char*']),
+ CFun('TIFFReadRGBAImage', 'int', ['TIFF*', 'uint32', 'uint32',
+ 'uint32*', 'int']),
+ CFun('TIFFSetField', 'int', ['TIFF*', 'ttag_t', '...']),
+ CFun('TIFFWriteEncodedStrip', 'tsize_t', ['TIFF*', 'tstrip_t',
+ 'tdata_t', 'tsize_t']),
+ CFun('_TIFFfree', 'void', ['tdata_t']),
+ CFun('_TIFFmalloc', 'tdata_t', ['tsize_t']),
+]
+
+
+def outputDynCFile(outfile, header_file_name):
+ outfile.write(COMMENT)
+ outfile.write('#include "%s"\n' % header_file_name)
+ outfile.write(C_EXTRA)
+ outfile.write('int libtiff_load_symbols(void)\n')
+ outfile.write('{\n')
+ for function in tiff_functions:
+ outfile.write(function.getLoadSymbol())
+ outfile.write('\treturn (1);\n')
+ outfile.write('}\n')
+ outfile.write("""
+
+/*******************
+ * SYMBOL POINTERS *
+ *******************/\n\n""")
+ for function in tiff_functions:
+ outfile.write('%s = NULL;\n' % function.getDynamicDecl())
+
+
+def outputDynHFile(outfile):
+ outfile.write(COMMENT)
+ outfile.write('#ifndef DYN_LIBTIFF_H\n')
+ outfile.write('#include "tiffio.h"\n')
+ for function in tiff_functions:
+ outfile.write('extern %s;\n' % function.getDynamicDecl())
+ outfile.write('#endif /* DYN_LIBTIFF_H */\n\n')
+
+
+if __name__ == '__main__':
+ outfile = file(C_FILENAME, 'w')
+ outputDynCFile(outfile, H_FILENAME)
+ outfile.close()
+ outfile = file(H_FILENAME, 'w')
+ outputDynHFile(outfile)
+ outfile.close()
diff --git a/source/blender/imbuf/intern/ham.c b/source/blender/imbuf/intern/ham.c
new file mode 100644
index 00000000000..de1d504980e
--- /dev/null
+++ b/source/blender/imbuf/intern/ham.c
@@ -0,0 +1,279 @@
+/**
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * ham.c
+ *
+ * $Id$
+ */
+
+#include "BLI_blenlib.h"
+
+#include "imbuf.h"
+#include "imbuf_patch.h"
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+#include "IMB_cmap.h"
+#include "IMB_hamx.h"
+#include "IMB_ham.h"
+
+extern short alpha_col0;
+
+#define HAMB 0x0100
+#define HAMG 0x0400
+#define HAMR 0x0200
+#define HAMC 0x1000
+#define HAMFREE 0x2000
+
+static void addhamdither(short x, unsigned char *dit,
+ short dmax, unsigned char *rgb,
+ unsigned short *ham,
+ short type, short round, short shift)
+{
+ short dx = 0;
+ short c1, c2;
+
+ for (;x>0;x--){
+ if (ham[0] & (HAMFREE | type)){
+ c2 = c1 = *rgb;
+
+ /* wrap dither */
+ while (dx >= dmax) dx -= dmax;
+
+ c1 += dit[dx];
+ if (c1 > 255) c1 = 255;
+ c2 += round;
+ if (c2 > 255) c2 = 255;
+
+ if (c1 != c2){
+ c1 >>= shift; c2 >>= shift;
+ if (ham[1] & HAMFREE){
+ ham[0] = type + c1;
+ ham[1] = type + c2;
+ } else if (ham[1] & type){
+ ham[0] = type + c1;
+ } else if ((ham[2] & (type | HAMFREE)) == type){
+ ham[0] = type + c1;
+ } else if ((ham[1] & HAMC) | (ham[2] & HAMC)){
+ ham[0] = type + c1;
+ }
+ }
+ }
+ rgb += 4;
+ ham ++;
+ dx ++;
+ }
+}
+
+static void convhamscanl(short x, short y,
+ unsigned char *rgbbase,
+ unsigned char *coltab,
+ short *deltab,
+ short bits)
+{
+ int a, r, g, b, lr, lg, lb, dr, dg, db, col, fout, type, x2;
+ int round, shift;
+ uchar *rgb, dit[2];
+ unsigned short *ham, *hambase;
+
+ /* Concept:
+ first we check the entire image, where color transitions are coded: FGRB XXXX XXXX
+ F - free color value, can be changed by anyone
+ G/R/B - green/red/blue ham transition, only to be changed by this color
+ XXXX XXXX - N bits value.
+
+ 0000 XXXX XXXX is palette color.
+
+ after that first the green dither is added, then the red dither, and finally blue dither
+ */
+
+ if ((hambase = (unsigned short *) malloc((x+4) * sizeof(unsigned short)))==0) return;
+
+ lb = coltab[1];
+ lg = coltab[2];
+ lr = coltab[3];
+ type = col = 0;
+
+ ham = hambase;
+ rgb = rgbbase;
+
+ shift = 8 - bits;
+ round = 1 << (shift - 1);
+
+ /* to prevent 'noise' at the end of the line */
+ for (x2 = 3; x2 >= 0; x2 --) hambase[x + x2] = HAMFREE;
+
+ for (x2 = x ;x2 > 0; x2--){
+ r = rgb[0] + round;
+ g = rgb[1] + round;
+ b = rgb[2] + round;
+ a = rgb[3];
+
+ if (a < 128 && alpha_col0) {
+ a = 1;
+ } else a = 0;
+
+ if (b > 255) b = 255;
+ if (g > 255) {
+ g = 255;
+ }
+ if (r > 255) r = 255;
+
+ r >>= shift;
+ g >>= shift;
+ b >>= shift;
+
+ if ((b-lb) | (g-lg) | (r-lr) | a){
+ if (a) {
+ col = 0;
+ type = HAMC;
+ } else {
+ col = ((b << (2 * bits)) + (g << bits) + r) << 1;
+ fout = deltab[col + 1];
+ col = deltab[col];
+ type = HAMC;
+
+ dr = quadr[lr-r];
+ dg = quadr[lg-g];
+ db = quadr[lb-b];
+
+ if ((dr+dg) <= fout){
+ fout = dr+dg;
+ col = b;
+ type = HAMB;
+ }
+ if ((dg+db) <= fout){
+ fout = dg+db;
+ col = r;
+ type = HAMR;
+ }
+ if ((dr+db) <= fout){
+ fout = dr+db;
+ col = g;
+ type = HAMG;
+ }
+ }
+
+ switch(type){
+ case HAMG:
+ lg = g;
+ break;
+ case HAMR:
+ lr = r;
+ break;
+ case HAMB:
+ lb = b;
+ break;
+ default:
+ lb = coltab[col*4 + 1];
+ lg = coltab[col*4 + 2];
+ lr = coltab[col*4 + 3];
+ }
+ *ham = type + col;
+ } else *ham = HAMG + HAMFREE + g;
+
+ rgb += 4;
+ ham ++;
+ }
+
+
+ if (y & 1){
+ dit[0] = 0 << (shift - 2);
+ dit[1] = 3 << (shift - 2);
+ } else {
+ dit[0] = 2 << (shift - 2);
+ dit[1] = 1 << (shift - 2);
+ }
+
+ addhamdither(x,dit,2,rgbbase+2,hambase,HAMG, round, shift);
+
+ if ((y & 1)==0){
+ dit[0] = 3 << (shift - 2);
+ dit[1] = 0 << (shift - 2);
+ } else {
+ dit[0] = 1 << (shift - 2);
+ dit[1] = 2 << (shift - 2);
+ }
+
+ addhamdither(x,dit,2,rgbbase+3,hambase,HAMR, round, shift);
+ addhamdither(x,dit,2,rgbbase+1,hambase,HAMB, round, shift);
+
+
+ ham = hambase;
+ rgb = rgbbase;
+ rgb += 3;
+
+ for (x2=x;x2>0;x2--){
+ type = *(ham++);
+ if (type & HAMG) type |= HAMR | HAMB;
+
+ *rgb = (type & 0xff) | ((type & (HAMR | HAMB)) >> shift);
+ rgb += 4;
+ }
+
+ free (hambase);
+}
+
+
+short imb_converttoham(struct ImBuf *ibuf)
+{
+ unsigned int coltab[256],*rect;
+ short x,y,* deltab;
+ int mincol;
+
+ memcpy(coltab,ibuf->cmap,4 * ibuf->maxcol);
+
+ mincol = ibuf->mincol;
+ if (alpha_col0 && mincol == 0) mincol = 1;
+
+ if (ibuf->ftype == AN_hamx) {
+ deltab = imb_coldeltatab((uchar *) coltab, 0, ibuf->maxcol, 4);
+ } else {
+ ibuf->cbits = ibuf->depth - 2;
+ imb_losecmapbits(ibuf, coltab);
+ deltab = imb_coldeltatab((uchar *) coltab, mincol, ibuf->maxcol, ibuf->cbits);
+ }
+
+ rect = ibuf->rect;
+ x=ibuf->x;
+ y=ibuf->y;
+
+ if (ibuf->ftype == AN_hamx){
+ IMB_dit2(ibuf, 2, 4);
+ IMB_dit2(ibuf, 1, 4);
+ IMB_dit2(ibuf, 0, 4);
+ imb_convhamx(ibuf, (uchar *)coltab, deltab);
+ } else {
+ for(;y > 0; y--){
+ convhamscanl(x, y, (uchar *)rect, (uchar *)coltab, deltab, ibuf->cbits);
+ rect += x;
+ }
+ }
+
+ return (TRUE);
+}
diff --git a/source/blender/imbuf/intern/hamx.c b/source/blender/imbuf/intern/hamx.c
new file mode 100644
index 00000000000..8a5cbda72ec
--- /dev/null
+++ b/source/blender/imbuf/intern/hamx.c
@@ -0,0 +1,583 @@
+/**
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * hamx.c
+ *
+ * $Id$
+ */
+
+#include "BLI_blenlib.h"
+
+#ifdef WIN32
+#include <io.h>
+#endif
+
+
+#include "imbuf.h"
+#include "imbuf_patch.h"
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "IMB_allocimbuf.h"
+#include "IMB_filter.h"
+#include "IMB_ham.h"
+#include "IMB_hamx.h"
+
+/* actually hard coded endianness */
+#define GET_BIG_LONG(x) (((uchar *) (x))[0] << 24 | ((uchar *) (x))[1] << 16 | ((uchar *) (x))[2] << 8 | ((uchar *) (x))[3])
+#define GET_LITTLE_LONG(x) (((uchar *) (x))[3] << 24 | ((uchar *) (x))[2] << 16 | ((uchar *) (x))[1] << 8 | ((uchar *) (x))[0])
+#define SWAP_L(x) (((x << 24) & 0xff000000) | ((x << 8) & 0xff0000) | ((x >> 8) & 0xff00) | ((x >> 24) & 0xff))
+#define SWAP_S(x) (((x << 8) & 0xff00) | ((x >> 8) & 0xff))
+
+/* more endianness... should move to a separate file... */
+#if defined(__sgi) || defined (__sparc) || defined (__sparc__) || defined (__PPC__) || defined (__ppc__) || defined (__BIG_ENDIAN__)
+#define GET_ID GET_BIG_LONG
+#define LITTLE_LONG SWAP_LONG
+#else
+#define GET_ID GET_LITTLE_LONG
+#define LITTLE_LONG ENDIAN_NOP
+#endif
+
+#ifndef ABS
+#define ABS(x) ((x) < 0 ? -(x) : (x))
+#endif
+
+static uchar hamx_array_char[] = {
+ 0x00,0x00,0xFF,0xFF, 0x00,0x00,0xFF,0xFF, 0x00,0x00,0xFF,0xFF, 0x00,0x00,0xFF,0xFF, 0x00,0x00,0xFF,0xFF, 0x00,0x00,0xFF,0xFF, 0x00,0x00,0xFF,0xFF, 0x00,0x00,0xFF,0xFF,
+ 0x00,0x00,0xFF,0xFF, 0x00,0x00,0xFF,0xFF, 0x00,0x00,0xFF,0xFF, 0x00,0x00,0xFF,0xFF, 0x00,0x00,0xFF,0xFF, 0x00,0x00,0xFF,0xFF, 0x00,0x00,0xFF,0xFF, 0x00,0x00,0xFF,0xFF,
+ 0x00,0xFF,0x00,0xFF, 0x00,0xFF,0x00,0xFF, 0x00,0xFF,0x00,0xFF, 0x00,0xFF,0x00,0xFF, 0x00,0xFF,0x00,0xFF, 0x00,0xFF,0x00,0xFF, 0x00,0xFF,0x00,0xFF, 0x00,0xFF,0x00,0xFF,
+ 0x00,0xFF,0x00,0xFF, 0x00,0xFF,0x00,0xFF, 0x00,0xFF,0x00,0xFF, 0x00,0xFF,0x00,0xFF, 0x00,0xFF,0x00,0xFF, 0x00,0xFF,0x00,0xFF, 0x00,0xFF,0x00,0xFF, 0x00,0xFF,0x00,0xFF,
+ 0x00,0xFF,0xFF,0x00, 0x00,0xFF,0xFF,0x00, 0x00,0xFF,0xFF,0x00, 0x00,0xFF,0xFF,0x00, 0x00,0xFF,0xFF,0x00, 0x00,0xFF,0xFF,0x00, 0x00,0xFF,0xFF,0x00, 0x00,0xFF,0xFF,0x00,
+ 0x00,0xFF,0xFF,0x00, 0x00,0xFF,0xFF,0x00, 0x00,0xFF,0xFF,0x00, 0x00,0xFF,0xFF,0x00, 0x00,0xFF,0xFF,0x00, 0x00,0xFF,0xFF,0x00, 0x00,0xFF,0xFF,0x00, 0x00,0xFF,0xFF,0x00,
+
+ 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
+
+ 0x00,0x00,0x00,0x00, 0x00,0x10,0x00,0x00, 0x00,0x20,0x00,0x00, 0x00,0x30,0x00,0x00, 0x00,0x40,0x00,0x00, 0x00,0x50,0x00,0x00, 0x00,0x60,0x00,0x00, 0x00,0x70,0x00,0x00,
+ 0x00,0x80,0x00,0x00, 0x00,0x90,0x00,0x00, 0x00,0xA0,0x00,0x00, 0x00,0xB0,0x00,0x00, 0x00,0xC0,0x00,0x00, 0x00,0xD0,0x00,0x00, 0x00,0xE0,0x00,0x00, 0x00,0xF0,0x00,0x00,
+ 0x00,0x00,0x00,0x00, 0x00,0x00,0x10,0x00, 0x00,0x00,0x20,0x00, 0x00,0x00,0x30,0x00, 0x00,0x00,0x40,0x00, 0x00,0x00,0x50,0x00, 0x00,0x00,0x60,0x00, 0x00,0x00,0x70,0x00,
+ 0x00,0x00,0x80,0x00, 0x00,0x00,0x90,0x00, 0x00,0x00,0xA0,0x00, 0x00,0x00,0xB0,0x00, 0x00,0x00,0xC0,0x00, 0x00,0x00,0xD0,0x00, 0x00,0x00,0xE0,0x00, 0x00,0x00,0xF0,0x00,
+ 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x10, 0x00,0x00,0x00,0x20, 0x00,0x00,0x00,0x30, 0x00,0x00,0x00,0x40, 0x00,0x00,0x00,0x50, 0x00,0x00,0x00,0x60, 0x00,0x00,0x00,0x70,
+ 0x00,0x00,0x00,0x80, 0x00,0x00,0x00,0x90, 0x00,0x00,0x00,0xA0, 0x00,0x00,0x00,0xB0, 0x00,0x00,0x00,0xC0, 0x00,0x00,0x00,0xD0, 0x00,0x00,0x00,0xE0, 0x00,0x00,0x00,0xF0,
+
+ 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x30, 0x00,0x00,0x00,0x60, 0x00,0x00,0x00,0x90, 0x00,0x00,0x00,0xC0, 0x00,0x00,0x00,0xF0,
+ 0x00,0x00,0x20,0x00, 0x00,0x00,0x20,0x30, 0x00,0x00,0x20,0x60, 0x00,0x00,0x20,0x90, 0x00,0x00,0x20,0xC0, 0x00,0x00,0x20,0xF0,
+ 0x00,0x00,0x40,0x00, 0x00,0x00,0x40,0x30, 0x00,0x00,0x40,0x60, 0x00,0x00,0x40,0x90, 0x00,0x00,0x40,0xC0, 0x00,0x00,0x40,0xF0,
+ 0x00,0x00,0x60,0x00, 0x00,0x00,0x60,0x30, 0x00,0x00,0x60,0x60, 0x00,0x00,0x60,0x90, 0x00,0x00,0x60,0xC0, 0x00,0x00,0x60,0xF0,
+ 0x00,0x00,0x90,0x00, 0x00,0x00,0x90,0x30, 0x00,0x00,0x90,0x60, 0x00,0x00,0x90,0x90, 0x00,0x00,0x90,0xC0, 0x00,0x00,0x90,0xF0,
+ 0x00,0x00,0xB0,0x00, 0x00,0x00,0xB0,0x30, 0x00,0x00,0xB0,0x60, 0x00,0x00,0xB0,0x90, 0x00,0x00,0xB0,0xC0, 0x00,0x00,0xB0,0xF0,
+ 0x00,0x00,0xD0,0x00, 0x00,0x00,0xD0,0x30, 0x00,0x00,0xD0,0x60, 0x00,0x00,0xD0,0x90, 0x00,0x00,0xD0,0xC0, 0x00,0x00,0xD0,0xF0,
+ 0x00,0x00,0xF0,0x00, 0x00,0x00,0xF0,0x30, 0x00,0x00,0xF0,0x60, 0x00,0x00,0xF0,0x90, 0x00,0x00,0xF0,0xC0, 0x00,0x00,0xF0,0xF0,
+ 0x00,0x50,0x00,0x00, 0x00,0x50,0x00,0x30, 0x00,0x50,0x00,0x60, 0x00,0x50,0x00,0x90, 0x00,0x50,0x00,0xC0, 0x00,0x50,0x00,0xF0,
+ 0x00,0x50,0x20,0x00, 0x00,0x50,0x20,0x30, 0x00,0x50,0x20,0x60, 0x00,0x50,0x20,0x90, 0x00,0x50,0x20,0xC0, 0x00,0x50,0x20,0xF0,
+ 0x00,0x50,0x40,0x00, 0x00,0x50,0x40,0x30, 0x00,0x50,0x40,0x60, 0x00,0x50,0x40,0x90, 0x00,0x50,0x40,0xC0, 0x00,0x50,0x40,0xF0,
+ 0x00,0x50,0x60,0x00, 0x00,0x50,0x60,0x30, 0x00,0x50,0x60,0x60, 0x00,0x50,0x60,0x90, 0x00,0x50,0x60,0xC0, 0x00,0x50,0x60,0xF0,
+ 0x00,0x50,0x90,0x00, 0x00,0x50,0x90,0x30, 0x00,0x50,0x90,0x60, 0x00,0x50,0x90,0x90, 0x00,0x50,0x90,0xC0, 0x00,0x50,0x90,0xF0,
+ 0x00,0x50,0xB0,0x00, 0x00,0x50,0xB0,0x30, 0x00,0x50,0xB0,0x60, 0x00,0x50,0xB0,0x90, 0x00,0x50,0xB0,0xC0, 0x00,0x50,0xB0,0xF0,
+ 0x00,0x50,0xD0,0x00, 0x00,0x50,0xD0,0x30, 0x00,0x50,0xD0,0x60, 0x00,0x50,0xD0,0x90, 0x00,0x50,0xD0,0xC0, 0x00,0x50,0xD0,0xF0,
+ 0x00,0x50,0xF0,0x00, 0x00,0x50,0xF0,0x30, 0x00,0x50,0xF0,0x60, 0x00,0x50,0xF0,0x90, 0x00,0x50,0xF0,0xC0, 0x00,0x50,0xF0,0xF0,
+ 0x00,0xA0,0x00,0x00, 0x00,0xA0,0x00,0x30, 0x00,0xA0,0x00,0x60, 0x00,0xA0,0x00,0x90, 0x00,0xA0,0x00,0xC0, 0x00,0xA0,0x00,0xF0,
+ 0x00,0xA0,0x20,0x00, 0x00,0xA0,0x20,0x30, 0x00,0xA0,0x20,0x60, 0x00,0xA0,0x20,0x90, 0x00,0xA0,0x20,0xC0, 0x00,0xA0,0x20,0xF0,
+ 0x00,0xA0,0x40,0x00, 0x00,0xA0,0x40,0x30, 0x00,0xA0,0x40,0x60, 0x00,0xA0,0x40,0x90, 0x00,0xA0,0x40,0xC0, 0x00,0xA0,0x40,0xF0,
+ 0x00,0xA0,0x60,0x00, 0x00,0xA0,0x60,0x30, 0x00,0xA0,0x60,0x60, 0x00,0xA0,0x60,0x90, 0x00,0xA0,0x60,0xC0, 0x00,0xA0,0x60,0xF0,
+ 0x00,0xA0,0x90,0x00, 0x00,0xA0,0x90,0x30, 0x00,0xA0,0x90,0x60, 0x00,0xA0,0x90,0x90, 0x00,0xA0,0x90,0xC0, 0x00,0xA0,0x90,0xF0,
+ 0x00,0xA0,0xB0,0x00, 0x00,0xA0,0xB0,0x30, 0x00,0xA0,0xB0,0x60, 0x00,0xA0,0xB0,0x90, 0x00,0xA0,0xB0,0xC0, 0x00,0xA0,0xB0,0xF0,
+ 0x00,0xA0,0xD0,0x00, 0x00,0xA0,0xD0,0x30, 0x00,0xA0,0xD0,0x60, 0x00,0xA0,0xD0,0x90, 0x00,0xA0,0xD0,0xC0, 0x00,0xA0,0xD0,0xF0,
+ 0x00,0xA0,0xF0,0x00, 0x00,0xA0,0xF0,0x30, 0x00,0xA0,0xF0,0x60, 0x00,0xA0,0xF0,0x90, 0x00,0xA0,0xF0,0xC0, 0x00,0xA0,0xF0,0xF0,
+ 0x00,0xF0,0x00,0x00, 0x00,0xF0,0x00,0x30, 0x00,0xF0,0x00,0x60, 0x00,0xF0,0x00,0x90, 0x00,0xF0,0x00,0xC0, 0x00,0xF0,0x00,0xF0,
+ 0x00,0xF0,0x20,0x00, 0x00,0xF0,0x20,0x30, 0x00,0xF0,0x20,0x60, 0x00,0xF0,0x20,0x90, 0x00,0xF0,0x20,0xC0, 0x00,0xF0,0x20,0xF0,
+ 0x00,0xF0,0x40,0x00, 0x00,0xF0,0x40,0x30, 0x00,0xF0,0x40,0x60, 0x00,0xF0,0x40,0x90, 0x00,0xF0,0x40,0xC0, 0x00,0xF0,0x40,0xF0,
+ 0x00,0xF0,0x60,0x00, 0x00,0xF0,0x60,0x30, 0x00,0xF0,0x60,0x60, 0x00,0xF0,0x60,0x90, 0x00,0xF0,0x60,0xC0, 0x00,0xF0,0x60,0xF0,
+ 0x00,0xF0,0x90,0x00, 0x00,0xF0,0x90,0x30, 0x00,0xF0,0x90,0x60, 0x00,0xF0,0x90,0x90, 0x00,0xF0,0x90,0xC0, 0x00,0xF0,0x90,0xF0,
+ 0x00,0xF0,0xB0,0x00, 0x00,0xF0,0xB0,0x30, 0x00,0xF0,0xB0,0x60, 0x00,0xF0,0xB0,0x90, 0x00,0xF0,0xB0,0xC0, 0x00,0xF0,0xB0,0xF0,
+ 0x00,0xF0,0xD0,0x00, 0x00,0xF0,0xD0,0x30, 0x00,0xF0,0xD0,0x60, 0x00,0xF0,0xD0,0x90, 0x00,0xF0,0xD0,0xC0, 0x00,0xF0,0xD0,0xF0,
+ 0x00,0xF0,0xF0,0x00, 0x00,0xF0,0xF0,0x30, 0x00,0xF0,0xF0,0x60, 0x00,0xF0,0xF0,0x90, 0x00,0xF0,0xF0,0xC0, 0x00,0xF0,0xF0,0xF0,
+
+ 0x00,0x10,0x10,0x10, 0x00,0x20,0x20,0x20, 0x00,0x30,0x30,0x30, 0x00,0x40,0x40,0x40,
+ 0x00,0x50,0x50,0x50, 0x00,0x60,0x60,0x60, 0x00,0x70,0x70,0x70, 0x00,0x80,0x80,0x80,
+ 0x00,0x90,0x90,0x90, 0x00,0xA0,0xA0,0xA0, 0x00,0xB0,0xB0,0xB0, 0x00,0xC0,0xC0,0xC0,
+ 0x00,0xD0,0xD0,0xD0, 0x00,0xE0,0xE0,0xE0
+};
+
+static int * hamx_array = (int *) (hamx_array_char);
+
+static uchar cmap_hamx[] = {
+ 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x30, 0x00,0x00,0x00,0x60, 0x00,0x00,0x00,0x90, 0x00,0x00,0x00,0xC0, 0x00,0x00,0x00,0xF0,
+ 0x00,0x00,0x20,0x00, 0x00,0x00,0x20,0x30, 0x00,0x00,0x20,0x60, 0x00,0x00,0x20,0x90, 0x00,0x00,0x20,0xC0, 0x00,0x00,0x20,0xF0,
+ 0x00,0x00,0x40,0x00, 0x00,0x00,0x40,0x30, 0x00,0x00,0x40,0x60, 0x00,0x00,0x40,0x90, 0x00,0x00,0x40,0xC0, 0x00,0x00,0x40,0xF0,
+ 0x00,0x00,0x60,0x00, 0x00,0x00,0x60,0x30, 0x00,0x00,0x60,0x60, 0x00,0x00,0x60,0x90, 0x00,0x00,0x60,0xC0, 0x00,0x00,0x60,0xF0,
+ 0x00,0x00,0x90,0x00, 0x00,0x00,0x90,0x30, 0x00,0x00,0x90,0x60, 0x00,0x00,0x90,0x90, 0x00,0x00,0x90,0xC0, 0x00,0x00,0x90,0xF0,
+ 0x00,0x00,0xB0,0x00, 0x00,0x00,0xB0,0x30, 0x00,0x00,0xB0,0x60, 0x00,0x00,0xB0,0x90, 0x00,0x00,0xB0,0xC0, 0x00,0x00,0xB0,0xF0,
+ 0x00,0x00,0xD0,0x00, 0x00,0x00,0xD0,0x30, 0x00,0x00,0xD0,0x60, 0x00,0x00,0xD0,0x90, 0x00,0x00,0xD0,0xC0, 0x00,0x00,0xD0,0xF0,
+ 0x00,0x00,0xF0,0x00, 0x00,0x00,0xF0,0x30, 0x00,0x00,0xF0,0x60, 0x00,0x00,0xF0,0x90, 0x00,0x00,0xF0,0xC0, 0x00,0x00,0xF0,0xF0,
+ 0x00,0x50,0x00,0x00, 0x00,0x50,0x00,0x30, 0x00,0x50,0x00,0x60, 0x00,0x50,0x00,0x90, 0x00,0x50,0x00,0xC0, 0x00,0x50,0x00,0xF0,
+ 0x00,0x50,0x20,0x00, 0x00,0x50,0x20,0x30, 0x00,0x50,0x20,0x60, 0x00,0x50,0x20,0x90, 0x00,0x50,0x20,0xC0, 0x00,0x50,0x20,0xF0,
+ 0x00,0x50,0x40,0x00, 0x00,0x50,0x40,0x30, 0x00,0x50,0x40,0x60, 0x00,0x50,0x40,0x90, 0x00,0x50,0x40,0xC0, 0x00,0x50,0x40,0xF0,
+ 0x00,0x50,0x60,0x00, 0x00,0x50,0x60,0x30, 0x00,0x50,0x60,0x60, 0x00,0x50,0x60,0x90, 0x00,0x50,0x60,0xC0, 0x00,0x50,0x60,0xF0,
+ 0x00,0x50,0x90,0x00, 0x00,0x50,0x90,0x30, 0x00,0x50,0x90,0x60, 0x00,0x50,0x90,0x90, 0x00,0x50,0x90,0xC0, 0x00,0x50,0x90,0xF0,
+ 0x00,0x50,0xB0,0x00, 0x00,0x50,0xB0,0x30, 0x00,0x50,0xB0,0x60, 0x00,0x50,0xB0,0x90, 0x00,0x50,0xB0,0xC0, 0x00,0x50,0xB0,0xF0,
+ 0x00,0x50,0xD0,0x00, 0x00,0x50,0xD0,0x30, 0x00,0x50,0xD0,0x60, 0x00,0x50,0xD0,0x90, 0x00,0x50,0xD0,0xC0, 0x00,0x50,0xD0,0xF0,
+ 0x00,0x50,0xF0,0x00, 0x00,0x50,0xF0,0x30, 0x00,0x50,0xF0,0x60, 0x00,0x50,0xF0,0x90, 0x00,0x50,0xF0,0xC0, 0x00,0x50,0xF0,0xF0,
+ 0x00,0xA0,0x00,0x00, 0x00,0xA0,0x00,0x30, 0x00,0xA0,0x00,0x60, 0x00,0xA0,0x00,0x90, 0x00,0xA0,0x00,0xC0, 0x00,0xA0,0x00,0xF0,
+ 0x00,0xA0,0x20,0x00, 0x00,0xA0,0x20,0x30, 0x00,0xA0,0x20,0x60, 0x00,0xA0,0x20,0x90, 0x00,0xA0,0x20,0xC0, 0x00,0xA0,0x20,0xF0,
+ 0x00,0xA0,0x40,0x00, 0x00,0xA0,0x40,0x30, 0x00,0xA0,0x40,0x60, 0x00,0xA0,0x40,0x90, 0x00,0xA0,0x40,0xC0, 0x00,0xA0,0x40,0xF0,
+ 0x00,0xA0,0x60,0x00, 0x00,0xA0,0x60,0x30, 0x00,0xA0,0x60,0x60, 0x00,0xA0,0x60,0x90, 0x00,0xA0,0x60,0xC0, 0x00,0xA0,0x60,0xF0,
+ 0x00,0xA0,0x90,0x00, 0x00,0xA0,0x90,0x30, 0x00,0xA0,0x90,0x60, 0x00,0xA0,0x90,0x90, 0x00,0xA0,0x90,0xC0, 0x00,0xA0,0x90,0xF0,
+ 0x00,0xA0,0xB0,0x00, 0x00,0xA0,0xB0,0x30, 0x00,0xA0,0xB0,0x60, 0x00,0xA0,0xB0,0x90, 0x00,0xA0,0xB0,0xC0, 0x00,0xA0,0xB0,0xF0,
+ 0x00,0xA0,0xD0,0x00, 0x00,0xA0,0xD0,0x30, 0x00,0xA0,0xD0,0x60, 0x00,0xA0,0xD0,0x90, 0x00,0xA0,0xD0,0xC0, 0x00,0xA0,0xD0,0xF0,
+ 0x00,0xA0,0xF0,0x00, 0x00,0xA0,0xF0,0x30, 0x00,0xA0,0xF0,0x60, 0x00,0xA0,0xF0,0x90, 0x00,0xA0,0xF0,0xC0, 0x00,0xA0,0xF0,0xF0,
+ 0x00,0xF0,0x00,0x00, 0x00,0xF0,0x00,0x30, 0x00,0xF0,0x00,0x60, 0x00,0xF0,0x00,0x90, 0x00,0xF0,0x00,0xC0, 0x00,0xF0,0x00,0xF0,
+ 0x00,0xF0,0x20,0x00, 0x00,0xF0,0x20,0x30, 0x00,0xF0,0x20,0x60, 0x00,0xF0,0x20,0x90, 0x00,0xF0,0x20,0xC0, 0x00,0xF0,0x20,0xF0,
+ 0x00,0xF0,0x40,0x00, 0x00,0xF0,0x40,0x30, 0x00,0xF0,0x40,0x60, 0x00,0xF0,0x40,0x90, 0x00,0xF0,0x40,0xC0, 0x00,0xF0,0x40,0xF0,
+ 0x00,0xF0,0x60,0x00, 0x00,0xF0,0x60,0x30, 0x00,0xF0,0x60,0x60, 0x00,0xF0,0x60,0x90, 0x00,0xF0,0x60,0xC0, 0x00,0xF0,0x60,0xF0,
+ 0x00,0xF0,0x90,0x00, 0x00,0xF0,0x90,0x30, 0x00,0xF0,0x90,0x60, 0x00,0xF0,0x90,0x90, 0x00,0xF0,0x90,0xC0, 0x00,0xF0,0x90,0xF0,
+ 0x00,0xF0,0xB0,0x00, 0x00,0xF0,0xB0,0x30, 0x00,0xF0,0xB0,0x60, 0x00,0xF0,0xB0,0x90, 0x00,0xF0,0xB0,0xC0, 0x00,0xF0,0xB0,0xF0,
+ 0x00,0xF0,0xD0,0x00, 0x00,0xF0,0xD0,0x30, 0x00,0xF0,0xD0,0x60, 0x00,0xF0,0xD0,0x90, 0x00,0xF0,0xD0,0xC0, 0x00,0xF0,0xD0,0xF0,
+ 0x00,0xF0,0xF0,0x00, 0x00,0xF0,0xF0,0x30, 0x00,0xF0,0xF0,0x60, 0x00,0xF0,0xF0,0x90, 0x00,0xF0,0xF0,0xC0, 0x00,0xF0,0xF0,0xF0,
+ 0x00,0x10,0x10,0x10, 0x00,0x20,0x20,0x20, 0x00,0x30,0x30,0x30, 0x00,0x40,0x40,0x40, 0x00,0x50,0x50,0x50, 0x00,0x60,0x60,0x60,
+ 0x00,0x70,0x70,0x70, 0x00,0x80,0x80,0x80, 0x00,0x90,0x90,0x90, 0x00,0xA0,0xA0,0xA0, 0x00,0xB0,0xB0,0xB0, 0x00,0xC0,0xC0,0xC0,
+ 0x00,0xD0,0xD0,0xD0, 0x00,0xE0,0xE0,0xE0
+};
+
+
+float adat_gamma = 1.0;
+float adat_distort = 1.0;
+
+/*
+ *
+ * New version:
+ *
+ * 32 brighntesses Y 15 with direct access (black and white are specials)
+ * 16 colors H ue
+ * 7 intensities S aturation
+ *
+ * Total 3584 'different' colors. First 512 colors free.
+ *
+ *
+ */
+
+void imb_convhamx(struct ImBuf *ibuf, unsigned char *coltab, short *deltab)
+{
+ short r,g,b,lr,lg,lb,dr,dg,db,col,fout,type,step;
+ int i;
+ uchar *rect;
+
+ /*
+ b = 0000 xxxx
+ g = 0001 xxxx
+ r = 0010 xxxx
+ cmap >= 48
+ */
+
+ for (step = 0 ; step < 2 ; step ++){
+ rect = (uchar *) ibuf->rect;
+ rect += 4*step;
+ i = ((ibuf->x * ibuf->y) + 2 - step - 1) / 2;
+
+ lb = coltab[1];
+ lg = coltab[2];
+ lr = coltab[3];
+ type = col = 0;
+
+ for ( ;i>0;i--){
+ b = rect[2] >> 4;
+ g = rect[1] >> 4;
+ r = rect[0] >> 4;
+
+ if ((b-lb) | (g-lg) | (r-lr)){
+ col = ((b<<8) + (g<<4) + r) << 1;
+ fout = deltab[col + 1];
+ col = deltab[col];
+ type = 0;
+ dr = quadr[lr-r] ;
+ dg = quadr[lg-g] ;
+ db = quadr[lb-b];
+
+ if ((dr+dg)<=fout) {
+ fout = dr+dg ;
+ type = 1;
+ }
+ if ((dg+db)<=fout) {
+ fout = dg+db;
+ type = 2;
+ }
+ if ((dr+db)<=fout) {
+ fout = dr+db;
+ type = 4;
+ }
+
+ switch(type){
+ case 1:
+ lb = b ;
+ col = b;
+ break;
+ case 4:
+ lg = g ;
+ col = g+16;
+ break;
+ case 2:
+ lr = r ;
+ col = r + 32;
+ break;
+ default:
+ /*printf("%04x %5d %5d ", (b<<8) + (g<<4) + r, col, fout);*/
+
+ lb = coltab[col*4 + 1];
+ lg = coltab[col*4 + 2];
+ lr = coltab[col*4 + 3];
+ /*printf("%01x%01x%01x %01x%01x%01x\n", b, g, r, lb, lg, lr);*/
+ col += 48;
+ }
+ }
+ rect[3] = col;
+ rect += 8;
+ }
+ }
+}
+
+static short dec_hamx(struct ImBuf * ibuf, unsigned char *body, int cmap[])
+{
+ int todo,i;
+ int j,step,col;
+ unsigned int *rect;
+
+ for (step = 0 ; step < 2 ; step ++){
+ rect = ibuf->rect;
+ rect += step;
+ todo = (ibuf->x * ibuf->y + 2 - step - 1) / 2;
+ col = cmap[0];
+ while (todo>0){
+ i = *body++;
+
+ if (i & 128){ /* fill */
+
+ i = 257-i;
+ todo -= i;
+ j = *(body++);
+
+ col = ((col & hamx_array[j]) | hamx_array[j + 256]);
+
+ do{
+ *rect = col;
+ rect += 2;
+ }while (--i);
+ } else{ /* copy */
+ i++;
+ todo-=i;
+
+ do{
+ j = *(body++);
+ *rect = col = ((col & hamx_array[j]) | hamx_array[j + 256]);
+ rect += 2;
+ }while (--i);
+ }
+ }
+ if (todo) return (0);
+ }
+ return(1);
+}
+
+
+struct ImBuf *imb_loadanim(int *iffmem, int flags)
+{
+ int chunk, totlen, len, *mem, cmaplen = 0;
+ unsigned int *cmap = NULL;
+ uchar *body = 0;
+ struct Adat adat;
+ struct ImBuf *ibuf=0;
+ static int is_flipped = FALSE;
+
+ mem=iffmem;
+ if (GET_ID(mem) != FORM) return (0);
+ if (GET_ID(mem + 2) != ANIM) return (0);
+ totlen= (GET_BIG_LONG(mem + 1) + 1) & ~1;
+ mem += 3;
+ totlen -= 4;
+ adat.w = 0;
+ adat.xorig = 0;
+ adat.yorig = 0;
+ adat.gamma = adat_gamma;
+ adat.distort = adat_distort;
+
+ while(totlen > 0){
+ chunk = GET_ID(mem);
+ len = (GET_BIG_LONG(mem + 1) + 1) & ~1;
+ mem += 2;
+
+ totlen -= len+8;
+ switch (chunk){
+ case ADAT:
+ if (len > sizeof(struct Adat)){
+ memcpy(&adat,mem,sizeof(struct Adat));
+ } else{
+ memcpy(&adat,mem,len);
+ }
+ adat.w = BIG_SHORT(adat.w);
+ adat.h = BIG_SHORT(adat.h);
+ adat.type = BIG_SHORT(adat.type);
+ adat.xorig = BIG_SHORT(adat.xorig);
+ adat.yorig = BIG_SHORT(adat.yorig);
+ break;
+ case CMAP:
+ cmap = (unsigned int *) mem;
+ cmaplen = len;
+ break;
+ case BODY:
+ body = (uchar *) mem;
+ break;
+ }
+ mem = (int *)((uchar *)mem +len);
+ }
+
+ if (body == 0) return (0);
+ if (adat.w == 0) return (0);
+
+ adat_gamma = adat.gamma;
+ adat_distort = adat.distort;
+
+ if (flags & IB_test) ibuf=IMB_allocImBuf(adat.w, adat.h, 24, 0, 0);
+ else ibuf=IMB_allocImBuf(adat.w, adat.h, 24, IB_rect, 0);
+ if (ibuf==0) return (0);
+
+ ibuf->ftype = (Anim | adat.type);
+ ibuf->xorig = adat.xorig;
+ ibuf->yorig = adat.yorig;
+ ibuf->flags = flags;
+
+ if (cmaplen){
+ ibuf->cmap = malloc(cmaplen);
+ memcpy(ibuf->cmap, cmap, cmaplen);
+ ibuf->maxcol = cmaplen >> 2;
+ }
+
+ if (flags & IB_test){
+ if (flags & IB_freem) free(iffmem);
+ return(ibuf);
+ }
+
+ switch (adat.type){
+ case HAMX:
+ if (flags & IB_rect){
+ if (!is_flipped) {
+ int i;
+ unsigned int * t;
+ t = (unsigned int *) hamx_array_char;
+ for (i = 0; i < sizeof(hamx_array_char) / sizeof(int) ; i++) {
+ t[i] = SWAP_LONG(t[i]);
+ }
+
+ t = (unsigned int *) cmap_hamx;
+
+ for (i = 0; i < sizeof(cmap_hamx) / sizeof(int) ; i++) {
+ t[i] = SWAP_LONG(t[i]);
+ }
+
+ is_flipped= TRUE;
+ }
+
+ if (dec_hamx(ibuf,body,(int*) cmap_hamx) == 0){
+ IMB_freeImBuf(ibuf);
+ ibuf = 0;
+ }
+ if (flags & IB_ttob) IMB_flipy(ibuf);
+ }
+ break;
+ default:
+ IMB_freeImBuf(ibuf);
+ ibuf = 0;
+ }
+
+ if (flags & IB_freem) free(iffmem);
+
+ return (ibuf);
+}
+
+
+static unsigned char *makebody_anim(int bytes,
+ unsigned char *buf,
+ unsigned char *rect)
+{
+ register uchar last,this;
+ register int copy;
+ register uchar *rectstart,*temp;
+
+ bytes--;
+ rectstart = rect;
+ last = *rect++;
+ this = *rect++;
+ copy = last^this;
+ while (bytes>0){
+ if (copy){
+ do{
+ last = this;
+ this = *rect++;
+ if (last == this){
+ if (this == rect[-3]){ /* three the same? */
+ bytes --; /* init bytes */
+ break;
+ }
+ }
+ }while (--bytes != 0);
+
+ copy = rect-rectstart;
+ copy --;
+ if (bytes) copy -= 2;
+
+ temp = rect;
+ rect = rectstart;
+
+ while (copy){
+ last = copy;
+ if (copy>MAXDAT) last = MAXDAT;
+ copy -= last;
+ *buf++ = last-1;
+ do{
+ *buf++ = *rect++;
+ }while(--last != 0);
+ }
+ rectstart = rect;
+ rect = temp;
+ last = this;
+
+ copy = FALSE;
+ } else {
+ while (*rect++ == this){ /* seek first different byte */
+ if (--bytes == 0) break; /* or end of line */
+ }
+ rect --;
+ copy = rect-rectstart;
+ rectstart = rect;
+ bytes --;
+ this = *rect++;
+
+ while (copy){
+ if (copy>MAXRUN){
+ *buf++ = -(MAXRUN-1);
+ *buf++ = last;
+ copy -= MAXRUN;
+ } else {
+ *buf++ = -(copy-1);
+ *buf++ = last;
+ break;
+ }
+ }
+ copy=TRUE;
+ }
+ }
+ return (buf);
+}
+
+
+short imb_enc_anim(struct ImBuf *ibuf, int file)
+{
+ int step, size, i, skip, steps = 0;
+ uchar *buf1, *crect, *_buf1, *_buf2, *bufend;
+ short ok = TRUE;
+
+ if (ibuf == 0) return (0);
+ if (file < 0 ) return (0);
+ if (ibuf->rect == 0) return(0);
+
+ /* add dither */
+
+ switch(ibuf->ftype){
+ case AN_hamx:
+ ibuf->cmap = (unsigned int *) cmap_hamx;
+ ibuf->mincol = 0;
+ ibuf->maxcol = sizeof(cmap_hamx) / 4;
+ imb_converttoham(ibuf);
+ steps = 2;
+ break;
+ }
+ if (steps == 0) return 0;
+
+ size = ((ibuf->x + 1)* (ibuf->y + 1)) / steps + 1024;
+ if ((_buf1 = malloc(size)) == 0) return(0);
+ if ((_buf2 = malloc(size)) == 0){
+ free(_buf1);
+ return(0);
+ }
+
+ skip = 4 * steps;
+ for (step = 0 ; step < steps ; step ++){
+ crect = (uchar *) ibuf->rect;
+ crect += 4 * step;
+ size = (ibuf->x * ibuf->y + steps - step - 1) / steps;
+ buf1 = _buf1;
+ if ((ibuf->ftype == AN_hamx) || (ibuf->ftype == AN_yuvx)){
+ crect += 3;
+ for (i = size ; i>0 ; i--){
+ *(buf1 ++) = *crect;
+ crect += skip;
+ }
+ } else{
+ for (i = size ; i>0 ; i--){
+ *(buf1 ++) = crect[1] + (crect[2] >> 2) + (crect[3] >> 5);
+ crect += skip;
+ }
+ }
+ bufend = makebody_anim(size,_buf2,_buf1);
+ if (bufend == 0){
+ ok = FALSE;
+ break;
+ }
+ size = bufend - _buf2;
+ if (write(file, _buf2, size) != size){
+ ok = FALSE;
+ break;
+ }
+ }
+ free(_buf1);
+ free(_buf2);
+ return (ok);
+}
diff --git a/source/blender/imbuf/intern/iff.c b/source/blender/imbuf/intern/iff.c
new file mode 100644
index 00000000000..675de9c76ab
--- /dev/null
+++ b/source/blender/imbuf/intern/iff.c
@@ -0,0 +1,226 @@
+/**
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * iff.c
+ *
+ * $Id$
+ */
+
+#ifdef WIN32
+#include <io.h>
+#endif
+#include "BLI_blenlib.h"
+#include "imbuf.h"
+#include "imbuf_patch.h"
+#include "IMB_imbuf_types.h"
+#include "IMB_iff.h"
+
+unsigned short imb_start_iff(struct ImBuf *ibuf, int file)
+{
+ unsigned int *point, size, *buf;
+
+ if ((point=buf=(unsigned int *)malloc(32768))==0) return FALSE;
+
+ *point++ = FORM; /* FORMxxxxILBM in buffer */
+ *point++ = 0;
+
+ if (IS_amiga(ibuf)){
+ struct BitMapHeader *bmhd;
+
+ *point++ = ILBM;
+ *point++ = CAMG;
+ *point++ = 4;
+ *point++ = (ibuf->ftype & 0xffff);
+
+ *point++=BMHD;
+ *point++=sizeof(struct BitMapHeader);
+
+ bmhd=(struct BitMapHeader *)point; /* bmhd points to location where bmhd will be */
+ point=(unsigned int *)((char *)point+sizeof(struct BitMapHeader)); /* advance pointer already */
+
+ bmhd->w=ibuf->x;
+ bmhd->h=ibuf->y;
+ bmhd->pageWidth=ibuf->x;
+ bmhd->pageHeight=ibuf->y;
+ bmhd->x=0;
+ bmhd->y=0;
+ bmhd->nPlanes=ibuf->depth;
+ bmhd->masking=0;
+ if (ibuf->flags & IB_vert){
+ bmhd->compression=2;
+ }
+ else{
+ bmhd->compression=1;
+ }
+ bmhd->pad1=0;
+ bmhd->transparentColor=0;
+ bmhd->xAspect=1;
+ bmhd->yAspect=1;
+ } else if (IS_anim(ibuf)){
+ struct Adat *adat;
+ extern float adat_gamma;
+ extern float adat_distort;
+
+ *point++ = ANIM;
+ *point++ = ADAT;
+ *point++ = BIG_LONG(sizeof(struct Adat));
+
+ adat = (struct Adat *)point;
+ point = (unsigned int *)((char *)point+sizeof(struct Adat)); /* advance pointer already */
+
+ adat->w = BIG_SHORT(ibuf->x);
+ adat->h = BIG_SHORT(ibuf->y);
+
+ adat->type = BIG_SHORT(ibuf->ftype);
+ adat->xorig = BIG_SHORT(ibuf->xorig);
+ adat->yorig = BIG_SHORT(ibuf->yorig);
+ adat->pad = 0;
+ adat->gamma = adat_gamma;
+ adat->distort = adat_distort;
+ }
+
+ size=((uchar *)point-(uchar *)buf);
+ if (write(file,buf,size)!=size){
+ free(buf);
+ return (FALSE);
+ }
+
+ if (ibuf->cmap){
+ if (IS_anim(ibuf)){
+ size = ibuf->maxcol * sizeof(int);
+ buf[0] = CMAP;
+ buf[1] = BIG_LONG(size);
+ if (write(file,buf,8) != 8){
+ free(buf);
+ return (FALSE);
+ }
+ if (write(file,ibuf->cmap,size) != size){
+ free(buf);
+ return (FALSE);
+ }
+ } else{
+ uchar *cpoint,*cols;
+ unsigned int i,bits;
+
+ point = buf;
+ if (IS_amiga(ibuf)){
+ *(point++) = CMAP;
+ *(point++) = BIG_LONG(3*ibuf->maxcol);
+ }
+
+ cpoint = (uchar *) point;
+ cols = (uchar *)ibuf->cmap;
+ if ((ibuf->cbits > 0) && (ibuf->cbits < 8)){
+ bits = ~((1 << (8-ibuf->cbits)) - 1);
+ } else bits = -1;
+
+ if (IS_ham(ibuf)) bits = -1;
+
+ for (i=0 ; i<ibuf->maxcol ; i++){
+ *(cpoint++) = cols[0] & bits;
+ *(cpoint++) = cols[1] & bits;
+ *(cpoint++) = cols[2] & bits;
+ cols += 4;
+ }
+ if (ibuf->maxcol & 1) *(cpoint++)=0;
+
+ size=(cpoint-(uchar *)buf);
+ if (write(file,buf,size)!=size){
+ free(buf);
+ return (FALSE);
+ }
+ }
+ }
+
+ if (IS_amiga(ibuf)) buf[0] = BODY;
+ if (IS_anim(ibuf)) buf[0] = BODY;
+ buf[1]=0;
+
+ if (write(file,buf,8)!=8){
+ free(buf);
+ return(FALSE);
+ }
+
+ free(buf);
+ return (TRUE);
+}
+
+
+unsigned short imb_update_iff(int file, int code)
+{
+ int buf[2], filelen, skip;
+ uchar nop;
+
+ if (file<=0) return (FALSE);
+
+ filelen = BLI_filesize(file)-8; /* calc filelength */
+
+ lseek(file,0L,2); /* seek end */
+
+ if (filelen & 1){ /* make length 'even' */
+ switch(code){
+ case BODY:
+ nop = IFFNOP;
+ break;
+ }
+ if (write(file,&nop,1)!=1) return (FALSE);
+ filelen++;
+ }
+ lseek(file,4L,0);
+
+ buf[0] = BIG_LONG(filelen);
+
+ if (write(file, buf, 4) != 4) return (FALSE);
+ if (code == 0) return (TRUE);
+
+ filelen-=4;
+ lseek(file,4L,1);
+
+ while (filelen>0){ /* seek BODY */
+ read(file, buf, 8);
+ filelen -= 8;
+ if (buf[0] == code) break;
+
+ skip = (BIG_LONG(buf[1]) + 1) & ~1;
+ filelen -= skip;
+ lseek(file, skip, 1);
+ }
+ if (filelen <= 0) {
+ printf("update_iff: couldn't find chunk\n");
+ return (FALSE);
+ }
+
+ lseek(file, -4L, 1);
+
+ buf[0] = BIG_LONG(filelen);
+
+ if (write(file, buf, 4)!=4) return (FALSE);
+
+ return (TRUE);
+}
diff --git a/source/blender/imbuf/intern/imageprocess.c b/source/blender/imbuf/intern/imageprocess.c
new file mode 100644
index 00000000000..54e0ec94672
--- /dev/null
+++ b/source/blender/imbuf/intern/imageprocess.c
@@ -0,0 +1,301 @@
+/**
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * This file was moved here from the src/ directory. It is meant to
+ * deal with endianness. It resided in a general blending lib. The
+ * other functions were only used during rendering. This single
+ * function remained. It should probably move to imbuf/intern/util.c,
+ * but we'll keep it here for the time being. (nzc)*/
+
+/* imageprocess.c MIXED MODEL
+ *
+ * april 95
+ *
+ * $Id$
+ */
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+#include "math.h"
+
+/* This define should be relocated to a global header some where Kent Mein
+I stole it from util.h in the plugins api */
+#define MAX2(x,y) ( (x)>(y) ? (x) : (y) )
+
+/* Only this one is used liberally here, and in imbuf */
+void IMB_convert_rgba_to_abgr(struct ImBuf *ibuf)
+{
+ int size, do_float=0;
+ unsigned char rt, *cp = (unsigned char *)ibuf->rect;
+ float rtf, *cpf = ibuf->rect_float;
+
+ if (ibuf->rect_float) do_float = 1;
+ size = ibuf->x * ibuf->y;
+
+ while(size-- > 0) {
+ rt= cp[0];
+ cp[0]= cp[3];
+ cp[3]= rt;
+ rt= cp[1];
+ cp[1]= cp[2];
+ cp[2]= rt;
+ cp+= 4;
+ if (do_float) {
+ rtf= cpf[0];
+ cpf[0]= cpf[3];
+ cpf[3]= rtf;
+ rtf= cpf[1];
+ cpf[1]= cpf[2];
+ cpf[2]= rtf;
+ cpf+= 4;
+ }
+ }
+}
+
+/**************************************************************************
+* INTERPOLATIONS
+*
+* Reference and docs:
+* http://wiki.blender.org/index.php/User:Damiles#Interpolations_Algorithms
+***************************************************************************/
+
+/* BICUBIC Interpolation functions */
+/* More info: http://wiki.blender.org/index.php/User:Damiles#Bicubic_pixel_interpolation
+*/
+/* function assumes out to be zero'ed, only does RGBA */
+static float P(float k){
+ float aux;
+ aux=(float)(1.0f/6.0f)*( pow( MAX2(k+2.0f,0) , 3.0f ) - 4.0f * pow( MAX2(k+1.0f,0) , 3.0f ) + 6.0f * pow( MAX2(k,0) , 3.0f ) - 4.0f * pow( MAX2(k-1.0f,0) , 3.0f));
+ return aux ;
+}
+
+void bicubic_interpolation(ImBuf *in, ImBuf *out, float x, float y, int xout, int yout)
+{
+ int i,j,n,m,x1,y1;
+ unsigned char *dataI,*outI;
+ float a,b, outR,outG,outB,outA,*dataF,*outF;
+ int do_rect, do_float;
+
+ if (in == NULL) return;
+ if (in->rect == NULL && in->rect_float == NULL) return;
+
+ do_rect= (out->rect != NULL);
+ do_float= (out->rect_float != NULL);
+
+ i= (int)floor(x);
+ j= (int)floor(y);
+ a= x - i;
+ b= y - j;
+
+ outR= 0.0f;
+ outG= 0.0f;
+ outB= 0.0f;
+ outA= 0.0f;
+ for(n= -1; n<= 2; n++){
+ for(m= -1; m<= 2; m++){
+ x1= i+n;
+ y1= j+m;
+ if (x1>0 && x1 < in->x && y1>0 && y1<in->y) {
+ if (do_float) {
+ dataF= in->rect_float + in->x * y1 * 4 + 4*x1;
+ outR+= dataF[0] * P(n-a) * P(b-m);
+ outG+= dataF[1] * P(n-a) * P(b-m);
+ outB+= dataF[2] * P(n-a) * P(b-m);
+ outA+= dataF[3] * P(n-a) * P(b-m);
+ }
+ if (do_rect) {
+ dataI= (unsigned char*)in->rect + in->x * y1 * 4 + 4*x1;
+ outR+= dataI[0] * P(n-a) * P(b-m);
+ outG+= dataI[1] * P(n-a) * P(b-m);
+ outB+= dataI[2] * P(n-a) * P(b-m);
+ outA+= dataI[3] * P(n-a) * P(b-m);
+ }
+ }
+ }
+ }
+ if (do_rect) {
+ outI= (unsigned char *)out->rect + out->x * yout * 4 + 4*xout;
+ outI[0]= (int)outR;
+ outI[1]= (int)outG;
+ outI[2]= (int)outB;
+ outI[3]= (int)outA;
+ }
+ if (do_float) {
+ outF= (float *)out->rect_float + out->x * yout * 4 + 4*xout;
+ outF[0]= outR;
+ outF[1]= outG;
+ outF[2]= outB;
+ outF[3]= outA;
+ }
+}
+
+/* function assumes out to be zero'ed, only does RGBA */
+/* BILINEAR INTERPOLATION */
+void bilinear_interpolation(ImBuf *in, ImBuf *out, float u, float v, int xout, int yout)
+{
+ float *row1, *row2, *row3, *row4, a, b, *outF;
+ unsigned char *row1I, *row2I, *row3I, *row4I, *outI;
+ float a_b, ma_b, a_mb, ma_mb;
+ float empty[4]= {0.0f, 0.0f, 0.0f, 0.0f};
+ unsigned char emptyI[4]= {0, 0, 0, 0};
+ int y1, y2, x1, x2;
+ int do_rect, do_float;
+
+ if (in==NULL) return;
+ if (in->rect==NULL && in->rect_float==NULL) return;
+
+ do_rect= (out->rect != NULL);
+ do_float= (out->rect_float != NULL);
+
+ x1= (int)floor(u);
+ x2= (int)ceil(u);
+ y1= (int)floor(v);
+ y2= (int)ceil(v);
+
+ // sample area entirely outside image?
+ if (x2<0 || x1>in->x-1 || y2<0 || y1>in->y-1) return;
+
+ if (do_rect)
+ outI=(unsigned char *)out->rect + out->x * yout * 4 + 4*xout;
+ else
+ outI= NULL;
+ if (do_float)
+ outF=(float *)out->rect_float + out->x * yout * 4 + 4*xout;
+ else
+ outF= NULL;
+
+ if (do_float) {
+ // sample including outside of edges of image
+ if (x1<0 || y1<0) row1= empty;
+ else row1= (float *)in->rect_float + in->x * y1 * 4 + 4*x1;
+
+ if (x1<0 || y2>in->y-1) row2= empty;
+ else row2= (float *)in->rect_float + in->x * y2 * 4 + 4*x1;
+
+ if (x2>in->x-1 || y1<0) row3= empty;
+ else row3= (float *)in->rect_float + in->x * y1 * 4 + 4*x2;
+
+ if (x2>in->x-1 || y2>in->y-1) row4= empty;
+ else row4= (float *)in->rect_float + in->x * y2 * 4 + 4*x2;
+
+ a= u-floor(u);
+ b= v-floor(v);
+ a_b= a*b; ma_b= (1.0f-a)*b; a_mb= a*(1.0f-b); ma_mb= (1.0f-a)*(1.0f-b);
+
+ outF[0]= ma_mb*row1[0] + a_mb*row3[0] + ma_b*row2[0]+ a_b*row4[0];
+ outF[1]= ma_mb*row1[1] + a_mb*row3[1] + ma_b*row2[1]+ a_b*row4[1];
+ outF[2]= ma_mb*row1[2] + a_mb*row3[2] + ma_b*row2[2]+ a_b*row4[2];
+ outF[3]= ma_mb*row1[3] + a_mb*row3[3] + ma_b*row2[3]+ a_b*row4[3];
+ }
+ if (do_rect) {
+ // sample including outside of edges of image
+ if (x1<0 || y1<0) row1I= emptyI;
+ else row1I= (unsigned char *)in->rect + in->x * y1 * 4 + 4*x1;
+
+ if (x1<0 || y2>in->y-1) row2I= emptyI;
+ else row2I= (unsigned char *)in->rect + in->x * y2 * 4 + 4*x1;
+
+ if (x2>in->x-1 || y1<0) row3I= emptyI;
+ else row3I= (unsigned char *)in->rect + in->x * y1 * 4 + 4*x2;
+
+ if (x2>in->x-1 || y2>in->y-1) row4I= emptyI;
+ else row4I= (unsigned char *)in->rect + in->x * y2 * 4 + 4*x2;
+
+ a= u-floor(u);
+ b= v-floor(v);
+ a_b= a*b; ma_b= (1.0f-a)*b; a_mb= a*(1.0f-b); ma_mb= (1.0f-a)*(1.0f-b);
+
+ outI[0]= ma_mb*row1I[0] + a_mb*row3I[0] + ma_b*row2I[0]+ a_b*row4I[0];
+ outI[1]= ma_mb*row1I[1] + a_mb*row3I[1] + ma_b*row2I[1]+ a_b*row4I[1];
+ outI[2]= ma_mb*row1I[2] + a_mb*row3I[2] + ma_b*row2I[2]+ a_b*row4I[2];
+ outI[3]= ma_mb*row1I[3] + a_mb*row3I[3] + ma_b*row2I[3]+ a_b*row4I[3];
+ }
+}
+
+/* function assumes out to be zero'ed, only does RGBA */
+/* NEAREST INTERPOLATION */
+void neareast_interpolation(ImBuf *in, ImBuf *out, float u, float v,int xout, int yout)
+{
+ float *outF,*dataF;
+ unsigned char *dataI,*outI;
+ int y1, x1;
+ int do_rect, do_float;
+
+ if (in==NULL) return;
+ if (in->rect==NULL && in->rect_float==NULL) return;
+
+ do_rect= (out->rect != NULL);
+ do_float= (out->rect_float != NULL);
+
+ x1= (int)(u);
+ y1= (int)(v);
+
+ if (do_rect)
+ outI=(unsigned char *)out->rect + out->x * yout * 4 + 4*xout;
+ else
+ outI= NULL;
+ if (do_float)
+ outF=(float *)out->rect_float + out->x * yout * 4 + 4*xout;
+ else
+ outF= NULL;
+
+ // sample area entirely outside image?
+ if (x1<0 || x1>in->x-1 || y1<0 || y1>in->y-1) return;
+
+ // sample including outside of edges of image
+ if (x1<0 || y1<0) {
+ if (do_rect) {
+ outI[0]= 0;
+ outI[1]= 0;
+ outI[2]= 0;
+ outI[3]= 0;
+ }
+ if (do_float) {
+ outF[0]= 0.0f;
+ outF[1]= 0.0f;
+ outF[2]= 0.0f;
+ outF[3]= 0.0f;
+ }
+ } else {
+ dataI= (unsigned char *)in->rect + in->x * y1 * 4 + 4*x1;
+ if (do_rect) {
+ outI[0]= dataI[0];
+ outI[1]= dataI[1];
+ outI[2]= dataI[2];
+ outI[3]= dataI[3];
+ }
+ dataF= in->rect_float + in->x * y1 * 4 + 4*x1;
+ if (do_float) {
+ outF[0]= dataF[0];
+ outF[1]= dataF[1];
+ outF[2]= dataF[2];
+ outF[3]= dataF[3];
+ }
+ }
+}
diff --git a/source/blender/imbuf/intern/imbuf.h b/source/blender/imbuf/intern/imbuf.h
new file mode 100644
index 00000000000..1f17217459d
--- /dev/null
+++ b/source/blender/imbuf/intern/imbuf.h
@@ -0,0 +1,171 @@
+/**
+ * imbuf.h (mar-2001 nzc)
+ *
+ * This header might have to become external...
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef IMBUF_H
+#define IMBUF_H
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <stdio.h>
+
+#ifndef WIN32
+#include <unistd.h>
+#endif
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <math.h>
+
+#ifndef WIN32
+#include <sys/mman.h>
+#endif
+
+#if !defined(WIN32) && !defined(__BeOS)
+#define O_BINARY 0
+#endif
+
+#define SWAP_SHORT(x) (((x & 0xff) << 8) | ((x >> 8) & 0xff))
+#define SWAP_LONG(x) (((x) << 24) | (((x) & 0xff00) << 8) | (((x) >> 8) & 0xff00) | (((x) >> 24) & 0xff))
+
+#define ENDIAN_NOP(x) (x)
+
+#if defined(__sgi) || defined(__sparc) || defined(__sparc__) || defined (__PPC__) || (defined (__APPLE__) && !defined(__LITTLE_ENDIAN__))
+#define LITTLE_SHORT SWAP_SHORT
+#define LITTLE_LONG SWAP_LONG
+#define BIG_SHORT ENDIAN_NOP
+#define BIG_LONG ENDIAN_NOP
+#else
+#define LITTLE_SHORT ENDIAN_NOP
+#define LITTLE_LONG ENDIAN_NOP
+#define BIG_SHORT SWAP_SHORT
+#define BIG_LONG SWAP_LONG
+#endif
+
+#define malloc(x) MEM_mallocN(x, __FILE__)
+#define free(x) MEM_freeN(x)
+#define calloc(x,y) MEM_callocN((x)*(y), __FILE__)
+#define freelist(x) BLI_freelistN(x)
+
+#ifdef SHLIB
+void *(*ib_calloc)();
+#define calloc(x,y) ib_calloc((x),(y))
+void *(*ib_malloc)();
+#define malloc(x) ib_malloc(x)
+void (*ib_free)();
+#define free(x) ib_free(x)
+void (*ib_memcpy)();
+#define memcpy(x,y,z) ib_memcpy((x),(y),(z))
+int (*ib_abs)();
+#define abs(x) ib_abs(x)
+void (*ib_fprin_tf)();
+#define fprintf ib_fprin_tf
+int (*ib_sprin_tf)();
+#define sprintf ib_sprin_tf
+void (*ib_prin_tf)();
+#define printf ib_prin_tf
+int (*ib_lseek)();
+#define lseek(x,y,z) ib_lseek((x),(y),(z))
+void *(*ib_mmap)();
+#define mmap(u,v,w,x,y,z) ib_mmap((u),(v),(w),(x),(y),(z))
+int (*ib_munmap)();
+#define munmap(x,y) ib_munmap((x),(y))
+int (*ib_open)();
+#define open(x,y) ib_open((x),(y))
+void (*ib_close)();
+#define close(x) ib_close(x)
+int (*ib_write)();
+#define write(x,y,z) ib_write((x),(y),(z))
+int (*ib_read)();
+#define read(x,y,z) ib_read((x),(y),(z))
+int (*ib_fchmod)();
+#define fchmod(x,y) ib_fchmod((x),(y))
+int (*ib_remove)();
+#define remove(x) ib_remove(x)
+size_t (*ib_strlen)();
+#define strlen(x) ib_strlen(x)
+int (*ib_isdigit)();
+#define isdigit(x) ib_isdigit(x)
+char *(*ib_strcpy)();
+#define strcpy(x,y) ib_strcpy((x),(y))
+int (*ib_atoi)();
+#define atoi(x) ib_atoi(x)
+char *(*ib_strcat)();
+#define strcat(x,y) ib_strcat((x),(y))
+int (*ib_stat)();
+/* #define stat(x,y) ib_stat((x),(y)) */
+FILE *ib_iob;
+#define _iob ib_iob
+
+#else
+
+#define ib_stat stat
+
+#endif /* SHLIB */
+
+
+#define WIDTHB(x) (((x+15)>>4)<<1)
+
+extern unsigned short *quadr;
+extern float dyuvrgb[4][4];
+extern float rgbdyuv[4][4];
+
+
+typedef struct Adat
+{
+ unsigned short w, h;
+ unsigned short type;
+ unsigned short xorig, yorig;
+ unsigned short pad;
+ float gamma;
+ float distort;
+}Adat;
+
+struct BitMapHeader
+{
+ unsigned short w, h; /* in pixels */
+ unsigned short x, y;
+ char nPlanes;
+ char masking;
+ char compression;
+ char pad1;
+ unsigned short transparentColor;
+ char xAspect, yAspect;
+ short pageWidth, pageHeight;
+};
+
+#endif /* IMBUF_H */
+
diff --git a/source/blender/imbuf/intern/imbuf_patch.h b/source/blender/imbuf/intern/imbuf_patch.h
new file mode 100644
index 00000000000..f2d490d235b
--- /dev/null
+++ b/source/blender/imbuf/intern/imbuf_patch.h
@@ -0,0 +1,114 @@
+/**
+ * imbuf_patch.h
+ *
+ * These are some definitions to make imbuf more independent from the
+ * rest of the blender code. Most of these are dirty and should not
+ * really exist.
+ *
+ * $Id$ *
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef IMBUF_PATCH_H
+#define IMBUF_PATCH_H
+
+/* most of imbuf uses this aloc, and it will disappear soon
+ * (hopefully) (25-10-2001 nzc) */
+#include "MEM_guardedalloc.h"
+
+struct ImBuf;
+
+/* originally, these were defines ... */
+typedef unsigned char uchar;
+
+/* should not be used at all */
+#define TRUE 1
+#define FALSE 0
+
+/* Endianness: flip the byte order. It's strange that this is needed..
+ * After all, there is an internal endian.{c,h}... */
+#if defined(__sgi) || defined (__sparc) || defined(__sparc__) || defined (__PPC__) || defined (__ppc__) || defined (__BIG_ENDIAN__)
+#define MAKE_ID(a,b,c,d) ( (int)(a)<<24 | (int)(b)<<16 | (c)<<8 | (d) )
+#else
+#define MAKE_ID(a,b,c,d) ( (int)(d)<<24 | (int)(c)<<16 | (b)<<8 | (a) )
+#endif
+
+/* These defines loop back to the internal Blender memory management
+ * system, implemented in blenlib. */
+#define NEW(x) (x*)MEM_mallocN(sizeof(x),# x)
+#define mallocstruct(x,y) (x*)malloc((y)* sizeof(x))
+#define callocstruct(x,y) (x*)calloc((y), sizeof(x))
+
+/* These vars are used thoughout the image buffer for conversions. */
+extern float rgbyuv[4][4];
+extern float yuvrgb[4][4];
+extern float rgbbeta[4][4];
+
+/* This one helps debugging. */
+extern int IB_verbose;
+
+/* These ID's are used for checking memory blocks. See blenlib for
+ * more details. This set is only used in the imbuf internally. */
+
+#define CAT MAKE_ID('C','A','T',' ')
+#define FORM MAKE_ID('F','O','R','M')
+#define ILBM MAKE_ID('I','L','B','M')
+#define BMHD MAKE_ID('B','M','H','D')
+#define CMAP MAKE_ID('C','M','A','P')
+#define CAMG MAKE_ID('C','A','M','G')
+#define BODY MAKE_ID('B','O','D','Y')
+
+#define ANIM MAKE_ID('A','N','I','M')
+#define ADAT MAKE_ID('A','D','A','T')
+#define CODE MAKE_ID('C','O','D','E')
+#define ANHD MAKE_ID('A','N','H','D')
+#define DLTA MAKE_ID('D','L','T','A')
+#define BLCK MAKE_ID('B','L','C','K')
+
+#define MAXRUN 126
+#define MAXDAT 126
+#define IFFNOP 128
+
+#define camg ftype
+
+#define LI_rect IB_rect
+#define LI_planes IB_planes
+#define LI_kcmap IB_cmap
+#define LI_cmap IB_cmap
+#define LI_freem IB_freem
+#define LI_test IB_test
+
+#define SI_rect IB_rect
+#define SI_planes IB_planes
+#define SI_kcmap IB_cmap
+#define SI_cmap IB_cmap
+#define SI_vert IB_vert
+
+#endif
+
diff --git a/source/blender/imbuf/intern/imginfo.c b/source/blender/imbuf/intern/imginfo.c
new file mode 100644
index 00000000000..37bde9e5ac3
--- /dev/null
+++ b/source/blender/imbuf/intern/imginfo.c
@@ -0,0 +1,158 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Austin Benesh. Ton Roosendaal.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "BLI_blenlib.h"
+#include "MEM_guardedalloc.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "IMB_imginfo.h"
+
+
+
+void IMB_imginfo_free(struct ImBuf* img)
+{
+ ImgInfo *info;
+
+ if (!img)
+ return;
+ if (!img->img_info) {
+ return;
+ }
+ info = img->img_info;
+ while (info) {
+ ImgInfo* next = info->next;
+ MEM_freeN(info->key);
+ MEM_freeN(info->value);
+ MEM_freeN(info);
+ info = next;
+ }
+}
+
+int IMB_imginfo_get_field(struct ImBuf* img, const char* key, char* field, int len)
+{
+ ImgInfo *info;
+ int retval = 0;
+
+ if (!img)
+ return 0;
+ if (!img->img_info) {
+ return 0;
+ }
+ info = img->img_info;
+ while (info) {
+ if (strcmp(key, info->key) == 0) {
+ BLI_strncpy(field, info->value, len);
+ retval = 1;
+ break;
+ }
+ info = info->next;
+ }
+ return retval;
+}
+
+int IMB_imginfo_add_field(struct ImBuf* img, const char* key, const char* field)
+{
+ ImgInfo *info;
+ ImgInfo *last;
+
+ if (!img)
+ return 0;
+
+ if (!img->img_info) {
+ img->img_info = MEM_callocN(sizeof(ImgInfo), "ImgInfo");
+ info = img->img_info;
+ } else {
+ info = img->img_info;
+ last = info;
+ while (info) {
+ last = info;
+ info = info->next;
+ }
+ info = MEM_callocN(sizeof(ImgInfo), "ImgInfo");
+ last->next = info;
+ }
+ info->key = BLI_strdup(key);
+ info->value = BLI_strdup(field);
+ return 1;
+}
+
+int IMB_imginfo_del_field(struct ImBuf *img, const char *key)
+{
+ ImgInfo *p, *p1;
+
+ if ((!img) || (!img->img_info))
+ return (0);
+
+ p = img->img_info;
+ p1 = NULL;
+ while (p) {
+ if (!strcmp (key, p->key)) {
+ if (p1)
+ p1->next = p->next;
+ else
+ img->img_info = p->next;
+
+ MEM_freeN(p->key);
+ MEM_freeN(p->value);
+ MEM_freeN(p);
+ return (1);
+ }
+ p1 = p;
+ p = p->next;
+ }
+ return (0);
+}
+
+int IMB_imginfo_change_field(struct ImBuf *img, const char *key, const char *field)
+{
+ ImgInfo *p;
+
+ if (!img)
+ return (0);
+
+ if (!img->img_info)
+ return (IMB_imginfo_add_field (img, key, field));
+
+ p = img->img_info;
+ while (p) {
+ if (!strcmp (key, p->key)) {
+ MEM_freeN (p->value);
+ p->value = BLI_strdup (field);
+ return (1);
+ }
+ p = p->next;
+ }
+
+ return (IMB_imginfo_add_field (img, key, field));
+}
diff --git a/source/blender/imbuf/intern/iris.c b/source/blender/imbuf/intern/iris.c
new file mode 100644
index 00000000000..5c0a3f94a0e
--- /dev/null
+++ b/source/blender/imbuf/intern/iris.c
@@ -0,0 +1,653 @@
+/**
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * iris.c
+ *
+ * $Id$
+ */
+
+#include <string.h>
+#include "BLI_blenlib.h"
+#include "imbuf.h"
+#include "imbuf_patch.h"
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+#include "IMB_allocimbuf.h"
+#include "IMB_iris.h"
+
+typedef struct {
+ unsigned short imagic; /* stuff saved on disk . . */
+ unsigned short type;
+ unsigned short dim;
+ unsigned short xsize;
+ unsigned short ysize;
+ unsigned short zsize;
+ unsigned int min;
+ unsigned int max;
+ unsigned int wastebytes;
+ char name[80];
+ unsigned int colormap;
+
+ int file; /* stuff used in core only */
+ unsigned short flags;
+ short dorev;
+ short x;
+ short y;
+ short z;
+ short cnt;
+ unsigned short *ptr;
+ unsigned short *base;
+ unsigned short *tmpbuf;
+ unsigned int offset;
+ unsigned int rleend; /* for rle images */
+ unsigned int *rowstart; /* for rle images */
+ int *rowsize; /* for rle images */
+} IMAGE;
+
+#define RINTLUM (79)
+#define GINTLUM (156)
+#define BINTLUM (21)
+
+#define ILUM(r,g,b) ((int)(RINTLUM*(r)+GINTLUM*(g)+BINTLUM*(b))>>8)
+
+#define OFFSET_R 0 /* this is byte order dependent */
+#define OFFSET_G 1
+#define OFFSET_B 2
+#define OFFSET_A 3
+
+#define CHANOFFSET(z) (3-(z)) /* this is byte order dependent */
+
+#define TYPEMASK 0xff00
+#define BPPMASK 0x00ff
+#define ITYPE_VERBATIM 0x0000
+#define ITYPE_RLE 0x0100
+#define ISRLE(type) (((type) & 0xff00) == ITYPE_RLE)
+#define ISVERBATIM(type) (((type) & 0xff00) == ITYPE_VERBATIM)
+#define BPP(type) ((type) & BPPMASK)
+#define RLE(bpp) (ITYPE_RLE | (bpp))
+#define VERBATIM(bpp) (ITYPE_VERBATIM | (bpp))
+#define IBUFSIZE(pixels) ((pixels+(pixels>>6))<<2)
+#define RLE_NOP 0x00
+
+/* funcs */
+static void readheader(FILE *inf, IMAGE *image);
+static int writeheader(FILE *outf, IMAGE *image);
+
+static unsigned short getshort(FILE *inf);
+static unsigned int getlong(FILE *inf);
+static void putshort(FILE *outf, unsigned short val);
+static int putlong(FILE *outf, unsigned int val);
+static int writetab(FILE *outf, unsigned int *tab, int len);
+static void readtab(FILE *inf, unsigned int *tab, int len);
+
+static void expandrow(unsigned char *optr, unsigned char *iptr, int z);
+static void interleaverow(unsigned char *lptr, unsigned char *cptr, int z, int n);
+static int compressrow(unsigned char *lbuf, unsigned char *rlebuf, int z, int cnt);
+static void lumrow(unsigned char *rgbptr, unsigned char *lumptr, int n);
+
+/*
+ * byte order independent read/write of shorts and ints.
+ *
+ */
+
+static uchar * file_data;
+static int file_offset;
+
+static unsigned short getshort(FILE *inf)
+{
+ unsigned char * buf;
+
+ buf = file_data + file_offset;
+ file_offset += 2;
+
+ return (buf[0]<<8)+(buf[1]<<0);
+}
+
+static unsigned int getlong(FILE *inf)
+{
+ unsigned char * buf;
+
+ buf = file_data + file_offset;
+ file_offset += 4;
+
+ return (buf[0]<<24)+(buf[1]<<16)+(buf[2]<<8)+(buf[3]<<0);
+}
+
+static void putshort(FILE *outf, unsigned short val)
+{
+ unsigned char buf[2];
+
+ buf[0] = (val>>8);
+ buf[1] = (val>>0);
+ fwrite(buf,2,1,outf);
+}
+
+static int putlong(FILE *outf, unsigned int val)
+{
+ unsigned char buf[4];
+
+ buf[0] = (val>>24);
+ buf[1] = (val>>16);
+ buf[2] = (val>>8);
+ buf[3] = (val>>0);
+ return fwrite(buf,4,1,outf);
+}
+
+static void readheader(FILE *inf, IMAGE *image)
+{
+ memset(image, 0, sizeof(IMAGE));
+ image->imagic = getshort(inf);
+ image->type = getshort(inf);
+ image->dim = getshort(inf);
+ image->xsize = getshort(inf);
+ image->ysize = getshort(inf);
+ image->zsize = getshort(inf);
+}
+
+static int writeheader(FILE *outf, IMAGE *image)
+{
+ IMAGE t;
+
+ memset(&t, 0, sizeof(IMAGE));
+ fwrite(&t,sizeof(IMAGE),1,outf);
+ fseek(outf,0,SEEK_SET);
+ putshort(outf,image->imagic);
+ putshort(outf,image->type);
+ putshort(outf,image->dim);
+ putshort(outf,image->xsize);
+ putshort(outf,image->ysize);
+ putshort(outf,image->zsize);
+ putlong(outf,image->min);
+ putlong(outf,image->max);
+ putlong(outf,0);
+ return fwrite("no name",8,1,outf);
+}
+
+static int writetab(FILE *outf, unsigned int *tab, int len)
+{
+ int r = 0;
+
+ while(len) {
+ r = putlong(outf,*tab++);
+ len -= 4;
+ }
+ return r;
+}
+
+static void readtab(FILE *inf, unsigned int *tab, int len)
+{
+ while(len) {
+ *tab++ = getlong(inf);
+ len -= 4;
+ }
+}
+
+static void test_endian_zbuf(struct ImBuf *ibuf)
+{
+ int len;
+ int *zval;
+
+ if( BIG_LONG(1) == 1 ) return;
+ if(ibuf->zbuf==0) return;
+
+ len= ibuf->x*ibuf->y;
+ zval= ibuf->zbuf;
+
+ while(len--) {
+ zval[0]= BIG_LONG(zval[0]);
+ zval++;
+ }
+}
+
+
+/*
+ * longimagedata -
+ * read in a B/W RGB or RGBA iris image file and return a
+ * pointer to an array of ints.
+ *
+ */
+
+struct ImBuf *imb_loadiris(unsigned char *mem, int flags)
+{
+ unsigned int *base, *lptr = NULL;
+ unsigned int *zbase, *zptr;
+ unsigned char *rledat;
+ unsigned int *starttab, *lengthtab;
+ FILE *inf = NULL;
+ IMAGE image;
+ int x, y, z, tablen;
+ int xsize, ysize, zsize;
+ int bpp, rle, cur, badorder;
+ ImBuf * ibuf;
+ uchar * rect;
+
+ /*printf("new iris\n");*/
+
+ file_data = mem;
+ file_offset = 0;
+
+ readheader(inf, &image);
+ if(image.imagic != IMAGIC) {
+ fprintf(stderr,"longimagedata: bad magic number in image file\n");
+ return(0);
+ }
+
+ rle = ISRLE(image.type);
+ bpp = BPP(image.type);
+ if(bpp != 1 ) {
+ fprintf(stderr,"longimagedata: image must have 1 byte per pix chan\n");
+ return(0);
+ }
+
+ xsize = image.xsize;
+ ysize = image.ysize;
+ zsize = image.zsize;
+
+ if (flags & IB_test) {
+ ibuf = IMB_allocImBuf(image.xsize, image.ysize, 8 * image.zsize, 0, 0);
+ if (ibuf) ibuf->ftype = IMAGIC;
+ return(ibuf);
+ }
+
+ if (rle) {
+ tablen = ysize*zsize*sizeof(int);
+ starttab = (unsigned int *)malloc(tablen);
+ lengthtab = (unsigned int *)malloc(tablen);
+ file_offset = 512;
+
+ readtab(inf,starttab,tablen);
+ readtab(inf,lengthtab,tablen);
+
+ /* check data order */
+ cur = 0;
+ badorder = 0;
+ for (y = 0; y<ysize; y++) {
+ for (z = 0; z<zsize; z++) {
+ if (starttab[y+z*ysize]<cur) {
+ badorder = 1;
+ break;
+ }
+ cur = starttab[y+z*ysize];
+ }
+ if(badorder)
+ break;
+ }
+
+ ibuf = IMB_allocImBuf(xsize, ysize, 8 * zsize, IB_rect, 0);
+ if (ibuf->depth > 32) ibuf->depth = 32;
+ base = ibuf->rect;
+ zbase = (unsigned int *)ibuf->zbuf;
+
+ if (badorder) {
+ for(z=0; z<zsize; z++) {
+ lptr = base;
+ for(y=0; y<ysize; y++) {
+ file_offset = starttab[y+z*ysize];
+
+ rledat = file_data + file_offset;
+ file_offset += lengthtab[y+z*ysize];
+
+ expandrow((uchar *)lptr, rledat, 3-z);
+ lptr += xsize;
+ }
+ }
+ }
+ else {
+ lptr = base;
+ zptr = zbase;
+ for(y=0; y<ysize; y++) {
+
+ for(z=0; z<zsize; z++) {
+
+ file_offset = starttab[y+z*ysize];
+
+ rledat = file_data + file_offset;
+ file_offset += lengthtab[y+z*ysize];
+
+ if(z<4) expandrow((uchar *)lptr, rledat, 3-z);
+ else if(z<8) expandrow((uchar *)zptr, rledat, 7-z);
+ }
+ lptr += xsize;
+ zptr += xsize;
+ }
+ }
+
+ free(starttab);
+ free(lengthtab);
+ }
+ else {
+
+ ibuf = IMB_allocImBuf(xsize, ysize, 8 * zsize, IB_rect, 0);
+ if (ibuf->depth > 32) ibuf->depth = 32;
+
+ base = ibuf->rect;
+ zbase = (unsigned int *)ibuf->zbuf;
+
+ file_offset = 512;
+ rledat = file_data + file_offset;
+
+ for(z = 0; z < zsize; z++) {
+
+ if(z<4) lptr = base;
+ else if(z<8) lptr= zbase;
+
+ for(y = 0; y < ysize; y++) {
+
+ interleaverow((uchar *)lptr, rledat, 3-z, xsize);
+ rledat += xsize;
+
+ lptr += xsize;
+ }
+ }
+ }
+
+ if (image.zsize == 1){
+ rect = (uchar *) ibuf->rect;
+ for (x = ibuf->x * ibuf->y; x > 0; x--) {
+ rect[0] = 255;
+ rect[1] = rect[2] = rect[3];
+ rect += 4;
+ }
+ } else if (image.zsize == 2){
+ /* grayscale with alpha */
+ rect = (uchar *) ibuf->rect;
+ for (x = ibuf->x * ibuf->y; x > 0; x--) {
+ rect[0] = rect[2];
+ rect[1] = rect[2] = rect[3];
+ rect += 4;
+ }
+ } else if (image.zsize == 3){
+ /* add alpha */
+ rect = (uchar *) ibuf->rect;
+ for (x = ibuf->x * ibuf->y; x > 0; x--) {
+ rect[0] = 255;
+ rect += 4;
+ }
+ }
+
+ ibuf->ftype = IMAGIC;
+ if (flags & IB_ttob) IMB_flipy(ibuf);
+
+ test_endian_zbuf(ibuf);
+
+ if (ibuf) {
+ if (ibuf->rect)
+ IMB_convert_rgba_to_abgr(ibuf);
+ }
+
+ return(ibuf);
+}
+
+/* static utility functions for longimagedata */
+
+static void interleaverow(unsigned char *lptr, unsigned char *cptr, int z, int n)
+{
+ lptr += z;
+ while(n--) {
+ *lptr = *cptr++;
+ lptr += 4;
+ }
+}
+
+static void expandrow(unsigned char *optr, unsigned char *iptr, int z)
+{
+ unsigned char pixel, count;
+
+ optr += z;
+ while(1) {
+ pixel = *iptr++;
+ if ( !(count = (pixel & 0x7f)) )
+ return;
+ if(pixel & 0x80) {
+ while(count>=8) {
+ optr[0*4] = iptr[0];
+ optr[1*4] = iptr[1];
+ optr[2*4] = iptr[2];
+ optr[3*4] = iptr[3];
+ optr[4*4] = iptr[4];
+ optr[5*4] = iptr[5];
+ optr[6*4] = iptr[6];
+ optr[7*4] = iptr[7];
+ optr += 8*4;
+ iptr += 8;
+ count -= 8;
+ }
+ while(count--) {
+ *optr = *iptr++;
+ optr+=4;
+ }
+ } else {
+ pixel = *iptr++;
+ while(count>=8) {
+ optr[0*4] = pixel;
+ optr[1*4] = pixel;
+ optr[2*4] = pixel;
+ optr[3*4] = pixel;
+ optr[4*4] = pixel;
+ optr[5*4] = pixel;
+ optr[6*4] = pixel;
+ optr[7*4] = pixel;
+ optr += 8*4;
+ count -= 8;
+ }
+ while(count--) {
+ *optr = pixel;
+ optr+=4;
+ }
+ }
+ }
+}
+
+/*
+ * output_iris -
+ * copy an array of ints to an iris image file. Each int
+ * represents one pixel. xsize and ysize specify the dimensions of
+ * the pixel array. zsize specifies what kind of image file to
+ * write out. if zsize is 1, the luminance of the pixels are
+ * calculated, and a sinlge channel black and white image is saved.
+ * If zsize is 3, an RGB image file is saved. If zsize is 4, an
+ * RGBA image file is saved.
+ *
+ * Added: zbuf write
+ */
+
+static int output_iris(unsigned int *lptr, int xsize, int ysize, int zsize, char *name, int *zptr)
+{
+ FILE *outf;
+ IMAGE *image;
+ int tablen, y, z, pos, len = 0;
+ unsigned int *starttab, *lengthtab;
+ unsigned char *rlebuf;
+ unsigned int *lumbuf;
+ int rlebuflen, goodwrite;
+
+ goodwrite = 1;
+ outf = fopen(name, "wb");
+ if(!outf) return 0;
+
+ tablen = ysize*zsize*sizeof(int);
+
+ image = (IMAGE *)malloc(sizeof(IMAGE));
+ starttab = (unsigned int *)malloc(tablen);
+ lengthtab = (unsigned int *)malloc(tablen);
+ rlebuflen = 1.05*xsize+10;
+ rlebuf = (unsigned char *)malloc(rlebuflen);
+ lumbuf = (unsigned int *)malloc(xsize*sizeof(int));
+
+ memset(image, 0, sizeof(IMAGE));
+ image->imagic = IMAGIC;
+ image->type = RLE(1);
+ if(zsize>1)
+ image->dim = 3;
+ else
+ image->dim = 2;
+ image->xsize = xsize;
+ image->ysize = ysize;
+ image->zsize = zsize;
+ image->min = 0;
+ image->max = 255;
+ goodwrite *= writeheader(outf,image);
+ fseek(outf,512+2*tablen,SEEK_SET);
+ pos = 512+2*tablen;
+
+ for (y = 0; y < ysize; y++) {
+ for (z = 0; z < zsize; z++) {
+
+ if (zsize == 1) {
+ lumrow((uchar *)lptr,(uchar *)lumbuf,xsize);
+ len = compressrow((uchar *)lumbuf,rlebuf,CHANOFFSET(z),xsize);
+ }
+ else {
+ if(z<4) {
+ len = compressrow((uchar *)lptr, rlebuf,CHANOFFSET(z),xsize);
+ }
+ else if(z<8 && zptr) {
+ len = compressrow((uchar *)zptr, rlebuf,CHANOFFSET(z-4),xsize);
+ }
+ }
+ if(len>rlebuflen) {
+ fprintf(stderr,"output_iris: rlebuf is too small - bad poop\n");
+ exit(1);
+ }
+ goodwrite *= fwrite(rlebuf, len, 1, outf);
+ starttab[y+z*ysize] = pos;
+ lengthtab[y+z*ysize] = len;
+ pos += len;
+ }
+ lptr += xsize;
+ if(zptr) zptr += xsize;
+ }
+
+ fseek(outf,512,SEEK_SET);
+ goodwrite *= writetab(outf,starttab,tablen);
+ goodwrite *= writetab(outf,lengthtab,tablen);
+ free(image);
+ free(starttab);
+ free(lengthtab);
+ free(rlebuf);
+ free(lumbuf);
+ fclose(outf);
+ if(goodwrite)
+ return 1;
+ else {
+ fprintf(stderr,"output_iris: not enough space for image!!\n");
+ return 0;
+ }
+}
+
+/* static utility functions for output_iris */
+
+static void lumrow(unsigned char *rgbptr, unsigned char *lumptr, int n)
+{
+ lumptr += CHANOFFSET(0);
+ while(n--) {
+ *lumptr = ILUM(rgbptr[OFFSET_R],rgbptr[OFFSET_G],rgbptr[OFFSET_B]);
+ lumptr += 4;
+ rgbptr += 4;
+ }
+}
+
+static int compressrow(unsigned char *lbuf, unsigned char *rlebuf, int z, int cnt)
+{
+ unsigned char *iptr, *ibufend, *sptr, *optr;
+ short todo, cc;
+ int count;
+
+ lbuf += z;
+ iptr = lbuf;
+ ibufend = iptr+cnt*4;
+ optr = rlebuf;
+
+ while(iptr<ibufend) {
+ sptr = iptr;
+ iptr += 8;
+ while((iptr<ibufend)&& ((iptr[-8]!=iptr[-4])||(iptr[-4]!=iptr[0])))
+ iptr+=4;
+ iptr -= 8;
+ count = (iptr-sptr)/4;
+ while(count) {
+ todo = count>126 ? 126:count;
+ count -= todo;
+ *optr++ = 0x80|todo;
+ while(todo>8) {
+ optr[0] = sptr[0*4];
+ optr[1] = sptr[1*4];
+ optr[2] = sptr[2*4];
+ optr[3] = sptr[3*4];
+ optr[4] = sptr[4*4];
+ optr[5] = sptr[5*4];
+ optr[6] = sptr[6*4];
+ optr[7] = sptr[7*4];
+
+ optr += 8;
+ sptr += 8*4;
+ todo -= 8;
+ }
+ while(todo--) {
+ *optr++ = *sptr;
+ sptr += 4;
+ }
+ }
+ sptr = iptr;
+ cc = *iptr;
+ iptr += 4;
+ while( (iptr<ibufend) && (*iptr == cc) )
+ iptr += 4;
+ count = (iptr-sptr)/4;
+ while(count) {
+ todo = count>126 ? 126:count;
+ count -= todo;
+ *optr++ = todo;
+ *optr++ = cc;
+ }
+ }
+ *optr++ = 0;
+ return optr - (unsigned char *)rlebuf;
+}
+
+short imb_saveiris(struct ImBuf * ibuf, char *name, int flags)
+{
+ short zsize;
+ int ret;
+
+ zsize = (ibuf->depth + 7) >> 3;
+ if (flags & IB_zbuf && ibuf->zbuf != 0) zsize = 8;
+
+ IMB_convert_rgba_to_abgr(ibuf);
+ test_endian_zbuf(ibuf);
+
+ ret = output_iris(ibuf->rect, ibuf->x, ibuf->y, zsize, name, ibuf->zbuf);
+
+ /* restore! Quite clumsy, 2 times a switch... maybe better a malloc ? */
+ IMB_convert_rgba_to_abgr(ibuf);
+ test_endian_zbuf(ibuf);
+
+ return(ret);
+}
+
diff --git a/source/blender/imbuf/intern/jpeg.c b/source/blender/imbuf/intern/jpeg.c
new file mode 100644
index 00000000000..1774aa7c156
--- /dev/null
+++ b/source/blender/imbuf/intern/jpeg.c
@@ -0,0 +1,620 @@
+/**
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * jpeg.c
+ *
+ * $Id$
+ */
+
+
+/* This little block needed for linking to Blender... */
+#include <stdio.h>
+#include "BLI_blenlib.h"
+
+#include "imbuf.h"
+#include "imbuf_patch.h"
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+#include "IMB_jpeg.h"
+#include "jpeglib.h"
+
+/* the types are from the jpeg lib */
+static void jpeg_error (j_common_ptr cinfo);
+static void init_source(j_decompress_ptr cinfo);
+static boolean fill_input_buffer(j_decompress_ptr cinfo);
+static void skip_input_data(j_decompress_ptr cinfo, long num_bytes);
+static void term_source(j_decompress_ptr cinfo);
+static void memory_source(j_decompress_ptr cinfo, unsigned char *buffer, int size);
+static boolean handle_app1 (j_decompress_ptr cinfo);
+static ImBuf * ibJpegImageFromCinfo(struct jpeg_decompress_struct * cinfo, int flags);
+
+
+/*
+ * In principle there are 4 jpeg formats.
+ *
+ * 1. jpeg - standard printing, u & v at quarter of resulution
+ * 2. jvid - standaard video, u & v half resolution, frame not interlaced
+
+type 3 is unsupported as of jul 05 2000 Frank.
+
+ * 3. jstr - as 2, but written in 2 seperate fields
+
+ * 4. jmax - no scaling in the components
+ */
+
+static int jpeg_failed = FALSE;
+static int jpeg_default_quality;
+static int ibuf_ftype;
+
+int imb_is_a_jpeg(unsigned char *mem) {
+
+ if ((mem[0]== 0xFF) && (mem[1] == 0xD8))return 1;
+ return 0;
+}
+
+static void jpeg_error (j_common_ptr cinfo)
+{
+ /* Always display the message */
+ (*cinfo->err->output_message) (cinfo);
+
+ /* Let the memory manager delete any temp files before we die */
+ jpeg_destroy(cinfo);
+
+ jpeg_failed = TRUE;
+}
+
+//----------------------------------------------------------
+// INPUT HANDLER FROM MEMORY
+//----------------------------------------------------------
+
+typedef struct {
+ unsigned char *buffer;
+ int filled;
+} buffer_struct;
+
+typedef struct {
+ struct jpeg_source_mgr pub; /* public fields */
+
+ unsigned char *buffer;
+ int size;
+ JOCTET terminal[2];
+} my_source_mgr;
+
+typedef my_source_mgr * my_src_ptr;
+
+static void init_source(j_decompress_ptr cinfo)
+{
+}
+
+
+static boolean fill_input_buffer(j_decompress_ptr cinfo)
+{
+ my_src_ptr src = (my_src_ptr) cinfo->src;
+
+ /* Since we have given all we have got already
+ * we simply fake an end of file
+ */
+
+ src->pub.next_input_byte = src->terminal;
+ src->pub.bytes_in_buffer = 2;
+ src->terminal[0] = (JOCTET) 0xFF;
+ src->terminal[1] = (JOCTET) JPEG_EOI;
+
+ return TRUE;
+}
+
+
+static void skip_input_data(j_decompress_ptr cinfo, long num_bytes)
+{
+ my_src_ptr src = (my_src_ptr) cinfo->src;
+
+ src->pub.next_input_byte = src->pub.next_input_byte + num_bytes;
+}
+
+
+static void term_source(j_decompress_ptr cinfo)
+{
+}
+
+static void memory_source(j_decompress_ptr cinfo, unsigned char *buffer, int size)
+{
+ my_src_ptr src;
+
+ if (cinfo->src == NULL)
+ { /* first time for this JPEG object? */
+ cinfo->src = (struct jpeg_source_mgr *)(*cinfo->mem->alloc_small)
+ ((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(my_source_mgr));
+ }
+
+ src = (my_src_ptr) cinfo->src;
+ src->pub.init_source = init_source;
+ src->pub.fill_input_buffer = fill_input_buffer;
+ src->pub.skip_input_data = skip_input_data;
+ src->pub.resync_to_restart = jpeg_resync_to_restart;
+ src->pub.term_source = term_source;
+
+ src->pub.bytes_in_buffer = size;
+ src->pub.next_input_byte = buffer;
+
+ src->buffer = buffer;
+ src->size = size;
+}
+
+
+#define MAKESTMT(stuff) do { stuff } while (0)
+
+#define INPUT_VARS(cinfo) \
+ struct jpeg_source_mgr * datasrc = (cinfo)->src; \
+ const JOCTET * next_input_byte = datasrc->next_input_byte; \
+ size_t bytes_in_buffer = datasrc->bytes_in_buffer
+
+/* Unload the local copies --- do this only at a restart boundary */
+#define INPUT_SYNC(cinfo) \
+ ( datasrc->next_input_byte = next_input_byte, \
+ datasrc->bytes_in_buffer = bytes_in_buffer )
+
+/* Reload the local copies --- seldom used except in MAKE_BYTE_AVAIL */
+#define INPUT_RELOAD(cinfo) \
+ ( next_input_byte = datasrc->next_input_byte, \
+ bytes_in_buffer = datasrc->bytes_in_buffer )
+
+/* Internal macro for INPUT_BYTE and INPUT_2BYTES: make a byte available.
+ * Note we do *not* do INPUT_SYNC before calling fill_input_buffer,
+ * but we must reload the local copies after a successful fill.
+ */
+#define MAKE_BYTE_AVAIL(cinfo,action) \
+ if (bytes_in_buffer == 0) { \
+ if (! (*datasrc->fill_input_buffer) (cinfo)) \
+ { action; } \
+ INPUT_RELOAD(cinfo); \
+ } \
+ bytes_in_buffer--
+
+/* Read a byte into variable V.
+ * If must suspend, take the specified action (typically "return FALSE").
+ */
+#define INPUT_BYTE(cinfo,V,action) \
+ MAKESTMT( MAKE_BYTE_AVAIL(cinfo,action); \
+ V = GETJOCTET(*next_input_byte++); )
+
+/* As above, but read two bytes interpreted as an unsigned 16-bit integer.
+ * V should be declared unsigned int or perhaps INT32.
+ */
+#define INPUT_2BYTES(cinfo,V,action) \
+ MAKESTMT( MAKE_BYTE_AVAIL(cinfo,action); \
+ V = ((unsigned int) GETJOCTET(*next_input_byte++)) << 8; \
+ MAKE_BYTE_AVAIL(cinfo,action); \
+ V += GETJOCTET(*next_input_byte++); )
+
+
+static boolean
+handle_app1 (j_decompress_ptr cinfo)
+{
+ INT32 length, i;
+ char neogeo[128];
+
+ INPUT_VARS(cinfo);
+
+ INPUT_2BYTES(cinfo, length, return FALSE);
+ length -= 2;
+
+ if (length < 16) {
+ for (i = 0; i < length; i++) INPUT_BYTE(cinfo, neogeo[i], return FALSE);
+ length = 0;
+ if (strncmp(neogeo, "NeoGeo", 6) == 0) memcpy(&ibuf_ftype, neogeo + 6, 4);
+ ibuf_ftype = BIG_LONG(ibuf_ftype);
+ }
+ INPUT_SYNC(cinfo); /* do before skip_input_data */
+ if (length > 0) (*cinfo->src->skip_input_data) (cinfo, length);
+ return TRUE;
+}
+
+
+static ImBuf * ibJpegImageFromCinfo(struct jpeg_decompress_struct * cinfo, int flags)
+{
+ JSAMPARRAY row_pointer;
+ JSAMPLE * buffer = 0;
+ int row_stride;
+ int x, y, depth, r, g, b, k;
+ struct ImBuf * ibuf = 0;
+ uchar * rect;
+
+ /* install own app1 handler */
+ ibuf_ftype = 0;
+ jpeg_set_marker_processor(cinfo, 0xe1, handle_app1);
+ cinfo->dct_method = JDCT_FLOAT;
+
+ if (jpeg_read_header(cinfo, FALSE) == JPEG_HEADER_OK) {
+ x = cinfo->image_width;
+ y = cinfo->image_height;
+ depth = cinfo->num_components;
+
+ if (cinfo->jpeg_color_space == JCS_YCCK) cinfo->out_color_space = JCS_CMYK;
+
+ jpeg_start_decompress(cinfo);
+
+ if (ibuf_ftype == 0) {
+ ibuf_ftype = JPG_STD;
+ if (cinfo->max_v_samp_factor == 1) {
+ if (cinfo->max_h_samp_factor == 1) ibuf_ftype = JPG_MAX;
+ else ibuf_ftype = JPG_VID;
+ }
+ }
+
+ if (flags & IB_test) {
+ jpeg_abort_decompress(cinfo);
+ ibuf = IMB_allocImBuf(x, y, 8 * depth, 0, 0);
+ } else {
+ ibuf = IMB_allocImBuf(x, y, 8 * depth, IB_rect, 0);
+
+ row_stride = cinfo->output_width * depth;
+
+ row_pointer = (*cinfo->mem->alloc_sarray) ((j_common_ptr) cinfo, JPOOL_IMAGE, row_stride, 1);
+
+ for (y = ibuf->y - 1; y >= 0; y--) {
+ jpeg_read_scanlines(cinfo, row_pointer, 1);
+ if (flags & IB_ttob) {
+ rect = (uchar *) (ibuf->rect + (ibuf->y - 1 - y) * ibuf->x);
+ } else {
+ rect = (uchar *) (ibuf->rect + y * ibuf->x);
+ }
+ buffer = row_pointer[0];
+
+ switch(depth) {
+ case 1:
+ for (x=ibuf->x; x >0; x--) {
+ rect[3] = 255;
+ rect[0] = rect[1] = rect[2] = *buffer++;
+ rect += 4;
+ }
+ break;
+ case 3:
+ for (x=ibuf->x; x >0; x--) {
+ rect[3] = 255;
+ rect[0] = *buffer++;
+ rect[1] = *buffer++;
+ rect[2] = *buffer++;
+ rect += 4;
+ }
+ break;
+ case 4:
+ for (x=ibuf->x; x >0; x--) {
+ r = *buffer++;
+ g = *buffer++;
+ b = *buffer++;
+ k = *buffer++;
+
+ k = 255 - k;
+ r -= k;
+ if (r & 0xffffff00) {
+ if (r < 0) r = 0;
+ else r = 255;
+ }
+ g -= k;
+ if (g & 0xffffff00) {
+ if (g < 0) g = 0;
+ else g = 255;
+ }
+ b -= k;
+ if (b & 0xffffff00) {
+ if (b < 0) b = 0;
+ else b = 255;
+ }
+
+ rect[3] = 255 - k;
+ rect[2] = b;
+ rect[1] = g;
+ rect[0] = r;
+ rect += 4;
+ }
+ }
+ }
+ jpeg_finish_decompress(cinfo);
+ }
+
+ jpeg_destroy((j_common_ptr) cinfo);
+ ibuf->ftype = ibuf_ftype;
+ }
+
+ return(ibuf);
+}
+
+ImBuf * imb_ibJpegImageFromFilename (const char * filename, int flags)
+{
+ struct jpeg_decompress_struct _cinfo, *cinfo = &_cinfo;
+ struct jpeg_error_mgr jerr;
+ FILE * infile;
+ ImBuf * ibuf;
+
+ if ((infile = fopen(filename, "rb")) == NULL) return 0;
+
+ cinfo->err = jpeg_std_error(&jerr);
+ jerr.error_exit = jpeg_error;
+
+ jpeg_create_decompress(cinfo);
+ jpeg_stdio_src(cinfo, infile);
+
+ ibuf = ibJpegImageFromCinfo(cinfo, flags);
+
+ fclose(infile);
+ return(ibuf);
+}
+
+ImBuf * imb_ibJpegImageFromMemory (unsigned char * buffer, int size, int flags)
+{
+ struct jpeg_decompress_struct _cinfo, *cinfo = &_cinfo;
+ struct jpeg_error_mgr jerr;
+ ImBuf * ibuf;
+
+ cinfo->err = jpeg_std_error(&jerr);
+ jerr.error_exit = jpeg_error;
+
+ jpeg_create_decompress(cinfo);
+ memory_source(cinfo, buffer, size);
+
+ ibuf = ibJpegImageFromCinfo(cinfo, flags);
+
+ return(ibuf);
+}
+
+
+static void write_jpeg(struct jpeg_compress_struct * cinfo, struct ImBuf * ibuf)
+{
+ JSAMPLE * buffer = 0;
+ JSAMPROW row_pointer[1];
+ uchar * rect;
+ int x, y;
+ char neogeo[128];
+
+
+ jpeg_start_compress(cinfo, TRUE);
+
+ strcpy(neogeo, "NeoGeo");
+ ibuf_ftype = BIG_LONG(ibuf->ftype);
+
+ memcpy(neogeo + 6, &ibuf_ftype, 4);
+ jpeg_write_marker(cinfo, 0xe1, (JOCTET*) neogeo, 10);
+
+ row_pointer[0] =
+ mallocstruct(JSAMPLE,
+ cinfo->input_components *
+ cinfo->image_width);
+
+ for(y = ibuf->y - 1; y >= 0; y--){
+ rect = (uchar *) (ibuf->rect + y * ibuf->x);
+ buffer = row_pointer[0];
+
+ switch(cinfo->in_color_space){
+ case JCS_RGB:
+ for (x = 0; x < ibuf->x; x++) {
+ *buffer++ = rect[0];
+ *buffer++ = rect[1];
+ *buffer++ = rect[2];
+ rect += 4;
+ }
+ break;
+ case JCS_GRAYSCALE:
+ for (x = 0; x < ibuf->x; x++) {
+ *buffer++ = rect[0];
+ rect += 4;
+ }
+ break;
+ case JCS_UNKNOWN:
+ memcpy(buffer, rect, 4 * ibuf->x);
+ break;
+ /* default was missing... intentional ? */
+ default:
+ ; /* do nothing */
+ }
+
+ jpeg_write_scanlines(cinfo, row_pointer, 1);
+
+ if (jpeg_failed) break;
+ }
+
+ if (jpeg_failed == FALSE) jpeg_finish_compress(cinfo);
+ free(row_pointer[0]);
+}
+
+
+static int init_jpeg(FILE * outfile, struct jpeg_compress_struct * cinfo, struct ImBuf *ibuf)
+{
+ int quality;
+
+ quality = ibuf->ftype & 0xff;
+ if (quality <= 0) quality = jpeg_default_quality;
+ if (quality > 100) quality = 100;
+
+ jpeg_create_compress(cinfo);
+ jpeg_stdio_dest(cinfo, outfile);
+
+ cinfo->image_width = ibuf->x;
+ cinfo->image_height = ibuf->y;
+
+ cinfo->in_color_space = JCS_RGB;
+ if (ibuf->depth == 8 && ibuf->cmap == 0) cinfo->in_color_space = JCS_GRAYSCALE;
+ if (ibuf->depth == 32) cinfo->in_color_space = JCS_UNKNOWN;
+
+ switch(cinfo->in_color_space){
+ case JCS_RGB:
+ cinfo->input_components = 3;
+ break;
+ case JCS_GRAYSCALE:
+ cinfo->input_components = 1;
+ break;
+ case JCS_UNKNOWN:
+ cinfo->input_components = 4;
+ break;
+ /* default was missing... intentional ? */
+ default:
+ ; /* do nothing */
+ }
+ jpeg_set_defaults(cinfo);
+
+ /* own settings */
+
+ cinfo->dct_method = JDCT_FLOAT;
+ jpeg_set_quality(cinfo, quality, TRUE);
+
+ return(0);
+}
+
+
+static int save_stdjpeg(char * name, struct ImBuf * ibuf)
+{
+ FILE * outfile;
+ struct jpeg_compress_struct _cinfo, *cinfo = &_cinfo;
+ struct jpeg_error_mgr jerr;
+
+ if ((outfile = fopen(name, "wb")) == NULL) return 0;
+ jpeg_default_quality = 75;
+
+ cinfo->err = jpeg_std_error(&jerr);
+ jerr.error_exit = jpeg_error;
+
+ init_jpeg(outfile, cinfo, ibuf);
+
+ write_jpeg(cinfo, ibuf);
+
+ fclose(outfile);
+ jpeg_destroy_compress(cinfo);
+
+ if (jpeg_failed) {
+ remove(name);
+ return 0;
+ }
+ return 1;
+}
+
+
+static int save_vidjpeg(char * name, struct ImBuf * ibuf)
+{
+ FILE * outfile;
+ struct jpeg_compress_struct _cinfo, *cinfo = &_cinfo;
+ struct jpeg_error_mgr jerr;
+
+ if ((outfile = fopen(name, "wb")) == NULL) return 0;
+ jpeg_default_quality = 90;
+
+ cinfo->err = jpeg_std_error(&jerr);
+ jerr.error_exit = jpeg_error;
+
+ init_jpeg(outfile, cinfo, ibuf);
+
+ /* adjust scaling factors */
+ if (cinfo->in_color_space == JCS_RGB) {
+ cinfo->comp_info[0].h_samp_factor = 2;
+ cinfo->comp_info[0].v_samp_factor = 1;
+ }
+
+ write_jpeg(cinfo, ibuf);
+
+ fclose(outfile);
+ jpeg_destroy_compress(cinfo);
+
+ if (jpeg_failed) {
+ remove(name);
+ return 0;
+ }
+ return 1;
+}
+
+static int save_jstjpeg(char * name, struct ImBuf * ibuf)
+{
+ char fieldname[1024];
+ struct ImBuf * tbuf;
+ int oldy, returnval;
+
+ tbuf = IMB_allocImBuf(ibuf->x, ibuf->y / 2, 24, IB_rect, 0);
+ tbuf->ftype = ibuf->ftype;
+ tbuf->flags = ibuf->flags;
+
+ oldy = ibuf->y;
+ ibuf->x *= 2;
+ ibuf->y /= 2;
+
+ IMB_rectcpy(tbuf, ibuf, 0, 0, 0, 0, ibuf->x, ibuf->y);
+ sprintf(fieldname, "%s.jf0", name);
+
+ returnval = save_vidjpeg(fieldname, tbuf) ;
+ if (returnval == 1) {
+ IMB_rectcpy(tbuf, ibuf, 0, 0, tbuf->x, 0, ibuf->x, ibuf->y);
+ sprintf(fieldname, "%s.jf1", name);
+ returnval = save_vidjpeg(fieldname, tbuf);
+ }
+
+ ibuf->y = oldy;
+ ibuf->x /= 2;
+ IMB_freeImBuf(tbuf);
+
+ return returnval;
+}
+
+static int save_maxjpeg(char * name, struct ImBuf * ibuf)
+{
+ FILE * outfile;
+ struct jpeg_compress_struct _cinfo, *cinfo = &_cinfo;
+ struct jpeg_error_mgr jerr;
+
+ if ((outfile = fopen(name, "wb")) == NULL) return 0;
+ jpeg_default_quality = 100;
+
+ cinfo->err = jpeg_std_error(&jerr);
+ jerr.error_exit = jpeg_error;
+
+ init_jpeg(outfile, cinfo, ibuf);
+
+ /* adjust scaling factors */
+ if (cinfo->in_color_space == JCS_RGB) {
+ cinfo->comp_info[0].h_samp_factor = 1;
+ cinfo->comp_info[0].v_samp_factor = 1;
+ }
+
+ write_jpeg(cinfo, ibuf);
+
+ fclose(outfile);
+ jpeg_destroy_compress(cinfo);
+
+ if (jpeg_failed) {
+ remove(name);
+ return 0;
+ }
+ return 1;
+}
+
+int imb_savejpeg(struct ImBuf * ibuf, char * name, int flags)
+{
+
+ ibuf->flags = flags;
+ if (IS_stdjpg(ibuf)) return save_stdjpeg(name, ibuf);
+ if (IS_jstjpg(ibuf)) return save_jstjpeg(name, ibuf);
+ if (IS_maxjpg(ibuf)) return save_maxjpeg(name, ibuf);
+ return save_vidjpeg(name, ibuf);
+}
+
diff --git a/source/blender/imbuf/intern/matrix.h b/source/blender/imbuf/intern/matrix.h
new file mode 100644
index 00000000000..e062ee38f8f
--- /dev/null
+++ b/source/blender/imbuf/intern/matrix.h
@@ -0,0 +1,87 @@
+/**
+ * matrix.c
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/* rgbyuv is identiek aan rgbbeta */
+
+float rgbyuv[4][4]={ /* afgeleid uit videoframer = Y Cr Cb in kopieen van Francois*/
+ /* is identriek aan matrix van jpeg */
+ { .50000, .11400, -.08131, 0.0,}, /* b */
+ {-.33126, .58700, -.41869, 0.0,}, /* g */
+ {-.16874, .29900, .50000, 0.0,}, /* r */
+ { 128.0, 0.0, 128.0, 1.0}};
+
+ /* b-y (u) y r-y (v) */
+
+
+float rgbbeta[4][4]={ /* afgeleid uit videoframer = Y Cr Cb in kopieen van Francois*/
+ /* is identriek aan matrix van jpeg */
+ {.50000, .11400, -.08131, 0.0,}, /* b-y -> b */
+ {-.33126, .58700, -.41869, 0.0,}, /* y -> g */
+ {-.16874, .29900, .50000, 0.0,}, /* r-y -> r */
+ { 128.0, 0.0, 128.0, 1.0}};
+
+ /* b-y y r-y */
+
+
+
+float yuvrgb[4][4]={
+ {1.77200, -0.34414, 0.0, 0.0, },
+ {1.0, 1.0, 1.0, 0.0, },
+ {0.0, -0.71414, 1.40200, 0.0, },
+ {-226.816, 135.460, -179.456, 1.0}};
+
+float rgb_to_bw[4][4]={
+ {.299, .299, .299, 0.0,},
+ {.587, .587, .587, 0.0,},
+ {.114, .114, .114, 0.0,},
+ { 0.5, 0.5, 0.5, 1.0}};
+
+float dyuvrgb_oud[4][4]={
+ {1.0 , 1.0 , 1.0, 0.0,},
+ {1.733, -0.337, 0.0, 0.0,},
+ {0.0, -.698, 1.371, 0.0,},
+ {-221.8, 132.47, -175.5, 1.0}};
+
+float dyuvrgb[4][4]={
+ {1.164 , 1.164 , 1.164, 0.0,},
+ {2.018, -0.391, 0.0, 0.0,},
+ {0.0, -0.813, 1.596, 0.0,},
+ {-276.7, 135.6, -222.7, 1.0}};
+
+float rgbdyuv[4][4]={
+ {0.439, 0.098, -0.071, 0.0,},
+ {-0.291, 0.504, -0.368, 0.0,},
+ {-0.148, 0.257, 0.439, 0.0,},
+ {128.0, 16.0, 128.0, 1.0}};
+
diff --git a/source/blender/imbuf/intern/md5.c b/source/blender/imbuf/intern/md5.c
new file mode 100644
index 00000000000..a3165467b53
--- /dev/null
+++ b/source/blender/imbuf/intern/md5.c
@@ -0,0 +1,361 @@
+/* md5.c - Functions to compute MD5 message digest of files or memory blocks
+ according to the definition of MD5 in RFC 1321 from April 1992.
+ Copyright (C) 1995 Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+
+# include <stdlib.h>
+# include <string.h>
+
+#include "md5.h"
+
+#ifdef WORDS_BIGENDIAN
+# define SWAP(n) \
+ (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24))
+#else
+# define SWAP(n) (n)
+#endif
+
+
+/* This array contains the bytes used to pad the buffer to the next
+ 64-byte boundary. (RFC 1321, 3.1: Step 1) */
+static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ };
+
+
+/* Initialize structure containing state of computation.
+ (RFC 1321, 3.3: Step 3) */
+void
+md5_init_ctx (ctx)
+ struct md5_ctx *ctx;
+{
+ ctx->A = 0x67452301;
+ ctx->B = 0xefcdab89;
+ ctx->C = 0x98badcfe;
+ ctx->D = 0x10325476;
+}
+
+/* Put result from CTX in first 16 bytes following RESBUF. The result must
+ be in little endian byte order. */
+void *
+md5_read_ctx (ctx, resbuf)
+ const struct md5_ctx *ctx;
+ void *resbuf;
+{
+ ((md5_uint32 *) resbuf)[0] = SWAP (ctx->A);
+ ((md5_uint32 *) resbuf)[1] = SWAP (ctx->B);
+ ((md5_uint32 *) resbuf)[2] = SWAP (ctx->C);
+ ((md5_uint32 *) resbuf)[3] = SWAP (ctx->D);
+
+ return resbuf;
+}
+
+/* Compute MD5 message digest for bytes read from STREAM. The
+ resulting message digest number will be written into the 16 bytes
+ beginning at RESBLOCK. */
+int
+md5_stream (stream, resblock)
+ FILE *stream;
+ void *resblock;
+{
+ /* Important: BLOCKSIZE must be a multiple of 64. */
+#define BLOCKSIZE 4096
+ struct md5_ctx ctx;
+ md5_uint32 len[2];
+ char buffer[BLOCKSIZE + 72];
+ size_t pad, sum;
+
+ /* Initialize the computation context. */
+ md5_init_ctx (&ctx);
+
+ len[0] = 0;
+ len[1] = 0;
+
+ /* Iterate over full file contents. */
+ while (1)
+ {
+ /* We read the file in blocks of BLOCKSIZE bytes. One call of the
+ computation function processes the whole buffer so that with the
+ next round of the loop another block can be read. */
+ size_t n;
+ sum = 0;
+
+ /* Read block. Take care for partial reads. */
+ do
+ {
+ n = fread (buffer, 1, BLOCKSIZE - sum, stream);
+
+ sum += n;
+ }
+ while (sum < BLOCKSIZE && n != 0);
+ if (n == 0 && ferror (stream))
+ return 1;
+
+ /* RFC 1321 specifies the possible length of the file up to 2^64 bits.
+ Here we only compute the number of bytes. Do a double word
+ increment. */
+ len[0] += sum;
+ if (len[0] < sum)
+ ++len[1];
+
+ /* If end of file is reached, end the loop. */
+ if (n == 0)
+ break;
+
+ /* Process buffer with BLOCKSIZE bytes. Note that
+ BLOCKSIZE % 64 == 0
+ */
+ md5_process_block (buffer, BLOCKSIZE, &ctx);
+ }
+
+ /* We can copy 64 byte because the buffer is always big enough. FILLBUF
+ contains the needed bits. */
+ memcpy (&buffer[sum], fillbuf, 64);
+
+ /* Compute amount of padding bytes needed. Alignment is done to
+ (N + PAD) % 64 == 56
+ There is always at least one byte padded. I.e. even the alignment
+ is correctly aligned 64 padding bytes are added. */
+ pad = sum & 63;
+ pad = pad >= 56 ? 64 + 56 - pad : 56 - pad;
+
+ /* Put the 64-bit file length in *bits* at the end of the buffer. */
+ *(md5_uint32 *) &buffer[sum + pad] = SWAP (len[0] << 3);
+ *(md5_uint32 *) &buffer[sum + pad + 4] = SWAP ((len[1] << 3)
+ | (len[0] >> 29));
+
+ /* Process last bytes. */
+ md5_process_block (buffer, sum + pad + 8, &ctx);
+
+ /* Construct result in desired memory. */
+ md5_read_ctx (&ctx, resblock);
+ return 0;
+}
+
+/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
+ result is always in little endian byte order, so that a byte-wise
+ output yields to the wanted ASCII representation of the message
+ digest. */
+void *
+md5_buffer (buffer, len, resblock)
+ const char *buffer;
+ size_t len;
+ void *resblock;
+{
+ struct md5_ctx ctx;
+ char restbuf[64 + 72];
+ size_t blocks = len & ~63;
+ size_t pad, rest;
+
+ /* Initialize the computation context. */
+ md5_init_ctx (&ctx);
+
+ /* Process whole buffer but last len % 64 bytes. */
+ md5_process_block (buffer, blocks, &ctx);
+
+ /* REST bytes are not processed yet. */
+ rest = len - blocks;
+ /* Copy to own buffer. */
+ memcpy (restbuf, &buffer[blocks], rest);
+ /* Append needed fill bytes at end of buffer. We can copy 64 byte
+ because the buffer is always big enough. */
+ memcpy (&restbuf[rest], fillbuf, 64);
+
+ /* PAD bytes are used for padding to correct alignment. Note that
+ always at least one byte is padded. */
+ pad = rest >= 56 ? 64 + 56 - rest : 56 - rest;
+
+ /* Put length of buffer in *bits* in last eight bytes. */
+ *(md5_uint32 *) &restbuf[rest + pad] = (md5_uint32) SWAP (len << 3);
+ *(md5_uint32 *) &restbuf[rest + pad + 4] = (md5_uint32) SWAP (len >> 29);
+
+ /* Process last bytes. */
+ md5_process_block (restbuf, rest + pad + 8, &ctx);
+
+ /* Put result in desired memory area. */
+ return md5_read_ctx (&ctx, resblock);
+}
+
+
+/* These are the four functions used in the four steps of the MD5 algorithm
+ and defined in the RFC 1321. The first function is a little bit optimized
+ (as found in Colin Plumbs public domain implementation). */
+/* #define FF(b, c, d) ((b & c) | (~b & d)) */
+#define FF(b, c, d) (d ^ (b & (c ^ d)))
+#define FG(b, c, d) FF (d, b, c)
+#define FH(b, c, d) (b ^ c ^ d)
+#define FI(b, c, d) (c ^ (b | ~d))
+
+/* Process LEN bytes of BUFFER, accumulating context into CTX.
+ It is assumed that LEN % 64 == 0. */
+
+void
+md5_process_block (buffer, len, ctx)
+ const void *buffer;
+ size_t len;
+ struct md5_ctx *ctx;
+{
+ md5_uint32 correct_words[16];
+ const md5_uint32 *words = buffer;
+ size_t nwords = len / sizeof (md5_uint32);
+ const md5_uint32 *endp = words + nwords;
+ md5_uint32 A = ctx->A;
+ md5_uint32 B = ctx->B;
+ md5_uint32 C = ctx->C;
+ md5_uint32 D = ctx->D;
+
+ /* Process all bytes in the buffer with 64 bytes in each round of
+ the loop. */
+ while (words < endp)
+ {
+ md5_uint32 *cwp = correct_words;
+ md5_uint32 A_save = A;
+ md5_uint32 B_save = B;
+ md5_uint32 C_save = C;
+ md5_uint32 D_save = D;
+
+ /* First round: using the given function, the context and a constant
+ the next context is computed. Because the algorithms processing
+ unit is a 32-bit word and it is determined to work on words in
+ little endian byte order we perhaps have to change the byte order
+ before the computation. To reduce the work for the next steps
+ we store the swapped words in the array CORRECT_WORDS. */
+
+#define OP(a, b, c, d, s, T) \
+ do \
+ { \
+ a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T; \
+ ++words; \
+ CYCLIC (a, s); \
+ a += b; \
+ } \
+ while (0)
+
+ /* It is unfortunate that C does not provide an operator for
+ cyclic rotation. Hope the C compiler is smart enough. */
+#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
+
+ /* Before we start, one word to the strange constants.
+ They are defined in RFC 1321 as
+
+ T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
+ */
+
+ /* Round 1. */
+ OP (A, B, C, D, 7, 0xd76aa478);
+ OP (D, A, B, C, 12, 0xe8c7b756);
+ OP (C, D, A, B, 17, 0x242070db);
+ OP (B, C, D, A, 22, 0xc1bdceee);
+ OP (A, B, C, D, 7, 0xf57c0faf);
+ OP (D, A, B, C, 12, 0x4787c62a);
+ OP (C, D, A, B, 17, 0xa8304613);
+ OP (B, C, D, A, 22, 0xfd469501);
+ OP (A, B, C, D, 7, 0x698098d8);
+ OP (D, A, B, C, 12, 0x8b44f7af);
+ OP (C, D, A, B, 17, 0xffff5bb1);
+ OP (B, C, D, A, 22, 0x895cd7be);
+ OP (A, B, C, D, 7, 0x6b901122);
+ OP (D, A, B, C, 12, 0xfd987193);
+ OP (C, D, A, B, 17, 0xa679438e);
+ OP (B, C, D, A, 22, 0x49b40821);
+
+ /* For the second to fourth round we have the possibly swapped words
+ in CORRECT_WORDS. Redefine the macro to take an additional first
+ argument specifying the function to use. */
+#undef OP
+#define OP(f, a, b, c, d, k, s, T) \
+ do \
+ { \
+ a += f (b, c, d) + correct_words[k] + T; \
+ CYCLIC (a, s); \
+ a += b; \
+ } \
+ while (0)
+
+ /* Round 2. */
+ OP (FG, A, B, C, D, 1, 5, 0xf61e2562);
+ OP (FG, D, A, B, C, 6, 9, 0xc040b340);
+ OP (FG, C, D, A, B, 11, 14, 0x265e5a51);
+ OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa);
+ OP (FG, A, B, C, D, 5, 5, 0xd62f105d);
+ OP (FG, D, A, B, C, 10, 9, 0x02441453);
+ OP (FG, C, D, A, B, 15, 14, 0xd8a1e681);
+ OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8);
+ OP (FG, A, B, C, D, 9, 5, 0x21e1cde6);
+ OP (FG, D, A, B, C, 14, 9, 0xc33707d6);
+ OP (FG, C, D, A, B, 3, 14, 0xf4d50d87);
+ OP (FG, B, C, D, A, 8, 20, 0x455a14ed);
+ OP (FG, A, B, C, D, 13, 5, 0xa9e3e905);
+ OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8);
+ OP (FG, C, D, A, B, 7, 14, 0x676f02d9);
+ OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
+
+ /* Round 3. */
+ OP (FH, A, B, C, D, 5, 4, 0xfffa3942);
+ OP (FH, D, A, B, C, 8, 11, 0x8771f681);
+ OP (FH, C, D, A, B, 11, 16, 0x6d9d6122);
+ OP (FH, B, C, D, A, 14, 23, 0xfde5380c);
+ OP (FH, A, B, C, D, 1, 4, 0xa4beea44);
+ OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9);
+ OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60);
+ OP (FH, B, C, D, A, 10, 23, 0xbebfbc70);
+ OP (FH, A, B, C, D, 13, 4, 0x289b7ec6);
+ OP (FH, D, A, B, C, 0, 11, 0xeaa127fa);
+ OP (FH, C, D, A, B, 3, 16, 0xd4ef3085);
+ OP (FH, B, C, D, A, 6, 23, 0x04881d05);
+ OP (FH, A, B, C, D, 9, 4, 0xd9d4d039);
+ OP (FH, D, A, B, C, 12, 11, 0xe6db99e5);
+ OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8);
+ OP (FH, B, C, D, A, 2, 23, 0xc4ac5665);
+
+ /* Round 4. */
+ OP (FI, A, B, C, D, 0, 6, 0xf4292244);
+ OP (FI, D, A, B, C, 7, 10, 0x432aff97);
+ OP (FI, C, D, A, B, 14, 15, 0xab9423a7);
+ OP (FI, B, C, D, A, 5, 21, 0xfc93a039);
+ OP (FI, A, B, C, D, 12, 6, 0x655b59c3);
+ OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92);
+ OP (FI, C, D, A, B, 10, 15, 0xffeff47d);
+ OP (FI, B, C, D, A, 1, 21, 0x85845dd1);
+ OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f);
+ OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
+ OP (FI, C, D, A, B, 6, 15, 0xa3014314);
+ OP (FI, B, C, D, A, 13, 21, 0x4e0811a1);
+ OP (FI, A, B, C, D, 4, 6, 0xf7537e82);
+ OP (FI, D, A, B, C, 11, 10, 0xbd3af235);
+ OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb);
+ OP (FI, B, C, D, A, 9, 21, 0xeb86d391);
+
+ /* Add the starting values of the context. */
+ A += A_save;
+ B += B_save;
+ C += C_save;
+ D += D_save;
+ }
+
+ /* Put checksum in context given as argument. */
+ ctx->A = A;
+ ctx->B = B;
+ ctx->C = C;
+ ctx->D = D;
+}
+
diff --git a/source/blender/imbuf/intern/md5.h b/source/blender/imbuf/intern/md5.h
new file mode 100644
index 00000000000..8b0d946430e
--- /dev/null
+++ b/source/blender/imbuf/intern/md5.h
@@ -0,0 +1,116 @@
+/* md5.h - Declaration of functions and data types used for MD5 sum
+ computing library functions.
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef _MD5_H
+#define _MD5_H
+
+#include <stdio.h>
+
+#if defined HAVE_LIMITS_H || _LIBC
+# include <limits.h>
+#endif
+
+/* The following contortions are an attempt to use the C preprocessor
+ to determine an unsigned integral type that is 32 bits wide. An
+ alternative approach is to use autoconf's AC_CHECK_SIZEOF macro, but
+ doing that would require that the configure script compile and *run*
+ the resulting executable. Locally running cross-compiled executables
+ is usually not possible. */
+
+#if defined __STDC__ && __STDC__
+# define UINT_MAX_32_BITS 4294967295U
+#else
+# define UINT_MAX_32_BITS 0xFFFFFFFF
+#endif
+
+/* If UINT_MAX isn't defined, assume it's a 32-bit type.
+ This should be valid for all systems GNU cares about because
+ that doesn't include 16-bit systems, and only modern systems
+ (that certainly have <limits.h>) have 64+-bit integral types. */
+
+#ifndef UINT_MAX
+# define UINT_MAX UINT_MAX_32_BITS
+#endif
+
+#if UINT_MAX == UINT_MAX_32_BITS
+ typedef unsigned int md5_uint32;
+#else
+# if USHRT_MAX == UINT_MAX_32_BITS
+ typedef unsigned short md5_uint32;
+# else
+# if ULONG_MAX == UINT_MAX_32_BITS
+ typedef unsigned long md5_uint32;
+# else
+ /* The following line is intended to evoke an error.
+ Using #error is not portable enough. */
+ "Cannot determine unsigned 32-bit data type."
+# endif
+# endif
+#endif
+
+#undef __P
+#if defined (__STDC__) && __STDC__
+#define __P(x) x
+#else
+#define __P(x) ()
+#endif
+
+/* Structure to save state of computation between the single steps. */
+struct md5_ctx
+{
+ md5_uint32 A;
+ md5_uint32 B;
+ md5_uint32 C;
+ md5_uint32 D;
+};
+
+/*
+ * The following three functions are build up the low level used in
+ * the functions `md5_stream' and `md5_buffer'.
+ */
+
+/* Initialize structure containing state of computation.
+ (RFC 1321, 3.3: Step 3) */
+void md5_init_ctx __P ((struct md5_ctx *ctx));
+
+/* Starting with the result of former calls of this function (or the
+ initialzation function update the context for the next LEN bytes
+ starting at BUFFER.
+ It is necessary that LEN is a multiple of 64!!! */
+void md5_process_block __P ((const void *buffer, size_t len,
+ struct md5_ctx *ctx));
+
+/* Put result from CTX in first 16 bytes following RESBUF. The result is
+ always in little endian byte order, so that a byte-wise output yields
+ to the wanted ASCII representation of the message digest. */
+void *md5_read_ctx __P ((const struct md5_ctx *ctx, void *resbuf));
+
+
+/* Compute MD5 message digest for bytes read from STREAM. The
+ resulting message digest number will be written into the 16 bytes
+ beginning at RESBLOCK. */
+int md5_stream __P ((FILE *stream, void *resblock));
+
+/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
+ result is always in little endian byte order, so that a byte-wise
+ output yields to the wanted ASCII representation of the message
+ digest. */
+void *md5_buffer __P ((const char *buffer, size_t len, void *resblock));
+
+#endif
+
diff --git a/source/blender/imbuf/intern/openexr/CMakeLists.txt b/source/blender/imbuf/intern/openexr/CMakeLists.txt
new file mode 100644
index 00000000000..cfe5b28b7e8
--- /dev/null
+++ b/source/blender/imbuf/intern/openexr/CMakeLists.txt
@@ -0,0 +1,45 @@
+# $Id$
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2006, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Jacques Beaurain.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+
+SET(SRC openexr_api.cpp)
+
+SET(INC
+ .
+ ../../../blenkernel
+ ../../
+ ..
+ ../../../blenlib
+ intern/include
+ ../../../../../intern/guardedalloc
+ ../../../makesdna
+ ${OPENEXR_INC}
+)
+
+BLENDERLIB(bf_openexr "${SRC}" "${INC}")
+#env.BlenderLib ('bf_openexr', source_files, incs, defs, libtype=['core','player'], priority = [90, 200])
diff --git a/source/blender/imbuf/intern/openexr/Makefile b/source/blender/imbuf/intern/openexr/Makefile
new file mode 100644
index 00000000000..a3b79c951dd
--- /dev/null
+++ b/source/blender/imbuf/intern/openexr/Makefile
@@ -0,0 +1,48 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Gernot Ziegler <gz@lysator.liu.se>
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+#
+
+LIBNAME = openexr
+DIR = $(OCGDIR)/blender/imbuf/openexr
+
+include nan_compile.mk
+
+CFLAGS += $(LEVEL_1_C_WARNINGS)
+
+CPPFLAGS += -I../../../makesdna
+CPPFLAGS += -I../../../blenkernel
+CPPFLAGS += -I../../../blenlib
+CPPFLAGS += -I../../../imbuf
+CPPFLAGS += -I../../../imbuf/intern
+CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
+CPPFLAGS += $(NAN_OPENEXR_INC)
+CPPFLAGS += -I.
diff --git a/source/blender/imbuf/intern/openexr/SConscript b/source/blender/imbuf/intern/openexr/SConscript
new file mode 100644
index 00000000000..1b0a0ed6110
--- /dev/null
+++ b/source/blender/imbuf/intern/openexr/SConscript
@@ -0,0 +1,18 @@
+#!/usr/bin/python
+Import ('env')
+
+source_files = ['openexr_api.cpp']
+
+incs = ['.',
+ '../../../blenkernel',
+ '../../',
+ '..',
+ '../../../blenlib',
+ 'intern/include',
+ '#/intern/guardedalloc',
+ '../../../makesdna']
+incs += Split(env['BF_OPENEXR_INC'])
+
+defs = []
+
+env.BlenderLib ('bf_openexr', source_files, incs, defs, libtype=['core','player'], priority = [90, 200])
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp
new file mode 100644
index 00000000000..3cbada812b9
--- /dev/null
+++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp
@@ -0,0 +1,967 @@
+/**
+*
+ * ***** BEGIN GPLLICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright by Gernot Ziegler <gz@lysator.liu.se>.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Austin Benesh, Ton Roosendaal (float, half, speedup, cleanup...).
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string>
+
+
+#include <openexr_api.h>
+
+extern "C"
+{
+
+// The following prevents a linking error in debug mode for MSVC using the libs in CVS
+#if defined(WITH_OPENEXR) && defined(_WIN32) && defined(_DEBUG) && !defined(__MINGW32__) && !defined(__CYGWIN__)
+_CRTIMP void __cdecl _invalid_parameter_noinfo(void)
+{
+}
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+#include "IMB_allocimbuf.h"
+
+#define WITH_OPENEXR
+#include "openexr_multi.h"
+}
+
+#include <iostream>
+
+#if defined (_WIN32) && !defined(FREE_WINDOWS)
+#include <half.h>
+#include <IlmImf/ImfVersion.h>
+#include <IlmImf/ImfArray.h>
+#include <IlmImf/ImfIO.h>
+#include <IlmImf/ImfChannelList.h>
+#include <IlmImf/ImfPixelType.h>
+#include <IlmImf/ImfInputFile.h>
+#include <IlmImf/ImfOutputFile.h>
+#include <IlmImf/ImfCompression.h>
+#include <IlmImf/ImfCompressionAttribute.h>
+#include <IlmImf/ImfStringAttribute.h>
+#include <Imath/ImathBox.h>
+#else
+#include <OpenEXR/half.h>
+#include <OpenEXR/ImfVersion.h>
+#include <OpenEXR/ImathBox.h>
+#include <OpenEXR/ImfArray.h>
+#include <OpenEXR/ImfIO.h>
+#include <OpenEXR/ImfChannelList.h>
+#include <OpenEXR/ImfPixelType.h>
+#include <OpenEXR/ImfInputFile.h>
+#include <OpenEXR/ImfOutputFile.h>
+#include <OpenEXR/ImfCompression.h>
+#include <OpenEXR/ImfCompressionAttribute.h>
+#include <OpenEXR/ImfStringAttribute.h>
+#endif
+
+using namespace Imf;
+using namespace Imath;
+
+class Mem_IStream: public IStream
+{
+public:
+
+ Mem_IStream (unsigned char *exrbuf, int exrsize):
+ IStream("dummy"), _exrpos (0), _exrsize(exrsize) { _exrbuf = exrbuf; }
+
+ virtual bool read (char c[], int n);
+ virtual Int64 tellg ();
+ virtual void seekg (Int64 pos);
+ virtual void clear ();
+ //virtual ~Mem_IStream() {}; // unused
+
+private:
+
+ Int64 _exrpos;
+ Int64 _exrsize;
+ unsigned char *_exrbuf;
+};
+
+bool Mem_IStream::read (char c[], int n)
+{
+ if (n + _exrpos <= _exrsize)
+ {
+ memcpy(c, (void *)(&_exrbuf[_exrpos]), n);
+ _exrpos += n;
+ return true;
+ }
+ else
+ return false;
+}
+
+Int64 Mem_IStream::tellg ()
+{
+ return _exrpos;
+}
+
+void Mem_IStream::seekg (Int64 pos)
+{
+ _exrpos = pos;
+}
+
+void Mem_IStream::clear ()
+{
+}
+
+struct _RGBAZ
+{
+ half r;
+ half g;
+ half b;
+ half a;
+ half z;
+};
+
+typedef struct _RGBAZ RGBAZ;
+
+extern "C"
+{
+
+int imb_is_a_openexr(unsigned char *mem)
+{
+ return Imf::isImfMagic ((const char *)mem);
+}
+
+static void openexr_header_compression(Header *header, int compression)
+{
+ switch(compression)
+ {
+ case 0:
+ header->compression() = NO_COMPRESSION;
+ break;
+ case 1:
+ header->compression() = PXR24_COMPRESSION;
+ break;
+ case 2:
+ header->compression() = ZIP_COMPRESSION;
+ break;
+ case 3:
+ header->compression() = PIZ_COMPRESSION;
+ break;
+ case 4:
+ header->compression() = RLE_COMPRESSION;
+ break;
+ default:
+ header->compression() = ZIP_COMPRESSION;
+ break;
+ }
+}
+
+static short imb_save_openexr_half(struct ImBuf *ibuf, char *name, int flags)
+{
+
+ int width = ibuf->x;
+ int height = ibuf->y;
+ int write_zbuf = (flags & IB_zbuffloat) && ibuf->zbuf_float != NULL; // summarize
+
+ try
+ {
+ Header header (width, height);
+
+ openexr_header_compression(&header, ibuf->ftype & OPENEXR_COMPRESS);
+
+ header.channels().insert ("R", Channel (HALF));
+ header.channels().insert ("G", Channel (HALF));
+ header.channels().insert ("B", Channel (HALF));
+ if (ibuf->depth==32)
+ header.channels().insert ("A", Channel (HALF));
+ if (write_zbuf) // z we do as float always
+ header.channels().insert ("Z", Channel (FLOAT));
+
+ FrameBuffer frameBuffer;
+ OutputFile *file = new OutputFile(name, header);
+
+ /* we store first everything in half array */
+ RGBAZ *pixels = new RGBAZ[height * width];
+ RGBAZ *to = pixels;
+ int xstride= sizeof (RGBAZ);
+ int ystride= xstride*width;
+
+ /* indicate used buffers */
+ frameBuffer.insert ("R", Slice (HALF, (char *) &pixels[0].r, xstride, ystride));
+ frameBuffer.insert ("G", Slice (HALF, (char *) &pixels[0].g, xstride, ystride));
+ frameBuffer.insert ("B", Slice (HALF, (char *) &pixels[0].b, xstride, ystride));
+ if (ibuf->depth==32)
+ frameBuffer.insert ("A", Slice (HALF, (char *) &pixels[0].a, xstride, ystride));
+ if (write_zbuf)
+ frameBuffer.insert ("Z", Slice (FLOAT, (char *) ibuf->zbuf_float + 4*(height-1)*width,
+ sizeof(float), sizeof(float) * -width));
+ if(ibuf->rect_float) {
+ float *from;
+
+ for (int i = ibuf->y-1; i >= 0; i--)
+ {
+ from= ibuf->rect_float + 4*i*width;
+
+ for (int j = ibuf->x; j > 0; j--)
+ {
+ to->r = from[0];
+ to->g = from[1];
+ to->b = from[2];
+ to->a = from[3];
+ to++; from += 4;
+ }
+ }
+ }
+ else {
+ unsigned char *from;
+
+ for (int i = ibuf->y-1; i >= 0; i--)
+ {
+ from= (unsigned char *)(ibuf->rect + i*width);
+
+ for (int j = ibuf->x; j > 0; j--)
+ {
+ to->r = (float)(from[0])/255.0;
+ to->g = (float)(from[1])/255.0;
+ to->b = (float)(from[2])/255.0;
+ to->a = (float)(from[3])/255.0;
+ to++; from += 4;
+ }
+ }
+ }
+
+// printf("OpenEXR-save: Writing OpenEXR file of height %d.\n", height);
+
+ file->setFrameBuffer (frameBuffer);
+ file->writePixels (height);
+ delete file;
+ delete [] pixels;
+ }
+ catch (const std::exception &exc)
+ {
+ printf("OpenEXR-save: ERROR: %s\n", exc.what());
+ if (ibuf) IMB_freeImBuf(ibuf);
+
+ return (0);
+ }
+
+ return (1);
+}
+
+static short imb_save_openexr_float(struct ImBuf *ibuf, char *name, int flags)
+{
+
+ int width = ibuf->x;
+ int height = ibuf->y;
+ int write_zbuf = (flags & IB_zbuffloat) && ibuf->zbuf_float != NULL; // summarize
+
+ try
+ {
+ Header header (width, height);
+
+ openexr_header_compression(&header, ibuf->ftype & OPENEXR_COMPRESS);
+
+ header.channels().insert ("R", Channel (FLOAT));
+ header.channels().insert ("G", Channel (FLOAT));
+ header.channels().insert ("B", Channel (FLOAT));
+ if (ibuf->depth==32)
+ header.channels().insert ("A", Channel (FLOAT));
+ if (write_zbuf)
+ header.channels().insert ("Z", Channel (FLOAT));
+
+ FrameBuffer frameBuffer;
+ OutputFile *file = new OutputFile(name, header);
+ float *first= ibuf->rect_float + 4*(height-1)*width;
+ int xstride = sizeof(float) * 4;
+ int ystride = - xstride*width;
+
+ frameBuffer.insert ("R", Slice (FLOAT, (char *) first, xstride, ystride));
+ frameBuffer.insert ("G", Slice (FLOAT, (char *) (first+1), xstride, ystride));
+ frameBuffer.insert ("B", Slice (FLOAT, (char *) (first+2), xstride, ystride));
+ if (ibuf->depth==32)
+ frameBuffer.insert ("A", Slice (FLOAT, (char *) (first+3), xstride, ystride));
+ if (write_zbuf)
+ frameBuffer.insert ("Z", Slice (FLOAT, (char *) ibuf->zbuf_float + 4*(height-1)*width,
+ sizeof(float), sizeof(float) * -width));
+ file->setFrameBuffer (frameBuffer);
+ file->writePixels (height);
+ delete file;
+ }
+ catch (const std::exception &exc)
+ {
+ printf("OpenEXR-save: ERROR: %s\n", exc.what());
+ if (ibuf) IMB_freeImBuf(ibuf);
+
+ return (0);
+ }
+
+ return (1);
+ // printf("OpenEXR-save: Done.\n");
+}
+
+
+short imb_save_openexr(struct ImBuf *ibuf, char *name, int flags)
+{
+ if (flags & IB_mem)
+ {
+ printf("OpenEXR-save: Create EXR in memory CURRENTLY NOT SUPPORTED !\n");
+ imb_addencodedbufferImBuf(ibuf);
+ ibuf->encodedsize = 0;
+ return(0);
+ }
+
+ if (ibuf->ftype & OPENEXR_HALF)
+ return imb_save_openexr_half(ibuf, name, flags);
+ else {
+ /* when no float rect, we save as half (16 bits is sufficient) */
+ if (ibuf->rect_float==NULL)
+ return imb_save_openexr_half(ibuf, name, flags);
+ else
+ return imb_save_openexr_float(ibuf, name, flags);
+ }
+}
+
+/* ********************* Nicer API, MultiLayer and with Tile file support ************************************ */
+
+/* naming rules:
+ - parse name from right to left
+ - last character is channel ID, 1 char like 'A' 'R' 'G' 'B' 'X' 'Y' 'Z' 'W' 'U' 'V'
+ - separated with a dot; the Pass name (like "Depth", "Color", "Diffuse" or "Combined")
+ - separated with a dot: the Layer name (like "Lamp1" or "Walls" or "Characters")
+*/
+
+static ListBase exrhandles= {NULL, NULL};
+
+typedef struct ExrHandle {
+ struct ExrHandle *next, *prev;
+
+ InputFile *ifile;
+ TiledOutputFile *tofile;
+ OutputFile *ofile;
+ int tilex, tiley;
+ int width, height;
+
+ ListBase channels; /* flattened out, ExrChannel */
+ ListBase layers; /* hierarchical, pointing in end to ExrChannel */
+} ExrHandle;
+
+/* flattened out channel */
+typedef struct ExrChannel {
+ struct ExrChannel *next, *prev;
+
+ char name[EXR_TOT_MAXNAME+1]; /* full name of layer+pass */
+ int xstride, ystride; /* step to next pixel, to next scanline */
+ float *rect; /* first pointer to write in */
+ char chan_id; /* quick lookup of channel char */
+} ExrChannel;
+
+
+/* hierarchical; layers -> passes -> channels[] */
+typedef struct ExrPass {
+ struct ExrPass *next, *prev;
+ char name[EXR_PASS_MAXNAME];
+ int totchan;
+ float *rect;
+ struct ExrChannel *chan[EXR_PASS_MAXCHAN];
+ char chan_id[EXR_PASS_MAXCHAN];
+} ExrPass;
+
+typedef struct ExrLayer {
+ struct ExrLayer *next, *prev;
+ char name[EXR_LAY_MAXNAME+1];
+ ListBase passes;
+} ExrLayer;
+
+/* ********************** */
+
+void *IMB_exr_get_handle(void)
+{
+ ExrHandle *data= (ExrHandle *)MEM_callocN(sizeof(ExrHandle), "exr handle");
+ BLI_addtail(&exrhandles, data);
+ return data;
+}
+
+/* adds flattened ExrChannels */
+/* xstride, ystride and rect can be done in set_channel too, for tile writing */
+void IMB_exr_add_channel(void *handle, const char *layname, const char *passname, int xstride, int ystride, float *rect)
+{
+ ExrHandle *data= (ExrHandle *)handle;
+ ExrChannel *echan;
+
+ echan= (ExrChannel *)MEM_callocN(sizeof(ExrChannel), "exr tile channel");
+
+ if(layname) {
+ char lay[EXR_LAY_MAXNAME+1], pass[EXR_PASS_MAXNAME+1];
+ BLI_strncpy(lay, layname, EXR_LAY_MAXNAME);
+ BLI_strncpy(pass, passname, EXR_PASS_MAXNAME);
+
+ sprintf(echan->name, "%s.%s", lay, pass);
+ }
+ else
+ BLI_strncpy(echan->name, passname, EXR_TOT_MAXNAME-1);
+
+ echan->xstride= xstride;
+ echan->ystride= ystride;
+ echan->rect= rect;
+
+ // printf("added channel %s\n", echan->name);
+ BLI_addtail(&data->channels, echan);
+}
+
+void IMB_exr_begin_write(void *handle, char *filename, int width, int height, int compress)
+{
+ ExrHandle *data= (ExrHandle *)handle;
+ Header header (width, height);
+ ExrChannel *echan;
+
+ data->width= width;
+ data->height= height;
+
+ for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next)
+ header.channels().insert (echan->name, Channel (FLOAT));
+
+ openexr_header_compression(&header, compress);
+ /* header.lineOrder() = DECREASING_Y; this crashes in windows for file read! */
+
+ header.insert ("BlenderMultiChannel", StringAttribute ("Blender V2.43"));
+
+ data->ofile = new OutputFile(filename, header);
+}
+
+void IMB_exrtile_begin_write(void *handle, char *filename, int width, int height, int tilex, int tiley)
+{
+ ExrHandle *data= (ExrHandle *)handle;
+ Header header (width, height);
+ ExrChannel *echan;
+
+ data->tilex= tilex;
+ data->tiley= tiley;
+ data->width= width;
+ data->height= height;
+
+ for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next)
+ header.channels().insert (echan->name, Channel (FLOAT));
+
+ header.setTileDescription (TileDescription (tilex, tiley, ONE_LEVEL));
+ header.lineOrder() = RANDOM_Y;
+ header.compression() = RLE_COMPRESSION;
+
+ header.insert ("BlenderMultiChannel", StringAttribute ("Blender V2.43"));
+
+ data->tofile = new TiledOutputFile(filename, header);
+}
+
+/* read from file */
+int IMB_exr_begin_read(void *handle, char *filename, int *width, int *height)
+{
+ ExrHandle *data= (ExrHandle *)handle;
+
+ if(BLI_exists(filename)) {
+ data->ifile = new InputFile(filename);
+ if(data->ifile) {
+ Box2i dw = data->ifile->header().dataWindow();
+ data->width= *width = dw.max.x - dw.min.x + 1;
+ data->height= *height = dw.max.y - dw.min.y + 1;
+
+ const ChannelList &channels = data->ifile->header().channels();
+
+ for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i)
+ IMB_exr_add_channel(data, NULL, i.name(), 0, 0, NULL);
+
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* still clumsy name handling, layers/channels can be ordered as list in list later */
+void IMB_exr_set_channel(void *handle, char *layname, char *passname, int xstride, int ystride, float *rect)
+{
+ ExrHandle *data= (ExrHandle *)handle;
+ ExrChannel *echan;
+ char name[EXR_TOT_MAXNAME + 1];
+
+ if(layname) {
+ char lay[EXR_LAY_MAXNAME+1], pass[EXR_PASS_MAXNAME+1];
+ BLI_strncpy(lay, layname, EXR_LAY_MAXNAME);
+ BLI_strncpy(pass, passname, EXR_PASS_MAXNAME);
+
+ sprintf(name, "%s.%s", lay, pass);
+ }
+ else
+ BLI_strncpy(name, passname, EXR_TOT_MAXNAME-1);
+
+
+ for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next)
+ if(strcmp(echan->name, name)==0)
+ break;
+
+ if(echan) {
+ echan->xstride= xstride;
+ echan->ystride= ystride;
+ echan->rect= rect;
+ }
+ else
+ printf("IMB_exrtile_set_channel error %s\n", name);
+}
+
+void IMB_exrtile_clear_channels(void *handle)
+{
+ ExrHandle *data= (ExrHandle *)handle;
+ BLI_freelistN(&data->channels);
+}
+
+void IMB_exrtile_write_channels(void *handle, int partx, int party)
+{
+ ExrHandle *data= (ExrHandle *)handle;
+ FrameBuffer frameBuffer;
+ ExrChannel *echan;
+
+ for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next) {
+ float *rect= echan->rect - echan->xstride*partx - echan->ystride*party;
+
+ frameBuffer.insert (echan->name, Slice (FLOAT, (char *)rect,
+ echan->xstride*sizeof(float), echan->ystride*sizeof(float)));
+ }
+
+ data->tofile->setFrameBuffer (frameBuffer);
+ // printf("write tile %d %d\n", partx/data->tilex, party/data->tiley);
+ data->tofile->writeTile (partx/data->tilex, party/data->tiley);
+
+}
+
+void IMB_exr_write_channels(void *handle)
+{
+ ExrHandle *data= (ExrHandle *)handle;
+ FrameBuffer frameBuffer;
+ ExrChannel *echan;
+
+ for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next)
+ frameBuffer.insert (echan->name, Slice (FLOAT, (char *)echan->rect,
+ echan->xstride*sizeof(float), echan->ystride*sizeof(float)));
+
+ data->ofile->setFrameBuffer (frameBuffer);
+ data->ofile->writePixels (data->height);
+
+}
+
+void IMB_exr_read_channels(void *handle)
+{
+ ExrHandle *data= (ExrHandle *)handle;
+ FrameBuffer frameBuffer;
+ ExrChannel *echan;
+
+ for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next) {
+ /* no datawindow correction needed */
+ if(echan->rect)
+ frameBuffer.insert (echan->name, Slice (FLOAT, (char *)echan->rect,
+ echan->xstride*sizeof(float), echan->ystride*sizeof(float)));
+ else
+ printf("warning, channel with no rect set %s\n", echan->name);
+ }
+
+ data->ifile->setFrameBuffer (frameBuffer);
+ data->ifile->readPixels (0, data->height-1);
+}
+
+void IMB_exr_multilayer_convert(void *handle, void *base,
+ void * (*addlayer)(void *base, char *str),
+ void (*addpass)(void *base, void *lay, char *str,
+ float *rect, int totchan, char *chan_id))
+{
+ ExrHandle *data= (ExrHandle *)handle;
+ ExrLayer *lay;
+ ExrPass *pass;
+
+ if(data->layers.first==NULL) {
+ printf("cannot convert multilayer, no layers in handle\n");
+ return;
+ }
+
+ for(lay= (ExrLayer *)data->layers.first; lay; lay= lay->next) {
+ void *laybase= addlayer(base, lay->name);
+ if(laybase) {
+ for(pass= (ExrPass *)lay->passes.first; pass; pass= pass->next) {
+ addpass(base, laybase, pass->name, pass->rect, pass->totchan, pass->chan_id);
+ pass->rect= NULL;
+ }
+ }
+ }
+}
+
+
+void IMB_exr_close(void *handle)
+{
+ ExrHandle *data= (ExrHandle *)handle;
+ ExrChannel *echan;
+ ExrLayer *lay;
+ ExrPass *pass;
+
+ if(data->ifile)
+ delete data->ifile;
+ else if(data->ofile)
+ delete data->ofile;
+ else if(data->tofile)
+ delete data->tofile;
+
+ data->ifile= NULL;
+ data->ofile= NULL;
+ data->tofile= NULL;
+
+ BLI_freelistN(&data->channels);
+
+ for(lay= (ExrLayer *)data->layers.first; lay; lay= lay->next) {
+ for(pass= (ExrPass *)lay->passes.first; pass; pass= pass->next)
+ if(pass->rect)
+ MEM_freeN(pass->rect);
+ BLI_freelistN(&lay->passes);
+ }
+ BLI_freelistN(&data->layers);
+
+ BLI_remlink(&exrhandles, data);
+ MEM_freeN(data);
+}
+
+/* ********* */
+
+static int imb_exr_split_channel_name(ExrChannel *echan, char *layname, char *passname)
+{
+ int plen, len= strlen(echan->name);
+
+ if(len < 4) {
+ printf("multilayer read: name too short: %s\n", echan->name);
+ return 0;
+ }
+ if(echan->name[len-2]!='.') {
+ printf("multilayer read: name has no Channel: %s\n", echan->name);
+ return 0;
+ }
+ echan->chan_id= echan->name[len-1];
+
+ len-= 3;
+ while(len>=0) {
+ if(echan->name[len]=='.')
+ break;
+ len--;
+ }
+ BLI_strncpy(passname, echan->name+len+1, EXR_PASS_MAXNAME);
+ plen= strlen(passname);
+ if(plen < 3) {
+ printf("multilayer read: should not happen: %s\n", echan->name);
+ return 0;
+ }
+ passname[plen-2]= 0;
+
+ if(len<1)
+ layname[0]= 0;
+ else {
+ BLI_strncpy(layname, echan->name, EXR_LAY_MAXNAME);
+ layname[len]= 0;
+ }
+ // printf("found lay %s pass %s chan %c\n", layname, passname, echan->chan_id);
+ return 1;
+}
+
+static ExrLayer *imb_exr_get_layer(ListBase *lb, char *layname)
+{
+ ExrLayer *lay;
+
+ for(lay= (ExrLayer *)lb->first; lay; lay= lay->next) {
+ if( strcmp(lay->name, layname)==0 )
+ return lay;
+ }
+ lay= (ExrLayer *)MEM_callocN(sizeof(ExrLayer), "exr layer");
+ BLI_addtail(lb, lay);
+ BLI_strncpy(lay->name, layname, EXR_LAY_MAXNAME);
+
+ return lay;
+}
+
+static ExrPass *imb_exr_get_pass(ListBase *lb, char *passname)
+{
+ ExrPass *pass;
+
+ for(pass= (ExrPass *)lb->first; pass; pass= pass->next) {
+ if( strcmp(pass->name, passname)==0 )
+ return pass;
+ }
+
+ pass= (ExrPass *)MEM_callocN(sizeof(ExrPass), "exr pass");
+
+ if(strcmp(passname, "Combined")==0)
+ BLI_addhead(lb, pass);
+ else
+ BLI_addtail(lb, pass);
+
+ BLI_strncpy(pass->name, passname, EXR_LAY_MAXNAME);
+
+ return pass;
+}
+
+/* creates channels, makes a hierarchy and assigns memory to channels */
+static ExrHandle *imb_exr_begin_read_mem(InputFile *file, int width, int height)
+{
+ ExrLayer *lay;
+ ExrPass *pass;
+ ExrChannel *echan;
+ ExrHandle *data= (ExrHandle *)IMB_exr_get_handle();
+ int a;
+ char layname[EXR_TOT_MAXNAME], passname[EXR_TOT_MAXNAME];
+
+ data->ifile= file;
+ data->width= width;
+ data->height= height;
+
+ const ChannelList &channels = data->ifile->header().channels();
+
+ for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i)
+ IMB_exr_add_channel(data, NULL, i.name(), 0, 0, NULL);
+
+ /* now try to sort out how to assign memory to the channels */
+ /* first build hierarchical layer list */
+ for(echan= (ExrChannel *)data->channels.first; echan; echan= echan->next) {
+ if( imb_exr_split_channel_name(echan, layname, passname) ) {
+ ExrLayer *lay= imb_exr_get_layer(&data->layers, layname);
+ ExrPass *pass= imb_exr_get_pass(&lay->passes, passname);
+
+ pass->chan[pass->totchan]= echan;
+ pass->totchan++;
+ if(pass->totchan>=EXR_PASS_MAXCHAN)
+ break;
+ }
+ }
+ if(echan) {
+ printf("error, too many channels in one pass: %s\n", echan->name);
+ IMB_exr_close(data);
+ return NULL;
+ }
+
+ /* with some heuristics, try to merge the channels in buffers */
+ for(lay= (ExrLayer *)data->layers.first; lay; lay= lay->next) {
+ for(pass= (ExrPass *)lay->passes.first; pass; pass= pass->next) {
+ if(pass->totchan) {
+ pass->rect= (float *)MEM_mapallocN(width*height*pass->totchan*sizeof(float), "pass rect");
+ if(pass->totchan==1) {
+ echan= pass->chan[0];
+ echan->rect= pass->rect;
+ echan->xstride= 1;
+ echan->ystride= width;
+ pass->chan_id[0]= echan->chan_id;
+ }
+ else {
+ char lookup[256];
+
+ memset(lookup, 0, sizeof(lookup));
+
+ /* we can have RGB(A), XYZ(W), UVA */
+ if(pass->totchan==3 || pass->totchan==4) {
+ if(pass->chan[0]->chan_id=='B' || pass->chan[1]->chan_id=='B' || pass->chan[2]->chan_id=='B') {
+ lookup['R']= 0;
+ lookup['G']= 1;
+ lookup['B']= 2;
+ lookup['A']= 3;
+ }
+ else if(pass->chan[0]->chan_id=='Y' || pass->chan[1]->chan_id=='Y' || pass->chan[2]->chan_id=='Y') {
+ lookup['X']= 0;
+ lookup['Y']= 1;
+ lookup['Z']= 2;
+ lookup['W']= 3;
+ }
+ else {
+ lookup['U']= 0;
+ lookup['V']= 1;
+ lookup['A']= 2;
+ }
+ for(a=0; a<pass->totchan; a++) {
+ echan= pass->chan[a];
+ echan->rect= pass->rect + lookup[echan->chan_id];
+ echan->xstride= pass->totchan;
+ echan->ystride= width*pass->totchan;
+ pass->chan_id[ lookup[echan->chan_id] ]= echan->chan_id;
+ }
+ }
+ else { /* unknown */
+ for(a=0; a<pass->totchan; a++) {
+ echan= pass->chan[a];
+ echan->rect= pass->rect + a;
+ echan->xstride= pass->totchan;
+ echan->ystride= width*pass->totchan;
+ pass->chan_id[a]= echan->chan_id;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return data;
+}
+
+
+/* ********************************************************* */
+
+typedef struct RGBA
+{
+ float r;
+ float g;
+ float b;
+ float a;
+} RGBA;
+
+
+static void exr_print_filecontents(InputFile *file)
+{
+ const ChannelList &channels = file->header().channels();
+
+ for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i)
+ {
+ const Channel &channel = i.channel();
+ printf("OpenEXR-load: Found channel %s of type %d\n", i.name(), channel.type);
+ }
+}
+
+static int exr_has_zbuffer(InputFile *file)
+{
+ const ChannelList &channels = file->header().channels();
+
+ for (ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i)
+ {
+ const Channel &channel = i.channel();
+ if(strcmp("Z", i.name())==0)
+ return 1;
+ }
+ return 0;
+}
+
+static int exr_is_renderresult(InputFile *file)
+{
+ const StringAttribute *comments= file->header().findTypedAttribute<StringAttribute>("BlenderMultiChannel");
+ if(comments)
+// if(comments->value() == "Blender MultiChannel")
+ return 1;
+ return 0;
+}
+
+struct ImBuf *imb_load_openexr(unsigned char *mem, int size, int flags)
+{
+ struct ImBuf *ibuf = NULL;
+ InputFile *file = NULL;
+
+ if (imb_is_a_openexr(mem) == 0) return(NULL);
+
+ try
+ {
+ Mem_IStream *membuf = new Mem_IStream(mem, size);
+ int is_multi;
+ file = new InputFile(*membuf);
+
+ Box2i dw = file->header().dataWindow();
+ int width = dw.max.x - dw.min.x + 1;
+ int height = dw.max.y - dw.min.y + 1;
+
+ //printf("OpenEXR-load: image data window %d %d %d %d\n",
+ // dw.min.x, dw.min.y, dw.max.x, dw.max.y);
+
+ // exr_print_filecontents(file);
+
+ is_multi= exr_is_renderresult(file);
+
+ /* do not make an ibuf when */
+ if(is_multi && !(flags & IB_test) && !(flags & IB_multilayer))
+ {
+ printf("Error: can't process EXR multilayer file\n");
+ }
+ else {
+
+ ibuf = IMB_allocImBuf(width, height, 32, 0, 0);
+ ibuf->ftype = OPENEXR;
+
+ if (!(flags & IB_test))
+ {
+ if(is_multi) /* only enters with IB_multilayer flag set */
+ {
+ /* constructs channels for reading, allocates memory in channels */
+ ExrHandle *handle= imb_exr_begin_read_mem(file, width, height);
+ if(handle) {
+ IMB_exr_read_channels(handle);
+ ibuf->userdata= handle; /* potential danger, the caller has to check for this! */
+ return ibuf;
+ }
+ }
+ else {
+ FrameBuffer frameBuffer;
+ float *first;
+ int xstride = sizeof(float) * 4;
+ int ystride = - xstride*width;
+
+ imb_addrectfloatImBuf(ibuf);
+
+ /* inverse correct first pixel for datawindow coordinates (- dw.min.y because of y flip) */
+ first= ibuf->rect_float - 4*(dw.min.x - dw.min.y*width);
+ /* but, since we read y-flipped (negative y stride) we move to last scanline */
+ first+= 4*(height-1)*width;
+
+ frameBuffer.insert ("R", Slice (FLOAT, (char *) first, xstride, ystride));
+ frameBuffer.insert ("G", Slice (FLOAT, (char *) (first+1), xstride, ystride));
+ frameBuffer.insert ("B", Slice (FLOAT, (char *) (first+2), xstride, ystride));
+ /* 1.0 is fill value */
+ frameBuffer.insert ("A", Slice (FLOAT, (char *) (first+3), xstride, ystride, 1, 1, 1.0f));
+
+ if(exr_has_zbuffer(file))
+ {
+ float *firstz;
+
+ addzbuffloatImBuf(ibuf);
+ firstz= ibuf->zbuf_float - (dw.min.x - dw.min.y*width);
+ firstz+= (height-1)*width;
+ frameBuffer.insert ("Z", Slice (FLOAT, (char *)firstz , sizeof(float), -width*sizeof(float)));
+ }
+
+ file->setFrameBuffer (frameBuffer);
+ file->readPixels (dw.min.y, dw.max.y);
+
+ IMB_rect_from_float(ibuf);
+ }
+ }
+
+ }
+ delete file;
+
+ return(ibuf);
+
+ }
+ catch (const std::exception &exc)
+ {
+ std::cerr << exc.what() << std::endl;
+ if (ibuf) IMB_freeImBuf(ibuf);
+ delete file;
+
+ return (0);
+ }
+
+}
+
+
+} // export "C"
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.h b/source/blender/imbuf/intern/openexr/openexr_api.h
new file mode 100644
index 00000000000..7572dbcb292
--- /dev/null
+++ b/source/blender/imbuf/intern/openexr/openexr_api.h
@@ -0,0 +1,59 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Austin Benesh. Ton Roosendaal.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef _OPENEXR_API_H
+#define _OPENEXR_API_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define OPENEXR_FLOATRGB 0x1
+#define OPENEXR_ZBUF 0x2
+
+#include <stdio.h>
+
+ /**
+ * Test presence of OpenEXR file.
+ * @param mem pointer to loaded OpenEXR bitstream
+ */
+
+int imb_is_a_openexr (unsigned char *mem);
+
+short imb_save_openexr (struct ImBuf *ibuf, char *name, int flags);
+
+struct ImBuf *imb_load_openexr (unsigned char *mem, int size, int flags);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
+#endif /* __OPENEXR_API_H */
diff --git a/source/blender/imbuf/intern/openexr/openexr_multi.h b/source/blender/imbuf/intern/openexr/openexr_multi.h
new file mode 100644
index 00000000000..ca4f7405f44
--- /dev/null
+++ b/source/blender/imbuf/intern/openexr/openexr_multi.h
@@ -0,0 +1,93 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Ton Roosendaal.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef _OPENEXR_MULTI_H
+#define _OPENEXR_MULTI_H
+
+/* experiment with more advanced exr api */
+
+/* Note: as for now openexr only supports 32 chars in channel names.
+ This api also supports max 8 channels per pass now. easy to fix! */
+#define EXR_LAY_MAXNAME 19
+#define EXR_PASS_MAXNAME 11
+#define EXR_TOT_MAXNAME 32
+#define EXR_PASS_MAXCHAN 8
+
+
+#ifdef WITH_OPENEXR
+void * IMB_exr_get_handle (void);
+void IMB_exr_add_channel (void *handle, const char *layname, const char *passname, int xstride, int ystride, float *rect);
+
+int IMB_exr_begin_read (void *handle, char *filename, int *width, int *height);
+void IMB_exr_begin_write (void *handle, char *filename, int width, int height, int compress);
+void IMB_exrtile_begin_write (void *handle, char *filename, int width, int height, int tilex, int tiley);
+
+void IMB_exr_set_channel (void *handle, char *layname, char *passname, int xstride, int ystride, float *rect);
+
+void IMB_exr_read_channels (void *handle);
+void IMB_exr_write_channels (void *handle);
+void IMB_exrtile_write_channels (void *handle, int partx, int party);
+void IMB_exrtile_clear_channels (void *handle);
+
+void IMB_exr_multilayer_convert (void *handle, void *base,
+ void * (*addlayer)(void *base, char *str),
+ void (*addpass)(void *base, void *lay, char *str, float *rect, int totchan, char *chan_id));
+
+void IMB_exr_close (void *handle);
+
+
+#else
+
+/* ugly... but we only use it on pipeline.c, render module, now */
+
+void * IMB_exr_get_handle (void) {return NULL;}
+void IMB_exr_add_channel (void *handle, const char *layname, const char *channame, int xstride, int ystride, float *rect) {}
+
+int IMB_exr_begin_read (void *handle, char *filename, int *width, int *height) {return 0;}
+void IMB_exr_begin_write (void *handle, char *filename, int width, int height, int compress) {}
+void IMB_exrtile_begin_write (void *handle, char *filename, int width, int height, int tilex, int tiley) {}
+
+void IMB_exr_set_channel (void *handle, char *layname, char *channame, int xstride, int ystride, float *rect) {}
+
+void IMB_exr_read_channels (void *handle) {}
+void IMB_exr_write_channels (void *handle) {}
+void IMB_exrtile_write_channels (void *handle, int partx, int party) {}
+void IMB_exrtile_clear_channels (void *handle) {}
+
+void IMB_exr_multilayer_convert (void *handle, void *base,
+ void * (*addlayer)(void *base, char *str),
+ void (*addpass)(void *base, void *lay, char *str, float *rect, int totchan, char *chan_id)) {}
+
+void IMB_exr_close (void *handle) {}
+
+#endif
+
+
+
+#endif /* __OPENEXR_MULTI_H */
diff --git a/source/blender/imbuf/intern/png.c b/source/blender/imbuf/intern/png.c
new file mode 100644
index 00000000000..c77ff7ea56f
--- /dev/null
+++ b/source/blender/imbuf/intern/png.c
@@ -0,0 +1,461 @@
+/**
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * $Id$
+ */
+
+
+#include "png.h"
+
+#include "BLI_blenlib.h"
+
+#include "imbuf.h"
+#include "imbuf_patch.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "IMB_allocimbuf.h"
+#include "IMB_cmap.h"
+#include "IMB_imginfo.h"
+#include "IMB_png.h"
+
+typedef struct PNGReadStruct {
+ unsigned char *data;
+ unsigned int size;
+ unsigned int seek;
+}PNGReadStruct;
+
+static void ReadData( png_structp png_ptr, png_bytep data, png_size_t length);
+static void WriteData( png_structp png_ptr, png_bytep data, png_size_t length);
+static void Flush( png_structp png_ptr);
+
+int imb_is_a_png(void *mem)
+{
+ int ret_val = 0;
+
+ if (mem) ret_val = !png_sig_cmp(mem, 0, 8);
+ return(ret_val);
+}
+
+static void Flush(png_structp png_ptr)
+{
+}
+
+static void WriteData( png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ ImBuf *ibuf = (ImBuf *) png_get_io_ptr(png_ptr);
+
+ // if buffer is to small increase it.
+ while (ibuf->encodedsize + length > ibuf->encodedbuffersize) {
+ imb_enlargeencodedbufferImBuf(ibuf);
+ }
+
+ memcpy(ibuf->encodedbuffer + ibuf->encodedsize, data, length);
+ ibuf->encodedsize += length;
+}
+
+static void ReadData( png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ PNGReadStruct *rs= (PNGReadStruct *) png_get_io_ptr(png_ptr);
+
+ if (rs) {
+ if (length <= rs->size - rs->seek) {
+ memcpy(data, rs->data + rs->seek, length);
+ rs->seek += length;
+ return;
+ }
+ }
+
+ printf("Reached EOF while decoding PNG\n");
+ longjmp(png_jmpbuf(png_ptr), 1);
+}
+
+short imb_savepng(struct ImBuf *ibuf, char *name, int flags)
+{
+ png_structp png_ptr;
+ png_infop info_ptr;
+
+ unsigned char *pixels = 0;
+ unsigned char *from, *to;
+ png_bytepp row_pointers = 0;
+ int i, bytesperpixel, color_type = PNG_COLOR_TYPE_GRAY;
+ FILE *fp = 0;
+
+ bytesperpixel = (ibuf->depth + 7) >> 3;
+ if ((bytesperpixel > 4) || (bytesperpixel == 2)) {
+ printf("imb_savepng: unsupported bytes per pixel: %d\n", bytesperpixel);
+ return (0);
+ }
+
+ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
+ NULL, NULL, NULL);
+ if (png_ptr == NULL) {
+ printf("Cannot png_create_write_struct\n");
+ return 0;
+ }
+
+ info_ptr = png_create_info_struct(png_ptr);
+ if (info_ptr == NULL) {
+ png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
+ printf("Cannot png_create_info_struct\n");
+ return 0;
+ }
+
+ if (setjmp(png_jmpbuf(png_ptr))) {
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ if (pixels) MEM_freeN(pixels);
+ if (row_pointers) MEM_freeN(row_pointers);
+ // printf("Aborting\n");
+ if (fp) {
+ fflush(fp);
+ fclose(fp);
+ }
+ return 0;
+ }
+
+ // copy image data
+
+ pixels = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned char), "pixels");
+ if (pixels == NULL) {
+ printf("Cannot allocate pixels array\n");
+ return 0;
+ }
+
+ from = (unsigned char *) ibuf->rect;
+ to = pixels;
+
+ switch (bytesperpixel) {
+ case 4:
+ color_type = PNG_COLOR_TYPE_RGBA;
+ for (i = ibuf->x * ibuf->y; i > 0; i--) {
+ to[0] = from[0];
+ to[1] = from[1];
+ to[2] = from[2];
+ to[3] = from[3];
+ to += 4; from += 4;
+ }
+ break;
+ case 3:
+ color_type = PNG_COLOR_TYPE_RGB;
+ for (i = ibuf->x * ibuf->y; i > 0; i--) {
+ to[0] = from[0];
+ to[1] = from[1];
+ to[2] = from[2];
+ to += 3; from += 4;
+ }
+ break;
+ case 1:
+ color_type = PNG_COLOR_TYPE_GRAY;
+ for (i = ibuf->x * ibuf->y; i > 0; i--) {
+ to[0] = from[0];
+ to++; from += 4;
+ }
+ break;
+ }
+
+ if (flags & IB_mem) {
+ // create image in memory
+ imb_addencodedbufferImBuf(ibuf);
+ ibuf->encodedsize = 0;
+
+ png_set_write_fn(png_ptr,
+ (png_voidp) ibuf,
+ WriteData,
+ Flush);
+ } else {
+ fp = fopen(name, "wb");
+ if (!fp) {
+ MEM_freeN(pixels);
+ return 0;
+ }
+ png_init_io(png_ptr, fp);
+ }
+
+ /*
+ png_set_filter(png_ptr, 0,
+ PNG_FILTER_NONE | PNG_FILTER_VALUE_NONE |
+ PNG_FILTER_SUB | PNG_FILTER_VALUE_SUB |
+ PNG_FILTER_UP | PNG_FILTER_VALUE_UP |
+ PNG_FILTER_AVG | PNG_FILTER_VALUE_AVG |
+ PNG_FILTER_PAETH | PNG_FILTER_VALUE_PAETH|
+ PNG_ALL_FILTERS);
+
+ png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);
+ */
+
+ // png image settings
+ png_set_IHDR(png_ptr,
+ info_ptr,
+ ibuf->x,
+ ibuf->y,
+ 8,
+ color_type,
+ PNG_INTERLACE_NONE,
+ PNG_COMPRESSION_TYPE_DEFAULT,
+ PNG_FILTER_TYPE_DEFAULT);
+
+ /* image text info */
+ if (ibuf->img_info) {
+ png_text* imginfo;
+ ImgInfo* iptr;
+ int num_text = 0;
+ iptr = ibuf->img_info;
+ while (iptr) {
+ num_text++;
+ iptr = iptr->next;
+ }
+
+ imginfo = MEM_callocN(num_text*sizeof(png_text), "png_imginfo");
+ iptr = ibuf->img_info;
+ num_text = 0;
+ while (iptr) {
+
+ imginfo[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
+ imginfo[num_text].key = iptr->key;
+ imginfo[num_text].text = iptr->value;
+ num_text++;
+ iptr = iptr->next;
+ }
+
+ png_set_text(png_ptr, info_ptr, imginfo, num_text);
+ MEM_freeN(imginfo);
+
+ }
+
+ // write the file header information
+ png_write_info(png_ptr, info_ptr);
+
+ // allocate memory for an array of row-pointers
+ row_pointers = (png_bytepp) MEM_mallocN(ibuf->y * sizeof(png_bytep), "row_pointers");
+ if (row_pointers == NULL) {
+ printf("Cannot allocate row-pointers array\n");
+ MEM_freeN(pixels);
+ return 0;
+ }
+
+ // set the individual row-pointers to point at the correct offsets
+ for (i = 0; i < ibuf->y; i++) {
+ row_pointers[ibuf->y-1-i] = (png_bytep)
+ ((unsigned char *)pixels + (i * ibuf->x) * bytesperpixel * sizeof(unsigned char));
+ }
+
+ // write out the entire image data in one call
+ png_write_image(png_ptr, row_pointers);
+
+ // write the additional chunks to the PNG file (not really needed)
+ png_write_end(png_ptr, info_ptr);
+
+ // clean up
+ MEM_freeN(pixels);
+ MEM_freeN(row_pointers);
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+
+ if (fp) {
+ fflush(fp);
+ fclose(fp);
+ }
+
+ return(1);
+}
+
+struct ImBuf *imb_loadpng(unsigned char *mem, int size, int flags)
+{
+ struct ImBuf *ibuf = 0;
+ png_structp png_ptr;
+ png_infop info_ptr;
+ unsigned char *pixels = 0;
+ png_bytepp row_pointers = 0;
+ png_uint_32 width, height;
+ int bit_depth, color_type;
+ PNGReadStruct ps;
+
+ unsigned char *from, *to;
+ int i, bytesperpixel;
+
+ if (imb_is_a_png(mem) == 0) return(0);
+
+ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
+ NULL, NULL, NULL);
+ if (png_ptr == NULL) {
+ printf("Cannot png_create_read_struct\n");
+ return 0;
+ }
+
+ info_ptr = png_create_info_struct(png_ptr);
+ if (info_ptr == NULL) {
+ png_destroy_read_struct(&png_ptr, (png_infopp)NULL,
+ (png_infopp)NULL);
+ printf("Cannot png_create_info_struct\n");
+ return 0;
+ }
+
+ ps.size = size;
+ ps.data = mem;
+ ps.seek = 0;
+
+ png_set_read_fn(png_ptr, (void *) &ps, ReadData);
+
+ if (setjmp(png_jmpbuf(png_ptr))) {
+ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
+ if (pixels) MEM_freeN(pixels);
+ if (row_pointers) MEM_freeN(row_pointers);
+ if (ibuf) IMB_freeImBuf(ibuf);
+ return 0;
+ }
+
+ // png_set_sig_bytes(png_ptr, 8);
+
+ png_read_info(png_ptr, info_ptr);
+ png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth,
+ &color_type, NULL, NULL, NULL);
+
+ if (bit_depth == 16) {
+ png_set_strip_16(png_ptr);
+ bit_depth = 8;
+ }
+
+ bytesperpixel = png_get_channels(png_ptr, info_ptr);
+
+ switch(color_type) {
+ case PNG_COLOR_TYPE_RGB:
+ case PNG_COLOR_TYPE_RGB_ALPHA:
+ break;
+ case PNG_COLOR_TYPE_PALETTE:
+ png_set_palette_to_rgb(png_ptr);
+ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
+ bytesperpixel = 4;
+ } else {
+ bytesperpixel = 3;
+ }
+ break;
+ case PNG_COLOR_TYPE_GRAY:
+ case PNG_COLOR_TYPE_GRAY_ALPHA:
+ if (bit_depth < 8) {
+ png_set_expand(png_ptr);
+ bit_depth = 8;
+ }
+ break;
+ default:
+ printf("PNG format not supported\n");
+ longjmp(png_jmpbuf(png_ptr), 1);
+ }
+
+ ibuf = IMB_allocImBuf(width, height, 8 * bytesperpixel, 0, 0);
+
+ if (ibuf) {
+ ibuf->ftype = PNG;
+ } else {
+ printf("Couldn't allocate memory for PNG image\n");
+ }
+
+ if (ibuf && ((flags & IB_test) == 0)) {
+ imb_addrectImBuf(ibuf);
+
+ pixels = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned char), "pixels");
+ if (pixels == NULL) {
+ printf("Cannot allocate pixels array\n");
+ longjmp(png_jmpbuf(png_ptr), 1);
+ }
+
+ // allocate memory for an array of row-pointers
+ row_pointers = (png_bytepp) MEM_mallocN(ibuf->y * sizeof(png_bytep), "row_pointers");
+ if (row_pointers == NULL) {
+ printf("Cannot allocate row-pointers array\n");
+ longjmp(png_jmpbuf(png_ptr), 1);
+ }
+
+ // set the individual row-pointers to point at the correct offsets
+ for (i = 0; i < ibuf->y; i++) {
+ row_pointers[ibuf->y-1-i] = (png_bytep)
+ ((unsigned char *)pixels + (i * ibuf->x) * bytesperpixel * sizeof(unsigned char));
+ }
+
+ png_read_image(png_ptr, row_pointers);
+
+ // copy image data
+
+ to = (unsigned char *) ibuf->rect;
+ from = pixels;
+
+ switch (bytesperpixel) {
+ case 4:
+ for (i = ibuf->x * ibuf->y; i > 0; i--) {
+ to[0] = from[0];
+ to[1] = from[1];
+ to[2] = from[2];
+ to[3] = from[3];
+ to += 4; from += 4;
+ }
+ break;
+ case 3:
+ for (i = ibuf->x * ibuf->y; i > 0; i--) {
+ to[0] = from[0];
+ to[1] = from[1];
+ to[2] = from[2];
+ to[3] = 0xff;
+ to += 4; from += 3;
+ }
+ break;
+ case 2:
+ for (i = ibuf->x * ibuf->y; i > 0; i--) {
+ to[0] = to[1] = to[2] = from[0];
+ to[3] = from[1];
+ to += 4; from += 2;
+ }
+ break;
+ case 1:
+ for (i = ibuf->x * ibuf->y; i > 0; i--) {
+ to[0] = to[1] = to[2] = from[0];
+ to[3] = 0xff;
+ to += 4; from++;
+ }
+ break;
+ }
+
+ if (flags & IB_imginfo) {
+ png_text* text_chunks;
+ int count = png_get_text(png_ptr, info_ptr, &text_chunks, NULL);
+ for(i = 0; i < count; i++) {
+ IMB_imginfo_add_field(ibuf, text_chunks[i].key, text_chunks[i].text);
+ ibuf->flags |= IB_imginfo;
+ }
+ }
+
+ png_read_end(png_ptr, info_ptr);
+ }
+
+ // clean up
+ MEM_freeN(pixels);
+ MEM_freeN(row_pointers);
+ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
+
+ return(ibuf);
+}
+
diff --git a/source/blender/imbuf/intern/radiance_hdr.c b/source/blender/imbuf/intern/radiance_hdr.c
new file mode 100644
index 00000000000..3cb9ca79ffc
--- /dev/null
+++ b/source/blender/imbuf/intern/radiance_hdr.c
@@ -0,0 +1,366 @@
+/*
+ * radiance_hdr.c
+ *
+ * $Id:
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+*/
+
+/* ----------------------------------------------------------------------
+ Radiance High Dynamic Range image file IO
+ For description and code for reading/writing of radiance hdr files
+ by Greg Ward, refer to:
+ http://radsite.lbl.gov/radiance/refer/Notes/picture_format.html
+----------------------------------------------------------------------
+*/
+
+#ifdef WIN32
+#include <io.h>
+#endif
+#include "BLI_blenlib.h"
+
+#include "imbuf.h"
+#include "imbuf_patch.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "IMB_allocimbuf.h"
+#include "IMB_cmap.h"
+#include "IMB_radiance_hdr.h"
+
+/* needed constants */
+#define MINELEN 8
+#define MAXELEN 0x7fff
+#define MINRUN 4 /* minimum run length */
+#define RED 0
+#define GRN 1
+#define BLU 2
+#define EXP 3
+#define COLXS 128
+typedef unsigned char RGBE[4];
+typedef float fCOLOR[3];
+/* copy source -> dest */
+#define copy_rgbe(c1, c2) (c2[RED]=c1[RED], c2[GRN]=c1[GRN], c2[BLU]=c1[BLU], c2[EXP]=c1[EXP])
+#define copy_fcol(f1, f2) (f2[RED]=f1[RED], f2[GRN]=f1[GRN], f2[BLU]=f1[BLU])
+
+/* read routines */
+static unsigned char* oldreadcolrs(RGBE *scan, unsigned char *mem, int xmax)
+{
+ int i, rshift = 0, len = xmax;
+ while (len > 0) {
+ scan[0][RED] = *mem++;
+ scan[0][GRN] = *mem++;
+ scan[0][BLU] = *mem++;
+ scan[0][EXP] = *mem++;
+ if (scan[0][RED] == 1 && scan[0][GRN] == 1 && scan[0][BLU] == 1) {
+ for (i=scan[0][EXP]<<rshift;i>0;i--) {
+ copy_rgbe(scan[-1], scan[0]);
+ scan++;
+ len--;
+ }
+ rshift += 8;
+ }
+ else {
+ scan++;
+ len--;
+ rshift = 0;
+ }
+ }
+ return mem;
+}
+
+static unsigned char* freadcolrs(RGBE *scan, unsigned char* mem, int xmax)
+{
+ int i, j, code, val;
+
+ if ((xmax < MINELEN) | (xmax > MAXELEN)) return oldreadcolrs(scan, mem, xmax);
+
+ i = *mem++;
+ if (i != 2) return oldreadcolrs(scan, mem-1, xmax);
+
+ scan[0][GRN] = *mem++;
+ scan[0][BLU] = *mem++;
+
+ i = *mem++;
+ if (((scan[0][BLU] << 8) | i) != xmax) return NULL;
+
+ for (i=0;i<4;i++)
+ for (j=0;j<xmax;) {
+ code = *mem++;
+ if (code > 128) {
+ code &= 127;
+ val = *mem++;
+ while (code--)
+ scan[j++][i] = (unsigned char)val;
+ }
+ else
+ while (code--)
+ scan[j++][i] = *mem++;
+ }
+ return mem;
+}
+
+/* helper functions */
+
+/* rgbe -> float color */
+static void RGBE2FLOAT(RGBE rgbe, fCOLOR fcol)
+{
+ if (rgbe[EXP]==0) {
+ fcol[RED] = fcol[GRN] = fcol[BLU] = 0;
+ }
+ else {
+ float f = ldexp(1.0, rgbe[EXP]-(COLXS+8));
+ fcol[RED] = f*(rgbe[RED] + 0.5f);
+ fcol[GRN] = f*(rgbe[GRN] + 0.5f);
+ fcol[BLU] = f*(rgbe[BLU] + 0.5f);
+ }
+}
+
+/* float color -> rgbe */
+static void FLOAT2RGBE(fCOLOR fcol, RGBE rgbe)
+{
+ int e;
+ float d = (fcol[RED]>fcol[GRN]) ? fcol[RED] : fcol[GRN];
+ if (fcol[BLU]>d) d = fcol[BLU];
+ if (d <= 1e-32f)
+ rgbe[RED] = rgbe[GRN] = rgbe[BLU] = rgbe[EXP] = 0;
+ else {
+ d = frexp(d, &e) * 256.f / d;
+ rgbe[RED] = (unsigned char)(fcol[RED] * d);
+ rgbe[GRN] = (unsigned char)(fcol[GRN] * d);
+ rgbe[BLU] = (unsigned char)(fcol[BLU] * d);
+ rgbe[EXP] = (unsigned char)(e + COLXS);
+ }
+}
+
+/* ImBuf read */
+
+int imb_is_a_hdr(void *buf)
+{
+ // For recognition, Blender only loads first 32 bytes, so use #?RADIANCE id instead
+ // update: actually, the 'RADIANCE' part is just an optional program name, the magic word is really only the '#?' part
+ //if (strstr((char*)buf, "#?RADIANCE")) return 1;
+ if (strstr((char*)buf, "#?")) return 1;
+ // if (strstr((char*)buf, "32-bit_rle_rgbe")) return 1;
+ return 0;
+}
+
+struct ImBuf *imb_loadhdr(unsigned char *mem, int size, int flags)
+{
+ struct ImBuf* ibuf;
+ RGBE* sline;
+ fCOLOR fcol;
+ float* rect_float;
+ int found=0;
+ int width=0, height=0;
+ int x, y;
+ unsigned char* ptr;
+ unsigned char* rect;
+ char oriY[80], oriX[80];
+
+ if (imb_is_a_hdr((void*)mem))
+ {
+ /* find empty line, next line is resolution info */
+ for (x=1;x<size;x++) {
+ if ((mem[x-1]=='\n') && (mem[x]=='\n')) {
+ found = 1;
+ break;
+ }
+ }
+ if (found) {
+ sscanf((char*)&mem[x+1], "%s %d %s %d", (char*)&oriY, &height, (char*)&oriX, &width);
+
+ /* find end of this line, data right behind it */
+ ptr = (unsigned char *)strchr((char*)&mem[x+1], '\n');
+ ptr++;
+
+ if (flags & IB_test) ibuf = IMB_allocImBuf(width, height, 32, 0, 0);
+ else ibuf = IMB_allocImBuf(width, height, 32, IB_rect|IB_rectfloat, 0);
+
+ if (ibuf==NULL) return NULL;
+ ibuf->ftype = RADHDR;
+ ibuf->xorig = ibuf->yorig = 0;
+
+ if (flags & IB_test) return ibuf;
+
+ /* read in and decode the actual data */
+ sline = (RGBE*)MEM_mallocN(sizeof(RGBE)*width, "radhdr_read_tmpscan");
+ rect = (unsigned char*)ibuf->rect;
+ rect_float = (float *)ibuf->rect_float;
+
+ for (y=0;y<height;y++) {
+ ptr = freadcolrs(sline, ptr, width);
+ if (ptr==NULL) {
+ printf("HDR decode error\n");
+ MEM_freeN(sline);
+ return ibuf;
+ }
+ for (x=0;x<width;x++) {
+ /* convert to ldr */
+ RGBE2FLOAT(sline[x], fcol);
+ *rect_float++ = fcol[RED];
+ *rect_float++ = fcol[GRN];
+ *rect_float++ = fcol[BLU];
+ *rect_float++ = 1.0f;
+ /* Also old oldstyle for the rest of blender which is not using floats yet */
+ // e: changed to simpler tonemapping, previous code was rather slow (is this actually still relevant at all?)
+ fcol[RED] = fcol[RED]/(1.f + fcol[RED]);
+ fcol[GRN] = fcol[GRN]/(1.f + fcol[GRN]);
+ fcol[BLU] = fcol[BLU]/(1.f + fcol[BLU]);
+ *rect++ = (unsigned char)((fcol[RED] < 0.f) ? 0 : ((fcol[RED] > 1.f) ? 255 : (255.f*fcol[RED])));
+ *rect++ = (unsigned char)((fcol[GRN] < 0.f) ? 0 : ((fcol[GRN] > 1.f) ? 255 : (255.f*fcol[GRN])));
+ *rect++ = (unsigned char)((fcol[BLU] < 0.f) ? 0 : ((fcol[BLU] > 1.f) ? 255 : (255.f*fcol[BLU])));
+ *rect++ = 255;
+ }
+ }
+ MEM_freeN(sline);
+ if (oriY[0]=='-') IMB_flipy(ibuf);
+ return ibuf;
+ }
+ //else printf("Data not found!\n");
+ }
+ //else printf("Not a valid radiance HDR file!\n");
+
+ return NULL;
+}
+
+/* ImBuf write */
+static int fwritecolrs(FILE* file, int width, unsigned char* ibufscan, float* fpscan)
+{
+ int x, i, j, beg, c2, cnt=0;
+ fCOLOR fcol;
+ RGBE rgbe, *rgbe_scan;
+
+ if ((ibufscan==NULL) && (fpscan==NULL)) return 0;
+
+ rgbe_scan = (RGBE*)MEM_mallocN(sizeof(RGBE)*width, "radhdr_write_tmpscan");
+
+ /* convert scanline */
+ j= 0;
+ for (i=0;i<width;i++) {
+ if (fpscan) {
+ fcol[RED] = fpscan[j];
+ fcol[GRN] = fpscan[j+1];
+ fcol[BLU] = fpscan[j+2];
+ } else {
+ fcol[RED] = (float)ibufscan[j] / 255.f;
+ fcol[GRN] = (float)ibufscan[j+1] / 255.f;
+ fcol[BLU] = (float)ibufscan[j+2] /255.f;
+ }
+ FLOAT2RGBE(fcol, rgbe);
+ copy_rgbe(rgbe, rgbe_scan[i]);
+ j+=4;
+ }
+
+ if ((width < MINELEN) | (width > MAXELEN)) { /* OOBs, write out flat */
+ x=fwrite((char *)rgbe_scan, sizeof(RGBE), width, file) - width;
+ MEM_freeN(rgbe_scan);
+ return x;
+ }
+ /* put magic header */
+ putc(2, file);
+ putc(2, file);
+ putc((unsigned char)(width >> 8), file);
+ putc((unsigned char)(width & 255), file);
+ /* put components seperately */
+ for (i=0;i<4;i++) {
+ for (j=0;j<width;j+=cnt) { /* find next run */
+ for (beg=j;beg<width;beg+=cnt) {
+ for (cnt=1;(cnt<127) && ((beg+cnt)<width) && (rgbe_scan[beg+cnt][i] == rgbe_scan[beg][i]); cnt++);
+ if (cnt>=MINRUN) break; /* long enough */
+ }
+ if (((beg-j)>1) && ((beg-j) < MINRUN)) {
+ c2 = j+1;
+ while (rgbe_scan[c2++][i] == rgbe_scan[j][i])
+ if (c2 == beg) { /* short run */
+ putc((unsigned char)(128+beg-j), file);
+ putc((unsigned char)(rgbe_scan[j][i]), file);
+ j = beg;
+ break;
+ }
+ }
+ while (j < beg) { /* write out non-run */
+ if ((c2 = beg-j) > 128) c2 = 128;
+ putc((unsigned char)(c2), file);
+ while (c2--) putc(rgbe_scan[j++][i], file);
+ }
+ if (cnt >= MINRUN) { /* write out run */
+ putc((unsigned char)(128+cnt), file);
+ putc(rgbe_scan[beg][i], file);
+ }
+ else cnt = 0;
+ }
+ }
+ MEM_freeN(rgbe_scan);
+ return(ferror(file) ? -1 : 0);
+}
+
+static void writeHeader(FILE *file, int width, int height)
+{
+ fprintf(file, "#?RADIANCE");
+ fputc(10, file);
+ fprintf(file, "# %s", "Created with Blender");
+ fputc(10, file);
+ fprintf(file, "EXPOSURE=%25.13f", 1.0);
+ fputc(10, file);
+ fprintf(file, "FORMAT=32-bit_rle_rgbe");
+ fputc(10, file);
+ fputc(10, file);
+ fprintf(file, "-Y %d +X %d", height, width);
+ fputc(10, file);
+}
+
+short imb_savehdr(struct ImBuf *ibuf, char *name, int flags)
+{
+ FILE* file = fopen(name, "wb");
+ float *fp= NULL;
+ int y, width=ibuf->x, height=ibuf->y;
+ unsigned char *cp= NULL;
+
+ if (file==NULL) return 0;
+
+ writeHeader(file, width, height);
+
+ if(ibuf->rect)
+ cp= (unsigned char *)(ibuf->rect + (height-1)*width);
+ if(ibuf->rect_float)
+ fp= ibuf->rect_float + 4*(height-1)*width;
+
+ for (y=height-1;y>=0;y--) {
+ if (fwritecolrs(file, width, cp, fp) < 0) {
+ fclose(file);
+ printf("HDR write error\n");
+ return 0;
+ }
+ if(cp) cp-= 4*width;
+ if(fp) fp-= 4*width;
+ }
+
+ fclose(file);
+ return 1;
+}
+
diff --git a/source/blender/imbuf/intern/readimage.c b/source/blender/imbuf/intern/readimage.c
new file mode 100644
index 00000000000..ec0f17a8c2b
--- /dev/null
+++ b/source/blender/imbuf/intern/readimage.c
@@ -0,0 +1,311 @@
+/**
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * allocimbuf.c
+ *
+ * $Id$
+ */
+
+#ifdef WIN32
+#include <io.h>
+#endif
+
+#include "BLI_blenlib.h"
+
+#include "imbuf.h"
+#include "imbuf_patch.h"
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "IMB_amiga.h"
+#include "IMB_iris.h"
+#include "IMB_targa.h"
+#include "IMB_png.h"
+#include "IMB_hamx.h"
+#include "IMB_jpeg.h"
+#include "IMB_bmp.h"
+#include "IMB_tiff.h"
+#include "IMB_radiance_hdr.h"
+#include "IMB_dpxcineon.h"
+#include "BKE_global.h"
+
+#ifdef WITH_OPENEXR
+#include "openexr/openexr_api.h"
+#endif
+
+#ifdef WITH_DDS
+#include "dds/dds_api.h"
+#endif
+
+#ifdef WITH_QUICKTIME
+#if defined(_WIN32) || defined (__APPLE__)
+#include "quicktime_import.h"
+#endif
+#endif
+
+/* actually hard coded endianness */
+#define GET_BIG_LONG(x) (((uchar *) (x))[0] << 24 | ((uchar *) (x))[1] << 16 | ((uchar *) (x))[2] << 8 | ((uchar *) (x))[3])
+#define GET_LITTLE_LONG(x) (((uchar *) (x))[3] << 24 | ((uchar *) (x))[2] << 16 | ((uchar *) (x))[1] << 8 | ((uchar *) (x))[0])
+#define SWAP_L(x) (((x << 24) & 0xff000000) | ((x << 8) & 0xff0000) | ((x >> 8) & 0xff00) | ((x >> 24) & 0xff))
+#define SWAP_S(x) (((x << 8) & 0xff00) | ((x >> 8) & 0xff))
+
+/* more endianness... should move to a separate file... */
+#if defined(__sgi) || defined (__sparc) || defined (__sparc__) || defined (__PPC__) || defined (__ppc__) || defined (__BIG_ENDIAN__)
+#define GET_ID GET_BIG_LONG
+#define LITTLE_LONG SWAP_LONG
+#else
+#define GET_ID GET_LITTLE_LONG
+#define LITTLE_LONG ENDIAN_NOP
+#endif
+
+/* from misc_util: flip the bytes from x */
+#define GS(x) (((unsigned char *)(x))[0] << 8 | ((unsigned char *)(x))[1])
+
+/* this one is only def-ed once, strangely... */
+#define GSS(x) (((uchar *)(x))[1] << 8 | ((uchar *)(x))[0])
+
+int IB_verbose = TRUE;
+
+ImBuf *IMB_ibImageFromMemory(int *mem, int size, int flags) {
+ int len;
+ struct ImBuf *ibuf;
+
+ if (mem == NULL) {
+ printf("Error in ibImageFromMemory: NULL pointer\n");
+ } else {
+ if ((GS(mem) == IMAGIC) || (GSS(mem) == IMAGIC)){
+ return (imb_loadiris((uchar *) mem, flags));
+ } else if (imb_is_a_jpeg((uchar *)mem)) {
+ return (imb_ibJpegImageFromMemory((uchar *)mem, size, flags));
+ }
+
+ if (GET_ID(mem) == CAT){
+ mem += 3;
+ size -= 4;
+ while (size > 0){
+ if (GET_ID(mem) == FORM){
+ len = ((GET_BIG_LONG(mem+1) + 1) & ~1) + 8;
+ if ((GET_ID(mem+2) == ILBM) || (GET_ID(mem+2) == ANIM)) break;
+ mem = (int *)((uchar *)mem +len);
+ size -= len;
+ } else return(0);
+ }
+ }
+
+ if (size > 0){
+ if (GET_ID(mem) == FORM){
+ if (GET_ID(mem+2) == ILBM){
+ return (imb_loadamiga(mem, flags));
+ } else if (GET_ID(mem+5) == ILBM){ /* animaties */
+ return (imb_loadamiga(mem+3, flags));
+ } else if (GET_ID(mem+2) == ANIM){
+ return (imb_loadanim(mem, flags));
+ }
+ }
+ }
+
+ ibuf = imb_loadpng((uchar *)mem, size, flags);
+ if (ibuf) return(ibuf);
+
+ ibuf = imb_bmp_decode((uchar *)mem, size, flags);
+ if (ibuf) return(ibuf);
+
+ ibuf = imb_loadtarga((uchar *)mem, flags);
+ if (ibuf) return(ibuf);
+
+ ibuf = imb_loaddpx((uchar *)mem, size, flags);
+ if (ibuf) return(ibuf);
+
+ ibuf = imb_loadcineon((uchar *)mem, size, flags);
+ if (ibuf) return(ibuf);
+
+ if (G.have_libtiff) {
+ ibuf = imb_loadtiff((uchar *)mem, size, flags);
+ if (ibuf) return(ibuf);
+ }
+
+ ibuf = imb_loadhdr((uchar*)mem, size, flags);
+ if (ibuf) return (ibuf);
+
+#ifdef WITH_OPENEXR
+ ibuf = imb_load_openexr((uchar *)mem, size, flags);
+ if (ibuf) return (ibuf);
+#endif
+
+#ifdef WITH_DDS
+ ibuf = imb_load_dds((uchar *)mem, size, flags);
+ if (ibuf) return (ibuf);
+#endif
+
+#ifdef WITH_QUICKTIME
+#if defined(_WIN32) || defined (__APPLE__)
+ if(G.have_quicktime) {
+ ibuf = imb_quicktime_decode((uchar *)mem, size, flags);
+ if (ibuf) return(ibuf);
+ }
+#endif
+#endif
+
+ if (IB_verbose) fprintf(stderr, "Unknown fileformat\n");
+ }
+
+ return (0);
+}
+
+
+struct ImBuf *IMB_loadiffmem(int *mem, int flags) {
+ int len,maxlen;
+ struct ImBuf *ibuf;
+
+ // IMB_loadiffmem shouldn't be used anymore in new development
+ // it's still here to be backwards compatible...
+
+ maxlen= (GET_BIG_LONG(mem+1) + 1) & ~1;
+
+ if (GET_ID(mem) == CAT){
+ mem += 3;
+ maxlen -= 4;
+ while(maxlen > 0){
+ if (GET_ID(mem) == FORM){
+ len = ((GET_BIG_LONG(mem+1) + 1) & ~1) + 8;
+ if ((GET_ID(mem+2) == ILBM) || (GET_ID(mem+2) == ANIM)) break;
+ mem = (int *)((uchar *)mem +len);
+ maxlen -= len;
+ } else return(0);
+ }
+ }
+
+ if (maxlen > 0){
+ if (GET_ID(mem) == FORM){
+ if (GET_ID(mem+2) == ILBM){
+ return (imb_loadamiga(mem, flags));
+ } else if (GET_ID(mem+5) == ILBM){ /* animaties */
+ return (imb_loadamiga(mem+3, flags));
+ } else if (GET_ID(mem+2) == ANIM){
+ return (imb_loadanim(mem, flags));
+ }
+ } else if ((GS(mem) == IMAGIC) || (GSS(mem) == IMAGIC)){
+ return (imb_loadiris((uchar *) mem,flags));
+ } else if ((BIG_LONG(mem[0]) & 0xfffffff0) == 0xffd8ffe0) {
+ return (0);
+ }
+ }
+
+ ibuf = imb_loadtarga((uchar *) mem,flags);
+ if (ibuf) return(ibuf);
+
+ if (IB_verbose) fprintf(stderr,"Unknown fileformat\n");
+ return (0);
+}
+
+struct ImBuf *IMB_loadifffile(int file, int flags) {
+ struct ImBuf *ibuf;
+ int size, *mem;
+
+ if (file == -1) return (0);
+
+ size = BLI_filesize(file);
+
+#if defined(AMIGA) || defined(__BeOS) || defined(WIN32)
+ mem= (int *)malloc(size);
+ if (mem==0) {
+ printf("Out of mem\n");
+ return (0);
+ }
+
+ if (read(file, mem, size)!=size){
+ printf("Read Error\n");
+ free(mem);
+ return (0);
+ }
+
+ ibuf = IMB_ibImageFromMemory(mem, size, flags);
+ free(mem);
+
+ /* for jpeg read */
+ lseek(file, 0L, SEEK_SET);
+
+#else
+ mem= (int *)mmap(0,size,PROT_READ,MAP_SHARED,file,0);
+ if (mem==(int *)-1){
+ printf("Couldn't get mapping\n");
+ return (0);
+ }
+
+ ibuf = IMB_ibImageFromMemory(mem, size, flags);
+
+ if (munmap( (void *) mem, size)){
+ printf("Couldn't unmap file.\n");
+ }
+#endif
+ return(ibuf);
+}
+
+
+struct ImBuf *IMB_loadiffname(const char *naam, int flags) {
+ int file;
+ struct ImBuf *ibuf;
+ int buf[1];
+
+ file = open(naam, O_BINARY|O_RDONLY);
+
+ if (file == -1) return (0);
+
+ ibuf= IMB_loadifffile(file, flags);
+
+ if (ibuf == NULL) {
+ if (read(file, buf, 4) != 4) buf[0] = 0;
+ if ((BIG_LONG(buf[0]) & 0xfffffff0) == 0xffd8ffe0)
+ ibuf = imb_ibJpegImageFromFilename(naam, flags);
+ }
+
+ if (ibuf) {
+ strncpy(ibuf->name, naam, sizeof(ibuf->name));
+ if (flags & IB_fields) IMB_de_interlace(ibuf);
+ }
+ close(file);
+ return(ibuf);
+}
+
+struct ImBuf *IMB_testiffname(char *naam,int flags) {
+ int file;
+ struct ImBuf *ibuf;
+
+ flags |= IB_test;
+ file = open(naam,O_BINARY|O_RDONLY);
+
+ if (file<=0) return (0);
+
+ ibuf=IMB_loadifffile(file,flags);
+ if (ibuf) {
+ strncpy(ibuf->name, naam, sizeof(ibuf->name));
+ }
+ close(file);
+ return(ibuf);
+}
diff --git a/source/blender/imbuf/intern/rectop.c b/source/blender/imbuf/intern/rectop.c
new file mode 100644
index 00000000000..63de3bd2355
--- /dev/null
+++ b/source/blender/imbuf/intern/rectop.c
@@ -0,0 +1,601 @@
+/**
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * allocimbuf.c
+ *
+ * $Id$
+ */
+
+#include "BLI_blenlib.h"
+
+#include "imbuf.h"
+#include "imbuf_patch.h"
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "IMB_allocimbuf.h"
+
+/* blend modes */
+
+static void blend_color_mix(char *cp, char *cp1, char *cp2, int fac)
+{
+ /* this and other blending modes previously used >>8 instead of /255. both
+ are not equivalent (>>8 is /256), and the former results in rounding
+ errors that can turn colors black fast after repeated blending */
+ int mfac= 255-fac;
+
+ cp[0]= (mfac*cp1[0]+fac*cp2[0])/255;
+ cp[1]= (mfac*cp1[1]+fac*cp2[1])/255;
+ cp[2]= (mfac*cp1[2]+fac*cp2[2])/255;
+}
+
+static void blend_color_add(char *cp, char *cp1, char *cp2, int fac)
+{
+ int temp;
+
+ temp= cp1[0] + ((fac*cp2[0])/255);
+ if(temp>254) cp[0]= 255; else cp[0]= temp;
+ temp= cp1[1] + ((fac*cp2[1])/255);
+ if(temp>254) cp[1]= 255; else cp[1]= temp;
+ temp= cp1[2] + ((fac*cp2[2])/255);
+ if(temp>254) cp[2]= 255; else cp[2]= temp;
+}
+
+static void blend_color_sub(char *cp, char *cp1, char *cp2, int fac)
+{
+ int temp;
+
+ temp= cp1[0] - ((fac*cp2[0])/255);
+ if(temp<0) cp[0]= 0; else cp[0]= temp;
+ temp= cp1[1] - ((fac*cp2[1])/255);
+ if(temp<0) cp[1]= 0; else cp[1]= temp;
+ temp= cp1[2] - ((fac*cp2[2])/255);
+ if(temp<0) cp[2]= 0; else cp[2]= temp;
+}
+
+static void blend_color_mul(char *cp, char *cp1, char *cp2, int fac)
+{
+ int mfac= 255-fac;
+
+ /* first mul, then blend the fac */
+ cp[0]= (mfac*cp1[0] + fac*((cp1[0]*cp2[0])/255))/255;
+ cp[1]= (mfac*cp1[1] + fac*((cp1[1]*cp2[1])/255))/255;
+ cp[2]= (mfac*cp1[2] + fac*((cp1[2]*cp2[2])/255))/255;
+}
+
+static void blend_color_lighten(char *cp, char *cp1, char *cp2, int fac)
+{
+ /* See if are lighter, if so mix, else dont do anything.
+ if the paint col is darker then the original, then ignore */
+ if (cp1[0]+cp1[1]+cp1[2] > cp2[0]+cp2[1]+cp2[2]) {
+ cp[0]= cp1[0];
+ cp[1]= cp1[1];
+ cp[2]= cp1[2];
+ }
+ else
+ blend_color_mix(cp, cp1, cp2, fac);
+}
+
+static void blend_color_darken(char *cp, char *cp1, char *cp2, int fac)
+{
+ /* See if were darker, if so mix, else dont do anything.
+ if the paint col is brighter then the original, then ignore */
+ if (cp1[0]+cp1[1]+cp1[2] < cp2[0]+cp2[1]+cp2[2]) {
+ cp[0]= cp1[0];
+ cp[1]= cp1[1];
+ cp[2]= cp1[2];
+ }
+ else
+ blend_color_mix(cp, cp1, cp2, fac);
+}
+
+unsigned int IMB_blend_color(unsigned int src1, unsigned int src2, int fac, IMB_BlendMode mode)
+{
+ unsigned int dst;
+ int temp;
+ char *cp, *cp1, *cp2;
+
+ if (fac==0)
+ return src1;
+
+ cp = (char*)&dst;
+ cp1 = (char*)&src1;
+ cp2 = (char*)&src2;
+
+ switch (mode) {
+ case IMB_BLEND_MIX:
+ blend_color_mix(cp, cp1, cp2, fac); break;
+ case IMB_BLEND_ADD:
+ blend_color_add(cp, cp1, cp2, fac); break;
+ case IMB_BLEND_SUB:
+ blend_color_sub(cp, cp1, cp2, fac); break;
+ case IMB_BLEND_MUL:
+ blend_color_mul(cp, cp1, cp2, fac); break;
+ case IMB_BLEND_LIGHTEN:
+ blend_color_lighten(cp, cp1, cp2, fac); break;
+ case IMB_BLEND_DARKEN:
+ blend_color_darken(cp, cp1, cp2, fac); break;
+ default:
+ cp[0]= cp1[0];
+ cp[1]= cp1[1];
+ cp[2]= cp1[2];
+ }
+
+ if (mode == IMB_BLEND_ERASE_ALPHA) {
+ temp= (cp1[3] - fac*cp2[3]/255);
+ cp[3]= (temp < 0)? 0: temp;
+ }
+ else { /* this does ADD_ALPHA also */
+ temp= (cp1[3] + fac*cp2[3]/255);
+ cp[3]= (temp > 255)? 255: temp;
+ }
+
+ return dst;
+}
+
+static void blend_color_mix_float(float *cp, float *cp1, float *cp2, float fac)
+{
+ float mfac= 1.0-fac;
+ cp[0]= mfac*cp1[0] + fac*cp2[0];
+ cp[1]= mfac*cp1[1] + fac*cp2[1];
+ cp[2]= mfac*cp1[2] + fac*cp2[2];
+}
+
+static void blend_color_add_float(float *cp, float *cp1, float *cp2, float fac)
+{
+ cp[0] = cp1[0] + fac*cp2[0];
+ cp[1] = cp1[1] + fac*cp2[1];
+ cp[2] = cp1[2] + fac*cp2[2];
+
+ if (cp[0] > 1.0f) cp[0]= 1.0f;
+ if (cp[1] > 1.0f) cp[1]= 1.0f;
+ if (cp[2] > 1.0f) cp[2]= 1.0f;
+}
+
+static void blend_color_sub_float(float *cp, float *cp1, float *cp2, float fac)
+{
+ cp[0] = cp1[0] - fac*cp2[0];
+ cp[1] = cp1[1] - fac*cp2[1];
+ cp[2] = cp1[2] - fac*cp2[2];
+
+ if (cp[0] < 0.0f) cp[0]= 0.0f;
+ if (cp[1] < 0.0f) cp[1]= 0.0f;
+ if (cp[2] < 0.0f) cp[2]= 0.0f;
+}
+
+static void blend_color_mul_float(float *cp, float *cp1, float *cp2, float fac)
+{
+ float mfac= 1.0-fac;
+
+ cp[0]= mfac*cp1[0] + fac*(cp1[0]*cp2[0]);
+ cp[1]= mfac*cp1[1] + fac*(cp1[1]*cp2[1]);
+ cp[2]= mfac*cp1[2] + fac*(cp1[2]*cp2[2]);
+}
+
+static void blend_color_lighten_float(float *cp, float *cp1, float *cp2, float fac)
+{
+ /* See if are lighter, if so mix, else dont do anything.
+ if the pafloat col is darker then the original, then ignore */
+ if (cp1[0]+cp1[1]+cp1[2] > cp2[0]+cp2[1]+cp2[2]) {
+ cp[0]= cp1[0];
+ cp[1]= cp1[1];
+ cp[2]= cp1[2];
+ }
+ else
+ blend_color_mix_float(cp, cp1, cp2, fac);
+}
+
+static void blend_color_darken_float(float *cp, float *cp1, float *cp2, float fac)
+{
+ /* See if were darker, if so mix, else dont do anything.
+ if the pafloat col is brighter then the original, then ignore */
+ if (cp1[0]+cp1[1]+cp1[2] < cp2[0]+cp2[1]+cp2[2]) {
+ cp[0]= cp1[0];
+ cp[1]= cp1[1];
+ cp[2]= cp1[2];
+ }
+ else
+ blend_color_mix_float(cp, cp1, cp2, fac);
+}
+
+void IMB_blend_color_float(float *dst, float *src1, float *src2, float fac, IMB_BlendMode mode)
+{
+ if (fac==0) {
+ dst[0]= src1[0];
+ dst[1]= src1[1];
+ dst[2]= src1[2];
+ dst[3]= src1[3];
+ return;
+ }
+
+ switch (mode) {
+ case IMB_BLEND_MIX:
+ blend_color_mix_float(dst, src1, src2, fac); break;
+ case IMB_BLEND_ADD:
+ blend_color_add_float(dst, src1, src2, fac); break;
+ case IMB_BLEND_SUB:
+ blend_color_sub_float(dst, src1, src2, fac); break;
+ case IMB_BLEND_MUL:
+ blend_color_mul_float(dst, src1, src2, fac); break;
+ case IMB_BLEND_LIGHTEN:
+ blend_color_lighten_float(dst, src1, src2, fac); break;
+ case IMB_BLEND_DARKEN:
+ blend_color_darken_float(dst, src1, src2, fac); break;
+ default:
+ dst[0]= src1[0];
+ dst[1]= src1[1];
+ dst[2]= src1[2];
+ }
+
+ if (mode == IMB_BLEND_ERASE_ALPHA) {
+ dst[3]= (src1[3] - fac*src2[3]);
+ if (dst[3] < 0.0f) dst[3] = 0.0f;
+ }
+ else { /* this does ADD_ALPHA also */
+ dst[3]= (src1[3] + fac*src2[3]);
+ if (dst[3] > 1.0f) dst[3] = 1.0f;
+ }
+}
+
+/* clipping */
+
+void IMB_rectclip(struct ImBuf *dbuf, struct ImBuf *sbuf, int *destx,
+ int *desty, int *srcx, int *srcy, int *width, int *height)
+{
+ int tmp;
+
+ if (dbuf == NULL) return;
+
+ if (*destx < 0) {
+ *srcx -= *destx;
+ *width += *destx;
+ *destx = 0;
+ }
+ if (*srcx < 0) {
+ *destx -= *srcx;
+ *width += *destx;
+ *srcx = 0;
+ }
+ if (*desty < 0) {
+ *srcy -= *desty;
+ *height += *desty;
+ *desty = 0;
+ }
+ if (*srcy < 0) {
+ *desty -= *srcy;
+ *height += *desty;
+ *srcy = 0;
+ }
+
+ tmp = dbuf->x - *destx;
+ if (*width > tmp) *width = tmp;
+ tmp = dbuf->y - *desty;
+ if (*height > tmp) *height = tmp;
+
+ if (sbuf) {
+ tmp = sbuf->x - *srcx;
+ if (*width > tmp) *width = tmp;
+ tmp = sbuf->y - *srcy;
+ if (*height > tmp) *height = tmp;
+ }
+
+ if ((*height <= 0) || (*width <= 0)) {
+ *width = 0;
+ *height = 0;
+ }
+}
+
+/* copy and blend */
+
+void IMB_rectcpy(struct ImBuf *dbuf, struct ImBuf *sbuf, int destx,
+ int desty, int srcx, int srcy, int width, int height)
+{
+ IMB_rectblend(dbuf, sbuf, destx, desty, srcx, srcy, width, height,
+ IMB_BLEND_COPY);
+}
+
+void IMB_rectblend(struct ImBuf *dbuf, struct ImBuf *sbuf, int destx,
+ int desty, int srcx, int srcy, int width, int height, IMB_BlendMode mode)
+{
+ unsigned int *drect = NULL, *srect = NULL, *dr, *sr;
+ float *drectf = NULL, *srectf = NULL, *drf, *srf;
+ int do_float, do_char, srcskip, destskip, x;
+
+ if (dbuf == NULL) return;
+
+ IMB_rectclip(dbuf, sbuf, &destx, &desty, &srcx, &srcy, &width, &height);
+
+ if (width == 0 || height == 0) return;
+ if (sbuf && sbuf->channels!=4) return;
+ if (dbuf->channels!=4) return;
+
+ do_char = (sbuf && sbuf->rect && dbuf->rect);
+ do_float = (sbuf && sbuf->rect_float && dbuf->rect_float);
+
+ if (do_char) drect = dbuf->rect + desty * dbuf->x + destx;
+ if (do_float) drectf = dbuf->rect_float + (desty * dbuf->x + destx)*4;
+
+ destskip = dbuf->x;
+
+ if (sbuf) {
+ if (do_char) srect = sbuf->rect + srcy * sbuf->x + srcx;
+ if (do_float) srectf = sbuf->rect_float + (srcy * sbuf->x + srcx)*4;
+ srcskip = sbuf->x;
+ } else {
+ srect = drect;
+ srectf = drectf;
+ srcskip = destskip;
+ }
+
+ if (mode == IMB_BLEND_COPY) {
+ /* copy */
+ for (;height > 0; height--) {
+ if (do_char) {
+ memcpy(drect,srect, width * sizeof(int));
+ drect += destskip;
+ srect += srcskip;
+ }
+
+ if (do_float) {
+ memcpy(drectf,srectf, width * sizeof(float) * 4);
+ drectf += destskip*4;
+ srectf += srcskip*4;
+ }
+ }
+ }
+ else if (mode == IMB_BLEND_COPY_RGB) {
+ /* copy rgb only */
+ for (;height > 0; height--) {
+ if (do_char) {
+ dr = drect;
+ sr = srect;
+ for (x=width; x > 0; x--, dr++, sr++) {
+ ((char*)dr)[0]= ((char*)sr)[0];
+ ((char*)dr)[1]= ((char*)sr)[1];
+ ((char*)dr)[2]= ((char*)sr)[2];
+ }
+ drect += destskip;
+ srect += srcskip;
+ }
+
+ if (do_float) {
+ drf = drectf;
+ srf = srectf;
+ for (x=width; x > 0; x--, drf+=4, srf+=4) {
+ drf[0]= srf[0];
+ drf[1]= srf[1];
+ drf[2]= srf[2];
+ }
+ drectf += destskip*4;
+ srectf += srcskip*4;
+ }
+ }
+ }
+ else if (mode == IMB_BLEND_COPY_ALPHA) {
+ /* copy alpha only */
+ for (;height > 0; height--) {
+ if (do_char) {
+ dr = drect;
+ sr = srect;
+ for (x=width; x > 0; x--, dr++, sr++)
+ ((char*)dr)[3]= ((char*)sr)[3];
+ drect += destskip;
+ srect += srcskip;
+ }
+
+ if (do_float) {
+ drf = drectf;
+ srf = srectf;
+ for (x=width; x > 0; x--, drf+=4, srf+=4)
+ drf[3]= srf[3];
+ drectf += destskip*4;
+ srectf += srcskip*4;
+ }
+ }
+ }
+ else {
+ /* blend */
+ for (;height > 0; height--) {
+ if (do_char) {
+ dr = drect;
+ sr = srect;
+ for (x=width; x > 0; x--, dr++, sr++)
+ *dr = IMB_blend_color(*dr, *sr, ((char*)sr)[3], mode);
+
+ drect += destskip;
+ srect += srcskip;
+ }
+
+ if (do_float) {
+ drf = drectf;
+ srf = srectf;
+ for (x=width; x > 0; x--, drf+=4, srf+=4)
+ IMB_blend_color_float(drf, drf, srf, srf[3], mode);
+
+ drectf += destskip*4;
+ srectf += srcskip*4;
+ }
+ }
+ }
+}
+
+void IMB_rectblend_torus(struct ImBuf *dbuf, struct ImBuf *sbuf, int destx,
+ int desty, int srcx, int srcy, int width, int height, IMB_BlendMode mode)
+{
+ int origw, origh, w, h;
+
+ if (dbuf->x == 0 || dbuf->y == 0 || sbuf->x == 0 || sbuf->y == 0)
+ return;
+
+ /* convert destination and source coordinates too be withing image */
+ destx = destx % dbuf->x;
+ if (destx < 0) destx += dbuf->x;
+ desty = desty % dbuf->y;
+ if (desty < 0) desty += dbuf->y;
+ srcx = srcx % sbuf->x;
+ if (srcx < 0) srcx += sbuf->x;
+ srcy = srcy % sbuf->y;
+ if (srcy < 0) srcy += sbuf->y;
+
+ /* clip width of blending area to destination imbuf, to avoid writing the
+ same pixel twice */
+ origw = w = (width > dbuf->x)? dbuf->x: width;
+ origh = h = (height > dbuf->y)? dbuf->y: height;
+
+ /* clip and blend */
+ IMB_rectclip(dbuf, sbuf, &destx, &desty, &srcx, &srcy, &w, &h);
+ IMB_rectblend(dbuf, sbuf, destx, desty, srcx, srcy, w, h, mode);
+
+ /* do 3 other rects if needed */
+ if (w < origw)
+ IMB_rectblend(dbuf, sbuf, (destx+w)%dbuf->x, desty, (srcx+w)%sbuf->x, srcy,
+ origw-w, h, mode);
+ if (h < origh)
+ IMB_rectblend(dbuf, sbuf, destx, (desty+h)%dbuf->y, srcx, (srcy+h)%sbuf->y,
+ w, origh-h, mode);
+ if ((w < origw) && (h < origh))
+ IMB_rectblend(dbuf, sbuf, (destx+w)%dbuf->x, (desty+h)%dbuf->y,
+ (srcx+w)%sbuf->x, (srcy+h)%sbuf->y, origw-w, origh-h, mode);
+}
+
+/* fill */
+
+void IMB_rectfill(struct ImBuf *drect, float col[4])
+{
+ int num;
+
+ if(drect->rect) {
+ unsigned int *rrect = drect->rect;
+ char ccol[4];
+
+ ccol[0]= (int)(col[0]*255);
+ ccol[1]= (int)(col[1]*255);
+ ccol[2]= (int)(col[2]*255);
+ ccol[3]= (int)(col[3]*255);
+
+ num = drect->x * drect->y;
+ for (;num > 0; num--)
+ *rrect++ = *((unsigned int*)ccol);
+ }
+
+ if(drect->rect_float) {
+ float *rrectf = drect->rect_float;
+
+ num = drect->x * drect->y;
+ for (;num > 0; num--) {
+ *rrectf++ = col[0];
+ *rrectf++ = col[1];
+ *rrectf++ = col[2];
+ *rrectf++ = col[3];
+ }
+ }
+}
+
+/* maybe we should use BKE_utildefines.h */
+#define FTOCHAR(val) (val<=0.0f ? 0: (val>=1.0f ? 255: (char)(255.99f*val)))
+#define CLAMP(a, b, c) if((a)<(b)) (a)=(b); else if((a)>(c)) (a)=(c)
+#define SWAP(type, a, b) { type sw_ap; sw_ap=(a); (a)=(b); (b)=sw_ap; }
+
+void buf_rectfill_area(unsigned char *rect, float *rectf, int width, int height, float *col, int x1, int y1, int x2, int y2)
+{
+ int i, j;
+ float a, ai;
+ if ((!rect && !rectf) || (!col) || col[3]==0.0)
+ return;
+
+ /* sanity checks for coords */
+ CLAMP(x1, 0, width);
+ CLAMP(x2, 0, width);
+ CLAMP(y1, 0, height);
+ CLAMP(y2, 0, height);
+
+ if (x1>x2) SWAP(int,x1,x2);
+ if (y1>y2) SWAP(int,y1,y2);
+ if (x1==x2 || y1==y2) return;
+
+ a = col[3];
+ ai = 1-a;
+
+
+ if (rect) {
+ unsigned char *pixel;
+ unsigned char chr=0, chg=0, chb=0;
+ float fr=0, fg=0, fb=0;
+
+ if (a == 1.0) {
+ chr = FTOCHAR(col[0]);
+ chg = FTOCHAR(col[1]);
+ chb = FTOCHAR(col[2]);
+ } else {
+ fr = col[0]*a;
+ fg = col[1]*a;
+ fb = col[2]*a;
+ }
+ for (j = 0; j < y2-y1; j++) {
+ for (i = 0; i < x2-x1; i++) {
+ pixel = rect + 4 * (((y1 + j) * width) + (x1 + i));
+ if (pixel >= rect && pixel < rect+ (4 * (width * height))) {
+ if (a == 1.0) {
+ pixel[0] = chr;
+ pixel[1] = chg;
+ pixel[2] = chb;
+ } else {
+ pixel[0] = (char)(fr + ((float)pixel[0]*ai));
+ pixel[1] = (char)(fg + ((float)pixel[1]*ai));
+ pixel[2] = (char)(fb + ((float)pixel[2]*ai));
+ }
+ }
+ }
+ }
+ }
+
+ if (rectf) {
+ float *pixel;
+ for (j = 0; j < y2-y1; j++) {
+ for (i = 0; i < x2-x1; i++) {
+ pixel = rectf + 4 * (((y1 + j) * width) + (x1 + i));
+ if (a == 1.0) {
+ pixel[0] = col[0];
+ pixel[1] = col[1];
+ pixel[2] = col[2];
+ } else {
+ pixel[0] = (col[0]*a) + (pixel[0]*ai);
+ pixel[1] = (col[1]*a) + (pixel[1]*ai);
+ pixel[2] = (col[2]*a) + (pixel[2]*ai);
+ }
+ }
+ }
+ }
+}
+
+void IMB_rectfill_area(struct ImBuf *ibuf, float *col, int x1, int y1, int x2, int y2)
+{
+ if (!ibuf) return;
+ buf_rectfill_area((unsigned char *) ibuf->rect, ibuf->rect_float, ibuf->x, ibuf->y, col, x1, y1, x2, y2);
+}
diff --git a/source/blender/imbuf/intern/rotate.c b/source/blender/imbuf/intern/rotate.c
new file mode 100644
index 00000000000..42b30d6284f
--- /dev/null
+++ b/source/blender/imbuf/intern/rotate.c
@@ -0,0 +1,120 @@
+/**
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * rotate.c
+ *
+ * $Id$
+ */
+
+#include "BLI_blenlib.h"
+
+#include "imbuf.h"
+#include "imbuf_patch.h"
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "IMB_allocimbuf.h"
+
+void IMB_flipy(struct ImBuf * ibuf)
+{
+ short x, y;
+ unsigned int *top, *bottom, do_float=0, *line;
+ float *topf=NULL, *bottomf=NULL, *linef=NULL;
+
+ if (ibuf == NULL) return;
+ if (ibuf->rect == NULL) return;
+
+ if (ibuf->rect_float) do_float =1;
+
+ x = ibuf->x;
+ y = ibuf->y;
+
+ top = ibuf->rect;
+ bottom = top + ((y-1) * x);
+ line= MEM_mallocN(x*sizeof(int), "linebuf");
+
+ if (do_float) {
+ topf= ibuf->rect_float;
+ bottomf = topf + 4*((y-1) * x);
+ linef= MEM_mallocN(4*x*sizeof(float), "linebuff");
+ }
+ y >>= 1;
+
+ for(;y>0;y--) {
+
+ memcpy(line, top, x*sizeof(int));
+ memcpy(top, bottom, x*sizeof(int));
+ memcpy(bottom, line, x*sizeof(int));
+ bottom -= x;
+ top+= x;
+
+ if(do_float) {
+ memcpy(linef, topf, 4*x*sizeof(float));
+ memcpy(topf, bottomf, 4*x*sizeof(float));
+ memcpy(bottomf, linef, 4*x*sizeof(float));
+ bottomf -= 4*x;
+ topf+= 4*x;
+ }
+ }
+
+ MEM_freeN(line);
+ if(linef) MEM_freeN(linef);
+}
+
+void IMB_flipx(struct ImBuf * ibuf)
+{
+ short x, y, xr, xl, yi;
+ unsigned int px;
+ float px_f[4];
+
+ if (ibuf == NULL) return;
+
+ x = ibuf->x;
+ y = ibuf->y;
+
+ if (ibuf->rect) {
+ for(yi=y-1;yi>=0;yi--) {
+ for(xr=x-1, xl=0; xr>=xl; xr--, xl++) {
+ px = ibuf->rect[(x*yi)+xr];
+ ibuf->rect[(x*yi)+xr] = ibuf->rect[(x*yi)+xl];
+ ibuf->rect[(x*yi)+xl] = px;
+ }
+ }
+ }
+
+ if (ibuf->rect_float) {
+ for(yi=y-1;yi>=0;yi--) {
+ for(xr=x-1, xl=0; xr>=xl; xr--, xl++) {
+ memcpy(&px_f, &ibuf->rect_float[((x*yi)+xr)*4], 4*sizeof(float));
+ memcpy(&ibuf->rect_float[((x*yi)+xr)*4], &ibuf->rect_float[((x*yi)+xl)*4], 4*sizeof(float));
+ memcpy(&ibuf->rect_float[((x*yi)+xl)*4], &px_f, 4*sizeof(float));
+ }
+ }
+ }
+}
diff --git a/source/blender/imbuf/intern/scaling.c b/source/blender/imbuf/intern/scaling.c
new file mode 100644
index 00000000000..cd933cb0767
--- /dev/null
+++ b/source/blender/imbuf/intern/scaling.c
@@ -0,0 +1,1267 @@
+/**
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * allocimbuf.c
+ *
+ * $Id$
+ */
+
+#include "BLI_blenlib.h"
+
+#include "imbuf.h"
+#include "imbuf_patch.h"
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "IMB_allocimbuf.h"
+#include "IMB_filter.h"
+
+/************************************************************************/
+/* SCALING */
+/************************************************************************/
+
+
+struct ImBuf *IMB_half_x(struct ImBuf *ibuf1)
+{
+ struct ImBuf *ibuf2;
+ uchar *p1,*_p1,*dest;
+ short a,r,g,b,x,y;
+ float af,rf,gf,bf, *p1f, *_p1f, *destf;
+ int do_rect, do_float;
+
+ if (ibuf1==NULL) return (0);
+ if (ibuf1->rect==NULL && ibuf1->rect_float==NULL) return (0);
+
+ do_rect= (ibuf1->rect != NULL);
+ do_float= (ibuf1->rect_float != NULL);
+
+ if (ibuf1->x <= 1) return(IMB_dupImBuf(ibuf1));
+
+ ibuf2 = IMB_allocImBuf((ibuf1->x)/2, ibuf1->y, ibuf1->depth, ibuf1->flags, 0);
+ if (ibuf2==NULL) return (0);
+
+ _p1 = (uchar *) ibuf1->rect;
+ dest=(uchar *) ibuf2->rect;
+
+ _p1f = ibuf1->rect_float;
+ destf= ibuf2->rect_float;
+
+ for(y=ibuf2->y;y>0;y--){
+ p1 = _p1;
+ p1f = _p1f;
+ for(x = ibuf2->x ; x>0 ; x--){
+ if (do_rect) {
+ a = *(p1++) ;
+ b = *(p1++) ;
+ g = *(p1++) ;
+ r = *(p1++);
+ a += *(p1++) ;
+ b += *(p1++) ;
+ g += *(p1++) ;
+ r += *(p1++);
+ *(dest++) = a >> 1;
+ *(dest++) = b >> 1;
+ *(dest++) = g >> 1;
+ *(dest++) = r >> 1;
+ }
+ if (do_float) {
+ af = *(p1f++);
+ bf = *(p1f++);
+ gf = *(p1f++);
+ rf = *(p1f++);
+ af += *(p1f++);
+ bf += *(p1f++);
+ gf += *(p1f++);
+ rf += *(p1f++);
+ *(destf++) = 0.5f*af;
+ *(destf++) = 0.5f*bf;
+ *(destf++) = 0.5f*gf;
+ *(destf++) = 0.5f*rf;
+ }
+ }
+ if (do_rect) _p1 += (ibuf1->x << 2);
+ if (do_float) _p1f += (ibuf1->x << 2);
+ }
+ return (ibuf2);
+}
+
+
+struct ImBuf *IMB_double_fast_x(struct ImBuf *ibuf1)
+{
+ struct ImBuf *ibuf2;
+ int *p1,*dest, i, col, do_rect, do_float;
+ float *p1f, *destf;
+
+ if (ibuf1==NULL) return (0);
+ if (ibuf1->rect==NULL && ibuf1->rect_float==NULL) return (0);
+
+ do_rect= (ibuf1->rect != NULL);
+ do_float= (ibuf1->rect_float != NULL);
+
+ ibuf2 = IMB_allocImBuf(2 * ibuf1->x , ibuf1->y , ibuf1->depth, ibuf1->flags, 0);
+ if (ibuf2==NULL) return (0);
+
+ p1 = (int *) ibuf1->rect;
+ dest=(int *) ibuf2->rect;
+ p1f = (float *)ibuf1->rect_float;
+ destf = (float *)ibuf2->rect_float;
+
+ for(i = ibuf1->y * ibuf1->x ; i>0 ; i--) {
+ if (do_rect) {
+ col = *p1++;
+ *dest++ = col;
+ *dest++ = col;
+ }
+ if (do_float) {
+ destf[0]= destf[4] =p1f[0];
+ destf[1]= destf[5] =p1f[1];
+ destf[2]= destf[6] =p1f[2];
+ destf[3]= destf[7] =p1f[3];
+ destf+= 8;
+ p1f+= 4;
+ }
+ }
+
+ return (ibuf2);
+}
+
+struct ImBuf *IMB_double_x(struct ImBuf *ibuf1)
+{
+ struct ImBuf *ibuf2;
+
+ if (ibuf1==NULL) return (0);
+ if (ibuf1->rect==NULL && ibuf1->rect_float==NULL) return (0);
+
+ ibuf2 = IMB_double_fast_x(ibuf1);
+
+ imb_filterx(ibuf2);
+ return (ibuf2);
+}
+
+
+struct ImBuf *IMB_half_y(struct ImBuf *ibuf1)
+{
+ struct ImBuf *ibuf2;
+ uchar *p1,*p2,*_p1,*dest;
+ short a,r,g,b,x,y;
+ int do_rect, do_float;
+ float af,rf,gf,bf,*p1f,*p2f,*_p1f,*destf;
+
+ p1= p2= NULL;
+ p1f= p2f= NULL;
+ if (ibuf1==NULL) return (0);
+ if (ibuf1->rect==NULL && ibuf1->rect_float==NULL) return (0);
+ if (ibuf1->y <= 1) return(IMB_dupImBuf(ibuf1));
+
+ do_rect= (ibuf1->rect != NULL);
+ do_float= (ibuf1->rect_float != NULL);
+
+ ibuf2 = IMB_allocImBuf(ibuf1->x , (ibuf1->y) / 2 , ibuf1->depth, ibuf1->flags, 0);
+ if (ibuf2==NULL) return (0);
+
+ _p1 = (uchar *) ibuf1->rect;
+ dest=(uchar *) ibuf2->rect;
+ _p1f = (float *) ibuf1->rect_float;
+ destf= (float *) ibuf2->rect_float;
+
+ for(y=ibuf2->y ; y>0 ; y--){
+ if (do_rect) {
+ p1 = _p1;
+ p2 = _p1 + (ibuf1->x << 2);
+ }
+ if (do_float) {
+ p1f = _p1f;
+ p2f = _p1f + (ibuf1->x << 2);
+ }
+ for(x = ibuf2->x ; x>0 ; x--){
+ if (do_rect) {
+ a = *(p1++) ;
+ b = *(p1++) ;
+ g = *(p1++) ;
+ r = *(p1++);
+ a += *(p2++) ;
+ b += *(p2++) ;
+ g += *(p2++) ;
+ r += *(p2++);
+ *(dest++) = a >> 1;
+ *(dest++) = b >> 1;
+ *(dest++) = g >> 1;
+ *(dest++) = r >> 1;
+ }
+ if (do_float) {
+ af = *(p1f++) ;
+ bf = *(p1f++) ;
+ gf = *(p1f++) ;
+ rf = *(p1f++);
+ af += *(p2f++) ;
+ bf += *(p2f++) ;
+ gf += *(p2f++) ;
+ rf += *(p2f++);
+ *(destf++) = 0.5f*af;
+ *(destf++) = 0.5f*bf;
+ *(destf++) = 0.5f*gf;
+ *(destf++) = 0.5f*rf;
+ }
+ }
+ if (do_rect) _p1 += (ibuf1->x << 3);
+ if (do_float) _p1f += (ibuf1->x << 3);
+ }
+ return (ibuf2);
+}
+
+
+struct ImBuf *IMB_double_fast_y(struct ImBuf *ibuf1)
+{
+ struct ImBuf *ibuf2;
+ int *p1, *dest1, *dest2;
+ float *p1f, *dest1f, *dest2f;
+ short x,y;
+ int do_rect, do_float;
+
+ if (ibuf1==NULL) return (0);
+ if (ibuf1->rect==NULL && ibuf1->rect_float==NULL) return (0);
+
+ do_rect= (ibuf1->rect != NULL);
+ do_float= (ibuf1->rect_float != NULL);
+
+ ibuf2 = IMB_allocImBuf(ibuf1->x , 2 * ibuf1->y , ibuf1->depth, ibuf1->flags, 0);
+ if (ibuf2==NULL) return (0);
+
+ p1 = (int *) ibuf1->rect;
+ dest1= (int *) ibuf2->rect;
+ p1f = (float *) ibuf1->rect_float;
+ dest1f= (float *) ibuf2->rect_float;
+
+ for(y = ibuf1->y ; y>0 ; y--){
+ if (do_rect) {
+ dest2 = dest1 + ibuf2->x;
+ for(x = ibuf2->x ; x>0 ; x--) *dest1++ = *dest2++ = *p1++;
+ dest1 = dest2;
+ }
+ if (do_float) {
+ dest2f = dest1f + (4*ibuf2->x);
+ for(x = ibuf2->x*4 ; x>0 ; x--) *dest1f++ = *dest2f++ = *p1f++;
+ dest1f = dest2f;
+ }
+ }
+
+ return (ibuf2);
+}
+
+struct ImBuf *IMB_double_y(struct ImBuf *ibuf1)
+{
+ struct ImBuf *ibuf2;
+
+ if (ibuf1==NULL) return (0);
+ if (ibuf1->rect==NULL) return (0);
+
+ ibuf2 = IMB_double_fast_y(ibuf1);
+
+ IMB_filtery(ibuf2);
+ return (ibuf2);
+}
+
+
+struct ImBuf *IMB_onehalf(struct ImBuf *ibuf1)
+{
+ struct ImBuf *ibuf2;
+ uchar *p1, *p2 = NULL, *dest;
+ float *p1f, *destf, *p2f = NULL;
+ int x,y;
+ int do_rect, do_float;
+
+ if (ibuf1==NULL) return (0);
+ if (ibuf1->rect==NULL && ibuf1->rect_float==NULL) return (0);
+
+ do_rect= (ibuf1->rect != NULL);
+ do_float= (ibuf1->rect_float != NULL);
+
+ if (ibuf1->x <= 1) return(IMB_half_y(ibuf1));
+ if (ibuf1->y <= 1) return(IMB_half_x(ibuf1));
+
+ ibuf2=IMB_allocImBuf((ibuf1->x)/2, (ibuf1->y)/2, ibuf1->depth, ibuf1->flags, 0);
+ if (ibuf2==NULL) return (0);
+
+ p1f = ibuf1->rect_float;
+ destf=ibuf2->rect_float;
+ p1 = (uchar *) ibuf1->rect;
+ dest=(uchar *) ibuf2->rect;
+
+ for(y=ibuf2->y;y>0;y--){
+ if (do_rect) p2 = p1 + (ibuf1->x << 2);
+ if (do_float) p2f = p1f + (ibuf1->x << 2);
+ for(x=ibuf2->x;x>0;x--){
+ if (do_rect) {
+ dest[0] = (p1[0] + p2[0] + p1[4] + p2[4]) >> 2;
+ dest[1] = (p1[1] + p2[1] + p1[5] + p2[5]) >> 2;
+ dest[2] = (p1[2] + p2[2] + p1[6] + p2[6]) >> 2;
+ dest[3] = (p1[3] + p2[3] + p1[7] + p2[7]) >> 2;
+ p1 += 8;
+ p2 += 8;
+ dest += 4;
+ }
+ if (do_float){
+ destf[0] = 0.25f*(p1f[0] + p2f[0] + p1f[4] + p2f[4]);
+ destf[1] = 0.25f*(p1f[1] + p2f[1] + p1f[5] + p2f[5]);
+ destf[2] = 0.25f*(p1f[2] + p2f[2] + p1f[6] + p2f[6]);
+ destf[3] = 0.25f*(p1f[3] + p2f[3] + p1f[7] + p2f[7]);
+ p1f += 8;
+ p2f += 8;
+ destf += 4;
+ }
+ }
+ if (do_rect) p1=p2;
+ if (do_float) p1f=p2f;
+ if(ibuf1->x & 1) {
+ if (do_rect) p1+=4;
+ if (do_float) p1f+=4;
+ }
+ }
+ return (ibuf2);
+}
+
+
+
+struct ImBuf *IMB_onethird(struct ImBuf *ibuf1)
+{
+ struct ImBuf *ibuf2;
+ uchar *p1,*p2,*p3,*dest;
+ float *p1f, *p2f, *p3f, *destf;
+ int do_rect, do_float;
+ short a,r,g,b,x,y,i;
+ float af,rf,gf,bf;
+
+ p2= p3= NULL;
+ p2f= p3f= NULL;
+ if (ibuf1==NULL) return (0);
+ if (ibuf1->rect==NULL && ibuf1->rect_float==NULL) return (0);
+
+ do_rect= (ibuf1->rect != NULL);
+ do_float= (ibuf1->rect_float != NULL);
+
+ ibuf2=IMB_allocImBuf((ibuf1->x)/3, (ibuf1->y)/3, ibuf1->depth, ibuf1->flags, 0);
+ if (ibuf2==NULL) return (0);
+
+ p1f = ibuf1->rect_float;
+ destf = ibuf2->rect_float;
+ p1 = (uchar *) ibuf1->rect;
+ dest=(uchar *) ibuf2->rect;
+
+ for(y=ibuf2->y;y>0;y--){
+ if (do_rect) {
+ p2 = p1 + (ibuf1->x << 2);
+ p3 = p2 + (ibuf1->x << 2);
+ }
+ if (do_float) {
+ p2f = p1f + (ibuf1->x <<2);
+ p3f = p2f + (ibuf1->x <<2);
+ }
+ for(x=ibuf2->x;x>0;x--){
+ a=r=g=b=0;
+ af=rf=gf=bf=0;
+ for (i=3;i>0;i--){
+ if (do_rect) {
+ a += *(p1++) + *(p2++) + *(p3++);
+ b += *(p1++) + *(p2++) + *(p3++);
+ g += *(p1++) + *(p2++) + *(p3++);
+ r += *(p1++) + *(p2++) + *(p3++);
+ }
+ if (do_float) {
+ af += *(p1f++) + *(p2f++) + *(p3f++);
+ bf += *(p1f++) + *(p2f++) + *(p3f++);
+ gf += *(p1f++) + *(p2f++) + *(p3f++);
+ rf += *(p1f++) + *(p2f++) + *(p3f++);
+ }
+ }
+ if (do_rect) {
+ *(dest++) = a/9;
+ *(dest++) = b/9;
+ *(dest++) = g/9;
+ *(dest++) = r/9;
+ }
+ if (do_float) {
+ *(destf++) = af/9.0f;
+ *(destf++) = bf/9.0f;
+ *(destf++) = gf/9.0f;
+ *(destf++) = rf/9.0f;
+ }
+ }
+ if (do_rect) p1=p3;
+ if (do_float) p1f = p3f;
+ }
+ return (ibuf2);
+}
+
+
+struct ImBuf *IMB_halflace(struct ImBuf *ibuf1)
+{
+ struct ImBuf *ibuf2;
+ uchar *p1,*p2,*dest;
+ float *p1f,*p2f,*destf;
+ short a,r,g,b,x,y,i;
+ float af,rf,gf,bf;
+ int do_rect, do_float;
+
+ p2= NULL;
+ p2f= NULL;
+ if (ibuf1==NULL) return (0);
+ if (ibuf1->rect==NULL && ibuf1->rect_float==NULL) return (0);
+
+ do_rect= (ibuf1->rect != NULL);
+ do_float= (ibuf1->rect_float != NULL);
+
+ ibuf2=IMB_allocImBuf((ibuf1->x)/4, (ibuf1->y)/2, ibuf1->depth, ibuf1->flags, 0);
+ if (ibuf2==NULL) return (0);
+
+ p1f = ibuf1->rect_float;
+ destf= ibuf2->rect_float;
+ p1 = (uchar *) ibuf1->rect;
+ dest=(uchar *) ibuf2->rect;
+
+ for(y= ibuf2->y / 2 ; y>0;y--){
+ if (do_rect) p2 = p1 + (ibuf1->x << 3);
+ if (do_float) p2f = p1f + (ibuf1->x << 3);
+ for(x = 2 * ibuf2->x;x>0;x--){
+ a=r=g=b=0;
+ af=rf=gf=bf=0;
+ for (i=4;i>0;i--){
+ if (do_rect) {
+ a += *(p1++) + *(p2++);
+ b += *(p1++) + *(p2++);
+ g += *(p1++) + *(p2++);
+ r += *(p1++) + *(p2++);
+ }
+ if (do_float) {
+ af += *(p1f++) + *(p2f++);
+ bf += *(p1f++) + *(p2f++);
+ gf += *(p1f++) + *(p2f++);
+ rf += *(p1f++) + *(p2f++);
+ }
+ }
+ if (do_rect) {
+ *(dest++) = a >> 3;
+ *(dest++) = b >> 3;
+ *(dest++) = g >> 3;
+ *(dest++) = r >> 3;
+ }
+ if (do_float) {
+ *(destf++) = 0.125f*af;
+ *(destf++) = 0.125f*bf;
+ *(destf++) = 0.125f*gf;
+ *(destf++) = 0.125f*rf;
+ }
+ }
+ if (do_rect) p1 = p2;
+ if (do_float) p1f = p2f;
+ }
+ return (ibuf2);
+}
+
+
+static struct ImBuf *scaledownx(struct ImBuf *ibuf, int newx)
+{
+ uchar *rect, *_newrect, *newrect;
+ float *rectf, *_newrectf, *newrectf;
+ float sample, add, val[4], nval[4], valf[4], nvalf[4];
+ int x, y, do_rect = 0, do_float = 0;
+
+ rectf= _newrectf= newrectf= NULL;
+ rect=_newrect= newrect= NULL;
+ nval[0]= nval[1]= nval[2]= nval[3]= 0.0f;
+ nvalf[0]=nvalf[1]=nvalf[2]=nvalf[3]= 0.0f;
+
+ if (ibuf==NULL) return(0);
+ if (ibuf->rect==NULL && ibuf->rect_float==NULL) return (ibuf);
+
+ if (ibuf->rect) {
+ do_rect = 1;
+ _newrect = MEM_mallocN(newx * ibuf->y * sizeof(int), "scaledownx");
+ if (_newrect==NULL) return(ibuf);
+ }
+ if (ibuf->rect_float) {
+ do_float = 1;
+ _newrectf = MEM_mallocN(newx * ibuf->y * sizeof(float) * 4, "scaledownxf");
+ if (_newrectf==NULL) {
+ if (_newrect) MEM_freeN(_newrect);
+ return(ibuf);
+ }
+ }
+
+ add = (ibuf->x - 0.001) / newx;
+
+ if (do_rect) {
+ rect = (uchar *) ibuf->rect;
+ newrect = _newrect;
+ }
+ if (do_float) {
+ rectf = ibuf->rect_float;
+ newrectf = _newrectf;
+ }
+
+ for (y = ibuf->y; y>0 ; y--) {
+ sample = 0.0f;
+ val[0]= val[1]= val[2]= val[3]= 0.0f;
+ valf[0]=valf[1]=valf[2]=valf[3]= 0.0f;
+
+ for (x = newx ; x>0 ; x--) {
+ if (do_rect) {
+ nval[0] = - val[0] * sample;
+ nval[1] = - val[1] * sample;
+ nval[2] = - val[2] * sample;
+ nval[3] = - val[3] * sample;
+ }
+ if (do_float) {
+ nvalf[0] = - valf[0] * sample;
+ nvalf[1] = - valf[1] * sample;
+ nvalf[2] = - valf[2] * sample;
+ nvalf[3] = - valf[3] * sample;
+ }
+
+ sample += add;
+
+ while (sample >= 1.0f){
+ sample -= 1.0f;
+
+ if (do_rect) {
+ nval[0] += rect[0];
+ nval[1] += rect[1];
+ nval[2] += rect[2];
+ nval[3] += rect[3];
+ rect += 4;
+ }
+ if (do_float) {
+ nvalf[0] += rectf[0];
+ nvalf[1] += rectf[1];
+ nvalf[2] += rectf[2];
+ nvalf[3] += rectf[3];
+ rectf += 4;
+ }
+ }
+
+ if (do_rect) {
+ val[0]= rect[0];val[1]= rect[1];val[2]= rect[2];val[3]= rect[3];
+ rect += 4;
+
+ newrect[0] = ((nval[0] + sample * val[0])/add + 0.5f);
+ newrect[1] = ((nval[1] + sample * val[1])/add + 0.5f);
+ newrect[2] = ((nval[2] + sample * val[2])/add + 0.5f);
+ newrect[3] = ((nval[3] + sample * val[3])/add + 0.5f);
+
+ newrect += 4;
+ }
+ if (do_float) {
+
+ valf[0]= rectf[0];valf[1]= rectf[1];valf[2]= rectf[2];valf[3]= rectf[3];
+ rectf += 4;
+
+ newrectf[0] = ((nvalf[0] + sample * valf[0])/add);
+ newrectf[1] = ((nvalf[1] + sample * valf[1])/add);
+ newrectf[2] = ((nvalf[2] + sample * valf[2])/add);
+ newrectf[3] = ((nvalf[3] + sample * valf[3])/add);
+
+ newrectf += 4;
+ }
+
+ sample -= 1.0f;
+ }
+ }
+
+ if (do_rect) {
+ imb_freerectImBuf(ibuf);
+ ibuf->mall |= IB_rect;
+ ibuf->rect = (unsigned int *) _newrect;
+ }
+ if (do_float) {
+ imb_freerectfloatImBuf(ibuf);
+ ibuf->mall |= IB_rectfloat;
+ ibuf->rect_float = _newrectf;
+ }
+
+ ibuf->x = newx;
+ return(ibuf);
+}
+
+
+static struct ImBuf *scaledowny(struct ImBuf *ibuf, int newy)
+{
+ uchar *rect, *_newrect, *newrect;
+ float *rectf, *_newrectf, *newrectf;
+ float sample, add, val[4], nval[4], valf[4], nvalf[4];
+ int x, y, skipx, do_rect = 0, do_float = 0;
+
+ rectf= _newrectf= newrectf= NULL;
+ rect= _newrect= newrect= NULL;
+ nval[0]= nval[1]= nval[2]= nval[3]= 0.0f;
+ nvalf[0]=nvalf[1]=nvalf[2]=nvalf[3]= 0.0f;
+
+ if (ibuf==NULL) return(0);
+ if (ibuf->rect==NULL && ibuf->rect_float==NULL) return (ibuf);
+
+ if (ibuf->rect) {
+ do_rect = 1;
+ _newrect = MEM_mallocN(newy * ibuf->x * sizeof(int), "scaledowny");
+ if (_newrect==NULL) return(ibuf);
+ }
+ if (ibuf->rect_float) {
+ do_float = 1;
+ _newrectf = MEM_mallocN(newy * ibuf->x * sizeof(float) * 4, "scaldownyf");
+ if (_newrectf==NULL) {
+ if (_newrect) MEM_freeN(_newrect);
+ return(ibuf);
+ }
+ }
+
+ add = (ibuf->y - 0.001) / newy;
+ skipx = 4 * ibuf->x;
+
+ for (x = skipx - 4; x>=0 ; x-= 4) {
+ if (do_rect) {
+ rect = ((uchar *) ibuf->rect) + x;
+ newrect = _newrect + x;
+ }
+ if (do_float) {
+ rectf = ibuf->rect_float + x;
+ newrectf = _newrectf + x;
+ }
+
+ sample = 0.0f;
+ val[0]= val[1]= val[2]= val[3]= 0.0f;
+ valf[0]=valf[1]=valf[2]=valf[3]= 0.0f;
+
+ for (y = newy ; y>0 ; y--) {
+ if (do_rect) {
+ nval[0] = - val[0] * sample;
+ nval[1] = - val[1] * sample;
+ nval[2] = - val[2] * sample;
+ nval[3] = - val[3] * sample;
+ }
+ if (do_float) {
+ nvalf[0] = - valf[0] * sample;
+ nvalf[1] = - valf[1] * sample;
+ nvalf[2] = - valf[2] * sample;
+ nvalf[3] = - valf[3] * sample;
+ }
+
+ sample += add;
+
+ while (sample >= 1.0) {
+ sample -= 1.0;
+
+ if (do_rect) {
+ nval[0] += rect[0];
+ nval[1] += rect[1];
+ nval[2] += rect[2];
+ nval[3] += rect[3];
+ rect += skipx;
+ }
+ if (do_float) {
+ nvalf[0] += rectf[0];
+ nvalf[1] += rectf[1];
+ nvalf[2] += rectf[2];
+ nvalf[3] += rectf[3];
+ rectf += skipx;
+ }
+ }
+
+ if (do_rect) {
+ val[0]= rect[0];val[1]= rect[1];val[2]= rect[2];val[3]= rect[3];
+ rect += skipx;
+
+ newrect[0] = ((nval[0] + sample * val[0])/add + 0.5f);
+ newrect[1] = ((nval[1] + sample * val[1])/add + 0.5f);
+ newrect[2] = ((nval[2] + sample * val[2])/add + 0.5f);
+ newrect[3] = ((nval[3] + sample * val[3])/add + 0.5f);
+
+ newrect += skipx;
+ }
+ if (do_float) {
+
+ valf[0]= rectf[0];valf[1]= rectf[1];valf[2]= rectf[2];valf[3]= rectf[3];
+ rectf += skipx;
+
+ newrectf[0] = ((nvalf[0] + sample * valf[0])/add);
+ newrectf[1] = ((nvalf[1] + sample * valf[1])/add);
+ newrectf[2] = ((nvalf[2] + sample * valf[2])/add);
+ newrectf[3] = ((nvalf[3] + sample * valf[3])/add);
+
+ newrectf += skipx;
+ }
+
+ sample -= 1.0;
+ }
+ }
+
+ if (do_rect) {
+ imb_freerectImBuf(ibuf);
+ ibuf->mall |= IB_rect;
+ ibuf->rect = (unsigned int *) _newrect;
+ }
+ if (do_float) {
+ imb_freerectfloatImBuf(ibuf);
+ ibuf->mall |= IB_rectfloat;
+ ibuf->rect_float = (float *) _newrectf;
+ }
+
+ ibuf->y = newy;
+ return(ibuf);
+}
+
+
+static struct ImBuf *scaleupx(struct ImBuf *ibuf, int newx)
+{
+ uchar *rect,*_newrect=NULL,*newrect;
+ float *rectf,*_newrectf=NULL,*newrectf;
+ float sample,add;
+ float val_a,nval_a,diff_a;
+ float val_b,nval_b,diff_b;
+ float val_g,nval_g,diff_g;
+ float val_r,nval_r,diff_r;
+ float val_af,nval_af,diff_af;
+ float val_bf,nval_bf,diff_bf;
+ float val_gf,nval_gf,diff_gf;
+ float val_rf,nval_rf,diff_rf;
+ int x,y, do_rect = 0, do_float = 0;
+
+ val_a = nval_a = diff_a = val_b = nval_b = diff_b = 0;
+ val_g = nval_g = diff_g = val_r = nval_r = diff_r = 0;
+ val_af = nval_af = diff_af = val_bf = nval_bf = diff_bf = 0;
+ val_gf = nval_gf = diff_gf = val_rf = nval_rf = diff_rf = 0;
+ if (ibuf==NULL) return(0);
+ if (ibuf->rect==NULL && ibuf->rect_float==NULL) return (ibuf);
+
+ if (ibuf->rect) {
+ do_rect = 1;
+ _newrect = MEM_mallocN(newx * ibuf->y * sizeof(int), "scaleupx");
+ if (_newrect==NULL) return(ibuf);
+ }
+ if (ibuf->rect_float) {
+ do_float = 1;
+ _newrectf = MEM_mallocN(newx * ibuf->y * sizeof(float) * 4, "scaleupxf");
+ if (_newrectf==NULL) {
+ if (_newrect) MEM_freeN(_newrect);
+ return(ibuf);
+ }
+ }
+
+ add = (ibuf->x - 1.001) / (newx - 1.0);
+
+ rect = (uchar *) ibuf->rect;
+ rectf = (float *) ibuf->rect_float;
+ newrect = _newrect;
+ newrectf = _newrectf;
+
+ for (y = ibuf->y; y>0 ; y--){
+
+ sample = 0;
+
+ if (do_rect) {
+ val_a = rect[0] ;
+ nval_a = rect[4];
+ diff_a = nval_a - val_a ;
+ val_a += 0.5;
+
+ val_b = rect[1] ;
+ nval_b = rect[5];
+ diff_b = nval_b - val_b ;
+ val_b += 0.5;
+
+ val_g = rect[2] ;
+ nval_g = rect[6];
+ diff_g = nval_g - val_g ;
+ val_g += 0.5;
+
+ val_r = rect[3] ;
+ nval_r = rect[7];
+ diff_r = nval_r - val_r ;
+ val_r += 0.5;
+
+ rect += 8;
+ }
+ if (do_float) {
+ val_af = rectf[0] ;
+ nval_af = rectf[4];
+ diff_af = nval_af - val_af;
+
+ val_bf = rectf[1] ;
+ nval_bf = rectf[5];
+ diff_bf = nval_bf - val_bf;
+
+ val_gf = rectf[2] ;
+ nval_gf = rectf[6];
+ diff_gf = nval_gf - val_gf;
+
+ val_rf = rectf[3] ;
+ nval_rf = rectf[7];
+ diff_rf = nval_rf - val_rf;
+
+ rectf += 8;
+ }
+ for (x = newx ; x>0 ; x--){
+ if (sample >= 1.0){
+ sample -= 1.0;
+
+ if (do_rect) {
+ val_a = nval_a ;
+ nval_a = rect[0] ;
+ diff_a = nval_a - val_a ;
+ val_a += 0.5;
+
+ val_b = nval_b ;
+ nval_b = rect[1] ;
+ diff_b = nval_b - val_b ;
+ val_b += 0.5;
+
+ val_g = nval_g ;
+ nval_g = rect[2] ;
+ diff_g = nval_g - val_g ;
+ val_g += 0.5;
+
+ val_r = nval_r ;
+ nval_r = rect[3] ;
+ diff_r = nval_r - val_r ;
+ val_r += 0.5;
+ rect += 4;
+ }
+ if (do_float) {
+ val_af = nval_af ;
+ nval_af = rectf[0] ;
+ diff_af = nval_af - val_af ;
+
+ val_bf = nval_bf ;
+ nval_bf = rectf[1] ;
+ diff_bf = nval_bf - val_bf ;
+
+ val_gf = nval_gf ;
+ nval_gf = rectf[2] ;
+ diff_gf = nval_gf - val_gf ;
+
+ val_rf = nval_rf ;
+ nval_rf = rectf[3] ;
+ diff_rf = nval_rf - val_rf;
+ rectf += 4;
+ }
+ }
+ if (do_rect) {
+ newrect[0] = val_a + sample * diff_a;
+ newrect[1] = val_b + sample * diff_b;
+ newrect[2] = val_g + sample * diff_g;
+ newrect[3] = val_r + sample * diff_r;
+ newrect += 4;
+ }
+ if (do_float) {
+ newrectf[0] = val_af + sample * diff_af;
+ newrectf[1] = val_bf + sample * diff_bf;
+ newrectf[2] = val_gf + sample * diff_gf;
+ newrectf[3] = val_rf + sample * diff_rf;
+ newrectf += 4;
+ }
+ sample += add;
+ }
+ }
+
+ if (do_rect) {
+ imb_freerectImBuf(ibuf);
+ ibuf->mall |= IB_rect;
+ ibuf->rect = (unsigned int *) _newrect;
+ }
+ if (do_float) {
+ imb_freerectfloatImBuf(ibuf);
+ ibuf->mall |= IB_rectfloat;
+ ibuf->rect_float = (float *) _newrectf;
+ }
+
+ ibuf->x = newx;
+ return(ibuf);
+}
+
+static struct ImBuf *scaleupy(struct ImBuf *ibuf, int newy)
+{
+ uchar *rect,*_newrect=NULL,*newrect;
+ float *rectf,*_newrectf=NULL,*newrectf;
+ float sample,add;
+ float val_a,nval_a,diff_a;
+ float val_b,nval_b,diff_b;
+ float val_g,nval_g,diff_g;
+ float val_r,nval_r,diff_r;
+ float val_af,nval_af,diff_af;
+ float val_bf,nval_bf,diff_bf;
+ float val_gf,nval_gf,diff_gf;
+ float val_rf,nval_rf,diff_rf;
+ int x,y, do_rect = 0, do_float = 0, skipx;
+
+ val_a = nval_a = diff_a = val_b = nval_b = diff_b = 0;
+ val_g = nval_g = diff_g = val_r = nval_r = diff_r = 0;
+ val_af = nval_af = diff_af = val_bf = nval_bf = diff_bf = 0;
+ val_gf = nval_gf = diff_gf = val_rf = nval_rf = diff_rf = 0;
+ if (ibuf==NULL) return(0);
+ if (ibuf->rect==NULL && ibuf->rect_float==NULL) return (ibuf);
+
+ if (ibuf->rect) {
+ do_rect = 1;
+ _newrect = MEM_mallocN(ibuf->x * newy * sizeof(int), "scaleupy");
+ if (_newrect==NULL) return(ibuf);
+ }
+ if (ibuf->rect_float) {
+ do_float = 1;
+ _newrectf = MEM_mallocN(ibuf->x * newy * sizeof(float) * 4, "scaleupyf");
+ if (_newrectf==NULL) {
+ if (_newrect) MEM_freeN(_newrect);
+ return(ibuf);
+ }
+ }
+
+ add = (ibuf->y - 1.001) / (newy - 1.0);
+ skipx = 4 * ibuf->x;
+
+ rect = (uchar *) ibuf->rect;
+ rectf = (float *) ibuf->rect_float;
+ newrect = _newrect;
+ newrectf = _newrectf;
+
+ for (x = ibuf->x; x>0 ; x--){
+
+ sample = 0;
+ if (do_rect) {
+ rect = ((uchar *)ibuf->rect) + 4*(x-1);
+ newrect = _newrect + 4*(x-1);
+
+ val_a = rect[0] ;
+ nval_a = rect[skipx];
+ diff_a = nval_a - val_a ;
+ val_a += 0.5;
+
+ val_b = rect[1] ;
+ nval_b = rect[skipx+1];
+ diff_b = nval_b - val_b ;
+ val_b += 0.5;
+
+ val_g = rect[2] ;
+ nval_g = rect[skipx+2];
+ diff_g = nval_g - val_g ;
+ val_g += 0.5;
+
+ val_r = rect[3] ;
+ nval_r = rect[skipx+4];
+ diff_r = nval_r - val_r ;
+ val_r += 0.5;
+
+ rect += 2*skipx;
+ }
+ if (do_float) {
+ rectf = ((float *)ibuf->rect_float) + 4*(x-1);
+ newrectf = _newrectf + 4*(x-1);
+
+ val_af = rectf[0] ;
+ nval_af = rectf[skipx];
+ diff_af = nval_af - val_af;
+
+ val_bf = rectf[1] ;
+ nval_bf = rectf[skipx+1];
+ diff_bf = nval_bf - val_bf;
+
+ val_gf = rectf[2] ;
+ nval_gf = rectf[skipx+2];
+ diff_gf = nval_gf - val_gf;
+
+ val_rf = rectf[3] ;
+ nval_rf = rectf[skipx+3];
+ diff_rf = nval_rf - val_rf;
+
+ rectf += 2*skipx;
+ }
+
+ for (y = newy ; y>0 ; y--){
+ if (sample >= 1.0){
+ sample -= 1.0;
+
+ if (do_rect) {
+ val_a = nval_a ;
+ nval_a = rect[0] ;
+ diff_a = nval_a - val_a ;
+ val_a += 0.5;
+
+ val_b = nval_b ;
+ nval_b = rect[1] ;
+ diff_b = nval_b - val_b ;
+ val_b += 0.5;
+
+ val_g = nval_g ;
+ nval_g = rect[2] ;
+ diff_g = nval_g - val_g ;
+ val_g += 0.5;
+
+ val_r = nval_r ;
+ nval_r = rect[3] ;
+ diff_r = nval_r - val_r ;
+ val_r += 0.5;
+ rect += skipx;
+ }
+ if (do_float) {
+ val_af = nval_af ;
+ nval_af = rectf[0] ;
+ diff_af = nval_af - val_af ;
+
+ val_bf = nval_bf ;
+ nval_bf = rectf[1] ;
+ diff_bf = nval_bf - val_bf ;
+
+ val_gf = nval_gf ;
+ nval_gf = rectf[2] ;
+ diff_gf = nval_gf - val_gf ;
+
+ val_rf = nval_rf ;
+ nval_rf = rectf[3] ;
+ diff_rf = nval_rf - val_rf;
+ rectf += skipx;
+ }
+ }
+ if (do_rect) {
+ newrect[0] = val_a + sample * diff_a;
+ newrect[1] = val_b + sample * diff_b;
+ newrect[2] = val_g + sample * diff_g;
+ newrect[3] = val_r + sample * diff_r;
+ newrect += skipx;
+ }
+ if (do_float) {
+ newrectf[0] = val_af + sample * diff_af;
+ newrectf[1] = val_bf + sample * diff_bf;
+ newrectf[2] = val_gf + sample * diff_gf;
+ newrectf[3] = val_rf + sample * diff_rf;
+ newrectf += skipx;
+ }
+ sample += add;
+ }
+ }
+
+ if (do_rect) {
+ imb_freerectImBuf(ibuf);
+ ibuf->mall |= IB_rect;
+ ibuf->rect = (unsigned int *) _newrect;
+ }
+ if (do_float) {
+ imb_freerectfloatImBuf(ibuf);
+ ibuf->mall |= IB_rectfloat;
+ ibuf->rect_float = (float *) _newrectf;
+ }
+
+ ibuf->y = newy;
+ return(ibuf);
+}
+
+
+/* no float buf needed here! */
+static void scalefast_Z_ImBuf(ImBuf *ibuf, short newx, short newy)
+{
+ unsigned int *rect, *_newrect, *newrect;
+ int x, y;
+ int ofsx, ofsy, stepx, stepy;
+
+ if (ibuf->zbuf) {
+ _newrect = MEM_mallocN(newx * newy * sizeof(int), "z rect");
+ if (_newrect==NULL) return;
+
+ stepx = (65536.0 * (ibuf->x - 1.0) / (newx - 1.0)) + 0.5;
+ stepy = (65536.0 * (ibuf->y - 1.0) / (newy - 1.0)) + 0.5;
+ ofsy = 32768;
+
+ newrect = _newrect;
+
+ for (y = newy; y > 0 ; y--){
+ rect = (unsigned int*) ibuf->zbuf;
+ rect += (ofsy >> 16) * ibuf->x;
+ ofsy += stepy;
+ ofsx = 32768;
+ for (x = newx ; x > 0 ; x--){
+ *newrect++ = rect[ofsx >> 16];
+ ofsx += stepx;
+ }
+ }
+
+ IMB_freezbufImBuf(ibuf);
+ ibuf->mall |= IB_zbuf;
+ ibuf->zbuf = (int*) _newrect;
+ }
+}
+
+struct ImBuf *IMB_scaleImBuf(struct ImBuf * ibuf, short newx, short newy)
+{
+ if (ibuf==NULL) return (0);
+ if (ibuf->rect==NULL && ibuf->rect_float==NULL) return (ibuf);
+
+ // scaleup / scaledown functions below change ibuf->x and ibuf->y
+ // so we first scale the Z-buffer (if any)
+ scalefast_Z_ImBuf(ibuf, newx, newy);
+
+ if (newx < ibuf->x) if (newx) scaledownx(ibuf,newx);
+ if (newy < ibuf->y) if (newy) scaledowny(ibuf,newy);
+ if (newx > ibuf->x) if (newx) scaleupx(ibuf,newx);
+ if (newy > ibuf->y) if (newy) scaleupy(ibuf,newy);
+
+ return(ibuf);
+}
+
+struct imbufRGBA {
+ float r, g, b, a;
+};
+
+struct ImBuf *IMB_scalefastImBuf(struct ImBuf *ibuf, short newx, short newy)
+{
+ unsigned int *rect,*_newrect,*newrect;
+ struct imbufRGBA *rectf, *_newrectf, *newrectf;
+ int x,y, do_float=0, do_rect=0;
+ int ofsx,ofsy,stepx,stepy;
+
+ rect = NULL; _newrect = NULL; newrect = NULL;
+ rectf = NULL; _newrectf = NULL; newrectf = NULL;
+
+ if (ibuf==NULL) return(0);
+ if (ibuf->rect) do_rect = 1;
+ if (ibuf->rect_float) do_float = 1;
+ if (do_rect==0 && do_float==0) return(ibuf);
+
+ if (newx == ibuf->x && newy == ibuf->y) return(ibuf);
+
+ if(do_rect) {
+ _newrect = MEM_mallocN(newx * newy * sizeof(int), "scalefastimbuf");
+ if (_newrect==NULL) return(ibuf);
+ newrect = _newrect;
+ }
+
+ if (do_float) {
+ _newrectf = MEM_mallocN(newx * newy * sizeof(float) * 4, "scalefastimbuf f");
+ if (_newrectf==NULL) {
+ if (_newrect) MEM_freeN(_newrect);
+ return(ibuf);
+ }
+ newrectf = _newrectf;
+ }
+
+ stepx = (65536.0 * (ibuf->x - 1.0) / (newx - 1.0)) + 0.5;
+ stepy = (65536.0 * (ibuf->y - 1.0) / (newy - 1.0)) + 0.5;
+ ofsy = 32768;
+
+ for (y = newy; y > 0 ; y--){
+ if(do_rect) {
+ rect = ibuf->rect;
+ rect += (ofsy >> 16) * ibuf->x;
+ }
+ if (do_float) {
+ rectf = (struct imbufRGBA *)ibuf->rect_float;
+ rectf += (ofsy >> 16) * ibuf->x;
+ }
+ ofsy += stepy;
+ ofsx = 32768;
+
+ if (do_rect) {
+ for (x = newx ; x>0 ; x--){
+ *newrect++ = rect[ofsx >> 16];
+ ofsx += stepx;
+ }
+ }
+
+ if (do_float) {
+ ofsx = 32768;
+ for (x = newx ; x>0 ; x--){
+ *newrectf++ = rectf[ofsx >> 16];
+ ofsx += stepx;
+ }
+ }
+ }
+
+ if (do_rect) {
+ imb_freerectImBuf(ibuf);
+ ibuf->mall |= IB_rect;
+ ibuf->rect = _newrect;
+ }
+
+ if (do_float) {
+ imb_freerectfloatImBuf(ibuf);
+ ibuf->mall |= IB_rectfloat;
+ ibuf->rect_float = (float *)_newrectf;
+ }
+
+ scalefast_Z_ImBuf(ibuf, newx, newy);
+
+ ibuf->x = newx;
+ ibuf->y = newy;
+ return(ibuf);
+}
+
+
+static struct ImBuf *generic_fieldscale(struct ImBuf *ibuf, short newx, short newy, struct ImBuf *(*scalefunc)(ImBuf *, short, short) )
+{
+ struct ImBuf *sbuf1, *sbuf2;
+
+ sbuf1 = IMB_allocImBuf(ibuf->x, ibuf->y / 2, ibuf->depth, ibuf->flags, 0);
+ sbuf2 = IMB_allocImBuf(ibuf->x, ibuf->y / 2, ibuf->depth, ibuf->flags, 0);
+
+ ibuf->x *= 2;
+
+ /* more args needed, 0 assumed... (nzc) */
+ IMB_rectcpy(sbuf1, ibuf, 0, 0, 0, 0, ibuf->x, ibuf->y);
+ IMB_rectcpy(sbuf2, ibuf, 0, 0, sbuf2->x, 0, ibuf->x, ibuf->y);
+
+ imb_freerectImBuf(ibuf);
+ imb_freerectfloatImBuf(ibuf);
+
+ ibuf->x = newx;
+ ibuf->y = newy;
+
+ imb_addrectImBuf(ibuf);
+ if(ibuf->flags & IB_rectfloat)
+ imb_addrectfloatImBuf(ibuf);
+
+ scalefunc(sbuf1, newx, newy / 2);
+ scalefunc(sbuf2, newx, newy / 2);
+
+ ibuf->x *= 2;
+
+ /* more args needed, 0 assumed... (nzc) */
+ IMB_rectcpy(ibuf, sbuf1, 0, 0, 0, 0, sbuf1->x, sbuf1->y);
+ IMB_rectcpy(ibuf, sbuf2, sbuf2->x, 0, 0, 0, sbuf2->x, sbuf2->y);
+
+ ibuf->x /= 2;
+
+ IMB_freeImBuf(sbuf1);
+ IMB_freeImBuf(sbuf2);
+
+ return(ibuf);
+}
+
+
+struct ImBuf *IMB_scalefastfieldImBuf(struct ImBuf *ibuf, short newx, short newy)
+{
+ return(generic_fieldscale(ibuf, newx, newy, IMB_scalefastImBuf));
+}
+
+struct ImBuf *IMB_scalefieldImBuf(struct ImBuf *ibuf, short newx, short newy)
+{
+ return(generic_fieldscale(ibuf, newx, newy, IMB_scaleImBuf));
+}
+
diff --git a/source/blender/imbuf/intern/targa.c b/source/blender/imbuf/intern/targa.c
new file mode 100644
index 00000000000..d2979215872
--- /dev/null
+++ b/source/blender/imbuf/intern/targa.c
@@ -0,0 +1,647 @@
+/**
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * $Id$
+ */
+
+#ifdef WIN32
+#include <io.h>
+#endif
+#include "BLI_blenlib.h"
+
+#include "imbuf.h"
+#include "imbuf_patch.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "IMB_allocimbuf.h"
+#include "IMB_cmap.h"
+#include "IMB_targa.h"
+
+
+/* this one is only def-ed once, strangely... related to GS? */
+#define GSS(x) (((uchar *)(x))[1] << 8 | ((uchar *)(x))[0])
+
+/***/
+
+typedef struct TARGA
+{
+ unsigned char numid;
+ unsigned char maptyp;
+ unsigned char imgtyp;
+ short maporig;
+ short mapsize;
+ unsigned char mapbits;
+ short xorig;
+ short yorig;
+ short xsize;
+ short ysize;
+ unsigned char pixsize;
+ unsigned char imgdes;
+} TARGA;
+
+/***/
+
+static int tga_out1(unsigned int data, FILE *file)
+{
+ uchar *p;
+
+ p = (uchar *) & data;
+ if (putc(p[0],file) == EOF) return(EOF);
+ return (~EOF);
+}
+
+static int tga_out2(unsigned int data, FILE * file)
+{
+ uchar *p;
+
+ p = (uchar *) & data;
+ if (putc(p[0],file) == EOF) return(EOF);
+ if (putc(p[1],file) == EOF) return(EOF);
+ return (~EOF);
+}
+
+
+static int tga_out3(unsigned int data, FILE * file)
+{
+ uchar *p;
+
+ p = (uchar *) & data;
+ if (putc(p[2],file) == EOF) return(EOF);
+ if (putc(p[1],file) == EOF) return(EOF);
+ if (putc(p[0],file) == EOF) return(EOF);
+ return (~EOF);
+}
+
+
+static int tga_out4(unsigned int data, FILE * file)
+{
+ uchar *p;
+
+ p = (uchar *) & data;
+ /* order = bgra */
+ if (putc(p[2],file) == EOF) return(EOF);
+ if (putc(p[1],file) == EOF) return(EOF);
+ if (putc(p[0],file) == EOF) return(EOF);
+ if (putc(p[3],file) == EOF) return(EOF);
+ return (~EOF);
+}
+
+static short makebody_tga(ImBuf * ibuf, FILE * file, int (*out)(unsigned int, FILE*))
+{
+ register int last,this;
+ register int copy, bytes;
+ register unsigned int *rect, *rectstart, *temp;
+ int y;
+
+ for (y = 0; y < ibuf->y; y++) {
+ bytes = ibuf->x - 1;
+ rectstart = rect = ibuf->rect + (y * ibuf->x);
+ last = *rect++;
+ this = *rect++;
+ copy = last^this;
+ while (bytes > 0){
+ if (copy){
+ do{
+ last = this;
+ this = *rect++;
+ if (last == this){
+ if (this == rect[-3]){ /* three the same? */
+ bytes --; /* set bytes */
+ break;
+ }
+ }
+ }while (--bytes != 0);
+
+ copy = rect-rectstart;
+ copy --;
+ if (bytes) copy -= 2;
+
+ temp = rect;
+ rect = rectstart;
+
+ while (copy){
+ last = copy;
+ if (copy>=128) last = 128;
+ copy -= last;
+ if (fputc(last-1,file) == EOF) return(0);
+ do{
+ if (out(*rect++,file) == EOF) return(0);
+ }while(--last != 0);
+ }
+ rectstart = rect;
+ rect = temp;
+ last = this;
+
+ copy = FALSE;
+ } else {
+ while (*rect++ == this){ /* seek for first different byte */
+ if (--bytes == 0) break; /* oor end of line */
+ }
+ rect --;
+ copy = rect-rectstart;
+ rectstart = rect;
+ bytes --;
+ this = *rect++;
+
+ while (copy){
+ if (copy>128){
+ if (fputc(255,file) == EOF) return(0);
+ copy -= 128;
+ } else {
+ if (copy == 1){
+ if (fputc(0,file) == EOF) return(0);
+ } else if (fputc(127 + copy,file) == EOF) return(0);
+ copy = 0;
+ }
+ if (out(last,file) == EOF) return(0);
+ }
+ copy=TRUE;
+ }
+ }
+ }
+ return (1);
+}
+
+static int dumptarga(struct ImBuf * ibuf, FILE * file)
+{
+ int size;
+ uchar *rect;
+
+ if (ibuf == 0) return (0);
+ if (ibuf->rect == 0) return (0);
+
+ size = ibuf->x * ibuf->y;
+ rect = (uchar *) ibuf->rect;
+
+ if (ibuf->depth <= 8) {
+ while(size > 0){
+ if (putc(*rect, file) == EOF) return (0);
+ size--;
+ rect += 4;
+ }
+ } else if (ibuf->depth <= 16) {
+ while(size > 0){
+ putc(rect[0], file);
+ if (putc(rect[1], file) == EOF) return (0);
+ size--;
+ rect += 4;
+ }
+ } else if (ibuf->depth <= 24) {
+ while(size > 0){
+ putc(rect[2], file);
+ putc(rect[1], file);
+ if (putc(rect[0], file) == EOF) return (0);
+ size--;
+ rect += 4;
+ }
+ } else if (ibuf->depth <= 32) {
+ while(size > 0){
+ putc(rect[2], file);
+ putc(rect[1], file);
+ putc(rect[0], file);
+ if (putc(rect[3], file) == EOF) return (0);
+ size--;
+ rect += 4;
+ }
+ } else return (0);
+
+ return (1);
+}
+
+
+short imb_savetarga(struct ImBuf * ibuf, char *name, int flags)
+{
+ char buf[20];
+ FILE *fildes;
+ int i;
+ short ok = 0;
+
+ if (ibuf == 0) return (0);
+ if (ibuf->rect == 0) return (0);
+
+ memset(buf,0,sizeof(buf));
+
+ /* buf[0] = 0; length string */
+
+ buf[16] = (ibuf->depth + 0x7 ) & ~0x7;
+ if (ibuf->cmap) {
+ buf[1] = 1;
+ buf[2] = 9;
+ buf[3] = ibuf->mincol & 0xff;
+ buf[4] = ibuf->mincol >> 8;
+ buf[5] = ibuf->maxcol & 0xff;
+ buf[6] = ibuf->maxcol >> 8;
+ buf[7] = 24;
+ if ((flags & IB_ttob) == 0) {
+ IMB_flipy(ibuf);
+ buf[17] = 0x20;
+ }
+ } else if (ibuf->depth > 8 ){
+ buf[2] = 10;
+ } else{
+ buf[2] = 11;
+ }
+
+ if (ibuf->ftype == RAWTGA) buf[2] &= ~8;
+
+ buf[8] = ibuf->xorig & 0xff;
+ buf[9] = ibuf->xorig >> 8;
+ buf[10] = ibuf->yorig & 0xff;
+ buf[11] = ibuf->yorig >> 8;
+
+ buf[12] = ibuf->x & 0xff;
+ buf[13] = ibuf->x >> 8;
+ buf[14] = ibuf->y & 0xff;
+ buf[15] = ibuf->y >> 8;
+
+ if (flags & IB_ttob) buf[17] ^= 0x20;
+
+ /* Don't forget to indicate that your 32 bit
+ * targa uses 8 bits for the alpha channel! */
+ if (ibuf->depth==32) {
+ buf[17] |= 0x08;
+ }
+ fildes = fopen(name,"wb");
+ if (!fildes) return 0;
+
+ if (fwrite(buf, 1, 18,fildes) != 18) return (0);
+
+ if (ibuf->cmap){
+ for (i = 0 ; i<ibuf->maxcol ; i++){
+ if (fwrite(((uchar *)(ibuf->cmap + i)) + 1,1,3,fildes) != 3) return (0);
+ }
+ }
+
+ if (ibuf->cmap && (flags & IB_cmap) == 0) IMB_converttocmap(ibuf);
+
+ if (ibuf->ftype == RAWTGA) {
+ ok = dumptarga(ibuf, fildes);
+ } else {
+ switch((ibuf->depth + 7) >> 3){
+ case 1:
+ ok = makebody_tga(ibuf, fildes, tga_out1);
+ break;
+ case 2:
+ ok = makebody_tga(ibuf, fildes, tga_out2);
+ break;
+ case 3:
+ ok = makebody_tga(ibuf, fildes, tga_out3);
+ break;
+ case 4:
+ ok = makebody_tga(ibuf, fildes, tga_out4);
+ break;
+ }
+ }
+
+ fclose(fildes);
+ return (ok);
+}
+
+
+static int checktarga(TARGA *tga, unsigned char *mem)
+{
+ tga->numid = mem[0];
+ tga->maptyp = mem[1];
+ tga->imgtyp = mem[2];
+
+ tga->maporig = GSS(mem+3);
+ tga->mapsize = GSS(mem+5);
+ tga->mapbits = mem[7];
+ tga->xorig = GSS(mem+8);
+ tga->yorig = GSS(mem+10);
+ tga->xsize = GSS(mem+12);
+ tga->ysize = GSS(mem+14);
+ tga->pixsize = mem[16];
+ tga->imgdes = mem[17];
+
+ if (tga->maptyp > 1) return(0);
+ switch (tga->imgtyp){
+ case 1: /* raw cmap */
+ case 2: /* raw rgb */
+ case 3: /* raw b&w */
+ case 9: /* cmap */
+ case 10: /* rgb */
+ case 11: /* b&w */
+ break;
+ default:
+ return(0);
+ }
+ if (tga->mapsize && tga->mapbits > 32) return(0);
+ if (tga->xsize <= 0 || tga->xsize >= 8192) return(0);
+ if (tga->ysize <= 0 || tga->ysize >= 8192) return(0);
+ if (tga->pixsize > 32) return(0);
+ if (tga->pixsize == 0) return(0);
+ return(1);
+}
+
+int imb_is_a_targa(void *buf) {
+ TARGA tga;
+
+ return checktarga(&tga, buf);
+}
+
+static void decodetarga(struct ImBuf *ibuf, unsigned char *mem, int psize)
+{
+ int count, col, size;
+ unsigned int *rect;
+ uchar * cp = (uchar *) &col;
+
+ if (ibuf == 0) return;
+ if (ibuf->rect == 0) return;
+
+ size = ibuf->x * ibuf->y;
+ rect = ibuf->rect;
+
+ /* set alpha */
+ cp[0] = 0xff;
+ cp[1] = cp[2] = 0;
+
+ while(size > 0){
+ count = *mem++;
+ if (count >= 128) {
+ /*if (count == 128) printf("TARGA: 128 in file !\n");*/
+ count -= 127;
+
+ if (psize & 2){
+ if (psize & 1){
+ /* order = bgra */
+ cp[0] = mem[3];
+ cp[1] = mem[0];
+ cp[2] = mem[1];
+ cp[3] = mem[2];
+ /*col = (mem[3] << 24) + (mem[0] << 16) + (mem[1] << 8) + mem[2];*/
+ mem += 4;
+ } else{
+ cp[1] = mem[0];
+ cp[2] = mem[1];
+ cp[3] = mem[2];
+ /*col = 0xff000000 + (mem[0] << 16) + (mem[1] << 8) + mem[2];*/
+ mem += 3;
+ }
+ } else{
+ if (psize & 1){
+ cp[0] = mem[0];
+ cp[1] = mem[1];
+ mem += 2;
+ } else{
+ col = *mem++;
+ }
+ }
+
+ size -= count;
+ if (size >= 0) {
+ while (count > 0) {
+ *rect++ = col;
+ count--;
+ }
+ }
+ } else{
+ count ++;
+ size -= count;
+ if (size >= 0) {
+ while (count > 0){
+ if (psize & 2){
+ if (psize & 1){
+ /* order = bgra */
+ cp[0] = mem[3];
+ cp[1] = mem[0];
+ cp[2] = mem[1];
+ cp[3] = mem[2];
+ /*col = (mem[3] << 24) + (mem[0] << 16) + (mem[1] << 8) + mem[2];*/
+ mem += 4;
+ } else{
+ cp[1] = mem[0];
+ cp[2] = mem[1];
+ cp[3] = mem[2];
+ /*col = 0xff000000 + (mem[0] << 16) + (mem[1] << 8) + mem[2];*/
+ mem += 3;
+ }
+ } else{
+ if (psize & 1){
+ cp[0] = mem[0];
+ cp[1] = mem[1];
+ mem += 2;
+ } else{
+ col = *mem++;
+ }
+ }
+ *rect++ = col;
+ count --;
+ }
+ }
+ }
+ }
+ if (size) printf("decodetarga: count would overwrite %d pixels\n", -size);
+}
+
+static void ldtarga(struct ImBuf * ibuf,unsigned char * mem, int psize)
+{
+ int col,size;
+ unsigned int *rect;
+ uchar * cp = (uchar *) &col;
+
+ if (ibuf == 0) return;
+ if (ibuf->rect == 0) return;
+
+ size = ibuf->x * ibuf->y;
+ rect = ibuf->rect;
+
+ /* set alpha */
+ cp[0] = 0xff;
+ cp[1] = cp[2] = 0;
+
+ while(size > 0){
+ if (psize & 2){
+ if (psize & 1){
+ /* order = bgra */
+ cp[0] = mem[3];
+ cp[1] = mem[0];
+ cp[2] = mem[1];
+ cp[3] = mem[2];
+ /*col = (mem[3] << 24) + (mem[0] << 16) + (mem[1] << 8) + mem[2];*/
+ mem += 4;
+ } else{
+ /* set alpha for 24 bits colors */
+ cp[1] = mem[0];
+ cp[2] = mem[1];
+ cp[3] = mem[2];
+ /*col = 0xff000000 + (mem[0] << 16) + (mem[1] << 8) + mem[2];*/
+ mem += 3;
+ }
+ } else{
+ if (psize & 1){
+ cp[0] = mem[0];
+ cp[1] = mem[1];
+ mem += 2;
+ } else{
+ col = *mem++;
+ }
+ }
+ *rect++ = col;
+ size--;
+ }
+}
+
+
+struct ImBuf *imb_loadtarga(unsigned char *mem, int flags)
+{
+ TARGA tga;
+ struct ImBuf * ibuf;
+ int col, count, size;
+ unsigned int * rect;
+ uchar * cp = (uchar *) &col;
+
+ if (checktarga(&tga,mem) == 0) return(0);
+
+ if (flags & IB_test) ibuf = IMB_allocImBuf(tga.xsize,tga.ysize,tga.pixsize, 0, 0);
+ else ibuf = IMB_allocImBuf(tga.xsize,tga.ysize,(tga.pixsize + 0x7) & ~0x7, IB_rect, 0);
+
+ if (ibuf == 0) return(0);
+ ibuf->ftype = TGA;
+ ibuf->xorig = tga.xorig;
+ ibuf->yorig = tga.yorig;
+ mem = mem + 18 + tga.numid;
+
+ cp[0] = 0xff;
+ cp[1] = cp[2] = 0;
+
+ if (tga.mapsize){
+ ibuf->mincol = tga.maporig;
+ ibuf->maxcol = tga.mapsize;
+ imb_addcmapImBuf(ibuf);
+ ibuf->cbits = 8;
+ for (count = 0 ; count < ibuf->maxcol ; count ++) {
+ switch (tga.mapbits >> 3) {
+ case 4:
+ cp[0] = mem[3];
+ cp[1] = mem[0];
+ cp[2] = mem[1];
+ cp[3] = mem[2];
+ mem += 4;
+ break;
+ case 3:
+ cp[1] = mem[0];
+ cp[2] = mem[1];
+ cp[3] = mem[2];
+ mem += 3;
+ break;
+ case 2:
+ cp[1] = mem[1];
+ cp[0] = mem[0];
+ mem += 2;
+ break;
+ case 1:
+ col = *mem++;
+ break;
+ }
+ ibuf->cmap[count] = col;
+ }
+
+ size = 0;
+ for (col = ibuf->maxcol - 1; col > 0; col >>= 1) size++;
+ ibuf->depth = size;
+
+ if (tga.mapbits != 32) { /* set alpha bits */
+ ibuf->cmap[0] &= BIG_LONG(0x00ffffff);
+ }
+ }
+
+ if (flags & IB_test) return (ibuf);
+
+ if (tga.imgtyp != 1 && tga.imgtyp != 9) IMB_freecmapImBuf(ibuf); /* happens sometimes (beuh) */
+
+ switch(tga.imgtyp){
+ case 1:
+ case 2:
+ case 3:
+ if (tga.pixsize <= 8) ldtarga(ibuf,mem,0);
+ else if (tga.pixsize <= 16) ldtarga(ibuf,mem,1);
+ else if (tga.pixsize <= 24) ldtarga(ibuf,mem,2);
+ else if (tga.pixsize <= 32) ldtarga(ibuf,mem,3);
+ break;
+ case 9:
+ case 10:
+ case 11:
+ if (tga.pixsize <= 8) decodetarga(ibuf,mem,0);
+ else if (tga.pixsize <= 16) decodetarga(ibuf,mem,1);
+ else if (tga.pixsize <= 24) decodetarga(ibuf,mem,2);
+ else if (tga.pixsize <= 32) decodetarga(ibuf,mem,3);
+ break;
+ }
+
+ if (ibuf->cmap){
+ if ((flags & IB_cmap) == 0) IMB_applycmap(ibuf);
+ }
+
+ if (tga.pixsize == 16 && ibuf->cmap == 0){
+ rect = ibuf->rect;
+ for (size = ibuf->x * ibuf->y; size > 0; --size, ++rect){
+ col = *rect;
+ cp = (uchar*)rect;
+ mem = (uchar*)&col;
+
+ cp[3] = ((mem[1] << 1) & 0xf8);
+ cp[2] = ((mem[0] & 0xe0) >> 2) + ((mem[1] & 0x03) << 6);
+ cp[1] = ((mem[0] << 3) & 0xf8);
+ cp[1] += cp[1] >> 5;
+ cp[2] += cp[2] >> 5;
+ cp[3] += cp[3] >> 5;
+ cp[0] = 0xff;
+ }
+ ibuf->depth = 24;
+ }
+
+ if (tga.imgtyp == 3 || tga.imgtyp == 11){
+ uchar *crect;
+ unsigned int *lrect, col;
+
+ crect = (uchar *) ibuf->rect;
+ lrect = (unsigned int *) ibuf->rect;
+
+ for (size = ibuf->x * ibuf->y; size > 0; size --){
+ col = *lrect++;
+
+ crect[0] = 255;
+ crect[1] = crect[2] = crect[3] = col;
+ crect += 4;
+ }
+ }
+
+ if (flags & IB_ttob) tga.imgdes ^= 0x20;
+ if (tga.imgdes & 0x20) IMB_flipy(ibuf);
+
+ if (ibuf) {
+ if (ibuf->rect && (flags & IB_cmap)==0)
+ IMB_convert_rgba_to_abgr(ibuf);
+ }
+
+ return(ibuf);
+}
diff --git a/source/blender/imbuf/intern/thumbs.c b/source/blender/imbuf/intern/thumbs.c
new file mode 100644
index 00000000000..131d2ef38f7
--- /dev/null
+++ b/source/blender/imbuf/intern/thumbs.c
@@ -0,0 +1,459 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2007 Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Andrea Weikert.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "BKE_global.h"
+#include "BKE_utildefines.h"
+#include "BLI_blenlib.h"
+#include "MEM_guardedalloc.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+#include "IMB_thumbs.h"
+#include "IMB_imginfo.h"
+
+
+#include "md5.h"
+
+#ifdef WIN32
+#include <windows.h> /* need to include windows.h so _WIN32_IE is defined */
+#ifndef _WIN32_IE
+#define _WIN32_IE 0x0400 /* minimal requirements for SHGetSpecialFolderPath on MINGW MSVC has this defined already */
+#endif
+#include <shlobj.h> /* for SHGetSpecialFolderPath, has to be done before BLI_winstuff because 'near' is disabled through BLI_windstuff */
+#include "BLI_winstuff.h"
+#include <process.h> /* getpid */
+#include <direct.h> /* chdir */
+#else
+#include <unistd.h>
+#endif
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+
+#define URI_MAX FILE_MAX*3 + 8
+
+static int get_thumb_dir( char* dir , ThumbSize size)
+{
+#ifdef WIN32
+ /* yes, applications shouldn't store data there, but so does GIMP :)*/
+ SHGetSpecialFolderPath(0, dir, CSIDL_PROFILE, 0);
+#else
+ char* home = getenv("HOME");
+ if (!home) return 0;
+ BLI_strncpy(dir, home, FILE_MAX);
+#endif
+ switch(size) {
+ case THB_NORMAL:
+ strcat(dir, "/.thumbnails/normal");
+ break;
+ case THB_LARGE:
+ strcat(dir, "/.thumbnails/large");
+ break;
+ case THB_FAIL:
+ strcat(dir, "/.thumbnails/fail/blender");
+ break;
+ default:
+ return 0; /* unknown size */
+ }
+ BLI_cleanup_dir(G.sce, dir);
+ return 1;
+}
+
+/** ----- begin of adapted code from glib ---
+ * The following code is adapted from function g_escape_uri_string from the gnome glib
+ * Source: http://svn.gnome.org/viewcvs/glib/trunk/glib/gconvert.c?view=markup
+ * released under the Gnu General Public License.
+ */
+typedef enum {
+ UNSAFE_ALL = 0x1, /* Escape all unsafe characters */
+ UNSAFE_ALLOW_PLUS = 0x2, /* Allows '+' */
+ UNSAFE_PATH = 0x8, /* Allows '/', '&', '=', ':', '@', '+', '$' and ',' */
+ UNSAFE_HOST = 0x10, /* Allows '/' and ':' and '@' */
+ UNSAFE_SLASHES = 0x20 /* Allows all characters except for '/' and '%' */
+} UnsafeCharacterSet;
+
+static const unsigned char acceptable[96] = {
+ /* A table of the ASCII chars from space (32) to DEL (127) */
+ /* ! " # $ % & ' ( ) * + , - . / */
+ 0x00,0x3F,0x20,0x20,0x28,0x00,0x2C,0x3F,0x3F,0x3F,0x3F,0x2A,0x28,0x3F,0x3F,0x1C,
+ /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
+ 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x38,0x20,0x20,0x2C,0x20,0x20,
+ /* @ A B C D E F G H I J K L M N O */
+ 0x38,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
+ /* P Q R S T U V W X Y Z [ \ ] ^ _ */
+ 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x20,0x20,0x20,0x20,0x3F,
+ /* ` a b c d e f g h i j k l m n o */
+ 0x20,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
+ /* p q r s t u v w x y z { | } ~ DEL */
+ 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x20,0x20,0x20,0x3F,0x20
+};
+
+static const char hex[17] = "0123456789abcdef";
+
+/* Note: This escape function works on file: URIs, but if you want to
+ * escape something else, please read RFC-2396 */
+void escape_uri_string (const char *string, char* escaped_string, int len,UnsafeCharacterSet mask)
+{
+#define ACCEPTABLE(a) ((a)>=32 && (a)<128 && (acceptable[(a)-32] & use_mask))
+
+ const char *p;
+ char *q;
+ int c;
+ UnsafeCharacterSet use_mask;
+ use_mask = mask;
+
+ for (q = escaped_string, p = string; (*p != '\0') && len; p++) {
+ c = (unsigned char) *p;
+ len--;
+
+ if (!ACCEPTABLE (c)) {
+ *q++ = '%'; /* means hex coming */
+ *q++ = hex[c >> 4];
+ *q++ = hex[c & 15];
+ } else {
+ *q++ = *p;
+ }
+ }
+
+ *q = '\0';
+}
+
+void to_hex_char(char* hexbytes, const unsigned char* bytes, int len)
+{
+ const unsigned char *p;
+ char *q;
+
+ for (q = hexbytes, p = bytes; len; p++) {
+ const unsigned char c = (unsigned char) *p;
+ len--;
+ *q++ = hex[c >> 4];
+ *q++ = hex[c & 15];
+ }
+}
+
+/** ----- end of adapted code from glib --- */
+
+static int uri_from_filename( const char *dir, const char *file, char *uri )
+{
+ char orig_uri[URI_MAX];
+ const char* dirstart = dir;
+
+#ifdef WIN32
+ {
+ char vol[3];
+
+ BLI_strncpy(orig_uri, "file:///", FILE_MAX);
+ if (strlen(dir) < 2 && dir[1] != ':') {
+ /* not a correct absolute path */
+ return 0;
+ }
+ /* on windows, using always uppercase drive/volume letter in uri */
+ vol[0] = (unsigned char)toupper(dir[0]);
+ vol[1] = ':';
+ vol[2] = '\0';
+ strcat(orig_uri, vol);
+ dirstart += 2;
+ }
+#else
+ BLI_strncpy(orig_uri, "file://", FILE_MAX);
+#endif
+ strcat(orig_uri, dirstart);
+ strcat(orig_uri, file);
+ BLI_char_switch(orig_uri, '\\', '/');
+
+#ifdef WITH_ICONV
+ {
+ char uri_utf8[FILE_MAX*3+8];
+ escape_uri_string(orig_uri, uri_utf8, FILE_MAX*3+8, UNSAFE_PATH);
+ BLI_string_to_utf8(uri_utf8, uri, NULL);
+ }
+#else
+ escape_uri_string(orig_uri, uri, FILE_MAX*3+8, UNSAFE_PATH);
+#endif
+ return 1;
+}
+
+static void thumbname_from_uri(const char* uri, char* thumb)
+{
+ char hexdigest[33];
+ unsigned char digest[16];
+
+ md5_buffer( uri, strlen(uri), digest);
+ hexdigest[0] = '\0';
+ to_hex_char(hexdigest, digest, 16);
+ hexdigest[32] = '\0';
+ sprintf(thumb, "%s.png", hexdigest);
+}
+
+static int thumbpath_from_uri(const char* uri, char* path, ThumbSize size)
+{
+ char tmppath[FILE_MAX];
+ int rv = 0;
+
+ if (get_thumb_dir(tmppath, size)) {
+ char thumb[40];
+ thumbname_from_uri(uri, thumb);
+ BLI_snprintf(path, FILE_MAX, "%s%s", tmppath, thumb);
+ rv = 1;
+ }
+ return rv;
+}
+
+
+/* create thumbnail for file and returns new imbuf for thumbnail */
+ImBuf* IMB_thumb_create(const char* dir, const char* file, ThumbSize size, ThumbSource source)
+{
+ ImBuf *img = 0;
+ char uri[URI_MAX];
+ char desc[URI_MAX+22];
+ char tpath[FILE_MAX];
+ char tdir[FILE_MAX];
+ char wdir[FILE_MAX];
+ char temp[FILE_MAX];
+ char mtime[40];
+ char cwidth[40];
+ char cheight[40];
+ char thumb[40];
+ short tsize = 128;
+ short ex, ey;
+ float scaledx, scaledy;
+ struct stat info;
+
+ switch(size) {
+ case THB_NORMAL:
+ tsize = 128;
+ break;
+ case THB_LARGE:
+ tsize = 256;
+ break;
+ case THB_FAIL:
+ tsize = 0;
+ break;
+ default:
+ return 0; /* unknown size */
+ }
+
+ uri_from_filename(dir, file,uri);
+ thumbname_from_uri(uri, thumb);
+ if (get_thumb_dir(tdir, size)) {
+ BLI_snprintf(tpath, FILE_MAX, "%s%s", tdir, thumb);
+ thumb[8] = '\0'; /* shorten for tempname, not needed anymore */
+ BLI_snprintf(temp, FILE_MAX, "%sblender_%d_%s.png", tdir, abs(getpid()), thumb);
+ if (strncmp(thumb, dir, strlen(dir)) == 0) {
+ return NULL;
+ }
+ if (size == THB_FAIL) {
+ img = IMB_allocImBuf(0,0,32, IB_rect | IB_imginfo, 0);
+ if (!img) return 0;
+ } else {
+ if (THB_SOURCE_IMAGE == source) {
+ BLI_getwdN(wdir);
+ chdir(dir);
+ img = IMB_loadiffname(file, IB_rect | IB_imginfo);
+ if (img != NULL) {
+ stat(file, &info);
+ sprintf(mtime, "%ld", info.st_mtime);
+ sprintf(cwidth, "%d", img->x);
+ sprintf(cheight, "%d", img->y);
+ chdir(wdir);
+ }
+ } else if (THB_SOURCE_MOVIE == source) {
+ struct anim * anim = NULL;
+ BLI_getwdN(wdir);
+ chdir(dir);
+ anim = IMB_open_anim(file, IB_rect | IB_imginfo);
+ if (anim != NULL) {
+ img = IMB_anim_absolute(anim, 0);
+ if (img == NULL) {
+ printf("not an anim; %s\n", file);
+ } else {
+ IMB_freeImBuf(img);
+ img = IMB_anim_previewframe(anim);
+ }
+ IMB_free_anim(anim);
+ }
+ stat(file, &info);
+ sprintf(mtime, "%ld", info.st_mtime);
+ chdir(wdir);
+ }
+ if (!img) return 0;
+
+ if (img->x > img->y) {
+ scaledx = (float)tsize;
+ scaledy = ( (float)img->y/(float)img->x )*tsize;
+ }
+ else {
+ scaledy = (float)tsize;
+ scaledx = ( (float)img->x/(float)img->y )*tsize;
+ }
+ ex = (short)scaledx;
+ ey = (short)scaledy;
+
+ IMB_scaleImBuf(img, ex, ey);
+ }
+ sprintf(desc, "Thumbnail for %s", uri);
+ IMB_imginfo_change_field(img, "Description", desc);
+ IMB_imginfo_change_field(img, "Software", "Blender");
+ IMB_imginfo_change_field(img, "Thumb::URI", uri);
+ IMB_imginfo_change_field(img, "Thumb::MTime", mtime);
+ if (THB_SOURCE_IMAGE == source) {
+ IMB_imginfo_change_field(img, "Thumb::Image::Width", cwidth);
+ IMB_imginfo_change_field(img, "Thumb::Image::Height", cheight);
+ }
+ img->ftype = PNG;
+ img->depth = 32;
+ if (IMB_saveiff(img, temp, IB_rect | IB_imginfo)) {
+#ifndef WIN32
+ chmod(temp, S_IRUSR | S_IWUSR);
+#endif
+ BLI_rename(temp, tpath);
+ }
+
+ return img;
+ }
+ return img;
+}
+
+/* read thumbnail for file and returns new imbuf for thumbnail */
+ImBuf* IMB_thumb_read(const char* dir, const char* file, ThumbSize size)
+{
+ char thumb[FILE_MAX];
+ char uri[FILE_MAX*3+8];
+ ImBuf *img = 0;
+
+ if (!uri_from_filename(dir, file,uri)) {
+ return NULL;
+ }
+ if (thumbpath_from_uri(uri, thumb, size)) {
+ img = IMB_loadiffname(thumb, IB_rect | IB_imginfo);
+ }
+
+ return img;
+}
+
+/* delete all thumbs for the file */
+void IMB_thumb_delete(const char* dir, const char* file, ThumbSize size)
+{
+ char thumb[FILE_MAX];
+ char uri[FILE_MAX*3+8];
+
+ if (!uri_from_filename(dir, file,uri)) {
+ return;
+ }
+ if (thumbpath_from_uri(uri, thumb, size)) {
+ if (strncmp(thumb, dir, strlen(dir)) == 0) {
+ return;
+ }
+ if (BLI_exists(thumb)) {
+ BLI_delete(thumb, 0, 0);
+ }
+ }
+}
+
+
+/* create the thumb if necessary and manage failed and old thumbs */
+ImBuf* IMB_thumb_manage(const char* dir, const char* file, ThumbSize size, ThumbSource source)
+{
+ char path[FILE_MAX];
+ char thumb[FILE_MAX];
+ char uri[FILE_MAX*3+8];
+ struct stat st;
+ ImBuf* img = NULL;
+
+ BLI_join_dirfile(path, dir, file);
+ if (stat(path, &st)) {
+ return NULL;
+ }
+ if (!uri_from_filename(dir, file,uri)) {
+ return NULL;
+ }
+ if (thumbpath_from_uri(uri, thumb, THB_FAIL)) {
+ /* failure thumb exists, don't try recreating */
+ if (BLI_exists(thumb)) {
+ return NULL;
+ }
+ }
+
+ if (thumbpath_from_uri(uri, thumb, size)) {
+ if (strncmp(thumb, dir, strlen(dir)) == 0) {
+ img = IMB_loadiffname(path, IB_rect);
+ } else {
+ img = IMB_loadiffname(thumb, IB_rect | IB_imginfo);
+ if (img) {
+ char mtime[40];
+ if (!IMB_imginfo_get_field(img, "Thumb::MTime", mtime, 40)) {
+ /* illegal thumb, forget it! */
+ IMB_freeImBuf(img);
+ img = 0;
+ } else {
+ time_t t = atol(mtime);
+ if (st.st_mtime != t) {
+ /* recreate all thumbs */
+ IMB_freeImBuf(img);
+ img = 0;
+ IMB_thumb_delete(dir, file, THB_NORMAL);
+ IMB_thumb_delete(dir, file, THB_LARGE);
+ IMB_thumb_delete(dir, file, THB_FAIL);
+ img = IMB_thumb_create(dir, file, size, source);
+ if(!img){
+ /* thumb creation failed, write fail thumb */
+ img = IMB_thumb_create(dir, file, THB_FAIL, source);
+ if (img) {
+ /* we don't need failed thumb anymore */
+ IMB_freeImBuf(img);
+ img = 0;
+ }
+ }
+ }
+ }
+ } else {
+ img = IMB_thumb_create(dir, file, size, source);
+ if(!img){
+ /* thumb creation failed, write fail thumb */
+ img = IMB_thumb_create(dir, file, THB_FAIL, source);
+ if (img) {
+ /* we don't need failed thumb anymore */
+ IMB_freeImBuf(img);
+ img = 0;
+ }
+ }
+ }
+ }
+ }
+
+ return img;
+}
+
+
diff --git a/source/blender/imbuf/intern/tiff.c b/source/blender/imbuf/intern/tiff.c
new file mode 100644
index 00000000000..6fc5fb99f8b
--- /dev/null
+++ b/source/blender/imbuf/intern/tiff.c
@@ -0,0 +1,547 @@
+/*
+ * tiff.c
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributor(s): Jonathan Merritt.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/**
+ * Provides TIFF file loading and saving for Blender, via libtiff.
+ *
+ * The task of loading is complicated somewhat by the fact that Blender has
+ * already loaded the file into a memory buffer. libtiff is not well
+ * configured to handle files in memory, so a client wrapper is written to
+ * surround the memory and turn it into a virtual file. Currently, reading
+ * of TIFF files is done using libtiff's RGBAImage support. This is a
+ * high-level routine that loads all images as 32-bit RGBA, handling all the
+ * required conversions between many different TIFF types internally.
+ *
+ * Saving supports RGB, RGBA and BW (greyscale) images correctly, with
+ * 8 bits per channel in all cases. The "deflate" compression algorithm is
+ * used to compress images.
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include "imbuf.h"
+#include "imbuf_patch.h"
+
+#include "BKE_global.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "IMB_allocimbuf.h"
+#include "IMB_cmap.h"
+#include "IMB_tiff.h"
+
+#include "dynlibtiff.h"
+
+
+
+/***********************
+ * Local declarations. *
+ ***********************/
+/* Reading and writing of an in-memory TIFF file. */
+tsize_t imb_tiff_ReadProc(thandle_t handle, tdata_t data, tsize_t n);
+tsize_t imb_tiff_WriteProc(thandle_t handle, tdata_t data, tsize_t n);
+toff_t imb_tiff_SeekProc(thandle_t handle, toff_t ofs, int whence);
+int imb_tiff_CloseProc(thandle_t handle);
+toff_t imb_tiff_SizeProc(thandle_t handle);
+int imb_tiff_DummyMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize);
+void imb_tiff_DummyUnmapProc(thandle_t fd, tdata_t base, toff_t size);
+
+
+/* Structure for in-memory TIFF file. */
+struct ImbTIFFMemFile {
+ unsigned char *mem; /* Location of first byte of TIFF file. */
+ toff_t offset; /* Current offset within the file. */
+ tsize_t size; /* Size of the TIFF file. */
+};
+#define IMB_TIFF_GET_MEMFILE(x) ((struct ImbTIFFMemFile*)(x));
+
+
+
+/*****************************
+ * Function implementations. *
+ *****************************/
+
+
+void imb_tiff_DummyUnmapProc(thandle_t fd, tdata_t base, toff_t size)
+{
+}
+
+int imb_tiff_DummyMapProc(thandle_t fd, tdata_t* pbase, toff_t* psize)
+{
+ return (0);
+}
+
+/**
+ * Reads data from an in-memory TIFF file.
+ *
+ * @param handle: Handle of the TIFF file (pointer to ImbTIFFMemFile).
+ * @param data: Buffer to contain data (treat as void*).
+ * @param n: Number of bytes to read.
+ *
+ * @return: Number of bytes actually read.
+ * 0 = EOF.
+ * -1 = Error (never returned).
+ */
+tsize_t imb_tiff_ReadProc(thandle_t handle, tdata_t data, tsize_t n)
+{
+ tsize_t nRemaining, nCopy;
+ struct ImbTIFFMemFile* mfile;
+ void *srcAddr;
+
+ /* get the pointer to the in-memory file */
+ mfile = IMB_TIFF_GET_MEMFILE(handle);
+ assert(mfile != NULL);
+ assert(mfile->mem != NULL);
+
+ /* find the actual number of bytes to read (copy) */
+ nCopy = n;
+ if ((tsize_t)mfile->offset >= mfile->size)
+ nRemaining = 0;
+ else
+ nRemaining = mfile->size - mfile->offset;
+
+ if (nCopy > nRemaining)
+ nCopy = nRemaining;
+
+ /* on EOF, return immediately and read (copy) nothing */
+ if (nCopy <= 0)
+ return (0);
+
+ /* all set -> do the read (copy) */
+ assert(sizeof(unsigned char) == 1);
+ srcAddr = (void*)(&(mfile->mem[mfile->offset]));
+ memcpy((void*)data, srcAddr, nCopy);
+ mfile->offset += nCopy; /* advance file ptr by copied bytes */
+ return nCopy;
+}
+
+
+
+/**
+ * Writes data to an in-memory TIFF file.
+ *
+ * NOTE: The current Blender implementation should not need this function. It
+ * is simply a stub.
+ */
+tsize_t imb_tiff_WriteProc(thandle_t handle, tdata_t data, tsize_t n)
+{
+ printf("imb_tiff_WriteProc: this function should not be called.\n");
+ return (-1);
+}
+
+
+
+/**
+ * Seeks to a new location in an in-memory TIFF file.
+ *
+ * @param handle: Handle of the TIFF file (pointer to ImbTIFFMemFile).
+ * @param ofs: Offset value (interpreted according to whence below).
+ * @param whence: This can be one of three values:
+ * SEEK_SET - The offset is set to ofs bytes.
+ * SEEK_CUR - The offset is set to its current location plus ofs bytes.
+ * SEEK_END - (This is unsupported and will return -1, indicating an
+ * error).
+ *
+ * @return: Resulting offset location within the file, measured in bytes from
+ * the beginning of the file. (-1) indicates an error.
+ */
+toff_t imb_tiff_SeekProc(thandle_t handle, toff_t ofs, int whence)
+{
+ struct ImbTIFFMemFile *mfile;
+ toff_t new_offset;
+
+ /* get the pointer to the in-memory file */
+ mfile = IMB_TIFF_GET_MEMFILE(handle);
+ assert(mfile != NULL);
+ assert(mfile->mem != NULL);
+
+ /* find the location we plan to seek to */
+ switch (whence) {
+ case SEEK_SET:
+ new_offset = ofs;
+ break;
+ case SEEK_CUR:
+ new_offset = mfile->offset + ofs;
+ break;
+ default:
+ /* no other types are supported - return an error */
+ printf("Unsupported TIFF SEEK type.\n");
+ return (-1);
+ }
+
+ /* set the new location */
+ mfile->offset = new_offset;
+ return mfile->offset;
+}
+
+
+
+/**
+ * Closes (virtually) an in-memory TIFF file.
+ *
+ * NOTE: All this function actually does is sets the data pointer within the
+ * TIFF file to NULL. That should trigger assertion errors if attempts
+ * are made to access the file after that point. However, no such
+ * attempts should ever be made (in theory).
+ *
+ * @param handle: Handle of the TIFF file (pointer to ImbTIFFMemFile).
+ *
+ * @return: 0
+ */
+int imb_tiff_CloseProc(thandle_t handle)
+{
+ struct ImbTIFFMemFile *mfile;
+
+ /* get the pointer to the in-memory file */
+ mfile = IMB_TIFF_GET_MEMFILE(handle);
+ assert(mfile != NULL);
+ assert(mfile->mem != NULL); /* the file has not been closed yet */
+
+ /* virtually close the file */
+ mfile->mem = NULL;
+ mfile->offset = 0;
+ mfile->size = 0;
+
+ return (0);
+}
+
+
+
+/**
+ * Returns the size of an in-memory TIFF file in bytes.
+ *
+ * @return: Size of file (in bytes).
+ */
+toff_t imb_tiff_SizeProc(thandle_t handle)
+{
+ struct ImbTIFFMemFile* mfile;
+
+ /* get the pointer to the in-memory file */
+ mfile = IMB_TIFF_GET_MEMFILE(handle);
+ assert(mfile != NULL);
+ assert(mfile->mem != NULL);
+
+ /* return the size */
+ return (toff_t)(mfile->size);
+}
+
+
+
+/**
+ * Checks whether a given memory buffer contains a TIFF file.
+ *
+ * FIXME: Possible memory leak if mem is less than IMB_TIFF_NCB bytes long.
+ * However, changing this will require up-stream modifications.
+ *
+ * This method uses the format identifiers from:
+ * http://www.faqs.org/faqs/graphics/fileformats-faq/part4/section-9.html
+ * The first four bytes of big-endian and little-endian TIFF files
+ * respectively are (hex):
+ * 4d 4d 00 2a
+ * 49 49 2a 00
+ * Note that TIFF files on *any* platform can be either big- or little-endian;
+ * it's not platform-specific.
+ *
+ * AFAICT, libtiff doesn't provide a method to do this automatically, and
+ * hence my manual comparison. - Jonathan Merritt (lancelet) 4th Sept 2005.
+ */
+#define IMB_TIFF_NCB 4 /* number of comparison bytes used */
+int imb_is_a_tiff(void *mem)
+{
+ char big_endian[IMB_TIFF_NCB] = { 0x4d, 0x4d, 0x00, 0x2a };
+ char lil_endian[IMB_TIFF_NCB] = { 0x49, 0x49, 0x2a, 0x00 };
+
+ return ( (memcmp(big_endian, mem, IMB_TIFF_NCB) == 0) ||
+ (memcmp(lil_endian, mem, IMB_TIFF_NCB) == 0) );
+}
+
+
+
+/**
+ * Loads a TIFF file.
+ *
+ * This function uses the "RGBA Image" support from libtiff, which enables
+ * it to load most commonly-encountered TIFF formats. libtiff handles format
+ * conversion, color depth conversion, etc.
+ *
+ * @param mem: Memory containing the TIFF file.
+ * @param size: Size of the mem buffer.
+ * @param flags: If flags has IB_test set then the file is not actually loaded,
+ * but all other operations take place.
+ *
+ * @return: A newly allocated ImBuf structure if successful, otherwise NULL.
+ */
+struct ImBuf *imb_loadtiff(unsigned char *mem, int size, int flags)
+{
+ TIFF *image = NULL;
+ struct ImBuf *ibuf = NULL;
+ struct ImbTIFFMemFile memFile;
+ uint32 width, height;
+ int bytesperpixel;
+ int success;
+ unsigned int pixel_i, byte_i;
+ uint32 *raster = NULL;
+ uint32 pixel;
+ unsigned char *to = NULL;
+
+ memFile.mem = mem;
+ memFile.offset = 0;
+ memFile.size = size;
+
+ /* check whether or not we have a TIFF file */
+ assert(size >= IMB_TIFF_NCB);
+ if (imb_is_a_tiff(mem) == 0)
+ return NULL;
+
+ /* open the TIFF client layer interface to the in-memory file */
+ image = libtiff_TIFFClientOpen("(Blender TIFF Interface Layer)",
+ "r", (thandle_t)(&memFile),
+ imb_tiff_ReadProc, imb_tiff_WriteProc,
+ imb_tiff_SeekProc, imb_tiff_CloseProc,
+ imb_tiff_SizeProc, imb_tiff_DummyMapProc, imb_tiff_DummyUnmapProc);
+ if (image == NULL) {
+ printf("imb_loadtiff: could not open TIFF IO layer.\n");
+ return NULL;
+ }
+
+ /* allocate the image buffer */
+ bytesperpixel = 4; /* 1 byte per channel, 4 channels */
+ libtiff_TIFFGetField(image, TIFFTAG_IMAGEWIDTH, &width);
+ libtiff_TIFFGetField(image, TIFFTAG_IMAGELENGTH, &height);
+ ibuf = IMB_allocImBuf(width, height, 8*bytesperpixel, 0, 0);
+ if (ibuf) {
+ ibuf->ftype = TIF;
+ } else {
+ printf("imb_loadtiff: could not allocate memory for TIFF " \
+ "image.\n");
+ libtiff_TIFFClose(image);
+ return NULL;
+ }
+
+ /* read in the image data */
+ if (!(flags & IB_test)) {
+
+ /* allocate memory for the ibuf->rect */
+ imb_addrectImBuf(ibuf);
+
+ /* perform actual read */
+ raster = (uint32*)libtiff__TIFFmalloc(
+ width*height * sizeof(uint32));
+ if (raster == NULL) {
+ libtiff_TIFFClose(image);
+ return NULL;
+ }
+ success = libtiff_TIFFReadRGBAImage(
+ image, width, height, raster, 0);
+ if (!success) {
+ printf("imb_loadtiff: This TIFF format is not " \
+ "currently supported by Blender.\n");
+ libtiff__TIFFfree(raster);
+ libtiff_TIFFClose(image);
+ return NULL;
+ }
+
+ /* copy raster to ibuf->rect; we do a fast copy if possible,
+ * otherwise revert to a slower component-wise copy */
+ if (sizeof(unsigned int) == sizeof(uint32)) {
+ memcpy(ibuf->rect, raster,
+ width*height*sizeof(uint32));
+ } else {
+ /* this may not be entirely necessary, but is put here
+ * in case sizeof(unsigned int) is not a 32-bit
+ * quantity */
+ printf("imb_loadtiff: using (slower) component-wise " \
+ "buffer copy.\n");
+ to = (unsigned char*)ibuf->rect;
+ for (pixel_i=0; pixel_i < width*height; pixel_i++)
+ {
+ byte_i = sizeof(unsigned int)*pixel_i;
+ pixel = raster[pixel_i];
+
+ to[byte_i++] = (unsigned char)TIFFGetR(pixel);
+ to[byte_i++] = (unsigned char)TIFFGetG(pixel);
+ to[byte_i++] = (unsigned char)TIFFGetB(pixel);
+ to[byte_i++] = (unsigned char)TIFFGetA(pixel);
+ }
+ }
+
+ libtiff__TIFFfree(raster);
+ }
+
+ /* close the client layer interface to the in-memory file */
+ libtiff_TIFFClose(image);
+
+ if (G.order == B_ENDIAN) IMB_convert_rgba_to_abgr(ibuf);
+
+ /* return successfully */
+ return (ibuf);
+}
+
+
+
+/**
+ * Saves a TIFF file.
+ *
+ * ImBuf structures with 1, 3 or 4 bytes per pixel (GRAY, RGB, RGBA
+ * respectively) are accepted, and interpreted correctly. Note that the TIFF
+ * convention is to use pre-multiplied alpha, which can be achieved within
+ * Blender by setting "Premul" alpha handling. Other alpha conventions are
+ * not strictly correct, but are permitted anyhow.
+ *
+ * @param ibuf: Image buffer.
+ * @param name: Name of the TIFF file to create.
+ * @param flags: Currently largely ignored.
+ *
+ * @return: 1 if the function is successful, 0 on failure.
+ */
+short imb_savetiff(struct ImBuf *ibuf, char *name, int flags)
+{
+ TIFF *image = NULL;
+ uint16 samplesperpixel;
+ size_t npixels;
+ unsigned char *pixels = NULL;
+ unsigned char *from = NULL, *to = NULL;
+ int x, y, from_i, to_i;
+ int extraSampleTypes[1] = { EXTRASAMPLE_ASSOCALPHA };
+
+ /* check for a valid number of bytes per pixel. Like the PNG writer,
+ * the TIFF writer supports 1, 3 or 4 bytes per pixel, corresponding
+ * to gray, RGB, RGBA respectively. */
+ samplesperpixel = (uint16)((ibuf->depth + 7) >> 3);
+ if ((samplesperpixel > 4) || (samplesperpixel == 2)) {
+ printf("imb_savetiff: unsupported number of bytes per " \
+ "pixel: %d\n", samplesperpixel);
+ return (0);
+ }
+
+ /* open TIFF file for writing */
+ if (flags & IB_mem) {
+ /* bork at the creation of a TIFF in memory */
+ printf("imb_savetiff: creation of in-memory TIFF files is " \
+ "not yet supported.\n");
+ return (0);
+ } else {
+ /* create image as a file */
+ image = libtiff_TIFFOpen(name, "w");
+ }
+ if (image == NULL) {
+ printf("imb_savetiff: could not open TIFF for writing.\n");
+ return (0);
+ }
+
+ /* allocate array for pixel data */
+ npixels = ibuf->x * ibuf->y;
+ pixels = (unsigned char*)libtiff__TIFFmalloc(npixels *
+ samplesperpixel * sizeof(unsigned char));
+ if (pixels == NULL) {
+ printf("imb_savetiff: could not allocate pixels array.\n");
+ libtiff_TIFFClose(image);
+ return (0);
+ }
+
+ /* copy pixel data. While copying, we flip the image
+ * vertically. */
+ from = (unsigned char*)ibuf->rect;
+ to = pixels;
+ libtiff_TIFFSetField(image, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel);
+ switch (samplesperpixel) {
+ case 4: /* RGBA images, 8 bits per channel */
+ libtiff_TIFFSetField(image, TIFFTAG_EXTRASAMPLES, 1,
+ extraSampleTypes);
+ libtiff_TIFFSetField(image, TIFFTAG_BITSPERSAMPLE, 8);
+ libtiff_TIFFSetField(image, TIFFTAG_PHOTOMETRIC,
+ PHOTOMETRIC_RGB);
+ for (x = 0; x < ibuf->x; x++) {
+ for (y = 0; y < ibuf->y; y++) {
+ from_i = 4*(y*ibuf->x+x);
+ to_i = 4*((ibuf->y-y-1)*ibuf->x+x);
+
+ to[to_i++] = from[from_i++];
+ to[to_i++] = from[from_i++];
+ to[to_i++] = from[from_i++];
+ to[to_i] = from[from_i];
+ }
+ }
+ break;
+ case 3: /* RGB images, 8 bits per channel */
+ libtiff_TIFFSetField(image, TIFFTAG_BITSPERSAMPLE, 8);
+ libtiff_TIFFSetField(image, TIFFTAG_PHOTOMETRIC,
+ PHOTOMETRIC_RGB);
+ for (x = 0; x < ibuf->x; x++) {
+ for (y = 0; y < ibuf->y; y++) {
+ from_i = 4*(y*ibuf->x+x);
+ to_i = 3*((ibuf->y-y-1)*ibuf->x+x);
+
+ to[to_i++] = from[from_i++];
+ to[to_i++] = from[from_i++];
+ to[to_i] = from[from_i];
+ }
+ }
+ break;
+ case 1: /* greyscale images, 1 channel with 8 bits */
+ libtiff_TIFFSetField(image, TIFFTAG_BITSPERSAMPLE, 8);
+ libtiff_TIFFSetField(image, TIFFTAG_PHOTOMETRIC,
+ PHOTOMETRIC_MINISBLACK);
+ for (x = 0; x < ibuf->x; x++) {
+ for (y = 0; y < ibuf->y; y++) {
+ from_i = 4*(y*ibuf->x+x);
+ to_i = 1*((ibuf->y-y-1)*ibuf->x+x);
+
+ to[to_i] = from[from_i];
+ }
+ }
+ break;
+ }
+
+ /* write the actual TIFF file */
+ libtiff_TIFFSetField(image, TIFFTAG_IMAGEWIDTH, ibuf->x);
+ libtiff_TIFFSetField(image, TIFFTAG_IMAGELENGTH, ibuf->y);
+ libtiff_TIFFSetField(image, TIFFTAG_ROWSPERSTRIP, ibuf->y);
+ libtiff_TIFFSetField(image, TIFFTAG_COMPRESSION, COMPRESSION_DEFLATE);
+ libtiff_TIFFSetField(image, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB);
+ libtiff_TIFFSetField(image, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ libtiff_TIFFSetField(image, TIFFTAG_XRESOLUTION, 150.0);
+ libtiff_TIFFSetField(image, TIFFTAG_YRESOLUTION, 150.0);
+ libtiff_TIFFSetField(image, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
+ if (libtiff_TIFFWriteEncodedStrip(image, 0, pixels,
+ ibuf->x*ibuf->y*samplesperpixel) == -1) {
+ printf("imb_savetiff: Could not write encoded TIFF.\n");
+ libtiff_TIFFClose(image);
+ libtiff__TIFFfree(pixels);
+ return (1);
+ }
+
+ /* close the TIFF file */
+ libtiff_TIFFClose(image);
+ libtiff__TIFFfree(pixels);
+ return (1);
+}
+
diff --git a/source/blender/imbuf/intern/util.c b/source/blender/imbuf/intern/util.c
new file mode 100644
index 00000000000..4c7b5fec2c4
--- /dev/null
+++ b/source/blender/imbuf/intern/util.c
@@ -0,0 +1,397 @@
+/**
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * util.c
+ *
+ * $Id$
+ */
+
+#include "BLI_blenlib.h"
+
+#include "DNA_userdef_types.h"
+#include "BKE_global.h"
+
+#include "imbuf.h"
+#include "imbuf_patch.h"
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "IMB_targa.h"
+#include "IMB_png.h"
+
+#ifdef WITH_DDS
+#include "dds/dds_api.h"
+#endif
+
+#include "IMB_bmp.h"
+#include "IMB_tiff.h"
+#include "IMB_radiance_hdr.h"
+#include "IMB_dpxcineon.h"
+
+#include "IMB_anim.h"
+
+#ifdef WITH_OPENEXR
+#include "openexr/openexr_api.h"
+#endif
+
+#ifdef WITH_QUICKTIME
+#include "quicktime_import.h"
+#endif
+
+#ifdef WITH_FFMPEG
+#include <ffmpeg/avcodec.h>
+#include <ffmpeg/avformat.h>
+
+#if LIBAVFORMAT_VERSION_INT < (49 << 16)
+#define FFMPEG_OLD_FRAME_RATE 1
+#else
+#define FFMPEG_CODEC_IS_POINTER 1
+#endif
+
+#endif
+
+#define UTIL_DEBUG 0
+
+/* from misc_util: flip the bytes from x */
+#define GS(x) (((unsigned char *)(x))[0] << 8 | ((unsigned char *)(x))[1])
+
+/* this one is only def-ed once, strangely... */
+#define GSS(x) (((uchar *)(x))[1] << 8 | ((uchar *)(x))[0])
+
+static int IMB_ispic_name(char *name)
+{
+ struct stat st;
+ int fp, buf[10];
+ int ofs = 0;
+
+ if(UTIL_DEBUG) printf("IMB_ispic_name: loading %s\n", name);
+
+ if (ib_stat(name,&st) == -1) return(0);
+ if (((st.st_mode) & S_IFMT) == S_IFREG){
+ if ((fp = open(name,O_BINARY|O_RDONLY)) >= 0){
+ if (read(fp,buf,32)==32){
+ close(fp);
+ if (buf[ofs] == CAT) ofs += 3;
+ if (buf[ofs] == FORM){
+ if (buf[ofs + 2] == ILBM) return(AMI);
+ if (buf[ofs + 2] == ANIM){
+ if (buf[ofs + 3] == FORM){
+ return(ANIM);
+ }else{
+ return(Anim);
+ }
+ }
+ } else {
+ if (GS(buf) == IMAGIC) return(IMAGIC);
+ if (GSS(buf) == IMAGIC) return(IMAGIC);
+ if ((BIG_LONG(buf[0]) & 0xfffffff0) == 0xffd8ffe0) return(JPG);
+
+ /* at windows there are ".ffl" files with the same magic numnber...
+ besides that, tim images are not really important anymore! */
+ /* if ((BIG_LONG(buf[0]) == 0x10000000) && ((BIG_LONG(buf[1]) & 0xf0ffffff) == 0)) return(TIM); */
+
+ }
+ if (imb_is_a_png(buf)) return(PNG);
+#ifdef WITH_DDS
+ if (imb_is_a_dds((uchar *)buf)) return(DDS);
+#endif
+ if (imb_is_a_targa(buf)) return(TGA);
+#ifdef WITH_OPENEXR
+ if (imb_is_a_openexr((uchar *)buf)) return(OPENEXR);
+#endif
+ if (imb_is_a_tiff(buf)) return(TIF);
+ if (imb_is_dpx(buf)) return (DPX);
+ if (imb_is_cineon(buf)) return(CINEON);
+ /* radhdr: check if hdr format */
+ if (imb_is_a_hdr(buf)) return(RADHDR);
+
+/*
+ if (imb_is_a_bmp(buf)) return(BMP);
+*/
+
+#ifdef WITH_QUICKTIME
+#if defined(_WIN32) || defined(__APPLE__)
+ if(G.have_quicktime) {
+ if (imb_is_a_quicktime(name)) return(QUICKTIME);
+ }
+#endif
+#endif
+
+ return(FALSE);
+ }
+ close(fp);
+ }
+ }
+ return(FALSE);
+}
+
+
+
+int IMB_ispic(char *filename)
+{
+ if(U.uiflag & USER_FILTERFILEEXTS) {
+ if (G.have_libtiff && (BLI_testextensie(filename, ".tif")
+ || BLI_testextensie(filename, ".tiff"))) {
+ return IMB_ispic_name(filename);
+ }
+ if (G.have_quicktime){
+ if( BLI_testextensie(filename, ".jpg")
+ || BLI_testextensie(filename, ".jpeg")
+ || BLI_testextensie(filename, ".tif")
+ || BLI_testextensie(filename, ".tiff")
+ || BLI_testextensie(filename, ".hdr")
+ || BLI_testextensie(filename, ".tga")
+ || BLI_testextensie(filename, ".rgb")
+ || BLI_testextensie(filename, ".bmp")
+ || BLI_testextensie(filename, ".png")
+#ifdef WITH_DDS
+ || BLI_testextensie(filename, ".dds")
+#endif
+ || BLI_testextensie(filename, ".iff")
+ || BLI_testextensie(filename, ".lbm")
+ || BLI_testextensie(filename, ".gif")
+ || BLI_testextensie(filename, ".psd")
+ || BLI_testextensie(filename, ".pct")
+ || BLI_testextensie(filename, ".pict")
+ || BLI_testextensie(filename, ".pntg") //macpaint
+ || BLI_testextensie(filename, ".qtif")
+ || BLI_testextensie(filename, ".cin")
+#ifdef WITH_BF_OPENEXR
+ || BLI_testextensie(filename, ".exr")
+#endif
+ || BLI_testextensie(filename, ".sgi")) {
+ return IMB_ispic_name(filename);
+ } else {
+ return(FALSE);
+ }
+ } else { /* no quicktime or libtiff */
+ if( BLI_testextensie(filename, ".jpg")
+ || BLI_testextensie(filename, ".jpeg")
+ || BLI_testextensie(filename, ".hdr")
+ || BLI_testextensie(filename, ".tga")
+ || BLI_testextensie(filename, ".rgb")
+ || BLI_testextensie(filename, ".bmp")
+ || BLI_testextensie(filename, ".png")
+ || BLI_testextensie(filename, ".cin")
+#ifdef WITH_DDS
+ || BLI_testextensie(filename, ".dds")
+#endif
+#ifdef WITH_BF_OPENEXR
+ || BLI_testextensie(filename, ".exr")
+#endif
+ || BLI_testextensie(filename, ".iff")
+ || BLI_testextensie(filename, ".lbm")
+ || BLI_testextensie(filename, ".sgi")) {
+ return IMB_ispic_name(filename);
+ }
+ else {
+ return(FALSE);
+ }
+ }
+ } else { /* no FILTERFILEEXTS */
+ return IMB_ispic_name(filename);
+ }
+}
+
+
+
+static int isavi (char *name) {
+ return AVI_is_avi (name);
+}
+
+#ifdef WITH_QUICKTIME
+static int isqtime (char *name) {
+ return anim_is_quicktime (name);
+}
+#endif
+
+#ifdef WITH_FFMPEG
+void do_init_ffmpeg()
+{
+ static int ffmpeg_init = 0;
+ if (!ffmpeg_init) {
+ ffmpeg_init = 1;
+ av_register_all();
+ }
+}
+
+#ifdef FFMPEG_CODEC_IS_POINTER
+static AVCodecContext* get_codec_from_stream(AVStream* stream)
+{
+ return stream->codec;
+}
+#else
+static AVCodecContext* get_codec_from_stream(AVStream* stream)
+{
+ return &stream->codec;
+}
+#endif
+
+
+static int isffmpeg (char *filename) {
+ AVFormatContext *pFormatCtx;
+ int i, videoStream;
+ AVCodec *pCodec;
+ AVCodecContext *pCodecCtx;
+
+ do_init_ffmpeg();
+
+ if( BLI_testextensie(filename, ".swf") ||
+ BLI_testextensie(filename, ".jpg") ||
+ BLI_testextensie(filename, ".png") ||
+ BLI_testextensie(filename, ".dds") ||
+ BLI_testextensie(filename, ".tga") ||
+ BLI_testextensie(filename, ".bmp") ||
+ BLI_testextensie(filename, ".exr") ||
+ BLI_testextensie(filename, ".cin") ||
+ BLI_testextensie(filename, ".wav")) return 0;
+
+ if(av_open_input_file(&pFormatCtx, filename, NULL, 0, NULL)!=0) {
+ if(UTIL_DEBUG) fprintf(stderr, "isffmpeg: av_open_input_file failed\n");
+ return 0;
+ }
+
+ if(av_find_stream_info(pFormatCtx)<0) {
+ if(UTIL_DEBUG) fprintf(stderr, "isffmpeg: av_find_stream_info failed\n");
+ av_close_input_file(pFormatCtx);
+ return 0;
+ }
+
+ if(UTIL_DEBUG) dump_format(pFormatCtx, 0, filename, 0);
+
+
+ /* Find the first video stream */
+ videoStream=-1;
+ for(i=0; i<pFormatCtx->nb_streams; i++)
+ if(get_codec_from_stream(pFormatCtx->streams[i])
+ ->codec_type==CODEC_TYPE_VIDEO)
+ {
+ videoStream=i;
+ break;
+ }
+
+ if(videoStream==-1) {
+ av_close_input_file(pFormatCtx);
+ return 0;
+ }
+
+ pCodecCtx = get_codec_from_stream(pFormatCtx->streams[videoStream]);
+
+ /* Find the decoder for the video stream */
+ pCodec=avcodec_find_decoder(pCodecCtx->codec_id);
+ if(pCodec==NULL) {
+ avcodec_close(pCodecCtx);
+ av_close_input_file(pFormatCtx);
+ return 0;
+ }
+
+ if(avcodec_open(pCodecCtx, pCodec)<0) {
+ avcodec_close(pCodecCtx);
+ av_close_input_file(pFormatCtx);
+ return 0;
+ }
+
+ avcodec_close(pCodecCtx);
+ av_close_input_file(pFormatCtx);
+
+ return 1;
+}
+#endif
+
+int imb_get_anim_type(char * name) {
+ int type;
+ struct stat st;
+
+ if(UTIL_DEBUG) printf("in getanimtype: %s\n", name);
+
+#ifndef _WIN32
+# ifdef WITH_FFMPEG
+ /* stat test below fails on large files > 4GB */
+ if (isffmpeg(name)) return (ANIM_FFMPEG);
+# endif
+ if (ib_stat(name,&st) == -1) return(0);
+ if (((st.st_mode) & S_IFMT) != S_IFREG) return(0);
+
+ if (isavi(name)) return (ANIM_AVI);
+
+ if (ismovie(name)) return (ANIM_MOVIE);
+# ifdef WITH_QUICKTIME
+ if (isqtime(name)) return (ANIM_QTIME);
+# endif
+#else
+ if (ib_stat(name,&st) == -1) return(0);
+ if (((st.st_mode) & S_IFMT) != S_IFREG) return(0);
+
+ if (isavi(name)) return (ANIM_AVI);
+
+ if (ismovie(name)) return (ANIM_MOVIE);
+# ifdef WITH_QUICKTIME
+ if (isqtime(name)) return (ANIM_QTIME);
+# endif
+# ifdef WITH_FFMPEG
+ if (isffmpeg(name)) return (ANIM_FFMPEG);
+# endif
+#endif
+ type = IMB_ispic(name);
+ if (type == ANIM) return (ANIM_ANIM5);
+ if (type) return(ANIM_SEQUENCE);
+ return(0);
+}
+
+int IMB_isanim(char *filename) {
+ int type;
+
+ if(U.uiflag & USER_FILTERFILEEXTS) {
+ if (G.have_quicktime){
+ if( BLI_testextensie(filename, ".avi")
+ || BLI_testextensie(filename, ".flc")
+ || BLI_testextensie(filename, ".dv")
+ || BLI_testextensie(filename, ".mov")
+ || BLI_testextensie(filename, ".movie")
+ || BLI_testextensie(filename, ".mv")) {
+ type = imb_get_anim_type(filename);
+ } else {
+ return(FALSE);
+ }
+ } else { // no quicktime
+ if( BLI_testextensie(filename, ".avi")
+ || BLI_testextensie(filename, ".dv")
+ || BLI_testextensie(filename, ".mv")) {
+ type = imb_get_anim_type(filename);
+ }
+ else {
+ return(FALSE);
+ }
+ }
+ } else { // no FILTERFILEEXTS
+ type = imb_get_anim_type(filename);
+ }
+
+ return (type && type!=ANIM_SEQUENCE);
+}
diff --git a/source/blender/imbuf/intern/writeimage.c b/source/blender/imbuf/intern/writeimage.c
new file mode 100644
index 00000000000..ccca8e9f859
--- /dev/null
+++ b/source/blender/imbuf/intern/writeimage.c
@@ -0,0 +1,185 @@
+/**
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * writeimage.c
+ *
+ * $Id$
+ */
+
+#ifdef WIN32
+#include <io.h>
+#endif
+
+#include "BKE_global.h"
+#include "BLI_blenlib.h"
+
+#include "imbuf.h"
+#include "imbuf_patch.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "IMB_allocimbuf.h"
+
+#include "IMB_dpxcineon.h"
+#include "IMB_targa.h"
+#include "IMB_jpeg.h"
+#include "IMB_iris.h"
+#include "IMB_ham.h"
+#include "IMB_hamx.h"
+#include "IMB_amiga.h"
+#include "IMB_png.h"
+#include "IMB_bmp.h"
+#include "IMB_tiff.h"
+#include "IMB_radiance_hdr.h"
+#ifdef WITH_OPENEXR
+#include "openexr/openexr_api.h"
+#endif
+#ifdef WITH_DDS
+#include "dds/dds_api.h"
+#endif
+
+#include "IMB_iff.h"
+#include "IMB_bitplanes.h"
+#include "IMB_divers.h"
+
+/* added facility to copy with saving non-float rects */
+
+short IMB_saveiff(struct ImBuf *ibuf, char *name, int flags)
+{
+ short ok=TRUE,delpl=FALSE;
+ int file = -1;
+
+ if (ibuf==0) return (FALSE);
+ ibuf->flags = flags;
+
+ /* Put formats that take a filename here */
+ if (IS_jpg(ibuf)) {
+ if(ibuf->rect==NULL && ibuf->rect_float)
+ IMB_rect_from_float(ibuf);
+ return imb_savejpeg(ibuf, name, flags);
+ }
+ if (IS_radhdr(ibuf)) {
+ return imb_savehdr(ibuf, name, flags);
+ }
+ if (IS_png(ibuf)) {
+ if(ibuf->rect==NULL && ibuf->rect_float)
+ IMB_rect_from_float(ibuf);
+ return imb_savepng(ibuf, name, flags);
+ }
+ if (IS_bmp(ibuf)) {
+ if(ibuf->rect==NULL && ibuf->rect_float)
+ IMB_rect_from_float(ibuf);
+ return imb_savebmp(ibuf, name, flags);
+ }
+ if (IS_tga(ibuf)) {
+ if(ibuf->rect==NULL && ibuf->rect_float)
+ IMB_rect_from_float(ibuf);
+ return imb_savetarga(ibuf, name, flags);
+ }
+ if (IS_iris(ibuf)) {
+ if(ibuf->rect==NULL && ibuf->rect_float)
+ IMB_rect_from_float(ibuf);
+ return imb_saveiris(ibuf, name, flags);
+ }
+ if (G.have_libtiff && IS_tiff(ibuf)) {
+ if(ibuf->rect==NULL && ibuf->rect_float)
+ IMB_rect_from_float(ibuf);
+ return imb_savetiff(ibuf, name, flags);
+ }
+#ifdef WITH_OPENEXR
+ if (IS_openexr(ibuf)) {
+ return imb_save_openexr(ibuf, name, flags);
+ }
+#endif
+/* not supported yet
+#ifdef WITH_DDS
+ if (IS_dds(ibuf)) {
+ return imb_save_dds(ibuf, name, flags);
+ }
+#endif
+*/
+ if (IS_cineon(ibuf)) {
+ return imb_savecineon(ibuf, name, flags);
+
+ }
+ if (IS_dpx(ibuf)) {
+ return imb_save_dpx(ibuf, name, flags);
+ }
+ file = open(name, O_BINARY | O_RDWR | O_CREAT | O_TRUNC, 0666);
+ if (file < 0) return (FALSE);
+
+ if (flags & IB_rect){
+ if (ibuf->cmap){
+ imb_checkncols(ibuf);
+ }
+ }
+
+ /* Put formats that take a filehandle here */
+ ok = imb_start_iff(ibuf,file);
+ if (IS_amiga(ibuf)){
+ IMB_flipy(ibuf);
+ if (flags & IB_rect){
+ if ((flags & IB_cmap) == 0) {
+ if (IS_ham(ibuf)){
+ if (ok) ok = imb_converttoham(ibuf);
+ }else if (ibuf->cmap){
+ if (ok) ok = IMB_converttocmap(ibuf);
+ }
+ }
+ if (ok){
+ if (ibuf->planes==0){
+ delpl=TRUE;
+ ok=imb_addplanesImBuf(ibuf);
+ }
+ imb_longtobp(ibuf);
+ }
+ }
+
+ if (flags & IB_vert){
+ if (ok) ok = imb_encodebodyv(ibuf,file);
+ }
+ else{
+ if (ok) ok = imb_encodebodyh(ibuf,file);
+ }
+ if (ok) ok = imb_update_iff(file,BODY);
+ }else if (IS_anim(ibuf)) {
+ if (ok) ok = imb_enc_anim(ibuf, file);
+ if (ok) ok = imb_update_iff(file, BODY);
+ }
+ close(file);
+
+ if (ok==FALSE) {
+ fprintf(stderr,"Couldn't save picture.\n");
+ }
+ if (delpl) imb_freeplanesImBuf(ibuf);
+
+ return (ok);
+}
+
diff --git a/source/blender/imbuf/readme.txt b/source/blender/imbuf/readme.txt
new file mode 100644
index 00000000000..181d5485310
--- /dev/null
+++ b/source/blender/imbuf/readme.txt
@@ -0,0 +1,50 @@
+The following 4 steps to adding a new image format to blender, its
+probably easiest to look at the png code for a clean clear example,
+animation formats are a bit more complicated but very similar:
+
+Step 1:
+create a new file named after the format for example lets say we were
+creating an openexr read/writer use openexr.c
+It should contain functions to match the following prototypes:
+
+struct ImBuf *imb_loadopenexr(unsigned char *mem,int size,int flags);
+/* Use one of the following depending on whats easyer for your file format */
+short imb_saveopenexr(struct ImBuf *ibuf, FILE myfile, int flags);
+short imb_saveopenexr(struct ImBuf *ibuf, char *myfile, int flags);
+
+/* Used to test if its the correct format
+int IMB_is_openexr(void *buf);
+
+Step 2:
+Add your hooks to read and write the image format these go in
+ writeimage.c and readimage.c just look at how the others are done
+
+Step 3:
+Add in IS_openexr to blender/source/blender/imbuf/IMB_imbuf_types.h
+Add in R_openexr to source/blender/makesdna/DNA_scene_types.h
+
+Step 4:
+Add your hooks to the gui.
+source/blender/src/buttons_scene.c
+source/blender/src/toets.c
+source/blender/src/writeimage.c
+
+Step 5:
+edit the following files:
+blender/source/blender/imbuf/intern/util.c
+blender/source/blender/src/filesel.c
+blender/source/blender/src/screendump.c
+and add your extension so that your format gets recognized in the thumbnails.
+
+Step 6:
+Alter the build process:
+For scons you need to edit blender/source/blender/imbuf/SConscript
+and add in your additional files to source_files.
+For msvp you need to edit blender/projectfiles/blender/imbuf/BL_imbuf.dsp
+and add in your additional files.
+If you have any external library info you will also need to add that
+to the various build processes.
+
+Step 7:
+Its also good to add your image format to:
+makepicstring in blender/source/blender/blenkernel/intern/image.c
diff --git a/source/blender/include/BDR_drawaction.h b/source/blender/include/BDR_drawaction.h
new file mode 100644
index 00000000000..673b13672c1
--- /dev/null
+++ b/source/blender/include/BDR_drawaction.h
@@ -0,0 +1,88 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BDR_DRAWACTION_H
+#define BDR_DRAWACTION_H
+
+struct BezTriple;
+struct Ipo;
+struct IpoCurve;
+struct gla2DDrawInfo;
+struct bAction;
+struct Object;
+struct ListBase;
+
+/* ****************************** Base Structs ****************************** */
+
+/* Keyframe Column Struct */
+typedef struct ActKeyColumn {
+ struct ActKeyColumn *next, *prev;
+ short sel, handle_type;
+ float cfra;
+
+ /* only while drawing - used to determine if long-keyframe needs to be drawn */
+ short modified;
+ short totcurve;
+} ActKeyColumn;
+
+/* 'Long Keyframe' Struct */
+typedef struct ActKeyBlock {
+ struct ActKeyBlock *next, *prev;
+ short sel, handle_type;
+ float val;
+ float start, end;
+
+ /* only while drawing - used to determine if block needs to be drawn */
+ short modified;
+ short totcurve;
+} ActKeyBlock;
+
+
+/* ******************************* Methods ****************************** */
+
+/* Action Generics */
+void draw_cfra_action(void);
+
+/* Channel Drawing */
+void draw_icu_channel(struct gla2DDrawInfo *di, struct IpoCurve *icu, float ypos);
+void draw_ipo_channel(struct gla2DDrawInfo *di, struct Ipo *ipo, float ypos);
+void draw_action_channel(struct gla2DDrawInfo *di, bAction *act, float ypos);
+void draw_object_channel(struct gla2DDrawInfo *di, Object *ob, float ypos);
+
+/* Keydata Generation */
+void icu_to_keylist(struct IpoCurve *icu, ListBase *keys, ListBase *blocks);
+void ipo_to_keylist(struct Ipo *ipo, ListBase *keys, ListBase *blocks);
+void action_to_keylist(bAction *act, ListBase *keys, ListBase *blocks);
+void ob_to_keylist(Object *ob, ListBase *keys, ListBase *blocks);
+
+#endif /* BDR_DRAWACTION_H */
+
diff --git a/source/blender/include/BDR_drawmesh.h b/source/blender/include/BDR_drawmesh.h
new file mode 100644
index 00000000000..998cadc18a3
--- /dev/null
+++ b/source/blender/include/BDR_drawmesh.h
@@ -0,0 +1,84 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BDR_DRAWMESH_H
+#define BDR_DRAWMESH_H
+
+struct Image;
+struct MTFace;
+struct Object;
+struct DerivedMesh;
+struct Mesh;
+struct EdgeHash;
+
+/**
+ * Enables or disable mipmapping for realtime images (textures).
+ * Note that this will will destroy all texture bindings in OpenGL.
+ * @see free_realtime_image()
+ * @param mipmap Turn mipmapping on (mipmap!=0) or off (mipmap==0).
+ */
+void set_mipmap(int mipmap);
+
+/**
+ * Enables or disable linear mipmap setting for realtime images (textures).
+ * Note that this will will destroy all texture bindings in OpenGL.
+ * @see free_realtime_image()
+ * @param mipmap Turn linear mipmapping on (linear!=0) or off (linear==0).
+ */
+void set_linear_mipmap(int linear);
+
+/**
+ * Returns the current setting for linear mipmapping.
+ */
+int get_linear_mipmap(void);
+
+/**
+ * Resets the realtime image cache variables.
+ */
+void clear_realtime_image_cache(void);
+
+
+void update_realtime_image(struct Image *ima, int x, int y, int w, int h);
+void free_realtime_image(struct Image *ima);
+void free_all_realtime_images(void);
+void make_repbind(struct Image *ima);
+int set_tpage(struct MTFace *tface);
+
+void texpaint_enable_mipmap(void);
+void texpaint_disable_mipmap(void);
+
+void draw_mesh_textured(struct Object *ob, struct DerivedMesh *dm, int facesel);
+struct EdgeHash *get_tface_mesh_marked_edge_info(struct Mesh *me);
+void init_realtime_GL(void);
+
+#endif /* BDR_DRAWMESH_H */
+
diff --git a/source/blender/include/BDR_drawobject.h b/source/blender/include/BDR_drawobject.h
new file mode 100644
index 00000000000..05bf4d75e88
--- /dev/null
+++ b/source/blender/include/BDR_drawobject.h
@@ -0,0 +1,82 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BDR_DRAWOBJECT_H
+#define BDR_DRAWOBJECT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+struct Object;
+struct Nurb;
+struct Lamp;
+struct ListBase;
+struct BoundBox;
+struct Base;
+struct BPoint;
+struct BezTriple;
+struct EditVert;
+struct EditFace;
+struct EditEdge;
+
+int set_gl_material(int nr);
+int init_gl_materials(struct Object *ob, int check_alpha);
+
+void mesh_foreachScreenVert(void (*func)(void *userData, struct EditVert *eve, int x, int y, int index), void *userData, int clipVerts);
+void mesh_foreachScreenEdge(void (*func)(void *userData, struct EditEdge *eed, int x0, int y0, int x1, int y1, int index), void *userData, int clipVerts);
+void mesh_foreachScreenFace(void (*func)(void *userData, struct EditFace *efa, int x, int y, int index), void *userData);
+
+void lattice_foreachScreenVert(void (*func)(void *userData, struct BPoint *bp, int x, int y), void *userData);
+void nurbs_foreachScreenVert(void (*func)(void *userData, struct Nurb *nu, struct BPoint *bp, struct BezTriple *bezt, int beztindex, int x, int y), void *userData);
+
+void drawcircball(int mode, float *cent, float rad, float tmat[][4]);
+void get_local_bounds(struct Object *ob, float *center, float *size);
+
+/* drawing flags: */
+#define DRAW_PICKING 1
+#define DRAW_CONSTCOLOR 2
+void draw_object(struct Base *base, int flag);
+void drawaxes(float size, int flag, char drawtype);
+
+void draw_object_ext(struct Base *base);
+void drawsolidcube(float size);
+extern void draw_object_backbufsel(struct Object *ob);
+void draw_object_instance(struct Object *ob, int dt, int outline);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BDR_DRAWOBJECT_H */
+
diff --git a/source/blender/include/BDR_editcurve.h b/source/blender/include/BDR_editcurve.h
new file mode 100644
index 00000000000..a8c36c3485b
--- /dev/null
+++ b/source/blender/include/BDR_editcurve.h
@@ -0,0 +1,102 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BDR_EDITCURVE_H
+#define BDR_EDITCURVE_H
+
+struct Object;
+struct Curve;
+struct Nurb;
+struct BezTriple;
+struct BPoint;
+struct BezTripleNurb;
+
+short isNurbsel(struct Nurb *nu);
+int isNurbsel_count(struct Nurb *nu);
+void printknots(void);
+void load_editNurb(void);
+void make_editNurb(void);
+void remake_editNurb(void);
+void separate_nurb(void);
+short isNurbselUV(struct Nurb *nu, int *u, int *v, int flag);
+void setflagsNurb(short flag);
+void rotateflagNurb(short flag, float *cent, float rotmat[][3]);
+void translateflagNurb(short flag, float *vec);
+void weightflagNurb(short flag, float w, int mode);
+void deleteflagNurb(short flag);
+short extrudeflagNurb(int flag);
+void adduplicateflagNurb(short flag);
+void switchdirectionNurb2(void);
+void switchdirection_knots(float *base, int tot);
+void deselectall_nurb(void);
+void hideNurb(int swap);
+void revealNurb(void);
+void selectswapNurb(void);
+void subdivideNurb(void);
+
+int convertspline(short type, struct Nurb *nu);
+void setsplinetype(short type);
+void rotate_direction_nurb(struct Nurb *nu);
+int is_u_selected(struct Nurb *nu, int u);
+void make_selection_list_nurb(void);
+void merge_2_nurb(struct Nurb *nu1, struct Nurb *nu2);
+void merge_nurb(void);
+void addsegment_nurb(void);
+void mouse_nurb(void);
+void spinNurb(float *dvec, short mode);
+void addvert_Nurb(int mode);
+void extrude_nurb(void);
+void makecyclicNurb(void);
+void selectconnected_nurb(void);
+void selectrow_nurb(void);
+void selectend_nurb(short selfirst, short doswap, short selstatus);
+void select_more_nurb(void);
+void select_less_nurb(void);
+void select_next_nurb(void);
+void select_prev_nurb(void);
+void select_random_nurb(void);
+void select_every_nth_nurb(void);
+void adduplicate_nurb(void);
+void delNurb(void);
+void nurb_set_smooth(short event);
+int join_curve(int type);
+struct Nurb *addNurbprim(int type, int stype, int newname);
+void default_curve_ipo(struct Curve *cu);
+void add_primitiveCurve(int stype);
+void add_primitiveNurb(int type);
+void clear_tilt(void);
+void clever_numbuts_curve(void);
+int bezt_compare (const void *e1, const void *e2);
+
+extern void undo_push_curve(char *name);
+
+#endif /* BDR_EDITCURVE_H */
diff --git a/source/blender/include/BDR_editface.h b/source/blender/include/BDR_editface.h
new file mode 100644
index 00000000000..72b0e7352da
--- /dev/null
+++ b/source/blender/include/BDR_editface.h
@@ -0,0 +1,61 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BDR_EDITFACE_H
+#define BDR_EDITFACE_H
+
+struct MTFace;
+struct EditFace;
+struct Mesh;
+struct MCol;
+
+struct MTFace *get_active_mtface(struct EditFace **efa, struct MCol **mcol, short sloppy);
+void calculate_uv_map(unsigned short mapmode);
+void default_uv(float uv[][2], float size);
+void make_tfaces(struct Mesh *me);
+void reveal_tface(void);
+void hide_tface(void);
+void select_linked_tfaces(int mode);
+void deselectall_tface(void);
+void selectswap_tface(void);
+void rotate_uv_tface(void);
+void mirror_uv_tface(void);
+int minmax_tface(float *min, float *max);
+void face_select(void);
+void face_borderselect(void);
+void uv_autocalc_tface(void);
+void set_texturepaint(void);
+void get_same_uv(void);
+void seam_mark_clear_tface(short mode);
+
+#endif /* BDR_EDITFACE_H */
+
diff --git a/source/blender/include/BDR_editmball.h b/source/blender/include/BDR_editmball.h
new file mode 100644
index 00000000000..e2b529acaf8
--- /dev/null
+++ b/source/blender/include/BDR_editmball.h
@@ -0,0 +1,56 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BDR_EDITMBALL_H
+#define BDR_EDITMBALL_H
+
+void make_editMball(void);
+void load_editMball(void);
+
+/**
+ * @attention The argument is discarded. It is there for
+ * compatibility.
+ */
+void add_primitiveMball(int);
+void deselectall_mball(void);
+void selectinverse_mball(void);
+void selectrandom_mball(void);
+void mouse_mball(void);
+void adduplicate_mball(void);
+void delete_mball(void);
+void freeMetaElemlist(struct ListBase *lb);
+void undo_push_mball(char *name);
+void hide_mball(char hide);
+void reveal_mball(void);
+
+#endif /* BDR_EDITMBALL_H */
+
diff --git a/source/blender/include/BDR_editobject.h b/source/blender/include/BDR_editobject.h
new file mode 100644
index 00000000000..2a96a8d65cb
--- /dev/null
+++ b/source/blender/include/BDR_editobject.h
@@ -0,0 +1,125 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BDR_EDITOBJECT_H
+#define BDR_EDITOBJECT_H
+
+struct Object;
+struct Tex;
+struct Material;
+struct Base;
+struct HookModifierData;
+struct Scene;
+
+void add_object_draw(int type);
+void add_objectLamp(short type);
+void free_and_unlink_base_from_scene(struct Scene *scene, struct Base *base);
+void free_and_unlink_base(struct Base *base);
+void delete_obj(int ok);
+void make_track(void);
+void apply_obmat(struct Object *ob);
+void clear_parent(void);
+void clear_track(void);
+void clear_object(char mode);
+void reset_slowparents(void);
+void set_slowparent(void);
+void make_vertex_parent(void);
+int test_parent_loop(struct Object *par, struct Object *ob);
+void make_parent(void);
+void make_proxy(void);
+
+#define EM_WAITCURSOR (1 << 0)
+#define EM_FREEDATA (1 << 1)
+#define EM_FREEUNDO (1 << 2)
+
+void exit_editmode(int flag);
+void check_editmode(int type);
+void enter_editmode(int wc);
+
+void docenter(int centermode);
+void docenter_new(void);
+void docenter_cursor(void);
+void movetolayer(void);
+void special_editmenu(void);
+void convertmenu(void);
+void copy_attr_menu(void);
+void copy_attr(short event);
+void link_to_scene(unsigned short nr);
+void make_links_menu(void);
+void make_links(short event);
+void make_duplilist_real(void);
+void apply_object(void);
+
+/* old transform */
+void apply_keyb_grid(float *val, float fac1, float fac2, float fac3, int invert);
+void headerprint(char *str);
+/* used for old game engine collision optimize */
+int cylinder_intersect_test(void);
+int sphere_intersect_test(void);
+
+
+void std_rmouse_transform(void (*xf_func)(int, int));
+void rightmouse_transform(void);
+void single_object_users(int flag);
+void new_id_matar(struct Material **matar, int totcol);
+void single_obdata_users(int flag);
+void single_mat_users(int flag);
+void do_single_tex_user(struct Tex **from);
+void single_tex_users_expand(void);
+void single_mat_users_expand(void);
+void single_user(void);
+void make_local_menu(void);
+void make_local(int mode);
+void adduplicate(int mode, int dupflag); /* when the dupflag is 0 no data is duplicated */
+void selectlinks_menu(void);
+void selectlinks(int nr);
+void image_aspect(void);
+void set_ob_ipoflags(void);
+void select_select_keys(void);
+int vergbaseco(const void *a1, const void *a2);
+void auto_timeoffs(void);
+void texspace_edit(void);
+void flip_subdivison(int);
+void mirrormenu(void);
+void hookmenu(void); /* object mode hook menu */
+
+
+void add_hook(void);
+void hook_select(struct HookModifierData *hmd);
+int hook_getIndexArray(int *tot, int **indexar, char *name, float *cent_r);
+
+int object_data_is_libdata(struct Object *ob);
+void hide_objects(int select);
+void show_objects(void);
+
+#endif /* BDR_EDITOBJECT_H */
+
diff --git a/source/blender/include/BDR_imagepaint.h b/source/blender/include/BDR_imagepaint.h
new file mode 100644
index 00000000000..e687d220906
--- /dev/null
+++ b/source/blender/include/BDR_imagepaint.h
@@ -0,0 +1,44 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BDR_IMAGEPAINT_H
+#define BDR_IMAGEPAINT_H
+
+void imagepaint_redraw_tool(void);
+void imagepaint_pick(short mousebutton);
+void imagepaint_paint(short mousebutton, short texturepaint);
+
+void imagepaint_undo();
+void free_imagepaint();
+
+#endif /* BDR_IMAGEPAINT_H */
+
diff --git a/source/blender/include/BDR_sculptmode.h b/source/blender/include/BDR_sculptmode.h
new file mode 100644
index 00000000000..c80f9ea8626
--- /dev/null
+++ b/source/blender/include/BDR_sculptmode.h
@@ -0,0 +1,142 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 by Nicholas Bishop
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef BDR_SCULPTMODE_H
+#define BDR_SCULPTMODE_H
+
+#include "DNA_listBase.h"
+#include "DNA_vec_types.h"
+/* For bglMats */
+#include "BIF_glutil.h"
+#include "transform.h"
+
+struct uiBlock;
+struct BrushData;
+struct EditData;
+struct IndexNode;
+struct KeyBlock;
+struct Mesh;
+struct Object;
+struct PartialVisibility;
+struct Scene;
+struct ScrArea;
+struct SculptData;
+struct SculptStroke;
+
+typedef enum PropsetMode {
+ PropsetNone = 0,
+ PropsetSize,
+ PropsetStrength,
+ PropsetTexRot
+} PropsetMode;
+typedef struct PropsetData {
+ PropsetMode mode;
+ unsigned int tex;
+ short origloc[2];
+ float *texdata;
+
+ short origsize;
+ char origstrength;
+ float origtexrot;
+
+ NumInput num;
+} PropsetData;
+
+typedef struct SculptSession {
+ bglMats mats;
+
+ /* An array of lists; array is sized as
+ large as the number of verts in the mesh,
+ the list for each vert contains the index
+ for all the faces that use that vertex */
+ struct ListBase *vertex_users;
+ struct IndexNode *vertex_users_mem;
+ int vertex_users_size;
+
+ /* Used temporarily per-stroke */
+ float *vertexcosnos;
+ ListBase damaged_rects;
+ ListBase damaged_verts;
+
+ /* Used to cache the render of the active texture */
+ unsigned int texcache_w, texcache_h, *texcache;
+
+ PropsetData *propset;
+
+ /* For rotating around a pivot point */
+ vec3f pivot;
+
+ struct SculptStroke *stroke;
+} SculptSession;
+
+SculptSession *sculpt_session(void);
+struct SculptData *sculpt_data(void);
+
+/* Memory */
+void sculptmode_init(struct Scene *);
+void sculptmode_free_all(struct Scene *);
+void sculptmode_correct_state(void);
+
+/* Interface */
+void sculptmode_draw_interface_tools(struct uiBlock *block,unsigned short cx, unsigned short cy);
+void sculptmode_draw_interface_textures(struct uiBlock *block,unsigned short cx, unsigned short cy);
+void sculptmode_rem_tex(void*,void*);
+void sculptmode_propset_init(PropsetMode mode);
+void sculptmode_propset(const unsigned short event);
+void sculptmode_selectbrush_menu(void);
+void sculptmode_draw_mesh(int);
+void sculpt_paint_brush(char clear);
+void sculpt_stroke_draw();
+
+struct BrushData *sculptmode_brush(void);
+float tex_angle(void);
+void do_symmetrical_brush_actions(struct EditData *e, short *, short *);
+
+void sculptmode_update_tex(void);
+char sculpt_modifiers_active(struct Object *ob);
+void sculpt(void);
+void set_sculptmode(void);
+
+/* Stroke */
+void sculpt_stroke_new(const int max);
+void sculpt_stroke_free();
+void sculpt_stroke_add_point(const short x, const short y);
+void sculpt_stroke_apply(struct EditData *);
+void sculpt_stroke_apply_all(struct EditData *e);
+void sculpt_stroke_draw();
+
+
+/* Partial Mesh Visibility */
+struct PartialVisibility *sculptmode_copy_pmv(struct PartialVisibility *);
+void sculptmode_pmv_free(struct PartialVisibility *);
+void sculptmode_revert_pmv(struct Mesh *me);
+void sculptmode_pmv_off(struct Mesh *me);
+void sculptmode_pmv(int mode);
+
+#endif
diff --git a/source/blender/include/BDR_unwrapper.h b/source/blender/include/BDR_unwrapper.h
new file mode 100644
index 00000000000..6a2b54409c3
--- /dev/null
+++ b/source/blender/include/BDR_unwrapper.h
@@ -0,0 +1,51 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BDR_UNWRAPPER_H
+#define BDR_UNWRAPPER_H
+
+struct Mesh;
+
+void set_seamtface(void); /* set TF_SEAM flags in tfaces */
+void select_linked_tfaces_with_seams(int mode, struct Mesh *me, unsigned int index);
+
+void unwrap_lscm(short seamcut); /* unwrap faces selected in 3d view */
+void minimize_stretch_tface_uv(void); /* optimize faces selected in uv editor */
+void pack_charts_tface_uv(void);
+
+/* for live mode: no undo pushes, caching for quicky re-unwrap */
+void unwrap_lscm_live_begin(void);
+void unwrap_lscm_live_re_solve(void);
+void unwrap_lscm_live_end(short cancel);
+
+#endif /* BDR_UNWRAPPER_H */
+
diff --git a/source/blender/include/BDR_vpaint.h b/source/blender/include/BDR_vpaint.h
new file mode 100644
index 00000000000..dcf9d4ce51a
--- /dev/null
+++ b/source/blender/include/BDR_vpaint.h
@@ -0,0 +1,58 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BDR_VPAINT_H
+#define BDR_VPAINT_H
+
+struct Mesh;
+struct MDeformVert; /* __NLA */
+
+unsigned int rgba_to_mcol(float r, float g, float b, float a);
+void do_shared_vertexcol(struct Mesh *me);
+void make_vertexcol(int shade);
+
+void clear_vpaint(void);
+void clear_vpaint_selectedfaces(void);
+void vpaint_dogamma(void);
+void sample_vpaint(void);
+
+void free_vertexpaint(void);
+void vertex_paint(void);
+void set_vpaint(void);
+
+void set_wpaint(void);
+void clear_wpaint_selectedfaces(void);
+void weight_paint(void);
+
+
+#endif /* BDR_VPAINT_H */
+
diff --git a/source/blender/include/BIF_butspace.h b/source/blender/include/BIF_butspace.h
new file mode 100644
index 00000000000..eb2cafad792
--- /dev/null
+++ b/source/blender/include/BIF_butspace.h
@@ -0,0 +1,139 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BIF_BUTSPACE_H
+#define BIF_BUTSPACE_H
+
+/* all internal/external calls and event codes for buttons space */
+/* should be split in 2 parts... */
+
+struct Base;
+struct ID;
+
+/* external, butspace.c */
+extern void do_butspace(unsigned short event);
+extern void redraw_test_buttons(struct Object *new);
+
+extern char *image_type_pup(void);
+
+/* buttons_editing.c */
+extern void validate_editbonebutton_cb(void *bonev, void *namev);
+
+/* buts->mainb old */
+#define BUTS_VIEW 0
+#define BUTS_LAMP 1
+#define BUTS_MAT 2
+#define BUTS_TEX 3
+#define BUTS_ANIM 4
+#define BUTS_WORLD 5
+#define BUTS_RENDER 6
+#define BUTS_EDIT 7
+#define BUTS_GAME 8
+#define BUTS_FPAINT 9
+#define BUTS_RADIO 10
+#define BUTS_SCRIPT 11
+#define BUTS_SOUND 12
+#define BUTS_CONSTRAINT 13
+#define BUTS_EFFECTS 14
+
+/* warning: the values of these defines are used in sbuts->tabs[7] */
+/* buts->mainb new */
+#define CONTEXT_SCENE 0
+#define CONTEXT_OBJECT 1
+#define CONTEXT_TYPES 2
+#define CONTEXT_SHADING 3
+#define CONTEXT_EDITING 4
+#define CONTEXT_SCRIPT 5
+#define CONTEXT_LOGIC 6
+
+/* buts->tab new */
+#define TAB_SHADING_MAT 0
+#define TAB_SHADING_TEX 1
+#define TAB_SHADING_RAD 2
+#define TAB_SHADING_WORLD 3
+#define TAB_SHADING_LAMP 4
+
+#define TAB_OBJECT_OBJECT 0
+#define TAB_OBJECT_PHYSICS 1
+
+#define TAB_SCENE_RENDER 0
+#define TAB_SCENE_WORLD 1
+#define TAB_SCENE_ANIM 2
+#define TAB_SCENE_SOUND 3
+
+
+/* buts->scaflag */
+#define BUTS_SENS_SEL 1
+#define BUTS_SENS_ACT 2
+#define BUTS_SENS_LINK 4
+#define BUTS_CONT_SEL 8
+#define BUTS_CONT_ACT 16
+#define BUTS_CONT_LINK 32
+#define BUTS_ACT_SEL 64
+#define BUTS_ACT_ACT 128
+#define BUTS_ACT_LINK 256
+
+
+/* buttons grid */
+#define PANELX 320
+#define PANELY 0
+#define PANELW 318
+#define PANELH 204
+
+#define BUTW1 300
+#define BUTW2 145
+#define BUTW3 93
+#define BUTW4 67
+#define ICONBUTW 20
+#define BUTH 22
+
+#define YSPACE 6
+#define XSPACE 10
+#define PANEL_YMAX 210
+#define PANEL_XMAX 310
+
+#define X1CLM1 10
+
+#define X2CLM1 X1CLM1
+#define X2CLM2 165
+
+#define X3CLM1 X1CLM1
+#define X3CLM2 113
+#define X3CLM3 217
+
+#define X4CLM1 X1CLM1
+#define X4CLM2 77
+#define X4CLM3 165
+#define X4CLM4 232
+
+
+#endif
+
diff --git a/source/blender/include/BIF_cursors.h b/source/blender/include/BIF_cursors.h
new file mode 100644
index 00000000000..fe3ff6e2506
--- /dev/null
+++ b/source/blender/include/BIF_cursors.h
@@ -0,0 +1,103 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+
+
+#ifndef __BLI_CURSORS_DOT_H__
+#define __BLI_CURSORS_DOT_H__
+
+void InitCursorData(void);
+short GetBlenderCursor(void);
+void SetBlenderCursor(short cursornum);
+
+//typedef struct BCursor_s BCursor;
+typedef struct BCursor {
+
+ char *small_bm;
+ char *small_mask;
+
+ char small_sizex;
+ char small_sizey;
+ char small_hotx;
+ char small_hoty;
+
+ char *big_bm;
+ char *big_mask;
+
+ char big_sizex;
+ char big_sizey;
+ char big_hotx;
+ char big_hoty;
+
+ char fg_color;
+ char bg_color;
+
+} BCursor;
+
+#define LASTCURSOR -2
+#define SYSCURSOR -1
+enum {
+ BC_NW_ARROWCURSOR=0,
+ BC_NS_ARROWCURSOR,
+ BC_EW_ARROWCURSOR,
+ BC_WAITCURSOR,
+ BC_CROSSCURSOR,
+ BC_EDITCROSSCURSOR,
+ BC_BOXSELCURSOR,
+ BC_KNIFECURSOR,
+ BC_VLOOPCURSOR,
+ BC_TEXTEDITCURSOR,
+ BC_PAINTBRUSHCURSOR,
+ BC_HANDCURSOR,
+ BC_NSEW_SCROLLCURSOR,
+ BC_NS_SCROLLCURSOR,
+ BC_EW_SCROLLCURSOR,
+ BC_EYEDROPPER_CURSOR,
+/* --- ALWAYS LAST ----- */
+ BC_NUMCURSORS,
+};
+
+
+enum {
+ BC_BLACK=0,
+ BC_WHITE,
+ BC_RED,
+ BC_BLUE,
+ BC_GREEN,
+ BC_YELLOW
+};
+
+#define SMALL_CURSOR 0
+#define BIG_CURSOR 1
+
+#endif
+
diff --git a/source/blender/include/BIF_drawimage.h b/source/blender/include/BIF_drawimage.h
new file mode 100644
index 00000000000..44e40b8cabb
--- /dev/null
+++ b/source/blender/include/BIF_drawimage.h
@@ -0,0 +1,74 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_DRAWIMAGE_H
+#define BIF_DRAWIMAGE_H
+
+struct ScrArea;
+struct SpaceImage;
+struct Render;
+struct Image;
+struct ImBuf;
+struct uiBlock;
+struct MTFace;
+
+void do_imagebuts(unsigned short event);
+void calc_image_view(struct SpaceImage *sima, char mode);
+void drawimagespace(struct ScrArea *sa, void *spacedata);
+void image_changed(struct SpaceImage *sima, struct Image *image);
+int draw_uvs_face_check(void);
+void tface_center(struct MTFace *tf, float cent[2], void * isquad);
+void draw_uvs_sima(void);
+void image_set_tile(struct SpaceImage *sima, int dotile);
+void image_home(void);
+void image_viewmove(int mode);
+void image_viewzoom(unsigned short event, int invert);
+void image_viewcenter(void);
+void uvco_to_areaco(float *vec, short *mval);
+void uvco_to_areaco_noclip(float *vec, int *mval);
+void what_image(struct SpaceImage *sima);
+void image_preview_event(int event);
+
+void image_info(struct Image *ima, struct ImBuf *ibuf, char *str);
+void imagespace_composite_flipbook(struct ScrArea *sa);
+
+void imagewindow_render_callbacks(struct Render *re);
+void imagewindow_toggle_render(void);
+void imagewindow_swap_render_rects(void);
+void imagewin_store_spare(void);
+struct ImBuf *imagewindow_get_ibuf(struct SpaceImage *sima);
+
+void image_editvertex_buts(struct uiBlock *block);
+void image_editcursor_buts(struct uiBlock *block);
+
+#endif
+
diff --git a/source/blender/include/BIF_drawoops.h b/source/blender/include/BIF_drawoops.h
new file mode 100644
index 00000000000..b42158d14fe
--- /dev/null
+++ b/source/blender/include/BIF_drawoops.h
@@ -0,0 +1,41 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_DRAWOOPS_H
+#define BIF_DRAWOOPS_H
+
+void give_oopslink_line(Oops *oops, OopsLink *ol, float *v1, float *v2);
+void mysbox(float x1, float y1, float x2, float y2);
+void boundbox_oops(short sel);
+
+#endif
+
diff --git a/source/blender/include/BIF_drawscene.h b/source/blender/include/BIF_drawscene.h
new file mode 100644
index 00000000000..ad18542ebb4
--- /dev/null
+++ b/source/blender/include/BIF_drawscene.h
@@ -0,0 +1,35 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+struct Scene;
+void set_scene(struct Scene *sce);
+
diff --git a/source/blender/include/BIF_drawscript.h b/source/blender/include/BIF_drawscript.h
new file mode 100644
index 00000000000..b50f12e836b
--- /dev/null
+++ b/source/blender/include/BIF_drawscript.h
@@ -0,0 +1,41 @@
+/**
+ *
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_DRAWSCRIPT_H
+#define BIF_DRAWSCRIPT_H
+
+struct ScrArea;
+struct SpaceScript;
+
+void free_scriptspace(struct SpaceScript *sc);
+
+#endif /* BIF_DRAWSCRIPT_H */
diff --git a/source/blender/include/BIF_drawseq.h b/source/blender/include/BIF_drawseq.h
new file mode 100644
index 00000000000..4571267a09c
--- /dev/null
+++ b/source/blender/include/BIF_drawseq.h
@@ -0,0 +1,46 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_DRAWSEQ_H
+#define BIF_DRAWSEQ_H
+
+struct ScrArea;
+struct Sequence;
+
+void drawprefetchseqspace(struct ScrArea *sa, void *spacedata);
+void drawseqspace(struct ScrArea *sa, void *spacedata);
+void set_special_seq_update(int val);
+
+void seq_viewmove(SpaceSeq *sseq);
+void seq_reset_imageofs(SpaceSeq *sseq);
+#endif
+
diff --git a/source/blender/include/BIF_drawtext.h b/source/blender/include/BIF_drawtext.h
new file mode 100644
index 00000000000..a63e2bb264d
--- /dev/null
+++ b/source/blender/include/BIF_drawtext.h
@@ -0,0 +1,54 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_DRAWTEXT_H
+#define BIF_DRAWTEXT_H
+
+struct ScrArea;
+struct SpaceText;
+struct Text;
+
+void unlink_text(struct Text *text);
+
+void free_textspace(struct SpaceText *st);
+
+void txt_write_file(struct Text *text);
+void add_text_fs(char *file);
+
+void free_txt_data(void);
+void pop_space_text(struct SpaceText *st);
+
+void get_format_string(void);
+void do_brackets(void);
+
+#endif
+
diff --git a/source/blender/include/BIF_editaction.h b/source/blender/include/BIF_editaction.h
new file mode 100644
index 00000000000..fe6f81b9416
--- /dev/null
+++ b/source/blender/include/BIF_editaction.h
@@ -0,0 +1,162 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): 2007, Joshua Leung, Action Editor Recode
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_EDITACTION_H
+#define BIF_EDITACTION_H
+
+/* some interface related sizes*/
+#define CHANNELHEIGHT 16
+#define CHANNELSKIP 2
+#define NAMEWIDTH 164
+#define SLIDERWIDTH 125
+#define ACTWIDTH (G.saction->actwidth)
+
+/* Some types for easier type-testing */
+enum {
+ ACTTYPE_NONE= 0,
+ ACTTYPE_ACHAN,
+ ACTTYPE_CONCHAN,
+ ACTTYPE_ICU,
+ ACTTYPE_FILLIPO,
+ ACTTYPE_FILLCON,
+ ACTTYPE_IPO,
+ ACTTYPE_SHAPEKEY
+};
+
+/* Macros for easier/more consistant state testing */
+#define VISIBLE_ACHAN(achan) ((achan->flag & ACHAN_HIDDEN)==0)
+#define EDITABLE_ACHAN(achan) ((VISIBLE_ACHAN(achan)) && ((achan->flag & ACHAN_PROTECTED)==0))
+#define EXPANDED_ACHAN(achan) ((VISIBLE_ACHAN(achan)) && (achan->flag & ACHAN_EXPANDED))
+#define SEL_ACHAN(achan) ((achan->flag & ACHAN_SELECTED) || (achan->flag & ACHAN_HILIGHTED))
+#define FILTER_IPO_ACHAN(achan) ((achan->flag & ACHAN_SHOWIPO))
+#define FILTER_CON_ACHAN(achan) ((achan->flag & ACHAN_SHOWCONS))
+
+#define EDITABLE_CONCHAN(conchan) ((conchan->flag & CONSTRAINT_CHANNEL_PROTECTED)==0)
+#define SEL_CONCHAN(conchan) (conchan->flag & CONSTRAINT_CHANNEL_SELECT)
+
+#define EDITABLE_ICU(icu) ((icu->flag & IPO_PROTECT)==0)
+#define SEL_ICU(icu) (icu->flag & IPO_SELECT)
+
+#define NLA_ACTION_SCALED (G.saction->pin==0 && OBACT && OBACT->action)
+#define NLA_IPO_SCALED (OBACT && OBACT->action && G.sipo->pin==0 && G.sipo->actname)
+
+/* constants for setting ipo-interpolation type */
+enum {
+ SET_IPO_MENU = -1,
+ SET_IPO_POPUP = 0,
+
+ SET_IPO_CONSTANT,
+ SET_IPO_LINEAR,
+ SET_IPO_BEZIER,
+};
+
+/* constants for setting ipo-extrapolation type */
+enum {
+
+ SET_EXTEND_MENU = 9,
+ SET_EXTEND_POPUP = 10,
+
+ SET_EXTEND_CONSTANT,
+ SET_EXTEND_EXTRAPOLATION,
+ SET_EXTEND_CYCLIC,
+ SET_EXTEND_CYCLICEXTRAPOLATION
+};
+
+
+struct bAction;
+struct bActionChannel;
+struct bPoseChannel;
+struct Object;
+struct Ipo;
+struct BWinEvent;
+struct Key;
+struct ListBase;
+
+/* Key operations */
+void transform_action_keys(int mode, int dummy);
+void duplicate_action_keys(void);
+void snap_action_keys(short mode);
+void mirror_action_keys(short mode);
+void insertkey_action(void);
+void delete_action_keys(void);
+void delete_action_channels(void);
+void clean_action(void);
+
+/* Column/Channel Key select */
+void column_select_action_keys(int mode);
+void selectall_action_keys(short mval[], short mode, short selectmode);
+void markers_selectkeys_between(void);
+
+/* Action Data Copying */
+void free_actcopybuf(void);
+void copy_actdata(void);
+void paste_actdata(void);
+
+/* channel/strip operations */
+void up_sel_action(void);
+void down_sel_action(void);
+void top_sel_action(void);
+void bottom_sel_action(void);
+
+/* IPO/Handle Types */
+void sethandles_action_keys(int code);
+void action_set_ipo_flags(short mode, short event);
+
+/* Select */
+void borderselect_action(void);
+void deselect_action_keys(short test, short sel);
+void deselect_action_channels(short test);
+void deselect_actionchannels(struct bAction *act, short test);
+int select_channel(struct bAction *act, struct bActionChannel *achan, int selectmode);
+void select_actionchannel_by_name(struct bAction *act, char *name, int select);
+
+/* ShapeKey stuff */
+struct Key *get_action_mesh_key(void);
+int get_nearest_key_num(struct Key *key, short *mval, float *x);
+
+void *get_nearest_act_channel(short mval[], short *ret_type);
+
+/* Action */
+struct bActionChannel *get_hilighted_action_channel(struct bAction* action);
+struct bAction *add_empty_action(char *name);
+struct bAction *ob_get_action(struct Object *ob);
+
+void actdata_filter(ListBase *act_data, int filter_mode, void *data, short datatype);
+void *get_action_context(short *datatype);
+
+void remake_action_ipos(struct bAction *act);
+
+/* event handling */
+void winqreadactionspace(struct ScrArea *sa, void *spacedata, struct BWinEvent *evt);
+
+#endif
+
diff --git a/source/blender/include/BIF_editarmature.h b/source/blender/include/BIF_editarmature.h
new file mode 100644
index 00000000000..903c663e5f3
--- /dev/null
+++ b/source/blender/include/BIF_editarmature.h
@@ -0,0 +1,142 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BIF_EDITARMATURE_H
+#define BIF_EDITARMATURE_H
+
+struct Object;
+struct Base;
+struct Bone;
+struct bArmature;
+struct ListBase;
+
+typedef struct EditBone
+{
+ struct EditBone *next, *prev;
+ struct EditBone *parent;/* Editbones have a one-way link (i.e. children refer
+ to parents. This is converted to a two-way link for
+ normal bones when leaving editmode. */
+ void *temp; /* Used to store temporary data */
+
+ char name[32];
+ float roll; /* Roll along axis. We'll ultimately use the axis/angle method
+ for determining the transformation matrix of the bone. The axis
+ is tail-head while roll provides the angle. Refer to Graphics
+ Gems 1 p. 466 (section IX.6) if it's not already in here somewhere*/
+
+ float head[3]; /* Orientation and length is implicit during editing */
+ float tail[3];
+ /* All joints are considered to have zero rotation with respect to
+ their parents. Therefore any rotations specified during the
+ animation are automatically relative to the bones' rest positions*/
+ int flag;
+
+ int parNr; /* Used for retrieving values from the menu system */
+
+ float dist, weight;
+ float xwidth, length, zwidth; /* put them in order! transform uses this as scale */
+ float ease1, ease2;
+ float rad_head, rad_tail;
+ short layer, segments;
+
+ float oldlength; /* for envelope scaling */
+
+} EditBone;
+
+
+void adduplicate_armature(void);
+void addvert_armature(void);
+void add_primitiveArmature(int type);
+void apply_rot_armature (struct Object *ob, float mat[3][3]);
+void docenter_armature (struct Object *ob, int centermode);
+
+void clear_armature(struct Object *ob, char mode);
+
+void delete_armature(void);
+void deselectall_armature(int toggle, int doundo);
+void deselectall_posearmature (struct Object *ob, int test, int doundo);
+int draw_armature(struct Base *base, int dt);
+void extrude_armature(int forked);
+void subdivide_armature(int numcuts);
+
+void free_editArmature(void);
+
+int join_armature(void);
+void load_editArmature(void);
+
+void make_bone_parent(void);
+void clear_bone_parent(void);
+struct Bone *get_indexed_bone (struct Object *ob, int index);
+
+void make_editArmature(void);
+void make_trans_bones (char mode);
+
+int do_pose_selectbuffer(struct Base *base, unsigned int *buffer, short hits);
+
+void mouse_armature(void);
+void remake_editArmature(void);
+void selectconnected_armature(void);
+void selectconnected_posearmature(void);
+void select_bone_parent(void);
+void unique_editbone_name (struct ListBase *ebones, char *name);
+
+void auto_align_armature(short mode);
+
+void create_vgroups_from_armature(struct Object *ob, struct Object *par);
+void add_verts_to_dgroups(struct Object *ob, struct Object *par, int heat, int mirror);
+
+void hide_selected_pose_bones(void);
+void hide_unselected_pose_bones(void);
+void show_all_pose_bones(void);
+
+int bone_looper(Object *ob, struct Bone *bone, void *data,
+ int (*bone_func)(Object *, struct Bone *, void *));
+
+void undo_push_armature(char *name);
+void armature_bone_rename(struct bArmature *arm, char *oldname, char *newname);
+void armature_flip_names(void);
+EditBone *armature_bone_get_mirrored(EditBone *ebo);
+void transform_armature_mirror_update(void);
+
+void hide_selected_armature_bones(void);
+void hide_unselected_armature_bones(void);
+void show_all_armature_bones(void);
+
+#define BONESEL_ROOT 0x10000000
+#define BONESEL_TIP 0x20000000
+#define BONESEL_BONE 0x40000000
+#define BONESEL_ANY (BONESEL_TIP|BONESEL_ROOT|BONESEL_BONE)
+
+#define BONESEL_NOSEL 0x80000000 /* Indicates a negative number */
+
+#endif
+
+
diff --git a/source/blender/include/BIF_editconstraint.h b/source/blender/include/BIF_editconstraint.h
new file mode 100644
index 00000000000..b8977c00d89
--- /dev/null
+++ b/source/blender/include/BIF_editconstraint.h
@@ -0,0 +1,72 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_EDITCONSTRAINT_H
+#define BIF_EDITCONSTRAINT_H
+
+struct ID;
+struct ListBase;
+struct Object;
+struct bConstraint;
+struct bConstraintChannel;
+struct Text;
+
+/* generic constraint editing functions */
+
+struct bConstraint *add_new_constraint(short type);
+
+void add_constraint_to_object(struct bConstraint *con, struct Object *ob);
+
+struct ListBase *get_active_constraints(struct Object *ob);
+struct bConstraint *get_active_constraint(struct Object *ob);
+struct ListBase *get_active_constraint_channels (struct Object *ob, int forcevalid);
+struct bConstraintChannel *get_active_constraint_channel(struct Object *ob);
+
+void object_test_constraints(struct Object *owner);
+
+void add_constraint(int only_IK);
+void ob_clear_constraints(void);
+
+void rename_constraint(struct Object *ob, struct bConstraint *con, char *newname);
+
+
+/* a few special functions for PyConstraints */
+char *buildmenu_pyconstraints(struct Text *con_text, int *pyconindex);
+void validate_pyconstraint_cb(void *arg1, void *arg2);
+void update_pyconstraint_cb(void *arg1, void *arg2);
+
+/* two special functions for ChildOf Constriant */
+void childof_const_setinv (void *conv, void *unused);
+void childof_const_clearinv(void *conv, void *unused);
+
+#endif
+
diff --git a/source/blender/include/BIF_editdeform.h b/source/blender/include/BIF_editdeform.h
new file mode 100644
index 00000000000..2a8f43c14e7
--- /dev/null
+++ b/source/blender/include/BIF_editdeform.h
@@ -0,0 +1,74 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_DEFORM_H
+#define BIF_DEFORM_H
+
+#define WEIGHT_REPLACE 1
+#define WEIGHT_ADD 2
+#define WEIGHT_SUBTRACT 3
+
+struct Object;
+struct Mesh;
+struct MDeformVert;
+struct MDeformWeight;
+struct bDeformGroup;
+
+struct bDeformGroup *add_defgroup_name (struct Object *ob, char *name);
+void add_defgroup (struct Object *ob);
+void del_defgroup_in_object_mode ( Object *ob );
+void del_defgroup (struct Object *ob);
+void duplicate_defgroup ( struct Object *ob );
+void assign_verts_defgroup (void);
+void remove_verts_defgroup (int allverts);
+void sel_verts_defgroup (int select);
+
+struct MDeformWeight *get_defweight (struct MDeformVert *dv, int defgroup);
+struct MDeformWeight *verify_defweight (struct MDeformVert *dv, int defgroup);
+
+
+void add_vert_to_defgroup (struct Object *ob, struct bDeformGroup *dg,
+ int vertnum, float weight,
+ int assignmode);
+void remove_vert_defgroup (struct Object *ob, struct bDeformGroup *dg,
+ int vertnum);
+void create_dverts(ID *id);
+
+void vertexgroup_select_by_name(struct Object *ob, char *name);
+
+extern void object_apply_deform(struct Object *ob);
+
+void vgroup_assign_with_menu(void);
+void vgroup_operation_with_menu(void);
+
+#endif
+
diff --git a/source/blender/include/BIF_editfont.h b/source/blender/include/BIF_editfont.h
new file mode 100644
index 00000000000..0c2c9d2779f
--- /dev/null
+++ b/source/blender/include/BIF_editfont.h
@@ -0,0 +1,73 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <wchar.h>
+
+#ifndef BIF_EDITFONT_H
+#define BIF_EDITFONT_H
+
+struct Text;
+
+extern char *BIF_lorem;
+extern wchar_t *copybuf;
+extern wchar_t *copybufinfo;
+
+typedef struct unicodect
+{
+ char *name;
+ char *longname;
+ int start;
+ int end;
+} unicodect;
+
+void do_textedit(unsigned short event, short val, unsigned long _ascii);
+void make_editText(void);
+void load_editText(void);
+void remake_editText(void);
+void free_editText(void);
+void paste_editText(void);
+void txt_export_to_object(struct Text *text);
+void txt_export_to_objects(struct Text *text);
+void undo_push_font(char *);
+void load_3dtext_fs(char *);
+void add_lorem(void);
+void paste_unicodeText(char *filename);
+
+/**
+ * @attention The argument is discarded. It is there for
+ * compatibility.
+ */
+void add_primitiveFont(int);
+void to_upper(void);
+
+#endif
+
diff --git a/source/blender/include/BIF_editgroup.h b/source/blender/include/BIF_editgroup.h
new file mode 100644
index 00000000000..9873a7aaef3
--- /dev/null
+++ b/source/blender/include/BIF_editgroup.h
@@ -0,0 +1,40 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+struct Group;
+struct Base;
+
+void add_selected_to_group(struct Group *group);
+void rem_selected_from_group(void);
+void group_operation_with_menu(void);
+void group_operation(int mode);
+
diff --git a/source/blender/include/BIF_editkey.h b/source/blender/include/BIF_editkey.h
new file mode 100644
index 00000000000..6c03e62a24c
--- /dev/null
+++ b/source/blender/include/BIF_editkey.h
@@ -0,0 +1,70 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_EDITKEY_H
+#define BIF_EDITKEY_H
+
+struct Key;
+struct KeyBlock;
+struct Mesh;
+struct Object;
+struct Lattice;
+struct Curve;
+struct uiBlock;
+struct BezTriple;
+struct IpoCurve;
+
+void mesh_to_key(struct Mesh *me, struct KeyBlock *kb);
+void key_to_mesh(struct KeyBlock *kb, struct Mesh *me);
+void insert_meshkey(struct Mesh *me, short rel);
+
+void latt_to_key(struct Lattice *lt, struct KeyBlock *kb);
+void key_to_latt(struct KeyBlock *kb, struct Lattice *lt);
+void insert_lattkey(struct Lattice *lt, short rel);
+
+void curve_to_key(struct Curve *cu, struct KeyBlock *kb, ListBase *nurb);
+void key_to_curve(struct KeyBlock *kb, struct Curve *cu, ListBase *nurb);
+void insert_curvekey(struct Curve *cu, short rel);
+
+void insert_shapekey(struct Object *ob);
+
+void delete_key(struct Object *ob);
+void move_keys(struct Object *ob);
+
+void make_rvk_slider(struct uiBlock *block, struct Object *ob, int keynum,
+ int x, int y, int w, int h, char *tip);
+
+// FIXME: move me somewhere else
+struct BezTriple *get_bezt_icu_time(struct IpoCurve *icu, float *frame, float *val);
+
+#endif
+
diff --git a/source/blender/include/BIF_editlattice.h b/source/blender/include/BIF_editlattice.h
new file mode 100644
index 00000000000..c7cf6c570ac
--- /dev/null
+++ b/source/blender/include/BIF_editlattice.h
@@ -0,0 +1,45 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_EDITLATTICE_H
+#define BIF_EDITLATTICE_H
+
+void free_editLatt(void);
+void make_editLatt(void);
+void load_editLatt(void);
+void remake_editLatt(void);
+void deselectall_Latt(void);
+void mouse_lattice(void);
+void undo_push_lattice(char *name);
+
+#endif
+
diff --git a/source/blender/include/BIF_editmesh.h b/source/blender/include/BIF_editmesh.h
new file mode 100644
index 00000000000..42d581ee758
--- /dev/null
+++ b/source/blender/include/BIF_editmesh.h
@@ -0,0 +1,265 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/* External for editmesh_xxxx.c functions */
+
+#ifndef BIF_EDITMESH_H
+#define BIF_EDITMESH_H
+
+#include "BKE_mesh.h"
+
+struct EditMesh;
+struct EditFace;
+struct EditEdge;
+struct EditVert;
+struct Mesh;
+struct bDeformGroup;
+struct View3D;
+struct EditSelection;
+struct CustomData;
+
+// edge and face flag both
+#define EM_FGON 2
+// face flag
+#define EM_FGON_DRAW 1
+
+extern unsigned int em_vertoffs, em_solidoffs, em_wireoffs;
+
+/* ******************* editmesh.c */
+extern void make_editMesh(void);
+extern void load_editMesh(void);
+extern void free_editMesh(struct EditMesh *);
+extern void remake_editMesh(void);
+
+ /* Editmesh Undo code */
+extern void undo_push_mesh(char *name);
+
+extern void separatemenu(void);
+extern void separate_mesh(void);
+extern void separate_mesh_loose(void);
+extern void separate_material(void);
+
+/* ******************* editmesh_add.c */
+extern void make_prim(int type, float imat[3][3], int tot, int seg,
+ int subdiv, float dia, float d, int ext, int fill,
+ float cent[3] );
+extern void add_primitiveMesh(int type);
+extern void adduplicate_mesh(void);
+extern void add_click_mesh(void);
+extern void addedgeface_mesh(void);
+void addfaces_from_edgenet();
+
+/* ******************* editmesh_lib.c */
+
+extern void EM_set_flag_all(int flag);
+extern void EM_clear_flag_all(int flag);
+
+extern void EM_select_face(struct EditFace *efa, int sel);
+extern void EM_select_edge(struct EditEdge *eed, int sel);
+extern float EM_face_area(struct EditFace *efa);
+extern float EM_face_perimeter(struct EditFace *efa);
+extern void EM_editselection_center(float *center, struct EditSelection *ese);
+extern void EM_editselection_normal(float *normal, struct EditSelection *ese);
+extern void EM_editselection_plane(float *plane, struct EditSelection *ese);
+
+extern void EM_deselect_flush(void); // vertices to edges/faces (exception!)
+extern void EM_select_flush(void); // vertices to edges/faces (exception!)
+extern void EM_selectmode_set(void); // when mode changes
+extern void EM_selectmode_flush(void); // when selection changes
+extern void EM_convertsel(short oldmode, short selectmode);
+extern void EM_remove_selection(void *data, int type);
+extern void EM_store_selection(void *data, int type);
+extern void EM_validate_selections(void);
+
+extern int EM_nfaces_selected(void);
+extern int EM_nvertices_selected(void);
+
+extern int faceselectedAND(struct EditFace *efa, int flag);
+extern void recalc_editnormals(void);
+extern void flip_editnormals(void);
+
+extern void EM_data_interp_from_verts(struct EditVert *v1,
+ struct EditVert *v2, struct EditVert *eve, float fac);
+extern struct EditFace *EM_face_from_faces(struct EditFace *efa1,
+ struct EditFace *efa2, int i1, int i2, int i3, int i4);
+extern void EM_data_interp_from_faces(struct EditFace *efa1,
+ struct EditFace *efa2, struct EditFace *efan, int i1, int i2, int i3, int i4);
+
+void EM_add_data_layer(struct CustomData *data, int type);
+void EM_free_data_layer(struct CustomData *data, int type);
+
+/* ******************* editmesh_mods.c */
+
+extern void EM_init_index_arrays(int forVert, int forEdge, int forFace);
+extern void EM_free_index_arrays(void);
+
+extern struct EditVert *EM_get_vert_for_index(int index);
+extern struct EditEdge *EM_get_edge_for_index(int index);
+extern struct EditFace *EM_get_face_for_index(int index);
+
+extern void EM_select_face_fgon(struct EditFace *efa, int sel);
+
+extern int EM_init_backbuf_border(short xmin, short ymin, short xmax, short ymax);
+extern int EM_mask_init_backbuf_border(short mcords[][2], short tot, short xmin, short ymin, short xmax, short ymax);
+extern int EM_init_backbuf_circle(short xs, short ys, short rads);
+extern int EM_check_backbuf(unsigned int index);
+extern void EM_free_backbuf(void);
+
+extern void EM_selectmode_menu(void);
+
+
+extern void vertexnoise(void);
+extern void vertexsmooth(void);
+extern void righthandfaces(int select);
+extern void mouse_mesh(void);
+
+extern void deselectall_mesh(void);
+extern void selectconnected_mesh_all(void);
+extern void selectconnected_mesh(void);
+extern void selectconnected_delimit_mesh(void);
+extern void selectconnected_delimit_mesh_all(void);
+extern void selectswap_mesh(void);
+
+extern void hide_mesh(int swap);
+extern void reveal_mesh(void);
+
+extern void vertices_to_sphere(void);
+
+ /** Aligns the selected MTFace's of @a me to the @a v3d,
+ * using the given axis (0-2). Can give a user error.
+ */
+extern void faceselect_align_view_to_selected(struct View3D *v3d, struct Mesh *me, int axis);
+ /** Aligns the selected faces or vertices of @a me to the @a v3d,
+ * using the given axis (0-2). Can give a user error.
+ */
+extern void editmesh_align_view_to_selected(struct View3D *v3d, int axis);
+
+ /* Selection */
+extern void select_non_manifold(void);
+extern void select_sharp_edges(void);
+extern void select_linked_flat_faces(void);
+extern void select_faces_by_numverts(int numverts);
+extern void select_more(void);
+extern void select_less(void);
+extern void selectrandom_mesh(void);
+extern void editmesh_select_by_material(int index);
+extern void editmesh_deselect_by_material(int index);
+
+extern void Vertex_Menu(void);
+extern void Edge_Menu(void);
+extern void Face_Menu(void);
+extern void select_mesh_group_menu(void);
+extern void editmesh_mark_seam(int clear);
+extern void loop_multiselect(int looptype);
+
+
+/* ******************* editmesh_loop.c */
+
+#define KNIFE_PROMPT 0
+#define KNIFE_EXACT 1
+#define KNIFE_MIDPOINT 2
+#define KNIFE_MULTICUT 3
+
+extern void CutEdgeloop(int numcuts);
+extern void KnifeSubdivide(char mode);
+extern void LoopMenu(void);
+
+#define LOOP_SELECT 1
+#define LOOP_CUT 2
+
+extern short sharesFace(struct EditEdge* e1, struct EditEdge* e2);
+
+/* ******************* editmesh_tools.c */
+
+#define SUBDIV_SELECT_ORIG 0
+#define SUBDIV_SELECT_INNER 1
+#define SUBDIV_SELECT_INNER_SEL 2
+#define SUBDIV_SELECT_LOOPCUT 3
+
+extern void convert_to_triface(int direction);
+extern int removedoublesflag(short flag, short automerge, float limit);
+extern void xsortvert_flag(int flag);
+extern void hashvert_flag(int flag);
+
+extern void esubdivideflag(int flag, float rad, int beauty, int numcuts, int selecttype);
+
+extern void extrude_mesh(void);
+extern void split_mesh(void);
+extern void extrude_repeat_mesh(int steps, float offs);
+extern void spin_mesh(int steps,float degr,float *dvec, int mode);
+extern void screw_mesh(int steps,int turns);
+extern void delete_mesh(void);
+extern void beauty_fill(void);
+extern void join_triangles(void);
+extern void edge_flip(void);
+extern void fill_mesh(void);
+extern void bevel_menu();
+void mesh_set_face_flags(short mode);
+extern void mesh_set_smooth_faces(short event);
+extern void mesh_rotate_uvs(void);
+extern void mesh_mirror_uvs(void);
+extern void mesh_rotate_colors(void);
+extern void mesh_mirror_colors(void);
+void mesh_copy_menu(void);
+void edge_rotate_selected(int dir);
+int EdgeSlide(short immediate, float imperc);
+int EdgeLoopDelete(void);
+void mesh_rip(void);
+
+struct EditVert *editedge_getOtherVert(struct EditEdge *eed, struct EditVert *ev);
+struct EditVert *editedge_getSharedVert(struct EditEdge *eed, struct EditEdge *eed2);
+int editedge_containsVert(struct EditEdge *eed, struct EditVert *eve);
+int editface_containsVert(struct EditFace *efa, struct EditVert *eve);
+int editface_containsEdge(struct EditFace *efa, struct EditEdge *eed);
+
+void shape_copy_select_from(void);
+void shape_propagate(void);
+
+int collapseEdges(void);
+int merge_firstlast(int first, int uvmerge);
+int merge_target( int target, int uvmerge);
+
+void pathselect(void);
+void loop_to_region(void);
+void region_to_loop(void);
+
+UvVertMap *make_uv_vert_map_EM(int selected, int do_face_idx_array, float *limit);
+UvMapVert *get_uv_map_vert_EM(UvVertMap *vmap, unsigned int v);
+void free_uv_vert_map_EM(UvVertMap *vmap);
+
+int EM_texFaceCheck(void); /* can we edit UV's for this mesh?*/
+int EM_vertColorCheck(void); /* can we edit colors for this mesh?*/
+
+void EM_set_actFace(struct EditFace *efa);
+struct EditFace * EM_get_actFace(void);
+
+#endif
diff --git a/source/blender/include/BIF_editmode_undo.h b/source/blender/include/BIF_editmode_undo.h
new file mode 100644
index 00000000000..b03b4160166
--- /dev/null
+++ b/source/blender/include/BIF_editmode_undo.h
@@ -0,0 +1,59 @@
+/**
+ * $Id:
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+
+#ifndef BIF_EDITMODE_UNDO_H
+#define BIF_EDITMODE_UNDO_H
+
+// Add this in your local code:
+
+extern void undo_editmode_push(char *name,
+ void (*freedata)(void *), // pointer to function freeing data
+ void (*to_editmode)(void *), // data to editmode conversion
+ void *(*from_editmode)(void)); // editmode to data conversion
+
+
+// Further exported for UI is:
+
+struct uiBlock;
+
+extern void undo_editmode_step(int step); // undo and redo
+extern void undo_editmode_clear(void); // free & clear all data
+extern void undo_editmode_menu(void); // history menu
+extern struct uiBlock *editmode_undohistorymenu(void *arg_unused);
+
+/* Hack to avoid multires undo data taking up insane amounts of memory */
+struct Object;
+void *undo_editmode_get_prev(struct Object *ob);
+
+#endif
+
diff --git a/source/blender/include/BIF_editnla.h b/source/blender/include/BIF_editnla.h
new file mode 100644
index 00000000000..f12a313b903
--- /dev/null
+++ b/source/blender/include/BIF_editnla.h
@@ -0,0 +1,65 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_EDITNLA_H
+#define BIF_EDITNLA_H
+
+struct BWinEvent;
+
+extern void winqreadnlaspace(struct ScrArea *sa, void *spacedata, struct BWinEvent *evt);
+
+/* NLA channel operations */
+void delete_nlachannel_keys(void);
+void duplicate_nlachannel_keys(void);
+void transform_nlachannel_keys(int mode, int dummy);
+
+/* Select */
+void borderselect_nla(void);
+void deselect_nlachannel_keys (int test);
+void deselect_nlachannels(int test);
+
+/* NLA Strip operations */
+void shift_nlastrips_up(void);
+void shift_nlastrips_down(void);
+void reset_action_strips(int val);
+void synchronize_action_strips(void);
+void snap_action_strips(int snap_mode);
+void add_nlablock(void);
+void add_empty_nlablock(void);
+void convert_nla(void);
+void copy_action_modifiers(void);
+
+/* Baking */
+void bake_all_to_action(void);
+
+#endif
+
diff --git a/source/blender/include/BIF_editoops.h b/source/blender/include/BIF_editoops.h
new file mode 100644
index 00000000000..ac1badfd7bd
--- /dev/null
+++ b/source/blender/include/BIF_editoops.h
@@ -0,0 +1,47 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_EDITOOPS_H
+#define BIF_EDITOOPS_H
+
+void borderselect_oops(void);
+void deselect_all_area_oops(void);
+void mouse_select_oops(void);
+void select_backlinked_oops(void);
+void select_linked_oops(void);
+void set_select_flag_oops(void);
+void swap_select_all_oops(void);
+void transform_oops(int mode, int context);
+
+void clever_numbuts_oops(void);
+#endif
+
diff --git a/source/blender/include/BIF_editsca.h b/source/blender/include/BIF_editsca.h
new file mode 100644
index 00000000000..c8e8a33d475
--- /dev/null
+++ b/source/blender/include/BIF_editsca.h
@@ -0,0 +1,41 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_EDITSCA_H
+#define BIF_EDITSCA_H
+
+void make_unique_prop_names(char *str);
+void do_gamebuts(unsigned short event);
+void gamebuts(void);
+
+#endif
+
diff --git a/source/blender/include/BIF_editseq.h b/source/blender/include/BIF_editseq.h
new file mode 100644
index 00000000000..74baf12c11a
--- /dev/null
+++ b/source/blender/include/BIF_editseq.h
@@ -0,0 +1,134 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_EDITSEQ_H
+#define BIF_EDITSEQ_H
+
+struct Sequence;
+
+void add_duplicate_seq(void);
+void add_sequence(int type);
+void borderselect_seq(void);
+void boundbox_seq(void);
+void change_sequence(void);
+void reload_sequence(void);
+void update_seq_ipo_rect(struct Sequence * seq);
+void update_seq_icu_rects(struct Sequence * seq);
+struct Sequence* get_last_seq();
+void set_last_seq(struct Sequence * seq);
+void clear_last_seq();
+void del_seq(void);
+void enter_meta(void);
+void exit_meta(void);
+struct Sequence* find_neighboring_sequence(struct Sequence *test, int lr, int sel);
+struct Sequence* find_next_prev_sequence(struct Sequence *test, int lr, int sel);
+struct Sequence* find_nearest_seq(int *hand);
+int insert_gap(int gap, int cfra);
+void make_meta(void);
+void select_channel_direction(struct Sequence *test,int lr);
+void select_more_seq(void);
+void select_less_seq(void);
+void mouse_select_seq(void);
+void no_gaps(void);
+void seq_snap(short event);
+void seq_snap_menu(void);
+void set_filter_seq(void);
+void swap_select_seq(void);
+void touch_seq_files(void);
+void seq_remap_paths(void);
+void transform_seq(int mode, int context);
+void transform_seq_nomarker(int mode, int context);
+void un_meta(void);
+void seq_cut(int cutframe);
+void seq_separate_images(void);
+void reassign_inputs_seq_effect(void);
+void select_surrounding_handles(struct Sequence *test);
+void select_surround_from_last();
+void select_dir_from_last(int lr);
+void select_neighbor_from_last(int lr);
+void select_linked_seq(int mode);
+struct Sequence* alloc_sequence(ListBase *lb, int cfra, int machine); /*used from python*/
+int check_single_seq(struct Sequence *seq);
+
+/* sequence transform functions, for internal used */
+int seq_tx_get_start(struct Sequence *seq);
+int seq_tx_get_end(struct Sequence *seq);
+
+int seq_tx_get_final_left(struct Sequence *seq);
+int seq_tx_get_final_right(struct Sequence *seq);
+
+void seq_tx_set_final_left(struct Sequence *seq, int i);
+void seq_tx_set_final_right(struct Sequence *seq, int i);
+
+/* check if one side can be transformed */
+int seq_tx_check_left(struct Sequence *seq);
+int seq_tx_check_right(struct Sequence *seq);
+
+#define SEQ_DEBUG_INFO(seq) printf("seq into '%s' -- len:%i start:%i startstill:%i endstill:%i startofs:%i endofs:%i\n",\
+ seq->name, seq->len, seq->start, seq->startstill, seq->endstill, seq->startofs, seq->endofs)
+
+/* seq macro's for transform
+ notice the difference between start/end and left/right.
+
+ left and right are the bounds at which the setuence is rendered,
+start and end are from the start and fixed length of the sequence.
+*/
+/*
+#define SEQ_GET_START(seq) (seq->start)
+#define SEQ_GET_END(seq) (seq->start+seq->len)
+
+#define SEQ_GET_FINAL_LEFT(seq) ((seq->start - seq->startstill) + seq->startofs)
+#define SEQ_GET_FINAL_RIGHT(seq) (((seq->start+seq->len) + seq->endstill) - seq->endofs)
+
+#define SEQ_SET_FINAL_LEFT(seq, val) \
+ if (val < (seq)->start) { \
+ (seq)->startstill = abs(val - (seq)->start); \
+ (seq)->startofs = 0; \
+} else { \
+ (seq)->startofs = abs(val - (seq)->start); \
+ (seq)->startstill = 0; \
+}
+
+#define SEQ_SET_FINAL_RIGHT(seq, val) \
+ if (val > (seq)->start + (seq)->len) { \
+ (seq)->endstill = abs(val - ((seq)->start + (seq)->len)); \
+ (seq)->endofs = 0; \
+} else { \
+ (seq)->endofs = abs(val - ((seq)->start + (seq)->len)); \
+ (seq)->endstill = 0; \
+}
+*/
+/* drawseq.c */
+void do_seqbuttons(short);
+
+#endif
+
diff --git a/source/blender/include/BIF_editsima.h b/source/blender/include/BIF_editsima.h
new file mode 100644
index 00000000000..a8a5c16df1a
--- /dev/null
+++ b/source/blender/include/BIF_editsima.h
@@ -0,0 +1,124 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+struct Mesh;
+struct EditMesh;
+struct SpaceImage;
+struct EditFace;
+struct MTFace;
+
+/* id can be from 0 to 3 */
+#define TF_PIN_MASK(id) (TF_PIN1 << id)
+#define TF_SEL_MASK(id) (TF_SEL1 << id)
+
+
+/* this checks weather a face is drarn without the local image check
+ * - warning - no check for G.sima->flag, use SIMA_FACEDRAW_CHECK
+ */
+#define SIMA_FACEDRAW_CHECK_NOLOCAL(efa) \
+ ((G.sima->flag & SI_SYNC_UVSEL) ? (efa->h==0) : (efa->h==0 && efa->f & SELECT))
+
+/* this check includes the local image check - (does the faces image match the space image?) */
+#define SIMA_FACEDRAW_CHECK(efa, tf) \
+ ((G.sima && G.sima->flag & SI_LOCAL_UV) ? ((tf->tpage==G.sima->image) ? SIMA_FACEDRAW_CHECK_NOLOCAL(efa):0) : (SIMA_FACEDRAW_CHECK_NOLOCAL(efa)))
+
+#define SIMA_FACESEL_CHECK(efa, tf) \
+ ((G.sima && G.sima->flag & SI_SYNC_UVSEL) ? (efa->f & SELECT) : (!(~tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3)) &&(!efa->v4 || tf->flag & TF_SEL4)))
+#define SIMA_FACESEL_SET(efa, tf) \
+ ((G.sima && G.sima->flag & SI_SYNC_UVSEL) ? (EM_select_face(efa, 1)) : (tf->flag |= (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)))
+#define SIMA_FACESEL_UNSET(efa, tf) \
+ ((G.sima && G.sima->flag & SI_SYNC_UVSEL) ? (EM_select_face(efa, 0)) : (tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)))
+
+#define SIMA_UVSEL_CHECK(efa, tf, i) ((G.sima && G.sima->flag & SI_SYNC_UVSEL) ? \
+ (G.scene->selectmode == SCE_SELECT_FACE ? efa->f & SELECT : ((*(&efa->v1 + i))->f & SELECT) ) : (tf->flag & TF_SEL_MASK(i) ))
+#define SIMA_UVSEL_SET(efa, tf, i) ((G.sima && G.sima->flag & SI_SYNC_UVSEL) ? \
+ (G.scene->selectmode == SCE_SELECT_FACE ? EM_select_face(efa, 1) : ((*(&efa->v1 + i))->f |= SELECT) ) : (tf->flag |= TF_SEL_MASK(i) ))
+#define SIMA_UVSEL_UNSET(efa, tf, i) ((G.sima && G.sima->flag & SI_SYNC_UVSEL) ? \
+ (G.scene->selectmode == SCE_SELECT_FACE ? EM_select_face(efa, 0) : ((*(&efa->v1 + i))->f &= ~SELECT) ) : (tf->flag &= ~TF_SEL_MASK(i) ))
+
+struct Object;
+
+void object_uvs_changed(struct Object *ob);
+void object_tface_flags_changed(struct Object *ob, int updateButtons);
+
+int is_uv_tface_editing_allowed(void);
+int is_uv_tface_editing_allowed_silent(void);
+
+void get_connected_limit_tface_uv(float *limit);
+int minmax_tface_uv(float *min, float *max);
+int cent_tface_uv(float *cent, int mode);
+
+void transform_width_height_tface_uv(int *width, int *height);
+void transform_aspect_ratio_tface_uv(float *aspx, float *aspy);
+
+void mouseco_to_cursor_sima(void);
+void borderselect_sima(short whichuvs);
+void mouseco_to_curtile(void);
+void mouse_select_sima(void);
+void snap_menu_sima(void);
+void aspect_sima(struct SpaceImage *sima, float *x, float *y);
+
+void select_invert_tface_uv(void);
+void select_swap_tface_uv(void);
+void mirrormenu_tface_uv(void);
+void mirror_tface_uv(char mirroraxis);
+void hide_tface_uv(int swap);
+void reveal_tface_uv(void);
+void stitch_limit_uv_tface(void);
+void stitch_vert_uv_tface(void);
+void unlink_selection(void);
+void uvface_setsel__internal(short select);
+void select_linked_tface_uv(int mode);
+void pin_tface_uv(int mode);
+void weld_align_menu_tface_uv(void);
+void weld_align_tface_uv(char tool);
+void be_square_tface_uv(struct EditMesh *em);
+void select_pinned_tface_uv(void);
+
+void sima_sample_color(void);
+
+#define UV_SELECT_ALL 1
+#define UV_SELECT_PINNED 2
+
+void new_image_sima(void);
+void reload_image_sima(void);
+void save_image_sima(void);
+void save_as_image_sima(void);
+void save_image_sequence_sima(void);
+void replace_image_sima(short imageselect);
+void open_image_sima(short imageselect);
+void pack_image_sima(void);
+
+/* checks images for forced updates on frame change */
+void BIF_image_update_frame(void);
+
+void find_nearest_uv(struct MTFace **nearesttf, struct EditFace **nearestefa, unsigned int *nearestv, int *nearestuv);
diff --git a/source/blender/include/BIF_editsound.h b/source/blender/include/BIF_editsound.h
new file mode 100644
index 00000000000..6e341bfb204
--- /dev/null
+++ b/source/blender/include/BIF_editsound.h
@@ -0,0 +1,87 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_EDITSOUND_H
+#define BIF_EDITSOUND_H
+
+struct bSound;
+struct bSample;
+struct ListBase;
+struct PackedFile;
+struct hdaudio;
+
+void sound_init_audio(void);
+void sound_initialize_sounds(void);
+void sound_exit_audio(void);
+int sound_get_mixrate(void);
+
+void* sound_get_audiodevice(void);
+void* sound_get_listener(void);
+
+int sound_set_sample(struct bSound* sound, struct bSample* sample);
+int sound_sample_is_null(struct bSound* sound);
+int sound_load_sample(struct bSound* sound);
+
+struct bSample* sound_find_sample(struct bSound* sound);
+struct bSample* sound_new_sample(struct bSound* sound);
+
+struct bSound* sound_new_sound(char *name);
+struct bSound* sound_make_copy(struct bSound* originalsound);
+void sound_end_all_sounds(void);
+
+void sound_initialize_sample(struct bSound * sound);
+void sound_load_samples(void);
+
+void sound_play_sound(struct bSound *sound);
+void sound_stop_all_sounds(void);
+
+void sound_set_position(void *object,
+ struct bSound *sound,
+ float obmatrix[4][4]);
+
+struct hdaudio * sound_open_hdaudio(char * name);
+struct hdaudio * sound_copy_hdaudio(struct hdaudio * c);
+
+long sound_hdaudio_get_duration(struct hdaudio * hdaudio, double frame_rate);
+void sound_hdaudio_extract(struct hdaudio * hdaudio,
+ short * target_buffer,
+ int sample_position /* units of target_rate */,
+ int target_rate,
+ int target_channels,
+ int nb_samples /* in target */);
+
+void sound_close_hdaudio(struct hdaudio * hdaudio);
+
+
+
+#endif
+
diff --git a/source/blender/include/BIF_editview.h b/source/blender/include/BIF_editview.h
new file mode 100644
index 00000000000..676bc3bd9f0
--- /dev/null
+++ b/source/blender/include/BIF_editview.h
@@ -0,0 +1,60 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_EDITVIEW_H
+#define BIF_EDITVIEW_H
+
+struct Base;
+struct Object;
+struct Camera;
+struct View3D;
+
+void arrows_move_cursor(unsigned short event);
+void borderselect(void);
+void circle_select(void);
+void deselectall(void);
+void selectswap(void);
+void selectall_type(short obtype);
+void selectall_layer(unsigned int layernum);
+void draw_sel_circle(short *mval, short *mvalo, float rad, float rado, int selecting);
+void fly(void);
+int gesture(void);
+void mouse_cursor(void);
+void mouse_select(void);
+void set_active_base(struct Base *base);
+void set_active_object(struct Object *ob);
+void set_render_border(void);
+void view3d_border_zoom(void);
+void view3d_edit_clipping(struct View3D *v3d);
+
+#endif
+
diff --git a/source/blender/include/BIF_filelist.h b/source/blender/include/BIF_filelist.h
new file mode 100644
index 00000000000..b81be38da01
--- /dev/null
+++ b/source/blender/include/BIF_filelist.h
@@ -0,0 +1,87 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2007 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_FILELIST_H
+#define BIF_FILELIST_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct FileList;
+struct direntry;
+struct BlendHandle;
+
+struct FileList * BIF_filelist_new();
+void BIF_filelist_init_icons();
+void BIF_filelist_free_icons();
+struct FileList * BIF_filelist_copy(struct FileList* filelist);
+int BIF_filelist_find(struct FileList* filelist, char *file);
+void BIF_filelist_free(struct FileList* filelist);
+void BIF_filelist_freelib(struct FileList* filelist);
+void BIF_filelist_sort(struct FileList* filelist, short sort);
+int BIF_filelist_numfiles(struct FileList* filelist);
+const char * BIF_filelist_dir(struct FileList* filelist);
+void BIF_filelist_setdir(struct FileList* filelist, const char *dir);
+void BIF_filelist_appenddir(struct FileList* filelist, const char *relname);
+struct direntry * BIF_filelist_file(struct FileList* filelist, int index);
+void BIF_filelist_hidedot(struct FileList* filelist, short hide);
+void BIF_filelist_setfilter(struct FileList* filelist, unsigned int filter);
+void BIF_filelist_filter(struct FileList* filelist);
+void BIF_filelist_swapselect(struct FileList* filelist);
+void BIF_filelist_imgsize(struct FileList* filelist, short w, short h);
+void BIF_filelist_loadimage(struct FileList* filelist, int index);
+struct ImBuf * BIF_filelist_getimage(struct FileList* filelist, int index);
+
+void BIF_filelist_readdir(struct FileList* filelist);
+
+int BIF_filelist_empty(struct FileList* filelist);
+void BIF_filelist_parent(struct FileList* filelist);
+void BIF_filelist_setfiletypes(struct FileList* filelist, short has_quicktime);
+int BIF_filelist_islibrary (struct FileList* filelist, char* dir, char* group);
+void BIF_filelist_from_main(struct FileList* filelist);
+void BIF_filelist_from_library(struct FileList* filelist);
+void BIF_filelist_append_library(struct FileList* filelist, char *dir, char* file, short flag, int idcode);
+void BIF_filelist_settype(struct FileList* filelist, int type);
+short BIF_filelist_gettype(struct FileList* filelist);
+void BIF_filelist_setipotype(struct FileList* filelist, short ipotype);
+void BIF_filelist_hasfunc(struct FileList* filelist, int has_func);
+
+struct BlendHandle *BIF_filelist_lib(struct FileList* filelist);
+int BIF_groupname_to_code(char *group); /* TODO: where should this go */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/source/blender/include/BIF_fsmenu.h b/source/blender/include/BIF_fsmenu.h
new file mode 100644
index 00000000000..1c5280c14f8
--- /dev/null
+++ b/source/blender/include/BIF_fsmenu.h
@@ -0,0 +1,76 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ *
+ */
+
+#ifndef BSE_FSMENU_H
+#define BSE_FSMENU_H
+
+ /** Returns the number of entries in the Fileselect Menu */
+int fsmenu_get_nentries (void);
+
+ /** Returns true if the fsmenu entry at @a index exists and
+ * is a seperator.
+ */
+int fsmenu_is_entry_a_seperator (int index);
+
+ /** Returns the fsmenu entry at @a index (or NULL if a bad index)
+ * or a seperator.
+ */
+char* fsmenu_get_entry (int index);
+
+ /** Returns a new menu description string representing the
+ * fileselect menu. Should be free'd with MEM_freeN.
+ */
+char* fsmenu_build_menu (void);
+
+ /** Append a seperator to the FSMenu, inserts always follow the
+ * last seperator.
+ */
+void fsmenu_append_separator (void);
+
+ /** Inserts a new fsmenu entry with the given @a path.
+ * Duplicate entries are not added.
+ * @param sorted Should entry be inserted in sorted order?
+ */
+void fsmenu_insert_entry (char *path, int sorted, short save);
+
+ /** Removes the fsmenu entry at the given @a index. */
+void fsmenu_remove_entry (int index);
+
+ /** saves the 'favourites' to the specified file */
+void fsmenu_write_file(const char *filename);
+
+ /** Free's all the memory associated with the fsmenu */
+void fsmenu_free (void);
+
+#endif
+
diff --git a/source/blender/include/BIF_gl.h b/source/blender/include/BIF_gl.h
new file mode 100644
index 00000000000..215e88dc002
--- /dev/null
+++ b/source/blender/include/BIF_gl.h
@@ -0,0 +1,82 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * os dependent include locations of gl.h
+ */
+
+#ifndef BIF_GL_H
+#define BIF_GL_H
+
+ /* Although not really a great idea to copy these defines
+ * from Windows' winnt.h, this lets us use GL without including
+ * windows.h everywhere (or BLI_winstuff.h) which is a good thing.
+ */
+#ifdef WIN32
+#ifndef APIENTRY
+#define APIENTRY __stdcall
+#endif
+
+#ifndef CALLBACK
+#define CALLBACK __stdcall
+#endif
+
+#ifndef WINGDIAPI
+#define WINGDIAPI __declspec(dllimport)
+#endif
+#endif
+
+#ifdef __APPLE__
+#include <OpenGL/gl.h>
+#include <OpenGL/glu.h>
+#else
+#include <GL/gl.h>
+#include <GL/glu.h>
+#endif
+ /*
+ * these should be phased out. cpack should be replaced in
+ * code with calls to glColor3ub, lrectwrite probably should
+ * change to a function. - zr
+ */
+
+/*
+ *
+ * This define converts a numerical value to the equivalent 24-bit
+ * color, while not being endian-sensitive. On little-endians, this
+ * is the same as doing a 'naive'indexing, on big-endian, it is not!
+ * */
+#define cpack(x) glColor3ub( ((x)&0xFF), (((x)>>8)&0xFF), (((x)>>16)&0xFF) )
+
+#define glMultMatrixf(x) glMultMatrixf( (float *)(x))
+#define glLoadMatrixf(x) glLoadMatrixf( (float *)(x))
+
+#define lrectwrite(a, b, c, d, rect) {glRasterPos2i(a, b);glDrawPixels((c)-(a)+1, (d)-(b)+1, GL_RGBA, GL_UNSIGNED_BYTE, rect);}
+
+#endif /* #ifdef BIF_GL_H */
+
diff --git a/source/blender/include/BIF_glutil.h b/source/blender/include/BIF_glutil.h
new file mode 100644
index 00000000000..237f7a85002
--- /dev/null
+++ b/source/blender/include/BIF_glutil.h
@@ -0,0 +1,225 @@
+/**
+ * @file BIF_glutil.h
+ *
+ * OpenGL drawing utility functions.
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_GLUTIL_H
+#define BIF_GLUTIL_H
+
+struct rcti;
+struct rctf;
+
+void sdrawXORline(int x0, int y0, int x1, int y1);
+void sdrawXORline4(int nr, int x0, int y0, int x1, int y1);
+
+void fdrawXORellipse(float xofs, float yofs, float hw, float hh);
+void fdrawXORcirc(float xofs, float yofs, float rad);
+
+ /**
+ * Draw an XOR'd line in the front buffer between
+ * the given points.
+ *
+ * @attention This function also handles flushing the GL
+ * pipeline, which means it is inappropriate for drawing
+ * a large number of lines at once.
+ */
+void glutil_draw_front_xor_line(int x0, int y0, int x1, int y1);
+
+ /**
+ * Draw a lined (non-looping) arc with the given
+ * @a radius, starting at angle @a start and arcing
+ * through @a angle. The arc is centered at the origin
+ * and drawn in the XY plane.
+ *
+ * @param start The initial angle (in radians).
+ * @param angle The length of the arc (in radians).
+ * @param radius The arc radius.
+ * @param nsegments The number of segments to use in drawing the arc.
+ */
+void glutil_draw_lined_arc (float start, float angle, float radius, int nsegments);
+
+ /**
+ * Draw a filled arc with the given @a radius,
+ * starting at angle @a start and arcing through
+ * @a angle. The arc is centered at the origin
+ * and drawn in the XY plane.
+ *
+ * @param start The initial angle (in radians).
+ * @param angle The length of the arc (in radians).
+ * @param radius The arc radius.
+ * @param nsegments The number of segments to use in drawing the arc.
+ */
+void glutil_draw_filled_arc (float start, float angle, float radius, int nsegments);
+
+ /**
+ * Routines an integer value as obtained by glGetIntegerv.
+ * The param must cause only one value to be gotten from GL.
+ */
+int glaGetOneInteger (int param);
+
+ /**
+ * Routines a float value as obtained by glGetIntegerv.
+ * The param must cause only one value to be gotten from GL.
+ */
+float glaGetOneFloat (int param);
+
+ /**
+ * Functions like glRasterPos2i, except ensures that the resulting
+ * raster position is valid. @a known_good_x and @a known_good_y
+ * should be coordinates of a point known to be within the current
+ * view frustum.
+ * @attention This routine should be used when the distance of @a x
+ * and @y away from the known good point is small (ie. for small icons
+ * and for bitmap characters), when drawing large+zoomed images it is
+ * possible for overflow to occur, the glaDrawPixelsSafe routine should
+ * be used instead.
+ */
+void glaRasterPosSafe2f (float x, float y, float known_good_x, float known_good_y);
+
+ /**
+ * Functions like a limited glDrawPixels, except ensures that
+ * the image is displayed onscreen even if the @a x and @a y
+ * coordinates for would be clipped. The routine respects the
+ * glPixelZoom values, pixel unpacking parameters are _not_
+ * respected.
+
+ * @attention This routine makes many assumptions: the rect data
+ * is expected to be in RGBA unsigned byte format, the coordinate
+ * (0.375, 0.375) is assumed to be within the view frustum, and the
+ * modelview and projection matrices are assumed to define a
+ * 1-to-1 mapping to screen space.
+ * @attention Furthmore, in the case of zoomed or unpixel aligned
+ * images extending outside the view frustum, but still within the
+ * window, some portion of the image may be visible left and/or
+ * below of the given @a x and @a y coordinates. It is recommended
+ * to use the glScissor functionality if images are to be drawn
+ * with an inset view matrix.
+ */
+void glaDrawPixelsSafe (float x, float y, int img_w, int img_h, int row_w, int format, int type, void *rect);
+
+ /**
+ * Functions like a limited glDrawPixels, but actually draws the
+ * image using textures, which can be tremendously faster on low-end
+ * cards, and also avoids problems with the raster position being
+ * clipped when offscreen. The routine respects the glPixelZoom values,
+ * pixel unpacking parameters are _not_ respected.
+
+ * @attention This routine makes many assumptions: the rect data
+ * is expected to be in RGBA byte or float format, and the
+ * modelview and projection matrices are assumed to define a
+ * 1-to-1 mapping to screen space.
+ */
+
+ /* only for float rects, converts to 32 bits and draws */
+void glaDrawPixelsSafe_to32(float fx, float fy, int img_w, int img_h, int row_w, float *rectf);
+
+
+void glaDrawPixelsTex (float x, float y, int img_w, int img_h, int format, void *rect);
+
+ /* 2D Drawing Assistance */
+
+ /** Define a 2D area (viewport, scissor, matrices) for OpenGL rendering.
+ * This routine sets up an OpenGL state appropriate for drawing using
+ * both vertice (glVertex, etc) and raster (glRasterPos, glRect) commands.
+ * All coordinates should be at integer positions. There is little to
+ * no reason to use glVertex2f etc. functions during 2D rendering, and
+ * thus no reason to +-0.5 the coordinates or perform other silly
+ * tricks.
+ *
+ * @param screen_rect The screen rectangle to be defined for 2D drawing.
+ */
+void glaDefine2DArea (struct rcti *screen_rect);
+
+typedef struct gla2DDrawInfo gla2DDrawInfo;
+
+ /** Save the current OpenGL state and initialize OpenGL for 2D
+ * rendering. glaEnd2DDraw should be called on the returned structure
+ * to free it and to return OpenGL to its previous state. The
+ * scissor rectangle is set to match the viewport.
+ *
+ * This routine sets up an OpenGL state appropriate for drawing using
+ * both vertice (glVertex, etc) and raster (glRasterPos, glRect) commands.
+ * All coordinates should be at integer positions. There is little to
+ * no reason to use glVertex2f etc. functions during 2D rendering, and
+ * thus no reason to +-0.5 the coordinates or perform other silly
+ * tricks.
+ *
+ * @param screen_rect The screen rectangle to be used for 2D drawing.
+ * @param world_rect The world rectangle that the 2D area represented
+ * by @a screen_rect is supposed to represent. If NULL it is assumed the
+ * world has a 1 to 1 mapping to the screen.
+ */
+gla2DDrawInfo* glaBegin2DDraw (struct rcti *screen_rect, struct rctf *world_rect);
+
+ /** Translate the (@a wo_x, @a wo_y) point from world coordinates into screen space. */
+void gla2DDrawTranslatePt (gla2DDrawInfo *di, float wo_x, float wo_y, int *sc_x_r, int *sc_y_r);
+
+ /** Translate the @a world point from world coordiantes into screen space. */
+void gla2DDrawTranslatePtv (gla2DDrawInfo *di, float world[2], int screen_r[2]);
+
+ /* Restores the previous OpenGL state and free's the auxilary
+ * gla data.
+ */
+void glaEnd2DDraw (gla2DDrawInfo *di);
+
+ /** Adjust the transformation mapping of a 2d area */
+void gla2DGetMap(gla2DDrawInfo *di, struct rctf *rect);
+void gla2DSetMap(gla2DDrawInfo *di, struct rctf *rect);
+
+
+/* use this for platform hacks. glPointSize is solved here */
+void bglBegin(int mode);
+void bglEnd(void);
+void bglVertex3fv(float *vec);
+void bglVertex3f(float x, float y, float z);
+void bglVertex2fv(float *vec);
+/* intel gfx cards frontbuffer problem */
+void bglFlush(void);
+int is_a_really_crappy_intel_card(void);
+void set_inverted_drawing(int enable);
+
+
+/* own working polygon offset */
+void bglPolygonOffset(float dist);
+
+/* For caching opengl matrices (gluProject/gluUnProject) */
+typedef struct bglMats {
+ double modelview[16];
+ double projection[16];
+ int viewport[4];
+} bglMats;
+void bgl_get_mats(bglMats *mats);
+
+#endif /* BIF_GLUTIL_H */
+
diff --git a/source/blender/include/BIF_graphics.h b/source/blender/include/BIF_graphics.h
new file mode 100644
index 00000000000..51aa2ceeb01
--- /dev/null
+++ b/source/blender/include/BIF_graphics.h
@@ -0,0 +1,59 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_GRAPHICS_H
+#define BIF_GRAPHICS_H
+
+ /* XXX, should move somewhere else, with collected windowing
+ * stuff, to be done once the proper windowing stuff has
+ * been formed.
+ */
+
+enum {
+ CURSOR_VPAINT,
+ CURSOR_FACESEL,
+ CURSOR_WAIT,
+ CURSOR_EDIT,
+ CURSOR_X_MOVE,
+ CURSOR_Y_MOVE,
+ CURSOR_HELP,
+ CURSOR_STD,
+ CURSOR_NONE,
+ CURSOR_PENCIL,
+ CURSOR_TEXTEDIT
+};
+
+void set_cursor(int curs);
+int get_cursor(void);
+
+#endif /* BIF_GRAPHICS_H */
+
diff --git a/source/blender/include/BIF_imasel.h b/source/blender/include/BIF_imasel.h
new file mode 100644
index 00000000000..0e92abe14e4
--- /dev/null
+++ b/source/blender/include/BIF_imasel.h
@@ -0,0 +1,51 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BIF_IMASEL_H
+#define BIF_IMASEL_H
+
+struct SpaceImaSel;
+struct ScrArea;
+
+void free_imasel(struct SpaceImaSel *simasel);
+
+void clever_numbuts_imasel(void);
+
+void activate_imageselect(int type, char *title, char *file, void (*func)(char *));
+void activate_imageselect_menu(int type, char *title, char *file, char *pupmenu, short *menup, void (*func)(char *));
+void activate_imageselect_args(int type, char *title, char *file, void (*func)(char *, void *, void *), void *arg1, void *arg2);
+
+void activate_databrowse_imasel(struct ID *id, int idcode, int fromcode, int retval, short *menup, void (*func)(unsigned short));
+/*
+void activate_databrowse_imasel_args(struct ID *id, int idcode, int fromcode, short *menup, void (*func)(char *, void *, void *), void *arg1, void *arg2);
+*/
+#endif
+
diff --git a/source/blender/include/BIF_interface.h b/source/blender/include/BIF_interface.h
new file mode 100644
index 00000000000..453e4e628fe
--- /dev/null
+++ b/source/blender/include/BIF_interface.h
@@ -0,0 +1,331 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_INTERFACE_H
+#define BIF_INTERFACE_H
+
+struct ID;
+struct ListBase;
+struct ScrArea;
+struct AutoComplete;
+
+/* uiBlock->dt */
+#define UI_EMBOSS 0 /* use one of the themes for drawing */
+#define UI_EMBOSSN 1 /* Nothing */
+#define UI_EMBOSSM 2 /* Minimal builtin emboss, also for logic buttons */
+#define UI_EMBOSSP 3 /* Pulldown */
+#define UI_EMBOSSR 4 /* Rounded */
+
+#define UI_EMBOSSX 0 /* for a python file, which i can't change.... duh! */
+
+/* uiBlock->direction */
+#define UI_TOP 1
+#define UI_DOWN 2
+#define UI_LEFT 4
+#define UI_RIGHT 8
+#define UI_DIRECTION 15
+#define UI_CENTER 16
+#define UI_SHIFT_FLIPPED 32
+
+/* uiBlock->autofill */
+#define UI_BLOCK_COLLUMNS 1
+#define UI_BLOCK_ROWS 2
+
+/* return from uiDoBlock */
+#define UI_CONT 0
+#define UI_NOTHING 1
+#define UI_RETURN_CANCEL 2
+#define UI_RETURN_OK 4
+#define UI_RETURN_OUT 8
+#define UI_RETURN 14
+#define UI_EXIT_LOOP 16
+
+/* uiBlock->flag (controls) */
+#define UI_BLOCK_LOOP 1
+#define UI_BLOCK_REDRAW 2
+#define UI_BLOCK_RET_1 4
+#define UI_BLOCK_BUSY 8
+#define UI_BLOCK_NUMSELECT 16
+#define UI_BLOCK_ENTER_OK 32
+#define UI_BLOCK_NOSHADOW 64
+#define UI_BLOCK_FRONTBUFFER 128
+#define UI_BLOCK_NO_HILITE 256
+
+ /* block->flag bits 12-15 are identical to but->flag bits */
+
+/* block->font, for now: bold = medium+1 */
+#define UI_HELV 0
+#define UI_HELVB 1
+
+/* panel controls */
+#define UI_PNL_TRANSP 1
+#define UI_PNL_SOLID 2
+
+#define UI_PNL_CLOSE 32
+#define UI_PNL_STOW 64
+#define UI_PNL_TO_MOUSE 128
+#define UI_PNL_UNSTOW 256
+#define UI_PNL_SCALE 512
+
+/* warning the first 4 flags are internal */
+/* but->flag */
+#define UI_TEXT_LEFT 16
+#define UI_ICON_LEFT 32
+#define UI_ICON_RIGHT 64
+ /* control for button type block */
+#define UI_MAKE_TOP 128
+#define UI_MAKE_DOWN 256
+#define UI_MAKE_LEFT 512
+#define UI_MAKE_RIGHT 1024
+ /* dont draw hilite on mouse over */
+#define UI_NO_HILITE 2048
+ /* button align flag, for drawing groups together */
+#define UI_BUT_ALIGN (15<<12)
+#define UI_BUT_ALIGN_TOP (1<<12)
+#define UI_BUT_ALIGN_LEFT (1<<13)
+#define UI_BUT_ALIGN_RIGHT (1<<14)
+#define UI_BUT_ALIGN_DOWN (1<<15)
+
+
+/* Button types, bits stored in 1 value... and a short even!
+- bits 0-4: bitnr (0-31)
+- bits 5-7: pointer type
+- bit 8: for 'bit'
+- bit 9-15: button type (now 6 bits, 64 types)
+*/
+
+#define CHA 32
+#define SHO 64
+#define INT 96
+#define FLO 128
+#define FUN 192
+#define BIT 256
+
+#define BUTPOIN (128+64+32)
+
+#define BUT (1<<9)
+#define ROW (2<<9)
+#define TOG (3<<9)
+#define SLI (4<<9)
+#define NUM (5<<9)
+#define TEX (6<<9)
+#define TOG3 (7<<9)
+#define TOGR (8<<9)
+#define TOGN (9<<9)
+#define LABEL (10<<9)
+#define MENU (11<<9)
+#define ICONROW (12<<9)
+#define ICONTOG (13<<9)
+#define NUMSLI (14<<9)
+#define COL (15<<9)
+#define IDPOIN (16<<9)
+#define HSVSLI (17<<9)
+#define SCROLL (18<<9)
+#define BLOCK (19<<9)
+#define BUTM (20<<9)
+#define SEPR (21<<9)
+#define LINK (22<<9)
+#define INLINK (23<<9)
+#define KEYEVT (24<<9)
+#define ICONTEXTROW (25<<9)
+#define HSVCUBE (26<<9)
+#define PULLDOWN (27<<9)
+#define ROUNDBOX (28<<9)
+#define CHARTAB (29<<9)
+#define BUT_COLORBAND (30<<9)
+#define BUT_NORMAL (31<<9)
+#define BUT_CURVE (32<<9)
+#define BUT_TOGDUAL (33<<9)
+#define ICONTOGN (34<<9)
+#define FTPREVIEW (35<<9)
+#define BUTTYPE (63<<9)
+
+
+
+typedef struct uiBut uiBut;
+typedef struct uiBlock uiBlock;
+
+void uiEmboss(float x1, float y1, float x2, float y2, int sel);
+void uiRoundBoxEmboss(float minx, float miny, float maxx, float maxy, float rad, int active);
+void uiRoundBox(float minx, float miny, float maxx, float maxy, float rad);
+void uiSetRoundBox(int type);
+void uiRoundRect(float minx, float miny, float maxx, float maxy, float rad);
+
+void uiDrawMenuBox(float minx, float miny, float maxx, float maxy, short flag);
+void uiTextBoundsBlock(uiBlock *block, int addval);
+void uiBoundsBlock(struct uiBlock *block, int addval);
+void uiDrawBlock(struct uiBlock *block);
+void uiGetMouse(int win, short *adr);
+void uiComposeLinks(uiBlock *block);
+void uiSetButLock(int val, char *lockstr);
+void uiClearButLock(void);
+int uiDoBlocks(struct ListBase *lb, int event);
+void uiSetCurFont(uiBlock *block, int index);
+void uiDefFont(unsigned int index, void *xl, void *large, void *medium, void *small);
+void uiFreeBlock(uiBlock *block);
+void uiFreeBlocks(struct ListBase *lb);
+void uiFreeBlocksWin(struct ListBase *lb, int win);
+uiBlock *uiNewBlock(struct ListBase *lb, char *name, short dt, short font, short win);
+uiBlock *uiGetBlock(char *name, struct ScrArea *sa);
+
+void uiBlockPickerButtons(struct uiBlock *block, float *col, float *hsv, float *old, char *hexcol, char mode, short retval);
+
+
+/* automatic aligning, horiz or verical */
+void uiBlockBeginAlign(uiBlock *block);
+void uiBlockEndAlign(uiBlock *block);
+
+uiBut *uiDefBut(uiBlock *block,
+ int type, int retval, char *str,
+ short x1, short y1,
+ short x2, short y2,
+ void *poin,
+ float min, float max,
+ float a1, float a2, char *tip);
+uiBut *uiDefButF(uiBlock *block, int type, int retval, char *str, short x1, short y1, short x2, short y2, float *poin, float min, float max, float a1, float a2, char *tip);
+uiBut *uiDefButBitF(uiBlock *block, int type, int bit, int retval, char *str, short x1, short y1, short x2, short y2, float *poin, float min, float max, float a1, float a2, char *tip);
+uiBut *uiDefButI(uiBlock *block, int type, int retval, char *str, short x1, short y1, short x2, short y2, int *poin, float min, float max, float a1, float a2, char *tip);
+uiBut *uiDefButBitI(uiBlock *block, int type, int bit, int retval, char *str, short x1, short y1, short x2, short y2, int *poin, float min, float max, float a1, float a2, char *tip);
+uiBut *uiDefButS(uiBlock *block, int type, int retval, char *str, short x1, short y1, short x2, short y2, short *poin, float min, float max, float a1, float a2, char *tip);
+uiBut *uiDefButBitS(uiBlock *block, int type, int bit, int retval, char *str, short x1, short y1, short x2, short y2, short *poin, float min, float max, float a1, float a2, char *tip);
+uiBut *uiDefButC(uiBlock *block, int type, int retval, char *str, short x1, short y1, short x2, short y2, char *poin, float min, float max, float a1, float a2, char *tip);
+uiBut *uiDefButBitC(uiBlock *block, int type, int bit, int retval, char *str, short x1, short y1, short x2, short y2, char *poin, float min, float max, float a1, float a2, char *tip);
+
+uiBut *uiDefIconBut(uiBlock *block,
+ int type, int retval, int icon,
+ short x1, short y1,
+ short x2, short y2,
+ void *poin,
+ float min, float max,
+ float a1, float a2, char *tip);
+uiBut *uiDefIconButF(uiBlock *block, int type, int retval, int icon, short x1, short y1, short x2, short y2, float *poin, float min, float max, float a1, float a2, char *tip);
+uiBut *uiDefIconButBitF(uiBlock *block, int type, int bit, int retval, int icon, short x1, short y1, short x2, short y2, float *poin, float min, float max, float a1, float a2, char *tip);
+uiBut *uiDefIconButI(uiBlock *block, int type, int retval, int icon, short x1, short y1, short x2, short y2, int *poin, float min, float max, float a1, float a2, char *tip);
+uiBut *uiDefIconButBitI(uiBlock *block, int type, int bit, int retval, int icon, short x1, short y1, short x2, short y2, int *poin, float min, float max, float a1, float a2, char *tip);
+uiBut *uiDefIconButS(uiBlock *block, int type, int retval, int icon, short x1, short y1, short x2, short y2, short *poin, float min, float max, float a1, float a2, char *tip);
+uiBut *uiDefIconButBitS(uiBlock *block, int type, int bit, int retval, int icon, short x1, short y1, short x2, short y2, short *poin, float min, float max, float a1, float a2, char *tip);
+uiBut *uiDefIconButC(uiBlock *block, int type, int retval, int icon, short x1, short y1, short x2, short y2, char *poin, float min, float max, float a1, float a2, char *tip);
+uiBut *uiDefIconButBitC(uiBlock *block, int type, int bit, int retval, int icon, short x1, short y1, short x2, short y2, char *poin, float min, float max, float a1, float a2, char *tip);
+
+uiBut *uiDefIconTextBut(uiBlock *block, int type, int retval, int icon, char *str, short x1, short y1, short x2, short y2, void *poin, float min, float max, float a1, float a2, char *tip);
+
+uiBut *uiDefIconTextButF(uiBlock *block, int type, int retval, int icon, char *str, short x1, short y1, short x2, short y2, float *poin, float min, float max, float a1, float a2, char *tip);
+uiBut *uiDefIconTextButBitF(uiBlock *block, int type, int bit, int retval, int icon, char *str, short x1, short y1, short x2, short y2, float *poin, float min, float max, float a1, float a2, char *tip);
+uiBut *uiDefIconTextButI(uiBlock *block, int type, int retval, int icon, char *str, short x1, short y1, short x2, short y2, int *poin, float min, float max, float a1, float a2, char *tip);
+uiBut *uiDefIconTextButBitI(uiBlock *block, int type, int bit, int retval, int icon, char *str, short x1, short y1, short x2, short y2, int *poin, float min, float max, float a1, float a2, char *tip);
+uiBut *uiDefIconTextButS(uiBlock *block, int type, int retval, int icon, char *str, short x1, short y1, short x2, short y2, short *poin, float min, float max, float a1, float a2, char *tip);
+uiBut *uiDefIconTextButBitS(uiBlock *block, int type, int bit, int retval, int icon, char *str, short x1, short y1, short x2, short y2, short *poin, float min, float max, float a1, float a2, char *tip);
+uiBut *uiDefIconTextButC(uiBlock *block, int type, int retval, int icon, char *str, short x1, short y1, short x2, short y2, char *poin, float min, float max, float a1, float a2, char *tip);
+uiBut *uiDefIconTextButBitC(uiBlock *block, int type, int bit, int retval, int icon, char *str, short x1, short y1, short x2, short y2, char *poin, float min, float max, float a1, float a2, char *tip);
+
+typedef void (*uiIDPoinFuncFP) (char *str, struct ID **idpp);
+uiBut *uiDefIDPoinBut(struct uiBlock *block, uiIDPoinFuncFP func, short blocktype, int retval, char *str,
+ short x1, short y1, short x2, short y2, void *idpp, char *tip);
+
+typedef uiBlock* (*uiBlockFuncFP) (void *arg1);
+uiBut *uiDefBlockBut(uiBlock *block, uiBlockFuncFP func, void *func_arg1, char *str, short x1, short y1, short x2, short y2, char *tip);
+uiBut *uiDefPulldownBut(uiBlock *block, uiBlockFuncFP func, void *func_arg1, char *str, short x1, short y1, short x2, short y2, char *tip);
+
+uiBut *uiDefIconTextBlockBut(uiBlock *block, uiBlockFuncFP func, void *arg, int icon, char *str, short x1, short y1, short x2, short y2, char *tip);
+uiBut *uiDefIconBlockBut(uiBlock *block, uiBlockFuncFP func, void *arg, int retval, int icon, short x1, short y1, short x2, short y2, char *tip);
+
+void uiDefKeyevtButS(uiBlock *block, int retval, char *str, short x1, short y1, short x2, short y2, short *spoin, char *tip);
+
+void uiAutoBlock(struct uiBlock *block,
+ float minx, float miny,
+ float sizex, float sizey, int flag);
+void uiSetButLink(struct uiBut *but,
+ void **poin,
+ void ***ppoin,
+ short *tot,
+ int from, int to);
+
+int uiBlocksGetYMin (ListBase *lb);
+int uiBlockGetCol (uiBlock *block);
+void* uiBlockGetCurFont (uiBlock *block);
+
+void uiBlockSetCol (uiBlock *block, int col);
+void uiBlockSetEmboss (uiBlock *block, int emboss);
+void uiBlockSetDirection (uiBlock *block, int direction);
+void uiBlockFlipOrder (uiBlock *block);
+void uiBlockSetFlag (uiBlock *block, int flag);
+void uiBlockSetXOfs (uiBlock *block, int xofs);
+
+int uiButGetRetVal (uiBut *but);
+
+void uiButSetFlag (uiBut *but, int flag);
+void uiButClearFlag (uiBut *but, int flag);
+
+void uiBlockSetButmFunc (uiBlock *block, void (*butmfunc)(void *arg, int but_a2), void *arg);
+
+void uiBlockSetFunc (uiBlock *block, void (*func)(void *arg1, void *arg2), void *arg1, void *arg2);
+void uiButSetFunc (uiBut *but, void (*func)(void *arg1, void *arg2), void *arg1, void *arg2);
+
+void uiButSetCompleteFunc(uiBut *but, void (*func)(char *str, void *arg), void *arg);
+
+void uiBlockSetDrawExtraFunc(uiBlock *block, void (*func)(struct ScrArea *sa, uiBlock *block));
+
+
+extern void pupmenu_set_active(int val);
+extern short pupmenu(char *instr);
+extern short pupmenu_col(char *instr, int maxrow);
+
+extern void uiFreePanels(struct ListBase *lb);
+extern void uiNewPanelTabbed(char *, char *);
+extern int uiNewPanel(struct ScrArea *sa, struct uiBlock *block, char *panelname, char *tabname, int ofsx, int ofsy, int sizex, int sizey);
+
+extern void uiSetPanel_view2d(struct ScrArea *sa);
+extern void uiMatchPanel_view2d(struct ScrArea *sa);
+
+extern void uiDrawBlocksPanels(struct ScrArea *sa, int re_align);
+extern void uiNewPanelHeight(struct uiBlock *block, int sizey);
+extern void uiNewPanelTitle(struct uiBlock *block, char *str);
+extern void uiPanelPush(struct uiBlock *block);
+extern void uiPanelPop(struct uiBlock *block);
+extern uiBlock *uiFindOpenPanelBlockName(ListBase *lb, char *name);
+extern int uiAlignPanelStep(struct ScrArea *sa, float fac);
+extern void uiPanelControl(int);
+extern void uiSetPanelHandler(int);
+
+extern void uiDrawBoxShadow(unsigned char alpha, float minx, float miny, float maxx, float maxy);
+extern void *uiSetCurFont_ext(float aspect);
+
+void shade_buttons_change_3d(void);
+
+typedef struct AutoComplete AutoComplete;
+
+AutoComplete *autocomplete_begin(char *startname, int maxlen);
+void autocomplete_do_name(AutoComplete *autocpl, const char *name);
+void autocomplete_end(AutoComplete *autocpl, char *autoname);
+
+#endif /* BIF_INTERFACE_H */
+
diff --git a/source/blender/include/BIF_interface_icons.h b/source/blender/include/BIF_interface_icons.h
new file mode 100644
index 00000000000..c628d68e9db
--- /dev/null
+++ b/source/blender/include/BIF_interface_icons.h
@@ -0,0 +1,72 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_PREVIEW_ICONS_H
+#define BIF_PREVIEW_ICONS_H
+
+struct Image;
+struct ImBuf;
+struct World;
+struct Tex;
+struct Lamp;
+struct Material;
+
+typedef struct IconFile {
+ struct IconFile *next, *prev;
+ char filename[80]; // FILE_MAXFILE size
+ int index;
+} IconFile;
+
+
+#define ICON_DEFAULT_HEIGHT 16
+#define PREVIEW_DEFAULT_HEIGHT 96
+
+/*
+ Resizable Icons for Blender
+*/
+void BIF_icons_init(int first_dyn_id);
+int BIF_icon_get_width(int icon_id);
+int BIF_icon_get_height(int icon_id);
+
+void BIF_icon_draw(float x, float y, int icon_id);
+void BIF_icon_draw_preview(float x, float y, int icon_id, int nocreate);
+
+void BIF_icon_draw_aspect(float x, float y, int icon_id, float aspect);
+void BIF_icon_draw_aspect_blended(float x, float y, int icon_id, float aspect, int shade);
+void BIF_icons_free();
+void BIF_icons_free_drawinfo(void *drawinfo);
+
+struct ListBase *BIF_iconfile_list(void);
+int BIF_iconfile_get_index(char *filename);
+
+
+#endif /* BIF_ICONS_H */
diff --git a/source/blender/include/BIF_keyval.h b/source/blender/include/BIF_keyval.h
new file mode 100644
index 00000000000..7134bd2b153
--- /dev/null
+++ b/source/blender/include/BIF_keyval.h
@@ -0,0 +1,39 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_KEYVAL_H
+#define BIF_KEYVAL_H
+
+char *key_event_to_string(unsigned short event);
+
+#endif
+
diff --git a/source/blender/include/BIF_language.h b/source/blender/include/BIF_language.h
new file mode 100644
index 00000000000..6ed8a8d1574
--- /dev/null
+++ b/source/blender/include/BIF_language.h
@@ -0,0 +1,69 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_LANGUAGE_H
+#define BIF_LANGUAGE_H
+
+#include "DNA_vec_types.h"
+
+struct BMF_Font;
+
+int read_languagefile(void); /* usiblender.c */
+void free_languagemenu(void); /* usiblender.c */
+
+void set_interface_font(char *str); /* headerbuttons.c */
+void start_interface_font(void); /* headerbuttons.c */
+void lang_setlanguage(void); /* usiblender.c */
+
+char *language_pup(void);
+char *fontsize_pup(void);
+
+int BIF_DrawString(struct BMF_Font* font, char *str, int translate);
+float BIF_GetStringWidth(struct BMF_Font* font, char *str, int translate);
+void BIF_GetBoundingBox(struct BMF_Font* font, char* str, int translate, rctf* bbox);
+
+void BIF_RasterPos(float x, float y);
+void BIF_SetScale(float aspect);
+void refresh_interface_font(void);
+
+struct LANGMenuEntry {
+ struct LANGMenuEntry *next;
+ char *line;
+ char *language;
+ char *code;
+ int id;
+};
+
+struct LANGMenuEntry *find_language(short langid);
+
+#endif /* BIF_LANGUAGE_H */
+
diff --git a/source/blender/include/BIF_mainqueue.h b/source/blender/include/BIF_mainqueue.h
new file mode 100644
index 00000000000..e2eaeea4dca
--- /dev/null
+++ b/source/blender/include/BIF_mainqueue.h
@@ -0,0 +1,47 @@
+/*
+ * Central queue handling functions.
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_MAINQUEUE_H
+#define BIF_MAINQUEUE_H
+
+#define MAXQUEUE 4096
+
+unsigned short mainqtest (void);
+unsigned short mainqread (short *val, char *ascii);
+void mainqenter (unsigned short event, short val);
+void mainqenter_ext (unsigned short event, short val, char ascii);
+void mainqpushback (unsigned short event, short val, char ascii);
+
+#endif /* BIF_MAINQUEUE_H */
+
diff --git a/source/blender/include/BIF_meshlaplacian.h b/source/blender/include/BIF_meshlaplacian.h
new file mode 100644
index 00000000000..74e4fef0937
--- /dev/null
+++ b/source/blender/include/BIF_meshlaplacian.h
@@ -0,0 +1,87 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * BIF_meshlaplacian.h: Algorithms using the mesh laplacian.
+ */
+
+#ifndef BIF_MESHLAPLACIAN_H
+#define BIF_MESHLAPLACIAN_H
+
+//#define RIGID_DEFORM
+
+struct Object;
+struct Mesh;
+struct bDeformGroup;
+struct MeshDeformModifierData;
+
+#ifdef RIGID_DEFORM
+struct EditMesh;
+#endif
+
+/* Laplacian System */
+
+struct LaplacianSystem;
+typedef struct LaplacianSystem LaplacianSystem;
+
+LaplacianSystem *laplacian_construct_begin(int totvert, int totface);
+
+void laplacian_add_vertex(LaplacianSystem *sys, float *co, int pinned);
+void laplacian_add_triangle(LaplacianSystem *sys, int v1, int v2, int v3);
+
+void laplacian_construct_end(LaplacianSystem *sys);
+void laplacian_delete(LaplacianSystem *sys);
+
+void laplacian_begin_solve(LaplacianSystem *sys, int index);
+void laplacian_add_right_hand_side(LaplacianSystem *sys, int v, float value);
+int laplacian_system_solve(LaplacianSystem *sys);
+float laplacian_system_get_solution(int v);
+
+/* Heat Weighting */
+
+void heat_bone_weighting(struct Object *ob, struct Mesh *me, float (*verts)[3],
+ int numbones, struct bDeformGroup **dgrouplist,
+ struct bDeformGroup **dgroupflip, float (*root)[3], float (*tip)[3],
+ int *selected);
+
+#ifdef RIGID_DEFORM
+/* As-Rigid-As-Possible Deformation */
+
+void rigid_deform_begin(struct EditMesh *em);
+void rigid_deform_iteration(void);
+void rigid_deform_end(int cancel);
+#endif
+
+/* Harmonic Coordinates */
+
+void harmonic_coordinates_bind(struct MeshDeformModifierData *mmd,
+ float (*vertexcos)[3], int totvert, float cagemat[][4]);
+
+#endif
+
diff --git a/source/blender/include/BIF_meshtools.h b/source/blender/include/BIF_meshtools.h
new file mode 100644
index 00000000000..a08f800d7b6
--- /dev/null
+++ b/source/blender/include/BIF_meshtools.h
@@ -0,0 +1,50 @@
+/**
+ * $Id:
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_MESHTOOLS_H
+#define BIF_MESHTOOLS_H
+
+struct Object;
+struct EditVert;
+
+extern int join_mesh(void);
+
+extern void sort_faces(void);
+extern void objects_bake_render_menu(void);
+extern void objects_bake_render(short event);
+
+extern long mesh_octree_table(struct Object *ob, float *co, char mode);
+extern int mesh_get_x_mirror_vert(struct Object *ob, int index);
+extern struct EditVert *editmesh_get_x_mirror_vert(struct Object *ob, float *co);
+
+#endif
+
diff --git a/source/blender/include/BIF_mywindow.h b/source/blender/include/BIF_mywindow.h
new file mode 100644
index 00000000000..28de60d2bc0
--- /dev/null
+++ b/source/blender/include/BIF_mywindow.h
@@ -0,0 +1,145 @@
+
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * These are the protos for mywindow.c -- an emulation of the
+ * (obsolete) IrisGL command set
+ */
+
+#ifndef BIF_MYWINDOW_H
+#define BIF_MYWINDOW_H
+
+struct rcti;
+
+/*---*/
+
+typedef struct BWinEvent {
+ unsigned short event;
+ short val;
+ char ascii;
+} BWinEvent;
+
+/*---*/
+
+int mywinget(void);
+void mywinclose(int winid);
+void mywinposition(int winid,
+ int xmin, int xmax,
+ int ymin, int ymax);
+/*---*/
+
+ /** Test if there are events available on a BWin queue.
+ *
+ * @param winid The ID of the window to query.
+ * @return True if there is an event available for _qread'ing.
+ */
+int bwin_qtest(int winid);
+
+ /** Read an event off of the BWin queue (if available).
+ *
+ * @param winid The ID of the window to read from.
+ * @param event_r A pointer to return the event in.
+ * @return True if an event was read and @a event_r filled.
+ */
+int bwin_qread(int winid, BWinEvent *event_r);
+
+ /** Add an event to the BWin queue.
+ *
+ * @param winid The ID of the window to add to.
+ * @param event A pointer to copy the event from.
+ */
+void bwin_qadd(int winid, BWinEvent *event);
+
+/*---*/
+
+void bwin_load_viewmatrix(int winid, float mat[][4]);
+void bwin_load_winmatrix(int winid, float mat[][4]);
+
+void bwin_get_viewmatrix(int winid, float mat[][4]);
+void bwin_get_winmatrix(int winid, float mat[][4]);
+
+void bwin_multmatrix(int winid, float mat[][4]);
+void bwin_scalematrix(int winid, float x, float y, float z);
+
+void bwin_ortho(int winid, float x1, float x2, float y1, float y2, float n, float f);
+void bwin_ortho2(int win, float x1, float x2, float y1, float y2);
+void bwin_frustum(int winid, float x1, float x2, float y1, float y2, float n, float f);
+
+void bwin_getsize(int winid, int *x, int *y);
+void bwin_getsuborigin(int winid, int *x, int *y);
+void bwin_get_rect(int winid, struct rcti *rect_r);
+void bwin_getsinglematrix(int winid, float mat[][4]);
+void bwin_clear_viewmat(int winid);
+
+int myswinopen(int parentid, int xmin, int xmax, int ymin, int ymax);
+int myswinopen_allowed(void);
+void myswapbuffers(void);
+
+void mygetmatrix(float mat[][4]);
+void mymultmatrix(float [][4]);
+
+void myloadmatrix(float mat[][4]);
+void mywinset(int wid);
+void myortho(float x1, float x2, float y1, float y2, float n, float f);
+void myortho2(float x1, float x2, float y1, float y2);
+void mywindow(float x1, float x2, float y1, float y2, float n, float f);
+void mygetsingmatrix(float (*)[4]);
+
+void setlinestyle(int nr);
+
+void BIF_wait_for_statechange(void);
+
+#define L_MOUSE 1
+#define M_MOUSE 2
+#define R_MOUSE 4
+short get_mbut(void);
+short get_qual(void);
+void getmouse(short *mval);
+
+float get_pressure(void);
+void get_tilt(float *xtilt, float *ytilt);
+#define DEV_MOUSE 0
+#define DEV_STYLUS 1
+#define DEV_ERASER 2
+short get_activedevice(void);
+
+void warp_pointer(int x, int y);
+
+int framebuffer_to_index(unsigned int col);
+void set_framebuffer_index_color(int index);
+
+int mywin_inmenu(void);
+void mywin_getmenu_rect(int *x, int *y, int *sx, int *sy);
+
+void my_put_frontbuffer_image(void);
+void my_get_frontbuffer_image(int x, int y, int sx, int sy);
+
+#endif
+
diff --git a/source/blender/include/BIF_oops.h b/source/blender/include/BIF_oops.h
new file mode 100644
index 00000000000..5da088a5ea7
--- /dev/null
+++ b/source/blender/include/BIF_oops.h
@@ -0,0 +1,71 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_OOPS_H
+#define BIF_OOPS_H
+
+struct Curve;
+struct Oops;
+struct OopsLink;
+struct SpaceOops;
+struct Material;
+struct Mesh;
+struct MetaBall;
+struct Object;
+struct Lamp;
+void add_curve_oopslinks(struct Curve *cu, struct Oops *oops, short flag);
+void add_from_link(struct Oops *from, struct Oops *oops);
+void add_material_oopslinks(struct Material *ma, struct Oops *oops, short flag);
+void add_mball_oopslinks(struct MetaBall *mb, struct Oops *oops, short flag);
+void add_mesh_oopslinks(struct Mesh *me, struct Oops *oops, short flag);
+void add_object_oopslinks(struct Object *ob, struct Oops *oops, short flag);
+void add_lamp_oopslinks(struct Lamp *la, struct Oops *oops, short flag);
+struct Oops *add_oops(void *id);
+struct OopsLink *add_oopslink(char *name, struct Oops *oops, short type, void *from, float xof, float yof);
+struct Oops *add_test_oops(void *id); /* incl links */
+void add_texture_oops(struct Material *ma);
+void build_oops(void);
+struct Oops *find_oops(ID *id);
+void free_oops(struct Oops *oops); /* ook oops zelf */
+void free_oopspace(struct SpaceOops *so);
+void new_oops_location(struct Oops *);
+int oops_test_overlap(struct Oops *test);
+int oops_test_overlaphide(struct Oops *test);
+float oopslink_totlen(struct Oops *oops);
+void shrink_oops(void);
+void shuffle_oops(void);
+int test_oops(struct Oops *oops);
+void test_oopslink(struct OopsLink *ol);
+void test_oopslinko(struct OopsLink *ol);
+
+#endif
+
diff --git a/source/blender/include/BIF_outliner.h b/source/blender/include/BIF_outliner.h
new file mode 100644
index 00000000000..34ed7950421
--- /dev/null
+++ b/source/blender/include/BIF_outliner.h
@@ -0,0 +1,106 @@
+/**
+ * $Id: BIF_outliner.h
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_OUTLINER_H
+#define BIF_OUTLINER_H
+
+struct TreeStoreElem;
+
+typedef struct TreeElement {
+ struct TreeElement *next, *prev, *parent;
+ ListBase subtree;
+ float xs, ys; // do selection
+ int store_index; // offset in tree store
+ short flag, index; // flag for non-saved stuff, index for data arrays
+ short idcode; // from TreeStore id
+ short xend; // width of item display, for select
+ char *name;
+ void *directdata; // Armature Bones, Base, ...
+} TreeElement;
+
+/* TreeElement->flag */
+#define TE_ACTIVE 1
+#define TE_ICONROW 2
+
+/* TreeStoreElem types */
+#define TSE_NLA 1
+#define TSE_NLA_ACTION 2
+#define TSE_DEFGROUP_BASE 3
+#define TSE_DEFGROUP 4
+#define TSE_BONE 5
+#define TSE_EBONE 6
+#define TSE_CONSTRAINT_BASE 7
+#define TSE_CONSTRAINT 8
+#define TSE_MODIFIER_BASE 9
+#define TSE_MODIFIER 10
+#define TSE_LINKED_OB 11
+#define TSE_SCRIPT_BASE 12
+#define TSE_POSE_BASE 13
+#define TSE_POSE_CHANNEL 14
+/*#ifdef WITH_VERSE*/
+#define TSE_VERSE_SESSION 15
+#define TSE_VERSE_OBJ_NODE 16
+#define TSE_VERSE_GEOM_NODE 17
+/*#endif*/
+#define TSE_PROXY 18
+#define TSE_R_LAYER_BASE 19
+#define TSE_R_LAYER 20
+#define TSE_R_PASS 21
+#define TSE_LINKED_MAT 22
+ /* NOTE, is used for light group */
+#define TSE_LINKED_LAMP 23
+
+/* outliner search flags */
+#define OL_FIND 0
+#define OL_FIND_CASE 1
+#define OL_FIND_COMPLETE 2
+#define OL_FIND_COMPLETE_CASE 3
+
+/* button events */
+#define OL_NAMEBUTTON 1
+
+extern void draw_outliner(struct ScrArea *sa, struct SpaceOops *so);
+extern void outliner_free_tree(struct ListBase *lb);
+extern void outliner_mouse_event(struct ScrArea *sa, short event);
+extern void outliner_toggle_visible(struct ScrArea *sa);
+extern void outliner_show_active(struct ScrArea *sa);
+extern void outliner_show_hierarchy(struct ScrArea *sa);
+extern void outliner_one_level(struct ScrArea *sa, int add);
+extern void outliner_select(struct ScrArea *sa);
+extern void outliner_toggle_selected(struct ScrArea *sa);
+extern void outliner_del(struct ScrArea *sa);
+extern void outliner_operation_menu(struct ScrArea *sa);
+extern void outliner_page_up_down(struct ScrArea *sa, int up);
+extern void outliner_find_panel(struct ScrArea *sa, int again, int flags);
+
+#endif
+
diff --git a/source/blender/include/BIF_poseobject.h b/source/blender/include/BIF_poseobject.h
new file mode 100644
index 00000000000..a640d3abe84
--- /dev/null
+++ b/source/blender/include/BIF_poseobject.h
@@ -0,0 +1,71 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_POSEOBJECT
+#define BIF_POSEOBJECT
+
+
+struct Object;
+struct bPoseChannel;
+
+void enter_posemode(void);
+void exit_posemode(void);
+
+ // sets chan->flag to POSE_KEY if bone selected
+void set_pose_keys(struct Object *ob);
+
+struct bPoseChannel *get_active_posechannel (struct Object *ob);
+int pose_channel_in_IK_chain(struct Object *ob, struct bPoseChannel *pchan);
+
+/* tools */
+void pose_select_constraint_target(void);
+void pose_special_editmenu(void);
+void pose_add_IK(void);
+void pose_clear_IK(void);
+void pose_clear_constraints(void);
+void pose_copy_menu(void);
+
+void free_posebuf(void);
+void copy_posebuf (void);
+void paste_posebuf (int flip);
+
+void pose_adds_vgroups(struct Object *meshobj, int heatweights);
+
+void pose_calculate_path(struct Object *ob);
+void pose_clear_paths(struct Object *ob);
+
+void pose_flip_names(void);
+void pose_activate_flipped_bone(void);
+void pose_movetolayer(void);
+
+#endif
+
diff --git a/source/blender/include/BIF_previewrender.h b/source/blender/include/BIF_previewrender.h
new file mode 100644
index 00000000000..f5661fa313d
--- /dev/null
+++ b/source/blender/include/BIF_previewrender.h
@@ -0,0 +1,94 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_PREVIEWRENDER_H
+#define BIF_PREVIEWRENDER_H
+
+#include "DNA_vec_types.h"
+
+struct View3D;
+struct SpaceButs;
+struct RenderInfo;
+struct Image;
+struct ScrArea;
+struct uiBlock;
+struct Render;
+
+#define PREVIEW_RENDERSIZE 140
+
+typedef void (*VectorDrawFunc)(int x, int y, int w, int h, float alpha);
+
+/* stores rendered preview - is also used for icons */
+typedef struct RenderInfo {
+ int pr_rectx;
+ int pr_recty;
+ short curtile, tottile, status;
+ rcti disprect; /* storage for view3d preview rect */
+ unsigned int* rect;
+ struct Render *re; /* persistant render */
+} RenderInfo;
+
+/* ri->status */
+#define PR_DBASE 1
+#define PR_DISPRECT 2
+#define PR_PROJECTED 4
+#define PR_ROTATED 8
+
+/* Render the preview
+
+pr_method:
+- PR_DRAW_RENDER: preview is rendered and drawn, as indicated by called context (buttons panel)
+- PR_ICON_RENDER: the preview is not drawn and the function is not dynamic,
+ so no events are processed. Hopefully fast enough for at least 32x32
+- PR_DO_RENDER: preview is rendered, not drawn, but events are processed for afterqueue,
+ in use for node editor now.
+*/
+
+#define PR_DRAW_RENDER 0
+#define PR_ICON_RENDER 1
+#define PR_DO_RENDER 2
+
+void BIF_previewrender (struct ID *id, struct RenderInfo *ri, struct ScrArea *area, int pr_method);
+void BIF_previewrender_buts (struct SpaceButs *sbuts);
+void BIF_previewdraw (struct ScrArea *sa, struct uiBlock *block);
+void BIF_preview_changed (short id_code);
+
+void BIF_preview_init_dbase (void);
+void BIF_preview_free_dbase (void);
+
+void BIF_view3d_previewrender(struct ScrArea *sa);
+void BIF_view3d_previewdraw (struct ScrArea *sa, struct uiBlock *block);
+void BIF_view3d_previewrender_free(struct View3D *v3d);
+void BIF_view3d_previewrender_clear(struct ScrArea *sa);
+void BIF_view3d_previewrender_signal(struct ScrArea *sa, short signal);
+
+#endif
diff --git a/source/blender/include/BIF_renderwin.h b/source/blender/include/BIF_renderwin.h
new file mode 100644
index 00000000000..789c3661db7
--- /dev/null
+++ b/source/blender/include/BIF_renderwin.h
@@ -0,0 +1,67 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+struct Render;
+struct ScrArea;
+struct RenderStats;
+
+void calc_renderwin_rectangle(int rectx, int recty, int posmask, int renderpos_r[2], int rendersize_r[2]);
+
+void BIF_close_render_display(void);
+
+void BIF_do_render(int anim);
+
+/**
+ * @param v3d The View3D space to render.
+ */
+void BIF_do_ogl_render(struct View3D *v3d, int anim);
+
+void BIF_renderwin_set_for_ogl_render(void);
+void BIF_renderwin_set_custom_cursor(unsigned char mask[16][2], unsigned char bitmap[16][2]);
+
+void BIF_redraw_render_rect(void);
+void BIF_swap_render_rects(void);
+void BIF_store_spare(void);
+void BIF_toggle_render_display(void);
+
+void BIF_init_render_callbacks(struct Render *re, int do_display);
+void BIF_end_render_callbacks(void);
+
+/* should not be here, ~WIP~ */
+void make_renderinfo_string(struct RenderStats *rs, char *str);
+
+/* space for info text */
+#define RW_HEADERY 18
+
+/* header print for window */
+#define RW_MAXTEXT 512
+
diff --git a/source/blender/include/BIF_resources.h b/source/blender/include/BIF_resources.h
new file mode 100644
index 00000000000..e63e84efcbd
--- /dev/null
+++ b/source/blender/include/BIF_resources.h
@@ -0,0 +1,599 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_RESOURCES_H
+#define BIF_RESOURCES_H
+
+/* elubie: TODO: move the typedef for icons to BIF_interface_icons.h */
+/* and add/replace include of BIF_resources.h by BIF_interface_icons.h */
+typedef enum {
+#define BIFICONID_FIRST (ICON_VIEW3D)
+ ICON_VIEW3D,
+ ICON_IPO,
+ ICON_OOPS,
+ ICON_BUTS,
+ ICON_FILESEL,
+ ICON_IMAGE_COL,
+ ICON_INFO,
+ ICON_SEQUENCE,
+ ICON_TEXT,
+ ICON_IMASEL,
+ ICON_SOUND,
+ ICON_ACTION,
+ ICON_NLA,
+ ICON_SCRIPTWIN,
+ ICON_TIME,
+ ICON_NODE,
+ ICON_SPACE2,
+ ICON_SPACE3,
+ ICON_SPACE4,
+ ICON_TRIA_LEFT,
+ ICON_TRIA_UP,
+ ICON_FONTPREVIEW,
+ ICON_BLANK4,
+ ICON_BLANK5,
+ ICON_BLANK6,
+
+ ICON_ORTHO,
+ ICON_PERSP,
+ ICON_CAMERA,
+ ICON_EFFECTS,
+ ICON_BBOX,
+ ICON_WIRE,
+ ICON_SOLID,
+ ICON_SMOOTH,
+ ICON_POTATO,
+ ICON_MARKER_HLT,
+ ICON_NORMALVIEW,
+ ICON_LOCALVIEW,
+ ICON_UNUSEDVIEW,
+ ICON_VIEWZOOM,
+ ICON_SORTALPHA,
+ ICON_SORTTIME,
+ ICON_SORTSIZE,
+ ICON_LONGDISPLAY,
+ ICON_SHORTDISPLAY,
+ ICON_TRIA_DOWN,
+ ICON_TRIA_RIGHT,
+ ICON_BLANK7,
+ ICON_BLANK8,
+ ICON_BLANK9,
+ ICON_BLANK10,
+
+ ICON_VIEW_AXIS_ALL,
+ ICON_VIEW_AXIS_NONE,
+ ICON_VIEW_AXIS_NONE2,
+ ICON_VIEW_AXIS_TOP,
+ ICON_VIEW_AXIS_FRONT,
+ ICON_VIEW_AXIS_SIDE,
+ ICON_POSE_DEHLT,
+ ICON_POSE_HLT,
+ ICON_BORDERMOVE,
+ ICON_MAYBE_ITS_A_LASSO,
+ ICON_BLANK1, /* ATTENTION, someone decided to use this throughout blender
+ and didn't care to neither rename it nor update the PNG */
+ ICON_VERSE,
+ ICON_MOD_BOOLEAN,
+ ICON_ARMATURE,
+ ICON_PAUSE,
+ ICON_ALIGN,
+ ICON_REC,
+ ICON_PLAY,
+ ICON_FF,
+ ICON_REW,
+ ICON_PYTHON,
+ ICON_BLANK11,
+ ICON_BLANK12,
+ ICON_BLANK13,
+ ICON_BLANK14,
+
+
+ ICON_DOTSUP,
+ ICON_DOTSDOWN,
+ ICON_MENU_PANEL,
+ ICON_AXIS_SIDE,
+ ICON_AXIS_FRONT,
+ ICON_AXIS_TOP,
+ ICON_STICKY_UVS_LOC,
+ ICON_STICKY_UVS_DISABLE,
+ ICON_STICKY_UVS_VERT,
+ ICON_PREV_KEYFRAME,
+ ICON_NEXT_KEYFRAME,
+ ICON_ENVMAP,
+ ICON_TRANSP_HLT,
+ ICON_TRANSP_DEHLT,
+ ICON_CIRCLE_DEHLT,
+ ICON_CIRCLE_HLT,
+ ICON_TPAINT_DEHLT,
+ ICON_TPAINT_HLT,
+ ICON_WPAINT_DEHLT,
+ ICON_WPAINT_HLT,
+ ICON_MARKER,
+ ICON_BLANK15,
+ ICON_BLANK16,
+ ICON_BLANK17,
+ ICON_BLANK18,
+
+ ICON_X,
+ ICON_GO_LEFT,
+ ICON_NO_GO_LEFT,
+ ICON_UNLOCKED,
+ ICON_LOCKED,
+ ICON_PARLIB,
+ ICON_DATALIB,
+ ICON_AUTO,
+ ICON_MATERIAL_DEHLT2,
+ ICON_RING,
+ ICON_GRID,
+ ICON_PROPEDIT,
+ ICON_KEEPRECT,
+ ICON_DESEL_CUBE_VERTS,
+ ICON_EDITMODE_DEHLT,
+ ICON_EDITMODE_HLT,
+ ICON_VPAINT_DEHLT,
+ ICON_VPAINT_HLT,
+ ICON_FACESEL_DEHLT,
+ ICON_FACESEL_HLT,
+ ICON_EDIT_DEHLT,
+ ICON_BOOKMARKS,
+ ICON_BLANK20,
+ ICON_BLANK21,
+ ICON_BLANK22,
+
+ ICON_HELP,
+ ICON_ERROR,
+ ICON_FOLDER_DEHLT,
+ ICON_FOLDER_HLT,
+ ICON_BLUEIMAGE_DEHLT,
+ ICON_BLUEIMAGE_HLT,
+ ICON_BPIBFOLDER_DEHLT,
+ ICON_BPIBFOLDER_HLT,
+ ICON_BPIBFOLDER_ERR,
+ ICON_UGLY_GREEN_RING,
+ ICON_GHOST,
+ ICON_SORTBYEXT,
+ ICON_SCULPTMODE_HLT,
+ ICON_VERTEXSEL,
+ ICON_EDGESEL,
+ ICON_FACESEL,
+ ICON_PLUS,
+ ICON_BPIBFOLDER_X,
+ ICON_BPIBFOLDERGREY,
+ ICON_MAGNIFY,
+ ICON_INFO2,
+ ICON_BLANK23,
+ ICON_BLANK24,
+ ICON_BLANK25,
+ ICON_BLANK26,
+
+ ICON_RIGHTARROW,
+ ICON_DOWNARROW_HLT,
+ ICON_ROUNDBEVELTHING,
+ ICON_FULLTEXTURE,
+ ICON_HOOK,
+ ICON_DOT,
+ ICON_WORLD_DEHLT,
+ ICON_CHECKBOX_DEHLT,
+ ICON_CHECKBOX_HLT,
+ ICON_LINK,
+ ICON_INLINK,
+ ICON_ZOOMIN,
+ ICON_ZOOMOUT,
+ ICON_PASTEDOWN,
+ ICON_COPYDOWN,
+ ICON_CONSTANT,
+ ICON_LINEAR,
+ ICON_CYCLIC,
+ ICON_KEY_DEHLT,
+ ICON_KEY_HLT,
+ ICON_GRID2,
+ ICON_BLANK27,
+ ICON_BLANK28,
+ ICON_BLANK29,
+ ICON_BLANK30,
+
+ ICON_EYE,
+ ICON_LAMP,
+ ICON_MATERIAL,
+ ICON_TEXTURE,
+ ICON_ANIM,
+ ICON_WORLD,
+ ICON_SCENE,
+ ICON_EDIT,
+ ICON_GAME,
+ ICON_PAINT,
+ ICON_RADIO,
+ ICON_SCRIPT,
+ ICON_SPEAKER,
+ ICON_PASTEUP,
+ ICON_COPYUP,
+ ICON_PASTEFLIPUP,
+ ICON_PASTEFLIPDOWN,
+ ICON_CYCLICLINEAR,
+ ICON_PIN_DEHLT,
+ ICON_PIN_HLT,
+ ICON_LITTLEGRID,
+ ICON_BLANK31,
+ ICON_BLANK32,
+ ICON_BLANK33,
+ ICON_BLANK34,
+
+ ICON_FULLSCREEN,
+ ICON_SPLITSCREEN,
+ ICON_RIGHTARROW_THIN,
+ ICON_DISCLOSURE_TRI_RIGHT,
+ ICON_DISCLOSURE_TRI_DOWN,
+ ICON_SCENE_SEPIA,
+ ICON_SCENE_DEHLT,
+ ICON_OBJECT,
+ ICON_MESH,
+ ICON_CURVE,
+ ICON_MBALL,
+ ICON_LATTICE,
+ ICON_LAMP_DEHLT,
+ ICON_MATERIAL_DEHLT,
+ ICON_TEXTURE_DEHLT,
+ ICON_IPO_DEHLT,
+ ICON_LIBRARY_DEHLT,
+ ICON_IMAGE_DEHLT,
+ ICON_EYEDROPPER,
+ ICON_WINDOW_WINDOW,
+ ICON_PANEL_CLOSE,
+ ICON_BLANK35,
+ ICON_BLANK36,
+ ICON_BLANK37,
+ ICON_BLANK38,
+
+ ICON_BLENDER,
+ ICON_PACKAGE,
+ ICON_UGLYPACKAGE,
+ ICON_MATPLANE,
+ ICON_MATSPHERE,
+ ICON_MATCUBE,
+ ICON_SCENE_HLT,
+ ICON_OBJECT_HLT,
+ ICON_MESH_HLT,
+ ICON_CURVE_HLT,
+ ICON_MBALL_HLT,
+ ICON_LATTICE_HLT,
+ ICON_LAMP_HLT,
+ ICON_MATERIAL_HLT,
+ ICON_TEXTURE_HLT,
+ ICON_IPO_HLT,
+ ICON_LIBRARY_HLT,
+ ICON_IMAGE_HLT,
+ ICON_CONSTRAINT,
+ ICON_CAMERA_DEHLT,
+ ICON_ARMATURE_DEHLT,
+ ICON_SNAP_GEAR,
+ ICON_SNAP_GEO,
+ ICON_BLANK41,
+ ICON_BLANK42,
+
+ ICON_SMOOTHCURVE,
+ ICON_SPHERECURVE,
+ ICON_ROOTCURVE,
+ ICON_SHARPCURVE,
+ ICON_LINCURVE,
+ ICON_NOCURVE,
+ ICON_RNDCURVE,
+ ICON_PROP_OFF,
+ ICON_PROP_ON,
+ ICON_PROP_CON,
+ ICON_SYNTAX,
+ ICON_SYNTAX_OFF,
+ ICON_MONKEY,
+ ICON_HAIR,
+ ICON_VIEWMOVE,
+ ICON_HOME,
+ ICON_CLIPUV_DEHLT,
+ ICON_CLIPUV_HLT,
+ ICON_BLANK2,
+ ICON_BLANK3,
+ ICON_VPAINT_COL,
+ ICON_RESTRICT_SELECT_OFF,
+ ICON_RESTRICT_SELECT_ON,
+ ICON_MUTE_IPO_OFF,
+ ICON_MUTE_IPO_ON,
+
+ ICON_MAN_TRANS,
+ ICON_MAN_ROT,
+ ICON_MAN_SCALE,
+ ICON_MANIPUL,
+ ICON_BLANK_47,
+ ICON_MODIFIER,
+ ICON_MOD_WAVE,
+ ICON_MOD_BUILD,
+ ICON_MOD_DECIM,
+ ICON_MOD_MIRROR,
+ ICON_MOD_SOFT,
+ ICON_MOD_SUBSURF,
+ ICON_SEQ_SEQUENCER,
+ ICON_SEQ_PREVIEW,
+ ICON_SEQ_LUMA_WAVEFORM,
+ ICON_SEQ_CHROMA_SCOPE,
+ ICON_ROTATE,
+ ICON_CURSOR,
+ ICON_ROTATECOLLECTION,
+ ICON_ROTATECENTER,
+ ICON_ROTACTIVE,
+ ICON_RESTRICT_VIEW_OFF,
+ ICON_RESTRICT_VIEW_ON,
+ ICON_RESTRICT_RENDER_OFF,
+ ICON_RESTRICT_RENDER_ON,
+
+ VICON_VIEW3D,
+ VICON_EDIT,
+ VICON_EDITMODE_DEHLT,
+ VICON_EDITMODE_HLT,
+ VICON_DISCLOSURE_TRI_RIGHT,
+ VICON_DISCLOSURE_TRI_DOWN,
+ VICON_MOVE_UP,
+ VICON_MOVE_DOWN,
+ VICON_X
+
+#define BIFICONID_LAST (VICON_X)
+#define BIFNICONIDS (BIFICONID_LAST-BIFICONID_FIRST + 1)
+} BIFIconID;
+
+typedef enum {
+#define BIFCOLORSHADE_FIRST (COLORSHADE_DARK)
+ COLORSHADE_DARK,
+ COLORSHADE_GREY,
+ COLORSHADE_MEDIUM,
+ COLORSHADE_HILITE,
+ COLORSHADE_LIGHT,
+ COLORSHADE_WHITE
+#define BIFCOLORSHADE_LAST (COLORSHADE_WHITE)
+#define BIFNCOLORSHADES (BIFCOLORSHADE_LAST-BIFCOLORSHADE_FIRST + 1)
+} BIFColorShade;
+
+typedef enum {
+#define BIFCOLORID_FIRST (BUTGREY)
+ BUTGREY = 0,
+ BUTGREEN,
+ BUTBLUE,
+ BUTSALMON,
+ MIDGREY,
+ BUTPURPLE,
+ BUTYELLOW,
+ REDALERT,
+ BUTRUST,
+ BUTWHITE,
+ BUTDBLUE,
+ BUTPINK,
+ BUTDPINK,
+ BUTMACTIVE,
+
+ BUTIPO,
+ BUTAUDIO,
+ BUTCAMERA,
+ BUTRANDOM,
+ BUTEDITOBJECT,
+ BUTPROPERTY,
+ BUTSCENE,
+ BUTMOTION,
+ BUTMESSAGE,
+ BUTACTION,
+ BUTCD,
+ BUTGAME,
+ BUTVISIBILITY,
+ BUTYUCK,
+ BUTSEASICK,
+ BUTCHOKE,
+ BUTIMPERIAL,
+
+ BUTTEXTCOLOR,
+ BUTTEXTPRESSED,
+ BUTSBACKGROUND,
+
+ VIEWPORTBACKCOLOR,
+ VIEWPORTGRIDCOLOR,
+ VIEWPORTACTIVECOLOR,
+ VIEWPORTSELECTEDCOLOR,
+ VIEWPORTUNSELCOLOR,
+
+ EDITVERTSEL,
+ EDITVERTUNSEL,
+ EDITEDGESEL,
+ EDITEDGEUNSEL
+
+#define BIFCOLORID_LAST (EDITEDGEUNSEL)
+#define BIFNCOLORIDS (BIFCOLORID_LAST-BIFCOLORID_FIRST + 1)
+
+} BIFColorID;
+
+/* XXX WARNING: this is saved in file, so do not change order! */
+enum {
+ TH_AUTO, /* for buttons, to signal automatic color assignment */
+
+// uibutton colors
+ TH_BUT_OUTLINE,
+ TH_BUT_NEUTRAL,
+ TH_BUT_ACTION,
+ TH_BUT_SETTING,
+ TH_BUT_SETTING1,
+ TH_BUT_SETTING2,
+ TH_BUT_NUM,
+ TH_BUT_TEXTFIELD,
+ TH_BUT_POPUP,
+ TH_BUT_TEXT,
+ TH_BUT_TEXT_HI,
+ TH_MENU_BACK,
+ TH_MENU_ITEM,
+ TH_MENU_HILITE,
+ TH_MENU_TEXT,
+ TH_MENU_TEXT_HI,
+
+ TH_BUT_DRAWTYPE,
+
+ TH_REDALERT,
+ TH_CUSTOM,
+
+ TH_BUT_TEXTFIELD_HI,
+ TH_ICONFILE,
+
+ TH_THEMEUI,
+// common colors among spaces
+
+ TH_BACK,
+ TH_TEXT,
+ TH_TEXT_HI,
+ TH_HEADER,
+ TH_HEADERDESEL,
+ TH_PANEL,
+ TH_SHADE1,
+ TH_SHADE2,
+ TH_HILITE,
+
+ TH_GRID,
+ TH_WIRE,
+ TH_SELECT,
+ TH_ACTIVE,
+ TH_GROUP,
+ TH_GROUP_ACTIVE,
+ TH_TRANSFORM,
+ TH_VERTEX,
+ TH_VERTEX_SELECT,
+ TH_VERTEX_SIZE,
+ TH_EDGE,
+ TH_EDGE_SELECT,
+ TH_EDGE_SEAM,
+ TH_EDGE_FACESEL,
+ TH_FACE,
+ TH_FACE_SELECT,
+ TH_NORMAL,
+ TH_FACE_DOT,
+ TH_FACEDOT_SIZE,
+
+ TH_SYNTAX_B,
+ TH_SYNTAX_V,
+ TH_SYNTAX_C,
+ TH_SYNTAX_L,
+ TH_SYNTAX_N,
+
+ TH_BONE_SOLID,
+ TH_BONE_POSE,
+
+ TH_STRIP,
+ TH_STRIP_SELECT,
+
+ TH_LAMP,
+
+ TH_NODE,
+ TH_NODE_IN_OUT,
+ TH_NODE_OPERATOR,
+ TH_NODE_CONVERTOR,
+ TH_NODE_GROUP,
+
+ TH_SEQ_MOVIE,
+ TH_SEQ_IMAGE,
+ TH_SEQ_SCENE,
+ TH_SEQ_AUDIO,
+ TH_SEQ_EFFECT,
+ TH_SEQ_PLUGIN,
+ TH_SEQ_TRANSITION,
+ TH_SEQ_META,
+
+ TH_EDGE_SHARP,
+ TH_EDITMESH_ACTIVE,
+};
+/* XXX WARNING: previous is saved in file, so do not change order! */
+
+/* theme drawtypes */
+#define TH_MINIMAL 0
+#define TH_SHADED 1
+#define TH_ROUNDED 2
+#define TH_OLDSKOOL 3
+
+/* specific defines per space should have higher define values */
+
+struct bTheme;
+
+// THE CODERS API FOR THEMES:
+
+// sets the color
+void BIF_ThemeColor(int colorid);
+
+// sets the color plus alpha
+void BIF_ThemeColor4(int colorid);
+
+// sets color plus offset for shade
+void BIF_ThemeColorShade(int colorid, int offset);
+
+// sets color plus offset for alpha
+void BIF_ThemeColorShadeAlpha(int colorid, int coloffset, int alphaoffset);
+
+// sets color, which is blend between two theme colors
+void BIF_ThemeColorBlend(int colorid1, int colorid2, float fac);
+// same, with shade offset
+void BIF_ThemeColorBlendShade(int colorid1, int colorid2, float fac, int offset);
+
+// returns one value, not scaled
+float BIF_GetThemeValuef(int colorid);
+int BIF_GetThemeValue(int colorid);
+
+// get three color values, scaled to 0.0-1.0 range
+void BIF_GetThemeColor3fv(int colorid, float *col);
+
+// get the 3 or 4 byte values
+void BIF_GetThemeColor3ubv(int colorid, char *col);
+void BIF_GetThemeColor4ubv(int colorid, char *col);
+
+// get a theme color from specified space type
+void BIF_GetThemeColorType4ubv(int colorid, int spacetype, char *col);
+
+// blends and shades between two color pointers
+void BIF_ColorPtrBlendShade3ubv(char *cp1, char *cp2, float fac, int offset);
+
+// get a 3 byte color, blended and shaded between two other char color pointers
+void BIF_GetColorPtrBlendShade3ubv(char *cp1, char *cp2, char *col, float fac, int offset);
+
+
+struct ScrArea;
+
+// internal (blender) usage only, for init and set active
+void BIF_InitTheme(void);
+void BIF_SetTheme(struct ScrArea *sa);
+void BIF_resources_init (void);
+void BIF_resources_free (void);
+void BIF_colors_init (void);
+void BIF_load_ui_colors (void);
+
+/* only for buttons in theme editor! */
+char *BIF_ThemeGetColorPtr(struct bTheme *btheme, int spacetype, int colorid);
+char *BIF_ThemeColorsPup(int spacetype);
+
+
+void BIF_def_color (BIFColorID colorid, unsigned char r, unsigned char g, unsigned char b);
+
+#endif /* BIF_ICONS_H */
diff --git a/source/blender/include/BIF_retopo.h b/source/blender/include/BIF_retopo.h
new file mode 100644
index 00000000000..5d39923a398
--- /dev/null
+++ b/source/blender/include/BIF_retopo.h
@@ -0,0 +1,110 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 by Nicholas Bishop
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_RETOPO_H
+#define BIF_RETOPO_H
+
+#include "DNA_vec_types.h"
+
+/* For bglMats */
+#include "BIF_glutil.h"
+
+struct EditVert;
+struct Mesh;
+struct View3D;
+
+typedef struct RetopoViewData {
+ bglMats mats;
+
+ char queue_matrix_update;
+} RetopoViewData;
+
+typedef struct RetopoPaintPoint {
+ struct RetopoPaintPoint *next, *prev;
+ vec2s loc;
+ short index;
+ float co[3];
+ struct EditVert *eve;
+} RetopoPaintPoint;
+
+typedef struct RetopoPaintLine {
+ struct RetopoPaintLine *next, *prev;
+ ListBase points;
+ ListBase hitlist; /* RetopoPaintHit */
+ RetopoPaintPoint *cyclic;
+} RetopoPaintLine;
+
+typedef struct RetopoPaintSel {
+ struct RetopoPaintSel *next, *prev;
+ RetopoPaintLine *line;
+ char first;
+} RetopoPaintSel;
+
+typedef struct RetopoPaintData {
+ char in_drag;
+ short sloc[2];
+
+ ListBase lines;
+ ListBase intersections; /* RetopoPaintPoint */
+
+ short seldist;
+ RetopoPaintSel nearest;
+
+ struct View3D *paint_v3d;
+} RetopoPaintData;
+
+RetopoPaintData *get_retopo_paint_data();
+
+char retopo_mesh_check();
+char retopo_curve_check();
+
+void retopo_end_okee();
+
+void retopo_free_paint_data(RetopoPaintData *rpd);
+void retopo_free_paint();
+
+char retopo_mesh_paint_check();
+void retopo_paint_view_update(struct View3D *v3d);
+void retopo_force_update();
+void retopo_paint_toggle(void*,void*);
+char retopo_paint(const unsigned short event);
+void retopo_draw_paint_lines();
+RetopoPaintData *retopo_paint_data_copy(RetopoPaintData *rpd);
+
+void retopo_toggle(void*,void*);
+void retopo_do_vert(struct View3D *v3d, float *v);
+void retopo_do_all();
+void retopo_do_all_cb(void *, void *);
+void retopo_queue_updates(struct View3D *v3d);
+
+void retopo_matrix_update(struct View3D *v3d);
+
+void retopo_free_view_data(struct View3D *v3d);
+
+#endif
diff --git a/source/blender/include/BIF_scrarea.h b/source/blender/include/BIF_scrarea.h
new file mode 100644
index 00000000000..c2953078edc
--- /dev/null
+++ b/source/blender/include/BIF_scrarea.h
@@ -0,0 +1,54 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct ScrArea;
+
+ /**
+ * Finds the first spacedata of @a type within
+ * the scrarea.
+ */
+void *scrarea_find_space_of_type(ScrArea *sa, int type);
+
+int scrarea_get_win_x (struct ScrArea *sa);
+int scrarea_get_win_y (struct ScrArea *sa);
+int scrarea_get_win_width (struct ScrArea *sa);
+int scrarea_get_win_height (struct ScrArea *sa);
+
+#ifdef __cplusplus
+}
+
+#endif
+
diff --git a/source/blender/include/BIF_screen.h b/source/blender/include/BIF_screen.h
new file mode 100644
index 00000000000..36719af7aa2
--- /dev/null
+++ b/source/blender/include/BIF_screen.h
@@ -0,0 +1,137 @@
+/* replacement for screen.h */
+/*
+ *
+ * Leftovers here are actually editscreen.c thingies
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_SCREEN_H
+#define BIF_SCREEN_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* externs in editscreen.c */
+extern int displaysizex, displaysizey;
+extern struct ScrArea *curarea;
+
+struct View3D;
+struct bScreen;
+struct ScrArea;
+struct ScrVert;
+struct ScrEdge;
+struct ListBase;
+
+struct View3D *find_biggest_view3d(void);
+struct ScrArea *find_biggest_area_of_type(int spacecode);
+struct ScrArea *find_biggest_area(void);
+
+void scrarea_queue_redraw(struct ScrArea *area);
+void scrarea_queue_winredraw(struct ScrArea *area);
+void scrarea_queue_headredraw(struct ScrArea *area);
+
+int blender_test_break(void);
+
+void duplicate_screen(void);
+void init_screen_cursors(void);
+void set_timecursor(int nr);
+void waitcursor(int val);
+void wich_cursor(struct ScrArea *sa);
+void setcursor_space(int spacetype, short cur);
+void set_g_activearea(struct ScrArea *sa);
+void getmouseco_sc(short *mval);
+void getmouseco_areawin(short *mval);
+void getmouseco_headwin(short *mval);
+int qtest(void);
+int anyqtest(void);
+void areawinset(short win);
+void headerbox(struct ScrArea *sa);
+void defheaddraw(void);
+void defheadchange(void);
+unsigned short winqtest(struct ScrArea *sa);
+unsigned short headqtest(struct ScrArea *sa);
+void winqdelete(struct ScrArea *sa);
+void winqclear(struct ScrArea *sa);
+void addqueue(short win, unsigned short event, short val);
+void addafterqueue(short win, unsigned short event, short val);
+void add_readfile_event(char *filename);
+short ext_qtest(void);
+unsigned short extern_qread(short *val);
+unsigned short extern_qread_ext(short *val, char *ascii);
+
+extern void markdirty_all(void); // also sets redraw event
+extern void markdirty_all_back(void);
+extern void markdirty_win_back(short winid);
+
+void screen_swapbuffers(void);
+void set_debug_swapbuffers_ovveride(struct bScreen *sc, int mode);
+int is_allowed_to_change_screen(struct bScreen *newp);
+void splash(void * data, int datasizei, char * string);
+void screen_delayed_undo_push(char *name);
+void screenmain(void);
+void getdisplaysize(void);
+void setprefsize(int stax, int stay, int sizx, int sizy, int maximized);
+void calc_arearcts(struct ScrArea *sa);
+void resize_screen(int x, int y, int w, int h);
+struct ScrArea *closest_bigger_area(void);
+int mywinopen(int mode, short posx, short posy, short sizex, short sizey);
+void setscreen(struct bScreen *sc);
+void area_fullscreen(void);
+int select_area(int spacetype);
+struct bScreen *default_twosplit(void);
+void initscreen(void);
+void unlink_screen(struct bScreen *sc);
+void reset_autosave(void);
+int area_is_active_area(struct ScrArea *area);
+void draw_area_emboss(struct ScrArea *sa);
+
+void headerprint(char *str);
+
+/* ******* handlers ****** */
+void add_screenhandler(struct bScreen *sc, short eventcode, short val);
+void rem_screenhandler(struct bScreen *sc, short eventcode);
+int do_screenhandlers(struct bScreen *sc);
+int has_screenhandler(struct bScreen *sc, short eventcode);
+
+ /***/
+
+/* return all layers of all 3d windows in a screen */
+unsigned int screen_view3d_layers(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BIF_SCREEN_H */
+
diff --git a/source/blender/include/BIF_space.h b/source/blender/include/BIF_space.h
new file mode 100644
index 00000000000..855773b3497
--- /dev/null
+++ b/source/blender/include/BIF_space.h
@@ -0,0 +1,148 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_SPACE_H
+#define BIF_SPACE_H
+
+struct ListBase;
+struct ScrArea;
+struct SpaceButs;
+struct View2D;
+struct BWinEvent;
+struct SpaceOops;
+
+#define REMAKEIPO 1
+#define OOPS_TEST 2
+
+#define BUT_HORIZONTAL 1
+#define BUT_VERTICAL 2
+
+/* is hardcoded in DNA_space_types.h */
+#define SPACE_MAXHANDLER 8
+
+/* view3d handler codes */
+#define VIEW3D_HANDLER_BACKGROUND 1
+#define VIEW3D_HANDLER_PROPERTIES 2
+#define VIEW3D_HANDLER_OBJECT 3
+#define VIEW3D_HANDLER_PREVIEW 4
+#define VIEW3D_HANDLER_MULTIRES 5
+
+/* ipo handler codes */
+#define IPO_HANDLER_PROPERTIES 20
+
+/* image handler codes */
+#define IMAGE_HANDLER_PROPERTIES 30
+#define IMAGE_HANDLER_PAINT 31
+#define IMAGE_HANDLER_CURVES 32
+#define IMAGE_HANDLER_PREVIEW 33
+#define IMAGE_HANDLER_GAME_PROPERTIES 34
+#define IMAGE_HANDLER_VIEW_PROPERTIES 35
+/*#define IMAGE_HANDLER_TRANSFORM_PROPERTIES 36*/
+
+/* action handler codes */
+#define ACTION_HANDLER_PROPERTIES 40
+
+/* nla handler codes */
+#define NLA_HANDLER_PROPERTIES 50
+
+/* sequence handler codes */
+#define SEQ_HANDLER_PROPERTIES 60
+
+/* imasel handler codes */
+#define IMASEL_HANDLER_IMAGE 70
+
+/* theme codes */
+#define B_ADD_THEME 3301
+#define B_DEL_THEME 3302
+#define B_NAME_THEME 3303
+#define B_THEMECOL 3304
+#define B_UPDATE_THEME 3305
+#define B_CHANGE_THEME 3306
+#define B_THEME_COPY 3307
+#define B_THEME_PASTE 3308
+#define B_UPDATE_THEME_ICONS 3309
+
+#define B_RECALCLIGHT 3310
+
+
+void scrarea_do_winprefetchdraw (struct ScrArea *sa);
+void scrarea_do_windraw (struct ScrArea *sa);
+void scrarea_do_winchange (struct ScrArea *sa);
+void scrarea_do_winhandle (struct ScrArea *sa, struct BWinEvent *evt);
+void scrarea_do_headdraw (struct ScrArea *sa);
+void scrarea_do_headchange (struct ScrArea *sa);
+
+/* space.c */
+extern void add_blockhandler(struct ScrArea *sa, short eventcode, short action);
+extern void rem_blockhandler(struct ScrArea *sa, short eventcode);
+extern void toggle_blockhandler(struct ScrArea *sa, short eventcode, short action);
+
+extern void space_set_commmandline_options(void);
+extern void allqueue(unsigned short event, short val);
+extern void allspace(unsigned short event, short val);
+extern void copy_view3d_lock(short val);
+extern void drawemptyspace(struct ScrArea *sa, void *spacedata);
+extern void drawinfospace(struct ScrArea *sa, void *spacedata);
+extern void duplicatespacelist(struct ScrArea *area, struct ListBase *lb1, struct ListBase *lb2);
+extern void extern_set_butspace(int fkey, int do_cycle);
+extern void force_draw(int header);
+extern void force_draw_all(int header);
+extern void force_draw_plus(int type, int header);
+extern void freespacelist(struct ScrArea *sa);
+extern void handle_view3d_around(void);
+extern void handle_view3d_lock(void);
+extern void init_v2d_oops(struct ScrArea *, struct SpaceOops *);
+extern void initipo(struct ScrArea *sa);
+extern void newspace(struct ScrArea *sa, int type);
+extern void set_rects_butspace(struct SpaceButs *buts);
+extern void test_butspace(void);
+extern void start_game(void);
+extern void select_object_grouped(short nr);
+extern void join_menu(void);
+
+extern void BIF_undo_push(char *str);
+extern void BIF_undo(void);
+extern void BIF_redo(void);
+extern void BIF_undo_menu(void);
+
+#if 0
+//#ifdef _WIN32 // FULLSCREEN
+extern void mainwindow_toggle_fullscreen(int fullscreen);
+#endif
+
+extern void mainwindow_set_filename_to_title(char *title);
+extern void mainwindow_raise(void);
+extern void mainwindow_make_active(void);
+extern void mainwindow_close(void);
+
+#endif
+
diff --git a/source/blender/include/BIF_spacetypes.h b/source/blender/include/BIF_spacetypes.h
new file mode 100644
index 00000000000..6125cfd5926
--- /dev/null
+++ b/source/blender/include/BIF_spacetypes.h
@@ -0,0 +1,67 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+struct ScrArea;
+struct BWinEvent;
+
+typedef struct _SpaceType SpaceType;
+
+typedef void (*SpacePrefetchDrawFP) (struct ScrArea *sa, void *spacedata);
+typedef void (*SpaceDrawFP) (struct ScrArea *sa, void *spacedata);
+typedef void (*SpaceChangeFP) (struct ScrArea *sa, void *spacedata);
+typedef void (*SpaceHandleFP) (struct ScrArea *sa, void *spacedata, struct BWinEvent *evt);
+
+ /***/
+
+SpaceType* spacetype_new (char *name);
+
+void spacetype_set_winfuncs (SpaceType *st, SpacePrefetchDrawFP prefetch, SpaceDrawFP draw, SpaceChangeFP change, SpaceHandleFP handle);
+
+ /***/
+
+SpaceType *spaceaction_get_type (void);
+SpaceType *spacebuts_get_type (void);
+SpaceType *spacefile_get_type (void);
+SpaceType *spaceimage_get_type (void);
+SpaceType *spaceimasel_get_type (void);
+SpaceType *spaceinfo_get_type (void);
+SpaceType *spaceipo_get_type (void);
+SpaceType *spacenla_get_type (void);
+SpaceType *spaceoops_get_type (void);
+SpaceType *spaceseq_get_type (void);
+SpaceType *spacesound_get_type (void);
+SpaceType *spacetext_get_type (void);
+SpaceType *spacescript_get_type (void);
+SpaceType *spaceview3d_get_type (void);
+SpaceType *spacetime_get_type (void);
+SpaceType *spacenode_get_type (void);
+
diff --git a/source/blender/include/BIF_tbcallback.h b/source/blender/include/BIF_tbcallback.h
new file mode 100644
index 00000000000..98aebf5c863
--- /dev/null
+++ b/source/blender/include/BIF_tbcallback.h
@@ -0,0 +1,42 @@
+/* $Id$
+*/
+/*
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****/
+
+/* defines callback structure for toolbox menu */
+typedef struct _TBcallback {
+ char *desc;
+ char *key;
+ void (*cb)(int v); /* callback function takes value */
+ int val;
+} TBcallback;
+
+typedef TBcallback * (*Tbox_callbackfunc)(int l, int x);
+void tboxSetCallback(Tbox_callbackfunc f);
+
diff --git a/source/blender/include/BIF_toets.h b/source/blender/include/BIF_toets.h
new file mode 100644
index 00000000000..f5a435d3d50
--- /dev/null
+++ b/source/blender/include/BIF_toets.h
@@ -0,0 +1,41 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_TOETS_H
+#define BIF_TOETS_H
+
+int blenderqread(unsigned short event, short val);
+void persptoetsen(unsigned short event); /* dutch rules man */
+int untitled(char *name);
+
+#endif
+
diff --git a/source/blender/include/BIF_toolbox.h b/source/blender/include/BIF_toolbox.h
new file mode 100644
index 00000000000..72867cbfa05
--- /dev/null
+++ b/source/blender/include/BIF_toolbox.h
@@ -0,0 +1,68 @@
+/* toolbox (SPACEKEY) related
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_TOOLBOX_H
+#define BIF_TOOLBOX_H
+
+/* toolbox.c */
+void asciitoraw (int ch, short unsigned int *event, short unsigned int *qual);
+
+void toolbox_n(void);
+void toolbox_n_add(void);
+void reset_toolbox(void);
+
+void notice (char *str, ...);
+void error (char *fmt, ...);
+
+void error_libdata (void);
+
+int saveover (char *filename);
+int okee (char *fmt, ...);
+
+short button (short *var, short min, short max, char *str);
+short fbutton (float *var, float min, float max, float a1, float a2, char *str);
+short sbutton (char *var, float min, float max, char *str); /* __NLA */
+
+int movetolayer_buts (unsigned int *lay, char *title);
+int movetolayer_short_buts (short *lay, char *title);
+
+void draw_numbuts_tip (char *str, int x1, int y1, int x2, int y2);
+int do_clever_numbuts (char *name, int tot, int winevent);
+void clever_numbuts_buts(void);
+void add_numbut (int nr, int type, char *str, float min, float max, void *poin, char *tip);
+void clever_numbuts (void);
+void replace_names_but (void);
+
+void BIF_screendump(int fscreen);
+void write_screendump(char *name);
+
+#endif
diff --git a/source/blender/include/BIF_transform.h b/source/blender/include/BIF_transform.h
new file mode 100644
index 00000000000..26900b06c52
--- /dev/null
+++ b/source/blender/include/BIF_transform.h
@@ -0,0 +1,108 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_TRANSFORM_H
+#define BIF_TRANSFORM_H
+
+/* ******************** Macros & Prototypes *********************** */
+
+/* MODE AND NUMINPUT FLAGS */
+#define TFM_INIT -1
+#define TFM_DUMMY 0
+#define TFM_TRANSLATION 1
+#define TFM_ROTATION 2
+#define TFM_RESIZE 3
+#define TFM_TOSPHERE 4
+#define TFM_SHEAR 5
+#define TFM_WARP 7
+#define TFM_SHRINKFATTEN 8
+#define TFM_TILT 9
+#define TFM_LAMP_ENERGY 10
+#define TFM_TRACKBALL 11
+#define TFM_PUSHPULL 12
+#define TFM_CREASE 13
+#define TFM_MIRROR 14
+#define TFM_BONESIZE 15
+#define TFM_BONE_ENVELOPE 16
+#define TFM_CURVE_SHRINKFATTEN 17
+#define TFM_BONE_ROLL 18
+#define TFM_TIME_TRANSLATE 19
+#define TFM_TIME_SLIDE 20
+#define TFM_TIME_SCALE 21
+#define TFM_TIME_EXTEND 22
+
+/* TRANSFORM CONTEXTS */
+#define CTX_NONE 0
+#define CTX_TEXTURE 1
+#define CTX_EDGE 2
+#define CTX_NO_PET 4
+#define CTX_TWEAK 8
+
+void initTransform(int mode, int context);
+void Transform(void);
+void Mirror(short mode);
+
+/* Standalone call to get the transformation center corresponding to the current situation
+ * returns 1 if successful, 0 otherwise (usually means there's no selection)
+ * (if 0 is returns, *vec is unmodified)
+ * */
+int calculateTransformCenter(int centerMode, float *vec);
+
+struct TransInfo;
+struct ScrArea;
+
+struct TransInfo * BIF_GetTransInfo(void);
+void BIF_setSingleAxisConstraint(float vec[3], char *text);
+void BIF_setDualAxisConstraint(float vec1[3], float vec2[3], char *text);
+void BIF_setLocalAxisConstraint(char axis, char *text);
+void BIF_setLocalLockConstraint(char axis, char *text);
+
+/* Drawing callbacks */
+void BIF_drawConstraint(void);
+void BIF_drawPropCircle(void);
+void BIF_drawSnap(void);
+
+void BIF_getPropCenter(float *center);
+
+void BIF_TransformSetUndo(char *str);
+
+void BIF_selectOrientation(void);
+
+/* view3d manipulators */
+void initManipulator(int mode);
+void ManipulatorTransform();
+
+int BIF_do_manipulator(struct ScrArea *sa);
+void BIF_draw_manipulator(struct ScrArea *sa);
+
+#endif
+
diff --git a/source/blender/include/BIF_usiblender.h b/source/blender/include/BIF_usiblender.h
new file mode 100644
index 00000000000..e77d1e98487
--- /dev/null
+++ b/source/blender/include/BIF_usiblender.h
@@ -0,0 +1,54 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_USIBLENDER_H
+#define BIF_USIBLENDER_H
+
+typedef struct RecentFile {
+ struct RecentFile *next, *prev;
+ char *filename;
+} RecentFile;
+
+void exit_usiblender(void);
+
+void BIF_init(void);
+
+void BIF_read_file(char *name);
+int BIF_read_homefile(int from_memory, int do_undo);
+void BIF_read_autosavefile(void);
+
+void BIF_write_file(char *target);
+void BIF_write_homefile(void);
+void BIF_write_autosave(void);
+
+#endif
+
diff --git a/source/blender/include/BIF_verse.h b/source/blender/include/BIF_verse.h
new file mode 100644
index 00000000000..d491316662d
--- /dev/null
+++ b/source/blender/include/BIF_verse.h
@@ -0,0 +1,142 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributor(s): Jiri Hnidek.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifdef WITH_VERSE
+
+#ifndef BIF_VERSE_H
+#define BIF_VERSE_H
+
+#include "BKE_verse.h"
+#include "DNA_meshdata_types.h"
+
+struct Object;
+
+struct EditMesh;
+struct EditVert;
+struct EditFace;
+struct Mesh;
+struct MVert;
+struct Mface;
+
+/* verse_object.c */
+void unsubscribe_from_obj_node(struct VNode *vnode);
+void unsubscribe_from_geom_node(struct VNode *vnode);
+void unsubscribe_from_bitmap_node(struct VNode *vnode);
+
+void test_and_send_idbutton_cb(void *obj, void *ob_name);
+
+struct Object *create_object_from_verse_node(struct VNode *vnode);
+
+void b_verse_pop_node(struct VNode *vnode);
+void b_verse_unsubscribe(VNode *vnode);
+void b_verse_push_object(struct VerseSession *session, struct Object *ob);
+void b_verse_delete_object(struct Object *ob);
+void b_verse_ms_get(void);
+
+void post_transform_pos(struct VNode *vnode);
+void post_transform_rot(struct VNode *vnode);
+void post_transform_scale(struct VNode *vnode);
+
+/*void post_transform(struct VNode *vnode);*/
+void post_link_set(struct VLink *vlink);
+void post_link_destroy(struct VLink *vlink);
+void post_object_free_constraint(struct VNode *vnode);
+
+void b_verse_send_transformation(struct Object *ob);
+
+/* verse_mesh.c */
+void b_verse_send_vertex_delete(struct EditVert *eve);
+void send_versevert_pos(struct VerseVert *vvert);
+
+void b_verse_send_face_delete(struct EditFace *efa);
+
+void sync_all_versefaces_with_editfaces(struct VNode *vnode);
+void sync_all_verseverts_with_editverts(struct VNode *vnode);
+
+void createVerseVert(struct EditVert *ev);
+void createVerseFace(struct EditFace *efa);
+
+void b_verse_duplicate_object(struct VerseSession *session, struct Object *ob, struct Object *n_ob);
+struct VNode *create_geom_vnode_from_geom_vnode(struct VNode *vnode);
+struct VNode *create_geom_vnode_data_from_editmesh(struct VerseSession *session, struct EditMesh *em);
+struct VNode *create_geom_vnode_data_from_mesh(struct VerseSession *session, struct Mesh *me);
+
+void destroy_unused_geometry(struct VNode *vnode);
+void destroy_binding_between_versemesh_and_editmesh(struct VNode *vnode);
+
+void destroy_versemesh(struct VNode *vnode);
+
+void unsubscribe_from_geom_node(struct VNode *vnode);
+
+void create_edit_mesh_from_geom_node(struct VNode *vnode);
+struct Mesh *create_mesh_from_geom_node(struct VNode *vnode);
+void create_meshdata_from_geom_node(struct Mesh *me, struct VNode *vnode);
+
+/* geometry post callback functions */
+void post_layer_create(struct VLayer *vlayer);
+void post_layer_destroy(struct VLayer *vlayer);
+
+void post_vertex_create(struct VerseVert *vvert);
+void post_vertex_set_xyz(struct VerseVert *vvert);
+void post_vertex_delete(struct VerseVert *vvert);
+void post_vertex_free_constraint(struct VerseVert *vvert);
+
+void post_polygon_set_uint8(struct VerseFace *vface);
+void post_polygon_create(struct VerseFace *vface);
+void post_polygon_set_corner(struct VerseFace *vface);
+void post_polygon_delete(struct VerseFace *vface);
+void post_polygon_free_constraint(struct VerseFace *vface);
+
+void post_geometry_free_constraint(struct VNode *vnode);
+
+/* verse_common.c */
+struct VerseSession *session_menu(void);
+char *verse_client_name(void);
+
+void post_tag_change(struct VTag *vtag);
+void post_taggroup_create(struct VTagGroup *vtaggroup);
+
+void post_node_create(struct VNode *vnode);
+void post_node_destroy(struct VNode *vnode);
+void post_node_name_set(struct VNode *vnode);
+
+void post_connect_accept(struct VerseSession *session);
+void post_connect_terminated(struct VerseSession *session);
+void post_connect_update(struct VerseSession *session);
+void post_server_add(void);
+
+/* verse_image.c */
+
+void sync_blender_image_with_verse_bitmap_node(struct VNode *vnode);
+void post_bitmap_dimension_set(struct VNode *vnode);
+void post_bitmap_layer_create(struct VBitmapLayer *vblayer);
+void post_bitmap_layer_destroy(struct VBitmapLayer *vblayer);
+void post_bitmap_tile_set(struct VBitmapLayer *vblayer, unsigned int xs, unsigned int ys);
+
+#endif
+
+#endif
diff --git a/source/blender/include/BIF_writeavicodec.h b/source/blender/include/BIF_writeavicodec.h
new file mode 100644
index 00000000000..5b8ccdce4e2
--- /dev/null
+++ b/source/blender/include/BIF_writeavicodec.h
@@ -0,0 +1,44 @@
+/**
+ * Functions for writing windows avi-format files.
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ *
+ */
+
+#ifdef _WIN32
+
+void start_avi_codec(RenderData *rd,int rectx, int recty );
+void append_avi_codec(int frame,int *pixels,int rectx, int recty);
+void end_avi_codec(void);
+int get_avicodec_settings(void);
+
+#endif
+
diff --git a/source/blender/include/BIF_writeimage.h b/source/blender/include/BIF_writeimage.h
new file mode 100644
index 00000000000..70978a033c2
--- /dev/null
+++ b/source/blender/include/BIF_writeimage.h
@@ -0,0 +1,45 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_WRITEIMAGE_H
+#define BIF_WRITEIMAGE_H
+
+struct ImBuf;
+struct EnvMap;
+
+void BIF_save_rendered_image(char *name);
+void BIF_save_rendered_image_fs(void);
+void BIF_save_envmap(struct EnvMap *env, char *str);
+void save_image_filesel_str(char *str);
+
+#endif
+
diff --git a/source/blender/include/BIF_writemovie.h b/source/blender/include/BIF_writemovie.h
new file mode 100644
index 00000000000..8dab1d4e7f8
--- /dev/null
+++ b/source/blender/include/BIF_writemovie.h
@@ -0,0 +1,41 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_WRITEMOVIE_H
+#define BIF_WRITEMOVIE_H
+
+void start_movie(void);
+void append_movie(int fnum);
+void end_movie(void);
+
+#endif
+
diff --git a/source/blender/include/BPI_script.h b/source/blender/include/BPI_script.h
new file mode 100644
index 00000000000..80ac8b46900
--- /dev/null
+++ b/source/blender/include/BPI_script.h
@@ -0,0 +1,71 @@
+/**
+ * include/BPI_script.h (jan-2004 ianwill)
+ *
+ * $Id$
+ *
+ * Header for BPython's script structure. BPI: Blender Python external include
+ * file.
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BPI_SCRIPT_H
+#define BPI_SCRIPT_H
+
+//#include "DNA_listBase.h"
+#include "DNA_ID.h"
+
+typedef struct Script {
+ ID id;
+
+ void *py_draw;
+ void *py_event;
+ void *py_button;
+ void *py_browsercallback;
+ void *py_globaldict;
+
+ int flags, lastspace;
+
+} Script;
+
+/* Note: a script that registers callbacks in the script->py_* pointers
+ * above (or calls the file or image selectors) needs to keep its global
+ * dictionary until Draw.Exit() is called and the callbacks removed.
+ * Unsetting SCRIPT_RUNNING means the interpreter reached the end of the
+ * script and returned control to Blender, but we can't get rid of its
+ * namespace (global dictionary) while SCRIPT_GUI or SCRIPT_FILESEL is set,
+ * because of the callbacks. The flags and the script name are saved in
+ * each running script's global dictionary, under '__script__'. */
+
+/* Flags */
+#define SCRIPT_RUNNING 0x01
+#define SCRIPT_GUI 0x02
+#define SCRIPT_FILESEL 0x04
+
+#endif /* BPI_SCRIPT_H */
diff --git a/source/blender/include/BSE_drawimasel.h b/source/blender/include/BSE_drawimasel.h
new file mode 100644
index 00000000000..6c68ba79bb9
--- /dev/null
+++ b/source/blender/include/BSE_drawimasel.h
@@ -0,0 +1,60 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BSE_DRAWIMASEL_H
+#define BSE_DRAWIMASEL_H
+
+
+/* button events */
+#define B_FS_FILENAME 1
+#define B_FS_DIRNAME 2
+#define B_FS_DIR_MENU 3
+#define B_FS_PARDIR 4
+#define B_FS_LOAD 5
+#define B_FS_CANCEL 6
+#define B_FS_LIBNAME 7
+#define B_FS_BOOKMARK 8
+
+/* ui geometry */
+#define IMASEL_BUTTONS_HEIGHT 60
+#define TILE_BORDER_X 8
+#define TILE_BORDER_Y 8
+
+struct ScrArea;
+struct SpaceImaSel;
+
+void drawimaselspace(struct ScrArea *sa, void *spacedata);
+void calc_imasel_rcts(SpaceImaSel *simasel, int winx, int winy);
+void do_imasel_buttonevents(short event, SpaceImaSel *simasel);
+
+#endif /* BSE_DRAWIMASEL_H */
+
diff --git a/source/blender/include/BSE_drawipo.h b/source/blender/include/BSE_drawipo.h
new file mode 100644
index 00000000000..07f116d8d67
--- /dev/null
+++ b/source/blender/include/BSE_drawipo.h
@@ -0,0 +1,76 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BSE_DRAWIPO_H
+#define BSE_DRAWIPO_H
+
+#define IN_2D_VERT_SCROLL(A) (BLI_in_rcti(&G.v2d->vert, A[0], A[1]))
+#define IN_2D_HORIZ_SCROLL(A) (BLI_in_rcti(&G.v2d->hor, A[0], A[1]))
+
+#define SELECT_REPLACE 1
+#define SELECT_ADD 2
+#define SELECT_SUBTRACT 4
+#define SELECT_INVERT 16
+
+struct ScrArea;
+struct EditIpo;
+struct View2D;
+struct rctf;
+
+void calc_ipogrid(void);
+void draw_ipogrid(void);
+
+void areamouseco_to_ipoco (struct View2D *v2d, short *mval, float *x, float *y);
+void ipoco_to_areaco (struct View2D *v2d, float *vec, short *mval);
+void ipoco_to_areaco_noclip (struct View2D *v2d, float *vec, short *mval);
+
+void view2d_do_locks (struct ScrArea *cursa, int flag);
+void view2d_zoom (struct View2D *v2d, float factor, int winx, int winy);
+void test_view2d (struct View2D *v2d, int winx, int winy);
+void calc_scrollrcts (struct ScrArea *sa, struct View2D *v2d, int winx, int winy);
+
+int in_ipo_buttons(void);
+void draw_view2d_numbers_horiz(int drawframes);
+void drawscroll(int disptype);
+void drawipospace(struct ScrArea *sa, void *spacedata);
+
+void center_currframe(void);
+void scroll_ipobuts(void);
+int view2dzoom(unsigned short event);
+int view2dmove(unsigned short event);
+void view2dborder(void);
+
+struct EditIpo *select_proj_ipo(struct rctf *rectf, int event);
+
+
+#endif /* BSE_DRAWIPO_H */
+
diff --git a/source/blender/include/BSE_drawnla.h b/source/blender/include/BSE_drawnla.h
new file mode 100644
index 00000000000..923d9a3f0df
--- /dev/null
+++ b/source/blender/include/BSE_drawnla.h
@@ -0,0 +1,52 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BSE_DRAWNLA_H
+#define BSE_DRAWNLA_H
+
+struct ScrArea;
+struct Base;
+struct gla2DDrawInfo;
+struct Object;
+
+void drawnlaspace(struct ScrArea *sa, void *spacedata);
+void do_nlabuts(unsigned short event);
+
+int count_nla_levels(void);
+int nla_filter (struct Base* base);
+
+ /* changes the gla2d system to map the strip transform */
+void map_active_strip(struct gla2DDrawInfo *di, struct Object *ob, int restore);
+
+
+#endif /* BSE_DRAWNLA */
+
diff --git a/source/blender/include/BSE_drawoops.h b/source/blender/include/BSE_drawoops.h
new file mode 100644
index 00000000000..43e1dee5943
--- /dev/null
+++ b/source/blender/include/BSE_drawoops.h
@@ -0,0 +1,50 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BSE_DRAWOOPS_H
+#define BSE_DRAWOOPS_H
+
+struct ScrArea;
+struct Oops;
+
+void boundbox_oops(short sel);
+void give_oopslink_line(struct Oops *oops, struct OopsLink *ol, float *v1, float *v2);
+void draw_oopslink(struct Oops *oops);
+void draw_icon_oops(float *co, short type);
+void mysbox(float x1, float y1, float x2, float y2);
+unsigned int give_oops_color(short type, short sel, unsigned int *border);
+void calc_oopstext(char *str, float *v1);
+void draw_oops(struct Oops *oops);
+void drawoopsspace(struct ScrArea *sa, void *spacedata);
+
+#endif /* BSE_DRAWOOPS */
+
diff --git a/source/blender/include/BSE_drawview.h b/source/blender/include/BSE_drawview.h
new file mode 100644
index 00000000000..9c577746da9
--- /dev/null
+++ b/source/blender/include/BSE_drawview.h
@@ -0,0 +1,88 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BSE_DRAWVIEW_H
+#define BSE_DRAWVIEW_H
+
+struct Object;
+struct BGpic;
+struct rctf;
+struct ScrArea;
+struct ImBuf;
+
+void default_gl_light(void);
+void init_gl_stuff(void);
+void circf(float x, float y, float rad);
+void circ(float x, float y, float rad);
+
+void do_viewbuts(unsigned short event);
+
+/* View3DAfter->type */
+#define V3D_XRAY 1
+#define V3D_TRANSP 2
+void add_view3d_after(struct View3D *v3d, struct Base *base, int type);
+
+void backdrawview3d(int test);
+void check_backbuf(void);
+unsigned int sample_backbuf(int x, int y);
+struct ImBuf *read_backbuf(short xmin, short ymin, short xmax, short ymax);
+unsigned int sample_backbuf_rect(short mval[2], int size, unsigned int min, unsigned int max, int *dist, short strict, unsigned int (*indextest)(unsigned int index));
+
+void drawview3dspace(struct ScrArea *sa, void *spacedata);
+void drawview3d_render(struct View3D *v3d, int winx, int winy);
+
+int update_time(void);
+void calc_viewborder(struct View3D *v3d, struct rctf *viewborder_r);
+void view3d_set_1_to_1_viewborder(struct View3D *v3d);
+
+int view3d_test_clipping(struct View3D *v3d, float *vec);
+void view3d_set_clipping(struct View3D *v3d);
+void view3d_clr_clipping(void);
+
+void sumo_callback(void *obp);
+void init_anim_sumo(void);
+void update_anim_sumo(void);
+void end_anim_sumo(void);
+
+void inner_play_anim_loop(int init, int mode);
+int play_anim(int mode);
+
+void make_axis_color(char *col, char *col2, char axis);
+
+/* SMOOTHVIEW */
+void smooth_view(struct View3D *v3d, float *ofs, float *quat, float *dist, float *lens);
+void smooth_view_to_camera(struct View3D *v3d);
+void view_settings_from_ob(struct Object *ob, float *ofs, float *quat, float *dist, float *lens);
+void object_view_settings(struct Object *ob, float *lens, float *clipsta, float *clipend);
+
+#endif /* BSE_DRAWVIEW_H */
+
diff --git a/source/blender/include/BSE_edit.h b/source/blender/include/BSE_edit.h
new file mode 100644
index 00000000000..048d4d012b2
--- /dev/null
+++ b/source/blender/include/BSE_edit.h
@@ -0,0 +1,55 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BSE_EDIT_H
+#define BSE_EDIT_H
+
+struct Object;
+struct rcti;
+
+int get_border(struct rcti *rect, short col);
+void countall(void);
+void snapmenu(void);
+void mergemenu(void);
+void delete_context_selected(void);
+void duplicate_context_selected(void);
+void toggle_shading(void);
+int minmax_verts(float *min, float *max);
+
+void snap_sel_to_grid(void);
+void snap_sel_to_curs(void);
+void snap_curs_to_grid(void);
+void snap_curs_to_sel(void);
+void snap_to_center(void);
+
+#endif /* BSE_EDIT_H */
+
diff --git a/source/blender/include/BSE_editaction_types.h b/source/blender/include/BSE_editaction_types.h
new file mode 100644
index 00000000000..48f0bc39ffc
--- /dev/null
+++ b/source/blender/include/BSE_editaction_types.h
@@ -0,0 +1,77 @@
+/**
+ * $Id: BIF_editaction.h 10519 2007-04-13 11:15:08Z aligorith $
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): 2007, Joshua Leung (major Action Editor recode)
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BIF_EDITACTION_TYPES_H
+#define BIF_EDITACTION_TYPES_H
+
+/******************************************************* */
+/* FILTERED ACTION DATA - TYPES */
+
+/* types of keyframe data in ActListElem */
+#define ALE_NONE 0
+#define ALE_IPO 1
+#define ALE_ICU 2
+
+/* This struct defines a structure used for quick access */
+typedef struct bActListElem {
+ struct bActListElem *next, *prev;
+
+ void *data; /* source data this elem represents */
+ int type; /* one of the ACTTYPE_* values */
+ int flag; /* copy of elem's flags for quick access */
+ int index; /* copy of adrcode where applicable */
+
+ void *key_data; /* motion data - ipo or ipo-curve */
+ short datatype; /* type of motion data to expect */
+
+ void *owner; /* will either be an action channel or fake ipo-channel (for keys) */
+ short ownertype; /* type of owner */
+} bActListElem;
+
+/******************************************************* */
+/* FILTER ACTION DATA - METHODS/TYPES */
+
+/* filtering flags - under what circumstances should a channel be added */
+#define ACTFILTER_VISIBLE 0x001 /* should channels be visible */
+#define ACTFILTER_SEL 0x002 /* should channels be selected */
+#define ACTFILTER_FOREDIT 0x004 /* does editable status matter */
+#define ACTFILTER_CHANNELS 0x008 /* do we only care that it is a channel */
+#define ACTFILTER_IPOKEYS 0x010 /* only channels referencing ipo's */
+#define ACTFILTER_ONLYICU 0x020 /* only reference ipo-curves */
+#define ACTFILTER_FORDRAWING 0x040 /* make list for interface drawing */
+
+/* Action Editor - Main Data types */
+#define ACTCONT_NONE 0
+#define ACTCONT_ACTION 1
+#define ACTCONT_SHAPEKEY 2
+
+#endif
diff --git a/source/blender/include/BSE_editipo.h b/source/blender/include/BSE_editipo.h
new file mode 100644
index 00000000000..37cae858656
--- /dev/null
+++ b/source/blender/include/BSE_editipo.h
@@ -0,0 +1,178 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BSE_EDITIPO_H
+#define BSE_EDITIPO_H
+
+struct TransVert;
+struct IpoCurve;
+struct BezTriple;
+struct Ipo;
+struct EditIpo;
+struct ID;
+struct ListBase;
+struct Object;
+struct IpoKey;
+struct TransOb;
+struct Tex;
+struct TransInfo;
+
+void remake_object_ipos(struct Object *ob);
+char *getname_ac_ei(int nr);
+char *getname_co_ei(int nr);
+char *getname_ob_ei(int nr, int colipo);
+char *getname_mtex_ei(int nr);
+char *getname_tex_ei(int nr);
+char *getname_mat_ei(int nr);
+char *getname_world_ei(int nr);
+char *getname_seq_ei(int nr);
+char *getname_cu_ei(int nr);
+char *getname_la_ei(int nr);
+char *getname_cam_ei(int nr);
+char *getname_snd_ei(int nr);
+char *getname_fluidsim_ei(int nr);
+
+char *getname_ipocurve(struct IpoCurve *icu, struct Object *ob);
+int geticon_ipo_blocktype(short blocktype);
+
+struct EditIpo *get_active_editipo(void);
+
+void boundbox_ipocurve(struct IpoCurve *icu, int selectedonly);
+void boundbox_ipo(struct Ipo *ipo, struct rctf *bb, int selectedonly);
+void editipo_changed(struct SpaceIpo *si, int doredraw);
+void scale_editipo(void);
+
+unsigned int ipo_rainbow(int cur, int tot);
+
+void test_editipo(int doit);
+void get_status_editipo(void);
+void update_editipo_flags(void);
+void set_editflag_editipo(void);
+void ipo_toggle_showkey(void);
+void swap_selectall_editipo(void);
+void swap_visible_editipo(void);
+void deselectall_editipo(void);
+
+void move_to_frame(void);
+void do_ipowin_buts(short event);
+void do_ipo_selectbuttons(void);
+
+
+/* gets ipo curve, creates if needed */
+struct IpoCurve *verify_ipocurve(struct ID *, short, char *, char *, int);
+struct Ipo *verify_ipo(struct ID *, short, char *, char *);
+int texchannel_to_adrcode(int channel);
+
+int insert_bezt_icu(struct IpoCurve *icu, struct BezTriple *bezt);
+void insert_vert_icu(struct IpoCurve *icu, float x, float y, short fast);
+void add_vert_ipo(void);
+
+void add_duplicate_editipo(void);
+void remove_doubles_ipo(void);
+void clean_ipo(void);
+void clean_ipo_curve(struct IpoCurve *icu);
+void smooth_ipo(void);
+void join_ipo_menu(void);
+void join_ipo(int mode);
+void ipo_snap_menu(void);
+void ipo_snap(short event);
+void ipo_mirror_menu(void);
+void ipo_mirror(short event);
+void mouse_select_ipo(void);
+void sethandles_ipo(int code);
+void select_ipo_bezier_keys(struct Ipo *ipo, int selectmode);
+void select_icu_bezier_keys(struct IpoCurve *icu, int selectmode);
+void set_ipotype(void);
+void borderselect_ipo(void);
+void del_ipo(int need_check);
+void del_ipoCurve ( struct IpoCurve * icu );
+void free_ipocopybuf(void);
+void copy_editipo(void);
+void paste_editipo(void);
+
+void set_exprap_ipo(int mode);
+
+void set_speed_editipo(float speed);
+void insertkey(ID *id, int blocktype, char *actname, char *constname, int adrcode, short fast);
+void insertkey_smarter(ID *id, int blocktype, char *actname, char *constname, int adrcode);
+void insertkey_editipo(void);
+void common_insertkey(void);
+void free_ipokey(struct ListBase *lb);
+void add_to_ipokey(struct ListBase *lb, struct BezTriple *bezt, int nr, int len);
+void make_ipokey(void);
+void make_ipokey_spec(struct ListBase *lb, struct Ipo *ipo);
+void make_ipokey_transform(struct Object *ob, struct ListBase *lb, int sel);
+void update_ipokey_val(void);
+void set_tob_old(float *old, float *poin);
+void set_ipo_pointers_transob(struct IpoKey *ik, struct TransOb *tob);
+void nextkey(struct ListBase *elems, int dir);
+void movekey_ipo(int dir);
+void movekey_obipo(int dir);
+void nextkey_ipo(int dir);
+void nextkey_obipo(int dir);
+void filter_sampledata(float *data, int sfra, int efra);
+void sampledata_to_ipocurve(float *data, int sfra, int efra, struct IpoCurve *icu);
+void ipo_record(void);
+
+void make_ipo_transdata(struct TransInfo *t);
+void remake_ipo_transdata(struct TransInfo *t);
+void transform_ipo(int mode);
+
+void actstrip_map_ipo_keys(struct Object *ob, struct Ipo *ipo, short restore, short only_keys);
+
+void sethandles_ipo_keys(struct Ipo *ipo, int code);
+void snap_ipo_keys(struct Ipo *ipo, short snaptype);
+void mirror_ipo_keys(struct Ipo *ipo, short mirror_mode);
+void setipotype_ipo(struct Ipo *ipo, int code);
+void set_ipo_key_selection(struct Ipo *ipo, int sel);
+int is_ipo_key_selected(struct Ipo *ipo);
+void delete_icu_key(struct IpoCurve *icu, int index);
+void delete_ipo_keys(struct Ipo *ipo);
+int fullselect_ipo_keys(struct Ipo *ipo);
+int add_trans_ipo_keys(struct Ipo *ipo, struct TransVert *tv, int tvtot);
+void duplicate_ipo_keys(struct Ipo *ipo);
+void borderselect_ipo_key(struct Ipo *ipo, float xmin, float xmax, int val);
+void borderselect_icu_key(struct IpoCurve *icu, float xmin, float xmax,
+ int (*select_function)(struct BezTriple *));
+int insertmatrixkey(ID *id, int blocktype, char *actname, char *constname, int adrcode);
+void insertfloatkey(ID *id, int blocktype, char *actname, char *constname, int adrcode, float floatkey);
+void select_ipo_key(struct Ipo *ipo, float selx, int sel);
+void select_icu_key(struct IpoCurve *icu, float selx, int selectmode);
+void setexprap_ipoloop(struct Ipo *ipo, int code);
+
+/* callbacks */
+int select_bezier_add(struct BezTriple *bezt);
+int select_bezier_subtract(struct BezTriple *bezt);
+int select_bezier_invert(struct BezTriple *bezt);
+
+#endif /* BSE_EDITIPO_H */
+
diff --git a/source/blender/include/BSE_editipo_types.h b/source/blender/include/BSE_editipo_types.h
new file mode 100644
index 00000000000..5076b36083a
--- /dev/null
+++ b/source/blender/include/BSE_editipo_types.h
@@ -0,0 +1,53 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BSE_EDITIPO_TYPES_H
+#define BSE_EDITIPO_TYPES_H
+
+struct BezTriple;
+
+typedef struct IpoKey {
+ struct IpoKey *next, *prev;
+ short flag, rt;
+ float val;
+ struct BezTriple **data;
+} IpoKey;
+
+typedef struct EditIpo {
+ char name[32]; // same length as keyblock->name
+ IpoCurve *icu;
+ short adrcode, flag;
+ short disptype, rt;
+ unsigned int col;
+} EditIpo;
+
+#endif /* BSE_EDITIPO_TYPES_H */
diff --git a/source/blender/include/BSE_editnla_types.h b/source/blender/include/BSE_editnla_types.h
new file mode 100644
index 00000000000..434e87fbbc4
--- /dev/null
+++ b/source/blender/include/BSE_editnla_types.h
@@ -0,0 +1,41 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BSE_EDITNLA_TYPES_H
+#define BSE_EDITNLA_TYPES_H
+
+#define NLAWIDTH 196
+#define NLACHANNELHEIGHT 16
+#define NLACHANNELSKIP 1
+
+#endif /* BSE_EDITNLA_TYPES_H */
+
diff --git a/source/blender/include/BSE_filesel.h b/source/blender/include/BSE_filesel.h
new file mode 100644
index 00000000000..a41eea32040
--- /dev/null
+++ b/source/blender/include/BSE_filesel.h
@@ -0,0 +1,66 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ *
+ */
+
+#ifndef BSE_FILESEL_H
+#define BSE_FILESEL_H
+
+struct SpaceFile;
+struct direntry;
+struct ID;
+struct ScrArea;
+struct BWinEvent;
+
+void filesel_statistics(struct SpaceFile *sfile, int *totfile, int *selfile, float *totlen, float *sellen);
+void test_flags_file(struct SpaceFile *sfile);
+void sort_filelist(struct SpaceFile *sfile);
+void read_dir(struct SpaceFile *sfile);
+void freefilelist(struct SpaceFile *sfile);
+void parent(struct SpaceFile *sfile);
+void swapselect_file(struct SpaceFile *sfile);
+void drawfilespace(struct ScrArea *sa, void *spacedata);
+
+void activate_fileselect(int type, char *title, char *file, void (*func)(char *));
+void activate_fileselect_menu(int type, char *title, char *file, char *pupmenu, short *menup, void (*func)(char *));
+void activate_fileselect_args(int type, char *title, char *file, void (*func)(char *, void *, void *), void *arg1, void *arg2);
+
+void activate_databrowse(struct ID *id, int idcode, int fromcode, int retval, short *menup, void (*func)(unsigned short));
+void activate_databrowse_args(struct ID *id, int idcode, int fromcode, short *menup, void (*func)(char *, void *, void *), void *arg1, void *arg2);
+
+void filesel_prevspace(void);
+void free_filesel_spec(char *dir);
+void winqreadfilespace(struct ScrArea *sa, void *spacedata, struct BWinEvent *evt);
+void main_to_filelist(struct SpaceFile *sfile);
+
+void clever_numbuts_filesel(void);
+#endif
+
diff --git a/source/blender/include/BSE_headerbuttons.h b/source/blender/include/BSE_headerbuttons.h
new file mode 100644
index 00000000000..112517dbe7f
--- /dev/null
+++ b/source/blender/include/BSE_headerbuttons.h
@@ -0,0 +1,158 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BSE_HEADERBUTTONS_H
+#define BSE_HEADERBUTTONS_H
+
+struct uiBlock;
+struct ScrArea;
+struct ID;
+struct SpaceIpo;
+struct Ipo;
+
+/* these used to be in blender/src/headerbuttons.c: */
+#define XIC 20
+#define YIC 20
+
+int std_libbuttons(struct uiBlock *block,
+ short xco, short yco, int pin, short *pinpoin,
+ int browse, short id_code, short special, struct ID *id, struct ID *parid,
+ short *menupoin, int users,
+ int lib, int del, int autobut, int keepbut);
+
+char *windowtype_pup(void);
+
+int GetButStringLength(char *str);
+void load_space_sound(char *str);
+void load_sound_buttons(char *str);
+/* end of declarations moved from old headerbuttons.c */
+
+void update_for_newframe_muted(void);
+void update_for_newframe_nodraw(int nosound);
+void free_matcopybuf(void);
+void clear_matcopybuf(void);
+void write_vrml_fs(void);
+void write_dxf_fs(void);
+void write_stl_fs(void);
+int buttons_do_unpack(void);
+struct Scene *copy_scene(struct Scene *sce, int level);
+
+void buttons_active_id(struct ID **id, struct ID **idfrom);
+
+int start_progress_bar(void);
+void end_progress_bar(void);
+int progress_bar(float done, char *busy_info);
+
+void update_for_newframe(void);
+
+void action_buttons(void);
+void buts_buttons(void);
+void file_buttons(void);
+void image_buttons(void);
+void imasel_buttons(void);
+void info_buttons(void);
+void ipo_buttons(void);
+void nla_buttons(void);
+void oops_buttons(void);
+void seq_buttons(void);
+void sound_buttons(void);
+void text_buttons(void);
+void script_buttons(void);
+void view3d_buttons(void);
+void time_buttons(struct ScrArea *sa);
+void node_buttons(struct ScrArea *sa);
+
+void do_global_buttons(unsigned short event);
+void do_global_buttons2(short event);
+
+void do_action_buttons(unsigned short event);
+void do_buts_buttons(short event);
+void do_file_buttons(short event);
+void do_image_buttons(unsigned short event);
+void do_imasel_buttons(short event);
+void do_info_buttons(unsigned short event);
+void do_ipo_buttons(short event);
+void do_layer_buttons(short event);
+void do_nla_buttons(unsigned short event);
+void do_oops_buttons(short event);
+void do_seq_buttons(short event);
+void do_sound_buttons(unsigned short event);
+void do_text_buttons(unsigned short event);
+void do_script_buttons(unsigned short event);
+void do_view3d_buttons(short event);
+void do_time_buttons(struct ScrArea *sa, unsigned short event);
+void do_node_buttons(struct ScrArea *sa, unsigned short event);
+
+void do_headerbuttons(short event);
+
+/* header_ipo.c */
+void spaceipo_assign_ipo(struct SpaceIpo *si, struct Ipo *ipo);
+
+/* header_text.c */
+void do_text_editmenu_to3dmenu(void *arg, int event);
+void do_text_formatmenu_convert(void *arg, int event);
+
+/* header_info.c */
+void do_info_add_meshmenu(void *arg, int event);
+void do_info_add_curvemenu(void *arg, int event);
+void do_info_add_surfacemenu(void *arg, int event);
+void do_info_add_metamenu(void *arg, int event);
+void do_info_add_lampmenu(void *arg, int event);
+void do_info_addmenu(void *arg, int event);
+
+/* header_node.c */
+void do_node_addmenu(void *arg, int event);
+
+/* header_view3d.c */
+void do_view3d_select_objectmenu(void *arg, int event);
+void do_view3d_select_object_groupedmenu(void *arg, int event);
+void do_view3d_select_object_linkedmenu(void *arg, int event);
+void do_view3d_select_object_layermenu(void *arg, int event);
+void do_view3d_select_object_typemenu(void *arg, int event);
+void do_view3d_select_faceselmenu(void *arg, int event);
+void do_view3d_select_meshmenu(void *arg, int event);
+void do_view3d_select_curvemenu(void *arg, int event);
+void do_view3d_select_metaballmenu(void *arg, int event);
+void do_view3d_edit_snapmenu(void *arg, int event);
+void do_view3d_edit_mirrormenu(void *arg, int event);
+void do_view3d_transform_moveaxismenu(void *arg, int event);
+void do_view3d_transform_rotateaxismenu(void *arg, int event);
+void do_view3d_transform_scaleaxismenu(void *arg, int event);
+void do_view3d_object_mirrormenu(void *arg, int event);
+void do_view3d_edit_mesh_normalsmenu(void *arg, int event);
+void do_view3d_edit_mesh_verticesmenu(void *arg, int event);
+void do_view3d_edit_mesh_edgesmenu(void *arg, int event);
+void do_view3d_edit_mesh_facesmenu(void *arg, int event);
+void do_view3d_edit_curve_segmentsmenu(void *arg, int event);
+void do_view3d_edit_curve_showhidemenu(void *arg, int event);
+
+#endif /* BSE_HEADERBUTTONS_H */
diff --git a/source/blender/include/BSE_node.h b/source/blender/include/BSE_node.h
new file mode 100644
index 00000000000..171a277e8e6
--- /dev/null
+++ b/source/blender/include/BSE_node.h
@@ -0,0 +1,137 @@
+/**
+ * $Id:
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your opt ion) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL BLOCK *****
+ */
+
+#ifndef BSE_NODE_H
+#define BSE_NODE_H
+
+/* ********** drawing sizes *********** */
+#define NODE_DY 20
+#define NODE_DYS 10
+#define NODE_SOCKSIZE 5
+#define BASIS_RAD 8.0f
+#define HIDDEN_RAD 15.0f
+
+
+struct SpaceNode;
+struct bNode;
+struct bNodeTree;
+struct Material;
+struct ID;
+struct Scene;
+struct Image;
+struct ImageUser;
+
+/* ************* API for editnode.c *********** */
+
+ /* helper calls to retreive active context for buttons, does groups */
+struct Material *editnode_get_active_material(struct Material *ma);
+struct bNode *editnode_get_active_idnode(struct bNodeTree *ntree, short id_code);
+struct bNode *editnode_get_active(struct bNodeTree *ntree);
+
+void snode_tag_dirty(struct SpaceNode *snode);
+
+void snode_set_context(struct SpaceNode *snode);
+
+void snode_home(struct ScrArea *sa, struct SpaceNode *snode);
+void snode_zoom_in(struct ScrArea *sa);
+void snode_zoom_out(struct ScrArea *sa);
+
+void node_deselectall(struct SpaceNode *snode, int swap);
+void node_border_select(struct SpaceNode *snode);
+
+void node_delete(struct SpaceNode *snode);
+void node_make_group(struct SpaceNode *snode);
+void node_ungroup(struct SpaceNode *snode);
+void snode_make_group_editable(struct SpaceNode *snode, struct bNode *gnode);
+void node_hide(struct SpaceNode *snode);
+void node_read_renderlayers(struct SpaceNode *snode);
+void clear_scene_in_nodes(struct Scene *sce);
+
+void node_transform_ext(int mode, int unused);
+void node_shader_default(struct Material *ma);
+void node_composit_default(struct Scene *scene);
+
+int node_has_hidden_sockets(struct bNode *node);
+
+struct bNode *node_add_node(struct SpaceNode *snode, int type, float locx, float locy);
+void node_adduplicate(struct SpaceNode *snode);
+
+void snode_autoconnect(struct SpaceNode *snode, struct bNode *node_to, int flag);
+void node_select_linked(struct SpaceNode *snode, int out);
+
+struct ImageUser *ntree_get_active_iuser(struct bNodeTree *ntree);
+
+void imagepaint_composite_tags(struct bNodeTree *ntree, struct Image *image, struct ImageUser *iuser);
+
+
+
+/* ************* drawnode.c *************** */
+struct SpaceNode;
+struct bNodeLink;
+void node_draw_link(struct SpaceNode *snode, struct bNodeLink *link);
+
+void init_node_butfuncs(void);
+
+/* exported to CMP and SHD nodes */
+//void node_ID_title_cb(void *node_v, void *unused_v);
+//void node_but_title_cb(void *node_v, void *but_v);
+//void node_texmap_cb(void *texmap_v, void *unused_v);
+//void node_new_mat_cb(void *ntree_v, void *node_v);
+//void node_browse_mat_cb(void *ntree_v, void *node_v);
+//void node_mat_alone_cb(void *node_v, void *unused);
+
+
+//void node_browse_image_cb(void *ntree_v, void *node_v);
+//void node_active_cb(void *ntree_v, void *node_v);
+//void node_image_type_cb(void *node_v, void *unused);
+//char *node_image_type_pup(void);
+//char *layer_menu(struct RenderResult *rr);
+//void image_layer_cb(void *ima_v, void *iuser_v);
+//void set_render_layers_title(void *node_v, void *unused);
+//char *scene_layer_menu(struct Scene *sce);
+//void node_browse_scene_cb(void *ntree_v, void *node_v);
+
+
+//int node_buts_curvevec(struct uiBlock *block, struct bNodeTree *ntree, struct bNode *node, struct rctf *butr);
+//int node_buts_curvecol(struct uiBlock *block, struct bNodeTree *ntree, struct bNode *node, struct rctf *butr);
+//int node_buts_rgb(struct uiBlock *block, struct bNodeTree *ntree, struct bNode *node, struct rctf *butr);
+//int node_buts_texture(struct uiBlock *block, struct bNodeTree *ntree, struct bNode *node, struct rctf *butr);
+//int node_buts_valtorgb(struct uiBlock *block, struct bNodeTree *ntree, struct bNode *node, struct rctf *butr);
+//int node_buts_value(struct uiBlock *block, struct bNodeTree *ntree, struct bNode *node, struct rctf *butr);
+//int node_buts_mix_rgb(struct uiBlock *block, struct bNodeTree *ntree, struct bNode *node, struct rctf *butr);
+//int node_buts_group(struct uiBlock *block, struct bNodeTree *ntree, struct bNode *node, struct rctf *butr);
+//int node_buts_normal(struct uiBlock *block, struct bNodeTree *ntree, struct bNode *node, struct rctf *butr);
+//int node_buts_math(struct uiBlock *block, struct bNodeTree *ntree, struct bNode *node, struct rctf *butr) ;
+
+
+/* ************* Shader nodes ***************** */
+
+
+#endif
+
diff --git a/source/blender/include/BSE_seqaudio.h b/source/blender/include/BSE_seqaudio.h
new file mode 100644
index 00000000000..985c4be73d2
--- /dev/null
+++ b/source/blender/include/BSE_seqaudio.h
@@ -0,0 +1,53 @@
+/**
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2003 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ *
+ */
+
+#ifndef BSE_SEQAUDIO_H
+#define BSE_SEQAUDIO_H
+
+#include "SDL.h"
+/* muha, we don't init (no SDL_main)! */
+#ifdef main
+# undef main
+#endif
+
+#include "DNA_sound_types.h"
+
+void audio_mixdown();
+void audio_makestream(bSound *sound);
+void audiostream_play(Uint32 startframe, Uint32 duration, int mixdown);
+void audiostream_fill(Uint8* mixdown, int len);
+void audiostream_start(Uint32 frame);
+void audiostream_scrub(Uint32 frame);
+void audiostream_stop(void);
+int audiostream_pos(void);
+
+#endif
+
diff --git a/source/blender/include/BSE_seqeffects.h b/source/blender/include/BSE_seqeffects.h
new file mode 100644
index 00000000000..2962bbf3676
--- /dev/null
+++ b/source/blender/include/BSE_seqeffects.h
@@ -0,0 +1,96 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Peter Schlaile < peter [at] schlaile [dot] de >
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ *
+ */
+
+#ifndef BSE_SEQUENCE_EFFECTS_H
+#define BSE_SEQUENCE_EFFECTS_H
+
+/* Wipe effect */
+enum {DO_SINGLE_WIPE, DO_DOUBLE_WIPE, DO_BOX_WIPE, DO_CROSS_WIPE,
+ DO_IRIS_WIPE,DO_CLOCK_WIPE};
+
+struct Sequence;
+struct ImBuf;
+
+struct SeqEffectHandle {
+ /* constructors & destructor */
+ /* init & init_plugin are _only_ called on first creation */
+ void (*init)(struct Sequence *seq);
+ void (*init_plugin)(struct Sequence * seq, const char * fname);
+
+ /* number of input strips needed
+ (called directly after construction) */
+ int (*num_inputs)();
+
+ /* load is called first time after readblenfile in
+ get_sequence_effect automatically */
+ void (*load)(struct Sequence *seq);
+
+ /* duplicate */
+ void (*copy)(struct Sequence *dst, struct Sequence * src);
+
+ /* destruct */
+ void (*free)(struct Sequence *seq);
+
+ /* returns: -1: no input needed,
+ 0: no early out,
+ 1: out = ibuf1,
+ 2: out = ibuf2 */
+ int (*early_out)(struct Sequence *seq,
+ float facf0, float facf1);
+
+ /* stores the y-range of the effect IPO */
+ void (*store_icu_yrange)(struct Sequence * seq,
+ short adrcode, float * ymin, float * ymax);
+
+ /* stores the default facf0 and facf1 if no IPO is present */
+ void (*get_default_fac)(struct Sequence * seq, int cfra,
+ float * facf0, float * facf1);
+
+ /* execute the effect
+ sequence effects are only required to either support
+ float-rects or byte-rects
+ (mixed cases are handled one layer up...) */
+
+ void (*execute)(struct Sequence *seq, int cfra,
+ float facf0, float facf1,
+ int x, int y,
+ struct ImBuf *ibuf1, struct ImBuf *ibuf2,
+ struct ImBuf *ibuf3, struct ImBuf *out);
+};
+
+struct SeqEffectHandle get_sequence_effect(struct Sequence * seq);
+int get_sequence_effect_num_inputs(int seq_type);
+void sequence_effect_speed_rebuild_map(struct Sequence * seq, int force);
+
+#endif
+
diff --git a/source/blender/include/BSE_seqscopes.h b/source/blender/include/BSE_seqscopes.h
new file mode 100644
index 00000000000..3dd5e495928
--- /dev/null
+++ b/source/blender/include/BSE_seqscopes.h
@@ -0,0 +1,38 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Author: Peter Schlaile < peter [at] schlaile [dot] de >
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+#ifndef BSE_SEQUENCE_SCOPES_H
+#define BSE_SEQUENCE_SCOPES_H
+
+struct ImBuf;
+
+struct ImBuf *make_waveform_view_from_ibuf(struct ImBuf * ibuf);
+struct ImBuf *make_vectorscope_view_from_ibuf(struct ImBuf * ibuf);
+
+#endif
+
diff --git a/source/blender/include/BSE_sequence.h b/source/blender/include/BSE_sequence.h
new file mode 100644
index 00000000000..ff79d417537
--- /dev/null
+++ b/source/blender/include/BSE_sequence.h
@@ -0,0 +1,85 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ *
+ */
+
+#ifndef BSE_SEQUENCE_H
+#define BSE_SEQUENCE_H
+
+
+struct PluginSeq;
+struct StripElem;
+struct Strip;
+struct Sequence;
+struct ListBase;
+struct Editing;
+struct ImBuf;
+struct Scene;
+
+void free_stripdata(int len, struct StripElem *se);
+void free_strip(struct Strip *strip);
+void new_stripdata(struct Sequence *seq);
+void free_sequence(struct Sequence *seq);
+void build_seqar(struct ListBase *seqbase, struct Sequence ***seqar, int *totseq);
+void free_editing(struct Editing *ed);
+void calc_sequence(struct Sequence *seq);
+void calc_sequence_disp(struct Sequence *seq);
+void sort_seq(void);
+void clear_scene_in_allseqs(struct Scene *sce);
+
+int evaluate_seq_frame(int cfra);
+struct StripElem *give_stripelem(struct Sequence *seq, int cfra);
+void set_meta_stripdata(struct Sequence *seqm);
+struct ImBuf *give_ibuf_seq(int rectx, int recty, int cfra, int chansel);
+/* chansel: render this channel. Default=0 (renders end result)*/
+
+/* sequence prefetch API */
+void seq_start_threads();
+void seq_stop_threads();
+void give_ibuf_prefetch_request(int rectx, int recty, int cfra, int chanshown);
+void seq_wait_for_prefetch_ready();
+struct ImBuf * give_ibuf_threaded(int rectx, int recty, int cfra,
+ int chanshown);
+
+
+void free_imbuf_seq_except(int cfra);
+void free_imbuf_seq_with_ipo(struct Ipo * ipo);
+void free_imbuf_seq(void);
+
+void update_changed_seq_and_deps(struct Sequence *seq, int len_change, int ibuf_change);
+
+/* still bad level call... */
+struct RenderResult;
+void do_render_seq(struct RenderResult *rr, int cfra);
+
+
+#endif
+
diff --git a/source/blender/include/BSE_time.h b/source/blender/include/BSE_time.h
new file mode 100644
index 00000000000..d5cff9f5e5f
--- /dev/null
+++ b/source/blender/include/BSE_time.h
@@ -0,0 +1,71 @@
+/**
+ * $Id:
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your opt ion) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BSE_TIME_H
+#define BSE_TIME_H
+
+struct ListBase;
+struct View2D;
+
+/* ******** Markers - General Api ********* */
+void add_marker(int frame);
+void duplicate_marker(void);
+void remove_marker(void);
+void rename_marker(void);
+void transform_markers(int mode, int smode);
+
+void borderselect_markers(void);
+void deselect_markers(short test, short sel);
+struct TimeMarker *find_nearest_marker(int clip_y);
+
+void nextprev_marker(short dir);
+void get_minmax_markers(short sel, float *first, float *last);
+int find_nearest_marker_time(float dx);
+
+void add_marker_to_cfra_elem(struct ListBase *lb, struct TimeMarker *marker, short only_sel);
+void make_marker_cfra_list(struct ListBase *lb, short only_sel);
+
+void draw_markers_timespace(int lines);
+TimeMarker *get_frame_marker(int frame);
+
+/* ******** Animation - Preview Range ************* */
+void anim_previewrange_set(void);
+void anim_previewrange_clear(void);
+
+void draw_anim_preview_timespace(void);
+
+/* *********** TimeLine Specific ***************/
+void timeline_frame_to_center(void);
+void nextprev_timeline_key(short dir);
+
+#endif
+
diff --git a/source/blender/include/BSE_trans_types.h b/source/blender/include/BSE_trans_types.h
new file mode 100644
index 00000000000..9c8b9e5595f
--- /dev/null
+++ b/source/blender/include/BSE_trans_types.h
@@ -0,0 +1,90 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BSE_TRANS_TYPES_H
+#define BSE_TRANS_TYPES_H
+
+struct Object;
+struct MDeformVert;
+struct ColorBand;
+
+typedef struct TransOb {
+ float *loc;
+ float oldloc[9];
+ float *eff;
+ float oldeff[3];
+ float *rot;
+ float oldrot[12];
+ float olddrot[3];
+ float *quat;
+ float oldquat[16];
+ float olddquat[4];
+ float *size;
+ float oldsize[12];
+ float olddsize[3];
+ float obmat[3][3];
+ float obinv[3][3];
+ float parmat[3][3];
+ float parinv[3][3];
+ float obvec[3];
+ int flag; /* keys */
+ float *locx, *locy, *locz;
+ float *rotx, *roty, *rotz;
+ float *quatx, *quaty, *quatz, *quatw;
+ float *sizex, *sizey, *sizez;
+ /* __NLA */
+ float axismat[3][3]; /* Restmat of object (for localspace transforms) */
+ void *data; /* Arbitrary data */
+ /* end __NLA */
+ struct Object *ob;
+} TransOb;
+
+typedef struct TransVert {
+ float *loc;
+ float oldloc[3], fac;
+ float *val, oldval;
+ int flag;
+ float *nor;
+} TransVert;
+
+typedef struct VPaint {
+ float r, g, b, a;
+ float size; /* of brush */
+ float gamma, mul;
+ short mode, flag;
+ int tot, pad; /* allocation size of prev buffers */
+ unsigned int *vpaint_prev; /* previous mesh colors */
+ struct MDeformVert *wpaint_prev; /* previous vertex weights */
+} VPaint;
+
+#endif /* BSE_TRANS_TYPES_H */
+
diff --git a/source/blender/include/BSE_types.h b/source/blender/include/BSE_types.h
new file mode 100644
index 00000000000..591ea2f5168
--- /dev/null
+++ b/source/blender/include/BSE_types.h
@@ -0,0 +1,69 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+/* forward declarations for some prototype header */
+/* these may wildly occur in other header files, too */
+
+struct BGpic;
+struct SpaceText;
+struct Oops;
+struct OopsLink;
+struct uiBlock;
+struct BoundBox;
+struct Image;
+struct ImBuf;
+struct SpaceImaSel;
+struct Sequence;
+struct Scene;
+struct IpoCurve;
+struct Ipo;
+struct IpoKey;
+struct Mesh;
+struct MTFace;
+struct Object;
+struct TransOb;
+struct TransVert;
+struct BPoint;
+struct BezTriple;
+
+struct Nurb;
+
+struct EditFace;
+struct EditVert;
+struct EditEdge;
+struct EditIpo;
+
+struct bArmature;
+struct Bone;
+
+/* interface crap */
+struct uiBut;
+
diff --git a/source/blender/include/BSE_view.h b/source/blender/include/BSE_view.h
new file mode 100644
index 00000000000..4e27f9f1a81
--- /dev/null
+++ b/source/blender/include/BSE_view.h
@@ -0,0 +1,97 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * protos for view.c -- not complete
+ */
+
+#ifndef BSE_VIEW_H
+#define BSE_VIEW_H
+
+struct Object;
+struct BoundBox;
+struct View3D;
+struct ScrArea;
+
+typedef struct ViewDepths {
+ unsigned short w, h;
+ float *depths;
+ double depth_range[2];
+
+ char damaged;
+} ViewDepths;
+
+#define PERSP_WIN 0
+#define PERSP_VIEW 1
+#define PERSP_STORE 2
+
+void persp_general(int a);
+void persp(int a);
+
+/* note, the define below is still used for shorts, to calc distances... */
+#define IS_CLIPPED 12000
+void view3d_get_object_project_mat(struct ScrArea *area, struct Object *ob, float pmat[4][4], float vmat[4][4]);
+void view3d_project_float(struct ScrArea *area, float *vec, float *adr, float mat[4][4]);
+void view3d_project_short_clip(struct ScrArea *area, float *vec, short *adr, float projmat[4][4], float viewmat[4][4]);
+void view3d_project_short_noclip(struct ScrArea *area, float *vec, short *adr, float mat[4][4]);
+
+void initgrabz(float x, float y, float z);
+void window_to_3d(float *vec, short mx, short my);
+void project_short(float *vec, short *adr);
+void project_short_noclip(float *vec, short *adr);
+void project_int(float *vec, int *adr);
+void project_float(float *vec, float *adr);
+
+int boundbox_clip(float obmat[][4], struct BoundBox *bb);
+void fdrawline(float x1, float y1, float x2, float y2);
+void fdrawbox(float x1, float y1, float x2, float y2);
+void sdrawline(short x1, short y1, short x2, short y2);
+void sdrawbox(short x1, short y1, short x2, short y2);
+void calctrackballvecfirst(struct rcti *area, short *mval, float *vec);
+void calctrackballvec(struct rcti *area, short *mval, float *vec);
+void viewmove(int mode);
+void view_zoom_mouseloc(float dfac, short *mouseloc);
+
+int get_view3d_viewplane(int winxi, int winyi, rctf *viewplane, float *clipsta, float *clipend, float *pixsize);
+void setwinmatrixview3d(int winx, int winy, struct rctf *rect);
+
+void obmat_to_viewmat(struct Object *ob, short smooth);
+void setviewmatrixview3d(void);
+float *give_cursor(void);
+unsigned int free_localbit(void);
+void initlocalview(void);
+void centerview(void);
+void restore_localviewdata(struct View3D *vd);
+void endlocalview(struct ScrArea *sa);
+void view3d_home(int center);
+short view3d_opengl_select(unsigned int *buffer, unsigned int buffsize, short x1, short y1, short x2, short y2);
+void view3d_align_axis_to_vector(struct View3D *v3d, int axisidx, float vec[3]);
+
+#endif
+
diff --git a/source/blender/include/LOD_DependKludge.h b/source/blender/include/LOD_DependKludge.h
new file mode 100644
index 00000000000..43034201b81
--- /dev/null
+++ b/source/blender/include/LOD_DependKludge.h
@@ -0,0 +1,40 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * Decimation file dependency fix (and kludge)
+ * Use together with a NAN_DECIMATIONTEST env.var. for Makefile-based linking
+ */
+#ifndef LOD_DEPENDKLUDGE_H
+#define LOD_DEPENDKLUDGE_H
+
+#define NAN_DECIMATION
+
+#endif //LOD_DEPENDKLUDGE_H
+
diff --git a/source/blender/include/blendef.h b/source/blender/include/blendef.h
new file mode 100644
index 00000000000..4c42ba85968
--- /dev/null
+++ b/source/blender/include/blendef.h
@@ -0,0 +1,460 @@
+/* $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BLENDEF_H
+#define BLENDEF_H
+
+
+/* **************** MAX ********************* */
+
+#define MAXFRAME 300000
+#define MAXFRAMEF 300000.0f
+
+#define MINFRAME 1
+#define MINFRAMEF 1.0
+
+/* max length material array, 16 because of bits in matfrom */
+#define MAXPICKBUF 10000
+#define MAXSEQ 32
+
+/* in buttons.c */
+#define MAX_EFFECT 20
+
+#ifndef MAXFLOAT
+#define MAXFLOAT ((float)3.40282347e+38)
+#endif
+
+/* also fill in structs itself, dna cannot handle defines, duplicate with utildefines.h still */
+#ifndef FILE_MAXDIR
+#define FILE_MAXDIR 160
+#define FILE_MAXFILE 80
+#endif
+
+
+#include <float.h>
+
+
+
+
+/* **************** GENERAL ********************* */
+
+// return values
+
+#define RET_OK 0
+#define RET_ERROR 1
+#define RET_CANCEL 2
+#define RET_YES (1 == 1)
+#define RET_NO (1 == 0)
+
+#if defined(__sgi) || defined(__sparc) || defined(__sparc__) || defined (__PPC__) || defined (__ppc__) || defined (__BIG_ENDIAN__)
+/* big endian */
+#define MAKE_ID2(c, d) ( (c)<<8 | (d) )
+#define MOST_SIG_BYTE 0
+#define BBIG_ENDIAN
+#else
+/* little endian */
+#define MAKE_ID2(c, d) ( (d)<<8 | (c) )
+#define MOST_SIG_BYTE 1
+#define BLITTLE_ENDIAN
+#endif
+
+#define SELECT 1
+#define HIDDEN 1
+#define FIRST 1
+#define ACTIVE 2
+/*#ifdef WITH_VERSE*/
+#define VERSE 3
+/*#endif*/
+#define DESELECT 0
+#define NOT_YET 0
+#define VISIBLE 0
+#define LAST 0
+
+#define TESTBASE(base) ( ((base)->flag & SELECT) && ((base)->lay & G.vd->lay) && (((base)->object->restrictflag & OB_RESTRICT_VIEW)==0) )
+#define TESTBASELIB(base) ( ((base)->flag & SELECT) && ((base)->lay & G.vd->lay) && ((base)->object->id.lib==0) && (((base)->object->restrictflag & OB_RESTRICT_VIEW)==0))
+#define BASE_SELECTABLE(base) ((base->lay & G.vd->lay) && (base->object->restrictflag & (OB_RESTRICT_SELECT|OB_RESTRICT_VIEW))==0)
+#define FIRSTBASE G.scene->base.first
+#define LASTBASE G.scene->base.last
+#define BASACT (G.scene->basact)
+#define OBACT (BASACT? BASACT->object: 0)
+#define ID_NEW(a) if( (a) && (a)->id.newid ) (a)= (void *)(a)->id.newid
+#define ID_NEW_US(a) if( (a)->id.newid) {(a)= (void *)(a)->id.newid; (a)->id.us++;}
+#define ID_NEW_US2(a) if( ((ID *)a)->newid) {(a)= ((ID *)a)->newid; ((ID *)a)->us++;}
+#define CFRA (G.scene->r.cfra)
+#define F_CFRA ((float)(G.scene->r.cfra))
+#define SFRA (G.scene->r.sfra)
+#define EFRA (G.scene->r.efra)
+#define PSFRA ((G.scene->r.psfra != 0)? (G.scene->r.psfra): (G.scene->r.sfra))
+#define PEFRA ((G.scene->r.psfra != 0)? (G.scene->r.pefra): (G.scene->r.efra))
+#define FRA2TIME(a) ((((double) G.scene->r.frs_sec_base) * (a)) / G.scene->r.frs_sec)
+#define TIME2FRA(a) ((((double) G.scene->r.frs_sec) * (a)) / G.scene->r.frs_sec_base)
+#define FPS (((double) G.scene->r.frs_sec) / G.scene->r.frs_sec_base)
+
+#define ISPOIN(a, b, c) ( (a->b) && (a->c) )
+#define ISPOIN3(a, b, c, d) ( (a->b) && (a->c) && (a->d) )
+#define ISPOIN4(a, b, c, d, e) ( (a->b) && (a->c) && (a->d) && (a->e) )
+
+#define BEZSELECTED(bezt) (((bezt)->f1 & 1) || ((bezt)->f2 & 1) || ((bezt)->f3 & 1))
+
+/* psfont */
+#define FNT_PDRAW 1
+#define FNT_HAEBERLI 2
+
+/* getbutton */
+
+/* do_global_buttons(event) */
+
+// (first event)
+#define B_LOCAL_ALONE 20
+
+
+#define B_ACTLOCAL 24 /* __NLA */
+#define B_ACTALONE 25 /* __NLA */
+#define B_ARMLOCAL 26 /* __NLA */
+#define B_ARMALONE 27 /* __NLA */
+
+#define B_WORLDLOCAL 28
+#define B_WORLDALONE 29
+#define B_LATTLOCAL 30
+#define B_MBALLLOCAL 31
+#define B_CAMERALOCAL 32
+#define B_OBLOCAL 33
+#define B_IPOLOCAL 34
+#define B_LAMPLOCAL 35
+#define B_MATLOCAL 36
+#define B_TEXLOCAL 37
+#define B_MESHLOCAL 38
+#define B_CURVELOCAL 39
+
+#define B_LATTALONE 40
+#define B_MBALLALONE 41
+#define B_CAMERAALONE 42
+#define B_OBALONE 43
+#define B_IPOALONE 44
+#define B_LAMPALONE 45
+#define B_MATALONE 46
+#define B_TEXALONE 47
+#define B_MESHALONE 48
+#define B_CURVEALONE 49
+
+/* EVENT < 50: alones en locals */
+
+#define B_KEEPDATA 60
+#define B_CONSOLETOG 61
+#define B_DRAWINFO 62
+#define B_REDRCURW3D 63
+#define B_FLIPINFOMENU 64
+#define B_FLIPFULLSCREEN 65
+#define B_PLAINMENUS 66
+
+
+#define B_GLRESLIMITCHANGED 69
+#define B_SHOWSPLASH 70
+#define B_RESETAUTOSAVE 71
+#define B_SOUNDTOGGLE 72
+#define B_MIPMAPCHANGED 73
+#define B_CONSTRAINTBROWSE 74 /* __NLA */
+#define B_ACTIONDELETE 75 /* __NLA */
+#define B_ACTIONBROWSE 76 /* __NLA */
+#define B_IMAGEDELETE 77
+#define B_LTEXBROWSE 78
+#define B_MESHBROWSE 79
+#define B_EXTEXBROWSE 80
+#define B_LOADTEMP 81
+#define B_MATDELETE 82
+#define B_TEXDELETE 83
+#define B_IPODELETE 84
+#define B_WORLDDELETE 85
+#define B_WTEXBROWSE 86
+#define B_WORLDBROWSE 87
+#define B_IPOBROWSE 88
+#define B_NEWFRAME 89
+#define B_LAMPBROWSE 90
+#define B_MATBROWSE 91
+#define B_TEXBROWSE 92
+#define B_EDITBROWSE 93
+#define B_AUTOTEXNAME 94
+#define B_AUTOMATNAME 95
+#define B_MATLOCK 96
+#define B_IDNAME 97
+#define B_NEWSPACE 98
+#define B_FULL 99
+#define B_REDR 100
+
+
+/* VIEW3D: 100 */
+#define B_HOME 101
+#define B_LAY 102
+/* watch: codes 102-132 in in use for layers */
+#define B_AUTOKEY 139
+#define B_SCENELOCK 140
+#define B_LOCALVIEW 141
+#define B_U_CAPSLOCK 142
+
+#define B_VIEWBUT 146
+#define B_PERSP 147
+#define B_PROPTOOL 148
+#define B_VIEWRENDER 149
+#define B_STARTGAME 150
+
+#define B_MODESELECT 156
+#define B_AROUND 157
+#define B_SEL_VERT 158
+#define B_SEL_EDGE 159
+#define B_SEL_FACE 160
+#define B_MAN_TRANS 161
+#define B_MAN_ROT 162
+#define B_MAN_SCALE 163
+
+/* IPO: 200 */
+#define B_IPOHOME 201
+#define B_IPOBORDER 202
+#define B_IPOCOPY 203
+#define B_IPOPASTE 204
+#define B_IPOCONT 205
+#define B_IPOEXTRAP 206
+#define B_IPOCYCLIC 207
+#define B_IPOMAIN 208
+#define B_IPOSHOWKEY 209
+#define B_IPOCYCLICX 210
+ /* warn: also used for oops and seq */
+#define B_VIEW2DZOOM 211
+#define B_IPOPIN 212
+#define B_IPO_ACTION_OB 213
+#define B_IPO_ACTION_KEY 214
+#define B_IPOVIEWCENTER 215
+#define B_IPOVIEWALL 216
+
+
+/* OOPS: 250 */
+#define B_OOPSHOME 251
+#define B_OOPSBORDER 252
+#define B_NEWOOPS 253
+#define B_OOPSVIEWSEL 254
+
+/* INFO: 300 */
+/* watch: also in filesel.c and editobject.c */
+#define B_INFOSCR 301
+#define B_INFODELSCR 302
+#define B_INFOSCE 304
+#define B_INFODELSCE 305
+#define B_FILEMENU 306
+#define B_PACKFILE 307
+
+#define B_CONSOLEOUT 308
+#define B_CONSOLENUMLINES 309
+#define B_USERPREF 310
+#define B_LOADUIFONT 311
+#define B_SETLANGUAGE 312
+#define B_SETFONTSIZE 313
+#define B_SETENCODING 314
+#define B_SETTRANSBUTS 315
+#define B_DOLANGUIFONT 316
+#define B_RESTOREFONT 317
+#define B_USETEXTUREFONT 318
+
+#define B_UITHEMECHANGED 320
+#define B_UITHEMECOLORMOD 321
+#define B_UITHEMERESET 322
+#define B_UITHEMEIMPORT 323
+#define B_UITHEMEEXPORT 324
+
+#define B_MEMCACHELIMIT 325
+#define B_WPAINT_RANGE 326
+
+/* Definitions for the fileselect buttons in user prefs */
+#define B_FONTDIRFILESEL 330
+#define B_TEXTUDIRFILESEL 331
+#define B_PLUGTEXDIRFILESEL 332
+#define B_PLUGSEQDIRFILESEL 333
+#define B_RENDERDIRFILESEL 334
+#define B_PYTHONDIRFILESEL 335
+#define B_SOUNDDIRFILESEL 336
+#define B_TEMPDIRFILESEL 337
+/* yafray: for exportdir select */
+#define B_YAFRAYDIRFILESEL 338
+#define B_PYMENUEVAL 339 /* re-eval scripts registration in menus */
+/* END Definitions for the fileselect buttons in user prefs */
+
+/* IMAGE: 350 */
+#define B_SIMAGEHOME 351
+#define B_SIMABROWSE 352
+#define B_SIMAGELOAD 353
+#define B_SIMA_REDR_IMA_3D 354
+#define B_SIMAGETILE 355
+#define B_BE_SQUARE 356
+#define B_TWINANIM 357
+#define B_SIMAGEREPLACE 358
+#define B_CLIP_UV 359
+#define B_SIMAGELOAD1 360
+#define B_SIMAGEREPLACE1 361
+#define B_SIMAGEPAINTTOOL 362
+#define B_SIMAPACKIMA 363
+#define B_SIMAGESAVE 364
+#define B_SIMACLONEBROWSE 365
+#define B_SIMACLONEDELETE 366
+#define B_SIMANOTHING 368
+#define B_SIMACURVES 369
+#define B_SIMARANGE 370
+#define B_SIMA_USE_ALPHA 371
+#define B_SIMA_SHOW_ALPHA 372
+#define B_SIMA_SHOW_ZBUF 373
+#define B_SIMABRUSHBROWSE 374
+#define B_SIMABRUSHDELETE 375
+#define B_SIMABRUSHLOCAL 376
+#define B_SIMABRUSHCHANGE 377
+#define B_SIMABTEXBROWSE 378
+#define B_SIMABTEXDELETE 379
+#define B_SIMARELOAD 380
+#define B_SIMANAME 381
+#define B_SIMAMULTI 382
+#define B_TRANS_IMAGE 383
+#define B_CURSOR_IMAGE 384
+#define B_SIMA_REPACK 385
+#define B_SIMA_PLAY 386
+#define B_SIMA_RECORD 387
+#define B_SIMAPIN 388
+#define B_SIMA3DVIEWDRAW 389
+
+
+/* BUTS: 400 */
+#define B_BUTSHOME 401
+#define B_BUTSPREVIEW 402
+#define B_MATCOPY 403
+#define B_MATPASTE 404
+#define B_MESHTYPE 405
+#define B_CONTEXT_SWITCH 406
+
+/* IMASEL: 450 */
+/* in imasel.h - not any more - elubie */
+#define B_SORTIMASELLIST 451
+#define B_RELOADIMASELDIR 452
+#define B_FILTERIMASELDIR 453
+
+/* TEXT: 500 */
+#define B_TEXTBROWSE 501
+#define B_TEXTALONE 502
+#define B_TEXTLOCAL 503
+#define B_TEXTDELETE 504
+#define B_TEXTFONT 505
+#define B_TEXTSTORE 506
+#define B_TEXTLINENUM 507
+#define B_TAB_NUMBERS 508
+#define B_SYNTAX 509
+
+/* SCRIPT: 525 */
+#define B_SCRIPTBROWSE 526
+#define B_SCRIPT2PREV 527
+
+/* FILE: 550 */
+#define B_SORTFILELIST 551
+#define B_RELOADDIR 552
+
+/* SEQUENCE: 600 */
+#define B_SEQHOME 601
+#define B_SEQCLEAR 602
+
+/* SOUND: 650 */
+#define B_SOUNDBROWSE 651
+#define B_SOUNDBROWSE2 652
+#define B_SOUNDHOME 653
+#define B_PACKSOUND 654
+
+/* ACTION: 701 - 750 */
+#define B_ACTHOME 701
+#define B_ACTCOPY 702
+#define B_ACTPASTE 703
+#define B_ACTPASTEFLIP 704
+#define B_ACTCYCLIC 705
+#define B_ACTCONT 706
+#define B_ACTMAIN 707
+#define B_ACTPIN 708
+#define B_ACTBAKE 709
+#define B_ACTCOPYKEYS 710
+#define B_ACTPASTEKEYS 711
+
+/* TIME: 751 - 800 */
+#define B_TL_REW 751
+#define B_TL_PLAY 752
+#define B_TL_FF 753
+#define B_TL_PREVKEY 754
+#define B_TL_NEXTKEY 755
+#define B_TL_STOP 756
+#define B_TL_PREVIEWON 757
+
+/* NLA: 801-850 */
+#define B_NLAHOME 801
+
+/* NODE: 851-900 */
+#define B_NODEHOME 851
+#define B_NODE_USEMAT 852
+#define B_NODE_USESCENE 853
+
+/* FREE 901 - 999 */
+
+
+#define B_NOP -1
+
+
+/* editbutflag */
+#define B_CLOCKWISE 1
+#define B_KEEPORIG 2
+#define B_BEAUTY 4
+#define B_SMOOTH 8
+#define B_BEAUTY_SHORT 16
+#define B_AUTOFGON 32
+#define B_KNIFE 0x80
+#define B_PERCENTSUBD 0x40
+#define B_MESH_X_MIRROR 0x100
+#define B_JOINTRIA_UV 0x200
+#define B_JOINTRIA_VCOL 0X400
+#define B_JOINTRIA_SHARP 0X800
+#define B_JOINTRIA_MAT 0X1000
+
+/* DISPLAYMODE */
+#define R_DISPLAYIMAGE 0
+#define R_DISPLAYWIN 1
+#define R_DISPLAYSCREEN 2
+
+/* Gvp.flag and Gwp.flag */
+#define VP_COLINDEX 1
+#define VP_AREA 2
+#define VP_SOFT 4
+#define VP_NORMALS 8
+#define VP_SPRAY 16
+#define VP_MIRROR_X 32
+#define VP_HARD 64
+#define VP_ONLYVGROUP 128
+
+/* Error messages */
+#define ERROR_LIBDATA_MESSAGE "Can't edit external libdata"
+
+
+#endif
diff --git a/source/blender/include/butspace.h b/source/blender/include/butspace.h
new file mode 100644
index 00000000000..fec85c03b77
--- /dev/null
+++ b/source/blender/include/butspace.h
@@ -0,0 +1,723 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef BUTSPACE_H
+#define BUTSPACE_H
+
+/* all internal calls and event codes for buttons space */
+
+struct Base;
+struct Object;
+struct ID;
+struct ColorBand;
+struct uiBlock;
+struct rctf;
+struct CurveMap;
+struct ImageUser;
+struct RenderResult;
+struct Image;
+
+/* buts->scaflag */
+#define BUTS_SENS_SEL 1
+#define BUTS_SENS_ACT 2
+#define BUTS_SENS_LINK 4
+#define BUTS_CONT_SEL 8
+#define BUTS_CONT_ACT 16
+#define BUTS_CONT_LINK 32
+#define BUTS_ACT_SEL 64
+#define BUTS_ACT_ACT 128
+#define BUTS_ACT_LINK 256
+
+/* internal */
+
+/* scene */
+extern void render_panels(void);
+extern void do_render_panels(unsigned short event);
+extern void anim_panels(void);
+extern void sound_panels(void);
+extern void do_soundbuts(unsigned short event);
+
+/* object */
+extern void object_panels(void);
+extern void physics_panels(void);
+extern void do_object_panels(unsigned short event);
+extern void do_constraintbuts(unsigned short event);
+extern void object_panel_constraint(char *context);
+extern void autocomplete_bone(char *str, void *arg_v);
+extern void autocomplete_vgroup(char *str, void *arg_v);
+
+/* effects */
+extern void effects_panels(void);
+extern void do_effects_panels(unsigned short event);
+
+/* modifiers */
+extern int mod_moveUp(void *ob_v, void *md_v);
+extern int mod_moveDown(void *ob_v, void *md_v);
+
+/* constraint */
+extern void const_moveUp(void *ob_v, void *con_v);
+extern void const_moveDown(void *ob_v, void *con_v);
+extern void del_constr_func (void *ob_v, void *con_v);
+extern void get_constraint_ipo_context(void *ob_v, char *actname);
+
+/* editing */
+extern void editing_panels(void);
+extern void do_common_editbuts(unsigned short event);
+extern void do_meshbuts(unsigned short event);
+extern void do_vgroupbuts(unsigned short event);
+extern void do_curvebuts(unsigned short event);
+extern void do_fontbuts(unsigned short event);
+extern void do_mballbuts(unsigned short event);
+extern void do_latticebuts(unsigned short event);
+extern void do_fpaintbuts(unsigned short event);
+extern void do_cambuts(unsigned short event);
+extern void do_armbuts(unsigned short event);
+extern void do_uvcalculationbuts(unsigned short event);
+extern void weight_paint_buttons(struct uiBlock *);
+
+extern char *get_vertexgroup_menustr(struct Object *ob); // used in object buttons
+
+/* shading */
+extern void draw_colorband_buts_small(struct uiBlock *block, struct ColorBand *coba, rctf *rct, int event);
+extern void material_panels(void);
+extern void do_matbuts(unsigned short event);
+extern void lamp_panels(void);
+extern void do_lampbuts(unsigned short event);
+extern void world_panels(void);
+extern void do_worldbuts(unsigned short event);
+extern void radio_panels(void);
+extern void do_radiobuts(unsigned short event);
+extern void texture_panels(void);
+extern void do_texbuts(unsigned short event);
+void uiblock_image_panel(struct uiBlock *block, struct Image **ima_pp, struct ImageUser *iuser,
+ short redraw, short imagechanged);
+void uiblock_layer_pass_buttons(struct uiBlock *block, struct RenderResult *rr,
+ struct ImageUser *iuser, int event, int x, int y, int w);
+
+/* logic */
+extern void do_logic_buts(unsigned short event);
+extern void logic_buts(void);
+
+/* script */
+extern void script_panels(void);
+extern void do_scriptbuts(unsigned short event);
+
+/* ipowindow */
+extern void do_ipobuts(unsigned short event); // drawipo.c (bad! ton)
+
+/* butspace.c */
+void test_meshpoin_but(char *name, struct ID **idpp);
+void test_obpoin_but(char *name, struct ID **idpp);
+void test_meshobpoin_but(char *name, struct ID **idpp);
+void test_scenepoin_but(char *name, struct ID **idpp);
+void test_matpoin_but(char *name, struct ID **idpp);
+void test_scriptpoin_but(char *name, struct ID **idpp);
+void test_actionpoin_but(char *name, ID **idpp);
+void test_grouppoin_but(char *name, ID **idpp);
+void test_texpoin_but(char *name, ID **idpp);
+void test_imapoin_but(char *name, ID **idpp);
+
+void test_idbutton_cb(void *namev, void *arg2_unused);
+
+struct CurveMapping;
+void curvemap_buttons(struct uiBlock *block, struct CurveMapping *cumap, char labeltype, short event, short redraw, struct rctf *rect);
+
+/* -------------- internal event defines ------------ */
+
+
+#define B_DIFF 1
+
+/* *********************** */
+#define B_VIEWBUTS 1100
+
+#define B_OBJECTPANELROT 1007
+#define B_OBJECTPANELMEDIAN 1008
+#define B_ARMATUREPANEL1 1009
+#define B_ARMATUREPANEL2 1010
+#define B_OBJECTPANELPARENT 1011
+#define B_OBJECTPANEL 1012
+#define B_ARMATUREPANEL3 1013
+#define B_OBJECTPANELSCALE 1014
+#define B_OBJECTPANELDIMS 1015
+
+/* *********************** */
+#define B_LAMPBUTS 1200
+
+#define B_LAMPREDRAW 1101
+#define B_COLLAMP 1102
+#define B_TEXCLEARLAMP 1103
+#define B_SBUFF 1104
+#define B_SHADBUF 1105
+#define B_SHADRAY 1106
+#define B_LMTEXPASTE 1107
+#define B_LMTEXCOPY 1108
+#define B_LFALLOFFCHANGED 1109
+
+/* *********************** */
+#define B_MATBUTS 1300
+
+#define B_MATCOL 1201
+#define B_SPECCOL 1202
+#define B_MIRCOL 1203
+#define B_ACTCOL 1204
+#define B_MATFROM 1205
+#define B_MATPRV 1206
+#define B_LAMPPRV 1207
+#define B_WORLDPRV 1208
+#define B_MTEXCOL 1210
+#define B_TEXCLEAR 1211
+#define B_MTEXPASTE 1212
+#define B_MTEXCOPY 1213
+#define B_MATLAY 1214
+#define B_MATHALO 1215
+#define B_MATZTRANSP 1216
+#define B_MATRAYTRANSP 1217
+#define B_MATCOLORBAND 1218
+ /* yafray: material preset menu event */
+#define B_MAT_YF_PRESET 1219
+
+#define B_MAT_LAYERBROWSE 1220
+#define B_MAT_USENODES 1221
+#define B_MAT_VCOL_PAINT 1222
+#define B_MAT_VCOL_LIGHT 1223
+
+ /* world buttons: buttons-preview update, and redraw 3dview */
+#define B_WORLDPRV2 1224
+
+/* *********************** */
+#define B_TEXBUTS 1400
+
+#define B_TEXTYPE 1301
+#define B_DEFTEXVAR 1302
+
+#define B_NAMEIMA 1304
+#define B_TEXCHANNEL 1305
+#define B_TEXREDR_PRV 1306
+#define B_IMAGECHANGED 1307
+
+#define B_LOADPLUGIN 1310
+#define B_NAMEPLUGIN 1311
+#define B_COLORBAND 1312
+#define B_ADDCOLORBAND 1313
+#define B_DELCOLORBAND 1314
+#define B_CALCCBAND 1315
+#define B_CALCCBAND2 1316
+#define B_DOCOLORBAND 1317
+#define B_REDRAWCBAND 1318
+#define B_BANDCOL 1319
+#define B_LOADTEXIMA1 1320
+#define B_TEXPRV 1321
+
+
+#define B_PLUGBUT 1325
+/* B_PLUGBUT reserves 24 buttons at least! */
+
+#define B_ENV_MAKE 1350
+#define B_ENV_FREE 1351
+#define B_ENV_DELETE 1352
+#define B_ENV_SAVE 1353
+#define B_ENV_OB 1354
+
+#define B_ENV_FREE_ALL 1357
+
+
+/* **************** animbuts = object buttons ******* */
+#define B_ANIMBUTS 1500
+
+#define B_RECALCPATH 1401
+#define B_TRACKBUTS 1402
+#define B_DUPLI_FRAME 1403
+#define B_DUPLI_VERTS 1404
+#define B_DUPLI_FACES 1405
+#define B_DUPLI_GROUP 1406
+
+
+#define B_PRINTSPEED 1413
+#define B_PRINTLEN 1414
+#define B_RELKEY 1415
+#define B_CURVECHECK 1416
+
+#define B_SOFTBODY_CHANGE 1420
+#define B_SOFTBODY_DEL_VG 1421
+#define B_SOFTBODY_BAKE 1422
+#define B_SOFTBODY_BAKE_FREE 1423
+
+/* this has MAX_EFFECT settings! Next free define is 1450... */
+#define B_SELEFFECT 1430
+
+/* Fluidsim button defines */
+#define B_FLUIDSIM_BAKE 1450
+#define B_FLUIDSIM_SELDIR 1451
+#define B_FLUIDSIM_FORCEREDRAW 1452
+#define B_FLUIDSIM_MAKEPART 1453
+
+#define B_GROUP_RELINK 1460
+#define B_OBJECT_IPOFLAG 1461
+
+/* *********************** */
+#define B_WORLDBUTS 1600
+
+#define B_TEXCLEARWORLD 1501
+#define B_COLHOR 1502
+#define B_COLZEN 1503
+#define B_WMTEXPASTE 1504
+#define B_WMTEXCOPY 1505
+#define B_AO_FALLOFF 1506
+
+/* *********************** */
+#define B_RENDERBUTS 1700
+
+#define B_FS_PIC 1601
+#define B_FS_BACKBUF 1602
+
+#define B_FS_FTYPE 1604
+#define B_DORENDER 1605
+#define B_DOANIM 1606
+#define B_PLAYANIM 1607
+#define B_PR_PAL 1608
+#define B_PR_FULL 1609
+#define B_PR_PRV 1610
+#define B_PR_HD 1611
+#define B_PR_PAL169 1612
+
+#define B_REDRAWDISP 1615
+#define B_SETBROWSE 1616
+#define B_CLEARSET 1617
+#define B_PR_PRESET 1618
+#define B_PR_PANO 1619
+#define B_PR_NTSC 1620
+
+#define B_IS_FTYPE 1622
+#define B_IS_BACKBUF 1623
+#define B_PR_PC 1624
+
+#define B_PR_PANO360 1627
+#define B_PR_HALFFIELDS 1628
+#define B_NEWRENDERPIPE 1629
+#define B_R_SCALE 1630
+#define B_G_SCALE 1631
+#define B_B_SCALE 1632
+#define B_USE_R_SCALE 1633
+#define B_USE_G_SCALE 1634
+#define B_USE_B_SCALE 1635
+#define B_EDGECOLSLI 1636
+#define B_GAMMASLI 1637
+
+#define B_FILETYPEMENU 1638
+#define B_SELECTCODEC 1639
+#define B_RTCHANGED 1640
+#define B_SWITCHRENDER 1641
+#define B_FBUF_REDO 1642
+
+#define B_SET_EDGE 1643
+#define B_SET_ZBLUR 1644
+#define B_ADD_RENDERLAYER 1645
+#define B_SET_PASS 1646
+
+/* *********************** */
+#define B_ARMATUREBUTS 1800
+#define B_POSE 1701
+
+/* *********************** */
+#define B_COMMONEDITBUTS 2049
+
+#define B_CHANGEDEP 2002
+#define B_MATWICH 2003
+#define B_MATNEW 2004
+#define B_MATDEL 2005
+#define B_MATASS 2006
+#define B_MATSEL 2007
+#define B_MATDESEL 2008
+#define B_HIDE 2009
+#define B_REVEAL 2010
+#define B_SELSWAP 2011
+#define B_SETSMOOTH 2012
+#define B_SETSOLID 2013
+#define B_AUTOTEX 2014
+#define B_DOCENTER 2015
+#define B_DOCENTERNEW 2016
+#define B_DOCENTERCURSOR 2017
+
+ /* 20 values! */
+#define B_OBLAY 2019
+
+#define B_ADDKEY 2041
+#define B_SETKEY 2042
+#define B_DELKEY 2043
+#define B_NAMEKEY 2044
+#define B_PREVKEY 2045
+#define B_NEXTKEY 2046
+#define B_LOCKKEY 2047
+
+#define B_MESHBUTS 2090
+
+#define B_FLIPNORM 2050
+#define B_SPIN 2051
+#define B_SPINDUP 2052
+#define B_EXTR 2053
+#define B_SCREW 2054
+#define B_EXTREP 2055
+#define B_SPLIT 2056
+#define B_REMDOUB 2057
+#define B_SUBDIV 2058
+#define B_FRACSUBDIV 2059
+#define B_XSORT 2060
+#define B_HASH 2061
+#define B_MAKESTICKY 2062
+#define B_DELSTICKY 2063
+#define B_NEWMCOL 2064
+#define B_DELMCOL 2065
+#define B_TOSPHERE 2066
+#define B_DECIM_FACES 2067
+#define B_DECIM_CANCEL 2068
+#define B_DECIM_APPLY 2069
+/* B_SLOWERDRAW and B_FASTERDRAW removed */
+#define B_VERTEXNOISE 2072
+#define B_VERTEXSMOOTH 2073
+#define B_NEWTFACE 2074
+#define B_DELTFACE 2075
+#define B_CHROMADEPTH 2076
+#define B_DRAWEDGES 2077
+#define B_DRAWCREASES 2078
+#define B_SETTFACE 2079
+#define B_SETMCOL 2080
+#define B_JOINTRIA 2081
+#define B_SETTFACE_RND 2082
+#define B_SETMCOL_RND 2083
+
+/* *********************** */
+#define B_VGROUPBUTS 2100
+
+#define B_NEWVGROUP 2091
+#define B_DELVGROUP 2092
+#define B_ASSIGNVGROUP 2093
+#define B_REMOVEVGROUP 2094
+#define B_SELVGROUP 2095
+#define B_DESELVGROUP 2096
+#define B_AUTOVGROUP 2097
+#define B_LINKEDVGROUP 2098
+#define B_COPYVGROUP 2099
+
+
+
+/* *********************** */
+#define B_CURVEBUTS 2200
+
+#define B_CONVERTPOLY 2101
+#define B_CONVERTBEZ 2102
+#define B_CONVERTBSPL 2103
+#define B_CONVERTCARD 2104
+#define B_CONVERTNURB 2105
+#define B_UNIFU 2106
+#define B_ENDPU 2107
+#define B_BEZU 2108
+#define B_UNIFV 2109
+#define B_ENDPV 2110
+#define B_BEZV 2111
+#define B_SETWEIGHT 2112
+#define B_SETW1 2113
+#define B_SETW2 2114
+#define B_SETW3 2115
+#define B_SETORDER 2116
+#define B_MAKEDISP 2117
+#define B_SUBDIVCURVE 2118
+#define B_SPINNURB 2119
+#define B_CU3D 2120
+#define B_SETRESOLU 2121
+#define B_SETW4 2122
+#define B_SUBSURFTYPE 2123
+#define B_TILTINTERP 2124
+
+/* *********************** */
+#define B_FONTBUTS 2300
+
+#define B_MAKEFONT 2201
+#define B_TOUPPER 2202
+#define B_SETFONT 2203
+#define B_LOADFONT 2204
+#define B_TEXTONCURVE 2205
+#define B_PACKFONT 2206
+#define B_LOAD3DTEXT 2207
+#define B_LOREM 2208
+#define B_FASTFONT 2209
+#define B_INSTB 2210
+#define B_DELTB 2211
+#define B_STYLETOSELB 2212
+#define B_STYLETOSELU 2213
+#define B_STYLETOSELI 2214
+
+#define B_SETCHAR 2215
+#define B_SETUPCHAR 2216
+#define B_SETDOWNCHAR 2217
+#define B_SETCAT 2218
+#define B_SETUNITEXT 2219
+
+/* *********************** */
+#define B_ARMBUTS 2400
+
+#define B_ARM_RECALCDATA 2301
+#define B_ARM_STRIDE 2302
+#define B_ARM_CALCPATHS 2303
+#define B_ARM_CLEARPATHS 2304
+
+/* *********************** */
+#define B_CAMBUTS 2500
+
+/* *********************** */
+#define B_MBALLBUTS 2600
+
+#define B_RECALCMBALL 2501
+
+/* *********************** */
+#define B_LATTBUTS 2700
+
+#define B_RESIZELAT 2601
+#define B_DRAWLAT 2602
+#define B_LATTCHANGED 2603
+#define B_REGULARLAT 2604
+
+/* *********************** */
+#define B_GAMEBUTS 2800
+
+#define B_ADD_PROP 2701
+#define B_CHANGE_PROP 2702
+
+#define B_ADD_SENS 2703
+#define B_CHANGE_SENS 2704
+#define B_DEL_SENS 2705
+
+#define B_ADD_CONT 2706
+#define B_CHANGE_CONT 2707
+#define B_DEL_CONT 2708
+
+#define B_ADD_ACT 2709
+#define B_CHANGE_ACT 2710
+#define B_DEL_ACT 2711
+
+#define B_SOUNDACT_BROWSE 2712
+
+#define B_SETSECTOR 2713
+#define B_SETPROP 2714
+#define B_SETACTOR 2715
+#define B_SETMAINACTOR 2716
+#define B_SETDYNA 2717
+
+/* *********************** */
+#define B_FPAINTBUTS 2900
+
+#define B_VPCOLSLI 2801
+#define B_VPGAMMA 2802
+
+#define B_COPY_TF_MODE 2804
+#define B_COPY_TF_UV 2805
+#define B_COPY_TF_COL 2806
+#define B_REDR_3D_IMA 2807
+#define B_SET_VCOL 2808
+
+#define B_COPY_TF_TEX 2814
+#define B_TFACE_HALO 2815
+#define B_TFACE_BILLB 2816
+
+#define B_SHOWTEX 2832
+#define B_ASSIGNMESH 2833
+
+#define B_WEIGHT0_0 2840
+#define B_WEIGHT1_4 2841
+#define B_WEIGHT1_2 2842
+#define B_WEIGHT3_4 2843
+#define B_WEIGHT1_0 2844
+
+#define B_OPA1_8 2845
+#define B_OPA1_4 2846
+#define B_OPA1_2 2847
+#define B_OPA3_4 2848
+#define B_OPA1_0 2849
+
+#define B_CLR_WPAINT 2850
+
+#define B_BRUSHBROWSE 2851
+#define B_BRUSHDELETE 2852
+#define B_BRUSHLOCAL 2853
+#define B_BRUSHCHANGE 2854
+#define B_BTEXBROWSE 2855
+#define B_BTEXDELETE 2856
+#define B_BRUSHKEEPDATA 2857
+
+/* Sculptmode */
+#define B_SCULPT_TEXBROWSE 2860
+
+/* *********************** */
+#define B_RADIOBUTS 3000
+
+#define B_RAD_GO 2901
+#define B_RAD_INIT 2902
+#define B_RAD_LIMITS 2903
+#define B_RAD_FAC 2904
+#define B_RAD_NODELIM 2905
+#define B_RAD_NODEFILT 2906
+#define B_RAD_FACEFILT 2907
+#define B_RAD_ADD 2908
+#define B_RAD_DELETE 2909
+#define B_RAD_COLLECT 2910
+#define B_RAD_SHOOTP 2911
+#define B_RAD_SHOOTE 2912
+#define B_RAD_REPLACE 2913
+#define B_RAD_DRAW 2914
+#define B_RAD_FREE 2915
+#define B_RAD_ADDMESH 2916
+
+/* *********************** */
+#define B_SCRIPTBUTS 3100
+
+#define B_SCRIPT_ADD 3001
+#define B_SCRIPT_DEL 3002
+#define B_SCRIPT_TYPE 3003
+
+/* Scene script buttons */
+#define B_SSCRIPT_ADD 3004
+#define B_SSCRIPT_DEL 3005
+#define B_SSCRIPT_TYPE 3006
+
+/* *********************** */
+#define B_SOUNDBUTS 3200
+enum B_SOUND_BUTTONS {
+ B_SOUND_CHANGED = 3101,
+ B_SOUND_REDRAW,
+ B_SOUND_VOLUME,
+ B_SOUND_PANNING,
+ B_SOUND_PITCH,
+ B_SOUND_LOAD_SAMPLE,
+ B_SOUND_MENU_SAMPLE,
+ B_SOUND_NAME_SAMPLE,
+ B_SOUND_UNLINK_SAMPLE,
+ B_SOUND_RELOAD_SAMPLE,
+ B_SOUND_UNPACK_SAMPLE,
+ B_SOUND_PLAY_SAMPLE,
+ B_SOUND_COPY_SOUND,
+ B_SOUND_LOOPSTART,
+ B_SOUND_LOOPEND,
+ B_SOUND_BIDIRECTIONAL,
+ B_SOUND_RECALC,
+ B_SOUND_RATECHANGED,
+ B_SOUND_MIXDOWN
+};
+
+/* *********************** */
+#define B_CONSTRAINTBUTS 3300
+enum {
+ B_CONSTRAINT_TEST = 3201,
+ B_CONSTRAINT_CHANGETARGET,
+ B_CONSTRAINT_ADD_NULL,
+ B_CONSTRAINT_ADD_KINEMATIC,
+ B_CONSTRAINT_ADD_TRACKTO,
+ B_CONSTRAINT_ADD_MINMAX,
+ B_CONSTRAINT_ADD_ROTLIKE,
+ B_CONSTRAINT_ADD_LOCLIKE,
+ B_CONSTRAINT_ADD_SIZELIKE,
+ B_CONSTRAINT_ADD_ACTION,
+ B_CONSTRAINT_ADD_LOCKTRACK,
+ B_CONSTRAINT_ADD_FOLLOWPATH,
+ B_CONSTRAINT_ADD_DISTANCELIMIT,
+ B_CONSTRAINT_ADD_STRETCHTO,
+ B_CONSTRAINT_ADD_LOCLIMIT,
+ B_CONSTRAINT_ADD_ROTLIMIT,
+ B_CONSTRAINT_ADD_SIZELIMIT,
+ B_CONSTRAINT_ADD_RIGIDBODYJOINT,
+ B_CONSTRAINT_ADD_CHILDOF,
+ B_CONSTRAINT_ADD_PYTHON,
+ B_CONSTRAINT_ADD_CLAMPTO,
+ B_CONSTRAINT_ADD_TRANSFORM,
+ B_CONSTRAINT_INF
+};
+
+/* *********************** */
+#define B_UVAUTOCALCBUTS 3400
+enum {
+ B_UVAUTO_REDRAW = 3301,
+ B_UVAUTO_SPHERE,
+ B_UVAUTO_CYLINDER,
+ B_UVAUTO_CYLRADIUS,
+ B_UVAUTO_WINDOW,
+ B_UVAUTO_CUBE,
+ B_UVAUTO_CUBESIZE,
+ B_UVAUTO_RESET,
+ B_UVAUTO_BOUNDS,
+ B_UVAUTO_TOP,
+ B_UVAUTO_FACE,
+ B_UVAUTO_OBJECT,
+ B_UVAUTO_ALIGNX,
+ B_UVAUTO_ALIGNY,
+ B_UVAUTO_UNWRAP,
+ B_UVAUTO_DRAWFACES
+};
+
+#define B_EFFECTSBUTS 3500
+
+#define B_AUTOTIMEOFS 3403
+#define B_FRAMEMAP 3404
+#define B_NEWEFFECT 3405
+#define B_PREVEFFECT 3406
+#define B_NEXTEFFECT 3407
+#define B_CHANGEEFFECT 3408
+#define B_CALCEFFECT 3409
+#define B_DELEFFECT 3410
+#define B_RECALCAL 3411
+#define B_RECALC_DEFL 3412
+#define B_EFFECT_DEP 3413
+#define B_FIELD_DEP 3414
+#define B_FIELD_CHANGE 3415
+#define B_PAF_SET_VG 3416
+#define B_PAF_SET_VG1 3417
+
+#define B_MODIFIER_BUTS 3600
+
+#define B_MODIFIER_RECALC 3501
+#define B_MODIFIER_REDRAW 3502
+
+/* *********************** */
+#define B_NODE_BUTS 4000
+ /* 400 slots reserved, we want an exec event for each node */
+#define B_NODE_LOADIMAGE 3601
+#define B_NODE_TREE_EXEC 3602
+
+ /* exec should be last in this list */
+#define B_NODE_EXEC 3610
+
+
+/* *********************** */
+/* BUTTON 4001-4032: layers? (sort this out!) */
+
+/* *********************** */
+/* event code 0x4000 (16384) and larger: general events (redraws, etc) */
+
+
+#endif
+
diff --git a/source/blender/include/datatoc.h b/source/blender/include/datatoc.h
new file mode 100644
index 00000000000..7afd4428d70
--- /dev/null
+++ b/source/blender/include/datatoc.h
@@ -0,0 +1,63 @@
+/*
+ * datatoc.h
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef DATATOC_H
+#define DATATOC_H
+
+extern int datatoc_B_blend_size;
+extern char datatoc_B_blend[];
+
+extern int datatoc_Bfs_size;
+extern char datatoc_Bfs[];
+
+extern int datatoc_blenderbuttons_size;
+extern char datatoc_blenderbuttons[];
+
+extern int datatoc_prvicons_size;
+extern char datatoc_prvicons[];
+
+extern int datatoc_Bfont_size;
+extern char datatoc_Bfont[];
+
+extern int datatoc_bfont_ttf_size;
+extern char datatoc_bfont_ttf[];
+
+extern int datatoc_cmap_tga_size;
+extern char datatoc_cmap_tga[];
+
+extern int datatoc_cmovie_tga_size;
+extern char datatoc_cmovie_tga[];
+
+#endif /* DATATOC_H */
+
diff --git a/source/blender/include/editlattice_ext.h b/source/blender/include/editlattice_ext.h
new file mode 100644
index 00000000000..afb109df5f7
--- /dev/null
+++ b/source/blender/include/editlattice_ext.h
@@ -0,0 +1,42 @@
+/*
+ * editlattice_ext.h
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef EDITLATTICE_EXT_H
+#define EDITLATTICE_EXT_H "$Id$"
+#define EDITLATTICE_EXT_H "Copyright (C) 2001 NaN Technologies B.V.
+
+void end_latt_deform(void);
+
+#endif /* EDITLATTICE_EXT_H */
+
diff --git a/source/blender/include/editmesh.h b/source/blender/include/editmesh.h
new file mode 100644
index 00000000000..1b2d91e22b8
--- /dev/null
+++ b/source/blender/include/editmesh.h
@@ -0,0 +1,110 @@
+/**
+ * $Id:
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/* Internal for editmesh_xxxx.c functions */
+
+#ifndef EDITMESH_H
+#define EDITMESH_H
+
+#define TEST_EDITMESH if(G.obedit==0) return; \
+ if( (G.vd->lay & G.obedit->lay)==0 ) return;
+
+#define UVCOPY(t, s) memcpy(t, s, 2 * sizeof(float));
+
+
+
+/* ******************* editmesh.c */
+extern void free_editvert(EditVert *eve);
+extern void free_editedge(EditEdge *eed);
+extern void free_editface(EditFace *efa);
+
+extern void free_vertlist(ListBase *edve);
+extern void free_edgelist(ListBase *lb);
+extern void free_facelist(ListBase *lb);
+
+extern void remedge(EditEdge *eed);
+
+extern struct EditVert *addvertlist(float *vec, struct EditVert *example);
+extern struct EditEdge *addedgelist(struct EditVert *v1, struct EditVert *v2, struct EditEdge *example);
+extern struct EditFace *addfacelist(struct EditVert *v1, struct EditVert *v2, struct EditVert *v3, struct EditVert *v4, struct EditFace *example, struct EditFace *exampleEdges);
+extern struct EditEdge *findedgelist(struct EditVert *v1, struct EditVert *v2);
+
+/* ******************* editmesh_add.c */
+
+
+/* ******************* editmesh_lib.c */
+extern void EM_fgon_flags(void);
+extern void EM_hide_reset(void);
+
+extern int faceselectedOR(EditFace *efa, int flag);
+extern int faceselectedAND(EditFace *efa, int flag);
+
+extern EditFace *exist_face(EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4);
+extern void flipface(EditFace *efa); // flips for normal direction
+extern int compareface(EditFace *vl1, EditFace *vl2);
+
+/* flag for selection bits, *nor will be filled with normal for extrusion constraint */
+/* return value defines if such normal was set */
+extern short extrudeflag_face_indiv(short flag, float *nor);
+extern short extrudeflag_verts_indiv(short flag, float *nor);
+extern short extrudeflag_edges_indiv(short flag, float *nor);
+extern short extrudeflag_vert(short flag, float *nor);
+extern short extrudeflag(short flag, float *nor);
+
+extern void adduplicateflag(int flag);
+extern void delfaceflag(int flag);
+
+extern void rotateflag(short flag, float *cent, float rotmat[][3]);
+extern void translateflag(short flag, float *vec);
+
+extern int convex(float *v1, float *v2, float *v3, float *v4);
+
+/* ******************* editmesh_mods.c */
+extern EditEdge *findnearestedge(int *dist);
+extern void EM_automerge(int update);
+
+/**
+ * findnearestvert
+ *
+ * dist (in/out): minimal distance to the nearest and at the end, actual distance
+ * sel: selection bias
+ * if SELECT, selected vertice are given a 5 pixel bias to make them farter than unselect verts
+ * if 0, unselected vertice are given the bias
+ * strict: if 1, the vertice corresponding to the sel parameter are ignored and not just biased
+ */
+extern EditVert *findnearestvert(int *dist, short sel, short strict);
+
+/* ******************* editmesh_tools.c */
+
+
+#endif
+
diff --git a/source/blender/include/interface.h b/source/blender/include/interface.h
new file mode 100644
index 00000000000..d8e779b9af8
--- /dev/null
+++ b/source/blender/include/interface.h
@@ -0,0 +1,236 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef INTERFACE_H
+#define INTERFACE_H
+
+#include "BIF_resources.h"
+
+/* general defines */
+
+#define UI_MAX_DRAW_STR 400
+#define UI_MAX_NAME_STR 64
+#define UI_ARRAY 29
+
+/* panel limits */
+#define UI_PANEL_MINX 100
+#define UI_PANEL_MINY 70
+
+/* uiBut->flag */
+#define UI_SELECT 1
+#define UI_MOUSE_OVER 2
+#define UI_ACTIVE 4
+#define UI_HAS_ICON 8
+/* warn: rest of uiBut->flag in BIF_interface.c */
+
+
+/* internal panel drawing defines */
+#define PNL_GRID 4
+#define PNL_DIST 8
+#define PNL_SAFETY 8
+#define PNL_HEADER 20
+
+/* panel->flag */
+#define PNL_SELECT 1
+#define PNL_CLOSEDX 2
+#define PNL_CLOSEDY 4
+#define PNL_CLOSED 6
+#define PNL_TABBED 8
+#define PNL_OVERLAP 16
+
+/* Button text selection:
+ * extension direction, selextend, inside ui_do_but_TEX */
+#define EXTEND_LEFT 1
+#define EXTEND_RIGHT 2
+
+typedef struct {
+ short xim, yim;
+ unsigned int *rect;
+ short xofs, yofs;
+} uiIconImage;
+
+typedef struct {
+ short mval[2];
+ short qual, val;
+ int event;
+} uiEvent;
+
+typedef struct {
+ void *xl, *large, *medium, *small;
+} uiFont;
+
+typedef struct uiLinkLine { /* only for draw/edit */
+ struct uiLinkLine *next, *prev;
+
+ short flag, pad;
+
+ struct uiBut *from, *to;
+} uiLinkLine;
+
+typedef struct {
+ void **poin; /* pointer to original pointer */
+ void ***ppoin; /* pointer to original pointer-array */
+ short *totlink; /* if pointer-array, here is the total */
+
+ short maxlink, pad;
+ short fromcode, tocode;
+
+ ListBase lines;
+} uiLink;
+
+struct uiBut {
+ struct uiBut *next, *prev;
+ short type, pointype, bit, bitnr, retval, strwidth, ofs, pos, selsta, selend;
+ int flag;
+
+ char *str;
+ char strdata[UI_MAX_NAME_STR];
+ char drawstr[UI_MAX_DRAW_STR];
+
+ float x1, y1, x2, y2;
+
+ char *poin;
+ float min, max;
+ float a1, a2, hsv[3]; // hsv is temp memory for hsv buttons
+ float aspect;
+
+ void (*func)(void *, void *);
+ void *func_arg1;
+ void *func_arg2;
+
+ void (*embossfunc)(int , int , float, float, float, float, float, int);
+ void (*sliderfunc)(int , float, float, float, float, float, float, int);
+
+ void (*autocomplete_func)(char *, void *);
+ void *autofunc_arg;
+
+ uiLink *link;
+
+ char *tip, *lockstr;
+
+ int themecol; /* themecolor id */
+ void *font;
+
+ BIFIconID icon;
+ short but_align; /* aligning buttons, horiz/vertical */
+ short lock, win;
+ short iconadd, dt;
+
+ /* IDPOIN data */
+ uiIDPoinFuncFP idpoin_func;
+ ID **idpoin_idpp;
+
+ /* BLOCK data */
+ uiBlockFuncFP block_func;
+
+ /* BUTM data */
+ void (*butm_func)(void *arg, int event);
+ void *butm_func_arg;
+
+ /* pointer back */
+ uiBlock *block;
+};
+
+struct uiBlock {
+ uiBlock *next, *prev;
+
+ ListBase buttons;
+ Panel *panel;
+
+ char name[UI_MAX_NAME_STR];
+
+ float winmat[4][4];
+
+ float minx, miny, maxx, maxy;
+ float aspect;
+
+ void (*butm_func)(void *arg, int event);
+ void *butm_func_arg;
+
+ void (*func)(void *arg1, void *arg2);
+ void *func_arg1;
+ void *func_arg2;
+
+ /* extra draw function for custom blocks */
+ void (*drawextra)();
+
+ int themecol; /* themecolor id */
+
+ short font; /* indices */
+ int afterval, flag;
+ void *curfont;
+
+ short autofill, win, winq, direction, dt;
+ short needflush, auto_open, in_use, pad; //flush see below
+ void *overdraw;
+ struct uiBlock *parent; // nested pulldowns
+
+ float xofs, yofs; // offset to parent button
+ rctf parentrct; // for pulldowns, rect the mouse is allowed outside of menu (parent button)
+ rctf safety; // pulldowns, to detect outside, can differ per case how it is created
+
+ rctf flush; // rect to be flushed to frontbuffer
+ int handler; // for panels in other windows than buttonswin... just event code
+};
+
+/* interface.c */
+
+extern void ui_graphics_to_window(int win, float *x, float *y);
+extern void ui_graphics_to_window_rct(int win, rctf *graph, rcti *winr);
+extern void ui_window_to_graphics(int win, float *x, float *y);
+
+extern void ui_block_flush_back(uiBlock *block);
+extern void ui_block_set_flush(uiBlock *block, uiBut *but);
+
+extern void ui_check_but(uiBut *but);
+extern double ui_get_but_val(uiBut *but);
+extern void ui_get_but_vectorf(uiBut *but, float *vec);
+extern void ui_set_but_vectorf(uiBut *but, float *vec);
+extern void ui_autofill(uiBlock *block);
+
+/* interface_panel.c */
+extern void ui_draw_panel(uiBlock *block);
+extern void ui_do_panel(uiBlock *block, uiEvent *uevent);
+extern void ui_scale_panel(uiBlock *block);
+extern void gl_round_box(int mode, float minx, float miny, float maxx, float maxy, float rad);
+extern void gl_round_box_shade(int mode, float minx, float miny, float maxx, float maxy, float rad, float shadetop, float shadedown);
+
+/* interface_draw.c */
+extern void ui_set_embossfunc(uiBut *but, int drawtype);
+extern void ui_draw_but(uiBut *but);
+extern void ui_rasterpos_safe(float x, float y, float aspect);
+extern void ui_draw_tria_icon(float x, float y, float aspect, char dir);
+extern void ui_draw_anti_x(float x1, float y1, float x2, float y2);
+extern void ui_dropshadow(rctf *rct, float radius, float aspect, int select);
+
+#endif
+
diff --git a/source/blender/include/keyed_functions.h b/source/blender/include/keyed_functions.h
new file mode 100644
index 00000000000..405fec16992
--- /dev/null
+++ b/source/blender/include/keyed_functions.h
@@ -0,0 +1,58 @@
+/**
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#define KEY_GETPTR(x) (g_ptrtab ? g_ptrtab[x] : 0)
+
+/* these are the defines for the keyed functions:
+
+ #define key_func<n> <function name to be behind key>
+
+ This function must be of type "int func(void*)"
+
+ To prevent symbol table dumpers from retrieving certain key
+ functions too easily, some of those functions have nonsense names.
+*/
+
+#define key_func1 key_return_true
+/* add the corresponding function pointer defines here.
+ Example:
+
+ #define key_func4 my_protected_function_name
+ #define MY_PROTECTED_FUNCTION_PTR KEY_GETPTR(KEY_FUNC3)
+
+ KEY_GETPTR(KEY_FUNC3) corresponds to the function pointer to function
+ key_func3 after the python key code unscrambled the function pointer tables.
+ Also add pointer initializations to these functions in
+ license_key.c:init_ftable() if necessary.
+*/
+
+#define KEY_RETURN_TRUE KEY_GETPTR(KEY_FUNC1)
+
diff --git a/source/blender/include/license_key.h b/source/blender/include/license_key.h
new file mode 100644
index 00000000000..1346998f520
--- /dev/null
+++ b/source/blender/include/license_key.h
@@ -0,0 +1,95 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef LICENCEKEY_H
+#define LICENCEKEY_H
+
+#define I_AM_PUBLISHER temp_val2
+#define LICENSE_KEY_VALID temp_val
+#define SHOW_LICENSE_KEY rotop
+
+extern int LICENSE_KEY_VALID;
+extern int I_AM_PUBLISHER;
+
+extern char * license_key_name;
+extern void loadKeyboard(char * name);
+extern void checkhome(void);
+extern void SHOW_LICENSE_KEY(void);
+
+#define LICENSE_CHECK_0 (0==0)
+
+// Stuff from the Python files from Strubi
+
+typedef int (*Fptr)(void *);
+
+extern Fptr g_functab[];
+extern Fptr g_ptrtab[];
+
+// TODO: From here on, this should be a generated header file...
+
+// change all KEY_FUNC values
+// if you change PYKEY_TABLEN or PYKEY_SEED
+// see below
+
+#define PYKEY_TABLEN 21 // don't change this unless needed. Other values
+ // may yield bad random orders
+
+#define PYKEY_SEED {26,8,1972}
+
+// these values are generated by $HOME/develop/intern/keymaker/makeseed.py
+// from the above seed value.
+
+// DO NOT EDIT THESE VALUES BY HAND!
+
+#define KEY_FUNC1 12
+#define KEY_FUNC2 8
+#define KEY_FUNC3 1
+#define KEY_FUNC4 16
+#define KEY_FUNC5 20
+#define KEY_FUNC6 18
+#define KEY_FUNC7 13
+#define KEY_FUNC8 6
+#define KEY_FUNC9 9
+#define KEY_FUNC10 7
+#define KEY_FUNC11 14
+#define KEY_FUNC12 0
+#define KEY_FUNC13 5
+#define KEY_FUNC14 10
+#define KEY_FUNC15 19
+#define KEY_FUNC16 2
+#define KEY_FUNC17 11
+#define KEY_FUNC18 3
+#define KEY_FUNC19 17
+#define KEY_FUNC20 15
+#define KEY_FUNC21 4
+
+#endif
+
diff --git a/source/blender/include/multires.h b/source/blender/include/multires.h
new file mode 100644
index 00000000000..bfa765e62ef
--- /dev/null
+++ b/source/blender/include/multires.h
@@ -0,0 +1,81 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 by Nicholas Bishop
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef MULTIRES_H
+#define MULTIRES_H
+
+struct CustomData;
+struct EditMesh;
+struct Object;
+struct MDeformVert;
+struct Mesh;
+struct MultiresLevel;
+struct Multires;
+struct uiBlock;
+
+/* For canceling operations that don't work with multires on or on a non-base level */
+int multires_test();
+int multires_level1_test();
+
+struct MultiresLevel *multires_level_n(struct Multires *mr, int n);
+
+void multires_draw_interface(struct uiBlock *block, unsigned short cx, unsigned short cy);
+void multires_disp_map(void *, void*);
+
+void multires_make(void *ob, void *me);
+void multires_delete(void *ob, void *me);
+struct Multires *multires_copy(struct Multires *orig);
+void multires_free(struct Multires *mr);
+void multires_free_level(struct MultiresLevel *lvl);
+void multires_del_lower(void *ob, void *me);
+void multires_del_higher(void *ob, void *me);
+void multires_add_level(void *ob, void *me);
+void multires_set_level_cb(void *ob, void *me);
+void multires_set_level(struct Object *ob, struct Mesh *me, const int render);
+void multires_update_levels(struct Mesh *me, const int render);
+void multires_level_to_mesh(struct Object *ob, struct Mesh *me, const int render);
+void multires_edge_level_update(void *ob, void *me);
+int multires_modifier_warning();
+
+/* after adding or removing vcolor layers, run this */
+void multires_load_cols(Mesh *me);
+
+/* multires-firstlevel.c */
+/* Generic */
+void multires_update_first_level(struct Mesh *me, struct EditMesh *em);
+void multires_update_customdata(struct MultiresLevel *lvl1, struct CustomData *src,
+ struct CustomData *dst, const int type);
+void multires_customdata_to_mesh(struct Mesh *me, struct EditMesh *em, struct MultiresLevel *lvl,
+ struct CustomData *src, struct CustomData *dst, const int type);
+void multires_del_lower_customdata(struct Multires *mr, struct MultiresLevel *cr_lvl);
+
+void multires_add_layer(struct Mesh *me, struct CustomData *cd, const int type, const int n);
+void multires_delete_layer(struct Mesh *me, struct CustomData *cd, const int type, int n);
+
+#endif
diff --git a/source/blender/include/mydevice.h b/source/blender/include/mydevice.h
new file mode 100644
index 00000000000..bec0e13726b
--- /dev/null
+++ b/source/blender/include/mydevice.h
@@ -0,0 +1,260 @@
+
+#ifndef __MYDEVICE_H__
+#define __MYDEVICE_H__
+
+/*
+ * This file has its origin at sgi, where all device defines were written down.
+ * Blender copied this concept quite some, and expanded it with internal new defines (ton)
+ *
+ * mouse / timer / window: until 0x020
+ * custom codes: 0x4...
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/* MOUSE : 0x00x */
+
+#define LEFTMOUSE 0x001
+#define MIDDLEMOUSE 0x002
+#define RIGHTMOUSE 0x003
+#define MOUSEX 0x004
+#define MOUSEY 0x005
+#define WHEELUPMOUSE 0x00a
+#define WHEELDOWNMOUSE 0x00b
+
+/* timers */
+
+#define TIMER0 0x006
+#define TIMER1 0x007
+#define TIMER2 0x008
+#define TIMER3 0x009
+
+/* SYSTEM : 0x01x */
+
+#define KEYBD 0x010 /* keyboard */
+#define RAWKEYBD 0x011 /* raw keyboard for keyboard manager */
+#define REDRAW 0x012 /* used by port manager to signal redraws */
+#define INPUTCHANGE 0x013 /* input connected or disconnected */
+#define QFULL 0x014 /* queue was filled */
+#define WINFREEZE 0x015 /* user wants process in this win to shut up */
+#define WINTHAW 0x016 /* user wants process in this win to go again */
+#define WINCLOSE 0x017 /* window close */
+#define WINQUIT 0x018 /* signal from user that app is to go away */
+#define Q_FIRSTTIME 0x019 /* on startup */
+
+/* standard keyboard */
+
+#define AKEY 'a'
+#define BKEY 'b'
+#define CKEY 'c'
+#define DKEY 'd'
+#define EKEY 'e'
+#define FKEY 'f'
+#define GKEY 'g'
+#define HKEY 'h'
+#define IKEY 'i'
+#define JKEY 'j'
+#define KKEY 'k'
+#define LKEY 'l'
+#define MKEY 'm'
+#define NKEY 'n'
+#define OKEY 'o'
+#define PKEY 'p'
+#define QKEY 'q'
+#define RKEY 'r'
+#define SKEY 's'
+#define TKEY 't'
+#define UKEY 'u'
+#define VKEY 'v'
+#define WKEY 'w'
+#define XKEY 'x'
+#define YKEY 'y'
+#define ZKEY 'z'
+
+#define ZEROKEY '0'
+#define ONEKEY '1'
+#define TWOKEY '2'
+#define THREEKEY '3'
+#define FOURKEY '4'
+#define FIVEKEY '5'
+#define SIXKEY '6'
+#define SEVENKEY '7'
+#define EIGHTKEY '8'
+#define NINEKEY '9'
+
+#define CAPSLOCKKEY 211
+
+#define LEFTCTRLKEY 212
+#define LEFTALTKEY 213
+#define RIGHTALTKEY 214
+#define RIGHTCTRLKEY 215
+#define RIGHTSHIFTKEY 216
+#define LEFTSHIFTKEY 217
+
+#define ESCKEY 218
+#define TABKEY 219
+#define RETKEY 220
+#define SPACEKEY 221
+#define LINEFEEDKEY 222
+#define BACKSPACEKEY 223
+#define DELKEY 224
+#define SEMICOLONKEY 225
+#define PERIODKEY 226
+#define COMMAKEY 227
+#define QUOTEKEY 228
+#define ACCENTGRAVEKEY 229
+#define MINUSKEY 230
+#define SLASHKEY 232
+#define BACKSLASHKEY 233
+#define EQUALKEY 234
+#define LEFTBRACKETKEY 235
+#define RIGHTBRACKETKEY 236
+
+#define LEFTARROWKEY 137
+#define DOWNARROWKEY 138
+#define RIGHTARROWKEY 139
+#define UPARROWKEY 140
+
+#define PAD0 150
+#define PAD1 151
+#define PAD2 152
+#define PAD3 153
+#define PAD4 154
+#define PAD5 155
+#define PAD6 156
+#define PAD7 157
+#define PAD8 158
+#define PAD9 159
+
+
+#define PADPERIOD 199
+#define PADSLASHKEY 161
+#define PADASTERKEY 160
+
+
+#define PADMINUS 162
+#define PADENTER 163
+#define PADPLUSKEY 164
+
+
+#define F1KEY 300
+#define F2KEY 301
+#define F3KEY 302
+#define F4KEY 303
+#define F5KEY 304
+#define F6KEY 305
+#define F7KEY 306
+#define F8KEY 307
+#define F9KEY 308
+#define F10KEY 309
+#define F11KEY 310
+#define F12KEY 311
+
+#define PAUSEKEY 165
+#define INSERTKEY 166
+#define HOMEKEY 167
+#define PAGEUPKEY 168
+#define PAGEDOWNKEY 169
+#define ENDKEY 170
+
+#define UNKNOWNKEY 171
+#define COMMANDKEY 172
+#define GRLESSKEY 173
+
+/* used as fake leftmouse events, special handled in interface.c */
+#define BUT_ACTIVATE 200
+#define BUT_NEXT 201
+#define BUT_PREV 202
+
+/* **************** BLENDER QUEUE EVENTS ********************* */
+
+#define CHANGED 0x4000
+#define DRAWEDGES 0x4001
+#define AFTERQUEUE 0x4002
+#define BACKBUFDRAW 0x4003
+#define EXECUTE 0x4004
+#define IGNORE_REDRAW 0x4005
+#define LOAD_FILE 0x4006
+#define RESHAPE 0x4007
+#define UI_BUT_EVENT 0x4008
+#define AUTOSAVE_FILE 0x4009
+#define UNDOPUSH 0x400A
+
+/* REDRAWVIEW3D has to be the first one (lowest number) for buttons! */
+#define REDRAWVIEW3D 0x4010
+#define REDRAWVIEWCAM 0x4011
+#define REDRAWVIEW3D_Z 0x4012
+
+#define REDRAWALL 0x4013
+#define REDRAWHEADERS 0x4014
+
+#define REDRAWBUTSHEAD 0x4015
+#define REDRAWBUTSALL 0x4016
+
+#define REDRAWBUTSSCENE 0x4017
+#define REDRAWBUTSOBJECT 0x4018
+#define REDRAWBUTSEDIT 0x4019
+#define REDRAWBUTSSCRIPT 0x401A
+#define REDRAWBUTSLOGIC 0x401B
+#define REDRAWBUTSSHADING 0x401C
+#define REDRAWBUTSGAME 0x401D
+#define REDRAWBUTSEFFECTS 0x401D
+
+#define REDRAWINFO 0x4021
+#define RENDERPREVIEW 0x4022
+#define REDRAWIPO 0x4023
+#define REDRAWDATASELECT 0x4024
+#define REDRAWSEQ 0x4025
+#define REDRAWIMAGE 0x4026
+#define REDRAWOOPS 0x4027
+#define REDRAWIMASEL 0x4028
+#define AFTERIMASELIMA 0x4029
+#define AFTERIMASELGET 0x402A
+#define AFTERIMAWRITE 0x402B
+#define IMALEFTMOUSE 0x402C
+#define AFTERPIBREAD 0x402D
+#define REDRAWTEXT 0x402E
+#define REDRAWSOUND 0x402F
+#define REDRAWACTION 0x4030
+#define REDRAWNLA 0x4031
+#define REDRAWSCRIPT 0x4032
+#define REDRAWTIME 0x4033
+#define REDRAWBUTSCONSTRAINT 0x4034
+#define ONLOAD_SCRIPT 0x4035
+#define SCREEN_HANDLER 0x4036
+#define REDRAWANIM 0x4037
+#define REDRAWNODE 0x4038
+#define RECALC_COMPOSITE 0x4039
+#define REDRAWMARKER 0x4040 /* all views that display markers */
+#define REDRAWVIEW3D_IMAGE 0x4041
+
+#endif /* !__MYDEVICE_H__ */
+
diff --git a/source/blender/include/nla.h b/source/blender/include/nla.h
new file mode 100644
index 00000000000..f07121bd56b
--- /dev/null
+++ b/source/blender/include/nla.h
@@ -0,0 +1,59 @@
+/* nla.h May 2001
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * Use this to turn experimental options on
+ * or off with the #define flags. Please do not
+ * put other includes, typdefs etc in this file.
+ * ===========================================
+ *
+ * __NLA
+ * This encompasses the new armature object, the
+ * action datablock and the action window-type.
+ *
+ * __CON_IPO
+ * Support for constraint ipo keys
+ *
+ * __NLA_ACTION_BY_MOTION_ACTUATOR
+ * New action actuator playback type
+ *
+ * $Id$
+ */
+
+#ifndef NLA_H
+#define NLA_H
+
+#define __NLA
+
+#define __CON_IPO // Not for Release: Not yet fully implemented
+//#define __NLA_ACTION_BY_MOTION_ACTUATOR // Not for release: Not yet fully implemented
+
+#endif
+
diff --git a/source/blender/include/objfnt.h b/source/blender/include/objfnt.h
new file mode 100644
index 00000000000..e54b7b5e1e3
--- /dev/null
+++ b/source/blender/include/objfnt.h
@@ -0,0 +1,105 @@
+/* $Id$
+*/
+/*
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+#ifndef OBJFNTDEF
+#define OBJFNTDEF
+
+typedef struct chardesc {
+ short movex, movey; /* advance */
+ short llx, lly; /* bounding box */
+ short urx, ury;
+ short *data; /* char data */
+ long datalen;
+} chardesc;
+
+typedef struct objfnt {
+ struct objfnt *freeaddr; /* if freeaddr != 0, objfnt is one chunck */
+ short type;
+ short charmin, charmax;
+ short my_nchars;
+ short scale;
+ chardesc *my_chars;
+} objfnt;
+
+#define OFMAGIC 0x93339333
+
+#define TM_TYPE 1
+#define PO_TYPE 2
+#define SP_TYPE 3
+
+/* ops for tmesh characters */
+
+#define TM_BGNTMESH (1)
+#define TM_SWAPTMESH (2)
+#define TM_ENDBGNTMESH (3)
+#define TM_RETENDTMESH (4)
+#define TM_RET (5)
+
+/* ops for poly characters */
+
+#define PO_BGNLOOP (1)
+#define PO_ENDBGNLOOP (2)
+#define PO_RETENDLOOP (3)
+#define PO_RET (4)
+
+/* ops for spline characters */
+
+#define SP_MOVETO (1)
+#define SP_LINETO (2)
+#define SP_CURVETO (3)
+#define SP_CLOSEPATH (4)
+#define SP_RETCLOSEPATH (5)
+#define SP_RET (6)
+
+
+#define MIN_ASCII ' '
+#define MAX_ASCII '~'
+#define NASCII (256 - 32)
+
+#define NOBBOX (30000)
+
+typedef struct pschar {
+ char *name;
+ int code;
+ int prog;
+} pschar;
+
+extern pschar charlist[NASCII];
+
+/* objfnt *fontname(void); */
+/* objfnt *readobjfnt(void); */
+/* objfnt *newobjfnt(void); */
+/* float fontstringwidth(void); */
+/* short *getcharprog(void); */
+/* chardesc *BLI_getchardesc(void); */
+/* char *asciiname(void); */
+
+#endif
+
diff --git a/source/blender/include/particle_effect.h b/source/blender/include/particle_effect.h
new file mode 100644
index 00000000000..883331ac740
--- /dev/null
+++ b/source/blender/include/particle_effect.h
@@ -0,0 +1,47 @@
+/* dec 95
+ * jan feb 96
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef PARTICLE_EFFECT_H
+#define PARTICLE_EFFECT_H
+
+/* effect.c */
+extern Effect *add_effect(int type);
+extern PartEff *give_parteff(Object *ob);
+extern void where_is_particle(PartEff *paf, Particle *pa, float ctime, float *vec);
+extern void free_effect(Effect *eff);
+extern void free_effects(ListBase *lb);
+extern void copy_effects(ListBase *lbn, ListBase *lb);
+extern void build_particle_system(Object *ob);
+
+#endif
+
diff --git a/source/blender/include/playanim_ext.h b/source/blender/include/playanim_ext.h
new file mode 100644
index 00000000000..bef610ac018
--- /dev/null
+++ b/source/blender/include/playanim_ext.h
@@ -0,0 +1,41 @@
+/*
+ * external interface
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef PLAYANIM_EXT_H
+#define PLAYANIM_EXT_H
+
+/* used in apps */
+extern void playanim(int argc, char **argv);
+
+#endif
+
diff --git a/source/blender/include/transform.h b/source/blender/include/transform.h
new file mode 100644
index 00000000000..a01bf92c871
--- /dev/null
+++ b/source/blender/include/transform.h
@@ -0,0 +1,452 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef TRANSFORM_H
+#define TRANSFORM_H
+
+#include "BIF_transform.h"
+
+/* ************************** Types ***************************** */
+
+struct TransInfo;
+struct TransData;
+struct TransSnap;
+struct NumInput;
+struct Object;
+struct View3D;
+struct ScrArea;
+struct bPose;
+
+
+typedef struct NumInput {
+ short idx;
+ short idx_max;
+ short flag; /* Different flags to indicate different behaviors */
+ float val[3]; /* Direct value of the input */
+ int ctrl[3]; /* Control to indicate what to do with the numbers that are typed */
+} NumInput ;
+
+/*
+ The ctrl value has different meaning:
+ 0 : No value has been typed
+
+ otherwise, |value| - 1 is where the cursor is located after the period
+ Positive : number is positive
+ Negative : number is negative
+*/
+
+typedef struct TransSnap {
+ short modePoint;
+ short modeTarget;
+ int status;
+ float snapPoint[3];
+ float snapTarget[3];
+ float dist; // Distance from snapPoint to snapTarget
+ double last;
+ void (*applySnap)(struct TransInfo *, float *);
+ void (*calcSnap)(struct TransInfo *, float *);
+ void (*targetSnap)(struct TransInfo *);
+ float (*distance)(struct TransInfo *, float p1[3], float p2[3]); // Get the transform distance between two points (used by Closest snap)
+} TransSnap;
+
+typedef struct TransCon {
+ char text[50]; /* Description of the Constraint for header_print */
+ float mtx[3][3]; /* Matrix of the Constraint space */
+ float imtx[3][3]; /* Inverse Matrix of the Constraint space */
+ float pmtx[3][3]; /* Projection Constraint Matrix (same as imtx with some axis == 0) */
+ float center[3]; /* transformation center to define where to draw the view widget
+ ALWAYS in global space. Unlike the transformation center */
+ short imval[2]; /* initial mouse value for visual calculation */
+ /* the one in TransInfo is not garanty to stay the same (Rotates change it) */
+ int mode; /* Mode flags of the Constraint */
+ void (*drawExtra)(struct TransInfo *);
+ /* For constraints that needs to draw differently from the other
+ uses this instead of the generic draw function */
+ void (*applyVec)(struct TransInfo *, struct TransData *, float *, float *, float *);
+ /* Apply function pointer for linear vectorial transformation */
+ /* The last three parameters are pointers to the in/out/printable vectors */
+ void (*applySize)(struct TransInfo *, struct TransData *, float [3][3]);
+ /* Apply function pointer for rotation transformation (prototype will change */
+ void (*applyRot)(struct TransInfo *, struct TransData *, float [3]);
+ /* Apply function pointer for rotation transformation (prototype will change */
+} TransCon;
+
+typedef struct TransDataIpokey {
+ int flag; /* which keys */
+ float *locx, *locy, *locz; /* channel pointers */
+ float *rotx, *roty, *rotz;
+ float *quatx, *quaty, *quatz, *quatw;
+ float *sizex, *sizey, *sizez;
+ float oldloc[9]; /* storage old values */
+ float oldrot[9];
+ float oldsize[9];
+ float oldquat[12];
+} TransDataIpokey;
+
+typedef struct TransDataExtension {
+ float drot[3]; /* Initial object drot */
+ float dsize[3]; /* Initial object dsize */
+ float *rot; /* Rotation of the data to transform (Faculative) */
+ float irot[3]; /* Initial rotation */
+ float *quat; /* Rotation quaternion of the data to transform (Faculative) */
+ float iquat[4]; /* Initial rotation quaternion */
+ float *size; /* Size of the data to transform (Faculative) */
+ float isize[3]; /* Initial size */
+ float obmat[3][3]; /* Object matrix */
+} TransDataExtension;
+
+typedef struct TransData2D {
+ float loc[3]; /* Location of data used to transform (x,y,0) */
+ float *loc2d; /* Pointer to real 2d location of data */
+} TransData2D;
+
+typedef struct TransData {
+ float dist; /* Distance needed to affect element (for Proportionnal Editing) */
+ float rdist; /* Distance to the nearest element (for Proportionnal Editing) */
+ float factor; /* Factor of the transformation (for Proportionnal Editing) */
+ float *loc; /* Location of the data to transform */
+ float iloc[3]; /* Initial location */
+ float *val; /* Value pointer for special transforms */
+ float ival; /* Old value*/
+ float center[3]; /* Individual data center */
+ float mtx[3][3]; /* Transformation matrix from data space to global space */
+ float smtx[3][3]; /* Transformation matrix from global space to data space */
+ float axismtx[3][3];/* Axis orientation matrix of the data */
+ struct Object *ob;
+ TransDataExtension *ext; /* for objects, poses. 1 single malloc per TransInfo! */
+ TransDataIpokey *tdi; /* for objects, ipo keys. per transdata a malloc */
+ void *tdmir; /* mirrored element pointer, in editmode mesh to EditVert */
+ short flag; /* Various flags */
+ short protectflag; /* If set, copy of Object or PoseChannel protection */
+/*#ifdef WITH_VERSE*/
+ void *verse; /* pointer at verse data struct (VerseVert, etc.) */
+/*#endif*/
+} TransData;
+
+typedef struct TransInfo {
+ int mode; /* current mode */
+ int flag; /* generic flags for special behaviors */
+ short state; /* current state (running, canceled,...)*/
+ int context; /* current context */
+ float val; /* init value for some transformations (and rotation angle) */
+ float fac; /* factor for distance based transform */
+ int (*transform)(struct TransInfo *, short *);
+ /* transform function pointer */
+ int (*handleEvent)(struct TransInfo *, unsigned short event, short val);
+ /* event handler function pointer RETURN 1 if redraw is needed */
+ int total; /* total number of transformed data */
+ TransData *data; /* transformed data (array) */
+ TransDataExtension *ext; /* transformed data extension (array) */
+ TransData2D *data2d; /* transformed data for 2d (array) */
+ TransCon con; /* transformed constraint */
+ TransSnap tsnap;
+ NumInput num; /* numerical input */
+ char redraw; /* redraw flag */
+ float propsize; /* proportional circle radius */
+ char proptext[20]; /* proportional falloff text */
+ float center[3]; /* center of transformation */
+ int center2d[2]; /* center in screen coordinates */
+ short imval[2]; /* initial mouse position */
+ short shiftmval[2]; /* mouse position when shift was pressed */
+ short idx_max; /* maximum index on the input vector */
+ float snap[3]; /* Snapping Gears */
+
+ float viewmat[4][4]; /* copy from G.vd, prevents feedback, */
+ float viewinv[4][4]; /* and to make sure we don't have to */
+ float persmat[4][4]; /* access G.vd from other space types */
+ float persinv[4][4];
+ short persp;
+ short around;
+ char spacetype; /* spacetype where transforming is */
+
+ float vec[3]; /* translation, to show for widget */
+ float mat[3][3]; /* rot/rescale, to show for widget */
+
+ char *undostr; /* if set, uses this string for undo */
+ float spacemtx[3][3]; /* orientation matrix of the current space */
+ char spacename[32]; /* name of the current space */
+
+ struct Object *poseobj; /* if t->flag & T_POSE, this denotes pose object */
+
+ void *customData; /* Per Transform custom data */
+} TransInfo;
+
+
+/* ******************** Macros & Prototypes *********************** */
+
+/* NUMINPUT FLAGS */
+#define NUM_NULL_ONE 2
+#define NUM_NO_NEGATIVE 4
+#define NUM_NO_ZERO 8
+#define NUM_NO_FRACTION 16
+#define NUM_AFFECT_ALL 32
+
+/* transinfo->state */
+#define TRANS_RUNNING 0
+#define TRANS_CONFIRM 1
+#define TRANS_CANCEL 2
+
+/* transinfo->flag */
+#define T_OBJECT (1 << 0)
+#define T_EDIT (1 << 1)
+#define T_POSE (1 << 2)
+#define T_TEXTURE (1 << 3)
+#define T_CAMERA (1 << 4)
+ // when shift pressed, higher resolution transform. cannot rely on G.qual, need event!
+#define T_SHIFT_MOD (1 << 5)
+ // trans on points, having no rotation/scale
+#define T_POINTS (1 << 6)
+ // for manipulator exceptions, like scaling using center point, drawing help lines
+#define T_USES_MANIPULATOR (1 << 7)
+
+/* restrictions flags */
+#define T_ALL_RESTRICTIONS ((1 << 8)|(1 << 9)|(1 << 10))
+#define T_NO_CONSTRAINT (1 << 8)
+#define T_NULL_ONE (1 << 9)
+#define T_NO_ZERO (1 << 10)
+
+#define T_PROP_EDIT (1 << 11)
+#define T_PROP_CONNECTED (1 << 12)
+
+/* if MMB is pressed or not */
+#define T_MMB_PRESSED (1 << 13)
+
+#define T_V3D_ALIGN (1 << 14)
+#define T_2D_EDIT (1 << 15) /* for 2d views like uv or ipo */
+#define T_CLIP_UV (1 << 16)
+
+#define T_FREE_CUSTOMDATA (1 << 17)
+
+/* ******************************************************************************** */
+
+/* transinfo->con->mode */
+#define CON_APPLY 1
+#define CON_AXIS0 2
+#define CON_AXIS1 4
+#define CON_AXIS2 8
+#define CON_SELECT 16
+#define CON_NOFLIP 32 /* does not reorient vector to face viewport when on */
+#define CON_LOCAL 64
+#define CON_USER 128
+
+/* transdata->flag */
+#define TD_SELECTED 1
+#define TD_NOACTION 2
+#define TD_USEQUAT 4
+#define TD_NOTCONNECTED 8
+#define TD_SINGLESIZE 16 /* used for scaling of MetaElem->rad */
+#ifdef WITH_VERSE
+ #define TD_VERSE_OBJECT 32
+ #define TD_VERSE_VERT 64
+#endif
+#define TD_TIMEONLY 128
+#define TD_NOCENTER 256
+
+/* transsnap->status */
+#define SNAP_ON 1
+#define TARGET_INIT 2
+#define POINT_INIT 4
+
+/* transsnap->modePoint */
+#define SNAP_GRID 0
+#define SNAP_GEO 1
+
+/* transsnap->modeTarget */
+#define SNAP_CLOSEST 0
+#define SNAP_CENTER 1
+#define SNAP_MEDIAN 2
+
+void checkFirstTime(void);
+
+void setTransformViewMatrices(TransInfo *t);
+void convertViewVec(TransInfo *t, float *vec, short dx, short dy);
+void projectIntView(TransInfo *t, float *vec, int *adr);
+void projectFloatView(TransInfo *t, float *vec, float *adr);
+
+void convertVecToDisplayNum(float *vec, float *num);
+void convertDisplayNumToVec(float *num, float *vec);
+
+void initWarp(TransInfo *t);
+int Warp(TransInfo *t, short mval[2]);
+
+void initShear(TransInfo *t);
+int handleEventShear(TransInfo *t, unsigned short evenl, short val);
+int Shear(TransInfo *t, short mval[2]);
+
+void initResize(TransInfo *t);
+int Resize(TransInfo *t, short mval[2]);
+
+void initTranslation(TransInfo *t);
+int Translation(TransInfo *t, short mval[2]);
+
+void initToSphere(TransInfo *t);
+int ToSphere(TransInfo *t, short mval[2]);
+
+void initRotation(TransInfo *t);
+int Rotation(TransInfo *t, short mval[2]);
+
+void initShrinkFatten(TransInfo *t);
+int ShrinkFatten(TransInfo *t, short mval[2]);
+
+void initTilt(TransInfo *t);
+int Tilt(TransInfo *t, short mval[2]);
+
+void initCurveShrinkFatten(TransInfo *t);
+int CurveShrinkFatten(TransInfo *t, short mval[2]);
+
+void initTrackball(TransInfo *t);
+int Trackball(TransInfo *t, short mval[2]);
+
+void initPushPull(TransInfo *t);
+int PushPull(TransInfo *t, short mval[2]);
+
+void initCrease(TransInfo *t);
+int Crease(TransInfo *t, short mval[2]);
+
+void initBoneSize(TransInfo *t);
+int BoneSize(TransInfo *t, short mval[2]);
+
+void initBoneEnvelope(TransInfo *t);
+int BoneEnvelope(TransInfo *t, short mval[2]);
+
+void initBoneRoll(TransInfo *t);
+int BoneRoll(TransInfo *t, short mval[2]);
+
+void initTimeTranslate(TransInfo *t);
+int TimeTranslate(TransInfo *t, short mval[2]);
+
+void initTimeSlide(TransInfo *t);
+int TimeSlide(TransInfo *t, short mval[2]);
+
+void initTimeScale(TransInfo *t);
+int TimeScale(TransInfo *t, short mval[2]);
+
+/*********************** transform_conversions.c ********** */
+struct ListBase;
+void flushTransIpoData(TransInfo *t);
+void flushTransUVs(TransInfo *t);
+int clipUVTransform(TransInfo *t, float *vec, int resize);
+
+/*********************** exported from transform_manipulator.c ********** */
+void draw_manipulator_ext(struct ScrArea *sa, int type, char axis, int col, float vec[3], float mat[][3]);
+int calc_manipulator_stats(struct ScrArea *sa);
+float get_drawsize(struct View3D *v3d);
+
+/*********************** TransData Creation and General Handling *********** */
+void createTransData(TransInfo *t);
+void sort_trans_data_dist(TransInfo *t);
+void add_tdi_poin(float *poin, float *old, float delta);
+void special_aftertrans_update(TransInfo *t);
+
+/* auto-keying stuff used by special_aftertrans_update */
+void autokeyframe_ob_cb_func(struct Object *ob, int tmode);
+void autokeyframe_pose_cb_func(struct Object *ob, int tmode, short targetless_ik);
+
+/*********************** Constraints *****************************/
+
+void getConstraintMatrix(TransInfo *t);
+void setConstraint(TransInfo *t, float space[3][3], int mode, const char text[]);
+void setLocalConstraint(TransInfo *t, int mode, const char text[]);
+void setUserConstraint(TransInfo *t, int mode, const char text[]);
+
+void constraintNumInput(TransInfo *t, float vec[3]);
+
+void getConstraintMatrix(TransInfo *t);
+int isLockConstraint(TransInfo *t);
+int getConstraintSpaceDimension(TransInfo *t);
+char constraintModeToChar(TransInfo *t);
+
+void startConstraint(TransInfo *t);
+void stopConstraint(TransInfo *t);
+
+void initSelectConstraint(TransInfo *t, float mtx[3][3]);
+void selectConstraint(TransInfo *t);
+void postSelectConstraint(TransInfo *t);
+
+void setNearestAxis(TransInfo *t);
+
+/*********************** Snapping ********************************/
+
+typedef enum {
+ NO_GEARS = 0,
+ BIG_GEARS = 1,
+ SMALL_GEARS = 2
+} GearsType;
+
+void snapGrid(TransInfo *t, float *val);
+void snapGridAction(TransInfo *t, float *val, GearsType action);
+
+void initSnapping(struct TransInfo *t);
+void applySnapping(TransInfo *t, float *vec);
+void resetSnapping(TransInfo *t);
+int handleSnapping(TransInfo *t, int event);
+void drawSnapping(TransInfo *t);
+
+/*********************** Generics ********************************/
+
+void initTrans(TransInfo *t);
+void initTransModeFlags(TransInfo *t, int mode);
+void postTrans (TransInfo *t);
+
+void drawLine(float *center, float *dir, char axis, short options);
+
+/* DRAWLINE options flags */
+#define DRAWLIGHT 1
+#define DRAWDASHED 2
+#define DRAWBOLD 4
+
+void applyTransObjects(TransInfo *t);
+void restoreTransObjects(TransInfo *t);
+void recalcData(TransInfo *t);
+
+void calculateCenter(TransInfo *t);
+void calculateCenter2D(TransInfo *t);
+void calculateCenterBound(TransInfo *t);
+void calculateCenterMedian(TransInfo *t);
+void calculateCenterCursor(TransInfo *t);
+
+void calculateCenterCursor2D(TransInfo *t);
+void calculatePropRatio(TransInfo *t);
+
+void getViewVector(float coord[3], float vec[3]);
+
+TransInfo * BIF_GetTransInfo(void);
+
+/*********************** NumInput ********************************/
+
+void outputNumInput(NumInput *n, char *str);
+short hasNumInput(NumInput *n);
+void applyNumInput(NumInput *n, float *vec);
+char handleNumInput(NumInput *n, unsigned short event);
+
+#endif
+
diff --git a/source/blender/makesdna/CMakeLists.txt b/source/blender/makesdna/CMakeLists.txt
new file mode 100644
index 00000000000..0311c5f0e5a
--- /dev/null
+++ b/source/blender/makesdna/CMakeLists.txt
@@ -0,0 +1,30 @@
+# $Id$
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2006, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Jacques Beaurain.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+
+SUBDIRS(intern)
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
new file mode 100644
index 00000000000..d939d0dc879
--- /dev/null
+++ b/source/blender/makesdna/DNA_ID.h
@@ -0,0 +1,229 @@
+/**
+ * blenlib/DNA_ID.h (mar-2001 nzc)
+ *
+ * ID and Library types, which are fundamental for sdna,
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef DNA_ID_H
+#define DNA_ID_H
+
+#include "DNA_listBase.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct Library;
+struct FileData;
+struct ID;
+
+typedef struct IDPropertyData {
+ void *pointer;
+ ListBase group;
+ int val, pad;
+} IDPropertyData;
+
+typedef struct IDProperty {
+ struct IDProperty *next, *prev;
+ char name[32];
+ char type, subtype;
+ short flag;
+ int saved; /*saved is used to indicate if this struct has been saved yet.
+ seemed like a good idea as a pad var was needed anyway :)*/
+ IDPropertyData data; /* note, alignment for 64 bits */
+ int len; /* array length, also (this is important!) string length + 1.
+ the idea is to be able to reuse array realloc functions on strings.*/
+ /*totallen is total length of allocated array/string, including a buffer.
+ Note that the buffering is mild; the code comes from python's list implementation.*/
+ int totallen; /*strings and arrays are both buffered, though the buffer isn't
+ saved.*/
+} IDProperty;
+
+#define MAX_IDPROP_NAME 32
+#define DEFAULT_ALLOC_FOR_NULL_STRINGS 64
+
+/*->type*/
+#define IDP_STRING 0
+#define IDP_INT 1
+#define IDP_FLOAT 2
+#define IDP_ARRAY 5
+#define IDP_GROUP 6
+/*the ID link property type hasn't been implemented yet, this will require
+ some cleanup of blenkernel, most likely.*/
+#define IDP_ID 7
+
+/*add any future new id property types here.*/
+
+/* watch it: Sequence has identical beginning. */
+/**
+ * ID is the first thing included in all serializable types. It
+ * provides a common handle to place all data in double-linked lists.
+ * */
+
+/* There's a nasty circular dependency here.... void* to the rescue! I
+ * really wonder why this is needed. */
+typedef struct ID {
+ void *next, *prev;
+ struct ID *newid;
+ struct Library *lib;
+ char name[24];
+ short us;
+ /**
+ * LIB_... flags report on status of the datablock this ID belongs
+ * to.
+ */
+ short flag;
+ int icon_id;
+ IDProperty *properties;
+} ID;
+
+/**
+ * For each library file used, a Library struct is added to Main
+ * WARNING: readfile.c, expand_doit() reads this struct without DNA check!
+ */
+typedef struct Library {
+ ID id;
+ ID *idblock;
+ struct FileData *filedata;
+ char name[240]; /* reveiled in the UI, can store relative path */
+ char filename[240]; /* expanded name, not relative, used while reading */
+ int tot, pad; /* tot, idblock and filedata are only fo read and write */
+ struct Library *parent; /* for outliner, showing dependency */
+} Library;
+
+#define PREVIEW_MIPMAPS 2
+#define PREVIEW_MIPMAP_ZERO 0
+#define PREVIEW_MIPMAP_LARGE 1
+
+typedef struct PreviewImage {
+ unsigned int w[2];
+ unsigned int h[2];
+ short changed[2];
+ short pad0, pad1;
+ unsigned int * rect[2];
+} PreviewImage;
+
+/**
+ * Defines for working with IDs.
+ *
+ * The tags represent types! This is a dirty way of enabling RTTI. The
+ * sig_byte end endian defines aren't really used much.
+ *
+ **/
+
+#if defined(__sgi) || defined(__sparc) || defined(__sparc__) || defined (__PPC__) || defined (__ppc__) || defined (__BIG_ENDIAN__)
+/* big endian */
+#define MAKE_ID2(c, d) ( (c)<<8 | (d) )
+#define MOST_SIG_BYTE 0
+#define BBIG_ENDIAN
+#else
+/* little endian */
+#define MAKE_ID2(c, d) ( (d)<<8 | (c) )
+#define MOST_SIG_BYTE 1
+#define BLITTLE_ENDIAN
+#endif
+
+/* ID from database */
+#define ID_SCE MAKE_ID2('S', 'C')
+#define ID_LI MAKE_ID2('L', 'I')
+#define ID_OB MAKE_ID2('O', 'B')
+#define ID_ME MAKE_ID2('M', 'E')
+#define ID_CU MAKE_ID2('C', 'U')
+#define ID_MB MAKE_ID2('M', 'B')
+#define ID_MA MAKE_ID2('M', 'A')
+#define ID_TE MAKE_ID2('T', 'E')
+#define ID_IM MAKE_ID2('I', 'M')
+#define ID_IK MAKE_ID2('I', 'K')
+#define ID_WV MAKE_ID2('W', 'V')
+#define ID_LT MAKE_ID2('L', 'T')
+#define ID_SE MAKE_ID2('S', 'E')
+#define ID_LF MAKE_ID2('L', 'F')
+#define ID_LA MAKE_ID2('L', 'A')
+#define ID_CA MAKE_ID2('C', 'A')
+#define ID_IP MAKE_ID2('I', 'P')
+#define ID_KE MAKE_ID2('K', 'E')
+#define ID_WO MAKE_ID2('W', 'O')
+#define ID_SCR MAKE_ID2('S', 'R')
+#define ID_VF MAKE_ID2('V', 'F')
+#define ID_TXT MAKE_ID2('T', 'X')
+#define ID_SO MAKE_ID2('S', 'O')
+#define ID_GR MAKE_ID2('G', 'R')
+#define ID_ID MAKE_ID2('I', 'D')
+#define ID_AR MAKE_ID2('A', 'R')
+#define ID_AC MAKE_ID2('A', 'C')
+#define ID_SCRIPT MAKE_ID2('P', 'Y')
+#define ID_NT MAKE_ID2('N', 'T')
+#define ID_BR MAKE_ID2('B', 'R')
+
+ /* NOTE! Fake IDs, needed for g.sipo->blocktype or outliner */
+#define ID_SEQ MAKE_ID2('S', 'Q')
+ /* constraint */
+#define ID_CO MAKE_ID2('C', 'O')
+ /* pose (action channel, used to be ID_AC in code, so we keep code for backwards compat) */
+#define ID_PO MAKE_ID2('A', 'C')
+ /* used in outliner... */
+#define ID_NLA MAKE_ID2('N', 'L')
+ /* fluidsim Ipo */
+#define ID_FLUIDSIM MAKE_ID2('F', 'S')
+
+
+/*#ifdef WITH_VERSE*/
+#define ID_VS MAKE_ID2('V', 'S') /* fake id for VerseSession, needed for outliner */
+#define ID_VN MAKE_ID2('V', 'N') /* fake id for VerseNode, needed for outliner */
+#define ID_MS MAKE_ID2('M', 'S') /* fake id for VerseServer root entry, needed for outliner */
+#define ID_SS MAKE_ID2('S', 'S') /* fake id for VerseServer entry, needed for ountliner */
+/*#endif*/
+
+
+/* id->flag: set frist 8 bits always at zero while reading */
+#define LIB_LOCAL 0
+#define LIB_EXTERN 1
+#define LIB_INDIRECT 2
+#define LIB_TEST 8
+#define LIB_TESTEXT 9
+#define LIB_TESTIND 10
+#define LIB_READ 16
+#define LIB_NEEDLINK 32
+
+#define LIB_NEW 256
+#define LIB_FAKEUSER 512
+/* free test flag */
+#define LIB_DOIT 1024
+/* */
+#define LIB_APPEND_TAG 2048
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h
new file mode 100644
index 00000000000..3c5ef7c94e6
--- /dev/null
+++ b/source/blender/makesdna/DNA_action_types.h
@@ -0,0 +1,225 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Original design: Reevan McKay
+ * Contributor(s): Full recode, Ton Roosendaal, Crete 2005
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+
+#ifndef DNA_ACTION_TYPES_H
+#define DNA_ACTION_TYPES_H
+
+#include "DNA_listBase.h"
+#include "DNA_ID.h"
+#include "DNA_view2d_types.h"
+
+struct SpaceLink;
+struct Object;
+
+/* PoseChannel stores the results of Actions (ipos) and transform information
+ with respect to the restposition of Armature bones */
+
+typedef struct bPoseChannel {
+ struct bPoseChannel *next, *prev;
+ ListBase constraints;/* Constraints that act on this PoseChannel */
+ char name[32]; /* Channels need longer names than normal blender objects */
+
+ short flag; /* dynamic, for detecting transform changes */
+ short constflag; /* for quick detecting which constraints affect this channel */
+ short ikflag; /* settings for IK bones */
+ short selectflag; /* copy of bone flag, so you can work with library armatures */
+ short protectflag; /* protect channels from being transformed */
+ short pad2;
+
+ int pathlen; /* for drawing paths, the amount of frames */
+ int pathsf; /* for drawing paths, the start frame number */
+ int pathef; /* for drawing paths, the end frame number */
+
+ struct Bone *bone; /* set on read file or rebuild pose */
+ struct bPoseChannel *parent; /* set on read file or rebuild pose */
+ struct bPoseChannel *child; /* set on read file or rebuild pose, the 'ik' child, for b-bones */
+ struct ListBase iktree; /* only while evaluating pose */
+
+ /* only while deform, stores precalculated b_bone deform mats,
+ dual quaternions */
+ void *b_bone_mats;
+ void *dual_quat;
+ void *b_bone_dual_quats;
+
+ float loc[3]; /* written in by actions or transform */
+ float size[3];
+ float quat[4];
+
+ float chan_mat[4][4]; /* matrix result of loc/quat/size , and where we put deform in, see next line */
+ float pose_mat[4][4]; /* constraints accumulate here. in the end, pose_mat = bone->arm_mat * chan_mat */
+ float constinv[4][4]; /* inverse result of constraints. doesn't include effect of restposition, parent, and local transform*/
+
+ float pose_head[3]; /* actually pose_mat[3] */
+ float pose_tail[3]; /* also used for drawing help lines... */
+
+ float limitmin[3], limitmax[3]; /* DOF constraint */
+ float stiffness[3]; /* DOF stiffness */
+ float ikstretch;
+
+ float *path; /* totpath x 3 x float */
+ struct Object *custom; /* draws custom object instead of this channel */
+
+} bPoseChannel;
+
+/* Pose-Object. It is only found under ob->pose. It is not library data, even
+ * though there is a define for it (hack for the outliner).
+ */
+typedef struct bPose {
+ ListBase chanbase; /* list of pose channels */
+ short flag, proxy_layer; /* proxy layer: copy from armature, gets synced */
+ float ctime; /* local action time of this pose */
+ float stride_offset[3]; /* applied to object */
+ float cyclic_offset[3]; /* result of match and cycles, applied in where_is_pose() */
+} bPose;
+
+/* Action Channels belong to Actions. They are linked with an IPO block, and can also own
+ * Constraint Channels in certain situations.
+ */
+typedef struct bActionChannel {
+ struct bActionChannel *next, *prev;
+ struct Ipo *ipo; /* IPO block this action channel references */
+ ListBase constraintChannels; /* Constraint Channels (when Action Channel represents an Object or Bone) */
+
+ int flag; /* settings accessed via bitmapping */
+ char name[32]; /* channel name */
+ int reserved1;
+} bActionChannel;
+
+/* Action. A recyclable block that contains a series of Action Channels (ipo), which define
+ * a clip of reusable animation for use in the NLA.
+ */
+typedef struct bAction {
+ ID id;
+ ListBase chanbase; /* Action Channels in this Action */
+} bAction;
+
+/* Action Editor Space. This is defined here instead of in DNA_space_types.h */
+typedef struct SpaceAction {
+ struct SpaceLink *next, *prev;
+ int spacetype;
+ float blockscale;
+ struct ScrArea *area;
+
+ short blockhandler[8];
+
+ View2D v2d;
+
+ bAction *action; /* the currently active action */
+ short flag, autosnap; /* flag: bitmapped settings; autosnap: automatic keyframe snapping mode */
+ short pin, actnr, lock; /* pin: keep showing current action; actnr: used for finding chosen action from menu; lock: lock time to other windows */
+ short actwidth; /* width of the left-hand side name panel (in pixels?) */
+ float timeslide; /* for Time-Slide transform mode drawing - current frame? */
+} SpaceAction;
+
+/* Action Channel flags */
+typedef enum ACHAN_FLAG {
+ ACHAN_SELECTED = (1<<0),
+ ACHAN_HILIGHTED = (1<<1),
+ ACHAN_HIDDEN = (1<<2),
+ ACHAN_PROTECTED = (1<<3),
+ ACHAN_EXPANDED = (1<<4),
+ ACHAN_SHOWIPO = (1<<5),
+ ACHAN_SHOWCONS = (1<<6),
+ ACHAN_MOVED = (1<<31),
+} ACHAN_FLAG;
+
+/* SpaceAction flag */
+typedef enum SACTION_FLAG {
+ /* during transform */
+ SACTION_MOVING = (1<<0),
+ /* show sliders (if relevant) */
+ SACTION_SLIDERS = (1<<1),
+ /* draw time in seconds instead of time in frames */
+ SACTION_DRAWTIME = (1<<2)
+} SACTION_FLAG;
+
+/* SpaceAction AutoSnap Settings (also used by SpaceNLA) */
+typedef enum SACTSNAP_MODES {
+ /* no auto-snap */
+ SACTSNAP_OFF = 0,
+ /* snap to 1.0 frame/second intervals */
+ SACTSNAP_STEP,
+ /* snap to actual frames/seconds (nla-action time) */
+ SACTSNAP_FRAME,
+ /* snap to nearest marker */
+ SACTSNAP_MARKER,
+} SACTSNAP_MODES;
+
+/* Pose->flag */
+typedef enum POSE_FLAG {
+ /* results in armature_rebuild_pose being called */
+ POSE_RECALC = (1<<0),
+ /* prevents any channel from getting overridden by anim from IPO */
+ POSE_LOCKED = (1<<1),
+ /* clears the POSE_LOCKED flag for the next time the pose is evaluated */
+ POSE_DO_UNLOCK = (1<<2)
+} POSE_FLAG;
+
+/* PoseChannel (transform) flags */
+enum {
+ POSE_LOC = 0x0001,
+ POSE_ROT = 0x0002,
+ POSE_SIZE = 0x0004,
+ POSE_IK_MAT = 0x0008,
+ POSE_UNUSED2 = 0x0010,
+ POSE_UNUSED3 = 0x0020,
+ POSE_UNUSED4 = 0x0040,
+ POSE_UNUSED5 = 0x0080,
+ POSE_HAS_IK = 0x0100,
+ POSE_CHAIN = 0x0200,
+ POSE_DONE = 0x0400,
+ POSE_KEY = 0x1000,
+ POSE_STRIDE = 0x2000
+};
+
+/* PoseChannel constflag (constraint detection) */
+typedef enum PCHAN_CONSTFLAG {
+ PCHAN_HAS_IK = (1<<0),
+ PCHAN_HAS_CONST = (1<<1),
+ /* only used for drawing Posemode, not stored in channel */
+ PCHAN_HAS_ACTION = (1<<2),
+ PCHAN_HAS_TARGET = (1<<3),
+ /* only for drawing Posemode too */
+ PCHAN_HAS_STRIDE = (1<<4)
+} PCHAN_CONSTFLAG;
+
+/* PoseChannel->ikflag */
+typedef enum PCHAN_IKFLAG {
+ BONE_IK_NO_XDOF = (1<<0),
+ BONE_IK_NO_YDOF = (1<<1),
+ BONE_IK_NO_ZDOF = (1<<2),
+
+ BONE_IK_XLIMIT = (1<<3),
+ BONE_IK_YLIMIT = (1<<4),
+ BONE_IK_ZLIMIT = (1<<5)
+} PCHAN_IKFLAG;
+
+
+#endif
+
diff --git a/source/blender/makesdna/DNA_actuator_types.h b/source/blender/makesdna/DNA_actuator_types.h
new file mode 100644
index 00000000000..0531e70bb97
--- /dev/null
+++ b/source/blender/makesdna/DNA_actuator_types.h
@@ -0,0 +1,395 @@
+/**
+ * blenlib/DNA_actuator_types.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef DNA_ACTUATOR_TYPES_H
+#define DNA_ACTUATOR_TYPES_H
+
+struct Object;
+struct Mesh;
+struct Scene;
+struct Group;
+
+/* ****************** ACTUATORS ********************* */
+
+/* unused now, moved to editobjectactuator in 2.02. Still needed for dna */
+typedef struct bAddObjectActuator {
+ int time, pad;
+ struct Object *ob;
+} bAddObjectActuator;
+
+typedef struct bActionActuator {
+ struct bAction *act; /* Pointer to action */
+ short type, flag; /* Playback type */
+ int sta, end; /* Start & End frames */
+ char name[32]; /* For property-driven playback */
+ int blendin; /* Number of frames of blending */
+ short priority; /* Execution priority */
+ short strideaxis; /* Displacement axis */
+ float stridelength; /* Displacement incurred by cycle */
+} bActionActuator;
+
+typedef struct bSoundActuator {
+ short flag, sndnr;
+ int sta, end;
+ short pad1[2];
+ struct bSound *sound;
+ short type, makecopy;
+ short copymade, pad2[1];
+} bSoundActuator;
+
+typedef struct bCDActuator {
+ short flag, sndnr;
+ int sta, end;
+ short type, track;
+ float volume;
+} bCDActuator;
+
+typedef struct bEditObjectActuator {
+ int time;
+ short type, flag;
+ struct Object *ob;
+ struct Mesh *me;
+ char name[32];
+ float linVelocity[3]; /* initial lin. velocity on creation */
+ short localflag; /* flag for the lin. vel: apply locally */
+ short pad;
+} bEditObjectActuator;
+
+typedef struct bSceneActuator {
+ short type, flag;
+ int pad;
+ struct Scene *scene;
+ struct Object *camera;
+} bSceneActuator;
+
+typedef struct bPropertyActuator {
+ int flag, type;
+ char name[32], value[32];
+ struct Object *ob;
+} bPropertyActuator;
+
+typedef struct bObjectActuator {
+ int flag, type;
+ float forceloc[3], forcerot[3];
+ float loc[3], rot[3];
+ float dloc[3], drot[3];
+ float linearvelocity[3], angularvelocity[3];
+} bObjectActuator;
+
+typedef struct bIpoActuator {
+ short flag, type;
+ int sta, end;
+ char name[32];
+
+ short pad1, cur, butsta, butend;
+
+} bIpoActuator;
+
+typedef struct bCameraActuator {
+ struct Object *ob;
+ float height, min, max;
+ float fac;
+ short flag, axis;
+ float visifac;
+} bCameraActuator ;
+
+typedef struct bConstraintActuator {
+ short flag, damp;
+ float slow;
+ float minloc[3], maxloc[3];
+ float minrot[3], maxrot[3];
+} bConstraintActuator;
+
+typedef struct bGroupActuator {
+ short flag, type;
+ int sta, end;
+ char name[32]; /* property or groupkey */
+
+ short pad[3], cur, butsta, butend;/* not referenced, can remove? */
+ struct Group *group; /* only during game */
+
+} bGroupActuator;
+
+/* I added a few extra fields here, to facilitate conversions */
+typedef struct bRandomActuator {
+ int seed;
+ int distribution;
+ int int_arg_1;
+ int int_arg_2;
+ float float_arg_1;
+ float float_arg_2;
+ char propname[32];
+} bRandomActuator;
+
+typedef struct bMessageActuator {
+ /**
+ * Send to all objects with this propertyname. Empty to broadcast.
+ */
+ char toPropName[32];
+
+ /**
+ * (Possible future use) pointer to a single destination object.
+ */
+ struct Object *toObject;
+
+ /**
+ * Message Subject to send.
+ */
+ char subject[32];
+
+ /**
+ * bodyType is either 'User defined text' or PropName
+ */
+ short bodyType, pad1;
+ int pad2;
+
+ /**
+ * Either User Defined Text or our PropName to send value of
+ */
+ char body[32];
+} bMessageActuator;
+
+typedef struct bGameActuator {
+ short flag, type;
+ int sta, end;
+ char filename[64];
+ char loadaniname[64];
+} bGameActuator;
+
+typedef struct bVisibilityActuator {
+ /** bit 0: Is this object visible? */
+ int flag;
+} bVisibilityActuator;
+
+typedef struct bActuator {
+ struct bActuator *next, *prev, *mynew;
+ short type;
+ /**
+ * Tells what type of actuator data <data> holds.
+ */
+ short flag;
+ short otype, go;
+ char name[32];
+
+ /**
+ * Data must point to an object actuator type struct.
+ */
+ void *data;
+
+ /**
+ * For ipo's and props: to find out which object the actuator
+ * belongs to */
+ struct Object *ob;
+
+} bActuator;
+
+typedef struct FreeCamera {
+ float mass, accelleration;
+ float maxspeed, maxrotspeed, maxtiltspeed;
+ int flag;
+ float rotdamp, tiltdamp, speeddamp, pad;
+} FreeCamera;
+
+/* objectactuator->flag */
+#define ACT_FORCE_LOCAL 1
+#define ACT_TORQUE_LOCAL 2
+#define ACT_DLOC_LOCAL 4
+#define ACT_DROT_LOCAL 8
+#define ACT_LIN_VEL_LOCAL 16
+#define ACT_ANG_VEL_LOCAL 32
+//#define ACT_ADD_LIN_VEL_LOCAL 64
+#define ACT_ADD_LIN_VEL 64
+
+#define ACT_OBJECT_FORCE 0
+#define ACT_OBJECT_TORQUE 1
+#define ACT_OBJECT_DLOC 2
+#define ACT_OBJECT_DROT 3
+#define ACT_OBJECT_LINV 4
+#define ACT_OBJECT_ANGV 5
+
+/* actuator->type */
+#define ACT_OBJECT 0
+#define ACT_IPO 1
+#define ACT_LAMP 2
+#define ACT_CAMERA 3
+#define ACT_MATERIAL 4
+#define ACT_SOUND 5
+#define ACT_PROPERTY 6
+ /* these two obsolete since 2.02 */
+#define ACT_ADD_OBJECT 7
+#define ACT_END_OBJECT 8
+
+#define ACT_CONSTRAINT 9
+#define ACT_EDIT_OBJECT 10
+#define ACT_SCENE 11
+#define ACT_GROUP 12
+#define ACT_RANDOM 13
+#define ACT_MESSAGE 14
+#define ACT_ACTION 15 /* __ NLA */
+#define ACT_CD 16
+#define ACT_GAME 17
+#define ACT_VISIBILITY 18
+
+/* actuator flag */
+#define ACT_SHOW 1
+#define ACT_DEL 2
+#define ACT_NEW 4
+
+/* link codes */
+#define LINK_SENSOR 0
+#define LINK_CONTROLLER 1
+#define LINK_ACTUATOR 2
+
+/* keyboardsensor->type */
+#define SENS_ALL_KEYS 1
+
+/* actionactuator->type */
+#define ACT_ACTION_PLAY 0
+#define ACT_ACTION_PINGPONG 1
+#define ACT_ACTION_FLIPPER 2
+#define ACT_ACTION_LOOP_STOP 3
+#define ACT_ACTION_LOOP_END 4
+#define ACT_ACTION_KEY2KEY 5
+#define ACT_ACTION_FROM_PROP 6
+#define ACT_ACTION_MOTION 7
+
+/* ipoactuator->type */
+#define ACT_IPO_PLAY 0
+#define ACT_IPO_PINGPONG 1
+#define ACT_IPO_FLIPPER 2
+#define ACT_IPO_LOOP_STOP 3
+#define ACT_IPO_LOOP_END 4
+#define ACT_IPO_KEY2KEY 5
+#define ACT_IPO_FROM_PROP 6
+
+/* groupactuator->type */
+#define ACT_GROUP_PLAY 0
+#define ACT_GROUP_PINGPONG 1
+#define ACT_GROUP_FLIPPER 2
+#define ACT_GROUP_LOOP_STOP 3
+#define ACT_GROUP_LOOP_END 4
+#define ACT_GROUP_FROM_PROP 5
+#define ACT_GROUP_SET 6
+
+/* ipoactuator->flag */
+#define ACT_IPOFORCE (1 << 0)
+#define ACT_IPOEND (1 << 1)
+#define ACT_IPOFORCE_LOCAL (1 << 2)
+#define ACT_IPOCHILD (1 << 4)
+
+/* ipoactuator->flag for k2k */
+#define ACT_K2K_PREV 1
+#define ACT_K2K_CYCLIC 2
+#define ACT_K2K_PINGPONG 4
+#define ACT_K2K_HOLD 8
+
+/* property actuator->type */
+#define ACT_PROP_ASSIGN 0
+#define ACT_PROP_ADD 1
+#define ACT_PROP_COPY 2
+
+/* constraint flag */
+#define ACT_CONST_LOCX 1
+#define ACT_CONST_LOCY 2
+#define ACT_CONST_LOCZ 4
+#define ACT_CONST_ROTX 8
+#define ACT_CONST_ROTY 16
+#define ACT_CONST_ROTZ 32
+
+/* editObjectActuator->type */
+#define ACT_EDOB_ADD_OBJECT 0
+#define ACT_EDOB_END_OBJECT 1
+#define ACT_EDOB_REPLACE_MESH 2
+#define ACT_EDOB_TRACK_TO 3
+#define ACT_EDOB_MAKE_CHILD 4
+#define ACT_EDOB_END_CHILD 5
+
+/* editObjectActuator->flag */
+#define ACT_TRACK_3D 1
+
+/* SceneActuator->type */
+#define ACT_SCENE_RESTART 0
+#define ACT_SCENE_SET 1
+#define ACT_SCENE_CAMERA 2
+#define ACT_SCENE_ADD_FRONT 3
+#define ACT_SCENE_ADD_BACK 4
+#define ACT_SCENE_REMOVE 5
+#define ACT_SCENE_SUSPEND 6
+#define ACT_SCENE_RESUME 7
+
+
+/* randomAct->distribution */
+#define ACT_RANDOM_BOOL_CONST 0
+#define ACT_RANDOM_BOOL_UNIFORM 1
+#define ACT_RANDOM_BOOL_BERNOUILLI 2
+#define ACT_RANDOM_INT_CONST 3
+#define ACT_RANDOM_INT_UNIFORM 4
+#define ACT_RANDOM_INT_POISSON 5
+#define ACT_RANDOM_FLOAT_CONST 6
+#define ACT_RANDOM_FLOAT_UNIFORM 7
+#define ACT_RANDOM_FLOAT_NORMAL 8
+#define ACT_RANDOM_FLOAT_NEGATIVE_EXPONENTIAL 9
+
+/* SoundActuator->type */
+#define ACT_SND_PLAY_STOP_SOUND 0
+#define ACT_SND_PLAY_END_SOUND 1
+#define ACT_SND_LOOP_STOP_SOUND 2
+#define ACT_SND_LOOP_END_SOUND 3
+#define ACT_SND_LOOP_BIDIRECTIONAL_SOUND 4
+#define ACT_SND_LOOP_BIDIRECTIONAL_STOP_SOUND 5
+
+/* messageactuator->type */
+#define ACT_MESG_MESG 0
+#define ACT_MESG_PROP 1
+
+/* cdactuator->type */
+#define ACT_CD_PLAY_ALL 0
+#define ACT_CD_PLAY_TRACK 1
+#define ACT_CD_LOOP_TRACK 2
+#define ACT_CD_VOLUME 3
+#define ACT_CD_STOP 4
+#define ACT_CD_PAUSE 5
+#define ACT_CD_RESUME 6
+
+/* gameactuator->type */
+#define ACT_GAME_LOAD 0
+#define ACT_GAME_START 1
+#define ACT_GAME_RESTART 2
+#define ACT_GAME_QUIT 3
+
+/* visibilityact->flag */
+/* Set means the object will become invisible */
+#define ACT_VISIBILITY_INVISIBLE (1 << 0)
+
+#endif
+
diff --git a/source/blender/makesdna/DNA_armature_types.h b/source/blender/makesdna/DNA_armature_types.h
new file mode 100644
index 00000000000..9f64a31c90c
--- /dev/null
+++ b/source/blender/makesdna/DNA_armature_types.h
@@ -0,0 +1,154 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Full recode, Ton Roosendaal, Crete 2005
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef DNA_ARMATURE_TYPES_H
+#define DNA_ARMATURE_TYPES_H
+
+#include "DNA_listBase.h"
+#include "DNA_ID.h"
+
+/* this system works on different transformation space levels;
+
+1) Bone Space; with each Bone having own (0,0,0) origin
+2) Armature Space; the rest position, in Object space, Bones Spaces are applied hierarchical
+3) Pose Space; the animation position, in Object space
+4) World Space; Object matrix applied to Pose or Armature space
+
+*/
+
+typedef struct Bone {
+ struct Bone *next, *prev; /* Next/prev elements within this list */
+ struct Bone *parent; /* Parent (ik parent if appropriate flag is set */
+ ListBase childbase; /* Children */
+ char name[32]; /* Name of the bone - must be unique within the armature */
+
+ float roll; /* roll is input for editmode, length calculated */
+ float head[3];
+ float tail[3]; /* head/tail and roll in Bone Space */
+ float bone_mat[3][3]; /* rotation derived from head/tail/roll */
+
+ int flag;
+
+ float arm_head[3];
+ float arm_tail[3]; /* head/tail and roll in Armature Space (rest pos) */
+ float arm_mat[4][4]; /* matrix: (bonemat(b)+head(b))*arm_mat(b-1), rest pos*/
+
+ float dist, weight; /* dist, weight: for non-deformgroup deforms */
+ float xwidth, length, zwidth; /* width: for block bones. keep in this order, transform! */
+ float ease1, ease2; /* length of bezier handles */
+ float rad_head, rad_tail; /* radius for head/tail sphere, defining deform as well, parent->rad_tip overrides rad_head*/
+
+ float size[3]; /* patch for upward compat, UNUSED! */
+ short layer;
+ short segments; /* for B-bones */
+}Bone;
+
+typedef struct bArmature {
+ ID id;
+ ListBase bonebase;
+ ListBase chainbase;
+ int flag;
+ int drawtype;
+ short deformflag;
+ short pathflag;
+ short layer, layer_protected; /* for buttons to work, both variables in this order together */
+ short ghostep, ghostsize; /*number of frames to ghosts to show, and step between them */
+ short ghosttype, pathsize; /* ghost drawing options and number of frames between points of path */
+ int ghostsf, ghostef; /* start and end frames of ghost-drawing range */
+ int pathsf, pathef; /* start and end frames of path-calculation range for all bones */
+}bArmature;
+
+/* armature->flag */
+/* dont use bit 7, was saved in files to disable stuff */
+
+/* armature->flag */
+#define ARM_RESTPOS 0x001
+ /* XRAY is here only for backwards converting */
+#define ARM_DRAWXRAY 0x002
+#define ARM_DRAWAXES 0x004
+#define ARM_DRAWNAMES 0x008
+#define ARM_POSEMODE 0x010
+#define ARM_EDITMODE 0x020
+#define ARM_DELAYDEFORM 0x040
+#define ARM_DONT_USE 0x080
+#define ARM_MIRROR_EDIT 0x100
+#define ARM_AUTO_IK 0x200
+ /* made option negative, for backwards compat */
+#define ARM_NO_CUSTOM 0x400
+#define ARM_COL_CUSTOM 0x800
+
+/* armature->drawtype */
+#define ARM_OCTA 0
+#define ARM_LINE 1
+#define ARM_B_BONE 2
+#define ARM_ENVELOPE 3
+
+/* armature->deformflag */
+#define ARM_DEF_VGROUP 1
+#define ARM_DEF_ENVELOPE 2
+#define ARM_DEF_QUATERNION 4
+#define ARM_DEF_B_BONE_REST 8
+
+/* armature->pathflag */
+#define ARM_PATH_FNUMS 0x001
+#define ARM_PATH_KFRAS 0x002
+#define ARM_PATH_HEADS 0x004
+
+/* armature->ghosttype */
+#define ARM_GHOST_CUR 0
+#define ARM_GHOST_RANGE 1
+
+/* bone->flag */
+#define BONE_SELECTED 1
+#define BONE_ROOTSEL 2
+#define BONE_TIPSEL 4
+ /* Used instead of BONE_SELECTED during transform */
+#define BONE_TRANSFORM 8
+#define BONE_CONNECTED 16
+ /* 32 used to be quatrot, was always set in files, do not reuse unless you clear it always */
+ /* hidden Bones when drawing Posechannels */
+#define BONE_HIDDEN_P 64
+ /* For detecting cyclic dependancies */
+#define BONE_DONE 128
+ /* active is on mouse clicks only */
+#define BONE_ACTIVE 256
+ /* No parent rotation or scale */
+#define BONE_HINGE 512
+ /* hidden Bones when drawing Armature Editmode */
+#define BONE_HIDDEN_A 1024
+ /* multiplies vgroup with envelope */
+#define BONE_MULT_VG_ENV 2048
+#define BONE_NO_DEFORM 4096
+ /* set to prevent destruction of its unkeyframed pose (after transform) */
+#define BONE_UNKEYED 8192
+ /* set to prevent hinge child bones from influencing the transform center */
+#define BONE_HINGE_CHILD_TRANSFORM 16384
+
+#endif
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
new file mode 100644
index 00000000000..1c272105067
--- /dev/null
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -0,0 +1,91 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef DNA_BRUSH_TYPES_H
+#define DNA_BRUSH_TYPES_H
+
+#include "DNA_ID.h"
+
+#ifndef MAX_MTEX
+#define MAX_MTEX 10
+#endif
+
+struct MTex;
+struct Image;
+
+typedef struct BrushClone {
+ struct Image *image; /* image for clone tool */
+ float offset[2]; /* offset of clone image from canvas */
+ float alpha, pad; /* transparency for drawing of clone image */
+} BrushClone;
+
+typedef struct Brush {
+ ID id;
+
+ short flag, blend; /* general purpose flag, blend mode */
+ int size; /* brush diameter */
+ float innerradius; /* inner radius after which the falloff starts */
+ float spacing; /* spacing of paint operations */
+ float rate; /* paint operations / second (airbrush) */
+
+ float rgb[3]; /* color */
+ float alpha; /* opacity */
+
+ short texact, pad;
+ struct MTex *mtex[10];
+
+ struct BrushClone clone;
+} Brush;
+
+/* Brush.flag */
+#define BRUSH_AIRBRUSH 1
+#define BRUSH_TORUS 2
+#define BRUSH_ALPHA_PRESSURE 4
+#define BRUSH_SIZE_PRESSURE 8
+#define BRUSH_RAD_PRESSURE 16
+#define BRUSH_SPACING_PRESSURE 32
+#define BRUSH_FIXED_TEX 64
+
+/* Brush.blend */
+#define BRUSH_BLEND_MIX 0
+#define BRUSH_BLEND_ADD 1
+#define BRUSH_BLEND_SUB 2
+#define BRUSH_BLEND_MUL 3
+#define BRUSH_BLEND_LIGHTEN 4
+#define BRUSH_BLEND_DARKEN 5
+#define BRUSH_BLEND_ERASE_ALPHA 6
+#define BRUSH_BLEND_ADD_ALPHA 7
+
+#define PAINT_TOOL_DRAW 0
+#define PAINT_TOOL_SOFTEN 1
+#define PAINT_TOOL_SMEAR 2
+#define PAINT_TOOL_CLONE 3
+
+#endif
+
diff --git a/source/blender/makesdna/DNA_camera_types.h b/source/blender/makesdna/DNA_camera_types.h
new file mode 100644
index 00000000000..4cb8ec25ebc
--- /dev/null
+++ b/source/blender/makesdna/DNA_camera_types.h
@@ -0,0 +1,91 @@
+/**
+ * blenlib/DNA_camera_types.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef DNA_CAMERA_TYPES_H
+#define DNA_CAMERA_TYPES_H
+
+#include "DNA_ID.h"
+#include "DNA_scriptlink_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct Ipo;
+struct Object;
+
+typedef struct Camera {
+ ID id;
+
+ short type, flag;
+ float passepartalpha, angle;
+ float clipsta, clipend;
+ float lens, ortho_scale, drawsize;
+ float shiftx, shifty;
+
+ /* yafray: dof params */
+ /* qdn: yafray var 'YF_dofdist' now enabled for defocus composit node as well.
+ The name was not changed so that no other files need to be modified */
+ float YF_dofdist, YF_aperture;
+ short YF_bkhtype, YF_bkhbias;
+ float YF_bkhrot;
+
+ struct Ipo *ipo;
+
+ ScriptLink scriptlink;
+ struct Object *dof_ob;
+} Camera;
+
+/* **************** CAMERA ********************* */
+
+/* type */
+#define CAM_PERSP 0
+#define CAM_ORTHO 1
+
+/* flag */
+#define CAM_SHOWLIMITS 1
+#define CAM_SHOWMIST 2
+#define CAM_SHOWPASSEPARTOUT 4
+#define CAM_SHOWTITLESAFE 8
+#define CAM_SHOWNAME 16
+#define CAM_ANGLETOGGLE 32
+
+/* yafray: dof sampling switch */
+#define CAM_YF_NO_QMC 512
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/source/blender/makesdna/DNA_color_types.h b/source/blender/makesdna/DNA_color_types.h
new file mode 100644
index 00000000000..a4224976f5f
--- /dev/null
+++ b/source/blender/makesdna/DNA_color_types.h
@@ -0,0 +1,81 @@
+/**
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef DNA_COLOR_TYPES_H
+#define DNA_COLOR_TYPES_H
+
+#include "DNA_vec_types.h"
+
+/* general defines for kernel functions */
+#define CM_RESOL 32
+#define CM_TABLE 256
+#define CM_TABLEDIV (1.0f/256.0f)
+
+#define CM_TOT 4
+
+typedef struct CurveMapPoint {
+ float x, y;
+ short flag, shorty; /* shorty for result lookup */
+} CurveMapPoint;
+
+/* curvepoint->flag */
+#define CUMA_SELECT 1
+#define CUMA_VECTOR 2
+
+typedef struct CurveMap {
+ short totpoint, flag;
+
+ float range; /* quick multiply value for reading table */
+ float mintable, maxtable; /* the x-axis range for the table */
+ float ext_in[2], ext_out[2]; /* for extrapolated curves, the direction vector */
+ CurveMapPoint *curve; /* actual curve */
+ CurveMapPoint *table; /* display and evaluate table */
+ CurveMapPoint *premultable; /* for RGB curves, premulled table */
+} CurveMap;
+
+/* cuma->flag */
+#define CUMA_EXTEND_EXTRAPOLATE 1
+
+typedef struct CurveMapping {
+ int flag, cur; /* cur; for buttons, to show active curve */
+
+ rctf curr, clipr; /* current rect, clip rect (is default rect too) */
+
+ CurveMap cm[4]; /* max 4 builtin curves per mapping struct now */
+ float black[3], white[3]; /* black/white point (black[0] abused for current frame) */
+ float bwmul[3], padf; /* black/white point multiply value, for speed */
+} CurveMapping;
+
+/* cumapping->flag */
+#define CUMA_DO_CLIP 1
+#define CUMA_PREMULLED 2
+#define CUMA_DRAW_CFRA 4
+
+#endif
+
diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h
new file mode 100644
index 00000000000..431ef56e1c4
--- /dev/null
+++ b/source/blender/makesdna/DNA_constraint_types.h
@@ -0,0 +1,493 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): 2007, Joshua Leung, major recode
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * Constraint DNA data
+ */
+
+#ifndef DNA_CONSTRAINT_TYPES_H
+#define DNA_CONSTRAINT_TYPES_H
+
+#include "DNA_ID.h"
+#include "DNA_ipo_types.h"
+#include "DNA_listBase.h"
+#include "DNA_object_types.h"
+
+struct Action;
+struct Text;
+
+/* channels reside in Object or Action (ListBase) constraintChannels */
+typedef struct bConstraintChannel {
+ struct bConstraintChannel *next, *prev;
+ Ipo *ipo;
+ short flag;
+ char name[30];
+} bConstraintChannel;
+
+/* A Constraint */
+typedef struct bConstraint {
+ struct bConstraint *next, *prev;
+
+ void *data; /* Constraint data (a valid constraint type) */
+ short type; /* Constraint type */
+ short flag; /* Flag - General Settings */
+
+ char ownspace; /* Space that owner should be evaluated in */
+ char tarspace; /* Space that target should be evaluated in (only used if 1 target) */
+
+ char name[30]; /* Constraint name */
+
+ float enforce; /* Amount of influence exherted by constraint (0.0-1.0) */
+} bConstraint;
+
+
+/* Multiple-target constraints --------------------- */
+
+/* This struct defines a constraint target.
+ * It is used during constraint solving regardless of how many targets the
+ * constraint has.
+ */
+typedef struct bConstraintTarget {
+ struct bConstraintTarget *next, *prev;
+
+ Object *tar; /* object to use as target */
+ char subtarget[32]; /* subtarget - pchan or vgroup name */
+
+ float matrix[4][4]; /* matrix used during constraint solving - should be cleared before each use */
+
+ short space; /* space that target should be evaluated in (overrides bConstraint->tarspace) */
+ short flag; /* runtime settings (for editor, etc.) */
+ short type; /* type of target (B_CONSTRAINT_OB_TYPE) */
+ short pad;
+} bConstraintTarget;
+
+/* bConstraintTarget -> flag */
+typedef enum B_CONSTRAINT_TARGET_FLAG {
+ CONSTRAINT_TAR_TEMP = (1<<0), /* temporary target-struct that needs to be freed after use */
+} B_CONSTRAINT_TARGET_FLAG;
+
+/* bConstraintTarget/bConstraintOb -> type */
+typedef enum B_CONSTRAINT_OB_TYPE {
+ CONSTRAINT_OBTYPE_OBJECT = 1, /* string is "" */
+ CONSTRAINT_OBTYPE_BONE, /* string is bone-name */
+ CONSTRAINT_OBTYPE_VERT, /* string is vertex-group name */
+ CONSTRAINT_OBTYPE_CV /* string is vertex-group name - is not available until curves get vgroups */
+} B_CONSTRAINT_OB_TYPE;
+
+
+
+/* Python Script Constraint */
+typedef struct bPythonConstraint {
+ struct Text *text; /* text-buffer (containing script) to execute */
+ IDProperty *prop; /* 'id-properties' used to store custom properties for constraint */
+
+ int flag; /* general settings/state indicators accessed by bitmapping */
+ int tarnum; /* number of targets - usually only 1-3 are needed */
+
+ ListBase targets; /* a list of targets that this constraint has (bConstraintTarget-s) */
+
+ Object *tar; /* target from previous implementation (version-patch sets this to NULL on file-load) */
+ char subtarget[32]; /* subtarger from previous implentation (version-patch sets this to "" on file-load) */
+} bPythonConstraint;
+
+/* Single-target subobject constraints --------------------- */
+/* Inverse-Kinematics (IK) constraint */
+typedef struct bKinematicConstraint {
+ Object *tar;
+ short iterations; /* Maximum number of iterations to try */
+ short flag; /* Like CONSTRAINT_IK_TIP */
+ int rootbone; /* index to rootbone, if zero go all the way to mother bone */
+ char subtarget[32]; /* String to specify sub-object target */
+
+ Object *poletar; /* Pole vector target */
+ char polesubtarget[32]; /* Pole vector sub-object target */
+ float poleangle; /* Pole vector rest angle */
+
+ float weight; /* Weight of goal in IK tree */
+ float orientweight; /* Amount of rotation a target applies on chain */
+ float grabtarget[3]; /* for target-less IK */
+} bKinematicConstraint;
+
+/* Track To Constraint */
+typedef struct bTrackToConstraint {
+ Object *tar;
+ int reserved1; /* I'll be using reserved1 and reserved2 as Track and Up flags, not sure if that's what they were intented for anyway. Not sure either if it would create backward incompatibility if I were to rename them. - theeth*/
+ int reserved2;
+ int flags;
+ int pad;
+ char subtarget[32];
+} bTrackToConstraint;
+
+/* Copy Rotation Constraint */
+typedef struct bRotateLikeConstraint {
+ Object *tar;
+ int flag;
+ int reserved1;
+ char subtarget[32];
+} bRotateLikeConstraint;
+
+/* Copy Location Constraint */
+typedef struct bLocateLikeConstraint {
+ Object *tar;
+ int flag;
+ int reserved1;
+ char subtarget[32];
+} bLocateLikeConstraint;
+
+/* Floor Constraint */
+typedef struct bMinMaxConstraint {
+ Object *tar;
+ int minmaxflag;
+ float offset;
+ int flag;
+ short sticky, stuck, pad1, pad2; /* for backward compatability */
+ float cache[3];
+ char subtarget[32];
+} bMinMaxConstraint;
+
+/* Copy Scale Constraint */
+typedef struct bSizeLikeConstraint {
+ Object *tar;
+ int flag;
+ int reserved1;
+ char subtarget[32];
+} bSizeLikeConstraint;
+
+/* Action Constraint */
+typedef struct bActionConstraint {
+ Object *tar;
+ short type; /* what transform 'channel' drives the result */
+ short local; /* was used in versions prior to the Constraints recode */
+ int start;
+ int end;
+ float min;
+ float max;
+ int pad;
+ struct bAction *act;
+ char subtarget[32];
+} bActionConstraint;
+
+/* Locked Axis Tracking constraint */
+typedef struct bLockTrackConstraint {
+ Object *tar;
+ int trackflag;
+ int lockflag;
+ char subtarget[32];
+} bLockTrackConstraint;
+
+/* Follow Path constraints */
+typedef struct bFollowPathConstraint {
+ Object *tar; /* Must be path object */
+ float offset; /* Offset in time on the path (in frame) */
+ int followflag;
+ int trackflag;
+ int upflag;
+} bFollowPathConstraint;
+
+/* Stretch to constraint */
+typedef struct bStretchToConstraint {
+ Object *tar;
+ int volmode;
+ int plane;
+ float orglength;
+ float bulge;
+ char subtarget[32];
+} bStretchToConstraint;
+
+/* Rigid Body constraint */
+typedef struct bRigidBodyJointConstraint {
+ Object *tar;
+ Object *child;
+ int type;
+ float pivX;
+ float pivY;
+ float pivZ;
+ float axX;
+ float axY;
+ float axZ;
+ float minLimit[6];
+ float maxLimit[6];
+ float extraFz;
+ short flag;
+ short pad;
+ short pad1;
+ short pad2;
+} bRigidBodyJointConstraint;
+
+/* Clamp-To Constraint */
+typedef struct bClampToConstraint {
+ Object *tar; /* 'target' must be a curve */
+ int flag; /* which axis/plane to compare owner's location on */
+ int flag2; /* for legacy reasons, this is flag2. used for any extra settings */
+} bClampToConstraint;
+
+/* Child Of Constraint */
+typedef struct bChildOfConstraint {
+ Object *tar; /* object which will act as parent (or target comes from) */
+ int flag; /* settings */
+ int pad;
+ float invmat[4][4]; /* parent-inverse matrix to use */
+ char subtarget[32]; /* string to specify a subobject target */
+} bChildOfConstraint;
+
+/* Generic Transform->Transform Constraint */
+typedef struct bTransformConstraint {
+ Object *tar; /* target (i.e. 'driver' object/bone) */
+ char subtarget[32];
+
+ short from, to; /* can be loc(0) , rot(1), or size(2) */
+ char map[3]; /* defines which target-axis deform is copied by each owner-axis */
+ char expo; /* extrapolate motion? if 0, confine to ranges */
+
+ float from_min[3]; /* from_min/max defines range of target transform */
+ float from_max[3]; /* to map on to to_min/max range. */
+
+ float to_min[3]; /* range of motion on owner caused by target */
+ float to_max[3];
+} bTransformConstraint;
+
+/* transform limiting constraints - zero target ---------------------------- */
+/* Limit Location Constraint */
+typedef struct bLocLimitConstraint {
+ float xmin, xmax;
+ float ymin, ymax;
+ float zmin, zmax;
+ short flag;
+ short flag2;
+} bLocLimitConstraint;
+
+/* Limit Rotation Constraint */
+typedef struct bRotLimitConstraint {
+ float xmin, xmax;
+ float ymin, ymax;
+ float zmin, zmax;
+ short flag;
+ short pad1;
+} bRotLimitConstraint;
+
+/* Limit Scaling Constraint */
+typedef struct bSizeLimitConstraint {
+ float xmin, xmax;
+ float ymin, ymax;
+ float zmin, zmax;
+ short flag;
+ short pad1;
+} bSizeLimitConstraint;
+
+/* ------------------------------------------ */
+
+/* bConstraint->type
+ * - Do not ever change the order of these, or else files could get
+ * broken as their correct value cannot be resolved
+ */
+typedef enum B_CONSTAINT_TYPES {
+ CONSTRAINT_TYPE_NULL = 0, /* Invalid/legacy constraint */
+ CONSTRAINT_TYPE_CHILDOF, /* Unimplemented non longer :) - during constraints recode, Aligorith */
+ CONSTRAINT_TYPE_TRACKTO,
+ CONSTRAINT_TYPE_KINEMATIC,
+ CONSTRAINT_TYPE_FOLLOWPATH,
+ CONSTRAINT_TYPE_ROTLIMIT, /* Unimplemented no longer :) - Aligorith */
+ CONSTRAINT_TYPE_LOCLIMIT, /* Unimplemented no longer :) - Aligorith */
+ CONSTRAINT_TYPE_SIZELIMIT, /* Unimplemented no longer :) - Aligorith */
+ CONSTRAINT_TYPE_ROTLIKE,
+ CONSTRAINT_TYPE_LOCLIKE,
+ CONSTRAINT_TYPE_SIZELIKE,
+ CONSTRAINT_TYPE_PYTHON, /* Unimplemented no longer :) - Aligorith. Scripts */
+ CONSTRAINT_TYPE_ACTION,
+ CONSTRAINT_TYPE_LOCKTRACK, /* New Tracking constraint that locks an axis in place - theeth */
+ CONSTRAINT_TYPE_DISTANCELIMIT, /* was never properly coded - removed! */
+ CONSTRAINT_TYPE_STRETCHTO, /* claiming this to be mine :) is in tuhopuu bjornmose */
+ CONSTRAINT_TYPE_MINMAX, /* floor constraint */
+ CONSTRAINT_TYPE_RIGIDBODYJOINT, /* rigidbody constraint */
+ CONSTRAINT_TYPE_CLAMPTO, /* clampto constraint */
+ CONSTRAINT_TYPE_TRANSFORM, /* transformation (loc/rot/size -> loc/rot/size) constraint */
+
+ /* NOTE: everytime a new constraint is added, update this */
+ NUM_CONSTRAINT_TYPES= CONSTRAINT_TYPE_TRANSFORM
+} B_CONSTRAINT_TYPES;
+
+/* bConstraint->flag */
+/* flags 0x2 (1<<1) and 0x8 (1<<3) were used in past */
+/* flag 0x20 (1<<5) was used to indicate that a constraint was evaluated using a 'local' hack for posebones only */
+typedef enum B_CONSTRAINT_FLAG {
+ /* expand for UI */
+ CONSTRAINT_EXPAND = (1<<0),
+ /* pre-check for illegal object name or bone name */
+ CONSTRAINT_DISABLE = (1<<2),
+ /* to indicate which Ipo should be shown, maybe for 3d access later too */
+ CONSTRAINT_ACTIVE = (1<<4),
+ /* to indicate that the owner's space should only be changed into ownspace, but not out of it */
+ CONSTRAINT_SPACEONCE = (1<<6)
+} B_CONSTRAINT_FLAG;
+
+/* bConstraint->ownspace/tarspace */
+typedef enum B_CONSTRAINT_SPACETYPES {
+ /* default for all - worldspace */
+ CONSTRAINT_SPACE_WORLD = 0,
+ /* for objects (relative to parent/without parent influence),
+ * for bones (along normals of bone, without parent/restpositions)
+ */
+ CONSTRAINT_SPACE_LOCAL,
+ /* for posechannels - pose space */
+ CONSTRAINT_SPACE_POSE,
+ /* for posechannels - local with parent */
+ CONSTRAINT_SPACE_PARLOCAL,
+} B_CONSTRAINT_SPACETYPES;
+
+/* bConstraintChannel.flag */
+typedef enum B_CONSTRAINTCHANNEL_FLAG {
+ CONSTRAINT_CHANNEL_SELECT = (1<<0),
+ CONSTRAINT_CHANNEL_PROTECTED = (1<<1)
+} B_CONSTRAINTCHANNEL_FLAG;
+
+/* -------------------------------------- */
+
+/**
+ * The flags for ROTLIKE, LOCLIKE and SIZELIKE should be kept identical
+ * (that is, same effect, different name). It simplifies the Python API access a lot.
+ */
+
+/* bRotateLikeConstraint.flag */
+#define ROTLIKE_X 0x01
+#define ROTLIKE_Y 0x02
+#define ROTLIKE_Z 0x04
+#define ROTLIKE_X_INVERT 0x10
+#define ROTLIKE_Y_INVERT 0x20
+#define ROTLIKE_Z_INVERT 0x40
+#define ROTLIKE_OFFSET 0x80
+
+/* bLocateLikeConstraint.flag */
+#define LOCLIKE_X 0x01
+#define LOCLIKE_Y 0x02
+#define LOCLIKE_Z 0x04
+#define LOCLIKE_TIP 0x08
+#define LOCLIKE_X_INVERT 0x10
+#define LOCLIKE_Y_INVERT 0x20
+#define LOCLIKE_Z_INVERT 0x40
+#define LOCLIKE_OFFSET 0x80
+
+/* bSizeLikeConstraint.flag */
+#define SIZELIKE_X 0x01
+#define SIZELIKE_Y 0x02
+#define SIZELIKE_Z 0x04
+#define SIZELIKE_OFFSET 0x80
+
+/* Axis flags */
+#define LOCK_X 0x00
+#define LOCK_Y 0x01
+#define LOCK_Z 0x02
+
+#define UP_X 0x00
+#define UP_Y 0x01
+#define UP_Z 0x02
+
+#define TRACK_X 0x00
+#define TRACK_Y 0x01
+#define TRACK_Z 0x02
+#define TRACK_nX 0x03
+#define TRACK_nY 0x04
+#define TRACK_nZ 0x05
+
+/* bTrackToConstraint->flags */
+#define TARGET_Z_UP 0x01
+
+#define VOLUME_XZ 0x00
+#define VOLUME_X 0x01
+#define VOLUME_Z 0x02
+#define NO_VOLUME 0x03
+
+#define PLANE_X 0x00
+#define PLANE_Y 0x01
+#define PLANE_Z 0x02
+
+/* Clamp-To Constraint ->flag */
+#define CLAMPTO_AUTO 0
+#define CLAMPTO_X 1
+#define CLAMPTO_Y 2
+#define CLAMPTO_Z 3
+
+/* ClampTo Constraint ->flag2 */
+#define CLAMPTO_CYCLIC 1
+
+/* bKinematicConstraint->flag */
+#define CONSTRAINT_IK_TIP 1
+#define CONSTRAINT_IK_ROT 2
+#define CONSTRAINT_IK_AUTO 4
+#define CONSTRAINT_IK_TEMP 8
+#define CONSTRAINT_IK_STRETCH 16
+#define CONSTRAINT_IK_POS 32
+#define CONSTRAINT_IK_SETANGLE 64
+#define CONSTRAINT_IK_GETANGLE 128
+
+/* MinMax (floor) flags */
+#define MINMAX_STICKY 0x01
+#define MINMAX_STUCK 0x02
+#define MINMAX_USEROT 0x04
+
+/* transform limiting constraints -> flag */
+#define LIMIT_XMIN 0x01
+#define LIMIT_XMAX 0x02
+#define LIMIT_YMIN 0x04
+#define LIMIT_YMAX 0x08
+#define LIMIT_ZMIN 0x10
+#define LIMIT_ZMAX 0x20
+
+#define LIMIT_XROT 0x01
+#define LIMIT_YROT 0x02
+#define LIMIT_ZROT 0x04
+
+/* not used anymore - for older Limit Location constraints only */
+#define LIMIT_NOPARENT 0x01
+
+/* python constraint -> flag */
+#define PYCON_USETARGETS 0x01
+#define PYCON_SCRIPTERROR 0x02
+
+/* ChildOf Constraint -> flag */
+#define CHILDOF_LOCX 0x001
+#define CHILDOF_LOCY 0x002
+#define CHILDOF_LOCZ 0x004
+#define CHILDOF_ROTX 0x008
+#define CHILDOF_ROTY 0x010
+#define CHILDOF_ROTZ 0x020
+#define CHILDOF_SIZEX 0x040
+#define CHILDOF_SIZEY 0x080
+#define CHILDOF_SIZEZ 0x100
+
+/* Rigid-Body Constraint */
+#define CONSTRAINT_DRAW_PIVOT 0x40
+
+/* important: these defines need to match up with PHY_DynamicTypes headerfile */
+#define CONSTRAINT_RB_BALL 1
+#define CONSTRAINT_RB_HINGE 2
+#define CONSTRAINT_RB_CONETWIST 4
+#define CONSTRAINT_RB_VEHICLE 11
+#define CONSTRAINT_RB_GENERIC6DOF 12
+
+#endif
diff --git a/source/blender/makesdna/DNA_controller_types.h b/source/blender/makesdna/DNA_controller_types.h
new file mode 100644
index 00000000000..b8bffd68db8
--- /dev/null
+++ b/source/blender/makesdna/DNA_controller_types.h
@@ -0,0 +1,79 @@
+/**
+ * blenlib/DNA_controller_types.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef DNA_CONTROLLER_TYPES_H
+#define DNA_CONTROLLER_TYPES_H
+
+struct bActuator;
+struct Text;
+struct bSensor;
+
+/* ****************** CONTROLLERS ********************* */
+
+typedef struct bExpressionCont {
+ char str[128];
+} bExpressionCont;
+
+typedef struct bPythonCont {
+ struct Text *text;
+} bPythonCont;
+
+typedef struct bController {
+ struct bController *next, *prev, *mynew;
+ short type, flag, inputs, totlinks;
+ short otype, totslinks, pad2, pad3;
+
+ char name[32];
+ void *data;
+
+ struct bActuator **links;
+
+ struct bSensor **slinks;
+ short val, valo;
+ int pad5;
+
+} bController;
+
+/* controller->type */
+#define CONT_LOGIC_AND 0
+#define CONT_LOGIC_OR 1
+#define CONT_EXPRESSION 2
+#define CONT_PYTHON 3
+
+/* controller->flag */
+#define CONT_SHOW 1
+#define CONT_DEL 2
+#define CONT_NEW 4
+
+#endif
+
diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h
new file mode 100644
index 00000000000..807fc2add07
--- /dev/null
+++ b/source/blender/makesdna/DNA_curve_types.h
@@ -0,0 +1,290 @@
+/**
+ * blenlib/DNA_curve_types.h (mar-2001 nzc)
+ *
+ * Curve stuff.
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef DNA_CURVE_TYPES_H
+#define DNA_CURVE_TYPES_H
+
+#include "DNA_listBase.h"
+#include "DNA_vec_types.h"
+#include "DNA_ID.h"
+
+#define MAXTEXTBOX 256 /* used in readfile.c and editfont.c */
+
+struct BoundBox;
+struct Object;
+struct Ipo;
+struct Key;
+struct Material;
+struct VFont;
+
+/* These two Lines with # tell makesdna this struct can be excluded. */
+#
+#
+typedef struct Path {
+ int len;
+ float *data;
+ float totdist;
+} Path;
+
+/* These two Lines with # tell makesdna this struct can be excluded. */
+#
+#
+typedef struct BevList {
+ struct BevList *next, *prev;
+ int nr, flag;
+ short poly, gat;
+} BevList;
+
+/* These two Lines with # tell makesdna this struct can be excluded. */
+#
+#
+typedef struct BevPoint {
+ float x, y, z, alfa, sina, cosa, mat[3][3];
+ short f1, f2;
+} BevPoint;
+
+/* Keyframes on IPO curves and Points on Bezier Curves/Paths are generally BezTriples */
+/* note: alfa location in struct is abused by Key system */
+/* vec in BezTriple looks like this:
+ vec[0][0]=x location of handle 1
+ vec[0][1]=y location of handle 1
+ vec[0][2]=z location of handle 1 (not used for IpoCurve Points(2d))
+ vec[1][0]=x location of control point
+ vec[1][1]=y location of control point
+ vec[1][2]=z location of control point
+ vec[2][0]=x location of handle 2
+ vec[2][1]=y location of handle 2
+ vec[2][2]=z location of handle 2 (not used for IpoCurve Points(2d))
+*/
+typedef struct BezTriple {
+ float vec[3][3];
+ float alfa, weight, radius; /* alfa: tilt in 3D View, weight: used for softbody goal weight, radius: for bevel tapering */
+ short h1, h2; /* h1, h2: the handle type of the two handles */
+ char f1, f2, f3, hide; /* f1, f2, f3: used for selection status, hide: used to indicate whether BezTriple is hidden */
+} BezTriple;
+
+/* note; alfa location in struct is abused by Key system */
+typedef struct BPoint {
+ float vec[4];
+ float alfa, weight; /* alfa: tilt in 3D View, weight: used for softbody goal weight */
+ short f1, hide; /* f1: selection status, hide: is point hidden or not */
+ float radius, pad; /* user-set radius per point for bevelling etc */
+} BPoint;
+
+typedef struct Nurb {
+ struct Nurb *next, *prev; /* multiple nurbs per curve object are allowed */
+ short type;
+ short mat_nr; /* index into material list */
+ short hide, flag;
+ short pntsu, pntsv; /* number of points in the U or V directions */
+ short resolu, resolv; /* tesselation resolution in the U or V directions */
+ short orderu, orderv;
+ short flagu, flagv;
+
+ float *knotsu, *knotsv;
+ BPoint *bp;
+ BezTriple *bezt;
+
+ short tilt_interp; /* KEY_LINEAR, KEY_CARDINAL, KEY_BSPLINE */
+ short pad;
+
+ int charidx;
+} Nurb;
+
+typedef struct CharInfo {
+ short kern;
+ short mat_nr;
+ char flag;
+ char pad;
+ short pad2;
+} CharInfo;
+
+typedef struct TextBox {
+ float x, y, w, h;
+} TextBox;
+
+typedef struct Curve {
+ ID id;
+
+ struct BoundBox *bb;
+
+ ListBase nurb;
+ ListBase disp;
+ struct Object *bevobj, *taperobj, *textoncurve;
+ struct Ipo *ipo;
+ Path *path;
+ struct Key *key;
+ struct Material **mat;
+
+ ListBase bev;
+
+ /* texture space, copied as one block in editobject.c */
+ float loc[3];
+ float size[3];
+ float rot[3];
+
+ int texflag;
+
+ short pathlen, totcol;
+ short flag, bevresol;
+ float width, ext1, ext2;
+
+ /* default */
+ short resolu, resolv;
+ short resolu_ren, resolv_ren;
+ int pad2;
+
+ /* font part */
+ short len, lines, pos, spacemode;
+ float spacing, linedist, shear, fsize, wordspace, ulpos, ulheight;
+ float xof, yof;
+ float linewidth;
+
+ char *str;
+ char family[24];
+ struct VFont *vfont;
+ struct VFont *vfontb;
+ struct VFont *vfonti;
+ struct VFont *vfontbi;
+
+ int sepchar;
+
+ int totbox, actbox, pad;
+ struct TextBox *tb;
+
+ int selstart, selend;
+
+ struct CharInfo *strinfo;
+ struct CharInfo curinfo;
+} Curve;
+
+typedef struct IpoDriver {
+ struct Object *ob;
+ short blocktype, adrcode, type, flag;
+ char name[128]; /* bone or constraint(?), or python expression here */
+} IpoDriver;
+
+/* temp? we store more bone names in 1 driver... */
+#define DRIVER_NAME_OFFS 32
+
+typedef struct IpoCurve {
+ struct IpoCurve *next, *prev;
+
+ struct BPoint *bp; /* are these even used anywhere? */
+ struct BezTriple *bezt; /* array of BezTriples (sizeof(BezTriple)*totvert. i.e. keyframes */
+
+ rctf maxrct, totrct; /* bounding boxes */
+
+ short blocktype, adrcode, vartype; /* blocktype= ipo-blocktype; adrcode= type of ipo-curve; vartype= 'format' of data */
+ short totvert; /* total number of BezTriples (i.e. keyframes) on curve */
+ short ipo, extrap; /* interpolation and extrapolation modes */
+ short flag, rt; /* flag= settings; rt= ??? */
+ float ymin, ymax; /* minimum/maximum y-extents for curve */
+ unsigned int bitmask; /* ??? */
+
+ float slide_min, slide_max; /* minimum/maximum values for sliders (in action editor) */
+ float curval; /* value of ipo-curve for current frame */
+
+ IpoDriver *driver; /* pointer to ipo-driver for this curve */
+
+} IpoCurve;
+
+/* **************** CURVE ********************* */
+
+/* texflag */
+#define CU_AUTOSPACE 1
+
+/* flag */
+#define CU_3D 1
+#define CU_FRONT 2
+#define CU_BACK 4
+#define CU_PATH 8
+#define CU_FOLLOW 16
+#define CU_UV_ORCO 32
+#define CU_NOPUNOFLIP 64
+#define CU_STRETCH 128
+#define CU_OFFS_PATHDIST 256
+#define CU_FAST 512 /* Font: no filling inside editmode */
+#define CU_RETOPO 1024
+
+/* spacemode */
+#define CU_LEFT 0
+#define CU_MIDDLE 1
+#define CU_RIGHT 2
+#define CU_JUSTIFY 3
+#define CU_FLUSH 4
+
+/* flag (nurb) */
+#define CU_SMOOTH 1
+
+/* type (nurb) */
+#define CU_POLY 0
+#define CU_BEZIER 1
+#define CU_BSPLINE 2
+#define CU_CARDINAL 3
+#define CU_NURBS 4
+#define CU_2D 8
+
+/* flagu flagv (nurb) */
+#define CU_CYCLIC 1
+
+/* h1 h2 (beztriple) */
+#define HD_FREE 0
+#define HD_AUTO 1
+#define HD_VECT 2
+#define HD_ALIGN 3
+#define HD_AUTO_ANIM 4
+
+/* *************** CHARINFO **************** */
+
+/* flag */
+#define CU_STYLE (1+2)
+#define CU_BOLD 1
+#define CU_ITALIC 2
+#define CU_UNDERLINE 4
+#define CU_WRAP 8 /* wordwrap occured here */
+
+/* *************** driver ****************** */
+
+/* driver->type */
+#define IPO_DRIVER_TYPE_NORMAL 0
+#define IPO_DRIVER_TYPE_PYTHON 1
+
+/* driver->flag */
+/* invalid flag: currently only used for buggy pydriver expressions: */
+#define IPO_DRIVER_FLAG_INVALID 1
+
+#endif
+
diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h
new file mode 100644
index 00000000000..1c1676ba277
--- /dev/null
+++ b/source/blender/makesdna/DNA_customdata_types.h
@@ -0,0 +1,102 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef DNA_CUSTOMDATA_TYPES_H
+#define DNA_CUSTOMDATA_TYPES_H
+
+/* descriptor and storage for a custom data layer */
+typedef struct CustomDataLayer {
+ int type; /* type of data in layer */
+ int offset; /* in editmode, offset of layer in block */
+ int flag; /* general purpose flag */
+ int active; /* number of the active layer of this type */
+ int active_rnd; /* number of the layer to render*/
+ char pad[4];
+ char name[32]; /* layer name */
+ void *data; /* layer data */
+} CustomDataLayer;
+
+/* structure which stores custom element data associated with mesh elements
+ * (vertices, edges or faces). The custom data is organised into a series of
+ * layers, each with a data type (e.g. MTFace, MDeformVert, etc.). */
+typedef struct CustomData {
+ CustomDataLayer *layers; /* CustomDataLayers, ordered by type */
+ int totlayer, maxlayer; /* number of layers, size of layers array */
+ int totsize, pad; /* in editmode, total size of all data layers */
+} CustomData;
+
+/* CustomData.type */
+#define CD_MVERT 0
+#define CD_MSTICKY 1
+#define CD_MDEFORMVERT 2
+#define CD_MEDGE 3
+#define CD_MFACE 4
+#define CD_MTFACE 5
+#define CD_MCOL 6
+#define CD_ORIGINDEX 7
+#define CD_NORMAL 8
+#define CD_FLAGS 9
+#define CD_PROP_FLT 10
+#define CD_PROP_INT 11
+#define CD_PROP_STR 12
+#define CD_NUMTYPES 13
+
+/* Bits for CustomDataMask */
+#define CD_MASK_MVERT (1 << CD_MVERT)
+#define CD_MASK_MSTICKY (1 << CD_MSTICKY)
+#define CD_MASK_MDEFORMVERT (1 << CD_MDEFORMVERT)
+#define CD_MASK_MEDGE (1 << CD_MEDGE)
+#define CD_MASK_MFACE (1 << CD_MFACE)
+#define CD_MASK_MTFACE (1 << CD_MTFACE)
+#define CD_MASK_MCOL (1 << CD_MCOL)
+#define CD_MASK_ORIGINDEX (1 << CD_ORIGINDEX)
+#define CD_MASK_NORMAL (1 << CD_NORMAL)
+#define CD_MASK_FLAGS (1 << CD_FLAGS)
+#define CD_MASK_PROP_FLT (1 << CD_PROP_FLT)
+#define CD_MASK_PROP_INT (1 << CD_PROP_INT)
+#define CD_MASK_PROP_STR (1 << CD_PROP_STR)
+
+
+/* CustomData.flag */
+
+/* indicates layer should not be copied by CustomData_from_template or
+ * CustomData_copy_data */
+#define CD_FLAG_NOCOPY (1<<0)
+/* indicates layer should not be freed (for layers backed by external data) */
+#define CD_FLAG_NOFREE (1<<1)
+/* indicates the layer is only temporary, also implies no copy */
+#define CD_FLAG_TEMPORARY ((1<<2)|CD_FLAG_NOCOPY)
+
+/* Limits */
+#define MAX_MTFACE 8
+#define MAX_MCOL 8
+
+#endif
diff --git a/source/blender/makesdna/DNA_documentation.h b/source/blender/makesdna/DNA_documentation.h
new file mode 100644
index 00000000000..45b58f17750
--- /dev/null
+++ b/source/blender/makesdna/DNA_documentation.h
@@ -0,0 +1,79 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * @mainpage DNA- Makesdna modules
+ *
+ * @section about About the DNA module
+ *
+ * The DNA module holds all type definitions that are serialized in a
+ * blender file. There is an executable that scans all files, looking
+ * for struct-s to serialize (hence sdna: Struct DNA). From this
+ * information, it builds a file with numbers that encode the format,
+ * the names of variables, and the plce to look for them.
+ *
+ * @section issues Known issues with DNA
+ *
+ * - Function pointers:
+ *
+ * Because of historical reasons, some function pointers were
+ * untyped. The parser/dna generator has been modified to explicitly
+ * handle these special cases. Most pointers have been given proper
+ * proto's by now. DNA_space_types.h::Spacefile::returnfuncmay still
+ * be badly defined. The reason for this is that is is called with
+ * different types of arguments. It takes a char* at this moment...
+ *
+ * - Path to the header files
+ *
+ * Also because of historical reasons, there is a path prefix to the
+ * headers that need to be scanned. This is the BASE_HEADER
+ * define. If you change the file-layout for DNA, you will probably
+ * have to change this (Not very flexible, but it is hardly ever
+ * changed. Sorry.).
+ *
+ * @section dependencies Dependencies
+ *
+ * DNA has no external dependencies (except for a few system
+ * includes).
+ *
+ **/
+
+
+/* PLEASE READ INSTRUCTIONS ABOUT ADDING VARIABLES IN 'DNA' STRUCTS IN
+
+ ../blenloader/intern/genfile.c
+ (ton)
+
+ */
+
+
+
+/* This file has intentionally no definitions or implementation. */
+
diff --git a/source/blender/makesdna/DNA_effect_types.h b/source/blender/makesdna/DNA_effect_types.h
new file mode 100644
index 00000000000..4d910861acd
--- /dev/null
+++ b/source/blender/makesdna/DNA_effect_types.h
@@ -0,0 +1,144 @@
+/**
+ * blenlib/DNA_effect_types.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef DNA_EFFECT_TYPES_H
+#define DNA_EFFECT_TYPES_H
+
+/* don't forget, new effects also in writefile.c for dna!!! */
+
+#define PAF_MAXMULT 4
+
+/* paf->flag (keep bit 0 free for compatibility) */
+#define PAF_BSPLINE 2
+#define PAF_STATIC 4
+#define PAF_FACE 8
+#define PAF_ANIMATED 16
+ /* show particles before they're emitted*/
+#define PAF_UNBORN 32
+ /* emit only from faces*/
+#define PAF_OFACE 64
+ /* show emitter (don't hide actual mesh)*/
+#define PAF_SHOWE 128
+ /* true random emit from faces (not just ordered jitter)*/
+#define PAF_TRAND 256
+ /* even distribution in face emission based on face areas*/
+#define PAF_EDISTR 512
+ /*show particles after they've died*/
+#define PAF_DIED 2048
+
+
+/*paf->flag2 for pos/neg paf->flag2neg*/
+#define PAF_TEXTIME 1 /*texture timing*/
+
+ /* eff->type */
+#define EFF_BUILD 0
+#define EFF_PARTICLE 1
+#define EFF_WAVE 2
+
+ /* eff->flag */
+#define EFF_SELECT 1
+
+ /* paf->stype */
+#define PAF_NORMAL 0
+#define PAF_VECT 1
+
+ /* paf->texmap */
+#define PAF_TEXINT 0
+#define PAF_TEXRGB 1
+#define PAF_TEXGRAD 2
+
+typedef struct Effect {
+ struct Effect *next, *prev;
+ short type, flag, buttype, rt;
+
+} Effect;
+
+typedef struct BuildEff {
+ struct BuildEff *next, *prev;
+ short type, flag, buttype, rt;
+
+ float len, sfra;
+
+} BuildEff;
+
+#
+#
+typedef struct Particle {
+ float co[3], no[3];
+ float time, lifetime;
+ short mat_nr, rt;
+} Particle;
+
+struct Group;
+
+typedef struct PartEff {
+ struct PartEff *next, *prev;
+ short type, flag, buttype, stype, vertgroup, userjit;
+
+ float sta, end, lifetime;
+ int totpart, totkey, seed;
+
+ float normfac, obfac, randfac, texfac, randlife;
+ float force[3];
+ float damp;
+
+ float nabla, vectsize, maxlen, pad, defvec[3];
+
+ float mult[4], life[4];
+ short child[4], mat[4];
+ short texmap, curmult;
+ short staticstep, omat, timetex, speedtex, flag2, flag2neg;
+ short disp, vertgroup_v;
+
+ char vgroupname[32], vgroupname_v[32];
+ float imat[4][4]; /* inverse matrix of parent Object */
+
+ Particle *keys;
+ struct Group *group;
+
+} PartEff;
+
+
+typedef struct WaveEff {
+ struct WaveEff *next, *prev;
+ short type, flag, buttype, stype;
+
+ float startx, starty, height, width;
+ float narrow, speed, minfac, damp;
+
+ float timeoffs, lifetime;
+
+} WaveEff;
+
+#endif
+
diff --git a/source/blender/makesdna/DNA_fileglobal_types.h b/source/blender/makesdna/DNA_fileglobal_types.h
new file mode 100644
index 00000000000..1aecf4da017
--- /dev/null
+++ b/source/blender/makesdna/DNA_fileglobal_types.h
@@ -0,0 +1,60 @@
+/**
+ * blenlib/DNA_fileglobal_types.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef DNA_FILEGLOBAL_TYPES_H
+#define DNA_FILEGLOBAL_TYPES_H
+
+/**
+ * FileGlobal stores a part of the current user-unterface settings at
+ * the moment of saving, and the file-specific settings.
+ */
+typedef struct FileGlobal {
+ char subvstr[4]; /* needs to be here, for human fileformat recognition */
+ short subversion, pads;
+ short minversion, minsubversion;
+ short displaymode, winpos;
+ void *curscreen;
+ void *curscene;
+ int fileflags;
+ int globalf;
+} FileGlobal;
+
+
+/* minversion: in file, the oldest past blender version you can use compliant */
+/* example: if in 2.43 the meshes lose mesh data, minversion is 2.43 then too */
+/* or: in 2.42, subversion 1, same as above, minversion then is 2.42, min subversion 1 */
+/* (defines for version are in the BKE_blender.h file, for historic reasons) */
+
+
+#endif
+
diff --git a/source/blender/makesdna/DNA_group_types.h b/source/blender/makesdna/DNA_group_types.h
new file mode 100644
index 00000000000..3a074dd63bc
--- /dev/null
+++ b/source/blender/makesdna/DNA_group_types.h
@@ -0,0 +1,65 @@
+/**
+ * blenlib/DNA_group_types.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef DNA_GROUP_TYPES_H
+#define DNA_GROUP_TYPES_H
+
+#include "DNA_listBase.h"
+#include "DNA_ID.h"
+
+struct Object;
+
+typedef struct GroupObject {
+ struct GroupObject *next, *prev;
+ struct Object *ob;
+ void *lampren; /* used while render */
+ int recalc; /* copy of ob->recalc, used to set animated groups OK */
+ int pad;
+} GroupObject;
+
+
+typedef struct Group {
+ ID id;
+
+ ListBase gobject; /* GroupObject */
+
+ /* Bad design, since layers stored in the scenes 'Base'
+ * the objects that show in the group can change depending
+ * on the last used scene */
+ unsigned int layer;
+ int pad;
+} Group;
+
+
+#endif
+
diff --git a/source/blender/makesdna/DNA_image_types.h b/source/blender/makesdna/DNA_image_types.h
new file mode 100644
index 00000000000..8a5a7ce4a4c
--- /dev/null
+++ b/source/blender/makesdna/DNA_image_types.h
@@ -0,0 +1,124 @@
+/**
+ * blenlib/DNA_image_types.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef DNA_IMAGE_TYPES_H
+#define DNA_IMAGE_TYPES_H
+
+#include "DNA_ID.h"
+
+struct PackedFile;
+struct anim;
+struct ImBuf;
+struct RenderResult;
+
+
+/* ImageUser is in Texture, in Nodes, Background Image, Image Window, .... */
+/* should be used in conjunction with an ID * to Image. */
+typedef struct ImageUser {
+ int framenr; /* movies, sequences: current to display */
+ int frames; /* total amount of frames to use */
+ int offset, sfra; /* offset within movie, start frame in global time */
+ short fie_ima, cycl; /* fields/image in movie, cyclic flag */
+ short flag, ok;
+
+ short multi_index, layer, pass; /* listbase indices, for menu browsing or retrieve buffer */
+ short menunr; /* localized menu entry, for handling browse event */
+} ImageUser;
+
+/* iuser->flag */
+#define IMA_ANIM_ALWAYS 1
+#define IMA_ANIM_REFRESHED 2
+
+typedef struct Image {
+ ID id;
+
+ char name[240]; /* file path */
+
+ ListBase ibufs; /* not written in file */
+
+ /* sources from: */
+ struct anim *anim;
+ struct RenderResult *rr;
+
+ short ok, flag;
+ short source, type, pad, pad1;
+ int lastframe;
+
+ /* texture page */
+ short tpageflag, totbind;
+ short xrep, yrep;
+ short twsta, twend;
+ unsigned int bindcode; /* only for current image... */
+ unsigned int *repbind; /* for repeat of parts of images */
+
+ struct PackedFile * packedfile;
+ struct PreviewImage * preview;
+
+ float lastupdate;
+ int lastused;
+ short animspeed;
+
+ short gen_x, gen_y, gen_type; /* for generated images */
+
+ /* display aspect - for UV editing images resized for faster openGL display */
+ float aspx, aspy;
+
+/*#ifdef WITH_VERSE*/
+ void *vnode; /* pointer at verse bitmap node */
+/*#endif*/
+} Image;
+
+
+/* **************** IMAGE ********************* */
+
+/* flag */
+#define IMA_FIELDS 1
+#define IMA_STD_FIELD 2
+
+#define IMA_REFLECT 16
+#define IMA_NOCOLLECT 32
+#define IMA_ANTIALI 64
+
+
+/* tpageflag */
+#define IMA_TILES 1
+#define IMA_TWINANIM 2
+#define IMA_COLCYCLE 4 /* Depreciated */
+#define IMA_MIPMAP_COMPLETE 8 /* all mipmap levels in OpenGL texture set? */
+#define IMA_CLAMP_U 16
+#define IMA_CLAMP_V 32
+
+/* ima->type and ima->source moved to BKE_image.h, for API */
+
+#endif
+
diff --git a/source/blender/makesdna/DNA_ipo_types.h b/source/blender/makesdna/DNA_ipo_types.h
new file mode 100644
index 00000000000..1fca73b576c
--- /dev/null
+++ b/source/blender/makesdna/DNA_ipo_types.h
@@ -0,0 +1,401 @@
+/**
+ * blenlib/DNA_ipo_types.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef DNA_IPO_TYPES_H
+#define DNA_IPO_TYPES_H
+
+#include "DNA_listBase.h"
+#include "DNA_vec_types.h"
+
+#include "DNA_ID.h"
+
+/* IPO Data-Block */
+typedef struct Ipo {
+ ID id;
+
+ ListBase curve; /* A list of IpoCurve structs in a linked list. */
+ rctf cur; /* Rect defining extents of keyframes? */
+
+ short blocktype, showkey; /* blocktype: self-explanatory; showkey: either 0 or 1 (show vertical yellow lines for editing) */
+ short muteipo, pad; /* muteipo: either 0 or 1 (whether ipo block is muted) */
+} Ipo;
+
+/* NOTE: IpoCurve struct is defined in DNA_curve_types.h, not in here... */
+
+/* sometimes used */
+typedef short IPO_Channel;
+
+/* defines: are these duped or new? */
+
+#define IPOBUTY 17
+
+#define TOB_IPO 1
+#define TOB_IPODROT 2
+
+/* disptype */
+#define IPO_DISPDEGR 1
+#define IPO_DISPBITS 2
+#define IPO_DISPTIME 3
+
+/* ******************** */
+
+#define OB_TOTIPO 29
+#define OB_TOTNAM 29
+
+#define OB_LOC_X 1
+#define OB_LOC_Y 2
+#define OB_LOC_Z 3
+#define OB_DLOC_X 4
+#define OB_DLOC_Y 5
+#define OB_DLOC_Z 6
+
+#define OB_ROT_X 7
+#define OB_ROT_Y 8
+#define OB_ROT_Z 9
+#define OB_DROT_X 10
+#define OB_DROT_Y 11
+#define OB_DROT_Z 12
+
+#define OB_SIZE_X 13
+#define OB_SIZE_Y 14
+#define OB_SIZE_Z 15
+#define OB_DSIZE_X 16
+#define OB_DSIZE_Y 17
+#define OB_DSIZE_Z 18
+
+#define OB_LAY 19
+
+#define OB_TIME 20
+
+#define OB_COL_R 21
+#define OB_COL_G 22
+#define OB_COL_B 23
+#define OB_COL_A 24
+
+#define OB_PD_FSTR 25
+#define OB_PD_FFALL 26
+#define OB_PD_SDAMP 27
+#define OB_PD_RDAMP 28
+#define OB_PD_PERM 29
+
+/* exception: driver channel, for bone driver only */
+#define OB_ROT_DIFF 100
+
+
+/* ******************** */
+
+#define MA_TOTIPO 40
+#define MA_TOTNAM 26
+
+#define MA_COL_R 1
+#define MA_COL_G 2
+#define MA_COL_B 3
+#define MA_SPEC_R 4
+#define MA_SPEC_G 5
+#define MA_SPEC_B 6
+#define MA_MIR_R 7
+#define MA_MIR_G 8
+#define MA_MIR_B 9
+#define MA_REF 10
+#define MA_ALPHA 11
+#define MA_EMIT 12
+#define MA_AMB 13
+#define MA_SPEC 14
+#define MA_HARD 15
+#define MA_SPTR 16
+#define MA_IOR 17
+#define MA_MODE 18
+#define MA_HASIZE 19
+#define MA_TRANSLU 20
+#define MA_RAYM 21
+#define MA_FRESMIR 22
+#define MA_FRESMIRI 23
+#define MA_FRESTRA 24
+#define MA_FRESTRAI 25
+#define MA_ADD 26
+
+#define MA_MAP1 0x20
+#define MA_MAP2 0x40
+#define MA_MAP3 0x80
+#define MA_MAP4 0x100
+#define MA_MAP5 0x200
+#define MA_MAP6 0x400
+#define MA_MAP7 0x800
+#define MA_MAP8 0x1000
+#define MA_MAP9 0x2000
+#define MA_MAP10 0x4000
+
+#define TEX_TOTNAM 14
+
+#define MAP_OFS_X 1
+#define MAP_OFS_Y 2
+#define MAP_OFS_Z 3
+#define MAP_SIZE_X 4
+#define MAP_SIZE_Y 5
+#define MAP_SIZE_Z 6
+#define MAP_R 7
+#define MAP_G 8
+#define MAP_B 9
+
+#define MAP_DVAR 10
+#define MAP_COLF 11
+#define MAP_NORF 12
+#define MAP_VARF 13
+#define MAP_DISP 14
+
+/* ******************** */
+
+#define TE_TOTIPO 26
+#define TE_TOTNAM 26
+
+#define TE_NSIZE 1
+#define TE_NDEPTH 2
+#define TE_NTYPE 3
+#define TE_TURB 4
+
+#define TE_VNW1 5
+#define TE_VNW2 6
+#define TE_VNW3 7
+#define TE_VNW4 8
+#define TE_VNMEXP 9
+#define TE_VN_DISTM 10
+#define TE_VN_COLT 11
+
+#define TE_ISCA 12
+#define TE_DISTA 13
+
+#define TE_MG_TYP 14
+#define TE_MGH 15
+#define TE_MG_LAC 16
+#define TE_MG_OCT 17
+#define TE_MG_OFF 18
+#define TE_MG_GAIN 19
+
+#define TE_N_BAS1 20
+#define TE_N_BAS2 21
+
+#define TE_COL_R 22
+#define TE_COL_G 23
+#define TE_COL_B 24
+#define TE_BRIGHT 25
+#define TE_CONTRA 26
+
+/* ******************** */
+
+#define SEQ_TOTIPO 1
+#define SEQ_TOTNAM 1
+
+#define SEQ_FAC1 1
+
+/* ******************** */
+
+#define CU_TOTIPO 1
+#define CU_TOTNAM 1
+
+#define CU_SPEED 1
+
+/* ******************** */
+
+#define KEY_TOTIPO 64
+#define KEY_TOTNAM 64
+
+#define KEY_SPEED 0
+#define KEY_NR 1
+
+/* ******************** */
+
+#define WO_TOTIPO 29
+#define WO_TOTNAM 16
+
+#define WO_HOR_R 1
+#define WO_HOR_G 2
+#define WO_HOR_B 3
+#define WO_ZEN_R 4
+#define WO_ZEN_G 5
+#define WO_ZEN_B 6
+
+#define WO_EXPOS 7
+
+#define WO_MISI 8
+#define WO_MISTDI 9
+#define WO_MISTSTA 10
+#define WO_MISTHI 11
+
+#define WO_STAR_R 12
+#define WO_STAR_G 13
+#define WO_STAR_B 14
+#define WO_STARDIST 15
+#define WO_STARSIZE 16
+
+/* ******************** */
+
+#define LA_TOTIPO 21
+#define LA_TOTNAM 10
+
+#define LA_ENERGY 1
+#define LA_COL_R 2
+#define LA_COL_G 3
+#define LA_COL_B 4
+#define LA_DIST 5
+#define LA_SPOTSI 6
+#define LA_SPOTBL 7
+#define LA_QUAD1 8
+#define LA_QUAD2 9
+#define LA_HALOINT 10
+
+/* ******************** */
+
+/* yafray: totipo & totnam +2 because of added curves */
+#define CAM_TOTIPO 7
+#define CAM_TOTNAM 7
+
+#define CAM_LENS 1
+#define CAM_STA 2
+#define CAM_END 3
+
+/* yafray aperture & focal distance curves */
+#define CAM_YF_APERT 4
+#define CAM_YF_FDIST 5
+
+#define CAM_SHIFT_X 6
+#define CAM_SHIFT_Y 7
+
+/* ******************** */
+
+#define SND_TOTIPO 4
+#define SND_TOTNAM 4
+
+#define SND_VOLUME 1
+#define SND_PITCH 2
+#define SND_PANNING 3
+#define SND_ATTEN 4
+
+/* ******************** */
+
+#define AC_TOTIPO 10 /* __NLA */
+#define AC_TOTNAM 10
+
+#define AC_LOC_X 1
+#define AC_LOC_Y 2
+#define AC_LOC_Z 3
+
+#define AC_SIZE_X 13
+#define AC_SIZE_Y 14
+#define AC_SIZE_Z 15
+
+#define AC_QUAT_W 25
+#define AC_QUAT_X 26
+#define AC_QUAT_Y 27
+#define AC_QUAT_Z 28
+
+/* ******************** */
+#define CO_TOTIPO 1 /* Constraint Ipos */
+#define CO_TOTNAM 1
+
+#define CO_ENFORCE 1
+/*
+#define CO_TIME 2
+#define CO_OFFSET_X 3
+#define CO_OFFSET_Y 4
+#define CO_OFFSET_Z 5
+#define CO_ORIENT_X 6
+#define CO_ORIENT_Y 7
+#define CO_ORIENT_Z 8
+#define CO_ROLL 9
+*/
+
+/* ******************** */
+/* fluidsim ipos NT */
+
+#define FLUIDSIM_TOTIPO 9
+#define FLUIDSIM_TOTNAM 9
+
+#define FLUIDSIM_VISC 1
+#define FLUIDSIM_TIME 2
+
+#define FLUIDSIM_GRAV_X 3
+#define FLUIDSIM_GRAV_Y 4
+#define FLUIDSIM_GRAV_Z 5
+
+#define FLUIDSIM_VEL_X 6
+#define FLUIDSIM_VEL_Y 7
+#define FLUIDSIM_VEL_Z 8
+
+#define FLUIDSIM_ACTIVE 9
+
+
+/* these are IpoCurve specific */
+/* **************** IPO ********************* */
+
+/* icu->vartype */
+#define IPO_CHAR 0
+#define IPO_SHORT 1
+#define IPO_INT 2
+#define IPO_LONG 3
+#define IPO_FLOAT 4
+#define IPO_DOUBLE 5
+#define IPO_FLOAT_DEGR 6
+ /* very special case, in keys */
+#define IPO_BEZTRIPLE 100
+#define IPO_BPOINT 101
+
+/* icu->vartype */
+#define IPO_BITS 16
+#define IPO_CHAR_BIT 16
+#define IPO_SHORT_BIT 17
+#define IPO_INT_BIT 18
+
+/* icu->ipo: the type of curve */
+#define IPO_CONST 0
+#define IPO_LIN 1
+#define IPO_BEZ 2
+#define IPO_MIXED 3 /* not used yet */
+
+/* icu->extrap */
+#define IPO_HORIZ 0
+#define IPO_DIR 1
+#define IPO_CYCL 2
+#define IPO_CYCLX 3
+
+/* icu->flag */
+#define IPO_VISIBLE 1
+#define IPO_SELECT 2
+#define IPO_EDIT 4
+#define IPO_LOCK 8
+#define IPO_AUTO_HORIZ 16
+#define IPO_ACTIVE 32
+#define IPO_PROTECT 64
+#define IPO_MUTE 128
+
+#endif
+
diff --git a/source/blender/makesdna/DNA_key_types.h b/source/blender/makesdna/DNA_key_types.h
new file mode 100644
index 00000000000..3292e07f80e
--- /dev/null
+++ b/source/blender/makesdna/DNA_key_types.h
@@ -0,0 +1,91 @@
+/**
+ * blenlib/DNA_key_types.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef DNA_KEY_TYPES_H
+#define DNA_KEY_TYPES_H
+
+#include "DNA_listBase.h"
+#include "DNA_ID.h"
+
+struct Ipo;
+
+typedef struct KeyBlock {
+ struct KeyBlock *next, *prev;
+
+ float pos;
+ float curval;
+ short type, adrcode;
+ int totelem;
+
+ void *data;
+ float *weights;
+ char name[32];
+ char vgroup[32];
+
+ float slidermin;
+ float slidermax;
+} KeyBlock;
+
+
+typedef struct Key {
+ ID id;
+
+ KeyBlock *refkey;
+ char elemstr[32];
+ int elemsize;
+ float curval;
+
+ ListBase block;
+ struct Ipo *ipo;
+
+ ID *from;
+
+ short type, totkey;
+ short slurph, flag;
+} Key;
+
+/* **************** KEY ********************* */
+
+/* key->type */
+#define KEY_NORMAL 0
+#define KEY_RELATIVE 1
+
+/* key->flag */
+
+/* keyblock->type */
+#define KEY_LINEAR 0
+#define KEY_CARDINAL 1
+#define KEY_BSPLINE 2
+
+#endif
+
diff --git a/source/blender/makesdna/DNA_lamp_types.h b/source/blender/makesdna/DNA_lamp_types.h
new file mode 100644
index 00000000000..f8cc2378cb1
--- /dev/null
+++ b/source/blender/makesdna/DNA_lamp_types.h
@@ -0,0 +1,174 @@
+/**
+ * blenlib/DNA_lamp_types.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef DNA_LAMP_TYPES_H
+#define DNA_LAMP_TYPES_H
+
+#include "DNA_ID.h"
+#include "DNA_scriptlink_types.h"
+
+#ifndef MAX_MTEX
+#define MAX_MTEX 10
+#endif
+
+struct MTex;
+struct Ipo;
+struct CurveMapping;
+
+typedef struct Lamp {
+ ID id;
+
+ short type, mode;
+
+ short colormodel, totex;
+ float r, g, b, k;
+
+ float energy, dist, spotsize, spotblend;
+ float haint;
+
+
+ float att1, att2; /* Quad1 and Quad2 attenuation */
+ int pad2;
+ struct CurveMapping *curfalloff;
+ short falloff_type;
+ short pad3;
+
+ float clipsta, clipend, shadspotsize;
+ float bias, soft;
+ short bufsize, samp, buffers, filtertype;
+ char bufflag, buftype;
+
+ short ray_samp, ray_sampy, ray_sampz;
+ short ray_samp_type;
+ short area_shape;
+ float area_size, area_sizey, area_sizez;
+ float adapt_thresh;
+ short ray_samp_method;
+ short pad1;
+
+ /* texact is for buttons */
+ short texact, shadhalostep;
+
+ /* yafray: photonlight params */
+ int YF_numphotons, YF_numsearch;
+ short YF_phdepth, YF_useqmc, YF_bufsize, YF_pad;
+ float YF_causticblur, YF_ltradius;
+ /* yafray: glow params */
+ float YF_glowint, YF_glowofs;
+ short YF_glowtype, YF_pad2;
+
+ struct MTex *mtex[10];
+ struct Ipo *ipo;
+
+ /* preview */
+ struct PreviewImage *preview;
+
+ ScriptLink scriptlink;
+} Lamp;
+
+/* **************** LAMP ********************* */
+
+/* type */
+#define LA_LOCAL 0
+#define LA_SUN 1
+#define LA_SPOT 2
+#define LA_HEMI 3
+#define LA_AREA 4
+/* yafray: extra lamp type used for caustic photonmap */
+#define LA_YF_PHOTON 5
+
+/* mode */
+#define LA_SHAD_BUF 1
+#define LA_HALO 2
+#define LA_LAYER 4
+#define LA_QUAD 8 /* no longer used */
+#define LA_NEG 16
+#define LA_ONLYSHADOW 32
+#define LA_SPHERE 64
+#define LA_SQUARE 128
+#define LA_TEXTURE 256
+#define LA_OSATEX 512
+#define LA_DEEP_SHADOW 1024
+#define LA_NO_DIFF 2048
+#define LA_NO_SPEC 4096
+#define LA_SHAD_RAY 8192
+/* yafray: lamp shadowbuffer flag, softlight */
+/* Since it is used with LOCAL lamp, can't use LA_SHAD */
+#define LA_YF_SOFT 16384
+
+/* falloff_type */
+#define LA_FALLOFF_CONSTANT 0
+#define LA_FALLOFF_INVLINEAR 1
+#define LA_FALLOFF_INVSQUARE 2
+#define LA_FALLOFF_CURVE 3
+#define LA_FALLOFF_SLIDERS 4
+
+
+/* buftype, no flag */
+#define LA_SHADBUF_REGULAR 0
+#define LA_SHADBUF_IRREGULAR 1
+#define LA_SHADBUF_HALFWAY 2
+
+/* bufflag, auto clipping */
+#define LA_SHADBUF_AUTO_START 1
+#define LA_SHADBUF_AUTO_END 2
+
+/* filtertype */
+#define LA_SHADBUF_BOX 0
+#define LA_SHADBUF_TENT 1
+#define LA_SHADBUF_GAUSS 2
+
+/* area shape */
+#define LA_AREA_SQUARE 0
+#define LA_AREA_RECT 1
+#define LA_AREA_CUBE 2
+#define LA_AREA_BOX 3
+
+/* ray_samp_method */
+#define LA_SAMP_CONSTANT 0
+#define LA_SAMP_HALTON 1
+#define LA_SAMP_HAMMERSLEY 2
+
+
+/* ray_samp_type */
+#define LA_SAMP_ROUND 1
+#define LA_SAMP_UMBRA 2
+#define LA_SAMP_DITHER 4
+#define LA_SAMP_JITTER 8
+
+/* mapto */
+#define LAMAP_COL 1
+
+
+#endif /* DNA_LAMP_TYPES_H */
+
diff --git a/source/blender/makesdna/DNA_lattice_types.h b/source/blender/makesdna/DNA_lattice_types.h
new file mode 100644
index 00000000000..823dc2ba485
--- /dev/null
+++ b/source/blender/makesdna/DNA_lattice_types.h
@@ -0,0 +1,67 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef DNA_LATTICE_TYPES_H
+#define DNA_LATTICE_TYPES_H
+
+#include "DNA_ID.h"
+
+struct BPoint;
+struct Ipo;
+struct Key;
+struct MDeformVert;
+
+typedef struct Lattice {
+ ID id;
+
+ short pntsu, pntsv, pntsw, flag;
+ short opntsu, opntsv, opntsw, pad2;
+ char typeu, typev, typew, type;
+ int pad;
+
+ float fu, fv, fw, du, dv, dw;
+
+ struct BPoint *def;
+
+ struct Ipo *ipo;
+ struct Key *key;
+
+ struct MDeformVert *dvert;
+} Lattice;
+
+/* ***************** LATTICE ********************* */
+
+/* flag */
+#define LT_GRID 1
+#define LT_OUTSIDE 2
+
+#endif
+
diff --git a/source/blender/makesdna/DNA_listBase.h b/source/blender/makesdna/DNA_listBase.h
new file mode 100644
index 00000000000..10a1b59fb01
--- /dev/null
+++ b/source/blender/makesdna/DNA_listBase.h
@@ -0,0 +1,64 @@
+/**
+ * blenlib/BLI_listBase.h mar 2001 Nzc
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * These structs are the foundation for all linked lists in the
+ * library system.
+ *
+ */
+
+#ifndef DNA_LISTBASE_H
+#define DNA_LISTBASE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct Link
+{
+ struct Link *next,*prev;
+} Link;
+
+/* never change the size of this! genfile.c detects pointerlen with it */
+typedef struct ListBase
+{
+ void *first, *last;
+} ListBase;
+
+/* 8 byte alignment! */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h
new file mode 100644
index 00000000000..252af0ebdb1
--- /dev/null
+++ b/source/blender/makesdna/DNA_material_types.h
@@ -0,0 +1,294 @@
+/**
+ * blenlib/DNA_material_types.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef DNA_MATERIAL_TYPES_H
+#define DNA_MATERIAL_TYPES_H
+
+#include "DNA_ID.h"
+#include "DNA_scriptlink_types.h"
+#include "DNA_listBase.h"
+
+#ifndef MAX_MTEX
+#define MAX_MTEX 10
+#endif
+
+struct MTex;
+struct Ipo;
+struct Material;
+struct ColorBand;
+struct Group;
+struct bNodeTree;
+
+/* WATCH IT: change type? also make changes in ipo.h */
+
+typedef struct Material {
+ ID id;
+
+ short colormodel, flag;
+ /* note, keep this below synced with render_types.h */
+ float r, g, b;
+ float specr, specg, specb;
+ float mirr, mirg, mirb;
+ float ambr, ambb, ambg;
+ float amb, emit, ang, spectra, ray_mirror;
+ float alpha, ref, spec, zoffs, add;
+ float translucency;
+ /* end synced with render_types.h */
+
+ float fresnel_mir, fresnel_mir_i;
+ float fresnel_tra, fresnel_tra_i;
+ float filter; /* filter added, for raytrace transparency and transmissivity */
+ float tx_limit, tx_falloff;
+ short ray_depth, ray_depth_tra;
+ short har;
+ char seed1, seed2;
+
+ float gloss_mir, gloss_tra;
+ short samp_gloss_mir, samp_gloss_tra;
+ float adapt_thresh_mir, adapt_thresh_tra;
+ float aniso_gloss_mir;
+ float dist_mir;
+ short fadeto_mir;
+ short pad1;
+
+ int mode, mode_l; /* mode_l is the or-ed result of all layer modes */
+ short flarec, starc, linec, ringc;
+ float hasize, flaresize, subsize, flareboost;
+ float strand_sta, strand_end, strand_ease;
+
+ float sbias; /* shadow bias */
+ float shad_alpha, padf; /* in use for irregular shadowbuffer */
+
+ /* for buttons and render*/
+ char rgbsel, texact, pr_type, use_nodes;
+ short pr_back, pr_lamp, septex, ml_flag; /* ml_flag is for disable base material */
+
+ /* shaders */
+ short diff_shader, spec_shader;
+ float roughness, refrac;
+ float param[4]; /* size, smooth, size, smooth, for toonshader */
+ float rms;
+ float darkness;
+ short texco, mapto;
+
+ /* ramp colors */
+ struct ColorBand *ramp_col;
+ struct ColorBand *ramp_spec;
+ char rampin_col, rampin_spec;
+ char rampblend_col, rampblend_spec;
+ short ramp_show, pad3;
+ float rampfac_col, rampfac_spec;
+
+ struct MTex *mtex[10];
+ struct bNodeTree *nodetree;
+ struct Ipo *ipo;
+ struct Group *group; /* light group */
+ struct PreviewImage * preview;
+
+ /* dynamic properties */
+ float friction, fh, reflect;
+ float fhdist, xyfrict;
+ short dynamode, pad2;
+
+ float sss_radius[3], sss_col[3];
+ float sss_error, sss_scale, sss_ior;
+ float sss_colfac, sss_texfac;
+ float sss_front, sss_back;
+ short sss_flag, sss_preset;
+
+ /* yafray: absorption color, dispersion parameters and material preset menu */
+ float YF_ar, YF_ag, YF_ab, YF_dscale, YF_dpwr;
+ int YF_dsmp, YF_preset, YF_djit;
+
+ ScriptLink scriptlink;
+} Material;
+
+/* **************** MATERIAL ********************* */
+
+ /* maximum number of materials per material array
+ * (on object, mesh, lamp, etc.)
+ */
+#define MAXMAT 16
+
+/* colormodel */
+#define MA_RGB 0
+#define MA_CMYK 1
+#define MA_YUV 2
+#define MA_HSV 3
+
+/* flag */
+ /* for render */
+#define MA_IS_USED 1
+
+/* mode (is int) */
+#define MA_TRACEBLE 1
+#define MA_SHADOW 2
+#define MA_SHLESS 4
+#define MA_WIRE 8
+#define MA_VERTEXCOL 16
+#define MA_HALO 32
+#define MA_ZTRA 64
+#define MA_VERTEXCOLP 128
+#define MA_ZINV 256
+#define MA_HALO_RINGS 256
+#define MA_ENV 512
+#define MA_HALO_LINES 512
+#define MA_ONLYSHADOW 1024
+#define MA_HALO_XALPHA 1024
+#define MA_STAR 0x800
+#define MA_FACETEXTURE 0x800
+#define MA_HALOTEX 0x1000
+#define MA_HALOPUNO 0x2000
+#define MA_ONLYCAST 0x2000
+#define MA_NOMIST 0x4000
+#define MA_HALO_SHADE 0x4000
+#define MA_HALO_FLARE 0x8000
+#define MA_RADIO 0x10000
+#define MA_RAYTRANSP 0x20000
+#define MA_RAYMIRROR 0x40000
+#define MA_SHADOW_TRA 0x80000
+#define MA_RAMP_COL 0x100000
+#define MA_RAMP_SPEC 0x200000
+#define MA_RAYBIAS 0x400000
+#define MA_FULL_OSA 0x800000
+#define MA_TANGENT_STR 0x1000000
+#define MA_SHADBUF 0x2000000
+ /* note; we drop MA_TANGENT_STR later to become tangent_u */
+#define MA_TANGENT_V 0x4000000
+/* qdn: a bit clumsy this, tangents needed for normal maps separated from shading */
+#define MA_NORMAP_TANG 0x8000000
+#define MA_GROUP_NOLAY 0x10000000
+
+#define MA_MODE_MASK 0x1fffffff /* all valid mode bits */
+
+/* ray mirror fadeout */
+#define MA_RAYMIR_FADETOSKY 0
+#define MA_RAYMIR_FADETOMAT 1
+
+/* diff_shader */
+#define MA_DIFF_LAMBERT 0
+#define MA_DIFF_ORENNAYAR 1
+#define MA_DIFF_TOON 2
+#define MA_DIFF_MINNAERT 3
+#define MA_DIFF_FRESNEL 4
+
+/* spec_shader */
+#define MA_SPEC_COOKTORR 0
+#define MA_SPEC_PHONG 1
+#define MA_SPEC_BLINN 2
+#define MA_SPEC_TOON 3
+#define MA_SPEC_WARDISO 4
+
+/* dynamode */
+#define MA_DRAW_DYNABUTS 1
+#define MA_FH_NOR 2
+
+/* ramps */
+#define MA_RAMP_IN_SHADER 0
+#define MA_RAMP_IN_ENERGY 1
+#define MA_RAMP_IN_NOR 2
+#define MA_RAMP_IN_RESULT 3
+
+#define MA_RAMP_BLEND 0
+#define MA_RAMP_ADD 1
+#define MA_RAMP_MULT 2
+#define MA_RAMP_SUB 3
+#define MA_RAMP_SCREEN 4
+#define MA_RAMP_DIV 5
+#define MA_RAMP_DIFF 6
+#define MA_RAMP_DARK 7
+#define MA_RAMP_LIGHT 8
+#define MA_RAMP_OVERLAY 9
+#define MA_RAMP_DODGE 10
+#define MA_RAMP_BURN 11
+#define MA_RAMP_HUE 12
+#define MA_RAMP_SAT 13
+#define MA_RAMP_VAL 14
+#define MA_RAMP_COLOR 15
+
+/* texco */
+#define TEXCO_ORCO 1
+#define TEXCO_REFL 2
+#define TEXCO_NORM 4
+#define TEXCO_GLOB 8
+#define TEXCO_UV 16
+#define TEXCO_OBJECT 32
+#define TEXCO_LAVECTOR 64
+#define TEXCO_VIEW 128
+#define TEXCO_STICKY 256
+#define TEXCO_OSA 512
+#define TEXCO_WINDOW 1024
+#define NEED_UV 2048
+#define TEXCO_TANGENT 4096
+ /* still stored in vertex->accum, 1 D */
+#define TEXCO_STRAND 8192
+#define TEXCO_STRESS 16384
+#define TEXCO_SPEED 32768
+
+/* mapto */
+#define MAP_COL 1
+#define MAP_NORM 2
+#define MAP_COLSPEC 4
+#define MAP_COLMIR 8
+#define MAP_VARS (0xFFF0)
+#define MAP_REF 16
+#define MAP_SPEC 32
+#define MAP_EMIT 64
+#define MAP_ALPHA 128
+#define MAP_HAR 256
+#define MAP_RAYMIRR 512
+#define MAP_TRANSLU 1024
+#define MAP_AMB 2048
+#define MAP_DISPLACE 4096
+#define MAP_WARP 8192
+#define MAP_LAYER 16384
+
+/* pr_type */
+#define MA_FLAT 0
+#define MA_SPHERE 1
+#define MA_CUBE 2
+#define MA_MONKEY 3
+#define MA_SPHERE_A 4
+#define MA_TEXTURE 5
+#define MA_LAMP 6
+#define MA_SKY 7
+#define MA_HAIR 10
+
+/* pr_back */
+#define MA_DARK 1
+
+/* sss_flag */
+#define MA_DIFF_SSS 1
+
+#endif
+
diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h
new file mode 100644
index 00000000000..59f3a64ba5e
--- /dev/null
+++ b/source/blender/makesdna/DNA_mesh_types.h
@@ -0,0 +1,139 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef DNA_MESH_TYPES_H
+#define DNA_MESH_TYPES_H
+
+#include "DNA_listBase.h"
+#include "DNA_ID.h"
+#include "DNA_customdata_types.h"
+
+struct DerivedMesh;
+struct Ipo;
+struct Key;
+struct Material;
+struct MVert;
+struct MEdge;
+struct MFace;
+struct MCol;
+struct MSticky;
+struct Mesh;
+struct OcInfo;
+struct Multires;
+struct PartialVisibility;
+
+typedef struct Mesh {
+ ID id;
+
+ struct BoundBox *bb;
+
+ ListBase effect;
+
+ struct Ipo *ipo;
+ struct Key *key;
+ struct Material **mat;
+
+ struct MFace *mface; /* array of mesh object mode faces */
+ struct MTFace *mtface; /* store face UV's and texture here */
+ struct TFace *tface; /* depecrated, use mtface */
+ struct MVert *mvert; /* array of verts */
+ struct MEdge *medge; /* array of edges */
+ struct MDeformVert *dvert; /* __NLA */
+ struct MCol *mcol; /* array of colors, this must be the number of faces * 4 */
+ struct MSticky *msticky;
+ struct Mesh *texcomesh;
+ struct MSelect *mselect;
+
+ struct CustomData vdata, edata, fdata;
+
+ int totvert, totedge, totface, totselect;
+
+ /* the last selected vertex/edge/face are used for the active face however
+ * this means the active face must always be selected, this is to keep track
+ * of the last selected face and is similar to the old active face flag where
+ * the face does not need to be selected, -1 is inactive */
+ int act_face;
+
+ int texflag;
+
+ /* texture space, copied as one block in editobject.c */
+ float loc[3];
+ float size[3];
+ float rot[3];
+
+ float cubemapsize, pad;
+
+ short smoothresh, flag;
+
+ short subdiv, subdivr;
+ short totcol;
+ short subsurftype; /* only kept for backwards compat, not used anymore */
+
+ struct Multires *mr; /* Multiresolution modeling data */
+ struct PartialVisibility *pv;
+/*ifdef WITH_VERSE*/
+ /* not written in file, pointer at geometry VerseNode */
+ void *vnode;
+/*#endif*/
+} Mesh;
+
+/* deprecated by MTFace, only here for file reading */
+typedef struct TFace {
+ void *tpage; /* the faces image for the active UVLayer */
+ float uv[4][2];
+ unsigned int col[4];
+ char flag, transp;
+ short mode, tile, unwrap;
+} TFace;
+
+/* **************** MESH ********************* */
+
+/* texflag */
+#define AUTOSPACE 1
+
+/* me->flag */
+#define ME_ISDONE 1
+#define ME_NOPUNOFLIP 2
+#define ME_TWOSIDED 4
+#define ME_UVEFFECT 8
+#define ME_VCOLEFFECT 16
+#define ME_AUTOSMOOTH 32
+#define ME_SMESH 64
+#define ME_SUBSURF 128
+#define ME_OPT_EDGES 256
+
+/* Subsurf Type */
+#define ME_CC_SUBSURF 0
+#define ME_SIMPLE_SUBSURF 1
+
+#define MESH_MAX_VERTS 2000000000L
+
+#endif
diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h
new file mode 100644
index 00000000000..68d9bb245cf
--- /dev/null
+++ b/source/blender/makesdna/DNA_meshdata_types.h
@@ -0,0 +1,250 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef DNA_MESHDATA_TYPES_H
+#define DNA_MESHDATA_TYPES_H
+
+#include "DNA_customdata_types.h"
+
+struct Bone;
+struct Image;
+
+typedef struct MFace {
+ unsigned int v1, v2, v3, v4;
+ char pad, mat_nr;
+ char edcode, flag; /* we keep edcode, for conversion to edges draw flags in old files */
+} MFace;
+
+typedef struct MEdge {
+ unsigned int v1, v2;
+ char crease, pad;
+ short flag;
+} MEdge;
+
+typedef struct MDeformWeight {
+ int def_nr;
+ float weight;
+} MDeformWeight;
+
+typedef struct MDeformVert {
+ struct MDeformWeight *dw;
+ int totweight;
+ int flag; /* flag only in use for weightpaint now */
+} MDeformVert;
+
+typedef struct MVert {
+ float co[3];
+ short no[3];
+ char flag, mat_nr;
+} MVert;
+
+/* at the moment alpha is abused for vertex painting
+ * and not used for transperency, note that red and blue are swapped */
+typedef struct MCol {
+ char a, r, g, b;
+} MCol;
+
+typedef struct MSticky {
+ float co[2];
+} MSticky;
+
+typedef struct MSelect {
+ int index;
+ int type;
+} MSelect;
+
+typedef struct MTFace {
+ float uv[4][2];
+ struct Image *tpage;
+ char flag, transp;
+ short mode, tile, unwrap;
+} MTFace;
+
+/*Custom Data Properties*/
+typedef struct MFloatProperty{
+ float f;
+} MFloatProperty;
+typedef struct MIntProperty{
+ int i;
+} MIntProperty;
+typedef struct MStringProperty{
+ char s[256];
+} MStringProperty;
+
+
+/* Multiresolution modeling */
+typedef struct MultiresCol {
+ float a, r, g, b;
+} MultiresCol;
+typedef struct MultiresColFace {
+ /* vertex colors */
+ MultiresCol col[4];
+} MultiresColFace;
+typedef struct MultiresFace {
+ unsigned int v[4];
+ unsigned int mid;
+ char flag, mat_nr, pad[2];
+} MultiresFace;
+typedef struct MultiresEdge {
+ unsigned int v[2];
+ unsigned int mid;
+} MultiresEdge;
+
+struct MultiresMapNode;
+typedef struct MultiresLevel {
+ struct MultiresLevel *next, *prev;
+
+ MultiresFace *faces;
+ MultiresColFace *colfaces;
+ MultiresEdge *edges;
+
+ /* Temporary connectivity data */
+ char *edge_boundary_states;
+ struct ListBase *vert_edge_map;
+ struct ListBase *vert_face_map;
+ struct MultiresMapNode *map_mem;
+
+ unsigned int totvert, totface, totedge, pad;
+
+ /* Kept for compatibility with older files */
+ MVert *verts;
+} MultiresLevel;
+
+typedef struct Multires {
+ ListBase levels;
+ MVert *verts;
+
+ unsigned char level_count, current, newlvl, edgelvl, pinlvl, renderlvl;
+ unsigned char use_col, pad;
+
+ /* Special level 1 data that cannot be modified from other levels */
+ CustomData vdata;
+ CustomData fdata;
+ short *edge_flags;
+ char *edge_creases;
+} Multires;
+
+typedef struct PartialVisibility {
+ unsigned int *vert_map; /* vert_map[Old Index]= New Index */
+ int *edge_map; /* edge_map[Old Index]= New Index, -1= hidden */
+ MFace *old_faces;
+ MEdge *old_edges;
+ unsigned int totface, totedge, totvert, pad;
+} PartialVisibility;
+
+/* mvert->flag (1=SELECT) */
+#define ME_SPHERETEST 2
+#define ME_SPHERETEMP 4
+#define ME_HIDE 16
+#define ME_VERT_MERGED (1<<6)
+
+/* medge->flag (1=SELECT)*/
+#define ME_EDGEDRAW (1<<1)
+#define ME_SEAM (1<<2)
+#define ME_FGON (1<<3)
+ /* reserve 16 for ME_HIDE */
+#define ME_EDGERENDER (1<<5)
+#define ME_LOOSEEDGE (1<<7)
+#define ME_SEAM_LAST (1<<8)
+#define ME_SHARP (1<<9)
+
+/* puno = vertexnormal (mface) */
+/* render assumes flips to be ordered like this */
+#define ME_FLIPV1 1
+#define ME_FLIPV2 2
+#define ME_FLIPV3 4
+#define ME_FLIPV4 8
+#define ME_PROJXY 16
+#define ME_PROJXZ 32
+#define ME_PROJYZ 64
+
+/* edcode (mface) */
+#define ME_V1V2 1
+#define ME_V2V3 2
+#define ME_V3V1 4
+#define ME_V3V4 4
+#define ME_V4V1 8
+
+/* flag (mface) */
+#define ME_SMOOTH 1
+#define ME_FACE_SEL 2
+ /* flag ME_HIDE==16 is used here too */
+/* mselect->type */
+#define ME_VSEl 0
+#define ME_ESEl 1
+#define ME_FSEL 2
+
+/* mtface->flag */
+#define TF_SELECT 1 /* use MFace hide flag (after 2.43), should be able to reuse after 2.44 */
+#define TF_ACTIVE 2 /* deprecated! */
+#define TF_SEL1 4
+#define TF_SEL2 8
+#define TF_SEL3 16
+#define TF_SEL4 32
+#define TF_HIDE 64 /* unused, same as TF_SELECT */
+
+/* mtface->mode */
+#define TF_DYNAMIC 1
+#define TF_DEPRECATED 2
+#define TF_TEX 4
+#define TF_SHAREDVERT 8
+#define TF_LIGHT 16
+
+#define TF_SHAREDCOL 64
+#define TF_TILES 128
+#define TF_BILLBOARD 256
+#define TF_TWOSIDE 512
+#define TF_INVISIBLE 1024
+
+#define TF_OBCOL 2048
+#define TF_BILLBOARD2 4096 /* with Z axis constraint */
+#define TF_SHADOW 8192
+#define TF_BMFONT 16384
+
+/* mtface->transp */
+#define TF_SOLID 0
+#define TF_ADD 1
+#define TF_ALPHA 2
+
+/* sub is not available in the user interface anymore */
+#define TF_SUB 3
+
+/* mtface->unwrap */
+#define TF_DEPRECATED1 1
+#define TF_DEPRECATED2 2
+#define TF_DEPRECATED3 4
+#define TF_DEPRECATED4 8
+#define TF_PIN1 16
+#define TF_PIN2 32
+#define TF_PIN3 64
+#define TF_PIN4 128
+
+#endif
diff --git a/source/blender/makesdna/DNA_meta_types.h b/source/blender/makesdna/DNA_meta_types.h
new file mode 100644
index 00000000000..e14782cf5ca
--- /dev/null
+++ b/source/blender/makesdna/DNA_meta_types.h
@@ -0,0 +1,120 @@
+/**
+ * blenlib/DNA_meta_types.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef DNA_META_TYPES_H
+#define DNA_META_TYPES_H
+
+#include "DNA_listBase.h"
+#include "DNA_ID.h"
+
+struct BoundBox;
+struct Ipo;
+struct Material;
+
+
+typedef struct MetaElem {
+ struct MetaElem *next, *prev;
+
+ struct BoundBox *bb; /* Bound Box of MetaElem */
+ int i1,j1,k1, i2,j2,k2; /* corners of Bounding Box in lattice */
+
+ short type, flag, selcol1, selcol2;
+ float x, y, z; /* Position of center of MetaElem */
+ float quat[4]; /* Rotation of MetaElem */
+ float expx, expy, expz; /* dimension parameters, used for some types like cubes */
+ float rad; /* radius of the meta element */
+ float rad2; /* temp field, used only while processing */
+ float s; /* stiffness, how much of the element to fill */
+ float len; /* old, only used for backwards compat. use dimensions now */
+
+ float *mat, *imat; /* matrix and inverted matrix */
+
+} MetaElem;
+
+typedef struct MetaBall {
+ ID id;
+
+ struct BoundBox *bb;
+
+ ListBase elems;
+ ListBase disp;
+ struct Ipo *ipo;
+
+ /* material of the mother ball will define the material used of all others */
+ struct Material **mat;
+
+ short flag, totcol;
+ int texflag; /* used to store MB_AUTOSPACE */
+
+ /* texture space, copied as one block in editobject.c */
+ float loc[3];
+ float size[3];
+ float rot[3];
+
+ float wiresize, rendersize; /* display and render res */
+
+ /* bias elements to have an offset volume.
+ mother ball changes will effect other objects thresholds,
+ but these may also have their own thresh as an offset */
+ float thresh;
+
+
+} MetaBall;
+
+/* **************** METABALL ********************* */
+
+/* texflag */
+#define MB_AUTOSPACE 1
+
+/* mb->flag */
+#define MB_UPDATE_ALWAYS 0
+#define MB_UPDATE_HALFRES 1
+#define MB_UPDATE_FAST 2
+#define MB_UPDATE_NEVER 3
+
+/* ml->type */
+#define MB_BALL 0
+#define MB_TUBEX 1 /* depercated */
+#define MB_TUBEY 2 /* depercated */
+#define MB_TUBEZ 3 /* depercated */
+#define MB_TUBE 4
+#define MB_PLANE 5
+#define MB_ELIPSOID 6
+#define MB_CUBE 7
+
+/* ml->flag */
+#define MB_NEGATIVE 2
+#define MB_HIDE 8
+#define MB_SCALE_RAD 16
+
+#endif
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
new file mode 100644
index 00000000000..42016ad1c16
--- /dev/null
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -0,0 +1,366 @@
+/**
+ * $Id$
+ */
+
+#ifndef DNA_MODIFIER_TYPES_H
+#define DNA_MODIFIER_TYPES_H
+
+#define MODSTACK_DEBUG 1
+
+/* WARNING ALERT! TYPEDEF VALUES ARE WRITTEN IN FILES! SO DO NOT CHANGE! */
+
+typedef enum ModifierType {
+ eModifierType_None = 0,
+ eModifierType_Subsurf,
+ eModifierType_Lattice,
+ eModifierType_Curve,
+ eModifierType_Build,
+ eModifierType_Mirror,
+ eModifierType_Decimate,
+ eModifierType_Wave,
+ eModifierType_Armature,
+ eModifierType_Hook,
+ eModifierType_Softbody,
+ eModifierType_Boolean,
+ eModifierType_Array,
+ eModifierType_EdgeSplit,
+ eModifierType_Displace,
+ eModifierType_UVProject,
+ eModifierType_Smooth,
+ eModifierType_Cast,
+ eModifierType_MeshDeform,
+ NUM_MODIFIER_TYPES
+} ModifierType;
+
+typedef enum ModifierMode {
+ eModifierMode_Realtime = (1<<0),
+ eModifierMode_Render = (1<<1),
+ eModifierMode_Editmode = (1<<2),
+ eModifierMode_OnCage = (1<<3),
+ eModifierMode_Expanded = (1<<4),
+ eModifierMode_Virtual = (1<<5),
+ eModifierMode_DisableTemporary = (1 << 31)
+} ModifierMode;
+
+typedef struct ModifierData {
+ struct ModifierData *next, *prev;
+
+ int type, mode;
+ char name[32];
+
+ char *error;
+} ModifierData;
+
+typedef enum {
+ eSubsurfModifierFlag_Incremental = (1<<0),
+ eSubsurfModifierFlag_DebugIncr = (1<<1),
+ eSubsurfModifierFlag_ControlEdges = (1<<2),
+ eSubsurfModifierFlag_SubsurfUv = (1<<3)
+} SubsurfModifierFlag;
+
+typedef struct SubsurfModifierData {
+ ModifierData modifier;
+
+ short subdivType, levels, renderLevels, flags;
+
+ void *emCache, *mCache;
+} SubsurfModifierData;
+
+typedef struct LatticeModifierData {
+ ModifierData modifier;
+
+ struct Object *object;
+ char name[32]; /* optional vertexgroup name */
+} LatticeModifierData;
+
+typedef struct CurveModifierData {
+ ModifierData modifier;
+
+ struct Object *object;
+ char name[32]; /* optional vertexgroup name */
+ short defaxis; /* axis along which curve deforms */
+ char pad[6];
+} CurveModifierData;
+
+/* CurveModifierData->defaxis */
+#define MOD_CURVE_POSX 1
+#define MOD_CURVE_POSY 2
+#define MOD_CURVE_POSZ 3
+#define MOD_CURVE_NEGX 4
+#define MOD_CURVE_NEGY 5
+#define MOD_CURVE_NEGZ 6
+
+typedef struct BuildModifierData {
+ ModifierData modifier;
+
+ float start, length;
+ int randomize, seed;
+} BuildModifierData;
+
+typedef struct ArrayModifierData {
+ ModifierData modifier;
+
+ /* the object with which to cap the start of the array */
+ struct Object *start_cap;
+ /* the object with which to cap the end of the array */
+ struct Object *end_cap;
+ /* the curve object to use for MOD_ARR_FITCURVE */
+ struct Object *curve_ob;
+ /* the object to use for object offset */
+ struct Object *offset_ob;
+ /* a constant duplicate offset;
+ 1 means the duplicates are 1 unit apart
+ */
+ float offset[3];
+ /* a scaled factor for duplicate offsets;
+ 1 means the duplicates are 1 object-width apart
+ */
+ float scale[3];
+ /* the length over which to distribute the duplicates */
+ float length;
+ /* the limit below which to merge vertices in adjacent duplicates */
+ float merge_dist;
+ /* determines how duplicate count is calculated; one of:
+ MOD_ARR_FIXEDCOUNT -> fixed
+ MOD_ARR_FITLENGTH -> calculated to fit a set length
+ MOD_ARR_FITCURVE -> calculated to fit the length of a Curve object
+ */
+ int fit_type;
+ /* flags specifying how total offset is calculated; binary OR of:
+ MOD_ARR_OFF_CONST -> total offset += offset
+ MOD_ARR_OFF_RELATIVE -> total offset += relative * object width
+ MOD_ARR_OFF_OBJ -> total offset += offset_ob's matrix
+ total offset is the sum of the individual enabled offsets
+ */
+ int offset_type;
+ /* general flags:
+ MOD_ARR_MERGE -> merge vertices in adjacent duplicates
+ */
+ int flags;
+ /* the number of duplicates to generate for MOD_ARR_FIXEDCOUNT */
+ int count;
+} ArrayModifierData;
+
+/* ArrayModifierData->fit_type */
+#define MOD_ARR_FIXEDCOUNT 0
+#define MOD_ARR_FITLENGTH 1
+#define MOD_ARR_FITCURVE 2
+
+/* ArrayModifierData->offset_type */
+#define MOD_ARR_OFF_CONST 1<<0
+#define MOD_ARR_OFF_RELATIVE 1<<1
+#define MOD_ARR_OFF_OBJ 1<<2
+
+/* ArrayModifierData->flags */
+#define MOD_ARR_MERGE 1<<0
+#define MOD_ARR_MERGEFINAL 1<<1
+
+typedef struct MirrorModifierData {
+ ModifierData modifier;
+
+ short axis, flag;
+ float tolerance;
+} MirrorModifierData;
+
+/* MirrorModifierData->flag */
+#define MOD_MIR_CLIPPING 1<<0
+#define MOD_MIR_MIRROR_U 1<<1
+#define MOD_MIR_MIRROR_V 1<<2
+#define MOD_MIR_AXIS_X 1<<3
+#define MOD_MIR_AXIS_Y 1<<4
+#define MOD_MIR_AXIS_Z 1<<5
+
+typedef struct EdgeSplitModifierData {
+ ModifierData modifier;
+
+ float split_angle; /* angle above which edges should be split */
+ int flags;
+} EdgeSplitModifierData;
+
+/* EdgeSplitModifierData->flags */
+#define MOD_EDGESPLIT_FROMANGLE 1<<1
+#define MOD_EDGESPLIT_FROMFLAG 1<<2
+
+typedef struct DisplaceModifierData {
+ ModifierData modifier;
+
+ struct Tex *texture;
+ float strength;
+ int direction;
+ char defgrp_name[32];
+ float midlevel;
+ int texmapping;
+ struct Object *map_object;
+ char uvlayer_name[32];
+ int uvlayer_tmp, pad;
+} DisplaceModifierData;
+
+/* DisplaceModifierData->direction */
+enum {
+ MOD_DISP_DIR_X,
+ MOD_DISP_DIR_Y,
+ MOD_DISP_DIR_Z,
+ MOD_DISP_DIR_NOR,
+ MOD_DISP_DIR_RGB_XYZ,
+};
+
+/* DisplaceModifierData->texmapping */
+enum {
+ MOD_DISP_MAP_LOCAL,
+ MOD_DISP_MAP_GLOBAL,
+ MOD_DISP_MAP_OBJECT,
+ MOD_DISP_MAP_UV,
+};
+
+typedef struct UVProjectModifierData {
+ ModifierData modifier;
+
+ /* the objects which do the projecting */
+ struct Object *projectors[10];
+ struct Image *image; /* the image to project */
+ int flags;
+ int num_projectors;
+ float aspectx, aspecty;
+ char uvlayer_name[32];
+ int uvlayer_tmp, pad;
+} UVProjectModifierData;
+
+#define MOD_UVPROJECT_MAXPROJECTORS 10
+
+/* UVProjectModifierData->flags */
+#define MOD_UVPROJECT_OVERRIDEIMAGE 1<<0
+
+typedef struct DecimateModifierData {
+ ModifierData modifier;
+
+ float percent;
+ int faceCount;
+} DecimateModifierData;
+
+/* Smooth modifier flags */
+#define MOD_SMOOTH_X (1<<1)
+#define MOD_SMOOTH_Y (1<<2)
+#define MOD_SMOOTH_Z (1<<3)
+
+typedef struct SmoothModifierData {
+ ModifierData modifier;
+ float fac;
+ char defgrp_name[32];
+ short flag, repeat;
+
+} SmoothModifierData;
+
+/* Cast modifier flags */
+#define MOD_CAST_X (1<<1)
+#define MOD_CAST_Y (1<<2)
+#define MOD_CAST_Z (1<<3)
+#define MOD_CAST_USE_OB_TRANSFORM (1<<4)
+#define MOD_CAST_SIZE_FROM_RADIUS (1<<5)
+
+/* Cast modifier projection types */
+#define MOD_CAST_TYPE_SPHERE 0
+#define MOD_CAST_TYPE_CYLINDER 1
+#define MOD_CAST_TYPE_CUBOID 2
+
+typedef struct CastModifierData {
+ ModifierData modifier;
+
+ struct Object *object;
+ float fac;
+ float radius;
+ float size;
+ char defgrp_name[32];
+ short flag, type;
+} CastModifierData;
+
+enum {
+ MOD_WAV_MAP_LOCAL,
+ MOD_WAV_MAP_GLOBAL,
+ MOD_WAV_MAP_OBJECT,
+ MOD_WAV_MAP_UV,
+};
+
+/* WaveModifierData.flag */
+#define MOD_WAVE_X 1<<1
+#define MOD_WAVE_Y 1<<2
+#define MOD_WAVE_CYCL 1<<3
+#define MOD_WAVE_NORM 1<<4
+#define MOD_WAVE_NORM_X 1<<5
+#define MOD_WAVE_NORM_Y 1<<6
+#define MOD_WAVE_NORM_Z 1<<7
+
+typedef struct WaveModifierData {
+ ModifierData modifier;
+
+ struct Object *objectcenter;
+ char defgrp_name[32];
+ struct Tex *texture;
+ struct Object *map_object;
+
+ short flag, pad;
+
+ float startx, starty, height, width;
+ float narrow, speed, damp;
+
+ int texmapping, uvlayer_tmp;
+
+ char uvlayer_name[32];
+
+ float timeoffs, lifetime;
+} WaveModifierData;
+
+typedef struct ArmatureModifierData {
+ ModifierData modifier;
+
+ short deformflag, pad1; /* deformflag replaces armature->deformflag */
+ int pad2;
+ struct Object *object;
+ char defgrp_name[32];
+} ArmatureModifierData;
+
+typedef struct HookModifierData {
+ ModifierData modifier;
+
+ struct Object *object;
+ float parentinv[4][4]; /* matrix making current transform unmodified */
+ float cent[3]; /* visualization of hook */
+ float falloff; /* if not zero, falloff is distance where influence zero */
+
+ int *indexar; /* if NULL, it's using vertexgroup */
+ int totindex;
+ float force;
+ char name[32]; /* optional vertexgroup name */
+} HookModifierData;
+
+typedef struct SoftbodyModifierData {
+ ModifierData modifier;
+} SoftbodyModifierData;
+
+typedef enum {
+ eBooleanModifierOp_Intersect,
+ eBooleanModifierOp_Union,
+ eBooleanModifierOp_Difference,
+} BooleanModifierOp;
+typedef struct BooleanModifierData {
+ ModifierData modifier;
+
+ struct Object *object;
+ int operation, pad;
+} BooleanModifierData;
+
+#define MOD_MDEF_INVERT_VGROUP (1<<0)
+
+typedef struct MeshDeformModifierData {
+ ModifierData modifier;
+
+ struct Object *object; /* mesh object */
+ char defgrp_name[32]; /* optional vertexgroup name */
+
+ float *bindweights, *bindcos; /* computed binding weights */
+ short gridsize, needbind;
+ short flag, pad;
+
+ int totvert, totcagevert;
+} MeshDeformModifierData;
+
+#endif
diff --git a/source/blender/makesdna/DNA_nla_types.h b/source/blender/makesdna/DNA_nla_types.h
new file mode 100644
index 00000000000..d7ccfe01085
--- /dev/null
+++ b/source/blender/makesdna/DNA_nla_types.h
@@ -0,0 +1,105 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef DNA_NLA_TYPES_H
+#define DNA_NLA_TYPES_H
+
+#include "DNA_listBase.h"
+
+struct bAction;
+struct Ipo;
+struct Object;
+
+/* simple uniform modifier structure, assumed it can hold all type info */
+typedef struct bActionModifier {
+ struct bActionModifier *next, *prev;
+ short type, flag;
+ char channel[32];
+
+ /* noise modifier */
+ float noisesize, turbul;
+ short channels;
+
+ /* path deform modifier */
+ short no_rot_axis;
+ struct Object *ob;
+} bActionModifier;
+
+/* NLA-Modifier Types */
+#define ACTSTRIP_MOD_DEFORM 0
+#define ACTSTRIP_MOD_NOISE 1
+#define ACTSTRIP_MOD_OOMPH 2
+
+typedef struct bActionStrip {
+ struct bActionStrip *next, *prev;
+ short flag, mode;
+ short stride_axis; /* axis 0=x, 1=y, 2=z */
+ short curmod; /* current modifier for buttons */
+
+ struct Ipo *ipo; /* Blending ipo - was used for some old NAN era experiments. Non-functional currently. */
+ struct bAction *act; /* The action referenced by this strip */
+ struct Object *object; /* For groups, the actual object being nla'ed */
+ float start, end; /* The range of frames covered by this strip */
+ float actstart, actend; /* The range of frames taken from the action */
+ float actoffs, padf; /* Offset within action, for cycles and striding */
+ float stridelen; /* The stridelength (considered when flag & ACT_USESTRIDE) */
+ float repeat; /* The number of times to repeat the action range */
+
+ float blendin, blendout; /* The number of frames on either end of the strip's length to fade in/out */
+
+ char stridechannel[32]; /* Instead of stridelen, it uses an action channel */
+ char offs_bone[32]; /* if repeat, use this bone/channel for defining offset */
+
+ struct ListBase modifiers; /* modifier stack */
+
+} bActionStrip;
+
+/* strip->mode (these defines aren't really used, but are here for reference) */
+#define ACTSTRIPMODE_BLEND 0
+#define ACTSTRIPMODE_ADD 1
+
+/* strip->flag */
+#define ACTSTRIP_SELECT 0x01
+#define ACTSTRIP_USESTRIDE 0x02
+#define ACTSTRIP_BLENDTONEXT 0x04 /* Not implemented. Is not used anywhere */
+#define ACTSTRIP_HOLDLASTFRAME 0x08
+#define ACTSTRIP_ACTIVE 0x10
+#define ACTSTRIP_LOCK_ACTION 0x20
+#define ACTSTRIP_MUTE 0x40
+#define ACTSTRIP_REVERSE 0x80 /* This has yet to be implemented. To indicate that a strip should be played backwards */
+#define ACTSTRIP_CYCLIC_USEX 0x100
+#define ACTSTRIP_CYCLIC_USEY 0x200
+#define ACTSTRIP_CYCLIC_USEZ 0x400
+#define ACTSTRIP_AUTO_BLENDS 0x800
+
+#endif
+
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
new file mode 100644
index 00000000000..5f20939fc23
--- /dev/null
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -0,0 +1,257 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef DNA_NODE_TYPES_H
+#define DNA_NODE_TYPES_H
+
+#include "DNA_ID.h"
+#include "DNA_vec_types.h"
+#include "DNA_listBase.h"
+
+struct ListBase;
+struct SpaceNode;
+struct bNodeLink;
+struct bNodeType;
+struct bNodeGroup;
+
+#define NODE_MAXSTR 32
+
+
+typedef struct bNodeStack {
+ float vec[4];
+ float min, max; /* min/max for values (UI writes it, execute might use it) */
+ void *data;
+ short hasinput; /* when input has link, tagged before executing */
+ short hasoutput; /* when output is linked, tagged before executing */
+ short datatype; /* type of data pointer */
+ short sockettype; /* type of socket stack comes from, to remap linking different sockets */
+} bNodeStack;
+
+/* ns->datatype, shadetree only */
+#define NS_OSA_VECTORS 1
+#define NS_OSA_VALUES 2
+
+typedef struct bNodeSocket {
+ struct bNodeSocket *next, *prev;
+
+ char name[32];
+ bNodeStack ns; /* custom data for inputs, only UI writes in this */
+
+ short type, flag; /* type is copy from socket type struct */
+ short limit, stack_index; /* limit for dependency sort, stack_index for exec */
+ short intern; /* intern = tag for group nodes */
+ short stack_index_ext; /* for groups, to find the caller stack index */
+ int pad1;
+
+ float locx, locy;
+
+ /* internal data to retrieve relations and groups */
+
+ int own_index, to_index; /* group socket identifiers, to find matching pairs after reading files */
+
+ struct bNodeSocket *tosock; /* group-node sockets point to the internal group counterpart sockets, set after read file */
+ struct bNodeLink *link; /* a link pointer, set in nodeSolveOrder() */
+
+} bNodeSocket;
+
+/* sock->type */
+#define SOCK_VALUE 0
+#define SOCK_VECTOR 1
+#define SOCK_RGBA 2
+
+/* sock->flag, first bit is select */
+ /* hidden is user defined, to hide unused */
+#define SOCK_HIDDEN 2
+ /* only used now for groups... */
+#define SOCK_IN_USE 4
+ /* unavailable is for dynamic sockets */
+#define SOCK_UNAVAIL 8
+
+#
+#
+typedef struct bNodePreview {
+ float *rect;
+ short xsize, ysize;
+} bNodePreview;
+
+
+/* limit data in bNode to what we want to see saved? */
+typedef struct bNode {
+ struct bNode *next, *prev, *new_node;
+
+ char name[32];
+ short type, flag;
+ short done, level; /* both for dependency and sorting */
+ short lasty, menunr; /* lasty: check preview render status, menunr: browse ID blocks */
+ short stack_index; /* for groupnode, offset in global caller stack */
+ short nr; /* number of this node in list, used for UI exec events */
+
+ ListBase inputs, outputs;
+ struct ID *id; /* optional link to libdata */
+ void *storage; /* custom data, must be struct, for storage in file */
+
+ float locx, locy; /* root offset for drawing */
+ float width, miniwidth;
+ short custom1, custom2; /* to be abused for buttons */
+
+ short need_exec, exec; /* need_exec is set as UI execution event, exec is flag during exec */
+
+ rctf totr; /* entire boundbox */
+ rctf butr; /* optional buttons area */
+ rctf prvr; /* optional preview area */
+ bNodePreview *preview; /* optional preview image */
+
+ struct bNodeType *typeinfo; /* lookup of callbacks and defaults */
+
+} bNode;
+
+/* node->flag */
+#define NODE_SELECT 1
+#define NODE_OPTIONS 2
+#define NODE_PREVIEW 4
+#define NODE_HIDDEN 8
+#define NODE_ACTIVE 16
+#define NODE_ACTIVE_ID 32
+#define NODE_DO_OUTPUT 64
+#define NODE_GROUP_EDIT 128
+ /* free test flag, undefined */
+#define NODE_TEST 256
+
+typedef struct bNodeLink {
+ struct bNodeLink *next, *prev;
+
+ bNode *fromnode, *tonode;
+ bNodeSocket *fromsock, *tosock;
+
+} bNodeLink;
+
+/* the basis for a Node tree, all links and nodes reside internal here */
+/* only re-usable node trees are in the library though, materials allocate own tree struct */
+typedef struct bNodeTree {
+ ID id;
+
+ ListBase nodes, links;
+
+ bNodeStack **stack; /* stack is only while executing, no read/write in file */
+
+ int type, init; /* set init on fileread */
+ int stacksize; /* amount of elements in stack */
+ int cur_index; /* sockets in groups have unique identifiers, adding new sockets always
+ will increase this counter */
+ ListBase alltypes; /* type definitions */
+ struct bNodeType *owntype; /* for groups or dynamic trees, no read/write */
+
+ /* callbacks */
+ void (*timecursor)(int nr);
+ void (*stats_draw)(char *str);
+ int (*test_break)(void);
+} bNodeTree;
+
+/* ntree->type, index */
+#define NTREE_SHADER 0
+#define NTREE_COMPOSIT 1
+
+/* ntree->init, flag */
+#define NTREE_TYPE_INIT 1
+#define NTREE_EXEC_INIT 2
+
+/* data structs, for node->storage */
+
+/* this one has been replaced with ImageUser, keep it for do_versions() */
+typedef struct NodeImageAnim {
+ int frames, sfra, nr;
+ char cyclic, movie;
+ short pad;
+} NodeImageAnim;
+
+typedef struct NodeBlurData {
+ short sizex, sizey, samples, maxspeed, minspeed, pad1;
+ float fac;
+ short filtertype;
+ char bokeh, gamma;
+ int pad2;
+} NodeBlurData;
+
+typedef struct NodeHueSat {
+ float hue, sat, val;
+} NodeHueSat;
+
+typedef struct NodeImageFile {
+ char name[256];
+ short imtype, subimtype, quality, codec;
+ int sfra, efra;
+} NodeImageFile;
+
+typedef struct NodeChroma {
+ float t1,t2,t3;
+ float fsize,fstrength,falpha;
+ float key[4];
+} NodeChroma;
+
+typedef struct NodeTwoXYs {
+ short x1, x2, y1, y2;
+} NodeTwoXYs;
+
+typedef struct NodeGeometry {
+ char uvname[32];
+ char colname[32];
+} NodeGeometry;
+
+typedef struct NodeVertexCol {
+ char name[32];
+} NodeVertexCol;
+
+/* qdn: Defocus blur node */
+typedef struct NodeDefocus {
+ char bktype, rotation, preview, gamco;
+ short samples, no_zbuf;
+ float fstop, maxblur, bthresh, scale;
+} NodeDefocus;
+
+
+/* qdn: glare node */
+typedef struct NodeGlare {
+ char quality, type, iter;
+ char angle, angle_ofs, size, pad[2];
+ float colmod, mix, threshold, fade;
+} NodeGlare;
+
+/* qdn: tonemap node */
+typedef struct NodeTonemap {
+ float key, offset, gamma;
+ float f, m, a, c;
+ int type;
+} NodeTonemap;
+
+/* qdn: lens distortion node */
+typedef struct NodeLensDist {
+ short jit, proj, fit, pad;
+} NodeLensDist;
+
+#endif
diff --git a/source/blender/makesdna/DNA_object_fluidsim.h b/source/blender/makesdna/DNA_object_fluidsim.h
new file mode 100644
index 00000000000..91c25d2ec1d
--- /dev/null
+++ b/source/blender/makesdna/DNA_object_fluidsim.h
@@ -0,0 +1,157 @@
+/**
+ *
+ * $Id:
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004-2005 by Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef DNA_OBJECT_FLUIDSIM_H
+#define DNA_OBJECT_FLUIDSIM_H
+
+#include "DNA_ID.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct Mesh;
+struct Ipo;
+struct MVert;
+
+typedef struct FluidsimSettings {
+ /* domain,fluid or obstacle */
+ short type;
+ /* display advanced options in fluid sim tab (on=1,off=0)*/
+ short show_advancedoptions;
+
+ /* domain object settings */
+ /* resolutions */
+ short resolutionxyz;
+ short previewresxyz;
+ /* size of the domain in real units (meters along largest resolution x,y,z extent) */
+ float realsize;
+ /* show original meshes, preview or final sim */
+ short guiDisplayMode;
+ short renderDisplayMode;
+
+ /* fluid properties */
+ float viscosityValue;
+ short viscosityMode;
+ short viscosityExponent;
+ /* gravity strength */
+ float gravx,gravy,gravz;
+ /* anim start end time */
+ float animStart, animEnd;
+ /* g star param (LBM compressibility) */
+ float gstar;
+ /* activate refinement? */
+ int maxRefine;
+
+ /* fluid object type settings */
+ /* gravity strength */
+ float iniVelx,iniVely,iniVelz;
+
+ /* store pointer to original mesh (for replacing the current one) */
+ struct Mesh *orgMesh;
+ /* pointer to the currently loaded fluidsim mesh */
+ struct Mesh *meshSurface;
+ /* a mesh to display the bounding box used for simulation */
+ struct Mesh *meshBB;
+
+ /* store output path, and file prefix for baked fluid surface */
+ /* strlens; 80= FILE_MAXFILE, 160= FILE_MAXDIR */
+ char surfdataPath[240];
+
+ /* store start coords of axis aligned bounding box together with size */
+ /* values are inited during derived mesh display */
+ float bbStart[3], bbSize[3];
+
+ /* animated params */
+ struct Ipo *ipo;
+
+ /* additional flags depending on the type, lower short contains flags
+ * to check validity, higher short additional flags */
+ short typeFlags;
+ /* switch off velocity genration, volume init type for fluid/obstacles (volume=1,shell=2,both=3) */
+ char domainNovecgen,volumeInitType;
+
+ /* boundary "stickiness" for part slip values */
+ float partSlipValue;
+
+ /* number of tracers to generate */
+ int generateTracers;
+ /* particle generation - on if >0, then determines amount (experimental...) */
+ float generateParticles;
+ /* smooth fluid surface? */
+ float surfaceSmoothing;
+ /* number of surface subdivisions*/
+ int surfaceSubdivs;
+ int unusedDNADummy;
+
+ /* particle display - size scaling, and alpha influence */
+ float particleInfSize, particleInfAlpha;
+ /* testing vars */
+ float farFieldSize;
+
+ /* save fluidsurface normals in mvert.no, and surface vertex velocities (if available) in mvert.co */
+ struct MVert *meshSurfNormals;
+
+} FluidsimSettings;
+
+/* ob->fluidsimSettings defines */
+#define OB_FLUIDSIM_ENABLE 1
+#define OB_FLUIDSIM_DOMAIN 2
+#define OB_FLUIDSIM_FLUID 4
+#define OB_FLUIDSIM_OBSTACLE 8
+#define OB_FLUIDSIM_INFLOW 16
+#define OB_FLUIDSIM_OUTFLOW 32
+#define OB_FLUIDSIM_PARTICLE 64
+
+#define OB_TYPEFLAG_START 0
+#define OB_FSGEO_THIN (1<<(OB_TYPEFLAG_START+1))
+#define OB_FSBND_NOSLIP (1<<(OB_TYPEFLAG_START+2))
+#define OB_FSBND_PARTSLIP (1<<(OB_TYPEFLAG_START+3))
+#define OB_FSBND_FREESLIP (1<<(OB_TYPEFLAG_START+4))
+#define OB_FSINFLOW_LOCALCOORD (1<<(OB_TYPEFLAG_START+5))
+
+// guiDisplayMode particle flags
+#define OB_FSDOM_GEOM 1
+#define OB_FSDOM_PREVIEW 2
+#define OB_FSDOM_FINAL 3
+#define OB_FSPART_BUBBLE (1<<1)
+#define OB_FSPART_DROP (1<<2)
+#define OB_FSPART_NEWPART (1<<3)
+#define OB_FSPART_FLOAT (1<<4)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff --git a/source/blender/makesdna/DNA_object_force.h b/source/blender/makesdna/DNA_object_force.h
new file mode 100644
index 00000000000..a821e209ef0
--- /dev/null
+++ b/source/blender/makesdna/DNA_object_force.h
@@ -0,0 +1,154 @@
+/**
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004-2005 by Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef DNA_OBJECT_FORCE_H
+#define DNA_OBJECT_FORCE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct PartDeflect {
+ short deflect; /* Deflection flag - does mesh deflect particles*/
+ short forcefield; /* Force field type, do the vertices attract / repel particles ? */
+ short flag; /* general settings flag */
+ short pad;
+
+ float pdef_damp; /* Damping factor for particle deflection */
+ float pdef_rdamp; /* Random element of damping for deflection */
+ float pdef_perm; /* Chance of particle passing through mesh */
+
+ float f_strength; /* The strength of the force (+ or - ) */
+ float f_power; /* The power law - real gravitation is 2 (square) */
+ float maxdist; /* if indicated, use this maximum */
+
+ float pdef_sbdamp; /* Damping factor for softbody deflection */
+ float pdef_sbift; /* inner face thickness for softbody deflection */
+ float pdef_sboft; /* outer face thickness for softbody deflection */
+} PartDeflect;
+
+
+typedef struct SBVertex {
+ float vec[4];
+} SBVertex;
+
+typedef struct SoftBody {
+ /* dynamic data */
+ int totpoint, totspring;
+ struct BodyPoint *bpoint; /* not saved in file */
+ struct BodySpring *bspring; /* not saved in file */
+ float ctime; /* last time calculated */
+
+ /* part of UI: */
+
+ /* general options */
+ float nodemass; /* softbody mass of *vertex* */
+ float grav; /* softbody amount of gravitaion to apply */
+ float mediafrict; /* friction to env */
+ float rklimit; /* error limit for ODE solver */
+ float physics_speed;/* user control over simulation speed */
+
+ /* goal */
+ float goalspring; /* softbody goal springs */
+ float goalfrict; /* softbody goal springs friction */
+ float mingoal; /* quick limits for goal */
+ float maxgoal;
+ float defgoal; /* default goal for vertices without vgroup */
+ short vertgroup; /* index starting at 1 */
+
+ short fuzzyness; /* */
+
+ /* springs */
+ float inspring; /* softbody inner springs */
+ float infrict; /* softbody inner springs friction */
+
+ /* baking */
+ int sfra, efra;
+ int interval;
+ short local, solverflags; /* local==1: use local coords for baking */
+
+ SBVertex **keys; /* array of size totpointkey */
+ int totpointkey, totkey; /* if totpointkey != totpoint or totkey!- (efra-sfra)/interval -> free keys */
+ float secondspring;
+
+ /* self collision*/
+ float colball; /* fixed collision ball size if > 0 */
+ float balldamp; /* cooling down collision response */
+ float ballstiff; /* pressure the ball is loaded with */
+ short sbc_mode;
+ short aeroedge,
+ minloops,
+ maxloops,
+ choke,
+ pad3,pad4,pad5
+ ;
+
+ struct SBScratch *scratch; /* scratch pad/cache on live time not saved in file */
+
+} SoftBody;
+
+/* pd->forcefield: Effector Fields types */
+#define PFIELD_FORCE 1
+#define PFIELD_VORTEX 2
+#define PFIELD_MAGNET 3
+#define PFIELD_WIND 4
+#define PFIELD_GUIDE 5
+
+/* pd->flag: various settings */
+#define PFIELD_USEMAX 1
+#define PDEFLE_DEFORM 2
+#define PFIELD_GUIDE_PATH_ADD 4
+
+/* ob->softflag */
+#define OB_SB_ENABLE 1
+#define OB_SB_GOAL 2
+#define OB_SB_EDGES 4
+#define OB_SB_QUADS 8
+#define OB_SB_POSTDEF 16
+#define OB_SB_REDO 32
+#define OB_SB_BAKESET 64
+#define OB_SB_BAKEDO 128
+#define OB_SB_RESET 256
+#define OB_SB_SELF 512
+#define OB_SB_FACECOLL 1024
+#define OB_SB_EDGECOLL 2048
+#define OB_SB_COLLFINAL 4096
+
+#define SBSO_MONITOR 1
+#define SBSO_OLDERR 2
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
new file mode 100644
index 00000000000..cb4aa42a847
--- /dev/null
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -0,0 +1,442 @@
+/**
+ * blenlib/DNA_object_types.h (mar-2001 nzc)
+ *
+ * Object is a sort of wrapper for general info.
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef DNA_OBJECT_TYPES_H
+#define DNA_OBJECT_TYPES_H
+
+#include "DNA_listBase.h"
+#include "DNA_ID.h"
+#include "DNA_scriptlink_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct bPose;
+struct Object;
+struct Ipo;
+struct BoundBox;
+struct Path;
+struct Material;
+struct bConstraintChannel;
+struct PartDeflect;
+struct SoftBody;
+struct FluidsimSettings;
+struct DerivedMesh;
+
+typedef struct bDeformGroup {
+ struct bDeformGroup *next, *prev;
+ char name[32];
+} bDeformGroup;
+
+typedef struct BoundBox {
+ float vec[8][3];
+ int flag, pad;
+} BoundBox;
+
+/* boundbox flag */
+#define OB_BB_DISABLED 1
+
+typedef struct Object {
+ ID id;
+
+ short type, partype;
+ int par1, par2, par3; /* can be vertexnrs */
+ char parsubstr[32]; /* String describing subobject info */
+ struct Object *parent, *track;
+ /* if ob->proxy (or proxy_group), this object is proxy for object ob->proxy */
+ /* proxy_from is set in target back to the proxy. */
+ struct Object *proxy, *proxy_group, *proxy_from;
+ struct Ipo *ipo;
+ struct Path *path;
+ struct BoundBox *bb;
+ struct bAction *action;
+ struct bPose *pose;
+ void *data;
+
+ ListBase constraintChannels;
+ ListBase effect;
+ ListBase disp;
+ ListBase defbase;
+ ListBase modifiers; /* list of ModifierData structures */
+
+ struct Material **mat;
+
+ /* rot en drot have to be together! (transform('r' en 's')) */
+ float loc[3], dloc[3], orig[3];
+ float size[3], dsize[3];
+ float rot[3], drot[3];
+ float quat[4], dquat[4];
+ float obmat[4][4];
+ float parentinv[4][4]; /* inverse result of parent, so that object doesn't 'stick' to parent */
+ float constinv[4][4]; /* inverse result of constraints. doesn't include effect of parent or object local transform */
+ float imat[4][4]; /* for during render, old game engine, temporally: ipokeys of transform */
+
+ unsigned int lay; /* copy of Base */
+
+ short flag; /* copy of Base */
+ short colbits; /* when zero, from obdata */
+
+ short transflag, ipoflag; /* transformation and ipo settings */
+ short trackflag, upflag;
+ short nlaflag, protectflag; /* nlaflag defines NLA override, protectflag is bits to lock transform */
+ short ipowin, scaflag; /* ipowin: blocktype last ipowindow */
+ short scavisflag, boundtype;
+
+ int dupon, dupoff, dupsta, dupend;
+
+ float sf, ctime;
+
+ /* during realtime */
+
+ /* note that inertia is only called inertia for historical reasons
+ * and is not changed to avoid DNA surgery. It actually reflects the
+ * Size value in the GameButtons (= radius) */
+
+ float mass, damping, inertia;
+ /* The form factor k is introduced to give the user more control
+ * and to fix incompatibility problems.
+ * For rotational symmetric objects, the inertia value can be
+ * expressed as: Theta = k * m * r^2
+ * where m = Mass, r = Radius
+ * For a Sphere, the form factor is by default = 0.4
+ */
+
+ float formfactor;
+ float rdamping, sizefac;
+
+ char dt, dtx;
+ char totcol; /* copy of mesh or curve or meta */
+ char actcol; /* currently selected material in the user interface */
+ char empty_drawtype, pad1[7];
+ float empty_drawsize;
+
+ ScriptLink scriptlink;
+ ListBase prop;
+ ListBase sensors;
+ ListBase controllers;
+ ListBase actuators;
+
+ /* now used to store cache particles,
+ * should be renamed see effect.c (Campbell) */
+ void *sumohandle;
+
+ float bbsize[3];
+ short index; /* custom index, for renderpasses */
+ unsigned short actdef; /* current deformation group */
+ float col[4]; /* object color, adjusted via IPO's only */
+ /**
+ * Settings for game objects
+ * bit 0: Object has dynamic behaviour
+ * bit 2: Object is evaluated by the gameengine
+ * bit 6: Use Fh settings in Materials
+ * bit 7: Use face normal to rotate Object
+ * bit 8: Friction is anisotropic
+ * bit 9: Object is a ghost
+ * bit 10: Do rigid body dynamics.
+ * bit 11: Use bounding object for physics
+ */
+ int gameflag;
+ /**
+ * More settings
+ * bit 15: Always ignore activity culling
+ */
+ int gameflag2;
+ short softflag; /* softboday settings */
+ short recalc; /* dependency flag */
+ float anisotropicFriction[3];
+
+ ListBase constraints;
+ ListBase nlastrips;
+ ListBase hooks;
+
+ struct PartDeflect *pd; /* particle deflector/attractor/collision data */
+ struct SoftBody *soft; /* if exists, saved in file */
+ struct Group *dup_group; /* object duplicator for group */
+
+ short fluidsimFlag; /* NT toggle fluidsim participation on/off */
+
+ short restrictflag; /* for restricting view, select, render etc. accessible in outliner */
+
+ short shapenr, shapeflag; /* current shape key for menu or pinned, flag for pinning */
+ float smoothresh; /* smoothresh is phong interpolation ray_shadow correction in render */
+ short recalco, pad4; /* recalco for temp storage of ob->recalc, bad design warning */
+
+ struct FluidsimSettings *fluidsimSettings; /* if fluidsim enabled, store additional settings */
+
+ struct DerivedMesh *derivedDeform, *derivedFinal;
+ int lastDataMask; /* the custom data layer mask that was last used to calculate derivedDeform and derivedFinal */
+ int pad;
+
+/*#ifdef WITH_VERSE*/
+ void *vnode; /* pointer at object VerseNode */
+/*#endif*/
+} Object;
+
+/* Warning, this is not used anymore because hooks are now modifiers */
+typedef struct ObHook {
+ struct ObHook *next, *prev;
+
+ struct Object *parent;
+ float parentinv[4][4]; /* matrix making current transform unmodified */
+ float mat[4][4]; /* temp matrix while hooking */
+ float cent[3]; /* visualization of hook */
+ float falloff; /* if not zero, falloff is distance where influence zero */
+
+ char name[32];
+
+ int *indexar;
+ int totindex, curindex; /* curindex is cache for fast lookup */
+ short type, active; /* active is only first hook, for button menu */
+ float force;
+} ObHook;
+
+
+/* this work object is defined in object.c */
+extern Object workob;
+
+
+/* **************** OBJECT ********************* */
+
+/* used many places... should be specialized */
+#define SELECT 1
+
+/* type */
+#define OB_EMPTY 0
+#define OB_MESH 1
+#define OB_CURVE 2
+#define OB_SURF 3
+#define OB_FONT 4
+#define OB_MBALL 5
+
+#define OB_LAMP 10
+#define OB_CAMERA 11
+
+#define OB_WAVE 21
+#define OB_LATTICE 22
+
+/* 23 and 24 are for life and sector (old file compat.) */
+#define OB_ARMATURE 25
+
+/* partype: first 4 bits: type */
+#define PARTYPE 15
+#define PAROBJECT 0
+#define PARCURVE 1
+#define PARKEY 2
+
+#define PARSKEL 4
+#define PARVERT1 5
+#define PARVERT3 6
+#define PARBONE 7
+#define PARSLOW 16
+
+/* (short) transflag */
+#define OB_OFFS_LOCAL 1
+#define OB_QUAT 2
+#define OB_NEG_SCALE 4
+#define OB_DUPLI (8+16+256+512)
+#define OB_DUPLIFRAMES 8
+#define OB_DUPLIVERTS 16
+#define OB_DUPLIROT 32
+#define OB_DUPLINOSPEED 64
+#define OB_POWERTRACK 128
+#define OB_DUPLIGROUP 256
+#define OB_DUPLIFACES 512
+#define OB_DUPLIFACES_SCALE 1024
+
+/* (short) ipoflag */
+#define OB_DRAWKEY 1
+#define OB_DRAWKEYSEL 2
+#define OB_OFFS_OB 4
+#define OB_OFFS_MAT 8
+#define OB_OFFS_VKEY 16
+#define OB_OFFS_PATH 32
+#define OB_OFFS_PARENT 64
+#define OB_OFFS_PARTICLE 128
+ /* get ipo from from action or not? */
+#define OB_ACTION_OB 256
+#define OB_ACTION_KEY 512
+ /* for stride edit */
+#define OB_DISABLE_PATH 1024
+
+/* (short) trackflag / upflag */
+#define OB_POSX 0
+#define OB_POSY 1
+#define OB_POSZ 2
+#define OB_NEGX 3
+#define OB_NEGY 4
+#define OB_NEGZ 5
+
+/* gameflag in game.h */
+
+/* dt: no flags */
+#define OB_BOUNDBOX 1
+#define OB_WIRE 2
+#define OB_SOLID 3
+#define OB_SHADED 4
+#define OB_TEXTURE 5
+
+/* this condition has been made more complex since editmode can draw textures */
+#define CHECK_OB_DRAWTEXTURE(vd, dt) ((vd->drawtype==OB_TEXTURE && dt>OB_SOLID) || (vd->drawtype==OB_SOLID && vd->flag2 & V3D_SOLID_TEX))
+
+/* dtx: flags, char! */
+#define OB_AXIS 2
+#define OB_TEXSPACE 4
+#define OB_DRAWNAME 8
+#define OB_DRAWIMAGE 16
+ /* for solid+wire display */
+#define OB_DRAWWIRE 32
+ /* for overdraw */
+#define OB_DRAWXRAY 64
+ /* enable transparent draw */
+#define OB_DRAWTRANSP 128
+
+/* empty_drawtype: no flags */
+#define OB_ARROWS 1
+#define OB_PLAINAXES 2
+#define OB_CIRCLE 3
+#define OB_SINGLE_ARROW 4
+#define OB_CUBE 5
+
+/* boundtype */
+#define OB_BOUND_BOX 0
+#define OB_BOUND_SPHERE 1
+#define OB_BOUND_CYLINDER 2
+#define OB_BOUND_CONE 3
+#define OB_BOUND_POLYH 4
+#define OB_BOUND_POLYT 5
+#define OB_BOUND_DYN_MESH 6
+
+
+/* **************** BASE ********************* */
+
+/* also needed for base!!!!! or rather, thy interfere....*/
+/* base->flag and ob->flag */
+#define BA_WAS_SEL 2
+#define BA_HAS_RECALC_OB 4
+#define BA_HAS_RECALC_DATA 8
+
+#define BA_DO_IPO 32
+
+#define BA_FROMSET 128
+
+/* an initial attempt as making selection more specific! */
+#define BA_DESELECT 0
+#define BA_SELECT 1
+
+
+#define OB_FROMDUPLI 512
+#define OB_DONE 1024
+#define OB_RADIO 2048
+#define OB_FROMGROUP 4096
+#define OB_POSEMODE 8192
+
+/* ob->recalc (flag bits!) */
+#define OB_RECALC_OB 1
+#define OB_RECALC_DATA 2
+ /* time flag is set when time changes need recalc, so baked systems can ignore it */
+#define OB_RECALC_TIME 4
+#define OB_RECALC 7
+
+/* ob->gameflag */
+#define OB_DYNAMIC 1
+#define OB_CHILD 2
+#define OB_ACTOR 4
+#define OB_INERTIA_LOCK_X 8
+#define OB_INERTIA_LOCK_Y 16
+#define OB_INERTIA_LOCK_Z 32
+#define OB_DO_FH 64
+#define OB_ROT_FH 128
+#define OB_ANISOTROPIC_FRICTION 256
+#define OB_GHOST 512
+#define OB_RIGID_BODY 1024
+#define OB_BOUNDS 2048
+
+#define OB_COLLISION_RESPONSE 4096
+#define OB_SECTOR 8192
+#define OB_PROP 16384
+#define OB_MAINACTOR 32768
+
+/* ob->gameflag2 */
+#define OB_NEVER_DO_ACTIVITY_CULLING 1
+
+#define OB_LIFE (OB_PROP|OB_DYNAMIC|OB_ACTOR|OB_MAINACTOR|OB_CHILD)
+
+/* ob->scavisflag */
+#define OB_VIS_SENS 1
+#define OB_VIS_CONT 2
+#define OB_VIS_ACT 4
+
+/* ob->scaflag */
+#define OB_SHOWSENS 64
+#define OB_SHOWACT 128
+#define OB_ADDSENS 256
+#define OB_ADDCONT 512
+#define OB_ADDACT 1024
+#define OB_SHOWCONT 2048
+
+/* ob->restrictflag */
+#define OB_RESTRICT_VIEW 1
+#define OB_RESTRICT_SELECT 2
+#define OB_RESTRICT_RENDER 4
+
+/* ob->shapeflag */
+#define OB_SHAPE_LOCK 1
+#define OB_SHAPE_TEMPLOCK 2
+
+/* ob->nlaflag */
+#define OB_NLA_OVERRIDE 1
+#define OB_NLA_COLLAPSED 2
+
+/* ob->protectflag */
+#define OB_LOCK_LOCX 1
+#define OB_LOCK_LOCY 2
+#define OB_LOCK_LOCZ 4
+#define OB_LOCK_LOC 7
+#define OB_LOCK_ROTX 8
+#define OB_LOCK_ROTY 16
+#define OB_LOCK_ROTZ 32
+#define OB_LOCK_SCALEX 64
+#define OB_LOCK_SCALEY 128
+#define OB_LOCK_SCALEZ 256
+
+/* ob->softflag in DNA_object_force.h */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/source/blender/makesdna/DNA_oops_types.h b/source/blender/makesdna/DNA_oops_types.h
new file mode 100644
index 00000000000..aaee18e3249
--- /dev/null
+++ b/source/blender/makesdna/DNA_oops_types.h
@@ -0,0 +1,86 @@
+/**
+ * blenlib/DNA_oops_types.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef DNA_OOPS_TYPES_H
+#define DNA_OOPS_TYPES_H
+
+#define OOPSX 5.0
+#define OOPSY 1.8
+
+#include "DNA_listBase.h"
+
+struct ID;
+
+typedef struct TreeStoreElem {
+ short type, nr, flag, used;
+ struct ID *id;
+} TreeStoreElem;
+
+typedef struct TreeStore {
+ int totelem, usedelem;
+ TreeStoreElem *data;
+} TreeStore;
+
+typedef struct Oops {
+ struct Oops *next, *prev;
+ short type, flag, dt, hide;
+ float x, y; /* left - bottom */
+ float dx, dy; /* shuffle */
+ struct ID *id;
+ ListBase link;
+} Oops;
+
+#
+#
+typedef struct OopsLink {
+ struct OopsLink *next, *prev;
+ short type, flag;
+ struct ID **idfrom;
+ Oops *to, *from; /* from is for temp */
+ float xof, yof;
+ char name[12];
+} OopsLink;
+
+/* oops->flag (1==SELECT) */
+#define OOPS_DOSELECT 2
+#define OOPS_REFER 4
+
+/* TreeStoreElem->flag */
+#define TSE_CLOSED 1
+#define TSE_SELECTED 2
+#define TSE_TEXTBUT 4
+
+/* TreeStoreElem types in BIF_outliner.h */
+
+#endif
+
diff --git a/source/blender/makesdna/DNA_packedFile_types.h b/source/blender/makesdna/DNA_packedFile_types.h
new file mode 100644
index 00000000000..a0fdd892106
--- /dev/null
+++ b/source/blender/makesdna/DNA_packedFile_types.h
@@ -0,0 +1,65 @@
+/* DNA_packedFile_types.h
+ *
+ * 12-oct-2000 nzc
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef DNA_PACKEDFILE_TYPES_H
+#define DNA_PACKEDFILE_TYPES_H
+
+typedef struct PackedFile {
+ int size;
+ int seek;
+ int flags;
+ int pad;
+ void * data;
+} PackedFile;
+
+enum PF_FileStatus
+{
+ PF_EQUAL = 0,
+ PF_DIFFERS,
+ PF_NOFILE,
+
+ PF_WRITE_ORIGINAL,
+ PF_WRITE_LOCAL,
+ PF_USE_LOCAL,
+ PF_USE_ORIGINAL,
+ PF_KEEP,
+ PF_REMOVE,
+ PF_NOOP,
+
+ PF_ASK
+};
+
+#endif /* PACKEDFILE_TYPES_H */
+
diff --git a/source/blender/makesdna/DNA_property_types.h b/source/blender/makesdna/DNA_property_types.h
new file mode 100644
index 00000000000..e46d557cc8b
--- /dev/null
+++ b/source/blender/makesdna/DNA_property_types.h
@@ -0,0 +1,68 @@
+/**
+ * blenlib/DNA_property_types.h (mar-2001 nzc)
+ *
+ * Renderrecipe and scene decription. The fact that there is a
+ * hierarchy here is a bit strange, and not desirable.
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef DNA_PROPERTY_TYPES_H
+#define DNA_PROPERTY_TYPES_H
+
+/* ********************* PROPERTY ************************ */
+
+typedef struct bProperty {
+ struct bProperty *next, *prev;
+ char name[32];
+ short type, otype; /* otype is for buttons, when a property type changes */
+ int data; /* data should be 4 bytes to store int,float stuff */
+ int old; /* old is for simul */
+ short flag, pad;
+ void *poin;
+ void *oldpoin; /* oldpoin is for simul */
+
+} bProperty;
+
+/* property->type */
+#define PROP_BOOL 0
+#define PROP_INT 1
+#define PROP_FLOAT 2
+#define PROP_STRING 3
+#define PROP_VECTOR 4
+#define PROP_TIME 5
+
+/* property->flag */
+#define PROP_DEBUG 1
+
+#define MAX_PROPSTRING 128
+
+#endif
+
diff --git a/source/blender/makesdna/DNA_radio_types.h b/source/blender/makesdna/DNA_radio_types.h
new file mode 100644
index 00000000000..adaa4e6e159
--- /dev/null
+++ b/source/blender/makesdna/DNA_radio_types.h
@@ -0,0 +1,53 @@
+/**
+ * radio_types.h dec 2000 Nzc
+ *
+ * All type defs for the Blender core.
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ *
+ */
+
+#ifndef DNA_RADIO_TYPES_H
+#define DNA_RADIO_TYPES_H
+
+typedef struct Radio {
+ short hemires, maxiter;
+ short drawtype, flag; /* bit 0 and 1: show limits */
+ short subshootp, subshoote, nodelim, maxsublamp;
+ short pama, pami, elma, elmi; /* patch and elem limits */
+ int maxnode;
+ float convergence;
+ float radfac, gamma; /* for display */
+
+} Radio;
+
+#endif
+
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
new file mode 100644
index 00000000000..031a88c517a
--- /dev/null
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -0,0 +1,672 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef DNA_SCENE_TYPES_H
+#define DNA_SCENE_TYPES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "DNA_vec_types.h"
+#include "DNA_listBase.h"
+#include "DNA_scriptlink_types.h"
+#include "DNA_ID.h"
+#include "DNA_scriptlink_types.h"
+
+struct Radio;
+struct Object;
+struct World;
+struct Scene;
+struct Image;
+struct Group;
+struct bNodeTree;
+
+typedef struct Base {
+ struct Base *next, *prev;
+ unsigned int lay, selcol;
+ int flag;
+ short sx, sy;
+ struct Object *object;
+} Base;
+
+typedef struct AviCodecData {
+ void *lpFormat; /* save format */
+ void *lpParms; /* compressor options */
+ unsigned int cbFormat; /* size of lpFormat buffer */
+ unsigned int cbParms; /* size of lpParms buffer */
+
+ unsigned int fccType; /* stream type, for consistency */
+ unsigned int fccHandler; /* compressor */
+ unsigned int dwKeyFrameEvery; /* keyframe rate */
+ unsigned int dwQuality; /* compress quality 0-10,000 */
+ unsigned int dwBytesPerSecond; /* bytes per second */
+ unsigned int dwFlags; /* flags... see below */
+ unsigned int dwInterleaveEvery; /* for non-video streams only */
+ unsigned int pad;
+
+ char avicodecname[128];
+} AviCodecData;
+
+typedef struct QuicktimeCodecData {
+
+ void *cdParms; /* codec/compressor options */
+ void *pad; /* padding */
+
+ unsigned int cdSize; /* size of cdParms buffer */
+ unsigned int pad2; /* padding */
+
+ char qtcodecname[128];
+} QuicktimeCodecData;
+
+typedef struct FFMpegCodecData {
+ int type;
+ int codec;
+ int audio_codec;
+ int video_bitrate;
+ int audio_bitrate;
+ int gop_size;
+ int flags;
+
+ int rc_min_rate;
+ int rc_max_rate;
+ int rc_buffer_size;
+ int mux_packet_size;
+ int mux_rate;
+} FFMpegCodecData;
+
+
+typedef struct AudioData {
+ int mixrate;
+ float main; /* Main mix in dB */
+ short flag;
+ short pad[3];
+} AudioData;
+
+typedef struct SceneRenderLayer {
+ struct SceneRenderLayer *next, *prev;
+
+ char name[32];
+
+ struct Material *mat_override;
+ struct Group *light_override;
+
+ unsigned int lay; /* scene->lay itself has priority over this */
+ int layflag;
+ int passflag; /* pass_xor has to be after passflag */
+ int pass_xor;
+} SceneRenderLayer;
+
+/* srl->layflag */
+#define SCE_LAY_SOLID 1
+#define SCE_LAY_ZTRA 2
+#define SCE_LAY_HALO 4
+#define SCE_LAY_EDGE 8
+#define SCE_LAY_SKY 16
+#define SCE_LAY_STRAND 32
+ /* flags between 32 and 0x8000 are set to 1 already, for future options */
+
+#define SCE_LAY_ALL_Z 0x8000
+#define SCE_LAY_XOR 0x10000
+#define SCE_LAY_DISABLE 0x20000
+
+/* srl->passflag */
+#define SCE_PASS_COMBINED 1
+#define SCE_PASS_Z 2
+#define SCE_PASS_RGBA 4
+#define SCE_PASS_DIFFUSE 8
+#define SCE_PASS_SPEC 16
+#define SCE_PASS_SHADOW 32
+#define SCE_PASS_AO 64
+#define SCE_PASS_REFLECT 128
+#define SCE_PASS_NORMAL 256
+#define SCE_PASS_VECTOR 512
+#define SCE_PASS_REFRACT 1024
+#define SCE_PASS_INDEXOB 2048
+#define SCE_PASS_UV 4096
+#define SCE_PASS_RADIO 8192
+/* note, srl->passflag is treestore element 'nr' in outliner, short still... */
+
+
+typedef struct RenderData {
+
+ struct AviCodecData *avicodecdata;
+ struct QuicktimeCodecData *qtcodecdata;
+ struct FFMpegCodecData ffcodecdata;
+
+ int cfra, sfra, efra; /* frames as in 'images' */
+ int psfra, pefra; /* start+end frames of preview range */
+
+ int images, framapto;
+ short flag, threads;
+
+ float ctime; /* use for calcutions */
+ float framelen, blurfac;
+
+ /** For UR edge rendering: give the edges this color */
+ float edgeR, edgeG, edgeB;
+
+ short fullscreen, xplay, yplay, freqplay; /* standalone player */
+ short depth, attrib, rt1, rt2; /* standalone player */
+
+ short stereomode; /* standalone player stereo settings */
+
+ short dimensionspreset; /* for the dimensions presets menu */
+
+ short filtertype; /* filter is box, tent, gauss, mitch, etc */
+
+ short size, maximsize; /* size in %, max in Kb */
+ /* from buttons: */
+ /**
+ * The desired number of pixels in the x direction
+ */
+ short xsch;
+ /**
+ * The desired number of pixels in the y direction
+ */
+ short ysch;
+ /**
+ * Adjustment factors for the aspect ratio in the x direction
+ */
+ short xasp;
+ /**
+ * Adjustment factors for the aspect ratio in the x direction
+ */
+ short yasp;
+ /**
+ * The number of part to use in the x direction
+ */
+ short xparts;
+ /**
+ * The number of part to use in the y direction
+ */
+ short yparts;
+
+ short winpos, planes, imtype, subimtype;
+
+ /** Mode bits: */
+ /* 0: Enable backbuffering for images */
+ short bufflag;
+ short quality;
+
+ /**
+ * Flags for render settings. Use bit-masking to access the settings.
+ */
+ short scemode;
+
+ /**
+ * Flags for render settings. Use bit-masking to access the settings.
+ */
+ int mode;
+
+ /* render engine, octree resolution */
+ short renderer, ocres, rpad[2];
+
+ /**
+ * What to do with the sky/background. Picks sky/premul/key
+ * blending for the background
+ */
+ short alphamode;
+
+ /**
+ * The number of samples to use per pixel.
+ */
+ short osa;
+
+ short frs_sec, edgeint;
+
+ /* safety, border and display rect */
+ rctf safety, border;
+ rcti disprect;
+
+ /* information on different layers to be rendered */
+ ListBase layers;
+ short actlay, pad;
+
+ float frs_sec_base;
+
+ /**
+ * Value used to define filter size for all filter options */
+ float gauss;
+
+ /** post-production settings. Depricated, but here for upwards compat (initialized to 1) */
+ float postmul, postgamma, posthue, postsat;
+
+ /* Dither noise intensity */
+ float dither_intensity;
+
+ /* Bake Render options */
+ short bake_osa, bake_filter, bake_mode, bake_flag;
+
+ /* yafray: global panel params. TODO: move elsewhere */
+ short GIquality, GIcache, GImethod, GIphotons, GIdirect;
+ short YF_AA, YFexportxml, YF_nobump, YF_clamprgb, yfpad1;
+ int GIdepth, GIcausdepth, GIpixelspersample;
+ int GIphotoncount, GImixphotons;
+ float GIphotonradius;
+ int YF_numprocs, YF_raydepth, YF_AApasses, YF_AAsamples;
+ float GIshadowquality, GIrefinement, GIpower, GIindirpower;
+ float YF_gamma, YF_exposure, YF_raybias, YF_AApixelsize, YF_AAthreshold;
+
+ /* paths to backbufffer, output, ftype */
+ char backbuf[160], pic[160], ftype[160];
+
+ /* stamps flags. */
+ int stamp;
+ short stamp_font_id, pad3; /* select one of blenders bitmap fonts */
+
+ /* stamp info user data. */
+ char stamp_udata[160];
+
+ /* foreground/background color. */
+ float fg_stamp[4];
+ float bg_stamp[4];
+} RenderData;
+
+
+typedef struct GameFraming {
+ float col[3];
+ char type, pad1, pad2, pad3;
+} GameFraming;
+
+#define SCE_GAMEFRAMING_BARS 0
+#define SCE_GAMEFRAMING_EXTEND 1
+#define SCE_GAMEFRAMING_SCALE 2
+
+typedef struct TimeMarker {
+ struct TimeMarker *next, *prev;
+ int frame;
+ char name[64];
+ unsigned int flag;
+} TimeMarker;
+
+struct ImagePaintSettings {
+ struct Brush *brush;
+ short flag, tool;
+ int pad3;
+};
+
+typedef struct ToolSettings {
+ /* Subdivide Settings */
+ short cornertype;
+ short editbutflag;
+ /*Triangle to Quad conversion threshold*/
+ float jointrilimit;
+ /* Extrude Tools */
+ float degr;
+ short step;
+ short turn;
+
+ float extr_offs;
+ float doublimit;
+
+ /* Primitive Settings */
+ /* UV Sphere */
+ short segments;
+ short rings;
+
+ /* Cylinder - Tube - Circle */
+ short vertices;
+
+ /* UV Calculation */
+ short unwrapper;
+ float uvcalc_radius;
+ float uvcalc_cubesize;
+ short uvcalc_mapdir;
+ short uvcalc_mapalign;
+ short uvcalc_flag;
+
+ short pad2;
+
+ /* Image Paint (8 byte aligned please!) */
+ struct ImagePaintSettings imapaint;
+
+ /* Select Group Threshold */
+ float select_thresh;
+
+ /* IPO-Editor */
+ float clean_thresh;
+
+ /* Retopo */
+ char retopo_mode;
+ char retopo_paint_tool;
+ char line_div, ellipse_div, retopo_hotspot;
+
+ /* Multires */
+ char multires_subdiv_type;
+
+ char pad4[2];
+} ToolSettings;
+
+/* Used by all brushes to store their properties, which can be directly set
+ by the interface code. Note that not all properties are actually used by
+ all the brushes. */
+typedef struct BrushData
+{
+ short size;
+ char strength, dir; /* Not used for smooth brush */
+ char airbrush;
+ char view;
+ char pad[2];
+} BrushData;
+
+struct SculptSession;
+typedef struct SculptData
+{
+ /* Data stored only from entering sculptmode until exiting sculptmode */
+ struct SculptSession *session;
+
+ /* Pointers to all of sculptmodes's textures */
+ struct MTex *mtex[10];
+
+ /* Settings for each brush */
+ BrushData drawbrush, smoothbrush, pinchbrush, inflatebrush, grabbrush, layerbrush, flattenbrush;
+ short brush_type;
+
+ /* For the Brush Shape */
+ short texact, texnr;
+ short spacing;
+ char texrept;
+ char texfade;
+ char texsep;
+
+ char averaging;
+ char flags;
+
+ /* Control tablet input */
+ char tablet_size, tablet_strength;
+
+ /* Symmetry is separate from the other BrushData because the same
+ settings are always used for all brush types */
+ char symm;
+} SculptData;
+
+typedef struct Scene {
+ ID id;
+ struct Object *camera;
+ struct World *world;
+
+ struct Scene *set;
+ struct Image *ima;
+
+ ListBase base;
+ struct Base *basact;
+
+ float cursor[3];
+ float twcent[3]; /* center for transform widget */
+ float twmin[3], twmax[3]; /* boundbox of selection for transform widget */
+ unsigned int lay;
+
+ /* editmode stuff */
+ float editbutsize; /* size of normals */
+ short selectmode; /* for mesh only! */
+ short proportional, prop_mode;
+ short automerge, pad5, pad6, pad7;
+
+ short use_nodes;
+
+ struct bNodeTree *nodetree;
+
+ void *ed; /* sequence editor data is allocated here */
+ struct Radio *radio;
+
+ struct GameFraming framing;
+
+ struct ToolSettings *toolsettings;
+
+ /* migrate or replace? depends on some internal things... */
+ /* no, is on the right place (ton) */
+ struct RenderData r;
+ struct AudioData audio;
+
+ ScriptLink scriptlink;
+
+ ListBase markers;
+
+ short jumpframe, pad1;
+ short snap_flag, snap_target;
+
+ /* none of the dependancy graph vars is mean to be saved */
+ struct DagForest *theDag;
+ short dagisvalid, dagflags;
+ short pad4, recalc; /* recalc = counterpart of ob->recalc */
+
+ /* Sculptmode data */
+ struct SculptData sculptdata;
+} Scene;
+
+
+/* **************** RENDERDATA ********************* */
+
+/* bufflag */
+#define R_BACKBUF 1
+#define R_BACKBUFANIM 2
+#define R_FRONTBUF 4
+#define R_FRONTBUFANIM 8
+
+/* mode (int now) */
+#define R_OSA 0x0001
+#define R_SHADOW 0x0002
+#define R_GAMMA 0x0004
+#define R_ORTHO 0x0008
+#define R_ENVMAP 0x0010
+#define R_EDGE 0x0020
+#define R_FIELDS 0x0040
+#define R_FIELDSTILL 0x0080
+#define R_RADIO 0x0100
+#define R_BORDER 0x0200
+#define R_PANORAMA 0x0400
+#define R_CROP 0x0800
+#define R_COSMO 0x1000
+#define R_ODDFIELD 0x2000
+#define R_MBLUR 0x4000
+ /* unified was here */
+#define R_RAYTRACE 0x10000
+ /* R_GAUSS is obsolete, but used to retrieve setting from old files */
+#define R_GAUSS 0x20000
+ /* fbuf obsolete... */
+#define R_FBUF 0x40000
+ /* threads obsolete... is there for old files */
+#define R_THREADS 0x80000
+#define R_SPEED 0x100000
+#define R_SSS 0x200000
+
+/* filtertype */
+#define R_FILTER_BOX 0
+#define R_FILTER_TENT 1
+#define R_FILTER_QUAD 2
+#define R_FILTER_CUBIC 3
+#define R_FILTER_CATROM 4
+#define R_FILTER_GAUSS 5
+#define R_FILTER_MITCH 6
+#define R_FILTER_FAST_GAUSS 7 /* note, this is only used for nodes at the moment */
+
+/* yafray: renderer flag (not only exclusive to yafray) */
+#define R_INTERN 0
+#define R_YAFRAY 1
+
+/* scemode */
+#define R_DOSEQ 0x0001
+#define R_BG_RENDER 0x0002
+ /* passepartout is camera option now, keep this for backward compatibility */
+#define R_PASSEPARTOUT 0x0004
+#define R_PREVIEWBUTS 0x0008
+#define R_EXTENSION 0x0010
+#define R_NODE_PREVIEW 0x0020
+#define R_DOCOMP 0x0040
+#define R_COMP_CROP 0x0080
+#define R_FREE_IMAGE 0x0100
+#define R_SINGLE_LAYER 0x0200
+#define R_EXR_TILE_FILE 0x0400
+#define R_COMP_FREE 0x0800
+#define R_NO_IMAGE_LOAD 0x1000
+#define R_NO_TEX 0x2000
+#define R_STAMP_INFO 0x4000
+
+/* r->stamp */
+#define R_STAMP_TIME 0x0001
+#define R_STAMP_FRAME 0x0002
+#define R_STAMP_DATE 0x0004
+#define R_STAMP_CAMERA 0x0008
+#define R_STAMP_SCENE 0x0010
+#define R_STAMP_NOTE 0x0020
+#define R_STAMP_DRAW 0x0040 /* draw in the image */
+#define R_STAMP_MARKER 0x0080
+
+/* alphamode */
+#define R_ADDSKY 0
+#define R_ALPHAPREMUL 1
+#define R_ALPHAKEY 2
+
+/* planes */
+#define R_PLANES24 24
+#define R_PLANES32 32
+#define R_PLANESBW 8
+
+/* imtype */
+#define R_TARGA 0
+#define R_IRIS 1
+#define R_HAMX 2
+#define R_FTYPE 3
+#define R_JPEG90 4
+#define R_MOVIE 5
+#define R_IRIZ 7
+#define R_RAWTGA 14
+#define R_AVIRAW 15
+#define R_AVIJPEG 16
+#define R_PNG 17
+#define R_AVICODEC 18
+#define R_QUICKTIME 19
+#define R_BMP 20
+#define R_RADHDR 21
+#define R_TIFF 22
+#define R_OPENEXR 23
+#define R_FFMPEG 24
+#define R_FRAMESERVER 25
+#define R_CINEON 26
+#define R_DPX 27
+#define R_MULTILAYER 28
+#define R_DDS 29
+
+/* subimtype, flag options for imtype */
+#define R_OPENEXR_HALF 1
+#define R_OPENEXR_ZBUF 2
+#define R_PREVIEW_JPG 4
+
+/* bake_mode: same as RE_BAKE_xxx defines */
+/* bake_flag: */
+#define R_BAKE_CLEAR 1
+#define R_BAKE_OSA 2
+
+/* **************** SCENE ********************* */
+#define RAD_PHASE_PATCHES 1
+#define RAD_PHASE_FACES 2
+
+/* base->flag is in DNA_object_types.h */
+
+/* scene->snap_flag */
+#define SCE_SNAP 1
+/* scene->snap_target */
+#define SCE_SNAP_TARGET_CLOSEST 0
+#define SCE_SNAP_TARGET_CENTER 1
+#define SCE_SNAP_TARGET_MEDIAN 2
+
+/* sce->selectmode */
+#define SCE_SELECT_VERTEX 1 /* for mesh */
+#define SCE_SELECT_EDGE 2
+#define SCE_SELECT_FACE 4
+
+/* sce->recalc (now in use by previewrender) */
+#define SCE_PRV_CHANGED 1
+
+/* sce->prop_mode (proportional falloff) */
+#define PROP_SMOOTH 0
+#define PROP_SPHERE 1
+#define PROP_ROOT 2
+#define PROP_SHARP 3
+#define PROP_LIN 4
+#define PROP_CONST 5
+#define PROP_RANDOM 6
+
+ /* return flag next_object function */
+#define F_START 0
+#define F_SCENE 1
+#define F_SET 2
+#define F_DUPLI 3
+
+/* audio->flag */
+#define AUDIO_MUTE 1
+#define AUDIO_SYNC 2
+#define AUDIO_SCRUB 4
+
+#define FFMPEG_MULTIPLEX_AUDIO 1
+#define FFMPEG_AUTOSPLIT_OUTPUT 2
+
+/* SculptData.flags */
+#define SCULPT_INPUT_SMOOTH 1
+#define SCULPT_DRAW_FAST 2
+#define SCULPT_DRAW_BRUSH 4
+/* SculptData.brushtype */
+#define DRAW_BRUSH 1
+#define SMOOTH_BRUSH 2
+#define PINCH_BRUSH 3
+#define INFLATE_BRUSH 4
+#define GRAB_BRUSH 5
+#define LAYER_BRUSH 6
+#define FLATTEN_BRUSH 7
+/* SculptData.texrept */
+#define SCULPTREPT_DRAG 1
+#define SCULPTREPT_TILE 2
+#define SCULPTREPT_3D 3
+
+#define SYMM_X 1
+#define SYMM_Y 2
+#define SYMM_Z 4
+
+/* toolsettings->imagepaint_flag */
+#define IMAGEPAINT_DRAWING 1
+#define IMAGEPAINT_DRAW_TOOL 2
+#define IMAGEPAINT_DRAW_TOOL_DRAWING 4
+
+/* toolsettings->retopo_mode */
+#define RETOPO 1
+#define RETOPO_PAINT 2
+
+/* toolsettings->retopo_paint_tool */
+#define RETOPO_PEN 1
+#define RETOPO_LINE 2
+#define RETOPO_ELLIPSE 4
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h
new file mode 100644
index 00000000000..65374983af5
--- /dev/null
+++ b/source/blender/makesdna/DNA_screen_types.h
@@ -0,0 +1,171 @@
+/**
+ * blenlib/DNA_screen_types.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef DNA_SCREEN_TYPES_H
+#define DNA_SCREEN_TYPES_H
+
+#include "DNA_listBase.h"
+#include "DNA_vec_types.h"
+
+#include "DNA_ID.h"
+#include "DNA_scriptlink_types.h"
+
+struct Scene;
+
+typedef struct bScreen {
+ ID id;
+ ListBase vertbase, edgebase, areabase;
+ struct Scene *scene;
+ short startx, endx, starty, endy; /* framebuffer coords */
+ short sizex, sizey;
+ short scenenr, screennr; /* only for pupmenu */
+ short full, pad;
+ short mainwin, winakt;
+ short handler[8]; /* similar to space handler now */
+} bScreen;
+
+typedef struct ScrVert {
+ struct ScrVert *next, *prev, *newv;
+ vec2s vec;
+ int flag;
+} ScrVert;
+
+typedef struct ScrEdge {
+ struct ScrEdge *next, *prev;
+ ScrVert *v1, *v2;
+ short border; /* 1 when at edge of screen */
+ short flag;
+ int pad;
+} ScrEdge;
+
+#ifndef DNA_USHORT_FIX
+#define DNA_USHORT_FIX
+/**
+ * @deprecated This typedef serves to avoid badly typed functions when
+ * @deprecated compiling while delivering a proper dna.c. Do not use
+ * @deprecated it in any case.
+ */
+typedef unsigned short dna_ushort_fix;
+#endif
+
+
+
+typedef struct Panel { /* the part from uiBlock that needs saved in file */
+ struct Panel *next, *prev;
+ char panelname[64], tabname[64]; /* defined as UI_MAX_NAME_STR */
+ char drawname[64]; /* panelname is identifier for restoring location */
+ short ofsx, ofsy, sizex, sizey;
+ short flag, active; /* active= used currently by a uiBlock */
+ short control;
+ short snap;
+ short old_ofsx, old_ofsy; /* for stow */
+ int sortcounter; /* when sorting panels, it uses this to put new ones in right place */
+ struct Panel *paneltab; /* this panel is tabbed in *paneltab */
+} Panel;
+
+typedef struct ScrArea {
+ struct ScrArea *next, *prev;
+ ScrVert *v1, *v2, *v3, *v4;
+ bScreen *full; /* if area==full, this is the parent */
+ float winmat[4][4];
+ rcti totrct, headrct, winrct;
+
+ short headwin, win;
+ short headertype; /* 0=no header, 1= down, 2= up */
+ char spacetype, butspacetype; /* SPACE_... */
+ short winx, winy; /* size */
+ char head_swap, head_equal;
+ char win_swap, win_equal;
+
+ short headbutlen, headbutofs;
+ short cursor, flag;
+
+ ScriptLink scriptlink;
+
+ ListBase spacedata;
+ ListBase uiblocks;
+ ListBase panels;
+} ScrArea;
+
+#define MAXWIN 128
+
+/* area->flag */
+#define HEADER_NO_PULLDOWN 1
+
+/* If you change EDGEWIDTH, also do the global arrat edcol[] */
+#define EDGEWIDTH 1
+#define EDGEWIDTH2 0
+#define AREAGRID 4
+#define AREAMINX 32
+#define HEADERY 26
+#define AREAMINY (HEADERY+EDGEWIDTH)
+
+#define HEADERDOWN 1
+#define HEADERTOP 2
+
+#define SCREENNORMAL 0
+#define SCREENFULL 1
+#define SCREENAUTOPLAY 2
+
+/* sa->win_swap */
+#define WIN_FRONT_OK 1
+#define WIN_BACK_OK 2
+#define WIN_EQUAL 3
+
+#define L_SCROLL 1 /* left scrollbar */
+#define R_SCROLL 2
+#define VERT_SCROLL 3
+#define T_SCROLL 4
+#define B_SCROLL 8
+#define HOR_SCROLL 12
+#define B_SCROLLO 16 /* special hack for outliner hscroll - prevent hanging */
+#define HOR_SCROLLO 20 /* in older versions of blender */
+
+/* Panel->snap - for snapping to screen edges */
+#define PNL_SNAP_NONE 0
+#define PNL_SNAP_TOP 1
+#define PNL_SNAP_RIGHT 2
+#define PNL_SNAP_BOTTOM 4
+#define PNL_SNAP_LEFT 8
+
+#define PNL_SNAP_DIST 9.0
+
+/* screen handlers */
+#define SCREEN_MAXHANDLER 8
+
+#define SCREEN_HANDLER_ANIM 1
+#define SCREEN_HANDLER_PYTHON 2
+#define SCREEN_HANDLER_VERSE 3
+
+#endif
+
diff --git a/source/blender/makesdna/DNA_scriptlink_types.h b/source/blender/makesdna/DNA_scriptlink_types.h
new file mode 100644
index 00000000000..8a08d3f12c1
--- /dev/null
+++ b/source/blender/makesdna/DNA_scriptlink_types.h
@@ -0,0 +1,77 @@
+/**
+ * blenlib/DNA_object_types.h (mar-2001 nzc)
+ *
+ * Scriptlink is hard-coded in object for some reason.
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef DNA_SCRIPTLINK_TYPES_H
+#define DNA_SCRIPTLINK_TYPES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct ID;
+
+typedef struct ScriptLink {
+ struct ID **scripts;
+ short *flag;
+
+ short actscript, totscript;
+ int pad;
+} ScriptLink;
+
+/* **************** SCRIPTLINKS ********************* */
+
+#define SCRIPT_FRAMECHANGED 1
+#define SCRIPT_ONLOAD 2
+#define SCRIPT_REDRAW 4
+#define SCRIPT_ONSAVE 8
+#define SCRIPT_RENDER 16
+/* POSTRENDER is not meant for the UI, it simply calls the
+ * RENDER script links for clean-up actions */
+#define SCRIPT_POSTRENDER 32
+
+/* **************** SPACE HANDLERS ********************* */
+/* these are special scriptlinks that can be assigned to
+ * a given space in a given ScrArea to:
+ * - (EVENT type) handle events sent to that space;
+ * - (DRAW type) draw on the space after its own drawing function finishes
+ */
+#define SPACEHANDLER_VIEW3D_EVENT 1
+#define SPACEHANDLER_VIEW3D_DRAW 2
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/source/blender/makesdna/DNA_sdna_types.h b/source/blender/makesdna/DNA_sdna_types.h
new file mode 100644
index 00000000000..8553a3868d1
--- /dev/null
+++ b/source/blender/makesdna/DNA_sdna_types.h
@@ -0,0 +1,83 @@
+/**
+ * blenlib/DNA_sdna.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef DNA_SDNA_H
+#define DNA_SDNA_H
+
+#
+#
+struct SDNA {
+ char *data;
+ int datalen, nr_names;
+ char **names;
+ int nr_types, pointerlen;
+ char **types;
+ short *typelens;
+ int nr_structs;
+ short **structs;
+
+ /* wrong place for this really, its a simple
+ * cache for findstruct_nr.
+ */
+ int lastfind;
+};
+
+#
+#
+typedef struct BHead {
+ int code, len;
+ void *old;
+ int SDNAnr, nr;
+} BHead;
+#
+#
+typedef struct BHead4 {
+ int code, len;
+ int old;
+ int SDNAnr, nr;
+} BHead4;
+#
+#
+typedef struct BHead8 {
+ int code, len;
+#if defined(WIN32) && !defined(FREE_WINDOWS)
+ /* This is a compiler type! */
+ __int64 old;
+#else
+ long long old;
+#endif
+ int SDNAnr, nr;
+} BHead8;
+
+#endif
+
diff --git a/source/blender/makesdna/DNA_sensor_types.h b/source/blender/makesdna/DNA_sensor_types.h
new file mode 100644
index 00000000000..7fcb400d66e
--- /dev/null
+++ b/source/blender/makesdna/DNA_sensor_types.h
@@ -0,0 +1,253 @@
+/**
+ * blenlib/DNA_sensor_types.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef DNA_SENSOR_TYPES_H
+#define DNA_SENSOR_TYPES_H
+
+struct Object;
+struct Material;
+
+/* ****************** SENSORS ********************* */
+
+typedef struct bNearSensor {
+ char name[32];
+ float dist, resetdist;
+ int lastval, pad;
+} bNearSensor;
+
+/**
+ * Defines the settings of a mouse sensor.
+ */
+typedef struct bMouseSensor {
+ /**
+ * The type of key this sensor listens to.
+ */
+ short type;
+ short flag;
+ short pad1;
+ short pad2;
+} bMouseSensor;
+
+typedef struct bTouchSensor {
+ char name[32];
+ struct Material *ma;
+ float dist, pad;
+} bTouchSensor;
+
+typedef struct bKeyboardSensor {
+ short key, qual;
+ short type, qual2;
+ /**
+ * Name of the target property
+ */
+ char targetName[32];
+ /**
+ * Name of the toggle property
+ */
+ char toggleName[32];
+} bKeyboardSensor;
+
+typedef struct bPropertySensor {
+ int type;
+ int pad;
+ char name[32];
+ char value[32];
+ char maxvalue[32];
+} bPropertySensor;
+
+typedef struct bCollisionSensor {
+ char name[32]; /* property name */
+ char materialName[32]; /* material */
+ short damptimer, damp;
+ short mode; /* flag to choose material or property */
+ short pad2;
+} bCollisionSensor;
+
+typedef struct bRadarSensor {
+ char name[32];
+ float angle;
+ float range;
+ short flag, axis;
+} bRadarSensor;
+
+typedef struct bRandomSensor {
+ char name[32];
+ int seed;
+ int delay;
+} bRandomSensor;
+
+typedef struct bRaySensor {
+ char name[32];
+ float range;
+ char propname[32];
+ char matname[32];
+ short mode;
+ short pad1;
+ int axisflag;
+} bRaySensor;
+
+typedef struct bMessageSensor {
+ /**
+ * (Possible future use) pointer to a single sender object
+ */
+ struct Object *fromObject;
+
+ /**
+ * Can be used to filter on subjects like this
+ */
+ char subject[32];
+
+ /**
+ * (Possible future use) body to filter on
+ */
+ char body[32];
+} bMessageSensor;
+
+typedef struct bSensor {
+ struct bSensor *next, *prev;
+ /* pulse and freq are the bool toggle and frame count for pulse mode */
+ short type, otype, flag, pulse;
+ short freq, totlinks, pad1, pad2;
+ char name[32];
+ void *data;
+
+ struct bController **links;
+
+ struct Object *ob;
+
+ /* just add here, to avoid align errors... */
+ short invert; /* Whether or not to invert the output. */
+ short freq2; /* The negative pulsing frequency? Not used anymore... */
+ int pad;
+} bSensor;
+
+typedef struct bJoystickSensor {
+ char name[32];
+ short type;
+ short pad;
+ int axis;
+ int axisf;
+ int button;
+ int buttonf;
+ int hat;
+ int hatf;
+ int precision;
+} bJoystickSensor;
+
+/* bMouseSensor->type: uses blender event defines */
+
+/* propertysensor->type */
+#define SENS_PROP_EQUAL 0
+#define SENS_PROP_NEQUAL 1
+#define SENS_PROP_INTERVAL 2
+#define SENS_PROP_CHANGED 3
+#define SENS_PROP_EXPRESSION 4
+
+/* raysensor->axisflag */
+/* flip x and y to make y default!!! */
+#define SENS_RAY_X_AXIS 1
+#define SENS_RAY_Y_AXIS 0
+#define SENS_RAY_Z_AXIS 2
+#define SENS_RAY_NEG_X_AXIS 3
+#define SENS_RAY_NEG_Y_AXIS 4
+#define SENS_RAY_NEG_Z_AXIS 5
+//#define SENS_RAY_NEGATIVE_AXIS 1
+
+/* bMessageSensor->type */
+#define SENS_MESG_MESG 0
+#define SENS_MESG_PROP 1
+
+/* sensor->type */
+#define SENS_ALWAYS 0
+#define SENS_TOUCH 1
+#define SENS_NEAR 2
+#define SENS_KEYBOARD 3
+#define SENS_PROPERTY 4
+#define SENS_MOUSE 5
+#define SENS_COLLISION 6
+#define SENS_RADAR 7
+#define SENS_RANDOM 8
+#define SENS_RAY 9
+#define SENS_MESSAGE 10
+#define SENS_JOYSTICK 11
+/* sensor->flag */
+#define SENS_SHOW 1
+#define SENS_DEL 2
+#define SENS_NEW 4
+#define SENS_NOT 8
+
+/* sensor->pulse */
+#define SENS_PULSE_CONT 0
+#define SENS_PULSE_REPEAT 1
+//#define SENS_PULSE_ONCE 2
+#define SENS_NEG_PULSE_MODE 4
+
+/* sensor->suppress */
+#define SENS_SUPPRESS_POSITIVE (1 << 0)
+#define SENS_SUPPRESS_NEGATIVE (1 << 1)
+
+/* collision, ray sensor modes: */
+/* A little bit fake: when property is active, the first bit is
+ * reset. Bite me :) So we don't actually use it, so we comment it out
+ * ... The reason for this is that we need to be backward compatible,
+ * and have a proper default value for this thing.
+ * */
+/* #define SENS_COLLISION_PROPERTY 0 */
+#define SENS_COLLISION_MATERIAL 1
+
+/* Some stuff for the mouse sensor Type: */
+#define BL_SENS_MOUSE_LEFT_BUTTON 1
+#define BL_SENS_MOUSE_MIDDLE_BUTTON 2
+#define BL_SENS_MOUSE_RIGHT_BUTTON 4
+#define BL_SENS_MOUSE_WHEEL_UP 5
+#define BL_SENS_MOUSE_WHEEL_DOWN 6
+#define BL_SENS_MOUSE_MOVEMENT 8
+#define BL_SENS_MOUSE_MOUSEOVER 16
+#define BL_SENS_MOUSE_MOUSEOVER_ANY 32
+
+#define SENS_JOY_BUTTON 0
+#define SENS_JOY_BUTTON_PRESSED 0
+#define SENS_JOY_BUTTON_RELEASED 1
+
+#define SENS_JOY_AXIS 1
+#define SENS_JOY_X_AXIS 0
+#define SENS_JOY_Y_AXIS 1
+#define SENS_JOY_NEG_X_AXIS 2
+#define SENS_JOY_NEG_Y_AXIS 3
+#define SENS_JOY_PRECISION 4
+
+#define SENS_JOY_HAT 2
+#define SENS_JOY_HAT_DIR 0
+
+#endif
+
diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h
new file mode 100644
index 00000000000..839d804fbea
--- /dev/null
+++ b/source/blender/makesdna/DNA_sequence_types.h
@@ -0,0 +1,239 @@
+/**
+ * blenlib/DNA_sequence_types.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef DNA_SEQUENCE_TYPES_H
+#define DNA_SEQUENCE_TYPES_H
+
+#include "DNA_listBase.h"
+
+/* needed for sound support */
+#include "DNA_sound_types.h"
+
+struct Ipo;
+struct Scene;
+
+/* strlens; 80= FILE_MAXFILE, 160= FILE_MAXDIR */
+
+typedef struct StripElem {
+ char name[80];
+ struct ImBuf *ibuf;
+ struct StripElem *se1, *se2, *se3;
+ short ok;
+ short pad;
+ int nr;
+} StripElem;
+
+typedef struct Strip {
+ struct Strip *next, *prev;
+ int rt, len, us, done;
+ StripElem *stripdata;
+ char dir[160];
+ int orx, ory;
+} Strip;
+
+
+typedef struct PluginSeq {
+ char name[256];
+ void *handle;
+
+ char *pname;
+
+ int vars, version;
+
+ void *varstr;
+ float *cfra;
+
+ float data[32];
+
+ void *instance_private_data;
+ void **current_private_data;
+
+ void (*doit)(void);
+
+ void (*callback)(void);
+} PluginSeq;
+
+/* The sequence structure is the basic struct used by any strip. each of the strips uses a different sequence structure.*/
+/* WATCH IT: first part identical to ID (for use in ipo's) */
+
+typedef struct Sequence {
+
+ struct Sequence *next, *prev;
+ void *tmp; /* tmp var for copying, and tagging for linked selection */
+ void *lib; /* needed (to be like ipo), else it will raise libdata warnings, this should never be used */
+ char name[24]; /* name, not set by default and dosnt need to be unique as with ID's */
+
+ short flag, type; /*flags bitmap (see below) and the type of sequence*/
+ int len; /* the length of the contense of this strip - before handles are applied */
+ int start, startofs, endofs;
+ int startstill, endstill;
+ int machine, depth; /*machine - the strip channel, depth - the depth in the sequence when dealing with metastrips */
+ int startdisp, enddisp; /*starting and ending points in the sequence*/
+ float mul, handsize;
+ /* is sfra needed anymore? - it looks like its only used in one place */
+ int sfra; /* starting frame according to the timeline of the scene. */
+
+ Strip *strip;
+ StripElem *curelem; /* reference the current frame - value from give_stripelem */
+
+ struct Ipo *ipo;
+ struct Scene *scene;
+ struct anim *anim;
+ float facf0, facf1;
+
+ PluginSeq *plugin;
+
+ /* pointers for effects: */
+ struct Sequence *seq1, *seq2, *seq3;
+
+ ListBase seqbase; /* list of strips for metastrips */
+
+ struct bSound *sound; /* the linked "bSound" object */
+ struct hdaudio *hdaudio; /* external hdaudio object */
+ float level, pan; /* level in dB (0=full), pan -1..1 */
+ int curpos; /* last sample position in audio_fill() */
+ float strobe;
+
+ void *effectdata; /* Struct pointer for effect settings */
+
+ int anim_preseek;
+ int pad;
+} Sequence;
+
+typedef struct MetaStack {
+ struct MetaStack *next, *prev;
+ ListBase *oldbasep;
+ Sequence *parseq;
+} MetaStack;
+
+typedef struct Editing {
+ ListBase *seqbasep;
+ ListBase seqbase;
+ ListBase metastack;
+ short flag;
+ short pad;
+ int rt;
+} Editing;
+
+/* ************* Effect Variable Structs ********* */
+typedef struct WipeVars {
+ float edgeWidth,angle;
+ short forward, wipetype;
+} WipeVars;
+
+typedef struct GlowVars {
+ float fMini; /* Minimum intensity to trigger a glow */
+ float fClamp;
+ float fBoost; /* Amount to multiply glow intensity */
+ float dDist; /* Radius of glow blurring */
+ int dQuality;
+ int bNoComp; /* SHOW/HIDE glow buffer */
+} GlowVars;
+
+typedef struct TransformVars {
+ float ScalexIni;
+ float ScaleyIni;
+ float ScalexFin;
+ float ScaleyFin;
+ float xIni;
+ float xFin;
+ float yIni;
+ float yFin;
+ float rotIni;
+ float rotFin;
+ int percent;
+ int interpolation;
+} TransformVars;
+
+typedef struct SolidColorVars {
+ float col[3];
+ float pad;
+} SolidColorVars;
+
+typedef struct SpeedControlVars {
+ float * frameMap;
+ float globalSpeed;
+ int flags;
+ int length;
+ int lastValidFrame;
+} SpeedControlVars;
+
+/* SpeedControlVars->flags */
+#define SEQ_SPEED_INTEGRATE 1
+#define SEQ_SPEED_BLEND 2
+#define SEQ_SPEED_COMPRESS_IPO_Y 4
+
+/* ***************** SEQUENCE ****************** */
+
+/* seq->flag */
+#define SEQ_LEFTSEL 2
+#define SEQ_RIGHTSEL 4
+#define SEQ_OVERLAP 8
+#define SEQ_FILTERY 16
+#define SEQ_MUTE 32
+#define SEQ_MAKE_PREMUL 64
+#define SEQ_REVERSE_FRAMES 128
+#define SEQ_IPO_FRAME_LOCKED 256
+#define SEQ_EFFECT_NOT_LOADED 512
+#define SEQ_FLAG_DELETE 1024
+#define SEQ_FLIPX 2048
+#define SEQ_FLIPY 4096
+
+/* seq->type WATCH IT: SEQ_EFFECT BIT is used to determine if this is an effect strip!!! */
+#define SEQ_IMAGE 0
+#define SEQ_META 1
+#define SEQ_SCENE 2
+#define SEQ_MOVIE 3
+#define SEQ_RAM_SOUND 4
+#define SEQ_HD_SOUND 5
+#define SEQ_MOVIE_AND_HD_SOUND 6 /* helper for add_sequence */
+
+#define SEQ_EFFECT 8
+#define SEQ_CROSS 8
+#define SEQ_ADD 9
+#define SEQ_SUB 10
+#define SEQ_ALPHAOVER 11
+#define SEQ_ALPHAUNDER 12
+#define SEQ_GAMCROSS 13
+#define SEQ_MUL 14
+#define SEQ_OVERDROP 15
+#define SEQ_PLUGIN 24
+#define SEQ_WIPE 25
+#define SEQ_GLOW 26
+#define SEQ_TRANSFORM 27
+#define SEQ_COLOR 28
+#define SEQ_SPEED 29
+
+
+#endif
+
diff --git a/source/blender/makesdna/DNA_sound_types.h b/source/blender/makesdna/DNA_sound_types.h
new file mode 100644
index 00000000000..27b9c373484
--- /dev/null
+++ b/source/blender/makesdna/DNA_sound_types.h
@@ -0,0 +1,183 @@
+/**
+ * blenlib/DNA_sound_types.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef DNA_SOUND_TYPES_H
+#define DNA_SOUND_TYPES_H
+
+#include "DNA_listBase.h"
+#include "DNA_ID.h"
+
+/* stupid... could easily be solved */
+#include "DNA_view2d_types.h"
+
+/* extern int noaudio; * defined in sound.c . also not very nice */
+/* extern ListBase *samples; don't do this in DNA, but in BKE_... instead */
+
+struct bSample;
+struct Ipo;
+struct PackedFile;
+struct SpaceLink;
+
+/* should not be here! */
+#
+#
+typedef struct bSample {
+ ID id;
+ void *data;
+ void *snd_sample;
+ short type, bits;
+ short channels;
+ int len, rate;
+// int buffer;
+ int alindex;
+ char fakedata[16];
+ int flags;
+ char name[160];
+ struct PackedFile * packedfile;
+ short us;
+} bSample;
+
+
+
+typedef struct bSound {
+ ID id;
+ char name[160];
+ struct bSample *sample;
+ void *stream;
+ struct PackedFile *packedfile;
+ struct PackedFile *newpackedfile;
+ void *snd_sound;
+ struct Ipo *ipo;
+ float volume, panning;
+ /**
+ * Sets the rollofffactor. The rollofffactor is a per-Source parameter
+ * the application can use to increase or decrease the range of a source
+ * by decreasing or increasing the attenuation, respectively. The default
+ * value is 1. The implementation is free to optimize for a rollofffactor
+ * value of 0, which indicates that the application does not wish any
+ * distance attenuation on the respective Source.
+ */
+ float attenuation;
+ float pitch;
+ /**
+ * min_gain indicates the minimal gain which is always guaranteed for this sound
+ */
+ float min_gain;
+ /**
+ * max_gain indicates the maximal gain which is always guaranteed for this sound
+ */
+ float max_gain;
+ /**
+ * Sets the referencedistance at which the listener will experience gain.
+ */
+ float distance;
+ int flags;
+ int streamlen;
+ char channels;
+ char highprio;
+ char pad[10];
+} bSound;
+
+typedef struct bSoundListener {
+ ID id;
+ /**
+ * Overall gain
+ */
+ float gain;
+ /**
+ * Sets a scaling to exaggerate or deemphasize the Doppler (pitch) shift
+ * resulting from the calculation.
+ */
+ float dopplerfactor;
+ /**
+ * Sets the value of the propagation speed relative to which the source
+ * velocities are interpreted.
+ */
+ float dopplervelocity;
+ short numsoundsblender;
+ short numsoundsgameengine;
+
+} bSoundListener;
+
+/* spacesound->flag */
+#define SND_DRAWFRAMES 1
+#define SND_CFRA_NUM 2
+
+typedef struct SpaceSound {
+ struct SpaceLink *next, *prev;
+ int spacetype;
+ float blockscale;
+ struct ScrArea *area;
+
+ View2D v2d;
+
+ bSound *sound;
+ short mode, sndnr;
+ short xof, yof;
+ short flag, lock;
+ int pad2;
+} SpaceSound;
+
+
+enum SAMPLE_FileTypes {
+ SAMPLE_INVALID = -1, // must be negative
+ SAMPLE_UNKNOWN = 0,
+ SAMPLE_RAW,
+ SAMPLE_WAV,
+ SAMPLE_MP2,
+ SAMPLE_MP3,
+ SAMPLE_OGG_VORBIS,
+ SAMPLE_WMA,
+ SAMPLE_ASF,
+ SAMPLE_AIFF
+};
+
+
+#define SOUND_CHANNELS_STEREO 0
+#define SOUND_CHANNELS_LEFT 1
+#define SOUND_CHANNELS_RIGHT 2
+
+#define SOUND_FLAGS_LOOP (1 << 0)
+#define SOUND_FLAGS_FIXED_VOLUME (1 << 1)
+#define SOUND_FLAGS_FIXED_PANNING (1 << 2)
+#define SOUND_FLAGS_3D (1 << 3)
+#define SOUND_FLAGS_BIDIRECTIONAL_LOOP (1 << 4)
+#define SOUND_FLAGS_PRIORITY (1 << 5)
+#define SOUND_FLAGS_SEQUENCE (1 << 6)
+
+#define SAMPLE_NEEDS_SAVE (1 << 0)
+
+/* to DNA_sound_types.h*/
+
+#endif
+
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
new file mode 100644
index 00000000000..10f488c9f61
--- /dev/null
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -0,0 +1,649 @@
+/**
+ * blenlib/DNA_space_types.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef DNA_SPACE_TYPES_H
+#define DNA_SPACE_TYPES_H
+
+#include "DNA_listBase.h"
+#include "DNA_vec_types.h"
+#include "DNA_oops_types.h" /* for TreeStoreElem */
+#include "DNA_image_types.h" /* ImageUser */
+/* Hum ... Not really nice... but needed for spacebuts. */
+#include "DNA_view2d_types.h"
+
+struct Ipo;
+struct ID;
+struct Text;
+struct Script;
+struct ImBuf;
+struct Image;
+struct SpaceIpo;
+struct BlendHandle;
+struct RenderInfo;
+struct bNodeTree;
+struct uiBlock;
+struct FileList;
+
+ /**
+ * The base structure all the other spaces
+ * are derived (implicitly) from. Would be
+ * good to make this explicit.
+ */
+typedef struct SpaceLink SpaceLink;
+struct SpaceLink {
+ SpaceLink *next, *prev;
+ int spacetype;
+ float blockscale;
+ struct ScrArea *area;
+ short blockhandler[8];
+};
+
+typedef struct SpaceInfo {
+ SpaceLink *next, *prev;
+ int spacetype;
+ float blockscale;
+ struct ScrArea *area;
+
+ short blockhandler[8];
+} SpaceInfo;
+
+typedef struct SpaceIpo {
+ SpaceLink *next, *prev;
+ int spacetype;
+ float blockscale;
+ struct ScrArea *area;
+
+ short blockhandler[8];
+
+ unsigned int rowbut, pad2;
+ View2D v2d;
+
+ void *editipo;
+ ListBase ipokey;
+
+ /* the ipo context we need to store */
+ struct Ipo *ipo;
+ struct ID *from;
+ char actname[32], constname[32];
+
+ short totipo, pin;
+ short butofs, channel;
+ short showkey, blocktype;
+ short menunr, lock;
+ int flag;
+ float median[3];
+ rctf tot;
+} SpaceIpo;
+
+typedef struct SpaceButs {
+ SpaceLink *next, *prev;
+ int spacetype;
+ float blockscale;
+ struct ScrArea *area;
+ struct RenderInfo *ri;
+
+ short blockhandler[8];
+
+ short cursens, curact;
+ short align, tabo; /* align for panels, tab is old tab */
+ View2D v2d;
+
+ short mainb, menunr; /* texnr and menunr have to remain shorts */
+ short pin, mainbo;
+ void *lockpoin;
+
+ short texnr;
+ char texfrom, showgroup;
+
+ short modeltype;
+ short scriptblock;
+ short scaflag;
+ short re_align;
+
+ short oldkeypress; /* for keeping track of the sub tab key cycling */
+ char pad, flag;
+
+ char texact, tab[7]; /* storing tabs for each context */
+
+} SpaceButs;
+
+typedef struct SpaceSeq {
+ SpaceLink *next, *prev;
+ int spacetype;
+ float blockscale;
+ struct ScrArea *area;
+
+ short blockhandler[8];
+
+ View2D v2d;
+
+ float xof, yof; /* offset for drawing the image preview */
+ short mainb, zoom;
+ short chanshown;
+ short pad2;
+ int flag;
+ int pad;
+} SpaceSeq;
+
+typedef struct SpaceFile {
+ SpaceLink *next, *prev;
+ int spacetype;
+ float blockscale;
+ struct ScrArea *area;
+
+ short blockhandler[8];
+
+ struct direntry *filelist;
+ int totfile;
+
+ char title[24];
+ char dir[160];
+ char file[80];
+
+ short type, ofs, flag, sort;
+ short maxnamelen, collums, f_fp, pad1;
+ int pad2;
+ char fp_str[8];
+
+ struct BlendHandle *libfiledata;
+
+ unsigned short retval; /* event */
+ short menu, act, ipotype;
+
+ /* one day we'll add unions to dna */
+ void (*returnfunc)(char *);
+ void (*returnfunc_event)(unsigned short);
+ void (*returnfunc_args)(char *, void *, void *);
+
+ void *arg1, *arg2;
+ short *menup; /* pointer to menu result or ID browsing */
+ char *pupmenu; /* optional menu in header */
+} SpaceFile;
+
+typedef struct SpaceOops {
+ SpaceLink *next, *prev;
+ int spacetype;
+ float blockscale;
+ struct ScrArea *area;
+
+ short blockhandler[8];
+
+ View2D v2d;
+
+ ListBase oops;
+ short pin, visiflag, flag, rt;
+ void *lockpoin;
+
+ ListBase tree;
+ struct TreeStore *treestore;
+
+ /* search stuff */
+ char search_string[32];
+ struct TreeStoreElem search_tse;
+ int search_flags, do_;
+
+ short type, outlinevis, storeflag;
+ short deps_flags;
+
+} SpaceOops;
+
+typedef struct SpaceImage {
+ SpaceLink *next, *prev;
+ int spacetype;
+ float blockscale;
+ struct ScrArea *area;
+
+ short blockhandler[8];
+
+ View2D v2d;
+
+ struct Image *image;
+ struct ImageUser iuser;
+
+ struct CurveMapping *cumap;
+ short mode, menunr;
+ short imanr;
+ short curtile; /* the currently active tile of the image when tile is enabled, is kept in sync with the active faces tile */
+ int flag;
+ short imtypenr, lock;
+ short showspare, pin;
+ float zoom;
+ char dt_uv; /* UV draw type */
+ char sticky; /* sticky selection type */
+ char pad[6];
+
+ float xof, yof; /* user defined offset, image is centered */
+ float centx, centy; /* storage for offset while render drawing */
+
+ char *info_str, *info_spare; /* info string for render */
+ struct ImBuf *spare;
+
+} SpaceImage;
+
+typedef struct SpaceNla {
+ struct SpaceLink *next, *prev;
+ int spacetype;
+ float blockscale;
+ struct ScrArea *area;
+
+ short blockhandler[8];
+
+ short menunr, lock;
+ short autosnap; /* this uses the same settings as autosnap for Action Editor */
+ short flag;
+
+ View2D v2d;
+} SpaceNla;
+
+typedef struct SpaceText {
+ SpaceLink *next, *prev;
+ int spacetype;
+ float blockscale;
+ struct ScrArea *area;
+
+ short blockhandler[8];
+
+ struct Text *text;
+
+ int top, viewlines;
+ short flags, menunr;
+
+ int font_id;
+ int lheight;
+ int left;
+ int showlinenrs;
+
+ int tabnumber;
+ int currtab_set;
+ int showsyntax;
+ int unused_padd;
+
+ float pix_per_line;
+
+ struct rcti txtscroll, txtbar;
+
+} SpaceText;
+
+typedef struct SpaceScript {
+ SpaceLink *next, *prev;
+ int spacetype;
+ float blockscale;
+ struct ScrArea *area;
+ struct Script *script;
+
+ short flags, menunr;
+ int pad1;
+
+ void *but_refs;
+} SpaceScript;
+
+typedef struct SpaceTime {
+ SpaceLink *next, *prev;
+ int spacetype;
+ float blockscale;
+ struct ScrArea *area;
+
+ View2D v2d;
+
+ int flag, redraws;
+
+} SpaceTime;
+
+typedef struct SpaceNode {
+ SpaceLink *next, *prev;
+ int spacetype;
+ float blockscale;
+ struct ScrArea *area;
+
+ View2D v2d;
+
+ struct ID *id, *from; /* context, no need to save in file? well... pinning... */
+ short flag, menunr; /* menunr: browse id block in header */
+ float aspect;
+ void *curfont;
+
+ float xof, yof; /* offset for drawing the backdrop */
+
+ struct bNodeTree *nodetree, *edittree;
+ int treetype, pad; /* treetype: as same nodetree->type */
+
+} SpaceNode;
+
+/* snode->flag */
+#define SNODE_DO_PREVIEW 1
+#define SNODE_BACKDRAW 2
+
+typedef struct SpaceImaSel {
+ SpaceLink *next, *prev;
+ int spacetype;
+ float blockscale;
+ struct ScrArea *area;
+
+ short blockhandler[8];
+
+ View2D v2d;
+
+ struct FileList *files;
+
+ /* specific stuff for drawing */
+ char title[24];
+ char dir[160];
+ char file[80];
+
+ short type, menu, flag, sort;
+
+ void *curfont;
+ int active_file;
+
+ int numtilesx;
+ int numtilesy;
+
+ int selstate;
+
+ struct rcti viewrect;
+ struct rcti bookmarkrect;
+
+ float scrollpos; /* current position of scrollhandle */
+ float scrollheight; /* height of the scrollhandle */
+ float scrollarea; /* scroll region, scrollpos is from 0 to scrollarea */
+
+ float aspect;
+ unsigned short retval; /* event */
+
+ short ipotype;
+
+ short filter;
+ short active_bookmark;
+ short pad, pad1;
+
+ /* view settings */
+ short prv_w;
+ short prv_h;
+
+ /* one day we'll add unions to dna */
+ void (*returnfunc)(char *);
+ void (*returnfunc_event)(unsigned short);
+ void (*returnfunc_args)(char *, void *, void *);
+
+ void *arg1, *arg2;
+ short *menup; /* pointer to menu result or ID browsing */
+ char *pupmenu; /* optional menu in header */
+
+ struct ImBuf *img;
+} SpaceImaSel;
+
+
+/* **************** SPACE ********************* */
+
+
+/* view3d Now in DNA_view3d_types.h */
+
+/* button defines in BIF_butspace.h */
+
+/* sbuts->flag */
+#define SB_PRV_OSA 1
+
+/* these values need to be hardcoded in structs, dna does not recognize defines */
+/* also defined in BKE */
+#define FILE_MAXDIR 160
+#define FILE_MAXFILE 80
+#define FILE_MAX 240
+
+/* filesel types */
+#define FILE_UNIX 8
+#define FILE_BLENDER 8
+#define FILE_SPECIAL 9
+
+#define FILE_LOADLIB 1
+#define FILE_MAIN 2
+#define FILE_LOADFONT 3
+
+/* sfile->flag and simasel->flag */
+#define FILE_SHOWSHORT 1
+#define FILE_STRINGCODE 2
+#define FILE_LINK 4
+#define FILE_HIDE_DOT 8
+#define FILE_AUTOSELECT 16
+#define FILE_ACTIVELAY 32
+#define FILE_ATCURSOR 64
+#define FILE_SYNCPOSE 128
+#define FILE_FILTER 256
+#define FILE_BOOKMARKS 512
+
+/* sfile->sort */
+#define FILE_SORTALPHA 0
+#define FILE_SORTDATE 1
+#define FILE_SORTSIZE 2
+#define FILE_SORTEXTENS 3
+
+/* files in filesel list: 2=ACTIVE */
+#define HILITE 1
+#define BLENDERFILE 4
+#define PSXFILE 8
+#define IMAGEFILE 16
+#define MOVIEFILE 32
+#define PYSCRIPTFILE 64
+#define FTFONTFILE 128
+#define SOUNDFILE 256
+#define TEXTFILE 512
+#define MOVIEFILE_ICON 1024 /* movie file that preview can't load */
+#define FOLDERFILE 2048 /* represents folders for filtering */
+
+#define SCROLLH 16 /* height scrollbar */
+#define SCROLLB 16 /* width scrollbar */
+
+/* SpaceImage->mode */
+#define SI_TEXTURE 0
+#define SI_SHOW 1
+
+/* SpaceImage->dt_uv */
+#define SI_UVDT_DASH 0
+#define SI_UVDT_BLACK 1
+#define SI_UVDT_WHITE 2
+#define SI_UVDT_OUTLINE 3
+
+/* SpaceImage->sticky
+ * Note DISABLE should be 0, however would also need to re-arrange icon order,
+ * also, sticky loc is the default mode so this means we dont need to 'do_versons' */
+#define SI_STICKY_LOC 0
+#define SI_STICKY_DISABLE 1
+#define SI_STICKY_VERTEX 2
+
+/* SpaceImage->flag */
+#define SI_BE_SQUARE 1<<0
+#define SI_EDITTILE 1<<1
+#define SI_CLIP_UV 1<<2
+#define SI_DRAWTOOL 1<<3
+#define SI_DEPRECATED1 1<<4 /* stick UVs to others in the same location */
+#define SI_DRAWSHADOW 1<<5
+#define SI_SELACTFACE 1<<6
+#define SI_DEPRECATED2 1<<7
+#define SI_DEPRECATED3 1<<8 /* stick UV selection to mesh vertex (UVs wont always be touching) */
+#define SI_COORDFLOATS 1<<9
+#define SI_PIXELSNAP 1<<10
+#define SI_LIVE_UNWRAP 1<<11
+#define SI_USE_ALPHA 1<<12
+#define SI_SHOW_ALPHA 1<<13
+#define SI_SHOW_ZBUF 1<<14
+ /* next two for render window dislay */
+#define SI_PREVSPACE 1<<15
+#define SI_FULLWINDOW 1<<16
+#define SI_SYNC_UVSEL 1<<17
+#define SI_LOCAL_UV 1<<18
+ /* this means that the image is drawn until it reaches the view edge,
+ * in the image view, its unrelated to the 'tile' mode for texface */
+#define SI_DRAW_TILE 1<<19
+#define SI_SMOOTH_UV 1<<20
+
+/* SpaceText flags (moved from DNA_text_types.h) */
+
+#define ST_SCROLL_SELECT 0x0001 // scrollable
+#define ST_CLEAR_NAMESPACE 0x0010 // clear namespace after script
+ // execution (see BPY_main.c)
+
+/* SpaceOops->type */
+#define SO_OOPS 0
+#define SO_OUTLINER 1
+#define SO_DEPSGRAPH 2
+
+/* SpaceOops->flag */
+#define SO_TESTBLOCKS 1
+#define SO_NEWSELECTED 2
+#define SO_HIDE_RESTRICTCOLS 4
+
+/* SpaceOops->visiflag */
+#define OOPS_SCE 1
+#define OOPS_OB 2
+#define OOPS_ME 4
+#define OOPS_CU 8
+#define OOPS_MB 16
+#define OOPS_LT 32
+#define OOPS_LA 64
+#define OOPS_MA 128
+#define OOPS_TE 256
+#define OOPS_IP 512
+#define OOPS_LAY 1024
+#define OOPS_LI 2048
+#define OOPS_IM 4096
+#define OOPS_AR 8192
+#define OOPS_GR 16384
+
+/* SpaceOops->outlinevis */
+#define SO_ALL_SCENES 0
+#define SO_CUR_SCENE 1
+#define SO_VISIBLE 2
+#define SO_SELECTED 3
+#define SO_ACTIVE 4
+#define SO_SAME_TYPE 5
+#define SO_GROUPS 6
+#define SO_LIBRARIES 7
+#define SO_VERSE_SESSION 8
+#define SO_VERSE_MS 9
+
+/* SpaceOops->storeflag */
+#define SO_TREESTORE_CLEANUP 1
+ /* if set, it allows redraws. gets set for some allqueue events */
+#define SO_TREESTORE_REDRAW 2
+
+/* headerbuttons: 450-499 */
+
+#define B_IMASELHOME 451
+#define B_IMASELREMOVEBIP 452
+
+#define C_BACK 0xBAAAAA
+#define C_DARK 0x665656
+#define C_DERK 0x766666
+#define C_HI 0xCBBBBB
+#define C_LO 0x544444
+
+/* queue settings */
+#define IMS_KNOW_WIN 1
+#define IMS_KNOW_BIP 2
+#define IMS_KNOW_DIR 4
+#define IMS_DOTHE_INF 8
+#define IMS_KNOW_INF 16
+#define IMS_DOTHE_IMA 32
+#define IMS_KNOW_IMA 64
+#define IMS_FOUND_BIP 128
+#define IMS_DOTHE_BIP 256
+#define IMS_WRITE_NO_BIP 512
+
+/* imasel->mode */
+#define IMS_NOIMA 0
+#define IMS_IMA 1
+#define IMS_ANIM 2
+#define IMS_DIR 4
+#define IMS_FILE 8
+#define IMS_STRINGCODE 16
+
+#define IMS_INDIR 1
+#define IMS_INDIRSLI 2
+#define IMS_INFILE 3
+#define IMS_INFILESLI 4
+
+/* nla->flag */
+#define SNLA_ALLKEYED 1
+#define SNLA_ACTIVELAYERS 2
+#define SNLA_DRAWTIME 4
+
+/* time->flag */
+ /* show timing in frames instead of in seconds */
+#define TIME_DRAWFRAMES 1
+ /* temporary flag set when scrubbing time */
+#define TIME_CFRA_NUM 2
+ /* only keyframes from active/selected channels get shown */
+#define TIME_ONLYACTSEL 4
+
+/* time->redraws */
+#define TIME_LEFTMOST_3D_WIN 1
+#define TIME_ALL_3D_WIN 2
+#define TIME_ALL_ANIM_WIN 4
+#define TIME_ALL_BUTS_WIN 8
+#define TIME_WITH_SEQ_AUDIO 16
+#define TIME_SEQ 32
+#define TIME_ALL_IMAGE_WIN 64
+
+/* sseq->mainb */
+#define SEQ_DRAW_SEQUENCE 0
+#define SEQ_DRAW_IMG_IMBUF 1
+#define SEQ_DRAW_IMG_WAVEFORM 2
+#define SEQ_DRAW_IMG_VECTORSCOPE 3
+
+/* sseq->flag */
+#define SEQ_DRAWFRAMES 1
+#define SEQ_MARKER_TRANS 2
+
+/* space types, moved from DNA_screen_types.h */
+enum {
+ SPACE_EMPTY,
+ SPACE_VIEW3D,
+ SPACE_IPO,
+ SPACE_OOPS,
+ SPACE_BUTS,
+ SPACE_FILE,
+ SPACE_IMAGE,
+ SPACE_INFO,
+ SPACE_SEQ,
+ SPACE_TEXT,
+ SPACE_IMASEL,
+ SPACE_SOUND,
+ SPACE_ACTION,
+ SPACE_NLA,
+ SPACE_SCRIPT,
+ SPACE_TIME,
+ SPACE_NODE,
+ SPACEICONMAX = SPACE_NODE
+/* SPACE_LOGIC */
+};
+
+#endif
diff --git a/source/blender/makesdna/DNA_text_types.h b/source/blender/makesdna/DNA_text_types.h
new file mode 100644
index 00000000000..8f2b40f7ff6
--- /dev/null
+++ b/source/blender/makesdna/DNA_text_types.h
@@ -0,0 +1,80 @@
+/**
+ * blenlib/DNA_text_types.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef DNA_TEXT_TYPES_H
+#define DNA_TEXT_TYPES_H
+
+#include "DNA_listBase.h"
+#include "DNA_ID.h"
+
+typedef struct TextLine {
+ struct TextLine *next, *prev;
+
+ char *line;
+ char *format;
+ int len, blen;
+} TextLine;
+
+typedef struct Text {
+ ID id;
+
+ char *name;
+
+ int flags, nlines;
+
+ ListBase lines;
+ TextLine *curl, *sell;
+ int curc, selc;
+
+ char *undo_buf;
+ int undo_pos, undo_len;
+
+ void *compiled;
+} Text;
+
+
+#define TXT_OFFSET 35
+#define TXT_TABSIZE 4
+#define TXT_INIT_UNDO 1024
+#define TXT_MAX_UNDO (TXT_INIT_UNDO*TXT_INIT_UNDO)
+
+/* text flags */
+#define TXT_ISDIRTY 0x0001
+#define TXT_ISTMP 0x0002
+#define TXT_ISMEM 0x0004
+#define TXT_ISEXT 0x0008
+#define TXT_ISSCRIPT 0x0010 /* used by space handler scriptlinks */
+#define TXT_READONLY 0x0100
+#define TXT_FOLLOW 0x0200 /* always follow cursor (console) */
+
+#endif
diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h
new file mode 100644
index 00000000000..cf51990c9bf
--- /dev/null
+++ b/source/blender/makesdna/DNA_texture_types.h
@@ -0,0 +1,377 @@
+/**
+ * blenlib/DNA_texture_types.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef DNA_TEXTURE_TYPES_H
+#define DNA_TEXTURE_TYPES_H
+
+#include "DNA_ID.h"
+#include "DNA_image_types.h"
+
+struct Ipo;
+struct PluginTex;
+struct ColorBand;
+struct EnvMap;
+struct Object;
+struct Tex;
+struct Image;
+struct PreviewImage;
+struct ImBuf;
+
+typedef struct MTex {
+
+ short texco, mapto, maptoneg, blendtype;
+ struct Object *object;
+ struct Tex *tex;
+ char uvname[32];
+
+ char projx, projy, projz, mapping;
+ float ofs[3], size[3];
+
+ short texflag, colormodel;
+ float r, g, b, k;
+ float def_var;
+
+ float colfac, norfac, varfac;
+ float dispfac;
+ float warpfac;
+
+} MTex;
+
+#ifndef DNA_USHORT_FIX
+#define DNA_USHORT_FIX
+/**
+ * @deprecated This typedef serves to avoid badly typed functions when
+ * @deprecated compiling while delivering a proper dna.c. Do not use
+ * @deprecated it in any case.
+ */
+typedef unsigned short dna_ushort_fix;
+#endif
+
+typedef struct PluginTex {
+ char name[160];
+ void *handle;
+
+ char *pname;
+ char *stnames;
+
+ int stypes;
+ int vars;
+ void *varstr;
+ float *result;
+ float *cfra;
+
+ float data[32];
+
+ int (*doit)(void);
+ void (*instance_init)(void *);
+
+ /* should be void (*)(unsigned short)... patched */
+ void (*callback)(dna_ushort_fix);
+
+ int version, pad;
+} PluginTex;
+
+typedef struct CBData {
+ float r, g, b, a, pos;
+ int cur;
+} CBData;
+
+/* 32 = MAXCOLORBAND */
+/* note that this has to remain a single struct, for UserDef */
+typedef struct ColorBand {
+ short flag, tot, cur, ipotype;
+ CBData data[32];
+
+} ColorBand;
+
+typedef struct EnvMap {
+ struct Object *object;
+ struct Image *ima; /* type ENV_LOAD */
+ struct ImBuf *cube[6]; /* these images are dynamic, not part of the main struct */
+ float imat[4][4];
+ float obimat[3][3];
+ short type, stype;
+ float clipsta, clipend;
+ float viewscale; /* viewscale is for planar envmaps to zoom in or out */
+ unsigned int notlay;
+ short cuberes, depth;
+ int ok, lastframe;
+ short recalc, lastsize;
+} EnvMap;
+
+typedef struct Tex {
+ ID id;
+
+ float noisesize, turbul;
+ float bright, contrast, rfac, gfac, bfac;
+ float filtersize;
+
+ /* newnoise: musgrave parameters */
+ float mg_H, mg_lacunarity, mg_octaves, mg_offset, mg_gain;
+
+ /* newnoise: distorted noise amount, musgrave & voronoi ouput scale */
+ float dist_amount, ns_outscale;
+
+ /* newnoise: voronoi nearest neighbour weights, minkovsky exponent, distance metric & color type */
+ float vn_w1, vn_w2, vn_w3, vn_w4, vn_mexp;
+ short vn_distm, vn_coltype;
+
+ short noisedepth, noisetype;
+
+ /* newnoise: noisebasis type for clouds/marble/etc, noisebasis2 only used for distorted noise */
+ short noisebasis, noisebasis2;
+
+ short imaflag, flag;
+ short type, stype;
+
+ float cropxmin, cropymin, cropxmax, cropymax;
+ short xrepeat, yrepeat;
+ short extend;
+
+ /* variables disabled, moved to struct iuser */
+ short fie_ima;
+ int len;
+ int frames, offset, sfra;
+
+ float checkerdist, nabla;
+ float norfac;
+
+ struct ImageUser iuser;
+
+ struct Ipo *ipo;
+ struct Image *ima;
+ struct PluginTex *plugin;
+ struct ColorBand *coba;
+ struct EnvMap *env;
+ struct PreviewImage * preview;
+
+} Tex;
+
+/* used for mapping node. note: rot is in degrees */
+
+typedef struct TexMapping {
+ float loc[3], rot[3], size[3];
+ int flag;
+
+ float mat[4][4];
+ float min[3], max[3];
+ struct Object *ob;
+
+} TexMapping;
+
+/* texmap->flag */
+#define TEXMAP_CLIP_MIN 1
+#define TEXMAP_CLIP_MAX 2
+
+
+/* **************** TEX ********************* */
+
+/* type */
+#define TEX_CLOUDS 1
+#define TEX_WOOD 2
+#define TEX_MARBLE 3
+#define TEX_MAGIC 4
+#define TEX_BLEND 5
+#define TEX_STUCCI 6
+#define TEX_NOISE 7
+#define TEX_IMAGE 8
+#define TEX_PLUGIN 9
+#define TEX_ENVMAP 10
+#define TEX_MUSGRAVE 11
+#define TEX_VORONOI 12
+#define TEX_DISTNOISE 13
+
+/* musgrave stype */
+#define TEX_MFRACTAL 0
+#define TEX_RIDGEDMF 1
+#define TEX_HYBRIDMF 2
+#define TEX_FBM 3
+#define TEX_HTERRAIN 4
+
+/* newnoise: noisebasis 1 & 2 */
+#define TEX_BLENDER 0
+#define TEX_STDPERLIN 1
+#define TEX_NEWPERLIN 2
+#define TEX_VORONOI_F1 3
+#define TEX_VORONOI_F2 4
+#define TEX_VORONOI_F3 5
+#define TEX_VORONOI_F4 6
+#define TEX_VORONOI_F2F1 7
+#define TEX_VORONOI_CRACKLE 8
+#define TEX_CELLNOISE 14
+
+/* newnoise: Voronoi distance metrics, vn_distm */
+#define TEX_DISTANCE 0
+#define TEX_DISTANCE_SQUARED 1
+#define TEX_MANHATTAN 2
+#define TEX_CHEBYCHEV 3
+#define TEX_MINKOVSKY_HALF 4
+#define TEX_MINKOVSKY_FOUR 5
+#define TEX_MINKOVSKY 6
+
+/* imaflag */
+#define TEX_INTERPOL 1
+#define TEX_USEALPHA 2
+#define TEX_MIPMAP 4
+#define TEX_IMAROT 16
+#define TEX_CALCALPHA 32
+#define TEX_NORMALMAP 2048
+#define TEX_GAUSS_MIP 4096
+
+/* imaflag unused, only for version check */
+#define TEX_FIELDS_ 8
+#define TEX_ANIMCYCLIC_ 64
+#define TEX_ANIM5_ 128
+#define TEX_ANTIALI_ 256
+#define TEX_ANTISCALE_ 512
+#define TEX_STD_FIELD_ 1024
+
+/* flag */
+#define TEX_COLORBAND 1
+#define TEX_FLIPBLEND 2
+#define TEX_NEGALPHA 4
+#define TEX_CHECKER_ODD 8
+#define TEX_CHECKER_EVEN 16
+#define TEX_PRV_ALPHA 32
+#define TEX_PRV_NOR 64
+#define TEX_REPEAT_XMIR 128
+#define TEX_REPEAT_YMIR 256
+#define TEX_FLAG_MASK ( TEX_COLORBAND | TEX_FLIPBLEND | TEX_NEGALPHA | TEX_CHECKER_ODD | TEX_CHECKER_EVEN | TEX_PRV_ALPHA | TEX_PRV_NOR | TEX_REPEAT_XMIR | TEX_REPEAT_YMIR )
+
+/* extend (starts with 1 because of backward comp.) */
+#define TEX_EXTEND 1
+#define TEX_CLIP 2
+#define TEX_REPEAT 3
+#define TEX_CLIPCUBE 4
+#define TEX_CHECKER 5
+
+/* noisetype */
+#define TEX_NOISESOFT 0
+#define TEX_NOISEPERL 1
+
+/* tex->noisebasis2 in texture.c - wood waveforms */
+#define TEX_SIN 0
+#define TEX_SAW 1
+#define TEX_TRI 2
+
+/* tex->stype in texture.c - wood types */
+#define TEX_BAND 0
+#define TEX_RING 1
+#define TEX_BANDNOISE 2
+#define TEX_RINGNOISE 3
+
+/* tex->stype in texture.c - cloud types */
+#define TEX_DEFAULT 0
+#define TEX_COLOR 1
+
+/* tex->stype in texture.c - marble types */
+#define TEX_SOFT 0
+#define TEX_SHARP 1
+#define TEX_SHARPER 2
+
+/* tex->stype in texture.c - blend types */
+#define TEX_LIN 0
+#define TEX_QUAD 1
+#define TEX_EASE 2
+#define TEX_DIAG 3
+#define TEX_SPHERE 4
+#define TEX_HALO 5
+#define TEX_RAD 6
+
+/* tex->stype in texture.c - stucci types */
+#define TEX_PLASTIC 0
+#define TEX_WALLIN 1
+#define TEX_WALLOUT 2
+
+/* tex->stype in texture.c - voronoi types */
+#define TEX_INTENSITY 0
+#define TEX_COL1 1
+#define TEX_COL2 2
+#define TEX_COL3 3
+
+/* wrap */
+#define MTEX_FLAT 0
+#define MTEX_CUBE 1
+#define MTEX_TUBE 2
+#define MTEX_SPHERE 3
+
+/* return value */
+#define TEX_INT 0
+#define TEX_RGB 1
+#define TEX_NOR 2
+
+/* **************** MTEX ********************* */
+
+/* proj */
+#define PROJ_N 0
+#define PROJ_X 1
+#define PROJ_Y 2
+#define PROJ_Z 3
+
+/* texflag */
+#define MTEX_RGBTOINT 1
+#define MTEX_STENCIL 2
+#define MTEX_NEGATIVE 4
+#define MTEX_ALPHAMIX 8
+#define MTEX_VIEWSPACE 16
+
+/* blendtype */
+#define MTEX_BLEND 0
+#define MTEX_MUL 1
+#define MTEX_ADD 2
+#define MTEX_SUB 3
+#define MTEX_DIV 4
+#define MTEX_DARK 5
+#define MTEX_DIFF 6
+#define MTEX_LIGHT 7
+#define MTEX_SCREEN 8
+#define MTEX_OVERLAY 9
+
+/* **************** EnvMap ********************* */
+
+/* type */
+#define ENV_CUBE 0
+#define ENV_PLANE 1
+#define ENV_SPHERE 2
+
+/* stype */
+#define ENV_STATIC 0
+#define ENV_ANIM 1
+#define ENV_LOAD 2
+
+/* ok */
+#define ENV_NORMAL 1
+#define ENV_OSA 2
+
+#endif
+
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
new file mode 100644
index 00000000000..47c00813913
--- /dev/null
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -0,0 +1,288 @@
+/**
+ * blenkernel/DNA_userdef_types.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef DNA_USERDEF_TYPES_H
+#define DNA_USERDEF_TYPES_H
+
+#include "DNA_listBase.h"
+#include "DNA_texture_types.h"
+
+/* themes; defines in BIF_resource.h */
+struct ColorBand;
+
+// global, button colors
+
+typedef struct ThemeUI {
+ char outline[4];
+ char neutral[4];
+ char action[4];
+ char setting[4];
+ char setting1[4];
+ char setting2[4];
+ char num[4];
+ char textfield[4];
+ char textfield_hi[4];
+ char popup[4];
+ char text[4];
+ char text_hi[4];
+ char menu_back[4];
+ char menu_item[4];
+ char menu_hilite[4];
+ char menu_text[4];
+ char menu_text_hi[4];
+
+ char but_drawtype;
+ char pad[3];
+ char iconfile[80]; // FILE_MAXFILE length
+
+} ThemeUI;
+
+// try to put them all in one, if needed a special struct can be created as well
+// for example later on, when we introduce wire colors for ob types or so...
+typedef struct ThemeSpace {
+ char back[4];
+ char text[4];
+ char text_hi[4];
+ char header[4];
+ char panel[4];
+
+ char shade1[4];
+ char shade2[4];
+
+ char hilite[4];
+ char grid[4];
+
+ char wire[4], select[4];
+ char lamp[4];
+ char active[4], group[4], group_active[4], transform[4];
+ char vertex[4], vertex_select[4];
+ char edge[4], edge_select[4];
+ char edge_seam[4], edge_sharp[4], edge_facesel[4];
+ char face[4], face_select[4]; // solid faces
+ char face_dot[4]; // selected color
+ char normal[4];
+ char bone_solid[4], bone_pose[4];
+ char strip[4], strip_select[4];
+
+ char vertex_size, facedot_size;
+ char bpad[2];
+
+ char syntaxl[4], syntaxn[4], syntaxb[4]; // syntax for textwindow and nodes
+ char syntaxv[4], syntaxc[4];
+
+ char movie[4], image[4], scene[4], audio[4]; // for sequence editor
+ char effect[4], plugin[4], transition[4], meta[4];
+ char editmesh_active[4];
+
+} ThemeSpace;
+
+
+typedef struct bTheme {
+ struct bTheme *next, *prev;
+ char name[32];
+
+ ThemeUI tui;
+
+ ThemeSpace tbuts;
+ ThemeSpace tv3d;
+ ThemeSpace tfile;
+ ThemeSpace tipo;
+ ThemeSpace tinfo;
+ ThemeSpace tsnd;
+ ThemeSpace tact;
+ ThemeSpace tnla;
+ ThemeSpace tseq;
+ ThemeSpace tima;
+ ThemeSpace timasel;
+ ThemeSpace text;
+ ThemeSpace toops;
+ ThemeSpace ttime;
+ ThemeSpace tnode;
+
+ unsigned char bpad[4], bpad1[4];
+
+} bTheme;
+
+typedef struct SolidLight {
+ int flag, pad;
+ float col[4], spec[4], vec[4];
+} SolidLight;
+
+typedef struct UserDef {
+ int flag, dupflag;
+ int savetime;
+ char tempdir[160]; // FILE_MAXDIR length
+ char fontdir[160];
+ char renderdir[160];
+ char textudir[160];
+ char plugtexdir[160];
+ char plugseqdir[160];
+ char pythondir[160];
+ char sounddir[160];
+ /* yafray: temporary xml export directory */
+ char yfexportdir[160];
+ short versions, vrmlflag; // tmp for export, will be replaced by strubi
+ int gameflags;
+ int wheellinescroll;
+ int uiflag, language;
+ short userpref, viewzoom;
+ short console_buffer; //console vars here for tuhopuu compat, --phase
+ short console_out;
+ int mixbufsize;
+ int fontsize;
+ short encoding;
+ short transopts;
+ short menuthreshold1, menuthreshold2;
+ char fontname[256]; // FILE_MAXDIR+FILE length
+ struct ListBase themes;
+ short undosteps;
+ short curssize;
+ short tb_leftmouse, tb_rightmouse;
+ struct SolidLight light[3];
+ short tw_hotspot, tw_flag, tw_handlesize, tw_size;
+ int textimeout, texcollectrate;
+ int memcachelimit;
+ int prefetchframes;
+ short frameserverport;
+ short pad_rot_angle; /*control the rotation step of the view when PAD2,PAD4,PAD6&PAD8 is use*/
+ short obcenter_dia;
+ short rvisize; /* rotating view icon size */
+ short rvibright; /* rotating view icon brightness */
+ short recent_files; /* maximum number of recently used files to remember */
+ short smooth_viewtx; /* miliseconds to spend spinning the view */
+ short glreslimit;
+ char versemaster[160];
+ char verseuser[160];
+ float glalphaclip, pad;
+
+ struct ColorBand coba_weight; /* from texture.h */
+} UserDef;
+
+extern UserDef U; /* from usiblender.c !!!! */
+
+/* ***************** USERDEF ****************** */
+
+/* flag */
+#define USER_AUTOSAVE (1 << 0)
+#define USER_AUTOGRABGRID (1 << 1)
+#define USER_AUTOROTGRID (1 << 2)
+#define USER_AUTOSIZEGRID (1 << 3)
+#define USER_SCENEGLOBAL (1 << 4)
+#define USER_TRACKBALL (1 << 5)
+#define USER_DUPLILINK (1 << 6)
+#define USER_FSCOLLUM (1 << 7)
+#define USER_MAT_ON_OB (1 << 8)
+#define USER_NO_CAPSLOCK (1 << 9)
+#define USER_VIEWMOVE (1 << 10)
+#define USER_TOOLTIPS (1 << 11)
+#define USER_TWOBUTTONMOUSE (1 << 12)
+#define USER_NONUMPAD (1 << 13)
+#define USER_LMOUSESELECT (1 << 14)
+#define USER_FILECOMPRESS (1 << 15)
+#define USER_SAVE_PREVIEWS (1 << 16)
+#define USER_CUSTOM_RANGE (1 << 17)
+#define USER_ADD_EDITMODE (1 << 18)
+#define USER_ADD_VIEWALIGNED (1 << 19)
+
+
+/* viewzom */
+#define USER_ZOOM_CONT 0
+#define USER_ZOOM_SCALE 1
+#define USER_ZOOM_DOLLY 2
+
+/* uiflag */
+
+#define USER_KEYINSERTACT (1 << 0)
+#define USER_KEYINSERTOBJ (1 << 1)
+#define USER_WHEELZOOMDIR (1 << 2)
+#define USER_FILTERFILEEXTS (1 << 3)
+#define USER_DRAWVIEWINFO (1 << 4)
+#define USER_PLAINMENUS (1 << 5) // old EVTTOCONSOLE print ghost events, here for tuhopuu compat. --phase
+ // old flag for hide pulldown was here
+#define USER_FLIPFULLSCREEN (1 << 7)
+#define USER_ALLWINCODECS (1 << 8)
+#define USER_MENUOPENAUTO (1 << 9)
+#define USER_PANELPINNED (1 << 10)
+#define USER_AUTOPERSP (1 << 11)
+#define USER_LOCKAROUND (1 << 12)
+#define USER_GLOBALUNDO (1 << 13)
+#define USER_ORBIT_SELECTION (1 << 14)
+#define USER_KEYINSERTAVAI (1 << 15)
+#define USER_HIDE_DOT (1 << 16)
+#define USER_SHOW_ROTVIEWICON (1 << 17)
+#define USER_SHOW_VIEWPORTNAME (1 << 18)
+#define USER_KEYINSERTNEED (1 << 19)
+#define USER_ZOOM_TO_MOUSEPOS (1 << 20)
+
+/* transopts */
+
+#define USER_TR_TOOLTIPS (1 << 0)
+#define USER_TR_BUTTONS (1 << 1)
+#define USER_TR_MENUS (1 << 2)
+#define USER_TR_FILESELECT (1 << 3)
+#define USER_TR_TEXTEDIT (1 << 4)
+#define USER_DOTRANSLATE (1 << 5)
+#define USER_USETEXTUREFONT (1 << 6)
+#define CONVERT_TO_UTF8 (1 << 7)
+
+/* dupflag */
+
+#define USER_DUP_MESH (1 << 0)
+#define USER_DUP_CURVE (1 << 1)
+#define USER_DUP_SURF (1 << 2)
+#define USER_DUP_FONT (1 << 3)
+#define USER_DUP_MBALL (1 << 4)
+#define USER_DUP_LAMP (1 << 5)
+#define USER_DUP_IPO (1 << 6)
+#define USER_DUP_MAT (1 << 7)
+#define USER_DUP_TEX (1 << 8)
+#define USER_DUP_ARM (1 << 9)
+#define USER_DUP_ACT (1 << 10)
+
+/* gameflags */
+
+#define USER_VERTEX_ARRAYS 1
+#define USER_DISABLE_SOUND 2
+#define USER_DISABLE_MIPMAP 4
+
+/* vrml flag */
+
+#define USER_VRML_LAYERS 1
+#define USER_VRML_AUTOSCALE 2
+#define USER_VRML_TWOSIDED 4
+
+/* tw_flag (transform widget) */
+
+
+#endif
diff --git a/source/blender/makesdna/DNA_vec_types.h b/source/blender/makesdna/DNA_vec_types.h
new file mode 100644
index 00000000000..9ae72b1c641
--- /dev/null
+++ b/source/blender/makesdna/DNA_vec_types.h
@@ -0,0 +1,91 @@
+/**
+ * vec_types.h dec 2000 Nzc
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ *
+ */
+
+#ifndef DNA_VEC_TYPES_H
+#define DNA_VEC_TYPES_H
+
+/* types */
+typedef struct vec2s {
+ short x, y;
+} vec2s;
+
+typedef struct vec2i {
+ int x, y;
+} vec2i;
+
+typedef struct vec2f {
+ float x, y;
+} vec2f;
+
+typedef struct vec2d {
+ double x, y;
+} vec2d;
+
+typedef struct vec3i {
+ int x, y, z;
+} vec3i;
+
+typedef struct vec3f {
+ float x, y, z;
+} vec3f;
+
+typedef struct vec3d {
+ double x, y, z;
+} vec3d;
+
+typedef struct vec4i {
+ int x, y, z, w;
+} vec4i;
+
+typedef struct vec4f {
+ float x, y, z, w;
+} vec4f;
+
+typedef struct vec4d {
+ double x, y, z, w;
+} vec4d;
+
+typedef struct rcti {
+ int xmin, xmax;
+ int ymin, ymax;
+} rcti;
+
+typedef struct rctf {
+ float xmin, xmax;
+ float ymin, ymax;
+} rctf;
+
+#endif
+
diff --git a/source/blender/makesdna/DNA_vfont_types.h b/source/blender/makesdna/DNA_vfont_types.h
new file mode 100644
index 00000000000..df9279d6243
--- /dev/null
+++ b/source/blender/makesdna/DNA_vfont_types.h
@@ -0,0 +1,63 @@
+/**
+ * blenlib/DNA_vfont_types.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef DNA_VFONT_TYPES_H
+#define DNA_VFONT_TYPES_H
+
+#include "DNA_ID.h"
+
+struct PackedFile;
+struct VFontData;
+
+typedef struct VFont {
+ ID id;
+
+ char name[256];
+ float scale, pad;
+
+ struct VFontData *data;
+ struct PackedFile * packedfile;
+} VFont;
+
+/* *************** FONT ****************** */
+
+#define FO_CURS 1
+#define FO_CURSUP 2
+#define FO_CURSDOWN 3
+#define FO_DUPLI 4
+#define FO_PAGEUP 8
+#define FO_PAGEDOWN 9
+#define FO_SELCHANGE 10
+
+#endif
+
diff --git a/source/blender/makesdna/DNA_view2d_types.h b/source/blender/makesdna/DNA_view2d_types.h
new file mode 100644
index 00000000000..3ed82ddc793
--- /dev/null
+++ b/source/blender/makesdna/DNA_view2d_types.h
@@ -0,0 +1,67 @@
+/**
+ * blenlib/DNA_view2d_types.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef DNA_VIEW2D_TYPES_H
+#define DNA_VIEW2D_TYPES_H
+
+#include "DNA_vec_types.h"
+
+typedef struct View2D {
+ rctf tot, cur;
+ rcti vert, hor, mask;
+ float min[2], max[2];
+ float minzoom, maxzoom;
+ short scroll, keeptot;
+ short keepaspect, keepzoom;
+ short oldwinx, oldwiny;
+ int flag;
+
+ float cursor[2]; /* only used in the UV view for now*/
+ short around;
+ char pad[6];
+} View2D;
+
+/* v2d->keepzoom */
+#define V2D_KEEPZOOM 0x0001
+#define V2D_LOCKZOOM_X 0x0100
+#define V2D_LOCKZOOM_Y 0x0200
+
+/* event codes for locking function */
+#define V2D_LOCK_COPY 1
+#define V2D_LOCK_REDRAW 2
+
+/* v2d->flag */
+#define V2D_VIEWLOCK 1
+
+#endif
+
diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h
new file mode 100644
index 00000000000..ee75d7b8f0f
--- /dev/null
+++ b/source/blender/makesdna/DNA_view3d_types.h
@@ -0,0 +1,212 @@
+/**
+ * blenlib/DNA_view3d_types.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef DNA_VIEW3D_TYPES_H
+#define DNA_VIEW3D_TYPES_H
+
+struct ViewDepths;
+struct Object;
+struct Image;
+struct Tex;
+struct SpaceLink;
+struct Base;
+struct BoundBox;
+struct RenderInfo;
+struct RetopoViewData;
+
+/* This is needed to not let VC choke on near and far... old
+ * proprietary MS extensions... */
+#ifdef WIN32
+#undef near
+#undef far
+#define near clipsta
+#define far clipend
+#endif
+
+#include "DNA_listBase.h"
+#include "DNA_image_types.h"
+
+/* The near/far thing is a Win EXCEPTION. Thus, leave near/far in the
+ * code, and patch for windows. */
+
+typedef struct BGpic {
+ struct Image *ima;
+ struct ImageUser iuser;
+ float xof, yof, size, zoom, blend;
+ short xim, yim;
+} BGpic;
+
+typedef struct View3D {
+ struct SpaceLink *next, *prev;
+ int spacetype;
+ float blockscale;
+ struct ScrArea *area;
+
+ short blockhandler[8];
+
+ float viewmat[4][4];
+ float viewinv[4][4];
+ float persmat[4][4];
+ float persinv[4][4];
+
+ float winmat1[4][4]; // persp(1) storage, for swap matrices
+ float viewmat1[4][4];
+
+ float viewquat[4], dist, zfac, pad0; /* zfac is initgrabz() result */
+
+ /**
+ * 0 - ortho
+ * 1 - do 3d perspective
+ * 2 - use the camera
+ */
+ short persp;
+ short view;
+
+ struct Object *camera, *ob_centre;
+ struct BGpic *bgpic;
+ struct View3D *localvd;
+ struct RenderInfo *ri;
+ struct RetopoViewData *retopo_view_data;
+ struct ViewDepths *depths;
+
+ char ob_centre_bone[32]; /* optional string for armature bone to define center */
+
+ /**
+ * The drawing mode for the 3d display. Set to OB_WIRE, OB_SOLID,
+ * OB_SHADED or OB_TEXTURED */
+ short drawtype;
+ short localview;
+ int lay, layact;
+ short scenelock, around, camzoom;
+
+ char pivot_last, pad1; /* pivot_last is for rotating around the last edited element */
+
+ float lens, grid, gridview, pixsize, near, far;
+ float camdx, camdy; /* camera view offsets, 1.0 = viewplane moves entire width/height */
+ float ofs[3], cursor[3];
+
+ short gridlines, viewbut;
+ short gridflag;
+ short modeselect, menunr, texnr;
+
+ /* transform widget info */
+ short twtype, twmode, twflag, twdrawflag;
+ float twmat[4][4];
+
+ /* user defined clipping planes */
+ float clip[4][4];
+
+ struct BoundBox *clipbb;
+
+ /* afterdraw, for xray & transparent */
+ struct ListBase afterdraw;
+ /* drawflags, denoting state */
+ short zbuf, transp, xray;
+
+ short flag, flag2;
+
+ short gridsubdiv; /* Number of subdivisions in the grid between each highlighted grid line */
+
+ short pad3;
+
+ short pad2;
+
+ void *properties_storage; /* Nkey panel stores stuff here, not in file */
+
+} View3D;
+
+/* View3D->flag (short) */
+#define V3D_MODE (16+32+64+128+256+512)
+#define V3D_DISPIMAGE 1
+#define V3D_DISPBGPIC 2
+#define V3D_HIDE_HELPLINES 4
+#define V3D_NEEDBACKBUFDRAW 8
+#define V3D_EDITMODE 16
+#define V3D_VERTEXPAINT 32
+#define V3D_FACESELECT 64
+#define V3D_POSEMODE 128
+#define V3D_TEXTUREPAINT 256
+#define V3D_WEIGHTPAINT 512
+#define V3D_ALIGN 1024
+#define V3D_SELECT_OUTLINE 2048
+#define V3D_ZBUF_SELECT 4096
+#define V3D_GLOBAL_STATS 8192
+#define V3D_CLIPPING 16384
+#define V3D_DRAW_CENTERS 32768
+
+
+/* View3d->flag2 (short) */
+#define V3D_OPP_DIRECTION_NAME 1
+#define V3D_FLYMODE 2
+#define V3D_DEPRECATED 4 /* V3D_TRANSFORM_SNAP, moved to a scene setting */
+#define V3D_SOLID_TEX 8
+
+/* View3D->around */
+#define V3D_CENTER 0
+#define V3D_CENTROID 3
+#define V3D_CURSOR 1
+#define V3D_LOCAL 2
+#define V3D_ACTIVE 4
+
+
+/* View3d->persp */
+#define V3D_PERSP_ORTHO 0
+#define V3D_PERSP_DO_3D_PERSP 1
+#define V3D_PERSP_USE_THE_CAMERA 2
+
+/* View3d->gridflag */
+#define V3D_SHOW_FLOOR 1
+#define V3D_SHOW_X 2
+#define V3D_SHOW_Y 4
+#define V3D_SHOW_Z 8
+
+/* View3d->twtype (bits, we can combine them) */
+#define V3D_MANIP_TRANSLATE 1
+#define V3D_MANIP_ROTATE 2
+#define V3D_MANIP_SCALE 4
+
+/* View3d->twmode */
+#define V3D_MANIP_GLOBAL 0
+#define V3D_MANIP_LOCAL 1
+#define V3D_MANIP_NORMAL 2
+#define V3D_MANIP_VIEW 3
+
+/* View3d->twflag */
+ /* USE = user setting, DRAW = based on selection */
+#define V3D_USE_MANIPULATOR 1
+#define V3D_DRAW_MANIPULATOR 2
+#define V3D_CALC_MANIPULATOR 4
+
+
+#endif
+
diff --git a/source/blender/makesdna/DNA_wave_types.h b/source/blender/makesdna/DNA_wave_types.h
new file mode 100644
index 00000000000..f499004fff8
--- /dev/null
+++ b/source/blender/makesdna/DNA_wave_types.h
@@ -0,0 +1,53 @@
+/**
+ * blenlib/DNA_wave_types.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef DNA_WAVE_TYPES_H
+#define DNA_WAVE_TYPES_H
+
+#include "DNA_ID.h"
+
+struct Ipo;
+
+
+/* a Wave has never been implemented... it was meant as a 'free' mathematical
+ deformation object type (ton) */
+
+typedef struct Wave {
+ ID id;
+
+ struct Ipo *ipo;
+
+} Wave;
+
+#endif
+
diff --git a/source/blender/makesdna/DNA_world_types.h b/source/blender/makesdna/DNA_world_types.h
new file mode 100644
index 00000000000..9e5ec4cdb9a
--- /dev/null
+++ b/source/blender/makesdna/DNA_world_types.h
@@ -0,0 +1,181 @@
+/**
+ * blenlib/DNA_world_types.h (mar-2001 nzc)
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifndef DNA_WORLD_TYPES_H
+#define DNA_WORLD_TYPES_H
+
+#include "DNA_ID.h"
+#include "DNA_scriptlink_types.h"
+
+struct Ipo;
+struct MTex;
+
+#ifndef MAX_MTEX
+#define MAX_MTEX 10
+#endif
+
+
+/**
+ * World defines general modeling data such as a background fill,
+ * gravity, color model, stars, etc. It mixes game-data, rendering
+ * data and modeling data. */
+typedef struct World {
+ ID id;
+
+ short colormodel, totex;
+ short texact, mistype;
+
+ /* TODO - hork, zenk and ambk are not used, should remove at some point (Campbell) */
+ float horr, horg, horb, hork;
+ float zenr, zeng, zenb, zenk;
+ float ambr, ambg, ambb, ambk;
+
+ unsigned int fastcol;
+
+ /**
+ * Exposure= mult factor. unused now, but maybe back later. Kept in to be upward compat.
+ * New is exp/range control. linfac & logfac are constants... don't belong in
+ * file, but allocating 8 bytes for temp mem isnt useful either.
+ */
+ float exposure, exp, range;
+ float linfac, logfac;
+
+ /**
+ * Gravitation constant for the game world
+ */
+ float gravity;
+
+ /**
+ * Radius of the activity bubble, in Manhattan length. Objects
+ * outside the box are activity-culled. */
+ float activityBoxRadius;
+
+ short skytype;
+ /**
+ * Some world modes
+ * bit 0: Do mist
+ * bit 1: Do stars
+ * bit 2: (reserved) depth of field
+ * bit 3: (gameengine): Activity culling is enabled.
+ */
+ short mode;
+ int physicsEngine; /* here it's aligned */
+
+ float misi, miststa, mistdist, misthi;
+
+ float starr, starg, starb, stark;
+ float starsize, starmindist;
+ float stardist, starcolnoise;
+
+ /* unused now: DOF */
+ short dofsta, dofend, dofmin, dofmax;
+
+ /* ambient occlusion */
+ float aodist, aodistfac, aoenergy, aobias;
+ short aomode, aosamp, aomix, aocolor;
+ float ao_adapt_thresh, ao_adapt_speed_fac;
+ float pad2[2];
+ short ao_samp_method;
+ short pad1[3];
+
+ float *aosphere, *aotables;
+
+
+ struct Ipo *ipo;
+ struct MTex *mtex[10];
+
+ /* previews */
+ struct PreviewImage *preview;
+
+ ScriptLink scriptlink;
+
+} World;
+
+/* **************** WORLD ********************* */
+
+/* skytype */
+#define WO_SKYBLEND 1
+#define WO_SKYREAL 2
+#define WO_SKYPAPER 4
+/* while render: */
+#define WO_SKYTEX 8
+#define WO_ZENUP 16
+
+/* mode */
+#define WO_MIST 1
+#define WO_STARS 2
+#define WO_DOF 4
+#define WO_ACTIVITY_CULLING 8
+#define WO_AMB_OCC 16
+
+/* aomix */
+#define WO_AOADD 0
+#define WO_AOSUB 1
+#define WO_AOADDSUB 2
+
+/* ao_samp_method - methods for sampling the AO hemi */
+#define WO_AOSAMP_CONSTANT 0
+#define WO_AOSAMP_HALTON 1
+#define WO_AOSAMP_HAMMERSLEY 2
+
+/* aomode (use distances & random sampling modes) */
+#define WO_AODIST 1
+#define WO_AORNDSMP 2
+
+/* aocolor */
+#define WO_AOPLAIN 0
+#define WO_AOSKYCOL 1
+#define WO_AOSKYTEX 2
+
+/* texco (also in DNA_material_types.h) */
+#define TEXCO_ANGMAP 64
+#define TEXCO_H_SPHEREMAP 256
+#define TEXCO_H_TUBEMAP 1024
+
+/* mapto */
+#define WOMAP_BLEND 1
+#define WOMAP_HORIZ 2
+#define WOMAP_ZENUP 4
+#define WOMAP_ZENDOWN 8
+#define WOMAP_MIST 16
+
+/* physicsEngine */
+#define WOPHY_NONE 0
+#define WOPHY_ENJI 1
+#define WOPHY_SUMO 2
+#define WOPHY_DYNAMO 3
+#define WOPHY_ODE 4
+#define WOPHY_BULLET 5
+
+#endif
+
diff --git a/source/blender/makesdna/Makefile b/source/blender/makesdna/Makefile
new file mode 100644
index 00000000000..f8274102b8c
--- /dev/null
+++ b/source/blender/makesdna/Makefile
@@ -0,0 +1,42 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+#
+# This module does not build normal .o's, but a DNA.c file, to be
+# compiled with the rest of the sources. To speed things up a little,
+# the compilation is done here.
+#
+# Bounces make to subdirectories.
+
+SOURCEDIR = source/blender/makesdna
+DIRS = intern
+
+include nan_subdirs.mk
diff --git a/source/blender/makesdna/SConscript b/source/blender/makesdna/SConscript
new file mode 100644
index 00000000000..d67be4955c4
--- /dev/null
+++ b/source/blender/makesdna/SConscript
@@ -0,0 +1,11 @@
+#!/usr/bin/python
+Import ('env')
+
+objs = []
+
+o = SConscript('intern/SConscript')
+objs.append (o)
+
+incs = '#/intern/guardedalloc'
+
+env.BlenderLib ( 'bf_dna', objs, Split(incs), [], libtype=['common','player'], priority = [10, 215] )
diff --git a/source/blender/makesdna/intern/CMakeLists.txt b/source/blender/makesdna/intern/CMakeLists.txt
new file mode 100644
index 00000000000..58aa4b3cd21
--- /dev/null
+++ b/source/blender/makesdna/intern/CMakeLists.txt
@@ -0,0 +1,37 @@
+# $Id$
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2006, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Jacques Beaurain.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+
+SET(SRC makesdna.c ../../../../intern/guardedalloc/intern/mallocn.c)
+
+INCLUDE_DIRECTORIES(../../../../intern/guardedalloc ..)
+
+FILE(GLOB INC_FILES ../*.h)
+ADD_EXECUTABLE(makesdna ${SRC} ${INC_FILES})
+
+MESSAGE(STATUS "Configuring makesdna")
diff --git a/source/blender/makesdna/intern/Makefile b/source/blender/makesdna/intern/Makefile
new file mode 100644
index 00000000000..bd498961e7a
--- /dev/null
+++ b/source/blender/makesdna/intern/Makefile
@@ -0,0 +1,86 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+#
+
+DIR = $(OCGDIR)/blender/makesdna
+CSRCS = $(wildcard *.c)
+
+ALLTARGETS = $(OBJS) $(DIR)/$(DEBUG_DIR)makesdna $(DIR)/$(SHARED_DIR)$(DEBUG_DIR)DNA.o
+
+include nan_compile.mk
+
+CFLAGS += $(LEVEL_1_C_WARNINGS)
+
+CPPFLAGS += -I$(OPENGL_HEADERS)
+CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
+CPPFLAGS += -I../../blenlib
+CPPFLAGS += -I..
+
+ifeq ($(OS),windows)
+ # Windows needs these extra libs because of winstuff... It is not
+ # _really_ needed, but it is the easiest fix for now. If you have
+ # some spare time, try to trace down the exact dep. Then again, you
+ # could also spend that time making the sdna system more robust.
+ ifneq ($(FREE_WINDOWS),true)
+ WINLIBS = kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib
+ WINLIBS += advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib
+ WINLIBS += winmm.lib opengl32.lib glu32.lib largeint.lib
+ WINLIBS += /link /nodefaultlib:libc
+ else
+ LDFLAGS += -mwindows -mno-cygwin
+ endif
+endif
+
+clean::
+ @$(RM) $(DIR)/makesdna* $(DIR)/DNA.c
+ @$(RM) $(DIR)/debug/makesdna* $(DIR)/debug/DNA.c
+
+# TODO include right .mk for ldflags
+
+# A small note: we do not use the debug version of the alloc lib. That
+# is done quite intentionally. If there is a bug in that lib, it needs
+# to be fixed by the module maintainer.
+$(DIR)/$(DEBUG_DIR)makesdna: $(OBJS) $(OCGDIR)/blender/blenlib/$(DEBUG_DIR)libblenlib.a
+ $(CC) $(LDFLAGS) -o $@ $(OBJS) \
+ $(NAN_GUARDEDALLOC)/lib/libguardedalloc.a $(WINLIBS)
+
+$(DIR)/$(DEBUG_DIR)DNA.c: $(DIR)/$(DEBUG_DIR)makesdna
+ ifeq ($(OS),windows)
+ $(SRCHOME)/tools/cygwin/cl_wrapper.pl - $(DIR)/$(DEBUG_DIR)makesdna \
+ $(DIR)/$(DEBUG_DIR)DNA.c
+ else
+ $(DIR)/$(DEBUG_DIR)makesdna $(DIR)/$(DEBUG_DIR)DNA.c
+ endif
+
+$(DIR)/$(SHARED_DIR)$(DEBUG_DIR)DNA.o: $(DIR)/$(DEBUG_DIR)DNA.c
+ $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@
+
diff --git a/source/blender/makesdna/intern/SConscript b/source/blender/makesdna/intern/SConscript
new file mode 100644
index 00000000000..fe712afbeeb
--- /dev/null
+++ b/source/blender/makesdna/intern/SConscript
@@ -0,0 +1,41 @@
+#!/usr/bin/python
+import sys
+import os
+
+Import ('env')
+cflags = ''
+defines = []
+root_build_dir=env['BF_BUILDDIR']
+
+source_files = ['makesdna.c']
+
+makesdna_tool = env.Copy()
+dna = env.Copy()
+makesdna_tool.Append(CCFLAGS = '-DBASE_HEADER="\\"source/blender/makesdna/\\"" ')
+
+makesdna_tool.Append (CPPPATH = ['#/intern/guardedalloc',
+ '../../makesdna'])
+
+if env['OURPLATFORM'] == 'linuxcross':
+ makesdna_tool.Replace(CC='gcc')
+ makesdna_tool.Replace(AR='ar')
+ makesdna_tool.Replace(LINK='gcc')
+
+if sys.platform != 'cygwin':
+ makesdna_tool.Append (CCFLAGS = cflags)
+makesdna_tool.Append (CPPDEFINES = defines)
+makesdna_tool.Append (LIBPATH = '#'+root_build_dir+'/lib')
+
+if env['OURPLATFORM'] == 'linux2' and root_build_dir[0]==os.sep:
+ makesdna = makesdna_tool.Program (target = root_build_dir+'/makesdna', source = source_files, LIBS=['bf_guardedalloc'])
+else:
+ makesdna = makesdna_tool.Program (target = '#'+root_build_dir+'/makesdna', source = source_files, LIBS=['bf_guardedalloc'])
+
+dna_dict = dna.Dictionary()
+dna.Depends ('dna.c', makesdna)
+if env['OURPLATFORM'] != 'linuxcross':
+ dna.Command ('dna.c', '', root_build_dir+os.sep+"makesdna $TARGET")
+else:
+ dna.Command ('dna.c', '', root_build_dir+os.sep+"makesdna.exe $TARGET")
+obj = 'intern/dna.c'
+Return ('obj')
diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c
new file mode 100644
index 00000000000..af41380d5f8
--- /dev/null
+++ b/source/blender/makesdna/intern/makesdna.c
@@ -0,0 +1,1149 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * Struct muncher for making SDNA
+ *
+ * Originally by Ton, some mods by Frank, and some cleaning and
+ * extension by Nzc.
+ *
+ * Makesdna creates a .c file with a long string of numbers that
+ * encode the Blender file format. It is fast, because it is basically
+ * a binary dump. There are some details to mind when reconstructing
+ * the file (endianness and byte-alignment).
+ *
+ * This little program scans all structs that need to be serialized,
+ * and determined the names and types of all members. It calculates
+ * how much memory (on disk or in ram) is needed to store that struct,
+ * and the offsets for reaching a particular one.
+ *
+ * There is a facility to get verbose output from sdna. Search for
+ * debugSDNA. This int can be set to 0 (no output) to some int. Higher
+ * numbers give more output.
+ * */
+
+#define DNA_VERSION_DATE "$Id$"
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "MEM_guardedalloc.h"
+#include "DNA_sdna_types.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define SDNA_MAX_FILENAME_LENGTH 255
+
+
+/* Included the path relative from /source/blender/ here, so we can move */
+/* headers around with more freedom. */
+char *includefiles[] = {
+
+ // if you add files here, please add them at the end
+ // of makesdna.c (this file) as well
+
+ "DNA_listBase.h",
+ "DNA_vec_types.h",
+ "DNA_ID.h",
+ "DNA_ipo_types.h",
+ "DNA_key_types.h",
+ "DNA_scriptlink_types.h",
+ "DNA_text_types.h",
+ "DNA_packedFile_types.h",
+ "DNA_camera_types.h",
+ "DNA_image_types.h",
+ "DNA_texture_types.h",
+ "DNA_lamp_types.h",
+ "DNA_wave_types.h",
+ "DNA_material_types.h",
+ "DNA_vfont_types.h",
+ // if you add files here, please add them at the end
+ // of makesdna.c (this file) as well
+ "DNA_meta_types.h",
+ "DNA_curve_types.h",
+ "DNA_mesh_types.h",
+ "DNA_meshdata_types.h",
+ "DNA_modifier_types.h",
+ "DNA_lattice_types.h",
+ "DNA_object_types.h",
+ "DNA_object_force.h",
+ "DNA_object_fluidsim.h",
+ "DNA_world_types.h",
+ "DNA_radio_types.h",
+ "DNA_scene_types.h",
+ "DNA_view3d_types.h",
+ "DNA_view2d_types.h",
+ "DNA_space_types.h",
+ "DNA_userdef_types.h",
+ "DNA_screen_types.h",
+ "DNA_sdna_types.h",
+ // if you add files here, please add them at the end
+ // of makesdna.c (this file) as well
+ "DNA_fileglobal_types.h",
+ "DNA_sequence_types.h",
+ "DNA_effect_types.h",
+ "DNA_oops_types.h",
+ "DNA_property_types.h",
+ "DNA_sensor_types.h",
+ "DNA_controller_types.h",
+ "DNA_actuator_types.h",
+ "DNA_sound_types.h",
+ "DNA_group_types.h",
+ "DNA_armature_types.h",
+ "DNA_action_types.h",
+ "DNA_constraint_types.h",
+ "DNA_nla_types.h",
+ "DNA_node_types.h",
+ "DNA_color_types.h",
+ "DNA_brush_types.h",
+ "DNA_customdata_types.h",
+ // if you add files here, please add them at the end
+ // of makesdna.c (this file) as well
+
+ // empty string to indicate end of includefiles
+ ""
+};
+
+int maxdata= 500000, maxnr= 50000;
+int nr_names=0;
+int nr_types=0;
+int nr_structs=0;
+char **names, *namedata; /* at adress names[a] is string a */
+char **types, *typedata; /* at adress types[a] is string a */
+short *typelens; /* at typelens[a] is de length of type a */
+short *alphalens; /* contains sizes as they are calculated on the DEC Alpha (64 bits) */
+short **structs, *structdata; /* at sp= structs[a] is the first adress of a struct definition
+ sp[0] is type number
+ sp[1] is amount of elements
+ sp[2] sp[3] is typenr, namenr (etc) */
+/*
+ * debugSDNA:
+ * - 0 = no output, except errors
+ * - 1 = detail actions
+ * - 2 = full trace, tell which names and types were found
+ * - 4 = full trace, plus all gritty details
+ */
+int debugSDNA = 0;
+int additional_slen_offset;
+
+/* ************************************************************************** */
+/* Functions */
+/* ************************************************************************** */
+
+/**
+ * Add type <str> to struct indexed by <len>, if it was not yet found.
+ */
+int add_type(char *str, int len);
+
+/**
+ * Add variable <str> to
+ */
+int add_name(char *str);
+
+/**
+ * Search whether this structure type was already found, and if not,
+ * add it.
+ */
+short *add_struct(int namecode);
+
+/**
+ * Remove comments from this buffer. Assumes that the buffer refers to
+ * ascii-code text.
+ */
+int preprocess_include(char *maindata, int len);
+
+/**
+ * Scan this file for serializable types.
+ */
+int convert_include(char *filename);
+
+/**
+ * Determine how many bytes are needed for an array.
+ */
+int arraysize(char *astr, int len);
+
+/**
+ * Determine how many bytes are needed for each struct.
+ */
+static int calculate_structlens(int);
+
+/**
+ * Construct the DNA.c file
+ */
+void dna_write(FILE *file, void *pntr, int size);
+
+/**
+ * Report all structures found so far, and print their lenghts.
+ */
+void printStructLenghts(void);
+
+
+
+/* ************************************************************************** */
+/* Implementation */
+/* ************************************************************************** */
+
+/* ************************* MAKEN DNA ********************** */
+
+int add_type(char *str, int len)
+{
+ int nr;
+ char *cp;
+
+ if(str[0]==0) return -1;
+
+ /* search through type array */
+ for(nr=0; nr<nr_types; nr++) {
+ if(strcmp(str, types[nr])==0) {
+ if (len) {
+ typelens[nr]= len;
+ alphalens[nr] = len;
+ }
+ return nr;
+ }
+ }
+
+ /* append new type */
+ if(nr_types==0) cp= typedata;
+ else {
+ cp= types[nr_types-1]+strlen(types[nr_types-1])+1;
+ }
+ strcpy(cp, str);
+ types[nr_types]= cp;
+ typelens[nr_types]= len;
+ alphalens[nr_types]= len;
+
+ if(nr_types>=maxnr) {
+ printf("too many types\n");
+ return nr_types-1;;
+ }
+ nr_types++;
+
+ return nr_types-1;
+}
+
+
+/**
+ *
+ * Because of the weird way of tokenizing, we have to 'cast' function
+ * pointers to ... (*f)(), whatever the original signature. In fact,
+ * we add name and type at the same time... There are two special
+ * cases, unfortunately. These are explicitly checked.
+ *
+ * */
+int add_name(char *str)
+{
+ int nr, i, j, k;
+ char *cp;
+ char buf[255]; /* stupid limit, change it :) */
+ char *name;
+
+ additional_slen_offset = 0;
+
+ if((str[0]==0) /* || (str[1]==0) */) return -1;
+
+ if (str[0] == '(' && str[1] == '*') {
+ if (debugSDNA > 3) printf("\t\t\t\t*** Function pointer found\n");
+ /* functionpointer: transform the type (sometimes) */
+ i = 0;
+ j = 0;
+
+ while (str[i] != ')') {
+ buf[i] = str[i];
+ i++;
+ }
+
+ /* Another number we need is the extra slen offset. This extra
+ * offset is the overshoot after a space. If there is no
+ * space, no overshoot should be calculated. */
+ j = i; /* j at first closing brace */
+
+ if (debugSDNA > 3) printf("first brace after offset %d\n", i);
+
+ j++; /* j beyond closing brace ? */
+ while ((str[j] != 0) && (str[j] != ')' )) {
+ if (debugSDNA > 3) printf("seen %c ( %d) \n", str[j], str[j]);
+ j++;
+ }
+ if (debugSDNA > 3) printf("seen %c ( %d) \n", str[j], str[j]);
+ if (debugSDNA > 3) printf("special after offset %d\n", j);
+
+ if (str[j] == 0 ) {
+ if (debugSDNA > 3) printf("offsetting for space\n");
+ /* get additional offset */
+ k = 0;
+ while (str[j] != ')') {
+ j++;
+ k++;
+ }
+ if (debugSDNA > 3) printf("extra offset %d\n", k);
+ additional_slen_offset = k;
+ } else if (str[j] == ')' ) {
+ if (debugSDNA > 3) printf("offsetting for brace\n");
+ ; /* don't get extra offset */
+ } else {
+ printf("Error during tokening function pointer argument list\n");
+ }
+
+ /*
+ * Put )(void) at the end? Maybe )(). Should check this with
+ * old sdna. Actually, sometimes )(), sometimes )(void...)
+ * Alas.. such is the nature of braindamage :(
+ *
+ * Sorted it out: always do )(), except for headdraw and
+ * windraw, part of ScrArea. This is important, because some
+ * linkers will treat different fp's differently when called
+ * !!! This has to do with interference in byte-alignment and
+ * the way args are pushed on the stack.
+ *
+ * */
+ buf[i] = 0;
+ if (debugSDNA > 3) printf("Name before chomping: %s\n", buf);
+ if ( (strncmp(buf,"(*headdraw", 10) == 0)
+ || (strncmp(buf,"(*windraw", 9) == 0) ) {
+ buf[i] = ')';
+ buf[i+1] = '(';
+ buf[i+2] = 'v';
+ buf[i+3] = 'o';
+ buf[i+4] = 'i';
+ buf[i+5] = 'd';
+ buf[i+6] = ')';
+ buf[i+7] = 0;
+ } else {
+ buf[i] = ')';
+ buf[i+1] = '(';
+ buf[i+2] = ')';
+ buf[i+3] = 0;
+ }
+ /* now precede with buf*/
+ if (debugSDNA > 3) printf("\t\t\t\t\tProposing fp name %s\n", buf);
+ name = buf;
+ } else {
+ /* normal field: old code */
+ name = str;
+ }
+
+ /* search name array */
+ for(nr=0; nr<nr_names; nr++) {
+ if(strcmp(name, names[nr])==0) {
+ return nr;
+ }
+ }
+
+ /* append new type */
+ if(nr_names==0) cp= namedata;
+ else {
+ cp= names[nr_names-1]+strlen(names[nr_names-1])+1;
+ }
+ strcpy(cp, name);
+ names[nr_names]= cp;
+
+ if(nr_names>=maxnr) {
+ printf("too many names\n");
+ return nr_names-1;
+ }
+ nr_names++;
+
+ return nr_names-1;
+}
+
+short *add_struct(int namecode)
+{
+ int len;
+ short *sp;
+
+ if(nr_structs==0) {
+ structs[0]= structdata;
+ }
+ else {
+ sp= structs[nr_structs-1];
+ len= sp[1];
+ structs[nr_structs]= sp+ 2*len+2;
+ }
+
+ sp= structs[nr_structs];
+ sp[0]= namecode;
+
+ if(nr_structs>=maxnr) {
+ printf("too many structs\n");
+ return sp;
+ }
+ nr_structs++;
+
+ return sp;
+}
+
+int preprocess_include(char *maindata, int len)
+{
+ int a, newlen, comment = 0;
+ char *cp, *temp, *md;
+
+ temp= MEM_mallocN(len, "preprocess_include");
+ memcpy(temp, maindata, len);
+
+ // remove all c++ comments
+ /* replace all enters/tabs/etc with spaces */
+ cp= temp;
+ a= len;
+ comment = 0;
+ while(a--) {
+ if(cp[0]=='/' && cp[1]=='/') {
+ comment = 1;
+ } else if (*cp<32) {
+ comment = 0;
+ }
+ if (comment || *cp<32 || *cp>128 ) *cp= 32;
+ cp++;
+ }
+
+
+ /* data from temp copy to maindata, remove comments and double spaces */
+ cp= temp;
+ md= maindata;
+ newlen= 0;
+ comment= 0;
+ a= len;
+ while(a--) {
+
+ if(cp[0]=='/' && cp[1]=='*') {
+ comment= 1;
+ cp[0]=cp[1]= 32;
+ }
+ if(cp[0]=='*' && cp[1]=='/') {
+ comment= 0;
+ cp[0]=cp[1]= 32;
+ }
+
+ /* do not copy when: */
+ if(comment);
+ else if( cp[0]==' ' && cp[1]==' ' );
+ else if( cp[-1]=='*' && cp[0]==' ' ); /* pointers with a space */
+ else {
+ md[0]= cp[0];
+ md++;
+ newlen++;
+ }
+ cp++;
+ }
+
+ MEM_freeN(temp);
+ return newlen;
+}
+
+static void *read_file_data(char *filename, int *len_r)
+{
+#ifdef WIN32
+ FILE *fp= fopen(filename, "rb");
+#else
+ FILE *fp= fopen(filename, "r");
+#endif
+ void *data;
+
+ if (!fp) {
+ *len_r= -1;
+ return NULL;
+ }
+
+ fseek(fp, 0L, SEEK_END);
+ *len_r= ftell(fp);
+ fseek(fp, 0L, SEEK_SET);
+
+ data= MEM_mallocN(*len_r, "read_file_data");
+ if (!data) {
+ *len_r= -1;
+ return NULL;
+ }
+
+ if (fread(data, *len_r, 1, fp)!=1) {
+ *len_r= -1;
+ MEM_freeN(data);
+ return NULL;
+ }
+
+ return data;
+}
+
+int convert_include(char *filename)
+{
+ /* read include file, skip structs with a '#' before it.
+ store all data in temporal arrays.
+ */
+ int filelen, count, overslaan, slen, type, name, strct;
+ short *structpoin, *sp;
+ char *maindata, *mainend, *md, *md1;
+
+ md= maindata= read_file_data(filename, &filelen);
+ if (filelen==-1) {
+ printf("Can't read file %s\n", filename);
+ return 1;
+ }
+
+ filelen= preprocess_include(maindata, filelen);
+ mainend= maindata+filelen-1;
+
+ /* we look for '{' and then back to 'struct' */
+ count= 0;
+ overslaan= 0;
+ while(count<filelen) {
+
+ /* code for skipping a struct: two hashes. (preprocess added a space) */
+ if(md[0]=='#' && md[1]==' ' && md[2]=='#') {
+ overslaan= 1;
+ }
+
+ if(md[0]=='{') {
+ md[0]= 0;
+ if(overslaan) {
+ overslaan= 0;
+ }
+ else {
+ if(md[-1]==' ') md[-1]= 0;
+ md1= md-2;
+ while( *md1!=32) md1--; /* to beginning of word */
+ md1++;
+
+ /* we've got a struct name when... */
+ if( strncmp(md1-7, "struct", 6)==0 ) {
+
+
+ strct= add_type(md1, 0);
+ structpoin= add_struct(strct);
+ sp= structpoin+2;
+
+ if (debugSDNA > 1) printf("\t|\t|-- detected struct %s\n", types[strct]);
+
+ /* first lets make it all nice strings */
+ md1= md+1;
+ while(*md1 != '}') {
+ if(md1>mainend) break;
+
+ if(*md1==',' || *md1==' ') *md1= 0;
+ md1++;
+ }
+
+ /* read types and names until first character that is not '}' */
+ md1= md+1;
+ while( *md1 != '}' ) {
+ if(md1>mainend) break;
+
+ /* skip when it says 'struct' or 'unsigned' */
+ if(*md1) {
+ if( strncmp(md1, "struct", 6)==0 ) md1+= 7;
+ if( strncmp(md1, "unsigned", 6)==0 ) md1+= 9;
+
+ /* we've got a type! */
+ type= add_type(md1, 0);
+
+ if (debugSDNA > 1) printf("\t|\t|\tfound type %s (", md1);
+
+ md1+= strlen(md1);
+
+
+ /* read until ';' */
+ while( *md1 != ';' ) {
+ if(md1>mainend) break;
+
+ if(*md1) {
+ /* We've got a name. slen needs
+ * correction for function
+ * pointers! */
+ slen= (int) strlen(md1);
+ if( md1[slen-1]==';' ) {
+ md1[slen-1]= 0;
+
+
+ name= add_name(md1);
+ slen += additional_slen_offset;
+ sp[0]= type;
+ sp[1]= name;
+
+ if ((debugSDNA>1) && (names[name] != 0 )) printf("%s |", names[name]);
+
+ structpoin[1]++;
+ sp+= 2;
+
+ md1+= slen;
+ break;
+ }
+
+
+ name= add_name(md1);
+ slen += additional_slen_offset;
+
+ sp[0]= type;
+ sp[1]= name;
+ if ((debugSDNA > 1) && (names[name] != 0 )) printf("%s ||", names[name]);
+
+ structpoin[1]++;
+ sp+= 2;
+
+ md1+= slen;
+ }
+ md1++;
+ }
+
+ if (debugSDNA > 1) printf(")\n");
+
+ }
+ md1++;
+ }
+ }
+ }
+ }
+ count++;
+ md++;
+ }
+
+ MEM_freeN(maindata);
+
+ return 0;
+}
+
+int arraysize(char *astr, int len)
+{
+ int a, mul=1;
+ char str[100], *cp=0;
+
+ memcpy(str, astr, len+1);
+
+ for(a=0; a<len; a++) {
+ if( str[a]== '[' ) {
+ cp= &(str[a+1]);
+ }
+ else if( str[a]==']' && cp) {
+ str[a]= 0;
+ mul*= atoi(cp);
+ }
+ }
+
+ return mul;
+}
+
+static int calculate_structlens(int firststruct)
+{
+ int a, b, len, alphalen, unknown= nr_structs, lastunknown, structtype, type, mul, namelen;
+ short *sp, *structpoin;
+ char *cp;
+ int has_pointer, dna_error = 0;
+
+ while(unknown) {
+ lastunknown= unknown;
+ unknown= 0;
+
+ /* check all structs... */
+ for(a=0; a<nr_structs; a++) {
+ structpoin= structs[a];
+ structtype= structpoin[0];
+
+ /* when length is not known... */
+ if(typelens[structtype]==0) {
+
+ sp= structpoin+2;
+ len= 0;
+ alphalen = 0;
+ has_pointer = 0;
+
+ /* check all elements in struct */
+ for(b=0; b<structpoin[1]; b++, sp+=2) {
+ type= sp[0];
+ cp= names[sp[1]];
+
+ namelen= (int) strlen(cp);
+ /* is it a pointer or function pointer? */
+ if(cp[0]=='*' || cp[1]=='*') {
+ has_pointer = 1;
+ /* has the name an extra length? (array) */
+ mul= 1;
+ if( cp[namelen-1]==']') mul= arraysize(cp, namelen);
+
+ /* 4-8 aligned/ */
+ if(sizeof(void *) == 4) {
+ if (len % 4) {
+ printf("Align pointer error in struct: %s %s\n", types[structtype], cp);
+ dna_error = 1;
+ }
+ } else {
+ if (len % 8) {
+ printf("Align pointer error in struct: %s %s\n", types[structtype], cp);
+ dna_error = 1;
+ }
+ }
+
+ if (alphalen % 8) {
+ printf("Align pointer error in struct: %s %s\n", types[structtype],cp);
+ dna_error = 1;
+ }
+
+ len += sizeof(void *) * mul;
+ alphalen += 8 * mul;
+
+ } else if( typelens[type] ) {
+ /* has the name an extra length? (array) */
+ mul= 1;
+ if( cp[namelen-1]==']') mul= arraysize(cp, namelen);
+
+ /* struct alignment */
+ if(type >= firststruct) {
+ if(sizeof(void *)==8 && (len % 8) ) {
+ printf("Align struct error: %s %s\n", types[structtype],cp);
+ dna_error = 1;
+ }
+ }
+
+ /* 2-4 aligned/ */
+ if(typelens[type]>3 && (len % 4) ) {
+ printf("Align 4 error in struct: %s %s (add %d padding bytes)\n", types[structtype], cp, len%4);
+ dna_error = 1;
+ }
+ else if(typelens[type]==2 && (len % 2) ) {
+ printf("Align 2 error in struct: %s %s (add %d padding bytes)\n", types[structtype], cp, len%2);
+ dna_error = 1;
+ }
+
+ len += mul*typelens[type];
+ alphalen += mul * alphalens[type];
+
+ } else {
+ len= 0;
+ alphalen = 0;
+ break;
+ }
+ }
+
+ if (len==0) {
+ unknown++;
+ } else {
+ typelens[structtype]= len;
+ alphalens[structtype]= alphalen;
+ // two ways to detect if a struct contains a pointer:
+ // has_pointer is set or alphalen != len
+ if (has_pointer || alphalen != len) {
+ if (alphalen % 8) {
+ printf("Sizeerror in struct: %s (add %d bytes)\n", types[structtype], alphalen%8);
+ dna_error = 1;
+ }
+ }
+
+ if(len % 4) {
+ printf("Sizeerror in struct: %s (add %d bytes)\n", types[structtype], len%4);
+ dna_error = 1;
+ }
+
+ }
+ }
+ }
+
+ if(unknown==lastunknown) break;
+ }
+
+ if(unknown) {
+ printf("ERROR: still %d structs unknown\n", unknown);
+
+ if (debugSDNA) {
+ printf("*** Known structs : \n");
+
+ for(a=0; a<nr_structs; a++) {
+ structpoin= structs[a];
+ structtype= structpoin[0];
+
+ /* length unknown */
+ if(typelens[structtype]!=0) {
+ printf(" %s\n", types[structtype]);
+ }
+ }
+ }
+
+
+ printf("*** Unknown structs : \n");
+
+ for(a=0; a<nr_structs; a++) {
+ structpoin= structs[a];
+ structtype= structpoin[0];
+
+ /* length unkown yet */
+ if(typelens[structtype]==0) {
+ printf(" %s\n", types[structtype]);
+ }
+ }
+ }
+
+ return(dna_error);
+}
+
+#define MAX_DNA_LINE_LENGTH 20
+
+void dna_write(FILE *file, void *pntr, int size)
+{
+ static int linelength = 0;
+ int i;
+ char *data;
+
+ data = (char *) pntr;
+
+ for (i = 0 ; i < size ; i++)
+ {
+ fprintf(file, "%d,", data[i]);
+ linelength++;
+ if (linelength >= MAX_DNA_LINE_LENGTH) {
+ fprintf(file, "\n");
+ linelength = 0;
+ }
+ }
+}
+
+void printStructLenghts(void)
+{
+ int a, unknown= nr_structs, lastunknown, structtype;
+ short *structpoin;
+ printf("\n\n*** All detected structs:\n");
+
+ while(unknown) {
+ lastunknown= unknown;
+ unknown= 0;
+
+ /* check all structs... */
+ for(a=0; a<nr_structs; a++) {
+ structpoin= structs[a];
+ structtype= structpoin[0];
+ printf("\t%s\t:%d\n", types[structtype], typelens[structtype]);
+ }
+ }
+
+ printf("*** End of list\n");
+
+}
+
+
+int make_structDNA(char *baseDirectory, FILE *file)
+{
+ int len, i;
+ short *sp;
+ /* str contains filenames. Since we now include paths, I stretched */
+ /* it a bit. Hope this is enough :) -nzc- */
+ char str[SDNA_MAX_FILENAME_LENGTH], *cp;
+ int firststruct;
+
+ if (debugSDNA > -1) {
+ fflush(stdout);
+ printf("Running makesdna at debug level %d\n", debugSDNA);
+ printf("\tProgram version: %s\n", DNA_VERSION_DATE);
+ }
+
+ /* the longest known struct is 50k, so we assume 100k is sufficent! */
+ namedata= MEM_callocN(maxdata, "namedata");
+ typedata= MEM_callocN(maxdata, "typedata");
+ structdata= MEM_callocN(maxdata, "structdata");
+
+ /* a maximum of 5000 variables, must be sufficient? */
+ names= MEM_callocN(sizeof(char *)*maxnr, "names");
+ types= MEM_callocN(sizeof(char *)*maxnr, "types");
+ typelens= MEM_callocN(sizeof(short)*maxnr, "typelens");
+ alphalens= MEM_callocN(sizeof(short)*maxnr, "alphalens");
+ structs= MEM_callocN(sizeof(short)*maxnr, "structs");
+
+ /* insertion of all known types */
+ /* watch it: uint is not allowed! use in structs an unsigned int */
+ add_type("char", 1); /* 0 */
+ add_type("uchar", 1); /* 1 */
+ add_type("short", 2); /* 2 */
+ add_type("ushort", 2); /* 3 */
+ add_type("int", 4); /* 4 */
+ add_type("long", 4); /* 5 */ /* should it be 8 on 64 bits? */
+ add_type("ulong", 4); /* 6 */
+ add_type("float", 4); /* 7 */
+ add_type("double", 8); /* 8 */
+ add_type("void", 0); /* 9 */
+
+ // the defines above shouldn't be output in the padding file...
+ firststruct = nr_types;
+
+ /* add all include files defined in the global array */
+ /* Since the internal file+path name buffer has limited length, I do a */
+ /* little test first... */
+ /* Mind the breaking condition here! */
+ if (debugSDNA) printf("\tStart of header scan:\n");
+ for (i = 0; strlen(includefiles[i]); i++) {
+ sprintf(str, "%s%s", baseDirectory, includefiles[i]);
+ if (debugSDNA) printf("\t|-- Converting %s\n", str);
+ if (convert_include(str)) {
+ return (1);
+ }
+ }
+ if (debugSDNA) printf("\tFinished scanning %d headers.\n", i);
+
+ if (calculate_structlens(firststruct)) {
+ // error
+ return(1);
+ }
+
+ /* FOR DEBUG */
+ if (debugSDNA > 1)
+ {
+ int a,b;
+/* short *elem; */
+ short num_types;
+
+ printf("nr_names %d nr_types %d nr_structs %d\n", nr_names, nr_types, nr_structs);
+ for(a=0; a<nr_names; a++) {
+ printf(" %s \n", names[a]);
+ }
+ printf("\n");
+
+ sp= typelens;
+ for(a=0; a<nr_types; a++, sp++) {
+ printf(" %s %d\n", types[a], *sp);
+ }
+ printf("\n");
+
+ for(a=0; a<nr_structs; a++) {
+ sp= structs[a];
+ printf(" struct %s elems: %d size: %d\n", types[sp[0]], sp[1],typelens[sp[0]]);
+ num_types = sp[1];
+ sp+= 2;
+ /* ? num_types was elem? */
+ for(b=0; b< num_types; b++, sp+= 2) {
+ printf(" %s %s\n", types[sp[0]], names[sp[1]]);
+ }
+ }
+ }
+
+ /* file writing */
+
+ if (debugSDNA > -1) printf("Writing file ... ");
+
+ if(nr_names==0 || nr_structs==0);
+ else {
+ strcpy(str, "SDNA");
+ dna_write(file, str, 4);
+
+ /* write names */
+ strcpy(str, "NAME");
+ dna_write(file, str, 4);
+ len= nr_names;
+ dna_write(file, &len, 4);
+
+ /* calculate size of datablock with strings */
+ cp= names[nr_names-1];
+ cp+= strlen(names[nr_names-1]) + 1; /* +1: null-terminator */
+ len= (long) (cp - (char*) names[0]);
+ len= (len+3) & ~3;
+ dna_write(file, names[0], len);
+
+ /* write TYPES */
+ strcpy(str, "TYPE");
+ dna_write(file, str, 4);
+ len= nr_types;
+ dna_write(file, &len, 4);
+
+ /* calculate datablock size */
+ cp= types[nr_types-1];
+ cp+= strlen(types[nr_types-1]) + 1; /* +1: null-terminator */
+ len= (long) (cp - (char*) types[0]);
+ len= (len+3) & ~3;
+
+ dna_write(file, types[0], len);
+
+ /* WRITE TYPELENGTHS */
+ strcpy(str, "TLEN");
+ dna_write(file, str, 4);
+
+ len= 2*nr_types;
+ if(nr_types & 1) len+= 2;
+ dna_write(file, typelens, len);
+
+ /* WRITE STRUCTS */
+ strcpy(str, "STRC");
+ dna_write(file, str, 4);
+ len= nr_structs;
+ dna_write(file, &len, 4);
+
+ /* calc datablock size */
+ sp= structs[nr_structs-1];
+ sp+= 2+ 2*( sp[1] );
+ len= (long) ((char*) sp - (char*) structs[0]);
+ len= (len+3) & ~3;
+
+ dna_write(file, structs[0], len);
+
+ /* a simple dna padding test */
+ if (0) {
+ FILE *fp;
+ int a;
+
+ fp= fopen("padding.c", "w");
+ if(fp==NULL);
+ else {
+
+ // add all include files defined in the global array
+ for (i = 0; strlen(includefiles[i]); i++) {
+ fprintf(fp, "#include \"%s%s\"\n", baseDirectory, includefiles[i]);
+ }
+
+ fprintf(fp, "main(){\n");
+ sp = typelens;
+ sp += firststruct;
+ for(a=firststruct; a<nr_types; a++, sp++) {
+ if(*sp) {
+ fprintf(fp, "\tif(sizeof(struct %s) - %d) printf(\"ALIGN ERROR:", types[a], *sp);
+ fprintf(fp, "%%d %s %d ", types[a], *sp);
+ fprintf(fp, "\\n\", sizeof(struct %s) - %d);\n", types[a], *sp);
+ }
+ }
+ fprintf(fp, "}\n");
+ fclose(fp);
+ }
+ }
+ /* end end padding test */
+ }
+
+
+ MEM_freeN(namedata);
+ MEM_freeN(typedata);
+ MEM_freeN(structdata);
+ MEM_freeN(names);
+ MEM_freeN(types);
+ MEM_freeN(typelens);
+ MEM_freeN(structs);
+
+ if (debugSDNA > -1) printf("done.\n");
+
+ return(0);
+}
+
+/* ************************* END MAKE DNA ********************** */
+
+static void make_bad_file(char *file)
+{
+ FILE *fp= fopen(file, "w");
+ fprintf(fp, "ERROR! Cannot make correct DNA.c file, STUPID!\n");
+ fclose(fp);
+}
+
+#ifndef BASE_HEADER
+#define BASE_HEADER "../"
+#endif
+
+int main(int argc, char ** argv)
+{
+ FILE *file;
+ int return_status = 0;
+
+ if (argc!=2 && argc!=3) {
+ printf("Usage: %s outfile.c [base directory]\n", argv[0]);
+ return_status = 1;
+ } else {
+ file = fopen(argv[1], "w");
+ if (!file) {
+ printf ("Unable to open file: %s\n", argv[1]);
+ return_status = 1;
+ } else {
+ char baseDirectory[256];
+
+ if (argc==3) {
+ strcpy(baseDirectory, argv[2]);
+ } else {
+ strcpy(baseDirectory, BASE_HEADER);
+ }
+
+ fprintf (file, "unsigned char DNAstr[]= {\n");
+ if (make_structDNA(baseDirectory, file)) {
+ // error
+ fclose(file);
+ make_bad_file(argv[1]);
+ return_status = 1;
+ } else {
+ fprintf(file, "};\n");
+ fprintf(file, "int DNAlen= sizeof(DNAstr);\n");
+
+ fclose(file);
+ }
+ }
+ }
+
+
+ return(return_status);
+}
+
+// include files for automatic dependancies
+#include "DNA_listBase.h"
+#include "DNA_vec_types.h"
+#include "DNA_ID.h"
+#include "DNA_ipo_types.h"
+#include "DNA_key_types.h"
+#include "DNA_scriptlink_types.h"
+#include "DNA_text_types.h"
+#include "DNA_packedFile_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_image_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_wave_types.h"
+#include "DNA_material_types.h"
+#include "DNA_vfont_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_object_types.h"
+#include "DNA_object_force.h"
+#include "DNA_object_fluidsim.h"
+#include "DNA_world_types.h"
+#include "DNA_radio_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_view2d_types.h"
+#include "DNA_space_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_sdna_types.h"
+#include "DNA_fileglobal_types.h"
+#include "DNA_sequence_types.h"
+#include "DNA_effect_types.h"
+#include "DNA_oops_types.h"
+#include "DNA_property_types.h"
+#include "DNA_sensor_types.h"
+#include "DNA_controller_types.h"
+#include "DNA_actuator_types.h"
+#include "DNA_sound_types.h"
+#include "DNA_group_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_action_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_nla_types.h"
+#include "DNA_node_types.h"
+#include "DNA_color_types.h"
+#include "DNA_brush_types.h"
+#include "DNA_customdata_types.h"
+/* end of list */
diff --git a/source/blender/nodes/CMP_node.h b/source/blender/nodes/CMP_node.h
new file mode 100644
index 00000000000..4b7e721ca57
--- /dev/null
+++ b/source/blender/nodes/CMP_node.h
@@ -0,0 +1,105 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef CMP_NODE_H
+#define CMP_NODE_H
+
+#include "BKE_node.h"
+
+
+/* ****************** types array for all composite nodes ****************** */
+
+extern bNodeType cmp_node_rlayers;
+extern bNodeType cmp_node_image;
+extern bNodeType cmp_node_texture;
+extern bNodeType cmp_node_value;
+extern bNodeType cmp_node_rgb;
+extern bNodeType cmp_node_curve_time;
+
+extern bNodeType cmp_node_composite;
+extern bNodeType cmp_node_viewer;
+extern bNodeType cmp_node_splitviewer;
+extern bNodeType cmp_node_output_file;
+
+extern bNodeType cmp_node_curve_rgb;
+extern bNodeType cmp_node_mix_rgb;
+extern bNodeType cmp_node_hue_sat;
+extern bNodeType cmp_node_brightcontrast;
+extern bNodeType cmp_node_gamma;
+extern bNodeType cmp_node_invert;
+extern bNodeType cmp_node_alphaover;
+extern bNodeType cmp_node_zcombine;
+
+extern bNodeType cmp_node_normal;
+extern bNodeType cmp_node_curve_vec;
+extern bNodeType cmp_node_map_value;
+extern bNodeType cmp_node_normalize;
+
+extern bNodeType cmp_node_filter;
+extern bNodeType cmp_node_blur;
+extern bNodeType cmp_node_vecblur;
+extern bNodeType cmp_node_dilateerode;
+extern bNodeType cmp_node_defocus;
+
+extern bNodeType cmp_node_valtorgb;
+extern bNodeType cmp_node_rgbtobw;
+extern bNodeType cmp_node_setalpha;
+extern bNodeType cmp_node_idmask;
+extern bNodeType cmp_node_math;
+extern bNodeType cmp_node_seprgba;
+extern bNodeType cmp_node_combrgba;
+extern bNodeType cmp_node_sephsva;
+extern bNodeType cmp_node_combhsva;
+extern bNodeType cmp_node_sepyuva;
+extern bNodeType cmp_node_combyuva;
+extern bNodeType cmp_node_sepycca;
+extern bNodeType cmp_node_combycca;
+
+extern bNodeType cmp_node_diff_matte;
+extern bNodeType cmp_node_chroma;
+extern bNodeType cmp_node_channel_matte;
+extern bNodeType cmp_node_color_spill;
+extern bNodeType cmp_node_luma_matte;
+
+extern bNodeType cmp_node_translate;
+extern bNodeType cmp_node_rotate;
+extern bNodeType cmp_node_scale;
+extern bNodeType cmp_node_flip;
+extern bNodeType cmp_node_crop;
+extern bNodeType cmp_node_displace;
+extern bNodeType cmp_node_mapuv;
+
+extern bNodeType cmp_node_glare;
+extern bNodeType cmp_node_tonemap;
+extern bNodeType cmp_node_lensdist;
+
+#endif
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
new file mode 100644
index 00000000000..6729d5099f0
--- /dev/null
+++ b/source/blender/nodes/CMakeLists.txt
@@ -0,0 +1,71 @@
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2006, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Jacques Beaurain.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+
+FILE(GLOB SRC intern/*.c intern/CMP_nodes/*.c intern/SHD_nodes/*.c)
+
+SET(INC
+ . ../../../intern/guardedalloc ../include ../blenlib ../makesdna
+ ../python ../render/extern/include ../../../intern/decimation/extern
+ ../imbuf ../avi ../../../intern/elbeem/extern
+ ../../../intern/iksolver/extern ../blenloader ../quicktime
+ ../blenkernel
+ ${SDL_INC}
+ ${ZLIB_INC}
+)
+
+IF(WITH_VERSE)
+ ADD_DEFINITIONS(-DWITH_VERSE)
+ SET(INC ${INC} ${VERSE_INC})
+ENDIF(WITH_VERSE)
+
+IF(WITH_OPENEXR)
+ ADD_DEFINITIONS(-DWITH_OPENEXR)
+ENDIF(WITH_OPENEXR)
+
+IF(WITH_QUICKTIME)
+ SET(INC ${INC} ${QUICKTIME_INC})
+ ADD_DEFINITIONS(-DWITH_QUICKTIME)
+ENDIF(WITH_QUICKTIME)
+
+IF(WITH_FFMPEG)
+ SET(INC ${INC} ${FFMPEG_INC})
+ ADD_DEFINITIONS(-DWITH_FFMPEG)
+ENDIF(WITH_FFMPEG)
+
+ADD_DEFINITIONS(-DWITH_CCGSUBSURF)
+
+BLENDERLIB(bf_nodes "${SRC}" "${INC}")
+
+IF(WITH_VERSE)
+ ADD_DEPENDENCIES(bf_nodes mkprot verse)
+ENDIF(WITH_VERSE)
+
+IF(WITH_INTERNATIONAL)
+ ADD_DEFINITIONS(-DWITH_FREETYPE2)
+ENDIF(WITH_INTERNATIONAL)
+
diff --git a/source/blender/nodes/Makefile b/source/blender/nodes/Makefile
new file mode 100644
index 00000000000..37edf74b3ea
--- /dev/null
+++ b/source/blender/nodes/Makefile
@@ -0,0 +1,37 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+# Bounces make to subdirectories.
+
+SOURCEDIR = source/blender/nodes
+DIRS = intern intern/CMP_nodes intern/SHD_nodes
+
+include nan_subdirs.mk
diff --git a/source/blender/nodes/SConscript b/source/blender/nodes/SConscript
new file mode 100644
index 00000000000..0460848b4a5
--- /dev/null
+++ b/source/blender/nodes/SConscript
@@ -0,0 +1,46 @@
+#!/usr/bin/python
+Import ('env')
+
+sources = env.Glob('intern/*.c')
+sources += env.Glob('intern/CMP_nodes/*.c')
+sources += env.Glob('intern/SHD_nodes/*.c')
+
+incs = '. ./intern '
+incs += '#/intern/guardedalloc ../include ../blenlib ../makesdna'
+incs += ' ../python ../render/extern/include '
+incs += ' ../imbuf ../avi '
+incs += ' ../blenloader ../quicktime'
+incs += ' ../blenkernel ../renderconverter '
+
+
+
+incs += ' ' + env['BF_OPENGL_INC']
+incs += ' ' + env['BF_ZLIB_INC']
+incs += ' ' + env['BF_SDL_INC']
+
+defs = ''
+
+if env['WITH_BF_INTERNATIONAL']:
+ defs += 'WITH_FREETYPE2'
+
+if env['WITH_BF_VERSE']:
+ defs += ' WITH_VERSE'
+ incs += ' ' + env['BF_VERSE_INCLUDE']
+
+if env['WITH_BF_VERSE']:
+ defs += ' WITH_VERSE'
+
+if env['WITH_BF_OPENEXR'] == 1:
+ defs += ' WITH_OPENEXR'
+
+if env['WITH_BF_FFMPEG'] == 1:
+ defs += ' WITH_FFMPEG'
+ incs += ' ' + env['BF_FFMPEG_INC']
+
+if env['WITH_BF_QUICKTIME'] == 1:
+ defs += ' WITH_QUICKTIME'
+ incs += ' ' + env['BF_QUICKTIME_INC']
+
+defs += ' WITH_CCGSUBSURF'
+
+env.BlenderLib ( libname = 'nodes', sources = sources, includes = Split(incs), defines = Split(defs), libtype=['core','player'], priority = [65, 20] )
diff --git a/source/blender/nodes/SHD_node.h b/source/blender/nodes/SHD_node.h
new file mode 100644
index 00000000000..8064a543ca0
--- /dev/null
+++ b/source/blender/nodes/SHD_node.h
@@ -0,0 +1,68 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef SHD_NODE_H
+#define SHD_NODE_H
+
+#include "BKE_node.h"
+
+
+/* the type definitions array */
+/* ****************** types array for all shaders ****************** */
+
+extern bNodeType sh_node_output;
+extern bNodeType sh_node_material;
+extern bNodeType sh_node_camera;
+extern bNodeType sh_node_value;
+extern bNodeType sh_node_rgb;
+extern bNodeType sh_node_mix_rgb;
+extern bNodeType sh_node_valtorgb;
+extern bNodeType sh_node_rgbtobw;
+extern bNodeType sh_node_texture;
+extern bNodeType sh_node_normal;
+extern bNodeType sh_node_geom;
+extern bNodeType sh_node_mapping;
+extern bNodeType sh_node_curve_vec;
+extern bNodeType sh_node_curve_rgb;
+extern bNodeType sh_node_math;
+extern bNodeType sh_node_vect_math;
+extern bNodeType sh_node_squeeze;
+extern bNodeType sh_node_material_ext;
+extern bNodeType sh_node_invert;
+extern bNodeType sh_node_seprgb;
+extern bNodeType sh_node_combrgb;
+extern bNodeType sh_node_hue_sat;
+
+
+#endif
+
+
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_alphaOver.c b/source/blender/nodes/intern/CMP_nodes/CMP_alphaOver.c
new file mode 100644
index 00000000000..f108098750c
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_alphaOver.c
@@ -0,0 +1,128 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../CMP_util.h"
+
+/* **************** ALPHAOVER ******************** */
+static bNodeSocketType cmp_node_alphaover_in[]= {
+ { SOCK_VALUE, 1, "Fac", 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketType cmp_node_alphaover_out[]= {
+ { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void do_alphaover_premul(bNode *node, float *out, float *src, float *over, float *fac)
+{
+
+ if(over[3]<=0.0f) {
+ QUATCOPY(out, src);
+ }
+ else if(*fac==1.0f && over[3]>=1.0f) {
+ QUATCOPY(out, over);
+ }
+ else {
+ float mul= 1.0f - *fac*over[3];
+
+ out[0]= (mul*src[0]) + *fac*over[0];
+ out[1]= (mul*src[1]) + *fac*over[1];
+ out[2]= (mul*src[2]) + *fac*over[2];
+ out[3]= (mul*src[3]) + *fac*over[3];
+ }
+}
+
+/* result will be still premul, but the over part is premulled */
+static void do_alphaover_key(bNode *node, float *out, float *src, float *over, float *fac)
+{
+
+ if(over[3]<=0.0f) {
+ QUATCOPY(out, src);
+ }
+ else if(*fac==1.0f && over[3]>=1.0f) {
+ QUATCOPY(out, over);
+ }
+ else {
+ float premul= fac[0]*over[3];
+ float mul= 1.0f - premul;
+
+ out[0]= (mul*src[0]) + premul*over[0];
+ out[1]= (mul*src[1]) + premul*over[1];
+ out[2]= (mul*src[2]) + premul*over[2];
+ out[3]= (mul*src[3]) + fac[0]*over[3];
+ }
+}
+
+
+static void node_composit_exec_alphaover(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order in: col col */
+ /* stack order out: col */
+ if(out[0]->hasoutput==0)
+ return;
+
+ /* input no image? then only color operation */
+ if(in[1]->data==NULL && in[2]->data==NULL) {
+ do_alphaover_premul(node, out[0]->vec, in[1]->vec, in[2]->vec, in[0]->vec);
+ }
+ else {
+ /* make output size of input image */
+ CompBuf *cbuf= in[1]->data?in[1]->data:in[2]->data;
+ CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */
+
+ if(node->custom1)
+ composit3_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, in[2]->data, in[2]->vec, in[0]->data, in[0]->vec, do_alphaover_key, CB_RGBA, CB_RGBA, CB_VAL);
+ else
+ composit3_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, in[2]->data, in[2]->vec, in[0]->data, in[0]->vec, do_alphaover_premul, CB_RGBA, CB_RGBA, CB_VAL);
+
+ out[0]->data= stackbuf;
+ }
+}
+
+bNodeType cmp_node_alphaover= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_ALPHAOVER,
+ /* name */ "AlphaOver",
+ /* width+range */ 80, 40, 120,
+ /* class+opts */ NODE_CLASS_OP_COLOR, NODE_OPTIONS,
+ /* input sock */ cmp_node_alphaover_in,
+ /* output sock */ cmp_node_alphaover_out,
+ /* storage */ "",
+ /* execfunc */ node_composit_exec_alphaover,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+
+};
+
+
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_blur.c b/source/blender/nodes/intern/CMP_nodes/CMP_blur.c
new file mode 100644
index 00000000000..8ef4af4d219
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_blur.c
@@ -0,0 +1,687 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../CMP_util.h"
+
+/* **************** BLUR ******************** */
+static bNodeSocketType cmp_node_blur_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 1, "Size", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketType cmp_node_blur_out[]= {
+ { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static float *make_gausstab(int filtertype, int rad)
+{
+ float *gausstab, sum, val;
+ int i, n;
+
+ n = 2 * rad + 1;
+
+ gausstab = (float *) MEM_mallocN(n * sizeof(float), "gauss");
+
+ sum = 0.0f;
+ for (i = -rad; i <= rad; i++) {
+ val= RE_filter_value(filtertype, (float)i/(float)rad);
+ sum += val;
+ gausstab[i+rad] = val;
+ }
+
+ sum= 1.0f/sum;
+ for(i=0; i<n; i++)
+ gausstab[i]*= sum;
+
+ return gausstab;
+}
+
+static float *make_bloomtab(int rad)
+{
+ float *bloomtab, val;
+ int i, n;
+
+ n = 2 * rad + 1;
+
+ bloomtab = (float *) MEM_mallocN(n * sizeof(float), "bloom");
+
+ for (i = -rad; i <= rad; i++) {
+ val = pow(1.0 - fabs((float)i)/((float)rad), 4.0);
+ bloomtab[i+rad] = val;
+ }
+
+ return bloomtab;
+}
+
+/* both input images of same type, either 4 or 1 channel */
+static void blur_single_image(bNode *node, CompBuf *new, CompBuf *img, float scale)
+{
+ NodeBlurData *nbd= node->storage;
+ CompBuf *work;
+ register float sum, val;
+ float rval, gval, bval, aval;
+ float *gausstab, *gausstabcent;
+ int rad, imgx= img->x, imgy= img->y;
+ int x, y, pix= img->type;
+ int i, bigstep;
+ float *src, *dest;
+
+ /* helper image */
+ work= alloc_compbuf(imgx, imgy, img->type, 1); /* allocs */
+
+ /* horizontal */
+ rad = scale*(float)nbd->sizex;
+ if(rad>imgx/2)
+ rad= imgx/2;
+ else if(rad<1)
+ rad= 1;
+
+ gausstab= make_gausstab(nbd->filtertype, rad);
+ gausstabcent= gausstab+rad;
+
+ for (y = 0; y < imgy; y++) {
+ float *srcd= img->rect + pix*(y*img->x);
+
+ dest = work->rect + pix*(y * img->x);
+
+ for (x = 0; x < imgx ; x++) {
+ int minr= x-rad<0?-x:-rad;
+ int maxr= x+rad>imgx?imgx-x:rad;
+
+ src= srcd + pix*(x+minr);
+
+ sum= gval = rval= bval= aval= 0.0f;
+ for (i= minr; i < maxr; i++) {
+ val= gausstabcent[i];
+ sum+= val;
+ rval += val * (*src++);
+ if(pix==4) {
+ gval += val * (*src++);
+ bval += val * (*src++);
+ aval += val * (*src++);
+ }
+ }
+ sum= 1.0f/sum;
+ *dest++ = rval*sum;
+ if(pix==4) {
+ *dest++ = gval*sum;
+ *dest++ = bval*sum;
+ *dest++ = aval*sum;
+ }
+ }
+ if(node->exec & NODE_BREAK)
+ break;
+ }
+
+ /* vertical */
+ MEM_freeN(gausstab);
+
+ rad = scale*(float)nbd->sizey;
+ if(rad>imgy/2)
+ rad= imgy/2;
+ else if(rad<1)
+ rad= 1;
+
+ gausstab= make_gausstab(nbd->filtertype, rad);
+ gausstabcent= gausstab+rad;
+
+ bigstep = pix*imgx;
+ for (x = 0; x < imgx; x++) {
+ float *srcd= work->rect + pix*x;
+
+ dest = new->rect + pix*x;
+
+ for (y = 0; y < imgy ; y++) {
+ int minr= y-rad<0?-y:-rad;
+ int maxr= y+rad>imgy?imgy-y:rad;
+
+ src= srcd + bigstep*(y+minr);
+
+ sum= gval = rval= bval= aval= 0.0f;
+ for (i= minr; i < maxr; i++) {
+ val= gausstabcent[i];
+ sum+= val;
+ rval += val * src[0];
+ if(pix==4) {
+ gval += val * src[1];
+ bval += val * src[2];
+ aval += val * src[3];
+ }
+ src += bigstep;
+ }
+ sum= 1.0f/sum;
+ dest[0] = rval*sum;
+ if(pix==4) {
+ dest[1] = gval*sum;
+ dest[2] = bval*sum;
+ dest[3] = aval*sum;
+ }
+ dest+= bigstep;
+ }
+ if(node->exec & NODE_BREAK)
+ break;
+ }
+
+ free_compbuf(work);
+ MEM_freeN(gausstab);
+}
+
+/* reference has to be mapped 0-1, and equal in size */
+static void bloom_with_reference(CompBuf *new, CompBuf *img, CompBuf *ref, float fac, NodeBlurData *nbd)
+{
+ CompBuf *wbuf;
+ register float val;
+ float radxf, radyf;
+ float **maintabs;
+ float *gausstabx, *gausstabcenty;
+ float *gausstaby, *gausstabcentx;
+ int radx, rady, imgx= img->x, imgy= img->y;
+ int x, y;
+ int i, j;
+ float *src, *dest, *wb;
+
+ wbuf= alloc_compbuf(imgx, imgy, CB_VAL, 1);
+
+ /* horizontal */
+ radx = (float)nbd->sizex;
+ if(radx>imgx/2)
+ radx= imgx/2;
+ else if(radx<1)
+ radx= 1;
+
+ /* vertical */
+ rady = (float)nbd->sizey;
+ if(rady>imgy/2)
+ rady= imgy/2;
+ else if(rady<1)
+ rady= 1;
+
+ x= MAX2(radx, rady);
+ maintabs= MEM_mallocN(x*sizeof(void *), "gauss array");
+ for(i= 0; i<x; i++)
+ maintabs[i]= make_bloomtab(i+1);
+
+ /* vars to store before we go */
+// refd= ref->rect;
+ src= img->rect;
+
+ radxf= (float)radx;
+ radyf= (float)rady;
+
+ for (y = 0; y < imgy; y++) {
+ for (x = 0; x < imgx ; x++, src+=4) {//, refd++) {
+
+// int refradx= (int)(refd[0]*radxf);
+// int refrady= (int)(refd[0]*radyf);
+
+ int refradx= (int)(radxf*0.3f*src[3]*(src[0]+src[1]+src[2]));
+ int refrady= (int)(radyf*0.3f*src[3]*(src[0]+src[1]+src[2]));
+
+ if(refradx>radx) refradx= radx;
+ else if(refradx<1) refradx= 1;
+ if(refrady>rady) refrady= rady;
+ else if(refrady<1) refrady= 1;
+
+ if(refradx==1 && refrady==1) {
+ wb= wbuf->rect + ( y*imgx + x);
+ dest= new->rect + 4*( y*imgx + x);
+ wb[0]+= 1.0f;
+ dest[0] += src[0];
+ dest[1] += src[1];
+ dest[2] += src[2];
+ dest[3] += src[3];
+ }
+ else {
+ int minxr= x-refradx<0?-x:-refradx;
+ int maxxr= x+refradx>imgx?imgx-x:refradx;
+ int minyr= y-refrady<0?-y:-refrady;
+ int maxyr= y+refrady>imgy?imgy-y:refrady;
+
+ float *destd= new->rect + 4*( (y + minyr)*imgx + x + minxr);
+ float *wbufd= wbuf->rect + ( (y + minyr)*imgx + x + minxr);
+
+ gausstabx= maintabs[refradx-1];
+ gausstabcentx= gausstabx+refradx;
+ gausstaby= maintabs[refrady-1];
+ gausstabcenty= gausstaby+refrady;
+
+ for (i= minyr; i < maxyr; i++, destd+= 4*imgx, wbufd+= imgx) {
+ dest= destd;
+ wb= wbufd;
+ for (j= minxr; j < maxxr; j++, dest+=4, wb++) {
+
+ val= gausstabcenty[i]*gausstabcentx[j];
+ wb[0]+= val;
+ dest[0] += val * src[0];
+ dest[1] += val * src[1];
+ dest[2] += val * src[2];
+ dest[3] += val * src[3];
+ }
+ }
+ }
+ }
+ }
+
+ x= imgx*imgy;
+ dest= new->rect;
+ wb= wbuf->rect;
+ while(x--) {
+ val= 1.0f/wb[0];
+ dest[0]*= val;
+ dest[1]*= val;
+ dest[2]*= val;
+ dest[3]*= val;
+ wb++;
+ dest+= 4;
+ }
+
+ free_compbuf(wbuf);
+
+ x= MAX2(radx, rady);
+ for(i= 0; i<x; i++)
+ MEM_freeN(maintabs[i]);
+ MEM_freeN(maintabs);
+
+}
+
+#if 0
+static float hexagon_filter(float fi, float fj)
+{
+ fi= fabs(fi);
+ fj= fabs(fj);
+
+ if(fj>0.33f) {
+ fj= (fj-0.33f)/0.66f;
+ if(fi+fj>1.0f)
+ return 0.0f;
+ else
+ return 1.0f;
+ }
+ else return 1.0f;
+}
+#endif
+
+/* uses full filter, no horizontal/vertical optimize possible */
+/* both images same type, either 1 or 4 channels */
+static void bokeh_single_image(bNode *node, CompBuf *new, CompBuf *img, float fac)
+{
+ NodeBlurData *nbd= node->storage;
+ register float val;
+ float radxf, radyf;
+ float *gausstab, *dgauss;
+ int radx, rady, imgx= img->x, imgy= img->y;
+ int x, y, pix= img->type;
+ int i, j, n;
+ float *src= NULL, *dest, *srcd= NULL;
+
+ /* horizontal */
+ radxf = fac*(float)nbd->sizex;
+ if(radxf>imgx/2.0f)
+ radxf= imgx/2.0f;
+ else if(radxf<1.0f)
+ radxf= 1.0f;
+
+ /* vertical */
+ radyf = fac*(float)nbd->sizey;
+ if(radyf>imgy/2.0f)
+ radyf= imgy/2.0f;
+ else if(radyf<1.0f)
+ radyf= 1.0f;
+
+ radx= ceil(radxf);
+ rady= ceil(radyf);
+
+ n = (2*radx+1)*(2*rady+1);
+
+ /* create a full filter image */
+ gausstab= MEM_mallocN(sizeof(float)*n, "filter tab");
+ dgauss= gausstab;
+ val= 0.0f;
+ for(j=-rady; j<=rady; j++) {
+ for(i=-radx; i<=radx; i++, dgauss++) {
+ float fj= (float)j/radyf;
+ float fi= (float)i/radxf;
+ float dist= sqrt(fj*fj + fi*fi);
+
+ //*dgauss= hexagon_filter(fi, fj);
+ *dgauss= RE_filter_value(nbd->filtertype, 2.0f*dist - 1.0f);
+
+ val+= *dgauss;
+ }
+ }
+
+ if(val!=0.0f) {
+ val= 1.0f/val;
+ for(j= n -1; j>=0; j--)
+ gausstab[j]*= val;
+ }
+ else gausstab[4]= 1.0f;
+
+ for (y = -rady+1; y < imgy+rady-1; y++) {
+
+ if(y<=0) srcd= img->rect;
+ else if(y<imgy) srcd+= pix*imgx;
+ else srcd= img->rect + pix*(imgy-1)*imgx;
+
+ for (x = -radx+1; x < imgx+radx-1 ; x++) {
+ int minxr= x-radx<0?-x:-radx;
+ int maxxr= x+radx>=imgx?imgx-x-1:radx;
+ int minyr= y-rady<0?-y:-rady;
+ int maxyr= y+rady>imgy-1?imgy-y-1:rady;
+
+ float *destd= new->rect + pix*( (y + minyr)*imgx + x + minxr);
+ float *dgausd= gausstab + (minyr+rady)*2*radx + minxr+radx;
+
+ if(x<=0) src= srcd;
+ else if(x<imgx) src+= pix;
+ else src= srcd + pix*(imgx-1);
+
+ for (i= minyr; i <=maxyr; i++, destd+= pix*imgx, dgausd+= 2*radx + 1) {
+ dest= destd;
+ dgauss= dgausd;
+ for (j= minxr; j <=maxxr; j++, dest+=pix, dgauss++) {
+ val= *dgauss;
+ if(val!=0.0f) {
+ dest[0] += val * src[0];
+ if(pix>1) {
+ dest[1] += val * src[1];
+ dest[2] += val * src[2];
+ dest[3] += val * src[3];
+ }
+ }
+ }
+ }
+ }
+ if(node->exec & NODE_BREAK)
+ break;
+ }
+
+ MEM_freeN(gausstab);
+}
+
+
+/* reference has to be mapped 0-1, and equal in size */
+static void blur_with_reference(bNode *node, CompBuf *new, CompBuf *img, CompBuf *ref)
+{
+ NodeBlurData *nbd= node->storage;
+ CompBuf *blurbuf, *ref_use;
+ register float sum, val;
+ float rval, gval, bval, aval, radxf, radyf;
+ float **maintabs;
+ float *gausstabx, *gausstabcenty;
+ float *gausstaby, *gausstabcentx;
+ int radx, rady, imgx= img->x, imgy= img->y;
+ int x, y, pix= img->type;
+ int i, j;
+ float *src, *dest, *refd, *blurd;
+
+ if(ref->x!=img->x && ref->y!=img->y)
+ return;
+
+ ref_use= typecheck_compbuf(ref, CB_VAL);
+
+ /* trick is; we blur the reference image... but only works with clipped values*/
+ blurbuf= alloc_compbuf(imgx, imgy, CB_VAL, 1);
+ blurd= blurbuf->rect;
+ refd= ref_use->rect;
+ for(x= imgx*imgy; x>0; x--, refd++, blurd++) {
+ if(refd[0]<0.0f) blurd[0]= 0.0f;
+ else if(refd[0]>1.0f) blurd[0]= 1.0f;
+ else blurd[0]= refd[0];
+ }
+
+ blur_single_image(node, blurbuf, blurbuf, 1.0f);
+
+ /* horizontal */
+ radx = (float)nbd->sizex;
+ if(radx>imgx/2)
+ radx= imgx/2;
+ else if(radx<1)
+ radx= 1;
+
+ /* vertical */
+ rady = (float)nbd->sizey;
+ if(rady>imgy/2)
+ rady= imgy/2;
+ else if(rady<1)
+ rady= 1;
+
+ x= MAX2(radx, rady);
+ maintabs= MEM_mallocN(x*sizeof(void *), "gauss array");
+ for(i= 0; i<x; i++)
+ maintabs[i]= make_gausstab(nbd->filtertype, i+1);
+
+ refd= blurbuf->rect;
+ dest= new->rect;
+ radxf= (float)radx;
+ radyf= (float)rady;
+
+ for (y = 0; y < imgy; y++) {
+ for (x = 0; x < imgx ; x++, dest+=pix, refd++) {
+ int refradx= (int)(refd[0]*radxf);
+ int refrady= (int)(refd[0]*radyf);
+
+ if(refradx>radx) refradx= radx;
+ else if(refradx<1) refradx= 1;
+ if(refrady>rady) refrady= rady;
+ else if(refrady<1) refrady= 1;
+
+ if(refradx==1 && refrady==1) {
+ src= img->rect + pix*( y*imgx + x);
+ if(pix==1)
+ dest[0]= src[0];
+ else
+ QUATCOPY(dest, src);
+ }
+ else {
+ int minxr= x-refradx<0?-x:-refradx;
+ int maxxr= x+refradx>imgx?imgx-x:refradx;
+ int minyr= y-refrady<0?-y:-refrady;
+ int maxyr= y+refrady>imgy?imgy-y:refrady;
+
+ float *srcd= img->rect + pix*( (y + minyr)*imgx + x + minxr);
+
+ gausstabx= maintabs[refradx-1];
+ gausstabcentx= gausstabx+refradx;
+ gausstaby= maintabs[refrady-1];
+ gausstabcenty= gausstaby+refrady;
+
+ sum= gval = rval= bval= aval= 0.0f;
+
+ for (i= minyr; i < maxyr; i++, srcd+= pix*imgx) {
+ src= srcd;
+ for (j= minxr; j < maxxr; j++, src+=pix) {
+
+ val= gausstabcenty[i]*gausstabcentx[j];
+ sum+= val;
+ rval += val * src[0];
+ if(pix>1) {
+ gval += val * src[1];
+ bval += val * src[2];
+ aval += val * src[3];
+ }
+ }
+ }
+ sum= 1.0f/sum;
+ dest[0] = rval*sum;
+ if(pix>1) {
+ dest[1] = gval*sum;
+ dest[2] = bval*sum;
+ dest[3] = aval*sum;
+ }
+ }
+ }
+ if(node->exec & NODE_BREAK)
+ break;
+ }
+
+ free_compbuf(blurbuf);
+
+ x= MAX2(radx, rady);
+ for(i= 0; i<x; i++)
+ MEM_freeN(maintabs[i]);
+ MEM_freeN(maintabs);
+
+ if(ref_use!=ref)
+ free_compbuf(ref_use);
+}
+
+static void node_composit_exec_blur(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ CompBuf *new, *img= in[0]->data;
+
+ if(img==NULL || out[0]->hasoutput==0)
+ return;
+
+ if (((NodeBlurData *)node->storage)->filtertype == R_FILTER_FAST_GAUSS) {
+ CompBuf *new, *img = in[0]->data;
+ /*from eeshlo's original patch, removed to fit in with the existing blur node */
+ /*const float sx = in[1]->vec[0], sy = in[2]->vec[0];*/
+
+ NodeBlurData *nbd= node->storage;
+ const float sx = ((float)nbd->sizex)/2.0f, sy = ((float)nbd->sizey)/2.0f;
+ int c;
+
+ if ((img==NULL) || (out[0]->hasoutput==0)) return;
+
+ if (img->type == CB_VEC2)
+ new = typecheck_compbuf(img, CB_VAL);
+ else if (img->type == CB_VEC3)
+ new = typecheck_compbuf(img, CB_RGBA);
+ else
+ new = dupalloc_compbuf(img);
+
+ if ((sx == sy) && (sx > 0.f)) {
+ for (c=0; c<new->type; ++c)
+ IIR_gauss(new, sx, c, 3);
+ }
+ else {
+ if (sx > 0.f) {
+ for (c=0; c<new->type; ++c)
+ IIR_gauss(new, sx, c, 1);
+ }
+ if (sy > 0.f) {
+ for (c=0; c<new->type; ++c)
+ IIR_gauss(new, sy, c, 2);
+ }
+ }
+ out[0]->data = new;
+
+ } else {
+ /* All non fast gauss blur methods */
+ if(img->type==CB_VEC2 || img->type==CB_VEC3) {
+ img= typecheck_compbuf(in[0]->data, CB_RGBA);
+ }
+
+ /* if fac input, we do it different */
+ if(in[1]->data) {
+
+ /* make output size of input image */
+ new= alloc_compbuf(img->x, img->y, img->type, 1); /* allocs */
+
+ /* accept image offsets from other nodes */
+ new->xof = img->xof;
+ new->yof = img->yof;
+
+ blur_with_reference(node, new, img, in[1]->data);
+ if(node->exec & NODE_BREAK) {
+ free_compbuf(new);
+ new= NULL;
+ }
+ out[0]->data= new;
+ }
+ else {
+
+ if(in[1]->vec[0]<=0.001f) { /* time node inputs can be a tiny value */
+ new= pass_on_compbuf(img);
+ }
+ else {
+ NodeBlurData *nbd= node->storage;
+ CompBuf *gammabuf;
+
+ /* make output size of input image */
+ new= alloc_compbuf(img->x, img->y, img->type, 1); /* allocs */
+
+ /* accept image offsets from other nodes */
+ new->xof = img->xof;
+ new->yof = img->yof;
+
+ if(nbd->gamma) {
+ gammabuf= dupalloc_compbuf(img);
+ gamma_correct_compbuf(gammabuf, 0);
+ }
+ else gammabuf= img;
+
+ if(nbd->bokeh)
+ bokeh_single_image(node, new, gammabuf, in[1]->vec[0]);
+ else if(1)
+ blur_single_image(node, new, gammabuf, in[1]->vec[0]);
+ else /* bloom experimental... */
+ bloom_with_reference(new, gammabuf, NULL, in[1]->vec[0], nbd);
+
+ if(nbd->gamma) {
+ gamma_correct_compbuf(new, 1);
+ free_compbuf(gammabuf);
+ }
+ if(node->exec & NODE_BREAK) {
+ free_compbuf(new);
+ new= NULL;
+ }
+ }
+ out[0]->data= new;
+ }
+ if(img!=in[0]->data)
+ free_compbuf(img);
+ }
+}
+
+static void node_composit_init_blur(bNode* node)
+{
+ node->storage= MEM_callocN(sizeof(NodeBlurData), "node blur data");
+}
+
+bNodeType cmp_node_blur= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_BLUR,
+ /* name */ "Blur",
+ /* width+range */ 120, 80, 200,
+ /* class+opts */ NODE_CLASS_OP_FILTER, NODE_OPTIONS,
+ /* input sock */ cmp_node_blur_in,
+ /* output sock */ cmp_node_blur_out,
+ /* storage */ "NodeBlurData",
+ /* execfunc */ node_composit_exec_blur,
+ /* butfunc */ NULL,
+ /* initfunc */ node_composit_init_blur,
+ /* freestoragefunc */ node_free_standard_storage,
+ /* copystoragefunc */ node_copy_standard_storage,
+ /* id */ NULL
+};
+
+
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_brightness.c b/source/blender/nodes/intern/CMP_nodes/CMP_brightness.c
new file mode 100644
index 00000000000..c87307434b5
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_brightness.c
@@ -0,0 +1,113 @@
+/**
+* $Id$
+*
+* ***** BEGIN GPL LICENSE BLOCK *****
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*
+* The Original Code is Copyright (C) 2006 Blender Foundation.
+* All rights reserved.
+*
+* The Original Code is: all of this file.
+*
+* Contributor(s): none yet.
+*
+* ***** END GPL LICENSE BLOCK *****
+
+*/
+
+#include "../CMP_util.h"
+
+
+/* **************** Brigh and contrsast ******************** */
+
+static bNodeSocketType cmp_node_brightcontrast_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 1, "bright", 0.0f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f},
+ { SOCK_VALUE, 1, "contrast", 0.0f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketType cmp_node_brightcontrast_out[]= {
+ { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void do_brightnesscontrast(bNode *node, float *out, float *in)
+{
+ float i;
+ int c;
+ float a, b, contrast, brightness, delta, v;
+ contrast = node->custom2;
+ brightness = (float)(node->custom1);
+ brightness = (brightness) / 100.0f;
+ delta = contrast / 200.0f;
+ a = 1.0f - delta * 2.0f;
+ /*
+ * The algorithm is by Werner D. Streidt
+ * (http://visca.com/ffactory/archives/5-99/msg00021.html)
+ * Extracted of OpenCV demhist.c
+ */
+ if( contrast > 0 )
+{
+ a = 1.0f / a;
+ b = a * (brightness - delta);
+ }
+ else
+ {
+ delta *= -1;
+ b = a * (brightness + delta);
+ }
+
+ for(c=0; c<3; c++){
+ i = in[c];
+ v = a*i + b;
+ out[c] = v;
+ }
+}
+
+static void node_composit_exec_brightcontrast(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ if(out[0]->hasoutput==0)
+ return;
+
+ if(in[0]->data) {
+ CompBuf *stackbuf, *cbuf= typecheck_compbuf(in[0]->data, CB_RGBA);
+ node->custom1 = in[1]->vec[0];
+ node->custom2 = in[2]->vec[0];
+ stackbuf= dupalloc_compbuf(cbuf);
+ composit1_pixel_processor(node, stackbuf, cbuf, in[0]->vec, do_brightnesscontrast, CB_RGBA);
+ out[0]->data = stackbuf;
+ if(cbuf != in[0]->data)
+ free_compbuf(cbuf);
+ }
+}
+
+bNodeType cmp_node_brightcontrast= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_BRIGHTCONTRAST,
+ /* name */ "Bright/Contrast",
+ /* width+range */ 140, 100, 320,
+ /* class+opts */ NODE_CLASS_OP_COLOR, NODE_OPTIONS,
+ /* input sock */ cmp_node_brightcontrast_in,
+ /* output sock */ cmp_node_brightcontrast_out,
+ /* storage */ "",
+ /* execfunc */ node_composit_exec_brightcontrast,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copysotragefunc */ NULL,
+ /* id */ NULL
+};
+
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_channelMatte.c b/source/blender/nodes/intern/CMP_nodes/CMP_channelMatte.c
new file mode 100644
index 00000000000..d0cc4e5b88d
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_channelMatte.c
@@ -0,0 +1,207 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../CMP_util.h"
+
+
+/* ******************* Channel Matte Node ********************************* */
+static bNodeSocketType cmp_node_channel_matte_in[]={
+ {SOCK_RGBA,1,"Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ {-1,0,""}
+};
+
+static bNodeSocketType cmp_node_channel_matte_out[]={
+ {SOCK_RGBA,0,"Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ {SOCK_VALUE,0,"Matte",0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ {-1,0,""}
+};
+
+static void do_normalized_rgba_to_ycca2(bNode *node, float *out, float *in)
+{
+ /*normalize to the range 0.0 to 1.0) */
+ rgb_to_ycc(in[0],in[1],in[2], &out[0], &out[1], &out[2]);
+ out[0]=(out[0])/255.0;
+ out[1]=(out[1])/255.0;
+ out[2]=(out[2])/255.0;
+ out[3]=in[3];
+}
+
+static void do_normalized_ycca_to_rgba2(bNode *node, float *out, float *in)
+{
+ /*un-normalize the normalize from above */
+ in[0]=in[0]*255.0;
+ in[1]=in[1]*255.0;
+ in[2]=in[2]*255.0;
+ ycc_to_rgb(in[0],in[1],in[2], &out[0], &out[1], &out[2]);
+ out[3]=in[3];
+}
+
+
+static void do_channel_matte(bNode *node, float *out, float *in)
+{
+ NodeChroma *c=(NodeChroma *)node->storage;
+ float alpha=0.0;
+
+ /* Alpha=G-MAX(R, B) */
+
+ switch(node->custom2)
+ {
+ case 1:
+ {
+ alpha=in[0]-MAX2(in[1],in[2]);
+ break;
+ }
+ case 2:
+ {
+ alpha=in[1]-MAX2(in[0],in[2]);
+ break;
+ }
+ case 3:
+ {
+ alpha=in[2]-MAX2(in[0],in[1]);
+ break;
+ }
+ default:
+ break;
+ }
+
+ /*flip because 0.0 is transparent, not 1.0*/
+ alpha=1-alpha;
+
+ /* test range*/
+ if(alpha>c->t1) {
+ alpha=in[3]; /*whatever it was prior */
+ }
+ else if(alpha<c->t2){
+ alpha=0.0;
+ }
+ else {/*blend */
+ alpha=(alpha-c->t2)/(c->t1-c->t2);
+ }
+
+
+ /* don't make something that was more transparent less transparent */
+ if (alpha<in[3]) {
+ out[3]=alpha;
+ }
+ else {
+ out[3]=in[3];
+ }
+
+}
+
+static void node_composit_exec_channel_matte(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ CompBuf *cbuf;
+ CompBuf *outbuf;
+
+ if(in[0]->hasinput==0) return;
+ if(in[0]->data==NULL) return;
+ if(out[0]->hasoutput==0 && out[1]->hasoutput==0) return;
+
+ cbuf=typecheck_compbuf(in[0]->data, CB_RGBA);
+
+ outbuf=dupalloc_compbuf(cbuf);
+
+ /*convert to colorspace*/
+ switch(node->custom1) {
+ case 1: /*RGB */
+ break;
+ case 2: /*HSV*/
+ composit1_pixel_processor(node, outbuf, cbuf, in[1]->vec, do_rgba_to_hsva, CB_RGBA);
+ break;
+ case 3: /*YUV*/
+ composit1_pixel_processor(node, outbuf, cbuf, in[1]->vec, do_rgba_to_yuva, CB_RGBA);
+ break;
+ case 4: /*YCC*/
+ composit1_pixel_processor(node, outbuf, cbuf, in[1]->vec, do_normalized_rgba_to_ycca2, CB_RGBA);
+ break;
+ default:
+ break;
+ }
+
+ /*use the selected channel information to do the key */
+ composit1_pixel_processor(node, outbuf, outbuf, in[1]->vec, do_channel_matte, CB_RGBA);
+
+ /*convert back to RGB colorspace in place*/
+ switch(node->custom1) {
+ case 1: /*RGB*/
+ break;
+ case 2: /*HSV*/
+ composit1_pixel_processor(node, outbuf, outbuf, in[1]->vec, do_hsva_to_rgba, CB_RGBA);
+ break;
+ case 3: /*YUV*/
+ composit1_pixel_processor(node, outbuf, outbuf, in[1]->vec, do_yuva_to_rgba, CB_RGBA);
+ break;
+ case 4: /*YCC*/
+ composit1_pixel_processor(node, outbuf, outbuf, in[1]->vec, do_normalized_ycca_to_rgba2, CB_RGBA);
+ break;
+ default:
+ break;
+ }
+
+ generate_preview(node, outbuf);
+ out[0]->data=outbuf;
+ if(out[1]->hasoutput)
+ out[1]->data=valbuf_from_rgbabuf(outbuf, CHAN_A);
+
+ if(cbuf!=in[0]->data)
+ free_compbuf(cbuf);
+
+}
+
+static void node_composit_init_channel_matte(bNode *node)
+{
+ NodeChroma *c= MEM_callocN(sizeof(NodeChroma), "node chroma");
+ node->storage=c;
+ c->t1= 0.0f;
+ c->t2= 0.0f;
+ c->t3= 0.0f;
+ c->fsize= 0.0f;
+ c->fstrength= 0.0f;
+ node->custom1= 1; /* RGB channel */
+ node->custom2= 2; /* Green Channel */
+}
+
+bNodeType cmp_node_channel_matte={
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_CHANNEL_MATTE,
+ /* name */ "Channel Key",
+ /* width+range */ 200, 80, 250,
+ /* class+opts */ NODE_CLASS_MATTE, NODE_PREVIEW|NODE_OPTIONS,
+ /* input sock */ cmp_node_channel_matte_in,
+ /* output sock */ cmp_node_channel_matte_out,
+ /* storage */ "NodeChroma",
+ /* execfunc */ node_composit_exec_channel_matte,
+ /* butfunc */ NULL,
+ /* initfunc */ node_composit_init_channel_matte,
+ /* freestoragefunc */ node_free_standard_storage,
+ /* copystoragefunc */ node_copy_standard_storage,
+ /* id */ NULL
+};
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_chromaMatte.c b/source/blender/nodes/intern/CMP_nodes/CMP_chromaMatte.c
new file mode 100644
index 00000000000..d836a829696
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_chromaMatte.c
@@ -0,0 +1,192 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../CMP_util.h"
+
+/* ******************* Chroma Key ********************************************************** */
+static bNodeSocketType cmp_node_chroma_in[]={
+ {SOCK_RGBA,1,"Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ {SOCK_RGBA,1,"Key Color", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ {-1,0,""}
+};
+
+static bNodeSocketType cmp_node_chroma_out[]={
+ {SOCK_RGBA,0,"Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ {SOCK_VALUE,0,"Matte",0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ {-1,0,""}
+};
+
+static void do_rgba_to_ycca_normalized(bNode *node, float *out, float *in)
+{
+ /*normalize to the range -1.0 to 1.0) */
+ rgb_to_ycc(in[0],in[1],in[2], &out[0], &out[1], &out[2]);
+ out[0]=((out[0])-16)/255.0;
+ out[1]=((out[1])-128)/255.0;
+ out[2]=((out[2])-128)/255.0;
+ out[3]=in[3];
+}
+
+static void do_ycca_to_rgba_normalized(bNode *node, float *out, float *in)
+{
+ /*un-normalize the normalize from above */
+ in[0]=(in[0]*255.0)+16;
+ in[1]=(in[1]*255.0)+128;
+ in[2]=(in[2]*255.0)+128;
+ ycc_to_rgb(in[0],in[1],in[2], &out[0], &out[1], &out[2]);
+ out[3]=in[3];
+}
+
+static void do_chroma_key(bNode *node, float *out, float *in)
+{
+ NodeChroma *c;
+ float x, z, alpha;
+ float theta, beta, angle;
+ float kfg, newY, newCb, newCr;
+
+ c=node->storage;
+
+ /* Algorithm from book "Video Demistified" */
+
+ /* find theta, the angle that the color space should be rotated based on key*/
+ theta=atan2(c->key[2],c->key[1]);
+
+ /*rotate the cb and cr into x/z space */
+ x=in[1]*cos(theta)+in[2]*sin(theta);
+ z=in[2]*cos(theta)-in[1]*sin(theta);
+
+ /*if within the acceptance angle */
+ angle=c->t1*M_PI/180.0; /* convert to radians */
+
+ /* if kfg is <0 then the pixel is outside of the key color */
+ kfg=x-(fabs(z)/tan(angle/2.0));
+
+ if(kfg>0.0) { /* found a pixel that is within key color */
+
+ newY=in[0]-(1-c->t3)*kfg;
+ newCb=in[1]-kfg*cosf(theta);
+ newCr=in[2]-kfg*sinf(theta);
+ alpha=(kfg+c->fsize)*(c->fstrength);
+
+ beta=atan2(newCr,newCb);
+ beta=beta*180.0/M_PI; /* convert to degrees for compare*/
+
+ /* if beta is within the clippin angle */
+ if(fabs(beta)<(c->t2/2.0)) {
+ newCb=0.0;
+ newCr=0.0;
+ alpha=0.0;
+ }
+
+ out[0]=newY;
+ out[1]=newCb;
+ out[2]=newCr;
+
+ /* don't make something that was more transparent less transparent */
+ if (alpha<in[3]) {
+ out[3]=alpha;
+ }
+ else {
+ out[3]=in[3];
+ }
+ }
+ else { /*pixel is outside key color */
+ out[0]=in[0];
+ out[1]=in[1];
+ out[2]=in[2];
+ out[3]=in[3]; /* make pixel just as transparent as it was before */
+ }
+}
+
+static void node_composit_exec_chroma_matte(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ CompBuf *cbuf;
+ CompBuf *chromabuf;
+ NodeChroma *c;
+
+ if(in[0]->hasinput==0) return;
+ if(in[0]->data==NULL) return;
+ if(out[0]->hasoutput==0 && out[1]->hasoutput==0) return;
+
+ cbuf= typecheck_compbuf(in[0]->data, CB_RGBA);
+
+ chromabuf= dupalloc_compbuf(cbuf);
+
+ c=node->storage;
+
+ /*convert rgbbuf to normalized chroma space*/
+ composit1_pixel_processor(node, chromabuf, cbuf, in[0]->vec, do_rgba_to_ycca_normalized, CB_RGBA);
+ /*convert key to normalized chroma color space */
+ do_rgba_to_ycca_normalized(node, c->key, in[1]->vec);
+
+ /*per pixel chroma key*/
+ composit1_pixel_processor(node, chromabuf, chromabuf, in[0]->vec, do_chroma_key, CB_RGBA);
+
+ /*convert back*/
+ composit1_pixel_processor(node, chromabuf, chromabuf, in[0]->vec, do_ycca_to_rgba_normalized, CB_RGBA);
+
+ out[0]->data= chromabuf;
+ if(out[1]->hasoutput)
+ out[1]->data= valbuf_from_rgbabuf(chromabuf, CHAN_A);
+
+ generate_preview(node, chromabuf);
+
+ if(cbuf!=in[0]->data)
+ free_compbuf(cbuf);
+};
+
+
+static void node_composit_init_chroma_matte(bNode *node)
+{
+ NodeChroma *c= MEM_callocN(sizeof(NodeChroma), "node chroma");
+ node->storage= c;
+ c->t1= 30.0f;
+ c->t2= 10.0f;
+ c->t3= 0.0f;
+ c->fsize= 0.0f;
+ c->fstrength= 1.0f;
+};
+
+bNodeType cmp_node_chroma={
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_CHROMA,
+ /* name */ "Chroma Key",
+ /* width+range */ 200, 80, 300,
+ /* class+opts */ NODE_CLASS_MATTE, NODE_PREVIEW|NODE_OPTIONS,
+ /* input sock */ cmp_node_chroma_in,
+ /* output sock */ cmp_node_chroma_out,
+ /* storage */ "NodeChroma",
+ /* execfunc */ node_composit_exec_chroma_matte,
+ /* butfunc */ NULL,
+ /* initfunc */ node_composit_init_chroma_matte,
+ /* freestoragefunc */ node_free_standard_storage,
+ /* copystoragefunc */ node_copy_standard_storage,
+ /* id */ NULL
+};
+
+
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_colorSpill.c b/source/blender/nodes/intern/CMP_nodes/CMP_colorSpill.c
new file mode 100644
index 00000000000..152180afc08
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_colorSpill.c
@@ -0,0 +1,144 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+
+#include "../CMP_util.h"
+
+
+/* ******************* Color Spill Supression ********************************* */
+static bNodeSocketType cmp_node_color_spill_in[]={
+ {SOCK_RGBA,1,"Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ {-1,0,""}
+};
+
+static bNodeSocketType cmp_node_color_spill_out[]={
+ {SOCK_RGBA,0,"Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ {-1,0,""}
+};
+
+static void do_reduce_red(bNode *node, float* out, float *in)
+{
+ NodeChroma *c;
+ c=node->storage;
+
+ if(in[0] > in[1] && in[0] > in[2]) {
+ out[0]=((in[1]+in[2])/2)*(1-c->t1);
+ }
+}
+
+static void do_reduce_green(bNode *node, float* out, float *in)
+{
+ NodeChroma *c;
+ c=node->storage;
+
+ if(in[1] > in[0] && in[1] > in[2]) {
+ out[1]=((in[0]+in[2])/2)*(1-c->t1);
+ }
+}
+
+static void do_reduce_blue(bNode *node, float* out, float *in)
+{
+ NodeChroma *c;
+ c=node->storage;
+
+ if(in[2] > in[1] && in[2] > in[1]) {
+ out[2]=((in[1]+in[0])/2)*(1-c->t1);
+ }
+}
+
+static void node_composit_exec_color_spill(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /*
+ Originally based on the information from the book "The Art and Science of Digital Composition" and
+ discussions from vfxtalk.com.*/
+ CompBuf *cbuf;
+ CompBuf *rgbbuf;
+
+ if(out[0]->hasoutput==0 || in[0]->hasinput==0) return;
+ if(in[0]->data==NULL) return;
+
+ cbuf=typecheck_compbuf(in[0]->data, CB_RGBA);
+ rgbbuf=dupalloc_compbuf(cbuf);
+
+ switch(node->custom1)
+ {
+ case 1: /*red spill*/
+ {
+ composit1_pixel_processor(node, rgbbuf, cbuf, in[1]->vec, do_reduce_red, CB_RGBA);
+ break;
+ }
+ case 2: /*green spill*/
+ {
+ composit1_pixel_processor(node, rgbbuf, cbuf, in[1]->vec, do_reduce_green, CB_RGBA);
+ break;
+ }
+ case 3: /*blue spill*/
+ {
+ composit1_pixel_processor(node, rgbbuf, cbuf, in[1]->vec, do_reduce_blue, CB_RGBA);
+ break;
+ }
+ default:
+ break;
+ }
+
+ out[0]->data=rgbbuf;
+
+ if(cbuf!=in[0]->data)
+ free_compbuf(cbuf);
+}
+
+static void node_composit_init_color_spill(bNode *node)
+{
+ NodeChroma *c= MEM_callocN(sizeof(NodeChroma), "node chroma");
+ node->storage=c;
+ c->t1= 0.0f;
+ c->t2= 0.0f;
+ c->t3= 0.0f;
+ c->fsize= 0.0f;
+ c->fstrength= 0.0f;
+ node->custom1= 2; /* green channel */
+}
+
+bNodeType cmp_node_color_spill={
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_COLOR_SPILL,
+ /* name */ "Color Spill",
+ /* width+range */ 140, 80, 200,
+ /* class+opts */ NODE_CLASS_MATTE, NODE_OPTIONS,
+ /* input sock */ cmp_node_color_spill_in,
+ /* output sock */ cmp_node_color_spill_out,
+ /* storage */ "NodeChroma",
+ /* execfunc */ node_composit_exec_color_spill,
+ /* butfunc */ NULL,
+ /* initfunc */ node_composit_init_color_spill,
+ /* freestoragefunc */ node_free_standard_storage,
+ /* copystoragefunc */ node_copy_standard_storage,
+ /* id */ NULL
+};
+
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_composite.c b/source/blender/nodes/intern/CMP_nodes/CMP_composite.c
new file mode 100644
index 00000000000..89bd8e43694
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_composite.c
@@ -0,0 +1,105 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../CMP_util.h"
+
+
+
+/* **************** COMPOSITE ******************** */
+static bNodeSocketType cmp_node_composite_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 1, "Alpha", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 1, "Z", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+/* applies to render pipeline */
+static void node_composit_exec_composite(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* image assigned to output */
+ /* stack order input sockets: col, alpha, z */
+
+ if(node->flag & NODE_DO_OUTPUT) { /* only one works on out */
+ RenderData *rd= data;
+ if(rd->scemode & R_DOCOMP) {
+ RenderResult *rr= RE_GetResult(RE_GetRender(G.scene->id.name)); /* G.scene is WEAK! */
+ if(rr) {
+ CompBuf *outbuf, *zbuf=NULL;
+
+ if(rr->rectf)
+ MEM_freeN(rr->rectf);
+ outbuf= alloc_compbuf(rr->rectx, rr->recty, CB_RGBA, 1);
+
+ if(in[1]->data==NULL)
+ composit1_pixel_processor(node, outbuf, in[0]->data, in[0]->vec, do_copy_rgba, CB_RGBA);
+ else
+ composit2_pixel_processor(node, outbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec, do_copy_a_rgba, CB_RGBA, CB_VAL);
+
+ if(in[2]->data) {
+ if(rr->rectz)
+ MEM_freeN(rr->rectz);
+ zbuf= alloc_compbuf(rr->rectx, rr->recty, CB_VAL, 1);
+ composit1_pixel_processor(node, zbuf, in[2]->data, in[2]->vec, do_copy_value, CB_VAL);
+ rr->rectz= zbuf->rect;
+ zbuf->malloc= 0;
+ free_compbuf(zbuf);
+ }
+ generate_preview(node, outbuf);
+
+ /* we give outbuf to rr... */
+ rr->rectf= outbuf->rect;
+ outbuf->malloc= 0;
+ free_compbuf(outbuf);
+
+ /* signal for imageviewer to refresh (it converts to byte rects...) */
+ BKE_image_signal(BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result"), NULL, IMA_SIGNAL_FREE);
+ return;
+ }
+ }
+ }
+ if(in[0]->data)
+ generate_preview(node, in[0]->data);
+}
+
+bNodeType cmp_node_composite= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_COMPOSITE,
+ /* name */ "Composite",
+ /* width+range */ 80, 60, 200,
+ /* class+opts */ NODE_CLASS_OUTPUT, NODE_PREVIEW,
+ /* input sock */ cmp_node_composite_in,
+ /* output sock */ NULL,
+ /* storage */ "",
+ /* execfunc */ node_composit_exec_composite,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+};
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_crop.c b/source/blender/nodes/intern/CMP_nodes/CMP_crop.c
new file mode 100644
index 00000000000..f3a00dec084
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_crop.c
@@ -0,0 +1,119 @@
+/**
+ *
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Juho Vepsäläinen
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../CMP_util.h"
+
+/* **************** Crop ******************** */
+
+static bNodeSocketType cmp_node_crop_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketType cmp_node_crop_out[]= {
+ { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void node_composit_exec_crop(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ if(in[0]->data) {
+ NodeTwoXYs *ntxy= node->storage;
+ CompBuf *cbuf= in[0]->data;
+ CompBuf *stackbuf;
+ int x, y;
+ float *srcfp, *outfp;
+ rcti outputrect;
+
+ /* check input image size */
+ if(cbuf->x <= ntxy->x1 + 1)
+ ntxy->x1= cbuf->x - 1;
+
+ if(cbuf->y <= ntxy->y1 + 1)
+ ntxy->y1= cbuf->y - 1;
+
+ if(cbuf->x <= ntxy->x2 + 1)
+ ntxy->x2= cbuf->x - 1;
+
+ if(cbuf->y <= ntxy->y2 + 1)
+ ntxy->y2= cbuf->y - 1;
+
+ /* figure out the minimums and maximums */
+ outputrect.xmax=MAX2(ntxy->x1, ntxy->x2) + 1;
+ outputrect.xmin=MIN2(ntxy->x1, ntxy->x2);
+ outputrect.ymax=MAX2(ntxy->y1, ntxy->y2) + 1;
+ outputrect.ymin=MIN2(ntxy->y1, ntxy->y2);
+
+ if(node->custom1) {
+ /* this option crops the image size too */
+ stackbuf= get_cropped_compbuf(&outputrect, cbuf->rect, cbuf->x, cbuf->y, cbuf->type);
+ }
+ else {
+ /* this option won't crop the size of the image as well */
+ /* allocate memory for the output image */
+ stackbuf = alloc_compbuf(cbuf->x, cbuf->y, cbuf->type, 1);
+
+ /* select the cropped part of the image and set it to the output */
+ for(y=outputrect.ymin; y<outputrect.ymax; y++){
+ srcfp= cbuf->rect + (y * cbuf->x + outputrect.xmin) * cbuf->type;
+ outfp= stackbuf->rect + (y * stackbuf->x + outputrect.xmin) * stackbuf->type;
+ for(x=outputrect.xmin; x<outputrect.xmax; x++, outfp+= stackbuf->type, srcfp+= cbuf->type)
+ memcpy(outfp, srcfp, sizeof(float)*stackbuf->type);
+ }
+ }
+
+ out[0]->data= stackbuf;
+ }
+}
+
+static void node_composit_init_crop(bNode* node)
+{
+ NodeTwoXYs *nxy= MEM_callocN(sizeof(NodeTwoXYs), "node xy data");
+ node->storage= nxy;
+ nxy->x1= 0;
+ nxy->x2= 0;
+ nxy->y1= 0;
+ nxy->y2= 0;
+}
+
+bNodeType cmp_node_crop= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_CROP,
+ /* name */ "Crop",
+ /* width+range */ 140, 100, 320,
+ /* class+opts */ NODE_CLASS_DISTORT, NODE_OPTIONS,
+ /* input sock */ cmp_node_crop_in,
+ /* output sock */ cmp_node_crop_out,
+ /* storage */ "NodeTwoXYs",
+ /* execfunc */ node_composit_exec_crop,
+ /* butfunc */ NULL,
+ /* initfunc */ node_composit_init_crop,
+ /* freestoragefunc */ node_free_standard_storage,
+ /* copystoragefunc */ node_copy_standard_storage,
+ /* id */ NULL
+};
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_curves.c b/source/blender/nodes/intern/CMP_nodes/CMP_curves.c
new file mode 100644
index 00000000000..17d9821a5ef
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_curves.c
@@ -0,0 +1,206 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../CMP_util.h"
+
+
+/* **************** CURVE Time ******************** */
+
+/* custom1 = sfra, custom2 = efra */
+static bNodeSocketType cmp_node_time_out[]= {
+ { SOCK_VALUE, 0, "Fac", 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void node_composit_exec_curves_time(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order output: fac */
+ float fac= 0.0f;
+
+ if(node->custom1 < node->custom2)
+ fac= (G.scene->r.cfra - node->custom1)/(float)(node->custom2-node->custom1);
+
+ fac= curvemapping_evaluateF(node->storage, 0, fac);
+ out[0]->vec[0]= CLAMPIS(fac, 0.0f, 1.0f);
+}
+
+
+static void node_composit_init_curves_time(bNode* node)
+{
+ node->custom1= G.scene->r.sfra;
+ node->custom2= G.scene->r.efra;
+ node->storage= curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+}
+
+bNodeType cmp_node_curve_time= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_TIME,
+ /* name */ "Time",
+ /* width+range */ 140, 100, 320,
+ /* class+opts */ NODE_CLASS_INPUT, NODE_OPTIONS,
+ /* input sock */ NULL,
+ /* output sock */ cmp_node_time_out,
+ /* storage */ "CurveMapping",
+ /* execfunc */ node_composit_exec_curves_time,
+ /* butfunc */ NULL,
+ /* initfunc */ node_composit_init_curves_time,
+ /* freestoragefunc */ node_free_curves,
+ /* copystoragefunc */ node_copy_curves,
+ /* id */ NULL
+};
+
+
+
+/* **************** CURVE VEC ******************** */
+static bNodeSocketType cmp_node_curve_vec_in[]= {
+ { SOCK_VECTOR, 1, "Vector", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static bNodeSocketType cmp_node_curve_vec_out[]= {
+ { SOCK_VECTOR, 0, "Vector", 0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void node_composit_exec_curve_vec(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order input: vec */
+ /* stack order output: vec */
+
+ curvemapping_evaluate_premulRGBF(node->storage, out[0]->vec, in[0]->vec);
+};
+
+static void node_composit_init_curve_vec(bNode* node)
+{
+ node->storage= curvemapping_add(3, -1.0f, -1.0f, 1.0f, 1.0f);
+};
+
+bNodeType cmp_node_curve_vec= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_CURVE_VEC,
+ /* name */ "Vector Curves",
+ /* width+range */ 200, 140, 320,
+ /* class+opts */ NODE_CLASS_OP_VECTOR, NODE_OPTIONS,
+ /* input sock */ cmp_node_curve_vec_in,
+ /* output sock */ cmp_node_curve_vec_out,
+ /* storage */ "CurveMapping",
+ /* execfunc */ node_composit_exec_curve_vec,
+ /* butfunc */ NULL,
+ /* initfunc */ node_composit_init_curve_vec,
+ /* freestoragefunc */ node_free_curves,
+ /* copystoragefunc */ node_copy_curves,
+ /* id */ NULL
+
+};
+
+/* **************** CURVE RGB ******************** */
+static bNodeSocketType cmp_node_curve_rgb_in[]= {
+ { SOCK_VALUE, 1, "Fac", 1.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
+ { SOCK_RGBA, 1, "Image", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static bNodeSocketType cmp_node_curve_rgb_out[]= {
+ { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void do_curves(bNode *node, float *out, float *in)
+{
+ curvemapping_evaluate_premulRGBF(node->storage, out, in);
+ out[3]= in[3];
+}
+
+static void do_curves_fac(bNode *node, float *out, float *in, float *fac)
+{
+
+ if(*fac>=1.0)
+ curvemapping_evaluate_premulRGBF(node->storage, out, in);
+ else if(*fac<=0.0) {
+ VECCOPY(out, in);
+ }
+ else {
+ float col[4], mfac= 1.0f-*fac;
+ curvemapping_evaluate_premulRGBF(node->storage, col, in);
+ out[0]= mfac*in[0] + *fac*col[0];
+ out[1]= mfac*in[1] + *fac*col[1];
+ out[2]= mfac*in[2] + *fac*col[2];
+ }
+ out[3]= in[3];
+}
+
+static void node_composit_exec_curve_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order input: fac, image */
+ /* stack order output: image */
+
+ if(out[0]->hasoutput==0)
+ return;
+
+ /* input no image? then only color operation */
+ if(in[1]->data==NULL) {
+ curvemapping_evaluateRGBF(node->storage, out[0]->vec, in[1]->vec);
+ }
+ else {
+ /* make output size of input image */
+ CompBuf *cbuf= in[1]->data;
+ CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */
+
+ if(in[0]->vec[0] == 1.0)
+ composit1_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, do_curves, CB_RGBA);
+ else
+ composit2_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, in[0]->data, in[0]->vec, do_curves_fac, CB_RGBA, CB_VAL);
+
+ out[0]->data= stackbuf;
+ }
+
+};
+
+static void node_composit_init_curve_rgb(bNode* node)
+{
+ node->storage= curvemapping_add(4, 0.0f, 0.0f, 1.0f, 1.0f);
+};
+
+bNodeType cmp_node_curve_rgb= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_CURVE_RGB,
+ /* name */ "RGB Curves",
+ /* width+range */ 200, 140, 320,
+ /* class+opts */ NODE_CLASS_OP_COLOR, NODE_OPTIONS,
+ /* input sock */ cmp_node_curve_rgb_in,
+ /* output sock */ cmp_node_curve_rgb_out,
+ /* storage */ "CurveMapping",
+ /* execfunc */ node_composit_exec_curve_rgb,
+ /* butfunc */ NULL,
+ /* initfunc */ node_composit_init_curve_rgb,
+ /* freestoragefunc */ node_free_curves,
+ /* copystoragefunc */ node_copy_curves,
+ /* id */ NULL
+};
+
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_defocus.c b/source/blender/nodes/intern/CMP_nodes/CMP_defocus.c
new file mode 100644
index 00000000000..53d01ab1d12
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_defocus.c
@@ -0,0 +1,855 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../CMP_util.h"
+
+/* ************ qdn: Defocus node ****************** */
+static bNodeSocketType cmp_node_defocus_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 1, "Z", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketType cmp_node_defocus_out[]= {
+ { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+
+// line coefs for point sampling & scancon. data.
+typedef struct BokehCoeffs {
+ float x0, y0, dx, dy;
+ float ls_x, ls_y;
+ float min_x, min_y, max_x, max_y;
+} BokehCoeffs;
+
+// returns array of BokehCoeffs
+// returns length of array in 'len_bkh',
+// radius squared of inscribed disk in 'inradsq', needed in getWeight() test,
+// BKH[8] is the data returned for the bokeh shape & bkh_b[4] is it's 2d bound
+static void makeBokeh(char bktype, char ro, int* len_bkh, float* inradsq, BokehCoeffs BKH[8], float bkh_b[4])
+{
+ float x0, x1, y0, y1, dx, dy, iDxy;
+ float w = MAX2(1e-5f, ro)*M_PI/180.f; // never reported stangely enough, but a zero offset causes missing center line...
+ float wi = (360.f/bktype)*M_PI/180.f;
+ int i, ov, nv;
+
+ // bktype must be at least 3 & <= 8
+ bktype = (bktype<3) ? 3 : ((bktype>8) ? 8 : bktype);
+ *len_bkh = bktype;
+ *inradsq = -1.f;
+
+ for (i=0; i<(*len_bkh); i++) {
+ x0 = cos(w);
+ y0 = sin(w);
+ w += wi;
+ x1 = cos(w);
+ y1 = sin(w);
+ if ((*inradsq)<0.f) {
+ // radius squared of inscribed disk
+ float idx=(x0+x1)*0.5f, idy=(y0+y1)*0.5f;
+ *inradsq = idx*idx + idy*idy;
+ }
+ BKH[i].x0 = x0;
+ BKH[i].y0 = y0;
+ dx = x1-x0, dy = y1-y0;
+ iDxy = 1.f / sqrt(dx*dx + dy*dy);
+ dx *= iDxy;
+ dy *= iDxy;
+ BKH[i].dx = dx;
+ BKH[i].dy = dy;
+ }
+
+ // precalc scanconversion data
+ // bokeh bound, not transformed, for scanconvert
+ bkh_b[0] = bkh_b[2] = 1e10f; // xmin/ymin
+ bkh_b[1] = bkh_b[3] = -1e10f; // xmax/ymax
+ ov = (*len_bkh) - 1;
+ for (nv=0; nv<(*len_bkh); nv++) {
+ bkh_b[0] = MIN2(bkh_b[0], BKH[nv].x0); // xmin
+ bkh_b[1] = MAX2(bkh_b[1], BKH[nv].x0); // xmax
+ bkh_b[2] = MIN2(bkh_b[2], BKH[nv].y0); // ymin
+ bkh_b[3] = MAX2(bkh_b[3], BKH[nv].y0); // ymax
+ BKH[nv].min_x = MIN2(BKH[ov].x0, BKH[nv].x0);
+ BKH[nv].max_x = MAX2(BKH[ov].x0, BKH[nv].x0);
+ BKH[nv].min_y = MIN2(BKH[ov].y0, BKH[nv].y0);
+ BKH[nv].max_y = MAX2(BKH[ov].y0, BKH[nv].y0);
+ dy = BKH[nv].y0 - BKH[ov].y0;
+ BKH[nv].ls_x = (BKH[nv].x0 - BKH[ov].x0) / ((dy==0.f) ? 1.f : dy);
+ BKH[nv].ls_y = (BKH[nv].ls_x==0.f) ? 1.f : (1.f/BKH[nv].ls_x);
+ ov = nv;
+ }
+}
+
+// test if u/v inside shape & returns weight value
+static float getWeight(BokehCoeffs* BKH, int len_bkh, float u, float v, float rad, float inradsq)
+{
+ BokehCoeffs* bc = BKH;
+ float cdist, irad = (rad==0.f) ? 1.f : (1.f/rad);
+ u *= irad;
+ v *= irad;
+
+ // early out test1: if point outside outer unit disk, it cannot be inside shape
+ cdist = u*u + v*v;
+ if (cdist>1.f) return 0.f;
+
+ // early out test2: if point inside or on inner disk, point must be inside shape
+ if (cdist<=inradsq) return 1.f;
+
+ while (len_bkh--) {
+ if ((bc->dy*(u - bc->x0) - bc->dx*(v - bc->y0)) > 0.f) return 0.f;
+ bc++;
+ }
+ return 1.f;
+}
+
+// QMC.seq. for sampling, A.Keller, EMS
+static float RI_vdC(unsigned int bits, unsigned int r)
+{
+ bits = ( bits << 16) | ( bits >> 16);
+ bits = ((bits & 0x00ff00ff) << 8) | ((bits & 0xff00ff00) >> 8);
+ bits = ((bits & 0x0f0f0f0f) << 4) | ((bits & 0xf0f0f0f0) >> 4);
+ bits = ((bits & 0x33333333) << 2) | ((bits & 0xcccccccc) >> 2);
+ bits = ((bits & 0x55555555) << 1) | ((bits & 0xaaaaaaaa) >> 1);
+ bits ^= r;
+ return (float)((double)bits / 4294967296.0);
+}
+
+// single channel IIR gaussian filtering
+// much faster than anything else, constant time independent of width
+// should extend to multichannel and make this a node, could be useful
+static void IIR_gauss_single(CompBuf* buf, float sigma)
+{
+ double q, q2, sc, cf[4], tsM[9], tsu[3], tsv[3];
+ float *X, *Y, *W;
+ int i, x, y, sz;
+
+ // single channel only for now
+ if (buf->type != CB_VAL) return;
+
+ // <0.5 not valid, though can have a possibly useful sort of sharpening effect
+ if (sigma < 0.5) return;
+
+ // see "Recursive Gabor Filtering" by Young/VanVliet
+ // all factors here in double.prec. Required, because for single.prec it seems to blow up if sigma > ~200
+ if (sigma >= 3.556)
+ q = 0.9804*(sigma - 3.556) + 2.5091;
+ else // sigma >= 0.5
+ q = (0.0561*sigma + 0.5784)*sigma - 0.2568;
+ q2 = q*q;
+ sc = (1.1668 + q)*(3.203729649 + (2.21566 + q)*q);
+ // no gabor filtering here, so no complex multiplies, just the regular coefs.
+ // all negated here, so as not to have to recalc Triggs/Sdika matrix
+ cf[1] = q*(5.788961737 + (6.76492 + 3.0*q)*q)/ sc;
+ cf[2] = -q2*(3.38246 + 3.0*q)/sc;
+ // 0 & 3 unchanged
+ cf[3] = q2*q/sc;
+ cf[0] = 1.0 - cf[1] - cf[2] - cf[3];
+
+ // Triggs/Sdika border corrections,
+ // it seems to work, not entirely sure if it is actually totally correct,
+ // Besides J.M.Geusebroek's anigauss.c (see http://www.science.uva.nl/~mark),
+ // found one other implementation by Cristoph Lampert,
+ // but neither seem to be quite the same, result seems to be ok sofar anyway.
+ // Extra scale factor here to not have to do it in filter,
+ // though maybe this had something to with the precision errors
+ sc = cf[0]/((1.0 + cf[1] - cf[2] + cf[3])*(1.0 - cf[1] - cf[2] - cf[3])*(1.0 + cf[2] + (cf[1] - cf[3])*cf[3]));
+ tsM[0] = sc*(-cf[3]*cf[1] + 1.0 - cf[3]*cf[3] - cf[2]);
+ tsM[1] = sc*((cf[3] + cf[1])*(cf[2] + cf[3]*cf[1]));
+ tsM[2] = sc*(cf[3]*(cf[1] + cf[3]*cf[2]));
+ tsM[3] = sc*(cf[1] + cf[3]*cf[2]);
+ tsM[4] = sc*(-(cf[2] - 1.0)*(cf[2] + cf[3]*cf[1]));
+ tsM[5] = sc*(-(cf[3]*cf[1] + cf[3]*cf[3] + cf[2] - 1.0)*cf[3]);
+ tsM[6] = sc*(cf[3]*cf[1] + cf[2] + cf[1]*cf[1] - cf[2]*cf[2]);
+ tsM[7] = sc*(cf[1]*cf[2] + cf[3]*cf[2]*cf[2] - cf[1]*cf[3]*cf[3] - cf[3]*cf[3]*cf[3] - cf[3]*cf[2] + cf[3]);
+ tsM[8] = sc*(cf[3]*(cf[1] + cf[3]*cf[2]));
+
+#define YVV(L)\
+{\
+ W[0] = cf[0]*X[0] + cf[1]*X[0] + cf[2]*X[0] + cf[3]*X[0];\
+ W[1] = cf[0]*X[1] + cf[1]*W[0] + cf[2]*X[0] + cf[3]*X[0];\
+ W[2] = cf[0]*X[2] + cf[1]*W[1] + cf[2]*W[0] + cf[3]*X[0];\
+ for (i=3; i<L; i++)\
+ W[i] = cf[0]*X[i] + cf[1]*W[i-1] + cf[2]*W[i-2] + cf[3]*W[i-3];\
+ tsu[0] = W[L-1] - X[L-1];\
+ tsu[1] = W[L-2] - X[L-1];\
+ tsu[2] = W[L-3] - X[L-1];\
+ tsv[0] = tsM[0]*tsu[0] + tsM[1]*tsu[1] + tsM[2]*tsu[2] + X[L-1];\
+ tsv[1] = tsM[3]*tsu[0] + tsM[4]*tsu[1] + tsM[5]*tsu[2] + X[L-1];\
+ tsv[2] = tsM[6]*tsu[0] + tsM[7]*tsu[1] + tsM[8]*tsu[2] + X[L-1];\
+ Y[L-1] = cf[0]*W[L-1] + cf[1]*tsv[0] + cf[2]*tsv[1] + cf[3]*tsv[2];\
+ Y[L-2] = cf[0]*W[L-2] + cf[1]*Y[L-1] + cf[2]*tsv[0] + cf[3]*tsv[1];\
+ Y[L-3] = cf[0]*W[L-3] + cf[1]*Y[L-2] + cf[2]*Y[L-1] + cf[3]*tsv[0];\
+ for (i=L-4; i>=0; i--)\
+ Y[i] = cf[0]*W[i] + cf[1]*Y[i+1] + cf[2]*Y[i+2] + cf[3]*Y[i+3];\
+}
+
+ // intermediate buffers
+ sz = MAX2(buf->x, buf->y);
+ Y = MEM_callocN(sz*sizeof(float), "IIR_gauss Y buf");
+ W = MEM_callocN(sz*sizeof(float), "IIR_gauss W buf");
+ // H
+ for (y=0; y<buf->y; y++) {
+ X = &buf->rect[y*buf->x];
+ YVV(buf->x);
+ memcpy(X, Y, sizeof(float)*buf->x);
+ }
+ // V
+ X = MEM_callocN(buf->y*sizeof(float), "IIR_gauss X buf");
+ for (x=0; x<buf->x; x++) {
+ for (y=0; y<buf->y; y++)
+ X[y] = buf->rect[x + y*buf->x];
+ YVV(buf->y);
+ for (y=0; y<buf->y; y++)
+ buf->rect[x + y*buf->x] = Y[y];
+ }
+ MEM_freeN(X);
+
+ MEM_freeN(W);
+ MEM_freeN(Y);
+#undef YVV
+}
+
+static void defocus_blur(bNode *node, CompBuf *new, CompBuf *img, CompBuf *zbuf, float inpval)
+{
+ NodeDefocus *nqd = node->storage;
+ CompBuf *wts; // weights buffer
+ CompBuf *crad; // CoC radius buffer
+ BokehCoeffs BKH[8]; // bokeh shape data, here never > 8 pts.
+ float bkh_b[4] = {0}; // shape 2D bound
+ unsigned int p, px, p4, zp, cp, cp4;
+ float *ctcol, u, v, iZ, ct_crad, lwt, wt=0, cR2=0;
+ float dof_sp, maxfgc, bk_hn_theta=0, inradsq=0;
+ float cam_fdist=1, cam_invfdist=1, cam_lens=35;
+ int x, y, sx, sy, len_bkh=0;
+ float aspect, aperture;
+ int minsz;
+ //float bcrad, nmaxc, scf;
+
+ // get some required params from the current scene camera
+ // (ton) this is wrong, needs fixed
+ Object* camob = G.scene->camera;
+ if (camob && camob->type==OB_CAMERA) {
+ Camera* cam = (Camera*)camob->data;
+ cam_lens = cam->lens;
+ cam_fdist = dof_camera(camob);
+ if (cam_fdist==0.0) cam_fdist = 1e10f; /* if the dof is 0.0 then set it be be far away */
+ cam_invfdist = 1.f/cam_fdist;
+ }
+
+ // guess work here.. best match with raytraced result
+ minsz = MIN2(img->x, img->y);
+ dof_sp = (float)minsz / (16.f / cam_lens); // <- == aspect * MIN2(img->x, img->y) / tan(0.5f * fov);
+
+ // aperture
+ aspect = (img->x > img->y) ? (img->y / (float)img->x) : (img->x / (float)img->y);
+ aperture = 0.5f*(cam_lens / (aspect*32.f)) / nqd->fstop;
+
+ // if not disk, make bokeh coefficients and other needed data
+ if (nqd->bktype!=0) {
+ makeBokeh(nqd->bktype, nqd->rotation, &len_bkh, &inradsq, BKH, bkh_b);
+ bk_hn_theta = 0.5 * nqd->bktype * sin(2.0 * M_PI / nqd->bktype); // weight factor
+ }
+
+ // accumulated weights
+ wts = alloc_compbuf(img->x, img->y, CB_VAL, 1);
+ // CoC radius buffer
+ crad = alloc_compbuf(img->x, img->y, CB_VAL, 1);
+
+ // if 'no_zbuf' flag set (which is always set if input is not an image),
+ // values are instead interpreted directly as blur radius values
+ if (nqd->no_zbuf) {
+ // to prevent *reaaallly* big radius values and impossible calculation times,
+ // limit the maximum to half the image width or height, whichever is smaller
+ float maxr = 0.5f*(float)MIN2(img->x, img->y);
+ for (p=0; p<(unsigned int)(img->x*img->y); p++) {
+ crad->rect[p] = zbuf ? (zbuf->rect[p]*nqd->scale) : inpval;
+ // bug #5921, limit minimum
+ crad->rect[p] = MAX2(1e-5f, crad->rect[p]);
+ crad->rect[p] = MIN2(crad->rect[p], maxr);
+ // if maxblur!=0, limit maximum
+ if (nqd->maxblur != 0.f) crad->rect[p] = MIN2(crad->rect[p], nqd->maxblur);
+ }
+ }
+ else {
+ // actual zbuffer.
+ // separate foreground from background CoC's
+ // then blur background and blend in again with foreground,
+ // improves the 'blurred foreground overlapping in-focus midground' sharp boundary problem.
+ // wts buffer here used for blendmask
+ maxfgc = 0.f; // maximum foreground CoC radius
+ for (y=0; y<img->y; y++) {
+ p = y * img->x;
+ for (x=0; x<img->x; x++) {
+ px = p + x;
+ iZ = (zbuf->rect[px]==0.f) ? 0.f : (1.f/zbuf->rect[px]);
+ crad->rect[px] = 0.5f*(aperture*(dof_sp*(cam_invfdist - iZ) - 1.f));
+ if (crad->rect[px] <= 0.f) {
+ wts->rect[px] = 1.f;
+ crad->rect[px] = -crad->rect[px];
+ if (crad->rect[px] > maxfgc) maxfgc = crad->rect[px];
+ }
+ else crad->rect[px] = wts->rect[px] = 0;
+ }
+ }
+
+ // fast blur...
+ // bug #6656 part 1, probably when previous node_composite.c was split into separate files, it was not properly updated
+ // to include recent cvs commits (well, at least not defocus node), so this part was missing...
+ wt = aperture*128.f;
+ IIR_gauss_single(crad, wt);
+ IIR_gauss_single(wts, wt);
+
+ // bug #6656 part 2a, although foreground blur is not based anymore on closest object,
+ // the rescaling op below was still based on that anyway, and unlike the comment in below code,
+ // the difference is therefore not always that small at all...
+ // so for now commented out, not sure if this is going to cause other future problems, lets just wait and see...
+ /*
+ // find new maximum to scale it back to original
+ // (could skip this, not strictly necessary, in general, difference is quite small, but just in case...)
+ nmaxc = 0;
+ for (p=0; p<(img->x*img->y); p++)
+ if (crad->rect[p] > nmaxc) nmaxc = crad->rect[p];
+ // rescale factor
+ scf = (nmaxc==0.f) ? 1.f: (maxfgc / nmaxc);
+ */
+
+ // and blend...
+ for (y=0; y<img->y; y++) {
+ p = y*img->x;
+ for (x=0; x<img->x; x++) {
+ px = p + x;
+ if (zbuf->rect[px]!=0.f) {
+ iZ = (zbuf->rect[px]==0.f) ? 0.f : (1.f/zbuf->rect[px]);
+
+ // bug #6656 part 2b, do not rescale
+ /*
+ bcrad = 0.5f*fabs(aperture*(dof_sp*(cam_invfdist - iZ) - 1.f));
+ // scale crad back to original maximum and blend
+ crad->rect[px] = bcrad + wts->rect[px]*(scf*crad->rect[px] - bcrad);
+ */
+ crad->rect[px] = 0.5f*fabs(aperture*(dof_sp*(cam_invfdist - iZ) - 1.f));
+
+ // 'bug' #6615, limit minimum radius to 1 pixel, not really a solution, but somewhat mitigates the problem
+ crad->rect[px] = MAX2(crad->rect[px], 0.5f);
+ // if maxblur!=0, limit maximum
+ if (nqd->maxblur != 0.f) crad->rect[px] = MIN2(crad->rect[px], nqd->maxblur);
+ }
+ else crad->rect[px] = 0.f;
+ // clear weights for next part
+ wts->rect[px] = 0.f;
+ }
+ // esc set by main calling process
+ if(node->exec & NODE_BREAK)
+ break;
+ }
+ }
+
+ //------------------------------------------------------------------
+ // main loop
+ for (y=0; y<img->y; y++) {
+ // some sort of visual feedback would be nice, or at least this text in the renderwin header
+ // but for now just print some info in the console every 8 scanlines.
+ if (((y & 7)==0) || (y==(img->y-1))) {
+ printf("\rdefocus: Processing Line %d of %d ... ", y+1, img->y);
+ fflush(stdout);
+ }
+ // esc set by main calling process
+ if(node->exec & NODE_BREAK)
+ break;
+
+ zp = y * img->x;
+ for (x=0; x<img->x; x++) {
+ cp = zp + x;
+ cp4 = cp * img->type;
+
+ // Circle of Confusion radius for current pixel
+ cR2 = ct_crad = crad->rect[cp];
+ // skip if zero (border render)
+ if (ct_crad==0.f) {
+ // related to bug #5921, forgot output image when skipping 0 radius values
+ new->rect[cp4] = img->rect[cp4];
+ if (new->type != CB_VAL) {
+ new->rect[cp4+1] = img->rect[cp4+1];
+ new->rect[cp4+2] = img->rect[cp4+2];
+ new->rect[cp4+3] = img->rect[cp4+3];
+ }
+ continue;
+ }
+ cR2 *= cR2;
+
+ // pixel color
+ ctcol = &img->rect[cp4];
+
+ if (!nqd->preview) {
+ int xs, xe, ys, ye;
+ float lwt, wtcol[4] = {0}, aacol[4] = {0};
+
+ // shape weight
+ if (nqd->bktype==0) // disk
+ wt = 1.f/((float)M_PI*cR2);
+ else
+ wt = 1.f/(cR2*bk_hn_theta);
+
+ // weighted color
+ wtcol[0] = wt*ctcol[0];
+ if (new->type != CB_VAL) {
+ wtcol[1] = wt*ctcol[1];
+ wtcol[2] = wt*ctcol[2];
+ wtcol[3] = wt*ctcol[3];
+ }
+
+ // macro for background blur overlap test
+ // unfortunately, since this is done per pixel,
+ // it has a very significant negative impact on processing time...
+ // (eg. aa disk blur without test: 112 sec, vs with test: 176 sec...)
+ // iff center blur radius > threshold
+ // and if overlap pixel in focus, do nothing, else add color/weigbt
+ // (threshold constant is dependant on amount of blur)
+ #define TESTBG1(c, w) {\
+ if (ct_crad > nqd->bthresh) {\
+ if (crad->rect[p] > nqd->bthresh) {\
+ new->rect[p] += c[0];\
+ wts->rect[p] += w;\
+ }\
+ }\
+ else {\
+ new->rect[p] += c[0];\
+ wts->rect[p] += w;\
+ }\
+ }
+ #define TESTBG4(c, w) {\
+ if (ct_crad > nqd->bthresh) {\
+ if (crad->rect[p] > nqd->bthresh) {\
+ new->rect[p4] += c[0];\
+ new->rect[p4+1] += c[1];\
+ new->rect[p4+2] += c[2];\
+ new->rect[p4+3] += c[3];\
+ wts->rect[p] += w;\
+ }\
+ }\
+ else {\
+ new->rect[p4] += c[0];\
+ new->rect[p4+1] += c[1];\
+ new->rect[p4+2] += c[2];\
+ new->rect[p4+3] += c[3];\
+ wts->rect[p] += w;\
+ }\
+ }
+ if (nqd->bktype == 0) {
+ // Disk
+ int _x, i, j, di;
+ float Dj, T;
+ // AA pixel
+ #define AAPIX(a, b) {\
+ int _ny = b;\
+ if ((_ny >= 0) && (_ny < new->y)) {\
+ int _nx = a;\
+ if ((_nx >=0) && (_nx < new->x)) {\
+ p = _ny*new->x + _nx;\
+ if (new->type==CB_VAL) {\
+ TESTBG1(aacol, lwt);\
+ }\
+ else {\
+ p4 = p * new->type;\
+ TESTBG4(aacol, lwt);\
+ }\
+ }\
+ }\
+ }
+ // circle scanline
+ #define CSCAN(a, b) {\
+ int _ny = y + b;\
+ if ((_ny >= 0) && (_ny < new->y)) {\
+ xs = x - a + 1;\
+ if (xs < 0) xs = 0;\
+ xe = x + a;\
+ if (xe > new->x) xe = new->x;\
+ p = _ny*new->x + xs;\
+ if (new->type==CB_VAL) {\
+ for (_x=xs; _x<xe; _x++, p++) TESTBG1(wtcol, wt);\
+ }\
+ else {\
+ p4 = p * new->type;\
+ for (_x=xs; _x<xe; _x++, p++, p4+=new->type) TESTBG4(wtcol, wt);\
+ }\
+ }\
+ }
+ i = ceil(ct_crad);
+ j = 0;
+ T = 0;
+ while (i > j) {
+ Dj = sqrt(cR2 - j*j);
+ Dj -= floor(Dj);
+ di = 0;
+ if (Dj > T) { i--; di = 1; }
+ T = Dj;
+ aacol[0] = wtcol[0]*Dj;
+ if (new->type != CB_VAL) {
+ aacol[1] = wtcol[1]*Dj;
+ aacol[2] = wtcol[2]*Dj;
+ aacol[3] = wtcol[3]*Dj;
+ }
+ lwt = wt*Dj;
+ if (i!=j) {
+ // outer pixels
+ AAPIX(x+j, y+i);
+ AAPIX(x+j, y-i);
+ if (j) {
+ AAPIX(x-j, y+i); // BL
+ AAPIX(x-j, y-i); // TL
+ }
+ if (di) { // only when i changed, interior of outer section
+ CSCAN(j, i); // bottom
+ CSCAN(j, -i); // top
+ }
+ }
+ // lower mid section
+ AAPIX(x+i, y+j);
+ if (i) AAPIX(x-i, y+j);
+ CSCAN(i, j);
+ // upper mid section
+ if (j) {
+ AAPIX(x+i, y-j);
+ if (i) AAPIX(x-i, y-j);
+ CSCAN(i, -j);
+ }
+ j++;
+ }
+ #undef CSCAN
+ #undef AAPIX
+ }
+ else {
+ // n-agonal
+ int ov, nv;
+ float mind, maxd, lwt;
+ ys = MAX2((int)floor(bkh_b[2]*ct_crad + y), 0);
+ ye = MIN2((int)ceil(bkh_b[3]*ct_crad + y), new->y - 1);
+ for (sy=ys; sy<=ye; sy++) {
+ float fxs = 1e10f, fxe = -1e10f;
+ float yf = (sy - y)/ct_crad;
+ int found = 0;
+ ov = len_bkh - 1;
+ mind = maxd = 0;
+ for (nv=0; nv<len_bkh; nv++) {
+ if ((BKH[nv].max_y >= yf) && (BKH[nv].min_y <= yf)) {
+ float tx = BKH[ov].x0 + BKH[nv].ls_x*(yf - BKH[ov].y0);
+ if (tx < fxs) { fxs = tx; mind = BKH[nv].ls_x; }
+ if (tx > fxe) { fxe = tx; maxd = BKH[nv].ls_x; }
+ if (++found == 2) break;
+ }
+ ov = nv;
+ }
+ if (found) {
+ fxs = fxs*ct_crad + x;
+ fxe = fxe*ct_crad + x;
+ xs = (int)floor(fxs), xe = (int)ceil(fxe);
+ // AA hack for first and last x pixel, near vertical edges only
+ if (fabs(mind) <= 1.f) {
+ if ((xs >= 0) && (xs < new->x)) {
+ lwt = 1.f-(fxs - xs);
+ aacol[0] = wtcol[0]*lwt;
+ p = xs + sy*new->x;
+ if (new->type==CB_VAL) {
+ lwt *= wt;
+ TESTBG1(aacol, lwt);
+ }
+ else {
+ p4 = p * new->type;
+ aacol[1] = wtcol[1]*lwt;
+ aacol[2] = wtcol[2]*lwt;
+ aacol[3] = wtcol[3]*lwt;
+ lwt *= wt;
+ TESTBG4(aacol, lwt);
+ }
+ }
+ }
+ if (fabs(maxd) <= 1.f) {
+ if ((xe >= 0) && (xe < new->x)) {
+ lwt = 1.f-(xe - fxe);
+ aacol[0] = wtcol[0]*lwt;
+ p = xe + sy*new->x;
+ if (new->type==CB_VAL) {
+ lwt *= wt;
+ TESTBG1(aacol, lwt);
+ }
+ else {
+ p4 = p * new->type;
+ aacol[1] = wtcol[1]*lwt;
+ aacol[2] = wtcol[2]*lwt;
+ aacol[3] = wtcol[3]*lwt;
+ lwt *= wt;
+ TESTBG4(aacol, lwt);
+ }
+ }
+ }
+ xs = MAX2(xs+1, 0);
+ xe = MIN2(xe, new->x);
+ // remaining interior scanline
+ p = sy*new->x + xs;
+ if (new->type==CB_VAL) {
+ for (sx=xs; sx<xe; sx++, p++) TESTBG1(wtcol, wt);
+ }
+ else {
+ p4 = p * new->type;
+ for (sx=xs; sx<xe; sx++, p++, p4+=new->type) TESTBG4(wtcol, wt);
+ }
+ }
+ }
+
+ // now traverse in opposite direction, y scanlines,
+ // but this time only draw the near horizontal edges,
+ // applying same AA hack as above
+ xs = MAX2((int)floor(bkh_b[0]*ct_crad + x), 0);
+ xe = MIN2((int)ceil(bkh_b[1]*ct_crad + x), img->x - 1);
+ for (sx=xs; sx<=xe; sx++) {
+ float xf = (sx - x)/ct_crad;
+ float fys = 1e10f, fye = -1e10f;
+ int found = 0;
+ ov = len_bkh - 1;
+ mind = maxd = 0;
+ for (nv=0; nv<len_bkh; nv++) {
+ if ((BKH[nv].max_x >= xf) && (BKH[nv].min_x <= xf)) {
+ float ty = BKH[ov].y0 + BKH[nv].ls_y*(xf - BKH[ov].x0);
+ if (ty < fys) { fys = ty; mind = BKH[nv].ls_y; }
+ if (ty > fye) { fye = ty; maxd = BKH[nv].ls_y; }
+ if (++found == 2) break;
+ }
+ ov = nv;
+ }
+ if (found) {
+ fys = fys*ct_crad + y;
+ fye = fye*ct_crad + y;
+ // near horizontal edges only, line slope <= 1
+ if (fabs(mind) <= 1.f) {
+ int iys = (int)floor(fys);
+ if ((iys >= 0) && (iys < new->y)) {
+ lwt = 1.f - (fys - iys);
+ aacol[0] = wtcol[0]*lwt;
+ p = sx + iys*new->x;
+ if (new->type==CB_VAL) {
+ lwt *= wt;
+ TESTBG1(aacol, lwt);
+ }
+ else {
+ p4 = p * new->type;
+ aacol[1] = wtcol[1]*lwt;
+ aacol[2] = wtcol[2]*lwt;
+ aacol[3] = wtcol[3]*lwt;
+ lwt *= wt;
+ TESTBG4(aacol, lwt);
+ }
+ }
+ }
+ if (fabs(maxd) <= 1.f) {
+ int iye = ceil(fye);
+ if ((iye >= 0) && (iye < new->y)) {
+ lwt = 1.f - (iye - fye);
+ aacol[0] = wtcol[0]*lwt;
+ p = sx + iye*new->x;
+ if (new->type==CB_VAL) {
+ lwt *= wt;
+ TESTBG1(aacol, lwt);
+ }
+ else {
+ p4 = p * new->type;
+ aacol[1] = wtcol[1]*lwt;
+ aacol[2] = wtcol[2]*lwt;
+ aacol[3] = wtcol[3]*lwt;
+ lwt *= wt;
+ TESTBG4(aacol, lwt);
+ }
+ }
+ }
+ }
+ }
+
+ }
+ #undef TESTBG4
+ #undef TESTBG1
+
+ }
+ else {
+ // sampled, simple rejection sampling here, good enough
+ unsigned int maxsam, s, ui = BLI_rand()*BLI_rand();
+ float wcor, cpr = BLI_frand();
+ if (nqd->no_zbuf)
+ maxsam = nqd->samples; // no zbuffer input, use sample value directly
+ else {
+ // depth adaptive sampling hack, the more out of focus, the more samples taken, 16 minimum.
+ maxsam = (int)(0.5f + nqd->samples*(1.f-(float)exp(-fabs(zbuf->rect[cp] - cam_fdist))));
+ if (maxsam < 16) maxsam = 16;
+ }
+ wcor = 1.f/(float)maxsam;
+ for (s=0; s<maxsam; ++s) {
+ u = ct_crad*(2.f*RI_vdC(s, ui) - 1.f);
+ v = ct_crad*(2.f*(s + cpr)/(float)maxsam - 1.f);
+ sx = (int)(x + u + 0.5f), sy = (int)(y + v + 0.5f);
+ if ((sx<0) || (sx >= new->x) || (sy<0) || (sy >= new->y)) continue;
+ p = sx + sy*new->x;
+ p4 = p * new->type;
+ if (nqd->bktype==0) // Disk
+ lwt = ((u*u + v*v)<=cR2) ? wcor : 0.f;
+ else // AA not needed here
+ lwt = wcor * getWeight(BKH, len_bkh, u, v, ct_crad, inradsq);
+ // prevent background bleeding onto in-focus pixels, user-option
+ if (ct_crad > nqd->bthresh) { // if center blur > threshold
+ if (crad->rect[p] > nqd->bthresh) { // if overlap pixel in focus, do nothing, else add color/weigbt
+ new->rect[p4] += ctcol[0] * lwt;
+ if (new->type != CB_VAL) {
+ new->rect[p4+1] += ctcol[1] * lwt;
+ new->rect[p4+2] += ctcol[2] * lwt;
+ new->rect[p4+3] += ctcol[3] * lwt;
+ }
+ wts->rect[p] += lwt;
+ }
+ }
+ else {
+ new->rect[p4] += ctcol[0] * lwt;
+ if (new->type != CB_VAL) {
+ new->rect[p4+1] += ctcol[1] * lwt;
+ new->rect[p4+2] += ctcol[2] * lwt;
+ new->rect[p4+3] += ctcol[3] * lwt;
+ }
+ wts->rect[p] += lwt;
+ }
+ }
+ }
+
+ }
+ }
+
+ // finally, normalize
+ for (y=0; y<new->y; y++) {
+ p = y * new->x;
+ p4 = p * new->type;
+ for (x=0; x<new->x; x++) {
+ float dv = (wts->rect[p]==0.f) ? 1.f : (1.f/wts->rect[p]);
+ new->rect[p4] *= dv;
+ if (new->type!=CB_VAL) {
+ new->rect[p4+1] *= dv;
+ new->rect[p4+2] *= dv;
+ new->rect[p4+3] *= dv;
+ }
+ p++;
+ p4 += new->type;
+ }
+ }
+
+ free_compbuf(crad);
+ free_compbuf(wts);
+
+ printf("Done\n");
+}
+
+
+static void node_composit_exec_defocus(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ CompBuf *new, *old, *zbuf_use = NULL, *img = in[0]->data, *zbuf = in[1]->data;
+ NodeDefocus *nqd = node->storage;
+
+ if ((img==NULL) || (out[0]->hasoutput==0)) return;
+
+ // if image not valid type or fstop==infinite (128), nothing to do, pass in to out
+ if (((img->type!=CB_RGBA) && (img->type!=CB_VAL)) || ((nqd->no_zbuf==0) && (nqd->fstop==128.f))) {
+ new = alloc_compbuf(img->x, img->y, img->type, 0);
+ new->rect = img->rect;
+ out[0]->data = new;
+ return;
+ }
+
+ if (zbuf!=NULL) {
+ // Zbuf input, check to make sure, single channel, same size
+ // doesn't have to be actual zbuffer, but must be value type
+ if ((zbuf->x != img->x) || (zbuf->y != img->y)) {
+ // could do a scale here instead...
+ printf("Z input must be same size as image !\n");
+ return;
+ }
+ zbuf_use = typecheck_compbuf(zbuf, CB_VAL);
+ }
+ else nqd->no_zbuf = 1; // no zbuffer input
+
+ // ok, process
+ old = img;
+ if (nqd->gamco) {
+ // gamma correct, blender func is simplified, fixed value & RGBA only, should make user param
+ old = dupalloc_compbuf(img);
+ gamma_correct_compbuf(old, 0);
+ }
+
+ new = alloc_compbuf(old->x, old->y, old->type, 1);
+ defocus_blur(node, new, old, zbuf_use, in[1]->vec[0]*nqd->scale);
+
+ if (nqd->gamco) {
+ gamma_correct_compbuf(new, 1);
+ free_compbuf(old);
+ }
+ if(node->exec & NODE_BREAK) {
+ free_compbuf(new);
+ new= NULL;
+ }
+ out[0]->data = new;
+ if (zbuf_use && (zbuf_use != zbuf)) free_compbuf(zbuf_use);
+}
+
+static void node_composit_init_defocus(bNode* node)
+{
+ /* qdn: defocus node */
+ NodeDefocus *nbd = MEM_callocN(sizeof(NodeDefocus), "node defocus data");
+ nbd->bktype = 0;
+ nbd->rotation = 0.f;
+ nbd->preview = 1;
+ nbd->gamco = 0;
+ nbd->samples = 16;
+ nbd->fstop = 128.f;
+ nbd->maxblur = 0;
+ nbd->bthresh = 1.f;
+ nbd->scale = 1.f;
+ nbd->no_zbuf = 1;
+ node->storage = nbd;
+}
+
+bNodeType cmp_node_defocus = {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_DEFOCUS,
+ /* name */ "Defocus",
+ /* width+range */ 150, 120, 200,
+ /* class+opts */ NODE_CLASS_OP_FILTER, NODE_OPTIONS,
+ /* input sock */ cmp_node_defocus_in,
+ /* output sock */ cmp_node_defocus_out,
+ /* storage */ "NodeDefocus",
+ /* execfunc */ node_composit_exec_defocus,
+ /* butfunc */ NULL,
+ /* initfunc */ node_composit_init_defocus,
+ /* freestoragefunc */ node_free_standard_storage,
+ /* copystoragefunc */ node_copy_standard_storage,
+ /* id */ NULL
+};
+
+
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_diffMatte.c b/source/blender/nodes/intern/CMP_nodes/CMP_diffMatte.c
new file mode 100644
index 00000000000..ade2111f246
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_diffMatte.c
@@ -0,0 +1,217 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../CMP_util.h"
+
+/* ******************* channel Difference Matte ********************************* */
+static bNodeSocketType cmp_node_diff_matte_in[]={
+ {SOCK_RGBA,1,"Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ {SOCK_RGBA,1,"Key Color", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ {-1,0,""}
+};
+
+static bNodeSocketType cmp_node_diff_matte_out[]={
+ {SOCK_RGBA,0,"Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ {SOCK_VALUE,0,"Matte",0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ {-1,0,""}
+};
+
+/* note, keyvals is passed on from caller as stack array */
+/* might have been nicer as temp struct though... */
+static void do_diff_matte(bNode *node, float *colorbuf, float *inbuf, float *keyvals)
+{
+ NodeChroma *c= (NodeChroma *)node->storage;
+ float *keymin= keyvals;
+ float *keymax= keyvals+3;
+ float *key= keyvals+6;
+ float tolerance= keyvals[9];
+ float distance, alpha;
+
+ /*process the pixel if it is close to the key or already transparent*/
+ if(((colorbuf[0]>keymin[0] && colorbuf[0]<keymax[0]) &&
+ (colorbuf[1]>keymin[1] && colorbuf[1]<keymax[1]) &&
+ (colorbuf[2]>keymin[2] && colorbuf[2]<keymax[2])) || inbuf[3]<1.0f) {
+
+ /*true distance from key*/
+ distance= sqrt((colorbuf[0]-key[0])*(colorbuf[0]-key[0])+
+ (colorbuf[1]-key[1])*(colorbuf[1]-key[1])+
+ (colorbuf[2]-key[2])*(colorbuf[2]-key[2]));
+
+ /*is it less transparent than the prevous pixel*/
+ alpha= distance/tolerance;
+ if(alpha > inbuf[3]) alpha= inbuf[3];
+ if(alpha > c->fstrength) alpha= 0.0f;
+
+ /*clamp*/
+ if (alpha>1.0f) alpha=1.0f;
+ if (alpha<0.0f) alpha=0.0f;
+
+ /*premultiplied picture*/
+ colorbuf[3]= alpha;
+ }
+ else {
+ /*foreground object*/
+ colorbuf[3]= inbuf[3];
+ }
+}
+
+static void node_composit_exec_diff_matte(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /*
+ Losely based on the Sequencer chroma key plug-in, but enhanced to work in other color spaces and
+ uses a differnt difference function (suggested in forums of vfxtalk.com).
+ */
+ CompBuf *workbuf;
+ CompBuf *inbuf;
+ NodeChroma *c;
+ float keyvals[10];
+ float *keymin= keyvals;
+ float *keymax= keyvals+3;
+ float *key= keyvals+6;
+ float *tolerance= keyvals+9;
+ float t[3];
+
+ /*is anything connected?*/
+ if(out[0]->hasoutput==0 && out[1]->hasoutput==0) return;
+ /*must have an image imput*/
+ if(in[0]->data==NULL) return;
+
+ inbuf=typecheck_compbuf(in[0]->data, CB_RGBA);
+
+ c=node->storage;
+ workbuf=dupalloc_compbuf(inbuf);
+
+ /*use the input color*/
+ key[0]= in[1]->vec[0];
+ key[1]= in[1]->vec[1];
+ key[2]= in[1]->vec[2];
+
+ /*get the tolerances from the UI*/
+ t[0]=c->t1;
+ t[1]=c->t2;
+ t[2]=c->t3;
+
+ /*convert to colorspace*/
+ switch(node->custom1) {
+ case 1: /*RGB*/
+ break;
+ case 2: /*HSV*/
+ /*convert the key (in place)*/
+ rgb_to_hsv(key[0], key[1], key[2], &key[0], &key[1], &key[2]);
+ composit1_pixel_processor(node, workbuf, inbuf, in[1]->vec, do_rgba_to_hsva, CB_RGBA);
+ break;
+ case 3: /*YUV*/
+ rgb_to_yuv(key[0], key[1], key[2], &key[0], &key[1], &key[2]);
+ composit1_pixel_processor(node, workbuf, inbuf, in[1]->vec, do_rgba_to_yuva, CB_RGBA);
+ break;
+ case 4: /*YCC*/
+ rgb_to_ycc(key[0], key[1], key[2], &key[0], &key[1], &key[2]);
+ composit1_pixel_processor(node, workbuf, inbuf, in[1]->vec, do_rgba_to_ycca, CB_RGBA);
+ /*account for ycc is on a 0..255 scale*/
+ t[0]= c->t1*255.0;
+ t[1]= c->t2*255.0;
+ t[2]= c->t3*255.0;
+ break;
+ default:
+ break;
+ }
+
+ /*find min/max tolerances*/
+ keymin[0]= key[0]-t[0];
+ keymin[1]= key[1]-t[1];
+ keymin[2]= key[2]-t[2];
+ keymax[0]= key[0]+t[0];
+ keymax[1]= key[1]+t[1];
+ keymax[2]= key[2]+t[2];
+
+ /*tolerance*/
+ *tolerance= sqrt((t[0])*(t[0])+
+ (t[1])*(t[1])+
+ (t[2])*(t[2]));
+
+ /* note, processor gets a keyvals array passed on as buffer constant */
+ composit2_pixel_processor(node, workbuf, workbuf, in[0]->vec, NULL, keyvals, do_diff_matte, CB_RGBA, CB_VAL);
+
+ /*convert back to RGB colorspace*/
+ switch(node->custom1) {
+ case 1: /*RGB*/
+ composit1_pixel_processor(node, workbuf, workbuf, in[1]->vec, do_copy_rgba, CB_RGBA);
+ break;
+ case 2: /*HSV*/
+ composit1_pixel_processor(node, workbuf, workbuf, in[1]->vec, do_hsva_to_rgba, CB_RGBA);
+ break;
+ case 3: /*YUV*/
+ composit1_pixel_processor(node, workbuf, workbuf, in[1]->vec, do_yuva_to_rgba, CB_RGBA);
+ break;
+ case 4: /*YCC*/
+ composit1_pixel_processor(node, workbuf, workbuf, in[1]->vec, do_ycca_to_rgba, CB_RGBA);
+ break;
+ default:
+ break;
+ }
+
+ out[0]->data=workbuf;
+ if(out[1]->hasoutput)
+ out[1]->data=valbuf_from_rgbabuf(workbuf, CHAN_A);
+ generate_preview(node, workbuf);
+
+ if(inbuf!=in[0]->data)
+ free_compbuf(inbuf);
+}
+
+static void node_composit_init_diff_matte(bNode *node)
+{
+ NodeChroma *c= MEM_callocN(sizeof(NodeChroma), "node chroma");
+ node->storage= c;
+ c->t1= 0.01f;
+ c->t2= 0.01f;
+ c->t3= 0.01f;
+ c->fsize= 0.0f;
+ c->fstrength= 0.0f;
+ node->custom1= 1; /* RGB */
+}
+
+bNodeType cmp_node_diff_matte={
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_DIFF_MATTE,
+ /* name */ "Difference Key",
+ /* width+range */ 200, 80, 250,
+ /* class+opts */ NODE_CLASS_MATTE, NODE_PREVIEW|NODE_OPTIONS,
+ /* input sock */ cmp_node_diff_matte_in,
+ /* output sock */ cmp_node_diff_matte_out,
+ /* storage */ "NodeChroma",
+ /* execfunc */ node_composit_exec_diff_matte,
+ /* butfunc */ NULL,
+ /* initfunc */ node_composit_init_diff_matte,
+ /* freestoragefunc */ node_free_standard_storage,
+ /* copystoragefunc */ node_copy_standard_storage,
+ /* id */ NULL
+};
+
+
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_dilate.c b/source/blender/nodes/intern/CMP_nodes/CMP_dilate.c
new file mode 100644
index 00000000000..81430436227
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_dilate.c
@@ -0,0 +1,163 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../CMP_util.h"
+
+
+/* **************** Dilate/Erode ******************** */
+
+static bNodeSocketType cmp_node_dilateerode_in[]= {
+ { SOCK_VALUE, 1, "Mask", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketType cmp_node_dilateerode_out[]= {
+ { SOCK_VALUE, 0, "Mask", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void morpho_dilate(CompBuf *cbuf)
+{
+ int x, y;
+ float *p, *rectf = cbuf->rect;
+
+ for (y=0; y < cbuf->y; y++) {
+ for (x=0; x < cbuf->x-1; x++) {
+ p = rectf + cbuf->x*y + x;
+ *p = MAX2(*p, *(p + 1));
+ }
+ }
+
+ for (y=0; y < cbuf->y; y++) {
+ for (x=cbuf->x-1; x >= 1; x--) {
+ p = rectf + cbuf->x*y + x;
+ *p = MAX2(*p, *(p - 1));
+ }
+ }
+
+ for (x=0; x < cbuf->x; x++) {
+ for (y=0; y < cbuf->y-1; y++) {
+ p = rectf + cbuf->x*y + x;
+ *p = MAX2(*p, *(p + cbuf->x));
+ }
+ }
+
+ for (x=0; x < cbuf->x; x++) {
+ for (y=cbuf->y-1; y >= 1; y--) {
+ p = rectf + cbuf->x*y + x;
+ *p = MAX2(*p, *(p - cbuf->x));
+ }
+ }
+}
+
+static void morpho_erode(CompBuf *cbuf)
+{
+ int x, y;
+ float *p, *rectf = cbuf->rect;
+
+ for (y=0; y < cbuf->y; y++) {
+ for (x=0; x < cbuf->x-1; x++) {
+ p = rectf + cbuf->x*y + x;
+ *p = MIN2(*p, *(p + 1));
+ }
+ }
+
+ for (y=0; y < cbuf->y; y++) {
+ for (x=cbuf->x-1; x >= 1; x--) {
+ p = rectf + cbuf->x*y + x;
+ *p = MIN2(*p, *(p - 1));
+ }
+ }
+
+ for (x=0; x < cbuf->x; x++) {
+ for (y=0; y < cbuf->y-1; y++) {
+ p = rectf + cbuf->x*y + x;
+ *p = MIN2(*p, *(p + cbuf->x));
+ }
+ }
+
+ for (x=0; x < cbuf->x; x++) {
+ for (y=cbuf->y-1; y >= 1; y--) {
+ p = rectf + cbuf->x*y + x;
+ *p = MIN2(*p, *(p - cbuf->x));
+ }
+ }
+
+}
+
+static void node_composit_exec_dilateerode(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order in: mask */
+ /* stack order out: mask */
+ if(out[0]->hasoutput==0)
+ return;
+
+ /* input no image? then only color operation */
+ if(in[0]->data==NULL) {
+ out[0]->vec[0] = out[0]->vec[1] = out[0]->vec[2] = 0.0f;
+ out[0]->vec[3] = 0.0f;
+ }
+ else {
+ /* make output size of input image */
+ CompBuf *cbuf= typecheck_compbuf(in[0]->data, CB_VAL);
+ CompBuf *stackbuf= dupalloc_compbuf(cbuf);
+ short i;
+
+ if (node->custom2 > 0) { // positive, dilate
+ for (i = 0; i < node->custom2; i++)
+ morpho_dilate(stackbuf);
+ } else if (node->custom2 < 0) { // negative, erode
+ for (i = 0; i > node->custom2; i--)
+ morpho_erode(stackbuf);
+ }
+
+ if(cbuf!=in[0]->data)
+ free_compbuf(cbuf);
+
+ out[0]->data= stackbuf;
+ }
+}
+
+bNodeType cmp_node_dilateerode= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_DILATEERODE,
+ /* name */ "Dilate/Erode",
+ /* width+range */ 130, 100, 320,
+ /* class+opts */ NODE_CLASS_OP_FILTER, NODE_OPTIONS,
+ /* input sock */ cmp_node_dilateerode_in,
+ /* output sock */ cmp_node_dilateerode_out,
+ /* storage */ "",
+ /* execfunc */ node_composit_exec_dilateerode,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+};
+
+
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_displace.c b/source/blender/nodes/intern/CMP_nodes/CMP_displace.c
new file mode 100644
index 00000000000..0ec15d9eb77
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_displace.c
@@ -0,0 +1,163 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../CMP_util.h"
+
+
+/* **************** Displace ******************** */
+
+static bNodeSocketType cmp_node_displace_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VECTOR, 1, "Vector", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 1, "X Scale", 0.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f},
+ { SOCK_VALUE, 1, "Y Scale", 0.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketType cmp_node_displace_out[]= {
+ { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void do_displace(CompBuf *stackbuf, CompBuf *cbuf, CompBuf *vecbuf, float *veccol, float *xscale, float *yscale)
+{
+ ImBuf *ibuf;
+ int x, y, sx, sy;
+ float dx=0.0, dy=0.0;
+ float dspx, dspy;
+ float uv[2];
+
+ float *out= stackbuf->rect, *vec=vecbuf->rect, *in= cbuf->rect;
+ float *vp, *vpnext, *vpprev;
+
+ int row = 3*vecbuf->x;
+
+ /* ibuf needed for sampling */
+ ibuf= IMB_allocImBuf(cbuf->x, cbuf->y, 32, 0, 0);
+ ibuf->rect_float= cbuf->rect;
+
+ vec = vecbuf->rect;
+
+ sx= stackbuf->x;
+ sy= stackbuf->y;
+
+ for(y=0; y<sy; y++) {
+ for(x= 0; x< sx; x++, out+=4, in+=4, vec+=3) {
+
+ /* the x-xrad stuff is a bit weird, but i seem to need it otherwise
+ * my returned pixels are offset weirdly */
+ vp = compbuf_get_pixel(vecbuf, veccol, x-vecbuf->xrad, y-vecbuf->yrad, vecbuf->xrad, vecbuf->yrad);
+
+ /* find the new displaced co-ords, also correcting for translate offset */
+ dspx = x - (*xscale * vp[0]);
+ dspy = y - (*yscale * vp[1]);
+
+ /* convert image space to 0.0-1.0 UV space for sampling, correcting for translate offset */
+ uv[0] = dspx / (float)sx;
+ uv[1] = dspy / (float)sy;
+
+ if(x>0 && x< vecbuf->x-1 && y>0 && y< vecbuf->y-1) {
+ vpnext = vp+row;
+ vpprev = vp-row;
+
+ /* adaptive sampling, X channel */
+ dx= 0.5f*(fabs(vp[0]-vp[-3]) + fabs(vp[0]-vp[3]));
+
+ dx+= 0.25f*(fabs(vp[0]-vpprev[-3]) + fabs(vp[0]-vpnext[-3]));
+ dx+= 0.25f*(fabs(vp[0]-vpprev[+3]) + fabs(vp[0]-vpnext[+3]));
+
+ /* adaptive sampling, Y channel */
+ dy= 0.5f*(fabs(vp[1]-vp[-row+1]) + fabs(vp[1]-vp[row+1]));
+
+ dy+= 0.25f*(fabs(vp[1]-vpprev[+1-3]) + fabs(vp[1]-vpnext[+1-3]));
+ dy+= 0.25f*(fabs(vp[1]-vpprev[+1+3]) + fabs(vp[1]-vpnext[+1+3]));
+
+ /* scaled down to prevent blurriness */
+ /* 8: magic number, provides a good level of sharpness without getting too aliased */
+ dx /= 8;
+ dy /= 8;
+ }
+
+ /* should use mipmap */
+ if(dx > 0.006f) dx= 0.006f;
+ if(dy > 0.006f) dy= 0.006f;
+ if ((vp[0]> 0.0) && (dx < 0.004)) dx = 0.004;
+ if ((vp[1]> 0.0) && (dy < 0.004)) dy = 0.004;
+
+
+ ibuf_sample(ibuf, uv[0], uv[1], dx, dy, out);
+ }
+ }
+
+ IMB_freeImBuf(ibuf);
+}
+
+
+static void node_composit_exec_displace(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ if(out[0]->hasoutput==0)
+ return;
+
+ if(in[0]->data && in[1]->data) {
+ CompBuf *cbuf= in[0]->data;
+ CompBuf *vecbuf= in[1]->data;
+ CompBuf *stackbuf;
+
+ cbuf= typecheck_compbuf(cbuf, CB_RGBA);
+ vecbuf= typecheck_compbuf(vecbuf, CB_VEC3);
+ stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */
+
+ do_displace(stackbuf, cbuf, vecbuf, in[1]->vec, in[2]->vec, in[3]->vec);
+
+ out[0]->data= stackbuf;
+
+
+ if(cbuf!=in[0]->data)
+ free_compbuf(cbuf);
+ if(vecbuf!=in[1]->data)
+ free_compbuf(vecbuf);
+ }
+}
+
+bNodeType cmp_node_displace= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_DISPLACE,
+ /* name */ "Displace",
+ /* width+range */ 140, 100, 320,
+ /* class+opts */ NODE_CLASS_DISTORT, NODE_OPTIONS,
+ /* input sock */ cmp_node_displace_in,
+ /* output sock */ cmp_node_displace_out,
+ /* storage */ "",
+ /* execfunc */ node_composit_exec_displace,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+};
+
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_filter.c b/source/blender/nodes/intern/CMP_nodes/CMP_filter.c
new file mode 100644
index 00000000000..46a9d747ac1
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_filter.c
@@ -0,0 +1,235 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../CMP_util.h"
+
+/* **************** FILTER ******************** */
+static bNodeSocketType cmp_node_filter_in[]= {
+ { SOCK_VALUE, 1, "Fac", 1.0f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketType cmp_node_filter_out[]= {
+ { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void do_filter_edge(CompBuf *out, CompBuf *in, float *filter, float fac)
+{
+ float *row1, *row2, *row3;
+ float *fp, f1, f2, mfac= 1.0f-fac;
+ int rowlen, x, y, c, pix= in->type;
+
+ rowlen= in->x;
+
+ for(y=0; y<in->y; y++) {
+ /* setup rows */
+ if(y==0) row1= in->rect;
+ else row1= in->rect + pix*(y-1)*rowlen;
+
+ row2= in->rect + y*pix*rowlen;
+
+ if(y==in->y-1) row3= row2;
+ else row3= row2 + pix*rowlen;
+
+ fp= out->rect + pix*y*rowlen;
+
+ if(pix==CB_RGBA) {
+ QUATCOPY(fp, row2);
+ fp+= pix;
+
+ for(x=2; x<rowlen; x++) {
+ for(c=0; c<3; c++) {
+ f1= filter[0]*row1[0] + filter[1]*row1[4] + filter[2]*row1[8] + filter[3]*row2[0] + filter[4]*row2[4] + filter[5]*row2[8] + filter[6]*row3[0] + filter[7]*row3[4] + filter[8]*row3[8];
+ f2= filter[0]*row1[0] + filter[3]*row1[4] + filter[6]*row1[8] + filter[1]*row2[0] + filter[4]*row2[4] + filter[7]*row2[8] + filter[2]*row3[0] + filter[5]*row3[4] + filter[8]*row3[8];
+ fp[0]= mfac*row2[4] + fac*sqrt(f1*f1 + f2*f2);
+ fp++; row1++; row2++; row3++;
+ }
+ fp[0]= row2[4];
+ /* no alpha... will clear it completely */
+ fp++; row1++; row2++; row3++;
+ }
+ QUATCOPY(fp, row2+4);
+ }
+ else if(pix==CB_VAL) {
+ for(x=2; x<rowlen; x++) {
+ f1= filter[0]*row1[0] + filter[1]*row1[1] + filter[2]*row1[2] + filter[3]*row2[0] + filter[4]*row2[1] + filter[5]*row2[2] + filter[6]*row3[0] + filter[7]*row3[1] + filter[8]*row3[2];
+ f2= filter[0]*row1[0] + filter[3]*row1[1] + filter[6]*row1[2] + filter[1]*row2[0] + filter[4]*row2[1] + filter[7]*row2[2] + filter[2]*row3[0] + filter[5]*row3[1] + filter[8]*row3[2];
+ fp[0]= mfac*row2[1] + fac*sqrt(f1*f1 + f2*f2);
+ fp++; row1++; row2++; row3++;
+ }
+ }
+ }
+}
+
+static void do_filter3(CompBuf *out, CompBuf *in, float *filter, float fac)
+{
+ float *row1, *row2, *row3;
+ float *fp, mfac= 1.0f-fac;
+ int rowlen, x, y, c;
+ int pixlen= in->type;
+
+ rowlen= in->x;
+
+ for(y=0; y<in->y; y++) {
+ /* setup rows */
+ if(y==0) row1= in->rect;
+ else row1= in->rect + pixlen*(y-1)*rowlen;
+
+ row2= in->rect + y*pixlen*rowlen;
+
+ if(y==in->y-1) row3= row2;
+ else row3= row2 + pixlen*rowlen;
+
+ fp= out->rect + pixlen*(y)*rowlen;
+
+ if(pixlen==1) {
+ fp[0]= row2[0];
+ fp+= 1;
+
+ for(x=2; x<rowlen; x++) {
+ fp[0]= mfac*row2[1] + fac*(filter[0]*row1[0] + filter[1]*row1[1] + filter[2]*row1[2] + filter[3]*row2[0] + filter[4]*row2[1] + filter[5]*row2[2] + filter[6]*row3[0] + filter[7]*row3[1] + filter[8]*row3[2]);
+ fp++; row1++; row2++; row3++;
+ }
+ fp[0]= row2[1];
+ }
+ else if(pixlen==2) {
+ fp[0]= row2[0];
+ fp[1]= row2[1];
+ fp+= 2;
+
+ for(x=2; x<rowlen; x++) {
+ for(c=0; c<2; c++) {
+ fp[0]= mfac*row2[2] + fac*(filter[0]*row1[0] + filter[1]*row1[2] + filter[2]*row1[4] + filter[3]*row2[0] + filter[4]*row2[2] + filter[5]*row2[4] + filter[6]*row3[0] + filter[7]*row3[2] + filter[8]*row3[4]);
+ fp++; row1++; row2++; row3++;
+ }
+ }
+ fp[0]= row2[2];
+ fp[1]= row2[3];
+ }
+ else if(pixlen==3) {
+ VECCOPY(fp, row2);
+ fp+= 3;
+
+ for(x=2; x<rowlen; x++) {
+ for(c=0; c<3; c++) {
+ fp[0]= mfac*row2[3] + fac*(filter[0]*row1[0] + filter[1]*row1[3] + filter[2]*row1[6] + filter[3]*row2[0] + filter[4]*row2[3] + filter[5]*row2[6] + filter[6]*row3[0] + filter[7]*row3[3] + filter[8]*row3[6]);
+ fp++; row1++; row2++; row3++;
+ }
+ }
+ VECCOPY(fp, row2+3);
+ }
+ else {
+ QUATCOPY(fp, row2);
+ fp+= 4;
+
+ for(x=2; x<rowlen; x++) {
+ for(c=0; c<4; c++) {
+ fp[0]= mfac*row2[4] + fac*(filter[0]*row1[0] + filter[1]*row1[4] + filter[2]*row1[8] + filter[3]*row2[0] + filter[4]*row2[4] + filter[5]*row2[8] + filter[6]*row3[0] + filter[7]*row3[4] + filter[8]*row3[8]);
+ fp++; row1++; row2++; row3++;
+ }
+ }
+ QUATCOPY(fp, row2+4);
+ }
+ }
+}
+
+
+static void node_composit_exec_filter(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ static float soft[9]= {1/16.0f, 2/16.0f, 1/16.0f, 2/16.0f, 4/16.0f, 2/16.0f, 1/16.0f, 2/16.0f, 1/16.0f};
+ float sharp[9]= {-1,-1,-1,-1,9,-1,-1,-1,-1};
+ float laplace[9]= {-1/8.0f, -1/8.0f, -1/8.0f, -1/8.0f, 1.0f, -1/8.0f, -1/8.0f, -1/8.0f, -1/8.0f};
+ float sobel[9]= {1,2,1,0,0,0,-1,-2,-1};
+ float prewitt[9]= {1,1,1,0,0,0,-1,-1,-1};
+ float kirsch[9]= {5,5,5,-3,-3,-3,-2,-2,-2};
+ float shadow[9]= {1,2,1,0,1,0,-1,-2,-1};
+
+ if(out[0]->hasoutput==0) return;
+
+ /* stack order in: Image */
+ /* stack order out: Image */
+
+ if(in[1]->data) {
+ /* make output size of first available input image */
+ CompBuf *cbuf= in[1]->data;
+ CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, cbuf->type, 1); /* allocs */
+
+ /* warning note: xof and yof are applied in pixelprocessor, but should be copied otherwise? */
+ stackbuf->xof= cbuf->xof;
+ stackbuf->yof= cbuf->yof;
+
+ switch(node->custom1) {
+ case CMP_FILT_SOFT:
+ do_filter3(stackbuf, cbuf, soft, in[0]->vec[0]);
+ break;
+ case CMP_FILT_SHARP:
+ do_filter3(stackbuf, cbuf, sharp, in[0]->vec[0]);
+ break;
+ case CMP_FILT_LAPLACE:
+ do_filter3(stackbuf, cbuf, laplace, in[0]->vec[0]);
+ break;
+ case CMP_FILT_SOBEL:
+ do_filter_edge(stackbuf, cbuf, sobel, in[0]->vec[0]);
+ break;
+ case CMP_FILT_PREWITT:
+ do_filter_edge(stackbuf, cbuf, prewitt, in[0]->vec[0]);
+ break;
+ case CMP_FILT_KIRSCH:
+ do_filter_edge(stackbuf, cbuf, kirsch, in[0]->vec[0]);
+ break;
+ case CMP_FILT_SHADOW:
+ do_filter3(stackbuf, cbuf, shadow, in[0]->vec[0]);
+ break;
+ }
+
+ out[0]->data= stackbuf;
+ }
+}
+
+
+bNodeType cmp_node_filter= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_FILTER,
+ /* name */ "Filter",
+ /* width+range */ 80, 40, 120,
+ /* class+opts */ NODE_CLASS_OP_FILTER, NODE_OPTIONS,
+ /* input sock */ cmp_node_filter_in,
+ /* output sock */ cmp_node_filter_out,
+ /* storage */ "",
+ /* execfunc */ node_composit_exec_filter,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+
+};
+
+
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_flip.c b/source/blender/nodes/intern/CMP_nodes/CMP_flip.c
new file mode 100644
index 00000000000..cd6fdf70ac4
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_flip.c
@@ -0,0 +1,105 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../CMP_util.h"
+
+/* **************** Flip ******************** */
+static bNodeSocketType cmp_node_flip_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static bNodeSocketType cmp_node_flip_out[]= {
+ { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void node_composit_exec_flip(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ if(in[0]->data) {
+ CompBuf *cbuf= in[0]->data;
+ CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, cbuf->type, 1); /* note, this returns zero'd image */
+ int i, src_pix, src_width, src_height, srcydelt, outydelt, x, y;
+ float *srcfp, *outfp;
+
+ src_pix= cbuf->type;
+ src_width= cbuf->x;
+ src_height= cbuf->y;
+ srcfp= cbuf->rect;
+ outfp= stackbuf->rect;
+ srcydelt= src_width*src_pix;
+ outydelt= srcydelt;
+
+ if(node->custom1) { /*set up output pointer for y flip*/
+ outfp+= (src_height-1)*outydelt;
+ outydelt= -outydelt;
+ }
+
+ for(y=0; y<src_height; y++) {
+ if(node->custom1 == 1) { /* no x flip so just copy line*/
+ memcpy(outfp, srcfp, sizeof(float) * src_pix * src_width);
+ srcfp+=srcydelt;
+ }
+ else {
+ outfp += (src_width-1)*src_pix;
+ for(x=0; x<src_width; x++) {
+ for(i=0; i<src_pix; i++) {
+ outfp[i]= srcfp[i];
+ }
+ outfp -= src_pix;
+ srcfp += src_pix;
+ }
+ outfp += src_pix;
+ }
+ outfp += outydelt;
+ }
+
+ out[0]->data= stackbuf;
+
+ }
+}
+
+bNodeType cmp_node_flip= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_FLIP,
+ /* name */ "Flip",
+ /* width+range */ 140, 100, 320,
+ /* class+opts */ NODE_CLASS_DISTORT, NODE_OPTIONS,
+ /* input sock */ cmp_node_flip_in,
+ /* output sock */ cmp_node_flip_out,
+ /* storage */ "",
+ /* execfunc */ node_composit_exec_flip,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+};
+
+
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_gamma.c b/source/blender/nodes/intern/CMP_nodes/CMP_gamma.c
new file mode 100644
index 00000000000..5d0ab729e08
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_gamma.c
@@ -0,0 +1,91 @@
+/**
+* $Id$
+*
+* ***** BEGIN GPL LICENSE BLOCK *****
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*
+* The Original Code is Copyright (C) 2006 Blender Foundation.
+* All rights reserved.
+*
+* The Original Code is: all of this file.
+*
+* Contributor(s): none yet.
+*
+* ***** END GPL LICENSE BLOCK *****
+
+*/
+
+#include "../CMP_util.h"
+
+/* **************** Gamma Tools ******************** */
+
+static bNodeSocketType cmp_node_gamma_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 1, "Gamma", 1.0f, 0.0f, 0.0f, 0.0f, 0.001f, 2.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketType cmp_node_gamma_out[]= {
+ { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void do_gamma(bNode *node, float *out, float *in, float *fac)
+{
+ int i=0;
+ for(i=0; i<3; i++) {
+ out[i] = pow(in[i],fac[0]);
+ }
+ out[3] = in[3];
+}
+static void node_composit_exec_gamma(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order in: Fac, Image */
+ /* stack order out: Image */
+ if(out[0]->hasoutput==0) return;
+
+ /* input no image? then only color operation */
+ if(in[0]->data==NULL) {
+ do_gamma(node, out[0]->vec, in[0]->vec, in[1]->vec);
+ }
+ else {
+ /* make output size of input image */
+ CompBuf *cbuf= in[0]->data;
+ CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); // allocs
+
+ composit2_pixel_processor(node, stackbuf, cbuf, in[0]->vec, in[1]->data, in[1]->vec, do_gamma, CB_RGBA, CB_VAL);
+
+ out[0]->data= stackbuf;
+ }
+}
+
+bNodeType cmp_node_gamma= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_GAMMA,
+ /* name */ "Gamma",
+ /* width+range */ 140, 100, 320,
+ /* class+opts */ NODE_CLASS_OP_COLOR, NODE_OPTIONS,
+ /* input sock */ cmp_node_gamma_in,
+ /* output sock */ cmp_node_gamma_out,
+ /* storage */ "",
+ /* execfunc */ node_composit_exec_gamma,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copysotragefunc */ NULL,
+ /* id */ NULL
+};
+
+
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_glare.c b/source/blender/nodes/intern/CMP_nodes/CMP_glare.c
new file mode 100644
index 00000000000..9943dd2246d
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_glare.c
@@ -0,0 +1,498 @@
+/**
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Alfredo de Greef (eeshlo)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../CMP_util.h"
+
+static bNodeSocketType cmp_node_glare_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketType cmp_node_glare_out[]= {
+ { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+
+// mix two images, src buffer does not have to be same size,
+static void mixImages(CompBuf *dst, CompBuf *src, float mix)
+{
+ int x, y;
+ fRGB c1, c2, *dcolp, *scolp;
+ const float mf = 2.f - 2.f*fabsf(mix - 0.5f);
+ if ((dst->x == src->x) && (dst->y == src->y)) {
+ for (y=0; y<dst->y; y++) {
+ dcolp = (fRGB*)&dst->rect[y*dst->x*dst->type];
+ scolp = (fRGB*)&src->rect[y*dst->x*dst->type];
+ for (x=0; x<dst->x; x++) {
+ fRGB_copy(c1, dcolp[x]);
+ fRGB_copy(c2, scolp[x]);
+ c1[0] += mix*(c2[0] - c1[0]);
+ c1[1] += mix*(c2[1] - c1[1]);
+ c1[2] += mix*(c2[2] - c1[2]);
+ if (c1[0] < 0.f) c1[0] = 0.f;
+ if (c1[1] < 0.f) c1[1] = 0.f;
+ if (c1[2] < 0.f) c1[2] = 0.f;
+ fRGB_mult(c1, mf);
+ fRGB_copy(dcolp[x], c1);
+ }
+ }
+ }
+ else {
+ float xr = src->x / (float)dst->x;
+ float yr = src->y / (float)dst->y;
+ for (y=0; y<dst->y; y++) {
+ dcolp = (fRGB*)&dst->rect[y*dst->x*dst->type];
+ for (x=0; x<dst->x; x++) {
+ fRGB_copy(c1, dcolp[x]);
+ qd_getPixelLerp(src, (x + 0.5f)*xr - 0.5f, (y + 0.5f)*yr - 0.5f, c2);
+ c1[0] += mix*(c2[0] - c1[0]);
+ c1[1] += mix*(c2[1] - c1[1]);
+ c1[2] += mix*(c2[2] - c1[2]);
+ if (c1[0] < 0.f) c1[0] = 0.f;
+ if (c1[1] < 0.f) c1[1] = 0.f;
+ if (c1[2] < 0.f) c1[2] = 0.f;
+ fRGB_mult(c1, mf);
+ fRGB_copy(dcolp[x], c1);
+ }
+ }
+ }
+}
+
+
+// adds src to dst image, must be of same size
+static void addImage(CompBuf* dst, CompBuf* src, float scale)
+{
+ if ((dst->x == src->x) && (dst->y == src->y)) {
+ int p = dst->x*dst->y*dst->type;
+ float *dcol = dst->rect, *scol = src->rect;
+ while (p--) *dcol++ += *scol++ * scale;
+ }
+}
+
+
+// returns possibly downscaled copy of all pixels above threshold
+static CompBuf* BTP(CompBuf* src, float threshold, int scaledown)
+{
+ int x, y;
+ CompBuf* bsrc = qd_downScaledCopy(src, scaledown);
+ float* cr = bsrc->rect;
+ for (y=0; y<bsrc->y; ++y)
+ for (x=0; x<bsrc->x; ++x, cr+=4) {
+ if ((0.212671f*cr[0] + 0.71516f*cr[1] + 0.072169f*cr[2]) >= threshold) {
+ cr[0] -= threshold, cr[1] -= threshold, cr[2] -= threshold;
+ cr[0] = MAX2(cr[0], 0.f);
+ cr[1] = MAX2(cr[1], 0.f);
+ cr[2] = MAX2(cr[2], 0.f);
+ }
+ else cr[0] = cr[1] = cr[2] = 0.f;
+ }
+ return bsrc;
+}
+
+//--------------------------------------------------------------------------------------------
+// simple 4-point star filter
+
+static void star4(NodeGlare* ndg, CompBuf* dst, CompBuf* src)
+{
+ int x, y, i, xm, xp, ym, yp;
+ float c[4] = {0,0,0,0}, tc[4] = {0,0,0,0};
+ CompBuf *tbuf1, *tbuf2, *tsrc;
+ const float f1 = 1.f - ndg->fade, f2 = (1.f - f1)*0.5f;
+ //const float t3 = ndg->threshold*3.f;
+ const float sc = (float)(1 << ndg->quality);
+ const float isc = 1.f/sc;
+
+ tsrc = BTP(src, ndg->threshold, (int)sc);
+
+ tbuf1 = dupalloc_compbuf(tsrc);
+ tbuf2 = dupalloc_compbuf(tsrc);
+
+ for (i=0; i<ndg->iter; i++) {
+ // (x || x-1, y-1) to (x || x+1, y+1)
+ // F
+ for (y=0; y<tbuf1->y; y++) {
+ ym = y - i;
+ yp = y + i;
+ for (x=0; x<tbuf1->x; x++) {
+ xm = x - i;
+ xp = x + i;
+ qd_getPixel(tbuf1, x, y, c);
+ fRGB_mult(c, f1);
+ qd_getPixel(tbuf1, (ndg->angle ? xm : x), ym, tc);
+ fRGB_madd(c, tc, f2);
+ qd_getPixel(tbuf1, (ndg->angle ? xp : x), yp, tc);
+ fRGB_madd(c, tc, f2);
+ qd_setPixel(tbuf1, x, y, c);
+ }
+ }
+ // B
+ for (y=tbuf1->y-1; y>=0; y--) {
+ ym = y - i;
+ yp = y + i;
+ for (x=tbuf1->x-1; x>=0; x--) {
+ xm = x - i;
+ xp = x + i;
+ qd_getPixel(tbuf1, x, y, c);
+ fRGB_mult(c, f1);
+ qd_getPixel(tbuf1, (ndg->angle ? xm : x), ym, tc);
+ fRGB_madd(c, tc, f2);
+ qd_getPixel(tbuf1, (ndg->angle ? xp : x), yp, tc);
+ fRGB_madd(c, tc, f2);
+ qd_setPixel(tbuf1, x, y, c);
+ }
+ }
+ // (x-1, y || y+1) to (x+1, y || y-1)
+ // F
+ for (y=0; y<tbuf2->y; y++) {
+ ym = y - i;
+ yp = y + i;
+ for (x=0; x<tbuf2->x; x++) {
+ xm = x - i;
+ xp = x + i;
+ qd_getPixel(tbuf2, x, y, c);
+ fRGB_mult(c, f1);
+ qd_getPixel(tbuf2, xm, (ndg->angle ? yp : y), tc);
+ fRGB_madd(c, tc, f2);
+ qd_getPixel(tbuf2, xp, (ndg->angle ? ym : y), tc);
+ fRGB_madd(c, tc, f2);
+ qd_setPixel(tbuf2, x, y, c);
+ }
+ }
+ // B
+ for (y=tbuf2->y-1; y>=0; y--) {
+ ym = y - i;
+ yp = y + i;
+ for (x=tbuf2->x-1; x>=0; x--) {
+ xm = x - i;
+ xp = x + i;
+ qd_getPixel(tbuf2, x, y, c);
+ fRGB_mult(c, f1);
+ qd_getPixel(tbuf2, xm, (ndg->angle ? yp : y), tc);
+ fRGB_madd(c, tc, f2);
+ qd_getPixel(tbuf2, xp, (ndg->angle ? ym : y), tc);
+ fRGB_madd(c, tc, f2);
+ qd_setPixel(tbuf2, x, y, c);
+ }
+ }
+ }
+
+ for (y=0; y<tbuf1->y; ++y)
+ for (x=0; x<tbuf1->x; ++x) {
+ unsigned int p = (x + y*tbuf1->x)*tbuf1->type;
+ tbuf1->rect[p] += tbuf2->rect[p];
+ tbuf1->rect[p+1] += tbuf2->rect[p+1];
+ tbuf1->rect[p+2] += tbuf2->rect[p+2];
+ }
+
+ for (y=0; y<dst->y; ++y) {
+ const float m = 0.5f + 0.5f*ndg->mix;
+ for (x=0; x<dst->x; ++x) {
+ unsigned int p = (x + y*dst->x)*dst->type;
+ qd_getPixelLerp(tbuf1, x*isc, y*isc, tc);
+ dst->rect[p] = src->rect[p] + m*(tc[0] - src->rect[p]);
+ dst->rect[p+1] = src->rect[p+1] + m*(tc[1] - src->rect[p+1]);
+ dst->rect[p+2] = src->rect[p+2] + m*(tc[2] - src->rect[p+2]);
+ }
+ }
+
+ free_compbuf(tbuf1);
+ free_compbuf(tbuf2);
+ free_compbuf(tsrc);
+}
+
+//--------------------------------------------------------------------------------------------
+// streak filter
+
+static void streaks(NodeGlare* ndg, CompBuf* dst, CompBuf* src)
+{
+ CompBuf *bsrc, *tsrc, *tdst, *sbuf;
+ int x, y, n;
+ unsigned int nump=0;
+ fRGB c1, c2, c3, c4;
+ float a, ang = 360.f/(float)ndg->angle;
+
+ bsrc = BTP(src, ndg->threshold, 1 << ndg->quality);
+ tsrc = dupalloc_compbuf(bsrc); // sample from buffer
+ tdst = alloc_compbuf(tsrc->x, tsrc->y, tsrc->type, 1); // sample to buffer
+ sbuf = alloc_compbuf(tsrc->x, tsrc->y, tsrc->type, 1); // streak sum buffer
+
+
+ for (a=0.f; a<360.f; a+=ang) {
+ const float an = (a + (float)ndg->angle_ofs)*(float)M_PI/180.f;
+ const float vx = cosf(an), vy = sinf(an);
+ for (n=0; n<ndg->iter; ++n) {
+ const float p4 = powf(4.f, n);
+ const float vxp = vx*p4, vyp = vy*p4;
+ const float wt = powf(ndg->fade, p4);
+ const float cmo = 1.f - powf(ndg->colmod, n+1); // colormodulation amount relative to current pass
+ float* tdstcol = tdst->rect;
+ for (y=0; y<tsrc->y; ++y) {
+ for (x=0; x<tsrc->x; ++x, tdstcol+=4) {
+ // first pass no offset, always same for every pass, exact copy,
+ // otherwise results in uneven brightness, only need once
+ if (n==0) qd_getPixel(tsrc, x, y, c1); else c1[0]=c1[1]=c1[2]=0;
+ qd_getPixelLerp(tsrc, x + vxp, y + vyp, c2);
+ qd_getPixelLerp(tsrc, x + vxp*2.f, y + vyp*2.f, c3);
+ qd_getPixelLerp(tsrc, x + vxp*3.f, y + vyp*3.f, c4);
+ // modulate color to look vaguely similar to a color spectrum
+ fRGB_rgbmult(c2, 1.f, cmo, cmo);
+ fRGB_rgbmult(c3, cmo, cmo, 1.f);
+ fRGB_rgbmult(c4, cmo, 1.f, cmo);
+ tdstcol[0] = 0.5f*(tdstcol[0] + c1[0] + wt*(c2[0] + wt*(c3[0] + wt*c4[0])));
+ tdstcol[1] = 0.5f*(tdstcol[1] + c1[1] + wt*(c2[1] + wt*(c3[1] + wt*c4[1])));
+ tdstcol[2] = 0.5f*(tdstcol[2] + c1[2] + wt*(c2[2] + wt*(c3[2] + wt*c4[2])));
+ }
+ }
+ memcpy(tsrc->rect, tdst->rect, sizeof(float)*tdst->x*tdst->y*tdst->type);
+ }
+
+ addImage(sbuf, tsrc, 1.f/(float)(6 - ndg->iter));
+ memset(tdst->rect, 0, tdst->x*tdst->y*tdst->type*sizeof(float));
+ memcpy(tsrc->rect, bsrc->rect, bsrc->x*bsrc->y*bsrc->type*sizeof(float));
+ nump++;
+ }
+
+ mixImages(dst, sbuf, 0.5f + 0.5f*ndg->mix);
+
+ free_compbuf(tsrc);
+ free_compbuf(tdst);
+ free_compbuf(sbuf);
+ free_compbuf(bsrc);
+}
+
+
+//--------------------------------------------------------------------------------------------
+// Ghosts (lensflare)
+
+static float smoothMask(float x, float y)
+{
+ float t;
+ x = 2.f*x - 1.f, y = 2.f*y - 1.f;
+ if ((t = 1.f - sqrtf(x*x + y*y)) <= 0.f) return 0.f;
+ return t;
+}
+
+static void ghosts(NodeGlare* ndg, CompBuf* dst, CompBuf* src)
+{
+ // colormodulation and scale factors (cm & scalef) for 16 passes max: 64
+ int x, y, n, p, np;
+ fRGB c, tc, cm[64];
+ float sc, isc, u, v, sm, s, t, ofs, scalef[64];
+ CompBuf *tbuf1, *tbuf2, *gbuf;
+ const float cmo = 1.f - ndg->colmod;
+ const int qt = 1 << ndg->quality;
+ const float s1 = 4.f/(float)qt, s2 = 2.f*s1;
+
+ gbuf = BTP(src, ndg->threshold, qt);
+ tbuf1 = dupalloc_compbuf(gbuf);
+ IIR_gauss(tbuf1, s1, 0, 3);
+ IIR_gauss(tbuf1, s1, 1, 3);
+ IIR_gauss(tbuf1, s1, 2, 3);
+ tbuf2 = dupalloc_compbuf(tbuf1);
+ IIR_gauss(tbuf2, s2, 0, 3);
+ IIR_gauss(tbuf2, s2, 1, 3);
+ IIR_gauss(tbuf2, s2, 2, 3);
+
+ if (ndg->iter & 1) ofs = 0.5f; else ofs = 0.f;
+ for (x=0; x<(ndg->iter*4); x++) {
+ y = x & 3;
+ cm[x][0] = cm[x][1] = cm[x][2] = 1;
+ if (y==1) fRGB_rgbmult(cm[x], 1.f, cmo, cmo);
+ if (y==2) fRGB_rgbmult(cm[x], cmo, cmo, 1.f);
+ if (y==3) fRGB_rgbmult(cm[x], cmo, 1.f, cmo);
+ scalef[x] = 2.1f*(1.f-(x+ofs)/(float)(ndg->iter*4));
+ if (x & 1) scalef[x] = -0.99f/scalef[x];
+ }
+
+ sc = 2.13;
+ isc = -0.97;
+ for (y=0; y<gbuf->y; y++) {
+ v = (float)(y+0.5f) / (float)gbuf->y;
+ for (x=0; x<gbuf->x; x++) {
+ u = (float)(x+0.5f) / (float)gbuf->x;
+ s = (u-0.5f)*sc + 0.5f, t = (v-0.5f)*sc + 0.5f;
+ qd_getPixelLerp(tbuf1, s*gbuf->x, t*gbuf->y, c);
+ sm = smoothMask(s, t);
+ fRGB_mult(c, sm);
+ s = (u-0.5f)*isc + 0.5f, t = (v-0.5f)*isc + 0.5f;
+ qd_getPixelLerp(tbuf2, s*gbuf->x - 0.5f, t*gbuf->y - 0.5f, tc);
+ sm = smoothMask(s, t);
+ fRGB_madd(c, tc, sm);
+ qd_setPixel(gbuf, x, y, c);
+ }
+ }
+
+ memset(tbuf1->rect, 0, tbuf1->x*tbuf1->y*tbuf1->type*sizeof(float));
+ for (n=1; n<ndg->iter; n++) {
+ for (y=0; y<gbuf->y; y++) {
+ v = (float)(y+0.5f) / (float)gbuf->y;
+ for (x=0; x<gbuf->x; x++) {
+ u = (float)(x+0.5f) / (float)gbuf->x;
+ tc[0] = tc[1] = tc[2] = 0.f;
+ for (p=0;p<4;p++) {
+ np = (n<<2) + p;
+ s = (u-0.5f)*scalef[np] + 0.5f;
+ t = (v-0.5f)*scalef[np] + 0.5f;
+ qd_getPixelLerp(gbuf, s*gbuf->x - 0.5f, t*gbuf->y - 0.5f, c);
+ fRGB_colormult(c, cm[np]);
+ sm = smoothMask(s, t)*0.25f;
+ fRGB_madd(tc, c, sm);
+ }
+ p = (x + y*tbuf1->x)*tbuf1->type;
+ tbuf1->rect[p] += tc[0];
+ tbuf1->rect[p+1] += tc[1];
+ tbuf1->rect[p+2] += tc[2];
+ }
+ }
+ memcpy(gbuf->rect, tbuf1->rect, tbuf1->x*tbuf1->y*tbuf1->type*sizeof(float));
+ }
+
+ free_compbuf(tbuf1);
+ free_compbuf(tbuf2);
+
+ mixImages(dst, gbuf, 0.5f + 0.5f*ndg->mix);
+ free_compbuf(gbuf);
+}
+
+//--------------------------------------------------------------------------------------------
+// Fog glow (convolution with kernel of exponential falloff)
+
+static void fglow(NodeGlare* ndg, CompBuf* dst, CompBuf* src)
+{
+ int x, y;
+ float scale, u, v, r, w, d;
+ fRGB fcol;
+ CompBuf *tsrc, *ckrn;
+ unsigned int sz = 1 << ndg->size;
+ const float cs_r = 1.f, cs_g = 1.f, cs_b = 1.f;
+
+ // temp. src image
+ tsrc = BTP(src, ndg->threshold, 1 << ndg->quality);
+ // make the convolution kernel
+ ckrn = alloc_compbuf(sz, sz, CB_RGBA, 1);
+
+ scale = 0.25f*sqrtf(sz*sz);
+
+ for (y=0; y<sz; ++y) {
+ v = 2.f*(y / (float)sz) - 1.f;
+ for (x=0; x<sz; ++x) {
+ u = 2.f*(x / (float)sz) - 1.f;
+ r = (u*u + v*v)*scale;
+ d = -sqrtf(sqrtf(sqrtf(r)))*9.f;
+ fcol[0] = expf(d*cs_r), fcol[1] = expf(d*cs_g), fcol[2] = expf(d*cs_b);
+ // linear window good enough here, visual result counts, not scientific analysis
+ //w = (1.f-fabs(u))*(1.f-fabs(v));
+ // actually, Hanning window is ok, cos^2 for some reason is slower
+ w = (0.5f + 0.5f*cosf(u*(float)M_PI))*(0.5f + 0.5f*cosf(v*(float)M_PI));
+ fRGB_mult(fcol, w);
+ qd_setPixel(ckrn, x, y, fcol);
+ }
+ }
+
+ convolve(tsrc, tsrc, ckrn);
+ free_compbuf(ckrn);
+ mixImages(dst, tsrc, 0.5f + 0.5f*ndg->mix);
+ free_compbuf(tsrc);
+}
+
+//--------------------------------------------------------------------------------------------
+
+static void node_composit_exec_glare(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ CompBuf *new, *img = in[0]->data;
+ NodeGlare* ndg = node->storage;
+
+ if ((img == NULL) || (out[0]->hasoutput == 0)) return;
+
+ if (img->type != CB_RGBA)
+ new = typecheck_compbuf(img, CB_RGBA);
+ else
+ new = dupalloc_compbuf(img);
+
+ {
+ int x, y;
+ for (y=0; y<new->y; ++y) {
+ fRGB* col = (fRGB*)&new->rect[y*new->x*new->type];
+ for (x=0; x<new->x; ++x) {
+ col[x][0] = MAX2(col[x][0], 0.f);
+ col[x][1] = MAX2(col[x][1], 0.f);
+ col[x][2] = MAX2(col[x][2], 0.f);
+ }
+ }
+ }
+
+ switch (ndg->type) {
+ case 0:
+ star4(ndg, new, img);
+ break;
+ case 1:
+ fglow(ndg, new, img);
+ break;
+ case 3:
+ ghosts(ndg, new, img);
+ break;
+ case 2:
+ default:
+ streaks(ndg, new, img);
+ }
+
+ out[0]->data = new;
+}
+
+static void node_composit_init_glare(bNode* node)
+{
+ NodeGlare *ndg = MEM_callocN(sizeof(NodeGlare), "node glare data");
+ ndg->quality = 1;
+ ndg->type = 2;
+ ndg->iter = 3;
+ ndg->colmod = 0.25;
+ ndg->mix = 0;
+ ndg->threshold = 1;
+ ndg->angle = 4;
+ ndg->angle_ofs = 0;
+ ndg->fade = 0.9;
+ ndg->size = 8;
+ node->storage = ndg;
+}
+
+bNodeType cmp_node_glare = {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_GLARE,
+ /* name */ "Glare",
+ /* width+range */ 150, 120, 200,
+ /* class+opts */ NODE_CLASS_OP_FILTER, NODE_OPTIONS,
+ /* input sock */ cmp_node_glare_in,
+ /* output sock */ cmp_node_glare_out,
+ /* storage */ "NodeGlare",
+ /* execfunc */ node_composit_exec_glare,
+ /* butfunc */ NULL,
+ /* initfunc */ node_composit_init_glare,
+ /* freestoragefunc */ node_free_standard_storage,
+ /* copystoragefunc */ node_copy_standard_storage,
+ /* id */ NULL
+};
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_hueSatVal.c b/source/blender/nodes/intern/CMP_nodes/CMP_hueSatVal.c
new file mode 100644
index 00000000000..eeddb4ce756
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_hueSatVal.c
@@ -0,0 +1,122 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../CMP_util.h"
+
+
+/* **************** Hue Saturation ******************** */
+static bNodeSocketType cmp_node_hue_sat_in[]= {
+ { SOCK_VALUE, 1, "Fac", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketType cmp_node_hue_sat_out[]= {
+ { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void do_hue_sat_fac(bNode *node, float *out, float *in, float *fac)
+{
+ NodeHueSat *nhs= node->storage;
+
+ if(*fac!=0.0f && (nhs->hue!=0.5f || nhs->sat!=1.0 || nhs->val!=1.0)) {
+ float col[3], hsv[3], mfac= 1.0f - *fac;
+
+ rgb_to_hsv(in[0], in[1], in[2], hsv, hsv+1, hsv+2);
+ hsv[0]+= (nhs->hue - 0.5f);
+ if(hsv[0]>1.0) hsv[0]-=1.0; else if(hsv[0]<0.0) hsv[0]+= 1.0;
+ hsv[1]*= nhs->sat;
+ if(hsv[1]>1.0) hsv[1]= 1.0; else if(hsv[1]<0.0) hsv[1]= 0.0;
+ hsv[2]*= nhs->val;
+ if(hsv[2]>1.0) hsv[2]= 1.0; else if(hsv[2]<0.0) hsv[2]= 0.0;
+ hsv_to_rgb(hsv[0], hsv[1], hsv[2], col, col+1, col+2);
+
+ out[0]= mfac*in[0] + *fac*col[0];
+ out[1]= mfac*in[1] + *fac*col[1];
+ out[2]= mfac*in[2] + *fac*col[2];
+ out[3]= in[3];
+ }
+ else {
+ QUATCOPY(out, in);
+ }
+}
+
+static void node_composit_exec_hue_sat(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order in: Fac, Image */
+ /* stack order out: Image */
+ if(out[0]->hasoutput==0) return;
+
+ /* input no image? then only color operation */
+ if(in[1]->data==NULL) {
+ do_hue_sat_fac(node, out[0]->vec, in[1]->vec, in[0]->vec);
+ }
+ else {
+ /* make output size of input image */
+ CompBuf *cbuf= dupalloc_compbuf(in[1]->data);
+ CompBuf *stackbuf=typecheck_compbuf(cbuf,CB_RGBA);
+
+ composit2_pixel_processor(node, stackbuf, stackbuf, in[1]->vec, in[0]->data, in[0]->vec, do_hue_sat_fac, CB_RGBA, CB_VAL);
+
+ out[0]->data= stackbuf;
+
+ /* get rid of intermediary cbuf if it's extra */
+ if(stackbuf!=cbuf)
+ free_compbuf(cbuf);
+ }
+}
+
+static void node_composit_init_hue_sat(bNode* node)
+{
+ NodeHueSat *nhs= MEM_callocN(sizeof(NodeHueSat), "node hue sat");
+ node->storage= nhs;
+ nhs->hue= 0.5f;
+ nhs->sat= 1.0f;
+ nhs->val= 1.0f;
+}
+
+bNodeType cmp_node_hue_sat= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_HUE_SAT,
+ /* name */ "Hue Saturation Value",
+ /* width+range */ 150, 80, 250,
+ /* class+opts */ NODE_CLASS_OP_COLOR, NODE_OPTIONS,
+ /* input sock */ cmp_node_hue_sat_in,
+ /* output sock */ cmp_node_hue_sat_out,
+ /* storage */ "NodeHueSat",
+ /* execfunc */ node_composit_exec_hue_sat,
+ /* butfunc */ NULL,
+ /* initfunc */ node_composit_init_hue_sat,
+ /* freestoragefunc */ node_free_standard_storage,
+ /* copystoragefunc */ node_copy_standard_storage,
+ /* id */ NULL
+
+};
+
+
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_idMask.c b/source/blender/nodes/intern/CMP_nodes/CMP_idMask.c
new file mode 100644
index 00000000000..abb9fa98d97
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_idMask.c
@@ -0,0 +1,104 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../CMP_util.h"
+
+
+/* **************** ID Mask ******************** */
+
+static bNodeSocketType cmp_node_idmask_in[]= {
+ { SOCK_VALUE, 1, "ID value", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketType cmp_node_idmask_out[]= {
+ { SOCK_VALUE, 0, "Alpha", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+/* stackbuf should be zeroed */
+static void do_idmask(CompBuf *stackbuf, CompBuf *cbuf, float idnr)
+{
+ float *rect;
+ int x;
+ char *abuf= MEM_mapallocN(cbuf->x*cbuf->y, "anti ali buf");
+
+ rect= cbuf->rect;
+ for(x= cbuf->x*cbuf->y - 1; x>=0; x--)
+ if(rect[x]==idnr)
+ abuf[x]= 255;
+
+ antialias_tagbuf(cbuf->x, cbuf->y, abuf);
+
+ rect= stackbuf->rect;
+ for(x= cbuf->x*cbuf->y - 1; x>=0; x--)
+ if(abuf[x]>1)
+ rect[x]= (1.0f/255.0f)*(float)abuf[x];
+
+ MEM_freeN(abuf);
+}
+
+static void node_composit_exec_idmask(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ if(out[0]->hasoutput==0)
+ return;
+
+ if(in[0]->data) {
+ CompBuf *cbuf= in[0]->data;
+ CompBuf *stackbuf;
+
+ if(cbuf->type!=CB_VAL)
+ return;
+
+ stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1); /* allocs */;
+
+ do_idmask(stackbuf, cbuf, (float)node->custom1);
+
+ out[0]->data= stackbuf;
+ }
+}
+
+
+bNodeType cmp_node_idmask= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_ID_MASK,
+ /* name */ "ID Mask",
+ /* width+range */ 140, 100, 320,
+ /* class+opts */ NODE_CLASS_CONVERTOR, NODE_OPTIONS,
+ /* input sock */ cmp_node_idmask_in,
+ /* output sock */ cmp_node_idmask_out,
+ /* storage */ "",
+ /* execfunc */ node_composit_exec_idmask,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+};
+
+
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_image.c b/source/blender/nodes/intern/CMP_nodes/CMP_image.c
new file mode 100644
index 00000000000..20308e968d3
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_image.c
@@ -0,0 +1,352 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../CMP_util.h"
+
+
+/* **************** IMAGE (and RenderResult, multilayer image) ******************** */
+
+static bNodeSocketType cmp_node_rlayers_out[]= {
+ { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 0, "Alpha", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 0, "Z", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_VECTOR, 0, "Normal", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_VECTOR, 0, "UV", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_VECTOR, 0, "Speed", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, "Color", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, "Diffuse", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, "Specular", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, "Shadow", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, "AO", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, "Reflect", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, "Refract", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, "Radio", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 0, "IndexOB", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+
+/* note: this function is used for multilayer too, to ensure uniform
+ handling with BKE_image_get_ibuf() */
+static CompBuf *node_composit_get_image(RenderData *rd, Image *ima, ImageUser *iuser)
+{
+ ImBuf *ibuf;
+ CompBuf *stackbuf;
+ int type;
+
+ ibuf= BKE_image_get_ibuf(ima, iuser);
+ if(ibuf==NULL)
+ return NULL;
+
+ if(ibuf->rect_float==NULL)
+ IMB_float_from_rect(ibuf);
+
+ type= ibuf->channels;
+
+ if(rd->scemode & R_COMP_CROP) {
+ stackbuf= get_cropped_compbuf(&rd->disprect, ibuf->rect_float, ibuf->x, ibuf->y, type);
+ }
+ else {
+ /* we put imbuf copy on stack, cbuf knows rect is from other ibuf when freed! */
+ stackbuf= alloc_compbuf(ibuf->x, ibuf->y, type, 0);
+ stackbuf->rect= ibuf->rect_float;
+ }
+
+ return stackbuf;
+};
+
+static CompBuf *node_composit_get_zimage(bNode *node, RenderData *rd)
+{
+ ImBuf *ibuf= BKE_image_get_ibuf((Image *)node->id, node->storage);
+ CompBuf *zbuf= NULL;
+
+ if(ibuf && ibuf->zbuf_float) {
+ if(rd->scemode & R_COMP_CROP) {
+ zbuf= get_cropped_compbuf(&rd->disprect, ibuf->zbuf_float, ibuf->x, ibuf->y, CB_VAL);
+ }
+ else {
+ zbuf= alloc_compbuf(ibuf->x, ibuf->y, CB_VAL, 0);
+ zbuf->rect= ibuf->zbuf_float;
+ }
+ }
+ return zbuf;
+};
+
+/* check if layer is available, returns pass buffer */
+static CompBuf *compbuf_multilayer_get(RenderData *rd, RenderLayer *rl, Image *ima, ImageUser *iuser, int passtype)
+{
+ RenderPass *rpass;
+ short index;
+
+ for(index=0, rpass= rl->passes.first; rpass; rpass= rpass->next, index++)
+ if(rpass->passtype==passtype)
+ break;
+
+ if(rpass) {
+ CompBuf *cbuf;
+
+ iuser->pass= index;
+ BKE_image_multilayer_index(ima->rr, iuser);
+ cbuf= node_composit_get_image(rd, ima, iuser);
+
+ return cbuf;
+ }
+ return NULL;
+};
+
+void outputs_multilayer_get(RenderData *rd, RenderLayer *rl, bNodeStack **out, Image *ima, ImageUser *iuser)
+{
+ if(out[RRES_OUT_Z]->hasoutput)
+ out[RRES_OUT_Z]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_Z);
+ if(out[RRES_OUT_VEC]->hasoutput)
+ out[RRES_OUT_VEC]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_VECTOR);
+ if(out[RRES_OUT_NORMAL]->hasoutput)
+ out[RRES_OUT_NORMAL]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_NORMAL);
+ if(out[RRES_OUT_UV]->hasoutput)
+ out[RRES_OUT_UV]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_UV);
+
+ if(out[RRES_OUT_RGBA]->hasoutput)
+ out[RRES_OUT_RGBA]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_RGBA);
+ if(out[RRES_OUT_DIFF]->hasoutput)
+ out[RRES_OUT_DIFF]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_DIFFUSE);
+ if(out[RRES_OUT_SPEC]->hasoutput)
+ out[RRES_OUT_SPEC]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_SPEC);
+ if(out[RRES_OUT_SHADOW]->hasoutput)
+ out[RRES_OUT_SHADOW]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_SHADOW);
+ if(out[RRES_OUT_AO]->hasoutput)
+ out[RRES_OUT_AO]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_AO);
+ if(out[RRES_OUT_REFLECT]->hasoutput)
+ out[RRES_OUT_REFLECT]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_REFLECT);
+ if(out[RRES_OUT_REFRACT]->hasoutput)
+ out[RRES_OUT_REFRACT]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_REFRACT);
+ if(out[RRES_OUT_RADIO]->hasoutput)
+ out[RRES_OUT_RADIO]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_RADIO);
+ if(out[RRES_OUT_INDEXOB]->hasoutput)
+ out[RRES_OUT_INDEXOB]->data= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_INDEXOB);
+
+};
+
+
+static void node_composit_exec_image(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+
+ /* image assigned to output */
+ /* stack order input sockets: col, alpha */
+ if(node->id) {
+ RenderData *rd= data;
+ Image *ima= (Image *)node->id;
+ ImageUser *iuser= (ImageUser *)node->storage;
+ CompBuf *stackbuf= NULL;
+
+ /* first set the right frame number in iuser */
+ BKE_image_user_calc_imanr(iuser, rd->cfra, 0);
+
+ /* force a load, we assume iuser index will be set OK anyway */
+ if(ima->type==IMA_TYPE_MULTILAYER)
+ BKE_image_get_ibuf(ima, iuser);
+
+ if(ima->type==IMA_TYPE_MULTILAYER && ima->rr) {
+ RenderLayer *rl= BLI_findlink(&ima->rr->layers, iuser->layer);
+
+ if(rl) {
+ out[0]->data= stackbuf= compbuf_multilayer_get(rd, rl, ima, iuser, SCE_PASS_COMBINED);
+
+ /* go over all layers */
+ outputs_multilayer_get(rd, rl, out, ima, iuser);
+ }
+ }
+ else {
+ stackbuf= node_composit_get_image(rd, ima, iuser);
+
+ /* put image on stack */
+ out[0]->data= stackbuf;
+
+ if(out[2]->hasoutput)
+ out[2]->data= node_composit_get_zimage(node, rd);
+ }
+
+ /* alpha and preview for both types */
+ if(stackbuf) {
+ if(out[1]->hasoutput)
+ out[1]->data= valbuf_from_rgbabuf(stackbuf, CHAN_A);
+
+ generate_preview(node, stackbuf);
+ }
+ }
+};
+
+static void node_composit_init_image(bNode* node)
+{
+ ImageUser *iuser= MEM_callocN(sizeof(ImageUser), "node image user");
+ node->storage= iuser;
+ iuser->sfra= 1;
+ iuser->fie_ima= 2;
+ iuser->ok= 1;
+}
+
+bNodeType cmp_node_image= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_IMAGE,
+ /* name */ "Image",
+ /* width+range */ 120, 80, 300,
+ /* class+opts */ NODE_CLASS_INPUT, NODE_PREVIEW|NODE_OPTIONS,
+ /* input sock */ NULL,
+ /* output sock */ cmp_node_rlayers_out,
+ /* storage */ "ImageUser",
+ /* execfunc */ node_composit_exec_image,
+ /* butfunc */ NULL,
+ /* initfunc */ node_composit_init_image,
+ /* freestoragefunc */ node_free_standard_storage,
+ /* copystoragefunc */ node_copy_standard_storage,
+ /* id */ NULL
+};
+
+/* **************** RENDER RESULT ******************** */
+
+static CompBuf *compbuf_from_pass(RenderData *rd, RenderLayer *rl, int rectx, int recty, int passcode)
+{
+ float *fp= RE_RenderLayerGetPass(rl, passcode);
+ if(fp) {
+ CompBuf *buf;
+ int buftype= CB_VEC3;
+
+ if(ELEM(passcode, SCE_PASS_Z, SCE_PASS_INDEXOB))
+ buftype= CB_VAL;
+ else if(passcode==SCE_PASS_VECTOR)
+ buftype= CB_VEC4;
+ else if(ELEM(passcode, SCE_PASS_COMBINED, SCE_PASS_RGBA))
+ buftype= CB_RGBA;
+
+ if(rd->scemode & R_COMP_CROP)
+ buf= get_cropped_compbuf(&rd->disprect, fp, rectx, recty, buftype);
+ else {
+ buf= alloc_compbuf(rectx, recty, buftype, 0);
+ buf->rect= fp;
+ }
+ return buf;
+ }
+ return NULL;
+};
+
+void node_composit_rlayers_out(RenderData *rd, RenderLayer *rl, bNodeStack **out, int rectx, int recty)
+{
+ if(out[RRES_OUT_Z]->hasoutput)
+ out[RRES_OUT_Z]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_Z);
+ if(out[RRES_OUT_VEC]->hasoutput)
+ out[RRES_OUT_VEC]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_VECTOR);
+ if(out[RRES_OUT_NORMAL]->hasoutput)
+ out[RRES_OUT_NORMAL]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_NORMAL);
+ if(out[RRES_OUT_UV]->hasoutput)
+ out[RRES_OUT_UV]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_UV);
+
+ if(out[RRES_OUT_RGBA]->hasoutput)
+ out[RRES_OUT_RGBA]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_RGBA);
+ if(out[RRES_OUT_DIFF]->hasoutput)
+ out[RRES_OUT_DIFF]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_DIFFUSE);
+ if(out[RRES_OUT_SPEC]->hasoutput)
+ out[RRES_OUT_SPEC]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_SPEC);
+ if(out[RRES_OUT_SHADOW]->hasoutput)
+ out[RRES_OUT_SHADOW]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_SHADOW);
+ if(out[RRES_OUT_AO]->hasoutput)
+ out[RRES_OUT_AO]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_AO);
+ if(out[RRES_OUT_REFLECT]->hasoutput)
+ out[RRES_OUT_REFLECT]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_REFLECT);
+ if(out[RRES_OUT_REFRACT]->hasoutput)
+ out[RRES_OUT_REFRACT]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_REFRACT);
+ if(out[RRES_OUT_RADIO]->hasoutput)
+ out[RRES_OUT_RADIO]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_RADIO);
+ if(out[RRES_OUT_INDEXOB]->hasoutput)
+ out[RRES_OUT_INDEXOB]->data= compbuf_from_pass(rd, rl, rectx, recty, SCE_PASS_INDEXOB);
+
+};
+
+static void node_composit_exec_rlayers(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ Scene *sce= node->id?(Scene *)node->id:G.scene; /* G.scene is WEAK! */
+ RenderData *rd= data;
+ RenderResult *rr;
+
+ rr= RE_GetResult(RE_GetRender(sce->id.name));
+
+ if(rr) {
+ SceneRenderLayer *srl= BLI_findlink(&sce->r.layers, node->custom1);
+ if(srl) {
+ RenderLayer *rl= RE_GetRenderLayer(rr, srl->name);
+ if(rl && rl->rectf) {
+ CompBuf *stackbuf;
+
+ /* we put render rect on stack, cbuf knows rect is from other ibuf when freed! */
+ if(rd->scemode & R_COMP_CROP)
+ stackbuf= get_cropped_compbuf(&rd->disprect, rl->rectf, rr->rectx, rr->recty, CB_RGBA);
+ else {
+ stackbuf= alloc_compbuf(rr->rectx, rr->recty, CB_RGBA, 0);
+ stackbuf->rect= rl->rectf;
+ }
+ if(stackbuf==NULL) {
+ printf("Error; Preview Panel in UV Window returns zero sized image\n");
+ }
+ else {
+ stackbuf->xof= rr->xof;
+ stackbuf->yof= rr->yof;
+
+ /* put on stack */
+ out[RRES_OUT_IMAGE]->data= stackbuf;
+
+ if(out[RRES_OUT_ALPHA]->hasoutput)
+ out[RRES_OUT_ALPHA]->data= valbuf_from_rgbabuf(stackbuf, CHAN_A);
+
+ node_composit_rlayers_out(rd, rl, out, rr->rectx, rr->recty);
+
+ generate_preview(node, stackbuf);
+ }
+ }
+ }
+ }
+};
+
+
+bNodeType cmp_node_rlayers= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_R_LAYERS,
+ /* name */ "Render Layers",
+ /* width+range */ 150, 100, 300,
+ /* class+opts */ NODE_CLASS_INPUT, NODE_PREVIEW|NODE_OPTIONS,
+ /* input sock */ NULL,
+ /* output sock */ cmp_node_rlayers_out,
+ /* storage */ "",
+ /* execfunc */ node_composit_exec_rlayers,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+
+};
+
+
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_invert.c b/source/blender/nodes/intern/CMP_nodes/CMP_invert.c
new file mode 100644
index 00000000000..4d8f5d63e75
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_invert.c
@@ -0,0 +1,134 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#include "../CMP_util.h"
+
+/* **************** INVERT ******************** */
+static bNodeSocketType cmp_node_invert_in[]= {
+ { SOCK_VALUE, 1, "Fac", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 1, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static bNodeSocketType cmp_node_invert_out[]= {
+ { SOCK_RGBA, 0, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void do_invert(bNode *node, float *out, float *in)
+{
+ if(node->custom1 & CMP_CHAN_RGB) {
+ out[0] = 1.0f - in[0];
+ out[1] = 1.0f - in[1];
+ out[2] = 1.0f - in[2];
+ } else
+ VECCOPY(out, in);
+
+ if(node->custom1 & CMP_CHAN_A)
+ out[3] = 1.0f - in[3];
+ else
+ out[3] = in[3];
+}
+
+static void do_invert_fac(bNode *node, float *out, float *in, float *fac)
+{
+ float col[4], facm;
+
+ do_invert(node, col, in);
+
+ /* blend inverted result against original input with fac */
+ facm = 1.0 - fac[0];
+
+ if(node->custom1 & CMP_CHAN_RGB) {
+ col[0] = fac[0]*col[0] + (facm*in[0]);
+ col[1] = fac[0]*col[1] + (facm*in[1]);
+ col[2] = fac[0]*col[2] + (facm*in[2]);
+ }
+ if(node->custom1 & CMP_CHAN_A)
+ col[3] = fac[0]*col[3] + (facm*in[3]);
+
+ QUATCOPY(out, col);
+}
+
+static void node_composit_exec_invert(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order in: fac, Image, Image */
+ /* stack order out: Image */
+ float *fac= in[0]->vec;
+
+ if(out[0]->hasoutput==0) return;
+
+ /* input no image? then only color operation */
+ if(in[1]->data==NULL && in[0]->data==NULL) {
+ do_invert_fac(node, out[0]->vec, in[1]->vec, fac);
+ }
+ else {
+ /* make output size of first available input image, or then size of fac */
+ CompBuf *cbuf= in[1]->data?in[1]->data:in[0]->data;
+
+ /* if neither RGB or A toggled on, pass through */
+ if (node->custom1 != 0) {
+ CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */
+
+ if (fac[0] < 1.0f || in[0]->data!=NULL)
+ composit2_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, in[0]->data, fac, do_invert_fac, CB_RGBA, CB_VAL);
+ else
+ composit1_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, do_invert, CB_RGBA);
+ out[0]->data= stackbuf;
+ return;
+
+ } else {
+ out[0]->data = pass_on_compbuf(cbuf);
+ return;
+ }
+ }
+}
+
+static void node_composit_init_invert(bNode *node)
+{
+ node->custom1 |= CMP_CHAN_RGB;
+}
+
+/* custom1 = mix type */
+bNodeType cmp_node_invert= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_INVERT,
+ /* name */ "Invert",
+ /* width+range */ 120, 120, 140,
+ /* class+opts */ NODE_CLASS_OP_COLOR, NODE_OPTIONS,
+ /* input sock */ cmp_node_invert_in,
+ /* output sock */ cmp_node_invert_out,
+ /* storage */ "",
+ /* execfunc */ node_composit_exec_invert,
+ /* butfunc */ NULL,
+ /* initfunc */ node_composit_init_invert,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+
+};
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_lensdist.c b/source/blender/nodes/intern/CMP_nodes/CMP_lensdist.c
new file mode 100644
index 00000000000..5dec6115fba
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_lensdist.c
@@ -0,0 +1,192 @@
+/**
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Alfredo de Greef (eeshlo)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../CMP_util.h"
+
+static bNodeSocketType cmp_node_lensdist_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 1, "Distort", 0.f, 0.f, 0.f, 0.f, -0.999f, 1.f},
+ { SOCK_VALUE, 1, "Dispersion", 0.f, 0.f, 0.f, 0.f, 0.f, 1.f},
+ { -1, 0, "" }
+};
+static bNodeSocketType cmp_node_lensdist_out[]= {
+ { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+
+static void lensDistort(CompBuf* dst, CompBuf* src, float kr, float kg, float kb, int jit, int proj, int fit)
+{
+ int x, y, z;
+ const float cx = 0.5f*(float)dst->x, cy = 0.5f*(float)dst->y;
+
+ if (proj) {
+ // shift
+ CompBuf* tsrc = dupalloc_compbuf(src);
+ for (z=0; z<tsrc->type; ++z)
+ IIR_gauss(tsrc, (kr+0.5f)*(kr+0.5f), z, 1);
+ kr *= 20.f;
+ for (y=0; y<dst->y; y++) {
+ fRGB* colp = (fRGB*)&dst->rect[y*dst->x*dst->type];
+ const float v = (y + 0.5f)/(float)dst->y;
+ for (x=0; x<dst->x; x++) {
+ const float u = (x + 0.5f)/(float)dst->x;
+ qd_getPixelLerpChan(tsrc, (u*dst->x + kr) - 0.5f, v*dst->y - 0.5f, 0, colp[x]);
+ if (tsrc->type == CB_VAL)
+ colp[x][1] = tsrc->rect[x + y*tsrc->x];
+ else
+ colp[x][1] = tsrc->rect[(x + y*tsrc->x)*tsrc->type + 1];
+ qd_getPixelLerpChan(tsrc, (u*dst->x - kr) - 0.5f, v*dst->y - 0.5f, 2, colp[x]+2);
+ }
+ }
+ free_compbuf(tsrc);
+ }
+ else {
+ // Spherical
+ // Scale factor to make bottom/top & right/left sides fit in window after deform
+ // so in the case of pincushion (kn < 0), corners will be outside window.
+ // Now also optionally scales image such that black areas are not visible when distort factor is positive
+ // (makes distorted corners match window corners, but really only valid if mk<=0.5)
+ const float mk = MAX3(kr, kg, kb);
+ const float sc = (fit && (mk > 0.f)) ? (1.f/(1.f + 2.f*mk)) : (1.f/(1.f + mk));
+ const float drg = 4.f*(kg - kr), dgb = 4.f*(kb - kg);
+ kr *= 4.f, kg *= 4.f, kb *= 4.f;
+
+ for (y=0; y<dst->y; y++) {
+ fRGB* colp = (fRGB*)&dst->rect[y*dst->x*dst->type];
+ const float v = sc*((y + 0.5f) - cy)/cy;
+ for (x=0; x<dst->x; x++) {
+ int dr = 0, dg = 0, db = 0;
+ float d, t, ln[6] = {0, 0, 0, 0, 0, 0};
+ fRGB c1, tc = {0, 0, 0, 0};
+ const float u = sc*((x + 0.5f) - cx)/cx;
+ int sta = 0, mid = 0, end = 0;
+ if ((t = 1.f - kr*(u*u + v*v)) >= 0.f) {
+ d = 1.f/(1.f + sqrtf(t));
+ ln[0] = (u*d + 0.5f)*dst->x - 0.5f, ln[1] = (v*d + 0.5f)*dst->y - 0.5f;
+ sta = 1;
+ }
+ if ((t = 1.f - kg*(u*u + v*v)) >= 0.f) {
+ d = 1.f/(1.f + sqrtf(t));
+ ln[2] = (u*d + 0.5f)*dst->x - 0.5f, ln[3] = (v*d + 0.5f)*dst->y - 0.5f;
+ mid = 1;
+ }
+ if ((t = 1.f - kb*(u*u + v*v)) >= 0.f) {
+ d = 1.f/(1.f + sqrtf(t));
+ ln[4] = (u*d + 0.5f)*dst->x - 0.5f, ln[5] = (v*d + 0.5f)*dst->y - 0.5f;
+ end = 1;
+ }
+
+ if (sta && mid && end) {
+ // RG
+ const int dx = ln[2] - ln[0], dy = ln[3] - ln[1];
+ const float dsf = sqrtf(dx*dx + dy*dy) + 1.f;
+ const int ds = (int)(jit ? ((dsf < 4.f) ? 2.f : sqrtf(dsf)) : dsf);
+ const float sd = 1.f/(float)ds;
+ for (z=0; z<ds; ++z) {
+ const float tz = ((float)z + (jit ? BLI_frand() : 0.5f))*sd;
+ t = 1.f - (kr + tz*drg)*(u*u + v*v);
+ d = 1.f / (1.f + sqrtf(t));
+ qd_getPixelLerp(src, (u*d + 0.5f)*dst->x - 0.5f, (v*d + 0.5f)*dst->y - 0.5f, c1);
+ if (src->type == CB_VAL) c1[1] = c1[2] = c1[0];
+ tc[0] += (1.f-tz)*c1[0], tc[1] += tz*c1[1];
+ dr++, dg++;
+ }
+ // GB
+ {
+ const int dx = ln[4] - ln[2], dy = ln[5] - ln[3];
+ const float dsf = sqrtf(dx*dx + dy*dy) + 1.f;
+ const int ds = (int)(jit ? ((dsf < 4.f) ? 2.f : sqrtf(dsf)) : dsf);
+ const float sd = 1.f/(float)ds;
+ for (z=0; z<ds; ++z) {
+ const float tz = ((float)z + (jit ? BLI_frand() : 0.5f))*sd;
+ t = 1.f - (kg + tz*dgb)*(u*u + v*v);
+ d = 1.f / (1.f + sqrtf(t));
+ qd_getPixelLerp(src, (u*d + 0.5f)*dst->x - 0.5f, (v*d + 0.5f)*dst->y - 0.5f, c1);
+ if (src->type == CB_VAL) c1[1] = c1[2] = c1[0];
+ tc[1] += (1.f-tz)*c1[1], tc[2] += tz*c1[2];
+ dg++, db++;
+ }
+ }
+ }
+
+ if (dr) colp[x][0] = 2.f*tc[0] / (float)dr;
+ if (dg) colp[x][1] = 2.f*tc[1] / (float)dg;
+ if (db) colp[x][2] = 2.f*tc[2] / (float)db;
+
+ }
+ }
+
+ }
+
+}
+
+
+static void node_composit_exec_lensdist(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ CompBuf *new, *img = in[0]->data;
+ NodeLensDist* nld = node->storage;
+ const float k = MAX2(MIN2(in[1]->vec[0], 1.f), -0.999f);
+ // smaller dispersion range for somewhat more control
+ const float d = 0.25f*MAX2(MIN2(in[2]->vec[0], 1.f), 0.f);
+ const float kr = MAX2(MIN2((k+d), 1.f), -0.999f), kb = MAX2(MIN2((k-d), 1.f), -0.999f);
+
+ if ((img==NULL) || (out[0]->hasoutput==0)) return;
+
+ new = alloc_compbuf(img->x, img->y, CB_RGBA, 1);
+
+ lensDistort(new, img, (nld->proj ? d : kr), k, kb, nld->jit, nld->proj, nld->fit);
+
+ out[0]->data = new;
+}
+
+
+static void node_composit_init_lensdist(bNode* node)
+{
+ NodeLensDist *nld = MEM_callocN(sizeof(NodeLensDist), "node lensdist data");
+ nld->jit = nld->proj = nld->fit = 0;
+ node->storage = nld;
+}
+
+
+bNodeType cmp_node_lensdist = {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_LENSDIST,
+ /* name */ "Lens Distortion",
+ /* width+range */ 150, 120, 200,
+ /* class+opts */ NODE_CLASS_DISTORT, NODE_OPTIONS,
+ /* input sock */ cmp_node_lensdist_in,
+ /* output sock */ cmp_node_lensdist_out,
+ /* storage */ "NodeLensDist",
+ /* execfunc */ node_composit_exec_lensdist,
+ /* butfunc */ NULL,
+ /* initfunc */ node_composit_init_lensdist,
+ /* freestoragefunc */ node_free_standard_storage,
+ /* copystoragefunc */ node_copy_standard_storage,
+ /* id */ NULL
+};
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_lummaMatte.c b/source/blender/nodes/intern/CMP_nodes/CMP_lummaMatte.c
new file mode 100644
index 00000000000..973d74d71ff
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_lummaMatte.c
@@ -0,0 +1,122 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../CMP_util.h"
+
+
+/* ******************* Luma Matte Node ********************************* */
+static bNodeSocketType cmp_node_luma_matte_in[]={
+ {SOCK_RGBA,1,"Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ {-1,0,""}
+};
+
+static bNodeSocketType cmp_node_luma_matte_out[]={
+ {SOCK_RGBA,0,"Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ {SOCK_VALUE,0,"Matte",0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ {-1,0,""}
+};
+
+static void do_luma_matte(bNode *node, float *out, float *in)
+{
+ NodeChroma *c=(NodeChroma *)node->storage;
+ float alpha;
+
+ alpha=0.0;
+
+ /* test range*/
+ if(in[0]>c->t1) {
+ alpha=1.0;
+ }
+ else if(in[1]<c->t2){
+ alpha=0.0;
+ }
+ else {/*blend */
+ alpha=(in[0]-c->t2)/(c->t1-c->t2);
+ }
+
+ /* don't make something that was more transparent less transparent */
+ if (alpha<in[3]) {
+ out[3]=alpha;
+ }
+ else {
+ out[3]=in[3];
+ }
+
+}
+
+static void node_composit_exec_luma_matte(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ CompBuf *cbuf;
+ CompBuf *outbuf;
+
+ if(in[0]->hasinput==0) return;
+ if(in[0]->data==NULL) return;
+ if(out[0]->hasoutput==0 && out[1]->hasoutput==0) return;
+
+ cbuf=typecheck_compbuf(in[0]->data, CB_RGBA);
+
+ outbuf=dupalloc_compbuf(cbuf);
+
+ composit1_pixel_processor(node, outbuf, cbuf, in[1]->vec, do_rgba_to_yuva, CB_RGBA);
+ composit1_pixel_processor(node, outbuf, outbuf, in[1]->vec, do_luma_matte, CB_RGBA);
+ composit1_pixel_processor(node, outbuf, outbuf, in[1]->vec, do_yuva_to_rgba, CB_RGBA);
+
+ generate_preview(node, outbuf);
+ out[0]->data=outbuf;
+ if (out[1]->hasoutput)
+ out[1]->data=valbuf_from_rgbabuf(outbuf, CHAN_A);
+ if(cbuf!=in[0]->data)
+ free_compbuf(cbuf);
+}
+
+static void node_composit_init_luma_matte(bNode *node)
+{
+ NodeChroma *c= MEM_callocN(sizeof(NodeChroma), "node chroma");
+ node->storage=c;
+ c->t1= 0.0f;
+ c->t2= 0.0f;
+};
+
+bNodeType cmp_node_luma_matte={
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_LUMA_MATTE,
+ /* name */ "Luminance Key",
+ /* width+range */ 200, 80, 250,
+ /* class+opts */ NODE_CLASS_MATTE, NODE_PREVIEW|NODE_OPTIONS,
+ /* input sock */ cmp_node_luma_matte_in,
+ /* output sock */ cmp_node_luma_matte_out,
+ /* storage */ "NodeChroma",
+ /* execfunc */ node_composit_exec_luma_matte,
+ /* butfunc */ NULL,
+ /* initfunc */ node_composit_init_luma_matte,
+ /* freestoragefunc */ node_free_standard_storage,
+ /* copystoragefunc */ node_copy_standard_storage,
+ /* id */ NULL
+};
+
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_mapUV.c b/source/blender/nodes/intern/CMP_nodes/CMP_mapUV.c
new file mode 100644
index 00000000000..ae3e5875aae
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_mapUV.c
@@ -0,0 +1,149 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../CMP_util.h"
+
+/* **************** Map UV ******************** */
+
+static bNodeSocketType cmp_node_mapuv_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VECTOR, 1, "UV", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketType cmp_node_mapuv_out[]= {
+ { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+/* foreach UV, use these values to read in cbuf and write to stackbuf */
+/* stackbuf should be zeroed */
+static void do_mapuv(CompBuf *stackbuf, CompBuf *cbuf, CompBuf *uvbuf, float threshold)
+{
+ ImBuf *ibuf;
+ float *out= stackbuf->rect, *uv, *uvnext, *uvprev;
+ float dx, dy, alpha;
+ int x, y, sx, sy, row= 3*stackbuf->x;
+
+ /* ibuf needed for sampling */
+ ibuf= IMB_allocImBuf(cbuf->x, cbuf->y, 32, 0, 0);
+ ibuf->rect_float= cbuf->rect;
+
+ /* vars for efficient looping */
+ uv= uvbuf->rect;
+ uvnext= uv+row;
+ uvprev= uv-row;
+ sx= stackbuf->x;
+ sy= stackbuf->y;
+
+ for(y=0; y<sy; y++) {
+ for(x=0; x<sx; x++, out+=4, uv+=3, uvnext+=3, uvprev+=3) {
+ if(x>0 && x<sx-1 && y>0 && y<sy-1) {
+ if(uv[2]!=0.0f) {
+
+ /* adaptive sampling, red (U) channel */
+ dx= 0.5f*(fabs(uv[0]-uv[-3]) + fabs(uv[0]-uv[3]));
+
+ dx+= 0.25f*(fabs(uv[0]-uvprev[-3]) + fabs(uv[0]-uvnext[-3]));
+ dx+= 0.25f*(fabs(uv[0]-uvprev[+3]) + fabs(uv[0]-uvnext[+3]));
+
+ /* adaptive sampling, green (V) channel */
+ dy= 0.5f*(fabs(uv[1]-uv[-row+1]) + fabs(uv[1]-uv[row+1]));
+
+ dy+= 0.25f*(fabs(uv[1]-uvprev[+1-3]) + fabs(uv[1]-uvnext[+1-3]));
+ dy+= 0.25f*(fabs(uv[1]-uvprev[+1+3]) + fabs(uv[1]-uvnext[+1+3]));
+
+ /* UV to alpha threshold */
+ alpha= 1.0f - threshold*(dx+dy);
+ if(alpha<0.0f) alpha= 0.0f;
+ else alpha*= uv[2];
+
+ /* should use mipmap */
+ if(dx > 0.20f) dx= 0.20f;
+ if(dy > 0.20f) dy= 0.20f;
+
+ ibuf_sample(ibuf, uv[0], uv[1], dx, dy, out);
+ /* premul */
+ if(alpha<1.0f) {
+ out[0]*= alpha;
+ out[1]*= alpha;
+ out[2]*= alpha;
+ out[3]*= alpha;
+ }
+ }
+ }
+ }
+ }
+
+ IMB_freeImBuf(ibuf);
+}
+
+
+static void node_composit_exec_mapuv(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ if(out[0]->hasoutput==0)
+ return;
+
+ if(in[0]->data && in[1]->data) {
+ CompBuf *cbuf= in[0]->data;
+ CompBuf *uvbuf= in[1]->data;
+ CompBuf *stackbuf;
+
+ cbuf= typecheck_compbuf(cbuf, CB_RGBA);
+ uvbuf= typecheck_compbuf(uvbuf, CB_VEC3);
+ stackbuf= alloc_compbuf(uvbuf->x, uvbuf->y, CB_RGBA, 1); /* allocs */;
+
+ do_mapuv(stackbuf, cbuf, uvbuf, 0.05f*(float)node->custom1);
+
+ out[0]->data= stackbuf;
+
+ if(cbuf!=in[0]->data)
+ free_compbuf(cbuf);
+ if(uvbuf!=in[1]->data)
+ free_compbuf(uvbuf);
+ }
+}
+
+bNodeType cmp_node_mapuv= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_MAP_UV,
+ /* name */ "Map UV",
+ /* width+range */ 140, 100, 320,
+ /* class+opts */ NODE_CLASS_DISTORT, NODE_OPTIONS,
+ /* input sock */ cmp_node_mapuv_in,
+ /* output sock */ cmp_node_mapuv_out,
+ /* storage */ "",
+ /* execfunc */ node_composit_exec_mapuv,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+};
+
+
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_mapValue.c b/source/blender/nodes/intern/CMP_nodes/CMP_mapValue.c
new file mode 100644
index 00000000000..8f0f9621c2e
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_mapValue.c
@@ -0,0 +1,101 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../CMP_util.h"
+
+/* **************** MAP VALUE ******************** */
+static bNodeSocketType cmp_node_map_value_in[]= {
+ { SOCK_VALUE, 1, "Value", 1.0f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketType cmp_node_map_value_out[]= {
+ { SOCK_VALUE, 0, "Value", 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void do_map_value(bNode *node, float *out, float *src)
+{
+ TexMapping *texmap= node->storage;
+
+ out[0]= (src[0] + texmap->loc[0])*texmap->size[0];
+ if(texmap->flag & TEXMAP_CLIP_MIN)
+ if(out[0]<texmap->min[0])
+ out[0]= texmap->min[0];
+ if(texmap->flag & TEXMAP_CLIP_MAX)
+ if(out[0]>texmap->max[0])
+ out[0]= texmap->max[0];
+}
+
+static void node_composit_exec_map_value(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order in: valbuf */
+ /* stack order out: valbuf */
+ if(out[0]->hasoutput==0) return;
+
+ /* input no image? then only value operation */
+ if(in[0]->data==NULL) {
+ do_map_value(node, out[0]->vec, in[0]->vec);
+ }
+ else {
+ /* make output size of input image */
+ CompBuf *cbuf= in[0]->data;
+ CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1); /* allocs */
+
+ composit1_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, do_map_value, CB_VAL);
+
+ out[0]->data= stackbuf;
+ }
+}
+
+
+static void node_composit_init_map_value(bNode* node)
+{
+ node->storage= add_mapping();
+}
+
+bNodeType cmp_node_map_value= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_MAP_VALUE,
+ /* name */ "Map Value",
+ /* width+range */ 100, 60, 150,
+ /* class+opts */ NODE_CLASS_OP_VECTOR, NODE_OPTIONS,
+ /* input sock */ cmp_node_map_value_in,
+ /* output sock */ cmp_node_map_value_out,
+ /* storage */ "TexMapping",
+ /* execfunc */ node_composit_exec_map_value,
+ /* butfunc */ NULL,
+ /* initfunc */ node_composit_init_map_value,
+ /* freestoragefunc */ node_free_standard_storage,
+ /* copystoragefunc */ node_copy_standard_storage,
+ /* id */ NULL
+
+};
+
+
+
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_math.c b/source/blender/nodes/intern/CMP_nodes/CMP_math.c
new file mode 100644
index 00000000000..cf2af9bbc11
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_math.c
@@ -0,0 +1,187 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../CMP_util.h"
+
+
+/* **************** SCALAR MATH ******************** */
+static bNodeSocketType cmp_node_math_in[]= {
+ { SOCK_VALUE, 1, "Value", 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f},
+ { SOCK_VALUE, 1, "Value", 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f},
+ { -1, 0, "" }
+};
+
+static bNodeSocketType cmp_node_math_out[]= {
+ { SOCK_VALUE, 0, "Value", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void do_math(bNode *node, float *out, float *in, float *in2)
+{
+ switch(node->custom1)
+ {
+ case 0: /* Add */
+ out[0]= in[0] + in2[0];
+ break;
+ case 1: /* Subtract */
+ out[0]= in[0] - in2[0];
+ break;
+ case 2: /* Multiply */
+ out[0]= in[0] * in2[0];
+ break;
+ case 3: /* Divide */
+ {
+ if(in[1]==0) /* We don't want to divide by zero. */
+ out[0]= 0.0;
+ else
+ out[0]= in[0] / in2[0];
+ }
+ break;
+ case 4: /* Sine */
+ out[0]= sin(in[0]);
+ break;
+ case 5: /* Cosine */
+ out[0]= cos(in[0]);
+ break;
+ case 6: /* Tangent */
+ out[0]= tan(in[0]);
+ break;
+ case 7: /* Arc-Sine */
+ {
+ /* Can't do the impossible... */
+ if(in[0] <= 1 && in[0] >= -1 )
+ out[0]= asin(in[0]);
+ else
+ out[0]= 0.0;
+ }
+ break;
+ case 8: /* Arc-Cosine */
+ {
+ /* Can't do the impossible... */
+ if( in[0] <= 1 && in[0] >= -1 )
+ out[0]= acos(in[0]);
+ else
+ out[0]= 0.0;
+ }
+ break;
+ case 9: /* Arc-Tangent */
+ out[0]= atan(in[0]);
+ break;
+ case 10: /* Power */
+ {
+ /* Don't want any imaginary numbers... */
+ if( in[0] >= 0 )
+ out[0]= pow(in[0], in2[0]);
+ else
+ out[0]= 0.0;
+ }
+ break;
+ case 11: /* Logarithm */
+ {
+ /* Don't want any imaginary numbers... */
+ if( in[0] > 0 && in2[0] > 0 )
+ out[0]= log(in[0]) / log(in2[0]);
+ else
+ out[0]= 0.0;
+ }
+ break;
+ case 12: /* Minimum */
+ {
+ if( in[0] < in2[0] )
+ out[0]= in[0];
+ else
+ out[0]= in2[0];
+ }
+ break;
+ case 13: /* Maximum */
+ {
+ if( in[0] > in2[0] )
+ out[0]= in[0];
+ else
+ out[0]= in2[0];
+ }
+ break;
+ case 14: /* Round */
+ {
+ out[0]= (int)(in[0] + 0.5f);
+ }
+ break;
+ }
+}
+
+static void node_composit_exec_math(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ CompBuf *cbuf=in[0]->data;
+ CompBuf *cbuf2=in[1]->data;
+ CompBuf *stackbuf;
+
+ /* check for inputs and outputs for early out*/
+ if(in[0]->hasinput==0 && in[1]->hasinput==0) return;
+ if(out[0]->hasoutput==0) return;
+
+ /* no image-color operation */
+ if(in[0]->data==NULL && in[1]->data==NULL) {
+ do_math(node, out[0]->vec, in[0]->vec, in[1]->vec);
+ return;
+ }
+
+ /*create output based on first input */
+ if(cbuf) {
+ stackbuf=alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1);
+ }
+ /* and if it doesn't exist use the second input since we
+ know that one of them must exist at this point*/
+ else {
+ stackbuf=alloc_compbuf(cbuf2->x, cbuf2->y, CB_VAL, 1);
+ }
+
+ /* operate in case there's valid size */
+ composit2_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec, do_math, CB_VAL, CB_VAL);
+ out[0]->data= stackbuf;
+}
+
+bNodeType cmp_node_math= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_MATH,
+ /* name */ "Math",
+ /* width+range */ 120, 110, 160,
+ /* class+opts */ NODE_CLASS_CONVERTOR, NODE_OPTIONS,
+ /* input sock */ cmp_node_math_in,
+ /* output sock */ cmp_node_math_out,
+ /* storage */ "",
+ /* execfunc */ node_composit_exec_math,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+};
+
+
+
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_mixrgb.c b/source/blender/nodes/intern/CMP_nodes/CMP_mixrgb.c
new file mode 100644
index 00000000000..6a4916b3fac
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_mixrgb.c
@@ -0,0 +1,96 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+#include "../CMP_util.h"
+
+/* **************** MIX RGB ******************** */
+static bNodeSocketType cmp_node_mix_rgb_in[]= {
+ { SOCK_VALUE, 1, "Fac", 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 5.0f},
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketType cmp_node_mix_rgb_out[]= {
+ { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void do_mix_rgb(bNode *node, float *out, float *in1, float *in2, float *fac)
+{
+ float col[3];
+
+ VECCOPY(col, in1);
+ if(node->custom2)
+ ramp_blend(node->custom1, col, col+1, col+2, in2[3]*fac[0], in2);
+ else
+ ramp_blend(node->custom1, col, col+1, col+2, fac[0], in2);
+ VECCOPY(out, col);
+ out[3]= in1[3];
+}
+
+static void node_composit_exec_mix_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order in: fac, Image, Image */
+ /* stack order out: Image */
+ float *fac= in[0]->vec;
+
+ if(out[0]->hasoutput==0) return;
+
+ /* input no image? then only color operation */
+ if(in[1]->data==NULL && in[2]->data==NULL) {
+ do_mix_rgb(node, out[0]->vec, in[1]->vec, in[2]->vec, fac);
+ }
+ else {
+ /* make output size of first available input image */
+ CompBuf *cbuf= in[1]->data?in[1]->data:in[2]->data;
+ CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */
+
+ composit3_pixel_processor(node, stackbuf, in[1]->data, in[1]->vec, in[2]->data, in[2]->vec, in[0]->data, fac, do_mix_rgb, CB_RGBA, CB_RGBA, CB_VAL);
+
+ out[0]->data= stackbuf;
+ }
+}
+
+/* custom1 = mix type */
+bNodeType cmp_node_mix_rgb= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_MIX_RGB,
+ /* name */ "Mix",
+ /* width+range */ 110, 60, 120,
+ /* class+opts */ NODE_CLASS_OP_COLOR, NODE_OPTIONS,
+ /* input sock */ cmp_node_mix_rgb_in,
+ /* output sock */ cmp_node_mix_rgb_out,
+ /* storage */ "",
+ /* execfunc */ node_composit_exec_mix_rgb,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+
+};
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_normal.c b/source/blender/nodes/intern/CMP_nodes/CMP_normal.c
new file mode 100644
index 00000000000..5219b224c6c
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_normal.c
@@ -0,0 +1,97 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../CMP_util.h"
+
+
+/* **************** NORMAL ******************** */
+static bNodeSocketType cmp_node_normal_in[]= {
+ { SOCK_VECTOR, 1, "Normal", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static bNodeSocketType cmp_node_normal_out[]= {
+ { SOCK_VECTOR, 0, "Normal", 0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f},
+ { SOCK_VALUE, 0, "Dot", 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void do_normal(bNode *node, float *out, float *in)
+{
+ bNodeSocket *sock= node->outputs.first;
+ float *nor= sock->ns.vec;
+
+ /* render normals point inside... the widget points outside */
+ out[0]= -INPR(nor, in);
+}
+
+/* generates normal, does dot product */
+static void node_composit_exec_normal(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ bNodeSocket *sock= node->outputs.first;
+ /* stack order input: normal */
+ /* stack order output: normal, value */
+
+ /* input no image? then only vector op */
+ if(in[0]->data==NULL) {
+ VECCOPY(out[0]->vec, sock->ns.vec);
+ /* render normals point inside... the widget points outside */
+ out[1]->vec[0]= -INPR(out[0]->vec, in[0]->vec);
+ }
+ else if(out[1]->hasoutput) {
+ /* make output size of input image */
+ CompBuf *cbuf= in[0]->data;
+ CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1); /* allocs */
+
+ composit1_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, do_normal, CB_VEC3);
+
+ out[1]->data= stackbuf;
+ }
+
+
+}
+
+bNodeType cmp_node_normal= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_NORMAL,
+ /* name */ "Normal",
+ /* width+range */ 100, 60, 200,
+ /* class+opts */ NODE_CLASS_OP_VECTOR, NODE_OPTIONS,
+ /* input sock */ cmp_node_normal_in,
+ /* output sock */ cmp_node_normal_out,
+ /* storage */ "",
+ /* execfunc */ node_composit_exec_normal,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+
+};
+
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_normalize.c b/source/blender/nodes/intern/CMP_nodes/CMP_normalize.c
new file mode 100644
index 00000000000..a62e4be4015
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_normalize.c
@@ -0,0 +1,113 @@
+/**
+ * $Id: CMP_normalize.c,v 1.0 2007/03/24 06:57:29 scourage Exp $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): gsr b3d, and a very minor edit from Robert Holcomb
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../CMP_util.h"
+
+
+/* **************** NORMALIZE single channel, useful for Z buffer ******************** */
+static bNodeSocketType cmp_node_normalize_in[]= {
+ { SOCK_VALUE, 1, "Value", 1.0f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketType cmp_node_normalize_out[]= {
+ { SOCK_VALUE, 0, "Value", 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void do_normalize(bNode *node, float *out, float *src, float *min, float *mult)
+{
+ float res;
+ res = (src[0] - min[0]) * mult[0];
+ if (res > 1.0f) {
+ out[0] = 1.0f;
+ }
+ else if (res < 0.0f) {
+ out[0] = 0.0f;
+ }
+ else {
+ out[0] = res;
+ }
+}
+
+#define BLENDER_ZMAX 10000.0f
+
+static void node_composit_exec_normalize(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order in: valbuf */
+ /* stack order out: valbuf */
+ if(out[0]->hasoutput==0) return;
+
+ /* input no image? then only value operation */
+ if(in[0]->data==NULL) {
+ QUATCOPY(out[0]->vec, in[0]->vec);
+ }
+ else {
+ float min = 1.0f+BLENDER_ZMAX;
+ float max = -1.0f-BLENDER_ZMAX;
+ float mult = 1.0f;
+ float *val;
+ /* make output size of input image */
+ CompBuf *cbuf= in[0]->data;
+ int tot= cbuf->x*cbuf->y;
+ CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1); /* allocs */
+
+ for (val = cbuf->rect; tot; tot--, val++) {
+ if ((*val > max) && (*val < BLENDER_ZMAX)) {
+ max = *val;
+ }
+ if (*val < min) {
+ min = *val;
+ }
+ }
+ mult = 1.0f/(max-min);
+
+ printf("min %f max %f\n", min, max);
+
+ composit3_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, NULL, &min, NULL, &mult, do_normalize, CB_VAL, CB_VAL, CB_VAL);
+
+ out[0]->data= stackbuf;
+ }
+}
+
+bNodeType cmp_node_normalize= {
+ /* *next, *prev*/ NULL, NULL,
+ /* type code */ CMP_NODE_NORMALIZE,
+ /* name */ "Normalize",
+ /* width+range */ 100, 60, 150,
+ /* class+opts */ NODE_CLASS_OP_VECTOR, NODE_OPTIONS,
+ /* input sock */ cmp_node_normalize_in,
+ /* output sock */ cmp_node_normalize_out,
+ /* storage */ "TexMapping",
+ /* execfunc */ node_composit_exec_normalize,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+};
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_outputFile.c b/source/blender/nodes/intern/CMP_nodes/CMP_outputFile.c
new file mode 100644
index 00000000000..722b00d57a9
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_outputFile.c
@@ -0,0 +1,112 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../CMP_util.h"
+
+/* **************** OUTPUT FILE ******************** */
+static bNodeSocketType cmp_node_output_file_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 1, "Z", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void node_composit_exec_output_file(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* image assigned to output */
+ /* stack order input sockets: col, alpha */
+
+ if(in[0]->data) {
+ RenderData *rd= data;
+ NodeImageFile *nif= node->storage;
+ if(nif->sfra!=nif->efra && (rd->cfra<nif->sfra || rd->cfra>nif->efra)) {
+ return; /* BAIL OUT RETURN */
+ }
+ else {
+ CompBuf *cbuf= typecheck_compbuf(in[0]->data, CB_RGBA);
+ ImBuf *ibuf= IMB_allocImBuf(cbuf->x, cbuf->y, 32, 0, 0);
+ char string[256];
+
+ ibuf->rect_float= cbuf->rect;
+ ibuf->dither= rd->dither_intensity;
+ if(in[1]->data) {
+ CompBuf *zbuf= in[1]->data;
+ if(zbuf->type==CB_VAL && zbuf->x==cbuf->x && zbuf->y==cbuf->y) {
+ nif->subimtype|= R_OPENEXR_ZBUF;
+ ibuf->zbuf_float= zbuf->rect;
+ }
+ }
+
+ BKE_makepicstring(string, nif->name, rd->cfra, nif->imtype);
+
+ if(0 == BKE_write_ibuf(ibuf, string, nif->imtype, nif->subimtype, nif->imtype==R_OPENEXR?nif->codec:nif->quality))
+ printf("Cannot save Node File Output to %s\n", string);
+ else
+ printf("Saved: %s\n", string);
+
+ IMB_freeImBuf(ibuf);
+
+ generate_preview(node, cbuf);
+
+ if(in[0]->data != cbuf)
+ free_compbuf(cbuf);
+ }
+ }
+}
+
+static void node_composit_init_output_file(bNode *node)
+{
+ NodeImageFile *nif= MEM_callocN(sizeof(NodeImageFile), "node image file");
+ node->storage= nif;
+ BLI_strncpy(nif->name, G.scene->r.pic, sizeof(nif->name));
+ nif->imtype= G.scene->r.imtype;
+ nif->subimtype= G.scene->r.subimtype;
+ nif->quality= G.scene->r.quality;
+ nif->sfra= G.scene->r.sfra;
+ nif->efra= G.scene->r.efra;
+};
+
+bNodeType cmp_node_output_file= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_OUTPUT_FILE,
+ /* name */ "File Output",
+ /* width+range */ 140, 80, 300,
+ /* class+opts */ NODE_CLASS_OUTPUT, NODE_PREVIEW|NODE_OPTIONS,
+ /* input sock */ cmp_node_output_file_in,
+ /* output sock */ NULL,
+ /* storage */ "NodeImageFile",
+ /* execfunc */ node_composit_exec_output_file,
+ /* butfunc */ NULL,
+ /* initfunc */ node_composit_init_output_file,
+ /* freestoragefunc */ node_free_standard_storage,
+ /* copystoragefunc */ node_copy_standard_storage,
+ /* id */ NULL
+
+};
+
+
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_rgb.c b/source/blender/nodes/intern/CMP_nodes/CMP_rgb.c
new file mode 100644
index 00000000000..ae2678dc5f0
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_rgb.c
@@ -0,0 +1,64 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../CMP_util.h"
+
+
+/* **************** RGB ******************** */
+static bNodeSocketType cmp_node_rgb_out[]= {
+ { SOCK_RGBA, 0, "RGBA", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void node_composit_exec_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ bNodeSocket *sock= node->outputs.first;
+
+ VECCOPY(out[0]->vec, sock->ns.vec);
+}
+
+bNodeType cmp_node_rgb= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_RGB,
+ /* name */ "RGB",
+ /* width+range */ 100, 60, 140,
+ /* class+opts */ NODE_CLASS_INPUT, NODE_OPTIONS,
+ /* input sock */ NULL,
+ /* output sock */ cmp_node_rgb_out,
+ /* storage */ "",
+ /* execfunc */ node_composit_exec_rgb,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+
+};
+
+
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_rotate.c b/source/blender/nodes/intern/CMP_nodes/CMP_rotate.c
new file mode 100644
index 00000000000..d32c2ccd9e7
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_rotate.c
@@ -0,0 +1,150 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../CMP_util.h"
+
+/* **************** Rotate ******************** */
+
+static bNodeSocketType cmp_node_rotate_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 1, "Degr", 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketType cmp_node_rotate_out[]= {
+ { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+/* function assumes out to be zero'ed, only does RGBA */
+static void bilinear_interpolation_rotate(CompBuf *in, float *out, float u, float v)
+{
+ float *row1, *row2, *row3, *row4, a, b;
+ float a_b, ma_b, a_mb, ma_mb;
+ float empty[4]= {0.0f, 0.0f, 0.0f, 0.0f};
+ int y1, y2, x1, x2;
+
+ x1= (int)floor(u);
+ x2= (int)ceil(u);
+ y1= (int)floor(v);
+ y2= (int)ceil(v);
+
+ /* sample area entirely outside image? */
+ if(x2<0 || x1>in->x-1 || y2<0 || y1>in->y-1)
+ return;
+
+ /* sample including outside of edges of image */
+ if(x1<0 || y1<0) row1= empty;
+ else row1= in->rect + in->x * y1 * in->type + in->type*x1;
+
+ if(x1<0 || y2>in->y-1) row2= empty;
+ else row2= in->rect + in->x * y2 * in->type + in->type*x1;
+
+ if(x2>in->x-1 || y1<0) row3= empty;
+ else row3= in->rect + in->x * y1 * in->type + in->type*x2;
+
+ if(x2>in->x-1 || y2>in->y-1) row4= empty;
+ else row4= in->rect + in->x * y2 * in->type + in->type*x2;
+
+ a= u-floor(u);
+ b= v-floor(v);
+ a_b= a*b; ma_b= (1.0f-a)*b; a_mb= a*(1.0f-b); ma_mb= (1.0f-a)*(1.0f-b);
+
+ out[0]= ma_mb*row1[0] + a_mb*row3[0] + ma_b*row2[0]+ a_b*row4[0];
+ out[1]= ma_mb*row1[1] + a_mb*row3[1] + ma_b*row2[1]+ a_b*row4[1];
+ out[2]= ma_mb*row1[2] + a_mb*row3[2] + ma_b*row2[2]+ a_b*row4[2];
+ out[3]= ma_mb*row1[3] + a_mb*row3[3] + ma_b*row2[3]+ a_b*row4[3];
+}
+
+/* only supports RGBA nodes now */
+static void node_composit_exec_rotate(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+
+ if(out[0]->hasoutput==0)
+ return;
+
+ if(in[0]->data) {
+ CompBuf *cbuf= typecheck_compbuf(in[0]->data, CB_RGBA);
+ CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* note, this returns zero'd image */
+ float *ofp, rad, u, v, s, c, centx, centy, miny, maxy, minx, maxx;
+ int x, y, yo;
+
+ rad= (M_PI*in[1]->vec[0])/180.0f;
+
+ s= sin(rad);
+ c= cos(rad);
+ centx= cbuf->x/2;
+ centy= cbuf->y/2;
+
+ minx= -centx;
+ maxx= -centx + (float)cbuf->x;
+ miny= -centy;
+ maxy= -centy + (float)cbuf->y;
+
+ for(y=miny; y<maxy; y++) {
+ yo= y+(int)centy;
+ ofp= stackbuf->rect + 4*yo*stackbuf->x;
+
+ for(x=minx; x<maxx; x++, ofp+=4) {
+ u= c*x + y*s + centx;
+ v= -s*x + c*y + centy;
+
+ bilinear_interpolation_rotate(cbuf, ofp, u, v);
+ }
+ }
+ /* rotate offset vector too, but why negative rad, ehh?? Has to be replaced with [3][3] matrix once (ton) */
+ s= sin(-rad);
+ c= cos(-rad);
+ centx= (float)cbuf->xof; centy= (float)cbuf->yof;
+ stackbuf->xof= (int)( c*centx + s*centy);
+ stackbuf->yof= (int)(-s*centx + c*centy);
+
+ /* pass on output and free */
+ out[0]->data= stackbuf;
+ if(cbuf!=in[0]->data)
+ free_compbuf(cbuf);
+
+ }
+}
+
+bNodeType cmp_node_rotate= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_ROTATE,
+ /* name */ "Rotate",
+ /* width+range */ 140, 100, 320,
+ /* class+opts */ NODE_CLASS_DISTORT, NODE_OPTIONS,
+ /* input sock */ cmp_node_rotate_in,
+ /* output sock */ cmp_node_rotate_out,
+ /* storage */ "",
+ /* execfunc */ node_composit_exec_rotate,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+};
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_scale.c b/source/blender/nodes/intern/CMP_nodes/CMP_scale.c
new file mode 100644
index 00000000000..a8477f4264e
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_scale.c
@@ -0,0 +1,125 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../CMP_util.h"
+
+/* **************** Scale ******************** */
+
+#define CMP_SCALE_MAX 12000
+
+static bNodeSocketType cmp_node_scale_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 1, "X", 1.0f, 0.0f, 0.0f, 0.0f, 0.0001f, CMP_SCALE_MAX},
+ { SOCK_VALUE, 1, "Y", 1.0f, 0.0f, 0.0f, 0.0f, 0.0001f, CMP_SCALE_MAX},
+ { -1, 0, "" }
+};
+static bNodeSocketType cmp_node_scale_out[]= {
+ { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+/* only supports RGBA nodes now */
+/* node->custom1 stores if input values are absolute or relative scale */
+static void node_composit_exec_scale(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ if(out[0]->hasoutput==0)
+ return;
+
+ if(in[0]->data) {
+ CompBuf *stackbuf, *cbuf= typecheck_compbuf(in[0]->data, CB_RGBA);
+ ImBuf *ibuf;
+ int newx, newy;
+
+ if(node->custom1==CMP_SCALE_RELATIVE) {
+ newx= MAX2((int)(in[1]->vec[0]*cbuf->x), 1);
+ newy= MAX2((int)(in[2]->vec[0]*cbuf->y), 1);
+ }
+ else { /* CMP_SCALE_ABSOLUTE */
+ newx= (int)in[1]->vec[0];
+ newy= (int)in[2]->vec[0];
+ }
+ newx= MIN2(newx, CMP_SCALE_MAX);
+ newy= MIN2(newy, CMP_SCALE_MAX);
+
+ ibuf= IMB_allocImBuf(cbuf->x, cbuf->y, 32, 0, 0);
+ if(ibuf) {
+ ibuf->rect_float= cbuf->rect;
+ IMB_scaleImBuf(ibuf, newx, newy);
+
+ if(ibuf->rect_float == cbuf->rect) {
+ /* no scaling happened. */
+ stackbuf= pass_on_compbuf(in[0]->data);
+ }
+ else {
+ stackbuf= alloc_compbuf(newx, newy, CB_RGBA, 0);
+ stackbuf->rect= ibuf->rect_float;
+ stackbuf->malloc= 1;
+ }
+
+ ibuf->rect_float= NULL;
+ ibuf->mall &= ~IB_rectfloat;
+ IMB_freeImBuf(ibuf);
+
+ /* also do the translation vector */
+ stackbuf->xof = (int)(((float)newx/(float)cbuf->x) * (float)cbuf->xof);
+ stackbuf->yof = (int)(((float)newy/(float)cbuf->y) * (float)cbuf->yof);
+ }
+ else {
+ stackbuf= dupalloc_compbuf(cbuf);
+ printf("Scaling to %dx%d failed\n", newx, newy);
+ }
+
+ out[0]->data= stackbuf;
+ if(cbuf!=in[0]->data)
+ free_compbuf(cbuf);
+ }
+};
+
+bNodeType cmp_node_scale= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_SCALE,
+ /* name */ "Scale",
+ /* width+range */ 140, 100, 320,
+ /* class+opts */ NODE_CLASS_DISTORT, NODE_OPTIONS,
+ /* input sock */ cmp_node_scale_in,
+ /* output sock */ cmp_node_scale_out,
+ /* storage */ "",
+ /* execfunc */ node_composit_exec_scale,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+};
+
+
+
+
+
+
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_sepcombHSVA.c b/source/blender/nodes/intern/CMP_nodes/CMP_sepcombHSVA.c
new file mode 100644
index 00000000000..e7598726555
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_sepcombHSVA.c
@@ -0,0 +1,191 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../CMP_util.h"
+
+
+/* **************** SEPARATE HSVA ******************** */
+static bNodeSocketType cmp_node_sephsva_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketType cmp_node_sephsva_out[]= {
+ { SOCK_VALUE, 0, "H", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 0, "S", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 0, "V", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 0, "A", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void do_sephsva(bNode *node, float *out, float *in)
+{
+ float h, s, v;
+
+ rgb_to_hsv(in[0], in[1], in[2], &h, &s, &v);
+
+ out[0]= h;
+ out[1]= s;
+ out[2]= v;
+ out[3]= in[3];
+}
+
+static void node_composit_exec_sephsva(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order out: bw channels */
+ /* stack order in: col */
+
+ /* input no image? then only color operation */
+ if(in[0]->data==NULL) {
+ float h, s, v;
+
+ rgb_to_hsv(in[0]->vec[0], in[0]->vec[1], in[0]->vec[2], &h, &s, &v);
+
+ out[0]->vec[0] = h;
+ out[1]->vec[0] = s;
+ out[2]->vec[0] = v;
+ out[3]->vec[0] = in[0]->vec[3];
+ }
+ else if ((out[0]->hasoutput) || (out[1]->hasoutput) || (out[2]->hasoutput) || (out[3]->hasoutput)) {
+ /* create new buffer so input buffer doesn't get corrupted */
+ CompBuf *cbuf= dupalloc_compbuf(in[0]->data);
+ CompBuf *cbuf2= typecheck_compbuf(cbuf, CB_RGBA);
+
+ /* convert the RGB stackbuf to an HSV representation */
+ composit1_pixel_processor(node, cbuf2, cbuf2, in[0]->vec, do_sephsva, CB_RGBA);
+
+ /* separate each of those channels */
+ if(out[0]->hasoutput)
+ out[0]->data= valbuf_from_rgbabuf(cbuf2, CHAN_R);
+ if(out[1]->hasoutput)
+ out[1]->data= valbuf_from_rgbabuf(cbuf2, CHAN_G);
+ if(out[2]->hasoutput)
+ out[2]->data= valbuf_from_rgbabuf(cbuf2, CHAN_B);
+ if(out[3]->hasoutput)
+ out[3]->data= valbuf_from_rgbabuf(cbuf2, CHAN_A);
+
+ /*not used anymore */
+ if(cbuf2!=cbuf)
+ free_compbuf(cbuf2);
+ free_compbuf(cbuf);
+ }
+}
+
+bNodeType cmp_node_sephsva= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_SEPHSVA,
+ /* name */ "Separate HSVA",
+ /* width+range */ 80, 40, 140,
+ /* class+opts */ NODE_CLASS_CONVERTOR, 0,
+ /* input sock */ cmp_node_sephsva_in,
+ /* output sock */ cmp_node_sephsva_out,
+ /* storage */ "",
+ /* execfunc */ node_composit_exec_sephsva,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+
+};
+
+/* **************** COMBINE HSVA ******************** */
+static bNodeSocketType cmp_node_combhsva_in[]= {
+ { SOCK_VALUE, 1, "H", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 1, "S", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 1, "V", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 1, "A", 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketType cmp_node_combhsva_out[]= {
+ { SOCK_RGBA, 0, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void do_comb_hsva(bNode *node, float *out, float *in1, float *in2, float *in3, float *in4)
+{
+ float r,g,b;
+ hsv_to_rgb(in1[0], in2[0], in3[0], &r, &g, &b);
+
+ out[0] = r;
+ out[1] = g;
+ out[2] = b;
+ out[3] = in4[0];
+}
+
+static void node_composit_exec_combhsva(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order out: 1 rgba channels */
+ /* stack order in: 4 value channels */
+
+ /* input no image? then only color operation */
+ if((in[0]->data==NULL) && (in[1]->data==NULL) && (in[2]->data==NULL) && (in[3]->data==NULL)) {
+ out[0]->vec[0] = in[0]->vec[0];
+ out[0]->vec[1] = in[1]->vec[0];
+ out[0]->vec[2] = in[2]->vec[0];
+ out[0]->vec[3] = in[3]->vec[0];
+ }
+ else {
+ /* make output size of first available input image */
+ CompBuf *cbuf;
+ CompBuf *stackbuf;
+
+ /* allocate a CompBuf the size of the first available input */
+ if (in[0]->data) cbuf = in[0]->data;
+ else if (in[1]->data) cbuf = in[1]->data;
+ else if (in[2]->data) cbuf = in[2]->data;
+ else cbuf = in[3]->data;
+
+ stackbuf = alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */
+
+ composit4_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec,
+ in[2]->data, in[2]->vec, in[3]->data, in[3]->vec,
+ do_comb_hsva, CB_VAL, CB_VAL, CB_VAL, CB_VAL);
+
+ out[0]->data= stackbuf;
+ }
+}
+
+bNodeType cmp_node_combhsva= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_COMBHSVA,
+ /* name */ "Combine HSVA",
+ /* width+range */ 80, 40, 140,
+ /* class+opts */ NODE_CLASS_CONVERTOR, NODE_OPTIONS,
+ /* input sock */ cmp_node_combhsva_in,
+ /* output sock */ cmp_node_combhsva_out,
+ /* storage */ "",
+ /* execfunc */ node_composit_exec_combhsva,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+};
+
+
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_sepcombRGBA.c b/source/blender/nodes/intern/CMP_nodes/CMP_sepcombRGBA.c
new file mode 100644
index 00000000000..08546c15450
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_sepcombRGBA.c
@@ -0,0 +1,167 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../CMP_util.h"
+
+/* **************** SEPARATE RGBA ******************** */
+static bNodeSocketType cmp_node_seprgba_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketType cmp_node_seprgba_out[]= {
+ { SOCK_VALUE, 0, "R", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 0, "G", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 0, "B", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 0, "A", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void node_composit_exec_seprgba(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order out: bw channels */
+ /* stack order in: col */
+
+ /* input no image? then only color operation */
+ if(in[0]->data==NULL) {
+ out[0]->vec[0] = in[0]->vec[0];
+ out[1]->vec[0] = in[0]->vec[1];
+ out[2]->vec[0] = in[0]->vec[2];
+ out[3]->vec[0] = in[0]->vec[3];
+ }
+ else {
+ /* make sure we get right rgba buffer */
+ CompBuf *cbuf= typecheck_compbuf(in[0]->data, CB_RGBA);
+
+ /* don't do any pixel processing, just copy the stack directly (faster, I presume) */
+ if(out[0]->hasoutput)
+ out[0]->data= valbuf_from_rgbabuf(cbuf, CHAN_R);
+ if(out[1]->hasoutput)
+ out[1]->data= valbuf_from_rgbabuf(cbuf, CHAN_G);
+ if(out[2]->hasoutput)
+ out[2]->data= valbuf_from_rgbabuf(cbuf, CHAN_B);
+ if(out[3]->hasoutput)
+ out[3]->data= valbuf_from_rgbabuf(cbuf, CHAN_A);
+
+ if(cbuf!=in[0]->data)
+ free_compbuf(cbuf);
+
+ }
+}
+
+bNodeType cmp_node_seprgba= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_SEPRGBA,
+ /* name */ "Separate RGBA",
+ /* width+range */ 80, 40, 140,
+ /* class+opts */ NODE_CLASS_CONVERTOR, 0,
+ /* input sock */ cmp_node_seprgba_in,
+ /* output sock */ cmp_node_seprgba_out,
+ /* storage */ "",
+ /* execfunc */ node_composit_exec_seprgba,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+
+};
+
+
+/* **************** COMBINE RGBA ******************** */
+static bNodeSocketType cmp_node_combrgba_in[]= {
+ { SOCK_VALUE, 1, "R", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 1, "G", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 1, "B", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 1, "A", 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketType cmp_node_combrgba_out[]= {
+ { SOCK_RGBA, 0, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void do_combrgba(bNode *node, float *out, float *in1, float *in2, float *in3, float *in4)
+{
+ out[0] = in1[0];
+ out[1] = in2[0];
+ out[2] = in3[0];
+ out[3] = in4[0];
+}
+
+static void node_composit_exec_combrgba(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order out: 1 rgba channels */
+ /* stack order in: 4 value channels */
+
+ /* input no image? then only color operation */
+ if((in[0]->data==NULL) && (in[1]->data==NULL) && (in[2]->data==NULL) && (in[3]->data==NULL)) {
+ out[0]->vec[0] = in[0]->vec[0];
+ out[0]->vec[1] = in[1]->vec[0];
+ out[0]->vec[2] = in[2]->vec[0];
+ out[0]->vec[3] = in[3]->vec[0];
+ }
+ else {
+ /* make output size of first available input image */
+ CompBuf *cbuf;
+ CompBuf *stackbuf;
+
+ /* allocate a CompBuf the size of the first available input */
+ if (in[0]->data) cbuf = in[0]->data;
+ else if (in[1]->data) cbuf = in[1]->data;
+ else if (in[2]->data) cbuf = in[2]->data;
+ else cbuf = in[3]->data;
+
+ stackbuf = alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */
+
+ composit4_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec,
+ in[2]->data, in[2]->vec, in[3]->data, in[3]->vec,
+ do_combrgba, CB_VAL, CB_VAL, CB_VAL, CB_VAL);
+
+ out[0]->data= stackbuf;
+ }
+}
+
+bNodeType cmp_node_combrgba= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_COMBRGBA,
+ /* name */ "Combine RGBA",
+ /* width+range */ 80, 40, 140,
+ /* class+opts */ NODE_CLASS_CONVERTOR, NODE_OPTIONS,
+ /* input sock */ cmp_node_combrgba_in,
+ /* output sock */ cmp_node_combrgba_out,
+ /* storage */ "",
+ /* execfunc */ node_composit_exec_combrgba,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+
+};
+
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_sepcombYCCA.c b/source/blender/nodes/intern/CMP_nodes/CMP_sepcombYCCA.c
new file mode 100644
index 00000000000..6802fab0bfc
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_sepcombYCCA.c
@@ -0,0 +1,197 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../CMP_util.h"
+
+
+/* **************** SEPARATE YCCA ******************** */
+static bNodeSocketType cmp_node_sepycca_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketType cmp_node_sepycca_out[]= {
+ { SOCK_VALUE, 0, "Y", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 0, "Cb", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 0, "Cr", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 0, "A", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void do_sepycca(bNode *node, float *out, float *in)
+{
+ float y, cb, cr;
+
+ rgb_to_ycc(in[0], in[1], in[2], &y, &cb, &cr);
+
+ /*divided by 255 to normalize for viewing in */
+ out[0]= y/255.0;
+ out[1]= cb/255.0;
+ out[2]= cr/255.0;
+ out[3]= in[3];
+}
+
+static void node_composit_exec_sepycca(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* input no image? then only color operation */
+ if(in[0]->data==NULL) {
+ float y, cb, cr;
+
+ rgb_to_ycc(in[0]->vec[0], in[0]->vec[1], in[0]->vec[2], &y, &cb, &cr);
+
+ /*divided by 255 to normalize for viewing in */
+ out[0]->vec[0] = y/255.0;
+ out[1]->vec[0] = cb/255.0;
+ out[2]->vec[0] = cr/255.0;
+ out[3]->vec[0] = in[0]->vec[3];
+ }
+ else if ((out[0]->hasoutput) || (out[1]->hasoutput) || (out[2]->hasoutput) || (out[3]->hasoutput)) {
+ /* make copy of buffer so input buffer doesn't get corrupted */
+ CompBuf *cbuf= dupalloc_compbuf(in[0]->data);
+ CompBuf *cbuf2=typecheck_compbuf(cbuf, CB_RGBA);
+
+ /* convert the RGB stackbuf to an HSV representation */
+ composit1_pixel_processor(node, cbuf2, cbuf2, in[0]->vec, do_sepycca, CB_RGBA);
+
+ /* separate each of those channels */
+ if(out[0]->hasoutput)
+ out[0]->data= valbuf_from_rgbabuf(cbuf2, CHAN_R);
+ if(out[1]->hasoutput)
+ out[1]->data= valbuf_from_rgbabuf(cbuf2, CHAN_G);
+ if(out[2]->hasoutput)
+ out[2]->data= valbuf_from_rgbabuf(cbuf2, CHAN_B);
+ if(out[3]->hasoutput)
+ out[3]->data= valbuf_from_rgbabuf(cbuf2, CHAN_A);
+
+ /*not used anymore */
+ if(cbuf2!=cbuf)
+ free_compbuf(cbuf2);
+ free_compbuf(cbuf);
+ }
+}
+
+bNodeType cmp_node_sepycca= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_SEPYCCA,
+ /* name */ "Separate YCbCrA",
+ /* width+range */ 80, 40, 140,
+ /* class+opts */ NODE_CLASS_CONVERTOR, 0,
+ /* input sock */ cmp_node_sepycca_in,
+ /* output sock */ cmp_node_sepycca_out,
+ /* storage */ "",
+ /* execfunc */ node_composit_exec_sepycca,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+};
+
+
+/* **************** COMBINE YCCA ******************** */
+static bNodeSocketType cmp_node_combycca_in[]= {
+ { SOCK_VALUE, 1, "Y", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 1, "Cb", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 1, "Cr", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 1, "A", 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketType cmp_node_combycca_out[]= {
+ { SOCK_RGBA, 0, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void do_comb_ycca(bNode *node, float *out, float *in1, float *in2, float *in3, float *in4)
+{
+ float r,g,b;
+ float y, cb, cr;
+
+ /*need to un-normalize the data*/
+ y=in1[0]*255;
+ cb=in2[0]*255;
+ cr=in3[0]*255;
+
+ ycc_to_rgb(y,cb,cr, &r, &g, &b);
+
+ out[0] = r;
+ out[1] = g;
+ out[2] = b;
+ out[3] = in4[0];
+}
+
+static void node_composit_exec_combycca(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order out: 1 ycca channels */
+ /* stack order in: 4 value channels */
+
+ /* input no image? then only color operation */
+ if((in[0]->data==NULL) && (in[1]->data==NULL) && (in[2]->data==NULL) && (in[3]->data==NULL)) {
+ out[0]->vec[0] = in[0]->vec[0];
+ out[0]->vec[1] = in[1]->vec[0];
+ out[0]->vec[2] = in[2]->vec[0];
+ out[0]->vec[3] = in[3]->vec[0];
+ }
+ else {
+ /* make output size of first available input image */
+ CompBuf *cbuf;
+ CompBuf *stackbuf;
+
+ /* allocate a CompBuf the size of the first available input */
+ if (in[0]->data) cbuf = in[0]->data;
+ else if (in[1]->data) cbuf = in[1]->data;
+ else if (in[2]->data) cbuf = in[2]->data;
+ else cbuf = in[3]->data;
+
+ stackbuf = alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */
+
+ composit4_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec,
+ in[2]->data, in[2]->vec, in[3]->data, in[3]->vec,
+ do_comb_ycca, CB_VAL, CB_VAL, CB_VAL, CB_VAL);
+
+ out[0]->data= stackbuf;
+ }
+}
+
+bNodeType cmp_node_combycca= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_COMBYCCA,
+ /* name */ "Combine YCbCrA",
+ /* width+range */ 80, 40, 140,
+ /* class+opts */ NODE_CLASS_CONVERTOR, NODE_OPTIONS,
+ /* input sock */ cmp_node_combycca_in,
+ /* output sock */ cmp_node_combycca_out,
+ /* storage */ "",
+ /* execfunc */ node_composit_exec_combycca,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+};
+
+
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_sepcombYUVA.c b/source/blender/nodes/intern/CMP_nodes/CMP_sepcombYUVA.c
new file mode 100644
index 00000000000..08027c5bc04
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_sepcombYUVA.c
@@ -0,0 +1,190 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../CMP_util.h"
+
+
+/* **************** SEPARATE YUVA ******************** */
+static bNodeSocketType cmp_node_sepyuva_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketType cmp_node_sepyuva_out[]= {
+ { SOCK_VALUE, 0, "Y", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 0, "U", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 0, "V", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 0, "A", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void do_sepyuva(bNode *node, float *out, float *in)
+{
+ float y, u, v;
+
+ rgb_to_yuv(in[0], in[1], in[2], &y, &u, &v);
+
+ out[0]= y;
+ out[1]= u;
+ out[2]= v;
+ out[3]= in[3];
+}
+
+static void node_composit_exec_sepyuva(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order out: bw channels */
+ /* stack order in: col */
+
+ /* input no image? then only color operation */
+ if(in[0]->data==NULL) {
+ float y, u, v;
+
+ rgb_to_yuv(in[0]->vec[0], in[0]->vec[1], in[0]->vec[2], &y, &u, &v);
+
+ out[0]->vec[0] = y;
+ out[1]->vec[0] = u;
+ out[2]->vec[0] = v;
+ out[3]->vec[0] = in[0]->vec[3];
+ }
+ else if ((out[0]->hasoutput) || (out[1]->hasoutput) || (out[2]->hasoutput) || (out[3]->hasoutput)) {
+ /* make copy of buffer so input image doesn't get corrupted */
+ CompBuf *cbuf= dupalloc_compbuf(in[0]->data);
+ CompBuf *cbuf2=typecheck_compbuf(cbuf, CB_RGBA);
+
+ /* convert the RGB stackbuf to an YUV representation */
+ composit1_pixel_processor(node, cbuf2, cbuf2, in[0]->vec, do_sepyuva, CB_RGBA);
+
+ /* separate each of those channels */
+ if(out[0]->hasoutput)
+ out[0]->data= valbuf_from_rgbabuf(cbuf2, CHAN_R);
+ if(out[1]->hasoutput)
+ out[1]->data= valbuf_from_rgbabuf(cbuf2, CHAN_G);
+ if(out[2]->hasoutput)
+ out[2]->data= valbuf_from_rgbabuf(cbuf2, CHAN_B);
+ if(out[3]->hasoutput)
+ out[3]->data= valbuf_from_rgbabuf(cbuf2, CHAN_A);
+
+ /*not used anymore */
+ if(cbuf2!=cbuf)
+ free_compbuf(cbuf2);
+ free_compbuf(cbuf);
+ }
+}
+
+bNodeType cmp_node_sepyuva= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_SEPYUVA,
+ /* name */ "Separate YUVA",
+ /* width+range */ 80, 40, 140,
+ /* class+opts */ NODE_CLASS_CONVERTOR, 0,
+ /* input sock */ cmp_node_sepyuva_in,
+ /* output sock */ cmp_node_sepyuva_out,
+ /* storage */ "",
+ /* execfunc */ node_composit_exec_sepyuva,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+};
+
+
+/* **************** COMBINE YUVA ******************** */
+static bNodeSocketType cmp_node_combyuva_in[]= {
+ { SOCK_VALUE, 1, "Y", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 1, "U", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 1, "V", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 1, "A", 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketType cmp_node_combyuva_out[]= {
+ { SOCK_RGBA, 0, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void do_comb_yuva(bNode *node, float *out, float *in1, float *in2, float *in3, float *in4)
+{
+ float r,g,b;
+ yuv_to_rgb(in1[0], in2[0], in3[0], &r, &g, &b);
+
+ out[0] = r;
+ out[1] = g;
+ out[2] = b;
+ out[3] = in4[0];
+}
+
+static void node_composit_exec_combyuva(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order out: 1 rgba channels */
+ /* stack order in: 4 value channels */
+
+ /* input no image? then only color operation */
+ if((in[0]->data==NULL) && (in[1]->data==NULL) && (in[2]->data==NULL) && (in[3]->data==NULL)) {
+ out[0]->vec[0] = in[0]->vec[0];
+ out[0]->vec[1] = in[1]->vec[0];
+ out[0]->vec[2] = in[2]->vec[0];
+ out[0]->vec[3] = in[3]->vec[0];
+ }
+ else {
+ /* make output size of first available input image */
+ CompBuf *cbuf;
+ CompBuf *stackbuf;
+
+ /* allocate a CompBuf the size of the first available input */
+ if (in[0]->data) cbuf = in[0]->data;
+ else if (in[1]->data) cbuf = in[1]->data;
+ else if (in[2]->data) cbuf = in[2]->data;
+ else cbuf = in[3]->data;
+
+ stackbuf = alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */
+
+ composit4_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec,
+ in[2]->data, in[2]->vec, in[3]->data, in[3]->vec,
+ do_comb_yuva, CB_VAL, CB_VAL, CB_VAL, CB_VAL);
+
+ out[0]->data= stackbuf;
+ }
+}
+
+bNodeType cmp_node_combyuva= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_COMBYUVA,
+ /* name */ "Combine YUVA",
+ /* width+range */ 80, 40, 140,
+ /* class+opts */ NODE_CLASS_CONVERTOR, NODE_OPTIONS,
+ /* input sock */ cmp_node_combyuva_in,
+ /* output sock */ cmp_node_combyuva_out,
+ /* storage */ "",
+ /* execfunc */ node_composit_exec_combyuva,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+};
+
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_setalpha.c b/source/blender/nodes/intern/CMP_nodes/CMP_setalpha.c
new file mode 100644
index 00000000000..a7e0e28989b
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_setalpha.c
@@ -0,0 +1,89 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../CMP_util.h"
+
+/* **************** SET ALPHA ******************** */
+static bNodeSocketType cmp_node_setalpha_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 1, "Alpha", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketType cmp_node_setalpha_out[]= {
+ { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void node_composit_exec_setalpha(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order out: RGBA image */
+ /* stack order in: col, alpha */
+
+ /* input no image? then only color operation */
+ if(in[0]->data==NULL && in[1]->data==NULL) {
+ out[0]->vec[0] = in[0]->vec[0];
+ out[0]->vec[1] = in[0]->vec[1];
+ out[0]->vec[2] = in[0]->vec[2];
+ out[0]->vec[3] = in[1]->vec[0];
+ }
+ else {
+ /* make output size of input image */
+ CompBuf *cbuf= in[0]->data?in[0]->data:in[1]->data;
+ CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */
+
+ if(in[1]->data==NULL && in[1]->vec[0]==1.0f) {
+ /* pass on image */
+ composit1_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, do_copy_rgb, CB_RGBA);
+ }
+ else {
+ /* send an compbuf or a value to set as alpha - composit2_pixel_processor handles choosing the right one */
+ composit2_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec, do_copy_a_rgba, CB_RGBA, CB_VAL);
+ }
+
+ out[0]->data= stackbuf;
+ }
+}
+
+bNodeType cmp_node_setalpha= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_SETALPHA,
+ /* name */ "Set Alpha",
+ /* width+range */ 120, 40, 140,
+ /* class+opts */ NODE_CLASS_CONVERTOR, NODE_OPTIONS,
+ /* input sock */ cmp_node_setalpha_in,
+ /* output sock */ cmp_node_setalpha_out,
+ /* storage */ "",
+ /* execfunc */ node_composit_exec_setalpha,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+
+};
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_splitViewer.c b/source/blender/nodes/intern/CMP_nodes/CMP_splitViewer.c
new file mode 100644
index 00000000000..8ce5a7caa04
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_splitViewer.c
@@ -0,0 +1,164 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../CMP_util.h"
+
+/* **************** SPLIT VIEWER ******************** */
+static bNodeSocketType cmp_node_splitviewer_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 1, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void do_copy_split_rgba(bNode *node, float *out, float *in1, float *in2, float *fac)
+{
+ if(*fac==0.0f) {
+ QUATCOPY(out, in1);
+ }
+ else {
+ QUATCOPY(out, in2);
+ }
+}
+
+static void node_composit_exec_splitviewer(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* image assigned to output */
+ /* stack order input sockets: image image */
+
+ if(in[0]->data==NULL || in[1]->data==NULL)
+ return;
+
+ if(node->id && (node->flag & NODE_DO_OUTPUT)) { /* only one works on out */
+ Image *ima= (Image *)node->id;
+ RenderData *rd= data;
+ ImBuf *ibuf;
+ CompBuf *cbuf, *buf1, *buf2, *mask;
+ int x, y;
+ float offset;
+
+ buf1= typecheck_compbuf(in[0]->data, CB_RGBA);
+ buf2= typecheck_compbuf(in[1]->data, CB_RGBA);
+
+ BKE_image_user_calc_imanr(node->storage, rd->cfra, 0);
+
+ /* always returns for viewer image, but we check nevertheless */
+ ibuf= BKE_image_get_ibuf(ima, node->storage);
+ if(ibuf==NULL) {
+ printf("node_composit_exec_viewer error\n");
+ return;
+ }
+
+ /* free all in ibuf */
+ imb_freerectImBuf(ibuf);
+ imb_freerectfloatImBuf(ibuf);
+ IMB_freezbuffloatImBuf(ibuf);
+
+ /* make ibuf, and connect to ima */
+ ibuf->x= buf1->x;
+ ibuf->y= buf1->y;
+ imb_addrectfloatImBuf(ibuf);
+
+ ima->ok= IMA_OK_LOADED;
+
+ /* output buf */
+ cbuf= alloc_compbuf(buf1->x, buf1->y, CB_RGBA, 0); /* no alloc*/
+ cbuf->rect= ibuf->rect_float;
+
+ /* mask buf */
+ mask= alloc_compbuf(buf1->x, buf1->y, CB_VAL, 1);
+
+
+ /* Check which offset mode is selected and limit offset if needed */
+ if(node->custom2 == 0) {
+ offset = buf1->x / 100.0f * node->custom1;
+ CLAMP(offset, 0, buf1->x);
+ }
+ else {
+ offset = buf1->y / 100.0f * node->custom1;
+ CLAMP(offset, 0, buf1->y);
+ }
+
+ if(node->custom2 == 0) {
+ for(y=0; y<buf1->y; y++) {
+ float *fac= mask->rect + y*buf1->x;
+ for(x=offset; x>0; x--, fac++)
+ *fac= 1.0f;
+ }
+ }
+ else {
+ for(y=0; y<offset; y++) {
+ float *fac= mask->rect + y*buf1->x;
+ for(x=buf1->x; x>0; x--, fac++)
+ *fac= 1.0f;
+ }
+ }
+
+ composit3_pixel_processor(node, cbuf, buf1, in[0]->vec, buf2, in[1]->vec, mask, NULL, do_copy_split_rgba, CB_RGBA, CB_RGBA, CB_VAL);
+
+ generate_preview(node, cbuf);
+ free_compbuf(cbuf);
+ free_compbuf(mask);
+
+ if(in[0]->data != buf1)
+ free_compbuf(buf1);
+ if(in[1]->data != buf2)
+ free_compbuf(buf2);
+ }
+}
+
+static void node_composit_init_splitviewer(bNode* node)
+{
+ ImageUser *iuser= MEM_callocN(sizeof(ImageUser), "node image user");
+ node->storage= iuser;
+ iuser->sfra= 1;
+ iuser->fie_ima= 2;
+ iuser->ok= 1;
+ node->custom1= 50; /* default 50% split */
+}
+
+bNodeType cmp_node_splitviewer= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_SPLITVIEWER,
+ /* name */ "SplitViewer",
+ /* width+range */ 140, 100, 320,
+ /* class+opts */ NODE_CLASS_OUTPUT, NODE_PREVIEW|NODE_OPTIONS,
+ /* input sock */ cmp_node_splitviewer_in,
+ /* output sock */ NULL,
+ /* storage */ "ImageUser",
+ /* execfunc */ node_composit_exec_splitviewer,
+ /* butfunc */ NULL,
+ /* initfunc */ node_composit_init_splitviewer,
+ /* freestoragefunc */ node_free_standard_storage,
+ /* copystoragefunc */ node_copy_standard_storage,
+ /* id */ NULL
+};
+
+
+
+
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_texture.c b/source/blender/nodes/intern/CMP_nodes/CMP_texture.c
new file mode 100644
index 00000000000..4ddab661627
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_texture.c
@@ -0,0 +1,149 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../CMP_util.h"
+
+/* **************** TEXTURE ******************** */
+static bNodeSocketType cmp_node_texture_in[]= {
+ { SOCK_VECTOR, 1, "Offset", 0.0f, 0.0f, 0.0f, 0.0f, -2.0f, 2.0f},
+ { SOCK_VECTOR, 1, "Scale", 1.0f, 1.0f, 1.0f, 1.0f, -10.0f, 10.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketType cmp_node_texture_out[]= {
+ { SOCK_VALUE, 0, "Value", 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_RGBA , 0, "Color", 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+/* called without rect allocated */
+static void texture_procedural(CompBuf *cbuf, float *col, float xco, float yco)
+{
+ bNode *node= cbuf->node;
+ bNodeSocket *sock= node->inputs.first;
+ TexResult texres= {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, NULL};
+ float vec[3], *size, nor[3]={0.0f, 0.0f, 0.0f};
+ int retval, type= cbuf->type;
+
+ size= sock->next->ns.vec;
+
+ vec[0]= size[0]*(xco + sock->ns.vec[0]);
+ vec[1]= size[1]*(yco + sock->ns.vec[1]);
+ vec[2]= size[2]*sock->ns.vec[2];
+
+ retval= multitex_ext((Tex *)node->id, vec, NULL, NULL, 0, &texres);
+
+ if(type==CB_VAL) {
+ if(texres.talpha)
+ col[0]= texres.ta;
+ else
+ col[0]= texres.tin;
+ }
+ else if(type==CB_RGBA) {
+ if(texres.talpha)
+ col[3]= texres.ta;
+ else
+ col[3]= texres.tin;
+
+ if((retval & TEX_RGB)) {
+ col[0]= texres.tr;
+ col[1]= texres.tg;
+ col[2]= texres.tb;
+ }
+ else col[0]= col[1]= col[2]= col[3];
+ }
+ else {
+ VECCOPY(col, nor);
+ }
+}
+
+/* texture node outputs get a small rect, to make sure all other nodes accept it */
+/* only the pixel-processor nodes do something with it though */
+static void node_composit_exec_texture(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* outputs: value, color, normal */
+
+ if(node->id) {
+ RenderResult *rr= RE_GetResult(RE_GetRender(G.scene->id.name)); /* G.scene is WEAK! */
+ short sizex, sizey;
+
+ /* first make the preview image */
+ CompBuf *prevbuf= alloc_compbuf(140, 140, CB_RGBA, 1); /* alloc */
+
+ if (rr) {
+ sizex = rr->rectx;
+ sizey = rr->recty;
+ } else {
+ sizex = G.scene->r.xsch;
+ sizey = G.scene->r.ysch;
+ }
+
+ prevbuf->rect_procedural= texture_procedural;
+ prevbuf->node= node;
+ composit1_pixel_processor(node, prevbuf, prevbuf, out[0]->vec, do_copy_rgba, CB_RGBA);
+ generate_preview(node, prevbuf);
+ free_compbuf(prevbuf);
+
+ if(out[0]->hasoutput) {
+ CompBuf *stackbuf= alloc_compbuf(sizex, sizey, CB_VAL, 1); /* alloc */
+
+ stackbuf->rect_procedural= texture_procedural;
+ stackbuf->node= node;
+
+ out[0]->data= stackbuf;
+ }
+ if(out[1]->hasoutput) {
+ CompBuf *stackbuf= alloc_compbuf(sizex, sizey, CB_RGBA, 1); /* alloc */
+
+ stackbuf->rect_procedural= texture_procedural;
+ stackbuf->node= node;
+
+ out[1]->data= stackbuf;
+ }
+ }
+}
+
+bNodeType cmp_node_texture= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_TEXTURE,
+ /* name */ "Texture",
+ /* width+range */ 120, 80, 240,
+ /* class+opts */ NODE_CLASS_INPUT, NODE_OPTIONS|NODE_PREVIEW,
+ /* input sock */ cmp_node_texture_in,
+ /* output sock */ cmp_node_texture_out,
+ /* storage */ "",
+ /* execfunc */ node_composit_exec_texture,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+
+};
+
+
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_tonemap.c b/source/blender/nodes/intern/CMP_nodes/CMP_tonemap.c
new file mode 100644
index 00000000000..cd617eca5c5
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_tonemap.c
@@ -0,0 +1,173 @@
+/**
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Alfredo de Greef (eeshlo)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../CMP_util.h"
+
+static bNodeSocketType cmp_node_tonemap_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketType cmp_node_tonemap_out[]= {
+ { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+
+static float avgLogLum(CompBuf *src, float* auto_key, float* Lav, float* Cav)
+{
+ float lsum = 0;
+ int p = src->x*src->y;
+ fRGB* bc = (fRGB*)src->rect;
+ float avl, maxl = -1e10f, minl = 1e10f;
+ const float sc = 1.f/(src->x*src->y);
+ *Lav = 0.f;
+ while (p--) {
+ float L = 0.212671f*bc[0][0] + 0.71516f*bc[0][1] + 0.072169f*bc[0][2];
+ *Lav += L;
+ fRGB_add(Cav, bc[0]);
+ lsum += logf(MAX2(L, 0.f) + 1e-5f);
+ maxl = (L > maxl) ? L : maxl;
+ minl = (L < minl) ? L : minl;
+ bc++;
+ }
+ *Lav *= sc;
+ fRGB_mult(Cav, sc);
+ maxl = logf(maxl + 1e-5f); minl = logf(minl + 1e-5f); avl = lsum*sc;
+ *auto_key = (maxl > minl) ? ((maxl - avl) / (maxl - minl)) : 1.f;
+ return expf(avl);
+}
+
+
+void static tonemap(NodeTonemap* ntm, CompBuf* dst, CompBuf* src)
+{
+ int x, y;
+ float dr, dg, db, al, igm = (ntm->gamma==0.f) ? 1 : (1.f / ntm->gamma);
+ float auto_key, Lav, Cav[3] = {0, 0, 0};
+
+ al = avgLogLum(src, &auto_key, &Lav, Cav);
+ al = (al == 0.f) ? 0.f : (ntm->key / al);
+
+ if (ntm->type == 1) {
+ // Reinhard/Devlin photoreceptor
+ const float f = expf(-ntm->f);
+ const float m = (ntm->m > 0.f) ? ntm->m : (0.3f + 0.7f*powf(auto_key, 1.4f));
+ const float ic = 1.f - ntm->c, ia = 1.f - ntm->a;
+ if (ntm->m == 0.f) printf("tonemap node, M: %g\n", m);
+ for (y=0; y<src->y; ++y) {
+ fRGB* sp = (fRGB*)&src->rect[y*src->x*src->type];
+ fRGB* dp = (fRGB*)&dst->rect[y*src->x*src->type];
+ for (x=0; x<src->x; ++x) {
+ const float L = 0.212671f*sp[x][0] + 0.71516f*sp[x][1] + 0.072169f*sp[x][2];
+ float I_l = sp[x][0] + ic*(L - sp[x][0]);
+ float I_g = Cav[0] + ic*(Lav - Cav[0]);
+ float I_a = I_l + ia*(I_g - I_l);
+ dp[x][0] /= (dp[x][0] + powf(f*I_a, m));
+ I_l = sp[x][1] + ic*(L - sp[x][1]);
+ I_g = Cav[1] + ic*(Lav - Cav[1]);
+ I_a = I_l + ia*(I_g - I_l);
+ dp[x][1] /= (dp[x][1] + powf(f*I_a, m));
+ I_l = sp[x][2] + ic*(L - sp[x][2]);
+ I_g = Cav[2] + ic*(Lav - Cav[2]);
+ I_a = I_l + ia*(I_g - I_l);
+ dp[x][2] /= (dp[x][2] + powf(f*I_a, m));
+ }
+ }
+ return;
+ }
+
+ // Reinhard simple photographic tm (simplest, not using whitepoint var)
+ for (y=0; y<src->y; y++) {
+ fRGB* sp = (fRGB*)&src->rect[y*src->x*src->type];
+ fRGB* dp = (fRGB*)&dst->rect[y*src->x*src->type];
+ for (x=0; x<src->x; x++) {
+ fRGB_copy(dp[x], sp[x]);
+ fRGB_mult(dp[x], al);
+ dr = dp[x][0] + ntm->offset;
+ dg = dp[x][1] + ntm->offset;
+ db = dp[x][2] + ntm->offset;
+ dp[x][0] /= ((dr == 0.f) ? 1.f : dr);
+ dp[x][1] /= ((dg == 0.f) ? 1.f : dg);
+ dp[x][2] /= ((db == 0.f) ? 1.f : db);
+ if (igm != 0.f) {
+ dp[x][0] = powf(MAX2(dp[x][0], 0.f), igm);
+ dp[x][1] = powf(MAX2(dp[x][1], 0.f), igm);
+ dp[x][2] = powf(MAX2(dp[x][2], 0.f), igm);
+ }
+ }
+ }
+}
+
+
+static void node_composit_exec_tonemap(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ CompBuf *new, *img = in[0]->data;
+
+ if ((img==NULL) || (out[0]->hasoutput==0)) return;
+
+ if (img->type != CB_RGBA)
+ new = typecheck_compbuf(img, CB_RGBA);
+ else
+ new = dupalloc_compbuf(img);
+
+ tonemap(node->storage, new, img);
+
+ out[0]->data = new;
+}
+
+static void node_composit_init_tonemap(bNode* node)
+{
+ NodeTonemap *ntm = MEM_callocN(sizeof(NodeTonemap), "node tonemap data");
+ ntm->type = 1;
+ ntm->key = 0.18;
+ ntm->offset = 1;
+ ntm->gamma = 1;
+ ntm->f = 0;
+ ntm->m = 0; // actual value is set according to input
+ // default a of 1 works well with natural HDR images, but not always so for cgi.
+ // Maybe should use 0 or at least lower initial value instead
+ ntm->a = 1;
+ ntm->c = 0;
+ node->storage = ntm;
+}
+
+bNodeType cmp_node_tonemap = {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_TONEMAP,
+ /* name */ "Tonemap",
+ /* width+range */ 150, 120, 200,
+ /* class+opts */ NODE_CLASS_OP_COLOR, NODE_OPTIONS,
+ /* input sock */ cmp_node_tonemap_in,
+ /* output sock */ cmp_node_tonemap_out,
+ /* storage */ "NodeTonemap",
+ /* execfunc */ node_composit_exec_tonemap,
+ /* butfunc */ NULL,
+ /* initfunc */ node_composit_init_tonemap,
+ /* freestoragefunc */ node_free_standard_storage,
+ /* copystoragefunc */ node_copy_standard_storage,
+ /* id */ NULL
+};
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_translate.c b/source/blender/nodes/intern/CMP_nodes/CMP_translate.c
new file mode 100644
index 00000000000..0b198a18b4e
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_translate.c
@@ -0,0 +1,75 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../CMP_util.h"
+
+
+/* **************** Translate ******************** */
+
+static bNodeSocketType cmp_node_translate_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 1, "X", 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f},
+ { SOCK_VALUE, 1, "Y", 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketType cmp_node_translate_out[]= {
+ { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void node_composit_exec_translate(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ if(in[0]->data) {
+ CompBuf *cbuf= in[0]->data;
+ CompBuf *stackbuf= pass_on_compbuf(cbuf);
+
+ stackbuf->xof+= (int)floor(in[1]->vec[0]);
+ stackbuf->yof+= (int)floor(in[2]->vec[0]);
+
+ out[0]->data= stackbuf;
+ }
+}
+
+bNodeType cmp_node_translate= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_TRANSLATE,
+ /* name */ "Translate",
+ /* width+range */ 140, 100, 320,
+ /* class+opts */ NODE_CLASS_DISTORT, NODE_OPTIONS,
+ /* input sock */ cmp_node_translate_in,
+ /* output sock */ cmp_node_translate_out,
+ /* storage */ "",
+ /* execfunc */ node_composit_exec_translate,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+};
+
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_valToRgb.c b/source/blender/nodes/intern/CMP_nodes/CMP_valToRgb.c
new file mode 100644
index 00000000000..0d50cb6374d
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_valToRgb.c
@@ -0,0 +1,157 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../CMP_util.h"
+
+
+/* **************** VALTORGB ******************** */
+static bNodeSocketType cmp_node_valtorgb_in[]= {
+ { SOCK_VALUE, 1, "Fac", 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketType cmp_node_valtorgb_out[]= {
+ { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 0, "Alpha", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void do_colorband_composit(bNode *node, float *out, float *in)
+{
+ do_colorband(node->storage, in[0], out);
+}
+
+static void node_composit_exec_valtorgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order in: fac */
+ /* stack order out: col, alpha */
+
+ if(out[0]->hasoutput==0 && out[1]->hasoutput==0)
+ return;
+
+ if(node->storage) {
+ /* input no image? then only color operation */
+ if(in[0]->data==NULL) {
+ do_colorband(node->storage, in[0]->vec[0], out[0]->vec);
+ }
+ else {
+ /* make output size of input image */
+ CompBuf *cbuf= in[0]->data;
+ CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */
+
+ composit1_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, do_colorband_composit, CB_VAL);
+
+ out[0]->data= stackbuf;
+
+ if(out[1]->hasoutput)
+ out[1]->data= valbuf_from_rgbabuf(stackbuf, CHAN_A);
+
+ }
+ }
+}
+
+static void node_composit_init_valtorgb(bNode* node)
+{
+ node->storage= add_colorband(1);
+}
+
+bNodeType cmp_node_valtorgb= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_VALTORGB,
+ /* name */ "ColorRamp",
+ /* width+range */ 240, 200, 300,
+ /* class+opts */ NODE_CLASS_CONVERTOR, NODE_OPTIONS,
+ /* input sock */ cmp_node_valtorgb_in,
+ /* output sock */ cmp_node_valtorgb_out,
+ /* storage */ "ColorBand",
+ /* execfunc */ node_composit_exec_valtorgb,
+ /* butfunc */ NULL,
+ /* initfunc */ node_composit_init_valtorgb,
+ /* freestoragefunc */ node_free_standard_storage,
+ /* copystoragefunc */ node_copy_standard_storage,
+ /* id */ NULL
+
+};
+
+
+/* **************** RGBTOBW ******************** */
+static bNodeSocketType cmp_node_rgbtobw_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketType cmp_node_rgbtobw_out[]= {
+ { SOCK_VALUE, 0, "Val", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void do_rgbtobw(bNode *node, float *out, float *in)
+{
+ out[0]= in[0]*0.35f + in[1]*0.45f + in[2]*0.2f;
+}
+
+static void node_composit_exec_rgbtobw(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order out: bw */
+ /* stack order in: col */
+
+ if(out[0]->hasoutput==0)
+ return;
+
+ /* input no image? then only color operation */
+ if(in[0]->data==NULL) {
+ do_rgbtobw(node, out[0]->vec, in[0]->vec);
+ }
+ else {
+ /* make output size of input image */
+ CompBuf *cbuf= in[0]->data;
+ CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1); /* allocs */
+
+ composit1_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, do_rgbtobw, CB_RGBA);
+
+ out[0]->data= stackbuf;
+ }
+}
+
+bNodeType cmp_node_rgbtobw= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_RGBTOBW,
+ /* name */ "RGB to BW",
+ /* width+range */ 80, 40, 120,
+ /* class+opts */ NODE_CLASS_CONVERTOR, 0,
+ /* input sock */ cmp_node_rgbtobw_in,
+ /* output sock */ cmp_node_rgbtobw_out,
+ /* storage */ "",
+ /* execfunc */ node_composit_exec_rgbtobw,
+ /* butfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+
+};
+
+
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_value.c b/source/blender/nodes/intern/CMP_nodes/CMP_value.c
new file mode 100644
index 00000000000..7430a373d23
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_value.c
@@ -0,0 +1,61 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../CMP_util.h"
+
+/* **************** VALUE ******************** */
+static bNodeSocketType cmp_node_value_out[]= {
+ { SOCK_VALUE, 0, "Value", 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void node_composit_exec_value(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ bNodeSocket *sock= node->outputs.first;
+
+ out[0]->vec[0]= sock->ns.vec[0];
+}
+
+bNodeType cmp_node_value= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_VALUE,
+ /* name */ "Value",
+ /* width+range */ 80, 40, 120,
+ /* class+opts */ NODE_CLASS_INPUT, NODE_OPTIONS,
+ /* input sock */ NULL,
+ /* output sock */ cmp_node_value_out,
+ /* storage */ "",
+ /* execfunc */ node_composit_exec_value,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+};
+
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_vecBlur.c b/source/blender/nodes/intern/CMP_nodes/CMP_vecBlur.c
new file mode 100644
index 00000000000..9e6c963126b
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_vecBlur.c
@@ -0,0 +1,110 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../CMP_util.h"
+
+
+/* **************** VECTOR BLUR ******************** */
+static bNodeSocketType cmp_node_vecblur_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 1, "Z", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_VECTOR, 1, "Speed", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketType cmp_node_vecblur_out[]= {
+ { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+
+
+static void node_composit_exec_vecblur(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ NodeBlurData *nbd= node->storage;
+ CompBuf *new, *img= in[0]->data, *vecbuf= in[2]->data, *zbuf= in[1]->data;
+
+ if(img==NULL || vecbuf==NULL || zbuf==NULL || out[0]->hasoutput==0)
+ return;
+ if(vecbuf->x!=img->x || vecbuf->y!=img->y) {
+ printf("ERROR: cannot do different sized vecbuf yet\n");
+ return;
+ }
+ if(vecbuf->type!=CB_VEC4) {
+ printf("ERROR: input should be vecbuf\n");
+ return;
+ }
+ if(zbuf->type!=CB_VAL) {
+ printf("ERROR: input should be zbuf\n");
+ return;
+ }
+ if(zbuf->x!=img->x || zbuf->y!=img->y) {
+ printf("ERROR: cannot do different sized zbuf yet\n");
+ return;
+ }
+
+ /* allow the input image to be of another type */
+ img= typecheck_compbuf(in[0]->data, CB_RGBA);
+
+ new= dupalloc_compbuf(img);
+
+ /* call special zbuffer version */
+ RE_zbuf_accumulate_vecblur(nbd, img->x, img->y, new->rect, img->rect, vecbuf->rect, zbuf->rect);
+
+ out[0]->data= new;
+
+ if(img!=in[0]->data)
+ free_compbuf(img);
+}
+
+static void node_composit_init_vecblur(bNode* node)
+{
+ NodeBlurData *nbd= MEM_callocN(sizeof(NodeBlurData), "node blur data");
+ node->storage= nbd;
+ nbd->samples= 32;
+ nbd->fac= 1.0f;
+};
+
+/* custom1: itterations, custom2: maxspeed (0 = nolimit) */
+bNodeType cmp_node_vecblur= {
+ /* next, prev */ NULL, NULL,
+ /* type code */ CMP_NODE_VECBLUR,
+ /* name */ "Vector Blur",
+ /* width+range */ 120, 80, 200,
+ /* class+opts */ NODE_CLASS_OP_FILTER, NODE_OPTIONS,
+ /* input sock */ cmp_node_vecblur_in,
+ /* output sock */ cmp_node_vecblur_out,
+ /* storage */ "NodeBlurData",
+ /* execfunc */ node_composit_exec_vecblur,
+ /* butfunc */ NULL,
+ /* initfunc */ node_composit_init_vecblur,
+ /* freestoragefunc */ node_free_standard_storage,
+ /* copystoragefunc */ node_copy_standard_storage,
+ /* id */ NULL
+};
+
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_viewer.c b/source/blender/nodes/intern/CMP_nodes/CMP_viewer.c
new file mode 100644
index 00000000000..c9e95e768c1
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_viewer.c
@@ -0,0 +1,144 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../CMP_util.h"
+
+
+/* **************** VIEWER ******************** */
+static bNodeSocketType cmp_node_viewer_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 1, "Alpha", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 1, "Z", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+
+static void node_composit_exec_viewer(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* image assigned to output */
+ /* stack order input sockets: col, alpha, z */
+
+ if(node->id && (node->flag & NODE_DO_OUTPUT)) { /* only one works on out */
+ RenderData *rd= data;
+ Image *ima= (Image *)node->id;
+ ImBuf *ibuf;
+ CompBuf *cbuf, *tbuf;
+ int rectx, recty;
+
+ BKE_image_user_calc_imanr(node->storage, rd->cfra, 0);
+
+ /* always returns for viewer image, but we check nevertheless */
+ ibuf= BKE_image_get_ibuf(ima, node->storage);
+ if(ibuf==NULL) {
+ printf("node_composit_exec_viewer error\n");
+ return;
+ }
+
+ /* free all in ibuf */
+ imb_freerectImBuf(ibuf);
+ imb_freerectfloatImBuf(ibuf);
+ IMB_freezbuffloatImBuf(ibuf);
+
+ /* get size */
+ tbuf= in[0]->data?in[0]->data:(in[1]->data?in[1]->data:in[2]->data);
+ if(tbuf==NULL) {
+ rectx= 320; recty= 256;
+ }
+ else {
+ rectx= tbuf->x;
+ recty= tbuf->y;
+ }
+
+ /* make ibuf, and connect to ima */
+ ibuf->x= rectx;
+ ibuf->y= recty;
+ imb_addrectfloatImBuf(ibuf);
+
+ ima->ok= IMA_OK_LOADED;
+
+ /* now we combine the input with ibuf */
+ cbuf= alloc_compbuf(rectx, recty, CB_RGBA, 0); /* no alloc*/
+ cbuf->rect= ibuf->rect_float;
+
+ /* when no alpha, we can simply copy */
+ if(in[1]->data==NULL) {
+ composit1_pixel_processor(node, cbuf, in[0]->data, in[0]->vec, do_copy_rgba, CB_RGBA);
+ }
+ else
+ composit2_pixel_processor(node, cbuf, in[0]->data, in[0]->vec, in[1]->data, in[1]->vec, do_copy_a_rgba, CB_RGBA, CB_VAL);
+
+ /* zbuf option */
+ if(in[2]->data) {
+ CompBuf *zbuf= alloc_compbuf(rectx, recty, CB_VAL, 1);
+ ibuf->zbuf_float= zbuf->rect;
+ ibuf->mall |= IB_zbuffloat;
+
+ composit1_pixel_processor(node, zbuf, in[2]->data, in[2]->vec, do_copy_value, CB_VAL);
+
+ /* free compbuf, but not the rect */
+ zbuf->malloc= 0;
+ free_compbuf(zbuf);
+ }
+
+ generate_preview(node, cbuf);
+ free_compbuf(cbuf);
+
+ }
+ else if(in[0]->data) {
+ generate_preview(node, in[0]->data);
+ }
+}
+
+static void node_composit_init_viewer(bNode* node)
+{
+ ImageUser *iuser= MEM_callocN(sizeof(ImageUser), "node image user");
+ node->storage= iuser;
+ iuser->sfra= 1;
+ iuser->fie_ima= 2;
+ iuser->ok= 1;
+}
+
+bNodeType cmp_node_viewer= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_VIEWER,
+ /* name */ "Viewer",
+ /* width+range */ 80, 60, 200,
+ /* class+opts */ NODE_CLASS_OUTPUT, NODE_PREVIEW,
+ /* input sock */ cmp_node_viewer_in,
+ /* output sock */ NULL,
+ /* storage */ "ImageUser",
+ /* execfunc */ node_composit_exec_viewer,
+ /* butfunc */ NULL,
+ /* initfunc */ node_composit_init_viewer,
+ /* freestoragefunc */ node_free_standard_storage,
+ /* copystoragefunc */ node_copy_standard_storage,
+ /* id */ NULL
+
+};
+
diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_zcombine.c b/source/blender/nodes/intern/CMP_nodes/CMP_zcombine.c
new file mode 100644
index 00000000000..29cf8f34d54
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/CMP_zcombine.c
@@ -0,0 +1,155 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../CMP_util.h"
+
+
+/* **************** Z COMBINE ******************** */
+ /* lazy coder note: node->custom1 is abused to send signal */
+static bNodeSocketType cmp_node_zcombine_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 1, "Z", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 10000.0f},
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 1, "Z", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 10000.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketType cmp_node_zcombine_out[]= {
+ { SOCK_RGBA, 0, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 0, "Z", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 10000.0f},
+ { -1, 0, "" }
+};
+
+static void do_zcombine_mask(bNode *node, float *out, float *z1, float *z2)
+{
+ if(*z1 > *z2) {
+ *out= 1.0f;
+ if(node->custom1)
+ *z1= *z2;
+ }
+}
+
+static void do_zcombine_add(bNode *node, float *out, float *col1, float *col2, float *acol)
+{
+ float alpha= *acol;
+ float malpha= 1.0f - alpha;
+
+ out[0]= malpha*col1[0] + alpha*col2[0];
+ out[1]= malpha*col1[1] + alpha*col2[1];
+ out[2]= malpha*col1[2] + alpha*col2[2];
+ out[3]= malpha*col1[3] + alpha*col2[3];
+}
+
+static void node_composit_exec_zcombine(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order in: col z col z */
+ /* stack order out: col z */
+ if(out[0]->hasoutput==0)
+ return;
+
+ /* no input image; do nothing now */
+ if(in[0]->data==NULL) {
+ return;
+ }
+ else {
+ /* make output size of first input image */
+ CompBuf *cbuf= in[0]->data;
+ CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */
+ CompBuf *zbuf, *mbuf;
+ float *fp;
+ int x;
+ char *aabuf;
+
+ if(out[1]->hasoutput) {
+ /* copy or make a buffer for for the first z value, here we write result in */
+ if(in[1]->data)
+ zbuf= dupalloc_compbuf(in[1]->data);
+ else {
+ float *zval;
+ int tot= cbuf->x*cbuf->y;
+
+ zbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1);
+ for(zval= zbuf->rect; tot; tot--, zval++)
+ *zval= in[1]->vec[0];
+ }
+ /* lazy coder hack */
+ node->custom1= 1;
+ }
+ else {
+ node->custom1= 0;
+ zbuf= in[1]->data;
+ }
+
+ /* make a mask based on comparison, optionally write zvalue */
+ mbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1);
+ composit2_pixel_processor(node, mbuf, zbuf, in[1]->vec, in[3]->data, in[3]->vec, do_zcombine_mask, CB_VAL, CB_VAL);
+
+ /* convert to char */
+ aabuf= MEM_mallocN(cbuf->x*cbuf->y, "aa buf");
+ fp= mbuf->rect;
+ for(x= cbuf->x*cbuf->y-1; x>=0; x--)
+ if(fp[x]==0.0f) aabuf[x]= 0;
+ else aabuf[x]= 255;
+
+ antialias_tagbuf(cbuf->x, cbuf->y, aabuf);
+
+ /* convert to float */
+ fp= mbuf->rect;
+ for(x= cbuf->x*cbuf->y-1; x>=0; x--)
+ if(aabuf[x]>1)
+ fp[x]= (1.0f/255.0f)*(float)aabuf[x];
+
+ composit3_pixel_processor(node, stackbuf, in[0]->data, in[0]->vec, in[2]->data, in[2]->vec, mbuf, NULL,
+ do_zcombine_add, CB_RGBA, CB_RGBA, CB_VAL);
+ /* free */
+ free_compbuf(mbuf);
+ MEM_freeN(aabuf);
+
+ out[0]->data= stackbuf;
+ if(node->custom1)
+ out[1]->data= zbuf;
+ }
+}
+
+bNodeType cmp_node_zcombine= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ CMP_NODE_ZCOMBINE,
+ /* name */ "Z Combine",
+ /* width+range */ 80, 40, 120,
+ /* class+opts */ NODE_CLASS_OP_COLOR, NODE_OPTIONS,
+ /* input sock */ cmp_node_zcombine_in,
+ /* output sock */ cmp_node_zcombine_out,
+ /* storage */ "",
+ /* execfunc */ node_composit_exec_zcombine,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+
+};
diff --git a/source/blender/nodes/intern/CMP_nodes/Makefile b/source/blender/nodes/intern/CMP_nodes/Makefile
new file mode 100644
index 00000000000..036812548b4
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_nodes/Makefile
@@ -0,0 +1,47 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+#
+
+LIBNAME = nodes_cmp
+DIR = $(OCGDIR)/blender/$(LIBNAME)
+
+include nan_compile.mk
+
+CFLAGS += $(LEVEL_1_C_WARNINGS)
+
+CPPFLAGS += -I../../../blenkernel
+CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
+CPPFLAGS += -I../../../makesdna
+CPPFLAGS += -I../../../blenlib
+CPPFLAGS += -I../../../include
+CPPFLAGS += -I../../../imbuf
+CPPFLAGS += -I../../../render/extern/include
diff --git a/source/blender/nodes/intern/CMP_util.c b/source/blender/nodes/intern/CMP_util.c
new file mode 100644
index 00000000000..eee33e33ff5
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_util.c
@@ -0,0 +1,1166 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "CMP_util.h"
+
+CompBuf *alloc_compbuf(int sizex, int sizey, int type, int alloc)
+{
+ CompBuf *cbuf= MEM_callocN(sizeof(CompBuf), "compbuf");
+
+ cbuf->x= sizex;
+ cbuf->y= sizey;
+ cbuf->xrad= sizex/2;
+ cbuf->yrad= sizey/2;
+
+ cbuf->type= type;
+ if(alloc) {
+ if(cbuf->type==CB_RGBA)
+ cbuf->rect= MEM_mapallocN(4*sizeof(float)*sizex*sizey, "compbuf RGBA rect");
+ else if(cbuf->type==CB_VEC3)
+ cbuf->rect= MEM_mapallocN(3*sizeof(float)*sizex*sizey, "compbuf Vector3 rect");
+ else if(cbuf->type==CB_VEC2)
+ cbuf->rect= MEM_mapallocN(2*sizeof(float)*sizex*sizey, "compbuf Vector2 rect");
+ else
+ cbuf->rect= MEM_mapallocN(sizeof(float)*sizex*sizey, "compbuf Fac rect");
+ cbuf->malloc= 1;
+ }
+ cbuf->disprect.xmin= 0;
+ cbuf->disprect.ymin= 0;
+ cbuf->disprect.xmax= sizex;
+ cbuf->disprect.ymax= sizey;
+
+ return cbuf;
+}
+
+CompBuf *dupalloc_compbuf(CompBuf *cbuf)
+{
+ CompBuf *dupbuf= alloc_compbuf(cbuf->x, cbuf->y, cbuf->type, 1);
+ if(dupbuf) {
+ memcpy(dupbuf->rect, cbuf->rect, cbuf->type*sizeof(float)*cbuf->x*cbuf->y);
+
+ dupbuf->xof= cbuf->xof;
+ dupbuf->yof= cbuf->yof;
+ }
+ return dupbuf;
+}
+
+/* instead of reference counting, we create a list */
+CompBuf *pass_on_compbuf(CompBuf *cbuf)
+{
+ CompBuf *dupbuf= alloc_compbuf(cbuf->x, cbuf->y, cbuf->type, 0);
+ CompBuf *lastbuf;
+
+ if(dupbuf) {
+ dupbuf->rect= cbuf->rect;
+ dupbuf->xof= cbuf->xof;
+ dupbuf->yof= cbuf->yof;
+ dupbuf->malloc= 0;
+
+ /* get last buffer in list, and append dupbuf */
+ for(lastbuf= cbuf; lastbuf; lastbuf= lastbuf->next)
+ if(lastbuf->next==NULL)
+ break;
+ lastbuf->next= dupbuf;
+ dupbuf->prev= lastbuf;
+ }
+ return dupbuf;
+}
+
+
+void free_compbuf(CompBuf *cbuf)
+{
+ /* check referencing, then remove from list and set malloc tag */
+ if(cbuf->prev || cbuf->next) {
+ if(cbuf->prev)
+ cbuf->prev->next= cbuf->next;
+ if(cbuf->next)
+ cbuf->next->prev= cbuf->prev;
+ if(cbuf->malloc) {
+ if(cbuf->prev)
+ cbuf->prev->malloc= 1;
+ else
+ cbuf->next->malloc= 1;
+ cbuf->malloc= 0;
+ }
+ }
+
+ if(cbuf->malloc && cbuf->rect)
+ MEM_freeN(cbuf->rect);
+
+ MEM_freeN(cbuf);
+}
+
+void print_compbuf(char *str, CompBuf *cbuf)
+{
+ printf("Compbuf %s %d %d %p\n", str, cbuf->x, cbuf->y, cbuf->rect);
+
+}
+
+CompBuf *get_cropped_compbuf(rcti *drect, float *rectf, int rectx, int recty, int type)
+{
+ CompBuf *cbuf;
+ rcti disprect= *drect;
+ float *outfp;
+ int dx, y;
+
+ if(disprect.xmax>rectx) disprect.xmax= rectx;
+ if(disprect.ymax>recty) disprect.ymax= recty;
+ if(disprect.xmin>= disprect.xmax) return NULL;
+ if(disprect.ymin>= disprect.ymax) return NULL;
+
+ cbuf= alloc_compbuf(disprect.xmax-disprect.xmin, disprect.ymax-disprect.ymin, type, 1);
+ outfp= cbuf->rect;
+ rectf += type*(disprect.ymin*rectx + disprect.xmin);
+ dx= type*cbuf->x;
+ for(y=cbuf->y; y>0; y--, outfp+=dx, rectf+=type*rectx)
+ memcpy(outfp, rectf, sizeof(float)*dx);
+
+ return cbuf;
+}
+
+CompBuf *scalefast_compbuf(CompBuf *inbuf, int newx, int newy)
+{
+ CompBuf *outbuf;
+ float *rectf, *newrectf, *rf;
+ int x, y, c, pixsize= inbuf->type;
+ int ofsx, ofsy, stepx, stepy;
+
+ if(inbuf->x==newx && inbuf->y==newy)
+ return dupalloc_compbuf(inbuf);
+
+ outbuf= alloc_compbuf(newx, newy, inbuf->type, 1);
+ newrectf= outbuf->rect;
+
+ stepx = (65536.0 * (inbuf->x - 1.0) / (newx - 1.0)) + 0.5;
+ stepy = (65536.0 * (inbuf->y - 1.0) / (newy - 1.0)) + 0.5;
+ ofsy = 32768;
+
+ for (y = newy; y > 0 ; y--){
+ rectf = inbuf->rect;
+ rectf += pixsize * (ofsy >> 16) * inbuf->x;
+
+ ofsy += stepy;
+ ofsx = 32768;
+
+ for (x = newx ; x>0 ; x--) {
+
+ rf= rectf + pixsize*(ofsx >> 16);
+ for(c=0; c<pixsize; c++)
+ newrectf[c] = rf[c];
+
+ newrectf+= pixsize;
+
+ ofsx += stepx;
+ }
+ }
+
+ return outbuf;
+}
+
+CompBuf *typecheck_compbuf(CompBuf *inbuf, int type)
+{
+ if(inbuf && inbuf->type!=type && inbuf->rect_procedural==NULL) {
+ CompBuf *outbuf= alloc_compbuf(inbuf->x, inbuf->y, type, 1);
+ float *inrf= inbuf->rect;
+ float *outrf= outbuf->rect;
+ int x= inbuf->x*inbuf->y;
+
+ /* warning note: xof and yof are applied in pixelprocessor, but should be copied otherwise? */
+ outbuf->xof= inbuf->xof;
+ outbuf->yof= inbuf->yof;
+
+ if(type==CB_VAL) {
+ if(inbuf->type==CB_VEC2) {
+ for(; x>0; x--, outrf+= 1, inrf+= 2)
+ *outrf= 0.5f*(inrf[0]+inrf[1]);
+ }
+ else if(inbuf->type==CB_VEC3) {
+ for(; x>0; x--, outrf+= 1, inrf+= 3)
+ *outrf= 0.333333f*(inrf[0]+inrf[1]+inrf[2]);
+ }
+ else if(inbuf->type==CB_RGBA) {
+ for(; x>0; x--, outrf+= 1, inrf+= 4)
+ *outrf= inrf[0]*0.35f + inrf[1]*0.45f + inrf[2]*0.2f;
+ }
+ }
+ else if(type==CB_VEC2) {
+ if(inbuf->type==CB_VAL) {
+ for(; x>0; x--, outrf+= 2, inrf+= 1) {
+ outrf[0]= inrf[0];
+ outrf[1]= inrf[0];
+ }
+ }
+ else if(inbuf->type==CB_VEC3) {
+ for(; x>0; x--, outrf+= 2, inrf+= 3) {
+ outrf[0]= inrf[0];
+ outrf[1]= inrf[1];
+ }
+ }
+ else if(inbuf->type==CB_RGBA) {
+ for(; x>0; x--, outrf+= 2, inrf+= 4) {
+ outrf[0]= inrf[0];
+ outrf[1]= inrf[1];
+ }
+ }
+ }
+ else if(type==CB_VEC3) {
+ if(inbuf->type==CB_VAL) {
+ for(; x>0; x--, outrf+= 3, inrf+= 1) {
+ outrf[0]= inrf[0];
+ outrf[1]= inrf[0];
+ outrf[2]= inrf[0];
+ }
+ }
+ else if(inbuf->type==CB_VEC2) {
+ for(; x>0; x--, outrf+= 3, inrf+= 2) {
+ outrf[0]= inrf[0];
+ outrf[1]= inrf[1];
+ outrf[2]= 0.0f;
+ }
+ }
+ else if(inbuf->type==CB_RGBA) {
+ for(; x>0; x--, outrf+= 3, inrf+= 4) {
+ outrf[0]= inrf[0];
+ outrf[1]= inrf[1];
+ outrf[2]= inrf[2];
+ }
+ }
+ }
+ else if(type==CB_RGBA) {
+ if(inbuf->type==CB_VAL) {
+ for(; x>0; x--, outrf+= 4, inrf+= 1) {
+ outrf[0]= inrf[0];
+ outrf[1]= inrf[0];
+ outrf[2]= inrf[0];
+ outrf[3]= 1.0f;
+ }
+ }
+ else if(inbuf->type==CB_VEC2) {
+ for(; x>0; x--, outrf+= 4, inrf+= 2) {
+ outrf[0]= inrf[0];
+ outrf[1]= inrf[1];
+ outrf[2]= 0.0f;
+ outrf[3]= 1.0f;
+ }
+ }
+ else if(inbuf->type==CB_VEC3) {
+ for(; x>0; x--, outrf+= 4, inrf+= 3) {
+ outrf[0]= inrf[0];
+ outrf[1]= inrf[1];
+ outrf[2]= inrf[2];
+ outrf[3]= 1.0f;
+ }
+ }
+ }
+
+ return outbuf;
+ }
+ return inbuf;
+}
+
+float *compbuf_get_pixel(CompBuf *cbuf, float *rectf, int x, int y, int xrad, int yrad)
+{
+ if(cbuf) {
+ if(cbuf->rect_procedural) {
+ cbuf->rect_procedural(cbuf, rectf, (float)x/(float)xrad, (float)y/(float)yrad);
+ return rectf;
+ }
+ else {
+ static float col[4]= {0.0f, 0.0f, 0.0f, 0.0f};
+
+ /* map coords */
+ x-= cbuf->xof;
+ y-= cbuf->yof;
+
+ if(y<-cbuf->yrad || y>= -cbuf->yrad+cbuf->y) return col;
+ if(x<-cbuf->xrad || x>= -cbuf->xrad+cbuf->x) return col;
+
+ return cbuf->rect + cbuf->type*( (cbuf->yrad+y)*cbuf->x + (cbuf->xrad+x) );
+ }
+ }
+ else return rectf;
+}
+
+/* **************************************************** */
+
+/* Pixel-to-Pixel operation, 1 Image in, 1 out */
+void composit1_pixel_processor(bNode *node, CompBuf *out, CompBuf *src_buf, float *src_col,
+ void (*func)(bNode *, float *, float *),
+ int src_type)
+{
+ CompBuf *src_use;
+ float *outfp=out->rect, *srcfp;
+ int xrad, yrad, x, y;
+
+ src_use= typecheck_compbuf(src_buf, src_type);
+
+ xrad= out->xrad;
+ yrad= out->yrad;
+
+ for(y= -yrad; y<-yrad+out->y; y++) {
+ for(x= -xrad; x<-xrad+out->x; x++, outfp+=out->type) {
+ srcfp= compbuf_get_pixel(src_use, src_col, x, y, xrad, yrad);
+ func(node, outfp, srcfp);
+ }
+ }
+
+ if(src_use!=src_buf)
+ free_compbuf(src_use);
+}
+
+/* Pixel-to-Pixel operation, 2 Images in, 1 out */
+void composit2_pixel_processor(bNode *node, CompBuf *out, CompBuf *src_buf, float *src_col,
+ CompBuf *fac_buf, float *fac, void (*func)(bNode *, float *, float *, float *),
+ int src_type, int fac_type)
+{
+ CompBuf *src_use, *fac_use;
+ float *outfp=out->rect, *srcfp, *facfp;
+ int xrad, yrad, x, y;
+
+ src_use= typecheck_compbuf(src_buf, src_type);
+ fac_use= typecheck_compbuf(fac_buf, fac_type);
+
+ xrad= out->xrad;
+ yrad= out->yrad;
+
+ for(y= -yrad; y<-yrad+out->y; y++) {
+ for(x= -xrad; x<-xrad+out->x; x++, outfp+=out->type) {
+ srcfp= compbuf_get_pixel(src_use, src_col, x, y, xrad, yrad);
+ facfp= compbuf_get_pixel(fac_use, fac, x, y, xrad, yrad);
+
+ func(node, outfp, srcfp, facfp);
+ }
+ }
+ if(src_use!=src_buf)
+ free_compbuf(src_use);
+ if(fac_use!=fac_buf)
+ free_compbuf(fac_use);
+}
+
+/* Pixel-to-Pixel operation, 3 Images in, 1 out */
+void composit3_pixel_processor(bNode *node, CompBuf *out, CompBuf *src1_buf, float *src1_col, CompBuf *src2_buf, float *src2_col,
+ CompBuf *fac_buf, float *fac, void (*func)(bNode *, float *, float *, float *, float *),
+ int src1_type, int src2_type, int fac_type)
+{
+ CompBuf *src1_use, *src2_use, *fac_use;
+ float *outfp=out->rect, *src1fp, *src2fp, *facfp;
+ int xrad, yrad, x, y;
+
+ src1_use= typecheck_compbuf(src1_buf, src1_type);
+ src2_use= typecheck_compbuf(src2_buf, src2_type);
+ fac_use= typecheck_compbuf(fac_buf, fac_type);
+
+ xrad= out->xrad;
+ yrad= out->yrad;
+
+ for(y= -yrad; y<-yrad+out->y; y++) {
+ for(x= -xrad; x<-xrad+out->x; x++, outfp+=out->type) {
+ src1fp= compbuf_get_pixel(src1_use, src1_col, x, y, xrad, yrad);
+ src2fp= compbuf_get_pixel(src2_use, src2_col, x, y, xrad, yrad);
+ facfp= compbuf_get_pixel(fac_use, fac, x, y, xrad, yrad);
+
+ func(node, outfp, src1fp, src2fp, facfp);
+ }
+ }
+
+ if(src1_use!=src1_buf)
+ free_compbuf(src1_use);
+ if(src2_use!=src2_buf)
+ free_compbuf(src2_use);
+ if(fac_use!=fac_buf)
+ free_compbuf(fac_use);
+}
+
+/* Pixel-to-Pixel operation, 4 Images in, 1 out */
+void composit4_pixel_processor(bNode *node, CompBuf *out, CompBuf *src1_buf, float *src1_col, CompBuf *fac1_buf, float *fac1,
+ CompBuf *src2_buf, float *src2_col, CompBuf *fac2_buf, float *fac2,
+ void (*func)(bNode *, float *, float *, float *, float *, float *),
+ int src1_type, int fac1_type, int src2_type, int fac2_type)
+{
+ CompBuf *src1_use, *src2_use, *fac1_use, *fac2_use;
+ float *outfp=out->rect, *src1fp, *src2fp, *fac1fp, *fac2fp;
+ int xrad, yrad, x, y;
+
+ src1_use= typecheck_compbuf(src1_buf, src1_type);
+ src2_use= typecheck_compbuf(src2_buf, src2_type);
+ fac1_use= typecheck_compbuf(fac1_buf, fac1_type);
+ fac2_use= typecheck_compbuf(fac2_buf, fac2_type);
+
+ xrad= out->xrad;
+ yrad= out->yrad;
+
+ for(y= -yrad; y<-yrad+out->y; y++) {
+ for(x= -xrad; x<-xrad+out->x; x++, outfp+=out->type) {
+ src1fp= compbuf_get_pixel(src1_use, src1_col, x, y, xrad, yrad);
+ src2fp= compbuf_get_pixel(src2_use, src2_col, x, y, xrad, yrad);
+ fac1fp= compbuf_get_pixel(fac1_use, fac1, x, y, xrad, yrad);
+ fac2fp= compbuf_get_pixel(fac2_use, fac2, x, y, xrad, yrad);
+
+ func(node, outfp, src1fp, fac1fp, src2fp, fac2fp);
+ }
+ }
+
+ if(src1_use!=src1_buf)
+ free_compbuf(src1_use);
+ if(src2_use!=src2_buf)
+ free_compbuf(src2_use);
+ if(fac1_use!=fac1_buf)
+ free_compbuf(fac1_use);
+ if(fac2_use!=fac2_buf)
+ free_compbuf(fac2_use);
+}
+
+
+CompBuf *valbuf_from_rgbabuf(CompBuf *cbuf, int channel)
+{
+ CompBuf *valbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1);
+ float *valf, *rectf;
+ int tot;
+
+ /* warning note: xof and yof are applied in pixelprocessor, but should be copied otherwise? */
+ valbuf->xof= cbuf->xof;
+ valbuf->yof= cbuf->yof;
+
+ valf= valbuf->rect;
+
+ /* defaults to returning alpha channel */
+ if ((channel < CHAN_R) && (channel > CHAN_A)) channel = CHAN_A;
+
+ rectf= cbuf->rect + channel;
+
+ for(tot= cbuf->x*cbuf->y; tot>0; tot--, valf++, rectf+=4)
+ *valf= *rectf;
+
+ return valbuf;
+}
+
+void generate_preview(bNode *node, CompBuf *stackbuf)
+{
+ bNodePreview *preview= node->preview;
+
+ if(preview && stackbuf) {
+ CompBuf *cbuf, *stackbuf_use;
+
+ if(stackbuf->rect==NULL) return;
+
+ stackbuf_use= typecheck_compbuf(stackbuf, CB_RGBA);
+
+ if(stackbuf->x > stackbuf->y) {
+ preview->xsize= 140;
+ preview->ysize= (140*stackbuf->y)/stackbuf->x;
+ }
+ else {
+ preview->ysize= 140;
+ preview->xsize= (140*stackbuf->x)/stackbuf->y;
+ }
+
+ cbuf= scalefast_compbuf(stackbuf_use, preview->xsize, preview->ysize);
+
+ /* this ensures free-compbuf does the right stuff */
+ SWAP(float *, cbuf->rect, node->preview->rect);
+
+ free_compbuf(cbuf);
+ if(stackbuf_use!=stackbuf)
+ free_compbuf(stackbuf_use);
+
+ }
+}
+
+void do_rgba_to_yuva(bNode *node, float *out, float *in)
+{
+ rgb_to_yuv(in[0],in[1],in[2], &out[0], &out[1], &out[2]);
+ out[3]=in[3];
+}
+
+void do_rgba_to_hsva(bNode *node, float *out, float *in)
+{
+ rgb_to_hsv(in[0],in[1],in[2], &out[0], &out[1], &out[2]);
+ out[3]=in[3];
+}
+
+void do_rgba_to_ycca(bNode *node, float *out, float *in)
+{
+ rgb_to_ycc(in[0],in[1],in[2], &out[0], &out[1], &out[2]);
+ out[3]=in[3];
+}
+
+void do_yuva_to_rgba(bNode *node, float *out, float *in)
+{
+ yuv_to_rgb(in[0],in[1],in[2], &out[0], &out[1], &out[2]);
+ out[3]=in[3];
+}
+
+void do_hsva_to_rgba(bNode *node, float *out, float *in)
+{
+ hsv_to_rgb(in[0],in[1],in[2], &out[0], &out[1], &out[2]);
+ out[3]=in[3];
+}
+
+void do_ycca_to_rgba(bNode *node, float *out, float *in)
+{
+ ycc_to_rgb(in[0],in[1],in[2], &out[0], &out[1], &out[2]);
+ out[3]=in[3];
+}
+
+void do_copy_rgba(bNode *node, float *out, float *in)
+{
+ QUATCOPY(out, in);
+}
+
+void do_copy_rgb(bNode *node, float *out, float *in)
+{
+ VECCOPY(out, in);
+ out[3]= 1.0f;
+}
+
+void do_copy_value(bNode *node, float *out, float *in)
+{
+ out[0]= in[0];
+}
+
+void do_copy_a_rgba(bNode *node, float *out, float *in, float *fac)
+{
+ VECCOPY(out, in);
+ out[3]= *fac;
+}
+
+/* only accepts RGBA buffers */
+void gamma_correct_compbuf(CompBuf *img, int inversed)
+{
+ float *drect;
+ int x;
+
+ if(img->type!=CB_RGBA) return;
+
+ drect= img->rect;
+ if(inversed) {
+ for(x=img->x*img->y; x>0; x--, drect+=4) {
+ if(drect[0]>0.0f) drect[0]= sqrt(drect[0]); else drect[0]= 0.0f;
+ if(drect[1]>0.0f) drect[1]= sqrt(drect[1]); else drect[1]= 0.0f;
+ if(drect[2]>0.0f) drect[2]= sqrt(drect[2]); else drect[2]= 0.0f;
+ }
+ }
+ else {
+ for(x=img->x*img->y; x>0; x--, drect+=4) {
+ if(drect[0]>0.0f) drect[0]*= drect[0]; else drect[0]= 0.0f;
+ if(drect[1]>0.0f) drect[1]*= drect[1]; else drect[1]= 0.0f;
+ if(drect[2]>0.0f) drect[2]*= drect[2]; else drect[2]= 0.0f;
+ }
+ }
+}
+
+
+
+
+/*
+ * 2D Fast Hartley Transform, used for convolution
+ */
+
+typedef float fREAL;
+
+// returns next highest power of 2 of x, as well it's log2 in L2
+static unsigned int nextPow2(unsigned int x, unsigned int* L2)
+{
+ unsigned int pw, x_notpow2 = x & (x-1);
+ *L2 = 0;
+ while (x>>=1) ++(*L2);
+ pw = 1 << (*L2);
+ if (x_notpow2) { (*L2)++; pw<<=1; }
+ return pw;
+}
+
+//------------------------------------------------------------------------------
+
+// from FXT library by Joerg Arndt, faster in order bitreversal
+// use: r = revbin_upd(r, h) where h = N>>1
+static unsigned int revbin_upd(unsigned int r, unsigned int h)
+{
+ while (!((r^=h)&h)) h >>= 1;
+ return r;
+}
+//------------------------------------------------------------------------------
+static void FHT(fREAL* data, unsigned int M, unsigned int inverse)
+{
+ double tt, fc, dc, fs, ds, a = M_PI;
+ fREAL t1, t2;
+ int n2, bd, bl, istep, k, len = 1 << M, n = 1;
+
+ int i, j = 0;
+ unsigned int Nh = len >> 1;
+ for (i=1;i<(len-1);++i) {
+ j = revbin_upd(j, Nh);
+ if (j>i) {
+ t1 = data[i];
+ data[i] = data[j];
+ data[j] = t1;
+ }
+ }
+
+ do {
+ fREAL* data_n = &data[n];
+
+ istep = n << 1;
+ for (k=0; k<len; k+=istep) {
+ t1 = data_n[k];
+ data_n[k] = data[k] - t1;
+ data[k] += t1;
+ }
+
+ n2 = n >> 1;
+ if (n>2) {
+ fc = dc = cos(a);
+ fs = ds = sqrt(1.0 - fc*fc); //sin(a);
+ bd = n-2;
+ for (bl=1; bl<n2; bl++) {
+ fREAL* data_nbd = &data_n[bd];
+ fREAL* data_bd = &data[bd];
+ for (k=bl; k<len; k+=istep) {
+ t1 = fc*data_n[k] + fs*data_nbd[k];
+ t2 = fs*data_n[k] - fc*data_nbd[k];
+ data_n[k] = data[k] - t1;
+ data_nbd[k] = data_bd[k] - t2;
+ data[k] += t1;
+ data_bd[k] += t2;
+ }
+ tt = fc*dc - fs*ds;
+ fs = fs*dc + fc*ds;
+ fc = tt;
+ bd -= 2;
+ }
+ }
+
+ if (n>1) {
+ for (k=n2; k<len; k+=istep) {
+ t1 = data_n[k];
+ data_n[k] = data[k] - t1;
+ data[k] += t1;
+ }
+ }
+
+ n = istep;
+ a *= 0.5;
+ } while (n<len);
+
+ if (inverse) {
+ fREAL sc = (fREAL)1 / (fREAL)len;
+ for (k=0; k<len; ++k)
+ data[k] *= sc;
+ }
+}
+//------------------------------------------------------------------------------
+/* 2D Fast Hartley Transform, Mx/My -> log2 of width/height,
+ nzp -> the row where zero pad data starts,
+ inverse -> see above */
+static void FHT2D(fREAL *data, unsigned int Mx, unsigned int My,
+ unsigned int nzp, unsigned int inverse)
+{
+ unsigned int i, j, Nx, Ny, maxy;
+ fREAL t;
+
+ Nx = 1 << Mx;
+ Ny = 1 << My;
+
+ // rows (forward transform skips 0 pad data)
+ maxy = inverse ? Ny : nzp;
+ for (j=0; j<maxy; ++j)
+ FHT(&data[Nx*j], Mx, inverse);
+
+ // transpose data
+ if (Nx==Ny) { // square
+ for (j=0; j<Ny; ++j)
+ for (i=j+1; i<Nx; ++i) {
+ unsigned int op = i + (j << Mx), np = j + (i << My);
+ t=data[op], data[op]=data[np], data[np]=t;
+ }
+ }
+ else { // rectangular
+ unsigned int k, Nym = Ny-1, stm = 1 << (Mx + My);
+ for (i=0; stm>0; i++) {
+ #define pred(k) (((k & Nym) << Mx) + (k >> My))
+ for (j=pred(i); j>i; j=pred(j));
+ if (j < i) continue;
+ for (k=i, j=pred(i); j!=i; k=j, j=pred(j), stm--)
+ { t=data[j], data[j]=data[k], data[k]=t; }
+ #undef pred
+ stm--;
+ }
+ }
+ // swap Mx/My & Nx/Ny
+ i = Nx, Nx = Ny, Ny = i;
+ i = Mx, Mx = My, My = i;
+
+ // now columns == transposed rows
+ for (j=0; j<Ny; ++j)
+ FHT(&data[Nx*j], Mx, inverse);
+
+ // finalize
+ for (j=0; j<=(Ny >> 1); j++) {
+ unsigned int jm = (Ny - j) & (Ny-1);
+ unsigned int ji = j << Mx;
+ unsigned int jmi = jm << Mx;
+ for (i=0; i<=(Nx >> 1); i++) {
+ unsigned int im = (Nx - i) & (Nx-1);
+ fREAL A = data[ji + i];
+ fREAL B = data[jmi + i];
+ fREAL C = data[ji + im];
+ fREAL D = data[jmi + im];
+ fREAL E = (fREAL)0.5*((A + D) - (B + C));
+ data[ji + i] = A - E;
+ data[jmi + i] = B + E;
+ data[ji + im] = C + E;
+ data[jmi + im] = D - E;
+ }
+ }
+
+}
+
+//------------------------------------------------------------------------------
+
+/* 2D convolution calc, d1 *= d2, M/N - > log2 of width/height */
+static void fht_convolve(fREAL* d1, fREAL* d2, unsigned int M, unsigned int N)
+{
+ fREAL a, b;
+ unsigned int i, j, k, L, mj, mL;
+ unsigned int m = 1 << M, n = 1 << N;
+ unsigned int m2 = 1 << (M-1), n2 = 1 << (N-1);
+ unsigned int mn2 = m << (N-1);
+
+ d1[0] *= d2[0];
+ d1[mn2] *= d2[mn2];
+ d1[m2] *= d2[m2];
+ d1[m2 + mn2] *= d2[m2 + mn2];
+ for (i=1; i<m2; i++) {
+ k = m - i;
+ a = d1[i]*d2[i] - d1[k]*d2[k];
+ b = d1[k]*d2[i] + d1[i]*d2[k];
+ d1[i] = (b + a)*(fREAL)0.5;
+ d1[k] = (b - a)*(fREAL)0.5;
+ a = d1[i + mn2]*d2[i + mn2] - d1[k + mn2]*d2[k + mn2];
+ b = d1[k + mn2]*d2[i + mn2] + d1[i + mn2]*d2[k + mn2];
+ d1[i + mn2] = (b + a)*(fREAL)0.5;
+ d1[k + mn2] = (b - a)*(fREAL)0.5;
+ }
+ for (j=1; j<n2; j++) {
+ L = n - j;
+ mj = j << M;
+ mL = L << M;
+ a = d1[mj]*d2[mj] - d1[mL]*d2[mL];
+ b = d1[mL]*d2[mj] + d1[mj]*d2[mL];
+ d1[mj] = (b + a)*(fREAL)0.5;
+ d1[mL] = (b - a)*(fREAL)0.5;
+ a = d1[m2 + mj]*d2[m2 + mj] - d1[m2 + mL]*d2[m2 + mL];
+ b = d1[m2 + mL]*d2[m2 + mj] + d1[m2 + mj]*d2[m2 + mL];
+ d1[m2 + mj] = (b + a)*(fREAL)0.5;
+ d1[m2 + mL] = (b - a)*(fREAL)0.5;
+ }
+ for (i=1; i<m2; i++) {
+ k = m - i;
+ for (j=1; j<n2; j++) {
+ L = n - j;
+ mj = j << M;
+ mL = L << M;
+ a = d1[i + mj]*d2[i + mj] - d1[k + mL]*d2[k + mL];
+ b = d1[k + mL]*d2[i + mj] + d1[i + mj]*d2[k + mL];
+ d1[i + mj] = (b + a)*(fREAL)0.5;
+ d1[k + mL] = (b - a)*(fREAL)0.5;
+ a = d1[i + mL]*d2[i + mL] - d1[k + mj]*d2[k + mj];
+ b = d1[k + mj]*d2[i + mL] + d1[i + mL]*d2[k + mj];
+ d1[i + mL] = (b + a)*(fREAL)0.5;
+ d1[k + mj] = (b - a)*(fREAL)0.5;
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+
+void convolve(CompBuf* dst, CompBuf* in1, CompBuf* in2)
+{
+ fREAL *data1, *data2, *fp;
+ unsigned int w2, h2, hw, hh, log2_w, log2_h;
+ fRGB wt, *colp;
+ int x, y, ch;
+ int xbl, ybl, nxb, nyb, xbsz, ybsz;
+ int in2done = 0;
+
+ CompBuf* rdst = alloc_compbuf(in1->x, in1->y, in1->type, 1);
+
+ // convolution result width & height
+ w2 = 2*in2->x - 1;
+ h2 = 2*in2->y - 1;
+ // FFT pow2 required size & log2
+ w2 = nextPow2(w2, &log2_w);
+ h2 = nextPow2(h2, &log2_h);
+
+ // alloc space
+ data1 = (fREAL*)MEM_callocN(3*w2*h2*sizeof(fREAL), "convolve_fast FHT data1");
+ data2 = (fREAL*)MEM_callocN(w2*h2*sizeof(fREAL), "convolve_fast FHT data2");
+
+ // normalize convolutor
+ wt[0] = wt[1] = wt[2] = 0.f;
+ for (y=0; y<in2->y; y++) {
+ colp = (fRGB*)&in2->rect[y*in2->x*in2->type];
+ for (x=0; x<in2->x; x++)
+ fRGB_add(wt, colp[x]);
+ }
+ if (wt[0] != 0.f) wt[0] = 1.f/wt[0];
+ if (wt[1] != 0.f) wt[1] = 1.f/wt[1];
+ if (wt[2] != 0.f) wt[2] = 1.f/wt[2];
+ for (y=0; y<in2->y; y++) {
+ colp = (fRGB*)&in2->rect[y*in2->x*in2->type];
+ for (x=0; x<in2->x; x++)
+ fRGB_colormult(colp[x], wt);
+ }
+
+ // copy image data, unpacking interleaved RGBA into separate channels
+ // only need to calc data1 once
+
+ // block add-overlap
+ hw = in2->x >> 1;
+ hh = in2->y >> 1;
+ xbsz = (w2 + 1) - in2->x;
+ ybsz = (h2 + 1) - in2->y;
+ nxb = in1->x / xbsz;
+ if (in1->x % xbsz) nxb++;
+ nyb = in1->y / ybsz;
+ if (in1->y % ybsz) nyb++;
+ for (ybl=0; ybl<nyb; ybl++) {
+ for (xbl=0; xbl<nxb; xbl++) {
+
+ // each channel one by one
+ for (ch=0; ch<3; ch++) {
+ fREAL* data1ch = &data1[ch*w2*h2];
+
+ // only need to calc fht data from in2 once, can re-use for every block
+ if (!in2done) {
+ // in2, channel ch -> data1
+ for (y=0; y<in2->y; y++) {
+ fp = &data1ch[y*w2];
+ colp = (fRGB*)&in2->rect[y*in2->x*in2->type];
+ for (x=0; x<in2->x; x++)
+ fp[x] = colp[x][ch];
+ }
+ }
+
+ // in1, channel ch -> data2
+ memset(data2, 0, w2*h2*sizeof(fREAL));
+ for (y=0; y<ybsz; y++) {
+ int yy = ybl*ybsz + y;
+ if (yy >= in1->y) continue;
+ fp = &data2[y*w2];
+ colp = (fRGB*)&in1->rect[yy*in1->x*in1->type];
+ for (x=0; x<xbsz; x++) {
+ int xx = xbl*xbsz + x;
+ if (xx >= in1->x) continue;
+ fp[x] = colp[xx][ch];
+ }
+ }
+
+ // forward FHT
+ // zero pad data start is different for each == height+1
+ if (!in2done) FHT2D(data1ch, log2_w, log2_h, in2->y+1, 0);
+ FHT2D(data2, log2_w, log2_h, in2->y+1, 0);
+
+ // FHT2D transposed data, row/col now swapped
+ // convolve & inverse FHT
+ fht_convolve(data2, data1ch, log2_h, log2_w);
+ FHT2D(data2, log2_h, log2_w, 0, 1);
+ // data again transposed, so in order again
+
+ // overlap-add result
+ for (y=0; y<(int)h2; y++) {
+ const int yy = ybl*ybsz + y - hh;
+ if ((yy < 0) || (yy >= in1->y)) continue;
+ fp = &data2[y*w2];
+ colp = (fRGB*)&rdst->rect[yy*in1->x*in1->type];
+ for (x=0; x<(int)w2; x++) {
+ const int xx = xbl*xbsz + x - hw;
+ if ((xx < 0) || (xx >= in1->x)) continue;
+ colp[xx][ch] += fp[x];
+ }
+ }
+
+ }
+ in2done = 1;
+ }
+ }
+
+ MEM_freeN(data2);
+ MEM_freeN(data1);
+ memcpy(dst->rect, rdst->rect, sizeof(float)*dst->x*dst->y*dst->type);
+ free_compbuf(rdst);
+}
+
+
+/*
+ *
+ * Utility functions qd_* should probably be intergrated better with other functions here.
+ *
+ */
+// sets fcol to pixelcolor at (x, y)
+void qd_getPixel(CompBuf* src, int x, int y, float* col)
+{
+ if ((x >= 0) && (x < src->x) && (y >= 0) && (y < src->y)) {
+ float* bc = &src->rect[(x + y*src->x)*src->type];
+ col[0] = bc[0], col[1] = bc[1], col[2] = bc[2];
+ }
+ else col[0] = col[1] = col[2] = 0.f;
+}
+
+// sets pixel (x, y) to color col
+void qd_setPixel(CompBuf* src, int x, int y, float* col)
+{
+ if ((x >= 0) && (x < src->x) && (y >= 0) && (y < src->y)) {
+ float* bc = &src->rect[(x + y*src->x)*src->type];
+ bc[0] = col[0], bc[1] = col[1], bc[2] = col[2];
+ }
+}
+
+// adds fcol to pixelcolor (x, y)
+void qd_addPixel(CompBuf* src, int x, int y, float* col)
+{
+ if ((x >= 0) && (x < src->x) && (y >= 0) && (y < src->y)) {
+ float* bc = &src->rect[(x + y*src->x)*src->type];
+ bc[0] += col[0], bc[1] += col[1], bc[2] += col[2];
+ }
+}
+
+// multiplies pixel by factor value f
+void qd_multPixel(CompBuf* src, int x, int y, float f)
+{
+ if ((x >= 0) && (x < src->x) && (y >= 0) && (y < src->y)) {
+ float* bc = &src->rect[(x + y*src->x)*src->type];
+ bc[0] *= f, bc[1] *= f, bc[2] *= f;
+ }
+}
+
+// bilinear interpolation with wraparound
+void qd_getPixelLerpWrap(CompBuf* src, float u, float v, float* col)
+{
+ const float ufl = floor(u), vfl = floor(v);
+ const int nx = (int)ufl % src->x, ny = (int)vfl % src->y;
+ const int x1 = (nx < 0) ? (nx + src->x) : nx;
+ const int y1 = (ny < 0) ? (ny + src->y) : ny;
+ const int x2 = (x1 + 1) % src->x, y2 = (y1 + 1) % src->y;
+ const float* c00 = &src->rect[(x1 + y1*src->x)*src->type];
+ const float* c10 = &src->rect[(x2 + y1*src->x)*src->type];
+ const float* c01 = &src->rect[(x1 + y2*src->x)*src->type];
+ const float* c11 = &src->rect[(x2 + y2*src->x)*src->type];
+ const float uf = u - ufl, vf = v - vfl;
+ const float w00=(1.f-uf)*(1.f-vf), w10=uf*(1.f-vf), w01=(1.f-uf)*vf, w11=uf*vf;
+ col[0] = w00*c00[0] + w10*c10[0] + w01*c01[0] + w11*c11[0];
+ if (src->type != CB_VAL) {
+ col[1] = w00*c00[1] + w10*c10[1] + w01*c01[1] + w11*c11[1];
+ col[2] = w00*c00[2] + w10*c10[2] + w01*c01[2] + w11*c11[2];
+ col[3] = w00*c00[3] + w10*c10[3] + w01*c01[3] + w11*c11[3];
+ }
+}
+
+// as above, without wrap around
+void qd_getPixelLerp(CompBuf* src, float u, float v, float* col)
+{
+ const float ufl = floor(u), vfl = floor(v);
+ const int x1 = (int)ufl, y1 = (int)vfl;
+ const int x2 = (int)ceil(u), y2 = (int)ceil(v);
+ if ((x2 >= 0) && (y2 >= 0) && (x1 < src->x) && (y1 < src->y)) {
+ const float B[4] = {0,0,0,0};
+ const int ox1 = (x1 < 0), oy1 = (y1 < 0), ox2 = (x2 >= src->x), oy2 = (y2 >= src->y);
+ const float* c00 = (ox1 || oy1) ? B : &src->rect[(x1 + y1*src->x)*src->type];
+ const float* c10 = (ox2 || oy1) ? B : &src->rect[(x2 + y1*src->x)*src->type];
+ const float* c01 = (ox1 || oy2) ? B : &src->rect[(x1 + y2*src->x)*src->type];
+ const float* c11 = (ox2 || oy2) ? B : &src->rect[(x2 + y2*src->x)*src->type];
+ const float uf = u - ufl, vf = v - vfl;
+ const float w00=(1.f-uf)*(1.f-vf), w10=uf*(1.f-vf), w01=(1.f-uf)*vf, w11=uf*vf;
+ col[0] = w00*c00[0] + w10*c10[0] + w01*c01[0] + w11*c11[0];
+ if (src->type != CB_VAL) {
+ col[1] = w00*c00[1] + w10*c10[1] + w01*c01[1] + w11*c11[1];
+ col[2] = w00*c00[2] + w10*c10[2] + w01*c01[2] + w11*c11[2];
+ col[3] = w00*c00[3] + w10*c10[3] + w01*c01[3] + w11*c11[3];
+ }
+ }
+ else col[0] = col[1] = col[2] = col[3] = 0.f;
+}
+
+// as above, sampling only one channel
+void qd_getPixelLerpChan(CompBuf* src, float u, float v, int chan, float* out)
+{
+ const float ufl = floor(u), vfl = floor(v);
+ const int x1 = (int)ufl, y1 = (int)vfl;
+ const int x2 = (int)ceil(u), y2 = (int)ceil(v);
+ if (chan >= src->type) chan = 0;
+ if ((x2 >= 0) && (y2 >= 0) && (x1 < src->x) && (y1 < src->y)) {
+ const float B[4] = {0,0,0,0};
+ const int ox1 = (x1 < 0), oy1 = (y1 < 0), ox2 = (x2 >= src->x), oy2 = (y2 >= src->y);
+ const float* c00 = (ox1 || oy1) ? B : &src->rect[(x1 + y1*src->x)*src->type + chan];
+ const float* c10 = (ox2 || oy1) ? B : &src->rect[(x2 + y1*src->x)*src->type + chan];
+ const float* c01 = (ox1 || oy2) ? B : &src->rect[(x1 + y2*src->x)*src->type + chan];
+ const float* c11 = (ox2 || oy2) ? B : &src->rect[(x2 + y2*src->x)*src->type + chan];
+ const float uf = u - ufl, vf = v - vfl;
+ const float w00=(1.f-uf)*(1.f-vf), w10=uf*(1.f-vf), w01=(1.f-uf)*vf, w11=uf*vf;
+ out[0] = w00*c00[0] + w10*c10[0] + w01*c01[0] + w11*c11[0];
+ }
+ else *out = 0.f;
+}
+
+
+CompBuf* qd_downScaledCopy(CompBuf* src, int scale)
+{
+ CompBuf* fbuf;
+ if (scale <= 1)
+ fbuf = dupalloc_compbuf(src);
+ else {
+ int nw = src->x/scale, nh = src->y/scale;
+ if ((2*(src->x % scale)) > scale) nw++;
+ if ((2*(src->y % scale)) > scale) nh++;
+ fbuf = alloc_compbuf(nw, nh, src->type, 1);
+ {
+ int x, y, xx, yy, sx, sy, mx, my;
+ float colsum[4];
+ float fscale = 1.f/(float)(scale*scale);
+ for (y=0; y<nh; y++) {
+ fRGB* fcolp = (fRGB*)&fbuf->rect[y*fbuf->x*fbuf->type];
+ yy = y*scale;
+ my = yy + scale;
+ if (my > src->y) my = src->y;
+ for (x=0; x<nw; x++) {
+ xx = x*scale;
+ mx = xx + scale;
+ if (mx > src->x) mx = src->x;
+ colsum[0] = colsum[1] = colsum[2] = 0.f;
+ for (sy=yy; sy<my; sy++) {
+ fRGB* scolp = (fRGB*)&src->rect[sy*src->x*src->type];
+ for (sx=xx; sx<mx; sx++)
+ fRGB_add(colsum, scolp[sx]);
+ }
+ fRGB_mult(colsum, fscale);
+ fRGB_copy(fcolp[x], colsum);
+ }
+ }
+ }
+ }
+ return fbuf;
+}
+
+// fast g.blur, per channel
+// xy var. bits 1 & 2 ca be used to blur in x or y direction separately
+void IIR_gauss(CompBuf* src, float sigma, int chan, int xy)
+{
+ double q, q2, sc, cf[4], tsM[9], tsu[3], tsv[3];
+ float *X, *Y, *W;
+ int i, x, y, sz;
+
+ // <0.5 not valid, though can have a possibly useful sort of sharpening effect
+ if (sigma < 0.5) return;
+
+ if ((xy < 1) || (xy > 3)) xy = 3;
+
+ // see "Recursive Gabor Filtering" by Young/VanVliet
+ // all factors here in double.prec. Required, because for single.prec it seems to blow up if sigma > ~200
+ if (sigma >= 3.556)
+ q = 0.9804*(sigma - 3.556) + 2.5091;
+ else // sigma >= 0.5
+ q = (0.0561*sigma + 0.5784)*sigma - 0.2568;
+ q2 = q*q;
+ sc = (1.1668 + q)*(3.203729649 + (2.21566 + q)*q);
+ // no gabor filtering here, so no complex multiplies, just the regular coefs.
+ // all negated here, so as not to have to recalc Triggs/Sdika matrix
+ cf[1] = q*(5.788961737 + (6.76492 + 3.0*q)*q)/ sc;
+ cf[2] = -q2*(3.38246 + 3.0*q)/sc;
+ // 0 & 3 unchanged
+ cf[3] = q2*q/sc;
+ cf[0] = 1.0 - cf[1] - cf[2] - cf[3];
+
+ // Triggs/Sdika border corrections,
+ // it seems to work, not entirely sure if it is actually totally correct,
+ // Besides J.M.Geusebroek's anigauss.c (see http://www.science.uva.nl/~mark),
+ // found one other implementation by Cristoph Lampert,
+ // but neither seem to be quite the same, result seems to be ok sofar anyway.
+ // Extra scale factor here to not have to do it in filter,
+ // though maybe this had something to with the precision errors
+ sc = cf[0]/((1.0 + cf[1] - cf[2] + cf[3])*(1.0 - cf[1] - cf[2] - cf[3])*(1.0 + cf[2] + (cf[1] - cf[3])*cf[3]));
+ tsM[0] = sc*(-cf[3]*cf[1] + 1.0 - cf[3]*cf[3] - cf[2]);
+ tsM[1] = sc*((cf[3] + cf[1])*(cf[2] + cf[3]*cf[1]));
+ tsM[2] = sc*(cf[3]*(cf[1] + cf[3]*cf[2]));
+ tsM[3] = sc*(cf[1] + cf[3]*cf[2]);
+ tsM[4] = sc*(-(cf[2] - 1.0)*(cf[2] + cf[3]*cf[1]));
+ tsM[5] = sc*(-(cf[3]*cf[1] + cf[3]*cf[3] + cf[2] - 1.0)*cf[3]);
+ tsM[6] = sc*(cf[3]*cf[1] + cf[2] + cf[1]*cf[1] - cf[2]*cf[2]);
+ tsM[7] = sc*(cf[1]*cf[2] + cf[3]*cf[2]*cf[2] - cf[1]*cf[3]*cf[3] - cf[3]*cf[3]*cf[3] - cf[3]*cf[2] + cf[3]);
+ tsM[8] = sc*(cf[3]*(cf[1] + cf[3]*cf[2]));
+
+#define YVV(L)\
+{\
+ W[0] = cf[0]*X[0] + cf[1]*X[0] + cf[2]*X[0] + cf[3]*X[0];\
+ W[1] = cf[0]*X[1] + cf[1]*W[0] + cf[2]*X[0] + cf[3]*X[0];\
+ W[2] = cf[0]*X[2] + cf[1]*W[1] + cf[2]*W[0] + cf[3]*X[0];\
+ for (i=3; i<L; i++)\
+ W[i] = cf[0]*X[i] + cf[1]*W[i-1] + cf[2]*W[i-2] + cf[3]*W[i-3];\
+ tsu[0] = W[L-1] - X[L-1];\
+ tsu[1] = W[L-2] - X[L-1];\
+ tsu[2] = W[L-3] - X[L-1];\
+ tsv[0] = tsM[0]*tsu[0] + tsM[1]*tsu[1] + tsM[2]*tsu[2] + X[L-1];\
+ tsv[1] = tsM[3]*tsu[0] + tsM[4]*tsu[1] + tsM[5]*tsu[2] + X[L-1];\
+ tsv[2] = tsM[6]*tsu[0] + tsM[7]*tsu[1] + tsM[8]*tsu[2] + X[L-1];\
+ Y[L-1] = cf[0]*W[L-1] + cf[1]*tsv[0] + cf[2]*tsv[1] + cf[3]*tsv[2];\
+ Y[L-2] = cf[0]*W[L-2] + cf[1]*Y[L-1] + cf[2]*tsv[0] + cf[3]*tsv[1];\
+ Y[L-3] = cf[0]*W[L-3] + cf[1]*Y[L-2] + cf[2]*Y[L-1] + cf[3]*tsv[0];\
+ for (i=L-4; i>=0; i--)\
+ Y[i] = cf[0]*W[i] + cf[1]*Y[i+1] + cf[2]*Y[i+2] + cf[3]*Y[i+3];\
+}
+
+ // intermediate buffers
+ sz = MAX2(src->x, src->y);
+ X = MEM_callocN(sz*sizeof(float), "IIR_gauss X buf");
+ Y = MEM_callocN(sz*sizeof(float), "IIR_gauss Y buf");
+ W = MEM_callocN(sz*sizeof(float), "IIR_gauss W buf");
+ if (xy & 1) { // H
+ for (y=0; y<src->y; ++y) {
+ const int yx = y*src->x;
+ for (x=0; x<src->x; ++x)
+ X[x] = src->rect[(x + yx)*src->type + chan];
+ YVV(src->x);
+ for (x=0; x<src->x; ++x)
+ src->rect[(x + yx)*src->type + chan] = Y[x];
+ }
+ }
+ if (xy & 2) { // V
+ for (x=0; x<src->x; ++x) {
+ for (y=0; y<src->y; ++y)
+ X[y] = src->rect[(x + y*src->x)*src->type + chan];
+ YVV(src->y);
+ for (y=0; y<src->y; ++y)
+ src->rect[(x + y*src->x)*src->type + chan] = Y[y];
+ }
+ }
+
+ MEM_freeN(X);
+ MEM_freeN(W);
+ MEM_freeN(Y);
+#undef YVV
+}
+
diff --git a/source/blender/nodes/intern/CMP_util.h b/source/blender/nodes/intern/CMP_util.h
new file mode 100644
index 00000000000..7cb10b75f3a
--- /dev/null
+++ b/source/blender/nodes/intern/CMP_util.h
@@ -0,0 +1,221 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef CMP_NODE_UTILS_H_
+#define CMP_NODE_UTILS_H_
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_camera_types.h" /* qdn: defocus node, need camera info */
+#include "DNA_action_types.h"
+#include "DNA_color_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_ID.h"
+#include "DNA_image_types.h"
+#include "DNA_material_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BKE_blender.h"
+#include "BKE_colortools.h"
+#include "BKE_global.h"
+#include "BKE_image.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
+#include "BKE_library.h"
+#include "BKE_object.h"
+
+#include "../CMP_node.h"
+#include "node_util.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+#include "BIF_interface.h"
+#include "BIF_interface_icons.h"
+#include "BIF_language.h"
+#include "BIF_mywindow.h"
+#include "BIF_previewrender.h"
+#include "BIF_resources.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+#include "BLI_rand.h"
+#include "BLI_threads.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "BSE_drawipo.h"
+#include "BSE_node.h"
+#include "BSE_view.h"
+
+#include "RE_pipeline.h"
+#include "RE_shader_ext.h"
+#include "RE_render_ext.h"
+
+#include "butspace.h"
+#include "blendef.h"
+#include "mydevice.h"
+
+/* *************************** operations support *************************** */
+
+/* general signal that's in output sockets, and goes over the wires */
+typedef struct CompBuf {
+ float *rect;
+ int x, y, xrad, yrad;
+ short type, malloc;
+ rcti disprect; /* cropped part of image */
+ int xof, yof; /* relative to center of target image */
+
+ void (*rect_procedural)(struct CompBuf *, float *, float, float);
+ bNode *node; /* only in use for procedural bufs */
+
+ struct CompBuf *next, *prev; /* for pass-on, works nicer than reference counting */
+} CompBuf;
+
+/* defines also used for pixel size */
+#define CB_RGBA 4
+#define CB_VEC4 4
+#define CB_VEC3 3
+#define CB_VEC2 2
+#define CB_VAL 1
+
+/* defines for RGBA channels */
+#define CHAN_R 0
+#define CHAN_G 1
+#define CHAN_B 2
+#define CHAN_A 3
+
+
+
+CompBuf *alloc_compbuf(int sizex, int sizey, int type, int alloc);
+CompBuf *dupalloc_compbuf(CompBuf *cbuf);
+CompBuf *pass_on_compbuf(CompBuf *cbuf);
+void free_compbuf(CompBuf *cbuf);
+void print_compbuf(char *str, CompBuf *cbuf);
+
+CompBuf *get_cropped_compbuf(rcti *drect, float *rectf, int rectx, int recty, int type);
+CompBuf *scalefast_compbuf(CompBuf *inbuf, int newx, int newy);
+CompBuf *typecheck_compbuf(CompBuf *inbuf, int type);
+float *compbuf_get_pixel(CompBuf *cbuf, float *rectf, int x, int y, int xrad, int yrad);
+
+/* **************************************************** */
+
+/* Pixel-to-Pixel operation, 1 Image in, 1 out */
+void composit1_pixel_processor(bNode *node, CompBuf *out, CompBuf *src_buf, float *src_col,
+ void (*func)(bNode *, float *, float *),
+ int src_type);
+/* Pixel-to-Pixel operation, 2 Images in, 1 out */
+void composit2_pixel_processor(bNode *node, CompBuf *out, CompBuf *src_buf, float *src_col,
+ CompBuf *fac_buf, float *fac, void (*func)(bNode *, float *, float *, float *),
+ int src_type, int fac_type);
+
+/* Pixel-to-Pixel operation, 3 Images in, 1 out */
+void composit3_pixel_processor(bNode *node, CompBuf *out, CompBuf *src1_buf, float *src1_col, CompBuf *src2_buf, float *src2_col,
+ CompBuf *fac_buf, float *fac, void (*func)(bNode *, float *, float *, float *, float *),
+ int src1_type, int src2_type, int fac_type);
+
+/* Pixel-to-Pixel operation, 4 Images in, 1 out */
+void composit4_pixel_processor(bNode *node, CompBuf *out, CompBuf *src1_buf, float *src1_col, CompBuf *fac1_buf, float *fac1,
+ CompBuf *src2_buf, float *src2_col, CompBuf *fac2_buf, float *fac2,
+ void (*func)(bNode *, float *, float *, float *, float *, float *),
+ int src1_type, int fac1_type, int src2_type, int fac2_type);
+
+CompBuf *valbuf_from_rgbabuf(CompBuf *cbuf, int channel);
+void generate_preview(bNode *node, CompBuf *stackbuf);
+
+void do_copy_rgba(bNode *node, float *out, float *in);
+void do_copy_rgb(bNode *node, float *out, float *in);
+void do_copy_value(bNode *node, float *out, float *in);
+void do_copy_a_rgba(bNode *node, float *out, float *in, float *fac);
+
+void do_rgba_to_yuva(bNode *node, float *out, float *in);
+void do_rgba_to_hsva(bNode *node, float *out, float *in);
+void do_rgba_to_ycca(bNode *node, float *out, float *in);
+void do_yuva_to_rgba(bNode *node, float *out, float *in);
+void do_hsva_to_rgba(bNode *node, float *out, float *in);
+void do_ycca_to_rgba(bNode *node, float *out, float *in);
+
+void gamma_correct_compbuf(CompBuf *img, int inversed);
+void convolve(CompBuf* dst, CompBuf* in1, CompBuf* in2);
+
+extern void node_ID_title_cb(void *node_v, void *unused_v);
+
+
+/* utility functions used by glare, tonemap and lense distortion */
+/* soms macros for color handling */
+typedef float fRGB[4];
+/* clear color */
+#define fRGB_clear(c) { c[0]=c[1]=c[2]=0.f; }
+/* copy c2 to c1 */
+#define fRGB_copy(c1, c2) { c1[0]=c2[0]; c1[1]=c2[1]; c1[2]=c2[2]; }
+/* add c2 to c1 */
+#define fRGB_add(c1, c2) { c1[0]+=c2[0]; c1[1]+=c2[1]; c1[2]+=c2[2]; }
+/* subtract c2 from c1 */
+#define fRGB_sub(c1, c2) { c1[0]-=c2[0]; c1[1]-=c2[1]; c1[2]-=c2[2]; }
+/* multiply c by float value s */
+#define fRGB_mult(c, s) { c[0]*=s; c[1]*=s; c[2]*=s; }
+/* multiply c2 by s and add to c1 */
+#define fRGB_madd(c1, c2, s) { c1[0]+=c2[0]*s; c1[1]+=c2[1]*s; c1[2]+=c2[2]*s; }
+/* multiply c2 by color c1 */
+#define fRGB_colormult(c, cs) { c[0]*=cs[0]; c[1]*=cs[1]; c[2]*=cs[2]; }
+/* multiply c2 by color c3 and add to c1 */
+#define fRGB_colormadd(c1, c2, c3) { c1[0]+=c2[0]*c3[0]; c1[1]+=c2[1]*c3[1]; c1[2]+=c2[2]*c3[2]; }
+/* multiply c2 by color rgb, rgb as separate arguments */
+#define fRGB_rgbmult(c, r, g, b) { c[0]*=(r); c[1]*=(g); c[2]*=(b); }
+/* swap colors c1 & c2 */
+#define fRGB_swap(c1, c2) { float _t=c1[0]; c1[0]=c2[0]; c2[0]=_t;\
+ _t=c1[1]; c1[1]=c2[1]; c2[1]=_t;\
+ _t=c1[2]; c1[2]=c2[2]; c2[2]=_t; }
+
+void qd_getPixel(CompBuf* src, int x, int y, float* col);
+void qd_setPixel(CompBuf* src, int x, int y, float* col);
+void qd_addPixel(CompBuf* src, int x, int y, float* col);
+void qd_multPixel(CompBuf* src, int x, int y, float f);
+void qd_getPixelLerpWrap(CompBuf* src, float u, float v, float* col);
+void qd_getPixelLerp(CompBuf* src, float u, float v, float* col);
+void qd_getPixelLerpChan(CompBuf* src, float u, float v, int chan, float* out);
+CompBuf* qd_downScaledCopy(CompBuf* src, int scale);
+void IIR_gauss(CompBuf* src, float sigma, int chan, int xy);
+/* end utility funcs */
+
+#endif
diff --git a/source/blender/nodes/intern/Makefile b/source/blender/nodes/intern/Makefile
new file mode 100644
index 00000000000..bae9a8dcf1d
--- /dev/null
+++ b/source/blender/nodes/intern/Makefile
@@ -0,0 +1,47 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+#
+
+LIBNAME = nodes
+DIR = $(OCGDIR)/blender/$(LIBNAME)
+
+include nan_compile.mk
+
+CFLAGS += $(LEVEL_1_C_WARNINGS)
+
+CPPFLAGS += -I../../blenkernel
+CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
+CPPFLAGS += -I../../makesdna
+CPPFLAGS += -I../../blenlib
+CPPFLAGS += -I../../include
+CPPFLAGS += -I../../imbuf
+CPPFLAGS += -I../../render/extern/include
diff --git a/source/blender/nodes/intern/SHD_nodes/Makefile b/source/blender/nodes/intern/SHD_nodes/Makefile
new file mode 100644
index 00000000000..6344af4a5cb
--- /dev/null
+++ b/source/blender/nodes/intern/SHD_nodes/Makefile
@@ -0,0 +1,47 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+#
+
+LIBNAME = nodes_shd
+DIR = $(OCGDIR)/blender/$(LIBNAME)
+
+include nan_compile.mk
+
+CFLAGS += $(LEVEL_1_C_WARNINGS)
+
+CPPFLAGS += -I../../../blenkernel
+CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
+CPPFLAGS += -I../../../makesdna
+CPPFLAGS += -I../../../blenlib
+CPPFLAGS += -I../../../include
+CPPFLAGS += -I../../../imbuf
+CPPFLAGS += -I../../../render/extern/include
diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_camera.c b/source/blender/nodes/intern/SHD_nodes/SHD_camera.c
new file mode 100644
index 00000000000..63260ff91ed
--- /dev/null
+++ b/source/blender/nodes/intern/SHD_nodes/SHD_camera.c
@@ -0,0 +1,68 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../SHD_util.h"
+
+/* **************** CAMERA INFO ******************** */
+static bNodeSocketType sh_node_camera_out[]= {
+ { SOCK_VECTOR, 0, "View Vector", 1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f}, /* None of these actually */
+ { SOCK_VALUE, 0, "View Z Depth", 0.f, 0.0f, 0.0f, 0.0f, 0.0f, 99999999999.0f}, /* have any limits on their */
+ { SOCK_VALUE, 0, "View Distance", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 99999999999.0f}, /* values. */
+ { -1, 0, "" }
+};
+
+
+static void node_shader_exec_camera(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ if(data) {
+ ShadeInput *shi= ((ShaderCallData *)data)->shi; /* Data we need for shading. */
+
+ VECCOPY(out[0]->vec, shi->co); /* get view vector */
+ out[1]->vec[0]= fabs(shi->co[2]); /* get view z-depth */
+ out[2]->vec[0]= Normalize(out[0]->vec); /* get view distance */
+ }
+ }
+
+bNodeType sh_node_camera= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ SH_NODE_CAMERA,
+ /* name */ "Camera Data",
+ /* width+range */ 95, 95, 120,
+ /* class+opts */ NODE_CLASS_INPUT, 0,
+ /* input sock */ NULL,
+ /* output sock */ sh_node_camera_out,
+ /* storage */ "node_camera",
+ /* execfunc */ node_shader_exec_camera,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+};
+
diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_curves.c b/source/blender/nodes/intern/SHD_nodes/SHD_curves.c
new file mode 100644
index 00000000000..b6f1f8d52cd
--- /dev/null
+++ b/source/blender/nodes/intern/SHD_nodes/SHD_curves.c
@@ -0,0 +1,119 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../SHD_util.h"
+
+
+/* **************** CURVE VEC ******************** */
+static bNodeSocketType sh_node_curve_vec_in[]= {
+ { SOCK_VECTOR, 1, "Vector", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static bNodeSocketType sh_node_curve_vec_out[]= {
+ { SOCK_VECTOR, 0, "Vector", 0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void node_shader_exec_curve_vec(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ float vec[3];
+
+ /* stack order input: vec */
+ /* stack order output: vec */
+ nodestack_get_vec(vec, SOCK_VECTOR, in[0]);
+ curvemapping_evaluate3F(node->storage, out[0]->vec, vec);
+}
+
+static void node_shader_init_curve_vec(bNode* node)
+{
+ node->storage= curvemapping_add(3, -1.0f, -1.0f, 1.0f, 1.0f);
+}
+
+bNodeType sh_node_curve_vec= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ SH_NODE_CURVE_VEC,
+ /* name */ "Vector Curves",
+ /* width+range */ 200, 140, 320,
+ /* class+opts */ NODE_CLASS_OP_VECTOR, NODE_OPTIONS,
+ /* input sock */ sh_node_curve_vec_in,
+ /* output sock */ sh_node_curve_vec_out,
+ /* storage */ "CurveMapping",
+ /* execfunc */ node_shader_exec_curve_vec,
+ /* butfunc */ NULL,
+ /* initfunc */ node_shader_init_curve_vec,
+ /* freestoragefunc */ node_free_curves,
+ /* copystoragefunc */ node_copy_curves,
+ /* id */ NULL
+
+};
+
+/* **************** CURVE RGB ******************** */
+static bNodeSocketType sh_node_curve_rgb_in[]= {
+ { SOCK_RGBA, 1, "Color", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static bNodeSocketType sh_node_curve_rgb_out[]= {
+ { SOCK_RGBA, 0, "Color", 0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void node_shader_exec_curve_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ float vec[3];
+
+ /* stack order input: vec */
+ /* stack order output: vec */
+ nodestack_get_vec(vec, SOCK_VECTOR, in[0]);
+ curvemapping_evaluateRGBF(node->storage, out[0]->vec, vec);
+}
+
+static void node_shader_init_curve_rgb(bNode *node)
+{
+ node->storage= curvemapping_add(4, 0.0f, 0.0f, 1.0f, 1.0f);
+}
+
+bNodeType sh_node_curve_rgb= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ SH_NODE_CURVE_RGB,
+ /* name */ "RGB Curves",
+ /* width+range */ 200, 140, 320,
+ /* class+opts */ NODE_CLASS_OP_COLOR, NODE_OPTIONS,
+ /* input sock */ sh_node_curve_rgb_in,
+ /* output sock */ sh_node_curve_rgb_out,
+ /* storage */ "CurveMapping",
+ /* execfunc */ node_shader_exec_curve_rgb,
+ /* butfunc */ NULL,
+ /* initfunc */ node_shader_init_curve_rgb,
+ /* freestoragefunc */ node_free_curves,
+ /* copystoragefunc */ node_copy_curves,
+ /* id */ NULL
+};
+
diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_dynamic.c b/source/blender/nodes/intern/SHD_nodes/SHD_dynamic.c
new file mode 100644
index 00000000000..1ba777a0533
--- /dev/null
+++ b/source/blender/nodes/intern/SHD_nodes/SHD_dynamic.c
@@ -0,0 +1,247 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2007 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Nathan Letwory
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifdef USE_PYNODES /* note: won't work without patch */
+
+#include <Python.h>
+#include <eval.h>
+
+#include "DNA_text_types.h"
+#include "BKE_text.h"
+
+#include "api2_2x/Node.h"
+#include "api2_2x/gen_utils.h"
+#include "BPY_extern.h"
+
+#include "../SHD_util.h"
+
+static PyObject *init_dynamicdict(void) {
+ PyObject *newscriptdict= PyDict_New();
+ PyDict_SetItemString(newscriptdict, "__builtins__", PyEval_GetBuiltins());
+ EXPP_dict_set_item_str(newscriptdict, "__name__", PyString_FromString("__main__"));
+ return newscriptdict;
+}
+
+static void free_dynamicdict(PyObject *dict) {
+ if(dict!=NULL) {
+ Py_DECREF(dict);
+ }
+}
+
+static void node_dynamic_init(bNode *node) {
+ NodeScriptDict *nsd= MEM_callocN(sizeof(NodeScriptDict), "node script dictionary");
+ int type= node->custom2;
+ node->custom2= 0;
+ node->storage= nsd;
+ if(type>=NODE_DYNAMIC_MENU) {
+ if(type==NODE_DYNAMIC_MENU) {
+ nodeMakeDynamicType(node);
+ node->custom1= SH_NODE_DYNAMIC_NEW;
+ } else {
+ node->custom1= SH_NODE_DYNAMIC_ADDEXIST;
+ }
+ node->id= node->typeinfo->id;
+ nodeDynamicParse(node);
+ } else {
+ if(node->custom1== SH_NODE_DYNAMIC_LOADED) {
+ nodeMakeDynamicType(node);
+ nodeDynamicParse(node);
+ } else if(node->custom1== SH_NODE_DYNAMIC_ADDEXIST)
+ nodeDynamicParse(node);
+ }
+}
+
+static void node_dynamic_free(bNode *node)
+{
+ NodeScriptDict *nsd= (NodeScriptDict *)(node->storage);
+ BPy_Node *pynode= nsd->node;
+ Py_XDECREF(pynode);
+ free_dynamicdict((PyObject *)(nsd->dict));
+ MEM_freeN(node->storage);
+}
+
+static void node_dynamic_copy(bNode *orig_node, bNode *new_node)
+{
+ NodeScriptDict *nsd= (NodeScriptDict *)(orig_node->storage);
+ new_node->storage= MEM_dupallocN(orig_node->storage);
+ if(nsd->node)
+ Py_INCREF((PyObject *)(nsd->node));
+ if(nsd->dict)
+ Py_INCREF((PyObject *)(nsd->dict));
+}
+
+static void node_dynamic_exec(void *data, bNode *node, bNodeStack **in, bNodeStack **out) {
+ BPy_Node *mynode = NULL;
+ NodeScriptDict *nsd = NULL;
+ PyObject *pyresult = NULL;
+ PyObject *args = NULL;
+ ShadeInput *shi= ((ShaderCallData *)data)->shi;
+
+ if(node->custom1==SH_NODE_DYNAMIC_NEW) {
+ nodeDynamicParse(node);
+ return;
+ }
+
+ if(node->custom2<0)
+ return;
+
+ if(node->custom1==SH_NODE_DYNAMIC_READY || node->custom1==SH_NODE_DYNAMIC_UPDATED) {
+ if(node->custom1== SH_NODE_DYNAMIC_UPDATED)
+ node->custom1= SH_NODE_DYNAMIC_READY;
+
+ nsd = (NodeScriptDict *)node->storage;
+
+ mynode = (BPy_Node *)(nsd->node);
+ if(mynode && PyCallable_Check((PyObject *)mynode)) {
+ mynode->node= node;
+ Node_SetStack(mynode, in, NODE_INPUTSTACK);
+ Node_SetStack(mynode, out, NODE_OUTPUTSTACK);
+ Node_SetShi(mynode, shi);
+ args=Py_BuildValue("()");
+ pyresult= PyObject_Call((PyObject *)mynode, args, NULL);
+ if(!pyresult) {
+ if(PyErr_Occurred()) {
+ PyErr_Print();
+ node->custom2= -1;
+ } else {
+ printf("PyObject_Call __call__ failed\n");
+ }
+ }
+ Py_XDECREF(pyresult);
+ Py_DECREF(args);
+ }
+ }
+}
+
+void nodeDynamicParse(struct bNode *node)
+{
+ BPy_Node *pynode= NULL;
+ PyObject *dict= NULL;
+ PyObject *key= NULL;
+ PyObject *value= NULL;
+ PyObject *testinst= NULL;
+ PyObject *args= NULL;
+ int pos = 0;
+ NodeScriptDict *nsd= NULL;
+ PyObject *pyresult = NULL;
+ PyObject *pycompiled = NULL;
+ Text *txt = NULL;
+ char *buf= NULL;
+
+ if(! node->id) {
+ return;
+ }
+
+ if(node->custom1!=SH_NODE_DYNAMIC_READY) {
+ txt = (Text *)node->id;
+ nsd = (NodeScriptDict *)node->storage;
+
+ if(nsd->dict==NULL && (node->custom1==SH_NODE_DYNAMIC_NEW||node->custom1==SH_NODE_DYNAMIC_LOADED)) {
+ nsd->dict= init_dynamicdict();
+ } else if(nsd->dict==NULL && node->custom1==SH_NODE_DYNAMIC_ADDEXIST) {
+ nsd->dict= node->typeinfo->pydict;
+ nsd->node= node->typeinfo->pynode;
+ Py_INCREF((PyObject *)(nsd->dict));
+ Py_INCREF((PyObject *)(nsd->node));
+ node->custom1= SH_NODE_DYNAMIC_READY;
+ return;
+ }
+ dict= (PyObject *)(nsd->dict);
+
+ if(node->custom1!=SH_NODE_DYNAMIC_ADDEXIST) {
+ buf = txt_to_buf( txt );
+ /*printf("Running script (%s, %d)...", node->name, node->custom1);*/
+ pyresult = PyRun_String(buf, Py_file_input, dict, dict);
+ /*printf(" done\n");*/
+
+ MEM_freeN(buf);
+
+ if(!pyresult) {
+ if(PyErr_Occurred()) {
+ PyErr_Print();
+ }
+ Py_XDECREF(pyresult);
+ return;
+ }
+
+ Py_DECREF(pyresult);
+
+ while(PyDict_Next( (PyObject *)(nsd->dict), &pos, &key, &value) ) {
+ if(PyObject_TypeCheck(value, &PyType_Type)==1) {
+ BPy_DefinitionMap *outputdef= Node_CreateOutputDefMap(node);
+ BPy_DefinitionMap *inputdef= Node_CreateInputDefMap(node);
+
+ args= Py_BuildValue("(OO)", inputdef, outputdef);
+ testinst= PyObject_Call(value, args, NULL);
+
+ Py_DECREF(outputdef);
+ Py_DECREF(inputdef);
+ if(testinst && PyObject_TypeCheck(testinst, &Node_Type)==1) {
+ Py_INCREF(testinst);
+ Py_INCREF(dict);
+ InitNode((BPy_Node *)(testinst), node);
+ nsd->node= testinst;
+ node->typeinfo->execfunc= node_dynamic_exec;
+ if(node->custom1== SH_NODE_DYNAMIC_NEW || node->custom1== SH_NODE_DYNAMIC_LOADED) {
+ node->typeinfo->pynode= testinst;
+ node->typeinfo->pydict= nsd->dict;
+ node->typeinfo->id= node->id;
+ nodeAddSockets(node, node->typeinfo);
+ nodeRegisterType(&node_all_shaders, node->typeinfo);
+ node->custom1= SH_NODE_DYNAMIC_READY;
+ }
+ break;
+ }
+ Py_DECREF(args);
+ }
+ }
+ }
+ }
+}
+
+
+bNodeType sh_node_dynamic = {
+ /* next, prev */ NULL, NULL,
+ /* type code */ SH_NODE_DYNAMIC,
+ /* name */ "Dynamic",
+ /* width+range */ 150, 60, 300,
+ /* class+opts */ NODE_CLASS_OP_DYNAMIC, NODE_OPTIONS,
+ /* input sock */ NULL,
+ /* output sock */ NULL,
+ /* storage */ "NodeScriptDict",
+ /* execfunc */ node_dynamic_exec,
+ /* butfunc */ NULL,
+ /* initfunc */ node_dynamic_init,
+ /* freefunc */ node_dynamic_free,
+ /* copyfunc */ node_dynamic_copy,
+ /* id */ NULL
+};
+
+#endif /* USE_PYNODES */
+
diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_geom.c b/source/blender/nodes/intern/SHD_nodes/SHD_geom.c
new file mode 100644
index 00000000000..b15aa6802f3
--- /dev/null
+++ b/source/blender/nodes/intern/SHD_nodes/SHD_geom.c
@@ -0,0 +1,144 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../SHD_util.h"
+
+
+/* **************** GEOMETRY ******************** */
+
+/* output socket type definition */
+static bNodeSocketType sh_node_geom_out[]= {
+ { SOCK_VECTOR, 0, "Global", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f}, /* btw; uses no limit */
+ { SOCK_VECTOR, 0, "Local", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
+ { SOCK_VECTOR, 0, "View", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
+ { SOCK_VECTOR, 0, "Orco", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
+ { SOCK_VECTOR, 0, "UV", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
+ { SOCK_VECTOR, 0, "Normal", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
+ { SOCK_RGBA, 0, "Vertex Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 0, "Front/Back", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+/* node execute callback */
+static void node_shader_exec_geom(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ if(data) {
+ ShadeInput *shi= ((ShaderCallData *)data)->shi;
+ NodeGeometry *ngeo= (NodeGeometry*)node->storage;
+ ShadeInputUV *suv= &shi->uv[0];
+ static float defaultvcol[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+ static float front= 0.0;
+ int i;
+
+ if(ngeo->uvname[0]) {
+ /* find uv layer by name */
+ for(i = 0; i < shi->totuv; i++) {
+ if(strcmp(shi->uv[i].name, ngeo->uvname)==0) {
+ suv= &shi->uv[i];
+ break;
+ }
+ }
+ }
+
+ /* out: global, local, view, orco, uv, normal, vertex color */
+ VECCOPY(out[GEOM_OUT_GLOB]->vec, shi->gl);
+ VECCOPY(out[GEOM_OUT_LOCAL]->vec, shi->co);
+ VECCOPY(out[GEOM_OUT_VIEW]->vec, shi->view);
+ VECCOPY(out[GEOM_OUT_ORCO]->vec, shi->lo);
+ VECCOPY(out[GEOM_OUT_UV]->vec, suv->uv);
+ VECCOPY(out[GEOM_OUT_NORMAL]->vec, shi->vno);
+
+ if (shi->totcol) {
+ /* find vertex color layer by name */
+ ShadeInputCol *scol= &shi->col[0];
+
+ if(ngeo->colname[0]) {
+ for(i = 0; i < shi->totcol; i++) {
+ if(strcmp(shi->col[i].name, ngeo->colname)==0) {
+ scol= &shi->col[i];
+ break;
+ }
+ }
+ }
+
+ VECCOPY(out[GEOM_OUT_VCOL]->vec, scol->col);
+ out[GEOM_OUT_VCOL]->vec[3]= 1.0f;
+ }
+ else
+ memcpy(out[GEOM_OUT_VCOL]->vec, defaultvcol, sizeof(defaultvcol));
+
+ if(shi->osatex) {
+ out[GEOM_OUT_GLOB]->data= shi->dxgl;
+ out[GEOM_OUT_GLOB]->datatype= NS_OSA_VECTORS;
+ out[GEOM_OUT_LOCAL]->data= shi->dxco;
+ out[GEOM_OUT_LOCAL]->datatype= NS_OSA_VECTORS;
+ out[GEOM_OUT_VIEW]->data= &shi->dxview;
+ out[GEOM_OUT_VIEW]->datatype= NS_OSA_VALUES;
+ out[GEOM_OUT_ORCO]->data= shi->dxlo;
+ out[GEOM_OUT_ORCO]->datatype= NS_OSA_VECTORS;
+ out[GEOM_OUT_UV]->data= suv->dxuv;
+ out[GEOM_OUT_UV]->datatype= NS_OSA_VECTORS;
+ out[GEOM_OUT_NORMAL]->data= shi->dxno;
+ out[GEOM_OUT_NORMAL]->datatype= NS_OSA_VECTORS;
+ }
+
+ /* front/back
+ * check the original un-flipped normals to determine front or back side */
+ if (shi->orignor[2] < FLT_EPSILON) {
+ front= 1.0f;
+ } else {
+ front = 0.0f;
+ }
+ out[GEOM_OUT_FRONTBACK]->vec[0]= front;
+ }
+}
+
+static void node_shader_init_geometry(bNode *node)
+{
+ node->storage= MEM_callocN(sizeof(NodeGeometry), "NodeGeometry");
+}
+
+/* node type definition */
+bNodeType sh_node_geom= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ SH_NODE_GEOMETRY,
+ /* name */ "Geometry",
+ /* width+range */ 120, 80, 160,
+ /* class+opts */ NODE_CLASS_INPUT, NODE_OPTIONS,
+ /* input sock */ NULL,
+ /* output sock */ sh_node_geom_out,
+ /* storage */ "NodeGeometry",
+ /* execfunc */ node_shader_exec_geom,
+ /* butfunc */ NULL,
+ /* initfunc */ node_shader_init_geometry,
+ /* freestoragefunc */ node_free_standard_storage,
+ /* copystoragefunc */ node_copy_standard_storage,
+ /* id */ NULL
+
+};
diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_hueSatVal.c b/source/blender/nodes/intern/SHD_nodes/SHD_hueSatVal.c
new file mode 100644
index 00000000000..8c07a2d1dc8
--- /dev/null
+++ b/source/blender/nodes/intern/SHD_nodes/SHD_hueSatVal.c
@@ -0,0 +1,94 @@
+/**
+ *
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Juho Vepsäläinen
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../SHD_util.h"
+
+
+/* **************** Hue Saturation ******************** */
+static bNodeSocketType sh_node_hue_sat_in[]= {
+ { SOCK_VALUE, 1, "Hue", 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 1, "Saturation", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 2.0f},
+ { SOCK_VALUE, 1, "Value", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 2.0f},
+ { SOCK_VALUE, 1, "Fac", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 1, "Color", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketType sh_node_hue_sat_out[]= {
+ { SOCK_RGBA, 0, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+/* note: it would be possible to use CMP version for both nodes */
+static void do_hue_sat_fac(bNode *node, float *out, float *hue, float *sat, float *val, float *in, float *fac)
+{
+ if(*fac!=0.0f && (*hue!=0.5f || *sat!=1.0 || *val!=1.0)) {
+ float col[3], hsv[3], mfac= 1.0f - *fac;
+
+ rgb_to_hsv(in[0], in[1], in[2], hsv, hsv+1, hsv+2);
+ hsv[0]+= (*hue - 0.5f);
+ if(hsv[0]>1.0) hsv[0]-=1.0; else if(hsv[0]<0.0) hsv[0]+= 1.0;
+ hsv[1]*= *sat;
+ if(hsv[1]>1.0) hsv[1]= 1.0; else if(hsv[1]<0.0) hsv[1]= 0.0;
+ hsv[2]*= *val;
+ if(hsv[2]>1.0) hsv[2]= 1.0; else if(hsv[2]<0.0) hsv[2]= 0.0;
+ hsv_to_rgb(hsv[0], hsv[1], hsv[2], col, col+1, col+2);
+
+ out[0]= mfac*in[0] + *fac*col[0];
+ out[1]= mfac*in[1] + *fac*col[1];
+ out[2]= mfac*in[2] + *fac*col[2];
+ }
+ else {
+ QUATCOPY(out, in);
+ }
+}
+
+static void node_shader_exec_hue_sat(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ do_hue_sat_fac(node, out[0]->vec, in[0]->vec, in[1]->vec, in[2]->vec, in[4]->vec, in[3]->vec);
+}
+
+bNodeType sh_node_hue_sat= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ SH_NODE_HUE_SAT,
+ /* name */ "Hue Saturation Value",
+ /* width+range */ 150, 80, 250,
+ /* class+opts */ NODE_CLASS_OP_COLOR, NODE_OPTIONS,
+ /* input sock */ sh_node_hue_sat_in,
+ /* output sock */ sh_node_hue_sat_out,
+ /* storage */ "",
+ /* execfunc */ node_shader_exec_hue_sat,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+
+};
+
+
diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_invert.c b/source/blender/nodes/intern/SHD_nodes/SHD_invert.c
new file mode 100644
index 00000000000..4d1ce282fce
--- /dev/null
+++ b/source/blender/nodes/intern/SHD_nodes/SHD_invert.c
@@ -0,0 +1,83 @@
+/**
+ * $Id: SHD_math.c,v 1.4 2007/04/04 13:58:12 jesterking Exp $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../SHD_util.h"
+
+
+
+/* **************** INVERT ******************** */
+static bNodeSocketType sh_node_invert_in[]= {
+ { SOCK_VALUE, 1, "Fac", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 1, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static bNodeSocketType sh_node_invert_out[]= {
+ { SOCK_RGBA, 0, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void node_shader_exec_invert(void *data, bNode *node, bNodeStack **in,
+bNodeStack **out)
+{
+ float col[3], facm;
+
+ col[0] = 1.0f - in[1]->vec[0];
+ col[1] = 1.0f - in[1]->vec[1];
+ col[2] = 1.0f - in[1]->vec[2];
+
+ /* if fac, blend result against original input */
+ if (in[0]->vec[0] < 1.0f) {
+ facm = 1.0 - in[0]->vec[0];
+
+ col[0] = in[0]->vec[0]*col[0] + (facm*in[1]->vec[0]);
+ col[1] = in[0]->vec[0]*col[1] + (facm*in[1]->vec[1]);
+ col[2] = in[0]->vec[0]*col[2] + (facm*in[1]->vec[2]);
+ }
+
+ VECCOPY(out[0]->vec, col);
+}
+
+bNodeType sh_node_invert= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ SH_NODE_INVERT,
+ /* name */ "Invert",
+ /* width+range */ 90, 80, 100,
+ /* class+opts */ NODE_CLASS_OP_COLOR, NODE_OPTIONS,
+ /* input sock */ sh_node_invert_in,
+ /* output sock */ sh_node_invert_out,
+ /* storage */ "",
+ /* execfunc */ node_shader_exec_invert,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+};
+
diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_mapping.c b/source/blender/nodes/intern/SHD_nodes/SHD_mapping.c
new file mode 100644
index 00000000000..589954c8f7b
--- /dev/null
+++ b/source/blender/nodes/intern/SHD_nodes/SHD_mapping.c
@@ -0,0 +1,89 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../SHD_util.h"
+
+/* **************** MAPPING ******************** */
+static bNodeSocketType sh_node_mapping_in[]= {
+ { SOCK_VECTOR, 1, "Vector", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static bNodeSocketType sh_node_mapping_out[]= {
+ { SOCK_VECTOR, 0, "Vector", 0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+/* do the regular mapping options for blender textures */
+static void node_shader_exec_mapping(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ TexMapping *texmap= node->storage;
+ float *vec= out[0]->vec;
+
+ /* stack order input: vector */
+ /* stack order output: vector */
+ nodestack_get_vec(vec, SOCK_VECTOR, in[0]);
+ Mat4MulVecfl(texmap->mat, vec);
+
+ if(texmap->flag & TEXMAP_CLIP_MIN) {
+ if(vec[0]<texmap->min[0]) vec[0]= texmap->min[0];
+ if(vec[1]<texmap->min[1]) vec[1]= texmap->min[1];
+ if(vec[2]<texmap->min[2]) vec[2]= texmap->min[2];
+ }
+ if(texmap->flag & TEXMAP_CLIP_MAX) {
+ if(vec[0]>texmap->max[0]) vec[0]= texmap->max[0];
+ if(vec[1]>texmap->max[1]) vec[1]= texmap->max[1];
+ if(vec[2]>texmap->max[2]) vec[2]= texmap->max[2];
+ }
+}
+
+
+static void node_shader_init_mapping(bNode *node)
+{
+ node->storage= add_mapping();
+}
+
+bNodeType sh_node_mapping= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ SH_NODE_MAPPING,
+ /* name */ "Mapping",
+ /* width+range */ 240, 160, 320,
+ /* class+opts */ NODE_CLASS_OP_VECTOR, NODE_OPTIONS,
+ /* input sock */ sh_node_mapping_in,
+ /* output sock */ sh_node_mapping_out,
+ /* storage */ "TexMapping",
+ /* execfunc */ node_shader_exec_mapping,
+ /* butfunc */ NULL,
+ /* initfunc */ node_shader_init_mapping,
+ /* freestoragefunc */ node_free_standard_storage,
+ /* copystoragefunc */ node_copy_standard_storage,
+ /* id */ NULL
+
+};
+
diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_material.c b/source/blender/nodes/intern/SHD_nodes/SHD_material.c
new file mode 100644
index 00000000000..bdceb134c0d
--- /dev/null
+++ b/source/blender/nodes/intern/SHD_nodes/SHD_material.c
@@ -0,0 +1,224 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../SHD_util.h"
+
+/* **************** MATERIAL ******************** */
+
+static bNodeSocketType sh_node_material_in[]= {
+ { SOCK_RGBA, 1, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 1, "Spec", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 1, "Refl", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VECTOR, 1, "Normal", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static bNodeSocketType sh_node_material_out[]= {
+ { SOCK_RGBA, 0, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 0, "Alpha", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_VECTOR, 0, "Normal", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+/* **************** EXTENDED MATERIAL ******************** */
+
+static bNodeSocketType sh_node_material_ext_in[]= {
+ { SOCK_RGBA, 1, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 1, "Spec", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 1, "Refl", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VECTOR, 1, "Normal", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
+ { SOCK_RGBA, 1, "Mirror", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 1, "AmbCol", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 1, "Ambient", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 1, "Emit", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 1, "SpecTra", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 1, "Ray Mirror", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 1, "Alpha", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 1, "Translucency", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static bNodeSocketType sh_node_material_ext_out[]= {
+ { SOCK_RGBA, 0, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 0, "Alpha", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_VECTOR, 0, "Normal", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
+ { SOCK_RGBA, 0, "Diffuse", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, "Spec", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 0, "AO", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void node_shader_exec_material(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ if(data && node->id) {
+ ShadeResult shrnode;
+ ShadeInput *shi;
+ ShaderCallData *shcd= data;
+ float col[4];
+
+ shi= shcd->shi;
+ shi->mat= (Material *)node->id;
+
+ /* copy all relevant material vars, note, keep this synced with render_types.h */
+ memcpy(&shi->r, &shi->mat->r, 23*sizeof(float));
+ shi->har= shi->mat->har;
+
+ /* write values */
+ if(in[MAT_IN_COLOR]->hasinput)
+ nodestack_get_vec(&shi->r, SOCK_VECTOR, in[MAT_IN_COLOR]);
+
+ if(in[MAT_IN_SPEC]->hasinput)
+ nodestack_get_vec(&shi->specr, SOCK_VECTOR, in[MAT_IN_SPEC]);
+
+ if(in[MAT_IN_REFL]->hasinput)
+ nodestack_get_vec(&shi->refl, SOCK_VALUE, in[MAT_IN_REFL]);
+
+ /* retrieve normal */
+ if(in[MAT_IN_NORMAL]->hasinput) {
+ nodestack_get_vec(shi->vn, SOCK_VECTOR, in[MAT_IN_NORMAL]);
+ Normalize(shi->vn);
+ }
+ else
+ VECCOPY(shi->vn, shi->vno);
+
+ /* custom option to flip normal */
+ if(node->custom1 & SH_NODE_MAT_NEG) {
+ shi->vn[0]= -shi->vn[0];
+ shi->vn[1]= -shi->vn[1];
+ shi->vn[2]= -shi->vn[2];
+ }
+
+ if (node->type == SH_NODE_MATERIAL_EXT) {
+ if(in[MAT_IN_MIR]->hasinput)
+ nodestack_get_vec(&shi->mirr, SOCK_VECTOR, in[MAT_IN_MIR]);
+ if(in[MAT_IN_AMBCOL]->hasinput)
+ nodestack_get_vec(&shi->ambr, SOCK_VECTOR, in[MAT_IN_AMBCOL]);
+ if(in[MAT_IN_AMB]->hasinput)
+ nodestack_get_vec(&shi->amb, SOCK_VALUE, in[MAT_IN_AMB]);
+ if(in[MAT_IN_EMIT]->hasinput)
+ nodestack_get_vec(&shi->emit, SOCK_VALUE, in[MAT_IN_EMIT]);
+ if(in[MAT_IN_SPECTRA]->hasinput)
+ nodestack_get_vec(&shi->spectra, SOCK_VALUE, in[MAT_IN_SPECTRA]);
+ if(in[MAT_IN_RAY_MIRROR]->hasinput)
+ nodestack_get_vec(&shi->ray_mirror, SOCK_VALUE, in[MAT_IN_RAY_MIRROR]);
+ if(in[MAT_IN_ALPHA]->hasinput)
+ nodestack_get_vec(&shi->alpha, SOCK_VALUE, in[MAT_IN_ALPHA]);
+ if(in[MAT_IN_TRANSLUCENCY]->hasinput)
+ nodestack_get_vec(&shi->translucency, SOCK_VALUE, in[MAT_IN_TRANSLUCENCY]);
+ }
+
+ node_shader_lamp_loop(shi, &shrnode); /* clears shrnode */
+
+ /* write to outputs */
+ if(node->custom1 & SH_NODE_MAT_DIFF) {
+ VECCOPY(col, shrnode.combined);
+ if(!(node->custom1 & SH_NODE_MAT_SPEC)) {
+ VecSubf(col, col, shrnode.spec);
+ }
+ }
+ else if(node->custom1 & SH_NODE_MAT_SPEC) {
+ VECCOPY(col, shrnode.spec);
+ }
+ else
+ col[0]= col[1]= col[2]= 0.0f;
+
+ col[3]= shrnode.alpha;
+
+ if(shi->do_preview)
+ nodeAddToPreview(node, col, shi->xs, shi->ys);
+
+ VECCOPY(out[MAT_OUT_COLOR]->vec, col);
+ out[MAT_OUT_ALPHA]->vec[0]= shrnode.alpha;
+
+ if(node->custom1 & SH_NODE_MAT_NEG) {
+ shi->vn[0]= -shi->vn[0];
+ shi->vn[1]= -shi->vn[1];
+ shi->vn[2]= -shi->vn[2];
+ }
+
+ VECCOPY(out[MAT_OUT_NORMAL]->vec, shi->vn);
+
+ /* Extended material options */
+ if (node->type == SH_NODE_MATERIAL_EXT) {
+ /* Shadow, Reflect, Refract, Radiosity, Speed seem to cause problems inside
+ * a node tree :( */
+ VECCOPY(out[MAT_OUT_DIFFUSE]->vec, shrnode.diff);
+ VECCOPY(out[MAT_OUT_SPEC]->vec, shrnode.spec);
+ VECCOPY(out[MAT_OUT_AO]->vec, shrnode.ao);
+ }
+
+ /* copy passes, now just active node */
+ if(node->flag & NODE_ACTIVE_ID)
+ *(shcd->shr)= shrnode;
+ }
+}
+
+
+static void node_shader_init_material(bNode* node)
+{
+ node->custom1= SH_NODE_MAT_DIFF|SH_NODE_MAT_SPEC;
+}
+
+
+bNodeType sh_node_material= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ SH_NODE_MATERIAL,
+ /* name */ "Material",
+ /* width+range */ 120, 80, 240,
+ /* class+opts */ NODE_CLASS_INPUT, NODE_OPTIONS|NODE_PREVIEW,
+ /* input sock */ sh_node_material_in,
+ /* output sock */ sh_node_material_out,
+ /* storage */ "",
+ /* execfunc */ node_shader_exec_material,
+ /* butfunc */ NULL,
+ /* initfunc */ node_shader_init_material,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+
+};
+
+bNodeType sh_node_material_ext= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ SH_NODE_MATERIAL_EXT,
+ /* name */ "Extended Material",
+ /* width+range */ 120, 80, 240,
+ /* class+opts */ NODE_CLASS_INPUT, NODE_OPTIONS|NODE_PREVIEW,
+ /* input sock */ sh_node_material_ext_in,
+ /* output sock */ sh_node_material_ext_out,
+ /* storage */ "",
+ /* execfunc */ node_shader_exec_material,
+ /* butfunc */ NULL,
+ /* initfunc */ node_shader_init_material,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+
+};
+
diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_math.c b/source/blender/nodes/intern/SHD_nodes/SHD_math.c
new file mode 100644
index 00000000000..95162e508d5
--- /dev/null
+++ b/source/blender/nodes/intern/SHD_nodes/SHD_math.c
@@ -0,0 +1,197 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../SHD_util.h"
+
+
+
+/* **************** SCALAR MATH ******************** */
+static bNodeSocketType sh_node_math_in[]= {
+ { SOCK_VALUE, 1, "Value", 0.5f, 0.5f, 0.5f, 1.0f, -100.0f, 100.0f},
+ { SOCK_VALUE, 1, "Value", 0.5f, 0.5f, 0.5f, 1.0f, -100.0f, 100.0f},
+ { -1, 0, "" }
+};
+
+static bNodeSocketType sh_node_math_out[]= {
+ { SOCK_VALUE, 0, "Value", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void node_shader_exec_math(void *data, bNode *node, bNodeStack **in,
+bNodeStack **out)
+{
+ switch(node->custom1){
+
+ case 0: /* Add */
+ out[0]->vec[0]= in[0]->vec[0] + in[1]->vec[0];
+ break;
+ case 1: /* Subtract */
+ out[0]->vec[0]= in[0]->vec[0] - in[1]->vec[0];
+ break;
+ case 2: /* Multiply */
+ out[0]->vec[0]= in[0]->vec[0] * in[1]->vec[0];
+ break;
+ case 3: /* Divide */
+ {
+ if(in[1]->vec[0]==0) /* We don't want to divide by zero. */
+ out[0]->vec[0]= 0.0;
+ else
+ out[0]->vec[0]= in[0]->vec[0] / in[1]->vec[0];
+ }
+ break;
+ case 4: /* Sine */
+ {
+ if(in[0]->hasinput || !in[1]->hasinput) /* This one only takes one input, so we've got to choose. */
+ out[0]->vec[0]= sin(in[0]->vec[0]);
+ else
+ out[0]->vec[0]= sin(in[1]->vec[0]);
+ }
+ break;
+ case 5: /* Cosine */
+ {
+ if(in[0]->hasinput || !in[1]->hasinput) /* This one only takes one input, so we've got to choose. */
+ out[0]->vec[0]= cos(in[0]->vec[0]);
+ else
+ out[0]->vec[0]= cos(in[1]->vec[0]);
+ }
+ break;
+ case 6: /* Tangent */
+ {
+ if(in[0]->hasinput || !in[1]->hasinput) /* This one only takes one input, so we've got to choose. */
+ out[0]->vec[0]= tan(in[0]->vec[0]);
+ else
+ out[0]->vec[0]= tan(in[1]->vec[0]);
+ }
+ break;
+ case 7: /* Arc-Sine */
+ {
+ if(in[0]->hasinput || !in[1]->hasinput) { /* This one only takes one input, so we've got to choose. */
+ /* Can't do the impossible... */
+ if( in[0]->vec[0] <= 1 && in[0]->vec[0] >= -1 )
+ out[0]->vec[0]= asin(in[0]->vec[0]);
+ else
+ out[0]->vec[0]= 0.0;
+ }
+ else {
+ /* Can't do the impossible... */
+ if( in[1]->vec[0] <= 1 && in[1]->vec[0] >= -1 )
+ out[0]->vec[0]= asin(in[1]->vec[0]);
+ else
+ out[0]->vec[0]= 0.0;
+ }
+ }
+ break;
+ case 8: /* Arc-Cosine */
+ {
+ if(in[0]->hasinput || !in[1]->hasinput) { /* This one only takes one input, so we've got to choose. */
+ /* Can't do the impossible... */
+ if( in[0]->vec[0] <= 1 && in[0]->vec[0] >= -1 )
+ out[0]->vec[0]= acos(in[0]->vec[0]);
+ else
+ out[0]->vec[0]= 0.0;
+ }
+ else {
+ /* Can't do the impossible... */
+ if( in[1]->vec[0] <= 1 && in[1]->vec[0] >= -1 )
+ out[0]->vec[0]= acos(in[1]->vec[0]);
+ else
+ out[0]->vec[0]= 0.0;
+ }
+ }
+ break;
+ case 9: /* Arc-Tangent */
+ {
+ if(in[0]->hasinput || !in[1]->hasinput) /* This one only takes one input, so we've got to choose. */
+ out[0]->vec[0]= atan(in[0]->vec[0]);
+ else
+ out[0]->vec[0]= atan(in[1]->vec[0]);
+ }
+ break;
+ case 10: /* Power */
+ {
+ /* Don't want any imaginary numbers... */
+ if( in[0]->vec[0] >= 0 )
+ out[0]->vec[0]= pow(in[0]->vec[0], in[1]->vec[0]);
+ else
+ out[0]->vec[0]= 0.0;
+ }
+ break;
+ case 11: /* Logarithm */
+ {
+ /* Don't want any imaginary numbers... */
+ if( in[0]->vec[0] > 0 && in[1]->vec[0] > 0 )
+ out[0]->vec[0]= log(in[0]->vec[0]) / log(in[1]->vec[0]);
+ else
+ out[0]->vec[0]= 0.0;
+ }
+ break;
+ case 12: /* Minimum */
+ {
+ if( in[0]->vec[0] < in[1]->vec[0] )
+ out[0]->vec[0]= in[0]->vec[0];
+ else
+ out[0]->vec[0]= in[1]->vec[0];
+ }
+ break;
+ case 13: /* Maximum */
+ {
+ if( in[0]->vec[0] > in[1]->vec[0] )
+ out[0]->vec[0]= in[0]->vec[0];
+ else
+ out[0]->vec[0]= in[1]->vec[0];
+ }
+ break;
+ case 14: /* Round */
+ {
+ if(in[0]->hasinput || !in[1]->hasinput) /* This one only takes one input, so we've got to choose. */
+ out[0]->vec[0]= (int)(in[0]->vec[0] + 0.5f);
+ else
+ out[0]->vec[0]= (int)(in[1]->vec[0] + 0.5f);
+ }
+ break;
+ }
+}
+
+bNodeType sh_node_math= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ SH_NODE_MATH,
+ /* name */ "Math",
+ /* width+range */ 120, 110, 160,
+ /* class+opts */ NODE_CLASS_CONVERTOR, NODE_OPTIONS,
+ /* input sock */ sh_node_math_in,
+ /* output sock */ sh_node_math_out,
+ /* storage */ "node_math",
+ /* execfunc */ node_shader_exec_math,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+};
+
diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_mixRgb.c b/source/blender/nodes/intern/SHD_nodes/SHD_mixRgb.c
new file mode 100644
index 00000000000..dba70253fda
--- /dev/null
+++ b/source/blender/nodes/intern/SHD_nodes/SHD_mixRgb.c
@@ -0,0 +1,79 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../SHD_util.h"
+
+
+/* **************** MIX RGB ******************** */
+static bNodeSocketType sh_node_mix_rgb_in[]= {
+ { SOCK_VALUE, 1, "Fac", 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 1, "Color1", 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 1, "Color2", 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketType sh_node_mix_rgb_out[]= {
+ { SOCK_RGBA, 0, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void node_shader_exec_mix_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order in: fac, col1, col2 */
+ /* stack order out: col */
+ float col[3];
+ float fac;
+ float vec[3];
+
+ nodestack_get_vec(&fac, SOCK_VALUE, in[0]);
+ CLAMP(fac, 0.0f, 1.0f);
+
+ nodestack_get_vec(col, SOCK_VECTOR, in[1]);
+ nodestack_get_vec(vec, SOCK_VECTOR, in[2]);
+
+ ramp_blend(node->custom1, col, col+1, col+2, fac, vec);
+ VECCOPY(out[0]->vec, col);
+}
+
+bNodeType sh_node_mix_rgb= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ SH_NODE_MIX_RGB,
+ /* name */ "Mix",
+ /* width+range */ 100, 60, 150,
+ /* class+opts */ NODE_CLASS_OP_COLOR, NODE_OPTIONS,
+ /* input sock */ sh_node_mix_rgb_in,
+ /* output sock */ sh_node_mix_rgb_out,
+ /* storage */ "",
+ /* execfunc */ node_shader_exec_mix_rgb,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+
+};
diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_normal.c b/source/blender/nodes/intern/SHD_nodes/SHD_normal.c
new file mode 100644
index 00000000000..f1ffd3446af
--- /dev/null
+++ b/source/blender/nodes/intern/SHD_nodes/SHD_normal.c
@@ -0,0 +1,76 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../SHD_util.h"
+
+/* **************** NORMAL ******************** */
+static bNodeSocketType sh_node_normal_in[]= {
+ { SOCK_VECTOR, 1, "Normal", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static bNodeSocketType sh_node_normal_out[]= {
+ { SOCK_VECTOR, 0, "Normal", 0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f},
+ { SOCK_VALUE, 0, "Dot", 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+/* generates normal, does dot product */
+static void node_shader_exec_normal(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ bNodeSocket *sock= node->outputs.first;
+ float vec[3];
+
+ /* stack order input: normal */
+ /* stack order output: normal, value */
+
+ nodestack_get_vec(vec, SOCK_VECTOR, in[0]);
+
+ VECCOPY(out[0]->vec, sock->ns.vec);
+ /* render normals point inside... the widget points outside */
+ out[1]->vec[0]= -INPR(out[0]->vec, vec);
+}
+
+bNodeType sh_node_normal= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ SH_NODE_NORMAL,
+ /* name */ "Normal",
+ /* width+range */ 100, 60, 200,
+ /* class+opts */ NODE_CLASS_OP_VECTOR, NODE_OPTIONS,
+ /* input sock */ sh_node_normal_in,
+ /* output sock */ sh_node_normal_out,
+ /* storage */ "",
+ /* execfunc */ node_shader_exec_normal,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+};
+
diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_output.c b/source/blender/nodes/intern/SHD_nodes/SHD_output.c
new file mode 100644
index 00000000000..0a9a30c452b
--- /dev/null
+++ b/source/blender/nodes/intern/SHD_nodes/SHD_output.c
@@ -0,0 +1,82 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../SHD_util.h"
+
+/* **************** OUTPUT ******************** */
+static bNodeSocketType sh_node_output_in[]= {
+ { SOCK_RGBA, 1, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 1, "Alpha", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void node_shader_exec_output(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ if(data) {
+ ShadeInput *shi= ((ShaderCallData *)data)->shi;
+ float col[4];
+
+ /* stack order input sockets: col, alpha, normal */
+ nodestack_get_vec(col, SOCK_VECTOR, in[0]);
+ nodestack_get_vec(col+3, SOCK_VALUE, in[1]);
+
+ if(shi->do_preview) {
+ nodeAddToPreview(node, col, shi->xs, shi->ys);
+ node->lasty= shi->ys;
+ }
+
+ if(node->flag & NODE_DO_OUTPUT) {
+ ShadeResult *shr= ((ShaderCallData *)data)->shr;
+
+ QUATCOPY(shr->combined, col);
+ shr->alpha= col[3];
+
+ // VECCOPY(shr->nor, in[3]->vec);
+ }
+ }
+}
+
+bNodeType sh_node_output= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ SH_NODE_OUTPUT,
+ /* name */ "Output",
+ /* width+range */ 80, 60, 200,
+ /* class+opts */ NODE_CLASS_OUTPUT, NODE_PREVIEW,
+ /* input sock */ sh_node_output_in,
+ /* output sock */ NULL,
+ /* storage */ "",
+ /* execfunc */ node_shader_exec_output,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+
+};
+
diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_rgb.c b/source/blender/nodes/intern/SHD_nodes/SHD_rgb.c
new file mode 100644
index 00000000000..4e56e26d3ad
--- /dev/null
+++ b/source/blender/nodes/intern/SHD_nodes/SHD_rgb.c
@@ -0,0 +1,61 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../SHD_util.h"
+
+/* **************** RGB ******************** */
+static bNodeSocketType sh_node_rgb_out[]= {
+ { SOCK_RGBA, 0, "Color", 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void node_shader_exec_rgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ bNodeSocket *sock= node->outputs.first;
+
+ VECCOPY(out[0]->vec, sock->ns.vec);
+}
+
+bNodeType sh_node_rgb= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ SH_NODE_RGB,
+ /* name */ "RGB",
+ /* width+range */ 100, 60, 140,
+ /* class+opts */ NODE_CLASS_INPUT, NODE_OPTIONS,
+ /* input sock */ NULL,
+ /* output sock */ sh_node_rgb_out,
+ /* storage */ "",
+ /* execfunc */ node_shader_exec_rgb,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+
+};
diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_sepcombRGB.c b/source/blender/nodes/intern/SHD_nodes/SHD_sepcombRGB.c
new file mode 100644
index 00000000000..2b52a8e2229
--- /dev/null
+++ b/source/blender/nodes/intern/SHD_nodes/SHD_sepcombRGB.c
@@ -0,0 +1,105 @@
+/**
+ *
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Juho Vepsäläinen
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../SHD_util.h"
+
+/* **************** SEPARATE RGBA ******************** */
+static bNodeSocketType sh_node_seprgb_in[]= {
+ { SOCK_RGBA, 1, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketType sh_node_seprgb_out[]= {
+ { SOCK_VALUE, 0, "R", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 0, "G", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 0, "B", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void node_shader_exec_seprgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ out[0]->vec[0] = in[0]->vec[0];
+ out[1]->vec[0] = in[0]->vec[1];
+ out[2]->vec[0] = in[0]->vec[2];
+}
+
+bNodeType sh_node_seprgb= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ SH_NODE_SEPRGB,
+ /* name */ "Separate RGB",
+ /* width+range */ 80, 40, 140,
+ /* class+opts */ NODE_CLASS_CONVERTOR, 0,
+ /* input sock */ sh_node_seprgb_in,
+ /* output sock */ sh_node_seprgb_out,
+ /* storage */ "",
+ /* execfunc */ node_shader_exec_seprgb,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+
+};
+
+
+/* **************** COMBINE RGB ******************** */
+static bNodeSocketType sh_node_combrgb_in[]= {
+ { SOCK_VALUE, 1, "R", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 1, "G", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 1, "B", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketType sh_node_combrgb_out[]= {
+ { SOCK_RGBA, 0, "Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void node_shader_exec_combrgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ out[0]->vec[0] = in[0]->vec[0];
+ out[0]->vec[1] = in[1]->vec[0];
+ out[0]->vec[2] = in[2]->vec[0];
+}
+
+bNodeType sh_node_combrgb= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ SH_NODE_COMBRGB,
+ /* name */ "Combine RGB",
+ /* width+range */ 80, 40, 140,
+ /* class+opts */ NODE_CLASS_CONVERTOR, NODE_OPTIONS,
+ /* input sock */ sh_node_combrgb_in,
+ /* output sock */ sh_node_combrgb_out,
+ /* storage */ "",
+ /* execfunc */ node_shader_exec_combrgb,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+
+};
diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_squeeze.c b/source/blender/nodes/intern/SHD_nodes/SHD_squeeze.c
new file mode 100644
index 00000000000..30abad666c4
--- /dev/null
+++ b/source/blender/nodes/intern/SHD_nodes/SHD_squeeze.c
@@ -0,0 +1,73 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../SHD_util.h"
+
+/* **************** VALUE SQUEEZE ******************** */
+static bNodeSocketType sh_node_squeeze_in[]= {
+ { SOCK_VALUE, 1, "Value", 0.0f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f},
+ { SOCK_VALUE, 1, "Width", 1.0f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f},
+ { SOCK_VALUE, 1, "Center", 0.0f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f},
+ { -1, 0, "" }
+};
+
+static bNodeSocketType sh_node_squeeze_out[]= {
+ { SOCK_VALUE, 0, "Value", 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void node_shader_exec_squeeze(void *data, bNode *node, bNodeStack **in,
+bNodeStack **out)
+{
+ float vec[3];
+
+ nodestack_get_vec(vec, SOCK_VALUE, in[0]);
+ nodestack_get_vec(vec+1, SOCK_VALUE, in[1]);
+ nodestack_get_vec(vec+2, SOCK_VALUE, in[2]);
+
+ out[0]->vec[0] = 1.0f / (1.0f + pow(2.71828183,-((vec[0]-vec[2])*vec[1]))) ;
+}
+
+bNodeType sh_node_squeeze= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ SH_NODE_SQUEEZE,
+ /* name */ "Squeeze Value",
+ /* width+range */ 120, 110, 160,
+ /* class+opts */ NODE_CLASS_CONVERTOR, NODE_OPTIONS,
+ /* input sock */ sh_node_squeeze_in,
+ /* output sock */ sh_node_squeeze_out,
+ /* storage */ "node_squeeze",
+ /* execfunc */ node_shader_exec_squeeze,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+};
+
diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_texture.c b/source/blender/nodes/intern/SHD_nodes/SHD_texture.c
new file mode 100644
index 00000000000..ace11a20d42
--- /dev/null
+++ b/source/blender/nodes/intern/SHD_nodes/SHD_texture.c
@@ -0,0 +1,130 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../SHD_util.h"
+
+/* **************** TEXTURE ******************** */
+static bNodeSocketType sh_node_texture_in[]= {
+ { SOCK_VECTOR, 1, "Vector", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f}, /* no limit */
+ { -1, 0, "" }
+};
+static bNodeSocketType sh_node_texture_out[]= {
+ { SOCK_VALUE, 0, "Value", 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_RGBA , 0, "Color", 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VECTOR, 0, "Normal", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void node_shader_exec_texture(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ if(data && node->id) {
+ ShadeInput *shi= ((ShaderCallData *)data)->shi;
+ TexResult texres;
+ float vec[3], nor[3]={0.0f, 0.0f, 0.0f};
+ int retval;
+
+ /* out: value, color, normal */
+
+ /* we should find out if a normal as output is needed, for now we do all */
+ texres.nor= nor;
+
+ if(in[0]->hasinput) {
+ nodestack_get_vec(vec, SOCK_VECTOR, in[0]);
+
+ if(in[0]->datatype==NS_OSA_VECTORS) {
+ float *fp= in[0]->data;
+ retval= multitex_ext((Tex *)node->id, vec, fp, fp+3, shi->osatex, &texres);
+ }
+ else if(in[0]->datatype==NS_OSA_VALUES) {
+ float *fp= in[0]->data;
+ float dxt[3], dyt[3];
+
+ dxt[0]= fp[0]; dxt[1]= dxt[2]= 0.0f;
+ dyt[0]= fp[1]; dyt[1]= dyt[2]= 0.0f;
+ retval= multitex_ext((Tex *)node->id, vec, dxt, dyt, shi->osatex, &texres);
+ }
+ else
+ retval= multitex_ext((Tex *)node->id, vec, NULL, NULL, 0, &texres);
+ }
+ else { /* only for previewrender, so we see stuff */
+ VECCOPY(vec, shi->lo);
+ retval= multitex_ext((Tex *)node->id, vec, NULL, NULL, 0, &texres);
+ }
+
+ /* stupid exception */
+ if( ((Tex *)node->id)->type==TEX_STUCCI) {
+ texres.tin= 0.5f + 0.7f*texres.nor[0];
+ CLAMP(texres.tin, 0.0f, 1.0f);
+ }
+
+ /* intensity and color need some handling */
+ if(texres.talpha)
+ out[0]->vec[0]= texres.ta;
+ else
+ out[0]->vec[0]= texres.tin;
+
+ if((retval & TEX_RGB)==0) {
+ out[1]->vec[0]= out[0]->vec[0];
+ out[1]->vec[1]= out[0]->vec[0];
+ out[1]->vec[2]= out[0]->vec[0];
+ out[1]->vec[3]= 1.0f;
+ }
+ else {
+ out[1]->vec[0]= texres.tr;
+ out[1]->vec[1]= texres.tg;
+ out[1]->vec[2]= texres.tb;
+ out[1]->vec[3]= 1.0f;
+ }
+
+ VECCOPY(out[2]->vec, nor);
+
+ if(shi->do_preview)
+ nodeAddToPreview(node, out[1]->vec, shi->xs, shi->ys);
+
+ }
+}
+
+bNodeType sh_node_texture= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ SH_NODE_TEXTURE,
+ /* name */ "Texture",
+ /* width+range */ 120, 80, 240,
+ /* class+opts */ NODE_CLASS_INPUT, NODE_OPTIONS|NODE_PREVIEW,
+ /* input sock */ sh_node_texture_in,
+ /* output sock */ sh_node_texture_out,
+ /* storage */ "",
+ /* execfunc */ node_shader_exec_texture,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+
+};
+
diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_valToRgb.c b/source/blender/nodes/intern/SHD_nodes/SHD_valToRgb.c
new file mode 100644
index 00000000000..cf7e33d9dca
--- /dev/null
+++ b/source/blender/nodes/intern/SHD_nodes/SHD_valToRgb.c
@@ -0,0 +1,116 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../SHD_util.h"
+
+/* **************** VALTORGB ******************** */
+static bNodeSocketType sh_node_valtorgb_in[]= {
+ { SOCK_VALUE, 1, "Fac", 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketType sh_node_valtorgb_out[]= {
+ { SOCK_RGBA, 0, "Color", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 0, "Alpha", 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void node_shader_exec_valtorgb(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order in: fac */
+ /* stack order out: col, alpha */
+
+ if(node->storage) {
+ float fac;
+ nodestack_get_vec(&fac, SOCK_VALUE, in[0]);
+
+ do_colorband(node->storage, fac, out[0]->vec);
+ out[1]->vec[0]= out[0]->vec[3];
+ }
+}
+
+static void node_shader_init_valtorgb(bNode *node)
+{
+ node->storage= add_colorband(1);
+}
+
+bNodeType sh_node_valtorgb= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ SH_NODE_VALTORGB,
+ /* name */ "ColorRamp",
+ /* width+range */ 240, 200, 300,
+ /* class+opts */ NODE_CLASS_CONVERTOR, NODE_OPTIONS,
+ /* input sock */ sh_node_valtorgb_in,
+ /* output sock */ sh_node_valtorgb_out,
+ /* storage */ "ColorBand",
+ /* execfunc */ node_shader_exec_valtorgb,
+ /* butfunc */ NULL,
+ /* initfunc */ node_shader_init_valtorgb,
+ /* freestoragefunc */ node_free_standard_storage,
+ /* copystoragefunc */ node_copy_standard_storage,
+ /* id */ NULL
+
+};
+
+/* **************** RGBTOBW ******************** */
+static bNodeSocketType sh_node_rgbtobw_in[]= {
+ { SOCK_RGBA, 1, "Color", 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketType sh_node_rgbtobw_out[]= {
+ { SOCK_VALUE, 0, "Val", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+
+static void node_shader_exec_rgbtobw(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ /* stack order out: bw */
+ /* stack order in: col */
+
+ out[0]->vec[0]= in[0]->vec[0]*0.35f + in[0]->vec[1]*0.45f + in[0]->vec[2]*0.2f;
+}
+
+bNodeType sh_node_rgbtobw= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ SH_NODE_RGBTOBW,
+ /* name */ "RGB to BW",
+ /* width+range */ 80, 40, 120,
+ /* class+opts */ NODE_CLASS_CONVERTOR, 0,
+ /* input sock */ sh_node_rgbtobw_in,
+ /* output sock */ sh_node_rgbtobw_out,
+ /* storage */ "",
+ /* execfunc */ node_shader_exec_rgbtobw,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+
+};
+
diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_value.c b/source/blender/nodes/intern/SHD_nodes/SHD_value.c
new file mode 100644
index 00000000000..57ef7226066
--- /dev/null
+++ b/source/blender/nodes/intern/SHD_nodes/SHD_value.c
@@ -0,0 +1,64 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../SHD_util.h"
+
+/* **************** VALUE ******************** */
+static bNodeSocketType sh_node_value_out[]= {
+ { SOCK_VALUE, 0, "Value", 0.5f, 0.0f, 0.0f, 0.0f, -100.0f, 100.0f},
+ { -1, 0, "" }
+};
+
+static void node_shader_exec_value(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ bNodeSocket *sock= node->outputs.first;
+
+ out[0]->vec[0]= sock->ns.vec[0];
+}
+
+
+
+bNodeType sh_node_value= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ SH_NODE_VALUE,
+ /* name */ "Value",
+ /* width+range */ 80, 50, 120,
+ /* class+opts */ NODE_CLASS_INPUT, NODE_OPTIONS,
+ /* input sock */ NULL,
+ /* output sock */ sh_node_value_out,
+ /* storage */ "",
+ /* execfunc */ node_shader_exec_value,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+
+};
+
diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_vectMath.c b/source/blender/nodes/intern/SHD_nodes/SHD_vectMath.c
new file mode 100644
index 00000000000..8d0a4b3abe3
--- /dev/null
+++ b/source/blender/nodes/intern/SHD_nodes/SHD_vectMath.c
@@ -0,0 +1,118 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+
+#include "../SHD_util.h"
+
+
+/* **************** VECTOR MATH ******************** */
+static bNodeSocketType sh_node_vect_math_in[]= {
+ { SOCK_VECTOR, 1, "Vector", 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VECTOR, 1, "Vector", 0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static bNodeSocketType sh_node_vect_math_out[]= {
+ { SOCK_VECTOR, 0, "Vector", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { SOCK_VALUE, 0, "Value", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+static void node_shader_exec_vect_math(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
+{
+ float vec1[3], vec2[3];
+
+ nodestack_get_vec(vec1, SOCK_VECTOR, in[0]);
+ nodestack_get_vec(vec2, SOCK_VECTOR, in[1]);
+
+ if(node->custom1 == 0) { /* Add */
+ out[0]->vec[0]= vec1[0] + vec2[0];
+ out[0]->vec[1]= vec1[1] + vec2[1];
+ out[0]->vec[2]= vec1[2] + vec2[2];
+
+ out[1]->vec[0]= (fabs(out[0]->vec[0]) + fabs(out[0]->vec[0]) + fabs(out[0]->vec[0])) / 3;
+ }
+ else if(node->custom1 == 1) { /* Subtract */
+ out[0]->vec[0]= vec1[0] - vec2[0];
+ out[0]->vec[1]= vec1[1] - vec2[1];
+ out[0]->vec[2]= vec1[2] - vec2[2];
+
+ out[1]->vec[0]= (fabs(out[0]->vec[0]) + fabs(out[0]->vec[0]) + fabs(out[0]->vec[0])) / 3;
+ }
+ else if(node->custom1 == 2) { /* Average */
+ out[0]->vec[0]= vec1[0] + vec2[0];
+ out[0]->vec[1]= vec1[1] + vec2[1];
+ out[0]->vec[2]= vec1[2] + vec2[2];
+
+ out[1]->vec[0] = Normalize( out[0]->vec );
+ }
+ else if(node->custom1 == 3) { /* Dot product */
+ out[1]->vec[0]= (vec1[0] * vec2[0]) + (vec1[1] * vec2[1]) + (vec1[2] * vec2[2]);
+ }
+ else if(node->custom1 == 4) { /* Cross product */
+ out[0]->vec[0]= (vec1[1] * vec2[2]) - (vec1[2] * vec2[1]);
+ out[0]->vec[1]= (vec1[2] * vec2[0]) - (vec1[0] * vec2[2]);
+ out[0]->vec[2]= (vec1[0] * vec2[1]) - (vec1[1] * vec2[0]);
+
+ out[1]->vec[0] = Normalize( out[0]->vec );
+ }
+ else if(node->custom1 == 5) { /* Normalize */
+ if(in[0]->hasinput || !in[1]->hasinput) { /* This one only takes one input, so we've got to choose. */
+ out[0]->vec[0]= vec1[0];
+ out[0]->vec[1]= vec1[1];
+ out[0]->vec[2]= vec1[2];
+ }
+ else {
+ out[0]->vec[0]= vec2[0];
+ out[0]->vec[1]= vec2[1];
+ out[0]->vec[2]= vec2[2];
+ }
+
+ out[1]->vec[0] = Normalize( out[0]->vec );
+ }
+
+}
+
+bNodeType sh_node_vect_math= {
+ /* *next,*prev */ NULL, NULL,
+ /* type code */ SH_NODE_VECT_MATH,
+ /* name */ "Vector Math",
+ /* width+range */ 80, 75, 140,
+ /* class+opts */ NODE_CLASS_CONVERTOR, NODE_OPTIONS,
+ /* input sock */ sh_node_vect_math_in,
+ /* output sock */ sh_node_vect_math_out,
+ /* storage */ "node_vect_math",
+ /* execfunc */ node_shader_exec_vect_math,
+ /* butfunc */ NULL,
+ /* initfunc */ NULL,
+ /* freestoragefunc */ NULL,
+ /* copystoragefunc */ NULL,
+ /* id */ NULL
+};
+
diff --git a/source/blender/nodes/intern/SHD_util.c b/source/blender/nodes/intern/SHD_util.c
new file mode 100644
index 00000000000..c9f58fbce49
--- /dev/null
+++ b/source/blender/nodes/intern/SHD_util.c
@@ -0,0 +1,208 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "SHD_util.h"
+
+
+
+
+
+/* ****** */
+
+void nodestack_get_vec(float *in, short type_in, bNodeStack *ns)
+{
+ float *from= ns->vec;
+
+ if(type_in==SOCK_VALUE) {
+ if(ns->sockettype==SOCK_VALUE)
+ *in= *from;
+ else
+ *in= 0.333333f*(from[0]+from[1]+from[2]);
+ }
+ else if(type_in==SOCK_VECTOR) {
+ if(ns->sockettype==SOCK_VALUE) {
+ in[0]= from[0];
+ in[1]= from[0];
+ in[2]= from[0];
+ }
+ else {
+ VECCOPY(in, from);
+ }
+ }
+ else { /* type_in==SOCK_RGBA */
+ if(ns->sockettype==SOCK_RGBA) {
+ QUATCOPY(in, from);
+ }
+ else if(ns->sockettype==SOCK_VALUE) {
+ in[0]= from[0];
+ in[1]= from[0];
+ in[2]= from[0];
+ in[3]= 1.0f;
+ }
+ else {
+ VECCOPY(in, from);
+ in[3]= 1.0f;
+ }
+ }
+}
+
+
+/* ******************* execute and parse ************ */
+
+void ntreeShaderExecTree(bNodeTree *ntree, ShadeInput *shi, ShadeResult *shr)
+{
+ ShaderCallData scd;
+
+ /* convert caller data to struct */
+ scd.shi= shi;
+ scd.shr= shr;
+ /* each material node has own local shaderesult, with optional copying */
+ memset(shr, 0, sizeof(ShadeResult));
+
+ ntreeExecTree(ntree, &scd, shi->thread); /* threads */
+
+ /* better not allow negative for now */
+ if(shr->combined[0]<0.0f) shr->combined[0]= 0.0f;
+ if(shr->combined[1]<0.0f) shr->combined[1]= 0.0f;
+ if(shr->combined[2]<0.0f) shr->combined[2]= 0.0f;
+
+}
+
+/* go over all used Geometry and Texture nodes, and return a texco flag */
+/* no group inside needed, this function is called for groups too */
+void ntreeShaderGetTexcoMode(bNodeTree *ntree, int r_mode, short *texco, int *mode)
+{
+ bNode *node;
+ bNodeSocket *sock;
+ int a;
+
+ ntreeSocketUseFlags(ntree);
+
+ for(node= ntree->nodes.first; node; node= node->next) {
+ if(node->type==SH_NODE_TEXTURE) {
+ if((r_mode & R_OSA) && node->id) {
+ Tex *tex= (Tex *)node->id;
+ if ELEM3(tex->type, TEX_IMAGE, TEX_PLUGIN, TEX_ENVMAP)
+ *texco |= TEXCO_OSA|NEED_UV;
+ }
+ /* usability exception... without input we still give the node orcos */
+ sock= node->inputs.first;
+ if(sock==NULL || sock->link==NULL)
+ *texco |= TEXCO_ORCO|NEED_UV;
+ }
+ else if(node->type==SH_NODE_GEOMETRY) {
+ /* note; sockets always exist for the given type! */
+ for(a=0, sock= node->outputs.first; sock; sock= sock->next, a++) {
+ if(sock->flag & SOCK_IN_USE) {
+ switch(a) {
+ case GEOM_OUT_GLOB:
+ *texco |= TEXCO_GLOB|NEED_UV; break;
+ case GEOM_OUT_VIEW:
+ *texco |= TEXCO_VIEW|NEED_UV; break;
+ case GEOM_OUT_ORCO:
+ *texco |= TEXCO_ORCO|NEED_UV; break;
+ case GEOM_OUT_UV:
+ *texco |= TEXCO_UV|NEED_UV; break;
+ case GEOM_OUT_NORMAL:
+ *texco |= TEXCO_NORM|NEED_UV; break;
+ case GEOM_OUT_VCOL:
+ *texco |= NEED_UV; *mode |= MA_VERTEXCOL; break;
+ }
+ }
+ }
+ }
+ }
+}
+
+/* nodes that use ID data get synced with local data */
+void nodeShaderSynchronizeID(bNode *node, int copyto)
+{
+ if(node->id==NULL) return;
+
+ if(ELEM(node->type, SH_NODE_MATERIAL, SH_NODE_MATERIAL_EXT)) {
+ bNodeSocket *sock;
+ Material *ma= (Material *)node->id;
+ int a;
+
+ /* hrmf, case in loop isnt super fast, but we dont edit 100s of material at same time either! */
+ for(a=0, sock= node->inputs.first; sock; sock= sock->next, a++) {
+ if(!(sock->flag & SOCK_HIDDEN)) {
+ if(copyto) {
+ switch(a) {
+ case MAT_IN_COLOR:
+ VECCOPY(&ma->r, sock->ns.vec); break;
+ case MAT_IN_SPEC:
+ VECCOPY(&ma->specr, sock->ns.vec); break;
+ case MAT_IN_REFL:
+ ma->ref= sock->ns.vec[0]; break;
+ case MAT_IN_MIR:
+ VECCOPY(&ma->mirr, sock->ns.vec); break;
+ case MAT_IN_AMB:
+ VECCOPY(&ma->ambr, sock->ns.vec); break;
+ case MAT_IN_EMIT:
+ ma->emit= sock->ns.vec[0]; break;
+ case MAT_IN_SPECTRA:
+ ma->spectra= sock->ns.vec[0]; break;
+ case MAT_IN_RAY_MIRROR:
+ ma->ray_mirror= sock->ns.vec[0]; break;
+ case MAT_IN_ALPHA:
+ ma->alpha= sock->ns.vec[0]; break;
+ case MAT_IN_TRANSLUCENCY:
+ ma->translucency= sock->ns.vec[0]; break;
+ }
+ }
+ else {
+ switch(a) {
+ case MAT_IN_COLOR:
+ VECCOPY(sock->ns.vec, &ma->r); break;
+ case MAT_IN_SPEC:
+ VECCOPY(sock->ns.vec, &ma->specr); break;
+ case MAT_IN_REFL:
+ sock->ns.vec[0]= ma->ref; break;
+ case MAT_IN_MIR:
+ VECCOPY(sock->ns.vec, &ma->mirr); break;
+ case MAT_IN_AMB:
+ VECCOPY(sock->ns.vec, &ma->ambr); break;
+ case MAT_IN_EMIT:
+ sock->ns.vec[0]= ma->emit; break;
+ case MAT_IN_SPECTRA:
+ sock->ns.vec[0]= ma->spectra; break;
+ case MAT_IN_RAY_MIRROR:
+ sock->ns.vec[0]= ma->ray_mirror; break;
+ case MAT_IN_ALPHA:
+ sock->ns.vec[0]= ma->alpha; break;
+ case MAT_IN_TRANSLUCENCY:
+ sock->ns.vec[0]= ma->translucency; break;
+ }
+ }
+ }
+ }
+ }
+
+}
diff --git a/source/blender/nodes/intern/SHD_util.h b/source/blender/nodes/intern/SHD_util.h
new file mode 100644
index 00000000000..f75802b7c15
--- /dev/null
+++ b/source/blender/nodes/intern/SHD_util.h
@@ -0,0 +1,140 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef SHD_NODE_UTIL_H_
+#define SHD_NODE_UTIL_H_
+
+#include <math.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_action_types.h"
+#include "DNA_color_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_ID.h"
+#include "DNA_image_types.h"
+#include "DNA_material_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BKE_blender.h"
+#include "BKE_colortools.h"
+#include "BKE_global.h"
+#include "BKE_image.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
+#include "BKE_library.h"
+
+#include "../SHD_node.h"
+#include "node_util.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+#include "BIF_interface.h"
+#include "BIF_interface_icons.h"
+#include "BIF_language.h"
+#include "BIF_mywindow.h"
+#include "BIF_previewrender.h"
+#include "BIF_resources.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+#include "BLI_rand.h"
+#include "BLI_threads.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "BSE_drawipo.h"
+#include "BSE_node.h"
+#include "BSE_view.h"
+
+#include "RE_pipeline.h"
+#include "RE_shader_ext.h"
+
+#include "butspace.h"
+#include "blendef.h"
+#include "mydevice.h"
+
+
+/* ********* exec data struct, remains internal *********** */
+
+typedef struct ShaderCallData {
+ ShadeInput *shi; /* from render pipe */
+ ShadeResult *shr; /* from render pipe */
+} ShaderCallData;
+
+/* output socket defines */
+#define GEOM_OUT_GLOB 0
+#define GEOM_OUT_LOCAL 1
+#define GEOM_OUT_VIEW 2
+#define GEOM_OUT_ORCO 3
+#define GEOM_OUT_UV 4
+#define GEOM_OUT_NORMAL 5
+#define GEOM_OUT_VCOL 6
+#define GEOM_OUT_FRONTBACK 7
+
+
+/* input socket defines */
+#define MAT_IN_COLOR 0
+#define MAT_IN_SPEC 1
+#define MAT_IN_REFL 2
+#define MAT_IN_NORMAL 3
+#define MAT_IN_MIR 4
+#define MAT_IN_AMBCOL 5
+#define MAT_IN_AMB 6
+#define MAT_IN_EMIT 7
+#define MAT_IN_SPECTRA 8
+#define MAT_IN_RAY_MIRROR 9
+#define MAT_IN_ALPHA 10
+#define MAT_IN_TRANSLUCENCY 11
+
+/* output socket defines */
+#define MAT_OUT_COLOR 0
+#define MAT_OUT_ALPHA 1
+#define MAT_OUT_NORMAL 2
+#define MAT_OUT_DIFFUSE 3
+#define MAT_OUT_SPEC 4
+#define MAT_OUT_AO 5
+
+
+extern void node_ID_title_cb(void *node_v, void *unused_v);
+void nodestack_get_vec(float *in, short type_in, bNodeStack *ns);
+
+#endif
diff --git a/source/blender/nodes/intern/node_util.c b/source/blender/nodes/intern/node_util.c
new file mode 100644
index 00000000000..4fb74911482
--- /dev/null
+++ b/source/blender/nodes/intern/node_util.c
@@ -0,0 +1,52 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2007 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Nathan Letwory.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "CMP_util.h"
+#include "SHD_util.h"
+
+void node_free_curves(bNode *node)
+{
+ curvemapping_free(node->storage);
+}
+
+void node_free_standard_storage(bNode *node)
+{
+ MEM_freeN(node->storage);
+}
+
+void node_copy_curves(bNode *orig_node, bNode *new_node)
+{
+ new_node->storage= curvemapping_copy(orig_node->storage);
+}
+
+void node_copy_standard_storage(bNode *orig_node, bNode *new_node)
+{
+ new_node->storage= MEM_dupallocN(orig_node->storage);
+}
+
diff --git a/source/blender/nodes/intern/node_util.h b/source/blender/nodes/intern/node_util.h
new file mode 100644
index 00000000000..5c8ed19a8d1
--- /dev/null
+++ b/source/blender/nodes/intern/node_util.h
@@ -0,0 +1,42 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2007 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Nathan Letwory.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef NODE_UTIL_H_
+#define NODE_UTIL_H_
+
+#include "MEM_guardedalloc.h"
+
+extern void node_free_curves(struct bNode *node);
+extern void node_free_standard_storage(struct bNode *node);
+
+extern void node_copy_curves(struct bNode *orig_node, struct bNode *new_node);
+extern void node_copy_standard_storage(struct bNode *orig_node, struct bNode *new_node);
+
+#endif
+
diff --git a/source/blender/python/BPY_extern.h b/source/blender/python/BPY_extern.h
new file mode 100644
index 00000000000..e4986727ab1
--- /dev/null
+++ b/source/blender/python/BPY_extern.h
@@ -0,0 +1,136 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code was in: source/blender/bpython/include/BPY_extern.h
+ *
+ * Contributor(s): Michel Selten, Willian P. Germano, Chris Keith
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BPY_EXTERN_H
+#define BPY_EXTERN_H
+
+extern char bprogname[]; /* holds a copy of argv[0], from creator.c */
+
+struct Text; /* defined in DNA_text_types.h */
+struct ID; /* DNA_ID.h */
+struct Object; /* DNA_object_types.h */
+struct IpoDriver; /* DNA_curve_types.h */
+struct ScriptLink; /* DNA_scriptlink_types.h */
+struct ListBase; /* DNA_listBase.h */
+struct SpaceText; /* DNA_space_types.h */
+struct SpaceScript; /* DNA_space_types.h */
+struct Script; /* BPI_script.h */
+struct ScrArea; /* DNA_screen_types.h */
+struct bScreen; /* DNA_screen_types.h */
+struct bConstraint; /* DNA_constraint_types.h */
+struct bPythonConstraint; /* DNA_constraint_types.h */
+struct bConstraintOb; /* DNA_constraint_types.h */
+struct bConstraintTarget; /* DNA_constraint_types.h*/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ /*These two next functions are important for making sure the Draw module
+ works correctly. Before calling any gui callback using the Draw module,
+ the following code must be executed:
+
+ if (some_drawspace_pylist) {
+ BPy_Set_DrawButtonsList(some_drawspace_pylist->but_refs);
+ BPy_Free_DrawButtonsList();
+ }
+ some_drawspace_pylist = PyList_New(0);
+ BPy_Set_DrawButtonsList(some_drawspace_pylist);
+
+ Also, BPy_Free_DrawButtonsList() must be called as necassary when a drawspace
+ with python callbacks is destroyed.
+
+ This is necassary to avoid blender buttons storing invalid pointers to freed
+ python data.*/
+ void BPy_Set_DrawButtonsList(void *list);
+ void BPy_Free_DrawButtonsList(void);
+
+ void BPY_pyconstraint_eval(struct bPythonConstraint *con, struct bConstraintOb *cob, struct ListBase *targets);
+ void BPY_pyconstraint_settings(void *arg1, void *arg2);
+ void BPY_pyconstraint_target(struct bPythonConstraint *con, struct bConstraintTarget *ct);
+ void BPY_pyconstraint_update(struct Object *owner, struct bConstraint *con);
+ int BPY_is_pyconstraint(struct Text *text);
+
+ void BPY_start_python( int argc, char **argv );
+ void BPY_end_python( void );
+ void BPY_post_start_python( void );
+ void init_syspath( int first_time );
+ void syspath_append( char *dir );
+
+ int BPY_Err_getLinenumber( void );
+ const char *BPY_Err_getFilename( void );
+
+ int BPY_txt_do_python_Text( struct Text *text );
+ int BPY_menu_do_python( short menutype, int event );
+ void BPY_run_python_script( char *filename );
+ void BPY_free_compiled_text( struct Text *text );
+
+ void BPY_clear_bad_scriptlinks( struct Text *byebye );
+ int BPY_has_onload_script( void );
+ void BPY_do_all_scripts( short event );
+ int BPY_check_all_scriptlinks( struct Text *text );
+ void BPY_do_pyscript( struct ID *id, short event );
+ void BPY_free_scriptlink( struct ScriptLink *slink );
+ void BPY_copy_scriptlink( struct ScriptLink *scriptlink );
+
+ int BPY_is_spacehandler(struct Text *text, char spacetype);
+ int BPY_del_spacehandler(struct Text *text, struct ScrArea *sa);
+ int BPY_add_spacehandler(struct Text *txt, struct ScrArea *sa,char spacetype);
+ int BPY_has_spacehandler(struct Text *text, struct ScrArea *sa);
+ void BPY_screen_free_spacehandlers(struct bScreen *sc);
+ int BPY_do_spacehandlers(struct ScrArea *sa, unsigned short event,
+ unsigned short space_event);
+
+ void BPY_pydriver_update(void);
+ float BPY_pydriver_eval(struct IpoDriver *driver);
+ struct Object **BPY_pydriver_get_objects(struct IpoDriver *driver);
+
+ int BPY_button_eval(char *expr, double *value);
+
+/* format importer hook */
+ int BPY_call_importloader( char *name );
+
+ void BPY_spacescript_do_pywin_draw( struct SpaceScript *sc );
+ void BPY_spacescript_do_pywin_event( struct SpaceScript *sc,
+ unsigned short event, short val, char ascii );
+ void BPY_clear_script( struct Script *script );
+ void BPY_free_finished_script( struct Script *script );
+
+/* void BPY_Err_Handle(struct Text *text); */
+/* void BPY_clear_bad_scriptlink(struct ID *id, struct Text *byebye); */
+/* void BPY_clear_bad_scriptlist(struct ListBase *, struct Text *byebye); */
+/* int BPY_spacetext_is_pywin(struct SpaceText *st); */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* BPY_EXTERN_H */
diff --git a/source/blender/python/BPY_interface.c b/source/blender/python/BPY_interface.c
new file mode 100644
index 00000000000..9c8203cf3fd
--- /dev/null
+++ b/source/blender/python/BPY_interface.c
@@ -0,0 +1,2663 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Michel Selten, Willian P. Germano, Stephen Swaney,
+ * Chris Keith, Chris Want, Ken Hughes
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#include <Python.h>
+
+#include "compile.h" /* for the PyCodeObject */
+#include "eval.h" /* for PyEval_EvalCode */
+#include "BLI_blenlib.h" /* for BLI_last_slash() */
+#include "BIF_interface.h" /* for pupmenu() */
+#include "BIF_space.h"
+#include "BIF_screen.h"
+#include "BIF_toolbox.h"
+#include "BKE_action.h" /* for get_pose_channel() */
+#include "BKE_library.h"
+#include "BKE_object.h" /* during_scriptlink() */
+#include "BKE_text.h"
+#include "BKE_constraint.h" /* for bConstraintOb */
+#include "BKE_idprop.h"
+
+#include "DNA_curve_types.h" /* for struct IpoDriver */
+#include "DNA_ID.h" /* ipo driver */
+#include "DNA_object_types.h" /* ipo driver */
+#include "DNA_constraint_types.h" /* for pyconstraint */
+
+#include "DNA_screen_types.h"
+#include "DNA_userdef_types.h" /* for U.pythondir */
+#include "MEM_guardedalloc.h"
+#include "BPY_extern.h"
+#include "BPY_menus.h"
+#include "BPI_script.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_armature.h"
+#include "api2_2x/EXPP_interface.h"
+#include "api2_2x/constant.h"
+#include "api2_2x/gen_utils.h"
+#include "api2_2x/gen_library.h" /* GetPyObjectFromID */
+#include "api2_2x/BGL.h"
+#include "api2_2x/Blender.h"
+#include "api2_2x/Camera.h"
+#include "api2_2x/Draw.h"
+#include "api2_2x/Object.h"
+#include "api2_2x/Registry.h"
+#include "api2_2x/Pose.h"
+#include "api2_2x/bpy.h" /* for the new "bpy" module */
+
+/*these next two are for pyconstraints*/
+#include "api2_2x/IDProp.h"
+#include "api2_2x/matrix.h"
+
+/* for scriptlinks */
+#include "DNA_lamp_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_world_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_material_types.h"
+
+/* bpy_registryDict is declared in api2_2x/Registry.h and defined
+ * in api2_2x/Registry.c
+ * This Python dictionary will be used to store data that scripts
+ * choose to preserve after they are executed, so user changes can be
+ * restored next time the script is used. Check the Blender.Registry module.
+ */
+/*#include "api2_2x/Registry.h" */
+
+/* for pydrivers (ipo drivers defined by one-line Python expressions) */
+PyObject *bpy_pydriver_Dict = NULL;
+
+/*
+ * set up a weakref list for Armatures
+ * creates list in __main__ module dict
+ */
+
+int setup_armature_weakrefs()
+{
+ PyObject *maindict;
+ PyObject *main_module;
+ char *list_name = ARM_WEAKREF_LIST_NAME;
+
+ main_module = PyImport_AddModule( "__main__");
+ if(main_module){
+ PyObject *weakreflink;
+ maindict= PyModule_GetDict(main_module);
+
+ /* check if there is already a dict entry for the armature weakrefs,
+ * and delete if so before making another one */
+
+ weakreflink= PyDict_GetItemString(maindict,list_name);
+ if( weakreflink != NULL ) {
+ PyDict_DelItemString(maindict,list_name);
+ Py_XDECREF( weakreflink );
+ }
+
+ if (PyDict_SetItemString(maindict,
+ list_name,
+ PyList_New(0)) == -1){
+ printf("Oops - setup_armature_weakrefs()\n");
+
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/* Declares the modules and their initialization functions
+ * These are TOP-LEVEL modules e.g. import `module` - there is no
+ * support for packages here e.g. import `package.module` */
+
+static struct _inittab BPy_Inittab_Modules[] = {
+ {"Blender", M_Blender_Init},
+ {"bpy", m_bpy_init},
+ {NULL, NULL}
+};
+
+/*************************************************************************
+* Structure definitions
+**************************************************************************/
+#define FILENAME_LENGTH 24
+
+typedef struct _ScriptError {
+ char filename[FILENAME_LENGTH];
+ int lineno;
+} ScriptError;
+
+/****************************************************************************
+* Global variables
+****************************************************************************/
+ScriptError g_script_error;
+
+/***************************************************************************
+* Function prototypes
+***************************************************************************/
+PyObject *RunPython( Text * text, PyObject * globaldict );
+char *GetName( Text * text );
+PyObject *CreateGlobalDictionary( void );
+void ReleaseGlobalDictionary( PyObject * dict );
+void DoAllScriptsFromList( ListBase * list, short event );
+PyObject *importText( char *name );
+void init_ourImport( void );
+void init_ourReload( void );
+PyObject *blender_import( PyObject * self, PyObject * args );
+PyObject *RunPython2( Text * text, PyObject * globaldict, PyObject *localdict );
+
+
+void BPY_Err_Handle( char *script_name );
+PyObject *traceback_getFilename( PyObject * tb );
+
+/****************************************************************************
+* Description: This function will start the interpreter and load all modules
+* as well as search for a python installation.
+****************************************************************************/
+void BPY_start_python( int argc, char **argv )
+{
+ static int argc_copy = 0;
+ static char **argv_copy = NULL;
+ int first_time = argc;
+
+ /* we keep a copy of the values of argc and argv so that the game engine
+ * can call BPY_start_python(0, NULL) whenever a game ends, without having
+ * to know argc and argv there (in source/blender/src/space.c) */
+ if( first_time ) {
+ argc_copy = argc;
+ argv_copy = argv;
+ }
+
+ //stuff for Registry module
+ bpy_registryDict = PyDict_New( );/* check comment at start of this file */
+ if( !bpy_registryDict )
+ printf( "Error: Couldn't create the Registry Python Dictionary!" );
+ Py_SetProgramName( "blender" );
+
+ /* Py_Initialize() will attempt to import the site module and
+ * print an error if not found. See init_syspath() for the
+ * rest of our init msgs.
+ */
+
+ /* print Python version
+ * Py_GetVersion() returns a ptr to a static string "9.9.9 (aaaa..."
+ */
+ {
+ int count = 3; /* a nice default for major.minor. example 2.5 */
+ const char *version = Py_GetVersion();
+ /* we know a blank is there somewhere! */
+ char *blank_ptr = strchr( version, ' ');
+ if(blank_ptr)
+ count = blank_ptr - version;
+
+ printf( "Compiled with Python version %.*s.\n", count, version );
+ }
+
+
+ //Initialize the TOP-LEVEL modules
+ PyImport_ExtendInittab(BPy_Inittab_Modules);
+
+ //Start the interpreter
+ Py_Initialize( );
+ PySys_SetArgv( argc_copy, argv_copy );
+
+ //Overrides __import__
+ init_ourImport( );
+ init_ourReload( );
+
+ //init a global dictionary
+ g_blenderdict = NULL;
+
+ //Look for a python installation
+ init_syspath( first_time ); /* not first_time: some msgs are suppressed */
+
+ return;
+}
+
+/*****************************************************************************/
+/* Description: This function will terminate the Python interpreter */
+/*****************************************************************************/
+void BPY_end_python( void )
+{
+ Script *script = NULL;
+
+ if( bpy_registryDict ) {
+ Py_DECREF( bpy_registryDict );
+ bpy_registryDict = NULL;
+ }
+
+ if( bpy_pydriver_Dict ) {
+ Py_DECREF( bpy_pydriver_Dict );
+ bpy_pydriver_Dict = NULL;
+ }
+
+ /* Freeing all scripts here prevents problems with the order in which
+ * Python is finalized and G.main is freed in exit_usiblender() */
+ for (script = G.main->script.first; script; script = script->id.next) {
+ BPY_clear_script(script);
+ free_libblock( &G.main->script, script );
+ }
+
+ Py_Finalize( );
+
+ BPyMenu_RemoveAllEntries( ); /* freeing bpymenu mem */
+
+ /* a script might've opened a .blend file but didn't close it, so: */
+ EXPP_Library_Close( );
+
+ return;
+}
+
+void syspath_append( char *dirname )
+{
+ PyObject *mod_sys= NULL, *dict= NULL, *path= NULL, *dir= NULL;
+ short ok=1;
+ PyErr_Clear( );
+
+ dir = Py_BuildValue( "s", dirname );
+
+ mod_sys = PyImport_ImportModule( "sys" ); /* new ref */
+
+ if (mod_sys) {
+ dict = PyModule_GetDict( mod_sys ); /* borrowed ref */
+ path = PyDict_GetItemString( dict, "path" ); /* borrowed ref */
+ if ( !PyList_Check( path ) ) {
+ ok = 0;
+ }
+ } else {
+ /* cant get the sys module */
+ ok = 0;
+ }
+
+ if (ok && PyList_Append( path, dir ) != 0)
+ ok = 0; /* append failed */
+
+ if( (ok==0) || PyErr_Occurred( ) )
+ Py_FatalError( "could import or build sys.path, can't continue" );
+
+ Py_XDECREF( mod_sys );
+}
+
+void init_syspath( int first_time )
+{
+ PyObject *path;
+ PyObject *mod, *d;
+ char *progname;
+ char execdir[FILE_MAXDIR]; /*defines from DNA_space_types.h */
+
+ int n;
+
+ path = Py_BuildValue( "s", bprogname );
+
+ mod = PyImport_ImportModule( "Blender.sys" );
+
+ if( mod ) {
+ d = PyModule_GetDict( mod );
+ EXPP_dict_set_item_str( d, "progname", path );
+ Py_DECREF( mod );
+ } else
+ printf( "Warning: could not set Blender.sys.progname\n" );
+
+ progname = BLI_last_slash( bprogname ); /* looks for the last dir separator */
+
+ n = progname - bprogname;
+ if( n > 0 ) {
+ strncpy( execdir, bprogname, n );
+ if( execdir[n - 1] == '.' )
+ n--; /*fix for when run as ./blender */
+ execdir[n] = '\0';
+
+ syspath_append( execdir ); /* append to module search path */
+ } else
+ printf( "Warning: could not determine argv[0] path\n" );
+
+ /*
+ attempt to import 'site' module as a check for valid
+ python install found.
+ */
+
+ printf("Checking for installed Python... "); /* appears after msg "Compiled with Python 2.x" */
+ mod = PyImport_ImportModule( "site" ); /* new ref */
+
+ if( mod ) {
+ printf("got it!\n");
+ Py_DECREF( mod );
+ } else { /* import 'site' failed */
+ PyErr_Clear( );
+ if( first_time ) {
+ printf( "No installed Python found.\n" );
+ printf( "Only built-in modules are available. Some scripts may not run.\n" );
+ printf( "Continuing happily.\n" );
+ }
+ }
+
+
+ /*
+ * initialize the sys module
+ * set sys.executable to the Blender exe
+ */
+
+ mod = PyImport_ImportModule( "sys" ); /* new ref */
+
+ if( mod ) {
+ d = PyModule_GetDict( mod ); /* borrowed ref */
+ EXPP_dict_set_item_str( d, "executable",
+ Py_BuildValue( "s", bprogname ) );
+ Py_DECREF( mod );
+ } else{
+ printf("import of sys module failed\n");
+ }
+}
+
+/****************************************************************************
+* Description: This function finishes Python initialization in Blender.
+
+Because U.pythondir (user defined dir for scripts) isn't
+initialized when BPY_start_Python needs to be executed, we
+postpone adding U.pythondir to sys.path and also BPyMenus
+(mechanism to register scripts in Blender menus) for when
+that dir info is available.
+****************************************************************************/
+void BPY_post_start_python( void )
+{
+ char dirpath[FILE_MAX];
+ char *sdir = NULL;
+
+ if(U.pythondir[0] != '\0' ) {
+ char modpath[FILE_MAX];
+ int upyslen = strlen(U.pythondir);
+
+ /* check if user pydir ends with a slash and, if so, remove the slash
+ * (for eventual implementations of c library's stat function that might
+ * not like it) */
+ if (upyslen > 2) { /* avoids doing anything if dir == '//' */
+ char ending = U.pythondir[upyslen - 1];
+
+ if (ending == '/' || ending == '\\')
+ U.pythondir[upyslen - 1] = '\0';
+ }
+
+ BLI_strncpy(dirpath, U.pythondir, FILE_MAX);
+ BLI_convertstringcode(dirpath, G.sce, 0);
+ syspath_append(dirpath); /* append to module search path */
+
+ BLI_make_file_string("/", modpath, dirpath, "bpymodules");
+ if (BLI_exists(modpath)) syspath_append(modpath);
+ }
+
+ sdir = bpy_gethome(1);
+ if (sdir) {
+
+ syspath_append(sdir);
+
+ BLI_make_file_string("/", dirpath, sdir, "bpymodules");
+ if (BLI_exists(dirpath)) syspath_append(dirpath);
+ }
+
+ BPyMenu_Init( 0 ); /* get dynamic menus (registered scripts) data */
+
+ return;
+}
+
+/****************************************************************************
+* Description: This function will return the linenumber on which an error
+* has occurred in the Python script.
+****************************************************************************/
+int BPY_Err_getLinenumber( void )
+{
+ return g_script_error.lineno;
+}
+
+/*****************************************************************************/
+/* Description: This function will return the filename of the python script. */
+/*****************************************************************************/
+const char *BPY_Err_getFilename( void )
+{
+ return g_script_error.filename;
+}
+
+/*****************************************************************************/
+/* Description: Return PyString filename from a traceback object */
+/*****************************************************************************/
+PyObject *traceback_getFilename( PyObject * tb )
+{
+ PyObject *v = NULL;
+
+/* co_filename is in f_code, which is in tb_frame, which is in tb */
+
+ v = PyObject_GetAttrString( tb, "tb_frame" );
+ if (v) {
+ Py_DECREF( v );
+ v = PyObject_GetAttrString( v, "f_code" );
+ if (v) {
+ Py_DECREF( v );
+ v = PyObject_GetAttrString( v, "co_filename" );
+ }
+ }
+
+ if (v) return v;
+ else return PyString_FromString("unknown");
+}
+
+/****************************************************************************
+* Description: Blender Python error handler. This catches the error and
+* stores filename and line number in a global
+*****************************************************************************/
+void BPY_Err_Handle( char *script_name )
+{
+ PyObject *exception, *err, *tb, *v;
+
+ if( !script_name ) {
+ printf( "Error: script has NULL name\n" );
+ return;
+ }
+
+ PyErr_Fetch( &exception, &err, &tb );
+
+ if (!script_name) script_name = "untitled";
+ //if( !exception && !tb ) {
+ // printf( "FATAL: spurious exception\n" );
+ // return;
+ //}
+
+ strcpy( g_script_error.filename, script_name );
+
+ if( exception
+ && PyErr_GivenExceptionMatches( exception, PyExc_SyntaxError ) ) {
+ /* no traceback available when SyntaxError */
+ PyErr_Restore( exception, err, tb ); /* takes away reference! */
+ PyErr_Print( );
+ v = PyObject_GetAttrString( err, "lineno" );
+ if( v ) {
+ g_script_error.lineno = PyInt_AsLong( v );
+ Py_DECREF( v );
+ } else {
+ g_script_error.lineno = -1;
+ }
+ /* this avoids an abort in Python 2.3's garbage collecting: */
+ PyErr_Clear( );
+ return;
+ } else {
+ PyErr_NormalizeException( &exception, &err, &tb );
+ PyErr_Restore( exception, err, tb ); /* takes away reference! */
+ PyErr_Print( );
+ tb = PySys_GetObject( "last_traceback" );
+
+ if( !tb ) {
+ printf( "\nCan't get traceback\n" );
+ return;
+ }
+
+ Py_INCREF( tb );
+
+/* From old bpython BPY_main.c:
+ * 'check traceback objects and look for last traceback in the
+ * same text file. This is used to jump to the line of where the
+ * error occured. "If the error occured in another text file or module,
+ * the last frame in the current file is adressed."'
+ */
+
+ for(;;) {
+ v = PyObject_GetAttrString( tb, "tb_next" );
+
+ if( !v || v == Py_None ||
+ strcmp(PyString_AsString(traceback_getFilename(v)), script_name)) {
+ break;
+ }
+
+ Py_DECREF( tb );
+ tb = v;
+ }
+
+ v = PyObject_GetAttrString( tb, "tb_lineno" );
+ if (v) {
+ g_script_error.lineno = PyInt_AsLong(v);
+ Py_DECREF(v);
+ }
+ v = traceback_getFilename( tb );
+ if (v) {
+ strncpy( g_script_error.filename, PyString_AsString( v ),
+ FILENAME_LENGTH );
+ Py_DECREF(v);
+ }
+ Py_DECREF( tb );
+ }
+
+ return;
+}
+
+/****************************************************************************
+* Description: This function executes the script passed by st.
+* Notes: It is called by blender/src/drawtext.c when a Blender user
+* presses ALT+PKEY in the script's text window.
+*****************************************************************************/
+int BPY_txt_do_python_Text( struct Text *text )
+{
+ PyObject *py_dict, *py_result;
+ BPy_constant *info;
+ char textname[24];
+ Script *script = G.main->script.first;
+
+ if( !text )
+ return 0;
+
+ /* check if this text is already running */
+ while( script ) {
+ if( !strcmp( script->id.name + 2, text->id.name + 2 ) ) {
+ /* if this text is already a running script,
+ * just move to it: */
+ SpaceScript *sc;
+ newspace( curarea, SPACE_SCRIPT );
+ sc = curarea->spacedata.first;
+ sc->script = script;
+ return 1;
+ }
+ script = script->id.next;
+ }
+
+ /* Create a new script structure and initialize it: */
+ script = alloc_libblock( &G.main->script, ID_SCRIPT, GetName( text ) );
+
+ if( !script ) {
+ printf( "couldn't allocate memory for Script struct!" );
+ return 0;
+ }
+
+ /* if in the script Blender.Load(blendfile) is not the last command,
+ * an error after it will call BPY_Err_Handle below, but the text struct
+ * will have been deallocated already, so we need to copy its name here.
+ */
+ BLI_strncpy( textname, GetName( text ),
+ strlen( GetName( text ) ) + 1 );
+
+ script->id.us = 1;
+ script->flags = SCRIPT_RUNNING;
+ script->py_draw = NULL;
+ script->py_event = NULL;
+ script->py_button = NULL;
+ script->py_browsercallback = NULL;
+
+ py_dict = CreateGlobalDictionary( );
+
+ if( !setup_armature_weakrefs()){
+ printf("Oops - weakref dict\n");
+ return 0;
+ }
+
+ script->py_globaldict = py_dict;
+
+ info = ( BPy_constant * ) PyConstant_New( );
+ if( info ) {
+ PyConstant_Insert( info, "name",
+ PyString_FromString( script->id.name + 2 ) );
+ Py_INCREF( Py_None );
+ PyConstant_Insert( info, "arg", Py_None );
+ EXPP_dict_set_item_str( py_dict, "__script__",
+ ( PyObject * ) info );
+ }
+
+ py_result = RunPython( text, py_dict ); /* Run the script */
+
+ if( !py_result ) { /* Failed execution of the script */
+
+ BPY_Err_Handle( textname );
+ ReleaseGlobalDictionary( py_dict );
+ script->py_globaldict = NULL;
+ if( G.main->script.first )
+ free_libblock( &G.main->script, script );
+
+ return 0;
+ } else {
+ Py_DECREF( py_result );
+ script->flags &= ~SCRIPT_RUNNING;
+ if( !script->flags ) {
+ ReleaseGlobalDictionary( py_dict );
+ script->py_globaldict = NULL;
+ free_libblock( &G.main->script, script );
+ }
+ }
+
+ return 1; /* normal return */
+}
+
+/****************************************************************************
+* Description: Called from command line to run a Python script
+* automatically. The script can be a file or a Blender Text in the current
+* .blend.
+****************************************************************************/
+void BPY_run_python_script( char *fn )
+{
+ Text *text = NULL;
+ int is_blender_text = 0;
+
+ if (!BLI_exists(fn)) { /* if there's no such filename ... */
+ text = G.main->text.first; /* try an already existing Blender Text */
+
+ while (text) {
+ if (!strcmp(fn, text->id.name + 2)) break;
+ text = text->id.next;
+ }
+
+ if (text == NULL) {
+ printf("\nError: no such file or Blender text -- %s.\n", fn);
+ return;
+ }
+ else is_blender_text = 1; /* fn is already a Blender Text */
+ }
+
+ else {
+ text = add_text(fn);
+
+ if (text == NULL) {
+ printf("\nError in BPY_run_python_script:\n"
+ "couldn't create Blender text from %s\n", fn);
+ /* Chris: On Windows if I continue I just get a segmentation
+ * violation. To get a baseline file I exit here. */
+ exit(2);
+ /* return; */
+ }
+ }
+
+ if (BPY_txt_do_python_Text(text) != 1) {
+ printf("\nError executing Python script from command-line:\n"
+ "%s (at line %d).\n", fn, BPY_Err_getLinenumber());
+ }
+
+ if (!is_blender_text) {
+ /* We can't simply free the text, since the script might have called
+ * Blender.Load() to load a new .blend, freeing previous data.
+ * So we check if the pointer is still valid. */
+ Text *txtptr = G.main->text.first;
+ while (txtptr) {
+ if (txtptr == text) {
+ free_libblock(&G.main->text, text);
+ break;
+ }
+ txtptr = txtptr->id.next;
+ }
+ }
+}
+
+/****************************************************************************
+* Description: This function executes the script chosen from a menu.
+* Notes: It is called by the ui code in src/header_???.c when a user
+* clicks on a menu entry that refers to a script.
+* Scripts are searched in the BPyMenuTable, using the given
+* menutype and event values to know which one was chosen.
+*****************************************************************************/
+int BPY_menu_do_python( short menutype, int event )
+{
+ PyObject *py_dict, *py_res, *pyarg = NULL;
+ BPy_constant *info;
+ BPyMenu *pym;
+ BPySubMenu *pysm;
+ FILE *fp = NULL;
+ char *buffer, *s;
+ char filestr[FILE_MAXDIR + FILE_MAXFILE];
+ char scriptname[21];
+ Script *script = NULL;
+ int len;
+
+ pym = BPyMenu_GetEntry( menutype, ( short ) event );
+
+ if( !pym )
+ return 0;
+
+ if( pym->version > G.version )
+ notice( "Version mismatch: script was written for Blender %d. "
+ "It may fail with yours: %d.", pym->version,
+ G.version );
+
+/* if there are submenus, let the user choose one from a pupmenu that we
+ * create here.*/
+ pysm = pym->submenus;
+ if( pysm ) {
+ char *pupstr;
+ int arg;
+
+ pupstr = BPyMenu_CreatePupmenuStr( pym, menutype );
+
+ if( pupstr ) {
+ arg = pupmenu( pupstr );
+ MEM_freeN( pupstr );
+
+ if( arg >= 0 ) {
+ while( arg-- )
+ pysm = pysm->next;
+ pyarg = PyString_FromString( pysm->arg );
+ } else
+ return 0;
+ }
+ }
+
+ if( !pyarg ) { /* no submenus */
+ Py_INCREF( Py_None );
+ pyarg = Py_None;
+ }
+
+ if( pym->dir ) { /* script is in U.pythondir */
+ char upythondir[FILE_MAXDIR];
+
+ /* dirs in Blender can be "//", which has a special meaning */
+ BLI_strncpy(upythondir, U.pythondir, FILE_MAXDIR);
+ BLI_convertstringcode(upythondir, G.sce, 0); /* if so, this expands it */
+ BLI_make_file_string( "/", filestr, upythondir, pym->filename );
+ }
+ else { /* script is in default scripts dir */
+ char *scriptsdir = bpy_gethome(1);
+
+ if (!scriptsdir) {
+ printf("Error loading script: can't find default scripts dir!");
+ return 0;
+ }
+
+ BLI_make_file_string( "/", filestr, scriptsdir, pym->filename );
+ }
+
+ fp = fopen( filestr, "rb" );
+ if( !fp ) {
+ printf( "Error loading script: couldn't open file %s\n",
+ filestr );
+ return 0;
+ }
+
+ BLI_strncpy(scriptname, pym->name, 21);
+ len = strlen(scriptname) - 1;
+ /* by convention, scripts that open the file browser or have submenus
+ * display '...'. Here we remove them from the datablock name */
+ while ((len > 0) && scriptname[len] == '.') {
+ scriptname[len] = '\0';
+ len--;
+ }
+
+ /* Create a new script structure and initialize it: */
+ script = alloc_libblock( &G.main->script, ID_SCRIPT, scriptname );
+
+ if( !script ) {
+ printf( "couldn't allocate memory for Script struct!" );
+ fclose( fp );
+ return 0;
+ }
+
+ /* let's find a proper area for an eventual script gui:
+ * (still experimenting here, need definition on which win
+ * each group will be put to code this properly) */
+ switch ( menutype ) {
+
+ case PYMENU_IMPORT: /* first 4 were handled in header_info.c */
+ case PYMENU_EXPORT:
+ case PYMENU_HELP:
+ case PYMENU_RENDER:
+ case PYMENU_WIZARDS:
+ case PYMENU_SCRIPTTEMPLATE:
+ case PYMENU_MESHFACEKEY:
+ break;
+
+ default:
+ if( curarea->spacetype != SPACE_SCRIPT ) {
+ ScrArea *sa = NULL;
+
+ sa = find_biggest_area_of_type( SPACE_BUTS );
+ if( sa ) {
+ if( ( 1.5 * sa->winx ) < sa->winy )
+ sa = NULL; /* too narrow? */
+ }
+
+ if( !sa )
+ sa = find_biggest_area_of_type( SPACE_SCRIPT );
+ if( !sa )
+ sa = find_biggest_area_of_type( SPACE_TEXT );
+ if( !sa )
+ sa = find_biggest_area_of_type( SPACE_IMAGE ); /* group UV */
+ if( !sa )
+ sa = find_biggest_area_of_type( SPACE_VIEW3D );
+
+ if( !sa )
+ sa = find_biggest_area( );
+
+ areawinset( sa->win );
+ }
+ break;
+ }
+
+ script->id.us = 1;
+ script->flags = SCRIPT_RUNNING;
+ script->py_draw = NULL;
+ script->py_event = NULL;
+ script->py_button = NULL;
+ script->py_browsercallback = NULL;
+
+ py_dict = CreateGlobalDictionary( );
+
+ script->py_globaldict = py_dict;
+
+ info = ( BPy_constant * ) PyConstant_New( );
+ if( info ) {
+ PyConstant_Insert( info, "name",
+ PyString_FromString( script->id.name + 2 ) );
+ PyConstant_Insert( info, "arg", pyarg );
+ EXPP_dict_set_item_str( py_dict, "__script__",
+ ( PyObject * ) info );
+ }
+
+ /* Previously we used PyRun_File to run directly the code on a FILE
+ * object, but as written in the Python/C API Ref Manual, chapter 2,
+ * 'FILE structs for different C libraries can be different and
+ * incompatible'.
+ * So now we load the script file data to a buffer */
+
+ fseek( fp, 0L, SEEK_END );
+ len = ftell( fp );
+ fseek( fp, 0L, SEEK_SET );
+
+ buffer = MEM_mallocN( len + 2, "pyfilebuf" ); /* len+2 to add '\n\0' */
+ len = fread( buffer, 1, len, fp );
+
+ buffer[len] = '\n'; /* fix syntax error in files w/o eol */
+ buffer[len + 1] = '\0';
+
+ /* fast clean-up of dos cr/lf line endings: change '\r' to space */
+
+ /* we also have to check for line splitters: '\\' */
+ /* to avoid possible syntax errors on dos files on win */
+ /**/
+ /* but first make sure we won't disturb memory below &buffer[0]: */
+ if( *buffer == '\r' )
+ *buffer = ' ';
+
+ /* now handle the whole buffer */
+ for( s = buffer + 1; *s != '\0'; s++ ) {
+ if( *s == '\r' ) {
+ if( *( s - 1 ) == '\\' ) { /* special case: long lines split with '\': */
+ *( s - 1 ) = ' '; /* we write ' \', because '\ ' is a syntax error */
+ *s = '\\';
+ } else
+ *s = ' '; /* not a split line, just replace '\r' with ' ' */
+ }
+ }
+
+ fclose( fp );
+
+
+ if( !setup_armature_weakrefs()){
+ printf("Oops - weakref dict\n");
+ MEM_freeN( buffer );
+ return 0;
+ }
+
+ /* run the string buffer */
+
+ py_res = PyRun_String( buffer, Py_file_input, py_dict, py_dict );
+
+ MEM_freeN( buffer );
+
+ if( !py_res ) { /* Failed execution of the script */
+
+ BPY_Err_Handle( script->id.name + 2 );
+ ReleaseGlobalDictionary( py_dict );
+ script->py_globaldict = NULL;
+ if( G.main->script.first )
+ free_libblock( &G.main->script, script );
+ error( "Python script error: check console" );
+
+ return 0;
+ } else {
+ Py_DECREF( py_res );
+ script->flags &= ~SCRIPT_RUNNING;
+
+ if( !script->flags ) {
+ ReleaseGlobalDictionary( py_dict );
+ script->py_globaldict = NULL;
+ free_libblock( &G.main->script, script );
+
+ /* special case: called from the menu in the Scripts window
+ * we have to change sc->script pointer, since it'll be freed here.*/
+ if( curarea->spacetype == SPACE_SCRIPT ) {
+ SpaceScript *sc = curarea->spacedata.first;
+ sc->script = G.main->script.first; /* can be null, which is ok ... */
+ /* ... meaning no other script is running right now. */
+ }
+
+ }
+ }
+
+ return 1; /* normal return */
+}
+
+/*****************************************************************************
+* Description:
+* Notes:
+*****************************************************************************/
+void BPY_free_compiled_text( struct Text *text )
+{
+ if( !text->compiled )
+ return;
+ Py_DECREF( ( PyObject * ) text->compiled );
+ text->compiled = NULL;
+
+ return;
+}
+
+/*****************************************************************************
+* Description: This function frees a finished (flags == 0) script.
+*****************************************************************************/
+void BPY_free_finished_script( Script * script )
+{
+ if( !script )
+ return;
+
+ if( PyErr_Occurred( ) ) { /* if script ended after filesel */
+ PyErr_Print( ); /* eventual errors are handled now */
+ error( "Python script error: check console" );
+ }
+
+ free_libblock( &G.main->script, script );
+ return;
+}
+
+static void unlink_script( Script * script )
+{ /* copied from unlink_text in drawtext.c */
+ bScreen *scr;
+ ScrArea *area;
+ SpaceLink *sl;
+
+ for( scr = G.main->screen.first; scr; scr = scr->id.next ) {
+ for( area = scr->areabase.first; area; area = area->next ) {
+ for( sl = area->spacedata.first; sl; sl = sl->next ) {
+ if( sl->spacetype == SPACE_SCRIPT ) {
+ SpaceScript *sc = ( SpaceScript * ) sl;
+
+ if( sc->script == script ) {
+ sc->script = NULL;
+
+ if( sc ==
+ area->spacedata.first ) {
+ scrarea_queue_redraw
+ ( area );
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void BPY_clear_script( Script * script )
+{
+ PyObject *dict;
+
+ if( !script )
+ return;
+
+ if (!Py_IsInitialized()) {
+ printf("\nError: trying to free script data after finalizing Python!");
+ printf("\nScript name: %s\n", script->id.name+2);
+ return;
+ }
+
+ Py_XDECREF( ( PyObject * ) script->py_draw );
+ Py_XDECREF( ( PyObject * ) script->py_event );
+ Py_XDECREF( ( PyObject * ) script->py_button );
+ Py_XDECREF( ( PyObject * ) script->py_browsercallback );
+ script->py_draw = NULL;
+ script->py_event = NULL;
+ script->py_button = NULL;
+ script->py_browsercallback = NULL;
+
+ dict = script->py_globaldict;
+
+ if( dict ) {
+ PyDict_Clear( dict );
+ Py_DECREF( dict ); /* Release dictionary. */
+ script->py_globaldict = NULL;
+ }
+
+ unlink_script( script );
+}
+
+/* PyDrivers */
+
+/* PyDrivers are Ipo Drivers governed by expressions written in Python.
+ * Expressions here are one-liners that evaluate to a float value. */
+
+/* For faster execution we keep a special dictionary for pydrivers, with
+ * the needed modules and aliases. */
+static int bpy_pydriver_create_dict(void)
+{
+ PyObject *d, *mod;
+
+ if (bpy_pydriver_Dict) return -1;
+
+ d = PyDict_New();
+ if (!d) return -1;
+
+ bpy_pydriver_Dict = d;
+
+ /* import some modules: builtins, Blender, math, Blender.noise */
+
+ PyDict_SetItemString(d, "__builtins__", PyEval_GetBuiltins());
+
+ mod = PyImport_ImportModule("Blender");
+ if (mod) {
+ PyDict_SetItemString(d, "Blender", mod);
+ PyDict_SetItemString(d, "b", mod);
+ Py_DECREF(mod);
+ }
+
+ mod = PyImport_ImportModule("math");
+ if (mod) {
+ PyDict_SetItemString(d, "math", mod);
+ PyDict_SetItemString(d, "m", mod);
+ Py_DECREF(mod);
+ }
+
+ mod = PyImport_ImportModule("Blender.Noise");
+ if (mod) {
+ PyDict_SetItemString(d, "noise", mod);
+ PyDict_SetItemString(d, "n", mod);
+ Py_DECREF(mod);
+ }
+
+ /* If there's a Blender text called pydrivers.py, import it.
+ * Users can add their own functions to this module. */
+ mod = importText("pydrivers"); /* can also use PyImport_Import() */
+ if (mod) {
+ PyDict_SetItemString(d, "pydrivers", mod);
+ PyDict_SetItemString(d, "p", mod);
+ Py_DECREF(mod);
+ }
+ else
+ PyErr_Clear();
+
+ /* short aliases for some Get() functions: */
+
+ /* ob(obname) == Blender.Object.Get(obname) */
+ mod = PyImport_ImportModule("Blender.Object");
+ if (mod) {
+ PyObject *fcn = PyObject_GetAttrString(mod, "Get");
+ Py_DECREF(mod);
+ if (fcn) {
+ PyDict_SetItemString(d, "ob", fcn);
+ Py_DECREF(fcn);
+ }
+ }
+
+ /* me(meshname) == Blender.Mesh.Get(meshname) */
+ mod = PyImport_ImportModule("Blender.Mesh");
+ if (mod) {
+ PyObject *fcn = PyObject_GetAttrString(mod, "Get");
+ Py_DECREF(mod);
+ if (fcn) {
+ PyDict_SetItemString(d, "me", fcn);
+ Py_DECREF(fcn);
+ }
+ }
+
+ /* ma(matname) == Blender.Material.Get(matname) */
+ mod = PyImport_ImportModule("Blender.Material");
+ if (mod) {
+ PyObject *fcn = PyObject_GetAttrString(mod, "Get");
+ Py_DECREF(mod);
+ if (fcn) {
+ PyDict_SetItemString(d, "ma", fcn);
+ Py_DECREF(fcn);
+ }
+ }
+
+ return 0;
+}
+
+/* error return function for BPY_eval_pydriver */
+static float pydriver_error(IpoDriver *driver) {
+
+ if (bpy_pydriver_oblist)
+ bpy_pydriver_freeList();
+
+ if (bpy_pydriver_Dict) { /* free the global dict used by pydrivers */
+ PyDict_Clear(bpy_pydriver_Dict);
+ Py_DECREF(bpy_pydriver_Dict);
+ bpy_pydriver_Dict = NULL;
+ }
+
+ driver->flag |= IPO_DRIVER_FLAG_INVALID; /* py expression failed */
+
+ if (driver->ob)
+ fprintf(stderr, "\nError in Ipo Driver: Object %s\nThis is the failed Python expression:\n'%s'\n\n", driver->ob->id.name+2, driver->name);
+ else
+ fprintf(stderr, "\nError in Ipo Driver: No Object\nThis is the failed Python expression:\n'%s'\n\n", driver->name);
+
+ PyErr_Print();
+
+ return 0.0f;
+}
+
+
+/********PyConstraints*********/
+
+/* This function checks whether a text-buffer is a PyConstraint candidate.
+ * It uses simple text parsing that could be easily confused!
+ */
+int BPY_is_pyconstraint(Text *text)
+{
+ TextLine *tline = text->lines.first;
+
+ if (tline && (tline->len > 10)) {
+ char *line = tline->line;
+
+ /* Expected format: #BPYCONSTRAINT
+ * The actual checks are forgiving, so slight variations also work. */
+ if (line && line[0] == '#' && strstr(line, "BPYCONSTRAINT")) return 1;
+ }
+ return 0;
+}
+
+/* This function is called to update PyConstraint data so that it is compatible with the script.
+ * Some of the allocating/freeing of memory for constraint targets occurs here, espcially
+ * if the number of targets changes.
+ */
+void BPY_pyconstraint_update(Object *owner, bConstraint *con)
+{
+ bPythonConstraint *data= con->data;
+
+ if (data->text) {
+ /* script does exist. it is assumed that this is a valid pyconstraint script */
+ PyObject *globals;
+ PyObject *retval, *gval;
+ int num, i;
+
+ /* clear the relevant flags first */
+ data->flag = 0;
+
+ /* populate globals dictionary */
+ globals = CreateGlobalDictionary();
+ retval = RunPython(data->text, globals);
+
+ if (retval == NULL) {
+ BPY_Err_Handle(data->text->id.name);
+ ReleaseGlobalDictionary(globals);
+ data->flag |= PYCON_SCRIPTERROR;
+ return;
+ }
+
+ Py_XDECREF(retval);
+ retval = NULL;
+
+ /* try to find NUM_TARGETS */
+ gval = PyDict_GetItemString(globals, "NUM_TARGETS");
+ if ( (gval) && (num= PyInt_AsLong(gval)) ) {
+ /* NUM_TARGETS is defined... and non-zero */
+ bConstraintTarget *ct;
+
+ /* check if it is valid (just make sure it is not negative)
+ * TODO: PyInt_AsLong may return -1 as sign of invalid input...
+ */
+ num = abs(num);
+ data->flag |= PYCON_USETARGETS;
+
+ /* check if the number of targets has changed */
+ if (num < data->tarnum) {
+ /* free a few targets */
+ num= data->tarnum - num;
+ for (i = 0; i < num; i++, data->tarnum--) {
+ ct= data->targets.last;
+ BLI_freelinkN(&data->targets, ct);
+ }
+ }
+ else if (num > data->tarnum) {
+ /* add a few targets */
+ num = num - data->tarnum;
+ for (i = 0; i < num; i++, data->tarnum++) {
+ ct= MEM_callocN(sizeof(bConstraintTarget), "PyConTarget");
+ BLI_addtail(&data->targets, ct);
+ }
+ }
+
+ /* validate targets */
+ con->flag &= ~CONSTRAINT_DISABLE;
+ for (ct= data->targets.first; ct; ct= ct->next) {
+ if (!exist_object(ct->tar)) {
+ ct->tar = NULL;
+ con->flag |= CONSTRAINT_DISABLE;
+ break;
+ }
+
+ if ((ct->tar == owner) && (ct->subtarget[0] != 0)) {
+ if (get_named_bone(get_armature(owner), ct->subtarget) == NULL) {
+ con->flag |= CONSTRAINT_DISABLE;
+ break;
+ }
+ }
+ }
+
+ /* clear globals */
+ ReleaseGlobalDictionary(globals);
+ }
+ else {
+ /* NUM_TARGETS is not defined or equals 0 */
+ ReleaseGlobalDictionary(globals);
+
+ /* free all targets */
+ BLI_freelistN(&data->targets);
+ data->tarnum = 0;
+ data->flag &= ~PYCON_USETARGETS;
+
+ return;
+ }
+ }
+ else {
+ /* no script, so clear any settings/data now */
+ data->tarnum = 0;
+ data->flag = 0;
+ con->flag &= ~CONSTRAINT_DISABLE;
+
+ BLI_freelistN(&data->targets);
+
+ /* supposedly this should still leave the base struct... */
+ IDP_FreeProperty(data->prop);
+ }
+}
+
+/* PyConstraints Evaluation Function (only called from evaluate_constraint)
+ * This function is responsible for modifying the ownermat that it is passed.
+ */
+void BPY_pyconstraint_eval(bPythonConstraint *con, bConstraintOb *cob, ListBase *targets)
+{
+ PyObject *srcmat, *tarmat, *tarmats, *idprop;
+ PyObject *globals;
+ PyObject *gval;
+ PyObject *pyargs, *retval;
+ bConstraintTarget *ct;
+ MatrixObject *retmat;
+ int row, col, index;
+
+ if (!con->text) return;
+ if (con->flag & PYCON_SCRIPTERROR) return;
+
+ globals = CreateGlobalDictionary();
+
+ /* wrap blender-data as PyObjects for evaluation
+ * - we expose the owner's matrix as pymatrix
+ * - id-properties are wrapped using the id-properties pyapi
+ * - targets are presented as a list of matrices
+ */
+ srcmat = newMatrixObject((float *)cob->matrix, 4, 4, Py_NEW);
+ idprop = BPy_Wrap_IDProperty(NULL, con->prop, NULL);
+
+ tarmats= PyList_New(con->tarnum);
+ for (ct=targets->first, index=0; ct; ct=ct->next, index++) {
+ tarmat = newMatrixObject((float *)ct->matrix, 4, 4, Py_NEW);
+ PyList_SetItem(tarmats, index, tarmat);
+ }
+
+
+/* since I can't remember what the armature weakrefs do, I'll just leave this here
+ commented out. This function was based on pydrivers, and it might still be relevent.
+ if( !setup_armature_weakrefs()){
+ fprintf( stderr, "Oops - weakref dict setup\n");
+ return result;
+ }
+*/
+
+ retval = RunPython(con->text, globals);
+
+ if (retval == NULL) {
+ BPY_Err_Handle(con->text->id.name);
+ con->flag |= PYCON_SCRIPTERROR;
+
+ /* free temp objects */
+ Py_XDECREF(idprop);
+ Py_XDECREF(srcmat);
+ Py_XDECREF(tarmats);
+
+ ReleaseGlobalDictionary(globals);
+
+ return;
+ }
+
+ if (retval) {Py_XDECREF( retval );}
+ retval = NULL;
+
+ gval = PyDict_GetItemString(globals, "doConstraint");
+ if (!gval) {
+ printf("ERROR: no doConstraint function in constraint!\n");
+
+ /* free temp objects */
+ Py_XDECREF(idprop);
+ Py_XDECREF(srcmat);
+ Py_XDECREF(tarmats);
+
+ ReleaseGlobalDictionary(globals);
+
+ return;
+ }
+
+ /* Now for the fun part! Try and find the functions we need. */
+ if (PyFunction_Check(gval)) {
+ pyargs = Py_BuildValue("OOO", srcmat, tarmats, idprop);
+ retval = PyObject_CallObject(gval, pyargs);
+ Py_XDECREF(pyargs);
+ }
+ else {
+ printf("ERROR: doConstraint is supposed to be a function!\n");
+ con->flag |= PYCON_SCRIPTERROR;
+
+ Py_XDECREF(idprop);
+ Py_XDECREF(srcmat);
+ Py_XDECREF(tarmats);
+
+ ReleaseGlobalDictionary(globals);
+
+ return;
+ }
+
+ if (!retval) {
+ BPY_Err_Handle(con->text->id.name);
+ con->flag |= PYCON_SCRIPTERROR;
+
+ /* free temp objects */
+ Py_XDECREF(idprop);
+ Py_XDECREF(srcmat);
+ Py_XDECREF(tarmats);
+
+ ReleaseGlobalDictionary(globals);
+
+ return;
+ }
+
+
+ if (!PyObject_TypeCheck(retval, &matrix_Type)) {
+ printf("Error in PyConstraint - doConstraint: Function not returning a matrix!\n");
+ con->flag |= PYCON_SCRIPTERROR;
+
+ Py_XDECREF(idprop);
+ Py_XDECREF(srcmat);
+ Py_XDECREF(tarmats);
+ Py_XDECREF(retval);
+
+ ReleaseGlobalDictionary(globals);
+
+ return;
+ }
+
+ retmat = (MatrixObject *)retval;
+ if (retmat->rowSize != 4 || retmat->colSize != 4) {
+ printf("Error in PyConstraint - doConstraint: Matrix returned is the wrong size!\n");
+ con->flag |= PYCON_SCRIPTERROR;
+
+ Py_XDECREF(idprop);
+ Py_XDECREF(srcmat);
+ Py_XDECREF(tarmats);
+ Py_XDECREF(retval);
+
+ ReleaseGlobalDictionary(globals);
+
+ return;
+ }
+
+ /* this is the reverse of code taken from newMatrix() */
+ for(row = 0; row < 4; row++) {
+ for(col = 0; col < 4; col++) {
+ cob->matrix[row][col] = retmat->contigPtr[row*4+col];
+ }
+ }
+
+ /* free temp objects */
+ Py_XDECREF(idprop);
+ Py_XDECREF(srcmat);
+ Py_XDECREF(tarmats);
+ Py_XDECREF(retval);
+
+ /* clear globals */
+ ReleaseGlobalDictionary(globals);
+}
+
+/* This evaluates the target matrix for each target the PyConstraint uses.
+ * NOTE: it only does one target at a time!
+ */
+void BPY_pyconstraint_target(bPythonConstraint *con, bConstraintTarget *ct)
+{
+ PyObject *tar, *subtar;
+ PyObject *tarmat, *idprop;
+ PyObject *globals;
+ PyObject *gval;
+ PyObject *pyargs, *retval;
+ MatrixObject *retmat;
+ int row, col;
+
+ if (!con->text) return;
+ if (con->flag & PYCON_SCRIPTERROR) return;
+ if (!ct) return;
+
+ globals = CreateGlobalDictionary();
+
+ tar = Object_CreatePyObject(ct->tar);
+ if ((ct->tar) && (ct->tar->type==OB_ARMATURE)) {
+ bPoseChannel *pchan;
+ pchan = get_pose_channel(ct->tar->pose, ct->subtarget);
+ subtar = PyPoseBone_FromPosechannel(pchan);
+ }
+ else
+ subtar = PyString_FromString(ct->subtarget);
+
+ tarmat = newMatrixObject((float *)ct->matrix, 4, 4, Py_NEW);
+ idprop = BPy_Wrap_IDProperty( NULL, con->prop, NULL);
+
+/* since I can't remember what the armature weakrefs do, I'll just leave this here
+ commented out. This function was based on pydrivers, and it might still be relevent.
+ if( !setup_armature_weakrefs()){
+ fprintf( stderr, "Oops - weakref dict setup\n");
+ return result;
+ }
+*/
+ retval = RunPython(con->text, globals);
+
+ if (retval == NULL) {
+ BPY_Err_Handle(con->text->id.name);
+ con->flag |= PYCON_SCRIPTERROR;
+
+ /* free temp objects */
+ Py_XDECREF(tar);
+ Py_XDECREF(subtar);
+ Py_XDECREF(idprop);
+ Py_XDECREF(tarmat);
+
+ ReleaseGlobalDictionary(globals);
+
+ return;
+ }
+
+ Py_XDECREF(retval);
+ retval = NULL;
+
+ /* try to find doTarget function to set the target matrix */
+ gval = PyDict_GetItemString(globals, "doTarget");
+ if (!gval) {
+ /* free temp objects */
+ Py_XDECREF(tar);
+ Py_XDECREF(subtar);
+ Py_XDECREF(idprop);
+ Py_XDECREF(tarmat);
+
+ ReleaseGlobalDictionary(globals);
+
+ return;
+ }
+
+ /* Now for the fun part! Try and find the functions we need.*/
+ if (PyFunction_Check(gval)) {
+ pyargs = Py_BuildValue("OOOO", tar, subtar, tarmat, idprop);
+ retval = PyObject_CallObject(gval, pyargs);
+ Py_XDECREF(pyargs);
+ }
+ else {
+ printf("ERROR: doTarget is supposed to be a function!\n");
+ con->flag |= PYCON_SCRIPTERROR;
+
+ Py_XDECREF(tar);
+ Py_XDECREF(subtar);
+ Py_XDECREF(idprop);
+ Py_XDECREF(tarmat);
+
+ ReleaseGlobalDictionary(globals);
+ return;
+ }
+
+ if (!retval) {
+ BPY_Err_Handle(con->text->id.name);
+ con->flag |= PYCON_SCRIPTERROR;
+
+
+ /* free temp objects */
+ Py_XDECREF(tar);
+ Py_XDECREF(subtar);
+ Py_XDECREF(idprop);
+ Py_XDECREF(tarmat);
+
+ ReleaseGlobalDictionary(globals);
+ return;
+ }
+
+ if (!PyObject_TypeCheck(retval, &matrix_Type)) {
+ con->flag |= PYCON_SCRIPTERROR;
+
+ Py_XDECREF(tar);
+ Py_XDECREF(subtar);
+ Py_XDECREF(idprop);
+ Py_XDECREF(tarmat);
+ Py_XDECREF(retval);
+
+ ReleaseGlobalDictionary(globals);
+ return;
+ }
+
+ retmat = (MatrixObject *)retval;
+ if (retmat->rowSize != 4 || retmat->colSize != 4) {
+ printf("Error in PyConstraint - doTarget: Matrix returned is the wrong size!\n");
+ con->flag |= PYCON_SCRIPTERROR;
+
+ Py_XDECREF(tar);
+ Py_XDECREF(subtar);
+ Py_XDECREF(idprop);
+ Py_XDECREF(tarmat);
+ Py_XDECREF(retval);
+
+ ReleaseGlobalDictionary(globals);
+ return;
+ }
+
+ /* this is the reverse of code taken from newMatrix() */
+ for(row = 0; row < 4; row++) {
+ for(col = 0; col < 4; col++) {
+ ct->matrix[row][col] = retmat->contigPtr[row*4+col];
+ }
+ }
+
+ /* free temp objects */
+ Py_XDECREF(tar);
+ Py_XDECREF(subtar);
+ Py_XDECREF(idprop);
+ Py_XDECREF(tarmat);
+ Py_XDECREF(retval);
+
+ /* clear globals */
+ ReleaseGlobalDictionary(globals);
+}
+
+/* This draws+handles the user-defined interface for editing pyconstraints idprops */
+void BPY_pyconstraint_settings(void *arg1, void *arg2)
+{
+ bPythonConstraint *con= (bPythonConstraint *)arg1;
+ PyObject *idprop;
+ PyObject *globals;
+ PyObject *gval;
+ PyObject *retval;
+
+ if (!con->text) return;
+ if (con->flag & PYCON_SCRIPTERROR) return;
+
+ globals = CreateGlobalDictionary();
+
+ idprop = BPy_Wrap_IDProperty( NULL, con->prop, NULL);
+
+ retval = RunPython(con->text, globals);
+
+ if (retval == NULL) {
+ BPY_Err_Handle(con->text->id.name);
+ ReleaseGlobalDictionary(globals);
+ con->flag |= PYCON_SCRIPTERROR;
+
+ /* free temp objects */
+ Py_XDECREF(idprop);
+ return;
+ }
+
+ if (retval) {Py_XDECREF( retval );}
+ retval = NULL;
+
+ gval = PyDict_GetItemString(globals, "getSettings");
+ if (!gval) {
+ printf("ERROR: no getSettings function in constraint!\n");
+
+ /* free temp objects */
+ ReleaseGlobalDictionary( globals );
+ Py_XDECREF(idprop);
+ return;
+ }
+
+ /* Now for the fun part! Try and find the functions we need. */
+ if (PyFunction_Check(gval)) {
+ retval = PyObject_CallFunction(gval, "O", idprop);
+ }
+ else {
+ printf("ERROR: getSettings is supposed to be a function!\n");
+ ReleaseGlobalDictionary( globals );
+
+ Py_XDECREF(idprop);
+ return;
+ }
+
+ if (!retval) {
+ BPY_Err_Handle(con->text->id.name);
+ con->flag |= PYCON_SCRIPTERROR;
+
+ /* free temp objects */
+ ReleaseGlobalDictionary(globals);
+ Py_XDECREF(idprop);
+ return;
+ }
+ else {
+ /* clear globals */
+ ReleaseGlobalDictionary(globals);
+
+ /* free temp objects */
+ Py_XDECREF(idprop);
+ Py_DECREF(retval);
+ return;
+ }
+}
+
+/* Update function, it gets rid of pydrivers global dictionary, forcing
+ * BPY_pydriver_eval to recreate it. This function is used to force
+ * reloading the Blender text module "pydrivers.py", if available, so
+ * updates in it reach pydriver evaluation. */
+void BPY_pydriver_update(void)
+{
+ if (bpy_pydriver_Dict) { /* free the global dict used by pydrivers */
+ PyDict_Clear(bpy_pydriver_Dict);
+ Py_DECREF(bpy_pydriver_Dict);
+ bpy_pydriver_Dict = NULL;
+ }
+
+ return;
+}
+
+/* for depsgraph.c, runs py expr once to collect all refs. made
+ * to objects (self refs. to the object that owns the py driver
+ * are not allowed). */
+struct Object **BPY_pydriver_get_objects(IpoDriver *driver)
+{
+ /*if (!driver || !driver->ob || driver->name[0] == '\0')
+ return NULL;*/
+
+ /*PyErr_Clear();*/
+
+ /* clear the flag that marks invalid python expressions */
+ driver->flag &= ~IPO_DRIVER_FLAG_INVALID;
+
+ /* tell we're running a pydriver, so Get() functions know they need
+ * to add the requested obj to our list */
+ bpy_pydriver_running(1);
+
+ /* append driver owner object as the 1st ob in the list;
+ * we put it there to make sure it is not itself referenced in
+ * its pydriver expression */
+ bpy_pydriver_appendToList(driver->ob);
+
+ /* this will append any other ob referenced in expr (driver->name)
+ * or set the driver's error flag if driver's py expression fails */
+ BPY_pydriver_eval(driver);
+
+ bpy_pydriver_running(0); /* ok, we're done */
+
+ return bpy_pydriver_obArrayFromList(); /* NULL if eval failed */
+}
+
+/* This evals py driver expressions, 'expr' is a Python expression that
+ * should evaluate to a float number, which is returned. */
+float BPY_pydriver_eval(IpoDriver *driver)
+{
+ char *expr = NULL;
+ PyObject *retval, *floatval, *bpy_ob = NULL;
+ float result = 0.0f; /* default return */
+ int setitem_retval;
+
+ if (!driver) return result;
+
+ expr = driver->name; /* the py expression to be evaluated */
+ if (!expr || expr[0]=='\0') return result;
+
+ if (!bpy_pydriver_Dict) {
+ if (bpy_pydriver_create_dict() != 0) {
+ fprintf(stderr, "Pydriver error: couldn't create Python dictionary");
+ return result;
+ }
+ }
+
+ if (driver->ob)
+ bpy_ob = Object_CreatePyObject(driver->ob);
+
+ if (!bpy_ob) {
+ Py_INCREF(Py_None);
+ bpy_ob = Py_None;
+ }
+
+ setitem_retval = EXPP_dict_set_item_str(bpy_pydriver_Dict, "self", bpy_ob);
+
+ if( !setup_armature_weakrefs()){
+ fprintf( stderr, "Oops - weakref dict setup\n");
+ return result;
+ }
+
+ retval = PyRun_String(expr, Py_eval_input, bpy_pydriver_Dict,
+ bpy_pydriver_Dict);
+
+ if (retval == NULL) {
+ return pydriver_error(driver);
+ }
+
+ floatval = PyNumber_Float(retval);
+ Py_DECREF(retval);
+
+ if (floatval == NULL)
+ return pydriver_error(driver);
+
+ result = (float)PyFloat_AsDouble(floatval);
+ Py_DECREF(floatval);
+
+ /* remove 'self', since this dict is also used by py buttons */
+ if (setitem_retval == 0) PyDict_DelItemString(bpy_pydriver_Dict, "self");
+
+ /* all fine, make sure the "invalid expression" flag is cleared */
+ driver->flag &= ~IPO_DRIVER_FLAG_INVALID;
+
+ return result;
+}
+
+/* Button Python Evaluation */
+
+/* Python evaluation for gui buttons:
+ * users can write any valid Python expression (that evals to an int or float)
+ * inside Blender's gui number buttons and have them evaluated to their
+ * actual int or float value.
+ *
+ * The global dict used for pydrivers is also used here, so all imported
+ * modules for pydrivers (including the pydrivers.py Blender text) are
+ * available for button py eval, too. */
+
+static int bpy_button_eval_error(char *expr) {
+
+ if (bpy_pydriver_oblist)
+ bpy_pydriver_freeList();
+
+ if (bpy_pydriver_Dict) { /* free the persistent global dict */
+ /* it's the same dict used by pydrivers */
+ PyDict_Clear(bpy_pydriver_Dict);
+ Py_DECREF(bpy_pydriver_Dict);
+ bpy_pydriver_Dict = NULL;
+ }
+
+ fprintf(stderr, "\nError in button evaluation:\nThis is the failed Python expression:\n'%s'\n\n", expr);
+
+ PyErr_Print();
+
+ return -1;
+}
+
+int BPY_button_eval(char *expr, double *value)
+{
+ PyObject *retval, *floatval;
+
+ if (!value || !expr || expr[0]=='\0') return -1;
+
+ *value = 0.0; /* default value */
+
+ if (!bpy_pydriver_Dict) {
+ if (bpy_pydriver_create_dict() != 0) {
+ fprintf(stderr,
+ "Button Python Eval error: couldn't create Python dictionary");
+ return -1;
+ }
+ }
+
+
+ if( !setup_armature_weakrefs()){
+ fprintf(stderr, "Oops - weakref dict\n");
+ return -1;
+ }
+
+ retval = PyRun_String(expr, Py_eval_input, bpy_pydriver_Dict,
+ bpy_pydriver_Dict);
+
+ if (retval == NULL) {
+ return bpy_button_eval_error(expr);
+ }
+ else {
+ floatval = PyNumber_Float(retval);
+ Py_DECREF(retval);
+ }
+
+ if (floatval == NULL)
+ return bpy_button_eval_error(expr);
+ else {
+ *value = (float)PyFloat_AsDouble(floatval);
+ Py_DECREF(floatval);
+ }
+
+ return 0; /* successful exit */
+}
+
+
+/*****************************************************************************/
+/* ScriptLinks */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* Description: */
+/* Notes: Not implemented yet */
+/*****************************************************************************/
+void BPY_clear_bad_scriptlinks( struct Text *byebye )
+{
+/*
+ BPY_clear_bad_scriptlist(getObjectList(), byebye);
+ BPY_clear_bad_scriptlist(getLampList(), byebye);
+ BPY_clear_bad_scriptlist(getCameraList(), byebye);
+ BPY_clear_bad_scriptlist(getMaterialList(), byebye);
+ BPY_clear_bad_scriptlist(getWorldList(), byebye);
+ BPY_clear_bad_scriptlink(&scene_getCurrent()->id, byebye);
+
+ allqueue(REDRAWBUTSSCRIPT, 0);
+*/
+ return;
+}
+
+/*****************************************************************************
+* Description: Loop through all scripts of a list of object types, and
+* execute these scripts.
+* For the scene, only the current active scene the scripts are
+* executed (if any).
+*****************************************************************************/
+void BPY_do_all_scripts( short event )
+{
+ DoAllScriptsFromList( &( G.main->object ), event );
+ DoAllScriptsFromList( &( G.main->lamp ), event );
+ DoAllScriptsFromList( &( G.main->camera ), event );
+ DoAllScriptsFromList( &( G.main->mat ), event );
+ DoAllScriptsFromList( &( G.main->world ), event );
+
+ BPY_do_pyscript( &( G.scene->id ), event );
+
+ return;
+}
+
+/*****************************************************************************
+* Description: Execute a Python script when an event occurs. The following
+* events are possible: frame changed, load script and redraw.
+* Only events happening to one of the following object types
+* are handled: Object, Lamp, Camera, Material, World and
+* Scene.
+*****************************************************************************/
+
+static ScriptLink *ID_getScriptlink( ID * id )
+{
+ switch ( MAKE_ID2( id->name[0], id->name[1] ) ) {
+ case ID_OB:
+ return &( ( Object * ) id )->scriptlink;
+ case ID_LA:
+ return &( ( Lamp * ) id )->scriptlink;
+ case ID_CA:
+ return &( ( Camera * ) id )->scriptlink;
+ case ID_MA:
+ return &( ( Material * ) id )->scriptlink;
+ case ID_WO:
+ return &( ( World * ) id )->scriptlink;
+ case ID_SCE:
+ return &( ( Scene * ) id )->scriptlink;
+ default:
+ return NULL;
+ }
+}
+
+int BPY_has_onload_script( void )
+{
+ ScriptLink *slink = &G.scene->scriptlink;
+ int i;
+
+ if( !slink || !slink->totscript )
+ return 0;
+
+ for( i = 0; i < slink->totscript; i++ ) {
+ if( ( slink->flag[i] == SCRIPT_ONLOAD )
+ && ( slink->scripts[i] != NULL ) )
+ return 1;
+ }
+
+ return 0;
+}
+
+void BPY_do_pyscript( ID * id, short event )
+{
+ ScriptLink *scriptlink;
+
+ if( !id ) return;
+
+ scriptlink = ID_getScriptlink( id );
+
+ if( scriptlink && scriptlink->totscript ) {
+ PyObject *value;
+ PyObject *dict;
+ PyObject *ret;
+ int index, during_slink = during_scriptlink( );
+
+ /* invalid scriptlinks (new .blend was just loaded), return */
+ if( during_slink < 0 )
+ return;
+
+ if( !setup_armature_weakrefs()){
+ printf("Oops - weakref dict, this is a bug\n");
+ return;
+ }
+
+ value = GetPyObjectFromID( id );
+ if( !value){
+ printf("Oops - could not get a valid python object for Blender.link, this is a bug\n");
+ return;
+ }
+
+ /* tell we're running a scriptlink. The sum also tells if this script
+ * is running nested inside another. Blender.Load needs this info to
+ * avoid trouble with invalid slink pointers. */
+ during_slink++;
+ disable_where_scriptlink( (short)during_slink );
+
+ /* set globals in Blender module to identify scriptlink */
+ EXPP_dict_set_item_str( g_blenderdict, "bylink", EXPP_incr_ret_True() );
+
+ EXPP_dict_set_item_str( g_blenderdict, "link", value );
+ EXPP_dict_set_item_str( g_blenderdict, "event",
+ PyString_FromString( event_to_name
+ ( event ) ) );
+
+ if (event == SCRIPT_POSTRENDER) event = SCRIPT_RENDER;
+
+ for( index = 0; index < scriptlink->totscript; index++ ) {
+ if( ( scriptlink->flag[index] == event ) &&
+ ( scriptlink->scripts[index] != NULL ) ) {
+ dict = CreateGlobalDictionary( );
+ ret = RunPython( ( Text * ) scriptlink->
+ scripts[index], dict );
+ ReleaseGlobalDictionary( dict );
+
+ if( !ret ) {
+ /* Failed execution of the script */
+ BPY_Err_Handle( scriptlink->
+ scripts[index]->name +
+ 2 );
+ //BPY_end_python ();
+ //BPY_start_python ();
+ } else {
+ Py_DECREF( ret );
+ }
+ /* If a scriptlink has just loaded a new .blend file, the
+ * scriptlink pointer became invalid (see api2_2x/Blender.c),
+ * so we stop here. */
+ if( during_scriptlink( ) == -1 ) {
+ during_slink = 1;
+ break;
+ }
+ }
+ }
+
+ disable_where_scriptlink( (short)(during_slink - 1) );
+
+ /* cleanup bylink flag and clear link so PyObject
+ * can be released
+ */
+ EXPP_dict_set_item_str( g_blenderdict, "bylink", EXPP_incr_ret_False() );
+ PyDict_SetItemString( g_blenderdict, "link", Py_None );
+ EXPP_dict_set_item_str( g_blenderdict, "event",
+ PyString_FromString( "" ) );
+ }
+}
+
+
+/* SPACE HANDLERS */
+
+/* These are special script links that can be assigned to ScrArea's to
+ * (EVENT type) receive events sent to a given space (and use or ignore them) or
+ * (DRAW type) be called after the space is drawn, to draw anything on top of
+ * the space area. */
+
+/* How to add space handlers to other spaces:
+ * - add the space event defines to DNA_scriptlink_types.h, as done for
+ * 3d view: SPACEHANDLER_VIEW3D_EVENT, for example;
+ * - add the new defines to Blender.SpaceHandler dictionary in Blender.c;
+ * - check space.c for how to call the event handlers;
+ * - check drawview.c for how to call the draw handlers;
+ * - check header_view3d.c for how to add the "Space Handler Scripts" menu.
+ * Note: DRAW handlers should be called with 'event = 0', chech drawview.c */
+
+int BPY_has_spacehandler(Text *text, ScrArea *sa)
+{
+ ScriptLink *slink;
+ int index;
+
+ if (!sa || !text) return 0;
+
+ slink = &sa->scriptlink;
+
+ for (index = 0; index < slink->totscript; index++) {
+ if (slink->scripts[index] && (slink->scripts[index] == (ID *)text))
+ return 1;
+ }
+
+ return 0;
+}
+
+int BPY_is_spacehandler(Text *text, char spacetype)
+{
+ TextLine *tline = text->lines.first;
+ unsigned short type = 0;
+
+ if (tline && (tline->len > 10)) {
+ char *line = tline->line;
+
+ /* Expected format: # SPACEHANDLER.SPACE.TYPE
+ * Ex: # SPACEHANDLER.VIEW3D.DRAW
+ * The actual checks are forgiving, so slight variations also work. */
+ if (line && line[0] == '#' && strstr(line, "HANDLER")) {
+ line++; /* skip '#' */
+
+ /* only done for 3D View right now, trivial to add for others: */
+ switch (spacetype) {
+ case SPACE_VIEW3D:
+ if (strstr(line, "3D")) { /* VIEW3D, 3DVIEW */
+ if (strstr(line, "DRAW")) type = SPACEHANDLER_VIEW3D_DRAW;
+ else if (strstr(line, "EVENT")) type = SPACEHANDLER_VIEW3D_EVENT;
+ }
+ break;
+ }
+ }
+ }
+ return type; /* 0 if not a space handler */
+}
+
+int BPY_del_spacehandler(Text *text, ScrArea *sa)
+{
+ ScriptLink *slink;
+ int i, j;
+
+ if (!sa || !text) return -1;
+
+ slink = &sa->scriptlink;
+ if (slink->totscript < 1) return -1;
+
+ for (i = 0; i < slink->totscript; i++) {
+ if (text == (Text *)slink->scripts[i]) {
+
+ for (j = i; j < slink->totscript - 1; j++) {
+ slink->flag[j] = slink->flag[j+1];
+ slink->scripts[j] = slink->scripts[j+1];
+ }
+ slink->totscript--;
+ /* like done in buttons_script.c we just free memory
+ * if all slinks have been removed -- less fragmentation,
+ * these should be quite small arrays */
+ if (slink->totscript == 0) {
+ if (slink->scripts) MEM_freeN(slink->scripts);
+ if (slink->flag) MEM_freeN(slink->flag);
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+int BPY_add_spacehandler(Text *text, ScrArea *sa, char spacetype)
+{
+ unsigned short handlertype;
+
+ if (!sa || !text) return -1;
+
+ handlertype = (unsigned short)BPY_is_spacehandler(text, spacetype);
+
+ if (handlertype) {
+ ScriptLink *slink = &sa->scriptlink;
+ void *stmp, *ftmp;
+ unsigned short space_event = SPACEHANDLER_VIEW3D_EVENT;
+
+ /* extend slink */
+
+ stmp= slink->scripts;
+ slink->scripts= MEM_mallocN(sizeof(ID*)*(slink->totscript+1),
+ "spacehandlerscripts");
+
+ ftmp= slink->flag;
+ slink->flag= MEM_mallocN(sizeof(short*)*(slink->totscript+1),
+ "spacehandlerflags");
+
+ if (slink->totscript) {
+ memcpy(slink->scripts, stmp, sizeof(ID*)*(slink->totscript));
+ MEM_freeN(stmp);
+
+ memcpy(slink->flag, ftmp, sizeof(short)*(slink->totscript));
+ MEM_freeN(ftmp);
+ }
+
+ switch (spacetype) {
+ case SPACE_VIEW3D:
+ if (handlertype == 1) space_event = SPACEHANDLER_VIEW3D_EVENT;
+ else space_event = SPACEHANDLER_VIEW3D_DRAW;
+ break;
+ default:
+ break;
+ }
+
+ slink->scripts[slink->totscript] = (ID *)text;
+ slink->flag[slink->totscript]= space_event;
+
+ slink->totscript++;
+ slink->actscript = slink->totscript;
+
+ }
+ return 0;
+}
+
+int BPY_do_spacehandlers( ScrArea *sa, unsigned short event,
+ unsigned short space_event )
+{
+ ScriptLink *scriptlink;
+ int retval = 0;
+
+ if (!sa || !(G.f & G_DOSCRIPTLINKS)) return 0;
+
+ scriptlink = &sa->scriptlink;
+
+ if (scriptlink->totscript > 0) {
+ PyObject *dict;
+ PyObject *ret;
+ int index, during_slink = during_scriptlink();
+
+ /* invalid scriptlinks (new .blend was just loaded), return */
+ if (during_slink < 0) return 0;
+
+ /* tell we're running a scriptlink. The sum also tells if this script
+ * is running nested inside another. Blender.Load needs this info to
+ * avoid trouble with invalid slink pointers.
+ * Update (test): allow EVENT space handlers to call file/image selectors,
+ * still disabled for DRAW space handlers: */
+ if (event == 0) { /* event = 0: DRAW space handler */
+ during_slink++;
+ disable_where_scriptlink( (short)during_slink );
+ }
+
+ if( !setup_armature_weakrefs()){
+ printf("Oops - weakref dict, this is a bug\n");
+ return 0;
+ }
+
+ /* set globals in Blender module to identify space handler scriptlink */
+ EXPP_dict_set_item_str(g_blenderdict, "bylink", EXPP_incr_ret_True());
+ /* unlike normal scriptlinks, here Blender.link is int (space event type) */
+ EXPP_dict_set_item_str(g_blenderdict, "link", PyInt_FromLong(space_event));
+ /* note: DRAW space_events set event to 0 */
+ EXPP_dict_set_item_str(g_blenderdict, "event", PyInt_FromLong(event));
+
+ /* now run all assigned space handlers for this space and space_event */
+ for( index = 0; index < scriptlink->totscript; index++ ) {
+
+ /* for DRAW handlers: */
+ if (event == 0) {
+ glPushAttrib(GL_ALL_ATTRIB_BITS);
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ }
+
+ if( ( scriptlink->flag[index] == space_event ) &&
+ ( scriptlink->scripts[index] != NULL ) ) {
+ dict = CreateGlobalDictionary();
+ ret = RunPython( ( Text * ) scriptlink->scripts[index], dict );
+ ReleaseGlobalDictionary( dict );
+
+ if (!ret) { /* Failed execution of the script */
+ BPY_Err_Handle( scriptlink->scripts[index]->name+2 );
+ } else {
+ Py_DECREF(ret);
+
+ /* an EVENT type (event != 0) script can either accept an event or
+ * ignore it:
+ * if the script sets Blender.event to None it accepted it;
+ * otherwise the space's event handling callback that called us
+ * can go on processing the event */
+ if (event && (PyDict_GetItemString(g_blenderdict,"event") == Py_None))
+ retval = 1; /* event was swallowed */
+ }
+
+ /* If a scriptlink has just loaded a new .blend file, the
+ * scriptlink pointer became invalid (see api2_2x/Blender.c),
+ * so we stop here. */
+ if( during_scriptlink( ) == -1 ) {
+ during_slink = 1;
+ if (event == 0) glPopAttrib();
+ break;
+ }
+ }
+
+ /* for DRAW handlers: */
+ if (event == 0) {
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+ glPopAttrib();
+ disable_where_scriptlink( (short)(during_slink - 1) );
+ }
+
+ }
+
+ EXPP_dict_set_item_str(g_blenderdict, "bylink", EXPP_incr_ret_False());
+ PyDict_SetItemString(g_blenderdict, "link", Py_None );
+ EXPP_dict_set_item_str(g_blenderdict, "event", PyString_FromString(""));
+ }
+
+ /* retval:
+ * space_event is of type EVENT:
+ * 0 - event was returned,
+ * 1 - event was processed;
+ * space_event is of type DRAW:
+ * 0 always */
+
+ return retval;
+}
+
+/*****************************************************************************
+* Description:
+* Notes:
+*****************************************************************************/
+void BPY_free_scriptlink( struct ScriptLink *slink )
+{
+ if( slink->totscript ) {
+ if( slink->flag ) {
+ MEM_freeN( slink->flag );
+ slink->flag= NULL;
+ }
+ if( slink->scripts ) {
+ MEM_freeN( slink->scripts );
+ slink->scripts= NULL;
+ }
+ }
+
+ return;
+}
+
+static int CheckAllSpaceHandlers(Text *text)
+{
+ bScreen *screen;
+ ScrArea *sa;
+ ScriptLink *slink;
+ int fixed = 0;
+
+ for (screen = G.main->screen.first; screen; screen = screen->id.next) {
+ for (sa = screen->areabase.first; sa; sa = sa->next) {
+ slink = &sa->scriptlink;
+ if (!slink->totscript) continue;
+ if (BPY_del_spacehandler(text, sa) == 0) fixed++;
+ }
+ }
+ return fixed;
+}
+
+static int CheckAllScriptsFromList( ListBase * list, Text * text )
+{
+ ID *id;
+ ScriptLink *scriptlink;
+ int index;
+ int fixed = 0;
+
+ id = list->first;
+
+ while( id != NULL ) {
+ scriptlink = ID_getScriptlink( id );
+ if( scriptlink && scriptlink->totscript ) {
+ for( index = 0; index < scriptlink->totscript; index++) {
+ if ((Text *)scriptlink->scripts[index] == text) {
+ scriptlink->scripts[index] = NULL;
+ fixed++;
+ }
+ }
+ }
+ id = id->next;
+ }
+
+ return fixed;
+}
+
+/* When a Text is deleted, we need to unlink it from eventual scriptlinks */
+int BPY_check_all_scriptlinks( Text * text )
+{
+ int fixed = 0;
+ fixed += CheckAllScriptsFromList( &( G.main->object ), text );
+ fixed += CheckAllScriptsFromList( &( G.main->lamp ), text );
+ fixed += CheckAllScriptsFromList( &( G.main->camera ), text );
+ fixed += CheckAllScriptsFromList( &( G.main->mat ), text );
+ fixed += CheckAllScriptsFromList( &( G.main->world ), text );
+ fixed += CheckAllScriptsFromList( &( G.main->scene ), text );
+ fixed += CheckAllSpaceHandlers(text);
+
+ return fixed;
+}
+
+/*****************************************************************************
+* Description:
+* Notes:
+*****************************************************************************/
+void BPY_copy_scriptlink( struct ScriptLink *scriptlink )
+{
+ void *tmp;
+
+ if( scriptlink->totscript ) {
+
+ tmp = scriptlink->scripts;
+ scriptlink->scripts =
+ MEM_mallocN( sizeof( ID * ) * scriptlink->totscript,
+ "scriptlistL" );
+ memcpy( scriptlink->scripts, tmp,
+ sizeof( ID * ) * scriptlink->totscript );
+
+ tmp = scriptlink->flag;
+ scriptlink->flag =
+ MEM_mallocN( sizeof( short ) * scriptlink->totscript,
+ "scriptlistF" );
+ memcpy( scriptlink->flag, tmp,
+ sizeof( short ) * scriptlink->totscript );
+ }
+
+ return;
+}
+
+/****************************************************************************
+* Description:
+* Notes: Not implemented yet
+*****************************************************************************/
+int BPY_call_importloader( char *name )
+{ /* XXX Should this function go away from Blender? */
+ printf( "In BPY_call_importloader(name=%s)\n", name );
+ return ( 0 );
+}
+
+/*****************************************************************************
+* Private functions
+*****************************************************************************/
+
+/*****************************************************************************
+* Description: This function executes the python script passed by text.
+* The Python dictionary containing global variables needs to
+* be passed in globaldict.
+*****************************************************************************/
+PyObject *RunPython( Text * text, PyObject * globaldict )
+{
+ char *buf = NULL;
+
+/* The script text is compiled to Python bytecode and saved at text->compiled
+ * to speed-up execution if the user executes the script multiple times */
+
+ if( !text->compiled ) { /* if it wasn't already compiled, do it now */
+ buf = txt_to_buf( text );
+
+ text->compiled =
+ Py_CompileString( buf, GetName( text ),
+ Py_file_input );
+
+ MEM_freeN( buf );
+
+ if( PyErr_Occurred( ) ) {
+ BPY_free_compiled_text( text );
+ return NULL;
+ }
+
+ }
+
+ return PyEval_EvalCode( text->compiled, globaldict, globaldict );
+}
+
+/*****************************************************************************
+* Description: This function returns the value of the name field of the
+* given Text struct.
+*****************************************************************************/
+char *GetName( Text * text )
+{
+ return ( text->id.name + 2 );
+}
+
+/*****************************************************************************
+* Description: This function creates a new Python dictionary object.
+*****************************************************************************/
+PyObject *CreateGlobalDictionary( void )
+{
+ PyObject *dict = PyDict_New( );
+
+ PyDict_SetItemString( dict, "__builtins__", PyEval_GetBuiltins( ) );
+ EXPP_dict_set_item_str( dict, "__name__",
+ PyString_FromString( "__main__" ) );
+
+ return dict;
+}
+
+/*****************************************************************************
+* Description: This function deletes a given Python dictionary object.
+*****************************************************************************/
+void ReleaseGlobalDictionary( PyObject * dict )
+{
+ PyDict_Clear( dict );
+ Py_DECREF( dict ); /* Release dictionary. */
+
+ return;
+}
+
+/***************************************************************************
+* Description: This function runs all scripts (if any) present in the
+* list argument. The event by which the function has been
+* called, is passed in the event argument.
+*****************************************************************************/
+void DoAllScriptsFromList( ListBase * list, short event )
+{
+ ID *id;
+
+ id = list->first;
+
+ while( id != NULL ) {
+ BPY_do_pyscript( id, event );
+ id = id->next;
+ }
+
+ return;
+}
+
+PyObject *importText( char *name )
+{
+ Text *text;
+ char *txtname;
+ char *buf = NULL;
+ int namelen = strlen( name );
+
+ txtname = malloc( namelen + 3 + 1 );
+ if( !txtname )
+ return NULL;
+
+ memcpy( txtname, name, namelen );
+ memcpy( &txtname[namelen], ".py", 4 );
+
+ text = ( Text * ) & ( G.main->text.first );
+
+ while( text ) {
+ if( !strcmp( txtname, GetName( text ) ) )
+ break;
+ text = text->id.next;
+ }
+
+ if( !text ) {
+ free( txtname );
+ return NULL;
+ }
+
+ if( !text->compiled ) {
+ buf = txt_to_buf( text );
+ text->compiled =
+ Py_CompileString( buf, GetName( text ),
+ Py_file_input );
+ MEM_freeN( buf );
+
+ if( PyErr_Occurred( ) ) {
+ PyErr_Print( );
+ BPY_free_compiled_text( text );
+ free( txtname );
+ return NULL;
+ }
+ }
+
+ free( txtname );
+ return PyImport_ExecCodeModule( name, text->compiled );
+}
+
+static PyMethodDef bimport[] = {
+ {"blimport", blender_import, METH_VARARGS, "our own import"}
+};
+
+PyObject *blender_import( PyObject * self, PyObject * args )
+{
+ PyObject *exception, *err, *tb;
+ char *name;
+ PyObject *globals = NULL, *locals = NULL, *fromlist = NULL;
+ PyObject *m;
+
+ if( !PyArg_ParseTuple( args, "s|OOO:bimport",
+ &name, &globals, &locals, &fromlist ) )
+ return NULL;
+
+ m = PyImport_ImportModuleEx( name, globals, locals, fromlist );
+
+ if( m )
+ return m;
+ else
+ PyErr_Fetch( &exception, &err, &tb ); /*restore for probable later use */
+
+ m = importText( name );
+ if( m ) { /* found module, ignore above exception */
+ PyErr_Clear( );
+ Py_XDECREF( exception );
+ Py_XDECREF( err );
+ Py_XDECREF( tb );
+ printf( "imported from text buffer...\n" );
+ } else {
+ PyErr_Restore( exception, err, tb );
+ }
+ return m;
+}
+
+void init_ourImport( void )
+{
+ PyObject *m, *d;
+ PyObject *import = PyCFunction_New( bimport, NULL );
+
+ m = PyImport_AddModule( "__builtin__" );
+ d = PyModule_GetDict( m );
+
+ EXPP_dict_set_item_str( d, "__import__", import );
+}
+
+/*
+ * find in-memory module and recompile
+ */
+
+static PyObject *reimportText( PyObject *module )
+{
+ Text *text;
+ char *txtname;
+ char *name;
+ char *buf = NULL;
+
+ /* get name, filename from the module itself */
+
+ txtname = PyModule_GetFilename( module );
+ name = PyModule_GetName( module );
+ if( !txtname || !name)
+ return NULL;
+
+ /* look up the text object */
+ text = ( Text * ) & ( G.main->text.first );
+ while( text ) {
+ if( !strcmp( txtname, GetName( text ) ) )
+ break;
+ text = text->id.next;
+ }
+
+ /* uh-oh.... didn't find it */
+ if( !text )
+ return NULL;
+
+ /* if previously compiled, free the object */
+ /* (can't see how could be NULL, but check just in case) */
+ if( text->compiled ){
+ Py_DECREF( (PyObject *)text->compiled );
+ }
+
+ /* compile the buffer */
+ buf = txt_to_buf( text );
+ text->compiled = Py_CompileString( buf, GetName( text ),
+ Py_file_input );
+ MEM_freeN( buf );
+
+ /* if compile failed.... return this error */
+ if( PyErr_Occurred( ) ) {
+ PyErr_Print( );
+ BPY_free_compiled_text( text );
+ return NULL;
+ }
+
+ /* make into a module */
+ return PyImport_ExecCodeModule( name, text->compiled );
+}
+
+/*
+ * our reload() module, to handle reloading in-memory scripts
+ */
+
+static PyObject *blender_reload( PyObject * self, PyObject * args )
+{
+ PyObject *exception, *err, *tb;
+ PyObject *module = NULL;
+ PyObject *newmodule = NULL;
+
+ /* check for a module arg */
+ if( !PyArg_ParseTuple( args, "O:breload", &module ) )
+ return NULL;
+
+ /* try reimporting from file */
+ newmodule = PyImport_ReloadModule( module );
+ if( newmodule )
+ return newmodule;
+
+ /* no file, try importing from memory */
+ PyErr_Fetch( &exception, &err, &tb ); /*restore for probable later use */
+
+ newmodule = reimportText( module );
+ if( newmodule ) { /* found module, ignore above exception */
+ PyErr_Clear( );
+ Py_XDECREF( exception );
+ Py_XDECREF( err );
+ Py_XDECREF( tb );
+ } else
+ PyErr_Restore( exception, err, tb );
+
+ return newmodule;
+}
+
+static PyMethodDef breload[] = {
+ {"blreload", blender_reload, METH_VARARGS, "our own reload"}
+};
+
+void init_ourReload( void )
+{
+ PyObject *m, *d;
+ PyObject *reload = PyCFunction_New( breload, NULL );
+
+ m = PyImport_AddModule( "__builtin__" );
+ d = PyModule_GetDict( m );
+ EXPP_dict_set_item_str( d, "reload", reload );
+}
diff --git a/source/blender/python/BPY_menus.c b/source/blender/python/BPY_menus.c
new file mode 100644
index 00000000000..5f16aa0241b
--- /dev/null
+++ b/source/blender/python/BPY_menus.c
@@ -0,0 +1,1118 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano, Michael Reimpell
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+/*
+ *This is the main file responsible for having bpython scripts accessible
+ * from Blender menus. To know more, please start with its header file.
+ */
+
+#include "BPY_menus.h"
+
+#include <Python.h>
+#ifndef WIN32
+ #include <dirent.h>
+#else
+ #include "BLI_winstuff.h"
+#endif
+#include "BKE_global.h"
+#include "BKE_utildefines.h"
+#include "BLI_blenlib.h"
+#include "MEM_guardedalloc.h"
+#include "DNA_userdef_types.h" /* for U.pythondir */
+#include "api2_2x/EXPP_interface.h" /* for bpy_gethome() */
+
+#define BPYMENU_DATAFILE "Bpymenus"
+#define MAX_DIR_DEPTH 4 /* max depth for traversing scripts dirs */
+#define MAX_DIR_NUMBER 30 /* max number of dirs in scripts dirs trees */
+
+static int DEBUG;
+static int Dir_Depth;
+static int Dirs_Number;
+
+/* BPyMenuTable holds all registered pymenus, as linked lists for each menu
+ * where they can appear (see PYMENUHOOKS enum in BPY_menus.h).
+*/
+BPyMenu *BPyMenuTable[PYMENU_TOTAL];
+
+static int bpymenu_group_atoi( char *str )
+{
+ if( !strcmp( str, "Export" ) )
+ return PYMENU_EXPORT;
+ else if( !strcmp( str, "Import" ) )
+ return PYMENU_IMPORT;
+ else if( !strcmp( str, "Help" ) )
+ return PYMENU_HELP;
+ else if( !strcmp( str, "HelpWebsites" ) )
+ return PYMENU_HELPWEBSITES;
+ else if( !strcmp( str, "HelpSystem" ) )
+ return PYMENU_HELPSYSTEM;
+ else if( !strcmp( str, "Render" ) )
+ return PYMENU_RENDER;
+ else if( !strcmp( str, "System" ) )
+ return PYMENU_SYSTEM;
+ else if( !strcmp( str, "Object" ) )
+ return PYMENU_OBJECT;
+ else if( !strcmp( str, "Mesh" ) )
+ return PYMENU_MESH;
+ else if( !strncmp( str, "Theme", 5 ) )
+ return PYMENU_THEMES;
+ else if( !strcmp( str, "Add" ) )
+ return PYMENU_ADD;
+ else if( !strcmp( str, "Wizards" ) )
+ return PYMENU_WIZARDS;
+ else if( !strcmp( str, "Animation" ) )
+ return PYMENU_ANIMATION;
+ else if( !strcmp( str, "Materials" ) )
+ return PYMENU_MATERIALS;
+ else if( !strcmp( str, "UV" ) )
+ return PYMENU_UV;
+ else if( !strcmp( str, "Image" ) )
+ return PYMENU_IMAGE;
+ else if( !strcmp( str, "FaceSelect" ) )
+ return PYMENU_FACESELECT;
+ else if( !strcmp( str, "WeightPaint" ) )
+ return PYMENU_WEIGHTPAINT;
+ else if( !strcmp( str, "VertexPaint" ) )
+ return PYMENU_VERTEXPAINT;
+ else if( !strcmp( str, "UVCalculation" ) )
+ return PYMENU_UVCALCULATION;
+ else if( !strcmp( str, "Armature" ) )
+ return PYMENU_ARMATURE;
+ else if( !strcmp( str, "ScriptTemplate" ) )
+ return PYMENU_SCRIPTTEMPLATE;
+ else if( !strcmp( str, "MeshFaceKey" ) )
+ return PYMENU_MESHFACEKEY;
+ else if( !strcmp( str, "AddMesh" ) )
+ return PYMENU_ADDMESH;
+ /* "Misc" or an inexistent group name: use misc */
+ else
+ return PYMENU_MISC;
+}
+
+char *BPyMenu_group_itoa( short menugroup )
+{
+ switch ( menugroup ) {
+ case PYMENU_EXPORT:
+ return "Export";
+ break;
+ case PYMENU_IMPORT:
+ return "Import";
+ break;
+ case PYMENU_ADD:
+ return "Add";
+ break;
+ case PYMENU_HELP:
+ return "Help";
+ break;
+ case PYMENU_HELPWEBSITES:
+ return "HelpWebsites";
+ break;
+ case PYMENU_HELPSYSTEM:
+ return "HelpSystem";
+ break;
+ case PYMENU_RENDER:
+ return "Render";
+ break;
+ case PYMENU_SYSTEM:
+ return "System";
+ break;
+ case PYMENU_OBJECT:
+ return "Object";
+ break;
+ case PYMENU_MESH:
+ return "Mesh";
+ break;
+ case PYMENU_THEMES:
+ return "Themes";
+ break;
+ case PYMENU_WIZARDS:
+ return "Wizards";
+ break;
+ case PYMENU_ANIMATION:
+ return "Animation";
+ break;
+ case PYMENU_MATERIALS:
+ return "Materials";
+ break;
+ case PYMENU_UV:
+ return "UV";
+ break;
+ case PYMENU_IMAGE:
+ return "Image";
+ break;
+ case PYMENU_FACESELECT:
+ return "FaceSelect";
+ break;
+ case PYMENU_WEIGHTPAINT:
+ return "WeightPaint";
+ break;
+ case PYMENU_VERTEXPAINT:
+ return "VertexPaint";
+ break;
+ case PYMENU_UVCALCULATION:
+ return "UVCalculation";
+ break;
+ case PYMENU_ARMATURE:
+ return "Armature";
+ break;
+ case PYMENU_SCRIPTTEMPLATE:
+ return "ScriptTemplate";
+ break;
+ case PYMENU_MESHFACEKEY:
+ return "MeshFaceKey";
+ break;
+ case PYMENU_ADDMESH:
+ return "AddMesh";
+ break;
+ case PYMENU_MISC:
+ return "Misc";
+ break;
+ }
+ return NULL;
+}
+
+/* BPyMenu_CreatePupmenuStr:
+ * build and return a meaninful string to be used by pupmenu(). The
+ * string is made of a bpymenu name as title and its submenus as possible
+ * choices for the user.
+*/
+char *BPyMenu_CreatePupmenuStr( BPyMenu * pym, short menugroup )
+{
+ BPySubMenu *pysm = pym->submenus;
+ char str[1024], str2[100];
+ int i = 0, rlen;
+
+ if( !pym || !pysm )
+ return NULL;
+
+ str[0] = '\0';
+
+ PyOS_snprintf( str2, sizeof( str2 ), "%s: %s%%t",
+ BPyMenu_group_itoa( menugroup ), pym->name );
+ strcat( str, str2 );
+
+ while( pysm ) {
+ PyOS_snprintf( str2, sizeof( str2 ), "|%s%%x%d", pysm->name,
+ i );
+ rlen = sizeof( str ) - strlen( str );
+ strncat( str, str2, rlen );
+ i++;
+ pysm = pysm->next;
+ }
+
+ return BLI_strdup( str );
+}
+
+static void bpymenu_RemoveAllSubEntries( BPySubMenu * smenu )
+{
+ BPySubMenu *tmp;
+
+ while( smenu ) {
+ tmp = smenu->next;
+ if( smenu->name )
+ MEM_freeN( smenu->name );
+ if( smenu->arg )
+ MEM_freeN( smenu->arg );
+ MEM_freeN( smenu );
+ smenu = tmp;
+ }
+ return;
+}
+
+void BPyMenu_RemoveAllEntries( void )
+{
+ BPyMenu *tmp, *pymenu;
+ int i;
+
+ for( i = 0; i < PYMENU_TOTAL; i++ ) {
+ pymenu = BPyMenuTable[i];
+ while( pymenu ) {
+ tmp = pymenu->next;
+ if( pymenu->name )
+ MEM_freeN( pymenu->name );
+ if( pymenu->filename )
+ MEM_freeN( pymenu->filename );
+ if( pymenu->tooltip )
+ MEM_freeN( pymenu->tooltip );
+ if( pymenu->submenus )
+ bpymenu_RemoveAllSubEntries( pymenu->
+ submenus );
+ MEM_freeN( pymenu );
+ pymenu = tmp;
+ }
+ BPyMenuTable[i] = NULL;
+ }
+
+ Dirs_Number = 0;
+ Dir_Depth = 0;
+
+ return;
+}
+
+static BPyMenu *bpymenu_FindEntry( short group, char *name )
+{
+ BPyMenu *pymenu;
+
+ if( ( group < 0 ) || ( group >= PYMENU_TOTAL ) )
+ return NULL;
+
+ pymenu = BPyMenuTable[group];
+
+ while( pymenu ) {
+ if( !strcmp( pymenu->name, name ) )
+ return pymenu;
+ pymenu = pymenu->next;
+ }
+
+ return NULL;
+}
+
+/* BPyMenu_GetEntry:
+ * given a group and a position, return the entry in that position from
+ * that group.
+*/
+BPyMenu *BPyMenu_GetEntry( short group, short pos )
+{
+ BPyMenu *pym = NULL;
+
+ if( ( group < 0 ) || ( group >= PYMENU_TOTAL ) )
+ return NULL;
+
+ pym = BPyMenuTable[group];
+
+ while( pos-- ) {
+ if( pym )
+ pym = pym->next;
+ else
+ break;
+ }
+
+ return pym; /* found entry or NULL */
+}
+
+static void bpymenu_set_tooltip( BPyMenu * pymenu, char *tip )
+{
+ if( !pymenu )
+ return;
+
+ if( pymenu->tooltip )
+ MEM_freeN( pymenu->tooltip );
+ pymenu->tooltip = BLI_strdup( tip );
+
+ return;
+}
+
+/* bpymenu_AddEntry:
+ * try to find an existing pymenu entry with the given type and name;
+ * if found, update it with new info, otherwise create a new one and fill it.
+ */
+static BPyMenu *bpymenu_AddEntry( short group, short version, char *name,
+ char *fname, int is_userdir, char *tooltip )
+{
+ BPyMenu *menu, *next = NULL, **iter;
+ int nameclash = 0;
+
+ if( ( group < 0 ) || ( group >= PYMENU_TOTAL ) )
+ return NULL;
+ if( !name || !fname )
+ return NULL;
+
+ menu = bpymenu_FindEntry( group, name ); /* already exists? */
+
+ /* if a menu with this name already exists in the same group:
+ * - if one script is in the default dir and the other in U.pythondir,
+ * accept and let the new one override the other.
+ * - otherwise, report the error and return NULL. */
+ if( menu ) {
+ if( menu->dir < is_userdir ) { /* new one is in U.pythondir */
+ nameclash = 1;
+ if( menu->name )
+ MEM_freeN( menu->name );
+ if( menu->filename )
+ MEM_freeN( menu->filename );
+ if( menu->tooltip )
+ MEM_freeN( menu->tooltip );
+ if( menu->submenus )
+ bpymenu_RemoveAllSubEntries( menu->submenus );
+ next = menu->next;
+ } else { /* they are in the same dir */
+ if (DEBUG) {
+ fprintf(stderr, "\n\
+Warning: script %s's menu name is already in use.\n\
+Edit the script and change its \n\
+Name: '%s'\n\
+field, please.\n\
+Note: if you really want to have two scripts for the same menu with\n\
+the same name, keep one in the default dir and the other in\n\
+the user defined dir (only the later will be registered).\n", fname, name);
+ }
+ return NULL;
+ }
+ } else
+ menu = MEM_mallocN( sizeof( BPyMenu ), "pymenu" );
+
+ if( !menu )
+ return NULL;
+
+ menu->name = BLI_strdup( name );
+ menu->version = version;
+ menu->filename = BLI_strdup( fname );
+ menu->tooltip = NULL;
+ if( tooltip )
+ menu->tooltip = BLI_strdup( tooltip );
+ menu->dir = is_userdir;
+ menu->submenus = NULL;
+ menu->next = next; /* non-NULL if menu already existed */
+
+ if( nameclash )
+ return menu; /* no need to place it, it's already at the list */
+ else { /* insert the new entry in its correct position at the table */
+ BPyMenu *prev = NULL;
+ char *s = NULL;
+
+ iter = &BPyMenuTable[group];
+ while( *iter ) {
+ s = ( *iter )->name;
+ if( s )
+ if( strcmp( menu->name, s ) < 0 )
+ break; /* sort by names */
+ prev = *iter;
+ iter = &( ( *iter )->next );
+ }
+
+ if( *iter ) { /* prepend */
+ menu->next = *iter;
+ if( prev )
+ prev->next = menu;
+ else
+ BPyMenuTable[group] = menu; /* is first entry */
+ } else
+ *iter = menu; /* append */
+ }
+
+ return menu;
+}
+
+/* bpymenu_AddSubEntry:
+ * add a submenu to an existing python menu.
+ */
+static int bpymenu_AddSubEntry( BPyMenu * mentry, char *name, char *arg )
+{
+ BPySubMenu *smenu, **iter;
+
+ smenu = MEM_mallocN( sizeof( BPySubMenu ), "pysubmenu" );
+ if( !smenu )
+ return -1;
+
+ smenu->name = BLI_strdup( name );
+ smenu->arg = BLI_strdup( arg );
+ smenu->next = NULL;
+
+ if( !smenu->name || !smenu->arg )
+ return -1;
+
+ iter = &( mentry->submenus );
+ while( *iter )
+ iter = &( ( *iter )->next );
+
+ *iter = smenu;
+
+ return 0;
+}
+
+/* bpymenu_CreateFromFile:
+ * parse the bpymenus data file where Python menu data is stored;
+ * based on this data, create and fill the pymenu structs.
+ */
+static int bpymenu_CreateFromFile( void )
+{
+ FILE *fp;
+ char line[255], w1[255], w2[255], tooltip[255], *tip;
+ char *homedir = NULL;
+ int parsing, version, is_userdir;
+ short group;
+ BPyMenu *pymenu = NULL;
+
+ /* init global bpymenu table (it is a list of pointers to struct BPyMenus
+ * for each available cathegory: import, export, etc.) */
+ for( group = 0; group < PYMENU_TOTAL; group++ )
+ BPyMenuTable[group] = NULL;
+
+ /* let's try to open the file with bpymenu data */
+ homedir = bpy_gethome(0);
+ if (!homedir) {
+ if( DEBUG )
+ fprintf(stderr,
+ "BPyMenus error: couldn't open config file Bpymenus: no home dir.\n");
+ return -1;
+ }
+
+ BLI_make_file_string( "/", line, homedir, BPYMENU_DATAFILE );
+
+ fp = fopen( line, "rb" );
+
+ if( !fp ) {
+ if( DEBUG )
+ fprintf(stderr, "BPyMenus error: couldn't open config file %s.\n", line );
+ return -1;
+ }
+
+ fgets( line, 255, fp ); /* header */
+
+ /* check if the U.pythondir we saved at the file is different from the
+ * current one. If so, return to force updating from dirs */
+ w1[0] = '\0';
+ fscanf( fp, "# User defined scripts dir: %[^\n]\n", w1 );
+ if( w1 ) {
+ char upythondir[FILE_MAXDIR];
+
+ BLI_strncpy(upythondir, U.pythondir, FILE_MAXDIR);
+ BLI_convertstringcode(upythondir, G.sce, 0);
+ if( strcmp( w1, upythondir ) != 0 )
+ return -1;
+ w1[0] = '\0';
+ }
+
+ while( fgets( line, 255, fp ) ) { /* parsing file lines */
+
+ switch ( line[0] ) { /* check first char */
+ case '#': /* comment */
+ continue;
+ break;
+ case '\n':
+ continue;
+ break;
+ default:
+ parsing = sscanf( line, "%s {\n", w1 ); /* menu group */
+ break;
+ }
+
+ if( parsing == 1 ) { /* got menu group string */
+ group = (short)bpymenu_group_atoi( w1 );
+ if( group < 0 && DEBUG ) { /* invalid type */
+ fprintf(stderr,
+ "BPyMenus error parsing config file: wrong group: %s,\n\
+will use 'Misc'.\n", w1 );
+ }
+ } else
+ continue;
+
+ for(;;) {
+ tip = NULL; /* optional tooltip */
+ fgets( line, 255, fp );
+ if( line[0] == '}' )
+ break;
+ else if( line[0] == '\n' )
+ continue;
+ else if( line[0] == '\'' ) { /* menu entry */
+ parsing =
+ sscanf( line,
+ "'%[^']' %d %s %d '%[^']'\n",
+ w1, &version, w2, &is_userdir,
+ tooltip );
+
+ if( parsing <= 0 ) { /* invalid line, get rid of it */
+ fgets( line, 255, fp );
+ } else if( parsing == 5 )
+ tip = tooltip; /* has tooltip */
+
+ pymenu = bpymenu_AddEntry( group,
+ ( short ) version,
+ w1, w2, is_userdir,
+ tip );
+ if( !pymenu ) {
+ puts( "BPyMenus error: couldn't create bpymenu entry.\n" );
+ fclose( fp );
+ return -1;
+ }
+ } else if( line[0] == '|' && line[1] == '_' ) { /* menu sub-entry */
+ if( !pymenu )
+ continue; /* no menu yet, skip this line */
+ sscanf( line, "|_%[^:]: %s\n", w1, w2 );
+ bpymenu_AddSubEntry( pymenu, w1, w2 );
+ }
+ }
+ }
+
+ fclose( fp );
+ return 0;
+}
+
+/* bpymenu_WriteDataFile:
+ * writes the registered scripts info to the user's home dir, for faster
+ * access when the scripts dir hasn't changed.
+*/
+static void bpymenu_WriteDataFile( void )
+{
+ BPyMenu *pymenu;
+ BPySubMenu *smenu;
+ FILE *fp;
+ char fname[FILE_MAXDIR], *homedir;
+ int i;
+
+ homedir = bpy_gethome(0);
+
+ if (!homedir) {
+ if( DEBUG )
+ fprintf(stderr,
+ "BPyMenus error: couldn't write Bpymenus file: no home dir.\n\n");
+ return;
+ }
+
+ BLI_make_file_string( "/", fname, homedir, BPYMENU_DATAFILE );
+
+ fp = fopen( fname, "w" );
+ if( !fp ) {
+ if( DEBUG )
+ fprintf(stderr, "BPyMenus error: couldn't write %s file.\n\n",
+ fname );
+ return;
+ }
+
+ fprintf( fp,
+ "# Blender: registered menu entries for bpython scripts\n" );
+
+ if (U.pythondir[0] != '\0' &&
+ strcmp(U.pythondir, "/") != 0 && strcmp(U.pythondir, "//") != 0)
+ {
+ char upythondir[FILE_MAXDIR];
+
+ BLI_strncpy(upythondir, U.pythondir, FILE_MAXDIR);
+ BLI_convertstringcode(upythondir, G.sce, 0);
+ fprintf( fp, "# User defined scripts dir: %s\n", upythondir );
+ }
+
+ for( i = 0; i < PYMENU_TOTAL; i++ ) {
+ pymenu = BPyMenuTable[i];
+ if( !pymenu )
+ continue;
+ fprintf( fp, "\n%s {\n", BPyMenu_group_itoa( (short)i ) );
+ while( pymenu ) {
+ fprintf( fp, "'%s' %d %s %d", pymenu->name,
+ pymenu->version, pymenu->filename,
+ pymenu->dir );
+ if( pymenu->tooltip )
+ fprintf( fp, " '%s'\n", pymenu->tooltip );
+ else
+ fprintf( fp, "\n" );
+ smenu = pymenu->submenus;
+ while( smenu ) {
+ fprintf( fp, "|_%s: %s\n", smenu->name,
+ smenu->arg );
+ smenu = smenu->next;
+ }
+ pymenu = pymenu->next;
+ }
+ fprintf( fp, "}\n" );
+ }
+
+ fclose( fp );
+ return;
+}
+
+/* BPyMenu_PrintAllEntries:
+ * useful for debugging.
+ */
+void BPyMenu_PrintAllEntries( void )
+{
+ BPyMenu *pymenu;
+ BPySubMenu *smenu;
+ int i;
+
+ printf( "# Blender: registered menu entries for bpython scripts\n" );
+
+ for( i = 0; i < PYMENU_TOTAL; i++ ) {
+ pymenu = BPyMenuTable[i];
+ printf( "\n%s {\n", BPyMenu_group_itoa( (short)i ) );
+ while( pymenu ) {
+ printf( "'%s' %d %s %d", pymenu->name, pymenu->version,
+ pymenu->filename, pymenu->dir );
+ if( pymenu->tooltip )
+ printf( " '%s'\n", pymenu->tooltip );
+ else
+ printf( "\n" );
+ smenu = pymenu->submenus;
+ while( smenu ) {
+ printf( "|_%s: %s\n", smenu->name,
+ smenu->arg );
+ smenu = smenu->next;
+ }
+ pymenu = pymenu->next;
+ }
+ printf( "}\n" );
+ }
+}
+
+/* bpymenu_ParseFile:
+ * recursively scans folders looking for scripts to register.
+ *
+ * This function scans the scripts directory looking for .py files with the
+ * right header and menu info, using that to fill the bpymenu structs.
+ * is_userdir defines if the script is in the default scripts dir or the
+ * user defined one (U.pythondir: is_userdir == 1).
+ * Speed is important.
+ *
+ * The first line of the script must be '#!BPY'.
+ * The header registration lines must appear between the first pair of
+ * '\"\"\"' and follow this order (the single-quotes are part of
+ * the format):
+ *
+ * # \"\"\"<br>
+ * # Name: 'script name for the menu'
+ * # Blender: <code>short int</code> (minimal Blender version)
+ * # Group: 'group name' (defines menu)
+ * # Submenu: 'submenu name' related_1word_arg
+ * # Tooltip: 'tooltip for the menu'
+ * # \"\"\"
+ *
+ * Notes:
+ *
+ * - Commenting out header lines with "#" is optional, but recommended.
+ * - There may be more than one submenu line, or none:
+ * submenus and the tooltip are optional;
+ * - The Blender version is the same number reported by
+ * Blender.Get('version') in BPython or G.version in C;
+ * - Line length must be less than 99.
+ */
+static int bpymenu_ParseFile(FILE *file, char *fname, int is_userdir)
+{
+ char line[100];
+ char head[100];
+ char middle[100];
+ char tail[100];
+ int matches;
+ int parser_state;
+
+ char script_name[100];
+ int script_version = 1;
+ int script_group;
+
+ BPyMenu *scriptMenu = NULL;
+
+ if (file != NULL) {
+ parser_state = 1; /* state of parser, 0 to terminate */
+
+ while ((parser_state != 0) && (fgets(line, 100, file) != NULL)) {
+
+ switch (parser_state) {
+
+ case 1: /* !BPY */
+ if (strncmp(line, "#!BPY", 5) == 0) {
+ parser_state++;
+ } else {
+ parser_state = 0;
+ }
+ break;
+
+ case 2: /* \"\"\" */
+ if ((strstr(line, "\"\"\""))) {
+ parser_state++;
+ }
+ break;
+
+ case 3: /* Name: 'script name for the menu' */
+ matches = sscanf(line, "%[^']'%[^']'%c", head, script_name, tail);
+ if ((matches == 3) && (strstr(head, "Name:") != NULL)) {
+ parser_state++;
+ } else {
+ if (DEBUG)
+ fprintf(stderr, "BPyMenus error: Wrong 'Name' line: %s\n", fname);
+ parser_state = 0;
+ }
+ break;
+
+ case 4: /* Blender: <short int> */
+ matches = sscanf(line, "%[^1234567890]%i%c", head, &script_version,
+ tail);
+ if (matches == 3) {
+ parser_state++;
+ } else {
+ if (DEBUG)
+ fprintf(stderr,"BPyMenus error: Wrong 'Blender' line: %s\n",fname);
+ parser_state = 0;
+ }
+ break;
+
+ case 5: /* Group: 'group name' */
+ matches = sscanf(line, "%[^']'%[^']'%c", head, middle, tail);
+ if ((matches == 3) && (strstr(head, "Group:") != NULL)) {
+ script_group = bpymenu_group_atoi(middle);
+ if (script_group < 0) {
+ if (DEBUG)
+ fprintf(stderr, "BPyMenus error: Unknown group \"%s\": %s\n",
+ middle, fname);
+ parser_state = 0;
+ }
+
+ else { /* register script */
+ scriptMenu = bpymenu_AddEntry((short)script_group,
+ (short int)script_version, script_name, fname, is_userdir,NULL);
+ if (scriptMenu == NULL) {
+ if (DEBUG)
+ fprintf(stderr,
+ "BPyMenus error: Couldn't create entry for: %s\n", fname);
+ parser_state = 0;
+ } else {
+ parser_state++;
+ }
+ }
+
+ } else {
+ if (DEBUG)
+ fprintf(stderr, "BPyMenus error: Wrong 'Group' line: %s\n",fname);
+ parser_state = 0;
+ }
+ break;
+
+ case 6: /* optional elements */
+ /* Submenu: 'submenu name' related_1word_arg */
+ matches = sscanf(line, "%[^']'%[^']'%s\n", head, middle, tail);
+ if ((matches == 3) && (strstr(head, "Submenu:") != NULL)) {
+ bpymenu_AddSubEntry(scriptMenu, middle, tail);
+ } else {
+ /* Tooltip: 'tooltip for the menu */
+ matches = sscanf(line, "%[^']'%[^']'%c", head, middle, tail);
+ if ((matches == 3) && ((strstr(head, "Tooltip:") != NULL) ||
+ (strstr(head, "Tip:") != NULL))) {
+ bpymenu_set_tooltip(scriptMenu, middle);
+ }
+ parser_state = 0;
+ }
+ break;
+
+ default:
+ parser_state = 0;
+ break;
+ }
+ }
+ }
+
+ else { /* shouldn't happen, it's checked in bpymenus_ParseDir */
+ if (DEBUG)
+ fprintf(stderr, "BPyMenus error: Couldn't open %s.\n", fname);
+ return -1;
+ }
+
+ return 0;
+}
+
+/* bpymenu_ParseDir:
+ * recursively scans folders looking for scripts to register.
+ *
+ * This function scans the scripts directory looking for .py files with the
+ * right header and menu info.
+ * - is_userdir defines if the script is in the default scripts dir or the
+ * user defined one (U.pythondir: is_userdir == 1);
+ * - parentdir is the parent dir name to store as part of the script filename,
+ * if we're down a subdir.
+ * Speed is important.
+ */
+static int bpymenu_ParseDir(char *dirname, char *parentdir, int is_userdir )
+{
+ DIR *dir;
+ FILE *file = NULL;
+ struct dirent *de;
+ struct stat status;
+ char *file_extension;
+ char path[FILE_MAX];
+ char subdir[FILE_MAX];
+ char *s = NULL;
+
+ dir = opendir(dirname);
+
+ if (dir != NULL) {
+ while ((de = readdir(dir)) != NULL) {
+
+ /* skip files and dirs starting with '.' or 'bpy' */
+ if ((de->d_name[0] == '.') || !strncmp(de->d_name, "bpy", 3)) {
+ continue;
+ }
+
+ BLI_make_file_string("/", path, dirname, de->d_name);
+
+ if (stat(path, &status) != 0) {
+ if (DEBUG)
+ fprintf(stderr, "stat %s failed: %s\n", path, strerror(errno));
+ }
+
+ if (S_ISREG(status.st_mode)) { /* is file */
+
+ file_extension = strstr(de->d_name, ".py");
+
+ if (file_extension && *(file_extension + 3) == '\0') {
+ file = fopen(path, "rb");
+
+ if (file) {
+ s = de->d_name;
+ if (parentdir) {
+ /* Join parentdir and de->d_name */
+ BLI_join_dirfile(subdir, parentdir, de->d_name);
+
+ s = subdir;
+ }
+ bpymenu_ParseFile(file, s, is_userdir);
+ fclose(file);
+ }
+
+ else {
+ if (DEBUG)
+ fprintf(stderr, "BPyMenus error: Couldn't open %s.\n", path);
+ }
+ }
+ }
+
+ else if (S_ISDIR(status.st_mode)) { /* is subdir */
+ Dirs_Number++;
+ Dir_Depth++;
+ if (Dirs_Number > MAX_DIR_NUMBER) {
+ if (DEBUG) {
+ fprintf(stderr, "BPyMenus error: too many subdirs.\n");
+ }
+ closedir(dir);
+ return -1;
+ }
+ else if (Dir_Depth > MAX_DIR_DEPTH) {
+ if (DEBUG)
+ fprintf(stderr,
+ "BPyMenus error: max depth reached traversing dir tree.\n");
+ closedir(dir);
+ return -1;
+ }
+ s = de->d_name;
+ if (parentdir) {
+ /* Join parentdir and de->d_name */
+ BLI_join_dirfile(subdir, parentdir, de->d_name);
+ s = subdir;
+ }
+ if (bpymenu_ParseDir(path, s, is_userdir) == -1) {
+ closedir(dir);
+ return -1;
+ }
+ Dir_Depth--;
+ }
+
+ }
+ closedir(dir);
+ }
+
+ else { /* open directory stream failed */
+ if (DEBUG)
+ fprintf(stderr, "opendir %s failed: %s\n", dirname, strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int bpymenu_GetStatMTime( char *name, int is_file, time_t * mtime )
+{
+ struct stat st;
+ int result;
+
+ result = stat( name, &st );
+
+ if( result == -1 )
+ return -1;
+
+ if( is_file ) {
+ if( !S_ISREG( st.st_mode ) )
+ return -2;
+ } else if( !S_ISDIR( st.st_mode ) )
+ return -2;
+
+ *mtime = st.st_mtime;
+
+ return 0;
+}
+
+/* BPyMenu_Init:
+ * import the bpython menus data to Blender, either from:
+ * - the BPYMENU_DATAFILE file (?/.blender/Bpymenus) or
+ * - the scripts dir(s), case newer than the datafile (then update the file).
+ * then fill the bpymenu table with this data.
+ * if param usedir != 0, then the data is recreated from the dir(s) anyway.
+*/
+int BPyMenu_Init( int usedir )
+{
+ char fname[FILE_MAXDIR];
+ char dirname[FILE_MAXDIR];
+ char upythondir[FILE_MAXDIR];
+ char *upydir = U.pythondir, *sdir = NULL;
+ time_t time_dir1 = 0, time_dir2 = 0, time_file = 0;
+ int stat_dir1 = 0, stat_dir2 = 0, stat_file = 0;
+ int i;
+
+ DEBUG = G.f & G_DEBUG; /* is Blender in debug mode (started with -d) ? */
+
+ /* init global bpymenu table (it is a list of pointers to struct BPyMenus
+ * for each available group: import, export, etc.) */
+ for( i = 0; i < PYMENU_TOTAL; i++ )
+ BPyMenuTable[i] = NULL;
+
+ if( DEBUG )
+ fprintf(stdout, "\nRegistering scripts in Blender menus ...\n\n" );
+
+ if( U.pythondir[0] == '\0') {
+ upydir = NULL;
+ }
+ else if (strcmp(U.pythondir, "/") == 0 || strcmp(U.pythondir, "//") == 0) {
+ /* these are not accepted to prevent possible slight slowdowns on startup;
+ * they should not be used as user defined scripts dir, anyway, also from
+ * speed considerations, since they'd not be dedicated scripts dirs */
+ if (DEBUG) fprintf(stderr,
+ "BPyMenus: invalid user defined Python scripts dir: \"/\" or \"//\".\n");
+ upydir = NULL;
+ }
+ else {
+ BLI_strncpy(upythondir, upydir, FILE_MAXDIR);
+ BLI_convertstringcode(upythondir, G.sce, 0);
+ }
+
+ sdir = bpy_gethome(1);
+
+ if (sdir) {
+ BLI_strncpy(dirname, sdir, FILE_MAXDIR);
+ stat_dir1 = bpymenu_GetStatMTime( dirname, 0, &time_dir1 );
+
+ if( stat_dir1 < 0 ) {
+ time_dir1 = 0;
+ if( DEBUG ) {
+ fprintf(stderr,
+ "\nDefault scripts dir: %s:\n%s\n", dirname, strerror(errno));
+ if( upydir )
+ fprintf(stdout,
+ "Getting scripts menu data from user defined dir: %s.\n",
+ upythondir );
+ }
+ }
+ }
+ else stat_dir1 = -1;
+
+ if( upydir ) {
+ stat_dir2 = bpymenu_GetStatMTime( upythondir, 0, &time_dir2 );
+
+ if( stat_dir2 < 0 ) {
+ time_dir2 = 0;
+ upydir = NULL;
+ if( DEBUG )
+ fprintf(stderr, "\nUser defined scripts dir: %s:\n%s.\n",
+ upythondir, strerror( errno ) );
+ if( stat_dir1 < 0 ) {
+ if( DEBUG )
+ fprintf(stderr, "\
+To have scripts in menus, please add them to the default scripts dir:\n\
+%s\n\
+and / or go to 'Info window -> File Paths tab' and set a valid path for\n\
+the user defined Python scripts dir.\n", dirname );
+ return -1;
+ }
+ }
+ }
+ else stat_dir2 = -1;
+
+ if( ( stat_dir1 < 0 ) && ( stat_dir2 < 0 ) ) {
+ if( DEBUG ) {
+ fprintf(stderr, "\nCannot register scripts in menus, no scripts dir"
+ " available.\nExpected default dir at: %s \n", dirname );
+ }
+ return -1;
+ }
+
+ if (usedir) stat_file = -1;
+ else { /* if we're not forced to use the dir */
+ char *homedir = bpy_gethome(0);
+
+ if (homedir) {
+ BLI_make_file_string( "/", fname, homedir, BPYMENU_DATAFILE );
+ stat_file = bpymenu_GetStatMTime( fname, 1, &time_file );
+ if( stat_file < 0 )
+ time_file = 0;
+
+ /* comparing dates */
+
+ if((stat_file == 0)
+ && (time_file > time_dir1) && (time_file > time_dir2))
+ { /* file is newer */
+ stat_file = bpymenu_CreateFromFile( ); /* -1 if an error occurred */
+ if( !stat_file && DEBUG )
+ fprintf(stdout,
+ "Getting menu data for scripts from file:\n%s\n\n", fname );
+ }
+ else stat_file = -1;
+ }
+ else stat_file = -1; /* -1 to use dirs: didn't use file or it was corrupted */
+ }
+
+ if( stat_file == -1 ) { /* use dirs */
+ if( DEBUG ) {
+ fprintf(stdout,
+ "Getting menu data for scripts from dir(s):\ndefault: %s\n", dirname );
+ if( upydir )
+ fprintf(stdout, "user defined: %s\n", upythondir );
+ fprintf(stdout, "\n");
+ }
+ if( stat_dir1 == 0 ) {
+ i = bpymenu_ParseDir( dirname, NULL, 0 );
+ if (i == -1 && DEBUG)
+ fprintf(stderr, "Default scripts dir does not seem valid.\n\n");
+ }
+ if( stat_dir2 == 0 ) {
+ BLI_strncpy(dirname, U.pythondir, FILE_MAXDIR);
+ BLI_convertstringcode(dirname, G.sce, 0);
+ i = bpymenu_ParseDir( dirname, NULL, 1 );
+ if (i == -1 && DEBUG)
+ fprintf(stderr, "User defined scripts dir does not seem valid.\n\n");
+ }
+
+ /* check if we got any data */
+ for( i = 0; i < PYMENU_TOTAL; i++ )
+ if( BPyMenuTable[i] )
+ break;
+
+ /* if we got, recreate the file */
+ if( i < PYMENU_TOTAL )
+ bpymenu_WriteDataFile( );
+ else if( DEBUG ) {
+ fprintf(stderr, "\n\
+Warning: Registering scripts in menus -- no info found.\n\
+Either your scripts dirs have no .py scripts or the scripts\n\
+don't have a header with registration data.\n\
+Default scripts dir is:\n\
+%s\n", dirname );
+ if( upydir )
+ fprintf(stderr, "User defined scripts dir is: %s\n",
+ upythondir );
+ }
+ }
+
+ return 0;
+}
diff --git a/source/blender/python/BPY_menus.h b/source/blender/python/BPY_menus.h
new file mode 100644
index 00000000000..89491ce3ef2
--- /dev/null
+++ b/source/blender/python/BPY_menus.h
@@ -0,0 +1,128 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano, Matt Ebb
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef BPY_MENUS_H
+#define BPY_MENUS_H
+
+/* This header exposes BPyMenu related public declarations. The implementation
+ * adds 'dynamic' menus to Blender, letting scripts register themselves in any
+ * of a few pre-defined (trivial to upgrade) places in menus. These places or
+ * slots are called groups here (Import, Export, etc). This is how it works:
+ * - scripts at dirs user pref U.pythondir and .blender/scripts/ are scanned
+ * for registration info.
+ * - this data is also saved to a Bpymenus file at the user's .blender/ dir and
+ * only re-created when the scripts folder gets modified.
+ * - on start-up Blender uses this info to fill a table, which is used to
+ * create the menu entries when they are needed (see header_info.c or
+ * header_script.c, under source/blender/src/, for examples).
+*/
+
+/* These two structs hold py menu/submenu info.
+ * BPyMenu holds a script's name (as should appear in the menu) and filename,
+ * plus an optional list of submenus. Each submenu is related to a string
+ * (arg) that the script can get from the __script__ pydict, to know which
+ * submenu was chosen. */
+
+typedef struct BPySubMenu {
+ char *name;
+ char *arg;
+ struct BPySubMenu *next;
+} BPySubMenu;
+
+typedef struct BPyMenu {
+ char *name;
+ char *filename;
+ char *tooltip;
+ short version; /* Blender version */
+ int dir; /* 0: default, 1: U.pythondir */
+ struct BPySubMenu *submenus;
+ struct BPyMenu *next;
+} BPyMenu;
+
+/* Scripts can be added to only a few pre-defined places in menus, like
+ * File->Import, File->Export, etc. (for speed and better control).
+ * To make a new menu 'slot' available for scripts:
+ * - add an entry to the enum below, before PYMENU_TOTAL, of course;
+ * - update the bpymenu_group_atoi() and BPyMenu_group_itoa() functions in
+ * BPY_menus.c;
+ * - add the necessary code to the header_***.c file in
+ * source/blender/src/, like done in header_info.c for import/export;
+*/
+typedef enum {
+ PYMENU_ADD,/* creates new objects */
+ PYMENU_ANIMATION,
+ PYMENU_EXPORT,
+ PYMENU_IMPORT,
+ PYMENU_MATERIALS,
+ PYMENU_MESH,
+ PYMENU_MISC,
+ PYMENU_OBJECT,
+ PYMENU_RENDER,/* exporters to external renderers */
+ PYMENU_SYSTEM,
+ PYMENU_THEMES,
+ PYMENU_UV,/* UV editing tools, to go in UV/Image editor space, 'UV' menu */
+ PYMENU_IMAGE,/* Image editing tools, to go in UV/Image editor space, 'Image' menu */
+ PYMENU_WIZARDS,/* complex 'app' scripts */
+
+ /* entries put after Wizards don't appear at the Scripts win->Scripts menu;
+ * see define right below */
+
+ PYMENU_FACESELECT,
+ PYMENU_WEIGHTPAINT,
+ PYMENU_VERTEXPAINT,
+ PYMENU_UVCALCULATION,
+ PYMENU_ARMATURE,
+ PYMENU_SCRIPTTEMPLATE,
+ PYMENU_HELP,/*Main Help menu items - prob best to leave for 'official' ones*/
+ PYMENU_HELPSYSTEM,/* Resources, troubleshooting, system tools */
+ PYMENU_HELPWEBSITES,/* Help -> Websites submenu */
+ PYMENU_MESHFACEKEY, /* face key in mesh editmode */
+ PYMENU_ADDMESH, /* adds mesh */
+ PYMENU_TOTAL
+} PYMENUHOOKS;
+
+#define PYMENU_SCRIPTS_MENU_TOTAL (PYMENU_WIZARDS + 1)
+
+/* BPyMenuTable holds all registered pymenus, as linked lists for each menu
+ * where they can appear (see PYMENUHOOKS enum above).
+*/
+extern BPyMenu *BPyMenuTable[]; /* defined in BPY_menus.c */
+
+/* public functions: */
+int BPyMenu_Init( int usedir );
+void BPyMenu_RemoveAllEntries( void );
+void BPyMenu_PrintAllEntries( void );
+char *BPyMenu_CreatePupmenuStr( BPyMenu * pym, short group );
+char *BPyMenu_group_itoa( short group );
+struct BPyMenu *BPyMenu_GetEntry( short group, short pos );
+
+#endif /* BPY_MENUS_H */
diff --git a/source/blender/python/CMakeLists.txt b/source/blender/python/CMakeLists.txt
new file mode 100644
index 00000000000..7df1f8a02d5
--- /dev/null
+++ b/source/blender/python/CMakeLists.txt
@@ -0,0 +1,57 @@
+# $Id$
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2006, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Jacques Beaurain.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+
+FILE(GLOB SRC api2_2x/*.c)
+SET(SRC ${SRC}
+ BPY_interface.c
+ BPY_menus.c
+)
+
+SET(INC
+ api2_2x ../blenkernel ../blenlib ../blenloader
+ ../render/extern/include ../radiosity/extern/include
+ ../makesdna ../../../intern/guardedalloc ../../../intern/bmfont ../imbuf ../include
+ ${PYTHON_INC}
+)
+
+IF(WITH_QUICKTIME)
+ SET(INC ${INC} ${QUICKTIME_INC})
+ ADD_DEFINITIONS(-DWITH_QUICKTIME)
+ENDIF(WITH_QUICKTIME)
+
+IF(WITH_OPENEXR)
+ ADD_DEFINITIONS(-DWITH_OPENEXR)
+ENDIF(WITH_OPENEXR)
+
+IF(WITH_FFMPEG)
+ ADD_DEFINITIONS(-DWITH_FFMPEG)
+ENDIF(WITH_FFMPEG)
+
+BLENDERLIB_NOLIST(blender_python "${SRC}" "${INC}")
+#env.BlenderLib ( libname='blender_python', sources = Split(sources), includes = Split(incs), defines = defs, libtype=['core','game2'], priority = [60,115] )
diff --git a/source/blender/python/Makefile b/source/blender/python/Makefile
new file mode 100644
index 00000000000..149e40092f3
--- /dev/null
+++ b/source/blender/python/Makefile
@@ -0,0 +1,37 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+# Bounces make to subdirectories.
+
+SOURCEDIR = source/blender/python
+DIRS = api2_2x
+
+include nan_subdirs.mk
diff --git a/source/blender/python/SConscript b/source/blender/python/SConscript
new file mode 100644
index 00000000000..9cd245394b0
--- /dev/null
+++ b/source/blender/python/SConscript
@@ -0,0 +1,26 @@
+#!/usr/bin/python
+Import ('env')
+
+sources = Split('BPY_interface.c BPY_menus.c') + env.Glob('api2_2x/*.c')
+
+incs = 'api2_2x ../blenkernel ../blenlib ../blenloader'
+incs += ' ../render/extern/include ../radiosity/extern/include'
+incs += ' ../makesdna #intern/guardedalloc #intern/bmfont ../imbuf ../include'
+incs += ' ' + env['BF_PYTHON_INC']
+incs += ' ' + env['BF_OPENGL_INC']
+
+defs = []
+if env['OURPLATFORM'] in ('win32-mingw') and env['BF_DEBUG']:
+ defs.append('Py_TRACE_REFS')
+
+if env['WITH_BF_QUICKTIME']==1:
+ incs += ' ' + env['BF_QUICKTIME_INC']
+ defs.append('WITH_QUICKTIME')
+
+if env['WITH_BF_OPENEXR'] == 1:
+ defs.append('WITH_OPENEXR')
+
+if env['WITH_BF_FFMPEG'] == 1:
+ defs.append('WITH_FFMPEG')
+
+env.BlenderLib ( libname='blender_python', sources = Split(sources), includes = Split(incs), defines = defs, libtype=['core','game2'], priority = [60,115] )
diff --git a/source/blender/python/api2_2x/Armature.c b/source/blender/python/api2_2x/Armature.c
new file mode 100644
index 00000000000..6c22e831bd4
--- /dev/null
+++ b/source/blender/python/api2_2x/Armature.c
@@ -0,0 +1,1490 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#include <stddef.h>
+
+#include "Armature.h" //This must come first
+
+#include "BKE_main.h"
+#include "BKE_global.h"
+#include "BKE_armature.h"
+#include "BKE_library.h"
+#include "BKE_depsgraph.h"
+#include "BKE_utildefines.h"
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "MEM_guardedalloc.h"
+#include "Bone.h"
+#include "NLA.h"
+#include "gen_utils.h"
+#include "gen_library.h"
+
+#include "DNA_object_types.h" //This must come before BIF_editarmature.h...
+#include "BIF_editarmature.h"
+
+//------------------EXTERNAL PROTOTYPES--------------------
+extern void make_boneList(ListBase* list, ListBase *bones, EditBone *parent);
+extern void editbones_to_armature (ListBase *list, Object *ob);
+
+//------------------------ERROR CODES---------------------------------
+//This is here just to make me happy and to have more consistant error strings :)
+static const char sBoneDictError[] = "ArmatureType.bones - Error: ";
+static const char sBoneDictBadArgs[] = "ArmatureType.bones - Bad Arguments: ";
+static const char sArmatureError[] = "ArmatureType - Error: ";
+static const char sArmatureBadArgs[] = "ArmatureType - Bad Arguments: ";
+static const char sModuleError[] = "Blender.Armature - Error: ";
+static const char sModuleBadArgs[] = "Blender.Armature - Bad Arguments: ";
+
+PyObject * arm_weakref_callback_weakref_dealloc(PyObject *self, PyObject *weakref);
+/* python callable */
+PyObject * arm_weakref_callback_weakref_dealloc__pyfunc;
+
+//################## BonesDict_Type (internal) ########################
+/*This is an internal psuedo-dictionary type that allows for manipulation
+* of bones inside of an armature. It is a subobject of armature.
+* i.e. Armature.bones['key']*/
+//#####################################################################
+
+//------------------METHOD IMPLEMENTATIONS-----------------------------
+//------------------------Armature.bones.items()
+//Returns a list of key:value pairs like dict.items()
+static PyObject* BonesDict_items(BPy_BonesDict *self)
+{
+ if (self->editmode_flag){
+ return PyDict_Items(self->editbonesMap);
+ }else{
+ return PyDict_Items(self->bonesMap);
+ }
+}
+//------------------------Armature.bones.keys()
+//Returns a list of keys like dict.keys()
+static PyObject* BonesDict_keys(BPy_BonesDict *self)
+{
+ if (self->editmode_flag){
+ return PyDict_Keys(self->editbonesMap);
+ }else{
+ return PyDict_Keys(self->bonesMap);
+ }
+}
+//------------------------Armature.bones.values()
+//Returns a list of values like dict.values()
+static PyObject* BonesDict_values(BPy_BonesDict *self)
+{
+ if (self->editmode_flag){
+ return PyDict_Values(self->editbonesMap);
+ }else{
+ return PyDict_Values(self->bonesMap);
+ }
+}
+//------------------ATTRIBUTE IMPLEMENTATION---------------------------
+//------------------TYPE_OBECT IMPLEMENTATION-----------------------
+//------------------------tp_doc
+//The __doc__ string for this object
+static char BPy_BonesDict_doc[] = "This is an internal subobject of armature\
+designed to act as a Py_Bone dictionary.";
+
+//------------------------tp_methods
+//This contains a list of all methods the object contains
+static PyMethodDef BPy_BonesDict_methods[] = {
+ {"items", (PyCFunction) BonesDict_items, METH_NOARGS,
+ "() - Returns the key:value pairs from the dictionary"},
+ {"keys", (PyCFunction) BonesDict_keys, METH_NOARGS,
+ "() - Returns the keys the dictionary"},
+ {"values", (PyCFunction) BonesDict_values, METH_NOARGS,
+ "() - Returns the values from the dictionary"},
+ {NULL, NULL, 0, NULL}
+};
+//-----------------(internal)
+static int BoneMapping_Init(PyObject *dictionary, ListBase *bones){
+ Bone *bone = NULL;
+ PyObject *py_bone = NULL;
+
+ for (bone = bones->first; bone; bone = bone->next){
+ py_bone = PyBone_FromBone(bone);
+ if (!py_bone)
+ return -1;
+
+ if(PyDict_SetItemString(dictionary, bone->name, py_bone) == -1) {
+ /* unlikely but possible */
+ Py_DECREF(py_bone);
+ return -1;
+ }
+
+ Py_DECREF(py_bone);
+ if (bone->childbase.first)
+ BoneMapping_Init(dictionary, &bone->childbase);
+ }
+ return 0;
+}
+//-----------------(internal)
+static int EditBoneMapping_Init(PyObject *dictionary, ListBase *editbones){
+ EditBone *editbone = NULL;
+ PyObject *py_editbone = NULL;
+
+ for (editbone = editbones->first; editbone; editbone = editbone->next){
+ py_editbone = PyEditBone_FromEditBone(editbone);
+ if (!py_editbone)
+ return -1;
+
+ if(PyDict_SetItemString(dictionary, editbone->name, py_editbone) == -1) {
+ Py_DECREF(py_editbone);
+ return -1;
+ }
+ Py_DECREF(py_editbone);
+ }
+ return 0;
+}
+//----------------- BonesDict_InitBones
+static int BonesDict_InitBones(BPy_BonesDict *self)
+{
+ PyDict_Clear(self->bonesMap);
+ if (BoneMapping_Init(self->bonesMap, self->bones) == -1)
+ return 0;
+ return 1;
+}
+//----------------- BonesDict_InitEditBones
+static int BonesDict_InitEditBones(BPy_BonesDict *self)
+{
+ PyDict_Clear(self->editbonesMap);
+ if (EditBoneMapping_Init(self->editbonesMap, &self->editbones) == -1)
+ return 0;
+ return 1;
+}
+//------------------------tp_repr
+//This is the string representation of the object
+static PyObject *BonesDict_repr(BPy_BonesDict *self)
+{
+ char str[2048];
+ PyObject *key, *value;
+ int pos = 0;
+ char *p = str;
+ char *keys, *vals;
+
+ p += sprintf(str, "[Bone Dict: {");
+
+ if (self->editmode_flag){
+ while (PyDict_Next(self->editbonesMap, &pos, &key, &value)) {
+ keys = PyString_AsString(key);
+ vals = PyString_AsString(value->ob_type->tp_repr(value));
+ if( strlen(str) + strlen(keys) + strlen(vals) < sizeof(str)-20 )
+ p += sprintf(p, "%s : %s, ", keys, vals );
+ else {
+ p += sprintf(p, "...." );
+ break;
+ }
+ }
+ }else{
+ while (PyDict_Next(self->bonesMap, &pos, &key, &value)) {
+ keys = PyString_AsString(key);
+ vals = PyString_AsString(value->ob_type->tp_repr(value));
+ if( strlen(str) + strlen(keys) + strlen(vals) < sizeof(str)-20 )
+ p += sprintf(p, "%s : %s, ", keys, vals );
+ else {
+ p += sprintf(p, "...." );
+ break;
+ }
+ }
+ }
+ sprintf(p, "}]");
+ return PyString_FromString(str);
+}
+
+//------------------------tp_dealloc
+//This tells how to 'tear-down' our object when ref count hits 0
+static void BonesDict_dealloc(BPy_BonesDict * self)
+{
+ Py_DECREF(self->bonesMap);
+ Py_DECREF(self->editbonesMap);
+ BLI_freelistN(&self->editbones);
+ PyObject_DEL( self );
+ return;
+}
+//------------------------mp_length
+//This gets the size of the dictionary
+static int BonesDict_len(BPy_BonesDict *self)
+{
+ if (self->editmode_flag){
+ return BLI_countlist(&self->editbones);
+ }else{
+ return BLI_countlist(self->bones);
+ }
+}
+//-----------------------mp_subscript
+//This defines getting a bone from the dictionary - x = Bones['key']
+static PyObject *BonesDict_GetItem(BPy_BonesDict *self, PyObject* key)
+{
+ PyObject *value = NULL;
+
+ if (self->editmode_flag){
+ value = PyDict_GetItem(self->editbonesMap, key);
+ }else{
+ value = PyDict_GetItem(self->bonesMap, key);
+ }
+ if(value == NULL){ /* item not found in dict. throw exception */
+ char* key_str = PyString_AsString( key );
+ if (key_str) {
+ return EXPP_ReturnPyObjError(PyExc_KeyError, "bone key must be a string" );
+ } else {
+ char buffer[128];
+ PyOS_snprintf( buffer, sizeof(buffer), "bone %s not found", key_str);
+ return EXPP_ReturnPyObjError(PyExc_KeyError, buffer );
+ }
+ }
+ return EXPP_incr_ret(value);
+}
+//-----------------------mp_ass_subscript
+//This does dict assignment - Bones['key'] = value
+static int BonesDict_SetItem(BPy_BonesDict *self, PyObject *key, PyObject *value)
+{
+ BPy_EditBone *editbone_for_deletion;
+ struct EditBone *editbone = NULL;
+ char *key_str = PyString_AsString(key);
+
+ if (!self->editmode_flag)
+ return EXPP_intError(PyExc_AttributeError, "%s%s",
+ sBoneDictBadArgs, "You must call makeEditable() first");
+
+ if (!key_str)
+ return EXPP_intError(PyExc_AttributeError, "%s%s",
+ sBoneDictBadArgs, "The key must be the name of an editbone");
+
+ if (value && !EditBoneObject_Check(value))
+ return EXPP_intError(PyExc_AttributeError, "%s%s",
+ sBoneDictBadArgs, "Can only assign editbones as values");
+
+ //parse value for assignment
+ if (value){ /* we know this must be an editbone from the above check */
+ //create a new editbone
+ editbone = MEM_callocN(sizeof(EditBone), "eBone");
+ BLI_strncpy(editbone->name, key_str, 32);
+ unique_editbone_name(NULL, editbone->name);
+ editbone->dist = ((BPy_EditBone*)value)->dist;
+ editbone->ease1 = ((BPy_EditBone*)value)->ease1;
+ editbone->ease2 = ((BPy_EditBone*)value)->ease2;
+ editbone->flag = ((BPy_EditBone*)value)->flag;
+ editbone->parent = ((BPy_EditBone*)value)->parent;
+ editbone->rad_head = ((BPy_EditBone*)value)->rad_head;
+ editbone->rad_tail = ((BPy_EditBone*)value)->rad_tail;
+ editbone->roll = ((BPy_EditBone*)value)->roll;
+ editbone->segments = ((BPy_EditBone*)value)->segments;
+ editbone->weight = ((BPy_EditBone*)value)->weight;
+ editbone->xwidth = ((BPy_EditBone*)value)->xwidth;
+ editbone->zwidth = ((BPy_EditBone*)value)->zwidth;
+ VECCOPY(editbone->head, ((BPy_EditBone*)value)->head);
+ VECCOPY(editbone->tail, ((BPy_EditBone*)value)->tail);
+ editbone->layer= ((BPy_EditBone*)value)->layer;
+
+ //set object pointer
+ ((BPy_EditBone*)value)->editbone = editbone;
+
+ //fix the bone's head position if flags indicate that it is 'connected'
+ if (editbone->flag & BONE_CONNECTED){
+ if(!editbone->parent){
+ ((BPy_EditBone*)value)->editbone = NULL;
+ MEM_freeN(editbone);
+ return EXPP_intError(PyExc_AttributeError, "%s%s",
+ sBoneDictBadArgs, "The 'connected' flag is set but the bone has no parent!");
+ }else{
+ VECCOPY(editbone->head, editbone->parent->tail);
+ }
+ }
+
+ //set in editbonelist
+ BLI_addtail(&self->editbones, editbone);
+
+ //set the new editbone in the mapping
+ if(PyDict_SetItemString(self->editbonesMap, key_str, value) == -1){
+ ((BPy_EditBone*)value)->editbone = NULL;
+ BLI_freelinkN(&self->editbones, editbone);
+ return EXPP_intError(PyExc_RuntimeError, "%s%s",
+ sBoneDictError, "Unable to access dictionary!");
+ }
+ }else {
+ //they are trying to delete the bone using 'del'
+ editbone_for_deletion = (BPy_EditBone*)PyDict_GetItem(self->editbonesMap, key);
+
+ if (!editbone_for_deletion)
+ return EXPP_intError(PyExc_KeyError, "%s%s%s%s",
+ sBoneDictError, "The key: ", key_str, " is not present in this dictionary!");
+
+ /*first kill the datastruct then remove the item from the dict
+ and wait for GC to pick it up.
+ We have to delete the datastruct here because the tp_dealloc
+ doesn't handle it*/
+
+ /*this is ugly but you have to set the parent to NULL for else
+ editbones_to_armature will crash looking for this bone*/
+ for (editbone = self->editbones.first; editbone; editbone = editbone->next){
+ if (editbone->parent == editbone_for_deletion->editbone) {
+ editbone->parent = NULL;
+ /* remove the connected flag or else the 'root' ball
+ * doesn't get drawn */
+ editbone->flag &= ~BONE_CONNECTED;
+ }
+ }
+ BLI_freelinkN(&self->editbones, editbone_for_deletion->editbone);
+ if(PyDict_DelItem(self->editbonesMap, key) == -1)
+ return EXPP_intError(PyExc_RuntimeError, "%s%s",
+ sBoneDictError, "Unable to access dictionary!");
+ }
+ return 0;
+}
+//------------------TYPE_OBJECT DEFINITION--------------------------
+//Mapping Protocol
+static PyMappingMethods BonesDict_MapMethods = {
+ (inquiry) BonesDict_len, //mp_length
+ (binaryfunc)BonesDict_GetItem, //mp_subscript
+ (objobjargproc)BonesDict_SetItem, //mp_ass_subscript
+};
+//BonesDict TypeObject
+PyTypeObject BonesDict_Type = {
+ PyObject_HEAD_INIT(NULL) //tp_head
+ 0, //tp_internal
+ "BonesDict", //tp_name
+ sizeof(BPy_BonesDict), //tp_basicsize
+ 0, //tp_itemsize
+ (destructor)BonesDict_dealloc, //tp_dealloc
+ 0, //tp_print
+ 0, //tp_getattr
+ 0, //tp_setattr
+ 0, //tp_compare
+ (reprfunc) BonesDict_repr, //tp_repr
+ 0, //tp_as_number
+ 0, //tp_as_sequence
+ &BonesDict_MapMethods, //tp_as_mapping
+ 0, //tp_hash
+ 0, //tp_call
+ 0, //tp_str
+ 0, //tp_getattro
+ 0, //tp_setattro
+ 0, //tp_as_buffer
+ Py_TPFLAGS_DEFAULT, //tp_flags
+ BPy_BonesDict_doc, //tp_doc
+ 0, //tp_traverse
+ 0, //tp_clear
+ 0, //tp_richcompare
+ 0, //tp_weaklistoffset
+ 0, //tp_iter
+ 0, //tp_iternext
+ BPy_BonesDict_methods, //tp_methods
+ 0, //tp_members
+ 0, //tp_getset
+ 0, //tp_base
+ 0, //tp_dict
+ 0, //tp_descr_get
+ 0, //tp_descr_set
+ 0, //tp_dictoffset
+ 0, //tp_init
+ 0, //tp_alloc
+ 0, //tp_new
+ 0, //tp_free
+ 0, //tp_is_gc
+ 0, //tp_bases
+ 0, //tp_mro
+ 0, //tp_cache
+ 0, //tp_subclasses
+ 0, //tp_weaklist
+ 0 //tp_del
+};
+//-----------------------PyBonesDict_FromPyArmature
+static PyObject *PyBonesDict_FromPyArmature(BPy_Armature *py_armature)
+{
+ BPy_BonesDict *py_BonesDict = (BPy_BonesDict *)PyObject_NEW( BPy_BonesDict, &BonesDict_Type );
+ if (!py_BonesDict)
+ goto RuntimeError;
+
+ py_BonesDict->bones = NULL;
+ py_BonesDict->editbones.first = py_BonesDict->editbones.last = NULL;
+
+ //create internal dictionaries
+ py_BonesDict->bonesMap = PyDict_New();
+ py_BonesDict->editbonesMap = PyDict_New();
+ if (!py_BonesDict->bonesMap || !py_BonesDict->editbonesMap)
+ goto RuntimeError;
+
+ //set listbase pointer
+ py_BonesDict->bones = &py_armature->armature->bonebase;
+
+ //now that everything is setup - init the mappings
+ if (!BonesDict_InitBones(py_BonesDict))
+ goto RuntimeError;
+ if (!BonesDict_InitEditBones(py_BonesDict))
+ goto RuntimeError;
+
+ //set editmode flag
+ py_BonesDict->editmode_flag = 0;
+
+ return (PyObject*)py_BonesDict;
+
+RuntimeError:
+ return EXPP_objError(PyExc_RuntimeError, "%s%s",
+ sBoneDictError, "Failed to create class");
+}
+
+//######################### Armature_Type #############################
+/*This type represents a thin wrapper around bArmature data types
+* internal to blender. It contains the psuedo-dictionary BonesDict
+* as an assistant in manipulating it's own bone collection*/
+//#################################################################
+
+//------------------METHOD IMPLEMENTATION------------------------------
+//------------------------Armature.makeEditable()
+static PyObject *Armature_makeEditable(BPy_Armature *self)
+{
+ if (self->armature->flag & ARM_EDITMODE)
+ goto AttributeError;
+
+ make_boneList(&self->Bones->editbones, self->Bones->bones, NULL);
+ if (!BonesDict_InitEditBones(self->Bones))
+ return NULL;
+ self->Bones->editmode_flag = 1;
+ return EXPP_incr_ret(Py_None);
+
+AttributeError:
+ return EXPP_objError(PyExc_AttributeError, "%s%s",
+ sArmatureBadArgs, "The armature cannot be placed manually in editmode before you call makeEditable()!");
+}
+
+//------------------------Armature.update()
+//This is a bit ugly because you need an object link to do this
+static PyObject *Armature_update(BPy_Armature *self)
+{
+ Object *obj = NULL;
+
+ for (obj = G.main->object.first; obj; obj = obj->id.next){
+ if (obj->data == self->armature)
+ break;
+ }
+ if (obj){
+ editbones_to_armature (&self->Bones->editbones, obj);
+ if (!BonesDict_InitBones(self->Bones))
+ return NULL;
+ self->Bones->editmode_flag = 0;
+ BLI_freelistN(&self->Bones->editbones);
+ }else{
+ goto AttributeError;
+
+ }
+ return EXPP_incr_ret(Py_None);
+
+AttributeError:
+ return EXPP_objError(PyExc_AttributeError, "%s%s",
+ sArmatureBadArgs, "The armature must be linked to an object before you can save changes!");
+}
+
+//------------------------Armature.__copy__()
+static PyObject *Armature_copy(BPy_Armature *self)
+{
+ PyObject *py_armature = NULL;
+ bArmature *bl_armature;
+ bl_armature= copy_armature(self->armature);
+ bl_armature->id.us= 0;
+ py_armature= Armature_CreatePyObject( bl_armature );
+ return py_armature;
+}
+
+//------------------ATTRIBUTE IMPLEMENTATION---------------------------
+//------------------------Armature.autoIK (getter)
+static PyObject *Armature_getAutoIK(BPy_Armature *self, void *closure)
+{
+ if (self->armature->flag & ARM_AUTO_IK)
+ return EXPP_incr_ret(Py_True);
+ else
+ return EXPP_incr_ret(Py_False);
+}
+//------------------------Armature.autoIK (setter)
+static int Armature_setAutoIK(BPy_Armature *self, PyObject *value, void *closure)
+{
+ if(value){
+ if(PyBool_Check(value)){
+ if (value == Py_True){
+ self->armature->flag |= ARM_AUTO_IK;
+ return 0;
+ }else if (value == Py_False){
+ self->armature->flag &= ~ARM_AUTO_IK;
+ return 0;
+ }
+ }
+ }
+ goto AttributeError;
+
+AttributeError:
+ return EXPP_intError(PyExc_AttributeError, "%s%s",
+ sArmatureBadArgs, "Expects True or False");
+}
+//------------------------Armature.layers (getter)
+static PyObject *Armature_getLayers(BPy_Armature *self, void *closure)
+{
+ int layers, bit = 0, val = 0;
+ PyObject *item = NULL, *laylist = PyList_New( 0 );
+
+ if( !laylist )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create pylist!" );
+
+ layers = self->armature->layer;
+
+ while( bit < 20 ) {
+ val = 1 << bit;
+ if( layers & val ) {
+ item = Py_BuildValue( "i", bit + 1 );
+ PyList_Append( laylist, item );
+ Py_DECREF( item );
+ }
+ bit++;
+ }
+ return laylist;
+}
+//------------------------Armature.layer (setter)
+static int Armature_setLayers(BPy_Armature *self, PyObject *value, void *closure)
+{
+ if(value){
+ if(PyList_Check(value)){
+ int layers = 0, len_list = 0;
+ int val;
+ PyObject *item = NULL;
+
+ len_list = PyList_Size(value);
+
+ if( len_list == 0 )
+ return EXPP_ReturnIntError( PyExc_AttributeError,
+ "list can't be empty, at least one layer must be set" );
+
+ while( len_list ) {
+ --len_list;
+ item = PyList_GetItem( value, len_list );
+ if( !PyInt_Check( item ) )
+ return EXPP_ReturnIntError( PyExc_AttributeError,
+ "list must contain only integer numbers" );
+
+ val = ( int ) PyInt_AsLong( item );
+ if( val < 1 || val > 20 )
+ return EXPP_ReturnIntError( PyExc_AttributeError,
+ "layer values must be in the range [1, 20]" );
+
+ layers |= 1 << ( val - 1 );
+ }
+
+ /* update any bases pointing to our object */
+ self->armature->layer = (short)layers;
+
+ return 0;
+ }
+ }
+ goto AttributeError;
+
+AttributeError:
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a list of integers" );
+}
+
+//------------------------Armature.mirrorEdit (getter)
+static PyObject *Armature_getMirrorEdit(BPy_Armature *self, void *closure)
+{
+ if (self->armature->flag & ARM_MIRROR_EDIT)
+ return EXPP_incr_ret(Py_True);
+ else
+ return EXPP_incr_ret(Py_False);
+}
+//------------------------Armature.mirrorEdit (setter)
+static int Armature_setMirrorEdit(BPy_Armature *self, PyObject *value, void *closure)
+{
+ if(value){
+ if(PyBool_Check(value)){
+ if (value == Py_True){
+ self->armature->flag |= ARM_MIRROR_EDIT;
+ return 0;
+ }else if (value == Py_False){
+ self->armature->flag &= ~ARM_MIRROR_EDIT;
+ return 0;
+ }
+ }
+ }
+ goto AttributeError;
+
+AttributeError:
+ return EXPP_intError(PyExc_AttributeError, "%s%s",
+ sArmatureBadArgs, "Expects True or False");
+}
+//------------------------Armature.drawType (getter)
+static PyObject *Armature_getDrawType(BPy_Armature *self, void *closure)
+{
+ if (self->armature->drawtype == ARM_OCTA){
+ return EXPP_GetModuleConstant("Blender.Armature", "OCTAHEDRON") ;
+ }else if (self->armature->drawtype == ARM_LINE){
+ return EXPP_GetModuleConstant("Blender.Armature", "STICK") ;
+ }else if (self->armature->drawtype == ARM_B_BONE){
+ return EXPP_GetModuleConstant("Blender.Armature", "BBONE") ;
+ }else if (self->armature->drawtype == ARM_ENVELOPE){
+ return EXPP_GetModuleConstant("Blender.Armature", "ENVELOPE") ;
+ }else{
+ goto RuntimeError;
+ }
+
+RuntimeError:
+ return EXPP_objError(PyExc_RuntimeError, "%s%s%s",
+ sArmatureError, "drawType: ", "Internal failure!");
+}
+//------------------------Armature.drawType (setter)
+static int Armature_setDrawType(BPy_Armature *self, PyObject *value, void *closure)
+{
+ PyObject *val = NULL, *name = NULL;
+ long numeric_value;
+
+ if(value){
+ if(BPy_Constant_Check(value)){
+ name = PyDict_GetItemString(((BPy_constant*)value)->dict, "name");
+ if (!STREQ2(PyString_AsString(name), "OCTAHEDRON", "STICK") &&
+ !STREQ2(PyString_AsString(name), "BBONE", "ENVELOPE"))
+ goto ValueError;
+ val = PyDict_GetItemString(((BPy_constant*)value)->dict, "value");
+ if (PyInt_Check(val)){
+ numeric_value = PyInt_AS_LONG(val);
+ self->armature->drawtype = (int)numeric_value;
+ return 0;
+ }
+ }
+ }
+ goto AttributeError;
+
+AttributeError:
+ return EXPP_intError(PyExc_AttributeError, "%s%s",
+ sArmatureBadArgs, "Expects module constant");
+
+ValueError:
+ return EXPP_intError(PyExc_AttributeError, "%s%s",
+ sArmatureBadArgs, "Argument must be the constant OCTAHEDRON, STICK, BBONE, or ENVELOPE");
+}
+//------------------------Armature.ghostStep (getter)
+static PyObject *Armature_getStep(BPy_Armature *self, void *closure)
+{
+ return PyInt_FromLong((long)self->armature->ghostsize);
+}
+//------------------------Armature.ghostStep (setter)
+static int Armature_setStep(BPy_Armature *self, PyObject *value, void *closure)
+{
+ long numerical_value;
+
+ if(value){
+ if(PyInt_Check(value)){
+ numerical_value = PyInt_AS_LONG(value);
+ if (numerical_value > 20.0f || numerical_value < 1.0f)
+ goto ValueError;
+ self->armature->ghostsize = (short)numerical_value;
+ return 0;
+ }
+ }
+ goto AttributeError;
+
+AttributeError:
+ return EXPP_intError(PyExc_AttributeError, "%s%s",
+ sArmatureBadArgs, "Expects Integer");
+
+ValueError:
+ return EXPP_intError(PyExc_AttributeError, "%s%s",
+ sArmatureBadArgs, "Argument must fall within 1-20");
+}
+//------------------------Armature.ghost (getter)
+static PyObject *Armature_getGhost(BPy_Armature *self, void *closure)
+{
+ return PyInt_FromLong((long)self->armature->ghostep);
+}
+//------------------------Armature.ghost (setter)
+static int Armature_setGhost(BPy_Armature *self, PyObject *value, void *closure)
+{
+ long numerical_value;
+
+ if(value){
+ if(PyInt_Check(value)){
+ numerical_value = PyInt_AS_LONG(value);
+ if (numerical_value > 30.0f || numerical_value < 0.0f)
+ goto ValueError;
+ self->armature->ghostep = (short)numerical_value;
+ return 0;
+ }
+ }
+ goto AttributeError;
+
+AttributeError:
+ return EXPP_intError(PyExc_AttributeError, "%s%s",
+ sArmatureBadArgs, "Expects Integer");
+
+ValueError:
+ return EXPP_intError(PyExc_AttributeError, "%s%s",
+ sArmatureBadArgs, "Argument must fall within 0-30");
+}
+//------------------------Armature.drawNames (getter)
+static PyObject *Armature_getDrawNames(BPy_Armature *self, void *closure)
+{
+ if (self->armature->flag & ARM_DRAWNAMES)
+ return EXPP_incr_ret(Py_True);
+ else
+ return EXPP_incr_ret(Py_False);
+}
+//------------------------Armature.drawNames (setter)
+static int Armature_setDrawNames(BPy_Armature *self, PyObject *value, void *closure)
+{
+ if(value){
+ if(PyBool_Check(value)){
+ if (value == Py_True){
+ self->armature->flag |= ARM_DRAWNAMES;
+ return 0;
+ }else if (value == Py_False){
+ self->armature->flag &= ~ARM_DRAWNAMES;
+ return 0;
+ }
+ }
+ }
+ goto AttributeError;
+
+AttributeError:
+ return EXPP_intError(PyExc_AttributeError, "%s%s",
+ sArmatureBadArgs, "Expects True or False");
+}
+//------------------------Armature.drawAxes (getter)
+static PyObject *Armature_getDrawAxes(BPy_Armature *self, void *closure)
+{
+ if (self->armature->flag & ARM_DRAWAXES)
+ return EXPP_incr_ret(Py_True);
+ else
+ return EXPP_incr_ret(Py_False);
+}
+//------------------------Armature.drawAxes (setter)
+static int Armature_setDrawAxes(BPy_Armature *self, PyObject *value, void *closure)
+{
+ if(value){
+ if(PyBool_Check(value)){
+ if (value == Py_True){
+ self->armature->flag |= ARM_DRAWAXES;
+ return 0;
+ }else if (value == Py_False){
+ self->armature->flag &= ~ARM_DRAWAXES;
+ return 0;
+ }
+ }
+ }
+ goto AttributeError;
+
+AttributeError:
+ return EXPP_intError(PyExc_AttributeError, "%s%s",
+ sArmatureBadArgs, "Expects True or False");
+}
+//------------------------Armature.delayDeform (getter)
+static PyObject *Armature_getDelayDeform(BPy_Armature *self, void *closure)
+{
+ if (self->armature->flag & ARM_DELAYDEFORM)
+ return EXPP_incr_ret(Py_True);
+ else
+ return EXPP_incr_ret(Py_False);
+}
+//------------------------Armature.delayDeform (setter)
+static int Armature_setDelayDeform(BPy_Armature *self, PyObject *value, void *closure)
+{
+ if(value){
+ if(PyBool_Check(value)){
+ if (value == Py_True){
+ self->armature->flag |= ARM_DELAYDEFORM;
+ return 0;
+ }else if (value == Py_False){
+ self->armature->flag &= ~ARM_DELAYDEFORM;
+ return 0;
+ }
+ }
+ }
+ goto AttributeError;
+
+AttributeError:
+ return EXPP_intError(PyExc_AttributeError, "%s%s",
+ sArmatureBadArgs, "Expects True or False");
+}
+//------------------------Armature.restPosition (getter)
+static PyObject *Armature_getRestPosition(BPy_Armature *self, void *closure)
+{
+ if (self->armature->flag & ARM_RESTPOS)
+ return EXPP_incr_ret(Py_True);
+ else
+ return EXPP_incr_ret(Py_False);
+}
+//------------------------Armature.restPosition (setter)
+static int Armature_setRestPosition(BPy_Armature *self, PyObject *value, void *closure)
+{
+ if(value){
+ if(PyBool_Check(value)){
+ if (value == Py_True){
+ self->armature->flag |= ARM_RESTPOS;
+ return 0;
+ }else if (value == Py_False){
+ self->armature->flag &= ~ARM_RESTPOS;
+ return 0;
+ }
+ }
+ }
+ goto AttributeError;
+
+AttributeError:
+ return EXPP_intError(PyExc_AttributeError, "%s%s",
+ sArmatureBadArgs, "Expects True or False");
+}
+//------------------------Armature.envelopes (getter)
+static PyObject *Armature_getEnvelopes(BPy_Armature *self, void *closure)
+{
+ if (self->armature->deformflag & ARM_DEF_ENVELOPE)
+ return EXPP_incr_ret(Py_True);
+ else
+ return EXPP_incr_ret(Py_False);
+}
+//------------------------Armature.envelopes (setter)
+static int Armature_setEnvelopes(BPy_Armature *self, PyObject *value, void *closure)
+{
+ if(value){
+ if(PyBool_Check(value)){
+ if (value == Py_True){
+ self->armature->deformflag |= ARM_DEF_ENVELOPE;
+ return 0;
+ }else if (value == Py_False){
+ self->armature->deformflag &= ~ARM_DEF_ENVELOPE;
+ return 0;
+ }
+ }
+ }
+ goto AttributeError;
+
+AttributeError:
+ return EXPP_intError(PyExc_AttributeError, "%s%s",
+ sArmatureBadArgs, "Expects True or False");
+}
+//------------------------Armature.vertexGroups (getter)
+static PyObject *Armature_getVertexGroups(BPy_Armature *self, void *closure)
+{
+ if (self->armature->deformflag & ARM_DEF_VGROUP)
+ return EXPP_incr_ret(Py_True);
+ else
+ return EXPP_incr_ret(Py_False);
+}
+//------------------------Armature.vertexGroups (setter)
+static int Armature_setVertexGroups(BPy_Armature *self, PyObject *value, void *closure)
+{
+ if(value){
+ if(PyBool_Check(value)){
+ if (value == Py_True){
+ self->armature->deformflag |= ARM_DEF_VGROUP;
+ return 0;
+ }else if (value == Py_False){
+ self->armature->deformflag &= ~ARM_DEF_VGROUP;
+ return 0;
+ }
+ }
+ }
+ goto AttributeError;
+
+AttributeError:
+ return EXPP_intError(PyExc_AttributeError, "%s%s",
+ sArmatureBadArgs, "Expects True or False");
+}
+
+//------------------------Armature.bones (getter)
+//Gets the name of the armature
+static PyObject *Armature_getBoneDict(BPy_Armature *self, void *closure)
+{
+ return EXPP_incr_ret((PyObject*)self->Bones);
+}
+//------------------------Armature.bones (setter)
+//Sets the name of the armature
+/*TODO*/
+/*Copy Bones through x = y*/
+static int Armature_setBoneDict(BPy_Armature *self, PyObject *value, void *closure)
+{
+ goto AttributeError;
+
+AttributeError:
+ return EXPP_intError(PyExc_AttributeError, "%s%s",
+ sArmatureError, "You are not allowed to change the .Bones attribute");
+}
+
+//------------------------Bone.layerMask (get)
+static PyObject *Armature_getLayerMask(BPy_Armature *self)
+{
+ /* do this extra stuff because the short's bits can be negative values */
+ unsigned short laymask = 0;
+ laymask |= self->armature->layer;
+ return PyInt_FromLong((int)laymask);
+}
+//------------------------Bone.layerMask (set)
+static int Armature_setLayerMask(BPy_Armature *self, PyObject *value)
+{
+ int laymask;
+ if (!PyInt_Check(value)) {
+ return EXPP_ReturnIntError( PyExc_AttributeError,
+ "expected an integer (bitmask) as argument" );
+ }
+
+ laymask = PyInt_AsLong(value);
+
+ if (laymask <= 0 || laymask > (1<<16) - 1)
+ return EXPP_ReturnIntError( PyExc_AttributeError,
+ "bitmask must have from 1 up to 16 bits set");
+
+ self->armature->layer = 0;
+ self->armature->layer |= laymask;
+
+ return 0;
+}
+
+//------------------TYPE_OBECT IMPLEMENTATION--------------------------
+//------------------------tp_doc
+//The __doc__ string for this object
+static char BPy_Armature_doc[] = "This object wraps a Blender Armature object.";
+//------------------------tp_methods
+//This contains a list of all methods the object contains
+static PyMethodDef BPy_Armature_methods[] = {
+ {"makeEditable", (PyCFunction) Armature_makeEditable, METH_NOARGS,
+ "() - Unlocks the ability to modify armature bones"},
+ {"update", (PyCFunction) Armature_update, METH_NOARGS,
+ "() - Rebuilds the armature based on changes to bones since the last call to makeEditable"},
+ {"__copy__", (PyCFunction) Armature_copy, METH_NOARGS,
+ "() - Return a copy of the armature."},
+ {"copy", (PyCFunction) Armature_copy, METH_NOARGS,
+ "() - Return a copy of the armature."},
+ {NULL, NULL, 0, NULL}
+};
+//------------------------tp_getset
+//This contains methods for attributes that require checking
+static PyGetSetDef BPy_Armature_getset[] = {
+ GENERIC_LIB_GETSETATTR,
+ {"bones", (getter)Armature_getBoneDict, (setter)Armature_setBoneDict,
+ "The armature's Bone dictionary", NULL},
+ {"vertexGroups", (getter)Armature_getVertexGroups, (setter)Armature_setVertexGroups,
+ "Enable/Disable vertex group defined deformation", NULL},
+ {"envelopes", (getter)Armature_getEnvelopes, (setter)Armature_setEnvelopes,
+ "Enable/Disable bone envelope defined deformation", NULL},
+ {"restPosition", (getter)Armature_getRestPosition, (setter)Armature_setRestPosition,
+ "Show armature rest position - disables posing", NULL},
+ {"delayDeform", (getter)Armature_getDelayDeform, (setter)Armature_setDelayDeform,
+ "Don't deform children when manipulating bones in pose mode", NULL},
+ {"drawAxes", (getter)Armature_getDrawAxes, (setter)Armature_setDrawAxes,
+ "Enable/Disable drawing the bone axes", NULL},
+ {"drawNames", (getter)Armature_getDrawNames, (setter)Armature_setDrawNames,
+ "Enable/Disable drawing the bone names", NULL},
+ {"ghost", (getter)Armature_getGhost, (setter)Armature_setGhost,
+ "Draw a number of ghosts around the current frame for current Action", NULL},
+ {"ghostStep", (getter)Armature_getStep, (setter)Armature_setStep,
+ "The number of frames between ghost instances", NULL},
+ {"drawType", (getter)Armature_getDrawType, (setter)Armature_setDrawType,
+ "The type of drawing currently applied to the armature", NULL},
+ {"mirrorEdit", (getter)Armature_getMirrorEdit, (setter)Armature_setMirrorEdit,
+ "Enable/Disable X-axis mirrored editing", NULL},
+ {"autoIK", (getter)Armature_getAutoIK, (setter)Armature_setAutoIK,
+ "Adds temporal IK chains while grabbing bones", NULL},
+ {"layers", (getter)Armature_getLayers, (setter)Armature_setLayers,
+ "List of layers for the armature", NULL},
+ {"layerMask", (getter)Armature_getLayerMask, (setter)Armature_setLayerMask,
+ "Layer bitmask", NULL },
+ {NULL, NULL, NULL, NULL, NULL}
+};
+//------------------------tp_new
+//This methods creates a new object (note it does not initialize it - only the building)
+//This can be called through python by myObject.__new__() however, tp_init is not called
+static PyObject *Armature_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ BPy_Armature *py_armature = NULL;
+ bArmature *bl_armature;
+
+ bl_armature = add_armature("Armature");
+ if(bl_armature) {
+ bl_armature->id.us = 0; // return count to 0 - add_armature() inc'd it
+
+ py_armature = (BPy_Armature*)type->tp_alloc(type, 0); //*new*
+ if (py_armature == NULL)
+ goto RuntimeError;
+
+ py_armature->armature = bl_armature;
+
+ //create armature.bones
+ py_armature->Bones = (BPy_BonesDict*)PyBonesDict_FromPyArmature(py_armature);
+ if (!py_armature->Bones)
+ goto RuntimeError;
+
+ } else {
+ goto RuntimeError;
+ }
+ return (PyObject*)py_armature;
+
+RuntimeError:
+ return EXPP_objError(PyExc_RuntimeError, "%s%s%s",
+ sArmatureError, " __new__: ", "couldn't create Armature Data in Blender");
+}
+//------------------------tp_init
+//This methods does initialization of the new object
+//This method will get called in python by 'myObject(argument, keyword=value)'
+//tp_new will be automatically called before this
+static int Armature_init(BPy_Armature *self, PyObject *args, PyObject *kwds)
+{
+ char buf[21];
+ char *name = "myArmature";
+ static char *kwlist[] = {"name", NULL};
+
+ if(!PyArg_ParseTupleAndKeywords(args, kwds, "|s", kwlist, &name)){
+ goto AttributeError;
+ }
+
+ //rename the armature if a name is supplied
+ if(!BLI_streq(name, "myArmature")){
+ PyOS_snprintf(buf, sizeof(buf), "%s", name);
+ rename_id(&self->armature->id, buf);
+ }
+ return 0;
+
+AttributeError:
+ return EXPP_intError(PyExc_AttributeError, "%s%s%s",
+ sArmatureBadArgs, " __init__: ", "Expects string(name)");
+}
+
+
+/*****************************************************************************/
+/* Function: Armature_compare */
+/* Description: This is a callback function for the BPy_Armature type. It */
+/* compares two Armature_Type objects. Only the "==" and "!=" */
+/* comparisons are meaninful. Returns 0 for equality and -1 if */
+/* they don't point to the same Blender Object struct. */
+/* In Python it becomes 1 if they are equal, 0 otherwise. */
+/*****************************************************************************/
+static int Armature_compare( BPy_Armature * a, BPy_Armature * b )
+{
+ return ( a->armature == b->armature ) ? 0 : -1;
+}
+
+//------------------------tp_repr
+//This is the string representation of the object
+static PyObject *Armature_repr(BPy_Armature *self)
+{
+ return PyString_FromFormat( "[Armature: \"%s\"]", self->armature->id.name + 2 ); //*new*
+}
+//------------------------tp_dealloc
+//This tells how to 'tear-down' our object when ref count hits 0
+///tp_dealloc
+static void Armature_dealloc(BPy_Armature * self)
+{
+ if (self->weaklist != NULL)
+ PyObject_ClearWeakRefs((PyObject *) self); /* this causes the weakref dealloc func to be called */
+
+ Py_DECREF(self->Bones);
+ PyObject_DEL( self );
+}
+//------------------TYPE_OBECT DEFINITION--------------------------
+PyTypeObject Armature_Type = {
+ PyObject_HEAD_INIT(NULL) //tp_head
+ 0, //tp_internal
+ "Armature", //tp_name
+ sizeof(BPy_Armature), //tp_basicsize
+ 0, //tp_itemsize
+ (destructor)Armature_dealloc, //tp_dealloc
+ 0, //tp_print
+ 0, //tp_getattr
+ 0, //tp_setattr
+ (cmpfunc) Armature_compare, //tp_compare
+ (reprfunc) Armature_repr, //tp_repr
+ 0, //tp_as_number
+ 0, //tp_as_sequence
+ 0, //tp_as_mapping
+ ( hashfunc ) GenericLib_hash, //tp_hash
+ 0, //tp_call
+ 0, //tp_str
+ 0, //tp_getattro
+ 0, //tp_setattro
+ 0, //tp_as_buffer
+ Py_TPFLAGS_DEFAULT| Py_TPFLAGS_HAVE_WEAKREFS, //tp_flags
+ BPy_Armature_doc, //tp_doc
+ 0, //tp_traverse
+ 0, //tp_clear
+ 0, //tp_richcompare
+ offsetof(BPy_Armature, weaklist), //tp_weaklistoffset
+ 0, //tp_iter
+ 0, //tp_iternext
+ BPy_Armature_methods, //tp_methods
+ 0, //tp_members
+ BPy_Armature_getset, //tp_getset
+ 0, //tp_base
+ 0, //tp_dict
+ 0, //tp_descr_get
+ 0, //tp_descr_set
+ 0, //tp_dictoffset
+ (initproc)Armature_init, //tp_init
+ 0, //tp_alloc
+ (newfunc)Armature_new, //tp_new
+ 0, //tp_free
+ 0, //tp_is_gc
+ 0, //tp_bases
+ 0, //tp_mro
+ 0, //tp_cache
+ 0, //tp_subclasses
+ 0, //tp_weaklist
+ 0 //tp_del
+};
+
+//-------------------MODULE METHODS IMPLEMENTATION------------------------
+//----------------Blender.Armature.Get()
+/* This function will return a Py_Armature when a single string is passed
+* or else it will return a {key:value} dictionary when mutliple strings are passed
+* or it will return a {key:value} dictionary of all armatures when nothing is passed */
+static PyObject *M_Armature_Get(PyObject * self, PyObject * args)
+{
+ PyObject *seq = NULL, *item = NULL, *dict = NULL, *py_armature = NULL;
+ char *name = "", buffer[24];
+ int size = 0, i;
+ void *data;
+
+ //GET ARGUMENTS - () ('s') ('s',..) (['s',..]) are exceptable
+ size = PySequence_Length(args);
+ if (size == 1) {
+ seq = PySequence_GetItem(args, 0); //*new*
+ if (!seq)
+ goto RuntimeError;
+ if(!PyString_Check(seq)){
+ if (PySequence_Check(seq)) {
+ size = PySequence_Length(seq);
+ } else {
+ Py_DECREF(seq);
+ goto AttributeError;
+ }
+ }
+ } else {
+ seq = EXPP_incr_ret(args); //*take ownership*
+ }
+ //'seq' should be a list, empty tuple or string - check list for strings
+ if(!PyString_Check(seq)){
+ for(i = 0; i < size; i++){
+ item = PySequence_GetItem(seq, i); //*new*
+ if (!item) {
+ Py_DECREF(seq);
+ goto RuntimeError;
+ }
+ if(!PyString_Check(item)){
+ EXPP_decr2(item, seq);
+ goto AttributeError;
+ }
+ Py_DECREF(item);
+ }
+ }
+
+ //GET ARMATURES
+ if(size != 1){
+ dict = PyDict_New(); //*new*
+ if(!dict){
+ Py_DECREF(seq);
+ goto RuntimeError;
+ }
+ if(size == 0){ //GET ALL ARMATURES
+ data = G.main->armature.first; //get the first data ID from the armature library
+ while (data){
+ py_armature = Armature_CreatePyObject(data); //*new*
+ if (!py_armature) {
+ EXPP_decr2(seq, dict);
+ return NULL; /* error is set from Armature_CreatePyObject */
+ }
+ sprintf(buffer, "%s", ((bArmature*)data)->id.name +2);
+ if(PyDict_SetItemString(dict, buffer, py_armature) == -1){ //add to dictionary
+ EXPP_decr3(seq, dict, py_armature);
+ goto RuntimeError;
+ }
+ Py_DECREF(py_armature);
+ data = ((ID*)data)->next;
+ }
+ Py_DECREF(seq);
+ }else{ //GET ARMATURE LIST
+ for (i = 0; i < size; i++) {
+ item = PySequence_GetItem(seq, i); //*new*
+ name = PyString_AsString(item);
+ Py_DECREF(item);
+ data = find_id("AR", name); //get data from library
+ if (data != NULL){
+ py_armature = Armature_CreatePyObject(data); //*new*
+ if (!py_armature) {
+ EXPP_decr2(seq, dict);
+ return NULL; /* error is set from Armature_CreatePyObject */
+ }
+
+ if(PyDict_SetItemString(dict, name, py_armature) == -1){ //add to dictionary
+ EXPP_decr3(seq, dict, py_armature);
+ goto RuntimeError;
+ }
+ Py_DECREF(py_armature);
+ }else{
+ if(PyDict_SetItemString(dict, name, Py_None) == -1){ //add to dictionary
+ EXPP_decr2(seq, dict);
+ goto RuntimeError;
+ }
+ Py_DECREF(Py_None);
+ }
+ }
+ Py_DECREF(seq);
+ }
+ return dict;
+ }else{ //GET SINGLE ARMATURE
+ if(!PyString_Check(seq)){ //This handles the bizarre case where (['s']) is passed
+ item = PySequence_GetItem(seq, 0); //*new*
+ name = PyString_AsString(item);
+ Py_DECREF(item);
+ }else{
+ name = PyString_AsString(seq);
+ }
+ Py_DECREF(seq);
+ data = find_id("AR", name); //get data from library
+ if (data != NULL){
+ return Armature_CreatePyObject(data); //*new*
+ }else{
+ char buffer[128];
+ PyOS_snprintf( buffer, sizeof(buffer),
+ "Armature \"%s\" not found", name);
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ buffer );
+ }
+ }
+
+RuntimeError:
+ return EXPP_objError(PyExc_RuntimeError, "%s%s%s",
+ sModuleError, "Get(): ", "Internal Error Ocurred");
+
+AttributeError:
+ return EXPP_objError(PyExc_AttributeError, "%s%s%s",
+ sModuleBadArgs, "Get(): ", "- Expects (optional) string sequence");
+}
+
+
+//----------------Blender.Armature.New()
+static PyObject *M_Armature_New(PyObject * self, PyObject * args)
+{
+ char *name = "Armature";
+ struct bArmature *armature;
+ BPy_Armature *obj;
+
+ if( !PyArg_ParseTuple( args, "|s", &name ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected nothing or a string as argument" );
+
+ armature= add_armature(name);
+ armature->id.us = 0;
+ obj = (BPy_Armature *)Armature_CreatePyObject(armature); /*new*/
+
+ if( !obj )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyObject_New() failed" );
+
+ obj->armature = armature;
+ return (PyObject *)obj;
+}
+
+
+//-------------------MODULE METHODS DEFINITION-----------------------------
+
+static char M_Armature_Get_doc[] = "(name) - return the armature with the name 'name', \
+ returns None if not found.\n If 'name' is not specified, it returns a list of all \
+ armatures in the\ncurrent scene.";
+
+static char M_Armature_New_doc[] = "(name) - return a new armature object.";
+
+struct PyMethodDef M_Armature_methods[] = {
+ {"Get", M_Armature_Get, METH_VARARGS, M_Armature_Get_doc},
+ {"New", M_Armature_New, METH_VARARGS, M_Armature_New_doc},
+ {NULL, NULL, 0, NULL}
+};
+//------------------VISIBLE PROTOTYPE IMPLEMENTATION-----------------------
+//------------------------Armature_RebuildEditbones (internal)
+PyObject * Armature_RebuildEditbones(PyObject *pyarmature)
+{
+ return Armature_makeEditable((BPy_Armature*)pyarmature);
+}
+
+//------------------------Armature_RebuildBones (internal)
+PyObject *Armature_RebuildBones(PyObject *pyarmature)
+{
+ return Armature_update((BPy_Armature*)pyarmature);
+}
+
+/* internal func to remove weakref from weakref list */
+PyObject * arm_weakref_callback_weakref_dealloc(PyObject *self, PyObject *weakref)
+{
+ char *list_name = ARM_WEAKREF_LIST_NAME;
+ PyObject *maindict = NULL, *armlist = NULL;
+ int i;
+
+ maindict= PyModule_GetDict(PyImport_AddModule( "__main__"));
+ armlist = PyDict_GetItemString(maindict, list_name);
+ if( !armlist){
+ printf("Oops - update_armature_weakrefs()\n");
+ Py_RETURN_NONE;
+ }
+
+ i = PySequence_Index(armlist, weakref);
+ if (i==-1) {
+ printf("callback weakref internal error, weakref not in list\n\tthis should never happen.\n");
+ Py_RETURN_NONE;
+ }
+ PySequence_DelItem(armlist, i);
+ Py_RETURN_NONE;
+}
+
+/*-----------------(internal)
+ * Converts a bArmature to a PyArmature */
+
+PyObject *Armature_CreatePyObject(struct bArmature *armature)
+{
+ BPy_Armature *py_armature = NULL;
+ PyObject *maindict = NULL, *weakref = NULL;
+ PyObject *armlist = NULL; /* list of armature weak refs */
+ char *list_name = ARM_WEAKREF_LIST_NAME;
+ int i;
+
+ //put a weakreference in __main__
+ maindict= PyModule_GetDict(PyImport_AddModule( "__main__"));
+
+ armlist = PyDict_GetItemString(maindict, list_name);
+ if(!armlist) {
+ printf("Oops - can't get the armature weakref list\n");
+ goto RuntimeError;
+ }
+
+ /* see if we alredy have it */
+ for (i=0; i< PyList_Size(armlist); i++) {
+ py_armature = (BPy_Armature *)PyWeakref_GetObject(PyList_GET_ITEM(armlist, i));
+ if (BPy_Armature_Check(py_armature) && py_armature->armature == armature) {
+ Py_INCREF(py_armature);
+ /*printf("reusing armature\n");*/
+ return (PyObject *)py_armature;
+ }
+ }
+
+
+ /*create armature type*/
+ py_armature = PyObject_NEW( BPy_Armature, &Armature_Type );
+
+ if (!py_armature){
+ printf("Oops - can't create py armature\n");
+ goto RuntimeError;
+ }
+
+ py_armature->armature = armature;
+ py_armature->weaklist = NULL; //init the weaklist
+
+ //create armature.bones
+ py_armature->Bones = (BPy_BonesDict*)PyBonesDict_FromPyArmature(py_armature);
+ if (!py_armature->Bones){
+ printf("Oops - creating armature.bones\n");
+ goto RuntimeError;
+ }
+
+ weakref = PyWeakref_NewRef((PyObject*)py_armature, arm_weakref_callback_weakref_dealloc__pyfunc);
+ if (PyList_Append(armlist, weakref) == -1){
+ printf("Oops - list-append failed\n");
+ goto RuntimeError;
+ }
+ Py_DECREF(weakref);
+
+ return (PyObject *) py_armature;
+
+RuntimeError:
+ return EXPP_objError(PyExc_RuntimeError, "%s%s%s",
+ sModuleError, "Armature_CreatePyObject: ", "Internal Error Ocurred");
+}
+//-----------------(internal)
+//Converts a PyArmature to a bArmature
+struct bArmature *PyArmature_AsArmature(BPy_Armature *py_armature)
+{
+ return (py_armature->armature);
+}
+
+struct bArmature *Armature_FromPyObject( PyObject * py_obj )
+{
+ return PyArmature_AsArmature((BPy_Armature*)py_obj);
+}
+
+/* internal use only */
+static PyMethodDef bpy_arm_weakref_callback_weakref_dealloc[] = {
+ {"arm_weakref_callback_weakref_dealloc", arm_weakref_callback_weakref_dealloc, METH_O, ""}
+};
+
+//-------------------MODULE INITIALIZATION--------------------------------
+PyObject *Armature_Init(void)
+{
+ PyObject *module, *dict;
+
+ //Initializes TypeObject.ob_type
+ if (PyType_Ready(&Armature_Type) < 0 || PyType_Ready(&BonesDict_Type) < 0 ||
+ PyType_Ready(&EditBone_Type) < 0 || PyType_Ready(&Bone_Type) < 0) {
+ return EXPP_incr_ret(Py_None);
+ }
+
+ /* Weakref management - used for callbacks so we can
+ * tell when a callback has been removed that a UI button referenced */
+ arm_weakref_callback_weakref_dealloc__pyfunc = PyCFunction_New(bpy_arm_weakref_callback_weakref_dealloc, NULL);
+
+
+ //Register the module
+ module = Py_InitModule3("Blender.Armature", M_Armature_methods,
+ "The Blender Armature module");
+
+ //Add TYPEOBJECTS to the module
+ PyModule_AddObject(module, "Armature",
+ EXPP_incr_ret((PyObject *)&Armature_Type)); //*steals*
+ PyModule_AddObject(module, "Bone",
+ EXPP_incr_ret((PyObject *)&Bone_Type)); //*steals*
+ PyModule_AddObject(module, "Editbone",
+ EXPP_incr_ret((PyObject *)&EditBone_Type)); //*steals*
+
+ //Add CONSTANTS to the module
+ PyModule_AddObject(module, "CONNECTED",
+ PyConstant_NewInt("CONNECTED", BONE_CONNECTED));
+ PyModule_AddObject(module, "HINGE",
+ PyConstant_NewInt("HINGE", BONE_HINGE));
+ PyModule_AddObject(module, "NO_DEFORM",
+ PyConstant_NewInt("NO_DEFORM", BONE_NO_DEFORM));
+ PyModule_AddObject(module, "MULTIPLY",
+ PyConstant_NewInt("MULTIPLY", BONE_MULT_VG_ENV));
+ PyModule_AddObject(module, "HIDDEN_EDIT",
+ PyConstant_NewInt("HIDDEN_EDIT", BONE_HIDDEN_A));
+ PyModule_AddObject(module, "ROOT_SELECTED",
+ PyConstant_NewInt("ROOT_SELECTED", BONE_ROOTSEL));
+ PyModule_AddObject(module, "BONE_SELECTED",
+ PyConstant_NewInt("BONE_SELECTED", BONE_SELECTED));
+ PyModule_AddObject(module, "TIP_SELECTED",
+ PyConstant_NewInt("TIP_SELECTED", BONE_TIPSEL));
+
+ PyModule_AddObject(module, "OCTAHEDRON",
+ PyConstant_NewInt("OCTAHEDRON", ARM_OCTA));
+ PyModule_AddObject(module, "STICK",
+ PyConstant_NewInt("STICK", ARM_LINE));
+ PyModule_AddObject(module, "BBONE",
+ PyConstant_NewInt("BBONE", ARM_B_BONE));
+ PyModule_AddObject(module, "ENVELOPE",
+ PyConstant_NewInt("ENVELOPE", ARM_ENVELOPE));
+
+ //Add SUBMODULES to the module
+ dict = PyModule_GetDict( module ); //borrowed
+ PyDict_SetItemString(dict, "NLA", NLA_Init()); //creates a *new* module
+
+ return module;
+}
diff --git a/source/blender/python/api2_2x/Armature.h b/source/blender/python/api2_2x/Armature.h
new file mode 100644
index 00000000000..7f543e375a1
--- /dev/null
+++ b/source/blender/python/api2_2x/Armature.h
@@ -0,0 +1,70 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Joseph gilbert
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_ARMATURE_H
+#define EXPP_ARMATURE_H
+
+#include <Python.h>
+#include "DNA_armature_types.h"
+
+//-------------------TYPE CHECKS---------------------------------
+#define BPy_Armature_Check(v) ((v)->ob_type == &Armature_Type)
+#define BPy_BonesDict_Check(v) ((v)->ob_type == &BonesDict_Type)
+//-------------------MODULE INIT---------------------------------
+PyObject *Armature_Init( void );
+//-------------------TYPEOBJECT----------------------------------
+extern PyTypeObject Armature_Type;
+extern PyTypeObject BonesDict_Type;
+//-------------------STRUCT DEFINITION---------------------------
+typedef struct {
+ PyObject_HEAD
+ PyObject *bonesMap; //wrapper for bones
+ PyObject *editbonesMap; //wrapper for editbones
+ ListBase *bones; //pointer to armature->bonebase
+ ListBase editbones; //allocated list of EditBones
+ short editmode_flag; //1 = in , 0 = not in
+} BPy_BonesDict;
+
+typedef struct {
+ PyObject_HEAD
+ struct bArmature * armature;
+ BPy_BonesDict *Bones; //BPy_BonesDict
+ PyObject *weaklist;
+} BPy_Armature;
+
+//-------------------VISIBLE PROTOTYPES-------------------------
+PyObject *Armature_CreatePyObject(struct bArmature *armature);
+struct bArmature *PyArmature_AsArmature(BPy_Armature *py_armature);
+PyObject * Armature_RebuildEditbones(PyObject *pyarmature);
+PyObject *Armature_RebuildBones(PyObject *pyarmature);
+
+struct bArmature *Armature_FromPyObject( PyObject * py_obj );
+
+#endif
diff --git a/source/blender/python/api2_2x/BGL.c b/source/blender/python/api2_2x/BGL.c
new file mode 100644
index 00000000000..56cc8c63b5f
--- /dev/null
+++ b/source/blender/python/api2_2x/BGL.c
@@ -0,0 +1,1590 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+/* This file is the Blender.BGL part of opy_draw.c, from the old
+ * bpython/intern dir, with minor changes to adapt it to the new Python
+ * implementation. The BGL submodule "wraps" OpenGL functions and constants,
+ * allowing script writers to make OpenGL calls in their Python scripts. */
+
+#include "BGL.h" /*This must come first */
+
+#include "MEM_guardedalloc.h"
+#include "gen_utils.h"
+
+static int type_size( int type );
+static Buffer *make_buffer( int type, int ndimensions, int *dimensions );
+
+static char Method_Buffer_doc[] =
+ "(type, dimensions, [template]) - Create a new Buffer object\n\n\
+(type) - The format to store data in\n\
+(dimensions) - An int or sequence specifying the dimensions of the buffer\n\
+[template] - A sequence of matching dimensions to the buffer to be created\n\
+ which will be used to initialize the Buffer.\n\n\
+If a template is not passed in all fields will be initialized to 0.\n\n\
+The type should be one of GL_BYTE, GL_SHORT, GL_INT, GL_FLOAT, or GL_DOUBLE.\n\
+If the dimensions are specified as an int a linear buffer will be\n\
+created. If a sequence is passed for the dimensions the buffer\n\
+will have len(sequence) dimensions, where the size for each dimension\n\
+is determined by the value in the sequence at that index.\n\n\
+For example, passing [100, 100] will create a 2 dimensional\n\
+square buffer. Passing [16, 16, 32] will create a 3 dimensional\n\
+buffer which is twice as deep as it is wide or high.";
+
+static PyObject *Method_Buffer( PyObject * self, PyObject * args );
+
+/* Buffer sequence methods */
+
+static int Buffer_len( PyObject * self );
+static PyObject *Buffer_item( PyObject * self, int i );
+static PyObject *Buffer_slice( PyObject * self, int begin, int end );
+static int Buffer_ass_item( PyObject * self, int i, PyObject * v );
+static int Buffer_ass_slice( PyObject * self, int begin, int end,
+ PyObject * seq );
+
+static PySequenceMethods Buffer_SeqMethods = {
+ ( inquiry ) Buffer_len, /*sq_length */
+ ( binaryfunc ) 0, /*sq_concat */
+ ( intargfunc ) 0, /*sq_repeat */
+ ( intargfunc ) Buffer_item, /*sq_item */
+ ( intintargfunc ) Buffer_slice, /*sq_slice */
+ ( intobjargproc ) Buffer_ass_item, /*sq_ass_item */
+ ( intintobjargproc ) Buffer_ass_slice, /*sq_ass_slice */
+};
+
+static void Buffer_dealloc( PyObject * self );
+static PyObject *Buffer_tolist( PyObject * self );
+static PyObject *Buffer_dimensions( PyObject * self );
+static PyObject *Buffer_getattr( PyObject * self, char *name );
+static PyObject *Buffer_repr( PyObject * self );
+
+PyTypeObject buffer_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required python macro */
+ 0, /*ob_size */
+ "buffer", /*tp_name */
+ sizeof( Buffer ), /*tp_basicsize */
+ 0, /*tp_itemsize */
+ ( destructor ) Buffer_dealloc, /*tp_dealloc */
+ ( printfunc ) 0, /*tp_print */
+ ( getattrfunc ) Buffer_getattr, /*tp_getattr */
+ ( setattrfunc ) 0, /*tp_setattr */
+ ( cmpfunc ) 0, /*tp_compare */
+ ( reprfunc ) Buffer_repr, /*tp_repr */
+ 0, /*tp_as_number */
+ &Buffer_SeqMethods, /*tp_as_sequence */
+};
+
+/* #ifndef __APPLE__ */
+
+#define BGL_Wrap(nargs, funcname, ret, arg_list) \
+static PyObject *Method_##funcname (PyObject *self, PyObject *args) {\
+ arg_def##nargs arg_list; \
+ ret_def_##ret; \
+ if(!PyArg_ParseTuple(args, arg_str##nargs arg_list, arg_ref##nargs arg_list)) return NULL;\
+ ret_set_##ret gl##funcname (arg_var##nargs arg_list);\
+ ret_ret_##ret; \
+}
+
+#define BGLU_Wrap(nargs, funcname, ret, arg_list) \
+static PyObject *Method_##funcname (PyObject *self, PyObject *args) {\
+ arg_def##nargs arg_list; \
+ ret_def_##ret; \
+ if(!PyArg_ParseTuple(args, arg_str##nargs arg_list, arg_ref##nargs arg_list)) return NULL;\
+ ret_set_##ret glu##funcname (arg_var##nargs arg_list);\
+ ret_ret_##ret; \
+}
+
+/* #endif */
+
+PyObject *BGL_Init( void );
+
+/********/
+static int type_size(int type)
+{
+ switch (type) {
+ case GL_BYTE:
+ return sizeof(char);
+ case GL_SHORT:
+ return sizeof(short);
+ case GL_INT:
+ return sizeof(int);
+ case GL_FLOAT:
+ return sizeof(float);
+ case GL_DOUBLE:
+ return sizeof(double);
+ }
+ return -1;
+}
+
+static Buffer *make_buffer(int type, int ndimensions, int *dimensions)
+{
+ Buffer *buffer;
+ void *buf= NULL;
+ int i, size, length;
+
+ length= 1;
+ for (i=0; i<ndimensions; i++)
+ length*= dimensions[i];
+
+ size= type_size(type);
+
+ buf= MEM_mallocN(length*size, "Buffer buffer");
+
+ buffer= (Buffer *) PyObject_NEW(Buffer, &buffer_Type);
+ buffer->parent= NULL;
+ buffer->ndimensions= ndimensions;
+ buffer->dimensions= dimensions;
+ buffer->type= type;
+ buffer->buf.asvoid= buf;
+
+ for (i= 0; i<length; i++) {
+ if (type==GL_BYTE)
+ buffer->buf.asbyte[i]= 0;
+ else if (type==GL_SHORT)
+ buffer->buf.asshort[i]= 0;
+ else if (type==GL_INT)
+ buffer->buf.asint[i]= 0;
+ else if (type==GL_FLOAT)
+ buffer->buf.asfloat[i]= 0.0f;
+ else if (type==GL_DOUBLE)
+ buffer->buf.asdouble[i]= 0.0;
+ }
+ return buffer;
+}
+
+static PyObject *Method_Buffer (PyObject *self, PyObject *args)
+{
+ PyObject *length_ob= NULL, *template= NULL;
+ Buffer *buffer;
+
+ int i, type;
+ int *dimensions = 0, ndimensions = 0;
+
+ if (!PyArg_ParseTuple(args, "iO|O", &type, &length_ob, &template))
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "expected an int and one or two PyObjects");
+
+ if (type!=GL_BYTE && type!=GL_SHORT && type!=GL_INT && type!=GL_FLOAT && type!=GL_DOUBLE) {
+ PyErr_SetString(PyExc_AttributeError, "type");
+ return NULL;
+ }
+
+ if (PyNumber_Check(length_ob)) {
+ ndimensions= 1;
+ dimensions= MEM_mallocN(ndimensions*sizeof(int), "Buffer dimensions");
+ dimensions[0]= PyInt_AsLong(length_ob);
+ } else if (PySequence_Check(length_ob)) {
+ ndimensions= PySequence_Length(length_ob);
+ dimensions= MEM_mallocN(ndimensions*sizeof(int), "Buffer dimensions");
+ for (i=0; i<ndimensions; i++) {
+ PyObject *ob= PySequence_GetItem(length_ob, i);
+
+ if (!PyNumber_Check(ob)) dimensions[i]= 1;
+ else dimensions[i]= PyInt_AsLong(ob);
+ Py_DECREF(ob);
+ }
+ }
+
+ buffer= make_buffer(type, ndimensions, dimensions);
+ if (template && ndimensions) {
+ if (Buffer_ass_slice((PyObject *) buffer, 0, dimensions[0], template)) {
+ Py_DECREF(buffer);
+ return NULL;
+ }
+ }
+
+ return (PyObject *) buffer;
+}
+
+/*@ Buffer sequence methods */
+
+static int Buffer_len(PyObject *self)
+{
+ Buffer *buf= (Buffer *) self;
+ return buf->dimensions[0];
+}
+
+static PyObject *Buffer_item(PyObject *self, int i)
+{
+ Buffer *buf= (Buffer *) self;
+
+ if (i >= buf->dimensions[0]) {
+ PyErr_SetString(PyExc_IndexError, "array index out of range");
+ return NULL;
+ }
+
+ if (buf->ndimensions==1) {
+ switch (buf->type) {
+ case GL_BYTE: return Py_BuildValue("b", buf->buf.asbyte[i]);
+ case GL_SHORT: return Py_BuildValue("h", buf->buf.asshort[i]);
+ case GL_INT: return Py_BuildValue("i", buf->buf.asint[i]);
+ case GL_FLOAT: return PyFloat_FromDouble(buf->buf.asfloat[i]);
+ case GL_DOUBLE: return Py_BuildValue("d", buf->buf.asdouble[i]);
+ }
+ } else {
+ Buffer *newbuf;
+ int j, length, size;
+
+ length= 1;
+ for (j=1; j<buf->ndimensions; j++) {
+ length*= buf->dimensions[j];
+ }
+ size= type_size(buf->type);
+
+ newbuf= (Buffer *) PyObject_NEW(Buffer, &buffer_Type);
+
+ Py_INCREF(self);
+ newbuf->parent= self;
+
+ newbuf->ndimensions= buf->ndimensions-1;
+ newbuf->type= buf->type;
+ newbuf->buf.asvoid= buf->buf.asbyte + i*length*size;
+ newbuf->dimensions= MEM_mallocN(newbuf->ndimensions*sizeof(int),
+ "Buffer dimensions");
+ memcpy(newbuf->dimensions, buf->dimensions+1,
+ newbuf->ndimensions*sizeof(int));
+
+ return (PyObject *) newbuf;
+ }
+
+ return NULL;
+}
+
+static PyObject *Buffer_slice(PyObject *self, int begin, int end)
+{
+ Buffer *buf= (Buffer *) self;
+ PyObject *list;
+ int count;
+
+ if (begin<0) begin= 0;
+ if (end>buf->dimensions[0])
+ end= buf->dimensions[0];
+ if (begin>end) begin= end;
+
+ list= PyList_New(end-begin);
+
+ for (count= begin; count<end; count++)
+ PyList_SetItem(list, count-begin, Buffer_item(self, count));
+
+ return list;
+}
+
+static int Buffer_ass_item(PyObject *self, int i, PyObject *v)
+{
+ Buffer *buf= (Buffer *) self;
+
+ if (i >= buf->dimensions[0]) {
+ PyErr_SetString(PyExc_IndexError, "array assignment index out of range");
+ return -1;
+ }
+
+ if (buf->ndimensions!=1) {
+ PyObject *row= Buffer_item(self, i);
+ int ret;
+
+ if (!row) return -1;
+ ret= Buffer_ass_slice(row, 0, buf->dimensions[1], v);
+ Py_DECREF(row);
+ return ret;
+ }
+
+ if (buf->type==GL_BYTE) {
+ if (!PyArg_Parse(v, "b;Coordinates must be ints", &buf->buf.asbyte[i]))
+ return -1;
+ } else if (buf->type==GL_SHORT) {
+ if (!PyArg_Parse(v, "h;Coordinates must be ints", &buf->buf.asshort[i]))
+ return -1;
+
+ } else if (buf->type==GL_INT) {
+ if (!PyArg_Parse(v, "i;Coordinates must be ints", &buf->buf.asint[i]))
+ return -1;
+ } else if (buf->type==GL_FLOAT) {
+ if (!PyArg_Parse(v, "f;Coordinates must be floats", &buf->buf.asfloat[i]))
+ return -1;
+ } else if (buf->type==GL_DOUBLE) {
+ if (!PyArg_Parse(v, "d;Coordinates must be floats", &buf->buf.asdouble[i]))
+ return -1;
+ }
+ return 0;
+}
+
+static int Buffer_ass_slice(PyObject *self, int begin, int end, PyObject *seq)
+{
+ Buffer *buf= (Buffer *) self;
+ PyObject *item;
+ int count, err=0;
+
+ if (begin<0) begin= 0;
+ if (end>buf->dimensions[0]) end= buf->dimensions[0];
+ if (begin>end) begin= end;
+
+ if (!PySequence_Check(seq)) {
+ PyErr_SetString(PyExc_TypeError,
+ "illegal argument type for built-in operation");
+ return -1;
+ }
+
+ if (PySequence_Length(seq)!=(end-begin)) {
+ PyErr_SetString(PyExc_TypeError, "size mismatch in assignment");
+ return -1;
+ }
+
+ for (count= begin; count<end; count++) {
+ item= PySequence_GetItem(seq, count-begin);
+ err= Buffer_ass_item(self, count, item);
+ Py_DECREF(item);
+ if (err) break;
+ }
+ return err;
+}
+
+static void Buffer_dealloc(PyObject *self)
+{
+ Buffer *buf = (Buffer *)self;
+
+ if (buf->parent) Py_DECREF (buf->parent);
+ else MEM_freeN (buf->buf.asvoid);
+
+ MEM_freeN (buf->dimensions);
+
+ PyObject_DEL (self);
+}
+
+static PyObject *Buffer_tolist(PyObject *self)
+{
+ int i, len= ((Buffer *)self)->dimensions[0];
+ PyObject *list= PyList_New(len);
+
+ for (i=0; i<len; i++) {
+ PyList_SetItem(list, i, Buffer_item(self, i));
+ }
+
+ return list;
+}
+
+static PyObject *Buffer_dimensions(PyObject *self)
+{
+ Buffer *buffer= (Buffer *) self;
+ PyObject *list= PyList_New(buffer->ndimensions);
+ int i;
+
+ for (i= 0; i<buffer->ndimensions; i++) {
+ PyList_SetItem(list, i, PyInt_FromLong(buffer->dimensions[i]));
+ }
+
+ return list;
+}
+
+static PyObject *Buffer_getattr(PyObject *self, char *name)
+{
+ if (strcmp(name, "list")==0) return Buffer_tolist(self);
+ else if (strcmp(name, "dimensions")==0) return Buffer_dimensions(self);
+
+ PyErr_SetString(PyExc_AttributeError, name);
+ return NULL;
+}
+
+static PyObject *Buffer_repr(PyObject *self)
+{
+ PyObject *list= Buffer_tolist(self);
+ PyObject *repr= PyObject_Repr(list);
+ Py_DECREF(list);
+
+ return repr;
+}
+
+
+BGL_Wrap(2, Accum, void, (GLenum, GLfloat))
+BGL_Wrap(2, AlphaFunc, void, (GLenum, GLclampf))
+BGL_Wrap(3, AreTexturesResident, GLboolean, (GLsizei, GLuintP, GLbooleanP))
+BGL_Wrap(1, Begin, void, (GLenum))
+BGL_Wrap(2, BindTexture, void, (GLenum, GLuint))
+BGL_Wrap(7, Bitmap, void, (GLsizei, GLsizei, GLfloat,
+ GLfloat, GLfloat, GLfloat, GLubyteP))
+BGL_Wrap(2, BlendFunc, void, (GLenum, GLenum))
+BGL_Wrap(1, CallList, void, (GLuint))
+BGL_Wrap(3, CallLists, void, (GLsizei, GLenum, GLvoidP))
+BGL_Wrap(1, Clear, void, (GLbitfield))
+BGL_Wrap(4, ClearAccum, void, (GLfloat, GLfloat, GLfloat, GLfloat))
+BGL_Wrap(4, ClearColor, void, (GLclampf, GLclampf, GLclampf, GLclampf))
+BGL_Wrap(1, ClearDepth, void, (GLclampd))
+BGL_Wrap(1, ClearIndex, void, (GLfloat))
+BGL_Wrap(1, ClearStencil, void, (GLint))
+BGL_Wrap(2, ClipPlane, void, (GLenum, GLdoubleP))
+BGL_Wrap(3, Color3b, void, (GLbyte, GLbyte, GLbyte))
+BGL_Wrap(1, Color3bv, void, (GLbyteP))
+BGL_Wrap(3, Color3d, void, (GLdouble, GLdouble, GLdouble))
+BGL_Wrap(1, Color3dv, void, (GLdoubleP))
+BGL_Wrap(3, Color3f, void, (GLfloat, GLfloat, GLfloat))
+BGL_Wrap(1, Color3fv, void, (GLfloatP))
+BGL_Wrap(3, Color3i, void, (GLint, GLint, GLint))
+BGL_Wrap(1, Color3iv, void, (GLintP))
+BGL_Wrap(3, Color3s, void, (GLshort, GLshort, GLshort))
+BGL_Wrap(1, Color3sv, void, (GLshortP))
+BGL_Wrap(3, Color3ub, void, (GLubyte, GLubyte, GLubyte))
+BGL_Wrap(1, Color3ubv, void, (GLubyteP))
+BGL_Wrap(3, Color3ui, void, (GLuint, GLuint, GLuint))
+BGL_Wrap(1, Color3uiv, void, (GLuintP))
+BGL_Wrap(3, Color3us, void, (GLushort, GLushort, GLushort))
+BGL_Wrap(1, Color3usv, void, (GLushortP))
+BGL_Wrap(4, Color4b, void, (GLbyte, GLbyte, GLbyte, GLbyte))
+BGL_Wrap(1, Color4bv, void, (GLbyteP))
+BGL_Wrap(4, Color4d, void, (GLdouble, GLdouble, GLdouble, GLdouble))
+BGL_Wrap(1, Color4dv, void, (GLdoubleP))
+BGL_Wrap(4, Color4f, void, (GLfloat, GLfloat, GLfloat, GLfloat))
+BGL_Wrap(1, Color4fv, void, (GLfloatP))
+BGL_Wrap(4, Color4i, void, (GLint, GLint, GLint, GLint))
+BGL_Wrap(1, Color4iv, void, (GLintP))
+BGL_Wrap(4, Color4s, void, (GLshort, GLshort, GLshort, GLshort))
+BGL_Wrap(1, Color4sv, void, (GLshortP))
+BGL_Wrap(4, Color4ub, void, (GLubyte, GLubyte, GLubyte, GLubyte))
+BGL_Wrap(1, Color4ubv, void, (GLubyteP))
+BGL_Wrap(4, Color4ui, void, (GLuint, GLuint, GLuint, GLuint))
+BGL_Wrap(1, Color4uiv, void, (GLuintP))
+BGL_Wrap(4, Color4us, void, (GLushort, GLushort, GLushort, GLushort))
+BGL_Wrap(1, Color4usv, void, (GLushortP))
+BGL_Wrap(4, ColorMask, void, (GLboolean, GLboolean, GLboolean, GLboolean))
+BGL_Wrap(2, ColorMaterial, void, (GLenum, GLenum))
+BGL_Wrap(5, CopyPixels, void, (GLint, GLint, GLsizei, GLsizei, GLenum))
+BGL_Wrap(1, CullFace, void, (GLenum))
+BGL_Wrap(2, DeleteLists, void, (GLuint, GLsizei))
+BGL_Wrap(2, DeleteTextures, void, (GLsizei, GLuintP))
+BGL_Wrap(1, DepthFunc, void, (GLenum))
+BGL_Wrap(1, DepthMask, void, (GLboolean))
+BGL_Wrap(2, DepthRange, void, (GLclampd, GLclampd))
+BGL_Wrap(1, Disable, void, (GLenum))
+BGL_Wrap(1, DrawBuffer, void, (GLenum))
+BGL_Wrap(5, DrawPixels, void, (GLsizei, GLsizei, GLenum, GLenum, GLvoidP))
+BGL_Wrap(1, EdgeFlag, void, (GLboolean))
+BGL_Wrap(1, EdgeFlagv, void, (GLbooleanP))
+BGL_Wrap(1, Enable, void, (GLenum))
+BGL_Wrap(1, End, void, (void))
+BGL_Wrap(1, EndList, void, (void))
+BGL_Wrap(1, EvalCoord1d, void, (GLdouble))
+BGL_Wrap(1, EvalCoord1dv, void, (GLdoubleP))
+BGL_Wrap(1, EvalCoord1f, void, (GLfloat))
+BGL_Wrap(1, EvalCoord1fv, void, (GLfloatP))
+BGL_Wrap(2, EvalCoord2d, void, (GLdouble, GLdouble))
+BGL_Wrap(1, EvalCoord2dv, void, (GLdoubleP))
+BGL_Wrap(2, EvalCoord2f, void, (GLfloat, GLfloat))
+BGL_Wrap(1, EvalCoord2fv, void, (GLfloatP))
+BGL_Wrap(3, EvalMesh1, void, (GLenum, GLint, GLint))
+BGL_Wrap(5, EvalMesh2, void, (GLenum, GLint, GLint, GLint, GLint))
+BGL_Wrap(1, EvalPoint1, void, (GLint))
+BGL_Wrap(2, EvalPoint2, void, (GLint, GLint))
+BGL_Wrap(3, FeedbackBuffer, void, (GLsizei, GLenum, GLfloatP))
+BGL_Wrap(1, Finish, void, (void))
+BGL_Wrap(1, Flush, void, (void))
+BGL_Wrap(2, Fogf, void, (GLenum, GLfloat))
+BGL_Wrap(2, Fogfv, void, (GLenum, GLfloatP))
+BGL_Wrap(2, Fogi, void, (GLenum, GLint))
+BGL_Wrap(2, Fogiv, void, (GLenum, GLintP))
+BGL_Wrap(1, FrontFace, void, (GLenum))
+BGL_Wrap(6, Frustum, void, (GLdouble, GLdouble,
+ GLdouble, GLdouble, GLdouble, GLdouble))
+BGL_Wrap(1, GenLists, GLuint, (GLsizei))
+BGL_Wrap(2, GenTextures, void, (GLsizei, GLuintP))
+BGL_Wrap(2, GetBooleanv, void, (GLenum, GLbooleanP))
+BGL_Wrap(2, GetClipPlane, void, (GLenum, GLdoubleP))
+BGL_Wrap(2, GetDoublev, void, (GLenum, GLdoubleP))
+BGL_Wrap(1, GetError, GLenum, (void))
+BGL_Wrap(2, GetFloatv, void, (GLenum, GLfloatP))
+BGL_Wrap(2, GetIntegerv, void, (GLenum, GLintP))
+BGL_Wrap(3, GetLightfv, void, (GLenum, GLenum, GLfloatP))
+BGL_Wrap(3, GetLightiv, void, (GLenum, GLenum, GLintP))
+BGL_Wrap(3, GetMapdv, void, (GLenum, GLenum, GLdoubleP))
+BGL_Wrap(3, GetMapfv, void, (GLenum, GLenum, GLfloatP))
+BGL_Wrap(3, GetMapiv, void, (GLenum, GLenum, GLintP))
+BGL_Wrap(3, GetMaterialfv, void, (GLenum, GLenum, GLfloatP))
+BGL_Wrap(3, GetMaterialiv, void, (GLenum, GLenum, GLintP))
+BGL_Wrap(2, GetPixelMapfv, void, (GLenum, GLfloatP))
+BGL_Wrap(2, GetPixelMapuiv, void, (GLenum, GLuintP))
+BGL_Wrap(2, GetPixelMapusv, void, (GLenum, GLushortP))
+BGL_Wrap(1, GetPolygonStipple,void, (GLubyteP))
+BGL_Wrap(1, GetString, GLstring, (GLenum))
+BGL_Wrap(3, GetTexEnvfv, void, (GLenum, GLenum, GLfloatP))
+BGL_Wrap(3, GetTexEnviv, void, (GLenum, GLenum, GLintP))
+BGL_Wrap(3, GetTexGendv, void, (GLenum, GLenum, GLdoubleP))
+BGL_Wrap(3, GetTexGenfv, void, (GLenum, GLenum, GLfloatP))
+BGL_Wrap(3, GetTexGeniv, void, (GLenum, GLenum, GLintP))
+BGL_Wrap(5, GetTexImage, void, (GLenum, GLint, GLenum, GLenum, GLvoidP))
+BGL_Wrap(4, GetTexLevelParameterfv, void, (GLenum, GLint, GLenum, GLfloatP))
+BGL_Wrap(4, GetTexLevelParameteriv, void, (GLenum, GLint, GLenum, GLintP))
+BGL_Wrap(3, GetTexParameterfv, void, (GLenum, GLenum, GLfloatP))
+BGL_Wrap(3, GetTexParameteriv, void, (GLenum, GLenum, GLintP))
+BGL_Wrap(2, Hint, void, (GLenum, GLenum))
+BGL_Wrap(1, IndexMask, void, (GLuint))
+BGL_Wrap(1, Indexd, void, (GLdouble))
+BGL_Wrap(1, Indexdv, void, (GLdoubleP))
+BGL_Wrap(1, Indexf, void, (GLfloat))
+BGL_Wrap(1, Indexfv, void, (GLfloatP))
+BGL_Wrap(1, Indexi, void, (GLint))
+BGL_Wrap(1, Indexiv, void, (GLintP))
+BGL_Wrap(1, Indexs, void, (GLshort))
+BGL_Wrap(1, Indexsv, void, (GLshortP))
+BGL_Wrap(1, InitNames, void, (void))
+BGL_Wrap(1, IsEnabled, GLboolean, (GLenum))
+BGL_Wrap(1, IsList, GLboolean, (GLuint))
+BGL_Wrap(1, IsTexture, GLboolean, (GLuint))
+BGL_Wrap(2, LightModelf, void, (GLenum, GLfloat))
+BGL_Wrap(2, LightModelfv, void, (GLenum, GLfloatP))
+BGL_Wrap(2, LightModeli, void, (GLenum, GLint))
+BGL_Wrap(2, LightModeliv, void, (GLenum, GLintP))
+BGL_Wrap(3, Lightf, void, (GLenum, GLenum, GLfloat))
+BGL_Wrap(3, Lightfv, void, (GLenum, GLenum, GLfloatP))
+BGL_Wrap(3, Lighti, void, (GLenum, GLenum, GLint))
+BGL_Wrap(3, Lightiv, void, (GLenum, GLenum, GLintP))
+BGL_Wrap(2, LineStipple, void, (GLint, GLushort))
+BGL_Wrap(1, LineWidth, void, (GLfloat))
+BGL_Wrap(1, ListBase, void, (GLuint))
+BGL_Wrap(1, LoadIdentity, void, (void))
+BGL_Wrap(1, LoadMatrixd, void, (GLdoubleP))
+BGL_Wrap(1, LoadMatrixf, void, (GLfloatP))
+BGL_Wrap(1, LoadName, void, (GLuint))
+BGL_Wrap(1, LogicOp, void, (GLenum))
+BGL_Wrap(6, Map1d, void, (GLenum, GLdouble, GLdouble,
+ GLint, GLint, GLdoubleP))
+BGL_Wrap(6, Map1f, void, (GLenum, GLfloat, GLfloat,
+ GLint, GLint, GLfloatP))
+BGL_Wrap(10, Map2d, void, (GLenum, GLdouble, GLdouble,
+ GLint, GLint, GLdouble, GLdouble, GLint, GLint, GLdoubleP))
+BGL_Wrap(10, Map2f, void, (GLenum, GLfloat, GLfloat,
+ GLint, GLint, GLfloat, GLfloat, GLint, GLint, GLfloatP))
+BGL_Wrap(3, MapGrid1d, void, (GLint, GLdouble, GLdouble))
+BGL_Wrap(3, MapGrid1f, void, (GLint, GLfloat, GLfloat))
+BGL_Wrap(6, MapGrid2d, void, (GLint, GLdouble, GLdouble,
+ GLint, GLdouble, GLdouble))
+BGL_Wrap(6, MapGrid2f, void, (GLint, GLfloat, GLfloat,
+ GLint, GLfloat, GLfloat))
+BGL_Wrap(3, Materialf, void, (GLenum, GLenum, GLfloat))
+BGL_Wrap(3, Materialfv, void, (GLenum, GLenum, GLfloatP))
+BGL_Wrap(3, Materiali, void, (GLenum, GLenum, GLint))
+BGL_Wrap(3, Materialiv, void, (GLenum, GLenum, GLintP))
+BGL_Wrap(1, MatrixMode, void, (GLenum))
+BGL_Wrap(1, MultMatrixd, void, (GLdoubleP))
+BGL_Wrap(1, MultMatrixf, void, (GLfloatP))
+BGL_Wrap(2, NewList, void, (GLuint, GLenum))
+BGL_Wrap(3, Normal3b, void, (GLbyte, GLbyte, GLbyte))
+BGL_Wrap(1, Normal3bv, void, (GLbyteP))
+BGL_Wrap(3, Normal3d, void, (GLdouble, GLdouble, GLdouble))
+BGL_Wrap(1, Normal3dv, void, (GLdoubleP))
+BGL_Wrap(3, Normal3f, void, (GLfloat, GLfloat, GLfloat))
+BGL_Wrap(1, Normal3fv, void, (GLfloatP))
+BGL_Wrap(3, Normal3i, void, (GLint, GLint, GLint))
+BGL_Wrap(1, Normal3iv, void, (GLintP))
+BGL_Wrap(3, Normal3s, void, (GLshort, GLshort, GLshort))
+BGL_Wrap(1, Normal3sv, void, (GLshortP))
+BGL_Wrap(6, Ortho, void, (GLdouble, GLdouble,
+ GLdouble, GLdouble, GLdouble, GLdouble))
+BGL_Wrap(1, PassThrough, void, (GLfloat))
+BGL_Wrap(3, PixelMapfv, void, (GLenum, GLint, GLfloatP))
+BGL_Wrap(3, PixelMapuiv, void, (GLenum, GLint, GLuintP))
+BGL_Wrap(3, PixelMapusv, void, (GLenum, GLint, GLushortP))
+BGL_Wrap(2, PixelStoref, void, (GLenum, GLfloat))
+BGL_Wrap(2, PixelStorei, void, (GLenum, GLint))
+BGL_Wrap(2, PixelTransferf, void, (GLenum, GLfloat))
+BGL_Wrap(2, PixelTransferi, void, (GLenum, GLint))
+BGL_Wrap(2, PixelZoom, void, (GLfloat, GLfloat))
+BGL_Wrap(1, PointSize, void, (GLfloat))
+BGL_Wrap(2, PolygonMode, void, (GLenum, GLenum))
+BGL_Wrap(2, PolygonOffset, void, (GLfloat, GLfloat))
+BGL_Wrap(1, PolygonStipple, void, (GLubyteP))
+BGL_Wrap(1, PopAttrib, void, (void))
+BGL_Wrap(1, PopClientAttrib, void, (void))
+BGL_Wrap(1, PopMatrix, void, (void))
+BGL_Wrap(1, PopName, void, (void))
+BGL_Wrap(3, PrioritizeTextures, void, (GLsizei, GLuintP, GLclampfP))
+BGL_Wrap(1, PushAttrib, void, (GLbitfield))
+BGL_Wrap(1, PushClientAttrib, void, (GLbitfield))
+BGL_Wrap(1, PushMatrix, void, (void))
+BGL_Wrap(1, PushName, void, (GLuint))
+BGL_Wrap(2, RasterPos2d, void, (GLdouble, GLdouble))
+BGL_Wrap(1, RasterPos2dv, void, (GLdoubleP))
+BGL_Wrap(2, RasterPos2f, void, (GLfloat, GLfloat))
+BGL_Wrap(1, RasterPos2fv, void, (GLfloatP))
+BGL_Wrap(2, RasterPos2i, void, (GLint, GLint))
+BGL_Wrap(1, RasterPos2iv, void, (GLintP))
+BGL_Wrap(2, RasterPos2s, void, (GLshort, GLshort))
+BGL_Wrap(1, RasterPos2sv, void, (GLshortP))
+BGL_Wrap(3, RasterPos3d, void, (GLdouble, GLdouble, GLdouble))
+BGL_Wrap(1, RasterPos3dv, void, (GLdoubleP))
+BGL_Wrap(3, RasterPos3f, void, (GLfloat, GLfloat, GLfloat))
+BGL_Wrap(1, RasterPos3fv, void, (GLfloatP))
+BGL_Wrap(3, RasterPos3i, void, (GLint, GLint, GLint))
+BGL_Wrap(1, RasterPos3iv, void, (GLintP))
+BGL_Wrap(3, RasterPos3s, void, (GLshort, GLshort, GLshort))
+BGL_Wrap(1, RasterPos3sv, void, (GLshortP))
+BGL_Wrap(4, RasterPos4d, void, (GLdouble, GLdouble, GLdouble, GLdouble))
+BGL_Wrap(1, RasterPos4dv, void, (GLdoubleP))
+BGL_Wrap(4, RasterPos4f, void, (GLfloat, GLfloat, GLfloat, GLfloat))
+BGL_Wrap(1, RasterPos4fv, void, (GLfloatP))
+BGL_Wrap(4, RasterPos4i, void, (GLint, GLint, GLint, GLint))
+BGL_Wrap(1, RasterPos4iv, void, (GLintP))
+BGL_Wrap(4, RasterPos4s, void, (GLshort, GLshort, GLshort, GLshort))
+BGL_Wrap(1, RasterPos4sv, void, (GLshortP))
+BGL_Wrap(1, ReadBuffer, void, (GLenum))
+BGL_Wrap(7, ReadPixels, void, (GLint, GLint, GLsizei,
+ GLsizei, GLenum, GLenum, GLvoidP))
+BGL_Wrap(4, Rectd, void, (GLdouble, GLdouble, GLdouble, GLdouble))
+BGL_Wrap(2, Rectdv, void, (GLdoubleP, GLdoubleP))
+BGL_Wrap(4, Rectf, void, (GLfloat, GLfloat, GLfloat, GLfloat))
+BGL_Wrap(2, Rectfv, void, (GLfloatP, GLfloatP))
+BGL_Wrap(4, Recti, void, (GLint, GLint, GLint, GLint))
+BGL_Wrap(2, Rectiv, void, (GLintP, GLintP))
+BGL_Wrap(4, Rects, void, (GLshort, GLshort, GLshort, GLshort))
+BGL_Wrap(2, Rectsv, void, (GLshortP, GLshortP))
+BGL_Wrap(1, RenderMode, GLint, (GLenum))
+BGL_Wrap(4, Rotated, void, (GLdouble, GLdouble, GLdouble, GLdouble))
+BGL_Wrap(4, Rotatef, void, (GLfloat, GLfloat, GLfloat, GLfloat))
+BGL_Wrap(3, Scaled, void, (GLdouble, GLdouble, GLdouble))
+BGL_Wrap(3, Scalef, void, (GLfloat, GLfloat, GLfloat))
+BGL_Wrap(4, Scissor, void, (GLint, GLint, GLsizei, GLsizei))
+BGL_Wrap(2, SelectBuffer, void, (GLsizei, GLuintP))
+BGL_Wrap(1, ShadeModel, void, (GLenum))
+BGL_Wrap(3, StencilFunc, void, (GLenum, GLint, GLuint))
+BGL_Wrap(1, StencilMask, void, (GLuint))
+BGL_Wrap(3, StencilOp, void, (GLenum, GLenum, GLenum))
+BGL_Wrap(1, TexCoord1d, void, (GLdouble))
+BGL_Wrap(1, TexCoord1dv, void, (GLdoubleP))
+BGL_Wrap(1, TexCoord1f, void, (GLfloat))
+BGL_Wrap(1, TexCoord1fv, void, (GLfloatP))
+BGL_Wrap(1, TexCoord1i, void, (GLint))
+BGL_Wrap(1, TexCoord1iv, void, (GLintP))
+BGL_Wrap(1, TexCoord1s, void, (GLshort))
+BGL_Wrap(1, TexCoord1sv, void, (GLshortP))
+BGL_Wrap(2, TexCoord2d, void, (GLdouble, GLdouble))
+BGL_Wrap(1, TexCoord2dv, void, (GLdoubleP))
+BGL_Wrap(2, TexCoord2f, void, (GLfloat, GLfloat))
+BGL_Wrap(1, TexCoord2fv, void, (GLfloatP))
+BGL_Wrap(2, TexCoord2i, void, (GLint, GLint))
+BGL_Wrap(1, TexCoord2iv, void, (GLintP))
+BGL_Wrap(2, TexCoord2s, void, (GLshort, GLshort))
+BGL_Wrap(1, TexCoord2sv, void, (GLshortP))
+BGL_Wrap(3, TexCoord3d, void, (GLdouble, GLdouble, GLdouble))
+BGL_Wrap(1, TexCoord3dv, void, (GLdoubleP))
+BGL_Wrap(3, TexCoord3f, void, (GLfloat, GLfloat, GLfloat))
+BGL_Wrap(1, TexCoord3fv, void, (GLfloatP))
+BGL_Wrap(3, TexCoord3i, void, (GLint, GLint, GLint))
+BGL_Wrap(1, TexCoord3iv, void, (GLintP))
+BGL_Wrap(3, TexCoord3s, void, (GLshort, GLshort, GLshort))
+BGL_Wrap(1, TexCoord3sv, void, (GLshortP))
+BGL_Wrap(4, TexCoord4d, void, (GLdouble, GLdouble, GLdouble, GLdouble))
+BGL_Wrap(1, TexCoord4dv, void, (GLdoubleP))
+BGL_Wrap(4, TexCoord4f, void, (GLfloat, GLfloat, GLfloat, GLfloat))
+BGL_Wrap(1, TexCoord4fv, void, (GLfloatP))
+BGL_Wrap(4, TexCoord4i, void, (GLint, GLint, GLint, GLint))
+BGL_Wrap(1, TexCoord4iv, void, (GLintP))
+BGL_Wrap(4, TexCoord4s, void, (GLshort, GLshort, GLshort, GLshort))
+BGL_Wrap(1, TexCoord4sv, void, (GLshortP))
+BGL_Wrap(3, TexEnvf, void, (GLenum, GLenum, GLfloat))
+BGL_Wrap(3, TexEnvfv, void, (GLenum, GLenum, GLfloatP))
+BGL_Wrap(3, TexEnvi, void, (GLenum, GLenum, GLint))
+BGL_Wrap(3, TexEnviv, void, (GLenum, GLenum, GLintP))
+BGL_Wrap(3, TexGend, void, (GLenum, GLenum, GLdouble))
+BGL_Wrap(3, TexGendv, void, (GLenum, GLenum, GLdoubleP))
+BGL_Wrap(3, TexGenf, void, (GLenum, GLenum, GLfloat))
+BGL_Wrap(3, TexGenfv, void, (GLenum, GLenum, GLfloatP))
+BGL_Wrap(3, TexGeni, void, (GLenum, GLenum, GLint))
+BGL_Wrap(3, TexGeniv, void, (GLenum, GLenum, GLintP))
+BGL_Wrap(8, TexImage1D, void, (GLenum, GLint, GLint,
+ GLsizei, GLint, GLenum, GLenum, GLvoidP))
+BGL_Wrap(9, TexImage2D, void, (GLenum, GLint, GLint,
+ GLsizei, GLsizei, GLint, GLenum, GLenum, GLvoidP))
+BGL_Wrap(3, TexParameterf, void, (GLenum, GLenum, GLfloat))
+BGL_Wrap(3, TexParameterfv, void, (GLenum, GLenum, GLfloatP))
+BGL_Wrap(3, TexParameteri, void, (GLenum, GLenum, GLint))
+BGL_Wrap(3, TexParameteriv, void, (GLenum, GLenum, GLintP))
+BGL_Wrap(3, Translated, void, (GLdouble, GLdouble, GLdouble))
+BGL_Wrap(3, Translatef, void, (GLfloat, GLfloat, GLfloat))
+BGL_Wrap(2, Vertex2d, void, (GLdouble, GLdouble))
+BGL_Wrap(1, Vertex2dv, void, (GLdoubleP))
+BGL_Wrap(2, Vertex2f, void, (GLfloat, GLfloat))
+BGL_Wrap(1, Vertex2fv, void, (GLfloatP))
+BGL_Wrap(2, Vertex2i, void, (GLint, GLint))
+BGL_Wrap(1, Vertex2iv, void, (GLintP))
+BGL_Wrap(2, Vertex2s, void, (GLshort, GLshort))
+BGL_Wrap(1, Vertex2sv, void, (GLshortP))
+BGL_Wrap(3, Vertex3d, void, (GLdouble, GLdouble, GLdouble))
+BGL_Wrap(1, Vertex3dv, void, (GLdoubleP))
+BGL_Wrap(3, Vertex3f, void, (GLfloat, GLfloat, GLfloat))
+BGL_Wrap(1, Vertex3fv, void, (GLfloatP))
+BGL_Wrap(3, Vertex3i, void, (GLint, GLint, GLint))
+BGL_Wrap(1, Vertex3iv, void, (GLintP))
+BGL_Wrap(3, Vertex3s, void, (GLshort, GLshort, GLshort))
+BGL_Wrap(1, Vertex3sv, void, (GLshortP))
+BGL_Wrap(4, Vertex4d, void, (GLdouble, GLdouble, GLdouble, GLdouble))
+BGL_Wrap(1, Vertex4dv, void, (GLdoubleP))
+BGL_Wrap(4, Vertex4f, void, (GLfloat, GLfloat, GLfloat, GLfloat))
+BGL_Wrap(1, Vertex4fv, void, (GLfloatP))
+BGL_Wrap(4, Vertex4i, void, (GLint, GLint, GLint, GLint))
+BGL_Wrap(1, Vertex4iv, void, (GLintP))
+BGL_Wrap(4, Vertex4s, void, (GLshort, GLshort, GLshort, GLshort))
+BGL_Wrap(1, Vertex4sv, void, (GLshortP))
+BGL_Wrap(4, Viewport, void, (GLint, GLint, GLsizei, GLsizei))
+BGLU_Wrap(4, Perspective, void, (GLdouble, GLdouble, GLdouble, GLdouble))
+BGLU_Wrap(9, LookAt, void, (GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble))
+BGLU_Wrap(4, Ortho2D, void, (GLdouble, GLdouble, GLdouble, GLdouble))
+BGLU_Wrap(5, PickMatrix, void, (GLdouble, GLdouble, GLdouble, GLdouble, GLintP))
+BGLU_Wrap(9, Project, GLint, (GLdouble, GLdouble, GLdouble, GLdoubleP, GLdoubleP, GLintP, GLdoubleP, GLdoubleP, GLdoubleP))
+BGLU_Wrap(9, UnProject, GLint, (GLdouble, GLdouble, GLdouble, GLdoubleP, GLdoubleP, GLintP, GLdoubleP, GLdoubleP, GLdoubleP))
+
+#undef MethodDef
+#define MethodDef(func) {"gl"#func, Method_##func, METH_VARARGS, "no string"}
+#define MethodDefu(func) {"glu"#func, Method_##func, METH_VARARGS, "no string"}
+/* So that MethodDef(Accum) becomes:
+ * {"glAccum", Method_Accumfunc, METH_VARARGS} */
+
+static struct PyMethodDef BGL_methods[] = {
+ {"Buffer", Method_Buffer, METH_VARARGS, Method_Buffer_doc},
+
+/* #ifndef __APPLE__ */
+ MethodDef(Accum),
+ MethodDef(AlphaFunc),
+ MethodDef(AreTexturesResident),
+ MethodDef(Begin),
+ MethodDef(BindTexture),
+ MethodDef(Bitmap),
+ MethodDef(BlendFunc),
+ MethodDef(CallList),
+ MethodDef(CallLists),
+ MethodDef(Clear),
+ MethodDef(ClearAccum),
+ MethodDef(ClearColor),
+ MethodDef(ClearDepth),
+ MethodDef(ClearIndex),
+ MethodDef(ClearStencil),
+ MethodDef(ClipPlane),
+ MethodDef(Color3b),
+ MethodDef(Color3bv),
+ MethodDef(Color3d),
+ MethodDef(Color3dv),
+ MethodDef(Color3f),
+ MethodDef(Color3fv),
+ MethodDef(Color3i),
+ MethodDef(Color3iv),
+ MethodDef(Color3s),
+ MethodDef(Color3sv),
+ MethodDef(Color3ub),
+ MethodDef(Color3ubv),
+ MethodDef(Color3ui),
+ MethodDef(Color3uiv),
+ MethodDef(Color3us),
+ MethodDef(Color3usv),
+ MethodDef(Color4b),
+ MethodDef(Color4bv),
+ MethodDef(Color4d),
+ MethodDef(Color4dv),
+ MethodDef(Color4f),
+ MethodDef(Color4fv),
+ MethodDef(Color4i),
+ MethodDef(Color4iv),
+ MethodDef(Color4s),
+ MethodDef(Color4sv),
+ MethodDef(Color4ub),
+ MethodDef(Color4ubv),
+ MethodDef(Color4ui),
+ MethodDef(Color4uiv),
+ MethodDef(Color4us),
+ MethodDef(Color4usv),
+ MethodDef(ColorMask),
+ MethodDef(ColorMaterial),
+ MethodDef(CopyPixels),
+ MethodDef(CullFace),
+ MethodDef(DeleteLists),
+ MethodDef(DeleteTextures),
+ MethodDef(DepthFunc),
+ MethodDef(DepthMask),
+ MethodDef(DepthRange),
+ MethodDef(Disable),
+ MethodDef(DrawBuffer),
+ MethodDef(DrawPixels),
+ MethodDef(EdgeFlag),
+ MethodDef(EdgeFlagv),
+ MethodDef(Enable),
+ MethodDef(End),
+ MethodDef(EndList),
+ MethodDef(EvalCoord1d),
+ MethodDef(EvalCoord1dv),
+ MethodDef(EvalCoord1f),
+ MethodDef(EvalCoord1fv),
+ MethodDef(EvalCoord2d),
+ MethodDef(EvalCoord2dv),
+ MethodDef(EvalCoord2f),
+ MethodDef(EvalCoord2fv),
+ MethodDef(EvalMesh1),
+ MethodDef(EvalMesh2),
+ MethodDef(EvalPoint1),
+ MethodDef(EvalPoint2),
+ MethodDef(FeedbackBuffer),
+ MethodDef(Finish),
+ MethodDef(Flush),
+ MethodDef(Fogf),
+ MethodDef(Fogfv),
+ MethodDef(Fogi),
+ MethodDef(Fogiv),
+ MethodDef(FrontFace),
+ MethodDef(Frustum),
+ MethodDef(GenLists),
+ MethodDef(GenTextures),
+ MethodDef(GetBooleanv),
+ MethodDef(GetClipPlane),
+ MethodDef(GetDoublev),
+ MethodDef(GetError),
+ MethodDef(GetFloatv),
+ MethodDef(GetIntegerv),
+ MethodDef(GetLightfv),
+ MethodDef(GetLightiv),
+ MethodDef(GetMapdv),
+ MethodDef(GetMapfv),
+ MethodDef(GetMapiv),
+ MethodDef(GetMaterialfv),
+ MethodDef(GetMaterialiv),
+ MethodDef(GetPixelMapfv),
+ MethodDef(GetPixelMapuiv),
+ MethodDef(GetPixelMapusv),
+ MethodDef(GetPolygonStipple),
+ MethodDef(GetString),
+ MethodDef(GetTexEnvfv),
+ MethodDef(GetTexEnviv),
+ MethodDef(GetTexGendv),
+ MethodDef(GetTexGenfv),
+ MethodDef(GetTexGeniv),
+ MethodDef(GetTexImage),
+ MethodDef(GetTexLevelParameterfv),
+ MethodDef(GetTexLevelParameteriv),
+ MethodDef(GetTexParameterfv),
+ MethodDef(GetTexParameteriv),
+ MethodDef(Hint),
+ MethodDef(IndexMask),
+ MethodDef(Indexd),
+ MethodDef(Indexdv),
+ MethodDef(Indexf),
+ MethodDef(Indexfv),
+ MethodDef(Indexi),
+ MethodDef(Indexiv),
+ MethodDef(Indexs),
+ MethodDef(Indexsv),
+ MethodDef(InitNames),
+ MethodDef(IsEnabled),
+ MethodDef(IsList),
+ MethodDef(IsTexture),
+ MethodDef(LightModelf),
+ MethodDef(LightModelfv),
+ MethodDef(LightModeli),
+ MethodDef(LightModeliv),
+ MethodDef(Lightf),
+ MethodDef(Lightfv),
+ MethodDef(Lighti),
+ MethodDef(Lightiv),
+ MethodDef(LineStipple),
+ MethodDef(LineWidth),
+ MethodDef(ListBase),
+ MethodDef(LoadIdentity),
+ MethodDef(LoadMatrixd),
+ MethodDef(LoadMatrixf),
+ MethodDef(LoadName),
+ MethodDef(LogicOp),
+ MethodDef(Map1d),
+ MethodDef(Map1f),
+ MethodDef(Map2d),
+ MethodDef(Map2f),
+ MethodDef(MapGrid1d),
+ MethodDef(MapGrid1f),
+ MethodDef(MapGrid2d),
+ MethodDef(MapGrid2f),
+ MethodDef(Materialf),
+ MethodDef(Materialfv),
+ MethodDef(Materiali),
+ MethodDef(Materialiv),
+ MethodDef(MatrixMode),
+ MethodDef(MultMatrixd),
+ MethodDef(MultMatrixf),
+ MethodDef(NewList),
+ MethodDef(Normal3b),
+ MethodDef(Normal3bv),
+ MethodDef(Normal3d),
+ MethodDef(Normal3dv),
+ MethodDef(Normal3f),
+ MethodDef(Normal3fv),
+ MethodDef(Normal3i),
+ MethodDef(Normal3iv),
+ MethodDef(Normal3s),
+ MethodDef(Normal3sv),
+ MethodDef(Ortho),
+ MethodDef(PassThrough),
+ MethodDef(PixelMapfv),
+ MethodDef(PixelMapuiv),
+ MethodDef(PixelMapusv),
+ MethodDef(PixelStoref),
+ MethodDef(PixelStorei),
+ MethodDef(PixelTransferf),
+ MethodDef(PixelTransferi),
+ MethodDef(PixelZoom),
+ MethodDef(PointSize),
+ MethodDef(PolygonMode),
+ MethodDef(PolygonOffset),
+ MethodDef(PolygonStipple),
+ MethodDef(PopAttrib),
+ MethodDef(PopClientAttrib),
+ MethodDef(PopMatrix),
+ MethodDef(PopName),
+ MethodDef(PrioritizeTextures),
+ MethodDef(PushAttrib),
+ MethodDef(PushClientAttrib),
+ MethodDef(PushMatrix),
+ MethodDef(PushName),
+ MethodDef(RasterPos2d),
+ MethodDef(RasterPos2dv),
+ MethodDef(RasterPos2f),
+ MethodDef(RasterPos2fv),
+ MethodDef(RasterPos2i),
+ MethodDef(RasterPos2iv),
+ MethodDef(RasterPos2s),
+ MethodDef(RasterPos2sv),
+ MethodDef(RasterPos3d),
+ MethodDef(RasterPos3dv),
+ MethodDef(RasterPos3f),
+ MethodDef(RasterPos3fv),
+ MethodDef(RasterPos3i),
+ MethodDef(RasterPos3iv),
+ MethodDef(RasterPos3s),
+ MethodDef(RasterPos3sv),
+ MethodDef(RasterPos4d),
+ MethodDef(RasterPos4dv),
+ MethodDef(RasterPos4f),
+ MethodDef(RasterPos4fv),
+ MethodDef(RasterPos4i),
+ MethodDef(RasterPos4iv),
+ MethodDef(RasterPos4s),
+ MethodDef(RasterPos4sv),
+ MethodDef(ReadBuffer),
+ MethodDef(ReadPixels),
+ MethodDef(Rectd),
+ MethodDef(Rectdv),
+ MethodDef(Rectf),
+ MethodDef(Rectfv),
+ MethodDef(Recti),
+ MethodDef(Rectiv),
+ MethodDef(Rects),
+ MethodDef(Rectsv),
+ MethodDef(RenderMode),
+ MethodDef(Rotated),
+ MethodDef(Rotatef),
+ MethodDef(Scaled),
+ MethodDef(Scalef),
+ MethodDef(Scissor),
+ MethodDef(SelectBuffer),
+ MethodDef(ShadeModel),
+ MethodDef(StencilFunc),
+ MethodDef(StencilMask),
+ MethodDef(StencilOp),
+ MethodDef(TexCoord1d),
+ MethodDef(TexCoord1dv),
+ MethodDef(TexCoord1f),
+ MethodDef(TexCoord1fv),
+ MethodDef(TexCoord1i),
+ MethodDef(TexCoord1iv),
+ MethodDef(TexCoord1s),
+ MethodDef(TexCoord1sv),
+ MethodDef(TexCoord2d),
+ MethodDef(TexCoord2dv),
+ MethodDef(TexCoord2f),
+ MethodDef(TexCoord2fv),
+ MethodDef(TexCoord2i),
+ MethodDef(TexCoord2iv),
+ MethodDef(TexCoord2s),
+ MethodDef(TexCoord2sv),
+ MethodDef(TexCoord3d),
+ MethodDef(TexCoord3dv),
+ MethodDef(TexCoord3f),
+ MethodDef(TexCoord3fv),
+ MethodDef(TexCoord3i),
+ MethodDef(TexCoord3iv),
+ MethodDef(TexCoord3s),
+ MethodDef(TexCoord3sv),
+ MethodDef(TexCoord4d),
+ MethodDef(TexCoord4dv),
+ MethodDef(TexCoord4f),
+ MethodDef(TexCoord4fv),
+ MethodDef(TexCoord4i),
+ MethodDef(TexCoord4iv),
+ MethodDef(TexCoord4s),
+ MethodDef(TexCoord4sv),
+ MethodDef(TexEnvf),
+ MethodDef(TexEnvfv),
+ MethodDef(TexEnvi),
+ MethodDef(TexEnviv),
+ MethodDef(TexGend),
+ MethodDef(TexGendv),
+ MethodDef(TexGenf),
+ MethodDef(TexGenfv),
+ MethodDef(TexGeni),
+ MethodDef(TexGeniv),
+ MethodDef(TexImage1D),
+ MethodDef(TexImage2D),
+ MethodDef(TexParameterf),
+ MethodDef(TexParameterfv),
+ MethodDef(TexParameteri),
+ MethodDef(TexParameteriv),
+ MethodDef(Translated),
+ MethodDef(Translatef),
+ MethodDef(Vertex2d),
+ MethodDef(Vertex2dv),
+ MethodDef(Vertex2f),
+ MethodDef(Vertex2fv),
+ MethodDef(Vertex2i),
+ MethodDef(Vertex2iv),
+ MethodDef(Vertex2s),
+ MethodDef(Vertex2sv),
+ MethodDef(Vertex3d),
+ MethodDef(Vertex3dv),
+ MethodDef(Vertex3f),
+ MethodDef(Vertex3fv),
+ MethodDef(Vertex3i),
+ MethodDef(Vertex3iv),
+ MethodDef(Vertex3s),
+ MethodDef(Vertex3sv),
+ MethodDef(Vertex4d),
+ MethodDef(Vertex4dv),
+ MethodDef(Vertex4f),
+ MethodDef(Vertex4fv),
+ MethodDef(Vertex4i),
+ MethodDef(Vertex4iv),
+ MethodDef(Vertex4s),
+ MethodDef(Vertex4sv),
+ MethodDef(Viewport),
+ MethodDefu(Perspective),
+ MethodDefu(LookAt),
+ MethodDefu(Ortho2D),
+ MethodDefu(PickMatrix),
+ MethodDefu(Project),
+ MethodDefu(UnProject),
+/* #endif */
+ {NULL, NULL, 0, NULL}
+};
+
+PyObject *BGL_Init(void)
+{
+ PyObject *mod= Py_InitModule("Blender.BGL", BGL_methods);
+ PyObject *dict= PyModule_GetDict(mod);
+
+ if( PyType_Ready( &buffer_Type) < 0)
+ Py_RETURN_NONE;
+
+#define EXPP_ADDCONST(x) EXPP_dict_set_item_str(dict, #x, PyInt_FromLong(x))
+
+/* So, for example:
+ * EXPP_ADDCONST(GL_CURRENT_BIT) becomes
+ * EXPP_dict_set_item_str(dict, "GL_CURRENT_BIT", PyInt_FromLong(GL_CURRENT_BIT)) */
+
+ EXPP_ADDCONST(GL_CURRENT_BIT);
+ EXPP_ADDCONST(GL_POINT_BIT);
+ EXPP_ADDCONST(GL_LINE_BIT);
+ EXPP_ADDCONST(GL_POLYGON_BIT);
+ EXPP_ADDCONST(GL_POLYGON_STIPPLE_BIT);
+ EXPP_ADDCONST(GL_PIXEL_MODE_BIT);
+ EXPP_ADDCONST(GL_LIGHTING_BIT);
+ EXPP_ADDCONST(GL_FOG_BIT);
+ EXPP_ADDCONST(GL_DEPTH_BUFFER_BIT);
+ EXPP_ADDCONST(GL_ACCUM_BUFFER_BIT);
+ EXPP_ADDCONST(GL_STENCIL_BUFFER_BIT);
+ EXPP_ADDCONST(GL_VIEWPORT_BIT);
+ EXPP_ADDCONST(GL_TRANSFORM_BIT);
+ EXPP_ADDCONST(GL_ENABLE_BIT);
+ EXPP_ADDCONST(GL_COLOR_BUFFER_BIT);
+ EXPP_ADDCONST(GL_HINT_BIT);
+ EXPP_ADDCONST(GL_EVAL_BIT);
+ EXPP_ADDCONST(GL_LIST_BIT);
+ EXPP_ADDCONST(GL_TEXTURE_BIT);
+ EXPP_ADDCONST(GL_SCISSOR_BIT);
+ EXPP_ADDCONST(GL_ALL_ATTRIB_BITS);
+
+ EXPP_ADDCONST(GL_FALSE);
+ EXPP_ADDCONST(GL_TRUE);
+
+ EXPP_ADDCONST(GL_POINTS);
+ EXPP_ADDCONST(GL_LINES);
+ EXPP_ADDCONST(GL_LINE_LOOP);
+ EXPP_ADDCONST(GL_LINE_STRIP);
+ EXPP_ADDCONST(GL_TRIANGLES);
+ EXPP_ADDCONST(GL_TRIANGLE_STRIP);
+ EXPP_ADDCONST(GL_TRIANGLE_FAN);
+ EXPP_ADDCONST(GL_QUADS);
+ EXPP_ADDCONST(GL_QUAD_STRIP);
+ EXPP_ADDCONST(GL_POLYGON);
+
+ EXPP_ADDCONST(GL_ACCUM);
+ EXPP_ADDCONST(GL_LOAD);
+ EXPP_ADDCONST(GL_RETURN);
+ EXPP_ADDCONST(GL_MULT);
+ EXPP_ADDCONST(GL_ADD);
+
+ EXPP_ADDCONST(GL_NEVER);
+ EXPP_ADDCONST(GL_LESS);
+ EXPP_ADDCONST(GL_EQUAL);
+ EXPP_ADDCONST(GL_LEQUAL);
+ EXPP_ADDCONST(GL_GREATER);
+ EXPP_ADDCONST(GL_NOTEQUAL);
+ EXPP_ADDCONST(GL_GEQUAL);
+ EXPP_ADDCONST(GL_ALWAYS);
+
+ EXPP_ADDCONST(GL_ZERO);
+ EXPP_ADDCONST(GL_ONE);
+ EXPP_ADDCONST(GL_SRC_COLOR);
+ EXPP_ADDCONST(GL_ONE_MINUS_SRC_COLOR);
+ EXPP_ADDCONST(GL_SRC_ALPHA);
+ EXPP_ADDCONST(GL_ONE_MINUS_SRC_ALPHA);
+ EXPP_ADDCONST(GL_DST_ALPHA);
+ EXPP_ADDCONST(GL_ONE_MINUS_DST_ALPHA);
+
+ EXPP_ADDCONST(GL_DST_COLOR);
+ EXPP_ADDCONST(GL_ONE_MINUS_DST_COLOR);
+ EXPP_ADDCONST(GL_SRC_ALPHA_SATURATE);
+
+ EXPP_ADDCONST(GL_NONE);
+ EXPP_ADDCONST(GL_FRONT_LEFT);
+ EXPP_ADDCONST(GL_FRONT_RIGHT);
+ EXPP_ADDCONST(GL_BACK_LEFT);
+ EXPP_ADDCONST(GL_BACK_RIGHT);
+ EXPP_ADDCONST(GL_FRONT);
+ EXPP_ADDCONST(GL_BACK);
+ EXPP_ADDCONST(GL_LEFT);
+ EXPP_ADDCONST(GL_RIGHT);
+ EXPP_ADDCONST(GL_FRONT_AND_BACK);
+ EXPP_ADDCONST(GL_AUX0);
+ EXPP_ADDCONST(GL_AUX1);
+ EXPP_ADDCONST(GL_AUX2);
+ EXPP_ADDCONST(GL_AUX3);
+
+ EXPP_ADDCONST(GL_NO_ERROR);
+ EXPP_ADDCONST(GL_INVALID_ENUM);
+ EXPP_ADDCONST(GL_INVALID_VALUE);
+ EXPP_ADDCONST(GL_INVALID_OPERATION);
+ EXPP_ADDCONST(GL_STACK_OVERFLOW);
+ EXPP_ADDCONST(GL_STACK_UNDERFLOW);
+ EXPP_ADDCONST(GL_OUT_OF_MEMORY);
+
+ EXPP_ADDCONST(GL_2D);
+ EXPP_ADDCONST(GL_3D);
+ EXPP_ADDCONST(GL_3D_COLOR);
+ EXPP_ADDCONST(GL_3D_COLOR_TEXTURE);
+ EXPP_ADDCONST(GL_4D_COLOR_TEXTURE);
+
+ EXPP_ADDCONST(GL_PASS_THROUGH_TOKEN);
+ EXPP_ADDCONST(GL_POINT_TOKEN);
+ EXPP_ADDCONST(GL_LINE_TOKEN);
+ EXPP_ADDCONST(GL_POLYGON_TOKEN);
+ EXPP_ADDCONST(GL_BITMAP_TOKEN);
+ EXPP_ADDCONST(GL_DRAW_PIXEL_TOKEN);
+ EXPP_ADDCONST(GL_COPY_PIXEL_TOKEN);
+ EXPP_ADDCONST(GL_LINE_RESET_TOKEN);
+
+ EXPP_ADDCONST(GL_EXP);
+ EXPP_ADDCONST(GL_EXP2);
+
+ EXPP_ADDCONST(GL_CW);
+ EXPP_ADDCONST(GL_CCW);
+
+ EXPP_ADDCONST(GL_COEFF);
+ EXPP_ADDCONST(GL_ORDER);
+ EXPP_ADDCONST(GL_DOMAIN);
+
+ EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_I);
+ EXPP_ADDCONST(GL_PIXEL_MAP_S_TO_S);
+ EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_R);
+ EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_G);
+ EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_B);
+ EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_A);
+ EXPP_ADDCONST(GL_PIXEL_MAP_R_TO_R);
+ EXPP_ADDCONST(GL_PIXEL_MAP_G_TO_G);
+ EXPP_ADDCONST(GL_PIXEL_MAP_B_TO_B);
+ EXPP_ADDCONST(GL_PIXEL_MAP_A_TO_A);
+
+ EXPP_ADDCONST(GL_CURRENT_COLOR);
+ EXPP_ADDCONST(GL_CURRENT_INDEX);
+ EXPP_ADDCONST(GL_CURRENT_NORMAL);
+ EXPP_ADDCONST(GL_CURRENT_TEXTURE_COORDS);
+ EXPP_ADDCONST(GL_CURRENT_RASTER_COLOR);
+ EXPP_ADDCONST(GL_CURRENT_RASTER_INDEX);
+ EXPP_ADDCONST(GL_CURRENT_RASTER_TEXTURE_COORDS);
+ EXPP_ADDCONST(GL_CURRENT_RASTER_POSITION);
+ EXPP_ADDCONST(GL_CURRENT_RASTER_POSITION_VALID);
+ EXPP_ADDCONST(GL_CURRENT_RASTER_DISTANCE);
+ EXPP_ADDCONST(GL_POINT_SMOOTH);
+ EXPP_ADDCONST(GL_POINT_SIZE);
+ EXPP_ADDCONST(GL_POINT_SIZE_RANGE);
+ EXPP_ADDCONST(GL_POINT_SIZE_GRANULARITY);
+ EXPP_ADDCONST(GL_LINE_SMOOTH);
+ EXPP_ADDCONST(GL_LINE_WIDTH);
+ EXPP_ADDCONST(GL_LINE_WIDTH_RANGE);
+ EXPP_ADDCONST(GL_LINE_WIDTH_GRANULARITY);
+ EXPP_ADDCONST(GL_LINE_STIPPLE);
+ EXPP_ADDCONST(GL_LINE_STIPPLE_PATTERN);
+ EXPP_ADDCONST(GL_LINE_STIPPLE_REPEAT);
+ EXPP_ADDCONST(GL_LIST_MODE);
+ EXPP_ADDCONST(GL_MAX_LIST_NESTING);
+ EXPP_ADDCONST(GL_LIST_BASE);
+ EXPP_ADDCONST(GL_LIST_INDEX);
+ EXPP_ADDCONST(GL_POLYGON_MODE);
+ EXPP_ADDCONST(GL_POLYGON_SMOOTH);
+ EXPP_ADDCONST(GL_POLYGON_STIPPLE);
+ EXPP_ADDCONST(GL_EDGE_FLAG);
+ EXPP_ADDCONST(GL_CULL_FACE);
+ EXPP_ADDCONST(GL_CULL_FACE_MODE);
+ EXPP_ADDCONST(GL_FRONT_FACE);
+ EXPP_ADDCONST(GL_LIGHTING);
+ EXPP_ADDCONST(GL_LIGHT_MODEL_LOCAL_VIEWER);
+ EXPP_ADDCONST(GL_LIGHT_MODEL_TWO_SIDE);
+ EXPP_ADDCONST(GL_LIGHT_MODEL_AMBIENT);
+ EXPP_ADDCONST(GL_SHADE_MODEL);
+ EXPP_ADDCONST(GL_COLOR_MATERIAL_FACE);
+ EXPP_ADDCONST(GL_COLOR_MATERIAL_PARAMETER);
+ EXPP_ADDCONST(GL_COLOR_MATERIAL);
+ EXPP_ADDCONST(GL_FOG);
+ EXPP_ADDCONST(GL_FOG_INDEX);
+ EXPP_ADDCONST(GL_FOG_DENSITY);
+ EXPP_ADDCONST(GL_FOG_START);
+ EXPP_ADDCONST(GL_FOG_END);
+ EXPP_ADDCONST(GL_FOG_MODE);
+ EXPP_ADDCONST(GL_FOG_COLOR);
+ EXPP_ADDCONST(GL_DEPTH_RANGE);
+ EXPP_ADDCONST(GL_DEPTH_TEST);
+ EXPP_ADDCONST(GL_DEPTH_WRITEMASK);
+ EXPP_ADDCONST(GL_DEPTH_CLEAR_VALUE);
+ EXPP_ADDCONST(GL_DEPTH_FUNC);
+ EXPP_ADDCONST(GL_ACCUM_CLEAR_VALUE);
+ EXPP_ADDCONST(GL_STENCIL_TEST);
+ EXPP_ADDCONST(GL_STENCIL_CLEAR_VALUE);
+ EXPP_ADDCONST(GL_STENCIL_FUNC);
+ EXPP_ADDCONST(GL_STENCIL_VALUE_MASK);
+ EXPP_ADDCONST(GL_STENCIL_FAIL);
+ EXPP_ADDCONST(GL_STENCIL_PASS_DEPTH_FAIL);
+ EXPP_ADDCONST(GL_STENCIL_PASS_DEPTH_PASS);
+ EXPP_ADDCONST(GL_STENCIL_REF);
+ EXPP_ADDCONST(GL_STENCIL_WRITEMASK);
+ EXPP_ADDCONST(GL_MATRIX_MODE);
+ EXPP_ADDCONST(GL_NORMALIZE);
+ EXPP_ADDCONST(GL_VIEWPORT);
+ EXPP_ADDCONST(GL_MODELVIEW_STACK_DEPTH);
+ EXPP_ADDCONST(GL_PROJECTION_STACK_DEPTH);
+ EXPP_ADDCONST(GL_TEXTURE_STACK_DEPTH);
+ EXPP_ADDCONST(GL_MODELVIEW_MATRIX);
+ EXPP_ADDCONST(GL_PROJECTION_MATRIX);
+ EXPP_ADDCONST(GL_TEXTURE_MATRIX);
+ EXPP_ADDCONST(GL_ATTRIB_STACK_DEPTH);
+ EXPP_ADDCONST(GL_ALPHA_TEST);
+ EXPP_ADDCONST(GL_ALPHA_TEST_FUNC);
+ EXPP_ADDCONST(GL_ALPHA_TEST_REF);
+ EXPP_ADDCONST(GL_DITHER);
+ EXPP_ADDCONST(GL_BLEND_DST);
+ EXPP_ADDCONST(GL_BLEND_SRC);
+ EXPP_ADDCONST(GL_BLEND);
+ EXPP_ADDCONST(GL_LOGIC_OP_MODE);
+ EXPP_ADDCONST(GL_LOGIC_OP);
+ EXPP_ADDCONST(GL_AUX_BUFFERS);
+ EXPP_ADDCONST(GL_DRAW_BUFFER);
+ EXPP_ADDCONST(GL_READ_BUFFER);
+ EXPP_ADDCONST(GL_SCISSOR_BOX);
+ EXPP_ADDCONST(GL_SCISSOR_TEST);
+ EXPP_ADDCONST(GL_INDEX_CLEAR_VALUE);
+ EXPP_ADDCONST(GL_INDEX_WRITEMASK);
+ EXPP_ADDCONST(GL_COLOR_CLEAR_VALUE);
+ EXPP_ADDCONST(GL_COLOR_WRITEMASK);
+ EXPP_ADDCONST(GL_INDEX_MODE);
+ EXPP_ADDCONST(GL_RGBA_MODE);
+ EXPP_ADDCONST(GL_DOUBLEBUFFER);
+ EXPP_ADDCONST(GL_STEREO);
+ EXPP_ADDCONST(GL_RENDER_MODE);
+ EXPP_ADDCONST(GL_PERSPECTIVE_CORRECTION_HINT);
+ EXPP_ADDCONST(GL_POINT_SMOOTH_HINT);
+ EXPP_ADDCONST(GL_LINE_SMOOTH_HINT);
+ EXPP_ADDCONST(GL_POLYGON_SMOOTH_HINT);
+ EXPP_ADDCONST(GL_FOG_HINT);
+ EXPP_ADDCONST(GL_TEXTURE_GEN_S);
+ EXPP_ADDCONST(GL_TEXTURE_GEN_T);
+ EXPP_ADDCONST(GL_TEXTURE_GEN_R);
+ EXPP_ADDCONST(GL_TEXTURE_GEN_Q);
+ EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_I_SIZE);
+ EXPP_ADDCONST(GL_PIXEL_MAP_S_TO_S_SIZE);
+ EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_R_SIZE);
+ EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_G_SIZE);
+ EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_B_SIZE);
+ EXPP_ADDCONST(GL_PIXEL_MAP_I_TO_A_SIZE);
+ EXPP_ADDCONST(GL_PIXEL_MAP_R_TO_R_SIZE);
+ EXPP_ADDCONST(GL_PIXEL_MAP_G_TO_G_SIZE);
+ EXPP_ADDCONST(GL_PIXEL_MAP_B_TO_B_SIZE);
+ EXPP_ADDCONST(GL_PIXEL_MAP_A_TO_A_SIZE);
+ EXPP_ADDCONST(GL_UNPACK_SWAP_BYTES);
+ EXPP_ADDCONST(GL_UNPACK_LSB_FIRST);
+ EXPP_ADDCONST(GL_UNPACK_ROW_LENGTH);
+ EXPP_ADDCONST(GL_UNPACK_SKIP_ROWS);
+ EXPP_ADDCONST(GL_UNPACK_SKIP_PIXELS);
+ EXPP_ADDCONST(GL_UNPACK_ALIGNMENT);
+ EXPP_ADDCONST(GL_PACK_SWAP_BYTES);
+ EXPP_ADDCONST(GL_PACK_LSB_FIRST);
+ EXPP_ADDCONST(GL_PACK_ROW_LENGTH);
+ EXPP_ADDCONST(GL_PACK_SKIP_ROWS);
+ EXPP_ADDCONST(GL_PACK_SKIP_PIXELS);
+ EXPP_ADDCONST(GL_PACK_ALIGNMENT);
+ EXPP_ADDCONST(GL_MAP_COLOR);
+ EXPP_ADDCONST(GL_MAP_STENCIL);
+ EXPP_ADDCONST(GL_INDEX_SHIFT);
+ EXPP_ADDCONST(GL_INDEX_OFFSET);
+ EXPP_ADDCONST(GL_RED_SCALE);
+ EXPP_ADDCONST(GL_RED_BIAS);
+ EXPP_ADDCONST(GL_ZOOM_X);
+ EXPP_ADDCONST(GL_ZOOM_Y);
+ EXPP_ADDCONST(GL_GREEN_SCALE);
+ EXPP_ADDCONST(GL_GREEN_BIAS);
+ EXPP_ADDCONST(GL_BLUE_SCALE);
+ EXPP_ADDCONST(GL_BLUE_BIAS);
+ EXPP_ADDCONST(GL_ALPHA_SCALE);
+ EXPP_ADDCONST(GL_ALPHA_BIAS);
+ EXPP_ADDCONST(GL_DEPTH_SCALE);
+ EXPP_ADDCONST(GL_DEPTH_BIAS);
+ EXPP_ADDCONST(GL_MAX_EVAL_ORDER);
+ EXPP_ADDCONST(GL_MAX_LIGHTS);
+ EXPP_ADDCONST(GL_MAX_CLIP_PLANES);
+ EXPP_ADDCONST(GL_MAX_TEXTURE_SIZE);
+ EXPP_ADDCONST(GL_MAX_PIXEL_MAP_TABLE);
+ EXPP_ADDCONST(GL_MAX_ATTRIB_STACK_DEPTH);
+ EXPP_ADDCONST(GL_MAX_MODELVIEW_STACK_DEPTH);
+ EXPP_ADDCONST(GL_MAX_NAME_STACK_DEPTH);
+ EXPP_ADDCONST(GL_MAX_PROJECTION_STACK_DEPTH);
+ EXPP_ADDCONST(GL_MAX_TEXTURE_STACK_DEPTH);
+ EXPP_ADDCONST(GL_MAX_VIEWPORT_DIMS);
+ EXPP_ADDCONST(GL_SUBPIXEL_BITS);
+ EXPP_ADDCONST(GL_INDEX_BITS);
+ EXPP_ADDCONST(GL_RED_BITS);
+ EXPP_ADDCONST(GL_GREEN_BITS);
+ EXPP_ADDCONST(GL_BLUE_BITS);
+ EXPP_ADDCONST(GL_ALPHA_BITS);
+ EXPP_ADDCONST(GL_DEPTH_BITS);
+ EXPP_ADDCONST(GL_STENCIL_BITS);
+ EXPP_ADDCONST(GL_ACCUM_RED_BITS);
+ EXPP_ADDCONST(GL_ACCUM_GREEN_BITS);
+ EXPP_ADDCONST(GL_ACCUM_BLUE_BITS);
+ EXPP_ADDCONST(GL_ACCUM_ALPHA_BITS);
+ EXPP_ADDCONST(GL_NAME_STACK_DEPTH);
+ EXPP_ADDCONST(GL_AUTO_NORMAL);
+ EXPP_ADDCONST(GL_MAP1_COLOR_4);
+ EXPP_ADDCONST(GL_MAP1_INDEX);
+ EXPP_ADDCONST(GL_MAP1_NORMAL);
+ EXPP_ADDCONST(GL_MAP1_TEXTURE_COORD_1);
+ EXPP_ADDCONST(GL_MAP1_TEXTURE_COORD_2);
+ EXPP_ADDCONST(GL_MAP1_TEXTURE_COORD_3);
+ EXPP_ADDCONST(GL_MAP1_TEXTURE_COORD_4);
+ EXPP_ADDCONST(GL_MAP1_VERTEX_3);
+ EXPP_ADDCONST(GL_MAP1_VERTEX_4);
+ EXPP_ADDCONST(GL_MAP2_COLOR_4);
+ EXPP_ADDCONST(GL_MAP2_INDEX);
+ EXPP_ADDCONST(GL_MAP2_NORMAL);
+ EXPP_ADDCONST(GL_MAP2_TEXTURE_COORD_1);
+ EXPP_ADDCONST(GL_MAP2_TEXTURE_COORD_2);
+ EXPP_ADDCONST(GL_MAP2_TEXTURE_COORD_3);
+ EXPP_ADDCONST(GL_MAP2_TEXTURE_COORD_4);
+ EXPP_ADDCONST(GL_MAP2_VERTEX_3);
+ EXPP_ADDCONST(GL_MAP2_VERTEX_4);
+ EXPP_ADDCONST(GL_MAP1_GRID_DOMAIN);
+ EXPP_ADDCONST(GL_MAP1_GRID_SEGMENTS);
+ EXPP_ADDCONST(GL_MAP2_GRID_DOMAIN);
+ EXPP_ADDCONST(GL_MAP2_GRID_SEGMENTS);
+ EXPP_ADDCONST(GL_TEXTURE_1D);
+ EXPP_ADDCONST(GL_TEXTURE_2D);
+
+ EXPP_ADDCONST(GL_TEXTURE_WIDTH);
+ EXPP_ADDCONST(GL_TEXTURE_HEIGHT);
+ EXPP_ADDCONST(GL_TEXTURE_COMPONENTS);
+ EXPP_ADDCONST(GL_TEXTURE_BORDER_COLOR);
+ EXPP_ADDCONST(GL_TEXTURE_BORDER);
+
+ EXPP_ADDCONST(GL_DONT_CARE);
+ EXPP_ADDCONST(GL_FASTEST);
+ EXPP_ADDCONST(GL_NICEST);
+
+ EXPP_ADDCONST(GL_AMBIENT);
+ EXPP_ADDCONST(GL_DIFFUSE);
+ EXPP_ADDCONST(GL_SPECULAR);
+ EXPP_ADDCONST(GL_POSITION);
+ EXPP_ADDCONST(GL_SPOT_DIRECTION);
+ EXPP_ADDCONST(GL_SPOT_EXPONENT);
+ EXPP_ADDCONST(GL_SPOT_CUTOFF);
+ EXPP_ADDCONST(GL_CONSTANT_ATTENUATION);
+ EXPP_ADDCONST(GL_LINEAR_ATTENUATION);
+ EXPP_ADDCONST(GL_QUADRATIC_ATTENUATION);
+
+ EXPP_ADDCONST(GL_COMPILE);
+ EXPP_ADDCONST(GL_COMPILE_AND_EXECUTE);
+
+ EXPP_ADDCONST(GL_BYTE);
+ EXPP_ADDCONST(GL_UNSIGNED_BYTE);
+ EXPP_ADDCONST(GL_SHORT);
+ EXPP_ADDCONST(GL_UNSIGNED_SHORT);
+ EXPP_ADDCONST(GL_INT);
+ EXPP_ADDCONST(GL_UNSIGNED_INT);
+ EXPP_ADDCONST(GL_FLOAT);
+ EXPP_ADDCONST(GL_DOUBLE);
+ EXPP_ADDCONST(GL_2_BYTES);
+ EXPP_ADDCONST(GL_3_BYTES);
+ EXPP_ADDCONST(GL_4_BYTES);
+
+ EXPP_ADDCONST(GL_CLEAR);
+ EXPP_ADDCONST(GL_AND);
+ EXPP_ADDCONST(GL_AND_REVERSE);
+ EXPP_ADDCONST(GL_COPY);
+ EXPP_ADDCONST(GL_AND_INVERTED);
+ EXPP_ADDCONST(GL_NOOP);
+ EXPP_ADDCONST(GL_XOR);
+ EXPP_ADDCONST(GL_OR);
+ EXPP_ADDCONST(GL_NOR);
+ EXPP_ADDCONST(GL_EQUIV);
+ EXPP_ADDCONST(GL_INVERT);
+ EXPP_ADDCONST(GL_OR_REVERSE);
+ EXPP_ADDCONST(GL_COPY_INVERTED);
+ EXPP_ADDCONST(GL_OR_INVERTED);
+ EXPP_ADDCONST(GL_NAND);
+ EXPP_ADDCONST(GL_SET);
+
+ EXPP_ADDCONST(GL_EMISSION);
+ EXPP_ADDCONST(GL_SHININESS);
+ EXPP_ADDCONST(GL_AMBIENT_AND_DIFFUSE);
+ EXPP_ADDCONST(GL_COLOR_INDEXES);
+
+ EXPP_ADDCONST(GL_MODELVIEW);
+ EXPP_ADDCONST(GL_PROJECTION);
+ EXPP_ADDCONST(GL_TEXTURE);
+
+ EXPP_ADDCONST(GL_COLOR);
+ EXPP_ADDCONST(GL_DEPTH);
+ EXPP_ADDCONST(GL_STENCIL);
+
+ EXPP_ADDCONST(GL_COLOR_INDEX);
+ EXPP_ADDCONST(GL_STENCIL_INDEX);
+ EXPP_ADDCONST(GL_DEPTH_COMPONENT);
+ EXPP_ADDCONST(GL_RED);
+ EXPP_ADDCONST(GL_GREEN);
+ EXPP_ADDCONST(GL_BLUE);
+ EXPP_ADDCONST(GL_ALPHA);
+ EXPP_ADDCONST(GL_RGB);
+ EXPP_ADDCONST(GL_RGBA);
+ EXPP_ADDCONST(GL_LUMINANCE);
+ EXPP_ADDCONST(GL_LUMINANCE_ALPHA);
+
+ EXPP_ADDCONST(GL_BITMAP);
+
+ EXPP_ADDCONST(GL_POINT);
+ EXPP_ADDCONST(GL_LINE);
+ EXPP_ADDCONST(GL_FILL);
+
+ EXPP_ADDCONST(GL_RENDER);
+ EXPP_ADDCONST(GL_FEEDBACK);
+ EXPP_ADDCONST(GL_SELECT);
+
+ EXPP_ADDCONST(GL_FLAT);
+ EXPP_ADDCONST(GL_SMOOTH);
+
+ EXPP_ADDCONST(GL_KEEP);
+ EXPP_ADDCONST(GL_REPLACE);
+ EXPP_ADDCONST(GL_INCR);
+ EXPP_ADDCONST(GL_DECR);
+
+ EXPP_ADDCONST(GL_VENDOR);
+ EXPP_ADDCONST(GL_RENDERER);
+ EXPP_ADDCONST(GL_VERSION);
+ EXPP_ADDCONST(GL_EXTENSIONS);
+
+ EXPP_ADDCONST(GL_S);
+ EXPP_ADDCONST(GL_T);
+ EXPP_ADDCONST(GL_R);
+ EXPP_ADDCONST(GL_Q);
+
+ EXPP_ADDCONST(GL_MODULATE);
+ EXPP_ADDCONST(GL_DECAL);
+
+ EXPP_ADDCONST(GL_TEXTURE_ENV_MODE);
+ EXPP_ADDCONST(GL_TEXTURE_ENV_COLOR);
+
+ EXPP_ADDCONST(GL_TEXTURE_ENV);
+
+ EXPP_ADDCONST(GL_EYE_LINEAR);
+ EXPP_ADDCONST(GL_OBJECT_LINEAR);
+ EXPP_ADDCONST(GL_SPHERE_MAP);
+
+ EXPP_ADDCONST(GL_TEXTURE_GEN_MODE);
+ EXPP_ADDCONST(GL_OBJECT_PLANE);
+ EXPP_ADDCONST(GL_EYE_PLANE);
+
+ EXPP_ADDCONST(GL_NEAREST);
+ EXPP_ADDCONST(GL_LINEAR);
+
+ EXPP_ADDCONST(GL_NEAREST_MIPMAP_NEAREST);
+ EXPP_ADDCONST(GL_LINEAR_MIPMAP_NEAREST);
+ EXPP_ADDCONST(GL_NEAREST_MIPMAP_LINEAR);
+ EXPP_ADDCONST(GL_LINEAR_MIPMAP_LINEAR);
+
+ EXPP_ADDCONST(GL_TEXTURE_MAG_FILTER);
+ EXPP_ADDCONST(GL_TEXTURE_MIN_FILTER);
+ EXPP_ADDCONST(GL_TEXTURE_WRAP_S);
+ EXPP_ADDCONST(GL_TEXTURE_WRAP_T);
+
+ EXPP_ADDCONST(GL_CLAMP);
+ EXPP_ADDCONST(GL_REPEAT);
+
+ EXPP_ADDCONST(GL_CLIP_PLANE0);
+ EXPP_ADDCONST(GL_CLIP_PLANE1);
+ EXPP_ADDCONST(GL_CLIP_PLANE2);
+ EXPP_ADDCONST(GL_CLIP_PLANE3);
+ EXPP_ADDCONST(GL_CLIP_PLANE4);
+ EXPP_ADDCONST(GL_CLIP_PLANE5);
+
+ EXPP_ADDCONST(GL_LIGHT0);
+ EXPP_ADDCONST(GL_LIGHT1);
+ EXPP_ADDCONST(GL_LIGHT2);
+ EXPP_ADDCONST(GL_LIGHT3);
+ EXPP_ADDCONST(GL_LIGHT4);
+ EXPP_ADDCONST(GL_LIGHT5);
+ EXPP_ADDCONST(GL_LIGHT6);
+ EXPP_ADDCONST(GL_LIGHT7);
+
+ EXPP_ADDCONST(GL_POLYGON_OFFSET_UNITS);
+ EXPP_ADDCONST(GL_POLYGON_OFFSET_POINT);
+ EXPP_ADDCONST(GL_POLYGON_OFFSET_LINE);
+ EXPP_ADDCONST(GL_POLYGON_OFFSET_FILL);
+ EXPP_ADDCONST(GL_POLYGON_OFFSET_FACTOR);
+
+ EXPP_ADDCONST(GL_TEXTURE_PRIORITY);
+ EXPP_ADDCONST(GL_TEXTURE_RESIDENT);
+ EXPP_ADDCONST(GL_TEXTURE_BINDING_1D);
+ EXPP_ADDCONST(GL_TEXTURE_BINDING_2D);
+
+ return mod;
+}
+
diff --git a/source/blender/python/api2_2x/BGL.h b/source/blender/python/api2_2x/BGL.h
new file mode 100644
index 00000000000..c7fbf079010
--- /dev/null
+++ b/source/blender/python/api2_2x/BGL.h
@@ -0,0 +1,333 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+/* This is the Blender.BGL part of opy_draw.c, from the old bpython/intern
+ * dir, with minor changes to adapt it to the new Python implementation.
+ * The BGL submodule "wraps" OpenGL functions and constants, allowing script
+ * writers to make OpenGL calls in their Python scripts for Blender. The
+ * more important original comments are marked with an @ symbol. */
+
+#ifndef EXPP_BGL_H
+#define EXPP_BGL_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <Python.h>
+#include "BIF_gl.h"
+
+
+/*@ Buffer Object */
+/*@ For Python access to OpenGL functions requiring a pointer. */
+
+typedef struct _Buffer {
+ PyObject_VAR_HEAD
+ PyObject * parent;
+
+ int type; /* GL_BYTE, GL_SHORT, GL_INT, GL_FLOAT */
+ int ndimensions;
+ int *dimensions;
+
+ union {
+ char *asbyte;
+ short *asshort;
+ int *asint;
+ float *asfloat;
+ double *asdouble;
+
+ void *asvoid;
+ } buf;
+} Buffer;
+
+
+/*@ By golly George! It looks like fancy pants macro time!!! */
+
+/*
+#define int_str "i"
+#define int_var(number) bgl_int##number
+#define int_ref(number) &bgl_int##number
+#define int_def(number) int int_var(number)
+
+#define float_str "f"
+#define float_var(number) bgl_float##number
+#define float_ref(number) &bgl_float##number
+#define float_def(number) float float_var(number)
+*/
+
+/* TYPE_str is the string to pass to Py_ArgParse (for the format) */
+/* TYPE_var is the name to pass to the GL function */
+/* TYPE_ref is the pointer to pass to Py_ArgParse (to store in) */
+/* TYPE_def is the C initialization of the variable */
+
+#define void_str ""
+#define void_var(num)
+#define void_ref(num) &bgl_var##num
+#define void_def(num) char bgl_var##num
+
+#define buffer_str "O!"
+#define buffer_var(number) (bgl_buffer##number)->buf.asvoid
+#define buffer_ref(number) &buffer_Type, &bgl_buffer##number
+#define buffer_def(number) Buffer *bgl_buffer##number
+
+/* GL Pointer fields, handled by buffer type */
+/* GLdoubleP, GLfloatP, GLintP, GLuintP, GLshortP */
+
+#define GLbooleanP_str "O!"
+#define GLbooleanP_var(number) (bgl_buffer##number)->buf.asvoid
+#define GLbooleanP_ref(number) &buffer_Type, &bgl_buffer##number
+#define GLbooleanP_def(number) Buffer *bgl_buffer##number
+
+#define GLbyteP_str "O!"
+#define GLbyteP_var(number) (bgl_buffer##number)->buf.asvoid
+#define GLbyteP_ref(number) &buffer_Type, &bgl_buffer##number
+#define GLbyteP_def(number) Buffer *bgl_buffer##number
+
+#define GLubyteP_str "O!"
+#define GLubyteP_var(number) (bgl_buffer##number)->buf.asvoid
+#define GLubyteP_ref(number) &buffer_Type, &bgl_buffer##number
+#define GLubyteP_def(number) Buffer *bgl_buffer##number
+
+#define GLintP_str "O!"
+#define GLintP_var(number) (bgl_buffer##number)->buf.asvoid
+#define GLintP_ref(number) &buffer_Type, &bgl_buffer##number
+#define GLintP_def(number) Buffer *bgl_buffer##number
+
+#define GLuintP_str "O!"
+#define GLuintP_var(number) (bgl_buffer##number)->buf.asvoid
+#define GLuintP_ref(number) &buffer_Type, &bgl_buffer##number
+#define GLuintP_def(number) Buffer *bgl_buffer##number
+
+#define GLshortP_str "O!"
+#define GLshortP_var(number) (bgl_buffer##number)->buf.asvoid
+#define GLshortP_ref(number) &buffer_Type, &bgl_buffer##number
+#define GLshortP_def(number) Buffer *bgl_buffer##number
+
+#define GLushortP_str "O!"
+#define GLushortP_var(number) (bgl_buffer##number)->buf.asvoid
+#define GLushortP_ref(number) &buffer_Type, &bgl_buffer##number
+#define GLushortP_def(number) Buffer *bgl_buffer##number
+
+#define GLfloatP_str "O!"
+#define GLfloatP_var(number) (bgl_buffer##number)->buf.asvoid
+#define GLfloatP_ref(number) &buffer_Type, &bgl_buffer##number
+#define GLfloatP_def(number) Buffer *bgl_buffer##number
+
+#define GLdoubleP_str "O!"
+#define GLdoubleP_var(number) (bgl_buffer##number)->buf.asvoid
+#define GLdoubleP_ref(number) &buffer_Type, &bgl_buffer##number
+#define GLdoubleP_def(number) Buffer *bgl_buffer##number
+
+#define GLclampfP_str "O!"
+#define GLclampfP_var(number) (bgl_buffer##number)->buf.asvoid
+#define GLclampfP_ref(number) &buffer_Type, &bgl_buffer##number
+#define GLclampfP_def(number) Buffer *bgl_buffer##number
+
+#define GLvoidP_str "O!"
+#define GLvoidP_var(number) (bgl_buffer##number)->buf.asvoid
+#define GLvoidP_ref(number) &buffer_Type, &bgl_buffer##number
+#define GLvoidP_def(number) Buffer *bgl_buffer##number
+
+#define buffer_str "O!"
+#define buffer_var(number) (bgl_buffer##number)->buf.asvoid
+#define buffer_ref(number) &buffer_Type, &bgl_buffer##number
+#define buffer_def(number) Buffer *bgl_buffer##number
+
+/*@The standard GL typedefs are used as prototypes, we can't
+ * use the GL type directly because Py_ArgParse expects normal
+ * C types.
+ *
+ * Py_ArgParse doesn't grok writing into unsigned variables,
+ * so we use signed everything (even stuff that should be unsigned.
+ */
+
+/* typedef unsigned int GLenum; */
+#define GLenum_str "i"
+#define GLenum_var(num) bgl_var##num
+#define GLenum_ref(num) &bgl_var##num
+#define GLenum_def(num) /* unsigned */ int GLenum_var(num)
+
+/* typedef unsigned int GLboolean; */
+#define GLboolean_str "b"
+#define GLboolean_var(num) bgl_var##num
+#define GLboolean_ref(num) &bgl_var##num
+#define GLboolean_def(num) /* unsigned */ char GLboolean_var(num)
+
+/* typedef unsigned int GLbitfield; */
+#define GLbitfield_str "i"
+#define GLbitfield_var(num) bgl_var##num
+#define GLbitfield_ref(num) &bgl_var##num
+#define GLbitfield_def(num) /* unsigned */ int GLbitfield_var(num)
+
+/* typedef signed char GLbyte; */
+#define GLbyte_str "b"
+#define GLbyte_var(num) bgl_var##num
+#define GLbyte_ref(num) &bgl_var##num
+#define GLbyte_def(num) signed char GLbyte_var(num)
+
+/* typedef short GLshort; */
+#define GLshort_str "h"
+#define GLshort_var(num) bgl_var##num
+#define GLshort_ref(num) &bgl_var##num
+#define GLshort_def(num) short GLshort_var(num)
+
+/* typedef int GLint; */
+#define GLint_str "i"
+#define GLint_var(num) bgl_var##num
+#define GLint_ref(num) &bgl_var##num
+#define GLint_def(num) int GLint_var(num)
+
+/* typedef int GLsizei; */
+#define GLsizei_str "i"
+#define GLsizei_var(num) bgl_var##num
+#define GLsizei_ref(num) &bgl_var##num
+#define GLsizei_def(num) int GLsizei_var(num)
+
+/* typedef unsigned char GLubyte; */
+#define GLubyte_str "b"
+#define GLubyte_var(num) bgl_var##num
+#define GLubyte_ref(num) &bgl_var##num
+#define GLubyte_def(num) /* unsigned */ char GLubyte_var(num)
+
+/* typedef unsigned short GLushort; */
+#define GLushort_str "h"
+#define GLushort_var(num) bgl_var##num
+#define GLushort_ref(num) &bgl_var##num
+#define GLushort_def(num) /* unsigned */ short GLushort_var(num)
+
+/* typedef unsigned int GLuint; */
+#define GLuint_str "i"
+#define GLuint_var(num) bgl_var##num
+#define GLuint_ref(num) &bgl_var##num
+#define GLuint_def(num) /* unsigned */ int GLuint_var(num)
+
+/* typedef float GLfloat; */
+#define GLfloat_str "f"
+#define GLfloat_var(num) bgl_var##num
+#define GLfloat_ref(num) &bgl_var##num
+#define GLfloat_def(num) float GLfloat_var(num)
+
+/* typedef float GLclampf; */
+#define GLclampf_str "f"
+#define GLclampf_var(num) bgl_var##num
+#define GLclampf_ref(num) &bgl_var##num
+#define GLclampf_def(num) float GLclampf_var(num)
+
+/* typedef double GLdouble; */
+#define GLdouble_str "d"
+#define GLdouble_var(num) bgl_var##num
+#define GLdouble_ref(num) &bgl_var##num
+#define GLdouble_def(num) double GLdouble_var(num)
+
+/* typedef double GLclampd; */
+#define GLclampd_str "d"
+#define GLclampd_var(num) bgl_var##num
+#define GLclampd_ref(num) &bgl_var##num
+#define GLclampd_def(num) double GLclampd_var(num)
+
+/* typedef void GLvoid; */
+/* #define GLvoid_str "" */
+/* #define GLvoid_var(num) bgl_var##num */
+/* #define GLvoid_ref(num) &bgl_var##num */
+/* #define GLvoid_def(num) char bgl_var##num */
+
+#define arg_def1(a1) a1##_def(1)
+#define arg_def2(a1, a2) arg_def1(a1); a2##_def(2)
+#define arg_def3(a1, a2, a3) arg_def2(a1, a2); a3##_def(3)
+#define arg_def4(a1, a2, a3, a4) arg_def3(a1, a2, a3); a4##_def(4)
+#define arg_def5(a1, a2, a3, a4, a5) arg_def4(a1, a2, a3, a4); a5##_def(5)
+#define arg_def6(a1, a2, a3, a4, a5, a6)arg_def5(a1, a2, a3, a4, a5); a6##_def(6)
+#define arg_def7(a1, a2, a3, a4, a5, a6, a7)arg_def6(a1, a2, a3, a4, a5, a6); a7##_def(7)
+#define arg_def8(a1, a2, a3, a4, a5, a6, a7, a8)arg_def7(a1, a2, a3, a4, a5, a6, a7); a8##_def(8)
+#define arg_def9(a1, a2, a3, a4, a5, a6, a7, a8, a9)arg_def8(a1, a2, a3, a4, a5, a6, a7, a8); a9##_def(9)
+#define arg_def10(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)arg_def9(a1, a2, a3, a4, a5, a6, a7, a8, a9); a10##_def(10)
+
+#define arg_var1(a1) a1##_var(1)
+#define arg_var2(a1, a2) arg_var1(a1), a2##_var(2)
+#define arg_var3(a1, a2, a3) arg_var2(a1, a2), a3##_var(3)
+#define arg_var4(a1, a2, a3, a4) arg_var3(a1, a2, a3), a4##_var(4)
+#define arg_var5(a1, a2, a3, a4, a5) arg_var4(a1, a2, a3, a4), a5##_var(5)
+#define arg_var6(a1, a2, a3, a4, a5, a6)arg_var5(a1, a2, a3, a4, a5), a6##_var(6)
+#define arg_var7(a1, a2, a3, a4, a5, a6, a7)arg_var6(a1, a2, a3, a4, a5, a6), a7##_var(7)
+#define arg_var8(a1, a2, a3, a4, a5, a6, a7, a8)arg_var7(a1, a2, a3, a4, a5, a6, a7), a8##_var(8)
+#define arg_var9(a1, a2, a3, a4, a5, a6, a7, a8, a9)arg_var8(a1, a2, a3, a4, a5, a6, a7, a8), a9##_var(9)
+#define arg_var10(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)arg_var9(a1, a2, a3, a4, a5, a6, a7, a8, a9), a10##_var(10)
+
+#define arg_ref1(a1) a1##_ref(1)
+#define arg_ref2(a1, a2) arg_ref1(a1), a2##_ref(2)
+#define arg_ref3(a1, a2, a3) arg_ref2(a1, a2), a3##_ref(3)
+#define arg_ref4(a1, a2, a3, a4) arg_ref3(a1, a2, a3), a4##_ref(4)
+#define arg_ref5(a1, a2, a3, a4, a5) arg_ref4(a1, a2, a3, a4), a5##_ref(5)
+#define arg_ref6(a1, a2, a3, a4, a5, a6)arg_ref5(a1, a2, a3, a4, a5), a6##_ref(6)
+#define arg_ref7(a1, a2, a3, a4, a5, a6, a7)arg_ref6(a1, a2, a3, a4, a5, a6), a7##_ref(7)
+#define arg_ref8(a1, a2, a3, a4, a5, a6, a7, a8)arg_ref7(a1, a2, a3, a4, a5, a6, a7), a8##_ref(8)
+#define arg_ref9(a1, a2, a3, a4, a5, a6, a7, a8, a9)arg_ref8(a1, a2, a3, a4, a5, a6, a7, a8), a9##_ref(9)
+#define arg_ref10(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)arg_ref9(a1, a2, a3, a4, a5, a6, a7, a8, a9), a10##_ref(10)
+
+#define arg_str1(a1) a1##_str
+#define arg_str2(a1, a2) arg_str1(a1) a2##_str
+#define arg_str3(a1, a2, a3) arg_str2(a1, a2) a3##_str
+#define arg_str4(a1, a2, a3, a4) arg_str3(a1, a2, a3) a4##_str
+#define arg_str5(a1, a2, a3, a4, a5) arg_str4(a1, a2, a3, a4) a5##_str
+#define arg_str6(a1, a2, a3, a4, a5, a6)arg_str5(a1, a2, a3, a4, a5) a6##_str
+#define arg_str7(a1, a2, a3, a4, a5, a6, a7)arg_str6(a1, a2, a3, a4, a5, a6) a7##_str
+#define arg_str8(a1, a2, a3, a4, a5, a6, a7, a8)arg_str7(a1, a2, a3, a4, a5, a6, a7) a8##_str
+#define arg_str9(a1, a2, a3, a4, a5, a6, a7, a8, a9)arg_str8(a1, a2, a3, a4, a5, a6, a7, a8) a9##_str
+#define arg_str10(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)arg_str9(a1, a2, a3, a4, a5, a6, a7, a8, a9) a10##_str
+
+#define ret_def_void
+#define ret_set_void
+#define ret_ret_void return EXPP_incr_ret(Py_None)
+
+#define ret_def_GLint int ret_int
+#define ret_set_GLint ret_int=
+#define ret_ret_GLint return PyInt_FromLong(ret_int);
+
+#define ret_def_GLuint unsigned int ret_uint
+#define ret_set_GLuint ret_uint=
+#define ret_ret_GLuint return PyInt_FromLong((long) ret_uint);
+
+#define ret_def_GLenum unsigned int ret_uint
+#define ret_set_GLenum ret_uint=
+#define ret_ret_GLenum return PyInt_FromLong((long) ret_uint);
+
+#define ret_def_GLboolean unsigned char ret_bool
+#define ret_set_GLboolean ret_bool=
+#define ret_ret_GLboolean return PyInt_FromLong((long) ret_bool);
+
+#define ret_def_GLstring const unsigned char *ret_str;
+#define ret_set_GLstring ret_str=
+#define ret_ret_GLstring return PyString_FromString(ret_str);
+
+
+
+#endif /* EXPP_BGL_H */
diff --git a/source/blender/python/api2_2x/BezTriple.c b/source/blender/python/api2_2x/BezTriple.c
new file mode 100644
index 00000000000..2aa908ff2b0
--- /dev/null
+++ b/source/blender/python/api2_2x/BezTriple.c
@@ -0,0 +1,716 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Jacques Guignot RIP 2005,
+ * Stephen Swaney, Ken Hughes
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "BezTriple.h" /*This must come first */
+#include "DNA_ipo_types.h"
+
+#include "MEM_guardedalloc.h"
+#include "gen_utils.h"
+
+
+/***************************************************************************
+ Python API function prototypes for the BezTriple module.
+***************************************************************************/
+static PyObject *M_BezTriple_New( PyObject * self, PyObject * args );
+static PyObject *M_BezTriple_Get( PyObject * self, PyObject * args );
+
+/*************************************
+ Doc strings for the BezTriple module
+*************************************/
+
+static char M_BezTriple_doc[] = "The Blender BezTriple module\n";
+
+/****************************************************************************
+ Python BPy_BezTriple instance methods declarations:
+****************************************************************************/
+static PyObject *BezTriple_oldsetPoints( BPy_BezTriple * self, PyObject * args );
+static int BezTriple_setPoints( BPy_BezTriple * self, PyObject * args );
+static PyObject *BezTriple_getPoints( BPy_BezTriple * self );
+static PyObject *BezTriple_getTriple( BPy_BezTriple * self );
+
+/****************************************************************************
+ Python method structure definition for Blender.BezTriple module:
+****************************************************************************/
+
+struct PyMethodDef M_BezTriple_methods[] = {
+ {"New", ( PyCFunction ) M_BezTriple_New, METH_VARARGS | METH_KEYWORDS,
+ 0},
+/* {"New", ( PyCFunction ) M_BezTriple_New, METH_O, 0}, */
+ {"Get", M_BezTriple_Get, METH_VARARGS, 0},
+ {"get", M_BezTriple_Get, METH_VARARGS, 0},
+ {NULL, NULL, 0, NULL}
+};
+
+/*****************************************************************************/
+/* Python BPy_BezTriple methods table: */
+/*****************************************************************************/
+static PyMethodDef BPy_BezTriple_methods[] = {
+ /* name, method, flags, doc */
+ {"setPoints", ( PyCFunction ) BezTriple_oldsetPoints, METH_VARARGS,
+ "(str) - Change BezTriple point coordinates"},
+ {"getPoints", ( PyCFunction ) BezTriple_getPoints, METH_NOARGS,
+ "() - return BezTriple knot point x and y coordinates"},
+ {"getTriple", ( PyCFunction ) BezTriple_getTriple, METH_NOARGS,
+ "() - return list of 3 floating point triplets. order is H1, knot, H2"},
+ {NULL, NULL, 0, NULL}
+};
+
+/****************************************************************************
+ Function: M_BezTriple_New
+ Python equivalent: Blender.BezTriple.New
+****************************************************************************/
+
+static PyObject *M_BezTriple_New( PyObject* self, PyObject * args )
+{
+ float numbuf[9];
+ PyObject* in_args = NULL;
+ int length;
+
+ /* accept list, tuple, or 3 or 9 args (which better be floats) */
+
+ length = PyTuple_Size( args );
+ if( length == 3 || length == 9 )
+ in_args = args;
+ else if( !PyArg_ParseTuple( args, "|O", &in_args) )
+ goto TypeError;
+
+ if( !in_args ) {
+ numbuf[0] = 0.0f; numbuf[1] = 0.0f; numbuf[2] = 0.0f;
+ numbuf[3] = 0.0f; numbuf[4] = 0.0f; numbuf[5] = 0.0f;
+ numbuf[6] = 0.0f; numbuf[7] = 0.0f; numbuf[8] = 0.0f;
+ } else {
+ int i, length;
+ if( !PySequence_Check( in_args ) )
+ goto TypeError;
+
+ length = PySequence_Length( in_args );
+ if( length != 9 && length != 3 )
+ goto TypeError;
+
+ for( i = 0; i < length; i++ ) {
+ PyObject *item, *pyfloat;
+ item = PySequence_ITEM( in_args, i);
+ if( !item )
+ goto TypeError;
+ pyfloat = PyNumber_Float( item );
+ Py_DECREF( item );
+ if( !pyfloat )
+ goto TypeError;
+ numbuf[i] = ( float )PyFloat_AS_DOUBLE( pyfloat );
+ Py_DECREF( pyfloat );
+ }
+
+ if( length == 3 ) {
+ numbuf[3] = numbuf[0]; numbuf[6] = numbuf[0];
+ numbuf[4] = numbuf[1]; numbuf[7] = numbuf[1];
+ numbuf[5] = numbuf[2]; numbuf[8] = numbuf[2];
+ }
+ }
+
+ return newBezTriple( numbuf );
+
+TypeError:
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected sequence of 3 or 9 floats or nothing" );
+}
+
+/****************************************************************************
+ Function: M_BezTriple_Get
+ Python equivalent: Blender.BezTriple.Get
+ Description: Receives a string and returns the ipo data obj
+ whose name matches the string. If no argument is
+ passed in, a list of all ipo data names in the
+ current scene is returned.
+****************************************************************************/
+static PyObject *M_BezTriple_Get( PyObject * self, PyObject * args )
+{
+ return 0;
+}
+
+/****************************************************************************
+ Function: BezTriple_dealloc
+ Description: This is a callback function for the BPy_BezTriple type. It is
+ the destructor function.
+****************************************************************************/
+static void BezTriple_dealloc( BPy_BezTriple * self )
+{
+ if( self->own_memory)
+ MEM_freeN( self->beztriple );
+
+ PyObject_DEL( self );
+}
+
+/*
+ * BezTriple_getTriple
+ *
+ * Get the coordinate data for a BezTriple. Returns a list of 3 points.
+ * List order is handle1, knot, handle2. each point consists of a list
+ * of x,y,z float values.
+ */
+
+static PyObject *BezTriple_getTriple( BPy_BezTriple * self )
+{
+ BezTriple *bezt = self->beztriple;
+ return Py_BuildValue( "[[fff][fff][fff]]",
+ bezt->vec[0][0], bezt->vec[0][1], bezt->vec[0][2],
+ bezt->vec[1][0], bezt->vec[1][1], bezt->vec[1][2],
+ bezt->vec[2][0], bezt->vec[2][1], bezt->vec[2][2] );
+}
+
+/*
+ * BezTriple_setTriple
+ *
+ * Set the cordinate data for a BezTriple. Takes a sequence of 3 points,
+ * of the same format at BezTriple_getTriple.
+ */
+
+static int BezTriple_setTriple( BPy_BezTriple * self, PyObject * args )
+{
+ int i, j;
+ struct BezTriple *bezt = self->beztriple;
+ float vec[3][3];
+
+ if( !PySequence_Check( args ) || PySequence_Size( args ) != 3 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected three sequences of three floats" );
+
+ for( i = 0; i < 3; i++ ) {
+ PyObject *obj1 = PySequence_ITEM( args, i );
+ if( !PySequence_Check( obj1 ) || PySequence_Size( obj1 ) != 3 ) {
+ Py_DECREF( obj1 );
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected three sequences of three floats" );
+ }
+ for( j = 0; j < 3; j++ ) {
+ PyObject *obj2 = PySequence_ITEM( obj1, j );
+ PyObject *num = PyNumber_Float( obj2 );
+ Py_DECREF( obj2 );
+
+ if( !num ) {
+ Py_DECREF( obj1 );
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "expected float parameter" );
+ }
+ vec[i][j] = ( float )PyFloat_AsDouble( num );
+ Py_DECREF( num );
+ }
+ Py_DECREF( obj1 );
+ }
+
+ for( i = 0; i < 3; i++ )
+ for( j = 0; j < 3; j++ )
+ bezt->vec[i][j] = vec[i][j];
+
+ return 0;
+}
+
+/*
+ * BezTriple_getPoint
+ *
+ * Get the coordinate data for a BezTriple. Returns the control point,
+ * as a list of x,y float values.
+ */
+
+static PyObject *BezTriple_getPoints( BPy_BezTriple * self )
+{
+ BezTriple *bezt = self->beztriple;
+ return Py_BuildValue( "[ff]", bezt->vec[1][0], bezt->vec[1][1] );
+}
+
+/*
+ * BezTriple_setPoint
+ *
+ * Set the coordinate data for a BezTriple. Accepts the x,y for the control
+ * point and builds handle values based on control point.
+ */
+
+static int BezTriple_setPoints( BPy_BezTriple * self, PyObject * args )
+{
+ int i;
+ struct BezTriple *bezt = self->beztriple;
+ float vec[2];
+
+ if( !PySequence_Check( args ) || PySequence_Size( args ) != 2 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected sequence of two floats" );
+
+ for( i = 0; i < 2; i++ ) {
+ PyObject *obj = PySequence_ITEM( args, i );
+ PyObject *num = PyNumber_Float( obj );
+ Py_DECREF( obj );
+
+ if( !num )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "expected float parameter" );
+ vec[i] = ( float )PyFloat_AsDouble( num );
+ Py_DECREF( num );
+ }
+
+ for( i = 0; i < 2; i++ ) {
+ bezt->vec[0][i] = vec[i] - 1;
+ bezt->vec[1][i] = vec[i];
+ bezt->vec[2][i] = vec[i] + 1;
+ }
+
+ /* experimental fussing with handles - ipo.c: calchandles_ipocurve */
+ if( bezt->vec[0][0] > bezt->vec[1][0] )
+ bezt->vec[0][0] = bezt->vec[1][0];
+
+ if( bezt->vec[2][0] < bezt->vec[1][0] )
+ bezt->vec[2][0] = bezt->vec[1][0];
+
+ return 0;
+}
+
+static PyObject *BezTriple_getTilt( BPy_BezTriple * self )
+{
+ return PyFloat_FromDouble( self->beztriple->alfa );
+}
+
+static int BezTriple_setTilt( BPy_BezTriple * self, PyObject *value )
+{
+ PyObject *num = PyNumber_Float( value );
+
+ if( !num )
+ return EXPP_ReturnIntError( PyExc_TypeError, "expected a float" );
+
+ self->beztriple->alfa = (float)PyFloat_AsDouble( num );
+ Py_DECREF( num );
+ return 0;
+}
+
+static PyObject *BezTriple_getWeight( BPy_BezTriple * self )
+{
+ return PyFloat_FromDouble( self->beztriple->weight );
+}
+
+static int BezTriple_setWeight( BPy_BezTriple * self, PyObject *value )
+{
+ PyObject *num = PyNumber_Float( value );
+
+ if( !num )
+ return EXPP_ReturnIntError( PyExc_TypeError, "expected a float" );
+
+ self->beztriple->weight = (float)PyFloat_AsDouble( num );
+ Py_DECREF( num );
+ return 0;
+}
+
+static PyObject *BezTriple_getRadius( BPy_BezTriple * self )
+{
+ return PyFloat_FromDouble( self->beztriple->radius );
+}
+
+static int BezTriple_setRadius( BPy_BezTriple * self, PyObject *value )
+{
+ PyObject *num = PyNumber_Float( value );
+
+ if( !num )
+ return EXPP_ReturnIntError( PyExc_TypeError, "expected a float" );
+
+ self->beztriple->radius = (float)PyFloat_AsDouble( num );
+ Py_DECREF( num );
+ return 0;
+}
+
+static PyObject *BezTriple_getHide( BPy_BezTriple * self )
+{
+ return PyInt_FromLong( self->beztriple->hide == IPO_BEZ );
+}
+
+static int BezTriple_setHide( BPy_BezTriple * self, PyObject *value )
+{
+ int param = PyObject_IsTrue( value );
+ if( param == -1 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected True/False or 0/1" );
+
+ if( param )
+ self->beztriple->hide = IPO_BEZ;
+ else
+ self->beztriple->hide = 0;
+ return 0;
+}
+
+static PyObject *BezTriple_getSelects( BPy_BezTriple * self )
+{
+ BezTriple *bezt = self->beztriple;
+
+ return Py_BuildValue( "[iii]", bezt->f1, bezt->f2, bezt->f3 );
+}
+
+static int BezTriple_setSelects( BPy_BezTriple * self, PyObject *args )
+{
+ struct BezTriple *bezt = self->beztriple;
+ PyObject *ob1, *ob2, *ob3;
+ int param1, param2, param3;
+
+ /* only accept a sequence of three booleans */
+
+ if( !PySequence_Check( args ) || PySequence_Size( args ) != 3 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected sequence of three integers" );
+
+ ob1 = PySequence_ITEM( args, 0 );
+ ob2 = PySequence_ITEM( args, 1 );
+ ob3 = PySequence_ITEM( args, 2 );
+
+ param1 = PyObject_IsTrue( ob1 );
+ param2 = PyObject_IsTrue( ob2 );
+ param3 = PyObject_IsTrue( ob3 );
+
+ if (param1==-1 || param2==-1 || param3==-1)
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a sequence of 3 items: True/False or 0/1" );
+
+ /* assign the selects */
+ bezt->f1 = (char)param1;
+ bezt->f2 = (char)param2;
+ bezt->f3 = (char)param3;
+
+ Py_DECREF( ob1 );
+ Py_DECREF( ob2 );
+ Py_DECREF( ob3 );
+ return 0;
+}
+
+static PyObject *BezTriple_getHandles( BPy_BezTriple * self )
+{
+ BezTriple *bezt = self->beztriple;
+
+ return Py_BuildValue( "[ii]", bezt->h1, bezt->h2 );
+}
+
+static int BezTriple_setHandles( BPy_BezTriple * self, PyObject *args )
+{
+ struct BezTriple *bezt = self->beztriple;
+ PyObject *ob1, *ob2;
+ short h1, h2;
+
+ /* only accept a sequence of two ints */
+
+ if( !PySequence_Check( args ) || PySequence_Size( args ) != 2 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected sequence of two integers" );
+
+ ob1 = PySequence_ITEM( args, 0 );
+ ob2 = PySequence_ITEM( args, 1 );
+
+ if( !PyInt_Check( ob1 ) || !PyInt_Check( ob2 ) ) {
+ Py_DECREF( ob1 );
+ Py_DECREF( ob2 );
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected sequence of two integers" );
+ }
+
+ h1 = ( short ) PyInt_AsLong( ob1 );
+ h2 = ( short ) PyInt_AsLong( ob2 );
+ Py_DECREF( ob1 );
+ Py_DECREF( ob2 );
+
+ if( h1 < HD_FREE || h2 < HD_FREE ||
+ h1 > HD_AUTO_ANIM || h2 > HD_AUTO_ANIM )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "expected int in range [0,4]" );
+
+ /* assign the handles */
+
+ bezt->h1 = h1;
+ bezt->h2 = h2;
+
+ return 0;
+}
+
+/*
+ * Python BezTriple attributes get/set structure
+ */
+
+static PyGetSetDef BPy_BezTriple_getseters[] = {
+ {"pt",
+ (getter)BezTriple_getPoints, (setter)BezTriple_setPoints,
+ "point knot values",
+ NULL},
+ {"vec",
+ (getter)BezTriple_getTriple, (setter)BezTriple_setTriple,
+ "point handle and knot values",
+ NULL},
+ {"tilt",
+ (getter)BezTriple_getTilt, (setter)BezTriple_setTilt,
+ "point tilt",
+ NULL},
+ {"hide",
+ (getter)BezTriple_getHide, (setter)BezTriple_setHide,
+ "point hide status",
+ NULL},
+ {"selects",
+ (getter)BezTriple_getSelects, (setter)BezTriple_setSelects,
+ "point select statuses",
+ NULL},
+ {"handleTypes",
+ (getter)BezTriple_getHandles, (setter)BezTriple_setHandles,
+ "point handle types",
+ NULL},
+ {"weight",
+ (getter)BezTriple_getWeight, (setter)BezTriple_setWeight,
+ "point weight",
+ NULL},
+ {"radius",
+ (getter)BezTriple_getRadius, (setter)BezTriple_setRadius,
+ "point radius",
+ NULL},
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+/*****************************************************************************/
+/* Function: BezTriple_repr */
+/* Description: This is a callback function for the BPy_BezTriple type. It */
+/* builds a meaninful string to represent BezTriple objects. */
+/*****************************************************************************/
+static PyObject *BezTriple_repr( BPy_BezTriple * self )
+{
+ char str[512];
+ sprintf( str,
+ "[BezTriple [%.6f, %.6f, %.6f] [%.6f, %.6f, %.6f] [%.6f, %.6f, %.6f]\n",
+ self->beztriple->vec[0][0], self->beztriple->vec[0][1], self->beztriple->vec[0][2],
+ self->beztriple->vec[1][0], self->beztriple->vec[1][1], self->beztriple->vec[1][2],
+ self->beztriple->vec[2][0], self->beztriple->vec[2][1], self->beztriple->vec[2][2]);
+ return PyString_FromString( str );
+}
+
+/************************************************************************
+ *
+ * Python BezTriple_Type structure definition
+ *
+ ************************************************************************/
+
+PyTypeObject BezTriple_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "BezTriple", /* char *tp_name; */
+ sizeof( BPy_BezTriple ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ ( destructor ) BezTriple_dealloc,/* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* cmpfunc tp_compare; */
+ ( reprfunc ) BezTriple_repr, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_BezTriple_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ BPy_BezTriple_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+static PyObject *M_BezTriple_HandleDict( void )
+{
+ PyObject *HM = PyConstant_New( );
+
+ if( HM ) {
+ BPy_constant *d = ( BPy_constant * ) HM;
+
+ PyConstant_Insert( d, "FREE", PyInt_FromLong( HD_FREE ) );
+ PyConstant_Insert( d, "AUTO", PyInt_FromLong( HD_AUTO ) );
+ PyConstant_Insert( d, "VECT", PyInt_FromLong( HD_VECT ) );
+ PyConstant_Insert( d, "ALIGN", PyInt_FromLong( HD_ALIGN ) );
+ PyConstant_Insert( d, "AUTOANIM", PyInt_FromLong( HD_AUTO_ANIM ) );
+ }
+ return HM;
+}
+
+/*
+ BezTriple_Init
+*/
+
+PyObject *BezTriple_Init( void )
+{
+ PyObject *submodule;
+ PyObject *HandleTypes = M_BezTriple_HandleDict( );
+
+ if( PyType_Ready( &BezTriple_Type ) < 0 )
+ return NULL;
+
+ submodule = Py_InitModule3( "Blender.BezTriple",
+ M_BezTriple_methods,
+ M_BezTriple_doc );
+ if( HandleTypes )
+ PyModule_AddObject( submodule, "HandleTypes", HandleTypes );
+
+
+ return submodule;
+}
+
+/* Three Python BezTriple_Type helper functions needed by the Object module: */
+
+/****************************************************************************
+ Function: BezTriple_CreatePyObject
+ Description: This function will create a new BPy_BezTriple from an existing
+ Blender ipo structure.
+****************************************************************************/
+PyObject *BezTriple_CreatePyObject( BezTriple * bzt )
+{
+ BPy_BezTriple *pybeztriple;
+
+ pybeztriple =
+ ( BPy_BezTriple * ) PyObject_NEW( BPy_BezTriple, &BezTriple_Type );
+
+ if( !pybeztriple )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create BPy_BezTriple object" );
+
+ pybeztriple->beztriple = bzt;
+ pybeztriple->own_memory = 0;
+
+ return ( PyObject * ) pybeztriple;
+}
+
+
+/*****************************************************************************/
+/* Function: BezTriple_FromPyObject */
+/* Description: This function returns the Blender beztriple from the given */
+/* PyObject. */
+/*****************************************************************************/
+BezTriple *BezTriple_FromPyObject( PyObject * pyobj )
+{
+ return ( ( BPy_BezTriple * ) pyobj )->beztriple;
+}
+
+
+/*
+ Create a new BezTriple
+ input args is a sequence - either 3 or 9 floats
+*/
+
+PyObject *newBezTriple( float *numbuf )
+{
+ int i, j, num;
+ PyObject *pyobj = NULL;
+ BezTriple *bzt = NULL;
+
+ /* create our own beztriple data */
+ bzt = MEM_callocN( sizeof( BezTriple ), "new bpytriple");
+
+ /* check malloc */
+ if( !bzt )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "MEM_callocN failed");
+
+ /* copy the data */
+ num = 0;
+ for( i = 0; i < 3; i++ ) {
+ for( j = 0; j < 3; j++) {
+ bzt->vec[i][j] = numbuf[num++];
+ }
+ }
+ bzt->h1 = HD_ALIGN;
+ bzt->h2 = HD_ALIGN;
+
+ /* wrap it */
+ pyobj = BezTriple_CreatePyObject( bzt );
+
+ /* we own it. must free later */
+ ( ( BPy_BezTriple * )pyobj)->own_memory = 1;
+
+ return pyobj;
+}
+
+/* #####DEPRECATED###### */
+
+static PyObject *BezTriple_oldsetPoints( BPy_BezTriple * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args,
+ (setter)BezTriple_setPoints );
+}
diff --git a/source/blender/python/api2_2x/BezTriple.h b/source/blender/python/api2_2x/BezTriple.h
new file mode 100644
index 00000000000..e2e015b502d
--- /dev/null
+++ b/source/blender/python/api2_2x/BezTriple.h
@@ -0,0 +1,64 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Jacques Guignot, Stephen Swaney
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_BEZTRIPLE_H
+#define EXPP_BEZTRIPLE_H
+
+#include <Python.h>
+#include "DNA_curve_types.h"
+
+extern PyTypeObject BezTriple_Type;
+
+/* type check macro */
+#define BPy_BezTriple_Check(o) \
+ ( (o)->ob_type == &BezTriple_Type)
+
+/****************************************************************************
+ Python BPy_BezTriple structure definition:
+****************************************************************************/
+
+typedef struct {
+ PyObject_HEAD /* required python macro */
+ BezTriple * beztriple;
+ int own_memory; /* true == we own this memory and must delete. */
+} BPy_BezTriple;
+
+/*
+ * prototypes
+ */
+
+PyObject *BezTriple_CreatePyObject( BezTriple * bzt );
+BezTriple *BezTriple_FromPyObject( PyObject * pyobj );
+PyObject *newBezTriple( float *args );
+PyObject *BezTriple_Init( void );
+
+#endif /* EXPP_BEZTRIPLE_H */
diff --git a/source/blender/python/api2_2x/Blender.c b/source/blender/python/api2_2x/Blender.c
new file mode 100644
index 00000000000..24b9f4d5186
--- /dev/null
+++ b/source/blender/python/api2_2x/Blender.c
@@ -0,0 +1,982 @@
+/*
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Michel Selten, Willian P. Germano, Joseph Gilbert,
+ * Campbell Barton
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+struct ID; /*keep me up here */
+
+#include "Blender.h" /*This must come first */
+
+/* for open, close in Blender_Load */
+#include <fcntl.h>
+#include "BDR_editobject.h" /* exit_editmode() */
+#include "BIF_usiblender.h"
+#include "BLI_blenlib.h"
+#include "BLO_writefile.h"
+#include "BKE_blender.h"
+#include "BKE_exotic.h"
+#include "BKE_global.h"
+#include "BKE_packedFile.h"
+#include "BKE_utildefines.h"
+#include "BKE_object.h"
+#include "BKE_scene.h"
+#include "BKE_text.h"
+#include "BKE_ipo.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BPI_script.h"
+#include "BSE_headerbuttons.h"
+#include "DNA_screen_types.h" /* for SPACE_VIEW3D */
+#include "DNA_userdef_types.h"
+#include "DNA_packedFile_types.h"
+#include "EXPP_interface.h" /* for bpy_gethome() */
+#include "gen_utils.h"
+#include "modules.h"
+#include "constant.h"
+#include "../BPY_extern.h" /* BPY_txt_do_python_Text */
+#include "../BPY_menus.h" /* to update menus */
+#include "Armature.h"
+#include "BezTriple.h"
+#include "Camera.h"
+#include "Constraint.h"
+#include "Curve.h"
+#include "CurNurb.h"
+#include "Draw.h"
+#include "Effect.h"
+#include "Ipo.h"
+#include "Ipocurve.h"
+#include "IDProp.h"
+#include "Key.h"
+#include "Lamp.h"
+#include "Lattice.h"
+#include "Library.h"
+#include "Mathutils.h"
+#include "Geometry.h"
+#include "Mesh.h"
+#include "Metaball.h"
+#include "Modifier.h"
+#include "NMesh.h"
+#include "Object.h"
+#include "Group.h"
+#include "Registry.h"
+#include "Scene.h"
+#include "Sound.h"
+#include "SurfNurb.h"
+#include "Sys.h"
+#include "Text.h"
+#include "Texture.h"
+#include "Window.h"
+#include "World.h"
+#include "Types.h"
+
+/**********************************************************/
+/* Python API function prototypes for the Blender module. */
+/**********************************************************/
+static PyObject *Blender_Set( PyObject * self, PyObject * args );
+static PyObject *Blender_Get( PyObject * self, PyObject * value );
+static PyObject *Blender_Redraw( PyObject * self, PyObject * args );
+static PyObject *Blender_Quit( PyObject * self );
+static PyObject *Blender_Load( PyObject * self, PyObject * args );
+static PyObject *Blender_Save( PyObject * self, PyObject * args );
+static PyObject *Blender_Run( PyObject * self, PyObject * value );
+static PyObject *Blender_ShowHelp( PyObject * self, PyObject * script );
+static PyObject *Blender_UpdateMenus( PyObject * self);
+static PyObject *Blender_PackAll( PyObject * self);
+static PyObject *Blender_UnpackAll( PyObject * self, PyObject * value);
+static PyObject *Blender_CountPackedFiles( PyObject * self );
+
+extern PyObject *Text3d_Init( void ); /* missing in some include */
+
+/*****************************************************************************/
+/* The following string definitions are used for documentation strings. */
+/* In Python these will be written to the console when doing a */
+/* Blender.__doc__ */
+/*****************************************************************************/
+static char Blender_Set_doc[] =
+ "(request, data) - Update settings in Blender\n\
+\n\
+(request) A string identifying the setting to change\n\
+ 'curframe' - Sets the current frame using the number in data";
+
+static char Blender_Get_doc[] = "(request) - Retrieve settings from Blender\n\
+\n\
+(request) A string indentifying the data to be returned\n\
+ 'curframe' - Returns the current animation frame\n\
+ 'curtime' - Returns the current animation time\n\
+ 'staframe' - Returns the start frame of the animation\n\
+ 'endframe' - Returns the end frame of the animation\n\
+ 'filename' - Returns the name of the last file read or written\n\
+ 'homedir' - Returns Blender's home dir\n\
+ 'datadir' - Returns the dir where scripts can save their data, if available\n\
+ 'scriptsdir' - Returns the main dir where scripts are kept, if available\n\
+ 'uscriptsdir' - Returns the user defined dir for scripts, if available\n\
+ 'version' - Returns the Blender version number";
+
+static char Blender_Redraw_doc[] = "() - Redraw all 3D windows";
+
+static char Blender_Quit_doc[] =
+ "() - Quit Blender. The current data is saved as 'quit.blend' before leaving.";
+
+static char Blender_Load_doc[] = "(filename) - Load the given file.\n\
+Supported formats:\n\
+Blender, DXF, Inventor 1.0 ASCII, VRML 1.0 asc, STL, Videoscape, radiogour.\n\
+\n\
+Notes:\n\
+1 - () - an empty argument loads the default .B.blend file;\n\
+2 - if the substring '.B.blend' occurs inside 'filename', the default\n\
+.B.blend file is loaded;\n\
+3 - If a Blender file is loaded the script ends immediately.\n\
+4 - The current data is always preserved as an autosave file, for safety;\n\
+5 - This function only works if the script where it's executed is the\n\
+only one running at the moment.";
+
+static char Blender_Save_doc[] =
+ "(filename) - Save data to a file based on the filename's extension.\n\
+Supported are: Blender's .blend and the builtin exporters:\n\
+VRML 1.0 (.wrl), Videoscape (.obj), DXF (.dxf) and STL (.stl)\n\
+(filename) - A filename with one of the supported extensions.\n\
+Note 1: 'filename' should not contain the substring \".B.blend\" in it.\n\
+Note 2: only .blend raises an error if file wasn't saved.\n\
+\tYou can use Blender.sys.exists(filename) to make sure the file was saved\n\
+\twhen writing to one of the other formats.";
+
+static char Blender_Run_doc[] =
+ "(script) - Run the given Python script.\n\
+(script) - the path to a file or the name of an available Blender Text.";
+
+static char Blender_ShowHelp_doc[] =
+"(script) - Show help for the given Python script.\n\
+ This will try to open the 'Scripts Help Browser' script, so to have\n\
+any help displayed the passed 'script' must be properly documented\n\
+with the expected strings (check API ref docs or any bundled script\n\
+for examples).\n\n\
+(script) - the filename of a script in the default or user defined\n\
+ scripts dir (no need to supply the full path name).";
+
+static char Blender_UpdateMenus_doc[] =
+ "() - Update the menus where scripts are registered. Only needed for\n\
+scripts that save other new scripts in the default or user defined folders.";
+
+static char Blender_PackAll_doc[] =
+"() - Pack all files.\n\
+All files will packed into the blend file.";
+static char Blender_UnpackAll_doc[] =
+"(mode) - Unpack files.\n\
+All files will be unpacked using specified mode.\n\n\
+(mode) - the unpack mode.";
+
+static char Blender_CountPackedFiles_doc[] =
+"() - Returns the number of packed files.";
+
+/*****************************************************************************/
+/* Python method structure definition. */
+/*****************************************************************************/
+static struct PyMethodDef Blender_methods[] = {
+ {"Set", Blender_Set, METH_VARARGS, Blender_Set_doc},
+ {"Get", Blender_Get, METH_O, Blender_Get_doc},
+ {"Redraw", Blender_Redraw, METH_VARARGS, Blender_Redraw_doc},
+ {"Quit", ( PyCFunction ) Blender_Quit, METH_NOARGS, Blender_Quit_doc},
+ {"Load", Blender_Load, METH_VARARGS, Blender_Load_doc},
+ {"Save", Blender_Save, METH_VARARGS, Blender_Save_doc},
+ {"Run", Blender_Run, METH_O, Blender_Run_doc},
+ {"ShowHelp", Blender_ShowHelp, METH_O, Blender_ShowHelp_doc},
+ {"CountPackedFiles", ( PyCFunction ) Blender_CountPackedFiles, METH_NOARGS, Blender_CountPackedFiles_doc},
+ {"PackAll", ( PyCFunction ) Blender_PackAll, METH_NOARGS, Blender_PackAll_doc},
+ {"UnpackAll", Blender_UnpackAll, METH_O, Blender_UnpackAll_doc},
+ {"UpdateMenus", ( PyCFunction ) Blender_UpdateMenus, METH_NOARGS,
+ Blender_UpdateMenus_doc},
+ {NULL, NULL, 0, NULL}
+};
+
+/*****************************************************************************/
+/* Global variables */
+/*****************************************************************************/
+PyObject *g_blenderdict;
+
+/*****************************************************************************/
+/* Function: Blender_Set */
+/* Python equivalent: Blender.Set */
+/*****************************************************************************/
+static PyObject *Blender_Set( PyObject * self, PyObject * args )
+{
+ char *name, *dir = NULL;
+ PyObject *arg;
+
+ if( !PyArg_ParseTuple( args, "sO", &name, &arg ) )
+ return EXPP_ReturnPyObjError( PyExc_ValueError, "expected 2 args, where the first is always a string" );
+
+ if( StringEqual( name, "curframe" ) ) {
+ if( !PyInt_Check( arg ) )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "expected an integer" );
+
+ G.scene->r.cfra = (short)PyInt_AsLong( arg ) ;
+
+ /* update all objects, so python scripts can export all objects
+ in a scene without worrying about the view layers */
+ scene_update_for_newframe(G.scene, (1<<20) - 1);
+
+ } else if (StringEqual( name , "uscriptsdir" ) ) {
+ if ( !PyArg_Parse( arg , "s" , &dir ))
+ return EXPP_ReturnPyObjError( PyExc_ValueError, "expected a string" );
+ BLI_strncpy(U.pythondir, dir, FILE_MAXDIR);
+ } else if (StringEqual( name , "yfexportdir" ) ) {
+ if ( !PyArg_Parse( arg , "s" , &dir ))
+ return EXPP_ReturnPyObjError( PyExc_ValueError, "expected a string" );
+ BLI_strncpy(U.yfexportdir, dir, FILE_MAXDIR);
+ } else if (StringEqual( name , "fontsdir" ) ) {
+ if ( !PyArg_Parse( arg , "s" , &dir ))
+ return EXPP_ReturnPyObjError( PyExc_ValueError, "expected a string" );
+ BLI_strncpy(U.fontdir, dir, FILE_MAXDIR);
+ } else if (StringEqual( name , "texturesdir" ) ) {
+ if ( !PyArg_Parse( arg , "s" , &dir ))
+ return EXPP_ReturnPyObjError( PyExc_ValueError, "expected a string" );
+ BLI_strncpy(U.textudir, dir, FILE_MAXDIR);
+ } else if (StringEqual( name , "texpluginsdir" ) ) {
+ if ( !PyArg_Parse( arg , "s" , &dir ))
+ return EXPP_ReturnPyObjError( PyExc_ValueError, "expected a string" );
+ BLI_strncpy(U.plugtexdir, dir, FILE_MAXDIR);
+ } else if (StringEqual( name , "seqpluginsdir" ) ) {
+ if ( !PyArg_Parse( arg , "s" , &dir ))
+ return EXPP_ReturnPyObjError( PyExc_ValueError, "expected a string" );
+ BLI_strncpy(U.plugseqdir, dir, FILE_MAXDIR);
+ } else if (StringEqual( name , "renderdir" ) ) {
+ if ( !PyArg_Parse( arg , "s" , &dir ))
+ return EXPP_ReturnPyObjError( PyExc_ValueError, "expected a string" );
+ BLI_strncpy(U.renderdir, dir, FILE_MAXDIR);
+ } else if (StringEqual( name , "soundsdir" ) ) {
+ if ( !PyArg_Parse( arg , "s" , &dir ))
+ return EXPP_ReturnPyObjError( PyExc_ValueError, "expected a string" );
+ BLI_strncpy(U.sounddir, dir, FILE_MAXDIR);
+ } else if (StringEqual( name , "tempdir" ) ) {
+ if ( !PyArg_Parse( arg , "s" , &dir ))
+ return EXPP_ReturnPyObjError( PyExc_ValueError, "expected a string" );
+ BLI_strncpy(U.tempdir, dir, FILE_MAXDIR);
+ } else
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "value given is not a blender setting" ) );
+ Py_RETURN_NONE;
+}
+
+/*****************************************************************************/
+/* Function: Blender_Get */
+/* Python equivalent: Blender.Get */
+/*****************************************************************************/
+static PyObject *Blender_Get( PyObject * self, PyObject * value )
+{
+ PyObject *ret = NULL;
+ char *str = PyString_AsString(value);
+
+ if( !str )
+ return EXPP_ReturnPyObjError (PyExc_TypeError,
+ "expected string argument");
+
+ if( StringEqual( str, "curframe" ) )
+ ret = PyInt_FromLong( G.scene->r.cfra );
+ else if( StringEqual( str, "curtime" ) )
+ ret = PyFloat_FromDouble( frame_to_float( G.scene->r.cfra ) );
+ else if( StringEqual( str, "rt" ) )
+ ret = PyInt_FromLong( (long)frame_to_float( G.rt ) );
+ else if( StringEqual( str, "staframe" ) )
+ ret = PyInt_FromLong( G.scene->r.sfra );
+ else if( StringEqual( str, "endframe" ) )
+ ret = PyInt_FromLong( G.scene->r.efra );
+ else if( StringEqual( str, "filename" ) ) {
+ if ( strstr(G.main->name, ".B.blend") != 0)
+ ret = PyString_FromString("");
+ else
+ ret = PyString_FromString(G.main->name);
+ }
+ else if( StringEqual( str, "homedir" ) ) {
+ char *hdir = bpy_gethome(0);
+ if( hdir && BLI_exists( hdir ))
+ ret = PyString_FromString( hdir );
+ else
+ ret = EXPP_incr_ret( Py_None );
+ }
+ else if( StringEqual( str, "datadir" ) ) {
+ char datadir[FILE_MAXDIR];
+ char *sdir = bpy_gethome(1);
+
+ if (sdir) {
+ BLI_make_file_string( "/", datadir, sdir, "bpydata" );
+ if( BLI_exists( datadir ) )
+ ret = PyString_FromString( datadir );
+ }
+ if (!ret) ret = EXPP_incr_ret( Py_None );
+ }
+ else if(StringEqual(str, "udatadir")) {
+ if (U.pythondir[0] != '\0') {
+ char upydir[FILE_MAXDIR];
+
+ BLI_strncpy(upydir, U.pythondir, FILE_MAXDIR);
+ BLI_convertstringcode(upydir, G.sce, 0);
+
+ if (BLI_exists(upydir)) {
+ char udatadir[FILE_MAXDIR];
+
+ BLI_make_file_string("/", udatadir, upydir, "bpydata");
+
+ if (BLI_exists(udatadir))
+ ret = PyString_FromString(udatadir);
+ }
+ }
+ if (!ret) ret = EXPP_incr_ret(Py_None);
+ }
+ else if( StringEqual( str, "scriptsdir" ) ) {
+ char *sdir = bpy_gethome(1);
+
+ if (sdir)
+ ret = PyString_FromString(sdir);
+ else
+ ret = EXPP_incr_ret( Py_None );
+ }
+ else if( StringEqual( str, "uscriptsdir" ) ) {
+ if (U.pythondir[0] != '\0') {
+ char upydir[FILE_MAXDIR];
+
+ BLI_strncpy(upydir, U.pythondir, FILE_MAXDIR);
+ BLI_convertstringcode(upydir, G.sce, 0);
+
+ if( BLI_exists( upydir ) )
+ ret = PyString_FromString( upydir );
+ }
+ if (!ret) ret = EXPP_incr_ret(Py_None);
+ }
+ /* USER PREFS: */
+ else if( StringEqual( str, "yfexportdir" ) ) {
+ if (U.yfexportdir[0] != '\0') {
+ char yfexportdir[FILE_MAXDIR];
+
+ BLI_strncpy(yfexportdir, U.yfexportdir, FILE_MAXDIR);
+ BLI_convertstringcode(yfexportdir, G.sce, 0);
+
+ if( BLI_exists( yfexportdir ) )
+ ret = PyString_FromString( yfexportdir );
+ }
+ if (!ret) ret = EXPP_incr_ret(Py_None);
+ }
+ /* fontsdir */
+ else if( StringEqual( str, "fontsdir" ) ) {
+ if (U.fontdir[0] != '\0') {
+ char fontdir[FILE_MAXDIR];
+
+ BLI_strncpy(fontdir, U.fontdir, FILE_MAXDIR);
+ BLI_convertstringcode(fontdir, G.sce, 0);
+
+ if( BLI_exists( fontdir ) )
+ ret = PyString_FromString( fontdir );
+ }
+ if (!ret) ret = EXPP_incr_ret(Py_None);
+ }
+ /* texturesdir */
+ else if( StringEqual( str, "texturesdir" ) ) {
+ if (U.textudir[0] != '\0') {
+ char textudir[FILE_MAXDIR];
+
+ BLI_strncpy(textudir, U.textudir, FILE_MAXDIR);
+ BLI_convertstringcode(textudir, G.sce, 0);
+
+ if( BLI_exists( textudir ) )
+ ret = PyString_FromString( textudir );
+ }
+ if (!ret) ret = EXPP_incr_ret(Py_None);
+ }
+ /* texpluginsdir */
+ else if( StringEqual( str, "texpluginsdir" ) ) {
+ if (U.plugtexdir[0] != '\0') {
+ char plugtexdir[FILE_MAXDIR];
+
+ BLI_strncpy(plugtexdir, U.plugtexdir, FILE_MAXDIR);
+ BLI_convertstringcode(plugtexdir, G.sce, 0);
+
+ if( BLI_exists( plugtexdir ) )
+ ret = PyString_FromString( plugtexdir );
+ }
+ if (!ret) ret = EXPP_incr_ret(Py_None);
+ }
+ /* seqpluginsdir */
+ else if( StringEqual( str, "seqpluginsdir" ) ) {
+ if (U.plugseqdir[0] != '\0') {
+ char plugseqdir[FILE_MAXDIR];
+
+ BLI_strncpy(plugseqdir, U.plugseqdir, FILE_MAXDIR);
+ BLI_convertstringcode(plugseqdir, G.sce, 0);
+
+ if( BLI_exists( plugseqdir ) )
+ ret = PyString_FromString( plugseqdir );
+ }
+ if (!ret) ret = EXPP_incr_ret(Py_None);
+ }
+ /* renderdir */
+ else if( StringEqual( str, "renderdir" ) ) {
+ if (U.renderdir[0] != '\0') {
+ char renderdir[FILE_MAXDIR];
+
+ BLI_strncpy(renderdir, U.renderdir, FILE_MAXDIR);
+ BLI_convertstringcode(renderdir, G.sce, 0);
+
+ if( BLI_exists( renderdir ) )
+ ret = PyString_FromString( renderdir );
+ }
+ if (!ret) ret = EXPP_incr_ret(Py_None);
+ }
+ /* soundsdir */
+ else if( StringEqual( str, "soundsdir" ) ) {
+ if (U.sounddir[0] != '\0') {
+ char sounddir[FILE_MAXDIR];
+
+ BLI_strncpy(sounddir, U.sounddir, FILE_MAXDIR);
+ BLI_convertstringcode(sounddir, G.sce, 0);
+
+ if( BLI_exists( sounddir ) )
+ ret = PyString_FromString( sounddir );
+ }
+ if (!ret) ret = EXPP_incr_ret(Py_None);
+ }
+ /* tempdir */
+ else if( StringEqual( str, "tempdir" ) ) {
+ if (U.tempdir[0] != '\0') {
+ char tempdir[FILE_MAXDIR];
+
+ BLI_strncpy(tempdir, U.tempdir, FILE_MAXDIR);
+ BLI_convertstringcode(tempdir, G.sce, 0);
+
+ if( BLI_exists( tempdir ) )
+ ret = PyString_FromString( tempdir );
+ }
+ if (!ret) ret = EXPP_incr_ret(Py_None);
+ }
+ /* icondir */
+ else if( StringEqual( str, "icondir" ) ) {
+
+ char icondirstr[FILE_MAXDIR];
+
+ #ifdef WIN32
+ BLI_make_file_string("/", icondirstr, BLI_gethome(), "icons");
+ #else
+ BLI_make_file_string("/", icondirstr, BLI_gethome(), ".blender/icons");
+ #endif
+
+ if( BLI_exists( icondirstr ) )
+ ret = PyString_FromString( icondirstr );
+
+ if (!ret) ret = EXPP_incr_ret(Py_None);
+ }
+ /* According to the old file (opy_blender.c), the following if
+ statement is a quick hack and needs some clean up. */
+ else if( StringEqual( str, "vrmloptions" ) ) {
+ ret = PyDict_New( );
+
+ EXPP_dict_set_item_str( ret, "twoside",
+ PyInt_FromLong( U.vrmlflag & USER_VRML_TWOSIDED ) );
+
+ EXPP_dict_set_item_str( ret, "layers",
+ PyInt_FromLong( U.vrmlflag & USER_VRML_LAYERS ) );
+
+ EXPP_dict_set_item_str( ret, "autoscale",
+ PyInt_FromLong( U.vrmlflag & USER_VRML_AUTOSCALE ) );
+
+ } /* End 'quick hack' part. */
+ else if(StringEqual( str, "version" ))
+ ret = PyInt_FromLong( G.version );
+ else
+ return EXPP_ReturnPyObjError( PyExc_AttributeError, "unknown attribute" );
+
+ if (ret) return ret;
+ else
+ return EXPP_ReturnPyObjError (PyExc_MemoryError,
+ "could not create pystring!");
+}
+
+/*****************************************************************************/
+/* Function: Blender_Redraw */
+/* Python equivalent: Blender.Redraw */
+/*****************************************************************************/
+static PyObject *Blender_Redraw( PyObject * self, PyObject * args )
+{
+ return M_Window_Redraw( self, args );
+}
+
+/*****************************************************************************/
+/* Function: Blender_Quit */
+/* Python equivalent: Blender.Quit */
+/*****************************************************************************/
+static PyObject *Blender_Quit( PyObject * self )
+{
+ BIF_write_autosave( ); /* save the current data first */
+
+ exit_usiblender( ); /* renames last autosave to quit.blend */
+
+ Py_RETURN_NONE;
+}
+
+/**
+ * Blender.Load
+ * loads Blender's .blend, DXF, radiogour(?), STL, Videoscape,
+ * Inventor 1.0 ASCII, VRML 1.0 asc.
+ */
+static PyObject *Blender_Load( PyObject * self, PyObject * args )
+{
+ char *fname = NULL;
+ int keep_oldfname = 0;
+ Script *script = NULL;
+ char str[32], name[FILE_MAXDIR];
+ int file, is_blend_file = 0;
+
+ if( !PyArg_ParseTuple( args, "|si", &fname, &keep_oldfname ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected filename and optional int or nothing as arguments" );
+
+ if( fname ) {
+ if( strlen( fname ) > FILE_MAXDIR ) /* G.main->name's max length */
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "filename too long!" );
+ else if( !BLI_exists( fname ) )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "requested file doesn't exist!" );
+
+ if( keep_oldfname )
+ BLI_strncpy( name, G.sce, FILE_MAXDIR );
+ }
+
+ /* We won't let a new .blend file be loaded if there are still other
+ * scripts running, since loading a new file will close and remove them. */
+
+ if( G.main->script.first != G.main->script.last )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "there are other scripts running at the Scripts win, close them first!" );
+
+ if( fname ) {
+ file = open( fname, O_BINARY | O_RDONLY );
+
+ if( file <= 0 ) {
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "cannot open file!" );
+ } else {
+ read( file, str, 31 );
+ close( file );
+
+ if( strncmp( str, "BLEN", 4 ) == 0 )
+ is_blend_file = 1;
+ }
+ } else
+ is_blend_file = 1; /* no arg given means default: .B.blend */
+
+ if( is_blend_file ) {
+
+ int during_slink = during_scriptlink( );
+
+ /* when loading a .blend file from a scriptlink, the scriptlink pointer
+ * in BPY_do_pyscript becomes invalid during a loop. Inform it here.
+ * Also do not allow a nested scriptlink (called from inside another)
+ * to load .blend files, to avoid nasty problems. */
+ if( during_slink >= 1 ) {
+ if( during_slink == 1 )
+ disable_where_scriptlink( -1 );
+ else {
+ return EXPP_ReturnPyObjError
+ ( PyExc_EnvironmentError,
+ "Blender.Load: cannot load .blend files from a nested scriptlink." );
+ }
+ }
+
+ /* trick: mark the script so that its script struct won't be freed after
+ * the script is executed (to avoid a double free warning on exit): */
+ script = G.main->script.first;
+ if( script )
+ script->flags |= SCRIPT_GUI;
+
+ BIF_write_autosave( ); /* for safety let's preserve the current data */
+ }
+
+ if( G.obedit )
+ exit_editmode(EM_FREEDATA);
+
+ if (G.background) { /* background mode */
+ if (is_blend_file)
+ BKE_read_file(fname, NULL);
+ else {
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "only .blend files can be loaded from command line,\n\
+ other file types require interactive mode.");
+ }
+ }
+ else { /* interactive mode */
+ /* for safety, any filename with .B.blend is considered the default one.
+ * It doesn't seem necessary to compare file attributes (like st_ino and
+ * st_dev, according to the glibc info pages) to find out if the given
+ * filename, that may have been given with a twisted misgiving path, is the
+ * default one for sure. Taking any .B.blend file as the default is good
+ * enough here. Note: the default file requires extra clean-up done by
+ * BIF_read_homefile: freeing the user theme data. */
+ if( !fname || ( strstr( fname, ".B.blend" ) && is_blend_file ) )
+ BIF_read_homefile(0, 1);
+ else
+ BIF_read_file( fname );
+
+ if( fname && keep_oldfname ) {
+ /*BLI_strncpy(G.main->name, name, FILE_MAXDIR); */
+ BLI_strncpy( G.sce, name, FILE_MAXDIR );
+ }
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Blender_Save( PyObject * self, PyObject * args )
+{
+ char *fname = NULL;
+ int overwrite = 0, len = 0;
+ char *error = NULL;
+ Library *li;
+
+ if( !PyArg_ParseTuple( args, "s|i", &fname, &overwrite ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected filename and optional int (overwrite flag) as arguments" );
+
+ for( li = G.main->library.first; li; li = li->id.next ) {
+ if( BLI_streq( li->name, fname ) ) {
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "cannot overwrite used library" );
+ }
+ }
+
+ /* for safety, any filename with .B.blend is considered the default one
+ * and not accepted here. */
+ if( strstr( fname, ".B.blend" ) )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "filename can't contain the substring \".B.blend\" in it." );
+
+ len = strlen( fname );
+
+ if( len > FILE_MAXDIR + FILE_MAXFILE )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "filename is too long!" );
+ else if( BLI_exists( fname ) && !overwrite )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "file already exists and overwrite flag was not given." );
+
+ disable_where_script( 1 ); /* to avoid error popups in the write_* functions */
+
+ if( BLI_testextensie( fname, ".blend" ) ) {
+ if( G.fileflags & G_AUTOPACK )
+ packAll( );
+ if( !BLO_write_file( fname, G.fileflags, &error ) ) {
+ disable_where_script( 0 );
+ return EXPP_ReturnPyObjError( PyExc_SystemError,
+ error );
+ }
+ } else if( BLI_testextensie( fname, ".dxf" ) )
+ write_dxf( fname );
+ else if( BLI_testextensie( fname, ".stl" ) )
+ write_stl( fname );
+ else if( BLI_testextensie( fname, ".wrl" ) )
+ write_vrml( fname );
+ else if( BLI_testextensie( fname, ".obj" ) )
+ write_videoscape( fname );
+ else {
+ disable_where_script( 0 );
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "unknown file extension." );
+ }
+
+ disable_where_script( 0 );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Blender_ShowHelp(PyObject *self, PyObject *script)
+{
+ char hspath[FILE_MAXDIR + FILE_MAXFILE]; /* path to help_browser.py */
+ char *sdir = bpy_gethome(1);
+ PyObject *rkeyd = NULL, *arglist = NULL;
+
+ if (!PyString_Check(script))
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "expected a script filename as argument");
+
+ /* first we try to find the help_browser script */
+
+ if (sdir) BLI_make_file_string("/", hspath, sdir, "help_browser.py");
+
+ if (!sdir || (!BLI_exists(hspath) && (U.pythondir[0] != '\0'))) {
+ char upydir[FILE_MAXDIR];
+
+ BLI_strncpy(upydir, U.pythondir, FILE_MAXDIR);
+ BLI_convertstringcode(upydir, G.sce, 0);
+ BLI_make_file_string("/", hspath, upydir, "help_browser.py");
+
+ if (!BLI_exists(hspath))
+ return EXPP_ReturnPyObjError(PyExc_RuntimeError,
+ "can't find script help_browser.py");
+ }
+
+ /* now we store the passed script in the registry dict and call the
+ * help_browser to show help info for it */
+ rkeyd = PyDict_New();
+ if (!rkeyd)
+ return EXPP_ReturnPyObjError(PyExc_MemoryError,
+ "can't create py dictionary!");
+
+ /* note: don't use EXPP_dict_set_item_str for 'script', which is an
+ * argument to the function we're in and so shouldn't be decref'ed: */
+ PyDict_SetItemString(rkeyd, "script", script);
+
+ EXPP_dict_set_item_str(bpy_registryDict, "__help_browser", rkeyd);
+
+ arglist = Py_BuildValue("(s)", hspath);
+ Blender_Run(self, arglist);
+ Py_DECREF(arglist);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Blender_Run(PyObject *self, PyObject *value)
+{
+ char *fname = PyString_AsString(value);
+ Text *text = NULL;
+ int is_blender_text = 0;
+ Script *script = NULL;
+
+ if (!fname)
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "expected a filename or a Blender Text name as argument");
+
+ if (!BLI_exists(fname)) { /* if there's no such filename ... */
+ text = G.main->text.first; /* try an already existing Blender Text */
+
+ while (text) {
+ if (!strcmp(fname, text->id.name + 2)) break;
+ text = text->id.next;
+ }
+
+ if (!text) {
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "no such file or Blender text");
+ }
+ else is_blender_text = 1; /* fn is already a Blender Text */
+ }
+
+ else {
+ text = add_text(fname);
+
+ if (!text) {
+ return EXPP_ReturnPyObjError(PyExc_RuntimeError,
+ "couldn't create Blender Text from given file");
+ }
+ }
+
+ /* (this is messy, check Draw.c's Method_Register and Window.c's file
+ * selector for more info)
+ * - caller script is the one that called this Blender_Run function;
+ * - called script is the argument to this function: fname;
+ * To mark scripts whose global dicts can't be freed right after
+ * the script execution (or better, 'first pass', since these scripts
+ * leave callbacks for gui or file/image selectors) we flag them. But to
+ * get a pointer to them we need to check which one is currently
+ * running (if none we're already at a spacescript). To make sure only
+ * the called script will have the SCRIPT_RUNNING flag on, we unset it
+ * for the caller script here: */
+ script = G.main->script.first;
+ while (script) {
+ if (script->flags & SCRIPT_RUNNING) break;
+ script = script->id.next;
+ }
+
+ if (script) script->flags &= ~SCRIPT_RUNNING; /* unset */
+
+ BPY_txt_do_python_Text(text); /* call new script */
+
+ if (script) script->flags |= SCRIPT_RUNNING; /* set */
+
+ if (!is_blender_text) free_libblock(&G.main->text, text);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject * Blender_UpdateMenus( PyObject * self )
+{
+
+ BPyMenu_RemoveAllEntries();
+
+ if (BPyMenu_Init(1) == -1)
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "invalid scripts dir");
+
+ Py_RETURN_NONE;
+}
+
+/*****************************************************************************/
+/* Function: Blender_PackAll */
+/* Python equivalent: Blender.PackAll */
+/*****************************************************************************/
+static PyObject *Blender_PackAll( PyObject * self)
+{
+ packAll();
+ Py_RETURN_NONE;
+}
+
+/*****************************************************************************/
+/* Function: Blender_UnpackAll */
+/* Python equivalent: Blender.UnpackAll */
+/*****************************************************************************/
+static PyObject *Blender_UnpackAll( PyObject * self, PyObject *value)
+{
+ int mode = PyInt_AsLong(value);
+
+ if (mode==-1)
+ return EXPP_ReturnPyObjError( PyExc_ValueError, "expected an int Blender.UnpackModes");
+ unpackAll(mode);
+ Py_RETURN_NONE;
+}
+
+/*****************************************************************************/
+/* Function: Blender_CountPackedFiles */
+/* Python equivalent: Blender.CountPackedFiles */
+/*****************************************************************************/
+static PyObject *Blender_CountPackedFiles( PyObject * self )
+{
+ int nfiles = countPackedFiles();
+ return PyInt_FromLong( nfiles );
+}
+static PyObject *Blender_UnpackModesDict( void )
+{
+ PyObject *UnpackModes = PyConstant_New( );
+ if( UnpackModes ) {
+ BPy_constant *d = ( BPy_constant * ) UnpackModes;
+ PyConstant_Insert( d, "EQUAL", PyInt_FromLong((long)PF_EQUAL) );
+ PyConstant_Insert( d, "DIFFERS",PyInt_FromLong((long)PF_DIFFERS) );
+ PyConstant_Insert( d, "NOFILE", PyInt_FromLong((long)PF_NOFILE) );
+ PyConstant_Insert( d, "WRITE_ORIGINAL", PyInt_FromLong((long)PF_WRITE_ORIGINAL) );
+ PyConstant_Insert( d, "WRITE_LOCAL", PyInt_FromLong((long)PF_WRITE_LOCAL) );
+ PyConstant_Insert( d, "USE_LOCAL", PyInt_FromLong((long)PF_USE_LOCAL) );
+ PyConstant_Insert( d, "USE_ORIGINAL", PyInt_FromLong((long)PF_USE_ORIGINAL) );
+ PyConstant_Insert( d, "KEEP", PyInt_FromLong((long)PF_KEEP) );
+ PyConstant_Insert( d, "NOOP", PyInt_FromLong((long)PF_NOOP) );
+ PyConstant_Insert( d, "ASK", PyInt_FromLong((long)PF_EQUAL) );
+ }
+ return UnpackModes;
+}
+
+/*****************************************************************************/
+/* Function: initBlender */
+/*****************************************************************************/
+
+void M_Blender_Init(void)
+{
+ PyObject *module;
+ PyObject *dict, *smode, *SpaceHandlers, *UnpackModes;
+
+ /* G.scene should only aver be NULL if blender is executed in
+ background mode, not loading a blend file and executing a python script eg.
+ blender -P somescript.py -b
+ The if below solves the segfaults that happen when python runs and
+ G.scene is NULL */
+ if(G.background && G.main->scene.first==NULL) {
+ Scene *sce= add_scene("1");
+ /*set_scene(sce);*/ /* causes a crash */
+ G.scene= sce;
+ }
+
+ module = Py_InitModule3("Blender", Blender_methods,
+ "The main Blender module");
+
+ types_InitAll(); /* set all our pytypes to &PyType_Type */
+
+ /* constants for packed files*/
+ UnpackModes = Blender_UnpackModesDict( );
+ if( UnpackModes )
+ PyModule_AddObject( module, "UnpackModes", UnpackModes );
+
+ SpaceHandlers = PyConstant_New();
+ if (SpaceHandlers) {
+ BPy_constant *d = (BPy_constant *)SpaceHandlers;
+
+ PyConstant_Insert(d,"VIEW3D_EVENT",PyInt_FromLong(SPACEHANDLER_VIEW3D_EVENT));
+ PyConstant_Insert(d,"VIEW3D_DRAW", PyInt_FromLong(SPACEHANDLER_VIEW3D_DRAW));
+
+ PyModule_AddObject(module, "SpaceHandlers", SpaceHandlers);
+ }
+
+ if (G.background)
+ smode = PyString_FromString("background");
+ else
+ smode = PyString_FromString("interactive");
+
+ dict = PyModule_GetDict(module);
+ g_blenderdict = dict;
+
+ PyModule_AddIntConstant(module, "TRUE", 1);
+ PyModule_AddIntConstant( module, "FALSE", 0 );
+
+ EXPP_dict_set_item_str(dict, "bylink", EXPP_incr_ret_False());
+ PyDict_SetItemString(dict, "link", Py_None);
+ EXPP_dict_set_item_str(dict, "event", PyString_FromString(""));
+ EXPP_dict_set_item_str(dict, "mode", smode);
+
+ PyDict_SetItemString(dict, "Armature", Armature_Init());
+ PyDict_SetItemString(dict, "BezTriple", BezTriple_Init());
+ PyDict_SetItemString(dict, "BGL", BGL_Init());
+ PyDict_SetItemString(dict, "CurNurb", CurNurb_Init());
+ PyDict_SetItemString(dict, "Constraint", Constraint_Init());
+ PyDict_SetItemString(dict, "Curve", Curve_Init());
+ PyDict_SetItemString(dict, "Camera", Camera_Init());
+ PyDict_SetItemString(dict, "Draw", Draw_Init());
+ PyDict_SetItemString(dict, "Effect", Effect_Init());
+ PyDict_SetItemString(dict, "Ipo", Ipo_Init());
+ PyDict_SetItemString(dict, "IpoCurve", IpoCurve_Init());
+ PyDict_SetItemString(dict, "Image", Image_Init());
+ PyDict_SetItemString(dict, "Key", Key_Init());
+ PyDict_SetItemString(dict, "Lamp", Lamp_Init());
+ PyDict_SetItemString(dict, "Lattice", Lattice_Init());
+ PyDict_SetItemString(dict, "Library", oldLibrary_Init());
+ PyDict_SetItemString(dict, "Material", Material_Init());
+ PyDict_SetItemString(dict, "Mesh", Mesh_Init());
+ PyDict_SetItemString(dict, "Metaball", Metaball_Init());
+ PyDict_SetItemString(dict, "Mathutils", Mathutils_Init());
+ PyDict_SetItemString(dict, "Geometry", Geometry_Init());
+ PyDict_SetItemString(dict, "Modifier", Modifier_Init());
+ PyDict_SetItemString(dict, "NMesh", NMesh_Init());
+ PyDict_SetItemString(dict, "Noise", Noise_Init());
+ PyDict_SetItemString(dict, "Object", Object_Init());
+ PyDict_SetItemString(dict, "Group", Group_Init());
+ PyDict_SetItemString(dict, "Registry", Registry_Init());
+ PyDict_SetItemString(dict, "Scene", Scene_Init());
+ PyDict_SetItemString(dict, "Sound", Sound_Init());
+ PyDict_SetItemString(dict, "SurfNurb", SurfNurb_Init());
+ PyDict_SetItemString(dict, "sys", sys_Init());
+ PyDict_SetItemString(dict, "Types", Types_Init());
+ PyDict_SetItemString(dict, "Text", Text_Init());
+ PyDict_SetItemString(dict, "Text3d", Text3d_Init());
+ PyDict_SetItemString(dict, "Texture", Texture_Init());
+ PyDict_SetItemString(dict, "Window", Window_Init());
+ PyDict_SetItemString(dict, "World", World_Init());
+
+}
diff --git a/source/blender/python/api2_2x/Blender.h b/source/blender/python/api2_2x/Blender.h
new file mode 100644
index 00000000000..df80daf3cea
--- /dev/null
+++ b/source/blender/python/api2_2x/Blender.h
@@ -0,0 +1,41 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Michel Selten, Willian P. Germano
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_BLENDER_H
+#define EXPP_BLENDER_H
+
+#include <Python.h>
+
+extern PyObject *g_blenderdict;
+void M_Blender_Init( void );
+
+#endif /* EXPP_BLENDER_H */
diff --git a/source/blender/python/api2_2x/Bone.c b/source/blender/python/api2_2x/Bone.c
new file mode 100644
index 00000000000..5eeb4bb2817
--- /dev/null
+++ b/source/blender/python/api2_2x/Bone.c
@@ -0,0 +1,1425 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Joseph Gilbert
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#include "Bone.h"
+#include "vector.h"
+#include "matrix.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BKE_utildefines.h"
+#include "gen_utils.h"
+#include "BKE_armature.h"
+#include "Mathutils.h"
+#include "BKE_library.h"
+
+//these must come in this order
+#include "DNA_object_types.h" //1
+#include "BIF_editarmature.h" //2
+
+//------------------------ERROR CODES---------------------------------
+//This is here just to make me happy and to have more consistant error strings :)
+static const char sEditBoneError[] = "EditBone - Error: ";
+// static const char sEditBoneBadArgs[] = "EditBone - Bad Arguments: ";
+static const char sBoneError[] = "Bone - Error: ";
+// static const char sBoneBadArgs[] = "Bone - Bad Arguments: ";
+
+//----------------------(internal)
+//gets the bone->roll (which is a localspace roll) and puts it in parentspace
+//(which is the 'roll' value the user sees)
+static double boneRoll_ToArmatureSpace(struct Bone *bone)
+{
+ float head[3], tail[3], delta[3];
+ float premat[3][3], postmat[3][3];
+ float imat[3][3], difmat[3][3];
+ double roll = 0.0f;
+
+ VECCOPY(head, bone->arm_head);
+ VECCOPY(tail, bone->arm_tail);
+ VECSUB (delta, tail, head);
+ vec_roll_to_mat3(delta, 0.0f, postmat);
+ Mat3CpyMat4(premat, bone->arm_mat);
+ Mat3Inv(imat, postmat);
+ Mat3MulMat3(difmat, imat, premat);
+
+ roll = atan2(difmat[2][0], difmat[2][2]);
+ if (difmat[0][0] < 0.0){
+ roll += M_PI;
+ }
+ return roll; //result is in radians
+}
+
+//################## EditBone_Type ########################
+/*This type is a wrapper for a tempory bone. This is an 'unparented' bone
+*object. The armature->bonebase will be calculated from these temporary
+*python tracked objects.*/
+//####################################################
+
+//------------------METHOD IMPLEMENTATIONS-----------------------------
+//-------------------------EditBone.hasParent()
+static PyObject *EditBone_hasParent(BPy_EditBone *self)
+{
+ if (self->editbone){
+ if (self->editbone->parent)
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+ }else{
+ goto AttributeError;
+ }
+
+AttributeError:
+ return EXPP_objError(PyExc_AttributeError, "%s%s%s",
+ sEditBoneError, ".hasParent: ", "EditBone must be added to the armature first");
+}
+//-------------------------EditBone.clearParent()
+static PyObject *EditBone_clearParent(BPy_EditBone *self)
+{
+ if (self->editbone){
+ if (self->editbone->parent)
+ self->editbone->parent = NULL;
+ Py_RETURN_NONE;
+ }else{
+ goto AttributeError;
+ }
+
+AttributeError:
+ return EXPP_objError(PyExc_AttributeError, "%s%s%s",
+ sEditBoneError, ".clearParent: ", "EditBone must be added to the armature first");
+}
+//------------------ATTRIBUTE IMPLEMENTATION---------------------------
+//------------------------EditBone.name (get)
+static PyObject *EditBone_getName(BPy_EditBone *self, void *closure)
+{
+ if (self->editbone)
+ return PyString_FromString(self->editbone->name);
+ else
+ return PyString_FromString(self->name);
+}
+//------------------------EditBone.name (set)
+//check for char[] overflow here...
+static int EditBone_setName(BPy_EditBone *self, PyObject *value, void *closure)
+{
+ char *name = "";
+
+ if (!PyArg_Parse(value, "s", &name))
+ goto AttributeError;
+
+ if (self->editbone)
+ BLI_strncpy(self->editbone->name, name, 32);
+ else
+ BLI_strncpy(self->name, name, 32);
+ return 0;
+
+AttributeError:
+ return EXPP_intError(PyExc_AttributeError, "%s%s%s",
+ sEditBoneError, ".name: ", "expects a string");
+}
+//------------------------EditBone.roll (get)
+static PyObject *EditBone_getRoll(BPy_EditBone *self, void *closure)
+{
+ if (self->editbone){
+ return PyFloat_FromDouble((self->editbone->roll * (180/Py_PI)));
+ }else{
+ return PyFloat_FromDouble((self->roll * (180/Py_PI)));
+ }
+}
+//------------------------EditBone.roll (set)
+static int EditBone_setRoll(BPy_EditBone *self, PyObject *value, void *closure)
+{
+ float roll = 0.0f;
+
+ if (!PyArg_Parse(value, "f", &roll))
+ goto AttributeError;
+
+ if (self->editbone){
+ self->editbone->roll = (float)(roll * (Py_PI/180));
+ }else{
+ self->roll = (float)(roll * (Py_PI/180));
+ }
+ return 0;
+
+AttributeError:
+ return EXPP_intError(PyExc_AttributeError, "%s%s%s",
+ sEditBoneError, ".roll: ", "expects a float");
+}
+//------------------------EditBone.head (get)
+static PyObject *EditBone_getHead(BPy_EditBone *self, void *closure)
+{
+ if (self->editbone){
+ return newVectorObject(self->editbone->head, 3, Py_WRAP);
+ }else{
+ return newVectorObject(self->head, 3, Py_NEW);
+ }
+}
+//------------------------EditBone.head (set)
+static int EditBone_setHead(BPy_EditBone *self, PyObject *value, void *closure)
+{
+ VectorObject *vec = NULL;
+ int x;
+
+ if (!PyArg_Parse(value, "O!", &vector_Type, &vec))
+ goto AttributeError;
+ if (vec->size != 3)
+ goto AttributeError2;
+
+ if (self->editbone){
+ for (x = 0; x < 3; x++){
+ self->editbone->head[x] = vec->vec[x];
+ }
+ }else{
+ for (x = 0; x < 3; x++){
+ self->head[x] = vec->vec[x];
+ }
+ }
+ return 0;
+
+AttributeError:
+ return EXPP_intError(PyExc_AttributeError, "%s%s%s",
+ sEditBoneError, ".head: ", "expects a Vector Object");
+
+AttributeError2:
+ return EXPP_intError(PyExc_AttributeError, "%s%s%s",
+ sEditBoneError, ".head: ", "Vector Object needs to be (x,y,z)");
+}
+//------------------------EditBone.tail (get)
+static PyObject *EditBone_getTail(BPy_EditBone *self, void *closure)
+{
+ if (self->editbone){
+ return newVectorObject(self->editbone->tail, 3, Py_WRAP);
+ }else{
+ return newVectorObject(self->tail, 3, Py_NEW);
+ }
+}
+//------------------------EditBone.tail (set)
+static int EditBone_setTail(BPy_EditBone *self, PyObject *value, void *closure)
+{
+ VectorObject *vec = NULL;
+ int x;
+
+ if (!PyArg_Parse(value, "O!", &vector_Type, &vec))
+ goto AttributeError;
+ if (vec->size != 3)
+ goto AttributeError2;
+
+ if (self->editbone){
+ for (x = 0; x < 3; x++){
+ self->editbone->tail[x] = vec->vec[x];
+ }
+ }else{
+ for (x = 0; x < 3; x++){
+ self->tail[x] = vec->vec[x];
+ }
+ }
+ return 0;
+
+AttributeError:
+ return EXPP_intError(PyExc_AttributeError, "%s%s%s",
+ sEditBoneError, ".tail: ", "expects a Vector Object");
+
+AttributeError2:
+ return EXPP_intError(PyExc_AttributeError, "%s%s%s",
+ sEditBoneError, ".tail: ", "Vector Object needs to be (x,y,z)");
+}
+//------------------------EditBone.weight (get)
+static PyObject *EditBone_getWeight(BPy_EditBone *self, void *closure)
+{
+ if (self->editbone)
+ return PyFloat_FromDouble(self->editbone->weight);
+ else
+ return PyFloat_FromDouble(self->weight);
+}
+//------------------------EditBone.weight (set)
+static int EditBone_setWeight(BPy_EditBone *self, PyObject *value, void *closure)
+{
+ float weight;
+
+ if (!PyArg_Parse(value, "f", &weight))
+ goto AttributeError;
+ CLAMP(weight, 0.0f, 1000.0f);
+
+ if (self->editbone)
+ self->editbone->weight = weight;
+ else
+ self->weight = weight;
+ return 0;
+
+AttributeError:
+ return EXPP_intError(PyExc_AttributeError, "%s%s%s",
+ sEditBoneError, ".weight: ", "expects a float");
+}
+//------------------------EditBone.deform_dist (get)
+static PyObject *EditBone_getDeform_dist(BPy_EditBone *self, void *closure)
+{
+ if (self->editbone)
+ return PyFloat_FromDouble(self->editbone->dist);
+ else
+ return PyFloat_FromDouble(self->dist);
+}
+//------------------------EditBone.deform_dist (set)
+static int EditBone_setDeform_dist(BPy_EditBone *self, PyObject *value, void *closure)
+{
+ float deform;
+
+ if (!PyArg_Parse(value, "f", &deform))
+ goto AttributeError;
+ CLAMP(deform, 0.0f, 1000.0f);
+
+ if (self->editbone)
+ self->editbone->dist = deform;
+ else
+ self->dist = deform;
+ return 0;
+
+AttributeError:
+ return EXPP_intError(PyExc_AttributeError, "%s%s%s",
+ sEditBoneError, ".deform_dist: ", "expects a float");
+}
+//------------------------EditBone.subdivisions (get)
+static PyObject *EditBone_getSubdivisions(BPy_EditBone *self, void *closure)
+{
+ if (self->editbone)
+ return PyInt_FromLong(self->editbone->segments);
+ else
+ return PyInt_FromLong(self->segments);
+}
+//------------------------EditBone.subdivisions (set)
+static int EditBone_setSubdivisions(BPy_EditBone *self, PyObject *value, void *closure)
+{
+ int segs;
+
+ if (!PyArg_Parse(value, "i", &segs))
+ goto AttributeError;
+ CLAMP(segs, 1, 32);
+
+ if (self->editbone)
+ self->editbone->segments = (short)segs;
+ else
+ self->segments = (short)segs;
+ return 0;
+
+AttributeError:
+ return EXPP_intError(PyExc_AttributeError, "%s%s%s",
+ sEditBoneError, ".subdivisions: ", "expects a integer");
+}
+//------------------------EditBone.options (get)
+static PyObject *EditBone_getOptions(BPy_EditBone *self, void *closure)
+{
+ PyObject *list = NULL;
+
+ list = PyList_New(0);
+ if (!list)
+ goto RuntimeError;
+
+ if(self->editbone){
+ if(self->editbone->flag & BONE_CONNECTED)
+ if (PyList_Append(list,
+ EXPP_GetModuleConstant("Blender.Armature", "CONNECTED")) == -1)
+ goto RuntimeError;
+ if(self->editbone->flag & BONE_HINGE)
+ if (PyList_Append(list,
+ EXPP_GetModuleConstant("Blender.Armature", "HINGE")) == -1)
+ goto RuntimeError;
+ if(self->editbone->flag & BONE_NO_DEFORM)
+ if (PyList_Append(list,
+ EXPP_GetModuleConstant("Blender.Armature", "NO_DEFORM")) == -1)
+ goto RuntimeError;
+ if(self->editbone->flag & BONE_MULT_VG_ENV)
+ if (PyList_Append(list,
+ EXPP_GetModuleConstant("Blender.Armature", "MULTIPLY")) == -1)
+ goto RuntimeError;
+ if(self->editbone->flag & BONE_HIDDEN_A)
+ if (PyList_Append(list,
+ EXPP_GetModuleConstant("Blender.Armature", "HIDDEN_EDIT")) == -1)
+ goto RuntimeError;
+ if(self->editbone->flag & BONE_ROOTSEL)
+ if (PyList_Append(list,
+ EXPP_GetModuleConstant("Blender.Armature", "ROOT_SELECTED")) == -1)
+ goto RuntimeError;
+ if(self->editbone->flag & BONE_SELECTED)
+ if (PyList_Append(list,
+ EXPP_GetModuleConstant("Blender.Armature", "BONE_SELECTED")) == -1)
+ goto RuntimeError;
+ if(self->editbone->flag & BONE_TIPSEL)
+ if (PyList_Append(list,
+ EXPP_GetModuleConstant("Blender.Armature", "TIP_SELECTED")) == -1)
+ goto RuntimeError;
+ }else{
+ if(self->flag & BONE_CONNECTED)
+ if (PyList_Append(list,
+ EXPP_GetModuleConstant("Blender.Armature", "CONNECTED")) == -1)
+ goto RuntimeError;
+ if(self->flag & BONE_HINGE)
+ if (PyList_Append(list,
+ EXPP_GetModuleConstant("Blender.Armature", "HINGE")) == -1)
+ goto RuntimeError;
+ if(self->flag & BONE_NO_DEFORM)
+ if (PyList_Append(list,
+ EXPP_GetModuleConstant("Blender.Armature", "NO_DEFORM")) == -1)
+ goto RuntimeError;
+ if(self->flag & BONE_MULT_VG_ENV)
+ if (PyList_Append(list,
+ EXPP_GetModuleConstant("Blender.Armature", "MULTIPLY")) == -1)
+ goto RuntimeError;
+ if(self->flag & BONE_HIDDEN_A)
+ if (PyList_Append(list,
+ EXPP_GetModuleConstant("Blender.Armature", "HIDDEN_EDIT")) == -1)
+ goto RuntimeError;
+ if(self->flag & BONE_ROOTSEL)
+ if (PyList_Append(list,
+ EXPP_GetModuleConstant("Blender.Armature", "ROOT_SELECTED")) == -1)
+ goto RuntimeError;
+ if(self->flag & BONE_SELECTED)
+ if (PyList_Append(list,
+ EXPP_GetModuleConstant("Blender.Armature", "BONE_SELECTED")) == -1)
+ goto RuntimeError;
+ if(self->flag & BONE_TIPSEL)
+ if (PyList_Append(list,
+ EXPP_GetModuleConstant("Blender.Armature", "TIP_SELECTED")) == -1)
+ goto RuntimeError;
+ }
+
+ return list;
+
+RuntimeError:
+ Py_XDECREF( list );
+ return EXPP_objError(PyExc_RuntimeError, "%s%s%s",
+ sEditBoneError, ".options: ", "Internal failure!");
+}
+//----------------------(internal) EditBone_CheckValidConstant
+static int EditBone_CheckValidConstant(PyObject *constant)
+{
+ PyObject *name = NULL;
+
+ if (constant){
+ if (BPy_Constant_Check(constant)){
+ name = PyDict_GetItemString(((BPy_constant*)constant)->dict, "name");
+ if (!name)
+ return 0;
+ if (!STREQ3(PyString_AsString(name), "CONNECTED", "HINGE", "NO_DEFORM") &&
+ !STREQ3(PyString_AsString(name), "ROOT_SELECTED", "BONE_SELECTED", "TIP_SELECTED") &&
+ !STREQ2(PyString_AsString(name), "MULTIPLY", "HIDDEN_EDIT"))
+ return 0;
+ else
+ return 1;
+ }else{
+ return 0;
+ }
+ }else{
+ return 0;
+ }
+}
+
+//------------------------EditBone.options (set)
+static int EditBone_setOptions(BPy_EditBone *self, PyObject *value, void *closure)
+{
+ int length, numeric_value, new_flag = 0, x;
+ PyObject *val = NULL, *index = NULL;
+
+ if (PyList_Check(value)){
+ length = PyList_Size(value);
+ for (x = 0; x < length; x++){
+ index = PyList_GetItem(value, x);
+ if (!EditBone_CheckValidConstant(index))
+ goto AttributeError2;
+ val = PyDict_GetItemString(((BPy_constant*)index)->dict, "value");
+ if (PyInt_Check(val)){
+ numeric_value = (int)PyInt_AS_LONG(val);
+ new_flag |= numeric_value;
+ }else{
+ goto AttributeError2;
+ }
+ }
+
+ //set the options
+ if(self->editbone){
+ //make sure the 'connected' property is set up correctly
+ if (new_flag & BONE_CONNECTED) {
+ if(!self->editbone->parent)
+ goto AttributeError3;
+ else
+ VECCOPY(self->editbone->head, self->editbone->parent->tail);
+ }
+ self->editbone->flag = new_flag;
+ }else{
+ self->flag = new_flag;
+ }
+ return 0;
+ }else if (BPy_Constant_Check(value)){
+ if (!EditBone_CheckValidConstant(value))
+ goto AttributeError2;
+ val = PyDict_GetItemString(((BPy_constant*)value)->dict, "value");
+ if (PyInt_Check(val)){
+ numeric_value = (int)PyInt_AS_LONG(val);
+
+ if(self->editbone){
+ //make sure the 'connected' property is set up correctly
+ if (numeric_value & BONE_CONNECTED) {
+ if(!self->editbone->parent)
+ goto AttributeError3;
+ else
+ VECCOPY(self->editbone->head, self->editbone->parent->tail);
+ }
+ self->editbone->flag = numeric_value;
+ }else{
+ self->flag = numeric_value;
+ }
+ return 0;
+ }else{
+ goto AttributeError2;
+ }
+ }else{
+ goto AttributeError1;
+ }
+
+AttributeError1:
+ return EXPP_intError(PyExc_AttributeError, "%s%s%s",
+ sEditBoneError, ".options: ", "Expects a constant or list of constants");
+AttributeError2:
+ return EXPP_intError(PyExc_AttributeError, "%s%s%s",
+ sEditBoneError, ".options: ", "Please use a constant defined in the Armature module");
+AttributeError3:
+ return EXPP_intError(PyExc_AttributeError, "%s%s%s",
+ sEditBoneError, ".options: ", "You can't connect to parent because no parent is set");
+}
+//------------------------EditBone.parent (get)
+static PyObject *EditBone_getParent(BPy_EditBone *self, void *closure)
+{
+ if (self->editbone){
+ if (self->editbone->parent)
+ return PyEditBone_FromEditBone(self->editbone->parent);
+ else
+ Py_RETURN_NONE;
+ }else{
+ Py_RETURN_NONE; //not in the list yet can't have a parent
+ }
+}
+//------------------------EditBone.parent (set)
+static int EditBone_setParent(BPy_EditBone *self, PyObject *value, void *closure)
+{
+ BPy_EditBone *parent = NULL;
+
+ if (!PyArg_Parse(value, "O!", &EditBone_Type, &parent))
+ goto AttributeError;
+
+ if (!parent->editbone)
+ goto AttributeError2;
+
+ if (self->editbone){
+ self->editbone->parent = parent->editbone;
+ }else{
+ self->parent = parent->editbone;
+ }
+ return 0;
+
+AttributeError:
+ return EXPP_intError(PyExc_AttributeError, "%s%s%s",
+ sEditBoneError, ".parent: ", "expects a EditBone Object");
+AttributeError2:
+ return EXPP_intError(PyExc_AttributeError, "%s%s%s",
+ sEditBoneError, ".parent: ", "This object is not in the armature's bone list!");
+}
+//------------------------EditBone.matrix (get)
+static PyObject *EditBone_getMatrix(BPy_EditBone *self, void *closure)
+{
+ float boneMatrix[3][3];
+ float axis[3];
+
+ if (self->editbone){
+ VECSUB(axis, self->editbone->tail, self->editbone->head);
+ vec_roll_to_mat3(axis, self->editbone->roll, boneMatrix);
+ }else{
+ VECSUB(axis, self->tail, self->head);
+ vec_roll_to_mat3(axis, self->roll, boneMatrix);
+ }
+
+ return newMatrixObject((float*)boneMatrix, 3, 3, Py_NEW);
+}
+//------------------------EditBone.matrix (set)
+static int EditBone_setMatrix(BPy_EditBone *self, PyObject *value, void *closure)
+{
+ PyObject *matrix;
+ float roll, length, vec[3], axis[3], mat3[3][3];
+
+ if (!PyArg_Parse(value, "O!", &matrix_Type, &matrix))
+ goto AttributeError;
+
+ //make sure we have the right sizes
+ if (((MatrixObject*)matrix)->rowSize != 3 && ((MatrixObject*)matrix)->colSize != 3){
+ if(((MatrixObject*)matrix)->rowSize != 4 && ((MatrixObject*)matrix)->colSize != 4){
+ goto AttributeError;
+ }
+ }
+
+ /*vec will be a normalized directional vector
+ * together with the length of the old bone vec*length = the new vector*/
+ /*The default rotation is 0,1,0 on the Y axis (see mat3_to_vec_roll)*/
+ if (((MatrixObject*)matrix)->rowSize == 4){
+ Mat3CpyMat4(mat3, ((float (*)[4])*((MatrixObject*)matrix)->matrix));
+ }else{
+ Mat3CpyMat3(mat3, ((float (*)[3])*((MatrixObject*)matrix)->matrix));
+ }
+ mat3_to_vec_roll(mat3, vec, &roll);
+
+ //if a 4x4 matrix was passed we'll translate the vector otherwise not
+ if (self->editbone){
+ self->editbone->roll = roll;
+ VecSubf(axis, self->editbone->tail, self->editbone->head);
+ length = VecLength(axis);
+ VecMulf(vec, length);
+ if (((MatrixObject*)matrix)->rowSize == 4)
+ VecCopyf(self->editbone->head, ((MatrixObject*)matrix)->matrix[3]);
+ VecAddf(self->editbone->tail, self->editbone->head, vec);
+ return 0;
+ }else{
+ self->roll = roll;
+ VecSubf(axis, self->tail, self->head);
+ length = VecLength(axis);
+ VecMulf(vec, length);
+ if (((MatrixObject*)matrix)->rowSize == 4)
+ VecCopyf(self->head, ((MatrixObject*)matrix)->matrix[3]);
+ VecAddf(self->tail, self->head, vec);
+ return 0;
+ }
+
+AttributeError:
+ return EXPP_intError(PyExc_AttributeError, "%s%s%s",
+ sEditBoneError, ".matrix: ", "expects a 3x3 or 4x4 Matrix Object");
+}
+//------------------------Bone.length (get)
+static PyObject *EditBone_getLength(BPy_EditBone *self, void *closure)
+{
+ float delta[3];
+ double dot = 0.0f;
+ int x;
+
+ if (self->editbone){
+ VECSUB(delta, self->editbone->tail, self->editbone->head);
+ for(x = 0; x < 3; x++){
+ dot += (delta[x] * delta[x]);
+ }
+ return PyFloat_FromDouble(sqrt(dot));
+ }else{
+ VECSUB(delta, self->tail, self->head);
+ for(x = 0; x < 3; x++){
+ dot += (delta[x] * delta[x]);
+ }
+ return PyFloat_FromDouble(sqrt(dot));
+ }
+}
+//------------------------Bone.length (set)
+static int EditBone_setLength(BPy_EditBone *self, PyObject *value, void *closure)
+{
+ printf("Sorry this isn't implemented yet.... :/");
+ return 1;
+}
+
+
+//------------------------Bone.headRadius (get)
+static PyObject *EditBone_getHeadRadius(BPy_EditBone *self, void *closure)
+{
+ if (self->editbone)
+ if (self->editbone->parent && self->editbone->flag & BONE_CONNECTED)
+ return PyFloat_FromDouble(self->editbone->parent->rad_tail);
+ else
+ return PyFloat_FromDouble(self->editbone->rad_head);
+ else
+ if (self->parent && self->flag & BONE_CONNECTED)
+ return PyFloat_FromDouble(self->parent->rad_tail);
+ else
+ return PyFloat_FromDouble(self->rad_head);
+}
+//------------------------Bone.headRadius (set)
+static int EditBone_setHeadRadius(BPy_EditBone *self, PyObject *value, void *closure)
+{
+ float radius;
+ if (!PyArg_Parse(value, "f", &radius))
+ goto AttributeError;
+ CLAMP(radius, 0.0f, 10000.0f);
+
+ if (self->editbone)
+ if (self->editbone->parent && self->editbone->flag & BONE_CONNECTED)
+ self->editbone->parent->rad_tail= radius;
+ else
+ self->editbone->rad_head= radius;
+ else
+ if (self->parent && self->flag & BONE_CONNECTED)
+ self->parent->rad_tail= radius;
+ else
+ self->rad_head= radius;
+ return 0;
+
+AttributeError:
+ return EXPP_intError(PyExc_AttributeError, "%s%s%s",
+ sEditBoneError, ".headRadius: ", "expects a float");
+}
+
+
+//------------------------Bone.tailRadius (get)
+static PyObject *EditBone_getTailRadius(BPy_EditBone *self, void *closure)
+{
+ if (self->editbone)
+ return PyFloat_FromDouble(self->editbone->rad_tail);
+ else
+ return PyFloat_FromDouble(self->rad_tail);
+}
+//------------------------Bone.tailRadius (set)
+static int EditBone_setTailRadius(BPy_EditBone *self, PyObject *value, void *closure)
+{
+ float radius;
+ if (!PyArg_Parse(value, "f", &radius))
+ goto AttributeError;
+ CLAMP(radius, 0.0f, 10000.0f);
+
+ if (self->editbone)
+ self->editbone->rad_tail = radius;
+ else
+ self->rad_tail = radius;
+ return 0;
+
+AttributeError:
+ return EXPP_intError(PyExc_AttributeError, "%s%s%s",
+ sEditBoneError, ".tailRadius: ", "expects a float");
+}
+
+//------------------------Bone.layerMask (get)
+static PyObject *EditBone_getLayerMask(BPy_EditBone *self)
+{
+ /* do this extra stuff because the short's bits can be negative values */
+ unsigned short laymask = 0;
+ if (self->editbone) laymask |= self->editbone->layer;
+ else laymask |= self->layer;
+ return PyInt_FromLong((int)laymask);
+}
+//------------------------Bone.layerMask (set)
+static int EditBone_setLayerMask(BPy_EditBone *self, PyObject *value)
+{
+ int laymask;
+ if (!PyInt_Check(value)) {
+ return EXPP_ReturnIntError( PyExc_AttributeError,
+ "expected an integer (bitmask) as argument" );
+ }
+
+ laymask = PyInt_AsLong(value);
+
+ if (laymask <= 0 || laymask > (1<<16) - 1)
+ return EXPP_ReturnIntError( PyExc_AttributeError,
+ "bitmask must have from 1 up to 16 bits set");
+
+ if (self->editbone) {
+ self->editbone->layer = 0;
+ self->editbone->layer |= laymask;
+ } else {
+ self->layer = 0;
+ self->layer |= laymask;
+ }
+
+ return 0;
+}
+
+//------------------TYPE_OBECT IMPLEMENTATION--------------------------
+//------------------------tp_methods
+//This contains a list of all methods the object contains
+static PyMethodDef BPy_EditBone_methods[] = {
+ {"hasParent", (PyCFunction) EditBone_hasParent, METH_NOARGS,
+ "() - True/False - Bone has a parent"},
+ {"clearParent", (PyCFunction) EditBone_clearParent, METH_NOARGS,
+ "() - sets the parent to None"},
+ {NULL, NULL, 0, NULL}
+};
+///------------------------tp_getset
+//This contains methods for attributes that require checking
+static PyGetSetDef BPy_EditBone_getset[] = {
+ {"name", (getter)EditBone_getName, (setter)EditBone_setName,
+ "The name of the bone", NULL},
+ {"roll", (getter)EditBone_getRoll, (setter)EditBone_setRoll,
+ "The roll (or rotation around the axis) of the bone", NULL},
+ {"head", (getter)EditBone_getHead, (setter)EditBone_setHead,
+ "The start point of the bone", NULL},
+ {"tail", (getter)EditBone_getTail, (setter)EditBone_setTail,
+ "The end point of the bone", NULL},
+ {"matrix", (getter)EditBone_getMatrix, (setter)EditBone_setMatrix,
+ "The matrix of the bone", NULL},
+ {"weight", (getter)EditBone_getWeight, (setter)EditBone_setWeight,
+ "The weight of the bone in relation to a parented mesh", NULL},
+ {"deformDist", (getter)EditBone_getDeform_dist, (setter)EditBone_setDeform_dist,
+ "The distance at which deformation has effect", NULL},
+ {"subdivisions", (getter)EditBone_getSubdivisions, (setter)EditBone_setSubdivisions,
+ "The number of subdivisions (for B-Bones)", NULL},
+ {"options", (getter)EditBone_getOptions, (setter)EditBone_setOptions,
+ "The options effective on this bone", NULL},
+ {"parent", (getter)EditBone_getParent, (setter)EditBone_setParent,
+ "The parent bone of this bone", NULL},
+ {"length", (getter)EditBone_getLength, (setter)EditBone_setLength,
+ "The length of this bone", NULL},
+ {"tailRadius", (getter)EditBone_getTailRadius, (setter)EditBone_setTailRadius,
+ "Set the radius of this bones tip", NULL},
+ {"headRadius", (getter)EditBone_getHeadRadius, (setter)EditBone_setHeadRadius,
+ "Set the radius of this bones head", NULL},
+ {"layerMask", (getter)EditBone_getLayerMask, (setter)EditBone_setLayerMask,
+ "Layer bitmask", NULL },
+ {NULL, NULL, NULL, NULL,NULL}
+};
+
+//------------------------tp_repr
+//This is the string representation of the object
+static PyObject *EditBone_repr(BPy_EditBone *self)
+{
+ if (self->editbone)
+ return PyString_FromFormat( "[EditBone \"%s\"]", self->editbone->name );
+ else
+ return PyString_FromFormat( "[EditBone \"%s\"]", self->name );
+}
+
+static int EditBone_compare( BPy_EditBone * a, BPy_EditBone * b )
+{
+ /* if they are not wrapped, then they cant be the same */
+ if (a->editbone==NULL && b->editbone==NULL) return -1;
+ return ( a->editbone == b->editbone ) ? 0 : -1;
+}
+
+
+//------------------------tp_doc
+//The __doc__ string for this object
+static char BPy_EditBone_doc[] = "This is an internal subobject of armature\
+designed to act as a wrapper for an 'edit bone'.";
+
+//------------------------tp_new
+//This methods creates a new object (note it does not initialize it - only the building)
+static PyObject *EditBone_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ char *name = "myEditBone";
+ BPy_EditBone *py_editBone = NULL;
+ float head[3], tail[3];
+
+ py_editBone = (BPy_EditBone*)type->tp_alloc(type, 0); //new
+ if (py_editBone == NULL)
+ goto RuntimeError;
+
+ //this pointer will be set when this bone is placed in ListBase
+ //otherwise this will act as a py_object
+ py_editBone->editbone = NULL;
+
+ unique_editbone_name(NULL, name);
+ BLI_strncpy(py_editBone->name, name, 32);
+ py_editBone->parent = NULL;
+ py_editBone->weight= 1.0f;
+ py_editBone->dist= 0.25f;
+ py_editBone->xwidth= 0.1f;
+ py_editBone->zwidth= 0.1f;
+ py_editBone->ease1= 1.0f;
+ py_editBone->ease2= 1.0f;
+ py_editBone->rad_head= 0.10f;
+ py_editBone->rad_tail= 0.05f;
+ py_editBone->segments= 1;
+ py_editBone->layer= 1;
+ py_editBone->flag = 0;
+ py_editBone->roll = 0.0f;
+
+ head[0] = head[1] = head[2] = 0.0f;
+ tail[1] = tail[2] = 0.0f;
+ tail[0] = 1.0f;
+ VECCOPY(py_editBone->head, head);
+ VECCOPY(py_editBone->tail, tail);
+
+ return (PyObject*)py_editBone;
+
+RuntimeError:
+ return EXPP_objError(PyExc_RuntimeError, "%s%s%s",
+ sEditBoneError, " __new__: ", "Internal Error");
+}
+//------------------------tp_dealloc
+//This tells how to 'tear-down' our object when ref count hits 0
+//the struct EditBone pointer will be handled by the BPy_BonesDict class
+static void EditBone_dealloc(BPy_EditBone * self)
+{
+ EditBone_Type.tp_free(self);
+ return;
+}
+//------------------TYPE_OBECT DEFINITION--------------------------
+PyTypeObject EditBone_Type = {
+ PyObject_HEAD_INIT(NULL) //tp_head
+ 0, //tp_internal
+ "EditBone", //tp_name
+ sizeof(BPy_EditBone), //tp_basicsize
+ 0, //tp_itemsize
+ (destructor)EditBone_dealloc, //tp_dealloc
+ 0, //tp_print
+ 0, //tp_getattr
+ 0, //tp_setattr
+ (cmpfunc)EditBone_compare, //tp_compare
+ (reprfunc)EditBone_repr, //tp_repr
+ 0, //tp_as_number
+ 0, //tp_as_sequence
+ 0, //tp_as_mapping
+ 0, //tp_hash
+ 0, //tp_call
+ 0, //tp_str
+ 0, //tp_getattro
+ 0, //tp_setattro
+ 0, //tp_as_buffer
+ Py_TPFLAGS_DEFAULT, //tp_flags
+ BPy_EditBone_doc, //tp_doc
+ 0, //tp_traverse
+ 0, //tp_clear
+ 0, //tp_richcompare
+ 0, //tp_weaklistoffset
+ 0, //tp_iter
+ 0, //tp_iternext
+ BPy_EditBone_methods, //tp_methods
+ 0, //tp_members
+ BPy_EditBone_getset, //tp_getset
+ 0, //tp_base
+ 0, //tp_dict
+ 0, //tp_descr_get
+ 0, //tp_descr_set
+ 0, //tp_dictoffset
+ 0, //tp_init
+ 0, //tp_alloc
+ (newfunc)EditBone_new, //tp_new
+ 0, //tp_free
+ 0, //tp_is_gc
+ 0, //tp_bases
+ 0, //tp_mro
+ 0, //tp_cache
+ 0, //tp_subclasses
+ 0, //tp_weaklist
+ 0 //tp_del
+};
+
+//------------------METHOD IMPLEMENTATIONS--------------------------------
+//------------------------(internal) PyBone_ChildrenAsList
+static int PyBone_ChildrenAsList(PyObject *list, ListBase *bones){
+ Bone *bone = NULL;
+ PyObject *py_bone = NULL;
+
+ for (bone = bones->first; bone; bone = bone->next){
+ py_bone = PyBone_FromBone(bone);
+ if (py_bone == NULL)
+ return 0;
+
+ if(PyList_Append(list, py_bone) == -1){
+ return 0;
+ }
+ Py_DECREF(py_bone);
+ if (bone->childbase.first)
+ if (!PyBone_ChildrenAsList(list, &bone->childbase))
+ return 0;
+ }
+ return 1;
+}
+//-------------------------Bone.hasParent()
+static PyObject *Bone_hasParent(BPy_Bone *self)
+{
+ if (self->bone->parent)
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+}
+//-------------------------Bone.hasChildren()
+static PyObject *Bone_hasChildren(BPy_Bone *self)
+{
+ if (self->bone->childbase.first)
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+}
+//-------------------------Bone.getAllChildren()
+static PyObject *Bone_getAllChildren(BPy_Bone *self)
+{
+ PyObject *list = PyList_New(0);
+ if (!self->bone->childbase.first) {
+ /* do nothing */
+ } else if (!PyBone_ChildrenAsList(list, &self->bone->childbase)) {
+ Py_XDECREF(list);
+ EXPP_objError(PyExc_RuntimeError, "%s%s",
+ sBoneError, "Internal error trying to wrap blender bones!");
+ }
+ return list;
+}
+
+//------------------ATTRIBUTE IMPLEMENTATIONS-----------------------------
+//------------------------Bone.name (get)
+static PyObject *Bone_getName(BPy_Bone *self, void *closure)
+{
+ return PyString_FromString(self->bone->name);
+}
+//------------------------Bone.name (set)
+//check for char[] overflow here...
+static int Bone_setName(BPy_Bone *self, PyObject *value, void *closure)
+{
+ return EXPP_intError(PyExc_ValueError, "%s%s",
+ sBoneError, "You must first call .makeEditable() to edit the armature");
+}
+//------------------------Bone.roll (get)
+static PyObject *Bone_getRoll(BPy_Bone *self, void *closure)
+{
+ return Py_BuildValue("{s:f, s:f}",
+ "BONESPACE", self->bone->roll * (180/Py_PI),
+ "ARMATURESPACE", boneRoll_ToArmatureSpace(self->bone) * (180/Py_PI));
+}
+//------------------------Bone.roll (set)
+static int Bone_setRoll(BPy_Bone *self, PyObject *value, void *closure)
+{
+ return EXPP_intError(PyExc_ValueError, "%s%s",
+ sBoneError, "You must first call .makeEditable() to edit the armature");
+}
+//------------------------Bone.head (get)
+static PyObject *Bone_getHead(BPy_Bone *self, void *closure)
+{
+ PyObject *val1 = newVectorObject(self->bone->head, 3, Py_WRAP);
+ PyObject *val2 = newVectorObject(self->bone->arm_head, 3, Py_WRAP);
+ PyObject *ret = Py_BuildValue(
+ "{s:O, s:O}", "BONESPACE", val1, "ARMATURESPACE", val2);
+
+ Py_DECREF(val1);
+ Py_DECREF(val2);
+ return ret;
+}
+//------------------------Bone.head (set)
+static int Bone_setHead(BPy_Bone *self, PyObject *value, void *closure)
+{
+ return EXPP_intError(PyExc_ValueError, "%s%s",
+ sBoneError, "You must first call .makeEditable() to edit the armature");
+}
+//------------------------Bone.tail (get)
+static PyObject *Bone_getTail(BPy_Bone *self, void *closure)
+{
+ PyObject *val1 = newVectorObject(self->bone->tail, 3, Py_WRAP);
+ PyObject *val2 = newVectorObject(self->bone->arm_tail, 3, Py_WRAP);
+ PyObject *ret = Py_BuildValue("{s:O, s:O}",
+ "BONESPACE", val1, "ARMATURESPACE", val2);
+
+ Py_DECREF(val1);
+ Py_DECREF(val2);
+ return ret;
+}
+//------------------------Bone.tail (set)
+static int Bone_setTail(BPy_Bone *self, PyObject *value, void *closure)
+{
+ return EXPP_intError(PyExc_ValueError, "%s%s",
+ sBoneError, "You must first call .makeEditable() to edit the armature");
+}
+//------------------------Bone.weight (get)
+static PyObject *Bone_getWeight(BPy_Bone *self, void *closure)
+{
+ return PyFloat_FromDouble(self->bone->weight);
+}
+//------------------------Bone.weight (set)
+static int Bone_setWeight(BPy_Bone *self, PyObject *value, void *closure)
+{
+ return EXPP_intError(PyExc_ValueError, "%s%s",
+ sBoneError, "You must first call .makeEditable() to edit the armature");
+}
+//------------------------Bone.deform_dist (get)
+static PyObject *Bone_getDeform_dist(BPy_Bone *self, void *closure)
+{
+ return PyFloat_FromDouble(self->bone->dist);
+}
+//------------------------Bone.deform_dist (set)
+static int Bone_setDeform_dist(BPy_Bone *self, PyObject *value, void *closure)
+{
+ return EXPP_intError(PyExc_ValueError, "%s%s",
+ sBoneError, "You must first call .makeEditable() to edit the armature");
+}
+//------------------------Bone.subdivisions (get)
+static PyObject *Bone_getSubdivisions(BPy_Bone *self, void *closure)
+{
+ return PyInt_FromLong(self->bone->segments);
+}
+//------------------------Bone.subdivisions (set)
+static int Bone_setSubdivisions(BPy_Bone *self, PyObject *value, void *closure)
+{
+ return EXPP_intError(PyExc_ValueError, "%s%s",
+ sBoneError, "You must first call .makeEditable() to edit the armature");
+}
+//------------------------Bone.connected (get)
+static PyObject *Bone_getOptions(BPy_Bone *self, void *closure)
+{
+ PyObject *list = NULL;
+
+ list = PyList_New(0);
+ if (list == NULL)
+ goto RuntimeError;
+
+ if(self->bone->flag & BONE_CONNECTED)
+ if (PyList_Append(list,
+ EXPP_GetModuleConstant("Blender.Armature", "CONNECTED")) == -1)
+ goto RuntimeError;
+ if(self->bone->flag & BONE_HINGE)
+ if (PyList_Append(list,
+ EXPP_GetModuleConstant("Blender.Armature", "HINGE")) == -1)
+ goto RuntimeError;
+ if(self->bone->flag & BONE_NO_DEFORM)
+ if (PyList_Append(list,
+ EXPP_GetModuleConstant("Blender.Armature", "NO_DEFORM")) == -1)
+ goto RuntimeError;
+ if(self->bone->flag & BONE_MULT_VG_ENV)
+ if (PyList_Append(list,
+ EXPP_GetModuleConstant("Blender.Armature", "MULTIPLY")) == -1)
+ goto RuntimeError;
+ if(self->bone->flag & BONE_HIDDEN_A)
+ if (PyList_Append(list,
+ EXPP_GetModuleConstant("Blender.Armature", "HIDDEN_EDIT")) == -1)
+ goto RuntimeError;
+ if(self->bone->flag & BONE_ROOTSEL)
+ if (PyList_Append(list,
+ EXPP_GetModuleConstant("Blender.Armature", "ROOT_SELECTED")) == -1)
+ goto RuntimeError;
+ if(self->bone->flag & BONE_SELECTED)
+ if (PyList_Append(list,
+ EXPP_GetModuleConstant("Blender.Armature", "BONE_SELECTED")) == -1)
+ goto RuntimeError;
+ if(self->bone->flag & BONE_TIPSEL)
+ if (PyList_Append(list,
+ EXPP_GetModuleConstant("Blender.Armature", "TIP_SELECTED")) == -1)
+ goto RuntimeError;
+
+ return list;
+
+RuntimeError:
+ Py_XDECREF(list);
+ return EXPP_objError(PyExc_RuntimeError, "%s%s%s",
+ sBoneError, "getOptions(): ", "Internal failure!");
+}
+//------------------------Bone.connected (set)
+static int Bone_setOptions(BPy_Bone *self, PyObject *value, void *closure)
+{
+ return EXPP_intError(PyExc_ValueError, "%s%s",
+ sBoneError, "You must first call .makeEditable() to edit the armature");
+}
+//------------------------Bone.parent (get)
+static PyObject *Bone_getParent(BPy_Bone *self, void *closure)
+{
+ if (self->bone->parent)
+ return PyBone_FromBone(self->bone->parent);
+ else
+ Py_RETURN_NONE;
+}
+//------------------------Bone.parent (set)
+static int Bone_setParent(BPy_Bone *self, PyObject *value, void *closure)
+{
+ return EXPP_intError(PyExc_ValueError, "%s%s",
+ sBoneError, "You must first call .makeEditable() to edit the armature");
+}
+//------------------------Bone.children (get)
+static PyObject *Bone_getChildren(BPy_Bone *self, void *closure)
+{
+ PyObject *list = PyList_New(0);
+ Bone *bone = NULL;
+ PyObject *py_bone = NULL;
+
+ if (self->bone->childbase.first){
+ for (bone = self->bone->childbase.first; bone; bone = bone->next){
+ py_bone = PyBone_FromBone(bone);
+ if (py_bone == NULL)
+ goto RuntimeError;
+ if (PyList_Append(list, py_bone) == -1)
+ goto RuntimeError;
+ Py_DECREF(py_bone);
+ }
+ }
+ return list;
+
+RuntimeError:
+ Py_XDECREF(list);
+ Py_XDECREF(py_bone);
+ return EXPP_objError(PyExc_RuntimeError, "%s%s",
+ sBoneError, "Internal error trying to wrap blender bones!");
+}
+//------------------------Bone.children (set)
+static int Bone_setChildren(BPy_Bone *self, PyObject *value, void *closure)
+{
+ return EXPP_intError(PyExc_ValueError, "%s%s",
+ sBoneError, "You must first call .makeEditable() to edit the armature");
+}
+//------------------------Bone.matrix (get)
+static PyObject *Bone_getMatrix(BPy_Bone *self, void *closure)
+{
+ PyObject *val1 = newMatrixObject((float*)self->bone->bone_mat, 3,3, Py_WRAP);
+ PyObject *val2 = newMatrixObject((float*)self->bone->arm_mat, 4,4, Py_WRAP);
+ PyObject *ret = Py_BuildValue("{s:O, s:O}",
+ "BONESPACE", val1, "ARMATURESPACE", val2);
+ Py_DECREF(val1);
+ Py_DECREF(val2);
+ return ret;
+
+
+}
+//------------------------Bone.matrix (set)
+static int Bone_setMatrix(BPy_Bone *self, PyObject *value, void *closure)
+{
+ return EXPP_intError(PyExc_ValueError, "%s%s",
+ sBoneError, "You must first call .makeEditable() to edit the armature");
+}
+//------------------------Bone.length (get)
+static PyObject *Bone_getLength(BPy_Bone *self, void *closure)
+{
+ return PyFloat_FromDouble(self->bone->length);
+}
+//------------------------Bone.length (set)
+static int Bone_setLength(BPy_Bone *self, PyObject *value, void *closure)
+{
+ return EXPP_intError(PyExc_ValueError, "%s%s",
+ sBoneError, "You must first call .makeEditable() to edit the armature");
+}
+
+//------------------------Bone.headRadius (get)
+static PyObject *Bone_getHeadRadius(BPy_Bone *self, void *closure)
+{
+
+ if (self->bone->parent && self->bone->flag & BONE_CONNECTED)
+ return PyFloat_FromDouble(self->bone->parent->rad_tail);
+ else
+ return PyFloat_FromDouble(self->bone->rad_head);
+}
+//------------------------Bone.headRadius (set)
+static int Bone_setHeadRadius(BPy_Bone *self, PyObject *value, void *closure)
+{
+ float radius;
+ if (!PyArg_Parse(value, "f", &radius))
+ goto AttributeError;
+ CLAMP(radius, 0.0f, 10000.0f);
+
+ if (self->bone->parent && self->bone->flag & BONE_CONNECTED)
+ self->bone->parent->rad_tail= radius;
+ else
+ self->bone->rad_head= radius;
+ return 0;
+
+AttributeError:
+ return EXPP_intError(PyExc_AttributeError, "%s%s%s",
+ sEditBoneError, ".headRadius: ", "expects a float");
+}
+
+//------------------------Bone.tailRadius (get)
+static PyObject *Bone_getTailRadius(BPy_Bone *self, void *closure)
+{
+ return PyFloat_FromDouble(self->bone->rad_tail);
+}
+
+//------------------------Bone.headRadius (set)
+static int Bone_setTailRadius(BPy_Bone *self, PyObject *value, void *closure)
+{
+ float radius;
+ if (!PyArg_Parse(value, "f", &radius))
+ goto AttributeError;
+ CLAMP(radius, 0.0f, 10000.0f);
+ self->bone->rad_tail= radius;
+ return 0;
+
+AttributeError:
+ return EXPP_intError(PyExc_AttributeError, "%s%s%s",
+ sEditBoneError, ".headRadius: ", "expects a float");
+}
+
+//------------------------Bone.layerMask (get)
+static PyObject *Bone_getLayerMask(BPy_Bone *self)
+{
+ /* do this extra stuff because the short's bits can be negative values */
+ unsigned short laymask = 0;
+ laymask |= self->bone->layer;
+ return PyInt_FromLong((int)laymask);
+}
+//------------------------Bone.layerMask (set)
+static int Bone_setLayerMask(BPy_Bone *self, PyObject *value)
+{
+ int laymask;
+ if (!PyInt_Check(value)) {
+ return EXPP_ReturnIntError( PyExc_AttributeError,
+ "expected an integer (bitmask) as argument" );
+ }
+
+ laymask = PyInt_AsLong(value);
+
+ if (laymask <= 0 || laymask > (1<<16) - 1)
+ return EXPP_ReturnIntError( PyExc_AttributeError,
+ "bitmask must have from 1 up to 16 bits set");
+
+ self->bone->layer = 0;
+ self->bone->layer |= laymask;
+
+ return 0;
+}
+
+//------------------TYPE_OBECT IMPLEMENTATION--------------------------
+//------------------------tp_methods
+//This contains a list of all methods the object contains
+static PyMethodDef BPy_Bone_methods[] = {
+ {"hasParent", (PyCFunction) Bone_hasParent, METH_NOARGS,
+ "() - True/False - Bone has a parent"},
+ {"hasChildren", (PyCFunction) Bone_hasChildren, METH_NOARGS,
+ "() - True/False - Bone has 1 or more children"},
+ {"getAllChildren", (PyCFunction) Bone_getAllChildren, METH_NOARGS,
+ "() - All the children for this bone - including children's children"},
+ {NULL, NULL, 0, NULL}
+};
+//------------------------tp_getset
+//This contains methods for attributes that require checking
+static PyGetSetDef BPy_Bone_getset[] = {
+ {"name", (getter)Bone_getName, (setter)Bone_setName,
+ "The name of the bone", NULL},
+ {"roll", (getter)Bone_getRoll, (setter)Bone_setRoll,
+ "The roll (or rotation around the axis) of the bone", NULL},
+ {"head", (getter)Bone_getHead, (setter)Bone_setHead,
+ "The start point of the bone", NULL},
+ {"tail", (getter)Bone_getTail, (setter)Bone_setTail,
+ "The end point of the bone", NULL},
+ {"matrix", (getter)Bone_getMatrix, (setter)Bone_setMatrix,
+ "The matrix of the bone", NULL},
+ {"weight", (getter)Bone_getWeight, (setter)Bone_setWeight,
+ "The weight of the bone in relation to a parented mesh", NULL},
+ {"deform_dist", (getter)Bone_getDeform_dist, (setter)Bone_setDeform_dist,
+ "The distance at which deformation has effect", NULL},
+ {"subdivisions", (getter)Bone_getSubdivisions, (setter)Bone_setSubdivisions,
+ "The number of subdivisions (for B-Bones)", NULL},
+ {"options", (getter)Bone_getOptions, (setter)Bone_setOptions,
+ "The options effective on this bone", NULL},
+ {"parent", (getter)Bone_getParent, (setter)Bone_setParent,
+ "The parent bone of this bone", NULL},
+ {"children", (getter)Bone_getChildren, (setter)Bone_setChildren,
+ "The child bones of this bone", NULL},
+ {"length", (getter)Bone_getLength, (setter)Bone_setLength,
+ "The length of this bone", NULL},
+ {"tailRadius", (getter)Bone_getTailRadius, (setter)Bone_setTailRadius,
+ "Set the radius of this bones tip", NULL},
+ {"headRadius", (getter)Bone_getHeadRadius, (setter)Bone_setHeadRadius,
+ "Set the radius of this bones head", NULL},
+ {"layerMask", (getter)Bone_getLayerMask, (setter)Bone_setLayerMask,
+ "Layer bitmask", NULL },
+ {NULL, NULL, NULL, NULL,NULL}
+};
+//------------------------tp_repr
+//This is the string representation of the object
+static PyObject *Bone_repr(BPy_Bone *self)
+{
+ return PyString_FromFormat( "[Bone \"%s\"]", self->bone->name );
+}
+static int Bone_compare( BPy_Bone * a, BPy_Bone * b )
+{
+ return ( a->bone == b->bone ) ? 0 : -1;
+}
+//------------------------tp_dealloc
+//This tells how to 'tear-down' our object when ref count hits 0
+static void Bone_dealloc(BPy_Bone * self)
+{
+ Bone_Type.tp_free(self);
+ return;
+}
+//------------------------tp_doc
+//The __doc__ string for this object
+static char BPy_Bone_doc[] = "This object wraps a Blender Boneobject.\n\
+ This object is a subobject of the Armature object.";
+
+//------------------TYPE_OBECT DEFINITION--------------------------
+PyTypeObject Bone_Type = {
+ PyObject_HEAD_INIT(NULL) //tp_head
+ 0, //tp_internal
+ "Bone", //tp_name
+ sizeof(BPy_Bone), //tp_basicsize
+ 0, //tp_itemsize
+ (destructor)Bone_dealloc, //tp_dealloc
+ 0, //tp_print
+ 0, //tp_getattr
+ 0, //tp_setattr
+ (cmpfunc) Bone_compare, //tp_compare
+ (reprfunc) Bone_repr, //tp_repr
+ 0, //tp_as_number
+ 0, //tp_as_sequence
+ 0, //tp_as_mapping
+ 0, //tp_hash
+ 0, //tp_call
+ 0, //tp_str
+ 0, //tp_getattro
+ 0, //tp_setattro
+ 0, //tp_as_buffer
+ Py_TPFLAGS_DEFAULT, //tp_flags
+ BPy_Bone_doc, //tp_doc
+ 0, //tp_traverse
+ 0, //tp_clear
+ 0, //tp_richcompare
+ 0, //tp_weaklistoffset
+ 0, //tp_iter
+ 0, //tp_iternext
+ BPy_Bone_methods, //tp_methods
+ 0, //tp_members
+ BPy_Bone_getset, //tp_getset
+ 0, //tp_base
+ 0, //tp_dict
+ 0, //tp_descr_get
+ 0, //tp_descr_set
+ 0, //tp_dictoffset
+ 0, //tp_init
+ 0, //tp_alloc
+ 0, //tp_new
+ 0, //tp_free
+ 0, //tp_is_gc
+ 0, //tp_bases
+ 0, //tp_mro
+ 0, //tp_cache
+ 0, //tp_subclasses
+ 0, //tp_weaklist
+ 0 //tp_del
+};
+//------------------VISIBLE PROTOTYPE IMPLEMENTATION-----------------------
+//-----------------(internal)
+//Converts a struct EditBone to a BPy_EditBone
+PyObject *PyEditBone_FromEditBone(struct EditBone *editbone)
+{
+ BPy_EditBone *py_editbone = NULL;
+
+ py_editbone = (BPy_EditBone*)EditBone_Type.tp_alloc(&EditBone_Type, 0); //*new*
+ if (!py_editbone)
+ goto RuntimeError;
+
+ py_editbone->editbone = editbone;
+
+ return (PyObject *) py_editbone;
+
+RuntimeError:
+ return EXPP_objError(PyExc_RuntimeError, "%s%s%s",
+ sEditBoneError, "PyEditBone_FromEditBone: ", "Internal Error Ocurred");
+}
+//-----------------(internal)
+//Converts a struct Bone to a BPy_Bone
+PyObject *PyBone_FromBone(struct Bone *bone)
+{
+ BPy_Bone *py_Bone = ( BPy_Bone * ) PyObject_NEW( BPy_Bone, &Bone_Type );
+
+ py_Bone->bone = bone;
+
+ return (PyObject *) py_Bone;
+}
+//-----------------(internal)
+//Converts a PyBone to a bBone
+struct Bone *PyBone_AsBone(BPy_Bone *py_Bone)
+{
+ return (py_Bone->bone);
+}
diff --git a/source/blender/python/api2_2x/Bone.h b/source/blender/python/api2_2x/Bone.h
new file mode 100644
index 00000000000..aa076afbed7
--- /dev/null
+++ b/source/blender/python/api2_2x/Bone.h
@@ -0,0 +1,76 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Joseph Gilbert
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_BONE_H
+#define EXPP_BONE_H
+
+#include <Python.h>
+#include "DNA_armature_types.h"
+
+/*-------------------TYPE CHECKS---------------------------------*/
+#define BoneObject_Check(v) ((v)->ob_type == &Bone_Type)
+#define EditBoneObject_Check(v) ((v)->ob_type == &EditBone_Type)
+/*-------------------TYPEOBJECT----------------------------------*/
+extern PyTypeObject EditBone_Type;
+extern PyTypeObject Bone_Type;
+/*-------------------STRUCT DEFINITION----------------------------*/
+
+typedef struct {
+ PyObject_HEAD
+ Bone * bone;
+} BPy_Bone;
+
+typedef struct {
+ PyObject_HEAD
+ struct EditBone *editbone;
+ struct EditBone *parent;
+ char name[32];
+ float roll;
+ float head[3];
+ float tail[3];
+ int flag;
+ float dist;
+ float weight;
+ float xwidth;
+ float zwidth;
+ float ease1;
+ float ease2;
+ float rad_head;
+ float rad_tail;
+ short segments;
+ short layer;
+} BPy_EditBone;
+/*-------------------VISIBLE PROTOTYPES-------------------------*/
+PyObject *PyBone_FromBone(struct Bone *bone);
+struct Bone *PyBone_AsBone(BPy_Bone *py_Bone);
+PyObject *PyEditBone_FromBone(Bone *bone);
+PyObject *PyEditBone_FromEditBone(struct EditBone *editbone);
+
+#endif
diff --git a/source/blender/python/api2_2x/Camera.c b/source/blender/python/api2_2x/Camera.c
new file mode 100644
index 00000000000..f6b443e5d06
--- /dev/null
+++ b/source/blender/python/api2_2x/Camera.c
@@ -0,0 +1,1057 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano, Johnny Matthews, Ken Hughes
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#include "Camera.h" /*This must come first */
+
+#include "BKE_main.h"
+#include "BKE_global.h"
+#include "BKE_object.h"
+#include "BKE_library.h"
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h" /* for M_PI */
+#include "BSE_editipo.h"
+#include "BIF_space.h"
+#include "mydevice.h"
+#include "gen_utils.h"
+#include "gen_library.h"
+#include "Ipo.h"
+
+
+#define IPOKEY_LENS 0
+#define IPOKEY_CLIPPING 1
+
+
+
+enum cam_consts {
+ EXPP_CAM_ATTR_LENS = 0,
+ EXPP_CAM_ATTR_ANGLE,
+ EXPP_CAM_ATTR_DOFDIST,
+ EXPP_CAM_ATTR_CLIPEND,
+ EXPP_CAM_ATTR_CLIPSTART,
+ EXPP_CAM_ATTR_SCALE,
+ EXPP_CAM_ATTR_DRAWSIZE,
+ EXPP_CAM_ATTR_SHIFTX,
+ EXPP_CAM_ATTR_SHIFTY,
+ EXPP_CAM_ATTR_ALPHA,
+};
+
+/*****************************************************************************/
+/* Python API function prototypes for the Camera module. */
+/*****************************************************************************/
+static PyObject *M_Camera_New( PyObject * self, PyObject * args,
+ PyObject * keywords );
+static PyObject *M_Camera_Get( PyObject * self, PyObject * args );
+
+/*****************************************************************************/
+/* The following string definitions are used for documentation strings. */
+/* In Python these will be written to the console when doing a */
+/* Blender.Camera.__doc__ */
+/*****************************************************************************/
+static char M_Camera_doc[] = "The Blender Camera module\n\
+\n\
+This module provides access to **Camera Data** objects in Blender\n\
+\n\
+Example::\n\
+\n\
+ from Blender import Camera, Object, Scene\n\
+ c = Camera.New('ortho') # create new ortho camera data\n\
+ c.scale = 6.0 # set scale value\n\
+ scn = Scene.GetCurrent() # get current Scene\n\
+ ob = scn.objects.new(c) # Make an object from this data in the scene\n\
+ cur.setCurrentCamera(ob) # make this camera the active";
+
+static char M_Camera_New_doc[] =
+ "Camera.New (type = 'persp', name = 'CamData'):\n\
+ Return a new Camera Data object with the given type and name.";
+
+static char M_Camera_Get_doc[] = "Camera.Get (name = None):\n\
+ Return the camera data with the given 'name', None if not found, or\n\
+ Return a list with all Camera Data objects in the current scene,\n\
+ if no argument was given.";
+
+/*****************************************************************************/
+/* Python method structure definition for Blender.Camera module: */
+/*****************************************************************************/
+struct PyMethodDef M_Camera_methods[] = {
+ {"New", ( PyCFunction ) M_Camera_New, METH_VARARGS | METH_KEYWORDS,
+ M_Camera_New_doc},
+ {"Get", M_Camera_Get, METH_VARARGS, M_Camera_Get_doc},
+ {"get", M_Camera_Get, METH_VARARGS, M_Camera_Get_doc},
+ {NULL, NULL, 0, NULL}
+};
+
+/*****************************************************************************/
+/* Python BPy_Camera methods declarations: */
+/*****************************************************************************/
+static PyObject *Camera_oldgetType( BPy_Camera * self );
+static PyObject *Camera_oldgetMode( BPy_Camera * self );
+static PyObject *Camera_oldgetLens( BPy_Camera * self );
+static PyObject *Camera_oldgetClipStart( BPy_Camera * self );
+static PyObject *Camera_oldgetClipEnd( BPy_Camera * self );
+static PyObject *Camera_oldgetDrawSize( BPy_Camera * self );
+static PyObject *Camera_oldgetScale( BPy_Camera * self );
+static PyObject *Camera_getIpo( BPy_Camera * self );
+static int Camera_setIpo( BPy_Camera * self, PyObject * value );
+static PyObject *Camera_oldsetIpo( BPy_Camera * self, PyObject * args );
+static PyObject *Camera_oldsetType( BPy_Camera * self, PyObject * args );
+static PyObject *Camera_oldsetMode( BPy_Camera * self, PyObject * args );
+static PyObject *Camera_oldsetLens( BPy_Camera * self, PyObject * args );
+static PyObject *Camera_oldsetClipStart( BPy_Camera * self, PyObject * args );
+static PyObject *Camera_oldsetClipEnd( BPy_Camera * self, PyObject * args );
+static PyObject *Camera_oldsetDrawSize( BPy_Camera * self, PyObject * args );
+static PyObject *Camera_oldsetScale( BPy_Camera * self, PyObject * args );
+static PyObject *Camera_oldgetScriptLinks( BPy_Camera * self, PyObject * value );
+static PyObject *Camera_addScriptLink( BPy_Camera * self, PyObject * args );
+static PyObject *Camera_oldclearIpo( BPy_Camera * self );
+static PyObject *Camera_clearScriptLinks( BPy_Camera * self, PyObject * args );
+static PyObject *Camera_insertIpoKey( BPy_Camera * self, PyObject * args );
+static PyObject *Camera_copy( BPy_Camera * self );
+
+
+/*****************************************************************************/
+/* Python BPy_Camera methods table: */
+/*****************************************************************************/
+static PyMethodDef BPy_Camera_methods[] = {
+ /* name, method, flags, doc */
+ {"getIpo", ( PyCFunction ) Camera_getIpo, METH_NOARGS,
+ "() - Return Camera Data Ipo"},
+ {"getName", ( PyCFunction ) GenericLib_getName, METH_NOARGS,
+ "() - Return Camera Data name"},
+ {"getType", ( PyCFunction ) Camera_oldgetType, METH_NOARGS,
+ "() - Return Camera type - 'persp':0, 'ortho':1"},
+ {"getMode", ( PyCFunction ) Camera_oldgetMode, METH_NOARGS,
+ "() - Return Camera mode flags (or'ed value) -\n"
+ " 'showLimits':1, 'showMist':2"},
+ {"getLens", ( PyCFunction ) Camera_oldgetLens, METH_NOARGS,
+ "() - Return *perspective* Camera lens value"},
+ {"getScale", ( PyCFunction ) Camera_oldgetScale, METH_NOARGS,
+ "() - Return *ortho* Camera scale value"},
+ {"getClipStart", ( PyCFunction ) Camera_oldgetClipStart, METH_NOARGS,
+ "() - Return Camera clip start value"},
+ {"getClipEnd", ( PyCFunction ) Camera_oldgetClipEnd, METH_NOARGS,
+ "() - Return Camera clip end value"},
+ {"getDrawSize", ( PyCFunction ) Camera_oldgetDrawSize, METH_NOARGS,
+ "() - Return Camera draw size value"},
+ {"setIpo", ( PyCFunction ) Camera_oldsetIpo, METH_VARARGS,
+ "(Blender Ipo) - Set Camera Ipo"},
+ {"clearIpo", ( PyCFunction ) Camera_oldclearIpo, METH_NOARGS,
+ "() - Unlink Ipo from this Camera."},
+ {"insertIpoKey", ( PyCFunction ) Camera_insertIpoKey, METH_VARARGS,
+ "( Camera IPO type ) - Inserts a key into IPO"},
+ {"setName", ( PyCFunction ) GenericLib_setName_with_method, METH_VARARGS,
+ "(s) - Set Camera Data name"},
+ {"setType", ( PyCFunction ) Camera_oldsetType, METH_O,
+ "(s) - Set Camera type, which can be 'persp' or 'ortho'"},
+ {"setMode", ( PyCFunction ) Camera_oldsetMode, METH_VARARGS,
+ "(<s<,s>>) - Set Camera mode flag(s): 'showLimits' and 'showMist'"},
+ {"setLens", ( PyCFunction ) Camera_oldsetLens, METH_O,
+ "(f) - Set *perpective* Camera lens value"},
+ {"setScale", ( PyCFunction ) Camera_oldsetScale, METH_O,
+ "(f) - Set *ortho* Camera scale value"},
+ {"setClipStart", ( PyCFunction ) Camera_oldsetClipStart, METH_O,
+ "(f) - Set Camera clip start value"},
+ {"setClipEnd", ( PyCFunction ) Camera_oldsetClipEnd, METH_O,
+ "(f) - Set Camera clip end value"},
+ {"setDrawSize", ( PyCFunction ) Camera_oldsetDrawSize, METH_O,
+ "(f) - Set Camera draw size value"},
+ {"getScriptLinks", ( PyCFunction ) Camera_oldgetScriptLinks, METH_O,
+ "(eventname) - Get a list of this camera's scriptlinks (Text names) "
+ "of the given type\n"
+ "(eventname) - string: FrameChanged, Redraw or Render."},
+ {"addScriptLink", ( PyCFunction ) Camera_addScriptLink, METH_VARARGS,
+ "(text, evt) - Add a new camera scriptlink.\n"
+ "(text) - string: an existing Blender Text name;\n"
+ "(evt) string: FrameChanged, Redraw or Render."},
+ {"clearScriptLinks", ( PyCFunction ) Camera_clearScriptLinks,
+ METH_NOARGS,
+ "() - Delete all scriptlinks from this camera.\n"
+ "([s1<,s2,s3...>]) - Delete specified scriptlinks from this camera."},
+ {"__copy__", ( PyCFunction ) Camera_copy, METH_NOARGS,
+ "() - Return a copy of the camera."},
+ {"copy", ( PyCFunction ) Camera_copy, METH_NOARGS,
+ "() - Return a copy of the camera."},
+ {NULL, NULL, 0, NULL}
+};
+
+/*****************************************************************************/
+/* Python Camera_Type callback function prototypes: */
+/*****************************************************************************/
+static int Camera_compare( BPy_Camera * a, BPy_Camera * b );
+static PyObject *Camera_repr( BPy_Camera * self );
+
+static PyObject *M_Camera_New( PyObject * self, PyObject * args,
+ PyObject * kwords )
+{
+ char *type_str = "persp"; /* "persp" is type 0, "ortho" is type 1 */
+ char *name_str = "Camera";
+ static char *kwlist[] = { "type_str", "name_str", NULL };
+ PyObject *pycam; /* for Camera Data object wrapper in Python */
+ Camera *blcam; /* for actual Camera Data we create in Blender */
+
+ /* Parse the arguments passed in by the Python interpreter */
+ if( !PyArg_ParseTupleAndKeywords( args, kwords, "|ss", kwlist,
+ &type_str, &name_str ) )
+ /* We expected string(s) (or nothing) as argument, but we didn't get that. */
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected zero, one or two strings as arguments" );
+
+ blcam = add_camera( name_str ); /* first create the Camera Data in Blender */
+
+ if( blcam ) /* now create the wrapper obj in Python */
+ pycam = Camera_CreatePyObject( blcam );
+ else
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't create Camera Data in Blender" );
+
+ /* let's return user count to zero, because ... */
+ blcam->id.us = 0; /* ... add_camera() incref'ed it */
+ /* XXX XXX Do this in other modules, too */
+
+ if( pycam == NULL )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create Camera PyObject" );
+
+ if( strcmp( type_str, "persp" ) == 0 )
+ /* default, no need to set, so */
+ /*blcam->type = (short)EXPP_CAM_TYPE_PERSP */
+ ;
+ /* we comment this line */
+ else if( strcmp( type_str, "ortho" ) == 0 )
+ blcam->type = ( short ) EXPP_CAM_TYPE_ORTHO;
+ else
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "unknown camera type" );
+
+ return pycam;
+}
+
+static PyObject *M_Camera_Get( PyObject * self, PyObject * args )
+{
+ char *name = NULL;
+ Camera *cam_iter;
+
+ if( !PyArg_ParseTuple( args, "|s", &name ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument (or nothing)" );
+
+ cam_iter = G.main->camera.first;
+
+ if( name ) { /* (name) - Search camera by name */
+
+ PyObject *wanted_cam = NULL;
+
+ while( cam_iter && !wanted_cam ) {
+
+ if( strcmp( name, cam_iter->id.name + 2 ) == 0 ) {
+ wanted_cam = Camera_CreatePyObject( cam_iter );
+ break;
+ }
+
+ cam_iter = cam_iter->id.next;
+ }
+
+ if( !wanted_cam ) { /* Requested camera doesn't exist */
+ char error_msg[64];
+ PyOS_snprintf( error_msg, sizeof( error_msg ),
+ "Camera \"%s\" not found", name );
+ return EXPP_ReturnPyObjError( PyExc_NameError,
+ error_msg );
+ }
+
+ return wanted_cam;
+ }
+
+ else { /* () - return a list of wrappers for all cameras in the scene */
+ int index = 0;
+ PyObject *cam_pylist, *pyobj;
+
+ cam_pylist =
+ PyList_New( BLI_countlist( &( G.main->camera ) ) );
+
+ if( !cam_pylist )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create PyList" );
+
+ while( cam_iter ) {
+ pyobj = Camera_CreatePyObject( cam_iter );
+
+ if( !pyobj ) {
+ Py_DECREF(cam_pylist);
+ return EXPP_ReturnPyObjError
+ ( PyExc_MemoryError,
+ "couldn't create Camera PyObject" );
+ }
+ PyList_SET_ITEM( cam_pylist, index, pyobj );
+
+ cam_iter = cam_iter->id.next;
+ index++;
+ }
+
+ return cam_pylist;
+ }
+}
+
+PyObject *Camera_Init( void )
+{
+ PyObject *submodule;
+
+ if( PyType_Ready( &Camera_Type ) < 0 )
+ return NULL;
+
+ submodule = Py_InitModule3( "Blender.Camera",
+ M_Camera_methods, M_Camera_doc );
+
+ PyModule_AddIntConstant( submodule, "LENS", IPOKEY_LENS );
+ PyModule_AddIntConstant( submodule, "CLIPPING", IPOKEY_CLIPPING );
+
+ return submodule;
+}
+
+/* Three Python Camera_Type helper functions needed by the Object module: */
+
+PyObject *Camera_CreatePyObject( Camera * cam )
+{
+ BPy_Camera *pycam;
+
+ pycam = ( BPy_Camera * ) PyObject_NEW( BPy_Camera, &Camera_Type );
+
+ if( !pycam )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create BPy_Camera PyObject" );
+
+ pycam->camera = cam;
+ return ( PyObject * ) pycam;
+}
+
+Camera *Camera_FromPyObject( PyObject * pyobj )
+{
+ return ( ( BPy_Camera * ) pyobj )->camera;
+}
+
+/*****************************************************************************/
+/* Python BPy_Camera methods: */
+/*****************************************************************************/
+
+static PyObject *Camera_oldgetType( BPy_Camera * self )
+{
+ return PyInt_FromLong( self->camera->type );
+}
+
+static PyObject *Camera_oldgetMode( BPy_Camera * self )
+{
+ return PyInt_FromLong( self->camera->flag );
+}
+
+static PyObject *Camera_oldgetLens( BPy_Camera * self )
+{
+ return PyFloat_FromDouble( self->camera->lens );
+}
+
+static PyObject *Camera_oldgetScale( BPy_Camera * self )
+{
+ return PyFloat_FromDouble( self->camera->ortho_scale );
+}
+
+static PyObject *Camera_oldgetClipStart( BPy_Camera * self )
+{
+ return PyFloat_FromDouble( self->camera->clipsta );
+}
+
+static PyObject *Camera_oldgetClipEnd( BPy_Camera * self )
+{
+ return PyFloat_FromDouble( self->camera->clipend );
+}
+
+static PyObject *Camera_oldgetDrawSize( BPy_Camera * self )
+{
+ return PyFloat_FromDouble( self->camera->drawsize );
+}
+
+
+
+static PyObject *Camera_oldsetIpo( BPy_Camera * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Camera_setIpo );
+}
+
+static PyObject *Camera_oldclearIpo( BPy_Camera * self )
+{
+ Camera *cam = self->camera;
+ Ipo *ipo = ( Ipo * ) cam->ipo;
+
+ if( ipo ) {
+ ID *id = &ipo->id;
+ if( id->us > 0 )
+ id->us--;
+ cam->ipo = NULL;
+
+ return EXPP_incr_ret_True();
+ }
+
+ return EXPP_incr_ret_False(); /* no ipo found */
+}
+
+static PyObject *Camera_oldsetType( BPy_Camera * self, PyObject * value )
+{
+ char *type = PyString_AsString(value);
+
+ if(!value)
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument" );
+
+ if( strcmp( type, "persp" ) == 0 )
+ self->camera->type = ( short ) EXPP_CAM_TYPE_PERSP;
+ else if( strcmp( type, "ortho" ) == 0 )
+ self->camera->type = ( short ) EXPP_CAM_TYPE_ORTHO;
+ else
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "unknown camera type" );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Camera_oldsetMode( BPy_Camera * self, PyObject * args )
+{
+ char *mode_str1 = NULL, *mode_str2 = NULL;
+ short flag = 0;
+
+ if( !PyArg_ParseTuple( args, "|ss", &mode_str1, &mode_str2 ) )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected one or two strings as arguments" );
+
+ if( mode_str1 != NULL ) {
+ if( strcmp( mode_str1, "showLimits" ) == 0 )
+ flag |= ( short ) EXPP_CAM_MODE_SHOWLIMITS;
+ else if( strcmp( mode_str1, "showMist" ) == 0 )
+ flag |= ( short ) EXPP_CAM_MODE_SHOWMIST;
+ else
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "first argument is an unknown camera flag" );
+
+ if( mode_str2 != NULL ) {
+ if( strcmp( mode_str2, "showLimits" ) == 0 )
+ flag |= ( short ) EXPP_CAM_MODE_SHOWLIMITS;
+ else if( strcmp( mode_str2, "showMist" ) == 0 )
+ flag |= ( short ) EXPP_CAM_MODE_SHOWMIST;
+ else
+ return EXPP_ReturnPyObjError
+ ( PyExc_AttributeError,
+ "second argument is an unknown camera flag" );
+ }
+ }
+
+ self->camera->flag = flag;
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Camera_oldsetLens( BPy_Camera * self, PyObject * value )
+{
+ float param = PyFloat_AsDouble(value);
+
+ if( !PyFloat_Check(value) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected float argument" );
+
+ self->camera->lens = EXPP_ClampFloat( param,
+ EXPP_CAM_LENS_MIN,
+ EXPP_CAM_LENS_MAX );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Camera_oldsetScale( BPy_Camera * self, PyObject * value )
+{
+ float param = PyFloat_AsDouble(value);
+
+ if( !PyFloat_Check(value) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected float argument" );
+
+ self->camera->ortho_scale = EXPP_ClampFloat( param,
+ EXPP_CAM_SCALE_MIN,
+ EXPP_CAM_SCALE_MAX );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Camera_oldsetClipStart( BPy_Camera * self, PyObject * value )
+{
+ float param = PyFloat_AsDouble(value);
+
+ if( !PyFloat_Check(value) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected float argument" );
+
+ self->camera->clipsta = EXPP_ClampFloat( param,
+ EXPP_CAM_CLIPSTART_MIN,
+ EXPP_CAM_CLIPSTART_MAX );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Camera_oldsetClipEnd( BPy_Camera * self, PyObject * value )
+{
+ float param = PyFloat_AsDouble(value);
+
+ if( !PyFloat_Check(value) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected float argument" );
+
+ self->camera->clipend = EXPP_ClampFloat( param,
+ EXPP_CAM_CLIPEND_MIN,
+ EXPP_CAM_CLIPEND_MAX );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Camera_oldsetDrawSize( BPy_Camera * self, PyObject * value )
+{
+ float param = PyFloat_AsDouble(value);
+
+ if( !PyFloat_Check(value) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected float argument" );
+
+ self->camera->drawsize = EXPP_ClampFloat( param,
+ EXPP_CAM_DRAWSIZE_MIN,
+ EXPP_CAM_DRAWSIZE_MAX );
+
+ Py_RETURN_NONE;
+}
+
+/* cam.addScriptLink */
+static PyObject *Camera_addScriptLink( BPy_Camera * self, PyObject * args )
+{
+ Camera *cam = self->camera;
+ ScriptLink *slink = NULL;
+
+ slink = &( cam )->scriptlink;
+
+ return EXPP_addScriptLink( slink, args, 0 );
+}
+
+/* cam.clearScriptLinks */
+static PyObject *Camera_clearScriptLinks( BPy_Camera * self, PyObject * args )
+{
+ Camera *cam = self->camera;
+ ScriptLink *slink = NULL;
+
+ slink = &( cam )->scriptlink;
+
+ return EXPP_clearScriptLinks( slink, args );
+}
+
+/* cam.getScriptLinks */
+static PyObject *Camera_oldgetScriptLinks( BPy_Camera * self, PyObject * value )
+{
+ Camera *cam = self->camera;
+ ScriptLink *slink = NULL;
+ PyObject *ret = NULL;
+
+ slink = &( cam )->scriptlink;
+
+ ret = EXPP_getScriptLinks( slink, value, 0 );
+
+ if( ret )
+ return ret;
+ else
+ return NULL;
+}
+
+/* cam.__copy__ */
+static PyObject *Camera_copy( BPy_Camera * self )
+{
+ PyObject *pycam; /* for Camera Data object wrapper in Python */
+ Camera *blcam; /* for actual Camera Data we create in Blender */
+
+ blcam = copy_camera( self->camera ); /* first create the Camera Data in Blender */
+
+ if( blcam ) /* now create the wrapper obj in Python */
+ pycam = Camera_CreatePyObject( blcam );
+ else
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't create Camera Data in Blender" );
+
+ /* let's return user count to zero, because ... */
+ blcam->id.us = 0; /* ... copy_camera() incref'ed it */
+ /* XXX XXX Do this in other modules, too */
+
+ if( pycam == NULL )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create Camera PyObject" );
+
+ return pycam;
+}
+
+static PyObject *Camera_getType( BPy_Camera * self )
+{
+ if (self->camera->type == EXPP_CAM_TYPE_PERSP)
+ return PyString_FromString("persp");
+ else /* must be EXPP_CAM_TYPE_ORTHO */
+ return PyString_FromString("ortho");
+}
+
+static int Camera_setType( BPy_Camera * self, PyObject * value )
+{
+ char *type = NULL;
+ type = PyString_AsString(value);
+
+ if (!type)
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "expected a string" );
+ if (strcmp("persp", type)==0) {
+ self->camera->type = EXPP_CAM_TYPE_PERSP;
+ return 0;
+ } else if (strcmp("ortho", type)==0) {
+ self->camera->type = EXPP_CAM_TYPE_ORTHO;
+ return 0;
+ }
+
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "expected a string \"ortho\" or \"persp\"" );
+}
+
+
+
+static PyObject *Camera_getMode( BPy_Camera * self )
+{
+ return PyInt_FromLong(self->camera->flag);
+}
+
+static int Camera_setMode( BPy_Camera * self, PyObject * value )
+{
+ unsigned int flag = 0;
+
+ if( !PyInt_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected an integer (bitmask) as argument" );
+
+ flag = ( unsigned int )PyInt_AS_LONG( value );
+
+ self->camera->flag = flag;
+ return 0;
+}
+
+static PyObject *Camera_getIpo( BPy_Camera * self )
+{
+ struct Ipo *ipo = self->camera->ipo;
+
+ if( ipo )
+ return Ipo_CreatePyObject( ipo );
+ Py_RETURN_NONE;
+}
+
+static int Camera_setIpo( BPy_Camera * self, PyObject * value )
+{
+ return GenericLib_assignData(value, (void **) &self->camera->ipo, 0, 1, ID_IP, ID_CA);
+}
+
+/*
+ * get floating point attributes
+ */
+
+static PyObject *getFloatAttr( BPy_Camera *self, void *type )
+{
+ float param;
+ struct Camera *cam= self->camera;
+
+ switch( (int)type ) {
+ case EXPP_CAM_ATTR_LENS:
+ param = cam->lens;
+ break;
+ case EXPP_CAM_ATTR_ANGLE:
+ param = 360.0f * atan(16.0f/cam->lens) / M_PI;
+ break;
+ case EXPP_CAM_ATTR_DOFDIST:
+ param = cam->YF_dofdist;
+ break;
+ case EXPP_CAM_ATTR_CLIPSTART:
+ param = cam->clipsta;
+ break;
+ case EXPP_CAM_ATTR_CLIPEND:
+ param = cam->clipend;
+ break;
+ case EXPP_CAM_ATTR_DRAWSIZE:
+ param = cam->drawsize;
+ break;
+ case EXPP_CAM_ATTR_SCALE:
+ param = cam->ortho_scale;
+ break;
+ case EXPP_CAM_ATTR_ALPHA:
+ param = cam->passepartalpha;
+ break;
+ case EXPP_CAM_ATTR_SHIFTX:
+ param = cam->shiftx;
+ break;
+ case EXPP_CAM_ATTR_SHIFTY:
+ param = cam->shifty;
+ break;
+
+ default:
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "undefined type in getFloatAttr" );
+ }
+
+ return PyFloat_FromDouble( param );
+}
+
+
+
+/*
+ * set floating point attributes which require clamping
+ */
+
+static int setFloatAttrClamp( BPy_Camera *self, PyObject *value, void *type )
+{
+ float *param;
+ struct Camera *cam = self->camera;
+ float min, max;
+ int ret;
+
+ switch( (int)type ) {
+ case EXPP_CAM_ATTR_LENS:
+ min = 1.0;
+ max = 250.0;
+ param = &cam->lens;
+ break;
+ case EXPP_CAM_ATTR_ANGLE:
+ min = 7.323871;
+ max = 172.847331;
+ param = &cam->lens;
+ break;
+ case EXPP_CAM_ATTR_DOFDIST:
+ min = 0.0;
+ max = 5000.0;
+ param = &cam->YF_dofdist;
+ break;
+ case EXPP_CAM_ATTR_CLIPSTART:
+ min = 0.0;
+ max = 100.0;
+ param = &cam->clipsta;
+ break;
+ case EXPP_CAM_ATTR_CLIPEND:
+ min = 1.0;
+ max = 5000.0;
+ param = &cam->clipend;
+ break;
+ case EXPP_CAM_ATTR_DRAWSIZE:
+ min = 0.1f;
+ max = 10.0;
+ param = &cam->drawsize;
+ break;
+ case EXPP_CAM_ATTR_SCALE:
+ min = 0.01f;
+ max = 1000.0;
+ param = &cam->ortho_scale;
+ break;
+ case EXPP_CAM_ATTR_ALPHA:
+ min = 0.0;
+ max = 1.0;
+ param = &cam->passepartalpha;
+ break;
+ case EXPP_CAM_ATTR_SHIFTX:
+ min = -2.0;
+ max = 2.0;
+ param = &cam->shiftx;
+ break;
+ case EXPP_CAM_ATTR_SHIFTY:
+ min = -2.0;
+ max = 2.0;
+ param = &cam->shifty;
+ break;
+
+ default:
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "undefined type in setFloatAttrClamp" );
+ }
+
+ ret = EXPP_setFloatClamped( value, param, min, max );
+
+ if (ret==0) {
+ if ((int)type == EXPP_CAM_ATTR_ANGLE) {
+ cam->lens = 16.0f / tan(M_PI*cam->lens/360.0f);
+ }
+ }
+ return ret;
+}
+
+
+/*
+ * get floating point attributes
+ */
+
+static PyObject *getFlagAttr( BPy_Camera *self, void *type )
+{
+ if (self->camera->flag & (int)type)
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+}
+
+/*
+ * set floating point attributes which require clamping
+ */
+
+static int setFlagAttr( BPy_Camera *self, PyObject *value, void *type )
+{
+ int param = PyObject_IsTrue( value );
+ if( param == -1 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected True/False or 0/1" );
+
+ if (param)
+ self->camera->flag |= (int)type;
+ else
+ self->camera->flag &= ~(int)type;
+ return 0;
+}
+
+
+/*****************************************************************************/
+/* Python attributes get/set structure: */
+/*****************************************************************************/
+static PyGetSetDef BPy_Camera_getseters[] = {
+ GENERIC_LIB_GETSETATTR,
+ {"type",
+ (getter)Camera_getType, (setter)Camera_setType,
+ "camera type \"persp\" or \"ortho\"",
+ NULL},
+ {"mode",
+ (getter)Camera_getMode, (setter)Camera_setMode,
+ "Cameras mode",
+ NULL},
+ {"ipo",
+ (getter)Camera_getIpo, (setter)Camera_setIpo,
+ "Cameras ipo",
+ NULL},
+
+ /* float settings */
+ {"lens",
+ (getter)getFloatAttr, (setter)setFloatAttrClamp,
+ "lens angle for perspective cameras",
+ (void *)EXPP_CAM_ATTR_LENS},
+ {"angle",
+ (getter)getFloatAttr, (setter)setFloatAttrClamp,
+ "lens angle for perspective cameras",
+ (void *)EXPP_CAM_ATTR_ANGLE},
+
+ {"scale",
+ (getter)getFloatAttr, (setter)setFloatAttrClamp,
+ "scale for ortho cameras",
+ (void *)EXPP_CAM_ATTR_SCALE},
+ {"clipStart",
+ (getter)getFloatAttr, (setter)setFloatAttrClamp,
+ "the cameras clip start",
+ (void *)EXPP_CAM_ATTR_CLIPSTART},
+ {"clipEnd",
+ (getter)getFloatAttr, (setter)setFloatAttrClamp,
+ "the cameras clip end",
+ (void *)EXPP_CAM_ATTR_CLIPEND},
+ {"shiftX",
+ (getter)getFloatAttr, (setter)setFloatAttrClamp,
+ "the cameras X perspective shift",
+ (void *)EXPP_CAM_ATTR_SHIFTX},
+ {"shiftY",
+ (getter)getFloatAttr, (setter)setFloatAttrClamp,
+ "the cameras Y perspective shift",
+ (void *)EXPP_CAM_ATTR_SHIFTY},
+ {"dofDist",
+ (getter)getFloatAttr, (setter)setFloatAttrClamp,
+ "cameras dof distance",
+ (void *)EXPP_CAM_ATTR_DOFDIST},
+ {"drawSize",
+ (getter)getFloatAttr, (setter)setFloatAttrClamp,
+ "the cameras display size",
+ (void *)EXPP_CAM_ATTR_DRAWSIZE},
+ {"alpha",
+ (getter)getFloatAttr, (setter)setFloatAttrClamp,
+ "passepart alpha value for display",
+ (void *)EXPP_CAM_ATTR_ALPHA},
+
+ /* flags - use flags as defined in DNA_camera_types.h */
+ {"drawLimits",
+ (getter)getFlagAttr, (setter)setFlagAttr,
+ "toggle the draw limits display flag",
+ (void *)CAM_SHOWLIMITS},
+ {"drawMist",
+ (getter)getFlagAttr, (setter)setFlagAttr,
+ "toggle the draw mist display flag",
+ (void *)CAM_SHOWMIST},
+ {"drawName",
+ (getter)getFlagAttr, (setter)setFlagAttr,
+ "toggle the draw name display flag",
+ (void *)CAM_SHOWNAME},
+ {"drawTileSafe",
+ (getter)getFlagAttr, (setter)setFlagAttr,
+ "toggle the tile safe display flag",
+ (void *)CAM_SHOWTITLESAFE},
+ {"drawPassepartout",
+ (getter)getFlagAttr, (setter)setFlagAttr,
+ "toggle the passPartOut display flag",
+ (void *)CAM_SHOWPASSEPARTOUT},
+ {"angleToggle",
+ (getter)getFlagAttr, (setter)setFlagAttr,
+ "toggle the camera input unit flag",
+ (void *)CAM_ANGLETOGGLE},
+ {NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+
+/*****************************************************************************/
+/* Python Camera_Type structure definition: */
+/*****************************************************************************/
+PyTypeObject Camera_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender Camera", /* char *tp_name; */
+ sizeof( BPy_Camera ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ NULL, /* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ ( cmpfunc ) Camera_compare, /* cmpfunc tp_compare; */
+ ( reprfunc ) Camera_repr, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_Camera_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ BPy_Camera_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+
+
+static int Camera_compare( BPy_Camera * a, BPy_Camera * b )
+{
+ Camera *pa = a->camera, *pb = b->camera;
+ return ( pa == pb ) ? 0 : -1;
+}
+
+static PyObject *Camera_repr( BPy_Camera * self )
+{
+ return PyString_FromFormat( "[Camera \"%s\"]",
+ self->camera->id.name + 2 );
+}
+
+/*
+ * Camera_insertIpoKey()
+ * inserts Camera IPO key for LENS and CLIPPING
+ */
+
+static PyObject *Camera_insertIpoKey( BPy_Camera * self, PyObject * args )
+{
+ int key = 0;
+
+ if( !PyArg_ParseTuple( args, "i", &( key ) ) )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected int argument" ) );
+
+ if (key == IPOKEY_LENS){
+ insertkey((ID *)self->camera, ID_CA, NULL, NULL, CAM_LENS, 0);
+ }
+ else if (key == IPOKEY_CLIPPING){
+ insertkey((ID *)self->camera, ID_CA, NULL, NULL, CAM_STA, 0);
+ insertkey((ID *)self->camera, ID_CA, NULL, NULL, CAM_END, 0);
+ }
+
+ allspace(REMAKEIPO, 0);
+ EXPP_allqueue(REDRAWIPO, 0);
+ EXPP_allqueue(REDRAWVIEW3D, 0);
+ EXPP_allqueue(REDRAWACTION, 0);
+ EXPP_allqueue(REDRAWNLA, 0);
+
+ Py_RETURN_NONE;
+}
diff --git a/source/blender/python/api2_2x/Camera.h b/source/blender/python/api2_2x/Camera.h
new file mode 100644
index 00000000000..c92e51c1468
--- /dev/null
+++ b/source/blender/python/api2_2x/Camera.h
@@ -0,0 +1,82 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_CAMERA_H
+#define EXPP_CAMERA_H
+
+#include <Python.h>
+#include "DNA_camera_types.h"
+
+extern PyTypeObject Camera_Type;
+
+#define BPy_Camera_Check(v) \
+ ((v)->ob_type == &Camera_Type) /* for type checking */
+
+/* Python BPy_Camera structure definition */
+typedef struct {
+ PyObject_HEAD /* required py macro */
+ Camera * camera;
+
+} BPy_Camera;
+
+/*****************************************************************************/
+/* Python BPy_Camera defaults: */
+/*****************************************************************************/
+
+/* Camera types */
+
+#define EXPP_CAM_TYPE_PERSP 0
+#define EXPP_CAM_TYPE_ORTHO 1
+
+/* Camera mode flags */
+
+#define EXPP_CAM_MODE_SHOWLIMITS 1
+#define EXPP_CAM_MODE_SHOWMIST 2
+
+/* Camera MIN, MAX values */
+
+#define EXPP_CAM_LENS_MIN 1.0
+#define EXPP_CAM_LENS_MAX 250.0
+#define EXPP_CAM_SCALE_MIN 0.01f
+#define EXPP_CAM_SCALE_MAX 1000.0
+#define EXPP_CAM_CLIPSTART_MIN 0.0
+#define EXPP_CAM_CLIPSTART_MAX 100.0
+#define EXPP_CAM_CLIPEND_MIN 1.0
+#define EXPP_CAM_CLIPEND_MAX 5000.0
+#define EXPP_CAM_DRAWSIZE_MIN 0.1f
+#define EXPP_CAM_DRAWSIZE_MAX 10.0
+
+PyObject *Camera_Init( void );
+PyObject *Camera_CreatePyObject( Camera * cam );
+Camera *Camera_FromPyObject( PyObject * pyobj );
+
+#endif /* EXPP_CAMERA_H */
diff --git a/source/blender/python/api2_2x/Constraint.c b/source/blender/python/api2_2x/Constraint.c
new file mode 100644
index 00000000000..1836c0c6bc2
--- /dev/null
+++ b/source/blender/python/api2_2x/Constraint.c
@@ -0,0 +1,2678 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Joseph Gilbert, Ken Hughes, Joshua Leung
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "Constraint.h" /*This must come first*/
+
+#include "DNA_object_types.h"
+#include "DNA_effect_types.h"
+#include "DNA_vec_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_text_types.h"
+
+#include "BKE_main.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_constraint.h"
+#include "BLI_blenlib.h"
+#include "BIF_editconstraint.h"
+#include "BSE_editipo.h"
+#include "MEM_guardedalloc.h"
+#include "butspace.h"
+#include "blendef.h"
+#include "mydevice.h"
+
+#include "IDProp.h"
+#include "Object.h"
+#include "NLA.h"
+#include "Text.h"
+#include "gen_utils.h"
+
+enum constraint_constants {
+ EXPP_CONSTR_XROT = 0,
+ EXPP_CONSTR_YROT = 1,
+ EXPP_CONSTR_ZROT = 2,
+ EXPP_CONSTR_XSIZE = 10,
+ EXPP_CONSTR_YSIZE = 11,
+ EXPP_CONSTR_ZSIZE = 12,
+ EXPP_CONSTR_XLOC = 20,
+ EXPP_CONSTR_YLOC = 21,
+ EXPP_CONSTR_ZLOC = 22,
+
+ EXPP_CONSTR_MAXX = TRACK_X,
+ EXPP_CONSTR_MAXY = TRACK_Y,
+ EXPP_CONSTR_MAXZ = TRACK_Z,
+ EXPP_CONSTR_MINX = TRACK_nX,
+ EXPP_CONSTR_MINY = TRACK_nY,
+ EXPP_CONSTR_MINZ = TRACK_nZ,
+
+ EXPP_CONSTR_TARGET = 100,
+ EXPP_CONSTR_STRETCH,
+ EXPP_CONSTR_ITERATIONS,
+ EXPP_CONSTR_BONE,
+ EXPP_CONSTR_CHAINLEN,
+ EXPP_CONSTR_POSWEIGHT,
+ EXPP_CONSTR_ROTWEIGHT,
+ EXPP_CONSTR_ROTATE,
+ EXPP_CONSTR_USETIP,
+
+ EXPP_CONSTR_ACTION,
+ EXPP_CONSTR_START,
+ EXPP_CONSTR_END,
+ EXPP_CONSTR_MIN,
+ EXPP_CONSTR_MAX,
+ EXPP_CONSTR_KEYON,
+
+ EXPP_CONSTR_TRACK,
+ EXPP_CONSTR_UP,
+
+ EXPP_CONSTR_RESTLENGTH,
+ EXPP_CONSTR_VOLVARIATION,
+ EXPP_CONSTR_VOLUMEMODE,
+ EXPP_CONSTR_PLANE,
+
+ EXPP_CONSTR_FOLLOW,
+ EXPP_CONSTR_OFFSET,
+ EXPP_CONSTR_FORWARD,
+
+ EXPP_CONSTR_LOCK,
+
+ EXPP_CONSTR_MINMAX,
+ EXPP_CONSTR_STICKY,
+
+ EXPP_CONSTR_COPY,
+ EXPP_CONSTR_LIMIT,
+ EXPP_CONSTR_CLAMP,
+
+ EXPP_CONSTR_LIMXMIN = LIMIT_XMIN,
+ EXPP_CONSTR_LIMXMAX = LIMIT_XMAX,
+ EXPP_CONSTR_LIMYMIN = LIMIT_YMIN,
+ EXPP_CONSTR_LIMYMAX = LIMIT_YMAX,
+ EXPP_CONSTR_LIMZMIN = LIMIT_ZMIN,
+ EXPP_CONSTR_LIMZMAX = LIMIT_ZMAX,
+
+ EXPP_CONSTR_LIMXROT = LIMIT_XROT,
+ EXPP_CONSTR_LIMYROT = LIMIT_YROT,
+ EXPP_CONSTR_LIMZROT = LIMIT_ZROT,
+
+ EXPP_CONSTR_CLAMPCYCLIC,
+
+ EXPP_CONSTR_XMIN,
+ EXPP_CONSTR_XMAX,
+ EXPP_CONSTR_YMIN,
+ EXPP_CONSTR_YMAX,
+ EXPP_CONSTR_ZMIN,
+ EXPP_CONSTR_ZMAX,
+
+ EXPP_CONSTR_SCRIPT,
+ EXPP_CONSTR_PROPS,
+
+ EXPP_CONSTR_FROM,
+ EXPP_CONSTR_TO,
+ EXPP_CONSTR_EXPO,
+ EXPP_CONSTR_FROMMINX,
+ EXPP_CONSTR_FROMMAXX,
+ EXPP_CONSTR_FROMMINY,
+ EXPP_CONSTR_FROMMAXY,
+ EXPP_CONSTR_FROMMINZ,
+ EXPP_CONSTR_FROMMAXZ,
+ EXPP_CONSTR_TOMINX,
+ EXPP_CONSTR_TOMAXX,
+ EXPP_CONSTR_TOMINY,
+ EXPP_CONSTR_TOMAXY,
+ EXPP_CONSTR_TOMINZ,
+ EXPP_CONSTR_TOMAXZ,
+ EXPP_CONSTR_MAPX,
+ EXPP_CONSTR_MAPY,
+ EXPP_CONSTR_MAPZ,
+
+ EXPP_CONSTR_OWNSPACE,
+ EXPP_CONSTR_TARSPACE,
+
+ EXPP_CONSTR_RB_TYPE,
+ EXPP_CONSTR_RB_BALL,
+ EXPP_CONSTR_RB_HINGE,
+ EXPP_CONSTR_RB_GENERIC6DOF,
+ EXPP_CONSTR_RB_VEHICLE,
+ EXPP_CONSTR_RB_PIVX,
+ EXPP_CONSTR_RB_PIVY,
+ EXPP_CONSTR_RB_PIVZ,
+ EXPP_CONSTR_RB_AXX,
+ EXPP_CONSTR_RB_AXY,
+ EXPP_CONSTR_RB_AXZ,
+ EXPP_CONSTR_RB_MINLIMIT0,
+ EXPP_CONSTR_RB_MINLIMIT1,
+ EXPP_CONSTR_RB_MINLIMIT2,
+ EXPP_CONSTR_RB_MINLIMIT3,
+ EXPP_CONSTR_RB_MINLIMIT4,
+ EXPP_CONSTR_RB_MINLIMIT5,
+ EXPP_CONSTR_RB_MAXLIMIT0,
+ EXPP_CONSTR_RB_MAXLIMIT1,
+ EXPP_CONSTR_RB_MAXLIMIT2,
+ EXPP_CONSTR_RB_MAXLIMIT3,
+ EXPP_CONSTR_RB_MAXLIMIT4,
+ EXPP_CONSTR_RB_MAXLIMIT5,
+ EXPP_CONSTR_RB_EXTRAFZ,
+ EXPP_CONSTR_RB_FLAG,
+
+};
+
+/*****************************************************************************/
+/* Python BPy_Constraint methods declarations: */
+/*****************************************************************************/
+static PyObject *Constraint_getName( BPy_Constraint * self );
+static int Constraint_setName( BPy_Constraint * self, PyObject *arg );
+static PyObject *Constraint_getType( BPy_Constraint * self );
+static PyObject *Constraint_getInfluence( BPy_Constraint * self );
+static int Constraint_setInfluence( BPy_Constraint * self, PyObject * arg );
+
+static PyObject *Constraint_insertKey( BPy_Constraint * self, PyObject * arg );
+
+static PyObject *Constraint_getData( BPy_Constraint * self, PyObject * key );
+static int Constraint_setData( BPy_Constraint * self, PyObject * key,
+ PyObject * value );
+
+/*****************************************************************************/
+/* Python BPy_Constraint methods table: */
+/*****************************************************************************/
+static PyMethodDef BPy_Constraint_methods[] = {
+ /* name, method, flags, doc */
+ {"insertKey", ( PyCFunction ) Constraint_insertKey, METH_O,
+ "Insert influence keyframe for constraint"},
+ {NULL, NULL, 0, NULL}
+};
+
+/*****************************************************************************/
+/* Python BPy_Constraint attributes get/set structure: */
+/*****************************************************************************/
+static PyGetSetDef BPy_Constraint_getseters[] = {
+ {"name",
+ (getter)Constraint_getName, (setter)Constraint_setName,
+ "Constraint name", NULL},
+ {"type",
+ (getter)Constraint_getType, (setter)NULL,
+ "Constraint type (read only)", NULL},
+ {"influence",
+ (getter)Constraint_getInfluence, (setter)Constraint_setInfluence,
+ "Constraint influence", NULL},
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+/*****************************************************************************/
+/* Python Constraint_Type Mapping Methods table: */
+/*****************************************************************************/
+static PyMappingMethods Constraint_as_mapping = {
+ NULL, /* mp_length */
+ ( binaryfunc ) Constraint_getData, /* mp_subscript */
+ ( objobjargproc ) Constraint_setData, /* mp_ass_subscript */
+};
+
+/*****************************************************************************/
+/* Python Constraint_Type callback function prototypes: */
+/*****************************************************************************/
+static PyObject *Constraint_repr( BPy_Constraint * self );
+static int Constraint_compare( BPy_Constraint * a, BPy_Constraint * b );
+
+/*****************************************************************************/
+/* Python Constraint_Type structure definition: */
+/*****************************************************************************/
+PyTypeObject Constraint_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender Constraint", /* char *tp_name; */
+ sizeof( BPy_Constraint ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ NULL, /* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ ( cmpfunc ) Constraint_compare, /* cmpfunc tp_compare; */
+ ( reprfunc ) Constraint_repr, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ &Constraint_as_mapping, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_Constraint_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ BPy_Constraint_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+/*****************************************************************************/
+/* Python BPy_Constraint methods: */
+/*****************************************************************************/
+
+/*
+ * return the name of this constraint
+ */
+
+static PyObject *Constraint_getName( BPy_Constraint * self )
+{
+ if( !self->con )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "This constraint has been removed!" );
+
+ return PyString_FromString( self->con->name );
+}
+
+/*
+ * set the name of this constraint
+ */
+
+static int Constraint_setName( BPy_Constraint * self, PyObject * attr )
+{
+ char *name = PyString_AsString( attr );
+ if( !name )
+ return EXPP_ReturnIntError( PyExc_TypeError, "expected string arg" );
+
+ if( !self->con )
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "This constraint has been removed!" );
+
+ BLI_strncpy( self->con->name, name, sizeof( self->con->name ) );
+
+ return 0;
+}
+
+/*
+ * return the influence of this constraint
+ */
+
+static PyObject *Constraint_getInfluence( BPy_Constraint * self )
+{
+ if( !self->con )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "This constraint has been removed!" );
+
+ return PyFloat_FromDouble( (double)self->con->enforce );
+}
+
+/*
+ * set the influence of this constraint
+ */
+
+static int Constraint_setInfluence( BPy_Constraint * self, PyObject * value )
+{
+ if( !self->con )
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "This constraint has been removed!" );
+
+ return EXPP_setFloatClamped( value, &self->con->enforce, 0.0, 1.0 );
+}
+
+/*
+ * return the type of this constraint
+ */
+
+static PyObject *Constraint_getType( BPy_Constraint * self )
+{
+ if( !self->con )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "This constraint has been removed!" );
+
+ return PyInt_FromLong( self->con->type );
+}
+
+/*
+ * add keyframe for influence
+ base on code in add_influence_key_to_constraint_func()
+ */
+static PyObject *Constraint_insertKey( BPy_Constraint * self, PyObject * value )
+{
+ IpoCurve *icu;
+ float cfra = (float)PyFloat_AsDouble(value);
+ char actname[32] = "";
+ Object *ob = self->obj;
+ bConstraint *con = self->con;
+
+ if( !self->con )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "This constraint has been removed!" );
+
+ /* get frame for inserting key */
+ if( PyFloat_Check(value) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a float argument" );
+
+ /* constraint_active_func(ob_v, con_v); */
+ get_constraint_ipo_context( ob, actname );
+ icu= verify_ipocurve((ID *)ob, ID_CO, actname, con->name, CO_ENFORCE);
+
+ if (!icu)
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "cannot get a curve from this IPO, may be using libdata" );
+
+ if( ob->action )
+ insert_vert_icu( icu, get_action_frame(ob, cfra), con->enforce, 0);
+ else
+ insert_vert_icu( icu, cfra, con->enforce, 0);
+
+ Py_RETURN_NONE;
+}
+
+/******************************************************************************/
+/* Constraint Space Conversion get/set procedures */
+/* - These are called before/instead of individual constraint */
+/* get/set procedures when OWNERSPACE or TARGETSPACE are chosen */
+/* - They are only called from Constraint_g/setData */
+/******************************************************************************/
+
+static PyObject *constspace_getter( BPy_Constraint * self, int type )
+{
+ bConstraint *con= (bConstraint *)(self->con);
+
+ /* depends on type being asked for
+ * NOTE: not all constraints support all space types
+ */
+ if (type == EXPP_CONSTR_OWNSPACE) {
+ switch (con->type) {
+ /* all of these support this... */
+ case CONSTRAINT_TYPE_PYTHON:
+ case CONSTRAINT_TYPE_LOCLIKE:
+ case CONSTRAINT_TYPE_ROTLIKE:
+ case CONSTRAINT_TYPE_SIZELIKE:
+ case CONSTRAINT_TYPE_TRACKTO:
+ case CONSTRAINT_TYPE_LOCLIMIT:
+ case CONSTRAINT_TYPE_ROTLIMIT:
+ case CONSTRAINT_TYPE_SIZELIMIT:
+ case CONSTRAINT_TYPE_TRANSFORM:
+ return PyInt_FromLong( (long)con->ownspace );
+ }
+ }
+ else if (type == EXPP_CONSTR_TARSPACE) {
+ switch (con->type) {
+ /* all of these support this... */
+ case CONSTRAINT_TYPE_PYTHON:
+ case CONSTRAINT_TYPE_ACTION:
+ case CONSTRAINT_TYPE_LOCLIKE:
+ case CONSTRAINT_TYPE_ROTLIKE:
+ case CONSTRAINT_TYPE_SIZELIKE:
+ case CONSTRAINT_TYPE_TRACKTO:
+ case CONSTRAINT_TYPE_TRANSFORM:
+ return PyInt_FromLong( (long)con->tarspace );
+ }
+ }
+
+ /* raise error if failed */
+ return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
+}
+
+static int constspace_setter( BPy_Constraint *self, int type, PyObject *value )
+{
+ bConstraint *con= (bConstraint *)(self->con);
+
+ /* depends on type being asked for
+ * NOTE: not all constraints support all space types
+ */
+ if (type == EXPP_CONSTR_OWNSPACE) {
+ switch (con->type) {
+ /* all of these support this... */
+ case CONSTRAINT_TYPE_PYTHON:
+ case CONSTRAINT_TYPE_LOCLIKE:
+ case CONSTRAINT_TYPE_ROTLIKE:
+ case CONSTRAINT_TYPE_SIZELIKE:
+ case CONSTRAINT_TYPE_TRACKTO:
+ case CONSTRAINT_TYPE_LOCLIMIT:
+ case CONSTRAINT_TYPE_ROTLIMIT:
+ case CONSTRAINT_TYPE_SIZELIMIT:
+ case CONSTRAINT_TYPE_TRANSFORM:
+ {
+ /* only copy depending on ownertype */
+ if (self->pchan) {
+ return EXPP_setIValueClamped( value, &con->ownspace,
+ CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_PARLOCAL, 'h' );
+ }
+ else {
+ return EXPP_setIValueClamped( value, &con->ownspace,
+ CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, 'h' );
+ }
+ }
+ break;
+ }
+ }
+ else if (type == EXPP_CONSTR_TARSPACE) {
+ switch (con->type) {
+ /* all of these support this... */
+ case CONSTRAINT_TYPE_PYTHON:
+ case CONSTRAINT_TYPE_ACTION:
+ case CONSTRAINT_TYPE_LOCLIKE:
+ case CONSTRAINT_TYPE_ROTLIKE:
+ case CONSTRAINT_TYPE_SIZELIKE:
+ case CONSTRAINT_TYPE_TRACKTO:
+ case CONSTRAINT_TYPE_TRANSFORM:
+ {
+ Object *tar;
+ char *subtarget;
+
+ // FIXME!!!
+ //tar= get_constraint_target(con, &subtarget);
+ tar = NULL;
+ subtarget = NULL;
+
+ /* only copy depending on target-type */
+ if (tar && subtarget[0]) {
+ return EXPP_setIValueClamped( value, &con->tarspace,
+ CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_PARLOCAL, 'h' );
+ }
+ else if (tar) {
+ return EXPP_setIValueClamped( value, &con->tarspace,
+ CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL, 'h' );
+ }
+ }
+ break;
+ }
+ }
+
+ /* raise error if failed */
+ return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
+}
+
+/*****************************************************************************/
+/* Specific constraint get/set procedures */
+/*****************************************************************************/
+
+static PyObject *kinematic_getter( BPy_Constraint * self, int type )
+{
+ bKinematicConstraint *con = (bKinematicConstraint *)(self->con->data);
+
+ switch( type ) {
+ case EXPP_CONSTR_TARGET:
+ return Object_CreatePyObject( con->tar );
+ case EXPP_CONSTR_BONE:
+ return PyString_FromString( con->subtarget );
+ case EXPP_CONSTR_STRETCH:
+ return PyBool_FromLong( (long)( con->flag & CONSTRAINT_IK_STRETCH ) ) ;
+ case EXPP_CONSTR_ITERATIONS:
+ return PyInt_FromLong( (long)con->iterations );
+ case EXPP_CONSTR_CHAINLEN:
+ return PyInt_FromLong( (long)con->rootbone );
+ case EXPP_CONSTR_POSWEIGHT:
+ return PyFloat_FromDouble( (double)con->weight );
+ case EXPP_CONSTR_ROTWEIGHT:
+ return PyFloat_FromDouble( (double)con->orientweight );
+ case EXPP_CONSTR_ROTATE:
+ return PyBool_FromLong( (long)( con->flag & CONSTRAINT_IK_ROT ) ) ;
+ case EXPP_CONSTR_USETIP:
+ return PyBool_FromLong( (long)( con->flag & CONSTRAINT_IK_TIP ) ) ;
+ default:
+ return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static int kinematic_setter( BPy_Constraint *self, int type, PyObject *value )
+{
+ bKinematicConstraint *con = (bKinematicConstraint *)(self->con->data);
+
+ switch( type ) {
+ case EXPP_CONSTR_TARGET: {
+ Object *obj = (( BPy_Object * )value)->object;
+ if( !BPy_Object_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected BPy object argument" );
+ con->tar = obj;
+ return 0;
+ }
+ case EXPP_CONSTR_BONE: {
+ char *name = PyString_AsString( value );
+ if( !name )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected string arg" );
+
+ BLI_strncpy( con->subtarget, name, sizeof( con->subtarget ) );
+
+ return 0;
+ }
+ case EXPP_CONSTR_STRETCH:
+ return EXPP_setBitfield( value, &con->flag, CONSTRAINT_IK_STRETCH, 'h' );
+ case EXPP_CONSTR_ITERATIONS:
+ return EXPP_setIValueClamped( value, &con->iterations, 1, 10000, 'h' );
+ case EXPP_CONSTR_CHAINLEN:
+ return EXPP_setIValueClamped( value, &con->rootbone, 0, 255, 'i' );
+ case EXPP_CONSTR_POSWEIGHT:
+ return EXPP_setFloatClamped( value, &con->weight, 0.01f, 1.0 );
+ case EXPP_CONSTR_ROTWEIGHT:
+ return EXPP_setFloatClamped( value, &con->orientweight, 0.01f, 1.0 );
+ case EXPP_CONSTR_ROTATE:
+ return EXPP_setBitfield( value, &con->flag, CONSTRAINT_IK_ROT, 'h' );
+ case EXPP_CONSTR_USETIP:
+ return EXPP_setBitfield( value, &con->flag, CONSTRAINT_IK_TIP, 'h' );
+ default:
+ return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static PyObject *action_getter( BPy_Constraint * self, int type )
+{
+ bActionConstraint *con = (bActionConstraint *)(self->con->data);
+
+ switch( type ) {
+ case EXPP_CONSTR_TARGET:
+ return Object_CreatePyObject( con->tar );
+ case EXPP_CONSTR_BONE:
+ return PyString_FromString( con->subtarget );
+ case EXPP_CONSTR_ACTION:
+ return Action_CreatePyObject( con->act );
+ case EXPP_CONSTR_START:
+ return PyInt_FromLong( (long)con->start );
+ case EXPP_CONSTR_END:
+ return PyInt_FromLong( (long)con->end );
+ case EXPP_CONSTR_MIN:
+ return PyFloat_FromDouble( (double)con->min );
+ case EXPP_CONSTR_MAX:
+ return PyFloat_FromDouble( (double)con->max );
+ case EXPP_CONSTR_KEYON:
+ return PyInt_FromLong( (long)con->type );
+ default:
+ return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static int action_setter( BPy_Constraint *self, int type, PyObject *value )
+{
+ bActionConstraint *con = (bActionConstraint *)(self->con->data);
+
+ switch( type ) {
+ case EXPP_CONSTR_TARGET: {
+ Object *obj = (( BPy_Object * )value)->object;
+ if( !BPy_Object_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected BPy object argument" );
+ con->tar = obj;
+ return 0;
+ }
+ case EXPP_CONSTR_BONE: {
+ char *name = PyString_AsString( value );
+ if( !name )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected string arg" );
+
+ BLI_strncpy( con->subtarget, name, sizeof( con->subtarget ) );
+
+ return 0;
+ }
+ case EXPP_CONSTR_ACTION: {
+ bAction *act = (( BPy_Action * )value)->action;
+ if( !BPy_Action_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected BPy action argument" );
+ con->act = act;
+ return 0;
+ }
+ case EXPP_CONSTR_START:
+ return EXPP_setIValueClamped( value, &con->start, 1, MAXFRAME, 'h' );
+ case EXPP_CONSTR_END:
+ return EXPP_setIValueClamped( value, &con->end, 1, MAXFRAME, 'h' );
+ case EXPP_CONSTR_MIN:
+ if (con->type < 10)
+ return EXPP_setFloatClamped( value, &con->min, -180.0, 180.0 );
+ else if (con->type < 20)
+ return EXPP_setFloatClamped( value, &con->min, 0.0001, 1000.0 );
+ else
+ return EXPP_setFloatClamped( value, &con->min, -1000.0, 1000.0 );
+ case EXPP_CONSTR_MAX:
+ if (con->type < 10)
+ return EXPP_setFloatClamped( value, &con->max, -180.0, 180.0 );
+ else if (con->type < 20)
+ return EXPP_setFloatClamped( value, &con->max, 0.0001, 1000.0 );
+ else
+ return EXPP_setFloatClamped( value, &con->max, -1000.0, 1000.0 );
+ case EXPP_CONSTR_KEYON:
+ return EXPP_setIValueRange( value, &con->type,
+ EXPP_CONSTR_XROT, EXPP_CONSTR_ZLOC, 'h' );
+ default:
+ return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static PyObject *trackto_getter( BPy_Constraint * self, int type )
+{
+ bTrackToConstraint *con = (bTrackToConstraint *)(self->con->data);
+
+ switch( type ) {
+ case EXPP_CONSTR_TARGET:
+ return Object_CreatePyObject( con->tar );
+ case EXPP_CONSTR_BONE:
+ return PyString_FromString( con->subtarget );
+ case EXPP_CONSTR_TRACK:
+ return PyInt_FromLong( (long)con->reserved1 );
+ case EXPP_CONSTR_UP:
+ return PyInt_FromLong( (long)con->reserved2 );
+ default:
+ return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static int trackto_setter( BPy_Constraint *self, int type, PyObject *value )
+{
+ bTrackToConstraint *con = (bTrackToConstraint *)(self->con->data);
+
+ switch( type ) {
+ case EXPP_CONSTR_TARGET: {
+ Object *obj = (( BPy_Object * )value)->object;
+ if( !BPy_Object_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected BPy object argument" );
+ con->tar = obj;
+ return 0;
+ }
+ case EXPP_CONSTR_BONE: {
+ char *name = PyString_AsString( value );
+ if( !name )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected string arg" );
+
+ BLI_strncpy( con->subtarget, name, sizeof( con->subtarget ) );
+
+ return 0;
+ }
+ case EXPP_CONSTR_TRACK:
+ return EXPP_setIValueRange( value, &con->reserved1,
+ TRACK_X, TRACK_nZ, 'i' );
+ case EXPP_CONSTR_UP:
+ return EXPP_setIValueRange( value, &con->reserved2,
+ UP_X, UP_Z, 'i' );
+ default:
+ return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static PyObject *stretchto_getter( BPy_Constraint * self, int type )
+{
+ bStretchToConstraint *con = (bStretchToConstraint *)(self->con->data);
+
+ switch( type ) {
+ case EXPP_CONSTR_TARGET:
+ return Object_CreatePyObject( con->tar );
+ case EXPP_CONSTR_BONE:
+ return PyString_FromString( con->subtarget );
+ case EXPP_CONSTR_RESTLENGTH:
+ return PyFloat_FromDouble( (double)con->orglength );
+ case EXPP_CONSTR_VOLVARIATION:
+ return PyFloat_FromDouble( (double)con->bulge );
+ case EXPP_CONSTR_VOLUMEMODE:
+ return PyInt_FromLong( (long)con->volmode );
+ case EXPP_CONSTR_PLANE:
+ return PyInt_FromLong( (long)con->plane );
+ default:
+ return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static int stretchto_setter( BPy_Constraint *self, int type, PyObject *value )
+{
+ bStretchToConstraint *con = (bStretchToConstraint *)(self->con->data);
+
+ switch( type ) {
+ case EXPP_CONSTR_TARGET: {
+ Object *obj = (( BPy_Object * )value)->object;
+ if( !BPy_Object_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected BPy object argument" );
+ con->tar = obj;
+ return 0;
+ }
+ case EXPP_CONSTR_BONE: {
+ char *name = PyString_AsString( value );
+ if( !name )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected string arg" );
+
+ BLI_strncpy( con->subtarget, name, sizeof( con->subtarget ) );
+
+ return 0;
+ }
+ case EXPP_CONSTR_RESTLENGTH:
+ return EXPP_setFloatClamped( value, &con->orglength, 0.0, 100.0 );
+ case EXPP_CONSTR_VOLVARIATION:
+ return EXPP_setFloatClamped( value, &con->bulge, 0.0, 100.0 );
+ case EXPP_CONSTR_VOLUMEMODE:
+ return EXPP_setIValueRange( value, &con->volmode,
+ VOLUME_XZ, NO_VOLUME, 'h' );
+ case EXPP_CONSTR_PLANE: {
+ int status, oldcode = con->plane;
+ status = EXPP_setIValueRange( value, &con->plane,
+ PLANE_X, PLANE_Z, 'h' );
+ if( !status && con->plane == PLANE_Y ) {
+ con->plane = oldcode;
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "value must be either PLANEX or PLANEZ" );
+ }
+ return status;
+ }
+ default:
+ return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static PyObject *followpath_getter( BPy_Constraint * self, int type )
+{
+ bFollowPathConstraint *con = (bFollowPathConstraint *)(self->con->data);
+
+ switch( type ) {
+ case EXPP_CONSTR_TARGET:
+ return Object_CreatePyObject( con->tar );
+ case EXPP_CONSTR_FOLLOW:
+ return PyBool_FromLong( (long)( con->followflag & SELECT ) );
+ case EXPP_CONSTR_OFFSET:
+ return PyFloat_FromDouble( (double)con->offset );
+ case EXPP_CONSTR_FORWARD:
+ return PyInt_FromLong( (long)con->trackflag );
+ case EXPP_CONSTR_UP:
+ return PyInt_FromLong( (long)con->upflag );
+ default:
+ return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static int followpath_setter( BPy_Constraint *self, int type, PyObject *value )
+{
+ bFollowPathConstraint *con = (bFollowPathConstraint *)(self->con->data);
+
+ switch( type ) {
+ case EXPP_CONSTR_TARGET: {
+ Object *obj = (( BPy_Object * )value)->object;
+ if( !BPy_Object_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected BPy object argument" );
+ con->tar = obj;
+ return 0;
+ }
+ case EXPP_CONSTR_FOLLOW:
+ return EXPP_setBitfield( value, &con->followflag, SELECT, 'i' );
+ case EXPP_CONSTR_OFFSET:
+ return EXPP_setFloatClamped( value, &con->offset,
+ -MAXFRAMEF, MAXFRAMEF );
+ case EXPP_CONSTR_FORWARD:
+ return EXPP_setIValueRange( value, &con->trackflag,
+ TRACK_X, TRACK_nZ, 'i' );
+ case EXPP_CONSTR_UP:
+ return EXPP_setIValueRange( value, &con->upflag,
+ UP_X, UP_Z, 'i' );
+ default:
+ return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static PyObject *clampto_getter( BPy_Constraint * self, int type )
+{
+ bClampToConstraint *con = (bClampToConstraint *)(self->con->data);
+
+ switch( type ) {
+ case EXPP_CONSTR_TARGET:
+ return Object_CreatePyObject( con->tar );
+ case EXPP_CONSTR_CLAMP:
+ return PyInt_FromLong( (long)con->flag );
+ case EXPP_CONSTR_CLAMPCYCLIC:
+ return PyBool_FromLong( (long)(con->flag2 & CLAMPTO_CYCLIC) );
+ default:
+ return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static int clampto_setter( BPy_Constraint *self, int type, PyObject *value )
+{
+ bClampToConstraint *con = (bClampToConstraint *)(self->con->data);
+
+ switch( type ) {
+ case EXPP_CONSTR_TARGET: {
+ Object *obj = (( BPy_Object * )value)->object;
+ if( !BPy_Object_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected BPy object argument" );
+ con->tar = obj;
+ return 0;
+ }
+ case EXPP_CONSTR_CLAMP:
+ return EXPP_setIValueRange( value, &con->flag,
+ CLAMPTO_AUTO, CLAMPTO_Z, 'i' );
+ case EXPP_CONSTR_CLAMPCYCLIC:
+ return EXPP_setBitfield( value, &con->flag2, CLAMPTO_CYCLIC, 'i' );
+ default:
+ return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
+ }
+}
+static PyObject *locktrack_getter( BPy_Constraint * self, int type )
+{
+ bLockTrackConstraint *con = (bLockTrackConstraint *)(self->con->data);
+
+ switch( type ) {
+ case EXPP_CONSTR_TARGET:
+ return Object_CreatePyObject( con->tar );
+ case EXPP_CONSTR_BONE:
+ return PyString_FromString( con->subtarget );
+ case EXPP_CONSTR_TRACK:
+ return PyInt_FromLong( (long)con->trackflag );
+ case EXPP_CONSTR_LOCK:
+ return PyInt_FromLong( (long)con->lockflag );
+ default:
+ return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static int locktrack_setter( BPy_Constraint *self, int type, PyObject *value )
+{
+ bLockTrackConstraint *con = (bLockTrackConstraint *)(self->con->data);
+
+ switch( type ) {
+ case EXPP_CONSTR_TARGET: {
+ Object *obj = (( BPy_Object * )value)->object;
+ if( !BPy_Object_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected BPy object argument" );
+ con->tar = obj;
+ return 0;
+ }
+ case EXPP_CONSTR_BONE: {
+ char *name = PyString_AsString( value );
+ if( !name )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected string arg" );
+
+ BLI_strncpy( con->subtarget, name, sizeof( con->subtarget ) );
+
+ return 0;
+ }
+ case EXPP_CONSTR_TRACK:
+ return EXPP_setIValueRange( value, &con->trackflag,
+ TRACK_X, TRACK_nZ, 'i' );
+ case EXPP_CONSTR_LOCK:
+ return EXPP_setIValueRange( value, &con->lockflag,
+ LOCK_X, LOCK_Z, 'i' );
+ default:
+ return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static PyObject *floor_getter( BPy_Constraint * self, int type )
+{
+ bMinMaxConstraint *con = (bMinMaxConstraint *)(self->con->data);
+
+ switch( type ) {
+ case EXPP_CONSTR_TARGET:
+ return Object_CreatePyObject( con->tar );
+ case EXPP_CONSTR_BONE:
+ return PyString_FromString( con->subtarget );
+ case EXPP_CONSTR_MINMAX:
+ return PyInt_FromLong( (long)con->minmaxflag );
+ case EXPP_CONSTR_OFFSET:
+ return PyFloat_FromDouble( (double)con->offset );
+ case EXPP_CONSTR_STICKY:
+ return PyBool_FromLong( (long)( con->flag & MINMAX_STICKY ) ) ;
+ default:
+ return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static int floor_setter( BPy_Constraint *self, int type, PyObject *value )
+{
+ bMinMaxConstraint *con = (bMinMaxConstraint *)(self->con->data);
+
+ switch( type ) {
+ case EXPP_CONSTR_TARGET: {
+ Object *obj = (( BPy_Object * )value)->object;
+ if( !BPy_Object_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected BPy object argument" );
+ con->tar = obj;
+ return 0;
+ }
+ case EXPP_CONSTR_BONE: {
+ char *name = PyString_AsString( value );
+ if( !name )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected string arg" );
+
+ BLI_strncpy( con->subtarget, name, sizeof( con->subtarget ) );
+
+ return 0;
+ }
+ case EXPP_CONSTR_MINMAX:
+ return EXPP_setIValueRange( value, &con->minmaxflag,
+ EXPP_CONSTR_MAXX, EXPP_CONSTR_MINZ, 'i' );
+ case EXPP_CONSTR_OFFSET:
+ return EXPP_setFloatClamped( value, &con->offset, -100.0, 100.0 );
+ case EXPP_CONSTR_STICKY:
+ return EXPP_setBitfield( value, &con->flag, MINMAX_STICKY, 'h' );
+ default:
+ return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static PyObject *locatelike_getter( BPy_Constraint * self, int type )
+{
+ bLocateLikeConstraint *con = (bLocateLikeConstraint *)(self->con->data);
+
+ switch( type ) {
+ case EXPP_CONSTR_TARGET:
+ return Object_CreatePyObject( con->tar );
+ case EXPP_CONSTR_BONE:
+ return PyString_FromString( con->subtarget );
+ case EXPP_CONSTR_COPY:
+ return PyInt_FromLong( (long)con->flag );
+ default:
+ return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static int locatelike_setter( BPy_Constraint *self, int type, PyObject *value )
+{
+ bLocateLikeConstraint *con = (bLocateLikeConstraint *)(self->con->data);
+
+ switch( type ) {
+ case EXPP_CONSTR_TARGET: {
+ Object *obj = (( BPy_Object * )value)->object;
+ if( !BPy_Object_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected BPy object argument" );
+ con->tar = obj;
+ return 0;
+ }
+ case EXPP_CONSTR_BONE: {
+ char *name = PyString_AsString( value );
+ if( !name )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected string arg" );
+
+ BLI_strncpy( con->subtarget, name, sizeof( con->subtarget ) );
+
+ return 0;
+ }
+ case EXPP_CONSTR_COPY:
+ return EXPP_setIValueRange( value, &con->flag,
+ 0, LOCLIKE_X | LOCLIKE_Y | LOCLIKE_Z | LOCLIKE_X_INVERT | LOCLIKE_Y_INVERT | LOCLIKE_Z_INVERT, 'i' );
+ default:
+ return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static PyObject *rotatelike_getter( BPy_Constraint * self, int type )
+{
+ bRotateLikeConstraint *con = (bRotateLikeConstraint *)(self->con->data);
+
+ switch( type ) {
+ case EXPP_CONSTR_TARGET:
+ return Object_CreatePyObject( con->tar );
+ case EXPP_CONSTR_BONE:
+ return PyString_FromString( con->subtarget );
+ case EXPP_CONSTR_COPY:
+ return PyInt_FromLong( (long)con->flag );
+ default:
+ return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static int rotatelike_setter( BPy_Constraint *self, int type, PyObject *value )
+{
+ bRotateLikeConstraint *con = (bRotateLikeConstraint *)(self->con->data);
+
+ switch( type ) {
+ case EXPP_CONSTR_TARGET: {
+ Object *obj = (( BPy_Object * )value)->object;
+ if( !BPy_Object_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected BPy object argument" );
+ con->tar = obj;
+ return 0;
+ }
+ case EXPP_CONSTR_BONE: {
+ char *name = PyString_AsString( value );
+ if( !name )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected string arg" );
+
+ BLI_strncpy( con->subtarget, name, sizeof( con->subtarget ) );
+
+ return 0;
+ }
+ case EXPP_CONSTR_COPY:
+ return EXPP_setIValueRange( value, &con->flag,
+ 0, ROTLIKE_X | ROTLIKE_Y | ROTLIKE_Z | ROTLIKE_X_INVERT | ROTLIKE_Y_INVERT | ROTLIKE_Z_INVERT, 'i' );
+ default:
+ return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static PyObject *sizelike_getter( BPy_Constraint * self, int type )
+{
+ bSizeLikeConstraint *con = (bSizeLikeConstraint *)(self->con->data);
+
+ switch( type ) {
+ case EXPP_CONSTR_TARGET:
+ return Object_CreatePyObject( con->tar );
+ case EXPP_CONSTR_BONE:
+ return PyString_FromString( con->subtarget );
+ case EXPP_CONSTR_COPY:
+ return PyInt_FromLong( (long)con->flag );
+ default:
+ return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static int sizelike_setter( BPy_Constraint *self, int type, PyObject *value )
+{
+ bSizeLikeConstraint *con = (bSizeLikeConstraint *)(self->con->data);
+
+ switch( type ) {
+ case EXPP_CONSTR_TARGET: {
+ Object *obj = (( BPy_Object * )value)->object;
+ if( !BPy_Object_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected BPy object argument" );
+ con->tar = obj;
+ return 0;
+ }
+ case EXPP_CONSTR_BONE: {
+ char *name = PyString_AsString( value );
+ if( !name )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected string arg" );
+
+ BLI_strncpy( con->subtarget, name, sizeof( con->subtarget ) );
+
+ return 0;
+ }
+ case EXPP_CONSTR_COPY:
+ return EXPP_setIValueRange( value, &con->flag,
+ 0, SIZELIKE_X | SIZELIKE_Y | SIZELIKE_Z, 'i' );
+ default:
+ return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static PyObject *loclimit_getter( BPy_Constraint * self, int type)
+{
+ bLocLimitConstraint *con = (bLocLimitConstraint *)(self->con->data);
+
+ switch( type ) {
+ case EXPP_CONSTR_LIMIT:
+ return PyInt_FromLong( (long)con->flag );
+ case EXPP_CONSTR_XMIN:
+ return PyFloat_FromDouble( (double)con->xmin );
+ case EXPP_CONSTR_XMAX:
+ return PyFloat_FromDouble( (double)con->xmax );
+ case EXPP_CONSTR_YMIN:
+ return PyFloat_FromDouble( (double)con->ymin );
+ case EXPP_CONSTR_YMAX:
+ return PyFloat_FromDouble( (double)con->ymax );
+ case EXPP_CONSTR_ZMIN:
+ return PyFloat_FromDouble( (double)con->zmin );
+ case EXPP_CONSTR_ZMAX:
+ return PyFloat_FromDouble( (double)con->zmax );
+ default:
+ return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static int loclimit_setter( BPy_Constraint *self, int type, PyObject *value )
+{
+ bLocLimitConstraint *con = (bLocLimitConstraint *)(self->con->data);
+
+ switch( type ) {
+ case EXPP_CONSTR_LIMIT:
+ return EXPP_setIValueRange( value, &con->flag, 0,
+ LIMIT_XMIN | LIMIT_XMAX | LIMIT_YMIN | LIMIT_YMAX | LIMIT_ZMIN | LIMIT_ZMAX , 'i' );
+ case EXPP_CONSTR_XMIN:
+ return EXPP_setFloatClamped( value, &con->xmin, -1000.0, 1000.0 );
+ case EXPP_CONSTR_XMAX:
+ return EXPP_setFloatClamped( value, &con->xmax, -1000.0, 1000.0 );
+ case EXPP_CONSTR_YMIN:
+ return EXPP_setFloatClamped( value, &con->ymin, -1000.0, 1000.0 );
+ case EXPP_CONSTR_YMAX:
+ return EXPP_setFloatClamped( value, &con->ymax, -1000.0, 1000.0 );
+ case EXPP_CONSTR_ZMIN:
+ return EXPP_setFloatClamped( value, &con->zmin, -1000.0, 1000.0 );
+ case EXPP_CONSTR_ZMAX:
+ return EXPP_setFloatClamped( value, &con->zmax, -1000.0, 1000.0 );
+ default:
+ return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static PyObject *rotlimit_getter( BPy_Constraint * self, int type )
+{
+ bRotLimitConstraint *con = (bRotLimitConstraint *)(self->con->data);
+
+ switch( type ) {
+ case EXPP_CONSTR_LIMIT:
+ return PyInt_FromLong( (long)con->flag );
+ case EXPP_CONSTR_XMIN:
+ return PyFloat_FromDouble( (double)con->xmin );
+ case EXPP_CONSTR_XMAX:
+ return PyFloat_FromDouble( (double)con->xmax );
+ case EXPP_CONSTR_YMIN:
+ return PyFloat_FromDouble( (double)con->ymin );
+ case EXPP_CONSTR_YMAX:
+ return PyFloat_FromDouble( (double)con->ymax );
+ case EXPP_CONSTR_ZMIN:
+ return PyFloat_FromDouble( (double)con->zmin );
+ case EXPP_CONSTR_ZMAX:
+ return PyFloat_FromDouble( (double)con->zmax );
+ default:
+ return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static int rotlimit_setter( BPy_Constraint *self, int type, PyObject *value )
+{
+ bRotLimitConstraint *con = (bRotLimitConstraint *)(self->con->data);
+
+ switch( type ) {
+ case EXPP_CONSTR_LIMIT:
+ return EXPP_setIValueRange( value, &con->flag, 0,
+ LIMIT_XROT | LIMIT_YROT | LIMIT_ZROT, 'i' );
+ case EXPP_CONSTR_XMIN:
+ return EXPP_setFloatClamped( value, &con->xmin, -360.0, 360.0 );
+ case EXPP_CONSTR_XMAX:
+ return EXPP_setFloatClamped( value, &con->xmax, -360.0, 360.0 );
+ case EXPP_CONSTR_YMIN:
+ return EXPP_setFloatClamped( value, &con->ymin, -360.0, 360.0 );
+ case EXPP_CONSTR_YMAX:
+ return EXPP_setFloatClamped( value, &con->ymax, -360.0, 360.0 );
+ case EXPP_CONSTR_ZMIN:
+ return EXPP_setFloatClamped( value, &con->zmin, -360.0, 360.0 );
+ case EXPP_CONSTR_ZMAX:
+ return EXPP_setFloatClamped( value, &con->zmax, -360.0, 360.0 );
+ default:
+ return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static PyObject *sizelimit_getter( BPy_Constraint * self, int type)
+{
+ bSizeLimitConstraint *con = (bSizeLimitConstraint *)(self->con->data);
+
+ switch( type ) {
+ case EXPP_CONSTR_LIMIT:
+ return PyInt_FromLong( (long)con->flag );
+ case EXPP_CONSTR_XMIN:
+ return PyFloat_FromDouble( (double)con->xmin );
+ case EXPP_CONSTR_XMAX:
+ return PyFloat_FromDouble( (double)con->xmax );
+ case EXPP_CONSTR_YMIN:
+ return PyFloat_FromDouble( (double)con->ymin );
+ case EXPP_CONSTR_YMAX:
+ return PyFloat_FromDouble( (double)con->ymax );
+ case EXPP_CONSTR_ZMIN:
+ return PyFloat_FromDouble( (double)con->zmin );
+ case EXPP_CONSTR_ZMAX:
+ return PyFloat_FromDouble( (double)con->zmax );
+ default:
+ return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static int sizelimit_setter( BPy_Constraint *self, int type, PyObject *value )
+{
+ bSizeLimitConstraint *con = (bSizeLimitConstraint *)(self->con->data);
+
+ switch( type ) {
+ case EXPP_CONSTR_LIMIT:
+ return EXPP_setIValueRange( value, &con->flag, 0,
+ LIMIT_XMIN | LIMIT_XMAX | LIMIT_YMIN | LIMIT_YMAX | LIMIT_ZMIN | LIMIT_ZMAX, 'i' );
+ case EXPP_CONSTR_XMIN:
+ return EXPP_setFloatClamped( value, &con->xmin, -1000.0, 1000.0 );
+ case EXPP_CONSTR_XMAX:
+ return EXPP_setFloatClamped( value, &con->xmax, -1000.0, 1000.0 );
+ case EXPP_CONSTR_YMIN:
+ return EXPP_setFloatClamped( value, &con->ymin, -1000.0, 1000.0 );
+ case EXPP_CONSTR_YMAX:
+ return EXPP_setFloatClamped( value, &con->ymax, -1000.0, 1000.0 );
+ case EXPP_CONSTR_ZMIN:
+ return EXPP_setFloatClamped( value, &con->zmin, -1000.0, 1000.0 );
+ case EXPP_CONSTR_ZMAX:
+ return EXPP_setFloatClamped( value, &con->zmax, -1000.0, 1000.0 );
+ default:
+ return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static PyObject *script_getter( BPy_Constraint * self, int type )
+{
+ bPythonConstraint *con = (bPythonConstraint *)(self->con->data);
+
+ switch( type ) {
+ // FIXME!!!
+ //case EXPP_CONSTR_TARGET:
+ // return Object_CreatePyObject( con->tar );
+ //case EXPP_CONSTR_BONE:
+ // return PyString_FromString( con->subtarget );
+ case EXPP_CONSTR_SCRIPT:
+ return Text_CreatePyObject( con->text );
+ case EXPP_CONSTR_PROPS:
+ return BPy_Wrap_IDProperty( NULL, con->prop, NULL);
+ default:
+ return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static int script_setter( BPy_Constraint *self, int type, PyObject *value )
+{
+ bPythonConstraint *con = (bPythonConstraint *)(self->con->data);
+
+ switch( type ) {
+ // FIXME!!!
+ //case EXPP_CONSTR_TARGET: {
+ // Object *obj = (( BPy_Object * )value)->object;
+ // if( !BPy_Object_Check( value ) )
+ // return EXPP_ReturnIntError( PyExc_TypeError,
+ // "expected BPy object argument" );
+ // con->tar = obj;
+ // return 0;
+ // }
+ //case EXPP_CONSTR_BONE: {
+ // char *name = PyString_AsString( value );
+ // if( !name )
+ // return EXPP_ReturnIntError( PyExc_TypeError,
+ // "expected string arg" );
+ //
+ // BLI_strncpy( con->subtarget, name, sizeof( con->subtarget ) );
+ //
+ // return 0;
+ // }
+ case EXPP_CONSTR_SCRIPT: {
+ Text *text = (( BPy_Text * )value)->text;
+ if( !BPy_Object_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected BPy text argument" );
+ con->text = text;
+ return 0;
+ }
+ case EXPP_CONSTR_PROPS:
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "setting ID-Properties of PyConstraints this way is not supported" );
+ default:
+ return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
+ }
+}
+
+
+static PyObject *rigidbody_getter( BPy_Constraint * self, int type)
+{
+ bRigidBodyJointConstraint *con = (bRigidBodyJointConstraint *)(self->con->data);
+
+ switch( type ) {
+ case EXPP_CONSTR_TARGET:
+ return Object_CreatePyObject( con->tar );
+ case EXPP_CONSTR_RB_PIVX:
+ return PyFloat_FromDouble( (double)con->pivX );
+ case EXPP_CONSTR_RB_PIVY:
+ return PyFloat_FromDouble( (double)con->pivY );
+ case EXPP_CONSTR_RB_PIVZ:
+ return PyFloat_FromDouble( (double)con->pivZ );
+ case EXPP_CONSTR_RB_AXX:
+ return PyFloat_FromDouble( (double)con->axX );
+ case EXPP_CONSTR_RB_AXY:
+ return PyFloat_FromDouble( (double)con->axY );
+ case EXPP_CONSTR_RB_AXZ:
+ return PyFloat_FromDouble( (double)con->axZ );
+ case EXPP_CONSTR_RB_MINLIMIT0:
+ return PyFloat_FromDouble( (double)con->minLimit[0] );
+ case EXPP_CONSTR_RB_MINLIMIT1:
+ return PyFloat_FromDouble( (double)con->minLimit[1] );
+ case EXPP_CONSTR_RB_MINLIMIT2:
+ return PyFloat_FromDouble( (double)con->minLimit[2] );
+ case EXPP_CONSTR_RB_MINLIMIT3:
+ return PyFloat_FromDouble( (double)con->minLimit[3] );
+ case EXPP_CONSTR_RB_MINLIMIT4:
+ return PyFloat_FromDouble( (double)con->minLimit[4] );
+ case EXPP_CONSTR_RB_MINLIMIT5:
+ return PyFloat_FromDouble( (double)con->minLimit[5] );
+ case EXPP_CONSTR_RB_MAXLIMIT0:
+ return PyFloat_FromDouble( (double)con->maxLimit[0] );
+ case EXPP_CONSTR_RB_MAXLIMIT1:
+ return PyFloat_FromDouble( (double)con->maxLimit[1] );
+ case EXPP_CONSTR_RB_MAXLIMIT2:
+ return PyFloat_FromDouble( (double)con->maxLimit[2] );
+ case EXPP_CONSTR_RB_MAXLIMIT3:
+ return PyFloat_FromDouble( (double)con->maxLimit[3] );
+ case EXPP_CONSTR_RB_MAXLIMIT4:
+ return PyFloat_FromDouble( (double)con->maxLimit[4] );
+ case EXPP_CONSTR_RB_MAXLIMIT5:
+ return PyFloat_FromDouble( (double)con->maxLimit[5] );
+ case EXPP_CONSTR_RB_EXTRAFZ:
+ return PyFloat_FromDouble( (double)con->extraFz );
+ case EXPP_CONSTR_LIMIT:
+ return PyInt_FromLong( (int)con->flag );
+
+ case EXPP_CONSTR_RB_TYPE:
+ return PyInt_FromLong( (int)con->type );
+ default:
+ return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
+ }
+}
+
+
+static int rigidbody_setter( BPy_Constraint *self, int type, PyObject *value )
+{
+ bRigidBodyJointConstraint *con = (bRigidBodyJointConstraint *)(self->con->data);
+
+ switch( type ) {
+ case EXPP_CONSTR_TARGET: {
+ Object *obj = (( BPy_Object * )value)->object;
+ if( !BPy_Object_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected BPy object argument" );
+ con->tar = obj;
+ return 0;
+ }
+ case EXPP_CONSTR_RB_PIVX:
+ return EXPP_setFloatClamped( value, &con->pivX , -1000.0, 1000.0 );
+ case EXPP_CONSTR_RB_PIVY:
+ return EXPP_setFloatClamped( value, &con->pivY , -1000.0, 1000.0 );
+ case EXPP_CONSTR_RB_PIVZ:
+ return EXPP_setFloatClamped( value, &con->pivZ , -1000.0, 1000.0 );
+ case EXPP_CONSTR_RB_AXX:
+ return EXPP_setFloatClamped( value, &con->axX , -1000.0, 1000.0 );
+ case EXPP_CONSTR_RB_AXY:
+ return EXPP_setFloatClamped( value, &con->axY , -1000.0, 1000.0 );
+ case EXPP_CONSTR_RB_AXZ:
+ return EXPP_setFloatClamped( value, &con->axZ , -1000.0, 1000.0 );
+ case EXPP_CONSTR_RB_MINLIMIT0:
+ return EXPP_setFloatClamped( value, &con->minLimit[0] , -1000.0, 1000.0 );
+ case EXPP_CONSTR_RB_MINLIMIT1:
+ return EXPP_setFloatClamped( value, &con->minLimit[1] , -1000.0, 1000.0 );
+ case EXPP_CONSTR_RB_MINLIMIT2:
+ return EXPP_setFloatClamped( value, &con->minLimit[2] , -1000.0, 1000.0 );
+ case EXPP_CONSTR_RB_MINLIMIT3:
+ return EXPP_setFloatClamped( value, &con->minLimit[3] , -1000.0, 1000.0 );
+ case EXPP_CONSTR_RB_MINLIMIT4:
+ return EXPP_setFloatClamped( value, &con->minLimit[4] , -1000.0, 1000.0 );
+ case EXPP_CONSTR_RB_MINLIMIT5:
+ return EXPP_setFloatClamped( value, &con->minLimit[5] , -1000.0, 1000.0 );
+ case EXPP_CONSTR_RB_MAXLIMIT0:
+ return EXPP_setFloatClamped( value, &con->maxLimit[0] , -1000.0, 1000.0 );
+ case EXPP_CONSTR_RB_MAXLIMIT1:
+ return EXPP_setFloatClamped( value, &con->maxLimit[1] , -1000.0, 1000.0 );
+ case EXPP_CONSTR_RB_MAXLIMIT2:
+ return EXPP_setFloatClamped( value, &con->maxLimit[2] , -1000.0, 1000.0 );
+ case EXPP_CONSTR_RB_MAXLIMIT3:
+ return EXPP_setFloatClamped( value, &con->maxLimit[3] , -1000.0, 1000.0 );
+ case EXPP_CONSTR_RB_MAXLIMIT4:
+ return EXPP_setFloatClamped( value, &con->maxLimit[4] , -1000.0, 1000.0 );
+ case EXPP_CONSTR_RB_MAXLIMIT5:
+ return EXPP_setFloatClamped( value, &con->maxLimit[5] , -1000.0, 1000.0 );
+ case EXPP_CONSTR_RB_EXTRAFZ:
+ return EXPP_setFloatClamped( value, &con->extraFz , -1000.0, 1000.0 );
+ case EXPP_CONSTR_LIMIT:
+ return EXPP_setIValueRange( value, &con->flag, 0,
+ LIMIT_XMIN | LIMIT_XMAX | LIMIT_YMIN | LIMIT_YMAX | LIMIT_ZMIN | LIMIT_ZMAX, 'i' );
+ case EXPP_CONSTR_RB_TYPE:
+ return EXPP_setIValueRange( value, &con->type, 0,
+ EXPP_CONSTR_RB_BALL | EXPP_CONSTR_RB_HINGE | EXPP_CONSTR_RB_GENERIC6DOF | EXPP_CONSTR_RB_VEHICLE, 'i' );
+ default:
+ return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static PyObject *childof_getter( BPy_Constraint * self, int type )
+{
+ bChildOfConstraint *con = (bChildOfConstraint *)(self->con->data);
+
+ switch( type ) {
+ case EXPP_CONSTR_TARGET:
+ return Object_CreatePyObject( con->tar );
+ case EXPP_CONSTR_BONE:
+ return PyString_FromString( con->subtarget );
+ case EXPP_CONSTR_COPY:
+ return PyInt_FromLong( (long)con->flag );
+ default:
+ return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static int childof_setter( BPy_Constraint *self, int type, PyObject *value )
+{
+ bChildOfConstraint *con = (bChildOfConstraint *)(self->con->data);
+
+ switch( type ) {
+ case EXPP_CONSTR_TARGET: {
+ Object *obj = (( BPy_Object * )value)->object;
+ if( !BPy_Object_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected BPy object argument" );
+ con->tar = obj;
+ return 0;
+ }
+ case EXPP_CONSTR_BONE: {
+ char *name = PyString_AsString( value );
+ if( !name )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected string arg" );
+
+ BLI_strncpy( con->subtarget, name, sizeof( con->subtarget ) );
+
+ return 0;
+ }
+ case EXPP_CONSTR_COPY:
+ return EXPP_setIValueRange( value, &con->flag,
+ 0, CHILDOF_LOCX| CHILDOF_LOCY | CHILDOF_LOCZ | CHILDOF_ROTX | CHILDOF_ROTY | CHILDOF_ROTZ |
+ CHILDOF_SIZEX |CHILDOF_SIZEY| CHILDOF_SIZEZ, 'i' );
+ default:
+ return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static PyObject *transf_getter( BPy_Constraint * self, int type )
+{
+ bTransformConstraint *con = (bTransformConstraint *)(self->con->data);
+
+ switch( type ) {
+ case EXPP_CONSTR_TARGET:
+ return Object_CreatePyObject( con->tar );
+ case EXPP_CONSTR_BONE:
+ return PyString_FromString( con->subtarget );
+ case EXPP_CONSTR_FROM:
+ return PyInt_FromLong( (long)con->from );
+ case EXPP_CONSTR_TO:
+ return PyInt_FromLong( (long)con->to );
+ case EXPP_CONSTR_MAPX:
+ return PyInt_FromLong( (long)con->map[0] );
+ case EXPP_CONSTR_MAPY:
+ return PyInt_FromLong( (long)con->map[1] );
+ case EXPP_CONSTR_MAPZ:
+ return PyInt_FromLong( (long)con->map[2] );
+ case EXPP_CONSTR_FROMMINX:
+ return PyFloat_FromDouble( (double)con->from_min[0] );
+ case EXPP_CONSTR_FROMMAXX:
+ return PyFloat_FromDouble( (double)con->from_max[0] );
+ case EXPP_CONSTR_FROMMINY:
+ return PyFloat_FromDouble( (double)con->from_min[1] );
+ case EXPP_CONSTR_FROMMAXY:
+ return PyFloat_FromDouble( (double)con->from_max[1] );
+ case EXPP_CONSTR_FROMMINZ:
+ return PyFloat_FromDouble( (double)con->from_min[2] );
+ case EXPP_CONSTR_FROMMAXZ:
+ return PyFloat_FromDouble( (double)con->from_max[2] );
+ case EXPP_CONSTR_TOMINX:
+ return PyFloat_FromDouble( (double)con->to_min[0] );
+ case EXPP_CONSTR_TOMAXX:
+ return PyFloat_FromDouble( (double)con->to_max[0] );
+ case EXPP_CONSTR_TOMINY:
+ return PyFloat_FromDouble( (double)con->to_min[1] );
+ case EXPP_CONSTR_TOMAXY:
+ return PyFloat_FromDouble( (double)con->to_max[1] );
+ case EXPP_CONSTR_TOMINZ:
+ return PyFloat_FromDouble( (double)con->to_min[2] );
+ case EXPP_CONSTR_TOMAXZ:
+ return PyFloat_FromDouble( (double)con->to_max[2] );
+ case EXPP_CONSTR_EXPO:
+ return PyBool_FromLong( (long)con->expo );
+ default:
+ return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static int transf_setter( BPy_Constraint *self, int type, PyObject *value )
+{
+ bTransformConstraint *con = (bTransformConstraint *)(self->con->data);
+ float fmin, fmax, tmin, tmax;
+
+ if (con->from == 2) {
+ fmin = 0.0001;
+ fmax = 1000.0;
+ }
+ else if (con->from == 1) {
+ fmin = -360.0;
+ fmax = 360.0;
+ }
+ else {
+ fmin = -1000.0;
+ fmax = 1000.0;
+ }
+
+ if (con->to == 2) {
+ tmin = 0.0001;
+ tmax = 1000.0;
+ }
+ else if (con->to == 1) {
+ tmin = -360.0;
+ tmax = 360.0;
+ }
+ else {
+ tmin = -1000.0;
+ tmax = 1000.0;
+ }
+
+ switch( type ) {
+ case EXPP_CONSTR_TARGET: {
+ Object *obj = (( BPy_Object * )value)->object;
+ if( !BPy_Object_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected BPy object argument" );
+ con->tar = obj;
+ return 0;
+ }
+ case EXPP_CONSTR_BONE: {
+ char *name = PyString_AsString( value );
+ if( !name )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected string arg" );
+
+ BLI_strncpy( con->subtarget, name, sizeof( con->subtarget ) );
+
+ return 0;
+ }
+ case EXPP_CONSTR_FROM:
+ return EXPP_setIValueClamped( value, &con->from, 0, 3, 'h' );
+ case EXPP_CONSTR_TO:
+ return EXPP_setIValueClamped( value, &con->to, 0, 3, 'h' );
+ case EXPP_CONSTR_MAPX:
+ return EXPP_setIValueClamped( value, &con->map[0], 0, 3, 'h' );
+ case EXPP_CONSTR_MAPY:
+ return EXPP_setIValueClamped( value, &con->map[1], 0, 3, 'h' );
+ case EXPP_CONSTR_MAPZ:
+ return EXPP_setIValueClamped( value, &con->map[2], 0, 3, 'h' );
+ case EXPP_CONSTR_FROMMINX:
+ return EXPP_setFloatClamped( value, &con->from_min[0], fmin, fmax );
+ case EXPP_CONSTR_FROMMAXX:
+ return EXPP_setFloatClamped( value, &con->from_max[0], fmin, fmax );
+ case EXPP_CONSTR_FROMMINY:
+ return EXPP_setFloatClamped( value, &con->from_min[1], fmin, fmax );
+ case EXPP_CONSTR_FROMMAXY:
+ return EXPP_setFloatClamped( value, &con->from_max[1], fmin, fmax );
+ case EXPP_CONSTR_FROMMINZ:
+ return EXPP_setFloatClamped( value, &con->from_min[2], fmin, fmax );
+ case EXPP_CONSTR_FROMMAXZ:
+ return EXPP_setFloatClamped( value, &con->from_max[2], fmin, fmax );
+ case EXPP_CONSTR_TOMINX:
+ return EXPP_setFloatClamped( value, &con->to_min[0], tmin, tmax );
+ case EXPP_CONSTR_TOMAXX:
+ return EXPP_setFloatClamped( value, &con->to_max[0], tmin, tmax );
+ case EXPP_CONSTR_TOMINY:
+ return EXPP_setFloatClamped( value, &con->to_min[1], tmin, tmax );
+ case EXPP_CONSTR_TOMAXY:
+ return EXPP_setFloatClamped( value, &con->to_max[1], tmin, tmax );
+ case EXPP_CONSTR_TOMINZ:
+ return EXPP_setFloatClamped( value, &con->to_min[2], tmin, tmax );
+ case EXPP_CONSTR_TOMAXZ:
+ return EXPP_setFloatClamped( value, &con->to_max[2], tmin, tmax );
+ case EXPP_CONSTR_EXPO:
+ return EXPP_setBitfield( value, &con->expo, 1, 'h' );
+ default:
+ return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
+ }
+}
+
+/*
+ * get data from a constraint
+ */
+
+static PyObject *Constraint_getData( BPy_Constraint * self, PyObject * key )
+{
+ int setting;
+
+ if( !PyInt_Check( key ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected an int arg" );
+
+ if( !self->con )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "This constraint has been removed!" );
+
+ setting = PyInt_AsLong( key );
+
+ /* bypass doing settings of individual constraints, if we're just doing
+ * constraint space access-stuff
+ */
+ if ((setting==EXPP_CONSTR_OWNSPACE) || (setting==EXPP_CONSTR_TARSPACE)) {
+ return constspace_getter( self, setting );
+ }
+ switch( self->con->type ) {
+ case CONSTRAINT_TYPE_NULL:
+ Py_RETURN_NONE;
+ case CONSTRAINT_TYPE_TRACKTO:
+ return trackto_getter( self, setting );
+ case CONSTRAINT_TYPE_KINEMATIC:
+ return kinematic_getter( self, setting );
+ case CONSTRAINT_TYPE_FOLLOWPATH:
+ return followpath_getter( self, setting );
+ case CONSTRAINT_TYPE_ACTION:
+ return action_getter( self, setting );
+ case CONSTRAINT_TYPE_LOCKTRACK:
+ return locktrack_getter( self, setting );
+ case CONSTRAINT_TYPE_STRETCHTO:
+ return stretchto_getter( self, setting );
+ case CONSTRAINT_TYPE_MINMAX:
+ return floor_getter( self, setting );
+ case CONSTRAINT_TYPE_LOCLIKE:
+ return locatelike_getter( self, setting );
+ case CONSTRAINT_TYPE_ROTLIKE:
+ return rotatelike_getter( self, setting );
+ case CONSTRAINT_TYPE_SIZELIKE:
+ return sizelike_getter( self, setting );
+ case CONSTRAINT_TYPE_ROTLIMIT:
+ return rotlimit_getter( self, setting );
+ case CONSTRAINT_TYPE_LOCLIMIT:
+ return loclimit_getter( self, setting );
+ case CONSTRAINT_TYPE_SIZELIMIT:
+ return sizelimit_getter( self, setting );
+ case CONSTRAINT_TYPE_RIGIDBODYJOINT:
+ return rigidbody_getter( self, setting );
+ case CONSTRAINT_TYPE_CLAMPTO:
+ return clampto_getter( self, setting );
+ case CONSTRAINT_TYPE_PYTHON:
+ return script_getter( self, setting );
+ case CONSTRAINT_TYPE_CHILDOF:
+ return childof_getter( self, setting );
+ case CONSTRAINT_TYPE_TRANSFORM:
+ return transf_getter( self, setting );
+ default:
+ return EXPP_ReturnPyObjError( PyExc_KeyError,
+ "unknown constraint type" );
+ }
+}
+
+static int Constraint_setData( BPy_Constraint * self, PyObject * key,
+ PyObject * arg )
+{
+ int key_int, result;
+
+ if( !PyNumber_Check( key ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected an int arg" );
+ if( !self->con )
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "This constraint has been removed!" );
+
+ key_int = PyInt_AsLong( key );
+
+ /* bypass doing settings of individual constraints, if we're just doing
+ * constraint space access-stuff
+ */
+ if ((key_int==EXPP_CONSTR_OWNSPACE) || (key_int==EXPP_CONSTR_TARSPACE)) {
+ result = constspace_setter( self, key_int, arg );
+ }
+ else {
+ switch( self->con->type ) {
+ case CONSTRAINT_TYPE_KINEMATIC:
+ result = kinematic_setter( self, key_int, arg );
+ break;
+ case CONSTRAINT_TYPE_ACTION:
+ result = action_setter( self, key_int, arg );
+ break;
+ case CONSTRAINT_TYPE_TRACKTO:
+ result = trackto_setter( self, key_int, arg );
+ break;
+ case CONSTRAINT_TYPE_STRETCHTO:
+ result = stretchto_setter( self, key_int, arg );
+ break;
+ case CONSTRAINT_TYPE_FOLLOWPATH:
+ result = followpath_setter( self, key_int, arg );
+ break;
+ case CONSTRAINT_TYPE_LOCKTRACK:
+ result = locktrack_setter( self, key_int, arg );
+ break;
+ case CONSTRAINT_TYPE_MINMAX:
+ result = floor_setter( self, key_int, arg );
+ break;
+ case CONSTRAINT_TYPE_LOCLIKE:
+ result = locatelike_setter( self, key_int, arg );
+ break;
+ case CONSTRAINT_TYPE_ROTLIKE:
+ result = rotatelike_setter( self, key_int, arg );
+ break;
+ case CONSTRAINT_TYPE_SIZELIKE:
+ result = sizelike_setter( self, key_int, arg );
+ break;
+ case CONSTRAINT_TYPE_ROTLIMIT:
+ result = rotlimit_setter( self, key_int, arg );
+ break;
+ case CONSTRAINT_TYPE_LOCLIMIT:
+ result = loclimit_setter( self, key_int, arg );
+ break;
+ case CONSTRAINT_TYPE_SIZELIMIT:
+ result = sizelimit_setter( self, key_int, arg);
+ break;
+ case CONSTRAINT_TYPE_RIGIDBODYJOINT:
+ result = rigidbody_setter( self, key_int, arg);
+ break;
+ case CONSTRAINT_TYPE_CLAMPTO:
+ result = clampto_setter( self, key_int, arg);
+ break;
+ case CONSTRAINT_TYPE_PYTHON:
+ result = script_setter( self, key_int, arg);
+ break;
+ case CONSTRAINT_TYPE_CHILDOF:
+ result = childof_setter( self, key_int, arg);
+ break;
+ case CONSTRAINT_TYPE_TRANSFORM:
+ result = transf_setter( self, key_int, arg);
+ break;
+ case CONSTRAINT_TYPE_NULL:
+ return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
+ default:
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "unsupported constraint setting" );
+ }
+ }
+ if( !result && self->pchan )
+ update_pose_constraint_flags( self->obj->pose );
+ return result;
+}
+
+/*****************************************************************************/
+/* Function: Constraint_compare */
+/* Description: This compares 2 constraint python types, == or != only. */
+/*****************************************************************************/
+static int Constraint_compare( BPy_Constraint * a, BPy_Constraint * b )
+{
+ return ( a->con == b->con ) ? 0 : -1;
+}
+
+/*****************************************************************************/
+/* Function: Constraint_repr */
+/* Description: This is a callback function for the BPy_Constraint type. It */
+/* builds a meaningful string to represent constraint objects. */
+/*****************************************************************************/
+
+static PyObject *Constraint_repr( BPy_Constraint * self )
+{
+ bConstraintTypeInfo *cti;
+
+ if (!self->con)
+ return PyString_FromString("[Constraint - Removed]");
+ else
+ cti= constraint_get_typeinfo(self->con);
+
+ if (cti) {
+ return PyString_FromFormat("[Constraint \"%s\", Type \"%s\"]",
+ self->con->name, cti->name);
+ }
+ else {
+ return PyString_FromString("[Constraint \"%s\", Type \"Unknown\"]");
+ }
+}
+
+/* Three Python Constraint_Type helper functions needed by the Object module: */
+
+/*****************************************************************************/
+/* Function: Constraint_CreatePyObject */
+/* Description: This function will create a new BPy_Constraint from an */
+/* existing Blender constraint structure. */
+/*****************************************************************************/
+PyObject *Constraint_CreatePyObject( bPoseChannel *pchan, Object *obj,
+ bConstraint *con )
+{
+ BPy_Constraint *pycon;
+ pycon = ( BPy_Constraint * ) PyObject_NEW( BPy_Constraint,
+ &Constraint_Type );
+ if( !pycon )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create BPy_Constraint object" );
+
+ pycon->con = con;
+
+ /* one of these two will be NULL */
+ pycon->obj = obj;
+ pycon->pchan = pchan;
+ return ( PyObject * ) pycon;
+}
+
+/*****************************************************************************/
+/* Function: Constraint_FromPyObject */
+/* Description: This function returns the Blender constraint from the given */
+/* PyObject. */
+/*****************************************************************************/
+bConstraint *Constraint_FromPyObject( BPy_Constraint * self )
+{
+ return self->con;
+}
+
+/*****************************************************************************/
+/* Constraint Sequence wrapper */
+/*****************************************************************************/
+
+/*
+ * Initialize the interator
+ */
+
+static PyObject *ConstraintSeq_getIter( BPy_ConstraintSeq * self )
+{
+ if( self->pchan )
+ self->iter = (bConstraint *)self->pchan->constraints.first;
+ else
+ self->iter = (bConstraint *)self->obj->constraints.first;
+ return EXPP_incr_ret ( (PyObject *) self );
+}
+
+/*
+ * Get the next Constraint
+ */
+
+static PyObject *ConstraintSeq_nextIter( BPy_ConstraintSeq * self )
+{
+ bConstraint *this = self->iter;
+ if( this ) {
+ self->iter = this->next;
+ return Constraint_CreatePyObject( self->pchan, self->obj, this );
+ }
+
+ return EXPP_ReturnPyObjError( PyExc_StopIteration,
+ "iterator at end" );
+}
+
+/* return the number of constraints */
+
+static int ConstraintSeq_length( BPy_ConstraintSeq * self )
+{
+ return BLI_countlist( self->pchan ?
+ &self->pchan->constraints : &self->obj->constraints );
+}
+
+/* return a constraint */
+
+static PyObject *ConstraintSeq_item( BPy_ConstraintSeq * self, int i )
+{
+ bConstraint *con = NULL;
+
+ /* if index is negative, start counting from the end of the list */
+ if( i < 0 )
+ i += ConstraintSeq_length( self );
+
+ /* skip through the list until we get the constraint or end of list */
+
+ if( self->pchan )
+ con = self->pchan->constraints.first;
+ else
+ con = self->obj->constraints.first;
+
+ while( i && con ) {
+ --i;
+ con = con->next;
+ }
+
+ if( con )
+ return Constraint_CreatePyObject( self->pchan, self->obj, con );
+ else
+ return EXPP_ReturnPyObjError( PyExc_IndexError,
+ "array index out of range" );
+}
+
+/*****************************************************************************/
+/* Python BPy_ConstraintSeq sequence table: */
+/*****************************************************************************/
+static PySequenceMethods ConstraintSeq_as_sequence = {
+ ( inquiry ) ConstraintSeq_length, /* sq_length */
+ ( binaryfunc ) 0, /* sq_concat */
+ ( intargfunc ) 0, /* sq_repeat */
+ ( intargfunc ) ConstraintSeq_item, /* sq_item */
+ ( intintargfunc ) 0, /* sq_slice */
+ ( intobjargproc ) 0, /* sq_ass_item */
+ ( intintobjargproc ) 0, /* sq_ass_slice */
+ ( objobjproc ) 0, /* sq_contains */
+ ( binaryfunc ) 0, /* sq_inplace_concat */
+ ( intargfunc ) 0, /* sq_inplace_repeat */
+};
+
+/*
+ * helper function to check for a valid constraint argument
+ */
+
+static bConstraint *locate_constr( BPy_ConstraintSeq *self, BPy_Constraint * value )
+{
+ bConstraint *con;
+
+ /* check that argument is a modifier */
+ if (!BPy_Constraint_Check(value))
+ return (bConstraint *)EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a constraint as an argument" );
+
+ /* check whether constraint has been removed */
+ if( !value->con )
+ return (bConstraint *)EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "This constraint has been removed!" );
+
+ /* verify the constraint is still exists in the stack */
+ if( self->pchan )
+ con = self->pchan->constraints.first;
+ else
+ con = self->obj->constraints.first;
+ while( con && con != value->con )
+ con = con->next;
+
+ /* if we didn't find it, exception */
+ if( !con )
+ return (bConstraint *)EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "This constraint is no longer in the object's stack" );
+
+ return con;
+}
+
+
+/* create a new constraint at the end of the list */
+
+static PyObject *ConstraintSeq_append( BPy_ConstraintSeq *self, PyObject *value )
+{
+ int type = (int)PyInt_AsLong(value);
+ bConstraint *con;
+
+ /* type 0 is CONSTRAINT_TYPE_NULL, should we be able to add one of these?
+ * if the value is not an int it will be -1 */
+ if( type < CONSTRAINT_TYPE_NULL || type > CONSTRAINT_TYPE_RIGIDBODYJOINT )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "arg not in int or out of range" );
+
+ con = add_new_constraint( type );
+ if( self->pchan ) {
+ BLI_addtail( &self->pchan->constraints, con );
+ update_pose_constraint_flags( self->obj->pose );
+ }
+ else
+ BLI_addtail( &self->obj->constraints, con );
+
+ return Constraint_CreatePyObject( self->pchan, self->obj, con );
+}
+
+/* move the constraint up in the stack */
+
+static PyObject *ConstraintSeq_moveUp( BPy_ConstraintSeq *self, BPy_Constraint *value )
+{
+ bConstraint *con = locate_constr( self, value );
+
+ /* if we can't locate the constraint, return (exception already set) */
+ if( !con )
+ return (PyObject *)NULL;
+
+ const_moveUp( self->obj, con );
+ Py_RETURN_NONE;
+}
+
+/* move the constraint down in the stack */
+
+static PyObject *ConstraintSeq_moveDown( BPy_ConstraintSeq *self, BPy_Constraint *value )
+{
+ bConstraint *con = locate_constr( self, value );
+
+ /* if we can't locate the constraint, return (exception already set) */
+ if( !con )
+ return (PyObject *)NULL;
+
+ const_moveDown( self->obj, con );
+ Py_RETURN_NONE;
+}
+
+/* remove an existing constraint */
+
+static PyObject *ConstraintSeq_remove( BPy_ConstraintSeq *self, BPy_Constraint *value )
+{
+ bConstraint *con = locate_constr( self, value );
+
+ /* if we can't locate the constraint, return (exception already set) */
+ if( !con )
+ return (PyObject *)NULL;
+
+ /* do the actual removal */
+ if( self->pchan )
+ BLI_remlink( &self->pchan->constraints, con );
+ else
+ BLI_remlink( &self->obj->constraints, con);
+ del_constr_func( self->obj, con );
+
+ /* erase the link to the constraint */
+ value->con = NULL;
+
+ Py_RETURN_NONE;
+}
+
+/*****************************************************************************/
+/* Function: ConstraintSeq_dealloc */
+/* Description: This is a callback function for the BPy_ConstraintSeq type. */
+/* It destroys data when the object is deleted. */
+/*****************************************************************************/
+static void ConstraintSeq_dealloc( BPy_Constraint * self )
+{
+ PyObject_DEL( self );
+}
+
+/*****************************************************************************/
+/* Python BPy_ConstraintSeq methods table: */
+/*****************************************************************************/
+static PyMethodDef BPy_ConstraintSeq_methods[] = {
+ /* name, method, flags, doc */
+ {"append", ( PyCFunction ) ConstraintSeq_append, METH_O,
+ "(type) - add a new constraint, where type is the constraint type"},
+ {"remove", ( PyCFunction ) ConstraintSeq_remove, METH_O,
+ "(con) - remove an existing constraint, where con is a constraint from this object."},
+ {"moveUp", ( PyCFunction ) ConstraintSeq_moveUp, METH_O,
+ "(con) - Move constraint up in stack"},
+ {"moveDown", ( PyCFunction ) ConstraintSeq_moveDown, METH_O,
+ "(con) - Move constraint down in stack"},
+ {NULL, NULL, 0, NULL}
+};
+
+/*****************************************************************************/
+/* Python ConstraintSeq_Type structure definition: */
+/*****************************************************************************/
+PyTypeObject ConstraintSeq_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender.Constraints", /* char *tp_name; */
+ sizeof( BPy_ConstraintSeq ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ ( destructor ) ConstraintSeq_dealloc,/* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* cmpfunc tp_compare; */
+ ( reprfunc ) NULL, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ &ConstraintSeq_as_sequence, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ ( getiterfunc )ConstraintSeq_getIter, /* getiterfunc tp_iter; */
+ ( iternextfunc )ConstraintSeq_nextIter, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_ConstraintSeq_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ NULL, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+/*****************************************************************************/
+/* Function: PoseConstraintSeq_CreatePyObject */
+/* Description: This function will create a new BPy_ConstraintSeq from an */
+/* existing ListBase structure. */
+/*****************************************************************************/
+PyObject *PoseConstraintSeq_CreatePyObject( bPoseChannel *pchan )
+{
+ BPy_ConstraintSeq *pyseq;
+ Object *ob;
+
+ for( ob = G.main->object.first; ob; ob = ob->id.next ) {
+ if( ob->type == OB_ARMATURE ) {
+ bPoseChannel *p = ob->pose->chanbase.first;
+ while( p ) {
+ if( p == pchan ) {
+ pyseq = ( BPy_ConstraintSeq * ) PyObject_NEW(
+ BPy_ConstraintSeq, &ConstraintSeq_Type );
+ if( !pyseq )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create BPy_ConstraintSeq object" );
+ pyseq->pchan = pchan;
+ pyseq->obj = ob;
+ return ( PyObject * ) pyseq;
+ } else
+ p = p->next;
+ }
+ }
+ }
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't find ANY armature with the pose!" );
+
+}
+
+/*****************************************************************************/
+/* Function: ObConstraintSeq_CreatePyObject */
+/* Description: This function will create a new BPy_ConstraintSeq from an */
+/* existing ListBase structure. */
+/*****************************************************************************/
+PyObject *ObConstraintSeq_CreatePyObject( Object *obj )
+{
+ BPy_ConstraintSeq *pyseq;
+ pyseq = ( BPy_ConstraintSeq * ) PyObject_NEW( BPy_ConstraintSeq,
+ &ConstraintSeq_Type );
+ if( !pyseq )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create BPy_ConstraintSeq object" );
+ pyseq->obj = obj;
+ pyseq->pchan = NULL;
+ return ( PyObject * ) pyseq;
+}
+
+static PyObject *M_Constraint_TypeDict( void )
+{
+ PyObject *S = PyConstant_New( );
+
+ if( S ) {
+ BPy_constant *d = ( BPy_constant * ) S;
+ PyConstant_Insert( d, "NULL",
+ PyInt_FromLong( CONSTRAINT_TYPE_NULL ) );
+ PyConstant_Insert( d, "TRACKTO",
+ PyInt_FromLong( CONSTRAINT_TYPE_TRACKTO ) );
+ PyConstant_Insert( d, "IKSOLVER",
+ PyInt_FromLong( CONSTRAINT_TYPE_KINEMATIC ) );
+ PyConstant_Insert( d, "FOLLOWPATH",
+ PyInt_FromLong( CONSTRAINT_TYPE_FOLLOWPATH ) );
+ PyConstant_Insert( d, "COPYROT",
+ PyInt_FromLong( CONSTRAINT_TYPE_ROTLIKE ) );
+ PyConstant_Insert( d, "COPYLOC",
+ PyInt_FromLong( CONSTRAINT_TYPE_LOCLIKE ) );
+ PyConstant_Insert( d, "COPYSIZE",
+ PyInt_FromLong( CONSTRAINT_TYPE_SIZELIKE ) );
+ PyConstant_Insert( d, "ACTION",
+ PyInt_FromLong( CONSTRAINT_TYPE_ACTION ) );
+ PyConstant_Insert( d, "LOCKTRACK",
+ PyInt_FromLong( CONSTRAINT_TYPE_LOCKTRACK ) );
+ PyConstant_Insert( d, "STRETCHTO",
+ PyInt_FromLong( CONSTRAINT_TYPE_STRETCHTO ) );
+ PyConstant_Insert( d, "FLOOR",
+ PyInt_FromLong( CONSTRAINT_TYPE_MINMAX ) );
+ PyConstant_Insert( d, "LIMITLOC",
+ PyInt_FromLong( CONSTRAINT_TYPE_LOCLIMIT ) );
+ PyConstant_Insert( d, "LIMITROT",
+ PyInt_FromLong( CONSTRAINT_TYPE_ROTLIMIT ) );
+ PyConstant_Insert( d, "LIMITSIZE",
+ PyInt_FromLong( CONSTRAINT_TYPE_SIZELIMIT ) );
+ PyConstant_Insert( d, "RIGIDBODYJOINT",
+ PyInt_FromLong( CONSTRAINT_TYPE_RIGIDBODYJOINT ) );
+ PyConstant_Insert( d, "CLAMPTO",
+ PyInt_FromLong( CONSTRAINT_TYPE_CLAMPTO ) );
+ PyConstant_Insert( d, "PYTHON",
+ PyInt_FromLong( CONSTRAINT_TYPE_PYTHON ) );
+ PyConstant_Insert( d, "CHILDOF",
+ PyInt_FromLong( CONSTRAINT_TYPE_CHILDOF ) );
+ PyConstant_Insert( d, "TRANSFORM",
+ PyInt_FromLong( CONSTRAINT_TYPE_TRANSFORM ) );
+ }
+ return S;
+}
+
+static PyObject *M_Constraint_SettingsDict( void )
+{
+ PyObject *S = PyConstant_New( );
+
+ if( S ) {
+ BPy_constant *d = ( BPy_constant * ) S;
+ PyConstant_Insert( d, "XROT",
+ PyInt_FromLong( EXPP_CONSTR_XROT ) );
+ PyConstant_Insert( d, "YROT",
+ PyInt_FromLong( EXPP_CONSTR_YROT ) );
+ PyConstant_Insert( d, "ZROT",
+ PyInt_FromLong( EXPP_CONSTR_ZROT ) );
+ PyConstant_Insert( d, "XSIZE",
+ PyInt_FromLong( EXPP_CONSTR_XSIZE ) );
+ PyConstant_Insert( d, "YSIZE",
+ PyInt_FromLong( EXPP_CONSTR_YSIZE ) );
+ PyConstant_Insert( d, "ZSIZE",
+ PyInt_FromLong( EXPP_CONSTR_ZSIZE ) );
+ PyConstant_Insert( d, "XLOC",
+ PyInt_FromLong( EXPP_CONSTR_XLOC ) );
+ PyConstant_Insert( d, "YLOC",
+ PyInt_FromLong( EXPP_CONSTR_YLOC ) );
+ PyConstant_Insert( d, "ZLOC",
+ PyInt_FromLong( EXPP_CONSTR_ZLOC ) );
+
+ PyConstant_Insert( d, "UPX",
+ PyInt_FromLong( UP_X ) );
+ PyConstant_Insert( d, "UPY",
+ PyInt_FromLong( UP_Y ) );
+ PyConstant_Insert( d, "UPZ",
+ PyInt_FromLong( UP_Z ) );
+
+ PyConstant_Insert( d, "TRACKX",
+ PyInt_FromLong( TRACK_X ) );
+ PyConstant_Insert( d, "TRACKY",
+ PyInt_FromLong( TRACK_Y ) );
+ PyConstant_Insert( d, "TRACKZ",
+ PyInt_FromLong( TRACK_Z ) );
+ PyConstant_Insert( d, "TRACKNEGX",
+ PyInt_FromLong( TRACK_nX ) );
+ PyConstant_Insert( d, "TRACKNEGY",
+ PyInt_FromLong( TRACK_nY ) );
+ PyConstant_Insert( d, "TRACKNEGZ",
+ PyInt_FromLong( TRACK_nZ ) );
+
+ PyConstant_Insert( d, "VOLUMEXZ",
+ PyInt_FromLong( VOLUME_XZ ) );
+ PyConstant_Insert( d, "VOLUMEX",
+ PyInt_FromLong( VOLUME_X ) );
+ PyConstant_Insert( d, "VOLUMEZ",
+ PyInt_FromLong( VOLUME_Z ) );
+ PyConstant_Insert( d, "VOLUMENONE",
+ PyInt_FromLong( NO_VOLUME ) );
+
+ PyConstant_Insert( d, "PLANEX",
+ PyInt_FromLong( PLANE_X ) );
+ PyConstant_Insert( d, "PLANEY",
+ PyInt_FromLong( PLANE_Y ) );
+ PyConstant_Insert( d, "PLANEZ",
+ PyInt_FromLong( PLANE_Z ) );
+
+ PyConstant_Insert( d, "LOCKX",
+ PyInt_FromLong( LOCK_X ) );
+ PyConstant_Insert( d, "LOCKY",
+ PyInt_FromLong( LOCK_Y ) );
+ PyConstant_Insert( d, "LOCKZ",
+ PyInt_FromLong( LOCK_Z ) );
+
+ PyConstant_Insert( d, "MAXX",
+ PyInt_FromLong( EXPP_CONSTR_MAXX ) );
+ PyConstant_Insert( d, "MAXY",
+ PyInt_FromLong( EXPP_CONSTR_MAXY ) );
+ PyConstant_Insert( d, "MAXZ",
+ PyInt_FromLong( EXPP_CONSTR_MAXZ ) );
+ PyConstant_Insert( d, "MINX",
+ PyInt_FromLong( EXPP_CONSTR_MINX ) );
+ PyConstant_Insert( d, "MINY",
+ PyInt_FromLong( EXPP_CONSTR_MINY ) );
+ PyConstant_Insert( d, "MINZ",
+ PyInt_FromLong( EXPP_CONSTR_MINZ ) );
+
+ PyConstant_Insert( d, "COPYX",
+ PyInt_FromLong( LOCLIKE_X ) );
+ PyConstant_Insert( d, "COPYY",
+ PyInt_FromLong( LOCLIKE_Y ) );
+ PyConstant_Insert( d, "COPYZ",
+ PyInt_FromLong( LOCLIKE_Z ) );
+ PyConstant_Insert( d, "COPYXINVERT",
+ PyInt_FromLong( LOCLIKE_X_INVERT ) );
+ PyConstant_Insert( d, "COPYYINVERT",
+ PyInt_FromLong( LOCLIKE_Y_INVERT ) );
+ PyConstant_Insert( d, "COPYZINVERT",
+ PyInt_FromLong( LOCLIKE_Z_INVERT ) );
+
+ PyConstant_Insert( d, "PARLOCX",
+ PyInt_FromLong( CHILDOF_LOCX ) );
+ PyConstant_Insert( d, "PARLOCY",
+ PyInt_FromLong( CHILDOF_LOCY ) );
+ PyConstant_Insert( d, "PARLOCZ",
+ PyInt_FromLong( CHILDOF_LOCZ ) );
+ PyConstant_Insert( d, "PARROTX",
+ PyInt_FromLong( CHILDOF_ROTX ) );
+ PyConstant_Insert( d, "PARROTY",
+ PyInt_FromLong( CHILDOF_ROTY ) );
+ PyConstant_Insert( d, "PARROTZ",
+ PyInt_FromLong( CHILDOF_ROTZ ) );
+ PyConstant_Insert( d, "PARSIZEX",
+ PyInt_FromLong( CHILDOF_LOCX ) );
+ PyConstant_Insert( d, "PARSIZEY",
+ PyInt_FromLong( CHILDOF_SIZEY ) );
+ PyConstant_Insert( d, "PARSIZEZ",
+ PyInt_FromLong( CHILDOF_SIZEZ ) );
+
+ PyConstant_Insert( d, "CLAMPAUTO",
+ PyInt_FromLong( CLAMPTO_AUTO ) );
+ PyConstant_Insert( d, "CLAMPX",
+ PyInt_FromLong( CLAMPTO_X ) );
+ PyConstant_Insert( d, "CLAMPY",
+ PyInt_FromLong( CLAMPTO_Y ) );
+ PyConstant_Insert( d, "CLAMPZ",
+ PyInt_FromLong( CLAMPTO_Z ) );
+ PyConstant_Insert( d, "CLAMPCYCLIC",
+ PyInt_FromLong( EXPP_CONSTR_CLAMPCYCLIC ));
+
+ PyConstant_Insert( d, "TARGET",
+ PyInt_FromLong( EXPP_CONSTR_TARGET ) );
+ PyConstant_Insert( d, "STRETCH",
+ PyInt_FromLong( EXPP_CONSTR_STRETCH ) );
+ PyConstant_Insert( d, "ITERATIONS",
+ PyInt_FromLong( EXPP_CONSTR_ITERATIONS ) );
+ PyConstant_Insert( d, "BONE",
+ PyInt_FromLong( EXPP_CONSTR_BONE ) );
+ PyConstant_Insert( d, "CHAINLEN",
+ PyInt_FromLong( EXPP_CONSTR_CHAINLEN ) );
+ PyConstant_Insert( d, "POSWEIGHT",
+ PyInt_FromLong( EXPP_CONSTR_POSWEIGHT ) );
+ PyConstant_Insert( d, "ROTWEIGHT",
+ PyInt_FromLong( EXPP_CONSTR_ROTWEIGHT ) );
+ PyConstant_Insert( d, "ROTATE",
+ PyInt_FromLong( EXPP_CONSTR_ROTATE ) );
+ PyConstant_Insert( d, "USETIP",
+ PyInt_FromLong( EXPP_CONSTR_USETIP ) );
+
+ PyConstant_Insert( d, "ACTION",
+ PyInt_FromLong( EXPP_CONSTR_ACTION ) );
+ PyConstant_Insert( d, "START",
+ PyInt_FromLong( EXPP_CONSTR_START ) );
+ PyConstant_Insert( d, "END",
+ PyInt_FromLong( EXPP_CONSTR_END ) );
+ PyConstant_Insert( d, "MIN",
+ PyInt_FromLong( EXPP_CONSTR_MIN ) );
+ PyConstant_Insert( d, "MAX",
+ PyInt_FromLong( EXPP_CONSTR_MAX ) );
+ PyConstant_Insert( d, "KEYON",
+ PyInt_FromLong( EXPP_CONSTR_KEYON ) );
+
+ PyConstant_Insert( d, "TRACK",
+ PyInt_FromLong( EXPP_CONSTR_TRACK ) );
+ PyConstant_Insert( d, "UP",
+ PyInt_FromLong( EXPP_CONSTR_UP ) );
+
+ PyConstant_Insert( d, "RESTLENGTH",
+ PyInt_FromLong( EXPP_CONSTR_RESTLENGTH ) );
+ PyConstant_Insert( d, "VOLVARIATION",
+ PyInt_FromLong( EXPP_CONSTR_VOLVARIATION ) );
+ PyConstant_Insert( d, "VOLUMEMODE",
+ PyInt_FromLong( EXPP_CONSTR_VOLUMEMODE ) );
+ PyConstant_Insert( d, "PLANE",
+ PyInt_FromLong( EXPP_CONSTR_PLANE ) );
+
+ PyConstant_Insert( d, "FOLLOW",
+ PyInt_FromLong( EXPP_CONSTR_FOLLOW ) );
+ PyConstant_Insert( d, "OFFSET",
+ PyInt_FromLong( EXPP_CONSTR_OFFSET ) );
+ PyConstant_Insert( d, "FORWARD",
+ PyInt_FromLong( EXPP_CONSTR_FORWARD ) );
+
+ PyConstant_Insert( d, "LOCK",
+ PyInt_FromLong( EXPP_CONSTR_LOCK ) );
+
+ PyConstant_Insert( d, "COPY",
+ PyInt_FromLong( EXPP_CONSTR_COPY ) );
+ PyConstant_Insert( d, "LIMIT",
+ PyInt_FromLong( EXPP_CONSTR_LIMIT ) );
+ PyConstant_Insert( d, "CLAMP",
+ PyInt_FromLong( EXPP_CONSTR_CLAMP ) );
+
+ PyConstant_Insert( d, "LIMIT_XMIN",
+ PyInt_FromLong( EXPP_CONSTR_LIMXMIN ) );
+ PyConstant_Insert( d, "LIMIT_XMAX",
+ PyInt_FromLong( EXPP_CONSTR_LIMXMAX ) );
+ PyConstant_Insert( d, "LIMIT_YMIN",
+ PyInt_FromLong( EXPP_CONSTR_LIMYMIN ) );
+ PyConstant_Insert( d, "LIMIT_YMAX",
+ PyInt_FromLong( EXPP_CONSTR_LIMYMAX ) );
+ PyConstant_Insert( d, "LIMIT_ZMIN",
+ PyInt_FromLong( EXPP_CONSTR_LIMZMIN ) );
+ PyConstant_Insert( d, "LIMIT_ZMAX",
+ PyInt_FromLong( EXPP_CONSTR_LIMZMAX ) );
+
+ PyConstant_Insert( d, "LIMIT_XROT",
+ PyInt_FromLong( EXPP_CONSTR_LIMXROT ) );
+ PyConstant_Insert( d, "LIMIT_YROT",
+ PyInt_FromLong( EXPP_CONSTR_LIMYROT ) );
+ PyConstant_Insert( d, "LIMIT_ZROT",
+ PyInt_FromLong( EXPP_CONSTR_LIMZROT ) );
+
+ PyConstant_Insert( d, "XMIN",
+ PyInt_FromLong( EXPP_CONSTR_XMIN ) );
+ PyConstant_Insert( d, "XMAX",
+ PyInt_FromLong( EXPP_CONSTR_XMAX ) );
+ PyConstant_Insert( d, "YMIN",
+ PyInt_FromLong( EXPP_CONSTR_YMIN ) );
+ PyConstant_Insert( d, "YMAX",
+ PyInt_FromLong( EXPP_CONSTR_YMAX ) );
+ PyConstant_Insert( d, "ZMIN",
+ PyInt_FromLong( EXPP_CONSTR_ZMIN ) );
+ PyConstant_Insert( d, "ZMAX",
+ PyInt_FromLong( EXPP_CONSTR_ZMAX ) );
+
+ PyConstant_Insert( d, "SCRIPT",
+ PyInt_FromLong( EXPP_CONSTR_SCRIPT ) );
+ PyConstant_Insert( d, "PROPERTIES",
+ PyInt_FromLong( EXPP_CONSTR_PROPS ) );
+
+ PyConstant_Insert( d, "FROM",
+ PyInt_FromLong( EXPP_CONSTR_FROM ) );
+ PyConstant_Insert( d, "TO",
+ PyInt_FromLong( EXPP_CONSTR_TO ) );
+ PyConstant_Insert( d, "EXTRAPOLATE",
+ PyInt_FromLong( EXPP_CONSTR_EXPO ) );
+ PyConstant_Insert( d, "MAPX",
+ PyInt_FromLong( EXPP_CONSTR_MAPX ) );
+ PyConstant_Insert( d, "MAPY",
+ PyInt_FromLong( EXPP_CONSTR_MAPY ) );
+ PyConstant_Insert( d, "MAPZ",
+ PyInt_FromLong( EXPP_CONSTR_MAPZ ) );
+ PyConstant_Insert( d, "FROM_MINX",
+ PyInt_FromLong( EXPP_CONSTR_FROMMINX ) );
+ PyConstant_Insert( d, "FROM_MAXX",
+ PyInt_FromLong( EXPP_CONSTR_FROMMAXX ) );
+ PyConstant_Insert( d, "FROM_MINY",
+ PyInt_FromLong( EXPP_CONSTR_FROMMINY ) );
+ PyConstant_Insert( d, "FROM_MAXY",
+ PyInt_FromLong( EXPP_CONSTR_FROMMAXY ) );
+ PyConstant_Insert( d, "FROM_MINZ",
+ PyInt_FromLong( EXPP_CONSTR_FROMMINZ ) );
+ PyConstant_Insert( d, "FROM_MAXZ",
+ PyInt_FromLong( EXPP_CONSTR_FROMMAXZ ) );
+ PyConstant_Insert( d, "TO_MINX",
+ PyInt_FromLong( EXPP_CONSTR_TOMINX ) );
+ PyConstant_Insert( d, "TO_MAXX",
+ PyInt_FromLong( EXPP_CONSTR_TOMAXX ) );
+ PyConstant_Insert( d, "TO_MINY",
+ PyInt_FromLong( EXPP_CONSTR_TOMINY ) );
+ PyConstant_Insert( d, "TO_MAXY",
+ PyInt_FromLong( EXPP_CONSTR_TOMAXY ) );
+ PyConstant_Insert( d, "TO_MINZ",
+ PyInt_FromLong( EXPP_CONSTR_TOMINZ ) );
+ PyConstant_Insert( d, "TO_MAXZ",
+ PyInt_FromLong( EXPP_CONSTR_TOMAXZ ) );
+
+ PyConstant_Insert( d, "LOC",
+ PyInt_FromLong( 0 ) );
+ PyConstant_Insert( d, "ROT",
+ PyInt_FromLong( 1 ) );
+ PyConstant_Insert( d, "SCALE",
+ PyInt_FromLong( 2 ) );
+
+ PyConstant_Insert( d, "CONSTR_RB_TYPE",
+ PyInt_FromLong( EXPP_CONSTR_RB_TYPE ) );
+ PyConstant_Insert( d, "CONSTR_RB_BALL",
+ PyInt_FromLong( EXPP_CONSTR_RB_BALL ) );
+ PyConstant_Insert( d, "CONSTR_RB_HINGE",
+ PyInt_FromLong( EXPP_CONSTR_RB_HINGE ) );
+ PyConstant_Insert( d, "CONSTR_RB_GENERIC6DOF",
+ PyInt_FromLong( EXPP_CONSTR_RB_GENERIC6DOF ) );
+ PyConstant_Insert( d, "CONSTR_RB_VEHICLE",
+ PyInt_FromLong( EXPP_CONSTR_RB_VEHICLE ) );
+ PyConstant_Insert( d, "CONSTR_RB_PIVX",
+ PyInt_FromLong( EXPP_CONSTR_RB_PIVX ) );
+ PyConstant_Insert( d, "CONSTR_RB_PIVY",
+ PyInt_FromLong( EXPP_CONSTR_RB_PIVY ) );
+ PyConstant_Insert( d, "CONSTR_RB_PIVZ",
+ PyInt_FromLong( EXPP_CONSTR_RB_PIVZ ) );
+ PyConstant_Insert( d, "CONSTR_RB_AXX",
+ PyInt_FromLong( EXPP_CONSTR_RB_AXX ) );
+ PyConstant_Insert( d, "CONSTR_RB_AXY",
+ PyInt_FromLong( EXPP_CONSTR_RB_AXY ) );
+ PyConstant_Insert( d, "CONSTR_RB_AXZ",
+ PyInt_FromLong( EXPP_CONSTR_RB_AXZ ) );
+ PyConstant_Insert( d, "CONSTR_RB_MINLIMIT0",
+ PyInt_FromLong( EXPP_CONSTR_RB_MINLIMIT0 ) );
+ PyConstant_Insert( d, "CONSTR_RB_MINLIMIT1",
+ PyInt_FromLong( EXPP_CONSTR_RB_MINLIMIT1 ) );
+ PyConstant_Insert( d, "CONSTR_RB_MINLIMIT2",
+ PyInt_FromLong( EXPP_CONSTR_RB_MINLIMIT2 ) );
+ PyConstant_Insert( d, "CONSTR_RB_MINLIMIT3",
+ PyInt_FromLong( EXPP_CONSTR_RB_MINLIMIT3 ) );
+ PyConstant_Insert( d, "CONSTR_RB_MINLIMIT4",
+ PyInt_FromLong( EXPP_CONSTR_RB_MINLIMIT4 ) );
+ PyConstant_Insert( d, "CONSTR_RB_MINLIMIT5",
+ PyInt_FromLong( EXPP_CONSTR_RB_MINLIMIT5 ) );
+ PyConstant_Insert( d, "CONSTR_RB_MAXLIMIT0",
+ PyInt_FromLong( EXPP_CONSTR_RB_MAXLIMIT0 ) );
+ PyConstant_Insert( d, "CONSTR_RB_MAXLIMIT1",
+ PyInt_FromLong( EXPP_CONSTR_RB_MAXLIMIT1 ) );
+ PyConstant_Insert( d, "CONSTR_RB_MAXLIMIT2",
+ PyInt_FromLong( EXPP_CONSTR_RB_MAXLIMIT2 ) );
+ PyConstant_Insert( d, "CONSTR_RB_MAXLIMIT3",
+ PyInt_FromLong( EXPP_CONSTR_RB_MAXLIMIT3 ) );
+ PyConstant_Insert( d, "CONSTR_RB_MAXLIMIT4",
+ PyInt_FromLong( EXPP_CONSTR_RB_MAXLIMIT4 ) );
+ PyConstant_Insert( d, "CONSTR_RB_MAXLIMIT5",
+ PyInt_FromLong( EXPP_CONSTR_RB_MAXLIMIT5 ) );
+ PyConstant_Insert( d, "CONSTR_RB_EXTRAFZ",
+ PyInt_FromLong( EXPP_CONSTR_RB_EXTRAFZ ) );
+ PyConstant_Insert( d, "CONSTR_RB_FLAG",
+ PyInt_FromLong( EXPP_CONSTR_RB_FLAG ) );
+
+
+ PyConstant_Insert( d, "OWNERSPACE",
+ PyInt_FromLong( EXPP_CONSTR_OWNSPACE ) );
+ PyConstant_Insert( d, "TARGETSPACE",
+ PyInt_FromLong( EXPP_CONSTR_TARSPACE ) );
+
+ PyConstant_Insert( d, "SPACE_WORLD",
+ PyInt_FromLong( CONSTRAINT_SPACE_WORLD) );
+ PyConstant_Insert( d, "SPACE_LOCAL",
+ PyInt_FromLong( CONSTRAINT_SPACE_LOCAL ) );
+ PyConstant_Insert( d, "SPACE_POSE",
+ PyInt_FromLong( CONSTRAINT_SPACE_POSE) );
+ PyConstant_Insert( d, "SPACE_PARLOCAL",
+ PyInt_FromLong( CONSTRAINT_SPACE_PARLOCAL ) );
+ }
+ return S;
+}
+
+/*****************************************************************************/
+/* Function: Constraint_Init */
+/*****************************************************************************/
+PyObject *Constraint_Init( void )
+{
+ PyObject *submodule;
+ PyObject *TypeDict = M_Constraint_TypeDict( );
+ PyObject *SettingsDict = M_Constraint_SettingsDict( );
+
+ if( PyType_Ready( &ConstraintSeq_Type ) < 0
+ || PyType_Ready( &Constraint_Type ) < 0 )
+ return NULL;
+
+ submodule = Py_InitModule3( "Blender.Constraint", NULL,
+ "Constraint module for accessing and creating constraint data" );
+
+ if( TypeDict )
+ PyModule_AddObject( submodule, "Type", TypeDict );
+
+ if( SettingsDict )
+ PyModule_AddObject( submodule, "Settings", SettingsDict );
+
+ return submodule;
+}
diff --git a/source/blender/python/api2_2x/Constraint.h b/source/blender/python/api2_2x/Constraint.h
new file mode 100644
index 00000000000..116eabbf380
--- /dev/null
+++ b/source/blender/python/api2_2x/Constraint.h
@@ -0,0 +1,76 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Joseph Gilbert, Ken Hughes
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_CONSTRAINT_H
+#define EXPP_CONSTRAINT_H
+
+#include <Python.h>
+#include "DNA_object_types.h"
+#include "DNA_action_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_listBase.h"
+
+/*****************************************************************************/
+/* Python BPy_Modifier structure definition: */
+/*****************************************************************************/
+typedef struct {
+ PyObject_HEAD /* required macro */
+ Object *obj; /* "parent" object */
+ bPoseChannel *pchan;/* "parent" pose channel */
+ /* if con this is null, the constraint has been removed and we need to
+ * raise an error when its data is accessed */
+ bConstraint *con;
+} BPy_Constraint;
+
+extern PyTypeObject Constraint_Type;
+
+#define BPy_Constraint_Check(v) ((v)->ob_type == &Constraint_Type) /* for type checking */
+typedef struct {
+ PyObject_HEAD /* required macro */
+ Object *obj; /* "parent" object */
+ bPoseChannel *pchan;/* "parent" pose channel */
+ bConstraint *iter;
+} BPy_ConstraintSeq;
+
+/*
+ * prototypes
+ */
+
+PyObject *Constraint_Init( void );
+PyObject *Constraint_CreatePyObject( bPoseChannel *pchan, Object *obj,
+ bConstraint *con );
+bConstraint *Constraint_FromPyObject( BPy_Constraint * obj );
+
+PyObject *PoseConstraintSeq_CreatePyObject( bPoseChannel *pchan );
+PyObject *ObConstraintSeq_CreatePyObject( Object *obj );
+
+#endif /* EXPP_CONSTRAINT_H */
diff --git a/source/blender/python/api2_2x/CurNurb.c b/source/blender/python/api2_2x/CurNurb.c
new file mode 100644
index 00000000000..642e7b7b5e6
--- /dev/null
+++ b/source/blender/python/api2_2x/CurNurb.c
@@ -0,0 +1,1078 @@
+/*
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Stephen Swaney, Campbell Barton, Ken Hughes
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "CurNurb.h" /*This must come first */
+
+#include "BKE_curve.h"
+#include "BDR_editcurve.h" /* for convertspline */
+#include "MEM_guardedalloc.h"
+#include "gen_utils.h"
+#include "BezTriple.h"
+
+/*
+ * forward declarations go here
+ */
+
+static PyObject *M_CurNurb_New( PyObject * self, PyObject * args );
+static PyObject *CurNurb_oldsetMatIndex( BPy_CurNurb * self, PyObject * args );
+static int CurNurb_setMatIndex( BPy_CurNurb * self, PyObject * args );
+static PyObject *CurNurb_getMatIndex( BPy_CurNurb * self );
+static PyObject *CurNurb_getFlagU( BPy_CurNurb * self );
+static PyObject *CurNurb_oldsetFlagU( BPy_CurNurb * self, PyObject * args );
+static int CurNurb_setFlagU( BPy_CurNurb * self, PyObject * args );
+static PyObject *CurNurb_getFlagV( BPy_CurNurb * self );
+static PyObject *CurNurb_oldsetFlagV( BPy_CurNurb * self, PyObject * args );
+static int CurNurb_setFlagV( BPy_CurNurb * self, PyObject * args );
+static PyObject *CurNurb_getType( BPy_CurNurb * self );
+static PyObject *CurNurb_oldsetType( BPy_CurNurb * self, PyObject * args );
+static int CurNurb_setType( BPy_CurNurb * self, PyObject * args );
+static PyObject *CurNurb_getKnotsU( BPy_CurNurb * self );
+static PyObject *CurNurb_getKnotsV( BPy_CurNurb * self );
+static PyObject *CurNurb_getPoints( BPy_CurNurb * self );
+/* static PyObject* CurNurb_setXXX( BPy_CurNurb* self, PyObject* args ); */
+static int CurNurb_setPoint( BPy_CurNurb * self, int index, PyObject * ob );
+static int CurNurb_length( PyInstanceObject * inst );
+static PyObject *CurNurb_getIter( BPy_CurNurb * self );
+static PyObject *CurNurb_iterNext( BPy_CurNurb * self );
+PyObject *CurNurb_append( BPy_CurNurb * self, PyObject * value );
+
+static PyObject *CurNurb_isNurb( BPy_CurNurb * self );
+static PyObject *CurNurb_isCyclic( BPy_CurNurb * self );
+static PyObject *CurNurb_dump( BPy_CurNurb * self );
+static PyObject *CurNurb_switchDirection( BPy_CurNurb * self );
+static PyObject *CurNurb_recalc( BPy_CurNurb * self );
+
+char M_CurNurb_doc[] = "CurNurb";
+
+
+/*
+ CurNurb_Type callback function prototypes:
+*/
+
+static int CurNurb_compare( BPy_CurNurb * a, BPy_CurNurb * b );
+static PyObject *CurNurb_repr( BPy_CurNurb * self );
+
+/*
+ table of module methods
+ these are the equivalent of class or static methods.
+ you do not need an object instance to call one.
+
+*/
+
+static PyMethodDef M_CurNurb_methods[] = {
+/* name, method, flags, doc_string */
+ {"New", ( PyCFunction ) M_CurNurb_New, METH_VARARGS | METH_KEYWORDS,
+ " () - doc string"},
+/* {"Get", (PyCFunction) M_CurNurb_method, METH_NOARGS, " () - doc string"}, */
+/* {"method", (PyCFunction) M_CurNurb_method, METH_NOARGS, " () - doc string"}, */
+
+ {NULL, NULL, 0, NULL}
+};
+
+
+
+/*
+ * method table
+ * table of instance methods
+ * these methods are invoked on an instance of the type.
+*/
+
+static PyMethodDef BPy_CurNurb_methods[] = {
+/* name, method, flags, doc */
+/* {"method", (PyCFunction) CurNurb_method, METH_NOARGS, " () - doc string"} */
+ {"setMatIndex", ( PyCFunction ) CurNurb_oldsetMatIndex, METH_VARARGS,
+ "( index ) - set index into materials list"},
+ {"getMatIndex", ( PyCFunction ) CurNurb_getMatIndex, METH_NOARGS,
+ "( ) - get current material index"},
+ {"setFlagU", ( PyCFunction ) CurNurb_oldsetFlagU, METH_VARARGS,
+ "( index ) - set flagU and recalculate the knots (0: uniform, 1: endpoints, 2: bezier)"},
+ {"getFlagU", ( PyCFunction ) CurNurb_getFlagU, METH_NOARGS,
+ "( ) - get flagU of the knots"},
+ {"setFlagV", ( PyCFunction ) CurNurb_oldsetFlagV, METH_VARARGS,
+ "( index ) - set flagV and recalculate the knots (0: uniform, 1: endpoints, 2: bezier)"},
+ {"getFlagV", ( PyCFunction ) CurNurb_getFlagV, METH_NOARGS,
+ "( ) - get flagV of the knots"},
+ {"setType", ( PyCFunction ) CurNurb_oldsetType, METH_VARARGS,
+ "( type ) - change the type of the curve (Poly: 0, Bezier: 1, NURBS: 4)"},
+ {"getType", ( PyCFunction ) CurNurb_getType, METH_NOARGS,
+ "( ) - get the type of the curve (Poly: 0, Bezier: 1, NURBS: 4)"},
+ {"append", ( PyCFunction ) CurNurb_append, METH_O,
+ "( point ) - add a new point. arg is BezTriple or list of x,y,z,w floats"},
+ {"isNurb", ( PyCFunction ) CurNurb_isNurb, METH_NOARGS,
+ "( ) - boolean function tests if this spline is type nurb or bezier"},
+ {"isCyclic", ( PyCFunction ) CurNurb_isCyclic, METH_NOARGS,
+ "( ) - boolean function tests if this spline is cyclic (closed) or not (open)"},
+ {"dump", ( PyCFunction ) CurNurb_dump, METH_NOARGS,
+ "( ) - dumps Nurb data)"},
+ {"switchDirection", ( PyCFunction ) CurNurb_switchDirection, METH_NOARGS,
+ "( ) - swaps curve beginning and end)"},
+ {"recalc", ( PyCFunction ) CurNurb_recalc, METH_NOARGS,
+ "( ) - recalc Nurb data)"},
+ {NULL, NULL, 0, NULL}
+};
+
+/*
+ * methods for CurNurb as sequece
+ */
+
+static PySequenceMethods CurNurb_as_sequence = {
+ ( inquiry ) CurNurb_length, /* sq_length */
+ ( binaryfunc ) 0, /* sq_concat */
+ ( intargfunc ) 0, /* sq_repeat */
+ ( intargfunc ) CurNurb_getPoint, /* sq_item */
+ ( intintargfunc ) 0, /* sq_slice */
+ ( intobjargproc ) CurNurb_setPoint, /* sq_ass_item */
+ 0, /* sq_ass_slice */
+ ( objobjproc ) 0, /* sq_contains */
+ 0,
+ 0
+};
+
+static PyGetSetDef BPy_CurNurb_getseters[] = {
+ {"mat_index",
+ (getter)CurNurb_getMatIndex, (setter)CurNurb_setMatIndex,
+ "CurNurb's material index",
+ NULL},
+ {"points",
+ (getter)CurNurb_getPoints, (setter)NULL,
+ "The number of curve points",
+ NULL},
+ {"flagU",
+ (getter)CurNurb_getFlagU, (setter)CurNurb_setFlagU,
+ "The knot type in the U direction",
+ NULL},
+ {"flagV",
+ (getter)CurNurb_getFlagV, (setter)CurNurb_setFlagV,
+ "The knot type in the V direction",
+ NULL},
+ {"type",
+ (getter)CurNurb_getType, (setter)CurNurb_setType,
+ "The curve type (poly: bezier, or NURBS)",
+ NULL},
+ {"knotsU",
+ (getter)CurNurb_getKnotsU, (setter)NULL,
+ "The The knot vector in the U direction",
+ NULL},
+ {"knotsV",
+ (getter)CurNurb_getKnotsV, (setter)NULL,
+ "The The knot vector in the V direction",
+ NULL},
+
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+/*
+ Object Type definition
+ full blown 2.3 struct
+ if you are having trouble building with an earlier version of python,
+ this is why.
+*/
+
+PyTypeObject CurNurb_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "CurNurb", /* char *tp_name; */
+ sizeof( CurNurb_Type ), /* int tp_basicsize, */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ NULL, /* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ ( cmpfunc ) CurNurb_compare, /* cmpfunc tp_compare; */
+ ( reprfunc ) CurNurb_repr, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ 0, /* PyNumberMethods *tp_as_number; */
+ &CurNurb_as_sequence, /* PySequenceMethods *tp_as_sequence; */
+ 0, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ 0, /* hashfunc tp_hash; */
+ 0, /* ternaryfunc tp_call; */
+ 0, /* reprfunc tp_str; */
+ 0, /* getattrofunc tp_getattro; */
+ 0, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ 0, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ 0, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ 0, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ 0, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ 0, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ ( getiterfunc ) CurNurb_getIter, /* getiterfunc tp_iter; */
+ ( iternextfunc ) CurNurb_iterNext, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_CurNurb_methods, /* struct PyMethodDef *tp_methods; */
+ 0, /* struct PyMemberDef *tp_members; */
+ BPy_CurNurb_getseters, /* struct PyGetSetDef *tp_getset; */
+ 0, /* struct _typeobject *tp_base; */
+ 0, /* PyObject *tp_dict; */
+ 0, /* descrgetfunc tp_descr_get; */
+ 0, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ 0, /* initproc tp_init; */
+ 0, /* allocfunc tp_alloc; */
+ 0, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ 0, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ 0, /* inquiry tp_is_gc; */
+ 0, /* PyObject *tp_bases; */
+ /* method resolution order */
+ 0, /* PyObject *tp_mro; */
+ 0, /* PyObject *tp_cache; */
+ 0, /* PyObject *tp_subclasses; */
+ 0, /* PyObject *tp_weaklist; */
+ 0
+};
+
+/*
+ compare
+ in this case, we consider two CurNurbs equal, if they point to the same
+ blender data.
+*/
+
+static int CurNurb_compare( BPy_CurNurb * a, BPy_CurNurb * b )
+{
+ Nurb *pa = a->nurb;
+ Nurb *pb = b->nurb;
+
+ return ( pa == pb ) ? 0 : -1;
+}
+
+
+/*
+ factory method to create a BPy_CurNurb from a Blender Nurb
+*/
+
+PyObject *CurNurb_CreatePyObject( Nurb * blen_nurb )
+{
+ BPy_CurNurb *pyNurb;
+
+ pyNurb = ( BPy_CurNurb * ) PyObject_NEW( BPy_CurNurb, &CurNurb_Type );
+
+ if( !pyNurb )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "could not create BPy_CurNurb PyObject" );
+
+ pyNurb->nurb = blen_nurb;
+ return ( PyObject * ) pyNurb;
+}
+
+
+/*
+ * CurNurb_repr
+ */
+static PyObject *CurNurb_repr( BPy_CurNurb * self )
+{ /* used by 'repr' */
+
+ return PyString_FromFormat( "[CurNurb \"%d\"]", self->nurb->type );
+}
+
+/* XXX Can't this be simply removed? */
+static PyObject *M_CurNurb_New( PyObject * self, PyObject * args )
+{
+ return ( PyObject * ) 0;
+
+}
+
+/*
+ * Curve.getType
+ */
+static PyObject *CurNurb_getType( BPy_CurNurb * self )
+{
+ /* type is on 3 first bits only */
+ return PyInt_FromLong( self->nurb->type & 7 );
+}
+
+/*
+ * Curve.setType
+ *
+ * Convert the curve using Blender's convertspline fonction
+ */
+static int CurNurb_setType( BPy_CurNurb * self, PyObject * args )
+{
+ PyObject* integer = PyNumber_Int( args );
+ short value;
+
+ if( !integer )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected integer argument" );
+
+ value = ( short )PyInt_AS_LONG( integer );
+ Py_DECREF( integer );
+
+ /* parameter value checking */
+ if (value != CU_POLY && value != CU_BEZIER && value != CU_NURBS)
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "expected integer argument" );
+
+ /* convert and raise error if impossible */
+ if (convertspline(value, self->nurb))
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "Conversion Impossible" );
+
+ return 0;
+}
+
+/*
+ * CurNurb_getKnotsU
+ *
+ * returns curve's knotsU in a tuple. Empty tuple is returned if curve
+ * isn't Nurbs or it doesn't have knots in U
+ */
+
+static PyObject *CurNurb_getKnotsU( BPy_CurNurb * self )
+{
+ if(self->nurb->knotsu) {
+ int len = KNOTSU(self->nurb);
+ int i;
+ PyObject *knotsu = PyTuple_New(len);
+ if( !knotsu )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "could not get CurNurb.knotsU attribute" );
+
+ for(i = 0; i < len; ++i)
+ PyTuple_SetItem(knotsu, i,
+ PyFloat_FromDouble(self->nurb->knotsu[i]));
+
+ return knotsu;
+ }
+ return PyTuple_New(0);
+}
+
+/*
+ * CurNurb_getKnotsV
+ *
+ * returns curve's knotsV in a tuple. Empty tuple is returned if curve doesn't have knots in V
+ */
+
+static PyObject *CurNurb_getKnotsV( BPy_CurNurb * self )
+{
+ if(self->nurb->knotsv) {
+ int len = KNOTSV(self->nurb);
+ int i;
+ PyObject *knotsv = PyTuple_New(len);
+ if( !knotsv )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "could not get CurNurb.knotsV index" );
+
+ for(i = 0; i < len; ++i)
+ PyTuple_SetItem(knotsv, i,
+ PyFloat_FromDouble(self->nurb->knotsv[i] ));
+
+ return knotsv;
+ }
+ return PyTuple_New(0);
+}
+
+static PyObject *CurNurb_getPoints( BPy_CurNurb * self )
+{
+ return PyInt_FromLong( ( long ) self->nurb->pntsu );
+}
+
+/*
+ * CurNurb_append( point )
+ * append a new point to a nurb curve.
+ * arg is BezTriple or list of xyzw floats
+ */
+
+PyObject *CurNurb_append( BPy_CurNurb * self, PyObject * value )
+{
+ return CurNurb_appendPointToNurb( self->nurb, value );
+}
+
+
+/*
+ * CurNurb_appendPointToNurb
+ * this is a non-bpy utility func to add a point to a given nurb.
+ * notice the first arg is Nurb*.
+ */
+
+PyObject *CurNurb_appendPointToNurb( Nurb * nurb, PyObject * value )
+{
+
+ int i;
+ int size;
+ int npoints = nurb->pntsu;
+
+ /*
+ do we have a list of four floats or a BezTriple?
+ */
+
+ /* if curve is empty, adjust type depending on input type */
+ if (nurb->bezt==NULL && nurb->bp==NULL) {
+ if (BPy_BezTriple_Check( value ))
+ nurb->type |= CU_BEZIER;
+ else if (PySequence_Check( value ))
+ nurb->type |= CU_NURBS;
+ else
+ return( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "Expected a BezTriple or a Sequence of 4 (or 5) floats" ) );
+ }
+
+
+
+ if ((nurb->type & 7)==CU_BEZIER) {
+ BezTriple *tmp;
+
+ if( !BPy_BezTriple_Check( value ) )
+ return( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "Expected a BezTriple\n" ) );
+
+/* printf("\ndbg: got a BezTriple\n"); */
+ tmp = nurb->bezt; /* save old points */
+ nurb->bezt =
+ ( BezTriple * ) MEM_mallocN( sizeof( BezTriple ) *
+ ( npoints + 1 ),
+ "CurNurb_append2" );
+
+ if( !nurb->bezt )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_MemoryError, "allocation failed" ) );
+
+ /* copy old points to new */
+ if( tmp ) {
+ memmove( nurb->bezt, tmp, sizeof( BezTriple ) * npoints );
+ MEM_freeN( tmp );
+ }
+
+ nurb->pntsu++;
+ /* add new point to end of list */
+ memcpy( nurb->bezt + npoints,
+ BezTriple_FromPyObject( value ), sizeof( BezTriple ) );
+
+ }
+ else if( PySequence_Check( value ) ) {
+ size = PySequence_Size( value );
+/* printf("\ndbg: got a sequence of size %d\n", size ); */
+ if( size == 4 || size == 5 ) {
+ BPoint *tmp;
+
+ tmp = nurb->bp; /* save old pts */
+
+ nurb->bp =
+ ( BPoint * ) MEM_mallocN( sizeof( BPoint ) *
+ ( npoints + 1 ),
+ "CurNurb_append1" );
+ if( !nurb->bp )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_MemoryError,
+ "allocation failed" ) );
+
+ memmove( nurb->bp, tmp, sizeof( BPoint ) * npoints );
+ if( tmp )
+ MEM_freeN( tmp );
+
+ ++nurb->pntsu;
+ /* initialize new BPoint from old */
+ memcpy( nurb->bp + npoints, nurb->bp,
+ sizeof( BPoint ) );
+
+ for( i = 0; i < 4; ++i ) {
+ PyObject *item = PySequence_GetItem( value, i );
+
+ if (item == NULL)
+ return NULL;
+
+
+ nurb->bp[npoints].vec[i] = ( float ) PyFloat_AsDouble( item );
+ Py_DECREF( item );
+ }
+
+ if (size == 5) {
+ PyObject *item = PySequence_GetItem( value, i );
+
+ if (item == NULL)
+ return NULL;
+
+ nurb->bp[npoints].alfa = ( float ) PyFloat_AsDouble( item );
+ Py_DECREF( item );
+ }
+ else {
+ nurb->bp[npoints].alfa = 0.0f;
+ }
+
+ makeknots( nurb, 1, nurb->flagu >> 1 );
+
+ } else {
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a sequence of 4 or 5 floats" );
+ }
+
+ } else {
+ /* bail with error */
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a sequence of 4 or 5 floats" );
+
+ }
+
+ Py_RETURN_NONE;
+}
+
+
+/*
+ * CurNurb_setMatIndex
+ *
+ * set index into material list
+ */
+
+static int CurNurb_setMatIndex( BPy_CurNurb * self, PyObject * args )
+{
+ printf ("%d\n", self->nurb->mat_nr);
+ return EXPP_setIValueRange( args, &self->nurb->mat_nr, 0, 15, 'h' );
+}
+
+/*
+ * CurNurb_getMatIndex
+ *
+ * returns index into material list
+ */
+
+static PyObject *CurNurb_getMatIndex( BPy_CurNurb * self )
+{
+ PyObject *index = PyInt_FromLong( ( long ) self->nurb->mat_nr );
+
+ if( index )
+ return index;
+
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "could not get material index" );
+}
+
+/*
+ * CurNurb_getFlagU
+ *
+ * returns curve's flagu
+ */
+
+static PyObject *CurNurb_getFlagU( BPy_CurNurb * self )
+{
+ PyObject *flagu = PyInt_FromLong( ( long ) self->nurb->flagu );
+
+ if( flagu )
+ return flagu;
+
+ return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "could not get CurNurb.flagu index" ) );
+}
+
+/*
+ * CurNurb_setFlagU
+ *
+ * set curve's flagu and recalculate the knots
+ *
+ * Possible values: 0 - uniform, 2 - endpoints, 4 - bezier
+ * bit 0 controls CU_CYCLIC
+ */
+
+static int CurNurb_setFlagU( BPy_CurNurb * self, PyObject * args )
+{
+ PyObject* integer = PyNumber_Int( args );
+ short value;
+
+ if( !integer )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected integer argument" );
+
+ value = ( short )PyInt_AS_LONG( integer );
+ Py_DECREF( integer );
+
+ if( value < 0 || value > 5 )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "expected integer argument in range [0,5]" );
+
+ if( self->nurb->flagu != value ) {
+ self->nurb->flagu = (short)value;
+ makeknots( self->nurb, 1, self->nurb->flagu >> 1 );
+ }
+
+ return 0;
+}
+
+/*
+ * CurNurb_getFlagV
+ *
+ * returns curve's flagu
+ */
+
+static PyObject *CurNurb_getFlagV( BPy_CurNurb * self )
+{
+ PyObject *flagv = PyInt_FromLong( ( long ) self->nurb->flagv );
+
+ if( flagv )
+ return flagv;
+
+ return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "could not get CurNurb.flagv" ) );
+}
+
+/*
+ * CurNurb_setFlagV
+ *
+ * set curve's flagu and recalculate the knots
+ *
+ * Possible values: 0 - uniform, 1 - endpoints, 2 - bezier
+ */
+
+static int CurNurb_setFlagV( BPy_CurNurb * self, PyObject * args )
+{
+ PyObject* integer = PyNumber_Int( args );
+ short value;
+
+ if( !integer )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected integer argument" );
+
+ value = ( short )PyInt_AS_LONG( integer );
+ Py_DECREF( integer );
+
+ if( value < 0 || value > 5 )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "expected integer argument in range [0,5]" );
+
+ if( self->nurb->flagv != value ) {
+ self->nurb->flagv = (short)value;
+ makeknots( self->nurb, 2, self->nurb->flagv >> 1 );
+ }
+
+ return 0;
+}
+
+/*
+ * CurNurb_getIter
+ *
+ * create an iterator for our CurNurb.
+ * this iterator returns the points for this CurNurb.
+ */
+
+static PyObject *CurNurb_getIter( BPy_CurNurb * self )
+{
+ self->bp = self->nurb->bp;
+ self->bezt = self->nurb->bezt;
+ self->atEnd = 0;
+ self->nextPoint = 0;
+
+ /* set exhausted flag if both bp and bezt are zero */
+ if( ( !self->bp ) && ( !self->bezt ) )
+ self->atEnd = 1;
+
+ Py_INCREF( self );
+ return ( PyObject * ) self;
+}
+
+
+static PyObject *CurNurb_iterNext( BPy_CurNurb * self )
+{
+ PyObject *po; /* return value */
+ Nurb *pnurb = self->nurb;
+ int npoints = pnurb->pntsu;
+
+ /* are we at end already? */
+ if( self->atEnd )
+ return ( EXPP_ReturnPyObjError( PyExc_StopIteration,
+ "iterator at end" ) );
+
+ if( self->nextPoint < npoints ) {
+
+ po = CurNurb_pointAtIndex( self->nurb, self->nextPoint );
+ self->nextPoint++;
+
+ return po;
+
+ } else {
+ self->atEnd = 1; /* set flag true */
+ }
+
+ return ( EXPP_ReturnPyObjError( PyExc_StopIteration,
+ "iterator at end" ) );
+}
+
+
+
+/*
+ * CurNurb_isNurb()
+ * test whether spline nurb or bezier
+ */
+
+static PyObject *CurNurb_isNurb( BPy_CurNurb * self )
+{
+ /* NOTE: a Nurb has bp and bezt pointers
+ * depending on type.
+ * It is possible both are NULL if no points exist.
+ * in that case, we return False
+ */
+
+ if( self->nurb->bp ) {
+ return EXPP_incr_ret_True();
+ } else {
+ return EXPP_incr_ret_False();
+ }
+}
+
+/*
+ * CurNurb_isCyclic()
+ * test whether spline cyclic (closed) or not (open)
+ */
+
+static PyObject *CurNurb_isCyclic( BPy_CurNurb * self )
+{
+ /* supposing that the flagu is always set */
+
+ if( self->nurb->flagu & CU_CYCLIC ) {
+ return EXPP_incr_ret_True();
+ } else {
+ return EXPP_incr_ret_False();
+ }
+}
+
+/*
+ * CurNurb_length
+ * returns the number of points in a Nurb
+ * this is a tp_as_sequence method, not a regular instance method.
+ */
+
+static int CurNurb_length( PyInstanceObject * inst )
+{
+ Nurb *nurb;
+ int len;
+
+ if( BPy_CurNurb_Check( ( PyObject * ) inst ) ) {
+ nurb = ( ( BPy_CurNurb * ) inst )->nurb;
+ len = nurb->pntsu;
+ return len;
+ }
+
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "arg is not a BPy_CurNurb" );
+}
+
+/*
+ * CurNurb_getPoint
+ * returns the Nth point in a Nurb
+ * this is one of the tp_as_sequence methods, hence the int N argument.
+ * it is called via the [] operator, not as a usual instance method.
+ */
+
+PyObject *CurNurb_getPoint( BPy_CurNurb * self, int index )
+{
+ Nurb *myNurb;
+
+ int npoints;
+
+ /* for convenince */
+ myNurb = self->nurb;
+ npoints = myNurb->pntsu;
+
+ /* DELETED: bail if index < 0 */
+ /* actually, this check is not needed since python treats */
+ /* negative indices as starting from the right end of a sequence */
+ /*
+ THAT IS WRONG, when passing a negative index, python adjusts it to be positive
+ BUT it can still overflow in the negatives if the index is too small.
+ For example, list[-6] when list contains 5 items means index = -1 in here.
+ (theeth)
+ */
+
+ /* bail if no Nurbs in Curve */
+ if( npoints == 0 )
+ return ( EXPP_ReturnPyObjError( PyExc_IndexError,
+ "no points in this CurNurb" ) );
+
+ /* check index limits */
+ if( index >= npoints || index < 0 )
+ return ( EXPP_ReturnPyObjError( PyExc_IndexError,
+ "index out of range" ) );
+
+ return CurNurb_pointAtIndex( myNurb, index );
+}
+
+/*
+ * CurNurb_setPoint
+ * modifies the Nth point in a Nurb
+ * this is one of the tp_as_sequence methods, hence the int N argument.
+ * it is called via the [] = operator, not as a usual instance method.
+ */
+static int CurNurb_setPoint( BPy_CurNurb * self, int index, PyObject * pyOb )
+{
+ Nurb *nurb = self->nurb;
+ int size;
+
+ /* check index limits */
+ if( index < 0 || index >= nurb->pntsu )
+ return EXPP_ReturnIntError( PyExc_IndexError,
+ "array assignment index out of range" );
+
+
+ /* branch by curve type */
+ if ((nurb->type & 7)==CU_BEZIER) { /* BEZIER */
+ /* check parameter type */
+ if( !BPy_BezTriple_Check( pyOb ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a BezTriple" );
+
+ /* copy bezier in array */
+ memcpy( nurb->bezt + index,
+ BezTriple_FromPyObject( pyOb ), sizeof( BezTriple ) );
+
+ return 0; /* finished correctly */
+ }
+ else { /* NURBS or POLY */
+ int i;
+
+ /* check parameter type */
+ if (!PySequence_Check( pyOb ))
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a list of 4 (or optionally 5 if the curve is 3D) floats" );
+
+ size = PySequence_Size( pyOb );
+
+ /* check sequence size */
+ if( size != 4 && size != 5 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a list of 4 (or optionally 5 if the curve is 3D) floats" );
+
+ /* copy x, y, z, w */
+ for( i = 0; i < 4; ++i ) {
+ PyObject *item = PySequence_GetItem( pyOb, i );
+
+ if (item == NULL)
+ return -1;
+
+ nurb->bp[index].vec[i] = ( float ) PyFloat_AsDouble( item );
+ Py_DECREF( item );
+ }
+
+ if (size == 5) { /* set tilt, if present */
+ PyObject *item = PySequence_GetItem( pyOb, i );
+
+ if (item == NULL)
+ return -1;
+
+ nurb->bp[index].alfa = ( float ) PyFloat_AsDouble( item );
+ Py_DECREF( item );
+ }
+ else { /* if not, set default */
+ nurb->bp[index].alfa = 0.0f;
+ }
+
+ return 0; /* finished correctly */
+ }
+}
+
+
+/*
+ * this is an internal routine. not callable directly from python
+ */
+
+PyObject *CurNurb_pointAtIndex( Nurb * nurb, int index )
+{
+ PyObject *pyo;
+
+ if( nurb->bp ) { /* we have a nurb curve */
+ int i;
+
+ /* add Tilt only if curve is 3D */
+ if (nurb->flag & CU_3D)
+ pyo = PyList_New( 5 );
+ else
+ pyo = PyList_New( 4 );
+
+ for( i = 0; i < 4; i++ ) {
+ PyList_SetItem( pyo, i,
+ PyFloat_FromDouble( nurb->bp[index].vec[i] ) );
+ }
+
+ /* add Tilt only if curve is 3D */
+ if (nurb->flag & CU_3D)
+ PyList_SetItem( pyo, 4, PyFloat_FromDouble( nurb->bp[index].alfa ) );
+
+ } else if( nurb->bezt ) { /* we have a bezier */
+ /* if an error occurs, we just pass it on */
+ pyo = BezTriple_CreatePyObject( &( nurb->bezt[index] ) );
+
+ } else /* something is horribly wrong */
+ /* neither bp or bezt is set && pntsu != 0 */
+ return EXPP_ReturnPyObjError( PyExc_SystemError,
+ "inconsistant structure found" );
+
+ return pyo;
+}
+
+/*
+ dump nurb
+*/
+
+PyObject *CurNurb_dump( BPy_CurNurb * self )
+{
+ BPoint *bp = NULL;
+ BezTriple *bezt = NULL;
+ Nurb *nurb = self->nurb;
+ int npoints = 0;
+
+ if( !self->nurb )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "no Nurb in this CurNurb");
+
+ printf(" type: %d, mat_nr: %d hide: %d flag: %d",
+ nurb->type, nurb->mat_nr, nurb->hide, nurb->flag);
+ printf("\n pntsu: %d, pntsv: %d, resolu: %d resolv: %d",
+ nurb->pntsu, nurb->pntsv, nurb->resolu, nurb->resolv );
+ printf("\n orderu: %d orderv: %d", nurb->orderu, nurb->orderv );
+ printf("\n flagu: %d flagv: %d",
+ nurb->flagu, nurb->flagv );
+
+ npoints = nurb->pntsu;
+
+ if( nurb->bp ) { /* we have a BPoint */
+ int n;
+ for( n = 0, bp = nurb->bp;
+ n < npoints;
+ n++, bp++ )
+ {
+ /* vec[4] */
+ printf( "\ncoords[%d]: ", n);
+ {
+ int i;
+ for( i = 0; i < 4; i++){
+ printf("%10.3f ", bp->vec[i] );
+ }
+ }
+
+ /* alfa, s[2] */
+ printf("\n alpha: %5.2f", bp->alfa);
+ /* f1, hide */
+ printf(" f1 %d hide %d", bp->f1, bp->hide );
+ printf("\n");
+ }
+ }
+ else { /* we have a BezTriple */
+ int n;
+ for( n = 0, bezt = nurb->bezt;
+ n < npoints;
+ n++, bezt++ )
+ {
+ int i, j;
+ printf("\npoint %d: ", n);
+ for( i = 0; i < 3; i++ ) {
+ printf("\nvec[%i] ",i );
+ for( j = 0; j < 3; j++ ) {
+ printf(" %5.2f ", bezt->vec[i][j] );
+ }
+ }
+
+
+ }
+ printf("\n");
+ }
+
+ Py_RETURN_NONE;
+}
+
+/*
+ recalc nurb
+*/
+
+static PyObject *CurNurb_recalc( BPy_CurNurb * self )
+{
+ calchandlesNurb ( self->nurb );
+ Py_RETURN_NONE;
+}
+
+PyObject *CurNurb_switchDirection( BPy_CurNurb * self )
+{
+ if( !self->nurb )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "no Nurb in this CurNurb");
+
+ switchdirectionNurb( self->nurb );
+
+ Py_RETURN_NONE;
+}
+
+PyObject *CurNurb_Init( void )
+{
+ if( PyType_Ready( &CurNurb_Type ) < 0)
+ return NULL;
+
+ return Py_InitModule3( "Blender.CurNurb", M_CurNurb_methods,
+ M_CurNurb_doc );
+}
+
+/* #####DEPRECATED###### */
+
+static PyObject *CurNurb_oldsetType( BPy_CurNurb * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args,
+ (setter)CurNurb_setType );
+}
+
+static PyObject *CurNurb_oldsetMatIndex( BPy_CurNurb * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args,
+ (setter)CurNurb_setMatIndex );
+}
+
+static PyObject *CurNurb_oldsetFlagU( BPy_CurNurb * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args,
+ (setter)CurNurb_setFlagU );
+}
+
+static PyObject *CurNurb_oldsetFlagV( BPy_CurNurb * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args,
+ (setter)CurNurb_setFlagV );
+}
diff --git a/source/blender/python/api2_2x/CurNurb.h b/source/blender/python/api2_2x/CurNurb.h
new file mode 100644
index 00000000000..06dbf7190ac
--- /dev/null
+++ b/source/blender/python/api2_2x/CurNurb.h
@@ -0,0 +1,70 @@
+/*
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Stephen Swaney
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef EXPP_NURB_H
+#define EXPP_NURB_H
+
+#include <Python.h>
+#include "DNA_curve_types.h"
+
+extern PyTypeObject CurNurb_Type;
+
+#define BPy_CurNurb_Check(v) ((v)->ob_type == &CurNurb_Type) /* for type checking */
+
+/* Python BPy_CurNurb structure definition */
+typedef struct {
+ PyObject_HEAD /* required py macro */
+ Nurb * nurb; /* pointer to Blender data */
+
+ /* iterator stuff */
+ /* internal ptrs to point data. do not free */
+ BPoint *bp;
+ BezTriple *bezt;
+ int atEnd; /* iter exhausted flag */
+ int nextPoint;
+
+} BPy_CurNurb;
+
+
+/*
+ * prototypes
+ */
+
+PyObject *CurNurb_Init( void );
+PyObject *CurNurb_CreatePyObject( Nurb * bzt );
+Nurb *CurNurb_FromPyObject( PyObject * pyobj );
+
+PyObject *CurNurb_getPoint( BPy_CurNurb * self, int index );
+PyObject *CurNurb_pointAtIndex( Nurb * nurb, int index );
+
+PyObject *CurNurb_appendPointToNurb( Nurb * nurb, PyObject * args );
+
+#endif /* EXPP_NURB_H */
diff --git a/source/blender/python/api2_2x/Curve.c b/source/blender/python/api2_2x/Curve.c
new file mode 100644
index 00000000000..e849522ef00
--- /dev/null
+++ b/source/blender/python/api2_2x/Curve.c
@@ -0,0 +1,1659 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Jacques Guignot, Stephen Swaney
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "Curve.h" /*This must come first*/
+
+#include "BLI_blenlib.h"
+#include "BKE_main.h"
+#include "BKE_displist.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_curve.h"
+#include "BKE_material.h"
+#include "MEM_guardedalloc.h" /* because we wil be mallocing memory */
+#include "CurNurb.h"
+#include "SurfNurb.h"
+#include "Material.h"
+#include "Object.h"
+#include "Key.h"
+#include "gen_utils.h"
+#include "gen_library.h"
+#include "mydevice.h"
+
+
+/*****************************************************************************/
+/* The following string definitions are used for documentation strings. */
+/* In Python these will be written to the console when doing a */
+/* Blender.Curve.__doc__ */
+/*****************************************************************************/
+
+char M_Curve_doc[] = "The Blender Curve module\n\n\
+This module provides access to **Curve Data** in Blender.\n\
+Functions :\n\
+ New(opt name) : creates a new curve object with the given name (optional)\n\
+ Get(name) : retreives a curve with the given name (mandatory)\n\
+ get(name) : same as Get. Kept for compatibility reasons";
+char M_Curve_New_doc[] = "";
+char M_Curve_Get_doc[] = "xxx";
+
+
+
+/*****************************************************************************/
+/* Python API function prototypes for the Curve module. */
+/*****************************************************************************/
+static PyObject *M_Curve_New( PyObject * self, PyObject * args );
+static PyObject *M_Curve_Get( PyObject * self, PyObject * args );
+
+
+/*****************************************************************************/
+/* Python BPy_Curve instance methods declarations: */
+/*****************************************************************************/
+
+static PyObject *Curve_getPathLen( BPy_Curve * self );
+static PyObject *Curve_setPathLen( BPy_Curve * self, PyObject * args );
+static PyObject *Curve_getTotcol( BPy_Curve * self );
+static PyObject *Curve_setTotcol( BPy_Curve * self, PyObject * args );
+#if 0
+PyObject *Curve_getResolu( BPy_Curve * self );
+PyObject *Curve_setResolu( BPy_Curve * self, PyObject * args );
+PyObject *Curve_getResolv( BPy_Curve * self );
+PyObject *Curve_setResolv( BPy_Curve * self, PyObject * args );
+PyObject *Curve_getWidth( BPy_Curve * self );
+PyObject *Curve_setWidth( BPy_Curve * self, PyObject * args );
+PyObject *Curve_getExt1( BPy_Curve * self );
+PyObject *Curve_setExt1( BPy_Curve * self, PyObject * args );
+PyObject *Curve_getExt2( BPy_Curve * self );
+PyObject *Curve_setExt2( BPy_Curve * self, PyObject * args );
+#endif
+static PyObject *Curve_getControlPoint( BPy_Curve * self, PyObject * args );
+static PyObject *Curve_setControlPoint( BPy_Curve * self, PyObject * args );
+static PyObject *Curve_getLoc( BPy_Curve * self );
+static PyObject *Curve_setLoc( BPy_Curve * self, PyObject * args );
+static PyObject *Curve_getRot( BPy_Curve * self );
+static PyObject *Curve_setRot( BPy_Curve * self, PyObject * args );
+static PyObject *Curve_getSize( BPy_Curve * self );
+static PyObject *Curve_setSize( BPy_Curve * self, PyObject * args );
+static PyObject *Curve_getNumCurves( BPy_Curve * self );
+static PyObject *Curve_getKey( BPy_Curve * self );
+static PyObject *Curve_isNurb( BPy_Curve * self, PyObject * args );
+static PyObject *Curve_isCyclic( BPy_Curve * self, PyObject * args);
+static PyObject *Curve_getNumPoints( BPy_Curve * self, PyObject * args );
+
+static PyObject *Curve_appendPoint( BPy_Curve * self, PyObject * args );
+static PyObject *Curve_appendNurb( BPy_Curve * self, PyObject * args );
+
+static PyObject *Curve_getMaterials( BPy_Curve * self );
+
+static PyObject *Curve_getBevOb( BPy_Curve * self );
+static PyObject *Curve_setBevOb( BPy_Curve * self, PyObject * args );
+
+static PyObject *Curve_getTaperOb( BPy_Curve * self );
+static PyObject *Curve_setTaperOb( BPy_Curve * self, PyObject * args );
+static PyObject *Curve_copy( BPy_Curve * self );
+
+static PyObject *Curve_getIter( BPy_Curve * self );
+static PyObject *Curve_iterNext( BPy_Curve * self );
+
+PyObject *Curve_getNurb( BPy_Curve * self, int n );
+static int Curve_length( PyInstanceObject * inst );
+
+
+struct chartrans *text_to_curve( Object * ob, int mode );
+/*****************************************************************************/
+/* Python BPy_Curve methods: */
+/* gives access to */
+/* name, pathlen totcol flag bevresol */
+/* resolu resolv width ext1 ext2 */
+/* controlpoint loc rot size */
+/* numpts */
+/*****************************************************************************/
+
+
+PyObject *Curve_getName( BPy_Curve * self )
+{
+ return PyString_FromString( self->curve->id.name + 2 );
+}
+
+static int Curve_newsetName( BPy_Curve * self, PyObject * args )
+{
+ char *name;
+
+ name = PyString_AsString( args );
+ if( !name )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected string argument" );
+
+ rename_id( &self->curve->id, name ); /* proper way in Blender */
+ Curve_update( self );
+
+ return 0;
+}
+
+static PyObject *Curve_getPathLen( BPy_Curve * self )
+{
+ return PyInt_FromLong( ( long ) self->curve->pathlen );
+}
+
+
+static int Curve_newsetPathLen( BPy_Curve * self, PyObject * args )
+{
+ PyObject *num;
+
+ if( !PyNumber_Check( args ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected int argument" );
+
+ num = PyNumber_Int( args );
+ self->curve->pathlen = (short)PyInt_AS_LONG( num );
+ Py_DECREF( num );
+
+ return 0;
+}
+
+static PyObject *Curve_getTotcol( BPy_Curve * self )
+{
+ return PyInt_FromLong( ( long ) self->curve->totcol );
+}
+
+
+PyObject *Curve_getMode( BPy_Curve * self )
+{
+ return PyInt_FromLong( ( long ) self->curve->flag );
+}
+
+
+static int Curve_newsetMode( BPy_Curve * self, PyObject * args )
+{
+ PyObject *num;
+
+ if( !PyNumber_Check( args ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected int argument" );
+
+ num = PyNumber_Int( args );
+ self->curve->flag = (short)PyInt_AS_LONG( num );
+ Py_DECREF( num );
+
+ return 0;
+}
+
+PyObject *Curve_getBevresol( BPy_Curve * self )
+{
+ return PyInt_FromLong( ( long ) self->curve->bevresol );
+}
+
+static int Curve_newsetBevresol( BPy_Curve * self, PyObject * args )
+{
+ short value;
+ PyObject *num;
+
+ if( !PyNumber_Check( args ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected int argument" );
+
+ num = PyNumber_Int( args );
+ value = (short)PyInt_AS_LONG( num );
+ Py_DECREF( num );
+
+ if( value > 10 || value < 0 )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "acceptable values are between 0 and 10" );
+
+ self->curve->bevresol = value;
+ return 0;
+}
+
+
+PyObject *Curve_getResolu( BPy_Curve * self )
+{
+ return PyInt_FromLong( ( long ) self->curve->resolu );
+}
+
+
+static int Curve_newsetResolu( BPy_Curve * self, PyObject * args )
+{
+ short value;
+ Nurb *nu;
+ PyObject *num;
+
+ if( !PyNumber_Check( args ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected int argument" );
+
+ num = PyNumber_Int( args );
+ value = (short)PyInt_AS_LONG( num );
+ Py_DECREF( num );
+
+ if( value > 128 || value < 1 )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "acceptable values are between 1 and 128" );
+
+ self->curve->resolu = value;
+ /* propagate the change through all the curves */
+ for( nu = self->curve->nurb.first; nu; nu = nu->next )
+ nu->resolu = value;
+
+ return 0;
+}
+
+PyObject *Curve_getResolv( BPy_Curve * self )
+{
+ return PyInt_FromLong( ( long ) self->curve->resolv );
+}
+
+static int Curve_newsetResolv( BPy_Curve * self, PyObject * args )
+{
+ short value;
+ PyObject *num;
+
+ if( !PyNumber_Check( args ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected int argument" );
+
+ num = PyNumber_Int( args );
+ value = (short)PyInt_AS_LONG( num );
+ Py_DECREF( num );
+
+ if(value > 128 || value < 1)
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "acceptable values are between 1 and 128" );
+ self->curve->resolv = value;
+
+ return 0;
+}
+
+PyObject *Curve_getWidth( BPy_Curve * self )
+{
+ return PyFloat_FromDouble( ( double ) self->curve->width );
+}
+
+
+static int Curve_newsetWidth( BPy_Curve * self, PyObject * args )
+{
+ float value;
+ PyObject *num;
+
+ if( !PyNumber_Check( args ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected float argument" );
+
+ num = PyNumber_Float( args );
+ value = (float)PyFloat_AS_DOUBLE( num );
+ Py_DECREF( num );
+
+ if(value > 2.0f || value < 0.0f)
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "acceptable values are between 2.0 and 0.0" );
+ self->curve->width = value;
+
+ return 0;
+}
+
+
+PyObject *Curve_getExt1( BPy_Curve * self )
+{
+ return PyFloat_FromDouble( ( double ) self->curve->ext1 );
+}
+
+
+static int Curve_newsetExt1( BPy_Curve * self, PyObject * args )
+{
+ float value;
+ PyObject *num;
+
+ if( !PyNumber_Check( args ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected float argument" );
+
+ num = PyNumber_Float( args );
+ value = (float)PyFloat_AS_DOUBLE( num );
+ Py_DECREF( num );
+
+ if(value > 100.0f || value < 0.0f)
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "acceptable values are between 0.0 and 100.0" );
+ self->curve->ext1 = value;
+
+ return 0;
+}
+
+PyObject *Curve_getExt2( BPy_Curve * self )
+{
+ return PyFloat_FromDouble( ( double ) self->curve->ext2 );
+}
+
+
+static int Curve_newsetExt2( BPy_Curve * self, PyObject * args )
+{
+ float value;
+ PyObject *num;
+
+ if( !PyNumber_Check( args ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected float argument" );
+
+ num = PyNumber_Float( args );
+ value = (float)PyFloat_AS_DOUBLE( num );
+ Py_DECREF( num );
+
+ if(value > 2.0f || value < 0.0f)
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "acceptable values are between 0.0 and 2.0" );
+ self->curve->ext2 = value;
+
+ return 0;
+}
+
+/*
+ * Curve_setControlPoint
+ * this function sets an EXISTING control point.
+ * it does NOT add a new one.
+ */
+
+static PyObject *Curve_setControlPoint( BPy_Curve * self, PyObject * args )
+{
+ PyObject *listargs = 0;
+ Nurb *ptrnurb = self->curve->nurb.first;
+ int numcourbe = 0, numpoint = 0, i, j;
+
+ if( !ptrnurb )
+ Py_RETURN_NONE;
+
+ if( ptrnurb->bp )
+ if( !PyArg_ParseTuple
+ ( args, "iiO", &numcourbe, &numpoint, &listargs ) )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_TypeError,
+ "expected int, int, list arguments" ) );
+ if( ptrnurb->bezt )
+ if( !PyArg_ParseTuple
+ ( args, "iiO", &numcourbe, &numpoint, &listargs ) )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_TypeError,
+ "expected int, int, list arguments" ) );
+
+ for( i = 0; i < numcourbe; i++ )
+ ptrnurb = ptrnurb->next;
+
+ if( ptrnurb->bp )
+ for( i = 0; i < 4; i++ )
+ ptrnurb->bp[numpoint].vec[i] =
+ (float)PyFloat_AsDouble( PyList_GetItem ( listargs, i ) );
+
+ if( ptrnurb->bezt )
+ for( i = 0; i < 3; i++ )
+ for( j = 0; j < 3; j++ )
+ ptrnurb->bezt[numpoint].vec[i][j] =
+ (float)PyFloat_AsDouble( PyList_GetItem
+ ( listargs,
+ i * 3 + j ) );
+
+ Py_RETURN_NONE;
+}
+
+
+static PyObject *Curve_getControlPoint( BPy_Curve * self, PyObject * args )
+{
+ PyObject *liste;
+ PyObject *item;
+
+ Nurb *ptrnurb;
+ int i, j;
+ /* input args: requested curve and point number on curve */
+ int numcourbe, numpoint;
+
+ if( !PyArg_ParseTuple( args, "ii", &numcourbe, &numpoint ) )
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected int int arguments" ) );
+ if( ( numcourbe < 0 ) || ( numpoint < 0 ) )
+ return ( EXPP_ReturnPyObjError( PyExc_ValueError,
+ "arguments must be non-negative" ) );
+
+ /* if no nurbs in this curve obj */
+ if( !self->curve->nurb.first )
+ return PyList_New( 0 );
+
+ /* walk the list of nurbs to find requested numcourbe */
+ ptrnurb = self->curve->nurb.first;
+ for( i = 0; i < numcourbe; i++ ) {
+ ptrnurb = ptrnurb->next;
+ if( !ptrnurb ) /* if zero, we ran just ran out of curves */
+ return ( EXPP_ReturnPyObjError( PyExc_ValueError,
+ "curve index out of range" ) );
+ }
+
+ /* check numpoint param against pntsu */
+ if( numpoint >= ptrnurb->pntsu )
+ return ( EXPP_ReturnPyObjError( PyExc_ValueError,
+ "point index out of range" ) );
+
+ liste = PyList_New( 0 );
+ if( ptrnurb->bp ) { /* if we are a nurb curve, you get 4 values */
+ for( i = 0; i < 4; i++ ) {
+ item = PyFloat_FromDouble( ptrnurb->bp[numpoint].vec[i] );
+ PyList_Append( liste, item );
+ Py_DECREF(item);
+ }
+ } else if( ptrnurb->bezt ) { /* if we are a bezier, you get 9 values */
+ for( i = 0; i < 3; i++ )
+ for( j = 0; j < 3; j++ ) {
+ item = PyFloat_FromDouble( ptrnurb->bezt[numpoint].vec[i][j] );
+ PyList_Append( liste, item );
+ Py_DECREF(item);
+ }
+ }
+
+ return liste;
+}
+
+static PyObject *Curve_getLoc( BPy_Curve * self )
+{
+ return Py_BuildValue( "[f,f,f]", self->curve->loc[0],
+ self->curve->loc[1], self->curve->loc[2] );
+}
+
+static int Curve_newsetLoc( BPy_Curve * self, PyObject * args )
+{
+ float loc[3];
+ int i;
+
+ if( ( !PyList_Check( args ) && !PyTuple_Check( args ) ) ||
+ PySequence_Size( args ) != 3 ) {
+TypeError:
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a sequence of three floats" );
+ }
+
+ for( i = 0; i < 3; i++ ) {
+ PyObject *item = PySequence_GetItem( args, i );
+ PyObject *num = PyNumber_Float( item );
+ Py_DECREF( item );
+ if( !num )
+ goto TypeError;
+ loc[i] = PyFloat_AS_DOUBLE( num );
+ Py_DECREF( num );
+ }
+ memcpy( self->curve->loc, loc, sizeof( loc ) );
+
+ return 0;
+}
+
+static PyObject *Curve_getRot( BPy_Curve * self )
+{
+ return Py_BuildValue( "[f,f,f]", self->curve->rot[0],
+ self->curve->rot[1], self->curve->rot[2] );
+}
+
+static int Curve_newsetRot( BPy_Curve * self, PyObject * args )
+{
+ float rot[3];
+ int i;
+
+ if( ( !PyList_Check( args ) && !PyTuple_Check( args ) ) ||
+ PySequence_Size( args ) != 3 ) {
+TypeError:
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a sequence of three floats" );
+ }
+
+ for( i = 0; i < 3; i++ ) {
+ PyObject *item = PySequence_GetItem( args, i );
+ PyObject *num = PyNumber_Float( item );
+ Py_DECREF( item );
+ if( !num )
+ goto TypeError;
+ rot[i] = PyFloat_AS_DOUBLE( num );
+ Py_DECREF( num );
+ }
+ memcpy( self->curve->rot, rot, sizeof( rot ) );
+
+ return 0;
+}
+
+static PyObject *Curve_getSize( BPy_Curve * self )
+{
+ return Py_BuildValue( "[f,f,f]", self->curve->size[0],
+ self->curve->size[1], self->curve->size[2] );
+}
+
+static int Curve_newsetSize( BPy_Curve * self, PyObject * args )
+{
+ float size[3];
+ int i;
+
+ if( ( !PyList_Check( args ) && !PyTuple_Check( args ) ) ||
+ PySequence_Size( args ) != 3 ) {
+TypeError:
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a sequence of three floats" );
+ }
+
+ for( i = 0; i < 3; i++ ) {
+ PyObject *item = PySequence_GetItem( args, i );
+ PyObject *num = PyNumber_Float( item );
+ Py_DECREF( item );
+ if( !num )
+ goto TypeError;
+ size[i] = PyFloat_AS_DOUBLE( num );
+ Py_DECREF( num );
+ }
+ memcpy( self->curve->size, size, sizeof( size ) );
+
+ return 0;
+}
+
+/*
+ * Count the number of splines in a Curve Object
+ * int getNumCurves()
+ */
+
+static PyObject *Curve_getNumCurves( BPy_Curve * self )
+{
+ Nurb *ptrnurb;
+ PyObject *ret_val;
+ int num_curves = 0; /* start with no splines */
+
+ /* get curve */
+ ptrnurb = self->curve->nurb.first;
+ if( ptrnurb ) { /* we have some nurbs in this curve */
+ for(;;) {
+ ++num_curves;
+ ptrnurb = ptrnurb->next;
+ if( !ptrnurb ) /* no more curves */
+ break;
+ }
+ }
+
+ ret_val = PyInt_FromLong( ( long ) num_curves );
+
+ if( ret_val )
+ return ret_val;
+
+ /* oops! */
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't get number of curves" );
+}
+
+/*
+ * get the key object linked to this curve
+ */
+
+static PyObject *Curve_getKey( BPy_Curve * self )
+{
+ PyObject *keyObj;
+
+ if (self->curve->key)
+ keyObj = Key_CreatePyObject(self->curve->key);
+ else keyObj = EXPP_incr_ret(Py_None);
+
+ return keyObj;
+}
+
+/*
+ * count the number of points in a given spline
+ * int getNumPoints( curve_num=0 )
+ *
+ */
+
+static PyObject *Curve_getNumPoints( BPy_Curve * self, PyObject * args )
+{
+ Nurb *ptrnurb;
+ PyObject *ret_val;
+ int curve_num = 0; /* default spline number */
+ int i;
+
+ /* parse input arg */
+ if( !PyArg_ParseTuple( args, "|i", &curve_num ) )
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected int argument" ) );
+
+ /* check arg - must be non-negative */
+ if( curve_num < 0 )
+ return ( EXPP_ReturnPyObjError( PyExc_ValueError,
+ "argument must be non-negative" ) );
+
+
+ /* walk the list of curves looking for our curve */
+ ptrnurb = self->curve->nurb.first;
+ if( !ptrnurb ) { /* no splines in this Curve */
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "no splines in this Curve" ) );
+ }
+
+ for( i = 0; i < curve_num; i++ ) {
+ ptrnurb = ptrnurb->next;
+ if( !ptrnurb ) /* if zero, we ran just ran out of curves */
+ return ( EXPP_ReturnPyObjError( PyExc_ValueError,
+ "curve index out of range" ) );
+ }
+
+ /* pntsu is the number of points in curve */
+ ret_val = PyInt_FromLong( ( long ) ptrnurb->pntsu );
+
+ if( ret_val )
+ return ret_val;
+
+ /* oops! */
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't get number of points for curve" );
+}
+
+/*
+ * Test whether a given spline of a Curve is a nurb
+ * as opposed to a bezier
+ * int isNurb( curve_num=0 )
+ */
+
+static PyObject *Curve_isNurb( BPy_Curve * self, PyObject * args )
+{
+ int curve_num = 0; /* default value */
+ int is_nurb;
+ Nurb *ptrnurb;
+ PyObject *ret_val;
+ int i;
+
+ /* parse and check input args */
+ if( !PyArg_ParseTuple( args, "|i", &curve_num ) ) {
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected int argument" ) );
+ }
+ if( curve_num < 0 ) {
+ return ( EXPP_ReturnPyObjError( PyExc_ValueError,
+ "curve number must be non-negative" ) );
+ }
+
+ ptrnurb = self->curve->nurb.first;
+
+ if( !ptrnurb ) /* no splines in this curve */
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "no splines in this Curve" ) );
+
+ for( i = 0; i < curve_num; i++ ) {
+ ptrnurb = ptrnurb->next;
+ if( !ptrnurb ) /* if zero, we ran just ran out of curves */
+ return ( EXPP_ReturnPyObjError( PyExc_ValueError,
+ "curve index out of range" ) );
+ }
+
+ /* right now, there are only two curve types, nurb and bezier. */
+ is_nurb = ptrnurb->bp ? 1 : 0;
+
+ ret_val = PyInt_FromLong( ( long ) is_nurb );
+ if( ret_val )
+ return ret_val;
+
+ /* oops */
+ return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't get curve type" ) );
+}
+
+/* trying to make a check for closedness (cyclic), following on isNurb (above)
+ copy-pasting done by antont@kyperjokki.fi */
+
+static PyObject *Curve_isCyclic( BPy_Curve * self, PyObject * args )
+{
+ int curve_num = 0; /* default value */
+ /* unused:*/
+ /* int is_cyclic;
+ * PyObject *ret_val;*/
+ Nurb *ptrnurb;
+ int i;
+
+ /* parse and check input args */
+ if( !PyArg_ParseTuple( args, "|i", &curve_num ) ) {
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected int argument" ) );
+ }
+ if( curve_num < 0 ) {
+ return ( EXPP_ReturnPyObjError( PyExc_ValueError,
+ "curve number must be non-negative" ) );
+ }
+
+ ptrnurb = self->curve->nurb.first;
+
+ if( !ptrnurb ) /* no splines in this curve */
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "no splines in this Curve" ) );
+
+ for( i = 0; i < curve_num; i++ ) {
+ ptrnurb = ptrnurb->next;
+ if( !ptrnurb ) /* if zero, we ran just ran out of curves */
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "curve index out of range" ) );
+ }
+
+ if( ptrnurb->flagu & CU_CYCLIC ){
+ return EXPP_incr_ret_True();
+ } else {
+ return EXPP_incr_ret_False();
+ }
+}
+
+
+/*
+ * Curve_appendPoint( numcurve, new_point )
+ * append a new point to indicated spline
+ */
+
+static PyObject *Curve_appendPoint( BPy_Curve * self, PyObject * args )
+{
+ int i;
+ int nurb_num; /* index of curve we append to */
+ PyObject *coord_args; /* coords for new point */
+ Nurb *nurb = self->curve->nurb.first; /* first nurb in Curve */
+
+/* fixme - need to malloc new Nurb */
+ if( !nurb )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_AttributeError, "no nurbs in this Curve" ) );
+
+ if( !PyArg_ParseTuple( args, "iO", &nurb_num, &coord_args ) )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_TypeError,
+ "expected int, coords as arguments" ) );
+
+ /*
+ chase down the list of Nurbs looking for our curve.
+ */
+ for( i = 0; i < nurb_num; i++ ) {
+ nurb = nurb->next;
+ if( !nurb ) /* we ran off end of list */
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "curve index out of range" );
+ }
+ return CurNurb_appendPointToNurb( nurb, coord_args );
+}
+
+
+/****
+ appendNurb( new_point )
+ create a new nurb in the Curve and add the point param to it.
+ returns a refernce to the newly created nurb.
+*****/
+
+static PyObject *Curve_appendNurb( BPy_Curve * self, PyObject * value )
+{
+ Nurb *new_nurb;
+ /* malloc new nurb */
+ new_nurb = ( Nurb * ) MEM_callocN( sizeof( Nurb ), "appendNurb" );
+ if( !new_nurb )
+ return EXPP_ReturnPyObjError
+ ( PyExc_MemoryError, "unable to malloc Nurb" );
+
+ if( CurNurb_appendPointToNurb( new_nurb, value ) ) {
+ new_nurb->resolu = self->curve->resolu;
+ new_nurb->resolv = self->curve->resolv;
+ new_nurb->hide = 0;
+ new_nurb->flag = 1;
+
+
+ if( new_nurb->bezt ) { /* do setup for bezt */
+ new_nurb->type = CU_BEZIER;
+ new_nurb->bezt->h1 = HD_ALIGN;
+ new_nurb->bezt->h2 = HD_ALIGN;
+ new_nurb->bezt->f1 = 1;
+ new_nurb->bezt->f2 = 1;
+ new_nurb->bezt->f3 = 1;
+ new_nurb->bezt->hide = 0;
+ /* calchandlesNurb( new_nurb ); */
+ } else { /* set up bp */
+ new_nurb->pntsv = 1;
+ new_nurb->type = CU_NURBS;
+ new_nurb->orderu = 4;
+ new_nurb->flagu = 0;
+ new_nurb->flagv = 0;
+ new_nurb->bp->f1 = 0;
+ new_nurb->bp->hide = 0;
+ new_nurb->knotsu = 0;
+ /*makenots( new_nurb, 1, new_nurb->flagu >> 1); */
+ }
+ BLI_addtail( &self->curve->nurb, new_nurb);
+
+ } else {
+ freeNurb( new_nurb );
+ return NULL; /* with PyErr already set */
+ }
+
+ return CurNurb_CreatePyObject( new_nurb );
+}
+
+
+/*
+ * Curve_update( )
+ * method to update display list for a Curve.
+ * used. after messing with control points
+ */
+
+PyObject *Curve_update( BPy_Curve * self )
+{
+ Nurb *nu = self->curve->nurb.first;
+
+ /* recalculate handles for each curve: calchandlesNurb() will make
+ * sure curves are bezier first */
+ while( nu ) {
+ calchandlesNurb ( nu );
+ nu = nu->next;
+ }
+
+ Object_updateDag( (void*) self->curve );
+
+ Py_RETURN_NONE;
+}
+
+/*
+ * Curve_getMaterials
+ *
+ */
+
+static PyObject *Curve_getMaterials( BPy_Curve * self )
+{
+ return EXPP_PyList_fromMaterialList( self->curve->mat,
+ self->curve->totcol, 1 );
+}
+
+static int Curve_setMaterials( BPy_Curve *self, PyObject * value )
+{
+ Material **matlist;
+ int len;
+
+ if( !PySequence_Check( value ) ||
+ !EXPP_check_sequence_consistency( value, &Material_Type ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "sequence should only contain materials or None)" );
+
+ len = PySequence_Size( value );
+ if( len > 16 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "list can't have more than 16 materials" );
+
+ /* free old material list (if it exists) and adjust user counts */
+ if( self->curve->mat ) {
+ Curve *cur = self->curve;
+ int i;
+ for( i = cur->totcol; i-- > 0; )
+ if( cur->mat[i] )
+ cur->mat[i]->id.us--;
+ MEM_freeN( cur->mat );
+ }
+
+ /* build the new material list, increment user count, store it */
+
+ matlist = EXPP_newMaterialList_fromPyList( value );
+ EXPP_incr_mats_us( matlist, len );
+ self->curve->mat = matlist;
+ self->curve->totcol = (short)len;
+
+/**@ This is another ugly fix due to the weird material handling of blender.
+ * it makes sure that object material lists get updated (by their length)
+ * according to their data material lists, otherwise blender crashes.
+ * It just stupidly runs through all objects...BAD BAD BAD.
+ */
+
+ test_object_materials( ( ID * ) self->curve );
+
+ return 0;
+}
+
+/*****************************************************************************/
+/* Function: Curve_getBevOb */
+/* Description: Get the bevel object assign to the curve. */
+/*****************************************************************************/
+static PyObject *Curve_getBevOb( BPy_Curve * self)
+{
+ if( self->curve->bevobj ) {
+ return Object_CreatePyObject( self->curve->bevobj );
+ }
+
+ return EXPP_incr_ret( Py_None );
+}
+
+/*****************************************************************************/
+/* Function: Curve_newsetBevOb */
+/* Description: Assign a bevel object to the curve. */
+/*****************************************************************************/
+static int Curve_newsetBevOb( BPy_Curve * self, PyObject * args )
+{
+
+ if (BPy_Object_Check( args ) && ((BPy_Object *)args)->object->data == self->curve )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "Can't bevel an object to itself" );
+
+ return GenericLib_assignData(args, (void **) &self->curve->bevobj, 0, 0, ID_OB, OB_CURVE);
+}
+
+/*****************************************************************************/
+/* Function: Curve_getTaperOb */
+/* Description: Get the taper object assign to the curve. */
+/*****************************************************************************/
+
+static PyObject *Curve_getTaperOb( BPy_Curve * self)
+{
+ if( self->curve->taperobj )
+ return Object_CreatePyObject( self->curve->taperobj );
+
+ Py_RETURN_NONE;
+}
+
+/*****************************************************************************/
+/* Function: Curve_newsetTaperOb */
+/* Description: Assign a taper object to the curve. */
+/*****************************************************************************/
+
+static int Curve_newsetTaperOb( BPy_Curve * self, PyObject * args )
+{
+ if (BPy_Object_Check( args ) && ((BPy_Object *)args)->object->data == self->curve )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "Can't taper an object to itself" );
+
+ return GenericLib_assignData(args, (void **) &self->curve->taperobj, 0, 0, ID_OB, OB_CURVE);
+}
+
+/*****************************************************************************/
+/* Function: Curve_copy */
+/* Description: Return a copy of this curve data. */
+/*****************************************************************************/
+
+PyObject *Curve_copy( BPy_Curve * self )
+{
+ BPy_Curve *pycurve; /* for Curve Data object wrapper in Python */
+ Curve *blcurve = 0; /* for actual Curve Data we create in Blender */
+
+ /* copies the data */
+ blcurve = copy_curve( self->curve ); /* first create the Curve Data in Blender */
+
+ if( blcurve == NULL ) /* bail out if add_curve() failed */
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_RuntimeError,
+ "couldn't create Curve Data in Blender" ) );
+
+ /* return user count to zero because add_curve() inc'd it */
+ blcurve->id.us = 0;
+
+ /* create python wrapper obj */
+ pycurve = ( BPy_Curve * ) PyObject_NEW( BPy_Curve, &Curve_Type );
+
+ if( pycurve == NULL )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_MemoryError,
+ "couldn't create Curve Data object" ) );
+
+ pycurve->curve = blcurve; /* link Python curve wrapper to Blender Curve */
+ return ( PyObject * ) pycurve;
+}
+
+
+/*
+ * Curve_getIter
+ *
+ * create an iterator for our Curve.
+ * this iterator returns the Nurbs for this Curve.
+ * the iter_pointer always points to the next available item or null
+ */
+
+static PyObject *Curve_getIter( BPy_Curve * self )
+{
+ self->iter_pointer = self->curve->nurb.first;
+
+ Py_INCREF( self );
+ return ( PyObject * ) self;
+
+}
+
+
+/*
+ * Curve_iterNext
+ * get the next item.
+ * iter_pointer always points to the next available element
+ * or NULL if at the end of the list.
+ */
+
+static PyObject *Curve_iterNext( BPy_Curve * self )
+{
+ Nurb *pnurb;
+
+ if( self->iter_pointer ) {
+ pnurb = self->iter_pointer;
+ self->iter_pointer = pnurb->next; /* advance iterator */
+ if( (pnurb->type & 7) == CU_BEZIER || pnurb->pntsv <= 1 )
+ return CurNurb_CreatePyObject( pnurb ); /* make a bpy_curnurb */
+ else
+ return SurfNurb_CreatePyObject( pnurb ); /* make a bpy_surfnurb */
+ }
+
+ /* if iter_pointer was null, we are at end */
+ return EXPP_ReturnPyObjError( PyExc_StopIteration,
+ "iterator at end" );
+}
+
+/* tp_sequence methods */
+
+/*
+ * Curve_length
+ * returns the number of curves in a Curve
+ * this is a tp_as_sequence method, not a regular instance method.
+ */
+
+static int Curve_length( PyInstanceObject * inst )
+{
+ if( BPy_Curve_Check( ( PyObject * ) inst ) )
+ return ( ( int ) PyInt_AsLong
+ ( Curve_getNumCurves( ( BPy_Curve * ) inst ) ) );
+
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "arg is not a BPy_Curve" );
+
+}
+
+/*
+ * Curve_getNurb
+ * returns the Nth nurb in a Curve.
+ * this is one of the tp_as_sequence methods, hence the int N argument.
+ * it is called via the [] operator, not as a usual instance method.
+ */
+
+PyObject *Curve_getNurb( BPy_Curve * self, int n )
+{
+ Nurb *pNurb;
+ int i;
+
+ /* bail if index < 0 */
+ if( n < 0 )
+ return ( EXPP_ReturnPyObjError( PyExc_IndexError,
+ "index less than 0" ) );
+ /* bail if no Nurbs in Curve */
+ if( self->curve->nurb.first == 0 )
+ return ( EXPP_ReturnPyObjError( PyExc_IndexError,
+ "no Nurbs in this Curve" ) );
+ /* set pointer to nth Nurb */
+ for( pNurb = self->curve->nurb.first, i = 0;
+ pNurb != 0 && i < n; pNurb = pNurb->next, ++i )
+ /**/;
+
+ if( !pNurb ) /* we came to the end of the list */
+ return ( EXPP_ReturnPyObjError( PyExc_IndexError,
+ "index out of range" ) );
+
+ /* until there is a Surface BPyType, distinquish between a curve and a
+ * surface based on whether it's a Bezier and the v size */
+ if( (pNurb->type & 7) == CU_BEZIER || pNurb->pntsv <= 1 )
+ return CurNurb_CreatePyObject( pNurb ); /* make a bpy_curnurb */
+ else
+ return SurfNurb_CreatePyObject( pNurb ); /* make a bpy_surfnurb */
+
+}
+
+/*****************************************************************************/
+/* Function: Curve_compare */
+/* Description: This compares 2 curve python types, == or != only. */
+/*****************************************************************************/
+static int Curve_compare( BPy_Curve * a, BPy_Curve * b )
+{
+ return ( a->curve == b->curve ) ? 0 : -1;
+}
+
+/*****************************************************************************/
+/* Function: Curve_repr */
+/* Description: This is a callback function for the BPy_Curve type. It */
+/* builds a meaninful string to represent curve objects. */
+/*****************************************************************************/
+static PyObject *Curve_repr( BPy_Curve * self )
+{ /* used by 'repr' */
+
+ return PyString_FromFormat( "[Curve \"%s\"]",
+ self->curve->id.name + 2 );
+}
+
+/* attributes for curves */
+
+static PyGetSetDef Curve_getseters[] = {
+ GENERIC_LIB_GETSETATTR,
+ {"pathlen",
+ (getter)Curve_getPathLen, (setter)Curve_newsetPathLen,
+ "The path length, used to set the number of frames for an animation (not the physical length)",
+ NULL},
+ {"totcol",
+ (getter)Curve_getTotcol, (setter)NULL,
+ "The maximum number of linked materials",
+ NULL},
+ {"flag",
+ (getter)Curve_getMode, (setter)Curve_newsetMode,
+ "The flag bitmask",
+ NULL},
+ {"bevresol",
+ (getter)Curve_getBevresol, (setter)Curve_newsetBevresol,
+ "The bevel resolution",
+ NULL},
+ {"resolu",
+ (getter)Curve_getResolu, (setter)Curve_newsetResolu,
+ "The resolution in U direction",
+ NULL},
+ {"resolv",
+ (getter)Curve_getResolv, (setter)Curve_newsetResolv,
+ "The resolution in V direction",
+ NULL},
+ {"width",
+ (getter)Curve_getWidth, (setter)Curve_newsetWidth,
+ "The curve width",
+ NULL},
+ {"ext1",
+ (getter)Curve_getExt1, (setter)Curve_newsetExt1,
+ "The extent1 value (for bevels)",
+ NULL},
+ {"ext2",
+ (getter)Curve_getExt2, (setter)Curve_newsetExt2,
+ "The extent2 value (for bevels)",
+ NULL},
+ {"loc",
+ (getter)Curve_getLoc, (setter)Curve_newsetLoc,
+ "The data location (from the center)",
+ NULL},
+ {"rot",
+ (getter)Curve_getRot, (setter)Curve_newsetRot,
+ "The data rotation (from the center)",
+ NULL},
+ {"size",
+ (getter)Curve_getSize, (setter)Curve_newsetSize,
+ "The data size (from the center)",
+ NULL},
+ {"bevob",
+ (getter)Curve_getBevOb, (setter)Curve_newsetBevOb,
+ "The bevel object",
+ NULL},
+ {"taperob",
+ (getter)Curve_getTaperOb, (setter)Curve_newsetTaperOb,
+ "The taper object",
+ NULL},
+ {"key",
+ (getter)Curve_getKey, (setter)NULL,
+ "The shape key for the curve (if any)",
+ NULL},
+ {"materials",
+ (getter)Curve_getMaterials, (setter)Curve_setMaterials,
+ "The materials associated with the curve",
+ NULL},
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+
+};
+
+/*****************************************************************************/
+/* Function: M_Curve_New */
+/* Python equivalent: Blender.Curve.New */
+/*****************************************************************************/
+static PyObject *M_Curve_New( PyObject * self, PyObject * args )
+{
+ char *name = "Curve";
+ BPy_Curve *pycurve; /* for Curve Data object wrapper in Python */
+ Curve *blcurve = 0; /* for actual Curve Data we create in Blender */
+
+ if( !PyArg_ParseTuple( args, "|s", &name ) )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_TypeError,
+ "expected string argument or no argument" ) );
+
+ blcurve = add_curve( name, OB_CURVE ); /* first create the Curve Data in Blender */
+
+ if( blcurve == NULL ) /* bail out if add_curve() failed */
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_RuntimeError,
+ "couldn't create Curve Data in Blender" ) );
+
+ /* return user count to zero because add_curve() inc'd it */
+ blcurve->id.us = 0;
+ /* create python wrapper obj */
+ pycurve = ( BPy_Curve * ) PyObject_NEW( BPy_Curve, &Curve_Type );
+
+ if( pycurve == NULL )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_MemoryError,
+ "couldn't create Curve Data object" ) );
+
+ pycurve->curve = blcurve; /* link Python curve wrapper to Blender Curve */
+
+ return ( PyObject * ) pycurve;
+}
+
+/*****************************************************************************/
+/* Function: M_Curve_Get */
+/* Python equivalent: Blender.Curve.Get */
+/*****************************************************************************/
+static PyObject *M_Curve_Get( PyObject * self, PyObject * args )
+{
+
+ char *name = NULL;
+ Curve *curv_iter;
+ BPy_Curve *wanted_curv;
+
+ if( !PyArg_ParseTuple( args, "|s", &name ) ) /* expects nothing or a string */
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument" ) );
+ if( name ) { /*a name has been given */
+ /* Use the name to search for the curve requested */
+ wanted_curv = NULL;
+ curv_iter = G.main->curve.first;
+
+ while( ( curv_iter ) && ( wanted_curv == NULL ) ) {
+
+ if( strcmp( name, curv_iter->id.name + 2 ) == 0 ) {
+ wanted_curv = ( BPy_Curve * )
+ PyObject_NEW( BPy_Curve, &Curve_Type );
+ if( wanted_curv )
+ wanted_curv->curve = curv_iter;
+ }
+
+ curv_iter = curv_iter->id.next;
+ }
+
+ if( wanted_curv == NULL ) { /* Requested curve doesn't exist */
+ char error_msg[64];
+ PyOS_snprintf( error_msg, sizeof( error_msg ),
+ "Curve \"%s\" not found", name );
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_NameError, error_msg ) );
+ }
+
+
+ return ( PyObject * ) wanted_curv;
+ } /* end of if(name) */
+ else {
+ /* no name has been given; return a list of all curves by name. */
+ PyObject *curvlist;
+
+ curv_iter = G.main->curve.first;
+ curvlist = PyList_New( 0 );
+
+ if( curvlist == NULL )
+ return ( EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create PyList" ) );
+
+ while( curv_iter ) {
+ BPy_Curve *found_cur =
+ ( BPy_Curve * ) PyObject_NEW( BPy_Curve,
+ &Curve_Type );
+ found_cur->curve = curv_iter;
+ PyList_Append( curvlist, ( PyObject * ) found_cur );
+ Py_DECREF(found_cur);
+ curv_iter = curv_iter->id.next;
+ }
+
+ return ( curvlist );
+ } /* end of else */
+}
+
+/*****************************************************************************/
+/* Python method definitions for Blender.Curve module: */
+/*****************************************************************************/
+struct PyMethodDef M_Curve_methods[] = {
+ {"New", ( PyCFunction ) M_Curve_New, METH_VARARGS, M_Curve_New_doc},
+ {"Get", M_Curve_Get, METH_VARARGS, M_Curve_Get_doc},
+ {"get", M_Curve_Get, METH_VARARGS, M_Curve_Get_doc},
+ {NULL, NULL, 0, NULL}
+};
+
+
+/*****************************************************************************/
+/* Python BPy_Curve instance methods table: */
+/*****************************************************************************/
+static PyMethodDef BPy_Curve_methods[] = {
+ {"getName", ( PyCFunction ) Curve_getName,
+ METH_NOARGS, "() - Return Curve Data name"},
+ {"setName", ( PyCFunction ) Curve_setName,
+ METH_VARARGS, "() - Sets Curve Data name"},
+ {"getPathLen", ( PyCFunction ) Curve_getPathLen,
+ METH_NOARGS, "() - Return Curve path length"},
+ {"setPathLen", ( PyCFunction ) Curve_setPathLen,
+ METH_VARARGS, "(int) - Sets Curve path length"},
+ {"getTotcol", ( PyCFunction ) Curve_getTotcol,
+ METH_NOARGS, "() - Return the number of materials of the curve"},
+ {"setTotcol", ( PyCFunction ) Curve_setTotcol,
+ METH_VARARGS, "(int) - Sets the number of materials of the curve"},
+ {"getFlag", ( PyCFunction ) Curve_getMode,
+ METH_NOARGS, "() - Return flag (see the doc for semantic)"},
+ {"setFlag", ( PyCFunction ) Curve_setMode,
+ METH_VARARGS, "(int) - Sets flag (see the doc for semantic)"},
+ {"getBevresol", ( PyCFunction ) Curve_getBevresol,
+ METH_NOARGS, "() - Return bevel resolution"},
+ {"setBevresol", ( PyCFunction ) Curve_setBevresol,
+ METH_VARARGS, "(int) - Sets bevel resolution"},
+ {"getResolu", ( PyCFunction ) Curve_getResolu,
+ METH_NOARGS, "() - Return U resolution"},
+ {"setResolu", ( PyCFunction ) Curve_setResolu,
+ METH_VARARGS, "(int) - Sets U resolution"},
+ {"getResolv", ( PyCFunction ) Curve_getResolv,
+ METH_NOARGS, "() - Return V resolution"},
+ {"setResolv", ( PyCFunction ) Curve_setResolv,
+ METH_VARARGS, "(int) - Sets V resolution"},
+ {"getWidth", ( PyCFunction ) Curve_getWidth,
+ METH_NOARGS, "() - Return curve width"},
+ {"setWidth", ( PyCFunction ) Curve_setWidth,
+ METH_VARARGS, "(int) - Sets curve width"},
+ {"getExt1", ( PyCFunction ) Curve_getExt1,
+ METH_NOARGS, "() - Returns extent 1 of the bevel"},
+ {"setExt1", ( PyCFunction ) Curve_setExt1,
+ METH_VARARGS, "(int) - Sets extent 1 of the bevel"},
+ {"getExt2", ( PyCFunction ) Curve_getExt2,
+ METH_NOARGS, "() - Return extent 2 of the bevel "},
+ {"setExt2", ( PyCFunction ) Curve_setExt2,
+ METH_VARARGS, "(int) - Sets extent 2 of the bevel "},
+ {"getControlPoint", ( PyCFunction ) Curve_getControlPoint,
+ METH_VARARGS, "(int numcurve,int numpoint) -\
+Gets a control point.Depending upon the curve type, returne a list of 4 or 9 floats"},
+ {"setControlPoint", ( PyCFunction ) Curve_setControlPoint,
+ METH_VARARGS, "(int numcurve,int numpoint,float x,float y,float z,\
+float w)(nurbs) or (int numcurve,int numpoint,float x1,...,x9(bezier)\
+Sets a control point "},
+ {"getLoc", ( PyCFunction ) Curve_getLoc,
+ METH_NOARGS, "() - Gets Location of the curve (a 3-tuple) "},
+ {"setLoc", ( PyCFunction ) Curve_setLoc,
+ METH_VARARGS, "(3-tuple) - Sets Location "},
+ {"getRot", ( PyCFunction ) Curve_getRot,
+ METH_NOARGS, "() - Gets curve rotation"},
+ {"setRot", ( PyCFunction ) Curve_setRot,
+ METH_VARARGS, "(3-tuple) - Sets curve rotation"},
+ {"getSize", ( PyCFunction ) Curve_getSize,
+ METH_NOARGS, "() - Gets curve size"},
+ {"setSize", ( PyCFunction ) Curve_setSize,
+ METH_VARARGS, "(3-tuple) - Sets curve size"},
+ {"getNumCurves", ( PyCFunction ) Curve_getNumCurves,
+ METH_NOARGS, "() - Gets number of curves in Curve"},
+ {"getKey", ( PyCFunction ) Curve_getKey,
+ METH_NOARGS, "() - Gets curve key"},
+ {"isNurb", ( PyCFunction ) Curve_isNurb,
+ METH_VARARGS,
+ "(nothing or integer) - returns 1 if curve is type Nurb, O otherwise."},
+ {"isCyclic", ( PyCFunction ) Curve_isCyclic,
+ METH_VARARGS, "( nothing or integer ) - returns true if curve is cyclic (closed), false otherwise."},
+ {"getNumPoints", ( PyCFunction ) Curve_getNumPoints,
+ METH_VARARGS,
+ "(nothing or integer) - returns the number of points of the specified curve"},
+ {"appendPoint", ( PyCFunction ) Curve_appendPoint, METH_VARARGS,
+ "( int numcurve, list of coordinates) - adds a new point to end of curve"},
+ {"appendNurb", ( PyCFunction ) Curve_appendNurb, METH_O,
+ "( new_nurb ) - adds a new nurb to the Curve"},
+ {"update", ( PyCFunction ) Curve_update, METH_NOARGS,
+ "( ) - updates display lists after changes to Curve"},
+ {"getMaterials", ( PyCFunction ) Curve_getMaterials, METH_NOARGS,
+ "() - returns list of materials assigned to this Curve"},
+ {"getBevOb", ( PyCFunction ) Curve_getBevOb, METH_NOARGS,
+ "() - returns Bevel Object assigned to this Curve"},
+ {"setBevOb", ( PyCFunction ) Curve_setBevOb, METH_VARARGS,
+ "() - assign a Bevel Object to this Curve"},
+ {"getTaperOb", ( PyCFunction ) Curve_getTaperOb, METH_NOARGS,
+ "() - returns Taper Object assigned to this Curve"},
+ {"setTaperOb", ( PyCFunction ) Curve_setTaperOb, METH_VARARGS,
+ "() - assign a Taper Object to this Curve"},
+ {"__copy__", ( PyCFunction ) Curve_copy, METH_NOARGS,
+ "() - make a copy of this curve data"},
+ {"copy", ( PyCFunction ) Curve_copy, METH_NOARGS,
+ "() - make a copy of this curve data"},
+ {NULL, NULL, 0, NULL}
+};
+
+
+/*****************************************************************************/
+/* Python Curve_Type callback function prototypes: */
+/*****************************************************************************/
+static int Curve_compare( BPy_Curve * a, BPy_Curve * b );
+static PyObject *Curve_repr( BPy_Curve * msh );
+
+static PySequenceMethods Curve_as_sequence = {
+ ( inquiry ) Curve_length, /* sq_length */
+ ( binaryfunc ) 0, /* sq_concat */
+ ( intargfunc ) 0, /* sq_repeat */
+ ( intargfunc ) Curve_getNurb, /* sq_item */
+ ( intintargfunc ) 0, /* sq_slice */
+ 0, /* sq_ass_item */
+ 0, /* sq_ass_slice */
+ ( objobjproc ) 0, /* sq_contains */
+ 0,
+ 0
+};
+
+/*****************************************************************************/
+/* Python Curve_Type structure definition: */
+/*****************************************************************************/
+PyTypeObject Curve_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required macro */
+ 0, /* ob_size */
+ "Curve", /* tp_name */
+ sizeof( BPy_Curve ), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ /* methods */
+ NULL, /* tp_dealloc */
+ 0, /* tp_print */
+ ( getattrfunc ) NULL, /* tp_getattr */
+ ( setattrfunc ) NULL, /* tp_setattr */
+ ( cmpfunc ) Curve_compare, /* tp_compare */
+ ( reprfunc ) Curve_repr, /* tp_repr */
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ &Curve_as_sequence, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ ( hashfunc ) GenericLib_hash, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ ( getiterfunc ) Curve_getIter, /* getiterfunc tp_iter; */
+ ( iternextfunc ) Curve_iterNext, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_Curve_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ Curve_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+
+/*****************************************************************************/
+/* Function: Curve_Init */
+/*****************************************************************************/
+PyObject *Curve_Init( void )
+{
+ PyObject *submodule;
+
+ if( PyType_Ready( &Curve_Type) < 0) /* set exception. -1 is failure */
+ return NULL;
+
+ submodule =
+ Py_InitModule3( "Blender.Curve", M_Curve_methods,
+ M_Curve_doc );
+ return ( submodule );
+}
+
+
+/*
+ * Curve_CreatePyObject
+ * constructor to build a py object from blender data
+ */
+
+PyObject *Curve_CreatePyObject( struct Curve * curve )
+{
+ BPy_Curve *blen_object;
+
+ blen_object = ( BPy_Curve * ) PyObject_NEW( BPy_Curve, &Curve_Type );
+
+ if( blen_object == NULL ) {
+ return ( NULL );
+ }
+ blen_object->curve = curve;
+ return ( ( PyObject * ) blen_object );
+
+}
+
+struct Curve *Curve_FromPyObject( PyObject * py_obj )
+{
+ BPy_Curve *blen_obj;
+
+ blen_obj = ( BPy_Curve * ) py_obj;
+ return ( blen_obj->curve );
+
+}
+
+/* #####DEPRECATED###### */
+
+PyObject *Curve_setName( BPy_Curve * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Curve_newsetName );
+}
+
+static PyObject *Curve_setPathLen( BPy_Curve * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args,
+ (setter)Curve_newsetPathLen );
+}
+
+static PyObject *Curve_setTotcol( BPy_Curve * self, PyObject * args )
+{
+ if( !PyArg_ParseTuple( args, "i", &( self->curve->totcol ) ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected int argument" );
+ Py_RETURN_NONE;
+}
+
+PyObject *Curve_setMode( BPy_Curve * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args,
+ (setter)Curve_newsetMode );
+}
+
+PyObject *Curve_setBevresol( BPy_Curve * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args,
+ (setter)Curve_newsetBevresol);
+}
+
+PyObject *Curve_setResolu( BPy_Curve * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args,
+ (setter)Curve_newsetResolu );
+}
+
+PyObject *Curve_setResolv( BPy_Curve * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args,
+ (setter)Curve_newsetResolv );
+}
+
+PyObject *Curve_setWidth( BPy_Curve * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args,
+ (setter)Curve_newsetWidth );
+}
+
+PyObject *Curve_setExt1( BPy_Curve * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args,
+ (setter)Curve_newsetExt1 );
+}
+
+PyObject *Curve_setExt2( BPy_Curve * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args,
+ (setter)Curve_newsetExt2 );
+}
+
+static PyObject *Curve_setLoc( BPy_Curve * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args,
+ (setter)Curve_newsetLoc );
+}
+
+static PyObject *Curve_setRot( BPy_Curve * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args,
+ (setter)Curve_newsetRot );
+}
+
+static PyObject *Curve_setSize( BPy_Curve * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args,
+ (setter)Curve_newsetSize );
+}
+
+PyObject *Curve_setBevOb( BPy_Curve * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args,
+ (setter)Curve_newsetBevOb );
+}
+
+PyObject *Curve_setTaperOb( BPy_Curve * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args,
+ (setter)Curve_newsetTaperOb );
+}
+
diff --git a/source/blender/python/api2_2x/Curve.h b/source/blender/python/api2_2x/Curve.h
new file mode 100644
index 00000000000..70be37500f1
--- /dev/null
+++ b/source/blender/python/api2_2x/Curve.h
@@ -0,0 +1,78 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Jacques Guignot, Stephen Swaney
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_CURVE_H
+#define EXPP_CURVE_H
+
+#include <Python.h>
+#include "DNA_curve_types.h"
+
+extern PyTypeObject Curve_Type;
+
+#define BPy_Curve_Check(v) ((v)->ob_type==&Curve_Type)
+
+/* Python BPy_Curve structure definition */
+typedef struct {
+ PyObject_HEAD /* required py macro */
+ Curve * curve; /* libdata must be second */
+ /* pointer for iterator: does not point to owned memory */
+ Nurb *iter_pointer;
+} BPy_Curve;
+
+
+/*
+ * protoypes
+ */
+
+PyObject *Curve_Init( void );
+PyObject *Curve_CreatePyObject( struct Curve * curve );
+struct Curve *Curve_FromPyObject( PyObject * py_obj );
+PyObject *Curve_update( BPy_Curve * self );
+
+PyObject *Curve_getName( BPy_Curve * self );
+PyObject *Curve_setName( BPy_Curve * self, PyObject * args );
+PyObject *Curve_getMode( BPy_Curve * self );
+PyObject *Curve_setMode( BPy_Curve * self, PyObject * args );
+PyObject *Curve_getBevresol( BPy_Curve * self );
+PyObject *Curve_setBevresol( BPy_Curve * self, PyObject * args );
+PyObject *Curve_getResolu( BPy_Curve * self );
+PyObject *Curve_setResolu( BPy_Curve * self, PyObject * args );
+PyObject *Curve_getResolv( BPy_Curve * self );
+PyObject *Curve_setResolv( BPy_Curve * self, PyObject * args );
+PyObject *Curve_getExt1( BPy_Curve * self );
+PyObject *Curve_setExt1( BPy_Curve * self, PyObject * args );
+PyObject *Curve_getExt2( BPy_Curve * self );
+PyObject *Curve_setExt2( BPy_Curve * self, PyObject * args );
+PyObject *Curve_getWidth( BPy_Curve * self );
+PyObject *Curve_setWidth( BPy_Curve * self, PyObject * args );
+
+#endif /* EXPP_CURVE_H */
diff --git a/source/blender/python/api2_2x/Draw.c b/source/blender/python/api2_2x/Draw.c
new file mode 100644
index 00000000000..54ff927a2b3
--- /dev/null
+++ b/source/blender/python/api2_2x/Draw.c
@@ -0,0 +1,2210 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano, Campbell Barton, Ken Hughes
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+/* This file is the Blender.Draw part of opy_draw.c, from the old
+ * bpython/intern dir, with minor changes to adapt it to the new Python
+ * implementation. Non-trivial original comments are marked with an
+ * @ symbol at their beginning. */
+
+#include "Draw.h" /*This must come first*/
+
+#include "BLI_blenlib.h"
+#include "MEM_guardedalloc.h"
+#include "BMF_Api.h"
+#include "DNA_screen_types.h"
+#include "BKE_global.h"
+#include "BKE_image.h"
+#include "BKE_object.h"
+#include "BKE_main.h"
+#include "BKE_utildefines.h"
+#include "BIF_gl.h"
+#include "BIF_mywindow.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_interface.h"
+#include "BIF_toolbox.h"
+#include "BPI_script.h" /* script struct */
+#include "Image.h" /* for accessing Blender.Image objects */
+#include "IMB_imbuf_types.h" /* for the IB_rect define */
+#include "interface.h"
+#include "mydevice.h" /*@ for all the event constants */
+#include "gen_utils.h"
+#include "Window.h"
+#include "../BPY_extern.h"
+
+/* used so we can get G.scene->r.cfra for getting the
+current image frame, some images change frame if they are a sequence */
+#include "DNA_scene_types.h"
+
+/* these delimit the free range for button events */
+#define EXPP_BUTTON_EVENTS_OFFSET 1001
+#define EXPP_BUTTON_EVENTS_MIN 0
+#define EXPP_BUTTON_EVENTS_MAX 15382 /* 16384 - 1 - OFFSET */
+
+#define ButtonObject_Check(v) ((v)->ob_type == &Button_Type)
+
+#define UI_METHOD_ERRORCHECK \
+ if (check_button_event(&event) == -1)\
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,\
+ "button event argument must be in the range [0, 16382]");\
+ if (callback && !PyCallable_Check(callback))\
+ return EXPP_ReturnPyObjError( PyExc_ValueError,\
+ "callback is not a python function");\
+
+/* pointer to main dictionary defined in Blender.c */
+extern PyObject *g_blenderdict;
+
+/*@ hack to flag that window redraw has happened inside slider callback: */
+int EXPP_disable_force_draw = 0;
+
+/* forward declarations for internal functions */
+static void Button_dealloc( PyObject * self );
+static PyObject *Button_getattr( PyObject * self, char *name );
+static PyObject *Button_repr( PyObject * self );
+static PyObject *Button_richcmpr(PyObject *objectA, PyObject *objectB, int comparison_type);
+static int Button_setattr( PyObject * self, char *name, PyObject * v );
+
+static Button *newbutton( void );
+
+/* GUI interface routines */
+
+static void exit_pydraw( SpaceScript * sc, short error );
+static void exec_callback( SpaceScript * sc, PyObject * callback,
+ PyObject * args );
+static void spacescript_do_pywin_buttons( SpaceScript * sc,
+ unsigned short event );
+
+static PyObject *Method_Exit( PyObject * self );
+static PyObject *Method_Register( PyObject * self, PyObject * args );
+static PyObject *Method_Redraw( PyObject * self, PyObject * args );
+static PyObject *Method_Draw( PyObject * self );
+static PyObject *Method_Create( PyObject * self, PyObject * args );
+static PyObject *Method_UIBlock( PyObject * self, PyObject * args );
+
+static PyObject *Method_Button( PyObject * self, PyObject * args );
+static PyObject *Method_Menu( PyObject * self, PyObject * args );
+static PyObject *Method_Toggle( PyObject * self, PyObject * args );
+static PyObject *Method_Slider( PyObject * self, PyObject * args );
+static PyObject *Method_Scrollbar( PyObject * self, PyObject * args );
+static PyObject *Method_ColorPicker( PyObject * self, PyObject * args );
+static PyObject *Method_Normal( PyObject * self, PyObject * args );
+static PyObject *Method_Number( PyObject * self, PyObject * args );
+static PyObject *Method_String( PyObject * self, PyObject * args );
+static PyObject *Method_GetStringWidth( PyObject * self, PyObject * args );
+static PyObject *Method_Text( PyObject * self, PyObject * args );
+static PyObject *Method_Label( PyObject * self, PyObject * args );
+/* by Campbell: */
+static PyObject *Method_PupMenu( PyObject * self, PyObject * args );
+static PyObject *Method_PupIntInput( PyObject * self, PyObject * args );
+static PyObject *Method_PupFloatInput( PyObject * self, PyObject * args );
+static PyObject *Method_PupStrInput( PyObject * self, PyObject * args );
+static PyObject *Method_BeginAlign( PyObject * self, PyObject * args );
+static PyObject *Method_EndAlign( PyObject * self, PyObject * args );
+/* next by Jonathan Merritt (lancelet): */
+static PyObject *Method_Image( PyObject * self, PyObject * args);
+/* CLEVER NUMBUT */
+static PyObject *Method_PupBlock( PyObject * self, PyObject * args );
+
+static uiBlock *Get_uiBlock( void );
+
+static void py_slider_update( void *butv, void *data2_unused );
+
+/* hack to get 1 block for the UIBlock, only ever 1 at a time */
+static uiBlock *uiblock=NULL;
+
+static char Draw_doc[] = "The Blender.Draw submodule";
+
+static char Method_UIBlock_doc[] = "(drawfunc, x,y) - Popup dialog where buttons can be drawn (expemental)";
+
+static char Method_Register_doc[] =
+ "(draw, event, button) - Register callbacks for windowing\n\n\
+(draw) A function to draw the screen, taking no arguments\n\
+(event) A function to handle events, taking 2 arguments (evt, val)\n\
+ (evt) The event number\n\
+ (val) The value modifier (for key and mouse press/release)\n\
+(button) A function to handle button events, taking 1 argument (evt)\n\
+ (evt) The button number\n\n\
+A None object can be passed if a callback is unused.";
+
+
+static char Method_Redraw_doc[] = "([after]) - Queue a redraw event\n\n\
+[after=0] Determines whether the redraw is processed before\n\
+or after other input events.\n\n\
+Redraw events are buffered so that regardless of how many events\n\
+are queued the window only receives one redraw event.";
+
+static char Method_Draw_doc[] = "() - Force an immediate redraw\n\n\
+Forced redraws are not buffered, in other words the window is redrawn\n\
+exactly once for everytime this function is called.";
+
+
+static char Method_Create_doc[] =
+ "(value) - Create a default Button object\n\n\
+ (value) - The value to store in the button\n\n\
+ Valid values are ints, floats, and strings";
+
+static char Method_Button_doc[] =
+ "(name, event, x, y, width, height, [tooltip]) - Create a new Button \
+(push) button\n\n\
+(name) A string to display on the button\n\
+(event) The event number to pass to the button event function when activated\n\
+(x, y) The lower left coordinate of the button\n\
+(width, height) The button width and height\n\
+[tooltip=] The button's tooltip\n\n\
+This function can be called as Button() or PushButton().";
+
+static char Method_BeginAlign_doc[] =
+ "Buttons after this function will draw aligned (button layout only)";
+
+static char Method_EndAlign_doc[] =
+ "Use after BeginAlign() to stop aligning the buttons (button layout only).";
+
+static char Method_Menu_doc[] =
+ "(name, event, x, y, width, height, default, [tooltip]) - Create a new Menu \
+button\n\n\
+(name) A string to display on the button\n\
+(event) The event number to pass to the button event function when activated\n\
+(x, y) The lower left coordinate of the button\n\
+(width, height) The button width and height\n\
+(default) The number of the option to be selected by default\n\
+[tooltip=" "] The button's tooltip\n\n\
+The menu options are specified through the name of the\n\
+button. Options are followed by a format code and separated\n\
+by the '|' (pipe) character.\n\
+Valid format codes are\n\
+ %t - The option should be used as the title\n\
+ %xN - The option should set the integer N in the button value.";
+
+static char Method_Toggle_doc[] =
+ "(name, event, x, y, width, height, default, [tooltip]) - Create a new Toggle \
+button\n\n\
+(name) A string to display on the button\n\
+(event) The event number to pass to the button event function when activated\n\
+(x, y) The lower left coordinate of the button\n\
+(width, height) The button width and height\n\
+(default) An integer (0 or 1) specifying the default state\n\
+[tooltip=] The button's tooltip";
+
+
+static char Method_Slider_doc[] =
+ "(name, event, x, y, width, height, initial, min, max, [update, tooltip]) - \
+Create a new Slider button\n\n\
+(name) A string to display on the button\n\
+(event) The event number to pass to the button event function when activated\n\
+(x, y) The lower left coordinate of the button\n\
+(width, height) The button width and height\n\
+(initial, min, max) Three values (int or float) specifying the initial \
+ and limit values.\n\
+[update=1] A value controlling whether the slider will emit events as it \
+is edited.\n\
+ A non-zero value (default) enables the events. A zero value supresses them.\n\
+[tooltip=] The button's tooltip";
+
+
+static char Method_Scrollbar_doc[] =
+ "(event, x, y, width, height, initial, min, max, [update, tooltip]) - Create a \
+new Scrollbar\n\n\
+(event) The event number to pass to the button event function when activated\n\
+(x, y) The lower left coordinate of the button\n\
+(width, height) The button width and height\n\
+(initial, min, max) Three values (int or float) specifying the initial and limit values.\n\
+[update=1] A value controlling whether the slider will emit events as it is edited.\n\
+ A non-zero value (default) enables the events. A zero value supresses them.\n\
+[tooltip=] The button's tooltip";
+
+static char Method_ColorPicker_doc[] =
+ "(event, x, y, width, height, initial, [tooltip]) - Create a new Button \
+Color picker button\n\n\
+(event) The event number to pass to the button event function when the color changes\n\
+(x, y) The lower left coordinate of the button\n\
+(width, height) The button width and height\n\
+(initial) 3-Float tuple of the color (values between 0 and 1)\
+[tooltip=] The button's tooltip";
+
+static char Method_Normal_doc[] =
+ "(event, x, y, width, height, initial, [tooltip]) - Create a new Button \
+Normal button (a sphere that you can roll to change the normal)\n\n\
+(event) The event number to pass to the button event function when the color changes\n\
+(x, y) The lower left coordinate of the button\n\
+(width, height) The button width and height - non square will gave odd results\n\
+(initial) 3-Float tuple of the normal vector (values between -1 and 1)\
+[tooltip=] The button's tooltip";
+
+static char Method_Number_doc[] =
+ "(name, event, x, y, width, height, initial, min, max, [tooltip]) - Create a \
+new Number button\n\n\
+(name) A string to display on the button\n\
+(event) The event number to pass to the button event function when activated\n\
+(x, y) The lower left coordinate of the button\n\
+(width, height) The button width and height\n\
+(initial, min, max) Three values (int or float) specifying the initial and \
+limit values.\n\
+[tooltip=] The button's tooltip";
+
+static char Method_String_doc[] =
+ "(name, event, x, y, width, height, initial, length, [tooltip]) - Create a \
+new String button\n\n\
+(name) A string to display on the button\n\
+(event) The event number to pass to the button event function when activated\n\
+(x, y) The lower left coordinate of the button\n\
+(width, height) The button width and height\n\
+(initial) The string to display initially\n\
+(length) The maximum input length\n\
+[tooltip=] The button's tooltip";
+
+static char Method_GetStringWidth_doc[] =
+ "(text, font = 'normal') - Return the width in pixels of the given string\n\
+(font) The font size: 'normal' (default), 'small' or 'tiny'.";
+
+static char Method_Text_doc[] =
+ "(text, font = 'normal') - Draw text onscreen\n\n\
+(text) The text to draw\n\
+(font) The font size: 'normal' (default), 'small' or 'tiny'.\n\n\
+This function returns the width of the drawn string.";
+
+static char Method_Label_doc[] =
+ "(text, x, y) - Draw a text label onscreen\n\n\
+(text) The text to draw\n\
+(x, y) The lower left coordinate of the lable";
+
+static char Method_PupMenu_doc[] =
+ "(string, maxrow = None) - Display a pop-up menu at the screen.\n\
+The contents of the pop-up are specified through the 'string' argument,\n\
+like with Draw.Menu.\n\
+'maxrow' is an optional int to control how many rows the pop-up should have.\n\
+Options are followed by a format code and separated\n\
+by the '|' (pipe) character.\n\
+Valid format codes are\n\
+ %t - The option should be used as the title\n\
+ %xN - The option should set the integer N in the button value.\n\n\
+Ex: Draw.PupMenu('OK?%t|QUIT BLENDER') # should be familiar ...";
+
+static char Method_PupIntInput_doc[] =
+ "(text, default, min, max) - Display an int pop-up input.\n\
+(text) - text string to display on the button;\n\
+(default, min, max) - the default, min and max int values for the button;\n\
+Return the user input value or None on user exit";
+
+static char Method_PupFloatInput_doc[] =
+ "(text, default, min, max, clickStep, floatLen) - Display a float pop-up input.\n\
+(text) - text string to display on the button;\n\
+(default, min, max) - the default, min and max float values for the button;\n\
+(clickStep) - float increment/decrement for each click on the button arrows;\n\
+(floatLen) - an integer defining the precision (number of decimal places) of \n\
+the float value show.\n\
+Return the user input value or None on user exit";
+
+static char Method_Image_doc[] =
+ "(image, x, y, zoomx = 1.0, zoomy = 1.0, [clipx, clipy, clipw, cliph])) \n\
+ - Draw an image.\n\
+(image) - Blender.Image to draw.\n\
+(x, y) - floats specifying the location of the image.\n\
+(zoomx, zoomy) - float zoom factors in horizontal and vertical directions.\n\
+(clipx, clipy, clipw, cliph) - integers specifying a clipping rectangle within the original image.";
+
+static char Method_PupStrInput_doc[] =
+ "(text, default, max = 20) - Display a float pop-up input.\n\
+(text) - text string to display on the button;\n\
+(default) - the initial string to display (truncated to 'max' chars);\n\
+(max = 20) - The maximum number of chars the user can input;\n\
+Return the user input value or None on user exit";
+
+static char Method_PupBlock_doc[] =
+ "(title, sequence) - Display a pop-up block.\n\
+(title) - The title of the block.\n\
+(sequence) - A sequence defining what the block contains. \
+The order of the list is the order of appearance, from top down.\n\
+Possible format for sequence items:\n\
+[value is an object created with Create]\n\
+\ttext: Defines a label in the block\n\
+\t(text, value, tooltip = ''): Defines a toggle button \n\
+\t(text, value, min, max, tooltip = ''): Defines a num or string button \n\
+\t\t\tdepending on the value.\n\
+\t\tFor string, max is the maximum length of the text and min is unused.\n\
+Return 1 if the pop-up is confirmed, 0 otherwise. \n\
+Warning: On cancel, the value objects are brought back to there previous values, \
+\texcept for string values which will still contain the modified values.\n";
+
+static char Method_Exit_doc[] = "() - Exit the windowing interface";
+
+/*This is needed for button callbacks. Any button that uses a callback gets added to this list.
+ On the C side of drawing begin, this list should be cleared.
+ Each entry is a tuple of the form (button, callback py object)
+*/
+PyObject *M_Button_List = NULL;
+
+/*
+* here we engage in some macro trickery to define the PyMethodDef table
+*/
+
+#define _MethodDef(func, prefix) \
+ {#func, prefix##_##func, METH_VARARGS, prefix##_##func##_doc}
+
+/* So that _MethodDef(delete, Scene) expands to:
+ * {"delete", Scene_delete, METH_VARARGS, Scene_delete_doc} */
+
+#undef MethodDef
+#define MethodDef(func) _MethodDef(func, Method)
+
+static struct PyMethodDef Draw_methods[] = {
+ MethodDef( Create ),
+ MethodDef( UIBlock ),
+ MethodDef( Button ),
+ MethodDef( Toggle ),
+ MethodDef( Menu ),
+ MethodDef( Slider ),
+ MethodDef( Scrollbar ),
+ MethodDef( ColorPicker ),
+ MethodDef( Normal ),
+ MethodDef( Number ),
+ MethodDef( String ),
+ MethodDef( GetStringWidth ),
+ MethodDef( Text ),
+ MethodDef( Label ),
+ MethodDef( PupMenu ),
+ MethodDef( PupIntInput ),
+ MethodDef( PupFloatInput ),
+ MethodDef( PupStrInput ),
+ MethodDef( PupBlock ),
+ MethodDef( Image ),
+ {"Exit", (PyCFunction)Method_Exit, METH_NOARGS, Method_Exit_doc},
+ MethodDef( Redraw ),
+ {"Draw", (PyCFunction)Method_Draw, METH_NOARGS, Method_Draw_doc},
+ MethodDef( Register ),
+ {"PushButton", (PyCFunction)Method_Button, METH_VARARGS, Method_Button_doc},
+ MethodDef( BeginAlign ),
+ MethodDef( EndAlign),
+ {NULL, NULL, 0, NULL}
+};
+
+PyTypeObject Button_Type = {
+ PyObject_HEAD_INIT( NULL ) 0, /*ob_size */
+ "Button", /*tp_name */
+ sizeof( Button ), /*tp_basicsize */
+ 0, /*tp_itemsize */
+ ( destructor ) Button_dealloc, /*tp_dealloc */
+ ( printfunc ) 0, /*tp_print */
+ ( getattrfunc ) Button_getattr, /*tp_getattr */
+ ( setattrfunc ) Button_setattr, /*tp_setattr */
+ NULL, /*tp_cmp */
+ ( reprfunc ) Button_repr, /*tp_repr */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ (richcmpfunc)Button_richcmpr, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ NULL, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ NULL, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+static void Button_dealloc( PyObject * self )
+{
+ Button *but = ( Button * ) self;
+
+ if( but->type == BSTRING_TYPE ) {
+ if( but->val.asstr )
+ MEM_freeN( but->val.asstr );
+ }
+
+ PyObject_DEL( self );
+}
+
+static PyObject *Button_getattr( PyObject * self, char *name )
+{
+ Button *but = ( Button * ) self;
+
+ if( strcmp( name, "val" ) == 0 ) {
+ if( but->type == BINT_TYPE )
+ return PyInt_FromLong( but->val.asint );
+ else if( but->type == BFLOAT_TYPE )
+ return PyFloat_FromDouble( but->val.asfloat );
+ else if( but->type == BSTRING_TYPE )
+ return PyString_FromString( but->val.asstr );
+ else if( but->type == BVECTOR_TYPE )
+ return Py_BuildValue( "fff", but->val.asvec[0], but->val.asvec[1], but->val.asvec[2] );
+ }
+
+ PyErr_SetString( PyExc_AttributeError, name );
+ return NULL;
+}
+
+static int Button_setattr( PyObject * self, char *name, PyObject * v )
+{
+ Button *but = ( Button * ) self;
+
+ if( strcmp( name, "val" ) == 0 ) {
+ if( but->type == BINT_TYPE && PyNumber_Check(v) ) {
+ PyObject *pyVal = PyNumber_Int( v );
+ if (pyVal) {
+ but->val.asint = (int)PyInt_AS_LONG( pyVal );
+ Py_DECREF(pyVal);
+ return 0;
+ }
+ }
+ else if( but->type == BFLOAT_TYPE && PyNumber_Check(v) ) {
+ PyObject *pyVal = PyNumber_Float( v );
+ if (pyVal) {
+ but->val.asfloat = (float)PyFloat_AS_DOUBLE( pyVal );
+ Py_DECREF(pyVal);
+ return 0;
+ }
+ }
+ else if( but->type == BVECTOR_TYPE ) {
+ if ( PyArg_ParseTuple( v, "fff", but->val.asvec, but->val.asvec+1, but->val.asvec+2 ) )
+ return 0;
+ }
+ else if( but->type == BSTRING_TYPE && PyString_Check(v) ) {
+ char *newstr;
+ unsigned int newlen;
+
+ PyString_AsStringAndSize( v, &newstr, (int *)&newlen );
+
+ if (newlen+1> UI_MAX_DRAW_STR)
+ return EXPP_ReturnIntError( PyExc_ValueError, "Error: button string length exceeded max limit (399 chars).");
+
+ /* if the length of the new string is the same as */
+ /* the old one, just copy, else delete and realloc. */
+ if( but->slen == newlen ) {
+ BLI_strncpy( but->val.asstr, newstr,
+ but->slen + 1 );
+
+ return 0;
+
+ } else {
+ MEM_freeN( but->val.asstr );
+ but->slen = newlen;
+ but->val.asstr =
+ MEM_mallocN( but->slen + 1,
+ "button setattr" );
+ BLI_strncpy( but->val.asstr, newstr,
+ but->slen + 1 );
+
+ return 0;
+ }
+ }
+ } else {
+ /*
+ * Accessing the wrong attribute.
+ */
+ return EXPP_ReturnIntError( PyExc_AttributeError, name );
+ }
+
+ /*
+ * Correct attribute but value is incompatible with current button value.
+ */
+ return EXPP_ReturnIntError( PyExc_ValueError, "value incompatible with current button type" );
+}
+
+static PyObject *Button_repr( PyObject * self )
+{
+ return PyObject_Repr( Button_getattr( self, "val" ) );
+}
+
+static PyObject *Button_richcmpr(PyObject *objectA, PyObject *objectB, int comparison_type)
+{
+ PyObject *ret, *valA=NULL, *valB=NULL;
+ if (ButtonObject_Check(objectA))
+ objectA = valA = Button_getattr( objectA, "val" );
+ if (ButtonObject_Check(objectB))
+ objectB = valB = Button_getattr( objectB, "val" );
+ ret = PyObject_RichCompare(objectA, objectB, comparison_type);
+ Py_XDECREF(valA); /* Button_getattr created with 1 ref, we dont care about them now */
+ Py_XDECREF(valB);
+ return ret;
+}
+
+
+static Button *newbutton( void )
+{
+ Button *but = NULL;
+
+ but = ( Button * ) PyObject_NEW( Button, &Button_Type );
+ but->tooltip[0] = 0; /*NULL-terminate tooltip string*/
+ but->tooltip[255] = 0; /*necassary to insure we always have a NULL-terminated string, as
+ according to the docs strncpy doesn't do this for us.*/
+ return but;
+}
+
+/* GUI interface routines */
+
+static void exit_pydraw( SpaceScript * sc, short err )
+{
+ Script *script = NULL;
+
+ if( !sc || !sc->script )
+ return;
+
+ script = sc->script;
+
+ if( err ) {
+ PyErr_Print( );
+ script->flags = 0; /* mark script struct for deletion */
+ error( "Python script error: check console" );
+ scrarea_queue_redraw( sc->area );
+ }
+
+ BPy_Set_DrawButtonsList(sc->but_refs);
+ BPy_Free_DrawButtonsList(); /*clear all temp button references*/
+ sc->but_refs = NULL;
+
+ Py_XDECREF( ( PyObject * ) script->py_draw );
+ Py_XDECREF( ( PyObject * ) script->py_event );
+ Py_XDECREF( ( PyObject * ) script->py_button );
+
+ script->py_draw = script->py_event = script->py_button = NULL;
+}
+
+static void exec_callback( SpaceScript * sc, PyObject * callback,
+ PyObject * args )
+{
+ PyObject *result = PyObject_CallObject( callback, args );
+
+ if( result == NULL && sc->script ) { /* errors in the script */
+
+ if( sc->script->lastspace == SPACE_TEXT ) { /*if it can be an ALT+P script */
+ Text *text = G.main->text.first;
+
+ while( text ) { /* find it and free its compiled code */
+
+ if( !strcmp
+ ( text->id.name + 2,
+ sc->script->id.name + 2 ) ) {
+ BPY_free_compiled_text( text );
+ break;
+ }
+
+ text = text->id.next;
+ }
+ }
+ exit_pydraw( sc, 1 );
+ }
+
+ Py_XDECREF( result );
+ Py_DECREF( args );
+}
+
+/* BPY_spacescript_do_pywin_draw, the static spacescript_do_pywin_buttons and
+ * BPY_spacescript_do_pywin_event are the three functions responsible for
+ * calling the draw, buttons and event callbacks registered with Draw.Register
+ * (see Method_Register below). They are called (only the two BPY_ ones)
+ * from blender/src/drawscript.c */
+
+void BPY_spacescript_do_pywin_draw( SpaceScript * sc )
+{
+ uiBlock *block;
+ char butblock[20];
+ Script *script = sc->script;
+
+ sprintf( butblock, "win %d", curarea->win );
+ block = uiNewBlock( &curarea->uiblocks, butblock, UI_EMBOSSX,
+ UI_HELV, curarea->win );
+
+ if( script->py_draw ) {
+ if (sc->but_refs) {
+ BPy_Set_DrawButtonsList(sc->but_refs);
+ BPy_Free_DrawButtonsList(); /*clear all temp button references*/
+ }
+ sc->but_refs = PyList_New(0);
+ BPy_Set_DrawButtonsList(sc->but_refs);
+
+ glPushAttrib( GL_ALL_ATTRIB_BITS );
+ exec_callback( sc, script->py_draw, Py_BuildValue( "()" ) );
+ glPopAttrib( );
+ } else {
+ glClearColor( 0.4375, 0.4375, 0.4375, 0.0 );
+ glClear( GL_COLOR_BUFFER_BIT );
+ }
+
+ uiDrawBlock( block );
+
+ curarea->win_swap = WIN_BACK_OK;
+}
+
+static void spacescript_do_pywin_buttons( SpaceScript * sc,
+ unsigned short event )
+{
+ if( sc->script->py_button )
+ exec_callback( sc, sc->script->py_button,
+ Py_BuildValue( "(i)", event ) );
+}
+
+void BPY_spacescript_do_pywin_event( SpaceScript * sc, unsigned short event,
+ short val, char ascii )
+{
+ if( event == QKEY && G.qual & ( LR_ALTKEY | LR_CTRLKEY ) ) {
+ /* finish script: user pressed ALT+Q or CONTROL+Q */
+ Script *script = sc->script;
+
+ exit_pydraw( sc, 0 );
+
+ script->flags &= ~SCRIPT_GUI; /* we're done with this script */
+
+ return;
+ }
+
+ if (val) {
+
+ if (uiDoBlocks( &curarea->uiblocks, event ) != UI_NOTHING) event = 0;
+
+ if (event == UI_BUT_EVENT) {
+ /* check that event is in free range for script button events;
+ * read the comment before check_button_event() below to understand */
+ if (val >= EXPP_BUTTON_EVENTS_OFFSET && val < 0x4000)
+ spacescript_do_pywin_buttons(sc, val - EXPP_BUTTON_EVENTS_OFFSET);
+ return;
+ }
+ }
+
+ /* We use the "event" main module var, used by scriptlinks, to pass the ascii
+ * value to event callbacks (gui/event/button callbacks are not allowed
+ * inside scriptlinks, so this is ok) */
+ if( sc->script->py_event ) {
+ int pass_ascii = 0;
+ if (ascii > 31 && ascii != 127) {
+ pass_ascii = 1;
+ EXPP_dict_set_item_str(g_blenderdict, "event",
+ PyInt_FromLong((long)ascii));
+ }
+ exec_callback( sc, sc->script->py_event,
+ Py_BuildValue( "(ii)", event, val ) );
+ if (pass_ascii)
+ EXPP_dict_set_item_str(g_blenderdict, "event",
+ PyString_FromString(""));
+ }
+}
+
+static void exec_but_callback(void *pyobj, void *data)
+{
+ PyObject *result;
+ PyObject *pyvalue = NULL;
+ uiBut *but = (uiBut *)data;
+ PyObject *arg;
+ PyObject *callback = (PyObject *)pyobj;
+
+ double value = ui_get_but_val(but);
+
+ if (callback==NULL || callback == Py_None)
+ return;
+
+ /* Button types support
+ case MENU:
+ case TEX:
+ case TOG:
+ case NUMSLI:
+ case NUM:
+ case COL:
+ case BUT_NORMAL:
+ case BUT */
+ switch (but->type) {
+ case TEX:
+ /*printf("TEX\n");*/
+ pyvalue = PyString_FromString( (char *)but->poin );
+ break;
+ case NUM:
+ case NUMSLI:
+ case TOG:
+ case MENU:
+ if (but->pointype==FLO) {
+ /*printf("FLO\n");*/
+ pyvalue = PyFloat_FromDouble( (float)value );
+ } else if (but->pointype==INT) {
+ /*printf("INT\n");*/
+ pyvalue = PyInt_FromLong( (int)value );
+ } else if (but->pointype==SHO) {
+ /*printf("SHO\n");*/
+ pyvalue = PyInt_FromLong( (short)value );
+ }
+ break;
+ case COL:
+ case BUT_NORMAL:
+ {
+ float vec[3];
+ VECCOPY(vec, (float *)but->poin);
+ pyvalue = Py_BuildValue("(fff)", vec[0], vec[1], vec[2]);
+ break;
+ }
+ case BUT:
+ pyvalue = Py_None;
+ Py_INCREF(pyvalue);
+ break;
+ default:
+ pyvalue = Py_None;
+ Py_INCREF(pyvalue);
+ printf("Error, no button type matched.");
+ }
+
+ arg = PyTuple_New( 2 );
+ if (uiblock==NULL)
+ PyTuple_SetItem( arg, 0, PyInt_FromLong(but->retval - EXPP_BUTTON_EVENTS_OFFSET) );
+ else
+ PyTuple_SetItem( arg, 0, PyInt_FromLong(but->retval) );
+
+ PyTuple_SetItem( arg, 1, pyvalue );
+
+ result = PyObject_CallObject( callback, arg );
+ Py_DECREF(arg);
+
+ if (!result) {
+ Py_DECREF(pyvalue);
+ PyErr_Print( );
+ error( "Python script error: check console" );
+ }
+ Py_XDECREF( result );
+}
+
+/*note that this function populates the drawbutton ref lists.*/
+static void set_pycallback(uiBut *ubut, PyObject *callback, Button *but)
+{
+ PyObject *tuple;
+ if (!callback || !PyCallable_Check(callback)) {
+ if (M_Button_List && but) {
+ PyList_Append(M_Button_List, (PyObject*)but);
+ }
+ return;
+ }
+
+ if (M_Button_List) {
+ if (but) tuple = PyTuple_New(2);
+ else tuple = PyTuple_New(1);
+
+ /*the tuple API mandates this*/
+ Py_XINCREF(callback);
+ Py_XINCREF(but); /*this checks for NULL*/
+
+ PyTuple_SET_ITEM(tuple, 0, callback);
+ if (but) PyTuple_SET_ITEM(tuple, 1, (PyObject*)but);
+
+ PyList_Append(M_Button_List, tuple);
+ Py_DECREF(tuple); /*we have to do this to aovid double references.*/
+
+ uiButSetFunc(ubut, exec_but_callback, callback, ubut);
+ }
+}
+
+void BPy_Set_DrawButtonsList(void *list)
+{
+ M_Button_List = list;
+}
+
+/*this MUST be called after doing UI stuff.*/
+void BPy_Free_DrawButtonsList(void)
+{
+ /*Clear the list.*/
+ if (M_Button_List) {
+ PyList_SetSlice(M_Button_List, 0, PyList_Size(M_Button_List), NULL);
+ Py_DECREF(M_Button_List);
+ M_Button_List = NULL;
+ }
+}
+
+static PyObject *Method_Exit( PyObject * self )
+{
+ SpaceScript *sc;
+ Script *script;
+
+ /* if users call Draw.Exit when we are already out of the SPACE_SCRIPT, we
+ * simply return, for compatibility */
+ if( curarea->spacetype == SPACE_SCRIPT )
+ sc = curarea->spacedata.first;
+ else
+ Py_RETURN_NONE;
+
+ exit_pydraw( sc, 0 );
+
+ script = sc->script;
+
+ /* remove our lock to the current namespace */
+ script->flags &= ~SCRIPT_GUI;
+
+ Py_RETURN_NONE;
+}
+
+/* Method_Register (Draw.Register) registers callbacks for drawing, events
+ * and gui button events, so a script can continue executing after the
+ * interpreter reached its end and returned control to Blender. Everytime
+ * the SPACE_SCRIPT window with this script is redrawn, the registered
+ * callbacks are executed. */
+static PyObject *Method_Register( PyObject * self, PyObject * args )
+{
+ PyObject *newdrawc = NULL, *neweventc = NULL, *newbuttonc = NULL;
+ SpaceScript *sc;
+ Script *script;
+ int startspace = 0;
+
+ if( !PyArg_ParseTuple
+ ( args, "O|OO", &newdrawc, &neweventc, &newbuttonc ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected one or three PyObjects" );
+
+ if( !PyCallable_Check( newdrawc ) )
+ newdrawc = NULL;
+ if( !PyCallable_Check( neweventc ) )
+ neweventc = NULL;
+ if( !PyCallable_Check( newbuttonc ) )
+ newbuttonc = NULL;
+
+ if( !( newdrawc || neweventc || newbuttonc ) )
+ Py_RETURN_NONE;
+
+ startspace = curarea->spacetype;
+
+ /* first make sure the current area is of type SPACE_SCRIPT */
+ if( startspace != SPACE_SCRIPT )
+ newspace( curarea, SPACE_SCRIPT );
+
+ sc = curarea->spacedata.first;
+
+ /* There are two kinds of scripts:
+ * a) those that simply run, finish and return control to Blender;
+ * b) those that do like 'a)' above but leave callbacks for drawing,
+ * events and button events, with this Method_Register (Draw.Register
+ * in Python). These callbacks are called by scriptspaces (Scripts windows).
+ *
+ * We need to flag scripts that leave callbacks so their namespaces are
+ * not deleted when they 'finish' execution, because the callbacks will
+ * still need the namespace.
+ */
+
+ /* Let's see if this is a new script */
+ script = G.main->script.first;
+ while (script) {
+ if (script->flags & SCRIPT_RUNNING) break;
+ script = script->id.next;
+ }
+
+ if( !script ) {
+ /* not new, it's a left callback calling Register again */
+ script = sc->script;
+ if( !script ) {
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "Draw.Register can't be used inside script links" );
+ }
+ }
+ else sc->script = script;
+
+ /* Now we have the right script and can set a lock so its namespace can't be
+ * deleted for as long as we need it */
+ script->flags |= SCRIPT_GUI;
+
+ /* save the last space so we can go back to it upon finishing */
+ if( !script->lastspace )
+ script->lastspace = startspace;
+
+ /* clean the old callbacks */
+ exit_pydraw( sc, 0 );
+
+ /* prepare the new ones and insert them */
+ Py_XINCREF( newdrawc );
+ Py_XINCREF( neweventc );
+ Py_XINCREF( newbuttonc );
+
+ script->py_draw = newdrawc;
+ script->py_event = neweventc;
+ script->py_button = newbuttonc;
+
+ scrarea_queue_redraw( sc->area );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Method_Redraw( PyObject * self, PyObject * args )
+{
+ int after = 0;
+
+ if( !PyArg_ParseTuple( args, "|i", &after ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected int argument (or nothing)" );
+
+ if( after )
+ addafterqueue( curarea->win, REDRAW, 1 );
+ else
+ scrarea_queue_winredraw( curarea );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Method_Draw( PyObject * self )
+{
+ /*@ If forced drawing is disable queue a redraw event instead */
+ if( EXPP_disable_force_draw ) {
+ scrarea_queue_winredraw( curarea );
+ Py_RETURN_NONE;
+ }
+
+ scrarea_do_windraw( curarea );
+
+ screen_swapbuffers( );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Method_Create( PyObject * self, PyObject * args )
+{
+ Button *but = NULL;
+ PyObject *val;
+ char *newstr;
+
+ but = newbutton();
+ /* If this function dosnt sucseed this will need to be deallocated,
+ * make sure the type is NOT BSTRING_TYPE before deallocing -1 is ok.
+ * so we dont dealloc with an uninitialized value wich would be bad! */
+ if ( PyArg_ParseTuple( args, "fff", but->val.asvec, but->val.asvec+1, but->val.asvec+2 ) ) {
+ but->type = BVECTOR_TYPE;
+
+ } else if ( PyArg_ParseTuple( args, "O!", &PyFloat_Type, &val ) ) {
+ but->val.asfloat = (float)PyFloat_AS_DOUBLE(val);
+ but->type = BFLOAT_TYPE;
+
+ } else if ( PyArg_ParseTuple( args, "O!", &PyInt_Type, &val ) ) {
+ but->val.asint = (int)PyInt_AS_LONG(val);
+ but->type = BINT_TYPE;
+
+ } else if ( PyArg_ParseTuple( args, "s#", &newstr, &but->slen ) ) {
+ if (but->slen + 1 > UI_MAX_DRAW_STR) {
+ but->type = -1;
+ Py_DECREF((PyObject *)but); /* will remove */
+ but = NULL;
+ PyErr_SetString( PyExc_TypeError, "string is longer then 399 chars");
+ } else {
+ but->type = BSTRING_TYPE;
+ but->val.asstr = MEM_mallocN( but->slen + 1, "button string" );
+ BLI_strncpy( but->val.asstr, newstr, but->slen+1 );
+ }
+
+ } else {
+ but->type = -1;
+ Py_DECREF((PyObject *)but); /* will remove */
+ but = NULL;
+ PyErr_SetString( PyExc_TypeError, "expected string, float, int or 3-float tuple argument" );
+ }
+
+ if (but != NULL) {
+ PyErr_Clear();
+ }
+
+ return (PyObject*) but;
+}
+
+
+static PyObject *Method_UIBlock( PyObject * self, PyObject * args )
+{
+ PyObject *val = NULL;
+ PyObject *result = NULL;
+ ListBase listb= {NULL, NULL};
+
+ if ( !PyArg_ParseTuple( args, "O", &val ) || !PyCallable_Check( val ) )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected 1 python function and 2 ints" );
+
+ if (uiblock)
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "cannot run more then 1 UIBlock at a time" );
+
+ BPy_Set_DrawButtonsList(PyList_New(0));
+
+ mywinset(G.curscreen->mainwin);
+ uiblock= uiNewBlock(&listb, "numbuts", UI_EMBOSS, UI_HELV, G.curscreen->mainwin);
+
+ uiBlockSetFlag(uiblock, UI_BLOCK_LOOP|UI_BLOCK_REDRAW);
+ result = PyObject_CallObject( val, Py_BuildValue( "()" ) );
+
+ if (!result) {
+ PyErr_Print( );
+ error( "Python script error: check console" );
+ } else {
+ /* copied from do_clever_numbuts in toolbox.c */
+
+ /* Clear all events so tooltips work, this is not ideal and
+ only needed because calls from the menu still have some events
+ left over when do_clever_numbuts is called.
+ Calls from keyshortcuts do not have this problem.*/
+ ScrArea *sa;
+ BWinEvent temp_bevt;
+ for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
+ if(sa->win) {
+ while( bwin_qread( sa->win, &temp_bevt ) ) {}
+ }
+ if(sa->headwin) {
+ while( bwin_qread( sa->headwin, &temp_bevt ) ) {}
+ }
+ }
+ /* Done clearing events */
+
+ uiBoundsBlock(uiblock, 5);
+ uiDoBlocks(&listb, 0);
+ }
+ uiFreeBlocks(&listb);
+ uiblock = NULL;
+ BPy_Free_DrawButtonsList(); /*clear all temp button references*/
+
+ Py_XDECREF( result );
+ Py_RETURN_NONE;
+}
+
+void Set_uiBlock(uiBlock *block)
+{
+ uiblock = block;
+}
+
+static uiBlock *Get_uiBlock( void )
+{
+ char butblock[32];
+ /* Global, used now for UIBlock */
+ if (uiblock) {
+ return uiblock;
+ }
+ /* Local */
+ sprintf( butblock, "win %d", curarea->win );
+
+ return uiGetBlock( butblock, curarea );
+}
+
+
+/* We restrict the acceptable event numbers to a proper "free" range
+ * according to other spaces in Blender.
+ * winqread***space() (space events callbacks) use short for events
+ * (called 'val' there) and we also translate by EXPP_BUTTON_EVENTS_OFFSET
+ * to get rid of unwanted events (check BPY_do_pywin_events above for
+ * explanation). This function takes care of that and proper checking: */
+static int check_button_event(int *event) {
+ if ((*event < EXPP_BUTTON_EVENTS_MIN) ||
+ (*event > EXPP_BUTTON_EVENTS_MAX)) {
+ return -1;
+ }
+ if (uiblock==NULL) /* For UIBlock we need non offset UI elements */
+ *event += EXPP_BUTTON_EVENTS_OFFSET;
+ return 0;
+}
+
+static PyObject *Method_BeginAlign( PyObject * self, PyObject * args )
+{
+ uiBlock *block = Get_uiBlock( );
+
+ if (block)
+ uiBlockBeginAlign(block);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Method_EndAlign( PyObject * self, PyObject * args )
+{
+ uiBlock *block = Get_uiBlock( );
+
+ if (block)
+ uiBlockEndAlign(block);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Method_Button( PyObject * self, PyObject * args )
+{
+ uiBlock *block;
+ char *name, *tip = NULL;
+ int event;
+ int x, y, w, h;
+ PyObject *callback=NULL;
+
+ if( !PyArg_ParseTuple( args, "siiiii|sO", &name, &event,
+ &x, &y, &w, &h, &tip, &callback ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a string, five ints and optionally string and callback arguments" );
+
+ UI_METHOD_ERRORCHECK;
+
+ block = Get_uiBlock( );
+ if( block ) {
+ uiBut *ubut = uiDefBut( block, BUT, event, name, (short)x, (short)y, (short)w, (short)h, 0, 0, 0, 0, 0, tip );
+ set_pycallback(ubut, callback, NULL);
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *Method_Menu( PyObject * self, PyObject * args )
+{
+ uiBlock *block;
+ char *name, *tip = NULL;
+ int event, def;
+ int x, y, w, h;
+ Button *but;
+ PyObject *callback=NULL;
+
+ if( !PyArg_ParseTuple( args, "siiiiii|sO", &name, &event,
+ &x, &y, &w, &h, &def, &tip, &callback ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a string, six ints and optionally string and callback arguments" );
+
+ UI_METHOD_ERRORCHECK;
+
+ but = newbutton( );
+ but->type = BINT_TYPE;
+ but->val.asint = def;
+ if (tip) strncpy(but->tooltip, tip, BPY_MAX_TOOLTIP);
+
+ block = Get_uiBlock( );
+ if( block ) {
+ uiBut *ubut = uiDefButI( block, MENU, event, name, (short)x, (short)y, (short)w, (short)h,
+ &but->val.asint, 0, 0, 0, 0, but->tooltip );
+ set_pycallback(ubut, callback, but);
+ }
+ return ( PyObject * ) but;
+}
+
+static PyObject *Method_Toggle( PyObject * self, PyObject * args )
+{
+ uiBlock *block;
+ char *name, *tip = NULL;
+ int event;
+ int x, y, w, h, def;
+ Button *but;
+ PyObject *callback=NULL;
+
+ if( !PyArg_ParseTuple( args, "siiiiii|sO", &name, &event,
+ &x, &y, &w, &h, &def, &tip, &callback ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a string, six ints and optionally string and callback arguments" );
+
+ UI_METHOD_ERRORCHECK;
+
+ but = newbutton( );
+ but->type = BINT_TYPE;
+ but->val.asint = def;
+ if (tip) strncpy(but->tooltip, tip, BPY_MAX_TOOLTIP);
+
+ block = Get_uiBlock( );
+ if( block ) {
+ uiBut *ubut = uiDefButI( block, TOG, event, name, (short)x, (short)y, (short)w, (short)h,
+ &but->val.asint, 0, 0, 0, 0, but->tooltip );
+ set_pycallback(ubut, callback, but);
+ }
+ return ( PyObject * ) but;
+}
+
+/*@DO NOT TOUCH THIS FUNCTION !
+ Redrawing a slider inside its own callback routine is actually forbidden
+ with the current toolkit architecture (button routines are not reentrant).
+ But it works anyway.
+ XXX This is condemned to be dinosource in future - it's a hack.
+ */
+
+static void py_slider_update( void *butv, void *data2_unused )
+{
+ uiBut *but = butv;
+ PyObject *ref = Py_BuildValue( "(i)", SPACE_VIEW3D );
+ PyObject *ret = NULL;
+
+ EXPP_disable_force_draw = 1;
+ /*@ Disable forced drawing, otherwise the button object which
+ * is still being used might be deleted */
+
+ curarea->win_swap = WIN_BACK_OK;
+ /* removed global uiFrontBuf (contact ton when this goes wrong here) */
+
+ disable_where_script( 1 );
+
+ spacescript_do_pywin_buttons( curarea->spacedata.first,
+ (unsigned short)uiButGetRetVal( but ) - EXPP_BUTTON_EVENTS_OFFSET );
+
+ /* XXX useless right now, investigate better before a bcon 5 */
+ ret = M_Window_Redraw( 0, ref );
+
+ Py_XDECREF(ref);
+ Py_XDECREF(ret);
+
+ disable_where_script( 0 );
+
+ EXPP_disable_force_draw = 0;
+}
+
+static PyObject *Method_Slider( PyObject * self, PyObject * args )
+{
+ uiBlock *block;
+ char *name, *tip = NULL;
+ int event;
+ int x, y, w, h, realtime = 1;
+ Button *but;
+ PyObject *mino, *maxo, *inio;
+ PyObject *callback=NULL;
+
+ if( !PyArg_ParseTuple( args, "siiiiiOOO|isO", &name, &event,
+ &x, &y, &w, &h, &inio, &mino, &maxo, &realtime,
+ &tip, &callback ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a string, five ints, three PyObjects\n\
+ and optionally int, string and callback arguments" );
+
+ if(realtime && uiblock)
+ realtime = 0; /* realtime dosnt work with UIBlock */
+
+ UI_METHOD_ERRORCHECK;
+
+ but = newbutton( );
+
+ if( PyFloat_Check( inio ) ) {
+ float ini, min, max;
+
+ ini = (float)PyFloat_AsDouble( inio );
+ min = (float)PyFloat_AsDouble( mino );
+ max = (float)PyFloat_AsDouble( maxo );
+
+ but->type = BFLOAT_TYPE;
+ but->val.asfloat = ini;
+ if (tip) strncpy(but->tooltip, tip, BPY_MAX_TOOLTIP);
+
+ block = Get_uiBlock( );
+ if( block ) {
+ uiBut *ubut;
+ ubut = uiDefButF( block, NUMSLI, event, name, (short)x, (short)y, (short)w,
+ (short)h, &but->val.asfloat, min, max, 0, 0,
+ but->tooltip );
+ if( realtime )
+ uiButSetFunc( ubut, py_slider_update, ubut, NULL );
+ else
+ set_pycallback(ubut, callback, but);
+ }
+ } else {
+ int ini, min, max;
+
+ ini = PyInt_AsLong( inio );
+ min = PyInt_AsLong( mino );
+ max = PyInt_AsLong( maxo );
+
+ but->type = BINT_TYPE;
+ but->val.asint = ini;
+ if (tip) strncpy(but->tooltip, tip, BPY_MAX_TOOLTIP);
+
+ block = Get_uiBlock( );
+ if( block ) {
+ uiBut *ubut;
+ ubut = uiDefButI( block, NUMSLI, event, name, (short)x, (short)y, (short)w,
+ (short)h, &but->val.asint, (float)min, (float)max, 0, 0,
+ but->tooltip );
+ if( realtime )
+ uiButSetFunc( ubut, py_slider_update, ubut, NULL );
+ else
+ set_pycallback(ubut, callback, but);
+ }
+ }
+ return ( PyObject * ) but;
+}
+
+static PyObject *Method_Scrollbar( PyObject * self, PyObject * args )
+{
+ char *tip = NULL;
+ uiBlock *block;
+ int event;
+ int x, y, w, h, realtime = 1;
+ Button *but;
+ PyObject *mino, *maxo, *inio;
+ float ini, min, max;
+ uiBut *ubut;
+
+ if( !PyArg_ParseTuple( args, "iiiiiOOO|isO", &event, &x, &y, &w, &h,
+ &inio, &mino, &maxo, &realtime, &tip ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected five ints, three PyObjects and optionally\n\
+another int and string as arguments" );
+
+ if( !PyNumber_Check( inio ) || !PyNumber_Check( inio )
+ || !PyNumber_Check( inio ) )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected numbers for initial, min, and max" );
+
+ if (check_button_event(&event) == -1)
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "button event argument must be in the range [0, 16382]");
+
+ but = newbutton( );
+ if (tip) strncpy(but->tooltip, tip, BPY_MAX_TOOLTIP);
+
+ if( PyFloat_Check( inio ) )
+ but->type = BFLOAT_TYPE;
+ else
+ but->type = BINT_TYPE;
+
+ ini = (float)PyFloat_AsDouble( inio );
+ min = (float)PyFloat_AsDouble( mino );
+ max = (float)PyFloat_AsDouble( maxo );
+
+ block = Get_uiBlock( );
+
+ if( block ) {
+ if( but->type == BFLOAT_TYPE ) {
+ but->val.asfloat = ini;
+ ubut = uiDefButF( block, SCROLL, event, "", (short)x, (short)y, (short)w, (short)h,
+ &but->val.asfloat, min, max, 0, 0, but->tooltip );
+ if( realtime )
+ uiButSetFunc( ubut, py_slider_update, ubut, NULL );
+ } else {
+ but->val.asint = (int)ini;
+ ubut = uiDefButI( block, SCROLL, event, "", (short)x, (short)y, (short)w, (short)h,
+ &but->val.asint, min, max, 0, 0, but->tooltip );
+ if( realtime )
+ uiButSetFunc( ubut, py_slider_update, ubut, NULL );
+ }
+ }
+ return ( PyObject * ) but;
+}
+
+static PyObject *Method_ColorPicker( PyObject * self, PyObject * args )
+{
+ char USAGE_ERROR[] = "expected a 3-float tuple of values between 0 and 1";
+ Button *but;
+ PyObject *inio;
+ uiBlock *block;
+ char *tip = NULL;
+ float col[3];
+ int event;
+ short x, y, w, h;
+ PyObject *callback=NULL;
+
+ if( !PyArg_ParseTuple( args, "ihhhhO!|sO", &event,
+ &x, &y, &w, &h, &PyTuple_Type, &inio, &tip, &callback ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected five ints, one tuple and optionally string and callback arguments" );
+
+ UI_METHOD_ERRORCHECK;
+
+ if ( !PyArg_ParseTuple( inio, "fff", col, col+1, col+2 ) )
+ return EXPP_ReturnPyObjError( PyExc_ValueError, USAGE_ERROR);
+
+ if ( col[0] < 0 || col[0] > 1
+ || col[1] < 0 || col[1] > 1
+ || col[2] < 0 || col[2] > 1 )
+ return EXPP_ReturnPyObjError( PyExc_ValueError, USAGE_ERROR);
+
+ if ( EXPP_check_sequence_consistency( inio, &PyFloat_Type ) != 1 )
+ return EXPP_ReturnPyObjError( PyExc_ValueError, USAGE_ERROR);
+
+ but = newbutton();
+
+ but->type = BVECTOR_TYPE;
+ but->val.asvec[0] = col[0];
+ but->val.asvec[1] = col[1];
+ but->val.asvec[2] = col[2];
+ if (tip) strncpy(but->tooltip, tip, BPY_MAX_TOOLTIP);
+
+ block = Get_uiBlock( );
+ if( block ) {
+ uiBut *ubut;
+ ubut = uiDefButF( block, COL, event, "", x, y, w, h, but->val.asvec, 0, 0, 0, 0, but->tooltip);
+ set_pycallback(ubut, callback, but);
+ }
+
+ return ( PyObject * ) but;
+}
+
+
+
+static PyObject *Method_Normal( PyObject * self, PyObject * args )
+{
+ char USAGE_ERROR[] = "expected a 3-float tuple of values between -1 and 1";
+ Button *but;
+ PyObject *inio;
+ uiBlock *block;
+ char *tip = NULL;
+ float nor[3];
+ int event;
+ short x, y, w, h;
+ PyObject *callback=NULL;
+
+ if( !PyArg_ParseTuple( args, "ihhhhO!|sO", &event,
+ &x, &y, &w, &h, &PyTuple_Type, &inio, &tip, &callback ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected five ints, one tuple and optionally string and callback arguments" );
+
+ UI_METHOD_ERRORCHECK;
+
+ if ( !PyArg_ParseTuple( inio, "fff", nor, nor+1, nor+2 ) )
+ return EXPP_ReturnPyObjError( PyExc_ValueError, USAGE_ERROR);
+
+ if ( EXPP_check_sequence_consistency( inio, &PyFloat_Type ) != 1 )
+ return EXPP_ReturnPyObjError( PyExc_ValueError, USAGE_ERROR);
+
+ but = newbutton();
+ if (tip) strncpy(but->tooltip, tip, BPY_MAX_TOOLTIP);
+
+ but->type = BVECTOR_TYPE;
+ but->val.asvec[0] = nor[0];
+ but->val.asvec[1] = nor[1];
+ but->val.asvec[2] = nor[2];
+
+ block = Get_uiBlock( );
+ if( block ) {
+ uiBut *ubut;
+ ubut = uiDefButF( block, BUT_NORMAL, event, "", x, y, w, h, but->val.asvec, 0.0f, 1.0f, 0, 0, but->tooltip);
+ set_pycallback(ubut, callback, but);
+ }
+
+ return ( PyObject * ) but;
+}
+
+static PyObject *Method_Number( PyObject * self, PyObject * args )
+{
+ uiBlock *block;
+ char *name, *tip = NULL;
+ int event;
+ int x, y, w, h;
+ Button *but;
+ PyObject *mino, *maxo, *inio;
+ PyObject *callback=NULL;
+ uiBut *ubut= NULL;
+
+ if( !PyArg_ParseTuple( args, "siiiiiOOO|sO", &name, &event,
+ &x, &y, &w, &h, &inio, &mino, &maxo, &tip, &callback ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a string, five ints, three PyObjects and\n\
+ optionally string and callback arguments" );
+
+ UI_METHOD_ERRORCHECK;
+
+ but = newbutton( );
+ if (tip) strncpy(but->tooltip, tip, BPY_MAX_TOOLTIP);
+ block = Get_uiBlock( );
+
+ if( PyFloat_Check( inio ) ) {
+ float ini, min, max, range, precission=0;
+
+ ini = (float)PyFloat_AsDouble( inio );
+ min = (float)PyFloat_AsDouble( mino );
+ max = (float)PyFloat_AsDouble( maxo );
+
+ range= (float)fabs(max-min); /* Click step will be a 10th of the range. */
+ if (!range) range= 1.0f; /* avoid any odd errors */
+
+ /* set the precission to display*/
+ if (range>=1000.0f) precission=1.0f;
+ else if (range>=100.0f) precission=2.0f;
+ else if (range>=10.0f) precission=3.0f;
+ else precission=4.0f;
+
+ but->type = BFLOAT_TYPE;
+ but->val.asfloat = ini;
+
+
+ if( block )
+ ubut= uiDefButF( block, NUM, event, name, (short)x, (short)y, (short)w, (short)h,
+ &but->val.asfloat, min, max, 10*range, precission, but->tooltip );
+ } else {
+ int ini, min, max;
+
+ ini = PyInt_AsLong( inio );
+ min = PyInt_AsLong( mino );
+ max = PyInt_AsLong( maxo );
+
+ but->type = BINT_TYPE;
+ but->val.asint = ini;
+
+ if( block )
+ ubut= uiDefButI( block, NUM, event, name, (short)x, (short)y, (short)w, (short)h,
+ &but->val.asint, (float)min, (float)max, 0, 0, but->tooltip );
+ }
+
+ if (ubut) set_pycallback(ubut, callback, but);
+
+ return ( PyObject * ) but;
+}
+
+static PyObject *Method_String( PyObject * self, PyObject * args )
+{
+ uiBlock *block;
+ char *info_arg = NULL, *tip = NULL, *newstr = NULL;
+ char *info_str = NULL, *info_str0 = " ";
+ int event;
+ int x, y, w, h, len, real_len = 0;
+ Button *but;
+ PyObject *callback=NULL;
+
+ if( !PyArg_ParseTuple( args, "siiiiisi|sO", &info_arg, &event,
+ &x, &y, &w, &h, &newstr, &len, &tip, &callback ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a string, five ints, a string, an int and\n\
+ optionally string and callback arguments" );
+
+ UI_METHOD_ERRORCHECK;
+
+ if (len > (UI_MAX_DRAW_STR - 1))
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "The maximum length of a string is 399, your value is too high.");
+
+ real_len = strlen(newstr);
+ if (real_len > len) real_len = len;
+
+ but = newbutton( );
+ but->type = BSTRING_TYPE;
+ but->slen = len;
+ but->val.asstr = MEM_mallocN( len + 1, "pybutton str" );
+ if (tip) strncpy(but->tooltip, tip, BPY_MAX_TOOLTIP);
+
+ BLI_strncpy( but->val.asstr, newstr, len + 1); /* adds '\0' */
+ but->val.asstr[real_len] = '\0';
+
+ if (info_arg[0] == '\0') info_str = info_str0;
+ else info_str = info_arg;
+
+ block = Get_uiBlock( );
+ if( block ) {
+ uiBut *ubut = uiDefBut( block, TEX, event, info_str, (short)x, (short)y, (short)w, (short)h,
+ but->val.asstr, 0, (float)len, 0, 0, but->tooltip );
+ set_pycallback(ubut, callback, but);
+ }
+ return ( PyObject * ) but;
+}
+
+static PyObject *Method_GetStringWidth( PyObject * self, PyObject * args )
+{
+ char *text;
+ char *font_str = "normal";
+ struct BMF_Font *font;
+ PyObject *width;
+
+ if( !PyArg_ParseTuple( args, "s|s", &text, &font_str ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected one or two string arguments" );
+
+ if( !strcmp( font_str, "normal" ) )
+ font = ( &G )->font;
+ else if( !strcmp( font_str, "large" ) )
+ font = BMF_GetFont(BMF_kScreen15);
+ else if( !strcmp( font_str, "small" ) )
+ font = ( &G )->fonts;
+ else if( !strcmp( font_str, "tiny" ) )
+ font = ( &G )->fontss;
+ else
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "\"font\" must be: 'large', 'normal' (default), 'small' or 'tiny'." );
+
+ width = PyInt_FromLong( BMF_GetStringWidth( font, text ) );
+
+ if( !width )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create PyInt" );
+
+ return width;
+}
+
+static PyObject *Method_Text( PyObject * self, PyObject * args )
+{
+ char *text;
+ char *font_str = NULL;
+ struct BMF_Font *font;
+
+ if( !PyArg_ParseTuple( args, "s|s", &text, &font_str ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected one or two string arguments" );
+
+ if( !font_str )
+ font = ( &G )->font;
+ else if( !strcmp( font_str, "large" ) )
+ font = BMF_GetFont(BMF_kScreen15);
+ else if( !strcmp( font_str, "normal" ) )
+ font = ( &G )->font;
+ else if( !strcmp( font_str, "small" ) )
+ font = ( &G )->fonts;
+ else if( !strcmp( font_str, "tiny" ) )
+ font = ( &G )->fontss;
+ else
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "\"font\" must be: 'normal' (default), 'large', 'small' or 'tiny'." );
+
+ BMF_DrawString( font, text );
+
+ return PyInt_FromLong( BMF_GetStringWidth( font, text ) );
+}
+
+static PyObject *Method_Label( PyObject * self, PyObject * args )
+{
+ uiBlock *block;
+ char *text;
+ int x, y, w, h;
+
+ if( !PyArg_ParseTuple( args, "siiii", &text, &x, &y, &w, &h ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a string and four ints" );
+
+ block = Get_uiBlock( );
+ uiDefBut(block, LABEL, 0, text, x, y, w, h, 0, 0, 0, 0, 0, "");
+
+ Py_RETURN_NONE;
+}
+
+
+static PyObject *Method_PupMenu( PyObject * self, PyObject * args )
+{
+ char *text;
+ int maxrow = -1;
+ PyObject *ret;
+
+ if( !PyArg_ParseTuple( args, "s|i", &text, &maxrow ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a string and optionally an int as arguments" );
+
+ if( maxrow >= 0 )
+ ret = PyInt_FromLong( pupmenu_col( text, maxrow ) );
+ else
+ ret = PyInt_FromLong( pupmenu( text ) );
+
+ if( ret )
+ return ret;
+
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create a PyInt" );
+}
+
+static PyObject *Method_PupIntInput( PyObject * self, PyObject * args )
+{
+ char *text = NULL;
+ int min = 0, max = 1;
+ short var = 0;
+ PyObject *ret = NULL;
+
+ if( !PyArg_ParseTuple( args, "s|hii", &text, &var, &min, &max ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected 1 string and 3 int arguments" );
+
+ if( button( &var, (short)min, (short)max, text ) == 0 ) {
+ Py_INCREF( Py_None );
+ return Py_None;
+ }
+ ret = PyInt_FromLong( var );
+ if( ret )
+ return ret;
+
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create a PyInt" );
+}
+
+static PyObject *Method_PupFloatInput( PyObject * self, PyObject * args )
+{
+ char *text = NULL;
+ float min = 0, max = 1, var = 0, a1 = 10, a2 = 2;
+ PyObject *ret = NULL;
+
+ if( !PyArg_ParseTuple
+ ( args, "s|fffff", &text, &var, &min, &max, &a1, &a2 ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected 1 string and 5 float arguments" );
+
+ if( fbutton( &var, min, max, a1, a2, text ) == 0 ) {
+ Py_INCREF( Py_None );
+ return Py_None;
+ }
+ ret = PyFloat_FromDouble( var );
+ if( ret )
+ return ret;
+
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create a PyFloat" );
+}
+
+static PyObject *Method_PupStrInput( PyObject * self, PyObject * args )
+{
+ char *text = NULL, *textMsg = NULL;
+ char tmp[101];
+ char max = 20;
+ PyObject *ret = NULL;
+
+ if( !PyArg_ParseTuple( args, "ss|b", &textMsg, &text, &max ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected 2 strings and 1 int" );
+
+ if( ( max <= 0 ) || ( max > 100 ) )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "max string length value must be in the range [1, 100]." );
+
+ /* copying the text string handles both cases:
+ * max < strlen(text) (by truncating) and
+ * max > strlen(text) (by expanding to strlen(tmp)) */
+ BLI_strncpy( tmp, text, max + 1 );
+
+ if( sbutton( tmp, 0, max, textMsg ) == 0 ) {
+ Py_INCREF( Py_None );
+ return Py_None;
+ }
+
+ ret = PyString_FromString( tmp );
+
+ if( ret )
+ return ret;
+
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create a PyString" );
+}
+
+static PyObject *Method_PupBlock( PyObject * self, PyObject * args )
+{
+ PyObject *pyList, *pyItem;
+ float min, max;
+ int len, i;
+ char *title;
+
+ if (!PyArg_ParseTuple( args, "sO", &title, &pyList ) || !PySequence_Check( pyList ))
+ return EXPP_ReturnPyObjError( PyExc_TypeError, "expected a string and a sequence" );
+
+
+ len = PySequence_Length(pyList);
+
+ if (len == 0)
+ return EXPP_ReturnPyObjError( PyExc_ValueError, "expected a string and a non-empty sequence." );
+
+ if (len > 120) /* LIMIT DEFINED IN toolbox.c */
+ return EXPP_ReturnPyObjError( PyExc_ValueError, "sequence cannot have more than 120 elements" );
+
+ for ( i=0 ; i<len ; i++ ) {
+ PyObject *pyMin = NULL, *pyMax = NULL;
+ PyObject *f1, *f2;
+ Button *but = NULL;
+ int tlen;
+ char *text, *tip = NULL;
+
+ pyItem = PySequence_GetItem( pyList, i );
+ if (!pyItem)
+ return NULL;
+
+ if (PyString_Check( pyItem )) {
+ tlen = -2; /* single string for label, giving it a special len for later */
+ }
+ else if (PyTuple_Check( pyItem )) {
+ /* tuple for other button, get the length for later */
+ tlen = PyTuple_Size( pyItem );
+ }
+ else {
+ /* Neither a string or a tuple, error */
+ Py_DECREF( pyItem );
+ return EXPP_ReturnPyObjError( PyExc_ValueError, "expected a string or a tuple containing 2 to 5 values." );
+ }
+
+ switch (tlen) {
+ case -2: /* LABEL */
+ text = PyString_AsString( pyItem );
+ add_numbut(i, LABEL, text, 0, 0, NULL, NULL);
+ break;
+ case 2: /* TOGGLE (no tooltip) */
+ case 3: /* TOGGLE */
+ if (!PyArg_ParseTuple( pyItem, "sO!|s", &text, &Button_Type, &but, &tip )) {
+ Py_DECREF( pyItem );
+ return EXPP_ReturnPyObjError( PyExc_ValueError, "expected a tuple containing a string, a Button object and optionally a string for toggles" );
+ }
+
+ if (but->type != BINT_TYPE) {
+ Py_DECREF( pyItem );
+ return EXPP_ReturnPyObjError( PyExc_ValueError, "Button object for toggles should hold an integer" );
+ }
+
+ add_numbut(i, TOG|INT, text, 0, 0, &but->val.asint, tip);
+ break;
+ case 4: /* TEX and NUM (no tooltip) */
+ case 5: /* TEX and NUM */
+ if (!PyArg_ParseTuple( pyItem, "sO!OO|s", &text, &Button_Type, &but, &pyMin, &pyMax, &tip )) {
+ Py_DECREF( pyItem );
+ return EXPP_ReturnPyObjError( PyExc_ValueError, "expected a tuple containing a string, a Button object, two numerical values and optionally a string for Text and Num buttons" );
+ }
+
+ f1 = PyNumber_Float(pyMin);
+ f2 = PyNumber_Float(pyMax);
+
+ if (!f1 || !f2) {
+ Py_DECREF( pyItem );
+ return EXPP_ReturnPyObjError( PyExc_ValueError, "expected a tuple containing a string, a Button object, two numerical values and optionally a string for Text and Num buttons" );
+ }
+
+ min = (float)PyFloat_AS_DOUBLE(f1);
+ max = (float)PyFloat_AS_DOUBLE(f2);
+ Py_DECREF( f1 );
+ Py_DECREF( f2 );
+
+ switch ( but->type ) {
+ case BINT_TYPE:
+ add_numbut(i, NUM|INT, text, min, max, &but->val.asint, tip);
+ break;
+ case BFLOAT_TYPE:
+ add_numbut(i, NUM|FLO, text, min, max, &but->val.asfloat, tip);
+ break;
+ case BSTRING_TYPE:
+ if (max+1>UI_MAX_DRAW_STR) {
+ Py_DECREF( pyItem );
+ return EXPP_ReturnPyObjError( PyExc_ValueError, "length of a string buttons must be less then 400" );
+ }
+ max = (float)floor(max);
+
+ if (max > but->slen) {
+ int old_len = but->slen;
+ char *old_str = but->val.asstr;
+ but->slen = (int)max;
+ but->val.asstr = MEM_callocN( but->slen + 1, "button pupblock");
+ BLI_strncpy( but->val.asstr, old_str, old_len + 1 );
+ MEM_freeN(old_str);
+ }
+
+ add_numbut(i, TEX, text, 0.0f, max, but->val.asstr, tip);
+ }
+
+ break;
+ default:
+ Py_DECREF( pyItem );
+ return EXPP_ReturnPyObjError( PyExc_ValueError, "expected a string or a tuple containing 2 to 5 values." );
+ }
+ Py_DECREF( pyItem );
+ }
+
+ if (do_clever_numbuts(title, len, REDRAW))
+ return EXPP_incr_ret_True();
+ else
+ return EXPP_incr_ret_False();
+}
+
+
+/*****************************************************************************
+ * Function: Method_Image *
+ * Python equivalent: Blender.Draw.Image *
+ * *
+ * @author Jonathan Merritt <j.merritt@pgrad.unimelb.edu.au> *
+ ****************************************************************************/
+static PyObject *Method_Image( PyObject * self, PyObject * args )
+{
+ PyObject *pyObjImage;
+ BPy_Image *py_img;
+ Image *image;
+ ImBuf *ibuf;
+ float originX, originY;
+ float zoomX = 1.0, zoomY = 1.0;
+ int clipX = 0, clipY = 0, clipW = -1, clipH = -1;
+ /*GLfloat scissorBox[4];*/
+
+ /* parse the arguments passed-in from Python */
+ if( !PyArg_ParseTuple( args, "Off|ffiiii", &pyObjImage,
+ &originX, &originY, &zoomX, &zoomY,
+ &clipX, &clipY, &clipW, &clipH ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a Blender.Image and 2 floats, and " \
+ "optionally 2 floats and 4 ints as arguments" );
+ /* check that the first PyObject is actually a Blender.Image */
+ if( !BPy_Image_Check( pyObjImage ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a Blender.Image and 2 floats, and " \
+ "optionally 2 floats and 4 ints as arguments" );
+ /* check that the zoom factors are valid */
+ if( ( zoomX <= 0.0 ) || ( zoomY <= 0.0 ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "invalid zoom factors - they must be >= 0.0" );
+
+ /* fetch a C Image pointer from the passed-in Python object */
+ py_img = ( BPy_Image * ) pyObjImage;
+ image = py_img->image;
+ ibuf = BKE_image_get_ibuf( image, NULL );
+
+ if( !ibuf ) /* if failed to load the image */
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't load image data in Blender" );
+ if( !ibuf->rect ) /* no float yet */
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "Image has no byte rect" );
+
+ /* Update the time tag of the image */
+ tag_image_time(image);
+
+ /* set up a valid clipping rectangle. if no clip rectangle was
+ * given, this results in inclusion of the entire image. otherwise,
+ * the clipping is just checked against the bounds of the image.
+ * if clipW or clipH are less than zero then they include as much of
+ * the image as they can. */
+ clipX = EXPP_ClampInt( clipX, 0, ibuf->x );
+ clipY = EXPP_ClampInt( clipY, 0, ibuf->y );
+ if( ( clipW < 0 ) || ( clipW > ( ibuf->x - clipW ) ) )
+ clipW = ibuf->x - clipX;
+ if( ( clipH < 0 ) || ( clipH > ( ibuf->y - clipH ) ) )
+ clipH = ibuf->y - clipY;
+
+ /* -- we are "Go" to Draw! -- */
+
+ /* set the raster position.
+ *
+ * If the raster position is negative, then using glRasterPos2i()
+ * directly would cause it to be clipped. Instead, we first establish
+ * a valid raster position within the clipping rectangle of the
+ * window and then use glBitmap() with a NULL image pointer to offset
+ * it to the true position we require. To pick an initial valid
+ * raster position within the viewport, we query the clipping rectangle
+ * and use its lower-left pixel.
+ *
+ * This particular technique is documented in the glRasterPos() man
+ * page, although I haven't seen it used elsewhere in Blender.
+ */
+
+ /* update (W): to fix a bug where images wouldn't get drawn if the bottom
+ * left corner of the Scripts win were above a given height or to the right
+ * of a given width, the code below is being commented out. It should not
+ * be needed anyway, because spaces in Blender are projected to lie inside
+ * their areas, see src/drawscript.c for example. Note: the
+ * glaRasterPosSafe2i function in src/glutil.c does use the commented out
+ * technique, but with 0,0 instead of scissorBox. This function can be
+ * a little optimized, based on glaDrawPixelsSafe in that same fine, but
+ * we're too close to release 2.37 right now. */
+ /*
+ glGetFloatv( GL_SCISSOR_BOX, scissorBox );
+ glRasterPos2i( scissorBox[0], scissorBox[1] );
+ glBitmap( 0, 0, 0.0, 0.0,
+ originX-scissorBox[0], originY-scissorBox[1], NULL );
+ */
+
+ /* update (cont.): using these two lines instead:
+ * (based on glaRasterPosSafe2i, but Ken Hughes deserves credit
+ * for suggesting this exact fix in the bug tracker) */
+ glRasterPos2i(0, 0);
+ glBitmap( 0, 0, 0.0, 0.0, originX, originY, NULL );
+
+ /* set the zoom */
+ glPixelZoom( zoomX, zoomY );
+
+ /* set the width of the image (ROW_LENGTH), and the offset to the
+ * clip origin within the image in x (SKIP_PIXELS) and
+ * y (SKIP_ROWS) */
+ glPixelStorei( GL_UNPACK_ROW_LENGTH, ibuf->x );
+ glPixelStorei( GL_UNPACK_SKIP_PIXELS, clipX );
+ glPixelStorei( GL_UNPACK_SKIP_ROWS, clipY );
+
+ /* draw the image */
+ glDrawPixels( clipW, clipH, GL_RGBA, GL_UNSIGNED_BYTE,
+ ibuf->rect );
+
+ /* restore the defaults for some parameters (we could also use a
+ * glPushClientAttrib() and glPopClientAttrib() pair). */
+ glPixelZoom( 1.0, 1.0 );
+ glPixelStorei( GL_UNPACK_SKIP_ROWS, 0 );
+ glPixelStorei( GL_UNPACK_SKIP_PIXELS, 0 );
+ glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 );
+
+ Py_INCREF( Py_None );
+ return Py_None;
+
+}
+
+PyObject *Draw_Init( void )
+{
+ PyObject *submodule, *dict;
+
+ if( PyType_Ready( &Button_Type) < 0)
+ Py_RETURN_NONE;
+
+ submodule = Py_InitModule3( "Blender.Draw", Draw_methods, Draw_doc );
+
+ dict = PyModule_GetDict( submodule );
+
+#define EXPP_ADDCONST(x) \
+ EXPP_dict_set_item_str(dict, #x, PyInt_FromLong(x))
+
+ /* So, for example:
+ * EXPP_ADDCONST(LEFTMOUSE) becomes
+ * EXPP_dict_set_item_str(dict, "LEFTMOUSE", PyInt_FromLong(LEFTMOUSE))
+ */
+
+ EXPP_ADDCONST( LEFTMOUSE );
+ EXPP_ADDCONST( MIDDLEMOUSE );
+ EXPP_ADDCONST( RIGHTMOUSE );
+ EXPP_ADDCONST( WHEELUPMOUSE );
+ EXPP_ADDCONST( WHEELDOWNMOUSE );
+ EXPP_ADDCONST( MOUSEX );
+ EXPP_ADDCONST( MOUSEY );
+ EXPP_ADDCONST( TIMER0 );
+ EXPP_ADDCONST( TIMER1 );
+ EXPP_ADDCONST( TIMER2 );
+ EXPP_ADDCONST( TIMER3 );
+ EXPP_ADDCONST( KEYBD );
+ EXPP_ADDCONST( RAWKEYBD );
+ EXPP_ADDCONST( REDRAW );
+ EXPP_ADDCONST( INPUTCHANGE );
+ EXPP_ADDCONST( QFULL );
+ EXPP_ADDCONST( WINFREEZE );
+ EXPP_ADDCONST( WINTHAW );
+ EXPP_ADDCONST( WINCLOSE );
+ EXPP_ADDCONST( WINQUIT );
+#ifndef IRISGL
+ EXPP_ADDCONST( Q_FIRSTTIME );
+#endif
+ EXPP_ADDCONST( AKEY );
+ EXPP_ADDCONST( BKEY );
+ EXPP_ADDCONST( CKEY );
+ EXPP_ADDCONST( DKEY );
+ EXPP_ADDCONST( EKEY );
+ EXPP_ADDCONST( FKEY );
+ EXPP_ADDCONST( GKEY );
+ EXPP_ADDCONST( HKEY );
+ EXPP_ADDCONST( IKEY );
+ EXPP_ADDCONST( JKEY );
+ EXPP_ADDCONST( KKEY );
+ EXPP_ADDCONST( LKEY );
+ EXPP_ADDCONST( MKEY );
+ EXPP_ADDCONST( NKEY );
+ EXPP_ADDCONST( OKEY );
+ EXPP_ADDCONST( PKEY );
+ EXPP_ADDCONST( QKEY );
+ EXPP_ADDCONST( RKEY );
+ EXPP_ADDCONST( SKEY );
+ EXPP_ADDCONST( TKEY );
+ EXPP_ADDCONST( UKEY );
+ EXPP_ADDCONST( VKEY );
+ EXPP_ADDCONST( WKEY );
+ EXPP_ADDCONST( XKEY );
+ EXPP_ADDCONST( YKEY );
+ EXPP_ADDCONST( ZKEY );
+ EXPP_ADDCONST( ZEROKEY );
+ EXPP_ADDCONST( ONEKEY );
+ EXPP_ADDCONST( TWOKEY );
+ EXPP_ADDCONST( THREEKEY );
+ EXPP_ADDCONST( FOURKEY );
+ EXPP_ADDCONST( FIVEKEY );
+ EXPP_ADDCONST( SIXKEY );
+ EXPP_ADDCONST( SEVENKEY );
+ EXPP_ADDCONST( EIGHTKEY );
+ EXPP_ADDCONST( NINEKEY );
+ EXPP_ADDCONST( CAPSLOCKKEY );
+ EXPP_ADDCONST( LEFTCTRLKEY );
+ EXPP_ADDCONST( LEFTALTKEY );
+ EXPP_ADDCONST( RIGHTALTKEY );
+ EXPP_ADDCONST( RIGHTCTRLKEY );
+ EXPP_ADDCONST( RIGHTSHIFTKEY );
+ EXPP_ADDCONST( LEFTSHIFTKEY );
+ EXPP_ADDCONST( ESCKEY );
+ EXPP_ADDCONST( TABKEY );
+ EXPP_ADDCONST( RETKEY );
+ EXPP_ADDCONST( SPACEKEY );
+ EXPP_ADDCONST( LINEFEEDKEY );
+ EXPP_ADDCONST( BACKSPACEKEY );
+ EXPP_ADDCONST( DELKEY );
+ EXPP_ADDCONST( SEMICOLONKEY );
+ EXPP_ADDCONST( PERIODKEY );
+ EXPP_ADDCONST( COMMAKEY );
+ EXPP_ADDCONST( QUOTEKEY );
+ EXPP_ADDCONST( ACCENTGRAVEKEY );
+ EXPP_ADDCONST( MINUSKEY );
+ EXPP_ADDCONST( SLASHKEY );
+ EXPP_ADDCONST( BACKSLASHKEY );
+ EXPP_ADDCONST( EQUALKEY );
+ EXPP_ADDCONST( LEFTBRACKETKEY );
+ EXPP_ADDCONST( RIGHTBRACKETKEY );
+ EXPP_ADDCONST( LEFTARROWKEY );
+ EXPP_ADDCONST( DOWNARROWKEY );
+ EXPP_ADDCONST( RIGHTARROWKEY );
+ EXPP_ADDCONST( UPARROWKEY );
+ EXPP_ADDCONST( PAD2 );
+ EXPP_ADDCONST( PAD4 );
+ EXPP_ADDCONST( PAD6 );
+ EXPP_ADDCONST( PAD8 );
+ EXPP_ADDCONST( PAD1 );
+ EXPP_ADDCONST( PAD3 );
+ EXPP_ADDCONST( PAD5 );
+ EXPP_ADDCONST( PAD7 );
+ EXPP_ADDCONST( PAD9 );
+ EXPP_ADDCONST( PADPERIOD );
+ EXPP_ADDCONST( PADSLASHKEY );
+ EXPP_ADDCONST( PADASTERKEY );
+ EXPP_ADDCONST( PAD0 );
+ EXPP_ADDCONST( PADMINUS );
+ EXPP_ADDCONST( PADENTER );
+ EXPP_ADDCONST( PADPLUSKEY );
+ EXPP_ADDCONST( F1KEY );
+ EXPP_ADDCONST( F2KEY );
+ EXPP_ADDCONST( F3KEY );
+ EXPP_ADDCONST( F4KEY );
+ EXPP_ADDCONST( F5KEY );
+ EXPP_ADDCONST( F6KEY );
+ EXPP_ADDCONST( F7KEY );
+ EXPP_ADDCONST( F8KEY );
+ EXPP_ADDCONST( F9KEY );
+ EXPP_ADDCONST( F10KEY );
+ EXPP_ADDCONST( F11KEY );
+ EXPP_ADDCONST( F12KEY );
+ EXPP_ADDCONST( PAUSEKEY );
+ EXPP_ADDCONST( INSERTKEY );
+ EXPP_ADDCONST( HOMEKEY );
+ EXPP_ADDCONST( PAGEUPKEY );
+ EXPP_ADDCONST( PAGEDOWNKEY );
+ EXPP_ADDCONST( ENDKEY );
+
+ return submodule;
+}
diff --git a/source/blender/python/api2_2x/Draw.h b/source/blender/python/api2_2x/Draw.h
new file mode 100644
index 00000000000..12712713d1d
--- /dev/null
+++ b/source/blender/python/api2_2x/Draw.h
@@ -0,0 +1,77 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+/* The code in Draw.[ch] and BGL.[ch] comes from opy_draw.c in the old
+ * bpython/intern dir, with minor modifications to suit the current
+ * implementation. Important original comments are marked with an @ symbol. */
+
+#ifndef EXPP_DRAW_H_
+#define EXPP_DRAW_H_
+
+#include <Python.h>
+#include "DNA_space_types.h"
+#include "DNA_text_types.h"
+
+void initDraw( void );
+
+/*
+ * Button Object stuct
+ */
+
+typedef struct _Button {
+ PyObject_VAR_HEAD /* required Py Macro */
+ int type; /*@ 1 == int, 2 == float, 3 == string */
+ unsigned int slen; /*@ length of string (if type == 3) */
+ union {
+ int asint;
+ float asfloat;
+ char *asstr;
+ float asvec[3];
+ } val;
+ char tooltip[256];
+} Button;
+
+#define BPY_MAX_TOOLTIP 255
+
+#define BINT_TYPE 1
+#define BFLOAT_TYPE 2
+#define BSTRING_TYPE 3
+#define BVECTOR_TYPE 4
+
+/*
+ * these are declared in ../BPY_extern.h
+*/
+
+PyObject *M_Draw_Init( void );
+PyObject *Draw_Init( void );
+
+#endif /* EXPP_DRAW_H */
diff --git a/source/blender/python/api2_2x/EXPP_interface.c b/source/blender/python/api2_2x/EXPP_interface.c
new file mode 100644
index 00000000000..ee8b04ebde9
--- /dev/null
+++ b/source/blender/python/api2_2x/EXPP_interface.c
@@ -0,0 +1,230 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Michel Selten
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#include <Python.h>
+
+#include "EXPP_interface.h"
+#include "BLI_blenlib.h"
+#include "MEM_guardedalloc.h"
+#include "BLI_linklist.h" /* linked list: LinkNode struct and functions */
+#include "DNA_object_types.h"
+#include "DNA_space_types.h" /* for FILE_MAXDIR, FILE_MAXFILE */
+#include "Blender.h"
+
+extern char bprogname[]; /* argv[0] from creator.c */
+
+/* this makes sure BLI_gethome() returns a path with '.blender' appended
+ * Besides, this function now either returns userhome/.blender (if it exists)
+ * or blenderInstallDir/.blender/ otherwise (can also be cvs dir).
+ * If append_scriptsdir is non NULL, "scripts/" is appended to the dir, to
+ * get the path to the scripts folder ("release/scripts/" if cvs dir).
+ * Finally, if all else fails BLI_gethome() is returned
+ * (or NULL if append_scriptdir != 0).
+*/
+char *bpy_gethome(int append_scriptsdir)
+{
+ static char homedir[FILE_MAXDIR];
+ static char scriptsdir[FILE_MAXDIR];
+ char tmpdir[FILE_MAXDIR];
+ char bprogdir[FILE_MAXDIR];
+ char *s;
+ int i;
+
+ if (append_scriptsdir) {
+ if (scriptsdir[0] != '\0')
+ return scriptsdir;
+ }
+ else if (homedir[0] != '\0')
+ return homedir;
+
+ /* BLI_gethome() can return NULL if env vars are not set */
+ s = BLI_gethome();
+
+ if( !s ) /* bail if no $HOME */
+ {
+ printf("$HOME is NOT set\n");
+ return NULL;
+ }
+
+ if( strstr( s, ".blender" ) )
+ PyOS_snprintf( homedir, FILE_MAXDIR, s );
+ else
+ BLI_make_file_string( "/", homedir, s, ".blender" );
+
+ /* if userhome/.blender/ exists, return it */
+ if( BLI_exists( homedir ) ) {
+ if (append_scriptsdir) {
+ BLI_make_file_string("/", scriptsdir, homedir, "scripts");
+ if (BLI_exists (scriptsdir)) return scriptsdir;
+ }
+ else return homedir;
+ }
+ else homedir[0] = '\0';
+
+ /* if either:
+ * no homedir was found or
+ * append_scriptsdir = 1 but there's no scripts/ inside homedir,
+ * use argv[0] (bprogname) to get .blender/ in
+ * Blender's installation dir */
+ s = BLI_last_slash( bprogname );
+
+ i = s - bprogname + 1;
+
+ PyOS_snprintf( bprogdir, i, "%s", bprogname );
+
+ /* using tmpdir to preserve homedir (if) found above:
+ * the ideal is to have a home dir with scripts dir inside
+ * it, but if that isn't available, it's possible to
+ * have a 'broken' home dir somewhere and a scripts dir in the
+ * cvs sources */
+ BLI_make_file_string( "/", tmpdir, bprogdir, ".blender" );
+
+ if (BLI_exists(tmpdir)) {
+ if (append_scriptsdir) {
+ BLI_make_file_string("/", scriptsdir, tmpdir, "scripts");
+ if (BLI_exists(scriptsdir)) {
+ PyOS_snprintf(homedir, FILE_MAXDIR, "%s", tmpdir);
+ return scriptsdir;
+ }
+ else {
+ homedir[0] = '\0';
+ scriptsdir[0] = '\0';
+ }
+ }
+ else return homedir;
+ }
+
+ /* last try for scripts dir: blender in cvs dir, scripts/ inside release/: */
+ if (append_scriptsdir) {
+ BLI_make_file_string("/", scriptsdir, bprogdir, "release/scripts");
+ if (BLI_exists(scriptsdir)) return scriptsdir;
+ else scriptsdir[0] = '\0';
+ }
+
+ return NULL;
+}
+
+/* PyDrivers */
+
+/*
+ * Pydrivers are Blender Ipo Drivers defined by Python expressions.
+ * We need to tell DAG about objects used in these expressions, so we
+ * eval each expression to collect the ob refs. in it.
+ */
+
+/* these are checked for example in Object.c: M_Object_Get (Object.Get())
+ * to collect the refs. */
+static int pydriver_running = 0;
+
+int bpy_during_pydriver(void)
+{
+ return pydriver_running;
+}
+
+void bpy_pydriver_running(int state)
+{
+ pydriver_running = state;
+}
+
+/* Obj references are collected in this extern linked list: */
+LinkNode *bpy_pydriver_oblist = NULL;
+
+void bpy_pydriver_freeList(void)
+{
+ BLI_linklist_free(bpy_pydriver_oblist, NULL);
+ bpy_pydriver_oblist = NULL;
+}
+
+void bpy_pydriver_appendToList(struct Object *ob)
+{
+ LinkNode *ln = bpy_pydriver_oblist;
+
+ /* check that the expression is not referencing its owner object */
+
+/* XXX COMMENTED OUT TO TEST IF WE REALLY NEED TO IMPOSE THIS RESTRICTION
+ if (ln && ln->link) {
+ if (ob == (Object *)ln->link) {
+ PyErr_SetString(PyExc_AttributeError,
+ "Python driver expression can't reference its own object");
+ return;
+ }
+ else
+ ln = ln->next;
+ }
+*/
+ while (ln) { /* is ob already in list? ... */
+ if (ob == (Object *)ln->link)
+ break;
+ ln = ln->next;
+ }
+
+ if (!ln) /* ... not yet, append it */
+ BLI_linklist_append(&bpy_pydriver_oblist, (void *)ob);
+
+ return;
+}
+
+/* Get an array from our linked list of objs referenced in the
+ * current pydriver. The first node in the list is discarded,
+ * since it is the actual pydriver owner, which shouldn't be
+ * passed to the depsgraph (no self references). */
+struct Object **bpy_pydriver_obArrayFromList(void)
+{
+ Object **obarray = NULL;
+
+ if (bpy_pydriver_oblist) {
+ int i;
+ short len = BLI_linklist_length(bpy_pydriver_oblist);
+
+ if (len > 1) {
+
+ obarray = (Object **)MEM_mallocN(sizeof(Object*)*len,
+ "pydriver array");
+
+ if (obarray) {
+ LinkNode *ln = bpy_pydriver_oblist;
+ ln = ln->next; /* skip first ob, which is the pydriver owner */
+
+ for (i = 0; i < len-1; i++) {
+ obarray[i] = (Object *)ln->link;
+ ln = ln->next;
+ }
+
+ obarray[len-1] = NULL; /* NULL-terminated array */
+ }
+ }
+ bpy_pydriver_freeList();
+ }
+
+ return obarray;
+}
+
diff --git a/source/blender/python/api2_2x/EXPP_interface.h b/source/blender/python/api2_2x/EXPP_interface.h
new file mode 100644
index 00000000000..80767af1c01
--- /dev/null
+++ b/source/blender/python/api2_2x/EXPP_interface.h
@@ -0,0 +1,56 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Michel Selten, Willian P. Germano
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_INTERFACE_H
+#define EXPP_INTERFACE_H
+
+struct Object;
+struct Script;
+struct LinkNode;
+
+extern struct LinkNode *bpy_pydriver_oblist;
+
+void initBlenderApi2_2x( void );
+char *bpy_gethome( int append_scriptsdir );
+void discardFromBDict( char *key );
+void EXPP_Library_Close( void ); /* in Library.c, used by BPY_end_python */
+
+/* PyDrivers */
+
+void bpy_pydriver_freeList(void);
+void bpy_pydriver_appendToList(struct Object *ob);
+struct Object **bpy_pydriver_obArrayFromList(void);
+
+int bpy_during_pydriver(void);
+void bpy_pydriver_running(int state);
+
+#endif /* EXPP_INTERFACE_H */
diff --git a/source/blender/python/api2_2x/Effect.c b/source/blender/python/api2_2x/Effect.c
new file mode 100644
index 00000000000..ce6b553da0d
--- /dev/null
+++ b/source/blender/python/api2_2x/Effect.c
@@ -0,0 +1,1575 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Jacques Guignot, Jean-Michel Soler, Ken Hughes
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#include "Effect.h" /*This must come first */
+
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h" /* for G.scene->r.cfra */
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_effect.h"
+#include "BKE_object.h"
+#include "BKE_deform.h"
+#include "BKE_scene.h" /* for G.scene->r.cfra */
+#include "BKE_ipo.h" /* frame_to_float() */
+#include "BLI_blenlib.h"
+#include "gen_utils.h"
+#include "blendef.h"
+#include "vector.h"
+#include "MTC_matrixops.h"
+
+#define EXPP_EFFECT_STA_MIN -250.0f
+#define EXPP_EFFECT_END_MIN 1.0f
+#define EXPP_EFFECT_LIFETIME_MIN 1.0f
+#define EXPP_EFFECT_NORMFAC_MIN -2.0f
+#define EXPP_EFFECT_NORMFAC_MAX 2.0f
+#define EXPP_EFFECT_OBFAC_MIN -1.0f
+#define EXPP_EFFECT_OBFAC_MAX 1.0f
+#define EXPP_EFFECT_RANDFAC_MIN 0.0f
+#define EXPP_EFFECT_RANDFAC_MAX 2.0f
+#define EXPP_EFFECT_TEXFAC_MIN 0.0f
+#define EXPP_EFFECT_TEXFAC_MAX 2.0f
+#define EXPP_EFFECT_RANDLIFE_MIN 0.0f
+#define EXPP_EFFECT_RANDLIFE_MAX 2.0f
+#define EXPP_EFFECT_NABLA_MIN 0.0001f
+#define EXPP_EFFECT_NABLA_MAX 1.0f
+#define EXPP_EFFECT_VECTSIZE_MIN 0.0f
+#define EXPP_EFFECT_VECTSIZE_MAX 1.0f
+#define EXPP_EFFECT_TOTPART_MIN 1.0f
+#define EXPP_EFFECT_TOTPART_MAX 100000.0f
+#define EXPP_EFFECT_FORCE_MIN -1.0f
+#define EXPP_EFFECT_FORCE_MAX 1.0f
+#define EXPP_EFFECT_MULT_MIN 0.0f
+#define EXPP_EFFECT_MULT_MAX 1.0f
+#define EXPP_EFFECT_LIFE_MIN 1.0f
+#define EXPP_EFFECT_DEFVEC_MIN -1.0f
+#define EXPP_EFFECT_DEFVEC_MAX 1.0f
+#define EXPP_EFFECT_DAMP_MIN 0.0f
+#define EXPP_EFFECT_DAMP_MAX 1.0f
+
+#define EXPP_EFFECT_TOTKEY_MIN 1
+#define EXPP_EFFECT_TOTKEY_MAX 100
+#define EXPP_EFFECT_SEED_MIN 0
+#define EXPP_EFFECT_SEED_MAX 255
+#define EXPP_EFFECT_CHILD_MIN 1
+#define EXPP_EFFECT_CHILD_MAX 600
+#define EXPP_EFFECT_CHILDMAT_MIN 1
+#define EXPP_EFFECT_CHILDMAT_MAX 16
+#define EXPP_EFFECT_JITTER_MIN 0
+#define EXPP_EFFECT_JITTER_MAX 200
+#define EXPP_EFFECT_DISPMAT_MIN 1
+#define EXPP_EFFECT_DISPMAT_MAX 16
+#define EXPP_EFFECT_TIMETEX_MIN 1
+#define EXPP_EFFECT_TIMETEX_MAX 10
+#define EXPP_EFFECT_SPEEDTEX_MIN 1
+#define EXPP_EFFECT_SPEEDTEX_MAX 10
+#define EXPP_EFFECT_TEXMAP_MIN 1
+#define EXPP_EFFECT_TEXMAP_MAX 3
+
+#define EXPP_EFFECT_SPEEDTYPE_INTENSITY 0
+#define EXPP_EFFECT_SPEEDTYPE_RGB 1
+#define EXPP_EFFECT_SPEEDTYPE_GRADIENT 2
+
+#define EXPP_EFFECT_STATICSTEP_MIN 1
+#define EXPP_EFFECT_STATICSTEP_MAX 100
+#define EXPP_EFFECT_DISP_MIN 0
+#define EXPP_EFFECT_DISP_MAX 100
+
+/*****************************************************************************/
+/* Python API function prototypes for the Blender module. */
+/*****************************************************************************/
+static PyObject *M_Effect_New( PyObject * self, PyObject * args );
+static PyObject *M_Effect_Get( PyObject * self, PyObject * args );
+
+/*****************************************************************************/
+/* Python BPy_Effect methods declarations: */
+/*****************************************************************************/
+static PyObject *Effect_getType( BPy_Effect * self );
+static int Effect_setType( void );
+static PyObject *Effect_getStype( BPy_Effect * self );
+static int Effect_setStype( BPy_Effect * self, PyObject * args );
+static PyObject *Effect_getFlag( BPy_Effect * self );
+static int Effect_setFlag( BPy_Effect * self, PyObject * args );
+static PyObject *Effect_getSta( BPy_Effect * self );
+static int Effect_setSta( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_getEnd( BPy_Effect * self );
+static int Effect_setEnd( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_getLifetime( BPy_Effect * self );
+static int Effect_setLifetime( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_getNormfac( BPy_Effect * self );
+static int Effect_setNormfac( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_getObfac( BPy_Effect * self );
+static int Effect_setObfac( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_getRandfac( BPy_Effect * self );
+static int Effect_setRandfac( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_getTexfac( BPy_Effect * self );
+static int Effect_setTexfac( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_getRandlife( BPy_Effect * self );
+static int Effect_setRandlife( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_getNabla( BPy_Effect * self );
+static int Effect_setNabla( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_getVectsize( BPy_Effect * self );
+static int Effect_setVectsize( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_getTotpart( BPy_Effect * self );
+static int Effect_setTotpart( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_getTotkey( BPy_Effect * self );
+static int Effect_setTotkey( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_getSeed( BPy_Effect * self );
+static int Effect_setSeed( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_getForce( BPy_Effect * self );
+static int Effect_setForce( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_getMult( BPy_Effect * self );
+static int Effect_setMult( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_getLife( BPy_Effect * self );
+static int Effect_setLife( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_getChildMat( BPy_Effect * self );
+static int Effect_setChildMat( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_getChild( BPy_Effect * self );
+static int Effect_setChild( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_getDefvec( BPy_Effect * self );
+static int Effect_setDefvec( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_getJitter( BPy_Effect * self );
+static int Effect_setJitter( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_getDispMat( BPy_Effect * self );
+static int Effect_setDispMat( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_getEmissionTex( BPy_Effect * self );
+static int Effect_setEmissionTex( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_getForceTex( BPy_Effect * self );
+static int Effect_setForceTex( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_getDamping( BPy_Effect * self );
+static int Effect_setDamping( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_getSpeedType( BPy_Effect * self );
+static int Effect_setSpeedType( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_getVertGroup( BPy_Effect * self );
+static int Effect_setVertGroup( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_getSpeedVertGroup( BPy_Effect * self );
+static int Effect_setSpeedVertGroup( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_getStaticStep( BPy_Effect * self );
+static int Effect_setStaticStep( BPy_Effect * self , PyObject * a);
+static PyObject *Effect_getDisp( BPy_Effect * self );
+static int Effect_setDisp( BPy_Effect * self , PyObject * a);
+static PyObject *Effect_getParticlesLoc( BPy_Effect * self );
+
+static PyObject *Effect_oldsetType( void );
+static PyObject *Effect_oldsetStype( BPy_Effect * self, PyObject * args );
+static PyObject *Effect_oldsetFlag( BPy_Effect * self, PyObject * args );
+static PyObject *Effect_oldsetSta( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_oldsetEnd( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_oldsetLifetime( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_oldsetNormfac( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_oldsetObfac( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_oldsetRandfac( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_oldsetTexfac( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_oldsetRandlife( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_oldsetNabla( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_oldsetVectsize( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_oldsetTotpart( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_oldsetTotkey( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_oldsetSeed( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_oldsetForce( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_oldsetMult( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_oldsetLife( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_oldsetMat( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_oldsetChild( BPy_Effect * self, PyObject * a );
+static PyObject *Effect_oldsetDefvec( BPy_Effect * self, PyObject * a );
+
+/*****************************************************************************/
+/* Python Effect_Type callback function prototypes: */
+/*****************************************************************************/
+static PyObject *Effect_repr( void );
+
+/*****************************************************************************/
+/* The following string definitions are used for documentation strings. */
+/* In Python these will be written to the console when doing a */
+/* Blender.Particle.__doc__ */
+/*****************************************************************************/
+static char M_Particle_doc[] = "The Blender Effect module\n\n\
+This module provides access to **Object Data** in Blender.\n\
+Functions :\n\
+ New(name) : creates a new part object and adds it to the given mesh object \n\
+ Get(name) : retreives a particle with the given name (mandatory)\n\
+ get(name) : same as Get. Kept for compatibility reasons.\n";
+static char M_Effect_New_doc[] = "New(name) : creates a new part object and adds it to the given mesh object\n";
+static char M_Effect_Get_doc[] = "xxx";
+
+/*****************************************************************************/
+/* Python method structure definition for Blender.Particle module: */
+/*****************************************************************************/
+static struct PyMethodDef M_Particle_methods[] = {
+ {"New", ( PyCFunction ) M_Effect_New, METH_VARARGS, M_Effect_New_doc},
+ {"Get", M_Effect_Get, METH_VARARGS, M_Effect_Get_doc},
+ {"get", M_Effect_Get, METH_VARARGS, M_Effect_Get_doc},
+ {NULL, NULL, 0, NULL}
+};
+
+/*****************************************************************************/
+/* Python BPy_Effect methods table: */
+/*****************************************************************************/
+static PyMethodDef BPy_Effect_methods[] = {
+ {"getType", ( PyCFunction ) Effect_getType,
+ METH_NOARGS, "() - Return Effect type"},
+ {"setType", ( PyCFunction ) Effect_oldsetType,
+ METH_VARARGS, "() - Set Effect type"},
+ {"getStype", ( PyCFunction ) Effect_getStype,
+ METH_NOARGS, "() - Return Effect stype"},
+ {"setStype", ( PyCFunction ) Effect_oldsetStype,
+ METH_VARARGS, "() - Set Effect stype"},
+ {"getFlag", ( PyCFunction ) Effect_getFlag,
+ METH_NOARGS, "() - Return Effect flag"},
+ {"setFlag", ( PyCFunction ) Effect_oldsetFlag,
+ METH_VARARGS, "() - Set Effect flag"},
+ {"getStartTime", ( PyCFunction ) Effect_getSta,
+ METH_NOARGS, "()-Return particle start time"},
+ {"setStartTime", ( PyCFunction ) Effect_oldsetSta, METH_VARARGS,
+ "()- Sets particle start time"},
+ {"getEndTime", ( PyCFunction ) Effect_getEnd,
+ METH_NOARGS, "()-Return particle end time"},
+ {"setEndTime", ( PyCFunction ) Effect_oldsetEnd, METH_VARARGS,
+ "()- Sets particle end time"},
+ {"getLifetime", ( PyCFunction ) Effect_getLifetime,
+ METH_NOARGS, "()-Return particle life time"},
+ {"setLifetime", ( PyCFunction ) Effect_oldsetLifetime, METH_VARARGS,
+ "()- Sets particle life time "},
+ {"getNormfac", ( PyCFunction ) Effect_getNormfac,
+ METH_NOARGS, "()-Return particle life time"},
+ {"setNormfac", ( PyCFunction ) Effect_oldsetNormfac, METH_VARARGS,
+ "()- Sets particle life time "},
+ {"getObfac", ( PyCFunction ) Effect_getObfac,
+ METH_NOARGS, "()-Return particle life time"},
+ {"setObfac", ( PyCFunction ) Effect_oldsetObfac, METH_VARARGS,
+ "()- Sets particle life time "},
+ {"getRandfac", ( PyCFunction ) Effect_getRandfac,
+ METH_NOARGS, "()-Return particle life time"},
+ {"setRandfac", ( PyCFunction ) Effect_oldsetRandfac, METH_VARARGS,
+ "()- Sets particle life time "},
+ {"getTexfac", ( PyCFunction ) Effect_getTexfac,
+ METH_NOARGS, "()-Return particle life time"},
+ {"setTexfac", ( PyCFunction ) Effect_oldsetTexfac, METH_VARARGS,
+ "()- Sets particle life time "},
+ {"getRandlife", ( PyCFunction ) Effect_getRandlife,
+ METH_NOARGS, "()-Return particle life time"},
+ {"setRandlife", ( PyCFunction ) Effect_oldsetRandlife, METH_VARARGS,
+ "()- Sets particle life time "},
+ {"getNabla", ( PyCFunction ) Effect_getNabla,
+ METH_NOARGS, "()-Return particle life time"},
+ {"setNabla", ( PyCFunction ) Effect_oldsetNabla, METH_VARARGS,
+ "()- Sets particle life time "},
+ {"getVectsize", ( PyCFunction ) Effect_getVectsize,
+ METH_NOARGS, "()-Return particle life time"},
+ {"setVectsize", ( PyCFunction ) Effect_oldsetVectsize, METH_VARARGS,
+ "()- Sets particle life time "},
+ {"getTotpart", ( PyCFunction ) Effect_getTotpart,
+ METH_NOARGS, "()-Return particle life time"},
+ {"setTotpart", ( PyCFunction ) Effect_oldsetTotpart, METH_VARARGS,
+ "()- Sets particle life time "},
+ {"getTotkey", ( PyCFunction ) Effect_getTotkey,
+ METH_NOARGS, "()-Return the number of key positions."},
+ {"setTotkey", ( PyCFunction ) Effect_oldsetTotkey, METH_VARARGS,
+ "()-Set the number of key positions. "},
+ {"getSeed", ( PyCFunction ) Effect_getSeed,
+ METH_NOARGS, "()-Return particle life time"},
+ {"setSeed", ( PyCFunction ) Effect_oldsetSeed, METH_VARARGS,
+ "()- Sets particle life time "},
+ {"getForce", ( PyCFunction ) Effect_getForce,
+ METH_NOARGS, "()-Return particle life time"},
+ {"setForce", ( PyCFunction ) Effect_oldsetForce, METH_VARARGS,
+ "()- Sets particle life time "},
+ {"getMult", ( PyCFunction ) Effect_getMult,
+ METH_NOARGS, "()-Return particle life time"},
+ {"setMult", ( PyCFunction ) Effect_oldsetMult, METH_VARARGS,
+ "()- Sets particle life time "},
+ {"getLife", ( PyCFunction ) Effect_getLife,
+ METH_NOARGS, "()-Return particle life time"},
+ {"setLife", ( PyCFunction ) Effect_oldsetLife, METH_VARARGS,
+ "()- Sets particle life time "},
+ {"getMat", ( PyCFunction ) Effect_getChildMat,
+ METH_NOARGS, "()-Return particle life time"},
+ {"setMat", ( PyCFunction ) Effect_oldsetMat, METH_VARARGS,
+ "()- Sets particle life time "},
+ {"getChild", ( PyCFunction ) Effect_getChild,
+ METH_NOARGS, "()-Return particle life time"},
+ {"setChild", ( PyCFunction ) Effect_oldsetChild, METH_VARARGS,
+ "()- Sets particle life time "},
+ {"getDefvec", ( PyCFunction ) Effect_getDefvec,
+ METH_NOARGS, "()-Return particle life time"},
+ {"setDefvec", ( PyCFunction ) Effect_oldsetDefvec, METH_VARARGS,
+ "()- Sets particle life time "},
+ {"getParticlesLoc", ( PyCFunction ) Effect_getParticlesLoc, METH_NOARGS,
+ "()- Sets particle life time "},
+ {NULL, NULL, 0, NULL}
+};
+
+/*****************************************************************************/
+/* Python BPy_Effect attributes get/set structure: */
+/*****************************************************************************/
+static PyGetSetDef BPy_Effect_getseters[] = {
+ {"flag",
+ (getter)Effect_getFlag, (setter)Effect_setFlag,
+ "The particle flag bitfield",
+ NULL},
+ {"stype",
+ (getter)Effect_getStype, (setter)Effect_setStype,
+ "The particle stype bitfield",
+ NULL},
+ {"disp",
+ (getter)Effect_getDisp, (setter)Effect_setDisp,
+ "The particle display value",
+ NULL},
+ {"staticStep",
+ (getter)Effect_getStaticStep, (setter)Effect_setStaticStep,
+ "The particle static step value",
+ NULL},
+ {"type",
+ (getter)Effect_getType, (setter)Effect_setType,
+ "The effect's type (deprecated)",
+ NULL},
+ {"child",
+ (getter)Effect_getChild, (setter)Effect_setChild,
+ "The number of children of a particle that multiply itself",
+ NULL},
+ {"childMat",
+ (getter)Effect_getChildMat, (setter)Effect_setChildMat,
+ "Specify the material used for the particles",
+ NULL},
+ {"damping",
+ (getter)Effect_getDamping, (setter)Effect_setDamping,
+ "The damping factor",
+ NULL},
+ {"defvec",
+ (getter)Effect_getDefvec, (setter)Effect_setDefvec,
+ "The axes of a force, determined by the texture",
+ NULL},
+ {"dispMat",
+ (getter)Effect_getDispMat, (setter)Effect_setDispMat,
+ "The material used for the particles",
+ NULL},
+ {"emissionTex",
+ (getter)Effect_getEmissionTex, (setter)Effect_setEmissionTex,
+ "The texture used for texture emission",
+ NULL},
+ {"end",
+ (getter)Effect_getEnd, (setter)Effect_setEnd,
+ "The endframe for the effect",
+ NULL},
+ {"force",
+ (getter)Effect_getForce, (setter)Effect_setForce,
+ "The axes of a continues force",
+ NULL},
+ {"forceTex",
+ (getter)Effect_getForceTex, (setter)Effect_setForceTex,
+ "The texture used for force",
+ NULL},
+ {"jitter",
+ (getter)Effect_getJitter, (setter)Effect_setJitter,
+ "Jitter table distribution: maximum particles per face",
+ NULL},
+ {"life",
+ (getter)Effect_getLife, (setter)Effect_setLife,
+ "The life span of the next generation of particles",
+ NULL},
+ {"lifetime",
+ (getter)Effect_getLifetime, (setter)Effect_setLifetime,
+ "The life span of the particles",
+ NULL},
+ {"mult",
+ (getter)Effect_getMult, (setter)Effect_setMult,
+ "The probabilities that a \"dying\" particle spawns a new one",
+ NULL},
+ {"nabla",
+ (getter)Effect_getNabla, (setter)Effect_setNabla,
+ "The dimension of the area for gradient calculation",
+ NULL},
+ {"normfac",
+ (getter)Effect_getNormfac, (setter)Effect_setNormfac,
+ "Particle's starting speed (from the mesh)",
+ NULL},
+ {"obfac",
+ (getter)Effect_getObfac, (setter)Effect_setObfac,
+ "Particle's starting speed (from the object)",
+ NULL},
+ {"randfac",
+ (getter)Effect_getRandfac, (setter)Effect_setRandfac,
+ "The random variation for the starting speed",
+ NULL},
+ {"randlife",
+ (getter)Effect_getRandlife, (setter)Effect_setRandlife,
+ "The random variation for a particle's life",
+ NULL},
+ {"seed",
+ (getter)Effect_getSeed, (setter)Effect_setSeed,
+ "The seed for random variations",
+ NULL},
+ {"speedType",
+ (getter)Effect_getSpeedType, (setter)Effect_setSpeedType,
+ "Controls which texture property affects particle speeds",
+ NULL},
+ {"speedVGroup",
+ (getter)Effect_getSpeedVertGroup, (setter)Effect_setSpeedVertGroup,
+ "Vertex group for speed control",
+ NULL},
+ {"sta",
+ (getter)Effect_getSta, (setter)Effect_setSta,
+ "The startframe for the effect",
+ NULL},
+ {"texfac",
+ (getter)Effect_getTexfac, (setter)Effect_setTexfac,
+ "Particle's starting speed (from the texture)",
+ NULL},
+ {"totpart",
+ (getter)Effect_getTotpart, (setter)Effect_setTotpart,
+ "The total number of particles",
+ NULL},
+ {"totkey",
+ (getter)Effect_getTotkey, (setter)Effect_setTotkey,
+ "The total number of key positions",
+ NULL},
+ {"vectsize",
+ (getter)Effect_getVectsize, (setter)Effect_setVectsize,
+ "The speed for particle's rotation direction",
+ NULL},
+ {"vGroup",
+ (getter)Effect_getVertGroup, (setter)Effect_setVertGroup,
+ "Vertex group for emitted particles",
+ NULL},
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+/*****************************************************************************/
+/* Python Effect_Type structure definition: */
+/*****************************************************************************/
+PyTypeObject Effect_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender Effect", /* char *tp_name; */
+ sizeof( BPy_Effect ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ NULL, /* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* cmpfunc tp_compare; */
+ ( reprfunc ) Effect_repr, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_Effect_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ BPy_Effect_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+/*****************************************************************************/
+/* Python method structure definition for Blender.Effect module: */
+/*****************************************************************************/
+
+struct PyMethodDef M_Effect_methods[] = {
+ {"New", ( PyCFunction ) M_Effect_New, METH_VARARGS, NULL},
+ {"Get", M_Effect_Get, METH_VARARGS, NULL},
+ {"get", M_Effect_Get, METH_VARARGS, NULL},
+ {NULL, NULL, 0, NULL}
+};
+
+/*****************************************************************************/
+/* Function: M_Effect_New */
+/* Python equivalent: Blender.Effect.New */
+/*****************************************************************************/
+PyObject *M_Effect_New( PyObject * self, PyObject * args )
+{
+ Effect *bleffect = 0;
+ Object *ob;
+ char *name = NULL;
+
+ if( !PyArg_ParseTuple( args, "s", &name ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument" );
+
+ for( ob = G.main->object.first; ob; ob = ob->id.next )
+ if( !strcmp( name, ob->id.name + 2 ) )
+ break;
+
+ if( !ob )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "object does not exist" );
+
+ if( ob->type != OB_MESH )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "object is not a mesh" );
+
+ bleffect = add_effect( EFF_PARTICLE );
+ if( !bleffect )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't create Effect Data in Blender" );
+
+ BLI_addtail( &ob->effect, bleffect );
+
+ return EffectCreatePyObject( bleffect, ob );
+}
+
+/*****************************************************************************/
+/* Function: M_Effect_Get */
+/* Python equivalent: Blender.Effect.Get */
+/*****************************************************************************/
+PyObject *M_Effect_Get( PyObject * self, PyObject * args )
+{
+ /*arguments : string object name
+ int : position of effect in the obj's effect list */
+ char *name = NULL;
+ Object *object_iter;
+ Effect *eff;
+ int num = -1, i;
+
+ if( !PyArg_ParseTuple( args, "|si", &name, &num ) )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected string int argument" ) );
+
+ object_iter = G.main->object.first;
+
+ if( !object_iter )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "Scene contains no object" ) );
+
+ if( name ) { /* (name, num = -1) - try to find the given object */
+
+ while( object_iter ) {
+
+ if( !strcmp( name, object_iter->id.name + 2 ) ) {
+
+ eff = object_iter->effect.first; /*can be NULL: None will be returned*/
+
+ if (num >= 0) { /* return effect in given num position if available */
+
+ for( i = 0; i < num; i++ ) {
+ if (!eff) break;
+ eff = eff->next;
+ }
+
+ if (eff) {
+ return EffectCreatePyObject( eff, object_iter );
+ } else { /* didn't find any effect in the given position */
+ Py_RETURN_NONE;
+ }
+ }
+
+ else {/*return a list with all effects linked to the given object*/
+ /* this was pointed by Stephen Swaney */
+ PyObject *effectlist = PyList_New( 0 );
+
+ while (eff) {
+ PyObject *found_eff = EffectCreatePyObject( eff,
+ object_iter );
+ PyList_Append( effectlist, found_eff );
+ Py_DECREF( found_eff ); /* PyList_Append incref'ed it */
+ eff = eff->next;
+ }
+ return effectlist;
+ }
+ }
+
+ object_iter = object_iter->id.next;
+ }
+
+ if (!object_iter)
+ return EXPP_ReturnPyObjError (PyExc_AttributeError,
+ "no such object");
+ }
+
+ else { /* () - return a list with all effects currently in Blender */
+ PyObject *effectlist = PyList_New( 0 );
+
+ while( object_iter ) {
+ if( object_iter->effect.first != NULL ) {
+ eff = object_iter->effect.first;
+ while( eff ) {
+ PyObject *found_eff = EffectCreatePyObject( eff,
+ object_iter );
+ PyList_Append( effectlist, found_eff );
+ Py_DECREF( found_eff );
+ eff = eff->next;
+ }
+ }
+ object_iter = object_iter->id.next;
+ }
+ return effectlist;
+ }
+ Py_INCREF( Py_None );
+ return Py_None;
+}
+
+/* create the Blender.Effect.Flags constant dict */
+
+static PyObject *Effect_FlagsDict( void )
+{
+ PyObject *Flags = PyConstant_New( );
+
+ if( Flags ) {
+ BPy_constant *c = ( BPy_constant * ) Flags;
+
+ PyConstant_Insert( c, "SELECTED",
+ PyInt_FromLong( EFF_SELECT ) );
+ PyConstant_Insert( c, "BSPLINE",
+ PyInt_FromLong( PAF_BSPLINE ) );
+ PyConstant_Insert( c, "STATIC",
+ PyInt_FromLong( PAF_STATIC ) );
+ PyConstant_Insert( c, "FACES",
+ PyInt_FromLong( PAF_FACE ) );
+ PyConstant_Insert( c, "ANIMATED",
+ PyInt_FromLong( PAF_ANIMATED ) );
+ PyConstant_Insert( c, "UNBORN",
+ PyInt_FromLong( PAF_UNBORN ) );
+ PyConstant_Insert( c, "VERTS",
+ PyInt_FromLong( PAF_OFACE ) );
+ PyConstant_Insert( c, "EMESH",
+ PyInt_FromLong( PAF_SHOWE ) );
+ PyConstant_Insert( c, "TRUERAND",
+ PyInt_FromLong( PAF_TRAND ) );
+ PyConstant_Insert( c, "EVENDIST",
+ PyInt_FromLong( PAF_EDISTR ) );
+ PyConstant_Insert( c, "DIED",
+ PyInt_FromLong( PAF_DIED ) );
+ }
+ return Flags;
+}
+
+static PyObject *Effect_SpeedTypeDict( void )
+{
+ PyObject *Type = PyConstant_New( );
+
+ if( Type ) {
+ BPy_constant *c = ( BPy_constant * ) Type;
+
+ PyConstant_Insert( c, "INTENSITY",
+ PyInt_FromLong( EXPP_EFFECT_SPEEDTYPE_INTENSITY ) );
+ PyConstant_Insert( c, "RGB",
+ PyInt_FromLong( EXPP_EFFECT_SPEEDTYPE_RGB ) );
+ PyConstant_Insert( c, "GRADIENT",
+ PyInt_FromLong( EXPP_EFFECT_SPEEDTYPE_GRADIENT ) );
+ }
+ return Type;
+}
+
+/*****************************************************************************/
+/* Function: Effect_Init */
+/*****************************************************************************/
+
+PyObject *Effect_Init( void )
+{
+ PyObject *submodule, *dict;
+ PyObject *particle;
+ PyObject *Flags;
+ PyObject *Types;
+
+ if( PyType_Ready( &Effect_Type ) < 0)
+ return NULL;
+
+ Flags = Effect_FlagsDict( );
+ Types = Effect_SpeedTypeDict( );
+
+ submodule = Py_InitModule3( "Blender.Effect", M_Effect_methods, 0 );
+ if( Flags )
+ PyModule_AddObject( submodule, "Flags", Flags );
+ if( Types )
+ PyModule_AddObject( submodule, "SpeedTypes", Types );
+
+ particle = Py_InitModule3( "Blender.Particle", M_Particle_methods,
+ M_Particle_doc );
+
+ dict = PyModule_GetDict( submodule );
+
+ PyDict_SetItemString( dict, "Particle", particle );
+ return ( submodule );
+}
+
+/*****************************************************************************/
+/* Python BPy_Effect methods: */
+/*****************************************************************************/
+
+static PyObject *Effect_getType( BPy_Effect * self )
+{
+ return PyInt_FromLong( ( long ) self->effect->type );
+}
+
+/* does nothing since there is only one type of effect */
+
+static int Effect_setType( void )
+{
+ return 0;
+}
+
+static int Effect_setStype( BPy_Effect * self, PyObject * args )
+{
+ short param;
+ if( !PyArg_Parse( args, "h", &param ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected an int as argument" );
+ self->effect->stype = param;
+ return 0;
+}
+
+static PyObject *Effect_getStype( BPy_Effect * self )
+{
+ return PyInt_FromLong( (long)( self->effect->stype ) );
+}
+
+static PyObject *Effect_getFlag( BPy_Effect * self )
+{
+ return PyInt_FromLong( (long)( self->effect->flag ^ PAF_OFACE ) );
+}
+
+static int Effect_setFlag( BPy_Effect * self, PyObject * args )
+{
+ short param;
+ static short bitmask = PAF_BSPLINE | PAF_STATIC | PAF_FACE | PAF_ANIMATED |
+ PAF_UNBORN | PAF_OFACE | PAF_SHOWE | PAF_TRAND | PAF_EDISTR | PAF_DIED;
+
+ if( !PyArg_Parse( args, "h", &param ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected an int as argument" );
+
+ /* we don't allow users to change the select bit at this time */
+ param &= ~EFF_SELECT;
+
+ if ( ( param & bitmask ) != param )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "invalid bit(s) set in mask" );
+
+ /* the sense of "Verts" is inverted (clear is enabled) */
+ param ^= PAF_OFACE;
+
+ /* leave select bit alone, and add in the others */
+ self->effect->flag &= EFF_SELECT;
+ self->effect->flag |= param;
+ return 0;
+}
+
+static PyObject *Effect_getSta( BPy_Effect * self )
+{
+ return PyFloat_FromDouble( self->effect->sta );
+}
+
+static int Effect_setSta( BPy_Effect * self, PyObject * args )
+{
+ return EXPP_setFloatClamped( args, &self->effect->sta,
+ EXPP_EFFECT_STA_MIN, MAXFRAMEF );
+}
+
+static PyObject *Effect_getEnd( BPy_Effect * self )
+{
+ return PyFloat_FromDouble( ((PartEff *) self->effect)->end );
+}
+
+static int Effect_setEnd( BPy_Effect * self, PyObject * args )
+{
+ float val;
+
+ if( !PyArg_Parse( args, "f", &val ) )
+ return EXPP_ReturnIntError( PyExc_AttributeError,
+ "expected float argument" );
+
+ self->effect->end = EXPP_ClampFloat( val,
+ EXPP_EFFECT_END_MIN, MAXFRAMEF );
+ return 0;
+}
+
+static PyObject *Effect_getLifetime( BPy_Effect * self )
+{
+ return PyFloat_FromDouble( self->effect->lifetime );
+}
+
+static int Effect_setLifetime( BPy_Effect * self, PyObject * args )
+{
+ return EXPP_setFloatClamped( args, &self->effect->lifetime,
+ EXPP_EFFECT_LIFETIME_MIN, MAXFRAMEF );
+}
+
+static PyObject *Effect_getNormfac( BPy_Effect * self )
+{
+ return PyFloat_FromDouble( self->effect->normfac );
+}
+
+static int Effect_setNormfac( BPy_Effect * self, PyObject * args )
+{
+ return EXPP_setFloatClamped( args, &self->effect->normfac,
+ EXPP_EFFECT_NORMFAC_MIN, EXPP_EFFECT_NORMFAC_MAX );
+}
+
+static PyObject *Effect_getObfac( BPy_Effect * self )
+{
+ return PyFloat_FromDouble( self->effect->obfac );
+}
+
+static int Effect_setObfac( BPy_Effect * self, PyObject * args )
+{
+ return EXPP_setFloatClamped( args, &self->effect->obfac,
+ EXPP_EFFECT_OBFAC_MIN, EXPP_EFFECT_OBFAC_MAX );
+}
+
+static PyObject *Effect_getRandfac( BPy_Effect * self )
+{
+ return PyFloat_FromDouble( self->effect->randfac );
+}
+
+static int Effect_setRandfac( BPy_Effect * self, PyObject * args )
+{
+ return EXPP_setFloatClamped( args, &self->effect->randfac,
+ EXPP_EFFECT_RANDFAC_MIN, EXPP_EFFECT_RANDFAC_MAX );
+}
+
+static PyObject *Effect_getTexfac( BPy_Effect * self )
+{
+ return PyFloat_FromDouble( self->effect->texfac );
+}
+
+static int Effect_setTexfac( BPy_Effect * self, PyObject * args )
+{
+ return EXPP_setFloatClamped( args, &self->effect->texfac,
+ EXPP_EFFECT_TEXFAC_MIN, EXPP_EFFECT_TEXFAC_MAX );
+}
+
+static PyObject *Effect_getRandlife( BPy_Effect * self )
+{
+ return PyFloat_FromDouble( self->effect->randlife );
+}
+
+static int Effect_setRandlife( BPy_Effect * self, PyObject * args )
+{
+ return EXPP_setFloatClamped( args, &self->effect->randlife,
+ EXPP_EFFECT_RANDLIFE_MIN, EXPP_EFFECT_RANDLIFE_MAX );
+}
+
+static PyObject *Effect_getNabla( BPy_Effect * self )
+{
+ return PyFloat_FromDouble( self->effect->nabla );
+}
+
+static int Effect_setNabla( BPy_Effect * self, PyObject * args )
+{
+ return EXPP_setFloatClamped( args, &self->effect->nabla,
+ EXPP_EFFECT_NABLA_MIN, EXPP_EFFECT_NABLA_MAX );
+}
+
+static PyObject *Effect_getVectsize( BPy_Effect * self )
+{
+ return PyFloat_FromDouble( self->effect->vectsize );
+}
+
+static int Effect_setVectsize( BPy_Effect * self, PyObject * args )
+{
+ return EXPP_setFloatClamped( args, &self->effect->vectsize,
+ EXPP_EFFECT_VECTSIZE_MIN, EXPP_EFFECT_VECTSIZE_MAX );
+}
+
+static PyObject *Effect_getTotpart( BPy_Effect * self )
+{
+ return PyInt_FromLong( self->effect->totpart );
+}
+
+static int Effect_setTotpart( BPy_Effect * self, PyObject * args )
+{
+ return EXPP_setIValueClamped( args, &self->effect->totpart,
+ (int)EXPP_EFFECT_TOTPART_MIN, (int)EXPP_EFFECT_TOTPART_MAX, 'i' );
+}
+
+static PyObject *Effect_getTotkey( BPy_Effect * self )
+{
+ return PyInt_FromLong( self->effect->totkey );
+}
+
+static int Effect_setTotkey( BPy_Effect * self, PyObject * args )
+{
+ return EXPP_setIValueClamped( args, &self->effect->totkey,
+ EXPP_EFFECT_TOTKEY_MIN, EXPP_EFFECT_TOTKEY_MAX, 'i' );
+}
+
+static PyObject *Effect_getSeed( BPy_Effect * self )
+{
+ return PyInt_FromLong( self->effect->seed );
+}
+
+static int Effect_setSeed( BPy_Effect * self, PyObject * args )
+{
+ return EXPP_setIValueClamped( args, &self->effect->seed,
+ EXPP_EFFECT_SEED_MIN, EXPP_EFFECT_SEED_MAX, 'i' );
+}
+
+static PyObject *Effect_getForce( BPy_Effect * self )
+{
+ return Py_BuildValue( "(f,f,f)", self->effect->force[0],
+ self->effect->force[1], self->effect->force[2] );
+}
+
+static int Effect_setForce( BPy_Effect * self, PyObject * args )
+{
+ float val[3];
+ int i;
+
+ if( PyTuple_Check( args ) && PyTuple_Size( args ) == 1 )
+ args = PyTuple_GetItem( args, 0 );
+
+ if( !PyArg_ParseTuple( args, "fff", &val[0], &val[1], &val[2] ) )
+ return EXPP_ReturnIntError( PyExc_AttributeError,
+ "expected a tuple of three float arguments" );
+ for( i = 0; i < 3; ++i )
+ self->effect->force[i] = EXPP_ClampFloat( val[i],
+ EXPP_EFFECT_FORCE_MIN, EXPP_EFFECT_FORCE_MAX );
+ return 0;
+}
+
+static PyObject *Effect_getMult( BPy_Effect * self )
+{
+ return Py_BuildValue( "(f,f,f,f)", self->effect->mult[0],
+ self->effect->mult[1], self->effect->mult[2],
+ self->effect->mult[3] );
+}
+
+static int Effect_setMult( BPy_Effect * self, PyObject * args )
+{
+ float val[4];
+ int i;
+
+ if( PyTuple_Check( args ) && PyTuple_Size( args ) == 1 )
+ args = PyTuple_GetItem( args, 0 );
+
+ if( !PyArg_ParseTuple( args, "ffff", &val[0], &val[1], &val[2], &val[3] ) )
+ return EXPP_ReturnIntError( PyExc_AttributeError,
+ "expected a tuple of four float arguments" );
+ for( i = 0; i < 4; ++i )
+ self->effect->mult[i] = EXPP_ClampFloat( val[i],
+ EXPP_EFFECT_MULT_MIN, EXPP_EFFECT_MULT_MAX );
+ return 0;
+}
+
+static PyObject *Effect_getLife( BPy_Effect * self )
+{
+ return Py_BuildValue( "(f,f,f,f)", self->effect->life[0],
+ self->effect->life[1], self->effect->life[2],
+ self->effect->life[3] );
+}
+
+static int Effect_setLife( BPy_Effect * self, PyObject * args )
+{
+ float val[4];
+ int i;
+
+ if( PyTuple_Check( args ) && PyTuple_Size( args ) == 1 )
+ args = PyTuple_GetItem( args, 0 );
+
+ if( !PyArg_ParseTuple( args, "ffff", &val[0], &val[1], &val[2], &val[3] ) )
+ return EXPP_ReturnIntError( PyExc_AttributeError,
+ "expected a tuple of four float arguments" );
+ for( i = 0; i < 4; ++i )
+ self->effect->life[i] = EXPP_ClampFloat( val[i],
+ EXPP_EFFECT_LIFE_MIN, MAXFRAMEF );
+ return 0;
+}
+
+static PyObject *Effect_getChild( BPy_Effect * self )
+{
+ return Py_BuildValue( "(h,h,h,h)", self->effect->child[0],
+ self->effect->child[1], self->effect->child[2],
+ self->effect->child[3] );
+}
+
+
+static int Effect_setChild( BPy_Effect * self, PyObject * args )
+{
+ short val[4];
+ int i;
+
+ if( PyTuple_Check( args ) && PyTuple_Size( args ) == 1 )
+ args = PyTuple_GetItem( args, 0 );
+
+ if( !PyArg_ParseTuple( args, "hhhh", &val[0], &val[1], &val[2], &val[3] ) )
+ return EXPP_ReturnIntError( PyExc_AttributeError,
+ "expected a tuple of four int argument" );
+ for( i = 0; i < 4; ++i )
+ self->effect->child[i] = (short)EXPP_ClampInt( val[i],
+ EXPP_EFFECT_CHILD_MIN, EXPP_EFFECT_CHILD_MAX );
+ return 0;
+}
+
+static PyObject *Effect_getChildMat( BPy_Effect * self )
+{
+ return Py_BuildValue( "(h,h,h,h)", self->effect->mat[0],
+ self->effect->mat[1], self->effect->mat[2],
+ self->effect->mat[3] );
+}
+
+static int Effect_setChildMat( BPy_Effect * self, PyObject * args )
+{
+ short val[4];
+ int i;
+
+ if( PyTuple_Check( args ) && PyTuple_Size( args ) == 1 )
+ args = PyTuple_GetItem( args, 0 );
+
+ if( !PyArg_ParseTuple( args, "hhhh", &val[0], &val[1], &val[2], &val[3] ) )
+ return EXPP_ReturnIntError( PyExc_AttributeError,
+ "expected a tuple of four int argument" );
+ for( i = 0; i < 4; ++i )
+ self->effect->mat[i] = (short)EXPP_ClampInt( val[i],
+ EXPP_EFFECT_CHILDMAT_MIN, EXPP_EFFECT_CHILDMAT_MAX );
+ return 0;
+}
+
+static PyObject *Effect_getDefvec( BPy_Effect * self )
+{
+ return Py_BuildValue( "(f,f,f)", self->effect->defvec[0],
+ self->effect->defvec[1], self->effect->defvec[2] );
+}
+
+static int Effect_setDefvec( BPy_Effect * self, PyObject * args )
+{
+ float val[3];
+ int i;
+
+ if( PyTuple_Check( args ) && PyTuple_Size( args ) == 1 )
+ args = PyTuple_GetItem( args, 0 );
+
+ if( !PyArg_ParseTuple( args, "fff", &val[0], &val[1], &val[2] ) )
+ return EXPP_ReturnIntError( PyExc_AttributeError,
+ "expected a tuple of three float arguments" );
+
+ for( i = 0; i < 3; ++i )
+ self->effect->defvec[i] = EXPP_ClampFloat( val[i],
+ EXPP_EFFECT_DEFVEC_MIN, EXPP_EFFECT_DEFVEC_MAX );
+ return 0;
+}
+
+static PyObject *Effect_getJitter( BPy_Effect * self )
+{
+ return PyInt_FromLong( ( long )self->effect->userjit );
+}
+
+static int Effect_setJitter( BPy_Effect * self, PyObject * args )
+{
+ return EXPP_setIValueClamped( args, &self->effect->userjit,
+ EXPP_EFFECT_JITTER_MIN, EXPP_EFFECT_JITTER_MAX, 'h' );
+}
+
+static PyObject *Effect_getDispMat( BPy_Effect * self )
+{
+ return PyInt_FromLong( ( long )self->effect->omat );
+}
+
+static int Effect_setDispMat( BPy_Effect * self, PyObject * args )
+{
+ return EXPP_setIValueClamped( args, &self->effect->omat,
+ EXPP_EFFECT_DISPMAT_MIN, EXPP_EFFECT_DISPMAT_MAX, 'h' );
+}
+
+static PyObject *Effect_getEmissionTex( BPy_Effect * self )
+{
+ return PyInt_FromLong( ( long )self->effect->timetex );
+}
+
+static int Effect_setEmissionTex( BPy_Effect * self, PyObject * args )
+{
+ return EXPP_setIValueClamped( args, &self->effect->timetex,
+ EXPP_EFFECT_TIMETEX_MIN, EXPP_EFFECT_TIMETEX_MAX, 'h' );
+}
+
+static PyObject *Effect_getForceTex( BPy_Effect * self )
+{
+ return PyInt_FromLong( ( long )self->effect->speedtex );
+}
+
+static int Effect_setForceTex( BPy_Effect * self, PyObject * args )
+{
+ return EXPP_setIValueClamped( args, &self->effect->speedtex,
+ EXPP_EFFECT_SPEEDTEX_MIN, EXPP_EFFECT_SPEEDTEX_MAX, 'h' );
+}
+
+static PyObject *Effect_getSpeedType( BPy_Effect * self )
+{
+ return PyInt_FromLong( ( long )self->effect->texmap );
+}
+
+static int Effect_setSpeedType( BPy_Effect * self, PyObject * args )
+{
+ return EXPP_setIValueRange( args, &self->effect->texmap,
+ EXPP_EFFECT_SPEEDTYPE_INTENSITY, EXPP_EFFECT_SPEEDTYPE_GRADIENT,
+ 'h' );
+}
+
+static PyObject *Effect_getDamping( BPy_Effect * self )
+{
+ return PyFloat_FromDouble( ( double )self->effect->damp );
+}
+
+static int Effect_setDamping( BPy_Effect * self, PyObject * args )
+{
+ return EXPP_setFloatClamped( args, &self->effect->damp,
+ EXPP_EFFECT_DAMP_MIN, EXPP_EFFECT_DAMP_MAX );
+}
+
+static PyObject *Effect_getVertGroup( BPy_Effect * self )
+{
+ return PyString_FromString( self->effect->vgroupname );
+}
+
+
+static int Effect_setVertGroup( BPy_Effect * self, PyObject * value )
+{
+ char *name;
+ bDeformGroup *dg;
+
+ name = PyString_AsString ( value );
+ if( !name )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected string argument" );
+
+ PyOS_snprintf( self->effect->vgroupname,
+ sizeof( self->effect->vgroupname )-1, "%s", name );
+
+ dg = get_named_vertexgroup( self->object, self->effect->vgroupname );
+ if( dg )
+ self->effect->vertgroup = (short)get_defgroup_num( self->object, dg )+1;
+ else
+ self->effect->vertgroup = 0;
+
+ return 0;
+}
+
+static PyObject *Effect_getSpeedVertGroup( BPy_Effect * self )
+{
+ return PyString_FromString( self->effect->vgroupname_v );
+}
+
+static int Effect_setSpeedVertGroup( BPy_Effect * self, PyObject * value )
+{
+ char *name;
+ bDeformGroup *dg;
+
+ name = PyString_AsString ( value );
+ if( !name )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected string argument" );
+
+ PyOS_snprintf( self->effect->vgroupname_v,
+ sizeof( self->effect->vgroupname_v )-1, "%s", name );
+
+ dg = get_named_vertexgroup( self->object, self->effect->vgroupname_v );
+ if( dg )
+ self->effect->vertgroup_v = (short)get_defgroup_num( self->object, dg )+1;
+ else
+ self->effect->vertgroup_v = 0;
+
+ return 0;
+}
+
+/*****************************************************************************/
+/* attribute: getDisp */
+/* Description: the current value of the display number button */
+/* Data: self effect */
+/* Return: integer value between 0 and 100 */
+/*****************************************************************************/
+static PyObject *Effect_getDisp( BPy_Effect * self )
+{
+ return PyInt_FromLong( ( long )self->effect->disp );
+}
+
+static int Effect_setDisp( BPy_Effect * self, PyObject * args )
+{
+ return EXPP_setIValueRange( args, &self->effect->disp,
+ EXPP_EFFECT_DISP_MIN, EXPP_EFFECT_DISP_MAX, 'h' );
+}
+
+/*****************************************************************************/
+/* attribute: getStep */
+/* Description: the current value of the Step number button */
+/* Data: self effect */
+/* Return: integer value between 1 and 100 */
+/*****************************************************************************/
+static PyObject *Effect_getStaticStep( BPy_Effect * self )
+{
+ return PyInt_FromLong( ( long )self->effect->staticstep );
+}
+
+static int Effect_setStaticStep( BPy_Effect * self , PyObject * args )
+{
+ return EXPP_setIValueRange( args, &self->effect->staticstep,
+ EXPP_EFFECT_STATICSTEP_MIN, EXPP_EFFECT_STATICSTEP_MAX,
+ 'h' );
+}
+
+/*****************************************************************************/
+/* Method: getParticlesLoc */
+/* Python equivalent: effect.getParticlesLoc */
+/* Description: Get the current location of each particle */
+/* and return a list of 3D vectors */
+/* or a list of ists of two 3D vectors */
+/* if effect.vect has any sense */
+/* Data: notihng get the current time from G.scene */
+/* Return: One python list of 3D vector */
+/*****************************************************************************/
+static PyObject *Effect_getParticlesLoc( BPy_Effect * self )
+{
+ Object *ob;
+ Effect *eff;
+ PartEff *paf;
+ Particle *pa=0;
+ PyObject *list, *strand_list, *pyvec, *pyvec2;
+ float p_time, c_time, vec[3], vec1[3], cfra, m_time, s_time;
+ int a;
+ short disp=100 ;
+
+ cfra=frame_to_float( G.scene->r.cfra );
+
+ /* as we need to update the particles system we try to retrieve
+ the object to which the effect is connected */
+ eff =(Effect *) self->effect;
+
+ ob= self->object;
+ if(!ob)
+ return ( EXPP_ReturnPyObjError (PyExc_AttributeError,
+ "Effect has no object" ) );
+ /*get the particles data */
+ paf= (PartEff *)eff;
+
+ /* particles->disp reduce the display number of particles */
+ /* as we want the complete list ... we backup the disp value and restore later */
+ if (paf->disp<100)
+ disp= paf->disp; paf->disp=100;
+
+
+ build_particle_system(ob);
+ pa= paf->keys;
+
+ if(!pa)
+ return ( EXPP_ReturnPyObjError (PyExc_AttributeError,
+ "Particles Location : no Keys" ) );
+
+ /* if object is in motion */
+ if( ob->ipoflag & OB_OFFS_PARTICLE )
+ p_time= ob->sf;
+ else
+ p_time= 0.0;
+
+ list = PyList_New( 0 );
+ if( !list )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError, "PyList() failed" );
+
+ c_time= bsystem_time( ob, cfra, p_time );
+
+ for( a=0; a < paf->totpart; a++, pa += paf->totkey ) {
+
+ if(paf->flag & PAF_STATIC ) {
+ strand_list = PyList_New( 0 );
+ m_time= pa->time+pa->lifetime+paf->staticstep-1;
+ for(c_time= pa->time; c_time<m_time; c_time+=paf->staticstep) {
+ where_is_particle(paf, pa, c_time, vec);
+ MTC_Mat4MulVecfl(ob->obmat, vec); /* make worldspace like the others */
+ pyvec = newVectorObject(vec, 3, Py_NEW);
+ if( PyList_Append( strand_list, pyvec) < 0 ) {
+ Py_DECREF( list );
+ Py_DECREF( strand_list );
+ Py_XDECREF( pyvec );
+
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "Couldn't append item to PyList" );
+ }
+ Py_DECREF( pyvec );
+
+ }
+
+ if( PyList_Append( list, strand_list) < 0 ) {
+ Py_DECREF( list );
+ Py_DECREF( strand_list );
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "Couldn't append item to PyList" );
+ }
+ Py_DECREF( strand_list );
+ } else {
+ if(c_time > pa->time && c_time < pa->time+pa->lifetime ) {
+ /* vector particles are a tuple of 2 vectors */
+ if( paf->stype==PAF_VECT ) {
+ s_time= c_time;
+ p_time= c_time+1.0f;
+ if(c_time < pa->time) {
+ if(paf->flag & PAF_UNBORN)
+ p_time= pa->time+1.0f;
+ else
+ continue;
+ }
+ if(c_time > pa->time+pa->lifetime) {
+ if(paf->flag & PAF_DIED)
+ s_time= pa->time+pa->lifetime-1.0f;
+ else
+ continue;
+ }
+ where_is_particle(paf, pa, s_time, vec);
+ where_is_particle(paf, pa, p_time, vec1);
+ pyvec = newVectorObject(vec, 3, Py_NEW);
+ pyvec2 = newVectorObject(vec1, 3, Py_NEW);
+ if( PyList_Append( list, Py_BuildValue("[OO]", pyvec, pyvec2)) < 0 ) {
+ Py_DECREF( list );
+ Py_XDECREF( pyvec );
+ Py_XDECREF( pyvec2 );
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "Couldn't append item to PyList" );
+ }
+ Py_DECREF( pyvec );
+ Py_DECREF( pyvec2 );
+ } else { /* not a vector */
+ where_is_particle(paf, pa, c_time, vec);
+ pyvec = newVectorObject(vec, 3, Py_NEW);
+ if( PyList_Append( list, pyvec) < 0 ) {
+ Py_DECREF( list );
+ Py_XDECREF( pyvec );
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "Couldn't append item to PyList" );
+ }
+ Py_DECREF( pyvec );
+ }
+ }
+ }
+ }
+
+ /* restore the real disp value */
+ if (disp<100){
+ paf->disp=disp;
+ build_particle_system(ob);
+ }
+
+ return list;
+}
+
+/*****************************************************************************/
+/* Function: Effect_repr */
+/* Description: This is a callback function for the BPy_Effect type. It */
+/* builds a meaninful string to represent effcte objects. */
+/*****************************************************************************/
+
+static PyObject *Effect_repr( void )
+{
+ return PyString_FromString( "Particle" );
+}
+
+/*****************************************************************************/
+/* These are needed by Object.c */
+/*****************************************************************************/
+PyObject *EffectCreatePyObject( Effect * effect, Object *ob )
+{
+ BPy_Effect *blen_object;
+
+ blen_object =
+ ( BPy_Effect * ) PyObject_NEW( BPy_Effect, &Effect_Type );
+
+ if( blen_object )
+ blen_object->effect = (PartEff *)effect;
+ blen_object->object = ob;
+
+ return ( PyObject * ) blen_object;
+}
+
+int EffectCheckPyObject( PyObject * py_obj )
+{
+ return ( py_obj->ob_type == &Effect_Type );
+}
+
+/* #####DEPRECATED###### */
+
+static PyObject *Effect_oldsetChild( BPy_Effect * self, PyObject * args )
+{
+ return EXPP_setterWrapperTuple( (void *)self, args,
+ (setter)Effect_setChild );
+}
+
+static PyObject *Effect_oldsetDefvec( BPy_Effect * self, PyObject * args )
+{
+ return EXPP_setterWrapperTuple( (void *)self, args,
+ (setter)Effect_setDefvec );
+}
+
+static PyObject *Effect_oldsetForce( BPy_Effect * self, PyObject * args )
+{
+ return EXPP_setterWrapperTuple( (void *)self, args,
+ (setter)Effect_setForce );
+}
+
+static PyObject *Effect_oldsetMat( BPy_Effect * self, PyObject * args )
+{
+ return EXPP_setterWrapperTuple( (void *)self, args,
+ (setter)Effect_setChildMat );
+}
+
+static PyObject *Effect_oldsetEnd( BPy_Effect * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Effect_setEnd );
+}
+
+static PyObject *Effect_oldsetLife( BPy_Effect * self, PyObject * args )
+{
+ return EXPP_setterWrapperTuple( (void *)self, args,
+ (setter)Effect_setLife );
+}
+
+static PyObject *Effect_oldsetLifetime( BPy_Effect * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Effect_setLifetime );
+}
+
+static PyObject *Effect_oldsetMult( BPy_Effect * self, PyObject * args )
+{
+ return EXPP_setterWrapperTuple( (void *)self, args,
+ (setter)Effect_setMult );
+}
+
+static PyObject *Effect_oldsetNabla( BPy_Effect * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Effect_setNabla );
+}
+
+static PyObject *Effect_oldsetNormfac( BPy_Effect * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Effect_setNormfac );
+}
+
+static PyObject *Effect_oldsetObfac( BPy_Effect * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Effect_setObfac );
+}
+
+static PyObject *Effect_oldsetRandfac( BPy_Effect * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Effect_setRandfac );
+}
+
+static PyObject *Effect_oldsetRandlife( BPy_Effect * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Effect_setRandlife );
+}
+
+static PyObject *Effect_oldsetSeed( BPy_Effect * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Effect_setSeed );
+}
+
+static PyObject *Effect_oldsetSta( BPy_Effect * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Effect_setSta );
+}
+
+static PyObject *Effect_oldsetTexfac( BPy_Effect * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Effect_setTexfac );
+}
+
+static PyObject *Effect_oldsetTotkey( BPy_Effect * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Effect_setTotkey );
+}
+
+static PyObject *Effect_oldsetTotpart( BPy_Effect * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Effect_setTotpart );
+}
+
+static PyObject *Effect_oldsetVectsize( BPy_Effect * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Effect_setVectsize );
+}
+
+static PyObject *Effect_oldsetFlag( BPy_Effect * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Effect_setFlag );
+}
+
+static PyObject *Effect_oldsetStype( BPy_Effect * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Effect_setStype );
+}
+
+static PyObject *Effect_oldsetType( void )
+{
+ return EXPP_incr_ret( Py_None );
+}
diff --git a/source/blender/python/api2_2x/Effect.h b/source/blender/python/api2_2x/Effect.h
new file mode 100644
index 00000000000..b26e77f1794
--- /dev/null
+++ b/source/blender/python/api2_2x/Effect.h
@@ -0,0 +1,58 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Jacques Guignot
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_EFFECT_H
+#define EXPP_EFFECT_H
+
+#include <Python.h>
+#include "DNA_effect_types.h"
+#include "DNA_object_types.h"
+
+extern PyTypeObject Effect_Type;
+
+#define BPy_Effect_Check(v) ((v)->ob_type==&Effect_Type)
+
+/* Python BPy_Effect structure definition */
+typedef struct {
+ PyObject_HEAD /* required py macro */
+ PartEff * effect;
+ Object * object;
+} BPy_Effect;
+
+/*****************************************************************************/
+/* Python Effect_Type helpder function prototypes: */
+/*****************************************************************************/
+PyObject *Effect_Init( void );
+int EffectCheckPyObject( PyObject * py_obj );
+PyObject *EffectCreatePyObject( Effect * eff, Object * ob );
+
+#endif /* EXPP_EFFECT_H */
diff --git a/source/blender/python/api2_2x/Font.c b/source/blender/python/api2_2x/Font.c
new file mode 100644
index 00000000000..61edac2841a
--- /dev/null
+++ b/source/blender/python/api2_2x/Font.c
@@ -0,0 +1,403 @@
+/*
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Joilnen Leite
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "Font.h" /*This must come first*/
+
+#include "DNA_packedFile_types.h"
+#include "BKE_packedFile.h"
+#include "BKE_global.h"
+#include "BKE_library.h" /* for rename_id() */
+#include "BLI_blenlib.h"
+#include "gen_utils.h"
+#include "gen_library.h"
+
+#include "BKE_main.h" /* so we can access G.main->vfont.first */
+#include "DNA_space_types.h" /* for FILE_MAXDIR only */
+
+extern PyObject *M_Text3d_LoadFont( PyObject * self, PyObject * args );
+
+/*--------------------Python API function prototypes for the Font module----*/
+static PyObject *M_Font_Load( PyObject * self, PyObject * value );
+static PyObject *M_Font_Get( PyObject * self, PyObject * args );
+
+/*------------------------Python API Doc strings for the Font module--------*/
+char M_Font_doc[] = "The Blender Font module\n\n\
+This module provides control over **Font Data** objects in Blender.\n\n\
+Example::\n\n\
+ from Blender import Text3d.Font\n\
+ l = Text3d.Font.Load('/usr/share/fonts/verdata.ttf')\n";
+char M_Font_Get_doc[] = "(name) - return an existing font called 'name'\
+when no argument is given it returns a list of blenders fonts.";
+char M_Font_Load_doc[] =
+ "(filename) - return font from file filename as Font Object, \
+returns None if not found.\n";
+
+/*----- Python method structure definition for Blender.Text3d.Font module---*/
+struct PyMethodDef M_Font_methods[] = {
+ {"Get", ( PyCFunction ) M_Font_Get, METH_VARARGS, M_Font_Get_doc},
+ {"Load", ( PyCFunction ) M_Font_Load, METH_O, M_Font_Load_doc},
+ {NULL, NULL, 0, NULL}
+};
+
+/*--------------- Python BPy_Font methods declarations:-------------------*/
+static PyObject *Font_pack( BPy_Font * self );
+static PyObject *Font_unpack( BPy_Font * self, PyObject * args );
+
+/*--------------- Python BPy_Font methods table:--------------------------*/
+static PyMethodDef BPy_Font_methods[] = {
+ {"pack", ( PyCFunction ) Font_pack, METH_NOARGS,
+ "() - pack this Font"},
+ {"unpack", ( PyCFunction ) Font_unpack, METH_O,
+ "(mode) - unpack this packed font"},
+ {NULL, NULL, 0, NULL}
+};
+
+/*--------------- Python TypeFont callback function prototypes----------*/
+static int Font_compare( BPy_Font * a1, BPy_Font * a2 );
+static PyObject *Font_repr( BPy_Font * font );
+
+
+/*--------------- Python Font Module methods------------------------*/
+
+/*--------------- Blender.Text3d.Font.Get()-----------------------*/
+static PyObject *M_Font_Get( PyObject * self, PyObject * args )
+{
+ char *name = NULL;
+ VFont *vfont_iter;
+
+ if( !PyArg_ParseTuple( args, "|s", &name ) )
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument (or nothing)" ) );
+
+ vfont_iter = G.main->vfont.first;
+
+ if( name ) { /* (name) - Search font by name */
+
+ BPy_Font *wanted_vfont = NULL;
+
+ while(vfont_iter) {
+ if( strcmp( name, vfont_iter->id.name + 2 ) == 0 ) {
+ wanted_vfont =
+ ( BPy_Font * )
+ Font_CreatePyObject( vfont_iter );
+ break;
+ }
+ vfont_iter = vfont_iter->id.next;
+ }
+
+ if( wanted_vfont == NULL ) { /* Requested font doesn't exist */
+ char error_msg[64];
+ PyOS_snprintf( error_msg, sizeof( error_msg ),
+ "Font \"%s\" not found", name );
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_NameError, error_msg ) );
+ }
+
+ return ( PyObject * ) wanted_vfont;
+ }
+
+ else { /* () - return a list of all fonts in the scene */
+ int index = 0;
+ PyObject *vfontlist, *pyobj;
+
+ vfontlist = PyList_New( BLI_countlist( &( G.main->vfont ) ) );
+
+ if( vfontlist == NULL )
+ return ( EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create font list" ) );
+
+ while( vfont_iter ) {
+ pyobj = Font_CreatePyObject( vfont_iter );
+
+ if( !pyobj ) {
+ Py_DECREF(vfontlist);
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_MemoryError,
+ "couldn't create Object" ) );
+ }
+ PyList_SET_ITEM( vfontlist, index, pyobj );
+
+ vfont_iter = vfont_iter->id.next;
+ index++;
+ }
+
+ return vfontlist;
+ }
+}
+
+
+/*--------------- Blender.Text3d.Font.New()-----------------------*/
+PyObject *M_Font_Load( PyObject * self, PyObject * value )
+{
+ char *filename_str = PyString_AsString(value);
+ BPy_Font *py_font = NULL; /* for Font Data object wrapper in Python */
+
+ if( !value )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected string or empty argument" ) );
+
+ /*create python font*/
+ if( !S_ISDIR(BLI_exist(filename_str)) ) {
+ py_font= (BPy_Font *) M_Text3d_LoadFont (self, value);
+ }
+ else
+ Py_RETURN_NONE;
+ return ( PyObject * ) py_font;
+}
+
+/*--------------- Python BPy_Font getsetattr funcs ---------------------*/
+
+
+/*--------------- BPy_Font.filename-------------------------------------*/
+static PyObject *Font_getFilename( BPy_Font * self )
+{
+ return PyString_FromString( self->font->name );
+}
+
+static int Font_setFilename( BPy_Font * self, PyObject * value )
+{
+ char *name = NULL;
+
+ /* max len is FILE_MAXDIR = 160 chars like done in DNA_image_types.h */
+
+ name = PyString_AsString ( value );
+ if( !name )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected string argument" );
+
+ PyOS_snprintf( self->font->name, FILE_MAXDIR * sizeof( char ), "%s",
+ name );
+
+ return 0;
+}
+
+/*--------------- BPy_Font.pack()---------------------------------*/
+static PyObject *Font_pack( BPy_Font * self )
+{
+ if( !self->font->packedfile )
+ self->font->packedfile = newPackedFile(self->font->name);
+ Py_RETURN_NONE;
+}
+
+/*--------------- BPy_Font.unpack()---------------------------------*/
+static PyObject *Font_unpack( BPy_Font * self, PyObject * value )
+{
+ int mode= PyInt_AsLong(value);
+ VFont *font= self->font;
+
+ if( mode==-1 )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_AttributeError,
+ "expected int argument from Blender.UnpackModes" ) );
+
+ if (font->packedfile)
+ if (unpackVFont(font, mode) == RET_ERROR)
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "error unpacking font" );
+
+ Py_RETURN_NONE;
+}
+
+/*--------------- BPy_Font.packed---------------------------------*/
+static PyObject *Font_getPacked( BPy_Font * self )
+{
+ if (G.fileflags & G_AUTOPACK)
+ return EXPP_incr_ret_True();
+ else
+ return EXPP_incr_ret_False();
+}
+
+/*****************************************************************************/
+/* Python attributes get/set structure: */
+/*****************************************************************************/
+static PyGetSetDef BPy_Font_getseters[] = {
+ GENERIC_LIB_GETSETATTR,
+ {"filename",
+ (getter)Font_getFilename, (setter)Font_setFilename,
+ "Font filepath",
+ NULL},
+ {"packed",
+ (getter)Font_getPacked, (setter)NULL,
+ "Packed status",
+ NULL},
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+/*****************************************************************************/
+/* Python TypeFont structure definition: */
+/*****************************************************************************/
+PyTypeObject Font_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender Font", /* char *tp_name; */
+ sizeof( BPy_Font ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ NULL, /* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ ( cmpfunc ) Font_compare, /* cmpfunc tp_compare; */
+ ( reprfunc ) Font_repr, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ ( hashfunc ) GenericLib_hash, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_Font_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ BPy_Font_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+
+
+
+
+
+/*--------------- Font Module Init-----------------------------*/
+PyObject *Font_Init( void )
+{
+ PyObject *submodule;
+
+ if( PyType_Ready( &Font_Type ) < 0 )
+ return NULL;
+
+ submodule = Py_InitModule3( "Blender.Text3d.Font",
+ M_Font_methods, M_Font_doc );
+
+ return ( submodule );
+}
+
+/*--------------- Font module internal callbacks-----------------*/
+/*---------------BPy_Font internal callbacks/methods-------------*/
+
+/*--------------- repr---------------------------------------------*/
+static PyObject *Font_repr( BPy_Font * self )
+{
+ if( self->font )
+ return PyString_FromFormat( "[Font \"%s\"]",
+ self->font->id.name+2 );
+ else
+ return PyString_FromString( "[Font - no data]" );
+}
+
+/*--------------- compare------------------------------------------*/
+static int Font_compare( BPy_Font * a, BPy_Font * b )
+{
+ return ( a->font == b->font ) ? 0 : -1;
+}
+
+/*--------------- Font_CreatePyObject---------------------------------*/
+PyObject *Font_CreatePyObject( struct VFont * font )
+{
+ BPy_Font *blen_font;
+
+ blen_font = ( BPy_Font * ) PyObject_NEW( BPy_Font, &Font_Type );
+
+ blen_font->font = font;
+
+ return ( ( PyObject * ) blen_font );
+}
+
+/*--------------- Font_FromPyObject---------------------------------*/
+struct VFont *Font_FromPyObject( PyObject * py_obj )
+{
+ BPy_Font *blen_obj;
+
+ blen_obj = ( BPy_Font * ) py_obj;
+ if( !( ( BPy_Font * ) py_obj )->font ) { /*test to see if linked to text3d*/
+ //use python vars
+ return NULL;
+ } else {
+ return ( blen_obj->font );
+ }
+}
+
+
+
diff --git a/source/blender/python/api2_2x/Font.h b/source/blender/python/api2_2x/Font.h
new file mode 100644
index 00000000000..c1a1ec73fe2
--- /dev/null
+++ b/source/blender/python/api2_2x/Font.h
@@ -0,0 +1,53 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Joilnen Leite
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_FONT_H
+#define EXPP_FONT_H
+
+#include <Python.h>
+#include "DNA_vfont_types.h"
+
+extern PyTypeObject Font_Type;
+
+typedef struct {
+ PyObject_HEAD /* required py macro */
+ VFont * font; /* libdata must be second */
+} BPy_Font;
+
+/*------------------------------visible prototypes----------------------*/
+PyObject *Font_CreatePyObject( struct VFont * font );
+struct VFont *Font_FromPyObject( PyObject * py_obj );
+PyObject *Font_Init( void );
+
+#endif
+
+
diff --git a/source/blender/python/api2_2x/Geometry.c b/source/blender/python/api2_2x/Geometry.c
new file mode 100644
index 00000000000..a3b2bc8b244
--- /dev/null
+++ b/source/blender/python/api2_2x/Geometry.c
@@ -0,0 +1,433 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Joseph Gilbert, Campbell Barton
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "Geometry.h"
+
+/* - Not needed for now though other geometry functions will probably need them
+#include "BLI_arithb.h"
+#include "BKE_utildefines.h"
+*/
+
+/* Used for PolyFill */
+#include "BKE_displist.h"
+#include "MEM_guardedalloc.h"
+#include "BLI_blenlib.h"
+
+/* needed for EXPP_ReturnPyObjError and EXPP_check_sequence_consistency */
+#include "gen_utils.h"
+
+#include "BKE_utildefines.h"
+#include "BLI_boxpack2d.h"
+#include "BLI_arithb.h"
+
+#define SWAP_FLOAT(a,b,tmp) tmp=a; a=b; b=tmp
+#define eul 0.000001
+
+/*-- forward declarations -- */
+static PyObject *M_Geometry_PolyFill( PyObject * self, PyObject * polyLineSeq );
+static PyObject *M_Geometry_LineIntersect2D( PyObject * self, PyObject * args );
+static PyObject *M_Geometry_ClosestPointOnLine( PyObject * self, PyObject * args );
+static PyObject *M_Geometry_PointInTriangle2D( PyObject * self, PyObject * args );
+static PyObject *M_Geometry_BoxPack2D( PyObject * self, PyObject * args );
+
+
+/*-------------------------DOC STRINGS ---------------------------*/
+static char M_Geometry_doc[] = "The Blender Geometry module\n\n";
+static char M_Geometry_PolyFill_doc[] = "(veclist_list) - takes a list of polylines (each point a vector) and returns the point indicies for a polyline filled with triangles";
+static char M_Geometry_LineIntersect2D_doc[] = "(lineA_p1, lineA_p2, lineB_p1, lineB_p2) - takes 2 lines (as 4 vectors) and returns a vector for their point of intersection or None";
+static char M_Geometry_ClosestPointOnLine_doc[] = "(pt, line_p1, line_p2) - takes a point and a line and returns a (Vector, Bool) for the point on the line, and the bool so you can know if the point was between the 2 points";
+static char M_Geometry_PointInTriangle2D_doc[] = "(pt, tri_p1, tri_p2, tri_p3) - takes 4 vectors, one is the point and the next 3 define the triabgle, only the x and y are used from the vectors";
+static char M_Geometry_BoxPack2D_doc[] = "";
+/*-----------------------METHOD DEFINITIONS ----------------------*/
+struct PyMethodDef M_Geometry_methods[] = {
+ {"PolyFill", ( PyCFunction ) M_Geometry_PolyFill, METH_O, M_Geometry_PolyFill_doc},
+ {"LineIntersect2D", ( PyCFunction ) M_Geometry_LineIntersect2D, METH_VARARGS, M_Geometry_LineIntersect2D_doc},
+ {"ClosestPointOnLine", ( PyCFunction ) M_Geometry_ClosestPointOnLine, METH_VARARGS, M_Geometry_ClosestPointOnLine_doc},
+ {"PointInTriangle2D", ( PyCFunction ) M_Geometry_PointInTriangle2D, METH_VARARGS, M_Geometry_PointInTriangle2D_doc},
+ {"BoxPack2D", ( PyCFunction ) M_Geometry_BoxPack2D, METH_O, M_Geometry_BoxPack2D_doc},
+ {NULL, NULL, 0, NULL}
+};
+/*----------------------------MODULE INIT-------------------------*/
+PyObject *Geometry_Init(void)
+{
+ PyObject *submodule;
+
+ submodule = Py_InitModule3("Blender.Geometry",
+ M_Geometry_methods, M_Geometry_doc);
+ return (submodule);
+}
+
+/*----------------------------------Geometry.PolyFill() -------------------*/
+/* PolyFill function, uses Blenders scanfill to fill multiple poly lines */
+static PyObject *M_Geometry_PolyFill( PyObject * self, PyObject * polyLineSeq )
+{
+ PyObject *tri_list; /*return this list of tri's */
+ PyObject *polyLine, *polyVec;
+ int i, len_polylines, len_polypoints;
+
+ /* display listbase */
+ ListBase dispbase={NULL, NULL};
+ DispList *dl;
+ float *fp; /*pointer to the array of malloced dl->verts to set the points from the vectors */
+ int index, *dl_face, totpoints=0;
+
+
+ dispbase.first= dispbase.last= NULL;
+
+
+ if(!PySequence_Check(polyLineSeq)) {
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a sequence of poly lines" );
+ }
+
+ len_polylines = PySequence_Size( polyLineSeq );
+
+ for( i = 0; i < len_polylines; ++i ) {
+ polyLine= PySequence_GetItem( polyLineSeq, i );
+ if (!PySequence_Check(polyLine)) {
+ freedisplist(&dispbase);
+ Py_XDECREF(polyLine); /* may be null so use Py_XDECREF*/
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "One or more of the polylines is not a sequence of Mathutils.Vector's" );
+ }
+
+ len_polypoints= PySequence_Size( polyLine );
+ if (len_polypoints>0) { /* dont bother adding edges as polylines */
+ if (EXPP_check_sequence_consistency( polyLine, &vector_Type ) != 1) {
+ freedisplist(&dispbase);
+ Py_DECREF(polyLine);
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "A point in one of the polylines is not a Mathutils.Vector type" );
+ }
+
+ dl= MEM_callocN(sizeof(DispList), "poly disp");
+ BLI_addtail(&dispbase, dl);
+ dl->type= DL_INDEX3;
+ dl->nr= len_polypoints;
+ dl->type= DL_POLY;
+ dl->parts= 1; /* no faces, 1 edge loop */
+ dl->col= 0; /* no material */
+ dl->verts= fp= MEM_callocN( sizeof(float)*3*len_polypoints, "dl verts");
+ dl->index= MEM_callocN(sizeof(int)*3*len_polypoints, "dl index");
+
+ for( index = 0; index<len_polypoints; ++index, fp+=3) {
+ polyVec= PySequence_GetItem( polyLine, index );
+
+ fp[0] = ((VectorObject *)polyVec)->vec[0];
+ fp[1] = ((VectorObject *)polyVec)->vec[1];
+ if( ((VectorObject *)polyVec)->size > 2 )
+ fp[2] = ((VectorObject *)polyVec)->vec[2];
+ else
+ fp[2]= 0.0f; /* if its a 2d vector then set the z to be zero */
+
+ totpoints++;
+ Py_DECREF(polyVec);
+ }
+ }
+ Py_DECREF(polyLine);
+ }
+
+ if (totpoints) {
+ /* now make the list to return */
+ filldisplist(&dispbase, &dispbase);
+
+ /* The faces are stored in a new DisplayList
+ thats added to the head of the listbase */
+ dl= dispbase.first;
+
+ tri_list= PyList_New(dl->parts);
+ if( !tri_list ) {
+ freedisplist(&dispbase);
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "Geometry.PolyFill failed to make a new list" );
+ }
+
+ index= 0;
+ dl_face= dl->index;
+ while(index < dl->parts) {
+ PyList_SetItem(tri_list, index, Py_BuildValue("iii", dl_face[0], dl_face[1], dl_face[2]) );
+ dl_face+= 3;
+ index++;
+ }
+ freedisplist(&dispbase);
+ } else {
+ /* no points, do this so scripts dont barf */
+ tri_list= PyList_New(0);
+ }
+
+ return tri_list;
+}
+
+
+static PyObject *M_Geometry_LineIntersect2D( PyObject * self, PyObject * args )
+{
+ VectorObject *line_a1, *line_a2, *line_b1, *line_b2;
+ float a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y, xi, yi, a1,a2,b1,b2, newvec[2];
+ if( !PyArg_ParseTuple ( args, "O!O!O!O!",
+ &vector_Type, &line_a1,
+ &vector_Type, &line_a2,
+ &vector_Type, &line_b1,
+ &vector_Type, &line_b2)
+ )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_TypeError, "expected 4 vector types\n" ) );
+
+ a1x= line_a1->vec[0];
+ a1y= line_a1->vec[1];
+ a2x= line_a2->vec[0];
+ a2y= line_a2->vec[1];
+
+ b1x= line_b1->vec[0];
+ b1y= line_b1->vec[1];
+ b2x= line_b2->vec[0];
+ b2y= line_b2->vec[1];
+
+ if((MIN2(a1x, a2x) > MAX2(b1x, b2x)) ||
+ (MAX2(a1x, a2x) < MIN2(b1x, b2x)) ||
+ (MIN2(a1y, a2y) > MAX2(b1y, b2y)) ||
+ (MAX2(a1y, a2y) < MIN2(b1y, b2y)) ) {
+ Py_RETURN_NONE;
+ }
+ /* Make sure the hoz/vert line comes first. */
+ if (fabs(b1x - b2x) < eul || fabs(b1y - b2y) < eul) {
+ SWAP_FLOAT(a1x, b1x, xi); /*abuse xi*/
+ SWAP_FLOAT(a1y, b1y, xi);
+ SWAP_FLOAT(a2x, b2x, xi);
+ SWAP_FLOAT(a2y, b2y, xi);
+ }
+
+ if (fabs(a1x-a2x) < eul) { /* verticle line */
+ if (fabs(b1x-b2x) < eul){ /*verticle second line */
+ Py_RETURN_NONE; /* 2 verticle lines dont intersect. */
+ }
+ else if (fabs(b1y-b2y) < eul) {
+ /*X of vert, Y of hoz. no calculation needed */
+ newvec[0]= a1x;
+ newvec[1]= b1y;
+ return newVectorObject(newvec, 2, Py_NEW);
+ }
+
+ yi = (float)(((b1y / fabs(b1x - b2x)) * fabs(b2x - a1x)) + ((b2y / fabs(b1x - b2x)) * fabs(b1x - a1x)));
+
+ if (yi > MAX2(a1y, a2y)) {/* New point above seg1's vert line */
+ Py_RETURN_NONE;
+ } else if (yi < MIN2(a1y, a2y)) { /* New point below seg1's vert line */
+ Py_RETURN_NONE;
+ }
+ newvec[0]= a1x;
+ newvec[1]= yi;
+ return newVectorObject(newvec, 2, Py_NEW);
+ } else if (fabs(a2y-a1y) < eul) { /* hoz line1 */
+ if (fabs(b2y-b1y) < eul) { /*hoz line2*/
+ Py_RETURN_NONE; /*2 hoz lines dont intersect*/
+ }
+
+ /* Can skip vert line check for seg 2 since its covered above. */
+ xi = (float)(((b1x / fabs(b1y - b2y)) * fabs(b2y - a1y)) + ((b2x / fabs(b1y - b2y)) * fabs(b1y - a1y)));
+ if (xi > MAX2(a1x, a2x)) { /* New point right of hoz line1's */
+ Py_RETURN_NONE;
+ } else if (xi < MIN2(a1x, a2x)) { /*New point left of seg1's hoz line */
+ Py_RETURN_NONE;
+ }
+ newvec[0]= xi;
+ newvec[1]= a1y;
+ return newVectorObject(newvec, 2, Py_NEW);
+ }
+
+ b1 = (a2y-a1y)/(a2x-a1x);
+ b2 = (b2y-b1y)/(b2x-b1x);
+ a1 = a1y-b1*a1x;
+ a2 = b1y-b2*b1x;
+
+ if (b1 - b2 == 0.0) {
+ Py_RETURN_NONE;
+ }
+
+ xi = - (a1-a2)/(b1-b2);
+ yi = a1+b1*xi;
+ if ((a1x-xi)*(xi-a2x) >= 0 && (b1x-xi)*(xi-b2x) >= 0 && (a1y-yi)*(yi-a2y) >= 0 && (b1y-yi)*(yi-b2y)>=0) {
+ newvec[0]= xi;
+ newvec[1]= yi;
+ return newVectorObject(newvec, 2, Py_NEW);
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *M_Geometry_ClosestPointOnLine( PyObject * self, PyObject * args )
+{
+ VectorObject *pt, *line_1, *line_2;
+ float pt_in[3], pt_out[3], l1[3], l2[3];
+ float lambda;
+ PyObject *ret, *val1, *val2;
+
+ if( !PyArg_ParseTuple ( args, "O!O!O!",
+ &vector_Type, &pt,
+ &vector_Type, &line_1,
+ &vector_Type, &line_2)
+ )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_TypeError, "expected 3 vector types\n" ) );
+
+ /* accept 2d verts */
+ if (pt->size==3) { VECCOPY(pt_in, pt->vec);}
+ else { pt_in[2]=0.0; VECCOPY2D(pt_in, pt->vec) }
+
+ if (line_1->size==3) { VECCOPY(l1, line_1->vec);}
+ else { l1[2]=0.0; VECCOPY2D(l1, line_1->vec) }
+
+ if (line_2->size==3) { VECCOPY(l2, line_2->vec);}
+ else { l2[2]=0.0; VECCOPY2D(l2, line_2->vec) }
+
+ /* do the calculation */
+ lambda = lambda_cp_line_ex(pt_in, l1, l2, pt_out);
+
+ val1 = newVectorObject(pt_out, 3, Py_NEW);
+ val2 = PyFloat_FromDouble(lambda);
+
+ ret = PyTuple_Pack(2, val1, val2);
+
+ Py_DECREF(val1);
+ Py_DECREF(val2);
+
+ return ret;
+}
+
+#define SIDE_OF_LINE(pa,pb,pp) ((pa[0]-pp[0])*(pb[1]-pp[1]))-((pb[0]-pp[0])*(pa[1]-pp[1]))
+#define POINT_IN_TRI(p0,p1,p2,p3) ((SIDE_OF_LINE(p1,p2,p0)>=0) && (SIDE_OF_LINE(p2,p3,p0)>=0) && (SIDE_OF_LINE(p3,p1,p0)>=0))
+
+static PyObject *M_Geometry_PointInTriangle2D( PyObject * self, PyObject * args )
+{
+ VectorObject *pt_vec, *tri_p1, *tri_p2, *tri_p3;
+
+ if( !PyArg_ParseTuple ( args, "O!O!O!O!",
+ &vector_Type, &pt_vec,
+ &vector_Type, &tri_p1,
+ &vector_Type, &tri_p2,
+ &vector_Type, &tri_p3)
+ )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_TypeError, "expected 4 vector types\n" ) );
+
+ if POINT_IN_TRI(pt_vec->vec, tri_p1->vec, tri_p2->vec, tri_p3->vec)
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+}
+
+int boxPack_FromPyObject(PyObject * value, boxPack **boxarray )
+{
+ int len, i;
+ PyObject *list_item, *item_1, *item_2;
+ boxPack *box;
+
+
+ /* Error checking must alredy be done */
+ if( !PyList_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "can only back a list of [x,y,x,w]" );
+
+ len = PyList_Size( value );
+
+ (*boxarray) = MEM_mallocN( len*sizeof(boxPack), "boxPack box");
+
+
+ for( i = 0; i < len; i++ ) {
+ list_item = PyList_GET_ITEM( value, i );
+ if( !PyList_Check( list_item ) || PyList_Size( list_item ) < 4 ) {
+ MEM_freeN(*boxarray);
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "can only back a list of [x,y,x,w]" );
+ }
+
+ box = (*boxarray)+i;
+
+ item_1 = PyList_GET_ITEM(list_item, 2);
+ item_2 = PyList_GET_ITEM(list_item, 3);
+
+ if (!PyNumber_Check(item_1) || !PyNumber_Check(item_2)) {
+ MEM_freeN(*boxarray);
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "can only back a list of 2d boxes [x,y,x,w]" );
+ }
+
+ box->w = (float)PyFloat_AsDouble( item_1 );
+ box->h = (float)PyFloat_AsDouble( item_2 );
+ box->index = i;
+ /* verts will be added later */
+ }
+ return 0;
+}
+
+void boxPack_ToPyObject(PyObject * value, boxPack **boxarray)
+{
+ int len, i;
+ PyObject *list_item;
+ boxPack *box;
+
+ len = PyList_Size( value );
+
+ for( i = 0; i < len; i++ ) {
+ box = (*boxarray)+i;
+ list_item = PyList_GET_ITEM( value, box->index );
+ PyList_SET_ITEM( list_item, 0, PyFloat_FromDouble( box->x ));
+ PyList_SET_ITEM( list_item, 1, PyFloat_FromDouble( box->y ));
+ }
+ MEM_freeN(*boxarray);
+}
+
+
+static PyObject *M_Geometry_BoxPack2D( PyObject * self, PyObject * boxlist )
+{
+ boxPack *boxarray;
+ float tot_width, tot_height;
+ int len;
+ int error;
+
+ if(!PyList_Check(boxlist))
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a sequence of boxes [[x,y,w,h], ... ]" );
+
+ len = PyList_Size( boxlist );
+
+ if (!len)
+ return Py_BuildValue( "ff", 0.0, 0.0);
+
+ error = boxPack_FromPyObject(boxlist, &boxarray);
+ if (error!=0) return NULL;
+
+ /* Non Python function */
+ boxPack2D(boxarray, len, &tot_width, &tot_height);
+
+ boxPack_ToPyObject(boxlist, &boxarray);
+
+ return Py_BuildValue( "ff", tot_width, tot_height);
+}
diff --git a/source/blender/python/api2_2x/Geometry.h b/source/blender/python/api2_2x/Geometry.h
new file mode 100644
index 00000000000..c74f832c642
--- /dev/null
+++ b/source/blender/python/api2_2x/Geometry.h
@@ -0,0 +1,42 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Joseph Gilbert
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+/*Include this file for access to vector, quat, matrix, euler, etc...*/
+
+#ifndef EXPP_Geometry_H
+#define EXPP_Geometry_H
+
+#include <Python.h>
+#include "vector.h"
+
+PyObject *Geometry_Init( void );
+
+#endif /* EXPP_Geometry_H */
diff --git a/source/blender/python/api2_2x/Group.c b/source/blender/python/api2_2x/Group.c
new file mode 100644
index 00000000000..26e5edd0733
--- /dev/null
+++ b/source/blender/python/api2_2x/Group.c
@@ -0,0 +1,813 @@
+/*
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Campbell Barton
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "Group.h" /* This must come first */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_group_types.h"
+#include "DNA_scene_types.h" /* for Base */
+
+#include "BKE_mesh.h"
+#include "BKE_library.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_scene.h"
+#include "BKE_group.h"
+
+#include "BLI_blenlib.h"
+
+#include "blendef.h"
+#include "Object.h"
+#include "gen_utils.h"
+#include "gen_library.h"
+
+/* checks for the group being removed */
+#define GROUP_DEL_CHECK_PY(bpy_group) if (!(bpy_group->group)) return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, "Group has been removed" ) )
+#define GROUP_DEL_CHECK_INT(bpy_group) if (!(bpy_group->group)) return ( EXPP_ReturnIntError( PyExc_RuntimeError, "Group has been removed" ) )
+
+/*****************************************************************************/
+/* Python API function prototypes for the Blender module. */
+/*****************************************************************************/
+static PyObject *M_Group_New( PyObject * self, PyObject * args );
+PyObject *M_Group_Get( PyObject * self, PyObject * args );
+PyObject *M_Group_Unlink( PyObject * self, BPy_Group * pygrp );
+
+/* internal */
+static PyObject *GroupObSeq_CreatePyObject( BPy_Group *self, GroupObject *iter );
+
+/*****************************************************************************/
+/* Python method structure definition for Blender.Object module: */
+/*****************************************************************************/
+struct PyMethodDef M_Group_methods[] = {
+ {"New", ( PyCFunction ) M_Group_New, METH_VARARGS,
+ "(name) Add a new empty group"},
+ {"Get", ( PyCFunction ) M_Group_Get, METH_VARARGS,
+"(name) - return the group with the name 'name',\
+returns None if notfound.\nIf 'name' is not specified, it returns a list of all groups."},
+ {"Unlink", ( PyCFunction ) M_Group_Unlink, METH_O,
+ "(group) - Unlink (delete) this group from Blender."},
+ {NULL, NULL, 0, NULL}
+};
+
+/*****************************************************************************/
+/* Python BPy_Group methods table: */
+/*****************************************************************************/
+static PyObject *BPy_Group_copy( BPy_Group * self );
+
+static PyMethodDef BPy_Group_methods[] = {
+ /* name, method, flags, doc */
+ {"__copy__", ( PyCFunction ) BPy_Group_copy, METH_VARARGS,
+ "() - Return a copy of the group containing the same objects."},
+ {"copy", ( PyCFunction ) BPy_Group_copy, METH_VARARGS,
+ "() - Return a copy of the group containing the same objects."},
+ {NULL, NULL, 0, NULL}
+};
+
+
+static PyObject *BPy_Group_copy( BPy_Group * self )
+{
+ BPy_Group *py_group; /* for Group Data object wrapper in Python */
+ struct Group *bl_group;
+ GroupObject *group_ob, *group_ob_new; /* Group object, copied and added to the groups */
+
+ GROUP_DEL_CHECK_PY(self);
+
+ bl_group= add_group( self->group->id.name + 2 );
+
+ if( bl_group ) /* now create the wrapper grp in Python */
+ py_group = ( BPy_Group * ) Group_CreatePyObject( bl_group );
+ else
+ return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't create Group Data in Blender" ) );
+
+ bl_group->id.us = 1;
+
+ /* Now add the objects to the group */
+ group_ob= self->group->gobject.first;
+ while(group_ob) {
+ /* save time by not using */
+ group_ob_new= MEM_callocN(sizeof(GroupObject), "groupobject");
+ group_ob_new->ob= group_ob->ob;
+ BLI_addtail( &bl_group->gobject, group_ob_new);
+ group_ob= group_ob->next;
+ }
+
+ return ( PyObject * ) py_group;
+
+}
+
+
+/************************************************************************
+ *
+ * Python BPy_Object attributes
+ *
+ ************************************************************************/
+static PyObject *Group_getObjects( BPy_Group * self )
+{
+ return GroupObSeq_CreatePyObject(self, NULL);
+}
+
+
+static void add_to_group_wraper(Group *group, Object *ob) {
+ Base *base;
+ add_to_group(group, ob);
+
+ if (!(ob->flag & OB_FROMGROUP)) { /* do this to avoid a listbase lookup */
+ ob->flag |= OB_FROMGROUP;
+
+ base= object_in_scene(ob, G.scene);
+ if (base)
+ base->flag |= OB_FROMGROUP;
+ }
+}
+
+/* only for internal use Blender.Group.Get("MyGroup").objects= []*/
+static int Group_setObjects( BPy_Group * self, PyObject * args )
+{
+ int i, list_size;
+ Group *group;
+ Object *blen_ob;
+ group= self->group;
+
+ GROUP_DEL_CHECK_INT(self);
+
+ if( PyList_Check( args ) ) {
+ if( EXPP_check_sequence_consistency( args, &Object_Type ) != 1)
+ return ( EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a list of objects" ) );
+
+ /* remove all from the list and add the new items */
+ free_group(group); /* unlink all objects from this group, keep the group */
+ list_size= PyList_Size( args );
+ for( i = 0; i < list_size; i++ ) {
+ blen_ob= ((BPy_Object *)PyList_GET_ITEM( args, i ))->object;
+ add_to_group_wraper(group, blen_ob);
+ }
+ } else if (PyIter_Check(args)) {
+ PyObject *iterator = PyObject_GetIter(args);
+ PyObject *item;
+ if (iterator == NULL) {
+ Py_DECREF(iterator);
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a list of objects, This iterator cannot be used." );
+ }
+ free_group(group); /* unlink all objects from this group, keep the group */
+ item = PyIter_Next(iterator);
+ while (item) {
+ if ( PyObject_TypeCheck(item, &Object_Type) ) {
+ blen_ob= ((BPy_Object *)item)->object;
+ add_to_group_wraper(group, blen_ob);
+ }
+ Py_DECREF(item);
+ item = PyIter_Next(iterator);
+ }
+
+ Py_DECREF(iterator);
+
+ if (PyErr_Occurred()) {
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "An unknown error occured while adding iterator objects to the group.\nThe group has been modified." );
+ }
+
+ } else
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a list or sequence of objects" );
+ return 0;
+}
+
+
+
+/*****************************************************************************/
+/* PythonTypeObject callback function prototypes */
+/*****************************************************************************/
+static PyObject *Group_repr( BPy_Group * obj );
+static int Group_compare( BPy_Group * a, BPy_Group * b );
+
+/*****************************************************************************/
+/* Python BPy_Group getsetattr funcs: */
+/*****************************************************************************/
+static int Group_setLayers( BPy_Group * self, PyObject * value )
+{
+ unsigned int laymask = 0;
+
+ GROUP_DEL_CHECK_INT(self);
+
+ if( !PyInt_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected an integer (bitmask) as argument" );
+
+ laymask = ( unsigned int )PyInt_AS_LONG( value );
+
+ if( laymask <= 0 )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "layer value cannot be zero or below" );
+
+ self->group->layer= laymask & ((1<<20) - 1);
+
+ return 0;
+}
+
+static PyObject *Group_getLayers( BPy_Group * self )
+{
+ return PyInt_FromLong( self->group->layer );
+}
+
+
+/*****************************************************************************/
+/* Python attributes get/set structure: */
+/*****************************************************************************/
+static PyGetSetDef BPy_Group_getseters[] = {
+ GENERIC_LIB_GETSETATTR,
+ {"layers",
+ (getter)Group_getLayers, (setter)Group_setLayers,
+ "layer mask for this group",
+ NULL},
+ {"objects",
+ (getter)Group_getObjects, (setter)Group_setObjects,
+ "objects in this group",
+ NULL},
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+/*****************************************************************************/
+/* Python TypeGroup structure definition: */
+/*****************************************************************************/
+PyTypeObject Group_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender Group", /* char *tp_name; */
+ sizeof( BPy_Group ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ NULL, /* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ ( cmpfunc ) Group_compare, /* cmpfunc tp_compare; */
+ ( reprfunc ) Group_repr, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ ( hashfunc ) GenericLib_hash, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_Group_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ BPy_Group_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+
+
+
+
+/*****************************************************************************/
+/* Function: M_Group_New */
+/* Python equivalent: Blender.Group.New */
+/*****************************************************************************/
+PyObject *M_Group_New( PyObject * self, PyObject * args )
+{
+ char *name = "Group";
+ BPy_Group *py_group; /* for Group Data object wrapper in Python */
+ struct Group *bl_group;
+
+ if( !PyArg_ParseTuple( args, "|s", &name ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "string expected as argument or nothing" );
+
+ bl_group= add_group( name );
+
+ if( bl_group ) /* now create the wrapper grp in Python */
+ py_group = ( BPy_Group * ) Group_CreatePyObject( bl_group );
+ else
+ return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't create Group Data in Blender" ) );
+
+ bl_group->id.us = 1;
+
+ return ( PyObject * ) py_group;
+}
+
+/*****************************************************************************/
+/* Function: M_Group_Get */
+/* Python equivalent: Blender.Group.Get */
+/*****************************************************************************/
+PyObject *M_Group_Get( PyObject * self, PyObject * args )
+{
+ char *name = NULL;
+ Group *group_iter;
+
+ if( !PyArg_ParseTuple( args, "|s", &name ) )
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument (or nothing)" ) );
+
+ group_iter = G.main->group.first;
+
+ if( name ) { /* (name) - Search group by name */
+
+ BPy_Group *wanted_group = NULL;
+
+ while( ( group_iter ) && ( wanted_group == NULL ) ) {
+
+ if( strcmp( name, group_iter->id.name + 2 ) == 0 )
+ wanted_group =
+ ( BPy_Group * )
+ Group_CreatePyObject( group_iter );
+
+ group_iter = group_iter->id.next;
+ }
+
+ if( wanted_group == NULL ) { /* Requested group doesn't exist */
+ char error_msg[64];
+ PyOS_snprintf( error_msg, sizeof( error_msg ),
+ "Group \"%s\" not found", name );
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_NameError, error_msg ) );
+ }
+
+ return ( PyObject * ) wanted_group;
+ }
+
+ else { /* () - return a list of all groups in the scene */
+ int index = 0;
+ PyObject *grouplist, *pyobj;
+
+ grouplist = PyList_New( BLI_countlist( &( G.main->group ) ) );
+
+ if( grouplist == NULL )
+ return ( EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create group list" ) );
+
+ while( group_iter ) {
+ pyobj = Group_CreatePyObject( group_iter );
+
+ if( !pyobj ) {
+ Py_DECREF(grouplist);
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_MemoryError,
+ "couldn't create Object" ) );
+ }
+ PyList_SET_ITEM( grouplist, index, pyobj );
+
+ group_iter = group_iter->id.next;
+ index++;
+ }
+
+ return grouplist;
+ }
+}
+
+
+/*****************************************************************************/
+/* Function: M_Group_Unlink */
+/* Python equivalent: Blender.Group.Unlink */
+/*****************************************************************************/
+PyObject *M_Group_Unlink( PyObject * self, BPy_Group * pygrp )
+{
+ Group *group;
+ if( !BPy_Group_Check(pygrp) )
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a group" ) );
+
+ GROUP_DEL_CHECK_PY(pygrp);
+
+ group= pygrp->group;
+
+ pygrp->group= NULL;
+ free_group(group);
+ unlink_group(group);
+ group->id.us= 0;
+ free_libblock( &G.main->group, group );
+ Py_RETURN_NONE;
+}
+
+
+/*****************************************************************************/
+/* Function: initObject */
+/*****************************************************************************/
+PyObject *Group_Init( void )
+{
+ PyObject *submodule;
+ if( PyType_Ready( &Group_Type ) < 0 )
+ return NULL;
+ if( PyType_Ready( &GroupObSeq_Type ) < 0 )
+ return NULL;
+
+ submodule = Py_InitModule3( "Blender.Group", M_Group_methods,
+ "The Blender Group module\n\n\
+This module provides access to **Group Data** in Blender.\n" );
+
+ /*Add SUBMODULES to the module*/
+ /*PyDict_SetItemString(dict, "Constraint", Constraint_Init()); //creates a *new* module*/
+ return submodule;
+}
+
+
+/*****************************************************************************/
+/* Function: Group_CreatePyObject */
+/* Description: This function will create a new BlenObject from an existing */
+/* Object structure. */
+/*****************************************************************************/
+PyObject *Group_CreatePyObject( struct Group * grp )
+{
+ BPy_Group *pygrp;
+
+ if( !grp )
+ Py_RETURN_NONE;
+
+ pygrp =
+ ( BPy_Group * ) PyObject_NEW( BPy_Group, &Group_Type );
+
+ if( pygrp == NULL ) {
+ return ( NULL );
+ }
+ pygrp->group = grp;
+ return ( ( PyObject * ) pygrp );
+}
+
+/*****************************************************************************/
+/* Function: Group_FromPyObject */
+/* Description: This function returns the Blender group from the given */
+/* PyObject. */
+/*****************************************************************************/
+Group *Group_FromPyObject( PyObject * py_grp )
+{
+ BPy_Group *blen_grp;
+
+ blen_grp = ( BPy_Group * ) py_grp;
+ return ( blen_grp->group );
+}
+
+/*****************************************************************************/
+/* Function: Group_compare */
+/* Description: This is a callback function for the BPy_Group type. It */
+/* compares two Group_Type objects. Only the "==" and "!=" */
+/* comparisons are meaninful. Returns 0 for equality and -1 if */
+/* they don't point to the same Blender Object struct. */
+/* In Python it becomes 1 if they are equal, 0 otherwise. */
+/*****************************************************************************/
+static int Group_compare( BPy_Group * a, BPy_Group * b )
+{
+ Group *pa = a->group, *pb = b->group;
+ return ( pa == pb ) ? 0 : -1;
+}
+
+/*****************************************************************************/
+/* Function: Group_repr */
+/* Description: This is a callback function for the BPy_Group type. It */
+/* builds a meaninful string to represent object objects. */
+/*****************************************************************************/
+static PyObject *Group_repr( BPy_Group * self )
+{
+ if (!self->group)
+ return PyString_FromString( "[Group - Removed]" );
+
+ return PyString_FromFormat( "[Group \"%s\"]",
+ self->group->id.name + 2 );
+}
+
+
+/************************************************************************
+ *
+ * GroupOb sequence
+ *
+ ************************************************************************/
+/*
+ * create a thin GroupOb object
+ */
+
+static PyObject *GroupObSeq_CreatePyObject( BPy_Group *self, GroupObject *iter )
+{
+ BPy_GroupObSeq *seq = PyObject_NEW( BPy_GroupObSeq, &GroupObSeq_Type);
+ seq->bpygroup = self; Py_INCREF(self);
+ seq->iter= iter;
+ return (PyObject *)seq;
+}
+
+
+static int GroupObSeq_len( BPy_GroupObSeq * self )
+{
+ GROUP_DEL_CHECK_INT(self->bpygroup);
+ return BLI_countlist( &( self->bpygroup->group->gobject ) );
+}
+
+/*
+ * retrive a single GroupOb from somewhere in the GroupObex list
+ */
+
+static PyObject *GroupObSeq_item( BPy_GroupObSeq * self, int i )
+{
+ Group *group= self->bpygroup->group;
+ int index=0;
+ PyObject *bpy_obj;
+ GroupObject *gob;
+
+ GROUP_DEL_CHECK_PY(self->bpygroup);
+
+ for (gob= group->gobject.first; gob && i!=index; gob= gob->next, index++) {}
+
+ if (!(gob))
+ return EXPP_ReturnPyObjError( PyExc_IndexError,
+ "array index out of range" );
+
+ bpy_obj = Object_CreatePyObject( gob->ob );
+
+ if( !bpy_obj )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyObject_New() failed" );
+
+ return (PyObject *)bpy_obj;
+
+}
+
+static PySequenceMethods GroupObSeq_as_sequence = {
+ ( inquiry ) GroupObSeq_len, /* sq_length */
+ ( binaryfunc ) 0, /* sq_concat */
+ ( intargfunc ) 0, /* sq_repeat */
+ ( intargfunc ) GroupObSeq_item, /* sq_item */
+ ( intintargfunc ) 0, /* sq_slice */
+ ( intobjargproc ) 0, /* sq_ass_item */
+ ( intintobjargproc ) 0, /* sq_ass_slice */
+ 0,0,0,
+};
+
+/************************************************************************
+ *
+ * Python GroupObSeq_Type iterator (iterates over GroupObjects)
+ *
+ ************************************************************************/
+
+/*
+ * Initialize the interator index
+ */
+
+static PyObject *GroupObSeq_getIter( BPy_GroupObSeq * self )
+{
+ GROUP_DEL_CHECK_PY(self->bpygroup);
+
+ if (!self->iter) {
+ self->iter = self->bpygroup->group->gobject.first;
+ return EXPP_incr_ret ( (PyObject *) self );
+ } else {
+ return GroupObSeq_CreatePyObject(self->bpygroup, self->bpygroup->group->gobject.first);
+ }
+}
+
+/*
+ * Return next GroupOb.
+ */
+
+static PyObject *GroupObSeq_nextIter( BPy_GroupObSeq * self )
+{
+ PyObject *object;
+ if( !(self->iter) || !(self->bpygroup->group) ) {
+ self->iter = NULL; /* so we can add objects again */
+ return EXPP_ReturnPyObjError( PyExc_StopIteration,
+ "iterator at end" );
+ }
+
+ object= Object_CreatePyObject( self->iter->ob );
+ self->iter= self->iter->next;
+ return object;
+}
+
+
+static PyObject *GroupObSeq_link( BPy_GroupObSeq * self, BPy_Object *value )
+{
+ Object *blen_ob;
+
+ GROUP_DEL_CHECK_PY(self->bpygroup);
+
+ if( !BPy_Object_Check(value) )
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a python object as an argument" ) );
+
+ /*
+ if (self->iter != NULL)
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "Cannot modify group objects while iterating" );
+ */
+
+ blen_ob = value->object;
+
+ add_to_group_wraper(self->bpygroup->group, blen_ob); /* this checks so as not to add the object into the group twice*/
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *GroupObSeq_unlink( BPy_GroupObSeq * self, BPy_Object *value )
+{
+ Object *blen_ob;
+ Base *base= NULL;
+
+ GROUP_DEL_CHECK_PY(self->bpygroup);
+
+ if( !BPy_Object_Check(value) )
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a python object as an argument" ) );
+
+ blen_ob = value->object;
+
+
+
+ rem_from_group(self->bpygroup->group, blen_ob);
+
+ if(find_group(blen_ob)==NULL) {
+ blen_ob->flag &= ~OB_FROMGROUP;
+
+ base= object_in_scene(blen_ob, G.scene);
+ if (base)
+ base->flag &= ~OB_FROMGROUP;
+ }
+ Py_RETURN_NONE;
+}
+
+static struct PyMethodDef BPy_GroupObSeq_methods[] = {
+ {"link", (PyCFunction)GroupObSeq_link, METH_O,
+ "make the object a part of this group"},
+ {"unlink", (PyCFunction)GroupObSeq_unlink, METH_O,
+ "unlink an object from this group"},
+ {NULL, NULL, 0, NULL}
+};
+
+/************************************************************************
+ *
+ * Python GroupObSeq_Type standard operations
+ *
+ ************************************************************************/
+
+static void GroupObSeq_dealloc( BPy_GroupObSeq * self )
+{
+ Py_DECREF(self->bpygroup);
+ PyObject_DEL( self );
+}
+
+/*****************************************************************************/
+/* Python GroupObSeq_Type structure definition: */
+/*****************************************************************************/
+PyTypeObject GroupObSeq_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender GroupObSeq", /* char *tp_name; */
+ sizeof( BPy_GroupObSeq ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ ( destructor ) GroupObSeq_dealloc,/* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* cmpfunc tp_compare; */
+ NULL, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ &GroupObSeq_as_sequence, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ ( getiterfunc) GroupObSeq_getIter, /* getiterfunc tp_iter; */
+ ( iternextfunc ) GroupObSeq_nextIter, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_GroupObSeq_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ NULL, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
diff --git a/source/blender/python/api2_2x/Group.h b/source/blender/python/api2_2x/Group.h
new file mode 100644
index 00000000000..0512623b5f8
--- /dev/null
+++ b/source/blender/python/api2_2x/Group.h
@@ -0,0 +1,66 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Michel Selten
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_GROUP_H
+#define EXPP_GROUP_H
+
+#include <Python.h>
+#include "DNA_group_types.h"
+
+/* The Group PyTypeObject defined in Group.c */
+extern PyTypeObject Group_Type;
+extern PyTypeObject GroupObSeq_Type;
+
+#define BPy_Group_Check(v) ((v)->ob_type == &Group_Type)
+#define BPy_GroupObSeq_Check(v) ((v)->ob_type == &GroupObSeq_Type)
+
+/*****************************************************************************/
+/* Python BPy_Group structure definition. */
+/*****************************************************************************/
+typedef struct {
+ PyObject_HEAD
+ struct Group *group;
+} BPy_Group;
+
+
+/* Group object sequence, iterate on the groups object listbase*/
+typedef struct {
+ PyObject_VAR_HEAD /* required python macro */
+ BPy_Group *bpygroup; /* link to the python group so we can know if its been removed */
+ GroupObject *iter; /* so we can iterate over the objects */
+} BPy_GroupObSeq;
+
+PyObject *Group_Init( void );
+PyObject *Group_CreatePyObject( struct Group *group );
+Group *Group_FromPyObject( PyObject * py_obj );
+
+#endif /* EXPP_GROUP_H */
diff --git a/source/blender/python/api2_2x/IDProp.c b/source/blender/python/api2_2x/IDProp.c
new file mode 100644
index 00000000000..4f2fa82b21e
--- /dev/null
+++ b/source/blender/python/api2_2x/IDProp.c
@@ -0,0 +1,895 @@
+/**
+ * $Id: IDProp.c
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Joseph Eagar
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "DNA_ID.h"
+
+#include "BKE_idprop.h"
+
+#include "IDProp.h"
+#include "gen_utils.h"
+
+#include "MEM_guardedalloc.h"
+
+#define BSTR_EQ(a, b) (*(a) == *(b) && !strcmp(a, b))
+
+/*** Function to wrap ID properties ***/
+PyObject *BPy_Wrap_IDProperty(ID *id, IDProperty *prop, IDProperty *parent);
+
+extern PyTypeObject IDArray_Type;
+extern PyTypeObject IDGroup_Iter_Type;
+
+/*********************** ID Property Main Wrapper Stuff ***************/
+
+PyObject *IDGroup_repr( BPy_IDProperty *self )
+{
+ return PyString_FromString( "(ID Property)" );
+}
+
+extern PyTypeObject IDGroup_Type;
+
+PyObject *BPy_IDGroup_WrapData( ID *id, IDProperty *prop )
+{
+ switch ( prop->type ) {
+ case IDP_STRING:
+ return PyString_FromString( prop->data.pointer );
+ case IDP_INT:
+ return PyInt_FromLong( (long)prop->data.val );
+ case IDP_FLOAT:
+ return PyFloat_FromDouble( (double)(*(float*)(&prop->data.val)) );
+ case IDP_GROUP:
+ /*blegh*/
+ {
+ BPy_IDProperty *group = PyObject_New(BPy_IDProperty, &IDGroup_Type);
+ if (!group)
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyObject_New() failed" );
+
+ group->id = id;
+ group->prop = prop;
+ return (PyObject*) group;
+ }
+ case IDP_ARRAY:
+ {
+ BPy_IDProperty *array = PyObject_New(BPy_IDProperty, &IDArray_Type);
+ if (!array)
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyObject_New() failed" );
+
+ array->id = id;
+ array->prop = prop;
+ return (PyObject*) array;
+ }
+ }
+ Py_RETURN_NONE;
+}
+
+int BPy_IDGroup_SetData(BPy_IDProperty *self, IDProperty *prop, PyObject *value)
+{
+ switch (prop->type) {
+ case IDP_STRING:
+ {
+ char *st;
+ if (!PyString_Check(value))
+ return EXPP_ReturnIntError(PyExc_TypeError, "expected a string!");
+
+ st = PyString_AsString(value);
+ IDP_ResizeArray(prop, strlen(st)+1);
+ strcpy(prop->data.pointer, st);
+ return 0;
+ }
+
+ case IDP_INT:
+ {
+ int ivalue;
+ if (!PyNumber_Check(value))
+ return EXPP_ReturnIntError(PyExc_TypeError, "expected an int!");
+ value = PyNumber_Int(value);
+ if (!value)
+ return EXPP_ReturnIntError(PyExc_TypeError, "expected an int!");
+ ivalue = (int) PyInt_AsLong(value);
+ prop->data.val = ivalue;
+ Py_XDECREF(value);
+ break;
+ }
+ case IDP_FLOAT:
+ {
+ float fvalue;
+ if (!PyNumber_Check(value))
+ return EXPP_ReturnIntError(PyExc_TypeError, "expected a float!");
+ value = PyNumber_Float(value);
+ if (!value)
+ return EXPP_ReturnIntError(PyExc_TypeError, "expected a float!");
+ fvalue = (float) PyFloat_AsDouble(value);
+ *(float*)&self->prop->data.val = fvalue;
+ Py_XDECREF(value);
+ break;
+ }
+
+ default:
+ return EXPP_ReturnIntError(PyExc_AttributeError, "attempt to set read-only attribute!");
+ }
+ return 0;
+}
+
+PyObject *BPy_IDGroup_GetName(BPy_IDProperty *self, void *bleh)
+{
+ return PyString_FromString(self->prop->name);
+}
+
+int BPy_IDGroup_SetName(BPy_IDProperty *self, PyObject *value, void *bleh)
+{
+ char *st;
+ if (!PyString_Check(value))
+ return EXPP_ReturnIntError(PyExc_TypeError, "expected a string!");
+
+ st = PyString_AsString(value);
+ if (strlen(st) >= MAX_IDPROP_NAME)
+ return EXPP_ReturnIntError(PyExc_TypeError, "string length cannot exceed 31 characters!");
+
+ strcpy(self->prop->name, st);
+ return 0;
+}
+
+PyObject *BPy_IDGroup_GetType(BPy_IDProperty *self)
+{
+ return PyInt_FromLong((long)self->prop->type);
+}
+
+static PyGetSetDef BPy_IDGroup_getseters[] = {
+ {"name",
+ (getter)BPy_IDGroup_GetName, (setter)BPy_IDGroup_SetName,
+ "The name of this Group.",
+ NULL},
+ {NULL, NULL, NULL, NULL, NULL}
+};
+
+int BPy_IDGroup_Map_Len(BPy_IDProperty *self)
+{
+ if (self->prop->type != IDP_GROUP)
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "len() of unsized object");
+
+ return self->prop->len;
+}
+
+PyObject *BPy_IDGroup_Map_GetItem(BPy_IDProperty *self, PyObject *item)
+{
+ IDProperty *loop;
+ char *st;
+
+ if (self->prop->type != IDP_GROUP)
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "unsubscriptable object");
+
+ if (!PyString_Check(item))
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "only strings are allowed as keys of ID properties");
+
+ st = PyString_AsString(item);
+ for (loop=self->prop->data.group.first; loop; loop=loop->next) {
+ if (BSTR_EQ(loop->name, st)) return BPy_IDGroup_WrapData(self->id, loop);
+ }
+ return EXPP_ReturnPyObjError( PyExc_KeyError,
+ "key not in subgroup dict");
+}
+
+/*returns NULL on success, error string on failure*/
+char *BPy_IDProperty_Map_ValidateAndCreate(char *name, IDProperty *group, PyObject *ob)
+{
+ IDProperty *prop = NULL;
+ IDPropertyTemplate val = {0};
+
+ if (PyFloat_Check(ob)) {
+ val.f = (float) PyFloat_AsDouble(ob);
+ prop = IDP_New(IDP_FLOAT, val, name);
+ } else if (PyInt_Check(ob)) {
+ val.i = (int) PyInt_AsLong(ob);
+ prop = IDP_New(IDP_INT, val, name);
+ } else if (PyString_Check(ob)) {
+ val.str = PyString_AsString(ob);
+ prop = IDP_New(IDP_STRING, val, name);
+ } else if (PySequence_Check(ob)) {
+ PyObject *item;
+ int i;
+
+ /*validate sequence and derive type.
+ we assume IDP_INT unless we hit a float
+ number; then we assume it's */
+ val.array.type = IDP_INT;
+ val.array.len = PySequence_Length(ob);
+ for (i=0; i<val.array.len; i++) {
+ item = PySequence_GetItem(ob, i);
+ if (PyFloat_Check(item)) val.array.type = IDP_FLOAT;
+ else if (!PyInt_Check(item)) return "only floats and ints are allowed in ID property arrays";
+ Py_XDECREF(item);
+ }
+
+ prop = IDP_New(IDP_ARRAY, val, name);
+ for (i=0; i<val.array.len; i++) {
+ item = PySequence_GetItem(ob, i);
+ if (val.array.type == IDP_INT) {
+ item = PyNumber_Int(item);
+ ((int*)prop->data.pointer)[i] = (int)PyInt_AsLong(item);
+ } else {
+ item = PyNumber_Float(item);
+ ((float*)prop->data.pointer)[i] = (float)PyFloat_AsDouble(item);
+ }
+ Py_XDECREF(item);
+ }
+ } else if (PyMapping_Check(ob)) {
+ PyObject *keys, *vals, *key, *pval;
+ int i, len;
+ /*yay! we get into recursive stuff now!*/
+ keys = PyMapping_Keys(ob);
+ vals = PyMapping_Values(ob);
+
+ /*we allocate the group first; if we hit any invalid data,
+ we can delete it easily enough.*/
+ prop = IDP_New(IDP_GROUP, val, name);
+ len = PyMapping_Length(ob);
+ for (i=0; i<len; i++) {
+ key = PySequence_GetItem(keys, i);
+ pval = PySequence_GetItem(vals, i);
+ if (!PyString_Check(key)) {
+ IDP_FreeProperty(prop);
+ MEM_freeN(prop);
+ Py_XDECREF(keys);
+ Py_XDECREF(vals);
+ Py_XDECREF(key);
+ Py_XDECREF(pval);
+ return "invalid element in subgroup dict template!";
+ }
+ if (BPy_IDProperty_Map_ValidateAndCreate(PyString_AsString(key), prop, pval)) {
+ IDP_FreeProperty(prop);
+ MEM_freeN(prop);
+ Py_XDECREF(keys);
+ Py_XDECREF(vals);
+ Py_XDECREF(key);
+ Py_XDECREF(pval);
+ return "invalid element in subgroup dict template!";
+ }
+ Py_XDECREF(key);
+ Py_XDECREF(pval);
+ }
+ Py_XDECREF(keys);
+ Py_XDECREF(vals);
+ } else return "invalid property value";
+
+ IDP_ReplaceInGroup(group, prop);
+ return NULL;
+}
+
+int BPy_IDGroup_Map_SetItem(BPy_IDProperty *self, PyObject *key, PyObject *val)
+{
+ char *err;
+
+ if (self->prop->type != IDP_GROUP)
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "unsubscriptable object");
+
+ if (!PyString_Check(key))
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "only strings are allowed as subgroup keys" );
+
+ if (val == NULL) {
+ IDProperty *pkey = IDP_GetPropertyFromGroup(self->prop, PyString_AsString(key));
+ if (pkey) {
+ IDP_RemFromGroup(self->prop, pkey);
+ IDP_FreeProperty(pkey);
+ MEM_freeN(pkey);
+ return 0;
+ } else return EXPP_ReturnIntError( PyExc_RuntimeError, "property not found in group" );
+ }
+
+ err = BPy_IDProperty_Map_ValidateAndCreate(PyString_AsString(key), self->prop, val);
+ if (err) return EXPP_ReturnIntError( PyExc_RuntimeError, err );
+
+ return 0;
+}
+
+PyObject *BPy_IDGroup_SpawnIterator(BPy_IDProperty *self)
+{
+ BPy_IDGroup_Iter *iter = PyObject_New(BPy_IDGroup_Iter, &IDGroup_Iter_Type);
+
+ if (!iter)
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyObject_New() failed" );
+ iter->group = self;
+ iter->mode = IDPROP_ITER_KEYS;
+ iter->cur = self->prop->data.group.first;
+ Py_XINCREF(iter);
+ return (PyObject*) iter;
+}
+
+PyObject *BPy_IDGroup_MapDataToPy(IDProperty *prop)
+{
+ switch (prop->type) {
+ case IDP_STRING:
+ return PyString_FromString(prop->data.pointer);
+ break;
+ case IDP_FLOAT:
+ return PyFloat_FromDouble(*((float*)&prop->data.val));
+ break;
+ case IDP_INT:
+ return PyInt_FromLong( (long)prop->data.val );
+ break;
+ case IDP_ARRAY:
+ {
+ PyObject *seq = PyList_New(prop->len);
+ int i;
+
+ if (!seq)
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyList_New() failed" );
+
+ for (i=0; i<prop->len; i++) {
+ if (prop->subtype == IDP_FLOAT)
+ PyList_SetItem(seq, i,
+ PyFloat_FromDouble(((float*)prop->data.pointer)[i]));
+
+ else PyList_SetItem(seq, i,
+ PyInt_FromLong(((int*)prop->data.pointer)[i]));
+ }
+ return seq;
+ }
+ case IDP_GROUP:
+ {
+ PyObject *dict = PyDict_New(), *wrap;
+ IDProperty *loop;
+
+ if (!dict)
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyDict_New() failed" );
+
+ for (loop=prop->data.group.first; loop; loop=loop->next) {
+ wrap = BPy_IDGroup_MapDataToPy(loop);
+ if (!wrap)
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "BPy_IDGroup_MapDataToPy() failed" );
+
+ PyDict_SetItemString(dict, loop->name, wrap);
+ }
+ return dict;
+ }
+ }
+
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "eek!! a property exists with a bad type code!!!" );
+}
+
+PyObject *BPy_IDGroup_Pop(BPy_IDProperty *self, PyObject *value)
+{
+ IDProperty *loop;
+ PyObject *pyform;
+ char *name = PyString_AsString(value);
+
+ if (!name) {
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "pop expected at least 1 arguments, got 0" );
+ }
+
+ for (loop=self->prop->data.group.first; loop; loop=loop->next) {
+ if (BSTR_EQ(loop->name, name)) {
+ pyform = BPy_IDGroup_MapDataToPy(loop);
+
+ if (!pyform)
+ /*ok something bad happened with the pyobject,
+ so don't remove the prop from the group. if pyform is
+ NULL, then it already should have raised an exception.*/
+ return NULL;
+
+ IDP_RemFromGroup(self->prop, loop);
+ return pyform;
+ }
+ }
+
+ return EXPP_ReturnPyObjError( PyExc_KeyError,
+ "item not in group" );
+}
+
+PyObject *BPy_IDGroup_IterItems(BPy_IDProperty *self)
+{
+ BPy_IDGroup_Iter *iter = PyObject_New(BPy_IDGroup_Iter, &IDGroup_Iter_Type);
+
+ if (!iter)
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyObject_New() failed" );
+
+ iter->group = self;
+ iter->mode = IDPROP_ITER_ITEMS;
+ iter->cur = self->prop->data.group.first;
+ Py_XINCREF(iter);
+ return (PyObject*) iter;
+}
+
+PyObject *BPy_IDGroup_GetKeys(BPy_IDProperty *self)
+{
+ PyObject *seq = PyList_New(self->prop->len);
+ IDProperty *loop;
+ int i;
+
+ if (!seq)
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyList_New() failed" );
+
+ for (i=0, loop=self->prop->data.group.first; loop; loop=loop->next, i++)
+ PyList_SetItem(seq, i, PyString_FromString(loop->name));
+
+ return seq;
+}
+
+PyObject *BPy_IDGroup_GetValues(BPy_IDProperty *self)
+{
+ PyObject *seq = PyList_New(self->prop->len);
+ IDProperty *loop;
+ int i;
+
+ if (!seq)
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyList_New() failed" );
+
+ for (i=0, loop=self->prop->data.group.first; loop; loop=loop->next, i++) {
+ PyList_SetItem(seq, i, BPy_IDGroup_WrapData(self->id, loop));
+ }
+
+ return seq;
+}
+
+PyObject *BPy_IDGroup_HasKey(BPy_IDProperty *self, PyObject *value)
+{
+ IDProperty *loop;
+ char *name = PyString_AsString(value);
+
+ if (!name)
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a string");
+
+ for (loop=self->prop->data.group.first; loop; loop=loop->next) {
+ if (BSTR_EQ(loop->name, name)) Py_RETURN_TRUE;
+ }
+
+ Py_RETURN_FALSE;
+}
+
+PyObject *BPy_IDGroup_Update(BPy_IDProperty *self, PyObject *vars)
+{
+ PyObject *pyob, *pkey, *pval;
+ int i=0;
+
+ if (PySequence_Size(vars) != 1)
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected an object derived from dict.");
+
+ pyob = PyTuple_GET_ITEM(vars, 0);
+ if (!PyDict_Check(pyob))
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected an object derived from dict.");
+
+ while (PyDict_Next(pyob, &i, &pkey, &pval)) {
+ BPy_IDGroup_Map_SetItem(self, pkey, pval);
+ if (PyErr_Occurred()) return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+PyObject *BPy_IDGroup_ConvertToPy(BPy_IDProperty *self)
+{
+ return BPy_IDGroup_MapDataToPy(self->prop);
+}
+
+static struct PyMethodDef BPy_IDGroup_methods[] = {
+ {"pop", (PyCFunction)BPy_IDGroup_Pop, METH_O,
+ "pop an item from the group; raises KeyError if the item doesn't exist."},
+ {"iteritems", (PyCFunction)BPy_IDGroup_IterItems, METH_NOARGS,
+ "iterate through the items in the dict; behaves like dictionary method iteritems."},
+ {"keys", (PyCFunction)BPy_IDGroup_GetKeys, METH_NOARGS,
+ "get the keys associated with this group as a list of strings."},
+ {"values", (PyCFunction)BPy_IDGroup_GetValues, METH_NOARGS,
+ "get the values associated with this group."},
+ {"has_key", (PyCFunction)BPy_IDGroup_HasKey, METH_O,
+ "returns true if the group contains a key, false if not."},
+ {"update", (PyCFunction)BPy_IDGroup_Update, METH_VARARGS,
+ "updates the values in the group with the values of another or a dict."},
+ {"convert_to_pyobject", (PyCFunction)BPy_IDGroup_ConvertToPy, METH_NOARGS,
+ "return a purely python version of the group."},
+ {0, NULL, 0, NULL}
+};
+
+PyMappingMethods BPy_IDGroup_Mapping = {
+ (inquiry)BPy_IDGroup_Map_Len, /*inquiry mp_length */
+ (binaryfunc)BPy_IDGroup_Map_GetItem, /*binaryfunc mp_subscript */
+ (objobjargproc)BPy_IDGroup_Map_SetItem, /*objobjargproc mp_ass_subscript */
+};
+
+PyTypeObject IDGroup_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender IDProperty", /* char *tp_name; */
+ sizeof( BPy_IDProperty ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ NULL, /* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* cmpfunc tp_compare; */
+ ( reprfunc ) IDGroup_repr, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ &BPy_IDGroup_Mapping, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ (getiterfunc)BPy_IDGroup_SpawnIterator, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_IDGroup_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ BPy_IDGroup_getseters, /* struct PyGetSetDef *tp_getset; */
+};
+
+/*********** Main external wrapping function *******/
+PyObject *BPy_Wrap_IDProperty(ID *id, IDProperty *prop, IDProperty *parent)
+{
+ BPy_IDProperty *wrap = PyObject_New(BPy_IDProperty, &IDGroup_Type);
+
+ if (!wrap)
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyObject_New() failed" );
+
+ wrap->prop = prop;
+ wrap->parent = parent;
+ wrap->id = id;
+ //wrap->destroy = 0;
+ return (PyObject*) wrap;
+}
+
+
+/********Array Wrapper********/
+
+PyObject *IDArray_repr(BPy_IDArray *self)
+{
+ return PyString_FromString("(ID Array)");
+}
+
+
+PyObject *BPy_IDArray_GetType(BPy_IDArray *self)
+{
+ return PyInt_FromLong( (long)self->prop->subtype );
+}
+
+PyObject *BPy_IDArray_GetLen(BPy_IDArray *self)
+{
+ return PyInt_FromLong( (long)self->prop->len );
+}
+
+static PyGetSetDef BPy_IDArray_getseters[] = {
+ {"len",
+ (getter)BPy_IDArray_GetLen, (setter)NULL,
+ "The length of the array, can also be gotten with len(array).",
+ NULL},
+ {"type",
+ (getter)BPy_IDArray_GetType, (setter)NULL,
+ "The type of the data in the array, is an ant.",
+ NULL},
+ {NULL, NULL, NULL, NULL, NULL},
+};
+
+int BPy_IDArray_Len(BPy_IDArray *self)
+{
+ return self->prop->len;
+}
+
+PyObject *BPy_IDArray_GetItem(BPy_IDArray *self, int index)
+{
+ if (index < 0 || index >= self->prop->len)
+ return EXPP_ReturnPyObjError( PyExc_IndexError,
+ "index out of range!");
+
+ switch (self->prop->subtype) {
+ case IDP_FLOAT:
+ return PyFloat_FromDouble( (double)(((float*)self->prop->data.pointer)[index]));
+ break;
+ case IDP_INT:
+ return PyInt_FromLong( (long)((int*)self->prop->data.pointer)[index] );
+ break;
+ }
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "invalid/corrupt array type!");
+}
+
+int BPy_IDArray_SetItem(BPy_IDArray *self, int index, PyObject *val)
+{
+ int i;
+ float f;
+
+ if (index < 0 || index >= self->prop->len)
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "index out of range!");
+
+ switch (self->prop->subtype) {
+ case IDP_FLOAT:
+ if (!PyNumber_Check(val)) return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a float");
+ val = PyNumber_Float(val);
+ if (!val) return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a float");
+
+ f = (float) PyFloat_AsDouble(val);
+ ((float*)self->prop->data.pointer)[index] = f;
+ Py_XDECREF(val);
+ break;
+ case IDP_INT:
+ if (!PyNumber_Check(val)) return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected an int");
+ val = PyNumber_Int(val);
+ if (!val) return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected an int");
+
+ i = (int) PyInt_AsLong(val);
+ ((int*)self->prop->data.pointer)[index] = i;
+ Py_XDECREF(val);
+ break;
+ }
+ return 0;
+}
+
+static PySequenceMethods BPy_IDArray_Seq = {
+ (inquiry) BPy_IDArray_Len, /* inquiry sq_length */
+ 0, /* binaryfunc sq_concat */
+ 0, /* intargfunc sq_repeat */
+ (intargfunc)BPy_IDArray_GetItem, /* intargfunc sq_item */
+ 0, /* intintargfunc sq_slice */
+ (intobjargproc)BPy_IDArray_SetItem, /* intobjargproc sq_ass_item */
+ 0, /* intintobjargproc sq_ass_slice */
+ 0, /* objobjproc sq_contains */
+ /* Added in release 2.0 */
+ 0, /* binaryfunc sq_inplace_concat */
+ 0, /* intargfunc sq_inplace_repeat */
+};
+
+PyTypeObject IDArray_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender IDArray", /* char *tp_name; */
+ sizeof( BPy_IDArray ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ NULL, /* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* cmpfunc tp_compare; */
+ ( reprfunc ) IDArray_repr, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ &BPy_IDArray_Seq, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ NULL, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ BPy_IDArray_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+/*********** ID Property Group iterator ********/
+
+PyObject *IDGroup_Iter_iterself(PyObject *self)
+{
+ Py_XINCREF(self);
+ return self;
+}
+
+PyObject *IDGroup_Iter_repr(BPy_IDGroup_Iter *self)
+{
+ return PyString_FromString("(ID Property Group)");
+}
+
+PyObject *BPy_Group_Iter_Next(BPy_IDGroup_Iter *self)
+{
+ IDProperty *cur=NULL;
+ PyObject *tmpval;
+ PyObject *ret;
+
+ if (self->cur) {
+ cur = self->cur;
+ self->cur = self->cur->next;
+ if (self->mode == IDPROP_ITER_ITEMS) {
+ tmpval = BPy_IDGroup_WrapData(self->group->id, cur);
+ ret = Py_BuildValue("[s, O]", cur->name, tmpval);
+ Py_DECREF(tmpval);
+ return ret;
+ } else {
+ return PyString_FromString(cur->name);
+ }
+ } else {
+ return EXPP_ReturnPyObjError( PyExc_StopIteration,
+ "iterator at end" );
+ }
+}
+
+PyTypeObject IDGroup_Iter_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender IDGroup_Iter", /* char *tp_name; */
+ sizeof( BPy_IDGroup_Iter ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ NULL, /* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* cmpfunc tp_compare; */
+ ( reprfunc ) IDGroup_Iter_repr, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ IDGroup_Iter_iterself, /* getiterfunc tp_iter; */
+ (iternextfunc) BPy_Group_Iter_Next, /* iternextfunc tp_iternext; */
+};
+
+void IDProp_Init_Types(void)
+{
+ PyType_Ready( &IDGroup_Type );
+ PyType_Ready( &IDGroup_Iter_Type );
+ PyType_Ready( &IDArray_Type );
+}
diff --git a/source/blender/python/api2_2x/IDProp.h b/source/blender/python/api2_2x/IDProp.h
new file mode 100644
index 00000000000..5fcf4f6e1b7
--- /dev/null
+++ b/source/blender/python/api2_2x/IDProp.h
@@ -0,0 +1,61 @@
+/**
+ * $Id: IDProp.h
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Joseph Eagar
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <Python.h>
+
+struct ID;
+struct IDProperty;
+struct BPy_IDGroup_Iter;
+
+typedef struct BPy_IDProperty {
+ PyObject_VAR_HEAD
+ struct ID *id;
+ struct IDProperty *prop, *parent;
+ PyObject *data_wrap;
+} BPy_IDProperty;
+
+typedef struct BPy_IDArray {
+ PyObject_VAR_HEAD
+ struct ID *id;
+ struct IDProperty *prop;
+} BPy_IDArray;
+
+typedef struct BPy_IDGroup_Iter {
+ PyObject_VAR_HEAD
+ BPy_IDProperty *group;
+ struct IDProperty *cur;
+ int mode;
+} BPy_IDGroup_Iter;
+
+PyObject *BPy_Wrap_IDProperty(struct ID *id, struct IDProperty *prop, struct IDProperty *parent);
+void IDProp_Init_Types(void);
+
+#define IDPROP_ITER_KEYS 0
+#define IDPROP_ITER_ITEMS 1
diff --git a/source/blender/python/api2_2x/Image.c b/source/blender/python/api2_2x/Image.c
new file mode 100644
index 00000000000..ddfc17c7deb
--- /dev/null
+++ b/source/blender/python/api2_2x/Image.c
@@ -0,0 +1,1339 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano, Campbell Barton, Joilnen B. Leite,
+ * Austin Benesh
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+#include "Image.h" /*This must come first */
+
+#include "BDR_drawmesh.h" /* free_realtime_image */
+#include "BKE_main.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_image.h"
+#include "BKE_idprop.h"
+#include "BIF_drawimage.h"
+#include "BLI_blenlib.h"
+#include "DNA_space_types.h" /* FILE_MAXDIR = 160 */
+#include "IMB_imbuf_types.h" /* for the IB_rect define */
+#include "BIF_gl.h"
+#include "gen_utils.h"
+#include "gen_library.h"
+#include "BKE_packedFile.h"
+#include "DNA_packedFile_types.h"
+#include "BKE_icons.h"
+#include "IMB_imbuf.h"
+#include "IDProp.h"
+
+/* used so we can get G.scene->r.cfra for getting the
+current image frame, some images change frame if they are a sequence */
+#include "DNA_scene_types.h"
+
+/*****************************************************************************/
+/* Python BPy_Image defaults: */
+/*****************************************************************************/
+#define EXPP_IMAGE_REP 1
+#define EXPP_IMAGE_REP_MIN 1
+#define EXPP_IMAGE_REP_MAX 16
+
+
+enum img_consts {
+ EXPP_IMAGE_ATTR_XREP = 0,
+ EXPP_IMAGE_ATTR_YREP,
+ EXPP_IMAGE_ATTR_START,
+ EXPP_IMAGE_ATTR_END,
+ EXPP_IMAGE_ATTR_SPEED,
+ EXPP_IMAGE_ATTR_BINDCODE,
+ EXPP_IMAGE_ATTR_SOURCE,
+};
+
+/************************/
+/*** The Image Module ***/
+/************************/
+
+/*****************************************************************************/
+/* Python API function prototypes for the Image module. */
+/*****************************************************************************/
+static PyObject *M_Image_New( PyObject * self, PyObject * args );
+static PyObject *M_Image_Get( PyObject * self, PyObject * args );
+static PyObject *M_Image_GetCurrent( PyObject * self );
+static PyObject *M_Image_Load( PyObject * self, PyObject * value );
+
+
+/*****************************************************************************/
+/* Python BPy_Image methods declarations: */
+/*****************************************************************************/
+static PyObject *Image_getFilename( BPy_Image * self );
+static PyObject *Image_getSize( BPy_Image * self );
+static PyObject *Image_getDepth( BPy_Image * self );
+static PyObject *Image_getXRep( BPy_Image * self );
+static PyObject *Image_getYRep( BPy_Image * self );
+static PyObject *Image_getBindCode( BPy_Image * self );
+static PyObject *Image_getStart( BPy_Image * self );
+static PyObject *Image_getEnd( BPy_Image * self );
+static PyObject *Image_getSpeed( BPy_Image * self );
+static int Image_setFilename( BPy_Image * self, PyObject * args );
+static PyObject *Image_oldsetFilename( BPy_Image * self, PyObject * args );
+static PyObject *Image_setXRep( BPy_Image * self, PyObject * value );
+static PyObject *Image_setYRep( BPy_Image * self, PyObject * value );
+static PyObject *Image_setStart( BPy_Image * self, PyObject * args );
+static PyObject *Image_setEnd( BPy_Image * self, PyObject * args );
+static PyObject *Image_setSpeed( BPy_Image * self, PyObject * args );
+static PyObject *Image_reload( BPy_Image * self );
+static PyObject *Image_glLoad( BPy_Image * self );
+static PyObject *Image_glFree( BPy_Image * self );
+static PyObject *Image_getPixelF( BPy_Image * self, PyObject * args );
+static PyObject *Image_getPixelI( BPy_Image * self, PyObject * args );
+static PyObject *Image_setPixelF( BPy_Image * self, PyObject * args );
+static PyObject *Image_setPixelI( BPy_Image * self, PyObject * args );
+static PyObject *Image_getMaxXY( BPy_Image * self );
+static PyObject *Image_getMinXY( BPy_Image * self );
+static PyObject *Image_save( BPy_Image * self );
+static PyObject *Image_unpack( BPy_Image * self, PyObject * value );
+static PyObject *Image_pack( BPy_Image * self );
+static PyObject *Image_makeCurrent( BPy_Image * self );
+
+
+/*****************************************************************************/
+/* Python BPy_Image methods table: */
+/*****************************************************************************/
+static PyMethodDef BPy_Image_methods[] = {
+ /* name, method, flags, doc */
+ {"getPixelF", ( PyCFunction ) Image_getPixelF, METH_VARARGS,
+ "(int, int) - Get pixel color as floats 0.0-1.0 returns [r,g,b,a]"},
+ {"getPixelI", ( PyCFunction ) Image_getPixelI, METH_VARARGS,
+ "(int, int) - Get pixel color as ints 0-255 returns [r,g,b,a]"},
+ {"setPixelF", ( PyCFunction ) Image_setPixelF, METH_VARARGS,
+ "(int, int, [f r,f g,f b,f a]) - Set pixel color using floats 0.0-1.0"},
+ {"setPixelI", ( PyCFunction ) Image_setPixelI, METH_VARARGS,
+ "(int, int, [i r, i g, i b, i a]) - Set pixel color using ints 0-255"},
+ {"getMaxXY", ( PyCFunction ) Image_getMaxXY, METH_NOARGS,
+ "() - Get maximum x & y coordinates of current image as [x, y]"},
+ {"getMinXY", ( PyCFunction ) Image_getMinXY, METH_NOARGS,
+ "() - Get minimun x & y coordinates of image as [x, y]"},
+ {"getName", ( PyCFunction ) GenericLib_getName, METH_NOARGS,
+ "() - Return Image object name"},
+ {"getFilename", ( PyCFunction ) Image_getFilename, METH_NOARGS,
+ "() - Return Image object filename"},
+ {"getSize", ( PyCFunction ) Image_getSize, METH_NOARGS,
+ "() - Return Image object [width, height] dimension in pixels"},
+ {"getDepth", ( PyCFunction ) Image_getDepth, METH_NOARGS,
+ "() - Return Image object pixel depth"},
+ {"getXRep", ( PyCFunction ) Image_getXRep, METH_NOARGS,
+ "() - Return Image object x repetition value"},
+ {"getYRep", ( PyCFunction ) Image_getYRep, METH_NOARGS,
+ "() - Return Image object y repetition value"},
+ {"getStart", ( PyCFunction ) Image_getStart, METH_NOARGS,
+ "() - Return Image object start frame."},
+ {"getEnd", ( PyCFunction ) Image_getEnd, METH_NOARGS,
+ "() - Return Image object end frame."},
+ {"getSpeed", ( PyCFunction ) Image_getSpeed, METH_NOARGS,
+ "() - Return Image object speed (fps)."},
+ {"getBindCode", ( PyCFunction ) Image_getBindCode, METH_NOARGS,
+ "() - Return Image object's bind code value"},
+ {"reload", ( PyCFunction ) Image_reload, METH_NOARGS,
+ "() - Reload the image from the filesystem"},
+ {"glLoad", ( PyCFunction ) Image_glLoad, METH_NOARGS,
+ "() - Load the image data in OpenGL texture memory.\n\
+ The bindcode (int) is returned."},
+ {"glFree", ( PyCFunction ) Image_glFree, METH_NOARGS,
+ "() - Free the image data from OpenGL texture memory only,\n\
+ see also image.glLoad()."},
+ {"setName", ( PyCFunction ) GenericLib_setName_with_method, METH_VARARGS,
+ "(str) - Change Image object name"},
+ {"setFilename", ( PyCFunction ) Image_oldsetFilename, METH_VARARGS,
+ "(str) - Change Image file name"},
+ {"setXRep", ( PyCFunction ) Image_setXRep, METH_O,
+ "(int) - Change Image object x repetition value"},
+ {"setYRep", ( PyCFunction ) Image_setYRep, METH_O,
+ "(int) - Change Image object y repetition value"},
+ {"setStart", ( PyCFunction ) Image_setStart, METH_VARARGS,
+ "(int) - Change Image object animation start value"},
+ {"setEnd", ( PyCFunction ) Image_setEnd, METH_VARARGS,
+ "(int) - Change Image object animation end value"},
+ {"setSpeed", ( PyCFunction ) Image_setSpeed, METH_VARARGS,
+ "(int) - Change Image object animation speed (fps)"},
+ {"save", ( PyCFunction ) Image_save, METH_NOARGS,
+ "() - Write image buffer to file"},
+ {"unpack", ( PyCFunction ) Image_unpack, METH_VARARGS,
+ "(int) - Unpack image. Uses the values defined in Blender.UnpackModes."},
+ {"pack", ( PyCFunction ) Image_pack, METH_NOARGS,
+ "() - Pack the image"},
+ {"makeCurrent", ( PyCFunction ) Image_makeCurrent, METH_NOARGS,
+ "() - Make this the currently displayed image"},
+ {NULL, NULL, 0, NULL}
+};
+
+
+/*****************************************************************************/
+/* The following string definitions are used for documentation strings. */
+/* In Python these will be written to the console when doing a */
+/* Blender.Image.__doc__ */
+/*****************************************************************************/
+static char M_Image_doc[] = "The Blender Image module\n\n";
+
+static char M_Image_New_doc[] =
+ "() - return a new Image object";
+
+static char M_Image_Get_doc[] =
+ "(name) - return the image with the name 'name', \
+returns None if not found.\n If 'name' is not specified, \
+it returns a list of all images in the\ncurrent scene.";
+
+static char M_Image_GetCurrent_doc[] =
+ "() - return the current image, from last active the uv/image view, \
+returns None no image is in the view.\n";
+
+static char M_Image_Load_doc[] =
+ "(filename) - return image from file filename as Image Object, \
+returns None if not found.\n";
+
+/*****************************************************************************/
+/* Python method structure definition for Blender.Image module: */
+/*****************************************************************************/
+struct PyMethodDef M_Image_methods[] = {
+ {"New", M_Image_New, METH_VARARGS, M_Image_New_doc},
+ {"Get", M_Image_Get, METH_VARARGS, M_Image_Get_doc},
+ {"GetCurrent", ( PyCFunction ) M_Image_GetCurrent, METH_NOARGS, M_Image_GetCurrent_doc},
+ {"get", M_Image_Get, METH_VARARGS, M_Image_Get_doc},
+ {"Load", M_Image_Load, METH_O, M_Image_Load_doc},
+ {NULL, NULL, 0, NULL}
+};
+
+
+/*****************************************************************************/
+/* Function: M_Image_New */
+/* Python equivalent: Blender.Image.New */
+/*****************************************************************************/
+static PyObject *M_Image_New( PyObject * self, PyObject * args)
+{
+ int width, height, depth;
+ char *name;
+ float color[] = {0, 0, 0, 1};
+ Image *image;
+ if( !PyArg_ParseTuple( args, "siii", &name, &width, &height, &depth ) )
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected 1 string and 3 ints" ) );
+ if (width > 5000 || height > 5000 || width < 1 || height < 1)
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "Image width and height must be between 1 and 5000" ) );
+ image = BKE_add_image_size(width, height, name, 0, color);
+ if( !image )
+ return ( EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create PyObject Image_Type" ) );
+
+ /* reset usage count, since BKE_add_image_size() incremented it */
+ /* image->id.us--; */
+ /* Strange, new images have a user count of one???, otherwise it messes up */
+
+ return Image_CreatePyObject( image );
+}
+
+
+
+/*****************************************************************************/
+/* Function: M_Image_Get */
+/* Python equivalent: Blender.Image.Get */
+/* Description: Receives a string and returns the image object */
+/* whose name matches the string. If no argument is */
+/* passed in, a list of all image names in the */
+/* current scene is returned. */
+/*****************************************************************************/
+static PyObject *M_Image_Get( PyObject * self, PyObject * args )
+{
+ char *name = NULL;
+ Image *img_iter;
+
+ if( !PyArg_ParseTuple( args, "|s", &name ) )
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument (or nothing)" ) );
+
+ img_iter = G.main->image.first;
+
+ if( name ) { /* (name) - Search image by name */
+
+ BPy_Image *wanted_image = NULL;
+
+ while( ( img_iter ) && ( wanted_image == NULL ) ) {
+ if( strcmp( name, img_iter->id.name + 2 ) == 0 ) {
+ wanted_image = ( BPy_Image * )
+ PyObject_NEW( BPy_Image, &Image_Type );
+ if( wanted_image )
+ wanted_image->image = img_iter;
+ }
+ img_iter = img_iter->id.next;
+ }
+
+ if( wanted_image == NULL ) { /* Requested image doesn't exist */
+ char error_msg[64];
+ PyOS_snprintf( error_msg, sizeof( error_msg ),
+ "Image \"%s\" not found", name );
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_NameError, error_msg ) );
+ }
+
+ return ( PyObject * ) wanted_image;
+ }
+
+ else { /* () - return a list of all images in the scene */
+ int index = 0;
+ PyObject *img_list, *pyobj;
+
+ img_list = PyList_New( BLI_countlist( &( G.main->image ) ) );
+
+ if( img_list == NULL )
+ return ( EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create PyList" ) );
+
+ while( img_iter ) {
+ pyobj = Image_CreatePyObject( img_iter );
+
+ PyList_SET_ITEM( img_list, index, pyobj );
+
+ img_iter = img_iter->id.next;
+ index++;
+ }
+
+ return ( img_list );
+ }
+}
+
+
+
+/*****************************************************************************/
+/* Function: M_Image_GetCurrent*/
+/* Python equivalent: Blender.Image.GetCurrent */
+/* Description: Returns the active current (G.sima) */
+/* This will be the image last under the mouse cursor */
+/* None if there is no Image. */
+/*****************************************************************************/
+static PyObject *M_Image_GetCurrent( PyObject * self )
+{
+ if (!G.sima || !G.sima->image) {
+ Py_RETURN_NONE;
+ }
+ what_image( G.sima ); /* make sure image data exists */
+ return Image_CreatePyObject( G.sima->image );
+}
+
+
+/*****************************************************************************/
+/* Function: M_Image_Load */
+/* Python equivalent: Blender.Image.Load */
+/* Description: Receives a string and returns the image object */
+/* whose filename matches the string. */
+/*****************************************************************************/
+static PyObject *M_Image_Load( PyObject * self, PyObject * value )
+{
+ char *fname = PyString_AsString(value);
+ Image *img_ptr;
+ BPy_Image *image;
+
+ if( !value )
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument" ) );
+
+ image = ( BPy_Image * ) PyObject_NEW( BPy_Image, &Image_Type );
+
+ if( !image )
+ return ( EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create PyObject Image_Type" ) );
+
+ img_ptr = BKE_add_image_file( fname );
+ if( !img_ptr )
+ return ( EXPP_ReturnPyObjError( PyExc_IOError,
+ "couldn't load image" ) );
+
+ /* force a load the image buffers*/
+ BKE_image_get_ibuf(img_ptr, NULL);
+
+ image->image = img_ptr;
+
+ return ( PyObject * ) image;
+}
+
+
+/**
+ * getPixelF( x, y )
+ * returns float list of pixel colors in rgba order.
+ * returned values are floats normalized to 0.0 - 1.0.
+ * blender images are all 4x8 bit at the moment apr-2005
+ */
+
+static PyObject *Image_getPixelF( BPy_Image * self, PyObject * args )
+{
+
+ PyObject *attr;
+ ImBuf *ibuf= BKE_image_get_ibuf(self->image, NULL);
+ char *pixel; /* image data */
+ int index; /* offset into image data */
+ int x = 0;
+ int y = 0;
+ int pixel_size = 4; /* each pixel is 4 x 8-bits packed in unsigned int */
+ int i;
+
+ if( !PyArg_ParseTuple( args, "ii", &x, &y ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected 2 integers" );
+
+ if( !ibuf || !ibuf->rect ) /* loading didn't work */
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't load image data in Blender" );
+
+ if( ibuf->type == 1 ) /* bitplane image */
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "unsupported bitplane image format" );
+
+ if( x > ( ibuf->x - 1 )
+ || y > ( ibuf->y - 1 )
+ || x < ibuf->xorig || y < ibuf->yorig )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "x or y is out of range" );
+
+ /*
+ assumption: from looking at source, skipx is often not set,
+ so we calc ourselves
+ */
+
+ attr = PyList_New(4);
+
+ if (!attr)
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't allocate memory for color list" );
+
+ index = ( x + y * ibuf->x ) * pixel_size;
+
+ pixel = ( char * ) ibuf->rect;
+ for (i=0; i<4; i++) {
+ PyList_SetItem( attr, i, PyFloat_FromDouble( ( ( double ) pixel[index+i] ) / 255.0 ));
+ }
+ return attr;
+}
+
+
+/**
+ * getPixelI( x, y )
+ * returns integer list of pixel colors in rgba order.
+ * returned values are ints normalized to 0-255.
+ * blender images are all 4x8 bit at the moment apr-2005
+ */
+
+static PyObject *Image_getPixelI( BPy_Image * self, PyObject * args )
+{
+ PyObject *attr = PyList_New(4);
+ ImBuf *ibuf= BKE_image_get_ibuf(self->image, NULL);
+ char *pixel; /* image data */
+ int index; /* offset into image data */
+ int x = 0;
+ int y = 0;
+ int pixel_size = 4; /* each pixel is 4 x 8-bits packed in unsigned int */
+ int i;
+
+ if (!attr)
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't allocate memory for color list" );
+
+ if( !PyArg_ParseTuple( args, "ii", &x, &y ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected 2 integers" );
+
+ if( !ibuf || !ibuf->rect ) /* didn't work */
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't load image data in Blender" );
+
+ if( ibuf->type == 1 ) /* bitplane image */
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "unsupported bitplane image format" );
+
+ if( x > ( ibuf->x - 1 )
+ || y > ( ibuf->y - 1 )
+ || x < ibuf->xorig || y < ibuf->yorig )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "x or y is out of range" );
+
+ /*
+ assumption: from looking at source, skipx is often not set,
+ so we calc ourselves
+ */
+
+ index = ( x + y * ibuf->x ) * pixel_size;
+ pixel = ( char * ) ibuf->rect;
+
+ for (i=0; i<4; i++) {
+ PyList_SetItem( attr, i, PyInt_FromLong( pixel[index+i] ));
+ }
+ return attr;
+}
+
+
+/* set pixel as floats */
+
+static PyObject *Image_setPixelF( BPy_Image * self, PyObject * args )
+{
+ ImBuf *ibuf= BKE_image_get_ibuf(self->image, NULL);
+ char *pixel; /* image data */
+ int index; /* offset into image data */
+ int x = 0;
+ int y = 0;
+ int a = 0;
+ int pixel_size = 4; /* each pixel is 4 x 8-bits packed in unsigned int */
+ float p[4];
+
+ if( !PyArg_ParseTuple
+ ( args, "ii(ffff)", &x, &y, &p[0], &p[1], &p[2], &p[3] ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected 2 integers and an array of 4 floats" );
+
+ if( !ibuf || !ibuf->rect ) /* didn't work */
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't load image data in Blender" );
+
+ if( ibuf->type == 1 ) /* bitplane image */
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "unsupported bitplane image format" );
+
+ if( x > ( ibuf->x - 1 )
+ || y > ( ibuf->y - 1 )
+ || x < ibuf->xorig || y < ibuf->yorig )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "x or y is out of ruange" );
+
+ for( a = 0; a < 4; a++ ) {
+ if( p[a] > 1.0 || p[a] < 0.0 )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "r, g, b, or a is out of range" );
+ }
+
+
+ /*
+ assumption: from looking at source, skipx is often not set,
+ so we calc ourselves
+ */
+
+ index = ( x + y * ibuf->x ) * pixel_size;
+
+ pixel = ( char * ) ibuf->rect;
+
+ pixel[index] = ( char ) ( p[0] * 255.0 );
+ pixel[index + 1] = ( char ) ( p[1] * 255.0 );
+ pixel[index + 2] = ( char ) ( p[2] * 255.0 );
+ pixel[index + 3] = ( char ) ( p[3] * 255.0 );
+
+ ibuf->userflags |= IB_BITMAPDIRTY;
+ Py_RETURN_NONE;
+}
+
+
+/* set pixel as ints */
+
+static PyObject *Image_setPixelI( BPy_Image * self, PyObject * args )
+{
+ ImBuf *ibuf= BKE_image_get_ibuf(self->image, NULL);
+ char *pixel; /* image data */
+ int index; /* offset into image data */
+ int x = 0;
+ int y = 0;
+ int a = 0;
+ int pixel_size = 4; /* each pixel is 4 x 8-bits packed in unsigned int */
+ int p[4];
+
+ if( !PyArg_ParseTuple
+ ( args, "ii(iiii)", &x, &y, &p[0], &p[1], &p[2], &p[3] ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected 2 integers and an list of 4 ints" );
+
+ if( !ibuf || !ibuf->rect ) /* didn't work */
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't load image data in Blender" );
+
+ if( ibuf->type == 1 ) /* bitplane image */
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "unsupported bitplane image format" );
+
+ if( x > ( ibuf->x - 1 )
+ || y > ( ibuf->y - 1 )
+ || x < ibuf->xorig || y < ibuf->yorig )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "x or y is out of range" );
+
+ for( a = 0; a < 4; a++ ) {
+ if( p[a] > 255 || p[a] < 0 )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "r, g, b, or a is out of range" );
+ }
+
+ /*
+ assumption: from looking at source, skipx is often not set,
+ so we calc ourselves
+ */
+
+ index = ( x + y * ibuf->x ) * pixel_size;
+
+ pixel = ( char * ) ibuf->rect;
+
+ pixel[index] = ( char ) p[0];
+ pixel[index + 1] = ( char ) p[1];
+ pixel[index + 2] = ( char ) p[2];
+ pixel[index + 3] = ( char ) p[3];
+
+ ibuf->userflags |= IB_BITMAPDIRTY;
+ Py_RETURN_NONE;
+}
+
+
+/* get max extent of image */
+
+static PyObject *Image_getMaxXY( BPy_Image * self )
+{
+ ImBuf *ibuf= BKE_image_get_ibuf(self->image, NULL);
+
+ if( !ibuf || !ibuf->rect ) /* didn't work */
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't load image data in Blender" );
+
+ return Py_BuildValue( "[i,i]", ibuf->x, ibuf->y );
+}
+
+
+/* get min extent of image */
+
+static PyObject *Image_getMinXY( BPy_Image * self )
+{
+ ImBuf *ibuf= BKE_image_get_ibuf(self->image, NULL);
+
+ if( !ibuf || !ibuf->rect ) /* didn't work */
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't load image data in Blender" );
+
+ return Py_BuildValue( "[i,i]", ibuf->xorig, ibuf->yorig );
+}
+
+/* unpack image */
+
+static PyObject *Image_unpack( BPy_Image * self, PyObject * value )
+{
+ Image *image = self->image;
+ int mode = (int)PyInt_AsLong(value);
+
+ /*get the absolute path */
+ if( mode==-1 )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected 1 integer from Blender.UnpackModes" );
+
+ if (image->packedfile==NULL)
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "image not packed" );
+
+ if (unpackImage(image, mode) == RET_ERROR)
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "error unpacking image" );
+ Py_RETURN_NONE;
+}
+
+/* pack image */
+
+static PyObject *Image_pack( BPy_Image * self )
+{
+ Image *image = self->image;
+ ImBuf *ibuf = BKE_image_get_ibuf(image, NULL);
+
+ if( !ibuf || !ibuf->rect ) /* didn't work */
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't load image data in Blender" );
+
+ if (image->packedfile ) { /* RePack? */
+ if (ibuf->userflags & IB_BITMAPDIRTY)
+ BKE_image_memorypack(image);
+ } else { /* Pack for the first time */
+ if (ibuf && (ibuf->userflags & IB_BITMAPDIRTY))
+ BKE_image_memorypack(image);
+ else
+ image->packedfile = newPackedFile(image->name);
+ }
+ Py_RETURN_NONE;
+}
+
+
+static PyObject *Image_makeCurrent( BPy_Image * self )
+{
+#if 0 /* add back in when bpy becomes "official" */
+ static char warning = 1;
+ if( warning ) {
+ printf("image.makeCurrent() deprecated!\n\t use 'bpy.images.active = image instead'\n");
+ --warning;
+ }
+#endif
+
+ if (!G.sima)
+ Py_RETURN_FALSE;
+
+ G.sima->image= self->image;
+ Py_RETURN_TRUE;
+}
+
+
+/* save image to file */
+
+static PyObject *Image_save( BPy_Image * self )
+{
+ ImBuf *ibuf= BKE_image_get_ibuf(self->image, NULL);
+
+ if(!ibuf)
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "could not save image (no image buffer)" );
+
+ /* If this is a packed file, write using writePackedFile
+ * because IMB_saveiff wont save to a file */
+ if (self->image->packedfile) {
+ if (writePackedFile(self->image->name, self->image->packedfile, 0) != RET_OK) {
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "could not save image (writing image from packedfile failed)" );
+ }
+ } else if (!IMB_saveiff( ibuf, self->image->name, ibuf->flags))
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "could not save image (writing the image buffer failed)" );
+
+ Py_RETURN_NONE; /* normal return, image saved */
+}
+
+static PyObject *M_Image_SourceDict( void )
+{
+ PyObject *Dict = PyConstant_New( );
+ if( Dict ) {
+ BPy_constant *d = ( BPy_constant * ) Dict;
+ PyConstant_Insert(d, "STILL", PyInt_FromLong(IMA_SRC_FILE));
+ PyConstant_Insert(d, "MOVIE", PyInt_FromLong(IMA_SRC_MOVIE));
+ PyConstant_Insert(d, "SEQUENCE", PyInt_FromLong(IMA_SRC_SEQUENCE));
+ PyConstant_Insert(d, "GENERATED", PyInt_FromLong(IMA_SRC_GENERATED));
+ }
+ return Dict;
+}
+
+/*****************************************************************************/
+/* Function: Image_Init */
+/*****************************************************************************/
+PyObject *Image_Init( void )
+{
+ PyObject *submodule;
+ PyObject *Sources = M_Image_SourceDict( );
+
+ if( PyType_Ready( &Image_Type ) < 0 )
+ return NULL;
+
+ submodule =
+ Py_InitModule3( "Blender.Image", M_Image_methods,
+ M_Image_doc );
+
+ if( Sources )
+ PyModule_AddObject( submodule, "Sources", Sources );
+
+ return submodule;
+}
+
+/*****************************************************************************/
+/* Python Image_Type callback function prototypes: */
+/*****************************************************************************/
+static int Image_compare( BPy_Image * a, BPy_Image * b );
+static PyObject *Image_repr( BPy_Image * self );
+
+/*****************************************************************************/
+/* Function: Image_CreatePyObject */
+/* Description: This function will create a new BPy_Image from an existing */
+/* Blender image structure. */
+/*****************************************************************************/
+PyObject *Image_CreatePyObject( Image * image )
+{
+ BPy_Image *py_img;
+ py_img = ( BPy_Image * ) PyObject_NEW( BPy_Image, &Image_Type );
+
+ if( !py_img )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create BPy_Image object" );
+
+ py_img->image = image;
+ return ( PyObject * ) py_img;
+}
+
+/*****************************************************************************/
+/* Function: Image_FromPyObject */
+/* Description: Returns the Blender Image associated with this object */
+/*****************************************************************************/
+Image *Image_FromPyObject( PyObject * pyobj )
+{
+ return ( ( BPy_Image * ) pyobj )->image;
+}
+
+static PyObject *Image_getFilename( BPy_Image * self )
+{
+ return PyString_FromString( self->image->name );
+}
+
+static PyObject *Image_getSize( BPy_Image * self )
+{
+ ImBuf *ibuf= BKE_image_get_ibuf(self->image, NULL);
+ PyObject *attr;
+
+ if( !ibuf ) /* didn't work */
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't load image data in Blender" );
+
+ attr = PyList_New(2);
+
+ if( !attr )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't get Image.size attribute" );
+
+ PyList_SetItem( attr, 0, PyInt_FromLong(ibuf->x));
+ PyList_SetItem( attr, 1, PyInt_FromLong(ibuf->y));
+ return attr;
+}
+
+static PyObject *Image_getDepth( BPy_Image * self )
+{
+ ImBuf *ibuf= BKE_image_get_ibuf(self->image, NULL);
+
+ if( !ibuf ) /* didn't work */
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't load image data in Blender" );
+
+ return PyInt_FromLong( (long)ibuf->depth );
+}
+
+
+static PyObject *Image_getXRep( BPy_Image * self )
+{
+ return PyInt_FromLong( self->image->xrep );
+}
+
+static PyObject *Image_getYRep( BPy_Image * self )
+{
+ return PyInt_FromLong( self->image->yrep );
+}
+
+static PyObject *Image_getStart( BPy_Image * self )
+{
+ return PyInt_FromLong( self->image->twsta );
+}
+
+static PyObject *Image_getEnd( BPy_Image * self )
+{
+ return PyInt_FromLong( self->image->twend );
+}
+
+static PyObject *Image_getSpeed( BPy_Image * self )
+{
+ return PyInt_FromLong( self->image->animspeed );
+}
+
+static PyObject *Image_getBindCode( BPy_Image * self )
+{
+ return PyLong_FromUnsignedLong( self->image->bindcode );
+}
+
+static PyObject *Image_reload( BPy_Image * self )
+{
+ Image *image = self->image;
+
+ BKE_image_signal(image, NULL, IMA_SIGNAL_RELOAD);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Image_glFree( BPy_Image * self )
+{
+ Image *image = self->image;
+
+ free_realtime_image( image );
+ /* remove the nocollect flag, image is available for garbage collection again */
+ image->flag &= ~IMA_NOCOLLECT;
+ Py_RETURN_NONE;
+}
+
+static PyObject *Image_glLoad( BPy_Image * self )
+{
+ Image *image = self->image;
+ unsigned int *bind = &image->bindcode;
+
+ if( *bind == 0 ) {
+ ImBuf *ibuf= BKE_image_get_ibuf(self->image, NULL);
+
+ if( !ibuf ) /* didn't work */
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't load image data in Blender" );
+
+ glGenTextures( 1, ( GLuint * ) bind );
+ glBindTexture( GL_TEXTURE_2D, *bind );
+
+ gluBuild2DMipmaps( GL_TEXTURE_2D, GL_RGBA, ibuf->x,
+ ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE,
+ ibuf->rect );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+ GL_LINEAR_MIPMAP_NEAREST );
+ glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
+ GL_LINEAR );
+ glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
+
+ glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, ibuf->x,
+ ibuf->y, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ ibuf->rect );
+
+ /* raise the nocollect flag,
+ image is not available for garbage collection
+ (python GL might use it directly)
+ */
+ image->flag |= IMA_NOCOLLECT;
+ }
+
+ return PyLong_FromUnsignedLong( image->bindcode );
+}
+
+static int Image_setFilename( BPy_Image * self, PyObject * value )
+{
+ char *name;
+
+ name = PyString_AsString(value);
+
+ if( !name )
+ return ( EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a string argument" ) );
+
+ /* max len is FILE_MAXDIR == 160, FILE_MAXFILE == 80 chars like done in DNA_image_types.h */
+ if( strlen(name) >= FILE_MAXDIR + FILE_MAXFILE )
+ return ( EXPP_ReturnIntError( PyExc_TypeError,
+ "string argument is limited to 240 chars at most" ) );
+
+ strcpy( self->image->name, name );
+ return 0;
+}
+
+static PyObject *Image_oldsetFilename( BPy_Image * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Image_setFilename );
+}
+
+static PyObject *Image_setXRep( BPy_Image * self, PyObject * value )
+{
+ short param = (short)PyInt_AsLong(value);
+
+ if( param !=-1 && param >= EXPP_IMAGE_REP_MIN && param <= EXPP_IMAGE_REP_MAX)
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected int argument in [1,16]" ) );
+
+ self->image->xrep = param;
+ Py_RETURN_NONE;
+}
+
+static PyObject *Image_setYRep( BPy_Image * self, PyObject * value )
+{
+ short param = (short)PyInt_AsLong(value);
+
+ if( param !=-1 && param >= EXPP_IMAGE_REP_MIN && param <= EXPP_IMAGE_REP_MAX)
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected int argument in [1,16]" ) );
+
+ self->image->yrep = param;
+ Py_RETURN_NONE;
+}
+
+
+static PyObject *Image_setStart( BPy_Image * self, PyObject * args )
+{
+ short value;
+
+ if( !PyArg_ParseTuple( args, "h", &value ) )
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected int argument in [0,128]" ) );
+
+ if( value >= 0 && value <= 128 )
+ self->image->twsta = value;
+ else
+ return ( EXPP_ReturnPyObjError( PyExc_ValueError,
+ "expected int argument in [0,128]" ) );
+
+ Py_RETURN_NONE;
+}
+
+
+static PyObject *Image_setEnd( BPy_Image * self, PyObject * args )
+{
+ short value;
+
+ if( !PyArg_ParseTuple( args, "h", &value ) )
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected int argument in [0,128]" ) );
+
+ if( value >= 0 && value <= 128 )
+ self->image->twend = value;
+ else
+ return ( EXPP_ReturnPyObjError( PyExc_ValueError,
+ "expected int argument in [0,128]" ) );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Image_setSpeed( BPy_Image * self, PyObject * args )
+{
+ short value;
+
+ if( !PyArg_ParseTuple( args, "h", &value ) )
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected int argument in [0,128]" ) );
+
+ if( value >= 1 && value <= 100 )
+ self->image->animspeed = value;
+ else
+ return ( EXPP_ReturnPyObjError( PyExc_ValueError,
+ "expected int argument in [0,128]" ) );
+
+ Py_RETURN_NONE;
+}
+
+
+/*****************************************************************************/
+/* Function: Image_compare */
+/* Description: This is a callback function for the BPy_Image type. It */
+/* compares two Image_Type objects. Only the "==" and "!=" */
+/* comparisons are meaninful. Returns 0 for equality and -1 if */
+/* they don't point to the same Blender Image struct. */
+/* In Python it becomes 1 if they are equal, 0 otherwise. */
+/*****************************************************************************/
+static int Image_compare( BPy_Image * a, BPy_Image * b )
+{
+ return ( a->image == b->image ) ? 0 : -1;
+}
+
+/*****************************************************************************/
+/* Function: Image_repr */
+/* Description: This is a callback function for the BPy_Image type. It */
+/* builds a meaninful string to represent image objects. */
+/*****************************************************************************/
+static PyObject *Image_repr( BPy_Image * self )
+{
+ return PyString_FromFormat( "[Image \"%s\"]",
+ self->image->id.name + 2 );
+}
+
+static PyObject *Image_getPacked(BPy_Image *self, void *closure)
+{
+ if (self->image->packedfile)
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+}
+
+static PyObject *Image_hasData(BPy_Image *self, void *closure)
+{
+ if (self->image->ibufs.first)
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+}
+
+static PyObject *Image_getFlag(BPy_Image *self, void *flag)
+{
+ if (self->image->flag & (int)flag)
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+
+}
+
+static PyObject *Image_getFlagTpage(BPy_Image *self, void *flag)
+{
+ if (self->image->tpageflag & (int)flag)
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+
+}
+
+static int Image_setSource( BPy_Image *self, PyObject *args)
+{
+ PyObject* integer = PyNumber_Int( args );
+ short value;
+
+ if( !integer )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected integer argument" );
+
+ value = ( short )PyInt_AS_LONG( integer );
+ Py_DECREF( integer );
+
+ if( value < IMA_SRC_FILE || value > IMA_SRC_GENERATED )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "expected integer argument in range 1-4" );
+
+ self->image->source = value;
+ return 0;
+}
+
+static int Image_setFlag(BPy_Image *self, PyObject *value, void *flag)
+{
+ int param = PyObject_IsTrue( value );
+ if( param == -1 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected True/False or 0/1" );
+
+ if ( param )
+ self->image->flag |= (int)flag;
+ else
+ self->image->flag &= ~(int)flag;
+ return 0;
+}
+
+static int Image_setFlagTpage(BPy_Image *self, PyObject *value, void *flag)
+{
+ int param = PyObject_IsTrue( value );
+ if( param == -1 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected True/False or 0/1" );
+
+ if ( param )
+ self->image->tpageflag |= (int)flag;
+ else
+ self->image->tpageflag &= ~(int)flag;
+ return 0;
+}
+
+/*
+ * get integer attributes
+ */
+static PyObject *getIntAttr( BPy_Image *self, void *type )
+{
+ int param;
+ struct Image *image = self->image;
+
+ switch( (int)type ) {
+ case EXPP_IMAGE_ATTR_XREP:
+ param = image->xrep;
+ break;
+ case EXPP_IMAGE_ATTR_YREP:
+ param = image->xrep;
+ break;
+ case EXPP_IMAGE_ATTR_START:
+ param = image->twsta;
+ break;
+ case EXPP_IMAGE_ATTR_END:
+ param = image->twend;
+ break;
+ case EXPP_IMAGE_ATTR_SPEED:
+ param = image->animspeed;
+ break;
+ case EXPP_IMAGE_ATTR_BINDCODE:
+ param = image->bindcode;
+ break;
+ case EXPP_IMAGE_ATTR_SOURCE:
+ param = image->source;
+ break;
+ default:
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "undefined type in getIntAttr" );
+ }
+
+ return PyInt_FromLong( param );
+}
+
+
+/*
+ * set integer attributes which require clamping
+ */
+
+static int setIntAttrClamp( BPy_Image *self, PyObject *value, void *type )
+{
+ void *param;
+ struct Image *image = self->image;
+ int min, max, size;
+
+ switch( (int)type ) {
+ case EXPP_IMAGE_ATTR_XREP:
+ min = EXPP_IMAGE_REP_MIN;
+ max = EXPP_IMAGE_REP_MAX;
+ size = 'h';
+ param = (void *)&image->xrep;
+ break;
+ case EXPP_IMAGE_ATTR_YREP:
+ min = EXPP_IMAGE_REP_MIN;
+ max = EXPP_IMAGE_REP_MAX;
+ size = 'h';
+ param = (void *)&image->yrep;
+ break;
+ case EXPP_IMAGE_ATTR_START:
+ min = 0;
+ max = 128;
+ size = 'h';
+ param = (void *)&image->twsta;
+ break;
+ case EXPP_IMAGE_ATTR_END:
+ min = 0;
+ max = 128;
+ size = 'h';
+ param = (void *)&image->twend;
+ break;
+ case EXPP_IMAGE_ATTR_SPEED:
+ min = 0;
+ max = 100;
+ size = 'h';
+ param = (void *)&image->animspeed;
+ break;
+ default:
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "undefined type in setIntAttrClamp");
+ }
+ return EXPP_setIValueClamped( value, param, min, max, size );
+}
+
+/*****************************************************************************/
+/* Python attributes get/set structure: */
+/*****************************************************************************/
+static PyGetSetDef BPy_Image_getseters[] = {
+ GENERIC_LIB_GETSETATTR,
+ {"filename", (getter)Image_getFilename, (setter)Image_setFilename,
+ "image path", NULL},
+ /* readonly */
+ {"depth", (getter)Image_getDepth, (setter)NULL,
+ "image depth", NULL},
+ {"size", (getter)Image_getSize, (setter)NULL,
+ "image size", NULL},
+ {"packed", (getter)Image_getPacked, (setter)NULL,
+ "image packed state", NULL },
+ {"has_data", (getter)Image_hasData, (setter)NULL,
+ "is image data loaded", NULL },
+ /* ints */
+ {"xrep", (getter)getIntAttr, (setter)setIntAttrClamp,
+ "image xrep", (void *)EXPP_IMAGE_ATTR_XREP },
+ {"yrep", (getter)getIntAttr, (setter)setIntAttrClamp,
+ "image yrep", (void *)EXPP_IMAGE_ATTR_YREP },
+ {"start", (getter)getIntAttr, (setter)setIntAttrClamp,
+ "image start frame", (void *)EXPP_IMAGE_ATTR_START },
+ {"end", (getter)getIntAttr, (setter)setIntAttrClamp,
+ "image end frame", (void *)EXPP_IMAGE_ATTR_END },
+ {"speed", (getter)getIntAttr, (setter)setIntAttrClamp,
+ "image end frame", (void *)EXPP_IMAGE_ATTR_SPEED },
+ {"bindcode", (getter)getIntAttr, (setter)NULL,
+ "openGL bindcode", (void *)EXPP_IMAGE_ATTR_BINDCODE },
+ {"source", (getter)getIntAttr, (setter)Image_setSource,
+ "image source type", (void *)EXPP_IMAGE_ATTR_SOURCE },
+ /* flags */
+ {"fields", (getter)Image_getFlag, (setter)Image_setFlag,
+ "image fields toggle", (void *)IMA_FIELDS },
+ {"fields_odd", (getter)Image_getFlag, (setter)Image_setFlag,
+ "image odd fields toggle", (void *)IMA_STD_FIELD },
+ {"antialias", (getter)Image_getFlag, (setter)Image_setFlag,
+ "image antialiasing toggle", (void *)IMA_ANTIALI },
+ {"reflect", (getter)Image_getFlag, (setter)Image_setFlag,
+ "image reflect toggle", (void *)IMA_REFLECT },
+ {"clampX", (getter)Image_getFlagTpage, (setter)Image_setFlagTpage,
+ "disable tiling on the X axis", (void *)IMA_CLAMP_U },
+ {"clampY", (getter)Image_getFlagTpage, (setter)Image_setFlagTpage,
+ "disable tiling on the Y axis", (void *)IMA_CLAMP_V },
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+
+/*****************************************************************************/
+/* Python Image_Type structure definition: */
+/*****************************************************************************/
+PyTypeObject Image_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required macro. ( no comma needed ) */
+ 0, /* ob_size */
+ "Blender Image", /* tp_name */
+ sizeof( BPy_Image ), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ /* methods */
+ NULL, /* tp_dealloc */
+ 0, /* tp_print */
+ NULL, /* tp_getattr */
+ NULL, /* tp_setattr */
+ ( cmpfunc ) Image_compare, /* tp_compare */
+ ( reprfunc ) Image_repr, /* tp_repr */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ ( hashfunc ) GenericLib_hash, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_Image_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ BPy_Image_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
diff --git a/source/blender/python/api2_2x/Image.h b/source/blender/python/api2_2x/Image.h
new file mode 100644
index 00000000000..a36627cb236
--- /dev/null
+++ b/source/blender/python/api2_2x/Image.h
@@ -0,0 +1,60 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano, Alex Mole
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_IMAGE_H
+#define EXPP_IMAGE_H
+
+#include <Python.h>
+#include "DNA_image_types.h"
+
+
+/*****************************************************************************/
+/* Python BPy_Image structure definition */
+/*****************************************************************************/
+typedef struct {
+ PyObject_HEAD
+ Image * image; /* libdata must be second */
+
+} BPy_Image;
+
+extern PyTypeObject Image_Type; /* The Image PyType Object */
+
+#define BPy_Image_Check(v) ((v)->ob_type == &Image_Type) /*for type checking */
+
+/*****************************************************************************/
+/* Module Blender.Image - public functions */
+/*****************************************************************************/
+PyObject *Image_Init( void );
+PyObject *Image_CreatePyObject( Image * image );
+Image *Image_FromPyObject( PyObject * pyobj );
+
+#endif /* EXPP_IMAGE_H */
diff --git a/source/blender/python/api2_2x/Ipo.c b/source/blender/python/api2_2x/Ipo.c
new file mode 100644
index 00000000000..9b2fd082bee
--- /dev/null
+++ b/source/blender/python/api2_2x/Ipo.c
@@ -0,0 +1,1842 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Jacques Guignot RIP 2005, Nathan Letwory,
+ * Stephen Swaney, Ken Hughes
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "Ipo.h" /*This must come first*/
+
+#include "BKE_main.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_object.h"
+#include "BKE_ipo.h"
+#include "BLI_blenlib.h"
+#include "BIF_space.h"
+#include "BSE_editipo.h"
+#include "MEM_guardedalloc.h"
+#include "DNA_key_types.h"
+#include "mydevice.h"
+#include "Ipocurve.h"
+#include "gen_utils.h"
+#include "gen_library.h"
+
+extern int ob_ar[];
+extern int la_ar[];
+extern int ma_ar[];
+extern int ac_ar[];
+extern int cam_ar[];
+extern int co_ar[];
+extern int cu_ar[];
+extern int seq_ar[];
+extern int te_ar[];
+extern int wo_ar[];
+
+PyObject *submodule;
+
+/*****************************************************************************/
+/* Python API function prototypes for the Ipo module. */
+/*****************************************************************************/
+static PyObject *M_Ipo_New( PyObject * self, PyObject * args );
+static PyObject *M_Ipo_Get( PyObject * self, PyObject * args );
+static PyObject *M_Ipo_Recalc( PyObject * self, PyObject * args );
+
+/*****************************************************************************/
+/* The following string definitions are used for documentation strings. */
+/* In Python these will be written to the console when doing a */
+/* Blender.Ipo.__doc__ */
+/*****************************************************************************/
+char M_Ipo_doc[] = "";
+char M_Ipo_New_doc[] = "";
+char M_Ipo_Get_doc[] = "";
+
+/*****************************************************************************/
+/* Python method structure definition for Blender.Ipo module: */
+/*****************************************************************************/
+
+struct PyMethodDef M_Ipo_methods[] = {
+ {"New", ( PyCFunction ) M_Ipo_New, METH_VARARGS | METH_KEYWORDS,
+ M_Ipo_New_doc},
+ {"Get", M_Ipo_Get, METH_VARARGS, M_Ipo_Get_doc},
+ {"get", M_Ipo_Get, METH_VARARGS, M_Ipo_Get_doc},
+ {"Recalc", M_Ipo_Recalc, METH_O, M_Ipo_Get_doc},
+ {NULL, NULL, 0, NULL}
+};
+
+/*****************************************************************************/
+/* Python BPy_Ipo methods declarations: */
+/*****************************************************************************/
+static PyObject *Ipo_getBlocktype( BPy_Ipo * self );
+static PyObject *Ipo_oldsetBlocktype( BPy_Ipo * self, PyObject * args );
+static int Ipo_setBlocktype( BPy_Ipo * self, PyObject * args );
+static PyObject *Ipo_getRctf( BPy_Ipo * self );
+static PyObject *Ipo_oldsetRctf( BPy_Ipo * self, PyObject * args );
+static int Ipo_setRctf( BPy_Ipo * self, PyObject * args );
+
+static PyObject *Ipo_getCurve( BPy_Ipo * self, PyObject * args );
+static PyObject *Ipo_getCurves( BPy_Ipo * self );
+static PyObject *Ipo_getCurveNames( BPy_Ipo * self );
+static PyObject *Ipo_addCurve( BPy_Ipo * self, PyObject * value );
+static PyObject *Ipo_delCurve( BPy_Ipo * self, PyObject * args );
+static PyObject *Ipo_getNcurves( BPy_Ipo * self );
+static PyObject *Ipo_getNBezPoints( BPy_Ipo * self, PyObject * args );
+static PyObject *Ipo_DeleteBezPoints( BPy_Ipo * self, PyObject * args );
+static PyObject *Ipo_getCurveBP( BPy_Ipo * self, PyObject * args );
+static PyObject *Ipo_getCurvecurval( BPy_Ipo * self, PyObject * args );
+static PyObject *Ipo_EvaluateCurveOn( BPy_Ipo * self, PyObject * args );
+
+static PyObject *Ipo_setCurveBeztriple( BPy_Ipo * self, PyObject * args );
+static PyObject *Ipo_getCurveBeztriple( BPy_Ipo * self, PyObject * args );
+
+static PyObject *Ipo_getChannel( BPy_Ipo * self );
+static PyObject *Ipo_copy( BPy_Ipo * self );
+static int Ipo_setChannel( BPy_Ipo * self, PyObject * args );
+
+static int Ipo_length( BPy_Ipo * inst );
+static PyObject *Ipo_getIpoCurveByName( BPy_Ipo * self, PyObject * key );
+static int Ipo_setIpoCurveByName( BPy_Ipo * self, PyObject * key,
+ PyObject * value );
+static int Ipo_contains( BPy_Ipo * self, PyObject * key );
+
+/*****************************************************************************/
+/* Python BPy_Ipo methods table: */
+/*****************************************************************************/
+static PyMethodDef BPy_Ipo_methods[] = {
+ /* name, method, flags, doc */
+ {"getName", ( PyCFunction ) GenericLib_getName, METH_NOARGS,
+ "() - Return Ipo Data name"},
+ {"setName", ( PyCFunction ) GenericLib_setName_with_method, METH_VARARGS,
+ "(str) - Change Ipo Data name"},
+ {"getBlocktype", ( PyCFunction ) Ipo_getBlocktype, METH_NOARGS,
+ "() - Return Ipo blocktype"},
+ {"setBlocktype", ( PyCFunction ) Ipo_oldsetBlocktype, METH_VARARGS,
+ "(str) - Change Ipo blocktype"},
+ {"getRctf", ( PyCFunction ) Ipo_getRctf, METH_NOARGS,
+ "() - Return Ipo rctf"},
+ {"setRctf", ( PyCFunction ) Ipo_oldsetRctf, METH_VARARGS,
+ "(flt,flt,flt,flt) - Change Ipo rctf"},
+ {"addCurve", ( PyCFunction ) Ipo_addCurve, METH_O,
+ "() - Add a curve to Ipo"},
+ {"delCurve", ( PyCFunction ) Ipo_delCurve, METH_VARARGS,
+ "(str) - Delete curve from Ipo"},
+ {"getNcurves", ( PyCFunction ) Ipo_getNcurves, METH_NOARGS,
+ "() - Return number of Ipo curves"},
+ {"getCurves", ( PyCFunction ) Ipo_getCurves, METH_NOARGS,
+ "() - Return list of all defined Ipo curves"},
+ {"getCurve", ( PyCFunction ) Ipo_getCurve, METH_VARARGS,
+ "(str|int) - Returns specified Ipo curve"},
+ {"getNBezPoints", ( PyCFunction ) Ipo_getNBezPoints, METH_VARARGS,
+ "(int) - Return number of Bez points on an Ipo curve"},
+ {"delBezPoint", ( PyCFunction ) Ipo_DeleteBezPoints, METH_VARARGS,
+ "(int) - deprecated: use ipocurve.delBezier()"},
+ {"getCurveBP", ( PyCFunction ) Ipo_getCurveBP, METH_VARARGS,
+ "() - unsupported"},
+ {"EvaluateCurveOn", ( PyCFunction ) Ipo_EvaluateCurveOn, METH_VARARGS,
+ "(int,flt) - deprecated: see ipocurve.evaluate()"},
+ {"getCurveCurval", ( PyCFunction ) Ipo_getCurvecurval, METH_VARARGS,
+ "(int) - deprecated: see ipocurve.evaluate()"},
+ {"getCurveBeztriple", ( PyCFunction ) Ipo_getCurveBeztriple, METH_VARARGS,
+ "(int,int) - deprecated: see ipocurve.bezierPoints[]"},
+ {"setCurveBeztriple", ( PyCFunction ) Ipo_setCurveBeztriple, METH_VARARGS,
+ "(int,int,list) - set a BezTriple"},
+
+ {"__copy__", ( PyCFunction ) Ipo_copy, METH_NOARGS,
+ "() - copy the ipo"},
+ {"copy", ( PyCFunction ) Ipo_copy, METH_NOARGS,
+ "() - copy the ipo"},
+
+ {NULL, NULL, 0, NULL}
+};
+
+/*****************************************************************************/
+/* Python BPy_Ipo attributes get/set structure: */
+/*****************************************************************************/
+static PyGetSetDef BPy_Ipo_getseters[] = {
+ GENERIC_LIB_GETSETATTR,
+ {"curves",
+ (getter)Ipo_getCurves, (setter)NULL,
+ "Ipo curves",
+ NULL},
+ {"curveConsts",
+ (getter)Ipo_getCurveNames, (setter)NULL,
+ "Ipo curve constants (values depend on Ipo type)",
+ NULL},
+ {"channel",
+ (getter)Ipo_getChannel, (setter)Ipo_setChannel,
+ "Ipo texture channel (world, lamp, material Ipos only)",
+ NULL},
+
+ {"blocktype",
+ (getter)Ipo_getBlocktype, (setter)NULL,
+ "Ipo block type",
+ NULL},
+ {"rctf",
+ (getter)Ipo_getRctf, (setter)Ipo_setRctf,
+ "Ipo type",
+ NULL},
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+/*****************************************************************************/
+/* Python Ipo_Type Mapping Methods table: */
+/*****************************************************************************/
+static PyMappingMethods Ipo_as_mapping = {
+ ( inquiry ) Ipo_length, /* mp_length */
+ ( binaryfunc ) Ipo_getIpoCurveByName, /* mp_subscript */
+ ( objobjargproc ) Ipo_setIpoCurveByName, /* mp_ass_subscript */
+};
+
+static PySequenceMethods Ipo_as_sequence = {
+ ( inquiry ) 0, /* sq_length */
+ ( binaryfunc ) 0, /* sq_concat */
+ ( intargfunc ) 0, /* sq_repeat */
+ ( intargfunc ) 0, /* sq_item */
+ ( intintargfunc ) 0, /* sq_slice */
+ ( intobjargproc ) 0, /* sq_ass_item */
+ ( intintobjargproc ) 0, /* sq_ass_slice */
+ ( objobjproc ) Ipo_contains, /* sq_contains */
+ ( binaryfunc ) 0, /* sq_inplace_concat */
+ ( intargfunc ) 0, /* sq_inplace_repeat */
+};
+
+/*****************************************************************************/
+/* Python Ipo_Type callback function prototypes: */
+/*****************************************************************************/
+/*static int IpoPrint (BPy_Ipo *self, FILE *fp, int flags);*/
+static int Ipo_compare( BPy_Ipo * a, BPy_Ipo * b );
+static PyObject *Ipo_repr( BPy_Ipo * self );
+static PyObject *Ipo_getIter( BPy_Ipo * self );
+static PyObject *Ipo_nextIter( BPy_Ipo * self );
+
+/* #define CURVEATTRS */ /* uncomment to enable curves as Ipo attributes */
+
+#ifdef CURVEATTRS
+static PyGetSetDef BPy_Ipocurve_getseter = {
+ "noname",
+ (getter)NULL, (setter)NULL,
+ "Ipo curve name",
+ NULL
+};
+
+void generate_curveattrs( PyObject* dict, int blocktype )
+{
+ typedef char * (*namefunc)(int, ... );
+ namefunc lookup_name;
+ int size;
+ int *vals = NULL;
+ char name[32];
+ PyObject*desc;
+
+ switch ( blocktype ) {
+ case ID_OB:
+ lookup_name = (namefunc)getname_ob_ei;
+ vals = ob_ar;
+ size = OB_TOTIPO;
+ break;
+ case ID_MA:
+ lookup_name = (namefunc)getname_mat_ei;
+ vals = ma_ar;
+ size = MA_TOTIPO;
+ break;
+ case ID_CA:
+ lookup_name = (namefunc)getname_cam_ei;
+ vals = cam_ar;
+ size = CAM_TOTIPO;
+ break;
+ case ID_LA:
+ lookup_name = (namefunc)getname_la_ei;
+ vals = la_ar;
+ size = LA_TOTIPO;
+ break;
+ case ID_TE:
+ lookup_name = (namefunc)getname_tex_ei;
+ vals = te_ar;
+ size = TE_TOTIPO;
+ break;
+ case ID_WO:
+ lookup_name = (namefunc)getname_world_ei;
+ vals = wo_ar;
+ size = WO_TOTIPO;
+ break;
+ case ID_PO:
+ lookup_name = (namefunc)getname_ac_ei;
+ vals = ac_ar;
+ size = AC_TOTIPO;
+ break;
+ case ID_CO:
+ lookup_name = (namefunc)getname_co_ei;
+ vals = co_ar;
+ size = CO_TOTIPO;
+ break;
+ case ID_CU:
+ lookup_name = (namefunc)getname_cu_ei;
+ vals = cu_ar;
+ size = CU_TOTIPO;
+ break;
+ case ID_SEQ:
+ lookup_name = (namefunc)getname_seq_ei;
+ vals = seq_ar;
+ size = SEQ_TOTIPO;
+ break;
+ }
+
+ desc = PyDescr_NewGetSet( &Ipo_Type, &BPy_Ipocurve_getseter );
+ while( size-- ) {
+ strcpy( name, lookup_name( *vals ) );
+ *name = tolower( *name );
+ PyDict_SetItemString( dict, name, desc );
+ ++vals;
+ }
+ Py_DECREF( desc );
+}
+
+static short lookup_curve_name( char *, int , int );
+
+static PyObject *getattro( PyObject *self, PyObject *value )
+{
+ char *name = PyString_AS_STRING( value );
+ Ipo *ipo = ((BPy_Ipo *)self)->ipo;
+ int adrcode;
+ IpoCurve *icu;
+
+ if( !strcmp(name, "__class__") )
+ return PyObject_GenericGetAttr( self, value );
+
+ if( !strcmp(name, "__dict__") ) /* no effect */
+ {
+ PyObject *dict;
+ dict = PyDict_Copy( self->ob_type->tp_dict );
+ generate_curveattrs( dict, ipo->blocktype );
+ return dict;
+ }
+
+ adrcode = lookup_curve_name( name, ipo->blocktype,
+ ((BPy_Ipo *)self)->mtex );
+
+ if( adrcode != -1 ) {
+ for( icu = ipo->curve.first; icu; icu = icu->next )
+ if( icu->adrcode == adrcode )
+ return IpoCurve_CreatePyObject( icu );
+ Py_RETURN_NONE;
+ }
+
+ return PyObject_GenericGetAttr( self, value );
+}
+#endif
+
+/*****************************************************************************/
+/* Python Ipo_Type structure definition: */
+/*****************************************************************************/
+PyTypeObject Ipo_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender Ipo", /* char *tp_name; */
+ sizeof( BPy_Ipo ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ NULL, /* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ ( cmpfunc ) Ipo_compare, /* cmpfunc tp_compare; */
+ ( reprfunc ) Ipo_repr, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ &Ipo_as_sequence, /* PySequenceMethods *tp_as_sequence; */
+ &Ipo_as_mapping, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ ( hashfunc ) GenericLib_hash, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+#ifdef CURVEATTRS
+ (getattrofunc)getattro,
+#else
+ NULL, /* getattrofunc tp_getattro; */
+#endif
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ ( getiterfunc) Ipo_getIter, /* getiterfunc tp_iter; */
+ ( iternextfunc ) Ipo_nextIter, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_Ipo_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ BPy_Ipo_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+/*****************************************************************************/
+/* internal utility routines */
+/*****************************************************************************/
+
+/*
+ * Search through list of known Ipocurves for a particular name.
+ *
+ * str: name of curve we are searching for
+ * blocktype: type of Ipo
+ * channel: texture channel number, for World/Lamp/Material curves
+ *
+ * returns the adrcode for the named curve if it exists, -1 otherwise
+ */
+
+/* this is needed since getname_ob_ei() is different from the rest */
+
+typedef char * (*namefunc)(int, ... );
+
+static short lookup_curve_name( char *str, int blocktype, int channel )
+{
+ namefunc lookup_name;
+ int *adrcodes = NULL;
+ int size = 0;
+
+ /* make sure channel type is ignored when it should be */
+ if( blocktype != ID_WO && blocktype != ID_LA && blocktype != ID_MA )
+ channel = -1;
+
+ switch ( blocktype ) {
+ case ID_OB:
+ lookup_name = (namefunc)getname_ob_ei;
+ adrcodes = ob_ar;
+ size = OB_TOTIPO;
+ break;
+ case ID_MA:
+ lookup_name = (namefunc)getname_mat_ei;
+ adrcodes = ma_ar;
+ size = MA_TOTIPO;
+ break;
+ case ID_CA:
+ lookup_name = (namefunc)getname_cam_ei;
+ adrcodes = cam_ar;
+ size = CAM_TOTIPO;
+ break;
+ case ID_LA:
+ lookup_name = (namefunc)getname_la_ei;
+ adrcodes = la_ar;
+ size = LA_TOTIPO;
+ break;
+ case ID_TE:
+ lookup_name = (namefunc)getname_tex_ei;
+ adrcodes = te_ar;
+ size = TE_TOTIPO;
+ break;
+ case ID_WO:
+ lookup_name = (namefunc)getname_world_ei;
+ adrcodes = wo_ar;
+ size = WO_TOTIPO;
+ break;
+ case ID_PO:
+ lookup_name = (namefunc)getname_ac_ei;
+ adrcodes = ac_ar;
+ size = AC_TOTIPO;
+ break;
+ case ID_CO:
+ lookup_name = (namefunc)getname_co_ei;
+ adrcodes = co_ar;
+ size = CO_TOTIPO;
+ break;
+ case ID_CU:
+ lookup_name = (namefunc)getname_cu_ei;
+ adrcodes = cu_ar;
+ size = CU_TOTIPO;
+ break;
+ case ID_SEQ:
+ lookup_name = (namefunc)getname_seq_ei;
+ adrcodes = seq_ar;
+ size = SEQ_TOTIPO;
+ break;
+ case ID_KE: /* shouldn't happen */
+ default:
+ return -1;
+ }
+
+ while ( size-- ) {
+ char *name = lookup_name ( *adrcodes );
+
+ /* if not a texture channel, just return the adrcode */
+ if( !strcmp( str, name ) ) {
+ if( channel == -1 || *adrcodes < MA_MAP1 )
+ return (short)*adrcodes;
+
+ /* otherwise adjust adrcode to include current channel */
+ else {
+ int param = (short)*adrcodes & ~MA_MAP1;
+ param |= texchannel_to_adrcode( channel );
+ return (short)param;
+ }
+ }
+ ++adrcodes;
+ }
+ return -1;
+}
+
+static short lookup_curve_key( char *str, Ipo *ipo )
+{
+ Key *keyiter;
+
+ /* find the ipo in the keylist */
+ for( keyiter = G.main->key.first; keyiter; keyiter = keyiter->id.next ) {
+ if( keyiter->ipo == ipo ) {
+ KeyBlock *block = keyiter->block.first;
+
+ /* look for a matching string, get the adrcode */
+ for( block = keyiter->block.first; block; block = block->next )
+ if( !strcmp( str, block->name ) )
+ return block->adrcode;
+
+ /* no match; no addr code */
+ return -1;
+ }
+ }
+
+ /* error if the ipo isn't in the list */
+ return -2;
+}
+
+/*
+ * Search through list of known Ipocurves for a particular adrcode.
+ *
+ * code: adrcode of curve we are searching for
+ * blocktype: type of Ipo
+ * channel: texture channel number, for World/Lamp/Material curves
+ *
+ * returns the adrcode for the named curve if it exists, -1 otherwise
+ */
+
+static short lookup_curve_adrcode( int code, int blocktype, int channel )
+{
+ int *adrcodes = NULL;
+ int size = 0;
+
+ switch ( blocktype ) {
+ case ID_OB:
+ adrcodes = ob_ar;
+ size = OB_TOTIPO;
+ break;
+ case ID_MA:
+ adrcodes = ma_ar;
+ size = MA_TOTIPO;
+ break;
+ case ID_CA:
+ adrcodes = cam_ar;
+ size = CAM_TOTIPO;
+ break;
+ case ID_LA:
+ adrcodes = la_ar;
+ size = LA_TOTIPO;
+ break;
+ case ID_TE:
+ adrcodes = te_ar;
+ size = TE_TOTIPO;
+ break;
+ case ID_WO:
+ adrcodes = wo_ar;
+ size = WO_TOTIPO;
+ break;
+ case ID_PO:
+ adrcodes = ac_ar;
+ size = AC_TOTIPO;
+ break;
+ case ID_CO:
+ adrcodes = co_ar;
+ size = CO_TOTIPO;
+ break;
+ case ID_CU:
+ adrcodes = cu_ar;
+ size = CU_TOTIPO;
+ break;
+ case ID_SEQ:
+ adrcodes = seq_ar;
+ size = SEQ_TOTIPO;
+ break;
+ case ID_KE:
+ default:
+ return -1;
+ }
+
+ while ( size-- ) {
+ if( *adrcodes == code ) {
+
+ /* if not a texture channel, just return the adrcode */
+ if( channel == -1 || *adrcodes < MA_MAP1 )
+ return (short)*adrcodes;
+
+ /* otherwise adjust adrcode to include current channel */
+ else {
+ int param = *adrcodes & ~MA_MAP1;
+ param |= texchannel_to_adrcode( channel );
+ return (short)param;
+ }
+ }
+ ++adrcodes;
+ }
+ return -1;
+}
+
+/*
+ * Delete an IpoCurve from an Ipo
+ */
+
+static void del_ipocurve( Ipo * ipo, IpoCurve * icu ) {
+ BLI_remlink( &( ipo->curve ), icu );
+ if( icu->bezt )
+ MEM_freeN( icu->bezt );
+ if( icu->driver )
+ MEM_freeN( icu->driver );
+ MEM_freeN( icu );
+
+ /* have to do this to avoid crashes in the IPO window */
+ allspace( REMAKEIPO, 0 );
+ EXPP_allqueue( REDRAWIPO, 0 );
+}
+
+/*****************************************************************************/
+/* Python BPy_Ipo functions: */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* Function: M_Ipo_New */
+/* Python equivalent: Blender.Ipo.New */
+/*****************************************************************************/
+
+static PyObject *M_Ipo_New( PyObject * self_unused, PyObject * args )
+{
+ char *name = NULL, *code = NULL;
+ int idcode = -1;
+ Ipo *blipo;
+
+ if( !PyArg_ParseTuple( args, "ss", &code, &name ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected two string arguments" );
+
+ if( !strcmp( code, "Object" ) )
+ idcode = ID_OB;
+ else if( !strcmp( code, "Camera" ) )
+ idcode = ID_CA;
+ else if( !strcmp( code, "World" ) )
+ idcode = ID_WO;
+ else if( !strcmp( code, "Material" ) )
+ idcode = ID_MA;
+ else if( !strcmp( code, "Texture" ) )
+ idcode = ID_TE;
+ else if( !strcmp( code, "Lamp" ) )
+ idcode = ID_LA;
+ else if( !strcmp( code, "Action" ) )
+ idcode = ID_PO;
+ else if( !strcmp( code, "Constraint" ) )
+ idcode = ID_CO;
+ else if( !strcmp( code, "Sequence" ) )
+ idcode = ID_SEQ;
+ else if( !strcmp( code, "Curve" ) )
+ idcode = ID_CU;
+ else if( !strcmp( code, "Key" ) )
+ idcode = ID_KE;
+ else return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "unknown Ipo code" );
+
+ blipo = add_ipo( name, idcode );
+
+ if( blipo ) {
+ /* return user count to zero because add_ipo() inc'd it */
+ blipo->id.us = 0;
+ /* create python wrapper obj */
+ return Ipo_CreatePyObject( blipo );
+ } else
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't create Ipo Data in Blender" );
+}
+
+/*****************************************************************************/
+/* Function: M_Ipo_Get */
+/* Python equivalent: Blender.Ipo.Get */
+/* Description: Receives a string and returns the ipo data obj */
+/* whose name matches the string. If no argument is */
+/* passed in, a list of all ipo data names in the */
+/* current scene is returned. */
+/*****************************************************************************/
+static PyObject *M_Ipo_Get( PyObject * self_unused, PyObject * args )
+{
+ char *name = NULL;
+ Ipo *ipo_iter;
+ PyObject *ipolist, *pyobj;
+ char error_msg[64];
+
+ if( !PyArg_ParseTuple( args, "|s", &name ) )
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument (or nothing)" ) );
+
+ ipo_iter = G.main->ipo.first;
+
+ if( name ) { /* (name) - Search ipo by name */
+ while( ipo_iter ) {
+ if( !strcmp( name, ipo_iter->id.name + 2 ) ) {
+ return Ipo_CreatePyObject( ipo_iter );
+ }
+ ipo_iter = ipo_iter->id.next;
+ }
+
+ PyOS_snprintf( error_msg, sizeof( error_msg ),
+ "Ipo \"%s\" not found", name );
+ return EXPP_ReturnPyObjError( PyExc_NameError, error_msg );
+ }
+
+ else { /* () - return a list with all ipos in the scene */
+ int index = 0;
+
+ ipolist = PyList_New( BLI_countlist( &( G.main->ipo ) ) );
+
+ if( !ipolist )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create PyList" );
+
+ while( ipo_iter ) {
+ pyobj = Ipo_CreatePyObject( ipo_iter );
+
+ if( !pyobj )
+ return NULL;
+
+ PyList_SET_ITEM( ipolist, index, pyobj );
+
+ ipo_iter = ipo_iter->id.next;
+ index++;
+ }
+
+ return ipolist;
+ }
+}
+
+/*
+ * This should probably be deprecated too? Or else documented in epydocs.
+ * Seems very similar to Ipocurve.recalc().
+ */
+
+/*****************************************************************************/
+/* Function: M_Ipo_Recalc */
+/* Python equivalent: Blender.Ipo.Recalc */
+/* Description: Receives (presumably) an IpoCurve object and */
+/* updates the curve after changes to control points. */
+/*****************************************************************************/
+static PyObject *M_Ipo_Recalc( PyObject * self_unused, PyObject * value )
+{
+ if( !BPy_IpoCurve_Check(value) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected Ipo curve argument" );
+
+ testhandles_ipocurve( IpoCurve_FromPyObject( value ) );
+
+ Py_RETURN_NONE;
+}
+
+/*****************************************************************************/
+/* Python BPy_Ipo methods: */
+/*****************************************************************************/
+static PyObject *Ipo_getBlocktype( BPy_Ipo * self )
+{
+ return PyInt_FromLong( self->ipo->blocktype );
+}
+
+static int Ipo_setBlocktype( BPy_Ipo * self, PyObject * args )
+{
+ if( !PyInt_Check( args ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected int argument" );
+
+ self->ipo->blocktype = (short)PyInt_AS_LONG( args );
+
+ return 0;
+}
+
+static PyObject *Ipo_getRctf( BPy_Ipo * self )
+{
+ PyObject *l = PyList_New( 4 );
+ PyList_SET_ITEM( l, 0, PyFloat_FromDouble( self->ipo->cur.xmin ) );
+ PyList_SET_ITEM( l, 1, PyFloat_FromDouble( self->ipo->cur.xmax ) );
+ PyList_SET_ITEM( l, 2, PyFloat_FromDouble( self->ipo->cur.ymin ) );
+ PyList_SET_ITEM( l, 3, PyFloat_FromDouble( self->ipo->cur.ymax ) );
+ return l;
+}
+
+static int Ipo_setRctf( BPy_Ipo * self, PyObject * args )
+{
+ float v[4];
+
+ if( !PyArg_ParseTuple( args, "ffff", v, v + 1, v + 2, v + 3 ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a tuple of 4 floats" );
+
+ self->ipo->cur.xmin = v[0];
+ self->ipo->cur.xmax = v[1];
+ self->ipo->cur.ymin = v[2];
+ self->ipo->cur.ymax = v[3];
+
+ return 0;
+}
+
+/*
+ * Get total number of Ipo curves for this Ipo. NOTE: this function
+ * returns all curves for Ipos which have texture channels, unlike
+ * Ipo_length().
+ */
+
+static PyObject *Ipo_getNcurves( BPy_Ipo * self )
+{
+ IpoCurve *icu;
+ int i = 0;
+
+ for( icu = self->ipo->curve.first; icu; icu = icu->next ) {
+ i++;
+ }
+
+ return PyInt_FromLong( (long)i );
+}
+
+/*
+ Function: Ipo_addCurve
+ Bpy: Blender.Ipo.addCurve( 'curname')
+
+ add a new curve to an existing IPO.
+ example:
+ ipo = Blender.Ipo.New('Object','ObIpo')
+ cu = ipo.addCurve('LocX')
+*/
+
+static PyObject *Ipo_addCurve( BPy_Ipo * self, PyObject * value )
+{
+ short param; /* numeric curve name constant */
+ char *cur_name = PyString_AsString(value); /* input arg: curve name */
+ Ipo *ipo = 0;
+ IpoCurve *icu = 0;
+ Link *link;
+
+ if( !cur_name )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_TypeError, "expected string argument" ) );
+
+
+ /* chase down the ipo list looking for ours */
+ link = G.main->ipo.first;
+
+ while( link ) {
+ ipo = ( Ipo * ) link;
+ if( ipo == self->ipo )
+ break;
+ link = link->next;
+ }
+
+ if( !link )
+ return EXPP_ReturnPyObjError
+ ( PyExc_RuntimeError, "Ipo not found" );
+
+ /*
+ * Check if the input arg curve name is valid depending on the block
+ * type, and set param to numeric value. Invalid names will return
+ * param = -1.
+ */
+
+ if( ipo->blocktype != ID_KE ) {
+ param = lookup_curve_name( cur_name, ipo->blocktype, self->mtex );
+ } else {
+ param = lookup_curve_key( cur_name, ipo );
+ if( param == -2 )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "unable to find matching key data for Ipo" );
+ }
+
+ if( param == -1 )
+ return EXPP_ReturnPyObjError( PyExc_NameError,
+ "curve name is not valid" );
+
+ /* see if the curve already exists */
+ for( icu = ipo->curve.first; icu; icu = icu->next )
+ if( icu->adrcode == param )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "Ipo curve already exists" );
+
+ /* create the new ipo curve */
+ icu = MEM_callocN( sizeof(IpoCurve), "Python added ipocurve");
+ icu->blocktype = ipo->blocktype;
+ icu->adrcode = param;
+ icu->flag |= IPO_VISIBLE|IPO_AUTO_HORIZ;
+ set_icu_vars( icu );
+ BLI_addtail( &(ipo->curve), icu);
+
+ allspace( REMAKEIPO, 0 );
+ EXPP_allqueue( REDRAWIPO, 0 );
+
+ /* create a bpy wrapper for the new ipo curve */
+ return IpoCurve_CreatePyObject( icu );
+}
+
+/*
+ Function: Ipo_delCurve
+ Bpy: Blender.Ipo.delCurve(curtype)
+
+ delete an existing curve from IPO.
+ example:
+ ipo = Blender.Ipo.New('Object','ObIpo')
+ cu = ipo.delCurve('LocX')
+*/
+
+static PyObject *Ipo_delCurve( BPy_Ipo * self, PyObject * value )
+{
+ IpoCurve *icu;
+ char *strname = PyString_AsString(value);
+
+ if( !strname )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument" );
+
+ for( icu = self->ipo->curve.first; icu; icu = icu->next ) {
+ if( !strcmp( strname, getIpoCurveName( icu ) ) ) {
+ del_ipocurve( self->ipo, icu );
+ Py_RETURN_NONE;
+ }
+ }
+
+ return EXPP_ReturnPyObjError( PyExc_ValueError, "IpoCurve not found" );
+}
+/*
+ */
+
+static PyObject *Ipo_getCurve( BPy_Ipo * self, PyObject * args )
+{
+ IpoCurve *icu = NULL;
+ short adrcode;
+ PyObject *value = NULL;
+
+ if( !PyArg_ParseTuple( args, "|O", &value ) )
+ goto typeError;
+
+ /* if no name give, get all the Ipocurves */
+ if( !value )
+ return Ipo_getCurves( self );
+
+ /* if arg is a string or int, look up the adrcode */
+ if( PyString_Check( value ) ) {
+ char *str = PyString_AsString( value );
+ for( icu = self->ipo->curve.first; icu; icu = icu->next ) {
+ if( !strcmp( str, getIpoCurveName( icu ) ) )
+ return IpoCurve_CreatePyObject( icu );
+ }
+ Py_RETURN_NONE;
+ }
+ else if( PyInt_Check( value ) ) {
+ adrcode = ( short )PyInt_AsLong( value );
+ for( icu = self->ipo->curve.first; icu; icu = icu->next ) {
+ if( icu->adrcode == adrcode )
+ return IpoCurve_CreatePyObject( icu );
+ }
+ Py_RETURN_NONE;
+ }
+
+typeError:
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "expected string or int argument" );
+}
+
+static PyObject *Ipo_getCurves( BPy_Ipo * self )
+{
+ PyObject *attr = PyList_New( 0 ), *pyipo;
+ IpoCurve *icu;
+
+ for( icu = self->ipo->curve.first; icu; icu = icu->next ) {
+ pyipo = IpoCurve_CreatePyObject( icu );
+ PyList_Append( attr, pyipo );
+ Py_DECREF(pyipo);
+ }
+ return attr;
+}
+
+/*
+ * return a list of valid curve name constants for the Ipo
+ */
+
+static PyObject *Ipo_getCurveNames( BPy_Ipo * self )
+{
+ namefunc lookup_name;
+ int size;
+ PyObject *dict;
+ int *vals = NULL;
+ char name[32];
+ PyObject *attr = Py_None;
+
+ /* determine what type of Ipo we are */
+
+ switch ( self->ipo->blocktype ) {
+ case ID_OB:
+ lookup_name = (namefunc)getname_ob_ei;
+ vals = ob_ar;
+ size = OB_TOTIPO;
+ strcpy( name, "OB_" );
+ break;
+ case ID_MA:
+ lookup_name = (namefunc)getname_mat_ei;
+ vals = ma_ar;
+ size = MA_TOTIPO;
+ strcpy( name, "MA_" );
+ break;
+ case ID_CA:
+ lookup_name = (namefunc)getname_cam_ei;
+ vals = cam_ar;
+ size = CAM_TOTIPO;
+ strcpy( name, "CA_" );
+ break;
+ case ID_LA:
+ lookup_name = (namefunc)getname_la_ei;
+ vals = la_ar;
+ size = LA_TOTIPO;
+ strcpy( name, "LA_" );
+ break;
+ case ID_TE:
+ lookup_name = (namefunc)getname_tex_ei;
+ vals = te_ar;
+ size = TE_TOTIPO;
+ strcpy( name, "TE_" );
+ break;
+ case ID_WO:
+ lookup_name = (namefunc)getname_world_ei;
+ vals = wo_ar;
+ size = WO_TOTIPO;
+ strcpy( name, "WO_" );
+ break;
+ case ID_PO:
+ lookup_name = (namefunc)getname_ac_ei;
+ vals = ac_ar;
+ size = AC_TOTIPO;
+ strcpy( name, "PO_" );
+ break;
+ case ID_CO:
+ lookup_name = (namefunc)getname_co_ei;
+ vals = co_ar;
+ size = CO_TOTIPO;
+ strcpy( name, "CO_" );
+ break;
+ case ID_CU:
+ lookup_name = (namefunc)getname_cu_ei;
+ vals = cu_ar;
+ size = CU_TOTIPO;
+ strcpy( name, "CU_" );
+ break;
+ case ID_SEQ:
+ lookup_name = (namefunc)getname_seq_ei;
+ vals = seq_ar;
+ size = SEQ_TOTIPO;
+ strcpy( name, "SQ_" );
+ break;
+ case ID_KE:
+ {
+ Key *key;
+
+ /* find the ipo in the keylist */
+ for( key = G.main->key.first; key; key = key->id.next ) {
+ if( key->ipo == self->ipo ) {
+ PyObject *tmpstr;
+ KeyBlock *block = key->block.first;
+ attr = PyList_New( 0 );
+
+ /* add each name to the list */
+ for( block = key->block.first; block; block = block->next ) {
+ tmpstr = PyString_FromString( block->name );
+ PyList_Append( attr, tmpstr);
+ Py_DECREF(tmpstr);
+ }
+ return attr;
+ }
+ }
+
+ /* error if the ipo isn't in the list */
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "unable to find matching key data for Ipo" );
+ }
+ default:
+ Py_DECREF( attr );
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "unknown Ipo type" );
+ }
+
+ /*
+ * go through the list of adrcodes to find names, then add to dictionary
+ * with string as key and adrcode as value
+ */
+
+ dict = PyModule_GetDict( submodule );
+ attr = PyConstant_New();
+
+ while( size-- ) {
+ char *ptr = name+3;
+ strcpy( name+3, lookup_name( *vals ) );
+ while( *ptr ) {
+ *ptr = (char)toupper( *ptr );
+ ++ptr;
+ }
+ PyConstant_Insert( (BPy_constant *)attr, name,
+ PyInt_FromLong( *vals ) );
+ ++vals;
+ }
+ return attr;
+}
+
+void generate_curveconsts( PyObject* module )
+{
+ namefunc lookup_name = NULL;
+ int size = 0;
+ int *vals = NULL;
+ char name[32];
+
+ unsigned int i = 0;
+ static short curvelist[] = {
+ ID_OB, ID_MA, ID_CA, ID_LA, ID_TE, ID_WO, ID_PO, ID_CO, ID_CU, ID_SEQ
+ };
+
+ for( i = 0; i < sizeof(curvelist)/sizeof(short); ++i ) {
+ switch ( curvelist[i] ) {
+ case ID_OB:
+ lookup_name = (namefunc)getname_ob_ei;
+ vals = ob_ar;
+ size = OB_TOTIPO;
+ strcpy( name, "OB_" );
+ break;
+ case ID_MA:
+ lookup_name = (namefunc)getname_mat_ei;
+ vals = ma_ar;
+ size = MA_TOTIPO;
+ strcpy( name, "MA_" );
+ break;
+ case ID_CA:
+ lookup_name = (namefunc)getname_cam_ei;
+ vals = cam_ar;
+ size = CAM_TOTIPO;
+ strcpy( name, "CA_" );
+ break;
+ case ID_LA:
+ lookup_name = (namefunc)getname_la_ei;
+ vals = la_ar;
+ size = LA_TOTIPO;
+ strcpy( name, "LA_" );
+ break;
+ case ID_TE:
+ lookup_name = (namefunc)getname_tex_ei;
+ vals = te_ar;
+ size = TE_TOTIPO;
+ strcpy( name, "TE_" );
+ break;
+ case ID_WO:
+ lookup_name = (namefunc)getname_world_ei;
+ vals = wo_ar;
+ size = WO_TOTIPO;
+ strcpy( name, "WO_" );
+ break;
+ case ID_PO:
+ lookup_name = (namefunc)getname_ac_ei;
+ vals = ac_ar;
+ size = AC_TOTIPO;
+ strcpy( name, "PO_" );
+ break;
+ case ID_CO:
+ lookup_name = (namefunc)getname_co_ei;
+ vals = co_ar;
+ size = CO_TOTIPO;
+ strcpy( name, "CO_" );
+ break;
+ case ID_CU:
+ lookup_name = (namefunc)getname_cu_ei;
+ vals = cu_ar;
+ size = CU_TOTIPO;
+ strcpy( name, "CU_" );
+ break;
+ case ID_SEQ:
+ lookup_name = (namefunc)getname_seq_ei;
+ vals = seq_ar;
+ size = SEQ_TOTIPO;
+ strcpy( name, "SQ_" );
+ break;
+ }
+
+ while( size-- ) {
+ char *ptr = name+3;
+ strcpy( name+3, lookup_name( *vals ) );
+ while( *ptr ) {
+ *ptr = (char)toupper( *ptr );
+ ++ptr;
+ }
+ PyModule_AddIntConstant( module, name, *vals );
+ ++vals;
+ }
+ }
+}
+
+
+/*
+ * get the current texture channel number, if defined
+ */
+
+static PyObject *Ipo_getChannel( BPy_Ipo * self )
+{
+ if( self->mtex != -1 )
+ return PyInt_FromLong( (long)self->mtex );
+ Py_RETURN_NONE;
+}
+
+/*
+ * set the current texture channel number, if defined
+ */
+
+static int Ipo_setChannel( BPy_Ipo * self, PyObject * value )
+{
+ if( self->mtex != -1 )
+ return EXPP_setIValueRange( value, &self->mtex, 0, 9, 'h' );
+ return 0;
+}
+
+/*****************************************************************************/
+/* Function: Ipo_compare */
+/* Description: This compares 2 ipo python types, == or != only. */
+/*****************************************************************************/
+static int Ipo_compare( BPy_Ipo * a, BPy_Ipo * b )
+{
+ return ( a->ipo == b->ipo ) ? 0 : -1;
+}
+
+/*****************************************************************************/
+/* Function: Ipo_repr */
+/* Description: This is a callback function for the BPy_Ipo type. It */
+/* builds a meaningful string to represent ipo objects. */
+/*****************************************************************************/
+static PyObject *Ipo_repr( BPy_Ipo * self )
+{
+ char *param;
+
+ switch ( self->ipo->blocktype ) {
+ case ID_OB:
+ param = "Object"; break;
+ case ID_CA:
+ param = "Camera"; break;
+ case ID_LA:
+ param = "Lamp"; break;
+ case ID_TE:
+ param = "Texture"; break;
+ case ID_WO:
+ param = "World"; break;
+ case ID_MA:
+ param = "Material"; break;
+ case ID_PO:
+ param = "Action"; break;
+ case ID_CO:
+ param = "Constriant"; break;
+ case ID_CU:
+ param = "Curve"; break;
+ case ID_SEQ:
+ param = "Sequence"; break;
+ case ID_KE:
+ param = "Key"; break;
+ default:
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "unknown Ipo type" );
+ }
+ return PyString_FromFormat( "[Ipo \"%s\" (%s)]", self->ipo->id.name + 2,
+ param );
+}
+
+/* Three Python Ipo_Type helper functions needed by the Object module: */
+
+/*****************************************************************************/
+/* Function: Ipo_CreatePyObject */
+/* Description: This function will create a new BPy_Ipo from an existing */
+/* Blender ipo structure. */
+/*****************************************************************************/
+PyObject *Ipo_CreatePyObject( Ipo * ipo )
+{
+ BPy_Ipo *pyipo;
+ pyipo = ( BPy_Ipo * ) PyObject_NEW( BPy_Ipo, &Ipo_Type );
+ if( !pyipo )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create BPy_Ipo object" );
+ pyipo->ipo = ipo;
+ pyipo->iter = 0;
+ if( pyipo->ipo->blocktype == ID_WO || pyipo->ipo->blocktype == ID_LA ||
+ pyipo->ipo->blocktype == ID_MA )
+ pyipo->mtex = 0;
+ else
+ pyipo->mtex = -1;
+ return ( PyObject * ) pyipo;
+}
+
+/*****************************************************************************/
+/* Function: Ipo_FromPyObject */
+/* Description: This function returns the Blender ipo from the given */
+/* PyObject. */
+/*****************************************************************************/
+Ipo *Ipo_FromPyObject( PyObject * pyobj )
+{
+ return ( ( BPy_Ipo * ) pyobj )->ipo;
+}
+
+/*****************************************************************************/
+/* Function: Ipo_length */
+/* Description: This function counts the number of curves accessible for the */
+/* PyObject. */
+/*****************************************************************************/
+static int Ipo_length( BPy_Ipo * self )
+{
+ IpoCurve *icu;
+ int len = 0;
+
+ for( icu = self->ipo->curve.first; icu; icu = icu->next ) {
+ if( self->mtex == -1 || icu->adrcode < MA_MAP1 ||
+ icu->adrcode & texchannel_to_adrcode( self->mtex ) )
+ ++len;
+ }
+ return len;
+}
+
+/*
+ * "mapping" operator getter: return an IpoCurve it we can find it
+ */
+
+static PyObject *Ipo_getIpoCurveByName( BPy_Ipo * self, PyObject * key )
+{
+ IpoCurve *icu = NULL;
+ int adrcode;
+
+ /* if Ipo is not ShapeKey and arg is an int, look up the adrcode */
+ if( self->ipo->blocktype != ID_KE && PyNumber_Check( key ) )
+ adrcode = lookup_curve_adrcode( PyInt_AsLong( key ),
+ self->ipo->blocktype, self->mtex );
+ /* if Ipo is ShapeKey and arg is string, look up the adrcode */
+ else if( self->ipo->blocktype == ID_KE && PyString_Check( key ) ) {
+ adrcode = lookup_curve_key( PyString_AS_STRING( key ), self->ipo );
+ if( adrcode == -2 )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "unable to find matching key data for Ipo" );
+ }
+ else
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected int or string key" );
+
+ /* if no adrcode found, value error */
+ if( adrcode == -1 )
+ return EXPP_ReturnPyObjError( PyExc_KeyError, "invalid curve key" );
+
+ /* search for a matching adrcode */
+ for( icu = self->ipo->curve.first; icu; icu = icu->next )
+ if( icu->adrcode == adrcode )
+ return IpoCurve_CreatePyObject( icu );
+
+ /* no curve found */
+ Py_RETURN_NONE;
+}
+
+/*
+ * "mapping" operator setter: create or delete an IpoCurve it we can find it
+ */
+
+static int Ipo_setIpoCurveByName( BPy_Ipo * self, PyObject * key,
+ PyObject * arg )
+{
+ IpoCurve *icu;
+ Ipo *ipo = self->ipo;
+ short adrcode;
+
+ /* "del ipo[const]" will send NULL here; give an error */
+ if( !arg )
+ return EXPP_ReturnIntError( PyExc_NotImplementedError,
+ "del operator not supported" );
+
+ /* "del ipo[const]" will send NULL here; give an error */
+ if( self->ipo->blocktype == ID_KE )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "creation or deletion of Shape Keys not supported" );
+
+ /* check for int argument */
+ if( !PyNumber_Check( key ) )
+ return EXPP_ReturnIntError( PyExc_TypeError, "expected int key" );
+
+ /* look up the key, return error if not found */
+ adrcode = lookup_curve_adrcode( PyInt_AsLong( key ),
+ self->ipo->blocktype, self->mtex );
+
+ if( adrcode == -1 )
+ return EXPP_ReturnIntError( PyExc_KeyError,
+ "invalid curve specified" );
+
+ /* if arg is None, delete the curve */
+ if( arg == Py_None ) {
+ for( icu = self->ipo->curve.first; icu; icu = icu->next ) {
+ if( icu->adrcode == adrcode ) {
+ del_ipocurve( ipo, icu );
+ return 0;
+ }
+ }
+
+ return EXPP_ReturnIntError( PyExc_ValueError, "IpoCurve not found" );
+ } else {
+
+ /* create the new ipo curve */
+ float time, curval;
+ PyObject *tmp, *flt=NULL, *val=NULL;
+
+ /* error if not a sequence or sequence with other than 2 values */
+ if( PySequence_Size( arg ) != 2 )
+ goto AttrError;
+
+ /* get the time and curval */
+ tmp = PySequence_ITEM( arg, 0 );
+ flt = PyNumber_Float( tmp );
+ Py_DECREF( tmp );
+ tmp = PySequence_ITEM( arg, 1 );
+ val = PyNumber_Float( tmp );
+ Py_DECREF( tmp );
+
+ if( !flt || !val )
+ goto AttrError;
+
+ time = (float)PyFloat_AS_DOUBLE( flt );
+ curval = (float)PyFloat_AS_DOUBLE( val );
+ Py_DECREF( flt );
+ Py_DECREF( val );
+
+ /* if curve already exist, delete the original */
+ for( icu = ipo->curve.first; icu; icu = icu->next )
+ if( icu->adrcode == adrcode ) {
+ del_ipocurve( ipo, icu );
+ break;
+ }
+
+ /* create the new curve, then add the key */
+ icu = MEM_callocN( sizeof(IpoCurve), "Python added ipocurve");
+ icu->blocktype = ipo->blocktype;
+ icu->adrcode = adrcode;
+ icu->flag |= IPO_VISIBLE|IPO_AUTO_HORIZ;
+ set_icu_vars( icu );
+ BLI_addtail( &(ipo->curve), icu);
+ insert_vert_icu( icu, time, curval, 0);
+
+ allspace( REMAKEIPO, 0 );
+ EXPP_allqueue( REDRAWIPO, 0 );
+
+ return 0;
+
+AttrError:
+ Py_XDECREF( val );
+ Py_XDECREF( flt );
+ return EXPP_ReturnIntError( PyExc_AttributeError,
+ "expected sequence of two floats" );
+ }
+}
+
+/*
+ * sequence __contains__ method (implements "x in ipo")
+ */
+
+static int Ipo_contains( BPy_Ipo *self, PyObject *key )
+{
+ IpoCurve *icu = NULL;
+ int adrcode;
+
+ /* take a Ipo curve name: key must be a int */
+
+ if( self->ipo->blocktype != ID_KE && PyNumber_Check( key ) ) {
+ adrcode = lookup_curve_adrcode( PyInt_AsLong( key ),
+ self->ipo->blocktype, self->mtex );
+
+ /* if we found an adrcode for the key, search the ipo's curve */
+ if( adrcode != -1 ) {
+ for( icu = self->ipo->curve.first; icu; icu = icu->next )
+ if( icu->adrcode == adrcode )
+ return 1;
+ }
+ } else if( self->ipo->blocktype == ID_KE && PyString_Check( key ) ) {
+ adrcode = lookup_curve_key( PyString_AS_STRING( key ), self->ipo );
+
+ /* if we found an adrcode for the key, search the ipo's curve */
+ if( adrcode >= 0 ) {
+ for( icu = self->ipo->curve.first; icu; icu = icu->next )
+ if( icu->adrcode == adrcode )
+ return 1;
+ }
+ }
+
+ /* no curve found */
+ return 0;
+}
+
+/*
+ * Initialize the interator index
+ */
+
+static PyObject *Ipo_getIter( BPy_Ipo * self )
+{
+ /* return a new IPO object if we are looping on the existing one
+ This allows nested loops */
+ if (self->iter==0) {
+ return EXPP_incr_ret ( (PyObject *) self );
+ } else {
+ return Ipo_CreatePyObject(self->ipo);
+ }
+}
+
+/*
+ * Get the next Ipo curve
+ */
+
+static PyObject *Ipo_nextIter( BPy_Ipo * self )
+{
+ int i;
+ IpoCurve *icu = self->ipo->curve.first;
+
+ ++self->iter;
+
+ /*
+ * count curves only if
+ * (a) Ipo has no texture channels
+ * (b) Ipo has texture channels, but curve is not that type
+ * (c) Ipo has texture channels, and curve is that type, and it is
+ * in the active texture channel
+ */
+ for( i = 0; icu; icu = icu->next ) {
+ if( self->mtex == -1 || icu->adrcode < MA_MAP1 ||
+ icu->adrcode & texchannel_to_adrcode( self->mtex ) ) {
+ ++i;
+
+ /* if indices match, return the curve */
+ if( i == self->iter )
+ return IpoCurve_CreatePyObject( icu );
+ }
+ }
+
+ self->iter = 0; /* allow iter use again */
+ /* ran out of curves */
+ return EXPP_ReturnPyObjError( PyExc_StopIteration,
+ "iterator at end" );
+}
+
+/*****************************************************************************/
+/* Function: Ipo_Init */
+/*****************************************************************************/
+PyObject *Ipo_Init( void )
+{
+ /* PyObject *submodule; */
+
+ if( PyType_Ready( &Ipo_Type ) < 0 )
+ return NULL;
+
+ submodule = Py_InitModule3( "Blender.Ipo", M_Ipo_methods, M_Ipo_doc );
+ generate_curveconsts( submodule );
+
+ return submodule;
+}
+
+/*
+ * The following methods should be deprecated when there are equivalent
+ * methods in Ipocurve (if there aren't already).
+ */
+
+static PyObject *Ipo_getNBezPoints( BPy_Ipo * self, PyObject * args )
+{
+ int num = 0;
+ IpoCurve *icu = NULL;
+
+ if( !PyArg_ParseTuple( args, "i", &num ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected int argument" );
+
+ icu = self->ipo->curve.first;
+ while( icu && num > 0 ) {
+ icu = icu->next;
+ --num;
+ }
+
+ if( num < 0 || !icu )
+ return EXPP_ReturnPyObjError( PyExc_IndexError,
+ "index out of range" );
+
+ return PyInt_FromLong( icu->totvert );
+}
+
+static PyObject *Ipo_DeleteBezPoints( BPy_Ipo * self, PyObject * args )
+{
+ int num = 0, i = 0;
+ IpoCurve *icu = 0;
+ if( !PyArg_ParseTuple( args, "i", &num ) )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_TypeError, "expected int argument" ) );
+ icu = self->ipo->curve.first;
+ if( !icu )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_TypeError, "No IPO curve" ) );
+ for( i = 0; i < num; i++ ) {
+ if( !icu )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_TypeError, "Bad curve number" ) );
+ icu = icu->next;
+
+ }
+ icu->totvert--;
+ return ( PyInt_FromLong( icu->totvert ) );
+}
+
+/*
+ * Ipo_getCurveBP()
+ * this method is UNSUPPORTED.
+ * Calling this method throws a TypeError Exception.
+ *
+ * it looks like the original intent was to return the first point
+ * of a BPoint Ipo curve. However, BPoint ipos are not currently
+ * implemented.
+ */
+
+static PyObject *Ipo_getCurveBP( BPy_Ipo * self_unused, PyObject * args_unused )
+{
+ return EXPP_ReturnPyObjError( PyExc_NotImplementedError,
+ "bpoint ipos are not supported" );
+}
+
+static PyObject *Ipo_getCurveBeztriple( BPy_Ipo * self, PyObject * args )
+{
+ struct BezTriple *ptrbt;
+ int num = 0, pos, i, j;
+ IpoCurve *icu;
+ PyObject *l, *pyfloat;
+
+ if( !PyArg_ParseTuple( args, "ii", &num, &pos ) )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_TypeError, "expected int argument" ) );
+ icu = self->ipo->curve.first;
+ if( !icu )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_TypeError, "No IPO curve" ) );
+ for( i = 0; i < num; i++ ) {
+ if( !icu )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_TypeError, "Bad ipo number" ) );
+ icu = icu->next;
+ }
+ if( pos >= icu->totvert )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "Bad bezt number" );
+
+ ptrbt = icu->bezt + pos;
+ if( !ptrbt )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "No bez triple" );
+
+ l = PyList_New( 0 );
+ for( i = 0; i < 3; i++ ) {
+ for( j = 0; j < 3; j++ ) {
+ pyfloat = PyFloat_FromDouble( ptrbt->vec[i][j] );
+ PyList_Append( l, pyfloat );
+ Py_DECREF(pyfloat);
+ }
+ }
+ return l;
+}
+
+static PyObject *Ipo_setCurveBeztriple( BPy_Ipo * self, PyObject * args )
+{
+ struct BezTriple *ptrbt;
+ int num = 0, pos, i;
+ IpoCurve *icu;
+ PyObject *listargs = 0;
+
+ if( !PyArg_ParseTuple( args, "iiO", &num, &pos, &listargs ) )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_TypeError,
+ "expected int int object argument" ) );
+ if( !PyTuple_Check( listargs ) )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_TypeError, "3rd arg should be a tuple" ) );
+ icu = self->ipo->curve.first;
+ if( !icu )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_TypeError, "No IPO curve" ) );
+ for( i = 0; i < num; i++ ) {
+ if( !icu )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_TypeError, "Bad ipo number" ) );
+ icu = icu->next;
+ }
+ if( pos >= icu->totvert )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "Bad bezt number" );
+
+ ptrbt = icu->bezt + pos;
+ if( !ptrbt )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "No bez triple" );
+
+ for( i = 0; i < 9; i++ ) {
+ PyObject *xx = PyTuple_GetItem( listargs, i );
+ ptrbt->vec[i / 3][i % 3] = (float)PyFloat_AsDouble( xx );
+ }
+
+ Py_INCREF( Py_None );
+ return Py_None;
+}
+
+/* Ipo.__copy__ */
+static PyObject *Ipo_copy( BPy_Ipo * self )
+{
+ Ipo *ipo = copy_ipo(self->ipo );
+ ipo->id.us = 0;
+ return Ipo_CreatePyObject(ipo);
+}
+
+static PyObject *Ipo_EvaluateCurveOn( BPy_Ipo * self, PyObject * args )
+{
+ int num = 0, i;
+ IpoCurve *icu;
+ float time = 0;
+
+ if( !PyArg_ParseTuple( args, "if", &num, &time ) )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_TypeError, "expected int argument" ) );
+
+ icu = self->ipo->curve.first;
+ if( !icu )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_TypeError, "No IPO curve" ) );
+
+ for( i = 0; i < num; i++ ) {
+ if( !icu )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_TypeError, "Bad ipo number" ) );
+ icu = icu->next;
+
+ }
+ return PyFloat_FromDouble( eval_icu( icu, time ) );
+}
+
+static PyObject *Ipo_getCurvecurval( BPy_Ipo * self, PyObject * args )
+{
+ int numcurve = 0, i;
+ IpoCurve *icu;
+ char *stringname = 0, *str1 = 0;
+
+ icu = self->ipo->curve.first;
+ if( !icu )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_TypeError, "No IPO curve" ) );
+
+ if( PyNumber_Check( PyTuple_GetItem( args, 0 ) ) ) /* args is an integer */
+ {
+ if( !PyArg_ParseTuple( args, "i", &numcurve ) )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_TypeError,
+ "expected int or string argument" ) );
+ for( i = 0; i < numcurve; i++ ) {
+ if( !icu )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_TypeError,
+ "Bad ipo number" ) );
+ icu = icu->next;
+ }
+ }
+
+ else /* args is a string */
+ {
+ if( !PyArg_ParseTuple( args, "s", &stringname ) )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_TypeError,
+ "expected int or string argument" ) );
+ while( icu ) {
+ str1 = getIpoCurveName( icu );
+ if( !strcmp( str1, stringname ) )
+ break;
+ icu = icu->next;
+ }
+ }
+
+ if( icu )
+ return PyFloat_FromDouble( icu->curval );
+ Py_RETURN_NONE;
+}
+
+/*
+ * The following methods should be deprecated when methods are pruned out.
+ */
+
+static PyObject *Ipo_oldsetRctf( BPy_Ipo * self, PyObject * args )
+{
+ return EXPP_setterWrapperTuple( (void *)self, args,
+ (setter)Ipo_setRctf );
+}
+
+static PyObject *Ipo_oldsetBlocktype( BPy_Ipo * self, PyObject * args )
+{
+ return EXPP_setterWrapperTuple( (void *)self, args,
+ (setter)Ipo_setBlocktype );
+}
diff --git a/source/blender/python/api2_2x/Ipo.h b/source/blender/python/api2_2x/Ipo.h
new file mode 100644
index 00000000000..d3bf2fd108b
--- /dev/null
+++ b/source/blender/python/api2_2x/Ipo.h
@@ -0,0 +1,63 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Jacques Guignot
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_IPO_H
+#define EXPP_IPO_H
+
+#include <Python.h>
+#include "DNA_ipo_types.h"
+
+/*****************************************************************************/
+/* Python BPy_Ipo structure definition: */
+/*****************************************************************************/
+typedef struct {
+ PyObject_HEAD /* required macro */
+ Ipo * ipo; /* libdata must be second */
+ short iter;
+ short mtex;
+} BPy_Ipo;
+
+extern PyTypeObject Ipo_Type;
+
+#define BPy_Ipo_Check(v) ((v)->ob_type == &Ipo_Type) /* for type checking */
+
+
+/*
+ * prototypes
+ */
+
+PyObject *Ipo_Init( void );
+PyObject *Ipo_CreatePyObject( struct Ipo *ipo );
+Ipo *Ipo_FromPyObject( PyObject * py_obj );
+
+
+#endif /* EXPP_IPO_H */
diff --git a/source/blender/python/api2_2x/Ipocurve.c b/source/blender/python/api2_2x/Ipocurve.c
new file mode 100644
index 00000000000..b8f3c3f6dd0
--- /dev/null
+++ b/source/blender/python/api2_2x/Ipocurve.c
@@ -0,0 +1,1080 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Jacques Guignot, Nathan Letwory, Ken Hughes, Johnny Matthews
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "Ipocurve.h" /*This must come first*/
+
+#include "Object.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_depsgraph.h"
+#include "BKE_ipo.h"
+#include "BIF_space.h"
+#include "BSE_editipo.h"
+#include "MEM_guardedalloc.h"
+#include "DNA_ipo_types.h"
+#include "DNA_key_types.h"
+#include "BezTriple.h"
+#include "gen_utils.h"
+
+/*****************************************************************************/
+/* The following string definitions are used for documentation strings. */
+/* In Python these will be written to the console when doing a */
+/* Blender.IpoCurve.__doc__ */
+/*****************************************************************************/
+char M_IpoCurve_doc[] = "";
+char M_IpoCurve_New_doc[] = "";
+char M_IpoCurve_Get_doc[] = "";
+
+/*****************************************************************************/
+/* Python method structure definition for Blender.IpoCurve module: */
+/*****************************************************************************/
+
+struct PyMethodDef M_IpoCurve_methods[] = {
+ {NULL, NULL, 0, NULL}
+};
+
+/*****************************************************************************/
+/* Python C_IpoCurve methods declarations: */
+/*****************************************************************************/
+static PyObject *IpoCurve_getName( C_IpoCurve * self );
+static PyObject *IpoCurve_Recalc( C_IpoCurve * self );
+static PyObject *IpoCurve_append( C_IpoCurve * self, PyObject * value );
+static PyObject *IpoCurve_addBezier( C_IpoCurve * self, PyObject * value );
+static PyObject *IpoCurve_delBezier( C_IpoCurve * self, PyObject * args );
+static PyObject *IpoCurve_setInterpolation( C_IpoCurve * self,
+ PyObject * value );
+static PyObject *IpoCurve_getInterpolation( C_IpoCurve * self );
+static PyObject *IpoCurve_newgetInterp( C_IpoCurve * self );
+static int IpoCurve_newsetInterp( C_IpoCurve * self, PyObject * args );
+static PyObject *IpoCurve_setExtrapolation( C_IpoCurve * self,
+ PyObject * value );
+static PyObject *IpoCurve_getExtrapolation( C_IpoCurve * self );
+static PyObject *IpoCurve_newgetExtend( C_IpoCurve * self );
+static int IpoCurve_newsetExtend( C_IpoCurve * self, PyObject * args );
+static PyObject *IpoCurve_getPoints( C_IpoCurve * self );
+static PyObject *IpoCurve_evaluate( C_IpoCurve * self, PyObject * args );
+static PyObject *IpoCurve_getDriver( C_IpoCurve * self );
+static int IpoCurve_setDriver( C_IpoCurve * self, PyObject * args );
+static PyObject *IpoCurve_getDriverObject( C_IpoCurve * self);
+static int IpoCurve_setDriverObject( C_IpoCurve * self, PyObject * args );
+static PyObject *IpoCurve_getDriverChannel( C_IpoCurve * self);
+static int IpoCurve_setDriverChannel( C_IpoCurve * self, PyObject * args );
+static PyObject *IpoCurve_getDriverExpression( C_IpoCurve * self);
+static PyObject *IpoCurve_getFlag( C_IpoCurve * self, void *type);
+static int IpoCurve_setFlag( C_IpoCurve * self, PyObject *value, void *type);
+
+static int IpoCurve_setDriverExpression( C_IpoCurve * self, PyObject * args );
+static PyObject *IpoCurve_getCurval( C_IpoCurve * self, PyObject * args );
+static int IpoCurve_setCurval( C_IpoCurve * self, PyObject * key,
+ PyObject * value );
+
+/*****************************************************************************/
+/* Python C_IpoCurve methods table: */
+/*****************************************************************************/
+static PyMethodDef C_IpoCurve_methods[] = {
+ /* name, method, flags, doc */
+ {"getName", ( PyCFunction ) IpoCurve_getName, METH_NOARGS,
+ "() - Return IpoCurve name"},
+ {"Recalc", ( PyCFunction ) IpoCurve_Recalc, METH_NOARGS,
+ "() - deprecated method. use recalc() instead"},
+ {"recalc", ( PyCFunction ) IpoCurve_Recalc, METH_NOARGS,
+ "() - Recomputes the curve after changes"},
+ {"update", ( PyCFunction ) IpoCurve_Recalc, METH_NOARGS,
+ "() - deprecated method: use recalc method instead."},
+ {"append", ( PyCFunction ) IpoCurve_append, METH_O,
+ "(coordlist) - Adds a Bezier point to a curve"},
+ {"addBezier", ( PyCFunction ) IpoCurve_addBezier, METH_O,
+ "() - deprecated method. use append() instead"},
+ {"delBezier", ( PyCFunction ) IpoCurve_delBezier, METH_VARARGS,
+ "() - deprecated method. use \"del icu[index]\" instead"},
+ {"setInterpolation", ( PyCFunction ) IpoCurve_setInterpolation,
+ METH_O, "(str) - Sets the interpolation type of the curve"},
+ {"getInterpolation", ( PyCFunction ) IpoCurve_getInterpolation,
+ METH_NOARGS, "() - Gets the interpolation type of the curve"},
+ {"setExtrapolation", ( PyCFunction ) IpoCurve_setExtrapolation,
+ METH_O, "(str) - Sets the extend mode of the curve"},
+ {"getExtrapolation", ( PyCFunction ) IpoCurve_getExtrapolation,
+ METH_NOARGS, "() - Gets the extend mode of the curve"},
+ {"getPoints", ( PyCFunction ) IpoCurve_getPoints, METH_NOARGS,
+ "() - Returns list of all bezTriples of the curve"},
+ {"evaluate", ( PyCFunction ) IpoCurve_evaluate, METH_VARARGS,
+ "(float) - Evaluate curve at given time"},
+ {NULL, NULL, 0, NULL}
+};
+
+/*
+ * IpoCurve methods
+ */
+
+static PyGetSetDef C_IpoCurve_getseters[] = {
+ {"name",
+ (getter)IpoCurve_getName, (setter)NULL,
+ "the IpoCurve name",
+ NULL},
+ {"bezierPoints",
+ (getter)IpoCurve_getPoints, (setter)NULL,
+ "list of all bezTriples of the curve",
+ NULL},
+ {"driver",
+ (getter)IpoCurve_getDriver, (setter)IpoCurve_setDriver,
+ "The status of the driver 1-object, 2-py expression, 0-off",
+ NULL},
+ {"driverObject",
+ (getter)IpoCurve_getDriverObject, (setter)IpoCurve_setDriverObject,
+ "The object used to drive the IpoCurve",
+ NULL},
+ {"driverChannel",
+ (getter)IpoCurve_getDriverChannel, (setter)IpoCurve_setDriverChannel,
+ "The channel on the driver object used to drive the IpoCurve",
+ NULL},
+ {"driverExpression",
+ (getter)IpoCurve_getDriverExpression, (setter)IpoCurve_setDriverExpression,
+ "The python expression on the driver used to drive the IpoCurve",
+ NULL},
+ {"interpolation",
+ (getter)IpoCurve_newgetInterp, (setter)IpoCurve_newsetInterp,
+ "The interpolation mode of the curve",
+ NULL},
+ {"extend",
+ (getter)IpoCurve_newgetExtend, (setter)IpoCurve_newsetExtend,
+ "The extend mode of the curve",
+ NULL},
+
+ {"sel",
+ (getter)IpoCurve_getFlag, (setter)IpoCurve_setFlag,
+ "the selection state of the curve",
+ (void *)IPO_SELECT},
+
+ {NULL,NULL,NULL,NULL,NULL}
+};
+
+/*****************************************************************************/
+/* Python IpoCurve_Type Mapping Methods table: */
+/*****************************************************************************/
+
+static PyMappingMethods IpoCurve_as_mapping = {
+ ( inquiry ) 0, /* mp_length */
+ ( binaryfunc ) IpoCurve_getCurval, /* mp_subscript */
+ ( objobjargproc ) IpoCurve_setCurval, /* mp_ass_subscript */
+};
+
+/*****************************************************************************/
+/* Python IpoCurve_Type callback function prototypes: */
+/*****************************************************************************/
+static int IpoCurve_compare( C_IpoCurve * a, C_IpoCurve * b );
+static PyObject *IpoCurve_repr( C_IpoCurve * self );
+
+/*****************************************************************************/
+/* Python IpoCurve_Type structure definition: */
+/*****************************************************************************/
+PyTypeObject IpoCurve_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required macro */
+ 0, /* ob_size */
+ "IpoCurve", /* tp_name */
+ sizeof( C_IpoCurve ), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ /* methods */
+ NULL, /* tp_dealloc */
+ 0, /* tp_print */
+ ( getattrfunc ) NULL, /* tp_getattr */
+ ( setattrfunc ) NULL, /* tp_setattr */
+ ( cmpfunc ) IpoCurve_compare, /* tp_compare */
+ ( reprfunc ) IpoCurve_repr, /* tp_repr */
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ &IpoCurve_as_mapping, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ C_IpoCurve_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ C_IpoCurve_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+/*****************************************************************************/
+/* local utility functions */
+/*****************************************************************************/
+
+/*
+ * Keys are handled differently than other Ipos, so go through contortions
+ * to find their names.
+ */
+
+static char *get_key_curvename( IpoCurve *ipocurve )
+{
+ Key *key_iter;
+ char *empty = "";
+
+ /* search for keys with an Ipo */
+
+ for( key_iter = G.main->key.first; key_iter; key_iter=key_iter->id.next) {
+ if( key_iter->ipo ) {
+ IpoCurve *icu = key_iter->ipo->curve.first;
+ /* search curves for a match */
+ while( icu ) {
+ if( icu == ipocurve ) {
+ KeyBlock *block = key_iter->block.first;
+ /* search for matching adrcode */
+ while( block ) {
+ if( block->adrcode == ipocurve->adrcode )
+ return block->name;
+ block = block->next;
+ }
+ }
+ icu = icu->next;
+ }
+ }
+ }
+
+ /* shouldn't get here unless deleted in UI while BPy object alive */
+ return empty;
+}
+
+/*
+ * internal bpy func to get Ipo Curve Name, used by Ipo.c and
+ * KX_BlenderSceneConverter.cpp.
+ *
+ * We are returning a pointer to string constants so there are
+ * no issues with who owns pointers.
+ */
+
+char *getIpoCurveName( IpoCurve * icu )
+{
+ switch ( icu->blocktype ) {
+ case ID_MA:
+ return getname_mat_ei( icu->adrcode );
+ case ID_WO:
+ return getname_world_ei( icu->adrcode );
+ case ID_CA:
+ return getname_cam_ei( icu->adrcode );
+ case ID_OB:
+ return getname_ob_ei( icu->adrcode, 1 );
+ /* solve: what if EffX/Y/Z are wanted? */
+ case ID_TE:
+ return getname_tex_ei( icu->adrcode );
+ case ID_LA:
+ return getname_la_ei( icu->adrcode );
+ case ID_PO:
+ return getname_ac_ei( icu->adrcode );
+ case ID_CU:
+ return getname_cu_ei( icu->adrcode );
+ case ID_KE:
+ /* return "Key"; */
+ /* ipo curves have no names... that was only meant for drawing the buttons... (ton) */
+ return get_key_curvename( icu );
+ case ID_SEQ:
+ return getname_seq_ei( icu->adrcode );
+ case ID_CO:
+ return getname_co_ei( icu->adrcode );
+ }
+ return NULL;
+}
+
+/*
+ * delete a bezTriple from a curve
+ */
+
+static void del_beztriple( IpoCurve *icu, int index )
+{
+ int npoints = icu->totvert - 1;
+ BezTriple * tmp = icu->bezt;
+
+ /*
+ * if delete empties list, then delete it, otherwise copy the remaining
+ * points to a new list
+ */
+
+ if( !npoints ) {
+ icu->bezt = NULL;
+ } else {
+ icu->bezt =
+ MEM_mallocN( sizeof( BezTriple ) * npoints, "bezt" );
+ if( index > 0 )
+ memmove( icu->bezt, tmp, index * sizeof( BezTriple ) );
+ if( index < npoints )
+ memmove( icu->bezt + index, tmp + index + 1,
+ ( npoints - index ) * sizeof( BezTriple ) );
+ }
+
+ /* free old list, adjust vertex count */
+ MEM_freeN( tmp );
+ icu->totvert--;
+
+ /* call calchandles_* instead of testhandles_* */
+ /* I'm not sure this is a complete solution but since we do not */
+ /* deal with curve handles right now, it seems ok */
+ calchandles_ipocurve( icu );
+}
+
+/*****************************************************************************/
+/* Python C_IpoCurve methods: */
+/*****************************************************************************/
+
+static PyObject *IpoCurve_setInterpolation( C_IpoCurve * self,
+ PyObject * value )
+{
+ char *interpolationtype = PyString_AsString(value);
+ short id;
+
+ if( !interpolationtype )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument" );
+
+ if( !strcmp( interpolationtype, "Bezier" ) )
+ id = IPO_BEZ;
+ else if( !strcmp( interpolationtype, "Constant" ) )
+ id = IPO_CONST;
+ else if( !strcmp( interpolationtype, "Linear" ) )
+ id = IPO_LIN;
+ else
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "bad interpolation type" );
+
+ self->ipocurve->ipo = id;
+ Py_RETURN_NONE;
+}
+
+static PyObject *IpoCurve_getInterpolation( C_IpoCurve * self )
+{
+ char *str = 0;
+ IpoCurve *icu = self->ipocurve;
+
+ switch( icu->ipo ) {
+ case IPO_BEZ:
+ str = "Bezier";
+ break;
+ case IPO_CONST:
+ str = "Constant";
+ break;
+ case IPO_LIN:
+ str = "Linear";
+ break;
+ default:
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "unknown interpolation type" );
+ }
+
+ return PyString_FromString( str );
+}
+
+static PyObject * IpoCurve_setExtrapolation( C_IpoCurve * self,
+ PyObject * value )
+{
+ char *extrapolationtype = PyString_AsString(value);
+ short id;
+
+ if( !extrapolationtype )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument" );
+
+ if( !strcmp( extrapolationtype, "Constant" ) )
+ id = 0;
+ else if( !strcmp( extrapolationtype, "Extrapolation" ) )
+ id = 1;
+ else if( !strcmp( extrapolationtype, "Cyclic" ) )
+ id = 2;
+ else if( !strcmp( extrapolationtype, "Cyclic_extrapolation" ) )
+ id = 3;
+ else
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "bad interpolation type" );
+
+ self->ipocurve->extrap = id;
+ Py_RETURN_NONE;
+}
+
+static PyObject *IpoCurve_getExtrapolation( C_IpoCurve * self )
+{
+ char *str;
+ IpoCurve *icu = self->ipocurve;
+
+ switch( icu->extrap ) {
+ case 0:
+ str = "Constant";
+ break;
+ case 1:
+ str = "Extrapolation";
+ break;
+ case 2:
+ str = "Cyclic";
+ break;
+ case 3:
+ str = "Cyclic_extrapolation";
+ break;
+ default:
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "bad extrapolation type" );
+ }
+
+ return PyString_FromString( str );
+}
+
+/*
+ * append a new BezTriple to curve
+ */
+
+static PyObject *IpoCurve_append( C_IpoCurve * self, PyObject * value )
+{
+ float x, y;
+ IpoCurve *icu = self->ipocurve;
+
+ /* if args is a already a beztriple, tack onto end of list */
+ if( BPy_BezTriple_Check ( value ) ) {
+ BPy_BezTriple *bobj = (BPy_BezTriple *)value;
+
+ BezTriple *newb = MEM_callocN( (icu->totvert+1)*sizeof(BezTriple),
+ "BPyBeztriple" );
+ if( icu->bezt ) {
+ memcpy( newb, icu->bezt, ( icu->totvert )*sizeof( BezTriple ) );
+ MEM_freeN( icu->bezt );
+ }
+ icu->bezt = newb;
+ memcpy( &icu->bezt[icu->totvert], bobj->beztriple,
+ sizeof( BezTriple ) );
+ icu->totvert++;
+ calchandles_ipocurve( icu );
+
+ /* otherwise try to get two floats and add to list */
+ } else {
+ PyObject *xobj, *yobj;
+ xobj = PyNumber_Float( PyTuple_GetItem( value, 0 ) );
+ yobj = PyNumber_Float( PyTuple_GetItem( value, 1 ) );
+
+ if( !xobj || !yobj )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected tuple of floats" );
+
+ x = (float)PyFloat_AsDouble( xobj );
+ Py_DECREF( xobj );
+ y = (float)PyFloat_AsDouble( yobj );
+ Py_DECREF( yobj );
+ insert_vert_icu( icu, x, y, 0);
+ }
+
+ Py_RETURN_NONE;
+}
+
+/*
+ Function: IpoCurve_delBezier
+ Bpy: Blender.Ipocurve.delBezier(0)
+
+ Delete an BezTriple from an IPO curve.
+ example:
+ ipo = Blender.Ipo.Get('ObIpo')
+ cu = ipo.getCurve('LocX')
+ cu.delBezier(0)
+*/
+
+static PyObject *IpoCurve_delBezier( C_IpoCurve * self, PyObject * args )
+{
+ int index;
+
+ if( !PyArg_ParseTuple( args, "i", &index ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected int argument" );
+
+ /* if index is negative, count from end of list */
+ if( index < 0 )
+ index += self->ipocurve->totvert;
+ /* check range of index */
+ if( index < 0 || index > self->ipocurve->totvert - 1 )
+ return EXPP_ReturnPyObjError( PyExc_IndexError,
+ "index outside of list" );
+
+ del_beztriple( self->ipocurve, index );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *IpoCurve_Recalc( C_IpoCurve * self )
+{
+ IpoCurve *icu = self->ipocurve;
+
+ /* testhandles_ipocurve (icu); */
+ /* call calchandles_* instead of testhandles_* */
+ /* I'm not sure this is a complete solution but since we do not */
+ /* deal with curve handles right now, it seems ok */
+ calchandles_ipocurve( icu );
+ sort_time_ipocurve( icu );
+
+ Py_INCREF( Py_None );
+ return Py_None;
+}
+
+static PyObject *IpoCurve_getName( C_IpoCurve * self )
+{
+ switch ( self->ipocurve->blocktype ) {
+ case ID_OB:
+ return PyString_FromString( getname_ob_ei( self->ipocurve->adrcode, 1 ) ); /* solve: what if EffX/Y/Z are wanted? */
+ case ID_TE:
+ return PyString_FromString( getname_tex_ei
+ ( self->ipocurve->adrcode ) );
+ case ID_LA:
+ return PyString_FromString( getname_la_ei
+ ( self->ipocurve->adrcode ) );
+ case ID_MA:
+ return PyString_FromString( getname_mat_ei
+ ( self->ipocurve->adrcode ) );
+ case ID_CA:
+ return PyString_FromString( getname_cam_ei
+ ( self->ipocurve->adrcode ) );
+ case ID_WO:
+ return PyString_FromString( getname_world_ei
+ ( self->ipocurve->adrcode ) );
+ case ID_PO:
+ return PyString_FromString( getname_ac_ei
+ ( self->ipocurve->adrcode ) );
+ case ID_CU:
+ return PyString_FromString( getname_cu_ei
+ ( self->ipocurve->adrcode ) );
+ case ID_KE:
+ return PyString_FromString( get_key_curvename( self->ipocurve ) );
+ case ID_SEQ:
+ return PyString_FromString( getname_seq_ei
+ ( self->ipocurve->adrcode ) );
+ case ID_CO:
+ return PyString_FromString( getname_co_ei
+ ( self->ipocurve->adrcode ) );
+ default:
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "This function doesn't support this ipocurve type yet" );
+ }
+}
+
+static PyObject *IpoCurve_getPoints( C_IpoCurve * self )
+{
+ BezTriple *bezt;
+ PyObject *po;
+ int i;
+ PyObject *list = PyList_New( self->ipocurve->totvert );
+
+ if( !list )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "PyList_New() failed" );
+
+ for( bezt = self->ipocurve->bezt, i = 0;
+ i < self->ipocurve->totvert; i++, bezt++ ) {
+ po = BezTriple_CreatePyObject( bezt );
+ if( !po ) {
+ Py_DECREF( list );
+ return NULL; /* This is okay since the error is alredy set */
+ }
+ PyList_SET_ITEM( list, i, po );
+ }
+ return list;
+}
+
+/*****************************************************************************/
+/* Function: IpoCurve_compare */
+/* Description: This compares 2 python types, == or != only. */
+/*****************************************************************************/
+static int IpoCurve_compare( C_IpoCurve * a, C_IpoCurve * b )
+{
+ return ( a->ipocurve == b->ipocurve ) ? 0 : -1;
+}
+
+/*****************************************************************************/
+/* Function: IpoCurve_repr */
+/* Description: This is a callback function for the C_IpoCurve type. It */
+/* builds a meaningful string to represent ipocurve objects. */
+/*****************************************************************************/
+static PyObject *IpoCurve_repr( C_IpoCurve * self )
+{
+ return PyString_FromFormat( "[IpoCurve \"%s\"]",
+ getIpoCurveName( self->ipocurve ) );
+}
+
+/* Three Python IpoCurve_Type helper functions needed by the Object module: */
+
+/*****************************************************************************/
+/* Function: IpoCurve_CreatePyObject */
+/* Description: This function will create a new C_IpoCurve from an existing */
+/* Blender ipo structure. */
+/*****************************************************************************/
+PyObject *IpoCurve_CreatePyObject( IpoCurve * icu )
+{
+ C_IpoCurve *pyipo;
+
+ pyipo = ( C_IpoCurve * ) PyObject_NEW( C_IpoCurve, &IpoCurve_Type );
+
+ if( !pyipo )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create C_IpoCurve object" );
+
+ pyipo->ipocurve = icu;
+
+ return ( PyObject * ) pyipo;
+}
+
+/*****************************************************************************/
+/* Function: IpoCurve_FromPyObject */
+/* Description: This function returns the Blender ipo from the given */
+/* PyObject. */
+/*****************************************************************************/
+IpoCurve *IpoCurve_FromPyObject( PyObject * pyobj )
+{
+ return ( ( C_IpoCurve * ) pyobj )->ipocurve;
+}
+
+/*
+ * get the value of an Ipocurve at a particular time
+ */
+
+static PyObject *IpoCurve_getCurval( C_IpoCurve * self, PyObject * args )
+{
+ float time;
+ PyObject *pyfloat = PyNumber_Float( args );
+
+ if( !pyfloat )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected float argument" );
+ time = ( float )PyFloat_AS_DOUBLE( pyfloat );
+ Py_DECREF( pyfloat );
+
+ return PyFloat_FromDouble( ( double ) eval_icu( self->ipocurve, time ) );
+}
+
+/*
+ * set the value of an Ipocurve at a particular time
+ */
+
+static int IpoCurve_setCurval( C_IpoCurve * self, PyObject * key,
+ PyObject * value )
+{
+ float time, curval;
+ PyObject *pyfloat;
+
+ /* make sure time, curval are both floats */
+
+ pyfloat = PyNumber_Float( key );
+ if( !pyfloat )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected float key" );
+ time = ( float )PyFloat_AS_DOUBLE( pyfloat );
+ Py_DECREF( pyfloat );
+
+ pyfloat = PyNumber_Float( value );
+ if( !pyfloat )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected float argument" );
+ curval = ( float )PyFloat_AS_DOUBLE( pyfloat );
+ Py_DECREF( pyfloat );
+
+ /* insert a key at the specified time */
+
+ insert_vert_icu( self->ipocurve, time, curval, 0);
+ allspace(REMAKEIPO, 0);
+ return 0;
+}
+
+/***************************************************************************/
+/* Function: IpoCurve_evaluate( time ) */
+/* Description: Evaluates IPO curve at the given time. */
+/***************************************************************************/
+
+static PyObject *IpoCurve_evaluate( C_IpoCurve * self, PyObject * args )
+{
+ float time = 0;
+ double eval = 0;
+
+ /* expecting float */
+ if( !PyArg_ParseTuple( args, "f", &time ) )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_TypeError, "expected float argument" ) );
+
+ eval = ( double ) eval_icu( self->ipocurve, time );
+
+ return PyFloat_FromDouble( eval );
+
+}
+
+static PyObject *IpoCurve_getDriver( C_IpoCurve * self )
+{
+ if( !self->ipocurve->driver )
+ return PyInt_FromLong( 0 );
+ else {
+ if (self->ipocurve->driver->type == IPO_DRIVER_TYPE_NORMAL)
+ return PyInt_FromLong( 1 );
+ if (self->ipocurve->driver->type == IPO_DRIVER_TYPE_PYTHON)
+ return PyInt_FromLong( 2 );
+ }
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "unknown driver type, internal error" );
+
+}
+
+/*
+ sets the driver to
+ 0: disabled
+ 1: enabled (object)
+ 2: enabled (python expression)
+*/
+static int IpoCurve_setDriver( C_IpoCurve * self, PyObject * args )
+{
+ IpoCurve *ipo = self->ipocurve;
+ int type;
+ if( !PyInt_Check( args ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected int argument 0 or 1 " );
+
+ type = PyInt_AS_LONG( args );
+
+ if (type < 0 || type > 2)
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "expected int argument 0, 1 or 2" );
+
+ if (type==0) { /* disable driver */
+ if( ipo->driver ) {
+ MEM_freeN( ipo->driver );
+ ipo->driver = NULL;
+ }
+ } else {
+ if( !ipo->driver ) { /*add driver if its not there */
+ ipo->driver = MEM_callocN( sizeof(IpoDriver), "ipo driver" );
+ ipo->driver->blocktype = ID_OB;
+ ipo->driver->adrcode = OB_LOC_X;
+ }
+
+ if (type==1 && ipo->driver->type != IPO_DRIVER_TYPE_NORMAL) {
+ ipo->driver->type = IPO_DRIVER_TYPE_NORMAL;
+ ipo->driver->ob = NULL;
+ ipo->driver->flag &= ~IPO_DRIVER_FLAG_INVALID;
+
+ } else if (type==2 && ipo->driver->type != IPO_DRIVER_TYPE_PYTHON) {
+ ipo->driver->type = IPO_DRIVER_TYPE_PYTHON;
+ /* we should probably set ipo->driver->ob, but theres no way to do it properly */
+ ipo->driver->ob = NULL;
+ }
+ }
+
+ return 0;
+}
+
+static PyObject *IpoCurve_getDriverObject( C_IpoCurve * self )
+{
+ IpoCurve *ipo = self->ipocurve;
+
+ if( ipo->driver )
+ return Object_CreatePyObject( ipo->driver->ob );
+
+ Py_RETURN_NONE;
+}
+
+static int IpoCurve_setDriverObject( C_IpoCurve * self, PyObject * arg )
+{
+ IpoCurve *ipo = self->ipocurve;
+
+ if( !ipo->driver )
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "This IpoCurve does not have an active driver" );
+
+ if(!BPy_Object_Check(arg) )
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "expected an object argument" );
+ ipo->driver->ob = ((BPy_Object *)arg)->object;
+
+ DAG_scene_sort(G.scene);
+
+ return 0;
+}
+
+static PyObject *IpoCurve_getDriverChannel( C_IpoCurve * self )
+{
+ if( !self->ipocurve->driver )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "This IpoCurve does not have an active driver" );
+
+ return PyInt_FromLong( self->ipocurve->driver->adrcode );
+}
+
+static int IpoCurve_setDriverChannel( C_IpoCurve * self, PyObject * args )
+{
+ IpoCurve *ipo = self->ipocurve;
+ short param;
+
+ if( !ipo->driver )
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "This IpoCurve does not have an active driver" );
+
+ if( !PyInt_Check( args ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected int argument" );
+
+ param = (short)PyInt_AS_LONG ( args );
+ if( ( param >= OB_LOC_X && param <= OB_LOC_Z )
+ || ( param >= OB_ROT_X && param <= OB_ROT_Z )
+ || ( param >= OB_SIZE_X && param <= OB_SIZE_Z ) ) {
+ ipo->driver->adrcode = (short)PyInt_AS_LONG ( args );
+ return 0;
+ }
+
+ return EXPP_ReturnIntError( PyExc_ValueError, "invalid int argument" );
+}
+
+static PyObject *IpoCurve_getDriverExpression( C_IpoCurve * self )
+{
+ IpoCurve *ipo = self->ipocurve;
+
+ if( ipo->driver && ipo->driver->type == IPO_DRIVER_TYPE_PYTHON )
+ return PyString_FromString( ipo->driver->name );
+
+ Py_RETURN_NONE;
+}
+
+static int IpoCurve_setDriverExpression( C_IpoCurve * self, PyObject * arg )
+{
+ IpoCurve *ipo = self->ipocurve;
+ char *exp; /* python expression */
+
+ if( !ipo->driver )
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "This IpoCurve does not have an active driver" );
+
+ if (ipo->driver->type != IPO_DRIVER_TYPE_PYTHON)
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "This IpoCurve is not a python expression set the driver attribute to 2" );
+
+ if(!PyString_Check(arg) )
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "expected a string argument" );
+
+ exp = PyString_AsString(arg);
+ if (strlen(exp)>127)
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "string is too long, use 127 characters or less" );
+
+ strcpy(ipo->driver->name, exp);
+ return 0;
+}
+
+static PyObject *M_IpoCurve_ExtendDict( void )
+{
+ PyObject *EM = PyConstant_New( );
+
+ if( EM ) {
+ BPy_constant *d = ( BPy_constant * ) EM;
+
+ PyConstant_Insert( d, "CONST", PyInt_FromLong( IPO_HORIZ ) );
+ PyConstant_Insert( d, "EXTRAP", PyInt_FromLong( IPO_DIR ) );
+ PyConstant_Insert( d, "CYCLIC", PyInt_FromLong( IPO_CYCL ) );
+ PyConstant_Insert( d, "CYCLIC_EXTRAP", PyInt_FromLong( IPO_CYCLX ) );
+ }
+ return EM;
+}
+
+static PyObject *M_IpoCurve_InterpDict( void )
+{
+ PyObject *IM = PyConstant_New( );
+
+ if( IM ) {
+ BPy_constant *d = ( BPy_constant * ) IM;
+
+ PyConstant_Insert( d, "CONST", PyInt_FromLong( IPO_CONST ) );
+ PyConstant_Insert( d, "LINEAR", PyInt_FromLong( IPO_LIN ) );
+ PyConstant_Insert( d, "BEZIER", PyInt_FromLong( IPO_BEZ ) );
+ }
+ return IM;
+}
+
+/*****************************************************************************/
+/* Function: IpoCurve_Init */
+/*****************************************************************************/
+PyObject *IpoCurve_Init( void )
+{
+ PyObject *submodule;
+ PyObject *ExtendTypes = M_IpoCurve_ExtendDict( );
+ PyObject *InterpTypes = M_IpoCurve_InterpDict( );
+
+ if( PyType_Ready( &IpoCurve_Type ) < 0)
+ return NULL;
+
+ submodule =
+ Py_InitModule3( "Blender.IpoCurve", M_IpoCurve_methods,
+ M_IpoCurve_doc );
+
+ PyModule_AddIntConstant( submodule, "LOC_X", OB_LOC_X );
+ PyModule_AddIntConstant( submodule, "LOC_Y", OB_LOC_Y );
+ PyModule_AddIntConstant( submodule, "LOC_Z", OB_LOC_Z );
+ PyModule_AddIntConstant( submodule, "ROT_X", OB_ROT_X );
+ PyModule_AddIntConstant( submodule, "ROT_Y", OB_ROT_Y );
+ PyModule_AddIntConstant( submodule, "ROT_Z", OB_ROT_Z );
+ PyModule_AddIntConstant( submodule, "SIZE_X", OB_SIZE_X );
+ PyModule_AddIntConstant( submodule, "SIZE_Y", OB_SIZE_Y );
+ PyModule_AddIntConstant( submodule, "SIZE_Z", OB_SIZE_Z );
+
+ if( ExtendTypes )
+ PyModule_AddObject( submodule, "ExtendTypes", ExtendTypes );
+ if( InterpTypes )
+ PyModule_AddObject( submodule, "InterpTypes", InterpTypes );
+
+ return submodule;
+}
+
+/*
+ */
+
+static PyObject *IpoCurve_newgetInterp( C_IpoCurve * self )
+{
+ return PyInt_FromLong( self->ipocurve->ipo );
+}
+
+static int IpoCurve_newsetInterp( C_IpoCurve * self, PyObject * value )
+{
+ return EXPP_setIValueRange( value, &self->ipocurve->ipo,
+ IPO_CONST, IPO_BEZ, 'h' );
+}
+
+static PyObject *IpoCurve_newgetExtend( C_IpoCurve * self )
+{
+ return PyInt_FromLong( self->ipocurve->extrap );
+}
+
+static int IpoCurve_newsetExtend( C_IpoCurve * self, PyObject * value )
+{
+ return EXPP_setIValueRange( value, &self->ipocurve->extrap,
+ IPO_HORIZ, IPO_CYCLX, 'h' );
+}
+
+static PyObject *IpoCurve_getFlag( C_IpoCurve * self, void *type )
+{
+ if (self->ipocurve->flag & (int)type)
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+}
+
+static int IpoCurve_setFlag( C_IpoCurve * self, PyObject *value, void *type )
+{
+ int param = PyObject_IsTrue( value );
+ if( param == -1 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected True/False or 0/1" );
+
+ if (param)
+ self->ipocurve->flag |= (int)type;
+ else
+ self->ipocurve->flag &= ~(int)type;
+
+ return 0;
+}
+
+
+/* #####DEPRECATED###### */
+
+static PyObject *IpoCurve_addBezier( C_IpoCurve * self, PyObject * value )
+{
+ float x, y;
+ int npoints;
+ IpoCurve *icu;
+ BezTriple *bzt, *tmp;
+ static char name[10] = "mlml";
+ if( !PyArg_ParseTuple( value, "ff", &x, &y ) )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_TypeError, "expected a tuple of 2 floats" ) );
+
+ icu = self->ipocurve;
+ npoints = icu->totvert;
+ tmp = icu->bezt;
+ icu->bezt = MEM_mallocN( sizeof( BezTriple ) * ( npoints + 1 ), name );
+ if( tmp ) {
+ memmove( icu->bezt, tmp, sizeof( BezTriple ) * npoints );
+ MEM_freeN( tmp );
+ }
+ memmove( icu->bezt + npoints, icu->bezt, sizeof( BezTriple ) );
+ icu->totvert++;
+ bzt = icu->bezt + npoints;
+ bzt->vec[0][0] = x - 1;
+ bzt->vec[1][0] = x;
+ bzt->vec[2][0] = x + 1;
+ bzt->vec[0][1] = y - 1;
+ bzt->vec[1][1] = y;
+ bzt->vec[2][1] = y + 1;
+ /* set handle type to Auto */
+ bzt->h1 = HD_AUTO;
+ bzt->h2 = HD_AUTO;
+
+ Py_RETURN_NONE;
+}
diff --git a/source/blender/python/api2_2x/Ipocurve.h b/source/blender/python/api2_2x/Ipocurve.h
new file mode 100644
index 00000000000..0844e11b04b
--- /dev/null
+++ b/source/blender/python/api2_2x/Ipocurve.h
@@ -0,0 +1,58 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Jacques Guignot
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_IPOCURVE_H
+#define EXPP_IPOCURVE_H
+
+#include <Python.h>
+#include "DNA_curve_types.h" /* declaration of IpoCurve */
+
+/*****************************************************************************/
+/* Python C_IpoCurve structure definition: */
+/*****************************************************************************/
+typedef struct {
+ PyObject_HEAD /* required macro */
+ IpoCurve * ipocurve;
+ char wrapped;
+} C_IpoCurve;
+
+extern PyTypeObject IpoCurve_Type;
+
+#define BPy_IpoCurve_Check(v) ((v)->ob_type == &IpoCurve_Type) /* for type checking */
+
+PyObject *IpoCurve_Init( void );
+PyObject *IpoCurve_CreatePyObject( IpoCurve * ipo );
+IpoCurve *IpoCurve_FromPyObject( PyObject * pyobj );
+char *getIpoCurveName( IpoCurve * icu );
+
+
+#endif /* EXPP_IPOCURVE_H */
diff --git a/source/blender/python/api2_2x/Key.c b/source/blender/python/api2_2x/Key.c
new file mode 100644
index 00000000000..88facd80b4e
--- /dev/null
+++ b/source/blender/python/api2_2x/Key.c
@@ -0,0 +1,683 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Pontus Lidman, Johnny Matthews, Ken Hughes,
+ * Michael Reimpell
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "Key.h" /*This must come first*/
+#include "vector.h"
+
+#include "DNA_scene_types.h"
+
+#include <BLI_blenlib.h>
+#include <BKE_global.h>
+#include <BKE_main.h>
+#include <BKE_curve.h>
+#include <BKE_library.h>
+#include "BIF_space.h"
+
+#include "Ipocurve.h"
+#include "NMesh.h" /* we create NMesh.NMVert objects */
+#include "Ipo.h"
+#include "BezTriple.h"
+
+#include "BSE_editipo.h"
+#include "mydevice.h"
+#include "BKE_depsgraph.h"
+#include "blendef.h"
+#include "constant.h"
+#include "gen_utils.h"
+#include "gen_library.h"
+
+#define KEY_TYPE_MESH 0
+#define KEY_TYPE_CURVE 1
+#define KEY_TYPE_LATTICE 2
+
+/* macro from blenkernel/intern/key.c:98 */
+#define GS(a) (*((short *)(a)))
+
+static int Key_compare( BPy_Key * a, BPy_Key * b );
+static PyObject *Key_repr( BPy_Key * self );
+static void Key_dealloc( BPy_Key * self );
+
+static PyObject *Key_getBlocks( BPy_Key * self );
+static PyObject *Key_getType( BPy_Key * self );
+static PyObject *Key_getRelative( BPy_Key * self );
+static PyObject *Key_getIpo( BPy_Key * self );
+static int Key_setIpo( BPy_Key * self, PyObject * args );
+static PyObject *Key_getValue( BPy_Key * self );
+static int Key_setRelative( BPy_Key * self, PyObject * value );
+
+static struct PyMethodDef Key_methods[] = {
+ { "getBlocks", (PyCFunction) Key_getBlocks, METH_NOARGS, "Get key blocks" },
+ { "getIpo", (PyCFunction) Key_getIpo, METH_NOARGS, "Get key Ipo" },
+ { 0, 0, 0, 0 }
+};
+
+static PyGetSetDef BPy_Key_getsetters[] = {
+ {"type",(getter)Key_getType, (setter)NULL,
+ "Key Type",NULL},
+ {"value",(getter)Key_getValue, (setter)NULL,
+ "Key value",NULL},
+ {"ipo",(getter)Key_getIpo, (setter)Key_setIpo,
+ "Ipo linked to key",NULL},
+ {"blocks",(getter)Key_getBlocks, (setter)NULL,
+ "Blocks linked to the key",NULL},
+ {"relative",(getter)Key_getRelative, (setter)Key_setRelative,
+ "Non-zero is key is relative",NULL},
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+static PyObject *KeyBlock_getData( PyObject * self );
+static PyObject *KeyBlock_getCurval( BPy_KeyBlock * self );
+static PyObject *KeyBlock_getName( BPy_KeyBlock * self );
+static PyObject *KeyBlock_getPos( BPy_KeyBlock * self );
+static PyObject *KeyBlock_getSlidermin( BPy_KeyBlock * self );
+static PyObject *KeyBlock_getSlidermax( BPy_KeyBlock * self );
+static PyObject *KeyBlock_getVgroup( BPy_KeyBlock * self );
+
+static int KeyBlock_setName( BPy_KeyBlock *, PyObject * args );
+static int KeyBlock_setVgroup( BPy_KeyBlock *, PyObject * args );
+static int KeyBlock_setSlidermin( BPy_KeyBlock *, PyObject * args );
+static int KeyBlock_setSlidermax( BPy_KeyBlock *, PyObject * args );
+
+static void KeyBlock_dealloc( BPy_KeyBlock * self );
+static int KeyBlock_compare( BPy_KeyBlock * a, BPy_KeyBlock * b );
+static PyObject *KeyBlock_repr( BPy_KeyBlock * self );
+
+static struct PyMethodDef KeyBlock_methods[] = {
+ { "getData", (PyCFunction) KeyBlock_getData, METH_NOARGS,
+ "Get keyblock data" },
+ { 0, 0, 0, 0 }
+};
+
+static PyGetSetDef BPy_KeyBlock_getsetters[] = {
+ {"curval",(getter)KeyBlock_getCurval, (setter)NULL,
+ "Current value of the corresponding IpoCurve",NULL},
+ {"name",(getter)KeyBlock_getName, (setter)KeyBlock_setName,
+ "Keyblock Name",NULL},
+ {"pos",(getter)KeyBlock_getPos, (setter)NULL,
+ "Keyblock Pos",NULL},
+ {"slidermin",(getter)KeyBlock_getSlidermin, (setter)KeyBlock_setSlidermin,
+ "Keyblock Slider Minimum",NULL},
+ {"slidermax",(getter)KeyBlock_getSlidermax, (setter)KeyBlock_setSlidermax,
+ "Keyblock Slider Maximum",NULL},
+ {"vgroup",(getter)KeyBlock_getVgroup, (setter)KeyBlock_setVgroup,
+ "Keyblock VGroup",NULL},
+ {"data",(getter)KeyBlock_getData, (setter)NULL,
+ "Keyblock VGroup",NULL},
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+PyTypeObject Key_Type = {
+ PyObject_HEAD_INIT( NULL ) 0, /*ob_size */
+ "Blender Key", /*tp_name */
+ sizeof( BPy_Key ), /*tp_basicsize */
+ 0, /*tp_itemsize */
+ /* methods */
+ ( destructor ) Key_dealloc,/* destructor tp_dealloc; */
+ ( printfunc ) 0, /*tp_print */
+ ( getattrfunc ) 0, /*tp_getattr */
+ ( setattrfunc ) 0, /*tp_setattr */
+ ( cmpfunc) Key_compare, /*tp_compare*/
+ ( reprfunc ) Key_repr, /* tp_repr */
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ ( hashfunc ) GenericLib_hash, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ Key_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ BPy_Key_getsetters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+PyTypeObject KeyBlock_Type = {
+ PyObject_HEAD_INIT( NULL ) 0, /*ob_size */
+ "Blender KeyBlock", /*tp_name */
+ sizeof( BPy_KeyBlock ), /*tp_basicsize */
+ 0, /*tp_itemsize */
+ /* methods */
+ ( destructor ) KeyBlock_dealloc,/* destructor tp_dealloc; */
+ ( printfunc ) 0, /*tp_print */
+ ( getattrfunc ) 0, /*tp_getattr */
+ ( setattrfunc ) 0, /*tp_setattr */
+ ( cmpfunc) KeyBlock_compare, /*tp_compare*/
+ ( reprfunc ) KeyBlock_repr, /* tp_repr */
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ KeyBlock_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ BPy_KeyBlock_getsetters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+PyObject *Key_CreatePyObject( Key * blenkey )
+{
+ BPy_Key *bpykey = PyObject_NEW( BPy_Key, &Key_Type );
+ /* blenkey may be NULL so be careful */
+ bpykey->key = blenkey;
+ return ( PyObject * ) bpykey;
+}
+
+static void Key_dealloc( BPy_Key * self )
+{
+ PyObject_DEL( self );
+}
+
+static int Key_compare( BPy_Key * a, BPy_Key * b )
+{
+ return ( a->key == b->key ) ? 0 : -1;
+}
+
+static PyObject *Key_repr( BPy_Key * self )
+{
+ return PyString_FromFormat( "[Key \"%s\"]", self->key->id.name + 2 );
+}
+
+static PyObject *Key_getIpo( BPy_Key * self )
+{
+ if (self->key->ipo)
+ return Ipo_CreatePyObject( self->key->ipo );
+ Py_RETURN_NONE;
+}
+
+static int Key_setIpo( BPy_Key * self, PyObject * value )
+{
+ return GenericLib_assignData(value, (void **) &self->key->ipo, 0, 1, ID_IP, ID_KE);
+}
+
+static PyObject *Key_getRelative( BPy_Key * self )
+{
+ if( self->key->type == KEY_RELATIVE )
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+}
+
+static int Key_setRelative( BPy_Key * self, PyObject * value )
+{
+ int param = PyObject_IsTrue( value );
+ if( param == -1 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected True/False or 0/1" );
+
+ if( param )
+ self->key->type = KEY_RELATIVE;
+ else
+ self->key->type = KEY_NORMAL;
+ allqueue(REDRAWIPO, 0);
+ allspace(REMAKEIPO, 0);
+
+ return 0;
+}
+
+static PyObject *Key_getType( BPy_Key * self )
+{
+ int idcode;
+ int type = -1;
+
+ idcode = GS( self->key->from->name );
+
+ switch( idcode ) {
+ case ID_ME:
+ type = KEY_TYPE_MESH;
+ break;
+ case ID_CU:
+ type = KEY_TYPE_CURVE;
+ break;
+ case ID_LT:
+ type = KEY_TYPE_LATTICE;
+ break;
+ }
+
+ return PyInt_FromLong( type );
+}
+
+static PyObject *Key_getBlocks( BPy_Key * self )
+{
+ Key *key = self->key;
+ KeyBlock *kb;
+ int i=0;
+ PyObject *l = PyList_New( BLI_countlist( &(key->block)) );
+
+ for (kb = key->block.first; kb; kb = kb->next, i++)
+ PyList_SET_ITEM( l, i, KeyBlock_CreatePyObject( kb, key ) );
+
+ return l;
+}
+
+static PyObject *Key_getValue( BPy_Key * self )
+{
+ BPy_Key *k = ( BPy_Key * ) self;
+
+ return PyFloat_FromDouble( k->key->curval );
+}
+
+/* ------------ Key Block Functions -------------- */
+PyObject *KeyBlock_CreatePyObject( KeyBlock * keyblock, Key *parentKey )
+{
+ BPy_KeyBlock *bpykb = PyObject_NEW( BPy_KeyBlock, &KeyBlock_Type );
+ bpykb->key = parentKey;
+ bpykb->keyblock = keyblock; /* keyblock maye be NULL, thats ok */
+ return ( PyObject * ) bpykb;
+}
+
+static PyObject *KeyBlock_getCurval( BPy_KeyBlock * self ) {
+ return PyFloat_FromDouble( self->keyblock->curval );
+}
+
+static PyObject *KeyBlock_getName( BPy_KeyBlock * self ) {
+ return PyString_FromString(self->keyblock->name);
+}
+
+static PyObject *KeyBlock_getPos( BPy_KeyBlock * self ){
+ return PyFloat_FromDouble( self->keyblock->pos );
+}
+
+static PyObject *KeyBlock_getSlidermin( BPy_KeyBlock * self ){
+ return PyFloat_FromDouble( self->keyblock->slidermin );
+}
+
+static PyObject *KeyBlock_getSlidermax( BPy_KeyBlock * self ){
+ return PyFloat_FromDouble( self->keyblock->slidermax );
+}
+
+static PyObject *KeyBlock_getVgroup( BPy_KeyBlock * self ){
+ return PyString_FromString(self->keyblock->vgroup);
+}
+
+static int KeyBlock_setName( BPy_KeyBlock * self, PyObject * args ){
+ char* text = NULL;
+
+ text = PyString_AsString ( args );
+ if( !text )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected string argument" );
+ strncpy( self->keyblock->name, text , 32);
+
+ return 0;
+}
+
+static int KeyBlock_setVgroup( BPy_KeyBlock * self, PyObject * args ){
+ char* text = NULL;
+
+ text = PyString_AsString ( args );
+ if( !text )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected string argument" );
+ strncpy( self->keyblock->vgroup, text , 32);
+
+ return 0;
+}
+static int KeyBlock_setSlidermin( BPy_KeyBlock * self, PyObject * args ){
+ return EXPP_setFloatClamped ( args, &self->keyblock->slidermin,
+ -10.0f,
+ 10.0f );
+}
+static int KeyBlock_setSlidermax( BPy_KeyBlock * self, PyObject * args ){
+ return EXPP_setFloatClamped ( args, &self->keyblock->slidermax,
+ -10.0f,
+ 10.0f );
+}
+
+static void KeyBlock_dealloc( BPy_KeyBlock * self )
+{
+ PyObject_DEL( self );
+}
+
+static int KeyBlock_compare( BPy_KeyBlock * a, BPy_KeyBlock * b )
+{
+ return ( a->keyblock == b->keyblock ) ? 0 : -1;
+}
+
+static PyObject *KeyBlock_repr( BPy_KeyBlock * self )
+{
+ return PyString_FromFormat( "[KeyBlock \"%s\"]", self->keyblock->name );
+}
+
+
+static Curve *find_curve( Key *key )
+{
+ Curve *cu;
+
+ if( !key )
+ return NULL;
+
+ for( cu = G.main->curve.first; cu; cu = cu->id.next ) {
+ if( cu->key == key )
+ break;
+ }
+ return cu;
+}
+
+static PyObject *KeyBlock_getData( PyObject * self )
+{
+ /* If this is a mesh key, data is an array of MVert coords.
+ If lattice, data is an array of BPoint coords
+ If curve, data is an array of BezTriple or BPoint */
+
+ char *datap;
+ int datasize;
+ int idcode;
+ int i;
+ Curve *cu;
+ Nurb* nu;
+ PyObject *l;
+ BPy_KeyBlock *kb = ( BPy_KeyBlock * ) self;
+ Key *key = kb->key;
+
+ if( !kb->keyblock->data ) {
+ Py_RETURN_NONE;
+ }
+
+ l = PyList_New( kb->keyblock->totelem );
+ if( !l )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "PyList_New() failed" );
+
+ idcode = GS( key->from->name );
+
+ switch(idcode) {
+ case ID_ME:
+
+ for (i=0, datap = kb->keyblock->data; i<kb->keyblock->totelem; i++) {
+ PyObject *vec = newVectorObject((float*)datap, 3, Py_WRAP);
+
+ if (!vec) return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "could not allocate memory for Blender.Mathutils.Vector wrapper!" );
+
+ PyList_SetItem(l, i, vec);
+ datap += kb->key->elemsize;
+ }
+ break;
+
+ case ID_CU:
+ cu = find_curve ( key );
+ if( !cu )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "key is no linked to any curve!" );
+ datasize = count_curveverts(&cu->nurb);
+ nu = cu->nurb.first;
+ if( nu->bezt ) {
+ datasize /= 3;
+ Py_DECREF (l);
+ l = PyList_New( datasize );
+ for( i = 0, datap = kb->keyblock->data; i < datasize;
+ i++, datap += sizeof(float)*3*4) {
+ PyObject *tuple = PyTuple_New(4), *vec;
+ float *vecs = (float*)datap;
+
+ if (!tuple) return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "PyTuple_New() failed!" );
+
+ vec = newVectorObject(vecs, 3, Py_WRAP);
+ if (!vec) return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "Could not allocate memory for Blender.Mathutils.Vector wrapper!" );
+
+ PyTuple_SET_ITEM( tuple, 0, vec);
+
+ vecs += 3;
+ vec = newVectorObject(vecs, 3, Py_WRAP);
+ if (!vec) return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "Could not allocate memory for Blender.Mathutils.Vector wrapper!" );
+
+ PyTuple_SET_ITEM( tuple, 1, vec);
+
+ vecs += 3;
+ vec = newVectorObject(vecs, 3, Py_WRAP);
+ if (!vec) return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "Could not allocate memory for Blender.Mathutils.Vector wrapper!" );
+
+ PyTuple_SET_ITEM( tuple, 2, vec);
+
+ /*tilts*/
+ vecs += 3;
+ vec = newVectorObject(vecs, 3, Py_WRAP);
+ if (!vec) return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "Could not allocate memory for Blender.Mathutils.Vector wrapper!" );
+
+ PyTuple_SET_ITEM( tuple, 3, vec);
+
+ PyList_SetItem( l, i, tuple );
+ }
+ } else {
+ for( i = 0, datap = kb->keyblock->data; i < datasize;
+ i++, datap += kb->key->elemsize ) {
+ PyObject *vec = newVectorObject((float*)datap, 4, Py_WRAP);
+ if (!vec) return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "could not allocate memory for Blender.Mathutils.Vector wrapper!" );
+
+ PyList_SetItem( l, i, vec );
+ }
+ }
+ break;
+
+ case ID_LT:
+ for( i = 0, datap = kb->keyblock->data; i < kb->keyblock->totelem;
+ i++, datap += kb->key->elemsize ) {
+ PyObject *vec = newVectorObject((float*)datap, 3, Py_WRAP);
+ if (!vec) return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "Could not allocate memory for Blender.Mathutils.Vector wrapper!" );
+
+ PyList_SetItem( l, i, vec );
+ }
+ break;
+ }
+
+ return l;
+}
+
+static PyObject *M_Key_Get( PyObject * self, PyObject * args )
+{
+ char *name = NULL;
+ Key *key_iter;
+ char error_msg[64];
+ int i;
+
+ if( !PyArg_ParseTuple( args, "|s", &name ) )
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument (or nothing)" ) );
+
+ if ( name ) {
+ for (key_iter = G.main->key.first; key_iter;
+ key_iter=key_iter->id.next) {
+ if (strcmp ( key_iter->id.name + 2, name ) == 0 ) {
+ return Key_CreatePyObject( key_iter );
+ }
+ }
+
+ PyOS_snprintf( error_msg, sizeof( error_msg ),
+ "Key \"%s\" not found", name );
+ return EXPP_ReturnPyObjError ( PyExc_NameError, error_msg );
+
+ } else {
+
+ PyObject *keylist;
+
+ keylist = PyList_New( BLI_countlist( &( G.main->key ) ) );
+
+ for ( i=0, key_iter = G.main->key.first; key_iter;
+ key_iter=key_iter->id.next, i++ ) {
+ PyList_SetItem(keylist, i, Key_CreatePyObject(key_iter));
+ }
+ return keylist;
+ }
+}
+
+struct PyMethodDef M_Key_methods[] = {
+ {"Get", M_Key_Get, METH_VARARGS, "Get a key or all key names"},
+ {NULL, NULL, 0, NULL}
+};
+
+static PyObject *M_Key_TypesDict( void )
+{
+ PyObject *T = PyConstant_New( );
+
+ if( T ) {
+ BPy_constant *d = ( BPy_constant * ) T;
+
+ PyConstant_Insert( d, "MESH", PyInt_FromLong( KEY_TYPE_MESH ) );
+ PyConstant_Insert( d, "CURVE", PyInt_FromLong( KEY_TYPE_CURVE ) );
+ PyConstant_Insert( d, "LATTICE", PyInt_FromLong( KEY_TYPE_LATTICE ) );
+ }
+
+ return T;
+}
+
+PyObject *Key_Init( void )
+{
+ PyObject *submodule;
+ PyObject *Types = NULL;
+
+ if( PyType_Ready( &Key_Type ) < 0 || PyType_Ready( &KeyBlock_Type ) < 0 )
+ return NULL;
+
+ submodule =
+ Py_InitModule3( "Blender.Key", M_Key_methods, "Key module" );
+
+ Types = M_Key_TypesDict( );
+ if( Types )
+ PyModule_AddObject( submodule, "Types", Types );
+
+ return submodule;
+}
+
diff --git a/source/blender/python/api2_2x/Key.h b/source/blender/python/api2_2x/Key.h
new file mode 100644
index 00000000000..87cb55d10eb
--- /dev/null
+++ b/source/blender/python/api2_2x/Key.h
@@ -0,0 +1,68 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Pontus Lidman
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef EXPP_KEY_H
+#define EXPP_KEY_H
+
+#include "Python.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <DNA_key_types.h>
+#include <DNA_curve_types.h>
+
+extern PyTypeObject Key_Type;
+extern PyTypeObject KeyBlock_Type;
+
+typedef struct {
+ PyObject_HEAD /* required python macro */
+ Key * key; /* libdata must be second */
+ /* Object *object;*/ /* for vertex grouping info, since it's stored on the object */
+ /*PyObject *keyBlock;*/
+ /*PyObject *ipo;*/
+} BPy_Key;
+
+typedef struct {
+ PyObject_HEAD /* required python macro */
+ Key *key;
+ KeyBlock * keyblock;
+ /* Object *object;*/ /* for vertex grouping info, since it's stored on the object */
+} BPy_KeyBlock;
+
+PyObject *Key_CreatePyObject( Key * k );
+PyObject *KeyBlock_CreatePyObject( KeyBlock * k, Key *parentKey );
+
+PyObject *Key_Init( void );
+
+#endif /* EXPP_KEY_H */
diff --git a/source/blender/python/api2_2x/Lamp.c b/source/blender/python/api2_2x/Lamp.c
new file mode 100644
index 00000000000..d40cc5a2cfc
--- /dev/null
+++ b/source/blender/python/api2_2x/Lamp.c
@@ -0,0 +1,1570 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano, Nathan Letwory, Stephen Swaney,
+ * Ken Hughes
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#include "Lamp.h" /*This must come first*/
+
+#include "BKE_main.h"
+#include "BKE_global.h"
+#include "BKE_object.h"
+#include "BKE_library.h"
+#include "BLI_blenlib.h"
+#include "BIF_space.h"
+#include "BSE_editipo.h"
+#include "mydevice.h"
+#include "Ipo.h"
+#include "constant.h"
+#include "gen_utils.h"
+#include "gen_library.h"
+
+/*****************************************************************************/
+/* Python BPy_Lamp defaults: */
+/*****************************************************************************/
+
+/* Lamp types */
+
+/* NOTE:
+ these are the same values as LA_* from DNA_lamp_types.h
+ is there some reason we are not simply using those #defines?
+ s. swaney 8-oct-2004
+*/
+
+#define EXPP_LAMP_TYPE_LAMP 0
+#define EXPP_LAMP_TYPE_SUN 1
+#define EXPP_LAMP_TYPE_SPOT 2
+#define EXPP_LAMP_TYPE_HEMI 3
+#define EXPP_LAMP_TYPE_AREA 4
+#define EXPP_LAMP_TYPE_YF_PHOTON 5
+/*
+ define a constant to keep magic numbers out of the code
+ this value should be equal to the last EXPP_LAMP_TYPE_*
+*/
+#define EXPP_LAMP_TYPE_MAX 5
+
+/* Lamp mode flags */
+
+#define EXPP_LAMP_MODE_SHADOWS 1
+#define EXPP_LAMP_MODE_HALO 2
+#define EXPP_LAMP_MODE_LAYER 4
+#define EXPP_LAMP_MODE_QUAD 8
+#define EXPP_LAMP_MODE_NEGATIVE 16
+#define EXPP_LAMP_MODE_ONLYSHADOW 32
+#define EXPP_LAMP_MODE_SPHERE 64
+#define EXPP_LAMP_MODE_SQUARE 128
+#define EXPP_LAMP_MODE_TEXTURE 256
+#define EXPP_LAMP_MODE_OSATEX 512
+#define EXPP_LAMP_MODE_DEEPSHADOW 1024
+#define EXPP_LAMP_MODE_NODIFFUSE 2048
+#define EXPP_LAMP_MODE_NOSPECULAR 4096
+#define EXPP_LAMP_MODE_SHAD_RAY 8192
+/* Lamp MIN, MAX values */
+
+#define EXPP_LAMP_SAMPLES_MIN 1
+#define EXPP_LAMP_SAMPLES_MAX 16
+#define EXPP_LAMP_BUFFERSIZE_MIN 512
+#define EXPP_LAMP_BUFFERSIZE_MAX 5120
+#define EXPP_LAMP_ENERGY_MIN 0.0
+#define EXPP_LAMP_ENERGY_MAX 10.0
+#define EXPP_LAMP_DIST_MIN 0.1f
+#define EXPP_LAMP_DIST_MAX 5000.0
+#define EXPP_LAMP_SPOTSIZE_MIN 1.0
+#define EXPP_LAMP_SPOTSIZE_MAX 180.0
+#define EXPP_LAMP_SPOTBLEND_MIN 0.00
+#define EXPP_LAMP_SPOTBLEND_MAX 1.00
+#define EXPP_LAMP_CLIPSTART_MIN 0.1f
+#define EXPP_LAMP_CLIPSTART_MAX 1000.0
+#define EXPP_LAMP_CLIPEND_MIN 1.0
+#define EXPP_LAMP_CLIPEND_MAX 5000.0
+#define EXPP_LAMP_BIAS_MIN 0.01f
+#define EXPP_LAMP_BIAS_MAX 5.00
+#define EXPP_LAMP_SOFTNESS_MIN 1.0
+#define EXPP_LAMP_SOFTNESS_MAX 100.0
+#define EXPP_LAMP_HALOINT_MIN 0.0
+#define EXPP_LAMP_HALOINT_MAX 5.0
+#define EXPP_LAMP_HALOSTEP_MIN 0
+#define EXPP_LAMP_HALOSTEP_MAX 12
+#define EXPP_LAMP_QUAD1_MIN 0.0
+#define EXPP_LAMP_QUAD1_MAX 1.0
+#define EXPP_LAMP_QUAD2_MIN 0.0
+#define EXPP_LAMP_QUAD2_MAX 1.0
+#define EXPP_LAMP_COL_MIN 0.0
+#define EXPP_LAMP_COL_MAX 1.0
+
+/* Raytracing settings */
+#define EXPP_LAMP_RAYSAMPLES_MIN 1
+#define EXPP_LAMP_RAYSAMPLES_MAX 16
+#define EXPP_LAMP_AREASIZE_MIN 0.01f
+#define EXPP_LAMP_AREASIZE_MAX 100.0f
+
+/* Lamp_setComponent() keys for which color to get/set */
+#define EXPP_LAMP_COMP_R 0x00
+#define EXPP_LAMP_COMP_G 0x01
+#define EXPP_LAMP_COMP_B 0x02
+
+#define IPOKEY_RGB 0
+#define IPOKEY_ENERGY 1
+#define IPOKEY_SPOTSIZE 2
+#define IPOKEY_OFFSET 3
+#define IPOKEY_SIZE 4
+
+/*****************************************************************************/
+/* Python API function prototypes for the Lamp module. */
+/*****************************************************************************/
+static PyObject *M_Lamp_New( PyObject * self, PyObject * args,
+ PyObject * keywords );
+static PyObject *M_Lamp_Get( PyObject * self, PyObject * args );
+
+/*****************************************************************************/
+/* The following string definitions are used for documentation strings. */
+/* In Python these will be written to the console when doing a */
+/* Blender.Lamp.__doc__ */
+/*****************************************************************************/
+static char M_Lamp_doc[] = "The Blender Lamp module\n\n\
+This module provides control over **Lamp Data** objects in Blender.\n\n\
+Example::\n\n\
+ from Blender import Lamp\n\
+ l = Lamp.New('Spot') # create new 'Spot' lamp data\n\
+ l.setMode('square', 'shadow') # set these two lamp mode flags\n\
+ ob = Object.New('Lamp') # create new lamp object\n\
+ ob.link(l) # link lamp obj with lamp data\n";
+
+static char M_Lamp_New_doc[] = "Lamp.New (type = 'Lamp', name = 'LampData'):\n\
+ Return a new Lamp Data object with the given type and name.";
+
+static char M_Lamp_Get_doc[] = "Lamp.Get (name = None):\n\
+ Return the Lamp Data with the given name, None if not found, or\n\
+ Return a list with all Lamp Data objects in the current scene,\n\
+ if no argument was given.";
+
+/*****************************************************************************/
+/* Python method structure definition for Blender.Lamp module: */
+/*****************************************************************************/
+struct PyMethodDef M_Lamp_methods[] = {
+ {"New", ( PyCFunction ) M_Lamp_New, METH_VARARGS | METH_KEYWORDS,
+ M_Lamp_New_doc},
+ {"Get", M_Lamp_Get, METH_VARARGS, M_Lamp_Get_doc},
+ {"get", M_Lamp_Get, METH_VARARGS, M_Lamp_Get_doc},
+ {NULL, NULL, 0, NULL}
+};
+
+/*****************************************************************************/
+/* Python BPy_Lamp methods declarations: */
+/*****************************************************************************/
+static PyObject *Lamp_getType( BPy_Lamp * self );
+static PyObject *Lamp_getTypesConst( void );
+static PyObject *Lamp_getMode( BPy_Lamp * self );
+static PyObject *Lamp_getModesConst( void );
+static PyObject *Lamp_getSamples( BPy_Lamp * self );
+static PyObject *Lamp_getRaySamplesX( BPy_Lamp * self );
+static PyObject *Lamp_getRaySamplesY( BPy_Lamp * self );
+static PyObject *Lamp_getAreaSizeX( BPy_Lamp * self );
+static PyObject *Lamp_getAreaSizeY( BPy_Lamp * self );
+static PyObject *Lamp_getBufferSize( BPy_Lamp * self );
+static PyObject *Lamp_getHaloStep( BPy_Lamp * self );
+static PyObject *Lamp_getEnergy( BPy_Lamp * self );
+static PyObject *Lamp_getDist( BPy_Lamp * self );
+static PyObject *Lamp_getSpotSize( BPy_Lamp * self );
+static PyObject *Lamp_getSpotBlend( BPy_Lamp * self );
+static PyObject *Lamp_getClipStart( BPy_Lamp * self );
+static PyObject *Lamp_getClipEnd( BPy_Lamp * self );
+static PyObject *Lamp_getBias( BPy_Lamp * self );
+static PyObject *Lamp_getSoftness( BPy_Lamp * self );
+static PyObject *Lamp_getHaloInt( BPy_Lamp * self );
+static PyObject *Lamp_getQuad1( BPy_Lamp * self );
+static PyObject *Lamp_getQuad2( BPy_Lamp * self );
+static PyObject *Lamp_getCol( BPy_Lamp * self );
+static PyObject *Lamp_getIpo( BPy_Lamp * self );
+static PyObject *Lamp_getComponent( BPy_Lamp * self, void * closure );
+static PyObject *Lamp_clearIpo( BPy_Lamp * self );
+static PyObject *Lamp_insertIpoKey( BPy_Lamp * self, PyObject * args );
+static PyObject *Lamp_oldsetIpo( BPy_Lamp * self, PyObject * args );
+static PyObject *Lamp_oldsetType( BPy_Lamp * self, PyObject * value );
+static PyObject *Lamp_oldsetMode( BPy_Lamp * self, PyObject * args );
+static PyObject *Lamp_oldsetSamples( BPy_Lamp * self, PyObject * args );
+static PyObject *Lamp_oldsetRaySamplesX( BPy_Lamp * self, PyObject * args );
+static PyObject *Lamp_oldsetRaySamplesY( BPy_Lamp * self, PyObject * args );
+static PyObject *Lamp_oldsetAreaSizeX( BPy_Lamp * self, PyObject * args );
+static PyObject *Lamp_oldsetAreaSizeY( BPy_Lamp * self, PyObject * args );
+static PyObject *Lamp_oldsetBufferSize( BPy_Lamp * self, PyObject * args );
+static PyObject *Lamp_oldsetHaloStep( BPy_Lamp * self, PyObject * args );
+static PyObject *Lamp_oldsetEnergy( BPy_Lamp * self, PyObject * args );
+static PyObject *Lamp_oldsetDist( BPy_Lamp * self, PyObject * args );
+static PyObject *Lamp_oldsetSpotSize( BPy_Lamp * self, PyObject * args );
+static PyObject *Lamp_oldsetSpotBlend( BPy_Lamp * self, PyObject * args );
+static PyObject *Lamp_oldsetClipStart( BPy_Lamp * self, PyObject * args );
+static PyObject *Lamp_oldsetClipEnd( BPy_Lamp * self, PyObject * args );
+static PyObject *Lamp_oldsetBias( BPy_Lamp * self, PyObject * args );
+static PyObject *Lamp_oldsetSoftness( BPy_Lamp * self, PyObject * args );
+static PyObject *Lamp_oldsetHaloInt( BPy_Lamp * self, PyObject * args );
+static PyObject *Lamp_oldsetQuad1( BPy_Lamp * self, PyObject * args );
+static PyObject *Lamp_oldsetQuad2( BPy_Lamp * self, PyObject * args );
+static PyObject *Lamp_oldsetCol( BPy_Lamp * self, PyObject * args );
+static PyObject *Lamp_copy( BPy_Lamp * self );
+static int Lamp_setIpo( BPy_Lamp * self, PyObject * args );
+static int Lamp_setType( BPy_Lamp * self, PyObject * args );
+static int Lamp_setMode( BPy_Lamp * self, PyObject * args );
+static int Lamp_setSamples( BPy_Lamp * self, PyObject * args );
+static int Lamp_setRaySamplesX( BPy_Lamp * self, PyObject * args );
+static int Lamp_setRaySamplesY( BPy_Lamp * self, PyObject * args );
+static int Lamp_setAreaSizeX( BPy_Lamp * self, PyObject * args );
+static int Lamp_setAreaSizeY( BPy_Lamp * self, PyObject * args );
+static int Lamp_setBufferSize( BPy_Lamp * self, PyObject * args );
+static int Lamp_setHaloStep( BPy_Lamp * self, PyObject * args );
+static int Lamp_setEnergy( BPy_Lamp * self, PyObject * args );
+static int Lamp_setDist( BPy_Lamp * self, PyObject * args );
+static int Lamp_setSpotSize( BPy_Lamp * self, PyObject * args );
+static int Lamp_setSpotBlend( BPy_Lamp * self, PyObject * args );
+static int Lamp_setClipStart( BPy_Lamp * self, PyObject * args );
+static int Lamp_setClipEnd( BPy_Lamp * self, PyObject * args );
+static int Lamp_setBias( BPy_Lamp * self, PyObject * args );
+static int Lamp_setSoftness( BPy_Lamp * self, PyObject * args );
+static int Lamp_setHaloInt( BPy_Lamp * self, PyObject * args );
+static int Lamp_setQuad1( BPy_Lamp * self, PyObject * args );
+static int Lamp_setQuad2( BPy_Lamp * self, PyObject * args );
+static int Lamp_setCol( BPy_Lamp * self, PyObject * args );
+static PyObject *Lamp_getScriptLinks( BPy_Lamp * self, PyObject * value );
+static PyObject *Lamp_addScriptLink( BPy_Lamp * self, PyObject * args );
+static PyObject *Lamp_clearScriptLinks( BPy_Lamp * self, PyObject * args );
+static int Lamp_setComponent( BPy_Lamp * self, PyObject * value, void * closure );
+
+/*****************************************************************************/
+/* Python BPy_Lamp methods table: */
+/*****************************************************************************/
+static PyMethodDef BPy_Lamp_methods[] = {
+ /* name, method, flags, doc */
+
+ {"getType", ( PyCFunction ) Lamp_getType, METH_NOARGS,
+ "() - return Lamp type - 'Lamp':0, 'Sun':1, 'Spot':2, 'Hemi':3, 'Area':4, 'Photon':5"},
+ {"getMode", ( PyCFunction ) Lamp_getMode, METH_NOARGS,
+ "() - return Lamp mode flags (or'ed value)"},
+ {"getSamples", ( PyCFunction ) Lamp_getSamples, METH_NOARGS,
+ "() - return Lamp samples value"},
+ {"getRaySamplesX", ( PyCFunction ) Lamp_getRaySamplesX, METH_NOARGS,
+ "() - return Lamp raytracing samples on the X axis"},
+ {"getRaySamplesY", ( PyCFunction ) Lamp_getRaySamplesY, METH_NOARGS,
+ "() - return Lamp raytracing samples on the Y axis"},
+ {"getAreaSizeX", ( PyCFunction ) Lamp_getAreaSizeX, METH_NOARGS,
+ "() - return Lamp area size on the X axis"},
+ {"getAreaSizeY", ( PyCFunction ) Lamp_getAreaSizeY, METH_NOARGS,
+ "() - return Lamp area size on the Y axis"},
+ {"getBufferSize", ( PyCFunction ) Lamp_getBufferSize, METH_NOARGS,
+ "() - return Lamp buffer size value"},
+ {"getHaloStep", ( PyCFunction ) Lamp_getHaloStep, METH_NOARGS,
+ "() - return Lamp halo step value"},
+ {"getEnergy", ( PyCFunction ) Lamp_getEnergy, METH_NOARGS,
+ "() - return Lamp energy value"},
+ {"getDist", ( PyCFunction ) Lamp_getDist, METH_NOARGS,
+ "() - return Lamp clipping distance value"},
+ {"getSpotSize", ( PyCFunction ) Lamp_getSpotSize, METH_NOARGS,
+ "() - return Lamp spot size value"},
+ {"getSpotBlend", ( PyCFunction ) Lamp_getSpotBlend, METH_NOARGS,
+ "() - return Lamp spot blend value"},
+ {"getClipStart", ( PyCFunction ) Lamp_getClipStart, METH_NOARGS,
+ "() - return Lamp clip start value"},
+ {"getClipEnd", ( PyCFunction ) Lamp_getClipEnd, METH_NOARGS,
+ "() - return Lamp clip end value"},
+ {"getBias", ( PyCFunction ) Lamp_getBias, METH_NOARGS,
+ "() - return Lamp bias value"},
+ {"getSoftness", ( PyCFunction ) Lamp_getSoftness, METH_NOARGS,
+ "() - return Lamp softness value"},
+ {"getHaloInt", ( PyCFunction ) Lamp_getHaloInt, METH_NOARGS,
+ "() - return Lamp halo intensity value"},
+ {"getQuad1", ( PyCFunction ) Lamp_getQuad1, METH_NOARGS,
+ "() - return light intensity value #1 for a Quad Lamp"},
+ {"getQuad2", ( PyCFunction ) Lamp_getQuad2, METH_NOARGS,
+ "() - return light intensity value #2 for a Quad Lamp"},
+ {"getCol", ( PyCFunction ) Lamp_getCol, METH_NOARGS,
+ "() - return light rgb color triplet"},
+ {"setName", ( PyCFunction ) GenericLib_setName_with_method, METH_VARARGS,
+ "(str) - rename Lamp"},
+ {"setType", ( PyCFunction ) Lamp_oldsetType, METH_O,
+ "(str) - change Lamp type, which can be 'Lamp', 'Sun', 'Spot', 'Hemi', 'Area', 'Photon'"},
+ {"setMode", ( PyCFunction ) Lamp_oldsetMode, METH_VARARGS,
+ "([up to eight str's]) - Set Lamp mode flag(s)"},
+ {"setSamples", ( PyCFunction ) Lamp_oldsetSamples, METH_VARARGS,
+ "(int) - change Lamp samples value"},
+ {"setRaySamplesX", ( PyCFunction ) Lamp_oldsetRaySamplesX, METH_VARARGS,
+ "(int) - change Lamp ray X samples value in [1,16]"},
+ {"setRaySamplesY", ( PyCFunction ) Lamp_oldsetRaySamplesY, METH_VARARGS,
+ "(int) - change Lamp ray Y samples value in [1,16]"},
+ {"setAreaSizeX", ( PyCFunction ) Lamp_oldsetAreaSizeX, METH_VARARGS,
+ "(float) - change Lamp ray X size for area lamps, value in [0.01, 100.0]"},
+ {"setAreaSizeY", ( PyCFunction ) Lamp_oldsetAreaSizeY, METH_VARARGS,
+ "(float) - change Lamp ray Y size for area lamps, value in [0.01, 100.0]"},
+ {"setBufferSize", ( PyCFunction ) Lamp_oldsetBufferSize, METH_VARARGS,
+ "(int) - change Lamp buffer size value"},
+ {"setHaloStep", ( PyCFunction ) Lamp_oldsetHaloStep, METH_VARARGS,
+ "(int) - change Lamp halo step value"},
+ {"setEnergy", ( PyCFunction ) Lamp_oldsetEnergy, METH_VARARGS,
+ "(float) - change Lamp energy value"},
+ {"setDist", ( PyCFunction ) Lamp_oldsetDist, METH_VARARGS,
+ "(float) - change Lamp clipping distance value"},
+ {"setSpotSize", ( PyCFunction ) Lamp_oldsetSpotSize, METH_VARARGS,
+ "(float) - change Lamp spot size value"},
+ {"setSpotBlend", ( PyCFunction ) Lamp_oldsetSpotBlend, METH_VARARGS,
+ "(float) - change Lamp spot blend value"},
+ {"setClipStart", ( PyCFunction ) Lamp_oldsetClipStart, METH_VARARGS,
+ "(float) - change Lamp clip start value"},
+ {"setClipEnd", ( PyCFunction ) Lamp_oldsetClipEnd, METH_VARARGS,
+ "(float) - change Lamp clip end value"},
+ {"setBias", ( PyCFunction ) Lamp_oldsetBias, METH_VARARGS,
+ "(float) - change Lamp draw size value"},
+ {"setSoftness", ( PyCFunction ) Lamp_oldsetSoftness, METH_VARARGS,
+ "(float) - change Lamp softness value"},
+ {"setHaloInt", ( PyCFunction ) Lamp_oldsetHaloInt, METH_VARARGS,
+ "(float) - change Lamp halo intensity value"},
+ {"setQuad1", ( PyCFunction ) Lamp_oldsetQuad1, METH_VARARGS,
+ "(float) - change light intensity value #1 for a Quad Lamp"},
+ {"setQuad2", ( PyCFunction ) Lamp_oldsetQuad2, METH_VARARGS,
+ "(float) - change light intensity value #2 for a Quad Lamp"},
+ {"setCol", ( PyCFunction ) Lamp_oldsetCol, METH_VARARGS,
+ "(f,f,f) or ([f,f,f]) - change light's rgb color triplet"},
+ {"getScriptLinks", ( PyCFunction ) Lamp_getScriptLinks, METH_O,
+ "(eventname) - Get a list of this lamp's scriptlinks (Text names) "
+ "of the given type\n"
+ "(eventname) - string: FrameChanged, Redraw or Render."},
+ {"addScriptLink", ( PyCFunction ) Lamp_addScriptLink, METH_VARARGS,
+ "(text, evt) - Add a new lamp scriptlink.\n"
+ "(text) - string: an existing Blender Text name;\n"
+ "(evt) string: FrameChanged, Redraw or Render."},
+ {"clearScriptLinks", ( PyCFunction ) Lamp_clearScriptLinks,
+ METH_VARARGS,
+ "() - Delete all scriptlinks from this lamp.\n"
+ "([s1<,s2,s3...>]) - Delete specified scriptlinks from this lamp."},
+ {"getIpo", ( PyCFunction ) Lamp_getIpo, METH_NOARGS,
+ "() - get IPO for this lamp"},
+ {"clearIpo", ( PyCFunction ) Lamp_clearIpo, METH_NOARGS,
+ "() - unlink the IPO for this lamp"},
+ {"setIpo", ( PyCFunction ) Lamp_oldsetIpo, METH_VARARGS,
+ "( lamp-ipo ) - link an IPO to this lamp"},
+ {"insertIpoKey", ( PyCFunction ) Lamp_insertIpoKey, METH_VARARGS,
+ "( Lamp IPO type ) - Inserts a key into IPO"},
+ {"__copy__", ( PyCFunction ) Lamp_copy, METH_NOARGS,
+ "() - Makes a copy of this lamp."},
+ {"copy", ( PyCFunction ) Lamp_copy, METH_NOARGS,
+ "() - Makes a copy of this lamp."},
+ {NULL, NULL, 0, NULL}
+};
+
+/*****************************************************************************/
+/* Python attributes get/set structure: */
+/*****************************************************************************/
+static PyGetSetDef BPy_Lamp_getseters[] = {
+ GENERIC_LIB_GETSETATTR,
+ {"bias",
+ (getter)Lamp_getBias, (setter)Lamp_setBias,
+ "Lamp shadow map sampling bias",
+ NULL},
+ {"bufferSize",
+ (getter)Lamp_getBufferSize, (setter)Lamp_setBufferSize,
+ "Lamp shadow buffer size",
+ NULL},
+ {"clipEnd",
+ (getter)Lamp_getClipEnd, (setter)Lamp_setClipEnd,
+ "Lamp shadow map clip end",
+ NULL},
+ {"clipStart",
+ (getter)Lamp_getClipStart, (setter)Lamp_setClipStart,
+ "Lamp shadow map clip start",
+ NULL},
+ {"col",
+ (getter)Lamp_getCol, (setter)Lamp_setCol,
+ "Lamp RGB color triplet",
+ NULL},
+ {"dist",
+ (getter)Lamp_getDist, (setter)Lamp_setDist,
+ "Lamp clipping distance",
+ NULL},
+ {"energy",
+ (getter)Lamp_getEnergy, (setter)Lamp_setEnergy,
+ "Lamp light intensity",
+ NULL},
+ {"haloInt",
+ (getter)Lamp_getHaloInt, (setter)Lamp_setHaloInt,
+ "Lamp spotlight halo intensity",
+ NULL},
+ {"haloStep",
+ (getter)Lamp_getHaloStep, (setter)Lamp_setHaloStep,
+ "Lamp volumetric halo sampling frequency",
+ NULL},
+ {"ipo",
+ (getter)Lamp_getIpo, (setter)Lamp_setIpo,
+ "Lamp Ipo",
+ NULL},
+ {"mode",
+ (getter)Lamp_getMode, (setter)Lamp_setMode,
+ "Lamp mode bitmask",
+ NULL},
+ {"quad1",
+ (getter)Lamp_getQuad1, (setter)Lamp_setQuad1,
+ "Quad lamp linear distance attenuation",
+ NULL},
+ {"quad2",
+ (getter)Lamp_getQuad2, (setter)Lamp_setQuad2,
+ "Quad lamp quadratic distance attenuation",
+ NULL},
+ {"samples",
+ (getter)Lamp_getSamples, (setter)Lamp_setSamples,
+ "Lamp shadow map samples",
+ NULL},
+ {"raySamplesX",
+ (getter)Lamp_getRaySamplesX, (setter)Lamp_setRaySamplesX,
+ "Lamp raytracing samples on the X axis",
+ NULL},
+ {"raySamplesY",
+ (getter)Lamp_getRaySamplesY, (setter)Lamp_setRaySamplesY,
+ "Lamp raytracing samples on the Y axis",
+ NULL},
+ {"areaSizeX",
+ (getter)Lamp_getAreaSizeX, (setter)Lamp_setAreaSizeX,
+ "Lamp X size for an arealamp",
+ NULL},
+ {"areaSizeY",
+ (getter)Lamp_getAreaSizeY, (setter)Lamp_setAreaSizeY,
+ "Lamp Y size for an arealamp",
+ NULL},
+ {"softness",
+ (getter)Lamp_getSoftness, (setter)Lamp_setSoftness,
+ "Lamp shadow sample area size",
+ NULL},
+ {"spotBlend",
+ (getter)Lamp_getSpotBlend, (setter)Lamp_setSpotBlend,
+ "Lamp spotlight edge softness",
+ NULL},
+ {"spotSize",
+ (getter)Lamp_getSpotSize, (setter)Lamp_setSpotSize,
+ "Lamp spotlight beam angle (in degrees)",
+ NULL},
+ {"type",
+ (getter)Lamp_getType, (setter)Lamp_setType,
+ "Lamp type",
+ NULL},
+ {"R",
+ (getter)Lamp_getComponent, (setter)Lamp_setComponent,
+ "Lamp color red component",
+ (void *)EXPP_LAMP_COMP_R},
+ {"r",
+ (getter)Lamp_getComponent, (setter)Lamp_setComponent,
+ "Lamp color red component",
+ (void *)EXPP_LAMP_COMP_R},
+ {"G",
+ (getter)Lamp_getComponent, (setter)Lamp_setComponent,
+ "Lamp color green component",
+ (void *)EXPP_LAMP_COMP_G},
+ {"g",
+ (getter)Lamp_getComponent, (setter)Lamp_setComponent,
+ "Lamp color green component",
+ (void *)EXPP_LAMP_COMP_G},
+ {"B",
+ (getter)Lamp_getComponent, (setter)Lamp_setComponent,
+ "Lamp color blue component",
+ (void *)EXPP_LAMP_COMP_B},
+ {"b",
+ (getter)Lamp_getComponent, (setter)Lamp_setComponent,
+ "Lamp color blue component",
+ (void *)EXPP_LAMP_COMP_B},
+ {"Modes",
+ (getter)Lamp_getModesConst, (setter)NULL,
+ "Dictionary of values for 'mode' attribute",
+ NULL},
+ {"Types",
+ (getter)Lamp_getTypesConst, (setter)NULL,
+ "Dictionary of values for 'type' attribute",
+ NULL},
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+/*****************************************************************************/
+/* Python TypeLamp callback function prototypes: */
+/*****************************************************************************/
+static void Lamp_dealloc( BPy_Lamp * lamp );
+static int Lamp_compare( BPy_Lamp * a, BPy_Lamp * b );
+static PyObject *Lamp_repr( BPy_Lamp * lamp );
+
+/*****************************************************************************/
+/* Python TypeLamp structure definition: */
+/*****************************************************************************/
+PyTypeObject Lamp_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender Lamp", /* char *tp_name; */
+ sizeof( BPy_Lamp ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ ( destructor ) Lamp_dealloc,/* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ ( cmpfunc ) Lamp_compare, /* cmpfunc tp_compare; */
+ ( reprfunc ) Lamp_repr, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ ( hashfunc ) GenericLib_hash, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_Lamp_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ BPy_Lamp_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+/*****************************************************************************/
+/* Function: M_Lamp_New */
+/* Python equivalent: Blender.Lamp.New */
+/*****************************************************************************/
+static PyObject *M_Lamp_New( PyObject * self, PyObject * args,
+ PyObject * keywords )
+{
+ char *type_str = "Lamp";
+ char *name_str = "Lamp";
+ static char *kwlist[] = { "type_str", "name_str", NULL };
+ BPy_Lamp *py_lamp; /* for Lamp Data object wrapper in Python */
+ Lamp *bl_lamp; /* for actual Lamp Data we create in Blender */
+
+ if( !PyArg_ParseTupleAndKeywords( args, keywords, "|ss", kwlist,
+ &type_str, &name_str ) )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected string(s) or empty argument" ) );
+
+ bl_lamp = add_lamp( name_str ); /* first create in Blender */
+
+ if( bl_lamp ) /* now create the wrapper obj in Python */
+ py_lamp = ( BPy_Lamp * ) Lamp_CreatePyObject( bl_lamp );
+ else
+ return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't create Lamp Data in Blender" ) );
+
+ /* let's return user count to zero, because ... */
+ bl_lamp->id.us = 0; /* ... add_lamp() incref'ed it */
+
+ if( py_lamp == NULL )
+ return ( EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create Lamp Data object" ) );
+
+ if( strcmp( type_str, "Lamp" ) == 0 )
+ bl_lamp->type = ( short ) EXPP_LAMP_TYPE_LAMP;
+ else if( strcmp( type_str, "Sun" ) == 0 )
+ bl_lamp->type = ( short ) EXPP_LAMP_TYPE_SUN;
+ else if( strcmp( type_str, "Spot" ) == 0 )
+ bl_lamp->type = ( short ) EXPP_LAMP_TYPE_SPOT;
+ else if( strcmp( type_str, "Hemi" ) == 0 )
+ bl_lamp->type = ( short ) EXPP_LAMP_TYPE_HEMI;
+ else if( strcmp( type_str, "Area" ) == 0 )
+ bl_lamp->type = ( short ) EXPP_LAMP_TYPE_AREA;
+ else if( strcmp( type_str, "Photon" ) == 0 )
+ bl_lamp->type = ( short ) EXPP_LAMP_TYPE_YF_PHOTON;
+ else
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "unknown lamp type" ) );
+
+ return ( PyObject * ) py_lamp;
+}
+
+/*****************************************************************************/
+/* Function: M_Lamp_Get */
+/* Python equivalent: Blender.Lamp.Get */
+/* Description: Receives a string and returns the lamp data obj */
+/* whose name matches the string. If no argument is */
+/* passed in, a list of all lamp data names in the */
+/* current scene is returned. */
+/*****************************************************************************/
+static PyObject *M_Lamp_Get( PyObject * self, PyObject * args )
+{
+ char *name = NULL;
+ Lamp *lamp_iter;
+
+ if( !PyArg_ParseTuple( args, "|s", &name ) )
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument (or nothing)" ) );
+
+ lamp_iter = G.main->lamp.first;
+
+ if( name ) { /* (name) - Search lamp by name */
+
+ BPy_Lamp *wanted_lamp = NULL;
+
+ while( ( lamp_iter ) && ( wanted_lamp == NULL ) ) {
+
+ if( strcmp( name, lamp_iter->id.name + 2 ) == 0 )
+ wanted_lamp =
+ ( BPy_Lamp * )
+ Lamp_CreatePyObject( lamp_iter );
+
+ lamp_iter = lamp_iter->id.next;
+ }
+
+ if( wanted_lamp == NULL ) { /* Requested lamp doesn't exist */
+ char error_msg[64];
+ PyOS_snprintf( error_msg, sizeof( error_msg ),
+ "Lamp \"%s\" not found", name );
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_NameError, error_msg ) );
+ }
+
+ return ( PyObject * ) wanted_lamp;
+ }
+
+ else { /* () - return a list of all lamps in the scene */
+ int index = 0;
+ PyObject *lamplist, *pyobj;
+
+ lamplist = PyList_New( BLI_countlist( &( G.main->lamp ) ) );
+
+ if( lamplist == NULL )
+ return ( EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create PyList" ) );
+
+ while( lamp_iter ) {
+ pyobj = Lamp_CreatePyObject( lamp_iter );
+
+ if( !pyobj ) {
+ Py_DECREF(lamplist);
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_MemoryError,
+ "couldn't create PyLamp" ) );
+ }
+
+ PyList_SET_ITEM( lamplist, index, pyobj );
+
+ lamp_iter = lamp_iter->id.next;
+ index++;
+ }
+
+ return lamplist;
+ }
+}
+
+static PyObject *Lamp_TypesDict( void )
+{ /* create the Blender.Lamp.Types constant dict */
+ PyObject *Types = PyConstant_New( );
+
+ if( Types ) {
+ BPy_constant *c = ( BPy_constant * ) Types;
+
+ PyConstant_Insert( c, "Lamp",
+ PyInt_FromLong( EXPP_LAMP_TYPE_LAMP ) );
+ PyConstant_Insert( c, "Sun",
+ PyInt_FromLong( EXPP_LAMP_TYPE_SUN ) );
+ PyConstant_Insert( c, "Spot",
+ PyInt_FromLong( EXPP_LAMP_TYPE_SPOT ) );
+ PyConstant_Insert( c, "Hemi",
+ PyInt_FromLong( EXPP_LAMP_TYPE_HEMI ) );
+ PyConstant_Insert( c, "Area",
+ PyInt_FromLong( EXPP_LAMP_TYPE_AREA ) );
+ PyConstant_Insert( c, "Photon",
+ PyInt_FromLong( EXPP_LAMP_TYPE_YF_PHOTON ) );
+ }
+
+ return Types;
+}
+
+static PyObject *Lamp_ModesDict( void )
+{ /* create the Blender.Lamp.Modes constant dict */
+ PyObject *Modes = PyConstant_New( );
+
+ if( Modes ) {
+ BPy_constant *c = ( BPy_constant * ) Modes;
+
+ PyConstant_Insert( c, "Shadows",
+ PyInt_FromLong( EXPP_LAMP_MODE_SHADOWS ) );
+ PyConstant_Insert( c, "Halo",
+ PyInt_FromLong( EXPP_LAMP_MODE_HALO ) );
+ PyConstant_Insert( c, "Layer",
+ PyInt_FromLong( EXPP_LAMP_MODE_LAYER ) );
+ PyConstant_Insert( c, "Quad",
+ PyInt_FromLong( EXPP_LAMP_MODE_QUAD ) );
+ PyConstant_Insert( c, "Negative",
+ PyInt_FromLong( EXPP_LAMP_MODE_NEGATIVE ) );
+ PyConstant_Insert( c, "Sphere",
+ PyInt_FromLong( EXPP_LAMP_MODE_SPHERE ) );
+ PyConstant_Insert( c, "Square",
+ PyInt_FromLong( EXPP_LAMP_MODE_SQUARE ) );
+ PyConstant_Insert( c, "OnlyShadow",
+ PyInt_FromLong( EXPP_LAMP_MODE_ONLYSHADOW ) );
+ PyConstant_Insert( c, "NoDiffuse",
+ PyInt_FromLong( EXPP_LAMP_MODE_NODIFFUSE ) );
+ PyConstant_Insert( c, "NoSpecular",
+ PyInt_FromLong( EXPP_LAMP_MODE_NOSPECULAR ) );
+ PyConstant_Insert( c, "RayShadow",
+ PyInt_FromLong( EXPP_LAMP_MODE_SHAD_RAY ) );
+ }
+
+ return Modes;
+}
+
+/*****************************************************************************/
+/* Function: Lamp_Init */
+/*****************************************************************************/
+/* Needed by the Blender module, to register the Blender.Lamp submodule */
+PyObject *Lamp_Init( void )
+{
+ PyObject *submodule, *Types, *Modes;
+
+ if( PyType_Ready( &Lamp_Type ) < 0)
+ return NULL;
+
+ Types = Lamp_TypesDict( );
+ Modes = Lamp_ModesDict( );
+
+ submodule =
+ Py_InitModule3( "Blender.Lamp", M_Lamp_methods, M_Lamp_doc );
+
+ if( Types )
+ PyModule_AddObject( submodule, "Types", Types );
+ if( Modes )
+ PyModule_AddObject( submodule, "Modes", Modes );
+
+ PyModule_AddIntConstant( submodule, "RGB", IPOKEY_RGB );
+ PyModule_AddIntConstant( submodule, "ENERGY", IPOKEY_ENERGY );
+ PyModule_AddIntConstant( submodule, "SPOTSIZE", IPOKEY_SPOTSIZE );
+ PyModule_AddIntConstant( submodule, "OFFSET", IPOKEY_OFFSET );
+ PyModule_AddIntConstant( submodule, "SIZE", IPOKEY_SIZE );
+
+ return submodule;
+}
+
+/* Three Python Lamp_Type helper functions needed by the Object module: */
+
+/*****************************************************************************/
+/* Function: Lamp_CreatePyObject */
+/* Description: This function will create a new BPy_Lamp from an existing */
+/* Blender lamp structure. */
+/*****************************************************************************/
+PyObject *Lamp_CreatePyObject( Lamp * lamp )
+{
+ BPy_Lamp *pylamp;
+ float *rgb[3];
+
+ pylamp = ( BPy_Lamp * ) PyObject_NEW( BPy_Lamp, &Lamp_Type );
+
+ if( !pylamp )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create BPy_Lamp object" );
+
+ pylamp->lamp = lamp;
+
+ rgb[0] = &lamp->r;
+ rgb[1] = &lamp->g;
+ rgb[2] = &lamp->b;
+
+ pylamp->color = ( BPy_rgbTuple * ) rgbTuple_New( rgb );
+ Py_INCREF(pylamp->color);
+
+ return ( PyObject * ) pylamp;
+}
+
+/*****************************************************************************/
+/* Function: Lamp_FromPyObject */
+/* Description: This function returns the Blender lamp from the given */
+/* PyObject. */
+/*****************************************************************************/
+Lamp *Lamp_FromPyObject( PyObject * pyobj )
+{
+ return ( ( BPy_Lamp * ) pyobj )->lamp;
+}
+
+/*****************************************************************************/
+/* Python BPy_Lamp methods: */
+/*****************************************************************************/
+
+/* Lamp.__copy__ */
+static PyObject *Lamp_copy( BPy_Lamp * self )
+{
+ Lamp *lamp = copy_lamp(self->lamp );
+ lamp->id.us = 0;
+ return Lamp_CreatePyObject(lamp);
+}
+
+static PyObject *Lamp_getType( BPy_Lamp * self )
+{
+ return PyInt_FromLong( self->lamp->type );
+}
+
+static PyObject *Lamp_getMode( BPy_Lamp * self )
+{
+ return PyInt_FromLong( self->lamp->mode );
+}
+
+static PyObject *Lamp_getSamples( BPy_Lamp * self )
+{
+ return PyInt_FromLong( self->lamp->samp );
+}
+
+static PyObject *Lamp_getRaySamplesX( BPy_Lamp * self )
+{
+ return PyInt_FromLong( self->lamp->ray_samp );
+}
+
+static PyObject *Lamp_getRaySamplesY( BPy_Lamp * self )
+{
+ return PyInt_FromLong( self->lamp->ray_sampy );
+}
+
+static PyObject *Lamp_getAreaSizeX( BPy_Lamp * self )
+{
+ return PyFloat_FromDouble( self->lamp->area_size );
+}
+
+static PyObject *Lamp_getAreaSizeY( BPy_Lamp * self )
+{
+ return PyFloat_FromDouble( self->lamp->area_sizey );
+}
+
+static PyObject *Lamp_getBufferSize( BPy_Lamp * self )
+{
+ return PyInt_FromLong( self->lamp->bufsize );
+}
+
+static PyObject *Lamp_getHaloStep( BPy_Lamp * self )
+{
+ return PyInt_FromLong( self->lamp->shadhalostep );
+}
+
+static PyObject *Lamp_getEnergy( BPy_Lamp * self )
+{
+ return PyFloat_FromDouble( self->lamp->energy );
+}
+
+static PyObject *Lamp_getDist( BPy_Lamp * self )
+{
+ return PyFloat_FromDouble( self->lamp->dist );
+}
+
+static PyObject *Lamp_getSpotSize( BPy_Lamp * self )
+{
+ return PyFloat_FromDouble( self->lamp->spotsize );
+}
+
+static PyObject *Lamp_getSpotBlend( BPy_Lamp * self )
+{
+ return PyFloat_FromDouble( self->lamp->spotblend );
+}
+
+static PyObject *Lamp_getClipStart( BPy_Lamp * self )
+{
+ return PyFloat_FromDouble( self->lamp->clipsta );
+}
+
+static PyObject *Lamp_getClipEnd( BPy_Lamp * self )
+{
+ return PyFloat_FromDouble( self->lamp->clipend );
+}
+
+static PyObject *Lamp_getBias( BPy_Lamp * self )
+{
+ return PyFloat_FromDouble( self->lamp->bias );
+}
+
+static PyObject *Lamp_getSoftness( BPy_Lamp * self )
+{
+ return PyFloat_FromDouble( self->lamp->soft );
+}
+
+static PyObject *Lamp_getHaloInt( BPy_Lamp * self )
+{
+ return PyFloat_FromDouble( self->lamp->haint );
+}
+
+static PyObject *Lamp_getQuad1( BPy_Lamp * self )
+{ /* should we complain if Lamp is not of type Quad? */
+ return PyFloat_FromDouble( self->lamp->att1 );
+}
+
+static PyObject *Lamp_getQuad2( BPy_Lamp * self )
+{ /* should we complain if Lamp is not of type Quad? */
+ return PyFloat_FromDouble( self->lamp->att2 );
+}
+
+static PyObject *Lamp_getCol( BPy_Lamp * self )
+{
+ return rgbTuple_getCol( self->color );
+}
+
+static int Lamp_setType( BPy_Lamp * self, PyObject * value )
+{
+ return EXPP_setIValueRange ( value, &self->lamp->type,
+ 0, EXPP_LAMP_TYPE_MAX, 'h' );
+}
+
+static int Lamp_setMode( BPy_Lamp * self, PyObject * value )
+{
+ short param;
+ static short bitmask = EXPP_LAMP_MODE_SHADOWS
+ | EXPP_LAMP_MODE_HALO
+ | EXPP_LAMP_MODE_LAYER
+ | EXPP_LAMP_MODE_QUAD
+ | EXPP_LAMP_MODE_NEGATIVE
+ | EXPP_LAMP_MODE_ONLYSHADOW
+ | EXPP_LAMP_MODE_SPHERE
+ | EXPP_LAMP_MODE_SQUARE
+ | EXPP_LAMP_MODE_NODIFFUSE
+ | EXPP_LAMP_MODE_NOSPECULAR
+ | EXPP_LAMP_MODE_SHAD_RAY;
+
+ if( !PyInt_Check ( value ) ) {
+ char errstr[128];
+ sprintf ( errstr , "expected int bitmask of 0x%04x", bitmask );
+ return EXPP_ReturnIntError( PyExc_TypeError, errstr );
+ }
+ param = (short)PyInt_AS_LONG ( value );
+
+ if ( ( param & bitmask ) != param )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "invalid bit(s) set in mask" );
+
+ self->lamp->mode = param;
+
+ return 0;
+}
+
+static int Lamp_setSamples( BPy_Lamp * self, PyObject * value )
+{
+ return EXPP_setIValueClamped ( value, &self->lamp->samp,
+ EXPP_LAMP_SAMPLES_MIN,
+ EXPP_LAMP_SAMPLES_MAX, 'h' );
+}
+
+
+static int Lamp_setRaySamplesX( BPy_Lamp * self, PyObject * value )
+{
+ return EXPP_setIValueClamped ( value, &self->lamp->ray_samp,
+ EXPP_LAMP_RAYSAMPLES_MIN,
+ EXPP_LAMP_RAYSAMPLES_MAX, 'h' );
+}
+
+static int Lamp_setRaySamplesY( BPy_Lamp * self, PyObject * value )
+{
+ return EXPP_setIValueClamped ( value, &self->lamp->ray_sampy,
+ EXPP_LAMP_RAYSAMPLES_MIN,
+ EXPP_LAMP_RAYSAMPLES_MAX, 'h' );
+}
+
+static int Lamp_setAreaSizeX( BPy_Lamp * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->lamp->area_size,
+ EXPP_LAMP_AREASIZE_MIN,
+ EXPP_LAMP_AREASIZE_MAX );
+}
+
+static int Lamp_setAreaSizeY( BPy_Lamp * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->lamp->area_sizey,
+ EXPP_LAMP_AREASIZE_MIN,
+ EXPP_LAMP_AREASIZE_MAX );
+}
+
+static int Lamp_setBufferSize( BPy_Lamp * self, PyObject * value )
+{
+ return EXPP_setIValueClamped ( value, &self->lamp->bufsize,
+ EXPP_LAMP_BUFFERSIZE_MIN,
+ EXPP_LAMP_BUFFERSIZE_MAX, 'h' );
+}
+
+static int Lamp_setHaloStep( BPy_Lamp * self, PyObject * value )
+{
+ return EXPP_setIValueClamped ( value, &self->lamp->shadhalostep,
+ EXPP_LAMP_HALOSTEP_MIN,
+ EXPP_LAMP_HALOSTEP_MAX, 'h' );
+}
+
+static int Lamp_setEnergy( BPy_Lamp * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->lamp->energy,
+ EXPP_LAMP_ENERGY_MIN,
+ EXPP_LAMP_ENERGY_MAX );
+}
+
+static int Lamp_setDist( BPy_Lamp * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->lamp->dist,
+ EXPP_LAMP_DIST_MIN,
+ EXPP_LAMP_DIST_MAX );
+}
+
+static int Lamp_setSpotSize( BPy_Lamp * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->lamp->spotsize,
+ EXPP_LAMP_SPOTSIZE_MIN,
+ EXPP_LAMP_SPOTSIZE_MAX );
+}
+
+static int Lamp_setSpotBlend( BPy_Lamp * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->lamp->spotblend,
+ EXPP_LAMP_SPOTBLEND_MIN,
+ EXPP_LAMP_SPOTBLEND_MAX );
+}
+
+static int Lamp_setClipStart( BPy_Lamp * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->lamp->clipsta,
+ EXPP_LAMP_CLIPSTART_MIN,
+ EXPP_LAMP_CLIPSTART_MAX );
+}
+
+static int Lamp_setClipEnd( BPy_Lamp * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->lamp->clipend,
+ EXPP_LAMP_CLIPEND_MIN,
+ EXPP_LAMP_CLIPEND_MAX );
+}
+
+static int Lamp_setBias( BPy_Lamp * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->lamp->bias,
+ EXPP_LAMP_BIAS_MIN,
+ EXPP_LAMP_BIAS_MAX );
+}
+
+static int Lamp_setSoftness( BPy_Lamp * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->lamp->soft,
+ EXPP_LAMP_SOFTNESS_MIN,
+ EXPP_LAMP_SOFTNESS_MAX );
+}
+
+static int Lamp_setHaloInt( BPy_Lamp * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->lamp->haint,
+ EXPP_LAMP_HALOINT_MIN,
+ EXPP_LAMP_HALOINT_MAX );
+}
+
+static int Lamp_setQuad1( BPy_Lamp * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->lamp->att1,
+ EXPP_LAMP_QUAD1_MIN,
+ EXPP_LAMP_QUAD1_MAX );
+}
+
+static int Lamp_setQuad2( BPy_Lamp * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->lamp->att2,
+ EXPP_LAMP_QUAD2_MIN,
+ EXPP_LAMP_QUAD2_MAX );
+}
+
+static PyObject *Lamp_getComponent( BPy_Lamp * self, void * closure )
+{
+ switch ( (int)closure ) {
+ case EXPP_LAMP_COMP_R:
+ return PyFloat_FromDouble( self->lamp->r );
+ case EXPP_LAMP_COMP_G:
+ return PyFloat_FromDouble( self->lamp->g );
+ case EXPP_LAMP_COMP_B:
+ return PyFloat_FromDouble( self->lamp->b );
+ default:
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "unknown color component specified" );
+ }
+}
+
+static int Lamp_setComponent( BPy_Lamp * self, PyObject * value,
+ void * closure )
+{
+ float color;
+
+ if( !PyNumber_Check ( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected float argument in [0.0,1.0]" );
+
+ color = (float)PyFloat_AsDouble( value );
+ color = EXPP_ClampFloat( color, EXPP_LAMP_COL_MIN, EXPP_LAMP_COL_MAX );
+
+ switch ( (int)closure ) {
+ case EXPP_LAMP_COMP_R:
+ self->lamp->r = color;
+ return 0;
+ case EXPP_LAMP_COMP_G:
+ self->lamp->g = color;
+ return 0;
+ case EXPP_LAMP_COMP_B:
+ self->lamp->b = color;
+ return 0;
+ }
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "unknown color component specified" );
+}
+
+static int Lamp_setCol( BPy_Lamp * self, PyObject * args )
+{
+ return rgbTuple_setCol( self->color, args );
+}
+
+/* lamp.addScriptLink */
+static PyObject *Lamp_addScriptLink( BPy_Lamp * self, PyObject * args )
+{
+ Lamp *lamp = self->lamp;
+ ScriptLink *slink = NULL;
+
+ slink = &( lamp )->scriptlink;
+
+ return EXPP_addScriptLink( slink, args, 0 );
+}
+
+/* lamp.clearScriptLinks */
+static PyObject *Lamp_clearScriptLinks( BPy_Lamp * self, PyObject * args )
+{
+ Lamp *lamp = self->lamp;
+ ScriptLink *slink = NULL;
+
+ slink = &( lamp )->scriptlink;
+
+ return EXPP_clearScriptLinks( slink, args );
+}
+
+/* mat.getScriptLinks */
+static PyObject *Lamp_getScriptLinks( BPy_Lamp * self, PyObject * value )
+{
+ Lamp *lamp = self->lamp;
+ ScriptLink *slink = NULL;
+ PyObject *ret = NULL;
+
+ slink = &( lamp )->scriptlink;
+
+ ret = EXPP_getScriptLinks( slink, value, 0 );
+
+ if( ret )
+ return ret;
+ else
+ return NULL;
+}
+
+/*****************************************************************************/
+/* Function: Lamp_dealloc */
+/* Description: This is a callback function for the BPy_Lamp type. It is */
+/* the destructor function. */
+/*****************************************************************************/
+static void Lamp_dealloc( BPy_Lamp * self )
+{
+ Py_DECREF( self->color );
+ PyObject_DEL( self );
+}
+
+/*****************************************************************************/
+/* Function: Lamp_compare */
+/* Description: This is a callback function for the BPy_Lamp type. It */
+/* compares two Lamp_Type objects. Only the "==" and "!=" */
+/* comparisons are meaningful. Returns 0 for equality and -1 */
+/* if they don't point to the same Blender Lamp struct. */
+/* In Python it becomes 1 if they are equal, 0 otherwise. */
+/*****************************************************************************/
+static int Lamp_compare( BPy_Lamp * a, BPy_Lamp * b )
+{
+ return ( a->lamp == b->lamp ) ? 0 : -1;
+}
+
+/*****************************************************************************/
+/* Function: Lamp_repr */
+/* Description: This is a callback function for the BPy_Lamp type. It */
+/* builds a meaninful string to represent lamp objects. */
+/*****************************************************************************/
+static PyObject *Lamp_repr( BPy_Lamp * self )
+{
+ return PyString_FromFormat( "[Lamp \"%s\"]", self->lamp->id.name + 2 );
+}
+
+static PyObject *Lamp_getIpo( BPy_Lamp * self )
+{
+ struct Ipo *ipo = self->lamp->ipo;
+
+ if( !ipo )
+ Py_RETURN_NONE;
+
+ return Ipo_CreatePyObject( ipo );
+}
+
+/*
+ * this should accept a Py_None argument and just delete the Ipo link
+ * (as Lamp_clearIpo() does)
+ */
+
+static int Lamp_setIpo( BPy_Lamp * self, PyObject * value )
+{
+ return GenericLib_assignData(value, (void **) &self->lamp->ipo, 0, 1, ID_IP, ID_LA);
+}
+
+/*
+ * Lamp_insertIpoKey()
+ * inserts Lamp IPO key for RGB,ENERGY,SPOTSIZE,OFFSET,SIZE
+ */
+
+static PyObject *Lamp_insertIpoKey( BPy_Lamp * self, PyObject * args )
+{
+ int key = 0, map;
+
+ if( !PyArg_ParseTuple( args, "i", &( key ) ) )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected int argument" ) );
+
+ map = texchannel_to_adrcode(self->lamp->texact);
+
+ if (key == IPOKEY_RGB ) {
+ insertkey((ID *)self->lamp, ID_LA, NULL, NULL, LA_COL_R, 0);
+ insertkey((ID *)self->lamp, ID_LA, NULL, NULL,LA_COL_G, 0);
+ insertkey((ID *)self->lamp, ID_LA, NULL, NULL,LA_COL_B, 0);
+ }
+ if (key == IPOKEY_ENERGY ) {
+ insertkey((ID *)self->lamp, ID_LA, NULL, NULL,LA_ENERGY, 0);
+ }
+ if (key == IPOKEY_SPOTSIZE ) {
+ insertkey((ID *)self->lamp, ID_LA, NULL, NULL,LA_SPOTSI, 0);
+ }
+ if (key == IPOKEY_OFFSET ) {
+ insertkey((ID *)self->lamp, ID_LA, NULL, NULL, map+MAP_OFS_X, 0);
+ insertkey((ID *)self->lamp, ID_LA, NULL, NULL, map+MAP_OFS_Y, 0);
+ insertkey((ID *)self->lamp, ID_LA, NULL, NULL, map+MAP_OFS_Z, 0);
+ }
+ if (key == IPOKEY_SIZE ) {
+ insertkey((ID *)self->lamp, ID_LA, NULL, NULL, map+MAP_SIZE_X, 0);
+ insertkey((ID *)self->lamp, ID_LA, NULL, NULL, map+MAP_SIZE_Y, 0);
+ insertkey((ID *)self->lamp, ID_LA, NULL, NULL, map+MAP_SIZE_Z, 0);
+ }
+
+ allspace(REMAKEIPO, 0);
+ EXPP_allqueue(REDRAWIPO, 0);
+ EXPP_allqueue(REDRAWVIEW3D, 0);
+ EXPP_allqueue(REDRAWACTION, 0);
+ EXPP_allqueue(REDRAWNLA, 0);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Lamp_getModesConst( void )
+{
+ return Py_BuildValue
+ ( "{s:h,s:h,s:h,s:h,s:h,s:h,s:h,s:h,s:h,s:h,s:h}",
+ "Shadows", EXPP_LAMP_MODE_SHADOWS, "Halo",
+ EXPP_LAMP_MODE_HALO, "Layer", EXPP_LAMP_MODE_LAYER,
+ "Quad", EXPP_LAMP_MODE_QUAD, "Negative",
+ EXPP_LAMP_MODE_NEGATIVE, "OnlyShadow",
+ EXPP_LAMP_MODE_ONLYSHADOW, "Sphere",
+ EXPP_LAMP_MODE_SPHERE, "Square",
+ EXPP_LAMP_MODE_SQUARE, "NoDiffuse",
+ EXPP_LAMP_MODE_NODIFFUSE, "NoSpecular",
+ EXPP_LAMP_MODE_NOSPECULAR, "RayShadow",
+ EXPP_LAMP_MODE_SHAD_RAY);
+}
+
+static PyObject *Lamp_getTypesConst( void )
+{
+ return Py_BuildValue( "{s:h,s:h,s:h,s:h,s:h,s:h}",
+ "Lamp", EXPP_LAMP_TYPE_LAMP,
+ "Sun", EXPP_LAMP_TYPE_SUN,
+ "Spot", EXPP_LAMP_TYPE_SPOT,
+ "Hemi", EXPP_LAMP_TYPE_HEMI,
+ "Area", EXPP_LAMP_TYPE_AREA,
+ "Photon", EXPP_LAMP_TYPE_YF_PHOTON );
+}
+
+/* #####DEPRECATED###### */
+
+static PyObject *Lamp_oldsetSamples( BPy_Lamp * self, PyObject * args )
+{
+ return EXPP_setterWrapper ( (void *)self, args, (setter)Lamp_setSamples );
+}
+
+static PyObject *Lamp_oldsetRaySamplesX( BPy_Lamp * self, PyObject * args )
+{
+ return EXPP_setterWrapper ( (void *)self, args, (setter)Lamp_setRaySamplesX );
+}
+
+static PyObject *Lamp_oldsetRaySamplesY( BPy_Lamp * self, PyObject * args )
+{
+ return EXPP_setterWrapper ( (void *)self, args, (setter)Lamp_setRaySamplesY );
+}
+
+static PyObject *Lamp_oldsetAreaSizeX( BPy_Lamp * self, PyObject * args )
+{
+ return EXPP_setterWrapper ( (void *)self, args, (setter)Lamp_setAreaSizeX );
+}
+
+static PyObject *Lamp_oldsetAreaSizeY( BPy_Lamp * self, PyObject * args )
+{
+ return EXPP_setterWrapper ( (void *)self, args, (setter)Lamp_setAreaSizeY );
+}
+
+static PyObject *Lamp_oldsetBufferSize( BPy_Lamp * self, PyObject * args )
+{
+ return EXPP_setterWrapper ( (void *)self, args, (setter)Lamp_setBufferSize );
+}
+
+static PyObject *Lamp_oldsetHaloStep( BPy_Lamp * self, PyObject * args )
+{
+ return EXPP_setterWrapper ( (void *)self, args, (setter)Lamp_setHaloStep );
+}
+
+static PyObject *Lamp_oldsetEnergy( BPy_Lamp * self, PyObject * args )
+{
+ return EXPP_setterWrapper ( (void *)self, args, (setter)Lamp_setEnergy );
+}
+
+static PyObject *Lamp_oldsetDist( BPy_Lamp * self, PyObject * args )
+{
+ return EXPP_setterWrapper ( (void *)self, args, (setter)Lamp_setDist );
+}
+
+static PyObject *Lamp_oldsetSpotSize( BPy_Lamp * self, PyObject * args )
+{
+ return EXPP_setterWrapper ( (void *)self, args, (setter)Lamp_setSpotSize );
+}
+
+static PyObject *Lamp_oldsetSpotBlend( BPy_Lamp * self, PyObject * args )
+{
+ return EXPP_setterWrapper ( (void *)self, args, (setter)Lamp_setSpotBlend );
+}
+
+static PyObject *Lamp_oldsetClipStart( BPy_Lamp * self, PyObject * args )
+{
+ return EXPP_setterWrapper ( (void *)self, args, (setter)Lamp_setClipStart );
+}
+
+static PyObject *Lamp_oldsetClipEnd( BPy_Lamp * self, PyObject * args )
+{
+ return EXPP_setterWrapper ( (void *)self, args, (setter)Lamp_setClipEnd );
+}
+
+static PyObject *Lamp_oldsetBias( BPy_Lamp * self, PyObject * args )
+{
+ return EXPP_setterWrapper ( (void *)self, args, (setter)Lamp_setBias );
+}
+
+static PyObject *Lamp_oldsetSoftness( BPy_Lamp * self, PyObject * args )
+{
+ return EXPP_setterWrapper ( (void *)self, args, (setter)Lamp_setSoftness );
+}
+
+static PyObject *Lamp_oldsetHaloInt( BPy_Lamp * self, PyObject * args )
+{
+ return EXPP_setterWrapper ( (void *)self, args, (setter)Lamp_setHaloInt );
+}
+
+static PyObject *Lamp_oldsetQuad1( BPy_Lamp * self, PyObject * args )
+{
+ return EXPP_setterWrapper ( (void *)self, args, (setter)Lamp_setQuad1 );
+}
+
+static PyObject *Lamp_oldsetQuad2( BPy_Lamp * self, PyObject * args )
+{
+ return EXPP_setterWrapper ( (void *)self, args, (setter)Lamp_setQuad2 );
+}
+
+static PyObject *Lamp_oldsetIpo( BPy_Lamp * self, PyObject * args )
+{
+ return EXPP_setterWrapper ( (void *)self, args, (setter)Lamp_setIpo );
+}
+
+static PyObject *Lamp_oldsetCol( BPy_Lamp * self, PyObject * args )
+{
+ return EXPP_setterWrapper ( (void *)self, args, (setter)Lamp_setCol );
+}
+
+/*
+ * the "not-well-behaved" methods which require more processing than
+ * just the simple wrapper
+ */
+
+/*
+ * clearIpo() returns True/False depending on whether lamp has an Ipo
+ */
+
+static PyObject *Lamp_clearIpo( BPy_Lamp * self )
+{
+ /* if Ipo defined, delete it and return true */
+
+ if( self->lamp->ipo ) {
+ PyObject *value = Py_BuildValue( "(O)", Py_None );
+ EXPP_setterWrapper ( (void *)self, value, (setter)Lamp_setIpo );
+ Py_DECREF ( value );
+ return EXPP_incr_ret_True();
+ }
+ return EXPP_incr_ret_False(); /* no ipo found */
+}
+
+/*
+ * setType() accepts a string while mode setter takes an integer
+ */
+
+static PyObject *Lamp_oldsetType( BPy_Lamp * self, PyObject * value )
+{
+ char *type = PyString_AsString(value);
+ PyObject *arg, *error;
+
+ /* parse string argument */
+
+ if( !value )
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument" ) );
+
+ /* check for valid arguments, set type accordingly */
+
+ if( !strcmp( type, "Lamp" ) )
+ self->lamp->type = ( short ) EXPP_LAMP_TYPE_LAMP;
+ else if( !strcmp( type, "Sun" ) )
+ self->lamp->type = ( short ) EXPP_LAMP_TYPE_SUN;
+ else if( !strcmp( type, "Spot" ) )
+ self->lamp->type = ( short ) EXPP_LAMP_TYPE_SPOT;
+ else if( !strcmp( type, "Hemi" ) )
+ self->lamp->type = ( short ) EXPP_LAMP_TYPE_HEMI;
+ else if( !strcmp( type, "Area" ) )
+ self->lamp->type = ( short ) EXPP_LAMP_TYPE_AREA;
+ else if( !strcmp( type, "Photon" ) )
+ self->lamp->type = ( short ) EXPP_LAMP_TYPE_YF_PHOTON;
+ else
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "unknown lamp type" );
+
+ /* build tuple, call wrapper */
+
+ arg = PyInt_FromLong( (long)type );
+ error = EXPP_setterWrapper ( (void *)self, arg, (setter)Lamp_setType );
+ Py_DECREF ( arg );
+ return error;
+}
+
+/*
+ * setMode() accepts up to ten strings while mode setter takes an integer
+ */
+
+static PyObject *Lamp_oldsetMode( BPy_Lamp * self, PyObject * args )
+{
+ short i, flag = 0;
+ PyObject *error, *value;
+ char *name;
+
+ /* check that we're passed a tuple of no more than 10 args*/
+
+ if ( !PyTuple_Check( args ) || PyTuple_Size( args ) > 10 )
+ return EXPP_ReturnPyObjError ( PyExc_AttributeError,
+ "expected up to 10 string arguments" );
+
+ /* check each argument for type, find its value */
+
+ for ( i = (short)PyTuple_Size( args ); i-- ; ) {
+ name = PyString_AsString ( PyTuple_GET_ITEM( args, i ) );
+ if( !name )
+ return EXPP_ReturnPyObjError ( PyExc_AttributeError,
+ "expected string argument" );
+
+ if( !strcmp( name, "Shadows" ) )
+ flag |= ( short ) EXPP_LAMP_MODE_SHADOWS;
+ else if( !strcmp( name, "Halo" ) )
+ flag |= ( short ) EXPP_LAMP_MODE_HALO;
+ else if( !strcmp( name, "Layer" ) )
+ flag |= ( short ) EXPP_LAMP_MODE_LAYER;
+ else if( !strcmp( name, "Quad" ) )
+ flag |= ( short ) EXPP_LAMP_MODE_QUAD;
+ else if( !strcmp( name, "Negative" ) )
+ flag |= ( short ) EXPP_LAMP_MODE_NEGATIVE;
+ else if( !strcmp( name, "OnlyShadow" ) )
+ flag |= ( short ) EXPP_LAMP_MODE_ONLYSHADOW;
+ else if( !strcmp( name, "Sphere" ) )
+ flag |= ( short ) EXPP_LAMP_MODE_SPHERE;
+ else if( !strcmp( name, "Square" ) )
+ flag |= ( short ) EXPP_LAMP_MODE_SQUARE;
+ else if( !strcmp( name, "NoDiffuse" ) )
+ flag |= ( short ) EXPP_LAMP_MODE_NODIFFUSE;
+ else if( !strcmp( name, "NoSpecular" ) )
+ flag |= ( short ) EXPP_LAMP_MODE_NOSPECULAR;
+ else if( !strcmp( name, "RayShadow" ) )
+ flag |= ( short ) EXPP_LAMP_MODE_SHAD_RAY;
+ else
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "unknown lamp flag argument" );
+ }
+
+ /* build tuple, call wrapper */
+
+ value = PyInt_FromLong( (long)flag );
+ error = EXPP_setterWrapper ( (void *)self, value, (setter)Lamp_setMode );
+ Py_DECREF ( value );
+ return error;
+}
+
diff --git a/source/blender/python/api2_2x/Lamp.h b/source/blender/python/api2_2x/Lamp.h
new file mode 100644
index 00000000000..3ad6348a152
--- /dev/null
+++ b/source/blender/python/api2_2x/Lamp.h
@@ -0,0 +1,61 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano, Nathan Letwory
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_LAMP_H
+#define EXPP_LAMP_H
+
+#include <Python.h>
+#include "DNA_lamp_types.h"
+#include "rgbTuple.h"
+
+extern PyTypeObject Lamp_Type;
+
+#define BPy_Lamp_Check(v) \
+ ((v)->ob_type == &Lamp_Type) /* for type checking */
+
+/* Python BPy_Lamp structure definition */
+typedef struct {
+ PyObject_HEAD /* required py macro */
+ Lamp * lamp; /* libdata must be second */
+ BPy_rgbTuple *color;
+} BPy_Lamp;
+
+
+/*
+ * prototypes
+ */
+
+PyObject *Lamp_Init( void );
+PyObject *Lamp_CreatePyObject( struct Lamp *lamp );
+Lamp *Lamp_FromPyObject( PyObject * pyobj );
+
+#endif /* EXPP_LAMP_H */
diff --git a/source/blender/python/api2_2x/Lattice.c b/source/blender/python/api2_2x/Lattice.c
new file mode 100644
index 00000000000..070e8225531
--- /dev/null
+++ b/source/blender/python/api2_2x/Lattice.c
@@ -0,0 +1,813 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Joseph Gilbert
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "Lattice.h" /*This must come first*/
+
+#include "BKE_utildefines.h"
+#include "BKE_main.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_lattice.h"
+#include "BLI_blenlib.h"
+#include "DNA_object_types.h"
+#include "DNA_key_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_scene_types.h"
+#include "BIF_editkey.h"
+#include "BIF_editdeform.h"
+#include "BIF_space.h"
+#include "blendef.h"
+#include "gen_utils.h"
+#include "gen_library.h"
+
+#include "Key.h"
+
+/*****************************************************************************/
+/* Python API function prototypes for the Lattice module. */
+/*****************************************************************************/
+static PyObject *M_Lattice_New( PyObject * self, PyObject * args );
+static PyObject *M_Lattice_Get( PyObject * self, PyObject * args );
+
+/*****************************************************************************/
+/* Lattice Module strings */
+/* The following string definitions are used for documentation strings. */
+/* In Python these will be written to the console when doing a */
+/* Blender.Lattice.__doc__ */
+/*****************************************************************************/
+static char M_Lattice_doc[] = "The Blender Lattice module\n\n";
+
+static char M_Lattice_New_doc[] = "() - return a new Lattice object";
+
+static char M_Lattice_Get_doc[] = "() - get a Lattice from blender";
+
+/*****************************************************************************/
+/* Python method structure definition for Blender.Lattice module: */
+/*****************************************************************************/
+struct PyMethodDef M_Lattice_methods[] = {
+ {"New", ( PyCFunction ) M_Lattice_New, METH_VARARGS,
+ M_Lattice_New_doc},
+ {"Get", ( PyCFunction ) M_Lattice_Get, METH_VARARGS,
+ M_Lattice_Get_doc},
+ {NULL, NULL, 0, NULL}
+};
+
+
+/*****************************************************************************/
+/* Lattice Strings */
+/* The following string definitions are used for documentation strings. */
+/* In Python these will be written to the console when doing a */
+/* Blender.Lattice.__doc__ */
+/*****************************************************************************/
+static char Lattice_getName_doc[] = "() - Return Lattice Object name";
+
+static char Lattice_setName_doc[] = "(str) - Change Lattice Object name";
+
+static char Lattice_setPartitions_doc[] =
+ "(str) - Set the number of Partitions in x,y,z";
+
+static char Lattice_getPartitions_doc[] =
+ "(str) - Get the number of Partitions in x,y,z";
+
+static char Lattice_getKey_doc[] =
+ "() - Get the Key object attached to this Lattice";
+
+static char Lattice_setKeyTypes_doc[] =
+ "(str) - Set the key types for x,y,z dimensions";
+
+static char Lattice_getKeyTypes_doc[] =
+ "(str) - Get the key types for x,y,z dimensions";
+
+static char Lattice_setMode_doc[] = "(str) - Make an outside or grid lattice";
+
+static char Lattice_getMode_doc[] = "(str) - Get lattice mode type";
+
+static char Lattice_setPoint_doc[] =
+ "(str) - Set the coordinates of a point on the lattice";
+
+static char Lattice_getPoint_doc[] =
+ "(str) - Get the coordinates of a point on the lattice";
+
+static char Lattice_insertKey_doc[] =
+ "(str) - Set a new key for the lattice at specified frame";
+
+static char Lattice_copy_doc[] =
+ "() - Return a copy of the lattice.";
+
+//***************************************************************************
+// Function: Lattice_CreatePyObject
+//***************************************************************************
+PyObject *Lattice_CreatePyObject( Lattice * lt )
+{
+ BPy_Lattice *pyLat;
+
+ pyLat = ( BPy_Lattice * ) PyObject_NEW( BPy_Lattice, &Lattice_Type );
+
+ if( !pyLat )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create BPy_Lattice PyObject" );
+
+ pyLat->lattice = lt;
+
+ return ( PyObject * ) pyLat;
+}
+
+//***************************************************************************
+// Function: Lattice_FromPyObject
+//***************************************************************************
+
+Lattice *Lattice_FromPyObject( PyObject * pyobj )
+{
+ return ( ( BPy_Lattice * ) pyobj )->lattice;
+}
+
+//***************************************************************************
+// Function: M_Lattice_New
+// Python equivalent: Blender.Lattice.New
+//***************************************************************************
+static PyObject *M_Lattice_New( PyObject * self, PyObject * args )
+{
+ char *name = NULL;
+ Lattice *bl_Lattice; // blender Lattice object
+ PyObject *py_Lattice; // python wrapper
+
+ if( !PyArg_ParseTuple( args, "|s", &name ) )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected string and int arguments (or nothing)" );
+
+ bl_Lattice = add_lattice( "Lattice" );
+
+ if( bl_Lattice ) {
+ bl_Lattice->id.us = 0;
+ py_Lattice = Lattice_CreatePyObject( bl_Lattice );
+ } else
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't create Lattice Object in Blender" );
+ if( !py_Lattice )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create Lattice Object wrapper" );
+
+ if( name )
+ rename_id( &bl_Lattice->id, name );
+
+ return py_Lattice;
+}
+
+//***************************************************************************
+// Function: M_Lattice_Get
+// Python equivalent: Blender.Lattice.Get
+//***************************************************************************
+static PyObject *M_Lattice_Get( PyObject * self, PyObject * args )
+{
+ char *name = NULL;
+ Lattice *lat_iter;
+
+ if( !PyArg_ParseTuple( args, "|s", &name ) )
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument (or nothing)" ) );
+
+ lat_iter = G.main->latt.first;
+
+ if( name ) { /* (name) - Search Lattice by name */
+
+ PyObject *wanted_lat = NULL;
+
+ while( ( lat_iter ) && ( wanted_lat == NULL ) ) {
+ if( strcmp( name, lat_iter->id.name + 2 ) == 0 ) {
+ wanted_lat =
+ Lattice_CreatePyObject( lat_iter );
+ }
+
+ lat_iter = lat_iter->id.next;
+ }
+
+ if( wanted_lat == NULL ) { /* Requested Lattice doesn't exist */
+ char error_msg[64];
+ PyOS_snprintf( error_msg, sizeof( error_msg ),
+ "Lattice \"%s\" not found", name );
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_NameError, error_msg ) );
+ }
+
+ return wanted_lat;
+ }
+
+ else { /* () - return a list of all Lattices in the scene */
+ int index = 0;
+ PyObject *latlist, *pyobj;
+
+ latlist = PyList_New( BLI_countlist( &( G.main->latt ) ) );
+
+ if( latlist == NULL )
+ return ( EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create PyList" ) );
+
+ while( lat_iter ) {
+ pyobj = Lattice_CreatePyObject( lat_iter );
+
+ if( !pyobj ) {
+ Py_DECREF(latlist);
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_MemoryError,
+ "couldn't create PyString" ) );
+ }
+ PyList_SET_ITEM( latlist, index, pyobj );
+
+ lat_iter = lat_iter->id.next;
+ index++;
+ }
+
+ return ( latlist );
+ }
+}
+
+//***************************************************************************
+// Function: Lattice_Init
+//***************************************************************************
+PyObject *Lattice_Init( void )
+{
+ PyObject *mod;
+ PyObject *dict;
+
+ if( PyType_Ready( &Lattice_Type ) < 0 )
+ return NULL;
+
+ mod = Py_InitModule3( "Blender.Lattice", M_Lattice_methods,
+ M_Lattice_doc );
+
+ dict = PyModule_GetDict( mod );
+
+ //Module dictionary
+#define EXPP_ADDCONST(x) EXPP_dict_set_item_str(dict, #x, PyInt_FromLong(LT_##x))
+ EXPP_ADDCONST( GRID );
+ EXPP_ADDCONST( OUTSIDE );
+
+#undef EXPP_ADDCONST
+#define EXPP_ADDCONST(x) EXPP_dict_set_item_str(dict, #x, PyInt_FromLong(KEY_##x))
+ EXPP_ADDCONST( LINEAR );
+ EXPP_ADDCONST( CARDINAL );
+ EXPP_ADDCONST( BSPLINE );
+
+ return ( mod );
+}
+
+static PyObject *Lattice_setPartitions( BPy_Lattice * self, PyObject * args )
+{
+ int x = 0;
+ int y = 0;
+ int z = 0;
+ Lattice *bl_Lattice;
+
+ if( !PyArg_ParseTuple( args, "iii", &x, &y, &z ) )
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected int,int,int argument" ) );
+
+ bl_Lattice = self->lattice;
+
+ if( x < 2 || y < 2 || z < 2 )
+ return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "partition values must be 2 or greater" ) );
+
+ resizelattice(bl_Lattice, x, y, z, NULL);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Lattice_getPartitions( BPy_Lattice * self )
+{
+ Lattice *bl_Lattice;
+ bl_Lattice = self->lattice;
+
+ return Py_BuildValue( "[i,i,i]", ( int ) bl_Lattice->pntsu,
+ ( int ) bl_Lattice->pntsv,
+ ( int ) bl_Lattice->pntsw );
+}
+
+static PyObject *Lattice_getKey( BPy_Lattice * self )
+{
+ Key *key = self->lattice->key;
+
+ if (key)
+ return Key_CreatePyObject(key);
+ else
+ Py_RETURN_NONE;
+}
+
+static PyObject *Lattice_getKeyTypes( BPy_Lattice * self )
+{
+ Lattice *bl_Lattice;
+ char *linear = "linear";
+ char *cardinal = "cardinal";
+ char *bspline = "bspline";
+ char *s_x = NULL, *s_y = NULL, *s_z = NULL;
+
+ bl_Lattice = self->lattice;
+
+ if( ( bl_Lattice->typeu ) == KEY_LINEAR )
+ s_x = linear;
+ else if( ( bl_Lattice->typeu ) == KEY_CARDINAL )
+ s_x = cardinal;
+ else if( ( bl_Lattice->typeu ) == KEY_BSPLINE )
+ s_x = bspline;
+ else
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "bad key type..." );
+
+ if( ( bl_Lattice->typev ) == KEY_LINEAR )
+ s_y = linear;
+ else if( ( bl_Lattice->typev ) == KEY_CARDINAL )
+ s_y = cardinal;
+ else if( ( bl_Lattice->typev ) == KEY_BSPLINE )
+ s_y = bspline;
+ else
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "bad key type..." );
+
+ if( ( bl_Lattice->typew ) == KEY_LINEAR )
+ s_z = linear;
+ else if( ( bl_Lattice->typew ) == KEY_CARDINAL )
+ s_z = cardinal;
+ else if( ( bl_Lattice->typew ) == KEY_BSPLINE )
+ s_z = bspline;
+ else
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "bad key type..." );
+
+ /* we made sure no s_[xyz] is NULL */
+ return Py_BuildValue( "[s,s,s]", s_x, s_y, s_z );
+}
+
+static PyObject *Lattice_setKeyTypes( BPy_Lattice * self, PyObject * args )
+{
+ int x;
+ int y;
+ int z;
+ Lattice *bl_Lattice;
+
+ if( !PyArg_ParseTuple( args, "iii", &x, &y, &z ) )
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected int,int,int argument" ) );
+
+ bl_Lattice = self->lattice;
+
+ if( x == KEY_LINEAR )
+ bl_Lattice->typeu = KEY_LINEAR;
+ else if( x == KEY_CARDINAL )
+ bl_Lattice->typeu = KEY_CARDINAL;
+ else if( x == KEY_BSPLINE )
+ bl_Lattice->typeu = KEY_BSPLINE;
+ else
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "type must be LINEAR, CARDINAL OR BSPLINE" );
+
+ if( y == KEY_LINEAR )
+ bl_Lattice->typev = KEY_LINEAR;
+ else if( y == KEY_CARDINAL )
+ bl_Lattice->typev = KEY_CARDINAL;
+ else if( y == KEY_BSPLINE )
+ bl_Lattice->typev = KEY_BSPLINE;
+ else
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "type must be LINEAR, CARDINAL OR BSPLINE" );
+
+ if( z == KEY_LINEAR )
+ bl_Lattice->typew = KEY_LINEAR;
+ else if( z == KEY_CARDINAL )
+ bl_Lattice->typew = KEY_CARDINAL;
+ else if( z == KEY_BSPLINE )
+ bl_Lattice->typew = KEY_BSPLINE;
+ else
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "type must be LINEAR, CARDINAL OR BSPLINE" );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Lattice_setMode( BPy_Lattice * self, PyObject * args )
+{
+ short type;
+ Lattice *bl_Lattice;
+ bl_Lattice = self->lattice;
+
+ if( !PyArg_ParseTuple( args, "h", &type ) )
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected int argument" ) );
+
+ if( type == LT_GRID )
+ bl_Lattice->flag = LT_GRID;
+ else if( type == LT_OUTSIDE ) {
+ bl_Lattice->flag = LT_OUTSIDE + LT_GRID;
+ outside_lattice( bl_Lattice );
+ } else
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "type must be either GRID or OUTSIDE" );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Lattice_getMode(BPy_Lattice * self)
+{
+ if( self->lattice->flag == 1 )
+ return PyString_FromString( "Grid" );
+ else if( self->lattice->flag == 3 )
+ return PyString_FromString( "Outside" );
+ Py_RETURN_NONE;
+}
+
+static PyObject *Lattice_setPoint( BPy_Lattice * self, PyObject * args )
+{
+ BPoint *bp, *bpoint;
+ short size;
+ Lattice *bl_Lattice;
+ int index, x;
+ float tempInt;
+ PyObject *listObject;
+
+ if( !PyArg_ParseTuple
+ ( args, "iO!", &index, &PyList_Type, &listObject ) )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_TypeError, "expected int & list argument" ) );
+
+ if( !PyList_Check( listObject ) )
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "2nd parameter should be a python list" ) );
+
+ if( !( PyList_Size( listObject ) == 3 ) )
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "Please pass 3 parameters in the list [x,y,z]" ) );
+
+ //init
+ bp = 0;
+ bl_Lattice = self->lattice;
+
+ //get bpoints
+ bp = bl_Lattice->def;
+
+ if( bp == 0 )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "no lattice points!" ) );
+
+ //calculate size of lattice
+ size = bl_Lattice->pntsu * bl_Lattice->pntsv * bl_Lattice->pntsw;
+
+ if( index < 0 || index > size )
+ return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "index outside of lattice size!" ) );
+
+ //get the bpoint
+ while( index ) {
+ index--;
+ bp++;
+ }
+ bpoint = bp;
+
+ for( x = 0; x < PyList_Size( listObject ); x++ ) {
+ if( !
+ ( PyArg_Parse
+ ( ( PyList_GetItem( listObject, x ) ), "f",
+ &tempInt ) ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "python list integer not parseable" );
+ bpoint->vec[x] = tempInt;
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Lattice_getPoint( BPy_Lattice * self, PyObject * args )
+{
+ BPoint *bp, *bpoint;
+ short size;
+ Lattice *bl_Lattice;
+ int index;
+
+ if( !PyArg_ParseTuple( args, "i", &index ) )
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected int argument" ) );
+
+ //init
+ bp = 0;
+ bl_Lattice = self->lattice;
+
+ //get bpoints
+ bp = bl_Lattice->def;
+
+ if( bp == 0 )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "no lattice points!" ) );
+
+ //calculate size of lattice
+ size = bl_Lattice->pntsu * bl_Lattice->pntsv * bl_Lattice->pntsw;
+
+ if( index < 0 || index > size )
+ return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "index outside of lattice size!" ) );
+
+ //get the bpoint
+ while( index ) {
+ index--;
+ bp++;
+ }
+ bpoint = bp;
+
+ if( bpoint == 0 )
+ return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "bpoint does not exist" ) );
+
+ return Py_BuildValue( "[f,f,f]", bp->vec[0], bp->vec[1], bp->vec[2] );
+}
+
+static PyObject *Lattice_insertKey( BPy_Lattice * self, PyObject * args )
+{
+ Lattice *lt;
+ int frame = -1, oldfra = -1;
+
+ if( !PyArg_ParseTuple( args, "i", &frame ) )
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected int argument" ) );
+
+ lt = self->lattice;
+
+ //set the current frame
+ if( frame > 0 ) {
+ frame = EXPP_ClampInt( frame, 1, MAXFRAME );
+ oldfra = G.scene->r.cfra;
+ G.scene->r.cfra = (int)frame;
+ }
+// else just use current frame, then
+// return (EXPP_ReturnPyObjError (PyExc_RuntimeError,
+// "frame value has to be greater than 0"));
+
+ //insert a keybock for the lattice (1=relative)
+ insert_lattkey( lt , 1);
+ allspace(REMAKEIPO, 0);
+
+ if( frame > 0 )
+ G.scene->r.cfra = (int)oldfra;
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Lattice_copy( BPy_Lattice * self )
+{
+ Lattice *bl_Lattice; // blender Lattice object
+ PyObject *py_Lattice; // python wrapper
+
+ bl_Lattice = copy_lattice( self->lattice );
+ bl_Lattice->id.us = 0;
+
+ if( bl_Lattice )
+ py_Lattice = Lattice_CreatePyObject( bl_Lattice );
+ else
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't create Lattice Object in Blender" );
+ if( !py_Lattice )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create Lattice Object wrapper" );
+
+ return py_Lattice;
+}
+
+static int Lattice_compare( BPy_Lattice * a, BPy_Lattice * b )
+{
+ return ( a->lattice == b->lattice ) ? 0 : -1;
+}
+
+
+//***************************************************************************
+// Function: Lattice_repr
+// Description: This is a callback function for the BPy_Lattice type. It
+// builds a meaninful string to represent Lattice objects.
+//***************************************************************************
+static PyObject *Lattice_repr( BPy_Lattice * self )
+{
+ if( self->lattice )
+ return PyString_FromFormat( "[Lattice \"%s\"]",
+ self->lattice->id.name + 2 );
+ else
+ return PyString_FromString( "[Lattice <deleted>]" );
+}
+
+/*****************************************************************************/
+/* Python BPy_Lattice methods table: */
+/*****************************************************************************/
+static PyMethodDef BPy_Lattice_methods[] = {
+ /* name, method, flags, doc */
+ {"getName", ( PyCFunction ) GenericLib_getName, METH_NOARGS,
+ Lattice_getName_doc},
+ {"setName", ( PyCFunction ) GenericLib_setName_with_method, METH_VARARGS,
+ Lattice_setName_doc},
+ {"setPartitions", ( PyCFunction ) Lattice_setPartitions, METH_VARARGS,
+ Lattice_setPartitions_doc},
+ {"getPartitions", ( PyCFunction ) Lattice_getPartitions, METH_NOARGS,
+ Lattice_getPartitions_doc},
+ {"getKey", ( PyCFunction ) Lattice_getKey, METH_NOARGS,
+ Lattice_getKey_doc},
+ {"setKeyTypes", ( PyCFunction ) Lattice_setKeyTypes, METH_VARARGS,
+ Lattice_setKeyTypes_doc},
+ {"getKeyTypes", ( PyCFunction ) Lattice_getKeyTypes, METH_NOARGS,
+ Lattice_getKeyTypes_doc},
+ {"setMode", ( PyCFunction ) Lattice_setMode, METH_VARARGS,
+ Lattice_setMode_doc},
+ {"getMode", ( PyCFunction ) Lattice_getMode, METH_NOARGS,
+ Lattice_getMode_doc},
+ {"setPoint", ( PyCFunction ) Lattice_setPoint, METH_VARARGS,
+ Lattice_setPoint_doc},
+ {"getPoint", ( PyCFunction ) Lattice_getPoint, METH_VARARGS,
+ Lattice_getPoint_doc},
+ {"insertKey", ( PyCFunction ) Lattice_insertKey, METH_VARARGS,
+ Lattice_insertKey_doc},
+ {"__copy__", ( PyCFunction ) Lattice_copy, METH_NOARGS,
+ Lattice_copy_doc},
+ {"copy", ( PyCFunction ) Lattice_copy, METH_NOARGS,
+ Lattice_copy_doc},
+ {NULL, NULL, 0, NULL}
+};
+
+/*****************************************************************************/
+/* Python attributes get/set functions: */
+/*****************************************************************************/
+static PyObject *Lattice_getWidth(BPy_Lattice * self)
+{
+ return PyInt_FromLong( self->lattice->pntsu );
+}
+static PyObject *Lattice_getHeight(BPy_Lattice * self)
+{
+ return PyInt_FromLong( self->lattice->pntsv );
+}
+static PyObject *Lattice_getDepth(BPy_Lattice * self)
+{
+ return PyInt_FromLong( self->lattice->pntsw );
+}
+static PyObject *Lattice_getLatSize(BPy_Lattice * self)
+{
+ return PyInt_FromLong(
+ self->lattice->pntsu * self->lattice->pntsv * self->lattice->pntsw );
+}
+
+
+static PyObject *Lattice_getAxisType(BPy_Lattice * self, void * type)
+{
+ char interp_type = 0;
+ switch ( (int)type ) {
+ case 0:
+ interp_type = self->lattice->typeu;
+ break;
+ case 1:
+ interp_type = self->lattice->typev;
+ break;
+ case 2:
+ interp_type = self->lattice->typew;
+ break;
+ }
+
+ switch (interp_type) {
+ case 0:
+ return PyString_FromString( "Linear" );
+ case 1:
+ return PyString_FromString( "Cardinal" );
+ case 2:
+ return PyString_FromString( "Bspline" );
+ }
+ Py_RETURN_NONE;
+}
+
+/*****************************************************************************/
+/* Python attributes get/set structure: */
+/*****************************************************************************/
+static PyGetSetDef BPy_Lattice_getseters[] = {
+ GENERIC_LIB_GETSETATTR,
+ {"width", (getter)Lattice_getWidth, (setter)NULL,
+ "lattice U subdivision ", NULL},
+ {"height", (getter)Lattice_getHeight, (setter)NULL,
+ "lattice V subdivision", NULL},
+ {"depth", (getter)Lattice_getDepth, (setter)NULL,
+ "lattice W subdivision", NULL},
+ {"latSize", (getter)Lattice_getLatSize, (setter)NULL,
+ "lattice W subdivision", NULL},
+
+ {"widthType", (getter)Lattice_getAxisType, NULL,
+ "lattice U interpolation type", (void *)0},
+ {"heightType", (getter)Lattice_getAxisType, NULL,
+ "lattice V interpolation type", (void *)1},
+ {"depthType", (getter)Lattice_getAxisType, NULL,
+ "lattice W interpolation type", (void *)2},
+
+ {"key", (getter)Lattice_getKey, NULL,
+ "lattice key", NULL},
+ {"mode", (getter)Lattice_getMode, NULL,
+ "lattice key", NULL},
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+/*****************************************************************************/
+/* Python Lattice_Type structure definition: */
+/*****************************************************************************/
+PyTypeObject Lattice_Type = {
+ PyObject_HEAD_INIT( NULL )
+ 0, /* ob_size */
+ "Blender Lattice", /* tp_name */
+ sizeof( BPy_Lattice ), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ /* methods */
+ NULL, /* tp_dealloc */
+ 0, /* tp_print */
+ NULL, /* tp_getattr */
+ NULL, /* tp_setattr */
+ ( cmpfunc ) Lattice_compare, /* tp_compare */
+ ( reprfunc ) Lattice_repr, /* tp_repr */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ ( hashfunc ) GenericLib_hash, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_Lattice_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ BPy_Lattice_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
diff --git a/source/blender/python/api2_2x/Lattice.h b/source/blender/python/api2_2x/Lattice.h
new file mode 100644
index 00000000000..fb47c2dd2e4
--- /dev/null
+++ b/source/blender/python/api2_2x/Lattice.h
@@ -0,0 +1,60 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Joseph Gilbert
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_Lattice_H
+#define EXPP_Lattice_H
+
+#include <Python.h>
+#include "DNA_lattice_types.h"
+
+/* The Group PyTypeObject defined in Lattice.c */
+extern PyTypeObject Lattice_Type;
+
+#define BPy_Lattice_Check(v) ((v)->ob_type == &Lattice_Type)
+
+/*****************************************************************************/
+/* Python BPy_Lattice structure definition: */
+/*****************************************************************************/
+typedef struct {
+ PyObject_HEAD
+ Lattice * lattice; /* libdata must be second */
+} BPy_Lattice;
+
+/*
+ * prototypes
+ */
+
+PyObject *Lattice_Init( void );
+PyObject *Lattice_CreatePyObject( Lattice * lt );
+Lattice *Lattice_FromPyObject( PyObject * pyobj );
+
+#endif /* EXPP_LATTICE_H */
diff --git a/source/blender/python/api2_2x/Library.c b/source/blender/python/api2_2x/Library.c
new file mode 100644
index 00000000000..1aacaf56786
--- /dev/null
+++ b/source/blender/python/api2_2x/Library.c
@@ -0,0 +1,1192 @@
+/**
+ * $Id$
+ *
+ * Blender.Library BPython module implementation.
+ * This submodule has functions to append data from .blend files.
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano, Campbell Barton, Ken Hughes
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+/************************************************************/
+/* Original library module code */
+/************************************************************/
+
+#include <Python.h>
+
+#include "DNA_curve_types.h"
+#include "DNA_object_types.h"
+#include "DNA_space_types.h" /* for line linked */
+#include "BKE_library.h" /* for all_local */
+#include "BKE_font.h" /* for text_to_curve */
+#include "BKE_utildefines.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BLI_blenlib.h"
+#include "BLO_readfile.h"
+#include "BLI_linklist.h"
+#include "MEM_guardedalloc.h"
+#include "gen_utils.h"
+
+/**
+ * Global variables.
+ */
+static BlendHandle *bpy_openlib = NULL; /* ptr to the open .blend file */
+static char *bpy_openlibname = NULL; /* its pathname */
+static int bpy_relative= 0;
+
+/**
+ * Function prototypes for the Library submodule.
+ */
+static PyObject *M_Library_Open( PyObject * self, PyObject * args );
+static PyObject *M_Library_Close( PyObject * self );
+static PyObject *M_Library_GetName( PyObject * self );
+static PyObject *M_Library_Update( PyObject * self );
+static PyObject *M_Library_Datablocks( PyObject * self, PyObject * value );
+static PyObject *oldM_Library_Load( PyObject * self, PyObject * args );
+static PyObject *M_Library_LinkableGroups( PyObject * self );
+static PyObject *M_Library_LinkedLibs( PyObject * self );
+
+PyObject *Library_Init( void );
+void EXPP_Library_Close( void );
+
+/**
+ * Module doc strings.
+ */
+static char M_Library_doc[] = "The Blender.Library submodule:\n\n\
+This module gives access to .blend files, using them as libraries of\n\
+data that can be loaded into the current scene in Blender.";
+
+static char Library_Open_doc[] =
+ "(filename) - Open the given .blend file for access to its objects.\n\
+If another library file is still open, it's closed automatically.";
+
+static char Library_Close_doc[] =
+ "() - Close the currently open library file, if any.";
+
+static char Library_GetName_doc[] =
+ "() - Get the filename of the currently open library file, if any.";
+
+static char Library_Datablocks_doc[] =
+ "(datablock) - List all datablocks of the given type in the currently\n\
+open library file.\n\
+(datablock) - datablock name as a string: Object, Mesh, etc.";
+
+static char Library_Load_doc[] =
+ "(name, datablock [,update = 1]) - Append object 'name' of type 'datablock'\n\
+from the open library file to the current scene.\n\
+(name) - (str) the name of the object.\n\
+(datablock) - (str) the datablock of the object.\n\
+(update = 1) - (int) if non-zero, all display lists are recalculated and the\n\
+links are updated. This is slow, set it to zero if you have more than one\n\
+object to load, then call Library.Update() after loading them all.";
+
+static char Library_Update_doc[] =
+ "() - Update the current scene, linking all loaded library objects and\n\
+remaking all display lists. This is slow, call it only once after loading\n\
+all objects (load each of them with update = 0:\n\
+Library.Load(name, datablock, 0), or the update will be automatic, repeated\n\
+for each loaded object.";
+
+static char Library_LinkableGroups_doc[] =
+ "() - Get all linkable groups from the open .blend library file.";
+
+static char Library_LinkedLibs_doc[] =
+ "() - Get all libs used in the the open .blend file.";
+
+/**
+ * Python method structure definition for Blender.Library submodule.
+ */
+struct PyMethodDef oldM_Library_methods[] = {
+ {"Open", M_Library_Open, METH_O, Library_Open_doc},
+ {"Close", ( PyCFunction ) M_Library_Close, METH_NOARGS,
+ Library_Close_doc},
+ {"GetName", ( PyCFunction ) M_Library_GetName, METH_NOARGS,
+ Library_GetName_doc},
+ {"Update", ( PyCFunction ) M_Library_Update, METH_NOARGS,
+ Library_Update_doc},
+ {"Datablocks", M_Library_Datablocks, METH_O,
+ Library_Datablocks_doc},
+ {"Load", oldM_Library_Load, METH_VARARGS, Library_Load_doc},
+ {"LinkableGroups", ( PyCFunction ) M_Library_LinkableGroups,
+ METH_NOARGS, Library_LinkableGroups_doc},
+ {"LinkedLibs", ( PyCFunction ) M_Library_LinkedLibs,
+ METH_NOARGS, Library_LinkedLibs_doc},
+ {NULL, NULL, 0, NULL}
+};
+
+/* Submodule Python functions: */
+
+/**
+ * Open a new .blend file.
+ * Only one can be open at a time, so this function also closes
+ * the previously opened file, if any.
+ */
+static PyObject *M_Library_Open( PyObject * self, PyObject * value )
+{
+ char *fname = PyString_AsString(value);
+ char filename[FILE_MAXDIR+FILE_MAXFILE];
+ char fname1[FILE_MAXDIR+FILE_MAXFILE];
+
+ int len = 0;
+
+ bpy_relative= 0; /* assume non relative each time we load */
+
+ if( !fname ) {
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a .blend filename" );
+ }
+
+ if( bpy_openlib ) {
+ M_Library_Close( self );
+ Py_DECREF( Py_None ); /* incref'ed by above function */
+ }
+
+ /* copy the name to make it absolute so BLO_blendhandle_from_file doesn't complain */
+ BLI_strncpy(fname1, fname, sizeof(fname1));
+ BLI_convertstringcode(fname1, G.sce, 0); /* make absolute */
+
+ /* G.sce = last file loaded, save for UI and restore after opening file */
+ BLI_strncpy(filename, G.sce, sizeof(filename));
+ bpy_openlib = BLO_blendhandle_from_file( fname1 );
+ BLI_strncpy(G.sce, filename, sizeof(filename));
+
+ if( !bpy_openlib )
+ return EXPP_ReturnPyObjError( PyExc_IOError, "file not found" );
+
+ /* "//someblend.blend" enables relative paths */
+ if (sizeof(fname) > 2 && fname[0] == '/' && fname[1] == '/')
+ bpy_relative= 1; /* global that makes the library relative on loading */
+
+ len = strlen( fname1 ) + 1; /* +1 for terminating '\0' */
+
+ bpy_openlibname = MEM_mallocN( len, "bpy_openlibname" );
+
+ if( bpy_openlibname )
+ PyOS_snprintf( bpy_openlibname, len, "%s", fname1 );
+
+ Py_RETURN_TRUE;
+}
+
+/**
+ * Close the current .blend file, if any.
+ */
+static PyObject *M_Library_Close( PyObject * self )
+{
+ if( bpy_openlib ) {
+ BLO_blendhandle_close( bpy_openlib );
+ bpy_openlib = NULL;
+ }
+
+ if( bpy_openlibname ) {
+ MEM_freeN( bpy_openlibname );
+ bpy_openlibname = NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+/**
+ * helper function for 'atexit' clean-ups, used by BPY_end_python,
+ * declared in EXPP_interface.h.
+ */
+void EXPP_Library_Close( void )
+{
+ if( bpy_openlib ) {
+ BLO_blendhandle_close( bpy_openlib );
+ bpy_openlib = NULL;
+ }
+
+ if( bpy_openlibname ) {
+ MEM_freeN( bpy_openlibname );
+ bpy_openlibname = NULL;
+ }
+}
+
+/**
+ * Get the filename of the currently open library file, if any.
+ */
+static PyObject *M_Library_GetName( PyObject * self )
+{
+ if( bpy_openlib && bpy_openlibname )
+ return Py_BuildValue( "s", bpy_openlibname );
+
+ Py_INCREF( Py_None );
+ return Py_None;
+}
+
+/**
+ * Return a list with all items of a given datablock type
+ * (like 'Object', 'Mesh', etc.) in the open library file.
+ */
+static PyObject *M_Library_Datablocks( PyObject * self, PyObject * value )
+{
+ char *name = PyString_AsString(value);
+ int blocktype = 0;
+ LinkNode *l = NULL, *names = NULL;
+ PyObject *list = NULL;
+
+ if( !bpy_openlib ) {
+ return EXPP_ReturnPyObjError( PyExc_IOError,
+ "no library file: open one first with Blender.Lib_Open(filename)" );
+ }
+
+ if( !name ) {
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a string (datablock type) as argument." );
+ }
+
+ blocktype = ( int ) BLO_idcode_from_name( name );
+
+ if( !blocktype ) {
+ return EXPP_ReturnPyObjError( PyExc_NameError,
+ "no such Blender datablock type" );
+ }
+
+ names = BLO_blendhandle_get_datablock_names( bpy_openlib, blocktype );
+
+ if( names ) {
+ int counter = 0;
+ list = PyList_New( BLI_linklist_length( names ) );
+ for( l = names; l; l = l->next ) {
+ PyList_SET_ITEM( list, counter,
+ PyString_FromString( ( char * ) l->link ) );
+ counter++;
+ }
+ BLI_linklist_free( names, free ); /* free linklist *and* each node's data */
+ return list;
+ }
+
+ Py_RETURN_NONE;
+}
+
+/**
+ * Return a list with the names of all linkable groups in the
+ * open library file.
+ */
+static PyObject *M_Library_LinkableGroups( PyObject * self )
+{
+ LinkNode *l = NULL, *names = NULL;
+ PyObject *list = NULL;
+
+ if( !bpy_openlib ) {
+ return EXPP_ReturnPyObjError( PyExc_IOError,
+ "no library file: open one first with Blender.Lib_Open(filename)" );
+ }
+
+ names = BLO_blendhandle_get_linkable_groups( bpy_openlib );
+ list = PyList_New( BLI_linklist_length( names ) );
+
+ if( names ) {
+ int counter = 0;
+
+ for( l = names; l; l = l->next ) {
+ PyList_SET_ITEM( list, counter, PyString_FromString( ( char * ) l->link ) );
+ counter++;
+ }
+ BLI_linklist_free( names, free ); /* free linklist *and* each node's data */
+ return list;
+ }
+ return list;
+}
+
+/**
+ * Return a list with the names of all externally linked libs used in the current Blend file
+ */
+static PyObject *M_Library_LinkedLibs( PyObject * self )
+{
+ int counter = 0;
+ Library *li;
+ PyObject *list;
+
+ list = PyList_New( BLI_countlist( &( G.main->library ) ) );
+ for (li= G.main->library.first; li; li= li->id.next) {
+ PyList_SET_ITEM( list, counter, PyString_FromString( li->name ));
+ counter++;
+ }
+ return list;
+}
+
+/**
+ * Load (append) a given datablock of a given datablock type
+ * to the current scene.
+ */
+static PyObject *oldM_Library_Load( PyObject * self, PyObject * args )
+{
+ char *name = NULL;
+ char *base = NULL;
+ int update = 1;
+ int blocktype = 0;
+ int linked = 0;
+
+ if( !bpy_openlib ) {
+ return EXPP_ReturnPyObjError( PyExc_IOError,
+ "no library file: you need to open one, first." );
+ }
+
+ if( !PyArg_ParseTuple( args, "ss|ii", &name, &base, &update, &linked ) ) {
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected two strings as arguments." );
+ }
+
+ blocktype = ( int ) BLO_idcode_from_name( base );
+
+ if( !blocktype )
+ return EXPP_ReturnPyObjError( PyExc_NameError,
+ "no such Blender datablock type" );
+
+ if (linked)
+ BLO_script_library_append( bpy_openlib, bpy_openlibname, name, blocktype, FILE_LINK, G.scene);
+ else
+ BLO_script_library_append( bpy_openlib, bpy_openlibname, name, blocktype, 0, G.scene);
+
+ if( update ) {
+ M_Library_Update( self );
+ Py_DECREF( Py_None ); /* incref'ed by above function */
+ }
+
+ if( bpy_relative ) {
+ /* and now find the latest append lib file */
+ Library *lib = G.main->library.first;
+ while( lib ) {
+ if( strcmp( bpy_openlibname, lib->name ) == 0 ) {
+
+ /* use the full path, this could have been read by other library even */
+ BLI_strncpy(lib->name, lib->filename, sizeof(lib->name));
+
+ /* uses current .blend file as reference */
+ BLI_makestringcode(G.sce, lib->name);
+ break;
+ }
+ lib = lib->id.next;
+ }
+
+ }
+
+ Py_INCREF( Py_None );
+ return Py_None;
+}
+
+/**
+ * Update all links and remake displists.
+ */
+static PyObject *M_Library_Update( PyObject * self )
+{ /* code adapted from do_library_append in src/filesel.c: */
+ Library *lib = NULL;
+
+ /* Displist code that was here is obsolete... depending on what
+ * this function is supposed to do (it should technically be unnecessary)
+ * can be replaced with depgraph calls - zr
+ */
+
+ if( bpy_openlibname ) {
+ strcpy( G.lib, bpy_openlibname );
+
+ /* and now find the latest append lib file */
+ lib = G.main->library.first;
+ while( lib ) {
+ if( strcmp( bpy_openlibname, lib->name ) == 0 )
+ break;
+ lib = lib->id.next;
+ }
+ all_local( lib, 0 );
+ }
+
+ Py_INCREF( Py_None );
+ return Py_None;
+}
+
+/**
+ * Initialize the Blender.Library submodule.
+ * Called by Blender_Init in Blender.c .
+ * @return the registered submodule.
+ */
+PyObject *oldLibrary_Init( void )
+{
+ PyObject *submod;
+
+ submod = Py_InitModule3( "Blender.Library", oldM_Library_methods,
+ M_Library_doc );
+
+ return submod;
+}
+
+/************************************************************/
+/* New library (LibData) module code */
+/************************************************************/
+
+#include "Library.h"
+
+/* if this module supercedes the old library module, include these instead */
+#if 0
+#include "BLI_blenlib.h"
+#include "MEM_guardedalloc.h"
+
+#include "DNA_curve_types.h"
+#include "DNA_object_types.h"
+#include "DNA_space_types.h" /* for line linked */
+#include "BKE_library.h" /* for all_local */
+#include "BKE_utildefines.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BLO_readfile.h"
+#include "BLI_linklist.h"
+
+#include "Object.h"
+#include "gen_utils.h"
+#endif
+
+#include "gen_library.h"
+
+/* Helper function */
+
+/*
+ * Try to open a library, set Python exceptions as necessary if not
+ * successful. On success, return a valid handle; othewise return NULL.
+ */
+
+static BlendHandle *open_library( char *filename, char *longFilename )
+{
+ char globalFilename[FILE_MAX];
+ BlendHandle *openlib = NULL;
+
+ /* get complete file name if necessary */
+ BLI_strncpy( longFilename, filename, FILE_MAX );
+ BLI_convertstringcode( longFilename, G.sce, 0 );
+
+ /* throw exceptions for wrong file type, cyclic reference */
+ if( !BLO_has_bfile_extension(longFilename) ) {
+ PyErr_SetString( PyExc_ValueError, "file not a library" );
+ return NULL;
+ }
+ if( BLI_streq(G.main->name, longFilename) ) {
+ PyErr_SetString( PyExc_ValueError,
+ "cannot use current file as library" );
+ return NULL;
+ }
+
+ /* G.sce = last file loaded, save for UI and restore after opening file */
+ BLI_strncpy(globalFilename, G.sce, sizeof(globalFilename));
+ openlib = BLO_blendhandle_from_file( longFilename );
+ BLI_strncpy(G.sce, globalFilename, sizeof(globalFilename));
+
+ /* if failed, set that exception code too */
+ if( !openlib )
+ PyErr_SetString( PyExc_IOError, "library not found" );
+
+ return openlib;
+}
+
+/*
+ * Create a specific type of LibraryData object. These are used for
+ * .append() and .link() access, for iterators, and (for Blender Objects)
+ * for defining "pseudo objects" for scene linking.
+ */
+
+static PyObject *CreatePyObject_LibData( int idtype, int kind,
+ void *name, void *iter, char *filename )
+{
+ BPy_LibraryData *seq = PyObject_NEW( BPy_LibraryData, &LibraryData_Type);
+ seq->iter = iter; /* the name list (for iterators) */
+ seq->type = idtype; /* the Blender ID type */
+ seq->kind = kind; /* used by Blender Objects */
+ seq->name = name; /* object name, iterator name list, or NULL */
+ /* save the library name */
+ BLI_strncpy( seq->filename, filename, strlen(filename)+1 );
+ return (PyObject *)seq;
+}
+
+/*
+ * Link/append data to the current .blend file, or create a pseudo object
+ * which can be linked/appended to a scene.
+ */
+
+static PyObject *lib_link_or_append( BPy_LibraryData *self, PyObject * value,
+ int mode )
+{
+ char *name = PyString_AsString(value);
+
+ /* get the name of the data used wants to append */
+ if( !name )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a string" );
+
+ /*
+ * For everything except objects, just add to Blender's DB. For objects,
+ * create an APPEND or LINK "pseudo object" for the Scene module.
+ */
+ if( self->type != ID_OB )
+ return LibraryData_importLibData( self, name, 0, NULL );
+ else {
+ /*
+ * If this is already a pseudo object, throw an exception: re-linking
+ * or re-appending is not allowed
+ */
+ if( self->kind != OTHER )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "object has already been marked for append or link" );
+
+ /* otherwise, create a pseudo object ready for appending or linking */
+
+ return CreatePyObject_LibData( ID_OB, mode,
+ BLI_strdupn( name, strlen( name ) ), NULL, self->filename );
+ }
+}
+
+/*
+ * Perform the actual link or append operation. This procedure is also
+ * called externally from the Scene module using a "pseudo Object" so we
+ * can be sure objects get linked to a scene.
+ */
+
+PyObject *LibraryData_importLibData( BPy_LibraryData *self, char *name,
+ int mode, Scene *scene )
+{
+ char longFilename[FILE_MAX];
+ BlendHandle *openlib;
+ Library *lib;
+ LinkNode *names, *ptr;
+ ID *id;
+ ListBase *lb;
+ char newName[32];
+
+ /* try to open the library */
+ openlib = open_library( self->filename, longFilename );
+ if( !openlib )
+ return NULL;
+
+ /* find all datablocks for the specified type */
+ names = BLO_blendhandle_get_datablock_names ( openlib, self->type );
+
+ /* now check for a match to the user-specified name */
+ for( ptr = names; ptr; ptr = ptr->next )
+ if( strcmp( ptr->link, name ) == 0 ) break;
+ BLI_linklist_free( names, free );
+
+ /* if no match, throw exception */
+ if( !ptr ) {
+ BLO_blendhandle_close( openlib );
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "library does not contain specified item" );
+ }
+
+ /*
+ * Figure out what the datablock will be named after it's imported. If
+ * it's a link, nothing to do. If it's an append, find what it might
+ * be renamed to.
+ */
+
+ if( mode != FILE_LINK ) {
+ flag_all_listbases_ids(LIB_APPEND_TAG, 1);
+
+ /* see what new block will be called */
+ strncpy( newName, name, strlen(name)+1 );
+ check_for_dupid( wich_libbase(G.main, self->type), NULL, newName );
+ }
+
+ /* import from the libary */
+ BLO_script_library_append( openlib, longFilename, name, self->type, mode,
+ scene );
+
+ /*
+ * locate the library. If this is an append, make the data local. If it
+ * is link, we need the library for later
+ */
+ for( lib = G.main->library.first; lib; lib = lib->id.next )
+ if( strcmp( longFilename, lib->name ) == 0 ) {
+ if( mode != FILE_LINK ) {
+ all_local( lib, 1 );
+ /* important we unset, otherwise these object wont
+ * link into other scenes from this blend file */
+ flag_all_listbases_ids(LIB_APPEND_TAG, 0);
+ }
+ break;
+ }
+
+ /* done with library; close it */
+ BLO_blendhandle_close( openlib );
+
+ /* this should not happen, but just in case */
+ if( !lib )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "could not library" );
+
+ /* find the base for this type */
+ lb = wich_libbase( G.main, self->type );
+
+ /*
+ * Check for linked data matching the name first. Even if we are trying
+ * to append, if the data has already been linked we need to return it
+ * (it won't be appended from the library).
+ */
+ for( id = lb->first; id; id = id->next ) {
+ if( id->lib == lib && id->name[2]==name[0] &&
+ strcmp(id->name+2, name)==0 )
+ return GetPyObjectFromID( id );
+ }
+
+ /*
+ * If we didn't find it, and we're appending, then try searching for the
+ * new datablock, possibly under a new name.
+ */
+ if( mode != FILE_LINK )
+ for( id = lb->first; id; id = id->next ) {
+ if( id->lib == NULL && id->name[2]==newName[0] &&
+ strcmp(id->name+2, newName)==0 )
+ return GetPyObjectFromID( id );
+ }
+
+ /* if we get here, something's really wrong */
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "could not find data after reading from library" );
+}
+
+/************************************************************
+ * Python LibraryData_Type getseters
+ ************************************************************/
+
+/* .append(): make a local copy of the library's data (except for objects) */
+
+static PyObject *LibraryData_getAppend( BPy_LibraryData *self, PyObject * value)
+{
+ return lib_link_or_append( self, value, OBJECT_IS_APPEND );
+}
+
+/* .link(): make a link to the library's data (except for objects) */
+
+static PyObject *LibraryData_getLink( BPy_LibraryData *self, PyObject * value)
+{
+ return lib_link_or_append( self, value, OBJECT_IS_LINK );
+}
+
+/************************************************************************
+ * Python LibraryData_Type iterator
+ ************************************************************************/
+
+/* Create and initialize the interator indices */
+
+static PyObject *LibraryData_getIter( BPy_LibraryData * self )
+{
+ char longFilename[FILE_MAX];
+ BlendHandle *openlib;
+ LinkNode *names;
+
+ /* try to open library */
+ openlib = open_library( self->filename, longFilename );
+
+ /* if failed, return exception */
+ if( !openlib )
+ return NULL;
+
+ /* find all datablocks for the specified type */
+ names = BLO_blendhandle_get_datablock_names ( openlib, self->type );
+
+ /* close library*/
+ BLO_blendhandle_close( openlib );
+
+ /* build an iterator object for the name list */
+ return CreatePyObject_LibData( self->type, OTHER, names,
+ names, self->filename );
+}
+
+/* Return next name. */
+
+static PyObject *LibraryData_nextIter( BPy_LibraryData * self )
+{
+ LinkNode *ptr = (LinkNode *)self->iter;
+ PyObject *ob;
+
+ /* if at the end of list, clean up */
+ if( !ptr ) {
+ /* If name list is still allocated, free storage. This check is
+ * necessary since iter.next() can technically be called repeatedly */
+ if( self->name ) {
+ BLI_linklist_free( (LinkNode *)self->name, free );
+ self->name = NULL;
+ }
+ return EXPP_ReturnPyObjError( PyExc_StopIteration,
+ "iterator at end" );
+ }
+
+ /* otherwise, return the next name in the list */
+ ob = PyString_FromString( ptr->link );
+ ptr = ptr->next;
+ self->iter = ptr;
+ return ob;
+}
+
+/************************************************************************
+ * Python LibraryData_type methods structure
+ ************************************************************************/
+
+static struct PyMethodDef BPy_LibraryData_methods[] = {
+ {"append", (PyCFunction)LibraryData_getAppend, METH_O,
+ "(str) - create new data from library"},
+ {"link", (PyCFunction)LibraryData_getLink, METH_O,
+ "(str) - link data from library"},
+ {NULL, NULL, 0, NULL}
+};
+
+/* Deallocate object and its data */
+
+static void LibraryData_dealloc( BPy_LibraryData * self )
+{
+ if( self->name )
+ MEM_freeN( self->name );
+
+ PyObject_DEL( self );
+}
+
+/* Display representation of what Library Data is wrapping */
+
+static PyObject *LibraryData_repr( BPy_LibraryData * self )
+{
+ char *linkstate = "";
+ char *str;
+
+ switch (self->type) {
+ case ID_OB:
+ /* objects can be lib data or pseudo objects */
+ switch( self->kind ) {
+ case OBJECT_IS_APPEND :
+ linkstate = ", appended";
+ break;
+ case OBJECT_IS_LINK :
+ linkstate = ", linked";
+ break;
+ default:
+ break;
+ }
+ str = "Object";
+ break;
+ case ID_SCE:
+ str = "Scene";
+ break;
+ case ID_ME:
+ str = "Mesh";
+ break;
+ case ID_CU:
+ str = "Curve";
+ break;
+ case ID_MB:
+ str = "Metaball";
+ break;
+ case ID_MA:
+ str = "Material";
+ break;
+ case ID_TE:
+ str = "Texture";
+ break;
+ case ID_IM:
+ str = "Image";
+ break;
+ case ID_LT:
+ str = "Lattice";
+ break;
+ case ID_LA:
+ str = "Lamp";
+ break;
+ case ID_CA:
+ str = "Camera";
+ break;
+ case ID_IP:
+ str = "Ipo";
+ break;
+ case ID_WO:
+ str = "World";
+ break;
+ case ID_VF:
+ str = "Font";
+ break;
+ case ID_TXT:
+ str = "Text";
+ break;
+ case ID_SO:
+ str = "Sound";
+ break;
+ case ID_GR:
+ str = "Group";
+ break;
+ case ID_AR:
+ str = "Armature";
+ break;
+ case ID_AC:
+ str = "Action";
+ break;
+ default:
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "unsupported ID type" );
+ }
+
+ return PyString_FromFormat( "[Library Data (%s%s)]", str, linkstate );
+}
+
+PyTypeObject LibraryData_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender LibData", /* char *tp_name; */
+ sizeof( BPy_LibraryData ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ ( destructor ) LibraryData_dealloc,/* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ ( cmpfunc ) NULL, /* cmpfunc tp_compare; */
+ ( reprfunc ) LibraryData_repr, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ (getiterfunc)LibraryData_getIter, /* getiterfunc tp_iter; */
+ (iternextfunc)LibraryData_nextIter, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_LibraryData_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ NULL, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+/*
+ * Create a LibraryData object for a specific type of Blender Group (ID_OB,
+ * ID_MA, etc). These can then be used to link or append the data.
+ */
+
+static PyObject *LibraryData_CreatePyObject( BPy_Library *self, void *mode )
+{
+ return CreatePyObject_LibData( (int)mode, OTHER, NULL, NULL,
+ self->filename );
+}
+
+/************************************************************
+ * Python Library_Type getseters
+ ************************************************************/
+
+/*
+ * Return the library's filename.
+ */
+
+static PyObject *Library_getFilename( BPy_Library * self )
+{
+ return PyString_FromString( self->filename );
+}
+
+/*
+ * Set/change the library's filename.
+ */
+
+static int Library_setFilename( BPy_Library * self, PyObject * args )
+{
+ char *filename = PyString_AsString( args );
+ if( !filename )
+ return EXPP_ReturnIntError( PyExc_TypeError, "expected a string" );
+
+ BLI_strncpy( self->filename, filename, sizeof(self->filename) );
+ return 0;
+}
+
+/************************************************************************
+ * Python Library_type attributes get/set structure
+ ************************************************************************/
+
+static PyGetSetDef Library_getseters[] = {
+ {"filename",
+ (getter)Library_getFilename, (setter)Library_setFilename,
+ "library filename",
+ NULL},
+ {"objects",
+ (getter)LibraryData_CreatePyObject, (setter)NULL,
+ "objects from the library",
+ (void *)ID_OB},
+ {"scenes",
+ (getter)LibraryData_CreatePyObject, (setter)NULL,
+ "scenes from the library",
+ (void *)ID_SCE},
+ {"meshes",
+ (getter)LibraryData_CreatePyObject, (setter)NULL,
+ "meshes from the library",
+ (void *)ID_ME},
+ {"curves",
+ (getter)LibraryData_CreatePyObject, (setter)NULL,
+ "curves from the library",
+ (void *)ID_CU},
+ {"metaballs",
+ (getter)LibraryData_CreatePyObject, (setter)NULL,
+ "metaballs from the library",
+ (void *)ID_MB},
+ {"lattices",
+ (getter)LibraryData_CreatePyObject, (setter)NULL,
+ "lattices from the library",
+ (void *)ID_LT},
+ {"lamps",
+ (getter)LibraryData_CreatePyObject, (setter)NULL,
+ "lamps from the library",
+ (void *)ID_LA},
+ {"cameras",
+ (getter)LibraryData_CreatePyObject, (setter)NULL,
+ "cameras from the library",
+ (void *)ID_CA},
+ {"materials",
+ (getter)LibraryData_CreatePyObject, (setter)NULL,
+ "objects from the library",
+ (void *)ID_MA},
+ {"textures",
+ (getter)LibraryData_CreatePyObject, (setter)NULL,
+ "textures from the library",
+ (void *)ID_TE},
+ {"images",
+ (getter)LibraryData_CreatePyObject, (setter)NULL,
+ "images from the library",
+ (void *)ID_IM},
+ {"ipos",
+ (getter)LibraryData_CreatePyObject, (setter)NULL,
+ "ipos from the library",
+ (void *)ID_IP},
+ {"worlds",
+ (getter)LibraryData_CreatePyObject, (setter)NULL,
+ "worlds from the library",
+ (void *)ID_WO},
+ {"fonts",
+ (getter)LibraryData_CreatePyObject, (setter)NULL,
+ "fonts from the library",
+ (void *)ID_VF},
+ {"texts",
+ (getter)LibraryData_CreatePyObject, (setter)NULL,
+ "texts from the library",
+ (void *)ID_TXT},
+ {"groups",
+ (getter)LibraryData_CreatePyObject, (setter)NULL,
+ "groups from the library",
+ (void *)ID_GR},
+ {"sounds",
+ (getter)LibraryData_CreatePyObject, (setter)NULL,
+ "sounds from the library",
+ (void *)ID_SO},
+ {"actions",
+ (getter)LibraryData_CreatePyObject, (setter)NULL,
+ "actions from the library",
+ (void *)ID_AC},
+ {"armatures",
+ (getter)LibraryData_CreatePyObject, (setter)NULL,
+ "armatures from the library",
+ (void *)ID_AR},
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+/*
+ * Define a new library and create a library object. We don't actually test
+ * if the library is valid here since we have to do it when the file is
+ * actually accessed later.
+ */
+
+static PyObject *M_Library_Load(PyObject *self, PyObject * value)
+{
+ char *filename = PyString_AsString(value);
+ BPy_Library *lib;
+
+ if( !filename )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a string" );
+
+ /* try to create a new object */
+ lib = (BPy_Library *)PyObject_NEW( BPy_Library, &Library_Type );
+ if( !lib )
+ return NULL;
+
+ /* assign the library filename for future use, then return */
+ BLI_strncpy( lib->filename, filename, sizeof(lib->filename) );
+
+ return (PyObject *)lib;
+}
+
+static struct PyMethodDef M_Library_methods[] = {
+ {"load", (PyCFunction)M_Library_Load, METH_O,
+ "(string) - declare a .blend file for use as a library"},
+ {NULL, NULL, 0, NULL}
+};
+
+/*****************************************************************************/
+/* Python Library_Type structure definition: */
+/*****************************************************************************/
+PyTypeObject Library_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender Library", /* char *tp_name; */
+ sizeof( BPy_Library ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ NULL, /* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ ( cmpfunc ) NULL, /* cmpfunc tp_compare; */
+ ( reprfunc ) NULL, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ NULL, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ Library_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+/*
+ * Library module initialization
+ */
+
+static char M_newLibrary_doc[] = "The Blender.lib submodule";
+
+PyObject *Library_Init( void )
+{
+ PyObject *submodule;
+
+ if( PyType_Ready( &Library_Type ) < 0 )
+ return NULL;
+ if( PyType_Ready( &LibraryData_Type ) < 0 )
+ return NULL;
+
+ submodule = Py_InitModule3( "Blender.lib", M_Library_methods,
+ M_newLibrary_doc );
+ return submodule;
+}
diff --git a/source/blender/python/api2_2x/Library.h b/source/blender/python/api2_2x/Library.h
new file mode 100644
index 00000000000..4814bf1410c
--- /dev/null
+++ b/source/blender/python/api2_2x/Library.h
@@ -0,0 +1,78 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Ken Hughes
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_LIBRARY_H
+#define EXPP_LIBRARY_H
+
+#include <Python.h>
+#include "DNA_scene_types.h"
+#include "BLI_linklist.h"
+
+#include "blendef.h"
+
+/*****************************************************************************/
+/* Python BPy_Library structure definition: */
+/*****************************************************************************/
+typedef struct {
+ PyObject_HEAD
+ char filename[FILE_MAXDIR + FILE_MAXFILE];
+} BPy_Library;
+
+typedef struct {
+ PyObject_HEAD
+ LinkNode *iter;
+ int type;
+ char filename[FILE_MAXDIR + FILE_MAXFILE];
+ char *name;
+ enum {
+ OBJECT_IS_LINK,
+ OBJECT_IS_APPEND,
+ OTHER
+ } kind;
+} BPy_LibraryData;
+
+extern PyTypeObject Library_Type;
+extern PyTypeObject LibraryData_Type;
+
+#define BPy_LibraryData_Check(v) ((v)->ob_type == &LibraryData_Type)
+#define BPy_Library_Check(v) ((v)->ob_type == &Library_Type)
+
+/*****************************************************************************/
+/* Module Blender.Library - public functions */
+/*****************************************************************************/
+PyObject *Library_Init( void );
+PyObject *oldLibrary_Init( void );
+
+PyObject *LibraryData_importLibData( BPy_LibraryData *self, char *name,
+ int mode, Scene *scene );
+
+#endif /* EXPP_LIBRARY_H */
diff --git a/source/blender/python/api2_2x/MTex.c b/source/blender/python/api2_2x/MTex.c
new file mode 100644
index 00000000000..4f7cff35c11
--- /dev/null
+++ b/source/blender/python/api2_2x/MTex.c
@@ -0,0 +1,827 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Alex Mole, Yehoshua Sapir
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+#include "MTex.h" /*This must come first*/
+
+#include "BKE_utildefines.h"
+#include "BLI_blenlib.h"
+#include "Texture.h"
+#include "Object.h"
+#include "gen_utils.h"
+#include "gen_library.h"
+
+#include <DNA_material_types.h>
+
+/*****************************************************************************/
+/* Python BPy_MTex methods declarations: */
+/*****************************************************************************/
+static PyObject *MTex_setTexMethod( BPy_MTex * self, PyObject * args );
+
+/*****************************************************************************/
+/* Python method structure definition for Blender.Texture.MTex module: */
+/*****************************************************************************/
+struct PyMethodDef M_MTex_methods[] = {
+ {NULL, NULL, 0, NULL}
+};
+
+/*****************************************************************************/
+/* Python BPy_MTex methods table: */
+/*****************************************************************************/
+static PyMethodDef BPy_MTex_methods[] = {
+ /* name, method, flags, doc */
+ {"setTex", ( PyCFunction ) MTex_setTexMethod, METH_VARARGS,
+ "(i) - Set MTex Texture"},
+ {NULL, NULL, 0, NULL}
+};
+
+/*****************************************************************************/
+/* Python MTex_Type callback function prototypes: */
+/*****************************************************************************/
+static int MTex_compare( BPy_MTex * a, BPy_MTex * b );
+static PyObject *MTex_repr( BPy_MTex * self );
+
+#define MTEXGET(x) \
+ static PyObject *MTex_get##x( BPy_MTex *self, void *closure );
+#define MTEXSET(x) \
+ static int MTex_set##x( BPy_MTex *self, PyObject *value, void *closure);
+#define MTEXGETSET(x) \
+ MTEXGET(x) \
+ MTEXSET(x)
+
+MTEXGETSET(Tex)
+MTEXGETSET(TexCo)
+MTEXGETSET(Object)
+MTEXGETSET(UVLayer)
+MTEXGETSET(MapTo)
+MTEXGETSET(Col)
+MTEXGETSET(DVar)
+MTEXGETSET(BlendMode)
+MTEXGETSET(ColFac)
+MTEXGETSET(NorFac)
+MTEXGETSET(VarFac)
+MTEXGETSET(DispFac)
+MTEXGETSET(WarpFac)
+MTEXGETSET(Ofs)
+MTEXGETSET(Size)
+MTEXGETSET(Mapping)
+MTEXGETSET(Flag)
+MTEXGETSET(ProjX)
+MTEXGETSET(ProjY)
+MTEXGETSET(ProjZ)
+MTEXGETSET(MapToFlag)
+
+/*****************************************************************************/
+/* Python get/set methods table */
+/*****************************************************************************/
+
+static PyGetSetDef MTex_getseters[] = {
+ { "tex", (getter) MTex_getTex, (setter) MTex_setTex,
+ "Texture whose mapping this MTex describes", NULL },
+ { "texco", (getter) MTex_getTexCo, (setter) MTex_setTexCo,
+ "Texture coordinate space (UV, Global, etc.)", NULL },
+ { "object", (getter) MTex_getObject, (setter) MTex_setObject,
+ "Object whose space to use when texco is Object", NULL },
+ { "uvlayer", (getter) MTex_getUVLayer, (setter) MTex_setUVLayer,
+ "Name of the UV layer to use", NULL },
+ { "mapto", (getter) MTex_getMapTo, (setter) MTex_setMapTo,
+ "What values the texture affects", NULL },
+ { "col", (getter) MTex_getCol, (setter) MTex_setCol,
+ "Color that the texture blends with", NULL },
+ { "dvar", (getter) MTex_getDVar, (setter) MTex_setDVar,
+ "Value that the texture blends with when not blending colors", NULL },
+ { "blendmode", (getter) MTex_getBlendMode, (setter) MTex_setBlendMode,
+ "Texture blending mode", NULL },
+ { "colfac", (getter) MTex_getColFac, (setter) MTex_setColFac,
+ "Factor by which texture affects color", NULL },
+ { "norfac", (getter) MTex_getNorFac, (setter) MTex_setNorFac,
+ "Factor by which texture affects normal", NULL },
+ { "varfac", (getter) MTex_getVarFac, (setter) MTex_setVarFac,
+ "Factor by which texture affects most variables", NULL },
+ { "dispfac", (getter) MTex_getDispFac, (setter) MTex_setDispFac,
+ "Factor by which texture affects displacement", NULL },
+ { "warpfac", (getter) MTex_getWarpFac, (setter) MTex_setWarpFac,
+ "Factor by which texture affects warp", NULL },
+ { "ofs", (getter) MTex_getOfs, (setter) MTex_setOfs,
+ "Offset to adjust texture space", NULL },
+ { "size", (getter) MTex_getSize, (setter) MTex_setSize,
+ "Size to scale texture space", NULL },
+ { "mapping", (getter) MTex_getMapping, (setter) MTex_setMapping,
+ "Mapping of texture coordinates (flat, cube, etc.)", NULL },
+ { "stencil", (getter) MTex_getFlag, (setter) MTex_setFlag,
+ "Stencil mode", (void*) MTEX_STENCIL },
+ { "neg", (getter) MTex_getFlag, (setter) MTex_setFlag,
+ "Negate texture values mode", (void*) MTEX_NEGATIVE },
+ { "noRGB", (getter) MTex_getFlag, (setter) MTex_setFlag,
+ "Convert texture RGB values to intensity values",
+ (void*) MTEX_RGBTOINT },
+ { "correctNor", (getter) MTex_getFlag, (setter) MTex_setFlag,
+ "Correct normal mapping for Texture space and Object space",
+ (void*) MTEX_VIEWSPACE },
+ { "xproj", (getter) MTex_getProjX, (setter) MTex_setProjX,
+ "Projection of X axis to Texture space", NULL },
+ { "yproj", (getter) MTex_getProjY, (setter) MTex_setProjY,
+ "Projection of Y axis to Texture space", NULL },
+ { "zproj", (getter) MTex_getProjZ, (setter) MTex_setProjZ,
+ "Projection of Z axis to Texture space", NULL },
+ { "mtCol", (getter) MTex_getMapToFlag, (setter) MTex_setMapToFlag,
+ "How texture maps to color", (void*) MAP_COL },
+ { "mtNor", (getter) MTex_getMapToFlag, (setter) MTex_setMapToFlag,
+ "How texture maps to normals", (void*) MAP_NORM },
+ { "mtCsp", (getter) MTex_getMapToFlag, (setter) MTex_setMapToFlag,
+ "How texture maps to specularity color", (void*) MAP_COLSPEC },
+ { "mtCmir", (getter) MTex_getMapToFlag, (setter) MTex_setMapToFlag,
+ "How texture maps to mirror color", (void*) MAP_COLMIR },
+ { "mtRef", (getter) MTex_getMapToFlag, (setter) MTex_setMapToFlag,
+ "How texture maps to reflectivity", (void*) MAP_REF },
+ { "mtSpec", (getter) MTex_getMapToFlag, (setter) MTex_setMapToFlag,
+ "How texture maps to specularity", (void*) MAP_SPEC },
+ { "mtEmit", (getter) MTex_getMapToFlag, (setter) MTex_setMapToFlag,
+ "How texture maps to emit value", (void*) MAP_EMIT },
+ { "mtAlpha", (getter) MTex_getMapToFlag, (setter) MTex_setMapToFlag,
+ "How texture maps to alpha value", (void*) MAP_ALPHA },
+ { "mtHard", (getter) MTex_getMapToFlag, (setter) MTex_setMapToFlag,
+ "How texture maps to hardness", (void*) MAP_HAR },
+ { "mtRayMir", (getter) MTex_getMapToFlag, (setter) MTex_setMapToFlag,
+ "How texture maps to RayMir value", (void*) MAP_RAYMIRR },
+ { "mtTranslu", (getter) MTex_getMapToFlag, (setter) MTex_setMapToFlag,
+ "How texture maps to translucency", (void*) MAP_TRANSLU },
+ { "mtAmb", (getter) MTex_getMapToFlag, (setter) MTex_setMapToFlag,
+ "How texture maps to ambient value", (void*) MAP_AMB },
+ { "mtDisp", (getter) MTex_getMapToFlag, (setter) MTex_setMapToFlag,
+ "How texture maps to displacement", (void*) MAP_DISPLACE },
+ { "mtWarp", (getter) MTex_getMapToFlag, (setter) MTex_setMapToFlag,
+ "How texture maps to warp", (void*) MAP_WARP },
+ { NULL, NULL, NULL, NULL, NULL }
+};
+
+
+
+/*****************************************************************************/
+/* Python MTex_Type structure definition: */
+/*****************************************************************************/
+
+PyTypeObject MTex_Type = {
+ PyObject_HEAD_INIT( NULL )
+ 0, /* ob_size */
+ "Blender MTex", /* tp_name */
+ sizeof( BPy_MTex ), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ /* methods */
+ NULL, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ ( cmpfunc ) MTex_compare, /* tp_compare */
+ ( reprfunc ) MTex_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_as_hash */
+ 0, 0, 0, 0, 0,
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+ 0, /* tp_doc */
+ 0, 0, 0, 0, 0, 0,
+ BPy_MTex_methods, /* tp_methods */
+ 0, /* tp_members */
+ MTex_getseters, /* struct PyGetSetDef *tp_getset; */
+ 0, /* struct _typeobject *tp_base; */
+ 0, /* PyObject *tp_dict; */
+ 0, /* descrgetfunc tp_descr_get; */
+ 0, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ 0, /* initproc tp_init; */
+ 0, /* allocfunc tp_alloc; */
+ 0, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ 0, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ 0, /* inquiry tp_is_gc; */
+ 0, /* PyObject *tp_bases; */
+ /* method resolution order */
+ 0, /* PyObject *tp_mro; */
+ 0, /* PyObject *tp_cache; */
+ 0, /* PyObject *tp_subclasses; */
+ 0, /* PyObject *tp_weaklist; */
+ 0
+};
+
+
+PyObject *MTex_Init( void )
+{
+ PyObject *submodule;
+/* PyObject *dict; */
+
+ /* call PyType_Ready() to init dictionaries & such */
+ if( PyType_Ready( &MTex_Type) < 0)
+ Py_RETURN_NONE;
+
+ submodule = Py_InitModule( "Blender.Texture.MTex", M_MTex_methods );
+
+ return submodule;
+}
+
+PyObject *MTex_CreatePyObject( MTex * mtex )
+{
+ BPy_MTex *pymtex;
+
+ pymtex = ( BPy_MTex * ) PyObject_NEW( BPy_MTex, &MTex_Type );
+ if( !pymtex )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create BPy_MTex PyObject" );
+
+ pymtex->mtex = mtex;
+ return ( PyObject * ) pymtex;
+}
+
+MTex *MTex_FromPyObject( PyObject * pyobj )
+{
+ return ( ( BPy_MTex * ) pyobj )->mtex;
+}
+
+/*****************************************************************************/
+/* Python BPy_MTex methods: */
+/*****************************************************************************/
+
+static PyObject *MTex_setTexMethod( BPy_MTex * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)MTex_setTex );
+}
+
+static int MTex_compare( BPy_MTex * a, BPy_MTex * b )
+{
+ return ( a->mtex == b->mtex ) ? 0 : -1;
+}
+
+static PyObject *MTex_repr( BPy_MTex * self )
+{
+ return PyString_FromFormat( "[MTex]" );
+}
+
+
+/*****************************************************************************/
+/* Python BPy_MTex get and set functions: */
+/*****************************************************************************/
+
+static PyObject *MTex_getTex( BPy_MTex *self, void *closure )
+{
+ if( self->mtex->tex )
+ return Texture_CreatePyObject( self->mtex->tex );
+ else
+ Py_RETURN_NONE;
+}
+
+static int MTex_setTex( BPy_MTex *self, PyObject *value, void *closure)
+{
+ return GenericLib_assignData(value, (void **) &self->mtex->tex, 0, 1, ID_TE, 0);
+}
+
+static PyObject *MTex_getTexCo( BPy_MTex *self, void *closure )
+{
+ return PyInt_FromLong( self->mtex->texco );
+}
+
+static int MTex_setTexCo( BPy_MTex *self, PyObject *value, void *closure)
+{
+ int texco;
+
+ if( !PyInt_Check( value ) ) {
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "Value must be a member of Texture.TexCo dictionary" );
+ }
+
+ texco = PyInt_AsLong( value ) ;
+
+ if (texco != TEXCO_ORCO && texco != TEXCO_REFL && texco != TEXCO_NORM &&
+ texco != TEXCO_GLOB && texco != TEXCO_UV && texco != TEXCO_OBJECT &&
+ texco != TEXCO_STRESS && texco != TEXCO_TANGENT && texco != TEXCO_WINDOW &&
+ texco != TEXCO_VIEW && texco != TEXCO_STICKY )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "Value must be a member of Texture.TexCo dictionary" );
+
+ self->mtex->texco = (short)texco;
+
+ return 0;
+}
+
+static PyObject *MTex_getObject( BPy_MTex *self, void *closure )
+{
+ if( self->mtex->object )
+ return Object_CreatePyObject( self->mtex->object );
+ else
+ Py_RETURN_NONE;
+}
+
+static int MTex_setObject( BPy_MTex *self, PyObject *value, void *closure)
+{
+ return GenericLib_assignData(value, (void **) &self->mtex->object, 0, 1, ID_OB, 0);
+}
+
+static PyObject *MTex_getUVLayer( BPy_MTex *self, void *closure )
+{
+ return PyString_FromString(self->mtex->uvname);
+}
+
+static int MTex_setUVLayer( BPy_MTex *self, PyObject *value, void *closure)
+{
+ if ( !PyString_Check(value) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected string value" );
+ BLI_strncpy(self->mtex->uvname, PyString_AsString(value), 31);
+ return 0;
+}
+
+static PyObject *MTex_getMapTo( BPy_MTex *self, void *closure )
+{
+ return PyInt_FromLong( self->mtex->mapto );
+}
+
+static int MTex_setMapTo( BPy_MTex *self, PyObject *value, void *closure)
+{
+ int mapto;
+
+ if( !PyInt_Check( value ) ) {
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected an int" );
+ }
+
+ mapto = PyInt_AsLong( value );
+
+ /* This method is deprecated anyway. */
+ if ( mapto < 0 || mapto > 16383 ) {
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "Value must be a sum of values from Texture.MapTo dictionary" );
+ }
+
+ self->mtex->mapto = (short)mapto;
+
+ return 0;
+}
+
+static PyObject *MTex_getCol( BPy_MTex *self, void *closure )
+{
+ return Py_BuildValue( "(f,f,f)", self->mtex->r, self->mtex->g,
+ self->mtex->b );
+}
+
+static int MTex_setCol( BPy_MTex *self, PyObject *value, void *closure)
+{
+ float rgb[3];
+ int i;
+
+ if( !PyArg_ParseTuple( value, "fff",
+ &rgb[0], &rgb[1], &rgb[2] ) )
+
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected tuple of 3 floats" );
+
+ for( i = 0; i < 3; ++i )
+ if( rgb[i] < 0 || rgb[i] > 1 )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "values must be in range [0,1]" );
+
+ self->mtex->r = rgb[0];
+ self->mtex->g = rgb[1];
+ self->mtex->b = rgb[2];
+
+ return 0;
+}
+
+static PyObject *MTex_getDVar( BPy_MTex *self, void *closure )
+{
+ return PyFloat_FromDouble(self->mtex->def_var);
+}
+
+static int MTex_setDVar( BPy_MTex *self, PyObject *value, void *closure)
+{
+ float f;
+
+ if ( !PyFloat_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a float" );
+
+ f = (float)PyFloat_AsDouble(value);
+
+ if (f < 0 || f > 1)
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "values must be in range [0,1]" );
+
+ self->mtex->def_var = f;
+
+ return 0;
+}
+
+static PyObject *MTex_getBlendMode( BPy_MTex *self, void *closure )
+{
+ return PyInt_FromLong(self->mtex->blendtype);
+}
+
+static int MTex_setBlendMode( BPy_MTex *self, PyObject *value, void *closure)
+{
+ int n;
+
+ if ( !PyInt_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "Value must be member of Texture.BlendModes dictionary" );
+
+ n = PyInt_AsLong(value);
+
+/* if (n != MTEX_BLEND && n != MTEX_MUL && n != MTEX_ADD &&
+ n != MTEX_SUB && n != MTEX_DIV && n != MTEX_DARK &&
+ n != MTEX_DIFF && n != MTEX_LIGHT && n != MTEX_SCREEN)*/
+ if (n < 0 || n > 8)
+ {
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "Value must be member of Texture.BlendModes dictionary" );
+ }
+
+ self->mtex->blendtype = (short)n;
+
+ return 0;
+}
+
+static PyObject *MTex_getColFac( BPy_MTex *self, void *closure )
+{
+ return PyFloat_FromDouble(self->mtex->colfac);
+}
+
+static int MTex_setColFac( BPy_MTex *self, PyObject *value, void *closure)
+{
+ float f;
+
+ if ( !PyFloat_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a float" );
+
+ f = (float)PyFloat_AsDouble(value);
+
+ if (f < 0 || f > 1)
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "values must be in range [0,1]" );
+
+ self->mtex->colfac = f;
+
+ return 0;
+}
+
+static PyObject *MTex_getNorFac( BPy_MTex *self, void *closure )
+{
+ return PyFloat_FromDouble(self->mtex->norfac);
+}
+
+static int MTex_setNorFac( BPy_MTex *self, PyObject *value, void *closure)
+{
+ float f;
+
+ if ( !PyFloat_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a float" );
+
+ f = (float)PyFloat_AsDouble(value);
+
+ if (f < 0 || f > 25)
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "values must be in range [0,25]" );
+
+ self->mtex->norfac = f;
+
+ return 0;
+}
+
+static PyObject *MTex_getVarFac( BPy_MTex *self, void *closure )
+{
+ return PyFloat_FromDouble(self->mtex->varfac);
+}
+
+static int MTex_setVarFac( BPy_MTex *self, PyObject *value, void *closure)
+{
+ float f;
+
+ if ( !PyFloat_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a float" );
+
+ f = (float)PyFloat_AsDouble(value);
+
+ if (f < 0 || f > 1)
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "values must be in range [0,1]" );
+
+ self->mtex->varfac = f;
+
+ return 0;
+}
+
+static PyObject *MTex_getDispFac( BPy_MTex *self, void *closure )
+{
+ return PyFloat_FromDouble(self->mtex->dispfac);
+}
+
+static int MTex_setDispFac( BPy_MTex *self, PyObject *value, void *closure)
+{
+ float f;
+
+ if ( !PyFloat_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a float" );
+
+ f = (float)PyFloat_AsDouble(value);
+
+ if (f < 0 || f > 1)
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "values must be in range [0,1]" );
+
+ self->mtex->dispfac = f;
+
+ return 0;
+}
+
+static PyObject *MTex_getWarpFac( BPy_MTex *self, void *closure )
+{
+ return PyFloat_FromDouble(self->mtex->warpfac);
+}
+
+static int MTex_setWarpFac( BPy_MTex *self, PyObject *value, void *closure)
+{
+ float f;
+
+ if ( !PyFloat_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a float" );
+
+ f = (float)PyFloat_AsDouble(value);
+
+ if (f < 0 || f > 1)
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "values must be in range [0,1]" );
+
+ self->mtex->warpfac = f;
+
+ return 0;
+}
+
+static PyObject *MTex_getOfs( BPy_MTex *self, void *closure )
+{
+ return Py_BuildValue( "(f,f,f)", self->mtex->ofs[0], self->mtex->ofs[1],
+ self->mtex->ofs[2] );
+}
+
+static int MTex_setOfs( BPy_MTex *self, PyObject *value, void *closure)
+{
+ float f[3];
+ int i;
+
+ if( !PyArg_ParseTuple( value, "fff", &f[0], &f[1], &f[2] ) )
+
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected tuple of 3 floats" );
+
+ for( i = 0; i < 3; ++i )
+ if( f[i] < -10 || f[i] > 10 )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "values must be in range [-10,10]" );
+
+ self->mtex->ofs[0] = f[0];
+ self->mtex->ofs[1] = f[1];
+ self->mtex->ofs[2] = f[2];
+
+ return 0;
+}
+
+static PyObject *MTex_getSize( BPy_MTex *self, void *closure )
+{
+ return Py_BuildValue( "(f,f,f)", self->mtex->size[0], self->mtex->size[1],
+ self->mtex->size[2] );
+}
+
+static int MTex_setSize( BPy_MTex *self, PyObject *value, void *closure)
+{
+ float f[3];
+ int i;
+
+ if( !PyArg_ParseTuple( value, "fff", &f[0], &f[1], &f[2] ) )
+
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected tuple of 3 floats" );
+
+ for( i = 0; i < 3; ++i )
+ if( f[i] < -100 || f[i] > 100 )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "values must be in range [-100,100]" );
+
+ self->mtex->size[0] = f[0];
+ self->mtex->size[1] = f[1];
+ self->mtex->size[2] = f[2];
+
+ return 0;
+}
+
+static PyObject *MTex_getMapping( BPy_MTex *self, void *closure )
+{
+ return PyInt_FromLong( self->mtex->mapping );
+}
+
+static int MTex_setMapping( BPy_MTex *self, PyObject *value, void *closure)
+{
+ int n;
+
+ if ( !PyInt_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "Value must be member of Texture.Mappings dictionary" );
+
+ n = PyInt_AsLong(value);
+
+/* if (n != MTEX_FLAT && n != MTEX_TUBE && n != MTEX_CUBE &&
+ n != MTEX_SPHERE) */
+ if (n < 0 || n > 3)
+ {
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "Value must be member of Texture.Mappings dictionary" );
+ }
+
+ self->mtex->mapping = (char)n;
+
+ return 0;
+}
+
+static PyObject *MTex_getFlag( BPy_MTex *self, void *closure )
+{
+ return PyBool_FromLong( self->mtex->texflag & ((int) closure) );
+}
+
+static int MTex_setFlag( BPy_MTex *self, PyObject *value, void *closure)
+{
+ if ( !PyBool_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a bool");
+
+ if ( value == Py_True )
+ self->mtex->texflag |= (int)closure;
+ else
+ self->mtex->texflag &= ~((int) closure);
+
+ return 0;
+}
+
+static PyObject *MTex_getProjX( BPy_MTex *self, void *closure )
+{
+ return PyInt_FromLong( self->mtex->projx );
+}
+
+static int MTex_setProjX( BPy_MTex *self, PyObject *value, void *closure)
+{
+ int proj;
+
+ if( !PyInt_Check( value ) ) {
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "Value must be a member of Texture.Proj dictionary" );
+ }
+
+ proj = PyInt_AsLong( value ) ;
+
+ /* valid values are from PROJ_N to PROJ_Z = 0 to 3 */
+ if (proj < 0 || proj > 3)
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "Value must be a member of Texture.Proj dictionary" );
+
+ self->mtex->projx = (char)proj;
+
+ return 0;
+}
+
+static PyObject *MTex_getProjY( BPy_MTex *self, void *closure )
+{
+ return PyInt_FromLong( self->mtex->projy );
+}
+
+static int MTex_setProjY( BPy_MTex *self, PyObject *value, void *closure )
+{
+ int proj;
+
+ if( !PyInt_Check( value ) ) {
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "Value must be a member of Texture.Proj dictionary" );
+ }
+
+ proj = PyInt_AsLong( value ) ;
+
+ /* valid values are from PROJ_N to PROJ_Z = 0 to 3 */
+ if (proj < 0 || proj > 3)
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "Value must be a member of Texture.Proj dictionary" );
+
+ self->mtex->projy = (char)proj;
+
+ return 0;
+}
+
+static PyObject *MTex_getProjZ( BPy_MTex *self, void *closure )
+{
+ return PyInt_FromLong( self->mtex->projz );
+}
+
+static int MTex_setProjZ( BPy_MTex *self, PyObject *value, void *closure)
+{
+ int proj;
+
+ if( !PyInt_Check( value ) ) {
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "Value must be a member of Texture.Proj dictionary" );
+ }
+
+ proj = PyInt_AsLong( value ) ;
+
+ /* valid values are from PROJ_N to PROJ_Z = 0 to 3 */
+ if (proj < 0 || proj > 3)
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "Value must be a member of Texture.Proj dictionary" );
+
+ self->mtex->projz = (char)proj;
+
+ return 0;
+}
+
+static PyObject *MTex_getMapToFlag( BPy_MTex *self, void *closure )
+{
+ int flag = (int) closure;
+
+ if ( self->mtex->mapto & flag )
+ {
+ return PyInt_FromLong( ( self->mtex->maptoneg & flag ) ? -1 : 1 );
+ } else {
+ return PyInt_FromLong( 0 );
+ }
+}
+
+static int MTex_setMapToFlag( BPy_MTex *self, PyObject *value, void *closure)
+{
+ int flag = (int) closure;
+ int intVal;
+
+ if ( !PyInt_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected an int");
+
+ intVal = PyInt_AsLong( value );
+
+ if (flag == MAP_COL || flag == MAP_COLSPEC || flag == MAP_COLMIR ||
+ flag == MAP_WARP) {
+ if (intVal < 0 || intVal > 1) {
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "value for that mapping must be 0 or 1" );
+ }
+ } else {
+ if (intVal < -1 || intVal > 1) {
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "value for that mapping must be -1, 0 or 1" );
+ }
+ }
+
+ switch (intVal)
+ {
+ case 0:
+ self->mtex->mapto &= ~flag;
+ self->mtex->maptoneg &= ~flag;
+ break;
+
+ case 1:
+ self->mtex->mapto |= flag;
+ self->mtex->maptoneg &= ~flag;
+ break;
+
+ case -1:
+ self->mtex->mapto |= flag;
+ self->mtex->maptoneg |= flag;
+ break;
+ }
+
+ return 0;
+}
diff --git a/source/blender/python/api2_2x/MTex.h b/source/blender/python/api2_2x/MTex.h
new file mode 100644
index 00000000000..2148212d82f
--- /dev/null
+++ b/source/blender/python/api2_2x/MTex.h
@@ -0,0 +1,63 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Alex Mole
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_MTEX_H
+#define EXPP_MTEX_H
+
+#include <Python.h>
+#include "DNA_texture_types.h"
+
+
+/*****************************************************************************/
+/* Python BPy_MTex structure definition */
+/*****************************************************************************/
+
+typedef struct {
+ PyObject_HEAD
+ MTex * mtex;
+} BPy_MTex;
+
+extern PyTypeObject MTex_Type;
+
+#define BPy_MTex_Check(v) ((v)->ob_type == &MTex_Type)
+
+
+/*****************************************************************************/
+/* Module Blender.Texture.MTex - public functions */
+/*****************************************************************************/
+
+PyObject *MTex_Init( void );
+PyObject *MTex_CreatePyObject( struct MTex *obj );
+MTex *MTex_FromPyObject( PyObject * py_obj );
+
+
+#endif /* EXPP_MTEX_H */
diff --git a/source/blender/python/api2_2x/Makefile b/source/blender/python/api2_2x/Makefile
new file mode 100644
index 00000000000..8a13adae989
--- /dev/null
+++ b/source/blender/python/api2_2x/Makefile
@@ -0,0 +1,64 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+#
+
+LIBNAME = python
+DIR = $(OCGDIR)/blender/python
+
+CSRCS ?= $(wildcard *.c) $(wildcard ../*.c)
+
+include nan_compile.mk
+
+CFLAGS += $(LEVEL_1_C_WARNINGS)
+
+ifeq ($(WITH_FFMPEG), true)
+ CPPFLAGS += -DWITH_FFMPEG
+endif
+
+CPPFLAGS += -I$(OPENGL_HEADERS)
+CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
+CPPFLAGS += -I../../makesdna
+CPPFLAGS += -I../../blenkernel
+CPPFLAGS += -I../../blenlib
+CPPFLAGS += -I../../blenloader
+CPPFLAGS += -I../../include
+CPPFLAGS += -I../../render/extern/include
+CPPFLAGS += -I../../radiosity/extern/include
+CPPFLAGS += -I$(NAN_BMFONT)/include
+CPPFLAGS += -I../../imbuf
+CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION)
+
+# We'll just add a little duct tape to fix things here ...
+.PHONY: clean
+clean::
+ @rm -f $(OCGDIR)/blender/BPY_*.o
+ @rm -f $(OCGDIR)/blender/BPY_*.d
diff --git a/source/blender/python/api2_2x/Material.c b/source/blender/python/api2_2x/Material.c
new file mode 100644
index 00000000000..851a46d51e5
--- /dev/null
+++ b/source/blender/python/api2_2x/Material.c
@@ -0,0 +1,3048 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano, Michel Selten, Alex Mole,
+ * Alexander Szakaly, Campbell Barton, Ken Hughes
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#include "Material.h" /*This must come first*/
+
+#include "DNA_space_types.h"
+#include "DNA_material_types.h"
+#include "BKE_main.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_material.h"
+#include "BKE_texture.h"
+#include "BKE_idprop.h"
+#include "BKE_utildefines.h" /* for CLAMP */
+#include "MEM_guardedalloc.h"
+#include "BLI_blenlib.h"
+#include "BSE_editipo.h"
+#include "BIF_space.h"
+#include "mydevice.h"
+#include "constant.h"
+#include "MTex.h"
+#include "Texture.h"
+#include "Ipo.h"
+#include "Group.h"
+#include "gen_utils.h"
+#include "gen_library.h"
+#include "IDProp.h"
+
+/*****************************************************************************/
+/* Python BPy_Material defaults: */
+/*****************************************************************************/
+/* Material MIN, MAX values */
+#define EXPP_MAT_ADD_MIN 0.0f
+#define EXPP_MAT_ADD_MAX 1.0f
+#define EXPP_MAT_ALPHA_MIN 0.0f
+#define EXPP_MAT_ALPHA_MAX 1.0f
+#define EXPP_MAT_AMB_MIN 0.0f
+#define EXPP_MAT_AMB_MAX 1.0f
+#define EXPP_MAT_COL_MIN 0.0f /* min/max for all ... */
+#define EXPP_MAT_COL_MAX 1.0f /* ... color triplets */
+#define EXPP_MAT_EMIT_MIN 0.0f
+#define EXPP_MAT_EMIT_MAX 1.0f
+#define EXPP_MAT_REF_MIN 0.0f
+#define EXPP_MAT_REF_MAX 1.0f
+#define EXPP_MAT_SPEC_MIN 0.0f
+#define EXPP_MAT_SPEC_MAX 2.0f
+#define EXPP_MAT_SPECTRA_MIN 0.0f
+#define EXPP_MAT_SPECTRA_MAX 1.0f
+
+/* Shader specific settings */
+
+#define EXPP_MAT_ROUGHNESS_MIN 0.0f
+#define EXPP_MAT_ROUGHNESS_MAX 3.140f
+#define EXPP_MAT_SPECSIZE_MIN 0.0f
+#define EXPP_MAT_SPECSIZE_MAX 1.530f
+#define EXPP_MAT_DIFFUSESIZE_MIN 0.0f
+#define EXPP_MAT_DIFFUSESIZE_MAX 3.140f
+#define EXPP_MAT_SPECSMOOTH_MIN 0.0f
+#define EXPP_MAT_SPECSMOOTH_MAX 1.0f
+#define EXPP_MAT_DIFFUSESMOOTH_MIN 0.0f
+#define EXPP_MAT_DIFFUSESMOOTH_MAX 1.0f
+#define EXPP_MAT_DIFFUSE_DARKNESS_MIN 0.0f
+#define EXPP_MAT_DIFFUSE_DARKNESS_MAX 2.0f
+#define EXPP_MAT_REFRACINDEX_MIN 1.0f
+#define EXPP_MAT_REFRACINDEX_MAX 10.0f
+#define EXPP_MAT_RMS_MIN 0.0f
+#define EXPP_MAT_RMS_MAX 0.4f
+/* End shader settings */
+
+#define EXPP_MAT_ZOFFS_MIN 0.0
+#define EXPP_MAT_ZOFFS_MAX 10.0
+#define EXPP_MAT_HALOSIZE_MIN 0.0
+#define EXPP_MAT_HALOSIZE_MAX 100.0
+#define EXPP_MAT_FLARESIZE_MIN 0.1f
+#define EXPP_MAT_FLARESIZE_MAX 25.0
+#define EXPP_MAT_FLAREBOOST_MIN 0.1f
+#define EXPP_MAT_FLAREBOOST_MAX 10.0
+#define EXPP_MAT_SUBSIZE_MIN 0.1f
+#define EXPP_MAT_SUBSIZE_MAX 25.0
+
+#define EXPP_MAT_HARD_MIN 1
+#define EXPP_MAT_HARD_MAX 255 /* 127 with MODE HALO ON */
+#define EXPP_MAT_HALOSEED_MIN 0
+#define EXPP_MAT_HALOSEED_MAX 255
+#define EXPP_MAT_NFLARES_MIN 1
+#define EXPP_MAT_NFLARES_MAX 32
+#define EXPP_MAT_FLARESEED_MIN 0
+#define EXPP_MAT_FLARESEED_MAX 255
+#define EXPP_MAT_NSTARS_MIN 3
+#define EXPP_MAT_NSTARS_MAX 50
+#define EXPP_MAT_NLINES_MIN 0
+#define EXPP_MAT_NLINES_MAX 250
+#define EXPP_MAT_NRINGS_MIN 0
+#define EXPP_MAT_NRINGS_MAX 24
+
+#define EXPP_MAT_RAYMIRR_MIN 0.0
+#define EXPP_MAT_RAYMIRR_MAX 1.0
+#define EXPP_MAT_MIRRDEPTH_MIN 0
+#define EXPP_MAT_MIRRDEPTH_MAX 10
+#define EXPP_MAT_FRESNELMIRR_MIN 0.0
+#define EXPP_MAT_FRESNELMIRR_MAX 5.0
+#define EXPP_MAT_FRESNELMIRRFAC_MIN 1.0
+#define EXPP_MAT_FRESNELMIRRFAC_MAX 5.0
+#define EXPP_MAT_FILTER_MIN 0.0
+#define EXPP_MAT_FILTER_MAX 1.0
+#define EXPP_MAT_TRANSLUCENCY_MIN 0.0
+#define EXPP_MAT_TRANSLUCENCY_MAX 1.0
+#define EXPP_MAT_ZOFFS_MIN 0.0
+#define EXPP_MAT_ZOFFS_MAX 10.0
+#define EXPP_MAT_IOR_MIN 1.0
+#define EXPP_MAT_IOR_MAX 3.0
+#define EXPP_MAT_TRANSDEPTH_MIN 0
+#define EXPP_MAT_TRANSDEPTH_MAX 10
+#define EXPP_MAT_FRESNELTRANS_MIN 0.0
+#define EXPP_MAT_FRESNELTRANS_MAX 5.0
+#define EXPP_MAT_FRESNELTRANSFAC_MIN 1.0
+#define EXPP_MAT_FRESNELTRANSFAC_MAX 5.0
+#define EXPP_MAT_SPECTRANS_MIN 0.0
+#define EXPP_MAT_SPECTRANS_MAX 1.0
+#define EXPP_MAT_MIRRTRANSADD_MIN 0.0
+#define EXPP_MAT_MIRRTRANSADD_MAX 1.0
+
+/* closure values for getColorComponent()/setColorComponent() */
+
+#define EXPP_MAT_COMP_R 0
+#define EXPP_MAT_COMP_G 1
+#define EXPP_MAT_COMP_B 2
+#define EXPP_MAT_COMP_SPECR 3
+#define EXPP_MAT_COMP_SPECG 4
+#define EXPP_MAT_COMP_SPECB 5
+#define EXPP_MAT_COMP_MIRR 6
+#define EXPP_MAT_COMP_MIRG 7
+#define EXPP_MAT_COMP_MIRB 8
+#define EXPP_MAT_COMP_SSSR 9
+#define EXPP_MAT_COMP_SSSG 10
+#define EXPP_MAT_COMP_SSSB 11
+
+
+#define IPOKEY_RGB 0
+#define IPOKEY_ALPHA 1
+#define IPOKEY_HALOSIZE 2
+#define IPOKEY_MODE 3
+#define IPOKEY_ALLCOLOR 10
+#define IPOKEY_ALLMIRROR 14
+#define IPOKEY_OFS 12
+#define IPOKEY_SIZE 13
+#define IPOKEY_ALLMAPPING 11
+
+/* SSS Settings */
+#define EXPP_MAT_SSS_SCALE_MIN 0.001
+#define EXPP_MAT_SSS_SCALE_MAX 1000.0
+#define EXPP_MAT_SSS_RADIUS_MIN 0.0
+#define EXPP_MAT_SSS_RADIUS_MAX 10000.0
+#define EXPP_MAT_SSS_IOR_MIN 0.1
+#define EXPP_MAT_SSS_IOR_MAX 2.0
+#define EXPP_MAT_SSS_ERROR_MIN 0.0
+#define EXPP_MAT_SSS_ERROR_MAX 1.0
+#define EXPP_MAT_SSS_FRONT_MIN 0.0
+#define EXPP_MAT_SSS_FRONT_MAX 2.0
+#define EXPP_MAT_SSS_BACK_MIN 0.0
+#define EXPP_MAT_SSS_BACK_MAX 10.0
+
+
+/*****************************************************************************/
+/* Python API function prototypes for the Material module. */
+/*****************************************************************************/
+static PyObject *M_Material_New( PyObject * self, PyObject * args,
+ PyObject * keywords );
+static PyObject *M_Material_Get( PyObject * self, PyObject * args );
+
+/*****************************************************************************/
+/* The following string definitions are used for documentation strings. In */
+/* Python these will be written to the console when doing a */
+/* Blender.Material.__doc__ */
+/*****************************************************************************/
+static char M_Material_doc[] = "The Blender Material module";
+
+static char M_Material_New_doc[] =
+ "(name) - return a new material called 'name'\n\
+() - return a new material called 'Mat'";
+
+static char M_Material_Get_doc[] =
+ "(name) - return the material called 'name', None if not found.\n\
+() - return a list of all materials in the current scene.";
+
+/*****************************************************************************/
+/* Python method structure definition for Blender.Material module: */
+/*****************************************************************************/
+struct PyMethodDef M_Material_methods[] = {
+ {"New", ( PyCFunction ) M_Material_New, METH_VARARGS | METH_KEYWORDS,
+ M_Material_New_doc},
+ {"Get", M_Material_Get, METH_VARARGS, M_Material_Get_doc},
+ {"get", M_Material_Get, METH_VARARGS, M_Material_Get_doc},
+ {NULL, NULL, 0, NULL}
+};
+
+/*****************************************************************************/
+/* Function: M_Material_New */
+/* Python equivalent: Blender.Material.New */
+/*****************************************************************************/
+static PyObject *M_Material_New( PyObject * self, PyObject * args,
+ PyObject * keywords )
+{
+ char *name = "Mat";
+ static char *kwlist[] = { "name", NULL };
+ BPy_Material *pymat; /* for Material Data object wrapper in Python */
+ Material *blmat; /* for actual Material Data we create in Blender */
+ char buf[21];
+
+ if( !PyArg_ParseTupleAndKeywords
+ ( args, keywords, "|s", kwlist, &name ) )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_AttributeError,
+ "expected string or nothing as argument" ) );
+
+ if( strcmp( name, "Mat" ) != 0 ) /* use gave us a name ? */
+ PyOS_snprintf( buf, sizeof( buf ), "%s", name );
+
+ blmat = add_material( name ); /* first create the Material Data in Blender */
+
+ if( blmat ) /* now create the wrapper obj in Python */
+ pymat = ( BPy_Material * ) Material_CreatePyObject( blmat );
+ else
+ return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't create Material Data in Blender" ) );
+
+ blmat->id.us = 0; /* was incref'ed by add_material() above */
+
+ if( pymat == NULL )
+ return ( EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create Material Data object" ) );
+
+ return ( PyObject * ) pymat;
+}
+
+/*****************************************************************************/
+/* Function: M_Material_Get */
+/* Python equivalent: Blender.Material.Get */
+/* Description: Receives a string and returns the material whose */
+/* name matches the string. If no argument is */
+/* passed in, a list with all materials in the */
+/* current scene is returned. */
+/*****************************************************************************/
+static PyObject *M_Material_Get( PyObject * self, PyObject * args )
+{
+ char *name = NULL;
+ Material *mat_iter;
+
+ if( !PyArg_ParseTuple( args, "|s", &name ) )
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument (or nothing)" ) );
+
+ if( name ) { /* (name) - Search material by name */
+
+ mat_iter = ( Material * ) GetIdFromList( &( G.main->mat ), name );
+
+ if( mat_iter == NULL ) { /* Requested material doesn't exist */
+ char error_msg[64];
+ PyOS_snprintf( error_msg, sizeof( error_msg ),
+ "Material \"%s\" not found", name );
+ return EXPP_ReturnPyObjError( PyExc_NameError,
+ error_msg );
+ }
+
+ return Material_CreatePyObject( mat_iter );
+ }
+
+ else { /* () - return a list with all materials in the scene */
+ int index = 0;
+ PyObject *matlist, *pyobj;
+
+ matlist = PyList_New( BLI_countlist( &( G.main->mat ) ) );
+
+ if( !matlist )
+ return ( EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create PyList" ) );
+
+ mat_iter = G.main->mat.first;
+ while( mat_iter ) {
+ pyobj = Material_CreatePyObject( mat_iter );
+
+ if( !pyobj ) {
+ Py_DECREF(matlist);
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_MemoryError,
+ "couldn't create PyObject" ) );
+ }
+ PyList_SET_ITEM( matlist, index, pyobj );
+
+ mat_iter = mat_iter->id.next;
+ index++;
+ }
+
+ return matlist;
+ }
+}
+
+static PyObject *Material_ModesDict( void )
+{
+ PyObject *Modes = PyConstant_New( );
+
+ if( Modes ) {
+ BPy_constant *c = ( BPy_constant * ) Modes;
+
+ PyConstant_Insert(c, "TRACEABLE", PyInt_FromLong(MA_TRACEBLE));
+ PyConstant_Insert(c, "SHADOW", PyInt_FromLong(MA_SHADOW));
+ PyConstant_Insert(c, "SHADOWBUF", PyInt_FromLong(MA_SHADBUF));
+ PyConstant_Insert(c, "TANGENTSTR", PyInt_FromLong(MA_TANGENT_STR));
+ PyConstant_Insert(c, "FULLOSA", PyInt_FromLong(MA_FULL_OSA));
+ PyConstant_Insert(c, "RAYBIAS", PyInt_FromLong(MA_RAYBIAS));
+ PyConstant_Insert(c, "TRANSPSHADOW", PyInt_FromLong(MA_SHADOW_TRA));
+ PyConstant_Insert(c, "RAMPCOL", PyInt_FromLong(MA_RAMP_COL));
+ PyConstant_Insert(c, "RAMPSPEC", PyInt_FromLong(MA_RAMP_SPEC));
+ PyConstant_Insert(c, "SHADELESS", PyInt_FromLong(MA_SHLESS));
+ PyConstant_Insert(c, "WIRE", PyInt_FromLong(MA_WIRE));
+ PyConstant_Insert(c, "VCOL_LIGHT", PyInt_FromLong(MA_VERTEXCOL));
+ PyConstant_Insert(c, "HALO", PyInt_FromLong(MA_HALO));
+ PyConstant_Insert(c, "ZTRANSP", PyInt_FromLong(MA_ZTRA));
+ PyConstant_Insert(c, "VCOL_PAINT", PyInt_FromLong(MA_VERTEXCOLP));
+ PyConstant_Insert(c, "ZINVERT", PyInt_FromLong(MA_ZINV));
+ PyConstant_Insert(c, "HALORINGS", PyInt_FromLong(MA_HALO_RINGS));
+ PyConstant_Insert(c, "ENV", PyInt_FromLong(MA_ENV));
+ PyConstant_Insert(c, "HALOLINES", PyInt_FromLong(MA_HALO_LINES));
+ PyConstant_Insert(c, "ONLYSHADOW", PyInt_FromLong(MA_ONLYSHADOW));
+ PyConstant_Insert(c, "HALOXALPHA", PyInt_FromLong(MA_HALO_XALPHA));
+ PyConstant_Insert(c, "HALOSTAR", PyInt_FromLong(MA_STAR));
+ PyConstant_Insert(c, "TEXFACE", PyInt_FromLong(MA_FACETEXTURE));
+ PyConstant_Insert(c, "HALOTEX", PyInt_FromLong(MA_HALOTEX));
+ PyConstant_Insert(c, "HALOPUNO", PyInt_FromLong(MA_HALOPUNO));
+ PyConstant_Insert(c, "NOMIST", PyInt_FromLong(MA_NOMIST));
+ PyConstant_Insert(c, "HALOSHADE", PyInt_FromLong(MA_HALO_SHADE));
+ PyConstant_Insert(c, "HALOFLARE", PyInt_FromLong(MA_HALO_FLARE));
+ PyConstant_Insert(c, "RADIO", PyInt_FromLong(MA_RADIO));
+ PyConstant_Insert(c, "RAYMIRROR", PyInt_FromLong(MA_RAYMIRROR));
+ PyConstant_Insert(c, "ZTRA", PyInt_FromLong(MA_ZTRA));
+ PyConstant_Insert(c, "RAYTRANSP", PyInt_FromLong(MA_RAYTRANSP));
+ PyConstant_Insert(c, "TANGENT_V", PyInt_FromLong(MA_TANGENT_V));
+ PyConstant_Insert(c, "NMAP_TS", PyInt_FromLong(MA_NORMAP_TANG));
+ PyConstant_Insert(c, "GROUP_EXCLUSIVE", PyInt_FromLong(MA_GROUP_NOLAY));
+ }
+
+ return Modes;
+}
+
+
+static PyObject *Material_ShadersDict( void )
+{
+ PyObject *Shaders = PyConstant_New( );
+
+ if( Shaders ) {
+ BPy_constant *c = ( BPy_constant * ) Shaders;
+
+ PyConstant_Insert(c, "DIFFUSE_LAMBERT", PyInt_FromLong(MA_DIFF_LAMBERT));
+ PyConstant_Insert(c, "DIFFUSE_ORENNAYAR", PyInt_FromLong(MA_DIFF_ORENNAYAR));
+ PyConstant_Insert(c, "DIFFUSE_TOON", PyInt_FromLong(MA_DIFF_TOON));
+ PyConstant_Insert(c, "DIFFUSE_MINNAERT", PyInt_FromLong(MA_DIFF_MINNAERT));
+ PyConstant_Insert(c, "SPEC_COOKTORR", PyInt_FromLong(MA_SPEC_COOKTORR));
+ PyConstant_Insert(c, "SPEC_PHONG", PyInt_FromLong(MA_SPEC_PHONG));
+ PyConstant_Insert(c, "SPEC_BLINN", PyInt_FromLong(MA_SPEC_BLINN));
+ PyConstant_Insert(c, "SPEC_TOON", PyInt_FromLong(MA_SPEC_TOON));
+ PyConstant_Insert(c, "SPEC_WARDISO", PyInt_FromLong(MA_SPEC_WARDISO));
+
+ }
+
+ return Shaders;
+}
+
+
+/*****************************************************************************/
+/* Function: Material_Init */
+/*****************************************************************************/
+PyObject *Material_Init( void )
+{
+ PyObject *submodule, *Modes, *Shaders;
+
+ if( PyType_Ready( &Material_Type ) < 0)
+ return NULL;
+
+ Modes = Material_ModesDict( );
+ Shaders = Material_ShadersDict( );
+
+ submodule = Py_InitModule3( "Blender.Material",
+ M_Material_methods, M_Material_doc );
+
+ if( Modes )
+ PyModule_AddObject( submodule, "Modes", Modes );
+ if( Shaders )
+ PyModule_AddObject( submodule, "Shaders", Shaders );
+
+ PyModule_AddIntConstant( submodule, "RGB", IPOKEY_RGB );
+ PyModule_AddIntConstant( submodule, "ALPHA", IPOKEY_ALPHA );
+ PyModule_AddIntConstant( submodule, "HALOSIZE", IPOKEY_HALOSIZE );
+ PyModule_AddIntConstant( submodule, "MODE", IPOKEY_MODE );
+ PyModule_AddIntConstant( submodule, "ALLCOLOR", IPOKEY_ALLCOLOR );
+ PyModule_AddIntConstant( submodule, "ALLMIRROR", IPOKEY_ALLMIRROR );
+ PyModule_AddIntConstant( submodule, "OFS", IPOKEY_OFS );
+ PyModule_AddIntConstant( submodule, "SIZE", IPOKEY_SIZE );
+ PyModule_AddIntConstant( submodule, "ALLMAPPING", IPOKEY_ALLMAPPING );
+
+ return ( submodule );
+}
+
+/***************************/
+/*** The Material PyType ***/
+/***************************/
+
+static PyObject *Matr_oldsetAdd( BPy_Material * self, PyObject * args );
+static PyObject *Matr_oldsetAlpha( BPy_Material * self, PyObject * args );
+static PyObject *Matr_oldsetAmb( BPy_Material * self, PyObject * args );
+static PyObject *Matr_oldsetEmit( BPy_Material * self, PyObject * args );
+static PyObject *Matr_oldsetFilter( BPy_Material * self, PyObject * args );
+static PyObject *Matr_oldsetFlareBoost( BPy_Material * self, PyObject * args );
+static PyObject *Matr_oldsetFlareSeed( BPy_Material * self, PyObject * args );
+static PyObject *Matr_oldsetFlareSize( BPy_Material * self, PyObject * args );
+static PyObject *Matr_oldsetFresnelMirr( BPy_Material * self, PyObject * args );
+static PyObject *Matr_oldsetFresnelMirrFac( BPy_Material * self, PyObject * args );
+static PyObject *Matr_oldsetFresnelTrans( BPy_Material * self, PyObject * args );
+static PyObject *Matr_oldsetFresnelTransFac( BPy_Material * self, PyObject * args );
+static PyObject *Matr_oldsetHaloSeed( BPy_Material * self, PyObject * args );
+static PyObject *Matr_oldsetHaloSize( BPy_Material * self, PyObject * args );
+static PyObject *Matr_oldsetHardness( BPy_Material * self, PyObject * args );
+static PyObject *Matr_oldsetIOR( BPy_Material * self, PyObject * args );
+static PyObject *Matr_oldsetNFlares( BPy_Material * self, PyObject * args );
+static PyObject *Matr_oldsetNLines( BPy_Material * self, PyObject * args );
+static PyObject *Matr_oldsetNRings( BPy_Material * self, PyObject * args );
+static PyObject *Matr_oldsetNStars( BPy_Material * self, PyObject * args );
+static PyObject *Matr_oldsetRayMirr( BPy_Material * self, PyObject * args );
+static PyObject *Matr_oldsetMirrDepth( BPy_Material * self, PyObject * args );
+static PyObject *Matr_oldsetRef( BPy_Material * self, PyObject * args );
+static PyObject *Matr_oldsetSpec( BPy_Material * self, PyObject * args );
+static PyObject *Matr_oldsetSpecTransp( BPy_Material * self, PyObject * args );
+static PyObject *Matr_oldsetSubSize( BPy_Material * self, PyObject * args );
+static PyObject *Matr_oldsetTransDepth( BPy_Material * self, PyObject * args );
+static PyObject *Matr_oldsetZOffset( BPy_Material * self, PyObject * args );
+static PyObject *Matr_oldsetMode( BPy_Material * self, PyObject * args );
+static PyObject *Matr_oldsetIpo( BPy_Material * self, PyObject * args );
+static PyObject *Matr_oldsetRGBCol( BPy_Material * self, PyObject * args );
+static PyObject *Matr_oldsetSpecCol( BPy_Material * self, PyObject * args );
+static PyObject *Matr_oldsetSpecShader( BPy_Material * self, PyObject * args );
+static PyObject *Matr_oldsetMirCol( BPy_Material * self, PyObject * args );
+static PyObject *Matr_oldsetDiffuseShader( BPy_Material * self, PyObject * args );
+static PyObject *Matr_oldsetRoughness( BPy_Material * self, PyObject * args );
+static PyObject *Matr_oldsetSpecSize( BPy_Material * self, PyObject * args );
+static PyObject *Matr_oldsetDiffuseSize( BPy_Material * self, PyObject * args );
+static PyObject *Matr_oldsetSpecSmooth( BPy_Material * self, PyObject * args );
+static PyObject *Matr_oldsetDiffuseSmooth( BPy_Material * self, PyObject * args );
+static PyObject *Matr_oldsetDiffuseDarkness( BPy_Material * self, PyObject * args );
+static PyObject *Matr_oldsetRefracIndex( BPy_Material * self, PyObject * args );
+static PyObject *Matr_oldsetRms( BPy_Material * self, PyObject * args );
+static PyObject *Matr_oldsetTranslucency( BPy_Material * self, PyObject * args );
+
+static int Material_setIpo( BPy_Material * self, PyObject * value );
+
+static int Material_setMode( BPy_Material * self, PyObject * value );
+static int Material_setRGBCol( BPy_Material * self, PyObject * value );
+static int Material_setSpecCol( BPy_Material * self, PyObject * value );
+static int Material_setMirCol( BPy_Material * self, PyObject * value );
+static int Material_setSssCol( BPy_Material * self, PyObject * value );
+static int Material_setColorComponent( BPy_Material * self, PyObject * value,
+ void * closure );
+static int Material_setAmb( BPy_Material * self, PyObject * value );
+static int Material_setEmit( BPy_Material * self, PyObject * value );
+static int Material_setSpecTransp( BPy_Material * self, PyObject * value );
+static int Material_setAlpha( BPy_Material * self, PyObject * value );
+static int Material_setShadAlpha( BPy_Material * self, PyObject * value );
+static int Material_setRef( BPy_Material * self, PyObject * value );
+static int Material_setSpec( BPy_Material * self, PyObject * value );
+static int Material_setZOffset( BPy_Material * self, PyObject * value );
+static int Material_setLightGroup( BPy_Material * self, PyObject * value );
+static int Material_setAdd( BPy_Material * self, PyObject * value );
+static int Material_setHaloSize( BPy_Material * self, PyObject * value );
+static int Material_setFlareSize( BPy_Material * self, PyObject * value );
+static int Material_setFlareBoost( BPy_Material * self, PyObject * value );
+static int Material_setSubSize( BPy_Material * self, PyObject * value );
+static int Material_setHaloSeed( BPy_Material * self, PyObject * value );
+static int Material_setFlareSeed( BPy_Material * self, PyObject * value );
+static int Material_setHardness( BPy_Material * self, PyObject * value );
+static int Material_setNFlares( BPy_Material * self, PyObject * value );
+static int Material_setNStars( BPy_Material * self, PyObject * value );
+static int Material_setNLines( BPy_Material * self, PyObject * value );
+static int Material_setNRings( BPy_Material * self, PyObject * value );
+static int Material_setRayMirr( BPy_Material * self, PyObject * value );
+static int Material_setMirrDepth( BPy_Material * self, PyObject * value );
+static int Material_setFresnelMirr( BPy_Material * self, PyObject * value );
+static int Material_setFresnelMirrFac( BPy_Material * self, PyObject * value );
+static int Material_setIOR( BPy_Material * self, PyObject * value );
+static int Material_setTransDepth( BPy_Material * self, PyObject * value );
+static int Material_setFresnelTrans( BPy_Material * self, PyObject * value );
+static int Material_setFresnelTransFac( BPy_Material * self, PyObject * value );
+static int Material_setRigidBodyFriction( BPy_Material * self, PyObject * value );
+static int Material_setRigidBodyRestitution( BPy_Material * self, PyObject * value );
+
+static int Material_setSpecShader( BPy_Material * self, PyObject * value );
+static int Material_setDiffuseShader( BPy_Material * self, PyObject * value );
+static int Material_setRoughness( BPy_Material * self, PyObject * value );
+static int Material_setSpecSize( BPy_Material * self, PyObject * value );
+static int Material_setDiffuseSize( BPy_Material * self, PyObject * value );
+static int Material_setSpecSmooth( BPy_Material * self, PyObject * value );
+static int Material_setDiffuseSmooth( BPy_Material * self, PyObject * value );
+static int Material_setDiffuseDarkness( BPy_Material * self, PyObject * value );
+static int Material_setRefracIndex( BPy_Material * self, PyObject * value );
+static int Material_setRms( BPy_Material * self, PyObject * value );
+static int Material_setFilter( BPy_Material * self, PyObject * value );
+static int Material_setTranslucency( BPy_Material * self, PyObject * value );
+
+static int Material_setSssEnable( BPy_Material * self, PyObject * value );
+static int Material_setSssScale( BPy_Material * self, PyObject * value );
+static int Material_setSssRadius( BPy_Material * self, PyObject * value, void * type );
+static int Material_setSssIOR( BPy_Material * self, PyObject * value );
+static int Material_setSssError( BPy_Material * self, PyObject * value );
+static int Material_setSssColorBlend( BPy_Material * self, PyObject * value );
+static int Material_setSssTexScatter( BPy_Material * self, PyObject * value );
+static int Material_setSssFront( BPy_Material * self, PyObject * value );
+static int Material_setSssBack( BPy_Material * self, PyObject * value );
+static int Material_setSssBack( BPy_Material * self, PyObject * value );
+
+static PyObject *Material_getColorComponent( BPy_Material * self,
+ void * closure );
+
+/*static int Material_setSeptex( BPy_Material * self, PyObject * value );
+ static PyObject *Material_getSeptex( BPy_Material * self );*/
+
+/*****************************************************************************/
+/* Python BPy_Material methods declarations: */
+/*****************************************************************************/
+static PyObject *Material_getIpo( BPy_Material * self );
+static PyObject *Material_getMode( BPy_Material * self );
+static PyObject *Material_getRGBCol( BPy_Material * self );
+/*static PyObject *Material_getAmbCol(BPy_Material *self);*/
+static PyObject *Material_getSpecCol( BPy_Material * self );
+static PyObject *Material_getMirCol( BPy_Material * self );
+static PyObject *Material_getSssCol( BPy_Material * self );
+static PyObject *Material_getAmb( BPy_Material * self );
+static PyObject *Material_getEmit( BPy_Material * self );
+static PyObject *Material_getAlpha( BPy_Material * self );
+static PyObject *Material_getShadAlpha( BPy_Material * self );
+static PyObject *Material_getRef( BPy_Material * self );
+static PyObject *Material_getSpec( BPy_Material * self );
+static PyObject *Material_getSpecTransp( BPy_Material * self );
+static PyObject *Material_getAdd( BPy_Material * self );
+static PyObject *Material_getZOffset( BPy_Material * self );
+static PyObject *Material_getLightGroup( BPy_Material * self );
+static PyObject *Material_getHaloSize( BPy_Material * self );
+static PyObject *Material_getHaloSeed( BPy_Material * self );
+static PyObject *Material_getFlareSize( BPy_Material * self );
+static PyObject *Material_getFlareSeed( BPy_Material * self );
+static PyObject *Material_getFlareBoost( BPy_Material * self );
+static PyObject *Material_getSubSize( BPy_Material * self );
+static PyObject *Material_getHardness( BPy_Material * self );
+static PyObject *Material_getNFlares( BPy_Material * self );
+static PyObject *Material_getNStars( BPy_Material * self );
+static PyObject *Material_getNLines( BPy_Material * self );
+static PyObject *Material_getNRings( BPy_Material * self );
+/* Shader settings */
+static PyObject *Material_getSpecShader( BPy_Material * self );
+static PyObject *Material_getDiffuseShader( BPy_Material * self );
+static PyObject *Material_getRoughness( BPy_Material * self );
+static PyObject *Material_getSpecSize( BPy_Material * self );
+static PyObject *Material_getDiffuseSize( BPy_Material * self );
+static PyObject *Material_getSpecSmooth( BPy_Material * self );
+static PyObject *Material_getDiffuseSmooth( BPy_Material * self );
+static PyObject *Material_getDiffuseDarkness( BPy_Material * self );
+static PyObject *Material_getRefracIndex( BPy_Material * self );
+static PyObject *Material_getRms( BPy_Material * self );
+
+static PyObject *Material_getRayMirr( BPy_Material * self );
+static PyObject *Material_getMirrDepth( BPy_Material * self );
+static PyObject *Material_getFresnelMirr( BPy_Material * self );
+static PyObject *Material_getFresnelMirrFac( BPy_Material * self );
+static PyObject *Material_getIOR( BPy_Material * self );
+static PyObject *Material_getTransDepth( BPy_Material * self );
+static PyObject *Material_getFresnelTrans( BPy_Material * self );
+static PyObject *Material_getFresnelTransFac( BPy_Material * self );
+static PyObject *Material_getRigidBodyFriction( BPy_Material * self );
+static PyObject *Material_getRigidBodyRestitution( BPy_Material * self );
+
+static PyObject *Material_getSssEnable( BPy_Material * self );
+static PyObject *Material_getSssScale( BPy_Material * self );
+static PyObject *Material_getSssRadius( BPy_Material * self, void * type );
+static PyObject *Material_getSssIOR( BPy_Material * self );
+static PyObject *Material_getSssError( BPy_Material * self );
+static PyObject *Material_getSssColorBlend( BPy_Material * self );
+static PyObject *Material_getSssTexScatter( BPy_Material * self );
+static PyObject *Material_getSssFront( BPy_Material * self );
+static PyObject *Material_getSssBack( BPy_Material * self );
+static PyObject *Material_getSssBack( BPy_Material * self );
+
+static PyObject *Material_getFilter( BPy_Material * self );
+static PyObject *Material_getTranslucency( BPy_Material * self );
+static PyObject *Material_getTextures( BPy_Material * self );
+static PyObject *Material_clearIpo( BPy_Material * self );
+
+static PyObject *Material_setTexture( BPy_Material * self, PyObject * args );
+static PyObject *Material_clearTexture( BPy_Material * self, PyObject * value );
+
+static PyObject *Material_getScriptLinks(BPy_Material *self, PyObject * value );
+static PyObject *Material_addScriptLink(BPy_Material * self, PyObject * args );
+static PyObject *Material_clearScriptLinks(BPy_Material *self, PyObject *args);
+
+static PyObject *Material_insertIpoKey( BPy_Material * self, PyObject * args );
+static PyObject *Material_getColorband( BPy_Material * self, void * type);
+int Material_setColorband( BPy_Material * self, PyObject * value, void * type);
+static PyObject *Material_copy( BPy_Material * self );
+
+
+/*****************************************************************************/
+/* Python BPy_Material methods table: */
+/*****************************************************************************/
+static PyMethodDef BPy_Material_methods[] = {
+ /* name, method, flags, doc */
+ {"getName", ( PyCFunction ) GenericLib_getName, METH_NOARGS,
+ "() - Return Material's name"},
+ {"getIpo", ( PyCFunction ) Material_getIpo, METH_NOARGS,
+ "() - Return Material's ipo or None if not found"},
+ {"getMode", ( PyCFunction ) Material_getMode, METH_NOARGS,
+ "() - Return Material's mode flags"},
+ {"getRGBCol", ( PyCFunction ) Material_getRGBCol, METH_NOARGS,
+ "() - Return Material's rgb color triplet"},
+/* {"getAmbCol", (PyCFunction)Material_getAmbCol, METH_NOARGS,
+ "() - Return Material's ambient color"},*/
+ {"getSpecCol", ( PyCFunction ) Material_getSpecCol, METH_NOARGS,
+ "() - Return Material's specular color"},
+ {"getMirCol", ( PyCFunction ) Material_getMirCol, METH_NOARGS,
+ "() - Return Material's mirror color"},
+ {"getAmb", ( PyCFunction ) Material_getAmb, METH_NOARGS,
+ "() - Return Material's ambient color blend factor"},
+ {"getEmit", ( PyCFunction ) Material_getEmit, METH_NOARGS,
+ "() - Return Material's emitting light intensity"},
+ {"getAlpha", ( PyCFunction ) Material_getAlpha, METH_NOARGS,
+ "() - Return Material's alpha (transparency) value"},
+ {"getRef", ( PyCFunction ) Material_getRef, METH_NOARGS,
+ "() - Return Material's reflectivity"},
+ {"getSpec", ( PyCFunction ) Material_getSpec, METH_NOARGS,
+ "() - Return Material's specularity"},
+ /* Shader specific settings */
+ {"getSpecShader", ( PyCFunction ) Material_getSpecShader, METH_NOARGS,
+ "() - Returns Material's specular shader" },
+ {"getDiffuseShader", ( PyCFunction ) Material_getDiffuseShader, METH_NOARGS,
+ "() - Returns Material's diffuse shader" },
+ {"getRoughness", ( PyCFunction ) Material_getRoughness, METH_NOARGS,
+ "() - Returns Material's Roughness (applies to the \"Oren Nayar\" Diffuse Shader only)" },
+ {"getSpecSize", ( PyCFunction ) Material_getSpecSize, METH_NOARGS,
+ "() - Returns Material's size of specular area (applies to the \"Toon\" Specular Shader only)" },
+ {"getDiffuseSize", ( PyCFunction ) Material_getDiffuseSize, METH_NOARGS,
+ "() - Returns Material's size of diffuse area (applies to the \"Toon\" Diffuse Shader only)" },
+ {"getSpecSmooth", ( PyCFunction ) Material_getSpecSmooth, METH_NOARGS,
+ "() - Returns Material's smoothing of specular area (applies to the \"Toon\" Diffuse Shader only)" },
+ {"getDiffuseSmooth", ( PyCFunction ) Material_getDiffuseSmooth, METH_NOARGS,
+ "() - Returns Material's smoothing of diffuse area (applies to the \"Toon\" Diffuse Shader only)" },
+ {"getDiffuseDarkness", ( PyCFunction ) Material_getDiffuseDarkness, METH_NOARGS,
+ "() - Returns Material's diffuse darkness (applies to the \"Minnaert\" Diffuse Shader only)" },
+ {"getRefracIndex", ( PyCFunction ) Material_getRefracIndex, METH_NOARGS,
+ "() - Returns Material's Index of Refraction (applies to the \"Blinn\" Specular Shader only)" },
+ {"getRms", ( PyCFunction ) Material_getRms, METH_NOARGS,
+ "() - Returns Material's standard deviation of surface slope (applies to the \"WardIso\" Specular Shader only)" },
+ /* End shader settings */
+ {"getSpecTransp", ( PyCFunction ) Material_getSpecTransp, METH_NOARGS,
+ "() - Return Material's specular transparency"},
+ {"getAdd", ( PyCFunction ) Material_getAdd, METH_NOARGS,
+ "() - Return Material's glow factor"},
+ {"getZOffset", ( PyCFunction ) Material_getZOffset, METH_NOARGS,
+ "() - Return Material's artificial offset for faces"},
+ {"getHaloSize", ( PyCFunction ) Material_getHaloSize, METH_NOARGS,
+ "() - Return Material's halo size"},
+ {"getHaloSeed", ( PyCFunction ) Material_getHaloSeed, METH_NOARGS,
+ "() - Return Material's seed for random ring dimension and line "
+ "location in halos"},
+ {"getFlareSize", ( PyCFunction ) Material_getFlareSize, METH_NOARGS,
+ "() - Return Material's (flare size)/(halo size) factor"},
+ {"getFlareSeed", ( PyCFunction ) Material_getFlareSeed, METH_NOARGS,
+ "() - Return Material's flare offset in the seed table"},
+ {"getFlareBoost", ( PyCFunction ) Material_getFlareBoost, METH_NOARGS,
+ "() - Return Material's flare boost"},
+ {"getSubSize", ( PyCFunction ) Material_getSubSize, METH_NOARGS,
+ "() - Return Material's dimension of subflare, dots and circles"},
+ {"getHardness", ( PyCFunction ) Material_getHardness, METH_NOARGS,
+ "() - Return Material's specular hardness"},
+ {"getNFlares", ( PyCFunction ) Material_getNFlares, METH_NOARGS,
+ "() - Return Material's number of flares in halo"},
+ {"getNStars", ( PyCFunction ) Material_getNStars, METH_NOARGS,
+ "() - Return Material's number of points in the halo stars"},
+ {"getNLines", ( PyCFunction ) Material_getNLines, METH_NOARGS,
+ "() - Return Material's number of lines in halo"},
+ {"getNRings", ( PyCFunction ) Material_getNRings, METH_NOARGS,
+ "() - Return Material's number of rings in halo"},
+ {"getRayMirr", ( PyCFunction ) Material_getRayMirr, METH_NOARGS,
+ "() - Return mount mirror"},
+ {"getMirrDepth", ( PyCFunction ) Material_getMirrDepth, METH_NOARGS,
+ "() - Return amount mirror depth"},
+ {"getFresnelMirr", ( PyCFunction ) Material_getFresnelMirr, METH_NOARGS,
+ "() - Return fresnel power for refractions"},
+ {"getFresnelMirrFac", ( PyCFunction ) Material_getFresnelMirrFac, METH_NOARGS,
+ "() - Return fresnel power for refractions factor"},
+ {"getFilter", ( PyCFunction ) Material_getFilter, METH_NOARGS,
+ "() - Return the amount of filtering when transparent raytrace is enabled"},
+ {"getTranslucency", ( PyCFunction ) Material_getTranslucency, METH_NOARGS,
+ "() - Return the Translucency, the amount of diffuse shading of the back side"},
+ {"getIOR", ( PyCFunction ) Material_getIOR, METH_NOARGS,
+ "() - Return IOR"},
+ {"getTransDepth", ( PyCFunction ) Material_getTransDepth, METH_NOARGS,
+ "() - Return amount inter-refractions"},
+ {"getFresnelTrans", ( PyCFunction ) Material_getFresnelTrans, METH_NOARGS,
+ "() - Return fresnel power for refractions"},
+ {"getFresnelTransFac", ( PyCFunction ) Material_getFresnelTransFac, METH_NOARGS,
+ "() - Return fresnel power for refractions factor"},
+
+ {"getTextures", ( PyCFunction ) Material_getTextures, METH_NOARGS,
+ "() - Return Material's texture list as a tuple"},
+ {"setName", ( PyCFunction ) GenericLib_setName_with_method, METH_VARARGS,
+ "(s) - Change Material's name"},
+ {"setIpo", ( PyCFunction ) Matr_oldsetIpo, METH_VARARGS,
+ "(Blender Ipo) - Change Material's Ipo"},
+ {"clearIpo", ( PyCFunction ) Material_clearIpo, METH_NOARGS,
+ "(Blender Ipo) - Unlink Ipo from this Material"},
+ {"insertIpoKey", ( PyCFunction ) Material_insertIpoKey, METH_VARARGS,
+ "(Material Ipo Constant) - Insert IPO Key at current frame"},
+ {"setMode", ( PyCFunction ) Matr_oldsetMode, METH_VARARGS,
+ "([s[,s]]) - Set Material's mode flag(s)"},
+ {"setRGBCol", ( PyCFunction ) Matr_oldsetRGBCol, METH_VARARGS,
+ "(f,f,f or [f,f,f]) - Set Material's rgb color triplet"},
+/* {"setAmbCol", (PyCFunction)Matr_oldsetAmbCol, METH_VARARGS,
+ "(f,f,f or [f,f,f]) - Set Material's ambient color"},*/
+ {"setSpecCol", ( PyCFunction ) Matr_oldsetSpecCol, METH_VARARGS,
+ "(f,f,f or [f,f,f]) - Set Material's specular color"},
+
+ /* Shader spesific settings */
+ {"setSpecShader", ( PyCFunction ) Matr_oldsetSpecShader, METH_VARARGS,
+ "(i) - Set the Material's specular shader" },
+ {"setDiffuseShader", ( PyCFunction ) Matr_oldsetDiffuseShader, METH_VARARGS,
+ "(i) - Set the Material's diffuse shader" },
+ {"setRoughness", ( PyCFunction ) Matr_oldsetRoughness, METH_VARARGS,
+ "(f) - Set the Material's Roughness (applies to the \"Oren Nayar\" Diffuse Shader only)" },
+ {"setSpecSize", ( PyCFunction ) Matr_oldsetSpecSize, METH_VARARGS,
+ "(f) - Set the Material's size of specular area (applies to the \"Toon\" Specular Shader only)" },
+ {"setDiffuseSize", ( PyCFunction ) Matr_oldsetDiffuseSize, METH_VARARGS,
+ "(f) - Set the Material's size of diffuse area (applies to the \"Toon\" Diffuse Shader only)" },
+ {"setSpecSmooth", ( PyCFunction ) Matr_oldsetSpecSmooth, METH_VARARGS,
+ "(f) - Set the Material's smoothing of specular area (applies to the \"Toon\" Specular Shader only)" },
+ {"setDiffuseSmooth", ( PyCFunction ) Matr_oldsetDiffuseSmooth, METH_VARARGS,
+ "(f) - Set the Material's smoothing of diffuse area (applies to the \"Toon\" Diffuse Shader only)" },
+ {"setDiffuseDarkness", ( PyCFunction ) Matr_oldsetDiffuseDarkness, METH_VARARGS,
+ "(f) - Set the Material's diffuse darkness (applies to the \"Minnaert\" Diffuse Shader only)" },
+ {"setRefracIndex", ( PyCFunction ) Matr_oldsetRefracIndex, METH_VARARGS,
+ "(f) - Set the Material's Index of Refraction (applies to the \"Blinn\" Specular Shader only)" },
+ {"setRms", ( PyCFunction ) Matr_oldsetRms, METH_VARARGS,
+ "(f) - Set the Material's standard deviation of surface slope (applies to the \"WardIso\" Specular Shader only)" },
+ /* End shader settings */
+
+ {"setMirCol", ( PyCFunction ) Matr_oldsetMirCol, METH_VARARGS,
+ "(f,f,f or [f,f,f]) - Set Material's mirror color"},
+ {"setAmb", ( PyCFunction ) Matr_oldsetAmb, METH_VARARGS,
+ "(f) - Set how much the Material's color is affected"
+ " by \nthe global ambient colors - [0.0, 1.0]"},
+ {"setEmit", ( PyCFunction ) Matr_oldsetEmit, METH_VARARGS,
+ "(f) - Set Material's emitting light intensity - [0.0, 1.0]"},
+ {"setAlpha", ( PyCFunction ) Matr_oldsetAlpha, METH_VARARGS,
+ "(f) - Set Material's alpha (transparency) - [0.0, 1.0]"},
+ {"setRef", ( PyCFunction ) Matr_oldsetRef, METH_VARARGS,
+ "(f) - Set Material's reflectivity - [0.0, 1.0]"},
+ {"setSpec", ( PyCFunction ) Matr_oldsetSpec, METH_VARARGS,
+ "(f) - Set Material's specularity - [0.0, 2.0]"},
+ {"setSpecTransp", ( PyCFunction ) Matr_oldsetSpecTransp, METH_VARARGS,
+ "(f) - Set Material's specular transparency - [0.0, 1.0]"},
+ {"setAdd", ( PyCFunction ) Matr_oldsetAdd, METH_VARARGS,
+ "(f) - Set Material's glow factor - [0.0, 1.0]"},
+ {"setZOffset", ( PyCFunction ) Matr_oldsetZOffset, METH_VARARGS,
+ "(f) - Set Material's artificial offset - [0.0, 10.0]"},
+ {"setHaloSize", ( PyCFunction ) Matr_oldsetHaloSize, METH_VARARGS,
+ "(f) - Set Material's halo size - [0.0, 100.0]"},
+ {"setHaloSeed", ( PyCFunction ) Matr_oldsetHaloSeed, METH_VARARGS,
+ "(i) - Set Material's halo seed - [0, 255]"},
+ {"setFlareSize", ( PyCFunction ) Matr_oldsetFlareSize, METH_VARARGS,
+ "(f) - Set Material's factor: (flare size)/(halo size) - [0.1, 25.0]"},
+ {"setFlareSeed", ( PyCFunction ) Matr_oldsetFlareSeed, METH_VARARGS,
+ "(i) - Set Material's flare seed - [0, 255]"},
+ {"setFlareBoost", ( PyCFunction ) Matr_oldsetFlareBoost, METH_VARARGS,
+ "(f) - Set Material's flare boost - [0.1, 10.0]"},
+ {"setSubSize", ( PyCFunction ) Matr_oldsetSubSize, METH_VARARGS,
+ "(f) - Set Material's dimension of subflare,"
+ " dots and circles - [0.1, 25.0]"},
+ {"setHardness", ( PyCFunction ) Matr_oldsetHardness, METH_VARARGS,
+ "(i) - Set Material's hardness - [1, 255 (127 if halo mode is ON)]"},
+ {"setNFlares", ( PyCFunction ) Matr_oldsetNFlares, METH_VARARGS,
+ "(i) - Set Material's number of flares in halo - [1, 32]"},
+ {"setNStars", ( PyCFunction ) Matr_oldsetNStars, METH_VARARGS,
+ "(i) - Set Material's number of stars in halo - [3, 50]"},
+ {"setNLines", ( PyCFunction ) Matr_oldsetNLines, METH_VARARGS,
+ "(i) - Set Material's number of lines in halo - [0, 250]"},
+ {"setNRings", ( PyCFunction ) Matr_oldsetNRings, METH_VARARGS,
+ "(i) - Set Material's number of rings in halo - [0, 24]"},
+ {"setRayMirr", ( PyCFunction ) Matr_oldsetRayMirr, METH_VARARGS,
+ "(f) - Set amount mirror - [0.0, 1.0]"},
+ {"setMirrDepth", ( PyCFunction ) Matr_oldsetMirrDepth, METH_VARARGS,
+ "(i) - Set amount inter-reflections - [0, 10]"},
+ {"setFresnelMirr", ( PyCFunction ) Matr_oldsetFresnelMirr, METH_VARARGS,
+ "(f) - Set fresnel power for mirror - [0.0, 5.0]"},
+ {"setFresnelMirrFac", ( PyCFunction ) Matr_oldsetFresnelMirrFac, METH_VARARGS,
+ "(f) - Set blend fac for mirror fresnel - [1.0, 5.0]"},
+ {"setFilter", ( PyCFunction ) Matr_oldsetFilter, METH_VARARGS,
+ "(f) - Set the amount of filtering when transparent raytrace is enabled"},
+ {"setTranslucency", ( PyCFunction ) Matr_oldsetTranslucency, METH_VARARGS,
+ "(f) - Set the Translucency, the amount of diffuse shading of the back side"},
+ {"setIOR", ( PyCFunction ) Matr_oldsetIOR, METH_VARARGS,
+ "(f) - Set IOR - [1.0, 3.0]"},
+ {"setTransDepth", ( PyCFunction ) Matr_oldsetTransDepth, METH_VARARGS,
+ "(i) - Set amount inter-refractions - [0, 10]"},
+ {"setFresnelTrans", ( PyCFunction ) Matr_oldsetFresnelTrans, METH_VARARGS,
+ "(f) - Set fresnel power for refractions - [0.0, 5.0]"},
+ {"setFresnelTransFac", ( PyCFunction ) Matr_oldsetFresnelTransFac, METH_VARARGS,
+ "(f) - Set fresnel power for refractions factor- [0.0, 5.0]"},
+ {"setTexture", ( PyCFunction ) Material_setTexture, METH_VARARGS,
+ "(n,tex,texco=0,mapto=0) - Set numbered texture to tex"},
+ {"clearTexture", ( PyCFunction ) Material_clearTexture, METH_O,
+ "(n) - Remove texture from numbered slot"},
+ {"getScriptLinks", ( PyCFunction ) Material_getScriptLinks, METH_O,
+ "(eventname) - Get a list of this material's scriptlinks (Text names) "
+ "of the given type\n"
+ "(eventname) - string: FrameChanged, Redraw or Render."},
+ {"addScriptLink", ( PyCFunction ) Material_addScriptLink, METH_VARARGS,
+ "(text, evt) - Add a new material scriptlink.\n"
+ "(text) - string: an existing Blender Text name;\n"
+ "(evt) string: FrameChanged, Redraw or Render."},
+ {"clearScriptLinks", ( PyCFunction ) Material_clearScriptLinks, METH_VARARGS,
+ "() - Delete all scriptlinks from this material.\n"
+ "([s1<,s2,s3...>]) - Delete specified scriptlinks from this material."},
+ {"__copy__", ( PyCFunction ) Material_copy, METH_NOARGS,
+ "() - Return a copy of the material."},
+ {"copy", ( PyCFunction ) Material_copy, METH_NOARGS,
+ "() - Return a copy of the material."},
+ {NULL, NULL, 0, NULL}
+};
+
+/*****************************************************************************/
+/* Python attributes get/set structure: */
+/*****************************************************************************/
+
+static PyGetSetDef BPy_Material_getseters[] = {
+ GENERIC_LIB_GETSETATTR,
+ {"add",
+ (getter)Material_getAdd, (setter)Material_setAdd,
+ "Strength of the add effect",
+ NULL},
+ {"alpha",
+ (getter)Material_getAlpha, (setter)Material_setAlpha,
+ "Alpha setting ",
+ NULL},
+ {"shadAlpha",
+ (getter)Material_getShadAlpha, (setter)Material_setShadAlpha,
+ "Shadow Alpha setting",
+ NULL},
+ {"amb",
+ (getter)Material_getAmb, (setter)Material_setAmb,
+ "Amount of global ambient color material receives",
+ NULL},
+ {"diffuseDarkness",
+ (getter)Material_getDiffuseDarkness, (setter)Material_setDiffuseDarkness,
+ "Material's diffuse darkness (\"Minnaert\" diffuse shader only)",
+ NULL},
+ {"diffuseShader",
+ (getter)Material_getDiffuseShader, (setter)Material_setDiffuseShader,
+ "Diffuse shader type",
+ NULL},
+ {"diffuseSize",
+ (getter)Material_getDiffuseSize, (setter)Material_setDiffuseSize,
+ "Material's diffuse area size (\"Toon\" diffuse shader only)",
+ NULL},
+ {"diffuseSmooth",
+ (getter)Material_getDiffuseSmooth, (setter)Material_setDiffuseSmooth,
+ "Material's diffuse area smoothing (\"Toon\" diffuse shader only)",
+ NULL},
+ {"emit",
+ (getter)Material_getEmit, (setter)Material_setEmit,
+ "Amount of light the material emits",
+ NULL},
+ {"filter",
+ (getter)Material_getFilter, (setter)Material_setFilter,
+ "Amount of filtering when transparent raytrace is enabled",
+ NULL},
+ {"flareBoost",
+ (getter)Material_getFlareBoost, (setter)Material_setFlareBoost,
+ "Flare's extra strength",
+ NULL},
+ {"flareSeed",
+ (getter)Material_getFlareSeed, (setter)Material_setFlareSeed,
+ "Offset in the flare seed table",
+ NULL},
+ {"flareSize",
+ (getter)Material_getFlareSize, (setter)Material_setFlareSize,
+ "Ratio of flare size to halo size",
+ NULL},
+ {"fresnelDepth",
+ (getter)Material_getFresnelMirr, (setter)Material_setFresnelMirr,
+ "Power of Fresnel for mirror reflection",
+ NULL},
+ {"fresnelDepthFac",
+ (getter)Material_getFresnelMirrFac, (setter)Material_setFresnelMirrFac,
+ "Blending factor for Fresnel mirror",
+ NULL},
+ {"fresnelTrans",
+ (getter)Material_getFresnelTrans, (setter)Material_setFresnelTrans,
+ "Power of Fresnel for transparency",
+ NULL},
+ {"fresnelTransFac",
+ (getter)Material_getFresnelTransFac, (setter)Material_setFresnelTransFac,
+ "Blending factor for Fresnel transparency",
+ NULL},
+ {"rbFriction",
+ (getter)Material_getRigidBodyFriction, (setter)Material_setRigidBodyFriction,
+ "Rigid Body Friction coefficient",
+ NULL},
+ {"rbRestitution",
+ (getter)Material_getRigidBodyRestitution, (setter)Material_setRigidBodyRestitution,
+ "Rigid Body Restitution coefficient",
+ NULL},
+
+ {"haloSeed",
+ (getter)Material_getHaloSeed, (setter)Material_setHaloSeed,
+ "Randomizes halo ring dimension and line location",
+ NULL},
+ {"haloSize",
+ (getter)Material_getHaloSize, (setter)Material_setHaloSize,
+ "Dimension of the halo",
+ NULL},
+ {"hard",
+ (getter)Material_getHardness, (setter)Material_setHardness,
+ "Specularity hardness",
+ NULL},
+ {"IOR",
+ (getter)Material_getIOR, (setter)Material_setIOR,
+ "Angular index of refraction for raytrace",
+ NULL},
+ {"ipo",
+ (getter)Material_getIpo, (setter)Material_setIpo,
+ "Material Ipo data",
+ NULL},
+ {"mirCol",
+ (getter)Material_getMirCol, (setter)Material_setMirCol,
+ "Mirror RGB color triplet",
+ NULL},
+ {"mirR",
+ (getter)Material_getColorComponent, (setter)Material_setColorComponent,
+ "Mirror color red component",
+ (void *) EXPP_MAT_COMP_MIRR },
+ {"mirG",
+ (getter)Material_getColorComponent, (setter)Material_setColorComponent,
+ "Mirror color green component",
+ (void *) EXPP_MAT_COMP_MIRG },
+ {"mirB",
+ (getter)Material_getColorComponent, (setter)Material_setColorComponent,
+ "Mirror color blue component",
+ (void *) EXPP_MAT_COMP_MIRB },
+ {"sssCol",
+ (getter)Material_getSssCol, (setter)Material_setSssCol,
+ "Sss RGB color triplet",
+ NULL},
+ {"sssR",
+ (getter)Material_getColorComponent, (setter)Material_setColorComponent,
+ "SSS color red component",
+ (void *) EXPP_MAT_COMP_SSSR },
+ {"sssG",
+ (getter)Material_getColorComponent, (setter)Material_setColorComponent,
+ "SSS color green component",
+ (void *) EXPP_MAT_COMP_SSSG },
+ {"sssB",
+ (getter)Material_getColorComponent, (setter)Material_setColorComponent,
+ "SSS color blue component",
+ (void *) EXPP_MAT_COMP_SSSB },
+ {"mode",
+ (getter)Material_getMode, (setter)Material_setMode,
+ "Material mode bitmask",
+ NULL},
+ {"nFlares",
+ (getter)Material_getNFlares, (setter)Material_setNFlares,
+ "Number of subflares with halo",
+ NULL},
+ {"nLines",
+ (getter)Material_getNLines, (setter)Material_setNLines,
+ "Number of star-shaped lines with halo",
+ NULL},
+ {"nRings",
+ (getter)Material_getNRings, (setter)Material_setNRings,
+ "Number of rings with halo",
+ NULL},
+ {"nStars",
+ (getter)Material_getNStars, (setter)Material_setNStars,
+ "Number of star points with halo",
+ NULL},
+ {"rayMirr",
+ (getter)Material_getRayMirr, (setter)Material_setRayMirr,
+ "Mirror reflection amount for raytrace",
+ NULL},
+ {"rayMirrDepth",
+ (getter)Material_getMirrDepth, (setter)Material_setMirrDepth,
+ "Amount of raytrace inter-reflections",
+ NULL},
+ {"ref",
+ (getter)Material_getRef, (setter)Material_setRef,
+ "Amount of reflections (for shader)",
+ NULL},
+ {"refracIndex",
+ (getter)Material_getRefracIndex, (setter)Material_setRefracIndex,
+ "Material's Index of Refraction (applies to the \"Blinn\" Specular Shader only",
+ NULL},
+ {"rgbCol",
+ (getter)Material_getRGBCol, (setter)Material_setRGBCol,
+ "Diffuse RGB color triplet",
+ NULL},
+ {"rms",
+ (getter)Material_getRms, (setter)Material_setRms,
+ "Material's surface slope standard deviation (\"WardIso\" specular shader only)",
+ NULL},
+ {"roughness",
+ (getter)Material_getRoughness, (setter)Material_setRoughness,
+ "Material's roughness (\"Oren Nayar\" diffuse shader only)",
+ NULL},
+ {"spec",
+ (getter)Material_getSpec, (setter)Material_setSpec,
+ "Degree of specularity",
+ NULL},
+ {"specCol",
+ (getter)Material_getSpecCol, (setter)Material_setSpecCol,
+ "Specular RGB color triplet",
+ NULL},
+ {"specR",
+ (getter)Material_getColorComponent, (setter)Material_setColorComponent,
+ "Specular color red component",
+ (void *) EXPP_MAT_COMP_SPECR },
+ {"specG",
+ (getter)Material_getColorComponent, (setter)Material_setColorComponent,
+ "Specular color green component",
+ (void *) EXPP_MAT_COMP_SPECG },
+ {"specB",
+ (getter)Material_getColorComponent, (setter)Material_setColorComponent,
+ "Specular color blue component",
+ (void *) EXPP_MAT_COMP_SPECB },
+ {"specTransp",
+ (getter)Material_getSpecTransp, (setter)Material_setSpecTransp,
+ "Makes specular areas opaque on transparent materials",
+ NULL},
+ {"specShader",
+ (getter)Material_getSpecShader, (setter)Material_setSpecShader,
+ "Specular shader type",
+ NULL},
+ {"specSize",
+ (getter)Material_getSpecSize, (setter)Material_setSpecSize,
+ "Material's specular area size (\"Toon\" specular shader only)",
+ NULL},
+ {"specSmooth",
+ (getter)Material_getSpecSmooth, (setter)Material_setSpecSmooth,
+ "Sets the smoothness of specular toon area",
+ NULL},
+ {"subSize",
+ (getter)Material_getSubSize, (setter)Material_setSubSize,
+ "Dimension of subflares, dots and circles",
+ NULL},
+ {"transDepth",
+ (getter)Material_getTransDepth, (setter)Material_setTransDepth,
+ "Amount of refractions for raytrace",
+ NULL},
+ {"translucency",
+ (getter)Material_getTranslucency, (setter)Material_setTranslucency,
+ "Amount of diffuse shading of the back side",
+ NULL},
+ {"zOffset",
+ (getter)Material_getZOffset, (setter)Material_setZOffset,
+ "Artificial offset in the Z buffer (for Ztransp option)",
+ NULL},
+ {"lightGroup",
+ (getter)Material_getLightGroup, (setter)Material_setLightGroup,
+ "Set the light group for this material",
+ NULL},
+ {"R",
+ (getter)Material_getColorComponent, (setter)Material_setColorComponent,
+ "Diffuse color red component",
+ (void *) EXPP_MAT_COMP_R },
+ {"G",
+ (getter)Material_getColorComponent, (setter)Material_setColorComponent,
+ "Diffuse color green component",
+ (void *) EXPP_MAT_COMP_G },
+ {"B",
+ (getter)Material_getColorComponent, (setter)Material_setColorComponent,
+ "Diffuse color blue component",
+ (void *) EXPP_MAT_COMP_B },
+ {"colorbandDiffuse",
+ (getter)Material_getColorband, (setter)Material_setColorband,
+ "The diffuse colorband for this material",
+ (void *) 0},
+ {"colorbandSpecular",
+ (getter)Material_getColorband, (setter)Material_setColorband,
+ "The specular colorband for this material",
+ (void *) 1},
+
+ /* SSS settings */
+ {"enableSSS",
+ (getter)Material_getSssEnable, (setter)Material_setSssEnable,
+ "if true, SSS will be rendered for this material",
+ NULL},
+ {"sssScale",
+ (getter)Material_getSssScale, (setter)Material_setSssScale,
+ "object scale for sss",
+ NULL},
+ {"sssRadiusRed",
+ (getter)Material_getSssRadius, (setter)Material_setSssRadius,
+ "Mean red scattering path length",
+ (void *) 0},
+ {"sssRadiusGreen",
+ (getter)Material_getSssRadius, (setter)Material_setSssRadius,
+ "Mean red scattering path length",
+ (void *) 1},
+ {"sssRadiusBlue",
+ (getter)Material_getSssRadius, (setter)Material_setSssRadius,
+ "Mean red scattering path length",
+ (void *) 0},
+ {"sssIOR",
+ (getter)Material_getSssIOR, (setter)Material_setSssIOR,
+ "index of refraction",
+ NULL},
+ {"sssError",
+ (getter)Material_getSssError, (setter)Material_setSssError,
+ "Error",
+ NULL},
+ {"sssColorBlend",
+ (getter)Material_getSssColorBlend, (setter)Material_setSssColorBlend,
+ "Blend factor for SSS Colors",
+ NULL},
+ {"sssTextureScatter",
+ (getter)Material_getSssTexScatter, (setter)Material_setSssTexScatter,
+ "Texture scattering factor",
+ NULL},
+ {"sssFont",
+ (getter)Material_getSssFront, (setter)Material_setSssFront,
+ "Front scattering weight",
+ NULL},
+ {"sssBack",
+ (getter)Material_getSssBack, (setter)Material_setSssBack,
+ "Back scattering weight",
+ NULL},
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+/*****************************************************************************/
+/* Python Material_Type callback function prototypes: */
+/*****************************************************************************/
+static void Material_dealloc( BPy_Material * self );
+static int Material_compare( BPy_Material * a, BPy_Material * b);
+static PyObject *Material_repr( BPy_Material * self );
+
+/*****************************************************************************/
+/* Python Material_Type structure definition: */
+/*****************************************************************************/
+PyTypeObject Material_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender Material", /* char *tp_name; */
+ sizeof( BPy_Material ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ ( destructor ) Material_dealloc,/* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ ( cmpfunc ) Material_compare,/* cmpfunc tp_compare; */
+ ( reprfunc ) Material_repr, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ ( hashfunc ) GenericLib_hash, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_Material_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ BPy_Material_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+/*****************************************************************************/
+/* Function: Material_dealloc */
+/* Description: This is a callback function for the BPy_Material type. It is */
+/* the destructor function. */
+/*****************************************************************************/
+static void Material_dealloc( BPy_Material * self )
+{
+ Py_DECREF( self->col );
+ Py_DECREF( self->amb );
+ Py_DECREF( self->spec );
+ Py_DECREF( self->mir );
+ Py_DECREF( self->sss );
+ PyObject_DEL( self );
+}
+
+/*****************************************************************************/
+/* Function: Material_CreatePyObject */
+/* Description: Create a new BPy_Material from an existing */
+/* Blender material structure. */
+/*****************************************************************************/
+PyObject *Material_CreatePyObject( struct Material *mat )
+{
+ BPy_Material *pymat;
+ float *col[3], *amb[3], *spec[3], *mir[3], *sss[3];
+
+ pymat = ( BPy_Material * ) PyObject_NEW( BPy_Material,
+ &Material_Type );
+
+ if( !pymat )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create BPy_Material object" );
+
+ pymat->material = mat;
+
+ col[0] = &mat->r;
+ col[1] = &mat->g;
+ col[2] = &mat->b;
+
+ amb[0] = &mat->ambr;
+ amb[1] = &mat->ambg;
+ amb[2] = &mat->ambb;
+
+ spec[0] = &mat->specr;
+ spec[1] = &mat->specg;
+ spec[2] = &mat->specb;
+
+ mir[0] = &mat->mirr;
+ mir[1] = &mat->mirg;
+ mir[2] = &mat->mirb;
+
+ sss[0] = &mat->sss_col[0];
+ sss[1] = &mat->sss_col[1];
+ sss[2] = &mat->sss_col[2];
+
+ pymat->col = ( BPy_rgbTuple * ) rgbTuple_New( col );
+ pymat->amb = ( BPy_rgbTuple * ) rgbTuple_New( amb );
+ pymat->spec = ( BPy_rgbTuple * ) rgbTuple_New( spec );
+ pymat->mir = ( BPy_rgbTuple * ) rgbTuple_New( mir );
+ pymat->sss = ( BPy_rgbTuple * ) rgbTuple_New( sss );
+
+ return ( PyObject * ) pymat;
+}
+
+/*****************************************************************************/
+/* Function: Material_FromPyObject */
+/* Description: This function returns the Blender material from the given */
+/* PyObject. */
+/*****************************************************************************/
+Material *Material_FromPyObject( PyObject * pyobj )
+{
+ return ( ( BPy_Material * ) pyobj )->material;
+}
+
+static PyObject *Material_getIpo( BPy_Material * self )
+{
+ Ipo *ipo = self->material->ipo;
+
+ if( !ipo )
+ Py_RETURN_NONE;
+
+ return Ipo_CreatePyObject( ipo );
+}
+
+static PyObject *Material_getMode( BPy_Material * self )
+{
+ return PyInt_FromLong( ( long ) self->material->mode );
+}
+
+static PyObject *Material_getRGBCol( BPy_Material * self )
+{
+ return rgbTuple_getCol( self->col );
+}
+
+/*
+static PyObject *Material_getAmbCol(BPy_Material *self)
+{
+ return rgbTuple_getCol(self->amb);
+}
+*/
+static PyObject *Material_getSpecCol( BPy_Material * self )
+{
+ return rgbTuple_getCol( self->spec );
+}
+
+static PyObject *Material_getMirCol( BPy_Material * self )
+{
+ return rgbTuple_getCol( self->mir );
+}
+
+static PyObject *Material_getSssCol( BPy_Material * self )
+{
+ return rgbTuple_getCol( self->sss );
+}
+
+static PyObject *Material_getSpecShader( BPy_Material * self )
+{
+ return PyInt_FromLong( ( long ) self->material->spec_shader );
+}
+
+static PyObject *Material_getDiffuseShader( BPy_Material * self )
+{
+ return PyInt_FromLong( ( long ) self->material->diff_shader );
+}
+
+static PyObject *Material_getRoughness( BPy_Material * self )
+{
+ return PyFloat_FromDouble( ( double ) self->material->roughness );
+}
+
+static PyObject *Material_getSpecSize( BPy_Material * self )
+{
+ return PyFloat_FromDouble( ( double ) self->material->param[2] );
+}
+
+static PyObject *Material_getDiffuseSize( BPy_Material * self )
+{
+ return PyFloat_FromDouble( ( double ) self->material->param[0] );
+}
+
+static PyObject *Material_getSpecSmooth( BPy_Material * self )
+{
+ return PyFloat_FromDouble( ( double ) self->material->param[3] );
+}
+
+static PyObject *Material_getDiffuseSmooth( BPy_Material * self )
+{
+ return PyFloat_FromDouble( ( double ) self->material->param[1] );
+}
+
+static PyObject *Material_getDiffuseDarkness( BPy_Material * self )
+{
+ return PyFloat_FromDouble( ( double ) self->material->darkness );
+}
+
+static PyObject *Material_getRefracIndex( BPy_Material * self )
+{
+ return PyFloat_FromDouble( ( double ) self->material->refrac );
+}
+
+static PyObject *Material_getRms( BPy_Material * self )
+{
+ return PyFloat_FromDouble( ( double ) self->material->rms );
+}
+
+static PyObject *Material_getAmb( BPy_Material * self )
+{
+ return PyFloat_FromDouble( ( double ) self->material->amb );
+}
+
+static PyObject *Material_getEmit( BPy_Material * self )
+{
+ return PyFloat_FromDouble( ( double ) self->material->emit );
+}
+
+static PyObject *Material_getAlpha( BPy_Material * self )
+{
+ return PyFloat_FromDouble( ( double ) self->material->alpha );
+}
+
+static PyObject *Material_getShadAlpha( BPy_Material * self )
+{
+ return PyFloat_FromDouble( ( double ) self->material->shad_alpha );
+}
+
+static PyObject *Material_getRef( BPy_Material * self )
+{
+ return PyFloat_FromDouble( ( double ) self->material->ref );
+}
+
+static PyObject *Material_getSpec( BPy_Material * self )
+{
+ return PyFloat_FromDouble( ( double ) self->material->spec );
+}
+
+static PyObject *Material_getSpecTransp( BPy_Material * self )
+{
+ return PyFloat_FromDouble( ( double ) self->material->spectra );
+}
+
+static PyObject *Material_getAdd( BPy_Material * self )
+{
+ return PyFloat_FromDouble( ( double ) self->material->add );
+}
+
+static PyObject *Material_getZOffset( BPy_Material * self )
+{
+ return PyFloat_FromDouble( ( double ) self->material->zoffs );
+}
+
+static PyObject *Material_getLightGroup( BPy_Material * self )
+{
+ return Group_CreatePyObject( self->material->group );
+}
+
+static PyObject *Material_getHaloSize( BPy_Material * self )
+{
+ return PyFloat_FromDouble( ( double ) self->material->hasize );
+}
+
+static PyObject *Material_getFlareSize( BPy_Material * self )
+{
+ return PyFloat_FromDouble( ( double ) self->material->flaresize );
+}
+
+static PyObject *Material_getFlareBoost( BPy_Material * self )
+{
+ return PyFloat_FromDouble( ( double ) self->material->flareboost );
+}
+
+static PyObject *Material_getSubSize( BPy_Material * self )
+{
+ return PyFloat_FromDouble( ( double ) self->material->subsize );
+}
+
+static PyObject *Material_getHaloSeed( BPy_Material * self )
+{
+ return PyInt_FromLong( ( long ) self->material->seed1 );
+}
+
+static PyObject *Material_getFlareSeed( BPy_Material * self )
+{
+ return PyInt_FromLong( ( long ) self->material->seed2 );
+}
+
+static PyObject *Material_getHardness( BPy_Material * self )
+{
+ return PyInt_FromLong( ( long ) self->material->har );
+}
+
+static PyObject *Material_getNFlares( BPy_Material * self )
+{
+ return PyInt_FromLong( ( long ) self->material->flarec );
+}
+
+static PyObject *Material_getNStars( BPy_Material * self )
+{
+ return PyInt_FromLong( ( long ) self->material->starc );
+}
+
+static PyObject *Material_getNLines( BPy_Material * self )
+{
+ return PyInt_FromLong( ( long ) self->material->linec );
+}
+
+static PyObject *Material_getNRings( BPy_Material * self )
+{
+ return PyInt_FromLong( ( long ) self->material->ringc );
+}
+
+static PyObject *Material_getRayMirr( BPy_Material * self )
+{
+ return PyFloat_FromDouble( ( double ) self->material->ray_mirror );
+}
+
+static PyObject *Material_getMirrDepth( BPy_Material * self )
+{
+ return PyInt_FromLong( ( long ) self->material->ray_depth );
+}
+
+static PyObject *Material_getFresnelMirr( BPy_Material * self )
+{
+ return PyFloat_FromDouble( ( double ) self->material->fresnel_mir );
+}
+
+static PyObject *Material_getFresnelMirrFac( BPy_Material * self )
+{
+ return PyFloat_FromDouble( ( double ) self->material->fresnel_mir_i );
+}
+
+static PyObject *Material_getFilter( BPy_Material * self )
+{
+ return PyFloat_FromDouble( ( double ) self->material->filter );
+}
+
+static PyObject *Material_getTranslucency( BPy_Material * self )
+{
+ return PyFloat_FromDouble( ( double ) self->material->translucency );
+}
+
+static PyObject *Material_getIOR( BPy_Material * self )
+{
+ return PyFloat_FromDouble( ( double ) self->material->ang );
+}
+
+static PyObject *Material_getTransDepth( BPy_Material * self )
+{
+ return PyInt_FromLong( ( long ) self->material->ray_depth_tra );
+}
+
+static PyObject *Material_getFresnelTrans( BPy_Material * self )
+{
+ return PyFloat_FromDouble( ( double ) self->material->fresnel_tra );
+}
+
+static PyObject *Material_getFresnelTransFac( BPy_Material * self )
+{
+ return PyFloat_FromDouble( ( double ) self->material->fresnel_tra_i );
+}
+
+static PyObject* Material_getRigidBodyFriction( BPy_Material * self )
+{
+ return PyFloat_FromDouble( ( double ) self->material->friction );
+}
+
+static PyObject* Material_getRigidBodyRestitution( BPy_Material * self )
+{
+ return PyFloat_FromDouble( ( double ) self->material->reflect );
+}
+
+/* SSS */
+static PyObject* Material_getSssEnable( BPy_Material * self )
+{
+ return EXPP_getBitfield( &self->material->sss_flag, MA_DIFF_SSS, 'h' );
+}
+
+static PyObject* Material_getSssScale( BPy_Material * self )
+{
+ return PyFloat_FromDouble( ( double ) self->material->sss_scale );
+}
+
+static PyObject* Material_getSssRadius( BPy_Material * self, void * type )
+{
+ return PyFloat_FromDouble( ( double ) (self->material->sss_radius[(int)type]) );
+}
+
+static PyObject* Material_getSssIOR( BPy_Material * self )
+{
+ return PyFloat_FromDouble( ( double ) self->material->sss_ior);
+}
+
+static PyObject* Material_getSssError( BPy_Material * self )
+{
+ return PyFloat_FromDouble( ( double ) self->material->sss_error);
+}
+
+static PyObject* Material_getSssColorBlend( BPy_Material * self )
+{
+ return PyFloat_FromDouble( ( double ) self->material->sss_colfac);
+}
+
+static PyObject* Material_getSssTexScatter( BPy_Material * self )
+{
+ return PyFloat_FromDouble( ( double ) self->material->sss_texfac);
+}
+
+static PyObject* Material_getSssFront( BPy_Material * self )
+{
+ return PyFloat_FromDouble( ( double ) self->material->sss_front);
+}
+
+static PyObject* Material_getSssBack( BPy_Material * self )
+{
+ return PyFloat_FromDouble( ( double ) self->material->sss_back);
+}
+
+static PyObject *Material_getTextures( BPy_Material * self )
+{
+ int i;
+ struct MTex *mtex;
+ PyObject *t[MAX_MTEX];
+ PyObject *tuple;
+
+ /* build a texture list */
+ for( i = 0; i < MAX_MTEX; ++i ) {
+ mtex = self->material->mtex[i];
+
+ if( mtex ) {
+ t[i] = MTex_CreatePyObject( mtex );
+ } else {
+ Py_INCREF( Py_None );
+ t[i] = Py_None;
+ }
+ }
+
+ /* turn the array into a tuple */
+ tuple = Py_BuildValue( "NNNNNNNNNN", t[0], t[1], t[2], t[3],
+ t[4], t[5], t[6], t[7], t[8], t[9] );
+ if( !tuple )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "Material_getTextures: couldn't create PyTuple" );
+
+ return tuple;
+}
+
+/*
+ * this should accept a Py_None argument and just delete the Ipo link
+ * (as Lamp_clearIpo() does)
+ */
+
+static int Material_setIpo( BPy_Material * self, PyObject * value )
+{
+ return GenericLib_assignData(value, (void **) &self->material->ipo, 0, 1, ID_IP, ID_MA);
+}
+
+
+/*
+ * Material_insertIpoKey( key )
+ * inserts Material IPO key at current frame
+ */
+
+static PyObject *Material_insertIpoKey( BPy_Material * self, PyObject * args )
+{
+ int key = 0, map;
+
+ if( !PyArg_ParseTuple( args, "i", &( key ) ) )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected int argument" ) );
+
+ map = texchannel_to_adrcode(self->material->texact);
+
+ if(key==IPOKEY_RGB || key==IPOKEY_ALLCOLOR) {
+ insertkey((ID *)self->material, ID_MA, NULL, NULL, MA_COL_R, 0);
+ insertkey((ID *)self->material, ID_MA, NULL, NULL, MA_COL_G, 0);
+ insertkey((ID *)self->material, ID_MA, NULL, NULL, MA_COL_B, 0);
+ }
+ if(key==IPOKEY_ALPHA || key==IPOKEY_ALLCOLOR) {
+ insertkey((ID *)self->material, ID_MA, NULL, NULL, MA_ALPHA, 0);
+ }
+ if(key==IPOKEY_HALOSIZE || key==IPOKEY_ALLCOLOR) {
+ insertkey((ID *)self->material, ID_MA, NULL, NULL, MA_HASIZE, 0);
+ }
+ if(key==IPOKEY_MODE || key==IPOKEY_ALLCOLOR) {
+ insertkey((ID *)self->material, ID_MA, NULL, NULL, MA_MODE, 0);
+ }
+ if(key==IPOKEY_ALLCOLOR) {
+ insertkey((ID *)self->material, ID_MA, NULL, NULL, MA_SPEC_R, 0);
+ insertkey((ID *)self->material, ID_MA, NULL, NULL, MA_SPEC_G, 0);
+ insertkey((ID *)self->material, ID_MA, NULL, NULL, MA_SPEC_B, 0);
+ insertkey((ID *)self->material, ID_MA, NULL, NULL, MA_REF, 0);
+ insertkey((ID *)self->material, ID_MA, NULL, NULL, MA_EMIT, 0);
+ insertkey((ID *)self->material, ID_MA, NULL, NULL, MA_AMB, 0);
+ insertkey((ID *)self->material, ID_MA, NULL, NULL, MA_SPEC, 0);
+ insertkey((ID *)self->material, ID_MA, NULL, NULL, MA_HARD, 0);
+ insertkey((ID *)self->material, ID_MA, NULL, NULL, MA_MODE, 0);
+ insertkey((ID *)self->material, ID_MA, NULL, NULL, MA_TRANSLU, 0);
+ insertkey((ID *)self->material, ID_MA, NULL, NULL, MA_ADD, 0);
+ }
+ if(key==IPOKEY_ALLMIRROR) {
+ insertkey((ID *)self->material, ID_MA, NULL, NULL, MA_RAYM, 0);
+ insertkey((ID *)self->material, ID_MA, NULL, NULL, MA_FRESMIR, 0);
+ insertkey((ID *)self->material, ID_MA, NULL, NULL, MA_FRESMIRI, 0);
+ insertkey((ID *)self->material, ID_MA, NULL, NULL, MA_FRESTRA, 0);
+ insertkey((ID *)self->material, ID_MA, NULL, NULL, MA_FRESTRAI, 0);
+ }
+ if(key==IPOKEY_OFS || key==IPOKEY_ALLMAPPING) {
+ insertkey((ID *)self->material, ID_MA, NULL, NULL, map+MAP_OFS_X, 0);
+ insertkey((ID *)self->material, ID_MA, NULL, NULL, map+MAP_OFS_Y, 0);
+ insertkey((ID *)self->material, ID_MA, NULL, NULL, map+MAP_OFS_Z, 0);
+ }
+ if(key==IPOKEY_SIZE || key==IPOKEY_ALLMAPPING) {
+ insertkey((ID *)self->material, ID_MA, NULL, NULL, map+MAP_SIZE_X, 0);
+ insertkey((ID *)self->material, ID_MA, NULL, NULL, map+MAP_SIZE_Y, 0);
+ insertkey((ID *)self->material, ID_MA, NULL, NULL, map+MAP_SIZE_Z, 0);
+ }
+ if(key==IPOKEY_ALLMAPPING) {
+ insertkey((ID *)self->material, ID_MA, NULL, NULL, map+MAP_R, 0);
+ insertkey((ID *)self->material, ID_MA, NULL, NULL, map+MAP_G, 0);
+ insertkey((ID *)self->material, ID_MA, NULL, NULL, map+MAP_B, 0);
+ insertkey((ID *)self->material, ID_MA, NULL, NULL, map+MAP_DVAR, 0);
+ insertkey((ID *)self->material, ID_MA, NULL, NULL, map+MAP_COLF, 0);
+ insertkey((ID *)self->material, ID_MA, NULL, NULL, map+MAP_NORF, 0);
+ insertkey((ID *)self->material, ID_MA, NULL, NULL, map+MAP_VARF, 0);
+ insertkey((ID *)self->material, ID_MA, NULL, NULL, map+MAP_DISP, 0);
+ }
+
+ allspace(REMAKEIPO, 0);
+ EXPP_allqueue(REDRAWIPO, 0);
+ EXPP_allqueue(REDRAWVIEW3D, 0);
+ EXPP_allqueue(REDRAWACTION, 0);
+ EXPP_allqueue(REDRAWNLA, 0);
+
+ Py_RETURN_NONE;
+}
+
+static int Material_setMode( BPy_Material * self, PyObject * value )
+{
+ int param;
+
+ if( !PyInt_Check( value ) ) {
+ char errstr[128];
+ sprintf ( errstr , "expected int bitmask of 0x%08x", MA_MODE_MASK );
+ return EXPP_ReturnIntError( PyExc_TypeError, errstr );
+ }
+ param = PyInt_AS_LONG ( value );
+
+ if ( ( param & MA_MODE_MASK ) != param )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "invalid bit(s) set in mask" );
+
+ self->material->mode &= ( MA_RAMP_COL | MA_RAMP_SPEC );
+ self->material->mode |= param & ~( MA_RAMP_COL | MA_RAMP_SPEC );
+
+ return 0;
+}
+
+static int Material_setRGBCol( BPy_Material * self, PyObject * value )
+{
+ return rgbTuple_setCol( self->col, value );
+}
+
+/*
+static PyObject *Material_setAmbCol (BPy_Material *self, PyObject * value )
+{
+ return rgbTuple_setCol(self->amb, value);
+}
+*/
+
+static int Material_setSpecCol( BPy_Material * self, PyObject * value )
+{
+ return rgbTuple_setCol( self->spec, value );
+}
+
+static int Material_setMirCol( BPy_Material * self, PyObject * value )
+{
+ return rgbTuple_setCol( self->mir, value );
+}
+
+static int Material_setSssCol( BPy_Material * self, PyObject * value )
+{
+ return rgbTuple_setCol( self->sss, value );
+}
+
+static int Material_setColorComponent( BPy_Material * self, PyObject * value,
+ void * closure )
+{
+ float param;
+
+ if( !PyNumber_Check ( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected float argument in [0.0,1.0]" );
+
+ param = (float)PyFloat_AsDouble( value );
+ param = EXPP_ClampFloat( param, EXPP_MAT_COL_MIN, EXPP_MAT_COL_MAX );
+
+ switch ( (int)closure ) {
+ case EXPP_MAT_COMP_R:
+ self->material->r = param;
+ return 0;
+ case EXPP_MAT_COMP_G:
+ self->material->g = param;
+ return 0;
+ case EXPP_MAT_COMP_B:
+ self->material->b = param;
+ return 0;
+ case EXPP_MAT_COMP_SPECR:
+ self->material->specr = param;
+ return 0;
+ case EXPP_MAT_COMP_SPECG:
+ self->material->specg = param;
+ return 0;
+ case EXPP_MAT_COMP_SPECB:
+ self->material->specb = param;
+ return 0;
+ case EXPP_MAT_COMP_MIRR:
+ self->material->mirr = param;
+ return 0;
+ case EXPP_MAT_COMP_MIRG:
+ self->material->mirg = param;
+ return 0;
+ case EXPP_MAT_COMP_MIRB:
+ self->material->mirb = param;
+ return 0;
+ case EXPP_MAT_COMP_SSSR:
+ self->material->sss_col[0] = param;
+ return 0;
+ case EXPP_MAT_COMP_SSSG:
+ self->material->sss_col[1] = param;
+ return 0;
+ case EXPP_MAT_COMP_SSSB:
+ self->material->sss_col[2] = param;
+ return 0;
+ }
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "unknown color component specified" );
+}
+
+/*#define setFloatWrapper(val, min, max) {return EXPP_setFloatClamped ( value, &self->material->#val, #min, #max}*/
+
+static int Material_setAmb( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->material->amb,
+ EXPP_MAT_AMB_MIN,
+ EXPP_MAT_AMB_MAX );
+}
+
+static int Material_setEmit( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->material->emit,
+ EXPP_MAT_EMIT_MIN,
+ EXPP_MAT_EMIT_MAX );
+}
+
+static int Material_setSpecTransp( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->material->spectra,
+ EXPP_MAT_SPECTRA_MIN,
+ EXPP_MAT_SPECTRA_MAX );
+}
+
+static int Material_setAlpha( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->material->alpha,
+ EXPP_MAT_ALPHA_MIN,
+ EXPP_MAT_ALPHA_MAX );
+}
+
+static int Material_setShadAlpha( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->material->shad_alpha,
+ EXPP_MAT_ALPHA_MIN,
+ EXPP_MAT_ALPHA_MAX );
+}
+
+static int Material_setRef( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->material->ref,
+ EXPP_MAT_REF_MIN,
+ EXPP_MAT_REF_MAX );
+}
+
+static int Material_setSpec( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->material->spec,
+ EXPP_MAT_SPEC_MIN,
+ EXPP_MAT_SPEC_MAX );
+}
+
+static int Material_setZOffset( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->material->zoffs,
+ EXPP_MAT_ZOFFS_MIN,
+ EXPP_MAT_ZOFFS_MAX );
+}
+
+static int Material_setLightGroup( BPy_Material * self, PyObject * value )
+{
+ return GenericLib_assignData(value, (void **) &self->material->group, NULL, 1, ID_GR, 0);
+}
+
+static int Material_setAdd( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->material->add,
+ EXPP_MAT_ADD_MIN,
+ EXPP_MAT_ADD_MAX );
+}
+
+static int Material_setHaloSize( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->material->hasize,
+ EXPP_MAT_HALOSIZE_MIN,
+ EXPP_MAT_HALOSIZE_MAX );
+}
+
+static int Material_setFlareSize( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->material->flaresize,
+ EXPP_MAT_FLARESIZE_MIN,
+ EXPP_MAT_FLARESIZE_MAX );
+}
+
+static int Material_setFlareBoost( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->material->flareboost,
+ EXPP_MAT_FLAREBOOST_MIN,
+ EXPP_MAT_FLAREBOOST_MAX );
+}
+
+static int Material_setSubSize( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->material->subsize,
+ EXPP_MAT_SUBSIZE_MIN,
+ EXPP_MAT_SUBSIZE_MAX );
+}
+
+static int Material_setHaloSeed( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setIValueClamped ( value, &self->material->seed1,
+ EXPP_MAT_HALOSEED_MIN,
+ EXPP_MAT_HALOSEED_MAX, 'b' );
+}
+
+static int Material_setFlareSeed( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setIValueClamped ( value, &self->material->seed2,
+ EXPP_MAT_FLARESEED_MIN,
+ EXPP_MAT_FLARESEED_MAX, 'b' );
+}
+
+static int Material_setHardness( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setIValueClamped ( value, &self->material->har,
+ EXPP_MAT_HARD_MIN,
+ EXPP_MAT_HARD_MAX, 'h' );
+}
+
+static int Material_setNFlares( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setIValueClamped ( value, &self->material->flarec,
+ EXPP_MAT_NFLARES_MIN,
+ EXPP_MAT_NFLARES_MAX, 'h' );
+}
+
+static int Material_setNStars( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setIValueClamped ( value, &self->material->starc,
+ EXPP_MAT_NSTARS_MIN,
+ EXPP_MAT_NSTARS_MAX, 'h' );
+}
+
+static int Material_setNLines( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setIValueClamped ( value, &self->material->linec,
+ EXPP_MAT_NLINES_MIN,
+ EXPP_MAT_NLINES_MAX, 'h' );
+}
+
+static int Material_setNRings( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setIValueClamped ( value, &self->material->ringc,
+ EXPP_MAT_NRINGS_MIN,
+ EXPP_MAT_NRINGS_MAX, 'h' );
+}
+
+static int Material_setRayMirr( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->material->ray_mirror,
+ EXPP_MAT_RAYMIRR_MIN,
+ EXPP_MAT_RAYMIRR_MAX );
+}
+
+static int Material_setMirrDepth( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setIValueClamped ( value, &self->material->ray_depth,
+ EXPP_MAT_MIRRDEPTH_MIN,
+ EXPP_MAT_MIRRDEPTH_MAX, 'h' );
+}
+
+static int Material_setFresnelMirr( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->material->fresnel_mir,
+ EXPP_MAT_FRESNELMIRR_MIN,
+ EXPP_MAT_FRESNELMIRR_MAX );
+}
+
+static int Material_setFresnelMirrFac( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->material->fresnel_mir_i,
+ EXPP_MAT_FRESNELMIRRFAC_MIN,
+ EXPP_MAT_FRESNELMIRRFAC_MAX );
+}
+
+static int Material_setIOR( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->material->ang,
+ EXPP_MAT_IOR_MIN,
+ EXPP_MAT_IOR_MAX );
+}
+
+static int Material_setTransDepth( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setIValueClamped ( value, &self->material->ray_depth_tra,
+ EXPP_MAT_TRANSDEPTH_MIN,
+ EXPP_MAT_TRANSDEPTH_MAX, 'h' );
+}
+
+static int Material_setFresnelTrans( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->material->fresnel_tra,
+ EXPP_MAT_FRESNELTRANS_MIN,
+ EXPP_MAT_FRESNELTRANS_MAX );
+}
+
+static int Material_setFresnelTransFac( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->material->fresnel_tra_i,
+ EXPP_MAT_FRESNELTRANSFAC_MIN,
+ EXPP_MAT_FRESNELTRANSFAC_MAX );
+}
+
+static int Material_setRigidBodyFriction( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->material->friction,
+ 0.f,
+ 100.f );
+}
+
+static int Material_setRigidBodyRestitution( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->material->reflect,
+ 0.f,
+ 1.f );
+}
+
+
+
+
+static int Material_setSpecShader( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setIValueRange( value, &self->material->spec_shader,
+ MA_SPEC_COOKTORR,
+ MA_SPEC_WARDISO, 'h' );
+}
+
+static int Material_setDiffuseShader( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setIValueRange( value, &self->material->diff_shader,
+ MA_DIFF_LAMBERT,
+ MA_DIFF_MINNAERT, 'h' );
+}
+
+static int Material_setRoughness( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->material->roughness,
+ EXPP_MAT_ROUGHNESS_MIN,
+ EXPP_MAT_ROUGHNESS_MAX );
+}
+
+static int Material_setSpecSize( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->material->param[2],
+ EXPP_MAT_SPECSIZE_MIN,
+ EXPP_MAT_SPECSIZE_MAX );
+}
+
+static int Material_setDiffuseSize( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->material->param[0],
+ EXPP_MAT_DIFFUSESIZE_MIN,
+ EXPP_MAT_DIFFUSESIZE_MAX );
+}
+
+static int Material_setSpecSmooth( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->material->param[3],
+ EXPP_MAT_SPECSMOOTH_MIN,
+ EXPP_MAT_SPECSMOOTH_MAX );
+}
+
+static int Material_setDiffuseSmooth( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->material->param[1],
+ EXPP_MAT_DIFFUSESMOOTH_MIN,
+ EXPP_MAT_DIFFUSESMOOTH_MAX );
+}
+
+static int Material_setDiffuseDarkness( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->material->darkness,
+ EXPP_MAT_DIFFUSE_DARKNESS_MIN,
+ EXPP_MAT_DIFFUSE_DARKNESS_MAX );
+}
+
+static int Material_setRefracIndex( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->material->refrac,
+ EXPP_MAT_REFRACINDEX_MIN,
+ EXPP_MAT_REFRACINDEX_MAX );
+}
+
+static int Material_setRms( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->material->rms,
+ EXPP_MAT_RMS_MIN,
+ EXPP_MAT_RMS_MAX );
+}
+
+static int Material_setFilter( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->material->filter,
+ EXPP_MAT_FILTER_MIN,
+ EXPP_MAT_FILTER_MAX );
+}
+
+static int Material_setTranslucency( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->material->translucency,
+ EXPP_MAT_TRANSLUCENCY_MIN,
+ EXPP_MAT_TRANSLUCENCY_MAX );
+}
+
+/* SSS */
+static int Material_setSssEnable( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setBitfield( value, &self->material->sss_flag, MA_DIFF_SSS, 'h' );
+}
+
+static int Material_setSssScale( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->material->sss_scale,
+ EXPP_MAT_SSS_SCALE_MIN,
+ EXPP_MAT_SSS_SCALE_MAX);
+}
+
+static int Material_setSssRadius( BPy_Material * self, PyObject * value, void *type )
+{
+ return EXPP_setFloatClamped ( value, &self->material->sss_radius[(int)type],
+ EXPP_MAT_SSS_RADIUS_MIN,
+ EXPP_MAT_SSS_RADIUS_MAX);
+}
+
+static int Material_setSssIOR( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->material->sss_ior,
+ EXPP_MAT_SSS_IOR_MIN,
+ EXPP_MAT_SSS_IOR_MAX);
+}
+
+static int Material_setSssError( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->material->sss_error,
+ EXPP_MAT_SSS_IOR_MIN,
+ EXPP_MAT_SSS_IOR_MAX);
+}
+
+static int Material_setSssColorBlend( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->material->sss_colfac,
+ 0.0,
+ 1.0);
+}
+
+static int Material_setSssTexScatter( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->material->sss_texfac,
+ 0.0,
+ 1.0);
+}
+
+static int Material_setSssFront( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->material->sss_front,
+ EXPP_MAT_SSS_FRONT_MIN,
+ EXPP_MAT_SSS_FRONT_MAX);
+}
+
+static int Material_setSssBack( BPy_Material * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->material->sss_back,
+ EXPP_MAT_SSS_BACK_MIN,
+ EXPP_MAT_SSS_BACK_MAX);
+}
+
+
+
+
+static PyObject *Material_setTexture( BPy_Material * self, PyObject * args )
+{
+ int texnum;
+ PyObject *pytex;
+ Tex *bltex;
+ int texco = TEXCO_ORCO, mapto = MAP_COL;
+
+ if( !PyArg_ParseTuple( args, "iO!|ii", &texnum, &Texture_Type, &pytex,
+ &texco, &mapto ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected int in [0,9] and Texture" );
+ if( ( texnum < 0 ) || ( texnum >= MAX_MTEX ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected int in [0,9] and Texture" );
+
+ bltex = Texture_FromPyObject( pytex );
+
+ if( !self->material->mtex[texnum] ) {
+ /* there isn't an mtex for this slot so we need to make one */
+ self->material->mtex[texnum] = add_mtex( );
+ } else {
+ /* we already had a texture here so deal with the old one first */
+ self->material->mtex[texnum]->tex->id.us--;
+ }
+
+ self->material->mtex[texnum]->tex = bltex;
+ id_us_plus( &bltex->id );
+ self->material->mtex[texnum]->texco = (short)texco;
+ self->material->mtex[texnum]->mapto = (short)mapto;
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Material_clearTexture( BPy_Material * self, PyObject * value )
+{
+ int texnum = (int)PyInt_AsLong(value);
+ struct MTex *mtex;
+ /* non ints will be -1 */
+ if( ( texnum < 0 ) || ( texnum >= MAX_MTEX ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected int in [0,9]" );
+
+ mtex = self->material->mtex[texnum];
+ if( mtex ) {
+ if( mtex->tex )
+ mtex->tex->id.us--;
+ MEM_freeN( mtex );
+ self->material->mtex[texnum] = NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+/* mat.addScriptLink */
+static PyObject *Material_addScriptLink( BPy_Material * self, PyObject * args )
+{
+ Material *mat = self->material;
+ ScriptLink *slink = NULL;
+
+ slink = &( mat )->scriptlink;
+
+ return EXPP_addScriptLink( slink, args, 0 );
+}
+
+/* mat.clearScriptLinks */
+static PyObject *Material_clearScriptLinks(BPy_Material *self, PyObject *args )
+{
+ Material *mat = self->material;
+ ScriptLink *slink = NULL;
+
+ slink = &( mat )->scriptlink;
+
+ return EXPP_clearScriptLinks( slink, args );
+}
+
+/* mat.getScriptLinks */
+static PyObject *Material_getScriptLinks( BPy_Material * self,
+ PyObject * value )
+{
+ Material *mat = self->material;
+ ScriptLink *slink = NULL;
+ PyObject *ret = NULL;
+
+ slink = &( mat )->scriptlink;
+
+ /* can't this just return? EXP_getScriptLinks() returns a PyObject*
+ * or NULL anyway */
+
+ ret = EXPP_getScriptLinks( slink, value, 0 );
+
+ if( ret )
+ return ret;
+ else
+ return NULL;
+}
+
+/* mat.__copy__ */
+static PyObject *Material_copy( BPy_Material * self )
+{
+ BPy_Material *pymat; /* for Material Data object wrapper in Python */
+ Material *blmat; /* for actual Material Data we create in Blender */
+
+ blmat = copy_material( self->material ); /* first copy the Material Data in Blender */
+
+ if( blmat ) /* now create the wrapper obj in Python */
+ pymat = ( BPy_Material * ) Material_CreatePyObject( blmat );
+ else
+ return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't create Material Data in Blender" ) );
+
+ blmat->id.us = 0; /* was incref'ed by add_material() above */
+
+ if( pymat == NULL )
+ return ( EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create Material Data object" ) );
+
+ return ( PyObject * ) pymat;
+}
+
+/* mat_a==mat_b or mat_a!=mat_b*/
+static int Material_compare( BPy_Material * a, BPy_Material * b )
+{
+ return ( a->material == b->material) ? 0 : -1;
+}
+
+/*****************************************************************************/
+/* Function: Material_repr */
+/* Description: This is a callback function for the BPy_Material type. It */
+/* builds a meaninful string to represent material objects. */
+/*****************************************************************************/
+static PyObject *Material_repr( BPy_Material * self )
+{
+ return PyString_FromFormat( "[Material \"%s\"]",
+ self->material->id.name + 2 );
+}
+
+/*****************************************************************************/
+/* These functions are used here and in in Texture.c */
+/*****************************************************************************/
+PyObject *EXPP_PyList_fromColorband( ColorBand *coba )
+{
+ short i;
+ PyObject *cbls;
+ PyObject *colls;
+
+ if (!coba)
+ return PyList_New( 0 );
+
+ cbls = PyList_New( coba->tot );
+
+ for (i=0; i < coba->tot; i++) {
+ colls = PyList_New( 5 );
+ PyList_SET_ITEM( colls, 0, PyFloat_FromDouble(coba->data[i].r) );
+ PyList_SET_ITEM( colls, 1, PyFloat_FromDouble(coba->data[i].g) );
+ PyList_SET_ITEM( colls, 2, PyFloat_FromDouble(coba->data[i].b) );
+ PyList_SET_ITEM( colls, 3, PyFloat_FromDouble(coba->data[i].a) );
+ PyList_SET_ITEM( colls, 4, PyFloat_FromDouble(coba->data[i].pos) );
+ PyList_SET_ITEM(cbls, i, colls);
+ }
+ return cbls;
+}
+
+/* make sure you coba is not none before calling this */
+int EXPP_Colorband_fromPyList( ColorBand **coba, PyObject * value )
+{
+ short totcol, i;
+ PyObject *colseq;
+ PyObject *pyflt;
+ float f;
+
+ if ( !PySequence_Check( value ) )
+ return ( EXPP_ReturnIntError( PyExc_TypeError,
+ "Colorband must be a sequence" ) );
+
+ totcol = PySequence_Size(value);
+ if ( totcol > 31)
+ return ( EXPP_ReturnIntError( PyExc_ValueError,
+ "Colorband must be between 1 and 31 in length" ) );
+
+ if (totcol==0) {
+ MEM_freeN(*coba);
+ *coba = NULL;
+ return 0;
+ }
+
+ if (!*coba)
+ *coba = MEM_callocN( sizeof(ColorBand), "colorband");
+
+ for (i=0; i<totcol; i++) {
+ colseq = PySequence_GetItem( value, i );
+ if ( !PySequence_Check( colseq ) || PySequence_Size( colseq ) != 5) {
+ Py_DECREF ( colseq );
+ return ( EXPP_ReturnIntError( PyExc_ValueError,
+ "Colorband colors must be sequences of 5 floats" ) );
+ }
+ for (i=0; i<5; i++) {
+ pyflt = PySequence_GetItem( colseq, i );
+ if (!PyNumber_Check(pyflt)) {
+ return ( EXPP_ReturnIntError( PyExc_ValueError,
+ "Colorband colors must be sequences of 5 floats" ) );
+ Py_DECREF ( pyflt );
+ Py_DECREF ( colseq );
+ }
+ Py_DECREF ( pyflt );
+ }
+ Py_DECREF ( colseq );
+ }
+
+ /* ok, continue - should check for 5 floats, will ignore non floats for now */
+ (*coba)->tot = totcol;
+ for (i=0; i<totcol; i++) {
+ colseq = PySequence_GetItem( value, i );
+
+ pyflt = PySequence_GetItem( colseq, 0 );
+ f = (float)PyFloat_AsDouble( pyflt );
+ CLAMP(f, 0.0, 1.0);
+ (*coba)->data[i].r = f;
+ Py_DECREF ( pyflt );
+
+ pyflt = PySequence_GetItem( colseq, 1 );
+ f = (float)PyFloat_AsDouble( pyflt );
+ CLAMP(f, 0.0, 1.0);
+ (*coba)->data[i].g = f;
+ Py_DECREF ( pyflt );
+
+ pyflt = PySequence_GetItem( colseq, 2 );
+ f = (float)PyFloat_AsDouble( pyflt );
+ CLAMP(f, 0.0, 1.0);
+ (*coba)->data[i].b = f;
+ Py_DECREF ( pyflt );
+
+ pyflt = PySequence_GetItem( colseq, 3 );
+ f = (float)PyFloat_AsDouble( pyflt );
+ CLAMP(f, 0.0, 1.0);
+ (*coba)->data[i].a = f;
+ Py_DECREF ( pyflt );
+
+ pyflt = PySequence_GetItem( colseq, 4 );
+ f = (float)PyFloat_AsDouble( pyflt );
+ CLAMP(f, 0.0, 1.0);
+ (*coba)->data[i].pos = f;
+ Py_DECREF ( pyflt );
+
+ Py_DECREF ( colseq );
+ }
+ return 0;
+}
+
+
+/*****************************************************************************/
+/* These functions are used in NMesh.c and Object.c */
+/*****************************************************************************/
+PyObject *EXPP_PyList_fromMaterialList( Material ** matlist, int len, int all )
+{
+ PyObject *list;
+ int i;
+
+ list = PyList_New( 0 );
+ if( !matlist )
+ return list;
+
+ for( i = 0; i < len; i++ ) {
+ Material *mat = matlist[i];
+ PyObject *ob;
+
+ if( mat ) {
+ ob = Material_CreatePyObject( mat );
+ PyList_Append( list, ob );
+ Py_DECREF( ob ); /* because Append increfs */
+ } else if( all ) { /* return NULL mats (empty slots) as Py_None */
+ PyList_Append( list, Py_None );
+ }
+ }
+
+ return list;
+}
+
+Material **EXPP_newMaterialList_fromPyList( PyObject * list )
+{
+ int i, len;
+ BPy_Material *pymat = 0;
+ Material *mat;
+ Material **matlist;
+
+ len = PySequence_Length( list );
+ if( len > 16 )
+ len = 16;
+ else if( len <= 0 )
+ return NULL;
+
+ matlist = EXPP_newMaterialList( len );
+
+ for( i = 0; i < len; i++ ) {
+
+ pymat = ( BPy_Material * ) PySequence_GetItem( list, i );
+
+ if( BPy_Material_Check( ( PyObject * ) pymat ) ) {
+ mat = pymat->material;
+ matlist[i] = mat;
+ } else if( ( PyObject * ) pymat == Py_None ) {
+ matlist[i] = NULL;
+ } else { /* error; illegal type in material list */
+ Py_DECREF( pymat );
+ MEM_freeN( matlist );
+ return NULL;
+ }
+
+ Py_DECREF( pymat );
+ }
+
+ return matlist;
+}
+
+Material **EXPP_newMaterialList( int len )
+{
+ Material **matlist =
+ ( Material ** ) MEM_mallocN( len * sizeof( Material * ),
+ "MaterialList" );
+
+ return matlist;
+}
+
+int EXPP_releaseMaterialList( Material ** matlist, int len )
+{
+ int i;
+ Material *mat;
+
+ if( ( len < 0 ) || ( len > MAXMAT ) ) {
+ printf( "illegal matindex!\n" );
+ return 0;
+ }
+
+ for( i = 0; i < len; i++ ) {
+ mat = matlist[i];
+ if( mat ) {
+ if( ( ( ID * ) mat )->us > 0 )
+ ( ( ID * ) mat )->us--;
+ else
+ printf( "FATAL: material usage=0: %s",
+ ( ( ID * ) mat )->name );
+ }
+ }
+ MEM_freeN( matlist );
+
+ return 1;
+}
+
+/** expands pointer array of length 'oldsize' to length 'newsize'.
+ * A pointer to the (void *) array must be passed as first argument
+ * The array pointer content can be NULL, in this case a new array of length
+ * 'newsize' is created.
+ */
+
+static int expandPtrArray( void **p, int oldsize, int newsize )
+{
+ void *newarray;
+
+ if( newsize < oldsize ) {
+ return 0;
+ }
+ newarray = MEM_callocN( sizeof( void * ) * newsize, "PtrArray" );
+ if( *p ) {
+ memcpy( newarray, *p, sizeof( void * ) * oldsize );
+ MEM_freeN( *p );
+ }
+ *p = newarray;
+ return 1;
+}
+
+int EXPP_synchronizeMaterialLists( Object * object )
+{
+ Material ***p_dataMaterials = give_matarar( object );
+ short *nmaterials = give_totcolp( object );
+ int result = 0;
+
+ if( object->totcol > *nmaterials ) {
+ /* More object mats than data mats */
+ result = expandPtrArray( ( void * ) p_dataMaterials,
+ *nmaterials, object->totcol );
+ *nmaterials = object->totcol;
+ } else {
+ if( object->totcol < *nmaterials ) {
+ /* More data mats than object mats */
+ result = expandPtrArray( ( void * ) &object->mat,
+ object->totcol, *nmaterials );
+ object->totcol = (char)*nmaterials;
+ }
+ } /* else no synchronization needed, they are of equal length */
+
+ return result; /* 1 if changed, 0 otherwise */
+}
+
+void EXPP_incr_mats_us( Material ** matlist, int len )
+{
+ int i;
+ Material *mat;
+
+ if( len <= 0 )
+ return;
+
+ for( i = 0; i < len; i++ ) {
+ mat = matlist[i];
+ if( mat )
+ mat->id.us++;
+ }
+
+ return;
+}
+
+static PyObject *Material_getColorComponent( BPy_Material * self,
+ void * closure )
+{
+ switch ( (int)closure ) {
+ case EXPP_MAT_COMP_R:
+ return PyFloat_FromDouble( ( double ) self->material->r );
+ case EXPP_MAT_COMP_G:
+ return PyFloat_FromDouble( ( double ) self->material->g );
+ case EXPP_MAT_COMP_B:
+ return PyFloat_FromDouble( ( double ) self->material->b );
+ case EXPP_MAT_COMP_SPECR:
+ return PyFloat_FromDouble( ( double ) self->material->specr );
+ case EXPP_MAT_COMP_SPECG:
+ return PyFloat_FromDouble( ( double ) self->material->specg );
+ case EXPP_MAT_COMP_SPECB:
+ return PyFloat_FromDouble( ( double ) self->material->specb );
+ case EXPP_MAT_COMP_MIRR:
+ return PyFloat_FromDouble( ( double ) self->material->mirr );
+ case EXPP_MAT_COMP_MIRG:
+ return PyFloat_FromDouble( ( double ) self->material->mirg );
+ case EXPP_MAT_COMP_MIRB:
+ return PyFloat_FromDouble( ( double ) self->material->mirb );
+ case EXPP_MAT_COMP_SSSR:
+ return PyFloat_FromDouble( ( double ) self->material->sss_col[0] );
+ case EXPP_MAT_COMP_SSSG:
+ return PyFloat_FromDouble( ( double ) self->material->sss_col[1] );
+ case EXPP_MAT_COMP_SSSB:
+ return PyFloat_FromDouble( ( double ) self->material->sss_col[2] );
+ default:
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "unknown color component specified" );
+ }
+}
+
+static PyObject *Material_getColorband( BPy_Material * self, void * type)
+{
+ switch( (long)type ) {
+ case 0: /* these are backwards, but that how it works */
+ return EXPP_PyList_fromColorband( self->material->ramp_col );
+ case 1:
+ return EXPP_PyList_fromColorband( self->material->ramp_spec );
+ }
+ Py_RETURN_NONE;
+}
+
+int Material_setColorband( BPy_Material * self, PyObject * value, void * type)
+{
+ switch( (long)type ) {
+ case 0: /* these are backwards, but that how it works */
+ return EXPP_Colorband_fromPyList( &self->material->ramp_col, value );
+ case 1:
+ return EXPP_Colorband_fromPyList( &self->material->ramp_spec, value );
+ }
+ return 0;
+}
+
+/* #####DEPRECATED###### */
+
+static PyObject *Matr_oldsetAdd( BPy_Material * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Material_setAdd );
+}
+
+static PyObject *Matr_oldsetAlpha( BPy_Material * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Material_setAlpha );
+}
+
+static PyObject *Matr_oldsetAmb( BPy_Material * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Material_setAmb );
+}
+
+static PyObject *Matr_oldsetDiffuseDarkness( BPy_Material * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Material_setDiffuseDarkness );
+}
+
+static PyObject *Matr_oldsetDiffuseShader( BPy_Material * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Material_setDiffuseShader );
+}
+
+static PyObject *Matr_oldsetDiffuseSize( BPy_Material * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Material_setDiffuseSize );
+}
+
+static PyObject *Matr_oldsetDiffuseSmooth( BPy_Material * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Material_setDiffuseSmooth );
+}
+
+static PyObject *Matr_oldsetEmit( BPy_Material * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Material_setEmit );
+}
+
+static PyObject *Matr_oldsetFilter( BPy_Material * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Material_setFilter );
+}
+
+static PyObject *Matr_oldsetFlareBoost( BPy_Material * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Material_setFlareBoost );
+}
+
+static PyObject *Matr_oldsetFlareSeed( BPy_Material * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Material_setFlareSeed );
+}
+
+static PyObject *Matr_oldsetFlareSize( BPy_Material * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Material_setFlareSize );
+}
+
+static PyObject *Matr_oldsetFresnelMirr( BPy_Material * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Material_setFresnelMirr );
+}
+
+static PyObject *Matr_oldsetFresnelMirrFac( BPy_Material * self,
+ PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Material_setFresnelMirrFac );
+}
+
+static PyObject *Matr_oldsetFresnelTrans( BPy_Material * self,
+ PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Material_setFresnelTrans );
+}
+
+static PyObject *Matr_oldsetFresnelTransFac( BPy_Material * self,
+ PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Material_setFresnelTransFac );
+}
+
+static PyObject *Matr_oldsetHaloSeed( BPy_Material * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Material_setHaloSeed );
+}
+
+static PyObject *Matr_oldsetHaloSize( BPy_Material * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Material_setHaloSize );
+}
+
+static PyObject *Matr_oldsetHardness( BPy_Material * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Material_setHardness );
+}
+
+static PyObject *Matr_oldsetIOR( BPy_Material * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Material_setIOR );
+}
+
+static PyObject *Matr_oldsetNFlares( BPy_Material * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Material_setNFlares );
+}
+
+static PyObject *Matr_oldsetNLines( BPy_Material * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Material_setNLines );
+}
+
+static PyObject *Matr_oldsetNRings( BPy_Material * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Material_setNRings );
+}
+
+static PyObject *Matr_oldsetNStars( BPy_Material * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Material_setNStars );
+}
+
+static PyObject *Matr_oldsetRayMirr( BPy_Material * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Material_setRayMirr );
+}
+
+static PyObject *Matr_oldsetRoughness( BPy_Material * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Material_setRoughness );
+}
+
+static PyObject *Matr_oldsetMirrDepth( BPy_Material * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Material_setMirrDepth );
+}
+
+static PyObject *Matr_oldsetRef( BPy_Material * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Material_setRef );
+}
+
+static PyObject *Matr_oldsetRefracIndex( BPy_Material * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Material_setRefracIndex );
+}
+
+static PyObject *Matr_oldsetRms( BPy_Material * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Material_setRms );
+}
+
+static PyObject *Matr_oldsetSpec( BPy_Material * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Material_setSpec );
+}
+
+static PyObject *Matr_oldsetSpecShader( BPy_Material * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Material_setSpecShader );
+}
+
+static PyObject *Matr_oldsetSpecSize( BPy_Material * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Material_setSpecSize );
+}
+
+static PyObject *Matr_oldsetSpecSmooth( BPy_Material * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Material_setSpecSmooth );
+}
+
+static PyObject *Matr_oldsetSpecTransp( BPy_Material * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Material_setSpecTransp );
+}
+
+static PyObject *Matr_oldsetSubSize( BPy_Material * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Material_setSubSize );
+}
+
+static PyObject *Matr_oldsetTranslucency( BPy_Material * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Material_setTranslucency );
+}
+
+static PyObject *Matr_oldsetTransDepth( BPy_Material * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Material_setTransDepth );
+}
+
+static PyObject *Matr_oldsetZOffset( BPy_Material * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Material_setZOffset );
+}
+
+static PyObject *Matr_oldsetRGBCol( BPy_Material * self, PyObject * args )
+{
+ return EXPP_setterWrapperTuple( (void *)self, args,
+ (setter)Material_setRGBCol );
+}
+
+static PyObject *Matr_oldsetSpecCol( BPy_Material * self, PyObject * args )
+{
+ return EXPP_setterWrapperTuple( (void *)self, args,
+ (setter)Material_setSpecCol );
+}
+
+static PyObject *Matr_oldsetMirCol( BPy_Material * self, PyObject * args )
+{
+ return EXPP_setterWrapperTuple( (void *)self, args,
+ (setter)Material_setMirCol );
+}
+
+
+/* Possible modes are traceable, shadow, shadeless, wire, vcolLight,
+ * vcolPaint, halo, ztransp, zinvert, haloRings, env, haloLines,
+ * onlyShadow, xalpha, star, faceTexture, haloTex, haloPuno, noMist,
+ * haloShaded, haloFlare */
+
+static PyObject *Matr_oldsetMode( BPy_Material * self, PyObject * args )
+{
+ unsigned int i, flag = 0, ok = 0;
+ PyObject *value, *error;
+ char *m[28] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL
+ };
+
+ /*
+ * check for a single integer argument; do a quick check for now
+ * that the value is not larger than double the highest flag bit
+ */
+
+ if ( (PySequence_Size( args ) == 1)
+ && PyInt_Check ( PyTuple_GET_ITEM ( args , 0 ) )
+ && PyArg_ParseTuple( args, "i", &flag )
+ && (flag & MA_MODE_MASK ) == flag ) {
+ ok = 1;
+
+ /*
+ * check for either an empty argument list, or up to 28 strings
+ */
+
+ } else if( PyArg_ParseTuple( args, "|ssssssssssssssssssssssssssss",
+ &m[0], &m[1], &m[2], &m[3], &m[4], &m[5], &m[6],
+ &m[7], &m[8], &m[9], &m[10], &m[11], &m[12],
+ &m[13], &m[14], &m[15], &m[16], &m[17], &m[18],
+ &m[19], &m[20], &m[21], &m[22], &m[23], &m[24],
+ &m[25], &m[26], &m[27] ) ) {
+ for( i = 0; i < 28; i++ ) {
+ if( m[i] == NULL )
+ break;
+ if( strcmp( m[i], "Traceable" ) == 0 )
+ flag |= MA_TRACEBLE;
+ else if( strcmp( m[i], "Shadow" ) == 0 )
+ flag |= MA_SHADOW;
+ else if( strcmp( m[i], "Shadeless" ) == 0 )
+ flag |= MA_SHLESS;
+ else if( strcmp( m[i], "Wire" ) == 0 )
+ flag |= MA_WIRE;
+ else if( strcmp( m[i], "VColLight" ) == 0 )
+ flag |= MA_VERTEXCOL;
+ else if( strcmp( m[i], "VColPaint" ) == 0 )
+ flag |= MA_VERTEXCOLP;
+ else if( strcmp( m[i], "Halo" ) == 0 )
+ flag |= MA_HALO;
+ else if( strcmp( m[i], "ZTransp" ) == 0 )
+ flag |= MA_ZTRA;
+ else if( strcmp( m[i], "ZInvert" ) == 0 )
+ flag |= MA_ZINV;
+ else if( strcmp( m[i], "HaloRings" ) == 0 )
+ flag |= MA_HALO_RINGS;
+ else if( strcmp( m[i], "HaloLines" ) == 0 )
+ flag |= MA_HALO_LINES;
+ else if( strcmp( m[i], "OnlyShadow" ) == 0 )
+ flag |= MA_ONLYSHADOW;
+ else if( strcmp( m[i], "HaloXAlpha" ) == 0 )
+ flag |= MA_HALO_XALPHA;
+ else if( strcmp( m[i], "HaloStar" ) == 0 )
+ flag |= MA_STAR;
+ else if( strcmp( m[i], "TexFace" ) == 0 )
+ flag |= MA_FACETEXTURE;
+ else if( strcmp( m[i], "HaloTex" ) == 0 )
+ flag |= MA_HALOTEX;
+ else if( strcmp( m[i], "HaloPuno" ) == 0 )
+ flag |= MA_HALOPUNO;
+ else if( strcmp( m[i], "NoMist" ) == 0 )
+ flag |= MA_NOMIST;
+ else if( strcmp( m[i], "HaloShaded" ) == 0 )
+ flag |= MA_HALO_SHADE;
+ else if( strcmp( m[i], "HaloFlare" ) == 0 )
+ flag |= MA_HALO_FLARE;
+ else if( strcmp( m[i], "Radio" ) == 0 )
+ flag |= MA_RADIO;
+ /* ** Mirror ** */
+ else if( strcmp( m[i], "RayMirr" ) == 0 )
+ flag |= MA_RAYMIRROR;
+ else if( strcmp( m[i], "ZTransp" ) == 0 )
+ flag |= MA_ZTRA;
+ else if( strcmp( m[i], "RayTransp" ) == 0 )
+ flag |= MA_RAYTRANSP;
+ else if( strcmp( m[i], "OnlyShadow" ) == 0 )
+ flag |= MA_ONLYSHADOW;
+ else if( strcmp( m[i], "NoMist" ) == 0 )
+ flag |= MA_NOMIST;
+ else if( strcmp( m[i], "Env" ) == 0 )
+ flag |= MA_ENV;
+ else
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "unknown Material mode argument" ) );
+ }
+ ok = 1;
+ }
+
+ /* if neither input method worked, then throw an exception */
+
+ if ( ok == 0 )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_AttributeError,
+ "expected nothing, an integer or up to 22 string argument(s)" ) );
+ /* build tuple, call wrapper */
+
+ value = Py_BuildValue("(i)", flag);
+ error = EXPP_setterWrapper( (void *)self, value, (setter)Material_setMode );
+ Py_DECREF ( value );
+ return error;
+}
+
+static PyObject *Matr_oldsetIpo( BPy_Material * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Material_setIpo );
+}
+
+/*
+ * clearIpo() returns True/False depending on whether material has an Ipo
+ */
+
+static PyObject *Material_clearIpo( BPy_Material * self )
+{
+ /* if Ipo defined, delete it and return true */
+
+ if( self->material->ipo ) {
+ PyObject *value = Py_BuildValue( "(O)", Py_None );
+ EXPP_setterWrapper( (void *)self, value, (setter)Material_setIpo );
+ Py_DECREF ( value );
+ return EXPP_incr_ret_True();
+ }
+ return EXPP_incr_ret_False(); /* no ipo found */
+}
+
diff --git a/source/blender/python/api2_2x/Material.h b/source/blender/python/api2_2x/Material.h
new file mode 100644
index 00000000000..c4061f795c7
--- /dev/null
+++ b/source/blender/python/api2_2x/Material.h
@@ -0,0 +1,78 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_MATERIAL_H
+#define EXPP_MATERIAL_H
+
+#include <Python.h>
+#include "DNA_object_types.h"
+#include "DNA_material_types.h"
+#include "DNA_texture_types.h" /* colorband */
+#include "rgbTuple.h"
+
+/*****************************************************************************/
+/* Python BPy_Material structure definition: */
+/*****************************************************************************/
+typedef struct {
+ PyObject_HEAD
+ Material * material; /* libdata must be second */
+ BPy_rgbTuple *col, *amb, *spec, *mir, *sss;
+} BPy_Material;
+
+extern PyTypeObject Material_Type; /* The Material PyType Object */
+
+#define BPy_Material_Check(v) \
+ ((v)->ob_type == &Material_Type) /* for type checking */
+
+/*****************************************************************************/
+/* Module Blender.Material - public functions */
+/*****************************************************************************/
+PyObject *M_Material_Init( void );
+
+PyObject *Material_Init( void );
+PyObject *Material_CreatePyObject( Material * mat );
+Material *Material_FromPyObject( PyObject * pyobj );
+
+/* colorband tp_getseters */
+PyObject *EXPP_PyList_fromColorband( ColorBand *coba );
+int EXPP_Colorband_fromPyList( ColorBand **coba, PyObject * value );
+
+/* Some functions needed by NMesh, Curve and friends */
+PyObject *EXPP_PyList_fromMaterialList( Material ** matlist, int len,
+ int all );
+Material **EXPP_newMaterialList_fromPyList( PyObject * list );
+Material **EXPP_newMaterialList( int len );
+void EXPP_incr_mats_us( Material ** matlist, int len );
+int EXPP_synchronizeMaterialLists( Object * object );
+int EXPP_releaseMaterialList( Material ** matlist, int len );
+
+#endif /* EXPP_MATERIAL_H */
diff --git a/source/blender/python/api2_2x/Mathutils.c b/source/blender/python/api2_2x/Mathutils.c
new file mode 100644
index 00000000000..3605c956a58
--- /dev/null
+++ b/source/blender/python/api2_2x/Mathutils.c
@@ -0,0 +1,1804 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Joseph Gilbert, Campbell Barton
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "Mathutils.h"
+
+#include "BLI_arithb.h"
+#include "PIL_time.h"
+#include "BLI_rand.h"
+#include "BKE_utildefines.h"
+
+#include "gen_utils.h"
+
+//-------------------------DOC STRINGS ---------------------------
+static char M_Mathutils_doc[] = "The Blender Mathutils module\n\n";
+static char M_Mathutils_Vector_doc[] = "() - create a new vector object from a list of floats";
+static char M_Mathutils_Matrix_doc[] = "() - create a new matrix object from a list of floats";
+static char M_Mathutils_Quaternion_doc[] = "() - create a quaternion from a list or an axis of rotation and an angle";
+static char M_Mathutils_Euler_doc[] = "() - create and return a new euler object";
+static char M_Mathutils_Rand_doc[] = "() - return a random number";
+static char M_Mathutils_CrossVecs_doc[] = "() - returns a vector perpedicular to the 2 vectors crossed";
+static char M_Mathutils_CopyVec_doc[] = "() - create a copy of vector";
+static char M_Mathutils_DotVecs_doc[] = "() - return the dot product of two vectors";
+static char M_Mathutils_AngleBetweenVecs_doc[] = "() - returns the angle between two vectors in degrees";
+static char M_Mathutils_MidpointVecs_doc[] = "() - return the vector to the midpoint between two vectors";
+static char M_Mathutils_MatMultVec_doc[] = "() - multiplies a matrix by a column vector";
+static char M_Mathutils_VecMultMat_doc[] = "() - multiplies a row vector by a matrix";
+static char M_Mathutils_ProjectVecs_doc[] = "() - returns the projection vector from the projection of vecA onto vecB";
+static char M_Mathutils_RotationMatrix_doc[] = "() - construct a rotation matrix from an angle and axis of rotation";
+static char M_Mathutils_ScaleMatrix_doc[] = "() - construct a scaling matrix from a scaling factor";
+static char M_Mathutils_OrthoProjectionMatrix_doc[] = "() - construct a orthographic projection matrix from a selected plane";
+static char M_Mathutils_ShearMatrix_doc[] = "() - construct a shearing matrix from a plane of shear and a shear factor";
+static char M_Mathutils_CopyMat_doc[] = "() - create a copy of a matrix";
+static char M_Mathutils_TranslationMatrix_doc[] = "(vec) - create a translation matrix from a vector";
+static char M_Mathutils_CopyQuat_doc[] = "() - copy quatB to quatA";
+static char M_Mathutils_CopyEuler_doc[] = "() - copy eulB to eultA";
+static char M_Mathutils_CrossQuats_doc[] = "() - return the mutliplication of two quaternions";
+static char M_Mathutils_DotQuats_doc[] = "() - return the dot product of two quaternions";
+static char M_Mathutils_Slerp_doc[] = "() - returns the interpolation between two quaternions";
+static char M_Mathutils_DifferenceQuats_doc[] = "() - return the angular displacment difference between two quats";
+static char M_Mathutils_RotateEuler_doc[] = "() - rotate euler by an axis and angle";
+static char M_Mathutils_Intersect_doc[] = "(v1, v2, v3, ray, orig, clip=1) - returns the intersection between a ray and a triangle, if possible, returns None otherwise";
+static char M_Mathutils_TriangleArea_doc[] = "(v1, v2, v3) - returns the area size of the 2D or 3D triangle defined";
+static char M_Mathutils_TriangleNormal_doc[] = "(v1, v2, v3) - returns the normal of the 3D triangle defined";
+static char M_Mathutils_QuadNormal_doc[] = "(v1, v2, v3, v4) - returns the normal of the 3D quad defined";
+static char M_Mathutils_LineIntersect_doc[] = "(v1, v2, v3, v4) - returns a tuple with the points on each line respectively closest to the other";
+static char M_Mathutils_Point_doc[] = "Creates a 2d or 3d point object";
+//-----------------------METHOD DEFINITIONS ----------------------
+struct PyMethodDef M_Mathutils_methods[] = {
+ {"Rand", (PyCFunction) M_Mathutils_Rand, METH_VARARGS, M_Mathutils_Rand_doc},
+ {"Vector", (PyCFunction) M_Mathutils_Vector, METH_VARARGS, M_Mathutils_Vector_doc},
+ {"CrossVecs", (PyCFunction) M_Mathutils_CrossVecs, METH_VARARGS, M_Mathutils_CrossVecs_doc},
+ {"DotVecs", (PyCFunction) M_Mathutils_DotVecs, METH_VARARGS, M_Mathutils_DotVecs_doc},
+ {"AngleBetweenVecs", (PyCFunction) M_Mathutils_AngleBetweenVecs, METH_VARARGS, M_Mathutils_AngleBetweenVecs_doc},
+ {"MidpointVecs", (PyCFunction) M_Mathutils_MidpointVecs, METH_VARARGS, M_Mathutils_MidpointVecs_doc},
+ {"VecMultMat", (PyCFunction) M_Mathutils_VecMultMat, METH_VARARGS, M_Mathutils_VecMultMat_doc},
+ {"ProjectVecs", (PyCFunction) M_Mathutils_ProjectVecs, METH_VARARGS, M_Mathutils_ProjectVecs_doc},
+ {"CopyVec", (PyCFunction) M_Mathutils_CopyVec, METH_VARARGS, M_Mathutils_CopyVec_doc},
+ {"Matrix", (PyCFunction) M_Mathutils_Matrix, METH_VARARGS, M_Mathutils_Matrix_doc},
+ {"RotationMatrix", (PyCFunction) M_Mathutils_RotationMatrix, METH_VARARGS, M_Mathutils_RotationMatrix_doc},
+ {"ScaleMatrix", (PyCFunction) M_Mathutils_ScaleMatrix, METH_VARARGS, M_Mathutils_ScaleMatrix_doc},
+ {"ShearMatrix", (PyCFunction) M_Mathutils_ShearMatrix, METH_VARARGS, M_Mathutils_ShearMatrix_doc},
+ {"TranslationMatrix", (PyCFunction) M_Mathutils_TranslationMatrix, METH_O, M_Mathutils_TranslationMatrix_doc},
+ {"CopyMat", (PyCFunction) M_Mathutils_CopyMat, METH_VARARGS, M_Mathutils_CopyMat_doc},
+ {"OrthoProjectionMatrix", (PyCFunction) M_Mathutils_OrthoProjectionMatrix, METH_VARARGS, M_Mathutils_OrthoProjectionMatrix_doc},
+ {"MatMultVec", (PyCFunction) M_Mathutils_MatMultVec, METH_VARARGS, M_Mathutils_MatMultVec_doc},
+ {"Quaternion", (PyCFunction) M_Mathutils_Quaternion, METH_VARARGS, M_Mathutils_Quaternion_doc},
+ {"CopyQuat", (PyCFunction) M_Mathutils_CopyQuat, METH_VARARGS, M_Mathutils_CopyQuat_doc},
+ {"CrossQuats", (PyCFunction) M_Mathutils_CrossQuats, METH_VARARGS, M_Mathutils_CrossQuats_doc},
+ {"DotQuats", (PyCFunction) M_Mathutils_DotQuats, METH_VARARGS, M_Mathutils_DotQuats_doc},
+ {"DifferenceQuats", (PyCFunction) M_Mathutils_DifferenceQuats, METH_VARARGS,M_Mathutils_DifferenceQuats_doc},
+ {"Slerp", (PyCFunction) M_Mathutils_Slerp, METH_VARARGS, M_Mathutils_Slerp_doc},
+ {"Euler", (PyCFunction) M_Mathutils_Euler, METH_VARARGS, M_Mathutils_Euler_doc},
+ {"CopyEuler", (PyCFunction) M_Mathutils_CopyEuler, METH_VARARGS, M_Mathutils_CopyEuler_doc},
+ {"RotateEuler", (PyCFunction) M_Mathutils_RotateEuler, METH_VARARGS, M_Mathutils_RotateEuler_doc},
+ {"Intersect", ( PyCFunction ) M_Mathutils_Intersect, METH_VARARGS, M_Mathutils_Intersect_doc},
+ {"TriangleArea", ( PyCFunction ) M_Mathutils_TriangleArea, METH_VARARGS, M_Mathutils_TriangleArea_doc},
+ {"TriangleNormal", ( PyCFunction ) M_Mathutils_TriangleNormal, METH_VARARGS, M_Mathutils_TriangleNormal_doc},
+ {"QuadNormal", ( PyCFunction ) M_Mathutils_QuadNormal, METH_VARARGS, M_Mathutils_QuadNormal_doc},
+ {"LineIntersect", ( PyCFunction ) M_Mathutils_LineIntersect, METH_VARARGS, M_Mathutils_LineIntersect_doc},
+ {"Point", (PyCFunction) M_Mathutils_Point, METH_VARARGS, M_Mathutils_Point_doc},
+ {NULL, NULL, 0, NULL}
+};
+//----------------------------MODULE INIT-------------------------
+PyObject *Mathutils_Init(void)
+{
+ PyObject *submodule;
+
+ //seed the generator for the rand function
+ BLI_srand((unsigned int) (PIL_check_seconds_timer() *
+ 0x7FFFFFFF));
+
+ /* needed for getseters */
+ if( PyType_Ready( &vector_Type ) < 0 )
+ return NULL;
+ if( PyType_Ready( &matrix_Type ) < 0 )
+ return NULL;
+ if( PyType_Ready( &euler_Type ) < 0 )
+ return NULL;
+ if( PyType_Ready( &quaternion_Type ) < 0 )
+ return NULL;
+
+ submodule = Py_InitModule3("Blender.Mathutils",
+ M_Mathutils_methods, M_Mathutils_doc);
+ return (submodule);
+}
+//-----------------------------METHODS----------------------------
+//----------------column_vector_multiplication (internal)---------
+//COLUMN VECTOR Multiplication (Matrix X Vector)
+// [1][2][3] [a]
+// [4][5][6] * [b]
+// [7][8][9] [c]
+//vector/matrix multiplication IS NOT COMMUTATIVE!!!!
+PyObject *column_vector_multiplication(MatrixObject * mat, VectorObject* vec)
+{
+ float vecNew[4], vecCopy[4];
+ double dot = 0.0f;
+ int x, y, z = 0;
+
+ if(mat->rowSize != vec->size){
+ if(mat->rowSize == 4 && vec->size != 3){
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "matrix * vector: matrix row size and vector size must be the same");
+ }else{
+ vecCopy[3] = 1.0f;
+ }
+ }
+
+ for(x = 0; x < vec->size; x++){
+ vecCopy[x] = vec->vec[x];
+ }
+
+ for(x = 0; x < mat->rowSize; x++) {
+ for(y = 0; y < mat->colSize; y++) {
+ dot += mat->matrix[x][y] * vecCopy[y];
+ }
+ vecNew[z++] = (float)dot;
+ dot = 0.0f;
+ }
+ return newVectorObject(vecNew, vec->size, Py_NEW);
+}
+//This is a helper for point/matrix translation
+
+PyObject *column_point_multiplication(MatrixObject * mat, PointObject* pt)
+{
+ float ptNew[4], ptCopy[4];
+ double dot = 0.0f;
+ int x, y, z = 0;
+
+ if(mat->rowSize != pt->size){
+ if(mat->rowSize == 4 && pt->size != 3){
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "matrix * point: matrix row size and point size must be the same\n");
+ }else{
+ ptCopy[3] = 0.0f;
+ }
+ }
+
+ for(x = 0; x < pt->size; x++){
+ ptCopy[x] = pt->coord[x];
+ }
+
+ for(x = 0; x < mat->rowSize; x++) {
+ for(y = 0; y < mat->colSize; y++) {
+ dot += mat->matrix[x][y] * ptCopy[y];
+ }
+ ptNew[z++] = (float)dot;
+ dot = 0.0f;
+ }
+ return newPointObject(ptNew, pt->size, Py_NEW);
+}
+//-----------------row_vector_multiplication (internal)-----------
+//ROW VECTOR Multiplication - Vector X Matrix
+//[x][y][z] * [1][2][3]
+// [4][5][6]
+// [7][8][9]
+//vector/matrix multiplication IS NOT COMMUTATIVE!!!!
+PyObject *row_vector_multiplication(VectorObject* vec, MatrixObject * mat)
+{
+ float vecNew[4], vecCopy[4];
+ double dot = 0.0f;
+ int x, y, z = 0, vec_size = vec->size;
+
+ if(mat->colSize != vec_size){
+ if(mat->rowSize == 4 && vec_size != 3){
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "vector * matrix: matrix column size and the vector size must be the same");
+ }else{
+ vecCopy[3] = 1.0f;
+ }
+ }
+
+ for(x = 0; x < vec_size; x++){
+ vecCopy[x] = vec->vec[x];
+ }
+
+ //muliplication
+ for(x = 0; x < mat->colSize; x++) {
+ for(y = 0; y < mat->rowSize; y++) {
+ dot += mat->matrix[y][x] * vecCopy[y];
+ }
+ vecNew[z++] = (float)dot;
+ dot = 0.0f;
+ }
+ return newVectorObject(vecNew, vec_size, Py_NEW);
+}
+//This is a helper for the point class
+PyObject *row_point_multiplication(PointObject* pt, MatrixObject * mat)
+{
+ float ptNew[4], ptCopy[4];
+ double dot = 0.0f;
+ int x, y, z = 0, size;
+
+ if(mat->colSize != pt->size){
+ if(mat->rowSize == 4 && pt->size != 3){
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "point * matrix: matrix column size and the point size must be the same\n");
+ }else{
+ ptCopy[3] = 0.0f;
+ }
+ }
+ size = pt->size;
+ for(x = 0; x < pt->size; x++){
+ ptCopy[x] = pt->coord[x];
+ }
+
+ //muliplication
+ for(x = 0; x < mat->colSize; x++) {
+ for(y = 0; y < mat->rowSize; y++) {
+ dot += mat->matrix[y][x] * ptCopy[y];
+ }
+ ptNew[z++] = (float)dot;
+ dot = 0.0f;
+ }
+ return newPointObject(ptNew, size, Py_NEW);
+}
+//-----------------quat_rotation (internal)-----------
+//This function multiplies a vector/point * quat or vice versa
+//to rotate the point/vector by the quaternion
+//arguments should all be 3D
+PyObject *quat_rotation(PyObject *arg1, PyObject *arg2)
+{
+ float rot[3];
+ QuaternionObject *quat = NULL;
+ VectorObject *vec = NULL;
+ PointObject *pt = NULL;
+
+ if(QuaternionObject_Check(arg1)){
+ quat = (QuaternionObject*)arg1;
+ if(VectorObject_Check(arg2)){
+ vec = (VectorObject*)arg2;
+ rot[0] = quat->quat[0]*quat->quat[0]*vec->vec[0] + 2*quat->quat[2]*quat->quat[0]*vec->vec[2] -
+ 2*quat->quat[3]*quat->quat[0]*vec->vec[1] + quat->quat[1]*quat->quat[1]*vec->vec[0] +
+ 2*quat->quat[2]*quat->quat[1]*vec->vec[1] + 2*quat->quat[3]*quat->quat[1]*vec->vec[2] -
+ quat->quat[3]*quat->quat[3]*vec->vec[0] - quat->quat[2]*quat->quat[2]*vec->vec[0];
+ rot[1] = 2*quat->quat[1]*quat->quat[2]*vec->vec[0] + quat->quat[2]*quat->quat[2]*vec->vec[1] +
+ 2*quat->quat[3]*quat->quat[2]*vec->vec[2] + 2*quat->quat[0]*quat->quat[3]*vec->vec[0] -
+ quat->quat[3]*quat->quat[3]*vec->vec[1] + quat->quat[0]*quat->quat[0]*vec->vec[1] -
+ 2*quat->quat[1]*quat->quat[0]*vec->vec[2] - quat->quat[1]*quat->quat[1]*vec->vec[1];
+ rot[2] = 2*quat->quat[1]*quat->quat[3]*vec->vec[0] + 2*quat->quat[2]*quat->quat[3]*vec->vec[1] +
+ quat->quat[3]*quat->quat[3]*vec->vec[2] - 2*quat->quat[0]*quat->quat[2]*vec->vec[0] -
+ quat->quat[2]*quat->quat[2]*vec->vec[2] + 2*quat->quat[0]*quat->quat[1]*vec->vec[1] -
+ quat->quat[1]*quat->quat[1]*vec->vec[2] + quat->quat[0]*quat->quat[0]*vec->vec[2];
+ return newVectorObject(rot, 3, Py_NEW);
+ }else if(PointObject_Check(arg2)){
+ pt = (PointObject*)arg2;
+ rot[0] = quat->quat[0]*quat->quat[0]*pt->coord[0] + 2*quat->quat[2]*quat->quat[0]*pt->coord[2] -
+ 2*quat->quat[3]*quat->quat[0]*pt->coord[1] + quat->quat[1]*quat->quat[1]*pt->coord[0] +
+ 2*quat->quat[2]*quat->quat[1]*pt->coord[1] + 2*quat->quat[3]*quat->quat[1]*pt->coord[2] -
+ quat->quat[3]*quat->quat[3]*pt->coord[0] - quat->quat[2]*quat->quat[2]*pt->coord[0];
+ rot[1] = 2*quat->quat[1]*quat->quat[2]*pt->coord[0] + quat->quat[2]*quat->quat[2]*pt->coord[1] +
+ 2*quat->quat[3]*quat->quat[2]*pt->coord[2] + 2*quat->quat[0]*quat->quat[3]*pt->coord[0] -
+ quat->quat[3]*quat->quat[3]*pt->coord[1] + quat->quat[0]*quat->quat[0]*pt->coord[1] -
+ 2*quat->quat[1]*quat->quat[0]*pt->coord[2] - quat->quat[1]*quat->quat[1]*pt->coord[1];
+ rot[2] = 2*quat->quat[1]*quat->quat[3]*pt->coord[0] + 2*quat->quat[2]*quat->quat[3]*pt->coord[1] +
+ quat->quat[3]*quat->quat[3]*pt->coord[2] - 2*quat->quat[0]*quat->quat[2]*pt->coord[0] -
+ quat->quat[2]*quat->quat[2]*pt->coord[2] + 2*quat->quat[0]*quat->quat[1]*pt->coord[1] -
+ quat->quat[1]*quat->quat[1]*pt->coord[2] + quat->quat[0]*quat->quat[0]*pt->coord[2];
+ return newPointObject(rot, 3, Py_NEW);
+ }
+ }else if(VectorObject_Check(arg1)){
+ vec = (VectorObject*)arg1;
+ if(QuaternionObject_Check(arg2)){
+ quat = (QuaternionObject*)arg2;
+ rot[0] = quat->quat[0]*quat->quat[0]*vec->vec[0] + 2*quat->quat[2]*quat->quat[0]*vec->vec[2] -
+ 2*quat->quat[3]*quat->quat[0]*vec->vec[1] + quat->quat[1]*quat->quat[1]*vec->vec[0] +
+ 2*quat->quat[2]*quat->quat[1]*vec->vec[1] + 2*quat->quat[3]*quat->quat[1]*vec->vec[2] -
+ quat->quat[3]*quat->quat[3]*vec->vec[0] - quat->quat[2]*quat->quat[2]*vec->vec[0];
+ rot[1] = 2*quat->quat[1]*quat->quat[2]*vec->vec[0] + quat->quat[2]*quat->quat[2]*vec->vec[1] +
+ 2*quat->quat[3]*quat->quat[2]*vec->vec[2] + 2*quat->quat[0]*quat->quat[3]*vec->vec[0] -
+ quat->quat[3]*quat->quat[3]*vec->vec[1] + quat->quat[0]*quat->quat[0]*vec->vec[1] -
+ 2*quat->quat[1]*quat->quat[0]*vec->vec[2] - quat->quat[1]*quat->quat[1]*vec->vec[1];
+ rot[2] = 2*quat->quat[1]*quat->quat[3]*vec->vec[0] + 2*quat->quat[2]*quat->quat[3]*vec->vec[1] +
+ quat->quat[3]*quat->quat[3]*vec->vec[2] - 2*quat->quat[0]*quat->quat[2]*vec->vec[0] -
+ quat->quat[2]*quat->quat[2]*vec->vec[2] + 2*quat->quat[0]*quat->quat[1]*vec->vec[1] -
+ quat->quat[1]*quat->quat[1]*vec->vec[2] + quat->quat[0]*quat->quat[0]*vec->vec[2];
+ return newVectorObject(rot, 3, Py_NEW);
+ }
+ }else if(PointObject_Check(arg1)){
+ pt = (PointObject*)arg1;
+ if(QuaternionObject_Check(arg2)){
+ quat = (QuaternionObject*)arg2;
+ rot[0] = quat->quat[0]*quat->quat[0]*pt->coord[0] + 2*quat->quat[2]*quat->quat[0]*pt->coord[2] -
+ 2*quat->quat[3]*quat->quat[0]*pt->coord[1] + quat->quat[1]*quat->quat[1]*pt->coord[0] +
+ 2*quat->quat[2]*quat->quat[1]*pt->coord[1] + 2*quat->quat[3]*quat->quat[1]*pt->coord[2] -
+ quat->quat[3]*quat->quat[3]*pt->coord[0] - quat->quat[2]*quat->quat[2]*pt->coord[0];
+ rot[1] = 2*quat->quat[1]*quat->quat[2]*pt->coord[0] + quat->quat[2]*quat->quat[2]*pt->coord[1] +
+ 2*quat->quat[3]*quat->quat[2]*pt->coord[2] + 2*quat->quat[0]*quat->quat[3]*pt->coord[0] -
+ quat->quat[3]*quat->quat[3]*pt->coord[1] + quat->quat[0]*quat->quat[0]*pt->coord[1] -
+ 2*quat->quat[1]*quat->quat[0]*pt->coord[2] - quat->quat[1]*quat->quat[1]*pt->coord[1];
+ rot[2] = 2*quat->quat[1]*quat->quat[3]*pt->coord[0] + 2*quat->quat[2]*quat->quat[3]*pt->coord[1] +
+ quat->quat[3]*quat->quat[3]*pt->coord[2] - 2*quat->quat[0]*quat->quat[2]*pt->coord[0] -
+ quat->quat[2]*quat->quat[2]*pt->coord[2] + 2*quat->quat[0]*quat->quat[1]*pt->coord[1] -
+ quat->quat[1]*quat->quat[1]*pt->coord[2] + quat->quat[0]*quat->quat[0]*pt->coord[2];
+ return newPointObject(rot, 3, Py_NEW);
+ }
+ }
+
+ return (EXPP_ReturnPyObjError(PyExc_RuntimeError,
+ "quat_rotation(internal): internal problem rotating vector/point\n"));
+}
+
+//----------------------------------Mathutils.Rand() --------------------
+//returns a random number between a high and low value
+PyObject *M_Mathutils_Rand(PyObject * self, PyObject * args)
+{
+ float high, low, range;
+ double rand;
+ //initializers
+ high = 1.0;
+ low = 0.0;
+
+ if(!PyArg_ParseTuple(args, "|ff", &low, &high))
+ return (EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Mathutils.Rand(): expected nothing or optional (float, float)\n"));
+
+ if((high < low) || (high < 0 && low > 0))
+ return (EXPP_ReturnPyObjError(PyExc_ValueError,
+ "Mathutils.Rand(): high value should be larger than low value\n"));
+
+ //get the random number 0 - 1
+ rand = BLI_drand();
+
+ //set it to range
+ range = high - low;
+ rand = rand * range;
+ rand = rand + low;
+
+ return PyFloat_FromDouble(rand);
+}
+//----------------------------------VECTOR FUNCTIONS---------------------
+//----------------------------------Mathutils.Vector() ------------------
+// Supports 2D, 3D, and 4D vector objects both int and float values
+// accepted. Mixed float and int values accepted. Ints are parsed to float
+PyObject *M_Mathutils_Vector(PyObject * self, PyObject * args)
+{
+ PyObject *listObject = NULL;
+ int size, i;
+ float vec[4];
+ PyObject *v, *f;
+
+ size = PySequence_Length(args);
+ if (size == 1) {
+ listObject = PySequence_GetItem(args, 0);
+ if (PySequence_Check(listObject)) {
+ size = PySequence_Length(listObject);
+ } else { // Single argument was not a sequence
+ Py_XDECREF(listObject);
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Mathutils.Vector(): 2-4 floats or ints expected (optionally in a sequence)\n");
+ }
+ } else if (size == 0) {
+ //returns a new empty 3d vector
+ return newVectorObject(NULL, 3, Py_NEW);
+ } else {
+ listObject = EXPP_incr_ret(args);
+ }
+
+ if (size<2 || size>4) { // Invalid vector size
+ Py_XDECREF(listObject);
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Mathutils.Vector(): 2-4 floats or ints expected (optionally in a sequence)\n");
+ }
+
+ for (i=0; i<size; i++) {
+ v=PySequence_GetItem(listObject, i);
+ if (v==NULL) { // Failed to read sequence
+ Py_XDECREF(listObject);
+ return EXPP_ReturnPyObjError(PyExc_RuntimeError,
+ "Mathutils.Vector(): 2-4 floats or ints expected (optionally in a sequence)\n");
+ }
+
+ f=PyNumber_Float(v);
+ if(f==NULL) { // parsed item not a number
+ Py_DECREF(v);
+ Py_XDECREF(listObject);
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Mathutils.Vector(): 2-4 floats or ints expected (optionally in a sequence)\n");
+ }
+
+ vec[i]=(float)PyFloat_AS_DOUBLE(f);
+ EXPP_decr2(f,v);
+ }
+ Py_DECREF(listObject);
+ return newVectorObject(vec, size, Py_NEW);
+}
+//----------------------------------Mathutils.CrossVecs() ---------------
+//finds perpendicular vector - only 3D is supported
+PyObject *M_Mathutils_CrossVecs(PyObject * self, PyObject * args)
+{
+ PyObject *vecCross = NULL;
+ VectorObject *vec1 = NULL, *vec2 = NULL;
+
+ if(!PyArg_ParseTuple(args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2))
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Mathutils.CrossVecs(): expects (2) 3D vector objects\n");
+ if(vec1->size != 3 || vec2->size != 3)
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Mathutils.CrossVecs(): expects (2) 3D vector objects\n");
+
+ vecCross = newVectorObject(NULL, 3, Py_NEW);
+ Crossf(((VectorObject*)vecCross)->vec, vec1->vec, vec2->vec);
+ return vecCross;
+}
+//----------------------------------Mathutils.DotVec() -------------------
+//calculates the dot product of two vectors
+PyObject *M_Mathutils_DotVecs(PyObject * self, PyObject * args)
+{
+ VectorObject *vec1 = NULL, *vec2 = NULL;
+ double dot = 0.0f;
+ int x;
+
+ if(!PyArg_ParseTuple(args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2))
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Mathutils.DotVecs(): expects (2) vector objects of the same size\n");
+ if(vec1->size != vec2->size)
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Mathutils.DotVecs(): expects (2) vector objects of the same size\n");
+
+ for(x = 0; x < vec1->size; x++) {
+ dot += vec1->vec[x] * vec2->vec[x];
+ }
+ return PyFloat_FromDouble(dot);
+}
+//----------------------------------Mathutils.AngleBetweenVecs() ---------
+//calculates the angle between 2 vectors
+PyObject *M_Mathutils_AngleBetweenVecs(PyObject * self, PyObject * args)
+{
+ VectorObject *vec1 = NULL, *vec2 = NULL;
+ double dot = 0.0f, angleRads, test_v1 = 0.0f, test_v2 = 0.0f;
+ int x, size;
+
+ if(!PyArg_ParseTuple(args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2))
+ goto AttributeError1; //not vectors
+ if(vec1->size != vec2->size)
+ goto AttributeError1; //bad sizes
+
+ //since size is the same....
+ size = vec1->size;
+
+ for(x = 0; x < size; x++) {
+ test_v1 += vec1->vec[x] * vec1->vec[x];
+ test_v2 += vec2->vec[x] * vec2->vec[x];
+ }
+ if (!test_v1 || !test_v2){
+ goto AttributeError2; //zero-length vector
+ }
+
+ //dot product
+ for(x = 0; x < size; x++) {
+ dot += vec1->vec[x] * vec2->vec[x];
+ }
+ dot /= (sqrt(test_v1) * sqrt(test_v2));
+
+ if (dot < -1.0f || dot > 1.0f) {
+ CLAMP(dot,-1.0f,1.0f);
+ }
+ angleRads = (double)acos(dot);
+
+ return PyFloat_FromDouble(angleRads * (180/ Py_PI));
+
+AttributeError1:
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Mathutils.AngleBetweenVecs(): expects (2) VECTOR objects of the same size\n");
+
+AttributeError2:
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Mathutils.AngleBetweenVecs(): zero length vectors are not acceptable arguments\n");
+}
+//----------------------------------Mathutils.MidpointVecs() -------------
+//calculates the midpoint between 2 vectors
+PyObject *M_Mathutils_MidpointVecs(PyObject * self, PyObject * args)
+{
+ VectorObject *vec1 = NULL, *vec2 = NULL;
+ float vec[4];
+ int x;
+
+ if(!PyArg_ParseTuple(args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2))
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Mathutils.MidpointVecs(): expects (2) vector objects of the same size\n");
+ if(vec1->size != vec2->size)
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Mathutils.MidpointVecs(): expects (2) vector objects of the same size\n");
+
+ for(x = 0; x < vec1->size; x++) {
+ vec[x] = 0.5f * (vec1->vec[x] + vec2->vec[x]);
+ }
+ return newVectorObject(vec, vec1->size, Py_NEW);
+}
+//----------------------------------Mathutils.ProjectVecs() -------------
+//projects vector 1 onto vector 2
+PyObject *M_Mathutils_ProjectVecs(PyObject * self, PyObject * args)
+{
+ VectorObject *vec1 = NULL, *vec2 = NULL;
+ float vec[4];
+ double dot = 0.0f, dot2 = 0.0f;
+ int x, size;
+
+ if(!PyArg_ParseTuple(args, "O!O!", &vector_Type, &vec1, &vector_Type, &vec2))
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Mathutils.ProjectVecs(): expects (2) vector objects of the same size\n");
+ if(vec1->size != vec2->size)
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Mathutils.ProjectVecs(): expects (2) vector objects of the same size\n");
+
+ //since they are the same size...
+ size = vec1->size;
+
+ //get dot products
+ for(x = 0; x < size; x++) {
+ dot += vec1->vec[x] * vec2->vec[x];
+ dot2 += vec2->vec[x] * vec2->vec[x];
+ }
+ //projection
+ dot /= dot2;
+ for(x = 0; x < size; x++) {
+ vec[x] = (float)(dot * vec2->vec[x]);
+ }
+ return newVectorObject(vec, size, Py_NEW);
+}
+//----------------------------------MATRIX FUNCTIONS--------------------
+//----------------------------------Mathutils.Matrix() -----------------
+//mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc.
+//create a new matrix type
+PyObject *M_Mathutils_Matrix(PyObject * self, PyObject * args)
+{
+ PyObject *listObject = NULL;
+ PyObject *argObject, *m, *s, *f;
+ MatrixObject *mat;
+ int argSize, seqSize = 0, i, j;
+ float matrix[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
+
+ argSize = PySequence_Length(args);
+ if(argSize > 4){ //bad arg nums
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Mathutils.Matrix(): expects 0-4 numeric sequences of the same size\n");
+ } else if (argSize == 0) { //return empty 4D matrix
+ return (PyObject *) newMatrixObject(NULL, 4, 4, Py_NEW);
+ }else if (argSize == 1){
+ //copy constructor for matrix objects
+ argObject = PySequence_GetItem(args, 0);
+ if(MatrixObject_Check(argObject)){
+ mat = (MatrixObject*)argObject;
+
+ argSize = mat->rowSize; //rows
+ seqSize = mat->colSize; //col
+ for(i = 0; i < (seqSize * argSize); i++){
+ matrix[i] = mat->contigPtr[i];
+ }
+ }
+ Py_DECREF(argObject);
+ }else{ //2-4 arguments (all seqs? all same size?)
+ for(i =0; i < argSize; i++){
+ argObject = PySequence_GetItem(args, i);
+ if (PySequence_Check(argObject)) { //seq?
+ if(seqSize){ //0 at first
+ if(PySequence_Length(argObject) != seqSize){ //seq size not same
+ Py_DECREF(argObject);
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Mathutils.Matrix(): expects 0-4 numeric sequences of the same size\n");
+ }
+ }
+ seqSize = PySequence_Length(argObject);
+ }else{ //arg not a sequence
+ Py_XDECREF(argObject);
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Mathutils.Matrix(): expects 0-4 numeric sequences of the same size\n");
+ }
+ Py_DECREF(argObject);
+ }
+ //all is well... let's continue parsing
+ listObject = args;
+ for (i = 0; i < argSize; i++){
+ m = PySequence_GetItem(listObject, i);
+ if (m == NULL) { // Failed to read sequence
+ return EXPP_ReturnPyObjError(PyExc_RuntimeError,
+ "Mathutils.Matrix(): failed to parse arguments...\n");
+ }
+
+ for (j = 0; j < seqSize; j++) {
+ s = PySequence_GetItem(m, j);
+ if (s == NULL) { // Failed to read sequence
+ Py_DECREF(m);
+ return EXPP_ReturnPyObjError(PyExc_RuntimeError,
+ "Mathutils.Matrix(): failed to parse arguments...\n");
+ }
+
+ f = PyNumber_Float(s);
+ if(f == NULL) { // parsed item is not a number
+ EXPP_decr2(m,s);
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Mathutils.Matrix(): expects 0-4 numeric sequences of the same size\n");
+ }
+
+ matrix[(seqSize*i)+j]=(float)PyFloat_AS_DOUBLE(f);
+ EXPP_decr2(f,s);
+ }
+ Py_DECREF(m);
+ }
+ }
+ return newMatrixObject(matrix, argSize, seqSize, Py_NEW);
+}
+//----------------------------------Mathutils.RotationMatrix() ----------
+//mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc.
+//creates a rotation matrix
+PyObject *M_Mathutils_RotationMatrix(PyObject * self, PyObject * args)
+{
+ VectorObject *vec = NULL;
+ char *axis = NULL;
+ int matSize;
+ float angle = 0.0f, norm = 0.0f, cosAngle = 0.0f, sinAngle = 0.0f;
+ float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
+
+ if(!PyArg_ParseTuple
+ (args, "fi|sO!", &angle, &matSize, &axis, &vector_Type, &vec)) {
+ return EXPP_ReturnPyObjError (PyExc_TypeError,
+ "Mathutils.RotationMatrix(): expected float int and optional string and vector\n");
+ }
+
+ /* Clamp to -360:360 */
+ while (angle<-360.0f)
+ angle+=360.0;
+ while (angle>360.0f)
+ angle-=360.0;
+
+ if(matSize != 2 && matSize != 3 && matSize != 4)
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Mathutils.RotationMatrix(): can only return a 2x2 3x3 or 4x4 matrix\n");
+ if(matSize == 2 && (axis != NULL || vec != NULL))
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Mathutils.RotationMatrix(): cannot create a 2x2 rotation matrix around arbitrary axis\n");
+ if((matSize == 3 || matSize == 4) && axis == NULL)
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Mathutils.RotationMatrix(): please choose an axis of rotation for 3d and 4d matrices\n");
+ if(axis) {
+ if(((strcmp(axis, "r") == 0) ||
+ (strcmp(axis, "R") == 0)) && vec == NULL)
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Mathutils.RotationMatrix(): please define the arbitrary axis of rotation\n");
+ }
+ if(vec) {
+ if(vec->size != 3)
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Mathutils.RotationMatrix(): the arbitrary axis must be a 3D vector\n");
+ }
+ //convert to radians
+ angle = angle * (float) (Py_PI / 180);
+ if(axis == NULL && matSize == 2) {
+ //2D rotation matrix
+ mat[0] = (float) cos (angle);
+ mat[1] = (float) sin (angle);
+ mat[2] = -((float) sin(angle));
+ mat[3] = (float) cos(angle);
+ } else if((strcmp(axis, "x") == 0) || (strcmp(axis, "X") == 0)) {
+ //rotation around X
+ mat[0] = 1.0f;
+ mat[4] = (float) cos(angle);
+ mat[5] = (float) sin(angle);
+ mat[7] = -((float) sin(angle));
+ mat[8] = (float) cos(angle);
+ } else if((strcmp(axis, "y") == 0) || (strcmp(axis, "Y") == 0)) {
+ //rotation around Y
+ mat[0] = (float) cos(angle);
+ mat[2] = -((float) sin(angle));
+ mat[4] = 1.0f;
+ mat[6] = (float) sin(angle);
+ mat[8] = (float) cos(angle);
+ } else if((strcmp(axis, "z") == 0) || (strcmp(axis, "Z") == 0)) {
+ //rotation around Z
+ mat[0] = (float) cos(angle);
+ mat[1] = (float) sin(angle);
+ mat[3] = -((float) sin(angle));
+ mat[4] = (float) cos(angle);
+ mat[8] = 1.0f;
+ } else if((strcmp(axis, "r") == 0) || (strcmp(axis, "R") == 0)) {
+ //arbitrary rotation
+ //normalize arbitrary axis
+ norm = (float) sqrt(vec->vec[0] * vec->vec[0] +
+ vec->vec[1] * vec->vec[1] +
+ vec->vec[2] * vec->vec[2]);
+ vec->vec[0] /= norm;
+ vec->vec[1] /= norm;
+ vec->vec[2] /= norm;
+
+ //create matrix
+ cosAngle = (float) cos(angle);
+ sinAngle = (float) sin(angle);
+ mat[0] = ((vec->vec[0] * vec->vec[0]) * (1 - cosAngle)) +
+ cosAngle;
+ mat[1] = ((vec->vec[0] * vec->vec[1]) * (1 - cosAngle)) +
+ (vec->vec[2] * sinAngle);
+ mat[2] = ((vec->vec[0] * vec->vec[2]) * (1 - cosAngle)) -
+ (vec->vec[1] * sinAngle);
+ mat[3] = ((vec->vec[0] * vec->vec[1]) * (1 - cosAngle)) -
+ (vec->vec[2] * sinAngle);
+ mat[4] = ((vec->vec[1] * vec->vec[1]) * (1 - cosAngle)) +
+ cosAngle;
+ mat[5] = ((vec->vec[1] * vec->vec[2]) * (1 - cosAngle)) +
+ (vec->vec[0] * sinAngle);
+ mat[6] = ((vec->vec[0] * vec->vec[2]) * (1 - cosAngle)) +
+ (vec->vec[1] * sinAngle);
+ mat[7] = ((vec->vec[1] * vec->vec[2]) * (1 - cosAngle)) -
+ (vec->vec[0] * sinAngle);
+ mat[8] = ((vec->vec[2] * vec->vec[2]) * (1 - cosAngle)) +
+ cosAngle;
+ } else {
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Mathutils.RotationMatrix(): unrecognizable axis of rotation type - expected x,y,z or r\n");
+ }
+ if(matSize == 4) {
+ //resize matrix
+ mat[10] = mat[8];
+ mat[9] = mat[7];
+ mat[8] = mat[6];
+ mat[7] = 0.0f;
+ mat[6] = mat[5];
+ mat[5] = mat[4];
+ mat[4] = mat[3];
+ mat[3] = 0.0f;
+ }
+ //pass to matrix creation
+ return newMatrixObject(mat, matSize, matSize, Py_NEW);
+}
+//----------------------------------Mathutils.TranslationMatrix() -------
+//creates a translation matrix
+PyObject *M_Mathutils_TranslationMatrix(PyObject * self, VectorObject * vec)
+{
+ float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
+
+ if(!VectorObject_Check(vec)) {
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Mathutils.TranslationMatrix(): expected vector\n");
+ }
+ if(vec->size != 3 && vec->size != 4) {
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Mathutils.TranslationMatrix(): vector must be 3D or 4D\n");
+ }
+ //create a identity matrix and add translation
+ Mat4One((float(*)[4]) mat);
+ mat[12] = vec->vec[0];
+ mat[13] = vec->vec[1];
+ mat[14] = vec->vec[2];
+
+ return newMatrixObject(mat, 4, 4, Py_NEW);
+}
+//----------------------------------Mathutils.ScaleMatrix() -------------
+//mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc.
+//creates a scaling matrix
+PyObject *M_Mathutils_ScaleMatrix(PyObject * self, PyObject * args)
+{
+ VectorObject *vec = NULL;
+ float norm = 0.0f, factor;
+ int matSize, x;
+ float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
+
+ if(!PyArg_ParseTuple
+ (args, "fi|O!", &factor, &matSize, &vector_Type, &vec)) {
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Mathutils.ScaleMatrix(): expected float int and optional vector\n");
+ }
+ if(matSize != 2 && matSize != 3 && matSize != 4)
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Mathutils.ScaleMatrix(): can only return a 2x2 3x3 or 4x4 matrix\n");
+ if(vec) {
+ if(vec->size > 2 && matSize == 2)
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Mathutils.ScaleMatrix(): please use 2D vectors when scaling in 2D\n");
+ }
+ if(vec == NULL) { //scaling along axis
+ if(matSize == 2) {
+ mat[0] = factor;
+ mat[3] = factor;
+ } else {
+ mat[0] = factor;
+ mat[4] = factor;
+ mat[8] = factor;
+ }
+ } else { //scaling in arbitrary direction
+ //normalize arbitrary axis
+ for(x = 0; x < vec->size; x++) {
+ norm += vec->vec[x] * vec->vec[x];
+ }
+ norm = (float) sqrt(norm);
+ for(x = 0; x < vec->size; x++) {
+ vec->vec[x] /= norm;
+ }
+ if(matSize == 2) {
+ mat[0] = 1 +((factor - 1) *(vec->vec[0] * vec->vec[0]));
+ mat[1] =((factor - 1) *(vec->vec[0] * vec->vec[1]));
+ mat[2] =((factor - 1) *(vec->vec[0] * vec->vec[1]));
+ mat[3] = 1 + ((factor - 1) *(vec->vec[1] * vec->vec[1]));
+ } else {
+ mat[0] = 1 + ((factor - 1) *(vec->vec[0] * vec->vec[0]));
+ mat[1] =((factor - 1) *(vec->vec[0] * vec->vec[1]));
+ mat[2] =((factor - 1) *(vec->vec[0] * vec->vec[2]));
+ mat[3] =((factor - 1) *(vec->vec[0] * vec->vec[1]));
+ mat[4] = 1 + ((factor - 1) *(vec->vec[1] * vec->vec[1]));
+ mat[5] =((factor - 1) *(vec->vec[1] * vec->vec[2]));
+ mat[6] =((factor - 1) *(vec->vec[0] * vec->vec[2]));
+ mat[7] =((factor - 1) *(vec->vec[1] * vec->vec[2]));
+ mat[8] = 1 + ((factor - 1) *(vec->vec[2] * vec->vec[2]));
+ }
+ }
+ if(matSize == 4) {
+ //resize matrix
+ mat[10] = mat[8];
+ mat[9] = mat[7];
+ mat[8] = mat[6];
+ mat[7] = 0.0f;
+ mat[6] = mat[5];
+ mat[5] = mat[4];
+ mat[4] = mat[3];
+ mat[3] = 0.0f;
+ }
+ //pass to matrix creation
+ return newMatrixObject(mat, matSize, matSize, Py_NEW);
+}
+//----------------------------------Mathutils.OrthoProjectionMatrix() ---
+//mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc.
+//creates an ortho projection matrix
+PyObject *M_Mathutils_OrthoProjectionMatrix(PyObject * self, PyObject * args)
+{
+ VectorObject *vec = NULL;
+ char *plane;
+ int matSize, x;
+ float norm = 0.0f;
+ float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
+
+ if(!PyArg_ParseTuple
+ (args, "si|O!", &plane, &matSize, &vector_Type, &vec)) {
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Mathutils.OrthoProjectionMatrix(): expected string and int and optional vector\n");
+ }
+ if(matSize != 2 && matSize != 3 && matSize != 4)
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Mathutils.OrthoProjectionMatrix(): can only return a 2x2 3x3 or 4x4 matrix\n");
+ if(vec) {
+ if(vec->size > 2 && matSize == 2)
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Mathutils.OrthoProjectionMatrix(): please use 2D vectors when scaling in 2D\n");
+ }
+ if(vec == NULL) { //ortho projection onto cardinal plane
+ if(((strcmp(plane, "x") == 0)
+ || (strcmp(plane, "X") == 0)) && matSize == 2) {
+ mat[0] = 1.0f;
+ } else if(((strcmp(plane, "y") == 0)
+ || (strcmp(plane, "Y") == 0))
+ && matSize == 2) {
+ mat[3] = 1.0f;
+ } else if(((strcmp(plane, "xy") == 0)
+ || (strcmp(plane, "XY") == 0))
+ && matSize > 2) {
+ mat[0] = 1.0f;
+ mat[4] = 1.0f;
+ } else if(((strcmp(plane, "xz") == 0)
+ || (strcmp(plane, "XZ") == 0))
+ && matSize > 2) {
+ mat[0] = 1.0f;
+ mat[8] = 1.0f;
+ } else if(((strcmp(plane, "yz") == 0)
+ || (strcmp(plane, "YZ") == 0))
+ && matSize > 2) {
+ mat[4] = 1.0f;
+ mat[8] = 1.0f;
+ } else {
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Mathutils.OrthoProjectionMatrix(): unknown plane - expected: x, y, xy, xz, yz\n");
+ }
+ } else { //arbitrary plane
+ //normalize arbitrary axis
+ for(x = 0; x < vec->size; x++) {
+ norm += vec->vec[x] * vec->vec[x];
+ }
+ norm = (float) sqrt(norm);
+ for(x = 0; x < vec->size; x++) {
+ vec->vec[x] /= norm;
+ }
+ if(((strcmp(plane, "r") == 0)
+ || (strcmp(plane, "R") == 0)) && matSize == 2) {
+ mat[0] = 1 - (vec->vec[0] * vec->vec[0]);
+ mat[1] = -(vec->vec[0] * vec->vec[1]);
+ mat[2] = -(vec->vec[0] * vec->vec[1]);
+ mat[3] = 1 - (vec->vec[1] * vec->vec[1]);
+ } else if(((strcmp(plane, "r") == 0)
+ || (strcmp(plane, "R") == 0))
+ && matSize > 2) {
+ mat[0] = 1 - (vec->vec[0] * vec->vec[0]);
+ mat[1] = -(vec->vec[0] * vec->vec[1]);
+ mat[2] = -(vec->vec[0] * vec->vec[2]);
+ mat[3] = -(vec->vec[0] * vec->vec[1]);
+ mat[4] = 1 - (vec->vec[1] * vec->vec[1]);
+ mat[5] = -(vec->vec[1] * vec->vec[2]);
+ mat[6] = -(vec->vec[0] * vec->vec[2]);
+ mat[7] = -(vec->vec[1] * vec->vec[2]);
+ mat[8] = 1 - (vec->vec[2] * vec->vec[2]);
+ } else {
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Mathutils.OrthoProjectionMatrix(): unknown plane - expected: 'r' expected for axis designation\n");
+ }
+ }
+ if(matSize == 4) {
+ //resize matrix
+ mat[10] = mat[8];
+ mat[9] = mat[7];
+ mat[8] = mat[6];
+ mat[7] = 0.0f;
+ mat[6] = mat[5];
+ mat[5] = mat[4];
+ mat[4] = mat[3];
+ mat[3] = 0.0f;
+ }
+ //pass to matrix creation
+ return newMatrixObject(mat, matSize, matSize, Py_NEW);
+}
+//----------------------------------Mathutils.ShearMatrix() -------------
+//creates a shear matrix
+PyObject *M_Mathutils_ShearMatrix(PyObject * self, PyObject * args)
+{
+ int matSize;
+ char *plane;
+ float factor;
+ float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
+
+ if(!PyArg_ParseTuple(args, "sfi", &plane, &factor, &matSize)) {
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Mathutils.ShearMatrix(): expected string float and int\n");
+ }
+ if(matSize != 2 && matSize != 3 && matSize != 4)
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Mathutils.ShearMatrix(): can only return a 2x2 3x3 or 4x4 matrix\n");
+
+ if(((strcmp(plane, "x") == 0) || (strcmp(plane, "X") == 0))
+ && matSize == 2) {
+ mat[0] = 1.0f;
+ mat[2] = factor;
+ mat[3] = 1.0f;
+ } else if(((strcmp(plane, "y") == 0)
+ || (strcmp(plane, "Y") == 0)) && matSize == 2) {
+ mat[0] = 1.0f;
+ mat[1] = factor;
+ mat[3] = 1.0f;
+ } else if(((strcmp(plane, "xy") == 0)
+ || (strcmp(plane, "XY") == 0)) && matSize > 2) {
+ mat[0] = 1.0f;
+ mat[4] = 1.0f;
+ mat[6] = factor;
+ mat[7] = factor;
+ } else if(((strcmp(plane, "xz") == 0)
+ || (strcmp(plane, "XZ") == 0)) && matSize > 2) {
+ mat[0] = 1.0f;
+ mat[3] = factor;
+ mat[4] = 1.0f;
+ mat[5] = factor;
+ mat[8] = 1.0f;
+ } else if(((strcmp(plane, "yz") == 0)
+ || (strcmp(plane, "YZ") == 0)) && matSize > 2) {
+ mat[0] = 1.0f;
+ mat[1] = factor;
+ mat[2] = factor;
+ mat[4] = 1.0f;
+ mat[8] = 1.0f;
+ } else {
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Mathutils.ShearMatrix(): expected: x, y, xy, xz, yz or wrong matrix size for shearing plane\n");
+ }
+ if(matSize == 4) {
+ //resize matrix
+ mat[10] = mat[8];
+ mat[9] = mat[7];
+ mat[8] = mat[6];
+ mat[7] = 0.0f;
+ mat[6] = mat[5];
+ mat[5] = mat[4];
+ mat[4] = mat[3];
+ mat[3] = 0.0f;
+ }
+ //pass to matrix creation
+ return newMatrixObject(mat, matSize, matSize, Py_NEW);
+}
+//----------------------------------QUATERNION FUNCTIONS-----------------
+//----------------------------------Mathutils.Quaternion() --------------
+PyObject *M_Mathutils_Quaternion(PyObject * self, PyObject * args)
+{
+ PyObject *listObject = NULL, *n, *q, *f;
+ int size, i;
+ float quat[4];
+ double norm = 0.0f, angle = 0.0f;
+
+ size = PySequence_Length(args);
+ if (size == 1 || size == 2) { //seq?
+ listObject = PySequence_GetItem(args, 0);
+ if (PySequence_Check(listObject)) {
+ size = PySequence_Length(listObject);
+ if ((size == 4 && PySequence_Length(args) !=1) ||
+ (size == 3 && PySequence_Length(args) !=2) || (size >4 || size < 3)) {
+ // invalid args/size
+ Py_DECREF(listObject);
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
+ }
+ if(size == 3){ //get angle in axis/angle
+ n = PyNumber_Float(PySequence_GetItem(args, 1));
+ if(n == NULL) { // parsed item not a number or getItem fail
+ Py_DECREF(listObject);
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
+ }
+ angle = PyFloat_AS_DOUBLE(n);
+ Py_DECREF(n);
+ }
+ }else{
+ listObject = PySequence_GetItem(args, 1);
+ if (size>1 && PySequence_Check(listObject)) {
+ size = PySequence_Length(listObject);
+ if (size != 3) {
+ // invalid args/size
+ Py_DECREF(listObject);
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
+ }
+ n = PyNumber_Float(PySequence_GetItem(args, 0));
+ if(n == NULL) { // parsed item not a number or getItem fail
+ Py_DECREF(listObject);
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
+ }
+ angle = PyFloat_AS_DOUBLE(n);
+ Py_DECREF(n);
+ } else { // argument was not a sequence
+ Py_XDECREF(listObject);
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
+ }
+ }
+ } else if (size == 0) { //returns a new empty quat
+ return newQuaternionObject(NULL, Py_NEW);
+ } else {
+ listObject = EXPP_incr_ret(args);
+ }
+
+ if (size == 3) { // invalid quat size
+ if(PySequence_Length(args) != 2){
+ Py_DECREF(listObject);
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
+ }
+ }else{
+ if(size != 4){
+ Py_DECREF(listObject);
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
+ }
+ }
+
+ for (i=0; i<size; i++) { //parse
+ q = PySequence_GetItem(listObject, i);
+ if (q == NULL) { // Failed to read sequence
+ Py_DECREF(listObject);
+ return EXPP_ReturnPyObjError(PyExc_RuntimeError,
+ "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
+ }
+
+ f = PyNumber_Float(q);
+ if(f == NULL) { // parsed item not a number
+ EXPP_decr2(q, listObject);
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Mathutils.Quaternion(): 4d numeric sequence expected or 3d vector and number\n");
+ }
+
+ quat[i] = (float)PyFloat_AS_DOUBLE(f);
+ EXPP_decr2(f, q);
+ }
+ if(size == 3){ //calculate the quat based on axis/angle
+ norm = sqrt(quat[0] * quat[0] + quat[1] * quat[1] + quat[2] * quat[2]);
+ quat[0] /= (float)norm;
+ quat[1] /= (float)norm;
+ quat[2] /= (float)norm;
+
+ angle = angle * (Py_PI / 180);
+ quat[3] =(float) (sin(angle/ 2.0f)) * quat[2];
+ quat[2] =(float) (sin(angle/ 2.0f)) * quat[1];
+ quat[1] =(float) (sin(angle/ 2.0f)) * quat[0];
+ quat[0] =(float) (cos(angle/ 2.0f));
+ }
+
+ Py_DECREF(listObject);
+ return newQuaternionObject(quat, Py_NEW);
+}
+//----------------------------------Mathutils.CrossQuats() ----------------
+//quaternion multiplication - associate not commutative
+PyObject *M_Mathutils_CrossQuats(PyObject * self, PyObject * args)
+{
+ QuaternionObject *quatU = NULL, *quatV = NULL;
+ float quat[4];
+
+ if(!PyArg_ParseTuple(args, "O!O!", &quaternion_Type, &quatU,
+ &quaternion_Type, &quatV))
+ return EXPP_ReturnPyObjError(PyExc_TypeError,"Mathutils.CrossQuats(): expected Quaternion types");
+ QuatMul(quat, quatU->quat, quatV->quat);
+
+ return newQuaternionObject(quat, Py_NEW);
+}
+//----------------------------------Mathutils.DotQuats() ----------------
+//returns the dot product of 2 quaternions
+PyObject *M_Mathutils_DotQuats(PyObject * self, PyObject * args)
+{
+ QuaternionObject *quatU = NULL, *quatV = NULL;
+ double dot = 0.0f;
+ int x;
+
+ if(!PyArg_ParseTuple(args, "O!O!", &quaternion_Type, &quatU,
+ &quaternion_Type, &quatV))
+ return EXPP_ReturnPyObjError(PyExc_TypeError, "Mathutils.DotQuats(): expected Quaternion types");
+
+ for(x = 0; x < 4; x++) {
+ dot += quatU->quat[x] * quatV->quat[x];
+ }
+ return PyFloat_FromDouble(dot);
+}
+//----------------------------------Mathutils.DifferenceQuats() ---------
+//returns the difference between 2 quaternions
+PyObject *M_Mathutils_DifferenceQuats(PyObject * self, PyObject * args)
+{
+ QuaternionObject *quatU = NULL, *quatV = NULL;
+ float quat[4], tempQuat[4];
+ double dot = 0.0f;
+ int x;
+
+ if(!PyArg_ParseTuple(args, "O!O!", &quaternion_Type,
+ &quatU, &quaternion_Type, &quatV))
+ return EXPP_ReturnPyObjError(PyExc_TypeError, "Mathutils.DifferenceQuats(): expected Quaternion types");
+
+ tempQuat[0] = quatU->quat[0];
+ tempQuat[1] = -quatU->quat[1];
+ tempQuat[2] = -quatU->quat[2];
+ tempQuat[3] = -quatU->quat[3];
+
+ dot = sqrt(tempQuat[0] * tempQuat[0] + tempQuat[1] * tempQuat[1] +
+ tempQuat[2] * tempQuat[2] + tempQuat[3] * tempQuat[3]);
+
+ for(x = 0; x < 4; x++) {
+ tempQuat[x] /= (float)(dot * dot);
+ }
+ QuatMul(quat, tempQuat, quatV->quat);
+ return newQuaternionObject(quat, Py_NEW);
+}
+//----------------------------------Mathutils.Slerp() ------------------
+//attemps to interpolate 2 quaternions and return the result
+PyObject *M_Mathutils_Slerp(PyObject * self, PyObject * args)
+{
+ QuaternionObject *quatU = NULL, *quatV = NULL;
+ float quat[4], quat_u[4], quat_v[4], param;
+ double x, y, dot, sinT, angle, IsinT;
+ int z;
+
+ if(!PyArg_ParseTuple(args, "O!O!f", &quaternion_Type,
+ &quatU, &quaternion_Type, &quatV, &param))
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Mathutils.Slerp(): expected Quaternion types and float");
+
+ if(param > 1.0f || param < 0.0f)
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Mathutils.Slerp(): interpolation factor must be between 0.0 and 1.0");
+
+ //copy quats
+ for(z = 0; z < 4; z++){
+ quat_u[z] = quatU->quat[z];
+ quat_v[z] = quatV->quat[z];
+ }
+
+ //dot product
+ dot = quat_u[0] * quat_v[0] + quat_u[1] * quat_v[1] +
+ quat_u[2] * quat_v[2] + quat_u[3] * quat_v[3];
+
+ //if negative negate a quat (shortest arc)
+ if(dot < 0.0f) {
+ quat_v[0] = -quat_v[0];
+ quat_v[1] = -quat_v[1];
+ quat_v[2] = -quat_v[2];
+ quat_v[3] = -quat_v[3];
+ dot = -dot;
+ }
+ if(dot > .99999f) { //very close
+ x = 1.0f - param;
+ y = param;
+ } else {
+ //calculate sin of angle
+ sinT = sqrt(1.0f - (dot * dot));
+ //calculate angle
+ angle = atan2(sinT, dot);
+ //caluculate inverse of sin(theta)
+ IsinT = 1.0f / sinT;
+ x = sin((1.0f - param) * angle) * IsinT;
+ y = sin(param * angle) * IsinT;
+ }
+ //interpolate
+ quat[0] = (float)(quat_u[0] * x + quat_v[0] * y);
+ quat[1] = (float)(quat_u[1] * x + quat_v[1] * y);
+ quat[2] = (float)(quat_u[2] * x + quat_v[2] * y);
+ quat[3] = (float)(quat_u[3] * x + quat_v[3] * y);
+
+ return newQuaternionObject(quat, Py_NEW);
+}
+//----------------------------------EULER FUNCTIONS----------------------
+//----------------------------------Mathutils.Euler() -------------------
+//makes a new euler for you to play with
+PyObject *M_Mathutils_Euler(PyObject * self, PyObject * args)
+{
+
+ PyObject *listObject = NULL;
+ int size, i;
+ float eul[3];
+ PyObject *e, *f;
+
+ size = PySequence_Length(args);
+ if (size == 1) {
+ listObject = PySequence_GetItem(args, 0);
+ if (PySequence_Check(listObject)) {
+ size = PySequence_Length(listObject);
+ } else { // Single argument was not a sequence
+ Py_DECREF(listObject);
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Mathutils.Euler(): 3d numeric sequence expected\n");
+ }
+ } else if (size == 0) {
+ //returns a new empty 3d euler
+ return newEulerObject(NULL, Py_NEW);
+ } else {
+ listObject = EXPP_incr_ret(args);
+ }
+
+ if (size != 3) { // Invalid euler size
+ Py_DECREF(listObject);
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Mathutils.Euler(): 3d numeric sequence expected\n");
+ }
+
+ for (i=0; i<size; i++) {
+ e = PySequence_GetItem(listObject, i);
+ if (e == NULL) { // Failed to read sequence
+ Py_DECREF(listObject);
+ return EXPP_ReturnPyObjError(PyExc_RuntimeError,
+ "Mathutils.Euler(): 3d numeric sequence expected\n");
+ }
+
+ f = PyNumber_Float(e);
+ if(f == NULL) { // parsed item not a number
+ EXPP_decr2(e, listObject);
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Mathutils.Euler(): 3d numeric sequence expected\n");
+ }
+
+ eul[i]=(float)PyFloat_AS_DOUBLE(f);
+ EXPP_decr2(f,e);
+ }
+ Py_DECREF(listObject);
+ return newEulerObject(eul, Py_NEW);
+}
+//----------------------------------POINT FUNCTIONS---------------------
+//----------------------------------Mathutils.Point() ------------------
+PyObject *M_Mathutils_Point(PyObject * self, PyObject * args)
+{
+ PyObject *listObject = NULL;
+ int size, i;
+ float point[3];
+ PyObject *v, *f;
+
+ size = PySequence_Length(args);
+ if (size == 1) {
+ listObject = PySequence_GetItem(args, 0);
+ if (PySequence_Check(listObject)) {
+ size = PySequence_Length(listObject);
+ } else { // Single argument was not a sequence
+ Py_XDECREF(listObject);
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Mathutils.Point(): 2-3 floats or ints expected (optionally in a sequence)\n");
+ }
+ } else if (size == 0) {
+ //returns a new empty 3d point
+ return newPointObject(NULL, 3, Py_NEW);
+ } else {
+ listObject = EXPP_incr_ret(args);
+ }
+
+ if (size<2 || size>3) { // Invalid vector size
+ Py_XDECREF(listObject);
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Mathutils.Point(): 2-3 floats or ints expected (optionally in a sequence)\n");
+ }
+
+ for (i=0; i<size; i++) {
+ v=PySequence_GetItem(listObject, i);
+ if (v==NULL) { // Failed to read sequence
+ Py_XDECREF(listObject);
+ return EXPP_ReturnPyObjError(PyExc_RuntimeError,
+ "Mathutils.Point(): 2-3 floats or ints expected (optionally in a sequence)\n");
+ }
+
+ f=PyNumber_Float(v);
+ if(f==NULL) { // parsed item not a number
+ Py_DECREF(v);
+ Py_XDECREF(listObject);
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Mathutils.Point(): 2-3 floats or ints expected (optionally in a sequence)\n");
+ }
+
+ point[i]=(float)PyFloat_AS_DOUBLE(f);
+ EXPP_decr2(f,v);
+ }
+ Py_DECREF(listObject);
+ return newPointObject(point, size, Py_NEW);
+}
+//---------------------------------INTERSECTION FUNCTIONS--------------------
+//----------------------------------Mathutils.Intersect() -------------------
+PyObject *M_Mathutils_Intersect( PyObject * self, PyObject * args )
+{
+ VectorObject *ray, *ray_off, *vec1, *vec2, *vec3;
+ float dir[3], orig[3], v1[3], v2[3], v3[3], e1[3], e2[3], pvec[3], tvec[3], qvec[3];
+ float det, inv_det, u, v, t;
+ int clip = 1;
+
+ if( !PyArg_ParseTuple
+ ( args, "O!O!O!O!O!|i", &vector_Type, &vec1, &vector_Type, &vec2
+ , &vector_Type, &vec3, &vector_Type, &ray, &vector_Type, &ray_off , &clip) )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_TypeError, "expected 5 vector types\n" ) );
+ if( vec1->size != 3 || vec2->size != 3 || vec3->size != 3 ||
+ ray->size != 3 || ray_off->size != 3)
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "only 3D vectors for all parameters\n" ) );
+
+ VECCOPY(v1, vec1->vec);
+ VECCOPY(v2, vec2->vec);
+ VECCOPY(v3, vec3->vec);
+
+ VECCOPY(dir, ray->vec);
+ Normalize(dir);
+
+ VECCOPY(orig, ray_off->vec);
+
+ /* find vectors for two edges sharing v1 */
+ VecSubf(e1, v2, v1);
+ VecSubf(e2, v3, v1);
+
+ /* begin calculating determinant - also used to calculated U parameter */
+ Crossf(pvec, dir, e2);
+
+ /* if determinant is near zero, ray lies in plane of triangle */
+ det = Inpf(e1, pvec);
+
+ if (det > -0.000001 && det < 0.000001) {
+ return EXPP_incr_ret( Py_None );
+ }
+
+ inv_det = 1.0f / det;
+
+ /* calculate distance from v1 to ray origin */
+ VecSubf(tvec, orig, v1);
+
+ /* calculate U parameter and test bounds */
+ u = Inpf(tvec, pvec) * inv_det;
+ if (clip && (u < 0.0f || u > 1.0f)) {
+ return EXPP_incr_ret( Py_None );
+ }
+
+ /* prepare to test the V parameter */
+ Crossf(qvec, tvec, e1);
+
+ /* calculate V parameter and test bounds */
+ v = Inpf(dir, qvec) * inv_det;
+
+ if (clip && (v < 0.0f || u + v > 1.0f)) {
+ return EXPP_incr_ret( Py_None );
+ }
+
+ /* calculate t, ray intersects triangle */
+ t = Inpf(e2, qvec) * inv_det;
+
+ VecMulf(dir, t);
+ VecAddf(pvec, orig, dir);
+
+ return newVectorObject(pvec, 3, Py_NEW);
+}
+//----------------------------------Mathutils.LineIntersect() -------------------
+/* Line-Line intersection using algorithm from mathworld.wolfram.com */
+PyObject *M_Mathutils_LineIntersect( PyObject * self, PyObject * args )
+{
+ PyObject * tuple;
+ VectorObject *vec1, *vec2, *vec3, *vec4;
+ float v1[3], v2[3], v3[3], v4[3], i1[3], i2[3];
+
+ if( !PyArg_ParseTuple
+ ( args, "O!O!O!O!", &vector_Type, &vec1, &vector_Type, &vec2
+ , &vector_Type, &vec3, &vector_Type, &vec4 ) )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_TypeError, "expected 4 vector types\n" ) );
+ if( vec1->size != vec2->size || vec1->size != vec3->size || vec1->size != vec2->size)
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "vectors must be of the same size\n" ) );
+
+ if( vec1->size == 3 || vec1->size == 2) {
+ float a[3], b[3], c[3], ab[3], cb[3], dir1[3], dir2[3];
+ float d;
+ if (vec1->size == 3) {
+ VECCOPY(v1, vec1->vec);
+ VECCOPY(v2, vec2->vec);
+ VECCOPY(v3, vec3->vec);
+ VECCOPY(v4, vec4->vec);
+ }
+ else {
+ v1[0] = vec1->vec[0];
+ v1[1] = vec1->vec[1];
+ v1[2] = 0.0f;
+
+ v2[0] = vec2->vec[0];
+ v2[1] = vec2->vec[1];
+ v2[2] = 0.0f;
+
+ v3[0] = vec3->vec[0];
+ v3[1] = vec3->vec[1];
+ v3[2] = 0.0f;
+
+ v4[0] = vec4->vec[0];
+ v4[1] = vec4->vec[1];
+ v4[2] = 0.0f;
+ }
+
+ VecSubf(c, v3, v1);
+ VecSubf(a, v2, v1);
+ VecSubf(b, v4, v3);
+
+ VECCOPY(dir1, a);
+ Normalize(dir1);
+ VECCOPY(dir2, b);
+ Normalize(dir2);
+ d = Inpf(dir1, dir2);
+ if (d == 1.0f || d == -1.0f) {
+ /* colinear */
+ return EXPP_incr_ret( Py_None );
+ }
+
+ Crossf(ab, a, b);
+ d = Inpf(c, ab);
+
+ /* test if the two lines are coplanar */
+ if (d > -0.000001f && d < 0.000001f) {
+ Crossf(cb, c, b);
+
+ VecMulf(a, Inpf(cb, ab) / Inpf(ab, ab));
+ VecAddf(i1, v1, a);
+ VECCOPY(i2, i1);
+ }
+ /* if not */
+ else {
+ float n[3], t[3];
+ VecSubf(t, v1, v3);
+
+ /* offset between both plane where the lines lies */
+ Crossf(n, a, b);
+ Projf(t, t, n);
+
+ /* for the first line, offset the second line until it is coplanar */
+ VecAddf(v3, v3, t);
+ VecAddf(v4, v4, t);
+
+ VecSubf(c, v3, v1);
+ VecSubf(a, v2, v1);
+ VecSubf(b, v4, v3);
+
+ Crossf(ab, a, b);
+ Crossf(cb, c, b);
+
+ VecMulf(a, Inpf(cb, ab) / Inpf(ab, ab));
+ VecAddf(i1, v1, a);
+
+ /* for the second line, just substract the offset from the first intersection point */
+ VecSubf(i2, i1, t);
+ }
+
+ tuple = PyTuple_New( 2 );
+ PyTuple_SetItem( tuple, 0, newVectorObject(i1, vec1->size, Py_NEW) );
+ PyTuple_SetItem( tuple, 1, newVectorObject(i2, vec1->size, Py_NEW) );
+ return tuple;
+ }
+ else {
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "2D/3D vectors only\n" ) );
+ }
+}
+
+
+
+//---------------------------------NORMALS FUNCTIONS--------------------
+//----------------------------------Mathutils.QuadNormal() -------------------
+PyObject *M_Mathutils_QuadNormal( PyObject * self, PyObject * args )
+{
+ VectorObject *vec1;
+ VectorObject *vec2;
+ VectorObject *vec3;
+ VectorObject *vec4;
+ float v1[3], v2[3], v3[3], v4[3], e1[3], e2[3], n1[3], n2[3];
+
+ if( !PyArg_ParseTuple
+ ( args, "O!O!O!O!", &vector_Type, &vec1, &vector_Type, &vec2
+ , &vector_Type, &vec3, &vector_Type, &vec4 ) )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_TypeError, "expected 4 vector types\n" ) );
+ if( vec1->size != vec2->size || vec1->size != vec3->size || vec1->size != vec4->size)
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "vectors must be of the same size\n" ) );
+ if( vec1->size != 3 )
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "only 3D vectors\n" ) );
+
+ VECCOPY(v1, vec1->vec);
+ VECCOPY(v2, vec2->vec);
+ VECCOPY(v3, vec3->vec);
+ VECCOPY(v4, vec4->vec);
+
+ /* find vectors for two edges sharing v2 */
+ VecSubf(e1, v1, v2);
+ VecSubf(e2, v3, v2);
+
+ Crossf(n1, e2, e1);
+ Normalize(n1);
+
+ /* find vectors for two edges sharing v4 */
+ VecSubf(e1, v3, v4);
+ VecSubf(e2, v1, v4);
+
+ Crossf(n2, e2, e1);
+ Normalize(n2);
+
+ /* adding and averaging the normals of both triangles */
+ VecAddf(n1, n2, n1);
+ Normalize(n1);
+
+ return newVectorObject(n1, 3, Py_NEW);
+}
+
+//----------------------------Mathutils.TriangleNormal() -------------------
+PyObject *M_Mathutils_TriangleNormal( PyObject * self, PyObject * args )
+{
+ VectorObject *vec1, *vec2, *vec3;
+ float v1[3], v2[3], v3[3], e1[3], e2[3], n[3];
+
+ if( !PyArg_ParseTuple
+ ( args, "O!O!O!", &vector_Type, &vec1, &vector_Type, &vec2
+ , &vector_Type, &vec3 ) )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_TypeError, "expected 3 vector types\n" ) );
+ if( vec1->size != vec2->size || vec1->size != vec3->size )
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "vectors must be of the same size\n" ) );
+ if( vec1->size != 3 )
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "only 3D vectors\n" ) );
+
+ VECCOPY(v1, vec1->vec);
+ VECCOPY(v2, vec2->vec);
+ VECCOPY(v3, vec3->vec);
+
+ /* find vectors for two edges sharing v2 */
+ VecSubf(e1, v1, v2);
+ VecSubf(e2, v3, v2);
+
+ Crossf(n, e2, e1);
+ Normalize(n);
+
+ return newVectorObject(n, 3, Py_NEW);
+}
+
+//--------------------------------- AREA FUNCTIONS--------------------
+//----------------------------------Mathutils.TriangleArea() -------------------
+PyObject *M_Mathutils_TriangleArea( PyObject * self, PyObject * args )
+{
+ VectorObject *vec1, *vec2, *vec3;
+ float v1[3], v2[3], v3[3];
+
+ if( !PyArg_ParseTuple
+ ( args, "O!O!O!", &vector_Type, &vec1, &vector_Type, &vec2
+ , &vector_Type, &vec3 ) )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_TypeError, "expected 3 vector types\n" ) );
+ if( vec1->size != vec2->size || vec1->size != vec3->size )
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "vectors must be of the same size\n" ) );
+
+ if (vec1->size == 3) {
+ VECCOPY(v1, vec1->vec);
+ VECCOPY(v2, vec2->vec);
+ VECCOPY(v3, vec3->vec);
+
+ return PyFloat_FromDouble( AreaT3Dfl(v1, v2, v3) );
+ }
+ else if (vec1->size == 2) {
+ v1[0] = vec1->vec[0];
+ v1[1] = vec1->vec[1];
+
+ v2[0] = vec2->vec[0];
+ v2[1] = vec2->vec[1];
+
+ v3[0] = vec3->vec[0];
+ v3[1] = vec3->vec[1];
+
+ return PyFloat_FromDouble( AreaF2Dfl(v1, v2, v3) );
+ }
+ else {
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "only 2D,3D vectors are supported\n" ) );
+ }
+}
+//#############################DEPRECATED################################
+//#######################################################################
+//----------------------------------Mathutils.CopyMat() -----------------
+//copies a matrix into a new matrix
+PyObject *M_Mathutils_CopyMat(PyObject * self, PyObject * args)
+{
+ PyObject *matrix = NULL;
+ static char warning = 1;
+
+ if( warning ) {
+ printf("Mathutils.CopyMat(): deprecated :use Mathutils.Matrix() to copy matrices\n");
+ --warning;
+ }
+
+ matrix = M_Mathutils_Matrix(self, args);
+ if(matrix == NULL)
+ return NULL; //error string already set if we get here
+ else
+ return matrix;
+}
+//----------------------------------Mathutils.CopyVec() -----------------
+//makes a new vector that is a copy of the input
+PyObject *M_Mathutils_CopyVec(PyObject * self, PyObject * args)
+{
+ PyObject *vec = NULL;
+ static char warning = 1;
+
+ if( warning ) {
+ printf("Mathutils.CopyVec(): Deprecated: use Mathutils.Vector() to copy vectors\n");
+ --warning;
+ }
+
+ vec = M_Mathutils_Vector(self, args);
+ if(vec == NULL)
+ return NULL; //error string already set if we get here
+ else
+ return vec;
+}
+//----------------------------------Mathutils.CopyQuat() --------------
+//Copies a quaternion to a new quat
+PyObject *M_Mathutils_CopyQuat(PyObject * self, PyObject * args)
+{
+ PyObject *quat = NULL;
+ static char warning = 1;
+
+ if( warning ) {
+ printf("Mathutils.CopyQuat(): Deprecated: use Mathutils.Quaternion() to copy vectors\n");
+ --warning;
+ }
+
+ quat = M_Mathutils_Quaternion(self, args);
+ if(quat == NULL)
+ return NULL; //error string already set if we get here
+ else
+ return quat;
+}
+//----------------------------------Mathutils.CopyEuler() ---------------
+//copies a euler to a new euler
+PyObject *M_Mathutils_CopyEuler(PyObject * self, PyObject * args)
+{
+ PyObject *eul = NULL;
+ static char warning = 1;
+
+ if( warning ) {
+ printf("Mathutils.CopyEuler(): deprecated:use Mathutils.Euler() to copy vectors\n");
+ --warning;
+ }
+
+ eul = M_Mathutils_Euler(self, args);
+ if(eul == NULL)
+ return NULL; //error string already set if we get here
+ else
+ return eul;
+}
+//----------------------------------Mathutils.RotateEuler() ------------
+//rotates a euler a certain amount and returns the result
+//should return a unique euler rotation (i.e. no 720 degree pitches :)
+PyObject *M_Mathutils_RotateEuler(PyObject * self, PyObject * args)
+{
+ EulerObject *Eul = NULL;
+ float angle;
+ char *axis;
+ static char warning = 1;
+
+ if( warning ) {
+ printf("Mathutils.RotateEuler(): Deprecated:use Euler.rotate() to rotate a euler\n");
+ --warning;
+ }
+
+ if(!PyArg_ParseTuple(args, "O!fs", &euler_Type, &Eul, &angle, &axis))
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Mathutils.RotateEuler(): expected euler type & float & string");
+
+ Euler_Rotate(Eul, Py_BuildValue("fs", angle, axis));
+ Py_RETURN_NONE;
+}
+//----------------------------------Mathutils.MatMultVec() --------------
+//COLUMN VECTOR Multiplication (Matrix X Vector)
+PyObject *M_Mathutils_MatMultVec(PyObject * self, PyObject * args)
+{
+ MatrixObject *mat = NULL;
+ VectorObject *vec = NULL;
+ static char warning = 1;
+
+ if( warning ) {
+ printf("Mathutils.MatMultVec(): Deprecated: use matrix * vec to perform column vector multiplication\n");
+ --warning;
+ }
+
+ //get pyObjects
+ if(!PyArg_ParseTuple(args, "O!O!", &matrix_Type, &mat, &vector_Type, &vec))
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Mathutils.MatMultVec(): MatMultVec() expects a matrix and a vector object - in that order\n");
+
+ return column_vector_multiplication(mat, vec);
+}
+//----------------------------------Mathutils.VecMultMat() ---------------
+//ROW VECTOR Multiplication - Vector X Matrix
+PyObject *M_Mathutils_VecMultMat(PyObject * self, PyObject * args)
+{
+ MatrixObject *mat = NULL;
+ VectorObject *vec = NULL;
+ static char warning = 1;
+
+ if( warning ) {
+ printf("Mathutils.VecMultMat(): Deprecated: use vec * matrix to perform row vector multiplication\n");
+ --warning;
+ }
+
+ //get pyObjects
+ if(!PyArg_ParseTuple(args, "O!O!", &vector_Type, &vec, &matrix_Type, &mat))
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Mathutils.VecMultMat(): VecMultMat() expects a vector and matrix object - in that order\n");
+
+ return row_vector_multiplication(vec, mat);
+}
+//#######################################################################
+//#############################DEPRECATED################################
diff --git a/source/blender/python/api2_2x/Mathutils.h b/source/blender/python/api2_2x/Mathutils.h
new file mode 100644
index 00000000000..901cb2139d7
--- /dev/null
+++ b/source/blender/python/api2_2x/Mathutils.h
@@ -0,0 +1,85 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Joseph Gilbert
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+//Include this file for access to vector, quat, matrix, euler, etc...
+
+#ifndef EXPP_Mathutils_H
+#define EXPP_Mathutils_H
+
+#include <Python.h>
+#include "vector.h"
+#include "matrix.h"
+#include "quat.h"
+#include "euler.h"
+#include "point.h"
+
+PyObject *Mathutils_Init( void );
+PyObject *row_vector_multiplication(VectorObject* vec, MatrixObject * mat);
+PyObject *column_vector_multiplication(MatrixObject * mat, VectorObject* vec);
+PyObject *row_point_multiplication(PointObject* pt, MatrixObject * mat);
+PyObject *column_point_multiplication(MatrixObject * mat, PointObject* pt);
+PyObject *quat_rotation(PyObject *arg1, PyObject *arg2);
+
+PyObject *M_Mathutils_Rand(PyObject * self, PyObject * args);
+PyObject *M_Mathutils_Vector(PyObject * self, PyObject * args);
+PyObject *M_Mathutils_CrossVecs(PyObject * self, PyObject * args);
+PyObject *M_Mathutils_DotVecs(PyObject * self, PyObject * args);
+PyObject *M_Mathutils_AngleBetweenVecs(PyObject * self, PyObject * args);
+PyObject *M_Mathutils_MidpointVecs(PyObject * self, PyObject * args);
+PyObject *M_Mathutils_ProjectVecs(PyObject * self, PyObject * args);
+PyObject *M_Mathutils_Matrix(PyObject * self, PyObject * args);
+PyObject *M_Mathutils_RotationMatrix(PyObject * self, PyObject * args);
+PyObject *M_Mathutils_TranslationMatrix(PyObject * self, VectorObject * value);
+PyObject *M_Mathutils_ScaleMatrix(PyObject * self, PyObject * args);
+PyObject *M_Mathutils_OrthoProjectionMatrix(PyObject * self, PyObject * args);
+PyObject *M_Mathutils_ShearMatrix(PyObject * self, PyObject * args);
+PyObject *M_Mathutils_Quaternion(PyObject * self, PyObject * args);
+PyObject *M_Mathutils_CrossQuats(PyObject * self, PyObject * args);
+PyObject *M_Mathutils_DotQuats(PyObject * self, PyObject * args);
+PyObject *M_Mathutils_DifferenceQuats(PyObject * self, PyObject * args);
+PyObject *M_Mathutils_Slerp(PyObject * self, PyObject * args);
+PyObject *M_Mathutils_Euler(PyObject * self, PyObject * args);
+PyObject *M_Mathutils_Intersect( PyObject * self, PyObject * args );
+PyObject *M_Mathutils_TriangleArea( PyObject * self, PyObject * args );
+PyObject *M_Mathutils_TriangleNormal( PyObject * self, PyObject * args );
+PyObject *M_Mathutils_QuadNormal( PyObject * self, PyObject * args );
+PyObject *M_Mathutils_LineIntersect( PyObject * self, PyObject * args );
+PyObject *M_Mathutils_Point(PyObject * self, PyObject * args);
+//DEPRECATED
+PyObject *M_Mathutils_CopyMat(PyObject * self, PyObject * args);
+PyObject *M_Mathutils_CopyVec(PyObject * self, PyObject * args);
+PyObject *M_Mathutils_CopyQuat(PyObject * self, PyObject * args);
+PyObject *M_Mathutils_CopyEuler(PyObject * self, PyObject * args);
+PyObject *M_Mathutils_RotateEuler(PyObject * self, PyObject * args);
+PyObject *M_Mathutils_MatMultVec(PyObject * self, PyObject * args);
+PyObject *M_Mathutils_VecMultMat(PyObject * self, PyObject * args);
+
+#endif /* EXPP_Mathutils_H */
diff --git a/source/blender/python/api2_2x/Mesh.c b/source/blender/python/api2_2x/Mesh.c
new file mode 100644
index 00000000000..494a1250728
--- /dev/null
+++ b/source/blender/python/api2_2x/Mesh.c
@@ -0,0 +1,8648 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender, partially based on NMesh.c API.
+ *
+ * Contributor(s): Ken Hughes
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "Mesh.h" /*This must come first*/
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_key_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_oops_types.h"
+#include "DNA_space_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_modifier_types.h"
+
+#include "BDR_editface.h" /* make_tfaces */
+#include "BDR_vpaint.h"
+#include "BDR_editobject.h"
+
+#include "BIF_editdeform.h"
+#include "BIF_editkey.h" /* insert_meshkey */
+#include "BIF_space.h" /* REMAKEIPO - insert_meshkey */
+#include "BIF_editview.h"
+#include "BIF_editmesh.h"
+#include "BIF_meshtools.h"
+
+#include "BKE_customdata.h"
+#include "BKE_deform.h"
+#include "BKE_displist.h"
+#include "BKE_mesh.h"
+#include "BKE_material.h"
+#include "BKE_main.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_object.h"
+#include "BKE_mball.h"
+#include "BKE_utildefines.h"
+#include "BKE_depsgraph.h"
+#include "BSE_edit.h" /* for countall(); */
+#include "BKE_curve.h" /* for copy_curve(); */
+#include "BKE_modifier.h" /* for modifier_new(), modifier_copyData(); */
+#include "BKE_idprop.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+
+#include "blendef.h"
+#include "mydevice.h"
+#include "butspace.h" /* for mesh tools */
+#include "Object.h"
+#include "Key.h"
+#include "Image.h"
+#include "Material.h"
+#include "Mathutils.h"
+#include "IDProp.h"
+#include "meshPrimitive.h"
+#include "constant.h"
+#include "gen_utils.h"
+#include "gen_library.h"
+#include "multires.h"
+
+/* EXPP Mesh defines */
+
+#define MESH_SMOOTHRESH 30
+#define MESH_SMOOTHRESH_MIN 1
+#define MESH_SMOOTHRESH_MAX 80
+#define MESH_SUBDIV 1
+#define MESH_SUBDIV_MIN 0
+#define MESH_SUBDIV_MAX 6
+
+#define MESH_HASFACEUV 0
+#define MESH_HASMCOL 1
+#define MESH_HASVERTUV 2
+#define MESH_HASMULTIRES 3
+
+#define MESH_MULTIRES_LEVEL 0
+#define MESH_MULTIRES_EDGE 1
+#define MESH_MULTIRES_PIN 2
+#define MESH_MULTIRES_RENDER 3
+
+#define MESH_TOOL_TOSPHERE 0
+#define MESH_TOOL_VERTEXSMOOTH 1
+#define MESH_TOOL_FLIPNORM 2
+#define MESH_TOOL_SUBDIV 3
+#define MESH_TOOL_REMDOUB 4
+#define MESH_TOOL_FILL 5
+#define MESH_TOOL_RECALCNORM 6
+#define MESH_TOOL_TRI2QUAD 7
+#define MESH_TOOL_QUAD2TRI 8
+
+static PyObject *MVertSeq_CreatePyObject( Mesh * mesh );
+static PyObject *MFaceSeq_CreatePyObject( Mesh * mesh );
+static PyObject *MEdgeSeq_CreatePyObject( Mesh * mesh );
+static PyObject *MFace_CreatePyObject( Mesh * mesh, int i );
+static PyObject *MEdge_CreatePyObject( Mesh * mesh, int i );
+
+#define MFACE_VERT_BADRANGE_CHECK(me, face) ((int)face->v1 >= me->totvert || (int)face->v2 >= me->totvert || (int)face->v3 >= me->totvert || (int)face->v4 >= me->totvert)
+#define MEDGE_VERT_BADRANGE_CHECK(me, edge) ((int)edge->v1 >= me->totvert || (int)edge->v2 >= me->totvert)
+
+/************************************************************************
+ *
+ * internal utilities
+ *
+ ************************************************************************/
+
+/*
+ * internal structures used for sorting edges and faces
+ */
+
+typedef struct SrchEdges {
+ unsigned int v[2]; /* indices for verts */
+ unsigned char swap; /* non-zero if verts swapped */
+ unsigned int index; /* index in original param list of this edge */
+ /* (will be used by findEdges) */
+} SrchEdges;
+
+typedef struct SrchFaces {
+ unsigned int v[4]; /* indices for verts */
+ unsigned int index; /* index in original param list of this edge */
+ unsigned char order; /* order of original verts, bitpacked */
+} SrchFaces;
+
+typedef struct FaceEdges {
+ unsigned int v[2]; /* search key (vert indices) */
+ unsigned int index; /* location in edge list */
+ unsigned char sel; /* selection state */
+} FaceEdges;
+
+/*
+ * compare edges by vertex indices
+ */
+
+int medge_comp( const void *va, const void *vb )
+{
+ const unsigned int *a = ((SrchEdges *)va)->v;
+ const unsigned int *b = ((SrchEdges *)vb)->v;
+
+ /* compare first index for differences */
+
+ if (a[0] < b[0]) return -1;
+ else if (a[0] > b[0]) return 1;
+
+ /* if first indices equal, compare second index for differences */
+
+ else if (a[1] < b[1]) return -1;
+ else return (a[1] > b[1]);
+}
+
+/*
+ * compare edges by insert list indices
+ */
+
+int medge_index_comp( const void *va, const void *vb )
+{
+ const SrchEdges *a = (SrchEdges *)va;
+ const SrchEdges *b = (SrchEdges *)vb;
+
+ /* compare list indices for differences */
+
+ if (a->index < b->index) return -1;
+ else return (a->index > b->index);
+}
+
+
+/*
+ * compare faces by vertex indices
+ */
+
+int mface_comp( const void *va, const void *vb )
+{
+ const SrchFaces *a = va;
+ const SrchFaces *b = vb;
+ int i;
+
+ /* compare indices, first to last, for differences */
+ for( i = 0; i < 4; ++i ) {
+ if( a->v[i] < b->v[i] )
+ return -1;
+ if( a->v[i] > b->v[i] )
+ return 1;
+ }
+
+ /*
+ * don't think this needs be done; if order is different then either
+ * (a) the face is good, just reversed or has a different starting
+ * vertex, or (b) face is bad (for 4 verts) and there's a "twist"
+ */
+
+#if 0
+ /* if all the same verts, compare their order */
+ if( a->order < b->order )
+ return -1;
+ if( a->order > b->order )
+ return 1;
+#endif
+
+ return 0;
+}
+
+/*
+ * compare faces by insert list indices
+ */
+
+int mface_index_comp( const void *va, const void *vb )
+{
+ const SrchFaces *a = va;
+ const SrchFaces *b = vb;
+
+ /* compare indices, first to last, for differences */
+ if( a->index < b->index )
+ return -1;
+ if( a->index > b->index )
+ return 1;
+ return 0;
+}
+
+/*
+ * compare edges by vertex indices
+ */
+
+int faceedge_comp( const void *va, const void *vb )
+{
+ const unsigned int *a = ((FaceEdges *)va)->v;
+ const unsigned int *b = ((FaceEdges *)vb)->v;
+
+ /* compare first index for differences */
+
+ if (a[0] < b[0]) return -1;
+ else if (a[0] > b[0]) return 1;
+
+ /* if first indices equal, compare second index for differences */
+
+ else if (a[1] < b[1]) return -1;
+ else return (a[1] > b[1]);
+}
+
+/*
+ * update the DAG for all objects linked to this mesh
+ */
+
+static void mesh_update( Mesh * mesh )
+{
+ Object_updateDag( (void *) mesh );
+}
+
+/*
+ * delete vertices from mesh, then delete edges/keys/faces which used those
+ * vertices
+ *
+ * Deletion is done by "smart compaction"; groups of verts/edges/faces which
+ * remain in the list are copied to new list instead of one at a time. Since
+ * Blender has no realloc we would have to copy things anyway, so there's no
+ * point trying to fill empty entries with data from the end of the lists.
+ *
+ * vert_table is a lookup table for mapping old verts to new verts (after the
+ * vextex list has deleted vertices removed). Each entry contains the
+ * vertex's new index.
+ */
+
+static void delete_verts( Mesh *mesh, unsigned int *vert_table, int to_delete )
+{
+ /*
+ * (1) allocate vertex table (initialize contents to 0)
+ * (2) mark each vertex being deleted in vertex table (= UINT_MAX)
+ * (3) update remaining table entries with "new" vertex index (after
+ * compaction)
+ * (4) allocate new vertex list
+ * (5) do "smart copy" of vertices from old to new
+ * * each moved vertex is entered into vertex table: if vertex i is
+ * moving to index j in new list
+ * vert_table[i] = j;
+ * (6) if keys, do "smart copy" of keys
+ * (7) process edge list
+ * update vert index
+ * delete edges which delete verts
+ * (7) allocate new edge list
+ * (8) do "smart copy" of edges
+ * (9) allocate new face list
+ * (10) do "smart copy" of face
+ */
+
+ unsigned int *tmpvert;
+ CustomData vdata;
+ int i, count, state, dstindex, totvert;
+
+ totvert = mesh->totvert - to_delete;
+ CustomData_copy( &mesh->vdata, &vdata, CD_MASK_MESH, CD_CALLOC, totvert );
+
+ /*
+ * do "smart compaction" of the table; find and copy groups of vertices
+ * which are not being deleted
+ */
+
+ dstindex = 0;
+ tmpvert = vert_table;
+ count = 0;
+ state = 1;
+ for( i = 0; i < mesh->totvert; ++i, ++tmpvert ) {
+ switch( state ) {
+ case 0: /* skipping verts */
+ if( *tmpvert == UINT_MAX ) {
+ ++count;
+ } else {
+ count = 1;
+ state = 1;
+ }
+ break;
+ case 1: /* gathering verts */
+ if( *tmpvert != UINT_MAX ) {
+ ++count;
+ } else {
+ if( count ) {
+ CustomData_copy_data( &mesh->vdata, &vdata, i-count,
+ dstindex, count );
+ dstindex += count;
+ }
+ count = 1;
+ state = 0;
+ }
+ }
+ }
+
+ /* if we were gathering verts at the end of the loop, copy those */
+ if( state && count )
+ CustomData_copy_data( &mesh->vdata, &vdata, i-count, dstindex, count );
+
+ /* delete old vertex list, install the new one, update vertex count */
+ CustomData_free( &mesh->vdata, mesh->totvert );
+ mesh->vdata = vdata;
+ mesh->totvert = totvert;
+ mesh_update_customdata_pointers( mesh );
+}
+
+static void delete_edges( Mesh *mesh, unsigned int *vert_table, int to_delete )
+{
+ int i;
+ MEdge *tmpedge;
+
+ /* if not given, then mark and count edges to be deleted */
+ if( !to_delete ) {
+ tmpedge = mesh->medge;
+ for( i = mesh->totedge; i-- ; ++tmpedge )
+ if( vert_table[tmpedge->v1] == UINT_MAX ||
+ vert_table[tmpedge->v2] == UINT_MAX ) {
+ tmpedge->v1 = UINT_MAX;
+ ++to_delete;
+ }
+ }
+
+ /* if there are edges to delete, handle it */
+ if( to_delete ) {
+ CustomData edata;
+ int count, state, dstindex, totedge;
+
+ /* allocate new edge list and populate */
+ totedge = mesh->totedge - to_delete;
+ CustomData_copy( &mesh->edata, &edata, CD_MASK_MESH, CD_CALLOC, totedge);
+
+ /*
+ * do "smart compaction" of the edges; find and copy groups of edges
+ * which are not being deleted
+ */
+
+ dstindex = 0;
+ tmpedge = mesh->medge;
+ count = 0;
+ state = 1;
+ for( i = 0; i < mesh->totedge; ++i, ++tmpedge ) {
+ switch( state ) {
+ case 0: /* skipping edges */
+ if( tmpedge->v1 == UINT_MAX ) {
+ ++count;
+ } else {
+ count = 1;
+ state = 1;
+ }
+ break;
+ case 1: /* gathering edges */
+ if( tmpedge->v1 != UINT_MAX ) {
+ ++count;
+ } else {
+ if( count ) {
+ CustomData_copy_data( &mesh->edata, &edata, i-count,
+ dstindex, count );
+ dstindex += count;
+ }
+ count = 1;
+ state = 0;
+ }
+ }
+ /* if edge is good, update vertex indices */
+ }
+
+ /* copy any pending good edges */
+ if( state && count )
+ CustomData_copy_data( &mesh->edata, &edata, i-count, dstindex,
+ count );
+
+ /* delete old edge list, install the new one, update vertex count */
+ CustomData_free( &mesh->edata, mesh->totedge );
+ mesh->edata = edata;
+ mesh->totedge = totedge;
+ mesh_update_customdata_pointers( mesh );
+ }
+
+ /* if vertices were deleted, update edge's vertices */
+ if( vert_table ) {
+ tmpedge = mesh->medge;
+ for( i = mesh->totedge; i--; ++tmpedge ) {
+ tmpedge->v1 = vert_table[tmpedge->v1];
+ tmpedge->v2 = vert_table[tmpedge->v2];
+ }
+ }
+}
+
+/*
+* Since all faces must have 3 or 4 verts, we can't have v3 or v4 be zero.
+* If that happens during the deletion, we have to shuffle the vertices
+* around; otherwise it can cause an Eeekadoodle or worse. If there are
+* texture faces as well, they have to be shuffled as well.
+*
+* (code borrowed from test_index_face() in mesh.c, but since we know the
+* faces already have correct number of vertices, this is a little faster)
+*/
+
+static void eeek_fix( MFace *mface, int len4 )
+{
+ /* if 4 verts, then neither v3 nor v4 can be zero */
+ if( len4 ) {
+ if( !mface->v3 || !mface->v4 ) {
+ SWAP( int, mface->v1, mface->v3 );
+ SWAP( int, mface->v2, mface->v4 );
+ }
+ } else if( !mface->v3 ) {
+ /* if 2 verts, then just v3 cannot be zero (v4 MUST be zero) */
+ SWAP( int, mface->v1, mface->v2 );
+ SWAP( int, mface->v2, mface->v3 );
+ }
+}
+
+static void delete_faces( Mesh *mesh, unsigned int *vert_table, int to_delete )
+{
+ int i;
+ MFace *tmpface;
+
+ /* if there are faces to delete, handle it */
+ if( to_delete ) {
+ CustomData fdata;
+ int count, state, dstindex, totface;
+
+ totface = mesh->totface - to_delete;
+ CustomData_copy( &mesh->fdata, &fdata, CD_MASK_MESH, CD_CALLOC, totface );
+
+ /*
+ * do "smart compaction" of the faces; find and copy groups of faces
+ * which are not being deleted
+ */
+
+ dstindex = 0;
+ tmpface = mesh->mface;
+
+ count = 0;
+ state = 1;
+ for( i = 0; i < mesh->totface; ++i ) {
+ switch( state ) {
+ case 0: /* skipping faces */
+ if( tmpface->v1 == UINT_MAX ) {
+ ++count;
+ } else {
+ count = 1;
+ state = 1;
+ }
+ break;
+ case 1: /* gathering faces */
+ if( tmpface->v1 != UINT_MAX ) {
+ ++count;
+ } else {
+ if( count ) {
+ CustomData_copy_data( &mesh->fdata, &fdata, i-count,
+ dstindex, count );
+ dstindex += count;
+ }
+ count = 1;
+ state = 0;
+ }
+ }
+ ++tmpface;
+ }
+
+ /* if we were gathering faces at the end of the loop, copy those */
+ if ( state && count )
+ CustomData_copy_data( &mesh->fdata, &fdata, i-count, dstindex,
+ count );
+
+ /* delete old face list, install the new one, update face count */
+
+ CustomData_free( &mesh->fdata, mesh->totface );
+ mesh->fdata = fdata;
+ mesh->totface = totface;
+ mesh_update_customdata_pointers( mesh );
+ }
+
+ /* if vertices were deleted, update face's vertices */
+ if( vert_table ) {
+ tmpface = mesh->mface;
+
+ for( i = 0; i<mesh->totface; ++i, ++tmpface ) {
+ int len4 = tmpface->v4;
+ tmpface->v1 = vert_table[tmpface->v1];
+ tmpface->v2 = vert_table[tmpface->v2];
+ tmpface->v3 = vert_table[tmpface->v3];
+ if(len4)
+ tmpface->v4 = vert_table[tmpface->v4];
+ else
+ tmpface->v4 = 0;
+
+ test_index_face( tmpface, &mesh->fdata, i, len4? 4: 3);
+ }
+ }
+}
+
+/*
+ * fill up vertex lookup table with old-to-new mappings
+ *
+ * returns the number of vertices marked for deletion
+ */
+
+static unsigned int make_vertex_table( unsigned int *vert_table, int count )
+{
+ int i;
+ unsigned int *tmpvert = vert_table;
+ unsigned int to_delete = 0;
+ unsigned int new_index = 0;
+
+ /* fill the lookup table with old->new index mappings */
+ for( i = count; i; --i, ++tmpvert ) {
+ if( *tmpvert == UINT_MAX ) {
+ ++to_delete;
+ } else {
+ *tmpvert = new_index;
+ ++new_index;
+ }
+ }
+ return to_delete;
+}
+
+
+/************************************************************************
+ *
+ * Color attributes
+ *
+ ************************************************************************/
+
+/*
+ * get a color attribute
+ */
+
+static PyObject *MCol_getAttr( BPy_MCol * self, void *type )
+{
+ unsigned char param;
+
+ switch( (long)type ) {
+ case 'R': /* these are backwards, but that how it works */
+ param = self->color->b;
+ break;
+ case 'G':
+ param = self->color->g;
+ break;
+ case 'B': /* these are backwards, but that how it works */
+ param = self->color->r;
+ break;
+ case 'A':
+ param = self->color->a;
+ break;
+ default:
+ {
+ char errstr[1024];
+ sprintf( errstr, "undefined type '%d' in MCol_getAttr",
+ (int)((long)type & 0xff));
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError, errstr );
+ }
+ }
+
+ return PyInt_FromLong( param );
+}
+
+/*
+ * set a color attribute
+ */
+
+static int MCol_setAttr( BPy_MCol * self, PyObject * value, void * type )
+{
+ unsigned char *param;
+
+ switch( (long)type ) {
+ case 'R': /* these are backwards, but that how it works */
+ param = (unsigned char *)&self->color->b;
+ break;
+ case 'G':
+ param = (unsigned char *)&self->color->g;
+ break;
+ case 'B': /* these are backwards, but that how it works */
+ param = (unsigned char *)&self->color->r;
+ break;
+ case 'A':
+ param = (unsigned char *)&self->color->a;
+ break;
+ default:
+ {
+ char errstr[1024];
+ sprintf( errstr, "undefined type '%d' in MCol_setAttr",
+ (int)((long)type & 0xff));
+ return EXPP_ReturnIntError( PyExc_RuntimeError, errstr );
+ }
+ }
+
+ return EXPP_setIValueClamped( value, param, 0, 255, 'b' );
+}
+
+/************************************************************************
+ *
+ * Python MCol_Type attributes get/set structure
+ *
+ ************************************************************************/
+
+static PyGetSetDef BPy_MCol_getseters[] = {
+ {"r",
+ (getter)MCol_getAttr, (setter)MCol_setAttr,
+ "red component",
+ (void *)'R'},
+ {"g",
+ (getter)MCol_getAttr, (setter)MCol_setAttr,
+ "green component",
+ (void *)'G'},
+ {"b",
+ (getter)MCol_getAttr, (setter)MCol_setAttr,
+ "blue component",
+ (void *)'B'},
+ {"a",
+ (getter)MCol_getAttr, (setter)MCol_setAttr,
+ "alpha component",
+ (void *)'A'},
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+
+/*----------------------------object[]---------------------------
+ sequence accessor (get)*/
+static PyObject *MCol_item(BPy_MCol * self, int i)
+{
+ unsigned char param;
+ switch (i) {
+ case 0:
+ param = self->color->b;
+ break;
+ case 1:
+ param = self->color->g;
+ break;
+ case 2:
+ param = self->color->r;
+ break;
+ case 3:
+ param = self->color->a;
+ break;
+ default:
+ return EXPP_ReturnPyObjError(PyExc_IndexError,
+ "vector[index] = x: assignment index out of range\n");
+ }
+
+ return PyInt_FromLong( param );
+}
+
+/*----------------------------object[]-------------------------
+ sequence accessor (set)*/
+static int MCol_ass_item(BPy_MCol * self, int i, PyObject * value)
+{
+ unsigned char *param;
+
+ switch (i) {
+ case 0:
+ param = (unsigned char *)&self->color->b; /* reversed? why */
+ break;
+ case 1:
+ param = (unsigned char *)&self->color->g;
+ break;
+ case 2:
+ param = (unsigned char *)&self->color->r; /* reversed? why */
+ break;
+ case 3:
+ param = (unsigned char *)&self->color->a;
+ break;
+ default:
+ {
+ return EXPP_ReturnIntError( PyExc_RuntimeError, "Index out of range" );
+ }
+ }
+ return EXPP_setIValueClamped( value, param, 0, 255, 'b' );
+}
+
+/************************************************************************
+ *
+ * Python MCol_Type methods
+ *
+ ************************************************************************/
+
+static PyObject *MCol_repr( BPy_MCol * self )
+{
+ return PyString_FromFormat( "[MCol %d %d %d %d]",
+ (int)self->color->b, (int)self->color->g,
+ (int)self->color->r, (int)self->color->a );
+}
+
+/*-----------------PROTCOL DECLARATIONS--------------------------*/
+static PySequenceMethods MCol_SeqMethods = {
+ (inquiry) NULL, /* sq_length */
+ (binaryfunc) NULL, /* sq_concat */
+ (intargfunc) NULL, /* sq_repeat */
+ (intargfunc) MCol_item, /* sq_item */
+ (intintargfunc) NULL, /* sq_slice */
+ (intobjargproc) MCol_ass_item, /* sq_ass_item */
+ (intintobjargproc) NULL, /* sq_ass_slice */
+};
+
+/************************************************************************
+ *
+ * Python MCol_Type structure definition
+ *
+ ************************************************************************/
+
+PyTypeObject MCol_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender MCol", /* char *tp_name; */
+ sizeof( BPy_MCol ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ NULL, /* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* cmpfunc tp_compare; */
+ ( reprfunc ) MCol_repr, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ &MCol_SeqMethods, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ NULL, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ BPy_MCol_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+static PyObject *MCol_CreatePyObject( MCol * color )
+{
+ BPy_MCol *obj = PyObject_NEW( BPy_MCol, &MCol_Type );
+
+ if( !obj )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyObject_New() failed" );
+
+ obj->color = color;
+ return (PyObject *)obj;
+}
+
+/************************************************************************
+ *
+ * BPy_MVert attributes
+ *
+ ************************************************************************/
+
+static MVert * MVert_get_pointer( BPy_MVert * self )
+{
+ if( BPy_MVert_Check( self ) ) {
+ if( self->index >= ((Mesh *)self->data)->totvert )
+ return (MVert *)EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "MVert is no longer valid" );
+ return &((Mesh *)self->data)->mvert[self->index];
+ }
+ else
+ return (MVert *)self->data;
+}
+
+/*
+ * get a vertex's coordinate
+ */
+
+static PyObject *MVert_getCoord( BPy_MVert * self )
+{
+ MVert *v;
+
+ v = MVert_get_pointer( self );
+ if( !v )
+ return NULL;
+
+ return newVectorObject( v->co, 3, Py_WRAP );
+}
+
+/*
+ * set a vertex's coordinate
+ */
+
+static int MVert_setCoord( BPy_MVert * self, VectorObject * value )
+{
+ int i;
+ MVert *v;
+
+ v = MVert_get_pointer( self );
+ if( !v )
+ return -1;
+
+ if( !VectorObject_Check( value ) || value->size != 3 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected vector argument of size 3" );
+
+ for( i=0; i<3 ; ++i)
+ v->co[i] = value->vec[i];
+
+ return 0;
+}
+
+/*
+ * get a vertex's index
+ */
+
+static PyObject *MVert_getIndex( BPy_MVert * self )
+{
+ if( self->index >= ((Mesh *)self->data)->totvert )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "MVert is no longer valid" );
+
+ return PyInt_FromLong( self->index );
+}
+
+
+/*
+ * get a verts's hidden state
+ */
+
+static PyObject *MVert_getMFlagBits( BPy_MVert * self, void * type )
+{
+ MVert *v;
+
+ v = MVert_get_pointer( self );
+ if (!v)
+ return NULL; /* error is set */
+
+ return EXPP_getBitfield( &v->flag, (int)((long)type & 0xff), 'b' );
+}
+
+
+/*
+ * set a verts's hidden state
+ */
+
+static int MVert_setMFlagBits( BPy_MVert * self, PyObject * value,
+ void * type )
+{
+ MVert *v;
+
+ v = MVert_get_pointer( self );
+
+ if (!v)
+ return -1; /* error is set */
+
+ return EXPP_setBitfield( value, &v->flag,
+ (int)((long)type & 0xff), 'b' );
+}
+
+
+/*
+ * get a vertex's normal
+ */
+
+static PyObject *MVert_getNormal( BPy_MVert * self )
+{
+ float no[3];
+ int i;
+ MVert *v;
+
+ v = MVert_get_pointer( self );
+ if( !v )
+ return NULL; /* error set */
+
+ for( i = 0; i < 3; ++i )
+ no[i] = (float)(v->no[i] / 32767.0);
+ return newVectorObject( no, 3, Py_NEW );
+}
+
+/*
+ * set a vertex's normal
+ */
+
+static int MVert_setNormal( BPy_MVert * self, VectorObject * value )
+{
+ int i;
+ MVert *v;
+ float normal[3];
+
+ v = MVert_get_pointer( self );
+ if( !v )
+ return -1; /* error set */
+
+ if( !VectorObject_Check( value ) || value->size != 3 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected vector argument of size 3" );
+
+
+ for( i=0; i<3 ; ++i)
+ normal[i] = value->vec[i];
+
+ Normalize(normal);
+
+ for( i=0; i<3 ; ++i)
+ v->no[i] = (short)(normal[i]*32767.0);
+
+ return 0;
+}
+
+
+/*
+ * get a vertex's select status
+ */
+
+static PyObject *MVert_getSel( BPy_MVert *self )
+{
+ MVert *v;
+
+ v = MVert_get_pointer( self );
+ if( !v )
+ return NULL; /* error is set */
+
+ return EXPP_getBitfield( &v->flag, SELECT, 'b' );
+}
+
+/*
+ * set a vertex's select status
+ */
+
+static int MVert_setSel( BPy_MVert *self, PyObject *value )
+{
+ MVert *v = MVert_get_pointer( self );
+ Mesh *me = (Mesh *)self->data;
+ if (!v)
+ return -1; /* error is set */
+
+ /*
+ * if vertex exists and setting status is OK, delete select storage
+ * of the edges and faces as well
+ */
+
+ if( v && !EXPP_setBitfield( value, &v->flag, SELECT, 'b' ) ) {
+ if( me && me->mselect ) {
+ MEM_freeN( me->mselect );
+ me->mselect = NULL;
+ }
+ return 0;
+ }
+ return -1;
+}
+
+/*
+ * get a vertex's UV coordinates
+ */
+
+static PyObject *MVert_getUVco( BPy_MVert *self )
+{
+ Mesh *me = (Mesh *)self->data;
+
+ if( !me->msticky )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "mesh has no 'sticky' coordinates" );
+
+ if( self->index >= ((Mesh *)self->data)->totvert )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "MVert is no longer valid" );
+
+ return newVectorObject( me->msticky[self->index].co, 2, Py_WRAP );
+}
+
+/*
+ * set a vertex's UV coordinates
+ */
+
+static int MVert_setUVco( BPy_MVert *self, PyObject *value )
+{
+ float uvco[3] = {0.0, 0.0};
+ Mesh *me = (Mesh *)self->data;
+ struct MSticky *v;
+ int i;
+
+ /*
+ * at least for now, don't allow creation of sticky coordinates if they
+ * don't already exist
+ */
+
+ if( !me->msticky )
+ return EXPP_ReturnIntError( PyExc_AttributeError,
+ "mesh has no 'sticky' coordinates" );
+
+ if( self->index >= ((Mesh *)self->data)->totvert )
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "MVert is no longer valid" );
+
+ if( VectorObject_Check( value ) ) {
+ VectorObject *vect = (VectorObject *)value;
+ if( vect->size != 2 )
+ return EXPP_ReturnIntError( PyExc_AttributeError,
+ "expected 2D vector" );
+ for( i = 0; i < vect->size; ++i )
+ uvco[i] = vect->vec[i];
+ } else if( !PyArg_ParseTuple( value, "ff",
+ &uvco[0], &uvco[1] ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected 2D vector" );
+
+ v = &me->msticky[self->index];
+
+ for( i = 0; i < 2; ++i )
+ v->co[i] = uvco[i];
+
+ return 0;
+}
+
+/************************************************************************
+ *
+ * Python MVert_Type attributes get/set structure
+ *
+ ************************************************************************/
+
+static PyGetSetDef BPy_MVert_getseters[] = {
+ {"co",
+ (getter)MVert_getCoord, (setter)MVert_setCoord,
+ "vertex's coordinate",
+ NULL},
+ {"index",
+ (getter)MVert_getIndex, (setter)NULL,
+ "vertex's index",
+ NULL},
+ {"no",
+ (getter)MVert_getNormal, (setter)MVert_setNormal,
+ "vertex's normal",
+ NULL},
+ {"sel",
+ (getter)MVert_getSel, (setter)MVert_setSel,
+ "vertex's select status",
+ NULL},
+ {"hide",
+ (getter)MVert_getMFlagBits, (setter)MVert_setMFlagBits,
+ "vert hidden in edit mode",
+ (void *)ME_HIDE},
+ {"uvco",
+ (getter)MVert_getUVco, (setter)MVert_setUVco,
+ "vertex's UV coordinates",
+ NULL},
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+static PyGetSetDef BPy_PVert_getseters[] = {
+ {"co",
+ (getter)MVert_getCoord, (setter)MVert_setCoord,
+ "vertex's coordinate",
+ NULL},
+ {"no",
+ (getter)MVert_getNormal, (setter)MVert_setNormal,
+ "vertex's normal",
+ NULL},
+ {"sel",
+ (getter)MVert_getSel, (setter)MVert_setSel,
+ "vertex's select status",
+ NULL},
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+/************************************************************************
+ *
+ * Python MVert_Type standard operations
+ *
+ ************************************************************************/
+
+static void MVert_dealloc( BPy_MVert * self )
+{
+ if( BPy_PVert_Check( self ) ) /* free memory of thick objects */
+ MEM_freeN ( self->data );
+
+ PyObject_DEL( self );
+}
+
+static int MVert_compare( BPy_MVert * a, BPy_MVert * b )
+{
+ return( a->data == b->data && a->index == b->index ) ? 0 : -1;
+}
+
+static PyObject *MVert_repr( BPy_MVert * self )
+{
+ char format[512];
+ char index[24];
+ MVert *v;
+
+ v = MVert_get_pointer( self );
+ if( !v )
+ return NULL;
+
+ if( BPy_MVert_Check( self ) )
+ sprintf( index, "%d", self->index );
+ else
+ BLI_strncpy( index, "(None)", 24 );
+
+ sprintf( format, "[MVert (%f %f %f) (%f %f %f) %s]",
+ v->co[0], v->co[1], v->co[2], (float)(v->no[0] / 32767.0),
+ (float)(v->no[1] / 32767.0), (float)(v->no[2] / 32767.0),
+ index );
+
+ return PyString_FromString( format );
+}
+
+static long MVert_hash( BPy_MVert *self )
+{
+ return (long)self->index;
+}
+
+static PyObject *Mesh_addPropLayer_internal(Mesh *mesh, CustomData *data, int tot, PyObject *args)
+{
+ char *name=NULL;
+ int type = -1;
+
+ if( !PyArg_ParseTuple( args, "si", &name, &type) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a string and an int" );
+ if (strlen(name)>31)
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "error, maximum name length is 31");
+ if((type != CD_PROP_FLT) && (type != CD_PROP_INT) && (type != CD_PROP_STR))
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "error, unknown layer type");
+ if (name)
+ CustomData_add_layer_named(data, type, CD_DEFAULT, NULL,tot,name);
+
+ mesh_update_customdata_pointers(mesh);
+ Py_RETURN_NONE;
+}
+
+static PyObject *Mesh_removePropLayer_internal(Mesh *mesh, CustomData *data, int tot,PyObject *value)
+{
+ CustomDataLayer *layer;
+ char *name=PyString_AsString(value);
+ int i;
+
+ if( !name )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument" );
+
+ if (strlen(name)>31)
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "error, maximum name length is 31" );
+
+ i = CustomData_get_named_layer_index(data, CD_PROP_FLT, name);
+ if(i == -1) i = CustomData_get_named_layer_index(data, CD_PROP_INT, name);
+ if(i == -1) i = CustomData_get_named_layer_index(data, CD_PROP_STR, name);
+ if (i==-1)
+ return EXPP_ReturnPyObjError(PyExc_ValueError,
+ "No matching layers to remove" );
+ layer = &data->layers[i];
+ CustomData_free_layer(data, layer->type, tot, i);
+ mesh_update_customdata_pointers(mesh);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Mesh_renamePropLayer_internal(Mesh *mesh, CustomData *data, PyObject *args)
+{
+ CustomDataLayer *layer;
+ int i;
+ char *name_from, *name_to;
+
+ if( !PyArg_ParseTuple( args, "ss", &name_from, &name_to ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected 2 strings" );
+
+ if (strlen(name_from)>31 || strlen(name_to)>31)
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "error, maximum name length is 31" );
+
+ i = CustomData_get_named_layer_index(data, CD_PROP_FLT, name_from);
+ if(i == -1) i = CustomData_get_named_layer_index(data, CD_PROP_INT, name_from);
+ if(i == -1) i = CustomData_get_named_layer_index(data, CD_PROP_STR, name_from);
+ if(i == -1)
+ return EXPP_ReturnPyObjError(PyExc_ValueError,
+ "No matching layers to rename" );
+
+ layer = &data->layers[i];
+
+ strcpy(layer->name, name_to); /* we alredy know the string sizes are under 32 */
+ CustomData_set_layer_unique_name(data, i);
+ Py_RETURN_NONE;
+}
+
+static PyObject *Mesh_propList_internal(CustomData *data)
+{
+ CustomDataLayer *layer;
+ PyObject *list = PyList_New( 0 ), *item;
+ int i;
+ for(i=0; i<data->totlayer; i++) {
+ layer = &data->layers[i];
+ if( (layer->type == CD_PROP_FLT) || (layer->type == CD_PROP_INT) || (layer->type == CD_PROP_STR)) {
+ item = PyString_FromString(layer->name);
+ PyList_Append( list, item );
+ Py_DECREF(item);
+ }
+ }
+ return list;
+}
+
+static PyObject *Mesh_getProperty_internal(CustomData *data, int eindex, PyObject *value)
+{
+ CustomDataLayer *layer;
+ char *name=PyString_AsString(value);
+ int i;
+ MFloatProperty *pf;
+ MIntProperty *pi;
+ MStringProperty *ps;
+
+ if(!name)
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected an string argument" );
+
+ if (strlen(name)>31)
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "error, maximum name length is 31" );
+
+ i = CustomData_get_named_layer_index(data, CD_PROP_FLT, name);
+ if(i == -1) i = CustomData_get_named_layer_index(data, CD_PROP_INT, name);
+ if(i == -1) i = CustomData_get_named_layer_index(data, CD_PROP_STR, name);
+ if(i == -1)
+ return EXPP_ReturnPyObjError(PyExc_ValueError,
+ "No matching layers" );
+
+ layer = &data->layers[i];
+
+ if(layer->type == CD_PROP_FLT){
+ pf = layer->data;
+ return PyFloat_FromDouble(pf[eindex].f);
+ }
+ else if(layer->type == CD_PROP_INT){
+ pi = layer->data;
+ return PyInt_FromLong(pi[eindex].i);
+
+ }
+ else if(layer->type == CD_PROP_STR){
+ ps = layer->data;
+ return PyString_FromString(ps[eindex].s);
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *Mesh_setProperty_internal(CustomData *data, int eindex, PyObject *args)
+{
+ CustomDataLayer *layer;
+ int i = 0, index, type = -1;
+ float f = 0.0f;
+ char *s=NULL, *name=NULL;
+ MFloatProperty *pf;
+ MIntProperty *pi;
+ MStringProperty *ps;
+ PyObject *val;
+
+ if(PyArg_ParseTuple(args, "sO", &name, &val)){
+ if (strlen(name)>31)
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "error, maximum name length is 31" );
+
+ if(PyInt_Check(val)){
+ type = CD_PROP_INT;
+ i = (int)PyInt_AS_LONG(val);
+ }
+ else if(PyFloat_Check(val)){
+ type = CD_PROP_FLT;
+ f = (float)PyFloat_AsDouble(val);
+ }
+ else if(PyString_Check(val)){
+ type = CD_PROP_STR;
+ s = PyString_AsString(val);
+ }
+ else
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected an name plus either float/int/string" );
+
+ }
+
+ index = CustomData_get_named_layer_index(data, type, name);
+ if(index == -1)
+ return EXPP_ReturnPyObjError(PyExc_ValueError,
+ "No matching layers or type mismatch" );
+
+ layer = &data->layers[index];
+
+ if(type==CD_PROP_STR){
+ if (strlen(s)>255){
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "error, maximum string length is 255");
+ }
+ else{
+ ps = layer->data;
+ strcpy(ps[eindex].s,s);
+ }
+ }
+ else if(type==CD_PROP_FLT){
+ pf = layer->data;
+ pf[eindex].f = f;
+ }
+ else{
+ pi = layer->data;
+ pi[eindex].i = i;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *MVert_getProp( BPy_MVert *self, PyObject *args)
+{
+ if( BPy_MVert_Check( self ) ){
+ Mesh *me = (Mesh *)self->data;
+ if(self->index >= me->totvert)
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "error, MVert is no longer valid part of mesh!");
+ else
+ return Mesh_getProperty_internal(&(me->vdata), self->index, args);
+ }
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "error, Vertex not part of a mesh!");
+}
+
+static PyObject *MVert_setProp( BPy_MVert *self, PyObject *args)
+{
+ if( BPy_MVert_Check( self ) ){
+ Mesh *me = (Mesh *)self->data;
+ if(self->index >= me->totvert)
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "error, MVert is no longer valid part of mesh!");
+ else
+ return Mesh_setProperty_internal(&(me->vdata), self->index, args);
+ }
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "error, Vertex not part of a mesh!");
+}
+
+static struct PyMethodDef BPy_MVert_methods[] = {
+ {"getProperty", (PyCFunction)MVert_getProp, METH_O,
+ "get property indicated by name"},
+ {"setProperty", (PyCFunction)MVert_setProp, METH_VARARGS,
+ "set property indicated by name"},
+ {NULL, NULL, 0, NULL}
+};
+
+
+/************************************************************************
+ *
+ * Python MVert_Type structure definition
+ *
+ ************************************************************************/
+
+PyTypeObject MVert_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender MVert", /* char *tp_name; */
+ sizeof( BPy_MVert ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ ( destructor ) MVert_dealloc,/* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ ( cmpfunc ) MVert_compare, /* cmpfunc tp_compare; */
+ ( reprfunc ) MVert_repr, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ ( hashfunc ) MVert_hash, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_MVert_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ BPy_MVert_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+/************************************************************************
+ *
+ * Python PVert_Type standard operations
+ *
+ ************************************************************************/
+
+static int PVert_compare( BPy_MVert * a, BPy_MVert * b )
+{
+ return( a->data == b->data ) ? 0 : -1;
+}
+
+/************************************************************************
+ *
+ * Python PVert_Type structure definition
+ *
+ ************************************************************************/
+
+PyTypeObject PVert_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender PVert", /* char *tp_name; */
+ sizeof( BPy_MVert ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ ( destructor ) MVert_dealloc,/* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ ( cmpfunc ) PVert_compare, /* cmpfunc tp_compare; */
+ ( reprfunc ) MVert_repr, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ ( hashfunc ) MVert_hash, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ NULL, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ BPy_PVert_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+/*
+ * create 'thin' or 'thick' MVert objects
+ *
+ * there are two types of objects; thin (wrappers for mesh vertex) and thick
+ * (not contains in mesh). Thin objects are MVert_Type and thick are
+ * PVert_Type. For thin objects, data is a pointer to a Mesh and index
+ * is the vertex's index in mesh->mvert. For thick objects, data is a
+ * pointer to an MVert; index is unused.
+ */
+
+/*
+ * create a thin MVert object
+ */
+
+static PyObject *MVert_CreatePyObject( Mesh *mesh, int i )
+{
+ BPy_MVert *obj = (BPy_MVert *)PyObject_NEW( BPy_MVert, &MVert_Type );
+
+ if( !obj )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyObject_New() failed" );
+
+ obj->index = i;
+ obj->data = mesh;
+ return (PyObject *)obj;
+}
+
+/*
+ * create a thick MVert object
+ */
+
+static PyObject *PVert_CreatePyObject( MVert *vert )
+{
+ MVert *newvert;
+ BPy_MVert *obj = (BPy_MVert *)PyObject_NEW( BPy_MVert, &PVert_Type );
+
+ if( !obj )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyObject_New() failed" );
+
+ newvert = (MVert *)MEM_callocN( sizeof( MVert ), "MVert" );
+ if( !newvert )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "MEM_callocN() failed" );
+
+ memcpy( newvert, vert, sizeof( MVert ) );
+ obj->data = newvert;
+ return (PyObject *)obj;
+}
+
+/************************************************************************
+ *
+ * Vertex sequence
+ *
+ ************************************************************************/
+
+static int MVertSeq_len( BPy_MVertSeq * self )
+{
+ return self->mesh->totvert;
+}
+
+/*
+ * retrive a single MVert from somewhere in the vertex list
+ */
+
+static PyObject *MVertSeq_item( BPy_MVertSeq * self, int i )
+{
+ if( i < 0 || i >= self->mesh->totvert )
+ return EXPP_ReturnPyObjError( PyExc_IndexError,
+ "array index out of range" );
+
+ return MVert_CreatePyObject( self->mesh, i );
+}
+
+/*
+ * retrieve a slice of the vertex list (as a Python list)
+ *
+ * Python is nice enough to handle negative indices for us: if the user
+ * specifies -1, Python will pass us len()-1. So we can just check for
+ * indices in the range 0:len()-1. Of course, we should never actually
+ * return the high index, but up to one less.
+ */
+
+static PyObject *MVertSeq_slice( BPy_MVertSeq *self, int low, int high )
+{
+ PyObject *list;
+ int i;
+
+ /*
+ * Python list slice operator returns empty list when asked for a slice
+ * outside the list, or if indices are reversed (low > high). Clamp
+ * our input to do the same.
+ */
+
+ if( low < 0 ) low = 0;
+ if( high > self->mesh->totvert ) high = self->mesh->totvert;
+ if( low > high ) low = high;
+
+ list = PyList_New( high-low );
+ if( !list )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyList_New() failed" );
+
+ /*
+ * return Py_NEW copies of requested vertices
+ */
+
+ for( i = low; i < high; ++i )
+ PyList_SET_ITEM( list, i-low,
+ PVert_CreatePyObject( (void *)&self->mesh->mvert[i] ) );
+ return list;
+}
+
+/*
+ * assign a single MVert to somewhere in the vertex list
+ */
+
+static int MVertSeq_assign_item( BPy_MVertSeq * self, int i,
+ BPy_MVert *v )
+{
+ MVert *dst = &self->mesh->mvert[i];
+ MVert *src;
+
+ if( !v )
+ return EXPP_ReturnIntError( PyExc_IndexError,
+ "del() not supported" );
+
+ if( i < 0 || i >= self->mesh->totvert )
+ return EXPP_ReturnIntError( PyExc_IndexError,
+ "array index out of range" );
+
+ if( BPy_MVert_Check( v ) )
+ src = &((Mesh *)v->data)->mvert[v->index];
+ else
+ src = (MVert *)v->data;
+
+ memcpy( dst, src, sizeof(MVert) );
+ /* mesh_update( self->mesh );*/
+ return 0;
+}
+
+static int MVertSeq_assign_slice( BPy_MVertSeq *self, int low, int high,
+ PyObject *args )
+{
+ int len, i;
+
+ if( !PyList_Check( args ) )
+ return EXPP_ReturnIntError( PyExc_IndexError,
+ "can only assign lists of MVerts" );
+
+ len = PyList_Size( args );
+
+ /*
+ * Python list slice assign operator allows for changing the size of the
+ * destination list, by replacement and appending....
+ *
+ * >>> l=[1,2,3,4]
+ * >>> m=[11,12,13,14]
+ * >>> l[5:7]=m
+ * >>> print l
+ * [1, 2, 3, 4, 11, 12, 13, 14]
+ * >>> l=[1,2,3,4]
+ * >>> l[2:3]=m
+ * >>> print l
+ * [1, 2, 11, 12, 13, 14, 4]
+ *
+ * We don't want the size of the list to change (at least not at time
+ * point in development) so we are a little more strict:
+ * - low and high indices must be in range [0:len()]
+ * - high-low == PyList_Size(v)
+ */
+
+ if( low < 0 || high > self->mesh->totvert || low > high )
+ return EXPP_ReturnIntError( PyExc_IndexError,
+ "invalid slice range" );
+
+ if( high-low != len )
+ return EXPP_ReturnIntError( PyExc_IndexError,
+ "slice range and input list sizes must be equal" );
+
+ for( i = low; i < high; ++i )
+ {
+ BPy_MVert *v = (BPy_MVert *)PyList_GET_ITEM( args, i-low );
+ MVert *dst = &self->mesh->mvert[i];
+ MVert *src;
+
+ if( BPy_MVert_Check( v ) )
+ src = &((Mesh *)v->data)->mvert[v->index];
+ else
+ src = (MVert *)v->data;
+
+ memcpy( dst, src, sizeof(MVert) );
+ }
+ /* mesh_update( self->mesh );*/
+ return 0;
+}
+
+static PySequenceMethods MVertSeq_as_sequence = {
+ ( inquiry ) MVertSeq_len, /* sq_length */
+ ( binaryfunc ) 0, /* sq_concat */
+ ( intargfunc ) 0, /* sq_repeat */
+ ( intargfunc ) MVertSeq_item, /* sq_item */
+ ( intintargfunc ) MVertSeq_slice, /* sq_slice */
+ ( intobjargproc ) MVertSeq_assign_item, /* sq_ass_item */
+ ( intintobjargproc ) MVertSeq_assign_slice, /* sq_ass_slice */
+ 0,0,0,
+};
+
+/************************************************************************
+ *
+ * Python MVertSeq_Type iterator (iterates over vertices)
+ *
+ ************************************************************************/
+
+/*
+ * Initialize the interator index
+ */
+
+static PyObject *MVertSeq_getIter( BPy_MVertSeq * self )
+{
+ if (self->iter==-1) { /* iteration for this pyobject is not yet used, just return self */
+ self->iter = 0;
+ return EXPP_incr_ret ( (PyObject *) self );
+ } else {
+ /* were alredy using this as an iterator, make a copy to loop on */
+ BPy_MVertSeq *seq = (BPy_MVertSeq *)MVertSeq_CreatePyObject(self->mesh);
+ seq->iter = 0;
+ return (PyObject *)seq;
+ }
+}
+
+/*
+ * Return next MVert.
+ */
+
+static PyObject *MVertSeq_nextIter( BPy_MVertSeq * self )
+{
+ if( self->iter == self->mesh->totvert ) {
+ self->iter= -1; /* allow it to be used as an iterator again without creating a new BPy_MVertSeq */
+ return EXPP_ReturnPyObjError( PyExc_StopIteration,
+ "iterator at end" );
+ }
+
+ return MVert_CreatePyObject( self->mesh, self->iter++ );
+}
+
+/************************************************************************
+ *
+ * Python MVertSeq_Type methods
+ *
+ ************************************************************************/
+
+static PyObject *MVertSeq_extend( BPy_MVertSeq * self, PyObject *args )
+{
+ int len, newlen;
+ int i,j;
+ PyObject *tmp;
+ MVert *newvert, *tmpvert;
+ Mesh *mesh = self->mesh;
+ CustomData vdata;
+ /* make sure we get a sequence of tuples of something */
+
+ switch( PySequence_Size( args ) ) {
+ case 1: /* better be a list or a tuple */
+ tmp = PyTuple_GET_ITEM( args, 0 );
+ if( !VectorObject_Check ( tmp ) ) {
+ if( !PySequence_Check ( tmp ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a sequence of sequence triplets" );
+ else if( !PySequence_Size ( tmp ) ) {
+ Py_RETURN_NONE;
+ }
+ args = tmp;
+ }
+ Py_INCREF( args ); /* so we can safely DECREF later */
+ break;
+ case 3:
+ tmp = PyTuple_GET_ITEM( args, 0 );
+ /* if first item is not a number, it's wrong */
+ if( !PyNumber_Check( tmp ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a sequence of sequence triplets" );
+
+ /* otherwise, put into a new tuple */
+ args = Py_BuildValue( "((OOO))", tmp,
+ PyTuple_GET_ITEM( args, 1 ), PyTuple_GET_ITEM( args, 2 ) );
+ if( !args )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "Py_BuildValue() failed" );
+ break;
+
+ default: /* anything else is definitely wrong */
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a sequence of sequence triplets" );
+ }
+
+ /* if no verts given, return quietly */
+ len = PySequence_Size( args );
+ if( len == 0 ) {
+ Py_DECREF ( args );
+ Py_RETURN_NONE;
+ }
+
+ /* create custom vertex data arrays and copy existing vertices into it */
+
+ newlen = mesh->totvert + len;
+ CustomData_copy( &mesh->vdata, &vdata, CD_MASK_MESH, CD_DEFAULT, newlen );
+ CustomData_copy_data( &mesh->vdata, &vdata, 0, 0, mesh->totvert );
+
+ if ( !CustomData_has_layer( &vdata, CD_MVERT ) )
+ CustomData_add_layer( &vdata, CD_MVERT, CD_CALLOC, NULL, newlen );
+
+ newvert = CustomData_get_layer( &vdata, CD_MVERT );
+
+ /* scan the input list and insert the new vertices */
+
+ tmpvert = &newvert[mesh->totvert];
+ for( i = 0; i < len; ++i ) {
+ float co[3];
+ tmp = PySequence_GetItem( args, i );
+ if( VectorObject_Check( tmp ) ) {
+ if( ((VectorObject *)tmp)->size != 3 ) {
+ CustomData_free( &vdata, newlen );
+ Py_DECREF ( tmp );
+ Py_DECREF ( args );
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "expected vector of size 3" );
+ }
+ for( j = 0; j < 3; ++j )
+ co[j] = ((VectorObject *)tmp)->vec[j];
+ } else if( PySequence_Check( tmp ) ) {
+ int ok=1;
+ PyObject *flt;
+ if( PySequence_Size( tmp ) != 3 )
+ ok = 0;
+ else
+ for( j = 0; ok && j < 3; ++j ) {
+ flt = PySequence_ITEM( tmp, j );
+ if( !PyNumber_Check ( flt ) )
+ ok = 0;
+ else
+ co[j] = (float)PyFloat_AsDouble( flt );
+ Py_DECREF( flt );
+ }
+
+ if( !ok ) {
+ CustomData_free( &vdata, newlen );
+ Py_DECREF ( args );
+ Py_DECREF ( tmp );
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "expected sequence triplet of floats" );
+ }
+ } else {
+ CustomData_free( &vdata, newlen );
+ Py_DECREF ( args );
+ Py_DECREF ( tmp );
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "expected sequence triplet of floats" );
+ }
+
+ Py_DECREF ( tmp );
+
+ /* add the coordinate to the new list */
+ memcpy( tmpvert->co, co, sizeof(co) );
+
+ tmpvert->flag |= SELECT;
+ /* TODO: anything else which needs to be done when we add a vert? */
+ /* probably not: NMesh's newvert() doesn't */
+ ++tmpvert;
+ }
+
+ CustomData_free( &mesh->vdata, mesh->totvert );
+ mesh->vdata = vdata;
+ mesh_update_customdata_pointers( mesh );
+
+ /*
+ * if there are keys, have to fix those lists up
+ */
+
+ if( mesh->key ) {
+ KeyBlock *currkey = mesh->key->block.first;
+ float *fp, *newkey;
+
+ while( currkey ) {
+
+ /* create key list, copy existing data if any */
+ newkey = MEM_callocN(mesh->key->elemsize*newlen, "keydata");
+ if( currkey->data ) {
+ memcpy( newkey, currkey->data,
+ mesh->totvert*mesh->key->elemsize );
+ MEM_freeN( currkey->data );
+ currkey->data = newkey;
+ }
+
+ /* add data for new vertices */
+ fp = (float *)((char *)currkey->data +
+ (mesh->key->elemsize*mesh->totvert));
+ tmpvert = mesh->mvert + mesh->totvert;
+ for( i = newlen - mesh->totvert; i > 0; --i ) {
+ VECCOPY(fp, tmpvert->co);
+ fp += 3;
+ tmpvert++;
+ }
+ currkey->totelem = newlen;
+ currkey = currkey->next;
+ }
+ }
+
+ /* set final vertex list size */
+ mesh->totvert = newlen;
+
+ mesh_update( mesh );
+
+ Py_DECREF ( args );
+ Py_RETURN_NONE;
+}
+
+static PyObject *MVertSeq_delete( BPy_MVertSeq * self, PyObject *args )
+{
+ unsigned int *vert_table;
+ int vert_delete, face_count;
+ int i;
+ Mesh *mesh = self->mesh;
+ MFace *tmpface;
+
+ /*
+ * if input tuple contains a single sequence, use it as input instead;
+ * otherwise use the sequence as-is and check later that it contains
+ * one or more integers or MVerts
+ */
+ if( PySequence_Size( args ) == 1 ) {
+ PyObject *tmp = PyTuple_GET_ITEM( args, 0 );
+ if( PySequence_Check( tmp ) )
+ args = tmp;
+ }
+
+ /* if sequence is empty, do nothing */
+ if( PySequence_Size( args ) == 0 ) {
+ Py_RETURN_NONE;
+ }
+
+ /* allocate vertex lookup table */
+ vert_table = (unsigned int *)MEM_callocN(
+ mesh->totvert*sizeof( unsigned int ), "vert_table" );
+
+ /* get the indices of vertices to be removed */
+ for( i = PySequence_Size( args ); i--; ) {
+ PyObject *tmp = PySequence_GetItem( args, i );
+ int index;
+ if( BPy_MVert_Check( tmp ) ) {
+ if( (void *)self->mesh != ((BPy_MVert*)tmp)->data ) {
+ MEM_freeN( vert_table );
+ Py_DECREF( tmp );
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "MVert belongs to a different mesh" );
+ }
+ index = ((BPy_MVert*)tmp)->index;
+ } else if( PyInt_Check( tmp ) ) {
+ index = PyInt_AsLong ( tmp );
+ } else {
+ MEM_freeN( vert_table );
+ Py_DECREF( tmp );
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a sequence of ints or MVerts" );
+ }
+ Py_DECREF( tmp );
+ if( index < 0 || index >= mesh->totvert ) {
+ MEM_freeN( vert_table );
+ return EXPP_ReturnPyObjError( PyExc_IndexError,
+ "array index out of range" );
+ }
+ vert_table[index] = UINT_MAX;
+ }
+
+ /* delete things, then clean up and return */
+
+ vert_delete = make_vertex_table( vert_table, mesh->totvert );
+ if( vert_delete )
+ delete_verts( mesh, vert_table, vert_delete );
+
+ /* calculate edges to delete, fix vertex indices */
+ delete_edges( mesh, vert_table, 0 );
+
+ /*
+ * find number of faces which contain any of the deleted vertices,
+ * and mark them, then delete them
+ */
+ tmpface = mesh->mface;
+ face_count=0;
+ for( i = mesh->totface; i--; ++tmpface ) {
+ if( vert_table[tmpface->v1] == UINT_MAX ||
+ vert_table[tmpface->v2] == UINT_MAX ||
+ vert_table[tmpface->v3] == UINT_MAX ||
+ ( tmpface->v4 && vert_table[tmpface->v4] == UINT_MAX ) ) {
+ tmpface->v1 = UINT_MAX;
+ ++face_count;
+ }
+ }
+ delete_faces( mesh, vert_table, face_count );
+
+ /* clean up and exit */
+ MEM_freeN( vert_table );
+ mesh_update ( mesh );
+ Py_RETURN_NONE;
+}
+
+static PyObject *MVertSeq_selected( BPy_MVertSeq * self )
+{
+ int i, count;
+ Mesh *mesh = self->mesh;
+ MVert *tmpvert;
+ PyObject *list;
+
+ /* first count selected edges (quicker than appending to PyList?) */
+ count = 0;
+ tmpvert = mesh->mvert;
+ for( i = 0; i < mesh->totvert; ++i, ++tmpvert )
+ if( tmpvert->flag & SELECT )
+ ++count;
+
+ list = PyList_New( count );
+ if( !list )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyList_New() failed" );
+
+ /* next, insert selected edges into list */
+ count = 0;
+ tmpvert = mesh->mvert;
+ for( i = 0; i < mesh->totvert; ++i, ++tmpvert ) {
+ if( tmpvert->flag & SELECT ) {
+ PyObject *tmp = PyInt_FromLong( i );
+ if( !tmp ) {
+ Py_DECREF( list );
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyInt_FromLong() failed" );
+ }
+ PyList_SET_ITEM( list, count, tmp );
+ ++count;
+ }
+ }
+ return list;
+}
+static PyObject *MVertSeq_add_layertype(BPy_MVertSeq *self, PyObject *args)
+{
+ Mesh *me = (Mesh*)self->mesh;
+ return Mesh_addPropLayer_internal(me, &(me->vdata), me->totvert, args);
+}
+static PyObject *MVertSeq_del_layertype(BPy_MVertSeq *self, PyObject *value)
+{
+ Mesh *me = (Mesh*)self->mesh;
+ return Mesh_removePropLayer_internal(me, &(me->vdata), me->totvert, value);
+}
+static PyObject *MVertSeq_rename_layertype(BPy_MVertSeq *self, PyObject *args)
+{
+ Mesh *me = (Mesh*)self->mesh;
+ return Mesh_renamePropLayer_internal(me,&(me->vdata),args);
+}
+static PyObject *MVertSeq_PropertyList(BPy_MVertSeq *self)
+{
+ Mesh *me = (Mesh*)self->mesh;
+ return Mesh_propList_internal(&(me->vdata));
+}
+static PyObject *M_Mesh_PropertiesTypeDict(void)
+{
+ PyObject *Types = PyConstant_New( );
+ if(Types) {
+ BPy_constant *d = (BPy_constant *) Types;
+ PyConstant_Insert(d, "FLOAT", PyInt_FromLong(CD_PROP_FLT));
+ PyConstant_Insert(d, "INT" , PyInt_FromLong(CD_PROP_INT));
+ PyConstant_Insert(d, "STRING", PyInt_FromLong(CD_PROP_STR));
+ }
+ return Types;
+}
+
+static struct PyMethodDef BPy_MVertSeq_methods[] = {
+ {"extend", (PyCFunction)MVertSeq_extend, METH_VARARGS,
+ "add vertices to mesh"},
+ {"delete", (PyCFunction)MVertSeq_delete, METH_VARARGS,
+ "delete vertices from mesh"},
+ {"selected", (PyCFunction)MVertSeq_selected, METH_NOARGS,
+ "returns a list containing indices of selected vertices"},
+ {"addPropertyLayer",(PyCFunction)MVertSeq_add_layertype, METH_VARARGS,
+ "add a new property layer"},
+ {"removePropertyLayer",(PyCFunction)MVertSeq_del_layertype, METH_O,
+ "removes a property layer"},
+ {"renamePropertyLayer",(PyCFunction)MVertSeq_rename_layertype, METH_VARARGS,
+ "renames an existing property layer"},
+ {NULL, NULL, 0, NULL}
+};
+
+static PyGetSetDef BPy_MVertSeq_getseters[] = {
+ {"properties",
+ (getter)MVertSeq_PropertyList, (setter)NULL,
+ "vertex property layers, read only",
+ NULL},
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+
+
+/************************************************************************
+ *
+ * Python MVertSeq_Type standard operations
+ *
+ ************************************************************************/
+
+/*****************************************************************************/
+/* Python MVertSeq_Type structure definition: */
+/*****************************************************************************/
+PyTypeObject MVertSeq_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender MVertSeq", /* char *tp_name; */
+ sizeof( BPy_MVertSeq ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ NULL, /* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* cmpfunc tp_compare; */
+ NULL, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ &MVertSeq_as_sequence, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ ( getiterfunc) MVertSeq_getIter, /* getiterfunc tp_iter; */
+ ( iternextfunc ) MVertSeq_nextIter, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_MVertSeq_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ BPy_MVertSeq_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+/************************************************************************
+ *
+ * Edge attributes
+ *
+ ************************************************************************/
+
+static MEdge * MEdge_get_pointer( BPy_MEdge * self )
+{
+ if( self->index >= self->mesh->totedge )
+ return (MEdge *)EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "MEdge is no longer valid" );
+ return &self->mesh->medge[self->index];
+}
+
+/*
+ * get an edge's crease value
+ */
+
+static PyObject *MEdge_getCrease( BPy_MEdge * self )
+{
+ MEdge *edge = MEdge_get_pointer( self );
+
+ if( !edge )
+ return NULL;
+
+ return PyInt_FromLong( edge->crease );
+}
+
+/*
+ * set an edge's crease value
+ */
+
+static int MEdge_setCrease( BPy_MEdge * self, PyObject * value )
+{
+ MEdge *edge = MEdge_get_pointer( self );
+
+ if( !edge )
+ return -1;
+
+ return EXPP_setIValueClamped( value, &edge->crease, 0, 255, 'b' );
+}
+
+/*
+ * get an edge's flag
+ */
+
+static PyObject *MEdge_getFlag( BPy_MEdge * self )
+{
+ MEdge *edge = MEdge_get_pointer( self );
+
+ if( !edge )
+ return NULL;
+
+ return PyInt_FromLong( edge->flag );
+}
+
+/*
+ * set an edge's flag
+ */
+
+static int MEdge_setFlag( BPy_MEdge * self, PyObject * value )
+{
+ short param;
+ static short bitmask = SELECT
+ | ME_EDGEDRAW
+ | ME_SEAM
+ | ME_FGON
+ | ME_HIDE
+ | ME_EDGERENDER
+ | ME_LOOSEEDGE
+ | ME_SEAM_LAST
+ | ME_SHARP;
+ MEdge *edge = MEdge_get_pointer( self );
+
+ if( !edge )
+ return -1;
+
+ if( !PyInt_Check ( value ) ) {
+ char errstr[128];
+ sprintf ( errstr , "expected int bitmask of 0x%04x", bitmask );
+ return EXPP_ReturnIntError( PyExc_TypeError, errstr );
+ }
+ param = (short)PyInt_AS_LONG ( value );
+
+ if ( ( param & bitmask ) != param )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "invalid bit(s) set in mask" );
+
+ edge->flag = param;
+
+ return 0;
+}
+
+/*
+ * get an edge's first vertex
+ */
+
+static PyObject *MEdge_getV1( BPy_MEdge * self )
+{
+ MEdge *edge = MEdge_get_pointer( self );
+
+ if( !edge )
+ return NULL;
+
+ return MVert_CreatePyObject( self->mesh, edge->v1 );
+}
+
+/*
+ * set an edge's first vertex
+ */
+
+static int MEdge_setV1( BPy_MEdge * self, BPy_MVert * value )
+{
+ MEdge *edge = MEdge_get_pointer( self );
+
+ if( !edge )
+ return -1;
+ if( !BPy_MVert_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError, "expected an MVert" );
+
+ edge->v1 = value->index;
+ return 0;
+}
+
+/*
+ * get an edge's second vertex
+ */
+
+static PyObject *MEdge_getV2( BPy_MEdge * self )
+{
+ MEdge *edge = MEdge_get_pointer( self );
+
+ if( !edge )
+ return NULL; /* error is set */
+ /* if v2 is out of range, the python mvert will complain, no need to check here */
+ return MVert_CreatePyObject( self->mesh, edge->v2 );
+}
+
+/*
+ * set an edge's second vertex
+ */
+
+static int MEdge_setV2( BPy_MEdge * self, BPy_MVert * value )
+{
+ MEdge *edge = MEdge_get_pointer( self );
+
+ if( !edge )
+ return -1; /* error is set */
+ if( !BPy_MVert_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError, "expected an MVert" );
+
+ if ( edge->v1 == value->index )
+ return EXPP_ReturnIntError( PyExc_ValueError, "an edge cant use the same vertex for each end" );
+
+ edge->v2 = value->index;
+ return 0;
+}
+
+/*
+ * get an edge's index
+ */
+
+static PyObject *MEdge_getIndex( BPy_MEdge * self )
+{
+ if( !MEdge_get_pointer( self ) )
+ return NULL; /* error is set */
+
+ return PyInt_FromLong( self->index );
+}
+
+/*
+ * get an edge's flag
+ */
+
+static PyObject *MEdge_getMFlagBits( BPy_MEdge * self, void * type )
+{
+ MEdge *edge = MEdge_get_pointer( self );
+
+ if( !edge )
+ return NULL; /* error is set */
+
+ return EXPP_getBitfield( &edge->flag, (int)((long)type & 0xff), 'b' );
+}
+
+/*
+ * get an edge's length
+ */
+
+static PyObject *MEdge_getLength( BPy_MEdge * self )
+{
+ MEdge *edge = MEdge_get_pointer( self );
+ double dot = 0.0f;
+ float tmpf;
+ int i;
+ float *v1, *v2;
+
+ if (!edge)
+ return NULL; /* error is set */
+
+ if MEDGE_VERT_BADRANGE_CHECK(self->mesh, edge)
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError, "This edge uses removed vert(s)" );
+
+ /* get the 2 edges vert locations */
+ v1= (&((Mesh *)self->mesh)->mvert[edge->v1])->co;
+ v2= (&((Mesh *)self->mesh)->mvert[edge->v2])->co;
+
+ if( !edge )
+ return NULL;
+
+ for( i = 0; i < 3; i++ ) {
+ tmpf = v1[i] - v2[i];
+ dot += tmpf*tmpf;
+ }
+ return PyFloat_FromDouble( sqrt( dot ) );
+}
+
+/*
+ * get an key for using in a dictionary or set key
+ */
+
+static PyObject *MEdge_getKey( BPy_MEdge * self )
+{
+ PyObject *attr;
+ MEdge *edge = MEdge_get_pointer( self );
+ if (!edge)
+ return NULL; /* error is set */
+
+ attr = PyTuple_New( 2 );
+ if (edge->v1 > edge->v2) {
+ PyTuple_SET_ITEM( attr, 0, PyInt_FromLong(edge->v2) );
+ PyTuple_SET_ITEM( attr, 1, PyInt_FromLong(edge->v1) );
+ } else {
+ PyTuple_SET_ITEM( attr, 0, PyInt_FromLong(edge->v1) );
+ PyTuple_SET_ITEM( attr, 1, PyInt_FromLong(edge->v2) );
+ }
+ return attr;
+}
+
+/*
+ * set an edge's select state
+ */
+
+static int MEdge_setSel( BPy_MEdge * self,PyObject * value,
+ void * type_unused )
+{
+ MEdge *edge = MEdge_get_pointer( self );
+ int param = PyObject_IsTrue( value );
+ Mesh *me = self->mesh;
+
+ if( !edge )
+ return -1;
+
+ if MEDGE_VERT_BADRANGE_CHECK(me, edge)
+ return EXPP_ReturnIntError( PyExc_RuntimeError, "This edge uses removed vert(s)" );
+
+ if( param == -1 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected True/False or 0/1" );
+
+ if( param ) {
+ edge->flag |= SELECT;
+ me->mvert[edge->v1].flag |= SELECT;
+ me->mvert[edge->v2].flag |= SELECT;
+ }
+ else {
+ edge->flag &= ~SELECT;
+ me->mvert[edge->v1].flag &= ~SELECT;
+ me->mvert[edge->v2].flag &= ~SELECT;
+ }
+
+ if( self->mesh->mselect ) {
+ MEM_freeN( self->mesh->mselect );
+ self->mesh->mselect = NULL;
+ }
+
+ return 0;
+}
+
+/************************************************************************
+ *
+ * Python MEdge_Type attributes get/set structure
+ *
+ ************************************************************************/
+
+static PyGetSetDef BPy_MEdge_getseters[] = {
+ {"crease",
+ (getter)MEdge_getCrease, (setter)MEdge_setCrease,
+ "edge's crease value",
+ NULL},
+ {"flag",
+ (getter)MEdge_getFlag, (setter)MEdge_setFlag,
+ "edge's flags",
+ NULL},
+ {"v1",
+ (getter)MEdge_getV1, (setter)MEdge_setV1,
+ "edge's first vertex",
+ NULL},
+ {"v2",
+ (getter)MEdge_getV2, (setter)MEdge_setV2,
+ "edge's second vertex",
+ NULL},
+ {"index",
+ (getter)MEdge_getIndex, (setter)NULL,
+ "edge's index",
+ NULL},
+ {"sel",
+ (getter)MEdge_getMFlagBits, (setter)MEdge_setSel,
+ "edge selected in edit mode",
+ (void *)SELECT},
+ {"length",
+ (getter)MEdge_getLength, (setter)NULL,
+ "edge's length, read only",
+ NULL},
+ {"key",
+ (getter)MEdge_getKey, (setter)NULL,
+ "edge's key for using with sets or dictionaries, read only",
+ NULL},
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+/************************************************************************
+ *
+ * Python MEdge_Type iterator (iterates over vertices)
+ *
+ ************************************************************************/
+
+/*
+ * Initialize the interator index
+ */
+
+static PyObject *MEdge_getIter( BPy_MEdge * self )
+{
+ if (self->iter==-1) { /* not alredy used to iterator on, just use self */
+ self->iter = 0;
+ return EXPP_incr_ret ( (PyObject *) self );
+ } else { /* alredy being iterated on, return a copy */
+ BPy_MEdge *seq = (BPy_MEdge *)MEdge_CreatePyObject(self->mesh, self->index);
+ seq->iter = 0;
+ return (PyObject *)seq;
+ }
+}
+
+/*
+ * Return next MVert. Throw an exception after the second vertex.
+ */
+
+static PyObject *MEdge_nextIter( BPy_MEdge * self )
+{
+ if( self->iter == 2 ) {
+ self->iter = -1;
+ return EXPP_ReturnPyObjError( PyExc_StopIteration,
+ "iterator at end" );
+ }
+
+ self->iter++;
+ if( self->iter == 1 )
+ return MEdge_getV1( self );
+ else
+ return MEdge_getV2( self );
+}
+
+/************************************************************************
+ *
+ * Python MEdge_Type standard operations
+ *
+ ************************************************************************/
+
+static int MEdge_compare( BPy_MEdge * a, BPy_MEdge * b )
+{
+ return( a->mesh == b->mesh && a->index == b->index ) ? 0 : -1;
+}
+
+static PyObject *MEdge_repr( BPy_MEdge * self )
+{
+ struct MEdge *edge = MEdge_get_pointer( self );
+
+ if( !edge )
+ return NULL;
+
+ return PyString_FromFormat( "[MEdge (%d %d) %d %d]",
+ (int)edge->v1, (int)edge->v2, (int)edge->crease,
+ (int)self->index );
+}
+
+static long MEdge_hash( BPy_MEdge *self )
+{
+ return (long)self->index;
+}
+static PyObject *MEdge_getProp( BPy_MEdge *self, PyObject *args)
+{
+ Mesh *me = (Mesh *)self->mesh;
+ return Mesh_getProperty_internal(&(me->edata), self->index, args);
+}
+
+static PyObject *MEdge_setProp( BPy_MEdge *self, PyObject *args)
+{
+ Mesh *me = (Mesh *)self->mesh;
+ return Mesh_setProperty_internal(&(me->edata), self->index, args);
+}
+
+static struct PyMethodDef BPy_MEdge_methods[] = {
+ {"getProperty", (PyCFunction)MEdge_getProp, METH_O,
+ "get property indicated by name"},
+ {"setProperty", (PyCFunction)MEdge_setProp, METH_VARARGS,
+ "set property indicated by name"},
+ {NULL, NULL, 0, NULL}
+};
+/************************************************************************
+ *
+ * Python MEdge_Type structure definition
+ *
+ ************************************************************************/
+
+PyTypeObject MEdge_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender MEdge", /* char *tp_name; */
+ sizeof( BPy_MEdge ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ NULL, /* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ ( cmpfunc ) MEdge_compare, /* cmpfunc tp_compare; */
+ ( reprfunc ) MEdge_repr, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ ( hashfunc ) MEdge_hash, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ ( getiterfunc) MEdge_getIter, /* getiterfunc tp_iter; */
+ ( iternextfunc ) MEdge_nextIter, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_MEdge_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ BPy_MEdge_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+static PyObject *MEdge_CreatePyObject( Mesh * mesh, int i )
+{
+ BPy_MEdge *obj = PyObject_NEW( BPy_MEdge, &MEdge_Type );
+
+ if( !obj )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyObject_New() failed" );
+
+ obj->mesh = mesh;
+ obj->index = i;
+ obj->iter = -1;
+ return (PyObject *)obj;
+}
+
+/************************************************************************
+ *
+ * Edge sequence
+ *
+ ************************************************************************/
+
+static int MEdgeSeq_len( BPy_MEdgeSeq * self )
+{
+ return self->mesh->totedge;
+}
+
+static PyObject *MEdgeSeq_item( BPy_MEdgeSeq * self, int i )
+{
+ if( i < 0 || i >= self->mesh->totedge )
+ return EXPP_ReturnPyObjError( PyExc_IndexError,
+ "array index out of range" );
+
+ return MEdge_CreatePyObject( self->mesh, i );
+}
+
+
+static PySequenceMethods MEdgeSeq_as_sequence = {
+ ( inquiry ) MEdgeSeq_len, /* sq_length */
+ ( binaryfunc ) 0, /* sq_concat */
+ ( intargfunc ) 0, /* sq_repeat */
+ ( intargfunc ) MEdgeSeq_item, /* sq_item */
+ ( intintargfunc ) 0, /* sq_slice */
+ ( intobjargproc ) 0, /* sq_ass_item */
+ ( intintobjargproc ) 0, /* sq_ass_slice */
+ 0,0,0,
+};
+
+/************************************************************************
+ *
+ * Python MEdgeSeq_Type iterator (iterates over edges)
+ *
+ ************************************************************************/
+
+/*
+ * Initialize the interator index
+ */
+
+static PyObject *MEdgeSeq_getIter( BPy_MEdgeSeq * self )
+{
+ if (self->iter==-1) { /* iteration for this pyobject is not yet used, just return self */
+ self->iter = 0;
+ return EXPP_incr_ret ( (PyObject *) self );
+ } else {
+ BPy_MEdgeSeq *seq = (BPy_MEdgeSeq *)MEdgeSeq_CreatePyObject(self->mesh);
+ seq->iter = 0;
+ return (PyObject *)seq;
+ }
+}
+
+/*
+ * Return next MEdge.
+ */
+
+static PyObject *MEdgeSeq_nextIter( BPy_MEdgeSeq * self )
+{
+ if( self->iter == self->mesh->totedge ) {
+ self->iter= -1;
+ return EXPP_ReturnPyObjError( PyExc_StopIteration,
+ "iterator at end" );
+ }
+
+ return MEdge_CreatePyObject( self->mesh, self->iter++ );
+}
+
+/************************************************************************
+ *
+ * Python MEdgeSeq_Type methods
+ *
+ ************************************************************************/
+
+/*
+ * Create edges from tuples of vertices. Duplicate new edges, or
+ * edges which already exist,
+ */
+
+static PyObject *MEdgeSeq_extend( BPy_MEdgeSeq * self, PyObject *args )
+{
+ int len, nverts;
+ int i, j, ok;
+ int new_edge_count, good_edges;
+ SrchEdges *oldpair, *newpair, *tmppair, *tmppair2;
+ PyObject *tmp;
+ BPy_MVert *e[4];
+ MEdge *tmpedge;
+ Mesh *mesh = self->mesh;
+
+ /* make sure we get a tuple of sequences of something */
+ switch( PySequence_Size( args ) ) {
+ case 1:
+ /* if a sequence... */
+ tmp = PyTuple_GET_ITEM( args, 0 );
+ if( PySequence_Check( tmp ) ) {
+ PyObject *tmp2;
+
+ /* ignore empty sequences */
+ if( !PySequence_Size( tmp ) ) {
+ Py_RETURN_NONE;
+ }
+
+ /* if another sequence, use it */
+ tmp2 = PySequence_ITEM( tmp, 0 );
+ if( PySequence_Check( tmp2 ) )
+ args = tmp;
+ Py_INCREF( args );
+ Py_DECREF( tmp2 );
+ } else
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a sequence of sequence pairs" );
+ break;
+ case 2:
+ case 3:
+ case 4: /* two to four args may be individual verts */
+ tmp = PyTuple_GET_ITEM( args, 0 );
+ /*
+ * if first item isn't a sequence, then assume it's a bunch of MVerts
+ * and wrap inside a tuple
+ */
+ if( !PySequence_Check( tmp ) ) {
+ args = Py_BuildValue( "(O)", args );
+ if( !args )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "Py_BuildValue() failed" );
+ /*
+ * otherwise, assume it already a bunch of sequences so use as-is
+ */
+ } else {
+ Py_INCREF( args ); /* so we can safely DECREF later */
+ }
+ break;
+ default: /* anything else is definitely wrong */
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a sequence of sequence pairs" );
+ }
+
+ /* make sure there is something to add */
+ len = PySequence_Size( args );
+ if( len == 0 ) {
+ Py_DECREF ( args );
+ Py_RETURN_NONE;
+ }
+
+ /* verify the param list and get a total count of number of edges */
+ new_edge_count = 0;
+ for( i = 0; i < len; ++i ) {
+ tmp = PySequence_GetItem( args, i );
+
+ /* not a tuple of MVerts... error */
+ if( !PySequence_Check( tmp ) ) {
+ Py_DECREF( tmp );
+ Py_DECREF( args );
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "expected sequence of MVert sequences" );
+ }
+
+ /* not the right number of MVerts... error */
+ nverts = PySequence_Size( tmp );
+ if( nverts < 2 || nverts > 4 ) {
+ Py_DECREF( tmp );
+ Py_DECREF( args );
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "expected 2 to 4 MVerts per sequence" );
+ }
+
+ if( EXPP_check_sequence_consistency( tmp, &MVert_Type ) == 1 ) {
+
+ /* get MVerts, check they're from this mesh */
+ ok = 1;
+ for( j = 0; ok && j < nverts; ++j ) {
+ e[0] = (BPy_MVert *)PySequence_GetItem( tmp, j );
+ if( (void *)e[0]->data != (void *)self->mesh )
+ ok = 0;
+ Py_DECREF( e[0] );
+ }
+ Py_DECREF( tmp );
+
+ /* not MVerts from another mesh ... error */
+ if( !ok ) {
+ Py_DECREF( args );
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "vertices are from a different mesh" );
+ }
+ } else {
+ ok = 0;
+ for( j = 0; ok == 0 && j < nverts; ++j ) {
+ PyObject *item = PySequence_ITEM( tmp, j );
+ if( !PyInt_Check( item ) )
+ ok = 1;
+ else {
+ int index = PyInt_AsLong ( item );
+ if( index < 0 || index >= self->mesh->totvert )
+ ok = 2;
+ }
+ Py_DECREF( item );
+ }
+ Py_DECREF( tmp );
+
+ /* not ints or outside of vertex list ... error */
+ if( ok ) {
+ Py_DECREF( args );
+ if( ok == 1 )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected an integer index" );
+ else
+ return EXPP_ReturnPyObjError( PyExc_KeyError,
+ "index out of range" );
+ }
+ }
+
+ if( nverts == 2 )
+ ++new_edge_count; /* if only two vert, then add only edge */
+ else
+ new_edge_count += nverts; /* otherwise, one edge per vert */
+ }
+
+ /* OK, commit to allocating the search structures */
+ newpair = (SrchEdges *)MEM_callocN( sizeof(SrchEdges)*new_edge_count,
+ "MEdgePairs" );
+
+ /* scan the input list and build the new edge pair list */
+ len = PySequence_Size( args );
+ tmppair = newpair;
+ new_edge_count = 0;
+ for( i = 0; i < len; ++i ) {
+ int edge_count;
+ int eedges[4];
+ tmp = PySequence_GetItem( args, i );
+ nverts = PySequence_Size( tmp );
+
+ /* get new references for the vertices */
+ for(j = 0; j < nverts; ++j ) {
+ PyObject *item = PySequence_ITEM( tmp, j );
+ if( BPy_MVert_Check( item ) ) {
+ eedges[j] = ((BPy_MVert *)item)->index;
+ } else {
+ eedges[j] = PyInt_AsLong ( item );
+ }
+ Py_DECREF( item );
+ }
+ Py_DECREF( tmp );
+
+ if( nverts == 2 )
+ edge_count = 1; /* again, two verts give just one edge */
+ else
+ edge_count = nverts;
+
+ /* now add the edges to the search list */
+ for( j = 0; j < edge_count; ++j ) {
+ int k = j+1;
+ if( k == nverts ) /* final edge */
+ k = 0;
+
+ /* sort verts into search list, skip if two are the same */
+ if( eedges[j] != eedges[k] ) {
+ if( eedges[j] < eedges[k] ) {
+ tmppair->v[0] = eedges[j];
+ tmppair->v[1] = eedges[k];
+ tmppair->swap = 0;
+ } else {
+ tmppair->v[0] = eedges[k];
+ tmppair->v[1] = eedges[j];
+ tmppair->swap = 1;
+ }
+ tmppair->index = new_edge_count;
+ ++new_edge_count;
+ tmppair++;
+ }
+ }
+
+ }
+
+ /* sort the new edge pairs */
+ qsort( newpair, new_edge_count, sizeof(SrchEdges), medge_comp );
+
+ /*
+ * find duplicates in the new list and mark. if it's a duplicate,
+ * then mark by setting second vert index to 0 (a real edge won't have
+ * second vert index of 0 since verts are sorted)
+ */
+
+ good_edges = new_edge_count; /* all edges are good at this point */
+
+ tmppair = newpair; /* "last good edge" */
+ tmppair2 = &tmppair[1]; /* "current candidate edge" */
+ for( i = 0; i < new_edge_count; ++i ) {
+ if( tmppair->v[0] != tmppair2->v[0] ||
+ tmppair->v[1] != tmppair2->v[1] )
+ tmppair = tmppair2; /* last != current, so current == last */
+ else {
+ tmppair2->v[1] = 0; /* last == current, so mark as duplicate */
+ --good_edges; /* one less good edge */
+ }
+ tmppair2++;
+ }
+
+ /* if mesh has edges, see if any of the new edges are already in it */
+ if( mesh->totedge ) {
+ oldpair = (SrchEdges *)MEM_callocN( sizeof(SrchEdges)*mesh->totedge,
+ "MEdgePairs" );
+
+ /*
+ * build a search list of new edges (don't need to update "swap"
+ * field, since we're not creating edges here)
+ */
+ tmppair = oldpair;
+ tmpedge = mesh->medge;
+ for( i = 0; i < mesh->totedge; ++i ) {
+ if( tmpedge->v1 < tmpedge->v2 ) {
+ tmppair->v[0] = tmpedge->v1;
+ tmppair->v[1] = tmpedge->v2;
+ } else {
+ tmppair->v[0] = tmpedge->v2;
+ tmppair->v[1] = tmpedge->v1;
+ }
+ ++tmpedge;
+ ++tmppair;
+ }
+
+ /* sort the old edge pairs */
+ qsort( oldpair, mesh->totedge, sizeof(SrchEdges), medge_comp );
+
+ /* eliminate new edges already in the mesh */
+ tmppair = newpair;
+ for( i = new_edge_count; i-- ; ) {
+ if( tmppair->v[1] ) {
+ if( bsearch( tmppair, oldpair, mesh->totedge,
+ sizeof(SrchEdges), medge_comp ) ) {
+ tmppair->v[1] = 0; /* mark as duplicate */
+ --good_edges;
+ }
+ }
+ tmppair++;
+ }
+ MEM_freeN( oldpair );
+ }
+
+ /* if any new edges are left, add to list */
+ if( good_edges ) {
+ CustomData edata;
+ int totedge = mesh->totedge+good_edges;
+
+ /* create custom edge data arrays and copy existing edges into it */
+ CustomData_copy( &mesh->edata, &edata, CD_MASK_MESH, CD_DEFAULT, totedge );
+ CustomData_copy_data( &mesh->edata, &edata, 0, 0, mesh->totedge );
+
+ if ( !CustomData_has_layer( &edata, CD_MEDGE ) )
+ CustomData_add_layer( &edata, CD_MEDGE, CD_CALLOC, NULL, totedge );
+
+ /* replace old with new data */
+ CustomData_free( &mesh->edata, mesh->totedge );
+ mesh->edata = edata;
+ mesh_update_customdata_pointers( mesh );
+
+ /* resort edges into original order */
+ qsort( newpair, new_edge_count, sizeof(SrchEdges), medge_index_comp );
+
+ /* point to the first edge we're going to add */
+ tmpedge = &mesh->medge[mesh->totedge];
+ tmppair = newpair;
+
+ /* as we find a good edge, add it */
+ while( good_edges ) {
+ if( tmppair->v[1] ) { /* not marked as duplicate ! */
+ if( !tmppair->swap ) {
+ tmpedge->v1 = tmppair->v[0];
+ tmpedge->v2 = tmppair->v[1];
+ } else {
+ tmpedge->v1 = tmppair->v[1];
+ tmpedge->v2 = tmppair->v[0];
+ }
+ tmpedge->flag = ME_EDGEDRAW | ME_EDGERENDER | SELECT;
+ mesh->totedge++;
+ --good_edges;
+ ++tmpedge;
+ }
+ tmppair++;
+ }
+ }
+
+ /* clean up and leave */
+ mesh_update( mesh );
+ MEM_freeN( newpair );
+ Py_DECREF ( args );
+ Py_RETURN_NONE;
+}
+
+static PyObject *MEdgeSeq_delete( BPy_MEdgeSeq * self, PyObject *args )
+{
+ Mesh *mesh = self->mesh;
+ MEdge *srcedge;
+ MFace *srcface;
+ unsigned int *vert_table, *del_table, *edge_table;
+ int i, len;
+ int face_count, edge_count, vert_count;
+
+ /*
+ * if input tuple contains a single sequence, use it as input instead;
+ * otherwise use the sequence as-is and check later that it contains
+ * one or more integers or MVerts
+ */
+ if( PySequence_Size( args ) == 1 ) {
+ PyObject *tmp = PyTuple_GET_ITEM( args, 0 );
+ if( PySequence_Check( tmp ) )
+ args = tmp;
+ }
+
+ /* if sequence is empty, do nothing */
+ len = PySequence_Size( args );
+ if( len == 0 ) {
+ Py_RETURN_NONE;
+ }
+
+ edge_table = (unsigned int *)MEM_callocN( len*sizeof( unsigned int ),
+ "edge_table" );
+
+ /* get the indices of edges to be removed */
+ for( i = len; i--; ) {
+ PyObject *tmp = PySequence_GetItem( args, i );
+ if( BPy_MEdge_Check( tmp ) )
+ edge_table[i] = ((BPy_MEdge *)tmp)->index;
+ else if( PyInt_Check( tmp ) )
+ edge_table[i] = PyInt_AsLong ( tmp );
+ else {
+ MEM_freeN( edge_table );
+ Py_DECREF( tmp );
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a sequence of ints or MEdges" );
+ }
+ Py_DECREF( tmp );
+
+ /* if index out-of-range, throw exception */
+ if( edge_table[i] >= (unsigned int)mesh->totedge ) {
+ MEM_freeN( edge_table );
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "array index out of range" );
+ }
+ }
+
+ /*
+ * build two tables: first table marks vertices which belong to an edge
+ * which is being deleted
+ */
+ del_table = (unsigned int *)MEM_callocN(
+ mesh->totvert*sizeof( unsigned int ), "vert_table" );
+
+ /*
+ * Borrow a trick from editmesh code: for each edge to be deleted, mark
+ * its vertices as well. Then go through face list and look for two
+ * consecutive marked vertices.
+ */
+
+ /* mark each edge that's to be deleted */
+ srcedge = mesh->medge;
+ for( i = len; i--; ) {
+ unsigned int idx = edge_table[i];
+ del_table[srcedge[idx].v1] = UINT_MAX;
+ del_table[srcedge[idx].v2] = UINT_MAX;
+ srcedge[idx].v1 = UINT_MAX;
+ }
+
+ /*
+ * second table is used for vertices which become orphaned (belong to no
+ * edges) and need to be deleted; it's also the normal lookup table for
+ * old->new vertex indices
+ */
+
+ vert_table = (unsigned int *)MEM_mallocN(
+ mesh->totvert*sizeof( unsigned int ), "vert_table" );
+
+ /* assume all edges will be deleted (fills with UINT_MAX) */
+ memset( vert_table, UCHAR_MAX, mesh->totvert*sizeof( unsigned int ) );
+
+ /* unmark vertices of each "good" edge; count each "bad" edge */
+ edge_count = 0;
+ for( i = mesh->totedge; i--; ++srcedge )
+ if( srcedge->v1 != UINT_MAX )
+ vert_table[srcedge->v1] = vert_table[srcedge->v2] = 0;
+ else
+ ++edge_count;
+
+ /*
+ * find faces which no longer have all edges
+ */
+
+ face_count = 0;
+ srcface = mesh->mface;
+ for( i = 0; i < mesh->totface; ++i, ++srcface ) {
+ int len = srcface->v4 ? 4 : 3;
+ unsigned int id[4];
+ int del;
+
+ id[0] = del_table[srcface->v1];
+ id[1] = del_table[srcface->v2];
+ id[2] = del_table[srcface->v3];
+ id[3] = del_table[srcface->v4];
+
+ del = ( id[0] == UINT_MAX && id[1] == UINT_MAX ) ||
+ ( id[1] == UINT_MAX && id[2] == UINT_MAX );
+ if( !del ) {
+ if( len == 3 )
+ del = ( id[2] == UINT_MAX && id[0] == UINT_MAX );
+ else
+ del = ( id[2] == UINT_MAX && id[3] == UINT_MAX ) ||
+ ( id[3] == UINT_MAX && id[0] == UINT_MAX );
+ }
+ if( del ) {
+ srcface->v1 = UINT_MAX;
+ ++face_count;
+ }
+ }
+
+ /* fix the vertex lookup table, if any verts to delete, do so now */
+ vert_count = make_vertex_table( vert_table, mesh->totvert );
+ if( vert_count )
+ delete_verts( mesh, vert_table, vert_count );
+
+ /* delete faces which have a deleted edge */
+ delete_faces( mesh, vert_table, face_count );
+
+ /* now delete the edges themselves */
+ delete_edges( mesh, vert_table, edge_count );
+
+ /* clean up and return */
+ MEM_freeN( del_table );
+ MEM_freeN( vert_table );
+ MEM_freeN( edge_table );
+ mesh_update ( mesh );
+ Py_RETURN_NONE;
+}
+
+static PyObject *MEdgeSeq_collapse( BPy_MEdgeSeq * self, PyObject *args )
+{
+ MEdge *srcedge;
+ unsigned int *edge_table;
+ float (*vert_list)[3];
+ int i, len;
+ Base *base, *basact;
+ Mesh *mesh = self->mesh;
+ Object *object = NULL;
+ PyObject *tmp;
+
+ /*
+ * when using removedoublesflag(), we need to switch to editmode, so
+ * nobody else can be using it
+ */
+
+ if( G.obedit )
+ return EXPP_ReturnPyObjError(PyExc_RuntimeError,
+ "can't use collapse() while in edit mode" );
+
+ /* make sure we get a tuple of sequences of something */
+ switch( PySequence_Size( args ) ) {
+ case 1:
+ /* if a sequence... */
+ tmp = PyTuple_GET_ITEM( args, 0 );
+ if( PySequence_Check( tmp ) ) {
+ PyObject *tmp2;
+
+ /* ignore empty sequences */
+ if( !PySequence_Size( tmp ) ) {
+ Py_RETURN_NONE;
+ }
+
+ /* if another sequence, use it */
+ tmp2 = PySequence_ITEM( tmp, 0 );
+ if( PySequence_Check( tmp2 ) )
+ args = tmp;
+ Py_INCREF( args );
+ Py_DECREF( tmp2 );
+ } else
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a sequence of sequence pairs" );
+ break;
+ case 2: /* two args may be individual edges/verts */
+ tmp = PyTuple_GET_ITEM( args, 0 );
+ /*
+ * if first item isn't a sequence, then assume it's a bunch of MVerts
+ * and wrap inside a tuple
+ */
+ if( !PySequence_Check( tmp ) ) {
+ args = Py_BuildValue( "(O)", args );
+ if( !args )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "Py_BuildValue() failed" );
+ /*
+ * otherwise, assume it already a bunch of sequences so use as-is
+ */
+ } else {
+ Py_INCREF( args ); /* so we can safely DECREF later */
+ }
+ break;
+ default: /* anything else is definitely wrong */
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a sequence of sequence pairs" );
+ }
+
+ /* if sequence is empty, do nothing */
+ len = PySequence_Size( args );
+ if( len == 0 ) {
+ Py_RETURN_NONE;
+ }
+
+ /* allocate table of edge indices and new vertex values */
+
+ edge_table = (unsigned int *)MEM_callocN( len*sizeof( unsigned int ),
+ "edge_table" );
+ vert_list = (float (*)[3])MEM_callocN( 3*len*sizeof( float ),
+ "vert_list" );
+
+ /* get the indices of edges to be collapsed and new vert locations */
+ for( i = len; i--; ) {
+ PyObject *tmp1;
+ PyObject *tmp2;
+
+ tmp = PySequence_GetItem( args, i );
+
+ /* if item isn't sequence of size 2, error */
+ if( !PySequence_Check( tmp ) || PySequence_Size( tmp ) != 2 ) {
+ MEM_freeN( edge_table );
+ MEM_freeN( vert_list );
+ Py_DECREF( tmp );
+ Py_DECREF( args );
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a sequence of (MEdges, vector)" );
+ }
+
+ /* if items aren't a MEdge/int and vector, error */
+ tmp1 = PySequence_GetItem( tmp, 0 );
+ tmp2 = PySequence_GetItem( tmp, 1 );
+ Py_DECREF( tmp );
+ if( !(BPy_MEdge_Check( tmp1 ) || PyInt_Check( tmp1 )) ||
+ !VectorObject_Check ( tmp2 ) ) {
+ MEM_freeN( edge_table );
+ MEM_freeN( vert_list );
+ Py_DECREF( tmp1 );
+ Py_DECREF( tmp2 );
+ Py_DECREF( args );
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a sequence of (MEdges, vector)" );
+ }
+
+ /* store edge index, new vertex location */
+ if( PyInt_Check( tmp1 ) )
+ edge_table[i] = PyInt_AsLong ( tmp1 );
+ else
+ edge_table[i] = ((BPy_MEdge *)tmp1)->index;
+ memcpy( vert_list[i], ((VectorObject *)tmp2)->vec,
+ 3*sizeof( float ) );
+ Py_DECREF( tmp1 );
+ Py_DECREF( tmp2 );
+
+ /* if index out-of-range, throw exception */
+ if( edge_table[i] >= (unsigned int)mesh->totedge ) {
+ MEM_freeN( edge_table );
+ MEM_freeN( vert_list );
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "edge index out of range" );
+ }
+ }
+
+ /*
+ * simple algorithm:
+ * (1) deselect all verts
+ * (2) for each edge
+ * (2a) replace both verts with the new vert
+ * (2b) select both verts
+ * (3) call removedoublesflag()
+ */
+
+ /* (1) deselect all verts */
+ for( i = mesh->totvert; i--; )
+ mesh->mvert[i].flag &= ~SELECT;
+
+ /* (2) replace edge's verts and select them */
+ for( i = len; i--; ) {
+ srcedge = &mesh->medge[edge_table[i]];
+ memcpy( &mesh->mvert[srcedge->v1].co, vert_list[i], 3*sizeof( float ) );
+ memcpy( &mesh->mvert[srcedge->v2].co, vert_list[i], 3*sizeof( float ) );
+ mesh->mvert[srcedge->v1].flag |= SELECT;
+ mesh->mvert[srcedge->v2].flag |= SELECT;
+ }
+
+ /* (3) call removedoublesflag() */
+ for( base = FIRSTBASE; base; base = base->next ) {
+ if( base->object->type == OB_MESH &&
+ base->object->data == self->mesh ) {
+ object = base->object;
+ break;
+ }
+ }
+
+ basact = BASACT;
+ BASACT = base;
+
+ removedoublesflag( 1, 0, 0.0 );
+ /* make mesh's object active, enter mesh edit mode */
+ G.obedit = object;
+
+ /* exit edit mode, free edit mesh */
+ load_editMesh();
+ free_editMesh(G.editMesh);
+
+ BASACT = basact;
+
+ /* clean up and exit */
+ Py_DECREF( args );
+ MEM_freeN( vert_list );
+ MEM_freeN( edge_table );
+ mesh_update ( mesh );
+ Py_RETURN_NONE;
+}
+
+
+static PyObject *MEdgeSeq_selected( BPy_MEdgeSeq * self )
+{
+ int i, count;
+ Mesh *mesh = self->mesh;
+ MEdge *tmpedge;
+ PyObject *list;
+
+ /* first count selected edges (quicker than appending to PyList?) */
+ count = 0;
+ tmpedge = mesh->medge;
+ for( i = 0; i < mesh->totedge; ++i, ++tmpedge )
+ if( (mesh->mvert[tmpedge->v1].flag & SELECT) &&
+ (mesh->mvert[tmpedge->v2].flag & SELECT) )
+ ++count;
+
+ list = PyList_New( count );
+ if( !list )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyList_New() failed" );
+
+ /* next, insert selected edges into list */
+ count = 0;
+ tmpedge = mesh->medge;
+ for( i = 0; i < mesh->totedge; ++i, ++tmpedge ) {
+ if( (mesh->mvert[tmpedge->v1].flag & SELECT) &&
+ (mesh->mvert[tmpedge->v2].flag & SELECT) ) {
+ PyObject *tmp = PyInt_FromLong( i );
+ if( !tmp ) {
+ Py_DECREF( list );
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyInt_FromLong() failed" );
+ }
+ PyList_SET_ITEM( list, count, tmp );
+ ++count;
+ }
+ }
+ return list;
+}
+
+static PyObject *MEdgeSeq_add_layertype(BPy_MEdgeSeq *self, PyObject *args)
+{
+ Mesh *me = (Mesh*)self->mesh;
+ return Mesh_addPropLayer_internal(me, &(me->edata), me->totedge, args);
+}
+static PyObject *MEdgeSeq_del_layertype(BPy_MEdgeSeq *self, PyObject *value)
+{
+ Mesh *me = (Mesh*)self->mesh;
+ return Mesh_removePropLayer_internal(me, &(me->edata), me->totedge, value);
+}
+static PyObject *MEdgeSeq_rename_layertype(BPy_MEdgeSeq *self, PyObject *args)
+{
+ Mesh *me = (Mesh*)self->mesh;
+ return Mesh_renamePropLayer_internal(me,&(me->edata),args);
+}
+static PyObject *MEdgeSeq_PropertyList(BPy_MEdgeSeq *self)
+{
+ Mesh *me = (Mesh*)self->mesh;
+ return Mesh_propList_internal(&(me->edata));
+}
+
+
+static struct PyMethodDef BPy_MEdgeSeq_methods[] = {
+ {"extend", (PyCFunction)MEdgeSeq_extend, METH_VARARGS,
+ "add edges to mesh"},
+ {"delete", (PyCFunction)MEdgeSeq_delete, METH_VARARGS,
+ "delete edges from mesh"},
+ {"selected", (PyCFunction)MEdgeSeq_selected, METH_NOARGS,
+ "returns a list containing indices of selected edges"},
+ {"collapse", (PyCFunction)MEdgeSeq_collapse, METH_VARARGS,
+ "collapse one or more edges to a vertex"},
+ {"addPropertyLayer",(PyCFunction)MEdgeSeq_add_layertype, METH_VARARGS,
+ "add a new property layer"},
+ {"removePropertyLayer",(PyCFunction)MEdgeSeq_del_layertype, METH_O,
+ "removes a property layer"},
+ {"renamePropertyLayer",(PyCFunction)MEdgeSeq_rename_layertype, METH_VARARGS,
+ "renames an existing property layer"},
+
+ {NULL, NULL, 0, NULL}
+};
+static PyGetSetDef BPy_MEdgeSeq_getseters[] = {
+ {"properties",
+ (getter)MEdgeSeq_PropertyList, (setter)NULL,
+ "edge property layers, read only",
+ NULL},
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+
+/************************************************************************
+ *
+ * Python MEdgeSeq_Type standard operators
+ *
+ ************************************************************************/
+
+/*****************************************************************************/
+/* Python MEdgeSeq_Type structure definition: */
+/*****************************************************************************/
+PyTypeObject MEdgeSeq_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender MEdgeSeq", /* char *tp_name; */
+ sizeof( BPy_MEdgeSeq ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ NULL, /* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* cmpfunc tp_compare; */
+ NULL, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ &MEdgeSeq_as_sequence, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ ( getiterfunc) MEdgeSeq_getIter, /* getiterfunc tp_iter; */
+ ( iternextfunc ) MEdgeSeq_nextIter, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_MEdgeSeq_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ BPy_MEdgeSeq_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+/************************************************************************
+ *
+ * Face attributes
+ *
+ ************************************************************************/
+
+static MFace * MFace_get_pointer( BPy_MFace * self )
+{
+ if( self->index >= self->mesh->totface )
+ return (MFace *)EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "MFace is no longer valid" );
+ return &self->mesh->mface[self->index];
+}
+
+/*
+ * get a face's vertices
+ */
+
+static PyObject *MFace_getVerts( BPy_MFace * self )
+{
+ PyObject *attr;
+ MFace *face = MFace_get_pointer( self );
+
+ if( !face )
+ return NULL;
+
+ attr = PyTuple_New( face->v4 ? 4 : 3 );
+
+ if( !attr )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyTuple_New() failed" );
+
+ PyTuple_SetItem( attr, 0, MVert_CreatePyObject( self->mesh, face->v1 ) );
+ PyTuple_SetItem( attr, 1, MVert_CreatePyObject( self->mesh, face->v2 ) );
+ PyTuple_SetItem( attr, 2, MVert_CreatePyObject( self->mesh, face->v3 ) );
+ if( face->v4 )
+ PyTuple_SetItem( attr, 3, MVert_CreatePyObject( self->mesh,
+ face->v4 ) );
+
+ return attr;
+}
+
+/*
+ * set a face's vertices
+ */
+
+static int MFace_setVerts( BPy_MFace * self, PyObject * args )
+{
+ BPy_MVert *v1, *v2, *v3, *v4 = NULL;
+ MFace *face = MFace_get_pointer( self );
+
+ if( !face )
+ return -1;
+
+ if( !PyArg_ParseTuple ( args, "O!O!O!|O!", &MVert_Type, &v1,
+ &MVert_Type, &v2, &MVert_Type, &v3, &MVert_Type, &v4 ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected tuple of 3 or 4 MVerts" );
+
+ if( v1->index == v2->index ||
+ v1->index == v3->index ||
+ v2->index == v3->index )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "cannot assign 2 or move verts that are the same" );
+
+ if(v4 && ( v1->index == v4->index ||
+ v2->index == v4->index ||
+ v3->index == v4->index ))
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "cannot assign 2 or move verts that are the same" );
+
+ if( v1->index >= self->mesh->totvert ||
+ v2->index >= self->mesh->totvert ||
+ v3->index >= self->mesh->totvert ||
+ (v4 &&( v4->index >= self->mesh->totvert)))
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "cannot assign verts that have been removed" );
+
+ face->v1 = v1->index;
+ face->v2 = v2->index;
+ face->v3 = v3->index;
+ if( v4 )
+ face->v4 = v4->index;
+ return 0;
+}
+
+/*
+ * get face's material index
+ */
+
+static PyObject *MFace_getMat( BPy_MFace * self )
+{
+ MFace *face = MFace_get_pointer( self );
+
+ if( !face )
+ return NULL;
+
+ return PyInt_FromLong( face->mat_nr );
+}
+
+/*
+ * set face's material index
+ */
+
+static int MFace_setMat( BPy_MFace * self, PyObject * value )
+{
+ MFace *face = MFace_get_pointer( self );
+
+ if( !face )
+ return -1; /* error is set */
+
+ return EXPP_setIValueRange( value, &face->mat_nr, 0, 15, 'b' );
+}
+
+/*
+ * get a face's index
+ */
+
+static PyObject *MFace_getIndex( BPy_MFace * self )
+{
+ MFace *face = MFace_get_pointer( self );
+
+ if( !face )
+ return NULL; /* error is set */
+
+ return PyInt_FromLong( self->index );
+}
+
+/*
+ * get face's normal index
+ */
+
+static PyObject *MFace_getNormal( BPy_MFace * self )
+{
+ float *vert[4];
+ float no[3];
+ MFace *face = MFace_get_pointer( self );
+
+ Mesh *me = self->mesh;
+
+ if( !face )
+ return NULL; /* error is set */
+
+ if MFACE_VERT_BADRANGE_CHECK(me, face)
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "one or more MFace vertices are no longer valid" );
+
+ vert[0] = me->mvert[face->v1].co;
+ vert[1] = me->mvert[face->v2].co;
+ vert[2] = me->mvert[face->v3].co;
+ if( face->v4 ) {
+ vert[3] = me->mvert[face->v4].co;
+ CalcNormFloat4( vert[0], vert[1], vert[2], vert[3], no );
+ } else
+ CalcNormFloat( vert[0], vert[1], vert[2], no );
+
+ return newVectorObject( no, 3, Py_NEW );
+}
+
+/*
+ * get face's center location
+ */
+
+static PyObject *MFace_getCent( BPy_MFace * self )
+{
+ float *vert[4];
+ float cent[3]= {0,0,0};
+ int i=3, j, k;
+ Mesh *me = self->mesh;
+ MFace *face = MFace_get_pointer( self );
+
+ if( !face )
+ return NULL; /* error is set */
+
+
+ if MFACE_VERT_BADRANGE_CHECK(me, face)
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "one or more MFace vertices are no longer valid" );
+
+ vert[0] = me->mvert[face->v1].co;
+ vert[1] = me->mvert[face->v2].co;
+ vert[2] = me->mvert[face->v3].co;
+ if( face->v4 ) {
+ vert[3] = me->mvert[face->v4].co;
+ i=4;
+ }
+
+ for (j=0;j<i;j++) {
+ for (k=0;k<3;k++) {
+ cent[k]+=vert[j][k];
+ }
+ }
+
+ for (j=0;j<3;j++) {
+ cent[j]=cent[j]/i;
+ }
+ return newVectorObject( cent, 3, Py_NEW );
+}
+
+/*
+ * get face's area
+ */
+static PyObject *MFace_getArea( BPy_MFace * self )
+{
+ float *v1,*v2,*v3,*v4;
+ MFace *face = MFace_get_pointer( self );
+ Mesh *me = self->mesh;
+
+ if( !face )
+ return NULL; /* error is set */
+
+ if MFACE_VERT_BADRANGE_CHECK(me, face)
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "one or more MFace vertices are no longer valid" );
+
+ v1 = me->mvert[face->v1].co;
+ v2 = me->mvert[face->v2].co;
+ v3 = me->mvert[face->v3].co;
+
+ if( face->v4 ) {
+ v4 = me->mvert[face->v4].co;
+ return PyFloat_FromDouble( AreaQ3Dfl(v1, v2, v3, v4));
+ } else
+ return PyFloat_FromDouble( AreaT3Dfl(v1, v2, v3));
+}
+
+/*
+ * get one of a face's mface flag bits
+ */
+
+static PyObject *MFace_getMFlagBits( BPy_MFace * self, void * type )
+{
+ MFace *face = MFace_get_pointer( self );
+
+ if( !face )
+ return NULL; /* error is set */
+
+ return EXPP_getBitfield( &face->flag, (int)((long)type & 0xff), 'b' );
+}
+
+/*
+ * set one of a face's mface flag bits
+ */
+
+static int MFace_setMFlagBits( BPy_MFace * self, PyObject * value,
+ void * type )
+{
+ MFace *face = MFace_get_pointer( self );
+
+ if( !face )
+ return -1; /* error is set */
+
+ return EXPP_setBitfield( value, &face->flag,
+ (int)((long)type & 0xff), 'b' );
+}
+
+static int MFace_setSelect( BPy_MFace * self, PyObject * value,
+ void * type_unused )
+{
+ MFace *face = MFace_get_pointer( self );
+ int param = PyObject_IsTrue( value );
+ Mesh *me;
+
+ if( !face )
+ return -1; /* error is set */
+
+ if( param == -1 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected True/False or 0/1" );
+
+ me = self->mesh;
+ if( param ) {
+ face->flag |= ME_FACE_SEL;
+ me->mvert[face->v1].flag |= SELECT;
+ me->mvert[face->v2].flag |= SELECT;
+ me->mvert[face->v3].flag |= SELECT;
+ if( face->v4 )
+ me->mvert[face->v4].flag |= SELECT;
+ }
+ else {
+ face->flag &= ~ME_FACE_SEL;
+ me->mvert[face->v1].flag &= ~SELECT;
+ me->mvert[face->v2].flag &= ~SELECT;
+ me->mvert[face->v3].flag &= ~SELECT;
+ if( face->v4 )
+ me->mvert[face->v4].flag &= ~SELECT;
+ }
+
+ if( self->mesh->mselect ) {
+ MEM_freeN( self->mesh->mselect );
+ self->mesh->mselect = NULL;
+ }
+
+ return 0;
+}
+
+/*
+ * get face's texture image
+ */
+
+static PyObject *MFace_getImage( BPy_MFace *self )
+{
+ MTFace *face;
+ if( !self->mesh->mtface )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "face has no texture values" );
+
+ if( !MFace_get_pointer( self ) )
+ return NULL;
+
+ face = &self->mesh->mtface[self->index];
+
+ if( face->tpage )
+ return Image_CreatePyObject( face->tpage );
+ else
+ Py_RETURN_NONE;
+}
+
+/*
+ * change or clear face's texture image
+ */
+
+static int MFace_setImage( BPy_MFace *self, PyObject *value )
+{
+ MTFace *face;
+
+ if( !MFace_get_pointer( self ) )
+ return -1;
+
+ if( value && value != Py_None && !BPy_Image_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected image object or None" );
+
+ if( !self->mesh->mtface )
+#if 0
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "face has no texture values" );
+#else
+ make_tfaces( self->mesh );
+#endif
+
+ face = &self->mesh->mtface[self->index];
+
+ if( value == NULL || value == Py_None )
+ face->tpage = NULL; /* should memory be freed? */
+ else {
+ face->tpage = ( ( BPy_Image * ) value )->image;
+ face->mode |= TF_TEX;
+ }
+
+ return 0;
+}
+
+#define MFACE_FLAG_BITMASK ( TF_SELECT | TF_SEL1 | \
+ TF_SEL2 | TF_SEL3 | TF_SEL4 | TF_HIDE )
+
+/*
+* get face's texture flag
+*/
+
+static PyObject *MFace_getFlag( BPy_MFace *self )
+{
+ int flag;
+ if( !self->mesh->mtface )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "face has no texture values" );
+
+ if( !MFace_get_pointer( self ) )
+ return NULL;
+
+ flag = self->mesh->mtface[self->index].flag & MFACE_FLAG_BITMASK;
+
+ /* so old scripts still work */
+ if (self->index == self->mesh->act_face)
+ flag |= TF_ACTIVE;
+
+ return PyInt_FromLong( (long)( flag ) );
+}
+
+/*
+ * set face's texture flag
+ */
+
+static int MFace_setFlag( BPy_MFace *self, PyObject *value )
+{
+ int param;
+
+ if( !self->mesh->mtface )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "face has no texture values" );
+
+ if( !MFace_get_pointer( self ) )
+ return -1;
+
+ if( !PyInt_Check ( value ) ) {
+ char errstr[128];
+ sprintf ( errstr , "expected int bitmask of 0x%04x", MFACE_FLAG_BITMASK );
+ return EXPP_ReturnIntError( PyExc_TypeError, errstr );
+ }
+ param = PyInt_AS_LONG ( value );
+
+ /* only one face can be active, so don't allow that here */
+ if( param & TF_ACTIVE )
+ param &= ~TF_ACTIVE;
+
+ if( ( param & MFACE_FLAG_BITMASK ) != param )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "invalid bit(s) set in mask" );
+
+ /* merge active setting with other new params */
+ param |= (self->mesh->mtface[self->index].flag);
+ self->mesh->mtface[self->index].flag = (char)param;
+
+ return 0;
+}
+
+/*
+ * get face's texture mode
+ */
+
+static PyObject *MFace_getMode( BPy_MFace *self )
+{
+ if( !self->mesh->mtface )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "face has no texture values" );
+
+ if( !MFace_get_pointer( self ) )
+ return NULL;
+
+ return PyInt_FromLong( self->mesh->mtface[self->index].mode );
+}
+
+/*
+ * set face's texture mode
+ */
+
+static int MFace_setMode( BPy_MFace *self, PyObject *value )
+{
+ int param;
+ static short bitmask = TF_DYNAMIC
+ | TF_TEX
+ | TF_SHAREDVERT
+ | TF_LIGHT
+ | TF_SHAREDCOL
+ | TF_TILES
+ | TF_BILLBOARD
+ | TF_TWOSIDE
+ | TF_INVISIBLE
+ | TF_OBCOL
+ | TF_BILLBOARD2
+ | TF_SHADOW
+ | TF_BMFONT;
+
+ if( !self->mesh->mtface )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "face has no texture values" );
+
+ if( !MFace_get_pointer( self ) )
+ return -1;
+
+ if( !PyInt_Check ( value ) ) {
+ char errstr[128];
+ sprintf ( errstr , "expected int bitmask of 0x%04x", bitmask );
+ return EXPP_ReturnIntError( PyExc_TypeError, errstr );
+ }
+ param = PyInt_AS_LONG ( value );
+
+ if( param == 0xffff ) /* if param is ALL, set everything but HALO */
+ param = bitmask ^ TF_BILLBOARD;
+ else if( ( param & bitmask ) != param )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "invalid bit(s) set in mask" );
+
+ /* Blender UI doesn't allow these on at the same time */
+
+ if( ( param & (TF_BILLBOARD | TF_BILLBOARD2) ) ==
+ (TF_BILLBOARD | TF_BILLBOARD2) )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "HALO and BILLBOARD cannot be enabled simultaneously" );
+
+ self->mesh->mtface[self->index].mode = (short)param;
+
+ return 0;
+}
+
+/*
+ * get face's texture transparency setting
+ */
+
+static PyObject *MFace_getTransp( BPy_MFace *self )
+{
+ if( !self->mesh->mtface )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "face has no texture values" );
+
+ if( !MFace_get_pointer( self ) )
+ return NULL;
+
+ return PyInt_FromLong( self->mesh->mtface[self->index].transp );
+}
+
+/*
+ * set face's texture transparency setting
+ */
+
+static int MFace_setTransp( BPy_MFace *self, PyObject *value )
+{
+ if( !self->mesh->mtface )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "face has no texture values" );
+
+ if( !MFace_get_pointer( self ) )
+ return -1;
+
+ return EXPP_setIValueRange( value,
+ &self->mesh->mtface[self->index].transp, TF_SOLID, TF_SUB, 'b' );
+}
+
+/*
+ * get a face's texture UV coord values
+ */
+
+static PyObject *MFace_getUV( BPy_MFace * self )
+{
+ MTFace *face;
+ PyObject *attr;
+ int length, i;
+
+ if( !self->mesh->mtface )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "face has no texture values" );
+
+ if( !MFace_get_pointer( self ) )
+ return NULL;
+
+ face = &self->mesh->mtface[self->index];
+ length = self->mesh->mface[self->index].v4 ? 4 : 3;
+ attr = PyTuple_New( length );
+
+ if( !attr )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyTuple_New() failed" );
+
+ for( i=0; i<length; ++i ) {
+ PyObject *vector = newVectorObject( face->uv[i], 2, Py_WRAP );
+ if( !vector )
+ return NULL;
+ PyTuple_SetItem( attr, i, vector );
+ }
+
+ return attr;
+}
+
+/*
+ * set a face's texture UV coord values
+ */
+
+static int MFace_setUV( BPy_MFace * self, PyObject * value )
+{
+ MTFace *face;
+ int length, i;
+
+ if( !MFace_get_pointer( self ) )
+ return -1;
+
+ if( !PySequence_Check( value ) ||
+ EXPP_check_sequence_consistency( value, &vector_Type ) != 1 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected sequence of vectors" );
+
+ length = self->mesh->mface[self->index].v4 ? 4 : 3;
+ if( length != PySequence_Size( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "size of vertex and UV sequences differ" );
+
+ if( !self->mesh->mtface )
+#if 0
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "face has no texture values" );
+#else
+ make_tfaces( self->mesh );
+#endif
+
+ face = &self->mesh->mtface[self->index];
+ for( i=0; i<length; ++i ) {
+ VectorObject *vector = (VectorObject *)PySequence_ITEM( value, i );
+ face->uv[i][0] = vector->vec[0];
+ face->uv[i][1] = vector->vec[1];
+ Py_DECREF( vector );
+ }
+ return 0;
+}
+
+/*
+ * get a face's texture UV coord select state
+ */
+
+static PyObject *MFace_getUVSel( BPy_MFace * self )
+{
+ MTFace *face;
+ PyObject *attr;
+ int length, i, mask;
+
+ if( !self->mesh->mtface )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "face has no texture values" );
+
+ if( !MFace_get_pointer( self ) )
+ return NULL;
+
+ face = &self->mesh->mtface[self->index];
+ length = self->mesh->mface[self->index].v4 ? 4 : 3;
+ attr = PyTuple_New( length );
+
+ if( !attr )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyTuple_New() failed" );
+
+ /* get coord select state, one bit at a time */
+ mask = TF_SEL1;
+ for( i=0; i<length; ++i, mask <<= 1 ) {
+ PyObject *value = PyInt_FromLong( face->flag & mask ? 1 : 0 );
+ if( !value ) {
+ Py_DECREF( attr );
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyInt_FromLong() failed" );
+ }
+ PyTuple_SetItem( attr, i, value );
+ }
+
+ return attr;
+}
+
+/*
+ * set a face's texture UV coord select state
+ */
+
+static int MFace_setUVSel( BPy_MFace * self, PyObject * value )
+{
+ MTFace *face;
+ int length, i, mask;
+
+ if( !MFace_get_pointer( self ) )
+ return -1;
+
+ if( !PySequence_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a tuple of integers" );
+
+ length = self->mesh->mface[self->index].v4 ? 4 : 3;
+ if( length != PySequence_Size( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "size of vertex and UV lists differ" );
+
+ if( !self->mesh->mtface )
+#if 0
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "face has no texture values" );
+#else
+ make_tfaces( self->mesh );
+#endif
+
+ /* set coord select state, one bit at a time */
+ face = &self->mesh->mtface[self->index];
+ mask = TF_SEL1;
+ for( i=0; i<length; ++i, mask <<= 1 ) {
+ PyObject *tmp = PySequence_GetItem( value, i ); /* adds a reference, remove below */
+ if( !PyInt_Check( tmp ) ) {
+ Py_DECREF(tmp);
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a tuple of integers" );
+ }
+ if( PyInt_AsLong( tmp ) )
+ face->flag |= mask;
+ else
+ face->flag &= ~mask;
+ Py_DECREF(tmp);
+ }
+ return 0;
+}
+
+/*
+ * get a face's vertex colors. note that if mesh->mtfaces is defined, then
+ * it takes precedent over mesh->mcol
+ */
+
+static PyObject *MFace_getCol( BPy_MFace * self )
+{
+ PyObject *attr;
+ int length, i;
+ MCol * mcol;
+
+ /* if there's no mesh color vectors or texture faces, nothing to do */
+
+ if( !self->mesh->mcol )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "face has no vertex colors" );
+
+ if( !MFace_get_pointer( self ) )
+ return NULL;
+
+ mcol = &self->mesh->mcol[self->index*4];
+
+ length = self->mesh->mface[self->index].v4 ? 4 : 3;
+ attr = PyTuple_New( length );
+
+ if( !attr )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyTuple_New() failed" );
+
+ for( i=0; i<length; ++i ) {
+ PyObject *color = MCol_CreatePyObject( &mcol[i] );
+ if( !color )
+ return NULL;
+ PyTuple_SetItem( attr, i, color );
+ }
+
+ return attr;
+}
+
+/*
+ * set a face's vertex colors
+ */
+
+static int MFace_setCol( BPy_MFace * self, PyObject *value )
+{
+ int length, i;
+ MCol * mcol;
+
+ /* if there's no mesh color vectors or texture faces, nothing to do */
+
+ if( !self->mesh->mcol )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "face has no vertex colors" );
+
+ if( !MFace_get_pointer( self ) )
+ return -1;
+
+ mcol = &self->mesh->mcol[self->index*4];
+
+ length = self->mesh->mface[self->index].v4 ? 4 : 3;
+
+ if( !PyList_Check( value ) && !PyTuple_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a sequence of MCols" );
+
+ if( EXPP_check_sequence_consistency( value, &MCol_Type ) != 1 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a sequence of MCols" );
+
+ if( PySequence_Size( value ) != length )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "incorrect number of colors for this face" );
+
+ for( i=0; i<length; ++i ) {
+ BPy_MCol *obj = (BPy_MCol *)PySequence_ITEM( value, i );
+ mcol[i].r = obj->color->r;
+ mcol[i].g = obj->color->g;
+ mcol[i].b = obj->color->b;
+ mcol[i].a = obj->color->a;
+ Py_DECREF( obj );
+ }
+ return 0;
+}
+
+
+/*
+ * get edge keys for using in a dictionary or set key
+ */
+
+static PyObject *MFace_getEdgeKeys( BPy_MFace * self )
+{
+ MFace *face = MFace_get_pointer( self );
+ PyObject *attr, *edpair;
+
+ if (!face)
+ return NULL; /* error set */
+
+ if (face->v4) {
+ attr = PyTuple_New( 4 );
+ edpair = PyTuple_New( 2 );
+ if (face->v1 > face->v2) {
+ PyTuple_SET_ITEM( edpair, 0, PyInt_FromLong(face->v2) );
+ PyTuple_SET_ITEM( edpair, 1, PyInt_FromLong(face->v1) );
+ } else {
+ PyTuple_SET_ITEM( edpair, 0, PyInt_FromLong(face->v1) );
+ PyTuple_SET_ITEM( edpair, 1, PyInt_FromLong(face->v2) );
+ }
+ PyTuple_SET_ITEM( attr, 0, edpair );
+
+ edpair = PyTuple_New( 2 );
+ if (face->v2 > face->v3) {
+ PyTuple_SET_ITEM( edpair, 0, PyInt_FromLong(face->v3) );
+ PyTuple_SET_ITEM( edpair, 1, PyInt_FromLong(face->v2) );
+ } else {
+ PyTuple_SET_ITEM( edpair, 0, PyInt_FromLong(face->v2) );
+ PyTuple_SET_ITEM( edpair, 1, PyInt_FromLong(face->v3) );
+ }
+ PyTuple_SET_ITEM( attr, 1, edpair );
+
+ edpair = PyTuple_New( 2 );
+ if (face->v3 > face->v4) {
+ PyTuple_SET_ITEM( edpair, 0, PyInt_FromLong(face->v4) );
+ PyTuple_SET_ITEM( edpair, 1, PyInt_FromLong(face->v3) );
+ } else {
+ PyTuple_SET_ITEM( edpair, 0, PyInt_FromLong(face->v3) );
+ PyTuple_SET_ITEM( edpair, 1, PyInt_FromLong(face->v4) );
+ }
+ PyTuple_SET_ITEM( attr, 2, edpair );
+
+ edpair = PyTuple_New( 2 );
+ if (face->v4 > face->v1) {
+ PyTuple_SET_ITEM( edpair, 0, PyInt_FromLong(face->v1) );
+ PyTuple_SET_ITEM( edpair, 1, PyInt_FromLong(face->v4) );
+ } else {
+ PyTuple_SET_ITEM( edpair, 0, PyInt_FromLong(face->v4) );
+ PyTuple_SET_ITEM( edpair, 1, PyInt_FromLong(face->v1) );
+ }
+ PyTuple_SET_ITEM( attr, 3, edpair );
+
+ } else {
+
+ attr = PyTuple_New( 3 );
+ edpair = PyTuple_New( 2 );
+ if (face->v1 > face->v2) {
+ PyTuple_SET_ITEM( edpair, 0, PyInt_FromLong(face->v2) );
+ PyTuple_SET_ITEM( edpair, 1, PyInt_FromLong(face->v1) );
+ } else {
+ PyTuple_SET_ITEM( edpair, 0, PyInt_FromLong(face->v1) );
+ PyTuple_SET_ITEM( edpair, 1, PyInt_FromLong(face->v2) );
+ }
+ PyTuple_SET_ITEM( attr, 0, edpair );
+
+ edpair = PyTuple_New( 2 );
+ if (face->v2 > face->v3) {
+ PyTuple_SET_ITEM( edpair, 0, PyInt_FromLong(face->v3) );
+ PyTuple_SET_ITEM( edpair, 1, PyInt_FromLong(face->v2) );
+ } else {
+ PyTuple_SET_ITEM( edpair, 0, PyInt_FromLong(face->v2) );
+ PyTuple_SET_ITEM( edpair, 1, PyInt_FromLong(face->v3) );
+ }
+ PyTuple_SET_ITEM( attr, 1, edpair );
+
+ edpair = PyTuple_New( 2 );
+ if (face->v3 > face->v1) {
+ PyTuple_SET_ITEM( edpair, 0, PyInt_FromLong(face->v1) );
+ PyTuple_SET_ITEM( edpair, 1, PyInt_FromLong(face->v3) );
+ } else {
+ PyTuple_SET_ITEM( edpair, 0, PyInt_FromLong(face->v3) );
+ PyTuple_SET_ITEM( edpair, 1, PyInt_FromLong(face->v1) );
+ }
+ PyTuple_SET_ITEM( attr, 2, edpair );
+ }
+
+ return attr;
+}
+
+
+/************************************************************************
+ *
+ * Python MFace_Type attributes get/set structure
+ *
+ ************************************************************************/
+
+static PyGetSetDef BPy_MFace_getseters[] = {
+ {"verts",
+ (getter)MFace_getVerts, (setter)MFace_setVerts,
+ "face's vertices",
+ NULL},
+ {"v",
+ (getter)MFace_getVerts, (setter)MFace_setVerts,
+ "deprecated: see 'verts'",
+ NULL},
+ {"mat",
+ (getter)MFace_getMat, (setter)MFace_setMat,
+ "face's material index",
+ NULL},
+ {"index",
+ (getter)MFace_getIndex, (setter)NULL,
+ "face's index",
+ NULL},
+ {"no",
+ (getter)MFace_getNormal, (setter)NULL,
+ "face's normal",
+ NULL},
+ {"cent",
+ (getter)MFace_getCent, (setter)NULL,
+ "face's center",
+ NULL},
+ {"area",
+ (getter)MFace_getArea, (setter)NULL,
+ "face's 3D area",
+ NULL},
+
+ {"hide",
+ (getter)MFace_getMFlagBits, (setter)MFace_setMFlagBits,
+ "face hidden in edit mode",
+ (void *)ME_HIDE},
+ {"sel",
+ (getter)MFace_getMFlagBits, (setter)MFace_setSelect,
+ "face selected in edit mode",
+ (void *)ME_FACE_SEL},
+ {"smooth",
+ (getter)MFace_getMFlagBits, (setter)MFace_setMFlagBits,
+ "face smooth enabled",
+ (void *)ME_SMOOTH},
+
+ /* attributes for texture faces (mostly, I think) */
+
+ {"col",
+ (getter)MFace_getCol, (setter)MFace_setCol,
+ "face's vertex colors",
+ NULL},
+ {"flag",
+ (getter)MFace_getFlag, (setter)MFace_setFlag,
+ "flags associated with texture faces",
+ NULL},
+ {"image",
+ (getter)MFace_getImage, (setter)MFace_setImage,
+ "image associated with texture faces",
+ NULL},
+ {"mode",
+ (getter)MFace_getMode, (setter)MFace_setMode,
+ "modes associated with texture faces",
+ NULL},
+ {"transp",
+ (getter)MFace_getTransp, (setter)MFace_setTransp,
+ "transparency of texture faces",
+ NULL},
+ {"uv",
+ (getter)MFace_getUV, (setter)MFace_setUV,
+ "face's UV coordinates",
+ NULL},
+ {"uvSel",
+ (getter)MFace_getUVSel, (setter)MFace_setUVSel,
+ "face's UV coordinates select status",
+ NULL},
+ {"edge_keys",
+ (getter)MFace_getEdgeKeys, (setter)NULL,
+ "for each edge this face uses return an ordered tuple edge pair that can be used as a key in a dictionary or set",
+ NULL},
+
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+/************************************************************************
+ *
+ * Python MFace_Type iterator (iterates over vertices)
+ *
+ ************************************************************************/
+
+/*
+ * Initialize the interator index
+ */
+
+static PyObject *MFace_getIter( BPy_MFace * self )
+{
+ if (self->iter==-1) {
+ self->iter = 0;
+ return EXPP_incr_ret ( (PyObject *) self );
+ } else {
+ BPy_MFace *seq= (BPy_MFace *)MFace_CreatePyObject(self->mesh, self->index);
+ seq->iter = 0;
+ return (PyObject *) seq;
+ }
+}
+
+/*
+ * Return next MVert. Throw an exception after the final vertex.
+ */
+
+static PyObject *MFace_nextIter( BPy_MFace * self )
+{
+ struct MFace *face = &self->mesh->mface[self->index];
+ int len = self->mesh->mface[self->index].v4 ? 4 : 3;
+
+ if( self->iter == len ) {
+ self->iter = -1;
+ return EXPP_ReturnPyObjError( PyExc_StopIteration,
+ "iterator at end" );
+ }
+
+ ++self->iter;
+ switch ( self->iter ) {
+ case 1:
+ return MVert_CreatePyObject( self->mesh, face->v1 );
+ case 2:
+ return MVert_CreatePyObject( self->mesh, face->v2 );
+ case 3:
+ return MVert_CreatePyObject( self->mesh, face->v3 );
+ default :
+ return MVert_CreatePyObject( self->mesh, face->v4 );
+ }
+}
+
+/************************************************************************
+ *
+ * Python MFace_Type methods
+ *
+ ************************************************************************/
+
+/************************************************************************
+ *
+ * Python MFace_Type standard operations
+ *
+ ************************************************************************/
+static int MFace_compare( BPy_MFace * a, BPy_MFace * b )
+{
+ return( a->mesh == b->mesh && a->index == b->index ) ? 0 : -1;
+}
+
+static PyObject *MFace_repr( BPy_MFace* self )
+{
+ MFace *face = MFace_get_pointer( self );
+
+ if( !face )
+ return NULL;
+
+ if( face->v4 )
+ return PyString_FromFormat( "[MFace (%d %d %d %d) %d]",
+ (int)face->v1, (int)face->v2,
+ (int)face->v3, (int)face->v4, (int)self->index );
+ else
+ return PyString_FromFormat( "[MFace (%d %d %d) %d]",
+ (int)face->v1, (int)face->v2,
+ (int)face->v3, (int)self->index );
+}
+
+static long MFace_hash( BPy_MFace *self )
+{
+ return (long)self->index;
+}
+
+static int MFace_len( BPy_MFace * self )
+{
+ if( self->index >= self->mesh->totface )
+ return 0;
+ return self->mesh->mface[self->index].v4 ? 4 : 3;
+}
+
+static PySequenceMethods MFace_as_sequence = {
+ ( inquiry ) MFace_len, /* sq_length */
+ ( binaryfunc ) 0, /* sq_concat */
+ ( intargfunc ) 0, /* sq_repeat */
+ ( intargfunc ) 0, /* sq_item */
+ ( intintargfunc ) 0, /* sq_slice */
+ ( intobjargproc ) 0, /* sq_ass_item */
+ ( intintobjargproc ) 0, /* sq_ass_slice */
+ 0,0,0,
+};
+
+static PyObject *MFace_getProp( BPy_MFace *self, PyObject *args)
+{
+ Mesh *me = (Mesh *)self->mesh;
+ MFace *face = MFace_get_pointer( self );
+ if( !face )
+ return NULL;
+ mesh_update_customdata_pointers(me); //!
+ return Mesh_getProperty_internal(&(me->fdata), self->index, args);
+}
+
+static PyObject *MFace_setProp( BPy_MFace *self, PyObject *args)
+{
+ Mesh *me = (Mesh *)self->mesh;
+ PyObject *obj;
+ MFace *face = MFace_get_pointer( self );
+ if( !face )
+ return NULL; /* error set */
+
+ obj = Mesh_setProperty_internal(&(me->fdata), self->index, args);
+ mesh_update_customdata_pointers(me); //!
+ return obj;
+}
+
+static struct PyMethodDef BPy_MFace_methods[] = {
+ {"getProperty", (PyCFunction)MFace_getProp, METH_O,
+ "get property indicated by name"},
+ {"setProperty", (PyCFunction)MFace_setProp, METH_VARARGS,
+ "set property indicated by name"},
+ {NULL, NULL, 0, NULL}
+};
+/************************************************************************
+ *
+ * Python MFace_Type structure definition
+ *
+ ************************************************************************/
+
+PyTypeObject MFace_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender MFace", /* char *tp_name; */
+ sizeof( BPy_MFace ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ NULL, /* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ ( cmpfunc ) MFace_compare, /* cmpfunc tp_compare; */
+ ( reprfunc ) MFace_repr, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ &MFace_as_sequence, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ ( hashfunc ) MFace_hash, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ ( getiterfunc ) MFace_getIter, /* getiterfunc tp_iter; */
+ ( iternextfunc ) MFace_nextIter, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_MFace_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ BPy_MFace_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+static PyObject *MFace_CreatePyObject( Mesh * mesh, int i )
+{
+ BPy_MFace *obj = PyObject_NEW( BPy_MFace, &MFace_Type );
+
+ if( !obj )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyObject_New() failed" );
+
+ obj->mesh = mesh;
+ obj->index = i;
+ obj->iter= -1;
+ return (PyObject *)obj;
+}
+
+/************************************************************************
+ *
+ * Face sequence
+ *
+ ************************************************************************/
+
+static int MFaceSeq_len( BPy_MFaceSeq * self )
+{
+ return self->mesh->totface;
+}
+
+static PyObject *MFaceSeq_item( BPy_MFaceSeq * self, int i )
+{
+ if( i < 0 || i >= self->mesh->totface )
+ return EXPP_ReturnPyObjError( PyExc_IndexError,
+ "array index out of range" );
+
+ return MFace_CreatePyObject( self->mesh, i );
+}
+
+static PySequenceMethods MFaceSeq_as_sequence = {
+ ( inquiry ) MFaceSeq_len, /* sq_length */
+ ( binaryfunc ) 0, /* sq_concat */
+ ( intargfunc ) 0, /* sq_repeat */
+ ( intargfunc ) MFaceSeq_item, /* sq_item */
+ ( intintargfunc ) 0, /* sq_slice */
+ ( intobjargproc ) 0, /* sq_ass_item */
+ ( intintobjargproc ) 0, /* sq_ass_slice */
+ 0,0,0,
+};
+
+/************************************************************************
+ *
+ * Python MFaceSeq_Type iterator (iterates over faces)
+ *
+ ************************************************************************/
+
+/*
+ * Initialize the interator index
+ */
+
+static PyObject *MFaceSeq_getIter( BPy_MFaceSeq * self )
+{
+ if (self->iter==-1) {
+ self->iter = 0;
+ return EXPP_incr_ret ( (PyObject *) self );
+ } else {
+ BPy_MFaceSeq *seq = (BPy_MFaceSeq *)MFaceSeq_CreatePyObject(self->mesh);
+ seq->iter = 0;
+ return (PyObject *)seq;
+ }
+}
+
+/*
+ * Return next MFace.
+ */
+
+static PyObject *MFaceSeq_nextIter( BPy_MFaceSeq * self )
+{
+ if( self->iter == self->mesh->totface ) {
+ self->iter= -1; /* not being used in a seq */
+ return EXPP_ReturnPyObjError( PyExc_StopIteration,
+ "iterator at end" );
+ }
+ return MFace_CreatePyObject( self->mesh, self->iter++ );
+}
+
+/************************************************************************
+ *
+ * Python MFaceSeq_Type methods
+ *
+ ************************************************************************/
+
+static PyObject *MFaceSeq_extend( BPy_MEdgeSeq * self, PyObject *args,
+ PyObject *keywds )
+{
+ /*
+ * (a) check input for valid edge objects, faces which consist of
+ * only three or four edges
+ * (b) check input to be sure edges form a closed face (each edge
+ * contains verts in two other different edges?)
+ *
+ * (1) build list of new faces; remove duplicates
+ * * use existing "v4=0 rule" for 3-vert faces
+ * (2) build list of existing faces for searching
+ * (3) from new face list, remove existing faces:
+ */
+
+ int len, nverts;
+ int i, j, k, new_face_count;
+ int good_faces;
+ SrchFaces *oldpair, *newpair, *tmppair, *tmppair2;
+ PyObject *tmp;
+ MFace *tmpface;
+ Mesh *mesh = self->mesh;
+ int ignore_dups = 0;
+ PyObject *return_list = NULL;
+
+ /* before we try to add faces, add edges; if it fails; exit */
+
+ tmp = MEdgeSeq_extend( self, args );
+ if( !tmp )
+ return NULL;
+ Py_DECREF( tmp );
+
+ /* process any keyword arguments */
+ if( keywds ) {
+ PyObject *res = PyDict_GetItemString( keywds, "ignoreDups" );
+ if( res ) {
+ ignore_dups = PyObject_IsTrue( res );
+ if (ignore_dups==-1) {
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "keyword argument \"ignoreDups\" expected True/False or 0/1" );
+ }
+ }
+ res = PyDict_GetItemString( keywds, "indexList" );
+ if (res) {
+ switch( PyObject_IsTrue( res ) ) {
+ case 0:
+ break;
+ case -1:
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "keyword argument \"indexList\" expected True/False or 0/1" );
+ default:
+ return_list = PyList_New( 0 );
+ }
+ }
+ }
+
+ /* make sure we get a tuple of sequences of something */
+
+ switch( PySequence_Size( args ) ) {
+ case 1: /* better be a sequence or a tuple */
+ /* if a sequence... */
+ tmp = PyTuple_GET_ITEM( args, 0 );
+ if( PySequence_Check( tmp ) ) {
+ PyObject *tmp2;
+
+ /* ignore empty sequences */
+ if( !PySequence_Size( tmp ) ) {
+ Py_RETURN_NONE;
+ }
+
+ /* if another sequence, use it */
+ tmp2 = PySequence_ITEM( tmp, 0 );
+ if( PySequence_Check( tmp2 ) )
+ args = tmp;
+ Py_INCREF( args );
+ Py_DECREF( tmp2 );
+ } else
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a sequence of sequence pairs" );
+ break;
+ case 2:
+ case 3:
+ case 4: /* two to four args may be individual verts */
+ tmp = PyTuple_GET_ITEM( args, 0 );
+ /*
+ * if first item isn't a sequence, then assume it's a bunch of MVerts
+ * and wrap inside a tuple
+ */
+ if( !PySequence_Check( tmp ) ) {
+ args = Py_BuildValue( "(O)", args );
+ if( !args )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "Py_BuildValue() failed" );
+ /*
+ * otherwise, assume it already a bunch of sequences so use as-is
+ */
+ } else {
+ Py_INCREF( args ); /* so we can safely DECREF later */
+ }
+ break;
+ default: /* anything else is definitely wrong */
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a sequence of sequence pairs" );
+ }
+
+ /* if nothing to add, just exit */
+ len = PySequence_Size( args );
+ if( len == 0 ) {
+ Py_DECREF( args );
+ Py_RETURN_NONE;
+ }
+
+ /*
+ * Since we call MEdgeSeq_extend first, we already know the input list
+ * is valid. Here we just need to count the total number of faces.
+ */
+
+ new_face_count = 0;
+ for( i = 0; i < len; ++i ) {
+ tmp = PySequence_ITEM( args, i );
+ nverts = PySequence_Size( tmp );
+ if( return_list || nverts != 2 )
+ ++new_face_count; /* new faces must have 3 or 4 verts */
+ Py_DECREF( tmp );
+ }
+
+ /* OK, commit to allocating the search structures */
+ newpair = (SrchFaces *)MEM_callocN( sizeof(SrchFaces)*new_face_count,
+ "MFacePairs" );
+
+ /* scan the input list and build the new face pair list */
+ len = PySequence_Size( args );
+ tmppair = newpair;
+
+ for( i = 0; i < len; ++i ) {
+ MFace tmpface;
+ unsigned int vert[4]={0,0,0,0};
+ unsigned char order[4]={0,1,2,3};
+ tmp = PySequence_GetItem( args, i );
+ nverts = PySequence_Size( tmp );
+
+ if( nverts == 2 ) { /* again, ignore 2-vert tuples */
+ if( return_list ) /* if returning indices, mark as deleted */
+ tmppair->v[1] = 0;
+ Py_DECREF( tmp );
+ continue;
+ }
+
+ /*
+ * get the face's vertices' indexes
+ */
+
+ for( j = 0; j < nverts; ++j ) {
+ PyObject *item = PySequence_ITEM( tmp, j );
+ if( BPy_MVert_Check( item ) )
+ vert[j] = ((BPy_MVert *)item)->index;
+ else
+ vert[j] = PyInt_AsLong( item );
+ Py_DECREF( item );
+ }
+ Py_DECREF( tmp );
+ tmpface.v1 = vert[0];
+ tmpface.v2 = vert[1];
+ tmpface.v3 = vert[2];
+ tmpface.v4 = vert[3];
+
+ /*
+ * go through some contortions to guarantee the third and fourth
+ * vertices are not index 0
+ */
+ eeek_fix( &tmpface, nverts == 4 );
+ vert[0] = tmpface.v1;
+ vert[1] = tmpface.v2;
+ vert[2] = tmpface.v3;
+ if( nverts == 3 )
+ vert[3] = tmppair->v[3] = 0;
+ else
+ vert[3] = tmpface.v4;
+
+ /*
+ * sort the verts before placing in pair list. the order of
+ * vertices in the face is very important, so keep track of
+ * the original order
+ */
+
+ for( j = nverts-1; j >= 0; --j ) {
+ for( k = 0; k < j; ++k ) {
+ if( vert[k] > vert[k+1] ) {
+ SWAP( int, vert[k], vert[k+1] );
+ SWAP( char, order[k], order[k+1] );
+ } else if( vert[k] == vert[k+1] ) {
+ break;
+ }
+ }
+ if( k < j )
+ break;
+ tmppair->v[j] = vert[j];
+ }
+ if( j >= 0 ) { /* a duplicate vertex found */
+ if( return_list ) { /* if returning index list */
+ tmppair->v[1] = 0; /* mark as deleted */
+ } else {
+ --new_face_count; /* otherwise skip */
+ continue;
+ }
+ }
+ tmppair->index = i;
+
+ /* pack order into a byte */
+ tmppair->order = order[0]|(order[1]<<2)|(order[2]<<4)|(order[3]<<6);
+ ++tmppair;
+ }
+
+ /*
+ * find duplicates in the new list and mark. if it's a duplicate,
+ * then mark by setting second vert index to 0 (a real edge won't have
+ * second vert index of 0 since verts are sorted)
+ */
+
+ good_faces = new_face_count; /* assume all faces good to start */
+
+ tmppair = newpair; /* "last good edge" */
+ tmppair2 = &tmppair[1]; /* "current candidate edge" */
+ if( !ignore_dups ) {
+
+ /* sort the new face pairs */
+ qsort( newpair, new_face_count, sizeof(SrchFaces), mface_comp );
+
+ for( i = 0; i < new_face_count; ++i ) {
+ if( mface_comp( tmppair, tmppair2 ) )
+ tmppair = tmppair2; /* last != current, so current == last */
+ else {
+ tmppair2->v[1] = 0; /* last == current, so mark as duplicate */
+ --good_faces; /* one less good face */
+ }
+ tmppair2++;
+ }
+ }
+
+ /* if mesh has faces, see if any of the new faces are already in it */
+ if( mesh->totface && !ignore_dups ) {
+ oldpair = (SrchFaces *)MEM_callocN( sizeof(SrchFaces)*mesh->totface,
+ "MFacePairs" );
+
+ tmppair = oldpair;
+ tmpface = mesh->mface;
+ for( i = 0; i < mesh->totface; ++i ) {
+ unsigned char order[4]={0,1,2,3};
+ int verts[4];
+ verts[0]=tmpface->v1;
+ verts[1]=tmpface->v2;
+ verts[2]=tmpface->v3;
+ verts[3]=tmpface->v4;
+
+ len = ( tmpface->v4 ) ? 3 : 2;
+ tmppair->v[3] = 0; /* for triangular faces */
+
+ /* sort the verts before placing in pair list here too */
+ for( j = len; j >= 0; --j ) {
+ for( k = 0; k < j; ++k )
+ if( verts[k] > verts[k+1] ) {
+ SWAP( int, verts[k], verts[k+1] );
+ SWAP( unsigned char, order[k], order[k+1] );
+ }
+ tmppair->v[j] = verts[j];
+ }
+
+ /* pack order into a byte */
+ tmppair->order = order[0]|(order[1]<<2)|(order[2]<<4)|(order[3]<<6);
+ ++tmppair;
+ ++tmpface;
+ }
+
+ /* sort the old face pairs */
+ qsort( oldpair, mesh->totface, sizeof(SrchFaces), mface_comp );
+
+ /* eliminate new faces already in the mesh */
+ tmppair = newpair;
+ for( i = good_faces; i ; ) {
+ if( tmppair->v[1] ) {
+ if( bsearch( tmppair, oldpair, mesh->totface,
+ sizeof(SrchFaces), mface_comp ) ) {
+ tmppair->v[1] = 0; /* mark as duplicate */
+ --good_faces;
+ }
+ --i;
+ }
+ tmppair++;
+ }
+ MEM_freeN( oldpair );
+ }
+
+ /* if any new faces are left, add to list */
+ if( good_faces || return_list ) {
+ int totface = mesh->totface+good_faces; /* new face count */
+ CustomData fdata;
+
+ CustomData_copy( &mesh->fdata, &fdata, CD_MASK_MESH, CD_DEFAULT, totface );
+ CustomData_copy_data( &mesh->fdata, &fdata, 0, 0, mesh->totface );
+
+ if ( !CustomData_has_layer( &fdata, CD_MFACE ) )
+ CustomData_add_layer( &fdata, CD_MFACE, CD_CALLOC, NULL, totface );
+
+ CustomData_free( &mesh->fdata, mesh->totface );
+ mesh->fdata = fdata;
+ mesh_update_customdata_pointers( mesh );
+
+ /* sort the faces back into their original input list order */
+ if( !ignore_dups )
+ qsort( newpair, new_face_count, sizeof(SrchFaces),
+ mface_index_comp );
+
+
+ /* point to the first face we're going to add */
+ tmpface = &mesh->mface[mesh->totface];
+ tmppair = newpair;
+
+ if( return_list )
+ good_faces = new_face_count; /* assume all faces good to start */
+
+ /* as we find a good face, add it */
+ while ( good_faces ) {
+ if( tmppair->v[1] ) {
+ int i;
+ unsigned int index[4];
+ unsigned char order = tmppair->order;
+
+ /* unpack the order of the vertices */
+ for( i = 0; i < 4; ++i ) {
+ index[(order & 0x03)] = i;
+ order >>= 2;
+ }
+
+ /* now place vertices in the proper order */
+ tmpface->v1 = tmppair->v[index[0]];
+ tmpface->v2 = tmppair->v[index[1]];
+ tmpface->v3 = tmppair->v[index[2]];
+ tmpface->v4 = tmppair->v[index[3]];
+
+ tmpface->flag = ME_FACE_SEL;
+
+ if( return_list ) {
+ tmp = PyInt_FromLong( mesh->totface );
+ PyList_Append( return_list, tmp );
+ Py_DECREF(tmp);
+ }
+ mesh->totface++;
+ ++tmpface;
+ --good_faces;
+ } else if( return_list ) {
+ PyList_Append( return_list, Py_None );
+ --good_faces;
+ }
+ tmppair++;
+ }
+ }
+
+ /* clean up and leave */
+ mesh_update( mesh );
+ Py_DECREF ( args );
+ MEM_freeN( newpair );
+
+ if( return_list )
+ return return_list;
+ else
+ Py_RETURN_NONE;
+}
+
+struct fourEdges
+{
+ FaceEdges *v[4];
+};
+
+static PyObject *MFaceSeq_delete( BPy_MFaceSeq * self, PyObject *args )
+{
+ unsigned int *face_table;
+ int i, len;
+ Mesh *mesh = self->mesh;
+ MFace *tmpface;
+ int face_count;
+ int edge_also = 0;
+
+ /* check for valid inputs */
+
+ if( PySequence_Size( args ) != 2 ||
+ !PyArg_ParseTuple( args, "iO", &edge_also, &args ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected and int and a sequence of ints or MFaces" );
+
+ if( !PyList_Check( args ) && !PyTuple_Check( args ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected and int and a sequence of ints or MFaces" );
+
+ /* see how many args we need to parse */
+ len = PySequence_Size( args );
+ if( len < 1 )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "sequence must contain at least one int or MFace" );
+
+ face_table = (unsigned int *)MEM_callocN( len*sizeof( unsigned int ),
+ "face_table" );
+
+ /* get the indices of faces to be removed */
+ for( i = len; i--; ) {
+ PyObject *tmp = PySequence_GetItem( args, i );
+ if( BPy_MFace_Check( tmp ) )
+ face_table[i] = ((BPy_MFace *)tmp)->index;
+ else if( PyInt_Check( tmp ) )
+ face_table[i] = PyInt_AsLong( tmp );
+ else {
+ MEM_freeN( face_table );
+ Py_DECREF( tmp );
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a sequence of ints or MFaces" );
+ }
+ Py_DECREF( tmp );
+
+ /* if index out-of-range, throw exception */
+ if( face_table[i] >= (unsigned int)mesh->totface ) {
+ MEM_freeN( face_table );
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "array index out of range" );
+ }
+ }
+
+ if( edge_also ) {
+ /*
+ * long version
+ *
+ * (1) build sorted table of all edges
+ * (2) construct face->edge lookup table for all faces
+ * face->e1 = mesh->medge[i]
+ * (3) (delete sorted table)
+ * (4) mark all edges as live
+ * (5) mark all edges for deleted faces as dead
+ * (6) mark all edges for remaining faces as live
+ * (7) delete all dead edges
+ * (8) (delete face lookup table)
+ *
+ */
+
+ FaceEdges *edge_table, *tmp_et;
+ MEdge *tmpedge;
+ FaceEdges **face_edges;
+ FaceEdges **tmp_fe;
+ struct fourEdges *fface;
+ int edge_count;
+
+ edge_table = MEM_mallocN( mesh->totedge*sizeof( FaceEdges ),
+ "edge_table" );
+
+ tmpedge = mesh->medge;
+ tmp_et = edge_table;
+
+ for( i = 0; i < mesh->totedge; ++i ) {
+ if( tmpedge->v1 < tmpedge->v2 ) {
+ tmp_et->v[0] = tmpedge->v1;
+ tmp_et->v[1] = tmpedge->v2;
+ } else {
+ tmp_et->v[0] = tmpedge->v2;
+ tmp_et->v[1] = tmpedge->v1;
+ }
+ tmp_et->index = i;
+ tmp_et->sel = 1; /* select each edge */
+ ++tmpedge;
+ ++tmp_et;
+ }
+
+ /* sort the edge pairs */
+ qsort( edge_table, mesh->totedge, sizeof(FaceEdges), faceedge_comp );
+
+ /* build face translation table, lookup edges */
+ face_edges = MEM_callocN( 4*sizeof(FaceEdges*)*mesh->totface,
+ "face_edges" );
+
+ tmp_fe = face_edges;
+ tmpface = mesh->mface;
+ for( i = mesh->totface; i--; ++tmpface ) {
+ FaceEdges *ptrs[4];
+ unsigned int verts[4];
+ int j,k;
+ FaceEdges target;
+ int len=tmpface->v4 ? 4 : 3;
+
+ ptrs[3] = NULL;
+ verts[0] = tmpface->v1;
+ verts[1] = tmpface->v2;
+ verts[2] = tmpface->v3;
+ if( len == 4 )
+ verts[3] = tmpface->v4;
+ for( j = 0; j < len; ++j ) {
+ k = (j+1) % len;
+ if( verts[j] < verts[k] ) {
+ target.v[0] = verts[j];
+ target.v[1] = verts[k];
+ } else {
+ target.v[0] = verts[k];
+ target.v[1] = verts[j];
+ }
+ ptrs[j] = bsearch( &target, edge_table, mesh->totedge,
+ sizeof(FaceEdges), faceedge_comp );
+ }
+ for( j = 0; j < 4; ++j, ++tmp_fe )
+ *tmp_fe = ptrs[j];
+ }
+
+ /* for each face, deselect each edge */
+ tmpface = mesh->mface;
+ face_count = 0;
+ for( i = len; i--; ) {
+ if( tmpface[face_table[i]].v1 != UINT_MAX ) {
+ fface = (void *)face_edges;
+ fface += face_table[i];
+ fface->v[0]->sel = 0;
+ fface->v[1]->sel = 0;
+ fface->v[2]->sel = 0;
+ if( fface->v[3] )
+ fface->v[3]->sel = 0;
+ tmpface[face_table[i]].v1 = UINT_MAX;
+ ++face_count;
+ }
+ }
+
+ /* for each face, deselect each edge */
+ tmpface = mesh->mface;
+ fface = (struct fourEdges *)face_edges;
+ for( i = mesh->totface; i--; ++tmpface, ++fface ) {
+ if( tmpface->v1 != UINT_MAX ) {
+ FaceEdges (*face)[4];
+ face = (void *)face_edges;
+ face += face_table[i];
+ fface->v[0]->sel = 1;
+ fface->v[1]->sel = 1;
+ fface->v[2]->sel = 1;
+ if( fface->v[3] )
+ fface->v[3]->sel = 1;
+ }
+ }
+
+ /* now mark the selected edges for deletion */
+
+ edge_count = 0;
+ for( i = 0; i < mesh->totedge; ++i ) {
+ if( !edge_table[i].sel ) {
+ mesh->medge[edge_table[i].index].v1 = UINT_MAX;
+ ++edge_count;
+ }
+ }
+
+ if( edge_count )
+ delete_edges( mesh, NULL, edge_count );
+
+ MEM_freeN( face_edges );
+ MEM_freeN( edge_table );
+ } else {
+ /* mark faces to delete */
+ tmpface = mesh->mface;
+ face_count = 0;
+ for( i = len; i--; )
+ if( tmpface[face_table[i]].v1 != UINT_MAX ) {
+ tmpface[face_table[i]].v1 = UINT_MAX;
+ ++face_count;
+ }
+ }
+
+ /* delete faces which have a deleted edge */
+ delete_faces( mesh, NULL, face_count );
+
+ /* clean up and return */
+ MEM_freeN( face_table );
+ mesh_update ( mesh );
+ Py_RETURN_NONE;
+}
+
+/* copied from meshtools.c - should make generic? */
+static void permutate(void *list, int num, int size, int *index)
+{
+ void *buf;
+ int len;
+ int i;
+
+ len = num * size;
+
+ buf = MEM_mallocN(len, "permutate");
+ memcpy(buf, list, len);
+
+ for (i = 0; i < num; i++) {
+ memcpy((char *)list + (i * size), (char *)buf + (index[i] * size), size);
+ }
+ MEM_freeN(buf);
+}
+
+/* this wrapps list sorting then applies back to the mesh */
+static PyObject *MFaceSeq_sort( BPy_MEdgeSeq * self, PyObject *args,
+ PyObject *keywds )
+{
+ PyObject *ret, *sort_func, *newargs;
+
+ Mesh *mesh = self->mesh;
+ PyObject *sorting_list;
+ CustomDataLayer *layer;
+ int i, *index;
+
+ /* get a list for internal use */
+ sorting_list = PySequence_List( (PyObject *)self );
+ if( !sorting_list )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyList_New() failed" );
+
+ /* create index list */
+ index = (int *) MEM_mallocN(sizeof(int) * mesh->totface, "sort faces");
+ if (!index)
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "faces.sort(...) failed to allocate memory" );
+
+ newargs = EXPP_PyTuple_New_Prepend(args, sorting_list);
+ sort_func = PyObject_GetAttrString( ((PyObject *)&PyList_Type), "sort");
+
+ ret = PyObject_Call(sort_func, newargs, keywds);
+
+ Py_DECREF(newargs);
+ Py_DECREF(sort_func);
+
+ if (ret) {
+ /* copy the faces indicies to index */
+ for (i = 0; i < mesh->totface; i++)
+ index[i] = ((BPy_MFace *)PyList_GET_ITEM(sorting_list, i))->index;
+
+ for(i = 0; i < mesh->fdata.totlayer; i++) {
+ layer = &mesh->fdata.layers[i];
+ permutate(layer->data, mesh->totface, CustomData_sizeof(layer->type), index);
+ }
+ }
+ Py_DECREF(sorting_list);
+ MEM_freeN(index);
+ return ret;
+}
+
+static PyObject *MFaceSeq_selected( BPy_MFaceSeq * self )
+{
+ int i, count;
+ Mesh *mesh = self->mesh;
+ MFace *tmpface;
+ PyObject *list;
+
+ /* first count selected faces (quicker than appending to PyList?) */
+ count = 0;
+ tmpface = mesh->mface;
+ for( i = 0; i < mesh->totface; ++i, ++tmpface )
+ if( tmpface->flag & ME_FACE_SEL )
+ ++count;
+
+ list = PyList_New( count );
+ if( !list )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyList_New() failed" );
+
+ /* next, insert selected faces into list */
+ count = 0;
+ tmpface = mesh->mface;
+ for( i = 0; i < mesh->totface; ++i, ++tmpface ) {
+ if( tmpface->flag & ME_FACE_SEL ) {
+ PyObject *tmp = PyInt_FromLong( i );
+ if( !tmp ) {
+ Py_DECREF( list );
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyInt_FromLong() failed" );
+ }
+ PyList_SET_ITEM( list, count, tmp );
+ ++count;
+ }
+ }
+ return list;
+}
+
+static PyObject *MFaceSeq_add_layertype(BPy_MFaceSeq *self, PyObject *args)
+{
+ Mesh *me = (Mesh*)self->mesh;
+ return Mesh_addPropLayer_internal(me, &(me->fdata), me->totface, args);
+}
+static PyObject *MFaceSeq_del_layertype(BPy_MFaceSeq *self, PyObject *value)
+{
+ Mesh *me = (Mesh*)self->mesh;
+ return Mesh_removePropLayer_internal(me, &(me->fdata), me->totface, value);
+}
+static PyObject *MFaceSeq_rename_layertype(BPy_MFaceSeq *self, PyObject *args)
+{
+ Mesh *me = (Mesh*)self->mesh;
+ return Mesh_renamePropLayer_internal(me,&(me->fdata),args);
+}
+static PyObject *MFaceSeq_PropertyList(BPy_MFaceSeq *self)
+{
+ Mesh *me = (Mesh*)self->mesh;
+ return Mesh_propList_internal(&(me->fdata));
+}
+
+static struct PyMethodDef BPy_MFaceSeq_methods[] = {
+ {"extend", (PyCFunction)MFaceSeq_extend, METH_VARARGS|METH_KEYWORDS,
+ "add faces to mesh"},
+ {"delete", (PyCFunction)MFaceSeq_delete, METH_VARARGS,
+ "delete faces from mesh"},
+ {"sort", (PyCFunction)MFaceSeq_sort, METH_VARARGS|METH_KEYWORDS,
+ "sort the faces using list sorts syntax"},
+ {"selected", (PyCFunction)MFaceSeq_selected, METH_NOARGS,
+ "returns a list containing indices of selected faces"},
+ {"addPropertyLayer",(PyCFunction)MFaceSeq_add_layertype, METH_VARARGS,
+ "add a new property layer"},
+ {"removePropertyLayer",(PyCFunction)MFaceSeq_del_layertype, METH_O,
+ "removes a property layer"},
+ {"renamePropertyLayer",(PyCFunction)MFaceSeq_rename_layertype, METH_VARARGS,
+ "renames an existing property layer"},
+ {NULL, NULL, 0, NULL}
+};
+static PyGetSetDef BPy_MFaceSeq_getseters[] = {
+ {"properties",
+ (getter)MFaceSeq_PropertyList, (setter)NULL,
+ "vertex property layers, read only",
+ NULL},
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+
+/************************************************************************
+ *
+ * Python MFaceSeq_Type standard operations
+ *
+ ************************************************************************/
+
+/*****************************************************************************/
+/* Python MFaceSeq_Type structure definition: */
+/*****************************************************************************/
+PyTypeObject MFaceSeq_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender MFaceSeq", /* char *tp_name; */
+ sizeof( BPy_MFaceSeq ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ NULL, /* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* cmpfunc tp_compare; */
+ NULL, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ &MFaceSeq_as_sequence, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ ( getiterfunc )MFaceSeq_getIter, /* getiterfunc tp_iter; */
+ ( iternextfunc )MFaceSeq_nextIter, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_MFaceSeq_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ BPy_MFaceSeq_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+/************************************************************************
+ *
+ * Python BPy_Mesh methods
+ *
+ ************************************************************************/
+
+static PyObject *Mesh_calcNormals( BPy_Mesh * self )
+{
+ Mesh *mesh = self->mesh;
+
+ mesh_calc_normals( mesh->mvert, mesh->totvert, mesh->mface,
+ mesh->totface, NULL );
+ Py_RETURN_NONE;
+}
+
+static PyObject *Mesh_vertexShade( BPy_Mesh * self )
+{
+ Base *base = FIRSTBASE;
+
+ if( G.obedit )
+ return EXPP_ReturnPyObjError(PyExc_RuntimeError,
+ "can't shade vertices while in edit mode" );
+
+ while( base ) {
+ if( base->object->type == OB_MESH &&
+ base->object->data == self->mesh ) {
+ base->flag |= SELECT;
+ set_active_base( base );
+ make_vertexcol(1);
+ countall();
+ Py_RETURN_NONE;
+ }
+ base = base->next;
+ }
+ return EXPP_ReturnPyObjError(PyExc_RuntimeError,
+ "object not found in baselist!" );
+}
+
+/*
+ * force display list update
+ */
+
+static PyObject *Mesh_Update( BPy_Mesh * self, PyObject *args, PyObject *kwd )
+{
+
+ char *blockname= NULL;
+ static char *kwlist[] = {"key", NULL};
+
+ if( !PyArg_ParseTupleAndKeywords(args, kwd, "|s", kwlist, &blockname) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "Expected nothing or the name of a shapeKey");
+
+ if (blockname) {
+ Mesh *me = self->mesh;
+ MVert *mv = me->mvert;
+ Key *key= me->key;
+ KeyBlock *kb;
+ float (*co)[3];
+ int i;
+
+ if (!key)
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "Cannot update the key for this mesh, it has no shape keys");
+
+ for (kb = key->block.first; kb; kb=kb->next)
+ if (strcmp(blockname, kb->name)==0)
+ break;
+
+ if (!kb)
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "This requested key to update does not exist");
+
+ for(i=0, co= kb->data; i<me->totvert; i++, mv++, co++)
+ VECCOPY(*co, mv->co);
+ } else {
+ /* Normal operation */
+ mesh_update( self->mesh );
+ }
+ Py_RETURN_NONE;
+}
+
+/*
+ * search for a single edge in mesh's edge list
+ */
+
+static PyObject *Mesh_findEdge( BPy_Mesh * self, PyObject *args )
+{
+ int i;
+ unsigned int v1, v2;
+ PyObject *tmp;
+ MEdge *edge = self->mesh->medge;
+
+ if( EXPP_check_sequence_consistency( args, &MVert_Type ) == 1 &&
+ PySequence_Size( args ) == 2 ) {
+ tmp = PyTuple_GET_ITEM( args, 0 );
+ v1 = ((BPy_MVert *)tmp)->index;
+ tmp = PyTuple_GET_ITEM( args, 1 );
+ v2 = ((BPy_MVert *)tmp)->index;
+ } else if( PyArg_ParseTuple( args, "ii", &v1, &v2 ) ) {
+ if( (int)v1 >= self->mesh->totvert || (int)v2 >= self->mesh->totvert )
+ return EXPP_ReturnPyObjError( PyExc_IndexError,
+ "index out of range" );
+ } else
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "expected tuple of two ints or MVerts" );
+
+ for( i = 0; i < self->mesh->totedge; ++i ) {
+ if( ( edge->v1 == v1 && edge->v2 == v2 )
+ || ( edge->v1 == v2 && edge->v2 == v1 ) ) {
+ tmp = PyInt_FromLong( i );
+ if( tmp )
+ return tmp;
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyInt_FromLong() failed" );
+ }
+ ++edge;
+ }
+ Py_RETURN_NONE;
+}
+
+/*
+ * search for a group of edges in mesh's edge list
+ */
+
+static PyObject *Mesh_findEdges( PyObject * self, PyObject *args )
+{
+ int len;
+ int i;
+ SrchEdges *oldpair, *tmppair, target, *result;
+ PyObject *list, *tmp;
+ BPy_MVert *v1, *v2;
+ unsigned int index1, index2;
+ MEdge *tmpedge;
+ Mesh *mesh = ((BPy_Mesh *)self)->mesh;
+
+ /* if no edges, nothing to do */
+
+ if( !mesh->totedge )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "mesh has no edges" );
+
+ /* make sure we get a sequence of tuples of something */
+
+ tmp = PyTuple_GET_ITEM( args, 0 );
+ switch( PySequence_Size ( args ) ) {
+ case 1: /* better be a list or a tuple */
+ if( !PySequence_Check ( tmp ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a sequence of tuple int or MVert pairs" );
+ args = tmp;
+ Py_INCREF( args ); /* so we can safely DECREF later */
+ break;
+ case 2: /* take any two args and put into a tuple */
+ if( PyTuple_Check( tmp ) )
+ Py_INCREF( args ); /* if first arg is a tuple, assume both are */
+ else {
+ args = Py_BuildValue( "((OO))", tmp, PyTuple_GET_ITEM( args, 1 ) );
+ if( !args )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "Py_BuildValue() failed" );
+ }
+ break;
+ default: /* anything else is definitely wrong */
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a sequence of tuple pairs" );
+ }
+
+ len = PySequence_Size( args );
+ if( len == 0 ) {
+ Py_DECREF( args );
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "expected at least one tuple" );
+ }
+
+ /* if a single edge, handle the simpler way */
+ if( len == 1 ) {
+ PyObject *result;
+ tmp = PySequence_GetItem( args, 0 );
+ result = Mesh_findEdge( (BPy_Mesh *)self, tmp );
+ Py_DECREF( tmp );
+ Py_DECREF( args );
+ return result;
+ }
+
+ /* build a list of all edges so we can search */
+ oldpair = (SrchEdges *)MEM_callocN( sizeof(SrchEdges)*mesh->totedge,
+ "MEdgePairs" );
+
+ tmppair = oldpair;
+ tmpedge = mesh->medge;
+ for( i = 0; i < mesh->totedge; ++i ) {
+ if( tmpedge->v1 < tmpedge->v2 ) {
+ tmppair->v[0] = tmpedge->v1;
+ tmppair->v[1] = tmpedge->v2;
+ } else {
+ tmppair->v[0] = tmpedge->v2;
+ tmppair->v[1] = tmpedge->v1;
+ }
+ tmppair->index = i;
+ ++tmpedge;
+ ++tmppair;
+ }
+
+ /* sort the old edge pairs */
+ qsort( oldpair, mesh->totedge, sizeof(SrchEdges), medge_comp );
+
+ list = PyList_New( len );
+ if( !len )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyList_New() failed" );
+
+ /* scan the input list, find vert pairs, then search the edge list */
+
+ for( i = 0; i < len; ++i ) {
+ tmp = PySequence_GetItem( args, i );
+ if( !PyTuple_Check( tmp ) || PyTuple_Size( tmp ) != 2 ) {
+ MEM_freeN( oldpair );
+ Py_DECREF( tmp );
+ Py_DECREF( args );
+ Py_DECREF( list );
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "expected tuple pair" );
+ }
+
+ /* get objects, check that they are both MVerts of this mesh */
+ v1 = (BPy_MVert *)PyTuple_GET_ITEM( tmp, 0 );
+ v2 = (BPy_MVert *)PyTuple_GET_ITEM( tmp, 1 );
+ Py_DECREF ( tmp );
+ if( BPy_MVert_Check( v1 ) && BPy_MVert_Check( v2 ) ) {
+ if( v1->data != (void *)mesh || v2->data != (void *)mesh ) {
+ MEM_freeN( oldpair );
+ Py_DECREF( args );
+ Py_DECREF( list );
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "one or both MVerts do not belong to this mesh" );
+ }
+ index1 = v1->index;
+ index2 = v2->index;
+ } else if( PyInt_Check( v1 ) && PyInt_Check( v2 ) ) {
+ index1 = PyInt_AsLong( (PyObject *)v1 );
+ index2 = PyInt_AsLong( (PyObject *)v2 );
+ if( (int)index1 >= mesh->totvert
+ || (int)index2 >= mesh->totvert ) {
+ MEM_freeN( oldpair );
+ Py_DECREF( args );
+ Py_DECREF( list );
+ return EXPP_ReturnPyObjError( PyExc_IndexError,
+ "index out of range" );
+ }
+ } else {
+ MEM_freeN( oldpair );
+ Py_DECREF( args );
+ Py_DECREF( list );
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "expected tuple to contain MVerts" );
+ }
+
+ /* sort verts into order */
+ if( index1 < index2 ) {
+ target.v[0] = index1;
+ target.v[1] = index2;
+ } else {
+ target.v[0] = index2;
+ target.v[1] = index1;
+ }
+
+ /* search edge list for a match; result is index or None */
+ result = bsearch( &target, oldpair, mesh->totedge,
+ sizeof(SrchEdges), medge_comp );
+ if( result )
+ tmp = PyInt_FromLong( result->index );
+ else
+ tmp = EXPP_incr_ret( Py_None );
+ if( !tmp ) {
+ MEM_freeN( oldpair );
+ Py_DECREF( args );
+ Py_DECREF( list );
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyInt_FromLong() failed" );
+ }
+ PyList_SET_ITEM( list, i, tmp );
+ }
+
+ MEM_freeN( oldpair );
+ Py_DECREF ( args );
+ return list;
+}
+
+/*
+ * replace mesh data with mesh data from another object
+ */
+
+
+static PyObject *Mesh_getFromObject( BPy_Mesh * self, PyObject * args )
+{
+ Object *ob = NULL;
+ PyObject *object_arg;
+ ID tmpid;
+ Mesh *tmpmesh;
+ Curve *tmpcu = NULL;
+ DerivedMesh *dm;
+ Object *tmpobj = NULL;
+ int cage = 0, render = 0, i;
+
+ if( !PyArg_ParseTuple( args, "O|ii", &object_arg, &cage, &render ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected object or string and optional integer arguments" );
+
+ if ( PyString_Check( object_arg ) ) {
+ char *name;
+ name = PyString_AsString ( object_arg );
+ ob = ( Object * ) GetIdFromList( &( G.main->object ), name );
+ if( !ob )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError, name );
+ } else if ( BPy_Object_Check(object_arg) ) {
+ ob = (( BPy_Object * ) object_arg)->object;
+ } else {
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected object or string and optional integer arguments" );
+ }
+
+ if( cage != 0 && cage != 1 )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "cage value must be 0 or 1" );
+
+
+
+ /* perform the mesh extraction based on type */
+ switch (ob->type) {
+ case OB_FONT:
+ case OB_CURVE:
+ case OB_SURF:
+ /* copies object and modifiers (but not the data) */
+ tmpobj= copy_object( ob );
+ tmpcu = (Curve *)tmpobj->data;
+ tmpcu->id.us--;
+
+ /* if getting the original caged mesh, delete object modifiers */
+ if( cage )
+ object_free_modifiers(tmpobj);
+
+ /* copies the data */
+ tmpobj->data = copy_curve( (Curve *) ob->data );
+
+#if 0
+ /* copy_curve() sets disp.first null, so currently not need */
+ {
+ Curve *cu;
+ cu = (Curve *)tmpobj->data;
+ if( cu->disp.first )
+ MEM_freeN( cu->disp.first );
+ cu->disp.first = NULL;
+ }
+
+#endif
+
+ /* get updated display list, and convert to a mesh */
+ makeDispListCurveTypes( tmpobj, 0 );
+ nurbs_to_mesh( tmpobj );
+
+ /* nurbs_to_mesh changes the type tp a mesh, check it worked */
+ if (tmpobj->type != OB_MESH) {
+ free_libblock_us( &G.main->object, tmpobj );
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "cant convert curve to mesh. Does the curve have any segments?" );
+ }
+ tmpmesh = tmpobj->data;
+ free_libblock_us( &G.main->object, tmpobj );
+ break;
+ case OB_MBALL:
+ /* metaballs don't have modifiers, so just convert to mesh */
+ ob = find_basis_mball( ob );
+ tmpmesh = add_mesh("Mesh");
+ mball_to_mesh( &ob->disp, tmpmesh );
+
+ break;
+ case OB_MESH:
+ /* copies object and modifiers (but not the data) */
+ if (cage) {
+ /* copies the data */
+ tmpmesh = copy_mesh( ob->data );
+ /* if not getting the original caged mesh, get final derived mesh */
+ } else {
+ /* Make a dummy mesh, saves copying */
+
+ /* Write the display mesh into the dummy mesh */
+ if (render)
+ dm = mesh_create_derived_render( ob, CD_MASK_MESH );
+ else
+ dm = mesh_create_derived_view( ob, CD_MASK_MESH );
+
+ tmpmesh = add_mesh( "Mesh" );
+ DM_to_mesh( dm, tmpmesh );
+ dm->release( dm );
+ }
+
+ break;
+ default:
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "Object does not have geometry data" );
+ }
+
+ /* free mesh data in the original */
+ free_mesh( self->mesh );
+ /* save a copy of our ID, dup the temporary mesh, restore the ID */
+ tmpid = self->mesh->id;
+ memcpy( self->mesh, tmpmesh, sizeof( Mesh ) );
+ self->mesh->id = tmpid;
+
+ /* if mesh has keys, make sure they point back to this mesh */
+ if( self->mesh->key )
+ self->mesh->key->from = (ID *)self->mesh;
+
+
+
+ /* Copy materials to new object */
+ switch (ob->type) {
+ case OB_SURF:
+ self->mesh->totcol = tmpcu->totcol;
+
+ /* free old material list (if it exists) and adjust user counts */
+ if( tmpcu->mat ) {
+ for( i = tmpcu->totcol; i-- > 0; ) {
+
+ /* are we an object material or data based? */
+ if (ob->colbits & 1<<i) {
+ self->mesh->mat[i] = ob->mat[i];
+ ob->mat[i]->id.us++;
+ tmpmesh->mat[i]->id.us--;
+ } else {
+ self->mesh->mat[i] = tmpcu->mat[i];
+ if (self->mesh->mat[i]) {
+ tmpmesh->mat[i]->id.us++;
+ }
+ }
+ }
+ }
+ break;
+
+#if 0
+ /* Crashes when assigning the new material, not sure why */
+ case OB_MBALL:
+ tmpmb = (MetaBall *)ob->data;
+ self->mesh->totcol = tmpmb->totcol;
+
+ /* free old material list (if it exists) and adjust user counts */
+ if( tmpmb->mat ) {
+ for( i = tmpmb->totcol; i-- > 0; ) {
+ self->mesh->mat[i] = tmpmb->mat[i]; /* CRASH HERE ??? */
+ if (self->mesh->mat[i]) {
+ tmpmb->mat[i]->id.us++;
+ }
+ }
+ }
+ break;
+#endif
+
+ case OB_MESH:
+ if (!cage) {
+ Mesh *origmesh= ob->data;
+ self->mesh->flag= origmesh->flag;
+ self->mesh->mat = MEM_dupallocN(origmesh->mat);
+ self->mesh->totcol = origmesh->totcol;
+ self->mesh->smoothresh= origmesh->smoothresh;
+ if( origmesh->mat ) {
+ for( i = origmesh->totcol; i-- > 0; ) {
+ /* are we an object material or data based? */
+ if (ob->colbits & 1<<i) {
+ self->mesh->mat[i] = ob->mat[i];
+
+ if (ob->mat[i])
+ ob->mat[i]->id.us++;
+ if (origmesh->mat[i])
+ origmesh->mat[i]->id.us--;
+ } else {
+ self->mesh->mat[i] = origmesh->mat[i];
+
+ if (origmesh->mat[i])
+ origmesh->mat[i]->id.us++;
+ }
+ }
+ }
+ }
+ break;
+ } /* end copy materials */
+
+
+
+ /* remove the temporary mesh */
+ BLI_remlink( &G.main->mesh, tmpmesh );
+ MEM_freeN( tmpmesh );
+
+ /* make sure materials get updated in objects */
+ test_object_materials( ( ID * ) self->mesh );
+
+ mesh_update( self->mesh );
+ Py_RETURN_NONE;
+}
+
+/*
+ * apply a transform to the mesh's vertices
+ *
+ * WARNING: unlike NMesh, this method ALWAYS changes the original mesh
+ */
+
+static PyObject *Mesh_transform( BPy_Mesh *self, PyObject *args, PyObject *kwd )
+{
+ Mesh *mesh = self->mesh;
+ MVert *mvert;
+ /*PyObject *pymat = NULL;*/
+ MatrixObject *bpymat=NULL;
+ int i, recalc_normals = 0, selected_only = 0;
+
+ static char *kwlist[] = {"matrix", "recalc_normals", "selected_only", NULL};
+
+ if( !PyArg_ParseTupleAndKeywords(args, kwd, "|O!ii", kwlist,
+ &matrix_Type, &bpymat, &recalc_normals, &selected_only) ) {
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "matrix must be a 4x4 transformation matrix\n"
+ "for example as returned by object.matrixWorld\n"
+ "and optionaly keyword bools, recalc_normals and selected_only\n");
+ }
+
+ if (!bpymat)
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "the first argument must be a matrix or\n"
+ "matrix passed as a keyword argument\n");
+
+
+ /*bpymat = ( MatrixObject * ) pymat;*/
+
+ if( bpymat->colSize != 4 || bpymat->rowSize != 4 )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "matrix must be a 4x4 transformation matrix\n"
+ "for example as returned by object.getMatrix()" );
+
+ /* loop through all the verts and transform by the supplied matrix */
+ mvert = mesh->mvert;
+ if (selected_only) {
+ for( i = 0; i < mesh->totvert; i++, mvert++ ) {
+ if (mvert->flag & SELECT) {
+ Mat4MulVecfl( (float(*)[4])*bpymat->matrix, mvert->co );
+ }
+ }
+ } else {
+ for( i = 0; i < mesh->totvert; i++, mvert++ ) {
+ Mat4MulVecfl( (float(*)[4])*bpymat->matrix, mvert->co );
+ }
+ }
+
+ if( recalc_normals ) {
+ /* loop through all the verts and transform normals by the inverse
+ * of the transpose of the supplied matrix */
+ float invmat[4][4], vec[3], nx, ny, nz;
+
+ /*
+ * we only need to invert a 3x3 submatrix, because the 4th component of
+ * affine vectors is 0, but Mat4Invert reports non invertible matrices
+ */
+
+ if (!Mat4Invert((float(*)[4])*invmat, (float(*)[4])*bpymat->matrix))
+ return EXPP_ReturnPyObjError (PyExc_AttributeError,
+ "given matrix is not invertible");
+
+ /*
+ * since normal is stored as shorts, convert to float
+ */
+
+ mvert = mesh->mvert;
+ for( i = 0; i < mesh->totvert; i++, mvert++ ) {
+ nx= vec[0] = (float)(mvert->no[0] / 32767.0);
+ ny= vec[1] = (float)(mvert->no[1] / 32767.0);
+ nz= vec[2] = (float)(mvert->no[2] / 32767.0);
+ vec[0] = nx*invmat[0][0] + ny*invmat[0][1] + nz*invmat[0][2];
+ vec[1] = nx*invmat[1][0] + ny*invmat[1][1] + nz*invmat[1][2];
+ vec[2] = nx*invmat[2][0] + ny*invmat[2][1] + nz*invmat[2][2];
+ Normalize( vec );
+ mvert->no[0] = (short)(vec[0] * 32767.0);
+ mvert->no[1] = (short)(vec[1] * 32767.0);
+ mvert->no[2] = (short)(vec[2] * 32767.0);
+ }
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Mesh_addVertGroup( PyObject * self, PyObject * value )
+{
+ char *groupStr = PyString_AsString(value);
+ struct Object *object;
+
+ if( !groupStr )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument" );
+
+ object = ( ( BPy_Mesh * ) self )->object;
+
+ if( object == NULL )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "mesh not linked to an object" );
+
+ /* add_defgroup_name clamps the name to 32, make sure that dosnt change */
+ add_defgroup_name( object, groupStr );
+
+ EXPP_allqueue( REDRAWBUTSALL, 1 );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Mesh_removeVertGroup( PyObject * self, PyObject * value )
+{
+ char *groupStr = PyString_AsString(value);
+ struct Object *object;
+ int nIndex;
+ bDeformGroup *pGroup;
+
+ if( !groupStr )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument" );
+
+ if( ( ( BPy_Mesh * ) self )->object == NULL )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "mesh must be linked to an object first..." );
+
+ object = ( ( BPy_Mesh * ) self )->object;
+
+ pGroup = get_named_vertexgroup( object, groupStr );
+ if( pGroup == NULL )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "group does not exist!" );
+
+ nIndex = get_defgroup_num( object, pGroup );
+ if( nIndex == -1 )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "no deform groups assigned to mesh" );
+ nIndex++;
+ object->actdef = (unsigned short)nIndex;
+
+ del_defgroup( object );
+
+ EXPP_allqueue( REDRAWBUTSALL, 1 );
+
+ Py_RETURN_NONE;
+}
+
+extern void add_vert_defnr( Object * ob, int def_nr, int vertnum, float weight,
+ int assignmode );
+extern void remove_vert_def_nr (Object *ob, int def_nr, int vertnum);
+
+static PyObject *Mesh_assignVertsToGroup( BPy_Mesh * self, PyObject * args )
+{
+ char *groupStr;
+ int nIndex;
+ bDeformGroup *pGroup;
+ PyObject *listObject;
+ int tempInt;
+ int x;
+ int assignmode = WEIGHT_REPLACE;
+ float weight = 1.0;
+ Object *object = self->object;
+ Mesh *mesh = self->mesh;
+
+ if( !object )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "mesh must be linked to an object first" );
+
+ if( ((Mesh *)object->data) != mesh )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "object no longer linked to this mesh" );
+
+ if( !PyArg_ParseTuple ( args, "sO!fi", &groupStr, &PyList_Type,
+ &listObject, &weight, &assignmode) ) {
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string, list, float, string arguments" );
+ }
+
+ pGroup = get_named_vertexgroup( object, groupStr );
+ if( pGroup == NULL )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "group does not exist!" );
+
+ nIndex = get_defgroup_num( object, pGroup );
+ if( nIndex == -1 )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "no deform groups assigned to mesh" );
+
+
+ if( assignmode != WEIGHT_REPLACE && assignmode != WEIGHT_ADD &&
+ assignmode != WEIGHT_SUBTRACT )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "bad assignment mode" );
+
+ /* makes a set of dVerts corresponding to the mVerts */
+ if( !mesh->dvert )
+ create_dverts( &mesh->id );
+
+ /* loop list adding verts to group */
+ for( x = 0; x < PyList_Size( listObject ); x++ ) {
+ if( !PyArg_Parse ( PyList_GetItem( listObject, x ), "i", &tempInt ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "python list integer not parseable" );
+
+ if( tempInt < 0 || tempInt >= mesh->totvert )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "bad vertex index in list" );
+
+ add_vert_defnr( object, nIndex, tempInt, weight, assignmode );
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Mesh_removeVertsFromGroup( BPy_Mesh * self, PyObject * args )
+{
+ /* not passing a list will remove all verts from group */
+
+ char *groupStr;
+ int nIndex;
+ Object *object;
+ Mesh *mesh;
+ bDeformGroup *pGroup;
+ PyObject *listObject = NULL;
+ int tempInt;
+ int i;
+
+ object = self->object;
+ mesh = self->mesh;
+ if( !object )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "mesh must be linked to an object first" );
+
+ if( ((Mesh *)object->data) != mesh )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "object no longer linked to this mesh" );
+
+ if( !PyArg_ParseTuple
+ ( args, "s|O!", &groupStr, &PyList_Type, &listObject ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string and optional list argument" );
+
+ if( !mesh->dvert )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "this mesh contains no deform vertices" );
+
+ pGroup = get_named_vertexgroup( object, groupStr );
+ if( pGroup == NULL )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "group does not exist!" );
+
+ nIndex = get_defgroup_num( object, pGroup );
+ if( nIndex == -1 )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "no deform groups assigned to mesh" );
+
+ /* get out of edit mode */
+
+ if( G.obedit ) {
+ load_editMesh();
+ free_editMesh(G.editMesh);
+ G.obedit = NULL;
+ }
+
+ if( !listObject ) /* no list given */
+ for( i = 0; i < mesh->totvert; i++ )
+ remove_vert_def_nr( object, nIndex, i );
+ else /* loop list removing verts to group */
+ for( i = 0; i < PyList_Size( listObject ); i++ ) {
+ if( !PyArg_Parse( PyList_GetItem( listObject, i ), "i", &tempInt ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "python list integer not parseable" );
+
+ if( tempInt < 0 || tempInt >= mesh->totvert )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "bad vertex index in list" );
+
+ remove_vert_def_nr( object, nIndex, tempInt );
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Mesh_getVertsFromGroup( BPy_Mesh* self, PyObject * args )
+{
+ /*
+ * not passing a list will return all verts from group
+ * passing indecies not part of the group will not return data in pyList
+ * can be used as a index/group check for a vertex
+ */
+
+ char *groupStr;
+ int nIndex;
+ bDeformGroup *pGroup;
+ MDeformVert *dvert;
+ int i, k, count;
+ PyObject *vertexList;
+ Object *object;
+ Mesh *mesh;
+
+ int num = 0;
+ int weightRet = 0;
+ PyObject *listObject = NULL;
+
+ object = self->object;
+ mesh = self->mesh;
+ if( !object )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "mesh must be linked to an object first" );
+
+ if( ((Mesh *)object->data) != mesh )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "object no longer linked to this mesh" );
+
+ if( !PyArg_ParseTuple( args, "s|iO!", &groupStr, &weightRet,
+ &PyList_Type, &listObject ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string and optional int and list arguments" );
+
+ if( weightRet < 0 || weightRet > 1 )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "return weights flag must be 0 or 1" );
+
+ if( !mesh->dvert )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "this mesh contains no deform vertices" );
+
+ pGroup = get_named_vertexgroup( object, groupStr );
+ if( !pGroup )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "group does not exist!" );
+
+ nIndex = get_defgroup_num( object, pGroup );
+ if( nIndex == -1 )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "no deform groups assigned to mesh" );
+
+ count = 0;
+
+ if( !listObject ) { /* do entire group */
+ vertexList = PyList_New( mesh->totvert );
+ if( !vertexList )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "getVertsFromGroup: can't create pylist!" );
+
+ dvert = mesh->dvert;
+ for( num = 0; num < mesh->totvert; num++, ++dvert ) {
+ for( i = 0; i < dvert->totweight; i++ ) {
+ if( dvert->dw[i].def_nr == nIndex ) {
+ PyObject *attr;
+ if( weightRet )
+ attr = Py_BuildValue( "(i,f)", num,
+ dvert->dw[i].weight );
+ else
+ attr = PyInt_FromLong ( num );
+ PyList_SetItem( vertexList, count, attr );
+ count++;
+ }
+ }
+ }
+
+ if (count < mesh->totvert)
+ PyList_SetSlice(vertexList, count, mesh->totvert, NULL);
+
+ } else { /* do individual vertices */
+ int listObjectLen = PyList_Size( listObject );
+
+ vertexList = PyList_New( listObjectLen );
+ for( i = 0; i < listObjectLen; i++ ) {
+ PyObject *attr = NULL;
+
+ num = PyInt_AsLong( PyList_GetItem( listObject, i ) );
+ if (num == -1) {/* -1 is an error AND an invalid range, we dont care which */
+ Py_DECREF(vertexList);
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "python list integer not parseable" );
+ }
+
+ if( num < 0 || num >= mesh->totvert ) {
+ Py_DECREF(vertexList);
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "bad vertex index in list" );
+ }
+ dvert = mesh->dvert + num;
+ for( k = 0; k < dvert->totweight; k++ ) {
+ if( dvert->dw[k].def_nr == nIndex ) {
+ if( weightRet )
+ attr = Py_BuildValue( "(i,f)", num,
+ dvert->dw[k].weight );
+ else
+ attr = PyInt_FromLong ( num );
+ PyList_SetItem( vertexList, count, attr );
+ count++;
+ }
+ }
+ }
+ if (count < listObjectLen)
+ PyList_SetSlice(vertexList, count, listObjectLen, NULL);
+ }
+
+ return vertexList;
+}
+
+static PyObject *Mesh_renameVertGroup( BPy_Mesh * self, PyObject * args )
+{
+ char *oldGr = NULL;
+ char *newGr = NULL;
+ bDeformGroup *defGroup;
+ Object *object;
+ Mesh *mesh;
+
+ object = self->object;
+ mesh = self->mesh;
+ if( !object )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "mesh must be linked to an object first" );
+
+ if( ((Mesh *)object->data) != mesh )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "object no longer linked to this mesh" );
+
+ if( !PyArg_ParseTuple( args, "ss", &oldGr, &newGr ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected two string arguments" );
+
+ defGroup = get_named_vertexgroup( object, oldGr );
+ if( !defGroup )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't find the vertex group" );
+
+ PyOS_snprintf( defGroup->name, 32, newGr );
+ unique_vertexgroup_name( defGroup, object );
+
+ Py_RETURN_NONE;
+}
+
+
+
+
+static PyObject *Mesh_getVertGroupNames( BPy_Mesh * self )
+{
+ bDeformGroup *defGroup;
+ PyObject *list;
+ Object *obj = self->object;
+ Mesh *mesh = self->mesh;
+ int count;
+
+ if( !obj )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "mesh must be linked to an object first" );
+
+ if( ((Mesh *)obj->data) != mesh )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "object no longer linked to this mesh" );
+
+ if( !obj )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "This mesh must be linked to an object" );
+
+ count = 0;
+ for( defGroup = obj->defbase.first; defGroup; defGroup = defGroup->next )
+ ++count;
+
+ list = PyList_New( count );
+ count = 0;
+ for( defGroup = obj->defbase.first; defGroup; defGroup = defGroup->next )
+ PyList_SET_ITEM( list, count++,
+ PyString_FromString( defGroup->name ) );
+
+ return list;
+}
+
+static PyObject *Mesh_getVertexInfluences( BPy_Mesh * self, PyObject * args )
+{
+ int index;
+ PyObject *influence_list = NULL;
+ Object *object = self->object;
+ Mesh *me = self->mesh;
+
+ /* Get a reference to the mesh object wrapped in here. */
+ if( !object )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "This mesh must be linked to an object" );
+
+ /* Parse the parameters: only on integer (vertex index) */
+ if( !PyArg_ParseTuple( args, "i", &index ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected int argument (index of the vertex)" );
+
+ /* check for valid index */
+ if( index < 0 || index >= me->totvert )
+ return EXPP_ReturnPyObjError( PyExc_IndexError,
+ "vertex index out of range" );
+
+ influence_list = PyList_New( 0 );
+
+ /* Proceed only if we have vertex deformation information */
+ if( me->dvert ) {
+ int i;
+ MDeformWeight *sweight = NULL;
+
+ /* Number of bones influencing the vertex */
+ int totinfluences = me->dvert[index].totweight;
+
+ /* Get the reference of the first weight structure */
+ sweight = me->dvert[index].dw;
+
+ /* Build the list only with weights and names of the influent bones */
+ for( i = 0; i < totinfluences; i++, sweight++ ) {
+ bDeformGroup *defgroup = BLI_findlink( &object->defbase,
+ sweight->def_nr );
+ if( defgroup )
+ PyList_Append( influence_list, Py_BuildValue( "[sf]",
+ defgroup->name, sweight->weight ) );
+ }
+ }
+
+ return influence_list;
+}
+
+static PyObject *Mesh_removeAllKeys( BPy_Mesh * self )
+{
+ Mesh *mesh = self->mesh;
+
+ if( !mesh || !mesh->key )
+ Py_RETURN_FALSE;
+
+ mesh->key->id.us--;
+ mesh->key = NULL;
+
+ Py_RETURN_TRUE;
+}
+
+
+static PyObject *Mesh_insertKey( BPy_Mesh * self, PyObject * args )
+{
+ Mesh *mesh = self->mesh;
+ int fra = -1, oldfra = -1;
+ char *type = NULL;
+ short typenum;
+
+ if (mesh->mr)
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "Shape Keys cannot be added to meshes with multires" );
+
+ if( !PyArg_ParseTuple( args, "|is", &fra, &type ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected nothing or an int and optionally a string as arguments" );
+
+ if( !type || !strcmp( type, "relative" ) )
+ typenum = 1;
+ else if( !strcmp( type, "absolute" ) )
+ typenum = 2;
+ else
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "if given, type should be 'relative' or 'absolute'" );
+
+ if( fra > 0 ) {
+ fra = EXPP_ClampInt( fra, 1, MAXFRAME );
+ oldfra = G.scene->r.cfra;
+ G.scene->r.cfra = fra;
+ }
+
+ insert_meshkey( mesh, typenum );
+ allspace(REMAKEIPO, 0);
+
+ if( fra > 0 )
+ G.scene->r.cfra = oldfra;
+
+ Py_RETURN_NONE;
+}
+
+
+
+
+/* Custom Data Layers */
+
+static PyObject * Mesh_addCustomLayer_internal(Mesh *me, PyObject * args, int type)
+{
+ char *name = NULL;
+ CustomData *data = &me->fdata;
+ if( !PyArg_ParseTuple( args, "|s", &name ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a string or nothing" );
+
+ if (strlen(name)>31)
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "error, maximum name length is 31" );
+
+ if (name)
+ CustomData_add_layer_named(data, type, CD_DEFAULT,
+ NULL, me->totface, name);
+ else
+ CustomData_add_layer(data, type, CD_DEFAULT,
+ NULL, me->totface);
+ mesh_update_customdata_pointers(me);
+ Py_RETURN_NONE;
+}
+
+static PyObject *Mesh_addUVLayer( BPy_Mesh * self, PyObject * args )
+{
+ return Mesh_addCustomLayer_internal(self->mesh, args, CD_MTFACE);
+}
+
+static PyObject *Mesh_addColorLayer( BPy_Mesh * self, PyObject * args )
+{
+ return Mesh_addCustomLayer_internal(self->mesh, args, CD_MCOL);
+}
+
+static PyObject *Mesh_removeLayer_internal( BPy_Mesh * self, PyObject * value, int type )
+{
+ Mesh *me = self->mesh;
+ CustomData *data = &me->fdata;
+ char *name = PyString_AsString(value);
+ int i;
+
+ if( !name )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument" );
+
+ if (strlen(name)>31)
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "error, maximum name length is 31" );
+
+ i = CustomData_get_named_layer_index(data, type, name);
+
+ if (i==-1)
+ return EXPP_ReturnPyObjError(PyExc_ValueError,
+ "No matching layers to remove" );
+
+ CustomData_free_layer(data, type, me->totface, i);
+ mesh_update_customdata_pointers(me);
+
+ /* No more Color or UV layers left ?
+ switch modes if this is the active object */
+ if (!CustomData_has_layer(data, type)) {
+ if (me == get_mesh(OBACT)) {
+ if(type == CD_MCOL && (G.f & G_VERTEXPAINT))
+ G.f &= ~G_VERTEXPAINT; /* get out of vertexpaint mode */
+ if(type == CD_MTFACE && (G.f & G_FACESELECT))
+ G.f |= ~G_FACESELECT; /* get out of faceselect mode */
+ }
+ }
+
+ Py_RETURN_NONE;
+}
+
+
+static PyObject *Mesh_removeUVLayer( BPy_Mesh * self, PyObject * value )
+{
+ return Mesh_removeLayer_internal(self, value, CD_MTFACE);
+}
+
+static PyObject *Mesh_removeColorLayer( BPy_Mesh * self, PyObject * value )
+{
+ return Mesh_removeLayer_internal(self, value, CD_MCOL);
+}
+
+
+static PyObject *Mesh_renameLayer_internal( BPy_Mesh * self, PyObject * args, int type )
+{
+ CustomData *data;
+ CustomDataLayer *layer;
+ Mesh *mesh = self->mesh;
+ int i;
+ char *name_from, *name_to;
+
+ data = &mesh->fdata;
+
+ if( !PyArg_ParseTuple( args, "ss", &name_from, &name_to ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected 2 strings" );
+
+ if (strlen(name_from)>31 || strlen(name_to)>31)
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "error, maximum name length is 31" );
+
+ i = CustomData_get_named_layer_index(data, type, name_from);
+
+ if (i==-1)
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "layer name was not found" );
+
+ layer = &data->layers[i];
+ strcpy(layer->name, name_to); /* we alredy know the string sizes are under 32 */
+ CustomData_set_layer_unique_name(data, i);
+ Py_RETURN_NONE;
+}
+
+static PyObject *Mesh_renameUVLayer( BPy_Mesh * self, PyObject * args )
+{
+ return Mesh_renameLayer_internal( self, args, CD_MTFACE );
+}
+
+static PyObject *Mesh_renameColorLayer( BPy_Mesh * self, PyObject * args )
+{
+ return Mesh_renameLayer_internal( self, args, CD_MCOL );
+}
+
+
+static PyObject *Mesh_getLayerNames_internal( BPy_Mesh * self, int type )
+{
+ CustomData *data;
+ CustomDataLayer *layer;
+ PyObject *str, *list = PyList_New( 0 );
+ Mesh *mesh = self->mesh;
+ int i;
+ data = &mesh->fdata;
+
+ /* see if there is a duplicate */
+ for(i=0; i<data->totlayer; i++) {
+ layer = &data->layers[i];
+ if(layer->type == type) {
+ str = PyString_FromString(layer->name);
+ PyList_Append( list, str );
+ Py_DECREF(str);
+ }
+ }
+ return list;
+}
+
+static PyObject *Mesh_getUVLayerNames( BPy_Mesh * self )
+{
+ return Mesh_getLayerNames_internal(self, CD_MTFACE);
+}
+
+static PyObject *Mesh_getColorLayerNames( BPy_Mesh * self )
+{
+ return Mesh_getLayerNames_internal(self, CD_MCOL);
+}
+/* used by activeUVLayer and activeColorLayer attrs */
+static PyObject *Mesh_getActiveLayer( BPy_Mesh * self, void *type )
+{
+ CustomData *data = &self->mesh->fdata;
+ int layer_type = (int)type;
+ int i;
+ if (layer_type < 0) { /* hack, if negative, its the renderlayer.*/
+ layer_type = -layer_type;
+ i = CustomData_get_render_layer_index(data, layer_type);
+ } else {
+ i = CustomData_get_active_layer_index(data, layer_type);
+ }
+ if (i == -1) /* so -1 is for no active layer 0+ for an active layer */
+ Py_RETURN_NONE;
+ else {
+ return PyString_FromString( data->layers[i].name);
+ }
+}
+
+static int Mesh_setActiveLayer( BPy_Mesh * self, PyObject * value, void *type )
+{
+ CustomData *data = &self->mesh->fdata;
+ char *name;
+ int i,ok,n,layer_type = (int)type, render=0;
+
+ if( !PyString_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "expected a string argument" );
+
+ if (layer_type<0) {
+ layer_type = -layer_type;
+ render = 1;
+ }
+
+ name = PyString_AsString( value );
+ ok = 0;
+ n = 0;
+ for(i=0; i < data->totlayer; ++i) {
+ if(data->layers[i].type == layer_type) {
+ if (strcmp(data->layers[i].name, name)==0) {
+ ok = 1;
+ break;
+ }
+ n++;
+ }
+ }
+
+ if (!ok)
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "layer name does not exist" );
+ if (render) {
+ CustomData_set_layer_render(data, layer_type, n);
+ } else {
+ CustomData_set_layer_active(data, layer_type, n);
+ mesh_update_customdata_pointers(self->mesh);
+ }
+ return 0;
+}
+
+
+/* multires */
+static PyObject *Mesh_getMultiresLevelCount( BPy_Mesh * self )
+{
+ int i;
+ if (!self->mesh->mr)
+ i=0;
+ else
+ i= self->mesh->mr->level_count;
+
+ return PyInt_FromLong(i);
+}
+
+
+static PyObject *Mesh_getMultires( BPy_Mesh * self, void *type )
+{
+ int i=0;
+ if (self->mesh->mr) {
+ switch ((int)type) {
+ case MESH_MULTIRES_LEVEL:
+ i = self->mesh->mr->newlvl;
+ break;
+ case MESH_MULTIRES_EDGE:
+ i = self->mesh->mr->edgelvl;
+ break;
+ case MESH_MULTIRES_PIN:
+ i = self->mesh->mr->pinlvl;
+ break;
+ case MESH_MULTIRES_RENDER:
+ i = self->mesh->mr->renderlvl;
+ break;
+ }
+ }
+
+ return PyInt_FromLong(i);
+}
+
+static int Mesh_setMultires( BPy_Mesh * self, PyObject *value, void *type )
+{
+ int i;
+ if( !PyInt_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected integer argument" );
+
+ if (!self->object)
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "This mesh must be linked to an object" );
+
+ if (!self->mesh->mr)
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "the mesh has no multires data" );
+
+ if (!self->mesh->mr->level_count)
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "multires data has no levels added" );
+
+ i = PyInt_AsLong(value);
+
+ if (i<1||i>self->mesh->mr->level_count)
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "value out of range" );
+
+ switch ((int)type) {
+ case MESH_MULTIRES_LEVEL:
+ self->mesh->mr->newlvl = i;
+ multires_set_level(self->object, self->mesh, 0);
+ break;
+ case MESH_MULTIRES_EDGE:
+ self->mesh->mr->edgelvl = i;
+ multires_edge_level_update(self->object, self->mesh);
+ break;
+ case MESH_MULTIRES_PIN:
+ self->mesh->mr->pinlvl = i;
+ break;
+ case MESH_MULTIRES_RENDER:
+ self->mesh->mr->renderlvl = i;
+ break;
+ }
+
+ return 0;
+}
+
+/* end multires */
+
+
+static PyObject *Mesh_Tools( BPy_Mesh * self, int type, void **args )
+{
+ Base *base;
+ int result;
+ Object *object = NULL;
+ PyObject *attr = NULL;
+
+ /* if already in edit mode, exit */
+
+ if( G.obedit )
+ return EXPP_ReturnPyObjError(PyExc_RuntimeError,
+ "can't use mesh tools while in edit mode" );
+
+ for( base = FIRSTBASE; base; base = base->next ) {
+ if( base->object->type == OB_MESH &&
+ base->object->data == self->mesh ) {
+ object = base->object;
+ break;
+ }
+ }
+ if( !object )
+ return EXPP_ReturnPyObjError(PyExc_RuntimeError,
+ "can't find an object for the mesh" );
+
+ if( object->type != OB_MESH )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "Object specified is not a mesh." );
+
+ /* make mesh's object active, enter mesh edit mode */
+ G.obedit = object;
+ make_editMesh();
+
+ /* apply operation, then exit edit mode */
+ switch( type ) {
+ case MESH_TOOL_TOSPHERE:
+ vertices_to_sphere();
+ break;
+ case MESH_TOOL_VERTEXSMOOTH:
+ vertexsmooth();
+ break;
+ case MESH_TOOL_FLIPNORM:
+ /* would be simple to rewrite this to not use edit mesh */
+ /* see flipface() */
+ flip_editnormals();
+ break;
+ case MESH_TOOL_SUBDIV:
+ esubdivideflag( 1, 0.0, *((int *)args[0]), 1, 0 );
+ break;
+ case MESH_TOOL_REMDOUB:
+ result = removedoublesflag( 1, 0, *((float *)args[0]) );
+
+ attr = PyInt_FromLong( result );
+ if( !attr )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyInt_FromLong() failed" );
+ break;
+ case MESH_TOOL_FILL:
+ fill_mesh();
+ break;
+ case MESH_TOOL_RECALCNORM:
+ righthandfaces( *((int *)args[0]) );
+ break;
+ case MESH_TOOL_TRI2QUAD:
+ join_triangles();
+ break;
+ case MESH_TOOL_QUAD2TRI:
+ convert_to_triface( *((int *)args[0]) );
+ break;
+ }
+
+ /* exit edit mode, free edit mesh */
+ load_editMesh();
+ free_editMesh(G.editMesh);
+
+ if(G.f & G_FACESELECT)
+ EXPP_allqueue( REDRAWIMAGE, 0 );
+ if(G.f & G_WEIGHTPAINT)
+ mesh_octree_table(G.obedit, NULL, 'e');
+ G.obedit = NULL;
+
+ DAG_object_flush_update(G.scene, object, OB_RECALC_DATA);
+
+ if( attr )
+ return attr;
+
+ Py_RETURN_NONE;
+}
+
+/*
+ * "Subdivide" function
+ */
+
+static PyObject *Mesh_subdivide( BPy_Mesh * self, PyObject * args )
+{
+ int beauty = 0;
+ void *params = &beauty;
+
+ if( !PyArg_ParseTuple( args, "|i", &beauty ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected nothing or an int argument" );
+
+ return Mesh_Tools( self, MESH_TOOL_SUBDIV, &params );
+}
+
+/*
+ * "Smooth" function
+ */
+
+static PyObject *Mesh_smooth( BPy_Mesh * self )
+{
+ return Mesh_Tools( self, MESH_TOOL_VERTEXSMOOTH, NULL );
+}
+
+/*
+ * "Remove doubles" function
+ */
+
+static PyObject *Mesh_removeDoubles( BPy_Mesh * self, PyObject *args )
+{
+ float limit;
+ void *params = &limit;
+
+ if( !PyArg_ParseTuple( args, "f", &limit ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected float argument" );
+
+ limit = EXPP_ClampFloat( limit, 0.0f, 1.0f );
+
+ return Mesh_Tools( self, MESH_TOOL_REMDOUB, &params );
+}
+
+/*
+ * "recalc normals" function
+ */
+
+static PyObject *Mesh_recalcNormals( BPy_Mesh * self, PyObject *args )
+{
+ int direction = 0;
+ void *params = &direction;
+
+ if( !PyArg_ParseTuple( args, "|i", &direction ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected nothing or an int in range [0,1]" );
+
+ if( direction < 0 || direction > 1 )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "expected int in range [0,1]" );
+
+ /* righthandfaces(1) = outward, righthandfaces(2) = inward */
+ ++direction;
+
+ return Mesh_Tools( self, MESH_TOOL_RECALCNORM, &params );
+}
+
+/*
+ * "Quads to Triangles" function
+ */
+
+static PyObject *Mesh_quad2tri( BPy_Mesh * self, PyObject *args )
+{
+ int kind = 0;
+ void *params = &kind;
+
+ if( !PyArg_ParseTuple( args, "|i", &kind ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected nothing or an int in range [0,1]" );
+
+ if( kind < 0 || kind > 1 )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "expected int in range [0,1]" );
+
+ return Mesh_Tools( self, MESH_TOOL_QUAD2TRI, &params );
+}
+
+/*
+ * "Triangles to Quads" function
+ */
+
+static PyObject *Mesh_tri2quad( BPy_Mesh * self )
+{
+ return Mesh_Tools( self, MESH_TOOL_TRI2QUAD, NULL );
+}
+
+/*
+ * "Flip normals" function
+ */
+
+static PyObject *Mesh_flipNormals( BPy_Mesh * self )
+{
+ return Mesh_Tools( self, MESH_TOOL_FLIPNORM, NULL );
+}
+
+/*
+ * "To sphere" function
+ */
+
+static PyObject *Mesh_toSphere( BPy_Mesh * self )
+{
+ return Mesh_Tools( self, MESH_TOOL_TOSPHERE, NULL );
+}
+
+/*
+ * "Fill" (scan fill) function
+ */
+
+static PyObject *Mesh_fill( BPy_Mesh * self )
+{
+ return Mesh_Tools( self, MESH_TOOL_FILL, NULL );
+}
+
+
+/*
+ * "pointInside" function
+ */
+#define SIDE_OF_LINE(pa,pb,pp) ((pa[0]-pp[0])*(pb[1]-pp[1]))-((pb[0]-pp[0])*(pa[1]-pp[1]))
+#define POINT_IN_TRI(p0,p1,p2,p3) ((SIDE_OF_LINE(p1,p2,p0)>=0) && (SIDE_OF_LINE(p2,p3,p0)>=0) && (SIDE_OF_LINE(p3,p1,p0)>=0))
+static short pointInside_internal(float *vec, float *v1, float *v2, float *v3 )
+{
+ float z,w1,w2,w3,wtot;
+
+ if (!POINT_IN_TRI(vec, v1,v2,v3))
+ return 0;
+
+ if (vec[2] < MAX3(v1[2], v2[2], v3[2])) {
+ w1= AreaF2Dfl(vec, v2, v3);
+ w2= AreaF2Dfl(v1, vec, v3);
+ w3= AreaF2Dfl(v1, v2, vec);
+ wtot = w1+w2+w3;
+ w1/=wtot; w2/=wtot; w3/=wtot;
+ z =((v1[2] * (w2+w3)) +
+ (v2[2] * (w1+w3)) +
+ (v3[2] * (w1+w2))) * 0.5;
+ /* only return true if the face is above vec*/
+ if (vec[2] < z )
+ return 1;
+ }
+ return 0;
+}
+
+static PyObject *Mesh_pointInside( BPy_Mesh * self, VectorObject * vec )
+{
+ Mesh *mesh = self->mesh;
+ MFace *mf = mesh->mface;
+ MVert *mvert = mesh->mvert;
+ int i;
+ int isect_count=0;
+
+ if(!VectorObject_Check(vec))
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected one vector type" );
+
+ if(vec->size < 3)
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Mesh.pointInside(vec) expects a 3D vector objects\n");
+
+ for( i = 0; i < mesh->totface; ++mf, ++i ) {
+ if (pointInside_internal(vec->vec, mvert[mf->v1].co, mvert[mf->v2].co, mvert[mf->v3].co))
+ isect_count++;
+ else if (mf->v4 && pointInside_internal(vec->vec,mvert[mf->v1].co, mvert[mf->v3].co, mvert[mf->v4].co))
+ isect_count++;
+ }
+
+ if (isect_count % 2)
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+}
+
+
+/*
+ * "__copy__" return a copy of the mesh
+ */
+
+static PyObject *Mesh_copy( BPy_Mesh * self )
+{
+ BPy_Mesh *obj;
+
+ obj = (BPy_Mesh *)PyObject_NEW( BPy_Mesh, &Mesh_Type );
+
+ if( !obj )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyObject_New() failed" );
+
+ obj->mesh = copy_mesh( self->mesh );
+ obj->mesh->id.us= 0;
+ obj->object = NULL;
+ obj->new = 1;
+ return (PyObject *)obj;
+}
+
+
+static struct PyMethodDef BPy_Mesh_methods[] = {
+ {"calcNormals", (PyCFunction)Mesh_calcNormals, METH_NOARGS,
+ "all recalculate vertex normals"},
+ {"vertexShade", (PyCFunction)Mesh_vertexShade, METH_VARARGS,
+ "color vertices based on the current lighting setup"},
+ {"findEdges", (PyCFunction)Mesh_findEdges, METH_VARARGS,
+ "find indices of an multiple edges in the mesh"},
+ {"getFromObject", (PyCFunction)Mesh_getFromObject, METH_VARARGS,
+ "Get a mesh by name"},
+ {"update", (PyCFunction)Mesh_Update, METH_VARARGS | METH_KEYWORDS,
+ "Update display lists after changes to mesh"},
+ {"transform", (PyCFunction)Mesh_transform, METH_VARARGS | METH_KEYWORDS,
+ "Applies a transformation matrix to mesh's vertices"},
+ {"addVertGroup", (PyCFunction)Mesh_addVertGroup, METH_O,
+ "Assign vertex group name to the object linked to the mesh"},
+ {"removeVertGroup", (PyCFunction)Mesh_removeVertGroup, METH_O,
+ "Delete vertex group name from the object linked to the mesh"},
+ {"assignVertsToGroup", (PyCFunction)Mesh_assignVertsToGroup, METH_VARARGS,
+ "Assigns vertices to a vertex group"},
+ {"removeVertsFromGroup", (PyCFunction)Mesh_removeVertsFromGroup, METH_VARARGS,
+ "Removes vertices from a vertex group"},
+ {"getVertsFromGroup", (PyCFunction)Mesh_getVertsFromGroup, METH_VARARGS,
+ "Get index and optional weight for vertices in vertex group"},
+ {"renameVertGroup", (PyCFunction)Mesh_renameVertGroup, METH_VARARGS,
+ "Rename an existing vertex group"},
+ {"getVertGroupNames", (PyCFunction)Mesh_getVertGroupNames, METH_NOARGS,
+ "Get names of vertex groups"},
+ {"getVertexInfluences", (PyCFunction)Mesh_getVertexInfluences, METH_VARARGS,
+ "Get list of the influences of bones for a given mesh vertex"},
+ /* Shape Keys */
+ {"removeAllKeys", (PyCFunction)Mesh_removeAllKeys, METH_NOARGS,
+ "Remove all the shape keys from a mesh"},
+ {"insertKey", (PyCFunction)Mesh_insertKey, METH_VARARGS,
+ "(frame = None, type = 'relative') - inserts a Mesh key at the given frame"},
+ /* Mesh tools */
+ {"smooth", (PyCFunction)Mesh_smooth, METH_NOARGS,
+ "Flattens angle of selected faces (experimental)"},
+ {"flipNormals", (PyCFunction)Mesh_flipNormals, METH_NOARGS,
+ "Toggles the direction of selected face's normals (experimental)"},
+ {"toSphere", (PyCFunction)Mesh_toSphere, METH_NOARGS,
+ "Moves selected vertices outward in a spherical shape (experimental)"},
+ {"fill", (PyCFunction)Mesh_fill, METH_NOARGS,
+ "Scan fill a closed edge loop (experimental)"},
+ {"triangleToQuad", (PyCFunction)Mesh_tri2quad, METH_VARARGS,
+ "Convert selected triangles to quads (experimental)"},
+ {"quadToTriangle", (PyCFunction)Mesh_quad2tri, METH_VARARGS,
+ "Convert selected quads to triangles (experimental)"},
+ {"subdivide", (PyCFunction)Mesh_subdivide, METH_VARARGS,
+ "Subdivide selected edges in a mesh (experimental)"},
+ {"remDoubles", (PyCFunction)Mesh_removeDoubles, METH_VARARGS,
+ "Removes duplicates from selected vertices (experimental)"},
+ {"recalcNormals", (PyCFunction)Mesh_recalcNormals, METH_VARARGS,
+ "Recalculates inside or outside normals (experimental)"},
+ {"pointInside", (PyCFunction)Mesh_pointInside, METH_O,
+ "Recalculates inside or outside normals (experimental)"},
+
+ /* mesh custom data layers */
+ {"addUVLayer", (PyCFunction)Mesh_addUVLayer, METH_VARARGS,
+ "adds a UV layer to this mesh"},
+ {"addColorLayer", (PyCFunction)Mesh_addColorLayer, METH_VARARGS,
+ "adds a color layer to this mesh "},
+ {"removeUVLayer", (PyCFunction)Mesh_removeUVLayer, METH_O,
+ "removes a UV layer to this mesh"},
+ {"removeColorLayer", (PyCFunction)Mesh_removeColorLayer, METH_O,
+ "removes a color layer to this mesh"},
+ {"getUVLayerNames", (PyCFunction)Mesh_getUVLayerNames, METH_NOARGS,
+ "Get names of UV layers"},
+ {"getColorLayerNames", (PyCFunction)Mesh_getColorLayerNames, METH_NOARGS,
+ "Get names of Color layers"},
+ {"renameUVLayer", (PyCFunction)Mesh_renameUVLayer, METH_VARARGS,
+ "Rename a UV Layer"},
+ {"renameColorLayer", (PyCFunction)Mesh_renameColorLayer, METH_VARARGS,
+ "Rename a Color Layer"},
+
+ /* python standard class functions */
+ {"__copy__", (PyCFunction)Mesh_copy, METH_NOARGS,
+ "Return a copy of the mesh"},
+ {"copy", (PyCFunction)Mesh_copy, METH_NOARGS,
+ "Return a copy of the mesh"},
+ {NULL, NULL, 0, NULL}
+};
+
+/************************************************************************
+ *
+ * Python BPy_Mesh attributes
+ *
+ ************************************************************************/
+
+static PyObject *MVertSeq_CreatePyObject( Mesh * mesh )
+{
+
+ BPy_MVertSeq *obj = PyObject_NEW( BPy_MVertSeq, &MVertSeq_Type);
+ obj->mesh = mesh;
+
+ /*
+ an iter of -1 means this seq has not been used as an iterator yet
+ once it is, then any other calls on getIter will return a new copy of BPy_MVertSeq
+ This means you can loop do nested loops with the same iterator without worrying about
+ the iter variable being used twice and messing up the loops.
+ */
+ obj->iter = -1;
+ return (PyObject *)obj;
+}
+
+static PyObject *Mesh_getVerts( BPy_Mesh * self )
+{
+ return MVertSeq_CreatePyObject(self->mesh);
+}
+
+static int Mesh_setVerts( BPy_Mesh * self, PyObject * args )
+{
+ MVert *dst;
+ MVert *src;
+ int i;
+
+ /* special case if None: delete the mesh */
+ if( args == NULL || args == Py_None ) {
+ Mesh *me = self->mesh;
+ free_mesh( me );
+ me->mvert = NULL; me->medge = NULL; me->mface = NULL;
+ me->mtface = NULL; me->dvert = NULL; me->mcol = NULL;
+ me->msticky = NULL; me->mat = NULL; me->bb = NULL;
+ me->totvert = me->totedge = me->totface = me->totcol = 0;
+ mesh_update( me );
+ return 0;
+ }
+
+ if( PyList_Check( args ) ) {
+ if( EXPP_check_sequence_consistency( args, &MVert_Type ) != 1 &&
+ EXPP_check_sequence_consistency( args, &PVert_Type ) != 1 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a list of MVerts" );
+
+ if( PyList_Size( args ) != self->mesh->totvert )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "list must have the same number of vertices as the mesh" );
+
+ dst = self->mesh->mvert;
+ for( i = 0; i < PyList_Size( args ); ++i ) {
+ BPy_MVert *v = (BPy_MVert *)PyList_GET_ITEM( args, i );
+
+ if( BPy_MVert_Check( v ) )
+ src = &((Mesh *)v->data)->mvert[v->index];
+ else
+ src = (MVert *)v->data;
+
+ memcpy( dst, src, sizeof(MVert) );
+ ++dst;
+ }
+ } else if( args->ob_type == &MVertSeq_Type ) {
+ Mesh *mesh = ( (BPy_MVertSeq *) args)->mesh;
+
+ if( mesh->totvert != self->mesh->totvert )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "vertex sequences must have the same number of vertices" );
+
+ memcpy( self->mesh->mvert, mesh->mvert, mesh->totvert*sizeof(MVert) );
+ } else
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a list or sequence of MVerts" );
+ return 0;
+}
+
+static PyObject *MEdgeSeq_CreatePyObject( Mesh *mesh )
+{
+ BPy_MEdgeSeq *obj = PyObject_NEW( BPy_MEdgeSeq, &MEdgeSeq_Type);
+ obj->mesh = mesh;
+ obj->iter = -1; /* iterator not yet used */
+ return (PyObject *)obj;
+}
+
+static PyObject *Mesh_getEdges( BPy_Mesh * self )
+{
+ return MEdgeSeq_CreatePyObject(self->mesh);
+}
+
+static PyObject *MFaceSeq_CreatePyObject( Mesh * mesh )
+{
+ BPy_MFaceSeq *obj= PyObject_NEW( BPy_MFaceSeq, &MFaceSeq_Type);
+ obj->mesh = mesh;
+ obj->iter = -1; /* iterator not yet used */
+ return (PyObject *)obj;
+}
+
+static PyObject *Mesh_getFaces( BPy_Mesh * self )
+{
+ return MFaceSeq_CreatePyObject( self->mesh );
+}
+
+static PyObject *Mesh_getMaterials( BPy_Mesh *self )
+{
+ return EXPP_PyList_fromMaterialList( self->mesh->mat,
+ self->mesh->totcol, 1 );
+}
+
+static int Mesh_setMaterials( BPy_Mesh *self, PyObject * value )
+{
+ Material **matlist;
+ int len;
+
+ if( !PySequence_Check( value ) ||
+ !EXPP_check_sequence_consistency( value, &Material_Type ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "list should only contain materials or None)" );
+
+ len = PyList_Size( value );
+ if( len > 16 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "list can't have more than 16 materials" );
+
+ /* free old material list (if it exists) and adjust user counts */
+ if( self->mesh->mat ) {
+ Mesh *me = self->mesh;
+ int i;
+ for( i = me->totcol; i-- > 0; )
+ if( me->mat[i] )
+ me->mat[i]->id.us--;
+ MEM_freeN( me->mat );
+ }
+
+ /* build the new material list, increment user count, store it */
+
+ matlist = EXPP_newMaterialList_fromPyList( value );
+ EXPP_incr_mats_us( matlist, len );
+ self->mesh->mat = matlist;
+ self->mesh->totcol = (short)len;
+
+/**@ This is another ugly fix due to the weird material handling of blender.
+ * it makes sure that object material lists get updated (by their length)
+ * according to their data material lists, otherwise blender crashes.
+ * It just stupidly runs through all objects...BAD BAD BAD.
+ */
+
+ test_object_materials( ( ID * ) self->mesh );
+
+ return 0;
+}
+
+static PyObject *Mesh_getMaxSmoothAngle( BPy_Mesh * self )
+{
+ return PyInt_FromLong( self->mesh->smoothresh );
+}
+
+static int Mesh_setMaxSmoothAngle( BPy_Mesh *self, PyObject *value )
+{
+ return EXPP_setIValueClamped( value, &self->mesh->smoothresh,
+ MESH_SMOOTHRESH_MIN,
+ MESH_SMOOTHRESH_MAX, 'h' );
+}
+
+static PyObject *Mesh_getSubDivLevels( BPy_Mesh * self )
+{
+ return Py_BuildValue( "(h,h)",
+ self->mesh->subdiv, self->mesh->subdivr );
+}
+
+static int Mesh_setSubDivLevels( BPy_Mesh *self, PyObject *value )
+{
+ int subdiv[2];
+ int i;
+ PyObject *tmp;
+
+ if( !PyTuple_Check( value ) || PyTuple_Size( value ) != 2 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected (int, int) as argument" );
+
+ for( i = 0; i < 2; i++ ) {
+ tmp = PyTuple_GET_ITEM( value, i );
+ if( !PyInt_Check( tmp ) )
+ return EXPP_ReturnIntError ( PyExc_TypeError,
+ "expected a list [int, int] as argument" );
+ subdiv[i] = EXPP_ClampInt( PyInt_AsLong( tmp ),
+ MESH_SUBDIV_MIN,
+ MESH_SUBDIV_MAX );
+ }
+
+ self->mesh->subdiv = (short)subdiv[0];
+ self->mesh->subdivr = (short)subdiv[1];
+ return 0;
+}
+
+static PyObject *Mesh_getFlag( BPy_Mesh * self, void *type )
+{
+ switch( (long)type ) {
+ case MESH_HASFACEUV:
+ return self->mesh->mtface ? EXPP_incr_ret_True() :
+ EXPP_incr_ret_False();
+ case MESH_HASMCOL:
+ return self->mesh->mcol ? EXPP_incr_ret_True() :
+ EXPP_incr_ret_False();
+ case MESH_HASVERTUV:
+ return self->mesh->msticky ? EXPP_incr_ret_True() :
+ EXPP_incr_ret_False();
+ case MESH_HASMULTIRES:
+ return self->mesh->mr ? EXPP_incr_ret_True() :
+ EXPP_incr_ret_False();
+ default:
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't get attribute" );
+ }
+}
+
+static int Mesh_setFlag( BPy_Mesh * self, PyObject *value, void *type )
+{
+ int param;
+ Mesh *mesh = self->mesh;
+
+ param = PyObject_IsTrue( value );
+
+ if( param == -1 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected True/False or 0/1" );
+
+ /* sticky is independent of faceUV and vertUV */
+
+ switch( (long)type ) {
+ case MESH_HASFACEUV:
+ if( !param ) {
+ if( mesh->mtface ) {
+ CustomData_free_layers( &mesh->fdata, CD_MTFACE, mesh->totface );
+ mesh->mtface = NULL;
+ }
+ } else if( !mesh->mtface ) {
+ if( !mesh->totface )
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "mesh has no faces" );
+ make_tfaces( mesh );
+ }
+ return 0;
+ case MESH_HASMCOL:
+ if( !param ) {
+ if( mesh->mcol ) {
+ CustomData_free_layers( &mesh->fdata, CD_MCOL, mesh->totface );
+ mesh->mcol = NULL;
+ }
+ } else if( !mesh->mcol ) {
+ /* TODO: mesh_create_shadedColors */
+ mesh->mcol = CustomData_add_layer( &mesh->fdata, CD_MCOL,
+ CD_DEFAULT, NULL, mesh->totface );
+ }
+ return 0;
+ case MESH_HASVERTUV:
+ if( !param ) {
+ if( mesh->msticky ) {
+ CustomData_free_layer_active( &mesh->vdata, CD_MSTICKY, mesh->totvert );
+ mesh->msticky = NULL;
+ }
+ } else {
+ if( !mesh->msticky ) {
+ mesh->msticky = CustomData_add_layer( &mesh->vdata, CD_MSTICKY,
+ CD_CALLOC, NULL, mesh->totvert );
+ memset( mesh->msticky, 255, mesh->totvert*sizeof( MSticky ) );
+ /* TODO: rework RE_make_sticky() so we can calculate */
+ }
+ }
+ return 0;
+ case MESH_HASMULTIRES:
+ if (!self->object)
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "This mesh must be linked to an object" );
+
+ if( !param ) {
+ if ( mesh->mr ) {
+ multires_delete(self->object, mesh);
+ }
+ } else {
+ if ( !mesh->mr ) {
+ if (mesh->key)
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "Cannot enable multires for a mesh with shape keys" );
+ multires_make(self->object, mesh);
+ }
+ }
+ return 0;
+ default:
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "couldn't get attribute" );
+ }
+}
+
+static PyObject *Mesh_getMode( BPy_Mesh * self )
+{
+ return PyInt_FromLong( self->mesh->flag );
+}
+
+static int Mesh_setMode( BPy_Mesh *self, PyObject *value )
+{
+ short param;
+ static short bitmask = ME_ISDONE | ME_NOPUNOFLIP | ME_TWOSIDED |
+ ME_UVEFFECT | ME_VCOLEFFECT | ME_AUTOSMOOTH | ME_SMESH |
+ ME_SUBSURF | ME_OPT_EDGES;
+
+ if( !PyInt_Check ( value ) ) {
+ char errstr[128];
+ sprintf ( errstr , "expected int bitmask of 0x%04x", bitmask );
+ return EXPP_ReturnIntError( PyExc_TypeError, errstr );
+ }
+ param = (short)PyInt_AS_LONG ( value );
+
+ if( ( param & bitmask ) != param )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "invalid bit(s) set in mask" );
+
+ self->mesh->flag = param;
+
+ return 0;
+}
+
+static PyObject *Mesh_getKey( BPy_Mesh * self )
+{
+ if( self->mesh->key )
+ return Key_CreatePyObject(self->mesh->key);
+ else
+ Py_RETURN_NONE;
+}
+
+
+static PyObject *Mesh_getActiveFace( BPy_Mesh * self )
+{
+ /* not needed but keep incase exceptions make use of it */
+ if( !self->mesh->mtface )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "face has no texture values" );
+
+ if (self->mesh->act_face != -1 && self->mesh->act_face <= self->mesh->totface)
+ return PyInt_FromLong( self->mesh->act_face );
+
+ Py_RETURN_NONE;
+}
+
+static int Mesh_setActiveFace( BPy_Mesh * self, PyObject * value )
+{
+ int param;
+
+ /* if no texture faces, error */
+
+ if( !self->mesh->mtface )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "face has no texture values" );
+
+ /* if param isn't an int, error */
+
+ if( !PyInt_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected an int argument" );
+
+ /* check for a valid index */
+
+ param = PyInt_AsLong( value );
+ if( param < 0 || param > self->mesh->totface )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "face index out of range" );
+
+ self->mesh->act_face = param;
+ return 0;
+}
+
+static PyObject *Mesh_getActiveGroup( BPy_Mesh * self )
+{
+ bDeformGroup *defGroup;
+ Object *object = self->object;
+
+ if( !object )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "This mesh must be linked to an object" );
+
+ if( object->actdef ) {
+ defGroup = BLI_findlink( &object->defbase, object->actdef-1 );
+ return PyString_FromString( defGroup->name );
+ }
+
+ Py_RETURN_NONE;
+}
+
+static int Mesh_setActiveGroup( BPy_Mesh * self, PyObject * arg )
+{
+ char *name;
+ int tmp;
+ Object *object = self->object;
+
+ if( !object )
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "This mesh must be linked to an object" );
+
+ if( !PyString_Check( arg ) )
+ return EXPP_ReturnIntError( PyExc_AttributeError,
+ "expected a string argument" );
+
+ name = PyString_AsString( arg );
+ tmp = object->actdef;
+ vertexgroup_select_by_name( object, name );
+ if( !object->actdef ) {
+ object->actdef = tmp;
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "vertex group not found" );
+ }
+
+ return 0;
+}
+
+static PyObject *Mesh_getTexMesh( BPy_Mesh * self )
+{
+ Mesh *texme= self->mesh->texcomesh;
+
+ if (texme)
+ return Mesh_CreatePyObject( texme, NULL );
+ else
+ Py_RETURN_NONE;
+}
+
+static int Mesh_setTexMesh( BPy_Mesh * self, PyObject * value )
+{
+ int ret = GenericLib_assignData(value, (void **) &self->mesh->texcomesh, 0, 1, ID_ME, 0);
+
+ if (ret==0 && value!=Py_None) /*This must be a mesh type*/
+ (( BPy_Mesh * ) value)->new= 0;
+
+ return ret;
+}
+
+static int Mesh_setSel( BPy_Mesh * self, PyObject * value )
+{
+ int i, param = PyObject_IsTrue( value );
+ Mesh *me = self->mesh;
+ MVert *mvert = me->mvert;
+ MEdge *medge = me->medge;
+ MFace *mface = me->mface;
+
+ if( param == -1 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected True/False or 0/1" );
+
+ if( param ) {
+ for( i = 0; i < me->totvert; ++mvert, ++i )
+ mvert->flag |= SELECT;
+ for( i = 0; i < me->totedge; ++medge, ++i )
+ medge->flag |= SELECT;
+ for( i = 0; i < me->totface; ++mface, ++i )
+ mface->flag |= ME_FACE_SEL;
+ } else {
+ for( i = 0; i < me->totvert; ++mvert, ++i )
+ mvert->flag &= ~SELECT;
+ for( i = 0; i < me->totedge; ++medge, ++i )
+ medge->flag &= ~SELECT;
+ for( i = 0; i < me->totface; ++mface, ++i )
+ mface->flag &= ~ME_FACE_SEL;
+ }
+
+ return 0;
+}
+
+static int Mesh_setHide( BPy_Mesh * self, PyObject * value )
+{
+ int i, param = PyObject_IsTrue( value );
+ Mesh *me = self->mesh;
+ MVert *mvert = me->mvert;
+ MEdge *medge = me->medge;
+ MFace *mface = me->mface;
+
+ if( param == -1 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected True/False or 0/1" );
+
+ if( param ) {
+ for( i = 0; i < me->totvert; ++mvert, ++i )
+ mvert->flag |= ME_HIDE;
+ for( i = 0; i < me->totedge; ++medge, ++i )
+ medge->flag |= ME_HIDE;
+ for( i = 0; i < me->totface; ++mface, ++i )
+ mface->flag |= ME_HIDE;
+ } else {
+ for( i = 0; i < me->totvert; ++mvert, ++i )
+ mvert->flag &= ~ME_HIDE;
+ for( i = 0; i < me->totedge; ++medge, ++i )
+ medge->flag &= ~ME_HIDE;
+ for( i = 0; i < me->totface; ++mface, ++i )
+ mface->flag &= ~ME_HIDE;
+ }
+
+ return 0;
+}
+
+/************************************************************************
+ *
+ * Python Mesh_Type standard operations
+ *
+ ************************************************************************/
+
+static void Mesh_dealloc( BPy_Mesh * self )
+{
+ Mesh *mesh = self->mesh;
+
+ /* if the mesh is new and has no users, delete it */
+ if( self->new && !mesh->id.us )
+ free_libblock( &G.main->mesh, mesh );
+
+ PyObject_DEL( self );
+}
+
+static int Mesh_compare( BPy_Mesh * a, BPy_Mesh * b )
+{
+ return ( a->mesh == b->mesh ) ? 0 : -1;
+}
+
+static PyObject *Mesh_repr( BPy_Mesh * self )
+{
+ return PyString_FromFormat( "[Mesh \"%s\"]",
+ self->mesh->id.name + 2 );
+}
+
+/*****************************************************************************/
+/* Python Mesh_Type attributes get/set structure: */
+/*****************************************************************************/
+static PyGetSetDef BPy_Mesh_getseters[] = {
+ GENERIC_LIB_GETSETATTR,
+ {"verts",
+ (getter)Mesh_getVerts, (setter)Mesh_setVerts,
+ "The mesh's vertices (MVert)",
+ NULL},
+ {"edges",
+ (getter)Mesh_getEdges, (setter)NULL,
+ "The mesh's edge data (MEdge)",
+ NULL},
+ {"faces",
+ (getter)Mesh_getFaces, (setter)NULL,
+ "The mesh's face data (MFace)",
+ NULL},
+ {"materials",
+ (getter)Mesh_getMaterials, (setter)Mesh_setMaterials,
+ "List of the mesh's materials",
+ NULL},
+ {"degr",
+ (getter)Mesh_getMaxSmoothAngle, (setter)Mesh_setMaxSmoothAngle,
+ "The max angle for auto smoothing",
+ NULL},
+ {"maxSmoothAngle",
+ (getter)Mesh_getMaxSmoothAngle, (setter)Mesh_setMaxSmoothAngle,
+ "deprecated: see 'degr'",
+ NULL},
+ {"subDivLevels",
+ (getter)Mesh_getSubDivLevels, (setter)Mesh_setSubDivLevels,
+ "The display and rendering subdivision levels",
+ NULL},
+ {"mode",
+ (getter)Mesh_getMode, (setter)Mesh_setMode,
+ "The mesh's mode bitfield",
+ NULL},
+ {"key",
+ (getter)Mesh_getKey, (setter)NULL,
+ "The mesh's key",
+ NULL},
+ {"faceUV",
+ (getter)Mesh_getFlag, (setter)Mesh_setFlag,
+ "UV-mapped textured faces enabled",
+ (void *)MESH_HASFACEUV},
+ {"vertexColors",
+ (getter)Mesh_getFlag, (setter)Mesh_setFlag,
+ "Vertex colors for the mesh enabled",
+ (void *)MESH_HASMCOL},
+ {"vertexUV",
+ (getter)Mesh_getFlag, (setter)Mesh_setFlag,
+ "'Sticky' flag for per vertex UV coordinates enabled",
+ (void *)MESH_HASVERTUV},
+ {"multires",
+ (getter)Mesh_getFlag, (setter)Mesh_setFlag,
+ "'Sticky' flag for per vertex UV coordinates enabled",
+ (void *)MESH_HASMULTIRES},
+ {"activeFace",
+ (getter)Mesh_getActiveFace, (setter)Mesh_setActiveFace,
+ "Index of the mesh's active texture face (in UV editor)",
+ NULL},
+ {"activeGroup",
+ (getter)Mesh_getActiveGroup, (setter)Mesh_setActiveGroup,
+ "Active group for the mesh",
+ NULL},
+
+ /* uv layers */
+ {"activeColorLayer",
+ (getter)Mesh_getActiveLayer, (setter)Mesh_setActiveLayer,
+ "Name of the active UV layer",
+ (void *)CD_MCOL},
+ {"activeUVLayer",
+ (getter)Mesh_getActiveLayer, (setter)Mesh_setActiveLayer,
+ "Name of the active vertex color layer",
+ (void *)CD_MTFACE},
+ /* hack flip CD_MCOL so it uses the render setting */
+ {"renderColorLayer",
+ (getter)Mesh_getActiveLayer, (setter)Mesh_setActiveLayer,
+ "Name of the render UV layer",
+ (void *)-CD_MCOL},
+ {"renderUVLayer",
+ (getter)Mesh_getActiveLayer, (setter)Mesh_setActiveLayer,
+ "Name of the render vertex color layer",
+ (void *)-CD_MTFACE},
+
+
+
+ /* Multires */
+ {"multiresLevelCount",
+ (getter)Mesh_getMultiresLevelCount, (setter)NULL,
+ "The total number of multires levels",
+ NULL},
+ {"multiresDrawLevel",
+ (getter)Mesh_getMultires, (setter)Mesh_setMultires,
+ "The current multires display level",
+ (void *)MESH_MULTIRES_LEVEL},
+ {"multiresEdgeLevel",
+ (getter)Mesh_getMultires, (setter)Mesh_setMultires,
+ "The current multires edge level",
+ (void *)MESH_MULTIRES_EDGE},
+ {"multiresPinLevel",
+ (getter)Mesh_getMultires, (setter)Mesh_setMultires,
+ "The current multires pin level",
+ (void *)MESH_MULTIRES_PIN},
+ {"multiresRenderLevel",
+ (getter)Mesh_getMultires, (setter)Mesh_setMultires,
+ "The current multires render level",
+ (void *)MESH_MULTIRES_RENDER},
+
+ {"texMesh",
+ (getter)Mesh_getTexMesh, (setter)Mesh_setTexMesh,
+ "The meshes tex mesh proxy texture coord mesh",
+ NULL},
+ {"sel",
+ (getter)NULL, (setter)Mesh_setSel,
+ "Select/deselect all verts, edges, faces in the mesh",
+ NULL},
+ {"hide",
+ (getter)NULL, (setter)Mesh_setHide,
+ "Hide/unhide all verts, edges, faces in the mesh",
+ NULL},
+
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+/*****************************************************************************/
+/* Python Mesh_Type structure definition: */
+/*****************************************************************************/
+PyTypeObject Mesh_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender Mesh", /* char *tp_name; */
+ sizeof( BPy_Mesh ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ ( destructor ) Mesh_dealloc,/* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ ( cmpfunc ) Mesh_compare, /* cmpfunc tp_compare; */
+ ( reprfunc ) Mesh_repr, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ ( hashfunc ) GenericLib_hash, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_Mesh_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ BPy_Mesh_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+/*
+ * get one or all mesh data objects
+ */
+
+static PyObject *M_Mesh_Get( PyObject * self_unused, PyObject * args )
+{
+ char *name = NULL;
+ Mesh *mesh = NULL;
+ BPy_Mesh* obj;
+
+ if( !PyArg_ParseTuple( args, "|s", &name ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected zero or one string arguments" );
+
+ if( name ) {
+ mesh = ( Mesh * ) GetIdFromList( &( G.main->mesh ), name );
+
+ if( !mesh ) {
+ char error_msg[64];
+ PyOS_snprintf( error_msg, sizeof( error_msg ),
+ "Mesh \"%s\" not found", name );
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_NameError, error_msg ) );
+ }
+ return Mesh_CreatePyObject( mesh, NULL );
+ } else { /* () - return a list with all meshes in the scene */
+ PyObject *meshlist;
+ Link *link;
+ int index = 0;
+
+ meshlist = PyList_New( BLI_countlist( &( G.main->mesh ) ) );
+
+ if( !meshlist )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create PyList" );
+
+ link = G.main->mesh.first;
+ index = 0;
+ while( link ) {
+ obj = ( BPy_Mesh * ) Mesh_CreatePyObject( ( Mesh * )link, NULL );
+ PyList_SetItem( meshlist, index, ( PyObject * ) obj );
+ index++;
+ link = link->next;
+ }
+ return meshlist;
+ }
+}
+
+/*
+ * create a new mesh data object
+ */
+
+static PyObject *M_Mesh_New( PyObject * self_unused, PyObject * args )
+{
+ char *name = "Mesh";
+ Mesh *mesh;
+ BPy_Mesh *obj;
+
+ if( !PyArg_ParseTuple( args, "|s", &name ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected nothing or a string as argument" );
+
+ obj = (BPy_Mesh *)PyObject_NEW( BPy_Mesh, &Mesh_Type );
+
+ if( !obj )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyObject_New() failed" );
+
+ mesh = add_mesh(name); /* doesn't return NULL now, but might someday */
+
+ if( !mesh ) {
+ Py_DECREF ( obj );
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "FATAL: could not create mesh object" );
+ }
+
+ /* Bound box set to null needed because a new mesh is initialized
+ with a bounding box of -1 -1 -1 -1 -1 -1
+ if its not set to null the bounding box is not re-calculated
+ when ob.getBoundBox() is called.*/
+ MEM_freeN(mesh->bb);
+ mesh->bb= NULL;
+
+ mesh->id.us = 0;
+
+ obj->mesh = mesh;
+ obj->object = NULL;
+ obj->new = 1;
+ return (PyObject *)obj;
+}
+
+/*
+ * creates a new MVert for users to manipulate
+ */
+
+static PyObject *M_Mesh_MVert( PyObject * self_unused, PyObject * args )
+{
+ int i;
+ MVert vert;
+
+ /* initialize the new vert's data */
+ memset( &vert, 0, sizeof( MVert ) );
+
+ /*
+ * accept either a 3D vector or tuple of three floats
+ */
+
+ if( PyTuple_Size ( args ) == 1 ) {
+ PyObject *tmp = PyTuple_GET_ITEM( args, 0 );
+ if( !VectorObject_Check( tmp ) || ((VectorObject *)tmp)->size != 3 )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "expected three floats or vector of size 3" );
+ for( i = 0; i < 3; ++i )
+ vert.co[i] = ((VectorObject *)tmp)->vec[i];
+ } else if( !PyArg_ParseTuple ( args, "fff",
+ &vert.co[0], &vert.co[1], &vert.co[2] ) )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "expected three floats or vector of size 3" );
+
+ /* make a new MVert from the data */
+ return PVert_CreatePyObject( &vert );
+}
+
+static PyObject *M_Mesh_Modes( PyObject * self_unused, PyObject * args )
+{
+ int modes = 0;
+
+ if( !G.scene ) {
+ Py_RETURN_NONE;
+ }
+
+ if( !PyArg_ParseTuple( args, "|i", &modes ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected optional int as argument" );
+
+ if( modes > ( SCE_SELECT_VERTEX | SCE_SELECT_EDGE | SCE_SELECT_FACE ) )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "value out of range" );
+
+ if( modes > 0 )
+ G.scene->selectmode = (short)modes;
+
+ return PyInt_FromLong( G.scene->selectmode );
+}
+
+static struct PyMethodDef M_Mesh_methods[] = {
+ {"New", (PyCFunction)M_Mesh_New, METH_VARARGS,
+ "Create a new mesh"},
+ {"Get", (PyCFunction)M_Mesh_Get, METH_VARARGS,
+ "Get a mesh by name"},
+ {"MVert", (PyCFunction)M_Mesh_MVert, METH_VARARGS,
+ "Create a new MVert"},
+ {"Mode", (PyCFunction)M_Mesh_Modes, METH_VARARGS,
+ "Get/set edit selection mode(s)"},
+ {NULL, NULL, 0, NULL},
+};
+
+static PyObject *M_Mesh_ModesDict( void )
+{
+ PyObject *Modes = PyConstant_New( );
+
+ if( Modes ) {
+ BPy_constant *d = ( BPy_constant * ) Modes;
+
+ PyConstant_Insert( d, "NOVNORMALSFLIP",
+ PyInt_FromLong( ME_NOPUNOFLIP ) );
+ PyConstant_Insert( d, "TWOSIDED", PyInt_FromLong( ME_TWOSIDED ) );
+ PyConstant_Insert( d, "AUTOSMOOTH",
+ PyInt_FromLong( ME_AUTOSMOOTH ) );
+ }
+
+ return Modes;
+}
+
+/* Set constants for face drawing mode -- see drawmesh.c */
+
+static PyObject *M_Mesh_FaceModesDict( void )
+{
+ PyObject *FM = PyConstant_New( );
+
+ if( FM ) {
+ BPy_constant *d = ( BPy_constant * ) FM;
+
+ PyConstant_Insert( d, "BILLBOARD",
+ PyInt_FromLong( TF_BILLBOARD2 ) );
+ PyConstant_Insert( d, "ALL", PyInt_FromLong( 0xffff ) );
+ PyConstant_Insert( d, "HALO", PyInt_FromLong( TF_BILLBOARD ) );
+ PyConstant_Insert( d, "DYNAMIC", PyInt_FromLong( TF_DYNAMIC ) );
+ PyConstant_Insert( d, "INVISIBLE", PyInt_FromLong( TF_INVISIBLE ) );
+ PyConstant_Insert( d, "LIGHT", PyInt_FromLong( TF_LIGHT ) );
+ PyConstant_Insert( d, "OBCOL", PyInt_FromLong( TF_OBCOL ) );
+ PyConstant_Insert( d, "SHADOW", PyInt_FromLong( TF_SHADOW ) );
+ PyConstant_Insert( d, "TEXT", PyInt_FromLong( TF_BMFONT ) );
+ PyConstant_Insert( d, "SHAREDVERT", PyInt_FromLong( TF_SHAREDVERT ) );
+ PyConstant_Insert( d, "SHAREDCOL", PyInt_FromLong( TF_SHAREDCOL ) );
+ PyConstant_Insert( d, "TEX", PyInt_FromLong( TF_TEX ) );
+ PyConstant_Insert( d, "TILES", PyInt_FromLong( TF_TILES ) );
+ PyConstant_Insert( d, "TWOSIDE", PyInt_FromLong( TF_TWOSIDE ) );
+ }
+
+ return FM;
+}
+
+static PyObject *M_Mesh_FaceFlagsDict( void )
+{
+ PyObject *FF = PyConstant_New( );
+
+ if( FF ) {
+ BPy_constant *d = ( BPy_constant * ) FF;
+
+ PyConstant_Insert( d, "SELECT", PyInt_FromLong( TF_SELECT ) );
+ PyConstant_Insert( d, "HIDE", PyInt_FromLong( TF_HIDE ) );
+ PyConstant_Insert( d, "ACTIVE", PyInt_FromLong( TF_ACTIVE ) ); /* deprecated */
+ }
+
+ return FF;
+}
+
+static PyObject *M_Mesh_FaceTranspModesDict( void )
+{
+ PyObject *FTM = PyConstant_New( );
+
+ if( FTM ) {
+ BPy_constant *d = ( BPy_constant * ) FTM;
+
+ PyConstant_Insert( d, "SOLID", PyInt_FromLong( TF_SOLID ) );
+ PyConstant_Insert( d, "ADD", PyInt_FromLong( TF_ADD ) );
+ PyConstant_Insert( d, "ALPHA", PyInt_FromLong( TF_ALPHA ) );
+ PyConstant_Insert( d, "SUB", PyInt_FromLong( TF_SUB ) );
+ }
+
+ return FTM;
+}
+
+static PyObject *M_Mesh_EdgeFlagsDict( void )
+{
+ PyObject *EF = PyConstant_New( );
+
+ if( EF ) {
+ BPy_constant *d = ( BPy_constant * ) EF;
+
+ PyConstant_Insert(d, "SELECT", PyInt_FromLong( SELECT ) );
+ PyConstant_Insert(d, "EDGEDRAW", PyInt_FromLong( ME_EDGEDRAW ) );
+ PyConstant_Insert(d, "EDGERENDER", PyInt_FromLong( ME_EDGERENDER ) );
+ PyConstant_Insert(d, "SEAM", PyInt_FromLong( ME_SEAM ) );
+ PyConstant_Insert(d, "FGON", PyInt_FromLong( ME_FGON ) );
+ PyConstant_Insert(d, "LOOSE", PyInt_FromLong( ME_LOOSEEDGE ) );
+ PyConstant_Insert(d, "SHARP", PyInt_FromLong( ME_SHARP ) );
+ }
+
+ return EF;
+}
+
+static PyObject *M_Mesh_VertAssignDict( void )
+{
+ PyObject *Vert = PyConstant_New( );
+ if( Vert ) {
+ BPy_constant *d = ( BPy_constant * ) Vert;
+ PyConstant_Insert(d, "ADD", PyInt_FromLong(WEIGHT_ADD));
+ PyConstant_Insert(d, "REPLACE", PyInt_FromLong(WEIGHT_REPLACE));
+ PyConstant_Insert(d, "SUBTRACT", PyInt_FromLong(WEIGHT_SUBTRACT));
+ }
+ return Vert;
+}
+
+
+static PyObject *M_Mesh_SelectModeDict( void )
+{
+ PyObject *Mode = PyConstant_New( );
+ if( Mode ) {
+ BPy_constant *d = ( BPy_constant * ) Mode;
+ PyConstant_Insert(d, "VERTEX", PyInt_FromLong(SCE_SELECT_VERTEX));
+ PyConstant_Insert(d, "EDGE", PyInt_FromLong(SCE_SELECT_EDGE));
+ PyConstant_Insert(d, "FACE", PyInt_FromLong(SCE_SELECT_FACE));
+ }
+ return Mode;
+}
+
+static char M_Mesh_doc[] = "The Blender.Mesh submodule";
+
+PyObject *Mesh_Init( void )
+{
+ PyObject *submodule;
+
+ PyObject *Modes = M_Mesh_ModesDict( );
+ PyObject *FaceFlags = M_Mesh_FaceFlagsDict( );
+ PyObject *FaceModes = M_Mesh_FaceModesDict( );
+ PyObject *FaceTranspModes = M_Mesh_FaceTranspModesDict( );
+ PyObject *EdgeFlags = M_Mesh_EdgeFlagsDict( );
+ PyObject *AssignModes = M_Mesh_VertAssignDict( );
+ PyObject *SelectModes = M_Mesh_SelectModeDict( );
+ PyObject *PropertyTypes = M_Mesh_PropertiesTypeDict( );
+
+ if( PyType_Ready( &MCol_Type ) < 0 )
+ return NULL;
+ if( PyType_Ready( &MVert_Type ) < 0 )
+ return NULL;
+ if( PyType_Ready( &PVert_Type ) < 0 )
+ return NULL;
+ if( PyType_Ready( &MVertSeq_Type ) < 0 )
+ return NULL;
+ if( PyType_Ready( &MEdge_Type ) < 0 )
+ return NULL;
+ if( PyType_Ready( &MEdgeSeq_Type ) < 0 )
+ return NULL;
+ if( PyType_Ready( &MFace_Type ) < 0 )
+ return NULL;
+ if( PyType_Ready( &MFaceSeq_Type ) < 0 )
+ return NULL;
+ if( PyType_Ready( &Mesh_Type ) < 0 )
+ return NULL;
+
+ submodule =
+ Py_InitModule3( "Blender.Mesh", M_Mesh_methods, M_Mesh_doc );
+ PyDict_SetItemString( PyModule_GetDict( submodule ),
+ "Primitives", MeshPrimitives_Init( ) );
+
+ if( Modes )
+ PyModule_AddObject( submodule, "Modes", Modes );
+ if( FaceFlags )
+ PyModule_AddObject( submodule, "FaceFlags", FaceFlags );
+ if( FaceModes )
+ PyModule_AddObject( submodule, "FaceModes", FaceModes );
+ if( FaceTranspModes )
+ PyModule_AddObject( submodule, "FaceTranspModes",
+ FaceTranspModes );
+ if( EdgeFlags )
+ PyModule_AddObject( submodule, "EdgeFlags", EdgeFlags );
+ if( AssignModes )
+ PyModule_AddObject( submodule, "AssignModes", AssignModes );
+ if( SelectModes )
+ PyModule_AddObject( submodule, "SelectModes", SelectModes );
+ if( PropertyTypes )
+ PyModule_AddObject( submodule, "PropertyTypes", PropertyTypes );
+
+
+
+ return submodule;
+}
+
+/* These are needed by Object.c */
+
+PyObject *Mesh_CreatePyObject( Mesh * me, Object *obj )
+{
+ BPy_Mesh *nmesh = PyObject_NEW( BPy_Mesh, &Mesh_Type );
+
+ if( !nmesh )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create BPy_Mesh object" );
+
+ nmesh->mesh = me;
+ nmesh->object = obj;
+ nmesh->new = 0;
+ G.totmesh++;
+
+ return ( PyObject * ) nmesh;
+}
+
+
+Mesh *Mesh_FromPyObject( PyObject * pyobj, Object *obj )
+{
+ BPy_Mesh *blen_obj;
+
+ blen_obj = ( BPy_Mesh * ) pyobj;
+ if (obj)
+ blen_obj->object = obj;
+
+ return blen_obj->mesh;
+
+}
diff --git a/source/blender/python/api2_2x/Mesh.h b/source/blender/python/api2_2x/Mesh.h
new file mode 100644
index 00000000000..0938f5fe8ef
--- /dev/null
+++ b/source/blender/python/api2_2x/Mesh.h
@@ -0,0 +1,127 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Ken Hughes
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/* Most of this file comes from opy_nmesh.[ch] in the old bpython dir */
+
+#ifndef EXPP_MESH_H
+#define EXPP_MESH_H
+
+#include <Python.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "Material.h"
+#include "Image.h"
+
+/* EXPP PyType Objects */
+extern PyTypeObject Mesh_Type;
+extern PyTypeObject MVert_Type;
+extern PyTypeObject PVert_Type;
+extern PyTypeObject MVertSeq_Type;
+extern PyTypeObject MEdge_Type;
+extern PyTypeObject MFace_Type;
+extern PyTypeObject MCol_Type;
+
+struct BPy_Object;
+
+/* Type checking for EXPP PyTypes */
+#define BPy_Mesh_Check(v) ((v)->ob_type == &Mesh_Type)
+#define BPy_MFace_Check(v) ((v)->ob_type == &MFace_Type)
+#define BPy_MEdge_Check(v) ((v)->ob_type == &MEdge_Type)
+#define BPy_MVert_Check(v) ((v)->ob_type == &MVert_Type)
+#define BPy_PVert_Check(v) ((v)->ob_type == &PVert_Type)
+#define BPy_MCol_Check(v) ((v)->ob_type == &MCol_Type)
+
+/* Typedefs for the new types */
+
+typedef struct {
+ PyObject_HEAD /* required python macro */
+ MCol *color;
+} BPy_MCol; /* a Mesh color: [r,g,b,a] */
+
+typedef struct {
+ PyObject_VAR_HEAD /* required python macro */
+ void * data; /* points to a Mesh or an MVert */
+ int index;
+} BPy_MVert; /* a Mesh vertex */
+
+typedef struct {
+ PyObject_VAR_HEAD /* required python macro */
+ Mesh * mesh;
+ int iter;
+} BPy_MVertSeq; /* a Mesh vertex sequence */
+
+typedef struct {
+ PyObject_VAR_HEAD /* required python macro */
+ Mesh *mesh; /* points to a Mesh */
+ int index;
+ short iter; /* char because it can only ever be between -1 and 2 */
+} BPy_MEdge; /* a Mesh edge */
+
+typedef struct {
+ PyObject_VAR_HEAD /* required python macro */
+ Mesh * mesh;
+ int iter;
+} BPy_MEdgeSeq; /* a Mesh edge sequence */
+
+typedef struct {
+ PyObject_VAR_HEAD /* required python macro */
+ Mesh * mesh;
+ int index;
+ short iter; /* char because it can only ever be between -1 and 4 */
+} BPy_MFace; /* a Mesh face */
+
+typedef struct {
+ PyObject_VAR_HEAD /* required python macro */
+ Mesh * mesh;
+ int iter;
+} BPy_MFaceSeq; /* a Mesh face sequence */
+
+typedef struct {
+ PyObject_HEAD /* required python macro */
+ Mesh *mesh;
+ Object *object;
+ char new; /* was mesh created or already existed? */
+} BPy_Mesh;
+
+/* PROTOS */
+
+PyObject *Mesh_Init( void );
+PyObject *Mesh_CreatePyObject( Mesh * me, Object *obj );
+Mesh *Mesh_FromPyObject( PyObject * pyobj, Object *obj );
+
+#endif /* EXPP_MESH_H */
diff --git a/source/blender/python/api2_2x/Metaball.c b/source/blender/python/api2_2x/Metaball.c
new file mode 100644
index 00000000000..98dc7ea1127
--- /dev/null
+++ b/source/blender/python/api2_2x/Metaball.c
@@ -0,0 +1,1189 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Jacques Guignot
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "Metaball.h" /*This must come first*/
+
+#include "BKE_main.h"
+#include "BKE_global.h"
+#include "BKE_mball.h"
+#include "BKE_library.h"
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h" /* for quat normal */
+#include "DNA_object_types.h"
+#include "Mathutils.h"
+#include "Material.h"
+#include "gen_utils.h"
+#include "gen_library.h"
+
+/* for dealing with materials */
+#include "MEM_guardedalloc.h"
+#include "BKE_material.h"
+
+/* checks for the metaelement being removed */
+#define METAELEM_DEL_CHECK_PY(bpy_meta_elem) if (!(bpy_meta_elem->metaelem)) return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, "Metaball has been removed" ) );
+#define METAELEM_DEL_CHECK_INT(bpy_meta_elem) if (!(bpy_meta_elem->metaelem)) return ( EXPP_ReturnIntError( PyExc_RuntimeError, "Metaball has been removed" ) );
+
+/*****************************************************************************/
+/* Python API function prototypes for the Metaball module. */
+/*****************************************************************************/
+static PyObject *M_Metaball_New( PyObject * self, PyObject * args );
+static PyObject *M_Metaball_Get( PyObject * self, PyObject * args );
+
+/*****************************************************************************/
+/* The following string definitions are used for documentation strings. */
+/* In Python these will be written to the console when doing a */
+/* Blender.Metaball.__doc__ */
+/*****************************************************************************/
+static char M_Metaball_doc[] =
+ "The Blender Metaball module\n\n\nMetaballs are primitive shapes\
+ such as balls, pipes, boxes and planes,\
+ that can join each other to create smooth,\
+ organic volumes\n. The shapes themseves are called\
+ 'Metaelements' and can be accessed from the Metaball module.";
+
+static char M_Metaball_New_doc[] = "Creates new metaball object data";
+
+static char M_Metaball_Get_doc[] = "Retreives an existing metaball object data";
+
+/*****************************************************************************/
+/* Python method structure definition for Blender.Metaball module: */
+/*****************************************************************************/
+struct PyMethodDef M_Metaball_methods[] = {
+ {"New", M_Metaball_New, METH_VARARGS, M_Metaball_New_doc},
+ {"Get", M_Metaball_Get, METH_VARARGS, M_Metaball_Get_doc},
+ {NULL, NULL, 0, NULL}
+};
+
+static PyObject *M_MetaElem_TypesDict( void )
+{
+ PyObject *Types = PyConstant_New( );
+
+ if( Types ) {
+ BPy_constant *d = ( BPy_constant * ) Types;
+
+ PyConstant_Insert( d, "BALL", PyInt_FromLong( MB_BALL ) );
+ /* PyConstant_Insert( d, "TUBEX", PyInt_FromLong( MB_TUBEX ) ); - DEPRICATED */
+ /* PyConstant_Insert( d, "TUBEY", PyInt_FromLong( MB_TUBEY ) ); - DEPRICATED */
+ /* PyConstant_Insert( d, "TUBEZ", PyInt_FromLong( MB_TUBEZ ) ); - DEPRICATED */
+ PyConstant_Insert( d, "TUBE", PyInt_FromLong( MB_TUBE ) );
+ PyConstant_Insert( d, "PLANE", PyInt_FromLong( MB_PLANE ) );
+ PyConstant_Insert( d, "ELIPSOID",PyInt_FromLong( MB_ELIPSOID ) );
+ PyConstant_Insert( d, "CUBE", PyInt_FromLong( MB_CUBE ) );
+ }
+
+ return Types;
+}
+
+static PyObject *M_MetaElem_UpdateDict( void )
+{
+ PyObject *Update = PyConstant_New( );
+
+ if( Update ) {
+ BPy_constant *d = ( BPy_constant * ) Update;
+ PyConstant_Insert( d, "ALWAYS", PyInt_FromLong( MB_UPDATE_ALWAYS ) );
+ PyConstant_Insert( d, "HALFRES",PyInt_FromLong( MB_UPDATE_HALFRES ) );
+ PyConstant_Insert( d, "FAST", PyInt_FromLong( MB_UPDATE_FAST ) );
+ PyConstant_Insert( d, "NEVER", PyInt_FromLong( MB_UPDATE_NEVER ) );
+ }
+
+ return Update;
+}
+
+/*****************************************************************************/
+/* Python BPy_Metaball methods declarations: */
+/*****************************************************************************/
+static PyObject *Metaball_getElements( BPy_Metaball * self );
+static PyObject *Metaball_getMaterials( BPy_Metaball * self );
+static int Metaball_setMaterials( BPy_Metaball * self, PyObject * value );
+static PyObject *Metaball_getWiresize( BPy_Metaball * self );
+static int Metaball_setWiresize( BPy_Metaball * self, PyObject * value );
+static PyObject *Metaball_getRendersize( BPy_Metaball * self );
+static int Metaball_setRendersize( BPy_Metaball * self, PyObject * value);
+static PyObject *Metaball_getThresh( BPy_Metaball * self );
+static int Metaball_setThresh( BPy_Metaball * self, PyObject * args );
+static PyObject *Metaball_getUpdate( BPy_Metaball * self );
+static int Metaball_setUpdate( BPy_Metaball * self, PyObject * args );
+static PyObject *Metaball_copy( BPy_Metaball * self );
+
+/*****************************************************************************/
+/* Python BPy_Metaball methods table: */
+/*****************************************************************************/
+static PyMethodDef BPy_Metaball_methods[] = {
+ /* name, method, flags, doc */
+ {"__copy__", ( PyCFunction ) Metaball_copy,
+ METH_NOARGS, "() - Return a copy of this metaball"},
+ {"copy", ( PyCFunction ) Metaball_copy,
+ METH_NOARGS, "() - Return a copy of this metaball"},
+ {NULL, NULL, 0, NULL}
+};
+
+/*****************************************************************************/
+/* Python BPy_Metaelem methods table: */
+/*****************************************************************************/
+static PyMethodDef BPy_Metaelem_methods[] = {
+ {NULL, NULL, 0, NULL}
+};
+
+/*****************************************************************************/
+/* Python Metaball_Type callback function prototypes: */
+/*****************************************************************************/
+static PyObject *Metaball_repr( BPy_Metaball * self );
+static int Metaball_compare( BPy_Metaball * a, BPy_Metaball * b );
+
+/*****************************************************************************/
+/* Python Metaelem_Type callback function prototypes: */
+/*****************************************************************************/
+static void Metaelem_dealloc( BPy_Metaelem * self );
+static PyObject *Metaelem_repr( BPy_Metaelem * self );
+static int Metaelem_compare( BPy_Metaelem * a, BPy_Metaelem * b );
+
+static PyObject *Metaelem_getType( BPy_Metaelem *self );
+static int Metaelem_setType( BPy_Metaelem * self, PyObject * args );
+static PyObject *Metaelem_getCoord( BPy_Metaelem * self );
+static int Metaelem_setCoord( BPy_Metaelem * self, VectorObject * value );
+static PyObject *Metaelem_getDims( BPy_Metaelem * self );
+static int Metaelem_setDims( BPy_Metaelem * self, VectorObject * value );
+static PyObject *Metaelem_getQuat( BPy_Metaelem * self );
+static int Metaelem_setQuat( BPy_Metaelem * self, QuaternionObject * value );
+static PyObject *Metaelem_getStiffness( BPy_Metaelem * self );
+static int Metaelem_setStiffness( BPy_Metaelem * self, PyObject * value );
+static PyObject *Metaelem_getRadius( BPy_Metaelem * self );
+static int Metaelem_setRadius( BPy_Metaelem * self, PyObject * value );
+
+static PyObject *Metaelem_getMFlagBits( BPy_Metaelem * self, void * type );
+static int Metaelem_setMFlagBits( BPy_Metaelem * self, PyObject * value, void * type );
+
+/*****************************************************************************/
+/* Python attributes get/set structure: */
+/*****************************************************************************/
+static PyGetSetDef BPy_Metaball_getseters[] = {
+ GENERIC_LIB_GETSETATTR,
+ {"materials",
+ (getter)Metaball_getMaterials, (setter)Metaball_setMaterials,
+ "Number of metaball users",
+ NULL},
+ {"elements",
+ (getter)Metaball_getElements, (setter)NULL,
+ "Elements in this metaball",
+ NULL},
+ {"wiresize",
+ (getter)Metaball_getWiresize, (setter)Metaball_setWiresize,
+ "The density to draw the metaball in the 3D view",
+ NULL},
+ {"rendersize",
+ (getter)Metaball_getRendersize, (setter)Metaball_setRendersize,
+ "The density to render wire",
+ NULL},
+ {"thresh",
+ (getter)Metaball_getThresh, (setter)Metaball_setThresh,
+ "The density to render wire",
+ NULL},
+ {"update",
+ (getter)Metaball_getUpdate, (setter)Metaball_setUpdate,
+ "The setting for updating this metaball data",
+ NULL},
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+
+/*****************************************************************************/
+/* Python TypeMetaball structure definition: */
+/*****************************************************************************/
+PyTypeObject Metaball_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender Metaball", /* char *tp_name; */
+ sizeof( BPy_Metaball ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ NULL, /* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ ( cmpfunc ) Metaball_compare, /* cmpfunc tp_compare; */
+ ( reprfunc ) Metaball_repr, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ ( hashfunc ) GenericLib_hash, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_Metaball_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ BPy_Metaball_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+
+static PyGetSetDef BPy_Metaelem_getseters[] = {
+ {"type",
+ (getter)Metaelem_getType, (setter)Metaelem_setType,
+ "Metaelem Type",
+ NULL},
+ {"co",
+ (getter)Metaelem_getCoord, (setter)Metaelem_setCoord,
+ "Metaelem Location",
+ NULL},
+ {"quat",
+ (getter)Metaelem_getQuat, (setter)Metaelem_setQuat,
+ "Metaelem Rotation Quat",
+ NULL},
+ {"dims",
+ (getter)Metaelem_getDims, (setter)Metaelem_setDims,
+ "Metaelem Dimensions",
+ NULL},
+ {"stiffness",
+ (getter)Metaelem_getStiffness, (setter)Metaelem_setStiffness,
+ "MetaElem stiffness",
+ NULL},
+ {"radius",
+ (getter)Metaelem_getRadius, (setter)Metaelem_setRadius,
+ "The radius of the MetaElem",
+ NULL},
+ {"negative",
+ (getter)Metaelem_getMFlagBits, (setter)Metaelem_setMFlagBits,
+ "The density to render wire",
+ (void *)MB_NEGATIVE},
+ {"hide",
+ (getter)Metaelem_getMFlagBits, (setter)Metaelem_setMFlagBits,
+ "The density to render wire",
+ (void *)MB_HIDE},
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+
+/*****************************************************************************/
+/* Python TypeMetaelem structure definition: */
+/*****************************************************************************/
+PyTypeObject Metaelem_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender Metaelem", /* char *tp_name; */
+ sizeof( BPy_Metaelem ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ ( destructor ) Metaelem_dealloc,/* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ ( cmpfunc ) Metaelem_compare, /* cmpfunc tp_compare; */
+ ( reprfunc ) Metaelem_repr, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_Metaelem_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ BPy_Metaelem_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+
+/*****************************************************************************/
+/* Function: M_Metaball_New */
+/* Python equivalent: Blender.Metaball.New */
+/*****************************************************************************/
+static PyObject *M_Metaball_New( PyObject * self, PyObject * args )
+{
+ char *name = 0;
+ BPy_Metaball *pymball; /* for Data object wrapper in Python */
+ MetaBall *blmball; /* for actual Data we create in Blender */
+
+ if( !PyArg_ParseTuple( args, "|s", &name ) )
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "Metaball.New() - expected string argument (or nothing)" ) );
+
+ /* first create the MetaBall Data in Blender */
+ if (name)
+ blmball = add_mball( name );
+ else
+ blmball = add_mball( "Meta" );
+
+ if( blmball ) {
+ /* return user count to zero since add_mball() incref'ed it */
+ blmball->id.us = 0;
+ /* now create the wrapper obj in Python */
+ pymball =
+ ( BPy_Metaball * ) PyObject_NEW( BPy_Metaball,
+ &Metaball_Type );
+ } else
+ return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "Metaball.New() - couldn't create data in Blender" ) );
+
+ if( pymball == NULL )
+ return ( EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create MetaBall Data object" ) );
+
+ pymball->metaball = blmball;
+ /*link Python mballer wrapper to Blender MetaBall */
+
+ return ( PyObject * ) pymball;
+}
+
+
+/*****************************************************************************/
+/* Function: M_Metaball_Get */
+/* Python equivalent: Blender.Metaball.Get */
+/* Description: Receives a string and returns the metaball data obj */
+/* whose name matches the string. If no argument is */
+/* passed in, a list of all metaball data names in the */
+/* current scene is returned. */
+/*****************************************************************************/
+static PyObject *M_Metaball_Get( PyObject * self, PyObject * args )
+{
+ char *name = NULL;
+ MetaBall *mball_iter = NULL;
+
+ if( !PyArg_ParseTuple( args, "|s", &name ) )
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "Metaball.Get() - expected string argument (or nothing)" ) );
+
+ if( name ) { /* (name) - Search mball by name */
+ mball_iter = ( MetaBall * ) GetIdFromList( &( G.main->mball ), name );
+
+ if (!mball_iter) {
+ char error_msg[128];
+ PyOS_snprintf( error_msg, sizeof( error_msg ),
+ "Metaball.Get(\"%s\") - not found", name );
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_NameError, error_msg ) );
+ }
+ return Metaball_CreatePyObject(mball_iter);
+
+ } else { /* () - return a list of all mballs in the scene */
+
+ PyObject *mballlist = PyList_New( BLI_countlist( &( G.main->mball ) ) );
+ int index=0;
+
+ if( mballlist == NULL )
+ return ( EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "MetaBall.Get() - couldn't create PyList" ) );
+
+ mball_iter = G.main->mball.first;
+ while( mball_iter ) {
+ PyList_SetItem( mballlist, index, Metaball_CreatePyObject(mball_iter) );
+ index++;
+ mball_iter = mball_iter->id.next;
+ }
+ return mballlist;
+ }
+
+}
+
+
+/*****************************************************************************/
+/* Function: initObject */
+/*****************************************************************************/
+PyObject *Metaball_Init( void )
+{
+ PyObject *submodule;
+ PyObject *Types= M_MetaElem_TypesDict( );
+ PyObject *Update= M_MetaElem_UpdateDict( );
+
+ if( PyType_Ready( &Metaball_Type ) < 0 )
+ return NULL;
+ if( PyType_Ready( &Metaelem_Type ) < 0 )
+ return NULL;
+ if( PyType_Ready( &MetaElemSeq_Type ) < 0 )
+ return NULL;
+
+ submodule = Py_InitModule3( "Blender.Metaball", M_Metaball_methods, M_Metaball_doc);
+
+ if( Types )
+ PyModule_AddObject( submodule, "Types", Types );
+ PyModule_AddObject( submodule, "Update", Update );
+
+ /*Add SUBMODULES to the module*/
+ /*PyDict_SetItemString(dict, "Constraint", Constraint_Init()); */ /*creates a *new* module*/
+ return submodule;
+}
+
+MetaBall *Metaball_FromPyObject( PyObject * pyobj )
+{
+ return ( ( BPy_Metaball * ) pyobj )->metaball;
+}
+
+static PyObject *Metaball_getMaterials( BPy_Metaball *self )
+{
+ return EXPP_PyList_fromMaterialList( self->metaball->mat,
+ self->metaball->totcol, 1 );
+}
+static int Metaball_setMaterials( BPy_Metaball *self, PyObject * value )
+{
+ Material **matlist;
+ int len;
+
+ if( !PySequence_Check( value ) ||
+ !EXPP_check_sequence_consistency( value, &Material_Type ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "metaball.materials - list should only contain materials or None)" );
+
+ len = PyList_Size( value );
+ if( len > 16 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "metaball.materials - list can't have more than 16 materials" );
+
+ /* free old material list (if it exists) and adjust user counts */
+ if( self->metaball->mat ) {
+ MetaBall *mb = self->metaball;
+ int i;
+ for( i = mb->totcol; i-- > 0; )
+ if( mb->mat[i] )
+ mb->mat[i]->id.us--;
+ MEM_freeN( mb->mat );
+ }
+
+ /* build the new material list, increment user count, store it */
+
+ matlist = EXPP_newMaterialList_fromPyList( value );
+ EXPP_incr_mats_us( matlist, len );
+ self->metaball->mat = matlist;
+ self->metaball->totcol = (short)len;
+
+/**@ This is another ugly fix due to the weird material handling of blender.
+ * it makes sure that object material lists get updated (by their length)
+ * according to their data material lists, otherwise blender crashes.
+ * It just stupidly runs through all objects...BAD BAD BAD.
+ */
+
+ test_object_materials( ( ID * ) self->metaball );
+
+ return 0;
+}
+
+static PyObject *Metaball_getWiresize( BPy_Metaball * self )
+{
+ return PyFloat_FromDouble( self->metaball->wiresize );
+}
+
+static int Metaball_setWiresize( BPy_Metaball * self, PyObject * value )
+{
+ float param;
+ if( !PyNumber_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "metaball.wiresize - expected float argument" );
+
+ param = (float)PyFloat_AsDouble( value );
+
+ self->metaball->wiresize = EXPP_ClampFloat(param, 0.05f, 1.0);
+ return 0;
+
+}
+static PyObject *Metaball_getRendersize( BPy_Metaball * self )
+{
+ return PyFloat_FromDouble( self->metaball->rendersize );
+}
+
+static int Metaball_setRendersize( BPy_Metaball * self, PyObject * value )
+{
+
+ float param;
+ if( !PyNumber_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "metaball.rendersize - expected float argument" );
+
+ param = (float)PyFloat_AsDouble( value );
+
+ self->metaball->rendersize = EXPP_ClampFloat(param, 0.05f, 1.0);
+ return 0;
+}
+
+static PyObject *Metaball_getThresh( BPy_Metaball * self )
+{
+ return PyFloat_FromDouble( self->metaball->thresh );
+}
+
+static int Metaball_setThresh( BPy_Metaball * self, PyObject * value )
+{
+
+ float param;
+ if( !PyNumber_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "metaball.thresh - expected float argument" );
+
+ param = (float)PyFloat_AsDouble( value );
+
+ self->metaball->thresh = EXPP_ClampFloat(param, 0.0, 5.0);
+ return 0;
+}
+
+static PyObject *Metaball_getUpdate( BPy_Metaball * self )
+{
+ return PyInt_FromLong( (long)self->metaball->flag );
+}
+
+static int Metaball_setUpdate( BPy_Metaball * self, PyObject * value )
+{
+
+ int param;
+ if( !PyInt_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "metaball.update - expected an int argument" );
+
+ param = (int)PyInt_AS_LONG( value );
+
+ self->metaball->flag = EXPP_ClampInt( param, 0, 3 );
+ return 0;
+}
+
+static PyObject *Metaball_copy( BPy_Metaball * self )
+{
+ BPy_Metaball *pymball; /* for Data object wrapper in Python */
+ MetaBall *blmball; /* for actual Data we create in Blender */
+
+ blmball = copy_mball( self->metaball ); /* first create the MetaBall Data in Blender */
+
+ if( blmball ) {
+ /* return user count to zero since add_mball() incref'ed it */
+ blmball->id.us = 0;
+ /* now create the wrapper obj in Python */
+ pymball =
+ ( BPy_Metaball * ) PyObject_NEW( BPy_Metaball,
+ &Metaball_Type );
+ } else
+ return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "metaball.__copy__() - couldn't create data in Blender" ) );
+
+ if( pymball == NULL )
+ return ( EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "metaball.__copy__() - couldn't create data in Blender" ) );
+
+ pymball->metaball = blmball;
+
+ return ( PyObject * ) pymball;
+}
+
+
+/* These are needed by Object.c */
+PyObject *Metaball_CreatePyObject( MetaBall * mball)
+{
+ BPy_Metaball *py_mball= PyObject_NEW( BPy_Metaball, &Metaball_Type );
+
+ if( !py_mball )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create BPy_Metaball object" );
+
+ py_mball->metaball= mball;
+
+ return ( PyObject * ) py_mball;
+}
+
+
+static PyObject *MetaElemSeq_CreatePyObject(BPy_Metaball *self, MetaElem *iter)
+{
+ BPy_MetaElemSeq *seq = PyObject_NEW( BPy_MetaElemSeq, &MetaElemSeq_Type);
+ seq->bpymetaball = self; Py_INCREF(self);
+ seq->iter= iter;
+ return (PyObject *)seq;
+}
+
+/*
+ * Element, get an instance of the iterator.
+ */
+static PyObject *Metaball_getElements( BPy_Metaball * self )
+{
+ return MetaElemSeq_CreatePyObject(self, NULL);
+}
+
+/*
+ * Metaelem dealloc - free from memory
+ */
+/* This is a callback function for the BPy_Metaelem type. It is */
+static void Metaelem_dealloc( BPy_Metaelem * self )
+{
+ self->metaelem= NULL; /* so any references to the same bpyobject will raise an error */
+ PyObject_DEL( self );
+}
+
+/*
+ * elem.type - int to set the shape of the element
+ */
+static PyObject *Metaelem_getType( BPy_Metaelem *self )
+{
+ METAELEM_DEL_CHECK_PY(self);
+
+ return PyInt_FromLong( self->metaelem->type );
+}
+static int Metaelem_setType( BPy_Metaelem * self, PyObject * value )
+{
+ int type;
+ if( !PyInt_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "metaelem.type - expected an integer (bitmask) as argument" );
+
+ METAELEM_DEL_CHECK_INT(self);
+
+ type = PyInt_AS_LONG( value );
+
+ if( (type < 0) || ( type > ( MB_BALL | MB_TUBEX | MB_TUBEY | MB_TUBEZ | MB_TUBE | MB_PLANE | MB_ELIPSOID | MB_CUBE ) ))
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "metaelem.type - value out of range" );
+
+ self->metaelem->type= type;
+ return 0;
+}
+
+/*
+ * elem.co - non wrapped vector representing location
+ */
+static PyObject *Metaelem_getCoord( BPy_Metaelem * self )
+{
+ float co[3];
+
+ METAELEM_DEL_CHECK_PY(self);
+
+ co[0]= self->metaelem->x;
+ co[1]= self->metaelem->y;
+ co[2]= self->metaelem->z;
+
+ return newVectorObject( co, 3, Py_NEW );
+}
+static int Metaelem_setCoord( BPy_Metaelem * self, VectorObject * value )
+{
+
+ if( !VectorObject_Check( value ) || value->size != 3 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "metaelem.co - expected vector argument of size 3" );
+
+ METAELEM_DEL_CHECK_INT(self);
+
+ self->metaelem->x= value->vec[0];
+ self->metaelem->y= value->vec[1];
+ self->metaelem->z= value->vec[2];
+ return 0;
+}
+
+/*
+ * elem.dims - non wrapped vector representing the xyz dimensions
+ * only effects some element types
+ */
+static PyObject *Metaelem_getDims( BPy_Metaelem * self )
+{
+ float co[3];
+ METAELEM_DEL_CHECK_PY(self);
+
+ co[0]= self->metaelem->expx;
+ co[1]= self->metaelem->expy;
+ co[2]= self->metaelem->expz;
+ return newVectorObject( co, 3, Py_NEW );
+}
+static int Metaelem_setDims( BPy_Metaelem * self, VectorObject * value )
+{
+ if( !VectorObject_Check( value ) || value->size != 3 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "metaelem.dims - expected vector argument of size 3" );
+
+ METAELEM_DEL_CHECK_INT(self);
+
+ self->metaelem->expx= EXPP_ClampFloat(value->vec[0], 0.0, 20.0);
+ self->metaelem->expy= EXPP_ClampFloat(value->vec[1], 0.0, 20.0);
+ self->metaelem->expz= EXPP_ClampFloat(value->vec[2], 0.0, 20.0);
+ return 0;
+}
+
+/*
+ * elem.quat - non wrapped quat representing the rotation
+ * only effects some element types - a rotated ball has no effect for eg.
+ */
+static PyObject *Metaelem_getQuat( BPy_Metaelem * self )
+{
+ METAELEM_DEL_CHECK_PY(self);
+ return newQuaternionObject(self->metaelem->quat, Py_NEW);
+}
+static int Metaelem_setQuat( BPy_Metaelem * self, QuaternionObject * value )
+{
+ int i;
+ if( !QuaternionObject_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "metaelem.quat - expected quat argument" );
+
+ METAELEM_DEL_CHECK_INT(self);
+
+ for (i = 0; i < 4; i++)
+ self->metaelem->quat[i]= value->quat[i];
+
+ /* need to normalize or metaball drawing can go into an infinate loop */
+ NormalQuat(self->metaelem->quat);
+
+ return 0;
+}
+
+/*
+ * elem.hide and elem.sel - get/set true false
+ */
+static PyObject *Metaelem_getMFlagBits( BPy_Metaelem * self, void * type )
+{
+ METAELEM_DEL_CHECK_PY(self);
+ return EXPP_getBitfield( &(self->metaelem->flag), (int)((long)type ), 'h' );
+}
+static int Metaelem_setMFlagBits( BPy_Metaelem * self, PyObject * value,
+ void * type )
+{
+ METAELEM_DEL_CHECK_INT(self);
+ return EXPP_setBitfield( value, &(self->metaelem->flag),
+ (int)((long)type), 'h' );
+}
+
+/*
+ * elem.stiffness - floating point, the volume of this element.
+ */
+static PyObject *Metaelem_getStiffness( BPy_Metaelem *self )
+{
+ METAELEM_DEL_CHECK_PY(self);
+ return PyFloat_FromDouble( self->metaelem->s );
+}
+static int Metaelem_setStiffness( BPy_Metaelem *self, PyObject *value)
+{
+ if( !PyNumber_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "metaelem.stiffness - expected float argument" );
+
+ self->metaelem->s = EXPP_ClampFloat((float)PyFloat_AsDouble( value ), 0.0, 10.0);
+ return 0;
+}
+
+/*
+ * elem.radius- floating point, the size if the element
+ */
+static PyObject *Metaelem_getRadius( BPy_Metaelem *self )
+{
+ METAELEM_DEL_CHECK_PY(self);
+ return PyFloat_FromDouble( self->metaelem->rad );
+}
+static int Metaelem_setRadius( BPy_Metaelem *self, PyObject *value)
+{
+ if( !PyNumber_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "metaelem.radius - expected float argument" );
+
+ self->metaelem->rad = /* is 5000 too small? */
+ EXPP_ClampFloat((float)PyFloat_AsDouble( value ), 0.0, 5000.0);
+
+ return 0;
+}
+
+
+/*
+ * callback functions for comparison.
+ * It compares two Metaball_Type objects. Only the "==" and "!="
+ * comparisons are meaninful. Returns 0 for equality and -1 if
+ * they don't point to the same Blender struct.
+ * In Python it becomes 1 if they are equal, 0 otherwise.
+ */
+static int Metaball_compare( BPy_Metaball * a, BPy_Metaball * b )
+{
+ MetaBall *pa = a->metaball, *pb = b->metaball;
+ return ( pa == pb ) ? 0 : -1;
+}
+
+static int MetaElemSeq_compare( BPy_MetaElemSeq * a, BPy_MetaElemSeq * b )
+{
+ MetaBall *pa = a->bpymetaball->metaball, *pb = b->bpymetaball->metaball;
+ return ( pa == pb ) ? 0 : -1;
+}
+
+static int Metaelem_compare( BPy_Metaelem * a, BPy_Metaelem * b )
+{
+ MetaElem *pa = a->metaelem, *pb = b->metaelem;
+ return ( pa == pb ) ? 0 : -1;
+}
+
+/*
+ * repr function
+ * callback functions building meaninful string to representations
+ */
+static PyObject *Metaball_repr( BPy_Metaball * self )
+{
+ return PyString_FromFormat( "[Metaball \"%s\"]",
+ self->metaball->id.name + 2 );
+}
+
+static PyObject *Metaelem_repr( BPy_Metaelem * self )
+{
+ return PyString_FromString( "Metaelem" );
+}
+
+static PyObject *MetaElemSeq_repr( BPy_MetaElemSeq * self )
+{
+ return PyString_FromFormat( "[Metaball Iterator \"%s\"]",
+ self->bpymetaball->metaball->id.name + 2 );
+}
+
+
+
+/*
+ * MeteElem Seq sequence
+ */
+
+static PyObject *MetaElem_CreatePyObject( MetaElem *metaelem )
+{
+ BPy_Metaelem *elem= PyObject_NEW( BPy_Metaelem, &Metaelem_Type);
+ elem->metaelem = metaelem; Py_INCREF(elem);
+ return (PyObject *)elem;
+}
+
+static int MetaElemSeq_len( BPy_MetaElemSeq * self )
+{
+ return BLI_countlist( &( self->bpymetaball->metaball->elems ) );
+}
+
+
+static PySequenceMethods MetaElemSeq_as_sequence = {
+ ( inquiry ) MetaElemSeq_len, /* sq_length */
+ ( binaryfunc ) 0, /* sq_concat */
+ ( intargfunc ) 0, /* sq_repeat */
+ ( intargfunc ) 0, /* sq_item */
+ ( intintargfunc ) 0, /* sq_slice */
+ ( intobjargproc ) 0, /* sq_ass_item */
+ ( intintobjargproc ) 0, /* sq_ass_slice */
+ 0,0,0,
+};
+
+/************************************************************************
+ *
+ * Python MetaElemSeq_Type iterator (iterates over Metaballs)
+ *
+ ************************************************************************/
+
+/*
+ * Initialize the interator
+ */
+
+static PyObject *MetaElemSeq_getIter( BPy_MetaElemSeq * self )
+{
+ if (!self->iter) { /* not alredy looping on this data, */
+ self->iter = self->bpymetaball->metaball->elems.first;
+ return EXPP_incr_ret ( (PyObject *) self );
+ } else
+ return MetaElemSeq_CreatePyObject(self->bpymetaball, self->bpymetaball->metaball->elems.first);
+}
+
+/*
+ * Return next MetaElem.
+ */
+
+static PyObject *MetaElemSeq_nextIter( BPy_MetaElemSeq * self )
+{
+ PyObject *object;
+ if( !(self->iter) || !(self->bpymetaball->metaball) ) {
+ self->iter= NULL;
+ return EXPP_ReturnPyObjError( PyExc_StopIteration,
+ "iterator at end" );
+ }
+
+ object= MetaElem_CreatePyObject( self->iter );
+ self->iter= self->iter->next;
+ return object;
+}
+
+/*
+ * Adds and returns a new metaelement,
+ * no args are taken so the returned metaball must be modified after adding.
+ * Accessed as mball.elements.add() where mball is a python metaball data type.
+ */
+static PyObject *MetaElemSeq_add( BPy_MetaElemSeq * self )
+{
+ MetaElem *ml;
+
+ ml = MEM_callocN( sizeof( MetaElem ), "metaelem" );
+ BLI_addhead( &( self->bpymetaball->metaball->elems ), ml );
+ ml->x = 0;
+ ml->y = 0;
+ ml->z = 0;
+ ml->quat[0]= 1.0;
+ ml->quat[1]= 0.0;
+ ml->quat[2]= 0.0;
+ ml->quat[3]= 0.0;
+ ml->rad = 2;
+ ml->s = 2.0;
+ ml->flag = SELECT;
+ ml->type = 0;
+ ml->expx = 1;
+ ml->expy = 1;
+ ml->expz = 1;
+ ml->type = MB_BALL;
+
+ return MetaElem_CreatePyObject(ml);
+}
+
+
+/*
+ * removes a metaelement if it is a part of the metaball,
+ * no args are taken so the returned metaball must be modified after adding.
+ * Accessed as mball.elements.add() where mball is a python metaball data type.
+ */
+static PyObject *MetaElemSeq_remove( BPy_MetaElemSeq * self, BPy_Metaelem *elem )
+{
+ MetaElem *ml_iter, *ml_py;
+
+ if( !BPy_Metaelem_Check(elem) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "elements.remove(metaelem) - expected a Metaball element" );
+
+ METAELEM_DEL_CHECK_PY(elem);
+
+ ml_py= elem->metaelem;
+
+ for (ml_iter= self->bpymetaball->metaball->elems.first; ml_iter; ml_iter= ml_iter->next) {
+ if (ml_py == ml_iter) {
+ elem->metaelem= NULL;
+ BLI_freelinkN( &(self->bpymetaball->metaball->elems), ml_py);
+ Py_RETURN_NONE;
+ }
+ }
+
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "elements.remove(elem): elem not in meta elements" );
+
+}
+
+static struct PyMethodDef BPy_MetaElemSeq_methods[] = {
+ {"add", (PyCFunction)MetaElemSeq_add, METH_NOARGS,
+ "add metaelem to metaball data"},
+ {"remove", (PyCFunction)MetaElemSeq_remove, METH_O,
+ "remove element from metaball data"},
+ {NULL, NULL, 0, NULL}
+};
+
+/************************************************************************
+ *
+ * Python MetaElemSeq_Type standard operations
+ *
+ ************************************************************************/
+
+static void MetaElemSeq_dealloc( BPy_MetaElemSeq * self )
+{
+ Py_DECREF(self->bpymetaball);
+ PyObject_DEL( self );
+}
+
+/*****************************************************************************/
+/* Python MetaElemSeq_Type structure definition: */
+/*****************************************************************************/
+PyTypeObject MetaElemSeq_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender MetaElemSeq", /* char *tp_name; */
+ sizeof( BPy_MetaElemSeq ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ ( destructor ) MetaElemSeq_dealloc,/* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ ( cmpfunc ) MetaElemSeq_compare, /* cmpfunc tp_compare; */
+ ( reprfunc ) MetaElemSeq_repr, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ &MetaElemSeq_as_sequence, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ ( getiterfunc) MetaElemSeq_getIter, /* getiterfunc tp_iter; */
+ ( iternextfunc ) MetaElemSeq_nextIter, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_MetaElemSeq_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ NULL, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
diff --git a/source/blender/python/api2_2x/Metaball.h b/source/blender/python/api2_2x/Metaball.h
new file mode 100644
index 00000000000..a54424302df
--- /dev/null
+++ b/source/blender/python/api2_2x/Metaball.h
@@ -0,0 +1,81 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Jacques Guignot
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef EXPP_METABALL_H
+#define EXPP_METABALL_H
+
+#include <Python.h>
+#include "DNA_meta_types.h"
+
+
+extern PyTypeObject Metaball_Type;
+
+#define BPy_Metaball_Check(v) ((v)->ob_type==&Metaball_Type)
+
+
+/* Python BPy_Metaball structure definition */
+typedef struct {
+ PyObject_HEAD /* required py macro */
+ MetaBall * metaball; /* libdata must be second */
+} BPy_Metaball;
+
+
+extern PyTypeObject Metaelem_Type;
+
+#define BPy_Metaelem_Check(v) ((v)->ob_type==&Metaelem_Type)
+
+/* Python BPy_Metaelem structure definition */
+typedef struct {
+ PyObject_HEAD /* required py macro */
+ MetaElem * metaelem;
+} BPy_Metaelem;
+
+extern PyTypeObject MetaElemSeq_Type;
+
+#define BPy_MetaElemSeq_Check(v) ((v)->ob_type==&MetaElemSeq_Type)
+
+/* Python BPy_MetaElemSeq structure definition */
+typedef struct {
+ PyObject_HEAD /* required py macro */
+ BPy_Metaball *bpymetaball; /* link to the python group so we can know if its been removed */
+ MetaElem * iter; /* so we can iterate over the objects */
+} BPy_MetaElemSeq;
+
+/*
+ * prototypes
+ */
+
+PyObject *Metaball_Init( void );
+PyObject *Metaball_CreatePyObject( MetaBall * mball );
+MetaBall *Metaball_FromPyObject( PyObject * py_obj );
+
+#endif /* EXPP_METABALL_H */
diff --git a/source/blender/python/api2_2x/Modifier.c b/source/blender/python/api2_2x/Modifier.c
new file mode 100644
index 00000000000..a1b052eb674
--- /dev/null
+++ b/source/blender/python/api2_2x/Modifier.c
@@ -0,0 +1,1693 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Ken Hughes, Campbell Barton
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/* TODO, accessing a modifier sequence of a deleted object will crash blender at the moment, not sure how to fix this. */
+
+
+#include "Modifier.h" /*This must come first*/
+
+#include "DNA_object_types.h"
+#include "DNA_effect_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_vec_types.h"
+
+#include "BKE_main.h"
+#include "BKE_global.h"
+#include "BKE_modifier.h"
+#include "BKE_library.h"
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "MEM_guardedalloc.h"
+#include "butspace.h"
+#include "blendef.h"
+#include "mydevice.h"
+
+#include "Object.h"
+#include "Texture.h"
+#include "Mathutils.h"
+#include "gen_utils.h"
+#include "gen_library.h"
+
+/* checks for the scene being removed */
+#define MODIFIER_DEL_CHECK_PY(bpy_modifier) if (!(bpy_modifier->md)) return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, "Modifier has been removed" ) )
+#define MODIFIER_DEL_CHECK_INT(bpy_modifier) if (!(bpy_modifier->md)) return ( EXPP_ReturnIntError( PyExc_RuntimeError, "Modifier has been removed" ) )
+
+enum mod_constants {
+ /*Apply to all modifiers*/
+ EXPP_MOD_RENDER = 0,
+ EXPP_MOD_REALTIME,
+ EXPP_MOD_EDITMODE,
+ EXPP_MOD_ONCAGE,
+
+ /*GENERIC*/
+ EXPP_MOD_OBJECT, /*ARMATURE, LATTICE, CURVE, BOOLEAN, ARRAY*/
+ EXPP_MOD_VERTGROUP, /*ARMATURE, LATTICE, CURVE, SMOOTH, CAST*/
+ EXPP_MOD_LIMIT, /*ARRAY, MIRROR*/
+ EXPP_MOD_FLAG, /*MIRROR, WAVE*/
+ EXPP_MOD_COUNT, /*DECIMATOR, ARRAY*/
+ EXPP_MOD_LENGTH, /*BUILD, ARRAY*/
+ EXPP_MOD_FACTOR, /*SMOOTH, CAST*/
+ EXPP_MOD_ENABLE_X, /*SMOOTH, CAST*/
+ EXPP_MOD_ENABLE_Y, /*SMOOTH, CAST*/
+ EXPP_MOD_ENABLE_Z, /*SMOOTH, CAST*/
+ EXPP_MOD_TYPES, /*SUBSURF, CAST*/
+
+ /*SUBSURF SPECIFIC*/
+ EXPP_MOD_LEVELS,
+ EXPP_MOD_RENDLEVELS,
+ EXPP_MOD_OPTIMAL,
+ EXPP_MOD_UV,
+
+ /*ARMATURE SPECIFIC*/
+ EXPP_MOD_ENVELOPES,
+
+ /*ARRAY SPECIFIC*/
+ EXPP_MOD_OBJECT_OFFSET,
+ EXPP_MOD_OBJECT_CURVE,
+ EXPP_MOD_OFFSET_VEC,
+ EXPP_MOD_SCALE_VEC,
+ EXPP_MOD_MERGE_DIST,
+
+ /*BUILD SPECIFIC*/
+ EXPP_MOD_START,
+ EXPP_MOD_SEED,
+ EXPP_MOD_RANDOMIZE,
+
+ /*MIRROR SPECIFIC*/
+ EXPP_MOD_AXIS_X,
+ EXPP_MOD_AXIS_Y,
+ EXPP_MOD_AXIS_Z,
+
+ /*DECIMATE SPECIFIC*/
+ EXPP_MOD_RATIO,
+
+ /*WAVE SPECIFIC*/
+ EXPP_MOD_STARTX,
+ EXPP_MOD_STARTY,
+ EXPP_MOD_HEIGHT,
+ EXPP_MOD_WIDTH,
+ EXPP_MOD_NARROW,
+ EXPP_MOD_SPEED,
+ EXPP_MOD_DAMP,
+ EXPP_MOD_LIFETIME,
+ EXPP_MOD_TIMEOFFS,
+
+ /*BOOLEAN SPECIFIC*/
+ EXPP_MOD_OPERATION,
+
+ /*EDGE SPLIT SPECIFIC */
+ EXPP_MOD_EDGESPLIT_ANGLE,
+ EXPP_MOD_EDGESPLIT_FROM_ANGLE,
+ EXPP_MOD_EDGESPLIT_FROM_SHARP,
+
+ /* DISPLACE */
+ EXPP_MOD_UVLAYER,
+ EXPP_MOD_MID_LEVEL,
+ EXPP_MOD_STRENGTH,
+ EXPP_MOD_TEXTURE,
+ EXPP_MOD_MAPPING,
+ EXPP_MOD_DIRECTION,
+
+ /* SMOOTH */
+ EXPP_MOD_REPEAT,
+
+ /* CAST */
+ EXPP_MOD_RADIUS,
+ EXPP_MOD_SIZE,
+ EXPP_MOD_USE_OB_TRANSFORM,
+ EXPP_MOD_SIZE_FROM_RADIUS
+
+ /* yet to be implemented */
+ /* EXPP_MOD_HOOK_,*/
+ /* , */
+};
+
+/*****************************************************************************/
+/* Python BPy_Modifier methods declarations: */
+/*****************************************************************************/
+static PyObject *Modifier_getName( BPy_Modifier * self );
+static int Modifier_setName( BPy_Modifier * self, PyObject *arg );
+static PyObject *Modifier_getType( BPy_Modifier * self );
+static PyObject *Modifier_reset( BPy_Modifier * self );
+
+static PyObject *Modifier_getData( BPy_Modifier * self, PyObject * key );
+static int Modifier_setData( BPy_Modifier * self, PyObject * key,
+ PyObject * value );
+
+/*****************************************************************************/
+/* Python BPy_Modifier methods table: */
+/*****************************************************************************/
+static PyMethodDef BPy_Modifier_methods[] = {
+ /* name, method, flags, doc */
+ {"reset", (PyCFunction)Modifier_reset, METH_NOARGS,
+ "resets a hook modifier location"},
+ {NULL, NULL, 0, NULL}
+};
+
+/*****************************************************************************/
+/* Python BPy_Modifier attributes get/set structure: */
+/*****************************************************************************/
+static PyGetSetDef BPy_Modifier_getseters[] = {
+ {"name",
+ (getter)Modifier_getName, (setter)Modifier_setName,
+ "Modifier name", NULL},
+ {"type",
+ (getter)Modifier_getType, (setter)NULL,
+ "Modifier type (read only)", NULL},
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+/*****************************************************************************/
+/* Python Modifier_Type Mapping Methods table: */
+/*****************************************************************************/
+static PyMappingMethods Modifier_as_mapping = {
+ NULL, /* mp_length */
+ ( binaryfunc ) Modifier_getData, /* mp_subscript */
+ ( objobjargproc ) Modifier_setData, /* mp_ass_subscript */
+};
+
+/*****************************************************************************/
+/* Python Modifier_Type callback function prototypes: */
+/*****************************************************************************/
+static PyObject *Modifier_repr( BPy_Modifier * self );
+
+/*****************************************************************************/
+/* Python Modifier_Type structure definition: */
+/*****************************************************************************/
+PyTypeObject Modifier_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender Modifier", /* char *tp_name; */
+ sizeof( BPy_Modifier ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ NULL, /* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* cmpfunc tp_compare; */
+ ( reprfunc ) Modifier_repr, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ &Modifier_as_mapping, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_Modifier_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ BPy_Modifier_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+/*****************************************************************************/
+/* Python BPy_Modifier methods: */
+/*****************************************************************************/
+
+/*
+ * return the name of this modifier
+ */
+
+static PyObject *Modifier_getName( BPy_Modifier * self )
+{
+ MODIFIER_DEL_CHECK_PY(self);
+ return PyString_FromString( self->md->name );
+}
+
+/*
+ * set the name of this modifier
+ */
+
+static int Modifier_setName( BPy_Modifier * self, PyObject * attr )
+{
+ char *name = PyString_AsString( attr );
+ if( !name )
+ return EXPP_ReturnIntError( PyExc_TypeError, "expected string arg" );
+
+ MODIFIER_DEL_CHECK_INT(self);
+
+ BLI_strncpy( self->md->name, name, sizeof( self->md->name ) );
+
+ return 0;
+}
+
+/*
+ * return the type of this modifier
+ */
+
+static PyObject *Modifier_getType( BPy_Modifier * self )
+{
+ MODIFIER_DEL_CHECK_PY(self);
+
+ return PyInt_FromLong( self->md->type );
+}
+
+static PyObject *subsurf_getter( BPy_Modifier * self, int type )
+{
+ SubsurfModifierData *md = ( SubsurfModifierData *)(self->md);
+
+ switch( type ) {
+ case EXPP_MOD_TYPES:
+ return PyInt_FromLong( ( long )md->subdivType );
+ case EXPP_MOD_LEVELS:
+ return PyInt_FromLong( ( long )md->levels );
+ case EXPP_MOD_RENDLEVELS:
+ return PyInt_FromLong( ( long )md->renderLevels );
+ case EXPP_MOD_OPTIMAL:
+ return PyBool_FromLong( ( long )
+ ( md->flags & eSubsurfModifierFlag_ControlEdges ) ) ;
+ case EXPP_MOD_UV:
+ return PyBool_FromLong( ( long )
+ ( md->flags & eSubsurfModifierFlag_SubsurfUv ) ) ;
+ default:
+ return EXPP_ReturnPyObjError( PyExc_KeyError,
+ "key not found" );
+ }
+}
+
+static int subsurf_setter( BPy_Modifier * self, int type,
+ PyObject *value )
+{
+ SubsurfModifierData *md = (SubsurfModifierData *)(self->md);
+
+ switch( type ) {
+ case EXPP_MOD_TYPES:
+ return EXPP_setIValueRange( value, &md->subdivType, 0, 1, 'h' );
+ case EXPP_MOD_LEVELS:
+ return EXPP_setIValueClamped( value, &md->levels, 1, 6, 'h' );
+ case EXPP_MOD_RENDLEVELS:
+ return EXPP_setIValueClamped( value, &md->renderLevels, 1, 6, 'h' );
+ case EXPP_MOD_OPTIMAL:
+ return EXPP_setBitfield( value, &md->flags,
+ eSubsurfModifierFlag_ControlEdges, 'h' );
+ case EXPP_MOD_UV:
+ return EXPP_setBitfield( value, &md->flags,
+ eSubsurfModifierFlag_SubsurfUv, 'h' );
+ default:
+ return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static PyObject *armature_getter( BPy_Modifier * self, int type )
+{
+ ArmatureModifierData *md = (ArmatureModifierData *)(self->md);
+
+ switch( type ) {
+ case EXPP_MOD_OBJECT:
+ return Object_CreatePyObject( md->object );
+ case EXPP_MOD_VERTGROUP:
+ return PyBool_FromLong( ( long )( md->deformflag & 1 ) ) ;
+ case EXPP_MOD_ENVELOPES:
+ return PyBool_FromLong( ( long )( md->deformflag & 2 ) ) ;
+ default:
+ return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static int armature_setter( BPy_Modifier *self, int type, PyObject *value )
+{
+ ArmatureModifierData *md = (ArmatureModifierData *)(self->md);
+
+ switch( type ) {
+ case EXPP_MOD_OBJECT:
+ return GenericLib_assignData(value, (void **) &md->object, 0, 0, ID_OB, OB_ARMATURE);
+ case EXPP_MOD_VERTGROUP:
+ return EXPP_setBitfield( value, &md->deformflag, 1, 'h' );
+ case EXPP_MOD_ENVELOPES:
+ return EXPP_setBitfield( value, &md->deformflag, 2, 'h' );
+ default:
+ return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static PyObject *lattice_getter( BPy_Modifier * self, int type )
+{
+ LatticeModifierData *md = (LatticeModifierData *)(self->md);
+
+ switch( type ) {
+ case EXPP_MOD_OBJECT:
+ return Object_CreatePyObject( md->object );
+ case EXPP_MOD_VERTGROUP:
+ return PyString_FromString( md->name ) ;
+ default:
+ return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static int lattice_setter( BPy_Modifier *self, int type, PyObject *value )
+{
+ LatticeModifierData *md = (LatticeModifierData *)(self->md);
+
+ switch( type ) {
+ case EXPP_MOD_OBJECT:
+ return GenericLib_assignData(value, (void **) &md->object, (void **) &self->object, 0, ID_OB, OB_LATTICE);
+ case EXPP_MOD_VERTGROUP: {
+ char *name = PyString_AsString( value );
+ if( !name )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected string arg" );
+ BLI_strncpy( md->name, name, sizeof( md->name ) );
+ break;
+ }
+ default:
+ return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
+ }
+ return 0;
+}
+
+static PyObject *curve_getter( BPy_Modifier * self, int type )
+{
+ CurveModifierData *md = (CurveModifierData *)(self->md);
+
+ switch( type ) {
+ case EXPP_MOD_OBJECT:
+ return Object_CreatePyObject( md->object );
+ case EXPP_MOD_VERTGROUP:
+ return PyString_FromString( md->name ) ;
+ default:
+ return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static int curve_setter( BPy_Modifier *self, int type, PyObject *value )
+{
+ CurveModifierData *md = (CurveModifierData *)(self->md);
+
+ switch( type ) {
+ case EXPP_MOD_OBJECT:
+ return GenericLib_assignData(value, (void **) &md->object, (void **) &self->object, 0, ID_OB, OB_CURVE);
+ case EXPP_MOD_VERTGROUP: {
+ char *name = PyString_AsString( value );
+ if( !name )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected string arg" );
+ BLI_strncpy( md->name, name, sizeof( md->name ) );
+ break;
+ }
+ default:
+ return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
+ }
+ return 0;
+}
+
+static PyObject *build_getter( BPy_Modifier * self, int type )
+{
+ BuildModifierData *md = (BuildModifierData *)(self->md);
+
+ switch( type ) {
+ case EXPP_MOD_START:
+ return PyFloat_FromDouble( ( float )md->start );
+ case EXPP_MOD_LENGTH:
+ return PyFloat_FromDouble( ( float )md->length );
+ case EXPP_MOD_SEED:
+ return PyInt_FromLong( ( long )md->seed );
+ case EXPP_MOD_RANDOMIZE:
+ return PyBool_FromLong( ( long )md->randomize ) ;
+ default:
+ return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static int build_setter( BPy_Modifier *self, int type, PyObject *value )
+{
+ BuildModifierData *md = (BuildModifierData *)(self->md);
+
+ switch( type ) {
+ case EXPP_MOD_START:
+ return EXPP_setFloatClamped( value, &md->start, 1.0, MAXFRAMEF );
+ case EXPP_MOD_LENGTH:
+ return EXPP_setFloatClamped( value, &md->length, 1.0, MAXFRAMEF );
+ case EXPP_MOD_SEED:
+ return EXPP_setIValueClamped( value, &md->seed, 1, MAXFRAME, 'i' );
+ case EXPP_MOD_RANDOMIZE:
+ return EXPP_setBitfield( value, &md->randomize, 1, 'i' );
+ default:
+ return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static PyObject *mirror_getter( BPy_Modifier * self, int type )
+{
+ MirrorModifierData *md = (MirrorModifierData *)(self->md);
+
+ switch( type ) {
+ case EXPP_MOD_LIMIT:
+ return PyFloat_FromDouble( (double)md->tolerance );
+ case EXPP_MOD_FLAG:
+ return PyBool_FromLong( (long)( md->flag & MOD_MIR_CLIPPING ) ) ;
+ case EXPP_MOD_AXIS_X:
+ return PyBool_FromLong( ( long )
+ ( md->flag & MOD_MIR_AXIS_X ) ) ;
+ case EXPP_MOD_AXIS_Y:
+ return PyBool_FromLong( ( long )
+ ( md->flag & MOD_MIR_AXIS_Y ) ) ;
+ case EXPP_MOD_AXIS_Z:
+ return PyBool_FromLong( ( long )
+ ( md->flag & MOD_MIR_AXIS_Z ) ) ;
+ default:
+ return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static int mirror_setter( BPy_Modifier *self, int type, PyObject *value )
+{
+ MirrorModifierData *md = (MirrorModifierData *)(self->md);
+
+ switch( type ) {
+ case EXPP_MOD_LIMIT:
+ return EXPP_setFloatClamped( value, &md->tolerance, 0.0, 1.0 );
+ case EXPP_MOD_FLAG:
+ return EXPP_setBitfield( value, &md->flag, MOD_MIR_CLIPPING, 'i' );
+ case EXPP_MOD_AXIS_X:
+ return EXPP_setBitfield( value, &md->flag, MOD_MIR_AXIS_X, 'h' );
+ case EXPP_MOD_AXIS_Y:
+ return EXPP_setBitfield( value, &md->flag, MOD_MIR_AXIS_Y, 'h' );
+ case EXPP_MOD_AXIS_Z:
+ return EXPP_setBitfield( value, &md->flag, MOD_MIR_AXIS_Z, 'h' );
+ default:
+ return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static PyObject *decimate_getter( BPy_Modifier * self, int type )
+{
+ DecimateModifierData *md = (DecimateModifierData *)(self->md);
+
+ if( type == EXPP_MOD_RATIO )
+ return PyFloat_FromDouble( (double)md->percent );
+ else if( type == EXPP_MOD_COUNT )
+ return PyInt_FromLong( (long)md->faceCount );
+ return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
+}
+
+static int decimate_setter( BPy_Modifier *self, int type, PyObject *value )
+{
+ DecimateModifierData *md = (DecimateModifierData *)(self->md);
+
+ if( type == EXPP_MOD_RATIO )
+ return EXPP_setFloatClamped( value, &md->percent, 0.0, 1.0 );
+ else if( type == EXPP_MOD_COUNT )
+ return EXPP_ReturnIntError( PyExc_AttributeError,
+ "value is read-only" );
+ return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
+}
+
+static PyObject *smooth_getter( BPy_Modifier * self, int type )
+{
+ SmoothModifierData *md = (SmoothModifierData *)(self->md);
+
+ switch( type ) {
+ case EXPP_MOD_FACTOR:
+ return PyFloat_FromDouble( (double)md->fac );
+ case EXPP_MOD_REPEAT:
+ return PyInt_FromLong( (long)md->repeat );
+ case EXPP_MOD_VERTGROUP:
+ return PyString_FromString( md->defgrp_name ) ;
+ case EXPP_MOD_ENABLE_X:
+ return EXPP_getBitfield( &md->flag, MOD_SMOOTH_X, 'h' );
+ case EXPP_MOD_ENABLE_Y:
+ return EXPP_getBitfield( &md->flag, MOD_SMOOTH_Y, 'h' );
+ case EXPP_MOD_ENABLE_Z:
+ return EXPP_getBitfield( &md->flag, MOD_SMOOTH_Z, 'h' );
+ default:
+ return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static int smooth_setter( BPy_Modifier *self, int type, PyObject *value )
+{
+ SmoothModifierData *md = (SmoothModifierData *)(self->md);
+
+ switch( type ) {
+ case EXPP_MOD_FACTOR:
+ return EXPP_setFloatClamped( value, &md->fac, -10.0, 10.0 );
+ case EXPP_MOD_REPEAT:
+ return EXPP_setIValueRange( value, &md->repeat, 0, 30, 'h' );
+ case EXPP_MOD_VERTGROUP: {
+ char *name = PyString_AsString( value );
+ if( !name ) return EXPP_ReturnIntError( PyExc_TypeError, "expected string arg" );
+ BLI_strncpy( md->defgrp_name, name, sizeof( md->defgrp_name ) );
+ return 0;
+ }
+ case EXPP_MOD_ENABLE_X:
+ return EXPP_setBitfield( value, &md->flag, MOD_SMOOTH_X, 'h' );
+ case EXPP_MOD_ENABLE_Y:
+ return EXPP_setBitfield( value, &md->flag, MOD_SMOOTH_Y, 'h' );
+ case EXPP_MOD_ENABLE_Z:
+ return EXPP_setBitfield( value, &md->flag, MOD_SMOOTH_Z, 'h' );
+ default:
+ return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static PyObject *cast_getter( BPy_Modifier * self, int type )
+{
+ CastModifierData *md = (CastModifierData *)(self->md);
+
+ switch( type ) {
+ case EXPP_MOD_TYPES:
+ return PyInt_FromLong( (long)md->type );
+ case EXPP_MOD_FACTOR:
+ return PyFloat_FromDouble( (double)md->fac );
+ case EXPP_MOD_RADIUS:
+ return PyFloat_FromDouble( (double)md->radius );
+ case EXPP_MOD_SIZE:
+ return PyFloat_FromDouble( (double)md->size );
+ case EXPP_MOD_OBJECT:
+ return Object_CreatePyObject( md->object );
+ case EXPP_MOD_VERTGROUP:
+ return PyString_FromString( md->defgrp_name ) ;
+ case EXPP_MOD_ENABLE_X:
+ return EXPP_getBitfield( &md->flag, MOD_CAST_X, 'h' );
+ case EXPP_MOD_ENABLE_Y:
+ return EXPP_getBitfield( &md->flag, MOD_CAST_Y, 'h' );
+ case EXPP_MOD_ENABLE_Z:
+ return EXPP_getBitfield( &md->flag, MOD_CAST_Z, 'h' );
+ case EXPP_MOD_USE_OB_TRANSFORM:
+ return EXPP_getBitfield( &md->flag, MOD_CAST_USE_OB_TRANSFORM, 'h' );
+ case EXPP_MOD_SIZE_FROM_RADIUS:
+ return EXPP_getBitfield( &md->flag, MOD_CAST_SIZE_FROM_RADIUS, 'h' );
+ default:
+ return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static int cast_setter( BPy_Modifier *self, int type, PyObject *value )
+{
+ CastModifierData *md = (CastModifierData *)(self->md);
+
+ switch( type ) {
+ case EXPP_MOD_TYPES:
+ return EXPP_setIValueRange( value, &md->type, 0, MOD_CAST_TYPE_CUBOID, 'h' );
+ case EXPP_MOD_FACTOR:
+ return EXPP_setFloatClamped( value, &md->fac, -10.0, 10.0 );
+ case EXPP_MOD_RADIUS:
+ return EXPP_setFloatClamped( value, &md->radius, 0.0, 100.0 );
+ case EXPP_MOD_SIZE:
+ return EXPP_setFloatClamped( value, &md->size, 0.0, 100.0 );
+ case EXPP_MOD_OBJECT: {
+ Object *ob_new=NULL;
+ if (value == Py_None) {
+ md->object = NULL;
+ } else if (BPy_Object_Check( value )) {
+ ob_new = ((( BPy_Object * )value)->object);
+ md->object = ob_new;
+ } else {
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "Expected an Object or None value" );
+ }
+ return 0;
+ }
+ case EXPP_MOD_VERTGROUP: {
+ char *name = PyString_AsString( value );
+ if( !name ) return EXPP_ReturnIntError( PyExc_TypeError, "expected string arg" );
+ BLI_strncpy( md->defgrp_name, name, sizeof( md->defgrp_name ) );
+ return 0;
+ }
+ case EXPP_MOD_ENABLE_X:
+ return EXPP_setBitfield( value, &md->flag, MOD_CAST_X, 'h' );
+ case EXPP_MOD_ENABLE_Y:
+ return EXPP_setBitfield( value, &md->flag, MOD_CAST_Y, 'h' );
+ case EXPP_MOD_ENABLE_Z:
+ return EXPP_setBitfield( value, &md->flag, MOD_CAST_Z, 'h' );
+ case EXPP_MOD_USE_OB_TRANSFORM:
+ return EXPP_setBitfield( value, &md->flag, MOD_CAST_USE_OB_TRANSFORM, 'h' );
+ case EXPP_MOD_SIZE_FROM_RADIUS:
+ return EXPP_setBitfield( value, &md->flag, MOD_CAST_SIZE_FROM_RADIUS, 'h' );
+ default:
+ return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static PyObject *wave_getter( BPy_Modifier * self, int type )
+{
+ WaveModifierData *md = (WaveModifierData *)(self->md);
+
+ switch( type ) {
+ case EXPP_MOD_STARTX:
+ return PyFloat_FromDouble( (double)md->startx );
+ case EXPP_MOD_STARTY:
+ return PyFloat_FromDouble( (double)md->starty );
+ case EXPP_MOD_HEIGHT:
+ return PyFloat_FromDouble( (double)md->height );
+ case EXPP_MOD_WIDTH:
+ return PyFloat_FromDouble( (double)md->width );
+ case EXPP_MOD_NARROW:
+ return PyFloat_FromDouble( (double)md->narrow );
+ case EXPP_MOD_SPEED:
+ return PyFloat_FromDouble( (double)md->speed );
+ case EXPP_MOD_DAMP:
+ return PyFloat_FromDouble( (double)md->damp );
+ case EXPP_MOD_LIFETIME:
+ return PyFloat_FromDouble( (double)md->lifetime );
+ case EXPP_MOD_TIMEOFFS:
+ return PyFloat_FromDouble( (double)md->timeoffs );
+ case EXPP_MOD_FLAG:
+ return PyInt_FromLong( (long)md->flag );
+ default:
+ return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static int wave_setter( BPy_Modifier *self, int type, PyObject *value )
+{
+ WaveModifierData *md = (WaveModifierData *)(self->md);
+
+ switch( type ) {
+ case EXPP_MOD_STARTX:
+ return EXPP_setFloatClamped( value, &md->startx, -100.0, 100.0 );
+ case EXPP_MOD_STARTY:
+ return EXPP_setFloatClamped( value, &md->starty, -100.0, 100.0 );
+ case EXPP_MOD_HEIGHT:
+ return EXPP_setFloatClamped( value, &md->height, -2.0, 2.0 );
+ case EXPP_MOD_WIDTH:
+ return EXPP_setFloatClamped( value, &md->width, 0.0, 5.0 );
+ case EXPP_MOD_NARROW:
+ return EXPP_setFloatClamped( value, &md->width, 0.0, 5.0 );
+ case EXPP_MOD_SPEED:
+ return EXPP_setFloatClamped( value, &md->speed, -2.0, 2.0 );
+ case EXPP_MOD_DAMP:
+ return EXPP_setFloatClamped( value, &md->damp, -MAXFRAMEF, MAXFRAMEF );
+ case EXPP_MOD_LIFETIME:
+ return EXPP_setFloatClamped( value, &md->lifetime, -MAXFRAMEF, MAXFRAMEF );
+ case EXPP_MOD_TIMEOFFS:
+ return EXPP_setFloatClamped( value, &md->timeoffs, -MAXFRAMEF, MAXFRAMEF );
+ case EXPP_MOD_FLAG:
+ return EXPP_setIValueRange( value, &md->flag, 0,
+ MOD_WAVE_X | MOD_WAVE_Y | MOD_WAVE_CYCL, 'h' );
+ default:
+ return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static PyObject *array_getter( BPy_Modifier * self, int type )
+{
+ ArrayModifierData *md = (ArrayModifierData *)(self->md);
+
+ if( type == EXPP_MOD_OBJECT_OFFSET )
+ return Object_CreatePyObject( md->offset_ob );
+ else if( type == EXPP_MOD_OBJECT_CURVE )
+ return Object_CreatePyObject( md->curve_ob );
+ else if( type == EXPP_MOD_COUNT )
+ return PyInt_FromLong( (long)md->count );
+ else if( type == EXPP_MOD_LENGTH )
+ return PyFloat_FromDouble( md->length );
+ else if( type == EXPP_MOD_MERGE_DIST )
+ return PyFloat_FromDouble( md->merge_dist );
+ else if( type == EXPP_MOD_MERGE_DIST )
+ return PyFloat_FromDouble( md->merge_dist );
+ else if( type == EXPP_MOD_OFFSET_VEC)
+ return newVectorObject( md->offset, 3, Py_NEW );
+ else if( type == EXPP_MOD_SCALE_VEC)
+ return newVectorObject( md->scale, 3, Py_NEW );
+
+ return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
+}
+
+static int array_setter( BPy_Modifier *self, int type, PyObject *value )
+{
+ ArrayModifierData *md = (ArrayModifierData *)(self->md);
+ switch( type ) {
+ case EXPP_MOD_OBJECT_OFFSET:
+ return GenericLib_assignData(value, (void **) &md->offset_ob, (void **) &self->object, 0, ID_OB, 0);
+ case EXPP_MOD_OBJECT_CURVE:
+ return GenericLib_assignData(value, (void **) &md->curve_ob, 0, 0, ID_OB, OB_CURVE);
+ case EXPP_MOD_COUNT:
+ return EXPP_setIValueClamped( value, &md->count, 1, 1000, 'i' );
+ case EXPP_MOD_LENGTH:
+ return EXPP_setFloatClamped( value, &md->length, 0.0, 1000.0 );
+ case EXPP_MOD_MERGE_DIST:
+ return EXPP_setFloatClamped( value, &md->merge_dist, 0.0, 1000.0 );
+ case EXPP_MOD_OFFSET_VEC:
+ return EXPP_setVec3Clamped( value, md->offset, -10000.0, 10000.0 );
+ case EXPP_MOD_SCALE_VEC:
+ return EXPP_setVec3Clamped( value, md->scale, -10000.0, 10000.0 );
+ default:
+ return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static PyObject *boolean_getter( BPy_Modifier * self, int type )
+{
+ BooleanModifierData *md = (BooleanModifierData *)(self->md);
+
+ if( type == EXPP_MOD_OBJECT )
+ return Object_CreatePyObject( md->object );
+ else if( type == EXPP_MOD_OPERATION )
+ return PyInt_FromLong( ( long )md->operation ) ;
+
+ return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
+}
+
+static int boolean_setter( BPy_Modifier *self, int type, PyObject *value )
+{
+ BooleanModifierData *md = (BooleanModifierData *)(self->md);
+
+ if( type == EXPP_MOD_OBJECT )
+ return GenericLib_assignData(value, (void **) &md->object, (void **) &self->object, 0, ID_OB, OB_MESH);
+ else if( type == EXPP_MOD_OPERATION )
+ return EXPP_setIValueRange( value, &md->operation,
+ eBooleanModifierOp_Intersect, eBooleanModifierOp_Difference,
+ 'h' );
+
+ return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
+}
+
+
+static PyObject *edgesplit_getter( BPy_Modifier * self, int type )
+{
+ EdgeSplitModifierData *md = (EdgeSplitModifierData *)(self->md);
+
+ switch( type ) {
+ case EXPP_MOD_EDGESPLIT_ANGLE:
+ return PyFloat_FromDouble( (double)md->split_angle );
+ case EXPP_MOD_EDGESPLIT_FROM_ANGLE:
+ return PyBool_FromLong( ( long )
+ ( md->flags & MOD_EDGESPLIT_FROMANGLE ) ) ;
+ case EXPP_MOD_EDGESPLIT_FROM_SHARP:
+ return PyBool_FromLong( ( long )
+ ( md->flags & MOD_EDGESPLIT_FROMFLAG ) ) ;
+
+ default:
+ return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static int edgesplit_setter( BPy_Modifier *self, int type, PyObject *value )
+{
+ EdgeSplitModifierData *md = (EdgeSplitModifierData *)(self->md);
+
+ switch( type ) {
+ case EXPP_MOD_EDGESPLIT_ANGLE:
+ return EXPP_setFloatClamped( value, &md->split_angle, 0.0, 180.0 );
+ case EXPP_MOD_EDGESPLIT_FROM_ANGLE:
+ return EXPP_setBitfield( value, &md->flags,
+ MOD_EDGESPLIT_FROMANGLE, 'h' );
+ case EXPP_MOD_EDGESPLIT_FROM_SHARP:
+ return EXPP_setBitfield( value, &md->flags,
+ MOD_EDGESPLIT_FROMFLAG, 'h' );
+
+ default:
+ return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static PyObject *displace_getter( BPy_Modifier * self, int type )
+{
+ DisplaceModifierData *md = (DisplaceModifierData *)(self->md);
+
+ switch( type ) {
+ case EXPP_MOD_TEXTURE:
+ if (md->texture) Texture_CreatePyObject( md->texture );
+ else Py_RETURN_NONE;
+ case EXPP_MOD_STRENGTH:
+ return PyFloat_FromDouble( (double)md->strength );
+ case EXPP_MOD_DIRECTION:
+ PyInt_FromLong( md->direction );
+ case EXPP_MOD_VERTGROUP:
+ return PyString_FromString( md->defgrp_name ) ;
+ case EXPP_MOD_MID_LEVEL:
+ return PyFloat_FromDouble( (double)md->midlevel );
+ case EXPP_MOD_MAPPING:
+ PyInt_FromLong( md->texmapping );
+ case EXPP_MOD_OBJECT:
+ return Object_CreatePyObject( md->map_object );
+ case EXPP_MOD_UVLAYER:
+ return PyString_FromString( md->uvlayer_name );
+ default:
+ return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static int displace_setter( BPy_Modifier *self, int type, PyObject *value )
+{
+ DisplaceModifierData *md = (DisplaceModifierData *)(self->md);
+
+ switch( type ) {
+ case EXPP_MOD_TEXTURE:
+ return GenericLib_assignData(value, (void **) &md->texture, 0, 1, ID_TE, 0);
+ case EXPP_MOD_STRENGTH:
+ return EXPP_setFloatClamped( value, &md->strength, -1000.0, 1000.0 );
+
+ case EXPP_MOD_DIRECTION:
+ return EXPP_setIValueClamped( value, &md->direction,
+ MOD_DISP_DIR_X, MOD_DISP_DIR_RGB_XYZ, 'i' );
+
+ case EXPP_MOD_VERTGROUP: {
+ char *name = PyString_AsString( value );
+ if( !name ) return EXPP_ReturnIntError( PyExc_TypeError, "expected string arg" );
+ BLI_strncpy( md->defgrp_name, name, sizeof( md->defgrp_name ) );
+ return 0;
+ }
+ case EXPP_MOD_MID_LEVEL:
+ return EXPP_setFloatClamped( value, &md->midlevel, 0.0, 1.0 );
+
+ case EXPP_MOD_MAPPING:
+ return EXPP_setIValueClamped( value, &md->texmapping,
+ MOD_DISP_MAP_LOCAL, MOD_DISP_MAP_UV, 'i' );
+
+ case EXPP_MOD_OBJECT: {
+ Object *ob_new=NULL;
+ if (value == Py_None) {
+ md->map_object = NULL;
+ } else if (BPy_Object_Check( value )) {
+ ob_new = ((( BPy_Object * )value)->object);
+ md->map_object = ob_new;
+ } else {
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "Expected an Object or None value" );
+ }
+ return 0;
+ }
+
+ case EXPP_MOD_UVLAYER: {
+ char *name = PyString_AsString( value );
+ if( !name ) return EXPP_ReturnIntError( PyExc_TypeError, "expected string arg" );
+ BLI_strncpy( md->uvlayer_name, name, sizeof( md->uvlayer_name ) );
+ return 0;
+ }
+ default:
+ return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
+ }
+}
+
+
+/* static PyObject *uvproject_getter( BPy_Modifier * self, int type )
+{
+ DisplaceModifierData *md = (DisplaceModifierData *)(self->md);
+
+ switch( type ) {
+ case EXPP_MOD_MID_LEVEL:
+ return PyFloat_FromDouble( (double)md->midlevel );
+ default:
+ return EXPP_ReturnPyObjError( PyExc_KeyError, "key not found" );
+ }
+}
+
+static int uvproject_setter( BPy_Modifier *self, int type, PyObject *value )
+{
+ DisplaceModifierData *md = (DisplaceModifierData *)(self->md);
+
+ switch( type ) {
+ case EXPP_MOD_TEXTURE:
+ return 0;
+ default:
+ return EXPP_ReturnIntError( PyExc_KeyError, "key not found" );
+ }
+} */
+
+
+/*
+ * get data from a modifier
+ */
+
+static PyObject *Modifier_getData( BPy_Modifier * self, PyObject * key )
+{
+ int setting;
+
+ if( !PyInt_Check( key ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected an int arg as stored in Blender.Modifier.Settings" );
+
+ MODIFIER_DEL_CHECK_PY(self);
+
+ setting = PyInt_AsLong( key );
+ switch( setting ) {
+ case EXPP_MOD_RENDER:
+ return EXPP_getBitfield( &self->md->mode, eModifierMode_Render, 'h' );
+ case EXPP_MOD_REALTIME:
+ return EXPP_getBitfield( &self->md->mode, eModifierMode_Realtime, 'h' );
+ case EXPP_MOD_EDITMODE:
+ return EXPP_getBitfield( &self->md->mode, eModifierMode_Editmode, 'h' );
+ case EXPP_MOD_ONCAGE:
+ return EXPP_getBitfield( &self->md->mode, eModifierMode_OnCage, 'h' );
+ default:
+ switch( self->md->type ) {
+ case eModifierType_Subsurf:
+ return subsurf_getter( self, setting );
+ case eModifierType_Armature:
+ return armature_getter( self, setting );
+ case eModifierType_Lattice:
+ return lattice_getter( self, setting );
+ case eModifierType_Curve:
+ return curve_getter( self, setting );
+ case eModifierType_Build:
+ return build_getter( self, setting );
+ case eModifierType_Mirror:
+ return mirror_getter( self, setting );
+ case eModifierType_Decimate:
+ return decimate_getter( self, setting );
+ case eModifierType_Smooth:
+ return smooth_getter( self, setting );
+ case eModifierType_Cast:
+ return cast_getter( self, setting );
+ case eModifierType_Wave:
+ return wave_getter( self, setting );
+ case eModifierType_Boolean:
+ return boolean_getter( self, setting );
+ case eModifierType_Array:
+ return array_getter( self, setting );
+ case eModifierType_EdgeSplit:
+ return edgesplit_getter( self, setting );
+ case eModifierType_Displace:
+ return displace_getter( self, setting );
+ /*case eModifierType_UVProject:
+ return uvproject_getter( self, setting );*/
+ case eModifierType_Hook:
+ case eModifierType_Softbody:
+ case eModifierType_None:
+ Py_RETURN_NONE;
+ }
+ }
+ return EXPP_ReturnPyObjError( PyExc_KeyError,
+ "unknown key or modifier type" );
+}
+
+static int Modifier_setData( BPy_Modifier * self, PyObject * key,
+ PyObject * arg )
+{
+ int key_int;
+
+ if( !PyNumber_Check( key ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected an int arg as stored in Blender.Modifier.Settings" );
+
+ MODIFIER_DEL_CHECK_INT(self);
+
+ key_int = PyInt_AsLong( key );
+
+ /* Chach for standard modifier settings */
+ switch( key_int ) {
+ case EXPP_MOD_RENDER:
+ return EXPP_setBitfield( arg, &self->md->mode,
+ eModifierMode_Render, 'h' );
+ case EXPP_MOD_REALTIME:
+ return EXPP_setBitfield( arg, &self->md->mode,
+ eModifierMode_Realtime, 'h' );
+ case EXPP_MOD_EDITMODE:
+ return EXPP_setBitfield( arg, &self->md->mode,
+ eModifierMode_Editmode, 'h' );
+ case EXPP_MOD_ONCAGE:
+ return EXPP_setBitfield( arg, &self->md->mode,
+ eModifierMode_OnCage, 'h' );
+ }
+
+ switch( self->md->type ) {
+ case eModifierType_Subsurf:
+ return subsurf_setter( self, key_int, arg );
+ case eModifierType_Armature:
+ return armature_setter( self, key_int, arg );
+ case eModifierType_Lattice:
+ return lattice_setter( self, key_int, arg );
+ case eModifierType_Curve:
+ return curve_setter( self, key_int, arg );
+ case eModifierType_Build:
+ return build_setter( self, key_int, arg );
+ case eModifierType_Mirror:
+ return mirror_setter( self, key_int, arg );
+ case eModifierType_Array:
+ return array_setter( self, key_int, arg );
+ case eModifierType_Decimate:
+ return decimate_setter( self, key_int, arg );
+ case eModifierType_Smooth:
+ return smooth_setter( self, key_int, arg );
+ case eModifierType_Cast:
+ return cast_setter( self, key_int, arg );
+ case eModifierType_Wave:
+ return wave_setter( self, key_int, arg );
+ case eModifierType_Boolean:
+ return boolean_setter( self, key_int, arg );
+ case eModifierType_EdgeSplit:
+ return edgesplit_setter( self, key_int, arg );
+ case eModifierType_Displace:
+ return displace_setter( self, key_int, arg );
+ /*case eModifierType_UVProject:
+ return uvproject_setter( self, key_int, arg );*/
+ case eModifierType_Hook:
+ case eModifierType_Softbody:
+ case eModifierType_None:
+ return 0;
+ }
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "unsupported modifier setting" );
+}
+
+
+static PyObject *Modifier_reset( BPy_Modifier * self )
+{
+ Object *ob = self->object;
+ ModifierData *md = self->md;
+ HookModifierData *hmd = (HookModifierData*) md;
+
+ MODIFIER_DEL_CHECK_PY(self);
+
+ if (md->type != eModifierType_Hook)
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "can only reset hooks" );
+
+ if (hmd->object) {
+ Mat4Invert(hmd->object->imat, hmd->object->obmat);
+ Mat4MulSerie(hmd->parentinv, hmd->object->imat, ob->obmat, NULL, NULL, NULL, NULL, NULL, NULL);
+ }
+ Py_RETURN_NONE;
+}
+
+/*****************************************************************************/
+/* Function: Modifier_repr */
+/* Description: This is a callback function for the BPy_Modifier type. It */
+/* builds a meaningful string to represent modifier objects. */
+/*****************************************************************************/
+static PyObject *Modifier_repr( BPy_Modifier * self )
+{
+ ModifierTypeInfo *mti;
+ if (self->md==NULL)
+ return PyString_FromString( "[Modifier - Removed");
+
+ mti= modifierType_getInfo(self->md->type);
+ return PyString_FromFormat( "[Modifier \"%s\", Type \"%s\"]", self->md->name, mti->name );
+}
+
+/* Three Python Modifier_Type helper functions needed by the Object module: */
+
+/*****************************************************************************/
+/* Function: Modifier_CreatePyObject */
+/* Description: This function will create a new BPy_Modifier from an */
+/* existing Blender modifier structure. */
+/*****************************************************************************/
+PyObject *Modifier_CreatePyObject( Object *ob, ModifierData * md )
+{
+ BPy_Modifier *pymod;
+ pymod = ( BPy_Modifier * ) PyObject_NEW( BPy_Modifier, &Modifier_Type );
+ if( !pymod )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create BPy_Modifier object" );
+ pymod->md = md;
+ pymod->object = ob;
+ return ( PyObject * ) pymod;
+}
+
+/*****************************************************************************/
+/* Function: Modifier_FromPyObject */
+/* Description: This function returns the Blender modifier from the given */
+/* PyObject. */
+/*****************************************************************************/
+ModifierData *Modifier_FromPyObject( PyObject * pyobj )
+{
+ return ( ( BPy_Modifier * ) pyobj )->md;
+}
+
+/*****************************************************************************/
+/* Modifier Sequence wrapper */
+/*****************************************************************************/
+
+/*
+ * Initialize the interator
+ */
+
+static PyObject *ModSeq_getIter( BPy_ModSeq * self )
+{
+ if (!self->iter) {
+ self->iter = (ModifierData *)self->object->modifiers.first;
+ return EXPP_incr_ret ( (PyObject *) self );
+ } else {
+ return ModSeq_CreatePyObject(self->object, (ModifierData *)self->object->modifiers.first);
+ }
+}
+
+/*
+ * Get the next Modifier
+ */
+
+static PyObject *ModSeq_nextIter( BPy_ModSeq * self )
+{
+ ModifierData *iter = self->iter;
+ if( iter ) {
+ self->iter = iter->next;
+ return Modifier_CreatePyObject( self->object, iter );
+ }
+
+ self->iter= NULL; /* mark as not iterating */
+ return EXPP_ReturnPyObjError( PyExc_StopIteration,
+ "iterator at end" );
+}
+
+/* return the number of modifiers */
+
+static int ModSeq_length( BPy_ModSeq * self )
+{
+ return BLI_countlist( &self->object->modifiers );
+}
+
+/* return a modifier */
+
+static PyObject *ModSeq_item( BPy_ModSeq * self, int i )
+{
+ ModifierData *md = NULL;
+
+ /* if index is negative, start counting from the end of the list */
+ if( i < 0 )
+ i += ModSeq_length( self );
+
+ /* skip through the list until we get the modifier or end of list */
+
+ for( md = self->object->modifiers.first; i && md; --i ) md = md->next;
+
+ if( md )
+ return Modifier_CreatePyObject( self->object, md );
+ else
+ return EXPP_ReturnPyObjError( PyExc_IndexError,
+ "array index out of range" );
+}
+
+/*****************************************************************************/
+/* Python BPy_ModSeq sequence table: */
+/*****************************************************************************/
+static PySequenceMethods ModSeq_as_sequence = {
+ ( inquiry ) ModSeq_length, /* sq_length */
+ ( binaryfunc ) 0, /* sq_concat */
+ ( intargfunc ) 0, /* sq_repeat */
+ ( intargfunc ) ModSeq_item, /* sq_item */
+ ( intintargfunc ) 0, /* sq_slice */
+ ( intobjargproc ) 0, /* sq_ass_item */
+ ( intintobjargproc ) 0, /* sq_ass_slice */
+ ( objobjproc ) 0, /* sq_contains */
+ ( binaryfunc ) 0, /* sq_inplace_concat */
+ ( intargfunc ) 0, /* sq_inplace_repeat */
+};
+
+/*
+ * helper function to check for a valid modifier argument
+ */
+
+static ModifierData *locate_modifier( BPy_ModSeq *self, BPy_Modifier * value )
+{
+ ModifierData *md;
+
+ /* check that argument is a modifier */
+ if( !BPy_Modifier_Check(value) )
+ return (ModifierData *)EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected an modifier as an argument" );
+
+ /* check whether modifier has been removed */
+ if( !value->md )
+ return (ModifierData *)EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "This modifier has been removed!" );
+
+ /* find the modifier in the object's list */
+ for( md = self->object->modifiers.first; md; md = md->next )
+ if( md == value->md )
+ return md;
+
+ /* return exception if we can't find the modifier */
+ return (ModifierData *)EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "This modifier is not in the object's stack" );
+}
+
+/* create a new modifier at the end of the list */
+
+static PyObject *ModSeq_append( BPy_ModSeq *self, PyObject *value )
+{
+ int type = PyInt_AsLong(value);
+
+ /* type 0 is eModifierType_None, should we be able to add one of these? */
+ if( type <= 0 || type >= NUM_MODIFIER_TYPES )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "Not an int or argument out of range, expected an int from Blender.Modifier.Type" );
+
+ BLI_addtail( &self->object->modifiers, modifier_new( type ) );
+ return Modifier_CreatePyObject( self->object, self->object->modifiers.last );
+}
+
+/* remove an existing modifier */
+
+static PyObject *ModSeq_remove( BPy_ModSeq *self, BPy_Modifier *value )
+{
+ ModifierData *md = locate_modifier( self, value );
+
+ /* if we can't locate the modifier, return (exception already set) */
+ if( !md )
+ return (PyObject *)NULL;
+
+ /* do the actual removal */
+ BLI_remlink( &self->object->modifiers, md );
+ modifier_free( md );
+
+ /* erase the link to the modifier */
+ value->md = NULL;
+
+ Py_RETURN_NONE;
+}
+
+/* move the modifier up in the stack */
+
+static PyObject *ModSeq_moveUp( BPy_ModSeq * self, BPy_Modifier * value )
+{
+ ModifierData *md = locate_modifier( self, value );
+
+ /* if we can't locate the modifier, return (exception already set) */
+ if( !md )
+ return (PyObject *)NULL;
+
+ if( mod_moveUp( self->object, md ) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "cannot move above a modifier requiring original data" );
+
+ Py_RETURN_NONE;
+}
+
+/* move the modifier down in the stack */
+
+static PyObject *ModSeq_moveDown( BPy_ModSeq * self, BPy_Modifier *value )
+{
+ ModifierData *md = locate_modifier( self, value );
+
+ /* if we can't locate the modifier, return (exception already set) */
+ if( !md )
+ return (PyObject *)NULL;
+
+ if( mod_moveDown( self->object, md ) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "cannot move beyond a non-deforming modifier" );
+
+ Py_RETURN_NONE;
+}
+
+/*****************************************************************************/
+/* Python BPy_ModSeq methods table: */
+/*****************************************************************************/
+static PyMethodDef BPy_ModSeq_methods[] = {
+ /* name, method, flags, doc */
+ {"append", ( PyCFunction ) ModSeq_append, METH_O,
+ "(type) - add a new modifier, where type is the type of modifier"},
+ {"remove", ( PyCFunction ) ModSeq_remove, METH_O,
+ "(modifier) - remove an existing modifier, where modifier is a modifier from this object."},
+ {"moveUp", ( PyCFunction ) ModSeq_moveUp, METH_O,
+ "(modifier) - Move a modifier up in stack"},
+ {"moveDown", ( PyCFunction ) ModSeq_moveDown, METH_O,
+ "(modifier) - Move a modifier down in stack"},
+ {NULL, NULL, 0, NULL}
+};
+
+/*****************************************************************************/
+/* Python ModSeq_Type structure definition: */
+/*****************************************************************************/
+PyTypeObject ModSeq_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender.Modifiers", /* char *tp_name; */
+ sizeof( BPy_ModSeq ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ NULL, /* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* cmpfunc tp_compare; */
+ ( reprfunc ) NULL, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ &ModSeq_as_sequence, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ ( getiterfunc )ModSeq_getIter, /* getiterfunc tp_iter; */
+ ( iternextfunc )ModSeq_nextIter, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_ModSeq_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ NULL, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+/*****************************************************************************/
+/* Function: ModSeq_CreatePyObject */
+/* Description: This function will create a new BPy_ModSeq from an */
+/* existing ListBase structure. */
+/*****************************************************************************/
+PyObject *ModSeq_CreatePyObject( Object *ob, ModifierData *iter )
+{
+ BPy_ModSeq *pymod;
+ pymod = ( BPy_ModSeq * ) PyObject_NEW( BPy_ModSeq, &ModSeq_Type );
+ if( !pymod )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create BPy_ModSeq object" );
+ pymod->object = ob;
+ pymod->iter = iter;
+ return ( PyObject * ) pymod;
+}
+
+static PyObject *M_Modifier_TypeDict( void )
+{
+ PyObject *S = PyConstant_New( );
+
+ if( S ) {
+ BPy_constant *d = ( BPy_constant * ) S;
+
+ PyConstant_Insert( d, "SUBSURF",
+ PyInt_FromLong( eModifierType_Subsurf ) );
+ PyConstant_Insert( d, "ARMATURE",
+ PyInt_FromLong( eModifierType_Armature ) );
+ PyConstant_Insert( d, "LATTICE",
+ PyInt_FromLong( eModifierType_Lattice ) );
+ PyConstant_Insert( d, "CURVE",
+ PyInt_FromLong( eModifierType_Curve ) );
+ PyConstant_Insert( d, "BUILD",
+ PyInt_FromLong( eModifierType_Build ) );
+ PyConstant_Insert( d, "MIRROR",
+ PyInt_FromLong( eModifierType_Mirror ) );
+ PyConstant_Insert( d, "DECIMATE",
+ PyInt_FromLong( eModifierType_Decimate ) );
+ PyConstant_Insert( d, "WAVE",
+ PyInt_FromLong( eModifierType_Wave ) );
+ PyConstant_Insert( d, "BOOLEAN",
+ PyInt_FromLong( eModifierType_Boolean ) );
+ PyConstant_Insert( d, "ARRAY",
+ PyInt_FromLong( eModifierType_Array ) );
+ PyConstant_Insert( d, "EDGESPLIT",
+ PyInt_FromLong( eModifierType_EdgeSplit ) );
+ PyConstant_Insert( d, "SMOOTH",
+ PyInt_FromLong( eModifierType_Smooth ) );
+ PyConstant_Insert( d, "CAST",
+ PyInt_FromLong( eModifierType_Cast ) );
+ }
+ return S;
+}
+
+
+static PyObject *M_Modifier_SettingsDict( void )
+{
+ PyObject *S = PyConstant_New( );
+
+ if( S ) {
+ BPy_constant *d = ( BPy_constant * ) S;
+
+/*
+# The lines below are a python script that uses the enum variables to create
+# the lines below
+# START PYSCRIPT
+st='''
+ EXPP_MOD_RENDER = 0,
+ EXPP_MOD_REALTIME,
+ EXPP_MOD_EDITMODE,
+ etc.. copy from above
+'''
+
+base= '''
+ PyConstant_Insert( d, "%s",
+ PyInt_FromLong( EXPP_MOD_%s ) );
+'''
+for var in st.replace(',','').split('\n'):
+
+ var= var.split()
+ if not var: continue
+ var= var[0]
+ if (not var) or var.startswith('/'): continue
+
+ var='_'.join(var.split('_')[2:])
+ print base % (var, var),
+# END PYSCRIPT
+*/
+
+ /*Auto generated from the above script*/
+ PyConstant_Insert( d, "RENDER",
+ PyInt_FromLong( EXPP_MOD_RENDER ) );
+ PyConstant_Insert( d, "REALTIME",
+ PyInt_FromLong( EXPP_MOD_REALTIME ) );
+ PyConstant_Insert( d, "EDITMODE",
+ PyInt_FromLong( EXPP_MOD_EDITMODE ) );
+ PyConstant_Insert( d, "ONCAGE",
+ PyInt_FromLong( EXPP_MOD_ONCAGE ) );
+ PyConstant_Insert( d, "OBJECT",
+ PyInt_FromLong( EXPP_MOD_OBJECT ) );
+ PyConstant_Insert( d, "VERTGROUP",
+ PyInt_FromLong( EXPP_MOD_VERTGROUP ) );
+ PyConstant_Insert( d, "LIMIT",
+ PyInt_FromLong( EXPP_MOD_LIMIT ) );
+ PyConstant_Insert( d, "FLAG",
+ PyInt_FromLong( EXPP_MOD_FLAG ) );
+ PyConstant_Insert( d, "COUNT",
+ PyInt_FromLong( EXPP_MOD_COUNT ) );
+ PyConstant_Insert( d, "LENGTH",
+ PyInt_FromLong( EXPP_MOD_LENGTH ) );
+ PyConstant_Insert( d, "FACTOR",
+ PyInt_FromLong( EXPP_MOD_FACTOR ) );
+ PyConstant_Insert( d, "ENABLE_X",
+ PyInt_FromLong( EXPP_MOD_ENABLE_X ) );
+ PyConstant_Insert( d, "ENABLE_Y",
+ PyInt_FromLong( EXPP_MOD_ENABLE_Y ) );
+ PyConstant_Insert( d, "ENABLE_Z",
+ PyInt_FromLong( EXPP_MOD_ENABLE_Z ) );
+ PyConstant_Insert( d, "TYPES",
+ PyInt_FromLong( EXPP_MOD_TYPES ) );
+ PyConstant_Insert( d, "LEVELS",
+ PyInt_FromLong( EXPP_MOD_LEVELS ) );
+ PyConstant_Insert( d, "RENDLEVELS",
+ PyInt_FromLong( EXPP_MOD_RENDLEVELS ) );
+ PyConstant_Insert( d, "OPTIMAL",
+ PyInt_FromLong( EXPP_MOD_OPTIMAL ) );
+ PyConstant_Insert( d, "UV",
+ PyInt_FromLong( EXPP_MOD_UV ) );
+ PyConstant_Insert( d, "ENVELOPES",
+ PyInt_FromLong( EXPP_MOD_ENVELOPES ) );
+ PyConstant_Insert( d, "OBJECT_OFFSET",
+ PyInt_FromLong( EXPP_MOD_OBJECT_OFFSET ) );
+ PyConstant_Insert( d, "OBJECT_CURVE",
+ PyInt_FromLong( EXPP_MOD_OBJECT_CURVE ) );
+ PyConstant_Insert( d, "OFFSET_VEC",
+ PyInt_FromLong( EXPP_MOD_OFFSET_VEC ) );
+ PyConstant_Insert( d, "SCALE_VEC",
+ PyInt_FromLong( EXPP_MOD_SCALE_VEC ) );
+ PyConstant_Insert( d, "MERGE_DIST",
+ PyInt_FromLong( EXPP_MOD_MERGE_DIST ) );
+ PyConstant_Insert( d, "START",
+ PyInt_FromLong( EXPP_MOD_START ) );
+ PyConstant_Insert( d, "SEED",
+ PyInt_FromLong( EXPP_MOD_SEED ) );
+ PyConstant_Insert( d, "RANDOMIZE",
+ PyInt_FromLong( EXPP_MOD_RANDOMIZE ) );
+ PyConstant_Insert( d, "AXIS_X",
+ PyInt_FromLong( EXPP_MOD_AXIS_X ) );
+ PyConstant_Insert( d, "AXIS_Y",
+ PyInt_FromLong( EXPP_MOD_AXIS_Y ) );
+ PyConstant_Insert( d, "AXIS_Z",
+ PyInt_FromLong( EXPP_MOD_AXIS_Z ) );
+ PyConstant_Insert( d, "RATIO",
+ PyInt_FromLong( EXPP_MOD_RATIO ) );
+ PyConstant_Insert( d, "STARTX",
+ PyInt_FromLong( EXPP_MOD_STARTX ) );
+ PyConstant_Insert( d, "STARTY",
+ PyInt_FromLong( EXPP_MOD_STARTY ) );
+ PyConstant_Insert( d, "HEIGHT",
+ PyInt_FromLong( EXPP_MOD_HEIGHT ) );
+ PyConstant_Insert( d, "WIDTH",
+ PyInt_FromLong( EXPP_MOD_WIDTH ) );
+ PyConstant_Insert( d, "NARROW",
+ PyInt_FromLong( EXPP_MOD_NARROW ) );
+ PyConstant_Insert( d, "SPEED",
+ PyInt_FromLong( EXPP_MOD_SPEED ) );
+ PyConstant_Insert( d, "DAMP",
+ PyInt_FromLong( EXPP_MOD_DAMP ) );
+ PyConstant_Insert( d, "LIFETIME",
+ PyInt_FromLong( EXPP_MOD_LIFETIME ) );
+ PyConstant_Insert( d, "TIMEOFFS",
+ PyInt_FromLong( EXPP_MOD_TIMEOFFS ) );
+ PyConstant_Insert( d, "OPERATION",
+ PyInt_FromLong( EXPP_MOD_OPERATION ) );
+ PyConstant_Insert( d, "EDGESPLIT_ANGLE",
+ PyInt_FromLong( EXPP_MOD_EDGESPLIT_ANGLE ) );
+ PyConstant_Insert( d, "EDGESPLIT_FROM_ANGLE",
+ PyInt_FromLong( EXPP_MOD_EDGESPLIT_FROM_ANGLE ) );
+ PyConstant_Insert( d, "EDGESPLIT_FROM_SHARP",
+ PyInt_FromLong( EXPP_MOD_EDGESPLIT_FROM_SHARP ) );
+ PyConstant_Insert( d, "UVLAYER",
+ PyInt_FromLong( EXPP_MOD_UVLAYER ) );
+ PyConstant_Insert( d, "MID_LEVEL",
+ PyInt_FromLong( EXPP_MOD_MID_LEVEL ) );
+ PyConstant_Insert( d, "STRENGTH",
+ PyInt_FromLong( EXPP_MOD_STRENGTH ) );
+ PyConstant_Insert( d, "TEXTURE",
+ PyInt_FromLong( EXPP_MOD_TEXTURE ) );
+ PyConstant_Insert( d, "MAPPING",
+ PyInt_FromLong( EXPP_MOD_MAPPING ) );
+ PyConstant_Insert( d, "DIRECTION",
+ PyInt_FromLong( EXPP_MOD_DIRECTION ) );
+ PyConstant_Insert( d, "REPEAT",
+ PyInt_FromLong( EXPP_MOD_REPEAT ) );
+ PyConstant_Insert( d, "RADIUS",
+ PyInt_FromLong( EXPP_MOD_RADIUS ) );
+ PyConstant_Insert( d, "SIZE",
+ PyInt_FromLong( EXPP_MOD_SIZE ) );
+ PyConstant_Insert( d, "USE_OB_TRANSFORM",
+ PyInt_FromLong( EXPP_MOD_USE_OB_TRANSFORM ) );
+ PyConstant_Insert( d, "SIZE_FROM_RADIUS",
+ PyInt_FromLong( EXPP_MOD_SIZE_FROM_RADIUS ) );
+ /*End Auto generated code*/
+ }
+ return S;
+}
+
+/*****************************************************************************/
+/* Function: Modifier_Init */
+/*****************************************************************************/
+PyObject *Modifier_Init( void )
+{
+ PyObject *submodule;
+ PyObject *TypeDict = M_Modifier_TypeDict( );
+ PyObject *SettingsDict = M_Modifier_SettingsDict( );
+
+ if( PyType_Ready( &ModSeq_Type ) < 0 ||
+ PyType_Ready( &Modifier_Type ) < 0 )
+ return NULL;
+
+ submodule = Py_InitModule3( "Blender.Modifier", NULL,
+ "Modifer module for accessing and creating object modifier data" );
+
+ if( TypeDict ) {
+ PyModule_AddObject( submodule, "Type", TypeDict ); /* deprecated */
+ /* since PyModule_AddObject() steals a reference, we need to
+ incref TypeDict to use it again */
+ Py_INCREF( TypeDict);
+ PyModule_AddObject( submodule, "Types", TypeDict );
+ }
+
+ if( SettingsDict )
+ PyModule_AddObject( submodule, "Settings", SettingsDict );
+
+ return submodule;
+}
diff --git a/source/blender/python/api2_2x/Modifier.h b/source/blender/python/api2_2x/Modifier.h
new file mode 100644
index 00000000000..e61371cd192
--- /dev/null
+++ b/source/blender/python/api2_2x/Modifier.h
@@ -0,0 +1,72 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Ken Hughes
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_MODIFIER_H
+#define EXPP_MODIFIER_H
+
+#include <Python.h>
+#include "DNA_object_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_listBase.h"
+
+/*****************************************************************************/
+/* Python BPy_Modifier and BPy_ModSeq structure definition: */
+/*****************************************************************************/
+typedef struct {
+ PyObject_HEAD /* required macro */
+ Object *object;
+ ModifierData *iter;
+} BPy_ModSeq;
+
+typedef struct {
+ PyObject_HEAD /* required macro */
+ Object *object;
+ /* if md this is null, the modifier has been removed and we need to raise
+ an error when its data is accessed */
+ ModifierData *md;
+} BPy_Modifier;
+
+extern PyTypeObject ModSeq_Type;
+extern PyTypeObject Modifier_Type;
+#define BPy_ModSeq_Check(v) ((v)->ob_type == &ModSeq_Type)
+#define BPy_Modifier_Check(v) ((v)->ob_type == &Modifier_Type)
+
+/*
+ * prototypes
+ */
+
+PyObject *Modifier_Init( void );
+PyObject *ModSeq_CreatePyObject( Object *obj, ModifierData *iter );
+PyObject *Modifier_CreatePyObject( Object *obj, ModifierData *md );
+ModifierData *Modifier_FromPyObject( PyObject * py_obj );
+
+#endif /* EXPP_MODIFIER_H */
diff --git a/source/blender/python/api2_2x/NLA.c b/source/blender/python/api2_2x/NLA.c
new file mode 100644
index 00000000000..7d701382f7b
--- /dev/null
+++ b/source/blender/python/api2_2x/NLA.c
@@ -0,0 +1,1590 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Joseph Gilbert
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#include "NLA.h" /*This must come first*/
+
+#include "DNA_curve_types.h"
+#include "DNA_scene_types.h"
+#include "BKE_action.h"
+#include "BKE_nla.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_library.h"
+#include "BLI_blenlib.h"
+#include "Object.h"
+#include "Ipo.h"
+#include "gen_utils.h"
+#include "gen_library.h"
+#include "blendef.h"
+#include "MEM_guardedalloc.h"
+
+#define ACTSTRIP_STRIDEAXIS_X 0
+#define ACTSTRIP_STRIDEAXIS_Y 1
+#define ACTSTRIP_STRIDEAXIS_Z 2
+
+/*****************************************************************************/
+/* Python API function prototypes for the NLA module. */
+/*****************************************************************************/
+static PyObject *M_NLA_NewAction( PyObject * self, PyObject * args );
+static PyObject *M_NLA_CopyAction( PyObject * self, PyObject * args );
+static PyObject *M_NLA_GetActions( PyObject * self );
+
+/*****************************************************************************/
+/* The following string definitions are used for documentation strings. */
+/* In Python these will be written to the console when doing a */
+/* Blender.Armature.NLA.__doc__ */
+/*****************************************************************************/
+char M_NLA_doc[] =
+ "The Blender NLA module -This module provides control over Armature keyframing in Blender.";
+char M_NLA_NewAction_doc[] =
+ "(name) - Create new action for linking to an object.";
+char M_NLA_CopyAction_doc[] = "(name) - Copy action and return copy.";
+char M_NLA_GetActions_doc[] = "(name) - Returns a dictionary of actions.";
+
+/*****************************************************************************/
+/* Python method structure definition for Blender.Armature.NLA module: */
+/*****************************************************************************/
+struct PyMethodDef M_NLA_methods[] = {
+ {"NewAction", ( PyCFunction ) M_NLA_NewAction, METH_VARARGS,
+ M_NLA_NewAction_doc},
+ {"CopyAction", ( PyCFunction ) M_NLA_CopyAction, METH_VARARGS,
+ M_NLA_CopyAction_doc},
+ {"GetActions", ( PyCFunction ) M_NLA_GetActions, METH_NOARGS,
+ M_NLA_GetActions_doc},
+ {NULL, NULL, 0, NULL}
+};
+/*****************************************************************************/
+/* Python BPy_Action methods declarations: */
+/*****************************************************************************/
+static PyObject *Action_setActive( BPy_Action * self, PyObject * args );
+static PyObject *Action_getFrameNumbers(BPy_Action *self);
+static PyObject *Action_getChannelIpo( BPy_Action * self, PyObject * value );
+static PyObject *Action_getChannelNames( BPy_Action * self );
+static PyObject *Action_renameChannel( BPy_Action * self, PyObject * args );
+static PyObject *Action_verifyChannel( BPy_Action * self, PyObject * value );
+static PyObject *Action_removeChannel( BPy_Action * self, PyObject * value );
+static PyObject *Action_getAllChannelIpos( BPy_Action * self );
+
+/*****************************************************************************/
+/* Python BPy_Action methods table: */
+/*****************************************************************************/
+static PyMethodDef BPy_Action_methods[] = {
+ /* name, method, flags, doc */
+ {"getName", ( PyCFunction ) GenericLib_getName, METH_NOARGS,
+ "() - return Action name"},
+ {"setName", ( PyCFunction ) GenericLib_setName_with_method, METH_VARARGS,
+ "(str) - rename Action"},
+ {"setActive", ( PyCFunction ) Action_setActive, METH_VARARGS,
+ "(str) -set this action as the active action for an object"},
+ {"getFrameNumbers", (PyCFunction) Action_getFrameNumbers, METH_NOARGS,
+ "() - get the frame numbers at which keys have been inserted"},
+ {"getChannelIpo", ( PyCFunction ) Action_getChannelIpo, METH_O,
+ "(str) -get the Ipo from a named action channel in this action"},
+ {"getChannelNames", ( PyCFunction ) Action_getChannelNames, METH_NOARGS,
+ "() -get the channel names for this action"},
+ {"renameChannel", ( PyCFunction ) Action_renameChannel, METH_VARARGS,
+ "(from, to) -rename the channel from string to string"},
+ {"verifyChannel", ( PyCFunction ) Action_verifyChannel, METH_O,
+ "(str) -verify the channel in this action"},
+ {"removeChannel", ( PyCFunction ) Action_removeChannel, METH_O,
+ "(str) -remove the channel from the action"},
+ {"getAllChannelIpos", ( PyCFunction ) Action_getAllChannelIpos,
+ METH_NOARGS,
+ "() - Return a dict of (name:ipo)-keys containing each channel in the object's action"},
+ {NULL, NULL, 0, NULL}
+};
+
+/*****************************************************************************/
+/* Python TypeAction callback function prototypes: */
+/*****************************************************************************/
+static int Action_compare( BPy_Action * a, BPy_Action * b );
+static PyObject *Action_repr( BPy_Action * bone );
+
+/*-------------------------------------------------------------------------*/
+static PyObject *M_NLA_NewAction( PyObject * self_unused, PyObject * args )
+{
+ char *name_str = "DefaultAction";
+ BPy_Action *py_action = NULL; /* for Action Data object wrapper in Python */
+ bAction *bl_action = NULL; /* for actual Action Data we create in Blender */
+
+ if( !PyArg_ParseTuple( args, "|s", &name_str ) ) {
+ EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected string or nothing" );
+ return NULL;
+ }
+ /* Create new action globally */
+ bl_action = alloc_libblock( &G.main->action, ID_AC, name_str );
+ bl_action->id.flag |= LIB_FAKEUSER; /* no need to assign a user because alloc_libblock alredy assigns one */
+
+
+ /* now create the wrapper obj in Python */
+ if( bl_action )
+ py_action =
+ ( BPy_Action * ) PyObject_NEW( BPy_Action,
+ &Action_Type );
+ else {
+ EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't create Action Data in Blender" );
+ return NULL;
+ }
+
+ if( py_action == NULL ) {
+ EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create Action Data object" );
+ return NULL;
+ }
+
+ py_action->action = bl_action; /* link Python action wrapper with Blender Action */
+
+ Py_INCREF( py_action );
+ return ( PyObject * ) py_action;
+}
+
+static PyObject *M_NLA_CopyAction( PyObject * self_unused, PyObject * args )
+{
+ BPy_Action *py_action = NULL;
+ bAction *copyAction = NULL;
+
+ if( !PyArg_ParseTuple( args, "O!", &Action_Type, &py_action ) ) {
+ EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected python action type" );
+ return NULL;
+ }
+ copyAction = copy_action( py_action->action );
+ return Action_CreatePyObject( copyAction );
+}
+
+static PyObject *M_NLA_GetActions( PyObject * self_unused )
+{
+ PyObject *dict = PyDict_New( );
+ bAction *action = NULL;
+
+ for( action = G.main->action.first; action; action = action->id.next ) {
+ PyObject *py_action = Action_CreatePyObject( action );
+ if( py_action ) {
+ /* Insert dict entry using the bone name as key */
+ if( PyDict_SetItemString
+ ( dict, action->id.name + 2, py_action ) != 0 ) {
+ Py_DECREF( py_action );
+ Py_DECREF( dict );
+
+ return EXPP_ReturnPyObjError
+ ( PyExc_RuntimeError,
+ "NLA_GetActions: couldn't set dict item" );
+ }
+ Py_DECREF( py_action );
+ } else {
+ Py_DECREF( dict );
+ return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "NLA_GetActions: could not create Action object" ) );
+ }
+ }
+ return dict;
+}
+
+static PyObject *Action_getFrameNumbers(BPy_Action *self)
+{
+ bActionChannel *achan = NULL;
+ IpoCurve *icu = NULL;
+ BezTriple *bezt = NULL;
+ int verts;
+ PyObject *py_list = NULL;
+
+ py_list = PyList_New(0);
+ for(achan = self->action->chanbase.first; achan; achan = achan->next){
+ if (achan->ipo) {
+ for (icu = achan->ipo->curve.first; icu; icu = icu->next){
+ bezt= icu->bezt;
+ if(bezt) {
+ verts = icu->totvert;
+ while(verts--) {
+ PyObject *value;
+ value = PyInt_FromLong((int)bezt->vec[1][0]);
+ if ( PySequence_Contains(py_list, value) == 0){
+ PyList_Append(py_list, value);
+ }
+ Py_DECREF(value);
+ bezt++;
+ }
+ }
+ }
+ }
+ }
+ PyList_Sort(py_list);
+ return EXPP_incr_ret(py_list);
+}
+
+static PyObject *Action_setActive( BPy_Action * self, PyObject * args )
+{
+ BPy_Object *object;
+
+ if( !self->action )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't get attribute from a NULL action" );
+
+ if( !PyArg_ParseTuple( args, "O!", &Object_Type, &object ) )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected python object argument" );
+
+ if( object->object->type != OB_ARMATURE )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "object not of type armature" );
+
+ /* if object is already attached to an action, decrement user count */
+ if( object->object->action )
+ --object->object->action->id.us;
+
+ /* set the active action to object */
+ object->object->action = self->action;
+ ++object->object->action->id.us;
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Action_getChannelIpo( BPy_Action * self, PyObject * value )
+{
+ char *chanName = PyString_AsString(value);
+ bActionChannel *chan;
+
+ if( !chanName )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "string expected" );
+
+ chan = get_action_channel( self->action, chanName );
+ if( !chan )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "no channel with that name" );
+
+ if( !chan->ipo ) {
+ Py_RETURN_NONE;
+ }
+
+ return Ipo_CreatePyObject( chan->ipo );
+}
+
+static PyObject *Action_getChannelNames( BPy_Action * self )
+{
+ PyObject *list = PyList_New( BLI_countlist(&(self->action->chanbase)) );
+ bActionChannel *chan = NULL;
+ int index=0;
+ for( chan = self->action->chanbase.first; chan; chan = chan->next ) {
+ PyList_SetItem( list, index, PyString_FromString(chan->name) );
+ index++;
+ }
+ return list;
+}
+
+static PyObject *Action_renameChannel( BPy_Action * self, PyObject * args )
+{
+ char *chanFrom, *chanTo;
+ bActionChannel *chan;
+
+ if( !PyArg_ParseTuple( args, "ss", &chanFrom, &chanTo ) )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "2 strings expected" );
+
+ chan = get_action_channel( self->action, chanFrom );
+ if( !chan )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "no channel with that name" );
+ if (strlen(chanTo) > 31)
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "new name greater then 31 characters long" );
+
+ if (get_action_channel( self->action, chanTo ))
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "channel target name alredy exists" );
+
+ strcpy(chan->name, chanTo);
+
+ Py_RETURN_NONE;
+}
+
+/*----------------------------------------------------------------------*/
+static PyObject *Action_verifyChannel( BPy_Action * self, PyObject * value )
+{
+ char *chanName = PyString_AsString(value);
+ bActionChannel *chan;
+
+ if( !self->action )
+ ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't create channel for a NULL action" ) );
+
+ if( !chanName )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected string argument" ) );
+
+ chan = verify_action_channel(self->action, chanName);
+
+ Py_RETURN_NONE;
+}
+
+
+static PyObject *Action_removeChannel( BPy_Action * self, PyObject * value )
+{
+ char *chanName = PyString_AsString(value);
+ bActionChannel *chan;
+
+ if( !chanName )
+ return (EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "string expected" ));
+
+
+ chan = get_action_channel( self->action, chanName );
+ if( chan == NULL ) {
+ EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "no channel with that name..." );
+ return NULL;
+ }
+ /*release ipo*/
+ if( chan->ipo )
+ chan->ipo->id.us--;
+
+ /*remove channel*/
+ BLI_freelinkN( &self->action->chanbase, chan );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Action_getAllChannelIpos( BPy_Action * self )
+{
+ PyObject *dict = PyDict_New( );
+ bActionChannel *chan = NULL;
+
+ for( chan = self->action->chanbase.first; chan; chan = chan->next ) {
+ PyObject *ipo_attr;
+ if( chan->ipo )
+ ipo_attr = Ipo_CreatePyObject( chan->ipo );
+ else {
+ ipo_attr = Py_None;
+ Py_INCREF( ipo_attr );
+ }
+ if( ipo_attr ) {
+ /* Insert dict entry using the bone name as key*/
+ if( PyDict_SetItemString( dict, chan->name, ipo_attr )
+ != 0 ) {
+ Py_DECREF( ipo_attr );
+ Py_DECREF( dict );
+
+ return EXPP_ReturnPyObjError
+ ( PyExc_RuntimeError,
+ "Action_getAllChannelIpos: couldn't set dict item" );
+ }
+ Py_DECREF( ipo_attr );
+ } else {
+ Py_DECREF( dict );
+ return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "Action_getAllChannelIpos: could not create Ipo object" ) );
+ }
+ }
+ return dict;
+}
+
+/*----------------------------------------------------------------------*/
+static int Action_compare( BPy_Action * a, BPy_Action * b )
+{
+ return ( a->action == b->action ) ? 0 : -1;
+}
+
+/*----------------------------------------------------------------------*/
+static PyObject *Action_repr( BPy_Action * self )
+{
+ if( self->action )
+ return PyString_FromFormat( "[Action \"%s\"]",
+ self->action->id.name + 2 );
+ else
+ return PyString_FromString( "NULL" );
+}
+
+/*----------------------------------------------------------------------*/
+PyObject *Action_CreatePyObject( struct bAction * act )
+{
+ BPy_Action *blen_action;
+
+ if(!act) Py_RETURN_NONE;
+
+ blen_action =
+ ( BPy_Action * ) PyObject_NEW( BPy_Action, &Action_Type );
+
+ if( !blen_action) {
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_RuntimeError, "failure to create object!" ) );
+ }
+ blen_action->action = act;
+ return ( ( PyObject * ) blen_action );
+}
+
+/*----------------------------------------------------------------------*/
+struct bAction *Action_FromPyObject( PyObject * py_obj )
+{
+ BPy_Action *blen_obj;
+
+ blen_obj = ( BPy_Action * ) py_obj;
+ return ( blen_obj->action );
+}
+
+/*****************************************************************************/
+/* Python attributes get/set structure: */
+/*****************************************************************************/
+static PyGetSetDef BPy_Action_getseters[] = {
+ GENERIC_LIB_GETSETATTR,
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+/*****************************************************************************/
+/* Python TypeAction structure definition: */
+/*****************************************************************************/
+PyTypeObject Action_Type = {
+ PyObject_HEAD_INIT( NULL )
+ 0, /* ob_size */
+ "Blender Action", /* tp_name */
+ sizeof( BPy_Action ), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ /* methods */
+ NULL, /* tp_dealloc */
+ NULL, /* tp_print */
+ NULL, /* tp_getattr */
+ NULL, /* tp_setattr */
+ ( cmpfunc ) Action_compare, /* tp_compare */
+ ( reprfunc ) Action_repr, /* tp_repr */
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ ( hashfunc ) GenericLib_hash, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_Action_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ BPy_Action_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+
+
+/*****************************************************************************/
+/* ActionStrip wrapper */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* Python BPy_ActionStrip attributes: */
+/*****************************************************************************/
+
+/*
+ * return the action for the action strip
+ */
+
+static PyObject *ActionStrip_getAction( BPy_ActionStrip * self )
+{
+ if( !self->strip )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "This strip has been removed!" );
+
+ return Action_CreatePyObject( self->strip->act );
+}
+
+/*
+ * return the start frame of the action strip
+ */
+
+static PyObject *ActionStrip_getStripStart( BPy_ActionStrip * self )
+{
+ if( !self->strip )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "This strip has been removed!" );
+
+ return PyFloat_FromDouble( self->strip->start );
+}
+
+/*
+ * set the start frame of the action strip
+ */
+
+static int ActionStrip_setStripStart( BPy_ActionStrip * self, PyObject * value )
+{
+ int retval;
+
+ if( !self->strip )
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "This strip has been removed!" );
+
+ retval = EXPP_setFloatClamped( value, &self->strip->start,
+ -1000.0, self->strip->end-1 );
+ if( !retval ) {
+ float max = self->strip->end - self->strip->start;
+ if( self->strip->blendin > max )
+ self->strip->blendin = max;
+ if( self->strip->blendout > max )
+ self->strip->blendout = max;
+ }
+ return retval;
+}
+
+/*
+ * return the ending frame of the action strip
+ */
+
+static PyObject *ActionStrip_getStripEnd( BPy_ActionStrip * self )
+{
+ if( !self->strip )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "This strip has been removed!" );
+
+ return PyFloat_FromDouble( self->strip->end );
+}
+
+/*
+ * set the ending frame of the action strip
+ */
+
+static int ActionStrip_setStripEnd( BPy_ActionStrip * self, PyObject * value )
+{
+ int retval;
+
+ if( !self->strip )
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "This strip has been removed!" );
+
+ retval = EXPP_setFloatClamped( value, &self->strip->end,
+ self->strip->start+1, MAXFRAMEF );
+ if( !retval ) {
+ float max = self->strip->end - self->strip->start;
+ if( self->strip->blendin > max )
+ self->strip->blendin = max;
+ if( self->strip->blendout > max )
+ self->strip->blendout = max;
+ }
+ return retval;
+}
+
+/*
+ * return the start frame of the action
+ */
+
+static PyObject *ActionStrip_getActionStart( BPy_ActionStrip * self )
+{
+ if( !self->strip )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "This strip has been removed!" );
+
+ return PyFloat_FromDouble( self->strip->actstart );
+}
+
+/*
+ * set the start frame of the action
+ */
+
+static int ActionStrip_setActionStart( BPy_ActionStrip * self, PyObject * value )
+{
+ if( !self->strip )
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "This strip has been removed!" );
+
+ return EXPP_setFloatClamped( value, &self->strip->actstart,
+ -1000.0, self->strip->actend-1 );
+}
+
+/*
+ * return the ending frame of the action
+ */
+
+static PyObject *ActionStrip_getActionEnd( BPy_ActionStrip * self )
+{
+ if( !self->strip )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "This strip has been removed!" );
+
+ return PyFloat_FromDouble( self->strip->actend );
+}
+
+/*
+ * set the ending frame of the action
+ */
+
+static int ActionStrip_setActionEnd( BPy_ActionStrip * self, PyObject * value )
+{
+ if( !self->strip )
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "This strip has been removed!" );
+
+ return EXPP_setFloatClamped( value, &self->strip->actend,
+ self->strip->actstart+1, MAXFRAMEF );
+}
+
+/*
+ * return the repeat value of the action strip
+ */
+
+static PyObject *ActionStrip_getRepeat( BPy_ActionStrip * self )
+{
+ if( !self->strip )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "This strip has been removed!" );
+
+ return PyFloat_FromDouble( self->strip->repeat );
+}
+
+/*
+ * set the repeat value of the action strip
+ */
+
+static int ActionStrip_setRepeat( BPy_ActionStrip * self, PyObject * value )
+{
+ if( !self->strip )
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "This strip has been removed!" );
+
+ return EXPP_setFloatClamped( value, &self->strip->repeat,
+ 0.001f, 1000.0f );
+}
+
+/*
+ * return the blend in of the action strip
+ */
+
+static PyObject *ActionStrip_getBlendIn( BPy_ActionStrip * self )
+{
+ if( !self->strip )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "This strip has been removed!" );
+
+ return PyFloat_FromDouble( self->strip->blendin );
+}
+
+/*
+ * set the blend in value of the action strip
+ */
+
+static int ActionStrip_setBlendIn( BPy_ActionStrip * self, PyObject * value )
+{
+ if( !self->strip )
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "This strip has been removed!" );
+
+ return EXPP_setFloatClamped( value, &self->strip->blendin,
+ 0.0, self->strip->end - self->strip->start );
+}
+
+/*
+ * return the blend out of the action strip
+ */
+
+static PyObject *ActionStrip_getBlendOut( BPy_ActionStrip * self )
+{
+ if( !self->strip )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "This strip has been removed!" );
+
+ return PyFloat_FromDouble( self->strip->blendout );
+}
+
+/*
+ * set the blend out value of the action strip
+ */
+
+static int ActionStrip_setBlendOut( BPy_ActionStrip * self, PyObject * value )
+{
+ if( !self->strip )
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "This strip has been removed!" );
+
+ return EXPP_setFloatClamped( value, &self->strip->blendout,
+ 0.0, self->strip->end - self->strip->start );
+}
+
+/*
+ * return the blend mode of the action strip
+ */
+
+static PyObject *ActionStrip_getBlendMode( BPy_ActionStrip * self )
+{
+ if( !self->strip )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "This strip has been removed!" );
+
+ return PyInt_FromLong( (long)self->strip->mode ) ;
+}
+
+/*
+ * set the blend mode value of the action strip
+ */
+
+static int ActionStrip_setBlendMode( BPy_ActionStrip * self, PyObject * value )
+{
+ if( !self->strip )
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "This strip has been removed!" );
+
+ return EXPP_setIValueRange( value, &self->strip->mode,
+ 0, ACTSTRIPMODE_ADD, 'h' );
+}
+
+/*
+ * return the flag settings of the action strip
+ */
+
+#define ACTIONSTRIP_MASK (ACTSTRIP_SELECT | ACTSTRIP_USESTRIDE \
+ | ACTSTRIP_HOLDLASTFRAME | ACTSTRIP_ACTIVE | ACTSTRIP_LOCK_ACTION)
+
+static PyObject *ActionStrip_getFlag( BPy_ActionStrip * self )
+{
+ if( !self->strip )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "This strip has been removed!" );
+
+ return PyInt_FromLong( (long)( self->strip->flag & ACTIONSTRIP_MASK ) ) ;
+}
+
+/*
+ * set the flag settings out value of the action strip
+ */
+
+static int ActionStrip_setFlag( BPy_ActionStrip * self, PyObject * arg )
+{
+ PyObject *num = PyNumber_Int( arg );
+ int value;
+
+ if( !self->strip )
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "This strip has been removed!" );
+ if( !num )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected int argument" );
+ value = PyInt_AS_LONG( num );
+ Py_DECREF( num );
+
+ if( ( value & ACTIONSTRIP_MASK ) != value ) {
+ char errstr[128];
+ sprintf ( errstr , "expected int bitmask of 0x%04x", ACTIONSTRIP_MASK );
+ return EXPP_ReturnIntError( PyExc_TypeError, errstr );
+ }
+
+ self->strip->flag = (short)value;
+ return 0;
+}
+
+/*
+ * return the stride axis of the action strip
+ */
+
+static PyObject *ActionStrip_getStrideAxis( BPy_ActionStrip * self )
+{
+ if( !self->strip )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "This strip has been removed!" );
+
+ return PyInt_FromLong( (long)self->strip->stride_axis ) ;
+}
+
+/*
+ * set the stride axis of the action strip
+ */
+
+static int ActionStrip_setStrideAxis( BPy_ActionStrip * self, PyObject * value )
+{
+ if( !self->strip )
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "This strip has been removed!" );
+
+ return EXPP_setIValueRange( value, &self->strip->stride_axis,
+ ACTSTRIP_STRIDEAXIS_X, ACTSTRIP_STRIDEAXIS_Z, 'h' );
+}
+
+/*
+ * return the stride length of the action strip
+ */
+
+static PyObject *ActionStrip_getStrideLength( BPy_ActionStrip * self )
+{
+ if( !self->strip )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "This strip has been removed!" );
+
+ return PyFloat_FromDouble( (double)self->strip->stridelen ) ;
+}
+
+/*
+ * set the stride length of the action strip
+ */
+
+static int ActionStrip_setStrideLength( BPy_ActionStrip * self, PyObject * value )
+{
+ if( !self->strip )
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "This strip has been removed!" );
+
+ return EXPP_setFloatClamped( value, &self->strip->stridelen,
+ 0.0001f, 1000.0 );
+}
+
+/*
+ * return the stride bone name
+ */
+
+static PyObject *ActionStrip_getStrideBone( BPy_ActionStrip * self )
+{
+ if( !self->strip )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "This strip has been removed!" );
+
+ return PyString_FromString( self->strip->stridechannel );
+}
+
+static PyObject *ActionStrip_getGroupTarget( BPy_ActionStrip * self )
+{
+ if( !self->strip )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "This strip has been removed!" );
+
+ if (self->strip->object) {
+ return Object_CreatePyObject( self->strip->object );
+ } else {
+ Py_RETURN_NONE;
+ }
+}
+
+/*
+ * set the stride bone name
+ */
+
+static int ActionStrip_setStrideBone( BPy_ActionStrip * self, PyObject * attr )
+{
+ char *name = PyString_AsString( attr );
+ if( !name )
+ return EXPP_ReturnIntError( PyExc_TypeError, "expected string arg" );
+
+ if( !self->strip )
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "This strip has been removed!" );
+
+ BLI_strncpy( self->strip->stridechannel, name, 32 );
+
+ return 0;
+}
+
+static int ActionStrip_setGroupTarget( BPy_ActionStrip * self, PyObject * args )
+{
+ if( !self->strip )
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "This strip has been removed!" );
+
+ if( (PyObject *)args == Py_None )
+ self->strip->object = NULL;
+ else if( BPy_Object_Check( args ) )
+ self->strip->object = ((BPy_Object *)args)->object;
+ else
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected an object or None" );
+ return 0;
+}
+
+/*****************************************************************************/
+/* Python BPy_Constraint attributes get/set structure: */
+/*****************************************************************************/
+static PyGetSetDef BPy_ActionStrip_getseters[] = {
+ {"action",
+ (getter)ActionStrip_getAction, (setter)NULL,
+ "Action associated with the strip", NULL},
+ {"stripStart",
+ (getter)ActionStrip_getStripStart, (setter)ActionStrip_setStripStart,
+ "Starting frame of the strip", NULL},
+ {"stripEnd",
+ (getter)ActionStrip_getStripEnd, (setter)ActionStrip_setStripEnd,
+ "Ending frame of the strip", NULL},
+ {"actionStart",
+ (getter)ActionStrip_getActionStart, (setter)ActionStrip_setActionStart,
+ "Starting frame of the action", NULL},
+ {"actionEnd",
+ (getter)ActionStrip_getActionEnd, (setter)ActionStrip_setActionEnd,
+ "Ending frame of the action", NULL},
+ {"repeat",
+ (getter)ActionStrip_getRepeat, (setter)ActionStrip_setRepeat,
+ "The number of times to repeat the action range", NULL},
+ {"blendIn",
+ (getter)ActionStrip_getBlendIn, (setter)ActionStrip_setBlendIn,
+ "Number of frames of motion blending", NULL},
+ {"blendOut",
+ (getter)ActionStrip_getBlendOut, (setter)ActionStrip_setBlendOut,
+ "Number of frames of ease-out", NULL},
+ {"mode",
+ (getter)ActionStrip_getBlendMode, (setter)ActionStrip_setBlendMode,
+ "Setting of blending mode", NULL},
+ {"flag",
+ (getter)ActionStrip_getFlag, (setter)ActionStrip_setFlag,
+ "Setting of blending flags", NULL},
+ {"strideAxis",
+ (getter)ActionStrip_getStrideAxis, (setter)ActionStrip_setStrideAxis,
+ "Dominant axis for stride bone", NULL},
+ {"strideLength",
+ (getter)ActionStrip_getStrideLength, (setter)ActionStrip_setStrideLength,
+ "Distance covered by one complete cycle of the action", NULL},
+ {"strideBone",
+ (getter)ActionStrip_getStrideBone, (setter)ActionStrip_setStrideBone,
+ "Name of Bone used for stride", NULL},
+ {"groupTarget",
+ (getter)ActionStrip_getGroupTarget, (setter)ActionStrip_setGroupTarget,
+ "Name of target armature within group", NULL},
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+/*****************************************************************************/
+/* Python BPy_ActionStrip methods: */
+/*****************************************************************************/
+
+/*
+ * restore the values of ActionStart and ActionEnd to their defaults
+ */
+
+static PyObject *ActionStrip_resetLimits( BPy_ActionStrip *self )
+{
+ bActionStrip *strip = self->strip;
+
+ if( !strip )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "This strip has been removed!" );
+
+ calc_action_range( strip->act, &strip->actstart, &strip->actend, 1 );
+
+ Py_RETURN_NONE;
+}
+
+/*
+ * reset the strip size
+ */
+
+static PyObject *ActionStrip_resetStripSize( BPy_ActionStrip *self )
+{
+ float mapping;
+ bActionStrip *strip = self->strip;
+
+ if( !strip )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "This strip has been removed!" );
+
+ mapping = (strip->actend - strip->actstart) / (strip->end - strip->start);
+ strip->end = strip->start + mapping*(strip->end - strip->start);
+
+ Py_RETURN_NONE;
+}
+
+/*
+ * snap to start and end to nearest frames
+ */
+
+static PyObject *ActionStrip_snapToFrame( BPy_ActionStrip *self )
+{
+ bActionStrip *strip = self->strip;
+
+ if( !strip )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "This strip has been removed!" );
+
+ strip->start= (float)floor(strip->start+0.5);
+ strip->end= (float)floor(strip->end+0.5);
+
+ Py_RETURN_NONE;
+}
+
+/*****************************************************************************/
+/* Python BPy_ActionStrip methods table: */
+/*****************************************************************************/
+static PyMethodDef BPy_ActionStrip_methods[] = {
+ /* name, method, flags, doc */
+ {"resetActionLimits", ( PyCFunction ) ActionStrip_resetLimits, METH_NOARGS,
+ "Restores the values of ActionStart and ActionEnd to their defaults"},
+ {"resetStripSize", ( PyCFunction ) ActionStrip_resetStripSize, METH_NOARGS,
+ "Resets the Action Strip size to its creation values"},
+ {"snapToFrame", ( PyCFunction ) ActionStrip_snapToFrame, METH_NOARGS,
+ "Snaps the ends of the action strip to the nearest whole numbered frame"},
+ {NULL, NULL, 0, NULL}
+};
+
+/*****************************************************************************/
+/* Python ActionStrip_Type structure definition: */
+/*****************************************************************************/
+PyTypeObject ActionStrip_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender.ActionStrip", /* char *tp_name; */
+ sizeof( BPy_ActionStrip ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ NULL, /* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* cmpfunc tp_compare; */
+ ( reprfunc ) NULL, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_ActionStrip_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ BPy_ActionStrip_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+static PyObject *M_ActionStrip_FlagsDict( void )
+{
+ PyObject *S = PyConstant_New( );
+
+ if( S ) {
+ BPy_constant *d = ( BPy_constant * ) S;
+ PyConstant_Insert( d, "SELECT",
+ PyInt_FromLong( ACTSTRIP_SELECT ) );
+ PyConstant_Insert( d, "STRIDE_PATH",
+ PyInt_FromLong( ACTSTRIP_USESTRIDE ) );
+ PyConstant_Insert( d, "HOLD",
+ PyInt_FromLong( ACTSTRIP_HOLDLASTFRAME ) );
+ PyConstant_Insert( d, "ACTIVE",
+ PyInt_FromLong( ACTSTRIP_ACTIVE ) );
+ PyConstant_Insert( d, "LOCK_ACTION",
+ PyInt_FromLong( ACTSTRIP_LOCK_ACTION ) );
+ }
+ return S;
+}
+
+static PyObject *M_ActionStrip_AxisDict( void )
+{
+ PyObject *S = PyConstant_New( );
+
+ if( S ) {
+ BPy_constant *d = ( BPy_constant * ) S;
+ PyConstant_Insert( d, "STRIDEAXIS_X",
+ PyInt_FromLong( ACTSTRIP_STRIDEAXIS_X ) );
+ PyConstant_Insert( d, "STRIDEAXIS_Y",
+ PyInt_FromLong( ACTSTRIP_STRIDEAXIS_Y ) );
+ PyConstant_Insert( d, "STRIDEAXIS_Z",
+ PyInt_FromLong( ACTSTRIP_STRIDEAXIS_Z ) );
+ }
+ return S;
+}
+
+static PyObject *M_ActionStrip_ModeDict( void )
+{
+ PyObject *S = PyConstant_New( );
+
+ if( S ) {
+ BPy_constant *d = ( BPy_constant * ) S;
+ PyConstant_Insert( d, "MODE_ADD",
+ PyInt_FromLong( ACTSTRIPMODE_ADD ) );
+ }
+ return S;
+}
+
+PyObject *ActionStrip_CreatePyObject( struct bActionStrip *strip )
+{
+ BPy_ActionStrip *pyobj;
+ pyobj = ( BPy_ActionStrip * ) PyObject_NEW( BPy_ActionStrip,
+ &ActionStrip_Type );
+ if( !pyobj )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create BPy_ActionStrip object" );
+ pyobj->strip = strip;
+ return ( PyObject * ) pyobj;
+}
+
+/*****************************************************************************/
+/* ActionStrip Sequence wrapper */
+/*****************************************************************************/
+
+/*
+ * Initialize the iterator
+ */
+
+static PyObject *ActionStrips_getIter( BPy_ActionStrips * self )
+{
+ self->iter = (bActionStrip *)self->ob->nlastrips.first;
+ return EXPP_incr_ret ( (PyObject *) self );
+}
+
+/*
+ * Get the next action strip
+ */
+
+static PyObject *ActionStrips_nextIter( BPy_ActionStrips * self )
+{
+ bActionStrip *strip = self->iter;
+ if( strip ) {
+ self->iter = strip->next;
+ return ActionStrip_CreatePyObject( strip );
+ }
+
+ return EXPP_ReturnPyObjError( PyExc_StopIteration,
+ "iterator at end" );
+}
+
+/* return the number of action strips */
+
+static int ActionStrips_length( BPy_ActionStrips * self )
+{
+ return BLI_countlist( &self->ob->nlastrips );
+}
+
+/* return an action strip */
+
+static PyObject *ActionStrips_item( BPy_ActionStrips * self, int i )
+{
+ bActionStrip *strip = NULL;
+
+ /* if index is negative, start counting from the end of the list */
+ if( i < 0 )
+ i += ActionStrips_length( self );
+
+ /* skip through the list until we get the strip or end of list */
+
+ strip = self->ob->nlastrips.first;
+
+ while( i && strip ) {
+ --i;
+ strip = strip->next;
+ }
+
+ if( strip )
+ return ActionStrip_CreatePyObject( strip );
+ else
+ return EXPP_ReturnPyObjError( PyExc_IndexError,
+ "array index out of range" );
+}
+
+/*****************************************************************************/
+/* Python BPy_ActionStrips sequence table: */
+/*****************************************************************************/
+static PySequenceMethods ActionStrips_as_sequence = {
+ ( inquiry ) ActionStrips_length, /* sq_length */
+ ( binaryfunc ) 0, /* sq_concat */
+ ( intargfunc ) 0, /* sq_repeat */
+ ( intargfunc ) ActionStrips_item, /* sq_item */
+ ( intintargfunc ) 0, /* sq_slice */
+ ( intobjargproc ) 0, /* sq_ass_item */
+ ( intintobjargproc ) 0, /* sq_ass_slice */
+ ( objobjproc ) 0, /* sq_contains */
+ ( binaryfunc ) 0, /* sq_inplace_concat */
+ ( intargfunc ) 0, /* sq_inplace_repeat */
+};
+
+
+/*****************************************************************************/
+/* Python BPy_ActionStrip methods: */
+/*****************************************************************************/
+
+/*
+ * helper function to check for a valid action strip argument
+ */
+
+static bActionStrip *locate_strip( BPy_ActionStrips *self,
+ PyObject *args, BPy_ActionStrip **stripobj )
+{
+ bActionStrip *strip = NULL;
+ BPy_ActionStrip *pyobj;
+
+ /* check that argument is a constraint */
+ if( !PyArg_ParseTuple( args, "O!", &ActionStrip_Type, &pyobj ) ) {
+ EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected an action strip as an argument" );
+ return NULL;
+ }
+
+ if( !pyobj->strip ) {
+ EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "This strip has been removed!" );
+ return NULL;
+ }
+
+ /* if caller needs the object, return it */
+ if( stripobj )
+ *stripobj = pyobj;
+
+ /* find the action strip in the NLA */
+ for( strip = self->ob->nlastrips.first; strip; strip = strip->next )
+ if( strip == pyobj->strip )
+ return strip;
+
+ /* return exception if we can't find the strip */
+ EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "action strip does not belong to this object" );
+ return NULL;
+}
+
+/*
+ * remove an action strip from the NLA
+ */
+
+static PyObject *ActionStrips_remove( BPy_ActionStrips *self, PyObject * args )
+{
+ BPy_ActionStrip *pyobj;
+ bActionStrip *strip = locate_strip( self, args, &pyobj );
+
+ /* return exception if we can't find the strip */
+ if( !strip )
+ return (PyObject *)NULL;
+
+ /* do the actual removal */
+ free_actionstrip(strip);
+ BLI_remlink(&self->ob->nlastrips, strip);
+ MEM_freeN(strip);
+
+ pyobj->strip = NULL;
+ Py_RETURN_NONE;
+}
+
+/*
+ * move an action strip up in the strip list
+ */
+
+static PyObject *ActionStrips_moveUp( BPy_ActionStrips *self, PyObject * args )
+{
+ bActionStrip *strip = locate_strip( self, args, NULL );
+
+ /* return exception if we can't find the strip */
+ if( !strip )
+ return (PyObject *)NULL;
+
+ /* if strip is not already the first, move it up */
+ if( strip != self->ob->nlastrips.first ) {
+ BLI_remlink(&self->ob->nlastrips, strip);
+ BLI_insertlink(&self->ob->nlastrips, strip->prev->prev, strip);
+ }
+
+ Py_RETURN_NONE;
+}
+
+/*
+ * move an action strip down in the strip list
+ */
+
+static PyObject *ActionStrips_moveDown( BPy_ActionStrips *self, PyObject * args )
+{
+ bActionStrip *strip = locate_strip( self, args, NULL );
+
+ /* return exception if we can't find the strip */
+ if( !strip )
+ return (PyObject *)NULL;
+
+ /* if strip is not already the last, move it down */
+ if( strip != self->ob->nlastrips.last ) {
+ BLI_remlink(&self->ob->nlastrips, strip);
+ BLI_insertlink(&self->ob->nlastrips, strip->next, strip);
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *ActionStrips_append( BPy_ActionStrips *self, PyObject * args )
+{
+ BPy_Action *pyobj;
+ Object *ob;
+ bActionStrip *strip;
+ bAction *act;
+
+ /* check that argument is an action */
+ if( !PyArg_ParseTuple( args, "O!", &Action_Type, &pyobj ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected an action as an argument" );
+
+ ob = self->ob;
+ act = pyobj->action;
+
+ /* Initialize the new action block */
+ strip = MEM_callocN( sizeof(bActionStrip), "bActionStrip" );
+
+ strip->act = act;
+ calc_action_range( strip->act, &strip->actstart, &strip->actend, 1 );
+ strip->start = (float)G.scene->r.cfra;
+ strip->end = strip->start + ( strip->actend - strip->actstart );
+ /* simple prevention of zero strips */
+ if( strip->start > strip->end-2 )
+ strip->end = strip->start+100;
+
+ strip->flag = ACTSTRIP_LOCK_ACTION;
+ find_stridechannel(ob, strip);
+
+ strip->repeat = 1.0;
+ act->id.us++;
+
+ BLI_addtail(&ob->nlastrips, strip);
+
+ Py_RETURN_NONE;
+}
+
+/*****************************************************************************/
+/* Python BPy_ActionStrips methods table: */
+/*****************************************************************************/
+static PyMethodDef BPy_ActionStrips_methods[] = {
+ /* name, method, flags, doc */
+ {"append", ( PyCFunction ) ActionStrips_append, METH_VARARGS,
+ "(action) - append a new actionstrip using existing action"},
+ {"remove", ( PyCFunction ) ActionStrips_remove, METH_VARARGS,
+ "(strip) - remove an existing strip from this actionstrips"},
+ {"moveUp", ( PyCFunction ) ActionStrips_moveUp, METH_VARARGS,
+ "(strip) - move an existing strip up in the actionstrips"},
+ {"moveDown", ( PyCFunction ) ActionStrips_moveDown, METH_VARARGS,
+ "(strip) - move an existing strip down in the actionstrips"},
+ {NULL, NULL, 0, NULL}
+};
+
+/*****************************************************************************/
+/* Python ActionStrips_Type structure definition: */
+/*****************************************************************************/
+PyTypeObject ActionStrips_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender.ActionStrips", /* char *tp_name; */
+ sizeof( BPy_ActionStrips ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ NULL, /* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* cmpfunc tp_compare; */
+ ( reprfunc ) NULL, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ &ActionStrips_as_sequence, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ ( getiterfunc )ActionStrips_getIter, /* getiterfunc tp_iter; */
+ ( iternextfunc )ActionStrips_nextIter, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_ActionStrips_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ NULL, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+PyObject *ActionStrips_CreatePyObject( Object *ob )
+{
+ BPy_ActionStrips *pyseq;
+ pyseq = ( BPy_ActionStrips * ) PyObject_NEW( BPy_ActionStrips,
+ &ActionStrips_Type );
+ if( !pyseq )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create BPy_ActionStrips object" );
+ pyseq->ob = ob;
+ return ( PyObject * ) pyseq;
+}
+
+/*****************************************************************************/
+/* Function: NLA_Init */
+/*****************************************************************************/
+PyObject *NLA_Init( void )
+{
+ PyObject *FlagsDict = M_ActionStrip_FlagsDict( );
+ PyObject *AxisDict = M_ActionStrip_AxisDict( );
+ PyObject *ModeDict = M_ActionStrip_ModeDict( );
+ PyObject *submodule;
+
+ if( PyType_Ready( &Action_Type ) < 0
+ || PyType_Ready( &ActionStrip_Type ) < 0
+ || PyType_Ready( &ActionStrips_Type ) < 0 )
+ return NULL;
+
+ submodule = Py_InitModule3( "Blender.Armature.NLA",
+ M_NLA_methods, M_NLA_doc );
+
+ if( FlagsDict )
+ PyModule_AddObject( submodule, "Flags", FlagsDict );
+ if( AxisDict )
+ PyModule_AddObject( submodule, "StrideAxes", AxisDict );
+ if( ModeDict )
+ PyModule_AddObject( submodule, "Modes", ModeDict );
+
+ return submodule;
+}
diff --git a/source/blender/python/api2_2x/NLA.h b/source/blender/python/api2_2x/NLA.h
new file mode 100644
index 00000000000..45873db40a4
--- /dev/null
+++ b/source/blender/python/api2_2x/NLA.h
@@ -0,0 +1,77 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Joseph Gilbert, Ken Hughes
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_NLA_H
+#define EXPP_NLA_H
+
+#include <Python.h>
+#include "DNA_action_types.h"
+#include "DNA_nla_types.h"
+
+struct Object;
+
+/** NLA module initialization function. */
+PyObject *NLA_Init( void );
+
+extern PyTypeObject Action_Type;
+extern PyTypeObject ActionStrip_Type;
+extern PyTypeObject ActionStrips_Type;
+
+/** Python BPy_NLA structure definition. */
+typedef struct {
+ PyObject_HEAD
+ bAction * action; /* libdata must be second */
+} BPy_Action;
+
+typedef struct {
+ PyObject_HEAD
+ bActionStrip * strip;
+} BPy_ActionStrip;
+
+typedef struct {
+ PyObject_HEAD
+ struct Object * ob;
+ struct bActionStrip *iter;
+} BPy_ActionStrips;
+
+/* Type checking for EXPP PyTypes */
+#define BPy_Action_Check(v) ((v)->ob_type == &Action_Type)
+#define BPy_ActionStrip_Check(v) ((v)->ob_type == &ActionStrip_Type)
+#define BPy_ActionStrips_Check(v) ((v)->ob_type == &ActionStrips_Type)
+
+PyObject *Action_CreatePyObject( struct bAction *action );
+bAction *Action_FromPyObject( PyObject * py_obj );
+
+PyObject *ActionStrip_CreatePyObject( struct bActionStrip *strip );
+PyObject *ActionStrips_CreatePyObject( struct Object *ob );
+
+#endif
diff --git a/source/blender/python/api2_2x/NMesh.c b/source/blender/python/api2_2x/NMesh.c
new file mode 100644
index 00000000000..e50c9678606
--- /dev/null
+++ b/source/blender/python/api2_2x/NMesh.c
@@ -0,0 +1,4164 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender, but it borrows all the old NMesh code.
+ *
+ * Contributor(s): Willian P. Germano, Jordi Rovira i Bonet, Joseph Gilbert,
+ * Bala Gi, Alexander Szakaly, Stephane Soppera, Campbell Barton, Ken Hughes,
+ * Daniel Dunbar.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "NMesh.h" /*This must come first*/
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_key_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
+#include "DNA_curve_types.h"
+
+#include "BDR_editface.h" /* make_tfaces */
+#include "BDR_vpaint.h"
+#include "BDR_editobject.h"
+
+#include "BIF_editdeform.h"
+#include "BIF_editkey.h" /* insert_meshkey */
+#include "BIF_editview.h"
+#include "BIF_space.h"
+
+#include "BKE_customdata.h"
+#include "BKE_deform.h"
+#include "BKE_mesh.h"
+#include "BKE_material.h"
+#include "BKE_main.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_displist.h"
+#include "BKE_object.h"
+#include "BKE_mball.h"
+#include "BKE_utildefines.h"
+#include "BKE_depsgraph.h"
+#include "BKE_idprop.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+
+#include "blendef.h"
+#include "mydevice.h"
+#include "Object.h"
+#include "Key.h"
+#include "Mathutils.h"
+#include "IDProp.h"
+#include "constant.h"
+#include "gen_utils.h"
+#include "gen_library.h"
+
+extern void countall(void);
+
+/* EXPP Mesh defines */
+
+#define NMESH_FRAME_MAX 30000
+#define NMESH_SMOOTHRESH 30
+#define NMESH_SMOOTHRESH_MIN 1
+#define NMESH_SMOOTHRESH_MAX 80
+#define NMESH_SUBDIV 1
+#define NMESH_SUBDIV_MIN 0
+#define NMESH_SUBDIV_MAX 6
+
+/* Globals */
+static PyObject *g_nmeshmodule = NULL;
+
+static int unlink_existingMeshData( Mesh * mesh );
+static int convert_NMeshToMesh( Mesh *mesh, BPy_NMesh *nmesh );
+static void check_dverts(Mesh *me, int old_totverts);
+static PyObject *NMesh_printDebug( PyObject * self );
+static PyObject *NMesh_addEdge( PyObject * self, PyObject * args );
+static PyObject *NMesh_findEdge( PyObject * self, PyObject * args );
+static PyObject *NMesh_removeEdge( PyObject * self, PyObject * args );
+static PyObject *NMesh_addFace( PyObject * self, PyObject * args );
+static PyObject *NMesh_removeFace( PyObject * self, PyObject * args );
+static PyObject *NMesh_addVertGroup( PyObject * self, PyObject * args );
+static PyObject *NMesh_removeVertGroup( PyObject * self, PyObject * args );
+static PyObject *NMesh_assignVertsToGroup( PyObject * self, PyObject * args );
+static PyObject *NMesh_removeVertsFromGroup( PyObject * self,PyObject * args );
+static PyObject *NMesh_getVertsFromGroup( PyObject * self, PyObject * args );
+static PyObject *NMesh_renameVertGroup( PyObject * self, PyObject * args );
+static PyObject *NMesh_getVertGroupNames( PyObject * self );
+static PyObject *NMesh_transform (PyObject *self, PyObject *args);
+
+static char NMesh_printDebug_doc[] =
+ "print debug info about the mesh.";
+
+static char NMesh_getKey_doc[] =
+ "get the Key object linked to this mesh";
+
+static char NMesh_addEdge_doc[] =
+ "create an edge between two vertices.\n\
+If an edge already exists between those vertices, it is returned.\n\
+(In Blender, only zero or one edge can link two vertices.)\n\
+Created edge is automatically added to edges list.";
+
+static char NMesh_findEdge_doc[] =
+ "find an edge between two vertices.";
+
+static char NMesh_removeEdge_doc[] =
+ "remove an edge between two vertices.\n\
+All faces using this edge are removed from faces list.";
+
+static char NMesh_addFace_doc[] =
+ "add a face to face list and add to edge list (if edge data exists) necessary edges.";
+
+static char NMesh_removeFace_doc[] =
+ "remove a face for face list and remove edges no more used by any other face (if \
+edge data exists).";
+
+static char NMesh_addVertGroup_doc[] =
+ "add a named and empty vertex(deform) Group to a mesh that has been linked\n\
+to an object. ";
+
+static char NMesh_removeVertGroup_doc[] =
+ "remove a named vertex(deform) Group from a mesh that has been linked\n\
+to an object. Will remove all verts assigned to group.";
+
+static char NMesh_assignVertsToGroup_doc[] =
+ "Adds an array (a python list) of vertex points (by index) to a named\n\
+vertex group. The list will have an associated wieght assigned to them.\n\
+The weight represents the amount of influence this group has over these\n\
+vertex points. Weights should be in the range of 0.0 - 1.0.\n\
+The assignmode can be either 'add', 'subtract', or 'replace'. If this vertex\n\
+is not assigned to the group 'add' creates a new association with the weight\n\
+specified, otherwise the weight given is added to the current weight of the\n\
+vertex.\n\
+'subtract' will attempt to subtract the weight passed from a vertex already\n\
+associated with a group, else it does nothing. 'replace' attempts to replace\n\
+the weight with the new weight value for an already associated vertex/group,\n\
+else it does nothing. The mesh must have all it's vertex points set before\n\
+attempting to assign any vertex points to a vertex group.";
+
+static char NMesh_removeVertsFromGroup_doc[] =
+ "Remove an array (a python list) of vertex points from a named group in a\n\
+mesh that has been linked to an object. If no list is given this will remove\n\
+all vertex point associations with the group passed";
+
+static char NMesh_getVertsFromGroup_doc[] =
+ "By passing a python list of vertex indices and a named group, this will\n\
+return a python list representing the indeces that are a part of this vertex.\n\
+group. If no association was found for the index passed nothing will be\n\
+return for the index. An optional flag will also return the weights as well";
+
+static char NMesh_renameVertGroup_doc[] = "Renames a vertex group";
+
+static char NMesh_getVertGroupNames_doc[] =
+ "Returns a list of all the vertex group names";
+
+static char M_NMesh_doc[] = "The Blender.NMesh submodule";
+
+static char M_NMesh_Col_doc[] = "([r, g, b, a]) - Get a new mesh color\n\n\
+[r=255, g=255, b=255, a=255] Specify the color components";
+
+static char M_NMesh_Face_doc[] =
+ "(vertexlist = None) - Get a new face, and pass optional vertex list";
+
+static char NMFace_append_doc[] =
+ "(vert) - appends Vertex 'vert' to face vertex list";
+
+static char M_NMesh_Vert_doc[] = "([x, y, z]) - Get a new vertex\n\n\
+[x, y, z] Specify new coordinates";
+
+static char NMesh_getMaterials_doc[] =
+ "(i = -1) - Get this mesh's list of materials.\n\
+(i = -1) - int: determines the list's contents:\n\
+-1: return the current list, possibly modified by the script (default);\n\
+ 0: get a fresh list from the Blender mesh -- modifications not included,\n\
+ unless the script called mesh.update() first;\n\
+ 1: like 0, but does not ignore empty slots, returns them as 'None'.";
+
+static char NMesh_setMaterials_doc[] =
+ "(matlist) - Set this mesh's list of materials. This method makes sure\n\
+the passed matlist is valid (can only include up to 16 materials and None's).";
+
+static char NMesh_addMaterial_doc[] =
+ "(material) - add a new Blender Material 'material' to this Mesh's materials\n\
+list.";
+
+static char NMesh_insertKey_doc[] =
+ "(frame = None, type = 'relative') - inserts a Mesh key at the given frame\n\
+if called without arguments, it inserts the key at the current Scene frame.\n\
+(type) - 'relative' or 'absolute'. Only relevant on the first call to this\n\
+function for each nmesh.";
+
+static char NMesh_removeAllKeys_doc[] =
+ "() - removes all keys from this mesh\n\
+returns True if successful or False if this NMesh wasn't linked to a real\n\
+Blender Mesh yet or the Mesh had no keys";
+
+static char NMesh_getSelectedFaces_doc[] =
+ "(flag = None) - returns list of selected Faces\n\
+If flag = 1, return indices instead";
+
+static char NMesh_getActiveFace_doc[] =
+ "returns the index of the active face ";
+
+static char NMesh_hasVertexUV_doc[] =
+ "(flag = None) - returns 1 if Mesh has per vertex UVs ('Sticky')\n\
+The optional argument sets the Sticky flag";
+
+static char NMesh_hasFaceUV_doc[] =
+ "(flag = None) - returns 1 if Mesh has textured faces\n\
+The optional argument sets the textured faces flag";
+
+static char NMesh_hasVertexColours_doc[] =
+ "(flag = None) - returns 1 if Mesh has vertex colors.\n\
+The optional argument sets the vertex color flag";
+
+static char NMesh_getVertexInfluences_doc[] =
+ "Return a list of the influences of bones in the vertex \n\
+specified by index. The list contains pairs with the \n\
+bone name and the weight.";
+
+static char NMesh_update_doc[] =
+"(recalc_normals = 0, store_edges = 0, vertex_shade = 0) - Updates the Mesh.\n\
+Optional arguments: if given and nonzero:\n\
+'recalc_normals': normal vectors are recalculated;\n\
+'store_edges': edges data is stored.\n\
+'vertex_shade': vertex colors are added based on the current lamp setup.";
+
+static char NMesh_getMode_doc[] =
+ "() - get the mode flags of this nmesh as an or'ed int value.";
+
+static char NMesh_setMode_doc[] =
+ "(int or none to 5 strings) - set the mode flags of this nmesh.\n\
+() - unset all flags.";
+
+static char NMesh_getMaxSmoothAngle_doc[] =
+ "() - get the max smooth angle for mesh auto smoothing.";
+
+static char NMesh_setMaxSmoothAngle_doc[] =
+ "(int) - set the max smooth angle for mesh auto smoothing in the range\n\
+[1,80] in degrees.";
+
+static char NMesh_getSubDivLevels_doc[] =
+ "() - get the subdivision levels for display and rendering: [display, render]";
+
+static char NMesh_setSubDivLevels_doc[] =
+ "([int, int]) - set the subdivision levels for [display, render] -- they are\n\
+clamped to the range [0,6].";
+
+static char M_NMesh_New_doc[] =
+ "() - returns a new, empty NMesh mesh object\n";
+
+static char M_NMesh_GetRaw_doc[] = "([name]) - Get a raw mesh from Blender\n\n\
+[name] Name of the mesh to be returned\n\n\
+If name is not specified a new empty mesh is\n\
+returned, otherwise Blender returns an existing\n\
+mesh.";
+
+static char M_NMesh_GetNames_doc[] = "\
+() - Get a list with the names of all available meshes in Blender\n\n\
+Any of these names can be passed to NMesh.GetRaw() for the actual mesh data.";
+
+static char M_NMesh_GetRawFromObject_doc[] =
+ "(name) - Get the raw mesh used by a Blender object\n\n\
+(name) Name of the object to get the mesh from\n\n\
+This returns the mesh as used by the object, which\n\
+means it contains all deformations and modifications.";
+
+static char M_NMesh_PutRaw_doc[] =
+ "(mesh, name = None, recalc_normals = 1, store_edges = 0]) -\n\
+Return a raw mesh to Blender\n\n\
+(mesh) The NMesh object to store\n\
+[name] The mesh to replace\n\
+[recalc_normals = 1] Flag to control vertex normal recalculation\n\
+[store_edges=0] Store edges data in the blender mesh\n\
+If the name of a mesh to replace is not given a new\n\
+object is created and returned.";
+
+static char NMesh_transform_doc[] =
+"(matrix, recalc_normals = 0) - Transform the mesh by the supplied 4x4 matrix\n\
+if recalc_normals is True, vertex normals are transformed along with \n\
+vertex coordinatess.\n";
+
+
+void mesh_update( Mesh * mesh, Object * ob )
+{
+ if (ob) {
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ }
+ else {
+ ob = G.main->object.first;
+ while (ob) {
+ if (ob->data == mesh) {
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ break;
+ }
+ ob = ob->id.next;
+ }
+ }
+}
+
+/*
+ * before trying to convert NMesh data back to mesh, verify that the
+ * lists contain the right type of data
+ */
+
+static int check_NMeshLists( BPy_NMesh *nmesh )
+{
+ int i;
+
+ if( !PySequence_Check( nmesh->verts ) )
+ return EXPP_ReturnIntError( PyExc_AttributeError,
+ "nmesh verts are not a sequence" );
+ if( !PySequence_Check( nmesh->edges ) )
+ return EXPP_ReturnIntError( PyExc_AttributeError,
+ "nmesh edges are not a sequence" );
+ if( !PySequence_Check( nmesh->faces ) )
+ return EXPP_ReturnIntError( PyExc_AttributeError,
+ "nmesh faces are not a sequence" );
+ if( !PySequence_Check( nmesh->materials ) )
+ return EXPP_ReturnIntError( PyExc_AttributeError,
+ "nmesh materials are not a sequence" );
+
+ if( EXPP_check_sequence_consistency( nmesh->verts, &NMVert_Type ) != 1 )
+ return EXPP_ReturnIntError( PyExc_AttributeError,
+ "nmesh vertices must be NMVerts" );
+ if( EXPP_check_sequence_consistency( nmesh->edges, &NMEdge_Type ) != 1 )
+ return EXPP_ReturnIntError( PyExc_AttributeError,
+ "nmesh edges must be NMEdges" );
+ if( EXPP_check_sequence_consistency( nmesh->faces, &NMFace_Type ) != 1 )
+ return EXPP_ReturnIntError( PyExc_AttributeError,
+ "nmesh faces must be NMFaces" );
+ for( i = 0 ; i < PySequence_Length(nmesh->faces); ++i ) {
+ int j, err=0;
+ PyObject *col, *v, *uv;
+ BPy_NMFace *face=(BPy_NMFace *)PySequence_GetItem(nmesh->faces, i);
+
+ col = face->col;
+ uv = face->uv;
+ v = face->v;
+ Py_DECREF( face );
+ if( EXPP_check_sequence_consistency( face->col, &NMCol_Type ) != 1 ) {
+ return EXPP_ReturnIntError( PyExc_AttributeError,
+ "nmesh face col must be NMCols" );
+ }
+ if( EXPP_check_sequence_consistency( face->v, &NMVert_Type ) != 1 )
+ return EXPP_ReturnIntError( PyExc_AttributeError,
+ "nmesh face v must be NMVerts" );
+
+ for( j = 0 ; !err && j < PySequence_Length( face->uv ); ++j ) {
+ PyObject *uv = PySequence_GetItem( face->uv, j);
+ if( PySequence_Check(uv) && PySequence_Length(uv) == 2 ) {
+ PyObject *p1 = PySequence_GetItem(uv, 0);
+ PyObject *p2 = PySequence_GetItem(uv, 1);
+ if( !PyNumber_Check(p1) || !PyNumber_Check(p2) )
+ err = 1;
+ Py_DECREF( p1 );
+ Py_DECREF( p2 );
+ }
+ else {
+ err = 1;
+ }
+
+ Py_DECREF( uv );
+ }
+ if( err )
+ return EXPP_ReturnIntError( PyExc_AttributeError,
+ "nmesh face uv must contain sequence of 2 floats" );
+ }
+ return 0;
+}
+
+
+/*****************************/
+/* Mesh Color Object */
+/*****************************/
+
+static void NMCol_dealloc( PyObject * self )
+{
+ PyObject_DEL( self );
+}
+
+static BPy_NMCol *newcol( char r, char g, char b, char a )
+{
+ BPy_NMCol *mc = ( BPy_NMCol * ) PyObject_NEW( BPy_NMCol, &NMCol_Type );
+
+ mc->r = r;
+ mc->g = g;
+ mc->b = b;
+ mc->a = a;
+
+ return mc;
+}
+
+static PyObject *M_NMesh_Col( PyObject * self, PyObject * args )
+{
+ char r = 255, g = 255, b = 255, a = 255;
+
+ if( PyArg_ParseTuple( args, "|bbbb", &r, &g, &b, &a ) )
+ return ( PyObject * ) newcol( r, g, b, a );
+
+ return NULL;
+}
+
+static PyObject *NMCol_getattr( PyObject * self, char *name )
+{
+ BPy_NMCol *mc = ( BPy_NMCol * ) self;
+
+ if( strcmp( name, "r" ) == 0 )
+ return Py_BuildValue( "i", mc->r );
+ else if( strcmp( name, "g" ) == 0 )
+ return Py_BuildValue( "i", mc->g );
+ else if( strcmp( name, "b" ) == 0 )
+ return Py_BuildValue( "i", mc->b );
+ else if( strcmp( name, "a" ) == 0 )
+ return Py_BuildValue( "i", mc->a );
+ else if( strcmp( name, "__members__" ) == 0 )
+ return Py_BuildValue( "[s,s,s,s]", "r", "g", "b", "a" );
+
+ return EXPP_ReturnPyObjError( PyExc_AttributeError, name );
+}
+
+static int NMCol_setattr( PyObject * self, char *name, PyObject * v )
+{
+ BPy_NMCol *mc = ( BPy_NMCol * ) self;
+ char ival;
+
+ if( !PyArg_Parse( v, "b", &ival ) )
+ return -1;
+
+ ival = ( char ) EXPP_ClampInt( ival, 0, 255 );
+
+ if( strcmp( name, "r" ) == 0 )
+ mc->r = (unsigned char)ival;
+ else if( strcmp( name, "g" ) == 0 )
+ mc->g = (unsigned char)ival;
+ else if( strcmp( name, "b" ) == 0 )
+ mc->b = (unsigned char)ival;
+ else if( strcmp( name, "a" ) == 0 )
+ mc->a = (unsigned char)ival;
+ else
+ return -1;
+
+ return 0;
+}
+
+static PyObject *NMCol_repr( BPy_NMCol * self )
+{
+ static char s[256];
+ sprintf( s, "[NMCol - <%d, %d, %d, %d>]", self->r, self->g, self->b,
+ self->a );
+ return Py_BuildValue( "s", s );
+}
+
+PyTypeObject NMCol_Type = {
+ PyObject_HEAD_INIT( NULL ) 0, /* ob_size */
+ "Blender NMCol", /* tp_name */
+ sizeof( BPy_NMCol ), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ /* methods */
+ ( destructor ) NMCol_dealloc, /* tp_dealloc */
+ ( printfunc ) 0, /* tp_print */
+ ( getattrfunc ) NMCol_getattr, /* tp_getattr */
+ ( setattrfunc ) NMCol_setattr, /* tp_setattr */
+ 0, /* tp_compare */
+ ( reprfunc ) NMCol_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 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, /* up to tp_del to avoid a warning */
+};
+
+/*****************************/
+/* NMesh Python Object */
+/*****************************/
+static void NMFace_dealloc( PyObject * self )
+{
+ BPy_NMFace *mf = ( BPy_NMFace * ) self;
+
+ Py_DECREF( mf->v );
+ Py_DECREF( mf->uv );
+ Py_DECREF( mf->col );
+
+ PyObject_DEL( self );
+}
+
+static PyObject *new_NMFace( PyObject * vertexlist )
+{
+ BPy_NMFace *mf = PyObject_NEW( BPy_NMFace, &NMFace_Type );
+ PyObject *vlcopy;
+
+ if( vertexlist ) { /* create a copy of the given vertex list */
+ PyObject *item;
+ int i, len = PyList_Size( vertexlist );
+
+ vlcopy = PyList_New( len );
+
+ if( !vlcopy ) {
+ Py_DECREF(mf);
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create PyList" );
+ }
+ for( i = 0; i < len; i++ ) {
+ item = PySequence_GetItem( vertexlist, i ); /* PySequence increfs */
+
+ if( item )
+ PyList_SET_ITEM( vlcopy, i, item );
+ else {
+ Py_DECREF(mf);
+ Py_DECREF(vlcopy);
+ return EXPP_ReturnPyObjError
+ ( PyExc_RuntimeError,
+ "couldn't get vertex from a PyList" );
+ }
+ }
+ } else /* create an empty vertex list */
+ vlcopy = PyList_New( 0 );
+
+ mf->v = vlcopy;
+ mf->uv = PyList_New( 0 );
+ mf->image = NULL;
+ mf->mode = TF_DYNAMIC + TF_TEX;
+ mf->flag = TF_SELECT;
+ mf->transp = TF_SOLID;
+ mf->col = PyList_New( 0 );
+
+ mf->mf_flag = 0;
+ mf->mat_nr = 0;
+ mf->orig_index = -1;
+
+ return ( PyObject * ) mf;
+}
+
+static PyObject *M_NMesh_Face( PyObject * self, PyObject * args )
+{
+ PyObject *vertlist = NULL;
+
+ if( !PyArg_ParseTuple( args, "|O!", &PyList_Type, &vertlist ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a list of vertices or nothing as argument" );
+
+/* if (!vertlist) vertlist = PyList_New(0); */
+
+ return new_NMFace( vertlist );
+}
+
+static PyObject *NMFace_append( PyObject * self, PyObject * args )
+{
+ PyObject *vert;
+ BPy_NMFace *f = ( BPy_NMFace * ) self;
+
+ if( !PyArg_ParseTuple( args, "O!", &NMVert_Type, &vert ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected an NMVert object" );
+
+ PyList_Append( f->v, vert );
+
+ Py_RETURN_NONE;
+}
+
+#undef MethodDef
+#define MethodDef(func) {#func, NMFace_##func, METH_VARARGS, NMFace_##func##_doc}
+
+static struct PyMethodDef NMFace_methods[] = {
+ MethodDef( append ),
+ {NULL, NULL, 0, NULL}
+};
+
+static PyObject *NMFace_getattr( PyObject * self, char *name )
+{
+ BPy_NMFace *mf = ( BPy_NMFace * ) self;
+
+ if( strcmp( name, "v" ) == 0 )
+ return Py_BuildValue( "O", mf->v );
+ else if( strcmp( name, "col" ) == 0 )
+ return Py_BuildValue( "O", mf->col );
+ else if( strcmp( name, "mat" ) == 0 ) // emulation XXX
+ return Py_BuildValue( "i", mf->mat_nr );
+ else if( strcmp( name, "materialIndex" ) == 0 )
+ return Py_BuildValue( "i", mf->mat_nr );
+ else if( strcmp( name, "smooth" ) == 0 )
+ return Py_BuildValue( "i", (mf->mf_flag & ME_SMOOTH) ? 1:0 );
+ else if( strcmp( name, "sel" ) == 0 )
+ return Py_BuildValue( "i", (mf->mf_flag & ME_FACE_SEL) ? 1:0 );
+ else if( strcmp( name, "hide" ) == 0 )
+ return Py_BuildValue( "i", (mf->mf_flag & ME_HIDE) ? 1:0 );
+
+ else if( strcmp( name, "image" ) == 0 ) {
+ if( mf->image )
+ return Image_CreatePyObject( mf->image );
+ else
+ Py_RETURN_NONE;
+ }
+
+ else if( strcmp( name, "mode" ) == 0 )
+ return Py_BuildValue( "i", mf->mode );
+ else if( strcmp( name, "flag" ) == 0 )
+ return Py_BuildValue( "i", mf->flag );
+ else if( strcmp( name, "transp" ) == 0 )
+ return Py_BuildValue( "i", mf->transp );
+ else if( strcmp( name, "uv" ) == 0 )
+ return Py_BuildValue( "O", mf->uv );
+
+ else if( ( strcmp( name, "normal" ) == 0 )
+ || ( strcmp( name, "no" ) == 0 ) ) {
+
+ if( EXPP_check_sequence_consistency( mf->v, &NMVert_Type ) ==
+ 1 ) {
+
+ float fNormal[3] = { 0.0, 0.0, 0.0 };
+ float *vco[4] = { NULL, NULL, NULL, NULL };
+ int nSize = PyList_Size( mf->v );
+ int loop;
+
+ if( nSize != 3 && nSize != 4 )
+ return EXPP_ReturnPyObjError
+ ( PyExc_AttributeError,
+ "face must contain either 3 or 4 verts" );
+
+ for( loop = 0; loop < nSize; loop++ ) {
+ BPy_NMVert *v =
+ ( BPy_NMVert * ) PyList_GetItem( mf->v,
+ loop );
+ vco[loop] = ( float * ) v->co;
+ }
+
+ if( nSize == 4 )
+ CalcNormFloat4( vco[0], vco[1], vco[2], vco[3],
+ fNormal );
+ else
+ CalcNormFloat( vco[0], vco[1], vco[2],
+ fNormal );
+
+ return Py_BuildValue( "[f,f,f]", fNormal[0],
+ fNormal[1], fNormal[2] );
+ } else // EXPP_check_sequence_consistency failed
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "this face does not contain a series of NMVerts" );
+ }
+
+ else if( strcmp( name, "__members__" ) == 0 )
+ return Py_BuildValue( "[s,s,s,s,s,s,s,s,s,s,s,s,s]",
+ "v", "col", "mat", "materialIndex",
+ "smooth", "image", "mode", "flag",
+ "transp", "uv", "normal", "sel", "hide");
+ return Py_FindMethod( NMFace_methods, ( PyObject * ) self, name );
+}
+
+static int NMFace_setattr( PyObject * self, char *name, PyObject * v )
+{
+ BPy_NMFace *mf = ( BPy_NMFace * ) self;
+ short ival;
+ char cval;
+
+ if( strcmp( name, "v" ) == 0 ) {
+
+ if( PySequence_Check( v ) ) {
+ Py_DECREF( mf->v );
+ mf->v = EXPP_incr_ret( v );
+
+ return 0;
+ }
+ } else if( strcmp( name, "col" ) == 0 ) {
+
+ if( PySequence_Check( v ) ) {
+ Py_DECREF( mf->col );
+ mf->col = EXPP_incr_ret( v );
+
+ return 0;
+ }
+ } else if( !strcmp( name, "mat" ) || !strcmp( name, "materialIndex" ) ) {
+ PyArg_Parse( v, "b", &cval );
+ mf->mat_nr = cval;
+
+ return 0;
+ } else if( strcmp( name, "smooth" ) == 0 ) {
+ PyArg_Parse( v, "h", &ival );
+ if (ival) mf->mf_flag |= ME_SMOOTH;
+ else mf->mf_flag &= ~ME_SMOOTH;
+
+ return 0;
+ } else if( strcmp( name, "sel" ) == 0 ) {
+ PyArg_Parse( v, "h", &ival );
+ if (ival) mf->mf_flag |= ME_FACE_SEL;
+ else mf->mf_flag &= ~ME_FACE_SEL;
+
+ return 0;
+ } else if( strcmp( name, "hide" ) == 0 ) {
+ PyArg_Parse( v, "h", &ival );
+ if (ival) mf->mf_flag |= ME_HIDE;
+ else mf->mf_flag &= ~ME_HIDE;
+
+ return 0;
+
+ } else if( strcmp( name, "uv" ) == 0 ) {
+
+ if( PySequence_Check( v ) ) {
+ Py_DECREF( mf->uv );
+ mf->uv = EXPP_incr_ret( v );
+
+ return 0;
+ }
+ } else if( strcmp( name, "flag" ) == 0 ) {
+ PyArg_Parse( v, "h", &ival );
+ mf->flag = ival;
+
+ return 0;
+ } else if( strcmp( name, "mode" ) == 0 ) {
+ PyArg_Parse( v, "h", &ival );
+ mf->mode = ival;
+
+ return 0;
+ } else if( strcmp( name, "transp" ) == 0 ) {
+ PyArg_Parse( v, "b", &cval );
+ mf->transp = cval;
+
+ return 0;
+ } else if( strcmp( name, "image" ) == 0 ) {
+ PyObject *pyimg;
+ if( !PyArg_Parse( v, "O!", &Image_Type, &pyimg ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected image object" );
+
+ if( pyimg == Py_None ) {
+ mf->image = NULL;
+
+ return 0;
+ }
+
+ mf->image = ( ( BPy_Image * ) pyimg )->image;
+
+ return 0;
+ }
+
+ return EXPP_ReturnIntError( PyExc_AttributeError, name );
+}
+
+static PyObject *NMFace_repr( PyObject * self )
+{
+ return PyString_FromString( "[NMFace]" );
+}
+
+static int NMFace_len( BPy_NMFace * self )
+{
+ return PySequence_Length( self->v );
+}
+
+static PyObject *NMFace_item( BPy_NMFace * self, int i )
+{
+ return PySequence_GetItem( self->v, i ); // new ref
+}
+
+static PyObject *NMFace_slice( BPy_NMFace * self, int begin, int end )
+{
+ return PyList_GetSlice( self->v, begin, end ); // new ref
+}
+
+static PySequenceMethods NMFace_SeqMethods = {
+ ( inquiry ) NMFace_len, /* sq_length */
+ ( binaryfunc ) 0, /* sq_concat */
+ ( intargfunc ) 0, /* sq_repeat */
+ ( intargfunc ) NMFace_item, /* sq_item */
+ ( intintargfunc ) NMFace_slice, /* sq_slice */
+ ( intobjargproc ) 0, /* sq_ass_item */
+ ( intintobjargproc ) 0, /* sq_ass_slice */
+ 0,0,0,
+};
+
+PyTypeObject NMFace_Type = {
+ PyObject_HEAD_INIT( NULL ) 0, /*ob_size */
+ "Blender NMFace", /*tp_name */
+ sizeof( BPy_NMFace ), /*tp_basicsize */
+ 0, /*tp_itemsize */
+ /* methods */
+ ( destructor ) NMFace_dealloc, /*tp_dealloc */
+ ( printfunc ) 0, /*tp_print */
+ ( getattrfunc ) NMFace_getattr, /*tp_getattr */
+ ( setattrfunc ) NMFace_setattr, /*tp_setattr */
+ 0, /*tp_compare */
+ ( reprfunc ) NMFace_repr, /*tp_repr */
+ 0, /*tp_as_number */
+ &NMFace_SeqMethods, /*tp_as_sequence */
+ 0, /*tp_as_mapping */
+ 0, /*tp_hash */
+ 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, /* up to tp_del to avoid a warning */
+};
+
+static BPy_NMVert *newvert( float *co )
+{
+ BPy_NMVert *mv = PyObject_NEW( BPy_NMVert, &NMVert_Type );
+
+ mv->co[0] = co[0];
+ mv->co[1] = co[1];
+ mv->co[2] = co[2];
+
+ mv->no[0] = mv->no[1] = mv->no[2] = 0.0;
+ mv->uvco[0] = mv->uvco[1] = mv->uvco[2] = 0.0;
+ mv->flag = 0;
+
+ return mv;
+}
+
+static PyObject *M_NMesh_Vert( PyObject * self, PyObject * args )
+{
+ float co[3] = { 0.0, 0.0, 0.0 };
+
+ if( !PyArg_ParseTuple( args, "|fff", &co[0], &co[1], &co[2] ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected three floats (or nothing) as arguments" );
+
+ return ( PyObject * ) newvert( co );
+}
+
+static void NMVert_dealloc( PyObject * self )
+{
+ PyObject_DEL( self );
+}
+
+static PyObject *NMVert_getattr( PyObject * self, char *name )
+{
+ BPy_NMVert *mv = ( BPy_NMVert * ) self;
+
+ if( !strcmp( name, "co" ) || !strcmp( name, "loc" ) )
+ return newVectorObject(mv->co,3,Py_WRAP);
+
+ else if( strcmp( name, "no" ) == 0 )
+ return newVectorObject(mv->no,3,Py_WRAP);
+ else if( strcmp( name, "uvco" ) == 0 )
+ return newVectorObject(mv->uvco,3,Py_WRAP);
+ else if( strcmp( name, "index" ) == 0 )
+ return PyInt_FromLong( mv->index );
+ else if( strcmp( name, "sel" ) == 0 )
+ return PyInt_FromLong( mv->flag & 1 );
+ else if( strcmp( name, "__members__" ) == 0 )
+ return Py_BuildValue( "[s,s,s,s,s]", "co", "no", "uvco",
+ "index", "sel" );
+
+ return EXPP_ReturnPyObjError( PyExc_AttributeError, name );
+}
+
+static int NMVert_setattr( PyObject * self, char *name, PyObject * v )
+{
+ BPy_NMVert *mv = ( BPy_NMVert * ) self;
+ int i;
+
+ if( strcmp( name, "index" ) == 0 ) {
+ PyArg_Parse( v, "i", &i );
+ mv->index = i;
+ return 0;
+ } else if( strcmp( name, "sel" ) == 0 ) {
+ PyArg_Parse( v, "i", &i );
+ mv->flag = i ? 1 : 0;
+ return 0;
+ } else if( strcmp( name, "uvco" ) == 0 ) {
+
+ if( !PyArg_ParseTuple( v, "ff|f",
+ &( mv->uvco[0] ), &( mv->uvco[1] ),
+ &( mv->uvco[2] ) ) )
+ return EXPP_ReturnIntError( PyExc_AttributeError,
+ "Vector tuple or triple expected" );
+
+ return 0;
+ }
+
+ return EXPP_ReturnIntError( PyExc_AttributeError, name );
+}
+
+static int NMVert_len( BPy_NMVert * self )
+{
+ return 3;
+}
+
+static PyObject *NMVert_item( BPy_NMVert * self, int i )
+{
+ if( i < 0 || i >= 3 )
+ return EXPP_ReturnPyObjError( PyExc_IndexError,
+ "array index out of range" );
+
+ return Py_BuildValue( "f", self->co[i] );
+}
+
+static PyObject *NMVert_slice( BPy_NMVert * self, int begin, int end )
+{
+ PyObject *list;
+ int count;
+
+ if( begin < 0 )
+ begin = 0;
+ if( end > 3 )
+ end = 3;
+ if( begin > end )
+ begin = end;
+
+ list = PyList_New( end - begin );
+
+ for( count = begin; count < end; count++ )
+ PyList_SetItem( list, count - begin,
+ PyFloat_FromDouble( self->co[count] ) );
+
+ return list;
+}
+
+static int NMVert_ass_item( BPy_NMVert * self, int i, PyObject * ob )
+{
+ if( i < 0 || i >= 3 )
+ return EXPP_ReturnIntError( PyExc_IndexError,
+ "array assignment index out of range" );
+
+ if( !PyNumber_Check( ob ) )
+ return EXPP_ReturnIntError( PyExc_IndexError,
+ "NMVert member must be a number" );
+
+ self->co[i] = (float)PyFloat_AsDouble( ob );
+
+ return 0;
+}
+
+static int NMVert_ass_slice( BPy_NMVert * self, int begin, int end,
+ PyObject * seq )
+{
+ int count;
+
+ if( begin < 0 )
+ begin = 0;
+ if( end > 3 )
+ end = 3;
+ if( begin > end )
+ begin = end;
+
+ if( !PySequence_Check( seq ) )
+ EXPP_ReturnIntError( PyExc_TypeError,
+ "illegal argument type for built-in operation" );
+
+ if( PySequence_Length( seq ) != ( end - begin ) )
+ EXPP_ReturnIntError( PyExc_TypeError,
+ "size mismatch in slice assignment" );
+
+ for( count = begin; count < end; count++ ) {
+ PyObject *ob = PySequence_GetItem( seq, count );
+
+ if( !PyArg_Parse( ob, "f", &self->co[count] ) ) {
+ Py_DECREF( ob );
+ return -1;
+ }
+
+ Py_DECREF( ob );
+ }
+
+ return 0;
+}
+
+static PySequenceMethods NMVert_SeqMethods = {
+ ( inquiry ) NMVert_len, /* sq_length */
+ ( binaryfunc ) 0, /* sq_concat */
+ ( intargfunc ) 0, /* sq_repeat */
+ ( intargfunc ) NMVert_item, /* sq_item */
+ ( intintargfunc ) NMVert_slice, /* sq_slice */
+ ( intobjargproc ) NMVert_ass_item, /* sq_ass_item */
+ ( intintobjargproc ) NMVert_ass_slice, /* sq_ass_slice */
+ 0,0,0,
+};
+
+PyTypeObject NMVert_Type = {
+ PyObject_HEAD_INIT( NULL )
+ 0, /*ob_size */
+ "Blender NMVert", /*tp_name */
+ sizeof( BPy_NMVert ), /*tp_basicsize */
+ 0, /*tp_itemsize */
+ /* methods */
+ ( destructor ) NMVert_dealloc, /*tp_dealloc */
+ ( printfunc ) 0, /*tp_print */
+ ( getattrfunc ) NMVert_getattr, /*tp_getattr */
+ ( setattrfunc ) NMVert_setattr, /*tp_setattr */
+ 0, /*tp_compare */
+ ( reprfunc ) 0, /*tp_repr */
+ 0, /*tp_as_number */
+ &NMVert_SeqMethods, /*tp_as_sequence */
+ 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, /* tp_del */
+};
+
+
+/*****************************
+ * NMEdge
+ *****************************/
+
+static BPy_NMEdge *new_NMEdge( BPy_NMVert * v1, BPy_NMVert * v2, char crease, short flag)
+{
+ BPy_NMEdge *edge=NULL;
+
+ if (!v1 || !v2) return NULL;
+ if (!BPy_NMVert_Check(v1) || !BPy_NMVert_Check(v2)) return NULL;
+
+ edge = PyObject_NEW( BPy_NMEdge, &NMEdge_Type );
+
+ edge->v1=EXPP_incr_ret((PyObject*)v1);
+ edge->v2=EXPP_incr_ret((PyObject*)v2);
+ edge->flag=flag;
+ edge->crease=crease;
+
+ return edge;
+}
+
+static void NMEdge_dealloc( PyObject * self )
+{
+ BPy_NMEdge *edge=(BPy_NMEdge *)self;
+
+ Py_DECREF(edge->v1);
+ Py_DECREF(edge->v2);
+
+ PyObject_DEL(self);
+}
+
+static PyObject *NMEdge_getattr( PyObject * self, char *name )
+{
+ BPy_NMEdge *edge=(BPy_NMEdge *)self;
+
+ if ( strcmp( name, "v1" ) == 0 )
+ return EXPP_incr_ret( edge->v1 );
+ else if ( strcmp( name, "v2" ) == 0 )
+ return EXPP_incr_ret( edge->v2 );
+ else if ( strcmp( name, "flag" ) == 0 )
+ return PyInt_FromLong( edge->flag );
+ else if ( strcmp( name, "crease" ) == 0 )
+ return PyInt_FromLong( edge->crease );
+ else if( strcmp( name, "__members__" ) == 0 )
+ return Py_BuildValue( "[s,s,s,s]",
+ "v1", "v2", "flag", "crease" );
+
+ return EXPP_ReturnPyObjError( PyExc_AttributeError, name );
+}
+
+static int NMEdge_setattr( PyObject * self, char *name, PyObject * v )
+{
+ BPy_NMEdge *edge=(BPy_NMEdge *)self;
+
+ if ( strcmp( name, "flag" ) == 0 )
+ {
+ short flag=0;
+ if( !PyInt_Check( v ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected int argument" );
+
+ flag = ( short ) PyInt_AsLong( v );
+
+ edge->flag = flag;
+
+ return 0;
+ }
+ else if ( strcmp( name, "crease" ) == 0 )
+ {
+ char crease=0;
+ if( !PyInt_Check( v ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected int argument" );
+
+ crease = ( char ) PyInt_AsLong( v );
+
+ edge->crease = crease;
+
+ return 0;
+ }
+
+ return EXPP_ReturnIntError( PyExc_AttributeError, name );
+}
+
+PyTypeObject NMEdge_Type = {
+ PyObject_HEAD_INIT( NULL )
+ 0, /*ob_size */
+ "Blender NMEdge", /*tp_name */
+ sizeof( BPy_NMEdge ), /*tp_basicsize */
+ 0, /*tp_itemsize */
+ /* methods */
+ ( destructor ) NMEdge_dealloc, /*tp_dealloc */
+ ( printfunc ) 0, /*tp_print */
+ ( getattrfunc ) NMEdge_getattr, /*tp_getattr */
+ ( setattrfunc ) NMEdge_setattr, /*tp_setattr */
+ 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,
+};
+
+static void NMesh_dealloc( PyObject * self )
+{
+ BPy_NMesh *me = ( BPy_NMesh * ) self;
+
+ CustomData_free( &me->fdata, me->totfdata );
+
+ Py_DECREF( me->name );
+ Py_DECREF( me->verts );
+ Py_DECREF( me->faces );
+ Py_DECREF( me->materials );
+ Py_DECREF( me->edges );
+
+ PyObject_DEL( self );
+}
+
+static PyObject *NMesh_getMaterials( PyObject * self, PyObject * args )
+{
+ BPy_NMesh *nm = ( BPy_NMesh * ) self;
+ PyObject *list = NULL;
+ Mesh *me = nm->mesh;
+ int all = -1;
+
+ if( !PyArg_ParseTuple( args, "|i", &all ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected nothing or an int (bool) as argument" );
+
+ if( all >= 0 ) {
+ if (!me)
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "meshes obtained with GetRawFromObject don't support this option");
+
+ list = EXPP_PyList_fromMaterialList( me->mat, me->totcol,
+ all );
+ Py_DECREF( nm->materials ); /* update nmesh.materials attribute */
+ nm->materials = EXPP_incr_ret( list );
+ } else
+ list = EXPP_incr_ret( nm->materials );
+
+ return list;
+}
+
+static PyObject *NMesh_setMaterials( PyObject * self, PyObject * args )
+{
+ BPy_NMesh *me = ( BPy_NMesh * ) self;
+ PyObject *pymats = NULL;
+
+ if( !PyArg_ParseTuple( args, "O!", &PyList_Type, &pymats ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a list of materials (None's also accepted) as argument" );
+
+ if( !EXPP_check_sequence_consistency( pymats, &Material_Type ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "list should only contain materials (None's also accepted)" );
+
+ if( PyList_Size( pymats ) > 16 )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "list can't have more than 16 materials" );
+
+ Py_DECREF( me->materials );
+ me->materials = EXPP_incr_ret( pymats );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *NMesh_addMaterial( PyObject * self, PyObject * args )
+{
+ BPy_NMesh *me = ( BPy_NMesh * ) self;
+ BPy_Material *pymat;
+ Material *mat;
+ PyObject *iter;
+ int i, len = 0;
+
+ if( !PyArg_ParseTuple( args, "O!", &Material_Type, &pymat ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected Blender Material PyObject" );
+
+ mat = pymat->material;
+ len = PyList_Size( me->materials );
+
+ if( len >= 16 )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "object data material lists can't have more than 16 materials" );
+
+ for( i = 0; i < len; i++ ) {
+ iter = PyList_GetItem( me->materials, i );
+ if( mat == Material_FromPyObject( iter ) )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "material already in the list" );
+ }
+
+ PyList_Append( me->materials, ( PyObject * ) pymat );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *NMesh_getKey( BPy_NMesh * self )
+{
+ PyObject *keyobj;
+
+ if( self->mesh->key )
+ keyobj = Key_CreatePyObject(self->mesh->key);
+ else
+ keyobj = EXPP_incr_ret(Py_None);
+
+ return keyobj;
+}
+
+static PyObject *NMesh_removeAllKeys( PyObject * self, PyObject * args )
+{
+ BPy_NMesh *nm = ( BPy_NMesh * ) self;
+ Mesh *me = nm->mesh;
+
+ if( !PyArg_ParseTuple( args, "" ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "this function expects no arguments" );
+
+ if( !me || !me->key )
+ return EXPP_incr_ret_False();
+
+ me->key->id.us--;
+ me->key = 0;
+
+ return EXPP_incr_ret_True();
+}
+
+static PyObject *NMesh_insertKey( PyObject * self, PyObject * args )
+{
+ int fra = -1, oldfra = -1;
+ char *type = NULL;
+ short typenum;
+ BPy_NMesh *nm = ( BPy_NMesh * ) self;
+ Mesh *mesh = nm->mesh;
+
+ if( !PyArg_ParseTuple( args, "|is", &fra, &type ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected nothing or an int and optionally a string as arguments" );
+
+ if( !type || !strcmp( type, "relative" ) )
+ typenum = 1;
+ else if( !strcmp( type, "absolute" ) )
+ typenum = 2;
+ else
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "if given, type should be 'relative' or 'absolute'" );
+
+ if( fra > 0 ) {
+ fra = EXPP_ClampInt( fra, 1, NMESH_FRAME_MAX );
+ oldfra = G.scene->r.cfra;
+ G.scene->r.cfra = (int)fra;
+ }
+
+ if( !mesh )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "update this NMesh first with its .update() method" );
+
+ insert_meshkey( mesh, typenum );
+ allspace(REMAKEIPO, 0);
+
+ if( fra > 0 )
+ G.scene->r.cfra = (int)oldfra;
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *NMesh_getSelectedFaces( PyObject * self, PyObject * args )
+{
+ BPy_NMesh *nm = ( BPy_NMesh * ) self;
+ Mesh *me = nm->mesh;
+ int i, totfaces, flag = 0;
+ PyObject *l, *pyval;
+
+ if( !PyArg_ParseTuple( args, "|i", &flag ) )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "expected int argument (or nothing)" );
+
+ l = PyList_New( 0 );
+ if( me == NULL || me->mface == NULL)
+ return l;
+
+ /* make sure not to write more faces then we have */
+ totfaces= MIN2(me->totface, PySequence_Length(nm->faces));
+
+ if( flag ) {
+ for( i = 0; i < totfaces; i++ ) {
+ if( me->mface[i].flag & ME_FACE_SEL ) {
+ pyval = PyInt_FromLong( i );
+ PyList_Append( l, pyval );
+ Py_DECREF(pyval);
+ }
+ }
+ } else {
+ for( i = 0; i < totfaces; i++ ) {
+ if( me->mface[i].flag & ME_FACE_SEL )
+ PyList_Append( l, PyList_GetItem( nm->faces, i ) );
+ }
+ }
+ return l;
+}
+
+static PyObject *NMesh_getActiveFace( PyObject * self )
+{
+ if( ( ( BPy_NMesh * ) self )->sel_face < 0 )
+ Py_RETURN_NONE;
+
+ return Py_BuildValue( "i", ( ( BPy_NMesh * ) self )->sel_face );
+}
+
+static PyObject *NMesh_hasVertexUV( PyObject * self, PyObject * args )
+{
+ BPy_NMesh *me = ( BPy_NMesh * ) self;
+ int flag = -1;
+
+ if( !PyArg_ParseTuple( args, "|i", &flag ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected int argument (or nothing)" );
+
+ switch ( flag ) {
+ case 0:
+ me->flags &= ~NMESH_HASVERTUV;
+ break;
+ case 1:
+ me->flags |= NMESH_HASVERTUV;
+ break;
+ default:
+ break;
+ }
+
+ if( me->flags & NMESH_HASVERTUV )
+ return EXPP_incr_ret_True();
+ else
+ return EXPP_incr_ret_False();
+}
+
+static PyObject *NMesh_hasFaceUV( PyObject * self, PyObject * args )
+{
+ BPy_NMesh *me = ( BPy_NMesh * ) self;
+ int flag = -1;
+
+ if( !PyArg_ParseTuple( args, "|i", &flag ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected int argument (or nothing)" );
+
+ switch ( flag ) {
+ case 0:
+ me->flags &= ~NMESH_HASFACEUV;
+ break;
+ case 1:
+ me->flags |= NMESH_HASFACEUV;
+ break;
+ default:
+ break;
+ }
+
+ if( me->flags & NMESH_HASFACEUV )
+ return EXPP_incr_ret_True();
+ else
+ return EXPP_incr_ret_False();
+}
+
+static PyObject *NMesh_hasVertexColours( PyObject * self, PyObject * args )
+{
+ BPy_NMesh *me = ( BPy_NMesh * ) self;
+ int flag = -1;
+
+ if( !PyArg_ParseTuple( args, "|i", &flag ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected int argument (or nothing)" );
+
+ switch ( flag ) {
+ case 0:
+ me->flags &= ~NMESH_HASMCOL;
+ break;
+ case 1:
+ me->flags |= NMESH_HASMCOL;
+ break;
+ default:
+ break;
+ }
+
+ if( me->flags & NMESH_HASMCOL )
+ return EXPP_incr_ret_True();
+ else
+ return EXPP_incr_ret_False();
+}
+
+static PyObject *NMesh_update( PyObject *self, PyObject *a, PyObject *kwd )
+{
+ BPy_NMesh *nmesh = ( BPy_NMesh * ) self;
+ Mesh *mesh = nmesh->mesh;
+ int recalc_normals = 0, store_edges = 0, vertex_shade = 0;
+ static char *kwlist[] = {"recalc_normals", "store_edges",
+ "vertex_shade", NULL};
+ int needs_redraw = 1;
+ int old_totvert = 0;
+
+ if (!PyArg_ParseTupleAndKeywords(a, kwd, "|iii", kwlist, &recalc_normals,
+ &store_edges, &vertex_shade ) )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected nothing or one to three bool(s) (0 or 1) as argument" );
+
+ if( check_NMeshLists( nmesh ) )
+ return NULL;
+
+ if( mesh ) {
+ old_totvert = mesh->totvert;
+ unlink_existingMeshData( mesh );
+ if( !convert_NMeshToMesh( mesh, nmesh ) )
+ return NULL;
+ if (mesh->dvert) check_dverts(mesh, old_totvert);
+ } else {
+ mesh = Mesh_fromNMesh( nmesh );
+ /* if mesh is NULL, there was an error */
+ if( !mesh )
+ return NULL;
+ nmesh->mesh = mesh;
+ }
+
+ if( recalc_normals )
+ mesh_calc_normals(mesh->mvert, mesh->totvert, mesh->mface, mesh->totface, NULL);
+
+ mesh_update( mesh, nmesh->object );
+
+ nmesh_updateMaterials( nmesh );
+
+ if( nmesh->name && nmesh->name != Py_None )
+ new_id( &( G.main->mesh ), &mesh->id,
+ PyString_AsString( nmesh->name ) );
+
+ if (vertex_shade) {
+ Base *base = FIRSTBASE;
+
+ if (!nmesh->object)
+ return EXPP_ReturnPyObjError(PyExc_RuntimeError,
+ "link this mesh to an object first with ob.link(mesh)" );
+
+ if (G.obedit)
+ return EXPP_ReturnPyObjError(PyExc_RuntimeError,
+ "can't shade vertices while in edit mode" );
+
+ while (base) {
+ if (base->object == nmesh->object) {
+ base->flag |= SELECT;
+ nmesh->object->flag = (short)base->flag;
+ set_active_base (base);
+ needs_redraw = 0; /* already done in make_vertexcol */
+ break;
+ }
+ base = base->next;
+ }
+
+ /* recalculate the derived mesh before trying to use it */
+ makeDerivedMesh(nmesh->object, CD_MASK_BAREMESH);
+ make_vertexcol(1);
+
+ countall();
+ }
+
+ if( !during_script( ) && needs_redraw)
+ EXPP_allqueue( REDRAWVIEW3D, 0 );
+
+ return PyInt_FromLong( 1 );
+}
+
+/** Implementation of the python method getVertexInfluence for an NMesh object.
+ * This method returns a list of pairs (string,float) with bone names and
+ * influences that this vertex receives.
+ * @author Jordi Rovira i Bonet
+ */
+
+static PyObject *NMesh_getVertexInfluences( PyObject * self, PyObject * args )
+{
+ int index;
+ PyObject *influence_list = NULL;
+ Object *object = ( ( BPy_NMesh * ) self )->object;
+ Mesh *me = ( ( BPy_NMesh * ) self )->mesh;
+
+ /* Get a reference to the mesh object wrapped in here. */
+ if( !me )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "unlinked nmesh: call its .update() method first" );
+
+ if( !object )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "This mesh must be linked to an object" );
+
+ /* Parse the parameters: only on integer (vertex index) */
+ if( !PyArg_ParseTuple( args, "i", &index ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected int argument (index of the vertex)" );
+
+ /* check for valid index */
+ if( index < 0 || index >= me->totvert )
+ return EXPP_ReturnPyObjError( PyExc_IndexError,
+ "vertex index out of range" );
+
+ influence_list = PyList_New( 0 );
+
+ /* Proceed only if we have vertex deformation information */
+ if( me->dvert ) {
+ int i;
+ MDeformWeight *sweight = NULL;
+
+ /* Number of bones influencing the vertex */
+ int totinfluences = me->dvert[index].totweight;
+
+ /* Get the reference of the first weight structure */
+ sweight = me->dvert[index].dw;
+
+ /* Build the list only with weights and names of the influent bones */
+ for( i = 0; i < totinfluences; i++, sweight++ ) {
+ bDeformGroup *defgroup = (bDeformGroup *) BLI_findlink( &object->defbase,
+ sweight->def_nr );
+ if( defgroup )
+ PyList_Append( influence_list, Py_BuildValue( "[sf]",
+ defgroup->name, sweight->weight ) );
+ }
+ }
+
+ return influence_list;
+}
+
+Mesh *Mesh_fromNMesh( BPy_NMesh * nmesh )
+{
+ Mesh *mesh = NULL;
+
+ mesh = add_mesh( "Mesh" );
+
+ if( !mesh ) {
+ PyErr_SetString( PyExc_RuntimeError,
+ "FATAL: could not create mesh object" );
+ return NULL;
+ }
+
+ mesh->id.us = 0; /* no user yet */
+ G.totmesh++;
+
+ if( !convert_NMeshToMesh( mesh, nmesh ) )
+ return NULL;
+
+ return mesh;
+}
+
+static PyObject *NMesh_getMaxSmoothAngle( BPy_NMesh * self )
+{
+ return PyInt_FromLong( self->smoothresh );
+}
+
+static PyObject *NMesh_setMaxSmoothAngle( PyObject * self, PyObject * args )
+{
+ short value = 0;
+ BPy_NMesh *nmesh = ( BPy_NMesh * ) self;
+
+ if( !PyArg_ParseTuple( args, "h", &value ) )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected an int in [1, 80] as argument" );
+
+ nmesh->smoothresh =
+ ( short ) EXPP_ClampInt( value, NMESH_SMOOTHRESH_MIN,
+ NMESH_SMOOTHRESH_MAX );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *NMesh_getSubDivLevels( BPy_NMesh * self )
+{
+ return Py_BuildValue( "[h,h]", self->subdiv[0], self->subdiv[1] );
+}
+
+static PyObject *NMesh_setSubDivLevels( PyObject * self, PyObject * args )
+{
+ short display = 0, render = 0;
+ BPy_NMesh *nmesh = ( BPy_NMesh * ) self;
+
+ if( !PyArg_ParseTuple( args, "(hh)", &display, &render ) )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected a sequence [int, int] as argument" );
+
+ nmesh->subdiv[0] =
+ ( short ) EXPP_ClampInt( display, NMESH_SUBDIV_MIN,
+ NMESH_SUBDIV_MAX );
+
+ nmesh->subdiv[1] =
+ ( short ) EXPP_ClampInt( render, NMESH_SUBDIV_MIN,
+ NMESH_SUBDIV_MAX );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *NMesh_getMode( BPy_NMesh * self )
+{
+ return PyInt_FromLong( self->mode );
+}
+
+static PyObject *NMesh_setMode( PyObject * self, PyObject * args )
+{
+ BPy_NMesh *nmesh = ( BPy_NMesh * ) self;
+ PyObject *arg1 = NULL;
+ char *m[5] = { NULL, NULL, NULL, NULL, NULL };
+ short i, mode = 0;
+
+ if( !PyArg_ParseTuple ( args, "|Ossss", &arg1, &m[1], &m[2], &m[3], &m[4] ) )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected an int or from none to 5 strings as argument(s)" );
+
+ if (arg1) {
+ if (PyInt_Check(arg1)) {
+ mode = (short)PyInt_AsLong(arg1);
+ }
+ else if (PyString_Check(arg1)) {
+ m[0] = PyString_AsString(arg1);
+ for( i = 0; i < 5; i++ ) {
+ if( !m[i] ) break;
+ else if( strcmp( m[i], "NoVNormalsFlip" ) == 0 )
+ mode |= ME_NOPUNOFLIP;
+ else if( strcmp( m[i], "TwoSided" ) == 0 )
+ mode |= ME_TWOSIDED;
+ else if( strcmp( m[i], "AutoSmooth" ) == 0 )
+ mode |= ME_AUTOSMOOTH;
+ else if( m[i][0] == '\0' )
+ mode = 0;
+ else
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "unknown NMesh mode" );
+ }
+ }
+ else return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected an int or from none to 5 strings as argument(s)" );
+ }
+
+ nmesh->mode = mode;
+
+ Py_RETURN_NONE;
+}
+
+/* METH_VARARGS: function(PyObject *self, PyObject *args) */
+#undef MethodDef
+#define MethodDef(func) {#func, NMesh_##func, METH_VARARGS, NMesh_##func##_doc}
+
+static struct PyMethodDef NMesh_methods[] = {
+ MethodDef( addEdge ),
+ MethodDef( findEdge ),
+ MethodDef( removeEdge ),
+ MethodDef( addFace ),
+ MethodDef( removeFace ),
+ MethodDef( addVertGroup ),
+ MethodDef( removeVertGroup ),
+ MethodDef( assignVertsToGroup ),
+ MethodDef( removeVertsFromGroup ),
+ MethodDef( getVertsFromGroup ),
+ MethodDef( renameVertGroup ),
+ MethodDef( hasVertexColours ),
+ MethodDef( hasFaceUV ),
+ MethodDef( hasVertexUV ),
+ MethodDef( getSelectedFaces ),
+ MethodDef( getVertexInfluences ),
+ MethodDef( getMaterials ),
+ MethodDef( setMaterials ),
+ MethodDef( addMaterial ),
+ MethodDef( insertKey ),
+ MethodDef( removeAllKeys ),
+ MethodDef( setMode ),
+ MethodDef( setMaxSmoothAngle ),
+ MethodDef( setSubDivLevels ),
+ MethodDef( transform ),
+
+/* METH_NOARGS: function(PyObject *self) */
+#undef MethodDef
+#define MethodDef(func) {#func, (PyCFunction)NMesh_##func, METH_NOARGS,\
+ NMesh_##func##_doc}
+
+ MethodDef( printDebug ),
+ MethodDef( getVertGroupNames ),
+ MethodDef( getActiveFace ),
+ MethodDef( getKey ),
+ MethodDef( getMode ),
+ MethodDef( getMaxSmoothAngle ),
+ MethodDef( getSubDivLevels ),
+
+/* METH_VARARGS | METH_KEYWORDS:
+ * function(PyObject *self, PyObject *args, PyObject *keywords) */
+#undef MethodDef
+#define MethodDef(func) {#func, (PyCFunction)NMesh_##func,\
+ METH_VARARGS | METH_KEYWORDS, NMesh_##func##_doc}
+
+ MethodDef( update ),
+ {NULL, NULL, 0, NULL}
+};
+
+static PyObject *NMesh_getattr( PyObject * self, char *name )
+{
+ BPy_NMesh *me = ( BPy_NMesh * ) self;
+
+ if( strcmp( name, "name" ) == 0 )
+ return EXPP_incr_ret( me->name );
+
+ else if ( strcmp( name, "properties" ) == 0 )
+ return BPy_Wrap_IDProperty( (ID*)me->mesh, IDP_GetProperties((ID*)me->mesh, 1), NULL );
+
+ else if( strcmp( name, "mode" ) == 0 )
+ return PyInt_FromLong( me->mode );
+
+ else if( strcmp( name, "block_type" ) == 0 ) /* for compatibility */
+ return PyString_FromString( "NMesh" );
+
+ else if( strcmp( name, "materials" ) == 0 )
+ return EXPP_incr_ret( me->materials );
+
+ else if( strcmp( name, "verts" ) == 0 )
+ return EXPP_incr_ret( me->verts );
+
+ else if( strcmp( name, "maxSmoothAngle" ) == 0 )
+ return PyInt_FromLong( me->smoothresh );
+
+ else if( strcmp( name, "subDivLevels" ) == 0 )
+ return Py_BuildValue( "[h,h]", me->subdiv[0], me->subdiv[1] );
+
+ else if( strcmp( name, "users" ) == 0 ) {
+ if( me->mesh ) {
+ return PyInt_FromLong( me->mesh->id.us );
+ } else { /* it's a free mesh: */
+ return Py_BuildValue( "i", 0 );
+ }
+ }
+ else if (strcmp( name, "key") == 0)
+ return NMesh_getKey((BPy_NMesh*)self);
+
+ else if( strcmp( name, "faces" ) == 0 )
+ return EXPP_incr_ret( me->faces );
+
+ else if( strcmp( name, "edges" ) == 0 )
+ {
+ return EXPP_incr_ret( me->edges );
+ }
+ else if( strcmp( name, "__members__" ) == 0 )
+ return Py_BuildValue( "[s,s,s,s,s,s,s,s,s,s,s]",
+ "name", "materials", "verts", "users",
+ "faces", "maxSmoothAngle",
+ "subdivLevels", "edges", "key" );
+
+ return Py_FindMethod( NMesh_methods, ( PyObject * ) self, name );
+}
+
+static int NMesh_setattr( PyObject * self, char *name, PyObject * v )
+{
+ BPy_NMesh *me = ( BPy_NMesh * ) self;
+
+ if( !strcmp( name, "name" ) ) {
+
+ if( !PyString_Check( v ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected string argument" );
+
+ Py_DECREF( me->name );
+ me->name = EXPP_incr_ret( v );
+ }
+
+ else if( !strcmp( name, "mode" ) ) {
+ short mode;
+
+ if( !PyInt_Check( v ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected int argument" );
+
+ mode = ( short ) PyInt_AsLong( v );
+ if( mode >= 0 )
+ me->mode = mode;
+ else
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "expected positive int argument" );
+ }
+
+ else if( !strcmp( name, "verts" ) || !strcmp( name, "faces" ) ||
+ !strcmp( name, "materials" ) ) {
+
+ if( PySequence_Check( v ) ) {
+
+ if( strcmp( name, "materials" ) == 0 ) {
+ Py_DECREF( me->materials );
+ me->materials = EXPP_incr_ret( v );
+ } else if( strcmp( name, "verts" ) == 0 ) {
+ Py_DECREF( me->verts );
+ me->verts = EXPP_incr_ret( v );
+ } else {
+ Py_DECREF( me->faces );
+ me->faces = EXPP_incr_ret( v );
+ }
+ }
+
+ else
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a list" );
+ }
+
+ else if( !strcmp( name, "maxSmoothAngle" ) ) {
+ short smoothresh = 0;
+
+ if( !PyInt_Check( v ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected int argument" );
+
+ smoothresh = ( short ) PyInt_AsLong( v );
+
+ me->smoothresh =
+ (short)EXPP_ClampInt( smoothresh, NMESH_SMOOTHRESH_MIN,
+ NMESH_SMOOTHRESH_MAX );
+ }
+
+ else if( !strcmp( name, "subDivLevels" ) ) {
+ int subdiv[2] = { 0, 0 };
+ int i;
+ PyObject *tmp;
+
+ if( !PySequence_Check( v ) || ( PySequence_Length( v ) != 2 ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a list [int, int] as argument" );
+
+ for( i = 0; i < 2; i++ ) {
+ tmp = PySequence_GetItem( v, i );
+ if( tmp ) {
+ if( !PyInt_Check( tmp ) ) {
+ Py_DECREF( tmp );
+ return EXPP_ReturnIntError
+ ( PyExc_TypeError,
+ "expected a list [int, int] as argument" );
+ }
+
+ subdiv[i] = PyInt_AsLong( tmp );
+ me->subdiv[i] =
+ ( short ) EXPP_ClampInt( subdiv[i],
+ NMESH_SUBDIV_MIN,
+ NMESH_SUBDIV_MAX );
+ Py_DECREF( tmp );
+ } else
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "couldn't retrieve subdiv values from list" );
+ }
+ }
+ else if( strcmp( name, "edges" ) == 0 )
+ {
+ if (PySequence_Check(v))
+ {
+ Py_DECREF(me->edges);
+ me->edges = EXPP_incr_ret( v );
+ }
+ }
+ else
+ return EXPP_ReturnIntError( PyExc_AttributeError, name );
+
+ return 0;
+}
+
+PyTypeObject NMesh_Type = {
+ PyObject_HEAD_INIT( NULL ) 0, /*ob_size */
+ "Blender NMesh", /*tp_name */
+ sizeof( BPy_NMesh ), /*tp_basicsize */
+ 0, /*tp_itemsize */
+ /* methods */
+ ( destructor ) NMesh_dealloc, /*tp_dealloc */
+ ( printfunc ) 0, /*tp_print */
+ ( getattrfunc ) NMesh_getattr, /*tp_getattr */
+ ( setattrfunc ) NMesh_setattr, /*tp_setattr */
+ 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,
+};
+
+static BPy_NMFace *nmface_from_data( BPy_NMesh * mesh, int vidxs[4],
+ char mat_nr, char flag, MTFace * tface, MCol * col, int orig_index )
+{
+ BPy_NMFace *newf = PyObject_NEW( BPy_NMFace, &NMFace_Type );
+ int i, len;
+
+ if( vidxs[3] )
+ len = 4;
+ else
+ len = 3;
+
+ newf->v = PyList_New( len );
+
+ for( i = 0; i < len; i++ )
+ PyList_SetItem( newf->v, i,
+ EXPP_incr_ret( PyList_GetItem
+ ( mesh->verts, vidxs[i] ) ) );
+
+ if( tface ) {
+ newf->uv = PyList_New( len ); // per-face UV coordinates
+
+ for( i = 0; i < len; i++ ) {
+ PyList_SetItem( newf->uv, i,
+ Py_BuildValue( "(ff)", tface->uv[i][0],
+ tface->uv[i][1] ) );
+ }
+
+ if( tface->tpage ) /* pointer to image per face: */
+ newf->image = ( Image * ) tface->tpage;
+ else
+ newf->image = NULL;
+
+ newf->mode = tface->mode; /* draw mode */
+ newf->flag = tface->flag; /* select flag */
+ newf->transp = tface->transp; /* transparency flag */
+ } else {
+ newf->mode = TF_DYNAMIC; /* just to initialize it to something meaninful, */
+ /* since without tfaces there are no tface->mode's, obviously. */
+ newf->image = NULL;
+ newf->uv = PyList_New( 0 );
+ }
+
+ newf->mat_nr = mat_nr;
+ newf->mf_flag = flag; /* MFace flag */
+ newf->orig_index = orig_index;
+
+ if( col ) {
+ newf->col = PyList_New( 4 );
+ for( i = 0; i < 4; i++, col++ ) {
+ PyList_SetItem( newf->col, i,
+ ( PyObject * ) newcol( col->b, col->g,
+ col->r,
+ col->a ) );
+ }
+ } else
+ newf->col = PyList_New( 0 );
+
+ return newf;
+}
+
+static BPy_NMEdge *nmedge_from_index( BPy_NMesh * mesh, int v0idx, int v1idx)
+{
+ BPy_NMVert *v1=(BPy_NMVert *)PyList_GetItem( mesh->verts, v0idx);
+ BPy_NMVert *v2=(BPy_NMVert *)PyList_GetItem( mesh->verts, v1idx);
+ return new_NMEdge(v1, v2, (char)0.0, 0);
+}
+
+static BPy_NMEdge *nmedge_from_data( BPy_NMesh * mesh, MEdge *edge )
+{
+ BPy_NMVert *v1=(BPy_NMVert *)PyList_GetItem( mesh->verts, edge->v1 );
+ BPy_NMVert *v2=(BPy_NMVert *)PyList_GetItem( mesh->verts, edge->v2 );
+ return new_NMEdge(v1, v2, edge->crease, edge->flag);
+}
+
+static BPy_NMVert *nmvert_from_data( MVert * vert, MSticky * st, float *co,
+ int idx, char flag )
+{
+ BPy_NMVert *mv = PyObject_NEW( BPy_NMVert, &NMVert_Type );
+
+ mv->co[0] = co[0];
+ mv->co[1] = co[1];
+ mv->co[2] = co[2];
+
+ mv->no[0] = (float)(vert->no[0] / 32767.0);
+ mv->no[1] = (float)(vert->no[1] / 32767.0);
+ mv->no[2] = (float)(vert->no[2] / 32767.0);
+
+ if( st ) {
+ mv->uvco[0] = st->co[0];
+ mv->uvco[1] = st->co[1];
+ mv->uvco[2] = 0.0;
+
+ } else
+ mv->uvco[0] = mv->uvco[1] = mv->uvco[2] = 0.0;
+
+ mv->index = idx;
+ mv->flag = flag & 1;
+
+ return mv;
+}
+
+static int get_active_faceindex( Mesh * me )
+{
+ if( me == NULL )
+ return -1;
+
+ if (me->act_face != -1 && me->act_face < me->totface)
+ return me->act_face;
+ return -1;
+}
+
+static BPy_NMVert *nmvert_from_float(float *co, float *no, int idx) {
+ BPy_NMVert *mv;
+
+ mv = PyObject_NEW( BPy_NMVert, &NMVert_Type );
+
+ mv->index = idx;
+
+ mv->co[0] = co[0];
+ mv->co[1] = co[1];
+ mv->co[2] = co[2];
+
+ mv->no[0] = no[0];
+ mv->no[1] = no[1];
+ mv->no[2] = no[2];
+
+ mv->uvco[0] = mv->uvco[1] = mv->uvco[2] = 0.0;
+
+ mv->flag = 0;
+
+ return mv;
+}
+
+static BPy_NMFace *nmface_from_index( BPy_NMesh * mesh, int vidxs[4], char mat_nr )
+{
+ BPy_NMFace *newf = PyObject_NEW( BPy_NMFace, &NMFace_Type );
+ int i, len;
+
+ if( vidxs[3] )
+ len = 4;
+ else if( vidxs[2] )
+ len = 3;
+ else
+ len = 2;
+
+ newf->v = PyList_New( len );
+
+ for( i = 0; i < len; i++ )
+ PyList_SetItem( newf->v, i,
+ EXPP_incr_ret( PyList_GetItem
+ ( mesh->verts, vidxs[i] ) ) );
+
+ newf->mode = TF_DYNAMIC; /* just to initialize it to something meaninful, */
+ /* since without tfaces there are no tface->mode's, obviously. */
+ newf->image = NULL;
+ newf->uv = PyList_New( 0 );
+
+ newf->mat_nr = mat_nr;
+ newf->mf_flag = 0;
+ newf->orig_index = -1;
+
+ newf->col = PyList_New( 0 );
+
+ return newf;
+}
+
+/* RATHER EVIL FUNCTION BORROWED FROM fix_faceindices IN editmesh.c */
+static void correctFaceIndex(int vidx[4])
+{
+ if (vidx[3]) {
+ if (vidx[1] == 0) {
+ vidx[1] = vidx[2];
+ vidx[2] = vidx[3];
+ vidx[3] = vidx[0];
+ vidx[0] = 0;
+ }
+ if (vidx[2] == 0) {
+ int t = vidx[1];
+ vidx[2] = vidx[0];
+ vidx[1] = vidx[3];
+ vidx[3] = t;
+ vidx[0] = 0;
+ }
+ if (vidx[3] == 0) {
+ vidx[3] = vidx[2];
+ vidx[2] = vidx[1];
+ vidx[1] = vidx[0];
+ vidx[0] = 0;
+ }
+ }
+ else if (vidx[1] == 0) {
+ vidx[1] = vidx[2];
+ vidx[2] = vidx[0];
+ vidx[0] = 0;
+ }
+ else if (vidx[2] == 0) {
+ vidx[2] = vidx[1];
+ vidx[1] = vidx[0];
+ vidx[0] = 0;
+ }
+}
+
+/*
+ CREATES A NMESH FROM DISPLIST DATA. INSPIRED BY THE FUNCTIONS CALLED WHEN
+ CONVERTING OBJECTS TO MESH.
+ */
+static PyObject *new_NMesh_displist(ListBase *lb, Object *ob)
+{
+ BPy_NMesh *me;
+ DispList *dl;
+ float *data, *ndata;
+ float normal[3] = {1, 0, 0};
+ int vidx[4];
+ int parts, p1, p2, p3, p4, a, b, one_normal=0, ioffset=0;
+ int *index;
+
+ /* Note: This routine does not create new edges for the faces
+ * it adds... should be fixed for consistency.
+ */
+
+ if (ob->type == OB_CURVE || ob->type == OB_FONT)
+ one_normal = 1;
+
+ me = PyObject_NEW( BPy_NMesh, &NMesh_Type );
+ me->name = EXPP_incr_ret( Py_None );
+ me->flags = 0;
+ me->mode = ME_TWOSIDED; /* default for new meshes */
+ me->subdiv[0] = NMESH_SUBDIV;
+ me->subdiv[1] = NMESH_SUBDIV;
+ me->smoothresh = NMESH_SMOOTHRESH;
+ me->edges = PyList_New( 0 );
+
+ me->object = ob;
+ me->materials = EXPP_PyList_fromMaterialList( ob->mat, ob->totcol, 0 );
+
+ me->verts = PyList_New( 0 );
+ me->faces = PyList_New( 0 );
+
+ memset(&me->fdata, 0, sizeof(me->fdata));
+ me->totfdata = 0;
+
+ dl= lb->first;
+ while(dl) {
+ parts= dl->parts;
+ index= dl->index;
+ data= dl->verts;
+ ndata= dl->nors;
+
+ switch(dl->type) {
+ case DL_SEGM:
+ for(a=0; a<dl->parts*dl->nr; a++, data+=3) {
+ PyList_Append(me->verts, ( PyObject * ) nmvert_from_float(data, normal, a));
+ }
+
+ vidx[2] = vidx[3] = 0;
+
+ for(a=0; a<dl->parts; a++) {
+ for(b=1; b<dl->nr; b++) {
+ int v0 = ioffset + a * dl->nr + b-1;
+ int v1 = ioffset + a * dl->nr + b;
+ PyList_Append(me->edges, ( PyObject * ) nmedge_from_index(me, v0, v1));
+ }
+ }
+ ioffset += dl->parts * dl->nr;
+ break;
+ case DL_POLY:
+ for(a=0; a<dl->parts*dl->nr; a++, data+=3) {
+ PyList_Append(me->verts, ( PyObject * ) nmvert_from_float(data, normal, a));
+ }
+
+ vidx[2] = vidx[3] = 0;
+
+ for(a=0; a<dl->parts; a++) {
+ for(b=0; b<dl->nr; b++) {
+ int v1, v0 = ioffset + a * dl->nr + b;
+ if(b==dl->nr-1) v1 = ioffset + a * dl->nr;
+ else v1= ioffset + a * dl->nr + b+1;
+ PyList_Append(me->edges, ( PyObject * ) nmedge_from_index(me, v0, v1));
+ }
+ }
+ ioffset += dl->parts * dl->nr;
+ break;
+ case DL_SURF:
+ for(a=0; a<dl->parts*dl->nr; a++, data+=3, ndata+=3) {
+ PyList_Append(me->verts, ( PyObject * ) nmvert_from_float(data, ndata, a));
+ }
+
+ for(a=0; a<dl->parts; a++) {
+
+ DL_SURFINDEX(dl->flag & DL_CYCL_U, dl->flag & DL_CYCL_V, dl->nr, dl->parts);
+
+
+ for(; b<dl->nr; b++) {
+ vidx[0] = p2 + ioffset;
+ vidx[1] = p1 + ioffset;
+ vidx[2] = p3 + ioffset;
+ vidx[3] = p4 + ioffset;
+ correctFaceIndex(vidx);
+
+ PyList_Append(me->faces, ( PyObject * ) nmface_from_index(me, vidx, (char)dl->col));
+
+ p2 = p1;
+ p4 = p3;
+ p1++;
+ p3++;
+ }
+ }
+ ioffset += dl->parts * dl->nr;
+ break;
+
+ case DL_INDEX3:
+ if (one_normal)
+ for(a=0; a<dl->nr; a++, data+=3)
+ PyList_Append(me->verts, ( PyObject * ) nmvert_from_float(data, ndata, a));
+ else
+ for(a=0; a<dl->nr; a++, data+=3, ndata+=3)
+ PyList_Append(me->verts, ( PyObject * ) nmvert_from_float(data, ndata, a));
+
+ while(parts--) {
+ vidx[0] = index[0] + ioffset;
+ vidx[1] = index[1] + ioffset;
+ vidx[2] = index[2] + ioffset;
+ vidx[3] = 0;
+ correctFaceIndex(vidx);
+
+ PyList_Append(me->faces, ( PyObject * ) nmface_from_index(me, vidx, (char)dl->col));
+ index+= 3;
+ }
+ ioffset += dl->nr;
+
+ break;
+
+ case DL_INDEX4:
+ for(a=0; a<dl->nr; a++, data+=3, ndata+=3) {
+ PyList_Append(me->verts, ( PyObject * ) nmvert_from_float(data, ndata, a));
+ }
+
+ while(parts--) {
+ vidx[0] = index[0] + ioffset;
+ vidx[1] = index[1] + ioffset;
+ vidx[2] = index[2] + ioffset;
+ vidx[3] = index[3] + ioffset;
+ correctFaceIndex(vidx);
+
+ PyList_Append(me->faces, ( PyObject * ) nmface_from_index(me, vidx, (char)dl->col));
+ index+= 4;
+ }
+ ioffset += dl->nr;
+ break;
+ }
+ dl= dl->next;
+ }
+
+ return ( PyObject * ) me;
+}
+
+static PyObject *new_NMesh_internal( Mesh * oldmesh,
+ DerivedMesh *dm )
+{
+ BPy_NMesh *me = PyObject_NEW( BPy_NMesh, &NMesh_Type );
+ me->flags = 0;
+ me->mode = ME_TWOSIDED; /* default for new meshes */
+ me->subdiv[0] = NMESH_SUBDIV;
+ me->subdiv[1] = NMESH_SUBDIV;
+ me->smoothresh = NMESH_SMOOTHRESH;
+
+ me->object = NULL; /* not linked to any object yet */
+
+ if( !oldmesh ) {
+ me->name = EXPP_incr_ret( Py_None );
+ me->materials = PyList_New( 0 );
+ me->verts = PyList_New( 0 );
+ me->edges = PyList_New( 0 );
+ me->faces = PyList_New( 0 );
+ me->mesh = 0;
+ memset(&me->fdata, 0, sizeof(me->fdata));
+ me->totfdata = 0;
+ } else {
+ MVert *mverts;
+ MSticky *msticky;
+ MFace *mfaces;
+ MTFace *tfaces;
+ MCol *mcols;
+ MEdge *medges;
+ CustomData *fdata;
+ int i, totvert, totface, totedge;
+
+ me->name = PyString_FromString( oldmesh->id.name + 2 );
+ me->mesh = oldmesh;
+ me->mode = oldmesh->flag; /* yes, we save the mesh flags in nmesh->mode */
+ me->subdiv[0] = oldmesh->subdiv;
+ me->subdiv[1] = oldmesh->subdivr;
+ me->smoothresh = oldmesh->smoothresh;
+
+ me->sel_face = get_active_faceindex( oldmesh );
+
+ if( dm ) {
+ msticky = NULL;
+ mverts = dm->getVertArray(dm);
+ mfaces = dm->getFaceArray(dm);
+ tfaces = dm->getFaceDataArray(dm, CD_MTFACE);
+ mcols = dm->getFaceDataArray(dm, CD_MCOL);
+ medges = dm->getEdgeArray(dm);
+ fdata = &dm->faceData;
+
+ totvert = dm->getNumVerts(dm);
+ totedge = dm->getNumEdges(dm);
+ totface = dm->getNumFaces(dm);;
+ } else {
+ msticky = oldmesh->msticky;
+ mverts = oldmesh->mvert;
+ mfaces = oldmesh->mface;
+ tfaces = oldmesh->mtface;
+ mcols = oldmesh->mcol;
+ medges = oldmesh->medge;
+ fdata = &oldmesh->fdata;
+
+ totvert = oldmesh->totvert;
+ totface = oldmesh->totface;
+ totedge = oldmesh->totedge;
+ }
+
+ /* copy non active mcol and mtface layers, these can't be edited
+ but will be preserved */
+ CustomData_copy( fdata, &me->fdata, CD_MASK_MCOL|CD_MASK_MTFACE,
+ CD_DUPLICATE, totface );
+ me->totfdata = totface;
+
+ if( msticky )
+ me->flags |= NMESH_HASVERTUV;
+ if( tfaces )
+ me->flags |= NMESH_HASFACEUV;
+ if( mcols )
+ me->flags |= NMESH_HASMCOL;
+
+ me->verts = PyList_New( totvert );
+
+ for( i = 0; i < totvert; i++ ) {
+ MVert *oldmv = &mverts[i];
+ MSticky *oldst = msticky ? &msticky[i] : NULL;
+
+ PyList_SetItem( me->verts, i,
+ ( PyObject * ) nmvert_from_data( oldmv,
+ oldst,
+ oldmv->co,
+ i,
+ oldmv->flag ) );
+ }
+
+ me->faces = PyList_New( totface );
+ for( i = 0; i < totface; i++ ) {
+ MTFace *oldtf = tfaces ? &tfaces[i] : NULL;
+ MCol *oldmc = mcols ? &mcols[i * 4] : NULL;
+ MFace *oldmf = &mfaces[i];
+ int vidxs[4];
+ vidxs[0] = oldmf->v1;
+ vidxs[1] = oldmf->v2;
+ vidxs[2] = oldmf->v3;
+ vidxs[3] = oldmf->v4;
+
+ PyList_SetItem( me->faces, i,
+ ( PyObject * ) nmface_from_data( me,
+ vidxs,
+ oldmf->
+ mat_nr,
+ oldmf->
+ flag,
+ oldtf,
+ oldmc,
+ i) );
+ }
+
+ me->edges = PyList_New( totedge );
+ for( i = 0; i < totedge; i++ )
+ {
+ MEdge *edge = &medges[i];
+ PyList_SetItem( me->edges, i, (PyObject*)nmedge_from_data ( me, edge ) );
+ }
+
+ me->materials = EXPP_PyList_fromMaterialList( oldmesh->mat, oldmesh->totcol, 0 );
+ }
+
+ return ( PyObject * ) me;
+}
+
+PyObject *new_NMesh( Mesh * oldmesh )
+{
+ return new_NMesh_internal( oldmesh, NULL );
+}
+
+static PyObject *M_NMesh_New( PyObject * self, PyObject * args )
+{
+ char *name = NULL;
+ PyObject *ret = NULL;
+
+ if( !PyArg_ParseTuple( args, "|s", &name ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected nothing or a string as argument" );
+
+ ret = new_NMesh( NULL );
+
+ if( ret && name ) {
+ BPy_NMesh *nmesh = ( BPy_NMesh * ) ret;
+ Py_DECREF( nmesh->name );
+ nmesh->name = PyString_FromString( name );
+ }
+
+ return ret;
+}
+
+static PyObject *M_NMesh_GetRaw( PyObject * self, PyObject * args )
+{
+ char *name = NULL;
+ Mesh *oldmesh = NULL;
+
+ if( !PyArg_ParseTuple( args, "|s", &name ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument (or nothing)" );
+
+ if( name ) {
+ oldmesh = ( Mesh * ) GetIdFromList( &( G.main->mesh ), name );
+
+ if( !oldmesh )
+ return EXPP_incr_ret( Py_None );
+ }
+
+ return new_NMesh( oldmesh );
+}
+
+static PyObject *M_NMesh_GetNames(PyObject *self)
+{
+ PyObject *names = PyList_New(0), *tmpstr;
+ Mesh *me = G.main->mesh.first;
+
+ while (me) {
+ tmpstr = PyString_FromString(me->id.name+2);
+ PyList_Append(names, tmpstr);
+ Py_DECREF(tmpstr);
+ me = me->id.next;
+ }
+
+ return names;
+}
+
+/* Note: NMesh.GetRawFromObject gets the display list mesh from Blender:
+ * the vertices are already transformed / deformed. */
+static PyObject *M_NMesh_GetRawFromObject( PyObject * self, PyObject * args )
+{
+ Object *ob;
+ PyObject *nmesh;
+ ListBase *lb=0;
+ DispList *dl;
+ char *name;
+
+ if( !PyArg_ParseTuple( args, "s", &name ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument" );
+
+ ob = ( Object * ) GetIdFromList( &( G.main->object ), name );
+
+ if( !ob )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError, name );
+
+
+ switch (ob->type) {
+ case OB_MBALL:
+ if( is_basis_mball(ob)) {
+ lb= &ob->disp;
+ if(lb->first==0) makeDispListMBall(ob);
+ nmesh = new_NMesh_displist(lb, ob);
+ }
+ else {
+ return EXPP_ReturnPyObjError( PyExc_AttributeError, "Object does not have geometry data" );
+ }
+ break;
+ case OB_FONT:
+ case OB_CURVE:
+ {
+ Curve *cu= ob->data;
+
+ lb= &cu->disp;
+ if(lb->first==0) makeDispListCurveTypes(ob, 0);
+
+ dl= lb->first;
+ if(dl==0)
+ return EXPP_ReturnPyObjError( PyExc_AttributeError, "Object does not have geometry data" );
+
+ if(dl->nors==0) addnormalsDispList(ob, lb);
+
+ nmesh = new_NMesh_displist(lb, ob);
+ }
+ break;
+ case OB_SURF:
+
+ lb= &((Curve *)ob->data)->disp;
+ if(lb->first==0) makeDispListCurveTypes(ob, 0);
+
+ dl= lb->first;
+ if(dl==0)
+ return EXPP_ReturnPyObjError( PyExc_AttributeError, "Object does not have geometry data" );
+
+ if(dl->nors==0) addnormalsDispList(ob, lb);
+ nmesh = new_NMesh_displist(lb, ob);
+
+ break;
+ case OB_MESH:
+ {
+ CustomDataMask dataMask = CD_MASK_BAREMESH | CD_MASK_MTFACE
+ | CD_MASK_MCOL;
+ DerivedMesh *dm = mesh_create_derived_render( ob, dataMask );
+ nmesh = new_NMesh_internal( ob->data, dm );
+ dm->release(dm);
+ }
+ break;
+ default:
+ return EXPP_ReturnPyObjError( PyExc_AttributeError, "Object does not have geometry data" );
+ }
+
+/* @hack: to mark that (deformed) mesh is readonly, so the update function
+ * will not try to write it. */
+
+ ( ( BPy_NMesh * ) nmesh )->mesh = 0;
+
+ return nmesh;
+}
+
+static void mvert_from_data( MVert * mv, MSticky * st, BPy_NMVert * from )
+{
+ mv->co[0] = from->co[0];
+ mv->co[1] = from->co[1];
+ mv->co[2] = from->co[2];
+
+ mv->no[0] = (short)(from->no[0] * 32767.0);
+ mv->no[1] = (short)(from->no[1] * 32767.0);
+ mv->no[2] = (short)(from->no[2] * 32767.0);
+
+ mv->flag = ( from->flag & 1 );
+ mv->mat_nr = 0;
+
+ if( st ) {
+ st->co[0] = from->uvco[0];
+ st->co[1] = from->uvco[1];
+ }
+}
+
+static int assignFaceUV( MTFace * tf, BPy_NMFace * nmface )
+{
+ PyObject *fuv, *tmp;
+ int i;
+ int len;
+
+ fuv = nmface->uv;
+ /* if no UV info, allows things to proceed as normal */
+ if( PySequence_Length( fuv ) == 0 ) {
+ tf->uv[0][0] = 0.0f; tf->uv[0][1] = 1.0f;
+ tf->uv[1][0] = 0.0f; tf->uv[1][1] = 0.0f;
+ tf->uv[2][0] = 1.0f; tf->uv[2][1] = 0.0f;
+ tf->uv[3][1] = 1.0f; tf->uv[3][1] = 1.0f;
+ return 1;
+ }
+
+ /* if there are too many uv coordinates, only take the first 4 */
+ len = PySequence_Length( fuv );
+ if( len > 4 )
+ len = 4;
+
+ /* fuv = [(u_1, v_1), ... (u_n, v_n)] */
+ for( i = 0; i < len; i++ ) {
+ tmp = PyList_GetItem( fuv, i ); /* stolen reference ! */
+ if( !PyArg_ParseTuple
+ ( tmp, "ff", &( tf->uv[i][0] ), &( tf->uv[i][1] ) ) ) {
+ PyErr_SetString ( PyExc_TypeError,
+ "expected tuple of two floats for uv" );
+ return 0;
+ }
+ }
+ if( nmface->image ) { /* image assigned ? */
+ tf->tpage = ( void * ) nmface->image;
+ } else
+ tf->tpage = 0;
+
+ tf->mode = nmface->mode; /* copy mode */
+ tf->flag = (char)nmface->flag; /* copy flag */
+ tf->transp = nmface->transp; /* copy transp flag */
+
+ return 1;
+}
+
+static int mface_from_data( MFace * mf, CustomData *fdata, int findex,
+ BPy_NMFace * from )
+{
+ BPy_NMVert *nmv;
+ MTFace *tf = CustomData_get(fdata, findex, CD_MTFACE);
+ MCol *col = CustomData_get(fdata, findex, CD_MCOL);
+
+ int numverts = PyList_Size( from->v );
+ if( numverts != 3 && numverts != 4 ) { /* face can only have three or four verts */
+ PyErr_SetString ( PyExc_RuntimeError,
+ "faces must have at 3 or 4 vertices" );
+ return 0;
+ }
+
+ nmv = ( BPy_NMVert * ) PyList_GetItem( from->v, 0 );
+ if( BPy_NMVert_Check( nmv ) && nmv->index != -1 )
+ mf->v1 = nmv->index;
+ else
+ mf->v1 = 0;
+
+ nmv = ( BPy_NMVert * ) PyList_GetItem( from->v, 1 );
+ if( BPy_NMVert_Check( nmv ) && nmv->index != -1 )
+ mf->v2 = nmv->index;
+ else
+ mf->v2 = 0;
+
+ nmv = ( BPy_NMVert * ) PyList_GetItem( from->v, 2 );
+ if( BPy_NMVert_Check( nmv ) && nmv->index != -1 )
+ mf->v3 = nmv->index;
+ else
+ mf->v3 = 0;
+
+ if( numverts == 4 ) {
+ nmv = ( BPy_NMVert * ) PyList_GetItem( from->v, 3 );
+ if( BPy_NMVert_Check( nmv ) && nmv->index != -1 )
+ mf->v4 = nmv->index;
+ else
+ mf->v4 = 0;
+ }
+
+ if( tf )
+ if( !assignFaceUV( tf, from ) )
+ return 0;
+
+ mf->mat_nr = from->mat_nr;
+ mf->flag = from->mf_flag;
+
+ if( col ) {
+ int i, len = PySequence_Length( from->col );
+
+ if( len > 4 )
+ len = 4;
+
+ for( i = 0; i < len; i++, col++ ) {
+ BPy_NMCol *mc =
+ ( BPy_NMCol * ) PySequence_GetItem( from->col,
+ i );
+ if( !BPy_NMCol_Check( mc ) ) {
+ Py_DECREF( mc );
+ continue;
+ }
+
+ col->b = mc->r;
+ col->g = mc->g;
+ col->r = mc->b;
+ col->a = mc->a;
+
+ Py_DECREF( mc );
+ }
+ }
+
+ test_index_face(mf, fdata, findex, numverts);
+
+ return 1;
+}
+
+/* check for a valid UV sequence */
+static int check_validFaceUV( BPy_NMesh * nmesh )
+{
+ PyObject *faces;
+ BPy_NMFace *nmface;
+ int i, n;
+
+ faces = nmesh->faces;
+ for( i = 0; i < PySequence_Length( faces ); i++ ) {
+ nmface = ( BPy_NMFace * ) PyList_GetItem( faces, i );
+ n = PySequence_Length( nmface->uv );
+ if( n != PySequence_Length( nmface->v ) ) {
+ if( n > 0 )
+ printf( "Warning: different length of vertex and UV coordinate " "list in face!\n" );
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/* this is a copy of unlink_mesh in mesh.c, because ... */
+static void EXPP_unlink_mesh( Mesh * me )
+{
+ int a;
+
+ if( me == 0 )
+ return;
+
+ for( a = 0; a < me->totcol; a++ ) {
+ if( me->mat[a] )
+ me->mat[a]->id.us--;
+ me->mat[a] = 0;
+ }
+
+/* ... here we want to preserve mesh keys */
+/* if users want to get rid of them, they can use mesh.removeAllKeys() */
+/*
+ if(me->key) me->key->id.us--;
+ me->key= 0;
+*/
+ if( me->texcomesh )
+ me->texcomesh = 0;
+
+ me->totcol = 0;
+}
+
+static int unlink_existingMeshData( Mesh * mesh )
+{
+ MDeformVert *dvert= NULL;
+
+ EXPP_unlink_mesh( mesh );
+
+ if(mesh->dvert) {
+ /* we don't want to remove dvert here, check_dverts still needs it */
+ dvert= mesh->dvert;
+ CustomData_set_layer( &mesh->vdata, CD_MDEFORMVERT, NULL );
+ }
+
+ CustomData_free( &mesh->vdata, mesh->totvert );
+ CustomData_free( &mesh->edata, mesh->totedge );
+ CustomData_free( &mesh->fdata, mesh->totface );
+ mesh_update_customdata_pointers( mesh );
+
+ if(dvert)
+ mesh->dvert= CustomData_add_layer( &mesh->vdata, CD_MDEFORMVERT,
+ CD_ASSIGN, dvert, mesh->totvert );
+
+ mesh->totedge = 0;
+
+ if( mesh->mat ) {
+ MEM_freeN( mesh->mat );
+ mesh->mat = NULL;
+ }
+
+ return 1;
+}
+
+Material **nmesh_updateMaterials( BPy_NMesh * nmesh )
+{
+ Material **matlist;
+ Mesh *mesh = nmesh->mesh;
+ int len = PyList_Size( nmesh->materials );
+
+ if( !mesh ) {
+ printf( "FATAL INTERNAL ERROR: illegal call to updateMaterials()\n" );
+ return 0;
+ }
+
+ if( len > 0 ) {
+ matlist = EXPP_newMaterialList_fromPyList( nmesh->materials );
+ EXPP_incr_mats_us( matlist, len );
+
+ if( mesh->mat )
+ MEM_freeN( mesh->mat );
+
+ mesh->mat = matlist;
+
+ } else {
+ matlist = 0;
+ }
+ mesh->totcol = (short)len;
+
+/**@ This is another ugly fix due to the weird material handling of blender.
+ * it makes sure that object material lists get updated (by their length)
+ * according to their data material lists, otherwise blender crashes.
+ * It just stupidly runs through all objects...BAD BAD BAD.
+ */
+ test_object_materials( ( ID * ) mesh );
+
+ return matlist;
+}
+
+PyObject *NMesh_assignMaterials_toObject( BPy_NMesh * nmesh, Object * ob )
+{
+ BPy_Material *pymat;
+ Material *ma;
+ int i;
+ short old_matmask;
+ Mesh *mesh = nmesh->mesh;
+ int nmats; /* number of mats == len(nmesh->materials) */
+
+ old_matmask = ob->colbits; /*@ HACK: save previous colbits */
+ ob->colbits = 0; /* make assign_material work on mesh linked material */
+
+ nmats = PyList_Size( nmesh->materials );
+
+ if( nmats > 0 && !mesh->mat ) {
+ ob->totcol = (char)nmats;
+ mesh->totcol = (short)nmats;
+ mesh->mat =
+ MEM_callocN( sizeof( void * ) * nmats, "bpy_memats" );
+
+ if( ob->mat )
+ MEM_freeN( ob->mat );
+ ob->mat =
+ MEM_callocN( sizeof( void * ) * nmats, "bpy_obmats" );
+ }
+
+ for( i = 0; i < nmats; i++ ) {
+ pymat = ( BPy_Material * ) PySequence_GetItem( nmesh->
+ materials, i );
+
+ if( BPy_Material_Check( ( PyObject * ) pymat ) ) {
+ ma = pymat->material;
+ assign_material( ob, ma, i + 1 ); /*@ XXX don't use this function anymore */
+ } else {
+ Py_DECREF( pymat );
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected Material type in attribute list 'materials'!" );
+ }
+
+ Py_DECREF( pymat );
+ }
+
+ ob->colbits = old_matmask; /*@ HACK */
+
+ ob->actcol = 1;
+ Py_RETURN_NONE;
+}
+
+static void fill_medge_from_nmesh(Mesh * mesh, BPy_NMesh * nmesh)
+{
+ int i,j;
+ MEdge *faces_edges=NULL;
+ int tot_faces_edges=0;
+ int tot_valid_faces_edges=0;
+ int nmeshtotedges=PyList_Size(nmesh->edges);
+ int tot_valid_nmedges=0;
+ BPy_NMEdge **valid_nmedges=NULL;
+
+ valid_nmedges=MEM_callocN(nmeshtotedges*sizeof(BPy_NMEdge *), "make BPy_NMEdge");
+
+ /* First compute the list of edges that exists because faces exists */
+ make_edges(mesh, 0); /* 0 = draw all edges */
+
+ faces_edges=mesh->medge;
+ tot_faces_edges=mesh->totedge;
+ tot_valid_faces_edges=tot_faces_edges;
+
+ mesh->medge= CustomData_set_layer(&mesh->edata, CD_MEDGE, NULL);
+ CustomData_free_layer_active(&mesh->edata, CD_MEDGE, mesh->totedge);
+ mesh->totedge = 0;
+
+ /* Flag each edge in faces_edges that is already in nmesh->edges list.
+ * Flaging an edge means MEdge v1=v2=0.
+ * Each time an edge is flagged, tot_valid_faces_edges is decremented.
+ *
+ * Also store in valid_nmedges pointers to each valid NMEdge in nmesh->edges.
+ * An invalid NMEdge is an edge that has a vertex that is not in the vertices
+ * list. Ie its index is -1.
+ * Each time an valid NMEdge is flagged, tot_valid_nmedges is incremented.
+ */
+ for( i = 0; i < nmeshtotedges; ++i )
+ {
+ int v1idx,v2idx;
+ BPy_NMEdge *edge=( BPy_NMEdge *) PyList_GetItem(nmesh->edges, i);
+ BPy_NMVert *v=(BPy_NMVert *)edge->v1;
+ v1idx=v->index;
+ v=(BPy_NMVert *)edge->v2;
+ v2idx=v->index;
+ if (-1 == v1idx || -1 == v2idx) continue;
+ valid_nmedges[tot_valid_nmedges]=edge;
+ ++tot_valid_nmedges;
+ for( j = 0; j < tot_faces_edges; j++ )
+ {
+ MEdge *me=faces_edges+j;
+ if ( ((int)me->v1==v1idx && (int)me->v2==v2idx) ||
+ ((int)me->v1==v2idx && (int)me->v2==v1idx) )
+ {
+ me->v1=0; me->v2=0;
+ --tot_valid_faces_edges;
+ }
+ }
+ }
+
+ /* tot_valid_faces_edges < 0 causes a sigsegv crash, so we
+ * clamp to prevent it
+ * (this is related to faces (correctly) requiring at least 3 verts now,
+ * which can break old scripts -- maybe we should also warn about the
+ * 'broken' mesh the user created, but for now, until we investigate
+ * better, this should do) */
+ if (tot_valid_faces_edges < 0) tot_valid_faces_edges = 0;
+
+ /* Now we have the total count of valid edges */
+ mesh->totedge=tot_valid_nmedges+tot_valid_faces_edges;
+ mesh->medge= CustomData_add_layer( &mesh->edata, CD_MEDGE, CD_CALLOC, NULL,
+ mesh->totedge );
+
+ for ( i = 0; i < tot_valid_nmedges; ++i )
+ {
+ BPy_NMEdge *edge=valid_nmedges[i];
+ MEdge *medge=mesh->medge+i;
+ int v1=((BPy_NMVert *)edge->v1)->index;
+ int v2=((BPy_NMVert *)edge->v2)->index;
+ medge->v1=v1;
+ medge->v2=v2;
+ medge->flag=edge->flag;
+ medge->crease=edge->crease;
+ }
+ for ( i = 0, j = tot_valid_nmedges; i < tot_faces_edges; ++i )
+ {
+ MEdge *edge=faces_edges+i;
+ if (edge->v1!=0 || edge->v2!=0) // valid edge
+ {
+ MEdge *medge=mesh->medge+j;
+ medge->v1=edge->v1;
+ medge->v2=edge->v2;
+ medge->flag=ME_EDGEDRAW|ME_EDGERENDER;
+ medge->crease=0;
+ ++j;
+ }
+ }
+
+ MEM_freeN( valid_nmedges );
+ MEM_freeN( faces_edges );
+}
+
+/* this should ensure meshes don't end up with wrongly sized
+ * me->dvert arrays, which can cause hangs; it's not ideal,
+ * it's better to wrap dverts in NMesh, but it should do for now
+ * since there are also methods in NMesh to edit dverts in the actual
+ * mesh in Blender and anyway this is memory friendly */
+static void check_dverts(Mesh *me, int old_totvert)
+{
+ int totvert = me->totvert;
+
+ /* if vert count didn't change or there are no dverts, all is fine */
+ if ((totvert == old_totvert) || (!me->dvert)) return;
+ /* if all verts have been deleted, free old dverts */
+ else if (totvert == 0) {
+ CustomData_free_layer_active( &me->vdata, CD_MDEFORMVERT, old_totvert );
+ me->dvert= NULL;
+ }
+ else {
+ /* verts added or removed, make new me->dvert */
+ MDeformVert *mdv = MEM_callocN( sizeof(MDeformVert)*totvert, "mdv" );
+ copy_dverts( mdv, me->dvert, MIN2( old_totvert, totvert ) );
+ free_dverts( me->dvert, old_totvert );
+ me->dvert= CustomData_set_layer( &me->vdata, CD_MDEFORMVERT, mdv );
+ }
+}
+
+static void check_mtface_mcols( BPy_NMesh *nmesh, Mesh *mesh )
+{
+ int i;
+
+ /* copy non-active mcol and mtface layers based on original index */
+ CustomData_merge( &nmesh->fdata, &mesh->fdata, CD_MASK_MCOL|CD_MASK_MTFACE,
+ CD_DEFAULT, mesh->totface );
+
+ for( i = 0; i < mesh->totface; i++ ) {
+ BPy_NMFace *mf =
+ ( BPy_NMFace * ) PySequence_GetItem( nmesh->faces, i );
+
+ if ( mf->orig_index != -1 )
+ CustomData_copy_data( &nmesh->fdata, &mesh->fdata, mf->orig_index,
+ i, 1 );
+
+ Py_DECREF( mf );
+ }
+
+ /* add new layers if needed */
+ if( ( nmesh->flags & NMESH_HASMCOL ) &&
+ !CustomData_has_layer( &mesh->fdata, CD_MCOL ) ) {
+ mesh->mcol = CustomData_add_layer( &mesh->fdata, CD_MCOL,
+ CD_DEFAULT, NULL, mesh->totface );
+ }
+
+ if( ( nmesh->flags & NMESH_HASFACEUV ) || check_validFaceUV( nmesh ) ) {
+ if ( !CustomData_has_layer( &mesh->fdata, CD_MTFACE) )
+ make_tfaces( mesh );
+ nmesh->flags |= NMESH_HASFACEUV;
+ }
+ else
+ CustomData_free_layers( &mesh->fdata, CD_MTFACE, mesh->totface );
+
+ /* active uvs and colors from NMFace will be written in mface_from_data */
+}
+
+static int convert_NMeshToMesh( Mesh * mesh, BPy_NMesh * nmesh)
+{
+ MFace *newmf;
+ MVert *newmv;
+ MSticky *newst;
+ int nmeshtotedges;
+ int i, j, ok;
+
+ /* Minor note: we used 'mode' because 'flag' was already used internally
+ * by nmesh */
+ mesh->flag = nmesh->mode;
+ mesh->smoothresh = nmesh->smoothresh;
+ mesh->subdiv = nmesh->subdiv[0];
+ mesh->subdivr = nmesh->subdiv[1];
+
+ /*@ material assignment moved to PutRaw */
+ mesh->totvert = PySequence_Length( nmesh->verts );
+ if( mesh->totvert ) {
+ if( nmesh->flags & NMESH_HASVERTUV )
+ mesh->msticky = CustomData_add_layer( &mesh->vdata, CD_MSTICKY,
+ CD_CALLOC, NULL, mesh->totvert );
+
+ mesh->mvert = CustomData_add_layer( &mesh->vdata, CD_MVERT, CD_CALLOC,
+ NULL, mesh->totvert );
+ }
+
+ if( mesh->totvert )
+ mesh->totface = PySequence_Length( nmesh->faces );
+ else
+ mesh->totface = 0;
+
+ if( mesh->totface ) {
+ check_mtface_mcols( nmesh, mesh );
+
+ mesh->mface = CustomData_add_layer( &mesh->fdata, CD_MFACE, CD_CALLOC,
+ NULL, mesh->totface );
+ }
+
+ mesh_update_customdata_pointers( mesh );
+
+ /*@ This stuff here is to tag all the vertices referenced
+ * by faces, then untag the vertices which are actually
+ * in the vert list. Any vertices untagged will be ignored
+ * by the mface_from_data function. It comes from my
+ * screwed up decision to not make faces only store the
+ * index. - Zr
+ */
+ for( i = 0; i < mesh->totface; i++ ) {
+ BPy_NMFace *mf =
+ ( BPy_NMFace * ) PySequence_GetItem( nmesh->faces, i );
+
+ j = PySequence_Length( mf->v );
+ while( j-- ) {
+ BPy_NMVert *mv =
+ ( BPy_NMVert * ) PySequence_GetItem( mf->v,
+ j );
+ if( BPy_NMVert_Check( mv ) )
+ mv->index = -1;
+ Py_DECREF( mv );
+ }
+
+ Py_DECREF( mf );
+ }
+ /* do the same for edges if there is edge data */
+ nmeshtotedges=PyList_Size(nmesh->edges);
+ for( i = 0; i < nmeshtotedges; ++i )
+ {
+ BPy_NMEdge *edge=( BPy_NMEdge *) PyList_GetItem(nmesh->edges, i);
+ BPy_NMVert *v=(BPy_NMVert *)edge->v1;
+ v->index=-1;
+ v=(BPy_NMVert *)edge->v2;
+ v->index=-1;
+ }
+
+ for( i = 0; i < mesh->totvert; i++ ) {
+ BPy_NMVert *mv =
+ ( BPy_NMVert * ) PySequence_GetItem( nmesh->verts, i );
+ mv->index = i;
+ Py_DECREF( mv );
+ }
+
+ newmv = mesh->mvert;
+ newst = mesh->msticky;
+ for( i = 0; i < mesh->totvert; i++ ) {
+ PyObject *mv = PySequence_GetItem( nmesh->verts, i );
+ mvert_from_data( newmv, newst, ( BPy_NMVert * ) mv );
+ Py_DECREF( mv );
+
+ newmv++;
+ if( newst )
+ newst++;
+ }
+
+ newmf = mesh->mface;
+ for( i = 0; i < mesh->totface; i++ ) {
+ PyObject *mf = PySequence_GetItem( nmesh->faces, i );
+ ok = mface_from_data( newmf, &mesh->fdata, i, ( BPy_NMFace * ) mf );
+ Py_DECREF( mf );
+ if( !ok )
+ return 0;
+ newmf++;
+ }
+
+ /* Always do this to ensure no loose edges in faces */
+ fill_medge_from_nmesh(mesh, nmesh);
+
+ return 1;
+}
+
+static PyObject *M_NMesh_PutRaw( PyObject * self, PyObject * args )
+{
+ char *name = NULL;
+ Mesh *mesh = NULL;
+ Object *ob = NULL;
+ BPy_NMesh *nmesh;
+ int recalc_normals = 1;
+ int store_edges = 0;
+ int old_totvert = 0;
+
+ if( !PyArg_ParseTuple( args, "O!|sii",
+ &NMesh_Type, &nmesh, &name, &recalc_normals, &store_edges ) )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected an NMesh object and optionally also a string and two ints" );
+
+ if( check_NMeshLists( nmesh ) )
+ return NULL;
+
+ if( name )
+ mesh = ( Mesh * ) GetIdFromList( &( G.main->mesh ), name );
+
+ if( !mesh || mesh->id.us == 0 ) {
+ ob = add_object( OB_MESH );
+ if( !ob ) {
+ PyErr_SetString( PyExc_RuntimeError,
+ "Fatal: could not create mesh object" );
+ return 0;
+ }
+
+ if( !mesh )
+ mesh = ( Mesh * ) ob->data;
+ else
+ set_mesh( ob, mesh ); // also does id.us++
+
+ nmesh->object = ob; // linking so vgrouping methods know which obj to work on
+ }
+
+ if( name )
+ new_id( &( G.main->mesh ), &mesh->id, name );
+ else if( nmesh->name && nmesh->name != Py_None )
+ new_id( &( G.main->mesh ), &mesh->id,
+ PyString_AsString( nmesh->name ) );
+
+ old_totvert = mesh->totvert;
+
+ unlink_existingMeshData( mesh );
+ if( !convert_NMeshToMesh( mesh, nmesh ) )
+ return NULL;
+ nmesh->mesh = mesh;
+
+ if (mesh->dvert) check_dverts(mesh, old_totvert);
+
+ if( recalc_normals )
+ mesh_calc_normals(mesh->mvert, mesh->totvert, mesh->mface, mesh->totface, NULL);
+
+ mesh_update( mesh, nmesh->object );
+
+ if( !during_script( ) )
+ EXPP_allqueue( REDRAWVIEW3D, 0 );
+
+ if (ob && G.obedit) { /* prevents a crash when a new object is created */
+ exit_editmode(EM_FREEDATA);
+ enter_editmode(0);
+ }
+
+ // @OK...this requires some explanation:
+ // Materials can be assigned two ways:
+ // a) to the object data (in this case, the mesh)
+ // b) to the Object
+ //
+ // Case a) is wanted, if Mesh data should be shared among objects,
+ // as well as its materials (up to 16)
+ // Case b) is wanted, when Mesh data should be shared, but not the
+ // materials. For example, you want several checker boards sharing their
+ // mesh data, but having different colors. So you would assign material
+ // index 0 to all even, index 1 to all odd faces and bind the materials
+ // to the Object instead (MaterialButtons: [OB] "link materials to object")
+ //
+ // This feature implies that pointers to materials can be stored in
+ // an object or a mesh. The number of total materials MUST be
+ // synchronized (ob->totcol <-> mesh->totcol). We avoid the dangerous
+ // direct access by calling blenderkernel/material.c:assign_material().
+
+ // The flags setting the material binding is found in ob->colbits, where
+ // each bit indicates the binding PER MATERIAL
+
+ if( ob ) { // we created a new object
+ NMesh_assignMaterials_toObject( nmesh, ob );
+ EXPP_synchronizeMaterialLists( ob );
+ return Object_CreatePyObject( ob );
+ } else {
+ mesh->mat =
+ EXPP_newMaterialList_fromPyList( nmesh->materials );
+ EXPP_incr_mats_us( mesh->mat,
+ PyList_Size( nmesh->materials ) );
+ Py_RETURN_NONE;
+ }
+
+}
+
+#undef MethodDef
+#define MethodDef(func) \
+ {#func, M_NMesh_##func, METH_VARARGS, M_NMesh_##func##_doc}
+
+static struct PyMethodDef M_NMesh_methods[] = {
+ MethodDef( Col ),
+ MethodDef( Vert ),
+ MethodDef( Face ),
+ MethodDef( New ),
+ MethodDef( GetRaw ),
+ MethodDef( GetRawFromObject ),
+ MethodDef( PutRaw ),
+ {"GetNames", (PyCFunction)M_NMesh_GetNames, METH_NOARGS,
+ M_NMesh_GetNames_doc},
+ {NULL, NULL, 0, NULL}
+};
+
+static PyObject *M_NMesh_Modes( void )
+{
+ PyObject *Modes = PyConstant_New( );
+
+ if( Modes ) {
+ BPy_constant *d = ( BPy_constant * ) Modes;
+
+ PyConstant_Insert( d, "NOVNORMALSFLIP",
+ PyInt_FromLong
+ ( ME_NOPUNOFLIP ) );
+ PyConstant_Insert( d, "TWOSIDED",
+ PyInt_FromLong( ME_TWOSIDED ) );
+ PyConstant_Insert( d, "AUTOSMOOTH",
+ PyInt_FromLong
+ ( ME_AUTOSMOOTH ) );
+ }
+
+ return Modes;
+}
+
+#undef EXPP_ADDCONST
+#define EXPP_ADDCONST(dict, name) \
+ PyConstant_Insert(dict, #name, PyInt_FromLong(TF_##name))
+/* Set constants for face drawing mode -- see drawmesh.c */
+
+static PyObject *M_NMesh_FaceModesDict( void )
+{
+ PyObject *FM = PyConstant_New( );
+
+ if( FM ) {
+ BPy_constant *d = ( BPy_constant * ) FM;
+
+ PyConstant_Insert( d, "BILLBOARD",
+ PyInt_FromLong( TF_BILLBOARD2 ) );
+ PyConstant_Insert( d, "ALL", PyInt_FromLong( 0x7fff ) );
+ PyConstant_Insert( d, "HALO", PyInt_FromLong( TF_BILLBOARD ) );
+ PyConstant_Insert( d, "DYNAMIC", PyInt_FromLong( TF_DYNAMIC ) );
+ PyConstant_Insert( d, "INVISIBLE", PyInt_FromLong( TF_INVISIBLE ) );
+ PyConstant_Insert( d, "LIGHT", PyInt_FromLong( TF_LIGHT ) );
+ PyConstant_Insert( d, "OBCOL", PyInt_FromLong( TF_OBCOL ) );
+ PyConstant_Insert( d, "SHADOW", PyInt_FromLong( TF_SHADOW ) );
+ PyConstant_Insert( d, "TEXT", PyInt_FromLong( TF_BMFONT ) );
+ PyConstant_Insert( d, "SHAREDVERT", PyInt_FromLong( TF_SHAREDVERT ) );
+ PyConstant_Insert( d, "SHAREDCOL", PyInt_FromLong( TF_SHAREDCOL ) );
+ PyConstant_Insert( d, "TEX", PyInt_FromLong( TF_TEX ) );
+ PyConstant_Insert( d, "TILES", PyInt_FromLong( TF_TILES ) );
+ PyConstant_Insert( d, "TWOSIDE", PyInt_FromLong( TF_TWOSIDE ) );
+ }
+
+ return FM;
+}
+
+static PyObject *M_NMesh_FaceFlagsDict( void )
+{
+ PyObject *FF = PyConstant_New( );
+
+ if( FF ) {
+ BPy_constant *d = ( BPy_constant * ) FF;
+
+ EXPP_ADDCONST( d, SELECT );
+ EXPP_ADDCONST( d, HIDE );
+ EXPP_ADDCONST( d, ACTIVE );
+ }
+
+ return FF;
+}
+
+static PyObject *M_NMesh_FaceTranspModesDict( void )
+{
+ PyObject *FTM = PyConstant_New( );
+
+ if( FTM ) {
+ BPy_constant *d = ( BPy_constant * ) FTM;
+
+ EXPP_ADDCONST( d, SOLID );
+ EXPP_ADDCONST( d, ADD );
+ EXPP_ADDCONST( d, ALPHA );
+ EXPP_ADDCONST( d, SUB );
+ }
+
+ return FTM;
+}
+
+static PyObject *M_NMesh_EdgeFlagsDict( void )
+{
+ PyObject *EF = PyConstant_New( );
+
+ if( EF ) {
+ BPy_constant *d = ( BPy_constant * ) EF;
+
+ PyConstant_Insert(d, "SELECT", PyInt_FromLong(1));
+ PyConstant_Insert(d, "EDGEDRAW", PyInt_FromLong(ME_EDGEDRAW));
+ PyConstant_Insert(d, "EDGERENDER", PyInt_FromLong(ME_EDGERENDER));
+ PyConstant_Insert(d, "SEAM", PyInt_FromLong(ME_SEAM));
+ PyConstant_Insert(d, "FGON", PyInt_FromLong(ME_FGON));
+ }
+
+ return EF;
+}
+
+PyObject *NMesh_Init( void )
+{
+ PyObject *submodule;
+
+ PyObject *Modes = M_NMesh_Modes( );
+ PyObject *FaceFlags = M_NMesh_FaceFlagsDict( );
+ PyObject *FaceModes = M_NMesh_FaceModesDict( );
+ PyObject *FaceTranspModes = M_NMesh_FaceTranspModesDict( );
+ PyObject *EdgeFlags = M_NMesh_EdgeFlagsDict( );
+
+ NMCol_Type.ob_type = &PyType_Type;
+ NMFace_Type.ob_type = &PyType_Type;
+ NMVert_Type.ob_type = &PyType_Type;
+ NMesh_Type.ob_type = &PyType_Type;
+
+ submodule =
+ Py_InitModule3( "Blender.NMesh", M_NMesh_methods,
+ M_NMesh_doc );
+
+ if( Modes )
+ PyModule_AddObject( submodule, "Modes", Modes );
+ if( FaceFlags )
+ PyModule_AddObject( submodule, "FaceFlags", FaceFlags );
+ if( FaceModes )
+ PyModule_AddObject( submodule, "FaceModes", FaceModes );
+ if( FaceTranspModes )
+ PyModule_AddObject( submodule, "FaceTranspModes",
+ FaceTranspModes );
+ if( EdgeFlags )
+ PyModule_AddObject( submodule, "EdgeFlags", EdgeFlags );
+
+ g_nmeshmodule = submodule;
+ return submodule;
+}
+
+/* These are needed by Object.c */
+
+PyObject *NMesh_CreatePyObject( Mesh * me, Object * ob )
+{
+ BPy_NMesh *nmesh = ( BPy_NMesh * ) new_NMesh( me );
+
+ if( nmesh )
+ nmesh->object = ob; /* linking nmesh and object for vgrouping methods */
+
+ return ( PyObject * ) nmesh;
+}
+
+int NMesh_CheckPyObject( PyObject * pyobj )
+{
+ return ( pyobj->ob_type == &NMesh_Type );
+}
+
+Mesh *NMesh_FromPyObject( PyObject * pyobj, Object * ob )
+{
+ if( pyobj->ob_type == &NMesh_Type ) {
+ Mesh *mesh;
+ BPy_NMesh *nmesh = ( BPy_NMesh * ) pyobj;
+
+ if( nmesh->mesh ) {
+ mesh = nmesh->mesh;
+ } else {
+ mesh = Mesh_fromNMesh( nmesh );
+ if( !mesh ) /* NULL means an PyError */
+ return NULL;
+
+ nmesh->mesh = mesh;
+
+ nmesh->object = ob; /* linking for vgrouping methods */
+ if( nmesh->name && nmesh->name != Py_None )
+ new_id( &( G.main->mesh ), &mesh->id,
+ PyString_AsString( nmesh->name ) );
+ mesh_update( mesh, nmesh->object );
+ nmesh_updateMaterials( nmesh );
+ }
+ return mesh;
+ }
+
+ PyErr_SetString( PyExc_AttributeError,
+ "link argument type is not supported " );
+ return NULL;
+}
+
+#define POINTER_CROSS_EQ(a1, a2, b1, b2) (((a1)==(b1) && (a2)==(b2)) || ((a1)==(b2) && (a2)==(b1)))
+
+static PyObject *findEdge( BPy_NMesh *nmesh, BPy_NMVert *v1, BPy_NMVert *v2, int create)
+{
+ int i;
+
+ for ( i = 0; i < PyList_Size(nmesh->edges); ++i )
+ {
+ BPy_NMEdge *edge=(BPy_NMEdge*)PyList_GetItem( nmesh->edges, i );
+ if (!BPy_NMEdge_Check(edge)) continue;
+ if ( POINTER_CROSS_EQ((BPy_NMVert*)edge->v1, (BPy_NMVert*)edge->v2, v1, v2) )
+ {
+ return EXPP_incr_ret((PyObject*)edge);
+ }
+ }
+
+ /* if this line is reached, edge has not been found */
+ if (create)
+ {
+ PyObject *newEdge=(PyObject *)new_NMEdge(v1, v2, 0, ME_EDGEDRAW|ME_EDGERENDER);
+ PyList_Append(nmesh->edges, newEdge);
+ return newEdge;
+ }
+ else
+ Py_RETURN_NONE;
+}
+
+static void removeEdge( BPy_NMesh *nmesh, BPy_NMVert *v1, BPy_NMVert *v2, int ununsedOnly)
+{
+ int i,j;
+ BPy_NMEdge *edge=NULL;
+ int edgeUsedByFace=0;
+ int totedge=PyList_Size(nmesh->edges);
+
+ /* find the edge in the edge list */
+ for ( i = 0; i < totedge; ++i )
+ {
+ edge=(BPy_NMEdge*)PyList_GetItem( nmesh->edges, i );
+ if (!BPy_NMEdge_Check(edge)) continue;
+ if ( POINTER_CROSS_EQ((BPy_NMVert*)edge->v1, (BPy_NMVert*)edge->v2, v1, v2) )
+ {
+ break;
+ }
+ }
+
+ if (i==totedge || !edge) // edge not found
+ return;
+
+ for ( j = PyList_Size(nmesh->faces)-1; j >= 0 ; --j )
+ {
+ BPy_NMFace *face=(BPy_NMFace *)PyList_GetItem(nmesh->faces, j);
+ int k, del_face=0;
+ int totv;
+ if (!BPy_NMFace_Check(face)) continue;
+ totv=PyList_Size(face->v);
+ if (totv<2) continue;
+ for ( k = 0; k < totv && !del_face; ++k )
+ {
+ BPy_NMVert *fe_v1=(BPy_NMVert *)PyList_GetItem(face->v, k ? k-1 : totv-1);
+ BPy_NMVert *fe_v2=(BPy_NMVert *)PyList_GetItem(face->v, k);
+ if ( POINTER_CROSS_EQ(v1, v2, fe_v1, fe_v2) )
+ {
+ edgeUsedByFace=1;
+ del_face=1;
+ }
+ }
+ if (del_face && !ununsedOnly)
+ {
+ PySequence_DelItem(nmesh->faces, j);
+ }
+ }
+
+ if (!ununsedOnly || (ununsedOnly && !edgeUsedByFace) )
+ PySequence_DelItem(nmesh->edges, PySequence_Index(nmesh->edges, (PyObject*)edge));
+}
+
+
+static PyObject *NMesh_addEdge( PyObject * self, PyObject * args )
+{
+ BPy_NMesh *bmesh=(BPy_NMesh *)self;
+ BPy_NMVert *v1=NULL, *v2=NULL;
+
+ if (!PyArg_ParseTuple
+ ( args, "O!O!", &NMVert_Type, &v1, &NMVert_Type, &v2 ) ) {
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected NMVert, NMVert" );
+ }
+
+ if (v1==v2)
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "vertices must be different" );
+
+ return findEdge(bmesh, v1, v2, 1);
+}
+
+static PyObject *NMesh_findEdge( PyObject * self, PyObject * args )
+{
+ BPy_NMesh *bmesh=(BPy_NMesh *)self;
+ BPy_NMVert *v1=NULL, *v2=NULL;
+
+ if (!PyArg_ParseTuple
+ ( args, "O!O!", &NMVert_Type, &v1, &NMVert_Type, &v2 ) ) {
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected NMVert, NMVert" );
+ }
+
+ if (v1==v2)
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "vertices must be different" );
+
+ return findEdge(bmesh, v1, v2, 0);
+}
+
+static PyObject *NMesh_removeEdge( PyObject * self, PyObject * args )
+{
+ BPy_NMesh *bmesh=(BPy_NMesh *)self;
+ BPy_NMVert *v1=NULL, *v2=NULL;
+
+ if (!PyArg_ParseTuple
+ ( args, "O!O!", &NMVert_Type, &v1, &NMVert_Type, &v2 ) ) {
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected NMVert, NMVert" );
+ }
+
+ if (v1==v2)
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "vertices must be different" );
+ removeEdge(bmesh, v1, v2, 0);
+
+ Py_RETURN_NONE;
+}
+
+
+static PyObject *NMesh_addFace( PyObject * self, PyObject * args )
+{
+ BPy_NMesh *nmesh=(BPy_NMesh *)self;
+
+ BPy_NMFace *face;
+ int totv=0;
+
+ if (!PyArg_ParseTuple
+ ( args, "O!", &NMFace_Type, &face ) ) {
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected NMFace argument" );
+ }
+
+ totv=PyList_Size(face->v);
+
+ /*
+ * Before edges data exists, having faces with two vertices was
+ * the only way of storing edges not attached to any face.
+ */
+ if (totv!=2)
+ PyList_Append(nmesh->faces, (PyObject*)face);
+
+ if (totv>=2)
+ {
+ /* when totv==2, there is only one edge, when totv==3 there is three edges
+ * and when totv==4 there is four edges.
+ * that's why in the following line totv==2 is a special case */
+ PyObject *edges = PyList_New((totv==2) ? 1 : totv);
+ if (totv==2)
+ {
+ BPy_NMVert *fe_v1=(BPy_NMVert *)PyList_GetItem(face->v, 0);
+ BPy_NMVert *fe_v2=(BPy_NMVert *)PyList_GetItem(face->v, 1);
+ BPy_NMEdge *edge=(BPy_NMEdge *)findEdge(nmesh, fe_v1, fe_v2, 1);
+ PyList_SetItem(edges, 0, (PyObject*)edge); // PyList_SetItem steals the reference
+ }
+ else
+ {
+ int k;
+ for ( k = 0; k < totv; ++k )
+ {
+ BPy_NMVert *fe_v1=(BPy_NMVert *)PyList_GetItem(face->v, k ? k-1 : totv-1);
+ BPy_NMVert *fe_v2=(BPy_NMVert *)PyList_GetItem(face->v, k);
+ BPy_NMEdge *edge=(BPy_NMEdge *)findEdge(nmesh, fe_v1, fe_v2, 1);
+ PyList_SetItem(edges, k, (PyObject*)edge); // PyList_SetItem steals the reference
+ }
+ }
+ return edges;
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *NMesh_removeFace( PyObject * self, PyObject * args )
+{
+ BPy_NMesh *nmesh=(BPy_NMesh *)self;
+
+ BPy_NMFace *face;
+ int totv=0;
+
+ if (!PyArg_ParseTuple
+ ( args, "O!", &NMFace_Type, &face ) ) {
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected NMFace argument" );
+ }
+
+ totv=PyList_Size(face->v);
+
+ {
+ int index=PySequence_Index(nmesh->faces, (PyObject*)face);
+ if (index>=0)
+ PySequence_DelItem(nmesh->faces, index);
+ }
+
+ if (totv>=2)
+ {
+ /* when totv==2, there is only one edge, when totv==3 there is three edges
+ * and when totv==4 there is four edges.
+ * that's why in the following line totv==2 is a special case */
+ if (totv==2)
+ {
+ BPy_NMVert *fe_v1=(BPy_NMVert *)PyList_GetItem(face->v, 0);
+ BPy_NMVert *fe_v2=(BPy_NMVert *)PyList_GetItem(face->v, 1);
+ removeEdge(nmesh, fe_v1, fe_v2, 1);
+ }
+ else
+ {
+ int k;
+ for ( k = 0; k < totv; ++k )
+ {
+ BPy_NMVert *fe_v1=(BPy_NMVert *)PyList_GetItem(face->v, k ? k-1 : totv-1);
+ BPy_NMVert *fe_v2=(BPy_NMVert *)PyList_GetItem(face->v, k);
+ removeEdge(nmesh, fe_v1, fe_v2, 1);
+ }
+ }
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *NMesh_printDebug( PyObject * self )
+{
+ BPy_NMesh *bmesh=(BPy_NMesh *)self;
+
+ Mesh *mesh=bmesh->mesh;
+
+ printf("**Vertices\n");
+ {
+ int i;
+ for (i=0; i<mesh->totvert; ++i)
+ {
+ MVert *v=mesh->mvert+i;
+ double x=v->co[0];
+ double y=v->co[1];
+ double z=v->co[2];
+ printf(" %2d : %.3f %.3f %.3f\n", i, x, y, z);
+ }
+ }
+
+ printf("**Edges\n");
+ {
+ int i;
+ for (i=0; i<mesh->totedge; ++i)
+ {
+ MEdge *e=mesh->medge+i;
+ int v1 = e->v1;
+ int v2 = e->v2;
+ int flag = e->flag;
+ printf(" %2d : %2d %2d flag=%d\n", i, v1, v2, flag);
+ }
+ }
+
+ printf("**Faces\n");
+ {
+ int i;
+ for (i=0; i<mesh->totface; ++i)
+ {
+ MFace *e=((MFace*)(mesh->mface))+i;
+ int v1 = e->v1;
+ int v2 = e->v2;
+ int v3 = e->v3;
+ int v4 = e->v4;
+ printf(" %2d : %2d %2d %2d %2d\n", i, v1, v2, v3, v4);
+ }
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *NMesh_addVertGroup( PyObject * self, PyObject * args )
+{
+ char *groupStr;
+ struct Object *object;
+ PyObject *tempStr;
+
+ if( !PyArg_ParseTuple( args, "s", &groupStr ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument" );
+
+ if( ( ( BPy_NMesh * ) self )->object == NULL )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "mesh must be linked to an object first..." );
+
+ object = ( ( BPy_NMesh * ) self )->object;
+
+ //get clamped name
+ tempStr = PyString_FromStringAndSize( groupStr, 32 );
+ groupStr = PyString_AsString( tempStr );
+
+ add_defgroup_name( object, groupStr );
+
+ EXPP_allqueue( REDRAWBUTSALL, 1 );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *NMesh_removeVertGroup( PyObject * self, PyObject * args )
+{
+ char *groupStr;
+ struct Object *object;
+ int nIndex;
+ bDeformGroup *pGroup;
+
+ if( !PyArg_ParseTuple( args, "s", &groupStr ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument" );
+
+ if( ( ( BPy_NMesh * ) self )->object == NULL )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "mesh must be linked to an object first..." );
+
+ object = ( ( BPy_NMesh * ) self )->object;
+
+ pGroup = get_named_vertexgroup( object, groupStr );
+ if( pGroup == NULL )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "group does not exist!" );
+
+ nIndex = get_defgroup_num( object, pGroup );
+ if( nIndex == -1 )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "no deform groups assigned to mesh" );
+ nIndex++;
+ object->actdef = (unsigned short)nIndex;
+
+ del_defgroup( object );
+
+ EXPP_allqueue( REDRAWBUTSALL, 1 );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *NMesh_assignVertsToGroup( PyObject * self, PyObject * args )
+{
+ //listObject is an integer list of vertex indices to add to group
+ //groupStr = group name
+ //weight is a float defining the weight this group has on this vertex
+ //assignmode = "replace", "add", "subtract"
+ // replace weight - add addition weight to vertex for this group
+ // - remove group influence from this vertex
+ //the function will not like it if your in editmode...
+
+ char *groupStr;
+ char *assignmodeStr = NULL;
+ int nIndex;
+ int assignmode;
+ float weight = 1.0;
+ struct Object *object;
+ bDeformGroup *pGroup;
+ PyObject *listObject;
+ int tempInt;
+ int x;
+
+ if( ( ( BPy_NMesh * ) self )->object == NULL )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "mesh must be linked to an object first..." );
+
+ if( !PyArg_ParseTuple
+ ( args, "sO!fs", &groupStr, &PyList_Type, &listObject, &weight,
+ &assignmodeStr ) ) {
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string, list, float, string arguments" );
+ }
+
+ object = ( ( BPy_NMesh * ) self )->object;
+
+ if( object->data == NULL )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "object contains no data..." );
+
+ pGroup = get_named_vertexgroup( object, groupStr );
+ if( pGroup == NULL )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "group does not exist!" );
+
+ nIndex = get_defgroup_num( object, pGroup );
+ if( nIndex == -1 )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "no deform groups assigned to mesh" );
+
+ if( assignmodeStr == NULL )
+ assignmode = 1; /* default */
+ else if( STREQ( assignmodeStr, "replace" ) )
+ assignmode = 1;
+ else if( STREQ( assignmodeStr, "add" ) )
+ assignmode = 2;
+ else if( STREQ( assignmodeStr, "subtract" ) )
+ assignmode = 3;
+ else
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "bad assignment mode" );
+
+ //makes a set of dVerts corresponding to the mVerts
+ if( !( ( Mesh * ) object->data )->dvert ) {
+ create_dverts( object->data );
+ }
+ //loop list adding verts to group
+ for( x = 0; x < PyList_Size( listObject ); x++ ) {
+ if( !
+ ( PyArg_Parse
+ ( ( PyList_GetItem( listObject, x ) ), "i",
+ &tempInt ) ) ) {
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "python list integer not parseable" );
+ }
+
+ if( tempInt < 0
+ || tempInt >= ( ( Mesh * ) object->data )->totvert ) {
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "bad vertex index in list" );
+ }
+
+ add_vert_defnr( object, nIndex, tempInt, weight, assignmode );
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *NMesh_removeVertsFromGroup( PyObject * self, PyObject * args )
+{
+ //not passing a list will remove all verts from group
+
+ char *groupStr;
+ int nIndex;
+ struct Object *object;
+ bDeformGroup *pGroup;
+ PyObject *listObject;
+ int tempInt;
+ int x, argc;
+
+ /* argc is the number of parameters passed in: 1 (no list given) or 2: */
+ argc = PyObject_Length( args );
+
+ if( !PyArg_ParseTuple
+ ( args, "s|O!", &groupStr, &PyList_Type, &listObject ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string and optional list argument" );
+
+ if( ( ( BPy_NMesh * ) self )->object == NULL )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "mesh must be linked to an object first..." );
+
+ object = ( ( BPy_NMesh * ) self )->object;
+
+ if( object->data == NULL )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "object contains no data..." );
+
+ if( ( !( ( Mesh * ) object->data )->dvert ) )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "this mesh contains no deform vertices...'" );
+
+ pGroup = get_named_vertexgroup( object, groupStr );
+ if( pGroup == NULL )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "group does not exist!" );
+
+ nIndex = get_defgroup_num( object, pGroup );
+ if( nIndex == -1 )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "no deform groups assigned to mesh" );
+
+ if( argc == 1 ) { /* no list given */
+ //enter editmode
+ if( ( G.obedit == 0 ) ) {
+ //set current object
+ BASACT->object = object;
+ G.obedit = BASACT->object;
+ }
+ //set current vertex group
+ nIndex++;
+ object->actdef = (unsigned short)nIndex;
+
+ //clear all dVerts in active group
+ remove_verts_defgroup( 1 );
+
+ //exit editmode
+ G.obedit = 0;
+ } else {
+ if( G.obedit != 0 ) //remove_vert_def_nr doesn't like it if your in editmode
+ G.obedit = 0;
+
+ //loop list adding verts to group
+ for( x = 0; x < PyList_Size( listObject ); x++ ) {
+ if( !
+ ( PyArg_Parse
+ ( ( PyList_GetItem( listObject, x ) ), "i",
+ &tempInt ) ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "python list integer not parseable" );
+
+ if( tempInt < 0
+ || tempInt >=
+ ( ( Mesh * ) object->data )->totvert )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "bad vertex index in list" );
+
+ remove_vert_def_nr( object, nIndex, tempInt );
+ }
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *NMesh_getVertsFromGroup( PyObject * self, PyObject * args )
+{
+ //not passing a list will return all verts from group
+ //passing indecies not part of the group will not return data in pyList
+ //can be used as a index/group check for a vertex
+
+ char *groupStr;
+ int nIndex;
+ int weightRet;
+ struct Object *object;
+ bDeformGroup *pGroup;
+ MVert *mvert;
+ MDeformVert *dvert;
+ float weight;
+ int i, k, l1, l2, count;
+ int num = 0;
+ PyObject *tempVertexList = NULL;
+ PyObject *vertexList;
+ PyObject *listObject;
+ int tempInt;
+ int x;
+
+ listObject = Py_None; //can't use NULL macro because compiler thinks
+ //it's a 0 and we need to check 0 index vertex pos
+ l1 = FALSE;
+ l2 = FALSE;
+ weightRet = 0;
+
+ if( !PyArg_ParseTuple( args, "s|iO!", &groupStr, &weightRet,
+ &PyList_Type, &listObject ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string and optional int and list arguments" );
+
+ if( weightRet < 0 || weightRet > 1 )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "return weights flag must be 0 or 1..." );
+
+ if( ( ( BPy_NMesh * ) self )->object == NULL )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "mesh must be linked to an object first..." );
+
+ object = ( ( BPy_NMesh * ) self )->object;
+
+ if( object->data == NULL )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "object contains no data..." );
+
+ if( ( !( ( Mesh * ) object->data )->dvert ) )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "this mesh contains no deform vertices...'" );
+
+ pGroup = get_named_vertexgroup( object, groupStr );
+ if( pGroup == NULL )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "group does not exist!" );
+
+ nIndex = get_defgroup_num( object, pGroup );
+ if( nIndex == -1 )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "no deform groups assigned to mesh" );
+
+ //temporary list
+ tempVertexList = PyList_New( ( ( Mesh * ) object->data )->totvert );
+ if( tempVertexList == NULL )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "getVertsFromGroup: can't create pylist!" );
+
+ count = 0;
+
+ if( listObject == Py_None ) //do entire group
+ {
+ for( k = 0; k < ( ( Mesh * ) object->data )->totvert; k++ ) {
+ dvert = ( ( Mesh * ) object->data )->dvert + k;
+
+ for( i = 0; i < dvert->totweight; i++ ) {
+ if( dvert->dw[i].def_nr == nIndex ) {
+ mvert = ( ( Mesh * ) object->data )->
+ mvert + k;
+ weight = dvert->dw[i].weight;
+ //printf("index =%3d weight:%10f\n", k, weight);
+
+ if( weightRet == 1 )
+ PyList_SetItem( tempVertexList,
+ count,
+ Py_BuildValue
+ ( "(i,f)", k,
+ weight ) );
+ else if( weightRet == 0 )
+ PyList_SetItem( tempVertexList,
+ count,
+ Py_BuildValue
+ ( "i", k ) );
+
+ count++;
+ }
+ }
+ }
+ } else //do single vertex
+ {
+ //loop list adding verts to group
+ for( x = 0; x < PyList_Size( listObject ); x++ ) {
+ if( !
+ ( PyArg_Parse
+ ( ( PyList_GetItem( listObject, x ) ), "i",
+ &tempInt ) ) ) {
+ Py_DECREF(tempVertexList);
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "python list integer not parseable" );
+ }
+ if( tempInt < 0
+ || tempInt >=
+ ( ( Mesh * ) object->data )->totvert ) {
+ Py_DECREF(tempVertexList);
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "bad vertex index in list" );
+ }
+ num = tempInt;
+ dvert = ( ( Mesh * ) object->data )->dvert + num;
+ for( i = 0; i < dvert->totweight; i++ ) {
+ l1 = TRUE;
+ if( dvert->dw[i].def_nr == nIndex ) {
+ l2 = TRUE;
+ mvert = ( ( Mesh * ) object->data )->
+ mvert + num;
+
+ weight = dvert->dw[i].weight;
+ //printf("index =%3d weight:%10f\n", num, weight);
+
+ if( weightRet == 1 ) {
+ PyList_SetItem( tempVertexList,
+ count,
+ Py_BuildValue
+ ( "(i,f)", num,
+ weight ) );
+ } else if( weightRet == 0 )
+ PyList_SetItem( tempVertexList,
+ count,
+ Py_BuildValue
+ ( "i", num ) );
+
+ count++;
+ }
+ if( l2 == FALSE )
+ printf( "vertex at index %d is not part of passed group...\n", tempInt );
+ }
+ if( l1 == FALSE )
+ printf( "vertex at index %d is not assigned to a vertex group...\n", tempInt );
+
+ l1 = l2 = FALSE; //reset flags
+ }
+ }
+ //only return what we need
+ vertexList = PyList_GetSlice( tempVertexList, 0, count );
+
+ Py_DECREF( tempVertexList );
+
+ return ( vertexList );
+}
+
+static PyObject *NMesh_renameVertGroup( PyObject * self, PyObject * args )
+{
+ char *oldGr = NULL;
+ char *newGr = NULL;
+ bDeformGroup *defGroup = NULL;
+ /*PyObject *tempStr; */
+
+
+ if( !( ( BPy_NMesh * ) self )->object )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "This mesh must be linked to an object" );
+
+ if( !PyArg_ParseTuple( args, "ss", &oldGr, &newGr ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "Expected string & string argument" );
+
+ defGroup =
+ get_named_vertexgroup( ( ( BPy_NMesh * ) self )->object,
+ oldGr );
+ if( defGroup == NULL )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "Couldn't find the expected vertex group" );
+
+ PyOS_snprintf( defGroup->name, 32, newGr );
+ unique_vertexgroup_name( defGroup, ( ( BPy_NMesh * ) self )->object );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *NMesh_getVertGroupNames( PyObject * self )
+{
+ bDeformGroup *defGroup;
+ PyObject *list, *tmpstr;
+
+ if( !( ( BPy_NMesh * ) self )->object )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "This mesh must be linked to an object" );
+
+ list = PyList_New( 0 );
+ for( defGroup = ( ( ( BPy_NMesh * ) self )->object )->defbase.first;
+ defGroup; defGroup = defGroup->next ) {
+
+ tmpstr = PyString_FromString( defGroup->name );
+ if( PyList_Append( list, tmpstr) < 0 ) {
+ Py_XDECREF(list);
+ Py_XDECREF(tmpstr);
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError, "Couldn't add item to list" );
+ }
+ Py_XDECREF(tmpstr);
+ }
+
+ return list;
+}
+
+static PyObject *NMesh_transform (PyObject *self, PyObject *args)
+{
+ BPy_NMesh *nmesh = ( BPy_NMesh * ) self;
+ BPy_NMVert *mv;
+ PyObject *ob1 = NULL;
+ MatrixObject *mat;
+ float vx, vy, vz;
+ int i, recalc_normals = 0;
+
+ if( !PyArg_ParseTuple( args, "O!|i", &matrix_Type, &ob1, &recalc_normals ) )
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected matrix and optionally an int as arguments" ) );
+
+ mat = ( MatrixObject * ) ob1;
+
+ if( mat->colSize != 4 || mat->rowSize != 4 )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "matrix must be a 4x4 transformation matrix\n"
+ "for example as returned by object.getMatrix()" ) );
+
+ /* loop through all the verts and transform locations by the supplied
+ * matrix */
+ for( i = 0; i < PySequence_Length(nmesh->verts); i++ ) {
+ mv = ( BPy_NMVert * ) PySequence_GetItem( nmesh->verts, i );
+ vx = mv->co[0];
+ vy = mv->co[1];
+ vz = mv->co[2];
+
+ /* Mat4MulVecfl(mat->matrix, mv->co); */
+ mv->co[0] = vx*mat->matrix[0][0] + vy*mat->matrix[1][0] +
+ vz*mat->matrix[2][0] + mat->matrix[3][0];
+ mv->co[1] = vx*mat->matrix[0][1] + vy*mat->matrix[1][1] +
+ vz*mat->matrix[2][1] + mat->matrix[3][1];
+ mv->co[2] = vx*mat->matrix[0][2] + vy*mat->matrix[1][2] +
+ vz*mat->matrix[2][2] + mat->matrix[3][2];
+
+ Py_DECREF(mv);
+ }
+
+ if ( recalc_normals ) {
+ /* loop through all the verts and transform normals by the inverse
+ * of the transpose of the supplied matrix */
+ float invmat[4][4];
+
+ /* we only need to invert a 3x3 submatrix, because the 4th component of
+ * affine vectors is 0, but Mat4Invert reports non invertible matrices */
+ if (!Mat4Invert((float(*)[4])*invmat, (float(*)[4])*mat->matrix))
+ return EXPP_ReturnPyObjError (PyExc_AttributeError,
+ "given matrix is not invertible");
+
+ for( i = 0; i < PySequence_Length(nmesh->verts); i++ ) {
+ mv = ( BPy_NMVert * ) PySequence_GetItem( nmesh->verts, i );
+ vx = mv->no[0];
+ vy = mv->no[1];
+ vz = mv->no[2];
+ mv->no[0] = vx*invmat[0][0] + vy*invmat[0][1] + vz*invmat[0][2];
+ mv->no[1] = vx*invmat[1][0] + vy*invmat[1][1] + vz*invmat[1][2];
+ mv->no[2] = vx*invmat[2][0] + vy*invmat[2][1] + vz*invmat[2][2];
+ Normalize(mv->no);
+ Py_DECREF(mv);
+ }
+ }
+
+ /* should we alternatively return a list of changed verts (and preserve
+ * the original ones) ? */
+ Py_RETURN_NONE;
+}
diff --git a/source/blender/python/api2_2x/NMesh.h b/source/blender/python/api2_2x/NMesh.h
new file mode 100644
index 00000000000..13ae12af522
--- /dev/null
+++ b/source/blender/python/api2_2x/NMesh.h
@@ -0,0 +1,157 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano, Jordi Rovira i Bonnet, Joseph Gilbert.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/* Most of this file comes from opy_nmesh.[ch] in the old bpython dir */
+
+#ifndef EXPP_NMESH_H
+#define EXPP_NMESH_H
+
+#include <Python.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "DNA_customdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "Material.h"
+#include "Image.h"
+
+/* EXPP PyType Objects */
+extern PyTypeObject NMesh_Type;
+extern PyTypeObject NMFace_Type;
+extern PyTypeObject NMVert_Type;
+extern PyTypeObject NMCol_Type;
+extern PyTypeObject NMEdge_Type;
+
+
+struct BPy_Object;
+
+/* These are from blender/src/editdeform.c, should be declared elsewhere,
+ * maybe in BIF_editdeform.h, after proper testing of vgrouping methods XXX */
+
+extern void add_vert_defnr( Object * ob, int def_nr, int vertnum, float weight,
+ int assignmode );
+extern void remove_vert_def_nr( Object * ob, int def_nr, int vertnum );
+
+
+
+/* Type checking for EXPP PyTypes */
+#define BPy_NMesh_Check(v) ((v)->ob_type == &NMesh_Type)
+#define BPy_NMFace_Check(v) ((v)->ob_type == &NMFace_Type)
+#define BPy_NMVert_Check(v) ((v)->ob_type == &NMVert_Type)
+#define BPy_NMCol_Check(v) ((v)->ob_type == &NMCol_Type)
+#define BPy_NMEdge_Check(v) ((v)->ob_type == &NMEdge_Type)
+
+/* Typedefs for the new types */
+
+typedef struct {
+ PyObject_HEAD /* required python macro */
+ unsigned char r, g, b, a;
+
+} BPy_NMCol; /* an NMesh color: [r,g,b,a] */
+
+typedef struct {
+ PyObject_VAR_HEAD /* required python macro */
+ float co[3];
+ float no[3];
+ float uvco[3];
+ int index;
+ char flag; /* see MVert flag in DNA_meshdata_types */
+
+} BPy_NMVert; /* an NMesh vertex */
+
+typedef struct {
+ PyObject_HEAD /* required python macro */
+ PyObject * v;
+ PyObject *uv;
+ PyObject *col;
+ short mode;
+ short flag; /* tface->flag */
+ unsigned char transp;
+ Image *image;
+ char mat_nr, mf_flag /* was char smooth */;
+ int orig_index;
+
+} BPy_NMFace; /* an NMesh face */
+
+typedef struct {
+ PyObject_HEAD /* required python macro */
+ PyObject *v1;
+ PyObject *v2;
+ char crease;
+ short flag;
+} BPy_NMEdge; /* an NMesh edge */
+
+typedef struct {
+ PyObject_HEAD /* required python macro */
+ Mesh * mesh; /* libdata must be second */
+ Object *object; /* for vertex grouping info, since it's stored on the object */
+ PyObject *name;
+ PyObject *materials;
+ PyObject *verts;
+ PyObject *faces;
+ PyObject *edges;
+ int sel_face; /*@ XXX remove */
+ short smoothresh; /* max AutoSmooth angle */
+ short subdiv[2]; /* SubDiv Levels: display and rendering */
+ short mode; /* see the EXPP_NMESH_* defines in the beginning of this file */
+ char flags;
+
+#define NMESH_HASMCOL (1<<0)
+#define NMESH_HASVERTUV (1<<1)
+#define NMESH_HASFACEUV (1<<2)
+
+ /* stores original data that is not accesible through NMesh, but that we
+ still want to preserve, indexed by orig_index in NMFace */
+ CustomData fdata;
+ int totfdata;
+
+} BPy_NMesh;
+
+/* PROTOS */
+
+PyObject *NMesh_Init( void );
+PyObject *NMesh_CreatePyObject( Mesh * me, Object * ob );
+Mesh *NMesh_FromPyObject( PyObject * pyobj, Object * ob );
+
+void mesh_update( Mesh * mesh , Object * ob );
+PyObject *new_NMesh( Mesh * oldmesh );
+Mesh *Mesh_fromNMesh( BPy_NMesh * nmesh );
+PyObject *NMesh_assignMaterials_toObject( BPy_NMesh * nmesh, Object * ob );
+Material **nmesh_updateMaterials( BPy_NMesh * nmesh );
+Material **newMaterialList_fromPyList( PyObject * list );
+
+
+#endif /* EXPP_NMESH_H */
diff --git a/source/blender/python/api2_2x/Node.c b/source/blender/python/api2_2x/Node.c
new file mode 100644
index 00000000000..296a30dea4e
--- /dev/null
+++ b/source/blender/python/api2_2x/Node.c
@@ -0,0 +1,1213 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006, Blender Foundation
+ * All rights reserved.
+ *
+ * Original code is this file
+ *
+ * Contributor(s): Nathan Letwory
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifdef USE_PYNODES /* note: won't work without patch */
+#include "Node.h"
+
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_node.h"
+
+#include "DNA_material_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "gen_utils.h"
+
+static PyObject *Node_repr( BPy_Node * self );
+static int Node_compare(BPy_Node *a, BPy_Node *b);
+static PyObject *ShadeInput_repr( BPy_ShadeInput * self );
+static int ShadeInput_compare(BPy_ShadeInput *a, BPy_ShadeInput *b);
+
+/**
+ * Take the descriptions from dict and create sockets for those in socks
+ * socks is a socketstack from a bNodeTypeInfo
+ */
+static int dict_socks_to_typeinfo(PyObject *dict, bNodeSocketType **socks, int len, int stage) {
+ int a = 0, pos = 0;
+ PyObject *key = NULL, *value = NULL;
+ bNodeSocketType *newsocks = NULL;
+
+ if(stage!=SH_NODE_DYNAMIC_READY && stage!=SH_NODE_DYNAMIC_ADDEXIST) {
+ newsocks = MEM_callocN(sizeof(bNodeSocketType)*(len+1), "bNodeSocketType");
+
+ if (dict) {
+ if(PyDict_Check(dict)) {
+ while(PyDict_Next(dict, &pos, &key, &value)) {
+ if(PyTuple_Check(value) && PyTuple_Size(value)==7) {
+ newsocks[a].name = BLI_strdup(PyString_AsString(key));
+ newsocks[a].type = (int)(PyInt_AsLong(PyTuple_GetItem(value, 0)));
+ newsocks[a].val1 = (float)(PyFloat_AsDouble(PyTuple_GetItem(value, 1)));
+ newsocks[a].val2 = (float)(PyFloat_AsDouble(PyTuple_GetItem(value, 2)));
+ newsocks[a].val3 = (float)(PyFloat_AsDouble(PyTuple_GetItem(value, 3)));
+ newsocks[a].val4 = (float)(PyFloat_AsDouble(PyTuple_GetItem(value, 4)));
+ newsocks[a].min = (float)(PyFloat_AsDouble(PyTuple_GetItem(value, 5)));
+ newsocks[a].max = (float)(PyFloat_AsDouble(PyTuple_GetItem(value, 6)));
+ a++;
+ }
+ }
+ } else {
+ return(EXPP_ReturnIntError( PyExc_AttributeError, "INPUT must be a dict"));
+ }
+ }
+ newsocks[a].type = -1;
+ if(*socks) {
+ int b = 0;
+ while((*socks)[b].type!=-1) {
+ MEM_freeN((*socks)[b].name);
+ (*socks)[b].name = NULL;
+ b++;
+ }
+ MEM_freeN(*socks);
+ }
+ *socks = newsocks;
+ }
+ return 0;
+}
+
+/* Get number of complying entries in a dict.
+ *
+ */
+static int num_dict_sockets(PyObject *dict) {
+ int a = 0, pos = 0;
+ PyObject *key = NULL, *value = NULL;
+ while(PyDict_Next(dict, &pos, &key, &value)) {
+ if(PyTuple_Check(value) && PyTuple_Size(value)==7)
+ a++;
+ }
+ return a;
+}
+
+static int Map_socketdef(PyObject *self, PyObject *args, void *closure)
+{
+ int newincnt = 0, newoutcnt = 0;
+ bNode *node = NULL;
+ BPy_DefinitionMap *defs= NULL;
+
+ Py_INCREF(args);
+ Py_INCREF(self);
+
+ defs= (BPy_DefinitionMap *)self;
+ node= defs->node;
+
+ if(!node) {
+ fprintf(stderr,"! no bNode in BPy_Node (Map_socketdef)\n");
+ return 0;
+ }
+
+ if(node->custom1==SH_NODE_DYNAMIC_READY && node->custom1==SH_NODE_DYNAMIC_ADDEXIST)
+ return 0;
+
+ switch((int)closure) {
+ case 'I':
+ if (args) {
+ if(PyDict_Check(args)) {
+ newincnt = num_dict_sockets(args);
+ dict_socks_to_typeinfo(args, &(node->typeinfo->inputs), newincnt, node->custom1);
+ } else {
+ Py_DECREF(self);
+ Py_DECREF(args);
+ return(EXPP_ReturnIntError( PyExc_AttributeError, "INPUT must be a dict"));
+ }
+ }
+ break;
+ case 'O':
+ if (args) {
+ if(PyDict_Check(args)) {
+ newoutcnt = num_dict_sockets(args);
+ dict_socks_to_typeinfo(args, &(node->typeinfo->outputs), newoutcnt, node->custom1);
+ } else {
+ Py_DECREF(self);
+ Py_DECREF(args);
+ return(EXPP_ReturnIntError( PyExc_AttributeError, "OUTPUT must be a dict"));
+ }
+ }
+ break;
+ default:
+ fprintf(stderr, "Hrm, why we got no dict? Todo: figure out proper complaint to scripter\n");
+ break;
+ }
+ Py_DECREF(self);
+ Py_DECREF(args);
+ return 0;
+}
+
+static PyGetSetDef InputDefMap_getseters[] = {
+ {"definitions", (getter)NULL, (setter)Map_socketdef,
+ "Set the inputs definition (dictionary)",
+ (void *)'I'},
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+PyTypeObject InputDefMap_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender.Node.InputDefinitions", /* char *tp_name; */
+ sizeof( BPy_DefinitionMap ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ NULL,/* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* cmpfunc tp_compare; */
+ NULL, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/input buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ 0, //( getiterfunc) MVertSeq_getIter, /* getiterfunc tp_iter; */
+ 0, //( iternextfunc ) MVertSeq_nextIter, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ 0, //BPy_MVertSeq_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ InputDefMap_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+BPy_DefinitionMap *Node_CreateInputDefMap(bNode *node) {
+ BPy_DefinitionMap *map = PyObject_NEW(BPy_DefinitionMap, &InputDefMap_Type);
+ map->node = node;
+ return map;
+}
+
+/***************************************/
+
+static PyGetSetDef OutputDefMap_getseters[] = {
+ {"definitions", (getter)NULL, (setter)Map_socketdef,
+ "Set the outputs definition (dictionary)",
+ (void *)'O'},
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+PyTypeObject OutputDefMap_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender.Node.OutputDefinitions", /* char *tp_name; */
+ sizeof( BPy_DefinitionMap ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ NULL,/* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* cmpfunc tp_compare; */
+ NULL, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ 0, //( getiterfunc) MVertSeq_getIter, /* getiterfunc tp_iter; */
+ 0, //( iternextfunc ) MVertSeq_nextIter, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ 0, //BPy_MVertSeq_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ OutputDefMap_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+BPy_DefinitionMap *Node_CreateOutputDefMap(bNode *node) {
+ BPy_DefinitionMap *map = PyObject_NEW(BPy_DefinitionMap, &OutputDefMap_Type);
+ map->node = node;
+ return map;
+}
+
+/***************************************/
+
+static int sockinmap_len ( BPy_SockMap * self) {
+ int a = 0;
+ if(self->typeinfo) {
+ while(self->typeinfo->inputs[a].type!=-1)
+ a++;
+ }
+ return a;
+}
+
+static int sockinmap_has_key( BPy_SockMap *self, PyObject *key) {
+ int a = 0;
+ char *strkey = PyString_AsString(key);
+
+ if(self->typeinfo){
+ while(self->typeinfo->inputs[a].type!=-1) {
+ if(BLI_strcaseeq(self->typeinfo->inputs[a].name, strkey)) {
+ return a;
+ }
+ a++;
+ }
+ }
+ return -1;
+}
+
+PyObject *sockinmap_subscript(BPy_SockMap *self, PyObject *idx) {
+ int a, _idx;
+ a = sockinmap_len(self);
+
+ if (PyString_Check(idx)) {
+ _idx = sockinmap_has_key( self, idx);
+ }
+ else if(PyInt_Check(idx)) {
+ PyErr_SetString(PyExc_ValueError, "int index not implemented");
+ Py_RETURN_NONE;
+ }
+ else if (PySlice_Check(idx)) {
+ PyErr_SetString(PyExc_ValueError, "slices not implemented");
+ Py_RETURN_NONE;
+ } else {
+ PyErr_SetString(PyExc_IndexError, "Index must be string");
+ Py_RETURN_NONE;
+ }
+
+
+ switch(self->typeinfo->inputs[_idx].type) {
+ case SOCK_VALUE:
+ return Py_BuildValue("f", self->stack[_idx]->vec[0]);
+ break;
+ case SOCK_VECTOR:
+ return Py_BuildValue("(fff)", self->stack[_idx]->vec[0], self->stack[_idx]->vec[1], self->stack[_idx]->vec[2]);
+ break;
+ case SOCK_RGBA:
+ return Py_BuildValue("(ffff)", self->stack[_idx]->vec[0], self->stack[_idx]->vec[1], self->stack[_idx]->vec[2], self->stack[_idx]->vec[3]);
+ break;
+ default:
+ break;
+ }
+ Py_RETURN_NONE;
+}
+
+/* read only */
+static PyMappingMethods sockinmap_as_mapping = {
+ ( inquiry ) sockinmap_len, /* mp_length */
+ ( binaryfunc ) sockinmap_subscript, /* mp_subscript */
+ ( objobjargproc ) 0 /* mp_ass_subscript */
+};
+
+PyTypeObject SockInMap_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender.Node.InputSockets", /* char *tp_name; */
+ sizeof( BPy_SockMap ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ NULL,/* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* cmpfunc tp_compare; */
+ NULL, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ &sockinmap_as_mapping, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ 0, //( getiterfunc) MVertSeq_getIter, /* getiterfunc tp_iter; */
+ 0, //( iternextfunc ) MVertSeq_nextIter, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ 0, //BPy_MVertSeq_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ NULL, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+static int sockoutmap_len ( BPy_SockMap * self) {
+ int a = 0;
+ if(self->typeinfo) {
+ while(self->typeinfo->outputs[a].type!=-1)
+ a++;
+ }
+ return a;
+}
+
+static int sockoutmap_has_key( BPy_SockMap *self, PyObject *key) {
+ int a = 0;
+ char *strkey = PyString_AsString(key);
+
+ if(self->typeinfo){
+ while(self->typeinfo->outputs[a].type!=-1) {
+ if(BLI_strcaseeq(self->typeinfo->outputs[a].name, strkey)) {
+ return a;
+ }
+ a++;
+ }
+ }
+ return -1;
+}
+
+static int sockoutmap_assign_subscript(BPy_SockMap *self, PyObject *idx, PyObject *value) {
+ int a, _idx;
+ a = sockoutmap_len(self);
+ if(PyInt_Check(idx)) {
+ _idx = (int)PyInt_AsLong(idx);
+ }
+ else if (PyString_Check(idx)) {
+ _idx = sockoutmap_has_key( self, idx);
+ }
+ else if (PySlice_Check(idx)) {
+ PyErr_SetString(PyExc_ValueError, "slices not implemented, yet");
+ return -1;
+ } else {
+ PyErr_SetString(PyExc_IndexError, "Index must be int or string");
+ return -1;
+ }
+ if(_idx > -1) {
+ switch(self->typeinfo->outputs[_idx].type) {
+ case SOCK_VALUE:
+ if(PyTuple_Size(value)==1)
+ self->stack[_idx]->vec[0] = (float)PyFloat_AsDouble(PyTuple_GetItem(value, 0));
+ return 0;
+ break;
+ case SOCK_VECTOR:
+ if(PyTuple_Size(value)==3) {
+ self->stack[_idx]->vec[0] = (float)PyFloat_AsDouble(PyTuple_GetItem(value, 0));
+ self->stack[_idx]->vec[1] = (float)PyFloat_AsDouble(PyTuple_GetItem(value, 1));
+ self->stack[_idx]->vec[2] = (float)PyFloat_AsDouble(PyTuple_GetItem(value, 2));
+ }
+ return 0;
+ break;
+ case SOCK_RGBA:
+ if(PyTuple_Size(value)==4) {
+ self->stack[_idx]->vec[0] = (float)PyFloat_AsDouble(PyTuple_GetItem(value, 0));
+ self->stack[_idx]->vec[1] = (float)PyFloat_AsDouble(PyTuple_GetItem(value, 1));
+ self->stack[_idx]->vec[2] = (float)PyFloat_AsDouble(PyTuple_GetItem(value, 2));
+ self->stack[_idx]->vec[3] = (float)PyFloat_AsDouble(PyTuple_GetItem(value, 3));
+ }
+ return 0;
+ break;
+ default:
+ break;
+ }
+ }
+ return 0;
+}
+
+/* write only */
+static PyMappingMethods sockoutmap_as_mapping = {
+ ( inquiry ) sockoutmap_len, /* mp_length */
+ ( binaryfunc ) 0, /* mp_subscript */
+ ( objobjargproc ) sockoutmap_assign_subscript /* mp_ass_subscript */
+};
+
+PyTypeObject SockOutMap_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender.Node.OutputSockets", /* char *tp_name; */
+ sizeof( BPy_SockMap ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ NULL,/* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* cmpfunc tp_compare; */
+ NULL, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ &sockoutmap_as_mapping, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ 0, //( getiterfunc) MVertSeq_getIter, /* getiterfunc tp_iter; */
+ 0, //( iternextfunc ) MVertSeq_nextIter, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ 0, //BPy_MVertSeq_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ NULL, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+
+static BPy_SockMap *Node_CreateInputMap(bNode *node, bNodeStack **stack) {
+ BPy_SockMap *map= PyObject_NEW(BPy_SockMap, &SockInMap_Type);
+ map->typeinfo= node->typeinfo;
+ map->stack= stack;
+ return map;
+}
+
+static PyObject *Node_GetInputMap(BPy_Node *self) {
+ BPy_SockMap *inmap= Node_CreateInputMap(self->node, self->in);
+ return (PyObject *)(inmap);
+}
+
+#define SURFACEVIEWVECTOR 0
+#define VIEWNORMAL 1
+#define SURFACENORMAL 2
+#define GLOBALTEXTURE 3
+#define TEXTURE 4
+#define PIXEL 5
+#define COLOR 6
+#define SPECULAR 7
+#define MIRROR 8
+#define AMBIENT 9
+#define AMBIENTFACTOR 10
+#define EMITFACTOR 11
+#define DISPLACE 12
+#define STRAND 13
+#define STRESS 14
+#define TANGENT 15
+#define SURFACE_D 30
+#define TEXTURE_D 31
+#define GLOBALTEXTURE_D 32
+#define REFLECTION_D 33
+#define NORMAL_D 34
+#define STICKY_D 35
+#define REFRACT_D 36
+#define STRAND_D 37
+
+static PyObject *ShadeInput_getAttribute(BPy_ShadeInput *self, void *type) {
+ PyObject *obj= NULL;
+ if(self->shi) {
+ switch((int)type) {
+ case SURFACEVIEWVECTOR:
+ obj= Py_BuildValue("(fff)", self->shi->view[0], self->shi->view[1], self->shi->view[2]);
+ break;
+ case VIEWNORMAL:
+ obj= Py_BuildValue("(fff)", self->shi->vn[0], self->shi->vn[1], self->shi->vn[2]);
+ break;
+ case SURFACENORMAL:
+ obj= Py_BuildValue("(fff)", self->shi->facenor[0], self->shi->facenor[1], self->shi->facenor[2]);
+ break;
+ case GLOBALTEXTURE:
+ obj= Py_BuildValue("(fff)", self->shi->gl[0], self->shi->gl[1], self->shi->gl[2]);
+ break;
+ case TEXTURE:
+ obj= Py_BuildValue("(fff)", self->shi->lo[0], self->shi->lo[1], self->shi->lo[2]);
+ break;
+ case PIXEL:
+ obj= Py_BuildValue("(ii)", self->shi->xs, self->shi->ys);
+ break;
+ case COLOR:
+ obj= Py_BuildValue("(fff)", self->shi->r, self->shi->g, self->shi->b);
+ break;
+ case SPECULAR:
+ obj= Py_BuildValue("(fff)", self->shi->specr, self->shi->specg, self->shi->specb);
+ break;
+ case MIRROR:
+ obj= Py_BuildValue("(fff)", self->shi->mirr, self->shi->mirg, self->shi->mirb);
+ break;
+ case AMBIENT:
+ obj= Py_BuildValue("(fff)", self->shi->ambr, self->shi->ambg, self->shi->ambb);
+ break;
+ case AMBIENTFACTOR:
+ obj= PyFloat_FromDouble((double)(self->shi->amb));
+ break;
+ case EMITFACTOR:
+ obj= PyFloat_FromDouble((double)(self->shi->emit));
+ break;
+ case DISPLACE:
+ obj= Py_BuildValue("(fff)", self->shi->displace[0], self->shi->displace[1], self->shi->displace[2]);
+ break;
+ case STRAND:
+ obj= PyFloat_FromDouble((double)(self->shi->strand));
+ break;
+ case STRESS:
+ obj= PyFloat_FromDouble((double)(self->shi->stress));
+ break;
+ case TANGENT:
+ obj= Py_BuildValue("(fff)", self->shi->tang[0], self->shi->tang[1], self->shi->tang[2]);
+ break;
+ case SURFACE_D:
+ obj= Py_BuildValue("(fff)(fff)", self->shi->dxco[0], self->shi->dxco[1], self->shi->dxco[2], self->shi->dyco[0], self->shi->dyco[1], self->shi->dyco[2]);
+ break;
+ case TEXTURE_D:
+ obj= Py_BuildValue("(fff)(fff)", self->shi->dxlo[0], self->shi->dxlo[1], self->shi->dxlo[2], self->shi->dylo[0], self->shi->dylo[1], self->shi->dylo[2]);
+ break;
+ case GLOBALTEXTURE_D:
+ obj= Py_BuildValue("(fff)(fff)", self->shi->dxgl[0], self->shi->dxgl[1], self->shi->dxgl[2], self->shi->dygl[0], self->shi->dygl[1], self->shi->dygl[2]);
+ break;
+ case REFLECTION_D:
+ obj= Py_BuildValue("(fff)(fff)", self->shi->dxref[0], self->shi->dxref[1], self->shi->dxref[2], self->shi->dyref[0], self->shi->dyref[1], self->shi->dyref[2]);
+ break;
+ case NORMAL_D:
+ obj= Py_BuildValue("(fff)(fff)", self->shi->dxno[0], self->shi->dxno[1], self->shi->dxno[2], self->shi->dyno[0], self->shi->dyno[1], self->shi->dyno[2]);
+ break;
+ case STICKY_D:
+ obj= Py_BuildValue("(fff)(fff)", self->shi->dxsticky[0], self->shi->dxsticky[1], self->shi->dxsticky[2], self->shi->dysticky[0], self->shi->dysticky[1], self->shi->dysticky[2]);
+ break;
+ case REFRACT_D:
+ obj= Py_BuildValue("(fff)(fff)", self->shi->dxrefract[0], self->shi->dxrefract[1], self->shi->dxrefract[2], self->shi->dyrefract[0], self->shi->dyrefract[1], self->shi->dyrefract[2]);
+ break;
+ case STRAND_D:
+ obj= Py_BuildValue("(ff)", self->shi->dxstrand, self->shi->dystrand);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if(!obj) {
+ Py_RETURN_NONE;
+ }
+ return obj;
+}
+
+static BPy_SockMap *Node_CreateOutputMap(bNode *node, bNodeStack **stack) {
+ BPy_SockMap *map = PyObject_NEW(BPy_SockMap, &SockOutMap_Type);
+ map->typeinfo= node->typeinfo;
+ map->stack= stack;
+ return map;
+}
+
+static PyObject *Node_GetOutputMap(BPy_Node *self) {
+ BPy_SockMap *outmap= Node_CreateOutputMap(self->node, self->out);
+ return (PyObject *)outmap;
+}
+
+static PyObject *Node_GetShi(BPy_Node *self) {
+ BPy_ShadeInput *shi= ShadeInput_CreatePyObject(self->shi);
+ return (PyObject *)shi;
+
+}
+
+static PyObject *node_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ PyObject *self;
+ assert(type!=NULL && type->tp_alloc!=NULL);
+ self= type->tp_alloc(type, 1);
+ return self;
+}
+
+static int node_init(BPy_Node *self, PyObject *args, PyObject *kwds)
+{
+ return 0;
+}
+
+static PyGetSetDef BPy_Node_getseters[] = {
+ {"ins",
+ (getter)Node_GetInputMap, (setter)NULL,
+ "Get the ShadeInput mapping (dictionary)",
+ NULL},
+ {"outs",
+ (getter)Node_GetOutputMap, (setter)NULL,
+ "Get the ShadeInput mapping (dictionary)",
+ NULL},
+ {"shi",
+ (getter)Node_GetShi, (setter)NULL,
+ "Get the ShadeInput (ShadeInput)",
+ NULL},
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+static PyGetSetDef BPy_ShadeInput_getseters[] = {
+ {"texture",
+ (getter)ShadeInput_getAttribute, (setter)NULL,
+ "Get the current texture coordinate (tuple)",
+ (void*)TEXTURE},
+ {"texture_global",
+ (getter)ShadeInput_getAttribute, (setter)NULL,
+ "Get the current global texture coordinate (tuple)",
+ (void*)GLOBALTEXTURE},
+ {"surface_normal",
+ (getter)ShadeInput_getAttribute, (setter)NULL,
+ "Get the current surface normal (tuple)",
+ (void*)SURFACENORMAL},
+ {"view_normal",
+ (getter)ShadeInput_getAttribute, (setter)NULL,
+ "Get the current view normal (tuple)",
+ (void*)VIEWNORMAL},
+ {"surface_view_vec",
+ (getter)ShadeInput_getAttribute, (setter)NULL,
+ "Get the vector pointing to the viewpoint from the point being shaded (tuple)",
+ (void*)SURFACEVIEWVECTOR},
+ {"pixel",
+ (getter)ShadeInput_getAttribute, (setter)NULL,
+ "Get the x,y-coordinate for the pixel rendered (tuple)",
+ (void*)PIXEL},
+ {"color",
+ (getter)ShadeInput_getAttribute, (setter)NULL,
+ "Get the color for the point being shaded (tuple)",
+ (void*)COLOR},
+ {"specular",
+ (getter)ShadeInput_getAttribute, (setter)NULL,
+ "Get the specular color for the point being shaded (tuple)",
+ (void*)SPECULAR},
+ {"mirror",
+ (getter)ShadeInput_getAttribute, (setter)NULL,
+ "Get the mirror color for the point being shaded (tuple)",
+ (void*)MIRROR},
+ {"ambient",
+ (getter)ShadeInput_getAttribute, (setter)NULL,
+ "Get the ambient color for the point being shaded (tuple)",
+ (void*)AMBIENT},
+ {"ambient_factor",
+ (getter)ShadeInput_getAttribute, (setter)NULL,
+ "Get the ambient factor for the point being shaded (float)",
+ (void*)AMBIENTFACTOR},
+ {"emit_factor",
+ (getter)ShadeInput_getAttribute, (setter)NULL,
+ "Get the emit factor for the point being shaded (float)",
+ (void*)EMITFACTOR},
+ {"displace",
+ (getter)ShadeInput_getAttribute, (setter)NULL,
+ "Get the displace vector for the point being shaded (tuple)",
+ (void*)DISPLACE},
+ {"strand",
+ (getter)ShadeInput_getAttribute, (setter)NULL,
+ "Get the strand factor(float)",
+ (void*)STRAND},
+ {"stress",
+ (getter)ShadeInput_getAttribute, (setter)NULL,
+ "Get the stress factor(float)",
+ (void*)STRESS},
+ {"tangent",
+ (getter)ShadeInput_getAttribute, (setter)NULL,
+ "Get the tangent vector (tuple)",
+ (void*)TANGENT},
+ {"surface_d",
+ (getter)ShadeInput_getAttribute, (setter)NULL,
+ "Get the surface d (tuple of tuples)",
+ (void*)SURFACE_D},
+ {"texture_d",
+ (getter)ShadeInput_getAttribute, (setter)NULL,
+ "Get the texture d (tuple of tuples)",
+ (void*)TEXTURE_D},
+ {"texture_global_d",
+ (getter)ShadeInput_getAttribute, (setter)NULL,
+ "Get the global texture d (tuple of tuples)",
+ (void*)GLOBALTEXTURE_D},
+ {"reflection_d",
+ (getter)ShadeInput_getAttribute, (setter)NULL,
+ "Get the reflection d (tuple of tuples)",
+ (void*)REFLECTION_D},
+ {"normal_d",
+ (getter)ShadeInput_getAttribute, (setter)NULL,
+ "Get the normal d (tuple of tuples)",
+ (void*)NORMAL_D},
+ {"sticky_d",
+ (getter)ShadeInput_getAttribute, (setter)NULL,
+ "Get the sticky d (tuple of tuples)",
+ (void*)STICKY_D},
+ {"refract_d",
+ (getter)ShadeInput_getAttribute, (setter)NULL,
+ "Get the refract d (tuple of tuples)",
+ (void*)REFRACT_D},
+ {"strand_d",
+ (getter)ShadeInput_getAttribute, (setter)NULL,
+ "Get the strand d (tuple)",
+ (void*)REFRACT_D},
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+PyTypeObject Node_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender.Node.node", /* char *tp_name; */
+ sizeof( BPy_Node ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ NULL,/* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL /*( getattrfunc ) PyObject_GenericGetAttr*/, /* getattrfunc tp_getattr; */
+ NULL /*( setattrfunc ) PyObject_GenericSetAttr*/, /* setattrfunc tp_setattr; */
+ ( cmpfunc ) Node_compare, /* cmpfunc tp_compare; */
+ ( reprfunc ) Node_repr, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ NULL, /*BPy_Node_methods,*/ /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ BPy_Node_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ (initproc)node_init, /* initproc tp_init; */
+ /*PyType_GenericAlloc*/NULL, /* allocfunc tp_alloc; */
+ node_new, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+PyTypeObject ShadeInput_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender.Node.ShadeInput", /* char *tp_name; */
+ sizeof( BPy_ShadeInput ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ NULL,/* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ ( cmpfunc ) ShadeInput_compare, /* cmpfunc tp_compare; */
+ ( reprfunc ) ShadeInput_repr, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ NULL, /*BPy_Node_methods,*/ /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ BPy_ShadeInput_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+
+/* Initialise Node module */
+PyObject *Node_Init(void)
+{
+ PyObject *submodule;
+
+ if( PyType_Ready( &Node_Type ) < 0 )
+ return NULL;
+ if( PyType_Ready( &ShadeInput_Type ) < 0 )
+ return NULL;
+ if( PyType_Ready( &OutputDefMap_Type ) < 0 )
+ return NULL;
+ if( PyType_Ready( &InputDefMap_Type ) < 0 )
+ return NULL;
+ if( PyType_Ready( &SockInMap_Type ) < 0 )
+ return NULL;
+ if( PyType_Ready( &SockOutMap_Type ) < 0 )
+ return NULL;
+ submodule = Py_InitModule3( "Blender.Node", NULL, "");
+
+ PyModule_AddIntConstant(submodule, "VALUE", SOCK_VALUE);
+ PyModule_AddIntConstant(submodule, "RGBA", SOCK_RGBA);
+ PyModule_AddIntConstant(submodule, "VECTOR", SOCK_VECTOR);
+
+ Py_INCREF(&Node_Type);
+ PyModule_AddObject(submodule, "node", (PyObject *)&Node_Type);
+
+ return submodule;
+
+}
+
+static int Node_compare(BPy_Node *a, BPy_Node *b)
+{
+ bNode *pa = a->node, *pb = b->node;
+ return (pa==pb) ? 0 : -1;
+}
+
+static PyObject *Node_repr(BPy_Node *self)
+{
+ return PyString_FromFormat( "[Node \"%s\"]",
+ self->node ? self->node->id->name+2 : "empty node");
+}
+
+BPy_Node *Node_CreatePyObject(bNode *node)
+{
+ BPy_Node *pynode;
+
+ pynode = (BPy_Node *)PyObject_NEW(BPy_Node, &Node_Type);
+ if(!pynode) {
+ fprintf(stderr,"Couldn't create BPy_Node object\n");
+ return (BPy_Node *)(EXPP_ReturnPyObjError(PyExc_MemoryError, "couldn't create BPy_Node object"));
+ }
+
+ pynode->node= node;
+
+ return pynode;
+}
+
+void InitNode(BPy_Node *self, bNode *node) {
+ self->node= node;
+}
+
+bNode *Node_FromPyObject(PyObject *pyobj)
+{
+ return ((BPy_Node *)pyobj)->node;
+}
+
+void Node_SetStack(BPy_Node *self, bNodeStack **stack, int type)
+{
+ if(type==NODE_INPUTSTACK) {
+ self->in= stack;
+ } else if(type==NODE_OUTPUTSTACK) {
+ self->out= stack;
+ }
+}
+
+void Node_SetShi(BPy_Node *self, ShadeInput *shi)
+{
+ self->shi= shi;
+}
+
+/*********************/
+
+static int ShadeInput_compare(BPy_ShadeInput *a, BPy_ShadeInput *b)
+{
+ ShadeInput *pa = a->shi, *pb = b->shi;
+ return (pa==pb) ? 0 : -1;
+}
+
+static PyObject *ShadeInput_repr(BPy_ShadeInput *self)
+{
+ return PyString_FromFormat( "[ShadeInput @ \"%p\"]", self);
+}
+
+BPy_ShadeInput *ShadeInput_CreatePyObject(ShadeInput *shi)
+{
+ BPy_ShadeInput *pyshi;
+
+ pyshi = (BPy_ShadeInput *)PyObject_NEW(BPy_ShadeInput, &ShadeInput_Type);
+ if(!pyshi) {
+ fprintf(stderr,"Couldn't create BPy_ShadeInput object\n");
+ return (BPy_ShadeInput *)(EXPP_ReturnPyObjError(PyExc_MemoryError, "couldn't create BPy_ShadeInput object"));
+ }
+
+ pyshi->shi = shi;
+
+ return pyshi;
+}
+#endif
+
diff --git a/source/blender/python/api2_2x/Node.h b/source/blender/python/api2_2x/Node.h
new file mode 100644
index 00000000000..f4796d1b80b
--- /dev/null
+++ b/source/blender/python/api2_2x/Node.h
@@ -0,0 +1,91 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006, Blender Foundation
+ * All rights reserved.
+ *
+ * Original code is this file
+ *
+ * Contributor(s): Nathan Letwory
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifdef USE_PYNODES /* note: won't work without patch */
+#ifndef __NODE_H__
+#define __NODE_H__
+
+#include <Python.h>
+#include "DNA_node_types.h"
+#include "BKE_node.h"
+
+#include "RE_shader_ext.h" /* <- ShadeInput Shaderesult TexResult */
+
+extern PyTypeObject Node_Type;
+extern PyTypeObject ShadeInput_Type;
+
+#define BPy_Node_Check(v) \
+ ((v)->ob_type == &Node_Type)
+
+#define BPy_ShadeInput_Check(v) \
+ ((v)->ob_type == &ShadeInput_Type)
+
+typedef struct BPy_ShadeInput {
+ PyObject_HEAD
+ ShadeInput *shi;
+} BPy_ShadeInput;
+
+typedef struct {
+ PyObject_VAR_HEAD
+ bNodeType *typeinfo;
+ bNodeStack **stack;
+} BPy_SockMap;
+
+typedef struct {
+ PyObject_HEAD
+ bNode *node;
+} BPy_DefinitionMap;
+
+typedef struct BPy_Node {
+ PyObject_HEAD
+ bNode *node;
+ bNodeStack **in;
+ bNodeStack **out;
+ ShadeInput *shi;
+} BPy_Node;
+
+extern PyObject *Node_Init(void);
+extern void InitNode(BPy_Node *self, bNode *node);
+extern BPy_Node *Node_CreatePyObject(bNode *node);
+extern BPy_DefinitionMap *Node_CreateOutputDefMap(bNode *node);
+extern BPy_DefinitionMap *Node_CreateInputDefMap(bNode *node);
+extern void Node_SetStack(BPy_Node *self, bNodeStack **stack, int type);
+extern void Node_SetShi(BPy_Node *self, ShadeInput *shi);
+extern BPy_ShadeInput *ShadeInput_CreatePyObject(ShadeInput *shi);
+extern void Node_dealloc(BPy_Node *self);
+extern void ShadeInput_dealloc(BPy_ShadeInput *self);
+
+#define NODE_INPUTSTACK 0
+#define NODE_OUTPUTSTACK 1
+
+#endif /* __NODE_H__*/
+#endif /* USE_PYNODES */
diff --git a/source/blender/python/api2_2x/Noise.c b/source/blender/python/api2_2x/Noise.c
new file mode 100644
index 00000000000..c1a41d46714
--- /dev/null
+++ b/source/blender/python/api2_2x/Noise.c
@@ -0,0 +1,713 @@
+/**
+ * $Id$
+ *
+ * Blender.Noise BPython module implementation.
+ * This submodule has functions to generate noise of various types.
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): eeshlo
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+/************************/
+/* Blender Noise Module */
+/************************/
+
+#include <Python.h>
+
+#include "BLI_blenlib.h"
+#include "DNA_texture_types.h"
+#include "constant.h"
+
+/*-----------------------------------------*/
+/* 'mersenne twister' random number generator */
+
+/*
+ A C-program for MT19937, with initialization improved 2002/2/10.
+ Coded by Takuji Nishimura and Makoto Matsumoto.
+ This is a faster version by taking Shawn Cokus's optimization,
+ Matthe Bellew's simplification, Isaku Wada's real version.
+
+ Before using, initialize the state by using init_genrand(seed)
+ or init_by_array(init_key, key_length).
+
+ Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ 2. 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.
+
+ 3. The names of its contributors may not 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.
+
+
+ Any feedback is very welcome.
+ http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
+ email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space)
+*/
+
+/* Period parameters */
+#define N 624
+#define M 397
+#define MATRIX_A 0x9908b0dfUL /* constant vector a */
+#define UMASK 0x80000000UL /* most significant w-r bits */
+#define LMASK 0x7fffffffUL /* least significant r bits */
+#define MIXBITS(u,v) ( ((u) & UMASK) | ((v) & LMASK) )
+#define TWIST(u,v) ((MIXBITS(u,v) >> 1) ^ ((v)&1UL ? MATRIX_A : 0UL))
+
+static unsigned long state[N]; /* the array for the state vector */
+static int left = 1;
+static int initf = 0;
+static unsigned long *next;
+
+PyObject *Noise_Init(void);
+
+/* initializes state[N] with a seed */
+static void init_genrand( unsigned long s )
+{
+ int j;
+ state[0] = s & 0xffffffffUL;
+ for( j = 1; j < N; j++ ) {
+ state[j] =
+ ( 1812433253UL *
+ ( state[j - 1] ^ ( state[j - 1] >> 30 ) ) + j );
+ /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
+ /* In the previous versions, MSBs of the seed affect */
+ /* only MSBs of the array state[]. */
+ /* 2002/01/09 modified by Makoto Matsumoto */
+ state[j] &= 0xffffffffUL; /* for >32 bit machines */
+ }
+ left = 1;
+ initf = 1;
+}
+
+static void next_state( void )
+{
+ unsigned long *p = state;
+ int j;
+
+ /* if init_genrand() has not been called, */
+ /* a default initial seed is used */
+ if( initf == 0 )
+ init_genrand( 5489UL );
+
+ left = N;
+ next = state;
+
+ for( j = N - M + 1; --j; p++ )
+ *p = p[M] ^ TWIST( p[0], p[1] );
+
+ for( j = M; --j; p++ )
+ *p = p[M - N] ^ TWIST( p[0], p[1] );
+
+ *p = p[M - N] ^ TWIST( p[0], state[0] );
+}
+
+/*------------------------------------------------------------*/
+
+static void setRndSeed( int seed )
+{
+ if( seed == 0 )
+ init_genrand( time( NULL ) );
+ else
+ init_genrand( seed );
+}
+
+/* float number in range [0, 1) using the mersenne twister rng */
+static float frand( )
+{
+ unsigned long y;
+
+ if( --left == 0 )
+ next_state( );
+ y = *next++;
+
+ /* Tempering */
+ y ^= ( y >> 11 );
+ y ^= ( y << 7 ) & 0x9d2c5680UL;
+ y ^= ( y << 15 ) & 0xefc60000UL;
+ y ^= ( y >> 18 );
+
+ return ( float ) y / 4294967296.f;
+}
+
+/*------------------------------------------------------------*/
+
+/* returns random unit vector */
+static void randuvec( float v[3] )
+{
+ float r;
+ v[2] = 2.f * frand( ) - 1.f;
+ if( ( r = 1.f - v[2] * v[2] ) > 0.f ) {
+ float a = (float)(6.283185307f * frand( ));
+ r = (float)sqrt( r );
+ v[0] = (float)(r * cos( a ));
+ v[1] = (float)(r * sin( a ));
+ } else
+ v[2] = 1.f;
+}
+
+static PyObject *Noise_random( PyObject * self )
+{
+ return Py_BuildValue( "f", frand( ) );
+}
+
+static PyObject *Noise_randuvec( PyObject * self )
+{
+ float v[3] = {0.0f, 0.0f, 0.0f};
+ randuvec( v );
+ return Py_BuildValue( "[fff]", v[0], v[1], v[2] );
+}
+
+/*---------------------------------------------------------------------*/
+
+/* Random seed init. Only used for MT random() & randuvec() */
+
+static PyObject *Noise_setRandomSeed( PyObject * self, PyObject * args )
+{
+ int s;
+ if( !PyArg_ParseTuple( args, "i", &s ) )
+ return NULL;
+ setRndSeed( s );
+ Py_INCREF( Py_None );
+ return Py_None;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* General noise */
+
+static PyObject *Noise_noise( PyObject * self, PyObject * args )
+{
+ float x, y, z;
+ int nb = 1;
+ if( !PyArg_ParseTuple( args, "(fff)|i", &x, &y, &z, &nb ) )
+ return NULL;
+
+ return PyFloat_FromDouble(
+ (double)(2.0 * BLI_gNoise( 1.0, x, y, z, 0, nb ) - 1.0) );
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* General Vector noise */
+
+static void vNoise( float x, float y, float z, int nb, float v[3] )
+{
+ /* Simply evaluate noise at 3 different positions */
+ v[0] = (float)(2.0 * BLI_gNoise( 1.f, x + 9.321f, y - 1.531f, z - 7.951f, 0,
+ nb ) - 1.0);
+ v[1] = (float)(2.0 * BLI_gNoise( 1.f, x, y, z, 0, nb ) - 1.0);
+ v[2] = (float)(2.0 * BLI_gNoise( 1.f, x + 6.327f, y + 0.1671f, z - 2.672f, 0,
+ nb ) - 1.0);
+}
+
+static PyObject *Noise_vNoise( PyObject * self, PyObject * args )
+{
+ float x, y, z, v[3];
+ int nb = 1;
+ if( !PyArg_ParseTuple( args, "(fff)|i", &x, &y, &z, &nb ) )
+ return NULL;
+ vNoise( x, y, z, nb, v );
+ return Py_BuildValue( "[fff]", v[0], v[1], v[2] );
+}
+
+/*---------------------------------------------------------------------------*/
+
+/* General turbulence */
+
+static float turb( float x, float y, float z, int oct, int hard, int nb,
+ float ampscale, float freqscale )
+{
+ float amp, out, t;
+ int i;
+ amp = 1.f;
+ out = (float)(2.0 * BLI_gNoise( 1.f, x, y, z, 0, nb ) - 1.0);
+ if( hard )
+ out = (float)fabs( out );
+ for( i = 1; i < oct; i++ ) {
+ amp *= ampscale;
+ x *= freqscale;
+ y *= freqscale;
+ z *= freqscale;
+ t = (float)(amp * ( 2.0 * BLI_gNoise( 1.f, x, y, z, 0, nb ) - 1.0 ));
+ if( hard )
+ t = (float)fabs( t );
+ out += t;
+ }
+ return out;
+}
+
+static PyObject *Noise_turbulence( PyObject * self, PyObject * args )
+{
+ float x, y, z;
+ int oct, hd, nb = 1;
+ float as = 0.5, fs = 2.0;
+ if( !PyArg_ParseTuple
+ ( args, "(fff)ii|iff", &x, &y, &z, &oct, &hd, &nb, &as, &fs ) )
+ return NULL;
+ return PyFloat_FromDouble( (double)turb( x, y, z, oct, hd, nb, as, fs ) );
+}
+
+/*--------------------------------------------------------------------------*/
+
+/* Turbulence Vector */
+
+static void vTurb( float x, float y, float z, int oct, int hard, int nb,
+ float ampscale, float freqscale, float v[3] )
+{
+ float amp, t[3];
+ int i;
+ amp = 1.f;
+ vNoise( x, y, z, nb, v );
+ if( hard ) {
+ v[0] = (float)fabs( v[0] );
+ v[1] = (float)fabs( v[1] );
+ v[2] = (float)fabs( v[2] );
+ }
+ for( i = 1; i < oct; i++ ) {
+ amp *= ampscale;
+ x *= freqscale;
+ y *= freqscale;
+ z *= freqscale;
+ vNoise( x, y, z, nb, t );
+ if( hard ) {
+ t[0] = (float)fabs( t[0] );
+ t[1] = (float)fabs( t[1] );
+ t[2] = (float)fabs( t[2] );
+ }
+ v[0] += amp * t[0];
+ v[1] += amp * t[1];
+ v[2] += amp * t[2];
+ }
+}
+
+static PyObject *Noise_vTurbulence( PyObject * self, PyObject * args )
+{
+ float x, y, z, v[3];
+ int oct, hd, nb = 1;
+ float as = 0.5, fs = 2.0;
+ if( !PyArg_ParseTuple
+ ( args, "(fff)ii|iff", &x, &y, &z, &oct, &hd, &nb, &as, &fs ) )
+ return NULL;
+ vTurb( x, y, z, oct, hd, nb, as, fs, v );
+ return Py_BuildValue( "[fff]", v[0], v[1], v[2] );
+}
+
+/*---------------------------------------------------------------------*/
+
+/* F. Kenton Musgrave's fractal functions */
+
+static PyObject *Noise_fBm( PyObject * self, PyObject * args )
+{
+ float x, y, z, H, lac, oct;
+ int nb = 1;
+ if( !PyArg_ParseTuple
+ ( args, "(fff)fff|i", &x, &y, &z, &H, &lac, &oct, &nb ) )
+ return NULL;
+ return PyFloat_FromDouble( (double)mg_fBm( x, y, z, H, lac, oct, nb ) );
+}
+
+/*------------------------------------------------------------------------*/
+
+static PyObject *Noise_multiFractal( PyObject * self, PyObject * args )
+{
+ float x, y, z, H, lac, oct;
+ int nb = 1;
+ if( !PyArg_ParseTuple
+ ( args, "(fff)fff|i", &x, &y, &z, &H, &lac, &oct, &nb ) )
+ return NULL;
+ return PyFloat_FromDouble( (double)mg_MultiFractal( x, y, z, H, lac, oct, nb ) );
+}
+
+/*------------------------------------------------------------------------*/
+
+static PyObject *Noise_vlNoise( PyObject * self, PyObject * args )
+{
+ float x, y, z, d;
+ int nt1 = 1, nt2 = 1;
+ if( !PyArg_ParseTuple
+ ( args, "(fff)f|ii", &x, &y, &z, &d, &nt1, &nt2 ) )
+ return NULL;
+ return PyFloat_FromDouble( (double)mg_VLNoise( x, y, z, d, nt1, nt2 ) );
+}
+
+/*-------------------------------------------------------------------------*/
+
+static PyObject *Noise_heteroTerrain( PyObject * self, PyObject * args )
+{
+ float x, y, z, H, lac, oct, ofs;
+ int nb = 1;
+ if( !PyArg_ParseTuple
+ ( args, "(fff)ffff|i", &x, &y, &z, &H, &lac, &oct, &ofs, &nb ) )
+ return NULL;
+
+ return PyFloat_FromDouble(
+ (double)mg_HeteroTerrain( x, y, z, H, lac, oct, ofs, nb ) );
+}
+
+/*-------------------------------------------------------------------------*/
+
+static PyObject *Noise_hybridMFractal( PyObject * self, PyObject * args )
+{
+ float x, y, z, H, lac, oct, ofs, gn;
+ int nb = 1;
+ if( !PyArg_ParseTuple
+ ( args, "(fff)fffff|i", &x, &y, &z, &H, &lac, &oct, &ofs, &gn,
+ &nb ) )
+ return NULL;
+
+ return PyFloat_FromDouble(
+ (double)mg_HybridMultiFractal( x, y, z, H, lac, oct, ofs, gn, nb) );
+}
+
+/*------------------------------------------------------------------------*/
+
+static PyObject *Noise_ridgedMFractal( PyObject * self, PyObject * args )
+{
+ float x, y, z, H, lac, oct, ofs, gn;
+ int nb = 1;
+ if( !PyArg_ParseTuple
+ ( args, "(fff)fffff|i", &x, &y, &z, &H, &lac, &oct, &ofs, &gn,
+ &nb ) )
+ return NULL;
+ return PyFloat_FromDouble(
+ (double)mg_RidgedMultiFractal( x, y, z, H, lac, oct, ofs, gn, nb) );
+}
+
+/*-------------------------------------------------------------------------*/
+
+static PyObject *Noise_voronoi( PyObject * self, PyObject * args )
+{
+ float x, y, z, da[4], pa[12];
+ int dtype = 0;
+ float me = 2.5; /* default minkovsky exponent */
+ if( !PyArg_ParseTuple( args, "(fff)|if", &x, &y, &z, &dtype, &me ) )
+ return NULL;
+ voronoi( x, y, z, da, pa, me, dtype );
+ return Py_BuildValue( "[[ffff][[fff][fff][fff][fff]]]",
+ da[0], da[1], da[2], da[3],
+ pa[0], pa[1], pa[2],
+ pa[3], pa[4], pa[5],
+ pa[6], pa[7], pa[8], pa[9], pa[10], pa[11] );
+}
+
+/*-------------------------------------------------------------------------*/
+
+static PyObject *Noise_cellNoise( PyObject * self, PyObject * args )
+{
+ float x, y, z;
+ if( !PyArg_ParseTuple( args, "(fff)", &x, &y, &z ) )
+ return NULL;
+ return Py_BuildValue( "f", cellNoise( x, y, z ) );
+}
+
+/*--------------------------------------------------------------------------*/
+
+static PyObject *Noise_cellNoiseV( PyObject * self, PyObject * args )
+{
+ float x, y, z, ca[3];
+ if( !PyArg_ParseTuple( args, "(fff)", &x, &y, &z ) )
+ return NULL;
+ cellNoiseV( x, y, z, ca );
+ return Py_BuildValue( "[fff]", ca[0], ca[1], ca[2] );
+}
+
+/*--------------------------------------------------------------------------*/
+/* For all other Blender modules, this stuff seems to be put in a header file.
+ This doesn't seem really appropriate to me, so I just put it here, feel free to change it.
+ In the original module I actually kept the docs stings with the functions themselves,
+ but I grouped them here so that it can easily be moved to a header if anyone thinks that is necessary. */
+
+static char random__doc__[] = "() No arguments.\n\n\
+Returns a random floating point number in the range [0, 1)";
+
+static char randuvec__doc__[] =
+ "() No arguments.\n\nReturns a random unit vector (3-float list).";
+
+static char setRandomSeed__doc__[] = "(seed value)\n\n\
+Initializes random number generator.\n\
+if seed is zero, the current time will be used instead.";
+
+static char noise__doc__[] = "((x,y,z) tuple, [noisetype])\n\n\
+Returns general noise of the optional specified type.\n\
+Optional argument noisetype determines the type of noise, STDPERLIN by default, see NoiseTypes.";
+
+static char vNoise__doc__[] = "((x,y,z) tuple, [noisetype])\n\n\
+Returns noise vector (3-float list) of the optional specified type.\
+Optional argument noisetype determines the type of noise, STDPERLIN by default, see NoiseTypes.";
+
+static char turbulence__doc__[] =
+ "((x,y,z) tuple, octaves, hard, [noisebasis], [ampscale], [freqscale])\n\n\
+Returns general turbulence value using the optional specified noisebasis function.\n\
+octaves (integer) is the number of noise values added.\n\
+hard (bool), when false (0) returns 'soft' noise, when true (1) returns 'hard' noise (returned value always positive).\n\
+Optional arguments:\n\
+noisebasis determines the type of noise used for the turbulence, STDPERLIN by default, see NoiseTypes.\n\
+ampscale sets the amplitude scale value of the noise frequencies added, 0.5 by default.\n\
+freqscale sets the frequency scale factor, 2.0 by default.";
+
+static char vTurbulence__doc__[] =
+ "((x,y,z) tuple, octaves, hard, [noisebasis], [ampscale], [freqscale])\n\n\
+Returns general turbulence vector (3-float list) using the optional specified noisebasis function.\n\
+octaves (integer) is the number of noise values added.\n\
+hard (bool), when false (0) returns 'soft' noise, when true (1) returns 'hard' noise (returned vector always positive).\n\
+Optional arguments:\n\
+noisebasis determines the type of noise used for the turbulence, STDPERLIN by default, see NoiseTypes.\n\
+ampscale sets the amplitude scale value of the noise frequencies added, 0.5 by default.\n\
+freqscale sets the frequency scale factor, 2.0 by default.";
+
+static char fBm__doc__[] =
+ "((x,y,z) tuple, H, lacunarity, octaves, [noisebasis])\n\n\
+Returns Fractal Brownian Motion noise value(fBm).\n\
+H is the fractal increment parameter.\n\
+lacunarity is the gap between successive frequencies.\n\
+octaves is the number of frequencies in the fBm.\n\
+Optional argument noisebasis determines the type of noise used for the turbulence, STDPERLIN by default, see NoiseTypes.";
+
+static char multiFractal__doc__[] =
+ "((x,y,z) tuple, H, lacunarity, octaves, [noisebasis])\n\n\
+Returns Multifractal noise value.\n\
+H determines the highest fractal dimension.\n\
+lacunarity is gap between successive frequencies.\n\
+octaves is the number of frequencies in the fBm.\n\
+Optional argument noisebasis determines the type of noise used for the turbulence, STDPERLIN by default, see NoiseTypes.";
+
+static char vlNoise__doc__[] =
+ "((x,y,z) tuple, distortion, [noisetype1], [noisetype2])\n\n\
+Returns Variable Lacunarity Noise value, a distorted variety of noise.\n\
+distortion sets the amount of distortion.\n\
+Optional arguments noisetype1 and noisetype2 set the noisetype to distort and the noisetype used for the distortion respectively.\n\
+See NoiseTypes, both are STDPERLIN by default.";
+
+static char heteroTerrain__doc__[] =
+ "((x,y,z) tuple, H, lacunarity, octaves, offset, [noisebasis])\n\n\
+returns Heterogeneous Terrain value\n\
+H determines the fractal dimension of the roughest areas.\n\
+lacunarity is the gap between successive frequencies.\n\
+octaves is the number of frequencies in the fBm.\n\
+offset raises the terrain from 'sea level'.\n\
+Optional argument noisebasis determines the type of noise used for the turbulence, STDPERLIN by default, see NoiseTypes.";
+
+static char hybridMFractal__doc__[] =
+ "((x,y,z) tuple, H, lacunarity, octaves, offset, gain, [noisebasis])\n\n\
+returns Hybrid Multifractal value.\n\
+H determines the fractal dimension of the roughest areas.\n\
+lacunarity is the gap between successive frequencies.\n\
+octaves is the number of frequencies in the fBm.\n\
+offset raises the terrain from 'sea level'.\n\
+gain scales the values.\n\
+Optional argument noisebasis determines the type of noise used for the turbulence, STDPERLIN by default, see NoiseTypes.";
+
+static char ridgedMFractal__doc__[] =
+ "((x,y,z) tuple, H, lacunarity, octaves, offset, gain [noisebasis])\n\n\
+returns Ridged Multifractal value.\n\
+H determines the fractal dimension of the roughest areas.\n\
+lacunarity is the gap between successive frequencies.\n\
+octaves is the number of frequencies in the fBm.\n\
+offset raises the terrain from 'sea level'.\n\
+gain scales the values.\n\
+Optional argument noisebasis determines the type of noise used for the turbulence, STDPERLIN by default, see NoiseTypes.";
+
+static char voronoi__doc__[] =
+ "((x,y,z) tuple, distance_metric, [exponent])\n\n\
+returns a list, containing a list of distances in order of closest feature,\n\
+and a list containing the positions of the four closest features\n\
+Optional arguments:\n\
+distance_metric: see DistanceMetrics, default is DISTANCE\n\
+exponent is only used with MINKOVSKY, default is 2.5.";
+
+static char cellNoise__doc__[] = "((x,y,z) tuple)\n\n\
+returns cellnoise float value.";
+
+static char cellNoiseV__doc__[] = "((x,y,z) tuple)\n\n\
+returns cellnoise vector/point/color (3-float list).";
+
+static char Noise__doc__[] = "Blender Noise and Turbulence Module\n\n\
+This module can be used to generate noise of various types.\n\
+This can be used for terrain generation, to create textures,\n\
+make animations more 'animated', object deformation, etc.\n\
+As an example, this code segment when scriptlinked to a framechanged event,\n\
+will make the camera sway randomly about, by changing parameters this can\n\
+look like anything from an earthquake to a very nervous or maybe even drunk cameraman...\n\
+(the camera needs an ipo with at least one Loc & Rot key for this to work!):\n\
+\n\
+\tfrom Blender import Get, Scene, Noise\n\
+\n\
+\t####################################################\n\
+\t# This controls jitter speed\n\
+\tsl = 0.025\n\
+\t# This controls the amount of position jitter\n\
+\tsp = 0.1\n\
+\t# This controls the amount of rotation jitter\n\
+\tsr = 0.25\n\
+\t####################################################\n\
+\n\
+\ttime = Get('curtime')\n\
+\tob = Scene.GetCurrent().getCurrentCamera()\n\
+\tps = (sl*time, sl*time, sl*time)\n\
+\t# To add jitter only when the camera moves, use this next line instead\n\
+\t#ps = (sl*ob.LocX, sl*ob.LocY, sl*ob.LocZ)\n\
+\trv = Noise.vTurbulence(ps, 3, 0, Noise.NoiseTypes.NEWPERLIN)\n\
+\tob.dloc = (sp*rv[0], sp*rv[1], sp*rv[2])\n\
+\tob.drot = (sr*rv[0], sr*rv[1], sr*rv[2])\n\
+\n";
+
+/* Just in case, declarations for a header file */
+/*
+static PyObject *Noise_random(PyObject *self);
+static PyObject *Noise_randuvec(PyObject *self);
+static PyObject *Noise_setRandomSeed(PyObject *self, PyObject *args);
+static PyObject *Noise_noise(PyObject *self, PyObject *args);
+static PyObject *Noise_vNoise(PyObject *self, PyObject *args);
+static PyObject *Noise_turbulence(PyObject *self, PyObject *args);
+static PyObject *Noise_vTurbulence(PyObject *self, PyObject *args);
+static PyObject *Noise_fBm(PyObject *self, PyObject *args);
+static PyObject *Noise_multiFractal(PyObject *self, PyObject *args);
+static PyObject *Noise_vlNoise(PyObject *self, PyObject *args);
+static PyObject *Noise_heteroTerrain(PyObject *self, PyObject *args);
+static PyObject *Noise_hybridMFractal(PyObject *self, PyObject *args);
+static PyObject *Noise_ridgedMFractal(PyObject *self, PyObject *args);
+static PyObject *Noise_voronoi(PyObject *self, PyObject *args);
+static PyObject *Noise_cellNoise(PyObject *self, PyObject *args);
+static PyObject *Noise_cellNoiseV(PyObject *self, PyObject *args);
+*/
+
+static PyMethodDef NoiseMethods[] = {
+ {"setRandomSeed", ( PyCFunction ) Noise_setRandomSeed, METH_VARARGS,
+ setRandomSeed__doc__},
+ {"random", ( PyCFunction ) Noise_random, METH_NOARGS, random__doc__},
+ {"randuvec", ( PyCFunction ) Noise_randuvec, METH_NOARGS,
+ randuvec__doc__},
+ {"noise", ( PyCFunction ) Noise_noise, METH_VARARGS, noise__doc__},
+ {"vNoise", ( PyCFunction ) Noise_vNoise, METH_VARARGS, vNoise__doc__},
+ {"turbulence", ( PyCFunction ) Noise_turbulence, METH_VARARGS,
+ turbulence__doc__},
+ {"vTurbulence", ( PyCFunction ) Noise_vTurbulence, METH_VARARGS,
+ vTurbulence__doc__},
+ {"fBm", ( PyCFunction ) Noise_fBm, METH_VARARGS, fBm__doc__},
+ {"multiFractal", ( PyCFunction ) Noise_multiFractal, METH_VARARGS,
+ multiFractal__doc__},
+ {"vlNoise", ( PyCFunction ) Noise_vlNoise, METH_VARARGS,
+ vlNoise__doc__},
+ {"heteroTerrain", ( PyCFunction ) Noise_heteroTerrain, METH_VARARGS,
+ heteroTerrain__doc__},
+ {"hybridMFractal", ( PyCFunction ) Noise_hybridMFractal, METH_VARARGS,
+ hybridMFractal__doc__},
+ {"ridgedMFractal", ( PyCFunction ) Noise_ridgedMFractal, METH_VARARGS,
+ ridgedMFractal__doc__},
+ {"voronoi", ( PyCFunction ) Noise_voronoi, METH_VARARGS,
+ voronoi__doc__},
+ {"cellNoise", ( PyCFunction ) Noise_cellNoise, METH_VARARGS,
+ cellNoise__doc__},
+ {"cellNoiseV", ( PyCFunction ) Noise_cellNoiseV, METH_VARARGS,
+ cellNoiseV__doc__},
+ {NULL, NULL, 0, NULL}
+};
+
+/*----------------------------------------------------------------------*/
+
+PyObject *Noise_Init(void)
+{
+ PyObject *NoiseTypes, *DistanceMetrics,
+ *md =
+ Py_InitModule3( "Blender.Noise", NoiseMethods, Noise__doc__ );
+
+ /* use current time as seed for random number generator by default */
+ setRndSeed( 0 );
+
+ /* Constant noisetype dictionary */
+ NoiseTypes = PyConstant_New( );
+ if( NoiseTypes ) {
+ BPy_constant *nt = ( BPy_constant * ) NoiseTypes;
+ PyConstant_Insert( nt, "BLENDER",
+ PyInt_FromLong( TEX_BLENDER ) );
+ PyConstant_Insert( nt, "STDPERLIN",
+ PyInt_FromLong( TEX_STDPERLIN ) );
+ PyConstant_Insert( nt, "NEWPERLIN",
+ PyInt_FromLong( TEX_NEWPERLIN ) );
+ PyConstant_Insert( nt, "VORONOI_F1",
+ PyInt_FromLong( TEX_VORONOI_F1 ) );
+ PyConstant_Insert( nt, "VORONOI_F2",
+ PyInt_FromLong( TEX_VORONOI_F2 ) );
+ PyConstant_Insert( nt, "VORONOI_F3",
+ PyInt_FromLong( TEX_VORONOI_F3 ) );
+ PyConstant_Insert( nt, "VORONOI_F4",
+ PyInt_FromLong( TEX_VORONOI_F4 ) );
+ PyConstant_Insert( nt, "VORONOI_F2F1",
+ PyInt_FromLong( TEX_VORONOI_F2F1 ) );
+ PyConstant_Insert( nt, "VORONOI_CRACKLE",
+ PyInt_FromLong( TEX_VORONOI_CRACKLE ) );
+ PyConstant_Insert( nt, "CELLNOISE",
+ PyInt_FromLong( TEX_CELLNOISE ) );
+ PyModule_AddObject( md, "NoiseTypes", NoiseTypes );
+ }
+
+ /* Constant distance metric dictionary for voronoi */
+ DistanceMetrics = PyConstant_New( );
+ if( DistanceMetrics ) {
+ BPy_constant *dm = ( BPy_constant * ) DistanceMetrics;
+ PyConstant_Insert( dm, "DISTANCE",
+ PyInt_FromLong( TEX_DISTANCE ) );
+ PyConstant_Insert( dm, "DISTANCE_SQUARED",
+ PyInt_FromLong( TEX_DISTANCE_SQUARED ) );
+ PyConstant_Insert( dm, "MANHATTAN",
+ PyInt_FromLong( TEX_MANHATTAN ) );
+ PyConstant_Insert( dm, "CHEBYCHEV",
+ PyInt_FromLong( TEX_CHEBYCHEV ) );
+ PyConstant_Insert( dm, "MINKOVSKY_HALF",
+ PyInt_FromLong( TEX_MINKOVSKY_HALF ) );
+ PyConstant_Insert( dm, "MINKOVSKY_FOUR",
+ PyInt_FromLong( TEX_MINKOVSKY_FOUR ) );
+ PyConstant_Insert( dm, "MINKOVSKY",
+ PyInt_FromLong( TEX_MINKOVSKY ) );
+ PyModule_AddObject( md, "DistanceMetrics", DistanceMetrics );
+ }
+
+ return md;
+}
diff --git a/source/blender/python/api2_2x/Object.c b/source/blender/python/api2_2x/Object.c
new file mode 100644
index 00000000000..e62f685cdf5
--- /dev/null
+++ b/source/blender/python/api2_2x/Object.c
@@ -0,0 +1,5942 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ *
+ * The Object module provides generic access to Objects of various types via
+ * the Python interface.
+ *
+ *
+ * Contributor(s): Michel Selten, Willian Germano, Jacques Guignot,
+ * Joseph Gilbert, Stephen Swaney, Bala Gi, Campbell Barton, Johnny Matthews,
+ * Ken Hughes, Alex Mole, Jean-Michel Soler
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+struct SpaceIpo;
+struct rctf;
+
+#include "Object.h" /*This must come first */
+
+#include "DNA_object_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_object_force.h"
+#include "DNA_userdef_types.h"
+#include "DNA_key_types.h" /* for pinShape and activeShape */
+
+#include "BKE_action.h"
+#include "BKE_anim.h" /* used for dupli-objects */
+#include "BKE_depsgraph.h"
+#include "BKE_effect.h"
+#include "BKE_font.h"
+#include "BKE_property.h"
+#include "BKE_mball.h"
+#include "BKE_softbody.h"
+#include "BKE_utildefines.h"
+#include "BKE_armature.h"
+#include "BKE_lattice.h"
+#include "BKE_mesh.h"
+#include "BKE_library.h"
+#include "BKE_object.h"
+#include "BKE_curve.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_scene.h"
+#include "BKE_nla.h"
+#include "BKE_material.h"
+#include "BKE_modifier.h"
+#include "BKE_idprop.h"
+#include "BKE_object.h"
+#include "BKE_key.h" /* for setting the activeShape */
+#include "BKE_displist.h"
+
+#include "BSE_editipo.h"
+#include "BSE_edit.h"
+
+#include "BIF_space.h"
+#include "BIF_editview.h"
+#include "BIF_drawscene.h"
+#include "BIF_meshtools.h"
+#include "BIF_editarmature.h"
+#include "BIF_editaction.h"
+#include "BIF_editnla.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+
+#include "BDR_editobject.h"
+#include "BDR_editcurve.h"
+#include "BDR_drawobject.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "mydevice.h"
+#include "blendef.h"
+#include "Scene.h"
+#include "Mathutils.h"
+#include "Mesh.h"
+#include "NMesh.h"
+#include "Curve.h"
+#include "Ipo.h"
+#include "Armature.h"
+#include "Pose.h"
+#include "Camera.h"
+#include "Lamp.h"
+#include "Lattice.h"
+#include "Text.h"
+#include "Text3d.h"
+#include "Metaball.h"
+#include "Draw.h"
+#include "NLA.h"
+#include "logic.h"
+#include "Effect.h"
+#include "Group.h"
+#include "Modifier.h"
+#include "Constraint.h"
+#include "gen_utils.h"
+#include "gen_library.h"
+#include "EXPP_interface.h"
+#include "BIF_editkey.h"
+#include "IDProp.h"
+
+/* Defines for insertIpoKey */
+
+#define IPOKEY_LOC 0
+#define IPOKEY_ROT 1
+#define IPOKEY_SIZE 2
+#define IPOKEY_LOCROT 3
+#define IPOKEY_LOCROTSIZE 4
+#define IPOKEY_PI_STRENGTH 5
+#define IPOKEY_PI_FALLOFF 6
+#define IPOKEY_PI_MAXDIST 7 /*Not Ready Yet*/
+#define IPOKEY_PI_SURFACEDAMP 8
+#define IPOKEY_PI_RANDOMDAMP 9
+#define IPOKEY_PI_PERM 10
+
+#define PFIELD_FORCE 1
+#define PFIELD_VORTEX 2
+#define PFIELD_MAGNET 3
+#define PFIELD_WIND 4
+
+enum obj_consts {
+ EXPP_OBJ_ATTR_LOC_X = 0,
+ EXPP_OBJ_ATTR_LOC_Y,
+ EXPP_OBJ_ATTR_LOC_Z,
+ EXPP_OBJ_ATTR_DLOC_X,
+ EXPP_OBJ_ATTR_DLOC_Y,
+ EXPP_OBJ_ATTR_DLOC_Z,
+ EXPP_OBJ_ATTR_ROT_X,
+ EXPP_OBJ_ATTR_ROT_Y,
+ EXPP_OBJ_ATTR_ROT_Z,
+ EXPP_OBJ_ATTR_DROT_X,
+ EXPP_OBJ_ATTR_DROT_Y,
+ EXPP_OBJ_ATTR_DROT_Z,
+ EXPP_OBJ_ATTR_SIZE_X,
+ EXPP_OBJ_ATTR_SIZE_Y,
+ EXPP_OBJ_ATTR_SIZE_Z,
+ EXPP_OBJ_ATTR_DSIZE_X,
+ EXPP_OBJ_ATTR_DSIZE_Y,
+ EXPP_OBJ_ATTR_DSIZE_Z,
+ EXPP_OBJ_ATTR_LOC,
+ EXPP_OBJ_ATTR_DLOC,
+ EXPP_OBJ_ATTR_DROT,
+ EXPP_OBJ_ATTR_SIZE,
+ EXPP_OBJ_ATTR_DSIZE,
+ EXPP_OBJ_ATTR_LAYERMASK,
+ EXPP_OBJ_ATTR_COLBITS,
+ EXPP_OBJ_ATTR_DRAWMODE,
+ EXPP_OBJ_ATTR_DRAWTYPE,
+ EXPP_OBJ_ATTR_DUPON,
+ EXPP_OBJ_ATTR_DUPOFF,
+ EXPP_OBJ_ATTR_DUPSTA,
+ EXPP_OBJ_ATTR_DUPEND,
+ EXPP_OBJ_ATTR_TIMEOFFSET,
+ EXPP_OBJ_ATTR_DRAWSIZE,
+ EXPP_OBJ_ATTR_PARENT_TYPE,
+ EXPP_OBJ_ATTR_PASSINDEX,
+ EXPP_OBJ_ATTR_ACT_MATERIAL,
+ EXPP_OBJ_ATTR_ACT_SHAPE,
+
+ EXPP_OBJ_ATTR_PI_SURFACEDAMP, /* these need to stay together */
+ EXPP_OBJ_ATTR_PI_RANDOMDAMP, /* and in order */
+ EXPP_OBJ_ATTR_PI_PERM,
+ EXPP_OBJ_ATTR_PI_STRENGTH,
+ EXPP_OBJ_ATTR_PI_FALLOFF,
+ EXPP_OBJ_ATTR_PI_MAXDIST,
+ EXPP_OBJ_ATTR_PI_SBDAMP,
+ EXPP_OBJ_ATTR_PI_SBIFACETHICK,
+ EXPP_OBJ_ATTR_PI_SBOFACETHICK,
+
+ EXPP_OBJ_ATTR_SB_NODEMASS, /* these need to stay together */
+ EXPP_OBJ_ATTR_SB_GRAV, /* and in order */
+ EXPP_OBJ_ATTR_SB_MEDIAFRICT,
+ EXPP_OBJ_ATTR_SB_RKLIMIT,
+ EXPP_OBJ_ATTR_SB_PHYSICSSPEED,
+ EXPP_OBJ_ATTR_SB_GOALSPRING,
+ EXPP_OBJ_ATTR_SB_GOALFRICT,
+ EXPP_OBJ_ATTR_SB_MINGOAL,
+ EXPP_OBJ_ATTR_SB_MAXGOAL,
+ EXPP_OBJ_ATTR_SB_DEFGOAL,
+ EXPP_OBJ_ATTR_SB_INSPRING,
+ EXPP_OBJ_ATTR_SB_INFRICT,
+
+};
+
+#define EXPP_OBJECT_DRAWSIZEMIN 0.01f
+#define EXPP_OBJECT_DRAWSIZEMAX 10.0f
+
+/* clamping and range values for particle interaction settings */
+#define EXPP_OBJECT_PIDAMP_MIN 0.0f
+#define EXPP_OBJECT_PIDAMP_MAX 1.0f
+#define EXPP_OBJECT_PIRDAMP_MIN 0.0f
+#define EXPP_OBJECT_PIRDAMP_MAX 1.0f
+#define EXPP_OBJECT_PIPERM_MIN 0.0f
+#define EXPP_OBJECT_PIPERM_MAX 1.0f
+#define EXPP_OBJECT_PISTRENGTH_MIN 0.0f
+#define EXPP_OBJECT_PISTRENGTH_MAX 1000.0f
+#define EXPP_OBJECT_PIPOWER_MIN 0.0f
+#define EXPP_OBJECT_PIPOWER_MAX 10.0f
+#define EXPP_OBJECT_PIMAXDIST_MIN 0.0f
+#define EXPP_OBJECT_PIMAXDIST_MAX 1000.0f
+#define EXPP_OBJECT_PISBDAMP_MIN 0.0f
+#define EXPP_OBJECT_PISBDAMP_MAX 1.0f
+#define EXPP_OBJECT_PISBIFTMIN 0.001f
+#define EXPP_OBJECT_PISBIFTMAX 1.0f
+#define EXPP_OBJECT_PISBOFTMIN 0.001f
+#define EXPP_OBJECT_PISBOFTMAX 1.0f
+
+/* clamping and range values for softbody settings */
+#define EXPP_OBJECT_SBMASS_MIN 0.0f
+#define EXPP_OBJECT_SBMASS_MAX 50.0f
+#define EXPP_OBJECT_SBGRAVITY_MIN 0.0f
+#define EXPP_OBJECT_SBGRAVITY_MAX 10.0f
+#define EXPP_OBJECT_SBFRICTION_MIN 0.0f
+#define EXPP_OBJECT_SBFRICTION_MAX 10.0f
+#define EXPP_OBJECT_SBSPEED_MIN 0.01f
+#define EXPP_OBJECT_SBSPEED_MAX 100.0f
+#define EXPP_OBJECT_SBERRORLIMIT_MIN 0.01f
+#define EXPP_OBJECT_SBERRORLIMIT_MAX 1.0f
+#define EXPP_OBJECT_SBGOALSPRING_MIN 0.0f
+#define EXPP_OBJECT_SBGOALSPRING_MAX 0.999f
+#define EXPP_OBJECT_SBGOALFRICT_MIN 0.0f
+#define EXPP_OBJECT_SBGOALFRICT_MAX 10.0f
+#define EXPP_OBJECT_SBMINGOAL_MIN 0.0f
+#define EXPP_OBJECT_SBMINGOAL_MAX 1.0f
+#define EXPP_OBJECT_SBMAXGOAL_MIN 0.0f
+#define EXPP_OBJECT_SBMAXGOAL_MAX 1.0f
+#define EXPP_OBJECT_SBINSPRING_MIN 0.0f
+#define EXPP_OBJECT_SBINSPRING_MAX 0.999f
+#define EXPP_OBJECT_SBINFRICT_MIN 0.0f
+#define EXPP_OBJECT_SBINFRICT_MAX 10.0f
+#define EXPP_OBJECT_SBDEFGOAL_MIN 0.0f
+#define EXPP_OBJECT_SBDEFGOAL_MAX 1.0f
+#define EXPP_OBJECT_SBNODEMASSMIN 0.001f
+#define EXPP_OBJECT_SBNODEMASSMAX 50.0f
+#define EXPP_OBJECT_SBGRAVMIN 0.0f
+#define EXPP_OBJECT_SBGRAVMAX 10.0f
+#define EXPP_OBJECT_SBMEDIAFRICTMIN 0.0f
+#define EXPP_OBJECT_SBMEDIAFRICTMAX 10.0f
+#define EXPP_OBJECT_SBRKLIMITMIN 0.01f
+#define EXPP_OBJECT_SBRKLIMITMAX 1.0f
+#define EXPP_OBJECT_SBPHYSICSSPEEDMIN 0.01f
+#define EXPP_OBJECT_SBPHYSICSSPEEDMAX 100.0f
+#define EXPP_OBJECT_SBGOALSPRINGMIN 0.0f
+#define EXPP_OBJECT_SBGOALSPRINGMAX 0.999f
+#define EXPP_OBJECT_SBGOALFRICTMIN 0.0f
+#define EXPP_OBJECT_SBGOALFRICTMAX 10.0f
+#define EXPP_OBJECT_SBMINGOALMIN 0.0f
+#define EXPP_OBJECT_SBMINGOALMAX 1.0f
+#define EXPP_OBJECT_SBMAXGOALMIN 0.0f
+#define EXPP_OBJECT_SBMAXGOALMAX 1.0f
+#define EXPP_OBJECT_SBDEFGOALMIN 0.0f
+#define EXPP_OBJECT_SBDEFGOALMAX 1.0f
+#define EXPP_OBJECT_SBINSPRINGMIN 0.0f
+#define EXPP_OBJECT_SBINSPRINGMAX 0.999f
+#define EXPP_OBJECT_SBINFRICTMIN 0.0f
+#define EXPP_OBJECT_SBINFRICTMAX 10.0f
+
+/*****************************************************************************/
+/* Python API function prototypes for the Blender module. */
+/*****************************************************************************/
+static PyObject *M_Object_New( PyObject * self, PyObject * args );
+PyObject *M_Object_Get( PyObject * self, PyObject * args );
+static PyObject *M_Object_GetSelected( PyObject * self );
+static PyObject *M_Object_Duplicate( PyObject * self, PyObject * args, PyObject *kwd);
+
+/* HELPER FUNCTION FOR PARENTING */
+static PyObject *internal_makeParent(Object *parent, PyObject *py_child, int partype, int noninverse, int fast, int v1, int v2, int v3, char *bonename);
+
+/*****************************************************************************/
+/* The following string definitions are used for documentation strings. */
+/* In Python these will be written to the console when doing a */
+/* Blender.Object.__doc__ */
+/*****************************************************************************/
+char M_Object_doc[] = "The Blender Object module\n\n\
+This module provides access to **Object Data** in Blender.\n";
+
+char M_Object_New_doc[] =
+ "(type) - Add a new object of type 'type' in the current scene";
+
+char M_Object_Get_doc[] =
+ "(name) - return the object with the name 'name', returns None if not\
+ found.\n\
+ If 'name' is not specified, it returns a list of all objects in the\n\
+ current scene.";
+
+char M_Object_GetSelected_doc[] =
+ "() - Returns a list of selected Objects in the active layer(s)\n\
+The active object is the first in the list, if visible";
+
+char M_Object_Duplicate_doc[] =
+ "(linked) - Duplicate all selected, visible objects in the current scene";
+
+
+/*****************************************************************************/
+/* Python method structure definition for Blender.Object module: */
+/*****************************************************************************/
+struct PyMethodDef M_Object_methods[] = {
+ {"New", ( PyCFunction ) M_Object_New, METH_VARARGS,
+ M_Object_New_doc},
+ {"Get", ( PyCFunction ) M_Object_Get, METH_VARARGS,
+ M_Object_Get_doc},
+ {"GetSelected", ( PyCFunction ) M_Object_GetSelected, METH_NOARGS,
+ M_Object_GetSelected_doc},
+ {"Duplicate", ( PyCFunction ) M_Object_Duplicate, METH_VARARGS | METH_KEYWORDS,
+ M_Object_Duplicate_doc},
+ {NULL, NULL, 0, NULL}
+};
+
+
+/*****************************************************************************/
+/* Python BPy_Object methods declarations: */
+/*****************************************************************************/
+static int setupSB(Object* ob); /*Make sure Softbody Pointer is initialized */
+static int setupPI(Object* ob);
+
+static PyObject *Object_buildParts( BPy_Object * self );
+static PyObject *Object_clearIpo( BPy_Object * self );
+static PyObject *Object_clrParent( BPy_Object * self, PyObject * args );
+static PyObject *Object_clearTrack( BPy_Object * self, PyObject * args );
+static PyObject *Object_getData(BPy_Object *self, PyObject *args, PyObject *kwd);
+static PyObject *Object_getDeltaLocation( BPy_Object * self );
+static PyObject *Object_getDrawMode( BPy_Object * self );
+static PyObject *Object_getDrawType( BPy_Object * self );
+static PyObject *Object_GetEuler( BPy_Object * self, PyObject * args );
+static PyObject *Object_getInverseMatrix( BPy_Object * self );
+static PyObject *Object_getIpo( BPy_Object * self );
+static PyObject *Object_getLocation( BPy_Object * self, PyObject * args );
+static PyObject *Object_getMaterials( BPy_Object * self, PyObject * args );
+static PyObject *Object_getMatrix( BPy_Object * self, PyObject * args );
+static PyObject *Object_getParent( BPy_Object * self );
+static PyObject *Object_getParentBoneName( BPy_Object * self );
+static int Object_setParentBoneName( BPy_Object * self, PyObject * value );
+static PyObject *Object_getSize( BPy_Object * self, PyObject * args );
+static PyObject *Object_getTimeOffset( BPy_Object * self );
+static PyObject *Object_getTracked( BPy_Object * self );
+static PyObject *Object_getType( BPy_Object * self );
+static PyObject *Object_getBoundBox( BPy_Object * self );
+static PyObject *Object_getAction( BPy_Object * self );
+static PyObject *Object_getPose( BPy_Object * self );
+static PyObject *Object_evaluatePose( BPy_Object * self, PyObject *args );
+static PyObject *Object_getSelected( BPy_Object * self );
+static PyObject *Object_makeDisplayList( BPy_Object * self );
+static PyObject *Object_link( BPy_Object * self, PyObject * args );
+static PyObject *Object_makeParent( BPy_Object * self, PyObject * args );
+static PyObject *Object_join( BPy_Object * self, PyObject * args );
+static PyObject *Object_makeParentDeform( BPy_Object * self, PyObject * args );
+static PyObject *Object_makeParentVertex( BPy_Object * self, PyObject * args );
+static PyObject *Object_makeParentBone( BPy_Object * self, PyObject * args );
+static PyObject *Object_materialUsage( void );
+static PyObject *Object_getDupliObjects ( BPy_Object * self);
+static PyObject *Object_getEffects( BPy_Object * self );
+static PyObject *Object_setDeltaLocation( BPy_Object * self, PyObject * args );
+static PyObject *Object_SetDrawMode( BPy_Object * self, PyObject * args );
+static PyObject *Object_SetDrawType( BPy_Object * self, PyObject * args );
+static PyObject *Object_SetEuler( BPy_Object * self, PyObject * args );
+static PyObject *Object_SetMatrix( BPy_Object * self, PyObject * args );
+static PyObject *Object_SetIpo( BPy_Object * self, PyObject * args );
+static PyObject *Object_insertIpoKey( BPy_Object * self, PyObject * args );
+static PyObject *Object_insertPoseKey( BPy_Object * self, PyObject * args );
+static PyObject *Object_insertCurrentPoseKey( BPy_Object * self, PyObject * args );
+static PyObject *Object_setConstraintInfluenceForBone( BPy_Object * self, PyObject * args );
+static PyObject *Object_setLocation( BPy_Object * self, PyObject * args );
+static PyObject *Object_setMaterials( BPy_Object * self, PyObject * args );
+static PyObject *Object_setSize( BPy_Object * self, PyObject * args );
+static PyObject *Object_setTimeOffset( BPy_Object * self, PyObject * args );
+static PyObject *Object_makeTrack( BPy_Object * self, PyObject * args );
+static PyObject *Object_shareFrom( BPy_Object * self, PyObject * args );
+static PyObject *Object_Select( BPy_Object * self, PyObject * args );
+static PyObject *Object_getAllProperties( BPy_Object * self );
+static PyObject *Object_addProperty( BPy_Object * self, PyObject * args );
+static PyObject *Object_removeProperty( BPy_Object * self, PyObject * args );
+static PyObject *Object_getProperty( BPy_Object * self, PyObject * args );
+static PyObject *Object_removeAllProperties( BPy_Object * self );
+static PyObject *Object_copyAllPropertiesTo( BPy_Object * self,
+ PyObject * args );
+static PyObject *Object_getScriptLinks( BPy_Object * self, PyObject * value );
+static PyObject *Object_addScriptLink( BPy_Object * self, PyObject * args );
+static PyObject *Object_clearScriptLinks( BPy_Object * self, PyObject *args );
+static PyObject *Object_getPIStrength( BPy_Object * self );
+static PyObject *Object_setPIStrength( BPy_Object * self, PyObject * args );
+static PyObject *Object_getPIFalloff( BPy_Object * self );
+static PyObject *Object_setPIFalloff( BPy_Object * self, PyObject * args );
+static PyObject *Object_getPIMaxDist( BPy_Object * self );
+static PyObject *Object_setPIMaxDist( BPy_Object * self, PyObject * args );
+static PyObject *Object_getPIUseMaxDist( BPy_Object * self );
+static PyObject *Object_SetPIUseMaxDist( BPy_Object * self, PyObject * args );
+static PyObject *Object_getPIType( BPy_Object * self );
+static PyObject *Object_SetPIType( BPy_Object * self, PyObject * args );
+static PyObject *Object_getPIPerm( BPy_Object * self );
+static PyObject *Object_SetPIPerm( BPy_Object * self, PyObject * args );
+static PyObject *Object_getPIRandomDamp( BPy_Object * self );
+static PyObject *Object_setPIRandomDamp( BPy_Object * self, PyObject * args );
+static PyObject *Object_getPISurfaceDamp( BPy_Object * self );
+static PyObject *Object_SetPISurfaceDamp( BPy_Object * self, PyObject * args );
+static PyObject *Object_getPIDeflection( BPy_Object * self );
+static PyObject *Object_SetPIDeflection( BPy_Object * self, PyObject * args );
+
+static int Object_setRBMass( BPy_Object * self, PyObject * args );
+static int Object_setRBFlags( BPy_Object * self, PyObject * args );
+static int Object_setRBShapeBoundType( BPy_Object * self, PyObject * args );
+
+static PyObject *Object_getSBMass( BPy_Object * self );
+static PyObject *Object_setSBMass( BPy_Object * self, PyObject * args );
+static PyObject *Object_getSBGravity( BPy_Object * self );
+static PyObject *Object_setSBGravity( BPy_Object * self, PyObject * args );
+static PyObject *Object_getSBFriction( BPy_Object * self );
+static PyObject *Object_setSBFriction( BPy_Object * self, PyObject * args );
+static PyObject *Object_getSBErrorLimit( BPy_Object * self );
+static PyObject *Object_setSBErrorLimit( BPy_Object * self, PyObject * args );
+static PyObject *Object_getSBGoalSpring( BPy_Object * self );
+static PyObject *Object_setSBGoalSpring( BPy_Object * self, PyObject * args );
+static PyObject *Object_getSBGoalFriction( BPy_Object * self );
+static PyObject *Object_setSBGoalFriction( BPy_Object * self, PyObject * args );
+static PyObject *Object_getSBMinGoal( BPy_Object * self );
+static PyObject *Object_setSBMinGoal( BPy_Object * self, PyObject * args );
+static PyObject *Object_getSBMaxGoal( BPy_Object * self );
+static PyObject *Object_setSBMaxGoal( BPy_Object * self, PyObject * args );
+static PyObject *Object_getSBInnerSpring( BPy_Object * self );
+static PyObject *Object_setSBInnerSpring( BPy_Object * self, PyObject * args );
+static PyObject *Object_getSBInnerSpringFriction( BPy_Object * self );
+static PyObject *Object_setSBInnerSpringFriction( BPy_Object * self, PyObject * args );
+
+static PyObject *Object_isSB( BPy_Object * self );
+static PyObject *Object_getSBDefaultGoal( BPy_Object * self );
+static PyObject *Object_setSBDefaultGoal( BPy_Object * self, PyObject * args );
+static PyObject *Object_getSBUseGoal( BPy_Object * self );
+static PyObject *Object_SetSBUseGoal( BPy_Object * self, PyObject * args );
+static PyObject *Object_getSBUseEdges( BPy_Object * self );
+static PyObject *Object_SetSBUseEdges( BPy_Object * self, PyObject * args );
+static PyObject *Object_getSBStiffQuads( BPy_Object * self );
+static PyObject *Object_SetSBStiffQuads( BPy_Object * self, PyObject * args );
+static PyObject *Object_insertShapeKey(BPy_Object * self);
+static PyObject *Object_copyNLA( BPy_Object * self, PyObject * args );
+static PyObject *Object_convertActionToStrip( BPy_Object * self );
+static PyObject *Object_copy(BPy_Object * self); /* __copy__ */
+
+/*****************************************************************************/
+/* Python BPy_Object methods table: */
+/*****************************************************************************/
+static PyMethodDef BPy_Object_methods[] = {
+ /* name, method, flags, doc */
+ {"buildParts", ( PyCFunction ) Object_buildParts, METH_NOARGS,
+ "Recalcs particle system (if any) "},
+ {"getIpo", ( PyCFunction ) Object_getIpo, METH_NOARGS,
+ "Returns the ipo of this object (if any) "},
+ {"clrParent", ( PyCFunction ) Object_clrParent, METH_VARARGS,
+ "Clears parent object. Optionally specify:\n\
+mode\n\tnonzero: Keep object transform\nfast\n\t>0: Don't update scene \
+hierarchy (faster)"},
+ {"clearTrack", ( PyCFunction ) Object_clearTrack, METH_VARARGS,
+ "Make this object not track another anymore. Optionally specify:\n\
+mode\n\t2: Keep object transform\nfast\n\t>0: Don't update scene \
+hierarchy (faster)"},
+ {"getData", ( PyCFunction ) Object_getData, METH_VARARGS | METH_KEYWORDS,
+ "(name_only = 0, mesh = 0) - Returns the datablock object containing the object's \
+data, e.g. Mesh.\n\
+If 'name_only' is nonzero or True, only the name of the datablock is returned"},
+ {"getDeltaLocation", ( PyCFunction ) Object_getDeltaLocation,
+ METH_NOARGS,
+ "Returns the object's delta location (x, y, z)"},
+ {"getDrawMode", ( PyCFunction ) Object_getDrawMode, METH_NOARGS,
+ "Returns the object draw modes"},
+ {"getDrawType", ( PyCFunction ) Object_getDrawType, METH_NOARGS,
+ "Returns the object draw type"},
+ {"getAction", ( PyCFunction ) Object_getAction, METH_NOARGS,
+ "Returns the active action for this object"},
+ {"evaluatePose", ( PyCFunction ) Object_evaluatePose, METH_VARARGS,
+ "(framenum) - Updates the pose to a certain frame number when the Object is\
+ bound to an Action"},
+ {"getPose", ( PyCFunction ) Object_getPose, METH_NOARGS,
+ "() - returns the pose from an object if it exists, else None"},
+ {"isSelected", ( PyCFunction ) Object_getSelected, METH_NOARGS,
+ "Return a 1 or 0 depending on whether the object is selected"},
+ {"getEuler", ( PyCFunction ) Object_GetEuler, METH_VARARGS,
+ "(space = 'localspace' / 'worldspace') - Returns the object's rotation as Euler rotation vector\n\
+(rotX, rotY, rotZ)"},
+ {"getInverseMatrix", ( PyCFunction ) Object_getInverseMatrix,
+ METH_NOARGS,
+ "Returns the object's inverse matrix"},
+ {"getLocation", ( PyCFunction ) Object_getLocation, METH_VARARGS,
+ "(space = 'localspace' / 'worldspace') - Returns the object's location (x, y, z)\n\
+"},
+ {"getMaterials", ( PyCFunction ) Object_getMaterials, METH_VARARGS,
+ "(i = 0) - Returns list of materials assigned to the object.\n\
+if i is nonzero, empty slots are not ignored: they are returned as None's."},
+ {"getMatrix", ( PyCFunction ) Object_getMatrix, METH_VARARGS,
+ "(str = 'worldspace') - Returns the object matrix.\n\
+(str = 'worldspace') - the desired matrix: worldspace (default), localspace\n\
+or old_worldspace.\n\
+\n\
+'old_worldspace' was the only behavior before Blender 2.34. With it the\n\
+matrix is not updated for changes made by the script itself\n\
+(like obj.LocX = 10) until a redraw happens, either called by the script or\n\
+automatic when the script finishes."},
+ {"getName", ( PyCFunction ) GenericLib_getName, METH_NOARGS,
+ "Returns the name of the object"},
+ {"getParent", ( PyCFunction ) Object_getParent, METH_NOARGS,
+ "Returns the object's parent object"},
+ {"getParentBoneName", ( PyCFunction ) Object_getParentBoneName, METH_NOARGS,
+ "Returns None, or the 'sub-name' of the parent (eg. Bone name)"},
+ {"getSize", ( PyCFunction ) Object_getSize, METH_VARARGS,
+ "(space = 'localspace' / 'worldspace') - Returns the object's size (x, y, z)"},
+ {"getTimeOffset", ( PyCFunction ) Object_getTimeOffset, METH_NOARGS,
+ "Returns the object's time offset"},
+ {"getTracked", ( PyCFunction ) Object_getTracked, METH_NOARGS,
+ "Returns the object's tracked object"},
+ {"getType", ( PyCFunction ) Object_getType, METH_NOARGS,
+ "Returns type of string of Object"},
+/* Particle Interaction */
+
+ {"getPIStrength", ( PyCFunction ) Object_getPIStrength, METH_NOARGS,
+ "Returns Particle Interaction Strength"},
+ {"setPIStrength", ( PyCFunction ) Object_setPIStrength, METH_VARARGS,
+ "Sets Particle Interaction Strength"},
+ {"getPIFalloff", ( PyCFunction ) Object_getPIFalloff, METH_NOARGS,
+ "Returns Particle Interaction Falloff"},
+ {"setPIFalloff", ( PyCFunction ) Object_setPIFalloff, METH_VARARGS,
+ "Sets Particle Interaction Falloff"},
+ {"getPIMaxDist", ( PyCFunction ) Object_getPIMaxDist, METH_NOARGS,
+ "Returns Particle Interaction Max Distance"},
+ {"setPIMaxDist", ( PyCFunction ) Object_setPIMaxDist, METH_VARARGS,
+ "Sets Particle Interaction Max Distance"},
+ {"getPIUseMaxDist", ( PyCFunction ) Object_getPIUseMaxDist, METH_NOARGS,
+ "Returns bool for Use Max Distace in Particle Interaction "},
+ {"setPIUseMaxDist", ( PyCFunction ) Object_SetPIUseMaxDist, METH_VARARGS,
+ "Sets if Max Distance should be used in Particle Interaction"},
+ {"getPIType", ( PyCFunction ) Object_getPIType, METH_NOARGS,
+ "Returns Particle Interaction Type"},
+ {"setPIType", ( PyCFunction ) Object_SetPIType, METH_VARARGS,
+ "sets Particle Interaction Type"},
+ {"getPIPerm", ( PyCFunction ) Object_getPIPerm, METH_NOARGS,
+ "Returns Particle Interaction Permiability"},
+ {"setPIPerm", ( PyCFunction ) Object_SetPIPerm, METH_VARARGS,
+ "Sets Particle Interaction Permiability"},
+ {"getPISurfaceDamp", ( PyCFunction ) Object_getPISurfaceDamp, METH_NOARGS,
+ "Returns Particle Interaction Surface Damping"},
+ {"setPISurfaceDamp", ( PyCFunction ) Object_SetPISurfaceDamp, METH_VARARGS,
+ "Sets Particle Interaction Surface Damping"},
+ {"getPIRandomDamp", ( PyCFunction ) Object_getPIRandomDamp, METH_NOARGS,
+ "Returns Particle Interaction Random Damping"},
+ {"setPIRandomDamp", ( PyCFunction ) Object_setPIRandomDamp, METH_VARARGS,
+ "Sets Particle Interaction Random Damping"},
+ {"getPIDeflection", ( PyCFunction ) Object_getPIDeflection, METH_NOARGS,
+ "Returns Particle Interaction Deflection"},
+ {"setPIDeflection", ( PyCFunction ) Object_SetPIDeflection, METH_VARARGS,
+ "Sets Particle Interaction Deflection"},
+
+/* Softbody */
+
+ {"isSB", ( PyCFunction ) Object_isSB, METH_NOARGS,
+ "True if object is a soft body"},
+ {"getSBMass", ( PyCFunction ) Object_getSBMass, METH_NOARGS,
+ "Returns SB Mass"},
+ {"setSBMass", ( PyCFunction ) Object_setSBMass, METH_VARARGS,
+ "Sets SB Mass"},
+ {"getSBGravity", ( PyCFunction ) Object_getSBGravity, METH_NOARGS,
+ "Returns SB Gravity"},
+ {"setSBGravity", ( PyCFunction ) Object_setSBGravity, METH_VARARGS,
+ "Sets SB Gravity"},
+ {"getSBFriction", ( PyCFunction ) Object_getSBFriction, METH_NOARGS,
+ "Returns SB Friction"},
+ {"setSBFriction", ( PyCFunction ) Object_setSBFriction, METH_VARARGS,
+ "Sets SB Friction"},
+ {"getSBErrorLimit", ( PyCFunction ) Object_getSBErrorLimit, METH_NOARGS,
+ "Returns SB ErrorLimit"},
+ {"setSBErrorLimit", ( PyCFunction ) Object_setSBErrorLimit, METH_VARARGS,
+ "Sets SB ErrorLimit"},
+ {"getSBGoalSpring", ( PyCFunction ) Object_getSBGoalSpring, METH_NOARGS,
+ "Returns SB GoalSpring"},
+ {"setSBGoalSpring", ( PyCFunction ) Object_setSBGoalSpring, METH_VARARGS,
+ "Sets SB GoalSpring"},
+ {"getSBGoalFriction", ( PyCFunction ) Object_getSBGoalFriction, METH_NOARGS,
+ "Returns SB GoalFriction"},
+ {"setSBGoalFriction", ( PyCFunction ) Object_setSBGoalFriction, METH_VARARGS,
+ "Sets SB GoalFriction"},
+ {"getSBMinGoal", ( PyCFunction ) Object_getSBMinGoal, METH_NOARGS,
+ "Returns SB MinGoal"},
+ {"setSBMinGoal", ( PyCFunction ) Object_setSBMinGoal, METH_VARARGS,
+ "Sets SB MinGoal "},
+ {"getSBMaxGoal", ( PyCFunction ) Object_getSBMaxGoal, METH_NOARGS,
+ "Returns SB MaxGoal"},
+ {"setSBMaxGoal", ( PyCFunction ) Object_setSBMaxGoal, METH_VARARGS,
+ "Sets SB MaxGoal"},
+ {"getSBInnerSpring", ( PyCFunction ) Object_getSBInnerSpring, METH_NOARGS,
+ "Returns SB InnerSpring"},
+ {"setSBInnerSpring", ( PyCFunction ) Object_setSBInnerSpring, METH_VARARGS,
+ "Sets SB InnerSpring"},
+ {"getSBInnerSpringFriction", ( PyCFunction ) Object_getSBInnerSpringFriction, METH_NOARGS,
+ "Returns SB InnerSpringFriction"},
+ {"setSBInnerSpringFriction", ( PyCFunction ) Object_setSBInnerSpringFriction, METH_VARARGS,
+ "Sets SB InnerSpringFriction"},
+ {"getSBDefaultGoal", ( PyCFunction ) Object_getSBDefaultGoal, METH_NOARGS,
+ "Returns SB DefaultGoal"},
+ {"setSBDefaultGoal", ( PyCFunction ) Object_setSBDefaultGoal, METH_VARARGS,
+ "Sets SB DefaultGoal"},
+ {"getSBUseGoal", ( PyCFunction ) Object_getSBUseGoal, METH_NOARGS,
+ "Returns SB UseGoal"},
+ {"setSBUseGoal", ( PyCFunction ) Object_SetSBUseGoal, METH_VARARGS,
+ "Sets SB UseGoal"},
+ {"getSBUseEdges", ( PyCFunction ) Object_getSBUseEdges, METH_NOARGS,
+ "Returns SB UseEdges"},
+ {"setSBUseEdges", ( PyCFunction ) Object_SetSBUseEdges, METH_VARARGS,
+ "Sets SB UseEdges"},
+ {"getSBStiffQuads", ( PyCFunction ) Object_getSBStiffQuads, METH_NOARGS,
+ "Returns SB StiffQuads"},
+ {"setSBStiffQuads", ( PyCFunction ) Object_SetSBStiffQuads, METH_VARARGS,
+ "Sets SB StiffQuads"},
+ {"getBoundBox", ( PyCFunction ) Object_getBoundBox, METH_NOARGS,
+ "Returns the object's bounding box"},
+ {"makeDisplayList", ( PyCFunction ) Object_makeDisplayList, METH_NOARGS,
+ "Update this object's Display List. Some changes like turning\n\
+'SubSurf' on for a mesh need this method (followed by a Redraw) to\n\
+show the changes on the 3d window."},
+ {"link", ( PyCFunction ) Object_link, METH_VARARGS,
+ "Links Object with data provided in the argument. The data must\n\
+match the Object's type, so you cannot link a Lamp to a Mesh type object."},
+ {"makeParent", ( PyCFunction ) Object_makeParent, METH_VARARGS,
+ "Makes the object the parent of the objects provided in the\n\
+argument which must be a list of valid Objects. Optional extra arguments:\n\
+mode:\n\t0: make parent with inverse\n\t1: without inverse\n\
+fast:\n\t0: update scene hierarchy automatically\n\t\
+don't update scene hierarchy (faster). In this case, you must\n\t\
+explicitly update the Scene hierarchy."},
+ {"join", ( PyCFunction ) Object_join, METH_VARARGS,
+ "(object_list) - Joins the objects in object list of the same type, into this object."},
+ {"makeParentDeform", ( PyCFunction ) Object_makeParentDeform, METH_VARARGS,
+ "Makes the object the deformation parent of the objects provided in the \n\
+argument which must be a list of valid Objects. Optional extra arguments:\n\
+mode:\n\t0: make parent with inverse\n\t1: without inverse\n\
+fast:\n\t0: update scene hierarchy automatically\n\t\
+don't update scene hierarchy (faster). In this case, you must\n\t\
+explicitly update the Scene hierarchy."},
+ {"makeParentVertex", ( PyCFunction ) Object_makeParentVertex, METH_VARARGS,
+ "Makes the object the vertex parent of the objects provided in the \n\
+argument which must be a list of valid Objects. \n\
+The second argument is a tuple of 1 or 3 positive integers which corresponds \
+to the index of the vertex you are parenting to.\n\
+Optional extra arguments:\n\
+mode:\n\t0: make parent with inverse\n\t1: without inverse\n\
+fast:\n\t0: update scene hierarchy automatically\n\t\
+don't update scene hierarchy (faster). In this case, you must\n\t\
+explicitly update the Scene hierarchy."},
+ {"makeParentBone", ( PyCFunction ) Object_makeParentBone, METH_VARARGS,
+ "Makes this armature objects bone, the parent of the objects provided in the \n\
+argument which must be a list of valid Objects. Optional extra arguments:\n\
+mode:\n\t0: make parent with inverse\n\t1: without inverse\n\
+fast:\n\t0: update scene hierarchy automatically\n\t\
+don't update scene hierarchy (faster). In this case, you must\n\t\
+explicitely update the Scene hierarchy."},
+
+ {"materialUsage", ( PyCFunction ) Object_materialUsage, METH_NOARGS,
+ "Determines the way the material is used and returns status.\n\
+Possible arguments (provide as strings):\n\
+\tData: Materials assigned to the object's data are shown. (default)\n\
+\tObject: Materials assigned to the object are shown."},
+ {"setDeltaLocation", ( PyCFunction ) Object_setDeltaLocation,
+ METH_VARARGS,
+ "Sets the object's delta location which must be a vector triple."},
+ {"setDrawMode", ( PyCFunction ) Object_SetDrawMode, METH_VARARGS,
+ "Sets the object's drawing mode. The argument can be a sum of:\n\
+2: axis\n4: texspace\n8: drawname\n16: drawimage\n32: drawwire\n64: drawxray\n128: drawtransp"},
+ {"setDrawType", ( PyCFunction ) Object_SetDrawType, METH_VARARGS,
+ "Sets the object's drawing type. The argument must be one of:\n\
+1: Bounding box\n2: Wire\n3: Solid\n4: Shaded\n5: Textured"},
+ {"setEuler", ( PyCFunction ) Object_SetEuler, METH_VARARGS,
+ "Set the object's rotation according to the specified Euler\n\
+angles. The argument must be a vector triple"},
+ {"setMatrix", ( PyCFunction ) Object_SetMatrix, METH_VARARGS,
+ "Set and apply a new local matrix for the object"},
+ {"setLocation", ( PyCFunction ) Object_setLocation, METH_VARARGS,
+ "Set the object's location. The first argument must be a vector\n\
+triple."},
+ {"setMaterials", ( PyCFunction ) Object_setMaterials, METH_VARARGS,
+ "Sets materials. The argument must be a list of valid material\n\
+objects."},
+ {"setName", ( PyCFunction ) GenericLib_setName_with_method, METH_VARARGS,
+ "Sets the name of the object"},
+ {"setSize", ( PyCFunction ) Object_setSize, METH_VARARGS,
+ "Set the object's size. The first argument must be a vector\n\
+triple."},
+ {"setTimeOffset", ( PyCFunction ) Object_setTimeOffset, METH_VARARGS,
+ "Set the object's time offset."},
+ {"makeTrack", ( PyCFunction ) Object_makeTrack, METH_VARARGS,
+ "(trackedobj, fast = 0) - Make this object track another.\n\
+ (trackedobj) - the object that will be tracked.\n\
+ (fast = 0) - if 0: update the scene hierarchy automatically. If you\n\
+ set 'fast' to a nonzero value, don't forget to update the scene yourself\n\
+ (see scene.update())."},
+ {"shareFrom", ( PyCFunction ) Object_shareFrom, METH_VARARGS,
+ "Link data of self with object specified in the argument. This\n\
+works only if self and the object specified are of the same type."},
+ {"select", ( PyCFunction ) Object_Select, METH_VARARGS,
+ "( 1 or 0 ) - Set the selected state of the object.\n\
+ 1 is selected, 0 not selected "},
+ {"setIpo", ( PyCFunction ) Object_SetIpo, METH_VARARGS,
+ "(Blender Ipo) - Sets the object's ipo"},
+ {"clearIpo", ( PyCFunction ) Object_clearIpo, METH_NOARGS,
+ "() - Unlink ipo from this object"},
+
+ {"insertIpoKey", ( PyCFunction ) Object_insertIpoKey, METH_VARARGS,
+ "( Object IPO type ) - Inserts a key into IPO"},
+ {"insertPoseKey", ( PyCFunction ) Object_insertPoseKey, METH_VARARGS,
+ "( Object Pose type ) - Inserts a key into Action"},
+ {"insertCurrentPoseKey", ( PyCFunction ) Object_insertCurrentPoseKey, METH_VARARGS,
+ "( Object Pose type ) - Inserts a key into Action based on current pose"},
+ {"setConstraintInfluenceForBone", ( PyCFunction ) Object_setConstraintInfluenceForBone, METH_VARARGS,
+ "( ) - sets a constraint influence for a certain bone in this (armature)object."},
+ {"copyNLA", ( PyCFunction ) Object_copyNLA, METH_VARARGS,
+ "( ) - copies all NLA strips from another object to this object."},
+ {"convertActionToStrip", ( PyCFunction ) Object_convertActionToStrip, METH_NOARGS,
+ "( ) - copies all NLA strips from another object to this object."},
+ {"getAllProperties", ( PyCFunction ) Object_getAllProperties, METH_NOARGS,
+ "() - Get all the properties from this object"},
+ {"addProperty", ( PyCFunction ) Object_addProperty, METH_VARARGS,
+ "() - Add a property to this object"},
+ {"removeProperty", ( PyCFunction ) Object_removeProperty, METH_VARARGS,
+ "() - Remove a property from this object"},
+ {"getProperty", ( PyCFunction ) Object_getProperty, METH_VARARGS,
+ "() - Get a property from this object by name"},
+ {"removeAllProperties", ( PyCFunction ) Object_removeAllProperties,
+ METH_NOARGS,
+ "() - removeAll a properties from this object"},
+ {"copyAllPropertiesTo", ( PyCFunction ) Object_copyAllPropertiesTo,
+ METH_VARARGS,
+ "() - copy all properties from this object to another object"},
+ {"getScriptLinks", ( PyCFunction ) Object_getScriptLinks, METH_O,
+ "(eventname) - Get a list of this object's scriptlinks (Text names) "
+ "of the given type\n"
+ "(eventname) - string: FrameChanged, Redraw or Render."},
+ {"addScriptLink", ( PyCFunction ) Object_addScriptLink, METH_VARARGS,
+ "(text, evt) - Add a new object scriptlink.\n"
+ "(text) - string: an existing Blender Text name;\n"
+ "(evt) string: FrameChanged, Redraw or Render."},
+ {"clearScriptLinks", ( PyCFunction ) Object_clearScriptLinks,
+ METH_VARARGS,
+ "() - Delete all scriptlinks from this object.\n"
+ "([s1<,s2,s3...>]) - Delete specified scriptlinks from this object."},
+ {"insertShapeKey", ( PyCFunction ) Object_insertShapeKey, METH_NOARGS,
+ "() - Insert a Shape Key in the current object"},
+ {"__copy__", ( PyCFunction ) Object_copy, METH_NOARGS,
+ "() - Return a copy of this object."},
+ {"copy", ( PyCFunction ) Object_copy, METH_NOARGS,
+ "() - Return a copy of this object."},
+ {NULL, NULL, 0, NULL}
+};
+
+/*****************************************************************************/
+/* PythonTypeObject callback function prototypes */
+/*****************************************************************************/
+static void Object_dealloc( BPy_Object * obj );
+static PyObject *Object_repr( BPy_Object * obj );
+static int Object_compare( BPy_Object * a, BPy_Object * b );
+
+/*****************************************************************************/
+/* Function: M_Object_New */
+/* Python equivalent: Blender.Object.New */
+/*****************************************************************************/
+
+/*
+ * Note: if this method is called without later linking object data to it,
+ * errors can be caused elsewhere in Blender. Future versions of the API
+ * will designate obdata as a parameter to this method to prevent this, and
+ * eventually this method will be deprecated.
+ *
+ * When we can guarantee that objects will always have valid obdata,
+ * unlink_object() should be edited to remove checks for NULL pointers and
+ * debugging messages.
+ */
+
+PyObject *M_Object_New( PyObject * self_unused, PyObject * args )
+{
+ struct Object *object;
+ int type;
+ char *str_type;
+ char *name = NULL;
+ PyObject *py_object;
+ BPy_Object *blen_object;
+
+ if( !PyArg_ParseTuple( args, "s|s", &str_type, &name ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "string expected as argument" );
+
+ if( strcmp( str_type, "Armature" ) == 0 )
+ type = OB_ARMATURE;
+ else if( strcmp( str_type, "Camera" ) == 0 )
+ type = OB_CAMERA;
+ else if( strcmp( str_type, "Curve" ) == 0 )
+ type = OB_CURVE;
+ else if (strcmp (str_type, "Text") == 0)
+ type = OB_FONT;
+ else if( strcmp( str_type, "Lamp" ) == 0 )
+ type = OB_LAMP;
+ else if( strcmp( str_type, "Lattice" ) == 0 )
+ type = OB_LATTICE;
+ else if( strcmp( str_type, "Mball" ) == 0 )
+ type = OB_MBALL;
+ else if( strcmp( str_type, "Mesh" ) == 0 )
+ type = OB_MESH;
+ else if( strcmp( str_type, "Surf" ) == 0 )
+ type = OB_SURF;
+/* else if (strcmp (str_type, "Wave") == 0) type = OB_WAVE; */
+ else if( strcmp( str_type, "Empty" ) == 0 )
+ type = OB_EMPTY;
+ else
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "Unknown type specified" );
+
+ /* Create a new object. */
+ if( name == NULL ) {
+ /* No name is specified, set the name to the type of the object. */
+ name = str_type;
+ }
+ object = add_only_object(type, name);
+
+ object->flag = 0;
+ object->lay = 1; /* Layer, by default visible*/
+ object->data = NULL;
+
+ /* user count is incremented in Object_CreatePyObject */
+ object->id.us = 0;
+
+ /* Create a Python object from it. */
+ py_object = Object_CreatePyObject( object );
+ blen_object = (BPy_Object *)py_object;
+
+ /* store the real object type in the PyObject, treat this as an Empty
+ * until it has some obdata */
+ blen_object->realtype = object->type;
+ object->type = OB_EMPTY;
+
+ return py_object;
+}
+
+/*****************************************************************************/
+/* Function: M_Object_Get */
+/* Python equivalent: Blender.Object.Get */
+/*****************************************************************************/
+PyObject *M_Object_Get( PyObject * self_unused, PyObject * args )
+{
+ struct Object *object;
+ PyObject *blen_object;
+ char *name = NULL;
+
+ PyArg_ParseTuple( args, "|s", &name );
+
+ if( name != NULL ) {
+ object = ( Object * ) GetIdFromList( &( G.main->object ), name );
+
+ /* No object exists with the name specified in the argument name. */
+ if( !object ){
+ char buffer[128];
+ PyOS_snprintf( buffer, sizeof(buffer),
+ "object \"%s\" not found", name);
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ buffer );
+ }
+
+ /* objects used in pydriver expressions need this */
+ if (bpy_during_pydriver())
+ bpy_pydriver_appendToList(object);
+
+ return Object_CreatePyObject( object );
+ } else {
+ /* No argument has been given. Return a list of all objects. */
+ PyObject *obj_list;
+ Link *link;
+ int index;
+
+ /* do not allow Get() (w/o arguments) inside pydriver, otherwise
+ * we'd have to update all objects in the DAG */
+ if (bpy_during_pydriver())
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "Object.Get requires an argument when used in pydrivers" );
+
+ obj_list = PyList_New( BLI_countlist( &( G.main->object ) ) );
+
+ if( !obj_list )
+ return EXPP_ReturnPyObjError( PyExc_SystemError,
+ "List creation failed." );
+
+ link = G.main->object.first;
+ index = 0;
+ while( link ) {
+ object = ( Object * ) link;
+ blen_object = Object_CreatePyObject( object );
+ if( !blen_object ) {
+ Py_DECREF( obj_list );
+ Py_RETURN_NONE;
+ }
+ PyList_SetItem( obj_list, index, blen_object );
+ index++;
+ link = link->next;
+ }
+ return obj_list;
+ }
+}
+
+/*****************************************************************************/
+/* Function: M_Object_GetSelected */
+/* Python equivalent: Blender.Object.GetSelected */
+/*****************************************************************************/
+static PyObject *M_Object_GetSelected( PyObject * self_unused )
+{
+ PyObject *blen_object;
+ PyObject *list;
+ Base *base_iter;
+
+ list = PyList_New( 0 );
+
+ if( G.vd == NULL ) {
+ /* No 3d view has been initialized yet, simply return an empty list */
+ return list;
+ }
+
+ if( ( G.scene->basact ) &&
+ ( ( G.scene->basact->flag & SELECT ) &&
+ ( G.scene->basact->lay & G.vd->lay ) ) ) {
+
+ /* Active object is first in the list. */
+ blen_object = Object_CreatePyObject( G.scene->basact->object );
+ if( !blen_object ) {
+ Py_DECREF( list );
+ Py_RETURN_NONE;
+ }
+ PyList_Append( list, blen_object );
+ Py_DECREF( blen_object );
+ }
+
+ base_iter = G.scene->base.first;
+ while( base_iter ) {
+ if( ( ( base_iter->flag & SELECT ) &&
+ ( base_iter->lay & G.vd->lay ) ) &&
+ ( base_iter != G.scene->basact ) ) {
+
+ blen_object = Object_CreatePyObject( base_iter->object );
+ if( blen_object ) {
+ PyList_Append( list, blen_object );
+ Py_DECREF( blen_object );
+ }
+ }
+ base_iter = base_iter->next;
+ }
+ return list;
+}
+
+
+/*****************************************************************************/
+/* Function: M_Object_Duplicate */
+/* Python equivalent: Blender.Object.Duplicate */
+/*****************************************************************************/
+static PyObject *M_Object_Duplicate( PyObject * self_unused,
+ PyObject * args, PyObject *kwd )
+{
+ int dupflag= 0; /* this a flag, passed to adduplicate() and used instead of U.dupflag sp python can set what is duplicated */
+
+ /* the following variables are bools, if set true they will modify the dupflag to pass to adduplicate() */
+ int mesh_dupe = 0;
+ int surface_dupe = 0;
+ int curve_dupe = 0;
+ int text_dupe = 0;
+ int metaball_dupe = 0;
+ int armature_dupe = 0;
+ int lamp_dupe = 0;
+ int material_dupe = 0;
+ int texture_dupe = 0;
+ int ipo_dupe = 0;
+
+ static char *kwlist[] = {"mesh", "surface", "curve",
+ "text", "metaball", "armature", "lamp", "material", "texture", "ipo", NULL};
+
+ /* duplicating in background causes segfaults */
+ if( G.background == 1 )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "cannot duplicate objects in background mode" );
+
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwd, "|iiiiiiiiii", kwlist,
+ &mesh_dupe, &surface_dupe, &curve_dupe, &text_dupe, &metaball_dupe,
+ &armature_dupe, &lamp_dupe, &material_dupe, &texture_dupe, &ipo_dupe))
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected nothing or bool keywords 'mesh', 'surface', 'curve', 'text', 'metaball', 'armature', 'lamp' 'material', 'texture' and 'ipo' as arguments" );
+
+ /* USER_DUP_ACT for actions is not supported in the UI so dont support it here */
+ if (mesh_dupe) dupflag |= USER_DUP_MESH;
+ if (surface_dupe) dupflag |= USER_DUP_SURF;
+ if (curve_dupe) dupflag |= USER_DUP_CURVE;
+ if (text_dupe) dupflag |= USER_DUP_FONT;
+ if (metaball_dupe) dupflag |= USER_DUP_MBALL;
+ if (armature_dupe) dupflag |= USER_DUP_ARM;
+ if (lamp_dupe) dupflag |= USER_DUP_LAMP;
+ if (material_dupe) dupflag |= USER_DUP_MAT;
+ if (texture_dupe) dupflag |= USER_DUP_TEX;
+ if (ipo_dupe) dupflag |= USER_DUP_IPO;
+ adduplicate(2, dupflag); /* 2 is a mode with no transform and no redraw, Duplicate the current selection, context sensitive */
+ Py_RETURN_NONE;
+}
+
+
+/*****************************************************************************/
+/* Python BPy_Object methods: */
+/*****************************************************************************/
+
+static PyObject *Object_buildParts( BPy_Object * self )
+{
+ build_particle_system( self->object );
+ Py_RETURN_NONE;
+}
+
+static PyObject *Object_clearIpo( BPy_Object * self )
+{
+ Object *ob = self->object;
+ Ipo *ipo = ( Ipo * ) ob->ipo;
+
+ if( ipo ) {
+ ID *id = &ipo->id;
+ if( id->us > 0 )
+ id->us--;
+ ob->ipo = NULL;
+
+ Py_RETURN_TRUE;
+ }
+
+ Py_RETURN_FALSE; /* no ipo found */
+}
+
+static PyObject *Object_clrParent( BPy_Object * self, PyObject * args )
+{
+ int mode = 0;
+ int fast = 0;
+
+ if( !PyArg_ParseTuple( args, "|ii", &mode, &fast ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected one or two optional integers as arguments" );
+
+ /* Remove the link only, the object is still in the scene. */
+ self->object->parent = NULL;
+
+ if( mode == 2 ) {
+ /* Keep transform */
+ apply_obmat( self->object );
+ }
+
+ if( !fast )
+ DAG_scene_sort( G.scene );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Object_clearTrack( BPy_Object * self, PyObject * args )
+{
+ int mode = 0;
+ int fast = 0;
+
+ if( !PyArg_ParseTuple( args, "|ii", &mode, &fast ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected one or two optional integers as arguments" );
+
+ /* Remove the link only, the object is still in the scene. */
+ self->object->track = NULL;
+
+ if( mode ) {
+ /* Keep transform */
+ apply_obmat( self->object );
+ }
+
+ if( !fast )
+ DAG_scene_sort( G.scene );
+
+ Py_RETURN_NONE;
+}
+
+/* adds object data to a Blender object, if object->data = NULL */
+int EXPP_add_obdata( struct Object *object )
+{
+ if( object->data != NULL )
+ return -1;
+
+ switch ( object->type ) {
+ case OB_ARMATURE:
+ /* TODO: Do we need to add something to G? (see the OB_LAMP case) */
+ object->data = add_armature( "Armature" );
+ break;
+ case OB_CAMERA:
+ /* TODO: Do we need to add something to G? (see the OB_LAMP case) */
+ object->data = add_camera( "Camera" );
+ break;
+ case OB_CURVE:
+ object->data = add_curve( "Curve", OB_CURVE );
+ G.totcurve++;
+ break;
+ case OB_LAMP:
+ object->data = add_lamp( "Lamp" );
+ G.totlamp++;
+ break;
+ case OB_MESH:
+ object->data = add_mesh( "Mesh" );
+ G.totmesh++;
+ break;
+ case OB_LATTICE:
+ object->data = ( void * ) add_lattice( "Lattice" );
+ object->dt = OB_WIRE;
+ break;
+ case OB_MBALL:
+ object->data = add_mball( "Meta" );
+ break;
+
+ /* TODO the following types will be supported later,
+ be sure to update Scene_link when new types are supported
+ case OB_SURF:
+ object->data = add_curve(OB_SURF);
+ G.totcurve++;
+ break;
+ case OB_FONT:
+ object->data = add_curve(OB_FONT);
+ break;
+ case OB_WAVE:
+ object->data = add_wave();
+ break;
+ */
+ default:
+ break;
+ }
+
+ if( !object->data )
+ return -1;
+
+ return 0;
+}
+
+static PyObject *Object_getDeltaLocation( BPy_Object * self )
+{
+ return Py_BuildValue( "fff", self->object->dloc[0],
+ self->object->dloc[1], self->object->dloc[2] );
+}
+
+static PyObject *Object_getAction( BPy_Object * self )
+{
+ if( self->object->action )
+ return Action_CreatePyObject( self->object->action );
+ Py_RETURN_NONE;
+}
+
+static int Object_setAction( BPy_Object * self, PyObject * value )
+{
+ return GenericLib_assignData(value, (void **) &self->object->action, 0, 1, ID_AC, 0);
+}
+
+static PyObject *Object_evaluatePose(BPy_Object *self, PyObject *args)
+{
+ int frame = 1;
+ if( !PyArg_ParseTuple( args, "i", &frame ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected int argument" );
+
+ frame = EXPP_ClampInt(frame, MINFRAME, MAXFRAME);
+ G.scene->r.cfra = frame;
+ do_all_pose_actions(self->object);
+ where_is_pose (self->object);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject * Object_getPose(BPy_Object *self)
+{
+ /*if there is no pose will return PyNone*/
+ return PyPose_FromPose(self->object->pose, self->object->id.name+2);
+}
+
+static PyObject *Object_getSelected( BPy_Object * self )
+{
+ Base *base;
+
+ base = FIRSTBASE;
+ while( base ) {
+ if( base->object == self->object ) {
+ if( base->flag & SELECT ) {
+ Py_RETURN_TRUE;
+ } else {
+ Py_RETURN_FALSE;
+ }
+ }
+ base = base->next;
+ }
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "could not find object's selection state" );
+}
+
+static int Object_setSelect( BPy_Object * self, PyObject * value )
+{
+ Base *base;
+ int param = PyObject_IsTrue( value );
+
+ if( param == -1 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected True/False or 0/1" );
+
+ base = FIRSTBASE;
+ while( base ) {
+ if( base->object == self->object ) {
+ if( param ) {
+ base->flag |= SELECT;
+ self->object->flag = (short)base->flag;
+ set_active_base( base );
+ } else {
+ base->flag &= ~SELECT;
+ self->object->flag = (short)base->flag;
+ }
+ break;
+ }
+ base = base->next;
+ }
+ if (base) { /* was the object selected? */
+ countall( );
+ }
+ return 0;
+}
+
+static PyObject *Object_GetEuler( BPy_Object * self, PyObject * args )
+{
+ char *space = "localspace"; /* default to local */
+ float eul[3];
+
+ if( !PyArg_ParseTuple( args, "|s", &space ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a string or nothing" );
+
+ if( BLI_streq( space, "worldspace" ) ) { /* Worldspace matrix */
+ float mat3[3][3];
+ disable_where_script( 1 );
+ where_is_object( self->object );
+ Mat3CpyMat4(mat3, self->object->obmat);
+ Mat3ToEul(mat3, eul);
+ disable_where_script( 0 );
+ } else if( BLI_streq( space, "localspace" ) ) { /* Localspace matrix */
+ eul[0] = self->object->rot[0];
+ eul[1] = self->object->rot[1];
+ eul[2] = self->object->rot[2];
+ } else {
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "expected either nothing, 'localspace' (default) or 'worldspace'" );
+ }
+
+ return ( PyObject * ) newEulerObject( eul, Py_NEW );
+}
+
+static PyObject *Object_getInverseMatrix( BPy_Object * self )
+{
+ MatrixObject *inverse =
+ ( MatrixObject * ) newMatrixObject( NULL, 4, 4, Py_NEW );
+ Mat4Invert( (float ( * )[4])*inverse->matrix, self->object->obmat );
+
+ return ( ( PyObject * ) inverse );
+}
+
+static PyObject *Object_getIpo( BPy_Object * self )
+{
+ struct Ipo *ipo = self->object->ipo;
+
+ if( ipo )
+ return Ipo_CreatePyObject( ipo );
+ Py_RETURN_NONE;
+}
+
+static PyObject *Object_getLocation( BPy_Object * self, PyObject * args )
+{
+ char *space = "localspace"; /* default to local */
+ PyObject *attr;
+ if( !PyArg_ParseTuple( args, "|s", &space ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a string or nothing" );
+
+ if( BLI_streq( space, "worldspace" ) ) { /* Worldspace matrix */
+ disable_where_script( 1 );
+ where_is_object( self->object );
+
+ attr = Py_BuildValue( "fff",
+ self->object->obmat[3][0],
+ self->object->obmat[3][1],
+ self->object->obmat[3][2] );
+
+ disable_where_script( 0 );
+ } else if( BLI_streq( space, "localspace" ) ) { /* Localspace matrix */
+ attr = Py_BuildValue( "fff",
+ self->object->loc[0],
+ self->object->loc[1],
+ self->object->loc[2] );
+ } else {
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "expected either nothing, 'localspace' (default) or 'worldspace'" );
+ }
+
+ return attr;
+}
+
+static PyObject *Object_getMaterials( BPy_Object * self, PyObject * args )
+{
+ int all = 0;
+
+ if( !PyArg_ParseTuple( args, "|i", &all ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected an int or nothing" );
+
+ return EXPP_PyList_fromMaterialList( self->object->mat,
+ self->object->totcol, all );
+}
+
+static PyObject *Object_getParent( BPy_Object * self )
+{
+ return Object_CreatePyObject( self->object->parent );
+}
+
+static PyObject *Object_getParentBoneName( BPy_Object * self )
+{
+ if( self->object->parent && self->object->parent->type==OB_ARMATURE && self->object->parsubstr[0] != '\0' )
+ return PyString_FromString( self->object->parsubstr );
+ Py_RETURN_NONE;
+}
+
+static int Object_setParentBoneName( BPy_Object * self, PyObject *value )
+{
+ char *bonename;
+
+ if (!PyString_Check(value))
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected an int or nothing" );
+
+ if (
+ self->object->parent &&
+ self->object->parent->type == OB_ARMATURE &&
+ self->object->partype == PARBONE
+ ) {/* its all good */} else
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "can only set the parent bone name for objects that already have a bone parent" );
+
+ bonename = PyString_AsString(value);
+
+ if (!get_named_bone(self->object->parent->data, bonename))
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "cannot parent to this bone: invalid bone name" );
+
+ strcpy(self->object->parsubstr, bonename);
+ DAG_scene_sort( G.scene );
+ return 0;
+}
+
+static PyObject *Object_getSize( BPy_Object * self, PyObject * args )
+{
+ char *space = "localspace"; /* default to local */
+ PyObject *attr;
+ if( !PyArg_ParseTuple( args, "|s", &space ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a string or nothing" );
+
+ if( BLI_streq( space, "worldspace" ) ) { /* Worldspace matrix */
+ float rot[3];
+ float mat[3][3], imat[3][3], tmat[3][3];
+ disable_where_script( 1 );
+ where_is_object( self->object );
+
+ Mat3CpyMat4(mat, self->object->obmat);
+
+ /* functionality copied from editobject.c apply_obmat */
+ Mat3ToEul(mat, rot);
+ EulToMat3(rot, tmat);
+ Mat3Inv(imat, tmat);
+ Mat3MulMat3(tmat, imat, mat);
+
+ attr = Py_BuildValue( "fff",
+ tmat[0][0],
+ tmat[1][1],
+ tmat[2][2] );
+ disable_where_script( 0 );
+ } else if( BLI_streq( space, "localspace" ) ) { /* Localspace matrix */
+ attr = Py_BuildValue( "fff",
+ self->object->size[0],
+ self->object->size[1],
+ self->object->size[2] );
+ } else {
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "expected either nothing, 'localspace' (default) or 'worldspace'" );
+ }
+ return attr;
+}
+
+static PyObject *Object_getTimeOffset( BPy_Object * self )
+{
+ return PyFloat_FromDouble ( (double) self->object->sf );
+}
+
+static PyObject *Object_getTracked( BPy_Object * self )
+{
+ return Object_CreatePyObject( self->object->track );
+}
+
+static PyObject *Object_getType( BPy_Object * self )
+{
+ char *str;
+ int type = self->object->type;
+
+ /* if object not yet linked to data, return the stored type */
+ if( self->realtype != OB_EMPTY )
+ type = self->realtype;
+
+ switch ( type ) {
+ case OB_ARMATURE:
+ str = "Armature";
+ break;
+ case OB_CAMERA:
+ str = "Camera";
+ break;
+ case OB_CURVE:
+ str = "Curve";
+ break;
+ case OB_EMPTY:
+ str = "Empty";
+ break;
+ case OB_FONT:
+ str = "Text";
+ break;
+ case OB_LAMP:
+ str = "Lamp";
+ break;
+ case OB_LATTICE:
+ str = "Lattice";
+ break;
+ case OB_MBALL:
+ str = "MBall";
+ break;
+ case OB_MESH:
+ str = "Mesh";
+ break;
+ case OB_SURF:
+ str = "Surf";
+ break;
+ case OB_WAVE:
+ str = "Wave";
+ break;
+ default:
+ str = "unknown";
+ break;
+ }
+
+ return PyString_FromString( str );
+}
+
+static PyObject *Object_getBoundBox( BPy_Object * self )
+{
+ int i;
+ float *vec = NULL;
+ PyObject *vector, *bbox;
+
+ if( !self->object->data )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "This object isn't linked to any object data (mesh, curve, etc) yet" );
+
+ if( !self->object->bb ) { /* if no ob bbox, we look in obdata */
+ Mesh *me;
+ Curve *curve;
+ switch ( self->object->type ) {
+ case OB_MESH:
+ me = self->object->data;
+ vec = (float*) mesh_get_bb(me)->vec;
+ break;
+ case OB_CURVE:
+ case OB_FONT:
+ case OB_SURF:
+ curve = self->object->data;
+ if( !curve->bb )
+ tex_space_curve( curve );
+ vec = ( float * ) curve->bb->vec;
+ break;
+ default:
+ Py_RETURN_NONE;
+ }
+
+ { /* transform our obdata bbox by the obmat.
+ the obmat is 4x4 homogeneous coords matrix.
+ each bbox coord is xyz, so we make it homogenous
+ by padding it with w=1.0 and doing the matrix mult.
+ afterwards we divide by w to get back to xyz.
+ */
+ /* printmatrix4( "obmat", self->object->obmat); */
+
+ float tmpvec[4]; /* tmp vector for homogenous coords math */
+ int i;
+ float *from;
+
+ bbox = PyList_New( 8 );
+ if( !bbox )
+ return EXPP_ReturnPyObjError
+ ( PyExc_MemoryError,
+ "couldn't create pylist" );
+ for( i = 0, from = vec; i < 8; i++, from += 3 ) {
+ memcpy( tmpvec, from, 3 * sizeof( float ) );
+ tmpvec[3] = 1.0f; /* set w coord */
+ Mat4MulVec4fl( self->object->obmat, tmpvec );
+ /* divide x,y,z by w */
+ tmpvec[0] /= tmpvec[3];
+ tmpvec[1] /= tmpvec[3];
+ tmpvec[2] /= tmpvec[3];
+
+#if 0
+ { /* debug print stuff */
+ int i;
+
+ printf( "\nobj bbox transformed\n" );
+ for( i = 0; i < 4; ++i )
+ printf( "%f ", tmpvec[i] );
+
+ printf( "\n" );
+ }
+#endif
+
+ /* because our bounding box is calculated and
+ does not have its own memory,
+ we must create vectors that allocate space */
+
+ vector = newVectorObject( NULL, 3, Py_NEW);
+ memcpy( ( ( VectorObject * ) vector )->vec,
+ tmpvec, 3 * sizeof( float ) );
+ PyList_SET_ITEM( bbox, i, vector );
+ }
+ }
+ } else { /* the ob bbox exists */
+ vec = ( float * ) self->object->bb->vec;
+
+ if( !vec )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't retrieve bounding box data" );
+
+ bbox = PyList_New( 8 );
+
+ if( !bbox )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create pylist" );
+
+ /* create vectors referencing object bounding box coords */
+ for( i = 0; i < 8; i++ ) {
+ vector = newVectorObject( vec, 3, Py_WRAP );
+ PyList_SET_ITEM( bbox, i, vector );
+ vec += 3;
+ }
+ }
+
+ return bbox;
+}
+
+static PyObject *Object_makeDisplayList( BPy_Object * self )
+{
+ Object *ob = self->object;
+
+ if( ob->type == OB_FONT ) {
+ Curve *cu = ob->data;
+ freedisplist( &cu->disp );
+ text_to_curve( ob, 0 );
+ }
+
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Object_link( BPy_Object * self, PyObject * args )
+{
+ PyObject *py_data;
+ ID *id;
+ ID *oldid;
+ int obj_id;
+ void *data = NULL;
+ int ok;
+
+ if( !PyArg_ParseTuple( args, "O", &py_data ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected an object as argument" );
+
+ if( BPy_Armature_Check( py_data ) )
+ data = ( void * ) PyArmature_AsArmature((BPy_Armature*)py_data);
+ else if( BPy_Camera_Check( py_data ) )
+ data = ( void * ) Camera_FromPyObject( py_data );
+ else if( BPy_Lamp_Check( py_data ) )
+ data = ( void * ) Lamp_FromPyObject( py_data );
+ else if( BPy_Curve_Check( py_data ) )
+ data = ( void * ) Curve_FromPyObject( py_data );
+ else if( BPy_NMesh_Check( py_data ) ) {
+ data = ( void * ) NMesh_FromPyObject( py_data, self->object );
+ if( !data ) /* NULL means there is already an error */
+ return NULL;
+ } else if( BPy_Mesh_Check( py_data ) )
+ data = ( void * ) Mesh_FromPyObject( py_data, self->object );
+ else if( BPy_Lattice_Check( py_data ) )
+ data = ( void * ) Lattice_FromPyObject( py_data );
+ else if( BPy_Metaball_Check( py_data ) )
+ data = ( void * ) Metaball_FromPyObject( py_data );
+ else if( BPy_Text3d_Check( py_data ) )
+ data = ( void * ) Text3d_FromPyObject( py_data );
+
+ /* have we set data to something good? */
+ if( !data )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "link argument type is not supported " );
+
+ oldid = ( ID * ) self->object->data;
+ id = ( ID * ) data;
+ obj_id = MAKE_ID2( id->name[0], id->name[1] );
+
+ /* if the object object has not been linked to real data before, we
+ * can now let it assume its real type */
+ if( self->realtype != OB_EMPTY ) {
+ self->object->type = self->realtype;
+ self->realtype = OB_EMPTY;
+ }
+
+ ok = 1;
+ switch ( obj_id ) {
+ case ID_AR:
+ if( self->object->type != OB_ARMATURE ) {
+ ok = 0;
+ }
+ break;
+ case ID_CA:
+ if( self->object->type != OB_CAMERA ) {
+ ok = 0;
+ }
+ break;
+ case ID_LA:
+ if( self->object->type != OB_LAMP ) {
+ ok = 0;
+ }
+ break;
+ case ID_ME:
+ if( self->object->type != OB_MESH ) {
+ ok = 0;
+ }
+ break;
+ case ID_CU:
+ if( self->object->type != OB_CURVE && self->object->type != OB_FONT ) {
+ ok = 0;
+ }
+ break;
+ case ID_LT:
+ if( self->object->type != OB_LATTICE ) {
+ ok = 0;
+ }
+ break;
+ case ID_MB:
+ if( self->object->type != OB_MBALL ) {
+ ok = 0;
+ }
+ break;
+ default:
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "Linking this object type is not supported" );
+ }
+
+ if( !ok )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "The 'link' object is incompatible with the base object" );
+ self->object->data = data;
+
+ /* creates the curve for the text object */
+ if (self->object->type == OB_FONT)
+ text_to_curve(self->object, 0);
+
+ id_us_plus( id );
+ if( oldid ) {
+ if( oldid->us > 0 ) {
+ oldid->us--;
+ } else {
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "old object reference count below 0" );
+ }
+ }
+
+ /* make sure data and object materials are consistent */
+ test_object_materials( id );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Object_makeParentVertex( BPy_Object * self, PyObject * args )
+{
+ PyObject *list;
+ PyObject *vlist;
+ PyObject *py_child;
+ PyObject *ret_val;
+ Object *parent;
+ int noninverse = 0;
+ int fast = 0;
+ int partype;
+ int v1, v2=0, v3=0;
+ int i;
+
+ /* Check if the arguments passed to makeParent are valid. */
+ if( !PyArg_ParseTuple( args, "OO|ii", &list, &vlist, &noninverse, &fast ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a list of objects, a tuple of integers and one or two integers as arguments" );
+
+ if( !PySequence_Check( list ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a list of objects" );
+
+ if (!PyTuple_Check( vlist ))
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a tuple of integers" );
+
+ switch( PyTuple_Size( vlist ) ) {
+ case 1:
+ if( !PyArg_ParseTuple( vlist, "i", &v1 ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a tuple of 1 or 3 integers" );
+
+ if ( v1 < 0 )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "indices must be strictly positive" );
+
+ partype = PARVERT1;
+ break;
+ case 3:
+ if( !PyArg_ParseTuple( vlist, "iii", &v1, &v2, &v3 ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a tuple of 1 or 3 integers" );
+
+ if ( v1 < 0 || v2 < 0 || v3 < 0)
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "indices must be strictly positive" );
+ partype = PARVERT3;
+ break;
+ default:
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a tuple of 1 or 3 integers" );
+ }
+
+ parent = ( Object * ) self->object;
+
+ if (!ELEM3(parent->type, OB_MESH, OB_CURVE, OB_SURF))
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "Parent Vertex only applies to curve, mesh or surface objects" );
+
+ if (parent->id.us == 0)
+ return EXPP_ReturnPyObjError (PyExc_RuntimeError,
+ "object must be linked to a scene before it can become a parent");
+
+ /* Check if the PyObject passed in list is a Blender object. */
+ for( i = 0; i < PySequence_Length( list ); i++ ) {
+ py_child = PySequence_GetItem( list, i );
+
+ ret_val = internal_makeParent(parent, py_child, partype, noninverse, fast, v1, v2, v3, NULL);
+ Py_DECREF (py_child);
+
+ if (ret_val)
+ Py_DECREF(ret_val);
+ else {
+ if (!fast) /* need to sort when interrupting in the middle of the list */
+ DAG_scene_sort( G.scene );
+ return NULL; /* error has been set already */
+ }
+ }
+
+ if (!fast) /* otherwise, only sort at the end */
+ DAG_scene_sort( G.scene );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Object_makeParentDeform( BPy_Object * self, PyObject * args )
+{
+ PyObject *list;
+ PyObject *py_child;
+ PyObject *ret_val;
+ Object *parent;
+ int noninverse = 0;
+ int fast = 0;
+ int i;
+
+ /* Check if the arguments passed to makeParent are valid. */
+ if( !PyArg_ParseTuple( args, "O|ii", &list, &noninverse, &fast ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a list of objects and one or two integers as arguments" );
+
+ if( !PySequence_Check( list ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a list of objects" );
+
+ parent = ( Object * ) self->object;
+
+ if (parent->type != OB_CURVE && parent->type != OB_ARMATURE)
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "Parent Deform only applies to curve or armature objects" );
+
+ if (parent->id.us == 0)
+ return EXPP_ReturnPyObjError (PyExc_RuntimeError,
+ "object must be linked to a scene before it can become a parent");
+
+ /* Check if the PyObject passed in list is a Blender object. */
+ for( i = 0; i < PySequence_Length( list ); i++ ) {
+ py_child = PySequence_GetItem( list, i );
+
+ ret_val = internal_makeParent(parent, py_child, PARSKEL, noninverse, fast, 0, 0, 0, NULL);
+ Py_DECREF (py_child);
+
+ if (ret_val)
+ Py_DECREF(ret_val);
+ else {
+ if (!fast) /* need to sort when interupting in the middle of the list */
+ DAG_scene_sort( G.scene );
+ return NULL; /* error has been set already */
+ }
+ }
+
+ if (!fast) /* otherwise, only sort at the end */
+ DAG_scene_sort( G.scene );
+
+ Py_RETURN_NONE;
+}
+
+
+static PyObject *Object_makeParentBone( BPy_Object * self, PyObject * args )
+{
+ char *bonename;
+ PyObject *list;
+ PyObject *py_child;
+ PyObject *ret_val;
+ Object *parent;
+ int noninverse = 0;
+ int fast = 0;
+ int i;
+
+ /* Check if the arguments passed to makeParent are valid. */
+ if( !PyArg_ParseTuple( args, "Os|ii", &list, &bonename, &noninverse, &fast ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a list of objects, bonename and optionally two integers as arguments" );
+
+ parent = ( Object * ) self->object;
+
+ if (parent->type != OB_ARMATURE)
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "Parent Bone only applies to armature objects" );
+
+ if (parent->id.us == 0)
+ return EXPP_ReturnPyObjError (PyExc_RuntimeError,
+ "object must be linked to a scene before it can become a parent");
+
+ if (!parent->data)
+ return EXPP_ReturnPyObjError (PyExc_RuntimeError,
+ "object must be linked to armature data");
+
+ if (!get_named_bone(parent->data, bonename))
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "Parent Bone Name is not in the armature" );
+
+ /* Check if the PyObject passed in list is a Blender object. */
+ for( i = 0; i < PySequence_Length( list ); i++ ) {
+ py_child = PySequence_GetItem( list, i );
+
+ ret_val = internal_makeParent(parent, py_child, PARBONE, noninverse, fast, 0, 0, 0, bonename);
+ Py_DECREF (py_child);
+
+ if (ret_val)
+ Py_DECREF(ret_val);
+ else {
+ if (!fast) /* need to sort when interupting in the middle of the list */
+ DAG_scene_sort( G.scene );
+ return NULL; /* error has been set already */
+ }
+ }
+
+ if (!fast) /* otherwise, only sort at the end */
+ DAG_scene_sort( G.scene );
+
+ Py_RETURN_NONE;
+}
+
+
+static PyObject *Object_makeParent( BPy_Object * self, PyObject * args )
+{
+ PyObject *list;
+ PyObject *py_child;
+ PyObject *ret_val;
+ Object *parent;
+ int noninverse = 0;
+ int fast = 0;
+ int i;
+
+ /* Check if the arguments passed to makeParent are valid. */
+ if( !PyArg_ParseTuple( args, "O|ii", &list, &noninverse, &fast ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a list of objects and one or two integers as arguments" );
+
+ if( !PySequence_Check( list ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a list of objects" );
+
+ parent = ( Object * ) self->object;
+
+ if (parent->id.us == 0)
+ return EXPP_ReturnPyObjError (PyExc_RuntimeError,
+ "object must be linked to a scene before it can become a parent");
+
+ /* Check if the PyObject passed in list is a Blender object. */
+ for( i = 0; i < PySequence_Length( list ); i++ ) {
+ py_child = PySequence_GetItem( list, i );
+
+ ret_val = internal_makeParent(parent, py_child, PAROBJECT, noninverse, fast, 0, 0, 0, NULL);
+ Py_DECREF (py_child);
+
+ if (ret_val)
+ Py_DECREF(ret_val);
+ else {
+ if (!fast) /* need to sort when interupting in the middle of the list */
+ DAG_scene_sort( G.scene );
+ return NULL; /* error has been set already */
+ }
+ }
+
+ if (!fast) /* otherwise, only sort at the end */
+ DAG_scene_sort( G.scene );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Object_join( BPy_Object * self, PyObject * args )
+{
+ PyObject *list;
+ PyObject *py_child;
+ Object *parent;
+ Object *child;
+ Scene *temp_scene;
+ Scene *orig_scene;
+ Base *temp_base;
+ short type;
+ int i, ok=0, ret_value=0, list_length=0;
+
+ /* joining in background causes segfaults */
+ if( G.background == 1 )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "cannot join objects in background mode" );
+
+ /* Check if the arguments passed to makeParent are valid. */
+ if( !PyArg_ParseTuple( args, "O", &list ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a list of objects" );
+
+ if( !PySequence_Check( list ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a list of objects" );
+
+ list_length = PySequence_Length( list ); /* if there are no objects to join then exit silently */
+
+ if( !list_length ) {
+ Py_RETURN_NONE;
+ }
+
+ parent = ( Object * ) self->object;
+ type = parent->type;
+
+ /* Only these object types are sypported */
+ if( type!=OB_MESH && type!=OB_CURVE && type!=OB_SURF && type!=OB_ARMATURE )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "Base object is not a type Blender can join" );
+
+ if( !object_in_scene( parent, G.scene ) )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "object must be in the current scene" );
+
+ /* exit editmode so join can be done */
+ if( G.obedit )
+ exit_editmode( EM_FREEDATA );
+
+ temp_scene = add_scene( "Scene" ); /* make the new scene */
+ temp_scene->lay= 1; /* first layer on */
+
+ /* TODO: use EXPP_check_sequence_consistency here */
+
+ /* Check if the PyObject passed in list is a Blender object. */
+ for( i = 0; i < list_length; i++ ) {
+ py_child = PySequence_GetItem( list, i );
+ if( !BPy_Object_Check( py_child ) ) {
+ /* Cleanup */
+ free_libblock( &G.main->scene, temp_scene );
+ Py_DECREF( py_child );
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a list of objects, one or more of the list items is not a Blender Object." );
+ } else {
+ /* List item is an object, is it the same type? */
+ child = ( Object * ) Object_FromPyObject( py_child );
+ Py_DECREF( py_child );
+ if( parent->type == child->type ) {
+ if( !object_in_scene( child, G.scene ) ) {
+ free_libblock( &G.main->scene, temp_scene );
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "object must be in the current scene" );
+ }
+
+ ok =1;
+ /* Add a new base, then link the base to the temp_scene */
+ temp_base = MEM_callocN( sizeof( Base ), "pynewbase" );
+ /* we know these types are the same, link to the temp scene
+ * for joining */
+ temp_base->object = child; /* link object to the new base */
+ temp_base->flag |= SELECT;
+ temp_base->lay = 1; /*1 layer on */
+
+ BLI_addhead( &temp_scene->base, temp_base ); /* finally, link new base to scene */
+ child->id.us += 1; /*Would usually increase user count but in this case it's ok not to */
+
+ /*DAG_object_flush_update(temp_scene, temp_base->object, OB_RECALC_DATA);*/
+ }
+ }
+ }
+
+ orig_scene = G.scene; /* backup our scene */
+
+ /* Add the main object into the temp_scene */
+ temp_base = MEM_callocN( sizeof( Base ), "pynewbase" );
+ temp_base->object = parent; /* link object to the new base */
+ temp_base->flag |= SELECT;
+ temp_base->lay = 1; /*1 layer on */
+ BLI_addhead( &temp_scene->base, temp_base ); /* finally, link new base to scene */
+ parent->id.us += 1;
+
+ /* all objects in the scene, set it active and the active object */
+ set_scene( temp_scene );
+ set_active_base( temp_base );
+
+ /* Do the joining now we know everythings OK. */
+ if(type == OB_MESH)
+ ret_value = join_mesh();
+ else if(type == OB_CURVE)
+ ret_value = join_curve(OB_CURVE);
+ else if(type == OB_SURF)
+ ret_value = join_curve(OB_SURF);
+ else if(type == OB_ARMATURE)
+ ret_value = join_armature();
+
+ /* May use this for correcting object user counts later on */
+ /*
+ if (!ret_value) {
+ temp_base = temp_scene->base.first;
+ while( base ) {
+ object = base->object;
+ object->id.us +=1
+ base = base->next;
+ }
+ }*/
+
+ /* remove old scene */
+ set_scene( orig_scene );
+ free_libblock( &G.main->scene, temp_scene );
+
+ /* no objects were of the correct type, return None */
+ if (!ok) {
+ Py_RETURN_NONE;
+ }
+
+ /* If the join failed then raise an error */
+ if (!ret_value)
+ return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
+"Blender failed to join the objects, this is not a script error.\n\
+Please add exception handling to your script with a RuntimeError exception\n\
+letting the user know that their data could not be joined." ) );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *internal_makeParent(Object *parent, PyObject *py_child,
+ int partype, /* parenting type */
+ int noninverse, int fast, /* parenting arguments */
+ int v1, int v2, int v3, /* for vertex parent */
+ char *bonename) /* for bone parents - assume the name is already checked to be a valid bone name*/
+{
+ Object *child = NULL;
+
+ if( BPy_Object_Check( py_child ) )
+ child = ( Object * ) Object_FromPyObject( py_child );
+
+ if( child == NULL )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "Object Type expected" );
+
+ if( test_parent_loop( parent, child ) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "parenting loop detected - parenting failed" );
+
+ if (partype == PARSKEL && child->type != OB_MESH)
+ child->partype = PAROBJECT;
+ else
+ child->partype = (short)partype;
+
+ if (partype == PARVERT3) {
+ child->par1 = v1;
+ child->par2 = v2;
+ child->par3 = v3;
+ }
+ else if (partype == PARVERT1) {
+ child->par1 = v1;
+ } else if (partype == PARBONE) {
+ strcpy( child->parsubstr, bonename );
+ }
+
+
+
+ child->parent = parent;
+ /* py_obj_child = (BPy_Object *) py_child; */
+ if( noninverse == 1 ) {
+ Mat4One(child->parentinv);
+ /* Parent inverse = unity */
+ child->loc[0] = 0.0;
+ child->loc[1] = 0.0;
+ child->loc[2] = 0.0;
+ } else {
+ what_does_parent( child );
+ Mat4Invert( child->parentinv, workob.obmat );
+ clear_workob();
+ }
+
+ if( !fast )
+ child->recalc |= OB_RECALC_OB;
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Object_materialUsage( void )
+{
+ return EXPP_ReturnPyObjError( PyExc_NotImplementedError,
+ "materialUsage: not yet implemented" );
+}
+
+static PyObject *Object_setDeltaLocation( BPy_Object * self, PyObject * args )
+{
+ float dloc1;
+ float dloc2;
+ float dloc3;
+ int status;
+
+ if( PyObject_Length( args ) == 3 )
+ status = PyArg_ParseTuple( args, "fff", &dloc1, &dloc2,
+ &dloc3 );
+ else
+ status = PyArg_ParseTuple( args, "(fff)", &dloc1, &dloc2,
+ &dloc3 );
+
+ if( !status )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected sequence argument of 3 floats" );
+
+ self->object->dloc[0] = dloc1;
+ self->object->dloc[1] = dloc2;
+ self->object->dloc[2] = dloc3;
+
+ /* since we have messed with object, we need to flag for DAG recalc */
+ self->object->recalc |= OB_RECALC_OB;
+
+ Py_RETURN_NONE;
+}
+
+#define DTX_MASK ( OB_AXIS | OB_TEXSPACE | OB_DRAWNAME | \
+ OB_DRAWIMAGE | OB_DRAWWIRE | OB_DRAWXRAY | OB_DRAWTRANSP )
+
+static PyObject *Object_getDrawMode( BPy_Object * self )
+{
+ return PyInt_FromLong( (long)(self->object->dtx & DTX_MASK) );
+}
+
+static int Object_setDrawMode( BPy_Object * self, PyObject * args )
+{
+ PyObject* integer = PyNumber_Int( args );
+ int value;
+
+ if( !integer )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected integer argument" );
+
+ value = ( int )PyInt_AS_LONG( integer );
+ Py_DECREF( integer );
+ if( value & ~DTX_MASK )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "undefined bit(s) set in bitfield" );
+
+ self->object->dtx = value;
+ self->object->recalc |= OB_RECALC_OB;
+
+ return 0;
+}
+
+static PyObject *Object_getDrawType( BPy_Object * self )
+{
+ return PyInt_FromLong( (long)self->object->dt );
+}
+
+static int Object_setDrawType( BPy_Object * self, PyObject * value )
+{
+ /* since we mess with object, we need to flag for DAG recalc */
+ self->object->recalc |= OB_RECALC_OB;
+
+ return EXPP_setIValueRange( value, &self->object->dt,
+ OB_BOUNDBOX, OB_TEXTURE, 'b' );
+}
+
+static int Object_setEuler( BPy_Object * self, PyObject * args )
+{
+ float rot1, rot2, rot3;
+ int status = 0; /* failure */
+
+ if( PyTuple_Check( args ) && PyTuple_Size( args ) == 1 )
+ args = PyTuple_GET_ITEM( args, 0 );
+
+ if( EulerObject_Check( args ) ) {
+ rot1 = ( ( EulerObject * ) args )->eul[0];
+ rot2 = ( ( EulerObject * ) args )->eul[1];
+ rot3 = ( ( EulerObject * ) args )->eul[2];
+ status = 1;
+ } else if( PySequence_Check( args ) && PySequence_Size( args ) == 3 ) {
+ if( PyList_Check( args ) )
+ args = PySequence_Tuple( args );
+ else
+ Py_INCREF( args );
+ status = PyArg_ParseTuple( args, "fff", &rot1, &rot2, &rot3 );
+ Py_DECREF( args );
+ }
+
+ if( !status )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected euler or sequence of 3 floats" );
+
+ self->object->rot[0] = rot1;
+ self->object->rot[1] = rot2;
+ self->object->rot[2] = rot3;
+
+ /* since we have messed with object, we need to flag for DAG recalc */
+ self->object->recalc |= OB_RECALC_OB;
+
+ return 0;
+}
+
+static int Object_setMatrix( BPy_Object * self, MatrixObject * mat )
+#if 0
+{
+ int x, y;
+
+ if( !MatrixObject_Check( mat ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected matrix object as argument" );
+
+ if( mat->rowSize == 4 && mat->colSize == 4 ) {
+ for( x = 0; x < 4; x++ ) {
+ for( y = 0; y < 4; y++ ) {
+ self->object->obmat[x][y] = mat->matrix[x][y];
+ }
+ }
+ } else if( mat->rowSize == 3 && mat->colSize == 3 ) {
+ for( x = 0; x < 3; x++ ) {
+ for( y = 0; y < 3; y++ ) {
+ self->object->obmat[x][y] = mat->matrix[x][y];
+ }
+ }
+ /* if a 3x3 matrix, clear the fourth row/column */
+ for( x = 0; x < 3; x++ )
+ self->object->obmat[x][3] = self->object->obmat[3][x] = 0.0;
+ self->object->obmat[3][3] = 1.0;
+ } else
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "expected 3x3 or 4x4 matrix" );
+
+ apply_obmat( self->object );
+
+ /* since we have messed with object, we need to flag for DAG recalc */
+ self->object->recalc |= OB_RECALC_OB;
+
+ return 0;
+}
+#endif
+{
+ int x, y;
+ float matrix[4][4]; /* for the result */
+ float invmat[4][4]; /* for the result */
+
+ if( !MatrixObject_Check( mat ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected matrix object as argument" );
+
+ if( mat->rowSize == 4 && mat->colSize == 4 ) {
+ for( x = 0; x < 4; x++ ) {
+ for( y = 0; y < 4; y++ ) {
+ matrix[x][y] = mat->matrix[x][y];
+ }
+ }
+ } else if( mat->rowSize == 3 && mat->colSize == 3 ) {
+ for( x = 0; x < 3; x++ ) {
+ for( y = 0; y < 3; y++ ) {
+ matrix[x][y] = mat->matrix[x][y];
+ }
+ }
+ /* if a 3x3 matrix, clear the fourth row/column */
+ for( x = 0; x < 3; x++ )
+ matrix[x][3] = matrix[3][x] = 0.0;
+ matrix[3][3] = 1.0;
+ } else
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "expected 3x3 or 4x4 matrix" );
+
+ /* localspace matrix is truly relative to the parent, but parameters
+ * stored in object are relative to parentinv matrix. Undo the parent
+ * inverse part before updating obmat and calling apply_obmat() */
+ if( self->object->parent ) {
+ Mat4Invert( invmat, self->object->parentinv );
+ Mat4MulMat4( self->object->obmat, matrix, invmat );
+ } else
+ Mat4CpyMat4( self->object->obmat, matrix );
+
+ apply_obmat( self->object );
+
+ /* since we have messed with object, we need to flag for DAG recalc */
+ self->object->recalc |= OB_RECALC_OB;
+
+ return 0;
+}
+
+
+/*
+ * Object_insertIpoKey()
+ * inserts Object IPO key for LOC, ROT, SIZE, LOCROT, or LOCROTSIZE
+ * Note it also inserts actions!
+ */
+
+static PyObject *Object_insertIpoKey( BPy_Object * self, PyObject * args )
+{
+ Object *ob= self->object;
+ int key = 0;
+ char *actname= NULL;
+
+ if( !PyArg_ParseTuple( args, "i", &key ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected int argument" );
+
+ if(ob->ipoflag & OB_ACTION_OB)
+ actname= "Object";
+
+ if (key == IPOKEY_LOC || key == IPOKEY_LOCROT || key == IPOKEY_LOCROTSIZE){
+ insertkey((ID *)ob, ID_OB, actname, NULL,OB_LOC_X, 0);
+ insertkey((ID *)ob, ID_OB, actname, NULL,OB_LOC_Y, 0);
+ insertkey((ID *)ob, ID_OB, actname, NULL,OB_LOC_Z, 0);
+ }
+ if (key == IPOKEY_ROT || key == IPOKEY_LOCROT || key == IPOKEY_LOCROTSIZE){
+ insertkey((ID *)ob, ID_OB, actname, NULL,OB_ROT_X, 0);
+ insertkey((ID *)ob, ID_OB, actname, NULL,OB_ROT_Y, 0);
+ insertkey((ID *)ob, ID_OB, actname, NULL,OB_ROT_Z, 0);
+ }
+ if (key == IPOKEY_SIZE || key == IPOKEY_LOCROTSIZE ){
+ insertkey((ID *)ob, ID_OB, actname, NULL,OB_SIZE_X, 0);
+ insertkey((ID *)ob, ID_OB, actname, NULL,OB_SIZE_Y, 0);
+ insertkey((ID *)ob, ID_OB, actname, NULL,OB_SIZE_Z, 0);
+ }
+
+ if (key == IPOKEY_PI_STRENGTH ){
+ insertkey((ID *)ob, ID_OB, actname, NULL, OB_PD_FSTR, 0);
+ } else if (key == IPOKEY_PI_FALLOFF ){
+ insertkey((ID *)ob, ID_OB, actname, NULL, OB_PD_FFALL, 0);
+ } else if (key == IPOKEY_PI_SURFACEDAMP ){
+ insertkey((ID *)ob, ID_OB, actname, NULL, OB_PD_SDAMP, 0);
+ } else if (key == IPOKEY_PI_RANDOMDAMP ){
+ insertkey((ID *)ob, ID_OB, actname, NULL, OB_PD_RDAMP, 0);
+ } else if (key == IPOKEY_PI_PERM ){
+ insertkey((ID *)ob, ID_OB, actname, NULL, OB_PD_PERM, 0);
+ }
+
+ allspace(REMAKEIPO, 0);
+ EXPP_allqueue(REDRAWIPO, 0);
+ EXPP_allqueue(REDRAWVIEW3D, 0);
+ EXPP_allqueue(REDRAWACTION, 0);
+ EXPP_allqueue(REDRAWNLA, 0);
+
+ Py_RETURN_NONE;
+}
+
+/*
+ * Object_insertPoseKey()
+ * inserts a Action Pose key from a given pose (sourceaction, frame) to the
+ * active action to a given framenum
+ */
+
+static PyObject *Object_insertPoseKey( BPy_Object * self, PyObject * args )
+{
+ Object *ob= self->object;
+ BPy_Action *sourceact;
+ char *chanName;
+ int actframe;
+
+
+ /* for doing the time trick, similar to editaction bake_action_with_client() */
+ int oldframe;
+ int curframe;
+
+ if( !PyArg_ParseTuple( args, "O!sii", &Action_Type, &sourceact,
+ &chanName, &actframe, &curframe ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expects an action to copy poses from, a string for chan/bone name, an int argument for frame to extract from the action and finally another int for the frame where to put the new key in the active object.action" );
+
+ extract_pose_from_action(ob->pose, sourceact->action, (float)actframe);
+
+ oldframe = G.scene->r.cfra;
+ G.scene->r.cfra = curframe;
+
+ /* XXX: must check chanName actually exists, otherwise segfaults! */
+ //achan = get_action_channel(sourceact->action, chanName);
+
+ insertkey(&ob->id, ID_PO, chanName, NULL, AC_LOC_X, 0);
+ insertkey(&ob->id, ID_PO, chanName, NULL, AC_LOC_Y, 0);
+ insertkey(&ob->id, ID_PO, chanName, NULL, AC_LOC_Z, 0);
+ insertkey(&ob->id, ID_PO, chanName, NULL, AC_QUAT_X, 0);
+ insertkey(&ob->id, ID_PO, chanName, NULL, AC_QUAT_Y, 0);
+ insertkey(&ob->id, ID_PO, chanName, NULL, AC_QUAT_Z, 0);
+ insertkey(&ob->id, ID_PO, chanName, NULL, AC_QUAT_W, 0);
+ insertkey(&ob->id, ID_PO, chanName, NULL, AC_SIZE_X, 0);
+ insertkey(&ob->id, ID_PO, chanName, NULL, AC_SIZE_Y, 0);
+ insertkey(&ob->id, ID_PO, chanName, NULL, AC_SIZE_Z, 0);
+
+ G.scene->r.cfra = oldframe;
+
+ allspace(REMAKEIPO, 0);
+ EXPP_allqueue(REDRAWIPO, 0);
+ EXPP_allqueue(REDRAWVIEW3D, 0);
+ EXPP_allqueue(REDRAWACTION, 0);
+ EXPP_allqueue(REDRAWNLA, 0);
+
+ /* restore, but now with the new action in place */
+ /*extract_pose_from_action(ob->pose, ob->action, G.scene->r.cfra);
+ where_is_pose(ob);*/
+
+ EXPP_allqueue(REDRAWACTION, 1);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Object_insertCurrentPoseKey( BPy_Object * self, PyObject * args )
+{
+ Object *ob= self->object;
+ char *chanName;
+
+ /* for doing the time trick, similar to editaction bake_action_with_client() */
+ int oldframe;
+ int curframe;
+
+ if( !PyArg_ParseTuple( args, "si", &chanName, &curframe ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected chan/bone name, and a time (int) argument" );
+
+ oldframe = G.scene->r.cfra;
+ G.scene->r.cfra = curframe;
+
+ /* XXX: must check chanName actually exists, otherwise segfaults! */
+
+ insertkey(&ob->id, ID_PO, chanName, NULL, AC_LOC_X, 0);
+ insertkey(&ob->id, ID_PO, chanName, NULL, AC_LOC_Y, 0);
+ insertkey(&ob->id, ID_PO, chanName, NULL, AC_LOC_Z, 0);
+ insertkey(&ob->id, ID_PO, chanName, NULL, AC_QUAT_X, 0);
+ insertkey(&ob->id, ID_PO, chanName, NULL, AC_QUAT_Y, 0);
+ insertkey(&ob->id, ID_PO, chanName, NULL, AC_QUAT_Z, 0);
+ insertkey(&ob->id, ID_PO, chanName, NULL, AC_QUAT_W, 0);
+ insertkey(&ob->id, ID_PO, chanName, NULL, AC_SIZE_X, 0);
+ insertkey(&ob->id, ID_PO, chanName, NULL, AC_SIZE_Y, 0);
+ insertkey(&ob->id, ID_PO, chanName, NULL, AC_SIZE_Z, 0);
+
+ G.scene->r.cfra = oldframe;
+
+ allspace(REMAKEIPO, 0);
+ EXPP_allqueue(REDRAWIPO, 0);
+ EXPP_allqueue(REDRAWVIEW3D, 0);
+ EXPP_allqueue(REDRAWACTION, 0);
+ EXPP_allqueue(REDRAWNLA, 0);
+
+ /* restore */
+ extract_pose_from_action(ob->pose, ob->action, (float)G.scene->r.cfra);
+ where_is_pose(ob);
+
+ EXPP_allqueue(REDRAWACTION, 1);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Object_setConstraintInfluenceForBone( BPy_Object * self,
+ PyObject * args )
+{
+ char *boneName, *constName;
+ float influence;
+ IpoCurve *icu;
+
+ if( !PyArg_ParseTuple( args, "ssf", &boneName, &constName, &influence ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expects bonename, constraintname, influenceval" );
+
+ icu = verify_ipocurve((ID *)self->object, ID_CO, boneName, constName,
+ CO_ENFORCE);
+
+ if (!icu)
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "cannot get a curve from this IPO, may be using libdata" );
+
+ insert_vert_icu(icu, (float)CFRA, influence, 0);
+ self->object->recalc |= OB_RECALC_OB;
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Object_copyNLA( BPy_Object * self, PyObject * args ) {
+ BPy_Object *bpy_fromob;
+
+ if( !PyArg_ParseTuple( args, "O", &bpy_fromob ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "requires a Blender Object to copy NLA strips from." );
+ copy_nlastrips(&self->object->nlastrips, &bpy_fromob->object->nlastrips);
+ self->object->recalc |= OB_RECALC_OB;
+
+ Py_RETURN_NONE;
+}
+
+/*Now that BPY has a Strip type, return the created strip.*/
+static PyObject *Object_convertActionToStrip( BPy_Object * self )
+{
+ bActionStrip *strip = convert_action_to_strip( self->object );
+ return ActionStrip_CreatePyObject( strip );
+}
+
+static PyObject *Object_setLocation( BPy_Object * self, PyObject * args )
+{
+ float loc1;
+ float loc2;
+ float loc3;
+ int status;
+
+ if( PyObject_Length( args ) == 3 )
+ status = PyArg_ParseTuple( args, "fff", &loc1, &loc2, &loc3 );
+ else
+ status = PyArg_ParseTuple( args, "(fff)", &loc1, &loc2,
+ &loc3 );
+
+ if( !status )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected list argument of 3 floats" );
+
+ self->object->loc[0] = loc1;
+ self->object->loc[1] = loc2;
+ self->object->loc[2] = loc3;
+
+ /* since we have messed with object, we need to flag for DAG recalc */
+ self->object->recalc |= OB_RECALC_OB;
+ DAG_object_flush_update(G.scene, self->object, OB_RECALC_DATA);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Object_setMaterials( BPy_Object * self, PyObject * args )
+{
+ PyObject *list;
+ int len;
+ int i;
+ Material **matlist = NULL;
+
+ if (!self->object->data)
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "object must be linked to object data (e.g. to a mesh) first" );
+
+ if( !PyArg_ParseTuple( args, "O!", &PyList_Type, &list ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a list (of materials or None) as argument" );
+
+ len = PyList_Size(list);
+
+ /* Object_getMaterials can return '[]' (zero-length list), so that must
+ * also be accepted by this method for
+ * ob2.setMaterials(ob1.getMaterials()) to always work.
+ * In other words, list can be '[]' and so len can be zero. */
+ if (len > 0) {
+ if( len > MAXMAT )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "list must have from 1 up to 16 materials" );
+
+ matlist = EXPP_newMaterialList_fromPyList( list );
+ if( !matlist )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "material list must be a list of valid materials!" );
+ }
+
+ if( self->object->mat )
+ EXPP_releaseMaterialList( self->object->mat, self->object->totcol );
+
+ /* Increase the user count on all materials */
+ for( i = 0; i < len; i++ ) {
+ if( matlist[i] )
+ id_us_plus( ( ID * ) matlist[i] );
+ }
+ self->object->mat = matlist;
+ self->object->totcol = (char)len;
+ self->object->actcol = (char)len;
+
+ switch ( self->object->type ) {
+ case OB_CURVE: /* fall through */
+ case OB_FONT: /* fall through */
+ case OB_MESH: /* fall through */
+ case OB_MBALL: /* fall through */
+ case OB_SURF:
+ EXPP_synchronizeMaterialLists( self->object );
+ break;
+ default:
+ break;
+ }
+
+ /* since we have messed with object, we need to flag for DAG recalc */
+ self->object->recalc |= OB_RECALC_OB;
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Object_setSize( BPy_Object * self, PyObject * args )
+{
+ float sizex;
+ float sizey;
+ float sizez;
+ int status;
+
+ if( PyObject_Length( args ) == 3 )
+ status = PyArg_ParseTuple( args, "fff", &sizex, &sizey,
+ &sizez );
+ else
+ status = PyArg_ParseTuple( args, "(fff)", &sizex, &sizey,
+ &sizez );
+
+ if( !status )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected list argument of 3 floats" );
+
+ self->object->size[0] = sizex;
+ self->object->size[1] = sizey;
+ self->object->size[2] = sizez;
+
+ /* since we have messed with object, we need to flag for DAG recalc */
+ self->object->recalc |= OB_RECALC_OB;
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Object_makeTrack( BPy_Object * self, PyObject * args )
+{
+ BPy_Object *tracked = NULL;
+ Object *ob = self->object;
+ int fast = 0;
+
+ if( !PyArg_ParseTuple( args, "O!|i", &Object_Type, &tracked, &fast ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected an object and optionally also an int as arguments." );
+
+ ob->track = tracked->object;
+
+ if( !fast )
+ DAG_scene_sort( G.scene );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Object_shareFrom( BPy_Object * self, PyObject * args )
+{
+ BPy_Object *object;
+ ID *id;
+ ID *oldid;
+
+ if( !PyArg_ParseTuple( args, "O!", &Object_Type, &object ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected an object argument" );
+
+ if( !object->object->data )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "Object argument has no data linked yet or is an empty" );
+
+ if( self->object->type != object->object->type &&
+ self->realtype != object->object->type)
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "objects are not of same data type" );
+
+ switch ( object->object->type ) {
+ case OB_MESH:
+ case OB_LAMP:
+ case OB_CAMERA: /* we can probably add the other types, too */
+ case OB_ARMATURE:
+ case OB_CURVE:
+ case OB_SURF:
+ case OB_LATTICE:
+
+ /* if this object had no data, we need to enable the realtype */
+ if (self->object->type == OB_EMPTY) {
+ self->object->type= self->realtype;
+ self->realtype = OB_EMPTY;
+ }
+
+ oldid = ( ID * ) self->object->data;
+ id = ( ID * ) object->object->data;
+ self->object->data = object->object->data;
+
+ if( self->object->type == OB_MESH && id ) {
+ self->object->totcol = 0;
+ EXPP_synchronizeMaterialLists( self->object );
+ }
+
+ id_us_plus( id );
+ if( oldid ) {
+ if( oldid->us > 0 ) {
+ oldid->us--;
+ } else {
+ return EXPP_ReturnPyObjError ( PyExc_RuntimeError,
+ "old object reference count below 0" );
+ }
+ }
+
+ Py_RETURN_NONE;
+ default:
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "object type not supported" );
+ }
+}
+
+static PyObject *Object_getAllProperties( BPy_Object * self )
+{
+ PyObject *prop_list, *pyval;
+ bProperty *prop = NULL;
+
+ prop_list = PyList_New( 0 );
+
+ prop = self->object->prop.first;
+ while( prop ) {
+ pyval = Property_CreatePyObject( prop );
+ PyList_Append( prop_list, pyval );
+ Py_DECREF(pyval);
+ prop = prop->next;
+ }
+ return prop_list;
+}
+
+static PyObject *Object_getProperty( BPy_Object * self, PyObject * args )
+{
+ char *prop_name = NULL;
+ bProperty *prop = NULL;
+
+ if( !PyArg_ParseTuple( args, "s", &prop_name ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a string" );
+
+ prop = get_property( self->object, prop_name );
+ if( prop )
+ return Property_CreatePyObject( prop );
+
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't find the property" );
+}
+
+static PyObject *Object_addProperty( BPy_Object * self, PyObject * args )
+{
+ bProperty *prop = NULL;
+ char *prop_name = NULL;
+ PyObject *prop_data = Py_None;
+ char *prop_type = NULL;
+ short type = -1;
+ BPy_Property *py_prop = NULL;
+ int argslen = PyObject_Length( args );
+
+ if( argslen == 3 || argslen == 2 ) {
+ if( !PyArg_ParseTuple( args, "sO|s", &prop_name, &prop_data,
+ &prop_type ) ) {
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expecting string, data, and optional string" );
+ }
+ } else if( argslen == 1 ) {
+ if( !PyArg_ParseTuple( args, "O!", &property_Type, &py_prop ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expecting a Property" );
+
+ if( py_prop->property != NULL )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "Property is already added to an object" );
+ } else {
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected 1,2 or 3 arguments" );
+ }
+
+ /*parse property type*/
+ if( !py_prop ) {
+ if( prop_type ) {
+ if( BLI_streq( prop_type, "BOOL" ) )
+ type = PROP_BOOL;
+ else if( BLI_streq( prop_type, "INT" ) )
+ type = PROP_INT;
+ else if( BLI_streq( prop_type, "FLOAT" ) )
+ type = PROP_FLOAT;
+ else if( BLI_streq( prop_type, "TIME" ) )
+ type = PROP_TIME;
+ else if( BLI_streq( prop_type, "STRING" ) )
+ type = PROP_STRING;
+ else
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "BOOL, INT, FLOAT, TIME or STRING expected" );
+ } else {
+ /*use the default*/
+ if( PyInt_Check( prop_data ) )
+ type = PROP_INT;
+ else if( PyFloat_Check( prop_data ) )
+ type = PROP_FLOAT;
+ else if( PyString_Check( prop_data ) )
+ type = PROP_STRING;
+ }
+ } else {
+ type = py_prop->type;
+ }
+
+ /*initialize a new bProperty of the specified type*/
+ prop = new_property( type );
+
+ /*parse data*/
+ if( !py_prop ) {
+ BLI_strncpy( prop->name, prop_name, 32 );
+ if( PyInt_Check( prop_data ) ) {
+ *( ( int * ) &prop->data ) =
+ ( int ) PyInt_AsLong( prop_data );
+ } else if( PyFloat_Check( prop_data ) ) {
+ *( ( float * ) &prop->data ) =
+ ( float ) PyFloat_AsDouble( prop_data );
+ } else if( PyString_Check( prop_data ) ) {
+ BLI_strncpy( prop->poin,
+ PyString_AsString( prop_data ),
+ MAX_PROPSTRING );
+ }
+ } else {
+ py_prop->property = prop;
+
+ /* this should never be able to happen is we just assigned a valid
+ * proper to py_prop->property */
+
+ if( !updateProperyData( py_prop ) ) {
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "Could not update property data" );
+ }
+ }
+
+ /*add to property listbase for the object*/
+ BLI_addtail( &self->object->prop, prop );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Object_removeProperty( BPy_Object * self, PyObject * args )
+{
+ char *prop_name = NULL;
+ BPy_Property *py_prop = NULL;
+ bProperty *prop = NULL;
+
+ /* we accept either a property stringname or actual object */
+ if( PyTuple_Size( args ) == 1 ) {
+ PyObject *prop = PyTuple_GET_ITEM( args, 0 );
+ if( BPy_Property_Check( prop ) )
+ py_prop = (BPy_Property *)prop;
+ else
+ prop_name = PyString_AsString( prop );
+ }
+ if( !py_prop && !prop_name )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a Property or a string" );
+
+ /*remove the link, free the data, and update the py struct*/
+ if( py_prop ) {
+ BLI_remlink( &self->object->prop, py_prop->property );
+ if( updatePyProperty( py_prop ) ) {
+ free_property( py_prop->property );
+ py_prop->property = NULL;
+ }
+ } else {
+ prop = get_property( self->object, prop_name );
+ if( prop ) {
+ BLI_remlink( &self->object->prop, prop );
+ free_property( prop );
+ }
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *Object_removeAllProperties( BPy_Object * self )
+{
+ free_properties( &self->object->prop );
+ Py_RETURN_NONE;
+}
+
+static PyObject *Object_copyAllPropertiesTo( BPy_Object * self,
+ PyObject * args )
+{
+ PyObject *dest;
+ bProperty *prop = NULL;
+ bProperty *propn = NULL;
+
+ if( !PyArg_ParseTuple( args, "O!", &Object_Type, &dest ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected an Object" );
+
+ /*make a copy of all its properties*/
+ prop = self->object->prop.first;
+ while( prop ) {
+ propn = copy_property( prop );
+ BLI_addtail( &( ( BPy_Object * ) dest )->object->prop, propn );
+ prop = prop->next;
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Object_addScriptLink( BPy_Object * self, PyObject * args )
+{
+ Object *obj = self->object;
+ ScriptLink *slink = &obj->scriptlink;
+ return EXPP_addScriptLink( slink, args, 0 );
+}
+
+static PyObject *Object_clearScriptLinks( BPy_Object * self, PyObject * args )
+{
+ Object *obj = self->object;
+ ScriptLink *slink = &obj->scriptlink;
+ return EXPP_clearScriptLinks( slink, args );
+}
+
+static PyObject *Object_getScriptLinks( BPy_Object * self, PyObject * value )
+{
+ Object *obj = self->object;
+ ScriptLink *slink = &obj->scriptlink;
+ return EXPP_getScriptLinks( slink, value, 0 );
+}
+
+static PyObject *Object_getNLAflagBits ( BPy_Object * self )
+{
+ if (self->object->nlaflag & OB_NLA_OVERRIDE)
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+}
+
+static int Object_setNLAflagBits ( BPy_Object * self, PyObject * value )
+{
+ int param;
+
+ param = PyObject_IsTrue( value );
+ if( param == -1 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected True/False or 0/1" );
+
+ if (param)
+ self->object->nlaflag |= OB_NLA_OVERRIDE;
+ else
+ self->object->nlaflag &= ~OB_NLA_OVERRIDE;
+
+ self->object->recalc |= OB_RECALC_OB;
+
+ return 0;
+}
+
+static PyObject *Object_getDupliObjects( BPy_Object * self )
+{
+ Object *ob= self->object;
+
+ if(ob->transflag & OB_DUPLI) {
+ /* before make duplis, update particle for current frame */
+ if(ob->transflag & OB_DUPLIVERTS) {
+ PartEff *paf= give_parteff(ob);
+ if(paf) {
+ if(paf->flag & PAF_ANIMATED) build_particle_system(ob);
+ }
+ }
+ if(ob->type!=OB_MBALL) {
+ PyObject *list;
+ DupliObject *dupob;
+ int index;
+ ListBase *duplilist = object_duplilist(G.scene, ob);
+
+ list = PyList_New( BLI_countlist(duplilist) );
+ if( !list )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyList_New() failed" );
+
+ for(dupob= duplilist->first, index=0; dupob; dupob= dupob->next, index++) {
+ PyObject *pair;
+ pair = PyTuple_New( 2 );
+
+ PyTuple_SET_ITEM( pair, 0, Object_CreatePyObject(dupob->ob) );
+ PyTuple_SET_ITEM( pair, 1, newMatrixObject((float*)dupob->mat,4,4,Py_NEW) );
+ PyList_SET_ITEM( list, index, pair);
+ }
+ free_object_duplilist(duplilist);
+ return list;
+ }
+ }
+ return PyList_New( 0 );
+}
+
+static PyObject *Object_getDupliGroup( BPy_Object * self )
+{
+ Object *ob= self->object;
+
+ if( ob->dup_group )
+ return Group_CreatePyObject( ob->dup_group );
+
+ Py_RETURN_NONE;
+}
+
+static int Object_setDupliGroup( BPy_Object * self, PyObject * value )
+{
+ return GenericLib_assignData(value, (void **) &self->object->dup_group, 0, 1, ID_GR, 0);
+}
+
+static PyObject *Object_getEffects( BPy_Object * self )
+{
+ PyObject *effect_list, *pyval;
+ Effect *eff;
+
+ effect_list = PyList_New( 0 );
+ if( !effect_list )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "PyList_New() failed" );
+
+ eff = self->object->effect.first;
+
+ while( eff ) {
+ pyval = EffectCreatePyObject( eff, self->object );
+ PyList_Append( effect_list, pyval );
+ Py_DECREF(pyval);
+ eff = eff->next;
+ }
+ return effect_list;
+}
+
+static PyObject *Object_getActionStrips( BPy_Object * self )
+{
+ return ActionStrips_CreatePyObject( self->object );
+}
+
+static PyObject *Object_getConstraints( BPy_Object * self )
+{
+ return ObConstraintSeq_CreatePyObject( self->object );
+}
+
+static PyObject *Object_getModifiers( BPy_Object * self )
+{
+ return ModSeq_CreatePyObject( self->object, NULL );
+}
+
+static int Object_setModifiers( BPy_Object * self, PyObject * value )
+{
+ BPy_ModSeq *pymodseq;
+ ModifierData *md;
+
+ if (!BPy_ModSeq_Check(value))
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "can only assign another objects modifiers" );
+
+ pymodseq = ( BPy_ModSeq * ) value;
+
+ if (self->object->type != pymodseq->object->type)
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "can only assign modifiers between objects of the same type" );
+
+ if (self->object == pymodseq->object)
+ return 0;
+
+ object_free_modifiers(self->object);
+ for (md=pymodseq->object->modifiers.first; md; md=md->next) {
+ if (md->type!=eModifierType_Hook) {
+ ModifierData *nmd = modifier_new(md->type);
+ modifier_copyData(md, nmd);
+ BLI_addtail(&self->object->modifiers, nmd);
+ }
+ }
+
+ DAG_object_flush_update(G.scene, self->object, OB_RECALC_DATA);
+ return 0;
+}
+
+static PyObject *Object_insertShapeKey(BPy_Object * self)
+{
+ insert_shapekey(self->object);
+ Py_RETURN_NONE;
+}
+
+/* __copy__() */
+static PyObject *Object_copy(BPy_Object * self)
+{
+ /* copy_object never returns NULL */
+ struct Object *object= copy_object( self->object );
+ object->id.us= 0; /*is 1 by default, not sure why */
+
+ /* Create a Python object from it. */
+ return Object_CreatePyObject( object );
+}
+
+/*****************************************************************************/
+/* Function: Object_CreatePyObject */
+/* Description: This function will create a new BlenObject from an existing */
+/* Object structure. */
+/*****************************************************************************/
+PyObject *Object_CreatePyObject( struct Object * obj )
+{
+ BPy_Object *blen_object;
+
+ if( !obj ) Py_RETURN_NONE;
+
+ blen_object =
+ ( BPy_Object * ) PyObject_NEW( BPy_Object, &Object_Type );
+
+ if( blen_object == NULL ) {
+ return ( NULL );
+ }
+ blen_object->object = obj;
+ blen_object->realtype = OB_EMPTY;
+ obj->id.us++;
+ return ( ( PyObject * ) blen_object );
+}
+
+/*****************************************************************************/
+/* Function: Object_FromPyObject */
+/* Description: This function returns the Blender object from the given */
+/* PyObject. */
+/*****************************************************************************/
+struct Object *Object_FromPyObject( PyObject * py_obj )
+{
+ BPy_Object *blen_obj;
+
+ blen_obj = ( BPy_Object * ) py_obj;
+ return ( blen_obj->object );
+}
+
+/*****************************************************************************/
+/* Function: Object_dealloc */
+/* Description: This is a callback function for the BlenObject type. It is */
+/* the destructor function. */
+/*****************************************************************************/
+static void Object_dealloc( BPy_Object * self )
+{
+ if( self->realtype != OB_EMPTY )
+ free_libblock_us( &G.main->object, self->object );
+ else
+ self->object->id.us--;
+
+#if 0 /* this will adjust the ID and if zero delete the object */
+ free_libblock_us( &G.main->object, self->object );
+#endif
+ PyObject_DEL( self );
+}
+
+/*****************************************************************************/
+/* Function: Object_compare */
+/* Description: This is a callback function for the BPy_Object type. It */
+/* compares two Object_Type objects. Only the "==" and "!=" */
+/* comparisons are meaninful. Returns 0 for equality and -1 if */
+/* they don't point to the same Blender Object struct. */
+/* In Python it becomes 1 if they are equal, 0 otherwise. */
+/*****************************************************************************/
+static int Object_compare( BPy_Object * a, BPy_Object * b )
+{
+ return ( a->object == b->object ) ? 0 : -1;
+}
+
+/*****************************************************************************/
+/* Function: Object_repr */
+/* Description: This is a callback function for the BPy_Object type. It */
+/* builds a meaninful string to represent object objects. */
+/*****************************************************************************/
+static PyObject *Object_repr( BPy_Object * self )
+{
+ return PyString_FromFormat( "[Object \"%s\"]",
+ self->object->id.name + 2 );
+}
+
+/* Particle Deflection functions */
+
+static PyObject *Object_getPIDeflection( BPy_Object * self )
+{
+ if( !self->object->pd && !setupPI(self->object) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "particle deflection could not be accessed" );
+
+ return PyBool_FromLong( ( long ) self->object->pd->deflect );
+}
+
+static int Object_setPIDeflection( BPy_Object * self, PyObject * value )
+{
+ int param;
+
+ if( !self->object->pd && !setupPI(self->object) )
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "particle deflection could not be accessed" );
+
+ param = PyObject_IsTrue( value );
+ if( param == -1 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected true/false argument" );
+
+ self->object->pd->deflect = (short)param;
+ self->object->recalc |= OB_RECALC_OB;
+
+ return 0;
+}
+
+static PyObject *Object_getPIType( BPy_Object * self )
+{
+ if( !self->object->pd && !setupPI(self->object) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "particle deflection could not be accessed" );
+
+ return PyInt_FromLong( ( long )self->object->pd->forcefield );
+}
+
+static int Object_setPIType( BPy_Object * self, PyObject * value )
+{
+ int status;
+ int oldforcefield;
+
+ if( !self->object->pd && !setupPI(self->object) )
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "particle deflection could not be accessed" );
+
+ oldforcefield = self->object->pd->forcefield;
+ status = EXPP_setIValueRange( value, &self->object->pd->forcefield,
+ PFIELD_FORCE, PFIELD_GUIDE, 'h' );
+
+ /*
+ * if value was set successfully but is PFIELD_MAGNET, restore the old
+ * value and throw exception
+ */
+ if( !status ) {
+ if ( self->object->pd->forcefield == PFIELD_MAGNET ) {
+ self->object->pd->forcefield = oldforcefield;
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "PFIELD_MAGNET not supported" );
+ }
+ self->object->recalc |= OB_RECALC_OB;
+ }
+ return status;
+}
+
+static PyObject *Object_getPIUseMaxDist( BPy_Object * self )
+{
+ if( !self->object->pd && !setupPI(self->object) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "particle deflection could not be accessed" );
+
+ return PyBool_FromLong( ( long )self->object->pd->flag );
+}
+
+static int Object_setPIUseMaxDist( BPy_Object * self, PyObject * value )
+{
+ int param;
+
+ if( !self->object->pd && !setupPI(self->object) )
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "particle deflection could not be accessed" );
+
+ param = PyObject_IsTrue( value );
+ if( param == -1 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected true/false argument" );
+
+ self->object->pd->flag = (short)param;
+ self->object->recalc |= OB_RECALC_OB;
+
+ return 0;
+}
+
+/* RIGIDBODY FUNCTIONS */
+
+static PyObject *Object_getRBMass( BPy_Object * self )
+{
+ return PyFloat_FromDouble( (double)self->object->mass );
+}
+
+static int Object_setRBMass( BPy_Object * self, PyObject * args )
+{
+ float value;
+ PyObject* flt = PyNumber_Float( args );
+
+ if( !flt )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected float argument" );
+ value = (float)PyFloat_AS_DOUBLE( flt );
+ Py_DECREF( flt );
+
+ if( value < 0.0f )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "acceptable values are non-negative, 0.0 or more" );
+
+ self->object->mass = value;
+ self->object->recalc |= OB_RECALC_OB;
+
+ return 0;
+}
+
+/* this is too low level, possible to add helper methods */
+
+#define GAMEFLAG_MASK ( OB_DYNAMIC | OB_CHILD | OB_ACTOR | OB_DO_FH | \
+ OB_ROT_FH | OB_ANISOTROPIC_FRICTION | OB_GHOST | OB_RIGID_BODY | \
+ OB_BOUNDS | OB_COLLISION_RESPONSE | OB_SECTOR | OB_PROP | \
+ OB_MAINACTOR )
+
+static PyObject *Object_getRBFlags( BPy_Object * self )
+{
+ return PyInt_FromLong( (long)( self->object->gameflag & GAMEFLAG_MASK ) );
+}
+
+static int Object_setRBFlags( BPy_Object * self, PyObject * args )
+{
+ PyObject* integer = PyNumber_Int( args );
+ int value;
+
+ if( !integer )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected integer argument" );
+
+ value = ( int )PyInt_AS_LONG( integer );
+ Py_DECREF( integer );
+ if( value & ~GAMEFLAG_MASK )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "undefined bit(s) set in bitfield" );
+
+ self->object->gameflag = value;
+ self->object->recalc |= OB_RECALC_OB;
+
+ return 0;
+}
+
+static PyObject *Object_getRBShapeBoundType( BPy_Object * self )
+{
+ return PyInt_FromLong( (long)self->object->boundtype );
+}
+
+static int Object_setRBShapeBoundType( BPy_Object * self, PyObject * args )
+{
+ self->object->recalc |= OB_RECALC_OB;
+ return EXPP_setIValueRange( args, &self->object->boundtype,
+ 0, OB_BOUND_DYN_MESH, 'h' );
+}
+
+/* SOFTBODY FUNCTIONS */
+
+PyObject *Object_isSB(BPy_Object *self)
+{
+ if( self->object->soft )
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+}
+
+static PyObject *Object_getSBUseGoal( BPy_Object * self )
+{
+ if( !self->object->soft && !setupSB(self->object) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "softbody could not be accessed" );
+
+ if( self->object->softflag & OB_SB_GOAL )
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+}
+
+static int Object_setSBUseGoal( BPy_Object * self, PyObject * value )
+{
+ int setting = PyObject_IsTrue( value );
+
+ if( !self->object->soft && !setupSB(self->object) )
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "softbody could not be accessed" );
+
+ if( setting == -1 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected true/false argument" );
+
+ if( setting )
+ self->object->softflag |= OB_SB_GOAL;
+ else
+ self->object->softflag &= ~OB_SB_GOAL;
+
+ self->object->recalc |= OB_RECALC_OB;
+ return 0;
+}
+
+static PyObject *Object_getSBUseEdges( BPy_Object * self )
+{
+ if( !self->object->soft && !setupSB(self->object) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "softbody could not be accessed" );
+
+ if( self->object->softflag & OB_SB_EDGES )
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+}
+
+static int Object_setSBUseEdges( BPy_Object * self, PyObject * value )
+{
+ int setting = PyObject_IsTrue( value );
+
+ if( !self->object->soft && !setupSB(self->object) )
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "softbody could not be accessed" );
+
+ if( setting == -1 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected true/false argument" );
+
+ if( setting )
+ self->object->softflag |= OB_SB_EDGES;
+ else
+ self->object->softflag &= ~OB_SB_EDGES;
+
+ self->object->recalc |= OB_RECALC_OB;
+ return 0;
+}
+
+static PyObject *Object_getSBStiffQuads( BPy_Object * self )
+{
+ if( !self->object->soft && !setupSB(self->object) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "softbody could not be accessed" );
+
+ if( self->object->softflag & OB_SB_QUADS )
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+}
+
+static int Object_setSBStiffQuads( BPy_Object * self, PyObject * value )
+{
+ int setting = PyObject_IsTrue( value );
+
+ if( !self->object->soft && !setupSB(self->object) )
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "softbody could not be accessed" );
+
+ if( setting == -1 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected true/false argument" );
+
+ if( setting )
+ self->object->softflag |= OB_SB_QUADS;
+ else
+ self->object->softflag &= ~OB_SB_QUADS;
+
+ self->object->recalc |= OB_RECALC_OB;
+ return 0;
+}
+
+static int setupSB( Object* ob )
+{
+ ob->soft= sbNew();
+ ob->softflag |= OB_SB_GOAL|OB_SB_EDGES;
+
+ if( !ob->soft )
+ return 0;
+ /* all this is initialized in sbNew() */
+#if 0
+ ob->soft->mediafrict = 0.5f;
+ ob->soft->nodemass = 1.0f;
+ ob->soft->grav = 0.0f;
+ ob->soft->rklimit = 0.1f;
+
+ ob->soft->goalspring = 0.5f;
+ ob->soft->goalfrict = 0.0f;
+ ob->soft->mingoal = 0.0f;
+ ob->soft->maxgoal = 1.0f;
+ ob->soft->defgoal = 0.7f;
+
+ ob->soft->inspring = 0.5f;
+ ob->soft->infrict = 0.5f;
+#endif
+ return 1;
+}
+
+static int setupPI( Object* ob )
+{
+ if( ob->pd==NULL ) {
+ ob->pd= MEM_callocN(sizeof(PartDeflect), "PartDeflect");
+ /* and if needed, init here */
+ }
+
+ if( !ob->pd )
+ return 0;
+
+ ob->pd->deflect =0;
+ ob->pd->forcefield =0;
+ ob->pd->flag =0;
+ ob->pd->pdef_damp =0;
+ ob->pd->pdef_rdamp =0;
+ ob->pd->pdef_perm =0;
+ ob->pd->f_strength =0;
+ ob->pd->f_power =0;
+ ob->pd->maxdist =0;
+ return 1;
+}
+
+/*
+ * scan list of Objects looking for matching obdata.
+ * if found, set OB_RECALC_DATA flag.
+ * call this from a bpy type update() method.
+ */
+
+void Object_updateDag( void *data )
+{
+ Object *ob;
+
+ if( !data )
+ return;
+
+ for( ob = G.main->object.first; ob; ob= ob->id.next ){
+ if( ob->data == data ) {
+ ob->recalc |= OB_RECALC_DATA;
+ }
+ }
+}
+
+/*
+ * utilities routines for handling generic getters and setters
+ */
+
+/*
+ * get integer attributes
+ */
+
+static PyObject *getIntAttr( BPy_Object *self, void *type )
+{
+ int param;
+ struct Object *object = self->object;
+
+ switch( (int)type ) {
+ case EXPP_OBJ_ATTR_LAYERMASK:
+ param = object->lay;
+ break;
+ case EXPP_OBJ_ATTR_COLBITS:
+ param = object->colbits;
+ if( param < 0 ) param += 65536;
+ break;
+ case EXPP_OBJ_ATTR_DRAWMODE:
+ param = object->dtx;
+ break;
+ case EXPP_OBJ_ATTR_DRAWTYPE:
+ param = object->dt;
+ break;
+ case EXPP_OBJ_ATTR_PARENT_TYPE:
+ param = object->partype;
+ break;
+ case EXPP_OBJ_ATTR_DUPON:
+ param = object->dupon;
+ break;
+ case EXPP_OBJ_ATTR_DUPOFF:
+ param = object->dupoff;
+ break;
+ case EXPP_OBJ_ATTR_DUPSTA:
+ param = object->dupsta;
+ break;
+ case EXPP_OBJ_ATTR_DUPEND:
+ param = object->dupend;
+ break;
+ case EXPP_OBJ_ATTR_PASSINDEX:
+ param = object->index;
+ break;
+ case EXPP_OBJ_ATTR_ACT_MATERIAL:
+ param = object->actcol;
+ break;
+ case EXPP_OBJ_ATTR_ACT_SHAPE:
+ param = object->shapenr;
+ break;
+ default:
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "undefined type in getIntAttr" );
+ }
+
+ return PyInt_FromLong( param );
+}
+
+/*
+ * set integer attributes which require clamping
+ */
+
+static int setIntAttrClamp( BPy_Object *self, PyObject *value, void *type )
+{
+ void *param;
+ struct Object *object = self->object;
+ int min, max, size;
+
+ switch( (int)type ) {
+ case EXPP_OBJ_ATTR_DUPON:
+ min = 1;
+ max = 1500;
+ size = 'H'; /* in case max is later made > 32767 */
+ param = (void *)&object->dupon;
+ break;
+ case EXPP_OBJ_ATTR_DUPOFF:
+ min = 0;
+ max = 1500;
+ size = 'H'; /* in case max is later made > 32767 */
+ param = (void *)&object->dupoff;
+ break;
+ case EXPP_OBJ_ATTR_DUPSTA:
+ min = 1;
+ max = 32767;
+ size = 'H'; /* in case max is later made > 32767 */
+ param = (void *)&object->dupsta;
+ break;
+ case EXPP_OBJ_ATTR_DUPEND:
+ min = 1;
+ max = 32767;
+ size = 'H'; /* in case max is later made > 32767 */
+ param = (void *)&object->dupend;
+ break;
+ case EXPP_OBJ_ATTR_PASSINDEX:
+ min = 0;
+ max = 1000;
+ size = 'H'; /* in case max is later made > 32767 */
+ param = (void *)&object->index;
+ break;
+ case EXPP_OBJ_ATTR_ACT_MATERIAL:
+ min = 1;
+ max = object->totcol;
+ size = 'b'; /* in case max is later made > 128 */
+ param = (void *)&object->actcol;
+ break;
+ case EXPP_OBJ_ATTR_ACT_SHAPE:
+ {
+ Key *key= ob_get_key(object);
+ KeyBlock *kb;
+ min = 1;
+ max = 0;
+ if (key) {
+ max= 1;
+ for (kb = key->block.first; kb; kb=kb->next, max++);
+ }
+ size = 'h'; /* in case max is later made > 128 */
+ param = (void *)&object->shapenr;
+ break;
+ }
+ default:
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "undefined type in setIntAttrClamp");
+ }
+
+ self->object->recalc |= OB_RECALC_OB;
+ return EXPP_setIValueClamped( value, param, min, max, size );
+}
+
+/*
+ * set integer attributes which require range checking
+ */
+
+static int setIntAttrRange( BPy_Object *self, PyObject *value, void *type )
+{
+ void *param;
+ struct Object *object = self->object;
+ int min, max, size;
+
+ if( !PyInt_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected integer argument" );
+
+ /* these parameters require clamping */
+
+ switch( (int)type ) {
+ case EXPP_OBJ_ATTR_COLBITS:
+ min = 0;
+ max = 0xffff;
+ size = 'H';
+ param = (void *)&object->colbits;
+ break;
+ default:
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "undefined type in setIntAttrRange" );
+ }
+
+ self->object->recalc |= OB_RECALC_OB;
+ return EXPP_setIValueRange( value, param, min, max, size );
+}
+
+/*
+ * get floating point attributes
+ */
+
+static PyObject *getFloatAttr( BPy_Object *self, void *type )
+{
+ float param;
+ struct Object *object = self->object;
+
+ if( (int)type >= EXPP_OBJ_ATTR_PI_SURFACEDAMP &&
+ (int)type <= EXPP_OBJ_ATTR_PI_SBOFACETHICK ) {
+ if( !self->object->pd && !setupPI(self->object) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "particle deflection could not be accessed" );
+ }
+ else if( (int)type >= EXPP_OBJ_ATTR_SB_NODEMASS &&
+ (int)type <= EXPP_OBJ_ATTR_SB_INFRICT ) {
+ if( !self->object->soft && !setupSB(self->object) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "softbody could not be accessed" );
+ }
+
+ switch( (int)type ) {
+ case EXPP_OBJ_ATTR_LOC_X:
+ param = object->loc[0];
+ break;
+ case EXPP_OBJ_ATTR_LOC_Y:
+ param = object->loc[1];
+ break;
+ case EXPP_OBJ_ATTR_LOC_Z:
+ param = object->loc[2];
+ break;
+ case EXPP_OBJ_ATTR_DLOC_X:
+ param = object->dloc[0];
+ break;
+ case EXPP_OBJ_ATTR_DLOC_Y:
+ param = object->dloc[1];
+ break;
+ case EXPP_OBJ_ATTR_DLOC_Z:
+ param = object->dloc[2];
+ break;
+ case EXPP_OBJ_ATTR_ROT_X:
+ param = object->rot[0];
+ break;
+ case EXPP_OBJ_ATTR_ROT_Y:
+ param = object->rot[1];
+ break;
+ case EXPP_OBJ_ATTR_ROT_Z:
+ param = object->rot[2];
+ break;
+ case EXPP_OBJ_ATTR_DROT_X:
+ param = object->drot[0];
+ break;
+ case EXPP_OBJ_ATTR_DROT_Y:
+ param = object->drot[1];
+ break;
+ case EXPP_OBJ_ATTR_DROT_Z:
+ param = object->drot[2];
+ break;
+ case EXPP_OBJ_ATTR_SIZE_X:
+ param = object->size[0];
+ break;
+ case EXPP_OBJ_ATTR_SIZE_Y:
+ param = object->size[1];
+ break;
+ case EXPP_OBJ_ATTR_SIZE_Z:
+ param = object->size[2];
+ break;
+ case EXPP_OBJ_ATTR_DSIZE_X:
+ param = object->dsize[0];
+ break;
+ case EXPP_OBJ_ATTR_DSIZE_Y:
+ param = object->dsize[1];
+ break;
+ case EXPP_OBJ_ATTR_DSIZE_Z:
+ param = object->dsize[2];
+ break;
+ case EXPP_OBJ_ATTR_TIMEOFFSET:
+ param = object->sf;
+ break;
+ case EXPP_OBJ_ATTR_DRAWSIZE:
+ param = object->empty_drawsize;
+ break;
+ case EXPP_OBJ_ATTR_PI_SURFACEDAMP:
+ param = object->pd->pdef_perm;
+ break;
+ case EXPP_OBJ_ATTR_PI_RANDOMDAMP:
+ param = object->pd->pdef_rdamp;
+ break;
+ case EXPP_OBJ_ATTR_PI_PERM:
+ param = object->pd->pdef_perm;
+ break;
+ case EXPP_OBJ_ATTR_PI_STRENGTH:
+ param = object->pd->f_strength;
+ break;
+ case EXPP_OBJ_ATTR_PI_FALLOFF:
+ param = object->pd->f_power;
+ break;
+ case EXPP_OBJ_ATTR_PI_MAXDIST:
+ param = object->pd->maxdist;
+ break;
+ case EXPP_OBJ_ATTR_PI_SBDAMP:
+ param = object->pd->pdef_sbdamp;
+ break;
+ case EXPP_OBJ_ATTR_PI_SBIFACETHICK:
+ param = object->pd->pdef_sbift;
+ break;
+ case EXPP_OBJ_ATTR_PI_SBOFACETHICK:
+ param = object->pd->pdef_sboft;
+ break;
+ case EXPP_OBJ_ATTR_SB_NODEMASS:
+ param = self->object->soft->nodemass;
+ break;
+ case EXPP_OBJ_ATTR_SB_GRAV:
+ param = self->object->soft->grav;
+ break;
+ case EXPP_OBJ_ATTR_SB_MEDIAFRICT:
+ param = self->object->soft->mediafrict;
+ break;
+ case EXPP_OBJ_ATTR_SB_RKLIMIT:
+ param = object->soft->rklimit;
+ break;
+ case EXPP_OBJ_ATTR_SB_PHYSICSSPEED:
+ param = object->soft->physics_speed;
+ break;
+ case EXPP_OBJ_ATTR_SB_GOALSPRING:
+ param = object->soft->goalspring;
+ break;
+ case EXPP_OBJ_ATTR_SB_GOALFRICT:
+ param = object->soft->goalfrict;
+ break;
+ case EXPP_OBJ_ATTR_SB_MINGOAL:
+ param = object->soft->mingoal;
+ break;
+ case EXPP_OBJ_ATTR_SB_MAXGOAL:
+ param = object->soft->maxgoal;
+ break;
+ case EXPP_OBJ_ATTR_SB_DEFGOAL:
+ param = object->soft->defgoal;
+ break;
+ case EXPP_OBJ_ATTR_SB_INSPRING:
+ param = object->soft->inspring;
+ break;
+ case EXPP_OBJ_ATTR_SB_INFRICT:
+ param = object->soft->infrict;
+ break;
+ default:
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "undefined type in getFloatAttr" );
+ }
+
+ return PyFloat_FromDouble( param );
+}
+
+/*
+ * set floating point attributes which require clamping
+ */
+
+static int setFloatAttrClamp( BPy_Object *self, PyObject *value, void *type )
+{
+ float *param;
+ struct Object *object = self->object;
+ float min, max;
+
+ if( (int)type >= EXPP_OBJ_ATTR_PI_SURFACEDAMP &&
+ (int)type <= EXPP_OBJ_ATTR_PI_SBOFACETHICK ) {
+ if( !self->object->pd && !setupPI(self->object) )
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "particle deflection could not be accessed" );
+ }
+ else if( (int)type >= EXPP_OBJ_ATTR_SB_NODEMASS &&
+ (int)type <= EXPP_OBJ_ATTR_SB_INFRICT ) {
+ if( !self->object->soft && !setupSB(self->object) )
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "softbody could not be accessed" );
+ }
+
+ switch( (int)type ) {
+ case EXPP_OBJ_ATTR_DRAWSIZE:
+ min = EXPP_OBJECT_DRAWSIZEMIN;
+ max = EXPP_OBJECT_DRAWSIZEMAX;
+ param = &object->empty_drawsize;
+ break;
+ case EXPP_OBJ_ATTR_TIMEOFFSET:
+ min = -MAXFRAMEF;
+ max = MAXFRAMEF;
+ param = &object->sf;
+ break;
+ case EXPP_OBJ_ATTR_PI_SURFACEDAMP:
+ min = EXPP_OBJECT_PIDAMP_MIN;
+ max = EXPP_OBJECT_PIDAMP_MAX;
+ param = &object->pd->pdef_perm;
+ break;
+ case EXPP_OBJ_ATTR_PI_RANDOMDAMP:
+ min = EXPP_OBJECT_PIRDAMP_MIN;
+ max = EXPP_OBJECT_PIRDAMP_MAX;
+ param = &object->pd->pdef_rdamp;
+ break;
+ case EXPP_OBJ_ATTR_PI_PERM:
+ min = EXPP_OBJECT_PIPERM_MIN;
+ max = EXPP_OBJECT_PIPERM_MAX;
+ param = &object->pd->pdef_perm;
+ break;
+ case EXPP_OBJ_ATTR_PI_STRENGTH:
+ min = EXPP_OBJECT_PISTRENGTH_MIN;
+ max = EXPP_OBJECT_PISTRENGTH_MAX;
+ param = &object->pd->f_strength;
+ break;
+ case EXPP_OBJ_ATTR_PI_FALLOFF:
+ min = EXPP_OBJECT_PIPOWER_MIN;
+ max = EXPP_OBJECT_PIPOWER_MAX;
+ param = &object->pd->f_power;
+ break;
+ case EXPP_OBJ_ATTR_PI_MAXDIST:
+ min = EXPP_OBJECT_PIMAXDIST_MIN;
+ max = EXPP_OBJECT_PIMAXDIST_MAX;
+ param = &object->pd->maxdist;
+ break;
+ case EXPP_OBJ_ATTR_PI_SBDAMP:
+ min = EXPP_OBJECT_PISBDAMP_MIN;
+ max = EXPP_OBJECT_PISBDAMP_MAX;
+ param = &object->pd->pdef_sbdamp;
+ break;
+ case EXPP_OBJ_ATTR_PI_SBIFACETHICK:
+ min = EXPP_OBJECT_PISBIFTMIN;
+ max = EXPP_OBJECT_PISBIFTMAX;
+ param = &object->pd->pdef_sbift;
+ break;
+ case EXPP_OBJ_ATTR_PI_SBOFACETHICK:
+ min = EXPP_OBJECT_PISBOFTMIN;
+ max = EXPP_OBJECT_PISBOFTMAX;
+ param = &object->pd->pdef_sboft;
+ break;
+ case EXPP_OBJ_ATTR_SB_NODEMASS:
+ min = EXPP_OBJECT_SBNODEMASSMIN;
+ max = EXPP_OBJECT_SBNODEMASSMAX;
+ param = &self->object->soft->nodemass;
+ break;
+ case EXPP_OBJ_ATTR_SB_GRAV:
+ min = EXPP_OBJECT_SBGRAVMIN;
+ max = EXPP_OBJECT_SBGRAVMAX;
+ param = &self->object->soft->grav;
+ break;
+ case EXPP_OBJ_ATTR_SB_MEDIAFRICT:
+ min = EXPP_OBJECT_SBMEDIAFRICTMIN;
+ max = EXPP_OBJECT_SBMEDIAFRICTMAX;
+ param = &self->object->soft->mediafrict;
+ break;
+ case EXPP_OBJ_ATTR_SB_RKLIMIT:
+ min = EXPP_OBJECT_SBRKLIMITMIN;
+ max = EXPP_OBJECT_SBRKLIMITMAX;
+ param = &self->object->soft->rklimit;
+ break;
+ case EXPP_OBJ_ATTR_SB_PHYSICSSPEED:
+ min = EXPP_OBJECT_SBPHYSICSSPEEDMIN;
+ max = EXPP_OBJECT_SBPHYSICSSPEEDMAX;
+ param = &self->object->soft->physics_speed;
+ break;
+ case EXPP_OBJ_ATTR_SB_GOALSPRING:
+ min = EXPP_OBJECT_SBGOALSPRINGMIN;
+ max = EXPP_OBJECT_SBGOALSPRINGMAX;
+ param = &self->object->soft->goalspring;
+ break;
+ case EXPP_OBJ_ATTR_SB_GOALFRICT:
+ min = EXPP_OBJECT_SBGOALFRICTMIN;
+ max = EXPP_OBJECT_SBGOALFRICTMAX;
+ param = &self->object->soft->goalfrict;
+ break;
+ case EXPP_OBJ_ATTR_SB_MINGOAL:
+ min = EXPP_OBJECT_SBMINGOALMIN;
+ max = EXPP_OBJECT_SBMINGOALMAX;
+ param = &self->object->soft->mingoal;
+ break;
+ case EXPP_OBJ_ATTR_SB_MAXGOAL:
+ min = EXPP_OBJECT_SBMAXGOALMIN;
+ max = EXPP_OBJECT_SBMAXGOALMAX;
+ param = &self->object->soft->maxgoal;
+ break;
+ case EXPP_OBJ_ATTR_SB_DEFGOAL:
+ min = EXPP_OBJECT_SBDEFGOALMIN;
+ max = EXPP_OBJECT_SBDEFGOALMAX;
+ param = &self->object->soft->defgoal;
+ break;
+ case EXPP_OBJ_ATTR_SB_INSPRING:
+ min = EXPP_OBJECT_SBINSPRINGMIN;
+ max = EXPP_OBJECT_SBINSPRINGMAX;
+ param = &self->object->soft->inspring;
+ break;
+ case EXPP_OBJ_ATTR_SB_INFRICT:
+ min = EXPP_OBJECT_SBINFRICTMIN;
+ max = EXPP_OBJECT_SBINFRICTMAX;
+ param = &self->object->soft->infrict;
+ break;
+ default:
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "undefined type in setFloatAttrClamp" );
+ }
+
+ self->object->recalc |= OB_RECALC_OB;
+ return EXPP_setFloatClamped( value, param, min, max );
+}
+
+/*
+ * set floating point attributes
+ */
+
+static int setFloatAttr( BPy_Object *self, PyObject *value, void *type )
+{
+ float param;
+ struct Object *object = self->object;
+
+ if( !PyNumber_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected float argument" );
+
+ param = (float)PyFloat_AsDouble( value );
+
+ switch( (int)type ) {
+ case EXPP_OBJ_ATTR_LOC_X:
+ object->loc[0] = param;
+ break;
+ case EXPP_OBJ_ATTR_LOC_Y:
+ object->loc[1] = param;
+ break;
+ case EXPP_OBJ_ATTR_LOC_Z:
+ object->loc[2] = param;
+ break;
+ case EXPP_OBJ_ATTR_DLOC_X:
+ object->dloc[0] = param;
+ break;
+ case EXPP_OBJ_ATTR_DLOC_Y:
+ object->dloc[1] = param;
+ break;
+ case EXPP_OBJ_ATTR_DLOC_Z:
+ object->dloc[2] = param;
+ break;
+ case EXPP_OBJ_ATTR_ROT_X:
+ object->rot[0] = param;
+ break;
+ case EXPP_OBJ_ATTR_ROT_Y:
+ object->rot[1] = param;
+ break;
+ case EXPP_OBJ_ATTR_ROT_Z:
+ object->rot[2] = param;
+ break;
+ case EXPP_OBJ_ATTR_DROT_X:
+ object->drot[0] = param;
+ break;
+ case EXPP_OBJ_ATTR_DROT_Y:
+ object->drot[1] = param;
+ break;
+ case EXPP_OBJ_ATTR_DROT_Z:
+ object->drot[2] = param;
+ break;
+ case EXPP_OBJ_ATTR_SIZE_X:
+ object->size[0] = param;
+ break;
+ case EXPP_OBJ_ATTR_SIZE_Y:
+ object->size[1] = param;
+ break;
+ case EXPP_OBJ_ATTR_SIZE_Z:
+ object->size[2] = param;
+ break;
+ case EXPP_OBJ_ATTR_DSIZE_X:
+ object->dsize[0] = param;
+ break;
+ case EXPP_OBJ_ATTR_DSIZE_Y:
+ object->dsize[1] = param;
+ break;
+ case EXPP_OBJ_ATTR_DSIZE_Z:
+ object->dsize[2] = param;
+ break;
+ default:
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "undefined type in setFloatAttr " );
+ }
+ self->object->recalc |= OB_RECALC_OB;
+ return 0;
+}
+
+/*
+ * get 3-tuple floating point attributes
+ */
+
+static PyObject *getFloat3Attr( BPy_Object *self, void *type )
+{
+ float *param;
+ struct Object *object = self->object;
+
+ switch( (int)type ) {
+ case EXPP_OBJ_ATTR_LOC:
+ param = object->loc;
+ break;
+ case EXPP_OBJ_ATTR_DLOC:
+ param = object->dloc;
+ break;
+ case EXPP_OBJ_ATTR_DROT:
+ param = object->drot;
+ break;
+ case EXPP_OBJ_ATTR_SIZE:
+ param = object->size;
+ break;
+ case EXPP_OBJ_ATTR_DSIZE:
+ param = object->dsize;
+ break;
+ default:
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "undefined type in getFloat3Attr" );
+ }
+
+ return Py_BuildValue( "(fff)", param[0], param[1], param[2] );
+}
+
+/*
+ * set 3-tuple floating point attributes
+ */
+
+static int setFloat3Attr( BPy_Object *self, PyObject *value, void *type )
+{
+ int i;
+ float *dst, param[3];
+ struct Object *object = self->object;
+
+ value = PySequence_Tuple( value );
+
+ if( !value || !PyArg_ParseTuple( value, "fff", &param[0], &param[1], &param[2] ) ) {
+ Py_XDECREF( value );
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a list or tuple of 3 floats" );
+ }
+
+ Py_DECREF( value );
+ switch( (int)type ) {
+ case EXPP_OBJ_ATTR_LOC:
+ dst = object->loc;
+ break;
+ case EXPP_OBJ_ATTR_DLOC:
+ dst = object->dloc;
+ break;
+ case EXPP_OBJ_ATTR_DROT:
+ dst = object->drot;
+ break;
+ case EXPP_OBJ_ATTR_SIZE:
+ dst = object->size;
+ break;
+ case EXPP_OBJ_ATTR_DSIZE:
+ dst = object->dsize;
+ break;
+ default:
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "undefined type in setFloat3Attr" );
+ }
+
+ for( i = 0; i < 3; ++i )
+ dst[i] = param[i];
+
+ self->object->recalc |= OB_RECALC_OB;
+ return 0;
+}
+
+/*****************************************************************************/
+/* BPy_Object methods and attribute handlers */
+/*****************************************************************************/
+
+static PyObject *Object_getShapeFlag( BPy_Object *self, void *type )
+{
+ if (self->object->shapeflag & (int)type)
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+}
+
+static int Object_setShapeFlag( BPy_Object *self, PyObject *value,
+ void *type )
+{
+ if (PyObject_IsTrue(value) )
+ self->object->shapeflag |= (int)type;
+ else
+ self->object->shapeflag &= ~(int)type;
+
+ self->object->recalc |= OB_RECALC_OB;
+ return 0;
+}
+
+static PyObject *Object_getRestricted( BPy_Object *self, void *type )
+{
+ if (self->object->restrictflag & (int)type)
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+}
+
+static int Object_setRestricted( BPy_Object *self, PyObject *value,
+ void *type )
+{
+ int param = PyObject_IsTrue( value );
+ if( param == -1 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected True/False or 0/1" );
+
+ if ( param )
+ self->object->restrictflag |= (int)type;
+ else
+ self->object->restrictflag &= ~(int)type;
+
+ return 0;
+}
+
+static PyObject *Object_getDrawModeBits( BPy_Object *self, void *type )
+{
+ return EXPP_getBitfield( (void *)&self->object->dtx, (int)type, 'b' );
+}
+
+static int Object_setDrawModeBits( BPy_Object *self, PyObject *value,
+ void *type )
+{
+ self->object->recalc |= OB_RECALC_OB;
+ return EXPP_setBitfield( value, (void *)&self->object->dtx,
+ (int)type, 'b' );
+}
+
+static PyObject *Object_getTransflagBits( BPy_Object *self, void *type )
+{
+ return EXPP_getBitfield( (void *)&self->object->transflag,
+ (int)type, 'h' );
+}
+
+static int Object_setTransflagBits( BPy_Object *self, PyObject *value,
+ void *type )
+{
+ self->object->recalc |= OB_RECALC_OB;
+ return EXPP_setBitfield( value, (void *)&self->object->transflag,
+ (int)type, 'h' );
+}
+
+static PyObject *Object_getLayers( BPy_Object * self )
+{
+ int layers, bit;
+ PyObject *laylist = PyList_New( 0 );
+
+ if( !laylist )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "PyList_New() failed" );
+
+ layers = self->object->lay & 0xfffff; /* get layer bitmask */
+
+ /*
+ * starting with the first layer, and until there are no more layers,
+ * find which layers are visible
+ */
+
+ for( bit = 1; layers; ++bit ) {
+ if( layers & 1 ) { /* if layer is visible, add to list */
+ PyObject *item = PyInt_FromLong( bit );
+ PyList_Append( laylist, item );
+ Py_DECREF( item );
+ }
+ layers >>= 1; /* go to the next layer */
+ }
+ return laylist;
+}
+
+/*
+ * usage note: caller of this func needs to do a Blender.Redraw(-1)
+ * to update and redraw the interface
+ */
+
+static int Object_setLayers( BPy_Object * self, PyObject *value )
+{
+ int layers = 0, val, i, len_list, local;
+ Base *base;
+
+ if( !PyList_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a list of integers in the range [1, 20]" );
+
+ len_list = PyList_Size( value );
+
+ /* build a bitmask, check for values outside of range */
+
+ for( i = 0; i < len_list; i++ ) {
+ PyObject* integer = PyNumber_Int( PyList_GetItem( value, i ) );
+ val = PyInt_AsLong( integer );
+ Py_XDECREF( integer );
+ if( !integer )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "list must contain only integer numbers" );
+ if( val < 1 || val > 20 )
+ return EXPP_ReturnIntError ( PyExc_ValueError,
+ "layer values must be in the range [1, 20]" );
+ layers |= 1 << ( val - 1 );
+ }
+
+ /* do this, to ensure layers are set for objects not in current scene */
+ self->object->lay= layers;
+
+ /* update any bases pointing to our object */
+ base = FIRSTBASE; /* first base in current scene */
+ while( base ) {
+ if( base->object == self->object ) {
+ base->lay &= 0xFFF00000;
+ local = base->lay;
+ base->lay = local | layers;
+ self->object->lay = base->lay;
+ break;
+ }
+ base = base->next;
+ }
+
+ /* these to calls here are overkill! (ton) */
+ if (base) { /* The object was found? */
+ countall();
+ DAG_scene_sort( G.scene );
+ }
+ return 0;
+}
+
+static int Object_setLayersMask( BPy_Object *self, PyObject *value )
+{
+ int layers = 0, local;
+ Base *base;
+
+ if( !PyInt_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected an integer (bitmask) as argument" );
+
+ layers = PyInt_AS_LONG( value );
+
+ /* make sure some bits are set, and only those bits are set */
+
+ if( !( layers & 0xFFFFF ) || ( layers & 0xFFF00000 ) )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "bitmask must have between 1 and 20 bits set" );
+
+ /* update any bases pointing to our object */
+
+ base = FIRSTBASE; /* first base in current scene */
+ while( base ) {
+ if( base->object == self->object ) {
+ base->lay &= 0xFFF00000;
+ local = base->lay;
+ base->lay = local | layers;
+ self->object->lay = base->lay;
+ break;
+ }
+ base = base->next;
+ }
+ if (base) { /* The object was found? */
+ countall();
+ DAG_scene_sort( G.scene );
+ }
+ return 0;
+}
+
+/*
+ * this should accept a Py_None argument and just delete the Ipo link
+ * (as Object_clearIpo() does)
+ */
+
+static int Object_setIpo( BPy_Object * self, PyObject * value )
+{
+ return GenericLib_assignData(value, (void **) &self->object->ipo, 0, 1, ID_IP, ID_OB);
+}
+
+static int Object_setTracked( BPy_Object * self, PyObject * value )
+{
+ int ret;
+ ret = GenericLib_assignData(value, (void **) &self->object->track, 0, 0, ID_OB, 0);
+ if (ret==0) {
+ self->object->recalc |= OB_RECALC_OB;
+ DAG_scene_sort( G.scene );
+ }
+ return ret;
+}
+
+/* Localspace matrix */
+
+static PyObject *Object_getMatrixLocal( BPy_Object * self )
+{
+ if( self->object->parent ) {
+ float matrix[4][4]; /* for the result */
+ float invmat[4][4]; /* for inverse of parent's matrix */
+
+ Mat4Invert(invmat, self->object->parent->obmat );
+ Mat4MulMat4(matrix, self->object->obmat, invmat);
+ return newMatrixObject((float*)matrix,4,4,Py_NEW);
+ } else { /* no parent, so return world space matrix */
+ disable_where_script( 1 );
+ where_is_object( self->object );
+ disable_where_script( 0 );
+ return newMatrixObject((float*)self->object->obmat,4,4,Py_WRAP);
+ }
+}
+
+/* Worldspace matrix */
+
+static PyObject *Object_getMatrixWorld( BPy_Object * self )
+{
+ disable_where_script( 1 );
+ where_is_object( self->object );
+ disable_where_script( 0 );
+ return newMatrixObject((float*)self->object->obmat,4,4,Py_WRAP);
+}
+
+/* Parent Inverse matrix */
+
+static PyObject *Object_getMatrixParentInverse( BPy_Object * self )
+{
+ return newMatrixObject((float*)self->object->parentinv,4,4,Py_WRAP);
+}
+
+/*
+ * Old behavior, prior to Blender 2.34, where eventual changes made by the
+ * script itself were not taken into account until a redraw happened, either
+ * called by the script or upon its exit.
+ */
+
+static PyObject *Object_getMatrixOldWorld( BPy_Object * self )
+{
+ return newMatrixObject((float*)self->object->obmat,4,4,Py_WRAP);
+}
+
+/*
+ * get one of three different matrix representations
+ */
+
+static PyObject *Object_getMatrix( BPy_Object * self, PyObject * args )
+{
+ char *space = "worldspace"; /* default to world */
+ char *errstr = "expected nothing, 'worldspace' (default), 'localspace' or 'old_worldspace'";
+
+ if( !PyArg_ParseTuple( args, "|s", &space ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError, errstr );
+
+ if( BLI_streq( space, "worldspace" ) )
+ return Object_getMatrixWorld( self );
+ else if( BLI_streq( space, "localspace" ) )
+ return Object_getMatrixLocal( self );
+ else if( BLI_streq( space, "old_worldspace" ) )
+ return Object_getMatrixOldWorld( self );
+ else
+ return EXPP_ReturnPyObjError( PyExc_ValueError, errstr );
+}
+
+static PyObject *get_obj_data( BPy_Object *self, int mesh )
+{
+ Object *object = self->object;
+ PyObject *data_object = NULL;
+
+ switch ( object->type ) {
+ case OB_ARMATURE:
+ data_object = Armature_CreatePyObject( object->data );
+ break;
+ case OB_CAMERA:
+ data_object = Camera_CreatePyObject( object->data );
+ break;
+ case OB_CURVE:
+ case OB_SURF:
+ data_object = Curve_CreatePyObject( object->data );
+ break;
+ case ID_IM:
+ data_object = Image_CreatePyObject( object->data );
+ break;
+ case ID_IP:
+ data_object = Ipo_CreatePyObject( object->data );
+ break;
+ case OB_LAMP:
+ data_object = Lamp_CreatePyObject( object->data );
+ break;
+ case OB_LATTICE:
+ data_object = Lattice_CreatePyObject( object->data );
+ break;
+ case ID_MA:
+ break;
+ case OB_MESH:
+ if( !mesh ) /* get as NMesh (default) */
+ data_object = NMesh_CreatePyObject( object->data, object );
+ else /* else get as Mesh */
+ data_object = Mesh_CreatePyObject( object->data, object );
+ break;
+ case OB_MBALL:
+ data_object = Metaball_CreatePyObject( object->data );
+ break;
+ case ID_OB:
+ data_object = Object_CreatePyObject( object->data );
+ break;
+ case ID_SCE:
+ break;
+ case OB_FONT:
+ data_object = Text3d_CreatePyObject( object->data );
+ break;
+ case ID_WO:
+ break;
+ default:
+ break;
+ }
+
+ if( data_object )
+ return data_object;
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Object_getData( BPy_Object *self, PyObject *args,
+ PyObject *kwd )
+{
+ Object *object = self->object;
+ int name_only = 0;
+ int mesh = 0; /* default mesh type = NMesh */
+ static char *kwlist[] = {"name_only", "mesh", NULL};
+
+ if( !PyArg_ParseTupleAndKeywords(args, kwd, "|ii", kwlist,
+ &name_only, &mesh) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected nothing or bool keywords 'name_only' or 'mesh' as argument" );
+
+ /* if there's no obdata, try to create it */
+ if( object->data == NULL ) {
+ int tmptype = object->type; /* save current type */
+
+ /* if we have no data and are faking an empty, set the type */
+ if( self->realtype != OB_EMPTY )
+ object->type = self->realtype;
+
+ if( EXPP_add_obdata( object ) != 0 ) { /* couldn't create obdata */
+ object->type = tmptype; /* restore previous type */
+ Py_RETURN_NONE;
+ }
+
+ /* if we set data successfully, clear the fake type */
+ self->realtype = OB_EMPTY;
+ }
+
+ /* user wants only the name of the data object */
+ if( name_only ) {
+ ID *id = object->data;
+ return PyString_FromString( id->name+2 );
+ }
+
+ return get_obj_data( self, mesh );
+}
+
+static PyObject *Object_getEuler( BPy_Object * self )
+{
+ return ( PyObject * ) newEulerObject( self->object->rot, Py_WRAP );
+}
+
+#define PROTFLAGS_MASK ( OB_LOCK_LOCX | OB_LOCK_LOCY | OB_LOCK_LOCZ | \
+ OB_LOCK_ROTX | OB_LOCK_ROTY | OB_LOCK_ROTZ | \
+ OB_LOCK_SCALEX | OB_LOCK_SCALEY | OB_LOCK_SCALEZ )
+
+static PyObject *Object_getProtectFlags( BPy_Object * self )
+{
+ return PyInt_FromLong( (long)(self->object->protectflag & PROTFLAGS_MASK) );
+}
+
+static int Object_setProtectFlags( BPy_Object * self, PyObject * args )
+{
+ PyObject* integer = PyNumber_Int( args );
+ short value;
+
+ if( !integer )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected integer argument" );
+
+ value = ( short )PyInt_AS_LONG( integer );
+ Py_DECREF( integer );
+ if( value & ~PROTFLAGS_MASK )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "undefined bit(s) set in bitfield" );
+
+ self->object->protectflag = value;
+ self->object->recalc |= OB_RECALC_OB;
+ return 0;
+}
+
+static PyObject *Object_getRBRadius( BPy_Object * self )
+{
+ return PyFloat_FromDouble( (double) self->object->inertia );
+}
+
+static int Object_setRBRadius( BPy_Object * self, PyObject * args )
+{
+ float value;
+ PyObject* flt = PyNumber_Float( args );
+
+ if( !flt )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected float argument" );
+ value = (float)PyFloat_AS_DOUBLE( flt );
+ Py_DECREF( flt );
+
+ if( value < 0.0f )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "acceptable values are non-negative, 0.0 or more" );
+
+ self->object->inertia = value;
+ self->object->recalc |= OB_RECALC_OB;
+
+ return 0;
+}
+
+static PyObject *Object_getRBHalfExtents( BPy_Object * self )
+{
+ float center[3], extents[3];
+
+ get_local_bounds( self->object, center, extents );
+ return Py_BuildValue( "[fff]", extents[0], extents[1], extents[2] );
+}
+
+static PyGetSetDef BPy_Object_getseters[] = {
+ GENERIC_LIB_GETSETATTR,
+ {"LocX",
+ (getter)getFloatAttr, (setter)setFloatAttr,
+ "The X location coordinate of the object",
+ (void *)EXPP_OBJ_ATTR_LOC_X},
+ {"LocY",
+ (getter)getFloatAttr, (setter)setFloatAttr,
+ "The Y location coordinate of the object",
+ (void *)EXPP_OBJ_ATTR_LOC_Y},
+ {"LocZ",
+ (getter)getFloatAttr, (setter)setFloatAttr,
+ "The Z location coordinate of the object",
+ (void *)EXPP_OBJ_ATTR_LOC_Z},
+ {"dLocX",
+ (getter)getFloatAttr, (setter)setFloatAttr,
+ "The delta X location coordinate of the object",
+ (void *)EXPP_OBJ_ATTR_DLOC_X},
+ {"dLocY",
+ (getter)getFloatAttr, (setter)setFloatAttr,
+ "The delta Y location coordinate of the object",
+ (void *)EXPP_OBJ_ATTR_DLOC_Y},
+ {"dLocZ",
+ (getter)getFloatAttr, (setter)setFloatAttr,
+ "The delta Z location coordinate of the object",
+ (void *)EXPP_OBJ_ATTR_DLOC_Z},
+ {"RotX",
+ (getter)getFloatAttr, (setter)setFloatAttr,
+ "The X rotation angle (in radians) of the object",
+ (void *)EXPP_OBJ_ATTR_ROT_X},
+ {"RotY",
+ (getter)getFloatAttr, (setter)setFloatAttr,
+ "The Y rotation angle (in radians) of the object",
+ (void *)EXPP_OBJ_ATTR_ROT_Y},
+ {"RotZ",
+ (getter)getFloatAttr, (setter)setFloatAttr,
+ "The Z rotation angle (in radians) of the object",
+ (void *)EXPP_OBJ_ATTR_ROT_Z},
+ {"dRotX",
+ (getter)getFloatAttr, (setter)setFloatAttr,
+ "The delta X rotation angle (in radians) of the object",
+ (void *)EXPP_OBJ_ATTR_DROT_X},
+ {"dRotY",
+ (getter)getFloatAttr, (setter)setFloatAttr,
+ "The delta Y rotation angle (in radians) of the object",
+ (void *)EXPP_OBJ_ATTR_DROT_Y},
+ {"dRotZ",
+ (getter)getFloatAttr, (setter)setFloatAttr,
+ "The delta Z rotation angle (in radians) of the object",
+ (void *)EXPP_OBJ_ATTR_DROT_Z},
+ {"SizeX",
+ (getter)getFloatAttr, (setter)setFloatAttr,
+ "The X size of the object",
+ (void *)EXPP_OBJ_ATTR_SIZE_X},
+ {"SizeY",
+ (getter)getFloatAttr, (setter)setFloatAttr,
+ "The Y size of the object",
+ (void *)EXPP_OBJ_ATTR_SIZE_Y},
+ {"SizeZ",
+ (getter)getFloatAttr, (setter)setFloatAttr,
+ "The Z size of the object",
+ (void *)EXPP_OBJ_ATTR_SIZE_Z},
+ {"dSizeX",
+ (getter)getFloatAttr, (setter)setFloatAttr,
+ "The delta X size of the object",
+ (void *)EXPP_OBJ_ATTR_DSIZE_X},
+ {"dSizeY",
+ (getter)getFloatAttr, (setter)setFloatAttr,
+ "The delta Y size of the object",
+ (void *)EXPP_OBJ_ATTR_DSIZE_Y},
+ {"dSizeZ",
+ (getter)getFloatAttr, (setter)setFloatAttr,
+ "The delta Z size of the object",
+ (void *)EXPP_OBJ_ATTR_DSIZE_Z},
+
+ {"loc",
+ (getter)getFloat3Attr, (setter)setFloat3Attr,
+ "The (X,Y,Z) location coordinates of the object",
+ (void *)EXPP_OBJ_ATTR_LOC},
+ {"dloc",
+ (getter)getFloat3Attr, (setter)setFloat3Attr,
+ "The delta (X,Y,Z) location coordinates of the object",
+ (void *)EXPP_OBJ_ATTR_DLOC},
+ {"rot",
+ (getter)Object_getEuler, (setter)Object_setEuler,
+ "The (X,Y,Z) rotation angles (in degrees) of the object",
+ NULL},
+ {"drot",
+ (getter)getFloat3Attr, (setter)setFloat3Attr,
+ "The delta (X,Y,Z) rotation angles (in radians) of the object",
+ (void *)EXPP_OBJ_ATTR_DROT},
+ {"size",
+ (getter)getFloat3Attr, (setter)setFloat3Attr,
+ "The (X,Y,Z) size of the object",
+ (void *)EXPP_OBJ_ATTR_SIZE},
+ {"dsize",
+ (getter)getFloat3Attr, (setter)setFloat3Attr,
+ "The delta (X,Y,Z) size of the object",
+ (void *)EXPP_OBJ_ATTR_DSIZE},
+ {"Layer",
+ (getter)getIntAttr, (setter)Object_setLayersMask,
+ "The object layers (bitfield)",
+ (void *)EXPP_OBJ_ATTR_LAYERMASK},
+ {"Layers",
+ (getter)getIntAttr, (setter)Object_setLayersMask,
+ "The object layers (bitfield)",
+ (void *)EXPP_OBJ_ATTR_LAYERMASK},
+ {"layers",
+ (getter)Object_getLayers, (setter)Object_setLayers,
+ "The object layers (list of ints)",
+ NULL},
+ {"ipo",
+ (getter)Object_getIpo, (setter)Object_setIpo,
+ "Object's Ipo data",
+ NULL},
+ {"colbits",
+ (getter)getIntAttr, (setter)setIntAttrRange,
+ "The Material usage bitfield",
+ (void *)EXPP_OBJ_ATTR_COLBITS},
+ {"drawMode",
+ (getter)getIntAttr, (setter)Object_setDrawMode,
+ "The object's drawing mode bitfield",
+ (void *)EXPP_OBJ_ATTR_DRAWMODE},
+ {"drawType",
+ (getter)getIntAttr, (setter)Object_setDrawType,
+ "The object's drawing type",
+ (void *)EXPP_OBJ_ATTR_DRAWTYPE},
+ {"parentType",
+ (getter)getIntAttr, (setter)NULL,
+ "The object's parent type",
+ (void *)EXPP_OBJ_ATTR_PARENT_TYPE},
+ {"DupOn",
+ (getter)getIntAttr, (setter)setIntAttrClamp,
+ "DupOn setting (for DupliFrames)",
+ (void *)EXPP_OBJ_ATTR_DUPON},
+ {"DupOff",
+ (getter)getIntAttr, (setter)setIntAttrClamp,
+ "DupOff setting (for DupliFrames)",
+ (void *)EXPP_OBJ_ATTR_DUPOFF},
+ {"DupSta",
+ (getter)getIntAttr, (setter)setIntAttrClamp,
+ "Starting frame (for DupliFrames)",
+ (void *)EXPP_OBJ_ATTR_DUPSTA},
+ {"DupEnd",
+ (getter)getIntAttr, (setter)setIntAttrClamp,
+ "Ending frame (for DupliFrames)",
+ (void *)EXPP_OBJ_ATTR_DUPEND},
+ {"passIndex",
+ (getter)getIntAttr, (setter)setIntAttrClamp,
+ "Index for object masks in the compositor",
+ (void *)EXPP_OBJ_ATTR_PASSINDEX},
+ {"activeMaterial",
+ (getter)getIntAttr, (setter)setIntAttrClamp,
+ "Index for the active material (displayed in the material panel)",
+ (void *)EXPP_OBJ_ATTR_ACT_MATERIAL},
+ {"mat",
+ (getter)Object_getMatrixWorld, (setter)NULL,
+ "worldspace matrix: absolute, takes vertex parents, tracking and Ipos into account",
+ NULL},
+ {"matrix",
+ (getter)Object_getMatrixWorld, (setter)NULL,
+ "worldspace matrix: absolute, takes vertex parents, tracking and Ipos into account",
+ NULL},
+ {"matrixWorld",
+ (getter)Object_getMatrixWorld, (setter)NULL,
+ "worldspace matrix: absolute, takes vertex parents, tracking and Ipos into account",
+ NULL},
+ {"matrixLocal",
+ (getter)Object_getMatrixLocal, (setter)Object_setMatrix,
+ "localspace matrix: relative to the object's parent",
+ NULL},
+ {"matrixParentInverse",
+ (getter)Object_getMatrixParentInverse, (setter)NULL,
+ "parents inverse matrix: parents localspace inverted matrix",
+ NULL},
+ {"matrixOldWorld",
+ (getter)Object_getMatrixOldWorld, (setter)NULL,
+ "old-type worldspace matrix (prior to Blender 2.34)",
+ NULL},
+ {"data",
+ (getter)get_obj_data, (setter)NULL,
+ "The Datablock object linked to this object",
+ NULL},
+ {"sel",
+ (getter)Object_getSelected, (setter)Object_setSelect,
+ "The object's selection state",
+ NULL},
+ {"parent",
+ (getter)Object_getParent, (setter)NULL,
+ "The object's parent object (if parented)",
+ NULL},
+ {"parentbonename",
+ (getter)Object_getParentBoneName, (setter)Object_setParentBoneName,
+ "The object's parent object's sub name",
+ NULL},
+ {"track",
+ (getter)Object_getTracked, (setter)Object_setTracked,
+ "The object's tracked object",
+ NULL},
+ {"timeOffset",
+ (getter)getFloatAttr, (setter)setFloatAttrClamp,
+ "The time offset of the object's animation",
+ (void *)EXPP_OBJ_ATTR_TIMEOFFSET},
+ {"type",
+ (getter)Object_getType, (setter)NULL,
+ "The object's type",
+ NULL},
+ {"boundingBox",
+ (getter)Object_getBoundBox, (setter)NULL,
+ "The bounding box of this object",
+ NULL},
+ {"action",
+ (getter)Object_getAction, (setter)Object_setAction,
+ "The action associated with this object (if defined)",
+ NULL},
+ {"game_properties",
+ (getter)Object_getAllProperties, (setter)NULL,
+ "The object's properties",
+ NULL},
+
+ {"piFalloff",
+ (getter)getFloatAttr, (setter)setFloatAttrClamp,
+ "The particle interaction falloff power",
+ (void *)EXPP_OBJ_ATTR_PI_FALLOFF},
+ {"piMaxDist",
+ (getter)getFloatAttr, (setter)setFloatAttrClamp,
+ "Max distance for the particle interaction field to work",
+ (void *)EXPP_OBJ_ATTR_PI_MAXDIST},
+ {"piPermeability",
+ (getter)getFloatAttr, (setter)setFloatAttrClamp,
+ "Probability that a particle will pass through the mesh",
+ (void *)EXPP_OBJ_ATTR_PI_PERM},
+ {"piRandomDamp",
+ (getter)getFloatAttr, (setter)setFloatAttrClamp,
+ "Random variation of particle interaction damping",
+ (void *)EXPP_OBJ_ATTR_PI_RANDOMDAMP},
+ {"piStrength",
+ (getter)getFloatAttr, (setter)setFloatAttrClamp,
+ "Particle interaction force field strength",
+ (void *)EXPP_OBJ_ATTR_PI_STRENGTH},
+ {"piSurfaceDamp",
+ (getter)getFloatAttr, (setter)setFloatAttrClamp,
+ "Amount of damping during particle collision",
+ (void *)EXPP_OBJ_ATTR_PI_SURFACEDAMP},
+ {"piSoftbodyDamp",
+ (getter)getFloatAttr, (setter)setFloatAttrClamp,
+ "Damping factor for softbody deflection",
+ (void *)EXPP_OBJ_ATTR_PI_SBDAMP},
+ {"piSoftbodyIThick",
+ (getter)getFloatAttr, (setter)setFloatAttrClamp,
+ "Inner face thickness for softbody deflection",
+ (void *)EXPP_OBJ_ATTR_PI_SBIFACETHICK},
+ {"piSoftbodyOThick",
+ (getter)getFloatAttr, (setter)setFloatAttrClamp,
+ "Outer face thickness for softbody deflection",
+ (void *)EXPP_OBJ_ATTR_PI_SBOFACETHICK},
+
+ {"piDeflection",
+ (getter)Object_getPIDeflection, (setter)Object_setPIDeflection,
+ "Deflects particles based on collision",
+ NULL},
+ {"piType",
+ (getter)Object_getPIType, (setter)Object_setPIType,
+ "Type of particle interaction (force field, wind, etc)",
+ NULL},
+ {"piUseMaxDist",
+ (getter)Object_getPIUseMaxDist, (setter)Object_setPIUseMaxDist,
+ "Use a maximum distance for the field to work",
+ NULL},
+
+ {"sbMass",
+ (getter)getFloatAttr, (setter)setFloatAttrClamp,
+ "Softbody point mass (heavier is slower)",
+ (void *)EXPP_OBJ_ATTR_SB_NODEMASS},
+ {"sbGrav",
+ (getter)getFloatAttr, (setter)setFloatAttrClamp,
+ "Apply gravitation to softbody point movement",
+ (void *)EXPP_OBJ_ATTR_SB_GRAV},
+ {"sbFriction",
+ (getter)getFloatAttr, (setter)setFloatAttrClamp,
+ "General media friction for softbody point movements",
+ (void *)EXPP_OBJ_ATTR_SB_MEDIAFRICT},
+ {"sbSpeed",
+ (getter)getFloatAttr, (setter)setFloatAttrClamp,
+ "Tweak timing for physics to control softbody frequency and speed",
+ (void *)EXPP_OBJ_ATTR_SB_MEDIAFRICT},
+ {"sbErrorLimit",
+ (getter)getFloatAttr, (setter)setFloatAttrClamp,
+ "Softbody Runge-Kutta ODE solver error limit (low values give more precision)",
+ (void *)EXPP_OBJ_ATTR_SB_RKLIMIT},
+ {"sbGoalSpring",
+ (getter)getFloatAttr, (setter)setFloatAttrClamp,
+ "Softbody goal (vertex target position) spring stiffness",
+ (void *)EXPP_OBJ_ATTR_SB_GOALSPRING},
+ {"sbGoalFriction",
+ (getter)getFloatAttr, (setter)setFloatAttrClamp,
+ "Softbody goal (vertex target position) friction",
+ (void *)EXPP_OBJ_ATTR_SB_GOALFRICT},
+ {"sbMinGoal",
+ (getter)getFloatAttr, (setter)setFloatAttrClamp,
+ "Softbody goal minimum (vertex group weights scaled to match this range)",
+ (void *)EXPP_OBJ_ATTR_SB_MINGOAL},
+ {"sbMaxGoal",
+ (getter)getFloatAttr, (setter)setFloatAttrClamp,
+ "Softbody goal maximum (vertex group weights scaled to match this range)",
+ (void *)EXPP_OBJ_ATTR_SB_MAXGOAL},
+ {"sbDefaultGoal",
+ (getter)getFloatAttr, (setter)setFloatAttrClamp,
+ "Default softbody goal value, when no vertex group used",
+ (void *)EXPP_OBJ_ATTR_SB_DEFGOAL},
+ {"sbInnerSpring",
+ (getter)getFloatAttr, (setter)setFloatAttrClamp,
+ "Softbody edge spring stiffness",
+ (void *)EXPP_OBJ_ATTR_SB_INSPRING},
+ {"sbInnerSpringFrict",
+ (getter)getFloatAttr, (setter)setFloatAttrClamp,
+ "Softbody edge spring friction",
+ (void *)EXPP_OBJ_ATTR_SB_INFRICT},
+ {"isSoftBody",
+ (getter)Object_isSB, (setter)NULL,
+ "True if object is a soft body",
+ NULL},
+ {"sbUseGoal",
+ (getter)Object_getSBUseGoal, (setter)Object_setSBUseGoal,
+ "Softbody forces for vertices to stick to animated position enabled",
+ NULL},
+ {"sbUseEdges",
+ (getter)Object_getSBUseEdges, (setter)Object_setSBUseEdges,
+ "Softbody use edges as springs enabled",
+ NULL},
+ {"sbStiffQuads",
+ (getter)Object_getSBStiffQuads, (setter)Object_setSBStiffQuads,
+ "Softbody adds diagonal springs on 4-gons enabled",
+ NULL},
+
+ {"axis",
+ (getter)Object_getDrawModeBits, (setter)Object_setDrawModeBits,
+ "Display of active object's center and axis enabled",
+ (void *)OB_AXIS},
+ {"texSpace",
+ (getter)Object_getDrawModeBits, (setter)Object_setDrawModeBits,
+ "Display of active object's texture space enabled",
+ (void *)OB_TEXSPACE},
+ {"nameMode",
+ (getter)Object_getDrawModeBits, (setter)Object_setDrawModeBits,
+ "Display of active object's name enabled",
+ (void *)OB_DRAWNAME},
+ {"wireMode",
+ (getter)Object_getDrawModeBits, (setter)Object_setDrawModeBits,
+ "Add the active object's wireframe over solid drawing enabled",
+ (void *)OB_DRAWWIRE},
+ {"xRay",
+ (getter)Object_getDrawModeBits, (setter)Object_setDrawModeBits,
+ "Draw the active object in front of others enabled",
+ (void *)OB_DRAWXRAY},
+ {"transp",
+ (getter)Object_getDrawModeBits, (setter)Object_setDrawModeBits,
+ "Transparent materials for the active object (mesh only) enabled",
+ (void *)OB_DRAWTRANSP},
+
+ {"enableNLAOverride",
+ (getter)Object_getNLAflagBits, (setter)Object_setNLAflagBits,
+ "Toggles Action-NLA based animation",
+ (void *)OB_NLA_OVERRIDE},
+
+ {"enableDupVerts",
+ (getter)Object_getTransflagBits, (setter)Object_setTransflagBits,
+ "Duplicate child objects on all vertices",
+ (void *)OB_DUPLIVERTS},
+ {"enableDupFaces",
+ (getter)Object_getTransflagBits, (setter)Object_setTransflagBits,
+ "Duplicate child objects on all faces",
+ (void *)OB_DUPLIFACES},
+ {"enableDupFacesScale",
+ (getter)Object_getTransflagBits, (setter)Object_setTransflagBits,
+ "Use face scale to scale all dupliFaces",
+ (void *)OB_DUPLIFACES_SCALE},
+ {"enableDupFrames",
+ (getter)Object_getTransflagBits, (setter)Object_setTransflagBits,
+ "Make copy of object for every frame",
+ (void *)OB_DUPLIFRAMES},
+ {"enableDupGroup",
+ (getter)Object_getTransflagBits, (setter)Object_setTransflagBits,
+ "Enable group instancing",
+ (void *)OB_DUPLIGROUP},
+ {"enableDupRot",
+ (getter)Object_getTransflagBits, (setter)Object_setTransflagBits,
+ "Rotate dupli according to vertex normal",
+ (void *)OB_DUPLIROT},
+ {"enableDupNoSpeed",
+ (getter)Object_getTransflagBits, (setter)Object_setTransflagBits,
+ "Set dupliframes to still, regardless of frame",
+ (void *)OB_DUPLINOSPEED},
+ {"DupObjects",
+ (getter)Object_getDupliObjects, (setter)NULL,
+ "Get a list of tuple pairs (object, matrix), for getting dupli objects",
+ NULL},
+ {"DupGroup",
+ (getter)Object_getDupliGroup, (setter)Object_setDupliGroup,
+ "Get a list of tuples for object duplicated by dupliframe",
+ NULL},
+
+ {"effects",
+ (getter)Object_getEffects, (setter)NULL,
+ "The list of particle effects associated with the object",
+ NULL},
+ {"actionStrips",
+ (getter)Object_getActionStrips, (setter)NULL,
+ "The action strips associated with the object",
+ NULL},
+ {"constraints",
+ (getter)Object_getConstraints, (setter)NULL,
+ "The constraints associated with the object",
+ NULL},
+ {"modifiers",
+ (getter)Object_getModifiers, (setter)Object_setModifiers,
+ "The modifiers associated with the object",
+ NULL},
+ {"protectFlags",
+ (getter)Object_getProtectFlags, (setter)Object_setProtectFlags,
+ "The \"transform locking\" bitfield for the object",
+ NULL},
+ {"drawSize",
+ (getter)getFloatAttr, (setter)setFloatAttrClamp,
+ "The size to display the Empty",
+ (void *)EXPP_OBJ_ATTR_DRAWSIZE},
+
+ {"rbFlags",
+ (getter)Object_getRBFlags, (setter)Object_setRBFlags,
+ "Rigid body flags",
+ NULL},
+ {"rbMass",
+ (getter)Object_getRBMass, (setter)Object_setRBMass,
+ "Rigid body object mass",
+ NULL},
+ {"rbRadius",
+ (getter)Object_getRBRadius, (setter)Object_setRBRadius,
+ "Rigid body bounding sphere size",
+ NULL},
+ {"rbShapeBoundType",
+ (getter)Object_getRBShapeBoundType, (setter)Object_setRBShapeBoundType,
+ "Rigid body physics bounds object type",
+ NULL},
+ {"rbHalfExtents",
+ (getter)Object_getRBHalfExtents, (setter)NULL,
+ "Rigid body physics bounds object type",
+ NULL},
+
+ {"restrictDisplay",
+ (getter)Object_getRestricted, (setter)Object_setRestricted,
+ "Toggle object restrictions",
+ (void *)OB_RESTRICT_VIEW},
+ {"restrictSelect",
+ (getter)Object_getRestricted, (setter)Object_setRestricted,
+ "Toggle object restrictions",
+ (void *)OB_RESTRICT_SELECT},
+ {"restrictRender",
+ (getter)Object_getRestricted, (setter)Object_setRestricted,
+ "Toggle object restrictions",
+ (void *)OB_RESTRICT_RENDER},
+
+ {"pinShape",
+ (getter)Object_getShapeFlag, (setter)Object_setShapeFlag,
+ "Set the state for pinning this object",
+ (void *)OB_SHAPE_LOCK},
+ {"activeShape",
+ (getter)getIntAttr, (setter)setIntAttrClamp,
+ "set the index for the active shape key",
+ (void *)EXPP_OBJ_ATTR_ACT_SHAPE},
+
+
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+/*****************************************************************************/
+/* Python Object_Type structure definition: */
+/*****************************************************************************/
+PyTypeObject Object_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender Object", /* char *tp_name; */
+ sizeof( BPy_Object ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ ( destructor ) Object_dealloc,/* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ ( cmpfunc ) Object_compare, /* cmpfunc tp_compare; */
+ ( reprfunc ) Object_repr, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ ( hashfunc ) GenericLib_hash, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_Object_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ BPy_Object_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+static PyObject *M_Object_DrawModesDict( void )
+{
+ PyObject *M = PyConstant_New( );
+
+ if( M ) {
+ BPy_constant *d = ( BPy_constant * ) M;
+ PyConstant_Insert( d, "AXIS", PyInt_FromLong( OB_AXIS ) );
+ PyConstant_Insert( d, "TEXSPACE", PyInt_FromLong( OB_TEXSPACE ) );
+ PyConstant_Insert( d, "NAME", PyInt_FromLong( OB_DRAWNAME ) );
+ PyConstant_Insert( d, "WIRE", PyInt_FromLong( OB_DRAWWIRE ) );
+ PyConstant_Insert( d, "XRAY", PyInt_FromLong( OB_DRAWXRAY ) );
+ PyConstant_Insert( d, "TRANSP", PyInt_FromLong( OB_DRAWTRANSP ) );
+ }
+ return M;
+}
+
+static PyObject *M_Object_DrawTypesDict( void )
+{
+ PyObject *M = PyConstant_New( );
+
+ if( M ) {
+ BPy_constant *d = ( BPy_constant * ) M;
+ PyConstant_Insert( d, "BOUNDBOX", PyInt_FromLong( OB_BOUNDBOX ) );
+ PyConstant_Insert( d, "WIRE", PyInt_FromLong( OB_WIRE ) );
+ PyConstant_Insert( d, "SOLID", PyInt_FromLong( OB_SOLID ) );
+ PyConstant_Insert( d, "SHADED", PyInt_FromLong( OB_SHADED ) );
+ }
+ return M;
+}
+
+static PyObject *M_Object_ParentTypesDict( void )
+{
+ PyObject *M = PyConstant_New( );
+
+ if( M ) {
+ BPy_constant *d = ( BPy_constant * ) M;
+ PyConstant_Insert( d, "OBJECT", PyInt_FromLong( PAROBJECT ) );
+ PyConstant_Insert( d, "CURVE", PyInt_FromLong( PARCURVE ) );
+
+ /* 2.43 was released as LATTICE as PARKEY, my bad,
+ lattice uses PARSKEL also - Campbell */
+ PyConstant_Insert( d, "LATTICE", PyInt_FromLong( PARSKEL ) );
+
+ PyConstant_Insert( d, "ARMATURE", PyInt_FromLong( PARSKEL ) );
+ PyConstant_Insert( d, "VERT1", PyInt_FromLong( PARVERT1 ) );
+ PyConstant_Insert( d, "VERT3", PyInt_FromLong( PARVERT3 ) );
+ PyConstant_Insert( d, "BONE", PyInt_FromLong( PARBONE ) );
+ }
+ return M;
+}
+
+static PyObject *M_Object_PITypesDict( void )
+{
+ PyObject *M = PyConstant_New( );
+
+ if( M ) {
+ BPy_constant *d = ( BPy_constant * ) M;
+ PyConstant_Insert( d, "NONE", PyInt_FromLong( 0 ) );
+ PyConstant_Insert( d, "FORCE", PyInt_FromLong( PFIELD_FORCE ) );
+ PyConstant_Insert( d, "VORTEX", PyInt_FromLong( PFIELD_VORTEX ) );
+ PyConstant_Insert( d, "WIND", PyInt_FromLong( PFIELD_WIND ) );
+ PyConstant_Insert( d, "GUIDE", PyInt_FromLong( PFIELD_GUIDE ) );
+ }
+ return M;
+}
+
+static PyObject *M_Object_ProtectDict( void )
+{
+ PyObject *M = PyConstant_New( );
+
+ if( M ) {
+ BPy_constant *d = ( BPy_constant * ) M;
+ PyConstant_Insert( d, "LOCX", PyInt_FromLong( OB_LOCK_LOCX ) );
+ PyConstant_Insert( d, "LOCY", PyInt_FromLong( OB_LOCK_LOCY ) );
+ PyConstant_Insert( d, "LOCZ", PyInt_FromLong( OB_LOCK_LOCZ ) );
+ PyConstant_Insert( d, "LOC", PyInt_FromLong( OB_LOCK_LOC ) );
+ PyConstant_Insert( d, "ROTX", PyInt_FromLong( OB_LOCK_ROTX ) );
+ PyConstant_Insert( d, "ROTY", PyInt_FromLong( OB_LOCK_ROTY ) );
+ PyConstant_Insert( d, "ROTZ", PyInt_FromLong( OB_LOCK_ROTZ ) );
+ PyConstant_Insert( d, "ROT",
+ PyInt_FromLong( OB_LOCK_ROTX|OB_LOCK_ROTY|OB_LOCK_ROTZ ) );
+ PyConstant_Insert( d, "SCALEX", PyInt_FromLong( OB_LOCK_SCALEX ) );
+ PyConstant_Insert( d, "SCALEY", PyInt_FromLong( OB_LOCK_SCALEY ) );
+ PyConstant_Insert( d, "SCALEZ", PyInt_FromLong( OB_LOCK_SCALEZ ) );
+ PyConstant_Insert( d, "SCALE",
+ PyInt_FromLong( OB_LOCK_SCALEX|OB_LOCK_SCALEY|OB_LOCK_SCALEZ ) );
+ }
+ return M;
+}
+
+static PyObject *M_Object_RBFlagsDict( void )
+{
+ PyObject *M = PyConstant_New( );
+
+ if( M ) {
+ BPy_constant *d = ( BPy_constant * ) M;
+ PyConstant_Insert( d, "DYNAMIC", PyInt_FromLong( OB_DYNAMIC ) );
+ PyConstant_Insert( d, "CHILD", PyInt_FromLong( OB_CHILD ) );
+ PyConstant_Insert( d, "ACTOR", PyInt_FromLong( OB_ACTOR ) );
+ PyConstant_Insert( d, "USEFH", PyInt_FromLong( OB_DO_FH ) );
+ PyConstant_Insert( d, "ROTFH", PyInt_FromLong( OB_ROT_FH ) );
+ PyConstant_Insert( d, "ANISOTROPIC",
+ PyInt_FromLong( OB_ANISOTROPIC_FRICTION ) );
+ PyConstant_Insert( d, "GHOST", PyInt_FromLong( OB_GHOST ) );
+ PyConstant_Insert( d, "RIGIDBODY", PyInt_FromLong( OB_RIGID_BODY ) );
+ PyConstant_Insert( d, "BOUNDS", PyInt_FromLong( OB_BOUNDS ) );
+ PyConstant_Insert( d, "COLLISION_RESPONSE",
+ PyInt_FromLong( OB_COLLISION_RESPONSE ) );
+ PyConstant_Insert( d, "SECTOR", PyInt_FromLong( OB_SECTOR ) );
+ PyConstant_Insert( d, "PROP", PyInt_FromLong( OB_PROP ) );
+ PyConstant_Insert( d, "MAINACTOR", PyInt_FromLong( OB_MAINACTOR ) );
+ }
+ return M;
+}
+
+static PyObject *M_Object_RBShapeBoundDict( void )
+{
+ PyObject *M = PyConstant_New( );
+
+ if( M ) {
+ BPy_constant *d = ( BPy_constant * ) M;
+ PyConstant_Insert( d, "BOX", PyInt_FromLong( OB_BOUND_BOX ) );
+ PyConstant_Insert( d, "SPHERE", PyInt_FromLong( OB_BOUND_SPHERE ) );
+ PyConstant_Insert( d, "CYLINDER", PyInt_FromLong( OB_BOUND_CYLINDER ) );
+ PyConstant_Insert( d, "CONE", PyInt_FromLong( OB_BOUND_CONE ) );
+ PyConstant_Insert( d, "POLYHEDERON", PyInt_FromLong( OB_BOUND_POLYH ) );
+ }
+ return M;
+}
+
+static PyObject *M_Object_IpoKeyTypesDict( void )
+{
+ PyObject *M = PyConstant_New( );
+
+ if( M ) {
+ BPy_constant *d = ( BPy_constant * ) M;
+ PyConstant_Insert( d, "LOC", PyInt_FromLong( IPOKEY_LOC ) );
+ PyConstant_Insert( d, "ROT", PyInt_FromLong( IPOKEY_ROT ) );
+ PyConstant_Insert( d, "SIZE", PyInt_FromLong( IPOKEY_SIZE ) );
+ PyConstant_Insert( d, "LOCROT", PyInt_FromLong( IPOKEY_LOCROT ) );
+ PyConstant_Insert( d, "LOCROTSIZE", PyInt_FromLong( IPOKEY_LOCROTSIZE ) );
+
+ PyConstant_Insert( d, "PI_STRENGTH", PyInt_FromLong( IPOKEY_PI_STRENGTH ) );
+ PyConstant_Insert( d, "PI_FALLOFF", PyInt_FromLong( IPOKEY_PI_FALLOFF ) );
+ PyConstant_Insert( d, "PI_SURFACEDAMP", PyInt_FromLong( IPOKEY_PI_SURFACEDAMP ) );
+ PyConstant_Insert( d, "PI_RANDOMDAMP", PyInt_FromLong( IPOKEY_PI_RANDOMDAMP ) );
+ PyConstant_Insert( d, "PI_PERM", PyInt_FromLong( IPOKEY_PI_PERM ) );
+ }
+ return M;
+}
+
+/*****************************************************************************/
+/* Function: initObject */
+/*****************************************************************************/
+PyObject *Object_Init( void )
+{
+ PyObject *module, *dict;
+ PyObject *DrawModesDict = M_Object_DrawModesDict( );
+ PyObject *DrawTypesDict = M_Object_DrawTypesDict( );
+ PyObject *ParentTypesDict = M_Object_ParentTypesDict( );
+ PyObject *ProtectDict = M_Object_ProtectDict( );
+ PyObject *PITypesDict = M_Object_PITypesDict( );
+ PyObject *RBFlagsDict = M_Object_RBFlagsDict( );
+ PyObject *RBShapesDict = M_Object_RBShapeBoundDict( );
+ PyObject *IpoKeyTypesDict = M_Object_IpoKeyTypesDict( );
+
+ PyType_Ready( &Object_Type ) ;
+
+ module = Py_InitModule3( "Blender.Object", M_Object_methods,
+ M_Object_doc );
+
+
+ /* We Should Remove these!!!! */
+ PyModule_AddIntConstant( module, "LOC", IPOKEY_LOC );
+ PyModule_AddIntConstant( module, "ROT", IPOKEY_ROT );
+ PyModule_AddIntConstant( module, "SIZE", IPOKEY_SIZE );
+ PyModule_AddIntConstant( module, "LOCROT", IPOKEY_LOCROT );
+ PyModule_AddIntConstant( module, "LOCROTSIZE", IPOKEY_LOCROTSIZE );
+
+ PyModule_AddIntConstant( module, "PI_STRENGTH", IPOKEY_PI_STRENGTH );
+ PyModule_AddIntConstant( module, "PI_FALLOFF", IPOKEY_PI_FALLOFF );
+ PyModule_AddIntConstant( module, "PI_SURFACEDAMP", IPOKEY_PI_SURFACEDAMP );
+ PyModule_AddIntConstant( module, "PI_RANDOMDAMP", IPOKEY_PI_RANDOMDAMP );
+ PyModule_AddIntConstant( module, "PI_PERM", IPOKEY_PI_PERM );
+
+ PyModule_AddIntConstant( module, "NONE",0 );
+ PyModule_AddIntConstant( module, "FORCE",PFIELD_FORCE );
+ PyModule_AddIntConstant( module, "VORTEX",PFIELD_VORTEX );
+ PyModule_AddIntConstant( module, "MAGNET",PFIELD_MAGNET );
+ PyModule_AddIntConstant( module, "WIND",PFIELD_WIND );
+ /* Only keeping above so as not to break compat */
+
+
+ if( DrawModesDict )
+ PyModule_AddObject( module, "DrawModes", DrawModesDict );
+ if( DrawTypesDict )
+ PyModule_AddObject( module, "DrawTypes", DrawTypesDict );
+ if( ParentTypesDict )
+ PyModule_AddObject( module, "ParentTypes", ParentTypesDict );
+ if( PITypesDict )
+ PyModule_AddObject( module, "PITypes", PITypesDict );
+ if( ProtectDict )
+ PyModule_AddObject( module, "ProtectFlags", ProtectDict );
+ if( RBFlagsDict )
+ PyModule_AddObject( module, "RBFlags", RBFlagsDict );
+ if( RBShapesDict )
+ PyModule_AddObject( module, "RBShapes", RBShapesDict );
+ if( IpoKeyTypesDict )
+ PyModule_AddObject( module, "IpoKeyTypes", IpoKeyTypesDict );
+
+ /*Add SUBMODULES to the module*/
+ dict = PyModule_GetDict( module ); /*borrowed*/
+ PyDict_SetItemString(dict, "Pose", Pose_Init()); /*creates a *new* module*/
+ /*PyDict_SetItemString(dict, "Constraint", Constraint_Init()); */ /*creates a *new* module*/
+
+ return ( module );
+}
+
+/* #####DEPRECATED###### */
+
+static PyObject *Object_SetIpo( BPy_Object * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Object_setIpo );
+}
+
+static PyObject *Object_Select( BPy_Object * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Object_setSelect );
+}
+
+static PyObject *Object_SetDrawMode( BPy_Object * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args,
+ (setter)Object_setDrawMode );
+}
+
+static PyObject *Object_SetDrawType( BPy_Object * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args,
+ (setter)Object_setDrawType );
+}
+
+static PyObject *Object_SetMatrix( BPy_Object * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args,
+ (setter)Object_setMatrix );
+}
+
+static PyObject *Object_SetEuler( BPy_Object * self, PyObject * args )
+{
+ return EXPP_setterWrapperTuple( (void *)self, args,
+ (setter)Object_setEuler );
+}
+
+static PyObject *Object_setTimeOffset( BPy_Object * self, PyObject * args )
+{
+ float newTimeOffset;
+
+ if( !PyArg_ParseTuple( args, "f", &newTimeOffset ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a float as argument" );
+
+ self->object->sf = newTimeOffset;
+ self->object->recalc |= OB_RECALC_OB;
+
+ Py_RETURN_NONE;
+}
+
+
+/*************************************************************************/
+/* particle defection methods */
+/*************************************************************************/
+
+static PyObject *Object_SetPIDeflection( BPy_Object * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args,
+ (setter)Object_setPIDeflection );
+}
+
+static PyObject *Object_SetPIType( BPy_Object * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args,
+ (setter)Object_setPIType );
+}
+
+static PyObject *Object_SetPIUseMaxDist( BPy_Object * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args,
+ (setter)Object_setPIUseMaxDist );
+}
+
+static PyObject *Object_getPISurfaceDamp( BPy_Object * self )
+{
+ if( !self->object->pd && !setupPI(self->object) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "particle deflection could not be accessed" );
+
+ return PyFloat_FromDouble( ( double ) self->object->pd->pdef_damp );
+}
+
+static PyObject *Object_SetPISurfaceDamp( BPy_Object * self, PyObject * args )
+{
+ float value;
+
+ if( !self->object->pd && !setupPI(self->object) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "particle deflection could not be accessed" );
+
+ if( !PyArg_ParseTuple( args, "f", &value ) )
+ return NULL;
+
+ self->object->pd->pdef_damp = EXPP_ClampFloat( value,
+ EXPP_OBJECT_PIDAMP_MIN, EXPP_OBJECT_PIDAMP_MAX );
+ self->object->recalc |= OB_RECALC_OB;
+ Py_RETURN_NONE;
+}
+
+static PyObject *Object_getPIPerm( BPy_Object * self )
+{
+ if( !self->object->pd && !setupPI(self->object) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "particle deflection could not be accessed" );
+ return PyFloat_FromDouble ( (double) self->object->pd->pdef_perm );
+}
+
+static PyObject *Object_SetPIPerm( BPy_Object * self, PyObject * args )
+{
+ float value;
+
+ if( !self->object->pd && !setupPI(self->object) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "particle deflection could not be accessed" );
+
+ if( !PyArg_ParseTuple( args, "f", &value ) )
+ return NULL;
+
+ self->object->pd->pdef_perm = EXPP_ClampFloat( value,
+ EXPP_OBJECT_PIPERM_MIN, EXPP_OBJECT_PIPERM_MAX );
+ self->object->recalc |= OB_RECALC_OB;
+ Py_RETURN_NONE;
+}
+
+static PyObject *Object_getPIStrength( BPy_Object * self )
+{
+ if( !self->object->pd && !setupPI(self->object) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "particle deflection could not be accessed" );
+
+ return PyFloat_FromDouble( ( double ) self->object->pd->f_strength );
+}
+
+static PyObject *Object_setPIStrength( BPy_Object * self, PyObject * args )
+{
+ float value;
+
+ if( !self->object->pd && !setupPI(self->object) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "particle deflection could not be accessed" );
+
+ if( !PyArg_ParseTuple( args, "f", &value ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected float argument" );
+
+ self->object->pd->f_strength = EXPP_ClampFloat( value,
+ EXPP_OBJECT_PISTRENGTH_MIN, EXPP_OBJECT_PISTRENGTH_MAX );
+ self->object->recalc |= OB_RECALC_OB;
+ Py_RETURN_NONE;
+}
+
+static PyObject *Object_getPIFalloff( BPy_Object * self )
+{
+ if( !self->object->pd && !setupPI(self->object) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "particle deflection could not be accessed" );
+
+ return PyFloat_FromDouble( ( double ) self->object->pd->f_power );
+}
+
+static PyObject *Object_setPIFalloff( BPy_Object * self, PyObject * args )
+{
+ float value;
+
+ if( !PyArg_ParseTuple( args, "f", &value ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected float argument" );
+
+ self->object->pd->f_power = EXPP_ClampFloat( value,
+ EXPP_OBJECT_PIPOWER_MIN, EXPP_OBJECT_PIPOWER_MAX );
+ self->object->recalc |= OB_RECALC_OB;
+ Py_RETURN_NONE;
+}
+
+static PyObject *Object_getPIMaxDist( BPy_Object * self )
+{
+ if( !self->object->pd && !setupPI(self->object) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "particle deflection could not be accessed" );
+
+ return PyFloat_FromDouble( ( double ) self->object->pd->maxdist );
+}
+
+static PyObject *Object_setPIMaxDist( BPy_Object * self, PyObject * args )
+{
+ float value;
+
+ if( !self->object->pd && !setupPI(self->object) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "particle deflection could not be accessed" );
+
+ if( !PyArg_ParseTuple( args, "f", &value ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected float argument" );
+
+ self->object->pd->maxdist = EXPP_ClampFloat( value,
+ EXPP_OBJECT_PIMAXDIST_MIN, EXPP_OBJECT_PIMAXDIST_MAX );
+ self->object->recalc |= OB_RECALC_OB;
+ Py_RETURN_NONE;
+}
+
+static PyObject *Object_getPIRandomDamp( BPy_Object * self )
+{
+ if( !self->object->pd && !setupPI(self->object) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "particle deflection could not be accessed" );
+
+ return PyFloat_FromDouble( ( double ) self->object->pd->pdef_rdamp );
+}
+
+static PyObject *Object_setPIRandomDamp( BPy_Object * self, PyObject * args )
+{
+ float value;
+
+ if( !self->object->pd && !setupPI(self->object) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "particle deflection could not be accessed" );
+
+ if( !PyArg_ParseTuple( args, "f", &value ) )
+ return NULL;
+
+ self->object->pd->pdef_rdamp = EXPP_ClampFloat( value,
+ EXPP_OBJECT_PIRDAMP_MIN, EXPP_OBJECT_PIRDAMP_MAX );
+ self->object->recalc |= OB_RECALC_OB;
+ Py_RETURN_NONE;
+}
+
+/*************************************************************************/
+/* softbody methods */
+/*************************************************************************/
+
+static PyObject *Object_getSBMass( BPy_Object * self )
+{
+ if( !self->object->soft && !setupSB(self->object) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "softbody could not be accessed" );
+
+ return PyFloat_FromDouble( ( double ) self->object->soft->nodemass );
+}
+
+static PyObject *Object_setSBMass( BPy_Object * self, PyObject * args )
+{
+ float value;
+
+ if( !self->object->soft && !setupSB(self->object) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "softbody could not be accessed" );
+
+ if( !PyArg_ParseTuple( args, "f", &value ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected float argument" );
+
+ self->object->soft->nodemass = EXPP_ClampFloat( value,
+ EXPP_OBJECT_SBNODEMASSMIN, EXPP_OBJECT_SBNODEMASSMAX );
+ self->object->recalc |= OB_RECALC_OB;
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Object_getSBGravity( BPy_Object * self )
+{
+ if( !self->object->soft && !setupSB(self->object) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "softbody could not be accessed" );
+
+ return PyFloat_FromDouble( ( double ) self->object->soft->grav );
+}
+
+static PyObject *Object_setSBGravity( BPy_Object * self, PyObject * args )
+{
+ float value;
+
+ if( !self->object->soft && !setupSB(self->object) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "softbody could not be accessed" );
+
+ if( !PyArg_ParseTuple( args, "f", &value ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected float argument" );
+
+ self->object->soft->grav = EXPP_ClampFloat( value,
+ EXPP_OBJECT_SBGRAVMIN, EXPP_OBJECT_SBGRAVMAX );
+ self->object->recalc |= OB_RECALC_OB;
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Object_getSBFriction( BPy_Object * self )
+{
+ if( !self->object->soft && !setupSB(self->object) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "softbody could not be accessed" );
+
+ return PyFloat_FromDouble( ( double ) self->object->soft->mediafrict );
+}
+
+static PyObject *Object_setSBFriction( BPy_Object * self, PyObject * args )
+{
+ float value;
+
+ if( !self->object->soft && !setupSB(self->object) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "softbody could not be accessed" );
+
+ if( !PyArg_ParseTuple( args, "f", &value ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected float argument" );
+
+ self->object->soft->mediafrict = EXPP_ClampFloat( value,
+ EXPP_OBJECT_SBMEDIAFRICTMIN, EXPP_OBJECT_SBMEDIAFRICTMAX );
+ self->object->recalc |= OB_RECALC_OB;
+ Py_RETURN_NONE;
+}
+
+static PyObject *Object_getSBErrorLimit( BPy_Object * self )
+{
+ if( !self->object->soft && !setupSB(self->object) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "softbody could not be accessed" );
+
+ return PyFloat_FromDouble( ( double ) self->object->soft->rklimit );
+}
+
+static PyObject *Object_setSBErrorLimit( BPy_Object * self, PyObject * args )
+{
+ float value;
+
+ if( !self->object->soft && !setupSB(self->object) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "softbody could not be accessed" );
+
+ if( !PyArg_ParseTuple( args, "f", &value ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected float argument" );
+
+ self->object->soft->rklimit = EXPP_ClampFloat( value,
+ EXPP_OBJECT_SBRKLIMITMIN, EXPP_OBJECT_SBRKLIMITMAX );
+ self->object->recalc |= OB_RECALC_OB;
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Object_getSBGoalSpring( BPy_Object * self )
+{
+ if( !self->object->soft && !setupSB(self->object) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "softbody could not be accessed" );
+
+ return PyFloat_FromDouble( ( double ) self->object->soft->goalspring );
+}
+
+static PyObject *Object_setSBGoalSpring( BPy_Object * self, PyObject * args )
+{
+ float value;
+
+ if( !self->object->soft && !setupSB(self->object) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "softbody could not be accessed" );
+
+ if( !PyArg_ParseTuple( args, "f", &value ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected float argument" );
+
+ self->object->soft->goalspring = EXPP_ClampFloat( value,
+ EXPP_OBJECT_SBGOALSPRINGMIN, EXPP_OBJECT_SBGOALSPRINGMAX );
+ self->object->recalc |= OB_RECALC_OB;
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Object_getSBGoalFriction( BPy_Object * self )
+{
+ if( !self->object->soft && !setupSB(self->object) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "softbody could not be accessed" );
+
+ return PyFloat_FromDouble( ( double ) self->object->soft->goalfrict );
+}
+
+static PyObject *Object_setSBGoalFriction( BPy_Object * self, PyObject * args )
+{
+ float value;
+
+ if( !self->object->soft && !setupSB(self->object) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "softbody could not be accessed" );
+
+ if( !PyArg_ParseTuple( args, "f", &value ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected float argument" );
+
+ self->object->soft->goalfrict = EXPP_ClampFloat( value,
+ EXPP_OBJECT_SBGOALFRICTMIN, EXPP_OBJECT_SBGOALFRICTMAX );
+ self->object->recalc |= OB_RECALC_OB;
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Object_getSBMinGoal( BPy_Object * self )
+{
+ if( !self->object->soft && !setupSB(self->object) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "softbody could not be accessed" );
+
+ return PyFloat_FromDouble( ( double ) self->object->soft->mingoal );
+}
+
+static PyObject *Object_setSBMinGoal( BPy_Object * self, PyObject * args )
+{
+ float value;
+
+ if( !self->object->soft && !setupSB(self->object) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "softbody could not be accessed" );
+
+ if( !PyArg_ParseTuple( args, "f", &value ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected float argument" );
+
+ self->object->soft->mingoal = EXPP_ClampFloat( value,
+ EXPP_OBJECT_SBMINGOALMIN, EXPP_OBJECT_SBMINGOALMAX );
+ self->object->recalc |= OB_RECALC_OB;
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Object_getSBMaxGoal( BPy_Object * self )
+{
+ if( !self->object->soft && !setupSB(self->object) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "softbody could not be accessed" );
+
+ return PyFloat_FromDouble( ( double ) self->object->soft->maxgoal );
+}
+
+static PyObject *Object_setSBMaxGoal( BPy_Object * self, PyObject * args )
+{
+ float value;
+
+ if( !self->object->soft && !setupSB(self->object) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "softbody could not be accessed" );
+
+ if( !PyArg_ParseTuple( args, "f", &value ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected float argument" );
+
+ self->object->soft->maxgoal = EXPP_ClampFloat( value,
+ EXPP_OBJECT_SBMAXGOALMIN, EXPP_OBJECT_SBMAXGOALMAX );
+ self->object->recalc |= OB_RECALC_OB;
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Object_getSBDefaultGoal( BPy_Object * self )
+{
+ if( !self->object->soft && !setupSB(self->object) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "softbody could not be accessed" );
+
+ return PyFloat_FromDouble( ( double ) self->object->soft->defgoal );
+}
+
+static PyObject *Object_setSBDefaultGoal( BPy_Object * self, PyObject * args )
+{
+ float value;
+
+ if( !self->object->soft && !setupSB(self->object) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "softbody could not be accessed" );
+
+ if( !PyArg_ParseTuple( args, "f", &value ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected float argument" );
+
+ self->object->soft->defgoal = EXPP_ClampFloat( value,
+ EXPP_OBJECT_SBDEFGOALMIN, EXPP_OBJECT_SBDEFGOALMAX );
+ self->object->recalc |= OB_RECALC_OB;
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Object_getSBInnerSpring( BPy_Object * self )
+{
+ if( !self->object->soft && !setupSB(self->object) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "softbody could not be accessed" );
+
+ return PyFloat_FromDouble( ( double ) self->object->soft->inspring );
+}
+
+static PyObject *Object_setSBInnerSpring( BPy_Object * self, PyObject * args )
+{
+ float value;
+
+ if( !self->object->soft && !setupSB(self->object) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "softbody could not be accessed" );
+
+ if( !PyArg_ParseTuple( args, "f", &value ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected float argument" );
+
+ self->object->soft->inspring = EXPP_ClampFloat( value,
+ EXPP_OBJECT_SBINSPRINGMIN, EXPP_OBJECT_SBINSPRINGMAX );
+ self->object->recalc |= OB_RECALC_OB;
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Object_getSBInnerSpringFriction( BPy_Object * self )
+{
+ if( !self->object->soft && !setupSB(self->object) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "softbody could not be accessed" );
+
+ return PyFloat_FromDouble( ( double ) self->object->soft->infrict );
+}
+
+static PyObject *Object_setSBInnerSpringFriction( BPy_Object * self,
+ PyObject * args )
+{
+ float value;
+
+ if( !self->object->soft && !setupSB(self->object) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "softbody could not be accessed" );
+
+ if( !PyArg_ParseTuple( args, "f", &value ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected float argument" );
+
+ self->object->soft->infrict = EXPP_ClampFloat( value,
+ EXPP_OBJECT_SBINFRICTMIN, EXPP_OBJECT_SBINFRICTMAX );
+ self->object->recalc |= OB_RECALC_OB;
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Object_SetSBUseGoal( BPy_Object * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args,
+ (setter)Object_setSBUseGoal );
+}
+
+static PyObject *Object_SetSBUseEdges( BPy_Object * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args,
+ (setter)Object_setSBUseEdges );
+}
+
+static PyObject *Object_SetSBStiffQuads( BPy_Object * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args,
+ (setter)Object_setSBStiffQuads );
+}
diff --git a/source/blender/python/api2_2x/Object.h b/source/blender/python/api2_2x/Object.h
new file mode 100644
index 00000000000..557513560fd
--- /dev/null
+++ b/source/blender/python/api2_2x/Object.h
@@ -0,0 +1,62 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Michel Selten
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_OBJECT_H
+#define EXPP_OBJECT_H
+
+#include <Python.h>
+#include "DNA_object_types.h"
+
+/* The Object PyType Object defined in Object.c */
+extern PyTypeObject Object_Type;
+
+#define BPy_Object_Check(v) \
+ ((v)->ob_type == &Object_Type) /* for type checking */
+
+/*****************************************************************************/
+/* Python BPy_Object structure definition. */
+/*****************************************************************************/
+typedef struct {
+ PyObject_HEAD
+ struct Object *object; /* libdata must be second */
+ short realtype;
+} BPy_Object;
+
+PyObject *Object_Init( void );
+PyObject *Object_CreatePyObject( struct Object *obj );
+Object *Object_FromPyObject( PyObject * py_obj );
+
+void Object_updateDag( void *data );
+
+int EXPP_add_obdata( struct Object *object );
+
+#endif /* EXPP_OBJECT_H */
diff --git a/source/blender/python/api2_2x/Particle.c b/source/blender/python/api2_2x/Particle.c
new file mode 100644
index 00000000000..e2fdbc5b6ad
--- /dev/null
+++ b/source/blender/python/api2_2x/Particle.c
@@ -0,0 +1,1040 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Jacques Guignot, Jean-Michel Soler
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "Particle.h" /*This must come first */
+
+#include "DNA_object_types.h"
+#include "BKE_effect.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_object.h"
+#include "BLI_blenlib.h"
+#include "gen_utils.h"
+
+/*****************************************************************************/
+/* Python API function prototypes for the Particle module. */
+/*****************************************************************************/
+PyObject *M_Particle_New( PyObject * self, PyObject * args );
+PyObject *M_Particle_Get( PyObject * self, PyObject * args );
+
+/*****************************************************************************/
+/* Python BPy_Particle methods declarations: */
+/*****************************************************************************/
+PyObject *Effect_getType( BPy_Effect * self );
+PyObject *Effect_setType( BPy_Effect * self, PyObject * args );
+PyObject *Effect_getFlag( BPy_Effect * self );
+PyObject *Effect_setFlag( BPy_Effect * self, PyObject * args );
+PyObject *Particle_getSta( BPy_Particle * self );
+PyObject *Particle_setSta( BPy_Particle * self, PyObject * a );
+PyObject *Particle_getEnd( BPy_Particle * self );
+PyObject *Particle_setEnd( BPy_Particle * self, PyObject * a );
+PyObject *Particle_getLifetime( BPy_Particle * self );
+PyObject *Particle_setLifetime( BPy_Particle * self, PyObject * a );
+PyObject *Particle_getNormfac( BPy_Particle * self );
+PyObject *Particle_setNormfac( BPy_Particle * self, PyObject * a );
+PyObject *Particle_getObfac( BPy_Particle * self );
+PyObject *Particle_setObfac( BPy_Particle * self, PyObject * a );
+PyObject *Particle_getRandfac( BPy_Particle * self );
+PyObject *Particle_setRandfac( BPy_Particle * self, PyObject * a );
+PyObject *Particle_getTexfac( BPy_Particle * self );
+PyObject *Particle_setTexfac( BPy_Particle * self, PyObject * a );
+PyObject *Particle_getRandlife( BPy_Particle * self );
+PyObject *Particle_setRandlife( BPy_Particle * self, PyObject * a );
+PyObject *Particle_getNabla( BPy_Particle * self );
+PyObject *Particle_setNabla( BPy_Particle * self, PyObject * a );
+PyObject *Particle_getVectsize( BPy_Particle * self );
+PyObject *Particle_setVectsize( BPy_Particle * self, PyObject * a );
+PyObject *Particle_getTotpart( BPy_Particle * self );
+PyObject *Particle_setTotpart( BPy_Particle * self, PyObject * a );
+PyObject *Particle_getTotkey( BPy_Particle * self );
+PyObject *Particle_setTotkey( BPy_Particle * self, PyObject * a );
+PyObject *Particle_getSeed( BPy_Particle * self );
+PyObject *Particle_setSeed( BPy_Particle * self, PyObject * a );
+PyObject *Particle_getForce( BPy_Particle * self );
+PyObject *Particle_setForce( BPy_Particle * self, PyObject * a );
+PyObject *Particle_getMult( BPy_Particle * self );
+PyObject *Particle_setMult( BPy_Particle * self, PyObject * a );
+PyObject *Particle_getLife( BPy_Particle * self );
+PyObject *Particle_setLife( BPy_Particle * self, PyObject * a );
+PyObject *Particle_getMat( BPy_Particle * self );
+PyObject *Particle_setMat( BPy_Particle * self, PyObject * a );
+PyObject *Particle_getChild( BPy_Particle * self );
+PyObject *Particle_setChild( BPy_Particle * self, PyObject * a );
+PyObject *Particle_getDefvec( BPy_Particle * self );
+PyObject *Particle_setDefvec( BPy_Particle * self, PyObject * a );
+
+/*****************************************************************************/
+/* Python Particle_Type callback function prototypes: */
+/*****************************************************************************/
+void ParticleDeAlloc( BPy_Particle * msh );
+//int ParticlePrint (BPy_Particle *msh, FILE *fp, int flags);
+int ParticleSetAttr( BPy_Particle * msh, char *name, PyObject * v );
+PyObject *ParticleGetAttr( BPy_Particle * msh, char *name );
+PyObject *ParticleRepr( void );
+PyObject *ParticleCreatePyObject( struct Effect *particle );
+int ParticleCheckPyObject( PyObject * py_obj );
+struct Particle *ParticleFromPyObject( PyObject * py_obj );
+
+
+/*****************************************************************************/
+/* Python BPy_Particle methods table: */
+/*****************************************************************************/
+static PyMethodDef BPy_Particle_methods[] = {
+ {"getType", ( PyCFunction ) Effect_getType,
+ METH_NOARGS, "() - Return Effect type"},
+ {"setType", ( PyCFunction ) Effect_setType,
+ METH_VARARGS, "() - Set Effect type"},
+ {"getFlag", ( PyCFunction ) Effect_getFlag,
+ METH_NOARGS, "() - Return Effect flag"},
+ {"setFlag", ( PyCFunction ) Effect_setFlag,
+ METH_VARARGS, "() - Set Effect flag"},
+ {"getStartTime", ( PyCFunction ) Particle_getSta,
+ METH_NOARGS, "()-Return particle start time"},
+ {"setStartTime", ( PyCFunction ) Particle_setSta, METH_VARARGS,
+ "()- Sets particle start time"},
+ {"getEndTime", ( PyCFunction ) Particle_getEnd,
+ METH_NOARGS, "()-Return particle end time"},
+ {"setEndTime", ( PyCFunction ) Particle_setEnd, METH_VARARGS,
+ "()- Sets particle end time"},
+ {"getLifetime", ( PyCFunction ) Particle_getLifetime,
+ METH_NOARGS, "()-Return particle life time"},
+ {"setLifetime", ( PyCFunction ) Particle_setLifetime, METH_VARARGS,
+ "()- Sets particle life time "},
+ {"getNormfac", ( PyCFunction ) Particle_getNormfac,
+ METH_NOARGS, "()-Return particle life time"},
+ {"setNormfac", ( PyCFunction ) Particle_setNormfac, METH_VARARGS,
+ "()- Sets particle life time "},
+ {"getObfac", ( PyCFunction ) Particle_getObfac,
+ METH_NOARGS, "()-Return particle life time"},
+ {"setObfac", ( PyCFunction ) Particle_setObfac, METH_VARARGS,
+ "()- Sets particle life time "},
+ {"getRandfac", ( PyCFunction ) Particle_getRandfac,
+ METH_NOARGS, "()-Return particle life time"},
+ {"setRandfac", ( PyCFunction ) Particle_setRandfac, METH_VARARGS,
+ "()- Sets particle life time "},
+ {"getTexfac", ( PyCFunction ) Particle_getTexfac,
+ METH_NOARGS, "()-Return particle life time"},
+ {"setTexfac", ( PyCFunction ) Particle_setTexfac, METH_VARARGS,
+ "()- Sets particle life time "},
+ {"getRandlife", ( PyCFunction ) Particle_getRandlife,
+ METH_NOARGS, "()-Return particle life time"},
+ {"setRandlife", ( PyCFunction ) Particle_setRandlife, METH_VARARGS,
+ "()- Sets particle life time "},
+ {"getNabla", ( PyCFunction ) Particle_getNabla,
+ METH_NOARGS, "()-Return particle life time"},
+ {"setNabla", ( PyCFunction ) Particle_setNabla, METH_VARARGS,
+ "()- Sets particle life time "},
+ {"getVectsize", ( PyCFunction ) Particle_getVectsize,
+ METH_NOARGS, "()-Return particle life time"},
+ {"setVectsize", ( PyCFunction ) Particle_setVectsize, METH_VARARGS,
+ "()- Sets particle life time "},
+ {"getTotpart", ( PyCFunction ) Particle_getTotpart,
+ METH_NOARGS, "()-Return particle life time"},
+ {"setTotpart", ( PyCFunction ) Particle_setTotpart, METH_VARARGS,
+ "()- Sets particle life time "},
+ {"getTotkey", ( PyCFunction ) Particle_getTotkey,
+ METH_NOARGS, "()-Return particle life time"},
+ {"setTotkey", ( PyCFunction ) Particle_setTotkey, METH_VARARGS,
+ "()- Sets particle life time "},
+ {"getSeed", ( PyCFunction ) Particle_getSeed,
+ METH_NOARGS, "()-Return particle life time"},
+ {"setSeed", ( PyCFunction ) Particle_setSeed, METH_VARARGS,
+ "()- Sets particle life time "},
+ {"getForce", ( PyCFunction ) Particle_getForce,
+ METH_NOARGS, "()-Return particle life time"},
+ {"setForce", ( PyCFunction ) Particle_setForce, METH_VARARGS,
+ "()- Sets particle life time "},
+ {"getMult", ( PyCFunction ) Particle_getMult,
+ METH_NOARGS, "()-Return particle life time"},
+ {"setMult", ( PyCFunction ) Particle_setMult, METH_VARARGS,
+ "()- Sets particle life time "},
+ {"getLife", ( PyCFunction ) Particle_getLife,
+ METH_NOARGS, "()-Return particle life time"},
+ {"setLife", ( PyCFunction ) Particle_setLife, METH_VARARGS,
+ "()- Sets particle life time "},
+ {"getMat", ( PyCFunction ) Particle_getMat,
+ METH_NOARGS, "()-Return particle life time"},
+ {"setMat", ( PyCFunction ) Particle_setMat, METH_VARARGS,
+ "()- Sets particle life time "},
+ {"getChild", ( PyCFunction ) Particle_getChild,
+ METH_NOARGS, "()-Return particle life time"},
+ {"setChild", ( PyCFunction ) Particle_setChild, METH_VARARGS,
+ "()- Sets particle life time "},
+ {"getDefvec", ( PyCFunction ) Particle_getDefvec,
+ METH_NOARGS, "()-Return particle life time"},
+ {"setDefvec", ( PyCFunction ) Particle_setDefvec, METH_VARARGS,
+ "()- Sets particle life time "},
+
+
+ {NULL, NULL, 0, NULL}
+};
+
+/**************** prototypes ********************/
+PyObject *Particle_Init( void );
+
+
+/*****************************************************************************/
+/* Python Particle_Type structure definition: */
+/*****************************************************************************/
+
+PyTypeObject Particle_Type = {
+ PyObject_HEAD_INIT( NULL )
+ 0,
+ "Particle",
+ sizeof( BPy_Particle ),
+ 0,
+
+ ( destructor ) ParticleDeAlloc,
+ 0,
+ ( getattrfunc ) ParticleGetAttr,
+ ( setattrfunc ) ParticleSetAttr,
+ 0,
+ ( reprfunc ) ParticleRepr,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0, 0, 0, 0, 0, 0,
+ 0,
+ 0, 0, 0, 0, 0, 0,
+ BPy_Particle_methods,
+ 0,
+};
+/*****************************************************************************/
+/* The following string definitions are used for documentation strings. */
+/* In Python these will be written to the console when doing a */
+/* Blender.Particle.__doc__ */
+/*****************************************************************************/
+char M_Particle_doc[] = "The Blender Particle module\n\n\
+This module provides access to **Object Data** in Blender.\n\
+Functions :\n\
+ New(object mesh's name) : creates a new part object and adds it to the given mesh object \n\
+ Get(name) : retreives a particle with the given name (mandatory)\n\
+ get(name) : same as Get. Kept for compatibility reasons.\n";
+char M_Particle_New_doc[] = "New(name) : creates a new part object and adds it to the given mesh object\n";
+char M_Particle_Get_doc[] = "xxx";
+
+
+/*****************************************************************************/
+/* Python method structure definition for Blender.Particle module: */
+/*****************************************************************************/
+struct PyMethodDef M_Particle_methods[] = {
+ {"New", ( PyCFunction ) M_Particle_New, METH_VARARGS, M_Particle_New_doc},
+ {"Get", M_Particle_Get, METH_VARARGS, M_Particle_Get_doc},
+ {"get", M_Particle_Get, METH_VARARGS, M_Particle_Get_doc},
+ {NULL, NULL, 0, NULL}
+};
+
+
+/*****************************************************************************/
+/* Function: M_Particle_New */
+/* Python equivalent: Blender.Effect.Particle.New */
+/* Description : Create a particle effect and add a link */
+/* to the given mesh-type Object */
+/* Data : String mesh object name */
+/* Return : pyobject particle */
+/*****************************************************************************/
+PyObject *M_Particle_New( PyObject * self, PyObject * args )
+{
+ BPy_Effect *pyeffect;
+ Effect *bleffect = 0;
+ Object *ob;
+ char *name = NULL;
+
+ if( !PyArg_ParseTuple( args, "s", &name ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument" );
+
+ for( ob = G.main->object.first; ob; ob = ob->id.next )
+ if( !strcmp( name, ob->id.name + 2 ) )
+ break;
+
+ if( !ob )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "object does not exist" );
+
+ if( ob->type != OB_MESH )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "object is not a mesh" );
+
+ pyeffect = ( BPy_Effect * ) PyObject_NEW( BPy_Effect, &Effect_Type );
+ if( !pyeffect )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create Effect Data object" );
+
+ bleffect = add_effect( EFF_PARTICLE );
+ if( !bleffect ) {
+ Py_DECREF( pyeffect );
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't create Effect Data in Blender" );
+ }
+
+ pyeffect->effect = (PartEff *)bleffect;
+ BLI_addtail( &ob->effect, bleffect );
+
+ return ( PyObject * ) pyeffect;
+}
+
+/*****************************************************************************/
+/* Function: M_Particle_Get */
+/* Python equivalent: Blender.Effect.Particle.Get */
+/*****************************************************************************/
+PyObject *M_Particle_Get( PyObject * self, PyObject * args )
+{
+ /*arguments : string object name
+ int : position of effect in the obj's effect list */
+ char *name = 0;
+ Object *object_iter;
+ Effect *eff;
+ BPy_Particle *wanted_eff;
+ int num, i;
+
+ if( !PyArg_ParseTuple( args, "si", &name, &num ) )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected string int argument" ) );
+
+ object_iter = G.main->object.first;
+ if( !object_iter )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "Scene contains no object" );
+
+ while( object_iter ) {
+ if( strcmp( name, object_iter->id.name + 2 ) ) {
+ object_iter = object_iter->id.next;
+ continue;
+ }
+
+ if( object_iter->effect.first != NULL ) {
+ eff = object_iter->effect.first;
+ for( i = 0; i < num; i++ ) {
+ if( eff->type != EFF_PARTICLE )
+ continue;
+ eff = eff->next;
+ if( !eff )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_AttributeError,
+ "Object" ) );
+ }
+ wanted_eff =
+ ( BPy_Particle * ) PyObject_NEW( BPy_Particle,
+ &Particle_Type );
+ wanted_eff->particle = eff;
+ return ( PyObject * ) wanted_eff;
+ }
+ object_iter = object_iter->id.next;
+ }
+ Py_INCREF( Py_None );
+ return Py_None;
+}
+
+/*****************************************************************************/
+/* Function: Particle_Init */
+/*****************************************************************************/
+PyObject *Particle_Init( void )
+{
+ PyObject *submodule;
+
+ if( PyType_Ready( &Particle_Type) < 0)
+ return NULL;
+
+ submodule =
+ Py_InitModule3( "Blender.Particle", M_Particle_methods, M_Particle_doc );
+ return ( submodule );
+}
+
+/*****************************************************************************/
+/* Python BPy_Particle methods: */
+/*****************************************************************************/
+
+PyObject *Particle_getSta( BPy_Particle * self )
+{
+
+ PartEff *ptr = ( PartEff * ) self->particle;
+ return PyFloat_FromDouble( ptr->sta );
+}
+
+
+
+PyObject *Particle_setSta( BPy_Particle * self, PyObject * args )
+{
+ PartEff *ptr = ( PartEff * ) self->particle;
+ float val = 0;
+ if( !PyArg_ParseTuple( args, "f", &val ) )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected float argument" ) );
+ ptr->sta = val;
+ Py_INCREF( Py_None );
+ return Py_None;
+}
+
+PyObject *Particle_getEnd( BPy_Particle * self )
+{
+
+ PartEff *ptr = ( PartEff * ) self->particle;
+ return PyFloat_FromDouble( ptr->end );
+}
+
+
+
+PyObject *Particle_setEnd( BPy_Particle * self, PyObject * args )
+{
+ float val = 0;
+ PartEff *ptr = ( PartEff * ) self->particle;
+ if( !PyArg_ParseTuple( args, "f", &val ) )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected float argument" ) );
+ ptr->end = val;
+ Py_INCREF( Py_None );
+ return Py_None;
+}
+
+PyObject *Particle_getLifetime( BPy_Particle * self )
+{
+
+ PartEff *ptr = ( PartEff * ) self->particle;
+ return PyFloat_FromDouble( ptr->lifetime );
+}
+
+
+
+PyObject *Particle_setLifetime( BPy_Particle * self, PyObject * args )
+{
+ PartEff *ptr = ( PartEff * ) self->particle;
+ float val = 0;
+ if( !PyArg_ParseTuple( args, "f", &val ) )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected float argument" ) );
+ ptr->lifetime = val;
+ Py_INCREF( Py_None );
+ return Py_None;
+}
+
+
+PyObject *Particle_getNormfac( BPy_Particle * self )
+{
+
+ PartEff *ptr = ( PartEff * ) self->particle;
+ return PyFloat_FromDouble( ptr->normfac );
+}
+
+
+
+PyObject *Particle_setNormfac( BPy_Particle * self, PyObject * args )
+{
+ PartEff *ptr = ( PartEff * ) self->particle;
+ float val = 0;
+ if( !PyArg_ParseTuple( args, "f", &val ) )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected float argument" ) );
+ ptr->normfac = val;
+ Py_INCREF( Py_None );
+ return Py_None;
+}
+
+
+
+PyObject *Particle_getObfac( BPy_Particle * self )
+{
+
+ PartEff *ptr = ( PartEff * ) self->particle;
+ return PyFloat_FromDouble( ptr->obfac );
+}
+
+
+
+PyObject *Particle_setObfac( BPy_Particle * self, PyObject * args )
+{
+ float val = 0;
+ PartEff *ptr = ( PartEff * ) self->particle;
+ if( !PyArg_ParseTuple( args, "f", &val ) )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected float argument" ) );
+ ptr->obfac = val;
+ Py_INCREF( Py_None );
+ return Py_None;
+}
+
+
+
+PyObject *Particle_getRandfac( BPy_Particle * self )
+{
+
+ PartEff *ptr = ( PartEff * ) self->particle;
+ return PyFloat_FromDouble( ptr->randfac );
+}
+
+
+
+PyObject *Particle_setRandfac( BPy_Particle * self, PyObject * args )
+{
+ float val = 0;
+ PartEff *ptr = ( PartEff * ) self->particle;
+ if( !PyArg_ParseTuple( args, "f", &val ) )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected float argument" ) );
+ ptr->randfac = val;
+ Py_INCREF( Py_None );
+ return Py_None;
+}
+
+
+
+PyObject *Particle_getTexfac( BPy_Particle * self )
+{
+
+ PartEff *ptr = ( PartEff * ) self->particle;
+ return PyFloat_FromDouble( ptr->texfac );
+}
+
+
+
+PyObject *Particle_setTexfac( BPy_Particle * self, PyObject * args )
+{
+ PartEff *ptr = ( PartEff * ) self->particle;
+ float val = 0;
+ if( !PyArg_ParseTuple( args, "f", &val ) )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected float argument" ) );
+ ptr->texfac = val;
+ Py_INCREF( Py_None );
+ return Py_None;
+}
+
+
+
+PyObject *Particle_getRandlife( BPy_Particle * self )
+{
+
+ PartEff *ptr = ( PartEff * ) self->particle;
+ return PyFloat_FromDouble( ptr->randlife );
+}
+
+
+
+PyObject *Particle_setRandlife( BPy_Particle * self, PyObject * args )
+{
+ PartEff *ptr = ( PartEff * ) self->particle;
+ float val = 0;
+ if( !PyArg_ParseTuple( args, "f", &val ) )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected float argument" ) );
+ ptr->randlife = val;
+ Py_INCREF( Py_None );
+ return Py_None;
+}
+
+
+
+PyObject *Particle_getNabla( BPy_Particle * self )
+{
+
+ PartEff *ptr = ( PartEff * ) self->particle;
+ return PyFloat_FromDouble( ptr->nabla );
+}
+
+
+
+PyObject *Particle_setNabla( BPy_Particle * self, PyObject * args )
+{
+ PartEff *ptr = ( PartEff * ) self->particle;
+ float val = 0;
+ if( !PyArg_ParseTuple( args, "f", &val ) )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected float argument" ) );
+ ptr->nabla = val;
+ Py_INCREF( Py_None );
+ return Py_None;
+}
+
+
+
+PyObject *Particle_getVectsize( BPy_Particle * self )
+{
+
+ PartEff *ptr = ( PartEff * ) self->particle;
+ return PyFloat_FromDouble( ptr->vectsize );
+}
+
+
+
+PyObject *Particle_setVectsize( BPy_Particle * self, PyObject * args )
+{
+ PartEff *ptr = ( PartEff * ) self->particle;
+ float val = 0;
+ if( !PyArg_ParseTuple( args, "f", &val ) )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected float argument" ) );
+ ptr->vectsize = val;
+ Py_INCREF( Py_None );
+ return Py_None;
+}
+
+
+PyObject *Particle_getTotpart( BPy_Particle * self )
+{
+
+ PartEff *ptr = ( PartEff * ) self->particle;
+ return PyInt_FromLong( ptr->totpart );
+}
+
+
+
+PyObject *Particle_setTotpart( BPy_Particle * self, PyObject * args )
+{
+ int val = 0;
+ PartEff *ptr = ( PartEff * ) self->particle;
+ if( !PyArg_ParseTuple( args, "i", &val ) )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected int argument" ) );
+ ptr->totpart = val;
+ Py_INCREF( Py_None );
+ return Py_None;
+}
+
+
+PyObject *Particle_getTotkey( BPy_Particle * self )
+{
+
+ PartEff *ptr = ( PartEff * ) self->particle;
+ return PyInt_FromLong( ptr->totkey );
+}
+
+
+
+PyObject *Particle_setTotkey( BPy_Particle * self, PyObject * args )
+{
+ PartEff *ptr = ( PartEff * ) self->particle;
+ int val = 0;
+ if( !PyArg_ParseTuple( args, "i", &val ) )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected int argument" ) );
+ ptr->totkey = val;
+ Py_INCREF( Py_None );
+ return Py_None;
+}
+
+
+
+PyObject *Particle_getSeed( BPy_Particle * self )
+{
+
+ PartEff *ptr = ( PartEff * ) self->particle;
+ return PyInt_FromLong( ptr->seed );
+}
+
+
+
+PyObject *Particle_setSeed( BPy_Particle * self, PyObject * args )
+{
+ PartEff *ptr = ( PartEff * ) self->particle;
+ int val = 0;
+ if( !PyArg_ParseTuple( args, "i", &val ) )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected int argument" ) );
+ ptr->seed = val;
+ Py_INCREF( Py_None );
+ return Py_None;
+}
+
+PyObject *Particle_getForce( BPy_Particle * self )
+{
+
+ PartEff *ptr = ( PartEff * ) self->particle;
+ return Py_BuildValue( "(f,f,f)", ptr->force[0], ptr->force[1],
+ ptr->force[2] );
+}
+
+
+PyObject *Particle_setForce( BPy_Particle * self, PyObject * args )
+{
+ PartEff *ptr = ( PartEff * ) self->particle;
+ float val[3];
+ if( PyTuple_Size( args ) == 1 )
+ args = PyTuple_GetItem( args, 0 );
+ val[0] = (float)PyFloat_AsDouble( PyTuple_GetItem( args, 0 ) );
+ val[1] = (float)PyFloat_AsDouble( PyTuple_GetItem( args, 1 ) );
+ val[2] = (float)PyFloat_AsDouble( PyTuple_GetItem( args, 2 ) );
+ /*
+ if (!PyArg_ParseTuple(args, "fff", val,val+1,val+2 ))
+ return(EXPP_ReturnPyObjError(PyExc_AttributeError,\
+ "expected three float arguments"));
+ */
+ ptr->force[0] = val[0];
+ ptr->force[1] = val[1];
+ ptr->force[2] = val[2];
+ Py_INCREF( Py_None );
+ return Py_None;
+}
+
+PyObject *Particle_getMult( BPy_Particle * self )
+{
+
+ PartEff *ptr = ( PartEff * ) self->particle;
+ return Py_BuildValue( "(f,f,f,f)",
+ ptr->mult[0], ptr->mult[1], ptr->mult[2],
+ ptr->mult[3] );
+}
+
+
+PyObject *Particle_setMult( BPy_Particle * self, PyObject * args )
+{
+ PartEff *ptr = ( PartEff * ) self->particle;
+ float val[4];
+ if( PyTuple_Size( args ) == 1 )
+ args = PyTuple_GetItem( args, 0 );
+ val[0] = (float)PyFloat_AsDouble( PyTuple_GetItem( args, 0 ) );
+ val[1] = (float)PyFloat_AsDouble( PyTuple_GetItem( args, 1 ) );
+ val[2] = (float)PyFloat_AsDouble( PyTuple_GetItem( args, 2 ) );
+ val[3] = (float)PyFloat_AsDouble( PyTuple_GetItem( args, 3 ) );
+ ptr->mult[0] = val[0];
+ ptr->mult[1] = val[1];
+ ptr->mult[2] = val[2];
+ ptr->mult[3] = val[3];
+ Py_INCREF( Py_None );
+ return Py_None;
+}
+
+
+
+
+PyObject *Particle_getLife( BPy_Particle * self )
+{
+
+ PartEff *ptr = ( PartEff * ) self->particle;
+ return Py_BuildValue( "(f,f,f,f)",
+ ptr->life[0], ptr->life[1], ptr->life[2],
+ ptr->life[3] );
+}
+
+
+PyObject *Particle_setLife( BPy_Particle * self, PyObject * args )
+{
+ PartEff *ptr = ( PartEff * ) self->particle;
+ float val[4];
+ if( PyTuple_Size( args ) == 1 )
+ args = PyTuple_GetItem( args, 0 );
+ val[0] = (float)PyFloat_AsDouble( PyTuple_GetItem( args, 0 ) );
+ val[1] = (float)PyFloat_AsDouble( PyTuple_GetItem( args, 1 ) );
+ val[2] = (float)PyFloat_AsDouble( PyTuple_GetItem( args, 2 ) );
+ val[3] = (float)PyFloat_AsDouble( PyTuple_GetItem( args, 3 ) );
+ ptr->life[0] = val[0];
+ ptr->life[1] = val[1];
+ ptr->life[2] = val[2];
+ ptr->life[3] = val[3];
+ Py_INCREF( Py_None );
+ return Py_None;
+}
+
+
+
+PyObject *Particle_getChild( BPy_Particle * self )
+{
+
+ PartEff *ptr = ( PartEff * ) self->particle;
+ return Py_BuildValue( "(f,f,f,f)",
+ ptr->child[0], ptr->child[1], ptr->child[2],
+ ptr->child[3] );
+}
+
+
+PyObject *Particle_setChild( BPy_Particle * self, PyObject * args )
+{
+ PartEff *ptr = ( PartEff * ) self->particle;
+ float val[4];
+ if( PyTuple_Size( args ) == 1 )
+ args = PyTuple_GetItem( args, 0 );
+ val[0] = (float)PyFloat_AsDouble( PyTuple_GetItem( args, 0 ) );
+ val[1] = (float)PyFloat_AsDouble( PyTuple_GetItem( args, 1 ) );
+ val[2] = (float)PyFloat_AsDouble( PyTuple_GetItem( args, 2 ) );
+ val[3] = (float)PyFloat_AsDouble( PyTuple_GetItem( args, 3 ) );
+ ptr->child[0] = (short)val[0];
+ ptr->child[1] = (short)val[1];
+ ptr->child[2] = (short)val[2];
+ ptr->child[3] = (short)val[3];
+ Py_INCREF( Py_None );
+ return Py_None;
+}
+
+
+
+PyObject *Particle_getMat( BPy_Particle * self )
+{
+
+ PartEff *ptr = ( PartEff * ) self->particle;
+ return Py_BuildValue( "(f,f,f,f)",
+ ptr->mat[0], ptr->mat[1], ptr->mat[2],
+ ptr->mat[3] );
+}
+
+
+PyObject *Particle_setMat( BPy_Particle * self, PyObject * args )
+{
+ PartEff *ptr = ( PartEff * ) self->particle;
+ float val[4];
+ if( PyTuple_Size( args ) == 1 )
+ args = PyTuple_GetItem( args, 0 );
+ val[0] = (float)PyFloat_AsDouble( PyTuple_GetItem( args, 0 ) );
+ val[1] = (float)PyFloat_AsDouble( PyTuple_GetItem( args, 1 ) );
+ val[2] = (float)PyFloat_AsDouble( PyTuple_GetItem( args, 2 ) );
+ val[3] = (float)PyFloat_AsDouble( PyTuple_GetItem( args, 3 ) );
+ ptr->mat[0] = (short)val[0];
+ ptr->mat[1] = (short)val[1];
+ ptr->mat[2] = (short)val[2];
+ ptr->mat[3] = (short)val[3];
+ Py_INCREF( Py_None );
+ return Py_None;
+}
+
+
+PyObject *Particle_getDefvec( BPy_Particle * self )
+{
+
+ PartEff *ptr = ( PartEff * ) self->particle;
+ return Py_BuildValue( "(f,f,f)",
+ ptr->defvec[0], ptr->defvec[1], ptr->defvec[2] );
+}
+
+
+PyObject *Particle_setDefvec( BPy_Particle * self, PyObject * args )
+{
+ PartEff *ptr = ( PartEff * ) self->particle;
+ float val[3];
+ if( PyTuple_Size( args ) == 1 )
+ args = PyTuple_GetItem( args, 0 );
+ val[0] = (float)PyFloat_AsDouble( PyTuple_GetItem( args, 0 ) );
+ val[1] = (float)PyFloat_AsDouble( PyTuple_GetItem( args, 1 ) );
+ val[2] = (float)PyFloat_AsDouble( PyTuple_GetItem( args, 2 ) );
+ ptr->defvec[0] = val[0];
+ ptr->defvec[1] = val[1];
+ ptr->defvec[2] = val[2];
+ Py_INCREF( Py_None );
+ return Py_None;
+}
+
+
+/*****************************************************************************/
+/* Function: ParticleDeAlloc */
+/* Description: This is a callback function for the BPy_Particle type. It is */
+/* the destructor function. */
+/*****************************************************************************/
+void ParticleDeAlloc( BPy_Particle * self )
+{
+ PartEff *ptr = ( PartEff * ) self;
+ PyObject_DEL( ptr );
+}
+
+/*****************************************************************************/
+/* Function: ParticleGetAttr */
+/* Description: This is a callback function for the BPy_Particle type. It is */
+/* the function that accesses BPy_Particle "member variables" */
+/* and methods. */
+/*****************************************************************************/
+
+
+PyObject *ParticleGetAttr( BPy_Particle * self, char *name )
+{
+
+ if( strcmp( name, "seed" ) == 0 )
+ return Particle_getSeed( self );
+ else if( strcmp( name, "nabla" ) == 0 )
+ return Particle_getNabla( self );
+ else if( strcmp( name, "sta" ) == 0 )
+ return Particle_getSta( self );
+ else if( strcmp( name, "end" ) == 0 )
+ return Particle_getEnd( self );
+ else if( strcmp( name, "lifetime" ) == 0 )
+ return Particle_getLifetime( self );
+ else if( strcmp( name, "normfac" ) == 0 )
+ return Particle_getNormfac( self );
+ else if( strcmp( name, "obfac" ) == 0 )
+ return Particle_getObfac( self );
+ else if( strcmp( name, "randfac" ) == 0 )
+ return Particle_getRandfac( self );
+ else if( strcmp( name, "texfac" ) == 0 )
+ return Particle_getTexfac( self );
+ else if( strcmp( name, "randlife" ) == 0 )
+ return Particle_getRandlife( self );
+ else if( strcmp( name, "vectsize" ) == 0 )
+ return Particle_getVectsize( self );
+ else if( strcmp( name, "totpart" ) == 0 )
+ return Particle_getTotpart( self );
+ else if( strcmp( name, "force" ) == 0 )
+ return Particle_getForce( self );
+ else if( strcmp( name, "mult" ) == 0 )
+ return Particle_getMult( self );
+ else if( strcmp( name, "life" ) == 0 )
+ return Particle_getLife( self );
+ else if( strcmp( name, "child" ) == 0 )
+ return Particle_getChild( self );
+ else if( strcmp( name, "mat" ) == 0 )
+ return Particle_getMat( self );
+ else if( strcmp( name, "defvec" ) == 0 )
+ return Particle_getDefvec( self );
+
+
+ return Py_FindMethod( BPy_Particle_methods, ( PyObject * ) self,
+ name );
+}
+
+/*****************************************************************************/
+/* Function: ParticleSetAttr */
+/* Description: This is a callback function for the BPy_Particle type. */
+/* It is the function that sets Particle Data attributes */
+/* (member vars) */
+/*****************************************************************************/
+int ParticleSetAttr( BPy_Particle * self, char *name, PyObject * value )
+{
+
+ PyObject *valtuple;
+ PyObject *error = NULL;
+
+ valtuple = Py_BuildValue( "(N)", value );
+
+ if( !valtuple )
+ return EXPP_ReturnIntError( PyExc_MemoryError,
+ "ParticleSetAttr: couldn't create PyTuple" );
+
+ if( strcmp( name, "seed" ) == 0 )
+ error = Particle_setSeed( self, valtuple );
+ else if( strcmp( name, "nabla" ) == 0 )
+ error = Particle_setNabla( self, valtuple );
+ else if( strcmp( name, "sta" ) == 0 )
+ error = Particle_setSta( self, valtuple );
+ else if( strcmp( name, "end" ) == 0 )
+ error = Particle_setEnd( self, valtuple );
+ else if( strcmp( name, "lifetime" ) == 0 )
+ error = Particle_setLifetime( self, valtuple );
+ else if( strcmp( name, "normfac" ) == 0 )
+ error = Particle_setNormfac( self, valtuple );
+ else if( strcmp( name, "obfac" ) == 0 )
+ error = Particle_setObfac( self, valtuple );
+ else if( strcmp( name, "randfac" ) == 0 )
+ error = Particle_setRandfac( self, valtuple );
+ else if( strcmp( name, "texfac" ) == 0 )
+ error = Particle_setTexfac( self, valtuple );
+ else if( strcmp( name, "randlife" ) == 0 )
+ error = Particle_setRandlife( self, valtuple );
+ else if( strcmp( name, "nabla" ) == 0 )
+ error = Particle_setNabla( self, valtuple );
+ else if( strcmp( name, "vectsize" ) == 0 )
+ error = Particle_setVectsize( self, valtuple );
+ else if( strcmp( name, "totpart" ) == 0 )
+ error = Particle_setTotpart( self, valtuple );
+ else if( strcmp( name, "seed" ) == 0 )
+ error = Particle_setSeed( self, valtuple );
+ else if( strcmp( name, "force" ) == 0 )
+ error = Particle_setForce( self, valtuple );
+ else if( strcmp( name, "mult" ) == 0 )
+ error = Particle_setMult( self, valtuple );
+ else if( strcmp( name, "life" ) == 0 )
+ error = Particle_setLife( self, valtuple );
+ else if( strcmp( name, "child" ) == 0 )
+ error = Particle_setChild( self, valtuple );
+ else if( strcmp( name, "mat" ) == 0 )
+ error = Particle_setMat( self, valtuple );
+ else if( strcmp( name, "defvec" ) == 0 )
+ error = Particle_setDefvec( self, valtuple );
+
+ else {
+ Py_DECREF( valtuple );
+
+ if( ( strcmp( name, "Types" ) == 0 ) ||
+ ( strcmp( name, "Modes" ) == 0 ) )
+ return ( EXPP_ReturnIntError( PyExc_AttributeError,
+ "constant dictionary -- cannot be changed" ) );
+
+ else
+ return ( EXPP_ReturnIntError( PyExc_KeyError,
+ "attribute not found" ) );
+ }
+
+ Py_DECREF(valtuple);
+ if( error != Py_None )
+ return -1;
+
+ Py_DECREF( Py_None );
+ return 0;
+}
+
+/*****************************************************************************/
+/* Function: ParticlePrint */
+/* Description: This is a callback function for the BPy_Particle type. It */
+/* particles a meaninful string to 'print' particle objects. */
+/*****************************************************************************/
+/*
+int ParticlePrint(BPy_Particle *self, FILE *fp, int flags)
+{
+ printf("Hi, I'm a particle!");
+ return 0;
+}
+*/
+/*****************************************************************************/
+/* Function: ParticleRepr */
+/* Description: This is a callback function for the BPy_Particle type. It */
+/* particles a meaninful string to represent particle objects. */
+/*****************************************************************************/
+PyObject *ParticleRepr( void )
+{
+ return PyString_FromString( "Particle" );
+}
+
+PyObject *ParticleCreatePyObject( struct Effect * particle )
+{
+ BPy_Particle *blen_object;
+
+
+ blen_object =
+ ( BPy_Particle * ) PyObject_NEW( BPy_Particle,
+ &Particle_Type );
+
+ if( blen_object == NULL ) {
+ return ( NULL );
+ }
+ blen_object->particle = particle;
+ return ( ( PyObject * ) blen_object );
+
+}
+
+int ParticleCheckPyObject( PyObject * py_obj )
+{
+ return ( py_obj->ob_type == &Particle_Type );
+}
+
+
+struct Particle *ParticleFromPyObject( PyObject * py_obj )
+{
+ BPy_Particle *blen_obj;
+
+ blen_obj = ( BPy_Particle * ) py_obj;
+ return ( ( struct Particle * ) blen_obj->particle );
+
+}
diff --git a/source/blender/python/api2_2x/Particle.h b/source/blender/python/api2_2x/Particle.h
new file mode 100644
index 00000000000..f9b75b20c63
--- /dev/null
+++ b/source/blender/python/api2_2x/Particle.h
@@ -0,0 +1,67 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Jacques Guignot
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef EXPP_PARTICLE_H
+#define EXPP_PARTICLE_H
+
+#include <Python.h>
+#include "DNA_effect_types.h"
+
+extern PyTypeObject Particle_Type;
+
+#define BPy_Particle_Check(v) ((v)->ob_type==&Particle_Type)
+
+/* Python BPy_Particle structure definition */
+typedef struct {
+ PyObject_HEAD /* required py macro */
+ Effect * particle;
+} BPy_Particle;
+
+#include "Effect.h"
+
+/*****************************************************************************/
+/* Python Particle_Type callback function prototypes: */
+/*****************************************************************************/
+#if 0
+void ParticleDeAlloc( BPy_Particle * msh );
+//int ParticlePrint (BPy_Particle *msh, FILE *fp, int flags);
+int ParticleSetAttr( BPy_Particle * msh, char *name, PyObject * v );
+PyObject *ParticleGetAttr( BPy_Particle * msh, char *name );
+PyObject *ParticleRepr( void );
+PyObject *ParticleCreatePyObject( struct Effect *particle );
+int ParticleCheckPyObject( PyObject * py_obj );
+struct Particle *ParticleFromPyObject( PyObject * py_obj );
+#endif
+
+
+
+#endif /* EXPP_PARTICLE_H */
diff --git a/source/blender/python/api2_2x/Pose.c b/source/blender/python/api2_2x/Pose.c
new file mode 100644
index 00000000000..01fbe591a74
--- /dev/null
+++ b/source/blender/python/api2_2x/Pose.c
@@ -0,0 +1,1395 @@
+/*
+ * $Id:
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Joseph Gilbert
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#include "Pose.h"
+
+
+#include "mydevice.h"
+#include "BKE_armature.h"
+#include "BKE_main.h"
+#include "BKE_global.h"
+#include "BKE_action.h"
+#include "BKE_utildefines.h"
+#include "BIF_editaction.h"
+#include "BIF_space.h"
+#include "BIF_poseobject.h"
+#include "BKE_depsgraph.h"
+#include "DNA_object_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_space_types.h" //1 - this order
+#include "BSE_editipo.h" //2
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "Mathutils.h"
+#include "Object.h"
+#include "Constraint.h"
+#include "NLA.h"
+#include "gen_utils.h"
+#include "gen_library.h"
+
+#include "DNA_armature_types.h" /*used for pose bone select*/
+
+#include "MEM_guardedalloc.h"
+
+extern void chan_calc_mat(bPoseChannel *chan);
+
+//------------------------ERROR CODES---------------------------------
+//This is here just to make me happy and to have more consistant error strings :)
+static const char sPoseError[] = "Pose - Error: ";
+//static const char sPoseBadArgs[] = "Pose - Bad Arguments: ";
+static const char sPoseBoneError[] = "PoseBone - Error: ";
+//static const char sPoseBoneBadArgs[] = "PoseBone - Bad Arguments: ";
+static const char sPoseBonesDictError[] = "PoseBone - Error: ";
+//static const char sPoseBonesDictBadArgs[] = "PoseBone - Bad Arguments: ";
+
+//################## PoseBonesDict_Type (internal) ########################
+/*This is an internal psuedo-dictionary type that allows for manipulation
+* of posechannels inside of a pose structure. It is a subobject of pose.
+* i.e. Pose.bones['key']*/
+//################################################################
+
+//------------------METHOD IMPLEMENTATIONS-----------------------------
+//------------------------Pose.bones.items()
+//Returns a list of key:value pairs like dict.items()
+static PyObject* PoseBonesDict_items(BPy_PoseBonesDict *self)
+{
+ return PyDict_Items(self->bonesMap);
+}
+//------------------------Pose.bones.keys()
+//Returns a list of keys like dict.keys()
+static PyObject* PoseBonesDict_keys(BPy_PoseBonesDict *self)
+{
+ return PyDict_Keys(self->bonesMap);
+}
+//------------------------Armature.bones.values()
+//Returns a list of values like dict.values()
+static PyObject* PoseBonesDict_values(BPy_PoseBonesDict *self)
+{
+ return PyDict_Values(self->bonesMap);
+}
+//------------------ATTRIBUTE IMPLEMENTATION---------------------------
+//------------------TYPE_OBECT IMPLEMENTATION-----------------------
+//------------------------tp_doc
+//The __doc__ string for this object
+static char BPy_PoseBonesDict_doc[] = "This is an internal subobject of pose\
+designed to act as a Py_PoseBone dictionary.";
+
+//------------------------tp_methods
+//This contains a list of all methods the object contains
+static PyMethodDef BPy_PoseBonesDict_methods[] = {
+ {"items", (PyCFunction) PoseBonesDict_items, METH_NOARGS,
+ "() - Returns the key:value pairs from the dictionary"},
+ {"keys", (PyCFunction) PoseBonesDict_keys, METH_NOARGS,
+ "() - Returns the keys the dictionary"},
+ {"values", (PyCFunction) PoseBonesDict_values, METH_NOARGS,
+ "() - Returns the values from the dictionary"},
+ {NULL, NULL, 0, NULL}
+};
+//-----------------(internal)
+static int PoseBoneMapping_Init(PyObject *dictionary, ListBase *posechannels){
+ bPoseChannel *pchan = NULL;
+ PyObject *py_posechannel = NULL;
+
+ for (pchan = posechannels->first; pchan; pchan = pchan->next){
+ py_posechannel = PyPoseBone_FromPosechannel(pchan);
+ if (!py_posechannel)
+ return -1;
+
+ if(PyDict_SetItemString(dictionary,
+ pchan->name, py_posechannel) == -1){
+ return -1;
+ }
+ Py_DECREF(py_posechannel);
+ }
+ return 0;
+}
+
+//----------------- BonesDict_InitBones
+static int PoseBonesDict_InitBones(BPy_PoseBonesDict *self)
+{
+ PyDict_Clear(self->bonesMap);
+ if (PoseBoneMapping_Init(self->bonesMap, self->bones) == -1)
+ return 0;
+ return 1;
+}
+
+//------------------------tp_repr
+//This is the string representation of the object
+static PyObject *PoseBonesDict_repr(BPy_PoseBonesDict *self)
+{
+ char buffer[128], *str;
+ PyObject *key, *value;
+ int pos = 0;
+
+ /* probably a bit of overkill but better then crashing */
+ str = MEM_mallocN( 64 + ( PyDict_Size( self->bonesMap ) * 128), "PoseBonesDict_repr" );
+ str[0] = '\0';
+
+ sprintf(buffer, "[Pose Bone Dict: {");
+ strcat(str,buffer);
+ while (PyDict_Next(self->bonesMap, &pos, &key, &value)) {
+ sprintf(buffer, "%s : %s, ", PyString_AsString(key),
+ PyString_AsString(value->ob_type->tp_repr(value)));
+ strcat(str,buffer);
+ }
+ sprintf(buffer, "}]\n");
+ strcat(str,buffer);
+
+ MEM_freeN( str );
+
+ return PyString_FromString(str);
+}
+
+//------------------------tp_dealloc
+//This tells how to 'tear-down' our object when ref count hits 0
+static void PoseBonesDict_dealloc(BPy_PoseBonesDict * self)
+{
+ Py_DECREF(self->bonesMap);
+ PoseBonesDict_Type.tp_free(self);
+ return;
+}
+//------------------------mp_length
+//This gets the size of the dictionary
+static int PoseBonesDict_len(BPy_PoseBonesDict *self)
+{
+ return BLI_countlist(self->bones);
+}
+//-----------------------mp_subscript
+//This defines getting a bone from the dictionary - x = Bones['key']
+static PyObject *PoseBonesDict_GetItem(BPy_PoseBonesDict *self, PyObject* key)
+{
+ PyObject *value = NULL;
+
+ value = PyDict_GetItem(self->bonesMap, key);
+ if(value == NULL)
+ Py_RETURN_NONE;
+
+ return EXPP_incr_ret(value);
+}
+//------------------TYPE_OBECT DEFINITION--------------------------
+//Mapping Protocol
+static PyMappingMethods PoseBonesDict_MapMethods = {
+ (inquiry) PoseBonesDict_len, //mp_length
+ (binaryfunc)PoseBonesDict_GetItem, //mp_subscript
+ 0, //mp_ass_subscript
+};
+//PoseBonesDict TypeObject
+PyTypeObject PoseBonesDict_Type = {
+ PyObject_HEAD_INIT(NULL) //tp_head
+ 0, //tp_internal
+ "PoseBonesDict", //tp_name
+ sizeof(BPy_PoseBonesDict), //tp_basicsize
+ 0, //tp_itemsize
+ (destructor)PoseBonesDict_dealloc, //tp_dealloc
+ 0, //tp_print
+ 0, //tp_getattr
+ 0, //tp_setattr
+ 0, //tp_compare
+ (reprfunc) PoseBonesDict_repr, //tp_repr
+ 0, //tp_as_number
+ 0, //tp_as_sequence
+ &PoseBonesDict_MapMethods, //tp_as_mapping
+ 0, //tp_hash
+ 0, //tp_call
+ 0, //tp_str
+ 0, //tp_getattro
+ 0, //tp_setattro
+ 0, //tp_as_buffer
+ Py_TPFLAGS_DEFAULT, //tp_flags
+ BPy_PoseBonesDict_doc, //tp_doc
+ 0, //tp_traverse
+ 0, //tp_clear
+ 0, //tp_richcompare
+ 0, //tp_weaklistoffset
+ 0, //tp_iter
+ 0, //tp_iternext
+ BPy_PoseBonesDict_methods, //tp_methods
+ 0, //tp_members
+ 0, //tp_getset
+ 0, //tp_base
+ 0, //tp_dict
+ 0, //tp_descr_get
+ 0, //tp_descr_set
+ 0, //tp_dictoffset
+ 0, //tp_init
+ 0, //tp_alloc
+ 0, //tp_new
+ 0, //tp_free
+ 0, //tp_is_gc
+ 0, //tp_bases
+ 0, //tp_mro
+ 0, //tp_cache
+ 0, //tp_subclasses
+ 0, //tp_weaklist
+ 0 //tp_del
+};
+//-----------------------PyPoseBonesDict_FromPyPose
+static PyObject *PyPoseBonesDict_FromPyPose(BPy_Pose *py_pose)
+{
+ BPy_PoseBonesDict *py_posebonesdict = NULL;
+
+ //create py object
+ py_posebonesdict = (BPy_PoseBonesDict *)PoseBonesDict_Type.tp_alloc(&PoseBonesDict_Type, 0);
+ if (!py_posebonesdict)
+ goto RuntimeError;
+
+ //create internal dictionaries
+ py_posebonesdict->bonesMap = PyDict_New();
+ if (!py_posebonesdict->bonesMap)
+ goto RuntimeError;
+
+ //set listbase pointer
+ py_posebonesdict->bones = &py_pose->pose->chanbase;
+
+ //now that everything is setup - init the mappings
+ if (!PoseBonesDict_InitBones(py_posebonesdict))
+ goto RuntimeError;
+
+ return (PyObject*)py_posebonesdict;
+
+RuntimeError:
+ return EXPP_objError(PyExc_RuntimeError, "%s%s",
+ sPoseBonesDictError, "Failed to create class");
+}
+
+//################## Pose_Type ##########################
+/*This type is a wrapper for a pose*/
+//####################################################
+//------------------METHOD IMPLEMENTATIONS------------------------------
+static PyObject *Pose_update(BPy_Pose *self)
+{
+ Object *daddy = NULL;
+
+ self->pose->flag |= POSE_RECALC;
+
+ for (daddy = G.main->object.first; daddy; daddy = daddy->id.next){
+ if (daddy->pose == self->pose){
+ break;
+ }
+ }
+
+ if(daddy)
+ where_is_pose(daddy);
+
+ Py_RETURN_NONE;
+}
+//------------------------tp_methods
+//This contains a list of all methods the object contains
+static PyMethodDef BPy_Pose_methods[] = {
+ {"update", (PyCFunction) Pose_update, METH_NOARGS,
+ "() - Rebuilds the pose with new values"},
+ {NULL, NULL, 0, NULL}
+};
+//------------------ATTRIBUTE IMPLEMENTATIONS---------------------------
+//------------------------Pose.bones (getter)
+//Gets the bones attribute
+static PyObject *Pose_getBoneDict(BPy_Pose *self, void *closure)
+{
+ return EXPP_incr_ret((PyObject*)self->Bones);
+}
+//------------------------Pose.bones (setter)
+//Sets the bones attribute
+static int Pose_setBoneDict(BPy_Pose *self, PyObject *value, void *closure)
+{
+ goto AttributeError;
+
+AttributeError:
+ return EXPP_intError(PyExc_AttributeError, "%s%s",
+ sPoseError, "You are not allowed to change the .bones attribute");
+}
+//------------------TYPE_OBECT IMPLEMENTATION---------------------------
+//------------------------tp_getset
+//This contains methods for attributes that require checking
+static PyGetSetDef BPy_Pose_getset[] = {
+ {"bones", (getter)Pose_getBoneDict, (setter)Pose_setBoneDict,
+ "The pose's Bone dictionary", NULL},
+ {NULL, NULL, NULL, NULL, NULL}
+};
+//------------------------tp_dealloc
+//This tells how to 'tear-down' our object when ref count hits 0
+static void Pose_dealloc(BPy_Pose *self)
+{
+ Py_DECREF(self->Bones);
+ Pose_Type.tp_free(self);
+ return;
+}
+//------------------------tp_cmp
+//This compares 2 pose types
+static int Pose_compare(BPy_Pose *a, BPy_Pose *b )
+{
+ return ( a->pose== b->pose ) ? 0 : -1;
+}
+//------------------------tp_repr
+//This is the string representation of the object
+static PyObject *Pose_repr(BPy_Pose *self)
+{
+ return PyString_FromFormat( "[Pose \"%s\"]", self->name);
+}
+//------------------------tp_doc
+//The __doc__ string for this object
+static char BPy_Pose_doc[] = "This object wraps a Blender Pose object.";
+
+//------------------TYPE_OBECT DEFINITION--------------------------
+PyTypeObject Pose_Type = {
+ PyObject_HEAD_INIT(NULL) //tp_head
+ 0, //tp_internal
+ "Pose", //tp_name
+ sizeof(BPy_Pose), //tp_basicsize
+ 0, //tp_itemsize
+ (destructor)Pose_dealloc, //tp_dealloc
+ 0, //tp_print
+ 0, //tp_getattr
+ 0, //tp_setattr
+ (cmpfunc)Pose_compare, //tp_compare
+ (reprfunc)Pose_repr, //tp_repr
+ 0, //tp_as_number
+ 0, //tp_as_sequence
+ 0, //tp_as_mapping
+ 0, //tp_hash
+ 0, //tp_call
+ 0, //tp_str
+ 0, //tp_getattro
+ 0, //tp_setattro
+ 0, //tp_as_buffer
+ Py_TPFLAGS_DEFAULT, //tp_flags
+ BPy_Pose_doc, //tp_doc
+ 0, //tp_traverse
+ 0, //tp_clear
+ 0, //tp_richcompare
+ 0, //tp_weaklistoffset
+ 0, //tp_iter
+ 0, //tp_iternext
+ BPy_Pose_methods, //tp_methods
+ 0, //tp_members
+ BPy_Pose_getset, //tp_getset
+ 0, //tp_base
+ 0, //tp_dict
+ 0, //tp_descr_get
+ 0, //tp_descr_set
+ 0, //tp_dictoffset
+ 0, //tp_init
+ 0, //tp_alloc
+ 0, //tp_new
+ 0, //tp_free
+ 0, //tp_is_gc
+ 0, //tp_bases
+ 0, //tp_mro
+ 0, //tp_cache
+ 0, //tp_subclasses
+ 0, //tp_weaklist
+ 0 //tp_del
+};
+//################## PoseBone_Type #####################
+/*This type is a wrapper for a posechannel*/
+//####################################################
+//------------------METHOD IMPLEMENTATIONS------------------------------
+//------------------------------PoseBone.insertKey()
+static PyObject *PoseBone_insertKey(BPy_PoseBone *self, PyObject *args)
+{
+ PyObject *parent_object = NULL;
+ PyObject *constants = NULL, *item = NULL;
+ int frame = 1, oldframe, length, x, numeric_value = 0, oldflag, no_ipo_update = 0;
+ bPoseChannel *pchan = NULL;
+
+
+ if (!PyArg_ParseTuple(args, "O!i|Oi", &Object_Type, &parent_object, &frame, &constants, &no_ipo_update ))
+ goto AttributeError;
+
+ /* incase we ever have a value other then 1 for fast */
+ if (no_ipo_update)
+ no_ipo_update = 1;
+
+ //verify that this pchannel is part of the object->pose
+ for (pchan = ((BPy_Object*)parent_object)->object->pose->chanbase.first;
+ pchan; pchan = pchan->next){
+ if (pchan == self->posechannel)
+ break;
+ }
+ if (!pchan)
+ goto AttributeError2;
+
+ //verify that there is an action bound to this object
+ if (!((BPy_Object*)parent_object)->object->action){
+ goto AttributeError5;
+ }
+
+ oldflag = self->posechannel->flag;
+ self->posechannel->flag = 0;
+ //set the flags for this posechannel
+ if (constants){
+ if(PySequence_Check(constants)){
+ length = PySequence_Length(constants);
+ for (x = 0; x < length; x++){
+ item = PySequence_GetItem(constants, x);
+ if (item == EXPP_GetModuleConstant("Blender.Object.Pose", "ROT")){
+ numeric_value |= POSE_ROT;
+ }else if (item == EXPP_GetModuleConstant("Blender.Object.Pose", "LOC")){
+ numeric_value |= POSE_LOC;
+ }else if (item == EXPP_GetModuleConstant("Blender.Object.Pose", "SIZE")){
+ numeric_value |= POSE_SIZE;
+ }else{
+ Py_DECREF(item);
+ self->posechannel->flag = (short)oldflag;
+ goto AttributeError4;
+ }
+ Py_DECREF(item);
+ }
+ self->posechannel->flag = (short)numeric_value;
+ }else if (BPy_Constant_Check(constants)){
+ if (constants == EXPP_GetModuleConstant("Blender.Object.Pose", "ROT")){
+ numeric_value |= POSE_ROT;
+ }else if (constants == EXPP_GetModuleConstant("Blender.Object.Pose", "LOC")){
+ numeric_value |= POSE_LOC;
+ }else if (constants == EXPP_GetModuleConstant("Blender.Object.Pose", "SIZE")){
+ numeric_value |= POSE_SIZE;
+ }else{
+ self->posechannel->flag = (short)oldflag;
+ goto AttributeError4;
+ }
+ self->posechannel->flag = (short)numeric_value;
+ }else{
+ goto AttributeError3;
+ }
+ }else{ //nothing passed so set them all
+ self->posechannel->flag |= POSE_ROT;
+ self->posechannel->flag |= POSE_LOC;
+ self->posechannel->flag |= POSE_SIZE;
+ }
+
+ //set the frame we want insertion on
+ oldframe = G.scene->r.cfra;
+ G.scene->r.cfra = frame;
+
+ //add the action channel if it's not there
+ verify_action_channel(((BPy_Object*)parent_object)->object->action,
+ self->posechannel->name);
+
+ //insert the pose keys
+ if (self->posechannel->flag & POSE_ROT){
+ insertkey(&((BPy_Object*)parent_object)->object->id,
+ ID_PO, self->posechannel->name, NULL, AC_QUAT_X, no_ipo_update);
+ insertkey(&((BPy_Object*)parent_object)->object->id,
+ ID_PO, self->posechannel->name, NULL, AC_QUAT_Y, no_ipo_update);
+ insertkey(&((BPy_Object*)parent_object)->object->id,
+ ID_PO, self->posechannel->name, NULL, AC_QUAT_Z, no_ipo_update);
+ insertkey(&((BPy_Object*)parent_object)->object->id,
+ ID_PO, self->posechannel->name, NULL, AC_QUAT_W, no_ipo_update);
+ }
+ if (self->posechannel->flag & POSE_LOC){
+ insertkey(&((BPy_Object*)parent_object)->object->id,
+ ID_PO, self->posechannel->name, NULL, AC_LOC_X, no_ipo_update);
+ insertkey(&((BPy_Object*)parent_object)->object->id,
+ ID_PO, self->posechannel->name, NULL, AC_LOC_Y, no_ipo_update);
+ insertkey(&((BPy_Object*)parent_object)->object->id,
+ ID_PO, self->posechannel->name, NULL, AC_LOC_Z, no_ipo_update);
+ }
+ if (self->posechannel->flag & POSE_SIZE){
+ insertkey(&((BPy_Object*)parent_object)->object->id,
+ ID_PO, self->posechannel->name, NULL, AC_SIZE_X, no_ipo_update);
+ insertkey(&((BPy_Object*)parent_object)->object->id,
+ ID_PO, self->posechannel->name, NULL, AC_SIZE_Y, no_ipo_update);
+ insertkey(&((BPy_Object*)parent_object)->object->id,
+ ID_PO, self->posechannel->name, NULL, AC_SIZE_Z, no_ipo_update);
+ }
+
+ //flip the frame back
+ G.scene->r.cfra = oldframe;
+
+ //update the IPOs
+ if (no_ipo_update==0)
+ remake_action_ipos (((BPy_Object*)parent_object)->object->action);
+
+ Py_RETURN_NONE;
+
+AttributeError:
+ return EXPP_objError(PyExc_AttributeError, "%s%s%s",
+ sPoseBoneError, ".insertKey: ", "expects an Object, int, (optional) constants");
+AttributeError2:
+ return EXPP_objError(PyExc_AttributeError, "%s%s%s",
+ sPoseBoneError, ".insertKey: ", "wrong object detected. \
+ Use the object this pose came from");
+AttributeError3:
+ return EXPP_objError(PyExc_AttributeError, "%s%s%s",
+ sPoseBoneError, ".insertKey: ", "Expects a constant or list of constants");
+AttributeError4:
+ return EXPP_objError(PyExc_AttributeError, "%s%s%s",
+ sPoseBoneError, ".insertKey: ", "Please use a constant defined in the Pose module");
+AttributeError5:
+ return EXPP_objError(PyExc_AttributeError, "%s%s%s",
+ sPoseBoneError, ".insertKey: ", "You must set up and link an Action to this object first");
+}
+//------------------------tp_methods
+//This contains a list of all methods the object contains
+static PyMethodDef BPy_PoseBone_methods[] = {
+ {"insertKey", (PyCFunction) PoseBone_insertKey, METH_VARARGS,
+ "() - insert a key for this pose into an action"},
+ {NULL, NULL, 0, NULL}
+};
+//------------------ATTRIBUTE IMPLEMENTATIONS---------------------------
+//------------------------PoseBone.name (getter)
+//Gets the name attribute
+static PyObject *PoseBone_getName(BPy_PoseBone *self, void *closure)
+{
+ return PyString_FromString(self->posechannel->name);
+}
+//------------------------PoseBone.name (setter)
+//Sets the name attribute
+static int PoseBone_setName(BPy_PoseBone *self, PyObject *value, void *closure)
+{
+ char *name = "";
+
+ if (!PyArg_Parse(value, "s", &name))
+ goto AttributeError;
+
+ BLI_strncpy(self->posechannel->name, name, 32);
+ return 0;
+
+AttributeError:
+ return EXPP_intError(PyExc_AttributeError, "%s%s%s",
+ sPoseBoneError, ".name: ", "expects a string");
+}
+//------------------------PoseBone.loc (getter)
+//Gets the loc attribute
+static PyObject *PoseBone_getLoc(BPy_PoseBone *self, void *closure)
+{
+ return newVectorObject(self->posechannel->loc, 3, Py_WRAP);
+}
+//------------------------PoseBone.loc (setter)
+//Sets the loc attribute
+static int PoseBone_setLoc(BPy_PoseBone *self, PyObject *value, void *closure)
+{
+ VectorObject *vec = NULL;
+ int x;
+
+ if (!PyArg_Parse(value, "O!", &vector_Type, &vec))
+ goto AttributeError;
+ if (vec->size != 3)
+ goto AttributeError;
+
+ for (x = 0; x < 3; x++){
+ self->posechannel->loc[x] = vec->vec[x];
+ }
+ return 0;
+
+AttributeError:
+ return EXPP_intError(PyExc_AttributeError, "%s%s%s",
+ sPoseBoneError, ".loc: ", "expects a 3d vector object");
+}
+//------------------------PoseBone.size (getter)
+//Gets the size attribute
+static PyObject *PoseBone_getSize(BPy_PoseBone *self, void *closure)
+{
+ return newVectorObject(self->posechannel->size, 3, Py_WRAP);
+}
+//------------------------PoseBone.size (setter)
+//Sets the size attribute
+static int PoseBone_setSize(BPy_PoseBone *self, PyObject *value, void *closure)
+{
+ VectorObject *vec = NULL;
+ int x;
+
+ if (!PyArg_Parse(value, "O!", &vector_Type, &vec))
+ goto AttributeError;
+ if (vec->size != 3)
+ goto AttributeError;
+
+ for (x = 0; x < 3; x++){
+ self->posechannel->size[x] = vec->vec[x];
+ }
+ return 0;
+
+AttributeError:
+ return EXPP_intError(PyExc_AttributeError, "%s%s%s",
+ sPoseBoneError, ".size: ", "expects a 3d vector object");
+}
+//------------------------PoseBone.quat (getter)
+//Gets the quat attribute
+static PyObject *PoseBone_getQuat(BPy_PoseBone *self, void *closure)
+{
+ return newQuaternionObject(self->posechannel->quat, Py_WRAP);
+}
+//------------------------PoseBone.quat (setter)
+//Sets the quat attribute
+static int PoseBone_setQuat(BPy_PoseBone *self, PyObject *value, void *closure)
+{
+ QuaternionObject *quat = NULL;
+ int x;
+
+ if (!PyArg_Parse(value, "O!", &quaternion_Type, &quat))
+ goto AttributeError;
+
+ for (x = 0; x < 4; x++){
+ self->posechannel->quat[x] = quat->quat[x];
+ }
+ return 0;
+
+AttributeError:
+ return EXPP_intError(PyExc_AttributeError, "%s%s%s",
+ sPoseBoneError, ".quat: ", "expects a quaternion object");
+}
+//------------------------PoseBone.localMatrix (getter)
+//Gets the chan_mat
+static PyObject *PoseBone_getLocalMatrix(BPy_PoseBone *self, void *closure)
+{
+ return newMatrixObject((float*)self->posechannel->chan_mat, 4, 4, Py_WRAP);
+}
+//------------------------PoseBone.localMatrix (setter)
+//Sets the chan_mat
+static int PoseBone_setLocalMatrix(BPy_PoseBone *self, PyObject *value, void *closure)
+{
+ MatrixObject *matrix = NULL;
+ float size[3], quat[4], loc[3];
+ float mat3[3][3], mat4[4][4];
+ int matsize = 0;
+
+ if (!PyArg_Parse(value, "O!", &matrix_Type, &matrix))
+ goto AttributeError;
+
+ if (matrix->rowSize == 3 && matrix->colSize == 3){
+ matsize = 3;
+ Mat3CpyMat3(mat3, (float(*)[3])*matrix->matrix);
+ }else if (matrix->rowSize == 4 && matrix->colSize == 4){
+ matsize = 4;
+ Mat4CpyMat4(mat4, (float(*)[4])*matrix->matrix);
+ }
+
+ if (matsize != 3 && matsize != 4){
+ goto AttributeError;
+ }
+
+ //get size and rotation
+ if (matsize == 3){
+ Mat3ToSize(mat3, size);
+ Mat3Ortho(mat3);
+ Mat3ToQuat(mat3, quat);
+ }else if (matsize == 4){
+ Mat4ToSize(mat4, size);
+ Mat4Ortho(mat4);
+ Mat4ToQuat(mat4, quat);
+ }
+
+ //get loc
+ if (matsize == 4) {
+ VECCOPY(loc, matrix->matrix[3]);
+ }
+ else {
+ loc[0]= loc[1]= loc[2]= 0.0f;
+ }
+
+ //copy new attributes
+ VECCOPY(self->posechannel->size, size);
+ QUATCOPY(self->posechannel->quat, quat);
+ if (matsize == 4){
+ VECCOPY(self->posechannel->loc, loc);
+ }
+
+ //rebuild matrix
+ chan_calc_mat(self->posechannel);
+ return 0;
+
+AttributeError:
+ return EXPP_intError(PyExc_AttributeError, "%s%s%s",
+ sPoseBoneError, ".localMatrix: ", "expects a 3x3 or 4x4 matrix object");
+}
+//------------------------PoseBone.poseMatrix (getter)
+//Gets the pose_mat
+static PyObject *PoseBone_getPoseMatrix(BPy_PoseBone *self, void *closure)
+{
+ return newMatrixObject((float*)self->posechannel->pose_mat, 4, 4, Py_WRAP);
+}
+//------------------------PoseBone.poseMatrix (setter)
+//Sets the pose_mat
+static int PoseBone_setPoseMatrix(BPy_PoseBone *self, MatrixObject *value, void *closure)
+{
+ float delta_mat[4][4], quat[4]; /* rotation */
+ float size[4]; /* size only */
+
+ if( !MatrixObject_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected matrix object as argument" );
+
+ if( value->colSize != 4 || value->rowSize != 4 )
+ return EXPP_ReturnIntError( PyExc_AttributeError,
+ "matrix must be a 4x4 transformation matrix\n"
+ "for example as returned by object.matrixWorld" );
+
+ /* get bone-space cursor matrix and extract location */
+ armature_mat_pose_to_bone(self->posechannel, (float (*)[4]) *value->matrix, delta_mat);
+
+ /* Visual Location */
+ VECCOPY(self->posechannel->loc, delta_mat[3]);
+
+ /* Visual Size */
+ Mat4ToSize(delta_mat, size);
+ VECCOPY(self->posechannel->size, size);
+
+ /* Visual Rotation */
+ Mat4ToQuat(delta_mat, quat);
+ QUATCOPY(self->posechannel->quat, quat);
+
+ return 0;
+}
+//------------------------PoseBone.constraints (getter)
+//Gets the constraints sequence
+static PyObject *PoseBone_getConstraints(BPy_PoseBone *self, void *closure)
+{
+ return PoseConstraintSeq_CreatePyObject( self->posechannel );
+}
+//------------------------PoseBone.limitmin (getter)
+//Gets the pose bone limitmin value
+static PyObject *PoseBone_getLimitMin(BPy_PoseBone *self, void *closure)
+{
+ float mylimitmin[3];
+ Object *obj = NULL;
+
+ obj = Object_FromPoseChannel(self->posechannel);
+ if (obj==NULL){
+ return EXPP_ReturnPyObjError(PyExc_AttributeError, "Bone data is not found");
+ }
+ mylimitmin[0]=0.0f;
+ mylimitmin[1]=0.0f;
+ mylimitmin[2]=0.0f;
+ if(pose_channel_in_IK_chain(obj, self->posechannel)){
+ if ((self->posechannel->ikflag & BONE_IK_NO_XDOF)==0) {
+ if ((self->posechannel->ikflag & BONE_IK_XLIMIT)) {
+ mylimitmin[0] = self->posechannel->limitmin[0];
+ }
+ }
+ if ((self->posechannel->ikflag & BONE_IK_NO_YDOF)==0) {
+ if ((self->posechannel->ikflag & BONE_IK_YLIMIT)) {
+ mylimitmin[1] = self->posechannel->limitmin[1];
+ }
+ }
+ if ((self->posechannel->ikflag & BONE_IK_NO_ZDOF)==0) {
+ if ((self->posechannel->ikflag & BONE_IK_ZLIMIT)) {
+ mylimitmin[2] = self->posechannel->limitmin[2];
+ }
+ }
+ }
+ return newVectorObject(mylimitmin, 3, Py_NEW);
+}
+//------------------------PoseBone.limitmin (setter)
+//Sets the pose bone limitmin value
+static int PoseBone_setLimitMin(BPy_PoseBone *self, PyObject *value, void *closure)
+{
+ float newlimitmin[3];
+ int x;
+ Object *obj = NULL;
+ if(!PySequence_Check(value)){
+ return EXPP_ReturnIntError(PyExc_AttributeError, "Argument is not a sequence");
+ }
+ if (PySequence_Size(value) !=3){
+ return EXPP_ReturnIntError(PyExc_AttributeError, "Argument size must be 3");
+ }
+ newlimitmin[0]=0.0f;
+ newlimitmin[1]=0.0f;
+ newlimitmin[2]=0.0f;
+ for (x = 0; x<3;x++){
+ PyObject *item;
+ item = PySequence_GetItem(value, x); //new reference
+ if (PyFloat_Check(item)){
+ newlimitmin[x] = (float)PyFloat_AsDouble(item);
+ }else if (PyInt_Check(item)){
+ newlimitmin[x] = (float)PyInt_AsLong(item);
+ }
+ Py_DECREF(item);
+ }
+ obj = Object_FromPoseChannel(self->posechannel);
+ if (obj==NULL){
+ return EXPP_ReturnIntError(PyExc_AttributeError, "Bone data is not found");
+ }
+ if(!pose_channel_in_IK_chain(obj, self->posechannel)){
+ return EXPP_ReturnIntError(PyExc_AttributeError, "Bone is not part of an IK chain");
+ }
+ if ((self->posechannel->ikflag & BONE_IK_NO_XDOF)==0) {
+ if ((self->posechannel->ikflag & BONE_IK_XLIMIT)) {
+ self->posechannel->limitmin[0] = EXPP_ClampFloat(newlimitmin[0], -180.0f, 0.0f);
+ }
+ }
+ if ((self->posechannel->ikflag & BONE_IK_NO_YDOF)==0) {
+ if ((self->posechannel->ikflag & BONE_IK_YLIMIT)) {
+ self->posechannel->limitmin[1] = EXPP_ClampFloat(newlimitmin[1], -180.0f, 0.0f);
+ }
+ }
+ if ((self->posechannel->ikflag & BONE_IK_NO_ZDOF)==0) {
+ if ((self->posechannel->ikflag & BONE_IK_ZLIMIT)) {
+ self->posechannel->limitmin[2] = EXPP_ClampFloat(newlimitmin[2], -180.0f, 0.0f);
+ }
+ }
+ DAG_object_flush_update(G.scene, obj, OB_RECALC_DATA);
+ return 0;
+}
+
+//------------------------PoseBone.limitmax (getter)
+//Gets the pose bone limitmax value
+static PyObject *PoseBone_getLimitMax(BPy_PoseBone *self, void *closure)
+{
+ float mylimitmax[3];
+ Object *obj = NULL;
+
+ obj = Object_FromPoseChannel(self->posechannel);
+ if (obj==NULL){
+ return EXPP_ReturnPyObjError(PyExc_AttributeError, "Bone data is not found");
+ }
+ mylimitmax[0]=0.0f;
+ mylimitmax[1]=0.0f;
+ mylimitmax[2]=0.0f;
+ if(pose_channel_in_IK_chain(obj, self->posechannel)){
+ if ((self->posechannel->ikflag & BONE_IK_NO_XDOF)==0) {
+ if ((self->posechannel->ikflag & BONE_IK_XLIMIT)) {
+ mylimitmax[0] = self->posechannel->limitmax[0];
+ }
+ }
+ if ((self->posechannel->ikflag & BONE_IK_NO_YDOF)==0) {
+ if ((self->posechannel->ikflag & BONE_IK_YLIMIT)) {
+ mylimitmax[1] = self->posechannel->limitmax[1];
+ }
+ }
+ if ((self->posechannel->ikflag & BONE_IK_NO_ZDOF)==0) {
+ if ((self->posechannel->ikflag & BONE_IK_ZLIMIT)) {
+ mylimitmax[2] = self->posechannel->limitmax[2];
+ }
+ }
+ }
+ return newVectorObject(mylimitmax, 3, Py_NEW);
+}
+//------------------------PoseBone.limitmax (setter)
+//Sets the pose bone limitmax value
+static int PoseBone_setLimitMax(BPy_PoseBone *self, PyObject *value, void *closure)
+{
+ float newlimitmax[3];
+ int x;
+ Object *obj = NULL;
+ if(!PySequence_Check(value)){
+ return EXPP_ReturnIntError(PyExc_AttributeError, "Argument is not a sequence");
+ }
+ if (PySequence_Size(value) !=3){
+ return EXPP_ReturnIntError(PyExc_AttributeError, "Argument size must be 3");
+ }
+ newlimitmax[0]=0.0f;
+ newlimitmax[1]=0.0f;
+ newlimitmax[2]=0.0f;
+ for (x = 0; x<3;x++){
+ PyObject *item;
+ item = PySequence_GetItem(value, x); //new reference
+ if (PyFloat_Check(item)){
+ newlimitmax[x] = (float)PyFloat_AsDouble(item);
+ }else if (PyInt_Check(item)){
+ newlimitmax[x] = (float)PyInt_AsLong(item);
+ }
+ Py_DECREF(item);
+ }
+ obj = Object_FromPoseChannel(self->posechannel);
+ if (obj==NULL){
+ return EXPP_ReturnIntError(PyExc_AttributeError, "Bone data is not found");
+ }
+ if(!pose_channel_in_IK_chain(obj, self->posechannel)){
+ return EXPP_ReturnIntError(PyExc_AttributeError, "Bone is not part of an IK chain");
+ }
+ if ((self->posechannel->ikflag & BONE_IK_NO_XDOF)==0) {
+ if ((self->posechannel->ikflag & BONE_IK_XLIMIT)) {
+ self->posechannel->limitmax[0] = EXPP_ClampFloat(newlimitmax[0], 0.0f, 180.0f);
+ }
+ }
+ if ((self->posechannel->ikflag & BONE_IK_NO_YDOF)==0) {
+ if ((self->posechannel->ikflag & BONE_IK_YLIMIT)) {
+ self->posechannel->limitmax[1] = EXPP_ClampFloat(newlimitmax[1], 0.0f, 180.0f);
+ }
+ }
+ if ((self->posechannel->ikflag & BONE_IK_NO_ZDOF)==0) {
+ if ((self->posechannel->ikflag & BONE_IK_ZLIMIT)) {
+ self->posechannel->limitmax[2] = EXPP_ClampFloat(newlimitmax[2], 0.0f, 180.0f);
+ }
+ }
+ DAG_object_flush_update(G.scene, obj, OB_RECALC_DATA);
+ return 0;
+}
+//------------------------PoseBone.head (getter)
+//Gets the pose head position
+static PyObject *PoseBone_getHead(BPy_PoseBone *self, void *closure)
+{
+ return newVectorObject(self->posechannel->pose_head, 3, Py_NEW);
+}
+//------------------------PoseBone.head (setter)
+//Sets the pose head position
+static int PoseBone_setHead(BPy_PoseBone *self, PyObject *value, void *closure)
+{
+ return EXPP_intError(PyExc_AttributeError, "%s%s%s",
+ sPoseBoneError, ".head: ", "not able to set this property");
+}
+//------------------------PoseBone.tail (getter)
+//Gets the pose tail position
+static PyObject *PoseBone_getTail(BPy_PoseBone *self, void *closure)
+{
+ return newVectorObject(self->posechannel->pose_tail, 3, Py_NEW);
+}
+//------------------------PoseBone.tail (setter)
+//Sets the pose tail position
+static int PoseBone_setTail(BPy_PoseBone *self, PyObject *value, void *closure)
+{
+ return EXPP_intError(PyExc_AttributeError, "%s%s%s",
+ sPoseBoneError, ".tail: ", "not able to set this property");
+}
+//------------------------PoseBone.sel (getter)
+//Gets the pose bones selection
+static PyObject *PoseBone_getSelect(BPy_PoseBone *self, void *closure)
+{
+ if (self->posechannel->bone->flag & BONE_SELECTED)
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+}
+//------------------------PoseBone.sel (setter)
+//Sets the pose bones selection
+static int PoseBone_setSelect(BPy_PoseBone *self, PyObject *value, void *closure)
+{
+ int param = PyObject_IsTrue( value );
+ if( param == -1 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected True/False or 0/1" );
+
+ if ( param )
+ self->posechannel->bone->flag |= BONE_SELECTED;
+ else
+ self->posechannel->bone->flag &= ~(BONE_SELECTED | BONE_ACTIVE);
+ return 0;
+}
+
+
+//------------------------PoseBone.parent (getter)
+//Gets the bones parent if any
+static PyObject *PoseBone_getParent(BPy_PoseBone *self, void *closure)
+{
+ if (self->posechannel->parent)
+ return PyPoseBone_FromPosechannel(self->posechannel->parent);
+ else
+ Py_RETURN_NONE;
+}
+
+//------------------------PoseBone.displayObject (getter)
+//Gets the pose bones object used for display
+static PyObject *PoseBone_getDisplayObject(BPy_PoseBone *self, void *closure)
+{
+ if (self->posechannel->custom)
+ return Object_CreatePyObject(self->posechannel->custom);
+ else
+ Py_RETURN_NONE;
+}
+
+//------------------------PoseBone.displayObject (setter)
+//Sets the pose bones object used for display
+static int PoseBone_setDisplayObject(BPy_PoseBone *self, PyObject *value, void *closure)
+{
+ return GenericLib_assignData(value, (void **) &self->posechannel->custom, 0, 0, ID_OB, 0);
+}
+
+//------------------------PoseBone.hasIK (getter)
+//Returns True/False if the bone has IK's
+static PyObject *PoseBone_hasIK(BPy_PoseBone *self, void *closure)
+{
+ Object *obj = NULL;
+
+ obj = Object_FromPoseChannel(self->posechannel);
+ if (obj==NULL)
+ Py_RETURN_FALSE;
+
+ if( pose_channel_in_IK_chain(obj, self->posechannel) )
+ Py_RETURN_TRUE;
+
+ Py_RETURN_FALSE;
+}
+
+//------------------------PoseBone.stretch (getter)
+//Gets the pose bones IK Stretch value
+static PyObject *PoseBone_getStretch(BPy_PoseBone *self, void *closure)
+{
+ return PyFloat_FromDouble( self->posechannel->ikstretch );
+}
+
+//------------------------PoseBone.stretch (setter)
+//Sets the pose bones IK Stretch value
+static int PoseBone_setStretch(BPy_PoseBone *self, PyObject *value, void *closure)
+{
+ float ikstretch;
+
+ if( !PyNumber_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected float argument" );
+
+ ikstretch = (float)PyFloat_AsDouble(value);
+ if (ikstretch<0) ikstretch = 0.0;
+ if (ikstretch>1) ikstretch = 1.0;
+ self->posechannel->ikstretch = ikstretch;
+ return 0;
+}
+
+//------------------------PoseBone.stiffX/Y/Z (getter)
+//Gets the pose bones IK stiffness
+static PyObject *PoseBone_getStiff(BPy_PoseBone *self, void *axis)
+{
+ return PyFloat_FromDouble( self->posechannel->stiffness[(int)axis] );
+}
+
+//------------------------PoseBone.stiffX/Y/Z (setter)
+//Sets the pose bones IK stiffness
+static int PoseBone_setStiff(BPy_PoseBone *self, PyObject *value, void *axis)
+{
+ float stiff;
+
+ if( !PyNumber_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected float argument" );
+
+ stiff = (float)PyFloat_AsDouble(value);
+ if (stiff<0) stiff = 0;
+ if (stiff>0.990) stiff = 0.990f;
+ self->posechannel->stiffness[(int)axis] = stiff;
+ return 0;
+}
+
+//------------------------PoseBone.* (getter)
+//Gets the pose bones flag
+/*
+static PyObject *PoseBone_getFlag(BPy_PoseBone *self, void *flag)
+{
+ if (self->posechannel->flag & (int)flag)
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+
+}
+*/
+
+//------------------------PoseBone.* (setter)
+//Gets the pose bones flag
+/*
+static int PoseBone_setFlag(BPy_PoseBone *self, PyObject *value, void *flag)
+{
+ if ( PyObject_IsTrue(value) )
+ self->posechannel->flag |= (int)flag;
+ else
+ self->posechannel->flag &= ~(int)flag;
+ return 0;
+}
+*/
+
+//------------------------PoseBone.* (getter)
+//Gets the pose bones ikflag
+static PyObject *PoseBone_getIKFlag(BPy_PoseBone *self, void *flag)
+{
+ if (self->posechannel->ikflag & (int)flag)
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+
+}
+
+//------------------------PoseBone.* (setter)
+//Sets the pose bones ikflag
+static int PoseBone_setIKFlag(BPy_PoseBone *self, PyObject *value, void *flag)
+{
+ int param = PyObject_IsTrue( value );
+ if( param == -1 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected True/False or 0/1" );
+
+ if ( param )
+ self->posechannel->ikflag |= (int)flag;
+ else
+ self->posechannel->ikflag &= ~(int)flag;
+ return 0;
+}
+
+//------------------------Bone.layerMask (get)
+static PyObject *PoseBone_getLayerMask(BPy_PoseBone *self)
+{
+ /* do this extra stuff because the short's bits can be negative values */
+ unsigned short laymask = 0;
+ laymask |= self->posechannel->bone->layer;
+ return PyInt_FromLong((int)laymask);
+}
+//------------------------Bone.layerMask (set)
+static int PoseBone_setLayerMask(BPy_PoseBone *self, PyObject *value)
+{
+ int laymask;
+ if (!PyInt_Check(value)) {
+ return EXPP_ReturnIntError( PyExc_AttributeError,
+ "expected an integer (bitmask) as argument" );
+ }
+
+ laymask = PyInt_AsLong(value);
+
+ if (laymask <= 0 || laymask > (1<<16) - 1)
+ return EXPP_ReturnIntError( PyExc_AttributeError,
+ "bitmask must have from 1 up to 16 bits set");
+
+ self->posechannel->bone->layer = 0;
+ self->posechannel->bone->layer |= laymask;
+
+ return 0;
+}
+
+//------------------TYPE_OBECT IMPLEMENTATION---------------------------
+//------------------------tp_getset
+//This contains methods for attributes that require checking
+static PyGetSetDef BPy_PoseBone_getset[] = {
+ {"name", (getter)PoseBone_getName, (setter)PoseBone_setName,
+ "The pose bone's name", NULL},
+ {"loc", (getter)PoseBone_getLoc, (setter)PoseBone_setLoc,
+ "The pose bone's change in location as a vector", NULL},
+ {"size", (getter)PoseBone_getSize, (setter)PoseBone_setSize,
+ "The pose bone's change in size as a vector", NULL},
+ {"quat", (getter)PoseBone_getQuat, (setter)PoseBone_setQuat,
+ "The pose bone's change in rotation as a quat", NULL},
+ {"localMatrix", (getter)PoseBone_getLocalMatrix, (setter)PoseBone_setLocalMatrix,
+ "The pose bone's change matrix built from the quat, loc, and size", NULL},
+ {"poseMatrix", (getter)PoseBone_getPoseMatrix, (setter)PoseBone_setPoseMatrix,
+ "The pose bone's matrix", NULL},
+ {"head", (getter)PoseBone_getHead, (setter)PoseBone_setHead,
+ "The pose bone's head positon", NULL},
+ {"tail", (getter)PoseBone_getTail, (setter)PoseBone_setTail,
+ "The pose bone's tail positon", NULL},
+ {"sel", (getter)PoseBone_getSelect, (setter)PoseBone_setSelect,
+ "The pose selection state", NULL},
+ {"limitMin", (getter)PoseBone_getLimitMin, (setter)PoseBone_setLimitMin,
+ "The pose bone dof min", NULL},
+ {"limitMax", (getter)PoseBone_getLimitMax, (setter)PoseBone_setLimitMax,
+ "The pose bone dof max", NULL},
+ {"constraints", (getter)PoseBone_getConstraints, (setter)NULL,
+ "The list of contraints that pertain to this pose bone", NULL},
+ {"parent", (getter)PoseBone_getParent, (setter)NULL,
+ "The bones parent (read only for posebones)", NULL},
+ {"displayObject", (getter)PoseBone_getDisplayObject, (setter)PoseBone_setDisplayObject,
+ "The poseMode object to draw in place of this bone", NULL},
+
+ {"hasIK", (getter)PoseBone_hasIK, (setter)NULL,
+ "True if the pose bone has IK (readonly)", NULL },
+
+ {"stretch", (getter)PoseBone_getStretch, (setter)PoseBone_setStretch,
+ "Stretch the bone to the IK Target", NULL },
+
+ {"stiffX", (getter)PoseBone_getStiff, (setter)PoseBone_setStiff,
+ "bones stiffness on the X axis", (void *)0 },
+ {"stiffY", (getter)PoseBone_getStiff, (setter)PoseBone_setStiff,
+ "bones stiffness on the Y axis", (void *)1 },
+ {"stiffZ", (getter)PoseBone_getStiff, (setter)PoseBone_setStiff,
+ "bones stiffness on the Z axis", (void *)2 },
+
+ {"limitX", (getter)PoseBone_getIKFlag, (setter)PoseBone_setIKFlag,
+ "limit rotation over X axis when part of an IK", (void *)BONE_IK_XLIMIT },
+ {"limitY", (getter)PoseBone_getIKFlag, (setter)PoseBone_setIKFlag,
+ "limit rotation over Y axis when part of an IK", (void *)BONE_IK_YLIMIT },
+ {"limitZ", (getter)PoseBone_getIKFlag, (setter)PoseBone_setIKFlag,
+ "limit rotation over Z axis when part of an IK", (void *)BONE_IK_ZLIMIT },
+
+ {"lockXRot", (getter)PoseBone_getIKFlag, (setter)PoseBone_setIKFlag,
+ "disable X DoF when part of an IK", (void *)BONE_IK_NO_XDOF },
+ {"lockYRot", (getter)PoseBone_getIKFlag, (setter)PoseBone_setIKFlag,
+ "disable Y DoF when part of an IK", (void *)BONE_IK_NO_YDOF },
+ {"lockZRot", (getter)PoseBone_getIKFlag, (setter)PoseBone_setIKFlag,
+ "disable Z DoF when part of an IK", (void *)BONE_IK_NO_ZDOF },
+ {"layerMask", (getter)PoseBone_getLayerMask, (setter)PoseBone_setLayerMask,
+ "Layer bitmask", NULL },
+ {NULL, NULL, NULL, NULL, NULL}
+};
+//------------------------tp_dealloc
+//This tells how to 'tear-down' our object when ref count hits 0
+static void PoseBone_dealloc(BPy_PoseBone *self)
+{
+ PoseBone_Type.tp_free(self);
+ return;
+}
+//------------------------tp_repr
+//This is the string representation of the object
+static PyObject *PoseBone_repr(BPy_PoseBone *self)
+{
+ return PyString_FromFormat( "[PoseBone \"%s\"]", self->posechannel->name);
+}
+//------------------------tp_doc
+//The __doc__ string for this object
+static char BPy_PoseBone_doc[] = "This object wraps a Blender PoseBone object.";
+
+//------------------TYPE_OBECT DEFINITION--------------------------
+PyTypeObject PoseBone_Type = {
+ PyObject_HEAD_INIT(NULL) //tp_head
+ 0, //tp_internal
+ "PoseBone", //tp_name
+ sizeof(BPy_PoseBone), //tp_basicsize
+ 0, //tp_itemsize
+ (destructor)PoseBone_dealloc, //tp_dealloc
+ 0, //tp_print
+ 0, //tp_getattr
+ 0, //tp_setattr
+ 0, //tp_compare
+ (reprfunc)PoseBone_repr, //tp_repr
+ 0, //tp_as_number
+ 0, //tp_as_sequence
+ 0, //tp_as_mapping
+ 0, //tp_hash
+ 0, //tp_call
+ 0, //tp_str
+ 0, //tp_getattro
+ 0, //tp_setattro
+ 0, //tp_as_buffer
+ Py_TPFLAGS_DEFAULT, //tp_flags
+ BPy_PoseBone_doc, //tp_doc
+ 0, //tp_traverse
+ 0, //tp_clear
+ 0, //tp_richcompare
+ 0, //tp_weaklistoffset
+ 0, //tp_iter
+ 0, //tp_iternext
+ BPy_PoseBone_methods, //tp_methods
+ 0, //tp_members
+ BPy_PoseBone_getset, //tp_getset
+ 0, //tp_base
+ 0, //tp_dict
+ 0, //tp_descr_get
+ 0, //tp_descr_set
+ 0, //tp_dictoffset
+ 0, //tp_init
+ 0, //tp_alloc
+ 0, //tp_new
+ 0, //tp_free
+ 0, //tp_is_gc
+ 0, //tp_bases
+ 0, //tp_mro
+ 0, //tp_cache
+ 0, //tp_subclasses
+ 0, //tp_weaklist
+ 0 //tp_del
+};
+//-------------------MODULE METHODS IMPLEMENTATION------------------------
+//-------------------MODULE METHODS DEFINITION-----------------------------
+struct PyMethodDef M_Pose_methods[] = {
+ {NULL, NULL, 0, NULL}
+};
+//-------------------MODULE INITIALIZATION--------------------------------
+PyObject *Pose_Init(void)
+{
+ PyObject *module;
+
+ //Initializes TypeObject.ob_type
+ if (PyType_Ready(&Pose_Type) < 0 || PyType_Ready(&PoseBone_Type) < 0 ||
+ PyType_Ready(&PoseBonesDict_Type) < 0) {
+ Py_RETURN_NONE;
+ }
+
+ //Register the module
+ module = Py_InitModule3("Blender.Object.Pose", M_Pose_methods,
+ "The Blender Pose module");
+
+ //Add TYPEOBJECTS to the module
+ PyModule_AddObject(module, "Pose",
+ EXPP_incr_ret((PyObject *)&Pose_Type)); //*steals*
+ PyModule_AddObject(module, "PoseBone",
+ EXPP_incr_ret((PyObject *)&PoseBone_Type)); //*steals*
+
+ //Add CONSTANTS to the module
+ PyModule_AddObject(module, "ROT",
+ PyConstant_NewInt("ROT", POSE_ROT));
+ PyModule_AddObject(module, "LOC",
+ PyConstant_NewInt("LOC", POSE_LOC));
+ PyModule_AddObject(module, "SIZE",
+ PyConstant_NewInt("SIZE", POSE_SIZE));
+
+ return module;
+}
+//------------------VISIBLE PROTOTYPE IMPLEMENTATION-----------------------
+//------------------------------PyPose_FromPose (internal)
+//Returns a PyPose from a bPose - return PyNone if bPose is NULL
+PyObject *PyPose_FromPose(bPose *pose, char *name)
+{
+ BPy_Pose *py_pose = NULL;
+
+ if (pose){
+ py_pose = (BPy_Pose*)Pose_Type.tp_alloc(&Pose_Type, 0);
+ if (!py_pose)
+ goto RuntimeError;
+
+ py_pose->pose = pose;
+ BLI_strncpy(py_pose->name, name, 24);
+
+ //create armature.bones
+ py_pose->Bones = (BPy_PoseBonesDict*)PyPoseBonesDict_FromPyPose(py_pose);
+ if (!py_pose->Bones)
+ goto RuntimeError;
+
+ return (PyObject*)py_pose;
+ }else{
+ Py_RETURN_NONE;
+ }
+
+RuntimeError:
+ return EXPP_objError(PyExc_RuntimeError, "%s%s%s",
+ sPoseError, "PyPose_FromPose: ", "Internal Error Ocurred");
+}
+//------------------------------PyPoseBone_FromPosechannel (internal)
+//Returns a PyPoseBone from a bPoseChannel - return PyNone if bPoseChannel is NULL
+PyObject *PyPoseBone_FromPosechannel(bPoseChannel *pchan)
+{
+ BPy_PoseBone *py_posechannel = NULL;
+
+ if (pchan){
+ py_posechannel = (BPy_PoseBone*)PoseBone_Type.tp_alloc(&PoseBone_Type, 0);
+ if (!py_posechannel)
+ goto RuntimeError;
+ py_posechannel->posechannel = pchan;
+ return (PyObject*)py_posechannel;
+ }else{
+ Py_RETURN_NONE;
+ }
+
+RuntimeError:
+ return EXPP_objError(PyExc_RuntimeError, "%s%s%s",
+ sPoseBoneError, "PyPoseBone_FromPosechannel: ", "Internal Error Ocurred");
+}
+//------------------------------Object_FromPoseChannel (internal)
+//An ugly method for determining where the pchan chame from
+Object *Object_FromPoseChannel(bPoseChannel *curr_pchan)
+{
+ int success = 0;
+ Object *obj = NULL;
+ bPoseChannel *pchan = NULL;
+ for(obj = G.main->object.first; obj; obj = obj->id.next){
+ if (obj->pose){
+ for (pchan = obj->pose->chanbase.first; pchan; pchan = pchan->next){
+ if (curr_pchan == pchan){
+ success = 1;
+ break;
+ }
+ }
+ if (success)
+ break;
+ }
+ }
+ return obj;
+}
diff --git a/source/blender/python/api2_2x/Pose.h b/source/blender/python/api2_2x/Pose.h
new file mode 100644
index 00000000000..17a9f871ee3
--- /dev/null
+++ b/source/blender/python/api2_2x/Pose.h
@@ -0,0 +1,71 @@
+/*
+ * $Id:
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Joseph Gilbert
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_POSE_H
+#define EXPP_POSE_H
+
+#include <Python.h>
+#include "DNA_action_types.h"
+#include "DNA_object_types.h"
+
+//-------------------TYPE CHECKS---------------------------------
+#define BPy_Pose_Check(v) ((v)->ob_type == &Pose_Type)
+#define BPy_PoseBone_Check(v) ((v)->ob_type == &PoseBone_Type)
+#define BPy_PoseBonesDict_Check(v) ((v)->ob_type == &PoseBonesDict_Type)
+//-------------------TYPEOBJECT----------------------------------
+extern PyTypeObject Pose_Type;
+extern PyTypeObject PoseBone_Type;
+extern PyTypeObject PoseBonesDict_Type;
+//-------------------STRUCT DEFINITION----------------------------
+typedef struct {
+ PyObject_HEAD
+ PyObject *bonesMap;
+ ListBase *bones;
+} BPy_PoseBonesDict;
+
+typedef struct {
+ PyObject_HEAD
+ bPose *pose;
+ char name[24]; //because poses have not names :(
+ BPy_PoseBonesDict *Bones;
+} BPy_Pose;
+
+typedef struct {
+ PyObject_HEAD
+ bPoseChannel *posechannel;
+
+} BPy_PoseBone;
+
+//-------------------VISIBLE PROTOTYPES-------------------------
+PyObject *Pose_Init(void);
+PyObject *PyPose_FromPose(bPose *pose, char *name);
+PyObject *PyPoseBone_FromPosechannel(bPoseChannel *pchan);
+Object *Object_FromPoseChannel(bPoseChannel *curr_pchan);
+#endif
diff --git a/source/blender/python/api2_2x/Registry.c b/source/blender/python/api2_2x/Registry.c
new file mode 100644
index 00000000000..8fa77b20741
--- /dev/null
+++ b/source/blender/python/api2_2x/Registry.c
@@ -0,0 +1,245 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#include "Registry.h" /*This must come first */
+
+#include "BKE_global.h"
+#include "gen_utils.h"
+
+
+/* the Registry dictionary */
+PyObject *bpy_registryDict = NULL;
+
+/*****************************************************************************/
+/* Python API function prototypes for the Registry module. */
+/*****************************************************************************/
+static PyObject *M_Registry_Keys( PyObject * self );
+static PyObject *M_Registry_GetKey( PyObject * self, PyObject * args );
+static PyObject *M_Registry_SetKey( PyObject * self, PyObject * args );
+static PyObject *M_Registry_RemoveKey( PyObject * self, PyObject * args );
+
+/*****************************************************************************/
+/* The following string definitions are used for documentation strings. */
+/* In Python these will be written to the console when doing a */
+/* Blender.Registry.__doc__ */
+/*****************************************************************************/
+char M_Registry_doc[] =
+ "The Blender Registry module (persistent data cache)\n\n\
+ Use this module to store configuration data that a script can reload\n\
+ when it is executed again.\n";
+
+char M_Registry_Keys_doc[] =
+ "() - Get all keys in the Registry dictionary.\n\n\
+ Each key references another dict with saved data from a specific script.\n";
+
+char M_Registry_GetKey_doc[] =
+ "(name, disk = False) - Get an entry (a dict) from the Registry dictionary\n\
+ (name) - a string that references a specific script;\n\
+ (disk = False) - search on the user (if available) or default scripts config\n\
+data dir.\n";
+
+char M_Registry_SetKey_doc[] =
+ "(key, dict, disk = False) - Store an entry in the Registry dictionary.\n\
+ If an entry with the same 'key' already exists, it is substituted.\n\
+ (key) - the string to use as a key for the dict being saved.\n\
+ (dict) - a dictionary with the data to be stored.\n\
+ (disk = False) - also write data as a config file inside the user (if\n\
+available) or default scripts config data dir.\n";
+
+char M_Registry_RemoveKey_doc[] =
+ "(key, disk = False) - Remove the dict with key 'key' from the Registry.\n\
+ (key) - the name of the key to delete;\n\
+ (disk = False) - if True the respective config file is also deleted.\n";
+
+/*****************************************************************************/
+/* Python method structure definition for Blender.Registry module: */
+/*****************************************************************************/
+struct PyMethodDef M_Registry_methods[] = {
+ {"Keys", ( PyCFunction ) M_Registry_Keys, METH_VARARGS,
+ M_Registry_Keys_doc},
+ {"GetKey", M_Registry_GetKey, METH_VARARGS, M_Registry_GetKey_doc},
+ {"SetKey", M_Registry_SetKey, METH_VARARGS, M_Registry_SetKey_doc},
+ {"RemoveKey", M_Registry_RemoveKey, METH_VARARGS,
+ M_Registry_RemoveKey_doc},
+ {NULL, NULL, 0, NULL}
+};
+
+/*****************************************************************************/
+/* Function: M_Registry_Keys */
+/* Python equivalent: Blender.Registry.Keys */
+/*****************************************************************************/
+PyObject *M_Registry_Keys( PyObject * self )
+{
+ PyObject *pydict = NULL;
+
+ if( !bpy_registryDict )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "No Registry dictionary found!" );
+
+ pydict = PyDict_Keys( bpy_registryDict );
+
+ if( !pydict )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "Registry_Keys: couldn't get keys" );
+
+ return pydict;
+}
+
+/*****************************************************************************/
+/* Function: M_Registry_GetKey */
+/* Python equivalent: Blender.Registry.GetKey */
+/*****************************************************************************/
+static PyObject *M_Registry_GetKey( PyObject * self, PyObject * args )
+{
+ PyObject *pyentry = NULL;
+ PyObject *pydict = NULL;
+ int disk = 0;
+
+ if( !bpy_registryDict )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "No Registry dictionary found!" );
+
+ if( !PyArg_ParseTuple( args, "O!|i", &PyString_Type, &pyentry, &disk ) )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected a string and optionally a bool" );
+
+ pydict = PyDict_GetItem( bpy_registryDict, pyentry ); /* borrowed ... */
+
+ if (!pydict) {
+ if (disk > 0) {
+ /* try to get data from disk */
+ char buf[256];
+ PyOS_snprintf(buf, sizeof(buf),
+ "import Blender, BPyRegistry; BPyRegistry.LoadConfigData('%s')",
+ PyString_AsString(pyentry));
+ if (!PyRun_SimpleString(buf))
+ pydict = PyDict_GetItem(bpy_registryDict, pyentry);
+ else PyErr_Clear();
+ }
+
+ if (!pydict) /* no need to return a KeyError, since without doubt */
+ pydict = Py_None; /* Py_None means no key (all valid keys are dicts) */
+ }
+
+ return EXPP_incr_ret (pydict); /* ... so we incref it */
+}
+
+/*****************************************************************************/
+/* Function: M_Registry_SetKey */
+/* Python equivalent: Blender.Registry.SetKey */
+/*****************************************************************************/
+static PyObject *M_Registry_SetKey( PyObject * self, PyObject * args )
+{
+ PyObject *pystr = NULL;
+ PyObject *pydict = NULL;
+ int disk = 0;
+
+ if( !bpy_registryDict )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "No Registry dictionary found!" );
+
+ if( !PyArg_ParseTuple( args, "O!O!|i",
+ &PyString_Type, &pystr, &PyDict_Type,
+ &pydict, &disk ) )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected a string and a dictionary" );
+
+ if( PyDict_SetItem( bpy_registryDict, pystr, pydict ) ) /* 0 on success */
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "Registry_SetKey: couldn't update the Registry dict" );
+
+ if (disk) {
+ /* try to save data to disk */
+ char buf[256];
+ PyOS_snprintf(buf, sizeof(buf),
+ "import Blender, BPyRegistry; BPyRegistry.SaveConfigData('%s')",
+ PyString_AsString(pystr));
+ if (PyRun_SimpleString(buf) != 0) {
+ PyErr_Clear();
+ if (G.f & G_DEBUG)
+ fprintf(stderr, "\nCan't save script configuration data!\n");
+ }
+ }
+
+ Py_INCREF( Py_None );
+ return Py_None;
+}
+
+/*****************************************************************************/
+/* Function: M_Registry_RemoveKey */
+/* Python equivalent: Blender.Registry.RemoveKey */
+/*****************************************************************************/
+static PyObject *M_Registry_RemoveKey( PyObject * self, PyObject * args )
+{
+ PyObject *pystr = NULL;
+ int disk = 0;
+
+ if( !bpy_registryDict )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "No Registry dictionary found!" );
+
+ if( !PyArg_ParseTuple( args, "O!|i", &PyString_Type, &pystr, &disk ) )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected a string and optionally a bool" );
+
+ if( PyDict_DelItem( bpy_registryDict, pystr ) ) /* returns 0 on success */
+ return EXPP_ReturnPyObjError( PyExc_KeyError,
+ "no such key in the Registry" );
+ else if (disk) {
+ /* try to delete from disk too */
+ char buf[256];
+ PyOS_snprintf(buf, sizeof(buf),
+ "import Blender, BPyRegistry; BPyRegistry.RemoveConfigData('%s')",
+ PyString_AsString(pystr));
+ if (PyRun_SimpleString(buf) != 0) {
+ PyErr_Clear();
+ if (G.f & G_DEBUG)
+ fprintf(stderr, "\nCan't remove script configuration data file!\n");
+ }
+ }
+
+ Py_INCREF( Py_None );
+ return Py_None;
+}
+
+/*****************************************************************************/
+/* Function: Registry_Init */
+/*****************************************************************************/
+PyObject *Registry_Init( void )
+{
+ PyObject *submodule;
+
+ submodule = Py_InitModule3( "Blender.Registry", M_Registry_methods,
+ M_Registry_doc );
+
+ return submodule;
+}
diff --git a/source/blender/python/api2_2x/Registry.h b/source/blender/python/api2_2x/Registry.h
new file mode 100644
index 00000000000..4383d63e0bc
--- /dev/null
+++ b/source/blender/python/api2_2x/Registry.h
@@ -0,0 +1,50 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+/* This submodule was introduced as a way to preserve configured data in
+ * scripts. A very simple idea: the script writer saves this data in a dict
+ * and registers this dict in the "Registry" dict. This way we can discard
+ * the global interpreter dictionary after a script is executed, since the
+ * data meant to be kept was copied to the Registry elsewhere. The current
+ * implementation is naive: scripts can deliberately mess with data saved by
+ * other scripts. This is so new script versions can delete older entries, if
+ * they need to. XXX Or should we block this? */
+
+#ifndef EXPP_REGISTRY_H
+#define EXPP_REGISTRY_H
+
+#include <Python.h>
+
+extern PyObject *bpy_registryDict;
+PyObject *Registry_Init( void );
+
+#endif /* EXPP_REGISTRY_H */
diff --git a/source/blender/python/api2_2x/Scene.c b/source/blender/python/api2_2x/Scene.c
new file mode 100644
index 00000000000..62b3a44690b
--- /dev/null
+++ b/source/blender/python/api2_2x/Scene.c
@@ -0,0 +1,1839 @@
+/*
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano, Jacques Guignot, Joseph Gilbert,
+ * Campbell Barton, Ken Hughes
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+struct View3D;
+
+#include "Scene.h" /*This must come first */
+
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "MEM_guardedalloc.h" /* for MEM_callocN */
+#include "DNA_space_types.h" /* SPACE_VIEW3D, SPACE_SEQ */
+#include "DNA_screen_types.h"
+#include "DNA_userdef_types.h" /* U.userdefs */
+#include "DNA_object_types.h" /* SceneObSeq_new */
+#include "BKE_depsgraph.h"
+#include "BKE_library.h"
+#include "BKE_object.h"
+#include "BKE_scene.h"
+#include "BKE_font.h"
+#include "BKE_idprop.h"
+#include "BLI_blenlib.h" /* only for SceneObSeq_new */
+#include "BSE_drawview.h" /* for play_anim */
+#include "BSE_headerbuttons.h" /* for copy_scene */
+#include "BIF_drawscene.h" /* for set_scene */
+#include "BIF_space.h" /* for copy_view3d_lock() */
+#include "BIF_screen.h" /* curarea */
+#include "BDR_editobject.h" /* free_and_unlink_base() */
+#include "mydevice.h" /* for #define REDRAW */
+#include "DNA_view3d_types.h"
+/* python types */
+#include "Object.h"
+#include "Camera.h"
+/* only for SceneObSeq_new */
+#include "BKE_material.h"
+#include "BLI_arithb.h"
+#include "Armature.h"
+#include "Lamp.h"
+#include "Curve.h"
+#include "NMesh.h"
+#include "Mesh.h"
+#include "World.h"
+#include "Lattice.h"
+#include "Metaball.h"
+#include "IDProp.h"
+#include "Text3d.h"
+#include "Library.h"
+
+#include "gen_utils.h"
+#include "gen_library.h"
+#include "sceneRender.h"
+#include "sceneRadio.h"
+#include "sceneTimeLine.h"
+#include "sceneSequence.h"
+
+
+#include "BKE_utildefines.h" /* vec copy */
+#include "vector.h"
+
+PyObject *M_Object_Get( PyObject * self, PyObject * args ); /* from Object.c */
+
+/* checks for the scene being removed */
+#define SCENE_DEL_CHECK_PY(bpy_scene) if (!(bpy_scene->scene)) return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, "Scene has been removed" ) )
+#define SCENE_DEL_CHECK_INT(bpy_scene) if (!(bpy_scene->scene)) return ( EXPP_ReturnIntError( PyExc_RuntimeError, "Scene has been removed" ) )
+
+
+enum obj_consts {
+ EXPP_OBSEQ_NORMAL = 0,
+ EXPP_OBSEQ_SELECTED,
+ EXPP_OBSEQ_CONTEXT
+};
+
+
+/*-----------------------Python API function prototypes for the Scene module--*/
+static PyObject *M_Scene_New( PyObject * self, PyObject * args,
+ PyObject * keywords );
+static PyObject *M_Scene_Get( PyObject * self, PyObject * args );
+static PyObject *M_Scene_GetCurrent( PyObject * self );
+static PyObject *M_Scene_getCurrent_deprecated( PyObject * self );
+static PyObject *M_Scene_Unlink( PyObject * self, PyObject * arg );
+/*-----------------------Scene module doc strings-----------------------------*/
+static char M_Scene_doc[] = "The Blender.Scene submodule";
+static char M_Scene_New_doc[] =
+ "(name = 'Scene') - Create a new Scene called 'name' in Blender.";
+static char M_Scene_Get_doc[] =
+ "(name = None) - Return the scene called 'name'. If 'name' is None, return a list with all Scenes.";
+static char M_Scene_GetCurrent_doc[] =
+ "() - Return the currently active Scene in Blender.";
+static char M_Scene_Unlink_doc[] =
+ "(scene) - Unlink (delete) scene 'Scene' from Blender. (scene) is of type Blender scene.";
+/*----------------------Scene module method def----------------------------*/
+struct PyMethodDef M_Scene_methods[] = {
+ {"New", ( PyCFunction ) M_Scene_New, METH_VARARGS | METH_KEYWORDS,
+ M_Scene_New_doc},
+ {"Get", M_Scene_Get, METH_VARARGS, M_Scene_Get_doc},
+ {"get", M_Scene_Get, METH_VARARGS, M_Scene_Get_doc},
+ {"GetCurrent", ( PyCFunction ) M_Scene_GetCurrent,
+ METH_NOARGS, M_Scene_GetCurrent_doc},
+ {"getCurrent", ( PyCFunction ) M_Scene_getCurrent_deprecated,
+ METH_NOARGS, M_Scene_GetCurrent_doc},
+ {"Unlink", M_Scene_Unlink, METH_VARARGS, M_Scene_Unlink_doc},
+ {"unlink", M_Scene_Unlink, METH_VARARGS, M_Scene_Unlink_doc},
+ {NULL, NULL, 0, NULL}
+};
+/*-----------------------BPy_Scene method declarations--------------------*/
+static PyObject *Scene_getLayerList( BPy_Scene * self );
+static PyObject *Scene_oldsetLayers( BPy_Scene * self, PyObject * arg );
+static PyObject *Scene_copy( BPy_Scene * self, PyObject * arg );
+static PyObject *Scene_makeCurrent( BPy_Scene * self );
+static PyObject *Scene_update( BPy_Scene * self, PyObject * args );
+static PyObject *Scene_link( BPy_Scene * self, PyObject * args );
+static PyObject *Scene_unlink( BPy_Scene * self, PyObject * args );
+static PyObject *Scene_getChildren( BPy_Scene * self );
+static PyObject *Scene_getActiveObject(BPy_Scene *self);
+static PyObject *Scene_getCurrentCamera( BPy_Scene * self );
+static PyObject *Scene_setCurrentCamera( BPy_Scene * self, PyObject * args );
+static PyObject *Scene_getRenderingContext( BPy_Scene * self );
+static PyObject *Scene_getRadiosityContext( BPy_Scene * self );
+static PyObject *Scene_getScriptLinks( BPy_Scene * self, PyObject * value );
+static PyObject *Scene_getSequence( BPy_Scene * self );
+static PyObject *Scene_addScriptLink( BPy_Scene * self, PyObject * args );
+static PyObject *Scene_clearScriptLinks( BPy_Scene * self, PyObject * args );
+static PyObject *Scene_play( BPy_Scene * self, PyObject * args );
+static PyObject *Scene_getTimeLine( BPy_Scene * self );
+
+
+/*internal*/
+static int Scene_compare( BPy_Scene * a, BPy_Scene * b );
+static PyObject *Scene_repr( BPy_Scene * self );
+
+/*object seq*/
+static PyObject *SceneObSeq_CreatePyObject( BPy_Scene *self, Base *iter, int mode);
+
+/*-----------------------BPy_Scene method def------------------------------*/
+static PyMethodDef BPy_Scene_methods[] = {
+ /* name, method, flags, doc */
+ {"getName", ( PyCFunction ) GenericLib_getName, METH_NOARGS,
+ "() - Return Scene name"},
+ {"setName", ( PyCFunction ) GenericLib_setName_with_method, METH_VARARGS,
+ "(str) - Change Scene name"},
+ {"getLayers", ( PyCFunction ) Scene_getLayerList, METH_NOARGS,
+ "() - Return a list of layers int indices which are set in this scene "},
+ {"setLayers", ( PyCFunction ) Scene_oldsetLayers, METH_VARARGS,
+ "(layers) - Change layers which are set in this scene\n"
+ "(layers) - list of integers in the range [1, 20]."},
+ {"copy", ( PyCFunction ) Scene_copy, METH_VARARGS,
+ "(duplicate_objects = 1) - Return a copy of this scene\n"
+ "The optional argument duplicate_objects defines how the scene\n"
+ "children are duplicated:\n\t0: Link Objects\n\t1: Link Object Data"
+ "\n\t2: Full copy\n"},
+ {"makeCurrent", ( PyCFunction ) Scene_makeCurrent, METH_NOARGS,
+ "() - Make self the current scene"},
+ {"update", ( PyCFunction ) Scene_update, METH_VARARGS,
+ "(full = 0) - Update scene self.\n"
+ "full = 0: sort the base list of objects."
+ "full = 1: full update -- also regroups, does ipos, keys"},
+ {"link", ( PyCFunction ) Scene_link, METH_VARARGS,
+ "(obj) - Link Object obj to this scene"},
+ {"unlink", ( PyCFunction ) Scene_unlink, METH_VARARGS,
+ "(obj) - Unlink Object obj from this scene"},
+ {"getChildren", ( PyCFunction ) Scene_getChildren, METH_NOARGS,
+ "() - Return list of all objects linked to this scene"},
+ {"getActiveObject", (PyCFunction)Scene_getActiveObject, METH_NOARGS,
+ "() - Return this scene's active object"},
+ {"getCurrentCamera", ( PyCFunction ) Scene_getCurrentCamera,
+ METH_NOARGS,
+ "() - Return current active Camera"},
+ {"getScriptLinks", ( PyCFunction ) Scene_getScriptLinks, METH_O,
+ "(eventname) - Get a list of this scene's scriptlinks (Text names) "
+ "of the given type\n"
+ "(eventname) - string: FrameChanged, OnLoad, OnSave, Redraw or Render."},
+ {"addScriptLink", ( PyCFunction ) Scene_addScriptLink, METH_VARARGS,
+ "(text, evt) - Add a new scene scriptlink.\n"
+ "(text) - string: an existing Blender Text name;\n"
+ "(evt) string: FrameChanged, OnLoad, OnSave, Redraw or Render."},
+ {"clearScriptLinks", ( PyCFunction ) Scene_clearScriptLinks,
+ METH_VARARGS,
+ "() - Delete all scriptlinks from this scene.\n"
+ "([s1<,s2,s3...>]) - Delete specified scriptlinks from this scene."},
+ {"setCurrentCamera", ( PyCFunction ) Scene_setCurrentCamera,
+ METH_VARARGS,
+ "() - Set the currently active Camera"},
+ {"getRenderingContext", ( PyCFunction ) Scene_getRenderingContext,
+ METH_NOARGS,
+ "() - Get the rendering context for the scene and return it as a BPy_RenderData"},
+ {"getRadiosityContext", ( PyCFunction ) Scene_getRadiosityContext,
+ METH_NOARGS,
+ "() - Get the radiosity context for this scene."},
+ {"play", ( PyCFunction ) Scene_play, METH_VARARGS,
+ "(mode = 0, win = VIEW3D) - Play realtime animation in Blender"
+ " (not rendered).\n"
+ "(mode) - int:\n"
+ "\t0 - keep playing in biggest given 'win';\n"
+ "\t1 - keep playing in all 'win', VIEW3D and SEQ windows;\n"
+ "\t2 - play once in biggest given 'win';\n"
+ "\t3 - play once in all 'win', VIEW3D and SEQ windows.\n"
+ "(win) - int: see Blender.Window.Types. Only these are meaningful here:"
+ "VIEW3D, SEQ, IPO, ACTION, NLA, SOUND. But others are also accepted, "
+ "since they can be used just as an interruptible timer. If 'win' is not"
+ "available or invalid, VIEW3D is tried, then any bigger window."
+ "Returns 0 for normal exit or 1 when canceled by user input."},
+ {"getTimeLine", ( PyCFunction ) Scene_getTimeLine, METH_NOARGS,
+ "() - Get time line of this Scene"},
+ {NULL, NULL, 0, NULL}
+};
+
+
+/*****************************************************************************/
+/* Python BPy_Scene getsetattr funcs: */
+/*****************************************************************************/
+static PyObject *Scene_getLayerMask( BPy_Scene * self )
+{
+ SCENE_DEL_CHECK_PY(self);
+ return PyInt_FromLong( self->scene->lay & ((1<<20)-1) );
+}
+
+static int Scene_setLayerMask( BPy_Scene * self, PyObject * value )
+{
+ int laymask = 0;
+
+ SCENE_DEL_CHECK_INT(self);
+
+ if (!PyInt_Check(value)) {
+ return EXPP_ReturnIntError( PyExc_AttributeError,
+ "expected an integer (bitmask) as argument" );
+ }
+
+ laymask = PyInt_AsLong(value);
+
+ if (laymask <= 0 || laymask > (1<<20) - 1) /* binary: 1111 1111 1111 1111 1111 */
+ return EXPP_ReturnIntError( PyExc_AttributeError,
+ "bitmask must have from 1 up to 20 bits set");
+
+ self->scene->lay = laymask;
+ /* if this is the current scene then apply the scene layers value
+ * to the view layers value: */
+ if (G.vd && (self->scene == G.scene)) {
+ int val, bit = 0;
+ G.vd->lay = laymask;
+
+ while( bit < 20 ) {
+ val = 1 << bit;
+ if( laymask & val ) {
+ G.vd->layact = val;
+ break;
+ }
+ bit++;
+ }
+ }
+
+ return 0;
+}
+
+static PyObject *Scene_getLayerList( BPy_Scene * self )
+{
+ PyObject *laylist, *item;
+ int layers, bit = 0, val = 0;
+
+ SCENE_DEL_CHECK_PY(self);
+
+ laylist = PyList_New( 0 );
+
+ if( !laylist )
+ return ( EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create pylist!" ) );
+
+ layers = self->scene->lay;
+
+ while( bit < 20 ) {
+ val = 1 << bit;
+ if( layers & val ) {
+ item = Py_BuildValue( "i", bit + 1 );
+ PyList_Append( laylist, item );
+ Py_DECREF( item );
+ }
+ bit++;
+ }
+ return laylist;
+}
+
+static int Scene_setLayerList( BPy_Scene * self, PyObject * value )
+{
+ PyObject *item = NULL;
+ int layers = 0, val, i, len_list;
+
+ SCENE_DEL_CHECK_INT(self);
+
+ if( !PySequence_Check( value ) )
+ return ( EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a list of integers in the range [1, 20]" ) );
+
+ len_list = PySequence_Size(value);
+
+ if (len_list == 0)
+ return ( EXPP_ReturnIntError( PyExc_AttributeError,
+ "list can't be empty, at least one layer must be set" ) );
+
+ for( i = 0; i < len_list; i++ ) {
+ item = PySequence_GetItem( value, i );
+
+ if( !PyInt_Check( item ) ) {
+ Py_DECREF( item );
+ return EXPP_ReturnIntError
+ ( PyExc_AttributeError,
+ "list must contain only integer numbers" );
+ }
+
+ val = ( int ) PyInt_AsLong( item );
+ if( val < 1 || val > 20 )
+ return EXPP_ReturnIntError
+ ( PyExc_AttributeError,
+ "layer values must be in the range [1, 20]" );
+
+ layers |= 1 << ( val - 1 );
+ }
+ self->scene->lay = layers;
+
+ if (G.vd && (self->scene == G.scene)) {
+ int bit = 0;
+ G.vd->lay = layers;
+
+ while( bit < 20 ) {
+ val = 1 << bit;
+ if( layers & val ) {
+ G.vd->layact = val;
+ break;
+ }
+ bit++;
+ }
+ }
+
+ return 0;
+}
+
+static PyObject *Scene_getWorld( BPy_Scene * self )
+{
+ SCENE_DEL_CHECK_PY(self);
+
+ if (!self->scene->world)
+ Py_RETURN_NONE;
+ return World_CreatePyObject(self->scene->world);
+}
+
+static int Scene_setWorld( BPy_Scene * self, PyObject * value )
+{
+ SCENE_DEL_CHECK_INT(self);
+ return GenericLib_assignData(value, (void **) &self->scene->world, NULL, 1, ID_WO, 0);
+}
+
+/* accessed from scn.objects */
+static PyObject *Scene_getObjects( BPy_Scene *self)
+{
+ SCENE_DEL_CHECK_PY(self);
+ return SceneObSeq_CreatePyObject(self, NULL, 0);
+}
+
+static PyObject *Scene_getCursor( BPy_Scene * self )
+{
+ SCENE_DEL_CHECK_PY(self);
+ return newVectorObject( self->scene->cursor, 3, Py_WRAP );
+}
+
+static int Scene_setCursor( BPy_Scene * self, PyObject * value )
+{
+ VectorObject *bpy_vec;
+ SCENE_DEL_CHECK_INT(self);
+ if (!VectorObject_Check(value))
+ return ( EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a vector" ) );
+
+ bpy_vec = (VectorObject *)value;
+
+ if (bpy_vec->size != 3)
+ return ( EXPP_ReturnIntError( PyExc_ValueError,
+ "can only assign a 3D vector" ) );
+
+ VECCOPY(self->scene->cursor, bpy_vec->vec);
+ return 0;
+}
+
+/*****************************************************************************/
+/* Python attributes get/set structure: */
+/*****************************************************************************/
+static PyGetSetDef BPy_Scene_getseters[] = {
+ GENERIC_LIB_GETSETATTR,
+ {"Layers",
+ (getter)Scene_getLayerMask, (setter)Scene_setLayerMask,
+ "Scene layer bitmask",
+ NULL},
+ {"layers",
+ (getter)Scene_getLayerList, (setter)Scene_setLayerList,
+ "Scene layer list",
+ NULL},
+ {"world",
+ (getter)Scene_getWorld, (setter)Scene_setWorld,
+ "Scene layer bitmask",
+ NULL},
+ {"cursor",
+ (getter)Scene_getCursor, (setter)Scene_setCursor,
+ "Scene layer bitmask",
+ NULL},
+ {"timeline",
+ (getter)Scene_getTimeLine, (setter)NULL,
+ "Scenes timeline (read only)",
+ NULL},
+ {"render",
+ (getter)Scene_getRenderingContext, (setter)NULL,
+ "Scenes rendering context (read only)",
+ NULL},
+ {"radiosity",
+ (getter)Scene_getRadiosityContext, (setter)NULL,
+ "Scenes radiosity context (read only)",
+ NULL},
+ {"sequence",
+ (getter)Scene_getSequence, (setter)NULL,
+ "Scene sequencer data (read only)",
+ NULL},
+
+ {"objects",
+ (getter)Scene_getObjects, (setter)NULL,
+ "Scene object iterator",
+ NULL},
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+
+
+/*-----------------------BPy_Scene method def------------------------------*/
+PyTypeObject Scene_Type = {
+ PyObject_HEAD_INIT( NULL )
+ 0, /* ob_size */
+ "Scene", /* tp_name */
+ sizeof( BPy_Scene ), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ /* methods */
+ NULL, /* tp_dealloc */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ ( cmpfunc ) Scene_compare, /* tp_compare */
+ ( reprfunc ) Scene_repr, /* tp_repr */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ ( hashfunc ) GenericLib_hash, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_Scene_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ BPy_Scene_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+/*-----------------------Scene module Init())-----------------------------*/
+PyObject *Scene_Init( void )
+{
+
+ PyObject *submodule;
+ PyObject *dict;
+
+ if( PyType_Ready( &Scene_Type ) < 0 )
+ return NULL;
+ if( PyType_Ready( &SceneObSeq_Type ) < 0 )
+ return NULL;
+
+ submodule = Py_InitModule3( "Blender.Scene", M_Scene_methods, M_Scene_doc );
+
+ dict = PyModule_GetDict( submodule );
+ PyDict_SetItemString( dict, "Render", Render_Init( ) );
+ PyDict_SetItemString( dict, "Radio", Radio_Init( ) );
+ PyDict_SetItemString( dict, "Sequence", Sequence_Init( ) );
+
+ return submodule;
+}
+
+/*-----------------------compare----------------------------------------*/
+static int Scene_compare( BPy_Scene * a, BPy_Scene * b )
+{
+ return ( a->scene == b->scene ) ? 0 : -1;
+}
+
+/*----------------------repr--------------------------------------------*/
+static PyObject *Scene_repr( BPy_Scene * self )
+{
+ if( !(self->scene) )
+ return PyString_FromString( "[Scene - Removed]");
+ else
+ return PyString_FromFormat( "[Scene \"%s\"]",
+ self->scene->id.name + 2 );
+}
+
+/*-----------------------CreatePyObject---------------------------------*/
+PyObject *Scene_CreatePyObject( Scene * scene )
+{
+ BPy_Scene *pyscene;
+
+ pyscene = ( BPy_Scene * ) PyObject_NEW( BPy_Scene, &Scene_Type );
+
+ if( !pyscene )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create BPy_Scene object" );
+
+ pyscene->scene = scene;
+
+ return ( PyObject * ) pyscene;
+}
+
+/*-----------------------FromPyObject-----------------------------------*/
+Scene *Scene_FromPyObject( PyObject * pyobj )
+{
+ return ( ( BPy_Scene * ) pyobj )->scene;
+}
+
+/*-----------------------Scene module function defintions---------------*/
+/*-----------------------Scene.New()------------------------------------*/
+static PyObject *M_Scene_New( PyObject * self, PyObject * args,
+ PyObject * kword )
+{
+ char *name = "Scene";
+ char *kw[] = { "name", NULL };
+ PyObject *pyscene; /* for the Scene object wrapper in Python */
+ Scene *blscene; /* for the actual Scene we create in Blender */
+
+ if( !PyArg_ParseTupleAndKeywords( args, kword, "|s", kw, &name ) )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected a string or an empty argument list" ) );
+
+ blscene = add_scene( name ); /* first create the Scene in Blender */
+
+ if( blscene ) {
+ /* normally, for most objects, we set the user count to zero here.
+ * Scene is different than most objs since it is the container
+ * for all the others. Since add_scene() has already set
+ * the user count to one, we leave it alone.
+ */
+
+ /* now create the wrapper obj in Python */
+ pyscene = Scene_CreatePyObject( blscene );
+ } else
+ return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't create Scene obj in Blender" ) );
+
+ if( pyscene == NULL )
+ return ( EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create Scene PyObject" ) );
+
+ return pyscene;
+}
+
+/*-----------------------Scene.Get()------------------------------------*/
+static PyObject *M_Scene_Get( PyObject * self, PyObject * args )
+{
+ char *name = NULL;
+ Scene *scene_iter;
+
+ if( !PyArg_ParseTuple( args, "|s", &name ) )
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument (or nothing)" ) );
+
+ scene_iter = G.main->scene.first;
+
+ if( name ) { /* (name) - Search scene by name */
+
+ PyObject *wanted_scene = NULL;
+
+ while( ( scene_iter ) && ( wanted_scene == NULL ) ) {
+
+ if( strcmp( name, scene_iter->id.name + 2 ) == 0 )
+ wanted_scene =
+ Scene_CreatePyObject( scene_iter );
+
+ scene_iter = scene_iter->id.next;
+ }
+
+ if( wanted_scene == NULL ) { /* Requested scene doesn't exist */
+ char error_msg[64];
+ PyOS_snprintf( error_msg, sizeof( error_msg ),
+ "Scene \"%s\" not found", name );
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_NameError, error_msg ) );
+ }
+
+ return wanted_scene;
+ }
+
+ else { /* () - return a list with wrappers for all scenes in Blender */
+ int index = 0;
+ PyObject *sce_pylist, *pyobj;
+
+ sce_pylist = PyList_New( BLI_countlist( &( G.main->scene ) ) );
+
+ if( sce_pylist == NULL )
+ return ( EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create PyList" ) );
+
+ while( scene_iter ) {
+ pyobj = Scene_CreatePyObject( scene_iter );
+
+ if( !pyobj ) {
+ Py_DECREF(sce_pylist);
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_MemoryError,
+ "couldn't create PyString" ) );
+ }
+ PyList_SET_ITEM( sce_pylist, index, pyobj );
+
+ scene_iter = scene_iter->id.next;
+ index++;
+ }
+
+ return sce_pylist;
+ }
+}
+
+/*-----------------------Scene.GetCurrent()------------------------------*/
+static PyObject *M_Scene_GetCurrent( PyObject * self )
+{
+ return Scene_CreatePyObject( ( Scene * ) G.scene );
+}
+
+static PyObject *M_Scene_getCurrent_deprecated( PyObject * self )
+{
+ static char warning = 1;
+ if( warning ) {
+ printf("Blender.Scene.getCurrent() is deprecated,\n\tuse Blender.Scene.GetCurrent() instead.\n");
+ --warning;
+ }
+
+ return Scene_CreatePyObject( ( Scene * ) G.scene );
+}
+
+
+/*-----------------------Scene.Unlink()----------------------------------*/
+static PyObject *M_Scene_Unlink( PyObject * self, PyObject * args )
+{
+ PyObject *pyobj;
+ BPy_Scene *pyscn;
+ Scene *scene;
+
+ if( !PyArg_ParseTuple( args, "O!", &Scene_Type, &pyobj ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected Scene PyType object" );
+
+ pyscn = (BPy_Scene *)pyobj;
+ scene = pyscn->scene;
+
+ SCENE_DEL_CHECK_PY(pyscn);
+
+ if( scene == G.scene )
+ return EXPP_ReturnPyObjError( PyExc_SystemError,
+ "current Scene cannot be removed!" );
+
+ free_libblock( &G.main->scene, scene );
+
+ pyscn->scene= NULL;
+ Py_RETURN_NONE;
+}
+
+/* DEPRECATE ME !!! */
+/*-----------------------BPy_Scene function defintions-------------------*/
+
+/*-----------------------Scene.setLayers()---------------------------------*/
+static PyObject *Scene_oldsetLayers( BPy_Scene * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Scene_setLayerList );
+}
+/* END DEPRECATE CODE */
+
+
+/*-----------------------Scene.copy()------------------------------------*/
+static PyObject *Scene_copy( BPy_Scene * self, PyObject * args )
+{
+ short dup_objs = 1;
+ Scene *scene = self->scene;
+
+ SCENE_DEL_CHECK_PY(self);
+
+ if( !PyArg_ParseTuple( args, "|h", &dup_objs ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected int in [0,2] or nothing as argument" );
+
+ return Scene_CreatePyObject( copy_scene( scene, dup_objs ) );
+}
+
+/*-----------------------Scene.makeCurrent()-----------------------------*/
+static PyObject *Scene_makeCurrent( BPy_Scene * self )
+{
+ Scene *scene = self->scene;
+#if 0 /* add back in when bpy becomes "official" */
+ static char warning = 1;
+ if( warning ) {
+ printf("scene.makeCurrent() deprecated!\n\tuse bpy.scenes.active = scene instead\n");
+ --warning;
+ }
+#endif
+
+ SCENE_DEL_CHECK_PY(self);
+
+ if( scene && scene != G.scene) {
+ set_scene( scene );
+ scene_update_for_newframe(scene, scene->lay);
+ }
+
+ Py_RETURN_NONE;
+}
+
+/*-----------------------Scene.update()----------------------------------*/
+static PyObject *Scene_update( BPy_Scene * self, PyObject * args )
+{
+ Scene *scene = self->scene;
+ int full = 0;
+
+ SCENE_DEL_CHECK_PY(self);
+ if( !PyArg_ParseTuple( args, "|i", &full ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected nothing or int (0 or 1) argument" );
+
+/* Under certain circunstances, DAG_scene_sort *here* can crash Blender.
+ * A "RuntimeError: max recursion limit" happens when a scriptlink
+ * on frame change has scene.update(1).
+ * Investigate better how to avoid this. */
+ if( !full )
+ DAG_scene_sort( scene );
+
+ else if( full == 1 )
+ set_scene_bg( scene );
+
+ else
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "in method scene.update(full), full should be:\n"
+ "0: to only sort scene elements (old behavior); or\n"
+ "1: for a full update (regroups, does ipos, keys, etc.)" );
+
+ Py_RETURN_NONE;
+}
+
+/*-----------------------Scene.link()------------------------------------*/
+static PyObject *Scene_link( BPy_Scene * self, PyObject * args )
+{
+ Scene *scene = self->scene;
+ BPy_Object *bpy_obj;
+ Object *object = NULL;
+ static char warning = 1;
+
+ if( warning ) {
+ printf("scene.link(ob) deprecated!\n\tuse scene.objects.link(ob) instead\n");
+ --warning;
+ }
+
+ SCENE_DEL_CHECK_PY(self);
+
+ if( !PyArg_ParseTuple( args, "O!", &Object_Type, &bpy_obj ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected Object argument" );
+
+
+ /*return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "Could not create data on demand for this object type!" );*/
+
+ object = bpy_obj->object;
+
+ /* Object.c's EXPP_add_obdata does not support these objects */
+ if (!object->data && (object->type == OB_SURF || object->type == OB_FONT || object->type == OB_WAVE )) {
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "Object has no data and new data cant be automaticaly created for Surf, Text or Wave type objects!" );
+ } else {
+ /* Ok, all is fine, let's try to link it */
+ Base *base;
+
+ /* We need to link the object to a 'Base', then link this base
+ * to the scene. See DNA_scene_types.h ... */
+
+ /* First, check if the object isn't already in the scene */
+ base = object_in_scene( object, scene );
+ /* if base is not NULL ... */
+ if( base ) /* ... the object is already in one of the Scene Bases */
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "object already in scene!" );
+
+ /* not linked, go get mem for a new base object */
+
+ base = MEM_callocN( sizeof( Base ), "pynewbase" );
+
+ if( !base )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't allocate new Base for object" );
+
+ /* if the object has not yet been linked to object data, then
+ * set the real type before we try creating data */
+
+ if( bpy_obj->realtype != OB_EMPTY ) {
+ object->type = bpy_obj->realtype;
+ bpy_obj->realtype = OB_EMPTY;
+ }
+
+ /* check if this object has obdata, case not, try to create it */
+
+ if( !object->data && ( object->type != OB_EMPTY ) )
+ EXPP_add_obdata( object ); /* returns -1 on error, defined in Object.c */
+
+ base->object = object; /* link object to the new base */
+ base->lay = object->lay;
+ base->flag = object->flag;
+
+ object->id.us += 1; /* incref the object user count in Blender */
+
+ BLI_addhead( &scene->base, base ); /* finally, link new base to scene */
+ }
+
+ Py_RETURN_NONE;
+}
+
+/*-----------------------Scene.unlink()----------------------------------*/
+static PyObject *Scene_unlink( BPy_Scene * self, PyObject * args )
+{
+ BPy_Object *bpy_obj = NULL;
+ Scene *scene = self->scene;
+ Base *base;
+ static char warning = 1;
+
+ if( warning ) {
+ printf("scene.unlink(ob) deprecated!\n\tuse scene.objects.unlink(ob) instead\n");
+ --warning;
+ }
+
+ SCENE_DEL_CHECK_PY(self);
+
+ if( !PyArg_ParseTuple( args, "O!", &Object_Type, &bpy_obj ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected Object as argument" );
+
+ /* is the object really in the scene? */
+ base = object_in_scene( bpy_obj->object, scene );
+
+ if( base ) { /* if it is, remove it */
+ if (scene->basact==base)
+ scene->basact= NULL; /* in case the object was selected */
+
+ free_and_unlink_base_from_scene( scene, base );
+ Py_RETURN_TRUE;
+ }
+ else
+ Py_RETURN_FALSE;
+}
+
+/*-----------------------Scene.getChildren()-----------------------------*/
+static PyObject *Scene_getChildren( BPy_Scene * self )
+{
+ Scene *scene = self->scene;
+ PyObject *pylist;
+ PyObject *bpy_obj;
+ Object *object;
+ Base *base;
+ static char warning = 1;
+
+ if( warning ) {
+ printf("scene.getChildren() deprecated!\n\tuse scene.objects instead\n");
+ --warning;
+ }
+
+ SCENE_DEL_CHECK_PY(self);
+
+ pylist = PyList_New( 0 );
+
+ base = scene->base.first;
+
+ while( base ) {
+ object = base->object;
+
+ bpy_obj = Object_CreatePyObject( object );
+
+ if( !bpy_obj ) {
+ Py_DECREF(pylist);
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't create new object wrapper" );
+ }
+ PyList_Append( pylist, bpy_obj );
+ Py_DECREF( bpy_obj ); /* PyList_Append incref'ed it */
+
+ base = base->next;
+ }
+
+ return pylist;
+}
+
+/*-----------------------Scene.getActiveObject()------------------------*/
+static PyObject *Scene_getActiveObject(BPy_Scene *self)
+{
+ Scene *scene = self->scene;
+ PyObject *pyob;
+ Object *ob;
+ static char warning = 1;
+
+ if( warning ) {
+ printf("scene.getActiveObject() deprecated!\n\tuse scene.objects.active instead\n");
+ --warning;
+ }
+
+ SCENE_DEL_CHECK_PY(self);
+
+ ob = ((scene->basact) ? (scene->basact->object) : 0);
+
+ if (ob) {
+ pyob = Object_CreatePyObject( ob );
+
+ if (!pyob)
+ return EXPP_ReturnPyObjError(PyExc_MemoryError,
+ "couldn't create new object wrapper!");
+
+ return pyob;
+ }
+
+ Py_RETURN_NONE; /* no active object */
+}
+
+/*-----------------------Scene.getCurrentCamera()------------------------*/
+static PyObject *Scene_getCurrentCamera( BPy_Scene * self )
+{
+ static char warning = 1;
+
+ if( warning ) {
+ printf("scene.getCurrentCamera() deprecated!\n\tuse scene.objects.camera instead\n");
+ --warning;
+ }
+
+ SCENE_DEL_CHECK_PY(self);
+ /* None is ok */
+ return Object_CreatePyObject( self->scene->camera );
+}
+
+/*-----------------------Scene.setCurrentCamera()------------------------*/
+static PyObject *Scene_setCurrentCamera( BPy_Scene * self, PyObject * args )
+{
+ Object *object;
+ BPy_Object *cam_obj;
+ Scene *scene = self->scene;
+ static char warning = 1;
+
+ if( warning ) {
+ printf("scene.setCurrentCamera(ob) deprecated!\n\tSet scene.objects.camera = ob instead\n");
+ --warning;
+ }
+
+ SCENE_DEL_CHECK_PY(self);
+
+ if( !PyArg_ParseTuple( args, "O!", &Object_Type, &cam_obj ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected Camera Object as argument" );
+
+ object = cam_obj->object;
+ if( object->type != OB_CAMERA )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "expected Camera Object as argument" );
+
+ scene->camera = object; /* set the current Camera */
+
+ /* if this is the current scene, update its window now */
+ if( !G.background && scene == G.scene ) /* Traced a crash to redrawing while in background mode -Campbell */
+ copy_view3d_lock( REDRAW );
+
+/* XXX copy_view3d_lock(REDRAW) prints "bad call to addqueue: 0 (18, 1)".
+ * The same happens in bpython. */
+
+ Py_RETURN_NONE;
+}
+
+/*-----------------------Scene.getRenderingContext()---------------------*/
+static PyObject *Scene_getRenderingContext( BPy_Scene * self )
+{
+ SCENE_DEL_CHECK_PY(self);
+ return RenderData_CreatePyObject( self->scene );
+}
+
+static PyObject *Scene_getRadiosityContext( BPy_Scene * self )
+{
+ SCENE_DEL_CHECK_PY(self);
+ return Radio_CreatePyObject( self->scene );
+}
+
+static PyObject *Scene_getSequence( BPy_Scene * self )
+{
+ SCENE_DEL_CHECK_PY(self);
+ if (self->scene->ed) /* we should create this if its not there :/ */
+ return SceneSeq_CreatePyObject( self->scene, NULL );
+ else
+ Py_RETURN_NONE;
+}
+
+/* scene.addScriptLink */
+static PyObject *Scene_addScriptLink( BPy_Scene * self, PyObject * args )
+{
+ Scene *scene = self->scene;
+ ScriptLink *slink = NULL;
+
+ SCENE_DEL_CHECK_PY(self);
+
+ slink = &( scene )->scriptlink;
+
+ return EXPP_addScriptLink( slink, args, 1 );
+}
+
+/* scene.clearScriptLinks */
+static PyObject *Scene_clearScriptLinks( BPy_Scene * self, PyObject * args )
+{
+ Scene *scene = self->scene;
+ ScriptLink *slink = NULL;
+
+ SCENE_DEL_CHECK_PY(self);
+
+ slink = &( scene )->scriptlink;
+
+ return EXPP_clearScriptLinks( slink, args );
+}
+
+/* scene.getScriptLinks */
+static PyObject *Scene_getScriptLinks( BPy_Scene * self, PyObject * value )
+{
+ Scene *scene = self->scene;
+ ScriptLink *slink = NULL;
+ PyObject *ret = NULL;
+
+ SCENE_DEL_CHECK_PY(self);
+
+ slink = &( scene )->scriptlink;
+
+ ret = EXPP_getScriptLinks( slink, value, 1 );
+
+ if( ret )
+ return ret;
+ else
+ return NULL;
+}
+
+static PyObject *Scene_play( BPy_Scene * self, PyObject * args )
+{
+ int mode = 0, win = SPACE_VIEW3D;
+ PyObject *ret = NULL;
+ ScrArea *sa = NULL, *oldsa = curarea;
+
+ SCENE_DEL_CHECK_PY(self);
+
+ if( !PyArg_ParseTuple( args, "|ii", &mode, &win ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected nothing, or or two ints as arguments." );
+
+ if( mode < 0 || mode > 3 )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "mode should be in range [0, 3]." );
+
+ switch ( win ) {
+ case SPACE_VIEW3D:
+ case SPACE_SEQ:
+ case SPACE_IPO:
+ case SPACE_ACTION:
+ case SPACE_NLA:
+ case SPACE_SOUND:
+ case SPACE_BUTS: /* from here they don't 'play', but ... */
+ case SPACE_TEXT: /* ... might be used as a timer. */
+ case SPACE_SCRIPT:
+ case SPACE_OOPS:
+ case SPACE_IMAGE:
+ case SPACE_IMASEL:
+ case SPACE_INFO:
+ case SPACE_FILE:
+ break;
+ default:
+ win = SPACE_VIEW3D;
+ }
+
+ /* we have to move to a proper win */
+ sa = find_biggest_area_of_type( win );
+ if( !sa && win != SPACE_VIEW3D )
+ sa = find_biggest_area_of_type( SPACE_VIEW3D );
+
+ if( !sa )
+ sa = find_biggest_area( );
+
+ if( sa )
+ areawinset( sa->win );
+
+ /* play_anim returns 0 for normal exit or 1 if user canceled it */
+ ret = PyInt_FromLong( (long)play_anim( mode ) );
+
+ if( sa )
+ areawinset( oldsa->win );
+
+ return ret;
+}
+
+static PyObject *Scene_getTimeLine( BPy_Scene *self )
+{
+ BPy_TimeLine *tm;
+
+ SCENE_DEL_CHECK_PY(self);
+
+ tm= (BPy_TimeLine *) PyObject_NEW (BPy_TimeLine, &TimeLine_Type);
+ if (!tm)
+ return EXPP_ReturnPyObjError (PyExc_MemoryError,
+ "couldn't create BPy_TimeLine object");
+ tm->marker_list= &(self->scene->markers);
+ tm->sfra= (int) self->scene->r.sfra;
+ tm->efra= (int) self->scene->r.efra;
+
+ return (PyObject *)tm;
+}
+
+/************************************************************************
+ *
+ * Object Sequence
+ *
+ ************************************************************************/
+/*
+ * create a thin wrapper for the scenes objects
+ */
+
+/* accessed from scn.objects.selected or scn.objects.context */
+static PyObject *SceneObSeq_getObjects( BPy_SceneObSeq *self, void *mode)
+{
+ SCENE_DEL_CHECK_PY(self->bpyscene);
+ return SceneObSeq_CreatePyObject(self->bpyscene, NULL, (int)((long)mode));
+}
+
+int SceneObSeq_setObjects( BPy_SceneObSeq *self, PyObject *value, void *_mode_)
+{
+ /*
+ ONLY SUPPORTS scn.objects.selected and scn.objects.context
+ cannot assign to scn.objects yet!!!
+ */
+ PyObject *item;
+ Scene *scene= self->bpyscene->scene;
+ Object *blen_ob;
+ Base *base;
+ int size, mode = (int)_mode_;
+
+ SCENE_DEL_CHECK_INT(self->bpyscene);
+
+ /* scn.objects.selected = scn.objects - shortcut to select all */
+ if (BPy_SceneObSeq_Check(value)) {
+ BPy_SceneObSeq *bpy_sceneseq = (BPy_SceneObSeq *)value;
+ if (self->bpyscene->scene != bpy_sceneseq->bpyscene->scene)
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "Cannot assign a SceneObSeq type from another scene" );
+ if (bpy_sceneseq->mode != EXPP_OBSEQ_NORMAL)
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "Can only assign scn.objects to scn.objects.context or scn.objects.selected" );
+
+ for (base= scene->base.first; base; base= base->next) {
+ base->flag |= SELECT;
+ base->object->flag |= SELECT;
+
+ if (mode==EXPP_OBSEQ_CONTEXT && G.vd) {
+ base->object->lay= base->lay= G.vd->lay;
+ }
+ }
+ return 0;
+ }
+
+ if (!PySequence_Check(value))
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "Error, must assign a sequence of objects to scn.objects.selected" );
+
+ /* for context and selected, just deselect, dont remove */
+ for (base= scene->base.first; base; base= base->next) {
+ base->flag &= ~SELECT;
+ base->object->flag &= ~SELECT;
+ }
+
+ size = PySequence_Length(value);
+ while (size) {
+ size--;
+ item = PySequence_GetItem(value, size);
+ if ( PyObject_TypeCheck(item, &Object_Type) ) {
+ blen_ob= ((BPy_Object *)item)->object;
+ base = object_in_scene( blen_ob, scene );
+ if (base) {
+ blen_ob->flag |= SELECT;
+ base->flag |= SELECT;
+ if (mode==EXPP_OBSEQ_CONTEXT && G.vd) {
+ blen_ob->restrictflag &= ~OB_RESTRICT_VIEW;
+ blen_ob->lay= base->lay= G.vd->lay;
+ }
+ }
+ }
+ Py_DECREF(item);
+ }
+ return 0;
+}
+
+
+static PyObject *SceneObSeq_CreatePyObject( BPy_Scene *self, Base *iter, int mode )
+{
+ BPy_SceneObSeq *seq = PyObject_NEW( BPy_SceneObSeq, &SceneObSeq_Type);
+ seq->bpyscene = self; Py_INCREF(self);
+ seq->iter = iter;
+ seq->mode = mode;
+ return (PyObject *)seq;
+}
+
+static int SceneObSeq_len( BPy_SceneObSeq * self )
+{
+ Scene *scene= self->bpyscene->scene;
+ SCENE_DEL_CHECK_INT(self->bpyscene);
+
+ if (self->mode == EXPP_OBSEQ_NORMAL)
+ return BLI_countlist( &( scene->base ) );
+ else if (self->mode == EXPP_OBSEQ_SELECTED) {
+ int len=0;
+ Base *base;
+ for (base= scene->base.first; base; base= base->next) {
+ if (base->flag & SELECT) {
+ len++;
+ }
+ }
+ return len;
+ } else if (self->mode == EXPP_OBSEQ_CONTEXT) {
+ int len=0;
+ Base *base;
+
+ if( G.vd == NULL ) /* No 3d view has been initialized yet, simply return an empty list */
+ return 0;
+
+ for (base= scene->base.first; base; base= base->next) {
+ if TESTBASE(base) {
+ len++;
+ }
+ }
+ return len;
+ }
+ /*should never run this */
+ return 0;
+}
+
+/*
+ * retrive a single Object from somewhere in the Object list
+ */
+
+static PyObject *SceneObSeq_item( BPy_SceneObSeq * self, int i )
+{
+ int index=0;
+ Base *base= NULL;
+ Scene *scene= self->bpyscene->scene;
+
+ SCENE_DEL_CHECK_PY(self->bpyscene);
+
+ /* objects */
+ if (self->mode==EXPP_OBSEQ_NORMAL)
+ for (base= scene->base.first; base && i!=index; base= base->next, index++) {}
+ /* selected */
+ else if (self->mode==EXPP_OBSEQ_SELECTED) {
+ for (base= scene->base.first; base && i!=index; base= base->next)
+ if (base->flag & SELECT)
+ index++;
+ }
+ /* context */
+ else if (self->mode==EXPP_OBSEQ_CONTEXT) {
+ if (G.vd)
+ for (base= scene->base.first; base && i!=index; base= base->next)
+ if TESTBASE(base)
+ index++;
+ }
+
+ if (!(base))
+ return EXPP_ReturnPyObjError( PyExc_IndexError,
+ "array index out of range" );
+
+ return Object_CreatePyObject( base->object );
+}
+
+static PySequenceMethods SceneObSeq_as_sequence = {
+ ( inquiry ) SceneObSeq_len, /* sq_length */
+ ( binaryfunc ) 0, /* sq_concat */
+ ( intargfunc ) 0, /* sq_repeat */
+ ( intargfunc ) SceneObSeq_item, /* sq_item */
+ ( intintargfunc ) 0, /* sq_slice */
+ ( intobjargproc ) 0, /* sq_ass_item */
+ ( intintobjargproc ) 0, /* sq_ass_slice */
+ 0,0,0,
+};
+
+
+/************************************************************************
+ *
+ * Python SceneObSeq_Type iterator (iterates over GroupObjects)
+ *
+ ************************************************************************/
+
+/*
+ * Initialize the interator index
+ */
+
+static PyObject *SceneObSeq_getIter( BPy_SceneObSeq * self )
+{
+ /* we need to get the first base, but for selected context we may need to advance
+ to the first selected or first conext base */
+ Base *base= self->bpyscene->scene->base.first;
+
+ SCENE_DEL_CHECK_PY(self->bpyscene);
+
+ if (self->mode==EXPP_OBSEQ_SELECTED)
+ while (base && !(base->flag & SELECT))
+ base= base->next;
+ else if (self->mode==EXPP_OBSEQ_CONTEXT) {
+ if (!G.vd)
+ base= NULL; /* will never iterate if we have no */
+ else
+ while (base && !TESTBASE(base))
+ base= base->next;
+ }
+ /* create a new iterator if were alredy using this one */
+ if (self->iter==NULL) {
+ self->iter = base;
+ return EXPP_incr_ret ( (PyObject *) self );
+ } else {
+ return SceneObSeq_CreatePyObject(self->bpyscene, base, self->mode);
+ }
+}
+
+/*
+ * Return next SceneOb.
+ */
+
+static PyObject *SceneObSeq_nextIter( BPy_SceneObSeq * self )
+{
+ PyObject *object;
+ Base *base;
+ if( !(self->iter) || !(self->bpyscene->scene) ) {
+ self->iter= NULL;
+ return EXPP_ReturnPyObjError( PyExc_StopIteration,
+ "iterator at end" );
+ }
+
+ object= Object_CreatePyObject( self->iter->object );
+ base= self->iter->next;
+
+ if (self->mode==EXPP_OBSEQ_SELECTED)
+ while (base && !(base->flag & SELECT))
+ base= base->next;
+ else if (self->mode==EXPP_OBSEQ_CONTEXT) {
+ if (!G.vd)
+ base= NULL; /* will never iterate if we have no */
+ else
+ while (base && !TESTBASE(base))
+ base= base->next;
+ }
+ self->iter= base;
+ return object;
+}
+
+
+static PyObject *SceneObSeq_link( BPy_SceneObSeq * self, PyObject *pyobj )
+{
+ SCENE_DEL_CHECK_PY(self->bpyscene);
+
+ /* this shold eventually replace Scene_link */
+ if (self->mode != EXPP_OBSEQ_NORMAL)
+ return (EXPP_ReturnPyObjError( PyExc_TypeError,
+ "Cannot link to objects.selection or objects.context!" ));
+
+ /*
+ if (self->iter != NULL)
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "Cannot modify scene objects while iterating" );
+ */
+
+ if( PyTuple_Size(pyobj) == 1 ) {
+ BPy_LibraryData *seq = ( BPy_LibraryData * )PyTuple_GET_ITEM( pyobj, 0 );
+ if( BPy_LibraryData_Check( seq ) )
+ return LibraryData_importLibData( seq, seq->name,
+ ( seq->kind == OBJECT_IS_LINK ? FILE_LINK : 0 ),
+ self->bpyscene->scene );
+ }
+ return Scene_link(self->bpyscene, pyobj);
+}
+
+/* This is buggy with new object data not already linked to an object, for now use the above code */
+static PyObject *SceneObSeq_new( BPy_SceneObSeq * self, PyObject *args )
+{
+
+ void *data = NULL;
+ char *name = NULL;
+ char *desc = NULL;
+ short type = OB_EMPTY;
+ struct Object *object;
+ Base *base;
+ PyObject *py_data;
+ Scene *scene= self->bpyscene->scene;
+
+ SCENE_DEL_CHECK_PY(self->bpyscene);
+
+ if (self->mode != EXPP_OBSEQ_NORMAL)
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "Cannot add new to objects.selection or objects.context!" );
+
+ if( !PyArg_ParseTuple( args, "O|s", &py_data, &name ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "scene.objects.new(obdata) - expected obdata to be\n\ta python obdata type or the string 'Empty'" );
+
+ if( BPy_Armature_Check( py_data ) ) {
+ data = ( void * ) Armature_FromPyObject( py_data );
+ type = OB_ARMATURE;
+ } else if( BPy_Camera_Check( py_data ) ) {
+ data = ( void * ) Camera_FromPyObject( py_data );
+ type = OB_CAMERA;
+ } else if( BPy_Lamp_Check( py_data ) ) {
+ data = ( void * ) Lamp_FromPyObject( py_data );
+ type = OB_LAMP;
+ } else if( BPy_Curve_Check( py_data ) ) {
+ data = ( void * ) Curve_FromPyObject( py_data );
+ type = OB_CURVE;
+ } else if( BPy_NMesh_Check( py_data ) ) {
+ data = ( void * ) NMesh_FromPyObject( py_data, NULL );
+ type = OB_MESH;
+ if( !data ) /* NULL means there is already an error */
+ return NULL;
+ } else if( BPy_Mesh_Check( py_data ) ) {
+ data = ( void * ) Mesh_FromPyObject( py_data, NULL );
+ type = OB_MESH;
+ } else if( BPy_Lattice_Check( py_data ) ) {
+ data = ( void * ) Lattice_FromPyObject( py_data );
+ type = OB_LATTICE;
+ } else if( BPy_Metaball_Check( py_data ) ) {
+ data = ( void * ) Metaball_FromPyObject( py_data );
+ type = OB_MBALL;
+ } else if( BPy_Text3d_Check( py_data ) ) {
+ data = ( void * ) Text3d_FromPyObject( py_data );
+ type = OB_FONT;
+ } else if( ( desc = PyString_AsString( (PyObject *)py_data ) ) != NULL ) {
+ if( !strcmp( desc, "Empty" ) ) {
+ type = OB_EMPTY;
+ data = NULL;
+ } else
+ goto typeError;
+ } else {
+typeError:
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected an object and optionally a string as arguments" );
+ }
+
+ if (!name) {
+ if (type == OB_EMPTY)
+ name = "Empty";
+ else
+ name = ((ID *)data)->name + 2;
+ }
+
+ object = add_only_object(type, name);
+
+ if( data ) {
+ object->data = data;
+ id_us_plus((ID *)data);
+ }
+
+ object->flag = SELECT;
+
+ /* creates the curve for the text object */
+ if (type == OB_FONT)
+ text_to_curve(object, 0);
+
+ /* link to scene */
+ base = MEM_callocN( sizeof( Base ), "pynewbase" );
+
+ if( !base )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't allocate new Base for object" );
+
+ base->object = object; /* link object to the new base */
+
+ if (scene == G.scene && G.vd) {
+ if (G.vd->localview) {
+ object->lay= G.vd->layact + G.vd->lay;
+ } else {
+ object->lay= G.vd->layact;
+ }
+ } else {
+ base->lay= object->lay = scene->lay & ((1<<20)-1); /* Layer, by default visible*/
+ }
+
+ base->lay= object->lay;
+
+ base->flag = SELECT;
+ object->id.us = 1; /* we will exist once in this scene */
+
+ BLI_addhead( &(scene->base), base ); /* finally, link new base to scene */
+
+ /* make sure data and object materials are consistent */
+ test_object_materials( (ID *)object->data );
+
+ /* so we can deal with vertex groups */
+ if (type == OB_MESH)
+ ((BPy_Mesh *)py_data)->object = object;
+
+ return Object_CreatePyObject( object );
+
+}
+
+static PyObject *SceneObSeq_unlink( BPy_SceneObSeq * self, PyObject *args )
+{
+ PyObject *pyobj;
+ Object *blen_ob;
+ Scene *scene;
+ Base *base= NULL;
+
+ SCENE_DEL_CHECK_PY(self->bpyscene);
+
+ if (self->mode != EXPP_OBSEQ_NORMAL)
+ return (EXPP_ReturnPyObjError( PyExc_TypeError,
+ "Cannot add new to objects.selection or objects.context!" ));
+
+ if( !PyArg_ParseTuple( args, "O!", &Object_Type, &pyobj ) )
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a python object as an argument" ) );
+
+ blen_ob = ( ( BPy_Object * ) pyobj )->object;
+
+ scene = self->bpyscene->scene;
+
+ /* is the object really in the scene? */
+ base = object_in_scene( blen_ob, scene);
+ if( base ) { /* if it is, remove it */
+ if (scene->basact==base)
+ scene->basact= NULL; /* in case the object was selected */
+ free_and_unlink_base_from_scene(scene, base);
+ Py_RETURN_TRUE;
+ }
+ Py_RETURN_FALSE;
+}
+
+PyObject *SceneObSeq_getActive(BPy_SceneObSeq *self)
+{
+ Base *base;
+ SCENE_DEL_CHECK_PY(self->bpyscene);
+
+ if (self->mode!=EXPP_OBSEQ_NORMAL)
+ return (EXPP_ReturnPyObjError( PyExc_TypeError,
+ "cannot get active from objects.selected or objects.context" ));
+
+ base= self->bpyscene->scene->basact;
+ if (!base)
+ Py_RETURN_NONE;
+
+ return Object_CreatePyObject( base->object );
+}
+
+static int SceneObSeq_setActive(BPy_SceneObSeq *self, PyObject *value)
+{
+ Base *base;
+
+ SCENE_DEL_CHECK_INT(self->bpyscene);
+
+ if (self->mode!=EXPP_OBSEQ_NORMAL)
+ return (EXPP_ReturnIntError( PyExc_TypeError,
+ "cannot set active from objects.selected or objects.context" ));
+
+ if (value==Py_None) {
+ self->bpyscene->scene->basact= NULL;
+ return 0;
+ }
+
+ if (!BPy_Object_Check(value))
+ return (EXPP_ReturnIntError( PyExc_ValueError,
+ "Object or None types can only be assigned to active!" ));
+
+ base = object_in_scene( ((BPy_Object *)value)->object, self->bpyscene->scene );
+
+ if (!base)
+ return (EXPP_ReturnIntError( PyExc_ValueError,
+ "cannot assign an active object outside the scene." ));
+
+ self->bpyscene->scene->basact= base;
+ return 0;
+}
+
+PyObject *SceneObSeq_getCamera(BPy_SceneObSeq *self)
+{
+ SCENE_DEL_CHECK_PY(self->bpyscene);
+
+ if (self->mode!=EXPP_OBSEQ_NORMAL)
+ return (EXPP_ReturnPyObjError( PyExc_TypeError,
+ "cannot get camera from objects.selected or objects.context" ));
+
+ return Object_CreatePyObject( self->bpyscene->scene->camera );
+}
+
+static int SceneObSeq_setCamera(BPy_SceneObSeq *self, PyObject *value)
+{
+ int ret;
+
+ SCENE_DEL_CHECK_INT(self->bpyscene);
+ if (self->mode!=EXPP_OBSEQ_NORMAL)
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "cannot set camera from objects.selected or objects.context" );
+
+ ret = GenericLib_assignData(value, (void **) &self->bpyscene->scene->camera, 0, 0, ID_OB, 0);
+
+ /* if this is the current scene, update its window now */
+ if( ret == 0 && !G.background && self->bpyscene->scene == G.scene ) /* Traced a crash to redrawing while in background mode -Campbell */
+ copy_view3d_lock( REDRAW );
+
+/* XXX copy_view3d_lock(REDRAW) prints "bad call to addqueue: 0 (18, 1)".
+ * The same happens in bpython. */
+
+ return ret;
+}
+
+
+static struct PyMethodDef BPy_SceneObSeq_methods[] = {
+ {"link", (PyCFunction)SceneObSeq_link, METH_VARARGS,
+ "link object to this scene"},
+ {"new", (PyCFunction)SceneObSeq_new, METH_VARARGS,
+ "Create a new object in this scene from the obdata given and return a new object"},
+ {"unlink", (PyCFunction)SceneObSeq_unlink, METH_VARARGS,
+ "unlinks the object from the scene"},
+ {NULL, NULL, 0, NULL}
+};
+
+/************************************************************************
+ *
+ * Python SceneObSeq_Type standard operations
+ *
+ ************************************************************************/
+
+static void SceneObSeq_dealloc( BPy_SceneObSeq * self )
+{
+ Py_DECREF(self->bpyscene);
+ PyObject_DEL( self );
+}
+
+static int SceneObSeq_compare( BPy_SceneObSeq * a, BPy_SceneObSeq * b )
+{
+ return ( a->bpyscene->scene == b->bpyscene->scene && a->mode == b->mode) ? 0 : -1;
+}
+
+/*
+ * repr function
+ * callback functions building meaninful string to representations
+ */
+static PyObject *SceneObSeq_repr( BPy_SceneObSeq * self )
+{
+ if( !(self->bpyscene->scene) )
+ return PyString_FromFormat( "[Scene ObjectSeq Removed]" );
+ else if (self->mode==EXPP_OBSEQ_SELECTED)
+ return PyString_FromFormat( "[Scene ObjectSeq Selected \"%s\"]",
+ self->bpyscene->scene->id.name + 2 );
+ else if (self->mode==EXPP_OBSEQ_CONTEXT)
+ return PyString_FromFormat( "[Scene ObjectSeq Context \"%s\"]",
+ self->bpyscene->scene->id.name + 2 );
+
+ /*self->mode==0*/
+ return PyString_FromFormat( "[Scene ObjectSeq \"%s\"]",
+ self->bpyscene->scene->id.name + 2 );
+}
+
+static PyGetSetDef SceneObSeq_getseters[] = {
+ {"selected",
+ (getter)SceneObSeq_getObjects, (setter)SceneObSeq_setObjects,
+ "sequence of selected objects",
+ (void *)EXPP_OBSEQ_SELECTED},
+ {"context",
+ (getter)SceneObSeq_getObjects, (setter)SceneObSeq_setObjects,
+ "sequence of user context objects",
+ (void *)EXPP_OBSEQ_CONTEXT},
+ {"active",
+ (getter)SceneObSeq_getActive, (setter)SceneObSeq_setActive,
+ "active object",
+ NULL},
+ {"camera",
+ (getter)SceneObSeq_getCamera, (setter)SceneObSeq_setCamera,
+ "camera object",
+ NULL},
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+/*****************************************************************************/
+/* Python SceneObSeq_Type structure definition: */
+/*****************************************************************************/
+PyTypeObject SceneObSeq_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender SceneObSeq", /* char *tp_name; */
+ sizeof( BPy_SceneObSeq ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ ( destructor ) SceneObSeq_dealloc,/* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ ( cmpfunc ) SceneObSeq_compare, /* cmpfunc tp_compare; */
+ ( reprfunc ) SceneObSeq_repr, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ &SceneObSeq_as_sequence, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ ( getiterfunc) SceneObSeq_getIter, /* getiterfunc tp_iter; */
+ ( iternextfunc ) SceneObSeq_nextIter, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_SceneObSeq_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ SceneObSeq_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
diff --git a/source/blender/python/api2_2x/Scene.h b/source/blender/python/api2_2x/Scene.h
new file mode 100644
index 00000000000..e6e509159d5
--- /dev/null
+++ b/source/blender/python/api2_2x/Scene.h
@@ -0,0 +1,70 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_SCENE_H
+#define EXPP_SCENE_H
+
+#include <Python.h>
+#include "DNA_scene_types.h"
+
+/* The Scene PyType Object defined in Scene.c */
+extern PyTypeObject Scene_Type;
+extern PyTypeObject SceneObSeq_Type;
+
+#define BPy_Scene_Check(v) \
+ ((v)->ob_type == &Scene_Type)
+#define BPy_SceneObSeq_Check(v) \
+ ((v)->ob_type == &SceneObSeq_Type)
+
+/*---------------------------Python BPy_Scene structure definition----------*/
+typedef struct {
+ PyObject_HEAD
+ Scene * scene; /* libdata must be second */
+} BPy_Scene;
+/*---------------------------Python BPy_Scene visible prototypes-----------*/
+/* Python Scene_Type helper functions needed by Blender (the Init function) and Object modules. */
+
+
+/* Scene object sequence, iterate on the scene object listbase*/
+typedef struct {
+ PyObject_VAR_HEAD /* required python macro */
+ BPy_Scene *bpyscene; /* link to the python scene so we can know if its been removed */
+ Base *iter; /* so we can iterate over the objects */
+ int mode; /*0:all objects, 1:selected objects, 2:user context*/
+} BPy_SceneObSeq;
+
+
+PyObject *Scene_Init( void );
+PyObject *Scene_CreatePyObject( Scene * scene );
+/*Scene *Scene_FromPyObject( PyObject * pyobj );*/ /* not used yet */
+
+#endif /* EXPP_SCENE_H */
diff --git a/source/blender/python/api2_2x/Sound.c b/source/blender/python/api2_2x/Sound.c
new file mode 100644
index 00000000000..6e20e4c3ee5
--- /dev/null
+++ b/source/blender/python/api2_2x/Sound.c
@@ -0,0 +1,607 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Chris Keith
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#include "Sound.h" /*This must come first*/
+
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BLI_blenlib.h"
+#include "BKE_sound.h"
+#include "BKE_library.h"
+#include "BIF_editsound.h"
+#include "BKE_packedFile.h"
+#include "mydevice.h" /* redraw defines */
+#include "gen_utils.h"
+#include "gen_library.h"
+#include "DNA_space_types.h" /* for FILE_MAXDIR only */
+
+/*****************************************************************************/
+/* Python BPy_Sound defaults: */
+/*****************************************************************************/
+
+#define EXPP_SND_volume_MIN 0.0
+#define EXPP_SND_volume_MAX 1.0
+#define EXPP_SND_pitch_MIN -12.0
+#define EXPP_SND_pitch_MAX 12.0
+#define EXPP_SND_attenuation_MIN 0.0
+#define EXPP_SND_attenuation_MAX 5.0
+
+/*****************************************************************************/
+/* Python API function prototypes for the Sound module. */
+/*****************************************************************************/
+static PyObject *M_Sound_Get( PyObject * self, PyObject * args );
+static PyObject *M_Sound_Load( PyObject * self, PyObject * value );
+
+/************************************************************************/
+/* The following string definitions are used for documentation strings. */
+/* In Python these will be written to the console when doing a */
+/* Blender.Sound.__doc__ */
+/************************************************************************/
+static char M_Sound_doc[] = "The Blender Sound module\n\n";
+
+static char M_Sound_Get_doc[] =
+ "(name) - return the sound with the name 'name', \
+returns None if not found.\n If 'name' is not specified, \
+it returns a list of all sounds in the\ncurrent scene.";
+
+static char M_Sound_Load_doc[] =
+ "(filename) - return sound from file filename as a Sound Object,\n\
+returns None if not found.";
+
+/*****************************************************************************/
+/* Python method structure definition for Blender.Sound module: */
+/*****************************************************************************/
+struct PyMethodDef M_Sound_methods[] = {
+ {"Get", M_Sound_Get, METH_VARARGS, M_Sound_Get_doc},
+ {"Load", M_Sound_Load, METH_O, M_Sound_Load_doc},
+ {NULL, NULL, 0, NULL}
+};
+
+/*****************************************************************************/
+/* Python Sound_Type callback function prototypes: */
+/*****************************************************************************/
+static int Sound_compare( BPy_Sound * a, BPy_Sound * b );
+static PyObject *Sound_repr( BPy_Sound * self );
+
+#define SOUND_FLOAT_METHODS(funcname, varname) \
+static PyObject *Sound_get ## funcname(BPy_Sound *self) { \
+ return PyFloat_FromDouble(self->sound->varname); \
+} \
+static PyObject *Sound_set ## funcname(BPy_Sound *self, PyObject *args) { \
+ float f = 0; \
+ if (!PyArg_ParseTuple(args, "f", &f)) \
+ return (EXPP_ReturnPyObjError (PyExc_TypeError, \
+ "expected float argument")); \
+ self->sound->varname = EXPP_ClampFloat(f, \
+ EXPP_SND_##varname##_MIN, EXPP_SND_##varname##_MAX); \
+ Py_RETURN_NONE; \
+}
+
+#define SOUND_FLOAT_METHOD_FUNCS(varname) \
+{"get"#varname, (PyCFunction)Sound_get ## varname, METH_NOARGS, \
+"() - Return Sound object "#varname}, \
+{"set"#varname, (PyCFunction)Sound_set ## varname, METH_VARARGS, \
+"(float) - Change Sound object "#varname},
+
+
+/*****************************************************************************/
+/* Python BPy_Sound methods declarations: */
+/*****************************************************************************/
+static PyObject *Sound_getName( BPy_Sound * self );
+static PyObject *Sound_getFilename( BPy_Sound * self );
+static PyObject *Sound_setName( BPy_Sound * self, PyObject * args );
+static int Sound_setFilename( BPy_Sound * self, PyObject * args );
+static PyObject *Sound_oldsetFilename( BPy_Sound * self, PyObject * args );
+static PyObject *Sound_setCurrent( BPy_Sound * self );
+static PyObject *Sound_play( BPy_Sound * self );
+static PyObject *Sound_unpack( BPy_Sound * self, PyObject * args);
+static PyObject *Sound_pack( BPy_Sound * self );
+/*static PyObject *Sound_reload ( BPy_Sound * self );*/
+SOUND_FLOAT_METHODS( Volume, volume )
+SOUND_FLOAT_METHODS( Attenuation, attenuation )
+SOUND_FLOAT_METHODS( Pitch, pitch )
+/* these can't be set via interface, removed for now */
+/*
+SOUND_FLOAT_METHODS( Panning, panning )
+SOUND_FLOAT_METHODS( MinGain, min_gain )
+SOUND_FLOAT_METHODS( MaxGain, max_gain )
+SOUND_FLOAT_METHODS( Distance, distance )
+*/
+
+/*****************************************************************************/
+/* Python BPy_Sound methods table: */
+/*****************************************************************************/
+static PyMethodDef BPy_Sound_methods[] = {
+ /* name, method, flags, doc */
+ {"getName", ( PyCFunction ) Sound_getName, METH_NOARGS,
+ "() - Return Sound object name"},
+ {"getFilename", ( PyCFunction ) Sound_getFilename, METH_NOARGS,
+ "() - Return Sound object filename"},
+ {"setName", ( PyCFunction ) Sound_setName, METH_VARARGS,
+ "(name) - Set Sound object name"},
+ {"setFilename", ( PyCFunction ) Sound_oldsetFilename, METH_VARARGS,
+ "(filename) - Set Sound object filename"},
+ {"setCurrent", ( PyCFunction ) Sound_setCurrent, METH_NOARGS,
+ "() - make this the active sound in the sound buttons win (also redraws)"},
+ {"play", ( PyCFunction ) Sound_play, METH_NOARGS,
+ "() - play this sound"},
+ {"unpack", ( PyCFunction ) Sound_unpack, METH_VARARGS,
+ "(int) - Unpack sound. Uses one of the values defined in Blender.UnpackModes."},
+ {"pack", ( PyCFunction ) Sound_pack, METH_NOARGS,
+ "() Pack the sound"},
+/*
+ {"reload", ( PyCFunction ) Sound_setCurrent, METH_NOARGS,
+ "() - reload this Sound object's sample.\n\
+ This is only useful if the original sound file has changed."},
+*/
+ SOUND_FLOAT_METHOD_FUNCS( Volume )
+ SOUND_FLOAT_METHOD_FUNCS( Attenuation )
+ SOUND_FLOAT_METHOD_FUNCS( Pitch )
+ /*
+ SOUND_FLOAT_METHOD_FUNCS( Panning )
+ SOUND_FLOAT_METHOD_FUNCS( MinGain )
+ SOUND_FLOAT_METHOD_FUNCS( MaxGain )
+ SOUND_FLOAT_METHOD_FUNCS( Distance )
+ */
+ {NULL, NULL, 0, NULL}
+};
+
+/* NOTE: these were copied and modified from image.h. To Be Done TBD:
+ * macro-ize them, or C++ templates eventually?
+ */
+/****************************************************************************/
+/* Function: M_Sound_Get */
+/* Python equivalent: Blender.Sound.Get */
+/* Description: Receives a string and returns the Sound object */
+/* whose name matches the string. If no argument is */
+/* passed in, a list of all Sound names in the */
+/* current scene is returned. */
+/****************************************************************************/
+static PyObject *M_Sound_Get( PyObject * self, PyObject * args )
+{
+ char *name = NULL;
+ bSound *snd_iter;
+
+ if( !PyArg_ParseTuple( args, "|s", &name ) )
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument (or nothing)" ) );
+
+ snd_iter = G.main->sound.first;
+
+ if( name ) { /* (name) - Search Sound by name */
+
+ BPy_Sound *wanted_Sound = NULL;
+
+ while( ( snd_iter ) && ( wanted_Sound == NULL ) ) {
+ if( strcmp( name, snd_iter->id.name + 2 ) == 0 ) {
+ wanted_Sound =
+ ( BPy_Sound * )
+ PyObject_NEW( BPy_Sound, &Sound_Type );
+ if( wanted_Sound ) {
+ wanted_Sound->sound = snd_iter;
+ break;
+ }
+ }
+ snd_iter = snd_iter->id.next;
+ }
+
+ if( wanted_Sound == NULL ) { /* Requested Sound doesn't exist */
+ char error_msg[64];
+ PyOS_snprintf( error_msg, sizeof( error_msg ),
+ "Sound \"%s\" not found", name );
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_NameError, error_msg ) );
+ }
+
+ return ( PyObject * ) wanted_Sound;
+ }
+
+ else { /* () - return a list of all Sounds in the scene */
+ int index = 0;
+ PyObject *snd_list, *pyobj;
+
+ snd_list = PyList_New( BLI_countlist( &( G.main->sound ) ) );
+
+ if( snd_list == NULL )
+ return ( EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create PyList" ) );
+
+ while( snd_iter ) {
+ pyobj = Sound_CreatePyObject( snd_iter );
+
+ if( !pyobj ) {
+ Py_DECREF(snd_list);
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_MemoryError,
+ "couldn't create PyObject" ) );
+ }
+ PyList_SET_ITEM( snd_list, index, pyobj );
+
+ snd_iter = snd_iter->id.next;
+ index++;
+ }
+
+ return ( snd_list );
+ }
+}
+
+/*****************************************************************************/
+/* Function: M_Sound_Load */
+/* Python equivalent: Blender.Sound.Load */
+/* Description: Receives a string and returns the Sound object */
+/* whose filename matches the string. */
+/*****************************************************************************/
+static PyObject *M_Sound_Load( PyObject * self, PyObject * value )
+{
+ char *fname = PyString_AsString(value);
+ bSound *snd_ptr;
+ BPy_Sound *snd;
+
+ if( !fname )
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument" ) );
+
+ snd = ( BPy_Sound * ) PyObject_NEW( BPy_Sound, &Sound_Type );
+
+ if( !snd )
+ return ( EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create PyObject Sound_Type" ) );
+
+ snd_ptr = sound_new_sound( fname );
+
+ if( snd_ptr ) {
+ if( G.ssound ) {
+ G.ssound->sound = snd_ptr;
+ }
+ }
+
+ if( !snd_ptr )
+ return ( EXPP_ReturnPyObjError( PyExc_IOError,
+ "not a valid sound sample" ) );
+
+ snd->sound = snd_ptr;
+
+ return ( PyObject * ) snd;
+}
+
+/*****************************************************************************/
+/* Function: Sound_Init */
+/*****************************************************************************/
+PyObject *Sound_Init( void )
+{
+ PyObject *submodule;
+
+ if( PyType_Ready( &Sound_Type ) < 0 )
+ return NULL;
+
+ submodule =
+ Py_InitModule3( "Blender.Sound", M_Sound_methods,
+ M_Sound_doc );
+
+ return ( submodule );
+}
+
+/************************/
+/*** The Sound PyType ***/
+/************************/
+
+
+/*****************************************************************************/
+/* Function: Sound_CreatePyObject */
+/* Description: This function will create a new BPy_Sound from an existing */
+/* Blender Sound structure. */
+/*****************************************************************************/
+PyObject *Sound_CreatePyObject( bSound * snd )
+{
+ BPy_Sound *py_snd;
+
+ py_snd = ( BPy_Sound * ) PyObject_NEW( BPy_Sound, &Sound_Type );
+
+ if( !py_snd )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create BPy_Sound object" );
+
+ py_snd->sound = snd;
+
+ return ( PyObject * ) py_snd;
+}
+
+/*****************************************************************************/
+/* Function: Sound_FromPyObject */
+/* Description: Returns the Blender Sound associated with this object */
+/*****************************************************************************/
+bSound *Sound_FromPyObject( PyObject * pyobj )
+{
+ return ( ( BPy_Sound * ) pyobj )->sound;
+}
+
+/*****************************************************************************/
+/* Python BPy_Sound methods: */
+/*****************************************************************************/
+static PyObject *Sound_getName( BPy_Sound * self )
+{
+ return PyString_FromString( self->sound->id.name + 2 );
+}
+
+static PyObject *Sound_getFilename( BPy_Sound * self )
+{
+ return PyString_FromString( self->sound->name );
+}
+
+static PyObject *Sound_getPacked( BPy_Sound * self )
+{
+ if (!sound_sample_is_null(self->sound)) {
+ bSample *sample = sound_find_sample(self->sound);
+ if (sample->packedfile)
+ Py_RETURN_TRUE;
+ }
+ Py_RETURN_FALSE;
+}
+
+static PyObject *Sound_setName( BPy_Sound * self, PyObject * args )
+{
+ char *name;
+
+ if( !PyArg_ParseTuple( args, "s", &name ) ) {
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected a String as argument" ) );
+ }
+
+ rename_id( &self->sound->id, name );
+
+ Py_RETURN_NONE;
+}
+
+static int Sound_setFilename( BPy_Sound * self, PyObject * value )
+{
+ char *name;
+
+ /* max len is FILE_MAXDIR = 160 chars like in DNA_image_types.h */
+ name = PyString_AsString(value);
+ if (!name || strlen(name) > FILE_MAXDIR)
+ return ( EXPP_ReturnIntError( PyExc_ValueError,
+ "string argument is limited to 160 chars at most" ) );
+
+ strcpy( self->sound->name, name );
+ return 0;
+}
+
+static PyObject *Sound_oldsetFilename( BPy_Sound * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)Sound_setFilename );
+}
+
+
+static PyObject *Sound_play( BPy_Sound * self )
+{
+ sound_play_sound( self->sound );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Sound_setCurrent( BPy_Sound * self )
+{
+ bSound *snd_ptr = self->sound;
+
+ if( snd_ptr ) {
+ if( G.ssound ) {
+ G.ssound->sound = snd_ptr;
+ }
+ }
+
+ EXPP_allqueue( REDRAWSOUND, 0 );
+ EXPP_allqueue( REDRAWBUTSLOGIC, 0 );
+
+ Py_RETURN_NONE;
+}
+
+/* unpack sound */
+
+static PyObject *Sound_unpack( BPy_Sound * self, PyObject * args )
+{
+ bSound *sound = self->sound;
+ int mode;
+ if( !PyArg_ParseTuple( args, "i", &mode ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected an integer from Blender.UnpackModes" );
+
+ if (!sound_sample_is_null(sound)) {
+ bSample *sample = sound_find_sample(sound);
+ if (sample->packedfile) {
+ if (unpackSample(sample, mode) == RET_ERROR)
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "error unpacking sound");
+ }
+ } else {
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError, "sound has no samples" );
+ }
+ Py_RETURN_NONE;
+}
+
+/* pack sound */
+
+static PyObject *Sound_pack( BPy_Sound * self )
+{
+ bSound *sound = self->sound;
+ if (!sound_sample_is_null(sound))
+ {
+ bSample *sample = sound_find_sample(sound);
+ if (sample->packedfile )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "sound alredy packed" );
+ sound_set_packedfile(sample, newPackedFile(sample->name));
+ }
+ else
+ {
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "sound has no samples" );
+ }
+ Py_RETURN_NONE;
+}
+
+/*
+static PyObject *Sound_reload( BPy_Sound * self)
+{
+ sound_free_sample();
+
+ if (sound->snd_sound) {
+ SND_RemoveSound(ghSoundScene, sound->snd_sound);
+ sound->snd_sound = NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+*/
+
+
+
+/*****************************************************************************/
+/* Function: Sound_compare */
+/* Description: This is a callback function for the BPy_Sound type. It */
+/* compares two Sound_Type objects. Only the "==" and "!=" */
+/* comparisons are meaninful. Returns 0 for equality and -1 if */
+/* they don't point to the same Blender Sound struct. */
+/* In Python it becomes 1 if they are equal, 0 otherwise. */
+/*****************************************************************************/
+static int Sound_compare( BPy_Sound * a, BPy_Sound * b )
+{
+ return ( a->sound == b->sound ) ? 0 : -1;
+}
+
+/*****************************************************************************/
+/* Function: Sound_repr */
+/* Description: This is a callback function for the BPy_Sound type. It */
+/* builds a meaninful string to represent Sound objects. */
+/*****************************************************************************/
+static PyObject *Sound_repr( BPy_Sound * self )
+{
+ return PyString_FromFormat( "[Sound \"%s\"]",
+ self->sound->id.name + 2 );
+}
+
+/*****************************************************************************/
+/* Python attributes get/set structure: */
+/*****************************************************************************/
+static PyGetSetDef BPy_Sound_getseters[] = {
+ GENERIC_LIB_GETSETATTR,
+ {"filename", (getter)Sound_getFilename, (setter)Sound_setFilename,
+ "text filename", NULL},
+ {"packed", (getter)Sound_getPacked, (setter)NULL,
+ "text filename", NULL},
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+
+
+/*****************************************************************************/
+/* Python Sound_Type structure definition: */
+/*****************************************************************************/
+PyTypeObject Sound_Type = {
+ PyObject_HEAD_INIT( NULL )
+ 0, /* ob_size */
+ "Blender Sound", /* tp_name */
+ sizeof( BPy_Sound ), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ /* methods */
+ NULL, /* tp_dealloc */
+ 0, /* tp_print */
+ NULL, /* tp_getattr */
+ NULL, /* tp_setattr */
+ ( cmpfunc ) Sound_compare, /* tp_compare */
+ ( reprfunc ) Sound_repr, /* tp_repr */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ ( hashfunc ) GenericLib_hash, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_Sound_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ BPy_Sound_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+
diff --git a/source/blender/python/api2_2x/Sound.h b/source/blender/python/api2_2x/Sound.h
new file mode 100644
index 00000000000..7a84bbd901d
--- /dev/null
+++ b/source/blender/python/api2_2x/Sound.h
@@ -0,0 +1,57 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Chris Keith
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_SOUND_H
+#define EXPP_SOUND_H
+
+#include <Python.h>
+#include "DNA_sound_types.h"
+
+#define BPy_Sound_Check(v) ((v)->ob_type == &Sound_Type)
+extern PyTypeObject Sound_Type;
+
+/*****************************************************************************/
+/* Python BPy_Sound structure definition */
+/*****************************************************************************/
+typedef struct {
+ PyObject_HEAD
+ bSound * sound;
+} BPy_Sound;
+
+/*****************************************************************************/
+/* Module Blender.Sound - public functions */
+/*****************************************************************************/
+PyObject *Sound_Init( void );
+PyObject *Sound_CreatePyObject( bSound * sound );
+bSound *Sound_FromPyObject( PyObject * pyobj );
+
+#endif /* EXPP_SOUND_H */
diff --git a/source/blender/python/api2_2x/SurfNurb.c b/source/blender/python/api2_2x/SurfNurb.c
new file mode 100644
index 00000000000..3499ec09936
--- /dev/null
+++ b/source/blender/python/api2_2x/SurfNurb.c
@@ -0,0 +1,857 @@
+/*
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Stephen Swaney
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "SurfNurb.h" /*This must come first */
+
+#include "BKE_curve.h"
+#include "BDR_editcurve.h" /* for convertspline */
+#include "MEM_guardedalloc.h"
+#include "gen_utils.h"
+#include "gen_library.h"
+#include "BezTriple.h"
+
+/*
+ * forward declarations go here
+ */
+
+static int SurfNurb_setPoint( BPy_SurfNurb * self, int index, PyObject * ob );
+static int SurfNurb_length( PyInstanceObject * inst );
+static PyObject *SurfNurb_getIter( BPy_SurfNurb * self );
+static PyObject *SurfNurb_iterNext( BPy_SurfNurb * self );
+PyObject *SurfNurb_append( BPy_SurfNurb * self, PyObject * args );
+
+char M_SurfNurb_doc[] = "SurfNurb";
+
+/*
+ table of module methods
+ these are the equivalent of class or static methods.
+ you do not need an object instance to call one.
+*/
+
+static PyMethodDef M_SurfNurb_methods[] = {
+/* name, method, flags, doc_string */
+/* {"Get", (PyCFunction) M_SurfNurb_method, METH_NOARGS, " () - doc string"}, */
+/* {"method", (PyCFunction) M_SurfNurb_method, METH_NOARGS, " () - doc string"}, */
+
+ {NULL, NULL, 0, NULL}
+};
+
+/*
+ * method table
+ * table of instance methods
+ * these methods are invoked on an instance of the type.
+*/
+
+static PyMethodDef BPy_SurfNurb_methods[] = {
+# if 0
+ {"append", ( PyCFunction ) SurfNurb_append, METH_VARARGS,
+ "( point ) - add a new point. arg is BezTriple or list of x,y,z,w floats"},
+#endif
+ {NULL, NULL, 0, NULL}
+};
+
+/*
+ * SurfNurb_appendPointToNurb
+ * this is a non-bpy utility func to add a point to a given nurb.
+ * notice the first arg is Nurb*.
+ */
+
+#if 0
+static PyObject *SurfNurb_appendPointToNurb( Nurb * nurb, PyObject * args )
+{
+
+ int i;
+ int size;
+ PyObject *pyOb;
+ int npoints = nurb->pntsu;
+
+ /*
+ do we have a list of four floats or a BezTriple?
+ */
+ if( !PyArg_ParseTuple( args, "O", &pyOb ))
+ return EXPP_ReturnPyObjError
+ ( PyExc_RuntimeError,
+ "Internal error parsing arguments" );
+
+
+
+ /* if curve is empty, adjust type depending on input type */
+ if (nurb->bezt==NULL && nurb->bp==NULL) {
+ if (BPy_BezTriple_Check( pyOb ))
+ nurb->type |= CU_BEZIER;
+ else if (PySequence_Check( pyOb ))
+ nurb->type |= CU_NURBS;
+ else
+ return( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "Expected a BezTriple or a Sequence of 4 (or 5) floats" ) );
+ }
+
+
+
+ if ((nurb->type & 7)==CU_BEZIER) {
+ BezTriple *tmp;
+
+ if( !BPy_BezTriple_Check( pyOb ) )
+ return( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "Expected a BezTriple\n" ) );
+
+/* printf("\ndbg: got a BezTriple\n"); */
+ tmp = nurb->bezt; /* save old points */
+ nurb->bezt =
+ ( BezTriple * ) MEM_mallocN( sizeof( BezTriple ) *
+ ( npoints + 1 ),
+ "SurfNurb_append2" );
+
+ if( !nurb->bezt )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_MemoryError, "allocation failed" ) );
+
+ /* copy old points to new */
+ if( tmp ) {
+ memmove( nurb->bezt, tmp, sizeof( BezTriple ) * npoints );
+ MEM_freeN( tmp );
+ }
+
+ nurb->pntsu++;
+ /* add new point to end of list */
+ memcpy( nurb->bezt + npoints,
+ BezTriple_FromPyObject( pyOb ), sizeof( BezTriple ) );
+
+ }
+ else if( PySequence_Check( pyOb ) ) {
+ size = PySequence_Size( pyOb );
+/* printf("\ndbg: got a sequence of size %d\n", size ); */
+ if( size == 4 || size == 5 ) {
+ BPoint *tmp;
+
+ tmp = nurb->bp; /* save old pts */
+
+ nurb->bp =
+ ( BPoint * ) MEM_mallocN( sizeof( BPoint ) *
+ ( npoints + 1 ),
+ "SurfNurb_append1" );
+ if( !nurb->bp )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_MemoryError,
+ "allocation failed" ) );
+
+ memmove( nurb->bp, tmp, sizeof( BPoint ) * npoints );
+ if( tmp )
+ MEM_freeN( tmp );
+
+ ++nurb->pntsu;
+ /* initialize new BPoint from old */
+ memcpy( nurb->bp + npoints, nurb->bp,
+ sizeof( BPoint ) );
+
+ for( i = 0; i < 4; ++i ) {
+ PyObject *item = PySequence_GetItem( pyOb, i );
+
+ if (item == NULL)
+ return NULL;
+
+
+ nurb->bp[npoints].vec[i] = ( float ) PyFloat_AsDouble( item );
+ Py_DECREF( item );
+ }
+
+ if (size == 5) {
+ PyObject *item = PySequence_GetItem( pyOb, i );
+
+ if (item == NULL)
+ return NULL;
+
+ nurb->bp[npoints].alfa = ( float ) PyFloat_AsDouble( item );
+ Py_DECREF( item );
+ }
+ else {
+ nurb->bp[npoints].alfa = 0.0f;
+ }
+
+ makeknots( nurb, 1, nurb->flagu >> 1 );
+
+ } else {
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a sequence of 4 or 5 floats" );
+ }
+
+ } else {
+ /* bail with error */
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a sequence of 4 or 5 floats" );
+
+ }
+
+ return ( EXPP_incr_ret( Py_None ) );
+}
+
+/*
+ * SurfNurb_append( point )
+ * append a new point to a nurb curve.
+ * arg is BezTriple or list of xyzw floats
+ */
+
+PyObject *SurfNurb_append( BPy_SurfNurb * self, PyObject * args )
+{
+ Nurb *nurb = self->nurb;
+
+ return SurfNurb_appendPointToNurb( nurb, args );
+}
+#endif
+
+#if 0
+/*
+ * SurfNurb_getMatIndex
+ *
+ * returns index into material list
+ */
+
+static PyObject *SurfNurb_getMatIndex( BPy_SurfNurb * self )
+{
+ return PyInt_FromLong( ( long ) self->nurb->mat_nr );
+}
+
+/*
+ * SurfNurb_setMatIndex
+ *
+ * set index into material list
+ */
+
+static int SurfNurb_setMatIndex( BPy_SurfNurb * self, PyObject * args )
+{
+ args = PyNumber_Int( args );
+
+ if( !args )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected integer argument" );
+
+ /* fixme: some range checking would be nice! */
+ /* can't do range checking without knowing the "parent" curve! */
+ self->nurb->mat_nr = ( short )PyInt_AS_LONG( args );
+ Py_DECREF( args );
+
+ return 0;
+}
+#endif
+
+/*
+ * SurfNurb_getPointsU
+ *
+ * returns number of control points in U direction
+ */
+
+static PyObject *SurfNurb_getPointsU( BPy_SurfNurb * self )
+{
+ return PyInt_FromLong( ( long ) self->nurb->pntsu );
+}
+
+/*
+ * SurfNurb_getPointsV
+ *
+ * returns number of control points in V direction
+ */
+
+static PyObject *SurfNurb_getPointsV( BPy_SurfNurb * self )
+{
+ return PyInt_FromLong( ( long ) self->nurb->pntsv );
+}
+
+/*
+ * SurfNurb_getFlagU
+ *
+ * returns curve's flagu
+ */
+
+static PyObject *SurfNurb_getFlagU( BPy_SurfNurb * self )
+{
+ return PyInt_FromLong( ( long ) (self->nurb->flagu >> 1) );
+}
+
+/*
+ * SurfNurb_setFlagU
+ *
+ * set curve's flagu and recalculate the knots
+ *
+ * Possible values: 0 - uniform, 2 - endpoints, 4 - bezier
+ * bit 0 controls CU_CYCLIC
+ */
+
+static int SurfNurb_setFlagU( BPy_SurfNurb * self, PyObject * args )
+{
+ int flagu;
+
+ args = PyNumber_Int( args );
+ if( !args )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected integer argument" );
+
+ flagu = ( int )PyInt_AS_LONG( args );
+ Py_DECREF( args );
+
+ if( flagu < 0 || flagu > 2 )
+ return EXPP_ReturnIntError( PyExc_AttributeError,
+ "expected integer argument in range [0,2]" );
+
+ flagu = (flagu << 1) | (self->nurb->flagu & CU_CYCLIC);
+ if( self->nurb->flagu != flagu ) {
+ self->nurb->flagu = (short)flagu;
+ makeknots( self->nurb, 1, self->nurb->flagu >> 1 );
+ }
+
+ return 0;
+}
+
+/*
+ * SurfNurb_getFlagV
+ *
+ * returns curve's flagu
+ */
+
+static PyObject *SurfNurb_getFlagV( BPy_SurfNurb * self )
+{
+ return PyInt_FromLong( ( long ) (self->nurb->flagv >> 1) );
+}
+
+/*
+ * SurfNurb_setFlagV
+ *
+ * set curve's flagu and recalculate the knots
+ *
+ * Possible values: 0 - uniform, 1 - endpoints, 2 - bezier
+ */
+
+static int SurfNurb_setFlagV( BPy_SurfNurb * self, PyObject * args )
+{
+ int flagv;
+
+ args = PyNumber_Int( args );
+ if( !args )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected integer argument" );
+
+ flagv = ( int )PyInt_AS_LONG( args );
+ Py_DECREF( args );
+
+ if( flagv < 0 || flagv > 2 )
+ return EXPP_ReturnIntError( PyExc_AttributeError,
+ "expected integer argument in range [0,2]" );
+
+ flagv = (flagv << 1) | (self->nurb->flagv & CU_CYCLIC);
+ if( self->nurb->flagv != flagv ) {
+ self->nurb->flagv = (short)flagv;
+ makeknots( self->nurb, 2, self->nurb->flagv >> 1 );
+ }
+
+ return 0;
+}
+
+/*
+ * SurfNurb_getOrder
+ *
+ * returns curve's order
+ */
+
+static PyObject *SurfNurb_getOrderU( BPy_SurfNurb * self )
+{
+ return PyInt_FromLong( ( long ) self->nurb->orderu );
+}
+
+static int SurfNurb_setOrderU( BPy_SurfNurb * self, PyObject * args )
+{
+ int order;
+
+ args = PyNumber_Int( args );
+ if( !args )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected integer argument" );
+
+ order = ( int )PyInt_AS_LONG( args );
+ Py_DECREF( args );
+
+ if( order < 2 ) order = 2;
+ else if( order > 6 ) order = 6;
+
+ if( self->nurb->pntsu < order )
+ order = self->nurb->pntsu;
+
+ self->nurb->orderu = (short)order;
+ makeknots( self->nurb, 1, self->nurb->flagu >> 1 );
+
+ return 0;
+}
+
+static PyObject *SurfNurb_getOrderV( BPy_SurfNurb * self )
+{
+ return PyInt_FromLong( ( long ) self->nurb->orderv );
+}
+
+static int SurfNurb_setOrderV( BPy_SurfNurb * self, PyObject * args )
+{
+ int order;
+
+ args = PyNumber_Int( args );
+ if( !args )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected integer argument" );
+
+ order = ( int )PyInt_AS_LONG( args );
+ Py_DECREF( args );
+
+ if( order < 2 ) order = 2;
+ else if( order > 6 ) order = 6;
+
+ if( self->nurb->pntsv < order )
+ order = self->nurb->pntsv;
+
+ self->nurb->orderv = (short)order;
+ makeknots( self->nurb, 2, self->nurb->flagv >> 1 );
+ return 0;
+}
+
+/*
+ * SurfNurb_getCyclic()
+ * test whether surface is cyclic (closed) or not (open)
+ */
+
+static PyObject *SurfNurb_getCyclicU( BPy_SurfNurb * self )
+{
+ if( self->nurb->flagu & CU_CYCLIC )
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+}
+
+static PyObject *SurfNurb_getCyclicV( BPy_SurfNurb * self )
+{
+ if( self->nurb->flagv & CU_CYCLIC )
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+}
+
+static int SurfNurb_setCyclicU( BPy_SurfNurb * self, PyObject * value )
+{
+ int param = PyObject_IsTrue( value );
+ if( param == -1 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected True/False or 0/1" );
+
+ if( param )
+ self->nurb->flagu |= CU_CYCLIC;
+ else
+ self->nurb->flagu &= ~CU_CYCLIC;
+ makeknots( self->nurb, 1, self->nurb->flagu >> 1 );
+ return 0;
+}
+
+static int SurfNurb_setCyclicV( BPy_SurfNurb * self, PyObject * value )
+{
+ int param = PyObject_IsTrue( value );
+ if( param == -1 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected True/False or 0/1" );
+
+ if( param )
+ self->nurb->flagv |= CU_CYCLIC;
+ else
+ self->nurb->flagv &= ~CU_CYCLIC;
+ makeknots( self->nurb, 2, self->nurb->flagu >> 1 );
+ return 0;
+}
+
+
+/*
+ * SurfNurb_getIter
+ *
+ * create an iterator for our SurfNurb.
+ * this iterator returns the points for this SurfNurb.
+ */
+
+static PyObject *SurfNurb_getIter( BPy_SurfNurb * self )
+{
+ self->bp = self->nurb->bp;
+ self->bezt = self->nurb->bezt;
+ self->nextPoint = 0;
+
+ Py_INCREF( self );
+ return ( PyObject * ) self;
+}
+
+static PyObject *SurfNurb_iterNext( BPy_SurfNurb * self )
+{
+ Nurb *pnurb = self->nurb;
+ int npoints = pnurb->pntsu * pnurb->pntsv;
+
+ if( self->bp && self->nextPoint < npoints )
+ return SurfNurb_pointAtIndex( self->nurb, self->nextPoint++ );
+ else
+ return EXPP_ReturnPyObjError( PyExc_StopIteration,
+ "iterator at end" );
+}
+
+/*
+ * SurfNurb_length
+ * returns the number of points in a Nurb
+ * this is a tp_as_sequence method, not a regular instance method.
+ */
+
+static int SurfNurb_length( PyInstanceObject * inst )
+{
+ Nurb *nurb;
+
+ if( BPy_SurfNurb_Check( ( PyObject * ) inst ) ) {
+ nurb = ( ( BPy_SurfNurb * ) inst )->nurb;
+ return (int)(nurb->pntsu * nurb->pntsu);
+ }
+
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "arg is not a BPy_SurfNurb" );
+}
+
+
+/*
+ * SurfNurb_getPoint
+ * returns the Nth point in a Nurb
+ * this is one of the tp_as_sequence methods, hence the int N argument.
+ * it is called via the [] operator, not as a usual instance method.
+ */
+
+PyObject *SurfNurb_getPoint( BPy_SurfNurb * self, int index )
+{
+ Nurb *myNurb;
+
+ int npoints;
+
+ /* for convenince */
+ myNurb = self->nurb;
+ npoints = myNurb->pntsu * myNurb->pntsv;
+
+ /* bail if no Nurbs in Curve */
+ if( npoints == 0 )
+ return ( EXPP_ReturnPyObjError( PyExc_IndexError,
+ "no points in this SurfNurb" ) );
+
+ /* check index limits */
+ if( index >= npoints || index < 0 )
+ return ( EXPP_ReturnPyObjError( PyExc_IndexError,
+ "index out of range" ) );
+
+ return SurfNurb_pointAtIndex( myNurb, index );
+}
+
+/*
+ * SurfNurb_setPoint
+ * modifies the Nth point in a Nurb
+ * this is one of the tp_as_sequence methods, hence the int N argument.
+ * it is called via the [] = operator, not as a usual instance method.
+ */
+static int SurfNurb_setPoint( BPy_SurfNurb * self, int index, PyObject * pyOb )
+{
+ Nurb *nurb = self->nurb;
+ int size;
+
+ /* check index limits */
+ if( index < 0 || index >= nurb->pntsu * nurb->pntsv )
+ return EXPP_ReturnIntError( PyExc_IndexError,
+ "array assignment index out of range\n" );
+
+ /* branch by curve type */
+#if 0
+ if ((nurb->type & 7)==CU_BEZIER) { /* BEZIER */
+ /* check parameter type */
+ if( !BPy_BezTriple_Check( pyOb ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a BezTriple\n" );
+
+ /* copy bezier in array */
+ memcpy( nurb->bezt + index,
+ BezTriple_FromPyObject( pyOb ), sizeof( BezTriple ) );
+
+ return 0; /* finished correctly */
+ }
+ else
+#endif
+ { /* NURBS or POLY */
+ int i;
+
+ /* check parameter type */
+ if (!PySequence_Check( pyOb ))
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a list of 4 (or optionaly 5 if the curve is 3D) floats\n" );
+
+ size = PySequence_Size( pyOb );
+
+ /* check sequence size */
+ if( size != 4 && size != 5 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a list of 4 (or optionaly 5 if the curve is 3D) floats\n" );
+
+ /* copy x, y, z, w */
+ for( i = 0; i < 4; ++i ) {
+ PyObject *item = PySequence_GetItem( pyOb, i );
+
+ if (item == NULL)
+ return -1;
+
+ nurb->bp[index].vec[i] = ( float ) PyFloat_AsDouble( item );
+ Py_DECREF( item );
+ }
+
+ if (size == 5) { /* set tilt, if present */
+ PyObject *item = PySequence_GetItem( pyOb, i );
+
+ if (item == NULL)
+ return -1;
+
+ nurb->bp[index].alfa = ( float ) PyFloat_AsDouble( item );
+ Py_DECREF( item );
+ }
+ else { /* if not, set default */
+ nurb->bp[index].alfa = 0.0f;
+ }
+
+ return 0; /* finished correctly */
+ }
+}
+
+
+/*
+ * this is an internal routine. not callable directly from python
+ */
+
+PyObject *SurfNurb_pointAtIndex( Nurb * nurb, int index )
+{
+ PyObject *pyo;
+
+ if( nurb->bp ) { /* we have a nurb curve */
+ int i;
+
+ /* add Tilt only if curve is 3D */
+ if (nurb->flag & CU_3D)
+ pyo = PyList_New( 5 );
+ else
+ pyo = PyList_New( 4 );
+
+ for( i = 0; i < 4; i++ ) {
+ PyList_SetItem( pyo, i,
+ PyFloat_FromDouble( nurb->bp[index].
+ vec[i] ) );
+ }
+
+ /* add Tilt only if curve is 3D */
+ if (nurb->flag & CU_3D)
+ PyList_SetItem( pyo, 4, PyFloat_FromDouble( nurb->bp[index].alfa ) );
+ return pyo;
+
+ } else /* something is horribly wrong */
+ return EXPP_ReturnPyObjError( PyExc_SystemError,
+ "non-NURB surface found" );
+}
+
+/*
+ * methods for SurfNurb as sequence
+ */
+
+static PySequenceMethods SurfNurb_as_sequence = {
+ ( inquiry ) SurfNurb_length, /* sq_length */
+ ( binaryfunc ) 0, /* sq_concat */
+ ( intargfunc ) 0, /* sq_repeat */
+ ( intargfunc ) SurfNurb_getPoint, /* sq_item */
+ ( intintargfunc ) 0, /* sq_slice */
+ ( intobjargproc ) SurfNurb_setPoint, /* sq_ass_item */
+ 0, /* sq_ass_slice */
+ ( objobjproc ) 0, /* sq_contains */
+ 0,
+ 0
+};
+
+static PyGetSetDef BPy_SurfNurb_getseters[] = {
+#if 0
+ {"matIndex",
+ (getter)SurfNurb_getMatIndex, (setter)SurfNurb_setMatIndex,
+ "material index", NULL},
+#endif
+ {"pointsU",
+ (getter)SurfNurb_getPointsU, (setter)NULL,
+ "number of control points in U direction", NULL},
+ {"pointsV",
+ (getter)SurfNurb_getPointsV, (setter)NULL,
+ "number of control points in V direction", NULL},
+ {"flagU",
+ (getter)SurfNurb_getFlagU, (setter)SurfNurb_setFlagU,
+ "knot flag for U direction", NULL},
+ {"flagV",
+ (getter)SurfNurb_getFlagV, (setter)SurfNurb_setFlagV,
+ "knot flag for V direction", NULL},
+ {"cyclicU",
+ (getter)SurfNurb_getCyclicU, (setter)SurfNurb_setCyclicU,
+ "cyclic setting for U direction", NULL},
+ {"cyclicV",
+ (getter)SurfNurb_getCyclicV, (setter)SurfNurb_setCyclicV,
+ "cyclic setting for V direction", NULL},
+ {"orderU",
+ (getter)SurfNurb_getOrderU, (setter)SurfNurb_setOrderU,
+ "order setting for U direction", NULL},
+ {"orderV",
+ (getter)SurfNurb_getOrderV, (setter)SurfNurb_setOrderV,
+ "order setting for V direction", NULL},
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+/*
+ * compare
+ * in this case, we consider two SurfNurbs equal, if they point to the same
+ * blender data.
+*/
+static int SurfNurb_compare( BPy_SurfNurb * a, BPy_SurfNurb * b )
+{
+ return ( a->nurb == b->nurb ) ? 0 : -1;
+}
+
+/*
+ * SurfNurb_repr
+ */
+static PyObject *SurfNurb_repr( BPy_SurfNurb * self )
+{
+ return PyString_FromFormat( "[SurfNurb \"%d\"]", self->nurb->type );
+}
+
+/*****************************************************************************/
+/* Python SurfNurb_Type structure definition: */
+/*****************************************************************************/
+PyTypeObject SurfNurb_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "SurfNurb", /* char *tp_name; */
+ sizeof( BPy_SurfNurb ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ NULL, /* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ ( cmpfunc ) SurfNurb_compare, /* cmpfunc tp_compare; */
+ ( reprfunc ) SurfNurb_repr, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ &SurfNurb_as_sequence, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ ( getiterfunc ) SurfNurb_getIter, /* getiterfunc tp_iter; */
+ ( iternextfunc ) SurfNurb_iterNext, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_SurfNurb_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ BPy_SurfNurb_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+/*
+ factory method to create a BPy_SurfNurb from a Blender Nurb
+*/
+
+PyObject *SurfNurb_CreatePyObject( Nurb * blen_nurb )
+{
+ BPy_SurfNurb *pyNurb;
+
+ pyNurb = ( BPy_SurfNurb * ) PyObject_NEW( BPy_SurfNurb, &SurfNurb_Type );
+
+ if( !pyNurb )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "could not create BPy_SurfNurb PyObject" );
+
+ pyNurb->nurb = blen_nurb;
+ return ( PyObject * ) pyNurb;
+}
+
+
+PyObject *SurfNurb_Init( void )
+{
+ PyType_Ready( &SurfNurb_Type );
+ return Py_InitModule3( "Blender.SurfNurb", M_SurfNurb_methods,
+ M_SurfNurb_doc );
+}
+
diff --git a/source/blender/python/api2_2x/SurfNurb.h b/source/blender/python/api2_2x/SurfNurb.h
new file mode 100644
index 00000000000..0559d84cbaf
--- /dev/null
+++ b/source/blender/python/api2_2x/SurfNurb.h
@@ -0,0 +1,68 @@
+/*
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Stephen Swaney
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef EXPP_SURFNURB_H
+#define EXPP_SURFNURB_H
+
+#include <Python.h>
+#include "DNA_curve_types.h"
+
+extern PyTypeObject SurfNurb_Type;
+
+#define BPy_SurfNurb_Check(v) ((v)->ob_type == &SurfNurb_Type) /* for type checking */
+
+/* Python BPy_SurfNurb structure definition */
+typedef struct {
+ PyObject_HEAD
+ Nurb * nurb;
+
+ /* iterator stuff */
+ /* internal ptrs to point data. do not free */
+ BPoint *bp;
+ BezTriple *bezt;
+ int atEnd; /* iter exhausted flag */
+ int nextPoint;
+
+} BPy_SurfNurb;
+
+
+/*
+ * prototypes
+ */
+
+PyObject *SurfNurb_Init( void );
+PyObject *SurfNurb_CreatePyObject( Nurb * bzt );
+Nurb *SurfNurb_FromPyObject( PyObject * pyobj );
+
+PyObject *SurfNurb_getPoint( BPy_SurfNurb * self, int index );
+PyObject *SurfNurb_pointAtIndex( Nurb * nurb, int index );
+
+#endif /* EXPP_SURFNURB_H */
diff --git a/source/blender/python/api2_2x/Sys.c b/source/blender/python/api2_2x/Sys.c
new file mode 100644
index 00000000000..7dc841e9d68
--- /dev/null
+++ b/source/blender/python/api2_2x/Sys.c
@@ -0,0 +1,400 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano, Campbell Barton
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#include "Sys.h" /*This must come first*/
+
+#include "BKE_utildefines.h"
+#include "BKE_global.h"
+#include "BLI_blenlib.h"
+#include "DNA_scene_types.h" /* G.scene-"r.cfra */
+#include "PIL_time.h"
+#include "gen_utils.h"
+
+#ifdef WIN32
+#define DIRSEP '\\'
+#define DIRSEP_STR "\\"
+#else
+#define DIRSEP '/'
+#define DIRSEP_STR "/"
+#endif
+
+
+/*****************************************************************************/
+/* Python API function prototypes for the sys module. */
+/*****************************************************************************/
+static PyObject *M_sys_basename( PyObject * self, PyObject * value );
+static PyObject *M_sys_dirname( PyObject * self, PyObject * value );
+static PyObject *M_sys_join( PyObject * self, PyObject * args );
+static PyObject *M_sys_splitext( PyObject * self, PyObject * value );
+static PyObject *M_sys_makename( PyObject * self, PyObject * args,
+ PyObject * kw );
+static PyObject *M_sys_exists( PyObject * self, PyObject * value );
+static PyObject *M_sys_time( PyObject * self );
+static PyObject *M_sys_sleep( PyObject * self, PyObject * args );
+static PyObject *M_sys_expandpath( PyObject *self, PyObject *value);
+
+/*****************************************************************************/
+/* The following string definitions are used for documentation strings. */
+/* In Python these will be written to the console when doing a */
+/* Blender.sys.__doc__ */
+/*****************************************************************************/
+static char M_sys_doc[] = "The Blender.sys submodule\n\
+\n\
+This is a minimal system module to supply simple functionality available\n\
+in the default Python module os.";
+
+static char M_sys_basename_doc[] =
+ "(path) - Split 'path' in dir and filename.\n\
+Return the filename.";
+
+static char M_sys_dirname_doc[] =
+ "(path) - Split 'path' in dir and filename.\n\
+Return the dir.";
+
+static char M_sys_join_doc[] =
+ "(dir, file) - Join dir and file to form a full filename.\n\
+Return the filename.";
+
+static char M_sys_splitext_doc[] =
+ "(path) - Split 'path' in root and extension:\n\
+/this/that/file.ext -> ('/this/that/file','.ext').\n\
+Return the pair (root, extension).";
+
+static char M_sys_makename_doc[] =
+ "(path = Blender.Get('filename'), ext = \"\", strip = 0) -\n\
+Strip dir and extension from path, leaving only a name, then append 'ext'\n\
+to it (if given) and return the resulting string.\n\n\
+(path) - string: a pathname -- Blender.Get('filename') if 'path' isn't given;\n\
+(ext = \"\") - string: the extension to append.\n\
+(strip = 0) - int: strip dirname from 'path' if given and non-zero.\n\
+Ex: makename('/path/to/file/myfile.foo','-01.abc') returns 'myfile-01.abc'\n\
+Ex: makename(ext='.txt') returns 'untitled.txt' if Blender.Get('filename')\n\
+returns a path to the file 'untitled.blend'";
+
+static char M_sys_time_doc[] =
+ "() - Return a float representing time elapsed in seconds.\n\
+Each successive call is garanteed to return values greater than or\n\
+equal to the previous call.";
+
+static char M_sys_sleep_doc[] =
+ "(milliseconds = 10) - Sleep for the specified time.\n\
+(milliseconds = 10) - the amount of time in milliseconds to sleep.\n\
+This function can be necessary in tight 'get event' loops.";
+
+static char M_sys_exists_doc[] =
+ "(path) - Check if the given pathname exists.\n\
+The return value is as follows:\n\
+\t 0: path doesn't exist;\n\
+\t 1: path is an existing filename;\n\
+\t 2: path is an existing dirname;\n\
+\t-1: path exists but is neither a regular file nor a dir.";
+
+static char M_sys_expandpath_doc[] =
+"(path) - Expand this Blender internal path to a proper file system path.\n\
+(path) - the string path to convert.\n\n\
+Note: internally Blender paths can contain two special character sequences:\n\
+- '//' (at start) for base path directory (the current .blend's dir path);\n\
+- '#' (at ending) for current frame number.\n\n\
+This function expands these to their actual content, returning a valid path.\n\
+If the special chars are not found in the given path, it is simply returned.";
+
+/*****************************************************************************/
+/* Python method structure definition for Blender.sys module: */
+/*****************************************************************************/
+struct PyMethodDef M_sys_methods[] = {
+ {"basename", M_sys_basename, METH_O, M_sys_basename_doc},
+ {"dirname", M_sys_dirname, METH_O, M_sys_dirname_doc},
+ {"join", M_sys_join, METH_VARARGS, M_sys_join_doc},
+ {"splitext", M_sys_splitext, METH_O, M_sys_splitext_doc},
+ {"makename", ( PyCFunction ) M_sys_makename,
+ METH_VARARGS | METH_KEYWORDS,
+ M_sys_makename_doc},
+ {"exists", M_sys_exists, METH_O, M_sys_exists_doc},
+ {"sleep", M_sys_sleep, METH_VARARGS, M_sys_sleep_doc},
+ {"time", ( PyCFunction ) M_sys_time, METH_NOARGS, M_sys_time_doc},
+ {"expandpath", M_sys_expandpath, METH_O, M_sys_expandpath_doc},
+ {NULL, NULL, 0, NULL}
+};
+
+/* Module Functions */
+
+static PyObject *g_sysmodule = NULL; /* pointer to Blender.sys module */
+
+PyObject *sys_Init( void )
+{
+ PyObject *submodule, *dict;
+
+ submodule = Py_InitModule3( "Blender.sys", M_sys_methods, M_sys_doc );
+
+ g_sysmodule = submodule;
+
+ dict = PyModule_GetDict( submodule );
+
+ EXPP_dict_set_item_str( dict, "dirsep", PyString_FromString(DIRSEP_STR) );
+ EXPP_dict_set_item_str( dict, "sep", PyString_FromString(DIRSEP_STR) );
+
+ return submodule;
+}
+
+static PyObject *M_sys_basename( PyObject * self, PyObject * value )
+{
+ char *name = PyString_AsString(value);
+ char *p, basename[FILE_MAXDIR + FILE_MAXFILE];
+ int n, len;
+
+ if( !name )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument" );
+
+ len = strlen( name );
+
+#ifdef WIN32
+ p = MAX2(strrchr( name, '/' ), strrchr( name, '\\' ));
+#else
+ p = strrchr( name, DIRSEP );
+#endif
+
+ if( p ) {
+ n = name + len - p - 1; /* - 1 because we don't want the sep */
+
+ if( n > FILE_MAXDIR + FILE_MAXFILE )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "path too long" );
+
+ BLI_strncpy( basename, p + 1, n + 1 );
+ return PyString_FromString( basename );
+ }
+
+ return PyString_FromString( name );
+}
+
+static PyObject *M_sys_dirname( PyObject * self, PyObject * value )
+{
+ char *name = PyString_AsString(value);
+ char *p, dirname[FILE_MAXDIR + FILE_MAXFILE];
+ int n;
+
+ if( !name )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument" );
+
+#ifdef WIN32
+ p = MAX2(strrchr( name, '/' ), strrchr( name, '\\' ));
+#else
+ p = strrchr( name, DIRSEP );
+#endif
+
+ if( p ) {
+ n = p - name;
+
+ if( n > FILE_MAXDIR + FILE_MAXFILE )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "path too long" );
+
+ BLI_strncpy( dirname, name, n + 1 );
+ return PyString_FromString( dirname );
+ }
+
+ return PyString_FromString( "." );
+}
+
+static PyObject *M_sys_join( PyObject * self, PyObject * args )
+{
+ char *name = NULL, *path = NULL;
+ char filename[FILE_MAXDIR + FILE_MAXFILE];
+ int pathlen = 0, namelen = 0;
+
+ if( !PyArg_ParseTuple( args, "ss", &path, &name ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument" );
+
+ pathlen = strlen( path ) + 1;
+ namelen = strlen( name ) + 1; /* + 1 to account for '\0' for BLI_strncpy */
+
+ if( pathlen + namelen > FILE_MAXDIR + FILE_MAXFILE - 1 )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "filename is too long." );
+
+ BLI_strncpy( filename, path, pathlen );
+
+ if( filename[pathlen - 2] != DIRSEP ) {
+ filename[pathlen - 1] = DIRSEP;
+ pathlen += 1;
+ }
+
+ BLI_strncpy( filename + pathlen - 1, name, namelen );
+
+ return PyString_FromString( filename );
+}
+
+static PyObject *M_sys_splitext( PyObject * self, PyObject * value )
+{
+ char *name = PyString_AsString(value);
+ char *dot, *p, path[FILE_MAXDIR + FILE_MAXFILE], ext[FILE_MAXDIR + FILE_MAXFILE];
+ int n, len;
+
+ if( !name )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument" );
+
+ len = strlen( name );
+ dot = strrchr( name, '.' );
+
+ if( !dot )
+ return Py_BuildValue( "ss", name, "" );
+
+ p = strrchr( name, DIRSEP );
+
+ if( p ) {
+ if( p > dot )
+ return Py_BuildValue( "ss", name, "" );
+ }
+
+ n = name + len - dot;
+
+ /* loong extensions are supported -- foolish, but Python's os.path.splitext
+ * supports them, so ... */
+
+ if( n >= FILE_MAXDIR + FILE_MAXFILE || ( len - n ) >= FILE_MAXDIR + FILE_MAXFILE )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError, "path too long" );
+
+ BLI_strncpy( ext, dot, n + 1 );
+ BLI_strncpy( path, name, dot - name + 1 );
+
+ return Py_BuildValue( "ss", path, ext );
+}
+
+static PyObject *M_sys_makename( PyObject * self, PyObject * args,
+ PyObject * kw )
+{
+ char *path = G.sce, *ext = NULL;
+ int strip = 0;
+ static char *kwlist[] = { "path", "ext", "strip", NULL };
+ char *dot = NULL, *p = NULL, basename[FILE_MAXDIR + FILE_MAXFILE];
+ int n, len, lenext = 0;
+
+ if( !PyArg_ParseTupleAndKeywords( args, kw, "|ssi", kwlist,
+ &path, &ext, &strip ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected one or two strings and an int (or nothing) as arguments" );
+
+ len = strlen( path ) + 1; /* + 1 to consider ending '\0' */
+ if( ext )
+ lenext = strlen( ext ) + 1;
+
+ if( ( len + lenext ) > FILE_MAXDIR + FILE_MAXFILE )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "path too long" );
+
+ p = strrchr( path, DIRSEP );
+
+ if( p && strip ) {
+ n = path + len - p;
+ BLI_strncpy( basename, p + 1, n ); /* + 1 to skip the sep */
+ } else
+ BLI_strncpy( basename, path, len );
+
+ dot = strrchr( basename, '.' );
+
+ /* now the extension: always remove the one in basename */
+ if( dot || ext ) {
+ if( !ext )
+ basename[dot - basename] = '\0';
+ else { /* if user gave an ext, append it */
+
+ if( dot )
+ n = dot - basename;
+ else
+ n = strlen( basename );
+
+ BLI_strncpy( basename + n, ext, lenext );
+ }
+ }
+
+ return PyString_FromString( basename );
+}
+
+static PyObject *M_sys_time( PyObject * self )
+{
+ return PyFloat_FromDouble( PIL_check_seconds_timer( ) );
+}
+
+static PyObject *M_sys_sleep( PyObject * self, PyObject * args )
+{
+ int millisecs = 10;
+
+ if( !PyArg_ParseTuple( args, "|i", &millisecs ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected int argument" );
+
+ PIL_sleep_ms( millisecs );
+
+ return EXPP_incr_ret( Py_None );
+}
+
+static PyObject *M_sys_exists( PyObject * self, PyObject * value )
+{
+ char *fname = PyString_AsString(value);
+
+ int mode = 0, i = -1;
+
+ if( !fname )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string (pathname) argument" );
+
+ mode = BLI_exist(fname);
+
+ if( mode == 0 )
+ i = 0;
+ else if( S_ISREG( mode ) )
+ i = 1;
+ else if( S_ISDIR( mode ) )
+ i = 2;
+ /* i stays as -1 if path exists but is neither a regular file nor a dir */
+
+ return PyInt_FromLong(i);
+}
+
+static PyObject *M_sys_expandpath( PyObject * self, PyObject * value )
+{
+ char *path = PyString_AsString(value);
+ char expanded[FILE_MAXDIR + FILE_MAXFILE];
+
+ if (!path)
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument" );
+
+ BLI_strncpy(expanded, path, FILE_MAXDIR + FILE_MAXFILE);
+ BLI_convertstringcode(expanded, G.sce, G.scene->r.cfra);
+
+ return PyString_FromString(expanded);
+}
diff --git a/source/blender/python/api2_2x/Sys.h b/source/blender/python/api2_2x/Sys.h
new file mode 100644
index 00000000000..d6e2689bba5
--- /dev/null
+++ b/source/blender/python/api2_2x/Sys.h
@@ -0,0 +1,40 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_sys_H
+#define EXPP_sys_H
+
+#include <Python.h>
+
+PyObject *sys_Init( void );
+
+#endif /* EXPP_sys_H */
diff --git a/source/blender/python/api2_2x/Text.c b/source/blender/python/api2_2x/Text.c
new file mode 100644
index 00000000000..d507d623c99
--- /dev/null
+++ b/source/blender/python/api2_2x/Text.c
@@ -0,0 +1,576 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#include "Text.h" /*This must come first*/
+
+#include "BKE_library.h"
+#include "BKE_sca.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BIF_drawtext.h"
+#include "BKE_text.h"
+#include "BLI_blenlib.h"
+#include "DNA_space_types.h"
+#include "gen_utils.h"
+#include "gen_library.h"
+#include "../BPY_extern.h"
+
+#define EXPP_TEXT_MODE_FOLLOW TXT_FOLLOW
+
+/*****************************************************************************/
+/* Python API function prototypes for the Text module. */
+/*****************************************************************************/
+static PyObject *M_Text_New( PyObject * self, PyObject * args);
+static PyObject *M_Text_Get( PyObject * self, PyObject * args );
+static PyObject *M_Text_Load( PyObject * self, PyObject * value );
+static PyObject *M_Text_unlink( PyObject * self, PyObject * args );
+
+/*****************************************************************************/
+/* The following string definitions are used for documentation strings. */
+/* In Python these will be written to the console when doing a */
+/* Blender.Text.__doc__ */
+/*****************************************************************************/
+static char M_Text_doc[] = "The Blender Text module\n\n";
+
+static char M_Text_New_doc[] = "() - return a new Text object";
+
+static char M_Text_Get_doc[] = "(name) - return the Text with name 'name', \
+returns None if not found.\n If 'name' is not specified, \
+it returns a list of all Texts in the\ncurrent scene.";
+
+static char M_Text_Load_doc[] =
+ "(filename) - return text from file filename as a Text Object, \
+returns None if not found.\n";
+
+static char M_Text_unlink_doc[] =
+ "(text) - remove Text object 'text' from Blender";
+
+/*****************************************************************************/
+/* Python method structure definition for Blender.Text module: */
+/*****************************************************************************/
+struct PyMethodDef M_Text_methods[] = {
+ {"New", M_Text_New, METH_VARARGS, M_Text_New_doc},
+ {"Get", M_Text_Get, METH_VARARGS, M_Text_Get_doc},
+ {"get", M_Text_Get, METH_VARARGS, M_Text_Get_doc},
+ {"Load", M_Text_Load, METH_O, M_Text_Load_doc},
+ {"unlink", M_Text_unlink, METH_VARARGS, M_Text_unlink_doc},
+ {NULL, NULL, 0, NULL}
+};
+
+
+/*****************************************************************************/
+/* Python BPy_Text methods declarations: */
+/*****************************************************************************/
+static PyObject *Text_getFilename( BPy_Text * self );
+static PyObject *Text_getNLines( BPy_Text * self );
+static PyObject *Text_clear( BPy_Text * self );
+static PyObject *Text_write( BPy_Text * self, PyObject * value );
+static PyObject *Text_set( BPy_Text * self, PyObject * args );
+static PyObject *Text_asLines( BPy_Text * self );
+
+/*****************************************************************************/
+/* Python BPy_Text methods table: */
+/*****************************************************************************/
+static PyMethodDef BPy_Text_methods[] = {
+ /* name, method, flags, doc */
+ {"getName", ( PyCFunction ) GenericLib_getName, METH_NOARGS,
+ "() - Return Text Object name"},
+ {"getFilename", ( PyCFunction ) Text_getFilename, METH_VARARGS,
+ "() - Return Text Object filename"},
+ {"getNLines", ( PyCFunction ) Text_getNLines, METH_VARARGS,
+ "() - Return number of lines in text buffer"},
+ {"setName", ( PyCFunction ) GenericLib_setName_with_method, METH_VARARGS,
+ "(str) - Change Text Object name"},
+ {"clear", ( PyCFunction ) Text_clear, METH_NOARGS,
+ "() - Clear Text buffer"},
+ {"write", ( PyCFunction ) Text_write, METH_O,
+ "(line) - Append string 'str' to Text buffer"},
+ {"set", ( PyCFunction ) Text_set, METH_VARARGS,
+ "(name, val) - Set attribute 'name' to value 'val'"},
+ {"asLines", ( PyCFunction ) Text_asLines, METH_NOARGS,
+ "() - Return text buffer as a list of lines"},
+ {NULL, NULL, 0, NULL}
+};
+
+/*****************************************************************************/
+/* Python Text_Type callback function prototypes: */
+/*****************************************************************************/
+static int Text_compare( BPy_Text * a, BPy_Text * b );
+static PyObject *Text_repr( BPy_Text * self );
+
+/*****************************************************************************/
+/* Function: M_Text_New */
+/* Python equivalent: Blender.Text.New */
+/*****************************************************************************/
+static PyObject *M_Text_New( PyObject * self, PyObject * args)
+{
+ char *name = "Text";
+ int follow = 0;
+ Text *bl_text; /* blender text object */
+ PyObject *py_text; /* python wrapper */
+
+ if( !PyArg_ParseTuple( args, "|si", &name, &follow ) )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected string and int arguments (or nothing)" );
+
+ bl_text = add_empty_text( name );
+
+ if( bl_text ) {
+ /* do not set user count because Text is already linked */
+
+ /* create python wrapper obj */
+ py_text = Text_CreatePyObject( bl_text );
+ } else
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't create Text Object in Blender" );
+ if( !py_text )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create Text Object wrapper" );
+
+ if( follow )
+ bl_text->flags |= EXPP_TEXT_MODE_FOLLOW;
+
+ return py_text;
+}
+
+/*****************************************************************************/
+/* Function: M_Text_Get */
+/* Python equivalent: Blender.Text.Get */
+/* Description: Receives a string and returns the text object */
+/* whose name matches the string. If no argument is */
+/* passed in, a list of all text names in the current */
+/* scene is returned. */
+/*****************************************************************************/
+static PyObject *M_Text_Get( PyObject * self, PyObject * args )
+{
+ char *name = NULL;
+ Text *txt_iter;
+
+ if( !PyArg_ParseTuple( args, "|s", &name ) )
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument (or nothing)" ) );
+
+ txt_iter = G.main->text.first;
+
+ if( name ) { /* (name) - Search text by name */
+
+ PyObject *wanted_txt = NULL;
+
+ while( ( txt_iter ) && ( wanted_txt == NULL ) ) {
+
+ if( strcmp( name, txt_iter->id.name + 2 ) == 0 ) {
+ wanted_txt = Text_CreatePyObject( txt_iter );
+ }
+
+ txt_iter = txt_iter->id.next;
+ }
+
+ if( wanted_txt == NULL ) { /* Requested text doesn't exist */
+ char error_msg[64];
+ PyOS_snprintf( error_msg, sizeof( error_msg ),
+ "Text \"%s\" not found", name );
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_NameError, error_msg ) );
+ }
+
+ return wanted_txt;
+ }
+
+ else { /* () - return a list of all texts in the scene */
+ int index = 0;
+ PyObject *txtlist, *pyobj;
+
+ txtlist = PyList_New( BLI_countlist( &( G.main->text ) ) );
+
+ if( txtlist == NULL )
+ return ( EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create PyList" ) );
+
+ while( txt_iter ) {
+ pyobj = Text_CreatePyObject( txt_iter );
+
+ if( !pyobj ) {
+ Py_DECREF(txtlist);
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_MemoryError,
+ "couldn't create PyString" ) );
+ }
+ PyList_SET_ITEM( txtlist, index, pyobj );
+
+ txt_iter = txt_iter->id.next;
+ index++;
+ }
+
+ return ( txtlist );
+ }
+}
+
+/*****************************************************************************/
+/* Function: M_Text_Load */
+/* Python equivalent: Blender.Text.Load */
+/* Description: Receives a filename and returns the text object */
+/* created from the corresponding file. */
+/*****************************************************************************/
+static PyObject *M_Text_Load( PyObject * self, PyObject * value )
+{
+ char *fname = PyString_AsString(value);
+ char fpath[FILE_MAXDIR + FILE_MAXFILE];
+ Text *txt_ptr = NULL;
+ unsigned int maxlen = FILE_MAXDIR + FILE_MAXFILE;
+
+ if( !fname )
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument" ) );
+
+ if (strlen(fname) > (maxlen - 1))
+ return EXPP_ReturnPyObjError (PyExc_AttributeError,
+ "text filename too long");
+ else if (!BLI_exists(fname))
+ return EXPP_ReturnPyObjError (PyExc_AttributeError,
+ "text file not found");
+
+ BLI_strncpy(fpath, fname, maxlen);
+
+ txt_ptr = add_text( fpath );
+ if( !txt_ptr )
+ return EXPP_ReturnPyObjError( PyExc_IOError,
+ "couldn't load text" );
+
+ return Text_CreatePyObject(txt_ptr);
+}
+
+/*****************************************************************************/
+/* Function: M_Text_unlink */
+/* Python equivalent: Blender.Text.unlink */
+/* Description: Removes the given Text object from Blender */
+/*****************************************************************************/
+static PyObject *M_Text_unlink( PyObject * self, PyObject * args )
+{
+ BPy_Text *textobj;
+ Text *text;
+
+ if( !PyArg_ParseTuple( args, "O!", &Text_Type, &textobj ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a Text object as argument" );
+
+ text = ( ( BPy_Text * ) textobj )->text;
+
+ if( !text )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "this text was already unlinked!" );
+
+ BPY_clear_bad_scriptlinks( text );
+ free_text_controllers( text );
+ unlink_text( text );
+
+ free_libblock( &G.main->text, text );
+
+ ( ( BPy_Text * ) textobj )->text = NULL;
+
+ Py_RETURN_NONE;
+}
+
+/*****************************************************************************/
+/* Function: Text_Init */
+/*****************************************************************************/
+PyObject *Text_Init( void )
+{
+ PyObject *submodule;
+
+ if( PyType_Ready( &Text_Type ) < 0 )
+ return NULL;
+
+ submodule =
+ Py_InitModule3( "Blender.Text", M_Text_methods, M_Text_doc );
+
+ return ( submodule );
+}
+
+/*****************************************************************************/
+/* Function: Text_CreatePyObject */
+/*****************************************************************************/
+PyObject *Text_CreatePyObject( Text * txt )
+{
+ BPy_Text *pytxt;
+
+ pytxt = ( BPy_Text * ) PyObject_NEW( BPy_Text, &Text_Type );
+
+ if( !pytxt )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create BPy_Text PyObject" );
+
+ pytxt->text = txt;
+
+ return ( PyObject * ) pytxt;
+}
+
+/*****************************************************************************/
+/* Python BPy_Text methods: */
+/*****************************************************************************/
+static PyObject *Text_getFilename( BPy_Text * self )
+{
+ if( self->text->name )
+ return PyString_FromString( self->text->name );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Text_getNLines( BPy_Text * self )
+{ /* text->nlines isn't updated in Blender (?) */
+ int nlines = 0;
+ TextLine *line;
+
+ line = self->text->lines.first;
+
+ while( line ) { /* so we have to count them ourselves */
+ line = line->next;
+ nlines++;
+ }
+
+ self->text->nlines = nlines; /* and update Blender, too (should we?) */
+
+ return PyInt_FromLong( nlines );
+}
+
+static PyObject *Text_clear( BPy_Text * self)
+{
+ int oldstate;
+
+ if( !self->text )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "This object isn't linked to a Blender Text Object" );
+
+ oldstate = txt_get_undostate( );
+ txt_set_undostate( 1 );
+ txt_sel_all( self->text );
+ txt_cut_sel( self->text );
+ txt_set_undostate( oldstate );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Text_set( BPy_Text * self, PyObject * args )
+{
+ int ival;
+ char *attr;
+
+ if( !PyArg_ParseTuple( args, "si", &attr, &ival ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a string and an int as arguments" );
+
+ if( strcmp( "follow_cursor", attr ) == 0 ) {
+ if( ival )
+ self->text->flags |= EXPP_TEXT_MODE_FOLLOW;
+ else
+ self->text->flags &= EXPP_TEXT_MODE_FOLLOW;
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Text_write( BPy_Text * self, PyObject * value )
+{
+ char *str = PyString_AsString(value);
+ int oldstate;
+
+ if( !self->text )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "This object isn't linked to a Blender Text Object" );
+
+ if( !str )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument" );
+
+ oldstate = txt_get_undostate( );
+ txt_insert_buf( self->text, str );
+ txt_move_eof( self->text, 0 );
+ txt_set_undostate( oldstate );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Text_asLines( BPy_Text * self )
+{
+ TextLine *line;
+ PyObject *list, *tmpstr;
+
+ if( !self->text )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "This object isn't linked to a Blender Text Object" );
+
+ line = self->text->lines.first;
+ list = PyList_New( 0 );
+
+ if( !list )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create PyList" );
+
+ while( line ) {
+ tmpstr = PyString_FromString( line->line );
+ PyList_Append( list, tmpstr );
+ Py_DECREF(tmpstr);
+ line = line->next;
+ }
+
+ return list;
+}
+
+/*****************************************************************************/
+/* Function: Text_compare */
+/* Description: This is a callback function for the BPy_Text type. It */
+/* compares two Text_Type objects. Only the "==" and "!=" */
+/* comparisons are meaninful. Returns 0 for equality and -1 if */
+/* they don't point to the same Blender Text struct. */
+/* In Python it becomes 1 if they are equal, 0 otherwise. */
+/*****************************************************************************/
+static int Text_compare( BPy_Text * a, BPy_Text * b )
+{
+ return ( a->text == b->text ) ? 0 : -1;
+}
+
+/*****************************************************************************/
+/* Function: Text_repr */
+/* Description: This is a callback function for the BPy_Text type. It */
+/* builds a meaninful string to represent text objects. */
+/*****************************************************************************/
+static PyObject *Text_repr( BPy_Text * self )
+{
+ if( self->text )
+ return PyString_FromFormat( "[Text \"%s\"]",
+ self->text->id.name + 2 );
+ else
+ return PyString_FromString( "[Text <deleted>]" );
+}
+
+/*****************************************************************************/
+/* Python attributes get/set functions: */
+/*****************************************************************************/
+static PyObject *Text_getMode(BPy_Text * self)
+{
+ return PyInt_FromLong( self->text->flags );
+}
+
+/*****************************************************************************/
+/* Python attributes get/set structure: */
+/*****************************************************************************/
+static PyGetSetDef BPy_Text_getseters[] = {
+ GENERIC_LIB_GETSETATTR,
+ {"filename", (getter)Text_getFilename, (setter)NULL,
+ "text filename", NULL},
+ {"mode", (getter)Text_getMode, (setter)NULL,
+ "text mode flag", NULL},
+ {"nlines", (getter)Text_getNLines, (setter)NULL,
+ "number of lines", NULL},
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+/*****************************************************************************/
+/* Python Text_Type structure definition: */
+/*****************************************************************************/
+PyTypeObject Text_Type = {
+ PyObject_HEAD_INIT( NULL )
+ 0, /* ob_size */
+ "Blender Text", /* tp_name */
+ sizeof( BPy_Text ), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ /* methods */
+ NULL, /* tp_dealloc */
+ NULL, /* tp_print */
+ NULL, /* tp_getattr */
+ NULL, /* tp_setattr */
+ ( cmpfunc ) Text_compare, /* tp_compare */
+ ( reprfunc ) Text_repr, /* tp_repr */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ ( hashfunc ) GenericLib_hash, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_Text_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ BPy_Text_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
diff --git a/source/blender/python/api2_2x/Text.h b/source/blender/python/api2_2x/Text.h
new file mode 100644
index 00000000000..b40c3807a81
--- /dev/null
+++ b/source/blender/python/api2_2x/Text.h
@@ -0,0 +1,52 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_TEXT_H
+#define EXPP_TEXT_H
+
+#include <Python.h>
+#include "DNA_text_types.h"
+
+extern PyTypeObject Text_Type;
+
+/* Type checking for EXPP PyTypes */
+#define BPy_Text_Check(v) ((v)->ob_type == &Text_Type)
+
+typedef struct {
+ PyObject_HEAD
+ Text * text; /* libdata must be second */
+} BPy_Text;
+
+PyObject *Text_Init( void );
+PyObject *Text_CreatePyObject( Text * txt );
+
+#endif /* EXPP_TEXT_H */
diff --git a/source/blender/python/api2_2x/Text3d.c b/source/blender/python/api2_2x/Text3d.c
new file mode 100644
index 00000000000..57a9c74b71d
--- /dev/null
+++ b/source/blender/python/api2_2x/Text3d.c
@@ -0,0 +1,1206 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Joilnen Leite
+ * Johnny Matthews
+ * Campbell BArton
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "Text3d.h" /*This must come first*/
+
+#include "DNA_object_types.h"
+#include "MEM_guardedalloc.h"
+#include "BKE_curve.h"
+#include "BKE_library.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BIF_editfont.h" /* do_textedit() */
+#include "Curve.h"
+#include "constant.h"
+#include "Font.h"
+#include "gen_utils.h"
+#include "gen_library.h"
+
+
+enum t3d_consts {
+ EXPP_T3D_ATTR_FRAME_WIDTH = 0,
+ EXPP_T3D_ATTR_FRAME_HEIGHT,
+ EXPP_T3D_ATTR_FRAME_X,
+ EXPP_T3D_ATTR_FRAME_Y
+};
+
+
+/*no prototypes declared in header files - external linkage outside of python*/
+extern VFont *get_builtin_font(void);
+extern void freedisplist(struct ListBase *lb);
+extern VFont *give_vfontpointer(int);
+extern VFont *exist_vfont(char *str);
+extern VFont *load_vfont(char *name);
+extern int BLI_exist(char *name);
+
+/*****************************************************************************/
+/* Python API function prototypes for the Text3D module. */
+/*****************************************************************************/
+static PyObject *M_Text3d_New( PyObject * self, PyObject * args );
+static PyObject *M_Text3d_Get( PyObject * self, PyObject * args );
+PyObject *M_Text3d_LoadFont (PyObject * self, PyObject * args );
+
+/*****************************************************************************
+ * Python callback function prototypes for the Text3D module.
+ *****************************************************************************/
+static PyObject *return_ModuleConstant( char *constant_name);
+static PyObject *generate_ModuleIntConstant(char *name, int value);
+
+/*****************************************************************************/
+/* Python method structure definition for Blender.Text3d module: */
+/*****************************************************************************/
+struct PyMethodDef M_Text3d_methods[] = {
+ {"New", ( PyCFunction ) M_Text3d_New, METH_VARARGS, NULL},
+ {"Get", ( PyCFunction ) M_Text3d_Get, METH_VARARGS, NULL},
+ {"LoadFont", ( PyCFunction ) M_Text3d_LoadFont, METH_O, NULL},
+ {NULL, NULL, 0, NULL}
+};
+
+/*****************************************************************************/
+/* Python Text3d_Type callback function prototypes: */
+/*****************************************************************************/
+/* int Text3dPrint (BPy_Text3d *msh, FILE *fp, int flags); */
+
+
+static PyObject *Text3d_repr( BPy_Text3d * self );
+static int Text3d_compare( BPy_Text3d * a, BPy_Text3d * b );
+
+/*****************************************************************************/
+/* Python BPy_Text3d methods declarations: */
+/*****************************************************************************/
+/*PyObject *Text3d_getType(BPy_Text3d *self);*/
+static PyObject *Text3d_getName( BPy_Text3d * self );
+static PyObject *Text3d_setName( BPy_Text3d * self, PyObject * args );
+static PyObject *Text3d_setText( BPy_Text3d * self, PyObject * value );
+static PyObject *Text3d_getText( BPy_Text3d * self );
+static PyObject *Text3d_getDrawMode( BPy_Text3d * self );
+static PyObject *Text3d_setDrawMode( BPy_Text3d * self, PyObject * args );
+static PyObject *Text3d_getUVorco( BPy_Text3d * self );
+static PyObject *Text3d_setUVorco( BPy_Text3d * self, PyObject * args );
+static PyObject *Text3d_getBevelAmount( BPy_Text3d * self );
+static PyObject *Text3d_setBevelAmount( BPy_Text3d * self, PyObject * args );
+static PyObject *Text3d_getDefaultResolution( BPy_Text3d * self );
+static PyObject *Text3d_setDefaultResolution( BPy_Text3d * self, PyObject * args );
+static PyObject *Text3d_getWidth( BPy_Text3d * self );
+static PyObject *Text3d_setWidth( BPy_Text3d * self, PyObject * args );
+static PyObject *Text3d_getExtrudeDepth( BPy_Text3d * self );
+static PyObject *Text3d_setExtrudeDepth( BPy_Text3d * self, PyObject * args );
+static PyObject *Text3d_getExtrudeBevelDepth( BPy_Text3d * self );
+static PyObject *Text3d_setExtrudeBevelDepth( BPy_Text3d * self, PyObject * args );
+static PyObject *Text3d_getShear( BPy_Text3d * self );
+static PyObject *Text3d_setShear( BPy_Text3d * self, PyObject * args );
+static PyObject *Text3d_getSize( BPy_Text3d * self );
+static PyObject *Text3d_setSize( BPy_Text3d * self, PyObject * args );
+static PyObject *Text3d_getLineSeparation( BPy_Text3d * self );
+static PyObject *Text3d_setLineSeparation( BPy_Text3d * self, PyObject * args );
+static PyObject *Text3d_getSpacing( BPy_Text3d * self );
+static PyObject *Text3d_setSpacing( BPy_Text3d * self, PyObject * args );
+static PyObject *Text3d_getXoffset( BPy_Text3d * self );
+static PyObject *Text3d_setXoffset( BPy_Text3d * self, PyObject * args );
+static PyObject *Text3d_getYoffset( BPy_Text3d * self );
+static PyObject *Text3d_setYoffset( BPy_Text3d * self, PyObject * args );
+static PyObject *Text3d_getAlignment( BPy_Text3d * self );
+static PyObject *Text3d_setAlignment( BPy_Text3d * self, PyObject * args );
+static PyObject *Text3d_getFont( BPy_Text3d * self );
+static PyObject *Text3d_setFont( BPy_Text3d * self, PyObject * args );
+static PyObject *Text3d_addFrame( BPy_Text3d * self );
+static PyObject *Text3d_removeFrame( BPy_Text3d * self, PyObject * args );
+
+/*****************************************************************************/
+/* Python BPy_Text3d methods table: */
+/*****************************************************************************/
+char M_Text3D_doc[] = "The Blender Text3D module\n\n\
+ This module provides control over Text Curve objects in Blender.\n";
+
+static PyMethodDef BPy_Text3d_methods[] = {
+ {"getName", ( PyCFunction ) Text3d_getName,
+ METH_NOARGS, "() - Return Text3d Data name"},
+ {"setName", ( PyCFunction ) Text3d_setName,
+ METH_VARARGS, "() - Sets Text3d Data name"},
+ {"setText", ( PyCFunction ) Text3d_setText,
+ METH_O, "() - Sets Text3d Data"},
+ {"getText", ( PyCFunction ) Text3d_getText,
+ METH_NOARGS, "() - Gets Text3d Data"},
+ {"getDrawMode", ( PyCFunction ) Text3d_getDrawMode,
+ METH_NOARGS, "() - Return the font drawing mode"},
+ {"setDrawMode", ( PyCFunction ) Text3d_setDrawMode,
+ METH_VARARGS, "(int) - Set the font drawing mode"},
+ {"getUVorco", ( PyCFunction ) Text3d_getUVorco,
+ METH_NOARGS, "() - Return wether UV coords are used for Texture mapping"},
+ {"setUVorco", ( PyCFunction ) Text3d_setUVorco,
+ METH_VARARGS, "() - Set the font to use UV coords for Texture mapping"},
+ {"getBevelAmount", ( PyCFunction ) Text3d_getBevelAmount,
+ METH_NOARGS, "() - Return bevel resolution"},
+ {"setBevelAmount", ( PyCFunction ) Text3d_setBevelAmount,
+ METH_VARARGS, "() - Sets bevel resolution"},
+ {"getDefaultResolution", ( PyCFunction ) Text3d_getDefaultResolution,
+ METH_NOARGS, "() - Return Default text resolution"},
+ {"setDefaultResolution", ( PyCFunction ) Text3d_setDefaultResolution,
+ METH_VARARGS, "() - Sets Default text Resolution"},
+ {"getWidth", ( PyCFunction ) Text3d_getWidth,
+ METH_NOARGS, "() - Return curve width"},
+ {"setWidth", ( PyCFunction ) Text3d_setWidth,
+ METH_VARARGS, "(int) - Sets curve width"},
+ {"getExtrudeDepth", ( PyCFunction ) Text3d_getExtrudeDepth,
+ METH_NOARGS, "() - Gets Text3d ExtrudeDepth"},
+ {"setExtrudeDepth", ( PyCFunction ) Text3d_setExtrudeDepth,
+ METH_VARARGS, "() - Sets Text3d ExtrudeDepth"},
+ {"getExtrudeBevelDepth", ( PyCFunction ) Text3d_getExtrudeBevelDepth,
+ METH_NOARGS, "() - Gets Text3d ExtrudeBevelDepth"},
+ {"setExtrudeBevelDepth", ( PyCFunction ) Text3d_setExtrudeBevelDepth,
+ METH_VARARGS, "() - Sets Text3d ExtrudeBevelDepth"},
+ {"getShear", ( PyCFunction ) Text3d_getShear,
+ METH_NOARGS, "() - Gets Text3d Shear Data"},
+ {"setShear", ( PyCFunction ) Text3d_setShear,
+ METH_VARARGS, "() - Sets Text3d Shear Data"},
+ {"getSize", ( PyCFunction ) Text3d_getSize,
+ METH_NOARGS, "() - Gets Text3d Size Data"},
+ {"setSize", ( PyCFunction ) Text3d_setSize,
+ METH_VARARGS, "() - Sets Text3d Size Data"},
+ {"getLineSeparation", ( PyCFunction ) Text3d_getLineSeparation,
+ METH_NOARGS, "() - Gets Text3d LineSeparation Data"},
+ {"setLineSeparation", ( PyCFunction ) Text3d_setLineSeparation,
+ METH_VARARGS, "() - Sets Text3d LineSeparation Data"},
+ {"getSpacing", ( PyCFunction ) Text3d_getSpacing,
+ METH_NOARGS, "() - Gets Text3d letter spacing"},
+ {"setSpacing", ( PyCFunction ) Text3d_setSpacing,
+ METH_VARARGS, "() - Sets Text3d letter spacing"},
+ {"getXoffset", ( PyCFunction ) Text3d_getXoffset,
+ METH_NOARGS, "() - Gets Text3d Xoffset Data"},
+ {"setXoffset", ( PyCFunction ) Text3d_setXoffset,
+ METH_VARARGS, "() - Sets Text3d Xoffset Data"},
+ {"getYoffset", ( PyCFunction ) Text3d_getYoffset,
+ METH_NOARGS, "() - Gets Text3d Yoffset Data"},
+ {"setYoffset", ( PyCFunction ) Text3d_setYoffset,
+ METH_VARARGS, "() - Sets Text3d Yoffset Data"},
+ {"getAlignment", ( PyCFunction ) Text3d_getAlignment,
+ METH_NOARGS, "() - Gets Text3d Alignment Data"},
+ {"setAlignment", ( PyCFunction ) Text3d_setAlignment,
+ METH_VARARGS, "() - Sets Text3d Alignment Data"},
+ {"getFont", ( PyCFunction ) Text3d_getFont,
+ METH_NOARGS, "() - Gets font list for Text3d"},
+ {"setFont", ( PyCFunction ) Text3d_setFont,
+ METH_VARARGS, "() - Sets font for Text3d"},
+ {"addFrame", ( PyCFunction ) Text3d_addFrame,
+ METH_NOARGS, "() - adds a new text frame"},
+ {"removeFrame", ( PyCFunction ) Text3d_removeFrame,
+ METH_VARARGS, "(index) - remove this frame"},
+ {NULL, NULL, 0, NULL}
+};
+
+
+static PyObject *Text3d_getTotalFrames( BPy_Text3d * self )
+{
+ return PyInt_FromLong( (long)(self->curve->totbox ) );
+}
+
+static PyObject *Text3d_getActiveFrame( BPy_Text3d * self )
+{
+ return PyInt_FromLong( (long)(self->curve->actbox-1) );
+}
+
+static int Text3d_setActiveFrame( BPy_Text3d * self, PyObject * value )
+{
+ struct Curve *curve= self->curve;
+ PyObject* frame_int = PyNumber_Int( value );
+ int index;
+
+
+ if( !frame_int )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected integer argument" );
+
+ index = ( int )PyInt_AS_LONG( frame_int );
+ index ++;
+ if (index < 1 || index > curve->totbox)
+ return EXPP_ReturnIntError( PyExc_IndexError,
+ "index out of range" );
+
+ curve->actbox = index;
+
+ return 0;
+}
+
+
+static PyObject *getFloatAttr( BPy_Text3d *self, void *type )
+{
+ float param;
+ struct Curve *curve= self->curve;
+
+ switch( (int)type ) {
+ case EXPP_T3D_ATTR_FRAME_WIDTH:
+ param = curve->tb[curve->actbox-1].w;
+ break;
+ case EXPP_T3D_ATTR_FRAME_HEIGHT:
+ param = curve->tb[curve->actbox-1].h;
+ break;
+ case EXPP_T3D_ATTR_FRAME_X:
+ param = curve->tb[curve->actbox-1].x;
+ break;
+ case EXPP_T3D_ATTR_FRAME_Y:
+ param = curve->tb[curve->actbox-1].y;
+ break;
+
+ default:
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "undefined type in getFloatAttr" );
+ }
+ return PyFloat_FromDouble( param );
+}
+
+static int setFloatAttrClamp( BPy_Text3d *self, PyObject *value, void *type )
+{
+ float *param;
+ struct Curve *curve= self->curve;
+ float min, max;
+
+ switch( (int)type ) {
+ case EXPP_T3D_ATTR_FRAME_WIDTH:
+ min = 0.0;
+ max = 50.0;
+ param = &(curve->tb[curve->actbox-1].w);
+ break;
+ case EXPP_T3D_ATTR_FRAME_HEIGHT:
+ min = 0.0;
+ max = 50.0;
+ param = &(curve->tb[curve->actbox-1].h);
+ break;
+ case EXPP_T3D_ATTR_FRAME_X:
+ min = 0.0;
+ max = 50.0;
+ param = &(curve->tb[curve->actbox-1].x);
+ break;
+ case EXPP_T3D_ATTR_FRAME_Y:
+ min = 0.0;
+ max = 50.0;
+ param = &(curve->tb[curve->actbox-1].y);
+ break;
+
+ default:
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "undefined type in setFloatAttrClamp" );
+ }
+
+ return EXPP_setFloatClamped( value, param, min, max );
+}
+
+/*****************************************************************************/
+/* Python attributes get/set structure: */
+/*****************************************************************************/
+static PyGetSetDef BPy_Text3d_getseters[] = {
+ GENERIC_LIB_GETSETATTR, /* didnt have any attributes, at least lets have the standard ID attrs */
+ {"activeFrame",
+ (getter)Text3d_getActiveFrame, (setter)Text3d_setActiveFrame,
+ "the index of the active text frame",
+ NULL},
+ {"totalFrames",
+ (getter)Text3d_getTotalFrames, (setter)NULL,
+ "the total number of text frames",
+ NULL},
+
+ {"frameWidth",
+ (getter)getFloatAttr, (setter)setFloatAttrClamp,
+ "the width of the active text frame",
+ (void *)EXPP_T3D_ATTR_FRAME_WIDTH},
+ {"frameHeight",
+ (getter)getFloatAttr, (setter)setFloatAttrClamp,
+ "the height of the active text frame",
+ (void *)EXPP_T3D_ATTR_FRAME_HEIGHT},
+ {"frameX",
+ (getter)getFloatAttr, (setter)setFloatAttrClamp,
+ "the X position of the active text frame",
+ (void *)EXPP_T3D_ATTR_FRAME_X},
+ {"frameY",
+ (getter)getFloatAttr, (setter)setFloatAttrClamp,
+ "the Y position of the active text frame",
+ (void *)EXPP_T3D_ATTR_FRAME_Y},
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+/*****************************************************************************/
+/* Python Text3d_Type structure definition: */
+/*****************************************************************************/
+PyTypeObject Text3d_Type = {
+ PyObject_HEAD_INIT( NULL )
+ 0, /* ob_size */
+ "Text3d", /* tp_name */
+ sizeof( BPy_Text3d ), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ /* methods */
+ NULL, /* tp_dealloc */
+ NULL, /* tp_print */
+ NULL, /* tp_getattr */
+ NULL, /* tp_setattr */
+ ( cmpfunc ) Text3d_compare, /* tp_compare */
+ ( reprfunc ) Text3d_repr, /* tp_repr */
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ ( hashfunc ) GenericLib_hash, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_Text3d_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ BPy_Text3d_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+
+/*
+ * Text3d_update( )
+ * method to update display list for a Curve.
+ */
+static PyObject *Text3d_update( BPy_Text3d * self )
+{
+ freedisplist( &self->curve->disp );
+ Py_RETURN_NONE;
+}
+
+/*****************************************************************************/
+/* Function: M_Text3d_New */
+/* Python equivalent: Blender.Text3d.New */
+/*****************************************************************************/
+
+PyObject *M_Text3d_New( PyObject * self, PyObject * args )
+{
+ char *name = NULL;
+ BPy_Text3d *pytext3d; /* for Curve Data object wrapper in Python */
+ Text3d *bltext3d = 0; /* for actual Curve Data we create in Blender */
+
+ if( !PyArg_ParseTuple( args, "|s", &name ) )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_AttributeError,
+ "expected string argument or no argument" ) );
+
+ bltext3d = add_curve( "Text", OB_FONT ); /* first create the Curve Data in Blender */
+ bltext3d->vfont= get_builtin_font();
+ bltext3d->vfont->id.us++;
+ bltext3d->str= MEM_mallocN(12, "str");
+ strcpy(bltext3d->str, "Text");
+ bltext3d->pos= 4;
+
+ bltext3d->strinfo= MEM_callocN(12*sizeof(CharInfo), "strinfo");
+ bltext3d->totbox= bltext3d->actbox= 1;
+ bltext3d->tb= MEM_callocN(MAXTEXTBOX*sizeof(TextBox), "textbox");
+ bltext3d->tb[0].w = bltext3d->tb[0].h = 0.0;
+
+ if( bltext3d == NULL ) /* bail out if add_curve() failed */
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_RuntimeError,
+ "couldn't create Curve Data in Blender" ) );
+
+ /* return user count to zero because add_curve() inc'd it */
+ bltext3d->id.us = 0;
+ /* create python wrapper obj */
+ pytext3d = ( BPy_Text3d * ) PyObject_NEW( BPy_Text3d, &Text3d_Type );
+
+ if( pytext3d == NULL )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_MemoryError,
+ "couldn't create Curve Data object" ) );
+
+ pytext3d->curve = bltext3d; /* link Python curve wrapper to Blender Curve */
+ if( name )
+ rename_id( &bltext3d->id, name );
+
+ Text3d_update ( pytext3d );
+ return ( PyObject * ) pytext3d;
+}
+
+PyObject *M_Text3d_Get( PyObject * self, PyObject * args )
+{
+ char *name = NULL;
+ Text3d *curv_iter;
+ BPy_Text3d *wanted_curv;
+
+ if( !PyArg_ParseTuple( args, "|s", &name ) ) /* expects nothing or a string */
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected string argument" ) );
+ if( name ) { /*a name has been given */
+ /* Use the name to search for the curve requested */
+ wanted_curv = NULL;
+ curv_iter = G.main->curve.first;
+
+ while( ( curv_iter ) && ( wanted_curv == NULL ) ) {
+
+ if( strcmp( name, curv_iter->id.name + 2 ) == 0 ) {
+ wanted_curv = ( BPy_Text3d * )
+ PyObject_NEW( BPy_Text3d, &Text3d_Type );
+ if( wanted_curv )
+ wanted_curv->curve = curv_iter;
+ }
+
+ curv_iter = curv_iter->id.next;
+ }
+
+ if( wanted_curv == NULL ) { /* Requested curve doesn't exist */
+ char error_msg[64];
+ PyOS_snprintf( error_msg, sizeof( error_msg ),
+ "Curve \"%s\" not found", name );
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_NameError, error_msg ) );
+ }
+
+ return ( PyObject * ) wanted_curv;
+ } /* end of if(name) */
+ else {
+ /* no name has been given; return a list of all curves by name. */
+ PyObject *curvlist;
+
+ curv_iter = G.main->curve.first;
+ curvlist = PyList_New( 0 );
+
+ if( curvlist == NULL )
+ return ( EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create PyList" ) );
+
+ while( curv_iter && curv_iter->vfont ) {
+ BPy_Text3d *found_text3d =
+ ( BPy_Text3d * ) PyObject_NEW( BPy_Text3d,
+ &Text3d_Type );
+ found_text3d->curve = curv_iter;
+ PyList_Append( curvlist, ( PyObject * ) found_text3d );
+ Py_DECREF(found_text3d);
+ curv_iter = curv_iter->id.next;
+ }
+ return ( curvlist );
+ }
+}
+
+static PyObject *generate_ModuleIntConstant(char *name, int value)
+{
+ PyObject *constant = PyConstant_New();
+
+ PyConstant_Insert((BPy_constant*)constant,
+ "value", PyInt_FromLong(value));
+ PyConstant_Insert((BPy_constant*)constant,
+ "name", PyString_FromString(name));
+
+ Py_INCREF(constant);
+ return constant;
+}
+
+PyObject *Text3d_Init( void )
+{
+ //module
+ PyObject *submodule, *dict;
+
+ //add module...
+ if( PyType_Ready( &Text3d_Type ) < 0 )
+ return NULL;
+
+ submodule = Py_InitModule3( "Blender.Text3d", M_Text3d_methods,
+ M_Text3D_doc);
+
+ //add constants to module...
+ PyModule_AddObject( submodule, "LEFT",
+ generate_ModuleIntConstant("Text3d.LEFT", CU_LEFT));
+ PyModule_AddObject( submodule, "MIDDLE",
+ generate_ModuleIntConstant("Text3d.MIDDLE", CU_MIDDLE));
+ PyModule_AddObject( submodule, "RIGHT",
+ generate_ModuleIntConstant("Text3d.RIGHT", CU_RIGHT));
+ PyModule_AddObject( submodule, "FLUSH",
+ generate_ModuleIntConstant("Text3d.FLUSH", CU_FLUSH));
+ PyModule_AddObject( submodule, "JUSTIFY",
+ generate_ModuleIntConstant("Text3d.JUSTIFY", CU_JUSTIFY));
+ PyModule_AddObject( submodule, "DRAW3D",
+ generate_ModuleIntConstant("Text3d.DRAW3D", CU_3D));
+ PyModule_AddObject( submodule, "DRAWFRONT",
+ generate_ModuleIntConstant("Text3d.DRAWFRONT", CU_FRONT));
+ PyModule_AddObject( submodule, "DRAWBACK",
+ generate_ModuleIntConstant("Text3d.DRAWBACK", CU_BACK));
+ PyModule_AddObject( submodule, "UVORCO",
+ generate_ModuleIntConstant("Text3d.UVORCO", CU_UV_ORCO));
+ dict = PyModule_GetDict( submodule );
+ PyDict_SetItemString( dict, "Font", Font_Init( ) );
+ return ( submodule );
+}
+
+/****************************************************************************
+ * Function: Text3d_repr
+ * Description: Callback function for the BPy_Text3d type to It
+ * build a meaninful string to represent Text3d objects.
+ *
+ ***************************************************************************/
+
+static PyObject *Text3d_repr( BPy_Text3d * self )
+{
+ /* skip over CU in idname. CUTEXT */
+ return PyString_FromFormat( "[Text3d \"%s\"]",
+ self->curve->id.name + 2 );
+}
+
+/****************************************************************************
+ * Function: Text3d_compare
+ * Description: Callback function for the BPy_Text3d type to Compare 2 types
+ *
+ ***************************************************************************/
+
+/* mat_a==mat_b or mat_a!=mat_b*/
+static int Text3d_compare( BPy_Text3d * a, BPy_Text3d * b )
+{
+ return ( a->curve == b->curve) ? 0 : -1;
+}
+
+struct Text3d *Text3d_FromPyObject( PyObject * py_obj )
+{
+ BPy_Text3d *blen_obj;
+
+ blen_obj = ( BPy_Text3d * ) py_obj;
+ return ((struct Text3d*) blen_obj->curve );
+}
+
+static PyObject *return_ModuleConstant( char *constant_name){
+
+ PyObject *module = NULL, *dict = NULL, *constant = NULL;;
+
+ module = PyImport_AddModule("Blender.Text3d");
+ if(!module){ //null = error returning module
+ return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "error encountered with returning module constant..." ) );
+ }
+ dict = PyModule_GetDict(module); //never fails
+
+ constant = PyDict_GetItemString(dict, constant_name);
+ if(!constant){ //null = key not found
+ return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "error encountered with returning module constant..." ) );
+ }
+
+ return EXPP_incr_ret( constant );
+}
+
+static PyObject *Text3d_getName( BPy_Text3d * self )
+{
+ return Curve_getName( (BPy_Curve*)self );
+}
+
+static PyObject *Text3d_setName( BPy_Text3d * self, PyObject * args )
+{
+ return Curve_setName( (BPy_Curve*)self,args );
+}
+
+static PyObject *Text3d_setText( BPy_Text3d * self, PyObject * value )
+{
+ char *text = PyString_AsString(value);
+
+ if( !text )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected string argument" );
+
+ /*
+ * If the text is currently being edited, then we have to put the
+ * text into the edit buffer.
+ */
+
+ if( G.obedit && G.obedit->data == self->curve ) {
+ short qual = G.qual;
+ G.qual = 0; /* save key qualifier, then clear it */
+ self->curve->pos = self->curve->len = 0;
+ while ( *text )
+ do_textedit( 0, 0, *text++ );
+ G.qual = qual;
+ } else {
+ short len = (short)strlen(text);
+ MEM_freeN( self->curve->str );
+ self->curve->str = MEM_callocN( len+sizeof(wchar_t), "str" );
+ strcpy( self->curve->str, text );
+ self->curve->pos = len;
+ self->curve->len = len;
+
+ if( self->curve->strinfo )
+ MEM_freeN( self->curve->strinfo );
+ /* don't know why this is +4, just duplicating load_editText() */
+ self->curve->strinfo = MEM_callocN( (len+4) *sizeof(CharInfo),
+ "strinfo");
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *Text3d_getText( BPy_Text3d * self )
+{
+ if( self->curve->str )
+ return PyString_FromString( self->curve->str );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject* Text3d_getDrawMode(BPy_Text3d* self)
+{
+ PyObject *tuple = NULL;
+ int size = 0, pos = 0;
+
+ //get the tuple size
+ if(self->curve->flag & CU_3D)
+ size++;
+ if (self->curve->flag & CU_FRONT)
+ size++;
+ if (self->curve->flag & CU_BACK)
+ size++;
+
+ //generate tuple
+ tuple = PyTuple_New(size);
+
+ //load tuple
+ if(self->curve->flag & CU_3D){
+ PyTuple_SET_ITEM( tuple, pos, return_ModuleConstant("DRAW3D"));
+ pos++;
+ }
+ if (self->curve->flag & CU_FRONT){
+ PyTuple_SET_ITEM( tuple, pos, return_ModuleConstant("DRAWFRONT"));
+ pos++;
+ }
+ if (self->curve->flag & CU_BACK){
+ PyTuple_SET_ITEM( tuple, pos, return_ModuleConstant("DRAWBACK"));
+ pos++;
+ }
+
+ return tuple;
+}
+
+static PyObject* Text3d_setDrawMode(BPy_Text3d* self,PyObject* args)
+{
+ PyObject *listObject = NULL;
+ int size, i;
+ short temp;
+
+ size = PySequence_Length(args);
+ if ( size == 1 ) {
+ listObject = PySequence_GetItem(args, 0);
+ if ( PySequence_Check(listObject) ) {
+ size = PySequence_Length(listObject);
+ }else{ //not a sequence but maybe a single constant
+ Py_INCREF(args);
+ listObject = args;
+ }
+ } else { //a list of objects (non-sequence)
+ Py_INCREF(args);
+ listObject = args;
+ }
+ if ( size > 3 || size < 1 ) {
+ //bad number of arguments
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "too many parameters - expects 1 - 3 constants" ) );
+ }
+ //clear bits
+ temp = self->curve->flag; //in case of failure
+ if(self->curve->flag & CU_3D)
+ self->curve->flag &= ~CU_3D;
+ if(self->curve->flag & CU_FRONT)
+ self->curve->flag &= ~CU_FRONT;
+ if(self->curve->flag & CU_BACK)
+ self->curve->flag &= ~CU_BACK;
+
+ //parse and set bits
+ for (i = 0; i < size; i++) {
+ PyObject *v;
+ int value;
+
+ v = PySequence_GetItem(listObject, i);
+ if (v == NULL) { //unable to return item - null = failure
+ Py_DECREF(listObject);
+ self->curve->flag = temp;
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "unable to parse list" ) );
+ }
+ if( !BPy_Constant_Check(v)){
+ Py_DECREF(listObject);
+ Py_DECREF(v);
+ self->curve->flag = temp;
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "bad argument types - expects module constants" ) );
+ }
+ value = PyInt_AS_LONG(PyDict_GetItemString(
+ ((BPy_constant*)v)->dict, "value"));
+ self->curve->flag |= (short)value;
+ Py_DECREF(v);
+ }
+ Py_DECREF(listObject);
+ Py_RETURN_NONE;
+}
+
+static PyObject* Text3d_getUVorco(BPy_Text3d* self)
+{
+ if(self->curve->flag & CU_UV_ORCO)
+ return EXPP_incr_ret_True();
+ else
+ return EXPP_incr_ret_False();
+}
+
+static PyObject* Text3d_setUVorco(BPy_Text3d* self,PyObject* args)
+{
+ int flag;
+
+ if( !PyArg_ParseTuple( args, "i", &flag ) )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected TRUE or FALSE (1 or 0)" );
+
+ if( flag < 0 || flag > 1 )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected TRUE or FALSE (1 or 0)" );
+
+ if( flag )
+ self->curve->flag |= CU_UV_ORCO;
+ else
+ self->curve->flag &= ~CU_UV_ORCO;
+
+ Py_RETURN_NONE;
+}
+
+static PyObject* Text3d_getBevelAmount(BPy_Text3d* self)
+{
+ return Curve_getBevresol((BPy_Curve*)self);
+}
+
+static PyObject* Text3d_setBevelAmount(BPy_Text3d* self,PyObject* args)
+{
+ return Curve_setBevresol((BPy_Curve*)self,args);
+}
+
+static PyObject *Text3d_getDefaultResolution( BPy_Text3d * self )
+{
+ return Curve_getResolu( (BPy_Curve*)self );
+}
+
+static PyObject *Text3d_setDefaultResolution( BPy_Text3d * self, PyObject * args )
+{
+ return Curve_setResolu( (BPy_Curve*)self,args );
+}
+
+static PyObject *Text3d_getWidth( BPy_Text3d * self )
+{
+ return Curve_getWidth( (BPy_Curve*)self );
+}
+
+static PyObject *Text3d_setWidth( BPy_Text3d * self, PyObject * args )
+{
+ return Curve_setWidth( (BPy_Curve*)self,args );
+}
+
+static PyObject *Text3d_getExtrudeDepth( BPy_Text3d * self )
+{
+ return Curve_getExt1( (BPy_Curve*)self );
+}
+
+static PyObject *Text3d_setExtrudeDepth( BPy_Text3d * self, PyObject * args )
+{
+ return Curve_setExt1( (BPy_Curve*)self,args );
+}
+
+static PyObject *Text3d_getExtrudeBevelDepth( BPy_Text3d * self )
+{
+ return Curve_getExt2( (BPy_Curve*)self );
+}
+
+static PyObject *Text3d_setExtrudeBevelDepth( BPy_Text3d * self, PyObject * args )
+{
+ return Curve_setExt2( (BPy_Curve*)self,args );
+}
+
+static PyObject *Text3d_getShear( BPy_Text3d * self )
+{
+ PyObject *attr = PyFloat_FromDouble( (double) self->curve->shear );
+
+ if( attr )
+ return attr;
+
+ return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't get Curve.shear attribute" ) );
+}
+
+static PyObject *Text3d_setShear( BPy_Text3d * self, PyObject * args )
+{
+ float value;
+
+ if( !PyArg_ParseTuple( args, "f", &value ) )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected float argument" ) );
+
+ if(value > 1.0f || value < -1.0f)
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "acceptable values are between 1.0 and -1.0" ) );
+ self->curve->shear = value;
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Text3d_getSize( BPy_Text3d * self )
+{
+ PyObject *attr = PyFloat_FromDouble( (double) self->curve->fsize );
+
+ if( attr )
+ return attr;
+
+ return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't get Curve.fsize attribute" ) );
+}
+
+static PyObject *Text3d_setSize( BPy_Text3d * self, PyObject * args )
+{
+ float value;
+
+ if( !PyArg_ParseTuple( args, "f", &value ) )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected float argument" ) );
+
+ if(value > 10.0f || value < 0.1f)
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "acceptable values are between 10.0 and 0.1" ) );
+ self->curve->fsize = value;
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Text3d_getLineSeparation( BPy_Text3d * self )
+{
+ PyObject *attr = PyFloat_FromDouble( (double) self->curve->linedist );
+
+ if( attr )
+ return attr;
+
+ return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't get Curve.linedist attribute" ) );
+}
+
+static PyObject *Text3d_setLineSeparation( BPy_Text3d * self, PyObject * args )
+{
+ float value;
+
+ if( !PyArg_ParseTuple( args, "f", &value ) )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected float argument" ) );
+
+ if(value > 10.0f || value < 0.0f)
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "acceptable values are between 10.0 and 0.0" ) );
+ self->curve->linedist = value;
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Text3d_getSpacing( BPy_Text3d * self )
+{
+ PyObject *attr = PyFloat_FromDouble( (double) self->curve->spacing );
+
+ if( attr )
+ return attr;
+
+ return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't get Curve.spacing attribute" ) );
+}
+
+static PyObject *Text3d_setSpacing( BPy_Text3d * self, PyObject * args )
+{
+ float value;
+
+ if( !PyArg_ParseTuple( args, "f", &value ) )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected float argument" ) );
+
+ if(value > 10.0f || value < 0.0f)
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "acceptable values are between 10.0 and 0.0" ) );
+ self->curve->spacing = value;
+
+ Py_RETURN_NONE;
+}
+static PyObject *Text3d_getXoffset( BPy_Text3d * self )
+{
+ PyObject *attr = PyFloat_FromDouble( (double) self->curve->xof );
+
+ if( attr )
+ return attr;
+
+ return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't get Curve.xof attribute" ) );
+}
+
+static PyObject *Text3d_setXoffset( BPy_Text3d * self, PyObject * args )
+{
+ float value;
+
+ if( !PyArg_ParseTuple( args, "f", &value ) )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected float argument" ) );
+
+ if(value > 50.0f || value < -50.0f)
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "acceptable values are between 50.0 and -50.0" ) );
+ self->curve->xof = value;
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Text3d_getYoffset( BPy_Text3d * self )
+{
+ PyObject *attr = PyFloat_FromDouble( (double) self->curve->yof );
+
+ if( attr )
+ return attr;
+
+ return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't get Curve.yof attribute" ) );
+}
+
+static PyObject *Text3d_setYoffset( BPy_Text3d * self, PyObject * args )
+{
+ float value;
+
+ if( !PyArg_ParseTuple( args, "f", &value ) )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected float argument" ) );
+
+ if(value > 50.0f || value < -50.0f)
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "acceptable values are between 50.0 and -50.0" ) );
+ self->curve->yof = value;
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Text3d_getAlignment( BPy_Text3d * self )
+{
+ if(self->curve->spacemode == CU_LEFT){
+ return return_ModuleConstant("LEFT");
+ }else if (self->curve->spacemode == CU_MIDDLE){
+ return return_ModuleConstant("MIDDLE");
+ }else if (self->curve->spacemode == CU_RIGHT){
+ return return_ModuleConstant("RIGHT");
+ }else if (self->curve->spacemode == CU_FLUSH){
+ return return_ModuleConstant("FLUSH");
+ }else if (self->curve->spacemode == CU_JUSTIFY){
+ return return_ModuleConstant("JUSTIFY");
+ }
+
+ return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't get Curve.spacemode attribute" ) );
+}
+
+static PyObject *Text3d_setAlignment( BPy_Text3d * self, PyObject * args )
+{
+ BPy_constant *constant;
+ int value;
+
+ if( !PyArg_ParseTuple( args, "O!", &constant_Type, &constant ) )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected module constant" ) );
+
+ value = PyInt_AS_LONG(PyDict_GetItemString(constant->dict, "value"));
+ self->curve->spacemode = (short)value;
+
+ Py_RETURN_NONE;
+}
+
+
+/*****************************************************************************
+ * Function: Text3d_CreatePyObject
+ * Description: This function will create a new BPy_Text3d from an existing
+ * Blender structure.
+ *****************************************************************************/
+
+PyObject *Text3d_CreatePyObject( Text3d * text3d )
+{
+ BPy_Text3d *pytext3d;
+
+ pytext3d = ( BPy_Text3d * ) PyObject_NEW( BPy_Text3d, &Text3d_Type );
+
+ if( !pytext3d )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create BPy_Text3d object" );
+
+ pytext3d->curve = text3d;
+
+ return ( PyObject * ) pytext3d;
+}
+
+static PyObject *Text3d_getFont( BPy_Text3d * self )
+{
+ if (self->curve)
+ return Font_CreatePyObject (self->curve->vfont);
+ else
+ Py_RETURN_NONE;
+}
+
+static PyObject *Text3d_setFont( BPy_Text3d * self, PyObject * args )
+{
+ BPy_Font *pyobj= NULL;
+ VFont *vf; //, *vfont;
+ if( !PyArg_ParseTuple( args, "|O!",&Font_Type, &pyobj) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a string" );
+ if( !pyobj ) {
+ // pyobj= M_Text3d_LoadFont (self, Py_BuildValue("(s)", "<builtin>"));
+ self->curve->vfont= get_builtin_font ();
+ Py_RETURN_NONE;
+ }
+ vf= exist_vfont(pyobj->font->name);
+ if (vf) {
+ id_us_plus((ID *)vf);
+ self->curve->vfont->id.us--;
+ self->curve->vfont= vf;
+ }
+ else {
+ vf= load_vfont (pyobj->font->name);
+ if (vf) {
+ id_us_plus((ID *)vf);
+ self->curve->vfont->id.us--;
+ self->curve->vfont= vf;
+ }
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *Text3d_addFrame( BPy_Text3d * self )
+{
+ Curve *cu = self->curve;
+
+ if (cu->totbox >= 256)
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "limited to 256 frames" );
+
+ cu->totbox++;
+ cu->tb[cu->totbox-1]= cu->tb[cu->totbox-2];
+ Py_RETURN_NONE;
+}
+
+static PyObject *Text3d_removeFrame( BPy_Text3d * self, PyObject * args )
+{
+ Curve *cu = self->curve;
+ int index, i;
+
+ if (cu->totbox == 1)
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "cannot remove the last frame" );
+
+ index = cu->totbox-1;
+
+ if( !PyArg_ParseTuple( args, "|i", &index ) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "expected an int" );
+
+ if (index < 0 || index >= cu->totbox )
+ return EXPP_ReturnPyObjError( PyExc_IndexError,
+ "index out of range" );
+
+ for (i = index; i < cu->totbox; i++) cu->tb[i]= cu->tb[i+1];
+ cu->totbox--;
+ cu->actbox--;
+ Py_RETURN_NONE;
+}
+
+
+PyObject *M_Text3d_LoadFont( PyObject * self, PyObject * value )
+{
+ char *fontfile= PyString_AsString(value);
+ FILE *file= NULL;
+ VFont *vf= NULL;
+
+ if( !fontfile )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a string" );
+ vf= exist_vfont(fontfile);
+ if( vf )
+ return Font_CreatePyObject( vf );
+ /* No use for that -- lukep
+ else
+ vf= NULL;
+ */
+ file= fopen( fontfile, "r");
+
+ if( file || !strcmp (fontfile, "<builtin>") ) {
+ load_vfont( fontfile );
+ if(file) fclose( file );
+ vf = exist_vfont( fontfile );
+ if(vf)
+ return Font_CreatePyObject( vf );
+ Py_RETURN_NONE;
+ }
+
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "string isn't filename or fontpath" );
+}
+
diff --git a/source/blender/python/api2_2x/Text3d.h b/source/blender/python/api2_2x/Text3d.h
new file mode 100644
index 00000000000..6486278f20d
--- /dev/null
+++ b/source/blender/python/api2_2x/Text3d.h
@@ -0,0 +1,56 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Joilnen Leite
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_TEXT3D_H
+#define EXPP_TEXT3D_H
+
+#include <Python.h>
+#include "DNA_curve_types.h"
+
+extern PyTypeObject Text3d_Type;
+
+#define BPy_Text3d_Check(v) ((v)->ob_type==&Text3d_Type)
+typedef Curve Text3d;
+
+/*prototypes*/
+PyObject *Text3d_Init( void );
+struct Text3d *Text3d_FromPyObject( PyObject * py_obj );
+PyObject *Text3d_CreatePyObject( Text3d* text3d );
+
+/* Python BPy_Text3d structure definition */
+typedef struct {
+ PyObject_HEAD /* required py macro */
+ Text3d * curve;
+} BPy_Text3d;
+
+#endif /* EXPP_TEXT3D_H */
+
diff --git a/source/blender/python/api2_2x/Texture.c b/source/blender/python/api2_2x/Texture.c
new file mode 100644
index 00000000000..34906757ebd
--- /dev/null
+++ b/source/blender/python/api2_2x/Texture.c
@@ -0,0 +1,2501 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Alex Mole, Nathan Letwory, Joilnen B. Leite, Ken Hughes
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+#include "Texture.h" /*This must come first*/
+
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_idprop.h"
+#include "BKE_library.h"
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
+
+#include "BLI_blenlib.h"
+
+#include "DNA_object_types.h"
+#include "DNA_material_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_texture_types.h"
+
+#include "MTex.h"
+#include "Image.h"
+#include "Ipo.h"
+#include "IDProp.h"
+#include "constant.h"
+#include "blendef.h"
+#include "gen_utils.h"
+#include "gen_library.h"
+
+#include "vector.h" /* for Texture_evaluate(vec) */
+#include "Material.h" /* for EXPP_Colorband_fromPyList and EXPP_PyList_fromColorband */
+#include "RE_shader_ext.h"
+
+/*****************************************************************************/
+/* Blender.Texture constants */
+/*****************************************************************************/
+#define EXPP_TEX_TYPE_NONE 0
+
+#define EXPP_TEX_TYPE_MIN EXPP_TEX_TYPE_NONE
+#define EXPP_TEX_TYPE_MAX TEX_DISTNOISE
+
+#define EXPP_TEX_ANIMFRAME_MIN 0
+#define EXPP_TEX_ANIMFRAME_MAX ((int)MAXFRAMEF)
+#define EXPP_TEX_ANIMLEN_MIN 0
+#define EXPP_TEX_ANIMLEN_MAX ((int)(MAXFRAMEF)/2)
+#define EXPP_TEX_ANIMMONSTART_MIN 0
+#define EXPP_TEX_ANIMMONSTART_MAX ((int)MAXFRAMEF)
+#define EXPP_TEX_ANIMMONDUR_MIN 0
+#define EXPP_TEX_ANIMMONDUR_MAX 250
+#define EXPP_TEX_ANIMOFFSET_MIN -((int)MAXFRAMEF)
+#define EXPP_TEX_ANIMOFFSET_MAX ((int)MAXFRAMEF)
+#define EXPP_TEX_ANIMSTART_MIN 1
+#define EXPP_TEX_ANIMSTART_MAX ((int)MAXFRAMEF)
+#define EXPP_TEX_FIEIMA_MIN 1
+#define EXPP_TEX_FIEIMA_MAX 200
+#define EXPP_TEX_NOISEDEPTH_MIN 0
+#define EXPP_TEX_NOISEDEPTH_MAX 6
+/* max depth is different for magic type textures */
+#define EXPP_TEX_NOISEDEPTH_MAX_MAGIC 10
+#define EXPP_TEX_REPEAT_MIN 1
+#define EXPP_TEX_REPEAT_MAX 512
+
+#define EXPP_TEX_FILTERSIZE_MIN 0.1f
+#define EXPP_TEX_FILTERSIZE_MAX 25.0f
+#define EXPP_TEX_NOISESIZE_MIN 0.0001f
+#define EXPP_TEX_NOISESIZE_MAX 2.0f
+#define EXPP_TEX_BRIGHTNESS_MIN 0.0f
+#define EXPP_TEX_BRIGHTNESS_MAX 2.0f
+#define EXPP_TEX_CONTRAST_MIN 0.01f
+#define EXPP_TEX_CONTRAST_MAX 5.0f
+#define EXPP_TEX_CROP_MIN -10.0f
+#define EXPP_TEX_CROP_MAX 10.0f
+#define EXPP_TEX_RGBCOL_MIN 0.0f
+#define EXPP_TEX_RGBCOL_MAX 2.0f
+#define EXPP_TEX_TURBULENCE_MIN 0.0f
+#define EXPP_TEX_TURBULENCE_MAX 200.0f
+#define EXPP_TEX_MH_G_MIN 0.0001f
+#define EXPP_TEX_MH_G_MAX 2.0f
+#define EXPP_TEX_LACUNARITY_MIN 0.0f
+#define EXPP_TEX_LACUNARITY_MAX 6.0f
+#define EXPP_TEX_OCTS_MIN 0.0f
+#define EXPP_TEX_OCTS_MAX 8.0f
+#define EXPP_TEX_ISCALE_MIN 0.0f
+#define EXPP_TEX_ISCALE_MAX 10.0f
+#define EXPP_TEX_EXP_MIN 0.010f
+#define EXPP_TEX_EXP_MAX 10.0f
+#define EXPP_TEX_WEIGHT1_MIN -2.0f
+#define EXPP_TEX_WEIGHT1_MAX 2.0f
+#define EXPP_TEX_WEIGHT2_MIN -2.0f
+#define EXPP_TEX_WEIGHT2_MAX 2.0f
+#define EXPP_TEX_WEIGHT3_MIN -2.0f
+#define EXPP_TEX_WEIGHT3_MAX 2.0f
+#define EXPP_TEX_WEIGHT4_MIN -2.0f
+#define EXPP_TEX_WEIGHT4_MAX 2.0f
+#define EXPP_TEX_DISTAMNT_MIN 0.0f
+#define EXPP_TEX_DISTAMNT_MAX 10.0f
+
+/* i can't find these defined anywhere- they're just taken from looking at */
+/* the button creation code in source/blender/src/buttons_shading.c */
+/* cloud stype */
+#define EXPP_TEX_STYPE_CLD_DEFAULT 0
+#define EXPP_TEX_STYPE_CLD_COLOR 1
+/* wood stype */
+#define EXPP_TEX_STYPE_WOD_BANDS 0
+#define EXPP_TEX_STYPE_WOD_RINGS 1
+#define EXPP_TEX_STYPE_WOD_BANDNOISE 2
+#define EXPP_TEX_STYPE_WOD_RINGNOISE 3
+/* magic stype */
+#define EXPP_TEX_STYPE_MAG_DEFAULT 0
+/* marble stype */
+#define EXPP_TEX_STYPE_MBL_SOFT 0
+#define EXPP_TEX_STYPE_MBL_SHARP 1
+#define EXPP_TEX_STYPE_MBL_SHARPER 2
+/* blend stype */
+#define EXPP_TEX_STYPE_BLN_LIN 0
+#define EXPP_TEX_STYPE_BLN_QUAD 1
+#define EXPP_TEX_STYPE_BLN_EASE 2
+#define EXPP_TEX_STYPE_BLN_DIAG 3
+#define EXPP_TEX_STYPE_BLN_SPHERE 4
+#define EXPP_TEX_STYPE_BLN_HALO 5
+/* stucci stype */
+#define EXPP_TEX_STYPE_STC_PLASTIC 0
+#define EXPP_TEX_STYPE_STC_WALLIN 1
+#define EXPP_TEX_STYPE_STC_WALLOUT 2
+/* noise stype */
+#define EXPP_TEX_STYPE_NSE_DEFAULT 0
+/* image stype */
+#define EXPP_TEX_STYPE_IMG_DEFAULT 0
+/* plug-in stype */
+#define EXPP_TEX_STYPE_PLG_DEFAULT 0
+/* envmap stype */
+#define EXPP_TEX_STYPE_ENV_STATIC 0
+#define EXPP_TEX_STYPE_ENV_ANIM 1
+#define EXPP_TEX_STYPE_ENV_LOAD 2
+/* musgrave stype */
+#define EXPP_TEX_STYPE_MUS_MFRACTAL 0
+#define EXPP_TEX_STYPE_MUS_RIDGEDMF 1
+#define EXPP_TEX_STYPE_MUS_HYBRIDMF 2
+#define EXPP_TEX_STYPE_MUS_FBM 3
+#define EXPP_TEX_STYPE_MUS_HTERRAIN 4
+/* voronoi stype */
+#define EXPP_TEX_STYPE_VN_INT 0
+#define EXPP_TEX_STYPE_VN_COL1 1
+#define EXPP_TEX_STYPE_VN_COL2 2
+#define EXPP_TEX_STYPE_VN_COL3 3
+
+#define EXPP_TEX_EXTEND_MIN TEX_EXTEND
+#define EXPP_TEX_EXTEND_MAX TEX_CHECKER
+
+#define EXPP_TEX_NOISE_SINE 0
+#define EXPP_TEX_NOISE_SAW 1
+#define EXPP_TEX_NOISE_TRI 2
+#define EXPP_TEX_NOISEBASIS2 0xffff
+
+/****************************************************************************/
+/* Texture String->Int maps */
+/****************************************************************************/
+
+static const EXPP_map_pair tex_type_map[] = {
+ {"None", EXPP_TEX_TYPE_NONE},
+ {"Clouds", TEX_CLOUDS},
+ {"Wood", TEX_WOOD},
+ {"Marble", TEX_MARBLE},
+ {"Magic", TEX_MAGIC},
+ {"Blend", TEX_BLEND},
+ {"Stucci", TEX_STUCCI},
+ {"Noise", TEX_NOISE},
+ {"Image", TEX_IMAGE},
+ {"Plugin", TEX_PLUGIN},
+ {"EnvMap", TEX_ENVMAP},
+ {"Musgrave", TEX_MUSGRAVE},
+ {"Voronoi", TEX_VORONOI},
+ {"DistortedNoise", TEX_DISTNOISE},
+ {NULL, 0}
+};
+
+static const EXPP_map_pair tex_flag_map[] = {
+/* NOTE "CheckerOdd" and "CheckerEven" are new */
+ {"ColorBand", TEX_COLORBAND },
+ {"FlipBlend", TEX_FLIPBLEND},
+ {"NegAlpha", TEX_NEGALPHA},
+ {"CheckerOdd",TEX_CHECKER_ODD},
+ {"CheckerEven",TEX_CHECKER_EVEN},
+ {"PreviewAlpha",TEX_PRV_ALPHA},
+ {"RepeatXMirror",TEX_REPEAT_XMIR},
+ {"RepeatYMirror",TEX_REPEAT_YMIR},
+ {NULL, 0}
+};
+
+/* NOTE: flags moved to image... */
+static const EXPP_map_pair tex_imageflag_map[] = {
+ {"InterPol", TEX_INTERPOL},
+ {"UseAlpha", TEX_USEALPHA},
+ {"MipMap", TEX_MIPMAP},
+ {"Rot90", TEX_IMAROT},
+ {"CalcAlpha", TEX_CALCALPHA},
+ {"NormalMap", TEX_NORMALMAP},
+ {NULL, 0}
+};
+
+static const EXPP_map_pair tex_extend_map[] = {
+ {"Extend", TEX_EXTEND},
+ {"Clip", TEX_CLIP},
+ {"ClipCube", TEX_CLIPCUBE},
+ {"Repeat", TEX_REPEAT},
+/* NOTE "Checker" is new */
+ {"Checker", TEX_CHECKER},
+ {NULL, 0}
+};
+
+/* array of maps for stype */
+static const EXPP_map_pair tex_stype_default_map[] = {
+ {"Default", 0},
+ {NULL, 0}
+};
+static const EXPP_map_pair tex_stype_clouds_map[] = {
+ {"Default", 0},
+ {"CloudDefault", EXPP_TEX_STYPE_CLD_DEFAULT},
+ {"CloudColor", EXPP_TEX_STYPE_CLD_COLOR},
+ {NULL, 0}
+};
+static const EXPP_map_pair tex_stype_wood_map[] = {
+ {"Default", 0},
+ {"WoodBands", EXPP_TEX_STYPE_WOD_BANDS},
+ {"WoodRings", EXPP_TEX_STYPE_WOD_RINGS},
+ {"WoodBandNoise", EXPP_TEX_STYPE_WOD_BANDNOISE},
+ {"WoodRingNoise", EXPP_TEX_STYPE_WOD_RINGNOISE},
+ {NULL, 0}
+};
+static const EXPP_map_pair tex_stype_marble_map[] = {
+ {"Default", 0},
+ {"MarbleSoft", EXPP_TEX_STYPE_MBL_SOFT},
+ {"MarbleSharp", EXPP_TEX_STYPE_MBL_SHARP},
+ {"MarbleSharper", EXPP_TEX_STYPE_MBL_SHARPER},
+ {NULL, 0}
+};
+static const EXPP_map_pair tex_stype_blend_map[] = {
+ {"Default", 0},
+ {"BlendLin", EXPP_TEX_STYPE_BLN_LIN},
+ {"BlendQuad", EXPP_TEX_STYPE_BLN_QUAD},
+ {"BlendEase", EXPP_TEX_STYPE_BLN_EASE},
+ {"BlendDiag", EXPP_TEX_STYPE_BLN_DIAG},
+ {"BlendSphere", EXPP_TEX_STYPE_BLN_SPHERE},
+ {"BlendHalo", EXPP_TEX_STYPE_BLN_HALO},
+ {NULL, 0}
+};
+static const EXPP_map_pair tex_stype_stucci_map[] = {
+ {"Default", 0},
+ {"StucciPlastic", EXPP_TEX_STYPE_STC_PLASTIC},
+ {"StucciWallIn", EXPP_TEX_STYPE_STC_WALLIN},
+ {"StucciWallOut", EXPP_TEX_STYPE_STC_WALLOUT},
+ {NULL, 0}
+};
+static const EXPP_map_pair tex_stype_envmap_map[] = {
+ {"Default", 0},
+ {"EnvmapStatic", EXPP_TEX_STYPE_ENV_STATIC},
+ {"EnvmapAnim", EXPP_TEX_STYPE_ENV_ANIM},
+ {"EnvmapLoad", EXPP_TEX_STYPE_ENV_LOAD},
+ {NULL, 0}
+};
+
+static const EXPP_map_pair tex_stype_musg_map[] = {
+ {"Default", 0},
+ {"MultiFractal", EXPP_TEX_STYPE_MUS_MFRACTAL},
+ {"HeteroTerrain", EXPP_TEX_STYPE_MUS_HTERRAIN},
+ {"RidgedMultiFractal", EXPP_TEX_STYPE_MUS_RIDGEDMF},
+ {"HybridMultiFractal", EXPP_TEX_STYPE_MUS_HYBRIDMF},
+ {"fBM", EXPP_TEX_STYPE_MUS_FBM},
+ {NULL, 0}
+};
+
+static const EXPP_map_pair tex_stype_distortednoise_map[] = {
+ {"Default", 0},
+ {"BlenderOriginal", TEX_BLENDER},
+ {"OriginalPerlin", TEX_STDPERLIN},
+ {"ImprovedPerlin", TEX_NEWPERLIN},
+ {"VoronoiF1", TEX_VORONOI_F1},
+ {"VoronoiF2", TEX_VORONOI_F2},
+ {"VoronoiF3", TEX_VORONOI_F3},
+ {"VoronoiF4", TEX_VORONOI_F4},
+ {"VoronoiF2-F1", TEX_VORONOI_F2F1},
+ {"VoronoiCrackle", TEX_VORONOI_CRACKLE},
+ {"CellNoise", TEX_CELLNOISE},
+ {NULL, 0}
+};
+
+static const EXPP_map_pair tex_stype_voronoi_map[] = {
+ {"Default", 0},
+ {"Int", EXPP_TEX_STYPE_VN_INT},
+ {"Col1", EXPP_TEX_STYPE_VN_COL1},
+ {"Col2", EXPP_TEX_STYPE_VN_COL2},
+ {"Col3", EXPP_TEX_STYPE_VN_COL3},
+ {NULL, 0}
+};
+
+static const EXPP_map_pair tex_distance_voronoi_map[] = {
+ {"Default", 0},
+ {"Distance", TEX_DISTANCE},
+ {"DistanceSquared", TEX_DISTANCE_SQUARED},
+ {"Manhattan", TEX_MANHATTAN},
+ {"Chebychev", TEX_CHEBYCHEV},
+ {"MinkovskyHalf", TEX_MINKOVSKY_HALF},
+ {"MinkovskyFour", TEX_MINKOVSKY_FOUR},
+ {"Minkovsky", TEX_MINKOVSKY},
+ {NULL, 0}
+};
+
+static const EXPP_map_pair *tex_stype_map[] = {
+ tex_stype_default_map, /* none */
+ tex_stype_clouds_map,
+ tex_stype_wood_map,
+ tex_stype_marble_map,
+ tex_stype_default_map, /* magic */
+ tex_stype_blend_map,
+ tex_stype_stucci_map,
+ tex_stype_default_map, /* noise */
+ tex_stype_default_map, /* image */
+ tex_stype_default_map, /* plugin */
+ tex_stype_envmap_map,
+ tex_stype_musg_map, /* musgrave */
+ tex_stype_voronoi_map, /* voronoi */
+ tex_stype_distortednoise_map, /* distorted noise */
+ tex_distance_voronoi_map
+};
+
+/*****************************************************************************/
+/* Python API function prototypes for the Texture module. */
+/*****************************************************************************/
+static PyObject *M_Texture_New( PyObject * self, PyObject * args,
+ PyObject * keywords );
+static PyObject *M_Texture_Get( PyObject * self, PyObject * args );
+
+/*****************************************************************************/
+/* The following string definitions are used for documentation strings. */
+/* In Python these will be written to the console when doing a */
+/* Blender.Texture.__doc__ */
+/*****************************************************************************/
+static char M_Texture_doc[] = "The Blender Texture module\n\
+\n\
+This module provides access to **Texture** objects in Blender\n";
+
+static char M_Texture_New_doc[] = "Texture.New (name = 'Tex'):\n\
+ Return a new Texture object with the given type and name.";
+
+static char M_Texture_Get_doc[] = "Texture.Get (name = None):\n\
+ Return the texture with the given 'name', None if not found, or\n\
+ Return a list with all texture objects in the current scene,\n\
+ if no argument was given.";
+
+/*****************************************************************************/
+/* Python method structure definition for Blender.Texture module: */
+/*****************************************************************************/
+struct PyMethodDef M_Texture_methods[] = {
+ {"New", ( PyCFunction ) M_Texture_New, METH_VARARGS | METH_KEYWORDS,
+ M_Texture_New_doc},
+ {"Get", M_Texture_Get, METH_VARARGS, M_Texture_Get_doc},
+ {NULL, NULL, 0, NULL}
+};
+
+/*****************************************************************************/
+/* Python BPy_Texture methods declarations: */
+/*****************************************************************************/
+#define GETFUNC(name) static PyObject *Texture_##name(BPy_Texture *self)
+#define OLDSETFUNC(name) static PyObject *Texture_old##name(BPy_Texture *self, \
+ PyObject *args)
+#define SETFUNC(name) static int Texture_##name(BPy_Texture *self, \
+ PyObject *value)
+#if 0
+GETFUNC( getExtend );
+GETFUNC( getImage );
+GETFUNC( getType );
+GETFUNC( getSType );
+GETFUNC( clearIpo );
+GETFUNC( getAnimMontage );
+GETFUNC( getAnimLength );
+SETFUNC( setAnimLength );
+SETFUNC( setAnimMontage );
+#endif
+
+GETFUNC( oldgetSType );
+GETFUNC( oldgetType );
+
+GETFUNC( clearIpo );
+GETFUNC( getAnimFrames );
+GETFUNC( getAnimOffset );
+GETFUNC( getAnimStart );
+GETFUNC( getBrightness );
+GETFUNC( getContrast );
+GETFUNC( getCrop );
+GETFUNC( getDistAmnt );
+GETFUNC( getDistMetric );
+GETFUNC( getExp );
+GETFUNC( getExtend );
+GETFUNC( getIntExtend );
+GETFUNC( getFieldsPerImage );
+GETFUNC( getFilterSize );
+GETFUNC( getFlags );
+GETFUNC( getHFracDim );
+GETFUNC( getImage );
+GETFUNC( getIpo );
+GETFUNC( getIScale );
+GETFUNC( getLacunarity );
+GETFUNC( getNoiseBasis );
+GETFUNC( getNoiseDepth );
+GETFUNC( getNoiseSize );
+GETFUNC( getNoiseType );
+GETFUNC( getOcts );
+GETFUNC( getRepeat );
+GETFUNC( getRGBCol );
+GETFUNC( getSType );
+GETFUNC( getTurbulence );
+GETFUNC( getType );
+GETFUNC( getWeight1 );
+GETFUNC( getWeight2 );
+GETFUNC( getWeight3 );
+GETFUNC( getWeight4 );
+#if 0
+/* not defined */
+GETFUNC( getUsers );
+#endif
+
+OLDSETFUNC( setDistMetric );
+OLDSETFUNC( setDistNoise ); /* special case used for ".noisebasis = ... */
+OLDSETFUNC( setExtend );
+OLDSETFUNC( setFlags );
+OLDSETFUNC( setImage );
+OLDSETFUNC( setImageFlags );
+OLDSETFUNC( setIpo );
+OLDSETFUNC( setNoiseBasis );
+OLDSETFUNC( setSType );
+OLDSETFUNC( setType );
+
+SETFUNC( setAnimFrames );
+SETFUNC( setAnimOffset );
+SETFUNC( setAnimStart );
+SETFUNC( setBrightness );
+SETFUNC( setContrast );
+SETFUNC( setCrop );
+SETFUNC( setDistAmnt );
+SETFUNC( setDistMetric );
+SETFUNC( setExp );
+SETFUNC( setIntExtend );
+SETFUNC( setFieldsPerImage );
+SETFUNC( setFilterSize );
+SETFUNC( setFlags );
+SETFUNC( setHFracDim );
+SETFUNC( setImage );
+SETFUNC( setIpo );
+SETFUNC( setIScale );
+SETFUNC( setLacunarity );
+SETFUNC( setNoiseBasis );
+SETFUNC( setNoiseDepth );
+SETFUNC( setNoiseSize );
+SETFUNC( setNoiseType );
+SETFUNC( setOcts );
+SETFUNC( setRepeat );
+SETFUNC( setRGBCol );
+SETFUNC( setSType );
+SETFUNC( setTurbulence );
+SETFUNC( setType );
+SETFUNC( setWeight1 );
+SETFUNC( setWeight2 );
+SETFUNC( setWeight3 );
+SETFUNC( setWeight4 );
+
+static PyObject *Texture_getImageFlags( BPy_Texture *self, void *type );
+static PyObject *Texture_getIUserFlags( BPy_Texture *self, void *type );
+static PyObject *Texture_getIUserCyclic( BPy_Texture *self );
+static PyObject *Texture_getNoiseBasis2( BPy_Texture *self, void *type );
+static int Texture_setImageFlags( BPy_Texture *self, PyObject *args,
+ void *type );
+static int Texture_setIUserFlags( BPy_Texture *self, PyObject *args,
+ void *type );
+static int Texture_setIUserCyclic( BPy_Texture *self, PyObject *args );
+static int Texture_setNoiseBasis2( BPy_Texture *self, PyObject *args,
+ void *type );
+
+static PyObject *Texture_getColorband( BPy_Texture * self);
+int Texture_setColorband( BPy_Texture * self, PyObject * value);
+static PyObject *Texture_evaluate( BPy_Texture *self, VectorObject *vec_in );
+static PyObject *Texture_copy( BPy_Texture *self );
+
+/*****************************************************************************/
+/* Python BPy_Texture methods table: */
+/*****************************************************************************/
+static PyMethodDef BPy_Texture_methods[] = {
+ /* name, method, flags, doc */
+ {"getExtend", ( PyCFunction ) Texture_getExtend, METH_NOARGS,
+ "() - Return Texture extend mode"},
+ {"getImage", ( PyCFunction ) Texture_getImage, METH_NOARGS,
+ "() - Return Texture Image"},
+ {"getName", ( PyCFunction ) GenericLib_getName, METH_NOARGS,
+ "() - Return Texture name"},
+ {"getSType", ( PyCFunction ) Texture_oldgetSType, METH_NOARGS,
+ "() - Return Texture stype as string"},
+ {"getType", ( PyCFunction ) Texture_oldgetType, METH_NOARGS,
+ "() - Return Texture type as string"},
+ {"getIpo", ( PyCFunction ) Texture_getIpo, METH_NOARGS,
+ "() - Return Texture Ipo"},
+ {"setIpo", ( PyCFunction ) Texture_oldsetIpo, METH_VARARGS,
+ "(Blender Ipo) - Set Texture Ipo"},
+ {"clearIpo", ( PyCFunction ) Texture_clearIpo, METH_NOARGS,
+ "() - Unlink Ipo from this Texture."},
+ {"setExtend", ( PyCFunction ) Texture_oldsetExtend, METH_VARARGS,
+ "(s) - Set Texture extend mode"},
+ {"setFlags", ( PyCFunction ) Texture_oldsetFlags, METH_VARARGS,
+ "(f1,f2,f3,f4,f5) - Set Texture flags"},
+ {"setImage", ( PyCFunction ) Texture_oldsetImage, METH_VARARGS,
+ "(Blender Image) - Set Texture Image"},
+ {"setImageFlags", ( PyCFunction ) Texture_oldsetImageFlags, METH_VARARGS,
+ "(s,s,s,s,...) - Set Texture image flags"},
+ {"setName", ( PyCFunction ) GenericLib_setName_with_method, METH_VARARGS,
+ "(s) - Set Texture name"},
+ {"setSType", ( PyCFunction ) Texture_oldsetSType, METH_VARARGS,
+ "(s) - Set Texture stype"},
+ {"setType", ( PyCFunction ) Texture_oldsetType, METH_VARARGS,
+ "(s) - Set Texture type"},
+ {"setNoiseBasis", ( PyCFunction ) Texture_oldsetNoiseBasis, METH_VARARGS,
+ "(s) - Set Noise basis"},
+ {"setDistNoise", ( PyCFunction ) Texture_oldsetDistNoise, METH_VARARGS,
+ "(s) - Set Dist Noise"},
+ {"setDistMetric", ( PyCFunction ) Texture_oldsetDistMetric, METH_VARARGS,
+ "(s) - Set Dist Metric"},
+ {"evaluate", ( PyCFunction ) Texture_evaluate, METH_O,
+ "(vector) - evaluate the texture at this position"},
+ {"__copy__", ( PyCFunction ) Texture_copy, METH_NOARGS,
+ "() - return a copy of the the texture"},
+ {"copy", ( PyCFunction ) Texture_copy, METH_NOARGS,
+ "() - return a copy of the the texture"},
+ {NULL, NULL, 0, NULL}
+};
+
+/*****************************************************************************/
+/* Python Texture_Type attributes get/set structure: */
+/*****************************************************************************/
+static PyGetSetDef BPy_Texture_getseters[] = {
+ GENERIC_LIB_GETSETATTR,
+ {"animFrames",
+ (getter)Texture_getAnimFrames, (setter)Texture_setAnimFrames,
+ "Number of frames of a movie to use",
+ NULL},
+#if 0
+ {"animLength",
+ (getter)Texture_getAnimLength, (setter)Texture_setAnimLength,
+ "Number of frames of a movie to use (0 for all)",
+ NULL},
+ {"animMontage",
+ (getter)Texture_getAnimMontage, (setter)Texture_setAnimMontage,
+ "Montage mode, start frames and durations",
+ NULL},
+#endif
+ {"animOffset",
+ (getter)Texture_getAnimOffset, (setter)Texture_setAnimOffset,
+ "Offsets the number of the first movie frame to use",
+ NULL},
+ {"animStart",
+ (getter)Texture_getAnimStart, (setter)Texture_setAnimStart,
+ "Starting frame of the movie to use",
+ NULL},
+ {"brightness",
+ (getter)Texture_getBrightness, (setter)Texture_setBrightness,
+ "Changes the brightness of a texture's color",
+ NULL},
+ {"contrast",
+ (getter)Texture_getContrast, (setter)Texture_setContrast,
+ "Changes the contrast of a texture's color",
+ NULL},
+ {"crop",
+ (getter)Texture_getCrop, (setter)Texture_setCrop,
+ "Sets the cropping extents (for image textures)",
+ NULL},
+ {"distAmnt",
+ (getter)Texture_getDistAmnt, (setter)Texture_setDistAmnt,
+ "Amount of distortion (for distorted noise textures)",
+ NULL},
+ {"distMetric",
+ (getter)Texture_getDistMetric, (setter)Texture_setDistMetric,
+ "The distance metric (for Voronoi textures)",
+ NULL},
+ {"exp",
+ (getter)Texture_getExp, (setter)Texture_setExp,
+ "Minkovsky exponent (for Minkovsky Voronoi textures)",
+ NULL},
+ {"extend",
+ (getter)Texture_getIntExtend, (setter)Texture_setIntExtend,
+ "Texture's 'Extend' mode (for image textures)",
+ NULL},
+ {"fieldsPerImage",
+ (getter)Texture_getFieldsPerImage, (setter)Texture_setFieldsPerImage,
+ "Number of fields per rendered frame",
+ NULL},
+ {"filterSize",
+ (getter)Texture_getFilterSize, (setter)Texture_setFilterSize,
+ "The filter size (for image and envmap textures)",
+ NULL},
+ {"flags",
+ (getter)Texture_getFlags, (setter)Texture_setFlags,
+ "Texture's 'Flag' bits",
+ NULL},
+ {"hFracDim",
+ (getter)Texture_getHFracDim, (setter)Texture_setHFracDim,
+ "Highest fractional dimension (for Musgrave textures)",
+ NULL},
+ {"imageFlags",
+ (getter)Texture_getImageFlags, (setter)Texture_setImageFlags,
+ "Texture's 'ImageFlags' bits",
+ NULL},
+ {"image",
+ (getter)Texture_getImage, (setter)Texture_setImage,
+ "Texture's image object",
+ NULL},
+ {"ipo",
+ (getter)Texture_getIpo, (setter)Texture_setIpo,
+ "Texture Ipo data",
+ NULL},
+ {"iScale",
+ (getter)Texture_getIScale, (setter)Texture_setIScale,
+ "Intensity output scale (for Musgrave and Voronoi textures)",
+ NULL},
+ {"lacunarity",
+ (getter)Texture_getLacunarity, (setter)Texture_setLacunarity,
+ "Gap between succesive frequencies (for Musgrave textures)",
+ NULL},
+ {"noiseBasis",
+ (getter)Texture_getNoiseBasis, (setter)Texture_setNoiseBasis,
+ "Noise basis type (wood, stucci, marble, clouds, Musgrave, distorted noise)",
+ NULL},
+ {"noiseBasis2",
+ (getter)Texture_getNoiseBasis2, (setter)Texture_setNoiseBasis2,
+ "Additional noise basis type (wood, marble, distorted noise)",
+ (void *)EXPP_TEX_NOISEBASIS2},
+ {"noiseDepth",
+ (getter)Texture_getNoiseDepth, (setter)Texture_setNoiseDepth,
+ "Noise depth (magic, marble, clouds)",
+ NULL},
+ {"noiseSize",
+ (getter)Texture_getNoiseSize, (setter)Texture_setNoiseSize,
+ "Noise size (wood, stucci, marble, clouds, Musgrave, distorted noise, Voronoi)",
+ NULL},
+/* NOTE for API rewrite: should use dict constants instead of strings */
+ {"noiseType",
+ (getter)Texture_getNoiseType, (setter)Texture_setNoiseType,
+ "Noise type (for wood, stucci, marble, clouds textures)",
+ NULL},
+ {"octs",
+ (getter)Texture_getOcts, (setter)Texture_setOcts,
+ "Number of frequencies (for Musgrave textures)",
+ NULL},
+ {"repeat",
+ (getter)Texture_getRepeat, (setter)Texture_setRepeat,
+ "Repetition multiplier (for image textures)",
+ NULL},
+ {"rgbCol",
+ (getter)Texture_getRGBCol, (setter)Texture_setRGBCol,
+ "RGB color tuple",
+ NULL},
+ {"stype",
+ (getter)Texture_getSType, (setter)Texture_setSType,
+ "Texture's 'SType' mode",
+ NULL},
+ {"turbulence",
+ (getter)Texture_getTurbulence, (setter)Texture_setTurbulence,
+ "Turbulence (for magic, wood, stucci, marble textures)",
+ NULL},
+ {"type",
+ (getter)Texture_getType, (setter)Texture_setType,
+ "Texture's 'Type' mode",
+ NULL},
+ {"weight1",
+ (getter)Texture_getWeight1, (setter)Texture_setWeight1,
+ "Weight 1 (for Voronoi textures)",
+ NULL},
+ {"weight2",
+ (getter)Texture_getWeight2, (setter)Texture_setWeight2,
+ "Weight 2 (for Voronoi textures)",
+ NULL},
+ {"weight3",
+ (getter)Texture_getWeight3, (setter)Texture_setWeight3,
+ "Weight 3 (for Voronoi textures)",
+ NULL},
+ {"weight4",
+ (getter)Texture_getWeight4, (setter)Texture_setWeight4,
+ "Weight 4 (for Voronoi textures)",
+ NULL},
+ {"sine",
+ (getter)Texture_getNoiseBasis2, (setter)Texture_setNoiseBasis2,
+ "Produce bands using sine wave (marble, wood textures)",
+ (void *)EXPP_TEX_NOISE_SINE},
+ {"saw",
+ (getter)Texture_getNoiseBasis2, (setter)Texture_setNoiseBasis2,
+ "Produce bands using saw wave (marble, wood textures)",
+ (void *)EXPP_TEX_NOISE_SAW},
+ {"tri",
+ (getter)Texture_getNoiseBasis2, (setter)Texture_setNoiseBasis2,
+ "Produce bands using triangle wave (marble, wood textures)",
+ (void *)EXPP_TEX_NOISE_TRI},
+ {"interpol",
+ (getter)Texture_getImageFlags, (setter)Texture_setImageFlags,
+ "Interpolate image's pixels to fit texture mapping enabled ('ImageFlags')",
+ (void *)TEX_INTERPOL},
+ {"useAlpha",
+ (getter)Texture_getImageFlags, (setter)Texture_setImageFlags,
+ "Use of image's alpha channel enabled ('ImageFlags')",
+ (void *)TEX_USEALPHA},
+ {"calcAlpha",
+ (getter)Texture_getImageFlags, (setter)Texture_setImageFlags,
+ "Calculation of image's alpha channel enabled ('ImageFlags')",
+ (void *)TEX_CALCALPHA},
+ {"mipmap",
+ (getter)Texture_getImageFlags, (setter)Texture_setImageFlags,
+ "Mipmaps enabled ('ImageFlags')",
+ (void *)TEX_MIPMAP},
+ {"rot90",
+ (getter)Texture_getImageFlags, (setter)Texture_setImageFlags,
+ "X/Y flip for rendering enabled ('ImageFlags')",
+ (void *)TEX_IMAROT},
+ {"autoRefresh",
+ (getter)Texture_getIUserFlags, (setter)Texture_setIUserFlags,
+ "Refresh image on frame changes enabled",
+ (void *)IMA_ANIM_ALWAYS},
+ {"cyclic",
+ (getter)Texture_getIUserCyclic, (setter)Texture_setIUserCyclic,
+ "Cycling of animated frames enabled",
+ NULL},
+#if 0
+ /* disabled, moved to image */
+ {"fields",
+ (getter)Texture_getImageFlags, (setter)Texture_setImageFlags,
+ "Use of image's fields enabled ('ImageFlags')",
+ (void *)TEX_FIELDS},
+ {"movie",
+ (getter)Texture_getImageFlags, (setter)Texture_setImageFlags,
+ "Movie frames as images enabled ('ImageFlags')",
+ (void *)TEX_ANIM5},
+ {"anti",
+ (getter)Texture_getImageFlags, (setter)Texture_setImageFlags,
+ "Image anti-aliasing enabled ('ImageFlags')",
+ (void *)TEX_ANTIALI},
+ {"stField",
+ (getter)Texture_getImageFlags, (setter)Texture_setImageFlags,
+ "Standard field deinterlacing enabled ('ImageFlags')",
+ (void *)TEX_STD_FIELD},
+#endif
+ {"normalMap",
+ (getter)Texture_getImageFlags, (setter)Texture_setImageFlags,
+ "Use of image RGB values for normal mapping enabled ('ImageFlags')",
+ (void *)TEX_NORMALMAP},
+ {"colorband",
+ (getter)Texture_getColorband, (setter)Texture_setColorband,
+ "The colorband for this texture",
+ NULL},
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+/*****************************************************************************/
+/* Python Texture_Type callback function prototypes: */
+/*****************************************************************************/
+static int Texture_compare( BPy_Texture * a, BPy_Texture * b );
+static PyObject *Texture_repr( BPy_Texture * self );
+
+/*****************************************************************************/
+/* Python Texture_Type structure definition: */
+/*****************************************************************************/
+PyTypeObject Texture_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender Texture", /* char *tp_name; */
+ sizeof( BPy_Texture ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ NULL, /* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ ( cmpfunc ) Texture_compare, /* cmpfunc tp_compare; */
+ ( reprfunc ) Texture_repr, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ ( hashfunc ) GenericLib_hash, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_Texture_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ BPy_Texture_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+static PyObject *M_Texture_New( PyObject * self, PyObject * args,
+ PyObject * kwords )
+{
+ char *name_str = "Tex";
+ static char *kwlist[] = { "name_str", NULL };
+ PyObject *pytex; /* for Texture object wrapper in Python */
+ Tex *bltex; /* for actual Tex we create in Blender */
+
+ /* Parse the arguments passed in by the Python interpreter */
+ if( !PyArg_ParseTupleAndKeywords
+ ( args, kwords, "|s", kwlist, &name_str ) )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected zero, one or two strings as arguments" );
+
+ bltex = add_texture( name_str ); /* first create the texture in Blender */
+
+ if( bltex ) /* now create the wrapper obj in Python */
+ pytex = Texture_CreatePyObject( bltex );
+ else
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't create Texture in Blender" );
+
+ /* let's return user count to zero, because add_texture() incref'd it */
+ bltex->id.us = 0;
+
+ if( pytex == NULL )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create Tex PyObject" );
+
+ return pytex;
+}
+
+static PyObject *M_Texture_Get( PyObject * self, PyObject * args )
+{
+ char *name = NULL;
+ Tex *tex_iter;
+
+ if( !PyArg_ParseTuple( args, "|s", &name ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument (or nothing)" );
+
+ tex_iter = G.main->tex.first;
+
+ if( name ) { /* (name) - Search for texture by name */
+
+ PyObject *wanted_tex = NULL;
+
+ while( tex_iter ) {
+ if( STREQ( name, tex_iter->id.name + 2 ) ) {
+ wanted_tex =
+ Texture_CreatePyObject( tex_iter );
+ break;
+ }
+
+ tex_iter = tex_iter->id.next;
+ }
+
+ if( !wanted_tex ) { /* Requested texture doesn't exist */
+ char error_msg[64];
+ PyOS_snprintf( error_msg, sizeof( error_msg ),
+ "Texture \"%s\" not found", name );
+ return EXPP_ReturnPyObjError( PyExc_NameError,
+ error_msg );
+ }
+
+ return wanted_tex;
+ }
+
+ else { /* () - return a list of wrappers for all textures in the scene */
+ int index = 0;
+ PyObject *tex_pylist, *pyobj;
+
+ tex_pylist = PyList_New( BLI_countlist( &( G.main->tex ) ) );
+ if( !tex_pylist )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create PyList" );
+
+ while( tex_iter ) {
+ pyobj = Texture_CreatePyObject( tex_iter );
+ if( !pyobj ) {
+ Py_DECREF(tex_pylist);
+ return EXPP_ReturnPyObjError
+ ( PyExc_MemoryError,
+ "couldn't create Texture PyObject" );
+ }
+ PyList_SET_ITEM( tex_pylist, index, pyobj );
+
+ tex_iter = tex_iter->id.next;
+ index++;
+ }
+
+ return tex_pylist;
+ }
+}
+
+static int Texture_compare( BPy_Texture * a, BPy_Texture * b )
+{
+ return ( a->texture == b->texture ) ? 0 : -1;
+}
+
+static PyObject *Texture_repr( BPy_Texture * self )
+{
+ return PyString_FromFormat( "[Texture \"%s\"]",
+ self->texture->id.name + 2 );
+}
+
+static PyObject *M_Texture_TypesDict( void )
+{
+ PyObject *Types = PyConstant_New( );
+ if( Types ) {
+ BPy_constant *d = ( BPy_constant * ) Types;
+ PyConstant_Insert(d, "NONE", PyInt_FromLong(EXPP_TEX_TYPE_NONE));
+ PyConstant_Insert(d, "CLOUDS", PyInt_FromLong(TEX_CLOUDS));
+ PyConstant_Insert(d, "WOOD", PyInt_FromLong(TEX_WOOD));
+ PyConstant_Insert(d, "MARBLE", PyInt_FromLong(TEX_MARBLE));
+ PyConstant_Insert(d, "MAGIC", PyInt_FromLong(TEX_MAGIC));
+ PyConstant_Insert(d, "BLEND", PyInt_FromLong(TEX_BLEND));
+ PyConstant_Insert(d, "STUCCI", PyInt_FromLong(TEX_STUCCI));
+ PyConstant_Insert(d, "NOISE", PyInt_FromLong(TEX_NOISE));
+ PyConstant_Insert(d, "IMAGE", PyInt_FromLong(TEX_IMAGE));
+ PyConstant_Insert(d, "PLUGIN", PyInt_FromLong(TEX_PLUGIN));
+ PyConstant_Insert(d, "ENVMAP", PyInt_FromLong(TEX_ENVMAP));
+ PyConstant_Insert(d, "MUSGRAVE", PyInt_FromLong(TEX_MUSGRAVE));
+ PyConstant_Insert(d, "VORONOI", PyInt_FromLong(TEX_VORONOI));
+ PyConstant_Insert(d, "DISTNOISE", PyInt_FromLong(TEX_DISTNOISE));
+ }
+ return Types;
+}
+
+static PyObject *M_Texture_STypesDict( void )
+{
+ PyObject *STypes = PyConstant_New( );
+ if( STypes ) {
+ BPy_constant *d = ( BPy_constant * ) STypes;
+
+ PyConstant_Insert(d, "CLD_DEFAULT",
+ PyInt_FromLong(EXPP_TEX_STYPE_CLD_DEFAULT));
+ PyConstant_Insert(d, "CLD_COLOR",
+ PyInt_FromLong(EXPP_TEX_STYPE_CLD_COLOR));
+ PyConstant_Insert(d, "WOD_BANDS",
+ PyInt_FromLong(EXPP_TEX_STYPE_WOD_BANDS));
+ PyConstant_Insert(d, "WOD_RINGS",
+ PyInt_FromLong(EXPP_TEX_STYPE_WOD_RINGS));
+ PyConstant_Insert(d, "WOD_BANDNOISE",
+ PyInt_FromLong(EXPP_TEX_STYPE_WOD_BANDNOISE));
+ PyConstant_Insert(d, "WOD_RINGNOISE",
+ PyInt_FromLong(EXPP_TEX_STYPE_WOD_RINGNOISE));
+ PyConstant_Insert(d, "MAG_DEFAULT",
+ PyInt_FromLong(EXPP_TEX_STYPE_MAG_DEFAULT));
+ PyConstant_Insert(d, "MBL_SOFT",
+ PyInt_FromLong(EXPP_TEX_STYPE_MBL_SOFT));
+ PyConstant_Insert(d, "MBL_SHARP",
+ PyInt_FromLong(EXPP_TEX_STYPE_MBL_SHARP));
+ PyConstant_Insert(d, "MBL_SHARPER",
+ PyInt_FromLong(EXPP_TEX_STYPE_MBL_SHARPER));
+ PyConstant_Insert(d, "BLN_LIN",
+ PyInt_FromLong(EXPP_TEX_STYPE_BLN_LIN));
+ PyConstant_Insert(d, "BLN_QUAD",
+ PyInt_FromLong(EXPP_TEX_STYPE_BLN_QUAD));
+ PyConstant_Insert(d, "BLN_EASE",
+ PyInt_FromLong(EXPP_TEX_STYPE_BLN_EASE));
+ PyConstant_Insert(d, "BLN_DIAG",
+ PyInt_FromLong(EXPP_TEX_STYPE_BLN_DIAG));
+ PyConstant_Insert(d, "BLN_SPHERE",
+ PyInt_FromLong(EXPP_TEX_STYPE_BLN_SPHERE));
+ PyConstant_Insert(d, "BLN_HALO",
+ PyInt_FromLong(EXPP_TEX_STYPE_BLN_HALO));
+ PyConstant_Insert(d, "STC_PLASTIC",
+ PyInt_FromLong(EXPP_TEX_STYPE_STC_PLASTIC));
+ PyConstant_Insert(d, "STC_WALLIN",
+ PyInt_FromLong(EXPP_TEX_STYPE_STC_WALLIN));
+ PyConstant_Insert(d, "STC_WALLOUT",
+ PyInt_FromLong(EXPP_TEX_STYPE_STC_WALLOUT));
+ PyConstant_Insert(d, "NSE_DEFAULT",
+ PyInt_FromLong(EXPP_TEX_STYPE_NSE_DEFAULT));
+ PyConstant_Insert(d, "IMG_DEFAULT",
+ PyInt_FromLong(EXPP_TEX_STYPE_IMG_DEFAULT));
+ PyConstant_Insert(d, "PLG_DEFAULT",
+ PyInt_FromLong(EXPP_TEX_STYPE_PLG_DEFAULT));
+ PyConstant_Insert(d, "ENV_STATIC",
+ PyInt_FromLong(EXPP_TEX_STYPE_ENV_STATIC));
+ PyConstant_Insert(d, "ENV_ANIM",
+ PyInt_FromLong(EXPP_TEX_STYPE_ENV_ANIM));
+ PyConstant_Insert(d, "ENV_LOAD",
+ PyInt_FromLong(EXPP_TEX_STYPE_ENV_LOAD));
+ PyConstant_Insert(d, "MUS_MFRACTAL",
+ PyInt_FromLong(EXPP_TEX_STYPE_MUS_MFRACTAL));
+ PyConstant_Insert(d, "MUS_RIDGEDMF",
+ PyInt_FromLong(EXPP_TEX_STYPE_MUS_RIDGEDMF));
+ PyConstant_Insert(d, "MUS_HYBRIDMF",
+ PyInt_FromLong(EXPP_TEX_STYPE_MUS_HYBRIDMF));
+ PyConstant_Insert(d, "MUS_FBM",
+ PyInt_FromLong(EXPP_TEX_STYPE_MUS_FBM));
+ PyConstant_Insert(d, "MUS_HTERRAIN",
+ PyInt_FromLong(EXPP_TEX_STYPE_MUS_HTERRAIN));
+ PyConstant_Insert(d, "DN_BLENDER",
+ PyInt_FromLong(TEX_BLENDER));
+ PyConstant_Insert(d, "DN_PERLIN",
+ PyInt_FromLong(TEX_STDPERLIN));
+ PyConstant_Insert(d, "DN_IMPROVEDPERLIN",
+ PyInt_FromLong(TEX_NEWPERLIN));
+ PyConstant_Insert(d, "DN_VORONOIF1",
+ PyInt_FromLong(TEX_VORONOI_F1));
+ PyConstant_Insert(d, "DN_VORONOIF2",
+ PyInt_FromLong(TEX_VORONOI_F2));
+ PyConstant_Insert(d, "DN_VORONOIF3",
+ PyInt_FromLong(TEX_VORONOI_F3));
+ PyConstant_Insert(d, "DN_VORONOIF4",
+ PyInt_FromLong(TEX_VORONOI_F4));
+ PyConstant_Insert(d, "DN_VORONOIF2F1",
+ PyInt_FromLong(TEX_VORONOI_F2F1));
+ PyConstant_Insert(d, "DN_VORONOICRACKLE",
+ PyInt_FromLong(TEX_VORONOI_CRACKLE));
+ PyConstant_Insert(d, "DN_CELLNOISE",
+ PyInt_FromLong(TEX_CELLNOISE));
+ PyConstant_Insert(d, "VN_INT",
+ PyInt_FromLong(EXPP_TEX_STYPE_VN_INT));
+ PyConstant_Insert(d, "VN_COL1",
+ PyInt_FromLong(EXPP_TEX_STYPE_VN_COL1));
+ PyConstant_Insert(d, "VN_COL2",
+ PyInt_FromLong(EXPP_TEX_STYPE_VN_COL2));
+ PyConstant_Insert(d, "VN_COL3",
+ PyInt_FromLong(EXPP_TEX_STYPE_VN_COL3));
+ PyConstant_Insert(d, "VN_TEX_DISTANCE",
+ PyInt_FromLong(TEX_DISTANCE));
+ PyConstant_Insert(d, "VN_TEX_DISTANCE_SQUARED",
+ PyInt_FromLong(TEX_DISTANCE_SQUARED));
+ PyConstant_Insert(d, "VN_TEX_MANHATTAN",
+ PyInt_FromLong(TEX_MANHATTAN));
+ PyConstant_Insert(d, "VN_TEX_CHEBYCHEV",
+ PyInt_FromLong(TEX_CHEBYCHEV));
+ PyConstant_Insert(d, "VN_TEX_MINKOVSKY_HALF",
+ PyInt_FromLong(TEX_MINKOVSKY_HALF));
+ PyConstant_Insert(d, "VN_TEX_MINKOVSKY_FOUR",
+ PyInt_FromLong(TEX_MINKOVSKY_FOUR));
+ PyConstant_Insert(d, "VN_TEX_MINKOVSKY",
+ PyInt_FromLong(TEX_MINKOVSKY));
+
+ }
+ return STypes;
+}
+
+static PyObject *M_Texture_TexCoDict( void )
+{
+ PyObject *TexCo = PyConstant_New( );
+ if( TexCo ) {
+ BPy_constant *d = ( BPy_constant * ) TexCo;
+ PyConstant_Insert(d, "ORCO", PyInt_FromLong(TEXCO_ORCO));
+ PyConstant_Insert(d, "REFL", PyInt_FromLong(TEXCO_REFL));
+ PyConstant_Insert(d, "NOR", PyInt_FromLong(TEXCO_NORM));
+ PyConstant_Insert(d, "GLOB", PyInt_FromLong(TEXCO_GLOB));
+ PyConstant_Insert(d, "UV", PyInt_FromLong(TEXCO_UV));
+ PyConstant_Insert(d, "OBJECT", PyInt_FromLong(TEXCO_OBJECT));
+ PyConstant_Insert(d, "WIN", PyInt_FromLong(TEXCO_WINDOW));
+ PyConstant_Insert(d, "VIEW", PyInt_FromLong(TEXCO_VIEW));
+ PyConstant_Insert(d, "STICK", PyInt_FromLong(TEXCO_STICKY));
+ PyConstant_Insert(d, "STRESS", PyInt_FromLong(TEXCO_STRESS));
+ PyConstant_Insert(d, "TANGENT", PyInt_FromLong(TEXCO_TANGENT));
+ }
+ return TexCo;
+}
+
+static PyObject *M_Texture_MapToDict( void )
+{
+ PyObject *MapTo = PyConstant_New( );
+ if( MapTo ) {
+ BPy_constant *d = ( BPy_constant * ) MapTo;
+ PyConstant_Insert(d, "COL", PyInt_FromLong(MAP_COL));
+ PyConstant_Insert(d, "NOR", PyInt_FromLong(MAP_NORM));
+ PyConstant_Insert(d, "CSP", PyInt_FromLong(MAP_COLSPEC));
+ PyConstant_Insert(d, "CMIR", PyInt_FromLong(MAP_COLMIR));
+ PyConstant_Insert(d, "REF", PyInt_FromLong(MAP_REF));
+ PyConstant_Insert(d, "SPEC", PyInt_FromLong(MAP_SPEC));
+ PyConstant_Insert(d, "HARD", PyInt_FromLong(MAP_HAR));
+ PyConstant_Insert(d, "ALPHA", PyInt_FromLong(MAP_ALPHA));
+ PyConstant_Insert(d, "EMIT", PyInt_FromLong(MAP_EMIT));
+ PyConstant_Insert(d, "RAYMIR", PyInt_FromLong(MAP_RAYMIRR));
+ PyConstant_Insert(d, "AMB", PyInt_FromLong(MAP_AMB));
+ PyConstant_Insert(d, "TRANSLU", PyInt_FromLong(MAP_TRANSLU));
+ PyConstant_Insert(d, "DISP", PyInt_FromLong(MAP_DISPLACE));
+ PyConstant_Insert(d, "WARP", PyInt_FromLong(MAP_WARP));
+ }
+ return MapTo;
+}
+
+static PyObject *M_Texture_FlagsDict( void )
+{
+ PyObject *Flags = PyConstant_New( );
+ if( Flags ) {
+ BPy_constant *d = ( BPy_constant * ) Flags;
+ PyConstant_Insert(d, "COLORBAND", PyInt_FromLong(TEX_COLORBAND));
+ PyConstant_Insert(d, "FLIPBLEND", PyInt_FromLong(TEX_FLIPBLEND));
+ PyConstant_Insert(d, "NEGALPHA", PyInt_FromLong(TEX_NEGALPHA));
+ PyConstant_Insert(d, "CHECKER_ODD", PyInt_FromLong(TEX_CHECKER_ODD));
+ PyConstant_Insert(d, "CHECKER_EVEN", PyInt_FromLong(TEX_CHECKER_EVEN));
+ PyConstant_Insert(d, "PREVIEW_ALPHA", PyInt_FromLong(TEX_PRV_ALPHA));
+ PyConstant_Insert(d, "REPEAT_XMIR", PyInt_FromLong(TEX_REPEAT_XMIR));
+ PyConstant_Insert(d, "REPEAT_YMIR", PyInt_FromLong(TEX_REPEAT_YMIR));
+ }
+ return Flags;
+}
+
+static PyObject *M_Texture_ExtendModesDict( void )
+{
+ PyObject *ExtendModes = PyConstant_New( );
+ if( ExtendModes ) {
+ BPy_constant *d = ( BPy_constant * ) ExtendModes;
+ PyConstant_Insert(d, "EXTEND", PyInt_FromLong(TEX_EXTEND));
+ PyConstant_Insert(d, "CLIP", PyInt_FromLong(TEX_CLIP));
+ PyConstant_Insert(d, "CLIPCUBE", PyInt_FromLong(TEX_CLIPCUBE));
+ PyConstant_Insert(d, "REPEAT", PyInt_FromLong(TEX_REPEAT));
+ }
+ return ExtendModes;
+}
+
+static PyObject *M_Texture_ImageFlagsDict( void )
+{
+ PyObject *ImageFlags = PyConstant_New( );
+ if( ImageFlags ) {
+ BPy_constant *d = ( BPy_constant * ) ImageFlags;
+ PyConstant_Insert(d, "INTERPOL", PyInt_FromLong(TEX_INTERPOL));
+ PyConstant_Insert(d, "USEALPHA", PyInt_FromLong(TEX_USEALPHA));
+ PyConstant_Insert(d, "MIPMAP", PyInt_FromLong(TEX_MIPMAP));
+ PyConstant_Insert(d, "ROT90", PyInt_FromLong(TEX_IMAROT));
+ PyConstant_Insert(d, "CALCALPHA", PyInt_FromLong(TEX_CALCALPHA));
+ PyConstant_Insert(d, "NORMALMAP", PyInt_FromLong(TEX_NORMALMAP));
+ }
+ return ImageFlags;
+}
+
+static PyObject *M_Texture_NoiseDict( void )
+{
+ PyObject *Noise = PyConstant_New( );
+ if( Noise ) {
+ BPy_constant *d = ( BPy_constant * ) Noise;
+ PyConstant_Insert(d, "SINE", PyInt_FromLong(EXPP_TEX_NOISE_SINE));
+ PyConstant_Insert(d, "SAW", PyInt_FromLong(EXPP_TEX_NOISE_SAW));
+ PyConstant_Insert(d, "TRI", PyInt_FromLong(EXPP_TEX_NOISE_TRI));
+ PyConstant_Insert(d, "BLENDER", PyInt_FromLong(TEX_BLENDER));
+ PyConstant_Insert(d, "PERLIN", PyInt_FromLong(TEX_STDPERLIN));
+ PyConstant_Insert(d, "IMPROVEDPERLIN", PyInt_FromLong(TEX_NEWPERLIN));
+ PyConstant_Insert(d, "VORONOIF1", PyInt_FromLong(TEX_VORONOI_F1));
+ PyConstant_Insert(d, "VORONOIF2", PyInt_FromLong(TEX_VORONOI_F2));
+ PyConstant_Insert(d, "VORONOIF3", PyInt_FromLong(TEX_VORONOI_F3));
+ PyConstant_Insert(d, "VORONOIF4", PyInt_FromLong(TEX_VORONOI_F4));
+ PyConstant_Insert(d, "VORONOIF2F1", PyInt_FromLong(TEX_VORONOI_F2F1));
+ PyConstant_Insert(d, "VORONOICRACKLE",
+ PyInt_FromLong(TEX_VORONOI_CRACKLE));
+ PyConstant_Insert(d, "CELLNOISE", PyInt_FromLong(TEX_CELLNOISE));
+ }
+ return Noise;
+}
+
+static PyObject *M_Texture_BlendModesDict( void )
+{
+ PyObject *BlendModes = PyConstant_New( );
+ if( BlendModes ) {
+ BPy_constant *d = ( BPy_constant * ) BlendModes;
+ PyConstant_Insert(d, "MIX", PyInt_FromLong(MTEX_BLEND));
+ PyConstant_Insert(d, "MULTIPLY", PyInt_FromLong(MTEX_MUL));
+ PyConstant_Insert(d, "ADD", PyInt_FromLong(MTEX_ADD));
+ PyConstant_Insert(d, "SUBTRACT", PyInt_FromLong(MTEX_SUB));
+ PyConstant_Insert(d, "DIVIDE", PyInt_FromLong(MTEX_DIV));
+ PyConstant_Insert(d, "DARKEN", PyInt_FromLong(MTEX_DARK));
+ PyConstant_Insert(d, "DIFFERENCE", PyInt_FromLong(MTEX_DIFF));
+ PyConstant_Insert(d, "LIGHTEN", PyInt_FromLong(MTEX_LIGHT));
+ PyConstant_Insert(d, "SCREEN", PyInt_FromLong(MTEX_SCREEN));
+ }
+ return BlendModes;
+}
+
+static PyObject *M_Texture_MappingsDict( void )
+{
+ PyObject *Mappings = PyConstant_New( );
+ if( Mappings ) {
+ BPy_constant *d = ( BPy_constant * ) Mappings;
+ PyConstant_Insert(d, "FLAT", PyInt_FromLong(MTEX_FLAT));
+ PyConstant_Insert(d, "CUBE", PyInt_FromLong(MTEX_CUBE));
+ PyConstant_Insert(d, "TUBE", PyInt_FromLong(MTEX_TUBE));
+ PyConstant_Insert(d, "SPHERE", PyInt_FromLong(MTEX_SPHERE));
+ }
+ return Mappings;
+}
+
+static PyObject *M_Texture_ProjDict( void )
+{
+ PyObject *Proj = PyConstant_New( );
+ if( Proj ) {
+ BPy_constant *d = ( BPy_constant * ) Proj;
+ PyConstant_Insert(d, "NONE", PyInt_FromLong(PROJ_N));
+ PyConstant_Insert(d, "X", PyInt_FromLong(PROJ_X));
+ PyConstant_Insert(d, "Y", PyInt_FromLong(PROJ_Y));
+ PyConstant_Insert(d, "Z", PyInt_FromLong(PROJ_Z));
+ }
+ return Proj;
+}
+
+PyObject *Texture_Init( void )
+{
+ PyObject *submodule;
+ PyObject *dict;
+
+ /* constants */
+ PyObject *Types = M_Texture_TypesDict( );
+ PyObject *STypes = M_Texture_STypesDict( );
+ PyObject *TexCo = M_Texture_TexCoDict( );
+ PyObject *MapTo = M_Texture_MapToDict( );
+ PyObject *Flags = M_Texture_FlagsDict( );
+ PyObject *ExtendModes = M_Texture_ExtendModesDict( );
+ PyObject *ImageFlags = M_Texture_ImageFlagsDict( );
+ PyObject *Noise = M_Texture_NoiseDict( );
+ PyObject *BlendModes = M_Texture_BlendModesDict( );
+ PyObject *Mappings = M_Texture_MappingsDict( );
+ PyObject *Proj = M_Texture_ProjDict( );
+
+ if( PyType_Ready( &Texture_Type ) < 0)
+ return NULL;
+
+ submodule = Py_InitModule3( "Blender.Texture",
+ M_Texture_methods, M_Texture_doc );
+
+ if( Types )
+ PyModule_AddObject( submodule, "Types", Types );
+ if( STypes )
+ PyModule_AddObject( submodule, "STypes", STypes );
+ if( TexCo )
+ PyModule_AddObject( submodule, "TexCo", TexCo );
+ if( MapTo )
+ PyModule_AddObject( submodule, "MapTo", MapTo );
+ if( Flags )
+ PyModule_AddObject( submodule, "Flags", Flags );
+ if( ExtendModes )
+ PyModule_AddObject( submodule, "ExtendModes", ExtendModes );
+ if( ImageFlags )
+ PyModule_AddObject( submodule, "ImageFlags", ImageFlags );
+ if( Noise )
+ PyModule_AddObject( submodule, "Noise", Noise );
+ if ( BlendModes )
+ PyModule_AddObject( submodule, "BlendModes", BlendModes );
+ if ( Mappings )
+ PyModule_AddObject( submodule, "Mappings", Mappings );
+ if ( Proj )
+ PyModule_AddObject( submodule, "Proj", Proj );
+
+ /* Add the MTex submodule to this module */
+ dict = PyModule_GetDict( submodule );
+ PyDict_SetItemString( dict, "MTex", MTex_Init( ) );
+
+ return submodule;
+}
+
+PyObject *Texture_CreatePyObject( Tex * tex )
+{
+ BPy_Texture *pytex;
+
+ pytex = ( BPy_Texture * ) PyObject_NEW( BPy_Texture, &Texture_Type );
+ if( !pytex )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create BPy_Texture PyObject" );
+
+ pytex->texture = tex;
+ return ( PyObject * ) pytex;
+}
+
+Tex *Texture_FromPyObject( PyObject * pyobj )
+{
+ return ( ( BPy_Texture * ) pyobj )->texture;
+}
+
+/*****************************************************************************/
+/* Python BPy_Texture methods: */
+/*****************************************************************************/
+
+static PyObject *Texture_getExtend( BPy_Texture * self )
+{
+ const char *extend = NULL;
+
+ if( EXPP_map_getStrVal
+ ( tex_extend_map, self->texture->extend, &extend ) )
+ return PyString_FromString( extend );
+
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "invalid internal extend mode" );
+}
+
+static PyObject *Texture_getImage( BPy_Texture * self )
+{
+ /* we need this to be an IMAGE texture, and we must have an image */
+ if( ( self->texture->type == TEX_IMAGE ||
+ self->texture->type == TEX_ENVMAP )
+ && self->texture->ima )
+ return Image_CreatePyObject( self->texture->ima );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Texture_oldgetSType( BPy_Texture * self )
+{
+ const char *stype = NULL;
+ int n_stype;
+
+ if( self->texture->type == TEX_VORONOI )
+ n_stype = self->texture->vn_coltype;
+#if 0
+ else if( self->texture->type == TEX_MUSGRAVE )
+ n_stype = self->texture->noisebasis;
+#endif
+ else if( self->texture->type == TEX_ENVMAP )
+ n_stype = self->texture->env->stype;
+ else
+ n_stype = self->texture->stype;
+
+ if( EXPP_map_getStrVal( tex_stype_map[self->texture->type],
+ n_stype, &stype ) )
+ return PyString_FromString( stype );
+
+
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "invalid texture stype internally" );
+}
+
+static PyObject *Texture_oldgetType( BPy_Texture * self )
+{
+ const char *type = NULL;
+
+ if( EXPP_map_getStrVal( tex_type_map, self->texture->type, &type ) )
+ return PyString_FromString( type );
+
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "invalid texture type internally" );
+}
+
+static int Texture_setAnimFrames( BPy_Texture * self, PyObject * value )
+{
+ return EXPP_setIValueClamped ( value, &self->texture->iuser.frames,
+ EXPP_TEX_ANIMFRAME_MIN,
+ EXPP_TEX_ANIMFRAME_MAX, 'h' );
+}
+
+static int Texture_setIUserCyclic( BPy_Texture * self, PyObject * value )
+{
+ int param = PyObject_IsTrue( value );
+ if( param == -1 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected True/False or 0/1" );
+
+ if( param )
+ self->texture->iuser.cycl = 1;
+ else
+ self->texture->iuser.cycl = 0;
+ return 0;
+}
+
+#if 0
+/* this was stupid to begin with! (ton) */
+static int Texture_setAnimLength( BPy_Texture * self, PyObject * value )
+{
+ return EXPP_setIValueClamped ( value, &self->texture->len,
+ EXPP_TEX_ANIMLEN_MIN,
+ EXPP_TEX_ANIMLEN_MAX, 'h' );
+}
+
+/* this is too simple to keep supporting? disabled for time being (ton) */
+static int Texture_setAnimMontage( BPy_Texture * self, PyObject * value )
+{
+ int fradur[4][2];
+ int i;
+
+ if( !PyArg_ParseTuple( value, "(ii)(ii)(ii)(ii)",
+ &fradur[0][0], &fradur[0][1],
+ &fradur[1][0], &fradur[1][1],
+ &fradur[2][0], &fradur[2][1],
+ &fradur[3][0], &fradur[3][1] ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a tuple of tuples" );
+
+ for( i = 0; i < 4; ++i ) {
+ self->texture->fradur[i][0] =
+ (short)EXPP_ClampInt ( fradur[i][0], EXPP_TEX_ANIMMONSTART_MIN,
+ EXPP_TEX_ANIMMONSTART_MAX );
+ self->texture->fradur[i][1] =
+ (short)EXPP_ClampInt ( fradur[i][1], EXPP_TEX_ANIMMONDUR_MIN,
+ EXPP_TEX_ANIMMONDUR_MAX );
+ }
+
+ return 0;
+}
+#endif
+
+static int Texture_setAnimOffset( BPy_Texture * self, PyObject * value )
+{
+ return EXPP_setIValueClamped ( value, &self->texture->iuser.offset,
+ EXPP_TEX_ANIMOFFSET_MIN,
+ EXPP_TEX_ANIMOFFSET_MAX, 'h' );
+}
+
+static int Texture_setAnimStart( BPy_Texture * self, PyObject * value )
+{
+ return EXPP_setIValueClamped ( value, &self->texture->iuser.sfra,
+ EXPP_TEX_ANIMSTART_MIN,
+ EXPP_TEX_ANIMSTART_MAX, 'h' );
+}
+
+static int Texture_setBrightness( BPy_Texture * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->texture->bright,
+ EXPP_TEX_BRIGHTNESS_MIN,
+ EXPP_TEX_BRIGHTNESS_MAX );
+}
+
+static int Texture_setContrast( BPy_Texture * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->texture->contrast,
+ EXPP_TEX_CONTRAST_MIN,
+ EXPP_TEX_CONTRAST_MAX );
+}
+
+static int Texture_setCrop( BPy_Texture * self, PyObject * value )
+{
+ float crop[4];
+
+ if( !PyArg_ParseTuple( value, "ffff",
+ &crop[0], &crop[1], &crop[2], &crop[3] ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected tuple of 4 floats" );
+
+ self->texture->cropxmin = EXPP_ClampFloat( crop[0], EXPP_TEX_CROP_MIN,
+ EXPP_TEX_CROP_MAX );
+ self->texture->cropymin = EXPP_ClampFloat( crop[1], EXPP_TEX_CROP_MIN,
+ EXPP_TEX_CROP_MAX );
+ self->texture->cropxmax = EXPP_ClampFloat( crop[2], EXPP_TEX_CROP_MIN,
+ EXPP_TEX_CROP_MAX );
+ self->texture->cropymax = EXPP_ClampFloat( crop[3], EXPP_TEX_CROP_MIN,
+ EXPP_TEX_CROP_MAX );
+
+ return 0;
+}
+
+static int Texture_setIntExtend( BPy_Texture * self, PyObject * value )
+{
+ return EXPP_setIValueRange ( value, &self->texture->extend,
+ EXPP_TEX_EXTEND_MIN,
+ EXPP_TEX_EXTEND_MAX, 'h' );
+}
+
+static int Texture_setFieldsPerImage( BPy_Texture * self,
+ PyObject * value )
+{
+ return EXPP_setIValueClamped ( value, &self->texture->iuser.fie_ima,
+ EXPP_TEX_FIEIMA_MIN,
+ EXPP_TEX_FIEIMA_MAX, 'h' );
+
+}
+
+static int Texture_setFilterSize( BPy_Texture * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->texture->filtersize,
+ EXPP_TEX_FILTERSIZE_MIN,
+ EXPP_TEX_FILTERSIZE_MAX );
+}
+
+static int Texture_setFlags( BPy_Texture * self, PyObject * value )
+{
+ int param;
+
+ if( !PyInt_Check( value ) ) {
+ char errstr[128];
+ sprintf ( errstr , "expected int bitmask of 0x%08x", TEX_FLAG_MASK );
+ return EXPP_ReturnIntError( PyExc_TypeError, errstr );
+ }
+ param = PyInt_AS_LONG ( value );
+
+ if ( ( param & TEX_FLAG_MASK ) != param )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "invalid bit(s) set in mask" );
+
+ self->texture->flag = (short)param;
+
+#if 0
+ /* if Colorband enabled, make sure we allocate memory for it */
+
+ if ( ( param & TEX_COLORBAND ) && !self->texture->coba )
+ self->texture->coba = add_colorband();
+#endif
+
+ return 0;
+}
+
+static int Texture_setImage( BPy_Texture * self, PyObject * value )
+{
+ Image *blimg = NULL;
+
+ if( !BPy_Image_Check (value) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected an Image" );
+ blimg = Image_FromPyObject( value );
+
+ if( self->texture->ima ) {
+ self->texture->ima->id.us--;
+ }
+
+ self->texture->ima = blimg;
+ id_us_plus( &blimg->id );
+
+ return 0;
+}
+
+static int Texture_setImageFlags( BPy_Texture * self, PyObject * value,
+ void *type )
+{
+ short param;
+
+ /*
+ * if type is non-zero, then attribute is "mipmap", "calcAlpha", etc.,
+ * so set/clear the bit in the bitfield based on the type
+ */
+
+ if( (int)type ) {
+ int err;
+ param = self->texture->imaflag;
+ err = EXPP_setBitfield( value, &param, (int)type, 'h' );
+ if( err )
+ return err;
+
+ /*
+ * if type is zero, then attribute is "imageFlags", so check
+ * value for a valid bitmap range.
+ */
+
+ } else {
+ int bitmask = TEX_INTERPOL
+ | TEX_USEALPHA
+ | TEX_MIPMAP
+ | TEX_IMAROT
+ | TEX_CALCALPHA
+ | TEX_NORMALMAP;
+
+ if( !PyInt_Check( value ) ) {
+ char errstr[128];
+ sprintf ( errstr , "expected int bitmask of 0x%08x", bitmask );
+ return EXPP_ReturnIntError( PyExc_TypeError, errstr );
+ }
+
+ param = (short)PyInt_AS_LONG( value );
+ if( ( param & bitmask ) != param )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "invalid bit(s) set in mask" );
+ }
+
+ /* everything is OK; save the new flag setting */
+
+ self->texture->imaflag = param;
+ return 0;
+}
+
+static int Texture_setIUserFlags( BPy_Texture * self, PyObject * value,
+ void *flag )
+{
+ int param = PyObject_IsTrue( value );
+ if( param == -1 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected True/False or 0/1" );
+
+ if( param )
+ self->texture->iuser.flag |= (int)flag;
+ else
+ self->texture->iuser.flag &= ~(int)flag;
+ return 0;
+}
+
+static int Texture_setNoiseDepth( BPy_Texture * self, PyObject * value )
+{
+ short max = EXPP_TEX_NOISEDEPTH_MAX;
+
+ /* for whatever reason, magic texture has a different max value */
+
+ if( self->texture->type == TEX_MAGIC )
+ max = EXPP_TEX_NOISEDEPTH_MAX_MAGIC;
+
+ return EXPP_setIValueClamped ( value, &self->texture->noisedepth,
+ EXPP_TEX_NOISEDEPTH_MIN, max, 'h' );
+}
+
+static int Texture_setNoiseSize( BPy_Texture * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->texture->noisesize,
+ EXPP_TEX_NOISESIZE_MIN,
+ EXPP_TEX_NOISESIZE_MAX );
+}
+
+static int Texture_setNoiseType( BPy_Texture * self, PyObject * value )
+{
+ char *param;
+
+ if( !PyString_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected string argument" );
+ param = PyString_AS_STRING( value );
+
+ if( STREQ( param, "soft" ) )
+ self->texture->noisetype = TEX_NOISESOFT;
+ else if( STREQ( param, "hard" ) )
+ self->texture->noisetype = TEX_NOISEPERL;
+ else
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "noise type must be 'soft' or 'hard'" );
+
+ return 0;
+}
+
+static int Texture_setNoiseBasis( BPy_Texture * self, PyObject * value )
+{
+ int param;
+
+ if( !PyInt_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected int (see 'Noise' constant dictionary)" );
+
+ param = PyInt_AS_LONG ( value );
+
+ if ( param < TEX_BLENDER
+ || ( param > TEX_VORONOI_CRACKLE
+ && param != TEX_CELLNOISE ) )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "invalid noise type" );
+
+ self->texture->noisebasis = (short)param;
+ return 0;
+}
+
+static int Texture_setNoiseBasis2( BPy_Texture * self, PyObject * value,
+ void *type )
+{
+ /*
+ * if type is EXPP_TEX_NOISEBASIS2, then this is the "noiseBasis2"
+ * attribute, so check the range and set the whole value
+ */
+
+ if( (int)type == EXPP_TEX_NOISEBASIS2 ) {
+ int param;
+ if( !PyInt_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected int (see 'Noise' constant dictionary)" );
+
+ param = PyInt_AS_LONG ( value );
+
+ if ( param < TEX_BLENDER
+ || ( param > TEX_VORONOI_CRACKLE
+ && param != TEX_CELLNOISE ) )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "invalid noise type" );
+
+ self->texture->noisebasis2 = (short)param;
+
+ /*
+ * for other type values, the attribute is "sine", "saw" or "tri",
+ * so set the noise basis to the supplied type if value is 1
+ */
+
+ } else {
+ if( !PyInt_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected int value of 1" );
+
+ if( PyInt_AS_LONG ( value ) != 1 )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "expected int value of 1" );
+
+ self->texture->noisebasis2 = (short)(int)type;
+ }
+ return 0;
+}
+
+static int Texture_setRepeat( BPy_Texture * self, PyObject * args )
+{
+ int repeat[2];
+
+ if( !PyArg_ParseTuple( args, "ii", &repeat[0], &repeat[1] ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected tuple of 2 ints" );
+
+ self->texture->xrepeat = (short)EXPP_ClampInt( repeat[0], EXPP_TEX_REPEAT_MIN,
+ EXPP_TEX_REPEAT_MAX );
+ self->texture->yrepeat = (short)EXPP_ClampInt( repeat[1], EXPP_TEX_REPEAT_MIN,
+ EXPP_TEX_REPEAT_MAX );
+
+ return 0;
+}
+
+static int Texture_setRGBCol( BPy_Texture * self, PyObject * args )
+{
+ float rgb[3];
+
+ if( !PyArg_ParseTuple( args, "fff", &rgb[0], &rgb[1], &rgb[2] ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected tuple of 3 floats" );
+
+ self->texture->rfac = EXPP_ClampFloat( rgb[0], EXPP_TEX_RGBCOL_MIN,
+ EXPP_TEX_RGBCOL_MAX );
+ self->texture->gfac = EXPP_ClampFloat( rgb[1], EXPP_TEX_RGBCOL_MIN,
+ EXPP_TEX_RGBCOL_MAX );
+ self->texture->bfac = EXPP_ClampFloat( rgb[2], EXPP_TEX_RGBCOL_MIN,
+ EXPP_TEX_RGBCOL_MAX );
+
+ return 0;
+}
+
+static int Texture_setSType( BPy_Texture * self, PyObject * value )
+{
+ short param;
+ const char *dummy = NULL;
+
+ if( !PyInt_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected int argument" );
+
+ param = (short)PyInt_AS_LONG ( value );
+
+ /* use the stype map to find out if this is a valid stype for this type *
+ * note that this will allow CLD_COLOR when type is ENVMAP. there's not *
+ * much that we can do about this though. */
+ if( !EXPP_map_getStrVal
+ ( tex_stype_map[self->texture->type], param, &dummy ) )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "invalid stype (for this type)" );
+
+ if( self->texture->type == TEX_VORONOI )
+ self->texture->vn_coltype = param;
+#if 0
+ else if( self->texture->type == TEX_MUSGRAVE )
+ self->texture->noisebasis = param;
+#endif
+ else if( self->texture->type == TEX_ENVMAP )
+ self->texture->env->stype = param;
+ else
+ self->texture->stype = param;
+
+ return 0;
+}
+
+static int Texture_setTurbulence( BPy_Texture * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->texture->turbul,
+ EXPP_TEX_TURBULENCE_MIN,
+ EXPP_TEX_TURBULENCE_MAX );
+}
+
+static int Texture_setHFracDim( BPy_Texture * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->texture->mg_H,
+ EXPP_TEX_MH_G_MIN,
+ EXPP_TEX_MH_G_MAX );
+}
+
+static int Texture_setLacunarity( BPy_Texture * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->texture->mg_lacunarity,
+ EXPP_TEX_LACUNARITY_MIN,
+ EXPP_TEX_LACUNARITY_MAX );
+}
+
+static int Texture_setOcts( BPy_Texture * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->texture->mg_octaves,
+ EXPP_TEX_OCTS_MIN,
+ EXPP_TEX_OCTS_MAX );
+}
+
+static int Texture_setIScale( BPy_Texture * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->texture->ns_outscale,
+ EXPP_TEX_ISCALE_MIN,
+ EXPP_TEX_ISCALE_MAX );
+}
+
+static int Texture_setType( BPy_Texture * self, PyObject * value )
+{
+ int err = EXPP_setIValueRange ( value, &self->texture->type,
+ EXPP_TEX_TYPE_MIN,
+ EXPP_TEX_TYPE_MAX, 'h' );
+
+ /*
+ * if we set the texture OK, and it's a environment map, and
+ * there is no environment map yet, allocate one (code borrowed
+ * from texture_panel_envmap() in source/blender/src/buttons_shading.c)
+ */
+
+ if( !err && self->texture->type == TEX_ENVMAP
+ && !self->texture->env ) {
+ self->texture->env = BKE_add_envmap();
+ self->texture->env->object= OBACT;
+ }
+ return err;
+}
+
+static int Texture_setDistMetric( BPy_Texture * self, PyObject * value )
+{
+#if 0
+ char *dist = NULL;
+
+ if( !PyArg_ParseTuple( value, "s", &dist ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument" );
+
+ /* can we really trust texture->type? */
+ if( self->texture->type == TEX_VORONOI &&
+ !EXPP_map_getShortVal( tex_stype_map[self->texture->type + 2],
+ dist, &self->texture->vn_distm ) )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "invalid dist metric type" );
+
+ Py_RETURN_NONE;
+#else
+ return EXPP_setIValueRange ( value, &self->texture->vn_distm,
+ TEX_DISTANCE,
+ TEX_MINKOVSKY, 'h' );
+#endif
+}
+
+static int Texture_setExp( BPy_Texture * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->texture->vn_mexp,
+ EXPP_TEX_EXP_MIN,
+ EXPP_TEX_EXP_MAX );
+}
+
+static int Texture_setWeight1( BPy_Texture * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->texture->vn_w1,
+ EXPP_TEX_WEIGHT1_MIN,
+ EXPP_TEX_WEIGHT1_MAX );
+}
+
+static int Texture_setWeight2( BPy_Texture * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->texture->vn_w2,
+ EXPP_TEX_WEIGHT2_MIN,
+ EXPP_TEX_WEIGHT2_MAX );
+}
+
+static int Texture_setWeight3( BPy_Texture * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->texture->vn_w3,
+ EXPP_TEX_WEIGHT3_MIN,
+ EXPP_TEX_WEIGHT3_MAX );
+}
+
+static int Texture_setWeight4( BPy_Texture * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->texture->vn_w4,
+ EXPP_TEX_WEIGHT4_MIN,
+ EXPP_TEX_WEIGHT4_MAX );
+}
+
+static int Texture_setDistAmnt( BPy_Texture * self, PyObject * value )
+{
+ return EXPP_setFloatClamped ( value, &self->texture->dist_amount,
+ EXPP_TEX_DISTAMNT_MIN,
+ EXPP_TEX_DISTAMNT_MAX );
+}
+
+static PyObject *Texture_getIpo( BPy_Texture * self )
+{
+ struct Ipo *ipo = self->texture->ipo;
+
+ if( !ipo )
+ Py_RETURN_NONE;
+
+ return Ipo_CreatePyObject( ipo );
+}
+
+/*
+ * this should accept a Py_None argument and just delete the Ipo link
+ * (as Texture_clearIpo() does)
+ */
+
+static int Texture_setIpo( BPy_Texture * self, PyObject * value )
+{
+ Ipo *ipo = NULL;
+ Ipo *oldipo = self->texture->ipo;
+ ID *id;
+
+ /* if parameter is not None, check for valid Ipo */
+
+ if ( value != Py_None ) {
+ if ( !BPy_Ipo_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "expected an Ipo object" );
+
+ ipo = Ipo_FromPyObject( value );
+
+ if( !ipo )
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "null ipo!" );
+
+ if( ipo->blocktype != ID_TE )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "Ipo is not a texture data Ipo" );
+ }
+
+ /* if already linked to Ipo, delete link */
+
+ if ( oldipo ) {
+ id = &oldipo->id;
+ if( id->us > 0 )
+ id->us--;
+ }
+
+ /* assign new Ipo and increment user count, or set to NULL if deleting */
+
+ self->texture->ipo = ipo;
+ if ( ipo ) {
+ id = &ipo->id;
+ id_us_plus(id);
+ }
+
+ return 0;
+}
+
+static PyObject *Texture_getAnimFrames( BPy_Texture *self )
+{
+ return PyInt_FromLong( self->texture->iuser.frames );
+}
+
+static PyObject *Texture_getIUserCyclic( BPy_Texture *self )
+{
+ if( self->texture->iuser.cycl )
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+}
+
+#if 0
+/* disabled. this option was too stupid! (ton) */
+static PyObject *Texture_getAnimLength( BPy_Texture *self )
+{
+ return PyInt_FromLong( self->texture->len );
+}
+
+static PyObject *Texture_getAnimMontage( BPy_Texture *self )
+{
+ return Py_BuildValue( "((i,i),(i,i),(i,i),(i,i))",
+ self->texture->fradur[0][0],
+ self->texture->fradur[0][1],
+ self->texture->fradur[1][0],
+ self->texture->fradur[1][1],
+ self->texture->fradur[2][0],
+ self->texture->fradur[2][1],
+ self->texture->fradur[3][0],
+ self->texture->fradur[3][1] );
+}
+#endif
+
+static PyObject *Texture_getAnimOffset( BPy_Texture *self )
+{
+ return PyInt_FromLong( self->texture->iuser.offset );
+}
+
+static PyObject *Texture_getAnimStart( BPy_Texture *self )
+{
+ return PyInt_FromLong( self->texture->iuser.sfra );
+}
+
+static PyObject *Texture_getBrightness( BPy_Texture *self )
+{
+ return PyFloat_FromDouble ( self->texture->bright );
+}
+
+static PyObject *Texture_getContrast( BPy_Texture *self )
+{
+ return PyFloat_FromDouble( self->texture->contrast );
+}
+
+static PyObject *Texture_getCrop( BPy_Texture *self )
+{
+ return Py_BuildValue( "(f,f,f,f)",
+ self->texture->cropxmin,
+ self->texture->cropymin,
+ self->texture->cropxmax,
+ self->texture->cropymax );
+}
+
+static PyObject *Texture_getDistAmnt( BPy_Texture *self )
+{
+ return PyFloat_FromDouble( self->texture->dist_amount );
+}
+
+static PyObject *Texture_getDistMetric( BPy_Texture *self )
+{
+ return PyInt_FromLong( self->texture->vn_distm );
+}
+
+static PyObject *Texture_getExp( BPy_Texture *self )
+{
+ return PyFloat_FromDouble( self->texture->vn_mexp );
+}
+
+static PyObject *Texture_getIntExtend( BPy_Texture * self )
+{
+ return PyInt_FromLong( self->texture->extend );
+}
+
+static PyObject *Texture_getFieldsPerImage( BPy_Texture *self )
+{
+ return PyInt_FromLong( self->texture->iuser.fie_ima );
+}
+
+static PyObject *Texture_getFilterSize( BPy_Texture *self )
+{
+ return PyFloat_FromDouble( self->texture->filtersize );
+}
+
+static PyObject *Texture_getFlags( BPy_Texture *self )
+{
+ return PyInt_FromLong( self->texture->flag );
+}
+
+static PyObject *Texture_getHFracDim( BPy_Texture *self )
+{
+ return PyInt_FromLong( (long)self->texture->mg_H );
+}
+
+static PyObject *Texture_getImageFlags( BPy_Texture *self, void *type )
+{
+ /* type == 0 means attribute "imageFlags"
+ * other types means attribute "mipmap", "calcAlpha", etc
+ */
+
+ if( (int)type )
+ return EXPP_getBitfield( &self->texture->imaflag, (int)type, 'h' );
+ else
+ return PyInt_FromLong( self->texture->imaflag );
+}
+
+static PyObject *Texture_getIUserFlags( BPy_Texture *self, void *flag )
+{
+ if( self->texture->iuser.flag & (int)flag )
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+}
+
+static PyObject *Texture_getIScale( BPy_Texture *self )
+{
+ return PyFloat_FromDouble( self->texture->ns_outscale );
+}
+
+static PyObject *Texture_getLacunarity( BPy_Texture *self )
+{
+ return PyFloat_FromDouble( self->texture->mg_lacunarity );
+}
+
+static PyObject *Texture_getNoiseBasis( BPy_Texture *self )
+{
+ return PyInt_FromLong( self->texture->noisebasis );
+}
+
+static PyObject *Texture_getNoiseBasis2( BPy_Texture *self, void *type )
+{
+ /* type == EXPP_TEX_NOISEBASIS2 means attribute "noiseBasis2"
+ * other types means attribute "sine", "saw", or "tri" attribute
+ */
+
+ if( (int)type == EXPP_TEX_NOISEBASIS2 )
+ return PyInt_FromLong( self->texture->noisebasis2 );
+ else
+ return PyInt_FromLong( ( self->texture->noisebasis2 == (int)type ) ? 1 : 0 );
+}
+
+static PyObject *Texture_getNoiseDepth( BPy_Texture *self )
+{
+ return PyInt_FromLong( self->texture->noisedepth );
+}
+
+static PyObject *Texture_getNoiseSize( BPy_Texture *self )
+{
+ return PyFloat_FromDouble( self->texture->noisesize );
+}
+
+static PyObject *Texture_getNoiseType( BPy_Texture *self )
+{
+ if ( self->texture->noisetype == TEX_NOISESOFT )
+ return PyString_FromString( "soft" );
+ else
+ return PyString_FromString( "hard" );
+}
+
+static PyObject *Texture_getOcts( BPy_Texture *self )
+{
+ return PyFloat_FromDouble( self->texture->mg_octaves );
+}
+
+static PyObject *Texture_getRepeat( BPy_Texture *self )
+{
+ return Py_BuildValue( "(i,i)", self->texture->xrepeat,
+ self->texture->yrepeat );
+}
+
+static PyObject *Texture_getRGBCol( BPy_Texture *self )
+{
+ return Py_BuildValue( "(f,f,f)", self->texture->rfac,
+ self->texture->gfac, self->texture->bfac );
+}
+
+static PyObject *Texture_getSType( BPy_Texture *self )
+{
+ if( self->texture->type == TEX_VORONOI )
+ return PyInt_FromLong( self->texture->vn_coltype );
+#if 0
+ if( self->texture->type == TEX_MUSGRAVE )
+ return PyInt_FromLong( self->texture->noisebasis );
+#endif
+ if( self->texture->type == TEX_ENVMAP )
+ return PyInt_FromLong( self->texture->env->stype );
+
+ return PyInt_FromLong( self->texture->stype );
+}
+
+static PyObject *Texture_getTurbulence( BPy_Texture *self )
+{
+ return PyFloat_FromDouble( self->texture->turbul );
+}
+
+static PyObject *Texture_getType( BPy_Texture *self )
+{
+ return PyInt_FromLong( self->texture->type );
+}
+
+static PyObject *Texture_getWeight1( BPy_Texture *self )
+{
+ return PyFloat_FromDouble( self->texture->vn_w1 );
+}
+
+static PyObject *Texture_getWeight2( BPy_Texture *self )
+{
+ return PyFloat_FromDouble( self->texture->vn_w2 );
+}
+
+static PyObject *Texture_getWeight3( BPy_Texture *self )
+{
+ return PyFloat_FromDouble( self->texture->vn_w3 );
+}
+
+static PyObject *Texture_getWeight4( BPy_Texture *self )
+{
+ return PyFloat_FromDouble( self->texture->vn_w4 );
+}
+
+/* #####DEPRECATED###### */
+
+static PyObject *Texture_oldsetImage( BPy_Texture * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args,
+ (setter)Texture_setImage );
+}
+
+static PyObject *Texture_oldsetIpo( BPy_Texture * self, PyObject * args )
+{
+ return EXPP_setterWrapper ( (void *)self, args, (setter)Texture_setIpo );
+}
+
+/*
+ * clearIpo() returns True/False depending on whether material has an Ipo
+ */
+
+static PyObject *Texture_clearIpo( BPy_Texture * self )
+{
+ /* if Ipo defined, delete it and return true */
+
+ if( self->texture->ipo ) {
+ PyObject *value = Py_BuildValue( "(O)", Py_None );
+ EXPP_setterWrapper( (void *)self, value, (setter)Texture_setIpo );
+ Py_DECREF( value );
+ return EXPP_incr_ret_True();
+ }
+ return EXPP_incr_ret_False(); /* no ipo found */
+}
+
+/*
+ * these older setter methods take strings as parameters; check the list of
+ * strings to figure out which bits to set, then call new attribute setters
+ * using the wrapper.
+ */
+
+static PyObject *Texture_oldsetFlags( BPy_Texture * self, PyObject * args )
+{
+ unsigned int i, flag = 0;
+ PyObject *value, *error;
+
+ /* check that we're passed a tuple */
+
+ if ( !PyTuple_Check( args ) )
+ return EXPP_ReturnPyObjError ( PyExc_AttributeError,
+ "expected a tuple of string arguments" );
+
+ /* check each argument for type, find its value */
+
+ for ( i = PyTuple_Size( args ); i-- ; ) {
+ short thisflag;
+ char * name = PyString_AsString( PyTuple_GET_ITEM( args, i ) );
+ if( !name )
+ return EXPP_ReturnPyObjError ( PyExc_AttributeError,
+ "expected string argument" );
+
+ if( !EXPP_map_getShortVal( tex_flag_map, name, &thisflag ) )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "unknown Texture flag argument" ) );
+
+ flag |= thisflag;
+ }
+
+ /* build tuple, call wrapper */
+
+ value = Py_BuildValue( "(i)", flag );
+ error = EXPP_setterWrapper( (void *)self, value, (setter)Texture_setFlags );
+ Py_DECREF ( value );
+ return error;
+}
+
+/*
+ * Texture_oldsetType() and Texture_oldsetExtend()
+ *
+ * These older setter methods convert a string into an integer setting, so
+ * doesn't make sense to try wrapping them.
+ */
+
+static PyObject *Texture_oldsetType( BPy_Texture * self, PyObject * args )
+{
+ char *type = NULL;
+
+ if( !PyArg_ParseTuple( args, "s", &type ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument" );
+
+ if( !EXPP_map_getShortVal( tex_type_map, type, &self->texture->type ) )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "invalid texture type" );
+
+ /*
+ * if we set the texture OK, and it's a environment map, and
+ * there is no environment map yet, allocate one (code borrowed
+ * from texture_panel_envmap() in source/blender/src/buttons_shading.c)
+ */
+
+ if( self->texture->type == TEX_ENVMAP
+ && !self->texture->env ) {
+ self->texture->env = BKE_add_envmap();
+ self->texture->env->object= OBACT;
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Texture_oldsetExtend( BPy_Texture * self, PyObject * args )
+{
+ char *extend = NULL;
+ if( !PyArg_ParseTuple( args, "s", &extend ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument" );
+
+ if( !EXPP_map_getShortVal
+ ( tex_extend_map, extend, &self->texture->extend ) )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "invalid extend mode" );
+
+ Py_RETURN_NONE;
+}
+
+/*
+ * Texture_oldsetNoiseBasis(), Texture_oldsetDistNoise()
+ * Texture_oldsetSType(), Texture_oldsetDistMetric(),
+ * Texture_oldsetImageFlags()
+ *
+ * these old setter methods behave differently from the attribute
+ * setters, so they are left unchanged.
+ */
+
+static PyObject *Texture_oldsetNoiseBasis( BPy_Texture * self, PyObject * args )
+{
+/* NOTE: leave as-is: don't use setterWrapper */
+ char *nbasis;
+
+ if( !PyArg_ParseTuple( args, "s", &nbasis ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument" );
+ if( self->texture->type == TEX_MUSGRAVE &&
+ EXPP_map_getShortVal( tex_stype_map[TEX_DISTNOISE],
+ nbasis, &self->texture->noisebasis ) );
+ else if( self->texture->type == TEX_DISTNOISE &&
+ !EXPP_map_getShortVal( tex_stype_map[TEX_DISTNOISE],
+ nbasis, &self->texture->noisebasis2 ) )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "invalid noise basis" );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Texture_oldsetDistNoise( BPy_Texture * self, PyObject * args )
+{
+/* NOTE: leave as-is: don't use setterWrapper */
+ char *nbasis;
+
+ if( !PyArg_ParseTuple( args, "s", &nbasis ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument" );
+ if( self->texture->type == TEX_DISTNOISE &&
+ !EXPP_map_getShortVal( tex_stype_map[TEX_DISTNOISE],
+ nbasis, &self->texture->noisebasis ) )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "invalid noise basis" );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Texture_oldsetSType( BPy_Texture * self, PyObject * args )
+{
+ char *stype = NULL;
+ if( !PyArg_ParseTuple( args, "s", &stype ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument" );
+
+ /* can we really trust texture->type? */
+ if( ( self->texture->type == TEX_VORONOI &&
+ EXPP_map_getShortVal( tex_stype_map[self->texture->type],
+ stype, &self->texture->vn_coltype ) ) );
+#if 0
+ else if( ( self->texture->type == TEX_MUSGRAVE &&
+ EXPP_map_getShortVal( tex_stype_map
+ [TEX_DISTNOISE], stype,
+ &self->texture->noisebasis ) ) );
+#endif
+ else if( ( self->texture->type == TEX_ENVMAP &&
+ EXPP_map_getShortVal( tex_stype_map[self->texture->type],
+ stype, &self->texture->env->stype ) ) );
+ else if( !EXPP_map_getShortVal
+ ( tex_stype_map[self->texture->type], stype,
+ &self->texture->stype ) )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "invalid texture stype" );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Texture_oldsetDistMetric( BPy_Texture * self, PyObject * args )
+{
+/* NOTE: leave as-is: don't use setterWrapper */
+ char *dist = NULL;
+
+ if( !PyArg_ParseTuple( args, "s", &dist ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument" );
+ /* can we really trust texture->type? */
+ if( self->texture->type == TEX_VORONOI &&
+ !EXPP_map_getShortVal( tex_stype_map[self->texture->type + 2],
+ dist, &self->texture->vn_distm ) )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "invalid dist metric type" );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Texture_oldsetImageFlags( BPy_Texture * self, PyObject * args )
+{
+ unsigned int i, flag = 0;
+
+ /* check that we're passed a tuple of no more than 3 args*/
+
+ if( !PyTuple_Check( args ) )
+ return EXPP_ReturnPyObjError ( PyExc_AttributeError,
+ "expected tuple of string arguments" );
+
+ /* check each argument for type, find its value */
+
+ for( i = PyTuple_Size( args ); i-- ; ) {
+ short thisflag;
+ char * name = PyString_AsString( PyTuple_GET_ITEM( args, i ) );
+ if( !name )
+ return EXPP_ReturnPyObjError ( PyExc_AttributeError,
+ "expected string argument" );
+
+ if( !EXPP_map_getShortVal( tex_imageflag_map, name, &thisflag ) )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "unknown Texture image flag name" );
+
+ flag |= thisflag;
+ }
+
+ self->texture->imaflag = (short)flag;
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *Texture_getColorband( BPy_Texture * self)
+{
+ return EXPP_PyList_fromColorband( self->texture->coba );
+}
+
+int Texture_setColorband( BPy_Texture * self, PyObject * value)
+{
+ return EXPP_Colorband_fromPyList( &self->texture->coba, value );
+}
+
+static PyObject *Texture_evaluate( BPy_Texture * self, VectorObject * vec_in )
+{
+ TexResult texres= {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, NULL};
+ float vec[4];
+ /* int rgbnor; dont use now */
+
+ if(!VectorObject_Check(vec_in) || vec_in->size < 3)
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "expects a 3D vector object");
+
+ /* rgbnor = .. we don't need this now */
+ multitex_ext(self->texture, vec_in->vec, NULL, NULL, 1, &texres);
+
+ vec[0] = texres.tr;
+ vec[1] = texres.tg;
+ vec[2] = texres.tb;
+ vec[3] = texres.tin;
+
+ return newVectorObject(vec, 4, Py_NEW);
+}
+
+static PyObject *Texture_copy( BPy_Texture * self )
+{
+ Tex *tex = copy_texture(self->texture );
+ tex->id.us = 0;
+ return Texture_CreatePyObject(tex);
+}
diff --git a/source/blender/python/api2_2x/Texture.h b/source/blender/python/api2_2x/Texture.h
new file mode 100644
index 00000000000..a5451687779
--- /dev/null
+++ b/source/blender/python/api2_2x/Texture.h
@@ -0,0 +1,64 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Alex Mole
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+/* based on Image.h */
+
+#ifndef EXPP_TEXTURE_H
+#define EXPP_TEXTURE_H
+
+#include <Python.h>
+#include "DNA_texture_types.h"
+
+/*****************************************************************************/
+/* Python BPy_Texture structure definition */
+/*****************************************************************************/
+
+typedef struct {
+ PyObject_HEAD
+ Tex * texture; /* libdata must be second */
+} BPy_Texture;
+
+extern PyTypeObject Texture_Type;
+
+#define BPy_Texture_Check(v) ((v)->ob_type == &Texture_Type)
+
+
+/*****************************************************************************/
+/* Module Blender.Texture - public functions */
+/*****************************************************************************/
+
+PyObject *Texture_Init( void );
+PyObject *Texture_CreatePyObject( struct Tex *tex );
+Tex *Texture_FromPyObject( PyObject * pyobj );
+
+
+#endif /* EXPP_TEXTURE_H */
diff --git a/source/blender/python/api2_2x/Types.c b/source/blender/python/api2_2x/Types.c
new file mode 100644
index 00000000000..8b51c590a5b
--- /dev/null
+++ b/source/blender/python/api2_2x/Types.c
@@ -0,0 +1,262 @@
+/*
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano, Alex Mole, Joseph Gilbert
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#include "Types.h"
+#include "IDProp.h"
+/*
+ stuff pasted from the old Types.h
+ is only need here now
+*/
+
+extern PyTypeObject IDGroup_Type, IDArray_Type;
+extern PyTypeObject Action_Type, Armature_Type;
+extern PyTypeObject Pose_Type;
+extern PyTypeObject BezTriple_Type, Bone_Type, Button_Type;
+extern PyTypeObject Camera_Type;
+extern PyTypeObject CurNurb_Type, SurfNurb_Type;
+extern PyTypeObject Curve_Type;
+extern PyTypeObject Effect_Type, Font_Type;
+extern PyTypeObject Image_Type, Ipo_Type, IpoCurve_Type;
+extern PyTypeObject Lamp_Type, Lattice_Type;
+extern PyTypeObject Material_Type, Metaball_Type, MTex_Type;
+extern PyTypeObject NMFace_Type, NMEdge_Type, NMVert_Type, NMCol_Type,
+ NMesh_Type;
+extern PyTypeObject MFace_Type, MVert_Type, PVert_Type, MEdge_Type, MCol_Type,
+ Mesh_Type;
+
+extern PyTypeObject Object_Type;
+extern PyTypeObject Group_Type;
+extern PyTypeObject Particle_Type;
+extern PyTypeObject Scene_Type, RenderData_Type;
+extern PyTypeObject Text_Type, Text3d_Type, Texture_Type;
+extern PyTypeObject World_Type;
+extern PyTypeObject property_Type;
+extern PyTypeObject buffer_Type, constant_Type, euler_Type;
+extern PyTypeObject matrix_Type, quaternion_Type, rgbTuple_Type, vector_Type;
+extern PyTypeObject point_Type;
+extern PyTypeObject Modifier_Type, ModSeq_Type;
+extern PyTypeObject EditBone_Type;
+extern PyTypeObject ThemeSpace_Type;
+extern PyTypeObject ThemeUI_Type;
+extern PyTypeObject TimeLine_Type;
+
+char M_Types_doc[] = "The Blender Types module\n\n\
+This module is a dictionary of all Blender Python types";
+
+struct PyMethodDef Null_methods[] = { {NULL, NULL, 0, NULL} };
+
+
+
+/* The internal types (lowercase first letter, like constant_Type) are only
+ * set when some object initializes them. But unless we do it early, we get
+ * some easy and unpredictable (varies with platform, even distro) ways to
+ * crash Blender. Some modules also need this early up, so let's generalize
+ * and init all our pytypes here.
+ */
+
+void types_InitAll( void )
+{
+ Action_Type.ob_type = &PyType_Type;
+ Pose_Type.ob_type = &PyType_Type;
+ Armature_Type.ob_type = &PyType_Type;
+ BezTriple_Type.ob_type = &PyType_Type;
+ Bone_Type.ob_type = &PyType_Type;
+ Button_Type.ob_type = &PyType_Type;
+ Camera_Type.ob_type = &PyType_Type;
+ CurNurb_Type.ob_type = &PyType_Type;
+ Curve_Type.ob_type = &PyType_Type;
+ Effect_Type.ob_type = &PyType_Type;
+ Image_Type.ob_type = &PyType_Type;
+ Ipo_Type.ob_type = &PyType_Type;
+ IpoCurve_Type.ob_type = &PyType_Type;
+ Lamp_Type.ob_type = &PyType_Type;
+ Lattice_Type.ob_type = &PyType_Type;
+ Material_Type.ob_type = &PyType_Type;
+ Metaball_Type.ob_type = &PyType_Type;
+ MTex_Type.ob_type = &PyType_Type;
+ NMCol_Type.ob_type = &PyType_Type;
+ NMFace_Type.ob_type = &PyType_Type;
+ NMEdge_Type.ob_type = &PyType_Type;
+ NMVert_Type.ob_type = &PyType_Type;
+ NMesh_Type.ob_type = &PyType_Type;
+ MFace_Type.ob_type = &PyType_Type;
+ MVert_Type.ob_type = &PyType_Type;
+ PVert_Type.ob_type = &PyType_Type;
+ MEdge_Type.ob_type = &PyType_Type;
+ MCol_Type.ob_type = &PyType_Type;
+ Mesh_Type.ob_type = &PyType_Type;
+ Object_Type.ob_type = &PyType_Type;
+ Group_Type.ob_type = &PyType_Type;
+ RenderData_Type.ob_type = &PyType_Type;
+ Scene_Type.ob_type = &PyType_Type;
+ SurfNurb_Type.ob_type = &PyType_Type;
+ Text_Type.ob_type = &PyType_Type;
+ Text3d_Type.ob_type = &PyType_Type;
+ Texture_Type.ob_type = &PyType_Type;
+ //TimeLine_Type.ob_type = &PyType_Type;
+ World_Type.ob_type = &PyType_Type;
+ buffer_Type.ob_type = &PyType_Type;
+ constant_Type.ob_type = &PyType_Type;
+ euler_Type.ob_type = &PyType_Type;
+ matrix_Type.ob_type = &PyType_Type;
+ quaternion_Type.ob_type = &PyType_Type;
+ PyType_Ready( &rgbTuple_Type );
+ vector_Type.ob_type = &PyType_Type;
+ property_Type.ob_type = &PyType_Type;
+ point_Type.ob_type = &PyType_Type;
+ PyType_Ready( &Modifier_Type );
+ PyType_Ready( &ModSeq_Type );
+ PyType_Ready( &EditBone_Type );
+ PyType_Ready( &ThemeSpace_Type );
+ PyType_Ready( &ThemeUI_Type );
+ IDProp_Init_Types();
+}
+
+/*****************************************************************************/
+/* Function: Types_Init */
+/*****************************************************************************/
+PyObject *Types_Init( void )
+{
+ PyObject *submodule, *dict;
+
+ submodule =
+ Py_InitModule3( "Blender.Types", Null_methods, M_Types_doc );
+
+ dict = PyModule_GetDict( submodule );
+
+ /* The Blender Object Type */
+
+ PyDict_SetItemString( dict, "ObjectType",
+ ( PyObject * ) &Object_Type );
+
+ /* Blender Object Data Types */
+
+ PyDict_SetItemString( dict, "GroupType",
+ ( PyObject * ) &Group_Type );
+
+ PyDict_SetItemString( dict, "SceneType", ( PyObject * ) &Scene_Type );
+ PyDict_SetItemString( dict, "RenderDataType",
+ ( PyObject * ) &RenderData_Type );
+
+ PyDict_SetItemString( dict, "NMeshType", ( PyObject * ) &NMesh_Type );
+ PyDict_SetItemString( dict, "NMFaceType",
+ ( PyObject * ) &NMFace_Type );
+ PyDict_SetItemString( dict, "NMVertType",
+ ( PyObject * ) &NMVert_Type );
+ PyDict_SetItemString( dict, "NMEdgeType",
+ ( PyObject * ) &NMEdge_Type );
+ PyDict_SetItemString( dict, "NMColType", ( PyObject * ) &NMCol_Type );
+
+ PyDict_SetItemString( dict, "MeshType", ( PyObject * ) &Mesh_Type );
+ PyDict_SetItemString( dict, "MFaceType",
+ ( PyObject * ) &MFace_Type );
+ PyDict_SetItemString( dict, "MEdgeType",
+ ( PyObject * ) &MEdge_Type );
+ PyDict_SetItemString( dict, "MVertType",
+ ( PyObject * ) &MVert_Type );
+ PyDict_SetItemString( dict, "PVertType",
+ ( PyObject * ) &PVert_Type );
+ PyDict_SetItemString( dict, "MColType", ( PyObject * ) &MCol_Type );
+
+ PyDict_SetItemString( dict, "ArmatureType",
+ ( PyObject * ) &Armature_Type );
+ PyDict_SetItemString( dict, "BoneType", ( PyObject * ) &Bone_Type );
+
+ PyDict_SetItemString( dict, "CurNurb_Type",
+ ( PyObject * ) &CurNurb_Type );
+ PyDict_SetItemString( dict, "SurfNurb_Type",
+ ( PyObject * ) &SurfNurb_Type );
+ PyDict_SetItemString( dict, "CurveType", ( PyObject * ) &Curve_Type );
+
+ PyDict_SetItemString( dict, "IpoType", ( PyObject * ) &Ipo_Type );
+ PyDict_SetItemString( dict, "MetaballType",
+ ( PyObject * ) &Metaball_Type );
+
+ PyDict_SetItemString( dict, "CameraType",
+ ( PyObject * ) &Camera_Type );
+ PyDict_SetItemString( dict, "ImageType", ( PyObject * ) &Image_Type );
+ PyDict_SetItemString( dict, "LampType", ( PyObject * ) &Lamp_Type );
+ PyDict_SetItemString( dict, "TextType", ( PyObject * ) &Text_Type );
+ PyDict_SetItemString( dict, "Text3dType", ( PyObject * ) &Text3d_Type );
+ PyDict_SetItemString( dict, "MaterialType",
+ ( PyObject * ) &Material_Type );
+
+ PyDict_SetItemString( dict, "ButtonType",
+ ( PyObject * ) &Button_Type );
+
+ PyDict_SetItemString( dict, "LatticeType",
+ ( PyObject * ) &Lattice_Type );
+
+ PyDict_SetItemString( dict, "TextureType",
+ ( PyObject * ) &Texture_Type );
+ PyDict_SetItemString( dict, "MTexType", ( PyObject * ) &MTex_Type );
+
+ /* External helper Types available to the main ones above */
+
+ PyDict_SetItemString( dict, "vectorType",
+ ( PyObject * ) &vector_Type );
+ PyDict_SetItemString( dict, "bufferType",
+ ( PyObject * ) &buffer_Type );
+ PyDict_SetItemString( dict, "constantType",
+ ( PyObject * ) &constant_Type );
+ PyDict_SetItemString( dict, "rgbTupleType",
+ ( PyObject * ) &rgbTuple_Type );
+ PyDict_SetItemString( dict, "matrix_Type",
+ ( PyObject * ) &matrix_Type );
+ PyDict_SetItemString( dict, "eulerType", ( PyObject * ) &euler_Type );
+ PyDict_SetItemString( dict, "quaternionType",
+ ( PyObject * ) &quaternion_Type );
+ PyDict_SetItemString( dict, "BezTripleType",
+ ( PyObject * ) &BezTriple_Type );
+ PyDict_SetItemString( dict, "ActionType",
+ ( PyObject * ) &Action_Type );
+ PyDict_SetItemString( dict, "PoseType",
+ ( PyObject * ) &Pose_Type );
+ PyDict_SetItemString( dict, "propertyType",
+ ( PyObject * ) &property_Type );
+ PyDict_SetItemString( dict, "pointType",
+ ( PyObject * ) &point_Type );
+ PyDict_SetItemString( dict, "ModifierType",
+ ( PyObject * ) &Modifier_Type );
+ PyDict_SetItemString( dict, "ModSeqType",
+ ( PyObject * ) &ModSeq_Type );
+ PyDict_SetItemString( dict, "EditBoneType",
+ ( PyObject * ) &EditBone_Type);
+ PyDict_SetItemString( dict, "ThemeSpaceType",
+ ( PyObject * ) &ThemeSpace_Type);
+ PyDict_SetItemString( dict, "ThemeUI_Type",
+ ( PyObject * ) &ThemeUI_Type);
+ PyDict_SetItemString( dict, "IDGroupType",
+ ( PyObject * ) &IDGroup_Type);
+ PyDict_SetItemString( dict, "IDArrayType",
+ ( PyObject * ) &IDArray_Type);
+ return submodule;
+}
diff --git a/source/blender/python/api2_2x/Types.h b/source/blender/python/api2_2x/Types.h
new file mode 100644
index 00000000000..adaf59bbfbf
--- /dev/null
+++ b/source/blender/python/api2_2x/Types.h
@@ -0,0 +1,41 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano, Alex Mole
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_TYPES_H
+#define EXPP_TYPES_H
+
+#include <Python.h>
+
+PyObject *Types_Init( void );
+void types_InitAll( void );
+
+#endif /* EXPP_TYPES_H */
diff --git a/source/blender/python/api2_2x/Window.c b/source/blender/python/api2_2x/Window.c
new file mode 100644
index 00000000000..323f209651a
--- /dev/null
+++ b/source/blender/python/api2_2x/Window.c
@@ -0,0 +1,1526 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano, Tom Musgrove, Michael Reimpell,
+ * Yann Vernier, Ken Hughes
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#include <Python.h>
+
+#include "BDR_editobject.h" /* enter / leave editmode */
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_object.h" /* for during_script() and during_scriptlink() */
+#include "BKE_scene.h" /* scene_find_camera() */
+#include "BPI_script.h"
+#include "BIF_mywindow.h"
+#include "BIF_imasel.h"
+#include "BSE_headerbuttons.h"
+#include "BSE_filesel.h"
+#include "BIF_editmesh.h" /* for undo_push_mesh() */
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_drawtext.h"
+#include "BIF_poseobject.h"
+#include "DNA_view3d_types.h"
+#include "DNA_space_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_text_types.h"
+#include "DNA_object_types.h"
+#include "mydevice.h"
+#include "blendef.h" /* OBACT */
+#include "windowTheme.h"
+#include "Mathutils.h"
+#include "constant.h"
+#include "gen_utils.h"
+#include "Armature.h"
+
+/* See Draw.c */
+extern int EXPP_disable_force_draw;
+extern void setcameratoview3d(void);
+
+/*****************************************************************************/
+/* Python API function prototypes for the Window module. */
+/*****************************************************************************/
+PyObject *M_Window_Redraw( PyObject * self, PyObject * args );
+static PyObject *M_Window_RedrawAll( PyObject * self, PyObject * args );
+static PyObject *M_Window_QRedrawAll( PyObject * self, PyObject * args );
+static PyObject *M_Window_DrawProgressBar( PyObject * self, PyObject * args );
+static PyObject *M_Window_GetCursorPos( PyObject * self );
+static PyObject *M_Window_SetCursorPos( PyObject * self, PyObject * args );
+static PyObject *M_Window_WaitCursor( PyObject * self, PyObject * args );
+static PyObject *M_Window_GetViewVector( PyObject * self );
+static PyObject *M_Window_GetActiveLayer( PyObject * self );
+static PyObject *M_Window_SetActiveLayer( PyObject * self, PyObject * args );
+static PyObject *M_Window_GetViewQuat( PyObject * self );
+static PyObject *M_Window_SetViewQuat( PyObject * self, PyObject * args );
+static PyObject *M_Window_GetViewOffset( PyObject * self );
+static PyObject *M_Window_SetViewOffset( PyObject * self, PyObject * args );
+static PyObject *M_Window_GetViewMatrix( PyObject * self );
+static PyObject *M_Window_GetPerspMatrix( PyObject * self );
+static PyObject *M_Window_FileSelector( PyObject * self, PyObject * args );
+static PyObject *M_Window_ImageSelector( PyObject * self, PyObject * args );
+static PyObject *M_Window_EditMode( PyObject * self, PyObject * args );
+static PyObject *M_Window_PoseMode( PyObject * self, PyObject * args );
+static PyObject *M_Window_ViewLayers( PyObject * self, PyObject * args );
+static PyObject *M_Window_CameraView( PyObject * self, PyObject * args );
+static PyObject *M_Window_QTest( PyObject * self );
+static PyObject *M_Window_QRead( PyObject * self );
+static PyObject *M_Window_QAdd( PyObject * self, PyObject * args );
+static PyObject *M_Window_QHandle( PyObject * self, PyObject * args );
+static PyObject *M_Window_GetMouseCoords( PyObject * self );
+static PyObject *M_Window_SetMouseCoords( PyObject * self, PyObject * args );
+static PyObject *M_Window_GetMouseButtons( PyObject * self );
+static PyObject *M_Window_GetKeyQualifiers( PyObject * self );
+static PyObject *M_Window_SetKeyQualifiers( PyObject * self, PyObject * args );
+static PyObject *M_Window_GetAreaSize( PyObject * self );
+static PyObject *M_Window_GetAreaID( PyObject * self );
+static PyObject *M_Window_GetScreenSize( PyObject * self );
+static PyObject *M_Window_GetScreens( PyObject * self );
+static PyObject *M_Window_SetScreen( PyObject * self, PyObject * value );
+static PyObject *M_Window_GetScreenInfo( PyObject * self, PyObject * args,
+ PyObject * kwords );
+PyObject *Window_Init( void );
+
+
+/*****************************************************************************/
+/* The following string definitions are used for documentation strings. */
+/* In Python these will be written to the console when doing a */
+/* Blender.Window.__doc__ */
+/*****************************************************************************/
+static char M_Window_doc[] = "The Blender Window module\n\n";
+
+static char M_Window_Redraw_doc[] =
+ "() - Force a redraw of a specific Window Type (see Window.Types)";
+
+static char M_Window_RedrawAll_doc[] = "() - Redraw all windows";
+
+static char M_Window_QRedrawAll_doc[] =
+ "() - Redraw all windows by queue event";
+
+static char M_Window_FileSelector_doc[] =
+ "(callback [, title, filename]) - Open a file selector window.\n\
+The selected file name is used as argument to a function callback f(name)\n\
+that you must provide. 'title' is optional and defaults to 'SELECT FILE'.\n\
+'filename' is optional and defaults to Blender.Get('filename').\n\n\
+Example:\n\n\
+import Blender\n\n\
+def my_function(filename):\n\
+ print 'The selected file was: ', filename\n\n\
+Blender.Window.FileSelector(my_function, 'SAVE FILE')\n";
+
+static char M_Window_ImageSelector_doc[] =
+ "(callback [, title, filename]) - Open an image selector window.\n\
+The selected file name is used as argument to a function callback f(name)\n\
+that you must provide. 'title' is optional and defaults to 'SELECT IMAGE'.\n\
+'filename' is optional and defaults to Blender.Get('filename').\n\n\
+Example:\n\n\
+import Blender\n\n\
+def my_function(filename):\n\
+ print 'The selected image file was: ', filename\n\n\
+Blender.Window.ImageSelector(my_function, 'LOAD IMAGE')\n";
+
+static char M_Window_DrawProgressBar_doc[] =
+ "(done, text) - Draw a progress bar.\n\
+'done' is a float value <= 1.0, 'text' contains info about what is\n\
+currently being done.";
+
+static char M_Window_GetCursorPos_doc[] =
+ "() - Get the current 3d cursor position as a list of three floats.";
+
+static char M_Window_SetCursorPos_doc[] =
+ "([f,f,f]) - Set the current 3d cursor position from a list of three floats.";
+
+static char M_Window_WaitCursor_doc[] =
+ "(bool) - Set cursor to wait mode (nonzero bool) or normal mode (0).";
+
+static char M_Window_GetViewVector_doc[] =
+ "() - Get the current 3d view vector as a list of three floats [x,y,z].";
+
+static char M_Window_GetActiveLayer_doc[] =
+ "() - Get the current 3d views active layer where new objects are created.";
+
+static char M_Window_SetActiveLayer_doc[] =
+ "(int) - Set the current 3d views active layer where new objects are created.";
+
+static char M_Window_GetViewMatrix_doc[] =
+ "() - Get the current 3d view matrix.";
+
+static char M_Window_GetPerspMatrix_doc[] =
+ "() - Get the current 3d Persp matrix.";
+
+static char M_Window_EditMode_doc[] =
+ "() - Get the current status -- 0: not in edit mode; 1: in edit mode.\n\
+(status) - if 1: enter edit mode; if 0: leave edit mode.\n\
+Returns the current status. This function is mostly useful to leave\n\
+edit mode before applying changes to a mesh (otherwise the changes will\n\
+be lost) and then returning to it upon leaving.";
+
+static char M_Window_PoseMode_doc[] =
+ "() - Get the current status -- 0: not in pose mode; 1: in edit mode";
+
+static char M_Window_ViewLayers_doc[] =
+ "(layers = [], winid = None) - Get/set active layers in all 3d View windows.\n\
+() - Make no changes, only return currently visible layers.\n\
+(layers = []) - a list of integers, each in the range [1, 20].\n\
+(layers = [], winid = int) - layers as above, winid is an optional.\n\
+arg that makes the function only set layers for that view.\n\
+This function returns the currently visible layers as a list of ints.";
+
+static char M_Window_GetViewQuat_doc[] =
+ "() - Get the current VIEW3D view quaternion values.";
+
+static char M_Window_SetViewQuat_doc[] =
+ "(quat) - Set the current VIEW3D view quaternion values.\n\
+(quat) - [f,f,f,f] or f,f,f,f: the new float values.";
+
+static char M_Window_GetViewOffset_doc[] =
+ "() - Get the current VIEW3D view offset values.";
+
+static char M_Window_SetViewOffset_doc[] =
+ "(ofs) - Set the current VIEW3D view offset values.\n\
+(ofs) - [f,f,f] or f,f,f: the new float values.";
+
+static char M_Window_CameraView_doc[] =
+ "(camtov3d = 0) - Set the current VIEW3D view to the active camera's view.\n\
+(camtov3d = 0) - bool: if nonzero it's the camera that gets positioned at the\n\
+current view, instead of the view being changed to that of the camera.\n\n\
+If no camera is the active object, the active camera for the current scene\n\
+is used.";
+
+static char M_Window_QTest_doc[] =
+ "() - Check if there are pending events in the event queue.";
+
+static char M_Window_QRead_doc[] =
+ "() - Get the next pending event from the event queue.\n\
+This function returns a list [event, val], where:\n\
+event - int: the key or mouse event (see Blender.Draw module);\n\
+val - int: if 1 it's a key or mouse button press, if 0 a release. For\n\
+ mouse movement events 'val' returns the new coordinates in x or y.";
+
+static char M_Window_QAdd_doc[] =
+ "(win, evt, val, after = 0) - Add an event to some window's event queue.\n\
+(win) - int: the win id, see Blender.Window.GetScreenInfo();\n\
+(evt) - int: the event number, see events in Blender.Draw;\n\
+(val) - bool: 1 for a key press, 0 for a release;\n\
+(after) - bool: if 1 the event is put after the current queue and added later.";
+
+static char M_Window_QHandle_doc[] =
+ "(win) - Process all events for the given window (area) now.\n\
+(win) - int: the window id, see Blender.Window.GetScreenInfo().\n\n\
+See Blender.Window.QAdd() for how to send events to a particular window.";
+
+static char M_Window_GetMouseCoords_doc[] =
+ "() - Get mouse pointer's current screen coordinates.";
+
+static char M_Window_SetMouseCoords_doc[] =
+ "(x, y) - Set mouse pointer's current screen coordinates.\n\
+(x,y) - ints ([x, y] also accepted): the new x, y coordinates.";
+
+static char M_Window_GetMouseButtons_doc[] =
+ "() - Get the current mouse button state (see Blender.Window.MButs dict).";
+
+static char M_Window_GetKeyQualifiers_doc[] =
+ "() - Get the current qualifier keys state.\n\
+An int is returned: or'ed combination of values in Blender.Window.Qual's dict.";
+
+static char M_Window_SetKeyQualifiers_doc[] =
+ "(qual) - Fake qualifier keys state.\n\
+(qual) - int: an or'ed combination of the values in Blender.Window.Qual dict.\n\
+Note: remember to reset to 0 after handling the related event (see QAdd()).";
+
+static char M_Window_GetAreaID_doc[] =
+ "() - Get the current window's (area) ID.";
+
+static char M_Window_GetAreaSize_doc[] =
+ "() - Get the current window's (area) size as [width, height].";
+
+static char M_Window_GetScreenSize_doc[] =
+ "() - Get the screen's size as [width, height].";
+
+static char M_Window_GetScreens_doc[] =
+ "() - Get a list with the names of all available screens.";
+
+static char M_Window_SetScreen_doc[] =
+ "(name) - Set current screen to the one with the given 'name'.";
+
+static char M_Window_GetScreenInfo_doc[] =
+ "(type = -1, rect = 'win', screen = None)\n\
+- Get info about the the areas in the current screen setup.\n\
+(type = -1) - int: the space type (Blender.Window.Types) to restrict the\n\
+ results to, all if -1;\n\
+(rect = 'win') - str: the rectangle of interest. This defines if the corner\n\
+ coordinates returned will refer to:\n\
+ - the whole area: 'total';\n\
+ - only the header: 'header';\n\
+ - only the window content (default): 'win'.\n\
+(screen = None) - str: the screen name, current if not given.\n\n\
+A list of dictionaries (one for each area) is returned.\n\
+Each dictionary has keys:\n\
+'vertices': [xmin, ymin, xmax, ymax] area corners;\n\
+'win': window type, see Blender.Window.Types dict;\n\
+'id': area's id.";
+
+/*****************************************************************************/
+/* Python method structure definition for Blender.Window module: */
+/*****************************************************************************/
+struct PyMethodDef M_Window_methods[] = {
+ {"Redraw", M_Window_Redraw, METH_VARARGS, M_Window_Redraw_doc},
+ {"RedrawAll", M_Window_RedrawAll, METH_VARARGS,
+ M_Window_RedrawAll_doc},
+ {"QRedrawAll", M_Window_QRedrawAll, METH_VARARGS,
+ M_Window_QRedrawAll_doc},
+ {"FileSelector", M_Window_FileSelector, METH_VARARGS,
+ M_Window_FileSelector_doc},
+ {"ImageSelector", ( PyCFunction ) M_Window_ImageSelector, METH_VARARGS,
+ M_Window_ImageSelector_doc},
+ {"DrawProgressBar", M_Window_DrawProgressBar, METH_VARARGS,
+ M_Window_DrawProgressBar_doc},
+ {"drawProgressBar", M_Window_DrawProgressBar, METH_VARARGS,
+ M_Window_DrawProgressBar_doc},
+ {"GetCursorPos", ( PyCFunction ) M_Window_GetCursorPos, METH_NOARGS,
+ M_Window_GetCursorPos_doc},
+ {"SetCursorPos", M_Window_SetCursorPos, METH_VARARGS,
+ M_Window_SetCursorPos_doc},
+ {"WaitCursor", M_Window_WaitCursor, METH_VARARGS,
+ M_Window_WaitCursor_doc},
+ {"GetViewVector", ( PyCFunction ) M_Window_GetViewVector, METH_NOARGS,
+ M_Window_GetViewVector_doc},
+ {"GetActiveLayer", ( PyCFunction ) M_Window_GetActiveLayer, METH_NOARGS,
+ M_Window_GetActiveLayer_doc},
+ {"SetActiveLayer", ( PyCFunction ) M_Window_SetActiveLayer, METH_VARARGS,
+ M_Window_SetActiveLayer_doc},
+ {"GetViewQuat", ( PyCFunction ) M_Window_GetViewQuat, METH_NOARGS,
+ M_Window_GetViewQuat_doc},
+ {"SetViewQuat", ( PyCFunction ) M_Window_SetViewQuat, METH_VARARGS,
+ M_Window_SetViewQuat_doc},
+ {"GetViewOffset", ( PyCFunction ) M_Window_GetViewOffset, METH_NOARGS,
+ M_Window_GetViewOffset_doc},
+ {"SetViewOffset", ( PyCFunction ) M_Window_SetViewOffset, METH_VARARGS,
+ M_Window_SetViewOffset_doc},
+ {"GetViewMatrix", ( PyCFunction ) M_Window_GetViewMatrix, METH_NOARGS,
+ M_Window_GetViewMatrix_doc},
+ {"GetPerspMatrix", ( PyCFunction ) M_Window_GetPerspMatrix, METH_NOARGS,
+ M_Window_GetPerspMatrix_doc},
+ {"EditMode", ( PyCFunction ) M_Window_EditMode, METH_VARARGS,
+ M_Window_EditMode_doc},
+ {"PoseMode", ( PyCFunction ) M_Window_PoseMode, METH_VARARGS,
+ M_Window_PoseMode_doc},
+ {"ViewLayers", ( PyCFunction ) M_Window_ViewLayers, METH_VARARGS,
+ M_Window_ViewLayers_doc},
+ /* typo, deprecate someday: */
+ {"ViewLayer", ( PyCFunction ) M_Window_ViewLayers, METH_VARARGS,
+ M_Window_ViewLayers_doc},
+ {"CameraView", ( PyCFunction ) M_Window_CameraView, METH_VARARGS,
+ M_Window_CameraView_doc},
+ {"QTest", ( PyCFunction ) M_Window_QTest, METH_NOARGS,
+ M_Window_QTest_doc},
+ {"QRead", ( PyCFunction ) M_Window_QRead, METH_NOARGS,
+ M_Window_QRead_doc},
+ {"QAdd", ( PyCFunction ) M_Window_QAdd, METH_VARARGS,
+ M_Window_QAdd_doc},
+ {"QHandle", ( PyCFunction ) M_Window_QHandle, METH_VARARGS,
+ M_Window_QHandle_doc},
+ {"GetMouseCoords", ( PyCFunction ) M_Window_GetMouseCoords,
+ METH_NOARGS,
+ M_Window_GetMouseCoords_doc},
+ {"SetMouseCoords", ( PyCFunction ) M_Window_SetMouseCoords,
+ METH_VARARGS,
+ M_Window_SetMouseCoords_doc},
+ {"GetMouseButtons", ( PyCFunction ) M_Window_GetMouseButtons,
+ METH_NOARGS,
+ M_Window_GetMouseButtons_doc},
+ {"GetKeyQualifiers", ( PyCFunction ) M_Window_GetKeyQualifiers,
+ METH_NOARGS,
+ M_Window_GetKeyQualifiers_doc},
+ {"SetKeyQualifiers", ( PyCFunction ) M_Window_SetKeyQualifiers,
+ METH_VARARGS,
+ M_Window_SetKeyQualifiers_doc},
+ {"GetAreaSize", ( PyCFunction ) M_Window_GetAreaSize, METH_NOARGS,
+ M_Window_GetAreaSize_doc},
+ {"GetAreaID", ( PyCFunction ) M_Window_GetAreaID, METH_NOARGS,
+ M_Window_GetAreaID_doc},
+ {"GetScreenSize", ( PyCFunction ) M_Window_GetScreenSize, METH_NOARGS,
+ M_Window_GetScreenSize_doc},
+ {"GetScreens", ( PyCFunction ) M_Window_GetScreens, METH_NOARGS,
+ M_Window_GetScreens_doc},
+ {"SetScreen", ( PyCFunction ) M_Window_SetScreen, METH_O,
+ M_Window_SetScreen_doc},
+ {"GetScreenInfo", ( PyCFunction ) M_Window_GetScreenInfo,
+ METH_VARARGS | METH_KEYWORDS, M_Window_GetScreenInfo_doc},
+ {NULL, NULL, 0, NULL}
+};
+
+/*****************************************************************************/
+/* Function: M_Window_Redraw */
+/* Python equivalent: Blender.Window.Redraw */
+/*****************************************************************************/
+/* not static so py_slider_update in Draw.[ch] can use it */
+PyObject *M_Window_Redraw( PyObject * self, PyObject * args )
+{
+ ScrArea *tempsa, *sa;
+ int wintype = SPACE_VIEW3D;
+ short redraw_all = 0;
+
+ if( !PyArg_ParseTuple( args, "|i", &wintype ) )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected int argument (or nothing)" ) );
+
+ if( wintype < 0 )
+ redraw_all = 1;
+
+ if( !during_script( ) && !G.background ) {
+ tempsa = curarea;
+ sa = G.curscreen->areabase.first;
+
+ while( sa ) {
+
+ if( sa->spacetype == wintype || redraw_all ) {
+ if (sa->spacetype == SPACE_SCRIPT && EXPP_disable_force_draw) {
+ scrarea_queue_redraw(sa);
+ }
+ else {
+ /* do not call fancy hacks here like pop_space_text(st); (ton) */
+ scrarea_do_windraw( sa );
+ if( sa->headwin ) scrarea_do_headdraw( sa );
+ }
+ }
+ sa = sa->next;
+ }
+
+ if( curarea != tempsa )
+ areawinset( tempsa->win );
+
+ if( curarea ) { /* is null if Blender is in bg mode */
+ if( curarea->headwin )
+ scrarea_do_headdraw( curarea );
+ screen_swapbuffers( );
+ }
+ }
+
+ Py_RETURN_NONE;
+}
+
+/*****************************************************************************/
+/* Function: M_Window_RedrawAll */
+/* Python equivalent: Blender.Window.RedrawAll */
+/*****************************************************************************/
+static PyObject *M_Window_RedrawAll( PyObject * self, PyObject * args )
+{
+ PyObject *arg = Py_BuildValue( "(i)", -1 );
+ PyObject *ret = M_Window_Redraw( self, arg );
+ Py_DECREF(arg);
+ return ret;
+}
+
+/*****************************************************************************/
+/* Function: M_Window_QRedrawAll */
+/* Python equivalent: Blender.Window.QRedrawAll */
+/*****************************************************************************/
+static PyObject *M_Window_QRedrawAll( PyObject * self, PyObject * args )
+{
+ EXPP_allqueue( REDRAWALL, 0 );
+ Py_RETURN_NONE;
+}
+
+/*****************************************************************************/
+/* Function: M_Window_FileSelector */
+/* Python equivalent: Blender.Window.FileSelector */
+/*****************************************************************************/
+
+/* This is the callback to "activate_fileselect" below. It receives the
+ * selected filename and (using it as argument) calls the Python callback
+ * provided by the script writer and stored in EXPP_FS_PyCallback. */
+
+static void getSelectedFile( char *name )
+{
+ PyObject *pycallback;
+ PyObject *result;
+ Script *script;
+
+ /* let's find the script that owns this callback */
+ script = G.main->script.first;
+ while (script) {
+ if (script->flags & SCRIPT_RUNNING) break;
+ script = script->id.next;
+ }
+
+ if (!script) {
+ if (curarea->spacetype == SPACE_SCRIPT) {
+ SpaceScript *sc = curarea->spacedata.first;
+ script = sc->script;
+ }
+ }
+
+ pycallback = script->py_browsercallback;
+
+ if (pycallback) {
+ result = PyObject_CallFunction( pycallback, "s", name );
+
+ if (!result) {
+ if (G.f & G_DEBUG)
+ fprintf(stderr, "BPy error: Callback call failed!\n");
+ }
+ else Py_DECREF(result);
+
+ if (script->py_browsercallback == pycallback)
+ script->py_browsercallback = NULL;
+ /* else another call to selector was made inside pycallback */
+
+ Py_DECREF(pycallback);
+ }
+
+ return;
+}
+
+static PyObject *M_Window_FileSelector( PyObject * self, PyObject * args )
+{
+ char *title = "SELECT FILE";
+ char *filename = G.sce;
+ SpaceScript *sc;
+ Script *script = NULL;
+ PyObject *pycallback = NULL;
+ int startspace = 0;
+
+ if (during_scriptlink())
+ return EXPP_ReturnPyObjError(PyExc_RuntimeError,
+ "script links can't call the file selector");
+
+ if (G.background)
+ return EXPP_ReturnPyObjError(PyExc_RuntimeError,
+ "the file selector is not available in background mode");
+
+ if((!PyArg_ParseTuple( args, "O|ss", &pycallback, &title, &filename))
+ || (!PyCallable_Check(pycallback)))
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "\nexpected a callback function (and optionally one or two strings) "
+ "as argument(s)" );
+
+ Py_INCREF(pycallback);
+
+/* trick: we move to a spacescript because then the fileselector will properly
+ * unset our SCRIPT_FILESEL flag when the user chooses a file or cancels the
+ * selection. This is necessary because when a user cancels, the
+ * getSelectedFile function above doesn't get called and so couldn't unset the
+ * flag. */
+ startspace = curarea->spacetype;
+ if( startspace != SPACE_SCRIPT )
+ newspace( curarea, SPACE_SCRIPT );
+
+ sc = curarea->spacedata.first;
+
+ /* let's find the script that called us */
+ script = G.main->script.first;
+ while (script) {
+ if (script->flags & SCRIPT_RUNNING) break;
+ script = script->id.next;
+ }
+
+ if( !script ) {
+ /* if not running, then we were already on a SpaceScript space, executing
+ * a registered callback -- aka: this script has a gui */
+ script = sc->script; /* this is the right script */
+ } else { /* still running, use the trick */
+ script->lastspace = startspace;
+ sc->script = script;
+ }
+
+ script->flags |= SCRIPT_FILESEL;
+
+ /* clear any previous callback (nested calls to selector) */
+ if (script->py_browsercallback) {
+ Py_DECREF((PyObject *)script->py_browsercallback);
+ }
+ script->py_browsercallback = pycallback;
+
+ activate_fileselect( FILE_BLENDER, title, filename, getSelectedFile );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *M_Window_ImageSelector( PyObject * self, PyObject * args )
+{
+ char *title = "SELECT IMAGE";
+ char *filename = G.sce;
+ SpaceScript *sc;
+ Script *script = NULL;
+ PyObject *pycallback = NULL;
+ int startspace = 0;
+
+ if (during_scriptlink())
+ return EXPP_ReturnPyObjError(PyExc_RuntimeError,
+ "script links can't call the image selector");
+
+ if (G.background)
+ return EXPP_ReturnPyObjError(PyExc_RuntimeError,
+ "the image selector is not available in background mode");
+
+ if( !PyArg_ParseTuple( args, "O|ss", &pycallback, &title, &filename )
+ || (!PyCallable_Check(pycallback)))
+ return EXPP_ReturnPyObjError ( PyExc_AttributeError,
+ "\nexpected a callback function (and optionally one or two strings) "
+ "as argument(s)" );
+
+ Py_INCREF(pycallback);
+
+/* trick: we move to a spacescript because then the fileselector will properly
+ * unset our SCRIPT_FILESEL flag when the user chooses a file or cancels the
+ * selection. This is necessary because when a user cancels, the
+ * getSelectedFile function above doesn't get called and so couldn't unset the
+ * flag. */
+ startspace = curarea->spacetype;
+ if( startspace != SPACE_SCRIPT )
+ newspace( curarea, SPACE_SCRIPT );
+
+ sc = curarea->spacedata.first;
+
+ /* let's find the script that called us */
+ script = G.main->script.first;
+ while (script) {
+ if (script->flags & SCRIPT_RUNNING) break;
+ script = script->id.next;
+ }
+
+ if( !script ) {
+ /* if not running, then we were already on a SpaceScript space, executing
+ * a registered callback -- aka: this script has a gui */
+ script = sc->script; /* this is the right script */
+ } else { /* still running, use the trick */
+ script->lastspace = startspace;
+ sc->script = script;
+ }
+
+ script->flags |= SCRIPT_FILESEL; /* same flag as filesel */
+ /* clear any previous callback (nested calls to selector) */
+ if (script->py_browsercallback) {
+ Py_DECREF((PyObject *)script->py_browsercallback);
+ }
+ script->py_browsercallback = pycallback;
+
+ activate_imageselect( FILE_BLENDER, title, filename, getSelectedFile );
+
+ Py_RETURN_NONE;
+}
+
+/*****************************************************************************/
+/* Function: M_Window_DrawProgressBar */
+/* Python equivalent: Blender.Window.DrawProgressBar */
+/*****************************************************************************/
+static PyObject *M_Window_DrawProgressBar( PyObject * self, PyObject * args )
+{
+ float done;
+ char *info = NULL;
+ int retval = 0;
+ ScrArea *sa = curarea;
+
+ if (G.background)
+ return EXPP_ReturnPyObjError(PyExc_RuntimeError,
+ "the progress bar is not available in background mode");
+
+ if( !PyArg_ParseTuple( args, "fs", &done, &info ) )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected a float and a string as arguments" ) );
+
+ retval = progress_bar( done, info );
+
+ areawinset(sa->win);
+
+ return Py_BuildValue( "i", retval );
+}
+
+/*****************************************************************************/
+/* Function: M_Window_GetCursorPos */
+/* Python equivalent: Blender.Window.GetCursorPos */
+/*****************************************************************************/
+static PyObject *M_Window_GetCursorPos( PyObject * self )
+{
+ float *cursor = NULL;
+ PyObject *pylist;
+
+ if( G.vd && G.vd->localview )
+ cursor = G.vd->cursor;
+ else
+ cursor = G.scene->cursor;
+
+ pylist = Py_BuildValue( "[fff]", cursor[0], cursor[1], cursor[2] );
+
+ if( !pylist )
+ return ( EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "GetCursorPos: couldn't create pylist" ) );
+
+ return pylist;
+}
+
+/*****************************************************************************/
+/* Function: M_Window_SetCursorPos */
+/* Python equivalent: Blender.Window.SetCursorPos */
+/*****************************************************************************/
+static PyObject *M_Window_SetCursorPos( PyObject * self, PyObject * args )
+{
+ int ok = 0;
+ float val[3];
+
+ if( PyObject_Length( args ) == 3 )
+ ok = PyArg_ParseTuple( args, "fff", &val[0], &val[1],
+ &val[2] );
+ else
+ ok = PyArg_ParseTuple( args, "(fff)", &val[0], &val[1],
+ &val[2] );
+
+ if( !ok )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected [f,f,f] or f,f,f as arguments" );
+
+ if( G.vd && G.vd->localview ) {
+ G.vd->cursor[0] = val[0];
+ G.vd->cursor[1] = val[1];
+ G.vd->cursor[2] = val[2];
+ } else {
+ G.scene->cursor[0] = val[0];
+ G.scene->cursor[1] = val[1];
+ G.scene->cursor[2] = val[2];
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *M_Window_WaitCursor( PyObject * self, PyObject * args )
+{
+ int bool;
+
+ if( !PyArg_ParseTuple( args, "i", &bool ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected bool (0 or 1) or nothing as argument" );
+
+ waitcursor( bool ); /* nonzero bool sets, zero unsets */
+
+ Py_RETURN_NONE;
+}
+
+/*****************************************************************************/
+/* Function: M_Window_GetViewVector */
+/* Python equivalent: Blender.Window.GetViewVector */
+/*****************************************************************************/
+static PyObject *M_Window_GetViewVector( PyObject * self )
+{
+ float *vec = NULL;
+
+ if( !G.vd )
+ Py_RETURN_NONE;
+
+ vec = G.vd->viewinv[2];
+
+ return Py_BuildValue( "[fff]", vec[0], vec[1], vec[2] );
+}
+
+/*****************************************************************************/
+/* Function: M_Window_GetActiveLayer */
+/* Python equivalent: Blender.Window.GetActiveLayer */
+/*****************************************************************************/
+static PyObject *M_Window_GetActiveLayer( PyObject * self )
+{
+ if (!G.vd) {
+ return PyInt_FromLong(0);
+ } else {
+ return PyInt_FromLong( G.vd->layact );
+ }
+}
+
+static PyObject *M_Window_SetActiveLayer( PyObject * self, PyObject * args )
+{
+ int layer, bit=1;
+ if( !PyArg_ParseTuple( args, "i", &layer ) )
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected an int" ) );
+
+ if (!G.vd)
+ Py_RETURN_FALSE;
+
+ bit= 0;
+ while(bit<32) {
+ if(layer & (1<<bit)) {
+ G.vd->layact= 1<<bit;
+ G.vd->lay |= G.vd->layact;
+
+ if (G.vd->scenelock) {
+ G.scene->lay |= G.vd->layact;
+ }
+ bit = -1; /* no error */
+ break;
+ }
+ bit++;
+ }
+
+ if (bit != -1)
+ return ( EXPP_ReturnPyObjError( PyExc_ValueError,
+ "The flag could not be used for the active layer" ) );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *M_Window_GetViewQuat( PyObject * self )
+{
+ float *vec = NULL;
+
+ if( !G.vd )
+ Py_RETURN_NONE;
+
+ vec = G.vd->viewquat;
+
+ return Py_BuildValue( "[ffff]", vec[0], vec[1], vec[2], vec[3] );
+}
+
+static PyObject *M_Window_SetViewQuat( PyObject * self, PyObject * args )
+{
+ int ok = 0;
+ float val[4];
+
+ if( !G.vd )
+ Py_RETURN_NONE;
+
+ if( PyObject_Length( args ) == 4 )
+ ok = PyArg_ParseTuple( args, "ffff", &val[0], &val[1], &val[2],
+ &val[3] );
+ else
+ ok = PyArg_ParseTuple( args, "(ffff)", &val[0], &val[1],
+ &val[2], &val[3] );
+
+ if( !ok )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected [f,f,f,f] or f,f,f,f as arguments" );
+
+ G.vd->viewquat[0] = val[0];
+ G.vd->viewquat[1] = val[1];
+ G.vd->viewquat[2] = val[2];
+ G.vd->viewquat[3] = val[3];
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *M_Window_GetViewOffset( PyObject * self )
+{
+ if( !G.vd )
+ Py_RETURN_NONE;
+ return Py_BuildValue( "[fff]", G.vd->ofs[0], G.vd->ofs[1], G.vd->ofs[2] );
+}
+
+static PyObject *M_Window_SetViewOffset( PyObject * self, PyObject * args )
+{
+ int ok = 0;
+ float val[3];
+
+ if( !G.vd )
+ Py_RETURN_NONE;
+
+ if( PyObject_Length( args ) == 3 )
+ ok = PyArg_ParseTuple( args, "fff", &val[0], &val[1],
+ &val[2] );
+ else
+ ok = PyArg_ParseTuple( args, "(fff)", &val[0], &val[1],
+ &val[2] );
+
+ if( !ok )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected [f,f,f] or f,f,f as arguments" );
+
+ G.vd->ofs[0] = val[0];
+ G.vd->ofs[1] = val[1];
+ G.vd->ofs[2] = val[2];
+
+ Py_RETURN_NONE;
+}
+
+
+/*****************************************************************************/
+/* Function: M_Window_GetViewMatrix */
+/* Python equivalent: Blender.Window.GetViewMatrix */
+/*****************************************************************************/
+static PyObject *M_Window_GetViewMatrix( PyObject * self )
+{
+ if( !G.vd )
+ Py_RETURN_NONE;
+
+ return newMatrixObject( ( float * ) G.vd->viewmat, 4, 4, Py_WRAP );
+}
+
+/*****************************************************************************/
+/* Function: M_Window_GetPerspMatrix */
+/* Python equivalent: Blender.Window.GetPerspMatrix */
+/*****************************************************************************/
+static PyObject *M_Window_GetPerspMatrix( PyObject * self )
+{
+ if( !G.vd )
+ Py_RETURN_NONE;
+
+ return newMatrixObject( ( float * ) G.vd->persmat, 4, 4, Py_WRAP );
+}
+
+
+/* update_armature_weakrefs()
+ * helper function used in M_Window_EditMode.
+ * rebuilds list of Armature weakrefs in __main__
+ */
+
+static int update_armature_weakrefs()
+{
+ /* stuff for armature weak refs */
+ char *list_name = ARM_WEAKREF_LIST_NAME;
+ PyObject *maindict = NULL, *armlist = NULL;
+ PyObject *pyarmature = NULL;
+ int x;
+
+ maindict= PyModule_GetDict(PyImport_AddModule( "__main__"));
+ armlist = PyDict_GetItemString(maindict, list_name);
+ if( !armlist){
+ printf("Oops - update_armature_weakrefs()\n");
+ return 0;
+ }
+
+ for (x = 0; x < PySequence_Size(armlist); x++){
+ pyarmature = PyWeakref_GetObject(PySequence_GetItem( armlist, x));
+ if (pyarmature != Py_None)
+ Armature_RebuildEditbones(pyarmature);
+ }
+ return 1;
+}
+
+
+static PyObject *M_Window_EditMode( PyObject * self, PyObject * args )
+{
+ short status = -1;
+ char *undo_str = "From script";
+ int undo_str_len = 11;
+ int do_undo = 1;
+
+ if( !PyArg_ParseTuple( args,
+ "|hs#i", &status, &undo_str, &undo_str_len, &do_undo ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected optional int (bool), string and int (bool) as arguments" );
+
+ if( status >= 0 ) {
+ if( status ) {
+ if( !G.obedit ){
+
+ //update armatures
+ if(! update_armature_weakrefs()){
+ return EXPP_ReturnPyObjError(
+ PyExc_RuntimeError,
+ "internal error - update_armature_weakrefs");
+ }
+
+ //enter editmode
+ enter_editmode(0);
+ }
+ } else if( G.obedit ) {
+ if( undo_str_len > 63 )
+ undo_str[63] = '\0'; /* 64 is max */
+ BIF_undo_push( undo_str ); /* This checks user undo settings */
+ exit_editmode( EM_FREEDATA );
+
+ //update armatures
+ if(! update_armature_weakrefs()){
+ return EXPP_ReturnPyObjError(
+ PyExc_RuntimeError,
+ "internal error - update_armature_weakrefs");
+ }
+
+ }
+ }
+
+ return Py_BuildValue( "h", G.obedit ? 1 : 0 );
+}
+
+static PyObject *M_Window_PoseMode( PyObject * self, PyObject * args )
+{
+ short status = -1;
+ short is_posemode = 0;
+ Base *base;
+
+ if( !PyArg_ParseTuple( args, "|h", &status ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected optional int (bool) as argument" );
+
+ if( status >= 0 ) {
+ if( status ) {
+ enter_posemode();
+ } else if( G.obedit ) {
+ exit_posemode();
+ }
+ }
+
+ base= BASACT;
+ if (base && base->object->flag & OB_POSEMODE) {
+ is_posemode = 1;
+ }
+
+ return Py_BuildValue( "h", is_posemode );
+}
+
+static PyObject *M_Window_ViewLayers( PyObject * self, PyObject * args )
+{
+ PyObject *item = NULL;
+ PyObject *list = NULL, *resl = NULL;
+ int val, i, bit = 0, layer = 0, len_list;
+ short winid = -1;
+
+ if( !G.scene ) {
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "can't get pointer to global scene" );
+ }
+
+ /* Pase Args, Nothing, One list, Or a list and an int */
+ if (PyTuple_GET_SIZE(args)!=0) {
+ if( !PyArg_ParseTuple ( args, "O!|h", &PyList_Type, &list, &winid) ) {
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "nothing or a list and optionaly a window ID argument" );
+ }
+ }
+
+ if( list ) {
+ len_list = PyList_Size(list);
+
+ if (len_list == 0)
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "list can't be empty, at list one layer must be set" );
+
+ for( i = 0; i < len_list; i++ ) {
+ item = PyList_GetItem( list, i );
+ if( !PyInt_Check( item ) )
+ return EXPP_ReturnPyObjError
+ ( PyExc_AttributeError,
+ "list must contain only integer numbers" );
+
+ val = ( int ) PyInt_AsLong( item );
+ if( val < 1 || val > 20 )
+ return EXPP_ReturnPyObjError
+ ( PyExc_AttributeError,
+ "layer values must be in the range [1, 20]" );
+
+ layer |= 1 << ( val - 1 );
+ }
+
+ if (winid==-1) {
+ /* set scene and viewport */
+ G.scene->lay = layer;
+ if (G.vd) {
+ G.vd->lay = layer;
+
+ while( bit < 20 ) {
+ val = 1 << bit;
+ if( layer & val ) {
+ G.vd->layact = val;
+ break;
+ }
+ bit++;
+ }
+ }
+ } else {
+ /* only set the windows layer */
+ ScrArea *sa;
+ SpaceLink *sl;
+ View3D *vd;
+
+ if (G.curscreen) { /* can never be too careful */
+ for (sa=G.curscreen->areabase.first; sa; sa= sa->next) {
+ if (winid == sa->win) {
+
+ for (sl= sa->spacedata.first; sl; sl= sl->next)
+ if(sl->spacetype==SPACE_VIEW3D)
+ break;
+
+ if (!sl)
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "The window matching the winid has no 3d viewport" );
+
+ vd= (View3D *) sl;
+ vd->lay = layer;
+
+ for(bit= 0; bit < 20; bit++) {
+ val = 1 << bit;
+ if( layer & val ) {
+ vd->layact = val;
+ break;
+ }
+ }
+
+ winid = -1; /* so we know its done */
+ break;
+ }
+ }
+ if (winid!=-1)
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "The winid argument did not match any window" );
+ }
+ }
+ }
+
+ resl = PyList_New( 0 );
+ if( !resl )
+ return ( EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create pylist!" ) );
+
+ layer = G.scene->lay;
+
+ bit = 0;
+ while( bit < 20 ) {
+ val = 1 << bit;
+ if( layer & val ) {
+ item = Py_BuildValue( "i", bit + 1 );
+ PyList_Append( resl, item );
+ Py_DECREF( item );
+ }
+ bit++;
+ }
+
+ return resl;
+}
+
+static PyObject *M_Window_CameraView( PyObject * self, PyObject * args )
+{
+ short camtov3d = 0;
+
+ if( !PyArg_ParseTuple( args, "|i", &camtov3d ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected an int (from Window.Views) as argument" );
+
+ if( !G.vd )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "this function can only be used after a 3d View has been initialized" );
+
+ if( !G.vd->camera ) {
+ if( BASACT && OBACT->type == OB_CAMERA )
+ G.vd->camera = OBACT;
+ else
+ G.vd->camera = scene_find_camera( G.scene );
+ handle_view3d_lock( );
+ }
+
+ G.vd->persp = 2;
+ G.vd->view = 0;
+
+ if( camtov3d )
+ setcameratoview3d( );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *M_Window_QTest( PyObject * self )
+{
+ return Py_BuildValue( "h", qtest( ) );
+}
+
+static PyObject *M_Window_QRead( PyObject * self )
+{
+ short val = 0;
+ unsigned short event;
+
+ if (G.background)
+ return EXPP_ReturnPyObjError(PyExc_RuntimeError,
+ "QRead is not available in background mode");
+
+ event = extern_qread( &val );
+
+ return Py_BuildValue( "ii", event, val );
+}
+
+static PyObject *M_Window_QAdd( PyObject * self, PyObject * args )
+{
+ short win;
+ short evt; /* unsigned, we check below */
+ short val;
+ short after = 0;
+
+ if (G.background)
+ return EXPP_ReturnPyObjError(PyExc_RuntimeError,
+ "QAdd is not available in background mode");
+
+ if( !PyArg_ParseTuple( args, "hhh|h", &win, &evt, &val, &after ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected three or four ints as arguments" );
+
+ if( evt < 0 ) /* evt is unsigned short */
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "event value must be a positive int, check events in Blender.Draw" );
+
+ if( after )
+ addafterqueue( win, evt, val );
+ else
+ addqueue( win, evt, val );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *M_Window_QHandle( PyObject * self, PyObject * args )
+{
+ short win;
+ ScrArea *sa;
+ ScrArea *oldsa = NULL;
+
+ if (G.background)
+ return EXPP_ReturnPyObjError(PyExc_RuntimeError,
+ "QHandle is not available in background mode");
+
+ if (!G.curscreen)
+ return EXPP_ReturnPyObjError(PyExc_RuntimeError,
+ "No screens available");
+
+ if( !PyArg_ParseTuple( args, "h", &win ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected an int as argument" );
+
+ for (sa= G.curscreen->areabase.first; sa; sa= sa->next)
+ if( sa->win == win )
+ break;
+
+ if( sa ) {
+ BWinEvent evt;
+ short do_redraw = 0, do_change = 0;
+
+ if( sa != curarea || sa->win != mywinget( ) ) {
+ oldsa = curarea;
+ areawinset( sa->win );
+ set_g_activearea( sa );
+ }
+ while( bwin_qread( sa->win, &evt ) ) {
+ if( evt.event == REDRAW ) {
+ do_redraw = 1;
+ } else if( evt.event == CHANGED ) {
+ sa->win_swap = 0;
+ do_change = 1;
+ do_redraw = 1;
+ } else {
+ scrarea_do_winhandle( sa, &evt );
+ }
+ }
+ }
+
+ if( oldsa ) {
+ areawinset( oldsa->win );
+ set_g_activearea( oldsa );
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *M_Window_GetMouseCoords( PyObject * self )
+{
+ short mval[2];
+
+ getmouse( mval );
+
+ return Py_BuildValue( "hh", mval[0], mval[1] );
+}
+
+static PyObject *M_Window_SetMouseCoords( PyObject * self, PyObject * args )
+{
+ int ok, x, y;
+
+ if( !G.curscreen )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "no current screen to retrieve info from!" );
+
+ x = G.curscreen->sizex / 2;
+ y = G.curscreen->sizey / 2;
+
+ if( PyObject_Length( args ) == 2 )
+ ok = PyArg_ParseTuple( args, "hh", &x, &y );
+ else
+ ok = PyArg_ParseTuple( args, "|(hh)", &x, &y );
+
+ if( !ok )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected [i, i] or i,i as arguments (or nothing)." );
+
+ warp_pointer( x, y );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *M_Window_GetMouseButtons( PyObject * self )
+{
+ short mbut = get_mbut( );
+
+ return Py_BuildValue( "h", mbut );
+}
+
+static PyObject *M_Window_GetKeyQualifiers( PyObject * self )
+{
+ short qual = get_qual( );
+
+ return Py_BuildValue( "h", qual );
+}
+
+static PyObject *M_Window_SetKeyQualifiers( PyObject * self, PyObject * args )
+{
+ short qual = 0;
+
+ if( !PyArg_ParseTuple( args, "|h", &qual ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected nothing or an int (or'ed flags) as argument" );
+
+ if( qual < 0 )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "value must be a positive int, check Blender.Window.Qual" );
+
+ G.qual = qual;
+
+ return Py_BuildValue( "h", qual );
+}
+
+static PyObject *M_Window_GetAreaSize( PyObject * self )
+{
+ ScrArea *sa = curarea;
+
+ if( !sa )
+ Py_RETURN_NONE;
+
+ return Py_BuildValue( "hh", sa->winx, sa->winy );
+}
+
+static PyObject *M_Window_GetAreaID( PyObject * self )
+{
+ ScrArea *sa = curarea;
+
+ if( !sa )
+ Py_RETURN_NONE;
+
+ return Py_BuildValue( "h", sa->win );
+}
+
+static PyObject *M_Window_GetScreenSize( PyObject * self )
+{
+ bScreen *scr = G.curscreen;
+
+ if( !scr )
+ Py_RETURN_NONE;
+
+ return Py_BuildValue( "hh", scr->sizex, scr->sizey );
+}
+
+
+static PyObject *M_Window_SetScreen( PyObject * self, PyObject * value )
+{
+ bScreen *scr = G.main->screen.first;
+ char *name = PyString_AsString(value);
+
+ if( !name )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string as argument" );
+
+ while( scr ) {
+ if( !strcmp( scr->id.name + 2, name ) ) {
+ setscreen( scr );
+ break;
+ }
+ scr = scr->id.next;
+ }
+
+ if( !scr )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "no such screen, check Window.GetScreens() for valid names" );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *M_Window_GetScreens( PyObject * self )
+{
+ bScreen *scr = G.main->screen.first;
+ PyObject *list = PyList_New( 0 );
+ PyObject *str = NULL;
+
+ if( !list )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create py list!" );
+
+ while( scr ) {
+ str = PyString_FromString( scr->id.name + 2 );
+
+ if( !str ) {
+ Py_DECREF( list );
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create py string!" );
+ }
+
+ PyList_Append( list, str ); /* incref's str */
+ Py_DECREF( str );
+
+ scr = scr->id.next;
+ }
+
+ return list;
+}
+
+static PyObject *M_Window_GetScreenInfo( PyObject * self, PyObject * args,
+ PyObject * kwords )
+{
+ ScrArea *sa = G.curscreen->areabase.first;
+ bScreen *scr = G.main->screen.first;
+ PyObject *item, *list;
+ rcti *rct;
+ int type = -1;
+ char *rect = "win";
+ char *screen = "";
+ static char *kwlist[] = { "type", "rect", "screen", NULL };
+ int rctype = 0;
+
+ if( !PyArg_ParseTupleAndKeywords( args, kwords, "|iss", kwlist, &type,
+ &rect, &screen ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected nothing or an int and two strings as arguments" );
+
+ if( !strcmp( rect, "win" ) )
+ rctype = 0;
+ else if( !strcmp( rect, "total" ) )
+ rctype = 1;
+ else if( !strcmp( rect, "header" ) )
+ rctype = 2;
+ else
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "requested invalid type for area rectangle coordinates." );
+
+ list = PyList_New( 0 );
+
+ if( screen && screen[0] != '\0' ) {
+ while( scr ) {
+ if( !strcmp( scr->id.name + 2, screen ) ) {
+ sa = scr->areabase.first;
+ break;
+ }
+ scr = scr->id.next;
+ }
+ }
+
+ if( !scr ) {
+ Py_DECREF( list );
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "no such screen, see existing ones with Window.GetScreens." );
+ }
+
+ while( sa ) {
+ if( type != -1 && sa->spacetype != type ) {
+ sa = sa->next;
+ continue;
+ }
+
+ switch ( rctype ) {
+ case 0:
+ rct = &sa->winrct;
+ break;
+ case 1:
+ rct = &sa->totrct;
+ break;
+ case 2:
+ default:
+ rct = &sa->headrct;
+ }
+
+ item = Py_BuildValue( "{s:[h,h,h,h],s:h,s:h}",
+ "vertices", rct->xmin, rct->ymin,
+ rct->xmax, rct->ymax, "type",
+ ( short ) sa->spacetype, "id",
+ ( short ) sa->win );
+ PyList_Append( list, item );
+ Py_DECREF( item );
+
+ sa = sa->next;
+ }
+
+ return list;
+}
+
+/*****************************************************************************/
+/* Function: Window_Init */
+/*****************************************************************************/
+PyObject *Window_Init( void )
+{
+ PyObject *submodule, *Types, *Qual, *MButs, *dict;
+
+ submodule =
+ Py_InitModule3( "Blender.Window", M_Window_methods,
+ M_Window_doc );
+
+ dict = PyModule_GetDict( submodule );
+ if( dict )
+ PyDict_SetItemString( dict, "Theme", Theme_Init( ) );
+
+ Types = PyConstant_New( );
+ Qual = PyConstant_New( );
+ MButs = PyConstant_New( );
+
+ if( Types ) {
+ BPy_constant *d = ( BPy_constant * ) Types;
+
+ PyConstant_Insert( d, "VIEW3D", PyInt_FromLong( SPACE_VIEW3D ) );
+ PyConstant_Insert( d, "IPO", PyInt_FromLong( SPACE_IPO ) );
+ PyConstant_Insert( d, "OOPS", PyInt_FromLong( SPACE_OOPS ) );
+ PyConstant_Insert( d, "BUTS", PyInt_FromLong( SPACE_BUTS ) );
+ PyConstant_Insert( d, "FILE", PyInt_FromLong( SPACE_FILE ) );
+ PyConstant_Insert( d, "IMAGE", PyInt_FromLong( SPACE_IMAGE ) );
+ PyConstant_Insert( d, "INFO", PyInt_FromLong( SPACE_INFO ) );
+ PyConstant_Insert( d, "SEQ", PyInt_FromLong( SPACE_SEQ ) );
+ PyConstant_Insert( d, "IMASEL", PyInt_FromLong( SPACE_IMASEL ) );
+ PyConstant_Insert( d, "SOUND", PyInt_FromLong( SPACE_SOUND ) );
+ PyConstant_Insert( d, "ACTION", PyInt_FromLong( SPACE_ACTION ) );
+ PyConstant_Insert( d, "TEXT", PyInt_FromLong( SPACE_TEXT ) );
+ PyConstant_Insert( d, "NLA", PyInt_FromLong( SPACE_NLA ) );
+ PyConstant_Insert( d, "SCRIPT", PyInt_FromLong( SPACE_SCRIPT ) );
+ PyConstant_Insert( d, "TIME", PyInt_FromLong( SPACE_TIME ) );
+ PyConstant_Insert( d, "NODE", PyInt_FromLong( SPACE_NODE ) );
+
+ PyModule_AddObject( submodule, "Types", Types );
+ }
+
+ if( Qual ) {
+ BPy_constant *d = ( BPy_constant * ) Qual;
+
+ PyConstant_Insert( d, "LALT", PyInt_FromLong( L_ALTKEY ) );
+ PyConstant_Insert( d, "RALT", PyInt_FromLong( R_ALTKEY ) );
+ PyConstant_Insert( d, "ALT", PyInt_FromLong( LR_ALTKEY ) );
+ PyConstant_Insert( d, "LCTRL", PyInt_FromLong( L_CTRLKEY ) );
+ PyConstant_Insert( d, "RCTRL", PyInt_FromLong( R_CTRLKEY ) );
+ PyConstant_Insert( d, "CTRL", PyInt_FromLong( LR_CTRLKEY ) );
+ PyConstant_Insert( d, "LSHIFT", PyInt_FromLong( L_SHIFTKEY ) );
+ PyConstant_Insert( d, "RSHIFT", PyInt_FromLong( R_SHIFTKEY ) );
+ PyConstant_Insert( d, "SHIFT", PyInt_FromLong( LR_SHIFTKEY ) );
+
+ PyModule_AddObject( submodule, "Qual", Qual );
+ }
+
+ if( MButs ) {
+ BPy_constant *d = ( BPy_constant * ) MButs;
+
+ PyConstant_Insert( d, "L", PyInt_FromLong( L_MOUSE ) );
+ PyConstant_Insert( d, "M", PyInt_FromLong( M_MOUSE ) );
+ PyConstant_Insert( d, "R", PyInt_FromLong( R_MOUSE ) );
+
+ PyModule_AddObject( submodule, "MButs", MButs );
+ }
+
+ return submodule;
+}
diff --git a/source/blender/python/api2_2x/Window.h b/source/blender/python/api2_2x/Window.h
new file mode 100644
index 00000000000..a39856ecd58
--- /dev/null
+++ b/source/blender/python/api2_2x/Window.h
@@ -0,0 +1,43 @@
+/*
+ * $Id:*
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+/* This file is useless now, CAN BE REMOVED. */
+
+#ifndef EXPP_WINDOW_H
+#define EXPP_WINDOW_H
+
+#include <Python.h>
+
+PyObject *Window_Init( void );
+PyObject *M_Window_Redraw( PyObject * self, PyObject * args );
+
+#endif /* EXPP_WINDOW_H */
diff --git a/source/blender/python/api2_2x/World.c b/source/blender/python/api2_2x/World.c
new file mode 100644
index 00000000000..7804a443639
--- /dev/null
+++ b/source/blender/python/api2_2x/World.c
@@ -0,0 +1,1034 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Jacques Guignot, Johnny Matthews
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+/**
+ * \file World.c
+ * \ingroup scripts
+ * \brief Blender.World Module and World Data PyObject implementation.
+ *
+ * Note: Parameters between "<" and ">" are optional. But if one of them is
+ * given, all preceding ones must be given, too. Of course, this only relates
+ * to the Python functions and methods described here and only inside Python
+ * code. [ This will go to another file later, probably the main exppython
+ * doc file]. XXX Better: put optional args with their default value:
+ * (self, name = "MyName")
+ */
+
+#include "World.h" /*This must come first*/
+
+#include "DNA_scene_types.h" /* for G.scene */
+#include "BKE_global.h"
+#include "BKE_world.h"
+#include "BKE_main.h"
+#include "BKE_library.h"
+#include "BLI_blenlib.h"
+#include "BSE_editipo.h"
+#include "BIF_space.h"
+#include "mydevice.h"
+#include "Ipo.h"
+#include "gen_utils.h"
+#include "gen_library.h"
+
+#define IPOKEY_ZENITH 0
+#define IPOKEY_HORIZON 1
+#define IPOKEY_MIST 2
+#define IPOKEY_STARS 3
+#define IPOKEY_OFFSET 4
+#define IPOKEY_SIZE 5
+/*****************************************************************************/
+/* Python BPy_World methods declarations: */
+/*****************************************************************************/
+static PyObject *World_getRange( BPy_World * self );
+static PyObject *World_setRange( BPy_World * self, PyObject * args );
+static PyObject *World_getIpo( BPy_World * self );
+static PyObject *World_oldsetIpo( BPy_World * self, PyObject * args );
+static int World_setIpo( BPy_World * self, PyObject * args );
+static PyObject *World_clearIpo( BPy_World * self );
+static PyObject *World_insertIpoKey( BPy_World * self, PyObject * args );
+static PyObject *World_getMode( BPy_World * self );
+static PyObject *World_oldsetMode( BPy_World * self, PyObject * args );
+static int World_setMode( BPy_World * self, PyObject * args );
+static PyObject *World_getSkytype( BPy_World * self );
+static PyObject *World_oldsetSkytype( BPy_World * self, PyObject * args );
+static int World_setSkytype( BPy_World * self, PyObject * args );
+static PyObject *World_getMistype( BPy_World * self );
+static PyObject *World_oldsetMistype( BPy_World * self, PyObject * args );
+static int World_setMistype( BPy_World * self, PyObject * args );
+static PyObject *World_getHor( BPy_World * self );
+static PyObject *World_oldsetHor( BPy_World * self, PyObject * args );
+static int World_setHor( BPy_World * self, PyObject * args );
+static PyObject *World_getZen( BPy_World * self );
+static PyObject *World_oldsetZen( BPy_World * self, PyObject * args );
+static int World_setZen( BPy_World * self, PyObject * args );
+static PyObject *World_getAmb( BPy_World * self );
+static PyObject *World_oldsetAmb( BPy_World * self, PyObject * args );
+static int World_setAmb( BPy_World * self, PyObject * args );
+static PyObject *World_getStar( BPy_World * self );
+static PyObject *World_oldsetStar( BPy_World * self, PyObject * args );
+static int World_setStar( BPy_World * self, PyObject * args );
+static PyObject *World_getMist( BPy_World * self );
+static PyObject *World_oldsetMist( BPy_World * self, PyObject * args );
+static int World_setMist( BPy_World * self, PyObject * args );
+static PyObject *World_getScriptLinks( BPy_World * self, PyObject * value );
+static PyObject *World_addScriptLink( BPy_World * self, PyObject * args );
+static PyObject *World_clearScriptLinks( BPy_World * self, PyObject * args );
+static PyObject *World_setCurrent( BPy_World * self );
+static PyObject *World_copy( BPy_World * self );
+
+
+/*****************************************************************************/
+/* Python API function prototypes for the World module. */
+/*****************************************************************************/
+static PyObject *M_World_New( PyObject * self, PyObject * args,
+ PyObject * keywords );
+static PyObject *M_World_Get( PyObject * self, PyObject * args );
+static PyObject *M_World_GetCurrent( PyObject * self );
+
+
+/*****************************************************************************/
+/* Python World_Type callback function prototypes: */
+/*****************************************************************************/
+//static int World_Print (BPy_World *self, FILE *fp, int flags);
+static int World_Compare( BPy_World * a, BPy_World * b );
+static PyObject *World_Repr( BPy_World * self );
+
+
+
+/*****************************************************************************/
+/* The following string definitions are used for documentation strings. */
+/* In Python these will be written to the console when doing a */
+/* Blender.World.__doc__ */
+/*****************************************************************************/
+static char M_World_doc[] = "The Blender World module\n\n\
+This module provides access to **World Data** objects in Blender\n\n";
+
+static char M_World_New_doc[] = "() - return a new World object";
+
+static char M_World_Get_doc[] =
+ "(name) - return the world with the name 'name', \
+returns None if not found.\n If 'name' is not specified, \
+it returns a list of all worlds in the\ncurrent scene.";
+static char M_World_GetCurrent_doc[] = "() - returns the current world, or \
+None if the Scene has no world";
+
+
+
+/*****************************************************************************/
+/* Python method structure definition for Blender.World module: */
+/*****************************************************************************/
+struct PyMethodDef M_World_methods[] = {
+ {"New", ( PyCFunction ) M_World_New, METH_VARARGS | METH_KEYWORDS,
+ M_World_New_doc},
+ {"Get", M_World_Get, METH_VARARGS, M_World_Get_doc},
+ {"GetActive", ( PyCFunction ) M_World_GetCurrent, METH_NOARGS,
+ M_World_GetCurrent_doc},
+ {"GetCurrent", ( PyCFunction ) M_World_GetCurrent, METH_NOARGS,
+ M_World_GetCurrent_doc},
+ {"get", M_World_Get, METH_VARARGS, M_World_Get_doc},
+ {NULL, NULL, 0, NULL}
+};
+
+
+
+/*****************************************************************************/
+/* Python BPy_World methods table: */
+/*****************************************************************************/
+static PyMethodDef BPy_World_methods[] = {
+ {"getRange", ( PyCFunction ) World_getRange, METH_NOARGS,
+ "() - Return World Range"},
+ {"setRange", ( PyCFunction ) World_setRange, METH_VARARGS,
+ "() - Change this World's range"},
+ {"getIpo", ( PyCFunction ) World_getIpo, METH_NOARGS,
+ "() - Return World Ipo"},
+ {"setIpo", ( PyCFunction ) World_oldsetIpo, METH_VARARGS,
+ "() - Change this World's ipo"},
+ {"clearIpo", ( PyCFunction ) World_clearIpo, METH_VARARGS,
+ "() - Unlink Ipo from this World"},
+ {"getName", ( PyCFunction ) GenericLib_getName, METH_NOARGS,
+ "() - Return World Data name"},
+ {"setName", ( PyCFunction ) GenericLib_setName_with_method, METH_VARARGS,
+ "() - Set World Data name"},
+ {"getMode", ( PyCFunction ) World_getMode, METH_NOARGS,
+ "() - Return World Data mode"},
+ {"setMode", ( PyCFunction ) World_oldsetMode, METH_VARARGS,
+ "(i) - Set World Data mode"},
+ {"getSkytype", ( PyCFunction ) World_getSkytype, METH_NOARGS,
+ "() - Return World Data skytype"},
+ {"setSkytype", ( PyCFunction ) World_oldsetSkytype, METH_VARARGS,
+ "() - Return World Data skytype"},
+ {"getMistype", ( PyCFunction ) World_getMistype, METH_NOARGS,
+ "() - Return World Data mistype"},
+ {"setMistype", ( PyCFunction ) World_oldsetMistype, METH_VARARGS,
+ "() - Return World Data mistype"},
+ {"getHor", ( PyCFunction ) World_getHor, METH_NOARGS,
+ "() - Return World Data hor"},
+ {"setHor", ( PyCFunction ) World_oldsetHor, METH_VARARGS,
+ "() - Return World Data hor"},
+ {"getZen", ( PyCFunction ) World_getZen, METH_NOARGS,
+ "() - Return World Data zen"},
+ {"setZen", ( PyCFunction ) World_oldsetZen, METH_VARARGS,
+ "() - Return World Data zen"},
+ {"getAmb", ( PyCFunction ) World_getAmb, METH_NOARGS,
+ "() - Return World Data amb"},
+ {"setAmb", ( PyCFunction ) World_oldsetAmb, METH_VARARGS,
+ "() - Return World Data amb"},
+ {"getStar", ( PyCFunction ) World_getStar, METH_NOARGS,
+ "() - Return World Data star"},
+ {"setStar", ( PyCFunction ) World_oldsetStar, METH_VARARGS,
+ "() - Return World Data star"},
+ {"getMist", ( PyCFunction ) World_getMist, METH_NOARGS,
+ "() - Return World Data mist"},
+ {"setMist", ( PyCFunction ) World_oldsetMist, METH_VARARGS,
+ "() - Return World Data mist"},
+ {"getScriptLinks", ( PyCFunction ) World_getScriptLinks, METH_O,
+ "(eventname) - Get a list of this world's scriptlinks (Text names) "
+ "of the given type\n"
+ "(eventname) - string: FrameChanged, Redraw or Render."},
+ {"addScriptLink", ( PyCFunction ) World_addScriptLink, METH_VARARGS,
+ "(text, evt) - Add a new world scriptlink.\n"
+ "(text) - string: an existing Blender Text name;\n"
+ "(evt) string: FrameChanged, Redraw or Render."},
+ {"clearScriptLinks", ( PyCFunction ) World_clearScriptLinks,
+ METH_VARARGS,
+ "() - Delete all scriptlinks from this world.\n"
+ "([s1<,s2,s3...>]) - Delete specified scriptlinks from this world."},
+ {"setCurrent", ( PyCFunction ) World_setCurrent, METH_NOARGS,
+ "() - Makes this world the active world for the current scene."},
+ {"makeActive", ( PyCFunction ) World_setCurrent, METH_NOARGS,
+ "please use setCurrent instead, this alias will be removed."},
+ {"insertIpoKey", ( PyCFunction ) World_insertIpoKey, METH_VARARGS,
+ "( World IPO type ) - Inserts a key into the IPO"},
+ {"__copy__", ( PyCFunction ) World_copy, METH_NOARGS,
+ "() - Makes a copy of this world."},
+ {"copy", ( PyCFunction ) World_copy, METH_NOARGS,
+ "() - Makes a copy of this world."},
+ {NULL, NULL, 0, NULL}
+};
+
+/*****************************************************************************/
+/* Python attributes get/set structure: */
+/*****************************************************************************/
+static PyGetSetDef BPy_World_getseters[] = {
+ GENERIC_LIB_GETSETATTR,
+ {"skytype", (getter)World_getSkytype, (setter)World_setSkytype,
+ "sky settings as a list", NULL},
+ {"mode", (getter)World_getMode, (setter)World_setMode,
+ "world mode", NULL},
+ {"mistype", (getter)World_getMistype, (setter)World_setMistype,
+ "world mist type", NULL},
+ {"hor", (getter)World_getHor, (setter)World_setHor,
+ "world horizon color", NULL},
+ {"amb", (getter)World_getAmb, (setter)World_setAmb,
+ "world ambient color", NULL},
+ {"mist", (getter)World_getMist, (setter)World_setMist,
+ "world mist settings", NULL},
+ {"ipo", (getter)World_getIpo, (setter)World_setIpo,
+ "world ipo", NULL},
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+/*****************************************************************************/
+/* Python World_Type structure definition: */
+/*****************************************************************************/
+PyTypeObject World_Type = {
+ PyObject_HEAD_INIT( NULL )
+ 0, /* ob_size */
+ "World", /* tp_name */
+ sizeof( BPy_World ), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ /* methods */
+ NULL, /* tp_dealloc */
+ 0, /* tp_print */
+ NULL, /* tp_getattr */
+ NULL, /* tp_setattr */
+ ( cmpfunc ) World_Compare, /* tp_compare */
+ ( reprfunc ) World_Repr, /* tp_repr */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ ( hashfunc ) GenericLib_hash, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_World_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ BPy_World_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+/**
+ * \defgroup World_Module Blender.World module functions
+ *
+ */
+
+/*@{*/
+
+/**
+ * \brief Python module function: Blender.World.New()
+ *
+ * This is the .New() function of the Blender.World submodule. It creates
+ * new World Data in Blender and returns its Python wrapper object. The
+ * name parameter is mandatory.
+ * \param <name> - string: The World Data name.
+ * \return A new World PyObject.
+ */
+
+static PyObject *M_World_New( PyObject * self, PyObject * args,
+ PyObject * kwords )
+{
+ char *name = NULL;
+ BPy_World *pyworld;
+ World *blworld;
+
+ if( !PyArg_ParseTuple( args, "s", &name ) )
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected int argument" ) );
+
+
+ blworld = add_world( name );
+
+ if( blworld ) {
+ /* return user count to zero because add_world() inc'd it */
+ blworld->id.us = 0;
+ /* create python wrapper obj */
+ pyworld =
+ ( BPy_World * ) PyObject_NEW( BPy_World, &World_Type );
+ } else
+ return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't create World Data in Blender" ) );
+
+ if( pyworld == NULL )
+ return ( EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create World Data object" ) );
+
+ pyworld->world = blworld;
+
+ return ( PyObject * ) pyworld;
+}
+
+/**
+ * \brief Python module function: Blender.World.Get()
+ *
+ * This is the .Get() function of the Blender.World submodule. It searches
+ * the list of current World Data objects and returns a Python wrapper for
+ * the one with the name provided by the user. If called with no arguments,
+ * it returns a list of all current World Data object names in Blender.
+ * \param <name> - string: The name of an existing Blender World Data object.
+ * \return () - A list with the names of all current World Data objects;\n
+ * \return (name) - A Python wrapper for the World Data called 'name'
+ * in Blender.
+ */
+
+static PyObject *M_World_Get( PyObject * self, PyObject * args )
+{
+
+ char *name = NULL;
+ World *world_iter;
+ PyObject *worldlist;
+ char error_msg[64];
+
+ if( !PyArg_ParseTuple( args, "|s", &name ) )
+ return ( EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument (or nothing)" ) );
+
+ if( name ) { /* (name) - Search world by name */
+ world_iter = ( World * ) GetIdFromList( &( G.main->world ), name );
+
+ if( world_iter == NULL ) { /* Requested world doesn't exist */
+ PyOS_snprintf( error_msg, sizeof( error_msg ),
+ "World \"%s\" not found", name );
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_NameError, error_msg ) );
+ }
+
+ return ( PyObject * ) World_CreatePyObject(world_iter);
+ }
+
+ else { /* return a list of all worlds in the scene */
+ world_iter = G.main->world.first;
+ worldlist = PyList_New( 0 );
+ if( worldlist == NULL )
+ return ( EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create PyList" ) );
+
+ while( world_iter ) {
+ BPy_World *found_world =
+ ( BPy_World * ) PyObject_NEW( BPy_World,
+ &World_Type );
+ found_world->world = world_iter;
+ PyList_Append( worldlist, ( PyObject * ) found_world );
+ Py_DECREF(found_world);
+
+ world_iter = world_iter->id.next;
+ }
+ return ( worldlist );
+ }
+
+}
+
+static PyObject *M_World_GetCurrent( PyObject * self )
+{
+ BPy_World *w = NULL;
+#if 0 /* add back in when bpy becomes "official" */
+ static char warning = 1;
+ if( warning ) {
+ printf("Blender.World.GetCurrent() deprecated!\n\tuse bpy.scenes.world instead\n");
+ --warning;
+ }
+#endif
+
+ if( !G.scene->world )
+ Py_RETURN_NONE;
+
+ w = ( BPy_World * ) PyObject_NEW( BPy_World, &World_Type );
+ w->world = G.scene->world;
+ return ( PyObject * ) w;
+}
+
+/*@}*/
+
+/**
+ * \brief Initializes the Blender.World submodule
+ *
+ * This function is used by Blender_Init() in Blender.c to register the
+ * Blender.World submodule in the main Blender module.
+ * \return PyObject*: The initialized submodule.
+ */
+
+PyObject *World_Init( void )
+{
+ PyObject *submodule;
+
+ if( PyType_Ready( &World_Type ) < 0 )
+ return NULL;
+
+ submodule = Py_InitModule3( "Blender.World",
+ M_World_methods, M_World_doc );
+
+ PyModule_AddIntConstant( submodule, "ZENITH", IPOKEY_ZENITH );
+ PyModule_AddIntConstant( submodule, "HORIZON", IPOKEY_HORIZON );
+ PyModule_AddIntConstant( submodule, "MIST", IPOKEY_MIST );
+ PyModule_AddIntConstant( submodule, "STARS", IPOKEY_STARS );
+ PyModule_AddIntConstant( submodule, "OFFSET", IPOKEY_OFFSET );
+ PyModule_AddIntConstant( submodule, "SIZE", IPOKEY_SIZE );
+
+ return ( submodule );
+}
+
+/*****************************************************************************/
+/* Python BPy_World methods: */
+/*****************************************************************************/
+static PyObject *World_getRange( BPy_World * self )
+{
+ return PyFloat_FromDouble( self->world->range );
+}
+
+static PyObject *World_setRange( BPy_World * self, PyObject * args )
+{
+ float range = 0.f;
+ if( !PyArg_ParseTuple( args, "f", &range ) )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_TypeError, "expected a float argument" ) );
+ self->world->range = range;
+ Py_RETURN_NONE;
+}
+
+
+static PyObject *World_getIpo( BPy_World * self )
+{
+ struct Ipo *ipo = self->world->ipo;
+
+ if( !ipo )
+ Py_RETURN_NONE;
+
+ return Ipo_CreatePyObject( ipo );
+}
+
+static int World_setIpo( BPy_World * self, PyObject * value )
+{
+ return GenericLib_assignData(value, (void **) &self->world->ipo, 0, 1, ID_IP, ID_WO);
+}
+
+static PyObject *World_oldsetIpo( BPy_World * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)World_setIpo );
+}
+
+static PyObject *World_clearIpo( BPy_World * self )
+{
+ World *world = self->world;
+ Ipo *ipo = ( Ipo * ) world->ipo;
+
+ if( ipo ) {
+ ID *id = &ipo->id;
+ if( id->us > 0 )
+ id->us--;
+ world->ipo = NULL;
+
+ return EXPP_incr_ret_True();
+ }
+
+ return EXPP_incr_ret_False(); /* no ipo found */
+}
+
+/**
+ * \brief World PyMethod getSkytype
+ *
+ * \return int : The World Data skytype.
+ */
+
+static PyObject *World_getSkytype( BPy_World * self )
+{
+ return PyInt_FromLong( ( long ) self->world->skytype );
+}
+
+
+/**
+ * \brief World PyMethod setSkytype
+ *
+ * \return int : The World Data skytype.
+ */
+
+static int World_setSkytype( BPy_World * self, PyObject * value )
+{
+ if( !PyInt_Check(value) )
+ return ( EXPP_ReturnIntError( PyExc_TypeError,
+ "expected int argument" ) );
+ self->world->skytype = (short)PyInt_AsLong(value);
+ return 0;
+}
+
+static PyObject *World_oldsetSkytype( BPy_World * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)World_setSkytype );
+}
+
+
+/**
+ * \brief World PyMethod getMode
+ *
+ * \return int : The World Data mode.
+ */
+
+static PyObject *World_getMode( BPy_World * self )
+{
+ return PyInt_FromLong( ( long ) self->world->mode );
+}
+
+
+/**
+ * \brief World PyMethod setMode
+ *
+ * \return int : The World Data mode.
+ */
+
+static int World_setMode( BPy_World * self, PyObject * value )
+{
+ if( !PyInt_Check(value) )
+ return ( EXPP_ReturnIntError( PyExc_TypeError,
+ "expected int argument" ) );
+ self->world->mode = (short)PyInt_AsLong(value);
+ return 0;
+}
+
+static PyObject *World_oldsetMode( BPy_World * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)World_setMode );
+}
+
+
+
+/**
+ * \brief World PyMethod getMistype
+ *
+ * \return int : The World Data mistype.
+ */
+
+static PyObject *World_getMistype( BPy_World * self )
+{
+ return PyInt_FromLong( ( long ) self->world->mistype );
+}
+
+
+/**
+ * \brief World PyMethod setMistype
+ *
+ * \return int : The World Data mistype.
+ */
+
+static int World_setMistype( BPy_World * self, PyObject * value )
+{
+ if( !PyInt_Check(value) )
+ return ( EXPP_ReturnIntError( PyExc_TypeError,
+ "expected int argument" ) );
+ self->world->mistype = (short)PyInt_AsLong(value);
+ return 0;
+}
+
+static PyObject *World_oldsetMistype( BPy_World * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)World_setMistype );
+}
+
+
+
+static PyObject *World_getHor( BPy_World * self )
+{
+ PyObject *attr = PyList_New( 3 );
+ if( !attr )
+ return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't create list" ) );
+ PyList_SET_ITEM( attr, 0, PyFloat_FromDouble( self->world->horr ) );
+ PyList_SET_ITEM( attr, 1, PyFloat_FromDouble( self->world->horg ) );
+ PyList_SET_ITEM( attr, 2, PyFloat_FromDouble( self->world->horb ) );
+ return attr;
+}
+
+
+static int World_setHor( BPy_World * self, PyObject * value )
+{
+ if( !PyList_Check( value ) )
+ return ( EXPP_ReturnIntError( PyExc_TypeError,
+ "expected list argument" ) );
+ if( PyList_Size( value ) != 3 )
+ return ( EXPP_ReturnIntError
+ ( PyExc_TypeError, "list size must be 3" ) );
+ self->world->horr = (float)PyFloat_AsDouble( PyList_GetItem( value, 0 ) );
+ self->world->horg = (float)PyFloat_AsDouble( PyList_GetItem( value, 1 ) );
+ self->world->horb = (float)PyFloat_AsDouble( PyList_GetItem( value, 2 ) );
+ return 0;
+}
+
+static PyObject *World_oldsetHor( BPy_World * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)World_setHor );
+}
+
+static PyObject *World_getZen( BPy_World * self )
+{
+ PyObject *attr = PyList_New( 3 );
+ if( !attr )
+ return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't create list" ) );
+ PyList_SET_ITEM( attr, 0, PyFloat_FromDouble( self->world->zenr ) );
+ PyList_SET_ITEM( attr, 1, PyFloat_FromDouble( self->world->zeng ) );
+ PyList_SET_ITEM( attr, 2, PyFloat_FromDouble( self->world->zenb ) );
+ return attr;
+}
+
+
+static int World_setZen( BPy_World * self, PyObject * value )
+{
+ if( !PyList_Check( value ) )
+ return ( EXPP_ReturnIntError( PyExc_TypeError,
+ "expected list argument" ) );
+ if( PyList_Size( value ) != 3 )
+ return ( EXPP_ReturnIntError
+ ( PyExc_TypeError, "list size must be 3" ) );
+ self->world->zenr = (float)PyFloat_AsDouble( PyList_GetItem( value, 0 ) );
+ self->world->zeng = (float)PyFloat_AsDouble( PyList_GetItem( value, 1 ) );
+ self->world->zenb = (float)PyFloat_AsDouble( PyList_GetItem( value, 2 ) );
+ return 0;
+}
+
+static PyObject *World_oldsetZen( BPy_World * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)World_setZen );
+}
+
+
+static PyObject *World_getAmb( BPy_World * self )
+{
+ PyObject *attr = PyList_New( 3 );
+ if( !attr )
+ return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't create list" ) );
+ PyList_SET_ITEM( attr, 0, PyFloat_FromDouble( self->world->ambr ) );
+ PyList_SET_ITEM( attr, 1, PyFloat_FromDouble( self->world->ambg ) );
+ PyList_SET_ITEM( attr, 2, PyFloat_FromDouble( self->world->ambb ) );
+ return attr;
+}
+
+
+static int World_setAmb( BPy_World * self, PyObject * value )
+{
+ if( !PyList_Check( value ) )
+ return ( EXPP_ReturnIntError( PyExc_TypeError,
+ "expected list argument" ) );
+ if( PyList_Size( value ) != 3 )
+ return ( EXPP_ReturnIntError
+ ( PyExc_TypeError, "wrong list size" ) );
+ self->world->ambr = (float)PyFloat_AsDouble( PyList_GetItem( value, 0 ) );
+ self->world->ambg = (float)PyFloat_AsDouble( PyList_GetItem( value, 1 ) );
+ self->world->ambb = (float)PyFloat_AsDouble( PyList_GetItem( value, 2 ) );
+ return 0;
+}
+
+static PyObject *World_oldsetAmb( BPy_World * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)World_setAmb );
+}
+
+static PyObject *World_getStar( BPy_World * self )
+{
+ PyObject *attr = PyList_New( 7 );
+ if( !attr )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_RuntimeError, "couldn't create list" ) );
+ PyList_SET_ITEM( attr, 0, PyFloat_FromDouble( self->world->starr ) );
+ PyList_SET_ITEM( attr, 1, PyFloat_FromDouble( self->world->starg ) );
+ PyList_SET_ITEM( attr, 2, PyFloat_FromDouble( self->world->starb ) );
+ PyList_SET_ITEM( attr, 3, PyFloat_FromDouble( self->world->starsize ) );
+ PyList_SET_ITEM( attr, 4, PyFloat_FromDouble( self->world->starmindist ) );
+ PyList_SET_ITEM( attr, 5, PyFloat_FromDouble( self->world->stardist ) );
+ PyList_SET_ITEM( attr, 6, PyFloat_FromDouble( self->world->starcolnoise ) );
+ return attr;
+}
+
+
+static int World_setStar( BPy_World * self, PyObject * value )
+{
+ if( !PyList_Check( value ) )
+ return ( EXPP_ReturnIntError
+ ( PyExc_TypeError, "expected list argument" ) );
+ if( PyList_Size( value ) != 7 )
+ return ( EXPP_ReturnIntError
+ ( PyExc_TypeError, "wrong list size" ) );
+ self->world->starr = (float)PyFloat_AsDouble( PyList_GetItem( value, 0 ) );
+ self->world->starg = (float)PyFloat_AsDouble( PyList_GetItem( value, 1 ) );
+ self->world->starb = (float)PyFloat_AsDouble( PyList_GetItem( value, 2 ) );
+ self->world->starsize =
+ (float)PyFloat_AsDouble( PyList_GetItem( value, 3 ) );
+ self->world->starmindist =
+ (float)PyFloat_AsDouble( PyList_GetItem( value, 4 ) );
+ self->world->stardist =
+ (float)PyFloat_AsDouble( PyList_GetItem( value, 5 ) );
+ self->world->starcolnoise =
+ (float)PyFloat_AsDouble( PyList_GetItem( value, 6 ) );
+ return 0;
+}
+
+static PyObject *World_oldsetStar( BPy_World * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)World_setStar );
+}
+
+
+static PyObject *World_getMist( BPy_World * self )
+{
+ PyObject *attr = PyList_New( 4 );
+ if( !attr )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_RuntimeError, "couldn't create list" ) );
+ PyList_SET_ITEM( attr, 0, PyFloat_FromDouble( self->world->misi ) );
+ PyList_SET_ITEM( attr, 1, PyFloat_FromDouble( self->world->miststa ) );
+ PyList_SET_ITEM( attr, 2, PyFloat_FromDouble( self->world->mistdist ) );
+ PyList_SET_ITEM( attr, 3, PyFloat_FromDouble( self->world->misthi ) );
+ return attr;
+}
+
+static int World_setMist( BPy_World * self, PyObject * value )
+{
+ if( !PyList_Check( value ) )
+ return ( EXPP_ReturnIntError
+ ( PyExc_TypeError, "expected list argument" ) );
+ if( PyList_Size( value ) != 4 )
+ return ( EXPP_ReturnIntError
+ ( PyExc_TypeError, "wrong list size" ) );
+ self->world->misi = (float)PyFloat_AsDouble( PyList_GetItem( value, 0 ) );
+ self->world->miststa =
+ (float)PyFloat_AsDouble( PyList_GetItem( value, 1 ) );
+ self->world->mistdist =
+ (float)PyFloat_AsDouble( PyList_GetItem( value, 2 ) );
+ self->world->misthi =
+ (float)PyFloat_AsDouble( PyList_GetItem( value, 3 ) );
+ return 0;
+}
+
+static PyObject *World_oldsetMist( BPy_World * self, PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)World_setMist );
+}
+
+
+/* world.addScriptLink */
+static PyObject *World_addScriptLink( BPy_World * self, PyObject * args )
+{
+ World *world = self->world;
+ ScriptLink *slink = NULL;
+
+ slink = &( world )->scriptlink;
+
+ return EXPP_addScriptLink( slink, args, 0 );
+}
+
+/* world.clearScriptLinks */
+static PyObject *World_clearScriptLinks( BPy_World * self, PyObject * args )
+{
+ World *world = self->world;
+ ScriptLink *slink = NULL;
+
+ slink = &( world )->scriptlink;
+
+ return EXPP_clearScriptLinks( slink, args );
+}
+
+/* world.getScriptLinks */
+static PyObject *World_getScriptLinks( BPy_World * self, PyObject * value )
+{
+ World *world = self->world;
+ ScriptLink *slink = NULL;
+ PyObject *ret = NULL;
+
+ slink = &( world )->scriptlink;
+
+ ret = EXPP_getScriptLinks( slink, value, 0 );
+
+ if( ret )
+ return ret;
+ else
+ return NULL;
+}
+
+
+/* world.setCurrent */
+static PyObject *World_setCurrent( BPy_World * self )
+{
+ World *world = self->world;
+#if 0 /* add back in when bpy becomes "official" */
+ static char warning = 1;
+ if( warning ) {
+ printf("world.setCurrent() deprecated!\n\tuse bpy.scenes.world=world instead\n");
+ --warning;
+ }
+#endif
+
+ /* If there is a world then it now has one less user */
+ if( G.scene->world )
+ G.scene->world->id.us--;
+ world->id.us++;
+ G.scene->world = world;
+ Py_RETURN_NONE;
+}
+
+/* world.__copy__ */
+static PyObject *World_copy( BPy_World * self )
+{
+ World *world = copy_world(self->world );
+ world->id.us = 0;
+ return World_CreatePyObject(world);
+}
+
+/**
+ * \brief The World PyType compare function
+ *
+ * This function compares two given World PyObjects, returning 0 for equality
+ * and -1 otherwise. In Python it becomes 1 if they are equal and 0 case not.
+ * The comparison is done with their pointers to Blender World Data objects,
+ * so any two wrappers pointing to the same Blender World Data will be
+ * considered the same World PyObject. Currently, only the "==" and "!="
+ * comparisons are meaninful -- the "<", "<=", ">" or ">=" are not.
+ */
+
+static int World_Compare( BPy_World * a, BPy_World * b )
+{
+ return ( a->world == b->world ) ? 0 : -1;
+}
+
+/**
+ * \brief The World PyType print callback
+ *
+ * This function is called when the user tries to print a PyObject of type
+ * World. It builds a string with the name of the wrapped Blender World.
+ */
+
+/*
+static int World_Print(BPy_World *self, FILE *fp, int flags)
+{
+ fprintf(fp, "[World \"%s\"]", self->world->id.name+2);
+ return 0;
+}
+*/
+
+/**
+ * \brief The World PyType repr callback
+ *
+ * This function is called when the statement "repr(myworld)" is executed in
+ * Python. Repr gives a string representation of a PyObject.
+ */
+
+static PyObject *World_Repr( BPy_World * self )
+{
+ return PyString_FromFormat( "[World \"%s\"]",
+ self->world->id.name + 2 );
+}
+
+/*@}*/
+/*
+static int World_compare (BPy_World *a, BPy_World *b)
+{
+ World *pa = a->world, *pb = b->world;
+ return (pa == pb) ? 0:-1;
+}
+*/
+PyObject *World_CreatePyObject( struct World * world )
+{
+ BPy_World *blen_object;
+
+ blen_object = ( BPy_World * ) PyObject_NEW( BPy_World, &World_Type );
+
+ if( blen_object == NULL ) {
+ return ( NULL );
+ }
+ blen_object->world = world;
+ return ( ( PyObject * ) blen_object );
+}
+
+World *World_FromPyObject( PyObject * py_obj )
+{
+ BPy_World *blen_obj;
+
+ blen_obj = ( BPy_World * ) py_obj;
+ return ( blen_obj->world );
+
+}
+
+/*
+ * World_insertIpoKey()
+ * inserts World IPO key for ZENITH,HORIZON,MIST,STARS,OFFSET,SIZE
+ */
+
+static PyObject *World_insertIpoKey( BPy_World * self, PyObject * args )
+{
+ int key = 0, map;
+
+ if( !PyArg_ParseTuple( args, "i", &( key ) ) )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected int argument" ) );
+
+ map = texchannel_to_adrcode(self->world->texact);
+
+ if(key == IPOKEY_ZENITH) {
+ insertkey((ID *)self->world, ID_WO, NULL, NULL, WO_ZEN_R, 0);
+ insertkey((ID *)self->world, ID_WO, NULL, NULL, WO_ZEN_G, 0);
+ insertkey((ID *)self->world, ID_WO, NULL, NULL, WO_ZEN_B, 0);
+ }
+ if(key == IPOKEY_HORIZON) {
+ insertkey((ID *)self->world, ID_WO, NULL, NULL, WO_HOR_R, 0);
+ insertkey((ID *)self->world, ID_WO, NULL, NULL, WO_HOR_G, 0);
+ insertkey((ID *)self->world, ID_WO, NULL, NULL, WO_HOR_B, 0);
+ }
+ if(key == IPOKEY_MIST) {
+ insertkey((ID *)self->world, ID_WO, NULL, NULL, WO_MISI, 0);
+ insertkey((ID *)self->world, ID_WO, NULL, NULL, WO_MISTDI, 0);
+ insertkey((ID *)self->world, ID_WO, NULL, NULL, WO_MISTSTA, 0);
+ insertkey((ID *)self->world, ID_WO, NULL, NULL, WO_MISTHI, 0);
+ }
+ if(key == IPOKEY_STARS) {
+ insertkey((ID *)self->world, ID_WO, NULL, NULL, WO_STAR_R, 0);
+ insertkey((ID *)self->world, ID_WO, NULL, NULL, WO_STAR_G, 0);
+ insertkey((ID *)self->world, ID_WO, NULL, NULL, WO_STAR_B, 0);
+ insertkey((ID *)self->world, ID_WO, NULL, NULL, WO_STARDIST, 0);
+ insertkey((ID *)self->world, ID_WO, NULL, NULL, WO_STARSIZE, 0);
+ }
+ if(key == IPOKEY_OFFSET) {
+ insertkey((ID *)self->world, ID_WO, NULL, NULL, map+MAP_OFS_X, 0);
+ insertkey((ID *)self->world, ID_WO, NULL, NULL, map+MAP_OFS_Y, 0);
+ insertkey((ID *)self->world, ID_WO, NULL, NULL, map+MAP_OFS_Z, 0);
+ }
+ if(key == IPOKEY_SIZE) {
+ insertkey((ID *)self->world, ID_WO, NULL, NULL, map+MAP_SIZE_X, 0);
+ insertkey((ID *)self->world, ID_WO, NULL, NULL, map+MAP_SIZE_Y, 0);
+ insertkey((ID *)self->world, ID_WO, NULL, NULL, map+MAP_SIZE_Z, 0);
+ }
+
+ allspace(REMAKEIPO, 0);
+ EXPP_allqueue(REDRAWIPO, 0);
+ EXPP_allqueue(REDRAWVIEW3D, 0);
+ EXPP_allqueue(REDRAWACTION, 0);
+ EXPP_allqueue(REDRAWNLA, 0);
+
+ Py_RETURN_NONE;
+}
diff --git a/source/blender/python/api2_2x/World.h b/source/blender/python/api2_2x/World.h
new file mode 100644
index 00000000000..ff0ec8709d7
--- /dev/null
+++ b/source/blender/python/api2_2x/World.h
@@ -0,0 +1,58 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Jacques Guignot
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_WORLD_H
+#define EXPP_WORLD_H
+
+#include <Python.h>
+#include "DNA_world_types.h"
+
+#define BPy_World_Check(v) ((v)->ob_type==&World_Type)
+
+/* Python BPy_World structure definition */
+typedef struct {
+ PyObject_HEAD /* required py macro */
+ World * world; /* Libdata must be second */
+} BPy_World;
+
+extern PyTypeObject World_Type;
+
+/*****************************************************************************/
+/* Python World_Type helper functions needed by Blender (the Init function) */
+/* and Object modules. */
+/*****************************************************************************/
+
+PyObject *World_Init( void );
+PyObject *World_CreatePyObject( World * world );
+World *World_FromPyObject( PyObject * pyobj );
+
+#endif /* EXPP_WORLD_H */
diff --git a/source/blender/python/api2_2x/bpy.c b/source/blender/python/api2_2x/bpy.c
new file mode 100644
index 00000000000..cee862c0e23
--- /dev/null
+++ b/source/blender/python/api2_2x/bpy.c
@@ -0,0 +1,86 @@
+/*
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Michel Selten, Willian P. Germano, Joseph Gilbert,
+ * Campbell Barton
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+/* for open, close in Blender_Load */
+
+#include "BLI_blenlib.h"
+#include "BKE_global.h"
+#include "BKE_utildefines.h"
+#include "BKE_scene.h"
+#include "BKE_main.h"
+
+#include "DNA_scene_types.h"
+
+#include "Types.h"
+#include "Library.h"
+
+#include "bpy.h"
+#include "bpy_data.h"
+#include "bpy_config.h"
+
+/*****************************************************************************/
+/* Global variables */
+/*****************************************************************************/
+PyObject *g_bpydict;
+
+/*****************************************************************************/
+/* Function: initBlender */
+/*****************************************************************************/
+
+void m_bpy_init(void)
+{
+ PyObject *module;
+ PyObject *dict;
+
+ /* G.scene should only aver be NULL if blender is executed in
+ background mode, not loading a blend file and executing a python script eg.
+ blender -P somescript.py -b
+ The if below solves the segfaults that happen when python runs and
+ G.scene is NULL */
+ if(G.background && G.main->scene.first==NULL) {
+ Scene *sce= add_scene("1");
+ /*set_scene(sce);*/ /* causes a crash */
+ G.scene= sce;
+ }
+
+ module = Py_InitModule3("bpy", NULL, "The main bpy module");
+
+ types_InitAll(); /* set all our pytypes to &PyType_Type */
+
+ dict = PyModule_GetDict(module);
+ g_bpydict = dict;
+
+ PyModule_AddObject( module, "config", Config_CreatePyObject() );
+ PyDict_SetItemString( dict, "data", Data_Init());
+ PyDict_SetItemString( dict, "libraries", Library_Init( ) );
+
+}
diff --git a/source/blender/python/api2_2x/bpy.h b/source/blender/python/api2_2x/bpy.h
new file mode 100644
index 00000000000..668196d8271
--- /dev/null
+++ b/source/blender/python/api2_2x/bpy.h
@@ -0,0 +1,41 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Michel Selten, Willian P. Germano
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_BPYMOD_H
+#define EXPP_BPYMOD_H
+
+#include <Python.h>
+
+extern PyObject *g_bpydict;
+void m_bpy_init( void );
+
+#endif /* EXPP_BPYMOD_H */
diff --git a/source/blender/python/api2_2x/bpy_config.c b/source/blender/python/api2_2x/bpy_config.c
new file mode 100644
index 00000000000..a061f31d8a0
--- /dev/null
+++ b/source/blender/python/api2_2x/bpy_config.c
@@ -0,0 +1,414 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Campbell Barton
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+/* python types */
+#include "DNA_userdef_types.h"
+#include "../api2_2x/gen_utils.h"
+#include "bpy_config.h"
+
+enum conf_consts {
+ /*string*/
+ EXPP_CONF_ATTR_PATH_YF_EXPORT = 0,
+ EXPP_CONF_ATTR_PATH_FONT,
+ EXPP_CONF_ATTR_PATH_RENDER,
+ EXPP_CONF_ATTR_PATH_TEXTURE,
+ EXPP_CONF_ATTR_PATH_PYTHON,
+ EXPP_CONF_ATTR_PATH_TEX_PLUGIN,
+ EXPP_CONF_ATTR_PATH_SOUND,
+ EXPP_CONF_ATTR_PATH_SEQ_PLUGIN,
+ EXPP_CONF_ATTR_PATH_TEMP,
+
+ /*int*/
+ EXPP_CONF_ATTR_UNDOSTEPS,
+ EXPP_CONF_ATTR_TEX_TIMEOUT,
+ EXPP_CONF_ATTR_TEX_COLLECT_RATE,
+ EXPP_CONF_ATTR_MEM_CACHE_LIMIT,
+ EXPP_CONF_ATTR_FONT_SIZE
+};
+
+PyObject *Config_CreatePyObject( )
+{
+ BPy_Config *conf = PyObject_NEW( BPy_Config, &Config_Type);
+ return (PyObject *)conf;
+}
+
+/*
+ * repr function
+ * callback functions building meaninful string to representations
+ */
+static PyObject *Config_repr( BPy_Config * self )
+{
+ return PyString_FromFormat( "[Blender Configuration Data]");
+}
+
+
+/*-----------------------Config module Init())-----------------------------*/
+/* see Main.c */
+/*
+static struct PyMethodDef BPy_Config_methods[] = {
+ {"new", (PyCFunction)MainSeq_new, METH_VARARGS,
+ "(name) - Create a new object in this scene from the obdata given and return a new object"},
+ {"load", (PyCFunction)MainSeq_load, METH_VARARGS,
+ "(filename) - loads the given filename for image, font and sound types"},
+ {"unlink", (PyCFunction)MainSeq_unlink, METH_VARARGS,
+ "unlinks the object from the scene"},
+ {NULL, NULL, 0, NULL}
+};*/
+
+/*
+ * get integer attributes
+ */
+static PyObject *getStrAttr( BPy_Config *self, void *type )
+{
+ char *param = NULL;
+
+ switch( (int)type ) {
+ case EXPP_CONF_ATTR_PATH_YF_EXPORT:
+ param = U.yfexportdir;
+ break;
+ case EXPP_CONF_ATTR_PATH_FONT:
+ param = U.fontdir;
+ break;
+ case EXPP_CONF_ATTR_PATH_RENDER:
+ param = U.renderdir;
+ break;
+ case EXPP_CONF_ATTR_PATH_TEXTURE:
+ param = U.textudir;
+ break;
+ case EXPP_CONF_ATTR_PATH_PYTHON:
+ param = U.pythondir;
+ break;
+ case EXPP_CONF_ATTR_PATH_TEX_PLUGIN:
+ param = U.plugtexdir;
+ break;
+ case EXPP_CONF_ATTR_PATH_SOUND:
+ param = U.sounddir;
+ break;
+ case EXPP_CONF_ATTR_PATH_SEQ_PLUGIN:
+ param = U.plugseqdir;
+ break;
+ case EXPP_CONF_ATTR_PATH_TEMP:
+ param = U.tempdir;
+ break;
+
+ default:
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "undefined type in getStrAttr" );
+ }
+
+ return PyString_FromString( param );
+}
+
+/*
+ * set integer attributes which require clamping
+ */
+
+static int setStrAttr( BPy_Config *self, PyObject *value, void *type )
+{
+ char *param;
+ int len=160;
+ char *str = PyString_AsString(value);
+
+ if (!str)
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "error, must assign a python string for setStrAttr");
+
+ switch( (int)type ) {
+ case EXPP_CONF_ATTR_PATH_YF_EXPORT:
+ param = U.yfexportdir;
+ break;
+ case EXPP_CONF_ATTR_PATH_FONT:
+ param = U.fontdir;
+ break;
+ case EXPP_CONF_ATTR_PATH_RENDER:
+ param = U.renderdir;
+ break;
+ case EXPP_CONF_ATTR_PATH_TEXTURE:
+ param = U.textudir;
+ break;
+ case EXPP_CONF_ATTR_PATH_PYTHON:
+ param = U.pythondir;
+ break;
+ case EXPP_CONF_ATTR_PATH_TEX_PLUGIN:
+ param = U.plugtexdir;
+ break;
+ case EXPP_CONF_ATTR_PATH_SOUND:
+ param = U.sounddir;
+ break;
+ case EXPP_CONF_ATTR_PATH_SEQ_PLUGIN:
+ param = U.plugseqdir;
+ break;
+ case EXPP_CONF_ATTR_PATH_TEMP:
+ param = U.tempdir;
+ break;
+
+ default:
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "undefined type in setStrAttr");
+ }
+
+ strncpy(param, str, len);
+ return 0;
+}
+
+
+/*
+ * get integer attributes
+ */
+
+static PyObject *getIntAttr( BPy_Config *self, void *type )
+{
+ int param;
+
+ switch( (int)type ) {
+ case EXPP_CONF_ATTR_UNDOSTEPS:
+ param = (int)U.undosteps;
+ break;
+ case EXPP_CONF_ATTR_TEX_TIMEOUT:
+ param = U.textimeout;
+ break;
+ case EXPP_CONF_ATTR_TEX_COLLECT_RATE:
+ param = U.texcollectrate;
+ break;
+ case EXPP_CONF_ATTR_MEM_CACHE_LIMIT:
+ param = U.memcachelimit;
+ break;
+ case EXPP_CONF_ATTR_FONT_SIZE:
+ param = U.fontsize;
+ break;
+
+ default:
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "undefined type in getIntAttr" );
+ }
+
+ return PyInt_FromLong( param );
+}
+
+/*
+ * set integer attributes which require clamping
+ */
+
+static int setIntAttrClamp( BPy_Config *self, PyObject *value, void *type )
+{
+ void *param;
+ int min, max, size;
+
+ switch( (int)type ) {
+ case EXPP_CONF_ATTR_UNDOSTEPS:
+ min = 0;
+ max = 64;
+ size = 'h';
+ param = (void *)&U.undosteps;
+ break;
+ case EXPP_CONF_ATTR_TEX_TIMEOUT:
+ min = 1;
+ max = 3600;
+ size = 'i';
+ param = (void *)&U.textimeout;
+ break;
+ case EXPP_CONF_ATTR_TEX_COLLECT_RATE:
+ min = 1;
+ max = 3600;
+ size = 'i';
+ param = (void *)&U.texcollectrate;
+ break;
+ case EXPP_CONF_ATTR_MEM_CACHE_LIMIT:
+ min = 1;
+ max = 1024;
+ size = 'i';
+ param = (void *)&U.memcachelimit;
+ break;
+ case EXPP_CONF_ATTR_FONT_SIZE:
+ min = 8;
+ max = 16;
+ size = 'i';
+ param = (void *)&U.fontsize;
+ break;
+
+ default:
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "undefined type in setIntAttrClamp");
+ }
+ return EXPP_setIValueClamped( value, param, min, max, size );
+}
+
+static PyGetSetDef Config_getseters[] = {
+
+ /* ints & shorts */
+ {"undoSteps",
+ (getter)getIntAttr, (setter)setIntAttrClamp,
+ "undo steps",
+ (void *)EXPP_CONF_ATTR_UNDOSTEPS},
+ {"textureTimeout",
+ (getter)getIntAttr, (setter)setIntAttrClamp,
+ "time for textures to stay in openGL memory",
+ (void *)EXPP_CONF_ATTR_TEX_TIMEOUT},
+ {"textureCollectRate",
+ (getter)getIntAttr, (setter)setIntAttrClamp,
+ "intervel for textures to be tagged as used",
+ (void *)EXPP_CONF_ATTR_TEX_COLLECT_RATE},
+ {"sequenceMemCacheLimit",
+ (getter)getIntAttr, (setter)setIntAttrClamp,
+ "maximum memory for the sequencer to use as cache",
+ (void *)EXPP_CONF_ATTR_MEM_CACHE_LIMIT},
+ {"fontSize",
+ (getter)getIntAttr, (setter)setIntAttrClamp,
+ "user interface font size",
+ (void *)EXPP_CONF_ATTR_FONT_SIZE},
+
+ /* Paths */
+ {"yfExportDir",
+ (getter)getStrAttr, (setter)setStrAttr,
+ "yafray export path",
+ (void *)EXPP_CONF_ATTR_PATH_YF_EXPORT},
+ {"fontDir",
+ (getter)getStrAttr, (setter)setStrAttr,
+ "default font path",
+ (void *)EXPP_CONF_ATTR_PATH_FONT},
+ {"renderDir",
+ (getter)getStrAttr, (setter)setStrAttr,
+ "default render path",
+ (void *)EXPP_CONF_ATTR_PATH_RENDER},
+ {"textureDir",
+ (getter)getStrAttr, (setter)setStrAttr,
+ "default texture path",
+ (void *)EXPP_CONF_ATTR_PATH_TEXTURE},
+ {"userScriptsDir",
+ (getter)getStrAttr, (setter)setStrAttr,
+ "user scripts path",
+ (void *)EXPP_CONF_ATTR_PATH_PYTHON},
+ {"texturePluginsDir",
+ (getter)getStrAttr, (setter)setStrAttr,
+ "default texture plugins path",
+ (void *)EXPP_CONF_ATTR_PATH_TEX_PLUGIN},
+ {"soundDir",
+ (getter)getStrAttr, (setter)setStrAttr,
+ "default sound path",
+ (void *)EXPP_CONF_ATTR_PATH_SOUND},
+ {"sequencePluginsDir",
+ (getter)getStrAttr, (setter)setStrAttr,
+ "sequencer plugins path",
+ (void *)EXPP_CONF_ATTR_PATH_SEQ_PLUGIN},
+ {"tempDir",
+ (getter)getStrAttr, (setter)setStrAttr,
+ "temporary file path",
+ (void *)EXPP_CONF_ATTR_PATH_TEMP},
+
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+
+/*
+ * Python Config_Type structure definition
+ */
+PyTypeObject Config_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender Config", /* char *tp_name; */
+ sizeof( BPy_Config ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ NULL, /* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* cmpfunc tp_compare; */
+ (reprfunc)Config_repr, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ NULL, /*BPy_Config_methods*/ /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ Config_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
diff --git a/source/blender/python/api2_2x/bpy_config.h b/source/blender/python/api2_2x/bpy_config.h
new file mode 100644
index 00000000000..979953acd76
--- /dev/null
+++ b/source/blender/python/api2_2x/bpy_config.h
@@ -0,0 +1,52 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Campbell Barton
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_BPY_CONFIG_H
+#define EXPP_BPY_CONFIG_H
+
+#include <Python.h>
+
+/* The Main PyType Object defined in Main.c */
+extern PyTypeObject Config_Type;
+
+#define BPy_Config_Check(v) \
+ ((v)->ob_type == &Config_Type)
+
+/* Main sequence, iterate on the libdatas listbase*/
+typedef struct {
+ PyObject_VAR_HEAD /* required python macro */
+} BPy_Config;
+
+PyObject *Config_CreatePyObject();
+
+
+#endif /* EXPP_BPY_CONFIG_H */
diff --git a/source/blender/python/api2_2x/bpy_data.c b/source/blender/python/api2_2x/bpy_data.c
new file mode 100644
index 00000000000..edb894bd982
--- /dev/null
+++ b/source/blender/python/api2_2x/bpy_data.c
@@ -0,0 +1,817 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Campbell Barton
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#include "bpy_data.h"
+
+#include "MEM_guardedalloc.h" /* for MEM_callocN */
+#include "DNA_space_types.h" /* SPACE_VIEW3D, SPACE_SEQ */
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h" /* LibBlockSeq_new */
+#include "DNA_texture_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_group_types.h"
+#include "DNA_world_types.h"
+#include "DNA_vfont_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_sound_types.h"
+#include "DNA_text_types.h"
+#include "DNA_action_types.h"
+#include "DNA_meta_types.h"
+
+/* Use the add_* from BKE_* */
+#include "BKE_global.h"
+#include "BKE_utildefines.h" /* clamp */
+#include "BKE_armature.h"
+#include "BKE_ipo.h"
+#include "BKE_image.h"
+#include "BKE_main.h"
+#include "BKE_library.h"
+#include "BKE_lattice.h"
+#include "BKE_object.h"
+#include "BKE_scene.h"
+#include "BKE_sca.h" /*free_text_controllers*/
+#include "BKE_font.h"
+#include "BKE_mball.h"
+#include "BKE_mesh.h"
+#include "BKE_curve.h"
+#include "BKE_material.h"
+#include "BKE_group.h"
+#include "BKE_text.h"
+#include "BKE_texture.h"
+#include "BKE_world.h"
+
+#include "BLI_blenlib.h" /* BLI_countlist */
+#include "BIF_drawscene.h" /* for set_scene */
+#include "BIF_screen.h" /* curarea */
+#include "BIF_drawimage.h" /* what image */
+#include "BIF_drawtext.h" /* unlink_text */
+#include "BIF_editsound.h" /* sound_new_sound */
+#include "BIF_editaction.h" /* add_empty_action */
+
+/* python types */
+#include "../BPY_extern.h" /* clearing scriptlinks */
+
+#include "gen_utils.h"
+#include "gen_library.h" /* generic ID functions */
+
+#include "Object.h"
+#include "Camera.h"
+#include "Armature.h"
+#include "Lamp.h"
+#include "Curve.h"
+#include "NMesh.h"
+#include "Mesh.h"
+#include "Lattice.h"
+#include "Metaball.h"
+#include "Text.h"
+#include "Text3d.h"
+#include "Font.h"
+#include "Group.h"
+#include "World.h"
+#include "Texture.h"
+#include "Ipo.h"
+#include "Text.h"
+#include "Sound.h"
+#include "NLA.h"
+#include "Scene.h"
+#include "Library.h"
+
+#include "bpy_config.h" /* config pydata */
+
+/* used only for texts.active */
+#include "BIF_screen.h"
+#include "DNA_space_types.h"
+#include "DNA_screen_types.h"
+
+extern VFont *get_builtin_font(void);
+
+static PyObject *LibBlockSeq_CreatePyObject( Link *iter, int type )
+{
+ BPy_LibBlockSeq *seq = PyObject_NEW( BPy_LibBlockSeq, &LibBlockSeq_Type);
+ seq->iter = iter;
+ seq->type = type;
+ return (PyObject *)seq;
+}
+
+
+static int LibBlockSeq_len( BPy_LibBlockSeq * self )
+{
+ ListBase *lb = wich_libbase(G.main, self->type);
+ return BLI_countlist( lb );
+}
+
+static PyObject * LibBlockSeq_subscript(BPy_LibBlockSeq * self, PyObject *key)
+{
+ char *name;
+ char *lib= NULL;
+ char use_lib = 0;
+ ID *id;
+
+ id = (ID *)wich_libbase(G.main, self->type)->first;
+
+ if ( PyString_Check(key) ) {
+ name = PyString_AsString ( key );
+ } else if (PyTuple_Check(key) && (PyTuple_Size(key) == 2) ) {
+ PyObject *pydata;
+ use_lib = 1;
+
+ /* Get the first arg */
+ pydata = PyTuple_GET_ITEM(key, 0);
+ if (!PyString_Check(pydata)) {
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "the data name must be a string" );
+ }
+
+ name = PyString_AsString ( pydata );
+
+ /* Get the second arg */
+ pydata = PyTuple_GET_ITEM(key, 1);
+ if (pydata == Py_None) {
+ lib = NULL; /* data must be local */
+ } else if (PyString_Check(pydata)) {
+ lib = PyString_AsString ( pydata );
+ if (!strcmp( "", lib)) {
+ lib = NULL; /* and empty string also means data must be local */
+ }
+ } else {
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "the lib name must be a string or None" );
+ }
+ } else {
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected the a name string or a tuple (lib, name)" );
+ }
+
+ for (; id; id = id->next) {
+ if(!strcmp( name, id->name+2 )) {
+ if (
+ (!use_lib) || /* any data, local or external lib data */
+ (use_lib && !lib && !id->lib) || /* only local */
+ (lib && use_lib && id->lib && (!strcmp( id->lib->name, lib))) /* only external lib */
+ )
+ {
+ return GetPyObjectFromID(id);
+ }
+ }
+ }
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_KeyError, "Requested data does not exist") );
+}
+
+static PyMappingMethods LibBlockSeq_as_mapping = {
+ ( inquiry ) LibBlockSeq_len, /* mp_length */
+ ( binaryfunc ) LibBlockSeq_subscript, /* mp_subscript */
+ ( objobjargproc ) 0, /* mp_ass_subscript */
+};
+
+
+/************************************************************************
+ *
+ * Python LibBlockSeq_Type iterator (iterates over GroupObjects)
+ *
+ ************************************************************************/
+
+/*
+ * Initialize the interator index
+ */
+
+static PyObject *LibBlockSeq_getIter( BPy_LibBlockSeq * self )
+{
+ /* we need to get the first base, but for selected context we may need to advance
+ to the first selected or first conext base */
+
+ ListBase *lb;
+ Link *link;
+ lb = wich_libbase(G.main, self->type);
+
+ link = lb->first;
+
+ /* create a new iterator if were alredy using this one */
+ if (self->iter==NULL) {
+ self->iter = link;
+ return EXPP_incr_ret ( (PyObject *) self );
+ } else {
+ return LibBlockSeq_CreatePyObject(link, self->type);
+ }
+}
+
+/*
+ * Return next LibBlockSeq iter.
+ */
+
+static PyObject *LibBlockSeq_nextIter( BPy_LibBlockSeq * self )
+{
+ PyObject *object;
+ Link *link;
+ if( !(self->iter) ) {
+ self->iter= NULL;
+ return EXPP_ReturnPyObjError( PyExc_StopIteration,
+ "iterator at end" );
+ }
+
+ object = GetPyObjectFromID((ID *)self->iter);
+
+ link= self->iter->next;
+ self->iter= link;
+ return object;
+}
+
+PyObject *LibBlockSeq_getActive(BPy_LibBlockSeq *self)
+{
+ switch (self->type) {
+ case ID_SCE:
+ if ( !G.scene ) {
+ Py_RETURN_NONE;
+ } else {
+ return Scene_CreatePyObject( ( Scene * ) G.scene );
+ }
+
+ break;
+ case ID_IM:
+ if (!G.sima || !G.sima->image) {
+ Py_RETURN_NONE;
+ } else {
+ what_image( G.sima ); /* make sure image data exists */
+ return Image_CreatePyObject( G.sima->image );
+ }
+ break;
+ case ID_TXT: {
+ SpaceText *st= curarea->spacedata.first;
+
+ if (st->spacetype!=SPACE_TEXT || st->text==NULL) {
+ Py_RETURN_NONE;
+ } else {
+ return Text_CreatePyObject( st->text );
+ }
+ }
+ }
+
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "Only Scene and Image types have the active attribute" );
+}
+
+static int LibBlockSeq_setActive(BPy_LibBlockSeq *self, PyObject *value)
+{
+ switch (self->type) {
+ case ID_SCE:
+ if (!BPy_Scene_Check(value)) {
+ return EXPP_ReturnIntError(PyExc_TypeError,
+ "Must be a scene" );
+ } else {
+ BPy_Scene *bpydata;
+ Scene *data;
+
+ bpydata = (BPy_Scene *)value;
+ data= bpydata->scene;
+
+ if (!data)
+ return EXPP_ReturnIntError(PyExc_RuntimeError,
+ "This Scene has been removed" );
+
+ if (data != G.scene) {
+ set_scene( data );
+ scene_update_for_newframe(data, data->lay);
+ }
+ }
+ return 0;
+
+ case ID_IM:
+ if (!BPy_Image_Check(value)) {
+ return EXPP_ReturnIntError(PyExc_TypeError,
+ "Must be a scene" );
+ } else {
+ BPy_Image *bpydata;
+ Image *data;
+
+ if (!G.sima)
+ return 0;
+
+ bpydata = (BPy_Image *)value;
+ data= bpydata->image;
+
+ if (!data)
+ return EXPP_ReturnIntError(PyExc_RuntimeError,
+ "This Scene has been removed" );
+
+ if (data != G.sima->image)
+ G.sima->image= data;
+ }
+ return 0;
+
+ case ID_TXT:
+ if (!BPy_Text_Check(value)) {
+ return EXPP_ReturnIntError(PyExc_TypeError,
+ "Must be a text" );
+ } else {
+ SpaceText *st= curarea->spacedata.first;
+ Text *data = ((BPy_Text *)value)->text;
+
+ if( !data )
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "This object isn't linked to a Blender Text Object" );
+ if(st->spacetype!=SPACE_TEXT)
+ return 0;
+ st->text = data;
+ }
+ return 0;
+ }
+
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "Only Scene and Image types have the active attribute" );
+}
+
+static int LibBlockSeq_setTag(BPy_LibBlockSeq *self, PyObject *value)
+{
+ ID *id;
+ int param = PyObject_IsTrue( value );
+
+ if( param == -1 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected True/False or 0/1" );
+
+ id = (ID *)wich_libbase(G.main, self->type)->first;
+
+ if (param) {
+ for (; id; id = id->next) {
+ id->flag |= LIB_DOIT;
+ }
+ } else {
+ for (; id; id = id->next) {
+ id->flag &= ~LIB_DOIT;
+ }
+ }
+
+ return 0;
+}
+
+
+/* New Data, internal functions */
+Mesh *add_mesh__internal(char *name)
+{
+ Mesh *mesh = add_mesh(name); /* doesn't return NULL now, but might someday */
+
+ /* Bound box set to null needed because a new mesh is initialized
+ with a bounding box of -1 -1 -1 -1 -1 -1
+ if its not set to null the bounding box is not re-calculated
+ when ob.getBoundBox() is called.*/
+ MEM_freeN(mesh->bb);
+ mesh->bb= NULL;
+ return mesh;
+}
+
+/* used for new and load */
+PyObject *LibBlockSeq_new(BPy_LibBlockSeq *self, PyObject * args, PyObject *kwd)
+{
+ ID *id = NULL;
+ char *name=NULL, *filename=NULL, *data_type=NULL;
+ int img_width=256, img_height=256;
+ float color[] = {0, 0, 0, 1};
+ short data_code = 0;
+ int user_count = 0;
+
+ /* Load from file */
+ if ( ( self->type==ID_IM || self->type==ID_VF ||
+ self->type==ID_SO || self->type==ID_TXT) &&
+ ( PyTuple_Size( args ) < 3 ))
+ {
+ static char *kwlist[] = {"name", "filename", NULL};
+
+ if(PyArg_ParseTupleAndKeywords(args, kwd, "|ss", kwlist, &name, &filename) && filename ) {
+ PyObject *ret= NULL;
+
+ if (strlen(filename) > FILE_MAXDIR + FILE_MAXFILE - 1)
+ return ( EXPP_ReturnPyObjError( PyExc_IOError,
+ "filename too long" ) );
+
+ if (self->type == ID_IM) {
+ Image *img = BKE_add_image_file( filename );
+ if (!img)
+ return ( EXPP_ReturnPyObjError( PyExc_IOError,
+ "couldn't load image" ) );
+ ret = Image_CreatePyObject( img );
+
+ } else if (self->type == ID_VF) {
+ VFont *vf = load_vfont (filename);
+ if (!vf)
+ return EXPP_ReturnPyObjError( PyExc_IOError,
+ "couldn't load font" );
+ ret = Font_CreatePyObject(vf);
+
+ } else if (self->type == ID_SO) {
+ bSound *snd = sound_new_sound( filename );
+ if (!snd)
+ return EXPP_ReturnPyObjError( PyExc_IOError,
+ "couldn't load sound" );
+ ret = Sound_CreatePyObject(snd);
+
+ } else if (self->type == ID_TXT) {
+ Text *txt = NULL;
+ txt = add_text( filename );
+ if( !txt )
+ return EXPP_ReturnPyObjError( PyExc_IOError,
+ "couldn't load text" );
+ ret = Text_CreatePyObject(txt);
+ }
+
+ if (!ret)
+ return EXPP_ReturnPyObjError( PyExc_IOError,
+ "couldn't create pyobject on load, unknown error" );
+ if (name) {
+ ID *id = ((BPy_GenericLib *)ret)->id;
+ rename_id( id, name );
+ }
+ return ret;
+ }
+ }
+
+ /* New Data */
+ if (self->type == ID_IM) {
+ /* Image, accepts width and height*/
+ if( !PyArg_ParseTuple( args, "|sii", &name, &img_width, &img_height ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "one string and two ints expected as arguments" );
+ CLAMP(img_width, 4, 5000);
+ CLAMP(img_height, 4, 5000);
+
+ } else if (self->type == ID_CU) {
+ /* Curve, needs name and type strings */
+ if( !PyArg_ParseTuple( args, "ss", &name, &data_type ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "two strings expected as arguments" );
+
+ if( !strcmp( data_type, "Curve" ) ) data_code = OB_CURVE;
+ else if( !strcmp( data_type, "Text3d" ) ) data_code = OB_FONT;/*
+ else if( !strcmp( data_type, "Surf" ) ) data_code = OB_SURF;*/
+ else return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "Second argument for Curve type incorrect\t\nmust be a string in (Curve or Text - Surf is not supported yet)" );
+
+ } else if (self->type == ID_IP) {
+ /* IPO, needs name and type strings */
+ if( !PyArg_ParseTuple( args, "ss", &name, &data_type ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "two strings expected as arguments" );
+
+ if( !strcmp( data_type, "Object" ) ) data_code = ID_OB;
+ else if( !strcmp( data_type, "Camera" ) ) data_code = ID_CA;
+ else if( !strcmp( data_type, "World" ) ) data_code = ID_WO;
+ else if( !strcmp( data_type, "Material" ) ) data_code = ID_MA;
+ else if( !strcmp( data_type, "Texture" ) ) data_code = ID_TE;
+ else if( !strcmp( data_type, "Lamp" ) ) data_code = ID_LA;
+ else if( !strcmp( data_type, "Action" ) ) data_code = ID_PO;
+ else if( !strcmp( data_type, "Constraint" ) ) data_code = ID_CO;
+ else if( !strcmp( data_type, "Sequence" ) ) data_code = ID_SEQ;
+ else if( !strcmp( data_type, "Curve" ) ) data_code = ID_CU;
+ else if( !strcmp( data_type, "Key" ) ) data_code = ID_KE;
+ else return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "Second argument for IPO type incorrect\t\nmust be a string in (Object, Camera, World, Material, Texture, Lamp, Action, Sequence, Curve, Key)" );
+
+ } else {
+ /* Other types only need the name */
+ if( !PyArg_ParseTuple( args, "|s", &name ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "new(name) - name must be a string argument" );
+ }
+
+ switch (self->type) {
+ case ID_SCE:
+ id = (ID *)add_scene( name?name:"Scene" );
+ user_count = 1;
+ break;
+ case ID_OB:
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "Add objects through the scenes objects iterator" );
+ case ID_ME:
+ id = (ID *)add_mesh__internal( name?name:"Mesh" );
+ break;
+ case ID_CU:
+ id = (ID *)add_curve( name?name:"Curve", data_code );
+ if (data_code==OB_FONT) {
+ Text3d *text3d = (Text3d *)id;
+ text3d->vfont= get_builtin_font();
+ text3d->vfont->id.us++;
+ text3d->str= MEM_mallocN(sizeof(wchar_t), "str");
+ text3d->str[0] = '\0';
+ text3d->totbox= text3d->actbox= 1;
+ text3d->tb= MEM_callocN(MAXTEXTBOX*sizeof(TextBox), "textbox");
+ text3d->tb[0].w = text3d->tb[0].h = 0.0;
+
+ } /*else { CURVE - Dont need to do anything } */
+ break;
+ case ID_MB:
+ id = (ID *)add_mball( name?name:"MBall" );
+ break;
+ case ID_MA:
+ id = (ID *)add_material( name?name:"Material" );
+ break;
+ case ID_TE:
+ id = (ID *)add_texture( name?name:"Texture" );
+ break;
+ case ID_IM:
+ {
+ id = (ID *)BKE_add_image_size(img_width, img_height, name?name:"Image", 0, color);
+ if( !id )
+ return ( EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create PyObject Image_Type" ) );
+ /* new images have zero user count */
+ break;
+ }
+ case ID_LT:
+ id = (ID *)add_lattice( name?name:"Lattice" );
+ break;
+ case ID_LA:
+ id = (ID *)add_lamp( name?name:"Lamp" );
+ break;
+ case ID_CA:
+ id = (ID *)add_camera( name?name:"Camera" );
+ break;
+ case ID_IP:
+ id = (ID *)add_ipo( name?name:"Ipo", data_code );
+ break;
+ case ID_WO:
+ id = (ID *)add_world( name?name:"World" );
+ break;
+ case ID_VF:
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "Cannot create new fonts, use the load() function to load from a file" );
+ case ID_TXT:
+ id = (ID *)add_empty_text( name?name:"Text" );
+ user_count = 1;
+ break;
+ case ID_SO:
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "Cannot create new sounds, use the load() function to load from a file" );
+ case ID_GR:
+ id = (ID *)add_group( name?name:"Group" );
+ user_count = 1;
+ break;
+ case ID_AR:
+ id = (ID *)add_armature( name?name:"Armature" );
+ break;
+ case ID_AC:
+ id = (ID *)add_empty_action( name?name:"Action" );
+ user_count = 1;
+ break;
+ }
+
+ if (!id)
+ Py_RETURN_NONE;
+
+ /* set some types user count to 1, otherwise zero */
+ id->us = user_count;
+
+ return GetPyObjectFromID(id);
+}
+
+
+PyObject *LibBlockSeq_unlink(BPy_LibBlockSeq *self, PyObject * value)
+{
+ switch (self->type) {
+ case ID_SCE:
+ if( !BPy_Scene_Check(value) ) {
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected Scene object" );
+ } else {
+ Scene *data = ((BPy_Scene *)value)->scene;
+
+ if (!data)
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "This Scene has been removed" );
+
+ /* Run the removal code */
+ free_libblock( &G.main->scene, data );
+ ((BPy_Scene *)value)->scene = NULL;
+ Py_RETURN_NONE;
+ }
+ case ID_GR:
+ if( !BPy_Group_Check(value) ) {
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected Group object" );
+ } else {
+ Group *data = ((BPy_Group *)value)->group;
+
+ if (!data)
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "This Group has been removed alredy" );
+
+ /* Run the removal code */
+ free_group(data);
+ unlink_group(data);
+ data->id.us= 0;
+ free_libblock( &G.main->group, data );
+ ((BPy_Group *)value)->group = NULL;
+
+ Py_RETURN_NONE;
+ }
+
+ case ID_TXT:
+ if( !BPy_Text_Check(value) ) {
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected Text object" );
+ } else {
+ Text *data = ((BPy_Text *)value)->text;
+
+ if (!data)
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "This Group has been removed alredy" );
+
+ /* Run the removal code */
+ BPY_clear_bad_scriptlinks( data );
+ free_text_controllers( data );
+ unlink_text( data );
+ free_libblock( &G.main->text, data );
+ ((BPy_Text *)value)->text = NULL;
+
+ Py_RETURN_NONE;
+ }
+ }
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "Only types Scene, Group and Text can unlink" );
+}
+
+static int LibBlockSeq_compare( BPy_LibBlockSeq * a, BPy_LibBlockSeq * b )
+{
+ return ( a->type == b->type) ? 0 : -1;
+}
+
+/*
+ * repr function
+ * callback functions building meaninful string to representations
+ */
+static PyObject *LibBlockSeq_repr( BPy_LibBlockSeq * self )
+{
+ return PyString_FromFormat( "[LibBlockSeq Iterator]");
+}
+
+static PyGetSetDef LibBlockSeq_getseters[] = {
+ {"active",
+ (getter)LibBlockSeq_getActive, (setter)LibBlockSeq_setActive,
+ "active object",
+ NULL},
+ {"tag",
+ (getter)NULL, (setter)LibBlockSeq_setTag,
+ "tag all data in True or False (write only)",
+ NULL},
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+static struct PyMethodDef BPy_LibBlockSeq_methods[] = {
+ {"new", (PyCFunction)LibBlockSeq_new, METH_VARARGS | METH_KEYWORDS,
+ "(name) - Create a new object in this scene from the obdata given and return a new object"},
+ {"unlink", (PyCFunction)LibBlockSeq_unlink, METH_O,
+ "unlinks the object from the scene"},
+ {NULL, NULL, 0, NULL}
+};
+
+/*****************************************************************************/
+/* Python LibBlockSeq_Type structure definition: */
+/*****************************************************************************/
+PyTypeObject LibBlockSeq_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender LibBlockSeq", /* char *tp_name; */
+ sizeof( BPy_LibBlockSeq ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ NULL, /* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ ( cmpfunc ) LibBlockSeq_compare, /* cmpfunc tp_compare; */
+ ( reprfunc ) LibBlockSeq_repr, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ &LibBlockSeq_as_mapping, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ ( getiterfunc) LibBlockSeq_getIter, /* getiterfunc tp_iter; */
+ ( iternextfunc ) LibBlockSeq_nextIter, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_LibBlockSeq_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ LibBlockSeq_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+
+/*-----------------------------BPy module Init())-----------------------------*/
+
+PyObject * Data_Init( void )
+{
+ PyObject *module;
+ PyObject *dict;
+
+
+ PyType_Ready( &LibBlockSeq_Type );
+ PyType_Ready( &Config_Type );
+
+ /*submodule = Py_InitModule3( "Blender.Main", NULL, M_Main_doc );*/
+ module = Py_InitModule3( "bpy.data", NULL, "The bpy.data submodule" );
+ dict = PyModule_GetDict( module );
+
+ /* Python Data Types */
+ PyModule_AddObject( module, "scenes", LibBlockSeq_CreatePyObject(NULL, ID_SCE) );
+ PyModule_AddObject( module, "objects", LibBlockSeq_CreatePyObject(NULL, ID_OB) );
+ PyModule_AddObject( module, "meshes", LibBlockSeq_CreatePyObject(NULL, ID_ME) );
+ PyModule_AddObject( module, "curves", LibBlockSeq_CreatePyObject(NULL, ID_CU) );
+ PyModule_AddObject( module, "metaballs",LibBlockSeq_CreatePyObject(NULL, ID_MB) );
+ PyModule_AddObject( module, "materials",LibBlockSeq_CreatePyObject(NULL, ID_MA) );
+ PyModule_AddObject( module, "textures", LibBlockSeq_CreatePyObject(NULL, ID_TE) );
+ PyModule_AddObject( module, "images", LibBlockSeq_CreatePyObject(NULL, ID_IM) );
+ PyModule_AddObject( module, "lattices", LibBlockSeq_CreatePyObject(NULL, ID_LT) );
+ PyModule_AddObject( module, "lamps", LibBlockSeq_CreatePyObject(NULL, ID_LA) );
+ PyModule_AddObject( module, "cameras", LibBlockSeq_CreatePyObject(NULL, ID_CA) );
+ PyModule_AddObject( module, "ipos", LibBlockSeq_CreatePyObject(NULL, ID_IP) );
+ PyModule_AddObject( module, "worlds", LibBlockSeq_CreatePyObject(NULL, ID_WO) );
+ PyModule_AddObject( module, "fonts", LibBlockSeq_CreatePyObject(NULL, ID_VF) );
+ PyModule_AddObject( module, "texts", LibBlockSeq_CreatePyObject(NULL, ID_TXT) );
+ PyModule_AddObject( module, "sounds", LibBlockSeq_CreatePyObject(NULL, ID_SO) );
+ PyModule_AddObject( module, "groups", LibBlockSeq_CreatePyObject(NULL, ID_GR) );
+ PyModule_AddObject( module, "armatures",LibBlockSeq_CreatePyObject(NULL, ID_AR) );
+ PyModule_AddObject( module, "actions", LibBlockSeq_CreatePyObject(NULL, ID_AC) );
+ return module;
+}
diff --git a/source/blender/python/api2_2x/bpy_data.h b/source/blender/python/api2_2x/bpy_data.h
new file mode 100644
index 00000000000..45600df6471
--- /dev/null
+++ b/source/blender/python/api2_2x/bpy_data.h
@@ -0,0 +1,55 @@
+/*
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Campbell Barton
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_BPYDATA_H
+#define EXPP_BPYDATA_H
+
+#include <Python.h>
+#include "DNA_listBase.h"
+
+/* The Main PyType Object defined in Main.c */
+extern PyTypeObject LibBlockSeq_Type;
+
+#define BPy_LibBlockSeq_Check(v) \
+ ((v)->ob_type == &LibBlockSeq_Type)
+
+/* Main sequence, iterate on the libdatas listbase*/
+typedef struct {
+ PyObject_VAR_HEAD /* required python macro */
+ Link *iter; /* so we can iterate over the listbase */
+
+ short type; /* store the ID type such as ID_ME */
+} BPy_LibBlockSeq;
+
+
+PyObject * Data_Init( void );
+
+#endif /* EXPP_BPYDATA_H */
diff --git a/source/blender/python/api2_2x/bpy_types.h b/source/blender/python/api2_2x/bpy_types.h
new file mode 100644
index 00000000000..0b83db6c674
--- /dev/null
+++ b/source/blender/python/api2_2x/bpy_types.h
@@ -0,0 +1,93 @@
+/*
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_bpy_types_h
+#define EXPP_bpy_types_h
+
+
+/*****************************************************************************/
+/* Camera Data */
+/*****************************************************************************/
+
+
+/*****************************************************************************/
+/* Lamp Data */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* Ipo Data */
+/*****************************************************************************/
+
+
+
+/*****************************************************************************/
+/* Metaball Data */
+/*****************************************************************************/
+
+
+/*****************************************************************************/
+/* Metaelem Data */
+/*****************************************************************************/
+
+
+/*****************************************************************************/
+/* Effect Data */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* Wave Data */
+/*****************************************************************************/
+
+
+/*****************************************************************************/
+/* Build Data */
+/*****************************************************************************/
+
+
+/*****************************************************************************/
+/* Particle Data */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* Curve Data */
+/*****************************************************************************/
+
+/**********
+ CurNurb data
+***********/
+
+
+/*****************************************************************************/
+/* World Data */
+/*****************************************************************************/
+
+
+#endif /* EXPP_bpy_types_h */
diff --git a/source/blender/python/api2_2x/charRGBA.c b/source/blender/python/api2_2x/charRGBA.c
new file mode 100644
index 00000000000..43c9b7772fa
--- /dev/null
+++ b/source/blender/python/api2_2x/charRGBA.c
@@ -0,0 +1,475 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#include "charRGBA.h" /*This must come first */
+#include "gen_utils.h"
+
+/* This file is heavily based on the old bpython Constant object code in
+ Blender */
+
+/*****************************************************************************/
+/* Python charRGBA_Type callback function prototypes: */
+/*****************************************************************************/
+static PyObject *charRGBA_repr( BPy_charRGBA * self );
+
+static int charRGBALength( BPy_charRGBA * self );
+
+static PyObject *charRGBASubscript( BPy_charRGBA * self, PyObject * key );
+static int charRGBAAssSubscript( BPy_charRGBA * self, PyObject * who,
+ PyObject * cares );
+
+static PyObject *charRGBAItem( BPy_charRGBA * self, int i );
+static int charRGBAAssItem( BPy_charRGBA * self, int i, PyObject * ob );
+static PyObject *charRGBASlice( BPy_charRGBA * self, int begin, int end );
+static int charRGBAAssSlice( BPy_charRGBA * self, int begin, int end,
+ PyObject * seq );
+static PyObject *charRGBA_getColor( BPy_charRGBA * self, void * type);
+static int charRGBA_setColor( BPy_charRGBA * self, PyObject * value, void * type);
+
+/*****************************************************************************/
+/* Python charRGBA_Type Mapping Methods table: */
+/*****************************************************************************/
+static PyMappingMethods charRGBAAsMapping = {
+ ( inquiry ) charRGBALength, /* mp_length */
+ ( binaryfunc ) charRGBASubscript, /* mp_subscript */
+ ( objobjargproc ) charRGBAAssSubscript, /* mp_ass_subscript */
+};
+
+/*****************************************************************************/
+/* Python charRGBA_Type Sequence Methods table: */
+/*****************************************************************************/
+static PySequenceMethods charRGBAAsSequence = {
+ ( inquiry ) charRGBALength, /* sq_length */
+ ( binaryfunc ) 0, /* sq_concat */
+ ( intargfunc ) 0, /* sq_repeat */
+ ( intargfunc ) charRGBAItem, /* sq_item */
+ ( intintargfunc ) charRGBASlice, /* sq_slice */
+ ( intobjargproc ) charRGBAAssItem, /* sq_ass_item */
+ ( intintobjargproc ) charRGBAAssSlice, /* sq_ass_slice */
+};
+
+static PyGetSetDef charRGBA_getseters[] = {
+ {"R",
+ (getter)charRGBA_getColor, (setter)charRGBA_setColor,
+ "the red component",
+ (void *) 0},
+ {"r",
+ (getter)charRGBA_getColor, (setter)charRGBA_setColor,
+ "the red component",
+ (void *) 0},
+ {"G",
+ (getter)charRGBA_getColor, (setter)charRGBA_setColor,
+ "the green component",
+ (void *) 1},
+ {"g",
+ (getter)charRGBA_getColor, (setter)charRGBA_setColor,
+ "the green component",
+ (void *) 1},
+ {"B",
+ (getter)charRGBA_getColor, (setter)charRGBA_setColor,
+ "the blue component",
+ (void *) 2},
+ {"b",
+ (getter)charRGBA_getColor, (setter)charRGBA_setColor,
+ "the blue component",
+ (void *) 2},
+ {"A",
+ (getter)charRGBA_getColor, (setter)charRGBA_setColor,
+ "the alpha component",
+ (void *) 3},
+ {"a",
+ (getter)charRGBA_getColor, (setter)charRGBA_setColor,
+ "the alpha component",
+ (void *) 3},
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+/*****************************************************************************/
+/* Python charRGBA_Type structure definition: */
+/*****************************************************************************/
+PyTypeObject charRGBA_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "charRGBA", /* tp_name */
+ sizeof( BPy_charRGBA ), /* tp_basicsize */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ NULL, /* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* cmpfunc tp_compare; */
+ ( reprfunc ) charRGBA_repr, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ &charRGBAAsSequence, /* PySequenceMethods *tp_as_sequence; */
+ &charRGBAAsMapping, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ NULL, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ charRGBA_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+/*****************************************************************************/
+/* Function: charRGBA_New */
+/*****************************************************************************/
+PyObject *charRGBA_New( char *rgba )
+{
+ BPy_charRGBA *charRGBA = NULL;
+
+ /*
+ * When called the first time, charRGBA_Type.tp_dealloc will be NULL.
+ * If that's the case, initialize the PyTypeObject. If the
+ * initialization succeeds, then create a new object.
+ */
+
+ if( charRGBA_Type.tp_dealloc || PyType_Ready( &charRGBA_Type ) >= 0 ) {
+ charRGBA = ( BPy_charRGBA * ) PyObject_NEW( BPy_charRGBA,
+ &charRGBA_Type );
+ }
+
+ if( charRGBA == NULL )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create charRGBA object" );
+
+ /* rgba is a pointer to the first item of a char[4] array */
+ charRGBA->rgba[0] = &rgba[0];
+ charRGBA->rgba[1] = &rgba[1];
+ charRGBA->rgba[2] = &rgba[2];
+ charRGBA->rgba[3] = &rgba[3];
+
+ return ( PyObject * ) charRGBA;
+}
+
+/*****************************************************************************/
+/* Functions: charRGBA_getCol and charRGBA_setCol */
+/* Description: These functions get/set rgba color triplet values. The */
+/* get function returns a tuple, the set one accepts three */
+/* chars (separated or in a tuple) as arguments. */
+/*****************************************************************************/
+PyObject *charRGBA_getCol( BPy_charRGBA * self )
+{
+ PyObject *list = PyList_New( 4 );
+
+ if( !list )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create PyList" );
+
+ PyList_SET_ITEM( list, 0, PyInt_FromLong( *(self->rgba[0])) );
+ PyList_SET_ITEM( list, 1, PyInt_FromLong( *(self->rgba[1])) );
+ PyList_SET_ITEM( list, 2, PyInt_FromLong( *(self->rgba[2])) );
+ PyList_SET_ITEM( list, 3, PyInt_FromLong( *(self->rgba[3])) );
+ return list;
+}
+
+PyObject *charRGBA_setCol( BPy_charRGBA * self, PyObject * args )
+{
+ int ok;
+ char r = 0, g = 0, b = 0, a = 0;
+
+ if( PyObject_Length( args ) == 4 )
+ ok = PyArg_ParseTuple( args, "bbbb", &r, &g, &b, &a );
+
+ else
+ ok = PyArg_ParseTuple( args, "|(bbbb)", &r, &g, &b, &a );
+
+ if( !ok )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected 1-byte ints [b,b,b,b] or b,b,b,b as arguments (or nothing)" );
+
+ *( self->rgba[0] ) = (char)EXPP_ClampInt( r, 0, 255 );
+ *( self->rgba[1] ) = (char)EXPP_ClampInt( g, 0, 255 );
+ *( self->rgba[2] ) = (char)EXPP_ClampInt( b, 0, 255 );
+ *( self->rgba[3] ) = (char)EXPP_ClampInt( a, 0, 255 );
+
+ return EXPP_incr_ret( Py_None );
+}
+
+/* return color value for one of the components */
+
+static PyObject *charRGBA_getColor( BPy_charRGBA * self, void * type)
+{
+ int index = ((long)type) & 3;
+ return PyInt_FromLong ( *self->rgba[index] );
+}
+
+/* sets the color value of one of the components */
+
+static int charRGBA_setColor( BPy_charRGBA * self, PyObject * value,
+ void * type)
+{
+ int index = ((long)type) & 3;
+ PyObject *num = PyNumber_Int( value );
+
+ /* argument must be a number */
+ if( !num )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected char argument" );
+
+ /* clamp valut to 0..255 then assign */
+ *self->rgba[index] = (char)EXPP_ClampInt( (int)PyInt_AS_LONG(value),
+ 0, 255 );
+ Py_DECREF( num );
+ return 0;
+}
+
+/*****************************************************************************/
+/* Section: charRGBA as Mapping */
+/* These functions provide code to access charRGBA objects as */
+/* mappings. */
+/*****************************************************************************/
+static int charRGBALength( BPy_charRGBA * self )
+{
+ return 4;
+}
+
+static PyObject *charRGBASubscript( BPy_charRGBA * self, PyObject * key )
+{
+ char *name = NULL;
+ int i;
+
+ if( PyNumber_Check( key ) )
+ return charRGBAItem( self, ( int ) PyInt_AsLong( key ) );
+
+ if( !PyArg_ParseTuple( key, "s", &name ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected int or string argument" );
+
+ if( !strcmp( name, "R" ) || !strcmp( name, "r" ) )
+ i = 0;
+ else if( !strcmp( name, "G" ) || !strcmp( name, "g" ) )
+ i = 1;
+ else if( !strcmp( name, "B" ) || !strcmp( name, "b" ) )
+ i = 2;
+ else if( !strcmp( name, "A" ) || !strcmp( name, "a" ) )
+ i = 3;
+ else
+ return EXPP_ReturnPyObjError( PyExc_AttributeError, name );
+
+ return PyInt_FromLong( (long)(*self->rgba[i]) );
+}
+
+static int charRGBAAssSubscript( BPy_charRGBA * self, PyObject * key,
+ PyObject * v )
+{
+ char *name = NULL;
+ int i;
+
+ if( !PyNumber_Check( v ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "value to assign must be a number" );
+
+ if( PyNumber_Check( key ) )
+ return charRGBAAssItem( self, ( int ) PyInt_AsLong( key ), v );
+
+ if( !PyArg_Parse( key, "s", &name ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected int or string argument" );
+
+ if( !strcmp( name, "R" ) || !strcmp( name, "r" ) )
+ i = 0;
+ else if( !strcmp( name, "G" ) || !strcmp( name, "g" ) )
+ i = 1;
+ else if( !strcmp( name, "B" ) || !strcmp( name, "b" ) )
+ i = 2;
+ else if( !strcmp( name, "A" ) || !strcmp( name, "a" ) )
+ i = 3;
+ else
+ return EXPP_ReturnIntError( PyExc_AttributeError, name );
+
+ *( self->rgba[i] ) = (char)EXPP_ClampInt( PyInt_AsLong( v ), 0, 255 );
+
+ return 0;
+}
+
+/*****************************************************************************/
+/* Section: charRGBA as Sequence */
+/* These functions provide code to access charRGBA objects as */
+/* sequences. */
+/*****************************************************************************/
+static PyObject *charRGBAItem( BPy_charRGBA * self, int i )
+{
+ if( i < 0 || i >= 4 )
+ return EXPP_ReturnPyObjError( PyExc_IndexError,
+ "array index out of range" );
+
+ return PyInt_FromLong( *(self->rgba[i]) );
+}
+
+static PyObject *charRGBASlice( BPy_charRGBA * self, int begin, int end )
+{
+ PyObject *list;
+ int count;
+
+ if( begin < 0 )
+ begin = 0;
+ if( end > 4 )
+ end = 4;
+ if( begin > end )
+ begin = end;
+
+ list = PyList_New( end - begin );
+
+ for( count = begin; count < end; count++ )
+ PyList_SetItem( list, count - begin,
+ PyInt_FromLong( *( self->rgba[count] ) ) );
+
+ return list;
+}
+
+static int charRGBAAssItem( BPy_charRGBA * self, int i, PyObject * ob )
+{
+ if( i < 0 || i >= 4 )
+ return EXPP_ReturnIntError( PyExc_IndexError,
+ "array assignment index out of range" );
+
+ if( !PyNumber_Check( ob ) )
+ return EXPP_ReturnIntError( PyExc_IndexError,
+ "color component must be a number" );
+
+ *( self->rgba[i] ) = (char)EXPP_ClampInt( PyInt_AsLong( ob ), 0, 255 );
+
+ return 0;
+}
+
+static int charRGBAAssSlice( BPy_charRGBA * self, int begin, int end,
+ PyObject * seq )
+{
+ int count;
+
+ if( begin < 0 )
+ begin = 0;
+ if( end > 4 )
+ end = 4;
+ if( begin > end )
+ begin = end;
+
+ if( !PySequence_Check( seq ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "illegal argument type for built-in operation" );
+
+ if( PySequence_Length( seq ) != ( end - begin ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "size mismatch in slice assignment" );
+
+ for( count = begin; count < end; count++ ) {
+ char value;
+ PyObject *ob = PySequence_GetItem( seq, count );
+
+ if( !PyArg_Parse( ob, "b", &value ) ) {
+ Py_DECREF( ob );
+ return -1;
+ }
+
+ *( self->rgba[count] ) = (char)EXPP_ClampInt( value, 0, 255 );
+
+ Py_DECREF( ob );
+ }
+
+ return 0;
+}
+
+/*****************************************************************************/
+/* Function: charRGBA_repr */
+/* Description: This is a callback function for the BPy_charRGBA type. It */
+/* builds a meaninful string to represent charRGBA objects. */
+/*****************************************************************************/
+static PyObject *charRGBA_repr( BPy_charRGBA * self )
+{
+ char r, g, b, a;
+
+ r = *( self->rgba[0] );
+ g = *( self->rgba[1] );
+ b = *( self->rgba[2] );
+ a = *( self->rgba[3] );
+
+ return PyString_FromFormat( "[%d, %d, %d, %d]", r, g, b, a );
+}
diff --git a/source/blender/python/api2_2x/charRGBA.h b/source/blender/python/api2_2x/charRGBA.h
new file mode 100644
index 00000000000..20573f1ce7b
--- /dev/null
+++ b/source/blender/python/api2_2x/charRGBA.h
@@ -0,0 +1,59 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_charRGBA_H
+#define EXPP_charRGBA_H
+
+#include <Python.h>
+
+/* Objects of <type 'charRGBA'> are used inside other Blender Python
+ * objects, so this header file must contain only 'public' declarations */
+/* there's also rgbTuple, for rgb floats and a color obj in NMesh, messy! */
+
+/* Python BPy_charRGBA structure definition: */
+
+typedef struct {
+ PyObject_HEAD
+ char *rgba[4]; /* array of four pointers to chars */
+
+} BPy_charRGBA;
+
+extern PyTypeObject charRGBA_Type;
+
+/*****************************************************************************/
+/* Python API function prototypes for the charRGBA helper module. */
+/*****************************************************************************/
+PyObject *charRGBA_New( char *rgba );
+PyObject *charRGBA_getCol( BPy_charRGBA * self );
+PyObject *charRGBA_setCol( BPy_charRGBA * self, PyObject * args );
+
+#endif /* EXPP_charRGBA_H */
diff --git a/source/blender/python/api2_2x/constant.c b/source/blender/python/api2_2x/constant.c
new file mode 100644
index 00000000000..3a64de610f1
--- /dev/null
+++ b/source/blender/python/api2_2x/constant.c
@@ -0,0 +1,269 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano, Joseph Gilbert
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#include "constant.h" /*This must come first */
+
+#include "gen_utils.h"
+#include "BLI_blenlib.h"
+
+PyTypeObject constant_Type;
+
+//------------------METHOD IMPLEMENTATIONS-----------------------------
+//------------------------constant.items()
+//Returns a list of key:value pairs like dict.items()
+PyObject* constant_items(BPy_constant *self)
+{
+ return PyDict_Items(self->dict);
+}
+//------------------------constant.keys()
+//Returns a list of keys like dict.keys()
+PyObject* constant_keys(BPy_constant *self)
+{
+ return PyDict_Keys(self->dict);
+}
+//------------------------constant.values()
+//Returns a list of values like dict.values()
+PyObject* constant_values(BPy_constant *self)
+{
+ return PyDict_Values(self->dict);
+}
+//------------------ATTRIBUTE IMPLEMENTATION---------------------------
+//------------------TYPE_OBECT IMPLEMENTATION--------------------------
+//-----------------------(internal)
+//Creates a new constant object
+static PyObject *new_const(void)
+{
+ BPy_constant *constant;
+
+ constant = (BPy_constant *) PyObject_NEW(BPy_constant, &constant_Type);
+ if(constant == NULL){
+ return (EXPP_ReturnPyObjError(PyExc_MemoryError,
+ "couldn't create constant object"));
+ }
+ if((constant->dict = PyDict_New()) == NULL){
+ return (EXPP_ReturnPyObjError(PyExc_MemoryError,
+ "couldn't create constant object's dictionary"));
+ }
+
+ return (PyObject *)constant;
+}
+//------------------------tp_doc
+//The __doc__ string for this object
+static char BPy_constant_doc[] = "This is an internal subobject of armature\
+designed to act as a Py_Bone dictionary.";
+
+//------------------------tp_methods
+//This contains a list of all methods the object contains
+static PyMethodDef BPy_constant_methods[] = {
+ {"items", (PyCFunction) constant_items, METH_NOARGS,
+ "() - Returns the key:value pairs from the dictionary"},
+ {"keys", (PyCFunction) constant_keys, METH_NOARGS,
+ "() - Returns the keys the dictionary"},
+ {"values", (PyCFunction) constant_values, METH_NOARGS,
+ "() - Returns the values from the dictionary"},
+ {NULL, NULL, 0, NULL}
+};
+//------------------------mp_length
+static int constantLength(BPy_constant *self)
+{
+ return 0;
+}
+//------------------------mp_subscript
+static PyObject *constantSubscript(BPy_constant *self, PyObject *key)
+{
+ if(self->dict) {
+ PyObject *v = PyDict_GetItem(self->dict, key);
+ if(v) {
+ return EXPP_incr_ret(v);
+ }
+ return EXPP_ReturnPyObjError( PyExc_KeyError,
+ "key not found" );
+ }
+ return NULL;
+}
+//------------------------mp_ass_subscript
+static int constantAssSubscript(BPy_constant *self, PyObject *who, PyObject *cares)
+{
+ return 0; /* no user assignments allowed */
+}
+//------------------------tp_getattro
+static PyObject *constant_getAttro(BPy_constant * self, PyObject *value)
+{
+ if(self->dict) {
+ PyObject *v;
+ char *name = PyString_AS_STRING( value );
+
+ if(!strcmp(name, "__members__"))
+ return PyDict_Keys(self->dict);
+
+#if 0
+ if(!strcmp(name, "__methods__") || !strcmp(name, "__dict__")) {
+ return PyObject_GenericGetAttr( (PyObject *)self, value );
+ }
+#endif
+
+ v = PyDict_GetItemString(self->dict, name);
+ if(v) {
+ return EXPP_incr_ret(v); /* was a borrowed ref */
+ }
+ return PyObject_GenericGetAttr( (PyObject *)self, value );
+ }
+ return (EXPP_ReturnPyObjError(PyExc_RuntimeError,
+ "constant object lacks a dictionary"));
+}
+//------------------------tp_repr
+static PyObject *constant_repr(BPy_constant * self)
+{
+ char str[4096];
+ PyObject *key, *value, *tempstr;
+ int pos = 0;
+
+ BLI_strncpy(str,"[Constant: ",4096);
+ tempstr = PyString_FromString("name");
+ value = PyDict_GetItem( self->dict, tempstr );
+ Py_DECREF(tempstr);
+ if(value) {
+ strcat(str, PyString_AsString(value));
+ } else {
+ short sep = 0;
+ strcat(str,"{");
+ while (PyDict_Next(self->dict, &pos, &key, &value)) {
+ if( sep )
+ strcat (str, ", ");
+ else
+ sep = 1;
+ strcat (str, PyString_AsString(key));
+ }
+ strcat(str,"}");
+ }
+ strcat(str, "]");
+ return PyString_FromString(str);
+}
+//------------------------tp_dealloc
+static void constant_dealloc(BPy_constant * self)
+{
+ Py_DECREF(self->dict);
+ PyObject_DEL(self);
+}
+
+//------------------TYPE_OBECT DEFINITION------------------------------
+static PyMappingMethods constantAsMapping = {
+ (inquiry) constantLength, // mp_length
+ (binaryfunc) constantSubscript, // mp_subscript
+ (objobjargproc) constantAssSubscript, // mp_ass_subscript
+};
+
+PyTypeObject constant_Type = {
+ PyObject_HEAD_INIT(NULL) //tp_head
+ 0, //tp_internal
+ "Constant", //tp_name
+ sizeof(BPy_constant), //tp_basicsize
+ 0, //tp_itemsize
+ (destructor)constant_dealloc, //tp_dealloc
+ 0, //tp_print
+ 0, //tp_getattr
+ 0, //tp_setattr
+ 0, //tp_compare
+ (reprfunc) constant_repr, //tp_repr
+ 0, //tp_as_number
+ 0, //tp_as_sequence
+ &constantAsMapping, //tp_as_mapping
+ 0, //tp_hash
+ 0, //tp_call
+ 0, //tp_str
+ (getattrofunc)constant_getAttro, //tp_getattro
+ 0, //tp_setattro
+ 0, //tp_as_buffer
+ Py_TPFLAGS_DEFAULT, //tp_flags
+ BPy_constant_doc, //tp_doc
+ 0, //tp_traverse
+ 0, //tp_clear
+ 0, //tp_richcompare
+ 0, //tp_weaklistoffset
+ 0, //tp_iter
+ 0, //tp_iternext
+ BPy_constant_methods, //tp_methods
+ 0, //tp_members
+ 0, //tp_getset
+ 0, //tp_base
+ 0, //tp_dict
+ 0, //tp_descr_get
+ 0, //tp_descr_set
+ 0, //tp_dictoffset
+ 0, //tp_init
+ 0, //tp_alloc
+ 0, //tp_new
+ 0, //tp_free
+ 0, //tp_is_gc
+ 0, //tp_bases
+ 0, //tp_mro
+ 0, //tp_cache
+ 0, //tp_subclasses
+ 0, //tp_weaklist
+ 0 //tp_del
+};
+//------------------VISIBLE PROTOTYPE IMPLEMENTATION-------------------
+//Creates a default empty constant
+PyObject *PyConstant_New(void)
+{
+ return new_const();
+}
+//Inserts a key:value pair into the constant and then returns 0/1
+int PyConstant_Insert(BPy_constant *self, char *name, PyObject *value)
+{
+ PyType_Ready( &constant_Type );
+ return EXPP_dict_set_item_str(self->dict, name, value);
+}
+//This is a helper function for generating constants......
+PyObject *PyConstant_NewInt(char *name, int value)
+{
+ PyObject *constant = PyConstant_New();
+
+ if (constant)
+ {
+ PyConstant_Insert((BPy_constant*)constant, "name", PyString_FromString(name));
+ PyConstant_Insert((BPy_constant*)constant, "value", PyInt_FromLong(value));
+ }
+ return constant;
+}
+//This is a helper function for generating constants......
+PyObject *PyConstant_NewString(char *name, char *value)
+{
+ PyObject *constant = PyConstant_New();
+
+ if (constant)
+ {
+ PyConstant_Insert((BPy_constant*)constant, "name", PyString_FromString(name));
+ PyConstant_Insert((BPy_constant*)constant, "value", PyString_FromString(value));
+ }
+ return constant;
+}
diff --git a/source/blender/python/api2_2x/constant.h b/source/blender/python/api2_2x/constant.h
new file mode 100644
index 00000000000..a3eb7e98e0d
--- /dev/null
+++ b/source/blender/python/api2_2x/constant.h
@@ -0,0 +1,53 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano, Joseph Gilbert
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_constant_H
+#define EXPP_constant_H
+
+#include <Python.h>
+
+/*-------------------TYPE CHECKS-------------------------------*/
+#define BPy_Constant_Check(v) ((v)->ob_type==&constant_Type)
+/*-------------------TYPEOBJECT--------------------------------*/
+extern PyTypeObject constant_Type;
+/*-------------------STRUCT DEFINITION-------------------------*/
+typedef struct {
+ PyObject_HEAD
+ PyObject * dict;
+} BPy_constant;
+/*-------------------VISIBLE PROTOTYPES-----------------------*/
+PyObject *PyConstant_New(void);
+int PyConstant_Insert(BPy_constant *self, char *name, PyObject *value);
+PyObject *PyConstant_NewInt(char *name, int value);
+PyObject *PyConstant_NewString(char *name, char *value);
+
+#endif /* EXPP_constant_H */
diff --git a/source/blender/python/api2_2x/doc/API_intro.py b/source/blender/python/api2_2x/doc/API_intro.py
new file mode 100644
index 00000000000..a630c47229e
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/API_intro.py
@@ -0,0 +1,247 @@
+# This is not a real module, it's simply an introductory text.
+
+"""
+The Blender Python API Reference
+================================
+
+ An asterisk (*) means the module has been updated.
+
+ for a full list of changes since 2.42 see U{http://mediawiki.blender.org/index.php/Release_Notes/Notes243/Python_API}
+
+ Top Module:
+ -----------
+
+ - L{Blender}
+ - L{bpy<Bpy>} (experimental)
+
+ Submodules:
+ -----------
+ - L{Armature} (*)
+ - L{NLA}
+ - L{Action<NLA.Action>}
+ - L{BezTriple} (*)
+ - L{BGL}
+ - L{Camera} (*)
+ - L{Curve} (*)
+ - L{Draw} (*)
+ - L{Effect}
+ - L{Geometry} (*)
+ - L{Group} (*)
+ - L{Image} (*)
+ - L{Ipo} (*)
+ - L{IpoCurve} (*)
+ - L{Key} (*)
+ - L{Lamp}
+ - L{Lattice} (*)
+ - L{Library} (*)
+ - L{Material} (*)
+ - L{Mathutils} (*)
+ - L{Mesh} (*)
+ - L{MeshPrimitives} (*)
+ - L{Metaball} (*)
+ - L{NMesh} (deprecated)
+ - L{Noise}
+ - L{Object} (*)
+ - L{Modifier} (*)
+ - L{Pose} (*)
+ - L{Constraint} (*)
+ - L{ActionStrips<NLA>} (*)
+ - L{Registry}
+ - L{Scene} (*)
+ - L{Radio}
+ - L{Render} (*)
+ - L{Sound} (*)
+ - L{Text}
+ - L{Text3d}
+ - L{Font}
+ - L{Texture} (*)
+ - L{TimeLine}
+ - L{Types}
+ - L{Window}
+ - L{Theme} (*)
+ - L{World}
+ - L{sys<Sys>}
+
+ Additional information:
+ -----------------------
+
+ - L{Special features<API_related>}:
+ - scripts: registering in menus, documenting, configuring (new);
+ - command line examples (new);
+ - script links (*), space handler script links, Group module (new).
+
+Introduction:
+=============
+
+ This reference documents the Blender Python API, a growing collection of
+ Python modules (libraries) that give access to part of the program's internal
+ data and functions.
+
+ Through scripting Blender can be extended in real-time via
+ U{Python <www.python.org>}, an impressive high level, multi-paradigm, open
+ source language. Newcomers are recommended to start with the tutorial that
+ comes with it.
+
+ This opens many interesting possibilities, ranging from automating repetitive
+ tasks to adding new functionality to the program: procedural models,
+ importers and exporters, even complex applications and so on. Blender itself
+ comes with some scripts, but many others can be found in the Scripts & Plugins
+ sections and forum posts at the Blender-related sites listed below.
+
+Scripting and Blender:
+======================
+
+These are the basic ways to execute scripts in Blender:
+
+ 1. They can be loaded or typed as text files in the Text Editor window, then
+ executed with ALT+P.
+ 2. Via command line: C{blender -P <scriptname>} will start Blender and execute
+ the given script. <scriptname> can be a filename in the user's file system or
+ the name of a text saved in a .blend Blender file:
+ 'blender myfile.blend -P textname'.
+ 3. Via command line in I{background mode}: use the '-b' flag (the order is
+ important): C{blender -b <blendfile> -P <scriptname>}. <blendfile> can be any
+ .blend file, including the default .B.blend that is in Blender's home directory
+ L{Blender.Get}('homedir'). In this mode no window will be opened and the
+ program will leave as soon as the script finishes execution.
+ 4. Properly registered scripts can be selected directly from the program's
+ menus.
+ 5. Scriptlinks: these are also loaded or typed in the Text Editor window and
+ can be linked to objects, materials or scenes using the Scriptlink buttons
+ tab. Script links get executed automatically when their events (ONLOAD,
+ REDRAW, FRAMECHANGED) are triggered. Normal scripts can create (L{Text}) and
+ link other scripts to objects and events, see L{Object.Object.addScriptLink},
+ for example.
+ 6. A script can call another script (that will run in its own context, with
+ its own global dictionary) with the L{Blender.Run} module function.
+
+
+Interaction with users:
+-----------------------
+
+ Scripts can:
+ - simply run and exit;
+ - pop messages, menus and small number and text input boxes;
+ - draw graphical user interfaces (GUIs) with OpenGL calls and native
+ program buttons, which stay there accepting user input like any other
+ Blender window until the user closes them;
+ - attach themselves to a space's event or drawing code (aka space handlers,
+ L{check here<API_related>});
+ - make changes to the 3D View (set visible layer(s), view point, etc);
+ - grab the main input event queue and process (or pass to Blender) selected
+ keyboard, mouse, redraw events -- not considered good practice, but still
+ available for private use;
+ - tell Blender to execute other scripts (see L{Blender.Run}());
+ - use external Python libraries, if available.
+
+ You can read the documentation for the L{Window}, L{Draw} and L{BGL} modules
+ for more information and also check the Python site for external modules that
+ might be useful to you. Note though that any imported module will become a
+ requirement of your script, since Blender itself does not bundle external
+ modules.
+
+Command line mode:
+------------------
+
+ Python was embedded in Blender, so to access BPython modules you need to
+ run scripts from the program itself: you can't import the Blender module
+ into an external Python interpreter.
+
+ On the other hand, for many tasks it's possible to control Blender via
+ some automated process using scripts. Interested readers should learn about
+ features like "OnLoad" script links, the "-b <blendfile>" (background mode)
+ and "-P <script>" (run script) command line options and API calls like
+ L{Blender.Save}, L{Blender.Load}, L{Blender.Quit} and the L{Library} and
+ L{Render} modules.
+
+ Note that command line scripts are run before Blender initializes its windows
+ (and in '-b' mode no window will be initialized), so many functions that get
+ or set window related attributes (like most in L{Window}) don't work here. If
+ you need those, use an ONLOAD script link (see L{Scene.Scene.addScriptLink})
+ instead -- it's also possible to use a command line script to write or set an
+ ONLOAD script link. Check the L{Blender.mode} module var to know if Blender
+ is being executed in "background" or "interactive" mode.
+
+ L{Click here for command line and background mode examples<API_related>}.
+
+
+Demo mode:
+----------
+
+ Blender has a demo mode, where once started it can work without user
+ intervention, "showing itself off". Demos can render stills and animations,
+ play rendered or real-time animations, calculate radiosity simulations and
+ do many other nifty things. If you want to turn a .blend file into a demo,
+ write a script to run the show and link it as a scene "OnLoad" scriptlink.
+ The demo will then be played automatically whenever this .blend file is
+ opened, B{unless Blender was started with the "-y" parameter}.
+
+The Game Engine API:
+--------------------
+
+ Blender has a game engine for users to create and play 3d games. This
+ engine lets programmers add scripts to improve game AI, control, etc, making
+ more complex interaction and tricks possible. The game engine API is
+ separate from the Blender Python API this document references and you can
+ find its own ref doc in the doc section of the main sites below.
+
+Blender Data Structures:
+------------------------
+
+ Programs manipulate data structures. Blender python scripts are no exception.
+ Blender uses an Object Oriented architecture. The BPython interface tries to
+ present Blender objects and their attributes in the same way you see them
+ through the User Interface (the GUI). One key to BPython programming is
+ understanding the information presented in Blender's OOPS window where Blender
+ objects and their relationships are displayed.
+
+ Each Blender graphic element (Mesh, Lamp, Curve, etc.) is composed from two
+ parts: an Object and ObData. The Object holds information about the position,
+ rotation and size of the element. This is information that all elements have
+ in common. The ObData holds information specific to that particular type of
+ element.
+
+ Each Object has a link to its associated ObData. A single ObData may be
+ shared by many Objects. A graphic element also has a link to a list of
+ Materials. By default, this list is associated with the ObData.
+
+ All Blender objects have a unique name. However, the name is qualified by the
+ type of the object. This means you can have a Lamp Object called Lamp.001
+ (OB:Lamp.001) and a Lamp ObData called Lamp.001 (LA:Lamp.001).
+
+ For a more in-depth look at Blender internals, and some understanding of why
+ Blender works the way it does, see the U{Blender Architecture document
+ <http://www.blender3d.org/cms/Blender_Architecture.336.0.html>}.
+
+
+A note to newbie script writers:
+--------------------------------
+
+ Interpreted languages are known to be much slower than compiled code, but for
+ many applications the difference is negligible or acceptable. Also, with
+ profiling (or even simple direct timing with L{Blender.sys.time<Sys.time>}) to
+ identify slow areas and well thought optimizations, the speed can be
+ I{considerably} improved in many cases. Try some of the best BPython scripts
+ to get an idea of what can be done, you may be surprised.
+
+@author: The Blender Python Team
+@requires: Blender 2.43 or newer.
+@version: 2.43
+@see: U{www.blender3d.org<http://www.blender3d.org>}: main site
+@see: U{www.blender.org<http://www.blender.org>}: documentation and forum
+@see: U{blenderartists.org<http://blenderartists.org>}: user forum
+@see: U{projects.blender.org<http://projects.blender.org>}
+@see: U{blender architecture<http://www.blender3d.org/cms/Blender_Architecture.336.0.html>}: blender architecture document
+@see: U{www.python.org<http://www.python.org>}
+@see: U{www.python.org/doc<http://www.python.org/doc>}
+@see: U{Blending into Python<en.wikibooks.org/wiki/Blender_3D:_Blending_Into_Python>}: User contributed documentation, featuring a blender/python cookbook with many examples.
+
+@note: the official version of this reference guide is only updated for each
+ new Blender release. But you can build the current CVS
+ version yourself: install epydoc, grab all files in the
+ source/blender/python/api2_2x/doc/ folder of Blender's CVS and use the
+ epy_docgen.sh script also found there to generate the html docs.
+ Naturally you will also need a recent Blender binary to try the new
+ features. If you prefer not to compile it yourself, there is a testing
+ builds forum at U{blender.org<http://www.blender.org>}.
+"""
diff --git a/source/blender/python/api2_2x/doc/API_related.py b/source/blender/python/api2_2x/doc/API_related.py
new file mode 100644
index 00000000000..87b29e7f524
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/API_related.py
@@ -0,0 +1,564 @@
+# This is not a real module, it's simply an introductory text.
+
+"""
+Blender Python related features
+===============================
+
+ L{Back to Main Page<API_intro>}
+
+
+Introduction:
+=============
+
+ This page describes special features available to BPython scripts:
+
+ - Command line mode is accessible with the '-P' and '-b' Blender options.
+ - Registration allows scripts to become available from some pre-defined menus
+ in Blender, like Import, Export, Wizards and so on.
+ - Script links are Blender Texts (scripts) executed when a particular event
+ (redraws, .blend file loading, saving, frame changed, etc.) occurs. Now
+ there are also "Space Handlers" to draw onto or get events from a given
+ space (only 3D View now) in some window.
+ - Proper documentation data is used by the 'Scripts Help Browser' script to
+ show help information for any registered script. Your own GUI can use
+ this facility with the L{Blender.ShowHelp} function.
+ - Configuration is for data in your script that can be tweaked according to
+ user taste or needs. Like documentation, this is another helper
+ functionality -- you don't need to provide a GUI yourself to edit config
+ data.
+
+
+ Command line usage:
+ ===================
+
+ Specifying scripts:
+ -------------------
+
+ The '-P' option followed either by:
+ - a script filename (full pathname if not in the same folder where you run
+ the command);
+ - the name of a Text in a .blend file (that must also be specified)
+ will open Blender and immediately run the given script.
+
+ Example::
+
+ # open Blender and execute the given script:
+ blender -P script.py
+
+ Passing parameters:
+ -------------------
+
+ To pass parameters to the script you can:
+ - write them to a file before running Blender, then make your script parse that file;
+ - set environment variables and access them with the 'os' module:
+
+ Examples with parameters being passed to the script via command line::
+
+ # execute a command like:
+
+ myvar=value blender -P script.py
+
+ # and in script.py access myvar with os.getenv
+ # (os.environ and os.setenv are also useful):
+
+ # script.py:
+ import os
+ val = os.getenv('myvar')
+
+ # To pass multiple parameters, simply write them in sequence,
+ # separated by spaces:
+
+ myvar1=value1 myvar2=value2 mystr="some string data" blender -P script.py
+
+ Background mode:
+ ----------------
+
+ In '-b' mode no windows will be opened: the program will run as a command
+ line tool able to render stills and animations and execute any working Python
+ script with complete access to loaded .blend's file contents. Once the task
+ is completed, the program will exit.
+
+ Background mode examples::
+
+ # Open Blender in background mode with file 'myfile.blend'
+ # and run the script 'script.py':
+
+ blender -b myfile.blend -P script.py
+
+ # Note: a .blend file is always required. 'script.py' can be a file
+ # in the file system or a Blender Text stored in 'myfile.blend'.
+
+ # Let's assume 'script.py' has code to render the current frame;
+ # this line will set the [s]tart and [e]nd (and so the current) frame to
+ # frame 44 and call the script:
+
+ blender -b myfile.blend -s 44 -e 44 -P script.py
+
+ # Using now a script written to render animations, we set different
+ # start and end frames and then execute this line:
+
+ blender -b myfile.blend -s 1 -e 10 -P script.py
+
+ # Note: we can also set frames and define if we want a single image or
+ # an animation in the script body itself, naturally.
+
+ The rendered pictures will be written to the default render folder, that can
+ also be set via BPython (take a look at L{Render.RenderData}). Their
+ names will be the equivalent frame number followed by the extension of the
+ chosen image type: 0001.png, for example. To rename them to something else,
+ coders can use the C{rename} function in the standard 'os' Python module.
+
+ Reminder: if you just need to render, it's not necessary to have a script.
+ Blender can create stills and animations with its own command line arguments.
+ Example:
+ - a single image at frame 44: blender -b myfile.blend -f 44
+ - an animation from frame 1 to 10: blender -b myfile.blend -s 1 -e 10 -a
+
+
+ Script links:
+ =============
+
+ Object script links:
+ --------------------
+
+ Users can link Blender Text scripts and objects to have the script
+ code executed when specific events occur to the objects. For example, if a
+ Camera has an script link set to "FrameChanged", the script will be executed
+ whenever the current frame is changed. Links can either be manually added by
+ users on the Buttons window -> Scripts tab or created by another script (see,
+ for example, L{Object.addScriptLink<Object.Object.addScriptLink>}).
+
+ These are the types which can be linked to scripts:
+ - Camera Data;
+ - Lamp Data;
+ - Materials;
+ - Objects;
+ - Scenes;
+ - Worlds.
+
+ And these are the available event choices:
+ - Redraw;
+ - FrameChanged;
+ - Render;
+ - OnLoad (*);
+ - OnSave (*).
+
+ (*) only available for scenes
+
+ There are three L{Blender} module variables that script link authors should
+ be aware of:
+ - B{bylink}: True if the script is running as a script link;
+ - B{link}: the object the running script was linked to (None if this is
+ not a script link);
+ - B{event}: the event type, if the running script is being executed as a
+ script link.
+
+ Example::
+ #script link
+ import Blender
+ if Blender.bylink: # we're running as a script link
+ print "Event: %s for %s" % (Blender.event, Blender.link)
+
+ B{Important note about "Render" events}:
+
+ Each "Render" script link is executed twice: before rendering and after, for
+ reverting changes and for possible clean up actions. Before rendering,
+ 'Blender.event' will be "Render" and after rendering it will be "PostRender".
+
+ Example::
+ # render script link
+ import Blender
+ event = Blender.event
+ if event == "Render":
+ # prepare for rendering
+ create_my_very_detailed_mesh_data()
+ elif event == "PostRender":
+ # done rendering, clean up
+ delete_my_very_detailed_mesh_data()
+
+ As suggested by the example above, this is especially useful for script links
+ that need to generate data only useful while rendering, or in case they need
+ to switch between two mesh data objects, one meant for realtime display and
+ the other, more detailed, for renders.
+
+ Space Handler script links:
+ ---------------------------
+
+ This is a new kind of script linked to spaces in a given window. Right now
+ only the 3D View has the necessary hooks, but the plan is to add access to
+ other types, too. Just to clarify naming conventions: in Blender, a screen
+ is partitioned in windows (also called areas) and each window can show any
+ space. Spaces are: 3D View, Text Editor, Scripts, Buttons, User Preferences,
+ Oops, etc.
+
+ Space handlers are texts in the Text Editor, like other script links, but they
+ need to have a special header to be recognized -- B{I{the first line in the
+ text file}} must inform:
+ 1. that they are space handlers;
+ 2. the space they belong to;
+ 3. whether they are EVENT or DRAW handlers.
+
+ Example header for a 3D View EVENT handler::
+
+ # SPACEHANDLER.VIEW3D.EVENT
+
+ Example header for a 3D View DRAW handler::
+
+ # SPACEHANDLER.VIEW3D.DRAW
+
+ Available space handlers can be toggled "on" or "off" in the space header's
+ B{View->Space Handler Scripts} submenu, by the user.
+
+ EVENT space handler scripts are called by that space's event handling callback
+ in Blender. The script receives the event B{before} it is further processed
+ by the program. An EVENT handler script should check Blender.event (compare
+ it against L{Draw} events) and either:
+ - process it (the script must set Blender.event to None then);
+ - ignore it.
+
+ Setting C{Blender.event = None} tells Blender not to go on processing itself
+ the event, because it was grabbed by the script.
+
+ Example::
+
+ # SPACEHANDLER.VIEW3D.EVENT
+
+ import Blender
+ from Blender import Draw
+ evt = Blender.event
+ return_it = False
+
+ if evt == Draw.LEFTMOUSE:
+ print "Swallowing the left mouse button press"
+ elif evt == Draw.AKEY:
+ print "Swallowing an 'a' character"
+ else:
+ print "Let the 3D View itself process this event:", evt
+ return_it = True
+
+ # if Blender should not process itself the passed event:
+ if not return_it: Blender.event = None
+
+ DRAW space handlers are called by that space's drawing callback in Blender.
+ The script is called B{after} the space has been drawn.
+
+ Two of the L{Blender} module variables related to script links assume
+ different roles for space handlers:
+ - B{bylink} is the same: True if the script is running as a script link;
+ - B{link}: integer from the L{Blender}.SpaceHandlers constant dictionary,
+ tells what space this handler belongs to and the handler's type
+ (EVENT, DRAW);
+ - B{event}:
+ - EVENT handlers: an input event (check keys and mouse events in L{Draw})
+ to be processed or ignored.
+ - DRAW handlers: 0 always.
+
+ B{Guidelines (important)}:
+ - EVENT handlers can access and change Blender objects just like any other
+ script, but they should not draw to the screen, B{use a DRAW handler to do
+ that}. Specifically: L{Draw.Image} and the L{BGL} drawing functions
+ should not be used inside an EVENT handler.
+ - DRAW handlers should leave the space in the same state it was before they
+ were executed. OpenGL attributes and the modelview and projection matrices
+ are automatically saved (pushed) before a DRAW handler runs and restored
+ (popped) after it finishes, no need to worry about that. Draw handlers
+ should not grab events;
+ - If script handlers need to pass information to each other (for example an
+ EVENT handler passing info to a DRAW handler), use the L{Registry} module.
+ - in short: use the event handler to deal with events and the draw handler to
+ draw and your script will be following the recommended practices for
+ Blender code.
+
+ Registering scripts:
+ ====================
+
+ To be registered a script needs two things:
+ - to be either in the default scripts directory or in the user defined scripts
+ path (see User Preferences window -> File Paths tab -> Python path);
+ - to have a proper header.
+
+ Try 'blender -d' to know where your default directory for scripts is, it will
+ inform either the directory or the file with that info already parsed, which is
+ in the same directory of the scripts folder.
+
+ The header should be like this one (all double and single apostrophes below
+ are required)::
+ #!BPY
+
+ # \"\"\"
+ # Name: 'Script Name'
+ # Blender: 233
+ # Group: 'Export'
+ # Submenu: 'All' all
+ # Submenu: 'Selected' sel
+ # Submenu: 'Configure (gui)' gui
+ # Tooltip: 'Export to some format.'
+ # \"\"\"
+
+ where:
+ - B{Name} is the string that will appear in the menu;
+ - B{Blender} is the minimum program version required to run the script;
+ - B{Group} defines where the script will be put, see all groups in the
+ Scripts Window's header, menu "Scripts";
+ - B{Submenu} adds optional submenus for further control;
+ - B{Tooltip} is the (short) tooltip string for the menu entry.
+
+ note:
+ - all double and single apostrophes above are required;
+ - you can "comment out" the header above, by starting lines with
+ '#', like we did. This is not required (except for the first line, #!BPY,
+ of course), but this way the header won't conflict with Python tools that
+ you can use to generate documentation for your script code. Just
+ remember to keep this header above any other line with triple
+ double-quotes (\"\"\") in your script.
+
+ Submenu lines are not required, use them if you want to provide extra
+ options. To see which submenu the user chose, check the "__script__"
+ dictionary in your code: __script__['arg'] has the defined keyword (the word
+ after the submenu string name: all, sel or gui in the example above) of the
+ chosen submenu. For example, if the user clicked on submenu 'Selected' above,
+ __script__['arg'] will be "sel".
+
+ If your script requires extra data or configuration files, there is a special
+ folder where they can be saved: see 'datadir' in L{Blender.Get}.
+
+
+ Documenting scripts:
+ ====================
+
+ The "Scripts Help Browser" script in the Help menu can parse special variables
+ from registered scripts and display help information for users. For that,
+ authors only need to add proper information to their scripts, after the
+ registration header.
+
+ The expected variables:
+
+ - __bpydoc__ (or __doc__) (type: string):
+ - The main help text. Write a first short paragraph explaining what the
+ script does, then add the rest of the help text, leaving a blank line
+ between each new paragraph. To force line breaks you can use <br> tags.
+
+ - __author__ (type: string or list of strings):
+ - Author name(s).
+
+ - __version__ (type: string):
+ - Script version. A good recommendation is using a version number followed
+ by the date in the format YYYY/MM/DD: "1.0 2005/12/31".
+
+ - __url__ (type: string or list of strings):
+ - Internet links that are shown as buttons in the help screen. Clicking
+ them opens the user's default browser at the specified location. The
+ expected format for each url entry is e.g.
+ "Author's site, http://www.somewhere.com". The first part, before the
+ comma (','), is used as the button's tooltip. There are two preset
+ options: "blender" and "elysiun", which link to the Python forums at
+ blender.org and elysiun.com, respectively.
+
+ - __email__ (optional, type: string or list of strings):
+ - Equivalent to __url__, but opens the user's default email client. You
+ can write the email as someone:somewhere*com and the help script will
+ substitute accordingly: someone@somewhere.com. This is only a minor help
+ to hide emails from spammers, since your script may be available at some
+ site. "scripts" is the available preset, with the email address of the
+ mailing list devoted to scripting in Blender, bf-scripts-dev@blender.org.
+ You should only use this one if you are subscribed to the list:
+ http://projects.blender.org/mailman/listinfo/bf-scripts-dev for more
+ information.
+
+ Example::
+ __author__ = 'Mr. Author'
+ __version__ = '1.0 2005/01/01'
+ __url__ = ["Author's site, http://somewhere.com",
+ "Support forum, http://somewhere.com/forum/", "blender", "elysiun"]
+ __email__ = ["Mr. Author, mrauthor:somewhere*com", "scripts"]
+ __bpydoc__ = \"\"\"\\
+ This script does this and that.
+
+ Explaining better, this script helps you create ...
+
+ You can write as many paragraphs as needed.
+
+ Shortcuts:<br>
+ Esc or Q: quit.<br>
+ etc.
+
+ Supported:<br>
+ Meshes, metaballs.
+
+ Known issues:<br>
+ This is just an example, there's no actual script.
+
+ Notes:<br>
+ You can check scripts bundled with Blender to see more examples of how to
+ add documentation to your own works.
+ \"\"\"
+
+ B{Note}: your own GUI or menu code can display documentation by calling the
+ help browser with the L{Blender.ShowHelp} function.
+
+ Configuring scripts:
+ ====================
+
+ The L{Blender.Registry<Registry>} module provides a simplified way to keep
+ scripts configuration options in memory and also saved in config files.
+ And with the "Scripts Config Editor" script in the System menu users can later
+ view and edit the options easily.
+
+ Let's first clarify what we mean by config options: they are simple data
+ (bools, ints, floats, strings) used by programs to conform to user
+ preferences. The buttons in Blender's User Preferences window are a good
+ example.
+
+ For example, a particular exporter might include:
+ - SEPARATE_MATS = False: a bool variable (True / False) to determine if it
+ should write materials to a separate file;
+ - VERSION = 2: an int to define an specific version of the export format;
+ - TEX_DIR = "/path/to/textures": a default texture dir to prepend to all
+ exported texture filenames instead of their actual paths.
+
+ The script needs to provide users a GUI to configure these options -- or else
+ directly editing the source code would be the only way to change them. And to
+ store changes made to the GUI so they can be reloaded any time the script is
+ executed, programmers have to write and load their own config files (ideally at
+ L{Blender.Get}('udatadir') or, if not available, L{Blender.Get}('datadir')).
+
+ This section describes BPython facilities (based on the L{Registry} module and
+ the config editor) that can take care of this in a simplified (and much
+ recommended) way.
+
+ Here's how it works::
+
+ # sample_exporter.py
+ import Blender
+ from Blender import Registry
+
+ # First define all config variables with their default values:
+ SEPARATE_MATERIALS = True
+ VERSION = True
+ TEX_DIR = ''
+ EXPORT_DIR = ''
+
+ # Then define a function to update the Registry:
+ def registry_update():
+ # populate a dict with current config values:
+ d = {
+ 'SEPARATE_MATERIALS': SEPARATE_MATERIALS,
+ 'VERSION': VERSION,
+ 'TEX_DIR': TEX_DIR,
+ 'EXPORT_DIR': EXPORT_DIR
+ }
+ # store the key (optional 3rd arg tells if
+ # the data should also be written to a file):
+ Registry.SetKey('sample_exporter', d, True)
+
+ # (A good convention is to use the script name as Registry key)
+
+ # Now we check if our key is available in the Registry or file system:
+ regdict = Registry.GetKey('sample_exporter', True)
+
+ # If this key already exists, update config variables with its values:
+ if regdict:
+ try:
+ SEPARATE_MATERIALS = regdict['SEPARATE_MATERIALS']
+ VERSION = regdict['VERSION']
+ TEX_DIR = regdict['TEX_DIR']
+ EXPORT_DIR = regdict['EXPORT_DIR']
+
+ # if data was corrupted (or a new version of the script changed
+ # (expanded, removed, renamed) the config vars and users may have
+ # the old config file around):
+ except: update_registry() # rewrite it
+
+ else: # if the key doesn't exist yet, use our function to create it:
+ update_registry()
+
+ # ...
+
+ Hint: nicer code than the simplistic example above can be written by keeping
+ config var names in a list of strings and using the exec function.
+
+ B{Note}: if your script's GUI lets users change config vars, call the
+ registry_update() function in the button events callback to save the changes.
+ On the other hand, you don't need to handle configuration
+ in your own gui, it can be left for the 'Scripts Config Editor',
+ which should have access to your script's config key as soon as the
+ above code is executed once (as soon as SetKey is executed).
+
+ B{Note} (limits for config vars): strings longer than 300 characters are
+ clamped and the number of items in dictionaries, sequences and the config key
+ itself is limited to 60.
+
+
+ Scripts Configuration Editor:
+ -----------------------------
+
+ This script should be available from the System menu in the Scripts window.
+ It provides a GUI to view and edit saved configuration data, both from the
+ Registry dictionary in memory and the scripts config data dir. This is
+ useful for all scripts with config vars, but especially for those without GUIs,
+ like most importers and exporters, since this editor will provide one for them.
+
+ The example above already gives a good idea of how the information can be
+ prepared to be accessible from this editor, but there is more worth knowing:
+
+ 1. String vars that end with '_dir' or '_file' (can be upper case, too) are
+ recognized as input boxes for dirs or files and a 'browse' button is added to
+ their right side, to call the file selector.
+
+ 2. Both key names and configuration variables names starting with an
+ underscore ('_') are ignored by the editor. Programmers can use this feature
+ for any key or config var that is not meant to be configured by this editor.
+
+ 3. The following information refers to extra config variables that may be
+ added specifically to aid the configuration editor script. To clarify, in the
+ example code above these variables (the string 'script' and the dictionaries
+ 'tooltips' and 'limits') would appear along with SEPARATE_MATERIALS, VERSION,
+ TEX_DIR and EXPORT_DIR, wherever they are written.
+
+ Minor note: these names are case insensitive: tooltips, TOOLTIPS, etc. are all
+ recognized.
+
+ 3.1 The config editor will try to display a 'help' button for a key, to show
+ documentation for the script that owns it. To find this "owner script", it
+ will first look for a config variable called 'script', a string containing
+ the name of the owner Python file (with or without '.py' extension)::
+
+ script = 'sample_exporter.py'
+
+ If there is no such variable, the editor will check if the file formed by the
+ key name and the '.py' extension exists. If both alternatives fail, no help
+ button will be displayed.
+
+ 3.2 You can define tooltips for the buttons that the editor creates for your
+ config data (string input, toggle, number sliders). Simply create a dict
+ called 'tooltips', where config var names are keys and their tooltips,
+ values::
+
+ tooltips = {
+ 'EXPORT_DIR': 'default folder where exported files should be saved',
+ 'VERBOSE': 'print info and warning messages to the console',
+ 'SEPARATE_MATERIALS': 'write materials to their own file'
+ }
+
+ 3.3 Int and float button sliders need min and max limits. This can be passed
+ to the editor via a dict called 'limits' (ivar1, ivar2 and fvar are meant as
+ extra config vars that might have been in the example code above)::
+
+ limits = {'ivar1': [-10, 10], 'ivar2': [0, 100], 'fvar1': [-12.3, 15.4]}
+
+ 4. The Config Editor itself maintains a Registry key called "General", with
+ general options relevant to many scripts, like "verbose" to tell if the user
+ wants messages printed to the console and "confirm overwrite", to know if
+ a script should ask for confirmation before overwriting files (all exporters
+ are recommended to access the General key and check this var -- L{sys.exists
+ <Sys.exists>} tells if files or folders already exist).
+
+ Hint: for actual examples, try the ac3d importer and exporter (it's enough to
+ call them from the menus then cancel with ESC), as those have been updated to
+ use this config system. After calling them their config data will be available
+ in the Config Editor. We also recommend adding a section about config vars
+ in your script's help info, as done in the ac3d ones.
+
+ L{Back to Main Page<API_intro>}
+ ===============================
+"""
diff --git a/source/blender/python/api2_2x/doc/Armature.py b/source/blender/python/api2_2x/doc/Armature.py
new file mode 100644
index 00000000000..0dbaf28d6f8
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Armature.py
@@ -0,0 +1,368 @@
+# Blender.Armature module and the Armature PyType object
+
+"""
+The Blender.Armature submodule.
+
+Armature
+========
+
+This module provides access to B{Armature} objects in Blender. These are
+"skeletons", used to deform and animate other objects -- meshes, for
+example.
+
+Example::
+ import Blender
+ from Blender import Armature
+ from Blender.Mathutils import *
+ #
+ arms = Armature.Get()
+ for arm in arms.values():
+ arm.drawType = Armature.STICK #set the draw type
+ arm.makeEditable() #enter editmode
+
+ #generating new editbone
+ eb = Armature.Editbone()
+ eb.roll = 10
+ eb.parent = arm.bones['Bone.003']
+ eb.head = Vector(1,1,1)
+ eb.tail = Vector(0,0,1)
+ eb.options = [Armature.HINGE, Armature.CONNECTED]
+
+ #add the bone
+ arm.bones['myNewBone'] = eb
+
+ #delete an old bone
+ del arm.bones['Bone.002']
+
+ arm.update() #save changes
+
+ for bone in arm.bones.values():
+ #print bone.matrix['ARMATURESPACE']
+ print bone.parent, bone.name
+ print bone.children, bone.name
+ print bone.options, bone.name
+
+
+Example::
+ # Adds empties for every bone in the selected armature, an example of getting worldspace locations for bones.
+ from Blender import *
+ def test_arm():
+ scn= Scene.GetCurrent()
+ arm_ob= scn.objects.active
+
+ if not arm_ob or arm_ob.type != 'Armature':
+ Draw.PupMenu('not an armature object')
+ return
+
+ # Deselect all
+ for ob in scn.objects:
+ if ob != arm_ob:
+ ob.sel= 0
+
+ arm_mat= arm_ob.matrixWorld
+
+ arm_data= arm_ob.getData()
+
+ bones= arm_data.bones.values()
+ for bone in bones:
+ bone_mat= bone.matrix['ARMATURESPACE']
+ bone_mat_world= bone_mat*arm_mat
+
+ ob_empty= scn.objects.new('Empty')
+ ob_empty.setMatrix(bone_mat_world)
+
+ test_arm()
+
+@var CONNECTED: Connect this bone to parent
+@type CONNECTED: Constant
+@var HINGE: Don't inherit rotation or scale from parent
+@type HINGE: Constant
+@var NO_DEFORM: If bone will not deform geometry
+@type NO_DEFORM: Constant
+@var MULTIPLY: Multiply bone with vertex group
+@type MULTIPLY: Constant
+@var HIDDEN_EDIT: Bone is hidden in editmode
+@type HIDDEN_EDIT: Constant
+@var ROOT_SELECTED: Root of the Bone is selected
+@type ROOT_SELECTED: Constant
+@var BONE_SELECTED: Bone is selected
+@type BONE_SELECTED: Constant
+@var TIP_SELECTED: Tip of the Bone is selected
+@type TIP_SELECTED: Constant
+@var OCTAHEDRON: Bones drawn as octahedrons
+@type OCTAHEDRON: Constant
+@var STICK: Bones drawn as a line
+@type STICK: Constant
+@var BBONE: Bones draw as a segmented B-spline
+@type BBONE: Constant
+@var ENVELOPE: Bones draw as a stick with envelope influence
+@type ENVELOPE: Constant
+"""
+
+def Get (name = None):
+ """
+ Get the Armature object(s) from Blender.
+ @type name: string, nothing, or list of strings
+ @param name: The string name of an armature.
+ @rtype: Blender Armature or a list of Blender Armatures
+ @return: It depends on the I{name} parameter:
+ - (name): The Armature object with the given I{name};
+ - (name, name, ...): A list of Armature objects
+ - (): A list with all Armature objects in the current scene.
+ @warning: In versions 2.42 and earlier, a string argument for an armature
+ that doesn't exist will return None. Later versions raise a Value error.
+ """
+
+def New (name = None):
+ """
+ Return a new armature.
+ @type name: string or nothing
+ @param name: The string name of the new armature.
+ @rtype: Blender Armature.
+ @return: A new armature.
+ """
+
+class Armature:
+ """
+ The Armature object
+ ===================
+ This object gives access to Armature-specific data in Blender.
+ @ivar bones: A Dictionary of Bones (BonesDict) that make up this armature.
+ @type bones: BonesDict Object
+ @ivar vertexGroups: Whether vertex groups define deformation
+ @type vertexGroups: Bool
+ @ivar envelopes: Whether bone envelopes define deformation
+ @type envelopes: Bool
+ @ivar restPosition: Show rest position (no posing possible)
+ @type restPosition: Bool
+ @ivar delayDeform: Don't deform children when manipulating bones
+ @type delayDeform: Bool
+ @ivar drawAxes: Draw bone axes
+ @type drawAxes: Bool
+ @ivar drawNames: Draw bone names
+ @type drawNames: Bool
+ @ivar ghost: Draw ghosts around frame for current Action
+ @type ghost: Bool
+ @ivar ghostStep: Number of frames between ghosts
+ @type ghostStep: Int
+ @ivar drawType: The drawing type that is used to display the armature
+ Acceptable values are:
+ - Armature.OCTAHEDRON: bones drawn as octahedrons
+ - Armature.STICK: bones drawn as sticks
+ - Armature.BBONE: bones drawn as b-bones
+ - Armature.ENVELOPE: bones drawn as sticks with envelopes
+ @type drawType: Constant Object
+ @ivar mirrorEdit: X-axis mirrored editing
+ @type mirrorEdit: Bool
+ @ivar autoIK: Adds temporary IK chains while grabbing bones
+ @type autoIK: Bool
+ @ivar layerMask: Layer bitmask
+ Example::
+ # set armature to layers 14 and 16
+ armature.layerMask = (1<<13) + (1<<15)
+ @type layerMask: Int
+ """
+
+ def __init__(name = 'myArmature'):
+ """
+ Initializer for the Armature TypeObject.
+ Example::
+ myNewArmature = Blender.Armature.Armature('AR_1')
+ @param name: The name for the new armature
+ @type name: string
+ @return: New Armature Object
+ @rtype: Armature Object
+ """
+
+ def makeEditable():
+ """
+ Put the armature into EditMode for editing purposes. (Enters Editmode)
+ @warning: Using Window.Editmode() to switch the editmode manually will cause problems and possibly even crash Blender.
+ @warning: This is only needed for operations such as adding and removing bones.
+ @warning: Do access pose data until you have called update() or settings will be lost.
+ @warning: The armature should not be in manual editmode
+ prior to calling this method. The armature must be parented
+ to an object prior to editing.
+ @rtype: None
+ """
+
+ def update():
+ """
+ Save all changes and update the armature. (Leaves Editmode)
+ @note: Must have called makeEditable() first.
+ @rtype: None
+ """
+
+import id_generics
+Armature.__doc__ += id_generics.attributes
+
+class BonesDict:
+ """
+ The BonesDict object
+ ====================
+ This object gives gives dictionary like access to the bones in an armature.
+ It is internal to blender but is called as 'Armature.bones'
+
+ Removing a bone:
+ Example::
+ del myArmature.bones['bone_name']
+ Adding a bone:
+ Example::
+ myEditBone = Armature.Editbone()
+ myArmature.bones['bone_name'] = myEditBone
+ """
+
+ def items():
+ """
+ Return the key, value pairs in this dictionary
+ @rtype: string, BPy_bone
+ @return: All strings, and py_bones in the armature (in that order)
+ """
+
+ def keys():
+ """
+ Return the keys in this dictionary
+ @rtype: string
+ @return: All strings representing the bone names
+ """
+
+ def values():
+ """
+ Return the values in this dictionary
+ @rtype: BPy_bone
+ @return: All BPy_bones in this dictionary
+ """
+
+class Bone:
+ """
+ The Bone object
+ ===============
+ This object gives access to Bone-specific data in Blender. This object
+ cannot be instantiated but is returned by BonesDict when the armature is not in editmode.
+ @ivar name: The name of this Bone.
+ @type name: String
+ @ivar roll: This Bone's roll value.
+ Keys are:
+ - 'ARMATURESPACE' - this roll in relation to the armature
+ - 'BONESPACE' - the roll in relation to itself
+ @type roll: Dictionary
+ @ivar head: This Bone's "head" ending position when in rest state.
+ Keys are:
+ - 'ARMATURESPACE' - this head position in relation to the armature
+ - 'BONESPACE' - the head position in relation to itself.
+ @type head: Dictionary
+ @ivar tail: This Bone's "tail" ending position when in rest state.
+ Keys are:
+ - 'ARMATURESPACE' - this tail position in relation to the armature
+ - 'BONESPACE' - the tail position in relation to itself
+ @type tail: Dictionary
+ @ivar matrix: This Bone's matrix. This cannot be set.
+ Keys are:
+ - 'ARMATURESPACE' - this matrix of the bone in relation to the armature
+ - 'BONESPACE' - the matrix of the bone in relation to itself
+ @type matrix: Matrix Object
+ @ivar parent: The parent Bone.
+ @type parent: Bone Object
+ @ivar children: The children directly attached to this bone.
+ @type children: List of Bone Objects
+ @ivar weight: The bone's weight.
+ @type weight: Float
+ @ivar options: Various bone options which can be:
+ - Armature.CONNECTED: IK to parent
+ - Armature.HINGE: No parent rotation or scaling
+ - Armature.NO_DEFORM: The bone does not deform geometry
+ - Armature.MULTIPLY: Multiply vgroups by envelope
+ - Armature.HIDDEN_EDIT: Hide bones in editmode
+ - Armature.ROOT_SELECTED: Selection of root ball of bone
+ - Armature.BONE_SELECTED: Selection of bone
+ - Armature.TIP_SELECTED: Selection of tip ball of bone
+ @type options: List of Constants
+ @ivar subdivision: The number of bone subdivisions.
+ @type subdivision: Int
+ @ivar deformDist: The deform distance of the bone
+ @type deformDist: Float
+ @ivar length: The length of the bone. This cannot be set.
+ @type length: Float
+ @ivar headRadius: The radius of this bones head (used for envalope bones)
+ @type headRadius: Float
+ @ivar tailRadius: The radius of this bones head (used for envalope bones)
+ @type tailRadius: Float
+ @ivar layerMask: Layer bitmask
+ Example::
+ # set bone to layers 14 and 16
+ bone.layerMask = (1<<13) + (1<<15)
+ @type layerMask: Int
+ """
+
+ def hasParent():
+ """
+ Whether or not this bone has a parent
+ @rtype: Bool
+ """
+
+ def hasChildren():
+ """
+ Whether or not this bone has children
+ @rtype: Bool
+ """
+
+ def getAllChildren():
+ """
+ Gets all the children under this bone including the children's children.
+ @rtype: List of Bone object
+ @return: all bones under this one
+ """
+
+class Editbone:
+ """
+ The Editbone Object
+ ===================
+ This object is a wrapper for editbone data and is used only in the manipulation
+ of the armature in editmode.
+ @ivar name: The name of this Bone.
+ @type name: String
+ @ivar roll: This Bone's roll value (armaturespace).
+ @type roll: Float
+ @ivar head: This Bone's "head" ending position when in rest state (armaturespace).
+ @type head: Vector Object
+ @ivar tail: This Bone's "tail" ending position when in rest state (armaturespace).
+ @type tail: Vector Object
+ @ivar matrix: This Bone's matrix. (armaturespace)
+ @type matrix: Matrix Object
+ @ivar parent: The parent Bone.
+ @type parent: Editbone Object
+ @ivar weight: The bone's weight.
+ @type weight: Float
+ @ivar options: Various bone options which can be:
+ - Armature.CONNECTED: IK to parent
+ - Armature.HINGE: No parent rotation or scaling
+ - Armature.NO_DEFORM: The bone does not deform geometry
+ - Armature.MULTIPLY: Multiply vgroups by envelope
+ - Armature.HIDDEN_EDIT: Hide bones in editmode
+ - Armature.ROOT_SELECTED: Selection of root ball of bone
+ - Armature.BONE_SELECTED: Selection of bone
+ - Armature.TIP_SELECTED: Selection of tip ball of bone
+ @type options: List of Constants
+ @ivar subdivision: The number of bone subdivisions.
+ @type subdivision: Int
+ @ivar deformDist: The deform distance of the bone
+ @type deformDist: Float
+ @ivar length: The length of the bone. This cannot be set.
+ @type length: Float
+ @ivar headRadius: The radius of this bones head (used for envalope bones)
+ @type headRadius: Float
+ @ivar tailRadius: The radius of this bones head (used for envalope bones)
+ @type tailRadius: Float
+ """
+
+ def hasParent():
+ """
+ Whether or not this bone has a parent
+ @rtype: Bool
+ """
+
+ def clearParent():
+ """
+ Set the parent to None
+ @rtype: None
+ """
diff --git a/source/blender/python/api2_2x/doc/BGL.py b/source/blender/python/api2_2x/doc/BGL.py
new file mode 100644
index 00000000000..661042f341b
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/BGL.py
@@ -0,0 +1,1778 @@
+# Blender.BGL module (OpenGL wrapper)
+
+"""
+The Blender.BGL submodule (the OpenGL wrapper).
+
+B{New}: some GLU functions: L{gluLookAt}, etc.
+
+The Blender.BGL submodule
+=========================
+
+This module wraps OpenGL constants and functions, making them available from
+within Blender Python.
+
+The complete list can be retrieved from the module itself, by listing its
+contents: dir(Blender.BGL). A simple search on the net can point to more
+than enough material to teach OpenGL programming, from books to many
+collections of tutorials.
+
+The "red book": "I{OpenGL Programming Guide: The Official Guide to Learning
+OpenGL}" and the online NeHe tutorials are two of the best resources.
+
+Example::
+ import Blender
+ from Blender.BGL import *
+ from Blender import Draw
+ R = G = B = 0
+ A = 1
+ title = "Testing BGL + Draw"
+ instructions = "Use mouse buttons or wheel to change the background color."
+ quitting = " Press ESC or q to quit."
+ len1 = Draw.GetStringWidth(title)
+ len2 = Draw.GetStringWidth(instructions + quitting)
+ #
+ def show_win():
+ glClearColor(R,G,B,A) # define color used to clear buffers
+ glClear(GL_COLOR_BUFFER_BIT) # use it to clear the color buffer
+ glColor3f(0.35,0.18,0.92) # define default color
+ glBegin(GL_POLYGON) # begin a vertex data list
+ glVertex2i(165, 158)
+ glVertex2i(252, 55)
+ glVertex2i(104, 128)
+ glEnd()
+ glColor3f(0.4,0.4,0.4) # change default color
+ glRecti(40, 96, 60+len1, 113)
+ glColor3f(1,1,1)
+ glRasterPos2i(50,100) # move cursor to x = 50, y = 100
+ Draw.Text(title) # draw this text there
+ glRasterPos2i(350,40) # move cursor again
+ Draw.Text(instructions + quitting) # draw another msg
+ glBegin(GL_LINE_LOOP) # begin a vertex-data list
+ glVertex2i(46,92)
+ glVertex2i(120,92)
+ glVertex2i(120,115)
+ glVertex2i(46,115)
+ glEnd() # close this list
+ #
+ def ev(evt, val): # event callback for Draw.Register()
+ global R,G,B,A # ... it handles input events
+ if evt == Draw.ESCKEY or evt == Draw.QKEY:
+ Draw.Exit() # this quits the script
+ elif not val: return
+ elif evt == Draw.LEFTMOUSE: R = 1 - R
+ elif evt == Draw.MIDDLEMOUSE: G = 1 - G
+ elif evt == Draw.RIGHTMOUSE: B = 1 - B
+ elif evt == Draw.WHEELUPMOUSE:
+ R += 0.1
+ if R > 1: R = 1
+ elif evt == Draw.WHEELDOWNMOUSE:
+ R -= 0.1
+ if R < 0: R = 0
+ else:
+ return # don't redraw if nothing changed
+ Draw.Redraw(1) # make changes visible.
+ #
+ Draw.Register(show_win, ev, None) # start the main loop
+
+@note: you can use the L{Image} module and L{Image.Image} BPy object to load
+ and set textures. See L{Image.Image.glLoad} and L{Image.Image.glFree},
+ for example.
+@see: U{www.opengl.org}
+@see: U{nehe.gamedev.net}
+"""
+
+def glAccum(op, value):
+ """
+ Operate on the accumulation buffer
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/accum.html}
+
+ @type op: Enumerated constant
+ @param op: The accumulation buffer operation.
+ @type value: float
+ @param value: a value used in the accumulation buffer operation.
+ """
+
+def glAlphaFunc(func, ref):
+ """
+ Specify the alpha test function
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/alphafunc.html}
+
+ @type func: Enumerated constant
+ @param func: Specifies the alpha comparison function.
+ @type ref: float
+ @param ref: The reference value that incoming alpha values are compared to.
+ Clamped between 0 and 1.
+ """
+
+def glAreTexturesResident(n, textures, residences):
+ """
+ Determine if textures are loaded in texture memory
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/aretexturesresident.html}
+
+ @type n: int
+ @param n: Specifies the number of textures to be queried.
+ @type textures: Buffer object I{type GL_INT}
+ @param textures: Specifies an array containing the names of the textures to be queried
+ @type residences: Buffer object I{type GL_INT}(boolean)
+ @param residences: An array in which the texture residence status in returned.The residence status of a
+ texture named by an element of textures is returned in the corresponding element of residences.
+ """
+
+def glBegin(mode):
+ """
+ Delimit the vertices of a primitive or a group of like primatives
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/begin.html}
+
+ @type mode: Enumerated constant
+ @param mode: Specifies the primitive that will be create from vertices between glBegin and
+ glEnd.
+ """
+
+def glBindTexture(target, texture):
+ """
+ Bind a named texture to a texturing target
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/bindtexture.html}
+
+ @type target: Enumerated constant
+ @param target: Specifies the target to which the texture is bound.
+ @type texture: unsigned int
+ @param texture: Specifies the name of a texture.
+ """
+
+def glBitmap(width, height, xorig, yorig, xmove, ymove, bitmap):
+ """
+ Draw a bitmap
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/bitmap.html}
+
+ @type width, height: int
+ @param width, height: Specify the pixel width and height of the bitmap image.
+ @type xorig,yorig: float
+ @param xorig,yorig: Specify the location of the origin in the bitmap image. The origin is measured
+ from the lower left corner of the bitmap, with right and up being the positive axes.
+ @type xmove,ymove: float
+ @param xmove,ymove: Specify the x and y offsets to be added to the current raster position after
+ the bitmap is drawn.
+ @type bitmap: Buffer object I{type GL_BYTE}
+ @param bitmap: Specifies the address of the bitmap image.
+ """
+
+def glBlendFunc(sfactor, dfactor):
+ """
+ Specify pixel arithmetic
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/blendfunc.html}
+
+ @type sfactor: Enumerated constant
+ @param sfactor: Specifies how the red, green, blue, and alpha source blending factors are
+ computed.
+ @type dfactor: Enumerated constant
+ @param dfactor: Specifies how the red, green, blue, and alpha destination blending factors are
+ computed.
+ """
+
+def glCallList(list):
+ """
+ Execute a display list
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/calllist.html}
+
+ @type list: unsigned int
+ @param list: Specifies the integer name of the display list to be executed.
+ """
+
+def glCallLists(n, type, lists):
+ """
+ Execute a list of display lists
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/calllists.html}
+
+ @type n: int
+ @param n: Specifies the number of display lists to be executed.
+ @type type: Enumerated constant
+ @param type: Specifies the type of values in lists.
+ @type lists: Buffer object
+ @param lists: Specifies the address of an array of name offsets in the display list.
+ The pointer type is void because the offsets can be bytes, shorts, ints, or floats,
+ depending on the value of type.
+ """
+
+def glClear(mask):
+ """
+ Clear buffers to preset values
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/clear.html}
+
+ @type mask: Enumerated constant(s)
+ @param mask: Bitwise OR of masks that indicate the buffers to be cleared.
+ """
+
+def glClearAccum(red, green, blue, alpha):
+ """
+ Specify clear values for the accumulation buffer
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/clearaccum.html}
+
+ @type red,green,blue,alpha: float
+ @param red,green,blue,alpha: Specify the red, green, blue, and alpha values used when the
+ accumulation buffer is cleared. The initial values are all 0.
+ """
+
+def glClearColor(red, green, blue, alpha):
+ """
+ Specify clear values for the color buffers
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/clearcolor.html}
+
+ @type red,green,blue,alpha: float
+ @param red,green,blue,alpha: Specify the red, green, blue, and alpha values used when the
+ color buffers are cleared. The initial values are all 0.
+ """
+
+def glClearDepth(depth):
+ """
+ Specify the clear value for the depth buffer
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/cleardepth.html}
+
+ @type depth: int
+ @param depth: Specifies the depth value used when the depth buffer is cleared.
+ The initial value is 1.
+ """
+
+def glClearIndex(c):
+ """
+ Specify the clear value for the color index buffers
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/clearindex.html}
+
+ @type c: float
+ @param c: Specifies the index used when the color index buffers are cleared.
+ The initial value is 0.
+ """
+
+def glClearStencil(s):
+ """
+ Specify the clear value for the stencil buffer
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/clearstencil.html}
+
+ @type s: int
+ @param s: Specifies the index used when the stencil buffer is cleared. The initial value is 0.
+ """
+
+def glClipPlane (plane, equation):
+ """
+ Specify a plane against which all geometry is clipped
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/clipplane.html}
+
+ @type plane: Enumerated constant
+ @param plane: Specifies which clipping plane is being positioned.
+ @type equation: Buffer object I{type GL_FLOAT}(double)
+ @param equation: Specifies the address of an array of four double- precision floating-point
+ values. These values are interpreted as a plane equation.
+ """
+
+def glColor (red, green, blue, alpha):
+ """
+ B{glColor3b, glColor3d, glColor3f, glColor3i, glColor3s, glColor3ub, glColor3ui, glColor3us,
+ glColor4b, glColor4d, glColor4f, glColor4i, glColor4s, glColor4ub, glColor4ui, glColor4us,
+ glColor3bv, glColor3dv, glColor3fv, glColor3iv, glColor3sv, glColor3ubv, glColor3uiv,
+ glColor3usv, glColor4bv, glColor4dv, glColor4fv, glColor4iv, glColor4sv, glColor4ubv,
+ glColor4uiv, glColor4usv}
+
+ Set a new color.
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/color.html}
+
+ @type red,green,blue,alpha: Depends on function prototype.
+ @param red,green,blue: Specify new red, green, and blue values for the current color.
+ @param alpha: Specifies a new alpha value for the current color. Included only in the
+ four-argument glColor4 commands. (With '4' colors only)
+ """
+
+def glColorMask(red, green, blue, alpha):
+ """
+ Enable and disable writing of frame buffer color components
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/colormask.html}
+
+ @type red,green,blue,alpha: int (boolean)
+ @param red,green,blue,alpha: Specify whether red, green, blue, and alpha can or cannot be
+ written into the frame buffer. The initial values are all GL_TRUE, indicating that the
+ color components can be written.
+ """
+
+def glColorMaterial(face, mode):
+ """
+ Cause a material color to track the current color
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/colormaterial.html}
+
+ @type face: Enumerated constant
+ @param face: Specifies whether front, back, or both front and back material parameters should
+ track the current color.
+ @type mode: Enumerated constant
+ @param mode: Specifies which of several material parameters track the current color.
+ """
+
+def glCopyPixels(x, y, width, height, type):
+ """
+ Copy pixels in the frame buffer
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/copypixels.html}
+
+ @type x,y: int
+ @param x,y: Specify the window coordinates of the lower left corner of the rectangular
+ region of pixels to be copied.
+ @type width, height: int
+ @param width,height: Specify the dimensions of the rectangular region of pixels to be copied.
+ Both must be non-negative.
+ @type type: Enumerated constant
+ @param type: Specifies whether color values, depth values, or stencil values are to be copied.
+ """
+
+def glCullFace(mode):
+ """
+ Specify whether front- or back-facing facets can be culled
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/cullface.html}
+
+ @type mode: Enumerated constant
+ @param mode: Specifies whether front- or back-facing facets are candidates for culling.
+ """
+
+def glDeleteLists(list, range):
+ """
+ Delete a contiguous group of display lists
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/deletelists.html}
+
+ @type list: unsigned int
+ @param list: Specifies the integer name of the first display list to delete
+ @type range: int
+ @param range: Specifies the number of display lists to delete
+ """
+
+def glDeleteTextures(n, textures):
+ """
+ Delete named textures
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/deletetextures.html}
+
+ @type n: int
+ @param n: Specifies the number of textures to be deleted
+ @type textures: Buffer I{GL_INT}
+ @param textures: Specifies an array of textures to be deleted
+ """
+
+def glDepthFunc(func):
+ """
+ Specify the value used for depth buffer comparisons
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/depthfunc.html}
+
+ @type func: Enumerated constant
+ @param func: Specifies the depth comparison function.
+ """
+
+def glDepthMask(flag):
+ """
+ Enable or disable writing into the depth buffer
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/depthmask.html}
+
+ @type flag: int (boolean)
+ @param flag: Specifies whether the depth buffer is enabled for writing. If flag is GL_FALSE,
+ depth buffer writing is disabled. Otherwise, it is enabled. Initially, depth buffer
+ writing is enabled.
+ """
+
+def glDepthRange(zNear, zFar):
+ """
+ Specify mapping of depth values from normalized device coordinates to window coordinates
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/depthrange.html}
+
+ @type zNear: int
+ @param zNear: Specifies the mapping of the near clipping plane to window coordinates.
+ The initial value is 0.
+ @type zFar: int
+ @param zFar: Specifies the mapping of the far clipping plane to window coordinates.
+ The initial value is 1.
+ """
+
+def glDisable(cap):
+ """
+ Disable server-side GL capabilities
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/enable.html}
+
+ @type cap: Enumerated constant
+ @param cap: Specifies a symbolic constant indicating a GL capability.
+ """
+
+def glDrawBuffer(mode):
+ """
+ Specify which color buffers are to be drawn into
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/drawbuffer.html}
+
+ @type mode: Enumerated constant
+ @param mode: Specifies up to four color buffers to be drawn into.
+ """
+
+def glDrawPixels(width, height, format, type, pixels):
+ """
+ Write a block of pixels to the frame buffer
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/drawpixels.html}
+
+ @type width, height: int
+ @param width, height: Specify the dimensions of the pixel rectangle to be
+ written into the frame buffer.
+ @type format: Enumerated constant
+ @param format: Specifies the format of the pixel data.
+ @type type: Enumerated constant
+ @param type: Specifies the data type for pixels.
+ @type pixels: Buffer object
+ @param pixels: Specifies a pointer to the pixel data.
+ """
+
+def glEdgeFlag (flag):
+ """
+ B{glEdgeFlag, glEdgeFlagv}
+
+ Flag edges as either boundary or non-boundary
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/edgeflag.html}
+
+ @type flag: Depends of function prototype
+ @param flag: Specifies the current edge flag value.The initial value is GL_TRUE.
+ """
+
+def glEnable(cap):
+ """
+ Enable server-side GL capabilities
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/enable.html}
+
+ @type cap: Enumerated constant
+ @param cap: Specifies a symbolic constant indicating a GL capability.
+ """
+
+def glEnd():
+ """
+ Delimit the vertices of a primitive or group of like primitives
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/begin.html}
+ """
+
+def glEndList():
+ """
+ Create or replace a display list
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/newlist.html}
+ """
+
+def glEvalCoord (u,v):
+ """
+ B{glEvalCoord1d, glEvalCoord1f, glEvalCoord2d, glEvalCoord2f, glEvalCoord1dv, glEvalCoord1fv,
+ glEvalCoord2dv, glEvalCoord2fv}
+
+ Evaluate enabled one- and two-dimensional maps
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/evalcoord.html}
+
+ @type u: Depends on function prototype.
+ @param u: Specifies a value that is the domain coordinate u to the basis function defined
+ in a previous glMap1 or glMap2 command. If the function prototype ends in 'v' then
+ u specifies a pointer to an array containing either one or two domain coordinates. The first
+ coordinate is u. The second coordinate is v, which is present only in glEvalCoord2 versions.
+ @type v: Depends on function prototype. (only with '2' prototypes)
+ @param v: Specifies a value that is the domain coordinate v to the basis function defined
+ in a previous glMap2 command. This argument is not present in a glEvalCoord1 command.
+ """
+
+def glEvalMesh (mode, i1, i2):
+ """
+ B{glEvalMesh1 or glEvalMesh2}
+
+ Compute a one- or two-dimensional grid of points or lines
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/evalmesh.html}
+
+ @type mode: Enumerated constant
+ @param mode: In glEvalMesh1, specifies whether to compute a one-dimensional
+ mesh of points or lines.
+ @type i1, i2: int
+ @param i1, i2: Specify the first and last integer values for the grid domain variable i.
+ """
+
+def glEvalPoint (i, j):
+ """
+ B{glEvalPoint1 and glEvalPoint2}
+
+ Generate and evaluate a single point in a mesh
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/evalpoint.html}
+
+ @type i: int
+ @param i: Specifies the integer value for grid domain variable i.
+ @type j: int (only with '2' prototypes)
+ @param j: Specifies the integer value for grid domain variable j (glEvalPoint2 only).
+ """
+
+def glFeedbackBuffer (size, type, buffer):
+ """
+ Controls feedback mode
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/feedbackbuffer.html}
+
+ @type size: int
+ @param size:Specifies the maximum number of values that can be written into buffer.
+ @type type: Enumerated constant
+ @param type:Specifies a symbolic constant that describes the information that
+ will be returned for each vertex.
+ @type buffer: Buffer object I{GL_FLOAT}
+ @param buffer: Returns the feedback data.
+ """
+
+def glFinish():
+ """
+ Block until all GL execution is complete
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/finish.html}
+ """
+
+def glFlush():
+ """
+ Force Execution of GL commands in finite time
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/flush.html}
+ """
+
+def glFog (pname, param):
+ """
+ B{glFogf, glFogi, glFogfv, glFogiv}
+
+ Specify fog parameters
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/fog.html}
+
+ @type pname: Enumerated constant
+ @param pname: Specifies a single-valued fog parameter. If the function prototype
+ ends in 'v' specifies a fog parameter.
+ @type param: Depends on function prototype.
+ @param param: Specifies the value or values to be assigned to pname. GL_FOG_COLOR
+ requires an array of four values. All other parameters accept an array containing
+ only a single value.
+ """
+
+def glFrontFace(mode):
+ """
+ Define front- and back-facing polygons
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/frontface.html}
+
+ @type mode: Enumerated constant
+ @param mode: Specifies the orientation of front-facing polygons.
+ """
+
+def glFrustum(left, right, bottom, top, zNear, zFar):
+ """
+ Multiply the current matrix by a perspective matrix
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/frustum.html}
+
+ @type left, right: double (float)
+ @param left, right: Specify the coordinates for the left and right vertical
+ clipping planes.
+ @type top, bottom: double (float)
+ @param top, bottom: Specify the coordinates for the bottom and top horizontal
+ clipping planes.
+ @type zNear, zFar: double (float)
+ @param zNear, zFar: Specify the distances to the near and far depth clipping planes.
+ Both distances must be positive.
+ """
+
+def glGenLists(range):
+ """
+ Generate a contiguous set of empty display lists
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/genlists.html}
+
+ @type range: int
+ @param range: Specifies the number of contiguous empty display lists to be generated.
+ """
+
+def glGenTextures(n, textures):
+ """
+ Generate texture names
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/gentextures.html}
+
+ @type n: int
+ @param n: Specifies the number of textures name to be generated.
+ @type textures: Buffer object I{type GL_INT}
+ @param textures: Specifies an array in which the generated textures names are stored.
+ """
+
+def glGet (pname, param):
+ """
+ B{glGetBooleanv, glGetfloatv, glGetFloatv, glGetIntegerv}
+
+ Return the value or values of a selected parameter
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/get.html}
+
+ @type pname: Enumerated constant
+ @param pname: Specifies the parameter value to be returned.
+ @type param: Depends on function prototype.
+ @param param: Returns the value or values of the specified parameter.
+ """
+
+def glGetClipPlane(plane, equation):
+ """
+ Return the coefficients of the specified clipping plane
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/getclipplane.html}
+
+ @type plane: Enumerated constant
+ @param plane: Specifies a clipping plane. The number of clipping planes depends on the
+ implementation, but at least six clipping planes are supported. They are identified by
+ symbolic names of the form GL_CLIP_PLANEi where 0 < i < GL_MAX_CLIP_PLANES.
+ @type equation: Buffer object I{type GL_FLOAT}
+ @param equation: Returns four float (double)-precision values that are the coefficients of the
+ plane equation of plane in eye coordinates. The initial value is (0, 0, 0, 0).
+ """
+
+def glGetError():
+ """
+ Return error information
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/geterror.html}
+ """
+
+def glGetLight (light, pname, params):
+ """
+ B{glGetLightfv and glGetLightiv}
+
+ Return light source parameter values
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/getlight.html}
+
+ @type light: Enumerated constant
+ @param light: Specifies a light source. The number of possible lights depends on the
+ implementation, but at least eight lights are supported. They are identified by symbolic
+ names of the form GL_LIGHTi where 0 < i < GL_MAX_LIGHTS.
+ @type pname: Enumerated constant
+ @param pname: Specifies a light source parameter for light.
+ @type params: Buffer object. Depends on function prototype.
+ @param params: Returns the requested data.
+ """
+
+def glGetMap (target, query, v):
+ """
+ B{glGetMapdv, glGetMapfv, glGetMapiv}
+
+ Return evaluator parameters
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/getmap.html}
+
+ @type target: Enumerated constant
+ @param target: Specifies the symbolic name of a map.
+ @type query: Enumerated constant
+ @param query: Specifies which parameter to return.
+ @type v: Buffer object. Depends on function prototype.
+ @param v: Returns the requested data.
+ """
+
+def glGetMaterial (face, pname, params):
+ """
+ B{glGetMaterialfv, glGetMaterialiv}
+
+ Return material parameters
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/getmaterial.html}
+
+ @type face: Enumerated constant
+ @param face: Specifies which of the two materials is being queried.
+ representing the front and back materials, respectively.
+ @type pname: Enumerated constant
+ @param pname: Specifies the material parameter to return.
+ @type params: Buffer object. Depends on function prototype.
+ @param params: Returns the requested data.
+ """
+
+def glGetPixelMap (map, values):
+ """
+ B{glGetPixelMapfv, glGetPixelMapuiv, glGetPixelMapusv}
+
+ Return the specified pixel map
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/getpixelmap.html}
+
+ @type map: Enumerated constant
+ @param map: Specifies the name of the pixel map to return.
+ @type values: Buffer object. Depends on function prototype.
+ @param values: Returns the pixel map contents.
+ """
+
+def glGetPolygonStipple(mask):
+ """
+ Return the polygon stipple pattern
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/getpolygonstipple.html}
+
+ @type mask: Buffer object I{type GL_BYTE}
+ @param mask: Returns the stipple pattern. The initial value is all 1's.
+ """
+
+def glGetString(name):
+ """
+ Return a string describing the current GL connection
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/getstring.html}
+
+ @type name: Enumerated constant
+ @param name: Specifies a symbolic constant.
+
+ """
+
+def glGetTexEnv (target, pname, params):
+ """
+ B{glGetTexEnvfv, glGetTexEnviv}
+
+ Return texture environment parameters
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/gettexenv.html}
+
+ @type target: Enumerated constant
+ @param target: Specifies a texture environment. Must be GL_TEXTURE_ENV.
+ @type pname: Enumerated constant
+ @param pname: Specifies the symbolic name of a texture environment parameter.
+ @type params: Buffer object. Depends on function prototype.
+ @param params: Returns the requested data.
+ """
+
+def glGetTexGen (coord, pname, params):
+ """
+ B{glGetTexGendv, glGetTexGenfv, glGetTexGeniv}
+
+ Return texture coordinate generation parameters
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/gettexgen.html}
+
+ @type coord: Enumerated constant
+ @param coord: Specifies a texture coordinate.
+ @type pname: Enumerated constant
+ @param pname: Specifies the symbolic name of the value(s) to be returned.
+ @type params: Buffer object. Depends on function prototype.
+ @param params: Returns the requested data.
+ """
+
+def glGetTexImage(target, level, format, type, pixels):
+ """
+ Return a texture image
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/getteximage.html}
+
+ @type target: Enumerated constant
+ @param target: Specifies which texture is to be obtained.
+ @type level: int
+ @param level: Specifies the level-of-detail number of the desired image.
+ Level 0 is the base image level. Level n is the nth mipmap reduction image.
+ @type format: Enumerated constant
+ @param format: Specifies a pixel format for the returned data.
+ @type type: Enumerated constant
+ @param type: Specifies a pixel type for the returned data.
+ @type pixels: Buffer object.
+ @param pixels: Returns the texture image. Should be a pointer to an array of the
+ type specified by type
+ """
+
+def glGetTexLevelParameter (target, level, pname, params):
+ """
+ B{glGetTexLevelParameterfv, glGetTexLevelParameteriv}
+
+ return texture parameter values for a specific level of detail
+ @see: U{opengl.org/developers/documentation/man_pages/hardcopy/GL/html/gl/gettexlevelparameter.html}
+
+ @type target: Enumerated constant
+ @param target: Specifies the symbolic name of the target texture.
+ @type level: int
+ @param level: Specifies the level-of-detail number of the desired image.
+ Level 0 is the base image level. Level n is the nth mipmap reduction image.
+ @type pname: Enumerated constant
+ @param pname: Specifies the symbolic name of a texture parameter.
+ @type params: Buffer object. Depends on function prototype.
+ @param params: Returns the requested data.
+ """
+
+def glGetTexParameter (target, pname, params):
+ """
+ B{glGetTexParameterfv, glGetTexParameteriv}
+
+ Return texture parameter values
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/gettexparameter.html}
+
+ @type target: Enumerated constant
+ @param target: Specifies the symbolic name of the target texture.
+ @type pname: Enumerated constant
+ @param pname: Specifies the symbolic name the target texture.
+ @type params: Buffer object. Depends on function prototype.
+ @param params: Returns the texture parameters.
+ """
+
+def glHint(target, mode):
+ """
+ Specify implementation-specific hints
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/hint.html}
+
+ @type target: Enumerated constant
+ @param target: Specifies a symbolic constant indicating the behavior to be
+ controlled.
+ @type mode: Enumerated constant
+ @param mode: Specifies a symbolic constant indicating the desired behavior.
+ """
+
+def glIndex (c):
+ """
+ B{glIndexd, glIndexf, glIndexi, glIndexs, glIndexdv, glIndexfv, glIndexiv, glIndexsv}
+
+ Set the current color index
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/index_.html}
+
+ @type c: Buffer object. Depends on function prototype.
+ @param c: Specifies a pointer to a one element array that contains the new value for
+ the current color index.
+ """
+
+def glInitNames():
+ """
+ Initialize the name stack
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/initnames.html}
+ """
+
+def glIsEnabled(cap):
+ """
+ Test whether a capability is enabled
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/isenabled.html}
+
+ @type cap: Enumerated constant
+ @param cap: Specifies a constant representing a GL capability.
+ """
+
+def glIsList(list):
+ """
+ Determine if a name corresponds to a display-list
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/islist.html}
+
+ @type list: unsigned int
+ @param list: Specifies a potential display-list name.
+ """
+
+def glIsTexture(texture):
+ """
+ Determine if a name corresponds to a texture
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/istexture.html}
+
+ @type texture: unsigned int
+ @param texture: Specifies a value that may be the name of a texture.
+ """
+
+def glLight (light, pname, param):
+ """
+ B{glLightf,glLighti, glLightfv, glLightiv}
+
+ Set the light source parameters
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/light.html}
+
+ @type light: Enumerated constant
+ @param light: Specifies a light. The number of lights depends on the implementation,
+ but at least eight lights are supported. They are identified by symbolic names of the
+ form GL_LIGHTi where 0 < i < GL_MAX_LIGHTS.
+ @type pname: Enumerated constant
+ @param pname: Specifies a single-valued light source parameter for light.
+ @type param: Depends on function prototype.
+ @param param: Specifies the value that parameter pname of light source light will be set to.
+ If function prototype ends in 'v' specifies a pointer to the value or values that
+ parameter pname of light source light will be set to.
+ """
+
+def glLightModel (pname, param):
+ """
+ B{glLightModelf, glLightModeli, glLightModelfv, glLightModeliv}
+
+ Set the lighting model parameters
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/lightmodel.html}
+
+ @type pname: Enumerated constant
+ @param pname: Specifies a single-value light model parameter.
+ @type param: Depends on function prototype.
+ @param param: Specifies the value that param will be set to. If function prototype ends in 'v'
+ specifies a pointer to the value or values that param will be set to.
+ """
+
+def glLineStipple(factor, pattern):
+ """
+ Specify the line stipple pattern
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/linestipple.html}
+
+ @type factor: int
+ @param factor: Specifies a multiplier for each bit in the line stipple pattern.
+ If factor is 3, for example, each bit in the pattern is used three times before
+ the next bit in the pattern is used. factor is clamped to the range [1, 256] and
+ defaults to 1.
+ @type pattern: unsigned short int
+ @param pattern: Specifies a 16-bit integer whose bit pattern determines which fragments
+ of a line will be drawn when the line is rasterized. Bit zero is used first; the default
+ pattern is all 1's.
+ """
+
+def glLineWidth(width):
+ """
+ Specify the width of rasterized lines.
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/linewidth.html}
+
+ @type width: float
+ @param width: Specifies the width of rasterized lines. The initial value is 1.
+ """
+
+def glListBase(base):
+ """
+ Set the display-list base for glCallLists
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/listbase.html}
+
+ @type base: unsigned int
+ @param base: Specifies an integer offset that will be added to glCallLists
+ offsets to generate display-list names. The initial value is 0.
+ """
+
+def glLoadIdentity():
+ """
+ Replace the current matrix with the identity matrix
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/loadidentity.html}
+ """
+
+def glLoadMatrix (m):
+ """
+ B{glLoadMatrixd, glLoadMatixf}
+
+ Replace the current matrix with the specified matrix
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/loadmatrix.html}
+
+ @type m: Buffer object. Depends on function prototype.
+ @param m: Specifies a pointer to 16 consecutive values, which are used as the elements
+ of a 4x4 column-major matrix.
+ """
+
+def glLoadName(name):
+ """
+ Load a name onto the name stack.
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/loadname.html}
+
+ @type name: unsigned int
+ @param name: Specifies a name that will replace the top value on the name stack.
+ """
+
+def glLogicOp(opcode):
+ """
+ Specify a logical pixel operation for color index rendering
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/logicop.html}
+
+ @type opcode: Enumerated constant
+ @param opcode: Specifies a symbolic constant that selects a logical operation.
+ """
+
+def glMap1 (target, u1, u2, stride, order, points):
+ """
+ B{glMap1d, glMap1f}
+
+ Define a one-dimensional evaluator
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/map1.html}
+
+ @type target: Enumerated constant
+ @param target: Specifies the kind of values that are generated by the evaluator.
+ @type u1, u2: Depends on function prototype.
+ @param u1,u2: Specify a linear mapping of u, as presented to glEvalCoord1, to ^, t
+ he variable that is evaluated by the equations specified by this command.
+ @type stride: int
+ @param stride: Specifies the number of floats or float (double)s between the beginning
+ of one control point and the beginning of the next one in the data structure
+ referenced in points. This allows control points to be embedded in arbitrary data
+ structures. The only constraint is that the values for a particular control point must
+ occupy contiguous memory locations.
+ @type order: int
+ @param order: Specifies the number of control points. Must be positive.
+ @type points: Buffer object. Depends on function prototype.
+ @param points: Specifies a pointer to the array of control points.
+ """
+
+def glMap2 (target, u1, u2, ustride, uorder, v1, v2, vstride, vorder, points):
+ """
+ B{glMap2d, glMap2f}
+
+ Define a two-dimensional evaluator
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/map2.html}
+
+ @type target: Enumerated constant
+ @param target: Specifies the kind of values that are generated by the evaluator.
+ @type u1, u2: Depends on function prototype.
+ @param u1,u2: Specify a linear mapping of u, as presented to glEvalCoord2, to ^, t
+ he variable that is evaluated by the equations specified by this command. Initially
+ u1 is 0 and u2 is 1.
+ @type ustride: int
+ @param ustride: Specifies the number of floats or float (double)s between the beginning
+ of control point R and the beginning of control point R ij, where i and j are the u
+ and v control point indices, respectively. This allows control points to be embedded
+ in arbitrary data structures. The only constraint is that the values for a particular
+ control point must occupy contiguous memory locations. The initial value of ustride is 0.
+ @type uorder: int
+ @param uorder: Specifies the dimension of the control point array in the u axis.
+ Must be positive. The initial value is 1.
+ @type v1, v2: Depends on function prototype.
+ @param v1, v2: Specify a linear mapping of v, as presented to glEvalCoord2, to ^,
+ one of the two variables that are evaluated by the equations specified by this command.
+ Initially, v1 is 0 and v2 is 1.
+ @type vstride: int
+ @param vstride: Specifies the number of floats or float (double)s between the beginning of control
+ point R and the beginning of control point R ij, where i and j are the u and v control
+ point(indices, respectively. This allows control points to be embedded in arbitrary data
+ structures. The only constraint is that the values for a particular control point must
+ occupy contiguous memory locations. The initial value of vstride is 0.
+ @type vorder: int
+ @param vorder: Specifies the dimension of the control point array in the v axis.
+ Must be positive. The initial value is 1.
+ @type points: Buffer object. Depends on function prototype.
+ @param points: Specifies a pointer to the array of control points.
+ """
+
+def glMapGrid (un, u1,u2 ,vn, v1, v2):
+ """
+ B{glMapGrid1d, glMapGrid1f, glMapGrid2d, glMapGrid2f}
+
+ Define a one- or two-dimensional mesh
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/mapgrid.html}
+
+ @type un: int
+ @param un: Specifies the number of partitions in the grid range interval
+ [u1, u2]. Must be positive.
+ @type u1, u2: Depends on function prototype.
+ @param u1, u2: Specify the mappings for integer grid domain values i=0 and i=un.
+ @type vn: int
+ @param vn: Specifies the number of partitions in the grid range interval [v1, v2]
+ (glMapGrid2 only).
+ @type v1, v2: Depends on function prototype.
+ @param v1, v2: Specify the mappings for integer grid domain values j=0 and j=vn
+ (glMapGrid2 only).
+ """
+
+def glMaterial (face, pname, params):
+ """
+ Specify material parameters for the lighting model.
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/material.html}
+
+ @type face: Enumerated constant
+ @param face: Specifies which face or faces are being updated. Must be one of:
+ @type pname: Enumerated constant
+ @param pname: Specifies the single-valued material parameter of the face
+ or faces that is being updated. Must be GL_SHININESS.
+ @type params: int
+ @param params: Specifies the value that parameter GL_SHININESS will be set to.
+ If function prototype ends in 'v' specifies a pointer to the value or values that
+ pname will be set to.
+ """
+
+def glMatrixMode(mode):
+ """
+ Specify which matrix is the current matrix.
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/matrixmode.html}
+
+ @type mode: Enumerated constant
+ @param mode: Specifies which matrix stack is the target for subsequent matrix operations.
+ """
+
+def glMultMatrix (m):
+ """
+ B{glMultMatrixd, glMultMatrixf}
+
+ Multiply the current matrix with the specified matrix
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/multmatrix.html}
+
+ @type m: Buffer object. Depends on function prototype.
+ @param m: Points to 16 consecutive values that are used as the elements of a 4x4 column
+ major matrix.
+ """
+
+def glNewList(list, mode):
+ """
+ Create or replace a display list
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/newlist.html}
+
+ @type list: unsigned int
+ @param list: Specifies the display list name
+ @type mode: Enumerated constant
+ @param mode: Specifies the compilation mode.
+ """
+
+def glNormal3 (nx, ny, nz, v):
+ """
+ B{Normal3b, Normal3bv, Normal3d, Normal3dv, Normal3f, Normal3fv, Normal3i, Normal3iv,
+ Normal3s, Normal3sv}
+
+ Set the current normal vector
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/normal.html}
+
+ @type nx, ny, nz: Depends on function prototype. (non - 'v' prototypes only)
+ @param nx, ny, nz: Specify the x, y, and z coordinates of the new current normal.
+ The initial value of the current normal is the unit vector, (0, 0, 1).
+ @type v: Buffer object. Depends on function prototype. ('v' prototypes)
+ @param v: Specifies a pointer to an array of three elements: the x,y, and z coordinates
+ of the new current normal.
+ """
+
+def glOrtho(left, right, bottom, top, zNear, zFar):
+ """
+ Multiply the current matrix with an orthographic matrix
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/ortho.html}
+
+ @type left, right: double (float)
+ @param left, right: Specify the coordinates for the left and
+ right vertical clipping planes.
+ @type bottom, top: double (float)
+ @param bottom, top: Specify the coordinates for the bottom and top
+ horizontal clipping planes.
+ @type zNear, zFar: double (float)
+ @param zNear, zFar: Specify the distances to the nearer and farther
+ depth clipping planes. These values are negative if the plane is to be behind the viewer.
+ """
+
+def glPassThrough(token):
+ """
+ Place a marker in the feedback buffer
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/passthrough.html}
+
+ @type token: float
+ @param token: Specifies a marker value to be placed in the feedback
+ buffer following a GL_PASS_THROUGH_TOKEN.
+ """
+
+def glPixelMap (map, mapsize, values):
+ """
+ B{glPixelMapfv, glPixelMapuiv, glPixelMapusv}
+
+ Set up pixel transfer maps
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/pixelmap.html}
+
+ @type map: Enumerated constant
+ @param map: Specifies a symbolic map name.
+ @type mapsize: int
+ @param mapsize: Specifies the size of the map being defined.
+ @type values: Buffer object. Depends on function prototype.
+ @param values: Specifies an array of mapsize values.
+ """
+
+def glPixelStore (pname, param):
+ """
+ B{glPixelStoref, glPixelStorei}
+
+ Set pixel storage modes
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/pixelstore.html}
+
+ @type pname: Enumerated constant
+ @param pname: Specifies the symbolic name of the parameter to be set.
+ Six values affect the packing of pixel data into memory.
+ Six more affect the unpacking of pixel data from memory.
+ @type param: Depends on function prototype.
+ @param param: Specifies the value that pname is set to.
+ """
+
+def glPixelTransfer (pname, param):
+ """
+ B{glPixelTransferf, glPixelTransferi}
+
+ Set pixel transfer modes
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/pixeltransfer.html}
+
+ @type pname: Enumerated constant
+ @param pname: Specifies the symbolic name of the pixel transfer parameter to be set.
+ @type param: Depends on function prototype.
+ @param param: Specifies the value that pname is set to.
+ """
+
+def glPixelZoom(xfactor, yfactor):
+ """
+ Specify the pixel zoom factors
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/pixelzoom.html}
+
+ @type xfactor, yfactor: float
+ @param xfactor, yfactor: Specify the x and y zoom factors for pixel write operations.
+ """
+
+def glPointSize(size):
+ """
+ Specify the diameter of rasterized points
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/pointsize.html}
+
+ @type size: float
+ @param size: Specifies the diameter of rasterized points. The initial value is 1.
+ """
+
+def glPolygonMode(face, mode):
+ """
+ Select a polygon rasterization mode
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/polygonmode.html}
+
+ @type face: Enumerated constant
+ @param face: Specifies the polygons that mode applies to.
+ Must be GL_FRONT for front-facing polygons, GL_BACK for back- facing polygons,
+ or GL_FRONT_AND_BACK for front- and back-facing polygons.
+ @type mode: Enumerated constant
+ @param mode: Specifies how polygons will be rasterized.
+ The initial value is GL_FILL for both front- and back- facing polygons.
+ """
+
+def glPolygonOffset(factor, units):
+ """
+ Set the scale and units used to calculate depth values
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/polygonoffset.html}
+
+ @type factor: float
+ @param factor: Specifies a scale factor that is used to create a variable depth
+ offset for each polygon. The initial value is 0.
+ @type units: float
+ @param units: Is multiplied by an implementation-specific value to create a constant
+ depth offset. The initial value is 0.
+ """
+
+def glPolygonStipple(mask):
+ """
+ Set the polygon stippling pattern
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/polygonstipple.html}
+
+ @type mask: Buffer object I{type GL_BYTE}
+ @param mask: Specifies a pointer to a 32x32 stipple pattern that will be unpacked
+ from memory in the same way that glDrawPixels unpacks pixels.
+ """
+
+def glPopAttrib():
+ """
+ Pop the server attribute stack
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/pushattrib.html}
+ """
+
+def glPopClientAttrib():
+ """
+ Pop the client attribute stack
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/pushclientattrib.html}
+ """
+
+def glPopMatrix():
+ """
+ Pop the current matrix stack
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/pushmatrix.html}
+ """
+
+def glPopName():
+ """
+ Pop the name stack
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/pushname.html}
+ """
+
+def glPrioritizeTextures(n, textures, priorities):
+ """
+ Set texture residence priority
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/prioritizetextures.html}
+
+ @type n: int
+ @param n:Specifies the number of textures to be prioritized.
+ @type textures: Buffer I{type GL_INT}
+ @param textures: Specifies an array containing the names of the textures to be prioritized.
+ @type priorities: Buffer I{type GL_FLOAT}
+ @param priorities: Specifies an array containing the texture priorities. A priority given
+ in an element of priorities applies to the texture named by the corresponding element of textures.
+ """
+
+def glPushAttrib(mask):
+ """
+ Push the server attribute stack
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/pushattrib.html}
+
+ @type mask: Enumerated constant(s)
+ @param mask: Specifies a mask that indicates which attributes to save.
+ """
+
+def glPushClientAttrib(mask):
+ """
+ Push the client attribute stack
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/pushclientattrib.html}
+
+ @type mask: Enumerated constant(s)
+ @param mask: Specifies a mask that indicates which attributes to save.
+ """
+
+def glPushMatrix():
+ """
+ Push the current matrix stack
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/pushmatrix.html}
+ """
+
+def glPushName(name):
+ """
+ Push the name stack
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/pushname.html}
+
+ @type name: unsigned int
+ @param name: Specifies a name that will be pushed onto the name stack.
+ """
+
+def glRasterPos (x,y,z,w):
+ """
+ B{glRasterPos2d, glRasterPos2f, glRasterPos2i, glRasterPos2s, glRasterPos3d,
+ glRasterPos3f, glRasterPos3i, glRasterPos3s, glRasterPos4d, glRasterPos4f,
+ glRasterPos4i, glRasterPos4s, glRasterPos2dv, glRasterPos2fv, glRasterPos2iv,
+ glRasterPos2sv, glRasterPos3dv, glRasterPos3fv, glRasterPos3iv, glRasterPos3sv,
+ glRasterPos4dv, glRasterPos4fv, glRasterPos4iv, glRasterPos4sv}
+
+ Specify the raster position for pixel operations
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/rasterpos.html}
+
+ @type x, y, z, w: Depends on function prototype. (z and w for '3' and '4' prototypes only)
+ @param x,y,z,w: Specify the x,y,z, and w object coordinates (if present) for the
+ raster position. If function prototype ends in 'v' specifies a pointer to an array of two,
+ three, or four elements, specifying x, y, z, and w coordinates, respectively.
+ @note:
+ If you are drawing to the 3d view with a Scriptlink of a space handler
+ the zoom level of the panels will scale the glRasterPos by the view matrix.
+ so a X of 10 will not always offset 10 pixels as you would expect.
+
+ To work around this get the scale value of the view matrix and use it to scale your pixel values.
+
+ Workaround::
+
+ import Blender
+ from Blender.BGL import *
+ xval, yval= 100, 40
+ # Get the scale of the view matrix
+ viewMatrix = Buffer(GL_FLOAT, 16)
+ glGetFloatv(GL_MODELVIEW_MATRIX, viewMatrix)
+ f = 1/viewMatrix[0]
+ glRasterPos2f(xval*f, yval*f) # Instead of the usual glRasterPos2i(xval, yval)
+ """
+
+def glReadBuffer(mode):
+ """
+ Select a color buffer source for pixels.
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/readbuffer.html}
+
+ @type mode: Enumerated constant
+ @param mode: Specifies a color buffer.
+ """
+
+def glReadPixels(x, y, width, height, format, type, pixels):
+ """
+ Read a block of pixels from the frame buffer
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/readpixels.html}
+
+ @type x,y: int
+ @param x,y:Specify the window coordinates of the first pixel that is read
+ from the frame buffer. This location is the lower left corner of a rectangular
+ block of pixels.
+ @type width, height: int
+ @param width, height: Specify the dimensions of the pixel rectangle. width and
+ height of one correspond to a single pixel.
+ @type format: Enumerated constant
+ @param format: Specifies the format of the pixel data.
+ @type type: Enumerated constant
+ @param type: Specifies the data type of the pixel data.
+ @type pixels: Buffer object
+ @param pixels: Returns the pixel data.
+ """
+
+def glRect (x1,y1,x2,y2,v1,v2):
+ """
+ B{glRectd, glRectf, glRecti, glRects, glRectdv, glRectfv, glRectiv, glRectsv}
+
+ Draw a rectangle
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/rect.html}
+
+ @type x1, y1: Depends on function prototype. (for non 'v' prototypes only)
+ @param x1, y1: Specify one vertex of a rectangle
+ @type x2, y2: Depends on function prototype. (for non 'v' prototypes only)
+ @param x2, y2: Specify the opposite vertex of the rectangle
+ @type v1, v2: Depends on function prototype. (for 'v' prototypes only)
+ @param v1, v2: Specifies a pointer to one vertex of a rectangle and the pointer
+ to the opposite vertex of the rectangle
+ """
+
+def glRenderMode(mode):
+ """
+ Set rasterization mode
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/rendermode.html}
+
+ @type mode: Enumerated constant
+ @param mode: Specifies the rasterization mode.
+ """
+
+def glRotate (angle, x, y, z):
+ """
+ B{glRotated, glRotatef}
+
+ Multiply the current matrix by a rotation matrix
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/rotate.html}
+
+ @type angle: Depends on function prototype.
+ @param angle: Specifies the angle of rotation in degrees.
+ @type x,y,z: Depends on function prototype.
+ @param x,y,z: Specify the x,y, and z coordinates of a vector respectively.
+ """
+
+def glScale (x,y,z):
+ """
+ B{glScaled, glScalef}
+
+ Multiply the current matrix by a general scaling matrix
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/scale.html}
+
+ @type x,y,z: Depends on function prototype.
+ @param x,y,z: Specify scale factors along the x,y, and z axes, respectively.
+ """
+
+def glScissor(x,y,width,height):
+ """
+ Define the scissor box
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/scissor.html}
+
+ @type x,y: int
+ @param x,y: Specify the lower left corner of the scissor box. Initially (0, 0).
+ @type width, height: int
+ @param width height: Specify the width and height of the scissor box. When a
+ GL context is first attached to a window, width and height are set to the
+ dimensions of that window.
+ """
+
+def glSelectBuffer(size, buffer):
+ """
+ Establish a buffer for selection mode values
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/selectbuffer.html}
+
+ @type size: int
+ @param size: Specifies the size of buffer
+ @type buffer: Buffer I{type GL_INT}
+ @param buffer: Returns the selection data
+ """
+
+def glShadeModel(mode):
+ """
+ Select flat or smooth shading
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/shademodel.html}
+
+ @type mode: Enumerated constant
+ @param mode: Specifies a symbolic value representing a shading technique.
+ """
+
+def glStencilFuc(func, ref, mask):
+ """
+ Set function and reference value for stencil testing
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/stencilfunc.html}
+
+ @type func: Enumerated constant
+ @param func:Specifies the test function.
+ @type ref: int
+ @param ref:Specifies the reference value for the stencil test. ref is clamped to
+ the range [0,2n-1], where n is the number of bitplanes in the stencil buffer.
+ The initial value is 0.
+ @type mask: unsigned int
+ @param mask:Specifies a mask that is ANDed with both the reference value and
+ the stored stencil value when the test is done. The initial value is all 1's.
+ """
+
+def glStencilMask(mask):
+ """
+ Control the writing of individual bits in the stencil planes
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/stencilmask.html}
+
+ @type mask: unsigned int
+ @param mask: Specifies a bit mask to enable and disable writing of individual bits
+ in the stencil planes. Initially, the mask is all 1's.
+ """
+
+def glStencilOp(fail, zfail, zpass):
+ """
+ Set stencil test actions
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/stencilop.html}
+
+ @type fail: Enumerated constant
+ @param fail: Specifies the action to take when the stencil test fails.
+ The initial value is GL_KEEP.
+ @type zfail: Enumerated constant
+ @param zfail: Specifies the stencil action when the stencil test passes, but the
+ depth test fails. zfail accepts the same symbolic constants as fail.
+ The initial value is GL_KEEP.
+ @type zpass: Enumerated constant
+ @param zpass: Specifies the stencil action when both the stencil test and the
+ depth test pass, or when the stencil test passes and either there is no depth
+ buffer or depth testing is not enabled. zpass accepts the same symbolic constants
+ as fail. The initial value is GL_KEEP.
+ """
+
+def glTexCoord (s,t,r,q,v):
+ """
+ B{glTexCoord1d, glTexCoord1f, glTexCoord1i, glTexCoord1s, glTexCoord2d, glTexCoord2f,
+ glTexCoord2i, glTexCoord2s, glTexCoord3d, glTexCoord3f, glTexCoord3i, glTexCoord3s,
+ glTexCoord4d, glTexCoord4f, glTexCoord4i, glTexCoord4s, glTexCoord1dv, glTexCoord1fv,
+ glTexCoord1iv, glTexCoord1sv, glTexCoord2dv, glTexCoord2fv, glTexCoord2iv,
+ glTexCoord2sv, glTexCoord3dv, glTexCoord3fv, glTexCoord3iv, glTexCoord3sv,
+ glTexCoord4dv, glTexCoord4fv, glTexCoord4iv, glTexCoord4sv}
+
+ Set the current texture coordinates
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/texcoord.html}
+
+ @type s,t,r,q: Depends on function prototype. (r and q for '3' and '4' prototypes only)
+ @param s,t,r,q: Specify s, t, r, and q texture coordinates. Not all parameters are
+ present in all forms of the command.
+ @type v: Buffer object. Depends on function prototype. (for 'v' prototypes only)
+ @param v: Specifies a pointer to an array of one, two, three, or four elements,
+ which in turn specify the s, t, r, and q texture coordinates.
+ """
+
+def glTexEnv (target, pname, param):
+ """
+ B{glTextEnvf, glTextEnvi, glTextEnvfv, glTextEnviv}
+
+ Set texture environment parameters
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/texenv.html}
+
+ @type target: Enumerated constant
+ @param target: Specifies a texture environment. Must be GL_TEXTURE_ENV.
+ @type pname: Enumerated constant
+ @param pname: Specifies the symbolic name of a single-valued texture environment
+ parameter. Must be GL_TEXTURE_ENV_MODE.
+ @type param: Depends on function prototype.
+ @param param: Specifies a single symbolic constant. If function prototype ends in 'v'
+ specifies a pointer to a parameter array that contains either a single symbolic
+ constant or an RGBA color
+ """
+
+def glTexGen (coord, pname, param):
+ """
+ B{glTexGend, glTexGenf, glTexGeni, glTexGendv, glTexGenfv, glTexGeniv}
+
+ Control the generation of texture coordinates
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/texgen.html}
+
+ @type coord: Enumerated constant
+ @param coord: Specifies a texture coordinate.
+ @type pname: Enumerated constant
+ @param pname: Specifies the symbolic name of the texture- coordinate generation function.
+ @type param: Depends on function prototype.
+ @param param: Specifies a single-valued texture generation parameter.
+ If function prototype ends in 'v' specifies a pointer to an array of texture
+ generation parameters. If pname is GL_TEXTURE_GEN_MODE, then the array must
+ contain a single symbolic constant. Otherwise, params holds the coefficients
+ for the texture-coordinate generation function specified by pname.
+ """
+
+def glTexImage1D(target, level, internalformat, width, border, format, type, pixels):
+ """
+ Specify a one-dimensional texture image
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/teximage1d.html}
+
+ @type target: Enumerated constant
+ @param target: Specifies the target texture.
+ @type level: int
+ @param level: Specifies the level-of-detail number. Level 0 is the base image level.
+ Level n is the nth mipmap reduction image.
+ @type internalformat: int
+ @param internalformat: Specifies the number of color components in the texture.
+ @type width: int
+ @param width: Specifies the width of the texture image. Must be 2n+2(border) for
+ some integer n. All implementations support texture images that are at least 64
+ texels wide. The height of the 1D texture image is 1.
+ @type border: int
+ @param border: Specifies the width of the border. Must be either 0 or 1.
+ @type format: Enumerated constant
+ @param format: Specifies the format of the pixel data.
+ @type type: Enumerated constant
+ @param type: Specifies the data type of the pixel data.
+ @type pixels: Buffer object.
+ @param pixels: Specifies a pointer to the image data in memory.
+ """
+
+def glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels):
+ """
+ Specify a two-dimensional texture image
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/teximage2d.html}
+
+ @type target: Enumerated constant
+ @param target: Specifies the target texture.
+ @type level: int
+ @param level: Specifies the level-of-detail number. Level 0 is the base image level.
+ Level n is the nth mipmap reduction image.
+ @type internalformat: int
+ @param internalformat: Specifies the number of color components in the texture.
+ @type width: int
+ @param width: Specifies the width of the texture image. Must be 2n+2(border) for
+ some integer n. All implementations support texture images that are at least 64
+ texels wide.
+ @type height: int
+ @param height: Specifies the height of the texture image. Must be 2m+2(border) for
+ some integer m. All implementations support texture images that are at least 64
+ texels high.
+ @type border: int
+ @param border: Specifies the width of the border. Must be either 0 or 1.
+ @type format: Enumerated constant
+ @param format: Specifies the format of the pixel data.
+ @type type: Enumerated constant
+ @param type: Specifies the data type of the pixel data.
+ @type pixels: Buffer object.
+ @param pixels: Specifies a pointer to the image data in memory.
+ """
+
+def glTexParameter (target, pname, param):
+ """
+ B{glTexParameterf, glTexParameteri, glTexParameterfv, glTexParameteriv}
+
+ Set texture parameters
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/texparameter.html}
+
+ @type target: Enumerated constant
+ @param target: Specifies the target texture.
+ @type pname: Enumerated constant
+ @param pname: Specifies the symbolic name of a single-valued texture parameter.
+ @type param: Depends on function prototype.
+ @param param: Specifies the value of pname. If function prototype ends in 'v' specifies
+ a pointer to an array where the value or values of pname are stored.
+ """
+
+def glTranslate (x, y, z):
+ """
+ B{glTranslatef, glTranslated}
+
+ Multiply the current matrix by a translation matrix
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/translate.html}
+
+ @type x,y,z: Depends on function prototype.
+ @param x,y,z: Specify the x, y, and z coordinates of a translation vector.
+ """
+
+def glVertex (x,y,z,w,v):
+ """
+ B{glVertex2d, glVertex2f, glVertex2i, glVertex2s, glVertex3d, glVertex3f, glVertex3i,
+ glVertex3s, glVertex4d, glVertex4f, glVertex4i, glVertex4s, glVertex2dv, glVertex2fv,
+ glVertex2iv, glVertex2sv, glVertex3dv, glVertex3fv, glVertex3iv, glVertex3sv, glVertex4dv,
+ glVertex4fv, glVertex4iv, glVertex4sv}
+
+ Specify a vertex
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/vertex.html}
+
+ @type x,y,z,w: Depends on function prototype (z and w for '3' and '4' prototypes only)
+ @param x,y,z,w: Specify x, y, z, and w coordinates of a vertex. Not all parameters
+ are present in all forms of the command.
+ @type v: Buffer object. Depends of function prototype (for 'v' prototypes only)
+ @param v: Specifies a pointer to an array of two, three, or four elements. The
+ elements of a two-element array are x and y; of a three-element array, x, y, and z;
+ and of a four-element array, x, y, z, and w.
+ """
+
+def glViewport(x,y,width,height):
+ """
+ Set the viewport
+ @see: U{www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/viewport.html}
+
+ @type x,y: int
+ @param x,y: Specify the lower left corner of the viewport rectangle,
+ in pixels. The initial value is (0,0).
+ @type width,height: int
+ @param width,height: Specify the width and height of the viewport. When a GL context
+ is first attached to a window, width and height are set to the dimensions of that window.
+ """
+
+def gluPerspective(fovY, aspect, zNear, zFar):
+ """
+ Set up a perspective projection matrix.
+ @see: U{http://biology.ncsa.uiuc.edu/cgi-bin/infosrch.cgi?cmd=getdoc&coll=0650&db=bks&fname=/SGI_Developer/OpenGL_RM/ch06.html#id5577288}
+
+ @type fovY: double
+ @param fovY: Specifies the field of view angle, in degrees, in the y direction.
+ @type aspect: double
+ @param aspect: Specifies the aspect ratio that determines the field of view in the x direction.
+ The aspect ratio is the ratio of x (width) to y (height).
+ @type zNear: double
+ @param zNear: Specifies the distance from the viewer to the near clipping plane (always positive).
+ @type zFar: double
+ @param zFar: Specifies the distance from the viewer to the far clipping plane (always positive).
+ """
+
+def gluLookAt(eyex, eyey, eyez, centerx, centery, centerz, upx, upy, upz):
+ """
+ Define a viewing transformation
+ @see: U{http://biology.ncsa.uiuc.edu/cgi-bin/infosrch.cgi?cmd=getdoc&coll=0650&db=bks&fname=/SGI_Developer/OpenGL_RM/ch06.html#id5573042}
+
+ @type eyex, eyey, eyez: double
+ @param eyex, eyey, eyez: Specifies the position of the eye point.
+ @type centerx, centery, centerz: double
+ @param centerx, centery, centerz: Specifies the position of the reference point.
+ @type upx, upy, upz: double
+ @param upx, upy, upz: Specifies the direction of the up vector.
+ """
+
+def gluOrtho2D(left, right, bottom, top):
+ """
+ Define a 2-D orthographic projection matrix
+ @see: U{http://biology.ncsa.uiuc.edu/cgi-bin/infosrch.cgi?cmd=getdoc&coll=0650&db=bks&fname=/SGI_Developer/OpenGL_RM/ch06.html#id5578074}
+
+ @type left, right: double
+ @param left, right: Specify the coordinates for the left and right vertical clipping planes.
+ @type bottom, top: double
+ @param bottom, top: Specify the coordinates for the bottom and top horizontal clipping planes.
+ """
+
+def gluPickMatrix(x, y, width, height, viewport):
+ """
+ Define a picking region
+ @see: U{http://biology.ncsa.uiuc.edu/cgi-bin/infosrch.cgi?cmd=getdoc&coll=0650&db=bks&fname=/SGI_Developer/OpenGL_RM/ch06.html#id5578074}
+
+ @type x, y: double
+ @param x, y: Specify the center of a picking region in window coordinates.
+ @type width, height: double
+ @param width, height: Specify the width and height, respectively, of the picking region in window coordinates.
+ @type viewport: Buffer object. [int]
+ @param viewport: Specifies the current viewport.
+ """
+
+def gluProject(objx, objy, objz, modelMatrix, projMatrix, viewport, winx, winy, winz):
+ """
+ Map object coordinates to window coordinates.
+ @see: U{http://biology.ncsa.uiuc.edu/cgi-bin/infosrch.cgi?cmd=getdoc&coll=0650&db=bks&fname=/SGI_Developer/OpenGL_RM/ch06.html#id5578074}
+
+ @type objx, objy, objz: double
+ @param objx, objy, objz: Specify the object coordinates.
+ @type modelMatrix: Buffer object. [double]
+ @param modelMatrix: Specifies the current modelview matrix (as from a glGetDoublev call).
+ @type projMatrix: Buffer object. [double]
+ @param projMatrix: Specifies the current projection matrix (as from a glGetDoublev call).
+ @type viewport: Buffer object. [int]
+ @param viewport: Specifies the current viewport (as from a glGetIntegerv call).
+ @type winx, winy, winz: Buffer object. [double]
+ @param winx, winy, winz: Return the computed window coordinates.
+ """
+
+def gluUnProject(winx, winy, winz, modelMatrix, projMatrix, viewport, objx, objy, objz):
+ """
+ Map object coordinates to window
+ coordinates.
+ @see: U{http://biology.ncsa.uiuc.edu/cgi-bin/infosrch.cgi?cmd=getdoc&coll=0650&db=bks&fname=/SGI_Developer/OpenGL_RM/ch06.html#id5582204}
+
+ @type winx, winy, winz: double
+ @param winx, winy, winz: Specify the window coordinates to be mapped.
+ @type modelMatrix: Buffer object. [double]
+ @param modelMatrix: Specifies the current modelview matrix (as from a glGetDoublev call).
+ @type projMatrix: Buffer object. [double]
+ @param projMatrix: Specifies the current projection matrix (as from a glGetDoublev call).
+ @type viewport: Buffer object. [int]
+ @param viewport: Specifies the current viewport (as from a glGetIntegerv call).
+ @type objx, objy, objz: Buffer object. [double]
+ @param objx, objy, objz: Return the computed object coordinates.
+ """
+
+class Buffer:
+ """
+ The Buffer object is simply a block of memory that is delineated and initialized by the
+ user. Many OpenGL functions return data to a C-style pointer, however, because this
+ is not possible in python the Buffer object can be used to this end. Wherever pointer
+ notation is used in the OpenGL functions the Buffer object can be used in it's BGL
+ wrapper. In some instances the Buffer object will need to be initialized with the template
+ parameter, while in other instances the user will want to create just a blank buffer
+ which will be zeroed by default.
+
+ Example with Buffer::
+ import Blender
+ from Blender import BGL
+ myByteBuffer = BGL.Buffer(BGL.GL_BYTE, [32,32])
+ BGL.glGetPolygonStipple(myByteBuffer)
+ print myByteBuffer.dimensions
+ print myByteBuffer.list
+ sliceBuffer = myByteBuffer[0:16]
+ print sliceBuffer
+
+ @ivar list: The contents of the Buffer.
+ @ivar dimensions: The size of the Buffer.
+ """
+
+ def __init__(type, dimensions, template = None):
+ """
+ This will create a new Buffer object for use with other BGL OpenGL commands.
+ Only the type of argument to store in the buffer and the dimensions of the buffer
+ are necessary. Buffers are zeroed by default unless a template is supplied, in
+ which case the buffer is initialized to the template.
+
+ @type type: int
+ @param type: The format to store data in. The type should be one of
+ GL_BYTE, GL_SHORT, GL_INT, or GL_FLOAT.
+ @type dimensions: An int or sequence object specifying the dimensions of the buffer.
+ @param dimensions: If the dimensions are specified as an int a linear array will
+ be created for the buffer. If a sequence is passed for the dimensions, the buffer
+ becomes n-Dimensional, where n is equal to the number of parameters passed in the
+ sequence. Example: [256,2] is a two- dimensional buffer while [256,256,4] creates
+ a three- dimensional buffer. You can think of each additional dimension as a sub-item
+ of the dimension to the left. i.e. [10,2] is a 10 element array each with 2 sub-items.
+ [(0,0), (0,1), (1,0), (1,1), (2,0), ...] etc.
+ @type template: A python sequence object (optional)
+ @param template: A sequence of matching dimensions which will be used to initialize
+ the Buffer. If a template is not passed in all fields will be initialized to 0.
+ @rtype: Buffer object
+ @return: The newly created buffer as a PyObject.
+ """
diff --git a/source/blender/python/api2_2x/doc/BezTriple.py b/source/blender/python/api2_2x/doc/BezTriple.py
new file mode 100644
index 00000000000..eb12dd0051e
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/BezTriple.py
@@ -0,0 +1,96 @@
+# Blender.BezTriple module and the BezTriple PyType object
+
+"""
+The Blender.BezTriple submodule
+
+B{New}:
+ - new attributes L{handleTypes<BezTriple.handleTypes>},
+ L{selects<BezTriple.selects>} and L{weight<BezTriple.weight>}
+
+This module provides access to the BezTriple Data in Blender. It is used by
+CurNurb and IpoCurve objects.
+
+@type HandleTypes: readonly dictionary
+@var HandleTypes: The available BezTriple handle types.
+ - FREE - handle has no constraints
+ - AUTO - completely constrain handle based on knot position
+ - VECT - constraint handle to line between current and neighboring knot
+ - ALIGN - constrain handle to lie in a straight line with knot's other
+ handle
+ - AUTOANIM - constrain IPO handles to be horizontal on extremes
+"""
+
+def New (coords):
+ """
+ Create a new BezTriple object.
+
+ @type coords: sequence of three or nine floats
+ @param coords: the coordinate values for the new control point. If three
+ floats are given, then the handle values are automatically generated.
+ @rtype: BezTriple
+ @return: a new BezTriple object
+ """
+
+class BezTriple:
+ """
+ The BezTriple object
+ ====================
+ This object gives access to generic data from all BezTriple objects in
+ Blender.
+ @ivar pt : the [x,y] coordinates for knot point of this BezTriple. After
+ changing coordinates of a Ipo curve, it is advisable to call
+ L{IpoCurve.recalc()<IpoCurve.IpoCurve.recalc>} to update the curve.
+ @type pt: list of two floats
+ @ivar vec : a list of the 3 points [ handle, knot, handle ] that comprise a
+ BezTriple, with each point composed of a list [x,y,z] of floats. The list
+ looks like [ [H1x, H1y, H1z], [Px, Py, Pz], [H2x, H2y, H2z] ].
+ Example::
+ # where bt is of type BezTriple
+ # and h1, p, and h2 are lists of 3 floats
+ h1, p, h2 = bt.vec
+ @type vec: list of points
+ @ivar tilt: the tilt/alpha value for the point
+ @type tilt: float
+ @ivar radius: the radius of this point (used for tapering bevels)
+ @type radius: float
+ @ivar hide: the visibility status of the knot. B{Note}: true/nonzero means
+ I{not} hidden. B{Note}: primarily intended for curves; not a good idea to
+ hide IPO control points.
+ @type hide: int
+ @ivar handleTypes: the types of the point's two handles. See
+ L{HandleTypes} for a complete description.
+ @type handleTypes list of two ints
+ @ivar selects: the select status for [handle, knot, handle]. True/nonzero
+ if the point is selected.
+ @type selects: list of three ints
+ @ivar weight: the weight assigned to the control point. Useful for
+ softbodies and possibly others.
+ @type weight: float
+ """
+
+ def getPoints():
+ """
+ Returns the x,y coordinates of the Bezier knot point (B{deprecated}).
+ See the L{BezTriple.pt} attribute.
+ @rtype: list of floats
+ @return: list of the x and y coordinates of the Bezier point.
+ """
+
+ def setPoints(newval):
+ """
+ Sets the x,y coordinates of the Bezier knot point (B{deprecated}).
+ See the L{BezTriple.pt} attribute.
+ @type newval: tuple of 2 floats
+ @param newval: the x and y coordinates of the new Bezier point.
+ @rtype: None
+ @return: None
+ """
+
+ def getTriple():
+ """
+ Returns the x,y,z coordinates for each of the three points that make up
+ a BezierTriple (B{deprecated}). See the L{BezTriple.vec} attribute.
+ @rtype: list consisting of 3 lists of 3 floats
+ @return: handle1, knot, handle2
+ """
+
diff --git a/source/blender/python/api2_2x/doc/Blender.py b/source/blender/python/api2_2x/doc/Blender.py
new file mode 100644
index 00000000000..51666d0e211
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Blender.py
@@ -0,0 +1,238 @@
+# The Blender Module
+
+# The module files in this folder are used to create the API documentation.
+# Doc system used: epydoc - http://epydoc.sf.net
+# pseudo command line (check the epy_docgen.sh file):
+# epydoc -o BPY_API_23x --url "http://www.blender.org" -t Blender.py \
+# -n "Blender" --no-private --no-frames Blender.py \
+# Types.py Scene.py Object.py [ ... etc]
+
+"""
+The main Blender module.
+
+B{New}: L{Run}, L{UpdateMenus}, new options to L{Get}, L{ShowHelp},
+L{SpaceHandlers} dictionary.
+L{UnpackModes} dictionary.
+
+Blender
+=======
+
+@type bylink: bool
+@var bylink: True if the current script is being executed as a script link.
+@type link: Blender Object or None; integer (space handlers)
+@var link: for normal script links, 'link' points to the linked Object (can be
+ a scene, object (mesh, camera, lamp), material or
+ world). For space handler script links, 'link' is an integer from the
+ Blender.L{SpaceHandlers} dictionary. For script not running as script
+ links, 'link' is None.
+@type event: string or int
+@var event: this has three possible uses: script link type or events callback
+ ascii value:
+ - for normal script links it is a string representing the link type
+ (OnLoad, FrameChanged, Redraw, etc.).
+ - for EVENT space handler script links it is the passed event.
+ - for normal L{GUI<Draw.Register>} scripts I{during the events callback},
+ it holds the ascii value of the current event, if it is a valid one.
+ Users interested in this should also check the builtin 'ord' and 'chr'
+ Python functions.
+@type mode: string
+@var mode: Blender's current mode:
+ - 'interactive': normal mode, with an open window answering to user input;
+ - 'background': Blender was started as 'C{blender -b <blender file>}' and
+ will exit as soon as it finishes rendering or executing a script
+ (ex: 'C{blender -b <blender file> -P <script>}'). Try 'C{blender -h}'
+ for more detailed informations.
+@type UnpackModes: constant dictionary
+@var UnpackModes: dictionary with available unpack modes.
+ - USE_LOCAL - use files in current directory (create when necessary)
+ - WRITE_LOCAL - write files in current directory (overwrite when necessary)
+ - USE_ORIGINAL - use files in original location (create when necessary)
+ - WRITE_ORIGINAL - write files in original location (overwrite when necessary)
+@type SpaceHandlers: constant dictionary
+@var SpaceHandlers: dictionary with space handler types.
+ - VIEW3D_EVENT;
+ - VIEW3D_DRAW.
+"""
+
+def Set (request, data):
+ """
+ Update settings in Blender.
+ @type request: string
+ @param request: The setting to change:
+ - 'curframe': the current animation frame
+ - 'uscriptsdir': user scripts dir
+ - 'yfexportdir': yafray temp xml storage dir
+ - 'fontsdir': font dir
+ - 'texturesdir': textures dir
+ - 'seqpluginsdir': sequencer plugin dir
+ - 'renderdir': default render output dir
+ - 'soundsdir': sound dir
+ - 'tempdir': temp file storage dir
+ @type data: int or string
+ @param data: The new value.
+ """
+
+def Get (request):
+ """
+ Retrieve settings from Blender.
+ @type request: string
+ @param request: The setting data to be returned:
+ - 'curframe': the current animation frame.
+ - 'curtime' : the current animation time.
+ - 'staframe': the start frame of the animation.
+ - 'endframe': the end frame of the animation.
+ - 'rt': the value of the 'rt' button for general debugging
+ - 'filename': the name of the last file read or written.
+ - 'homedir': Blender's home directory.
+ - 'datadir' : the path to the dir where scripts should store and
+ retrieve their data files, including saved configuration (can
+ be None, if not found).
+ - 'udatadir': the path to the user defined data dir. This may not be
+ available (is None if not found), but users that define uscriptsdir
+ have a place for their own scripts and script data that won't be
+ erased when a new version of Blender is installed. For this reason
+ we recommend scripts check this dir first and use it, if available.
+ - 'scriptsdir': the path to the main dir where scripts are stored.
+ - 'uscriptsdir': the path to the user defined dir for scripts. (*)
+ - 'icondir': the path to blenders icon theme files.
+ - 'yfexportdir': the path to the user defined dir for yafray export. (*)
+ - 'fontsdir': the path to the user defined dir for fonts. (*)
+ - 'texturesdir': the path to the user defined dir for textures. (*)
+ - 'texpluginsdir': the path to the user defined dir for texture plugins. (*)
+ - 'seqpluginsdir': the path to the user defined dir for sequence plugins. (*)
+ - 'renderdir': the path to the user defined dir for render output. (*)
+ - 'soundsdir': the path to the user defined dir for sound files. (*)
+ - 'tempdir': the path to the user defined dir for storage of Blender
+ temporary files. (*)
+ - 'version' : the Blender version number.
+ @note: (*) these can be set in Blender at the User Preferences window -> File
+ Paths tab.
+ @warn: this function returns None for requested dir paths that have not been
+ set or do not exist in the user's file system.
+ @return: The requested data or None if not found.
+ """
+
+def Redraw ():
+ """
+ Redraw all 3D windows.
+ """
+
+def Load (filename = None):
+ """
+ Load a Blender .blend file or any of the other supported file formats.
+
+ Supported formats:
+ - Blender's .blend;
+ - DXF;
+ - Open Inventor 1.0 ASCII;
+ - Radiogour;
+ - STL;
+ - Videoscape;
+ - VRML 1.0 asc.
+
+ @type filename: string
+ @param filename: the pathname to the desired file. If 'filename'
+ isn't given or if it contains the substring '.B.blend', the default
+ .B.blend file is loaded.
+
+ @warn: loading a new .blend file removes the current data in Blender. For
+ safety, this function saves the current data as an auto-save file in
+ the temporary dir used by Blender before loading a new Blender file.
+ @warn: after a call to Load(blendfile), current data in Blender is lost,
+ including the Python dictionaries. Any posterior references in the
+ script to previously defined data will generate a NameError. So it's
+ better to put Blender.Load as the last executed command in the script,
+ when this function is used to open .blend files.
+ @warn: if in edit mode, this function leaves it, since Blender itself
+ requires that.
+ @note: for all types except .blend files, this function only works in
+ interactive mode, not in background, following what Blender itself does.
+ """
+
+def Save (filename, overwrite = 0):
+ """
+ Save a Blender .blend file with the current program data or export to
+ one of the builtin file formats.
+
+ Supported formats:
+ - Blender (.blend);
+ - DXF (.dxf);
+ - STL (.stl);
+ - Videoscape (.obj);
+ - VRML 1.0 (.wrl).
+
+ @type filename: string
+ @param filename: the filename for the file to be written. It must have one
+ of the supported extensions or an error will be returned.
+ @type overwrite: int (bool)
+ @param overwrite: if non-zero, file 'filename' will be overwritten if it
+ already exists (can be checked with L{Blender.sys.exists<Sys.exists>}.
+ By default existing files are not overwritten (an error is returned).
+
+ @note: The substring ".B.blend" is not accepted inside 'filename'.
+ @note: DXF, STL and Videoscape export only B{selected} meshes.
+ """
+
+def Run (script):
+ """
+ Execute the given script.
+ @type script: string
+ @param script: the name of an available Blender Text (use L{Text.Get}() to
+ get a complete list) or the full pathname to a Python script file in the
+ system.
+ @note: the script is executed in its own context -- with its own global
+ dictionary -- as if it had been executed from the Text Editor or chosen
+ from a menu.
+ """
+
+def ShowHelp (script):
+ """
+ Show help for the given script. This is a time-saver ("code-saver") for
+ scripts that need to feature a 'help' button in their GUIs or a 'help'
+ submenu option. With proper documentation strings, calling this function is
+ enough to present a screen with help information plus link and email buttons.
+ @type script: string
+ @param script: the filename of a registered Python script.
+ @note: this function uses L{Run} and the "Scripts Help Browser" script. This
+ means that it expects proper doc strings in the script to be able to show
+ help for it (otherwise it offers to load the script source code as text).
+ The necessary information about doc strings is L{given here<API_related>}.
+ @note: 'script' doesn't need to be a full path name: "filename.py" is enough.
+ Note, though, that this function only works for properly registered
+ scripts (those that appear in menus).
+ """
+
+def UpdateMenus ():
+ """
+ Update the menus that list registered scripts. This will scan the default
+ and user defined (if available) folder(s) for scripts that have registration
+ data and will make them accessible via menus.
+ @note: only scripts that save other new scripts in the default or user
+ defined folders need to call this function.
+ """
+def UnpackAll (mode):
+ """
+ Unpack all files with specified mode.
+ @param mode: The Mode for unpacking. Must be one of the modes in
+ Blender.UnpackModes dictionary.
+ @type mode: int
+ """
+def PackAll ():
+ """
+ Pack all files.
+ """
+
+def CountPackedFiles():
+ """
+ Returns the number of packed files.
+ """
+
+def Quit ():
+ """
+ Exit from Blender immediately.
+ @warn: the use of this function should obviously be avoided, it is available
+ because there are some cases where it can be useful, like in automated
+ tests. For safety, a "quit.blend" file is saved (normal Blender behavior
+ upon exiting) when this function is called, so the data in Blender isn't
+ lost.
+ """
diff --git a/source/blender/python/api2_2x/doc/Blender_API.css b/source/blender/python/api2_2x/doc/Blender_API.css
new file mode 100644
index 00000000000..22c00536282
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Blender_API.css
@@ -0,0 +1,44 @@
+/* Generated by CaScadeS, a stylesheet editor for Mozilla Composer */
+
+ font { font-family: sans-serif ! important;
+ }
+
+ p { color: rgb(0, 0, 0);
+ font-family: sans-serif;
+ }
+
+ pre { color: rgb(0, 0, 0);
+ font-family: monospace;
+ }
+
+ a { font-family: sans-serif;
+ color: rgb(0, 135, 0);
+ font-weight: bold;
+ }
+
+ a:visited { font-family: sans-serif;
+ color: rgb(102, 102, 102);
+ }
+
+ a:hover { font-family: sans-serif;
+ color: rgb(184, 73, 0);
+ }
+
+ h1 { font-family: sans-serif;
+ color: rgb(255, 102, 0);
+ }
+
+ h2 { font-family: sans-serif;
+ color: rgb(255, 102, 0);
+ }
+
+ h3 { font-family: sans-serif;
+ color: rgb(255, 102, 0);
+ }
+
+ table { color: rgb(0, 0, 0);
+ opacity: 1;
+ border-bottom-color: rgb(0, 102, 0);
+ background-color: rgb(217, 216, 239);
+ }
+
diff --git a/source/blender/python/api2_2x/doc/Bpy.py b/source/blender/python/api2_2x/doc/Bpy.py
new file mode 100644
index 00000000000..e5eb751cf04
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Bpy.py
@@ -0,0 +1,25 @@
+# bpy module and the bpy PyType object
+
+"""
+The bpy module.
+
+bpy
+===
+
+ ATTENTION: This module is EXPERIMENTAL.
+ Features documented here are subject to change.
+
+ The bpy module is intended as a replacement for the Blender module.
+ It will eventually provide the same features and functionality.
+
+ This module uses a different model for the way data is accessed, added and removed. The various types such as groups, meshes, etc., are unchanged.
+
+ At the moment it provides an alternative way to access data from python.
+
+ Submodules:
+ -----------
+ - L{data<Bpy_data>}
+ - L{libraries<LibData.Libraries>}
+ - L{config<Bpy_config>}
+"""
+
diff --git a/source/blender/python/api2_2x/doc/Bpy_config.py b/source/blender/python/api2_2x/doc/Bpy_config.py
new file mode 100644
index 00000000000..ec3eb261c03
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Bpy_config.py
@@ -0,0 +1,38 @@
+# bpy module and the bpy PyType object
+
+"""
+bpy.config
+==========
+
+This module gives you direct access to blenders preferences.
+
+@var undoSteps: number of undo steps to store.
+@type undoSteps: int
+@var textureTimeout: free textures from openGL memory if unused after this time.
+@type textureTimeout: int
+@var textureCollectRate: tag textures as being used at this interval of time.
+@type textureCollectRate: int
+@var sequenceMemCacheLimit: how much memory to use for a sequencer cache.
+@type sequenceMemCacheLimit: int
+@var fontSize: display size for fonts in the user interface.
+@type fontSize: int
+@var yfExportDir: yafray export path.
+@type yfExportDir: string
+@var fontDir: default font path.
+@type fontDir: string
+@var renderDir: default render path.
+@type renderDir: string
+@var textureDir: default texture path.
+@type textureDir: string
+@var userScriptsDir: path for user scripts.
+@type userScriptsDir: string
+@var texturePluginsDir: default texture plugin path.
+@type texturePluginsDir: string
+@var soundDir: default sound path.
+@type soundDir: string
+@var sequencePluginsDir: default sequencer plugin path.
+@type sequencePluginsDir: string
+@var tempDir: path where temp files are saved.
+@type tempDir: string
+"""
+
diff --git a/source/blender/python/api2_2x/doc/Bpy_data.py b/source/blender/python/api2_2x/doc/Bpy_data.py
new file mode 100644
index 00000000000..e228db688d7
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Bpy_data.py
@@ -0,0 +1,281 @@
+# bpy module and the bpy PyType object
+
+"""
+The bpy module.
+
+bpy.data (Generic Data Access)
+==============================
+
+Example::
+
+ # apply the active image to the active mesh
+ # this script has no error checking to keep it small and readable.
+
+ sce= bpy.data.scenes.active
+ ob_act = sce.objects.active # assuming we have an active, might be None
+ me = ob_act.getData(mesh=1) # assuming a mesh type, could be any
+ img = bpy.data.images.active # assuming we have an active image
+
+ for f in me.faces:
+ f.image = img
+
+ Window.RedrawAll()
+
+Example::
+
+ # make a new object from an existing mesh
+ # and make it active
+ scn= bpy.data.scenes.active
+ me = bpy.data.meshes['mymesh']
+ ob = sce.objects.new(me) # new object from the mesh
+ sce.objects.active = ob
+
+Example::
+ # print the names of any non local objects
+ sce= bpy.data.scenes.active
+ for ob in sce.objects:
+ if ob.lib:
+ print 'external object:', ob.name, ob.lib
+
+Example::
+ # add an empty object at each vertex of the active mesh
+ scn= bpy.data.scenes.active
+ ob_act = sce.objects.active
+ matrix = ob_act.matrixWorld
+ me = ob_act.getData(mesh=1)
+
+ for v in me.verts:
+ ob = sce.objects.new('Empty')
+ ob.loc = v.co * matrix # transform the vertex location by the objects matrix.
+
+
+Example::
+ # load all the wave sound files in a directory
+ import os
+ sound_dir = '/home/me/soundfiles/'
+ sounds_new = []
+ for fname in os.listdir(sound_dir):
+ if fname.lower().endswith('.wav'):
+ try:
+ snd = bpy.data.sounds.new(filename = sound_dir + fname)
+ except:
+ snd = None
+
+ if snd:
+ sounds_new.append(snd)
+
+ # Print the sounds
+ for snd in sounds_new:
+ print snd
+
+Example::
+ # apply a new image to each selected mesh object as a texface.
+ width, height= 512, 512
+ scn= bpy.data.scenes.active
+
+ for ob in sce.objects.context:
+ if not ob.lib and ob.type == 'Mesh': # object isn't from a library and is a mesh
+ me = ob.getData(mesh=1)
+ me.faceUV = True # add UV coords and textures if we don't have them.
+
+ # Make an image named after the mesh
+ img = bpy.data.images.new(me.name, width, height)
+
+ for f in me.faces:
+ f.image = img
+
+ Window.RedrawAll()
+
+
+
+@var scenes: sequence for L{scene<Scene.Scene>} data
+@type scenes: L{libBlockSeq}
+@var objects: sequence for L{object<Object.Object>} data
+@type objects: L{libBlockSeq}
+@var meshes: sequence for L{mesh<Mesh.Mesh>} data
+@type meshes: L{libBlockSeq}
+@var curves: sequence for L{curve<Curve.Curve>} data, used to store Curve, Surface and Text3d data.
+@type curves: L{libBlockSeq}
+@var metaballs: sequence for L{metaball<Metaball.Metaball>} data
+@type metaballs: L{libBlockSeq}
+@var materials: sequence for L{material<Material.Material>} data
+@type materials: L{libBlockSeq}
+@var textures: sequence for L{texture<Texture.Texture>} data
+@type textures: L{libBlockSeq}
+@var images: sequence for L{image<Image.Image>} data
+@type images: L{libBlockSeq}
+@var lattices: sequence for L{lattice<Lattice.Lattice>} data
+@type lattices: L{libBlockSeq}
+@var lamps: sequence for L{lamp<Lamp.Lamp>} data
+@type lamps: L{libBlockSeq}
+@var cameras: sequence for L{camera<Camera.Camera>} data
+@type cameras: L{libBlockSeq}
+@var ipos: sequence for L{ipo<Ipo.Ipo>} data
+@type ipos: L{libBlockSeq}
+@var worlds: sequence for L{world<World.World>} data
+@type worlds: L{libBlockSeq}
+@var fonts: sequence for L{font<Font.Font>} data
+@type fonts: L{libBlockSeq}
+@var texts: sequence for L{text<Text.Text>} data
+@type texts: L{libBlockSeq}
+@var sounds: sequence for L{sound<Sound.Sound>} data
+@type sounds: L{libBlockSeq}
+@var groups: sequence for L{group<Group.Group>} data
+@type groups: L{libBlockSeq}
+@var armatures: sequence for L{armature<Armature.Armature>} data
+@type armatures: L{libBlockSeq}
+@var actions: sequence for L{action<NLA.Action>} data
+@type actions: L{libBlockSeq}
+"""
+
+
+class libBlockSeq:
+ """
+ Generic Data Access
+ ===================
+ This provides a unified way to access and manipulate data types in Blender
+ (scene, object, mesh, curve, metaball, material, texture, image, lattice,
+ lamp, camera, ipo, world, font, text, sound, groups, armatures, actions).
+
+ Get Item
+ ========
+ To get a datablock by name you can use dictionary-like syntax.
+
+ >>> ob = bpy.data.objects['myobject']
+
+ Note that this can only be used for getting.
+
+ >>> bpy.data.objects['myobject'] = data # will raise an error
+
+ B{Library distinctions}
+
+ Blender doesn't allow naming collisions within its own data, but it's
+ possible to run into naming collisions when you have data linked from an external blend file.
+
+ You can specify where the data is from by using a (name, library) pair as the key.
+
+ >>> group = bpy.data.groups['mygroup', '//mylib.blend'] # only return data linked from mylib
+
+ If you want to get a group from the local data only you can use None
+
+ >>> group = bpy.data.groups['mygroup', None] # always returns local data
+
+ Sequence
+ ========
+ These generic datablocks are sequence datatypes. They are not lists. They support the dictionary and iterator protocols. This implies the following
+
+ - A B{for} statement allows you to loop through data using the iterator protocol without wasting resources on creating a large list.
+
+ >>> for me in bpy.data.meshes:
+ ... print me.name
+
+ - You can also use len() to see how many datablocks exist.
+
+ >>> print len(bpy.data.scenes)
+
+ - Because the sequences are not lists and the [] operator is used to get items by name, you cannot use indexing to retrieve an item.
+
+ >>> ob = bpy.data.objects[-1] # will raise an error
+
+ - If you want to access the entire sequence as a list simply use the list() constructor.
+
+ >>> ipo_list = list(bpy.data.ipos)
+
+ @type tag: Bool
+ @ivar tag: A fast way to set the tag value of every member of the sequence to True or False
+
+ For example
+
+ >>> bpy.data.meshes.tag = True
+
+ Is the same as...
+
+ >>> for me in bpy.data.meshes: me.tag = True
+
+ @type active: Datablock or None
+ @ivar active: The active member of the datatype
+
+ Applies to:
+ - L{images}
+ - L{scenes}
+ - L{texts}
+ This can also be used to set the active data.
+
+ >>> bpy.data.images.active = bpy.data.images.new(filename = '/home/me/someimage.jpg')
+
+ """
+
+ def new(name):
+ """
+ fixme: need description for parameters.
+ This function returns a new datablock containing no data or loaded from a file.
+
+ Most datatypes accept a name for their argument except for L{sounds}, L{fonts}, L{ipos} and L{curves} that need an additional argument.
+
+ The name argument is optional if not given a default name will be assigned.
+
+ The name given may be modified by blender to make it unique.
+
+ Loading From File
+ =================
+ For L{images}, L{texts}, L{sounds}, L{fonts} types you can use the filename keyword to make a new datablock from a file.
+
+ New L{sounds}, L{fonts} can only be made with the a filename given.
+
+ The filename can a keyword or the second argument, use the keyword only for the datablocks new name to be set by the filename.
+
+ >>> sound = bpy.data.sounds.new('newsound', '~/mysound.wav') # uses the first string given for the name.
+
+ >>> sound = bpy.data.sounds.new(filename = '~/mysound.wav') # will use the filename to make the name.
+
+ Images
+ ======
+ Images optionally accept extra 2 arguments for width and height, values between 4 and 5000 if no args are given they will be 256.
+
+ >>> img = bpy.data.images.new(name, 512, 512)
+
+ Curves
+ ======
+ Curves need 2 arguments: bpy.data.curves.new(name, type) type must be one of the following...
+ - 'Curve'
+ - 'Text3d'
+
+ >>> text3d = bpy.data.curves.new('MyCurve', 'Text3d')
+
+ Ipos
+ ====
+ Ipos need 2 arguments: bpy.data.ipos.new(name, type) type must be one of the following...
+ - 'Camera'
+ - 'World'
+ - 'Material'
+ - 'Texture'
+ - 'Lamp'
+ - 'Action'
+ - 'Constraint'
+ - 'Sequence'
+ - 'Curve'
+ - 'Key'
+ Objects cannot be created from bpy.data.objects;
+ objects must be created from the scene. Here are some examples.
+
+ >>> ob = bpy.data.scenes.active.objects.new('Empty')
+
+ >>> scn = bpy.data.scenes.active
+ ... ob = sce.objects.new(bpy.data.meshes.new('mymesh'))
+
+ @rtype: datablock
+ """
+
+ def unlink(datablock):
+ """
+ This function removes a datablock.
+ applies to:
+ - L{scenes}
+ - L{groups}
+ - L{texts}
+ Other types will raise an error.
+ @rtype: None
+ """
+
+
+ \ No newline at end of file
diff --git a/source/blender/python/api2_2x/doc/Camera.py b/source/blender/python/api2_2x/doc/Camera.py
new file mode 100644
index 00000000000..c4e664efa66
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Camera.py
@@ -0,0 +1,257 @@
+# Blender.Camera module and the Camera PyType object
+
+"""
+The Blender.Camera submodule.
+
+B{New}: L{Camera.clearScriptLinks} accepts a parameter now.
+
+Camera Data
+===========
+
+This module provides access to B{Camera Data} objects in Blender.
+
+Example::
+
+ from Blender import Camera, Object, Scene
+ cam = Camera.New('ortho') # create new ortho camera data
+ cam.scale = 6.0 # set scale value for ortho view
+ scn = Scene.GetCurrent() # get current scene
+ ob = scn.objects.new(cam) # add a new camera object from the data
+ scn.setCurrentCamera(ob) # make this camera the active
+"""
+
+def New (type = 'persp', name = 'CamData'):
+ """
+ Create a new Camera Data object.
+ @type type: string
+ @param type: The Camera type: 'persp' or 'ortho'.
+ @type name: string
+ @param name: The Camera Data name.
+ @rtype: Blender Camera
+ @return: The created Camera Data object.
+ """
+
+def Get (name = None):
+ """
+ Get the Camera Data object(s) from Blender.
+ @type name: string
+ @param name: The name of the Camera Data.
+ @rtype: Blender Camera or a list of Blender Cameras
+ @return: It depends on the I{name} parameter:
+ - (name): The Camera Data object with the given I{name};
+ - (): A list with all Camera Data objects in the current scene.
+ """
+
+class Camera:
+ """
+ The Camera Data object
+ ======================
+ This object gives access to Camera-specific data in Blender.
+ @ivar type: The Camera type: 'persp' or 'ortho'
+ @ivar mode: The mode flags: B{ORed value}: 'showLimits':1, 'showMist':2.
+ @ivar lens: The lens value in [1.0, 250.0], only relevant to *persp* cameras.
+ @ivar angle: The lens value in degrees [7.323871, 172.847331], only relevant to *persp* cameras.
+ @ivar scale: The scale value in [0.01, 1000.00], only relevant to *ortho* cameras.
+ @ivar clipStart: The clip start value in [0.0, 100.0].
+ @ivar clipEnd: The clip end value in [1.0, 5000.0].
+ @ivar dofDist: The dofDist value in [0.0, 5000.0].
+ @ivar shiftX: The horizontal offset of the camera [-2.0, 2.0].
+ @ivar shiftY: The vertical offset of the camera [-2.0, 2.0].
+ @ivar alpha: The PassePart alpha [0.0, 1.0].
+ @ivar drawSize: The display size for the camera an the 3d view [0.1, 10.0].
+ @type ipo: Blender Ipo
+ @ivar ipo: The "camera data" ipo linked to this camera data object.
+ Set to None to clear the ipo.
+
+ @ivar drawLimits: Toggle the option to show limits in the 3d view.
+ @ivar drawName: Toggle the option to show the camera name in the 3d view.
+ @ivar drawMist: Toggle the option to show mist in the 3d view.
+ @ivar drawTileSafe: Toggle the option to show tile safe in the 3d view.
+ @ivar drawPassepartout: Toggle the option to show pass part out in the 3d view.
+
+ @warning: Most member variables assume values in some [Min, Max] interval.
+ When trying to set them, the given parameter will be clamped to lie in
+ that range: if val < Min, then val = Min, if val > Max, then val = Max.
+ """
+
+ def getName():
+ """
+ Get the name of this Camera Data object. (B{deprecated}) See the L{name} attribute.
+ @rtype: string
+ """
+
+ def setName(name):
+ """
+ Set the name of this Camera Data object. (B{deprecated}) See the L{name} attribute.
+ @type name: string
+ @param name: The new name.
+ """
+
+ def getIpo():
+ """
+ Get the Ipo associated with this camera data object, if any. (B{deprecated})
+ @rtype: Ipo
+ @return: the wrapped ipo or None. (B{deprecated}) See the L{ipo} attribute.
+ """
+
+ def setIpo(ipo):
+ """
+ Link an ipo to this camera data object. (B{deprecated}) See the L{ipo} attribute.
+ @type ipo: Blender Ipo
+ @param ipo: a "camera data" ipo.
+ """
+
+ def clearIpo():
+ """
+ Unlink the ipo from this camera data object. (B{deprecated}) See the L{ipo} attribute.
+ @return: True if there was an ipo linked or False otherwise.
+ """
+
+ def getType():
+ """
+ Get this Camera's type. (B{deprecated}) See the L{type} attribute.
+ @rtype: int
+ @return: 0 for 'persp' or 1 for 'ortho'.
+ """
+
+ def setType(type):
+ """
+ Set this Camera's type. (B{deprecated}) See the L{type} attribute.
+ @type type: string
+ @param type: The Camera type: 'persp' or 'ortho'.
+ """
+
+ def getMode():
+ """
+ Get this Camera's mode flags. (B{deprecated}) See the L{mode} attribute.
+ @rtype: int
+ @return: B{OR'ed value}: 'showLimits' is 1, 'showMist' is 2, or
+ respectively, 01 and 10 in binary.
+ """
+
+ def setMode(mode1 = None, mode2 = None):
+ """
+ Set this Camera's mode flags. Mode strings given are turned 'on'. (B{deprecated}) See the L{mode} attribute.
+ Those not provided are turned 'off', so cam.setMode() -- without
+ arguments -- turns off all mode flags for Camera cam.
+ @type mode1: string
+ @type mode2: string
+ @param mode1: A mode flag: 'showLimits' or 'showMist'.
+ @param mode2: A mode flag: 'showLimits' or 'showMist'.
+ """
+
+ def getLens():
+ """
+ Get the lens value. (B{deprecated}) See the L{lens} attribute.
+ @rtype: float
+ @warn: lens is only relevant for perspective (L{getType}) cameras.
+ """
+
+ def setLens(lens):
+ """
+ Set the lens value. (B{deprecated}) See the L{lens} attribute.
+ @type lens: float
+ @param lens: The new lens value.
+ @warn: lens is only relevant for perspective (L{type}) cameras.
+ """
+
+ def getScale():
+ """
+ Get the scale value. (B{deprecated}) See the L{scale} attribute.
+ @rtype: float
+ @warn: scale is only relevant for ortho (L{type}) cameras.
+ """
+
+ def setScale(scale):
+ """
+ Set the scale value. (B{deprecated}) See the L{scale} attribute.
+ @type scale: float
+ @param scale: The new scale value in [0.01, 1000.00].
+ @warn: scale is only relevant for ortho (L{getType}) cameras.
+ """
+
+ def getClipStart():
+ """
+ Get the clip start value. (B{deprecated}) See the L{clipStart} attribute.
+ @rtype: float
+ """
+
+ def setClipStart(clipstart):
+ """
+ Set the clip start value. (B{deprecated}) See the L{clipStart} attribute.
+ @type clipstart: float
+ @param clipstart: The new lens value.
+ """
+
+ def getClipEnd():
+ """
+ Get the clip end value. (B{deprecated}) See the L{clipEnd} attribute.
+ @rtype: float
+ """
+
+ def setClipEnd(clipend):
+ """
+ Set the clip end value. (B{deprecated}) See the L{clipEnd} attribute.
+ @type clipend: float
+ @param clipend: The new clip end value.
+ """
+
+ def getDrawSize():
+ """
+ Get the draw size value. (B{deprecated}) See the L{drawSize} attribute.
+ @rtype: float
+ """
+
+ def setDrawSize(drawsize):
+ """
+ Set the draw size value. (B{deprecated}) See the L{drawSize} attribute.
+ @type drawsize: float
+ @param drawsize: The new draw size value.
+ """
+
+ def getScriptLinks (event):
+ """
+ Get a list with this Camera's script links of type 'event'.
+ @type event: string
+ @param event: "FrameChanged", "Redraw" or "Render".
+ @rtype: list
+ @return: a list with Blender L{Text} names (the script links of the given
+ 'event' type) or None if there are no script links at all.
+ """
+
+ def clearScriptLinks (links = None):
+ """
+ Delete script links from this Camera. If no list is specified, all
+ script links are deleted.
+ @type links: list of strings
+ @param links: None (default) or a list of Blender L{Text} names.
+ """
+
+ def addScriptLink (text, event):
+ """
+ Add a new script link to this Camera.
+ @type text: string
+ @param text: the name of an existing Blender L{Text}.
+ @type event: string
+ @param event: "FrameChanged", "Redraw" or "Render".
+ """
+
+ def insertIpoKey(keytype):
+ """
+ Inserts keytype values in camera ipo at curframe. Uses module constants.
+ @type keytype: Integer
+ @param keytype:
+ -LENS
+ -CLIPPING
+ @return: py_none
+ """
+
+ def __copy__ ():
+ """
+ Make a copy of this camera
+ @rtype: Camera
+ @return: a copy of this camera
+ """
+
+import id_generics
+Camera.__doc__ += id_generics.attributes
diff --git a/source/blender/python/api2_2x/doc/Constraint.py b/source/blender/python/api2_2x/doc/Constraint.py
new file mode 100644
index 00000000000..4c1981c5238
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Constraint.py
@@ -0,0 +1,248 @@
+# Blender.Constraint module and the Constraint PyType object
+
+"""
+The Blender.Constraint submodule
+
+B{New}:
+ - provides access to Blender's constraint stack
+
+This module provides access to the Constraint Data in Blender.
+
+Examples::
+ from Blender import *
+
+ ob = Object.Get('Cube')
+ if len(ob.constraints) > 0:
+ const = ob.constraints[0]
+ if const.type == Constraint.Type.FLOOR:
+ offs = const[Constraint.Settings.OFFSET]
+
+Or to print all the constraints attached to each bone in a pose::
+ from Blender import *
+
+ ob = Object.Get('Armature')
+ pose = ob.getPose()
+ for bonename in pose.bones.keys():
+ bone = pose.bones[bonename]
+ for const in bone.constraints:
+ print bone.name,'=>',const
+
+@type Type: readonly dictionary
+@var Type: Constant Constraint dict used by L{Constraints.append()} and
+ for comparison with L{Constraint.type}. Values are
+ TRACKTO, IKSOLVER, FOLLOWPATH, COPYROT, COPYLOC, COPYSIZE, ACTION,
+ LOCKTRACK, STRETCHTO, FLOOR, LIMITLOC, LIMITROT, LIMITSIZE, CLAMPTO,
+ PYTHON, CHILDOF, TRANSFORM, NULL
+
+@type Settings: readonly dictionary
+@var Settings: Constant dict used for changing constraint settings.
+ - Used for all constraints
+ - TARGET (Object) (Note: not used by Limit Location (LIMITLOC),
+ Limit Rotation (LIMITROT), Limit Scale (LIMITSIZE))
+ - BONE (string): name of Bone sub-target (for armature targets) (Note: not
+ used by Stretch To (STRETCHTO), Limit Location (LIMITLOC), Limit Rotation
+ (LIMITROT), Limit Scale (LIMITSIZE), Follow Path (FOLLOWPATH), Clamp To (CLAMPTO))
+ - Used by some constraints:
+ - OWNERSPACE (int): for TRACKTO, COPYLOC, COPYROT, COPYSIZE, LIMITLOC, LIMITROT, LIMITSIZE, PYTHON, TRANSFORM
+ If the owner is an object, values are SPACE_WORLD, SPACE_LOCAL
+ If the owner is a bone, values are SPACE_WORLD, SPACE_POSE, SPACE_PARLOCAL, SPACE_LOCAL
+ - TARGETSPACE (int): for TRACKTO, COPYLOC, COPYROT, COPYSIZE, PYTHON, TRANSFORM, ACTION
+ If the owner is an object, values are SPACE_WORLD, SPACE_LOCAL
+ If the owner is a bone, values are SPACE_WORLD, SPACE_POSE, SPACE_PARLOCAL, SPACE_LOCAL
+ - Used by IK Solver (IKSOLVER) constraint:
+ - TOLERANCE (float): clamped to [0.0001:1.0]
+ - ITERATIONS (int): clamped to [1,10000]
+ - CHAINLEN (int): clamped to [0,255]
+ - POSWEIGHT (float): clamped to [0.01,1.0]
+ - ROTWEIGHT (float): clamped to [0.01,1.0]
+ - ROTATE (bool)
+ - USETIP (bool)
+ - Used by Action (ACTION) constraint:
+ - ACTION (Action Object)
+ - START (int): clamped to [1,maxframe]
+ - END (int): clamped to [1,maxframe]
+ - MIN (float): clamped to [-1000.0,1000.0] for Location, [-180.0,180.0] for Rotation, [0.0001,1000.0] for Scaling
+ - MAX (float): clamped to [-1000.0,1000.0] for Location, [-180.0,180.0] for Rotation, [0.0001,1000.0] for Scaling
+ - KEYON (int): values are XLOC, YLOC, ZLOC, XROT, YROT, ZROT, XSIZE, YSIZE, ZSIZE
+ - Used by Track To (TRACKTO) constraint:
+ - TRACK (int): values are TRACKX, TRACKY, TRACKZ, TRACKNEGX,
+ TRACKNEGY, TRACKNEGZ
+ - UP (int): values are UPX, UPY, UPZ
+ - Used by Stretch To (STRETCHTO) constraint:
+ - RESTLENGTH (float): clamped to [0.0:100.0]
+ - VOLVARIATION (float): clamped to [0.0:100.0]
+ - VOLUMEMODE (int): values are VOLUMEXZ, VOLUMEX, VOLUMEZ,
+ VOLUMENONE
+ - PLANE (int): values are PLANEX, PLANEZ
+ - Used by Follow Path (FOLLOWPATH) constraint:
+ - FOLLOW (bool)
+ - OFFSET (float): clamped to [-maxframe:maxframe]
+ - FORWARD (int): values are TRACKX, TRACKY, TRACKZ, TRACKNEGX,
+ TRACKNEGY, TRACKNEGZ
+ - UP (int): values are UPX, UPY, UPZ
+ - Used by Lock Track (FOLLOWPATH) constraint:
+ - TRACK (int): values are TRACKX, TRACKY, TRACKZ, TRACKNEGX,
+ TRACKNEGY, TRACKNEGZ
+ - LOCK (int): values are LOCKX, LOCKY, LOCKZ
+ - Used by Clamp To (CLAMPTO) constraint:
+ - CLAMP (int): values are CLAMPAUTO, CLAMPX, CLAMPY, CLAMPZ
+ - CLAMPCYCLIC (bool)
+ - Used by Floor (FLOOR) constraint:
+ - MINMAX (int): values are MINX, MINY, MINZ, MAXX, MAXY, MAXZ
+ - OFFSET (float): clamped to [-100.0,100.0]
+ - STICKY (bool)
+ - Used by Copy Location (COPYLOC) and Copy Rotation (COPYROT)
+ - COPY (bitfield): any combination of COPYX, COPYY and COPYZ with possible addition of COPYXINVERT, COPYYINVERT and COPYZINVERT to invert that particular input (if on).
+ - Used by Copy Size (COPYSIZE) constraint:
+ - COPY (bitfield): any combination of COPYX, COPYY and COPYZ
+ - Used by Limit Location (LIMITLOC) constraint:
+ - LIMIT (bitfield): any combination of LIMIT_XMIN, LIMIT_XMAX,
+ LIMIT_YMIN, LIMIT_YMAX, LIMIT_ZMIN, LIMIT_ZMAX
+ - XMIN (float): clamped to [-1000.0,1000.0]
+ - XMAX (float): clamped to [-1000.0,1000.0]
+ - YMIN (float): clamped to [-1000.0,1000.0]
+ - YMAX (float): clamped to [-1000.0,1000.0]
+ - ZMIN (float): clamped to [-1000.0,1000.0]
+ - ZMAX (float): clamped to [-1000.0,1000.0]
+ - Used by Limit Rotation (LIMITROT) constraint:
+ - LIMIT (bitfield): any combination of LIMIT_XROT, LIMIT_YROT,
+ LIMIT_ZROT
+ - XMIN (float): clamped to [-360.0,360.0]
+ - XMAX (float): clamped to [-360.0,360.0]
+ - YMIN (float): clamped to [-360.0,360.0]
+ - YMAX (float): clamped to [-360.0,360.0]
+ - ZMIN (float): clamped to [-360.0,360.0]
+ - ZMAX (float): clamped to [-360.0,360.0]
+ - Used by Limit Scale (LIMITSIZE) constraint:
+ - LIMIT (bitfield): any combination of LIMIT_XMIN, LIMIT_XMAX,
+ LIMIT_YMIN, LIMIT_YMAX, LIMIT_ZMIN, LIMIT_ZMAX
+ - XMIN (float): clamped to [0.0001,1000.0]
+ - XMAX (float): clamped to [0.0001,1000.0]
+ - YMIN (float): clamped to [0.0001,1000.0]
+ - YMAX (float): clamped to [0.0001,1000.0]
+ - ZMIN (float): clamped to [0.0001,1000.0]
+ - ZMAX (float): clamped to [0.0001,1000.0]
+ - Used by Python Script (PYTHON) constraint:
+ - SCRIPT (Text): script to use
+ - PROPERTIES (IDProperties): ID-Properties of constraint
+ - Used by Child Of (CHILDOF) constraint:
+ - COPY (bitfield): any combination of PARLOCX, PARLOCY, PARLOCZ,
+ PARROTX, PARROTY, PARROTZ, PARSIZEX, PARSIZEY, PARSIZEZ.
+ - Used by Transformation (TRANSFORM) constraint:
+ - FROM (int): values are LOC, ROT, SCALE
+ - TO (int): values are LOC, ROT, SCALE
+ - MAPX, MAPY, MAPZ (int): values are LOC, ROT, SCALE
+ - EXTRAPOLATE (bool)
+ - FROM_MINX, FROM_MINY, FROM_MINZ, FROM_MAXX,
+ FROM_MAXY, FROM_MAXZ (float):
+ If FROM==LOC, then is clamped to [-1000.0, 1000.0]
+ If FROM==ROT, then is clamped to [-360.0, 360.0]
+ If FROM==SCALE, then is clamped to [0.0001, 1000.0]
+ - TO_MINX, TO_MINY, TO_MINZ, TO_MAXX, TO_MAXY, TO_MAXZ (float):
+ If TO==LOC, then is clamped to [-1000.0, 1000.0]
+ If TO==ROT, then is clamped to [-360.0, 360.0]
+ If TO==SCALE, then is clamped to [0.0001, 1000.0]
+
+"""
+
+class Constraints:
+ """
+ The Constraints object
+ ======================
+ This object provides access to sequence of
+ L{constraints<Constraint.Constraint>} for a particular object.
+ They can be accessed from L{Object.constraints<Object.Object.constraints>}.
+ or L{PoseBone.constraints<Pose.PoseBone.constraints>}.
+ """
+
+ def __getitem__(index):
+ """
+ This operator returns one of the constraints in the stack.
+ @type index: int
+ @return: an Constraint object
+ @rtype: Constraint
+ @raise KeyError: index was out of range
+ """
+
+ def __len__():
+ """
+ Returns the number of constraints in the constraint stack.
+ @return: number of Constraints
+ @rtype: int
+ """
+
+ def append(type):
+ """
+ Appends a new constraint to the end of the constraint stack.
+ @param type: a constant specifying the type of constraint to create. as from L{Type}
+ @type type: int constant
+ @rtype: Constraint
+ @return: the new Constraint
+ """
+
+ def remove(con):
+ """
+ Remove a constraint from this objects constraint sequence.
+ @param con: a constraint from this sequence to remove.
+ @type con: Constraint
+ @note: Accessing attributes of the constraint after it is removed will
+ throw an exception.
+ """
+
+ def moveUp(con):
+ """
+ Moves the constraint up in the object's constraint stack.
+ @param con: a constraint from this sequence to remove.
+ @type con: Constraint
+ @rtype: None
+ """
+
+ def moveDown(con):
+ """
+ Moves the constraint down in the object's constraint stack.
+ @param con: a constraint from this sequence to remove.
+ @type con: Constraint
+ @rtype: None
+ """
+
+class Constraint:
+ """
+ The Constraint object
+ =====================
+ This object provides access to a constraint for a particular object
+ accessed from L{Constraints}.
+ @ivar name: The name of this constraint. 29 chars max.
+ @type name: string
+ @ivar type: The type of this constraint. Read-only. The returned value
+ matches the types in L{Type}.
+ @type type: int
+ @ivar influence: The influence value of the constraint. Valid values
+ are in the range [0.0,1.0].
+ @type influence: float
+ """
+
+ def __getitem__(key):
+ """
+ This operator returns one of the constraint's data attributes.
+ @param key: value from constraint's L{Constraint.Settings} constant
+ @type key: int constant
+ @return: the requested data
+ @rtype: varies
+ @raise KeyError: the key does not exist for the constraint
+ """
+
+ def __setitem__(key):
+ """
+ This operator changes one of the constraint's data attributes.
+ @param key: value from constraint's L{Constraint.Settings} constant
+ @type key: int constant
+ @raise KeyError: the key does not exist for the constraint
+ """
+
+ def insertKey(frame):
+ """
+ Adds an influence keyframe for the constraint Ipo.
+ @rtype: None
+ @param frame: the frame number at which to insert the key.
+ @type frame: float
+ """
diff --git a/source/blender/python/api2_2x/doc/Curve.py b/source/blender/python/api2_2x/doc/Curve.py
new file mode 100644
index 00000000000..d8ab28524fb
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Curve.py
@@ -0,0 +1,721 @@
+# Blender.Curve module and the Curve PyType object
+
+"""
+The Blender.Curve submodule.
+
+Curve Data
+==========
+
+This module provides access to B{Curve Data} objects in Blender.
+
+A Blender Curve Data consists of multiple L{CurNurb}(s). Try converting a Text object to a Curve to see an example of this. Each curve is of
+type Bezier or Nurb. The underlying L{CurNurb}(s) can be accessed with
+the [] operator. Operator [] returns an object of type L{CurNurb}.
+
+Note that L{CurNurb} can be used to acces a curve of any type (Poly, Bezier or Nurb)
+
+The Curve module also supports the Python iterator interface. This means you
+can access the L{CurNurb}(s) in a Curve and the control points in a L{CurNurb} using a
+Python B{for} statement.
+
+
+Add a Curve to a Scene Example::
+ from Blender import Curve, Object, Scene
+ cu = Curve.New() # create new curve data
+ scn = Scene.GetCurrent() # get current scene
+ ob = scn.objects.new(cu) # make a new curve from the curve data
+
+Iterator Example::
+ from Blender import Curve, Object, Scene
+ scn = Scene.GetCurrent() # get current scene
+ ob = scn.objects.active
+ curvedata = ob.data
+ for curnurb in curvedata:
+ print type( curnurb ), curnurb
+ for point in curnurb:
+ print type( point ), point
+
+Creating a Curve from a list of Vec triples Examples::
+ from Blender import *
+ def bezList2Curve(bezier_vecs):
+ '''
+ Take a list or vector triples and converts them into a bezier curve object
+ '''
+
+ def bezFromVecs(vecs):
+ '''
+ Bezier triple from 3 vecs, shortcut functon
+ '''
+ bt= BezTriple.New(\
+ vecs[0].x, vecs[0].y, vecs[0].z,\
+ vecs[1].x, vecs[1].y, vecs[1].z,\
+ vecs[2].x, vecs[2].y, vecs[2].z)
+
+ bt.handleTypes= (BezTriple.HandleTypes.FREE, BezTriple.HandleTypes.FREE)
+
+ return bt
+
+ # Create the curve data with one point
+ cu= Curve.New()
+ cu.appendNurb(bezFromVecs(bezier_vecs[0])) # We must add with a point to start with
+ cu_nurb= cu[0] # Get the first curve just added in the CurveData
+
+
+ i= 1 # skip first vec triple because it was used to init the curve
+ while i<len(bezier_vecs):
+ bt_vec_triple= bezier_vecs[i]
+ bt= bezFromVecs(bt_vec_triple)
+ cu_nurb.append(bt)
+ i+=1
+
+ # Add the Curve into the scene
+ scn= Scene.GetCurrent()
+ ob = scn.objects.new(cu)
+ return ob
+"""
+
+def New ( name):
+ """
+ Create a new Curve Data object.
+ @type name: string
+ @param name: The Curve Data name.
+ @rtype: Blender Curve
+ @return: The created Curve Data object.
+ """
+
+def Get (name = None):
+ """
+ Get the Curve Data object(s) from Blender.
+ @type name: string
+ @param name: The name of the Curve Data.
+ @rtype: Blender Curve or a list of Blender Curves
+ @return: It depends on the 'name' parameter:
+ - (name): The Curve Data object with the given name;
+ - (): A list with all Curve Data objects in the current scene.
+ """
+
+class Curve:
+ """
+ The Curve Data object
+ =====================
+ This object gives access to Curve and Surface data linked from Blender Objects.
+
+ @ivar name: The Curve Data name.
+ @type name: string
+ @ivar pathlen: The Curve Data path length, used to set the number of frames for an animation (not the physical length).
+ @type pathlen: int
+ @ivar totcol: The Curve Data maximal number of linked materials. Read-only.
+ @type totcol: int
+ @ivar flag: The Curve Data flag value; see L{getFlag()} for the semantics.
+ @ivar bevresol: The Curve Data bevel resolution. [0 - 32]
+ @type bevresol: int
+ @ivar resolu: The Curve Data U-resolution (used for curve and surface resolution) [0 - 1024].
+ @type resolu: int
+ @ivar resolv: The Curve Data V-resolution (used for surface resolution) [0 - 1024].
+ @type resolv: int
+ @ivar width: The Curve Data width [0 - 2].
+ @type width: float
+ @ivar ext1: The Curve Data extent1 (for bevels).
+ @type ext1: float
+ @ivar ext2: The Curve Data extent2 (for bevels).
+ @type ext2: float
+ @ivar loc: The Curve Data location(from the center).
+ @type loc: list of 3 floats
+ @ivar rot: The Curve Data rotation(from the center).
+ @type rot: list of 3 floats
+ @ivar size: The Curve Data size(from the center).
+ @type size: list of 3 floats
+ @ivar bevob: The Curve Bevel Object
+ @type bevob: Blender L{Object<Object.Object>} or None
+ @ivar taperob: The Curve Taper Object
+ @type taperob: Blender L{Object<Object.Object>} or None
+ @ivar key: The Key object associated with this Curve, if any.
+ @type key: Blender L{Key<Key.Key>}
+ @ivar materials: The curves's materials. Each curve can reference up to
+ 16 materials. Empty slots in the curve's list are represented by B{None}.
+ B{Note}: L{Object.colbits<Object.Object.colbits>} needs to be set correctly
+ for each object in order for these materials to be used instead of
+ the object's materials.
+ B{Note}: The list that's returned is I{not} linked to the original curve.
+ curve.materials.append(material) won't do anything.
+ Use curve.materials += [material] instead.
+ @type materials: list of L{Material}s
+ """
+
+ def getName():
+ """
+ Get the name of this Curve Data object.
+ @rtype: string
+ """
+
+ def setName(name):
+ """
+ Set the name of this Curve Data object.
+ @rtype: None
+ @type name: string
+ @param name: The new name.
+ """
+
+ def getPathLen():
+ """
+ Get this Curve's path frame length, used for an animated path.
+ @rtype: int
+ @return: the path length.
+ """
+
+ def setPathLen(len):
+ """
+ Set this Curve's path length.
+ @rtype: None
+ @type len: int
+ @param len: the new curve's length.
+ """
+
+ def getTotcol():
+ """
+ Get the number of materials linked to the Curve.
+ @rtype: int
+ @return: number of materials linked.
+ """
+
+ def setTotcol(totcol):
+ """
+ Set the number of materials linked to the Curve. B{Note}: this method
+ will probably be deprecated in the future.
+ @rtype: None
+ @type totcol: int
+ @param totcol: number of materials linked.
+ @warn: It is not advisable to use this method unless you know what you
+ are doing; it's possible to
+ corrupt a .blend file if you don't know what you're doing. If you want
+ to change the number of materials, use the L{materials} attribute.
+ """
+
+ def getFlag():
+ """
+ Get the Curve flag value.
+ This item is a bitfield whose value is a combination of the following parameters.
+ - Bit 0 : "3D" is set
+ - Bit 1 : "Front" is set
+ - Bit 2 : "Back" is set
+ - Bit 3 : "CurvePath" is set.
+ - Bit 4 : "CurveFollow" is set.
+
+ @rtype: integer bitfield
+ """
+
+ def setFlag(val):
+ """
+ Set the Curve flag value. The flag corresponds to the Blender settings for 3D, Front, Back, CurvePath and CurveFollow. This parameter is a bitfield.
+ @rtype: None
+ @type val: integer bitfield
+ @param val : The Curve's flag bits. See L{getFlag} for the meaning of the individual bits.
+ """
+
+ def getBevresol():
+ """
+ Get the Curve's bevel resolution value.
+ @rtype: float
+ """
+
+ def setBevresol(bevelresol):
+ """
+ Set the Curve's bevel resolution value.
+ @rtype: None
+ @type bevelresol: float
+ @param bevelresol: The new Curve's bevel resolution value.
+ """
+
+ def getResolu():
+ """
+ Get the Curve's U-resolution value.
+ @rtype: float
+ """
+
+ def setResolu(resolu):
+ """
+ Set the Curve's U-resolution value. [0 - 1024]
+ This is used for surfaces and curves.
+ @rtype: None
+ @type resolu: float
+ @param resolu: The new Curve's U-resolution value.
+ """
+
+ def getResolv():
+ """
+ Get the Curve's V-resolution value.
+ @rtype: float
+ """
+
+ def setResolv(resolv):
+ """
+ Set the Curve's V-resolution value. [0 - 1024].
+ This is used for surfaces only.
+ @rtype: None
+ @type resolv: float
+ @param resolv: The new Curve's V-resolution value.
+ """
+
+ def getWidth():
+ """
+ Get the Curve's width value.
+ @rtype: float
+ """
+
+ def setWidth(width):
+ """
+ Set the Curve's width value.
+ @rtype: None
+ @type width: float
+ @param width: The new Curve's width value.
+ """
+
+ def getExt1():
+ """
+ Get the Curve's ext1 value.
+ @rtype: float
+ """
+
+ def setExt1(ext1):
+ """
+ Set the Curve's ext1 value.
+ @rtype: None
+ @type ext1: float
+ @param ext1: The new Curve's ext1 value.
+ """
+
+ def getExt2():
+ """
+ Get the Curve's ext2 value.
+ @rtype: float
+ """
+
+ def setExt2(ext2):
+ """
+ Set the Curve's ext2 value.
+ @rtype: None
+ @type ext2: float
+ @param ext2: The new Curve's ext2 value.
+ """
+
+ def getControlPoint(numcurve,numpoint):
+ """
+ Get the curve's control point value (B{deprecated}). The numpoint arg
+ is an index into the list of points and starts with 0. B{Note}: new
+ scripts should use the [] operator on Curves and CurNurbs. Example::
+ curve = Blender.Curve.Get('Curve')
+ p0 = curve[0][0] # get first point from first nurb
+ # -- OR --
+ nurb = curve[0] # get first nurb
+ p0 = nurb[0] # get nurb's first point
+
+ @type numcurve: int
+ @type numpoint: int
+ @rtype: list of floats
+ @return: depends upon the curve's type.
+ - type Bezier : a list of nine floats. Values are x, y, z for handle-1, vertex and handle-2
+ - type Nurb : a list of 4 floats. Values are x, y, z, w.
+
+ """
+
+ def setControlPoint( numcurve, numpoint, controlpoint):
+ """
+ Set the Curve's controlpoint value. The numpoint arg is an index into the list of points and starts with 0.
+ @rtype: None
+ @type numcurve: int
+ @type numpoint: int
+ @type controlpoint: list
+ @param numcurve: index for spline in Curve, starting from 0
+ @param numpoint: index for point in spline, starting from 0
+ @param controlpoint: The new controlpoint value.
+ See L{getControlPoint} for the length of the list.
+ """
+
+ def appendPoint( numcurve, new_control_point ):
+ """
+ Add a new control point to the indicated curve (B{deprecated}).
+ New scripts should use L{CurNurb.append()}.
+ @rtype: None
+ @type numcurve: int
+ @type new_control_point: list of floats or BezTriple
+ @param numcurve: index for spline in Curve, starting from 0
+ @param new_control_point: depends on curve's type.
+ - type Bezier: a BezTriple
+ - type Nurb: a list of four or five floats for the xyzw values
+ @raise AttributeError: throws exception if numcurve is out of range.
+ """
+
+ def appendNurb( new_point ):
+ """
+ add a new curve to this Curve. The new point is added to the new curve. Blender does not support a curve with zero points. The new curve is added to the end of the list of curves in the Curve.
+ @rtype: CurNurb
+ @return: the newly added spline
+ @type new_point: BezTriple or list of xyzw coordinates for a Nurb curve.
+ @param new_point: see L{CurNurb.append} for description of parameter.
+ """
+
+ def getLoc():
+ """
+ Get the curve's location value.
+ @rtype: a list of 3 floats.
+ """
+
+ def setLoc(location):
+ """
+ Set the curve's location value.
+ @rtype: None
+ @type location: list[3]
+ @param location: The new Curve's location values.
+ """
+
+ def getRot():
+ """
+ Get the curve's rotation value.
+ @rtype: a list of 3 floats.
+ """
+
+ def setRot(rotation):
+ """
+ Set the Curve's rotation value.
+ @rtype: None
+ @type rotation: list[3]
+ @param rotation: The new Curve's rotation values.
+ """
+
+ def getSize():
+ """
+ Get the curve's size value.
+ @rtype: a list of 3 floats.
+ """
+
+ def setSize(size):
+ """
+ Set the curve size value.
+ @rtype: None
+ @type size: list[3]
+ @param size: The new Curve's size values.
+ """
+
+ def getMaterials():
+ """
+ Returns a list of materials assigned to the Curve.
+ @rtype: list of Material Objects
+ @return: list of Material Objects assigned to the Curve.
+ """
+
+ def getBevOb():
+ """
+ Returns the Bevel Object (BevOb) assigned to the Curve.
+ @rtype: Blender Object or None
+ @return: Bevel Object (BevOb) assigned to the Curve.
+ """
+
+ def setBevOb( object ):
+ """
+ Assign a Bevel Object (BevOb) to the Curve. Passing None as the object parameter removes the bevel.
+ @rtype: None
+ @return: None
+ @type object: Curve type Blender Object
+ @param object: Blender Object to assign as Bevel Object (BevOb)
+ @raise TypeError: throws exception if the parameter is not a Curve type Blender Object or None
+ """
+
+ def getTaperOb():
+ """
+ Returns the Taper Object (TaperOb) assigned to the Curve.
+ @rtype: Blender Object or None
+ @return: Taper Object (TaperOb) assigned to the Curve.
+ """
+
+ def setTaperOb( object ):
+ """
+ Assign a Taper Object (TaperOb) to the Curve. Passing None as the object parameter removes the taper.
+ @rtype: None
+ @return: None
+ @type object: Curve type Blender Object
+ @param object: Blender Object to assign as Taper Object (TaperOb)
+ @raise TypeError: throws exception if the parameter is not a Curve type Blender Object or None
+ """
+
+ def update():
+ """
+ Updates display list for a Curve.
+ Used after making changes to control points.
+ You B{must} use this if you want to see your changes!
+ @rtype: None
+ @return: None
+ """
+
+ def isNurb( curve_num ):
+ """
+ Tells type of a CurNurb (B{deprecated}).
+ New scripts should use L{CurNurb.isNurb()}.
+
+ @rtype: integer
+ @return: Zero if curve is type Bezier, one if curve is of type Nurb.
+ @type curve_num: integer
+ @param curve_num: zero-based index into list of curves in this Curve.
+ @raise AttributeError: throws exception if curve_num is out of range.
+ """
+
+ def isCyclic( curve_num ):
+ """
+ Tells whether or not a CurNurb is cyclic (closed) (B{deprecated}).
+ New scripts should use L{CurNurb.isCyclic()}.
+
+ @rtype: boolean
+ @return: True if is cyclic, False if not
+ @type curve_num: integer
+ @param curve_num: zero-based index into list of curves in this Curve
+ @raise AttributeError: throws exception if curve_num is out of range.
+ """
+
+ def switchDirection( ):
+ """
+ Reverse the direction of a curve.
+ @return: None
+
+ I{B{Example:}}
+ # This example switches the direction of all curves on the active object.
+ from Blender import *
+ scn = Scene.GetCurrent()
+ ob = scn.objects.active # must be a curve
+ data = ob.data
+ for cu in data: cu.switchDirection()
+ """
+
+ def getNumCurves():
+ """
+ Get the number of curves in this Curve Data object.
+ @rtype: integer
+ """
+
+ def getNumPoints( curve_num ):
+ """
+ Get the number of control points in the curve (B{deprecated}).
+ New scripts should use the len operator (I{len(curve)}).
+ @type curve_num: integer
+ @param curve_num: zero-based index into list of curves in this Curve
+ @rtype: integer
+ """
+
+ def getKey():
+ """
+ Return the L{Key<Key.Key>} object containing the keyframes for this
+ curve, if any.
+ @rtype: L{Key<Key.Key>} object or None
+ """
+
+ def recalc():
+ """
+ Recalculate control point handles after a curve has been changed.
+ @rtype: None
+ """
+
+ def __copy__ ():
+ """
+ Make a copy of this curve
+ @rtype: Curve
+ @return: a copy of this curve
+ """
+
+class CurNurb:
+ """
+ The CurNurb Object
+ ==================
+ This object provides access to the control points of the curves that make up a Blender Curve ObData.
+
+ The CurNurb supports the python iterator protocol which means you can use a python for statement to access the points in a curve.
+
+ The CurNurb also supports the sequence protocol which means you can access the control points of a CurNurb using the [] operator.
+
+ Note that CurNurb is used for accesing poly, bezier and nurbs type curves.
+
+ @ivar flagU: The CurNurb knot flag U. See L{setFlagU} for description.
+ @type flagU: int
+ @ivar flagV: The CurNurb knot flag V. See L{setFlagU} for description.
+ @type flagV: int
+ @ivar type: The type of the curve (Poly: 0, Bezier: 1, NURBS: 4)
+ @type type: int
+ @ivar knotsU: The knot vector in the U direction. The tuple will be empty
+ if the curve isn't a NURB or doesn't have knots in this direction.
+ @type knotsU: tuple of floats
+ @ivar knotsV: The knot vector in the V direction. The tuple will be empty
+ if the curve isn't a NURB or doesn't have knots in this direction.
+ @type knotsV: tuple of floats
+ """
+
+ def __setitem__( n, point ):
+ """
+ Replace the Nth point in the curve. The type of the argument must match the type of the curve. List of 4 floats (optional 5th float is the tilt value in radians) for Nurbs or BezTriple for Bezier.
+ @rtype: None
+ @return: None
+ @type n: integer
+ @param n: the index of the element to replace
+ @type point: BezTriple or list of 4 floats (optional 5th float is the tilt value in radians)
+ @param point: the point that will replace the one in the curve. The point can be either a BezTriple type or a list of 4 floats in x,y,z,w (optionally tilt in radians as 5th value) format for a Nurb curve.
+ """
+
+ def __getitem__( n ):
+ """
+ Get the Nth element in the curve. For Bezier curves, that element is a BezTriple. For the rest (Poly and Nurbs), it is a list of 5 floats: x, y, z, weight, tilt (in radians). NOTE 1: This element is independent on the curve, modifying it will not affect the curve. NOTE 2: Each successive call returns a new object.
+ @rtype: BezTriple (Bezier Curve) or List of 5 floats [x, y, z, w, t] for Poly or Nurbs
+ @return: The Nth element in the curve
+ @type n: integer
+ @param n: the index of the element to return
+ """
+
+ def append( new_point ):
+ """
+ Appends a new point to a curve. This method appends points to both Bezier and Nurb curves. The type of the argument must match the type of the curve. List of 4 floats (optional 5th float is the tilt value in radians) for Nurbs or BezTriple for Bezier.
+ @rtype: None
+ @return: None
+ @type new_point: BezTriple or list of 4 floats (optional 5th float is the tilt value in radians)
+ @param new_point: the new point to be appended to the curve. The new point can be either a BezTriple type or a list of 4 floats in x,y,z,w (optionally tilt in radians as 5th value) format for a Nurb curve.
+ """
+
+ def setMatIndex( index ):
+ """
+ Sets the Material index for this CurNurb.
+ @rtype: None
+ @return: None
+ @type index: integer
+ @param index: the new value for the Material number of this CurNurb. No range checking is done.
+ """
+
+ def getMatIndex():
+ """
+ Returns the Material index for this CurNurb.
+ @rtype: integer
+ @return: integer
+ """
+
+ def isNurb():
+ """
+ Boolean method used to determine whether a CurNurb is of type Bezier or of type Nurb.
+ @rtype: boolean
+ @return: True or False
+ """
+
+ def isCyclic():
+ """
+ Boolean method checks whether a CurNurb is cyclic (a closed curve) or not.
+ @rtype: boolean
+ @return: True or False
+ """
+
+ def getFlagU():
+ """
+ Get the CurNurb knot flag U.
+ @rtype: integer
+ @return: See L{setFlagU} for description of return value.
+ """
+
+ def setFlagU( flag ):
+ """
+ Set the entire CurNurb knot flag U (knots are recalculated automatically).
+ The flag can be one of six values:
+ - 0 or 1: uniform knots
+ - 2 or 3: endpoints knots
+ - 4 or 5: bezier knots
+ Bit 0 controls whether or not the curve is cyclic (1 = cyclic).
+ @type flag: integer
+ @param flag: CurNurb knot flag
+ @rtype: None
+ @return: None
+ """
+
+ def getFlagV():
+ """
+ Get the CurNurb knot flag V.
+ @rtype: integer
+ @return: See L{setFlagU} for description of return value.
+ """
+
+ def setFlagV( value ):
+ """
+ Set the CurNurb knot flag V (knots are recalculated automatically).
+ @type value: integer
+ @param value: See L{setFlagU} for description of return.
+ @rtype: None
+ @return: None
+ """
+
+ def getType():
+ """
+ Get the type of the curve.
+ @rtype: integer
+ @return: 0 - Poly, 1 - Bezier, 4 - NURBS
+ """
+
+ def setType( value ):
+ """
+ Set the type of the curve and converts the curve to its new type if needed
+ @type value: integer
+ @param value: CurNurb type flag (0 - Poly, 1 - Bezier, 4 - NURBS)
+ @rtype: None
+ @return: None
+ """
+
+class SurfNurb:
+ """
+ The SurfNurb Object
+ ===================
+ This object provides access to the control points of the surfaces that make
+ up a Blender Curve.
+
+ The SurfNurb supports the Python iterator and sequence protocols which
+ means you can use a python B{for} statement or [] operator to access the
+ points in a surface. Points are accessed linearly; for a N-by-M UV surface,
+ the first N control points correspond to V=0, then second N to V=1, and so
+ on.
+
+ @ivar flagU: The knot flag U. Changing the knot type automatically
+ recalculates the knots. The flag can be one of three values:
+ - 0 : uniform knots
+ - 1 : endpoints knots
+ - 2 : bezier knots
+ @type flagU: int
+ @ivar flagV: The knot flag V. See L{flagU} for description.
+ @type flagV: int
+ @ivar pointsU: The number of control points in the U direction (read only).
+ @type pointsU: int
+ @ivar pointsV: The number of control points in the V direction (read only).
+ @type pointsV: int
+ @ivar cyclicU: The cyclic setting for the U direction (True = cyclic).
+ @type cyclicU: boolean
+ @ivar cyclicV: The cyclic setting for the V direction (True = cyclic).
+ @type cyclicV: boolean
+ @ivar orderU: The order setting for the U direction. Values are clamped
+ to the range [2:6] and not greater than the U dimension.
+ @type orderU: int
+ @ivar orderV: The order setting for the V direction. Values are clamped
+ to the range [2:6] and not greater than the V dimension.
+ @type orderV: int
+ """
+
+ def __setitem__( n, point ):
+ """
+ Set the Nth control point in the surface.
+ @rtype: None
+ @return: None
+ @type n: integer
+ @param n: the index of the point to replace
+ @type point: list of 4 floats (optional 5th float is the tilt value
+ in radians)
+ @param point: the point that will replace the one in the curve. The
+ point is list of 4 floats in x,y,z,w (optionally tilt in radians as
+ 5th value) format.
+ """
+
+ def __getitem__( n ):
+ """
+ Get the Nth control point in the surface.
+ @rtype: List of 5 floats [x, y, z, w, t] for Poly or Nurbs
+ @return: The Nth point in the curve
+ @type n: integer
+ @param n: the index of the point to return
+ @note: This returned value is independent on the curve; modifying it will not affect the curve.
+ @note: Each successive call returns a new object.
+ """
+
diff --git a/source/blender/python/api2_2x/doc/Curvedoc.txt b/source/blender/python/api2_2x/doc/Curvedoc.txt
new file mode 100644
index 00000000000..cb435ff4048
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Curvedoc.txt
@@ -0,0 +1,105 @@
+CURVE Module documentation
+
+
+
+
+INTRODUCTION
+
+The Curve module gives access to the curves objects. Curves are used for many things in blender : creation of graphical objects, duplication of meshes, displacement of meshes, in IPOs for instance.
+Blender has three main types of curves :
+ nurbs curves, each control point has three coordinates.
+ bezier curves, each control point has nine coordinates.
+ text curves, which represent graphical text objects.
+
+
+
+
+
+
+functions of the module :
+
+Get(Name:string) : returns the Curve whose name is Name.
+
+get : same as Get
+
+New(Name:string (optional)) : Creates a new Curve Object.
+If the parameter Name is given, it will be the name of the Curve Object,
+else the name will be choosen by blender.
+
+
+Curve Object member functions :
+
+getName() : Retreives the Curve Object name.
+
+setName(Name : string) : Sets the Curve Object name.
+
+getPathLen() : Retrieves the Curve Object path length.
+
+setPathLen(len:int) : Sets the Curve Object path length.
+
+getTotcol() : Retreives the parameter totcol of the Curve.
+
+setTotcol(val:int) : Sets the parameter totcol
+/*I do not know what means this parameter...*/
+
+getFlag()Retrieves the mode of the Curve Object
+
+setFlag(val:int) :Sets the mode of the Curve.
+
+The mode of the curve is a combination of parameters.
+Bits 0,1,2 : "Back", "Front" and "3D".
+Bit 3 : "CurvePath" is set.
+Bit 4 : "CurveFollow" is set.
+
+getBevresol() : Retreives the bevel resolution of the curve.
+
+setBevresol(val:float) : Sets the bevel resolution of the curve.
+
+getResolu() : Retreives the U-resolution of the curve.
+
+setResolu(val:int) : sets the U-resolution of the curve.
+
+getResolv() : Retreives the V-resolution of the curve.
+
+setResolv(val:int) : sets the V-resolution of the curve.
+
+getWidth() : Retreives the bevel width of the curve.
+
+setWidth(val:float) : Sets the bevel width.
+
+getExt1() : Retreives the bevel height1 of the curve.
+
+setExt1(val:float) : Sets the bevel height1 of the curve.
+
+getExt2() : Retreives the bevel height2 of the curve.
+
+setExt2(val:float) : Sets the bevel height2 of the curve.
+
+getControlPoint(i:int) : Retreives the i-th control point.
+Depending upon the curve type, returne a list of 4(nurbs) or 9(bez) floats.
+
+setControlPoint(i:int, x1:float,...x4:float)
+setControlPoint(i:int, x1:float,...x9:float) : Sets the i-th control point value.
+
+getLoc() : Retreives the Curve location(from the center)
+
+setLoc(x:float,y:float,z:float) : Sets the Curve location
+
+getRot() : Retreives the Curve rotation(from the center)
+
+setRot(x:float,y:float,z:float) : Sets the Curve rotation.
+
+getSize() : Retreives the Curve size.
+
+setSize(x:float,y:float,z:float) : Sets the Curve size.
+
+Direct acces to the parameters values : You cann read and write the parameter XXX with the following syntax :
+val = obj.XXX
+or obj.XXX = val.
+The possible parameters names are :"name","pathlen","resolu","resolv","width","ext1", and "ext2"
+
+
+
+
+
+Submodules : No submodule.
diff --git a/source/blender/python/api2_2x/doc/Draw.py b/source/blender/python/api2_2x/doc/Draw.py
new file mode 100644
index 00000000000..9b6f29b6b51
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Draw.py
@@ -0,0 +1,880 @@
+# Blender.Draw module and the Button PyType object
+
+"""
+The Blender.Draw submodule.
+
+Draw
+====
+
+B{New}:
+ - access to ASCII values in L{events<Register>} callbacks;
+ - 'large' fonts for L{Text} and L{GetStringWidth}.
+ - Pop-up blocks with L{PupBlock}
+ - Color Picker button with L{ColorPicker}
+
+This module provides access to a B{windowing interface} in Blender. Its widgets
+include many kinds of buttons: push, toggle, menu, number, string, slider,
+scrollbar, plus support for text drawing. It also includes keyboard keys and
+mouse button code values in its dictionary, see a list after this example.
+
+Example::
+ import Blender
+ from Blender import Draw, BGL
+
+ mystring = ""
+ mymsg = ""
+ toggle = 0
+
+ def event(evt, val): # the function to handle input events
+ global mystring, mymsg
+
+ if not val: # val = 0: it's a key/mbutton release
+ if evt in [Draw.LEFTMOUSE, Draw.MIDDLEMOUSE, Draw.RIGHTMOUSE]:
+ mymsg = "You released a mouse button."
+ Draw.Redraw(1)
+ return
+
+ if evt == Draw.ESCKEY:
+ Draw.Exit() # exit when user presses ESC
+ return
+
+ elif Draw.AKEY <= evt <= Draw.ZKEY: mystring += chr(evt)
+ elif evt == Draw.SPACEKEY: mystring += ' '
+ elif evt == Draw.BACKSPACEKEY and len(mystring):
+ mystring = mystring[:-1]
+ else: return # no need to redraw if nothing changed
+
+ Draw.Redraw(1)
+
+ def button_event(evt): # the function to handle Draw Button events
+ global mymsg, toggle
+ if evt == 1:
+ mymsg = "You pressed the toggle button."
+ toggle = 1 - toggle
+ Draw.Redraw(1)
+
+ def gui(): # the function to draw the screen
+ global mystring, mymsg, toggle
+ if len(mystring) > 90: mystring = ""
+ BGL.glClearColor(0,0,1,1)
+ BGL.glClear(BGL.GL_COLOR_BUFFER_BIT)
+ BGL.glColor3f(1,1,1)
+ Draw.Toggle("Toggle", 1, 10, 10, 55, 20, toggle,"A toggle button")
+ BGL.glRasterPos2i(72, 16)
+ if toggle: toggle_state = "down"
+ else: toggle_state = "up"
+ Draw.Text("The toggle button is %s." % toggle_state, "small")
+ BGL.glRasterPos2i(10, 230)
+ Draw.Text("Type letters from a to z, ESC to leave.")
+ BGL.glRasterPos2i(20, 200)
+ Draw.Text(mystring)
+ BGL.glColor3f(1,0.4,0.3)
+ BGL.glRasterPos2i(340, 70)
+ Draw.Text(mymsg, "tiny")
+
+ Draw.Register(gui, event, button_event) # registering the 3 callbacks
+
+All available events:
+ - ACCENTGRAVEKEY
+ - AKEY
+ - BACKSLASHKEY
+ - BACKSPACEKEY
+ - BKEY
+ - CAPSLOCKKEY
+ - CKEY
+ - COMMAKEY
+ - DELKEY
+ - DKEY
+ - DOWNARROWKEY
+ - EIGHTKEY
+ - EKEY
+ - ENDKEY
+ - EQUALKEY
+ - ESCKEY
+ - F10KEY
+ - F11KEY
+ - F12KEY
+ - F1KEY
+ - F2KEY
+ - F3KEY
+ - F4KEY
+ - F5KEY
+ - F6KEY
+ - F7KEY
+ - F8KEY
+ - F9KEY
+ - FIVEKEY
+ - FKEY
+ - FOURKEY
+ - GKEY
+ - HKEY
+ - HOMEKEY
+ - IKEY
+ - INPUTCHANGE
+ - INSERTKEY
+ - JKEY
+ - KEYBD
+ - KKEY
+ - LEFTALTKEY
+ - LEFTARROWKEY
+ - LEFTBRACKETKEY
+ - LEFTCTRLKEY
+ - LEFTMOUSE
+ - LEFTSHIFTKEY
+ - LINEFEEDKEY
+ - LKEY
+ - MIDDLEMOUSE
+ - MINUSKEY
+ - MKEY
+ - MOUSEX
+ - MOUSEY
+ - NINEKEY
+ - NKEY
+ - OKEY
+ - ONEKEY
+ - PAD0
+ - PAD1
+ - PAD2
+ - PAD3
+ - PAD4
+ - PAD5
+ - PAD6
+ - PAD7
+ - PAD8
+ - PAD9
+ - PADASTERKEY
+ - PADENTER
+ - PADMINUS
+ - PADPERIOD
+ - PADPLUSKEY
+ - PADSLASHKEY
+ - PAGEDOWNKEY
+ - PAGEUPKEY
+ - PAUSEKEY
+ - PERIODKEY
+ - PKEY
+ - QFULL
+ - QKEY
+ - QUOTEKEY
+ - Q_FIRSTTIME
+ - RAWKEYBD
+ - REDRAW
+ - RETKEY
+ - RIGHTALTKEY
+ - RIGHTARROWKEY
+ - RIGHTBRACKETKEY
+ - RIGHTCTRLKEY
+ - RIGHTMOUSE
+ - RIGHTSHIFTKEY
+ - RKEY
+ - SEMICOLONKEY
+ - SEVENKEY
+ - SIXKEY
+ - SKEY
+ - SLASHKEY
+ - SPACEKEY
+ - TABKEY
+ - THREEKEY
+ - TIMER0
+ - TIMER1
+ - TIMER2
+ - TIMER3
+ - TKEY
+ - TWOKEY
+ - UKEY
+ - UPARROWKEY
+ - VKEY
+ - WHEELDOWNMOUSE
+ - WHEELUPMOUSE
+ - WINCLOSE
+ - WINFREEZE
+ - WINQUIT
+ - WINTHAW
+ - WKEY
+ - XKEY
+ - YKEY
+ - ZEROKEY
+ - ZKEY
+
+@note: function Button has an alias: L{PushButton}.
+
+@warn: B{very important}: if using your script causes "Error totblock"
+messages when Blender exits (meaning that memory has been leaked), this may
+have been caused by an ignored return value from one of the button types. To
+avoid this, assign created buttons return values to B{global} variables,
+instead of ignoring them. Examples::
+
+ # avoid this, it can cause memory leaks:
+ Draw.Toggle(...)
+ Draw.Number(...)
+ Draw.String(...)
+ # this is correct -- assuming the variables are globals:
+ my_toggle_button = Draw.Toggle(...)
+ my_int_button = Draw.Number(...)
+ my_str_button = Draw.String(...)
+
+
+@warn: Inside the windowing loop (after Draw.Register() has been executed and
+before Draw.Exit() is called), don't use the redraw functions from other
+modules (Blender and Window). The Draw submodule has its own Draw.Redraw() and
+Draw.Draw() functions that can be used inside the windowing loop.
+"""
+
+def Exit():
+ """
+ Exit the windowing interface.
+ """
+
+def BeginAlign():
+ """
+ Buttons after this function will draw aligned (button layout only).
+ """
+
+def EndAlign():
+ """
+ Use after BeginAlign() to stop aligning the buttons (button layout only).
+ """
+
+def UIBlock(draw):
+ """
+ This function creates a popup area where buttons, labels, sliders etc can be drawn.
+
+ @type draw: function
+ @param draw: A function to draw to the popup area, taking no arguments: draw().
+
+ @note: The size of the popup will expand to fit the bounds of the buttons created in the draw function.
+ @note: Be sure to use the mouse coordinates to position the buttons under the mouse,
+ so the popup dosn't exit as soon as it opens.
+ The coordinates for buttons start 0,0 at the bottom left hand side of the screen.
+ @note: Within this popup, Redraw events and the registered button callback will not work.
+ For buttons to run events, use per button callbacks.
+ @note: OpenGL drawing functions wont work within this popup, for text use L{Label} rather then L{Text}
+ @warning: L{Menu} will not work properly within a UIBlock, this is a limitation with blenders user interface internals.
+ """
+
+def Register(draw = None, event = None, button = None):
+ """
+ Register callbacks for windowing.
+ @type draw: function
+ @type event: function
+ @type button: function
+ @param draw: A function to draw the screen, taking no arguments: draw().
+ @param event: A function to handle keyboard and mouse input events, taking
+ two arguments: f(evt, val), where:
+ - 'evt' (int) is the event number;
+ - 'val' (int) is the value modifier. If val = 0, the event refers to a
+ key or mouse button being released. Otherwise it's a key/button press.
+ @param button: A function to handle Draw Button events, taking one argument:
+ f(evt), where:
+ - 'evt' is the button number (see the I{event} parameter in L{Button}).
+ @note: note that in the example at the beginning of this page Draw.Register
+ is called only once. It's not necessary to re-register the callbacks,
+ they will stay until Draw.Exit is called. It's enough to redraw the
+ screen, when a relevant event is caught.
+ @note: only during the B{event} callback: the L{Blender}.ascii variable holds
+ the ASCII integer value (if it exists and is valid) of the current event.
+ """
+
+def Redraw(after = 0):
+ """
+ Queue a redraw event. Redraw events are buffered so that, regardless of how
+ many events are queued, the window only receives one redraw event.
+ @type after: int
+ @param after: If non-zero, the redraw is processed before other input events.
+ """
+
+def Draw():
+ """
+ Force an immediate redraw. Forced redraws are not buffered. In other words,
+ the window is redrawn once every time this function is called.
+ """
+
+def Create(value):
+ """
+ Create a default Button object.
+ @type value: int, float, string or 3 floats
+ @param value: The value to store in the button.
+ @rtype: Blender Button
+ @return: The Button created.
+ @note: String values must have less then 400 characters.
+ """
+
+def PushButton(name, event, x, y, width, height, tooltip = None, callback = None):
+ """
+ Create a new (push) Button object.
+ @type name: string
+ @param name: The string to display on the button.
+ @type event: int
+ @param event: The event number to pass to the button event function when
+ activated.
+ @type x: int
+ @type y: int
+ @param x: The lower left x (horizontal) coordinate of the button.
+ @param y: The lower left y (vertical) coordinate of the button.
+ @type width: int
+ @type height: int
+ @param width: The button width.
+ @param height: The button height.
+ @type tooltip: string
+ @param tooltip: The button's tooltip (the string that appears when the mouse
+ is kept over the button).
+ @type callback: function
+ @param callback: an optional argument so this button can have its own
+ callback function. the function will run whenever this button is pressed.
+ This function must accept 2 arguments (event, val).
+ @note: This function used to be called only "Button". We added an
+ alternative alias to avoid a name clash with the L{Button} class/type that
+ caused trouble in this documentation's generation. The old name shouldn't
+ be deprecated, use Button or PushButton (better) at your choice.
+ """
+
+def PupMenu(name, maxrow = None):
+ """
+ Create a pop-up menu.
+
+ The menu options are specified through the 'name' parameter, like with
+ L{Menu}: options are followed by a format code and separated by the '|'
+ character. Valid format codes are:
+ - %t - The option should be used as the title of the pop-up;
+ - %l - insert a separating line (only works if 'maxrow' isn't given);
+ - %xB{N} - Chosen this option, PupMenu should return the integer B{N}.
+
+ Example::
+ name = "OK?%t|QUIT BLENDER" # if no %xN int is set, indices start from 1
+ result = Draw.PupMenu(name)
+ if result:
+ Draw.PupMenu("Really?%t|Yes|No")
+
+ @type name: string
+ @param name: The format string to define the contents of the button.
+ @type maxrow: int
+ @param maxrow: The maximum number of rows for each column in the pop-up.
+ @rtype: int
+ @return: the chosen entry number or -1 if none was chosen.
+ """
+
+def PupIntInput(text, default, min, max):
+ """
+ Create an integer number input pop-up.
+
+ This allows python to use Blender's integer number pop-up input.
+
+ Example::
+ default = 50
+ min = 0
+ max = 100
+
+ msg = "Set this value between 0 and 100"
+ result = Draw.PupIntInput(msg, default, min, max)
+ if result != None:
+ print result
+ else:
+ print 'no user input'
+
+ @type text: string
+ @param text: The text that is displayed in the pop-up.
+ @type default: int
+ @param default: The value that the pop-up is set to initially.
+ @type min: int
+ @param min: The lowest value the pop-up will allow.
+ @type max: int
+ @param max: The highest value the pop-up will allow.
+ @rtype: int
+ @return: the number chosen or None if none was chosen.
+ """
+
+def PupFloatInput(text, default, min, max, clickStep, floatLen):
+ """
+ Create a floating point number input pop-up.
+
+ This allows python to use Blender's floating point pop-up input.
+
+ Example::
+ default = 50
+ min = 0.0
+ max = 10.0
+ clickStep = 100
+ floatLen = 3
+
+ msg = "Set this value between 0 and 100"
+ result = Draw.PupFloatInput(msg, default, min, max, clickStep, floatLen)
+ if result != None:
+ print result
+ else:
+ print 'no user input'
+
+ @type text: string
+ @param text: The text that is displayed in the pop-up.
+ @type default: float
+ @param default: The value that the pop-up is set to initially.
+ @type min: float
+ @param min: The lowest value the pop-up will allow.
+ @type max: float
+ @param max: The highest value the pop-up will allow.
+ @type clickStep: int
+ @param clickStep: How much is incremented per user click, 100 will increment 1.0, 10 will increment 0.1 etc.
+ @type floatLen: int
+ @param floatLen: The number of decimal places to display, between 2 and 4.
+ @rtype: float
+ @return: the number chosen or None if none was chosen.
+ """
+
+def PupStrInput(text, default, max = 20):
+ """
+ Create a string input pop-up.
+
+ This allows python to use Blender's string pop-up input.
+
+ Example::
+ Blender.Draw.PupStrInput("Name:", "untitled", 25)
+
+ @type text: string
+ @param text: The text that is displayed in the pop-up.
+ @type default: string
+ @param default: The value that the pop-up is set to initially. If it's longer
+ then 'max', it's truncated.
+ @type max: int
+ @param max: The most characters the pop-up input will allow. If not given
+ it defaults to 20 chars. It should be in the range [1, 100].
+ @rtype: string
+ @return: The text entered by the user or None if none was chosen.
+ """
+
+def PupBlock(title, sequence):
+ """
+ Display a pop-up block.
+
+ Possible formats for the items in the sequence parameter.
+ (Value are objects created with L{Create})
+ - string: Defines a label
+ - (string, Value, string): Defines a toggle button. The first string is the text on the button, the optional second string is the tooltip.
+ - (string, Value, min, max, string): Defines a numeric or string button, depending on the content of Value. The first string is the text on the button, the optional second string is the tooltip. I{For string, max is the maximum length of the string and min is unused.}
+
+ Example::
+ import Blender
+
+ text = Blender.Draw.Create("short text")
+ f = Blender.Draw.Create(1.0)
+ i = Blender.Draw.Create(2)
+ tog = Blender.Draw.Create(0)
+
+ block = []
+
+ block.append(("Name: ", text, 0, 30, "this is some tool tip"))
+ block.append("Some Label")
+ block.append(("Value: ", f, 0.0, 100.0))
+ block.append(("Value: ", i, 0, 100))
+ block.append(("Option", tog, "another tooltip"))
+
+ retval = Blender.Draw.PupBlock("PupBlock test", block)
+
+ print "PupBlock returned", retval
+
+ print "text\\t", text
+ print "float\\t", f
+ print "int\\t", i
+ print "toggle\\t", tog
+
+ @warning: On cancel, the Value objects are brought back to there initial values except for string values which will still contain the modified values.
+ @type title: string
+ @param title: The title of the block.
+ @param sequence: A sequence defining what the block contains.
+ The order of the list is the order of appearance, from top down.
+ @rtype: int
+ @return: 1 if the pop-up is confirmed, 0 otherwise
+ """
+
+def Menu(name, event, x, y, width, height, default, tooltip = None, callback = None):
+ """
+ Create a new Menu Button object.
+
+ The menu options are specified through the 'name' of the button. Options are
+ I{followed} by a format code and separated by the '|' (pipe) character. Valid
+ format codes are:
+ - %t - The option should be used as the title;
+ - %l - Insert a separating line;
+ - %xB{N} - The option should set the integer B{N} in the button value.
+
+ Example::
+ name = "The Title %t|First Entry %x1|Second Entry %x2|Third Entry %x3"
+ menu = Draw.Menu(name, 2, 60, 120, 200, 40, 3, "Just a test menu.")
+ # note that, since default = 3, the "Third Entry"
+ # will appear as the default choice in the Menu.
+
+ @type name: string
+ @param name: The format string to define the contents of the button.
+ @type event: int
+ @param event: The event number to pass to the button event function when
+ activated.
+ @type x: int
+ @type y: int
+ @param x: The lower left x (horizontal) coordinate of the button.
+ @param y: The lower left y (vertical) coordinate of the button.
+ @type width: int
+ @type height: int
+ @param width: The button width.
+ @param height: The button height.
+ @type default: int
+ @param default: The number of the option to be selected by default.
+ @type tooltip: string
+ @param tooltip: The button's tooltip (the string that appears when the mouse
+ is kept over the button).
+ @type callback: function
+ @param callback: an optional argument so this button can have its own
+ callback function. the function will run whenever this button is pressed.
+ This function must accept 2 arguments (event, val).
+ @rtype: Blender Button
+ @return: The Button created.
+ """
+
+def Toggle(name, event, x, y, width, height, default, tooltip = None, callback = None):
+ """
+ Create a new Toggle Button object.
+ @type name: string
+ @param name: The string to display on the button.
+ @type event: int
+ @param event: The event number to pass to the button event function when
+ activated.
+ @type x: int
+ @type y: int
+ @param x: The lower left x (horizontal) coordinate of the button.
+ @param y: The lower left y (vertical) coordinate of the button.
+ @type width: int
+ @type height: int
+ @param width: The button width.
+ @param height: The button height.
+ @type default: int
+ @param default: The value specifying the default state:
+ (0 for "up", 1 for "down").
+ @type tooltip: string
+ @param tooltip: The button's tooltip (the string that appears when the mouse
+ is kept over the button).
+ @type callback: function
+ @param callback: an optional argument so this button can have its own
+ callback function. the function will run whenever this button is pressed.
+ This function must accept 2 arguments (event, val).
+ @rtype: Blender Button
+ @return: The Button created.
+ """
+
+def Slider(name, event, x, y, width, height, initial, min, max, realtime = 1,
+ tooltip = None, callback = None):
+ """
+ Create a new Slider Button object.
+ @type name: string
+ @param name: The string to display on the button.
+ @type event: int
+ @param event: The event number to pass to the button event function when
+ activated.
+ @type x: int
+ @type y: int
+ @param x: The lower left x (horizontal) coordinate of the button.
+ @param y: The lower left y (vertical) coordinate of the button.
+ @type width: int
+ @type height: int
+ @param width: The button width.
+ @param height: The button height.
+ @type initial: int or float
+ @type min: int or float
+ @type max: int or float
+ @param initial: The initial value.
+ @param min: The minimum value.
+ @param max: The maximum value.
+ @type realtime: int
+ @param realtime: If non-zero (the default), the slider will emit events as
+ it is edited.
+ @type tooltip: string
+ @param tooltip: The button's tooltip (the string that appears when the mouse
+ is kept over the button).
+
+ @type callback: function
+ @param callback: an optional argument so this button can have its own
+ callback function. the function will run whenever this button is pressed.
+ This function must accept 2 arguments (event, val).
+ @rtype: Blender Button
+ @return: The Button created.
+ @note: slider callbacks will not work if the realtime setting is enabled.
+ """
+
+#def Scrollbar(event, x, y, width, height, initial, min, max, realtime = 1,
+# tooltip = None):
+# """
+# Create a new Scrollbar Button object.
+# @type event: int
+# @param event: The event number to pass to the button event function when
+# activated.
+# @type x: int
+# @type y: int
+# @param x: The lower left x (horizontal) coordinate of the button.
+# @param y: The lower left y (vertical) coordinate of the button.
+# @type width: int
+# @type height: int
+# @param width: The button width.
+# @param height: The button height.
+# @type initial: int or float
+# @type min: int or float
+# @type max: int or float
+# @param initial: The initial value.
+# @param min: The minimum value.
+# @param max: The maximum value.
+# @type realtime: int
+# @param realtime: If non-zero (the default), the slider will emit events as
+# it is edited.
+# @type tooltip: string
+# @param tooltip: The button's tooltip (the string that appears when the mouse
+# is kept over the button).
+# @rtype: Blender Button
+# @return: The Button created.
+# """
+
+def ColorPicker(event, x, y, width, height, initial, tooltip = None, callback = None):
+ """
+ Create a new Color Picker Button object.
+ @type event: int
+ @param event: The event number to pass to the button event function when
+ activated.
+ @type x: int
+ @type y: int
+ @param x: The lower left x (horizontal) coordinate of the button.
+ @param y: The lower left y (vertical) coordinate of the button.
+ @type width: int
+ @type height: int
+ @param width: The button width.
+ @param height: The button height.
+ @type initial: 3-float tuple
+ @param initial: The initial color value. All values must be between 0 and 1
+ @type tooltip: string
+ @param tooltip: The button's tooltip (the string that appears when the mouse
+ is kept over the button).
+ @type callback: function
+ @param callback: an optional argument so this button can have its own
+ callback function. the function will run whenever this button is pressed.
+ This function must accept 2 arguments (event, val).
+ @rtype: Blender Button
+ @return: The Button created.
+ @note: The color picker will not work if the Register's event function is None.
+ @note: Using the same button variable with more then 1 button at a time will corrupt memory.
+ """
+
+def Normal(event, x, y, width, height, initial, tooltip = None, callback = None):
+ """
+ Create a new Normal button, this allows you to set a 3d vector by rotating a sphere.
+ @type event: int
+ @param event: The event number to pass to the button event function when
+ activated.
+ @type x: int
+ @type y: int
+ @param x: The lower left x (horizontal) coordinate of the button.
+ @param y: The lower left y (vertical) coordinate of the button.
+ @type width: int
+ @type height: int
+ @param width: The button width - non square normal buttons .
+ @param height: The button height.
+ @type initial: 3-float tuple
+ @param initial: The initial vector value.
+ @type tooltip: string
+ @param tooltip: The button's tooltip (the string that appears when the mouse
+ is kept over the button).
+ @type callback: function
+ @param callback: an optional argument so this button can have its own
+ callback function. the function will run whenever this button is pressed.
+ This function must accept 2 arguments (event, val).
+ @rtype: Blender Button
+ @return: The Button created.
+ @note: The normal button will not work if the Register's event function is None.
+ @note: Using the same button variable with more then 1 button at a time will corrupt memory.
+ """
+
+def Number(name, event, x, y, width, height, initial, min, max, tooltip = None, callback = None):
+ """
+ Create a new Number Button object.
+ @type name: string
+ @param name: The string to display on the button.
+ @type event: int
+ @param event: The event number to pass to the button event function when
+ activated.
+ @type x: int
+ @type y: int
+ @param x: The lower left x (horizontal) coordinate of the button.
+ @param y: The lower left y (vertical) coordinate of the button.
+ @type width: int
+ @type height: int
+ @param width: The button width.
+ @param height: The button height.
+ @type initial: int or float
+ @type min: int or float
+ @type max: int or float
+ @param initial: The initial value.
+ @param min: The minimum value.
+ @param max: The maximum value.
+ @type tooltip: string
+ @param tooltip: The button's tooltip (the string that appears when the mouse
+ is kept over the button).
+ @type callback: function
+ @param callback: an optional argument so this button can have its own
+ callback function. the function will run whenever this button is pressed.
+ This function must accept 2 arguments (event, val).
+ @rtype: Blender Button
+ @return: The Button created.
+
+ I{B{Example:}}
+
+ This example draws a single floating point value::
+ from Blender import Draw
+ b= Draw.Create(0.0) # Data for floating point button
+ def bevent(evt):
+ print 'My Button event:', evt
+ def gui():
+ global b
+ b= Draw.Number('value: ', 1000, 0,0, 200, 20, b.val, 0,10, 'some text tip')
+
+ Draw.Register(gui, None, bevent) # we are not going to worry about keyboard and mouse events
+ """
+
+
+def String(name, event, x, y, width, height, initial, length, tooltip = None, callback = None):
+ """
+ Create a new String Button object.
+ @type name: string
+ @param name: The string to display on the button.
+ @type event: int
+ @param event: The event number to pass to the button event function when
+ activated.
+ @type x: int
+ @type y: int
+ @param x: The lower left x (horizontal) coordinate of the button.
+ @param y: The lower left y (vertical) coordinate of the button.
+ @type width: int
+ @type height: int
+ @param width: The button width.
+ @param height: The button height.
+ @type initial: string
+ @param initial: The string to display initially.
+ @type length: int
+ @param length: The maximum input length.
+ @type tooltip: string
+ @param tooltip: The button's tooltip (the string that appears when the mouse
+ is kept over the button).
+ @type callback: function
+ @param callback: an optional argument so this button can have its own
+ callback function. the function will run whenever this button is pressed.
+ This function must accept 2 arguments (event, val).
+ @rtype: Blender Button
+ @return: The Button created.
+ """
+
+def GetStringWidth(string, fontsize = 'normal'):
+ """
+ Get the width in pixels of a string.
+ @type string: string
+ @param string: A string.
+ @type fontsize: string
+ @param fontsize: The size of the font: 'large', 'normal', 'small' or 'tiny'.
+ @rtype: int
+ @return: The width of I{string} with the chosen I{fontsize}.
+ """
+
+def Text(string, fontsize = 'normal'):
+ """
+ Draw a string on the screen.
+
+ Text location is set using the OpenGL raster location functions L{BGL.glRasterPos} before the text is drawn.
+ This sets the text location from the lower left corner of the current window.
+
+ Text color is set using the OpenGL color functions L{BGL.glColor} before the text is drawn.
+
+ @type string: string
+ @param string: The text string to draw.
+ @type fontsize: string
+ @param fontsize: The size of the font: 'large', 'normal', 'small' or 'tiny'.
+ @rtype: int
+ @return: The width of I{string} drawn with the chosen I{fontsize}.
+ @note: For drawing text in the 3d view see the workaround in L{BGL.glRasterPos}
+ """
+
+def Label(string, x, y, w, h):
+ """
+ Draw a text lable on the screen.
+
+ @type string: string
+ @param string: The text string to draw.
+ @rtype: None
+ @return: None
+ """
+
+def Image(image, x, y, zoomx=1.0, zoomy=1.0, clipx=0, clipy=0, clipw=-1, cliph=-1):
+ """
+ Draw an image on the screen.
+
+ The image is drawn at the location specified by the coordinates (x,y). A
+ pair of optional zoom factors (in horizontal and vertical directions) can
+ be applied to the image as it is drawn, and an additional clipping rectangle
+ can be applied to extract a particular sub-region of the image to draw.
+
+ Note that the clipping rectangle is given in image space coordinates. In
+ image space, the origin is located at the bottom left, with x coordinates
+ increasing to the right and y coordinates increasing upwards. No matter
+ where the clipping rectangle is placed in image space, the lower-left pixel
+ drawn on the screen is always placed at the coordinates (x,y). The
+ clipping rectangle is itself clipped to the dimensions of the image. If
+ either the width or the height of the clipping rectangle are negative then
+ the corresponding dimension (width or height) is set to include as much of
+ the image as possible.
+
+ For drawing images with alpha blending with the background you will need to enable blending as shown in the example.
+
+ Example::
+ import Blender
+ from Blender import BGL, Image, Draw
+
+ myimage = Image.Load('myimage.png')
+
+ def gui():
+ BGL.glEnable( BGL.GL_BLEND ) # Only needed for alpha blending images with background.
+ BGL.glBlendFunc(BGL.GL_SRC_ALPHA, BGL.GL_ONE_MINUS_SRC_ALPHA)
+
+ Draw.Image(myimage, 50, 50)
+
+ BGL.glDisable( BGL.GL_BLEND )
+ def event(evt, val):
+ if evt == Draw.ESCKEY:
+ Draw.Exit()
+
+ Draw.Register(gui, event, None)
+
+ @type image: Blender.Image
+ @param image: The image to draw.
+ @type x: int
+ @param x: The lower left x (horizontal) position of the origin of the image.
+ @type y: int
+ @param y: The lower left y (vertical) position of the origin of the image.
+ @type zoomx: float
+ @param zoomx: The x (horizontal) zoom factor to use when drawing the image.
+ @type zoomy: float
+ @param zoomy: The y (vertical) zoom factor to use when drawing the image.
+ @type clipx: int
+ @param clipx: The lower left x (horizontal) origin of the clipping rectangle
+ within the image. A value of 0 indicates the left of the
+ image.
+ @type clipy: int
+ @param clipy: The lower left y (vertical) origin of the clipping rectangle
+ within the image. A value of 0 indicates the bottom of the
+ image.
+ @type clipw: int
+ @param clipw: The width of the clipping rectangle within the image. If this
+ value is negative then the clipping rectangle includes as much
+ of the image as possible in the x (horizontal) direction.
+ @type cliph: int
+ @param cliph: The height of the clipping rectangle within the image. If this
+ value is negative then the clipping rectangle includes as much
+ of the image as possible in the y (vertical) direction.
+ """
+
+class Button:
+ """
+ The Button object
+ =================
+ This object represents a button in Blender's GUI.
+ @type val: int or float, string or 3-float tuple (depends on button type).
+ @ivar val: The button's value.
+ """
diff --git a/source/blender/python/api2_2x/doc/Effect.py b/source/blender/python/api2_2x/doc/Effect.py
new file mode 100644
index 00000000000..70f4287ae36
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Effect.py
@@ -0,0 +1,590 @@
+# Blender.Effect module and the Effect PyType effect
+
+"""
+The Blender.Effect submodule
+
+B{new}: now L{Get}('objname') (without specifying second parameter: 'position') returns a list of all effects linked to object "objname".
+
+Effect
+======
+
+INTRODUCTION
+
+The Effect module allows you to access all the data of particle effects.
+An effect can modify a mesh object using particles, where vertex of
+the mesh emits particles, which can themselves emit new particles.
+
+In the Blender internals, the effect object is just a placeholder for
+the particle effect. Prior to v2.39 build and wave effects were also
+supported by Blender, and the Python API supported all three types of
+effects. They were removed in v2.39 when the build and wave modifiers
+were implemented.
+
+
+Example::
+ import Blender
+ listffects = Blender.Effect.Get()
+ print listeffects
+ eff = listeffects[0]
+ #we suppose the first effect is a build effect
+ print eff.getLen()
+ eff.setLen(500)
+
+@type Flags: read-only dictionary
+@var Flags: The particle effect flags. Values can be ORed.
+ - SELECTED: The particle effect is selected in the UI. (Read-only)
+ - BSPLINE: Use a B-spline formula for particle interpolation
+ - STATIC: Make static particles
+ - ANIMATED: Recalculate static particles for each rendered frame
+ - VERTS: Emit particles from vertices
+ - FACES: Emit particles from faces
+ - EVENDIST: Use even distribution based on face area (requires FACES)
+ - TRUERAND: Use true random distribution based on face area (requires FACES)
+ - UNBORN: Make particles appear before they are emitted
+ - DIED: Make particles appear after they have died
+ - EMESH: Render emitter mesh
+
+@type SpeedTypes: read-only dictionary
+@var SpeedTypes: The available settings for selecting particle speed vectors.
+Only one setting is active at a time.
+ - INTENSITY: Use texture intensity
+ - RGB: Use RGB values
+ - GRADIENT: Use texture gradient
+"""
+
+def New (name):
+ """
+ Creates a new particle effect and attaches to an object.
+ @type name: string
+ @param name: The name of object to associate with the effect. Only mesh
+ objects are supported.
+ @rtype: Blender Effect
+ @return: the new effect
+ """
+
+def Get (name = None, position = None):
+ """
+ Get an Effect from Blender.
+ @type name: string
+ @param name: The name of object linked to the effect.
+ @type position: int
+ @param position: The position of the effect in the list of effects linked to the object.
+ @rtype: Blender Effect or a list of Blender Effects
+ @return: It depends on the 'objname, position' parameters:
+ - (): A list with all Effects in the current scene;
+ - (name): A list with all Effects linked to the given object;
+ - (name, position): The Effect linked to the given object at the given position
+ """
+
+class Effect:
+ """
+ The Effect object
+ =================
+ This object gives access to particle effect data in Blender.
+
+ @ivar child: The number of children a particle may have.
+ Values are clamped to the range [1,600].
+ @type child: tuple of 4 ints
+ @ivar childMat: The materials used by the 4 generation particles.
+ Values are clamped to the range [1,16].
+ @type childMat: tuple of 4 ints
+ @ivar damping: The particle damping factor. This controls the rate at
+ which particles decelerate.
+ Values are clamped to the range [0.0,1.0].
+ @type damping: float
+ @ivar defvec: The x, y and z axis of the force defined by the texture.
+ Values are clamped to the range [-1.0,1.0].
+ @type defvec: tuple of 3 floats
+ @ivar disp: The percentage of particles displayed.
+ Value is clamped to the range [0,100].
+ @type disp: int
+ @ivar dispMat: The material used for the particles.
+ Value is clamped to the range [1,16].
+ @type dispMat: int
+ @ivar emissionTex: The texture used for texture emission.
+ Value is clamped to the range [1,10].
+ @type emissionTex: int
+ @ivar end: The end time of the effect.
+ Value is clamped to the range [1.0,30000.0].
+ @type end: float
+ @ivar flag: The flag bitfield. See L{Flags} for values.
+ @type flag: int
+ @ivar force: The constant force applied to the parts.
+ Values are clamped to the range [-1.0,1.0].
+ @type force: tuple of 3 floats
+ @ivar forceTex: The texture used for force.
+ Value is clamped to the range [1,10].
+ @type forceTex: int
+ @ivar jitter: Jitter table distribution: maximum particles per face.
+ Values are clamped to the range [0,200].
+ @type jitter: int
+ @ivar life: The lifetime of of the next generation of particles.
+ Values are clamped to the range [1.0,30000.0].
+ @type life: tuple of 4 floats
+ @ivar lifetime: The lifetime of the effect.
+ Value is clamped to the range [1.0,30000.0].
+ @type lifetime: float
+ @ivar mult: The probabilities of a particle having a child.
+ Values are clamped to the range [0.0,1.0].
+ @type mult: tuple of 4 floats
+ @ivar nabla: The nabla value.
+ Value is clamped to the range [0.0001,1.0].
+ @type nabla: float
+ @ivar normfac: The normal strength of the particles relative to mesh.
+ Value is clamped to the range [-2.0,2.0].
+ @type normfac: float
+ @ivar obfac: The strength of the particles relative to objects.
+ Value is clamped to the range [-1.0,1.0].
+ @type obfac: float
+ @ivar randfac: The initial random speed of the particles.
+ Value is clamped to the range [0.0,2.0].
+ @type randfac: float
+ @ivar randlife: The variability of the life of the particles.
+ Value is clamped to the range [0.0,2.0].
+ @type randlife: float
+ @ivar seed: The seed of the random number generator.
+ Value is clamped to the range [0,255].
+ @type seed: int
+ @ivar speedType: Controls which texture property affects particle speeds.
+ See L{SpeedTypes} for values and their meanings.
+ @type speedType: int
+ @ivar speedVGroup: The name of the vertex group used for speed control.
+ @type speedVGroup: str
+ @ivar sta: The start time of the effect.
+ Value is clamped to the range [-250.0,30000.0].
+ @type sta: float
+ @ivar staticStep: percentage of skipped particles in static display.
+ Value is clamped to the range [1,100].
+ @type staticStep: int
+ @ivar stype: The bitfield for vector.
+ @type stype: int
+ @ivar texfac: The initial speed of the particles caused by the texture.
+ Value is clamped to the range [0.0,2.0].
+ @type texfac: float
+ @ivar totpart: The total number of particles.
+ Value is clamped to the range [1,100000].
+ @type totpart: int
+ @ivar totkey: The total number of key positions.
+ Value is clamped to the range [1,100].
+ @type totkey: int
+ @ivar type: The type of the effect. Deprecated.
+ @type type: int
+ @ivar vectsize: The size of vectors associated to the particles (if any).
+ Value is clamped to the range [0.0,1.0].
+ @type vectsize: float
+ @ivar vGroup: The name of the vertex group used for emitted particles.
+ @type vGroup: str
+ """
+
+ def getType():
+ """
+ Retrieves the type of an effect object.
+ Deprecated, since only particle effects are supported.
+ @rtype: int
+ @return: the type of an effect object : should always return 1
+ (particle effect)
+ """
+
+ def setType(name):
+ """
+ Deprecated, since only particle effects are supported.
+ @type name: int
+ @param name : the new type.
+ @rtype: None
+ @return: None
+ """
+
+ def getFlag():
+ """
+ Retrieves the flag of an effect object. The flag is a bit-mask.
+ @rtype: int
+ @return: The flag of the effect is a combination of parameters. See
+ L{Flags} for values.
+
+ """
+
+ def setFlag(newflag):
+ """
+ Sets the flag of an effect object. See L{Flags} for values.
+ @type newflag: int
+ @param newflag: the new flag.
+ @rtype: None
+ @return: None
+ """
+
+ def getStartTime():
+ """
+ Retrieves the starting time of a particle effect object
+ @rtype: float
+ @return: the starting time of the effect.
+ """
+
+ def setSta(newstart):
+ """
+ Sets the starting time of an particle effect object
+ @type newstart: float
+ @param newstart: the new starting time.
+ @rtype: None
+ @return: None
+ """
+
+ def getEndTime():
+ """
+ Retrieves the end time of a particle effect object
+ @rtype: float
+ @return: the end time of the effect.
+ """
+
+ def setEnd(newendrt):
+ """
+ Sets the end time of an particle effect object
+ @type newendrt: float
+ @param newendrt: the new end time.
+ @rtype: None
+ @return: None
+ """
+
+ def getLifetime():
+ """
+ Retrieves the lifetime of a particle effect object
+ @rtype: float
+ @return: the lifetime of the effect.
+ """
+
+
+ def setLifetime(newlifetime):
+ """
+ Sets the lifetime of a particle effect object
+ @type newlifetime: float
+ @param newlifetime: the new lifetime.
+ @rtype: None
+ @return: None
+ """
+
+ def getNormfac():
+ """
+ Retrieves the normal strength of the particles (relatively to mesh).
+ @rtype: float
+ @return: normal strength of the particles (relatively to mesh).
+ """
+
+ def setNormfac(newnormfac):
+ """
+ Sets the normal strength of the particles (relatively to mesh).
+ @type newnormfac: float
+ @param newnormfac: the normal strength of the particles (relatively to mesh).
+ @rtype: None
+ @return: None
+ """
+
+ def getObfac():
+ """
+ Retrieves the initial strength of the particles relatively to objects.
+ @rtype: float
+ @return: initial strength of the particles (relatively to mesh).
+ """
+
+ def setObfac(newobfac):
+ """
+ Sets the initial strength of the particles relatively to objects.
+ @type newobfac: float
+ @param newobfac: the initial strength of the particles relatively to objects.
+ @rtype: None
+ @return: None
+ """
+
+ def getRandfac():
+ """
+ Retrieves the random strength applied to the particles.
+ @rtype: float
+ @return: random strength applied to the particles.
+ """
+
+ def setRandfac(newrandfac):
+ """
+ Sets the random strength applied to the particles.
+ @type newrandfac: float
+ @param newrandfac: the random strength applied to the particles.
+ @rtype: None
+ @return: None
+ """
+
+ def getStype():
+ """
+ Retrieves the vect state of an effect object.
+ @rtype: int
+ @return: the Stype (Vect) of an effect object : 0 , Vect is not enabled, 1, Vect is enabled
+ (particle effect)
+ """
+
+ def setStype(int):
+ """
+ @type int : int
+ @param int : state of the Stype : 0 not enabled, 1 enabled.
+ @rtype: None
+ @return: None
+ """
+
+ def getTexfac():
+ """
+ Retrieves the strength applied to the particles from the texture of the object.
+ @rtype: float
+ @return: strength applied to the particles from the texture of the object.
+ """
+
+ def setTexfac(newtexfac):
+ """
+ Sets the strength applied to the particles from the texture of the object.
+ @type newtexfac: float
+ @param newtexfac: the strength applied to the particles from the texture of the object.
+ @rtype: None
+ @return: None
+ """
+
+ def getRandlife():
+ """
+ Retrieves the variability of the life of the particles.
+ @rtype: float
+ @return: variability of the life of the particles.
+ """
+
+ def setRandlife(newrandlife):
+ """
+ Sets the variability of the life of the particles.
+ @type newrandlife: float
+ @param newrandlife: the variability of the life of the particles.
+ @rtype: None
+ @return: None
+ """
+
+ def getNabla():
+ """
+ Retrieves the sensibility of the particles to the variations of the texture.
+ @rtype: float
+ @return: sensibility of the particles to the variations of the texture.
+ """
+
+
+ def setNabla(newnabla):
+ """
+ Sets the sensibility of the particles to the variations of the texture.
+ @type newnabla: float
+ @param newnabla: the sensibility of the particles to the variations of the texture.
+ @rtype: None
+ @return: None
+ """
+
+ def getVectsize():
+ """
+ Retrieves the size of the vector which is associated to the particles.
+ @rtype: float
+ @return: size of the vector which is associated to the particles.
+ """
+
+
+ def setVectsize(newvectsize):
+ """
+ Sets the size of the vector which is associated to the particles.
+ @type newvectsize: float
+ @param newvectsize: the size of the vector which is associated to the particles.
+ @rtype: None
+ @return: None
+ """
+
+ def getTotpart():
+ """
+ Retrieves the total number of particles.
+ @rtype: int
+ @return: the total number of particles.
+ """
+
+
+ def setTotpart(newtotpart):
+ """
+ Sets the the total number of particles.
+ @type newtotpart: int
+ @param newtotpart: the the total number of particles.
+ @rtype: None
+ @return: None
+ """
+
+ def getTotkey():
+ """
+ Retrieves the number of keys associated to the particles (kind of degree of freedom)
+ @rtype: int
+ @return: number of keys associated to the particles.
+ """
+
+ def setTotkey(newtotkey):
+ """
+ Sets the number of keys associated to the particles.
+ @type newtotkey: int
+ @param newtotkey: number of keys associated to the particles.
+ @rtype: None
+ @return: None
+ """
+
+ def getSeed():
+ """
+ Retrieves the random number generator seed.
+ @rtype: int
+ @return: current seed value.
+ """
+
+ def setSeed(newseed):
+ """
+ Sets the random number generator seed.
+ @type newseed: int
+ @param newseed: new seed value.
+ @rtype: None
+ @return: None
+ """
+
+ def getForce():
+ """
+ Retrieves the force applied to the particles.
+ @rtype: tuple of three floats
+ @return: force applied to the particles.
+ """
+
+ def setForce(newforce):
+ """
+ Sets the force applied to the particles.
+ @type newforce: tuple of 3 floats
+ @param newforce: force applied to the particles.
+ @rtype: None
+ @return: None
+ """
+
+ def getMult():
+ """
+ Retrieves the probabilities of a particle having a child.
+ @rtype: tuple of 4 floats
+ @return: probabilities of a particle having a child.
+ """
+
+ def setMult(newmult):
+ """
+ Sets the probabilities of a particle having a child.
+ @type newmult: tuple of 4 floats
+ @param newmult: probabilities of a particle having a child.
+ @rtype: None
+ @return: None
+ """
+
+ def getLife():
+ """
+ Retrieves the average life of the particles (4 generations)
+ @rtype: tuple of 4 floats
+ @return: average life of the particles (4 generations)
+ """
+
+ def setLife(newlife):
+ """
+ Sets the average life of the particles (4 generations).
+ @type newlife: tuple of 4 floats
+ @param newlife: average life of the particles (4 generations).
+ @rtype: None
+ @return: None
+ """
+
+ def getChild():
+ """
+ Retrieves the average number of children of the particles (4 generations).
+ @rtype: tuple of 4 ints
+ @return: average number of children of the particles (4 generations).
+ """
+
+ def setChild(newchild):
+ """
+ Sets the average number of children of the particles (4 generations).
+ @type newchild: tuple of 4 ints
+ @param newchild: average number of children of the particles (4 generations).
+ @rtype: None
+ @return: None
+ """
+
+ def getMat():
+ """
+ Retrieves the indexes of the materials associated to the particles (4 generations).
+ @rtype: tuple of 4 ints
+ @return: indexes of the materials associated to the particles (4 generations).
+ """
+
+ def setMat(newmat):
+ """
+ Sets the indexes of the materials associated to the particles (4 generations).
+ @type newmat: tuple of 4 ints
+ @param newmat: the indexes of the materials associated to the particles (4 generations).
+ @rtype: None
+ @return: None
+ """
+
+ def getDefvec():
+ """
+ Retrieves the x, y and z components of the force defined by the texture.
+ @rtype: tuple of 3 floats
+ @return: x, y and z components of the force defined by the texture.
+ """
+
+ def setDefvec(newdefvec):
+ """
+ Sets the x, y and z components of the force defined by the texture.
+ @type newdefvec: tuple of 3 floats
+ @param newdefvec: the x, y and z components of the force defined by the
+ texture.
+ @rtype: None
+ @return: None
+ """
+
+ def getParticlesLoc():
+ """
+ Gets the location of each particle at the current time in worldspace.
+ @rtype: A list of vector or a list of vector lists.
+ @return: The coordinates of each particle at the current time.
+ If the "Vect" option is enabled a list Vector pairs will be returned with a start and end point for each particle.
+ When static particles are enabled, a list of lists will be returned, each item a strand of particles.
+
+ Example::
+
+ import Blender
+ from Blender import Effect, Object
+ scn= Blender.Scene.GetCurrent()
+ ob= scn.getActiveObject()
+ effect= ob.effects[0]
+ particles= effect.getParticlesLoc()
+
+ # Check that particles are points only (not static and not vectors)
+ if not effect.getFlag() & Effect.Flags.STATIC or not effect.getStype():
+ for pt in particles:
+ ob_empty= scn.objects.new('Empty')
+ ob_empty.setLocation(pt)
+
+ else: # Particles will be a list
+ for pt in particles:
+ for pt_item in pt:
+ ob_empty= scn.objects.new('Empty')
+ ob_empty.setLocation(pt_item)
+
+ Example::
+ # Converts particles into a mesh with edges for strands
+ from Blender import Scene, Mathutils, Effect, Mesh, Object
+ scn= Scene.GetCurrent()
+ ob= scn.getActiveObject()
+ me= Mesh.New()
+
+ effects= Effect.Get()
+ for eff in effects:
+ for p in eff.getParticlesLoc():
+ # p is either a vector or a list of vectors. me.verts.extend() will deal with either
+ print p
+ me.verts.extend(p)
+
+ if type(p)==list: # Are we a strand or a pair, then add edges.
+ if len(p)>1:
+ edges= [(i, i+1) for i in range(len(me.verts)-len(p), len(me.verts)-1)]
+ me.edges.extend( edges )
+
+ print len(me.verts)
+ ob= scn.objects.new(me)
+ """
diff --git a/source/blender/python/api2_2x/doc/Effectdoc.txt b/source/blender/python/api2_2x/doc/Effectdoc.txt
new file mode 100644
index 00000000000..76cff428ed6
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Effectdoc.txt
@@ -0,0 +1,257 @@
+EFFECT Module documentation
+
+
+INTRODUCTION
+The module effect allows you to access all the data of an effect.
+An effect can modify an object (typically a mesh) in three different ways.
+ a) the build effect : makes the mesh appear progressively.
+ b) the wave effect : waves appear on the mesh (which should be fine-grained)
+ c) the particle effect : every vertex of the mesh emits particles,
+which can themselves emit new particles. This effect is the most parameterizable.
+
+In the blender internals, the effect object is just a placeholder for the "real"
+ effect, which can be a wave, particle or build effect. The python API follows
+this structure : the Effect module grants access to (the few) data which
+ are shared between all effects. It has three submodules : Wave, Build, Particle
+, which grant r/w access to the real parameters of these effects.
+
+
+
+
+functions of the module :
+
+Get(Name:string,pos:int) : returns the pos-th Effect associated
+ to the object whose name is Name.
+
+get : same as Get
+
+New(Type:string ) : Creates and returns a new Effect Object.
+The parameter Type can take the values "particle", "wave" or "build"
+
+
+
+Effect object member functions :
+
+getType() : Retrieves the type of the Effect Object.
+
+setType(val:int) : Sets the type of the Effect Object.
+The possible values of the type are :
+ 0 : effect build.
+ 1 : effect particle.
+ 2 : effect wave.
+
+
+getFlag()Retrieves the flag of the Effect Object
+
+setFlag(val:int) :Sets the flag
+
+The flag of the effect is a combination of parameters, whose semantics depend upon the effect type.
+All types :
+Bit 0 : set to 1 if the effect is selected in the effects window.
+Wave effect :
+Bits 1,2,3 : set to 1 if the button "X", "Y" or "Cycl" is clicked.
+Particle effect :
+Bits 1,2,3 : set to 1 if the button "Bspline", "Static" or "Face" is clicked.
+
+
+
+
+
+
+Submodules : Wave, Build, Particle.
+
+
+
+
+Wave module
+
+
+
+functions of the module :
+
+Get(Name:string,pos:int) : returns the pos-th wave Effect associated to the object whose name is Name.
+
+get : same as Get
+
+New( ) : Creates and returns a new Wave Object.
+
+
+Wave object member functions :
+
+getStartx() : returns the startx parameter of the wave object.
+
+setStartx(val:int) : sets the startx parameter of the wave object.
+
+getStarty() : returns the starty parameter of the wave object.
+
+setStarty(val:int) : sets the starty parameter of the wave object.
+
+getHeight() : returns the height parameter of the wave object.
+
+setHeight(val:int) : sets the height parameter of the wave object.
+
+getWidth() : returns the width parameter of the wave object.
+
+setWidth(val:int) : sets the width parameter of the wave object.
+
+getNarrow() : returns the narrow parameter of the wave object.
+
+setNarrow(val:int) : sets the narrow parameter of the wave object.
+
+getSpeed() : returns the speed parameter of the wave object.
+
+setSpeed(val:int) : sets the speed parameter of the wave object.
+
+getMinfac() : returns the minfac parameter of the wave object.
+
+setMinfac(val:int) : sets the minfac parameter of the wave object.
+
+getDamp() : returns the damp parameter of the wave object.
+
+setDamp(val:int) : sets the damp parameter of the wave object.
+
+getTimeoffs() : returns the timeoffs parameter of the wave object.
+
+setTimeoffs(val:int) : sets the time offset parameter of the wave object.
+
+getLifetime() : returns the lifetime parameter of the wave object.
+
+setLifetime(val:int) : sets the lifetime parameter of the wave object.
+
+
+
+The Object.attr syntax
+
+Wave attributes can be read/written with the object.attr syntax.
+Example :
+
+w = Blender.Wave.Get("Obname",3) #retrieves the 4th effect associated to the object named Obname
+a = w.speed # a is now the value corresponding to the speed of the effect
+w.speed = 42 # the speed of the effect is now equal to 42
+
+The parameter can take these values : "lifetime","timeoffs","damp","minfac","speed","narrow","width","height","startx","starty"
+
+
+
+
+Build module
+
+
+
+functions of the module :
+
+Get(Name:string,pos:int) : returns the pos-th build Effect associated to the object whose name is Name.
+
+get(Name:string,pos:int) : same as Get
+
+New( ) : Creates and returns a new Build Object.
+
+
+Build object member functions :
+
+getLen() : returns the length of the effect (in frames).
+
+setLen(val:float) : sets the length of the effect (in frames).
+
+getSfra() : returns the starting frame of the effect.
+
+setSfra(val:float) : sets the starting frame of the effect.
+
+
+The Object.attribute syntax
+
+The attribute can take these values : "sfra","len".
+
+
+Particle module
+
+
+
+functions of the module :
+
+Get(Name:string,pos:int) : returns the pos-th particle Effect associated to the object whose name is Name.
+
+get(Name:string,pos:int) : same as Get
+
+New( ) : Creates and returns a new Effect Object.
+
+
+Particle object member functions :
+
+getStartTime() : returns the start time of the particle effect (in frames).
+
+setStartTime(val:float) : sets the start time of the particle effect (in frames).
+
+getEndTime() : returns the end time of the particle effect (in frames).
+
+setEndTime(val:float) : sets the end time of the particle effect (in frames).
+
+getLifeTime() : returns the life time of the particles.
+
+setLifeTime(val:float) : sets the life time of the particles.
+
+getNormfac() : returns the normal strength of the particles (relatively to mesh).
+
+setNormfac(val:float) : sets the normal strength of the particles(relatively to mesh).
+
+getObfac() : returns the initial of the particles relatively to objects.
+
+setObfac(val:float) : sets the initial of the particles relatively to objects.
+
+getRandfac() : returns the initial random speed of the particles.
+
+setRandfac(val:float) : sets the initial random speed of the particles.
+
+getTexfac() : returns the initial speed of the particles caused by the texture.
+
+setTexfac(val:float) : sets the initial speed of the particles caused by the texture.
+
+getRandlife() : returns the variability of the life of the particles.
+
+setRandlife(val:float) : sets the variability of the life of the particles.
+
+getNabla() : returns the dimension of the area for gradient computation.
+
+setNabla(val:float) : sets the dimension of the area for gradient computation.
+
+getTotpart() : returns the total number of particles.
+
+setTotpart(val:int) : sets the total number of particles.
+
+getTotkey() : returns the number of key positions.
+
+setTotkey(val:int) : sets the number of key positions.
+
+getSeed() : returns the seed of the RNG.
+
+setSeed(val:int) : sets the seed of the RNG.
+
+getSeed() : returns the x,y,z components of the constant force applied to the particles.
+
+setSeed(valx:float,valy:float,valz:float) : sets the x,y,z components of the constant force applied to the particles.
+
+getMult() : returns the 4 probabilities of a particle having a child.
+
+setMult(val1:float,val2:float,val3:float,val4:float) : sets the 4 probabilities of a particle having a child.
+
+getLife() : returns the lifespan of the 4 generation particles.
+
+setLife(val1:float,val2:float,val3:float,val4:float) : sets the lifespan of the 4 generation particles.
+
+getMat() : returns the material used by the 4 generation particles.
+
+setMat(val1:float,val2:float,val3:float,val4:float) : sets the material used by the 4 generation particles.
+
+getChild() : returns the number of children a particle may have.
+
+setChild(val1:float,val2:float,val3:float,val4:float) : sets the number of children a particle may have.
+
+getDefvec() : returns the x, y and z axis of the force defined by the texture.
+
+setDefvec(val1:float,val2:float,val3:float) : sets the x, y and z axis of the force defined by the texture.
+
+
+
+The Object.attribute syntax
+
+The attribute can take these values : "seed","nabla","sta","end","lifetime","normfac","obfac","randfac","texfac","randlife","vectsize","totpart","force","mult","life","child","mat","defvec". \ No newline at end of file
diff --git a/source/blender/python/api2_2x/doc/Font.py b/source/blender/python/api2_2x/doc/Font.py
new file mode 100644
index 00000000000..c0ad66d0462
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Font.py
@@ -0,0 +1,69 @@
+# Blender.Text3d.Font module and the Font PyType object
+
+"""
+The Blender.Text3d.Font subsubmodule.
+
+Text3d.Font Objects
+===================
+
+This module provides access to B{Font} objects in Blender.
+
+Example::
+ import Blender
+ from Blender import Text3d
+
+ # Load a font
+ myfont= Text3d.Font.Load('/usr/share/fonts/ttf/verdana.ttf')
+
+ #
+ for font in Text3d.Font.Get():
+ print font.name, font.filename, font.packed
+"""
+
+def Load (filename):
+ """
+ Create a new Text3d.Font object.
+ @type filename: string
+ @param filename: file of the font
+ @rtype: Blender Text3d.Font
+ @return: The created Text3d.Font Data object.
+ """
+
+def Get (name = None):
+ """
+ Get the Text3d.Font object(s) from Blender.
+ @type name: string
+ @param name: The name of the Text3d object.
+ @rtype: Blender Text3d or a list of Blender Text3ds
+ @return: It depends on the 'name' parameter:
+ - (name): The Text3d object with the given name;
+ - (): A list with all Font objects in the current .blend file.
+ """
+class Font:
+ """
+ The Text3d.Font object
+ ======================
+ This object gives access Blender's B{Font} objects
+ @ivar filename: The filename (path) of the file loaded into this Font.
+ @type filename: string
+ @ivar packed: Boolean, True when the sample is packed (readonly).
+ @type packed: string
+ """
+
+ def pack():
+ """
+ Packs the sound into the current blend file.
+ @note: An error will be raised if the sound is already packed or the filename path does not exist.
+ @returns: nothing
+ @rtype: none
+ """
+
+ def unpack(mode):
+ """
+ Unpacks the sound to the samples filename.
+ @param mode: One of the values in Blender.UnpackModes dict.
+ @note: An error will be raised if the sound is not packed or the filename path does not exist.
+ @returns: nothing
+ @rtype: none
+ @type mode: int
+ """
diff --git a/source/blender/python/api2_2x/doc/Geometry.py b/source/blender/python/api2_2x/doc/Geometry.py
new file mode 100644
index 00000000000..f882f4b3b57
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Geometry.py
@@ -0,0 +1,97 @@
+# Blender.Geometry module and its subtypes
+
+"""
+The Blender.Geometry submodule.
+
+Geometry
+========
+
+This new module provides access to a geometry function.
+"""
+
+def PolyFill(polylines):
+ """
+ Takes a list of polylines and calculates triangles that would fill in the polylines.
+ Multiple lines can be used to make holes inside a polyline, or fill in 2 seperate lines at once.
+ @type polylines: List of lists containing vectors, each representing a closed polyline.
+ @rtype: list
+ @return: a list if tuples each a tuple of 3 ints representing a triangle indexing the points given.
+ @note: 2D Vectors will have an assumed Z axis of zero, 4D Vectors W axis is ignored.
+ @note: The order of points in a polyline effect the direction returned triangles face, reverse the order of a polyline to flip the normal of returned faces.
+
+ I{B{Example:}}
+
+ The example below creates 2 polylines and fills them in with faces, then makes a mesh in the current scene::
+ import Blender
+ Vector= Blender.Mathutils.Vector
+
+ # Outline of 5 points
+ polyline1= [Vector(-2.0, 1.0, 1.0), Vector(-1.0, 2.0, 1.0), Vector(1.0, 2.0, 1.0), Vector(1.0, -1.0, 1.0), Vector(-1.0, -1.0, 1.0)]
+ polyline2= [Vector(-1, 1, 1.0), Vector(0, 1, 1.0), Vector(0, 0, 1.0), Vector(-1.0, 0.0, 1.0)]
+ fill= Blender.Geometry.PolyFill([polyline1, polyline2])
+
+ # Make a new mesh and add the truangles into it
+ me= Blender.Mesh.New()
+ me.verts.extend(polyline1)
+ me.verts.extend(polyline2)
+ me.faces.extend(fill) # Add the faces, they reference the verts in polyline 1 and 2
+
+ scn = Blender.Scene.GetCurrent()
+ ob = scn.objects.new(me)
+ Blender.Redraw()
+ """
+
+def LineIntersect2D(vec1, vec2, vec3, vec4):
+ """
+ Takes 2 lines vec1, vec2 for the 2 points of the first line and vec2, vec3 for the 2 points of the second line.
+ @rtype: Vector
+ @return: a 2D Vector for the intersection or None where there is no intersection.
+ """
+
+def ClosestPointOnLine(pt, vec1, vec2):
+ """
+ Takes 2 lines vec1, vec2 for the 2 points of the first line and vec2, vec3 for the 2 points of the second line.
+ @rtype: tuple
+ @return: a tuple containing a vector and a float, the vector is the closest point on the line, the float is the position on the line, between 0 and 1 the point is on the line.
+ """
+
+def PointInTriangle2D(pt, tri_pt1, tri_pt2, tri_pt3):
+ """
+ Takes 4 vectors (one for the test point and 3 for the triangle)
+ This is a 2d function so only X and Y are used, Z and W will be ignored.
+ @rtype: bool
+ @return: True or False depending on the points intersection.
+ """
+
+def BoxPack2D(boxlist):
+ """
+ Takes a list of 2D boxes and packs them into a square.
+ Each box in boxlist must be a list of at least 4 items - [x,y,w,h], after running this script,
+ the X and Y values in each box will be moved to packed, non overlapping locations.
+
+ Example::
+
+ # Make 500 random boxes, pack them and make a mesh from it
+ from Blender import Geometry, Scene, Mesh
+ import random
+ boxes = []
+ for i in xrange(500):
+ boxes.append( [0,0, random.random()+0.1, random.random()+0.1] )
+ boxsize = Geometry.BoxPack2D(boxes)
+ print 'BoxSize', boxsize
+ me = Mesh.New()
+ for x in boxes:
+ me.verts.extend([(x[0],x[1], 0), (x[0],x[1]+x[3], 0), (x[0]+x[2],x[1]+x[3], 0), (x[0]+x[2],x[1], 0) ])
+ v1= me.verts[-1]
+ v2= me.verts[-2]
+ v3= me.verts[-3]
+ v4= me.verts[-4]
+ me.faces.extend([(v1,v2,v3,v4)])
+ scn = Scene.GetCurrent()
+ scn.objects.new(me)
+
+ @note: Each boxlist item can be longer then 4, the extra items are ignored and stay untouched.
+ @rtype: tuple
+ @return: a tuple pair - (width, height) of all the packed boxes.
+ """
+ \ No newline at end of file
diff --git a/source/blender/python/api2_2x/doc/Group.py b/source/blender/python/api2_2x/doc/Group.py
new file mode 100644
index 00000000000..aca7c56b4a5
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Group.py
@@ -0,0 +1,127 @@
+# Blender.Group module and the Group PyType object
+
+"""
+The Blender.Group submodule.
+
+Group
+=====
+
+This module provides access to B{Group} data in Blender.
+
+Example::
+
+ # Make Dupli's Real, as a python script.
+
+ from Blender import *
+
+ scn= Scene.GetCurrent()
+ for ob in scn.objects:
+ print 'Object Group Settings'
+ print ob.name, ob.type
+ print 'enableDupVerts:', ob.enableDupVerts
+ print 'enableDupFrames:', ob.enableDupFrames
+ print 'enableDupGroup:', ob.enableDupGroup
+ print 'DupGroup:', ob.DupGroup
+ dupe_obs= ob.DupObjects
+ print 'num dup obs:', len(dupe_obs)
+
+ for dup_ob, dup_matrix in dupe_obs:
+ print '\tDupOb', dup_ob.name
+ scn.objects.new(dup_ob.data)
+ new_ob.setMatrix(dup_matrix)
+ new_ob.sel= 1 # select all real instances.
+
+ ob.sel=0 # Desel the original object
+
+ Window.RedrawAll()
+
+Example::
+
+ # Make a new group with the selected objects, and add an instance of this group.
+
+ from Blender import *
+
+ scn= Scene.GetCurrent()
+
+ # New Group
+ grp= Group.New('mygroup')
+ grp.objects= scn.objects
+
+ # Instance the group at an empty using dupligroups
+ ob= scn.objects.new(None)
+ ob.enableDupGroup= True
+ ob.DupGroup= grp
+ Window.RedrawAll()
+
+
+Example::
+
+ # Remove all non mesh objects from a group.
+
+ from Blender import *
+
+ scn= Scene.GetCurrent()
+
+ # New Group
+ grp= Group.Get('mygroup')
+ for ob in list(grp.objects): # Convert to a list before looping because we are removing items
+ if ob.type != 'Mesh':
+ grp.objects.unlink(ob)
+"""
+
+def New (name = None):
+ """
+ Make a new empty group, name optional, default is "Group"
+ @type name: string
+ @param name: The name of the new group.
+ @rtype: Blender Group
+ @return: A Empty Blender Group object
+ """
+
+def Get (name = None):
+ """
+ Get the Group object(s) from Blender.
+ @type name: string
+ @param name: The name of the Group object.
+ @rtype: Blender Group or a list of Blender Groups
+ @return: It depends on the I{name} parameter:
+ - (name): The Group object called I{name}, Exception if it is not found.
+ - (): A list with all Group objects in the current blend file.
+ """
+
+def Unlink (group):
+ """
+ Unlink (delete) this group from Blender.
+ @Note: No objects will be removed, just the group that references them.
+ @type group: group
+ @param group: A group to remove from this blend file, does not remove objects that this group uses.
+ """
+
+
+class Group:
+ """
+ The Group object
+ ================
+ This object gives access to Groups in Blender.
+ @ivar layers: Layer bitmask for this group.
+ @type layers: int
+ @ivar objects: Objects that this group uses.
+ This is a sequence with-list like access so use list(grp.objects) if you need to use a list (where grp is a group).
+ The groups objects can be set by assigning a list or iterator of objects to the groups objects.
+ objects.link() and objects.unlink() also work with the the objects iterator just like with lists.
+
+ B{Note}: append() and remove() have been deprecated and replaced by link() and unlink(),
+ after Blender 2.43 append() and remove() will not be available.
+ @type objects: custom object sequence
+ """
+
+ def __copy__ ():
+ """
+ Make a copy of this group
+ @rtype: Group
+ @return: a copy of this group
+ """
+
+import id_generics
+Group.__doc__ += id_generics.attributes
+
diff --git a/source/blender/python/api2_2x/doc/IDProp.py b/source/blender/python/api2_2x/doc/IDProp.py
new file mode 100644
index 00000000000..0a0df335fa3
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/IDProp.py
@@ -0,0 +1,130 @@
+class IDGroup:
+ """
+ The IDGroup Type
+ ================
+ This type supports both iteration and the []
+ operator to get child ID properties.
+
+ You can also add new properties using the [] operator.
+ For example::
+
+ group['a float!'] = 0.0
+ group['an int!'] = 0
+ group['a string!'] = "hi!"
+ group['an array!'] = [0, 0, 1.0, 0]
+
+ group['a subgroup!] = {"float": 0.0, "an int": 1.0, "an array": [1, 2],
+ "another subgroup": {"a": 0.0, "str": "bleh"}}
+
+ Note that for arrays, the array type defaults to int unless a float is found
+ while scanning the template list; if any floats are found, then the whole
+ array is float.
+
+ You can also delete properties with the del operator. For example:
+
+ del group['property']
+
+ To get the type of a property, use the type() operator, for example::
+
+ if type(group['bleh']) == str: pass
+
+ To tell if the property is a group or array type, import the Blender.Types module and test
+ against IDGroupType and IDArrayType, like so::
+
+ from Blender.Types import IDGroupType, IDArrayType.
+
+ if type(group['bleghr']) == IDGroupType:
+ (do something)
+
+ @ivar name: The name of the property
+ @type name: string
+ """
+
+ def pop(item):
+ """
+ Pop an item from the group property.
+ @type item: string
+ @param item: The item name.
+ @rtype: can be dict, list, int, float or string.
+ @return: The removed property.
+ """
+
+ def update(updatedict):
+ """
+ Updates items in the dict, similar to normal python
+ dictionary method .update().
+ @type updatedict: dict
+ @param updatedict: A dict of simple types to derive updated/new IDProperties from.
+ @rtype: None
+ @return: None
+ """
+
+ def keys():
+ """
+ Returns a list of the keys in this property group.
+ @rtype: list of strings.
+ @return: a list of the keys in this property group.
+ """
+
+ def values():
+ """
+ Returns a list of the values in this property group.
+
+ Note that unless a value is itself a property group or an array, you
+ cannot change it by changing the values in this list, you must change them
+ in the parent property group.
+
+ For example,
+
+ group['some_property'] = new_value
+
+ . . .is correct, while,
+
+ values = group.values()
+ values[0] = new_value
+
+ . . .is wrong.
+
+ @rtype: list of strings.
+ @return: a list of the values in this property group.
+ """
+
+ def iteritems():
+ """
+ Implements the python dictionary iteritmes method.
+
+ For example::
+
+ for k, v in group.iteritems():
+ print "Property name: " + k
+ print "Property value: " + str(v)
+
+ @rtype: an iterator that spits out items of the form [key, value]
+ @return: an iterator.
+ """
+
+ def convert_to_pyobject():
+ """
+ Converts the entire property group to a purely python form.
+
+ @rtype: dict
+ @return: A python dictionary representing the property group
+ """
+
+class IDArray:
+ """
+ The IDArray Type
+ ================
+
+ @ivar type: returns the type of the array, can be either IDP_Int or IDP_Float
+ """
+
+ def __getitem__(index):
+ pass
+
+ def __setitem__(index, value):
+ pass
+
+ def __len__():
+ pass
+ \ No newline at end of file
diff --git a/source/blender/python/api2_2x/doc/Image.py b/source/blender/python/api2_2x/doc/Image.py
new file mode 100644
index 00000000000..6d613b3c8fe
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Image.py
@@ -0,0 +1,374 @@
+# Blender.Image module and the Image PyType object
+
+"""
+The Blender.Image submodule.
+
+Image
+=====
+
+B{New}: L{Image.clampX}, L{Image.clampY}.
+
+This module provides access to B{Image} objects in Blender.
+
+Example::
+ import Blender
+ from Blender import Image
+ #
+ image = Image.Load("/path/to/my/image.png") # load an image file
+ print "Image from", image.getFilename(),
+ print "loaded to obj", image.getName())
+ image.setXRep(4) # set x tiling factor
+ image.setYRep(2) # set y tiling factor
+ print "All Images available now:", Image.Get()
+
+@type Sources: readonly dictionary
+@var Sources: The available Image Source.
+ - STILL: Single image file
+ - MOVIE: Movie file
+ - SEQUENCE: Multiple image files, as sequence
+ - GENERATED: Generated image
+"""
+
+def Load (filename):
+ """
+ Load the image called 'filename' into an Image object.
+ @type filename: string
+ @param filename: The full path to the image file.
+ @rtype: Blender Image
+ @return: A Blender Image object with the data from I{filename}.
+ """
+
+def New (name, width, height, depth):
+ """
+ Create a new Image object.
+ @type name: string
+ @param name: The name of the new Image object.
+ @type width: int
+ @param width: The width of the new Image object, between 1 and 5000.
+ @type height: int
+ @param height: The height of the new Image object, between 1 and 5000.
+ @type depth: int
+ @param depth: The colour depth of the new Image object. (8:Grey, 24:RGB, 32:RGBA). (Not implimented yet, all new images will be 24bit)
+ @rtype: Blender Image
+ @return: A new Blender Image object.
+ """
+
+def Get (name = None):
+ """
+ Get the Image object(s) from Blender.
+ @type name: string
+ @param name: The name of the Image object.
+ @rtype: Blender Image or a list of Blender Images
+ @return: It depends on the I{name} parameter:
+ - (name): The Image object called I{name}, None if not found;
+ - (): A list with all Image objects in the current scene.
+ """
+
+def GetCurrent ():
+ """
+ Get the currently displayed Image from Blenders UV/Image window.
+ When multiple images are displayed, the last active UV/Image windows image is used.
+ @rtype: Blender Image
+ @return: The Current Blender Image, If there is no current image it returns None.
+ """
+
+from IDProp import IDGroup, IDArray
+class Image:
+ """
+ The Image object
+ ================
+ This object gives access to Images in Blender.
+ @ivar filename: The filename (path) to the image file loaded into this Image
+ object.
+ @type filename: string
+ @ivar size: The [width, height] dimensions of the image (in pixels).
+ @type size: list
+ @ivar depth: The pixel depth of the image. [8, 16, 18, 24, 32]
+ @type depth: int
+ @ivar xrep: Texture tiling: the number of repetitions in the x (horizontal)
+ axis. [1, 16].
+ @ivar yrep: Texture tiling: the number of repetitions in the y (vertical)
+ axis [1, 16].
+ @type xrep: int
+ @type yrep: int
+ @ivar start: Texture's animation start frame [0, 128].
+ @type start: int
+ @ivar end: Texture's animation end frame [0, 128].
+ @type end: int
+ @ivar speed: Texture's animation speed [1, 100].
+ @type speed: int
+ @ivar packed: True when the Texture is packed (readonly).
+ @type packed: boolean
+ @ivar has_data: True when the image has pixel data (readonly).
+ @type has_data: boolean
+ @ivar fields: enable or disable the fields option for this image.
+ @type fields: boolean
+ @ivar fields_odd: enable or disable the odd fields option for this image.
+ @type fields_odd: boolean
+ @ivar antialias: enable or disable the antialias option for this image.
+ @type antialias: boolean
+ @ivar bindcode: Texture's bind code (readonly).
+ @type bindcode: int
+ @ivar source: Image source type. See L{the Sources dictionary<Sources>} .
+ @type source: int
+ @ivar clampX: When true the image will not tile horizontally.
+ @type clampX: bool
+ @ivar clampY: When true the image will not tile vertically.
+ @type clampY: bool
+ """
+
+ def getName():
+ """
+ Get the name of this Image object.
+ @rtype: string
+ """
+
+ def getFilename():
+ """
+ Get the filename of the image file loaded into this Image object.
+ @rtype: string
+ """
+
+ def getSize():
+ """
+ Get the [width, height] dimensions (in pixels) of this image.
+ @rtype: list of 2 ints
+ """
+
+ def getDepth():
+ """
+ Get the pixel depth of this image.
+ @rtype: int
+ """
+
+ def getPixelF(x, y):
+ """
+ Get the the colors of the current pixel in the form [r,g,b,a].
+ Returned values are floats normalized to 0.0 - 1.0.
+ Pixel coordinates are in the range from 0 to N-1. See L{getMaxXY}
+ @returns: [ r, g, b, a]
+ @rtype: list of 4 floats
+ @type x: int
+ @type y: int
+ @param x: the x coordinate of pixel.
+ @param y: the y coordinate of pixel.
+ """
+ def getPixelI(x, y):
+ """
+ Get the the colors of the current pixel in the form [r,g,b,a].
+ Returned values are ints normalized to 0 - 255.
+ Pixel coordinates are in the range from 0 to N-1. See L{getMaxXY}
+ @returns: [ r, g, b, a]
+ @rtype: list of 4 ints
+ @type x: int
+ @type y: int
+ @param x: the x coordinate of pixel.
+ @param y: the y coordinate of pixel.
+ """
+
+ def getMaxXY():
+ """
+ Get the x & y size for the image. Image coordinates range from 0 to size-1.
+ @returns: [x, y]
+ @rtype: list of 2 ints
+ """
+
+ def getMinXY():
+ """
+ Get the x & y origin for the image. Image coordinates range from 0 to size-1.
+ @returns: [x, y]
+ @rtype: list of 2 ints
+ """
+
+ def getXRep():
+ """
+ Get the number of repetitions in the x (horizontal) axis for this Image.
+ This is for texture tiling.
+ @rtype: int
+ """
+
+ def getYRep():
+ """
+ Get the number of repetitions in the y (vertical) axis for this Image.
+ This is for texture tiling.
+ @rtype: int
+ """
+
+ def getBindCode():
+ """
+ Get the Image's bindcode. This is for texture loading using BGL calls.
+ See, for example, L{BGL.glBindTexture} and L{glLoad}.
+ @rtype: int
+ """
+
+ def getStart():
+ """
+ Get the Image's start frame. Used for animated textures.
+ @rtype: int
+ """
+
+ def getEnd():
+ """
+ Get the Image's end frame. Used for animated textures.
+ @rtype: int
+ """
+
+ def getSpeed():
+ """
+ Get the Image's speed (fps). Used for animated textures.
+ @rtype: int
+ """
+
+ def reload():
+ """
+ Reloads this image from the filesystem. If used within a loop you need to
+ redraw the Window to see the change in the image, e.g. with
+ Window.RedrawAll().
+ @warn: if the image file is corrupt or still being written, it will be
+ replaced by a blank image in Blender, but no error will be returned.
+ @returns: None
+ """
+
+ def glLoad():
+ """
+ Load this image's data into OpenGL texture memory, if it is not already
+ loaded (image.bindcode is 0 if it is not loaded yet).
+ @note: Usually you don't need to call this method. It is only necessary
+ if you want to draw textured objects in the Scripts window and the
+ image's bind code is zero at that moment, otherwise Blender itself can
+ take care of binding / unbinding textures. Calling this method for an
+ image with nonzero bind code simply returns the image's bind code value
+ (see L{getBindCode}).
+ @rtype: int
+ @returns: the texture's bind code.
+ """
+
+ def glFree():
+ """
+ Delete this image's data from OpenGL texture memory, only (the image itself
+ is not removed from Blender's memory). Internally, glDeleteTextures (see
+ L{BGL.glDeleteTextures}) is used, but this method also updates Blender's
+ Image object so that its bind code is set to 0. See also L{Image.glLoad},
+ L{Image.getBindCode}.
+ """
+
+ def setName(name):
+ """
+ Set the name of this Image object.
+ @type name: string
+ @param name: The new name.
+ """
+
+ def setFilename(name):
+ """
+ Change the filename of this Image object.
+ @type name: string
+ @param name: The new full filename.
+ @warn: use this with caution and note that the filename is truncated if
+ larger than 160 characters.
+ """
+
+ def setXRep(xrep):
+ """
+ Texture tiling: set the number of x repetitions for this Image.
+ @type xrep: int
+ @param xrep: The new value in [1, 16].
+ """
+
+ def setYRep(yrep):
+ """
+ Texture tiling: set the number of y repetitions for this Image.
+ @type yrep: int
+ @param yrep: The new value in [1, 16].
+ """
+
+ def setStart(start):
+ """
+ Get the Image's start frame. Used for animated textures.
+ @type start: int
+ @param start: The new value in [0, 128].
+ """
+
+ def setEnd(end):
+ """
+ Set the Image's end frame. Used for animated textures.
+ @type end: int
+ @param end: The new value in [0, 128].
+ """
+
+ def setSpeed(speed):
+ """
+ Set the Image's speed (fps). Used for animated textures.
+ @type speed: int
+ @param speed: The new value in [1, 100].
+ """
+
+ def setPixelF(x, y, (r, g, b,a )):
+ """
+ Set the the colors of the current pixel in the form [r,g,b,a].
+ Color values must be floats in the range 0.0 - 1.0.
+ Pixel coordinates are in the range from 0 to N-1. See L{getMaxXY}
+ @type x: int
+ @type y: int
+ @type r: float
+ @type g: float
+ @type b: float
+ @type a: float
+ @returns: nothing
+ @rtype: none
+ """
+
+ def setPixelI(x, y, (r, g, b, a)):
+ """
+ Set the the colors of the current pixel in the form [r,g,b,a].
+ Color values must be ints in the range 0 - 255.
+ Pixel coordinates are in the range from 0 to N-1. See L{getMaxXY}
+ @type x: int
+ @type y: int
+ @type r: int
+ @type g: int
+ @type b: int
+ @type a: int
+ @returns: nothing
+ @rtype: none
+ """
+
+ def save():
+ """
+ Saves the current image to L{filename}
+ @note: Saving to a directory that doent exist will raise an error.
+ @note: Saving a packed image will make a unique (numbered) name if the file alredy exists. Remove the file first to be sure it will not be renamed.
+ @returns: None
+ """
+
+ def pack():
+ """
+ Packs the image into the current blend file.
+
+ Since 2.44 new images without valid filenames can be packed.
+
+ If the image is alredy packed, it will be repacked.
+
+ @returns: nothing
+ @rtype: none
+ """
+
+ def unpack(mode):
+ """
+ Unpacks the image to the images filename.
+ @param mode: One of the values in L{Blender.UnpackModes}.
+ @note: An error will be raised if the image is not packed or the filename path does not exist.
+ @returns: nothing
+ @rtype: none
+ @type mode: int
+ """
+ def makeCurrent():
+ """
+ Set the currently displayed Image from Blenders UV/Image window.
+ When multiple images are displayed, the last active UV/Image windows image is used.
+ @warn: Deprecated, set bpy.data.images.active = image instead.
+ @rtype: bool
+ @return: True if the current image could be set, if no window was available, return False.
+ """
+import id_generics
+Image.__doc__ += id_generics.attributes
diff --git a/source/blender/python/api2_2x/doc/Ipo.py b/source/blender/python/api2_2x/doc/Ipo.py
new file mode 100644
index 00000000000..b8c472b371a
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Ipo.py
@@ -0,0 +1,437 @@
+# Blender.Ipo module and the Ipo PyType object
+
+"""
+The Blender.Ipo submodule
+
+B{New}:
+ - Ipo updates to both the program and Bpython access.
+ - access to Blender's new Ipo driver capabilities.
+ - Ipo now supports the mapping operator [] to access IpoCurves
+
+This module provides access to the Ipo Data in Blender. An Ipo is composed of
+several IpoCurves, and an IpoCurve is composed of several BezTriples.
+
+Example::
+ from Blender import Ipo
+
+ ipo = Ipo.Get('ObIpo') # retrieves an Ipo object
+ ipo.name = 'ipo1' # change the Ipo's name
+ icu = ipo[Ipo.OB_LOCX] # request X Location Ipo curve
+ if icu != None and len(icu.bezierPoints) > 0: # if curve exists and has BezTriple points
+ val = icu[2.5] # get the curve's value at time 2.5
+ ipo[Ipo.OB_LOCX] = None # delete the Ipo curve
+
+Each type of Ipo has different types Ipocurves. With the exception of Shape
+Key Ipos, constants are used to specify all Ipocurves. There are two ways
+to tell which Ipo curves go with which Ipo type:
+ - all constants start with a two-character identifier for their Ipo type;
+ for example, "OB_LOCX" is the LocX curve for an Object Ipo
+ - each Ipo now has a read-only attribute L{Ipo.curveConsts}, which returns
+ the valid Ipo curve types for that specific Ipo
+
+The valid IpoCurve constants are:
+ 1. Material Ipo: MA_R, MA_G, MA_B, MA_SPECR, MA_SPECG, MA_SPECB,
+ MA_MIRR, MA_MIRG, MA_MIRB, MA_REF, MA_ALPHA, MA_EMIT, MA_AMB,
+ MA_SPEC, MA_HARD, MA_SPTRA, MA_IOR, MA_MODE, MA_HASIZE, MA_TRANSLU,
+ MA_RAYMIR, MA_FRESMIR, MA_FRESMIRI, MA_FRESTRA, MA_FRESTRAI,
+ MA_TRAGLOW, MA_OFSX, MA_OFSY, MA_OFSZ, MA_SIZEX, MA_SIZEY, MA_SIZEZ,
+ MA_TEXR, MA_TEXG, MA_TEXB, MA_DEFVAR, MA_COL, MA_NOR, MA_VAR, MA_DISP
+ 2. Lamp Ipo: LA_ENERG, LA_R, LA_G, LA_B, LA_DIST, LA_SPOSI, LA_SPOBL,
+ LA_QUAD1, LA_QUAD2, LA_HAINT, LA_OFSX, LA_OFSY, LA_OFSZ, LA_SIZEX,
+ LA_SIZEY, LA_SIZEZ, LA_TEXR, LA_TEXG, LA_TEXB, LA_DEFVAR, LA_COL
+ 3. World Ipo: WO_HORR, WO_HORG, WO_HORB, WO_ZENR, WO_ZENG, WO_ZENB,
+ WO_EXPOS, WO_MISI, WO_MISDI, WO_MISSTA, WO_MISHI, WO_STARR,
+ WO_STARB, WO_STARG, WO_STARDI, WO_STARSI, WO_OFSX, WO_OFSY,
+ WO_OFSZ, WO_SIZEX, WO_SIZEY, WO_SIZEZ, WO_TEXR, WO_TEXG,
+ WO_TEXB, WO_DEFVAR, WO_COL, WO_NOR, WO_VAR
+ 4. Camera Ipo: CA_LENS, CA_CLSTA, CA_CLEND, CA_APERT, CA_FDIST
+ 5. Object Ipo: OB_LOCX, OB_LOCY, OB_LOCZ, OB_DLOCX, OB_DLOCY, OB_DLOCZ,
+ OB_ROTX, OB_ROTY, OB_ROTZ, OB_DROTX, OB_DROTY, OB_DROTZ,
+ OB_SIZEX, OB_SIZEY, OB_SIZEZ, OB_DSIZEX, OB_DSIZEY, OB_DSIZEZ,
+ OB_LAYER, OB_TIME, OB_COLR, OB_COLG, OB_COLB, OB_COLA,
+ OB_FSTRENG, OB_FFALL, OB_RDAMP, OB_DAMPING, OB_PERM
+ 6. Curve Ipo: CU_SPEED
+ 7. Constraint Ipo: CO_INF
+ 8. Texture Ipo: TE_NSIZE, TE_NDEPTH, TE_NTYPE, TE_TURB, TE_VNW1, TE_VNW2,
+ TE_VNW3, TE_VNW4, TE_MINKMEXP, TE_DISTM, TE_COLT, TE_ISCALE,
+ TE_DISTA, TE_MGTYPE, TE_MGH, TE_LACU, TE_OCT, TE_MGOFF,
+ TE_MGGAIN, TE_NBASE1, TE_NBASE2, TE_COLR, TE_COLG, TE_COLB,
+ TE_BRIGHT, TE_CONTRAS
+ 9. Pose/Action Ipo: PO_LOCX, PO_LOCY, PO_LOCZ, PO_SIZEX, PO_SIZEY,
+ PO_SIZEZ, PO_QUATW, PO_QUATX, PO_QUATY, PO_QUATZ
+ 10. Sequence Ipo: SQ_FAC
+
+Shape Key Ipos are handled differently from other Ipos. The user can rename
+the curves, so string are used to access them instead of constants. The
+L{Ipo.curveConsts} attribute for Shape Key Ipos returns a list of all defined
+key names.
+"""
+
+def New (type, name):
+ """
+ Creates a new Ipo.
+ @type type: string
+ @type name: string
+ @param type: The Ipo's blocktype. Depends on the object the Ipo will be
+ linked to. Currently supported types are Object, Camera, World,
+ Material, Texture, Lamp, Action, Constraint, Sequence, Curve, Key.
+ @param name: The name for this Ipo.
+ @rtype: Blender Ipo
+ @return: The created Ipo.
+ """
+
+def Get (name = None):
+ """
+ Get the Ipo from Blender.
+ @type name: string
+ @param name: The name of the requested Ipo, or nothing.
+ @rtype: Blender Ipo or a list of Blender Ipos
+ @return: It depends on the 'name' parameter:
+ - (name): The Ipo with the given name;
+ - (): A list with all Ipos in the current scene.
+ """
+
+class Ipo:
+ """
+ The Ipo object
+ ==============
+ This object gives access to Ipo data from all objects in Blender.
+ @Note: Blender Materials, Lamps and Worlds have I{texture channels} which
+ allow the user to assign textures to them. The Blender Ipo Window allows
+ the user to access the IpoCurves for these channels by specifying a number
+ between 0 and 9 (the number appears next to the Ipo type in the window
+ header). Prior to Version 2.42, the BPy API did not allow users to access
+ these texture channels in a predictable manner. A new attribute named
+ L{channel} was added to the API in Version 2.42 to correct this problem.
+
+ The current channel setting has an effect on the operators B{[]}, B{len()}
+ and others. For example, suppose a Material has three IpoCurves
+ (R, G, and B), and two texture channels (numbered 0 and 1), and furthermore
+ channel 0 has one Ipocurve (Col). The IpoCurve Col can only be
+ "seen" through the API when B{ipo.channel} is 0. Setting B{ipo.channel} to
+ 1 will cause this curve to be ignored by B{len(ipo)}::
+
+ from Blender import Ipo
+
+ ipo = Ipo.Get('MatIpo')
+ for channel in xrange(2):
+ ipo.channel = channel
+ print 'channel is',channel
+ print ' len is',len(ipo)
+ names = dict([(x[1],x[0]) for x in ipo.curveConsts.items()])
+ for curve in [Ipo.MA_R,Ipo.MA_COL]:
+ print ' ',names[curve],'is',curve in ipo
+
+ will output::
+ channel is 0
+ len is 4
+ MA_R is True
+ MA_COL is True
+ channel is 1
+ len is 3
+ MA_R is True
+ MA_COL is False
+
+ @ivar curves: Ipo curves currently defined for the Ipo.
+ @type curves: list of Ipocurves.
+ @ivar curveConsts: The valid Ipo curves for this Ipo. These can be used
+ by the [] mapping operator. The value
+ depends on the Ipo curve type. If the Ipo is any type other than a Key or
+ Shape Ipo, this attribute returns a set of constants that can be
+ used to specify a particular curve. For Key or Shape Ipos, the attribute
+ returns a list of all defined keys by name.
+ @type curveConsts: constant or list of strings. Read-only.
+ @ivar channel: the current texture channel for Blender object which support
+ textures (materials, lamps and worlds). Returns None if the Ipo does
+ not support texture channels. Value must be in the range [0,9].
+ @type channel: int or None
+ """
+
+ def __contains__():
+ """
+ The "in" operator for Ipos. It returns B{True} if the specified
+ IpoCurve exists for the Ipo. This operator B{should not} be used to
+ test for whether a curve constant is valid for a particular Ipo type.
+ Many constants for different Ipo types have the same value, and it is
+ the constant's value used internally.
+ No exceptions are raised if the argument is not a valid curve constant or
+ or string, nor does the operator return B{True} when the curve
+ constant is valid but does not currently exist. As such, it should only be
+ used to test for specific curves when the Ipo type is known::
+ ipo = Object.Get('Cube').ipo # get Object-type Ipo
+ if ipo:
+ print Ipo.OB_LOCX in ipo # prints "True" if 'LocX' curve exists
+ print Ipo.MA_R in ipo # also prints "True" since MA_R and OB_LOCX are have the same value
+ print 'hiccup' in ipo # always prints "False" since argument is not a constant
+
+ @return: see above.
+ @rtype: Boolean
+ """
+
+ def __getitem__():
+ """
+ This operator is similar to the Python dictionary mapping operator [],
+ except that the user cannot assign arbitrary keys. Each Ipo type has
+ a pre-defined set of IpoCurves which may or may not exist at a given time. This operator
+ will either return an IpoCurve object if the specified curve exists,
+ return None if the curve does not exists, or throws a KeyError exception
+ if the curve is not valid for this Ipo type.
+ @return: an IpoCurve object if it exists
+ @rtype: IpoCurve or None
+ @raise KeyError: an undefined IpoCurve was specified for the Ipo
+ """
+
+ def __iter__():
+ """
+ Iterator for Ipos. It returns all the defined IpoCurve objects associated
+ with the Ipo. For example::
+ from Blender import Ipo
+
+ ipo = Ipo.Get()
+ if len(ipo) > 0:
+ ipo = ipo[0]
+ print 'ipo name is',ipo.name
+ for icu in ipo:
+ print ' curve name is',icu.name
+ might result in::
+ ipo name is ObIpo
+ curve name is LocX
+ curve name is LocY
+ curve name is LocZ
+
+ @return: an IpoCurve object
+ @rtype: IpoCurve
+ """
+
+ def __len__():
+ """
+ Returns the number of curves defined for the Ipo.
+ @return: number of defined IpoCurves
+ @rtype: int
+ """
+
+ def getName():
+ """
+ Gets the name of the Ipo (B{deprecated}). See the L{name} attribute.
+ @rtype: string
+ @return: the name of the Ipo.
+ """
+
+ def setName(newname):
+ """
+ Sets the name of the Ipo (B{deprecated}). See the L{name} attribute.
+ @type newname: string
+ @rtype: None
+ @return: None
+ """
+
+ def getCurves():
+ """
+ Gets all the IpoCurves of the Ipo (B{deprecated}). Use the
+ L{iterator operator []<__iter__>} instead.
+ @rtype: list of IpoCurves
+ @return: A list (possibly empty) containing all the IpoCurves associated
+ to the Ipo object.
+ """
+
+ def getCurve(curve):
+ """
+ Return the specified IpoCurve (B{deprecated}). Use the L{mapping
+ operator B{[]}<__getitem__>} instead.
+ If the curve does not exist in the Ipo,
+ None is returned. I{curve} can be either a string or an integer,
+ denoting either the name of the Ipo curve or its internal adrcode.
+ The possible Ipo curve names are:
+
+ 1. Camera Ipo: Lens, ClSta, ClEnd, Apert, FDist.
+ 2. Material Ipo: R, G, B, SpecR, SpecG, SpecB, MirR, MirG, MirB, Ref,
+ Alpha, Emit, Amb, Spec, Hard, SpTra, Ior, Mode, HaSize, Translu,
+ RayMir, FresMir, FresMirI, FresTra, FresTraI, TraGlow, OfsX, OfsY,
+ OfsZ, SizeX, SizeY, SizeZ, texR, texG, texB, DefVar, Col, Nor, Var,
+ Disp.
+ 3. Object Ipo: LocX, LocY, LocZ, dLocX, dLocY, dLocZ, RotX, RotY, RotZ,
+ dRotX, dRotY, dRotZ, SizeX, SizeY, SizeZ, dSizeX, dSizeY, dSizeZ,
+ Layer, Time, ColR, ColG, ColB, ColA, FStreng, FFall, Damping,
+ RDamp, Perm.
+ 4. Lamp Ipo: Energ, R, G, B, Dist, SpoSi, SpoBl, Quad1, Quad2, HaInt.
+ 5. World Ipo: HorR, HorG, HorB, ZenR, ZenG, ZenB, Expos, Misi, MisDi,
+ MisSta, MisHi, StaR, StaG, StaB, StarDi, StarSi, OfsX, OfsY, OfsZ,
+ SizeX, SizeY, SizeZ, TexR, TexG, TexB, DefVar, Col, Nor, Var.
+ 5. World Ipo: HorR, HorG, HorB, ZenR, ZenG, ZenB, Expos, Misi, MisDi,
+ MisSta, MisHi, StarR, StarB, StarG, StarDi, StarSi, OfsX, OfsY, OfsZ,i
+ SizeX, SizeY, SizeZ, texR, texG, texB, DefVar, Col, Nor, Var.
+ 6. Texture Ipo: NSize, NDepth, NType, Turb, Vnw1, Vnw2, Vnw3, Vnw4,
+ MinkMExp, DistM, ColT, iScale, DistA, MgType, MgH, Lacu, Oct,
+ MgOff, MgGain, NBase1, NBase2.
+ 7. Curve Ipo: Speed.
+ 8. Action Ipo: LocX, LocY, LocZ, SizeX, SizeY, SizeZ, QuatX, QuatY,
+ QuatZ, QuatW.
+ 9. Sequence Ipo: Fac.
+ 10. Constraint Ipo: Inf.
+
+ The adrcode for the Ipo curve can also be given; this is useful for
+ accessing curves for Shape Key Ipos. The adrcodes for Shape Key Ipo are
+ numbered consecutively starting at 0.
+ @type curve : string or int
+ @rtype: IpoCurve object
+ @return: the corresponding IpoCurve, or None.
+ @raise ValueError: I{curve} is not a valid name or adrcode for this Ipo
+ type.
+ """
+
+ def addCurve(curvename):
+ """
+ Add a new curve to the Ipo object. The possible values for I{curvename} are:
+ 1. Camera Ipo: Lens, ClSta, ClEnd, Apert, FDist.
+ 2. Material Ipo: R, G, B, SpecR, SpecG, SpecB, MirR, MirG, MirB, Ref,
+ Alpha, Emit, Amb, Spec, Hard, SpTra, Ior, Mode, HaSize, Translu,
+ RayMir, FresMir, FresMirI, FresTra, FresTraI, TraGlow, OfsX, OfsY,
+ OfsZ, SizeX, SizeY, SizeZ, texR, texG, texB, DefVar, Col, Nor, Var,
+ Disp.
+ 3. Object Ipo: LocX, LocY, LocZ, dLocX, dLocY, dLocZ, RotX, RotY, RotZ,
+ dRotX, dRotY, dRotZ, SizeX, SizeY, SizeZ, dSizeX, dSizeY, dSizeZ,
+ Layer, Time, ColR, ColG, ColB, ColA, FStreng, FFall, Damping,
+ RDamp, Perm.
+ 4. Lamp Ipo: Energ, R, G, B, Dist, SpoSi, SpoBl, Quad1, Quad2, HaInt.
+ 5. World Ipo: HorR, HorG, HorB, ZenR, ZenG, ZenB, Expos, Misi, MisDi,
+ MisSta, MisHi, StaR, StaG, StaB, StarDi, StarSi, OfsX, OfsY, OfsZ,
+ SizeX, SizeY, SizeZ, TexR, TexG, TexB, DefVar, Col, Nor, Var.
+ 5. World Ipo: HorR, HorG, HorB, ZenR, ZenG, ZenB, Expos, Misi, MisDi,
+ MisSta, MisHi, StarR, StarB, StarG, StarDi, StarSi, OfsX, OfsY, OfsZ,i
+ SizeX, SizeY, SizeZ, texR, texG, texB, DefVar, Col, Nor, Var.
+ 6. Texture Ipo: NSize, NDepth, NType, Turb, Vnw1, Vnw2, Vnw3, Vnw4,
+ MinkMExp, DistM, ColT, iScale, DistA, MgType, MgH, Lacu, Oct,
+ MgOff, MgGain, NBase1, NBase2.
+ 7. Curve Ipo: Speed.
+ 8. Action Ipo: LocX, LocY, LocZ, SizeX, SizeY, SizeZ, QuatX, QuatY,
+ QuatZ, QuatW.
+ 9. Sequence Ipo: Fac.
+ 10. Constraint Ipo: Inf.
+
+ For Key IPOs, the name must be an existing KeyBlock name. Use
+ L{curveConsts} to determine the set of valid names.
+
+ @type curvename : string
+ @rtype: IpoCurve object
+ @return: the corresponding IpoCurve, or None.
+ @raise ValueError: I{curvename} is not valid or already exists
+ """
+
+ def delCurve(curvename):
+ """
+ Delete an existing curve from the Ipo object (B{deprecated}).
+ Use the L{mapping operator B{[]}<__getitem__>} instead::
+ from Blender import Ipo
+
+ ipo = Ipo.Get('ObIpo')
+ ipo[Ipo.LOCX] = None
+
+ @type curvename : string
+ @rtype: None
+ @return: None.
+ """
+
+ def getBlocktype():
+ """
+ Gets the blocktype of the Ipo.
+ @rtype: int
+ @return: the blocktype of the Ipo.
+ """
+
+ def setBlocktype(newblocktype):
+ """
+ Sets the blocktype of the Ipo.
+ @type newblocktype: int
+ @rtype: None
+ @return: None
+ @warn: 'newblocktype' should not be changed unless you really know what
+ you are doing ...
+ """
+
+ def getRctf():
+ """
+ Gets the rctf of the Ipo.
+ Kind of bounding box...
+ @rtype: list of floats
+ @return: the rctf of the Ipo.
+ """
+
+ def setRctf(newrctf):
+ """
+ Sets the rctf of the Ipo.
+ @type newrctf: four floats.
+ @rtype: None
+ @return: None
+ @warn: rctf should not be changed unless you really know what you are
+ doing ...
+ """
+
+ def getNcurves():
+ """
+ Gets the number of curves of the Ipo (B{deprecated}). Use
+ L{len(ipo)<__len__>} instead.
+ @rtype: int
+ @return: the number of curve of the Ipo.
+ """
+
+ def getCurveBP(curvepos):
+ """
+ This method is unsupported. BPoint Ipo curves are not implemented.
+ Calling this method throws a NotImplementedError exception.
+ @raise NotImplementedError: this method B{always} raises an exception
+ """
+
+ def getBeztriple(curvepos,pointpos):
+ """
+ Gets a beztriple of the Ipo (B{deprecated}). B{Note}:
+ Use L{IpoCurve.bezierPoints<IpoCurve.IpoCurve.bezierPoints>} instead.
+ @type curvepos: int
+ @param curvepos: the position of the curve in the Ipo.
+ @type pointpos: int
+ @param pointpos: the position of the point in the curve.
+ @rtype: list of 9 floats
+ @return: the beztriple of the Ipo, or an error is raised.
+ """
+
+ def setBeztriple(curvepos,pointpos,newbeztriple):
+ """
+ Sets the beztriple of the Ipo (B{deprecated}). B{Note}: use
+ L{IpoCurve.bezierPoints<IpoCurve.IpoCurve.bezierPoints>} to get a
+ BezTriple point, then use the
+ L{BezTriple} API to set the point's attributes.
+ @type curvepos: int
+ @param curvepos: the position of the curve in the Ipo.
+ @type pointpos: int
+ @param pointpos: the position of the point in the curve.
+ @type newbeztriple: list of 9 floats
+ @param newbeztriple: the new value for the point
+ @rtype: None
+ @return: None
+ """
+
+ def getCurveCurval(curvepos):
+ """
+ Gets the current value of a curve of the Ipo (B{deprecated}). B{Note}:
+ new scripts should use L{IpoCurve.evaluate()<IpoCurve.IpoCurve.evaluate>}.
+ @type curvepos: int or string
+ @param curvepos: the position of the curve in the Ipo or the name of the
+ curve
+ @rtype: float
+ @return: the current value of the selected curve of the Ipo.
+ """
+
+ def EvaluateCurveOn(curvepos,time):
+ """
+ Gets the value at a specific time of a curve of the Ipo (B{deprecated}).
+ B{Note}: new scripts should use
+ L{IpoCurve.evaluate()<IpoCurve.IpoCurve.evaluate>}.
+ @type curvepos: int
+ @param curvepos: the position of the curve in the Ipo.
+ @type time: float
+ @param time: the desired time.
+ @rtype: float
+ @return: the current value of the selected curve of the Ipo at the given
+ time.
+ """
+import id_generics
+Ipo.__doc__ += id_generics.attributes
diff --git a/source/blender/python/api2_2x/doc/IpoCurve.py b/source/blender/python/api2_2x/doc/IpoCurve.py
new file mode 100644
index 00000000000..873888cffb4
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/IpoCurve.py
@@ -0,0 +1,226 @@
+# Blender.IpoCurve module and the IpoCurve PyType object
+
+"""
+The Blender.IpoCurve submodule
+
+B{New}:
+ - IpoCurves supports the operator [], which accesses the value of
+ curves at a given time.
+
+This module provides access to the IpoCurve data in Blender. An Ipo is
+composed of several IpoCurves, and an IpoCurve are composed of several
+BezTriples.
+
+Example::
+ import Blender
+ ipo = Blender.Ipo.Get('ObIpo') # retrieves an Ipo object
+ ipo.name = 'ipo1' # change the Ipo's name
+ icu = ipo[Blender.Ipo.OB_LOCX] # request X Location Ipo curve object
+ if icu != None and len(icu.bezierPoints) > 0: # if curve exists and has BezTriple points
+ val = icu[2.5] # get the curve's value at time 2.5
+
+@type ExtendTypes: readonly dictionary
+@var ExtendTypes: The available IpoCurve extend types.
+ - CONST - curve is constant beyond first and last knots
+ - EXTRAP - curve maintains same slope beyond first and last knots
+ - CYCLIC - curve values repeat beyond first and last knots
+ - CYCLIC_EXTRAP - curve values repeat beyond first and last knots,
+ but while retaining continuity
+
+@type InterpTypes: readonly dictionary
+@var InterpTypes: The available IpoCurve interpolation types.
+ - CONST - curve remains constant from current BezTriple knot
+ - LINEAR - curve is linearly interpolated between adjacent knots
+ - BEZIER - curve is interpolated by a Bezier curve between adjacent knots
+"""
+
+class IpoCurve:
+ """
+ The IpoCurve object
+ ===================
+ This object gives access to generic data from all Ipo curves objects
+ in Blender.
+
+ Important Notes for Rotation Ipo Curves:\n
+ For the rotation Ipo curves, the y values for points are in units of 10
+ degrees. For example, 45.0 degrees is stored as 4.50 degrees. These are the
+ same numbers you see in the Transform Properties pop-up menu ( NKey ) in
+ the IPO Curve Editor window. Positive rotations are in a counter-clockwise
+ direction, following the standard convention.
+
+ @ivar driver: Status of the driver. 1= on, 0= object, 2= python expression.
+ @type driver: int
+ @ivar driverObject: Object used to drive the Ipo curve.
+ @type driverObject: Blender Object or None
+ @ivar driverExpression: Python expression used to drive the Ipo curve. [0 - 127 chars]
+ @type driverExpression: string
+ @ivar sel: The selection state of this curve.
+ @type sel: bool
+ @ivar driverChannel: Object channel used to drive the Ipo curve.
+ Use module constants: IpoCurve.LOC_X, IpoCurve.LOC_Y, IpoCurve.LOC_Z,
+ IpoCurve.ROT_X, IpoCurve.ROT_Y, IpoCurve.ROT_Z, IpoCurve.SIZE_X,
+ IpoCurve.SIZE_Y, IpoCurve.SIZE_Z
+ @type driverChannel: int
+ @ivar name: The IpoCurve data name.
+ @type name: string
+ @ivar bezierPoints: The list of the curve's bezier points.
+ @type bezierPoints: list of BezTriples.
+ @ivar interpolation: The curve's interpolation mode. See L{InterpTypes} for
+ values.
+ @type interpolation: int
+ @ivar extend: The curve's extend mode. See L{ExtendTypes} for values.
+
+ B{Note}: Cyclic Ipo curves never reach the end value. If the first and
+ last bezier points do not have the same y coordinate, the value of the
+ curve when it "cycles" is that of the first point. If a user wants to
+ get the value of the final curve point, read the final point from the
+ curve::
+
+ ipo = Blender.Object.Get('Cube').ipo
+ icu = ipo['LocX']
+ endtime,endvalue = icu.bezierPoints[-1].pt
+ @type extend: int
+ """
+
+ def __getitem__ (time):
+ """
+ Returns the value of the curve at a particular time.
+ @type time: float
+ @param time: time (Vertex X) on the curve
+ @rtype: float
+ @return: value (Vertex Y) corresponding to the given time
+ """
+
+ def __setitem__ (time):
+ """
+ Sets the value (Vertex Y) of the curve at a particular time.
+ @type time: float
+ @param time: time (Vertex X) on the curve
+ """
+
+ def setExtrapolation(extendmode):
+ """
+ Sets the extend mode of the curve (B{deprecated}). B{Note}: new scripts
+ should use the L{extend} attribute instead.
+ @type extendmode: string
+ @param extendmode: the extend mode of the curve.
+ Can be Constant, Extrapolation, Cyclic or Cyclic_extrapolation.
+ @rtype: None
+ @return: None
+ """
+
+ def getExtrapolation():
+ """
+ Gets the extend mode of the curve (B{deprecated}). B{Note}: new scripts
+ should use the L{extend} attribute instead.
+ @rtype: string
+ @return: the extend mode of the curve. Can be Constant, Extrapolation, Cyclic or Cyclic_extrapolation.
+ """
+
+ def setInterpolation(interpolationtype):
+ """
+ Sets the interpolation type of the curve (B{deprecated}). B{Note}:
+ new scripts should use the L{interpolation} attribute instead.
+ @type interpolationtype: string
+ @param interpolationtype: the interpolation type of the curve. Can be Constant, Bezier, or Linear.
+ @rtype: None
+ @return: None
+ """
+
+ def getInterpolation():
+ """
+ Gets the interpolation type of the curve (B{deprecated}). B{Note}:
+ new scripts should use the L{interpolation} attribute instead.
+ @rtype: string
+ @return: the interpolation type of the curve. Can be Constant, Bezier, or Linear.
+ """
+
+ def append(point):
+ """
+ Adds a Bezier point to a IpoCurve.
+ @type point: BezTriple or tuple of 2 floats
+ @param point: Can either be a BezTriple, or the x and y coordinates of
+ the Bezier knot point.
+ @rtype: None
+ @return: None
+ """
+
+ def addBezier(coordlist):
+ """
+ Adds a Bezier point to a curve B{deprecated}). B{Note}: new scripts
+ should use L{append} instead.
+ @type coordlist: tuple of (at least) 2 floats
+ @param coordlist: the x and y coordinates of the new Bezier point.
+ @rtype: None
+ @return: None
+ """
+
+ def delBezier(index):
+ """
+ Deletes a Bezier point from a curve.
+ @type index: integer
+ @param index: the index of the Bezier point. Negative values index from the end of the list.
+ @rtype: None
+ @return: None
+ """
+
+ def recalc():
+ """
+ Recomputes the curve after changes to control points.
+ @rtype: None
+ @return: None
+ """
+
+ def getName():
+ """
+ Returns the name of the Ipo curve (B{deprecated}). B{Note}:
+ new scripts should use the L{name} attribute instead.
+ The name can be:
+ 1. Camera Ipo: Lens, ClSta, ClEnd, Apert, FDist.
+ 2. Material Ipo: R, G, B, SpecR, SpecG, SpecB, MirR, MirG, MirB, Ref,
+ Alpha, Emit, Amb, Spec, Hard, SpTra, Ior, Mode, HaSize, Translu,
+ RayMir, FresMir, FresMirI, FresTra, FresTraI, TraGlow, OfsX, OfsY,
+ OfsZ, SizeX, SizeY, SizeZ, texR, texG, texB, DefVar, Col, Nor, Var,
+ Disp.
+ 3. Object Ipo: LocX, LocY, LocZ, dLocX, dLocY, dLocZ, RotX, RotY, RotZ,
+ dRotX, dRotY, dRotZ, SizeX, SizeY, SizeZ, dSizeX, dSizeY, dSizeZ,
+ Layer, Time, ColR, ColG, ColB, ColA, FStreng, FFall, Damping,
+ RDamp, Perm.
+ 4. Lamp Ipo: Energ, R, G, B, Dist, SpoSi, SpoBl, Quad1, Quad2, HaInt.
+ 5. World Ipo: HorR, HorG, HorB, ZenR, ZenG, ZenB, Expos, Misi, MisDi,
+ MisSta, MisHi, StaR, StaG, StaB, StarDi, StarSi, OfsX, OfsY, OfsZ,
+ SizeX, SizeY, SizeZ, TexR, TexG, TexB, DefVar, Col, Nor, Var.
+ 5. World Ipo: HorR, HorG, HorB, ZenR, ZenG, ZenB, Expos, Misi, MisDi,
+ MisSta, MisHi, StarR, StarB, StarG, StarDi, StarSi, OfsX, OfsY, OfsZ,i
+ SizeX, SizeY, SizeZ, texR, texG, texB, DefVar, Col, Nor, Var.
+ 6. Texture Ipo: NSize, NDepth, NType, Turb, Vnw1, Vnw2, Vnw3, Vnw4,
+ MinkMExp, DistM, ColT, iScale, DistA, MgType, MgH, Lacu, Oct,
+ MgOff, MgGain, NBase1, NBase2.
+ 7. Curve Ipo: Speed.
+ 8. Action Ipo: LocX, LocY, LocZ, SizeX, SizeY, SizeZ, QuatX, QuatY,
+ QuatZ, QuatW.
+ 9. Sequence Ipo: Fac.
+ 10. Constraint Ipo: Inf.
+
+ @rtype: string
+ @return: the name of the Ipo curve.
+ """
+
+ def getPoints():
+ """
+ Returns all the points of the IpoCurve (B{deprecated}).
+ B{Note}: new scripts should use the L{bezierPoints} attribute instead.
+ @rtype: list of BezTriples
+ @return: the points of the Ipo curve.
+ """
+
+ def evaluate( time ):
+ """
+ Compute the value of the Ipo curve at a particular time (B{deprecated}).
+ B{Note}: new scripts should use L{icu[time]<__getitem__>} instead.
+ @type time: float
+ @param time: value along the X axis
+ @rtype: float
+ @return: the Y value of the curve at the given time
+ """
+
diff --git a/source/blender/python/api2_2x/doc/Ipodoc.txt b/source/blender/python/api2_2x/doc/Ipodoc.txt
new file mode 100644
index 00000000000..81d51595fa9
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Ipodoc.txt
@@ -0,0 +1,66 @@
+IPO Module documentation
+
+
+INTRODUCTION
+The module ipo allows you to access all the data of an ipo.
+The most important part(s) of an ipo is its ipocurve(s). The ipocurve has a set of bezier points (defined by 9 coordinates). The ipo module grants the user read/write access to these points.
+
+
+
+
+functions of the module :
+
+Get(Name:string) : returns the Ipo associated whose name is Name.
+
+get : same as Get
+
+New(Name:string , idcode:int ) : Creates and returns a new Ipo Object.
+The parameters are mandatory. If the name is already used, blender will change it to name.XXX (XXX is an integer)
+
+
+
+Ipo object member functions :
+
+getName() : Retrieves the name of the Ipo Object.
+
+setName(newname:string) : Sets the name of the Ipo Object.
+
+getBlocktype() : Retrieves the blocktype of the Ipo Object.
+
+setBlocktype(newblocktype:string) : Sets the blocktype of the Ipo Object.
+
+getShowkey() : Retrieves the showkey of the Ipo Object.
+
+setShowkey(val:int) : Sets the showkey of the Ipo Object.
+
+getPad() : Retrieves the pad of the Ipo Object.
+
+setPad(val:int) : Sets the pad of the Ipo Object.
+
+getRctf() : Retrieves the rctf of the Ipo Object.
+
+setRctf(val:int) : Sets the rctf of the Ipo Object.
+
+I do not fully understand the meaning of these parameters.
+
+
+
+getNcurves() : returns the number of ipocurves the ipo object contains.
+
+getBP() : returns the basepoint of the ipo object (generally NULL)
+
+getCurveCurval(numcurve:int) : returns the current value of the ipo curve number numcurve.
+
+getCurveBeztriple(numcurve:int,numpoint:int) : returns a list of 9 floats, which are the coordinates of the control point number numpoint of the ipocurve number numcurve.
+
+
+
+setCurveBeztriple(numcurve:int,numpoint:int,newvalues : list of 9 floats) : sets the coordinates of the control point number numpoint of the ipocurve number numcurve to newvalues. (the z coordinate should be 0, but blender does not complain if non null values are passed)
+
+
+
+Example :
+import Blender
+
+d = Blender.Ipo.Get('ObIpo') # hope there is an ipo named "ObIpo"...Else create it before.
+
diff --git a/source/blender/python/api2_2x/doc/Key.py b/source/blender/python/api2_2x/doc/Key.py
new file mode 100644
index 00000000000..53f289d2e8b
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Key.py
@@ -0,0 +1,124 @@
+# Blender.Key module and the Key and KeyBlock PyType objects
+
+"""
+The Blender.Key submodule.
+
+This module provides access to B{Key} objects in Blender.
+
+@type Types: readonly dictionary
+@var Types: The type of a key owner, indicating the type of data in the
+data blocks.
+ - MESH - the key is a Mesh key; data blocks contain
+ L{NMVert<NMesh.NMVert>} vertices.
+ - CURVE - the key is a Curve key; data blocks contains either
+ L{BezTriples<BezTriple.BezTriple>} or points (represented by a list of
+ 3 floating point numbers).
+ - LATTICE - the key is a Lattice key; data blocks contain
+ BPoints, each point represented by a list of 3 floating point numbers.
+"""
+
+def Get(name = None):
+ """
+ Get the named Key object from Blender. If the name is omitted, it
+ will retrieve a list of all keys in Blender.
+ @type name: string
+ @param name: the name of the requested key
+ @return: If name was given, return that Key object (or None if not
+ found). If a name was not given, return a list of every Key object
+ in Blender.
+ """
+
+class Key:
+ """
+ The Key object
+ ==============
+ An object with keyframes (L{Lattice}, L{NMesh} or
+ L{Curve}) will contain a Key object representing the
+ keyframe data.
+
+ @ivar ipo: Key Ipo. Contains the Ipo if one is assigned to the
+ object, B{None} otherwise. Setting to B{None} clears the current Ipo.
+ @type ipo: Blender Ipo
+ @ivar value: The value of the key. Read-only.
+ @type value: float
+ @ivar type: An integer from the L{Types} dictionary
+ representing the Key type. Read-only.
+ @type type: int
+ @ivar blocks: A list of KeyBlocks for the key. Read-only.
+ @type blocks: Blender KeyBlock.
+ @ivar relative: Indicates whether the key is relative(=True) or normal.
+ @type relative: bool
+ """
+
+ def getIpo():
+ """
+ Get the L{Ipo} object associated with this key.
+ """
+ def getBlocks():
+ """
+ Get a list of L{KeyBlock}s, containing the keyframes defined for
+ this Key.
+ """
+
+class KeyBlock:
+ """
+ The KeyBlock object
+ ===================
+ Each Key object has a list of KeyBlocks attached, each KeyBlock
+ representing a keyframe.
+
+ @ivar curval: Current value of the corresponding IpoCurve. Read-only.
+ @type curval: float
+ @ivar name: The name of the Keyblock. Truncated to 32 characters.
+ @type name: string
+ @ivar pos: The position of the keyframe.
+ @type pos: float
+ @ivar slidermin: The minimum value for the action slider.
+ Value is clamped to the range [-10.0,10.0].
+ @type slidermin: float
+ @ivar slidermax: The maximum value for the action slider.
+ Value is clamped to the range [-10.0,10.0].
+ @type slidermax: float
+ @ivar vgroup: The assigned VGroup for the Key Block.
+ @type vgroup: string
+ @ivar data: The data of the KeyBlock (see L{getData}). This
+ attribute is read-only.
+ @type data: varies
+ """
+
+ def getData():
+ """
+ Get the data of a KeyBlock, as a list of data items. Each item
+ will have a different data format depending on the type of this
+ Key.
+
+ Note that prior to 2.45 the behaviour of this function
+ was different (and very wrong). Old scripts might need to be
+ updated.
+
+ - Mesh keys have a list of L{Vectors<Mathutils.Vector>} objects in the data
+ block.
+ - Lattice keys have a list of L{Vectors<Mathutils.Vector>} objects in the data
+ block.
+ - Curve keys return either a list of tuples, eacn containing
+ four L{Vectors<Mathutils.Vector>} (if the curve is a Bezier curve),
+ or otherwise just a list of L{Vectors<Mathutils.Vector>}.
+
+ For bezier keys, the first three vectors in the tuple are the Bezier
+ triple vectors, while the fourth vector's first element is the curve tilt
+ (the other two elements are reserved and are currently unused).
+
+ For non-Bezier keys, the first three elements of the returned vector is
+ the curve handle point, while the fourth element is the tilt.
+
+
+ A word on relative shape keys; relative shape keys are not actually
+ stored as offsets to the base shape key (like you'd expect). Instead,
+ each shape key stores an entire model (actually the state of the mesh
+ vertices after exiting editmode with any given key active).
+
+ The additive offset for a shape key is calculated (when needed) by
+ comparing the shape key with its base key, which is always the very
+ first in the keyblock list.
+ """
+
diff --git a/source/blender/python/api2_2x/doc/Lamp.py b/source/blender/python/api2_2x/doc/Lamp.py
new file mode 100644
index 00000000000..b65fe253530
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Lamp.py
@@ -0,0 +1,521 @@
+# Blender.Lamp module and the Lamp PyType object
+
+"""
+The Blender.Lamp submodule.
+
+B{New}: L{Lamp.clearScriptLinks} accepts a parameter now.
+
+Lamp Data
+=========
+
+This module provides control over B{Lamp Data} objects in Blender.
+
+Example::
+
+ from Blender import Lamp, Scene
+ l = Lamp.New('Spot') # create new 'Spot' lamp data
+ l.setMode('Square', 'Shadow') # set these two lamp mode flags
+ scn = Scene.GetCurrent()
+ ob = scn.objects.new(l)
+
+@type Types: read-only dictionary
+@var Types: The lamp types.
+ - 'Lamp': 0
+ - 'Sun' : 1
+ - 'Spot': 2
+ - 'Hemi': 3
+ - 'Area': 4
+ - 'Photon': 5
+@type Modes: read-only dictionary
+@var Modes: The lamp modes. Modes may be ORed together.
+ - 'Shadows'
+ - 'Halo'
+ - 'Layer'
+ - 'Quad'
+ - 'Negative'
+ - 'OnlyShadow'
+ - 'Sphere'
+ - 'Square'
+ - 'NoDiffuse'
+ - 'NoSpecular'
+ - 'RayShadow'
+
+ Example::
+ from Blender import Lamp, Object
+ # Change the mode of selected lamp objects.
+ for ob in Object.GetSelected(): # Loop through the current selection
+ if ob.getType() == "Lamp": # if this is a lamp.
+ lamp = ob.getData() # get the lamp data.
+ if lamp.type == Lamp.Types["Spot"]: # Lamp type is not a flag
+ lamp.mode &= ~Lamp.Modes["RayShadow"] # Disable RayShadow.
+ lamp.mode |= Lamp.Modes["Shadows"] # Enable Shadowbuffer shadows
+"""
+
+def New (type = 'Lamp', name = 'LampData'):
+ """
+ Create a new Lamp Data object.
+ @type type: string
+ @param type: The Lamp type: 'Lamp', 'Sun', 'Spot', 'Hemi', 'Area', or 'Photon'.
+ @type name: string
+ @param name: The Lamp Data name.
+ @rtype: Blender Lamp
+ @return: The created Lamp Data object.
+ """
+
+def Get (name = None):
+ """
+ Get the Lamp Data object(s) from Blender.
+ @type name: string
+ @param name: The name of the Lamp Data.
+ @rtype: Blender Lamp or a list of Blender Lamps
+ @return: It depends on the I{name} parameter:
+ - (name): The Lamp Data object with the given I{name};
+ - (): A list with all Lamp Data objects in the current scene.
+ """
+
+class Lamp:
+ """
+ The Lamp Data object
+ ====================
+ This object gives access to Lamp-specific data in Blender.
+
+ @ivar B: Lamp color blue component.
+ Value is clamped to the range [0.0,1.0].
+ @type B: float
+ @ivar G: Lamp color green component.
+ Value is clamped to the range [0.0,1.0].
+ @type G: float
+ @ivar R: Lamp color red component.
+ Value is clamped to the range [0.0,1.0].
+ @type R: float
+ @ivar bias: Lamp shadow map sampling bias.
+ Value is clamped to the range [0.01,5.0].
+ @type bias: float
+ @ivar bufferSize: Lamp shadow buffer size.
+ Value is clamped to the range [512,5120].
+ @type bufferSize: int
+ @ivar clipEnd: Lamp shadow map clip end.
+ Value is clamped to the range [1.0,5000.0].
+ @type clipEnd: float
+ @ivar clipStart: Lamp shadow map clip start.
+ Value is clamped to the range [0.1,1000.0].
+ @type clipStart: float
+ @ivar col: Lamp RGB color triplet.
+ Components are clamped to the range [0.0,1.0].
+ @type col: RGB tuple
+ @ivar dist: Lamp clipping distance.
+ Value is clamped to the range [0.1,5000.0].
+ @type dist: float
+ @ivar energy: Lamp light intensity.
+ Value is clamped to the range [0.0,10.0].
+ @type energy: float
+ @ivar haloInt: Lamp spotlight halo intensity.
+ Value is clamped to the range [0.0,5.0].
+ @type haloInt: float
+ @ivar haloStep: Lamp volumetric halo sampling frequency.
+ Value is clamped to the range [0,12].
+ @type haloStep: int
+ @ivar ipo: Lamp Ipo.
+ Contains the Ipo if one is assigned to the object, B{None} otherwise. Setting to B{None} clears the current Ipo..
+ @type ipo: Blender Ipo
+ @ivar mode: Lamp mode bitfield. See L{Modes} for values.
+ @type mode: int
+ @ivar quad1: Quad lamp linear distance attenuation.
+ Value is clamped to the range [0.0,1.0].
+ @type quad1: float
+ @ivar quad2: Quad lamp quadratic distance attenuation.
+ Value is clamped to the range [0.0,1.0].
+ @type quad2: float
+ @ivar samples: Lamp shadow map samples.
+ Value is clamped to the range [1,16].
+ @type samples: int
+ @ivar raySamplesX: Lamp raytracing X samples (X is used for the Y axis with square area lamps).
+ Value is clamped to the range [1,16].
+ @type raySamplesX: int
+ @ivar raySamplesY: Lamp raytracing Y samples (Y is only used for rectangle area lamps).
+ Value is clamped to the range [1,16].
+ @type raySamplesY: int
+ @ivar areaSizeX: Lamp X size (X is used for the Y axis with square area lamps)
+ Value is clamped to the range [0.01,100.0].
+ @type areaSizeX: float
+ @ivar areaSizeY: Lamp Y size (Y is only used for rectangle area lamps).
+ Value is clamped to the range [0.01,100.0].
+ @type areaSizeY: float
+ @ivar softness: Lamp shadow sample area size.
+ Value is clamped to the range [1.0,100.0].
+ @type softness: float
+ @ivar spotBlend: Lamp spotlight edge softness.
+ Value is clamped to the range [0.0,1.0].
+ @type spotBlend: float
+ @ivar spotSize: Lamp spotlight beam angle (in degrees).
+ Value is clamped to the range [1.0,180.0].
+ @type spotSize: float
+ @ivar type: Lamp type. See L{Types} for values.
+ @type type: int
+
+ @warning: Most member variables assume values in some [Min, Max] interval.
+ When trying to set them, the given parameter will be clamped to lie in
+ that range: if val < Min, then val = Min, if val > Max, then val = Max.
+ """
+
+ def getName():
+ """
+ Get the name of this Lamp Data object.
+ @rtype: string
+ """
+
+ def setName(name):
+ """
+ Set the name of this Lamp Data object.
+ @type name: string
+ @param name: The new name.
+ """
+
+ def getType():
+ """
+ Get this Lamp's type.
+ @rtype: int
+ """
+
+ def setType(type):
+ """
+ Set this Lamp's type.
+ @type type: string
+ @param type: The Lamp type: 'Lamp', 'Sun', 'Spot', 'Hemi', 'Area', or 'Photon'
+ """
+
+ def getMode():
+ """
+ Get this Lamp's mode flags.
+ @rtype: int
+ @return: B{OR'ed value}. Use the Modes dictionary to check which flags
+ are 'on'.
+
+ Example::
+ flags = mylamp.getMode()
+ if flags & mylamp.Modes['Shadows']:
+ print "This lamp produces shadows"
+ else:
+ print "The 'Shadows' flag is off"
+ """
+
+ def setMode(m = None, m2 = None, m3 = None, m4 = None,
+ m5 = None, m6 = None, m7 = None, m8 = None):
+ """
+ Set this Lamp's mode flags. Mode strings given are turned 'on'.
+ Those not provided are turned 'off', so lamp.setMode() -- without
+ arguments -- turns off all mode flags for Lamp lamp.
+ @type m: string
+ @param m: A mode flag. From 1 to 8 can be set at the same time.
+ """
+
+ def getSamples():
+ """
+ Get this lamp's samples value.
+ @rtype: int
+ """
+
+ def setSamples(samples):
+ """
+ Set the samples value.
+ @type samples: int
+ @param samples: The new samples value.
+ """
+
+ def getRaySamplesX():
+ """
+ Get this lamp's raytracing sample value on the X axis.
+ This value is only used for area lamps.
+ @rtype: int
+ """
+
+ def setRaySamplesX():
+ """
+ Set the lamp's raytracing sample value on the X axis, between 1 and 16.
+ This value is only used for area lamps.
+ @rtype: int
+ """
+
+ def getRaySamplesY():
+ """
+ Get this lamp's raytracing sample value on the Y axis.
+ This value is only used for rectangle area lamps.
+ @rtype: int
+ """
+
+ def setRaySamplesY():
+ """
+ Set the lamp's raytracing sample value on the Y axis, between 1 and 16.
+ This value is only used for rectangle area lamps.
+ @rtype: int
+ """
+
+ def getAreaSizeX():
+ """
+ Get this lamp's size on the X axis.
+ This value is only used for area lamps.
+ @rtype: int
+ """
+
+ def setAreaSizeX():
+ """
+ Set this lamp's size on the X axis.
+ This value is only used for area lamps.
+ @rtype: int
+ """
+
+ def getAreaSizeY():
+ """
+ Get this lamp's size on the Y axis.
+ This value is only used for rectangle area lamps.
+ @rtype: int
+ """
+
+ def setAreaSizeY():
+ """
+ Set this lamp's size on the Y axis.
+ This value is only used for rectangle area lamps.
+ @rtype: int
+ """
+
+ def getBufferSize():
+ """
+ Get this lamp's buffer size.
+ @rtype: int
+ """
+
+ def setBufferSize(bufsize):
+ """
+ Set the buffer size value.
+ @type bufsize: int
+ @param bufsize: The new buffer size value.
+ """
+
+ def getHaloStep():
+ """
+ Get this lamp's halo step value.
+ @rtype: int
+ """
+
+ def setHaloStep(hastep):
+ """
+ Set the halo step value.
+ @type hastep: int
+ @param hastep: The new halo step value.
+ """
+
+ def getEnergy():
+ """
+ Get this lamp's energy intensity value.
+ @rtype: float
+ """
+
+ def setEnergy(energy):
+ """
+ Set the energy intensity value.
+ @type energy: float
+ @param energy: The new energy value.
+ """
+
+ def getDist():
+ """
+ Get this lamp's distance value.
+ @rtype: float
+ """
+
+ def setDist(distance):
+ """
+ Set the distance value.
+ @type distance: float
+ @param distance: The new distance value.
+ """
+
+ def getSpotSize():
+ """
+ Get this lamp's spot size value.
+ @rtype: float
+ """
+
+ def setSpotSize(spotsize):
+ """
+ Set the spot size value.
+ @type spotsize: float
+ @param spotsize: The new spot size value.
+ """
+
+ def getSpotBlend():
+ """
+ Get this lamp's spot blend value.
+ @rtype: float
+ """
+
+ def setSpotBlend(spotblend):
+ """
+ Set the spot blend value.
+ @type spotblend: float
+ @param spotblend: The new spot blend value.
+ """
+
+ def getClipStart():
+ """
+ Get this lamp's clip start value.
+ @rtype: float
+ """
+
+ def setClipStart(clipstart):
+ """
+ Set the clip start value.
+ @type clipstart: float
+ @param clipstart: The new clip start value.
+ """
+
+ def getClipEnd():
+ """
+ Get this lamp's clip end value.
+ @rtype: float
+ """
+
+ def setClipEnd(clipend):
+ """
+ Set the clip end value.
+ @type clipend: float
+ @param clipend: The new clip end value.
+ """
+
+ def getBias():
+ """
+ Get this lamp's bias value.
+ @rtype: float
+ """
+
+ def setBias(bias):
+ """
+ Set the bias value.
+ @type bias: float
+ @param bias: The new bias value.
+ """
+
+ def getSoftness():
+ """
+ Get this lamp's softness value.
+ @rtype: float
+ """
+
+ def setSoftness(softness):
+ """
+ Set the softness value.
+ @type softness: float
+ @param softness: The new softness value.
+ """
+
+ def getHaloInt():
+ """
+ Get this lamp's halo intensity value.
+ @rtype: float
+ """
+
+ def setHaloInt(haloint):
+ """
+ Set the halo intensity value.
+ @type haloint: float
+ @param haloint: The new halo intensity value.
+ """
+
+ def getQuad1():
+ """
+ Get this lamp's quad 1 value.
+ @rtype: float
+ @warning: this only applies to Lamps with the 'Quad' flag on.
+ """
+
+ def setQuad1(quad1):
+ """
+ Set the quad 1 value.
+ @type quad1: float
+ @warning: this only applies to Lamps with the 'Quad' flag on.
+ """
+
+ def getQuad2():
+ """
+ Get this lamp's quad 2 value.
+ @rtype: float
+ @warning: this only applies to Lamps with the 'Quad' flag on.
+ """
+
+ def setQuad2(quad2):
+ """
+ Set the quad 2 value.
+ @type quad2: float
+ @param quad2: The new quad 2 value.
+ @warning: this only applies to Lamps with the 'Quad' flag on.
+ """
+
+ def getScriptLinks (event):
+ """
+ Get a list with this Lamp's script links of type 'event'.
+ @type event: string
+ @param event: "FrameChanged", "Redraw" or "Render".
+ @rtype: list
+ @return: a list with Blender L{Text} names (the script links of the given
+ 'event' type) or None if there are no script links at all.
+ """
+
+ def clearScriptLinks (links = None):
+ """
+ Delete script links from this Lamp. If no list is specified, all
+ script links are deleted.
+ @type links: list of strings
+ @param links: None (default) or a list of Blender L{Text} names.
+ """
+
+ def addScriptLink (text, event):
+ """
+ Add a new script link to this Lamp.
+ @type text: string
+ @param text: the name of an existing Blender L{Text}.
+ @type event: string
+ @param event: "FrameChanged", "Redraw" or "Render".
+ """
+
+ def getIpo():
+ """
+ Get the Ipo associated with this Lamp object, if any.
+ @rtype: Ipo
+ @return: the wrapped ipo or None.
+ """
+
+ def setIpo(ipo):
+ """
+ Link an ipo to this Lamp object.
+ @type ipo: Blender Ipo
+ @param ipo: a "lamp data" ipo.
+ """
+
+ def clearIpo():
+ """
+ Unlink the ipo from this Lamp object.
+ @return: True if there was an ipo linked or False otherwise.
+ """
+
+ def insertIpoKey(keytype):
+ """
+ Inserts keytype values in lamp ipo at curframe. Uses module constants.
+ @type keytype: Integer
+ @param keytype:
+ -RGB
+ -ENERGY
+ -SPOTSIZE
+ -OFFSET
+ -SIZE
+ @return: None
+ """
+
+ def __copy__ ():
+ """
+ Make a copy of this lamp
+ @rtype: Lamp
+ @return: a copy of this lamp
+ """
+
+import id_generics
+Lamp.__doc__ += id_generics.attributes
diff --git a/source/blender/python/api2_2x/doc/Lattice.py b/source/blender/python/api2_2x/doc/Lattice.py
new file mode 100644
index 00000000000..8666254ec0d
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Lattice.py
@@ -0,0 +1,209 @@
+# Blender.Lattice module and the Lattice PyType object
+
+"""
+The Blender.Lattice submodule.
+
+Lattice Object
+==============
+
+This module provides access to B{Lattice} object in Blender.
+
+Example::
+ import Blender
+ from Blender import Lattice, Object, Scene, Modifier
+
+ # Make new lattice data
+ lattice_data = Lattice.New()
+ lattice_data.setPartitions(5,5,5)
+ lattice_data.setKeyTypes(Lattice.LINEAR, Lattice.CARDINAL, Lattice.BSPLINE)
+ lattice_data.setMode(Lattice.OUTSIDE)
+
+ for y in range(125):
+ vec = lattice_data.getPoint(y)
+ co1 = vec[0] + vec[0] / 5
+ co2 = vec[1] - vec[2] * 0.3
+ co3 = vec[2] * 3
+ lattice_data.setPoint(y,[co1,co2,co3])
+
+ # Create a new object from the lattice in the current scene
+ scn = Scene.GetCurrent()
+ ob_lattice = scn.objects.new(lattice_data)
+
+ # Get an object to deform with this lattice
+ mySphere = Object.Get('Sphere')
+
+ # Apply lattice modifier
+ mod= mySphere.modifiers.append(Modifier.Type.LATTICE)
+ mod[Modifier.Settings.OBJECT] = ob_lattice
+ mySphere.makeDisplayList()
+
+ Blender.Redraw()
+"""
+
+def New (name = None):
+ """
+ Create a new Lattice object.
+ Passing a name to this function will name the Lattice
+ datablock, otherwise the Lattice data will be given a
+ default name.
+ @type name: string
+ @param name: The Lattice name.
+ @rtype: Blender Lattice
+ @return: The created Lattice Data object.
+ """
+
+def Get (name = None):
+ """
+ Get the Lattice object(s) from Blender.
+ @type name: string
+ @param name: The name of the Lattice object.
+ @rtype: Blender Lattice or a list of Blender Lattices
+ @return: It depends on the 'name' parameter:
+ - (name): The Lattice object with the given name;
+ - (): A list with all Lattice objects in the current scene.
+ """
+
+class Lattice:
+ """
+ The Lattice object
+ ==================
+ This object gives access to Lattices in Blender.
+ @ivar width: The number of x dimension partitions.
+ @ivar height: The number of y dimension partitions.
+ @ivar depth: The number of z dimension partitions.
+ @ivar widthType: The x dimension key type.
+ @ivar heightType: The y dimension key type.
+ @ivar depthType: The z dimension key type.
+ @ivar mode: The current mode of the Lattice.
+ @ivar latSize: The number of points in this Lattice (width*height*depth).
+ @cvar key: The L{Key.Key} object associated with this Lattice or None.
+ """
+
+ def getName():
+ """
+ Get the name of this Lattice datablock.
+ @rtype: string
+ @return: The name of the Lattice datablock.
+ """
+
+ def setName(name):
+ """
+ Set the name of this Lattice datablock.
+ @type name: string
+ @param name: The new name.
+ """
+
+ def getPartitions():
+ """
+ Gets the number of 'walls' or partitions that the Lattice has
+ in the x, y, and z dimensions.
+ @rtype: list of ints
+ @return: A list corresponding to the number of partitions: [x,y,z]
+ """
+
+ def setPartitions(x,y,z):
+ """
+ Set the number of 'walls' or partitions that the
+ Lattice will be created with in the x, y, and z dimensions.
+ @type x: int
+ @param x: The number of partitions in the x dimension of the Lattice.
+ @type y: int
+ @param y: The number of partitions in the y dimension of the Lattice.
+ @type z: int
+ @param z: The number of partitions in the z dimension of the Lattice.
+ """
+
+ def getKeyTypes():
+ """
+ Returns the deformation key types for the x, y, and z dimensions of the
+ Lattice.
+ @rtype: list of strings
+ @return: A list corresponding to the key types will be returned: [x,y,z]
+ """
+
+ def setKeyTypes(xType,yType,zType):
+ """
+ Sets the deformation key types for the x, y, and z dimensions of the
+ Lattice.
+ There are three key types possible:
+ - Lattice.CARDINAL
+ - Lattice.LINEAR
+ - Lattice.BSPLINE
+ @type xType: enum constant
+ @param xType: the deformation key type for the x dimension of the Lattice
+ @type yType: enum constant
+ @param yType: the deformation key type for the y dimension of the Lattice
+ @type zType: enum constant
+ @param zType: the deformation key type for the z dimension of the Lattice
+ """
+
+ def getMode():
+ """
+ Returns the current Lattice mode
+ @rtype: string
+ @return: A string representing the current Lattice mode
+ """
+
+ def setMode(modeType):
+ """
+ Sets the current Lattice mode
+ There are two Lattice modes possible:
+ - Lattice.GRID
+ - Lattice.OUTSIDE
+ @type modeType: enum constant
+ @param modeType: the Lattice mode
+ """
+
+ def getPoint(index):
+ """
+ Returns the coordinates of a point in the Lattice by index.
+ @type index: int
+ @param index: The index of the point on the Lattice you want returned
+ @rtype: list of floats
+ @return: The x,y,z coordiates of the Lattice point : [x,y,z]
+ """
+
+ def setPoint(index, position):
+ """
+ Sets the coordinates of a point in the Lattice by index.
+ @type index: int
+ @param index: The index of the point on the Lattice you want set
+ @type position: list of floats
+ @param position: The x,y,z coordinates that you want the point to be: [x,y,z]
+ """
+
+ def getKey():
+ """
+ Returns the L{Key.Key} object associated with this Lattice.
+ @rtype: L{Key.Key}
+ @return: A key object representing the keyframes of the lattice or None.
+ """
+
+ def insertKey(frame):
+ """
+ Inserts the current state of the Lattice as a new absolute keyframe
+
+ B{Example}::
+ for z in range(5):
+ for y in range(125):
+ vec = myLat.getPoint(y)
+ co1 = vec[0] + vec[2]
+ co2 = vec[1] - vec[2]
+ co3 = vec[2] + vec[1]
+ myLat.setPoint(y,[co1,co2,co3])
+ w = (z + 1) * 10
+ myLat.insertKey(w)
+
+ @type frame: int
+ @param frame: the frame at which the Lattice will be set as a keyframe
+ """
+
+ def __copy__ ():
+ """
+ Make a copy of this lattice
+ @rtype: Lattice
+ @return: a copy of this lattice
+ """
+
+import id_generics
+Lattice.__doc__ += id_generics.attributes
diff --git a/source/blender/python/api2_2x/doc/LibData.py b/source/blender/python/api2_2x/doc/LibData.py
new file mode 100644
index 00000000000..7884ea50659
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/LibData.py
@@ -0,0 +1,137 @@
+# bpy.lib submodule
+
+"""
+The bpy.libraries submodule.
+
+Libraries
+=========
+
+This module provides access to objects stored in .blend files. With it scripts
+can append from Blender files to the current scene, like the File->Append
+menu entry in Blender does. It allows programmers to use .blend files as
+data files for their scripts.
+
+@warn: This module is new and being considered as a replacement for the
+L{original Library<Library>} module. Users should stay tuned to see
+which module is supported in the end.
+
+Example::
+ import bpy
+
+ scn= bpy.scenes.active # get current scene
+ lib = bpy.libraries.load('//file.blend') # open file.blend
+ ob = scn.objects.link(lib.objects.append('Cube')) # append Cube object from library to current scene
+ mat = lib.objects.link('Material') # get a link to a material
+ me = ob.getData(mesh=1) # get mesh data
+ me.materials[0] = mat # assign linked material to mesh
+"""
+
+def load(filename):
+ """
+ Select an existing .blend file for use as a library. Unlike the
+ Library module, multiple libraries can be defined at the same time.
+
+ @type filename: string
+ @param filename: The filename of a Blender file. Filenames starting with "//" will be loaded relative to the blend file's location.
+ @rtype: Library
+ @return: return a L{Library} object.
+ """
+
+class Libraries:
+ """
+ The Library object
+ ==================
+ This class provides a unified way to access and manipulate library types
+ in Blender.
+ It provides access to scenes, objects, meshes, curves, metaballs,
+ materials, textures, images, lattices, lamps, cameras, ipos, worlds,
+ fonts, texts, sounds, groups, armatures, and actions.
+ @ivar filename: The path to the library
+ @type filename: string
+ @ivar scenes: library L{scene<Scene.Scene>} data
+ @type scenes: L{LibData}
+ @ivar objects: library L{object<Object.Object>} data
+ @type objects: L{LibData}
+ @ivar meshes: library L{mesh<Mesh.Mesh>} data
+ @type meshes: L{LibData}
+ @ivar curves: library L{curve<Curve.Curve>} data
+ @type curves: L{LibData}
+ @ivar metaballs: library L{metaball<Metaball.Metaball>} data
+ @type metaballs: L{LibData}
+ @ivar materials: library L{material<Material.Material>} data
+ @type materials: L{LibData}
+ @ivar textures: library L{texture<Texture.Texture>} data
+ @type textures: L{LibData}
+ @ivar images: library L{image<Image.Image>} data
+ @type images: L{LibData}
+ @ivar lattices: library L{lattice<Lattice.Lattice>} data
+ @type lattices: L{LibData}
+ @ivar lamps: library L{lamp<Lamp.Lamp>} data
+ @type lamps: L{LibData}
+ @ivar cameras: library L{camera<Camera.Camera>} data
+ @type cameras: L{LibData}
+ @ivar ipos: library L{ipo<Ipo.Ipo>} data
+ @type ipos: L{LibData}
+ @ivar worlds: library L{world<World.World>} data
+ @type worlds: L{LibData}
+ @ivar fonts: library L{font<Font.Font>} data
+ @type fonts: L{LibData}
+ @ivar texts: library L{text<Text.Text>} data
+ @type texts: L{LibData}
+ @ivar sounds: library L{sound<Sound.Sound>} data
+ @type sounds: L{LibData}
+ @ivar groups: library L{group<Group.Group>} data
+ @type groups: L{LibData}
+ @ivar armatures: library L{armature<Armature.Armature>} data
+ @type armatures: L{LibData}
+ @ivar actions: library L{action<NLA.Action>} data
+ @type actions: L{LibData}
+ """
+
+class LibData:
+ """
+ Generic Library Data Access
+ ===========================
+ This class provides access to a specific type of library data.
+ """
+
+ def append(name):
+ """
+ Append a new datablock from a library. The new copy
+ is added to the current .blend file.
+
+ B{Note}: Blender Objects cannot be appended or linked without linking
+ them to a scene. For this reason, lib.objects.append() returns a
+ special "wrapper object" which must be passed to Scene.objects.link()
+ or bpy.scenes.active.link() in order to actually create the object.
+ So the following code will not create a new object::
+ import bpy
+
+ scn= bpy.scenes.active # get current scene
+ lib = bpy.libraries.load('//file.blend') # open file.blend
+ pseudoOb = lib.objects.append('Cube')) # get an object wrapper
+ But this code will::
+ import bpy
+
+ scn= bpy.scenes.active # get current scene
+ lib = bpy.libraries.load('//file.blend') # open file.blend
+ pseudoOb = lib.objects.append('Cube')) # get an object wrapper
+ ob = scn.objects.link(pseudoOb) # link to scene
+ @rtype: Blender data
+ @return: return a Blender datablock or object
+ @raise IOError: library cannot be read
+ @raise ValueError: library does not contain B{name}
+ """
+
+ def link(name):
+ """
+ Link a new datablock from a library. The linked data is not copied
+ into the local .blend file.
+
+ See L{append} for notes on special handling of Blender Objects.
+ @rtype: Blender data
+ @return: return a Blender datablock or object
+ @raise IOError: library cannot be read
+ @raise ValueError: library does not contain B{name}
+ """
+
diff --git a/source/blender/python/api2_2x/doc/Library.py b/source/blender/python/api2_2x/doc/Library.py
new file mode 100644
index 00000000000..c99739d939b
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Library.py
@@ -0,0 +1,114 @@
+# Blender.Library submodule
+
+"""
+The Blender.Library submodule.
+
+Library
+=======
+
+This module provides access to objects stored in .blend files. With it scripts
+can append from Blender files to the current scene, like the File->Append
+menu entry in Blender does. It allows programmers to use .blend files as
+data files for their scripts.
+
+@warn: This module is being considered for deprecation. Users should
+consider using the L{new Library<LibData>} module and stay tuned to see
+which module is supported in the end.
+
+Example::
+ import Blender
+ from Blender import Library
+
+ def f(name):
+ open_library(name)
+
+ def open_library(name):
+ Library.Open(name)
+ groups = Library.LinkableGroups()
+
+ for db in groups:
+ print "DATABLOCK %s:" % db
+ for obname in Library.Datablocks(db):
+ print obname
+
+ if 'Object' in groups:
+ for obname in Library.Datablocks('Object'):
+ Library.Load(obname, 'Object', 0) # note the 0...
+ Library.Update()
+
+ Library.Close()
+ b.Redraw()
+
+ b.Window.FileSelector(f, "Choose Library", "*.blend")
+
+"""
+
+def Open (filename):
+ """
+ Open an existing .blend file. If there was already one open file, it is
+ closed first.
+ @type filename: string
+ @param filename: The filename of a Blender file. Filenames starting with "//" will be loaded relative to the blend file's location.
+ @rtype: bool
+ @return: 1 if successful. An IOError exception is thrown if the file cannot be opened.
+ """
+
+def Close ():
+ """
+ Close the currently open library file, if any.
+ """
+
+def getName ():
+ """
+ Get the filename of the currently open library file.
+ @rtype: string
+ @return: The open library filename.
+ """
+
+def LinkableGroups ():
+ """
+ Get all the linkable group names from the currently open library file. These
+ are the available groups for linking with the current scene. Ex: 'Object',
+ 'Mesh', 'Material', 'Text', etc.
+ @rtype: list of strings
+ @return: the list of linkable groups.
+ """
+
+def Datablocks (group):
+ """
+ Get all datablock objects of the given 'group' available in the currently
+ open library file.
+ @type group: string
+ @param group: datablock group, see L{LinkableGroups}.
+ """
+
+def Load (datablock, group, update = 1, linked = 0):
+ """
+ Load the given datablock object from the current library file
+ @type datablock: string
+ @type group: string
+ @type update: bool
+ @type linked: bool
+ @param datablock: an available object name, as returned by L{Datablocks}.
+ @param group: an available group name, as returned by L{LinkableGroups}.
+ @param update: defines if Blender should be updated after loading this
+ object. This means linking all objects and remaking all display lists,
+ so it is potentially very slow.
+ @param linked: Will keep objects linked to their source blend file, the update option or later updating will unlink the data from the original blend and make it local.
+
+ @warn: If you plan to load more than one object in sequence, it is
+ B{definitely recommended} to set 'update' to 0 in all calls to this
+ function and after them call L{Update}.
+ """
+
+def Update ():
+ """
+ Update all links and display lists in Blender. This function should be
+ called after a series of L{Load}(datablock, group, B{0}) calls to make
+ everything behave nicely.
+ @warn: to use this function, remember to set the third L{Load} parameter to
+ zero or each loading will automatically update Blender, which will slow
+ down your script and make you look like a lousy programmer.
+ Enough warnings :)?
+ """
+
diff --git a/source/blender/python/api2_2x/doc/Material.py b/source/blender/python/api2_2x/doc/Material.py
new file mode 100644
index 00000000000..40207dd92c0
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Material.py
@@ -0,0 +1,1061 @@
+# Blender.Material module and the Material PyObject
+
+"""
+The Blender.Material submodule.
+
+B{New}: access to shader data.
+
+Material
+========
+
+This module provides access to B{Material} objects in Blender.
+
+Example::
+ import Blender
+ from Blender import Material
+ mat = Material.New('newMat') # create a new Material called 'newMat'
+ print mat.rgbCol # print its rgb color triplet sequence
+ mat.rgbCol = [0.8, 0.2, 0.2] # change its color
+ mat.setAlpha(0.2) # mat.alpha = 0.2 -- almost transparent
+ mat.emit = 0.7 # equivalent to mat.setEmit(0.8)
+ mat.mode |= Material.Modes.ZTRANSP # turn on Z-Buffer transparency
+ mat.setName('RedBansheeSkin') # change its name
+ mat.setAdd(0.8) # make it glow
+ mat.setMode('Halo') # turn 'Halo' "on" and all others "off"
+
+@type Modes: readonly dictionary
+@var Modes: The available Material Modes.
+
+ B{Note}: Some Modes are only available when the 'Halo' mode is I{off} and
+ others only when it is I{on}. But these two subsets of modes share the same
+ numerical values in their Blender C #defines. So, for example, if 'Halo' is
+ on, then 'NoMist' is actually interpreted as 'HaloShaded'. We marked all
+ such possibilities in the Modes dict below: each halo-related mode that
+ uses an already taken value is preceded by "+" and appear below the normal
+ mode which also uses that value.
+
+ - TRACEABLE - Make Material visible for shadow lamps.
+ - SHADOW - Enable Material for shadows.
+ - SHADOWBUF - Enable Material to cast shadows with shadow buffers.
+ - SHADELESS - Make Material insensitive to light or shadow.
+ - WIRE - Render only the edges of faces.
+ - VCOL_LIGHT - Add vertex colors as extra light.
+ - VCOL_PAINT - Replace basic colors with vertex colors.
+ - HALO - Render as a halo.
+ - ZTRANSP - Z-buffer transparent faces.
+ - ZINVERT - Render with inverted Z-buffer.
+ - + HALORINGS - Render rings over the basic halo.
+ - ENV - Do not render Material.
+ - + HALOLINES - Render star shaped lines over the basic halo.
+ - ONLYSHADOW - Let alpha be determined on the degree of shadow.
+ - + HALOXALPHA - Use extreme alpha.
+ - TEXFACE - UV-Editor assigned texture gives color and texture info for faces.
+ - + HALOSTAR - Render halo as a star.
+ - NOMIST - Set the Material insensitive to mist.
+ - + HALOSHADED - Let halo receive light.
+ - HALOTEX - Give halo a texture.
+ - HALOPUNO - Use the vertex normal to specify the dimension of the halo.
+ - HALOFLARE - Render halo as a lens flare.
+ - RAYMIRROR - Enables raytracing for mirror reflection rendering.
+ - RAYTRANSP - Enables raytracing for transparency rendering.
+ - RAYBIAS - Prevent ray traced shadow errors with Phong interpolated normals.
+ - RAMPCOL - Status of colorband ramp for Material's diffuse color. This is a read-only bit.
+ - RAMPSPEC - Status of colorband ramp for Material's specular color. This is a read-only bit.
+ - TANGENTSTR - Uses direction of strands as normal for tangent-shading.
+ - TRANSPSHADOW - Lets Material receive transparent shadows based on material color and alpha.
+ - FULLOSA - Force rendering of all OSA samples.
+ - TANGENT_V - Use the tangent vector in V direction for shading
+ - NMAP_TS - Tangent space normal mapping.
+ - GROUP_EXCLUSIVE - Light from this group even if the lights are on a hidden Layer.
+
+@type Shaders: readonly dictionary
+@var Shaders: The available Material Shaders.
+ - DIFFUSE_LAMBERT - Make Material use the lambert diffuse shader.
+ - DIFFUSE_ORENNAYAR - Make Material use the Oren-Nayer diffuse shader.
+ - DIFFUSE_TOON - Make Material use the toon diffuse shader.
+ - DIFFUSE_MINNAERT - Make Material use the minnaert diffuse shader.
+ - SPEC_COOKTORR - Make Material use the Cook-Torr specular shader.
+ - SPEC_PHONG - Make Material use the Phong specular shader.
+ - SPEC_BLINN - Make Material use the Blinn specular shader.
+ - SPEC_TOON - Make Material use the toon specular shader.
+ - SPEC_WARDISO - Make Material use the Ward-iso specular shader.
+"""
+
+def New (name = 'Mat'):
+ """
+ Create a new Material object.
+ @type name: string
+ @param name: The Material name.
+ @rtype: Blender Material
+ @return: The created Material object.
+ """
+
+def Get (name = None):
+ """
+ Get the Material object(s) from Blender.
+ @type name: string
+ @param name: The name of the Material.
+ @rtype: Blender Material or a list of Blender Materials
+ @return: It depends on the 'name' parameter:
+ - (name): The Material object with the given name;
+ - (): A list with all Material objects in the current scene.
+ """
+
+class Material:
+ """
+ The Material object
+ ===================
+ This object gives access to Materials in Blender.
+ @ivar B: Diffuse color (L{rgbCol}) blue component.
+ Value is clamped to the range [0.0,1.0].
+ @type B: float
+ @ivar G: Diffuse color (L{rgbCol}) green component.
+ Value is clamped to the range [0.0,1.0].
+ @type G: float
+ @ivar IOR: Angular index of refraction for raytrace.
+ Value is clamped to the range [1.0,3.0].
+ @type IOR: float
+ @ivar R: Diffuse color (L{rgbCol}) red component.
+ Value is clamped to the range [0.0,1.0].
+ @type R: float
+ @ivar add: Strength of the add effect.
+ Value is clamped to the range [0.0,1.0].
+ @type add: float
+ @ivar alpha: Alpha (translucency) component of the material.
+ Value is clamped to the range [0.0,1.0].
+ @type alpha: float
+ @ivar shadAlpha: Shadow Alpha for irregular shadow buffer.
+ Value is clamped to the range [0.0,1.0].
+ @type shadAlpha: float
+ @ivar amb: Amount of global ambient color material receives.
+ Value is clamped to the range [0.0,1.0].
+ @type amb: float
+ @ivar diffuseDarkness: Material's diffuse darkness ("Minnaert" diffuse shader only).
+ Value is clamped to the range [0.0,2.0].
+ @type diffuseDarkness: float
+ @ivar diffuseShader: Diffuse shader type (see L{Shaders}).
+ Value must be in the range [0,3].
+ @type diffuseShader: int
+ @ivar diffuseSize: Material's diffuse area size ("Toon" diffuse shader only).
+ Value is clamped to the range [0.0,3.14].
+ @type diffuseSize: float
+ @ivar diffuseSmooth: Material's diffuse area smoothing ("Toon" diffuse shader only).
+ Value is clamped to the range [0.0,1.0].
+ @type diffuseSmooth: float
+ @ivar emit: Amount of light the material emits.
+ Value is clamped to the range [0.0,1.0].
+ @type emit: float
+ @ivar filter: Amount of filtering when transparent raytrace is enabled.
+ Value is clamped to the range [0.0,1.0].
+ @type filter: float
+ @ivar flareBoost: Flare's extra strength.
+ Value is clamped to the range [0.1,1.0].
+ @type flareBoost: float
+ @ivar flareSeed: Offset in the flare seed table.
+ Value is clamped to the range [1,255].
+ @type flareSeed: int
+ @ivar flareSize: Ratio of flare size to halo size.
+ Value is clamped to the range [0.1,25.0].
+ @type flareSize: float
+ @ivar fresnelDepth: Power of Fresnel for mirror reflection.
+ Value is clamped to the range [0.0,5.0].
+ @type fresnelDepth: float
+ @ivar fresnelDepthFac: Blending factor for Fresnel mirror.
+ Value is clamped to the range [1.0,5.0].
+ @type fresnelDepthFac: float
+ @ivar fresnelTrans: Power of Fresnel for transparency.
+ Value is clamped to the range [0.0,5.0].
+ @type fresnelTrans: float
+ @ivar fresnelTransFac: Blending factor for Fresnel transparency.
+ Value is clamped to the range [1.0,5.0].
+ @type fresnelTransFac: float
+ @ivar rbFriction: Rigid Body Friction coefficient.
+ Value is clamped to the range [0.0,100.0].
+ @type rbFriction: float
+ @ivar rbRestitution: Rigid Body Friction restitution.
+ Value is clamped to the range [0.0,1.0].
+ @type rbRestitution: float
+ @ivar haloSeed: Randomizes halo ring dimension and line location.
+ Value is clamped to the range [1,255].
+ @type haloSeed: int
+ @ivar haloSize: Dimension of the halo.
+ Value is clamped to the range [0.0,100.0].
+ @type haloSize: float
+ @ivar hard: Hardness of the specularity.
+ Value is clamped to the range [1,255].
+ @type hard: int
+ @ivar ipo: Material Ipo data.
+ Contains the Ipo if one is assigned to the object, None otherwise. Setting to None clears the current Ipo.
+ @type ipo: Blender Ipo
+
+ @ivar mirCol: Mirror RGB color triplet.
+ Components are clamped to the range [0.0,1.0].
+ @type mirCol: list of 3 floats
+ @ivar mirB: Mirror color (L{mirCol}) blue component.
+ Value is clamped to the range [0.0,1.0].
+ @type mirB: float
+ @ivar mirG: Mirror color (L{mirCol}) green component.
+ Value is clamped to the range [0.0,1.0].
+ @type mirG: float
+ @ivar mirR: Mirror color (L{mirCol}) red component.
+ Value is clamped to the range [0.0,1.0].
+ @type mirR: float
+
+ @ivar sssCol: SubSsurface scattering RGB color triplet.
+ Components are clamped to the range [0.0,1.0].
+ @type sssCol: list of 3 floats
+ @ivar sssB: SubSsurface scattering color (L{sssCol}) blue component.
+ Value is clamped to the range [0.0,1.0].
+ @type sssB: float
+ @ivar sssG: SubSsurface scattering color (L{sssCol}) green component.
+ Value is clamped to the range [0.0,1.0].
+ @type sssG: float
+ @ivar sssR: SubSsurface scattering color (L{sssCol}) red component.
+ Value is clamped to the range [0.0,1.0].
+ @type sssR: float
+
+ @ivar mode: Mode mode bitfield. See L{the Modes dictionary<Modes>} keys and descriptions.
+ @type mode: int
+ @ivar nFlares: Number of subflares with halo.
+ Value is clamped to the range [1,32].
+ @type nFlares: int
+ @ivar nLines: Number of star-shaped lines with halo.
+ Value is clamped to the range [0,250].
+ @type nLines: int
+ @ivar nRings: Number of rings with halo.
+ Value is clamped to the range [0,24].
+ @type nRings: int
+ @ivar nStars: Number of star points with halo.
+ Value is clamped to the range [3,50].
+ @type nStars: int
+ @ivar oopsLoc: Material OOPs location. Returns None if material not found in list.
+ @type oopsLoc: list of 2 floats
+ @ivar oopsSel: Material OOPs selection flag.
+ Value must be in the range [0,1].
+ @type oopsSel: int
+ @ivar rayMirr: Mirror reflection amount for raytrace.
+ Value is clamped to the range [0.0,1.0].
+ @type rayMirr: float
+ @ivar rayMirrDepth: Amount of raytrace inter-reflections.
+ Value is clamped to the range [0,10].
+ @type rayMirrDepth: int
+ @ivar ref: Amount of reflections (for shader).
+ Value is clamped to the range [0.0,1.0].
+ @type ref: float
+ @ivar refracIndex: Material's Index of Refraction (applies to the "Blinn" Specular Shader only.
+ Value is clamped to the range [1.0,10.0].
+ @type refracIndex: float
+ @ivar rgbCol: Diffuse RGB color triplet.
+ Components are clamped to the range [0.0,1.0].
+ @type rgbCol: list of 3 floats
+ @ivar rms: Material's surface slope standard deviation ("WardIso" specular shader only).
+ Value is clamped to the range [0.0,0.4].
+ @type rms: float
+ @ivar roughness: Material's roughness ("Oren Nayar" diffuse shader only).
+ Value is clamped to the range [0.0,3.14].
+ @type roughness: float
+ @ivar spec: Degree of specularity.
+ Value is clamped to the range [0.0,2.0].
+ @type spec: float
+ @ivar specB: Specular color (L{specCol}) blue component.
+ Value is clamped to the range [0.0,1.0].
+ @type specB: float
+ @ivar specCol: Specular RGB color triplet.
+ Components are clamped to the range [0.0,1.0].
+ @type specCol: list of 3 floats
+ @ivar specG: Specular color (L{specCol}) green component.
+ Value is clamped to the range [0.0,1.0].
+ @type specG: float
+ @ivar specR: Specular color (L{specCol}) red component.
+ Value is clamped to the range [0.0,1.0].
+ @type specR: float
+ @ivar specShader: Specular shader type. See L{Shaders}.
+ Value must be in the range [0,4].
+ @type specShader: int
+ @ivar specSize: Material's specular area size ("Toon" specular shader only).
+ Value is clamped to the range [0.0,1.53].
+ @type specSize: float
+ @ivar specSmooth: Sets the smoothness of specular toon area.
+ Value is clamped to the range [0.0,1.0].
+ @type specSmooth: float
+ @ivar specTransp: Makes specular areas opaque on transparent materials.
+ Value is clamped to the range [0.0,1.0].
+ @type specTransp: float
+ @ivar subSize: Dimension of subflares, dots and circles.
+ Value is clamped to the range [0.1,25.0].
+ @type subSize: float
+ @ivar transDepth: calculated maximal. Amount of refractions for raytrace.
+ Value is clamped to the range [0,10].
+ @type transDepth: int
+ @ivar translucency: Amount of diffuse shading of the back side.
+ Value is clamped to the range [0.0,1.0].
+ @type translucency: float
+ @ivar zOffset: Artificial offset in the Z buffer (for Ztransp option).
+ Value is clamped to the range [0.0,10.0].
+ @type zOffset: float
+ @ivar lightGroup: Limits lights that affect this material to a group.
+ @type lightGroup: Group or None
+ @ivar uvlayer: The uv layer name to use, when UV mapping is enabled.
+ @type uvlayer: string
+ @ivar colorband: Material colorband, a list of colors,
+ each color a list of 5 floats [0 - 1], [r,g,b,a,pos].
+ The colorband can have between 1 and 31 colors.
+ @type colorband: list
+
+ @ivar colorbandDiffuse: Material colorband, a list of colors,
+ each color a list of 5 floats [0 - 1], [r,g,b,a,pos].
+ The colorband can have between 1 and 31 colors.
+ @type colorbandDiffuse: list
+ @ivar colorbandSpecular: Material colorband, a list of colors,
+ each color a list of 5 floats [0 - 1], [r,g,b,a,pos].
+ The colorband can have between 1 and 31 colors.
+ @type colorbandSpecular: list
+
+ @ivar enableSSS: If True, subsurface scattering will be rendered on this material.
+ @type enableSSS: bool
+ @ivar sssScale: If True, subsurface scattering will be rendered on this material.
+ Value is clamped to the range [0.1,1000.0].
+ @type sssScale: bool
+ @ivar sssRadiusRed: Mean red scattering path length.
+ Value is clamped to the range [0.0,10000.0].
+ @type sssRadiusRed: float
+ @ivar sssRadiusGreen: Mean green scattering path length.
+ Value is clamped to the range [0.0,10000.0].
+ @type sssRadiusGreen: float
+ @ivar sssRadiusBlue: Mean blue scattering path length.
+ Value is clamped to the range [0.0,10000.0].
+ @type sssRadiusBlue: float
+ @ivar sssIOR: Refraction index.
+ Value is clamped to the range [0.1,2.0].
+ @type sssIOR: float
+ @ivar sssError: Error allowance for the calculation (a low value is slower).
+ Value is clamped to the range [0.0,10.0].
+ @type sssError: float
+ @ivar sssColorBlend: Blend factor for SSS colors.
+ Value is clamped to the range [0.0,1.0].
+ @type sssColorBlend: float
+ @ivar sssTextureScatter: Texture scattering factor.
+ Value is clamped to the range [0.0,1.0].
+ @type sssTextureScatter: float
+ @ivar sssFront: Front scattering weight.
+ Value is clamped to the range [0.0,2.0].
+ @type sssFront: float
+ @ivar sssBack: Back scattering weight
+ Value is clamped to the range [0.0,10.0].
+ @type sssBack: float
+
+ @warning: Most member variables assume values in some [Min, Max] interval.
+ When trying to set them, the given parameter will be clamped to lie in
+ that range: if val < Min, then val = Min, if val > Max, then val = Max.
+
+ """
+
+ def getName():
+ """
+ Get the name of this Material object.
+ @rtype: string
+ """
+
+ def setName(name):
+ """
+ Set the name of this Material object.
+ @type name: string
+ @param name: The new name.
+ """
+
+ def getIpo():
+ """
+ Get the Ipo associated with this material, if any.
+ @rtype: Ipo
+ @return: the wrapped ipo or None.
+ """
+
+ def setIpo(ipo):
+ """
+ Link an ipo to this material.
+ @type ipo: Blender Ipo
+ @param ipo: a material type ipo.
+ """
+
+ def clearIpo():
+ """
+ Unlink the ipo from this material.
+ @return: True if there was an ipo linked or False otherwise.
+ """
+
+ def insertIpoKey(keytype):
+ """
+ Inserts keytype values in material ipo at curframe. Uses module constants.
+ @type keytype: Integer
+ @param keytype:
+ -RGB
+ -ALPHA
+ -HALOSIZE
+ -MODE
+ -ALLCOLOR
+ -ALLMIRROR
+ -OFS
+ -SIZE
+ -ALLMAPPING
+ @return: py_none
+ """
+
+ def getMode():
+ """
+ Get this Material's mode flags.
+ @rtype: int
+ @return: B{OR'ed value}. Use the Modes dictionary to check which flags
+ are 'on'.
+
+ Example::
+ import Blender
+ from Blender import Material
+ flags = mymat.getMode()
+ if flags & Material.Modes['HALO']:
+ print "This material is rendered as a halo"
+ else:
+ print "Not a halo"
+ """
+
+ def setMode(param, stringN=None):
+ """
+ Set this Material's mode flags. Up to 22 mode strings can be given
+ and specify the modes which are turned 'on'. Those not provided are
+ turned 'off', so mat.setMode() -- without arguments -- turns off all
+ mode flags for Material mat. Valid mode strings are "Traceable",
+ "Shadow", "Shadeless", "Wire", "VColLight", "VColPaint", "Halo",
+ "ZTransp", "ZInvert", "HaloRings", "HaloLines", "OnlyShadow",
+ "HaloXAlpha", "HaloStar", "TexFace", "HaloTex", "HaloPuno", "NoMist",
+ "HaloShaded", "HaloFlare", "Radio", "RayMirr", "ZTransp", "RayTransp",
+ "Env"
+
+ An integer can also be given, which directly sets the mode flag. The
+ Modes dictionary keys can (and should) be added or ORed to specify
+ which modes to turn 'on'. The value returned from getMode() can
+ also be modified and input to this method.
+
+ @type param: string, None or int
+ @param param: A mode value (int) or flag (string). Can also be None.
+ @type stringN: string
+ @param stringN: A mode flag. Up to 22 flags can be set at the same time.
+ """
+
+ def getRGBCol():
+ """
+ Get the rgb color triplet sequence.
+ @rtype: list of 3 floats
+ @return: [r, g, b]
+ """
+
+ def setRGBCol(rgb = None):
+ """
+ Set the rgb color triplet sequence. If B{rgb} is None, set the color to black.
+ @type rgb: three floats or a list of three floats
+ @param rgb: The rgb color values in [0.0, 1.0] as:
+ - a list of three floats: setRGBCol ([r, g, b]) B{or}
+ - three floats as separate parameters: setRGBCol (r,g,b).
+ """
+
+ def getSpecCol():
+ """
+ Get the specular color triplet sequence.
+ @rtype: list of 3 floats
+ @return: [specR, specG, specB]
+ """
+
+ def setSpecCol(rgb = None):
+ """
+ Set the specular color triplet sequence. If B{rgb} is None, set the color to black.
+ @type rgb: three floats or a list of three floats
+ @param rgb: The rgb color values in [0.0, 1.0] as:
+ - a list of three floats: setSpecCol ([r, g, b]) B{or}
+ - three floats as separate parameters: setSpecCol (r,g,b).
+ """
+
+ def getMirCol():
+ """
+ Get the mirror color triplet sequence.
+ @rtype: list of 3 floats
+ @return: [mirR, mirG, mirb]
+ """
+
+ def setMirCol(rgb = None):
+ """
+ Set the mirror color triplet sequence. If B{rgb} is None, set the color to black.
+ @type rgb: three floats or a list of three floats
+ @param rgb: The rgb color values in [0.0, 1.0] as:
+ - a list of three floats: setMirCol ([r, g, b]) B{or}
+ - three floats as separate parameters: setMirCol (r,g,b).
+ """
+
+ def getAlpha():
+ """
+ Get the alpha (transparency) value.
+ @rtype: float
+ """
+
+ def setAlpha(alpha):
+ """
+ Set the alpha (transparency) value.
+ @type alpha: float
+ @param alpha: The new value in [0.0, 1.0].
+ """
+
+ def getAmb():
+ """
+ Get the ambient color blend factor.
+ @rtype: float
+ """
+
+ def setAmb(amb):
+ """
+ Set the ambient color blend factor.
+ @type amb: float
+ @param amb: The new value in [0.0, 1.0].
+ """
+
+ def getEmit():
+ """
+ Get the emitting light intensity.
+ @rtype: float
+ """
+
+ def setEmit(emit):
+ """
+ Set the emitting light intensity.
+ @type emit: float
+ @param emit: The new value in [0.0, 1.0].
+ """
+
+ def getRef():
+ """
+ Get the reflectivity value.
+ @rtype: float
+ """
+
+ def setRef(ref):
+ """
+ Set the reflectivity value.
+ @type ref: float
+ @param ref: The new value in [0.0, 1.0].
+ """
+
+ def getSpec():
+ """
+ Get the specularity value.
+ @rtype: float
+ """
+
+ def setSpec(spec):
+ """
+ Set the specularity value.
+ @type spec: float
+ @param spec: The new value in [0.0, 2.0].
+ """
+
+ def getSpecTransp():
+ """
+ Get the specular transparency.
+ @rtype: float
+ """
+
+ def setSpecTransp(spectransp):
+ """
+ Set the specular transparency.
+ @type spectransp: float
+ @param spectransp: The new value in [0.0, 1.0].
+ """
+
+ def setSpecShader(specShader):
+ """
+ Set the material's specular shader from one of the shaders in Material.Shaders dict.
+ @type specShader: int
+ @param specShader: The new value in [0, 4].
+ """
+
+ def getSpecShader(specShader):
+ """
+ Get the material's specular shader from one of the shaders in Material.Shaders dict.
+ @rtype: int
+ """
+
+ def setDiffuseShader(diffuseShader):
+ """
+ Set the material's diffuse shader from one of the shaders in Material.Shaders dict.
+ @type diffuseShader: int
+ @param diffuseShader: The new value in [0, 3].
+ """
+
+ def getDiffuseShader():
+ """
+ Get the material's diffuse shader from one of the shaders in Material.Shaders dict.
+ @rtype: int
+ """
+
+ def setRoughness(roughness):
+ """
+ Set the material's roughness (applies to the \"Oren Nayar\" Diffuse Shader only)
+ @type roughness: float
+ @param roughness: The new value in [0.0, 3.14].
+ """
+
+ def getRoughness():
+ """
+ Get the material's roughness (applies to the \"Oren Nayar\" Diffuse Shader only)
+ @rtype: float
+ """
+
+ def setSpecSize(specSize):
+ """
+ Set the material's size of specular area (applies to the \"Toon\" Specular Shader only)
+ @type specSize: float
+ @param specSize: The new value in [0.0, 1.53].
+ """
+
+ def getSpecSize():
+ """
+ Get the material's size of specular area (applies to the \"Toon\" Specular Shader only)
+ @rtype specSize: float
+ """
+
+ def setSpecSize(diffuseSize):
+ """
+ Set the material's size of diffuse area (applies to the \"Toon\" Diffuse Shader only)
+ @type diffuseSize: float
+ @param diffuseSize: The new value in [0.0, 3.14].
+ """
+
+ def getSpecSize():
+ """
+ Get the material's size of diffuse area (applies to the \"Toon\" Diffuse Shader only)
+ @rtype: float
+ """
+
+ def setSpecSmooth(specSmooth):
+ """
+ Set the material's smoothing of specular area (applies to the \"Toon\" Specular Shader only)
+ @type specSmooth: float
+ @param specSmooth: The new value in [0.0, 1.0].
+ """
+
+ def getSpecSmooth():
+ """
+ Get the material's smoothing of specular area (applies to the \"Toon\" Specular Shader only)
+ @rtype: float
+ """
+
+ def setDiffuseSmooth(diffuseSmooth):
+ """
+ Set the material's smoothing of diffuse area (applies to the \"Toon\" Diffuse Shader only)
+ @type diffuseSmooth: float
+ @param diffuseSmooth: The new value in [0.0, 1.0].
+ """
+
+ def getDiffuseSmooth():
+ """
+ Get the material's smoothing of diffuse area (applies to the \"Toon\" Diffuse Shader only)
+ @rtype: float
+ """
+
+ def setDiffuseDarkness(diffuseDarkness):
+ """
+ Set the material's diffuse darkness (applies to the \"Minnaert\" Diffuse Shader only)
+ @type diffuseDarkness: float
+ @param diffuseDarkness: The new value in [0.0, 2.0].
+ """
+
+ def getDiffuseDarkness():
+ """
+ Get the material's diffuse darkness (applies to the \"Minnaert\" Diffuse Shader only)
+ @rtype: float
+ """
+
+ def setRefracIndex(refracIndex):
+ """
+ Set the material's Index of Refraction (applies to the \"Blinn\" Specular Shader only)
+ @type refracIndex: float
+ @param refracIndex: The new value in [1.0, 10.0].
+ """
+
+ def getRefracIndex():
+ """
+ Get the material's Index of Refraction (applies to the \"Blinn\" Specular Shader only)
+ @rtype: float
+ """
+
+ def setRms(rms):
+ """
+ Set the material's standard deviation of surface slope (applies to the \"WardIso\" Specular Shader only)
+ @type rms: float
+ @param rms: The new value in [0.0, 0.4].
+ """
+
+ def getRms():
+ """
+ Get the material's standard deviation of surface slope (applies to the \"WardIso\" Specular Shader only)
+ @rtype: float
+ """
+
+ def setFilter(filter):
+ """
+ Set the material's amount of filtering when transparent raytrace is enabled
+ @type filter: float
+ @param filter: The new value in [0.0, 1.0].
+ """
+
+ def getFilter():
+ """
+ Get the material's amount of filtering when transparent raytrace is enabled
+ @rtype: float
+ """
+
+ def setTranslucency(translucency):
+ """
+ Set the material's amount of diffuse shading of the back side
+ @type translucency: float
+ @param translucency: The new value in [0.0, 1.0].
+ """
+
+ def getTranslucency():
+ """
+ Get the material's amount of diffuse shading of the back side
+ @rtype: float
+ """
+
+ def getAdd():
+ """
+ Get the glow factor.
+ @rtype: float
+ """
+
+ def setAdd(add):
+ """
+ Set the glow factor.
+ @type add: float
+ @param add: The new value in [0.0, 1.0].
+ """
+
+ def getZOffset():
+ """
+ Get the artificial offset for faces with this Material.
+ @rtype: float
+ """
+
+ def setZOffset(zoffset):
+ """
+ Set the artificial offset for faces with this Material.
+ @type zoffset: float
+ @param zoffset: The new value in [0.0, 10.0].
+ """
+
+ def getHaloSize():
+ """
+ Get the halo size.
+ @rtype: float
+ """
+
+ def setHaloSize(halosize):
+ """
+ Set the halo size.
+ @type halosize: float
+ @param halosize: The new value in [0.0, 100.0].
+ """
+
+ def getHaloSeed():
+ """
+ Get the seed for random ring dimension and line location in halos.
+ @rtype: int
+ """
+
+ def setHaloSeed(haloseed):
+ """
+ Set the seed for random ring dimension and line location in halos.
+ @type haloseed: int
+ @param haloseed: The new value in [0, 255].
+ """
+
+ def getFlareSize():
+ """
+ Get the ratio: flareSize / haloSize.
+ @rtype: float
+ """
+
+ def setFlareSize(flaresize):
+ """
+ Set the ratio: flareSize / haloSize.
+ @type flaresize: float
+ @param flaresize: The new value in [0.1, 25.0].
+ """
+
+ def getFlareSeed():
+ """
+ Get flare's offset in the seed table.
+ @rtype: int
+ """
+
+ def setFlareSeed(flareseed):
+ """
+ Set flare's offset in the seed table.
+ @type flareseed: int
+ @param flareseed: The new value in [0, 255].
+ """
+
+ def getFlareBoost():
+ """
+ Get the flare's extra strength.
+ @rtype: float
+ """
+
+ def setFlareBoost(flareboost):
+ """
+ Set the flare's extra strength.
+ @type flareboost: float
+ @param flareboost: The new value in [0.1, 10.0].
+ """
+
+ def getSubSize():
+ """
+ Get the dimension of subflare, dots and circles.
+ @rtype: float
+ """
+
+ def setSubSize(subsize):
+ """
+ Set the dimension of subflare, dots and circles.
+ @type subsize: float
+ @param subsize: The new value in [0.1, 25.0].
+ """
+
+ def getHardness():
+ """
+ Get the hardness of the specularity.
+ @rtype: int
+ """
+
+ def setHardness(hardness):
+ """
+ Set the hardness of the specularity.
+ @type hardness: int
+ @param hardness: The new value in [1, 511].
+ """
+
+ def getNFlares():
+ """
+ Get the number of halo subflares.
+ @rtype: int
+ """
+
+ def setNFlares(nflares):
+ """
+ Set the number of halo subflares.
+ @type nflares: int
+ @param nflares: The new value in [1, 32].
+ """
+
+ def getNStars():
+ """
+ Get the number of points in the halo stars.
+ @rtype: int
+ """
+
+ def setNStars(nstars):
+ """
+ Set the number of points in the halo stars.
+ @type nstars: int
+ @param nstars: The new value in [3, 50].
+ """
+
+ def getNLines():
+ """
+ Get the number of star shaped lines on each halo.
+ @rtype: int
+ """
+
+ def setNLines(nlines):
+ """
+ Set the number of star shaped lines on each halo.
+ @type nlines: int
+ @param nlines: The new value in [0, 250].
+ """
+
+ def getNRings():
+ """
+ Get the number of rings on each halo.
+ @rtype: int
+ """
+
+ def setNRings(nrings):
+ """
+ Set the number of rings on each halo.
+ @type nrings: int
+ @param nrings: The new value in [0, 24].
+ """
+
+ def getRayMirr():
+ """
+ Get amount mirror reflection for raytrace.
+ @rtype: float
+ """
+
+ def setRayMirr(nrmirr):
+ """
+ Set amount mirror reflection for raytrace.
+ @type nrmirr: float
+ @param nrmirr: The new value in [0.0, 1.0].
+ """
+
+ def getRayMirrDepth():
+ """
+ Get amount of inter-reflections calculated maximal.
+ @rtype: int
+ """
+
+ def setRayMirrDepth(nrmirr):
+ """
+ Set amount mirror reflection for raytrace.
+ @type nrmirr: int
+ @param nrmirr: The new value in [0.0, 1.0].
+ """
+
+ def getFresnelMirr():
+ """
+ Get power of Fresnel for mirror reflection.
+ @rtype: float
+ """
+
+ def setFresnelMirr(nrmirr):
+ """
+ Set power of Fresnel for mirror reflection.
+ @type nrmirr: float
+ @param nrmirr: The new value in [0.0, 1.0].
+ """
+
+ def getFresnelMirrFac():
+ """
+ Get the number of Ray Mirror.
+ @rtype: float
+ """
+
+ def setFresnelMirrFac(nrmirr):
+ """
+ Set the number of ray mirror
+ @type nrmirr: float
+ @param nrmirr: The new value in [0.0, 1.0].
+ """
+
+ def getIOR():
+ """
+ Get the angular index of refraction for raytrace.
+ @rtype: float
+ """
+
+ def setIOR(nrmirr):
+ """
+ Set the angular index of refraction for raytrace.
+ @type nrmirr: float
+ @param nrmirr: The new value in [0.0, 1.0].
+ """
+
+ def getTransDepth():
+ """
+ Get amount of refractions calculated maximal.
+ @rtype: int
+ """
+
+ def setTransDepth(nrmirr):
+ """
+ Set amount of refractions calculated maximal.
+ @type nrmirr: int
+ @param nrmirr: The new value in [0.0, 1.0].
+ """
+
+ def getFresnelTrans():
+ """
+ Get power of Fresnel for transparency.
+ @rtype: float
+ """
+
+ def setFresnelTrans(nrmirr):
+ """
+ Set power of Fresnel for transparency.
+ @type nrmirr: float
+ @param nrmirr: The new value in [0.0, 1.0].
+ """
+
+ def getFresnelTransFac():
+ """
+ Get blending factor for Fresnel.
+ @rtype: float
+ """
+
+ def setFresnelTransFac(nrmirr):
+ """
+ Set blending factor for Fresnel.
+ @type nrmirr: float
+ @param nrmirr: The new value in [0.0, 1.0].
+ """
+
+ def setTexture(index, texture, texco, mapto):
+ """
+ Assign a Blender Texture object to slot number 'number'.
+ @type index: int
+ @param index: material's texture index in [0, 9].
+ @type texture: Blender Texture
+ @param texture: a Blender Texture object.
+ @type texco: int
+ @param texco: optional ORed bitflag -- defaults to TexCo.ORCO. See TexCo var in L{Texture}.
+ @type mapto: int
+ @param mapto: optional ORed bitflag -- defaults to MapTo.COL. See MapTo var in L{Texture}.
+ """
+
+ def clearTexture(index):
+ """
+ Clear the ith (given by 'index') texture channel of this material.
+ @type index: int
+ @param index: material's texture channel index in [0, 9].
+ """
+
+ def getTextures ():
+ """
+ Get this Material's Texture list.
+ @rtype: list of MTex
+ @return: a list of Blender MTex objects. None is returned for each empty
+ texture slot.
+ """
+
+ def getScriptLinks (event):
+ """
+ Get a list with this Material's script links of type 'event'.
+ @type event: string
+ @param event: "FrameChanged" or "Redraw".
+ @rtype: list
+ @return: a list with Blender L{Text} names (the script links of the given
+ 'event' type) or None if there are no script links at all.
+ """
+
+ def clearScriptLinks (links = None):
+ """
+ Delete script links from this Material. If no list is specified, all
+ script links are deleted.
+ @type links: list of strings
+ @param links: None (default) or a list of Blender L{Text} names.
+ """
+
+ def addScriptLink (text, event):
+ """
+ Add a new script link to this Material.
+ @type text: string
+ @param text: the name of an existing Blender L{Text}.
+ @type event: string
+ @param event: "FrameChanged" or "Redraw".
+ """
+
+ def __copy__ ():
+ """
+ Make a copy of this material
+ @rtype: Material
+ @return: a copy of this material
+ """
+
+import id_generics
+Material.__doc__ += id_generics.attributes
diff --git a/source/blender/python/api2_2x/doc/Mathutils.py b/source/blender/python/api2_2x/doc/Mathutils.py
new file mode 100644
index 00000000000..7546bb5b6d5
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Mathutils.py
@@ -0,0 +1,864 @@
+# Blender.Mathutils module and its subtypes
+
+"""
+The Blender.Mathutils submodule.
+
+Mathutils
+=========
+
+This module provides access to matrices, eulers, quaternions and vectors.
+
+Example::
+ import Blender
+ from Blender import Mathutils
+ from Blender.Mathutils import *
+
+ vec = Vector([1,2,3])
+ mat = RotationMatrix(90, 4, 'x')
+ matT = TranslationMatrix(vec)
+
+ matTotal = mat * matT
+ matTotal.invert()
+
+ mat3 = matTotal.rotationPart
+ quat1 = mat.toQuat()
+ quat2 = mat3.toQuat()
+
+ angle = DifferenceQuats(quat1, quat2)
+ print angle
+"""
+
+def Rand (high = 1, low = 0):
+ """
+ Return a random number within a range.
+ High and low represent the range from which the random
+ number must return its result.
+ @type high: float
+ @param high: The upper range.
+ @type low: float
+ @param low: The lower range.
+ """
+
+def Intersect(vec1, vec2, vec3, ray, orig, clip=1):
+ """
+ Return the intersection between a ray and a triangle, if possible, return None otherwise.
+ @type vec1: Vector object.
+ @param vec1: A 3d vector, one corner of the triangle.
+ @type vec2: Vector object.
+ @param vec2: A 3d vector, one corner of the triangle.
+ @type vec3: Vector object.
+ @param vec3: A 3d vector, one corner of the triangle.
+ @type ray: Vector object.
+ @param ray: A 3d vector, the orientation of the ray. the length of the ray is not used, only the direction.
+ @type orig: Vector object.
+ @param orig: A 3d vector, the origin of the ray.
+ @type clip: integer
+ @param clip: if 0, don't restrict the intersection to the area of the triangle, use the infinite plane defined by the triangle.
+ @rtype: Vector object
+ @return: The intersection between a ray and a triangle, if possible, None otherwise.
+ """
+
+def TriangleArea(vec1, vec2, vec3):
+ """
+ Return the area size of the 2D or 3D triangle defined.
+ @type vec1: Vector object.
+ @param vec1: A 2d or 3d vector, one corner of the triangle.
+ @type vec2: Vector object.
+ @param vec2: A 2d or 3d vector, one corner of the triangle.
+ @type vec3: Vector object.
+ @param vec3: A 2d or 3d vector, one corner of the triangle.
+ @rtype: float
+ @return: The area size of the 2D or 3D triangle defined.
+ """
+
+def TriangleNormal(vec1, vec2, vec3):
+ """
+ Return the normal of the 3D triangle defined.
+ @type vec1: Vector object.
+ @param vec1: A 3d vector, one corner of the triangle.
+ @type vec2: Vector object.
+ @param vec2: A 3d vector, one corner of the triangle.
+ @type vec3: Vector object.
+ @param vec3: A 3d vector, one corner of the triangle.
+ @rtype: float
+ @return: The normal of the 3D triangle defined.
+ """
+
+def QuadNormal(vec1, vec2, vec3, vec4):
+ """
+ Return the normal of the 3D quad defined.
+ @type vec1: Vector object.
+ @param vec1: A 3d vector, the first vertex of the quad.
+ @type vec2: Vector object.
+ @param vec2: A 3d vector, the second vertex of the quad.
+ @type vec3: Vector object.
+ @param vec3: A 3d vector, the third vertex of the quad.
+ @type vec4: Vector object.
+ @param vec4: A 3d vector, the fourth vertex of the quad.
+ @rtype: float
+ @return: The normal of the 3D quad defined.
+ """
+
+def LineIntersect(vec1, vec2, vec3, vec4):
+ """
+ Return a tuple with the points on each line respectively closest to the other
+ (when both lines intersect, both vector hold the same value).
+ The lines are evaluated as infinite lines in space, the values returned may not be between the 2 points given for each line.
+ @type vec1: Vector object.
+ @param vec1: A 3d vector, one point on the first line.
+ @type vec2: Vector object.
+ @param vec2: A 3d vector, another point on the first line.
+ @type vec3: Vector object.
+ @param vec3: A 3d vector, one point on the second line.
+ @type vec4: Vector object.
+ @param vec4: A 3d vector, another point on the second line.
+ @rtype: (Vector object, Vector object)
+ @return: A tuple with the points on each line respectively closest to the other.
+ """
+
+def CopyVec(vector):
+ """
+ Create a copy of the Vector object.
+ @attention: B{DEPRECATED} use vector.copy() instead.
+ @type vector: Vector object.
+ @param vector: A 2d,3d or 4d vector to be copied.
+ @rtype: Vector object.
+ @return: A new vector object which is a copy of the one passed in.
+ """
+
+def CrossVecs(vec1, vec2):
+ """
+ Return the cross product of two vectors.
+ @type vec1: Vector object.
+ @param vec1: A 3d vector.
+ @type vec2: Vector object.
+ @param vec2: A 3d vector.
+ @rtype: Vector object.
+ @return: A new vector representing the cross product of
+ the two vectors.
+ """
+
+def DotVecs(vec1, vec2):
+ """
+ Return the dot product of two vectors.
+ @type vec1: Vector object.
+ @param vec1: A 2d,3d or 4d vector.
+ @type vec2: Vector object.
+ @param vec2: A 2d,3d or 4d vector.
+ @rtype: float
+ @return: Return the scalar product of vector muliplication.
+ """
+
+def AngleBetweenVecs(vec1, vec2):
+ """
+ Return the angle between two vectors. Zero length vectors raise an error.
+ @type vec1: Vector object.
+ @param vec1: A 2d or 3d vector.
+ @type vec2: Vector object.
+ @param vec2: A 2d or 3d vector.
+ @rtype: float
+ @return: The angle between the vectors in degrees.
+ @raise AttributeError: When there is a zero-length vector as an argument.
+ """
+
+def MidpointVecs(vec1, vec2):
+ """
+ Return a vector to the midpoint between two vectors.
+ @type vec1: Vector object.
+ @param vec1: A 2d,3d or 4d vector.
+ @type vec2: Vector object.
+ @param vec2: A 2d,3d or 4d vector.
+ @rtype: Vector object
+ @return: The vector to the midpoint.
+ """
+
+def VecMultMat(vec, mat):
+ """
+ Multiply a vector and matrix (pre-multiply)
+ Vector size and matrix column size must equal.
+ @type vec: Vector object.
+ @param vec: A 2d,3d or 4d vector.
+ @type mat: Matrix object.
+ @param mat: A 2d,3d or 4d matrix.
+ @rtype: Vector object
+ @return: The row vector that results from the muliplication.
+ @attention: B{DEPRECATED} You should now multiply vector * matrix direcly
+ Example::
+ result = myVector * myMatrix
+ """
+
+def ProjectVecs(vec1, vec2):
+ """
+ Return the projection of vec1 onto vec2.
+ @type vec1: Vector object.
+ @param vec1: A 2d,3d or 4d vector.
+ @type vec2: Vector object.
+ @param vec2: A 2d,3d or 4d vector.
+ @rtype: Vector object
+ @return: The parallel projection vector.
+ """
+
+def RotationMatrix(angle, matSize, axisFlag, axis):
+ """
+ Create a matrix representing a rotation.
+ @type angle: float
+ @param angle: The angle of rotation desired.
+ @type matSize: int
+ @param matSize: The size of the rotation matrix to construct.
+ Can be 2d, 3d, or 4d.
+ @type axisFlag: string (optional)
+ @param axisFlag: Possible values:
+ - "x - x-axis rotation"
+ - "y - y-axis rotation"
+ - "z - z-axis rotation"
+ - "r - arbitrary rotation around vector"
+ @type axis: Vector object. (optional)
+ @param axis: The arbitrary axis of rotation used with "R"
+ @rtype: Matrix object.
+ @return: A new rotation matrix.
+ """
+
+def TranslationMatrix(vector):
+ """
+ Create a matrix representing a translation
+ @type vector: Vector object
+ @param vector: The translation vector
+ @rtype: Matrix object.
+ @return: An identity matrix with a translation.
+ """
+
+def ScaleMatrix(factor, matSize, axis):
+ """
+ Create a matrix representing a scaling.
+ @type factor: float
+ @param factor: The factor of scaling to apply.
+ @type matSize: int
+ @param matSize: The size of the scale matrix to construct.
+ Can be 2d, 3d, or 4d.
+ @type axis: Vector object. (optional)
+ @param axis: Direction to influence scale.
+ @rtype: Matrix object.
+ @return: A new scale matrix.
+ """
+
+def OrthoProjectionMatrix(plane, matSize, axis):
+ """
+ Create a matrix to represent an orthographic projection
+ @type plane: string
+ @param plane: Can be any of the following:
+ - "x - x projection (2D)"
+ - "y - y projection (2D)"
+ - "xy - xy projection"
+ - "xz - xz projection"
+ - "yz - yz projection"
+ - "r - arbitrary projection plane"
+ @type matSize: int
+ @param matSize: The size of the projection matrix to construct.
+ Can be 2d, 3d, or 4d.
+ @type axis: Vector object. (optional)
+ @param axis: Arbitrary perpendicular plane vector.
+ @rtype: Matrix object.
+ @return: A new projeciton matrix.
+ """
+
+def ShearMatrix(plane, factor, matSize):
+ """
+ Create a matrix to represent an orthographic projection
+ @type plane: string
+ @param plane: Can be any of the following:
+ - "x - x shear (2D)"
+ - "y - y shear (2D)"
+ - "xy - xy shear"
+ - "xz - xz shear"
+ - "yz - yz shear"
+ @type factor: float
+ @param factor: The factor of shear to apply.
+ @type matSize: int
+ @param matSize: The size of the projection matrix to construct.
+ Can be 2d, 3d, or 4d.
+ @rtype: Matrix object.
+ @return: A new shear matrix.
+ """
+
+def CopyMat(matrix):
+ """
+ Create a copy of the Matrix object.
+ @type matrix: Matrix object.
+ @param matrix: A 2d,3d or 4d matrix to be copied.
+ @rtype: Matrix object.
+ @return: A new matrix object which is a copy of the one passed in.
+ @attention: B{DEPRECATED} Use the matrix copy funtion to make a copy.
+ Example::
+ newMat = myMat.copy()
+ """
+
+def MatMultVec(mat, vec):
+ """
+ Multiply a matrix and a vector (post-multiply)
+ Vector size and matrix row size must equal.
+ @type vec: Vector object.
+ @param vec: A 2d,3d or 4d vector.
+ @type mat: Matrix object.
+ @param mat: A 2d,3d or 4d matrix.
+ @rtype: Vector object
+ @return: The column vector that results from the muliplication.
+ @attention: B{DEPRECATED} You should use direct muliplication on the arguments
+ Example::
+ result = myMatrix * myVector
+ """
+
+def CopyQuat(quaternion):
+ """
+ Create a copy of the Quaternion object.
+ @type quaternion: Quaternion object.
+ @param quaternion: Quaternion to be copied.
+ @rtype: Quaternion object.
+ @return: A new quaternion object which is a copy of the one passed in.
+ @attention: B{DEPRECATED} You should use the Quaterion() constructor directly
+ to create copies of quaternions
+ Example::
+ newQuat = Quaternion(myQuat)
+ """
+
+def CrossQuats(quat1, quat2):
+ """
+ Return the cross product of two quaternions.
+ @type quat1: Quaternion object.
+ @param quat1: Quaternion.
+ @type quat2: Quaternion object.
+ @param quat2: Quaternion.
+ @rtype: Quaternion object.
+ @return: A new quaternion representing the cross product of
+ the two quaternions.
+ """
+
+def DotQuats(quat1, quat2):
+ """
+ Return the dot product of two quaternions.
+ @type quat1: Quaternion object.
+ @param quat1: Quaternion.
+ @type quat2: Quaternion object.
+ @param quat2: Quaternion.
+ @rtype: float
+ @return: Return the scalar product of quaternion muliplication.
+ """
+
+def DifferenceQuats(quat1, quat2):
+ """
+ Returns a quaternion represting the rotational difference.
+ @type quat1: Quaternion object.
+ @param quat1: Quaternion.
+ @type quat2: Quaternion object.
+ @param quat2: Quaternion.
+ @rtype: Quaternion object
+ @return: Return a quaternion which which represents the rotational
+ difference between the two quat rotations.
+ """
+
+def Slerp(quat1, quat2, factor):
+ """
+ Returns the interpolation of two quaternions.
+ @type quat1: Quaternion object.
+ @param quat1: Quaternion.
+ @type quat2: Quaternion object.
+ @param quat2: Quaternion.
+ @type factor: float
+ @param factor: The interpolation value
+ @rtype: Quaternion object
+ @return: The interpolated rotation.
+ """
+
+def CopyEuler(euler):
+ """
+ Create a new euler object.
+ @type euler: Euler object
+ @param euler: The euler to copy
+ @rtype: Euler object
+ @return: A copy of the euler object passed in.
+ @attention: B{DEPRECATED} You should use the Euler constructor directly
+ to make copies of Euler objects
+ Example::
+ newEuler = Euler(myEuler)
+ """
+
+def RotateEuler(euler, angle, axis):
+ """
+ Roatate a euler by an amount in degrees around an axis.
+ @type euler: Euler object
+ @param euler: Euler to rotate.
+ @type angle: float
+ @param angle: The amount of rotation in degrees
+ @type axis: string
+ @param axis: axis to rotate around:
+ - "x"
+ - "y"
+ - "z"
+ """
+
+class Vector:
+ """
+ The Vector object
+ =================
+ This object gives access to Vectors in Blender.
+ @ivar x: The x value.
+ @ivar y: The y value.
+ @ivar z: The z value (if any).
+ @ivar w: The w value (if any).
+ @ivar length: The magnitude of the vector.
+ @ivar magnitude: This is a synonym for length.
+ @ivar wrapped: Whether or not this item is wrapped data
+ @note: Comparison operators can be done on Vector classes:
+ - >, >=, <, <= test the vector magnitude
+ - ==, != test vector values e.g. 1,2,3 != 1,2,4 even if they are the same length
+ @note: Math can be performed on Vector classes
+ - vec + vec
+ - vec - vec
+ - vec * float/int
+ - vec * matrix
+ - vec * vec
+ - vec * quat
+ - -vec
+ @note: You can access a vector object like a sequence
+ - x = vector[0]
+ @attention: Vector data can be wrapped or non-wrapped. When a object is wrapped it
+ means that the object will give you direct access to the data inside of blender. Modification
+ of this object will directly change the data inside of blender. To copy a wrapped object
+ you need to use the object's constructor. If you copy and object by assignment you will not get
+ a second copy but a second reference to the same data. Only certain functions will return
+ wrapped data. This will be indicated in the method description.
+ Example::
+ wrappedObject = Object.getAttribute() #this is wrapped data
+ print wrappedObject.wrapped #prints 'True'
+ copyOfObject = Object(wrappedObject) #creates a copy of the object
+ secondPointer = wrappedObject #creates a second pointer to the same data
+ print wrappedObject.attribute #prints '5'
+ secondPointer.attribute = 10
+ print wrappedObject.attribute #prints '10'
+ print copyOfObject.attribute #prints '5'
+ """
+
+ def __init__(list = None):
+ """
+ Create a new 2d, 3d, or 4d Vector object from a list of floating point numbers.
+ @note: that python uses higher precission floating point numbers, so values assigned to a vector may have some rounding error.
+
+
+ Example::
+ v = Vector(1,0,0)
+ v = Vector(myVec)
+ v = Vector(list)
+ @type list: PyList of float or int
+ @param list: The list of values for the Vector object. Can be a sequence or raw numbers.
+ Must be 2, 3, or 4 values. The list is mapped to the parameters as [x,y,z,w].
+ @rtype: Vector object.
+ @return: It depends wheter a parameter was passed:
+ - (list): Vector object initialized with the given values;
+ - (): An empty 3 dimensional vector.
+ """
+
+ def copy():
+ """
+ Returns a copy of this vector
+ @return: a copy of itself
+ """
+
+ def zero():
+ """
+ Set all values to zero.
+ @return: an instance of itself
+ """
+
+ def normalize():
+ """
+ Normalize the vector, making the length of the vector always 1.0
+ @note: Normalize works for vectors of all sizes, however 4D Vectors w axis is left untouched.
+ @note: Normalizing a vector where all values are zero results in all axis having a nan value (not a number).
+ @return: an instance of itself
+ """
+
+ def negate():
+ """
+ Set all values to their negative.
+ @return: an instance of its self
+ """
+
+ def resize2D():
+ """
+ Resize the vector to 2d.
+ @return: an instance of itself
+ """
+
+ def resize3D():
+ """
+ Resize the vector to 3d. New axis will be 0.0.
+ @return: an instance of itself
+ """
+
+ def resize4D():
+ """
+ Resize the vector to 4d. New axis will be 0.0.
+ The last component will be 1.0, to make multiplying 3d vectors by 4x4 matrices easier.
+ @return: an instance of itself
+ """
+
+ def toTrackQuat(track, up):
+ """
+ Return a quaternion rotation from the vector and the track and up axis.
+ @type track: String.
+ @param track: Possible values:
+ - "x - x-axis up"
+ - "y - y-axis up"
+ - "z - z-axis up"
+ - "-x - negative x-axis up"
+ - "-y - negative y-axis up"
+ - "-z - negative z-axis up"
+ @type up: String.
+ @param up: Possible values:
+ - "x - x-axis up"
+ - "y - y-axis up"
+ - "z - z-axis up"
+ @rtype: Quaternion
+ @return: Return a quaternion rotation from the vector and the track and up axis.
+ """
+
+class Euler:
+ """
+ The Euler object
+ ================
+ This object gives access to Eulers in Blender.
+ @ivar x: The heading value in degrees.
+ @ivar y: The pitch value in degrees.
+ @ivar z: The roll value in degrees.
+ @ivar wrapped: Whether or not this object is wrapping data directly
+ @note: You can access a euler object like a sequence
+ - x = euler[0]
+ @note: Comparison operators can be done:
+ - ==, != test numeric values within epsilon
+ @attention: Euler data can be wrapped or non-wrapped. When a object is wrapped it
+ means that the object will give you direct access to the data inside of blender. Modification
+ of this object will directly change the data inside of blender. To copy a wrapped object
+ you need to use the object's constructor. If you copy and object by assignment you will not get
+ a second copy but a second reference to the same data. Only certain functions will return
+ wrapped data. This will be indicated in the method description.
+ Example::
+ wrappedObject = Object.getAttribute() #this is wrapped data
+ print wrappedObject.wrapped #prints 'True'
+ copyOfObject = Object(wrappedObject) #creates a copy of the object
+ secondPointer = wrappedObject #creates a second pointer to the same data
+ print wrappedObject.attribute #prints '5'
+ secondPointer.attribute = 10
+ print wrappedObject.attribute #prints '10'
+ print copyOfObject.attribute #prints '5'
+ """
+
+ def __init__(list = None):
+ """
+ Create a new euler object.
+
+ Example::
+ euler = Euler(45,0,0)
+ euler = Euler(myEuler)
+ euler = Euler(sequence)
+ @type list: PyList of float/int
+ @param list: 3d list to initialize euler
+ @rtype: Euler object
+ @return: Euler representing heading, pitch, bank.
+ @note: Values are in degrees.
+ """
+
+ def zero():
+ """
+ Set all values to zero.
+ @return: an instance of itself
+ """
+
+ def copy():
+ """
+ @return: a copy of this euler.
+ """
+
+ def unique():
+ """
+ Calculate a unique rotation for this euler. Avoids gimble lock.
+ @return: an instance of itself
+ """
+
+ def toMatrix():
+ """
+ Return a matrix representation of the euler.
+ @rtype: Matrix object
+ @return: A roation matrix representation of the euler.
+ """
+
+ def toQuat():
+ """
+ Return a quaternion representation of the euler.
+ @rtype: Quaternion object
+ @return: Quaternion representation of the euler.
+ """
+
+class Quaternion:
+ """
+ The Quaternion object
+ =====================
+ This object gives access to Quaternions in Blender.
+ @ivar w: The w value.
+ @ivar x: The x value.
+ @ivar y: The y value.
+ @ivar z: The z value.
+ @ivar wrapped: Wether or not this object wraps data directly
+ @ivar magnitude: The magnitude of the quaternion.
+ @ivar axis: Vector representing the axis of rotation.
+ @ivar angle: A scalar representing the amount of rotation
+ in degrees.
+ @note: Comparison operators can be done:
+ - ==, != test numeric values within epsilon
+ @note: Math can be performed on Quaternion classes
+ - quat + quat
+ - quat - quat
+ - quat * float/int
+ - quat * vec
+ - quat * quat
+ @note: You can access a quaternion object like a sequence
+ - x = quat[0]
+ @attention: Quaternion data can be wrapped or non-wrapped. When a object is wrapped it
+ means that the object will give you direct access to the data inside of blender. Modification
+ of this object will directly change the data inside of blender. To copy a wrapped object
+ you need to use the object's constructor. If you copy and object by assignment you will not get
+ a second copy but a second reference to the same data. Only certain functions will return
+ wrapped data. This will be indicated in the method description.
+ Example::
+ wrappedObject = Object.getAttribute() #this is wrapped data
+ print wrappedObject.wrapped #prints 'True'
+ copyOfObject = Object(wrappedObject) #creates a copy of the object
+ secondPointer = wrappedObject #creates a second pointer to the same data
+ print wrappedObject.attribute #prints '5'
+ secondPointer.attribute = 10
+ print wrappedObject.attribute #prints '10'
+ print copyOfObject.attribute #prints '5'
+ """
+
+ def __init__(list, angle = None):
+ """
+ Create a new quaternion object from initialized values.
+
+ Example::
+ quat = Quaternion(1,2,3,4)
+ quat = Quaternion(axis, angle)
+ quat = Quaternion()
+ quat = Quaternion(180, list)
+
+ @type list: PyList of int/float
+ @param list: A 3d or 4d list to initialize quaternion.
+ 4d if intializing [w,x,y,z], 3d if used as an axis of rotation.
+ @type angle: float (optional)
+ @param angle: An arbitrary rotation amount around 'list'.
+ List is used as an axis of rotation in this case.
+ @rtype: New quaternion object.
+ @return: It depends wheter a parameter was passed:
+ - (list/angle): Quaternion object initialized with the given values;
+ - (): An identity 4 dimensional quaternion.
+ """
+
+ def identity():
+ """
+ Set the quaternion to the identity quaternion.
+ @return: an instance of itself
+ """
+
+ def copy():
+ """
+ make a copy of the quaternion.
+ @return: a copy of itself
+ """
+
+ def negate():
+ """
+ Set the quaternion to its negative.
+ @return: an instance of itself
+ """
+
+ def conjugate():
+ """
+ Set the quaternion to its conjugate.
+ @return: an instance of itself
+ """
+
+ def inverse():
+ """
+ Set the quaternion to its inverse
+ @return: an instance of itself
+ """
+
+ def normalize():
+ """
+ Normalize the quaternion.
+ @return: an instance of itself
+ """
+
+ def toEuler():
+ """
+ Return Euler representation of the quaternion.
+ @rtype: Euler object
+ @return: Euler representation of the quaternion.
+ """
+
+ def toMatrix():
+ """
+ Return a matrix representation of the quaternion.
+ @rtype: Matrix object
+ @return: A rotation matrix representation of the quaternion.
+ """
+
+class Matrix:
+ """
+ The Matrix Object
+ =================
+ This object gives access to Matrices in Blender.
+ @ivar rowSize: The row size of the matrix.
+ @ivar colSize: The column size of the matrix.
+ @ivar wrapped: Whether or not this object wrapps internal data
+ @note: Math can be performed on Matrix classes
+ - mat + mat
+ - mat - mat
+ - mat * float/int
+ - mat * vec
+ - mat * mat
+ @note: Comparison operators can be done:
+ - ==, != test numeric values within epsilon
+ @note: You can access a quaternion object like a 2d sequence
+ - x = matrix[0][1]
+ - vector = matrix[2]
+ @attention: Quaternion data can be wrapped or non-wrapped. When a object is wrapped it
+ means that the object will give you direct access to the data inside of blender. Modification
+ of this object will directly change the data inside of blender. To copy a wrapped object
+ you need to use the object's constructor. If you copy and object by assignment you will not get
+ a second copy but a second reference to the same data. Only certain functions will return
+ wrapped data. This will be indicated in the method description.
+ Example::
+ wrappedObject = Object.getAttribute() #this is wrapped data
+ print wrappedObject.wrapped #prints 'True'
+ copyOfObject = Object(wrappedObject) #creates a copy of the object
+ secondPointer = wrappedObject #creates a second pointer to the same data
+ print wrappedObject.attribute #prints '5'
+ secondPointer.attribute = 10
+ print wrappedObject.attribute #prints '10'
+ print copyOfObject.attribute #prints '5'
+ """
+
+ def __init__(list1 = None, list2 = None, list3 = None, list4 = None):
+ """
+ Create a new matrix object from initialized values.
+
+ Example::
+ matrix = Matrix([1,1,1],[0,1,0],[1,0,0])
+ matrix = Matrix(mat)
+ matrix = Matrix(seq1, seq2, vector)
+
+ @type list1: PyList of int/float
+ @param list1: A 2d,3d or 4d list.
+ @type list2: PyList of int/float
+ @param list2: A 2d,3d or 4d list.
+ @type list3: PyList of int/float
+ @param list3: A 2d,3d or 4d list.
+ @type list4: PyList of int/float
+ @param list4: A 2d,3d or 4d list.
+ @rtype: New matrix object.
+ @return: It depends wheter a parameter was passed:
+ - (list1, etc.): Matrix object initialized with the given values;
+ - (): An empty 3 dimensional matrix.
+ """
+
+ def zero():
+ """
+ Set all matrix values to 0.
+ @return: an instance of itself
+ """
+
+
+ def copy():
+ """
+ Returns a copy of this matrix
+ @return: a copy of itself
+ """
+
+ def identity():
+ """
+ Set the matrix to the identity matrix.
+ An object with zero location and rotation, a scale of 1, will have an identity matrix.
+
+ See U{http://en.wikipedia.org/wiki/Identity_matrix}
+ @return: an instance of itself
+ """
+
+ def transpose():
+ """
+ Set the matrix to its transpose.
+
+ See U{http://en.wikipedia.org/wiki/Transpose}
+ @return: None
+ """
+
+ def determinant():
+ """
+ Return the determinant of a matrix.
+
+ See U{http://en.wikipedia.org/wiki/Determinant}
+ @rtype: float
+ @return: Return a the determinant of a matrix.
+ """
+
+ def invert():
+ """
+ Set the matrix to its inverse.
+
+ See U{http://en.wikipedia.org/wiki/Inverse_matrix}
+ @return: an instance of itself.
+ @raise ValueError: When matrix is singular.
+ """
+
+ def rotationPart():
+ """
+ Return the 3d submatrix corresponding to the linear term of the
+ embedded affine transformation in 3d. This matrix represents rotation
+ and scale. Note that the (4,4) element of a matrix can be used for uniform
+ scaling, too.
+ @rtype: Matrix object.
+ @return: Return the 3d matrix for rotation and scale.
+ """
+
+ def translationPart():
+ """
+ Return a the translation part of a 4 row matrix.
+ @rtype: Vector object.
+ @return: Return a the translation of a matrix.
+ """
+
+ def scalePart():
+ """
+ Return a the scale part of a 3x3 or 4x4 matrix.
+ @note: This method does not return negative a scale on any axis because it is not possible to obtain this data from the matrix alone.
+ @rtype: Vector object.
+ @return: Return a the scale of a matrix.
+ """
+
+ def resize4x4():
+ """
+ Resize the matrix to by 4x4
+ @return: an instance of itself.
+ """
+
+ def toEuler():
+ """
+ Return an Euler representation of the rotation matrix (3x3 or 4x4 matrix only).
+ @rtype: Euler object
+ @return: Euler representation of the rotation matrix.
+ """
+
+ def toQuat():
+ """
+ Return a quaternion representation of the rotation matrix
+ @rtype: Quaternion object
+ @return: Quaternion representation of the rotation matrix
+ """
+
diff --git a/source/blender/python/api2_2x/doc/Mesh.py b/source/blender/python/api2_2x/doc/Mesh.py
new file mode 100644
index 00000000000..e572d6a91ae
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Mesh.py
@@ -0,0 +1,1210 @@
+# Blender.Mesh module and the Mesh PyType object
+
+"""
+The Blender.Mesh submodule.
+
+B{New}:
+
+Mesh Data
+=========
+
+This module provides access to B{Mesh Data} objects in Blender. It differs
+from the NMesh module by allowing direct access to the actual Blender data,
+so that changes are done immediately without need to update or put the data
+back into the original mesh. The result is faster operations with less memory
+usage. The example below creates a simple pyramid, and sets some of the
+face's attributes (the vertex color):
+
+Example::
+ from Blender import *
+ import bpy
+
+ editmode = Window.EditMode() # are we in edit mode? If so ...
+ if editmode: Window.EditMode(0) # leave edit mode before getting the mesh
+
+ # define vertices and faces for a pyramid
+ coords=[ [-1,-1,-1], [1,-1,-1], [1,1,-1], [-1,1,-1], [0,0,1] ]
+ faces= [ [3,2,1,0], [0,1,4], [1,2,4], [2,3,4], [3,0,4] ]
+
+ me = bpy.data.meshes.new('myMesh') # create a new mesh
+
+ me.verts.extend(coords) # add vertices to mesh
+ me.faces.extend(faces) # add faces to the mesh (also adds edges)
+
+ me.vertexColors = 1 # enable vertex colors
+ me.faces[1].col[0].r = 255 # make each vertex a different color
+ me.faces[1].col[1].g = 255
+ me.faces[1].col[2].b = 255
+
+ scn = bpy.data.scenes.active # link object to current scene
+ ob = scn.objects.new(me, 'myObj')
+
+ if editmode: Window.EditMode(1) # optional, just being nice
+
+Vertices, edges and faces are added to a mesh using the .extend() methods.
+For best speed and efficiency, gather all vertices, edges or faces into a
+list and call .extend() once as in the above example. Similarly, deleting
+from the mesh is done with the .delete() methods and are most efficient when
+done once.
+
+@type Modes: readonly dictionary
+@type FaceFlags: readonly dictionary
+@type FaceModes: readonly dictionary
+@type FaceTranspModes: readonly dictionary
+@var Modes: The available mesh modes.
+ - NOVNORMALSFLIP - no flipping of vertex normals during render.
+ - TWOSIDED - double sided mesh.
+ - AUTOSMOOTH - turn auto smoothing of faces "on".
+ - note: SUBSURF and OPTIMAL have been removed, use Modifiers to apply subsurf.
+@var FaceFlags: The available *texture face* (uv face select mode) selection
+ flags. Note: these refer to TexFace faces, available if mesh.faceUV
+ returns true.
+ - SELECT - selected (deprecated in versions after 2.43, use face.sel).
+ - HIDE - hidden (deprecated in versions after 2.43, use face.hide).
+ - ACTIVE - the active face, read only - Use L{mesh.activeFace<Mesh.Mesh.activeFace>} to set.
+@var FaceModes: The available *texture face* modes. Note: these are only
+ meaningful if mesh.faceUV returns true, since in Blender this info is
+ stored at the TexFace (TexFace button in Edit Mesh buttons) structure.
+ - ALL - set all modes at once.
+ - BILLBOARD - always orient after camera.
+ - HALO - halo face, always point to camera.
+ - DYNAMIC - respond to collisions.
+ - INVISIBLE - invisible face.
+ - LIGHT - dynamic lighting.
+ - OBCOL - use object color instead of vertex colors.
+ - SHADOW - shadow type.
+ - SHAREDVERT - apparently unused in Blender.
+ - SHAREDCOL - shared vertex colors (per vertex).
+ - TEX - has texture image.
+ - TILES - uses tiled image.
+ - TWOSIDE - two-sided face.
+@var FaceTranspModes: The available face transparency modes. Note: these are
+ enumerated values (enums), they can't be combined (ANDed, ORed, etc) like a bit vector.
+ - SOLID - draw solid.
+ - ADD - add to background (halo).
+ - ALPHA - draw with transparency.
+ - SUB - subtract from background.
+@var EdgeFlags: The available edge flags.
+ - SELECT - selected (B{deprecated}). Use edge.sel attribute instead.
+ - EDGEDRAW - edge is drawn out of edition mode.
+ - EDGERENDER - edge is drawn out of edition mode.
+ - SEAM - edge is a seam for UV unwrapping
+ - FGON - edge is part of a F-Gon.
+ - LOOSE - Edge is not a part of a face (only set on leaving editmode)
+ - SHARP - Edge will be rendered sharp when used with the "Edge Split" modifier.
+@type AssignModes: readonly dictionary.
+@var AssignModes: The available vertex group assignment modes, used by
+ L{mesh.assignVertsToGroup()<Mesh.Mesh.assignVertsToGroup>}.
+ - ADD: if the vertex in the list is not assigned to the group
+ already, this creates a new association between this vertex and the
+ group with the weight specified, otherwise the weight given is added to
+ the current weight of an existing association between the vertex and
+ group.
+ - SUBTRACT: will attempt to subtract the weight passed from a vertex
+ already associated with a group, else it does nothing.\n
+ - REPLACE: attempts to replace a weight with the new weight value
+ for an already associated vertex/group, else it does nothing.
+@type SelectModes: readonly dictionary.
+@var SelectModes: The available edit select modes.
+ - VERTEX: vertex select mode.
+ - EDGE: edge select mode.
+ - FACE: face select mode.
+"""
+
+AssignModes = {'REPLACE':1}
+
+def Get(name=None):
+ """
+ Get the mesh data object called I{name} from Blender.
+ @type name: string
+ @param name: The name of the mesh data object.
+ @rtype: Mesh
+ @return: If a name is given, it returns either the requested mesh or None.
+ If no parameter is given, it returns all the meshes in the current scene.
+ """
+
+def New(name='Mesh'):
+ """
+ Create a new mesh data object called I{name}.
+ @type name: string
+ @param name: The name of the mesh data object.
+ @rtype: Mesh
+ @return: a new Blender mesh.
+ @note: if the mesh is not linked to an object, its datablock will be deleted
+ when the object is deallocated.
+ """
+
+def Mode(mode=0):
+ """
+ Get and/or set the selection modes for mesh editing. These are the modes
+ visible in the 3D window when a mesh is in Edit Mode.
+ @type mode: int
+ @param mode: The desired selection mode. See L{SelectModes} for values.
+ Modes can be combined. If omitted, the selection mode is not changed.
+ @rtype: int
+ @return: the current selection mode.
+ @note: The selection mode is an attribute of the current scene. If the
+ scene is changed, the selection mode may not be the same.
+ """
+
+def Unlink(name):
+ """
+ Delete an unused mesh from Blender's database. The mesh must not have
+ any users (i.e., it must not be linked to any object).
+ @type name: string
+ @param name: The name of the mesh data object.
+ @rtype: None
+ @note: This function may be a temporary solution; it may be replaced
+ in the future by a more general unlink function for many datablock types.
+ Hopefully this will be decided prior to the 2.42 release of Blender.
+ """
+
+class MCol:
+ """
+ The MCol object
+ ===============
+ This object is four ints representing an RGBA color.
+ @ivar r: The Red component in [0, 255].
+ @type r: int
+ @ivar g: The Green component in [0, 255].
+ @type g: int
+ @ivar b: The Blue component in [0, 255].
+ @type b: int
+ @ivar a: The Alpha (transparency) component in [0, 255].
+ @type a: int
+ """
+
+class MVert:
+ """
+ The MVert object
+ ================
+ This object holds mesh vertex data.
+ @ivar co: The vertex coordinates (x, y, z).
+ @type co: vector (WRAPPED DATA)
+ @ivar no: The vertex's unit normal vector (x, y, z).
+ B{Note}: if vertex coordinates are changed, it may be necessary to use
+ L{Mesh.calcNormals()} to update the vertex normals.
+ B{Note}: Vertex normals can be set, but are not wrapped so modifying a normal
+ vector will not effect the verts normal. The result is only visible
+ when faces have the smooth option enabled.
+ Example::
+ # This won't work.
+ for v in me.verts:
+ v.no.x= 0
+ v.no.y= 0
+ v.no.z= 1
+ # This will work
+ no= Blender.Mathutils.Vector(0,0,1)
+ for v in me.verts:
+ v.no= no
+ @type no: vector
+ @ivar uvco: The vertex texture "sticky" coordinates (x, y),
+ B{Note}: These are not seen in the UV editor and they are not a part of UV a UVLayer. Use face UV's for that.
+ if present. Available for MVerts only.
+ Use L{Mesh.vertexUV} to test for presence before trying to access;
+ otherwise an exception will may be thrown.
+ (Sticky coordinates can be set when the object is in the Edit mode;
+ from the Editing Panel (F9), look under the "Mesh" properties for the
+ "Sticky" button).
+ @type uvco: vector (WRAPPED DATA)
+ @ivar index: The vertex's index within the mesh (MVerts only). Read-only.
+ @type index: int
+ @ivar sel: The vertex's selection state (selected=1).
+ B{Note}: a Mesh will return the selection state of the mesh when EditMode
+ was last exited. A Python script operating in EditMode must exit EditMode
+ before getting the current selection state of the mesh.
+ @type sel: int
+ @ivar hide: The face's B{edit mode} visibility state (hidden=1).
+ @type hide: int
+ @warn: There are two kinds of UV texture coordinates in Blender: per vertex
+ ("sticky") and per face vertex (UV in L{MFace}). In the first, there's
+ only one UV pair of coordinates for each vertex in the mesh. In the
+ second, for each face it belongs to, a vertex can have different UV
+ coordinates. This makes the per face option more flexible, since two
+ adjacent faces won't have to be mapped to a continuous region in an image:
+ each face can be independently mapped to any part of its texture.
+ """
+
+ def __init__(coord):
+ """
+ Create a new PVert object.
+
+ @note: PVert-type objects are designed to be used for creating and
+ modifying a mesh's vertex list, but since they do not "wrap" any Blender
+ data there are some differences. The B{index} and B{uvco} attributes
+ are not defined for PVerts, and the B{no} attribute contains valid
+ data only if the PVert was created from an MVert (using a slice
+ operation on the mesh's vertex list.) PVerts also cannot be used as an
+ argument to any method which expects data wrapping a Blender mesh, such
+ as L{MVertSeq.delete()}.
+
+ Example::
+ v = Blender.Mesh.MVert(1,0,0)
+ v = Blender.Mesh.MVert(Blender.Mathutils.Vector([1,0,0]))
+
+ m = Blender.Mesh.Get('Mesh')
+ vlist = m.verts[:] # slice operation also returns PVerts
+
+ @type coord: three floats or a Vector object
+ @param coord: the coordinate values for the new vertex
+ @rtype: PVert
+ @return: a new PVert object
+
+ """
+
+class MVertSeq:
+ """
+ The MVertSeq object
+ ===================
+ This object provides sequence and iterator access to the mesh's vertices.
+ Access and assignment of single items and slices are also supported.
+ When a single item in the vertex list is accessed, the operator[] returns
+ a MVert object which "wraps" the actual vertex in the mesh; changing any
+ of the vertex's attributes will immediately change the data in the mesh.
+ When a slice of the vertex list is accessed, however, the operator[]
+ returns a list of PVert objects which are copies of the mesh's vertex
+ data. Changes to these objects have no effect on the mesh; they must be
+ assigned back to the mesh's vertex list.
+
+ Slice assignments cannot change the vertex list size. The size of the
+ list being assigned must be the same as the specified slice; otherwise an
+ exception is thrown.
+
+ Example::
+ import Blender
+ from Blender import Mesh
+
+ me = Mesh.Get("Plane") # get the mesh data called "Plane"
+ vert = me.verts[0] # vert accesses actual mesh data
+ vert.co[0] += 2 # change the vertex's X location
+ pvert = me.verts[-2:] # pvert is COPY of mesh's last two verts
+ pvert[0].co[0] += 2 # change the vertex's X location
+ pvert[1].co[0] += 2 # change the vertex's X location
+ me.verts[-1] = pvert[1] # put change to second vertex into mesh
+
+ @note: The mesh can be "cleared" by assigning B{None} to the mesh's vertex
+ list. This does not delete the Blender mesh object, it only deletes all
+ the memory allocated to the mesh. The result is equivalent to calling
+ Mesh.New(). The intent is to allow users writing exporters to free memory
+ after it is used in a quick and simple way.
+
+ Example::
+ import Blender
+ from Blender import Mesh
+
+ me = Mesh.Get("Plane") # get the mesh data called "Plane"
+ me.verts = None # delete all the mesh's attributes
+
+ """
+
+ def extend(coords):
+ """
+ Append zero or more vertices to the mesh. Unlike L{MEdgeSeq.extend()} and
+ L{MFaceSeq.extend()} no attempt is made to check for duplicate vertices in
+ the parameter list, or for vertices already in the mesh.
+ @note: Since Blender 2.44 all new verts are selected.
+
+ Example::
+ import Blender
+ from Blender import Mesh
+ from Blender.Mathutils import Vector
+
+ me = Mesh.Get("Plane") # get the mesh data called "Plane"
+ me.verts.extend(1,1,1) # add one vertex
+ l=[(.1,.1,.1),Vector([2,2,.5])]
+ me.verts.extend(l) # add multiple vertices
+
+ @type coords: sequences(s) of floats or vectors
+ @param coords: coords can be
+ - a sequence of three floats,
+ - a 3D vector, or
+ - a sequence (list or tuple) of either of the above.
+ """
+
+ def delete(verts):
+ """
+ Deletes one or more vertices from the mesh. Any edge or face which
+ uses the specified vertices are also deleted.
+
+ @type verts: multiple ints or MVerts
+ @param verts: can be
+ - a single MVert belonging to the mesh (B{note:} will not work with
+ PVerts)
+ - a single integer, specifying an index into the mesh's vertex list
+ - a sequence (list or tuple) containing two or more of either of
+ the above.
+ """
+
+ def selected():
+ """
+ Get selected vertices.
+ @return: a list of the indices for all vertices selected in edit mode.
+ @rtype: list of ints
+ """
+
+class MEdge:
+ """
+ The MEdge object
+ ================
+ This object holds mesh edge data.
+ @ivar v1: The first vertex of the edge.
+ @type v1: MVert
+ @ivar v2: The second vertex of the edge.
+ @type v2: MVert
+ @ivar length: The length of the edge, same as (ed.v1.co-ed.v2.co).length where "ed" is an MEdge.
+ @type length: float
+ @ivar crease: The crease value of the edge. It is in the range [0,255].
+ @type crease: int
+ @ivar flag: The bitfield describing edge properties. See L{EdgeFlags}.
+ Example::
+ # This script counts fgon and non fgon edges
+ from Blender import Scene, Mesh
+ scn= Scene.GetCurrent() # Current scene, important to be scene aware
+ ob= scn.objects.active # last selected object
+ me= ob.getData(mesh=1) # thin wrapper doesn't copy mesh data like nmesh
+
+ total_fgon_eds= total_nor_eds= 0
+
+ # Look through the edges and find any fgon edges, then print the findings to the console
+ for ed in me.edges: # all meshes have edge data now
+ if ed.flag & Mesh.EdgeFlags.FGON:
+ total_fgon_eds+=1
+ else:
+ total_nor_eds+=1
+
+ print 'Blender has', total_fgon_eds, 'fgon edges and', total_nor_eds, 'non fgon edges'
+ @type flag: int
+ @ivar index: The edge's index within the mesh. Read-only.
+ @type index: int
+ @ivar sel: The edge's B{edit mode} selection state (selected=1). B{Note}:
+ changing the select state of an edge changes the select state of the edge's
+ vertices.
+ @type sel: int
+ @ivar key: The edge's vert indices in an ordered tuple, which can be used
+ as a dictionary key. Read-only.
+ This is the same as (min(ed.v1.index, ed.v2.index), max(ed.v1.index, ed.v2.index))
+ @type key: tuple
+ """
+
+ def __iter__():
+ """
+ Iterator for MEdge. It iterates over the MVerts of the edge, returning
+ v1 then v2.
+ @return: one of the edge's vertices
+ @rtype: MVert
+ """
+
+class MEdgeSeq:
+ """
+ The MEdgeSeq object
+ ===================
+ This object provides sequence and iterator access to the mesh's edges.
+ """
+
+ def extend(vertseq):
+ """
+ Add zero or more edges to the mesh. Edges which already exist in the
+ mesh or with both vertices the same are ignored. If three or four verts
+ are specified in any sequence, an edge is also created between the first
+ and last vertices (this is useful when adding faces).
+ @note: Since Blender 2.44 all new edges are selected.
+
+ Example::
+ import Blender
+ from Blender import Mesh
+
+ me = Mesh.Get("Plane") # get the mesh data called "Plane"
+ v = me.verts # get vertices
+ if len(v) >= 6: # if there are enough vertices...
+ me.edges.extend(v[0],v[1]) # add a single edge
+ l=[(v[1],v[2],v[3]),[0,2,4,5]]
+ me.edges.extend(l) # add multiple edges
+
+ @type vertseq: sequence(s) of ints or MVerts
+ @param vertseq: either two to four ints or MVerts, or sequence
+ (list or tuple) of sequences each containing two to four ints or MVerts.
+ """
+
+ def delete(edges):
+ """
+ Deletes one or more edges from the mesh. In addition, also delete:
+ - any faces which uses the specified edge(s)
+ - any "orphan" vertices (belonging only to specified edge(s))
+
+ @type edges: multiple ints or MEdges
+ @param edges: can be
+ - a single MEdge belonging to the mesh
+ - a single integer, specifying an index into the mesh's edge list
+ - a sequence (list or tuple) containing two or more of either of
+ the above.
+ """
+
+ def selected():
+ """
+ Get selected edges.
+ Selected edges are those for which both vertices are selected.
+ @return: a list of the indices for all edges selected in edit mode.
+ @rtype: list of ints
+ """
+
+class MFace:
+ """
+ The MFace object
+ ================
+ This object holds mesh face data.
+
+ Example::
+ import Blender
+ from Blender import Mesh, Window
+
+ in_emode = Window.EditMode()
+ if in_emode: Window.EditMode(0)
+
+ me = Mesh.Get("Mesh")
+ faces = me.faces
+
+ ## Example for editmode faces selection:
+ selected_faces = []
+ for f in faces:
+ if f.sel:
+ selected_faces.append(f)
+ # ... unselect selected and select all the others:
+ for f in faces:
+ f.sel = not f.sel # 1 becomes 0, 0 becomes 1
+
+ ## Example for UV textured faces selection:
+ selected_faces = []
+ SEL = Mesh.FaceFlags['SELECT']
+ # get selected faces:
+ for f in faces:
+ if f.flag & SEL:
+ selected_faces.append(f)
+ # ... unselect selected and select all the others:
+ for f in faces:
+ if f.flag & SEL:
+ f.flag &= ~SEL # unselect these
+ else:
+ f.flag |= SEL # and select these
+
+ if in_emode: Window.EditMode(1)
+ Blender.Redraw()
+
+ @ivar verts: The face's vertices. Each face has 3 or 4 vertices.
+ @type verts: list of MVerts
+ @ivar v: Same as L{verts}. This attribute is only for compatibility with
+ NMesh scripts and will probably be deprecated in the future.
+ @ivar sel: The face's B{edit mode} selection state (selected=1).
+ This is not the same as the selection state of the textured faces
+ (see L{flag}). B{Note}: changing the select state of a face changes
+ the select state of the face's vertices.
+ @type sel: int
+ @ivar hide: The face's B{edit mode} visibility state (hidden=1).
+ This is not the same as the visibility state of
+ the textured faces (see L{flag}).
+ @type hide: int
+ @ivar smooth: If set, the vertex normals are averaged to make this
+ face look smooth. (This is the same as choosing "Set Smooth" in the
+ Editing Panel (F9) under "Link and Material" properties).
+ @type smooth: int
+ @ivar col: The face's vertex colors, if defined. Each vertex has its own
+ color.
+ Will throw an exception if L{Mesh.vertexColors} is False.
+
+ Example::
+ # This example uses vertex normals to apply normal colors to each face.
+ import bpy
+ from Blender import Window
+ scn= bpy.scenes.active # Current scene, important to be scene aware
+ ob= scn.objects.active # last selected object
+ me= ob.getData(mesh=1) # thin wrapper doesn't copy mesh data like nmesh
+ me.vertexColors= True # Enable face, vertex colors
+ for f in me.faces:
+ for i, v in enumerate(f):
+ no= v.no
+ col= f.col[i]
+ col.r= int((no.x+1)*128)
+ col.g= int((no.y+1)*128)
+ col.b= int((no.z+1)*128)
+ Window.RedrawAll()
+ @type col: tuple of MCols
+ @ivar mat: The face's index into the mesh's materials
+ list. It is in the range [0,15].
+ @type mat: int
+ @ivar image: The Image used as a texture for this face.
+ Setting this attribute will create UV faces if they do not exist.
+ Getting this attribute throw an exception if the mesh does not have
+ UV faces; use L{Mesh.faceUV} to test.
+ Assigning an image will automatically set the TEX attribute of the
+ L{mode} bitfield. Use "del f.image" or "f.image = None" to clear the
+ image assigned to the face.
+ @type image: Image
+ @ivar mode: The texture mode bitfield (see L{FaceModes}).
+ Will throw an exception if the mesh does not have UV faces; use
+ L{Mesh.faceUV} to test.
+ @type mode: int
+ @ivar index: The face's index within the mesh. Read-only.
+ @type index: int
+
+ @ivar flag: The face's B{texture mode} flags; indicates the selection,
+ active , and visibility states of a textured face (see
+ L{FaceFlags} for values).
+ This is not the same as the selection or visibility states of
+ the faces in edit mode (see L{sel} and L{hide}).
+ To set the active face, use
+ the L{Mesh.activeFace} attribute instead.
+ Will throw an exception if the mesh does not have UV faces; use
+ L{Mesh.faceUV} to test.
+
+ @ivar transp: Transparency mode. It is one of the values in
+ L{FaceTranspModes}).
+ Will throw an exception if the mesh does not have UV faces; use
+ L{Mesh.faceUV} to test.
+ @type transp: int
+
+ @ivar uv: The face's UV coordinates. Each vertex has its own UV coordinate.
+ Setting this attribute will create UV faces if they do not exist.
+ Getting this attribute throw an exception if the mesh does not have
+ UV faces; use L{Mesh.faceUV} to test.
+ @type uv: tuple of vectors (WRAPPED DATA)
+ @ivar uvSel: The face's UV coordinates selection state; a 1 indicates the
+ vertex is selected. Each vertex has its own UV coordinate select state
+ (this is not the same as the vertex's edit mode selection state).
+ Setting this attribute will create UV faces if they do not exist.
+ Getting this attribute throw an exception if the mesh does not have
+ UV faces; use L{Mesh.faceUV} to test.
+ @type uvSel: tuple of ints
+ @ivar no: The face's normal vector (x, y, z). Read-only.
+ @type no: vector
+ @ivar cent: The center of the face. Read-only.
+ @type cent: vector
+ @ivar area: The area of the face. Read-only.
+ @type area: float
+ @ivar edge_keys: A tuple, each item a key that can reference an edge by its
+ ordered indices. Read-only. This is useful for building connectivity data.
+ Example::
+ from Blender import Mesh
+ me = Mesh.Get('Cube')
+ # a dictionary where the edge is the key, and a list of faces that use it are the value
+ edge_faces = dict([(ed.key, []) for ed in me.edges])
+
+ # Add the faces to the dict
+ for f in me.faces:
+ for key in f.edge_keys:
+ edge_faces[key].append(f) # add this face to the edge as a user
+
+ # Print the edges and the number of face users
+ for key, face_users in edge_faces.iteritems():
+ print 'Edge:', key, 'uses:', len(face_users),'faces'
+
+ @type edge_keys: tuple
+ @note: there are regular faces and textured faces in Blender, both currently
+ with their own selection and visibility states, due to a mix of old and new
+ code. To (un)select or (un)hide regular faces (visible in EditMode), use
+ L{MFace.sel} and L{MFace.hide} attributes. For textured faces (UV Face
+ Select and Paint modes in Blender) use the L{MFace.flag} attribute.
+ Check the example above and note L{Window.EditMode}.
+ @note: Assigning UV textures to mesh faces in Blender works like this:
+ 1. Select your mesh.
+ 2. Enter face select mode (press f) and select at least some face(s).
+ 3. In the UV/Image Editor window, load / select an image.
+ 4. Play in both windows (better split the screen to see both at the same
+ time) until the UV coordinates are where you want them. Hint: in the
+ 3D window, the 'u' key opens a menu of default UV choices and the 'r'
+ key lets you rotate the UV coords.
+ 5. Leave face select mode (press f).
+ """
+
+ def __iter__():
+ """
+ Iterator for MVert. It iterates over the MVerts of the face, returning
+ v1, v2, v3 (and optionally v4);
+ @return: one of the face's vertices
+ @rtype: MVert
+ """
+
+ def __len__():
+ """
+ len for MVert. It returns the number of vertices in the face.
+ @rtype: int
+ """
+
+class MFaceSeq:
+ """
+ The MFaceSeq object
+ ===================
+ This object provides sequence and iterator access to the mesh's faces.
+ """
+
+ def extend(vertseq,ignoreDups=True,indexList=True):
+ """
+ Add zero or more faces and edges to the mesh. Faces which already exist
+ in the mesh, or faces which contain the same vertex multiple times are
+ ignored. Sequences of two vertices are accepted, but no face will be
+ created.
+ @note: Since Blender 2.44 all new faces are selected.
+
+ Example::
+ import Blender
+ from Blender import Mesh
+
+ me = Mesh.Get("Plane") # get the mesh data called "Plane"
+ v = me.verts # get vertices
+ if len(v) >= 6: # if there are enough vertices...
+ me.faces.extend(v[1],v[2],v[3]) # add a single edge
+ l=[(v[0],v[1]),[0,2,4,5]]
+ me.faces.extend(l) # add another face
+
+ @type vertseq: sequence(s) of MVerts
+ @param vertseq: either two to four ints or MVerts, or sequence (list or
+ tuple) of sequences each containing two to four ints or MVerts.
+ @type ignoreDups: boolean
+ @param ignoreDups: keyword parameter (default is False). If supplied and
+ True, do not check the input list or mesh for duplicate faces. This can
+ speed up scripts but can prossibly produce undesirable effects. Only
+ use if you know what you're doing.
+ @type indexList: boolean
+ @param indexList: keyword parameter (default is False). If supplied and
+ True, the method will return a list representing the new index for each
+ face in the input list. If faces are removed as duplicates, None is
+ inserted in place of the index.
+ @warning: Faces using the first vertex at the 3rd or 4th location in the
+ face's vertex list will have their order rotated so that the zero index
+ on in the first or second location in the face. When creating face data
+ with UVs or vertex colors, you may need to work around this, either by
+ checking for zero indices yourself or by adding a dummy first vertex to
+ the mesh that can be removed when your script has finished.
+ """
+
+ def delete(deledges, faces):
+ """
+ Deletes one or more faces (and optionally the edges associated with
+ the face(s)) from the mesh.
+
+ @type deledges: int
+ @param deledges: controls whether just the faces (deledges=0)
+ or the faces and edges (deledges=1) are deleted. These correspond to the
+ "Only Faces" and "Edges & Faces" options in the Edit Mode pop-up menu
+ @type faces: multiple ints or MFaces
+ @param faces: a sequence (list or tuple) containing one or more of:
+ - an MEdge belonging to the mesh
+ - a integer, specifying an index into the mesh's face list
+ """
+
+ def sort():
+ """
+ Sorts the faces using exactly the same syntax as pythons own list sorting function.
+
+ Example::
+ import Blender
+ from Blender import Mesh
+ me = Mesh.Get('mymesh')
+
+ me.faces.sort(key=lambda f: f.area)
+
+ me.faces.sort(key=lambda f: f.cent)
+
+ @note: Internally faces only refer to their index, so after sorting, faces you alredy have will not have their index changed to match the new sorted order.
+ """
+
+ def selected():
+ """
+ Get selected faces.
+ @return: a list of the indices for all faces selected in edit mode.
+ @rtype: list of ints
+ """
+
+from IDProp import IDGroup, IDArray
+class Mesh:
+ """
+ The Mesh Data object
+ ====================
+ This object gives access to mesh data in Blender.
+
+ @note: the verts, edges and faces attributes are implemented as sequences.
+ The operator[] and len() are defined for these sequences. You cannot
+ assign to an item in the sequence, but you can assign to most of the
+ attributes of individual items.
+ @ivar edges: The mesh's edges.
+ @type edges: sequence of MEdges
+ @ivar faces: The mesh's faces.
+ @type faces: sequence of MFaces
+ @ivar verts: The mesh's vertices.
+ @type verts: sequence of MVerts
+
+ @ivar materials: The mesh's materials. Each mesh can reference up to
+ 16 materials. Empty slots in the mesh's list are represented by B{None}.
+ B{Note}: L{Object.colbits<Object.Object.colbits>} needs to be set correctly
+ for each object in order for these materials to be used instead of
+ the object's materials.
+ B{Note}: Making the material list shorter does not change the face's material indices.
+ Take care when using the face's material indices to reference a material in this list.
+ B{Note}: The list that's returned is I{not} linked to the original mesh.
+ mesh.materials.append(material) won't do anything.
+ Use mesh.materials += [material] instead.
+ @type materials: list of L{Material}s
+ @ivar degr: The max angle for auto smoothing in [1,80].
+ @type degr: int
+ @ivar maxSmoothAngle: Same as L{degr}. This attribute is only for
+ compatibility with NMesh scripts and will probably be deprecated in
+ the future.
+ @ivar mode: The mesh's mode bitfield. See L{Modes}.
+ @type mode: int
+ @ivar sel: Sets selection status for all vertices, edges and faces in the
+ mesh (write only).
+ @type sel: boolean
+ @ivar hide: Sets hidden status for all vertices, edges and faces in the
+ mesh (write only).
+ @type hide: boolean
+ @ivar subDivLevels: The [display, rendering] subdivision levels in [1, 6].
+ @type subDivLevels: list of 2 ints
+ @ivar faceUV: The mesh contains UV-mapped textured faces.
+ @type faceUV: bool
+ @ivar vertexColors: The mesh contains vertex colors. Set True to add vertex colors.
+ @type vertexColors: bool
+ @ivar vertexUV: The mesh contains "sticky" per-vertex UV coordinates.
+ @type vertexUV: bool
+ @ivar activeFace: Index of the mesh's active face in UV Face Select and
+ Paint modes. Only one face can be active at a time. Note that this is
+ independent of the selected faces in Face Select and Edit modes.
+ Will throw an exception if the mesh does not have UV faces; use
+ L{faceUV} to test.
+ @type activeFace: int
+ @ivar activeGroup: The mesh's active vertex group. The mesh must be
+ linked to an object (read the comment in L{addVertGroup} for more info).
+ @type activeGroup: string or None
+ @ivar texMesh: The mesh's texMesh setting, used so coordinates from another
+ mesh can be used for rendering textures.
+ @type texMesh: Mesh or None
+ @ivar key: The L{Key<Key.Key>} object containing the keyframes for this mesh, if any.
+ @type key: Key or None
+ @ivar activeUVLayer: The mesh's active UV/Image layer. None if there is no UV/Image layers.
+
+ B{Note}: After setting this value, call L{update} so the result can be seen the the 3d view.
+ @type activeUVLayer: string
+ @ivar activeColorLayer: The mesh's active Vertex Color layer. None if there is no UV/Image layers.
+
+ B{Note}: After setting this value, call L{update} so the result can be seen the the 3d view.
+ @type activeColorLayer: string
+
+ @ivar renderUVLayer: The mesh's rendered UV/Image layer. None if there is no UV/Image layers.
+ @type renderUVLayer: string
+ @ivar renderColorLayer: The mesh's rendered Vertex Color layer. None if there is no UV/Image layers.
+ @type renderColorLayer: string
+
+ @ivar multires: The mesh has multires data, set True to add multires data.
+ Will throw an exception if the mesh has shape keys; use L{key} to test.
+ @type multires: bool
+ @ivar multiresLevelCount: The mesh has multires data. (read only)
+ @type multiresLevelCount: int
+ @ivar multiresDrawLevel: The multires level to display in the 3dview in [1 - multiresLevelCount].
+ @type multiresDrawLevel: int
+ @ivar multiresEdgeLevel: The multires level edge display in the 3dview [1 - multiresLevelCount].
+ @type multiresEdgeLevel: int
+ @ivar multiresPinLevel: The multires pin level, used for applying modifiers [1 - multiresLevelCount].
+ @type multiresPinLevel: int
+ @ivar multiresRenderLevel: The multires level to render [1 - multiresLevelCount].
+ @type multiresRenderLevel: int
+
+
+ """
+
+ def getFromObject(object, cage=0, render=0):
+ """
+ Replace the mesh's existing data with the raw mesh data from a Blender
+ Object. This method supports all the geometry based objects (mesh, text,
+ curve, surface, and meta). If the object has modifiers, they will be
+ applied before to the object before extracting the vertex data unless
+ the B{cage} parameter is 1.
+ @note: The mesh coordinates are in I{local space}, not the world space of
+ its object. For world space vertex coordinates, each vertex location must
+ be multiplied by the object's 4x4 transform matrix (see L{transform}).
+ @note: The objects materials will not be copied into the existing mesh,
+ however the face material indices will match the material list of the original data.
+ @type object: blender object or string
+ @param object: The Blender object or its name, which contains the geometry data.
+ @type cage: int
+ @param cage: determines whether the original vertices or derived vertices
+ @type render: int
+ @param render: determines whether the render setting for modifiers will be used or not.
+ (for objects with modifiers) are used. The default is derived vertices.
+ """
+
+ def calcNormals():
+ """
+ Recalculates the vertex normals using face data.
+ """
+
+ def pointInside(vector):
+ """
+ Returns true if vector is inside the mesh.
+ @note: Only returns a valid result for mesh data that has no holes.
+ """
+
+ def transform(matrix, recalc_normals = False, selected_only=False):
+ """
+ Transforms the mesh by the specified 4x4 matrix (such as returned by
+ L{Object.Object.getMatrix}). The matrix should be invertible.
+ Ideal usage for this is exporting to an external file where
+ global vertex locations are required for each object.
+ Sometimes external renderers or file formats do not use vertex normals.
+ In this case, you can skip transforming the vertex normals by leaving
+ the optional parameter recalc_normals as False or 0 (the default value).
+
+ Example::
+ # This script outputs deformed meshes worldspace vertex locations
+ # for a selected object without changing the object
+ import Blender
+ from Blender import Mesh, Object
+
+ ob = Object.GetSelected()[0] # Get the first selected object
+ me = Mesh.New() # Create a new mesh
+ me.getFromObject(ob.name) # Get the object's mesh data
+ verts = me.verts[:] # Save a copy of the vertices
+ me.transform(ob.matrix) # Convert verts to world space
+ for v in me.verts:
+ print 'worldspace vert', v.co
+ me.verts = verts # Restore the original verts
+
+ @type matrix: Py_Matrix
+ @param matrix: 4x4 Matrix which can contain location, scale and rotation.
+ @type recalc_normals: int
+ @param recalc_normals: if True or 1, also transform vertex normals.
+ @type selected_only: int
+ @param selected_only: if True or 1, only the selected verts will be transformed.
+ @warn: unlike L{NMesh.transform()<NMesh.NMesh.transform>}, this method
+ I{will immediately modify the mesh data} when it is used. If you
+ transform the mesh using the object's matrix to get the vertices'
+ world positions, the result will be a "double transform". To avoid
+ this you either need to set the object's matrix to the identity
+ matrix, perform the inverse transform after outputting the transformed
+ vertices, or make a copy of the vertices prior to using this method
+ and restore them after outputting the transformed vertices (as shown
+ in the example).
+ """
+
+ def vertexShade(object):
+ """
+ Colors vertices based on the current lighting setup, like when there
+ are no vertex colors and no textured faces and a user enters Vertex Paint
+ Mode in Blender (only lamps in visible layers account). An exception is
+ thrown if called while in EditMode.
+ @type object: Object
+ @param object: The Blender Object linked to the mesh.
+ """
+
+ def update(key=None):
+ """
+ Update display lists after changes to mesh. B{Note}: with changes taking
+ place for using a directed acyclic graph (DAG) for scene and object
+ updating, this method may be only temporary and may be removed in future
+ releases.
+ @type key: string
+ @param key: Use this optional argument to write the current vertex
+ locations to the a shape key. the name must match an existing shape key for this mesh
+ See L{Mesh.Mesh.key} and L{Key.Key.blocks} to get a list of the named shape keys, setting the active keys is
+ done from the object with L{Object.Object.pinShape}, L{Object.Object.activeShape}.
+
+
+
+ @warn: Since Blender 2.42 this function has changed; now it won't recalculate
+ vertex normals (seen when faces are smooth). See L{Mesh.calcNormals()}.
+ """
+
+ def findEdges(edges):
+ """
+ Quickly search for the location of an edges.
+ @type edges: sequence(s) of ints or MVerts
+ @param edges: can be tuples of MVerts or integer indexes (B{note:} will
+ not work with PVerts) or a sequence (list or tuple) containing two or
+ more sequences.
+ @rtype: int, None or list
+ @return: if an edge is found, its index is returned; otherwise None is
+ returned. If a sequence of edges is passed, a list is returned.
+ """
+
+ def addVertGroup(group):
+ """
+ Add a named and empty vertex (deform) group to the object this mesh is
+ linked to. The mesh must first be linked to an object (with object.link()
+ or object.getData() ) so the method knows which object to update.
+ This is because vertex groups in Blender are stored in I{the object} --
+ not in the mesh, which may be linked to more than one object.
+ @type group: string
+ @param group: the name for the new group.
+ """
+
+ def removeVertGroup(group):
+ """
+ Remove a named vertex (deform) group from the object linked to this mesh.
+ All vertices assigned to the group will be removed (just from the group,
+ not deleted from the mesh), if any. If this mesh was newly created, it
+ must first be linked to an object (read the comment in L{addVertGroup} for
+ more info).
+ @type group: string
+ @param group: the name of a vertex group.
+ """
+
+ def assignVertsToGroup(group, vertList, weight, assignmode = AssignModes['REPLACE']):
+ """
+ Adds an array (a Python list) of vertex points to a named vertex group
+ associated with a mesh. The vertex list is a list of vertex indices from
+ the mesh. You should assign vertex points to groups only when the mesh has
+ all its vertex points added to it and is already linked to an object.
+
+ I{B{Example:}}
+ The example here adds a new set of vertex indices to a sphere primitive::
+ import Blender
+ sphere = Blender.Object.Get('Sphere')
+ replace = Blender.Mesh.AssignModes.REPLACE
+ mesh = sphere.getData(mesh=True)
+ mesh.addVertGroup('firstGroup')
+ vertList = []
+ for x in range(300):
+ if x % 3 == 0:
+ vertList.append(x)
+ mesh.assignVertsToGroup('firstGroup', vertList, 0.5, replace)
+
+ @type group: string
+ @param group: the name of the group.
+ @type vertList: list of ints
+ @param vertList: a list of vertex indices.
+ @type weight: float
+ @param weight: the deform weight for (which means: the amount of influence
+ the group has over) the given vertices. It should be in the range
+ [0.0, 1.0]. If weight <= 0, the given vertices are removed from the
+ group. If weight > 1, it is clamped.
+ @type assignmode: module constant
+ @param assignmode: Three choices: REPLACE, ADD or SUBTRACT.
+ See L{AssignModes} for a complete description.
+ """
+
+ def removeVertsFromGroup(group, vertList = None):
+ """
+ Remove a list of vertices from the given group. If this mesh was newly
+ created, it must first be linked to an object (check L{addVertGroup}).
+ @type group: string
+ @param group: the name of a vertex group
+ @type vertList: list of ints
+ @param vertList: a list of vertex indices to be removed from I{group}.
+ If None, all vertices are removed -- the group is emptied.
+ """
+
+ def getVertsFromGroup(group, weightsFlag = 0, vertList = None):
+ """
+ Return a list of vertex indices associated with the passed group. This
+ method can be used to test whether a vertex index is part of a group and
+ if so, what its weight is.
+
+ I{B{Example:}}
+ Append this to the example from L{assignVertsToGroup}::
+ # ...
+ print "Vertex indices from group %s :" % groupName
+ print mesh.getVertsFromGroup('firstGroup')
+ print "Again, with weights:"
+ print mesh.getVertsFromGroup('firstGroup',1)
+ print "Again, with weights and restricted to the given indices:"
+ print mesh.getVertsFromGroup('firstGroup',1,[1,2,3,4,5,6])
+
+ @type group: string
+ @param group: the group name.
+ @type weightsFlag: bool
+ @param weightsFlag: if 1, each item in the list returned contains a
+ tuple pair (index, weight), the weight is a float between 0.0 and 1.0.
+ @type vertList: list of ints
+ @param vertList: if given, only those vertex points that are both in the
+ list and group passed in are returned.
+ """
+
+ def renameVertGroup(groupName, newName):
+ """
+ Renames a vertex group.
+ @type groupName: string
+ @param groupName: the vertex group name to be renamed.
+ @type newName: string
+ @param newName: the name to replace the old name.
+ """
+
+ def getVertGroupNames():
+ """
+ Return a list of all vertex group names.
+ @rtype: list of strings
+ @return: returns a list of strings representing all vertex group
+ associated with the mesh's object
+ """
+
+ def getUVLayerNames():
+ """
+ Return a list of all UV layer names
+ @rtype: list of strings
+ @return: returns a list of strings representing all UV layers
+ associated with the mesh's object
+ """
+
+ def getColorLayerNames():
+ """
+ Return a list of all color layer names
+ @rtype: list of strings
+ @return: returns a list of strings representing all color layers
+ associated with the mesh's object
+ """
+
+ def getVertexInfluences(index):
+ """
+ Get the bone influences for a specific vertex.
+ @type index: int
+ @param index: The index of a vertex.
+ @rtype: list of lists
+ @return: List of pairs [name, weight], where name is the bone name (string)
+ and weight is a float value.
+ """
+
+ def removeAllKeys():
+ """
+ Remove all mesh keys stored in this mesh.
+ @rtype: bool
+ @return: True if successful or False if the Mesh has no keys.
+ """
+
+ def insertKey(frame = None, type = 'relative'):
+ """
+ Insert a mesh key at the given frame.
+ @type frame: int
+ @type type: string
+ @param frame: The Scene frame where the mesh key should be inserted. If
+ None or the arg is not given, the current frame is used.
+ @param type: The mesh key type: 'relative' or 'absolute'. This is only
+ relevant on meshes with no keys.
+ @warn: This and L{removeAllKeys} were included in this release only to
+ make accessing vertex keys possible, but may not be a proper solution
+ and may be substituted by something better later. For example, it
+ seems that 'frame' should be kept in the range [1, 100]
+ (the curves can be manually tweaked in the Ipo Curve Editor window in
+ Blender itself later).
+ @warn: Will throw an error if the mesh has multires. use L{multires} to check.
+ """
+
+ def addUVLayer(name):
+ """
+ Adds a new UV/Image layer to this mesh, it will always be the last layer but not made active.
+ @type name: string
+ @param name: The name of the new UV layer, 31 characters max.
+ """
+
+ def addColorLayer(name):
+ """
+ Adds a new Vertex Color layer to this mesh, it will always be the last layer but not made active.
+ @type name: string
+ @param name: The name of the new Color layer, 31 characters max.
+ """
+
+ def removeUVLayer(name):
+ """
+ Removes the active UV/Image layer.
+ @type name: string
+ @param name: The name of the UV layer to remove.
+ """
+
+ def removeColorLayer(name):
+ """
+ Removes the active Vertex Color layer.
+ @type name: string
+ @param name: The name of the Color layer to remove.
+ """
+
+ def renameUVLayer(name, newname):
+ """
+ Renames the UV layer called name to newname.
+ @type name: string
+ @param name: The UV layer to rename.
+ @type newname: string
+ @param newname: The new name of the UV layer, will be made unique.
+ """
+
+ def renameColorLayer(name, newname):
+ """
+ Renames the color layer called name to newname.
+ @type name: string
+ @param name: The Color layer to rename.
+ @type newname: string
+ @param newname: The new name of the Color layer, will be made unique.
+ """
+
+ def smooth():
+ """
+ Flattens angle of selected faces. Experimental mesh tool.
+ An exception is thrown if called while in EditMode.
+ """
+
+ def flipNormals():
+ """
+ Toggles the direction of selected face's normals. Experimental mesh tool.
+ An exception is thrown if called while in EditMode.
+ """
+
+ def toSphere():
+ """
+ Moves selected vertices outward in a spherical shape. Experimental mesh
+ tool.
+ An exception is thrown if called while in EditMode.
+ """
+
+ def fill():
+ """
+ Scan fill a closed selected edge loop. Experimental mesh tool.
+ An exception is thrown if called while in EditMode.
+ """
+
+ def triangleToQuad():
+ """
+ Convert selected triangles to quads. Experimental mesh tool.
+ An exception is thrown if called while in EditMode.
+ """
+
+ def quadToTriangle(mode=0):
+ """
+ Convert selected quads to triangles. Experimental mesh tool.
+ An exception is thrown if called while in EditMode.
+ @type mode: int
+ @param mode: specifies whether a to add the new edge between the
+ closest (=0) or farthest(=1) vertices.
+ """
+
+ def subdivide(beauty=0):
+ """
+ Subdivide selected edges in a mesh. Experimental mesh tool.
+ An exception is thrown if called while in EditMode.
+ @type beauty: int
+ @param beauty: specifies whether a "beauty" subdivide should be
+ enabled (disabled is default). Value must be in the range [0,1].
+ """
+
+ def remDoubles(limit):
+ """
+ Removes duplicates from selected vertices. Experimental mesh tool.
+ An exception is thrown if called while in EditMode.
+ @type limit: float
+ @param limit: specifies the maximum distance considered for vertices
+ to be "doubles". Value is clamped to the range [0.0,1.0].
+ @rtype: int
+ @return: the number of vertices deleted
+ """
+
+ def recalcNormals(direction=0):
+ """
+ Recalculates inside or outside normals for selected faces. Experimental
+ mesh tool.
+ An exception is thrown if called while in EditMode.
+ @type direction: int
+ @param direction: specifies outward (0) or inward (1) normals. Outward
+ is the default. Value must be in the range [0,1].
+ """
+
+ def __copy__ ():
+ """
+ Make a copy of this mesh
+ @rtype: Mesh
+ @return: a copy of this mesh
+ """
+
+import id_generics
+Mesh.__doc__ += id_generics.attributes
diff --git a/source/blender/python/api2_2x/doc/MeshPrimitives.py b/source/blender/python/api2_2x/doc/MeshPrimitives.py
new file mode 100644
index 00000000000..4fb53ab4536
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/MeshPrimitives.py
@@ -0,0 +1,157 @@
+# Blender.Mesh.Primitives module
+
+"""
+The Blender.Mesh.Primitives submodule.
+
+B{New}:
+
+Mesh Primitive Data
+===================
+
+This submodule provides access Blender's mesh primitives. Each module
+function returns a BPy_Mesh object which wraps the mesh data. This data can
+then be manipulated using the L{Mesh} API.
+
+Example::
+
+ from Blender import *
+
+ me = Mesh.Primitives.Cube(2.0) # create a new cube of size 2
+ sc = Scene.GetCurrent() # get current scene
+ sc.objects.new(me,'Mesh') # add a new mesh-type object to the scene
+ Window.RedrawAll() # update windows
+"""
+
+def Plane(size=2.0):
+ """
+ Construct a filled planar mesh with 4 vertices. The default size
+ creates a 2 by 2 Blender unit plane, identical to the Blender UI.
+ @type size: float
+ @param size: optional size of the plane.
+ @rtype: L{BPy_Mesh<Mesh>}
+ @return: returns a mesh object.
+ """
+
+def Cube(size=2.0):
+ """
+ Construct a cube mesh. The default size creates a cube with each face
+ 2 by 2 Blender units, identical to the Blender UI.
+ @type size: float
+ @param size: optional size of the cube.
+ @rtype: L{BPy_Mesh<Mesh>}
+ @return: returns a mesh object.
+ """
+
+def Circle(verts=32,diameter=2.0):
+ """
+ Construct a circle mesh. The defaults create a circle with a
+ diameter of 2 Blender units, identical to the Blender UI.
+ @type verts: int
+ @param verts: optional number of vertices for the circle.
+ Value must be in the range [3,100].
+ @type diameter: float
+ @param diameter: optional diameter of the circle.
+ @rtype: L{BPy_Mesh<Mesh>}
+ @return: returns a mesh object.
+ """
+
+def Cylinder(verts=32, diameter=2.0, length=2.0):
+ """
+ Construct a cylindrical mesh (ends filled). The defaults create a
+ cylinder with a diameter of 2 Blender units and length 2 units,
+ identical to the Blender UI.
+ @type verts: int
+ @param verts: optional number of vertices in the cylinder's perimeter.
+ Value must be in the range [3,100].
+ @type diameter: float
+ @param diameter: optional diameter of the cylinder.
+ @type length: float
+ @param length: optional length of the cylinder.
+ @rtype: L{BPy_Mesh<Mesh>}
+ @return: returns a mesh object.
+ """
+
+def Tube(verts=32, diameter=2.0, length=2.0):
+ """
+ Construct a cylindrical mesh (ends not filled). The defaults create a
+ cylinder with a diameter of 2 Blender units and length 2 units, identical
+ to the Blender UI.
+ @type verts: int
+ @param verts: optional number of vertices in the tube's perimeter.
+ Value must be in the range [3,100].
+ @type diameter: float
+ @param diameter: optional diameter of the tube.
+ @type length: float
+ @param length: optional length of the tube.
+ @rtype: L{BPy_Mesh<Mesh>}
+ @return: returns a mesh object.
+ """
+
+def Cone(verts=32, diameter=2.0, length=2.0):
+ """
+ Construct a conic mesh (ends filled). The defaulte create a cone with a
+ base diameter of 2 Blender units and length 2 units, identical to
+ the Blender UI.
+ @type verts: int
+ @param verts: optional number of vertices in the cone's perimeter.
+ Value must be in the range [3,100].
+ @type diameter: float
+ @param diameter: optional diameter of the cone.
+ @type length: float
+ @param length: optional length of the cone.
+ @rtype: L{BPy_Mesh<Mesh>}
+ @return: returns a mesh object.
+ """
+
+def Grid(xres=32, yres=32, size=2.0):
+ """
+ Construct a grid mesh. The defaults create a 32 by 32 mesh of size 2
+ Blender units, identical to the Blender UI.
+ @type xres: int
+ @param xres: optional grid size in the x direction.
+ Value must be in the range [2,100].
+ @type yres: int
+ @param yres: optional grid size in the y direction.
+ Value must be in the range [2,100].
+ @type size: float
+ @param size: optional size of the grid.
+ @rtype: L{BPy_Mesh<Mesh>}
+ @return: returns a mesh object.
+ """
+
+def UVsphere(segments=32, rings=32, diameter=2.0):
+ """
+ Construct a UV sphere mesh. The defaults create a 32 by 32 sphere with
+ a diameter of 2 Blender units, identical to the Blender UI.
+ @type segments: int
+ @param segments: optional number of longitudinal divisions.
+ Value must be in the range [3,100].
+ @type rings: int
+ @param rings: optional number of latitudinal divisions.
+ Value must be in the range [3,100].
+ @type diameter: float
+ @param diameter: optional diameter of the sphere.
+ @rtype: L{BPy_Mesh<Mesh>}
+ @return: returns a mesh object.
+ """
+
+def Icosphere(subdivisions=2, diameter=2.0):
+ """
+ Construct a Icosphere mesh. The defaults create sphere with 2 subdivisions
+ and diameter of 2 Blender units, identical to the Blender UI.
+ @type subdivisions: int
+ @param subdivisions: optional number of subdivisions.
+ Value must be in the range [2,5].
+ @type diameter: float
+ @param diameter: optional diameter of the sphere.
+ @rtype: L{BPy_Mesh<Mesh>}
+ @return: returns a mesh object.
+ """
+
+def Monkey():
+ """
+ Construct a Suzanne mesh.
+ @rtype: L{BPy_Mesh<Mesh>}
+ @return: returns a mesh object.
+ """
+
diff --git a/source/blender/python/api2_2x/doc/Metaball.py b/source/blender/python/api2_2x/doc/Metaball.py
new file mode 100644
index 00000000000..69bcbedafae
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Metaball.py
@@ -0,0 +1,246 @@
+# Blender.Metaball module and the Metaball PyType metaball
+
+"""
+The Blender.Metaball submodule
+
+This module provides access to B{Metaball} data in Blender and the elements they contain.
+
+
+Example::
+ import Blender
+ mb = Blender.Metaball.New()
+ for i in xrange(20):
+ element= mb.elements.add()
+ element.co = Blender.Mathutils.Vector(i, 0, 0)
+ sce = Blender.Scene.GetCurrent()
+ sce.objects.new(mb)
+
+
+
+Example::
+ # Converts the active armature into metaballs
+ from Blender import *
+ def main():
+
+ scn= Scene.GetCurrent()
+ ob_arm= scn.objects.active
+ if not ob_arm or ob_arm.type!='Armature':
+ Draw.PupMenu('No Armature Selected')
+ return
+ arm= ob_arm.data
+
+ res= Draw.PupFloatInput('res:', 0.2, 0.05, 2.0)
+ if not res:
+ return
+
+ # Make a metaball
+ mb= Metaball.New()
+ mb.wiresize= res
+
+ # Link to the Scene
+ ob_mb = scn.objects.new(ob_mb)
+ ob_arm.sel= 0
+ ob_mb.setMatrix(ob_arm.matrixWorld)
+
+
+ meta_type= 0 # all elemts are ball type
+ meta_stiffness= 2.0 # Volume
+
+ for bone in arm.bones.values():
+ print bone
+
+ # Find out how many metaballs to add based on bone length, 4 min
+ length= bone.length
+ if length < res:
+ mballs= 4
+ else:
+ mballs= int(length/res)
+ if mballs < 4:
+ mballs = 4
+
+ print 'metaball count', mballs
+
+ # get the bone properties
+ head_rad= bone.headRadius
+ tail_rad= bone.tailRadius
+
+ head_loc= bone.head['ARMATURESPACE']
+ tail_loc= bone.tail['ARMATURESPACE']
+
+
+ for i in range(mballs):
+ f= float(i)
+
+ w1= f/mballs # weighting of this position on the bone for rad and loc
+ w2= 1-w1
+
+ loc= head_loc*w1 + tail_loc*w2
+ rad= (head_rad*w1 + tail_rad*w2) * 1.3
+
+ # Add the metaball
+ ml= mb.elements.add()
+ ml.co= loc
+ ml.radius= rad
+ ml.stiffness= meta_stiffness
+
+
+ Window.RedrawAll()
+
+ main()
+
+@type Types: readonly dictionary
+@var Types: MeteElement types.
+ - BALL
+ - TUBE
+ - PLANE
+ - ELIPSOID
+ - CUBE
+
+@type Update: readonly dictionary
+@var Update: MeteElement types.
+ - ALWAYS
+ - HALFRES
+ - FAST
+ - NEVER
+
+"""
+
+
+def New (name):
+ """
+ Creates a new Metaball.
+ @type name: string
+ @param name: The name of the metaball. If this parameter is not given (or not valid) blender will assign a name to the metaball.
+ @rtype: Blender Metaball
+ @return: The created Metaball.
+ """
+
+def Get (name):
+ """
+ Get the Metaball from Blender.
+ @type name: string
+ @param name: The name of the requested Metaball.
+ @rtype: Blender Metaball or a list of Blender Metaballs
+ @return: It depends on the 'name' parameter:
+ - (name): The Metaball with the given name;
+ - (): A list with all Metaballs in the current scene.
+ """
+
+class Metaball:
+ """
+ The Metaball object
+ ===================
+ This metaball gives access to generic data from all metaballs in Blender.
+ @ivar elements: Element iterator of MetaElemSeq type.
+ @type elements: MetaElemSeq
+ @ivar wiresize: display resolution.
+ Value clamped between 0.05 and 1.0.
+
+ A lower value results in more polygons.
+ @type wiresize: float
+ @ivar rendersize: render resolution.
+ Value clamped between 0.05 and 1.0.
+
+ A lower value results in more polygons.
+ @type rendersize: float
+ @ivar thresh: Threshold setting for this metaball.
+ Value clamped between 0.0 and 5.0.
+ @type thresh: float
+ @ivar materials: List of up to 16 Materials or None types
+ Only the first material of the mother-ball used at the moment.
+ @type materials: list
+ @ivar update: The update method to use for this metaball.
+ @type update: int
+ """
+
+ def __copy__():
+ """
+ Return a copy of this metaball object data.
+ @rtype: Metaball
+ @return: Metaball
+ """
+
+import id_generics
+Metaball.__doc__ += id_generics.attributes
+
+
+class MetaElemSeq:
+ """
+ The MetaElemSeq object
+ ======================
+ This object provides sequence and iterator access to the metaballs elements.
+ The elements accessed within this iterator "wraps" the actual metaball elements; changing any
+ of the elements's attributes will immediately change the data in the metaball.
+
+ This iterator is most like pythons 'set' type.
+ """
+
+ def add():
+ """
+ Append a new element to the metaball.
+ no arguments are taken, instead a new metaelement is
+ added to the metaball data and returned.
+ This new element can then be modified.
+
+ @return: a new meta element.
+ @rtype: Metaelement
+ """
+
+ def remove(element):
+ """
+ remove an element from the metaball data.
+
+ if the element is not a part of the metaball data, an error will be raised.
+
+ @return: None
+ @rtype: None
+ """
+
+ def __iter__():
+ """
+ Iterate over elements in this metaball.
+
+ @return: One of the metaelem in this metaball.
+ @rtype: Metaelem
+ """
+
+ def __len__():
+ """
+ Iterate over elements in this metaball.
+
+ @return: The number of elements in this metaball
+ @rtype: int
+ """
+
+class Metaelem:
+ """
+ The Metaelem object
+ ===================
+ This gives direct access to meta element data within a metaball.
+ @ivar type: The type of the metaball.
+ Values must be from L{Types}
+
+ Example::
+ from Blender import Metaball
+ mb= Metaball.Get('mb')
+ for el in mb.elements:
+ el.type= Metaball.Types.CUBE
+ @type type: int
+ @ivar co: The location of this element.
+ @type co: Vector
+ @ivar dims: Element dimensions.
+ Values clamped between 0 and 20 on all axies.
+ @type dims: Vector
+ @ivar quat: Element rotation.
+ @type quat: Quaternion
+ @ivar stiffness: Element stiffness.
+ Value clamped between 0 and 10.
+ @type stiffness: float
+ @ivar radius: Element radius.
+ Value clamped between 0 and 5000.
+ @type radius: float
+ @ivar negative: Element negative volume status.
+ @type negative: bool
+ @ivar hide: Element hidden status.
+ @type hide: bool
+ """
diff --git a/source/blender/python/api2_2x/doc/Metaballdoc.txt b/source/blender/python/api2_2x/doc/Metaballdoc.txt
new file mode 100644
index 00000000000..2c64a43571e
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Metaballdoc.txt
@@ -0,0 +1,58 @@
+METABALL Module documentation
+
+
+INTRODUCTION
+The metaball module effect allows you to access all the data of an metaball.
+A metaball consists of several (maybe only one) metaelems, which are spheres, interacting with each other, thus creating soft organic volumes.
+
+
+
+functions of the module :
+New(name) : creates ans returns a metaball object.
+Get(opt : name) : if the parameter name is given, returns the metaball object whose name has been passed, or Py_None, if no such metaball exists in the current scene. If no parameter is given, returns a list of all the metaballs in the current scene.
+get : alias for Get
+
+Metaball object member functions :
+
+getName()Return Metaball name
+setName(string newname) - Sets Metaball name
+getWiresize() - Return Metaball wire size
+setWiresize(float val) - Sets Metaball wire size
+getRendersize() - Return Metaball render size
+setRendersize(float newval- Sets Metaball render size
+getThresh()- Return Metaball threshold
+setThresh(float newval)- Sets Metaball threshold
+getBbox,- Return Metaball bounding box(a list of eight lists of three elements)
+getNMetaElems() Returns the number of Metaelems (basic spheres)
+getMetatype(int num_metaelem): returns the type of the metaelem number num_metaelem.
+0 : ball
+1 : tubex
+2 : tubey
+3 : tubez
+setMetatype(int num_metaelem,int newtype) : sets the type of the metaelem number num_metaelem.
+getMetadata(field_name,int num_metaelem) gets Metaball MetaData. Explained later.
+setMetadata(field_name,int num_metaelem,newval) sets Metaball MetaData. Explained later.
+getMetalay(int num_metaelem)
+getMetax(int num_metaelem) : gets the x coordinate of the metaelement
+setMetax(int num_metaelem,float newval) : sets the x coordinate of the metaelement
+getMetay(int num_metaelem) : gets the y coordinate of the metaelement
+setMetay(int num_metaelem,float newval) : sets the y coordinate of the metaelement
+getMetaz(int num_metaelem) : gets the z coordinate of the metaelement
+setMetaz(int num_metaelem,float newval) : sets the z coordinate of the metaelement
+getMetas(int num_metaelem) : gets the s coordinate of the metaelement
+setMetas(int num_metaelem,float newval) : sets the s coordinate of the metaelement
+getMetalen(int num_metaelem) : gets the length of the metaelement. Important for tubes.
+setMetalen(int num_metaelem,float newval) : sets the length of the metaelement. Important for tubes.
+getloc, - Gets Metaball loc values
+setloc, (f f f) - Sets Metaball loc values
+getrot, () - Gets Metaball rot values
+setrot,, (f f f) - Sets Metaball rot values
+getsize,() - Gets Metaball size values
+setsize,(f f f) - Sets Metaball size values
+
+
+
+
+The Object.attribute syntax
+
+The attribute can take these values : seed,nabla,sta,end,lifetime,normfac,obfac,randfac,texfac,randlife,vectsize,totpart,force,mult,life,child,mat,defvec. \ No newline at end of file
diff --git a/source/blender/python/api2_2x/doc/Modifier.py b/source/blender/python/api2_2x/doc/Modifier.py
new file mode 100644
index 00000000000..0c53f470b63
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Modifier.py
@@ -0,0 +1,225 @@
+# Blender.Modifier module and the Modifier PyType object
+
+"""
+The Blender.Modifier submodule
+
+B{New}:
+ - Supports the new Cast and Smooth modifiers.
+
+This module provides access to the Modifier Data in Blender.
+
+Example::
+ from Blender import *
+
+ ob = Object.Get('Cube') # retrieve an object
+ mods = ob.modifiers # get the object's modifiers
+ for mod in mods:
+ print mod,mod.name # print each modifier and its name
+ mod = mods.append(Modifier.Types.SUBSURF) # add a new subsurf modifier
+ mod[Modifier.Settings.LEVELS] = 3 # set subsurf subdivision levels to 3
+
+
+Example::
+ # Apply a lattice to an object and get the deformed object
+ # Uses an object called 'Cube' and a lattice called 'Lattice'
+
+ from Blender import *
+ ob_mesh= Object.Get('Cube')
+ ob_lattice= Object.Get('Lattice')
+
+ myMeshMod = ob_mesh.modifiers
+ mod = myMeshMod.append(Modifier.Types.LATTICE)
+ mod[Modifier.Settings.OBJECT] = ob_lattice
+
+ ob_mesh.makeDisplayList() # Needed to apply the modifier
+
+ Window.RedrawAll() # View the change
+
+ deformed_mesh= Mesh.New()
+ deformed_mesh.getFromObject(ob_mesh.name)
+
+
+ # Print the deformed locations
+ for v in deformed_mesh.verts:
+ print v.co
+
+
+
+@type Types: readonly dictionary
+@var Types: Constant Modifier dict used for L{ModSeq.append} to a
+ modifier sequence and comparing with L{Modifier.type}:
+ - ARMATURE - type value for Armature modifiers
+ - BOOLEAN - type value for Boolean modifiers
+ - BUILD - type value for Build modifiers
+ - CURVE - type value for Curve modifiers
+ - MIRROR - type value for Mirror modifiers
+ - DECIMATE - type value for Decimate modifiers
+ - LATTICE - type value for Lattice modifiers
+ - SUBSURF - type value for Subsurf modifiers
+ - WAVE - type value for Wave modifiers
+ - EDGESPLIT - type value for Edge Split modifiers
+ - DISPLACE - type value for Displace modifiers
+ - SMOOTH - type value for Smooth modifiers
+ - CAST - type value for Cast modifiers
+
+@type Settings: readonly dictionary
+@var Settings: Constant Modifier dict used for changing modifier settings.
+ - RENDER - Used for all modifiers (bool) If true, the modifier is enabled for rendering.
+ - REALTIME - Used for all modifiers (bool) If true, the modifier is enabled for interactive display.
+ - EDITMODE - Used for all modifiers (bool) If both REALTIME and EDITMODE are true, the modifier is enabled for interactive display while the object is in edit mode.
+ - ONCAGE - Used for all modifiers (bool) If true, the modifier is enabled for the editing cage during edit mode.
+
+ - OBJECT - Used for Armature, Lattice, Curve, Boolean and Array (Object)
+ - VERTGROUP - Used for Armature, Lattice, Curve, Smooth and Cast (String)
+ - LIMIT - Array and Mirror (float [0.0 - 1.0])
+ - FLAG - Mirror and Wave (int)
+ - COUNT - Decimator Polycount (readonly) and Array (int)
+ - LENGTH - Build [1.0-300000.0] and Array [0.0 - 10000.0] (float)
+ - FACTOR - Smooth [-10.0, 10.0] and Cast [-10.0, 10.0] (float)
+ - ENABLE_X = Smooth and Cast (bool, default: True)
+ - ENABLE_Y = Smooth and Cast (bool, default: True)
+ - ENABLE_Z = Smooth and Cast (bool, default: True)
+ - TYPES - Subsurf and Cast. For Subsurf it determines the subdivision algorithm - (int): 0 = Catmull-Clark; 1 = simple subdivision. For Cast it determines the shape to deform to = (int): 0 = Sphere; 1 = Cylinder; 2 = Cuboid
+
+ - LEVELS - Used for Subsurf only (int [0 - 6]). The number of subdivision levels used for interactive display.
+ - RENDLEVELS - Used for Subsurf only (int [0 - 6]). The number of subdivision levels used for rendering.
+ - OPTIMAL - Used for Subsurf only (bool). Enables Optimal Draw.
+ - UV - Used for Subsurf only (bool). Enables Subsurf UV.
+
+ - OBJECT_OFFSET - Used for Array only (Object)
+ - OBJECT_CURVE - Used for Array only (Curve Object)
+ - OFFSET_VEC - Used for Array only (3d Vector)
+ - SCALE_VEC - Used for Array only (3d Vector)
+ - MERGE_DIST - Used for Array only (float)
+
+ - ENVELOPES - Used for Armature only (bool)
+
+ - START - Used for Build only (int)
+ - SEED - Used for Build only (int)
+ - RANDOMIZE - Used for Build only (bool)
+
+ - AXIS_X - Used for Mirror only (bool)
+ - AXIS_Y - Used for Mirror only (bool)
+ - AXIS_Z - Used for Mirror only (bool)
+
+ - RATIO - Used for Decimate only (float [0.0 - 1.0])
+
+ - STARTX - Used for Wave only (float [-100.0 - 100.0])
+ - STARTY - Used for Wave only (float [-100.0 - 100.0])
+ - HEIGHT - Used for Wave only (float [-2.0 - 2.0])
+ - WIDTH - Used for Wave only (float [0.0 - 5.0])
+ - NARROW - Used for Wave only (float [0.0 - 10.0])
+ - SPEED - Used for Wave only (float [-2.0 - 2.0])
+ - DAMP - Used for Wave only (float [-MAXFRAME - MAXFRAME])
+ - LIFETIME - Used for Wave only (float [-MAXFRAME - MAXFRAME])
+ - TIMEOFFS - Used for Wave only (float [-MAXFRAME - MAXFRAME])
+
+ - OPERATION - Used for boolean only (int 0,1,2 : Intersect, Union, Difference)
+
+ - EDGESPLIT_ANGLE - Used for edge split only (float 0.0 - 180)
+ - EDGESPLIT_FROM_ANGLE - Used for edge split only, should the modifier use the edge angle (bool)
+ - EDGESPLIT_FROM_SHARP - Used for edge split only, should the modifier use the edge sharp flag (bool)
+
+ - UVLAYER - Used for Displace only
+ - MID_LEVEL - Used for Displace only (float [0.0, 1.0], default: 0.5)
+ - STRENGTH - Used for Displace only (float [-1000.0, 1000.0, default: 1.0)
+ - TEXTURE - Used for Displace only (string)
+ - MAPPING - Used for Displace only
+ - DIRECTION - Used for Displace only
+
+ - REPEAT - Used for Smooth only (int [0, 30], default: 1)
+
+ - RADIUS - Used for Cast only (float [0.0, 100.0], default: 0.0)
+ - SIZE - Used for Cast only (float [0.0, 100.0], default: 0.0)
+ - SIZE_FROM_RADIUS - Used for Cast only (bool, default: True)
+ - USE_OB_TRANSFORM - Used for Cast only (bool, default: False)
+"""
+
+class ModSeq:
+ """
+ The ModSeq object
+ =================
+ This object provides access to list of L{modifiers<Modifier.Modifier>} for a particular object.
+ Only accessed from L{Object.Object.modifiers}.
+ """
+
+ def __getitem__(index):
+ """
+ This operator returns one of the object's modifiers.
+ @type index: int
+ @return: an Modifier object
+ @rtype: Modifier
+ @raise KeyError: index was out of range
+ """
+
+ def __len__():
+ """
+ Returns the number of modifiers in the object's modifier stack.
+ @return: number of Modifiers
+ @rtype: int
+ """
+
+ def append(type):
+ """
+ Appends a new modifier to the end of the object's modifier stack.
+ @type type: a constant specifying the type of modifier to create. as from L{Types}
+ @rtype: Modifier
+ @return: the new Modifier
+ """
+
+ def remove(modifier):
+ """
+ Remove a modifier from this objects modifier sequence.
+ @type modifier: a modifier from this sequence to remove.
+ @note: Accessing attributes of the modifier after removing will raise an error.
+ """
+
+ def moveUp(modifier):
+ """
+ Moves the modifier up in the object's modifier stack.
+ @type modifier: a modifier from this sequence to remove.
+ @rtype: None
+ @raise RuntimeError: request to move above another modifier requiring
+ original data
+ @note: Accessing attributes of the modifier after removing will raise an error.
+ """
+
+ def moveDown(modifier):
+ """
+ Moves the modifier down in the object's modifier stack.
+ @type modifier: a modifier from this sequence to remove.
+ @rtype: None
+ @raise RuntimeError: request to move modifier beyond a non-deforming
+ modifier
+ @note: Accessing attributes of the modifier after removing will raise an error.
+ """
+
+class Modifier:
+ """
+ The Modifier object
+ ===================
+ This object provides access to a modifier for a particular object accessed
+ from L{ModSeq}.
+ @ivar name: The name of this modifier. 31 chars max.
+ @type name: string
+ @ivar type: The type of this modifier. Read-only. The returned value
+ matches the types in L{Types}.
+ @type type: int
+ """
+
+ def __getitem__(key):
+ """
+ This operator returns one of the modifier's data attributes.
+ @type key: value from modifier's L{Modifier.Settings} constant
+ @return: the requested data
+ @rtype: varies
+ @raise KeyError: the key does not exist for the modifier
+ """
+
+ def __setitem__(key):
+ """
+ This operator modifiers one of the modifier's data attributes.
+ @type key: value from modifier's L{Modifier.Settings} constant
+ @raise KeyError: the key does not exist for the modifier
+ """
+
diff --git a/source/blender/python/api2_2x/doc/NLA.py b/source/blender/python/api2_2x/doc/NLA.py
new file mode 100644
index 00000000000..adfcf77d965
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/NLA.py
@@ -0,0 +1,245 @@
+# Blender.Armature.NLA module and the Action PyType object
+
+"""
+The Blender.Armature.NLA submodule.
+
+NLA
+===
+
+This module provides access to B{Action} objects in Blender. Actions are a
+series of keyframes/Ipo curves that define the movement of a bone.
+Actions are linked to objects of type armature.
+
+@type Flags: readonly dictionary
+@var Flags: Constant dict used by the L{ActionStrip.flag} attribute.
+It is a bitmask and settings are ORed together.
+ - SELECT: action strip is selected in NLA window
+ - STRIDE_PATH: play action based on path position and stride.
+ - HOLD: continue displaying the last frame past the end of the strip
+ - ACTIVE: action strip is active in NLA window
+ - LOCK_ACTION: action start/end are automatically mapped to strip duration
+
+@type StrideAxes: readonly dictionary
+@var StrideAxes: Constant dict used by the L{ActionStrip.strideAxis} attribute.
+Values are STRIDEAXIS_X, STRIDEAXIS_Y, and STRIDEAXIS_Z.
+
+@type Modes: readonly dictionary
+@var Modes: Constant dict used by the L{ActionStrip.mode} attribute.
+Currently the only value is MODE_ADD.
+"""
+
+def NewAction (name = 'DefaultAction'):
+ """
+ Create a new Action object.
+ @type name: string
+ @param name: The Action name.
+ @rtype: PyAction
+ """
+
+def CopyAction (action):
+ """
+ Copy an action and it's keyframes
+ @type action: PyAction
+ @param action: The action to be copied.
+ @rtype: PyAction
+ @return: A copied action
+ """
+
+def GetActions ():
+ """
+ Get all actions and return them as a Key : Value Dictionary.
+ @rtype: Dictionary of PyActions
+ @return: All the actions in blender
+ """
+
+class Action:
+ """
+ The Action object
+ =================
+ This object gives access to Action-specific data in Blender.
+ """
+
+ def getName():
+ """
+ Get the name of this Action.
+ @rtype: string
+ """
+
+ def setName(name):
+ """
+ Set the name of this Action.
+ @type name: string
+ @param name: The new name
+ """
+
+ def setActive(object):
+ """
+ Set this action as the current action for an object.
+ @type object: PyObject
+ @param object: The object whose action is to be set
+ """
+
+ def getChannelIpo(channel):
+ """
+ Get the Ipo for the named channel in this action
+ @type channel: string
+ @param channel: The name of a channel in this action
+ @rtype: PyIpo or None
+ @return: the Ipo for the channel
+ """
+
+ def getFrameNumbers():
+ """
+ Gets the frame numbers at which a key was inserted into this action
+ @rtype: PyList
+ @return: a list of ints
+ """
+
+ def removeChannel(channel):
+ """
+ Remove a named channel from this action
+ @type channel: string
+ @param channel: The name of a channel in this action to be removed
+ """
+
+ def getAllChannelIpos():
+ """
+ Get the all the Ipos for this action
+ @rtype: Dictionary [channel : PyIpo or None]
+ @return: the Ipos for all the channels in the action
+ """
+
+ def getChannelNames():
+ """
+ Returns a list of channel names
+ @rtype: list
+ @return: the channel names that match bone and constraint names.
+ """
+
+ def renameChannel(nameFrom, nameTo):
+ """
+ rename an existing channel to a new name.
+
+ if the nameFrom channel dosnt exist or the nameTo exists, an error will be raised.
+ @return: None
+ """
+
+import id_generics
+Action.__doc__ += id_generics.attributes
+
+
+class ActionStrips:
+ """
+ The ActionStrips object
+ =======================
+ This object gives access to sequence of L{ActionStrip} objects for
+ a particular Object.
+ """
+
+ def __getitem__(index):
+ """
+ This operator returns one of the action strips in the stack.
+ @type index: int
+ @return: an action strip object
+ @rtype: ActionStrip
+ @raise KeyError: index was out of range
+ """
+
+ def __len__():
+ """
+ Returns the number of action strips for the object.
+ @return: number of action strips
+ @rtype: int
+ """
+
+ def append(action):
+ """
+ Appends a new action to the end of the action strip sequence.
+ @type action: L{Action<NLA.Action>}
+ @param action: the action to use in the action strip
+ @rtype: ActionStrip
+ @return: the new action strip
+ """
+
+ def remove(actionstrip):
+ """
+ Remove an action strip from this object's actionstrip sequence.
+ @type actionstrip: an action strip from this sequence to remove.
+ @note: Accessing attributes of the action strip after it is removed will
+ throw an exception.
+ """
+
+ def moveDown(actionstrip):
+ """
+ Move the action strip down in the object's actionstrip sequence.
+ @type actionstrip: an action strip from this sequence.
+ """
+
+ def moveUp(actionstrip):
+ """
+ Move the action strip up in the object's actionstrip sequence.
+ @type actionstrip: an action strip from this sequence.
+ """
+
+class ActionStrip:
+ """
+ The ActionStrip object
+ ======================
+ This object gives access to a particular action strip.
+ @ivar action: Action associated with the strip.
+ @type action: BPy Action object
+ @ivar stripStart: Starting frame of the strip.
+ @type stripStart: float
+ @ivar stripEnd: Ending frame of the strip.
+ @type stripEnd: float
+ @ivar actionStart: Starting frame of the action.
+ @type actionStart: float
+ @ivar actionEnd: Ending frame of the action.
+ @type actionEnd: float
+ @ivar repeat: The number of times to repeat the action range.
+ @type repeat: float
+ @ivar mode: Controls the ActionStrip mode. See L{Modes} for
+ valid values.
+ @type mode: int
+ @ivar flag: Controls various ActionStrip attributes. Values can be ORed.
+ See L{Flags} for valid values.
+ @type flag: int
+ @ivar strideAxis: Dominant axis for stride bone. See L{StrideAxes} for
+ valid values.
+ @type strideAxis: int
+ @ivar strideLength: Distance covered by one complete cycle of the action
+ specified in the Action Range.
+ @type strideLength: float
+ @ivar strideBone: Name of Bone used for stride
+ @type strideBone: string
+ @ivar groupTarget: Armature object within DupliGroup for local animation
+ @type groupTarget: object
+ @ivar blendIn: Number of frames of motion blending.
+ @type blendIn: float
+ @ivar blendOut: Number of frames of ease-out.
+ @type blendOut: float
+ """
+
+ def resetActionLimits():
+ """
+ Activates the functionality found in NLA Strip menu under "Reset Action
+ Start/End". This method restores the values of ActionStart and
+ ActionEnd to their defaults, usually the first and last frames within
+ an action that contain keys.
+ @rtype: None
+ """
+
+ def resetStripSize():
+ """
+ Activates the functionality found in NLA Strip menu under "Reset Strip
+ Size". This method resets the action strip size to its creation values.
+ @rtype: None
+ """
+
+ def snapToFrame():
+ """
+ Activates the functionality found in NLA Strip menu under "Snap to Frame".
+ This function snaps the ends of the action strip to the nearest whole
+ numbered frame.
+ @rtype: None
+ """
diff --git a/source/blender/python/api2_2x/doc/NMesh.py b/source/blender/python/api2_2x/doc/NMesh.py
new file mode 100644
index 00000000000..e6d779aebb8
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/NMesh.py
@@ -0,0 +1,823 @@
+# Blender.NMesh module and the NMesh PyType object
+
+"""
+The Blender.NMesh submodule.
+
+B{Deprecated}:
+This module is now maintained but not actively developed.
+
+Access to data such as properties, library, UVLayers and ColorLayers is not available
+further more, a mesh modified with NMesh will destroy inactive UV and Color layers
+so writing tools that use NMesh is discouraged.
+
+Use L{Mesh} instead.
+
+Mesh Data
+=========
+
+This module provides access to B{Mesh Data} objects in Blender.
+
+Example::
+
+ import Blender
+ from Blender import NMesh, Material, Window
+
+ editmode = Window.EditMode() # are we in edit mode? If so ...
+ if editmode: Window.EditMode(0) # leave edit mode before getting the mesh
+
+ me = NMesh.GetRaw("Plane") # get the mesh data called "Plane"
+
+ if not me.materials: # if there are no materials ...
+ newmat = Material.New() # create one ...
+ me.materials.append(newmat) # and append it to the mesh's list of mats
+
+ print me.materials # print the list of materials
+ mat = me.materials[0] # grab the first material in the list
+ mat.R = 1.0 # redefine its red component
+ for v in me.verts: # loop the list of vertices
+ v.co[0] *= 2.5 # multiply the coordinates
+ v.co[1] *= 5.0
+ v.co[2] *= 2.5
+ me.update() # update the real mesh in Blender
+
+ if editmode: Window.EditMode(1) # optional, just being nice
+
+@type Modes: readonly dictionary
+@type FaceFlags: readonly dictionary
+@type FaceModes: readonly dictionary
+@type FaceTranspModes: readonly dictionary
+@var Modes: The available mesh modes.
+ - NOVNORMALSFLIP - no flipping of vertex normals during render.
+ - TWOSIDED - double sided mesh.
+ - AUTOSMOOTH - turn auto smoothing of faces "on".
+@var FaceFlags: The available *texture face* (uv face select mode) selection
+ flags. Note: these refer to TexFace faces, available if nmesh.hasFaceUV()
+ returns true.
+ - SELECT - selected (deprecated after 2.43 release, use face.sel).
+ - HIDE - hidden (deprecated after 2.43 release, use face.sel).
+ - ACTIVE - the active face.
+@var FaceModes: The available *texture face* modes. Note: these are only
+ meaningful if nmesh.hasFaceUV() returns true, since in Blender this info is
+ stored at the TexFace (TexFace button in Edit Mesh buttons) structure.
+ - ALL - set all modes at once.
+ - BILLBOARD - always orient after camera.
+ - HALO - halo face, always point to camera.
+ - DYNAMIC - respond to collisions.
+ - INVISIBLE - invisible face.
+ - LIGHT - dynamic lighting.
+ - OBCOL - use object color instead of vertex colors.
+ - SHADOW - shadow type.
+ - SHAREDVERT - apparently unused in Blender.
+ - SHAREDCOL - shared vertex colors (per vertex).
+ - TEX - has texture image.
+ - TILES - uses tiled image.
+ - TWOSIDE - two-sided face.
+@var FaceTranspModes: The available face transparency modes. Note: these are
+ enumerated values (enums), they can't be combined (ANDed, ORed, etc) like a bit vector.
+ - SOLID - draw solid.
+ - ADD - add to background (halo).
+ - ALPHA - draw with transparency.
+ - SUB - subtract from background.
+@var EdgeFlags: The available edge flags.
+ - SELECT - selected.
+ - EDGEDRAW - edge is drawn out of edition mode.
+ - SEAM - edge is a seam for UV unwrapping
+ - FGON - edge is part of a F-Gon.
+"""
+
+def Col(col = [255, 255, 255, 255]):
+ """
+ Get a new mesh rgba color.
+ @type col: list
+ @param col: A list [red, green, blue, alpha] of integer values in [0, 255].
+ @rtype: NMCol
+ @return: A new NMCol (mesh rgba color) object.
+ """
+
+def Vert(x = 0, y = 0, z = 0):
+ """
+ Get a new vertex object.
+ @type x: float
+ @type y: float
+ @type z: float
+ @param x: The x coordinate of the vertex.
+ @param y: The y coordinate of the vertex.
+ @param z: The z coordinate of the vertex.
+ @rtype: NMVert
+ @return: A new NMVert object.
+ """
+
+def Face(vertexList = None):
+ """
+ Get a new face object.
+ @type vertexList: list
+ @param vertexList: A list of B{up to 4} NMVerts (mesh vertex
+ objects).
+ @rtype: NMFace
+ @return: A new NMFace object.
+ """
+
+def New(name = 'Mesh'):
+ """
+ Create a new mesh object.
+ @type name: string
+ @param name: An optional name for the created mesh.
+ rtype: NMesh
+ @return: A new (B{empty}) NMesh object.
+ """
+
+def GetRaw(name = None):
+ """
+ Get the mesh data object called I{name} from Blender.
+ @type name: string
+ @param name: The name of the mesh data object.
+ @rtype: NMesh
+ @return: It depends on the 'name' parameter:
+ - (name) - The NMesh wrapper of the mesh called I{name},
+ None if not found.
+ - () - A new (empty) NMesh object.
+ """
+
+def GetNames():
+ """
+ Get a list with the names of all available meshes in Blender.
+ @rtype: list of strings
+ @return: a list of mesh names.
+ @note: to get actual mesh data, pass a mesh name to L{GetRaw}.
+ """
+
+def GetRawFromObject(name):
+ """
+ Get the raw mesh data object from the Object in Blender called I{name}.\n
+ Note: The mesh coordinates are in local space, not the world space of its Object.\n
+ For world space vertex coordinates, each vertex location must be multiplied by the object's 4x4 matrix.
+ This function support all the geometry based objects: Mesh, Text, Surface, Curve, Meta.
+ @type name: string
+ @param name: The name of an Object.
+ @rtype: NMesh
+ @return: The NMesh wrapper of the mesh data from the Object called I{name}.
+ @note: For "subsurfed" meshes, it's the B{display} level of subdivision that
+ matters, the rendering one is only processed at the rendering pre-stage
+ and is not available for scripts. This is not a problem at all, since
+ you can get and set the subdivision levels via scripting, too (see
+ L{NMesh.NMesh.getSubDivLevels}, L{NMesh.NMesh.setSubDivLevels}).
+ @note: Meshes extracted from curve based objects (Font/2D filled curves)
+ contain both the filled surfaces and the outlines of the shapes.
+ @warn: This function gets I{deformed} mesh data, already modified for
+ displaying (think "display list"). It also doesn't let you overwrite the
+ original mesh in Blender, so if you try to update it, a new mesh will
+ be created.
+ @warn: For Meta Object's, this function will only return a NMesh with some geometry
+ when called on the base element (the one with the shortest name).
+ """
+
+def PutRaw(nmesh, name = None, recalc_normals = 1, store_edges = 0):
+ """
+ Put a BPython NMesh object as a mesh data object in Blender.
+ @note: if there is already a mesh with the given 'name', its contents are
+ freed and the new data is put in it. Also, if this mesh is not linked to any
+ object, a new object for it is created. Reminder: in Blender an object is
+ composed of the base object and linked object data (mesh, metaball, camera,
+ etc. etc).
+ @type nmesh: NMesh
+ @type name: string
+ @type recalc_normals: int
+ @type store_edges: int
+ @param name: The name of the mesh data object in Blender which will receive
+ this nmesh data. It can be an existing mesh data object or a new one.
+ @param recalc_normals: If non-zero, the vertex normals for the mesh will
+ be recalculated.
+ @param store_edges: deprecated, edges are always stored now.
+ @rtype: None or Object
+ @return: It depends on the 'name' parameter:
+ - I{name} refers to an existing mesh data obj already linked to an
+ object: return None.
+ - I{name} refers to a new mesh data obj or an unlinked (no users) one:
+ return the created Blender Object wrapper.
+ """
+
+class NMCol:
+ """
+ The NMCol object
+ ================
+ This object is a list of ints: [r, g, b, a] representing an
+ rgba color.
+ @ivar r: The Red component in [0, 255].
+ @ivar g: The Green component in [0, 255].
+ @ivar b: The Blue component in [0, 255].
+ @ivar a: The Alpha (transparency) component in [0, 255].
+ """
+
+class NMVert:
+ """
+ The NMVert object
+ =================
+ This object holds mesh vertex data.
+ @type co: 3D Vector object. (WRAPPED DATA)
+ @ivar co: The vertex coordinates (x, y, z).
+ @type no: 3D Vector object. (unit length) (WRAPPED DATA)
+ @ivar no: The vertex normal vector (x, y, z).
+ @type uvco: 3D Vector object. (WRAPPED DATA)
+ @ivar uvco: The vertex texture "sticky" coordinates. The Z value of the Vector is ignored.
+ @type index: int
+ @ivar index: The vertex index, if owned by a mesh.
+ @type sel: int
+ @ivar sel: The selection state (selected:1, unselected:0) of this vertex.\n
+ Note: An NMesh will return the selection state of the mesh when EditMod was last exited. A python script operating in EditMode must exit edit mode, before getting the current selection state of the mesh.
+ @warn: There are two kinds of uv texture coordinates in Blender: per vertex
+ ("sticky") and per face vertex (uv in L{NMFace}). In the first, there's
+ only one uv pair of coordinates for each vertex in the mesh. In the
+ second, for each face it belongs to, a vertex can have different uv
+ coordinates. This makes the per face option more flexible, since two
+ adjacent faces won't have to be mapped to a continuous region in an image:
+ each face can be independently mapped to any part of its texture.
+ """
+
+class NMEdge:
+ """
+ The NMEdge object
+ =================
+ This object holds mesh edge data.
+ @type v1: NMVert
+ @ivar v1: The first vertex of the edge.
+ @type v2: NMVert
+ @ivar v2: The second vertex of the edge.
+ @type crease: int
+ @ivar crease: The crease value of the edge. It is in the range [0,255].
+ @type flag: int
+ @ivar flag: The bitmask describing edge properties. See L{NMesh.EdgeFlags<EdgeFlags>}.
+ """
+
+class NMFace:
+ """
+ The NMFace object
+ =================
+ This object holds mesh face data.
+
+ Example::
+ import Blender
+ from Blender import NMesh, Window
+
+ in_emode = Window.EditMode()
+ if in_emode: Window.EditMode(0)
+
+ me = NMesh.GetRaw("Mesh")
+ faces = me.faces
+
+ ## Example for editmode faces selection:
+ selected_faces = []
+ for f in faces:
+ if f.sel:
+ selected_faces.append(f)
+ # ... unselect selected and select all the others:
+ for f in faces:
+ f.sel = 1 - f.sel # 1 becomes 0, 0 becomes 1
+
+ ## Example for uv textured faces selection:
+ selected_faces = []
+ SEL = NMesh.FaceFlags['SELECT']
+ # get selected faces:
+ for f in faces:
+ if f.flag & SEL:
+ selected_faces.append(f)
+ # ... unselect selected and select all the others:
+ for f in faces:
+ if f.flag & SEL:
+ f.flag &=~SEL # unselect these
+ else: f.flag |= SEL # and select these
+
+ me.update()
+ if in_emode: Window.EditMode(1)
+ Blender.Redraw()
+
+ @type v: list
+ @ivar v: The list of face vertices (B{up to 4}).
+ @type sel: bool
+ @ivar sel: The selection state (1: selected, 0: unselected) of this NMesh's
+ faces *in edit mode*. This is not the same as the selection state of
+ the textured faces (see L{flag}).
+ @type hide: bool
+ @ivar hide: The visibility state (1: hidden, 0: visible) of this NMesh's
+ faces *in edit mode*. This is not the same as the visibility state of
+ the textured faces (see L{flag}).
+ @ivar col: The list of vertex colors.
+ @ivar mat: Same as I{materialIndex} below.
+ @ivar materialIndex: The index of this face's material in its NMesh materials
+ list.
+ @ivar smooth: If non-zero, the vertex normals are averaged to make this
+ face look smooth.
+ @ivar image: The Image used as a texture for this face.
+ @ivar mode: The display mode (see L{Mesh.FaceModes<FaceModes>})
+ @ivar flag: Bit vector specifying selection / visibility flags for uv
+ textured faces (visible in Face Select mode, see
+ L{NMesh.FaceFlags<FaceFlags>}).
+ @ivar transp: Transparency mode bit vector
+ (see L{NMesh.FaceTranspModes<FaceTranspModes>}).
+ @ivar uv: List of per-face UV coordinates: [(u0, v0), (u1, v1), ...].
+ @ivar normal: (or just B{no}) The normal vector for this face: [x,y,z].
+ @note: there are normal faces and textured faces in Blender, both currently
+ with their own selection and visibility states, due to a mix of old and new
+ code. To (un)select or (un)hide normal faces (visible in editmode), use
+ L{sel} and L{hide} variables. For textured faces (Face Select
+ mode in Blender) use the old L{flag} bitflag. Also check the
+ example above and note L{Window.EditMode}.
+ @note: Assigning uv textures to mesh faces in Blender works like this:
+ 1. Select your mesh.
+ 2. Enter face select mode (press f) and select at least some face(s).
+ 3. In the UV/Image Editor window, load / select an image.
+ 4. Play in both windows (better split the screen to see both at the same
+ time) until the uv coordinates are where you want them. Hint: in the
+ 3d window, the 'u' key opens a menu of default uv choices and the 'r'
+ key lets you rotate the uv coordinates.
+ 5. Leave face select mode (press f).
+ """
+
+ def append(vertex):
+ """
+ Append a vertex to this face's vertex list.
+ @type vertex: NMVert
+ @param vertex: An NMVert object.
+ """
+
+from IDProp import IDGroup, IDArray
+class NMesh:
+ """
+ The NMesh Data object
+ =====================
+ This object gives access to mesh data in Blender. We refer to mesh as the
+ object in Blender and NMesh as its Python counterpart.
+ @ivar properties: Returns an L{IDGroup<IDProp.IDGroup>} reference to this
+ object's ID Properties.
+ @type properties: L{IDGroup<IDProp.IDGroup>}
+ @ivar name: The NMesh name. It's common to use this field to store extra
+ data about the mesh (to be exported to another program, for example).
+ @ivar materials: The list of materials used by this NMesh. See
+ L{getMaterials} for important details.
+ @ivar verts: The list of NMesh vertices (NMVerts).
+ @ivar users: The number of Objects using (linked to) this mesh.
+ @ivar faces: The list of NMesh faces (NMFaces).
+ @ivar edges: A list of L{NMEdge} edges.
+ @ivar mode: The mode flags for this mesh. See L{setMode}.
+ @ivar subDivLevels: The [display, rendering] subdivision levels in [1, 6].
+ @ivar maxSmoothAngle: The max angle for auto smoothing. See L{setMode}.
+ @cvar key: The L{Key.Key} object attached to this mesh, if any.
+ """
+
+ def addEdge(v1, v2):
+ """
+ Create an edge between two vertices.
+ If an edge already exists between those vertices, it is returned.
+ Created edge is automatically added to edges list.
+ You can only call this method if mesh has edge data.
+ @note: In Blender only zero or one edge can link two vertices.
+ @type v1: NMVert
+ @param v1: the first vertex of the edge.
+ @type v2: NMVert
+ @param v2: the second vertex of the edge.
+ @rtype: NMEdge
+ @return: The created or already existing edge.
+ """
+
+ def findEdge(v1, v2):
+ """
+ Try to find an edge between two vertices.
+ If no edge exists between v1 and v2, None is returned.
+ You can only call this method if mesh has edge data.
+ @type v1: NMVert
+ @param v1: the first vertex of the edge.
+ @type v2: NMVert
+ @param v2: the second vertex of the edge.
+ @rtype: NMEdge
+ @return: The found edge. None if no edge was found.
+ """
+
+ def removeEdge(v1, v2):
+ """
+ Remove an edge between two vertices.
+ All faces using this edge are removed from faces list.
+ You can only call this method if mesh has edge data.
+ @type v1: NMVert
+ @param v1: the first vertex of the edge.
+ @type v2: NMVert
+ @param v2: the second vertex of the edge.
+ """
+
+ def addFace(face):
+ """
+ Add a face to face list and add to edge list (if edge data exists) necessary edges.
+ @type face: NMFace
+ @param face: the face to add to the mesh.
+ @rtype: list of NMEdge
+ @return: If mesh has edge data, return the list of face edges.
+ """
+
+ def removeFace(face):
+ """
+ Remove a face for face list and remove edges no more used by any other face (if edge data exists).
+ @type face: NMFace
+ @param face: the face to add to the mesh.
+ """
+
+ def addMaterial(material):
+ """
+ Add a new material to this NMesh's list of materials. This method is the
+ slower but safer way to add materials, since it checks if the argument
+ given is really a material, imposes a limit of 16 materials and only adds
+ the material if it wasn't already in the list.
+ @type material: Blender Material
+ @param material: A Blender Material.
+ """
+
+ def getMaterials(what = -1):
+ """
+ Get this NMesh's list of materials.
+ @type what: int
+ @param what: determines the list's contents:
+ - -1: return the current NMesh's list;
+ - 0: retrieve a fresh list from the Blender mesh -- eventual
+ modifications made by the script not included, unless
+ L{update} is called before this method;
+ - 1: like 0, but empty slots are not ignored, they are returned as
+ None's.
+ @note: what >= 0 also updates nmesh.materials attribute.
+ @rtype: list of materials
+ @return: the requested list of materials.
+ @note: if a user goes to the material buttons window and removes some
+ mesh's link to a material, that material slot becomes empty.
+ Previously such materials were ignored.
+ @note: L{Object.colbits<Object.Object.colbits>} needs to be set correctly
+ for each object in order for these materials to be used instead of
+ the object's materials.
+ """
+
+ def setMaterials(matlist):
+ """
+ Set this NMesh's list of materials. This method checks the consistency of
+ the passed list: must only have materials or None's and can't contain more
+ than 16 entries.
+ @type matlist: list of materials
+ @param matlist: a list with materials, None's also accepted (they become
+ empty material slots in Blender.
+ @note: L{Object.colbits<Object.Object.colbits>} needs to be set correctly
+ for each object in order for these materials to be used instead of
+ the object's materials.
+ """
+
+ def hasVertexColours(flag = None):
+ """
+ Get (and optionally set) if this NMesh has vertex colors.
+ @type flag: int
+ @param flag: If given and non-zero, the "vertex color" flag for this NMesh
+ is turned I{on}.
+ @rtype: bool
+ @return: The current value of the "vertex color" flag.
+ @warn: If a mesh has both vertex colors and textured faces, this function
+ will return False. This is due to the way Blender deals internally with
+ the vertex colors array (if there are textured faces, it is copied to
+ the textured face structure and the original array is freed/deleted).
+ If you want to know if a mesh has both textured faces and vertex
+ colors, set *in Blender* the "VCol Paint" flag for each material that
+ covers an area that was also vertex painted and then check in your
+ Python script if that material flag is set. Of course also tell others
+ who use your script to do the same. The "VCol Paint" material mode flag
+ is the way to tell Blender itself to render with vertex colors, too, so
+ it's a natural solution.
+ """
+
+ def hasFaceUV(flag = None):
+ """
+ Get (and optionally set) if this NMesh has UV-mapped textured faces.
+ @type flag: int
+ @param flag: If given and non-zero, the "textured faces" flag for this
+ NMesh is turned I{on}.
+ @rtype: bool
+ @return: The current value of the "textured faces" flag.
+ """
+
+ def hasVertexUV(flag = None):
+ """
+ Get (and optionally set) the "sticky" flag that controls if a mesh has
+ per vertex UV coordinates.
+ @type flag: int
+ @param flag: If given and non-zero, the "sticky" flag for this NMesh is
+ turned I{on}.
+ @rtype: bool
+ @return: The current value of the "sticky" flag.
+ """
+
+ def getActiveFace():
+ """
+ Get the index of the active face.
+ @rtype: int
+ @return: The index of the active face.
+ """
+
+ def getSelectedFaces(flag = None):
+ """
+ Get list of selected faces.
+ @type flag: int
+ @param flag: If given and non-zero, the list will have indices instead of
+ the NMFace objects themselves.
+ @rtype: list
+ @return: It depends on the I{flag} parameter:
+ - if None or zero: List of NMFace objects.
+ - if non-zero: List of indices to NMFace objects.
+ @warn: this method exists to speed up retrieving of selected faces from
+ the actual mesh in Blender. So, if you make changes to the nmesh, you
+ need to L{update} it before using this method.
+ """
+
+ def getVertexInfluences(index):
+ """
+ Get influences of bones in a specific vertex.
+ @type index: int
+ @param index: The index of a vertex.
+ @rtype: list of lists
+ @return: List of pairs (name, weight), where name is the bone name (string)
+ and its weight is a float value.
+ """
+
+ def getKey():
+ """
+ Get the Key object representing the Vertex Keys (absolute or
+ relative) assigned to this mesh.
+ @rtype: L{Key.Key} object or None
+ """
+
+ def insertKey(frame = None, type = 'relative'):
+ """
+ Insert a mesh key at the given frame. Remember to L{update} the nmesh
+ before doing this, or changes in the vertices won't be updated in the
+ Blender mesh.
+ @type frame: int
+ @type type: string
+ @param frame: The Scene frame where the mesh key should be inserted. If
+ None, the current frame is used.
+ @param type: The mesh key type: 'relative' or 'absolute'. This is only
+ relevant on the first call to insertKey for each nmesh (and after all
+ keys were removed with L{removeAllKeys}, of course).
+ @warn: This and L{removeAllKeys} were included in this release only to
+ make accessing vertex keys possible, but may not be a proper solution
+ and may be substituted by something better later. For example, it
+ seems that 'frame' should be kept in the range [1, 100]
+ (the curves can be manually tweaked in the Ipo Curve Editor window in
+ Blender itself later).
+ """
+
+ def removeAllKeys():
+ """
+ Remove all mesh keys stored in this mesh.
+ @rtype: bool
+ @return: True if successful or False if this NMesh wasn't linked to a real
+ Blender Mesh yet (or was, but the Mesh had no keys).
+ @warn: Currently the mesh keys from meshes that are grabbed with
+ NMesh.GetRaw() or .GetRawFromObject() are preserved, so if you want to
+ clear them or don't want them at all, remember to call this method. Of
+ course NMeshes created with NMesh.New() don't have mesh keys until you
+ add them.
+ """
+
+ def update(recalc_normals = 0, store_edges = 0, vertex_shade = 0):
+ """
+ Update the mesh in Blender. The changes made are put back to the mesh in
+ Blender, if available, or put in a newly created mesh if this NMesh wasn't
+ already linked to one.
+ @type recalc_normals: int (bool)
+ @param recalc_normals: if nonzero the vertex normals are recalculated.
+ @type store_edges: int (bool)
+ @param store_edges: deprecated, edges are always stored now.
+ @type vertex_shade: int (bool)
+ @param vertex_shade: if nonzero vertices are colored based on the
+ current lighting setup, like when there are no vertex colors and no
+ textured faces and a user enters Vertex Paint Mode in Blender (only
+ lamps in visible layers account). To use this functionality, be out of
+ edit mode or else an error will be returned.
+ @warn: edit mesh and normal mesh are two different structures in Blender,
+ synchronized upon leaving or entering edit mode. Always remember to
+ leave edit mode (L{Window.EditMode}) before calling this update
+ method, or your changes will be lost. Even better: for the same reason
+ programmers should leave EditMode B{before} getting a mesh, or changes
+ made to the editmesh in Blender may not be visible to your script
+ (check the example at the top of NMesh module doc).
+ @warn: unlike the L{PutRaw} function, this method doesn't check validity of
+ vertex, face and material lists, because it is meant to be as fast as
+ possible (and already performs many tasks). So programmers should make
+ sure they only feed proper data to the nmesh -- a good general
+ recommendation, of course. It's also trivial to write code to check
+ all data before updating, for example by comparing each item's type
+ with the actual L{Types}, if you need to.
+ @note: this method also redraws the 3d view and -- if 'vertex_shade' is
+ nonzero -- the edit buttons window.
+ @note: if your mesh disappears after it's updated, try
+ L{Object.Object.makeDisplayList}. 'Subsurf' meshes (see L{getMode},
+ L{setMode}) need their display lists updated, too.
+ """
+
+ def transform(matrix, recalc_normals = False):
+ """
+ Transforms the mesh by the specified 4x4 matrix, as returned by
+ L{Object.Object.getMatrix}, though this will work with any invertible 4x4
+ matrix type. Ideal usage for this is exporting to an external file where
+ global vertex locations are required for each object.
+ Sometimes external renderers or file formats do not use vertex normals.
+ In this case, you can skip transforming the vertex normals by leaving
+ the optional parameter recalc_normals as False or 0 ( the default value ).
+
+ Example::
+ # This script outputs deformed meshes worldspace vertex locations
+ # for a selected object
+ import Blender
+ from Blender import NMesh, Object
+
+ ob = Object.GetSelected()[0] # Get the first selected object
+ me = NMesh.GetRawFromObject(ob.name) # Get the objects deformed mesh data
+ me.transform(ob.matrix)
+
+ for v in me.verts:
+ print 'worldspace vert', v.co
+
+ @type matrix: Py_Matrix
+ @param matrix: 4x4 Matrix which can contain location, scale and rotation.
+ @type recalc_normals: int (bool)
+ @param recalc_normals: if True or 1, transform normals as well as vertex coordinates.
+ @warn: if you call this method and later L{update} the mesh, the new
+ vertex positions will be passed back to Blender, but the object
+ matrix of each object linked to this mesh won't be automatically
+ updated. You need to set the object transformations (rotation,
+ translation and scaling) to identities, then, or the mesh data will
+ be changed ("transformed twice").
+ """
+
+ def getMode():
+ """
+ Get this mesh's mode flags.
+ @rtype: int
+ @return: ORed value. See L{Modes}.
+ """
+
+ def setMode(m=None, m1=None, m2=None):
+ """
+ Set the mode flags for this mesh. Given mode strings turn the mode "on".
+ Modes not passed in are turned "off", so setMode() (without arguments)
+ unsets all mode flags.
+ @type m: string or int (bitflag)
+ @param m: mode string or int. An int (see L{Modes}) or from none to 3
+ strings can be given:
+ - "NoVNormalsFlip"
+ - "TwoSided"
+ - "AutoSmooth"
+ """
+
+ def addVertGroup(group):
+ """
+ Add a named and empty vertex (deform) group to the object this nmesh is
+ linked to. If this nmesh was newly created or accessed with GetRaw, it must
+ first be linked to an object (with object.link or NMesh.PutRaw) so the
+ method knows which object to update.\n
+ This is because vertex groups in Blender are stored in I{the object} --
+ not in the mesh, which may be linked to more than one object. For this
+ reason, it's better to use "mesh = object.getData()" than
+ "mesh = NMesh.GetRaw(meshName)" to access an existing mesh.
+ @type group: string
+ @param group: the name for the new group.
+ """
+
+ def removeVertGroup(group):
+ """
+ Remove a named vertex (deform) group from the object linked to this nmesh.
+ All vertices assigned to the group will be removed (just from the group,
+ not deleted from the mesh), if any. If this nmesh was newly created, it
+ must first be linked to an object (read the comment in L{addVertGroup} for
+ more info).
+ @type group: string
+ @param group: the name of a vertex group.
+ """
+
+ def assignVertsToGroup(group, vertList, weight, assignmode = 'replace'):
+ """
+ Adds an array (a python list) of vertex points to a named vertex group
+ associated with a mesh. The vertex list is a list of vertex indices from
+ the mesh. You should assign vertex points to groups only when the mesh has
+ all its vertex points added to it and is already linked to an object.
+
+ I{B{Example:}}
+ The example here adds a new set of vertex indices to a sphere primitive::
+ import Blender
+ sphere = Blender.Object.Get('Sphere')
+ mesh = sphere.getData()
+ mesh.addVertGroup('firstGroup')
+ vertList = []
+ for x in range(300):
+ if x % 3 == 0:
+ vertList.append(x)
+ mesh.assignVertsToGroup('firstGroup', vertList, 0.5, 'add')
+
+ @type group: string
+ @param group: the name of the group.
+ @type vertList: list of ints
+ @param vertList: a list of vertex indices.
+ @type weight: float
+ @param weight: the deform weight for (which means: the amount of influence
+ the group has over) the given vertices. It should be in the range
+ [0.0, 1.0]. If weight <= 0, the given vertices are removed from the
+ group. If weight > 1, it is clamped.
+ @type assignmode: string
+ @param assignmode: Three choices:
+ - 'add'
+ - 'subtract'
+ - 'replace'\n
+
+ 'B{add}': if the vertex in the list is not assigned to the group
+ already, this creates a new association between this vertex and the
+ group with the weight specified, otherwise the weight given is added to
+ the current weight of an existing association between the vertex and
+ group.\n
+ 'B{subtract}' will attempt to subtract the weight passed from a vertex
+ already associated with a group, else it does nothing.\n
+ 'B{replace}' attempts to replace a weight with the new weight value
+ for an already associated vertex/group, else it does nothing.
+ """
+
+ def removeVertsFromGroup(group, vertList = None):
+ """
+ Remove a list of vertices from the given group. If this nmesh was newly
+ created, it must first be linked to an object (check L{addVertGroup}).
+ @type group: string
+ @param group: the name of a vertex group
+ @type vertList: list of ints
+ @param vertList: a list of vertex indices to be removed from the given
+ 'group'. If None, all vertices are removed -- the group is emptied.
+ """
+
+ def getVertsFromGroup(group, weightsFlag = 0, vertList = None):
+ """
+ Return a list of vertex indices associated with the passed group. This
+ method can be used to test whether a vertex index is part of a group and
+ if so, what its weight is.
+
+ I{B{Example:}}
+ Append this to the example from L{assignVertsToGroup}::
+ # ...
+ print "Vertex indices from group %s :" % groupName
+ print mesh.getVertsFromGroup('firstGroup')
+ print "Again, with weights:"
+ print mesh.getVertsFromGroup('firstGroup',1)
+ print "Again, with weights and restricted to the given indices:"
+ print mesh.getVertsFromGroup('firstGroup',1,[1,2,3,4,5,6])
+
+ @type group: string
+ @param group: the group name.
+ @type weightsFlag: bool
+ @param weightsFlag: if 1, the weight is returned along with the index.
+ @type vertList: list of ints
+ @param vertList: if given, only those vertex points that are both in the
+ list and group passed in are returned.
+ """
+
+ def renameVertGroup(groupName, newName):
+ """
+ Renames a vertex group.
+ @type groupName: string
+ @param groupName: the vertex group name to be renamed.
+ @type newName: string
+ @param newName: the name to replace the old name.
+ """
+
+ def getVertGroupNames():
+ """
+ Return a list of all vertex group names.
+ @rtype: list of strings
+ @return: returns a list of strings representing all vertex group
+ associated with the mesh's object
+ """
+
+ def getMaxSmoothAngle():
+ """
+ Get the max angle for auto smoothing.
+ Note: This will only affect smoothing generated at render time.
+ Smoothing can also be set per face which is visible in Blenders 3D View.
+ @return: The value in degrees.
+ """
+
+ def setMaxSmoothAngle(angle):
+ """
+ Set the max angle for auto smoothing.
+ @type angle: int
+ @param angle: The new value in degrees -- it's clamped to [1, 80].
+ """
+
+ def getSubDivLevels():
+ """
+ Get the mesh subdivision levels for realtime display and rendering.
+ @return: list of ints: [display, render].
+ """
+
+ def setSubDivLevels(subdiv):
+ """
+ Set the mesh subdivision levels for realtime display and rendering.
+ @type subdiv: list of 2 ints
+ @param subdiv: new subdiv levels: [display, render]. Both are clamped to
+ lie in the range [1, 6].
+ """
+
+
diff --git a/source/blender/python/api2_2x/doc/Noise.py b/source/blender/python/api2_2x/doc/Noise.py
new file mode 100644
index 00000000000..5a246031fd0
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Noise.py
@@ -0,0 +1,300 @@
+# Blender.Noise submodule
+
+"""
+The Blender.Noise submodule.
+
+Noise and Turbulence
+====================
+
+This module can be used to generate noise of various types. This can be used
+for terrain generation, to create textures, make animations more 'animated',
+object deformation, etc. As an example, this code segment when scriptlinked
+to a framechanged event, will make the camera sway randomly about, by changing
+parameters this can look like anything from an earthquake to a very nervous or
+maybe even drunk cameraman... (the camera needs an ipo with at least one Loc &
+Rot key for this to work!):
+
+Example::
+ from Blender import Get, Scene, Noise
+ ####################################################
+ # This controls jitter speed
+ sl = 0.025
+ # This controls the amount of position jitter
+ sp = 0.1
+ # This controls the amount of rotation jitter
+ sr = 0.25
+ ####################################################
+
+ time = Get('curtime')
+ ob = Scene.GetCurrent().getCurrentCamera()
+ ps = (sl*time, sl*time, sl*time)
+ # To add jitter only when the camera moves, use this next line instead
+ #ps = (sl*ob.LocX, sl*ob.LocY, sl*ob.LocZ)
+ rv = Noise.vTurbulence(ps, 3, 0, Noise.NoiseTypes.NEWPERLIN)
+ ob.dloc = (sp*rv[0], sp*rv[1], sp*rv[2])
+ ob.drot = (sr*rv[0], sr*rv[1], sr*rv[2])
+
+@type NoiseTypes: readonly dictionary
+@var NoiseTypes: The available noise types.
+ - BLENDER
+ - STDPERLIN
+ - NEWPERLIN
+ - VORONOI_F1
+ - VORONOI_F2
+ - VORONOI_F3
+ - VORONOI_F4
+ - VORONOI_F2F1
+ - VORONOI_CRACKLE
+ - CELLNOISE
+
+@type DistanceMetrics: readonly dictionary
+@var DistanceMetrics: The available distance metrics values for Voronoi.
+ - DISTANCE
+ - DISTANCE_SQUARED
+ - MANHATTAN
+ - CHEBYCHEV
+ - MINKOVSKY_HALF
+ - MINKOVSKY_FOUR
+ - MINKOVISKY
+"""
+
+NoiseTypes = {'BLENDER':0, 'STDPERLIN':1}
+
+DistanceMetrics = {'DISTANCE':0}
+
+def random ():
+ """
+ Returns a random floating point number."
+ @rtype: float
+ @return: a random number in [0, 1).
+ """
+
+def randuvec ():
+ """
+ Returns a random unit vector.
+ @rtype: 3-float list
+ @return: a list of three floats.
+ """
+
+def setRandomSeed (seed):
+ """
+ Initializes the random number generator.
+ @type seed: int
+ @param seed: the seed for the random number generator. If seed = 0, the
+ current time will be used as seed, instead.
+ """
+
+def noise (xyz, type = NoiseTypes['STDPERLIN']):
+ """
+ Returns general noise of the optional specified type.
+ @type xyz: tuple of 3 floats
+ @param xyz: (x,y,z) float values.
+ @type type: int
+ @param type: the type of noise to return. See L{NoiseTypes}.
+ @rtype: float
+ @return: the generated noise value.
+ """
+
+def vNoise (xyz, type = NoiseTypes['STDPERLIN']):
+ """
+ Returns noise vector of the optional specified type.
+ @type xyz: tuple of 3 floats
+ @param xyz: (x,y,z) float values.
+ @type type: int
+ @param type: the type of noise to return. See L{NoiseTypes}.
+ @rtype: 3-float list
+ @return: the generated noise vector.
+ """
+
+def turbulence (xyz, octaves, hard, basis = NoiseTypes['STDPERLIN'],
+ ampscale = 0.5, freqscale = 2.0):
+ """
+ Returns general turbulence value using the optional specified noise 'basis'
+ function.
+ @type xyz: 3-float tuple
+ @param xyz: (x,y,z) float values.
+ @type octaves: int
+ @param octaves: number of noise values added.
+ @type hard: bool
+ @param hard: noise hardness: 0 - soft noise; 1 - hard noise. (Returned value
+ is always positive.)
+ @type basis: int
+ @param basis: type of noise used for turbulence, see L{NoiseTypes}.
+ @type ampscale: float
+ @param ampscale: amplitude scale value of the noise frequencies added.
+ @type freqscale: float
+ @param freqscale: frequency scale factor.
+ @rtype: float
+ @return: the generated turbulence value.
+ """
+
+def vTurbulence (xyz, octaves, hard, basis = NoiseTypes['STDPERLIN'],
+ ampscale = 0.5, freqscale = 2.0):
+ """
+ Returns general turbulence vector using the optional specified noise basis
+function.
+ @type xyz: 3-float tuple
+ @param xyz: (x,y,z) float values.
+ @type octaves: int
+ @param octaves: number of noise values added.
+ @type hard: bool
+ @param hard: noise hardness: 0 - soft noise; 1 - hard noise. (Returned
+ vector is always positive.)
+ @type basis: int
+ @param basis: type of noise used for turbulence, see L{NoiseTypes}.
+ @type ampscale: float
+ @param ampscale: amplitude scale value of the noise frequencies added.
+ @type freqscale: float
+ @param freqscale: frequency scale factor.
+ @rtype: 3-float list
+ @return: the generated turbulence vector.
+ """
+
+def fBm (xyz, H, lacunarity, octaves, basis = NoiseTypes['STDPERLIN']):
+ """
+ Returns Fractal Brownian Motion noise value (fBm).
+ @type xyz: 3-float tuple
+ @param xyz: (x,y,z) float values.
+ @type H: float
+ @param H: the fractal increment parameter.
+ @type lacunarity: float
+ @param lacunarity: the gap between successive frequencies.
+ @type octaves: float
+ @param octaves: the number of frequencies in the fBm.
+ @type basis: int
+ @param basis: type of noise used for the turbulence, see L{NoiseTypes}.
+ @rtype: float
+ @return: the generated noise value.
+ """
+
+def multiFractal (xyz, H, lacunarity, octaves, basis = NoiseTypes['STDPERLIN']):
+ """
+ Returns Multifractal noise value.
+ @type xyz: 3-float tuple
+ @param xyz: (x,y,z) float values.
+ @type H: float
+ @param H: the highest fractal dimension.
+ @type lacunarity: float
+ @param lacunarity: the gap between successive frequencies.
+ @type octaves: float
+ @param octaves: the number of frequencies in the fBm.
+ @type basis: int
+ @param basis: type of noise used for the turbulence, see L{NoiseTypes}.
+ @rtype: float
+ @return: the generated noise value.
+ """
+
+def vlNoise (xyz, distortion, type1 = NoiseTypes['STDPERLIN'],
+ type2 = NoiseTypes['STDPERLIN']):
+ """
+ Returns Variable Lacunarity Noise value, a distorted variety of noise.
+ @type xyz: 3-float tuple
+ @param xyz: (x,y,z) float values.
+ @type distortion: float
+ @param distortion: the amount of distortion.
+ @type type1: int
+ @type type2: int
+ @param type1: sets the noise type to distort.
+ @param type2: sets the noise type used for the distortion.
+ @rtype: float
+ @return: the generated noise value.
+ """
+
+def heteroTerrain (xyz, H, lacunarity, octaves, offset,
+ basis = NoiseTypes['STDPERLIN']):
+ """
+ Returns Heterogeneous Terrain value.
+ @type xyz: 3-float tuple
+ @param xyz: (x,y,z) float values.
+ @type H: float
+ @param H: fractal dimension of the roughest areas.
+ @type lacunarity: float
+ @param lacunarity: gap between successive frequencies.
+ @type octaves: float
+ @param octaves: number of frequencies in the fBm.
+ @type offset: float
+ @param offset: it raises the terrain from 'sea level'.
+ @type basis: int
+ @param basis: noise basis determines the type of noise used for the
+ turbulence, see L{NoiseTypes}.
+ @rtype: float
+ @return: the generated value.
+ """
+
+def hybridMFractal (xyz, H, lacunarity, octaves, offset, gain,
+ basis = NoiseTypes['STDPERLIN']):
+ """
+ Returns Hybrid Multifractal value.
+ @type xyz: 3-float tuple
+ @param xyz: (x,y,z) float values.
+ @type H: float
+ @param H: fractal dimension of the roughest areas.
+ @type lacunarity: float
+ @param lacunarity: gap between successive frequencies.
+ @type octaves: float
+ @param octaves: number of frequencies in the fBm.
+ @type offset: float
+ @param offset: it raises the terrain from 'sea level'.
+ @type gain: float
+ @param gain: scale factor.
+ @type basis: int
+ @param basis: noise basis determines the type of noise used for the
+ turbulence, see L{NoiseTypes}.
+ @rtype: float
+ @return: the generated value.
+ """
+
+def ridgedMFractal (xyz, H, lacunarity, octaves, offset, gain,
+ basis = NoiseTypes['STDPERLIN']):
+ """
+ Returns Ridged Multifractal value.
+ @type xyz: 3-float tuple
+ @param xyz: (x,y,z) float values.
+ @type H: float
+ @param H: fractal dimension of the roughest areas.
+ @type lacunarity: float
+ @param lacunarity: gap between successive frequencies.
+ @type octaves: float
+ @param octaves: number of frequencies in the fBm.
+ @type offset: float
+ @param offset: it raises the terrain from 'sea level'.
+ @type gain: float
+ @param gain: scale factor.
+ @type basis: int
+ @param basis: noise basis determines the type of noise used for the
+ turbulence, see L{NoiseTypes}.
+ @rtype: float
+ @return: the generated value.
+ """
+
+def voronoi(xyz, distance_metric = DistanceMetrics['DISTANCE'], exponent = 2.5):
+ """
+ Returns Voronoi diagrams-related data.
+ @type xyz: 3-float tuple
+ @param xyz: (x,y,z) float values.
+ @type distance_metric: int
+ @param distance_metric: see L{DistanceMetrics}
+ @type exponent: float
+ @param exponent: only used with MINKOVSKY, default is 2.5.
+ @rtype: list
+ @return: a list containing a list of distances in order of closest feature,
+ and a list containing the positions of the four closest features.
+ """
+
+def cellNoise (xyz):
+ """
+ Returns cellnoise.
+ @type xyz: 3-float tuple
+ @param xyz: (x,y,z) float values.
+ @rtype: float
+ @return: the generated value.
+ """
+
+def cellNoiseV (xyz):
+ """
+ Returns cellnoise vector/point/color.
+ @type xyz: 3-float tuple
+ @param xyz: (x,y,z) float values.
+ @rtype: 3-float list
+ @return: the generated vector.
+ """
diff --git a/source/blender/python/api2_2x/doc/Object.py b/source/blender/python/api2_2x/doc/Object.py
new file mode 100644
index 00000000000..34cdd4b7821
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Object.py
@@ -0,0 +1,1754 @@
+# Blender.Object module and the Object PyType object
+
+"""
+The Blender.Object submodule
+
+B{New}:
+ - Addition of attributes for particle deflection, softbodies, and
+ rigidbodies.
+ - Objects now increment the Blender user count when they are created and
+ decremented it when they are destroyed. This means Python scripts can
+ keep the object "alive" if it is deleted in the Blender GUI.
+ - L{Object.getData} now accepts two optional bool keyword argument to
+ define (1) if the user wants the data object or just its name
+ and (2) if a mesh object should use NMesh or Mesh.
+ - L{Object.clearScriptLinks} accepts a parameter now.
+ - Object attributes: renamed Layer to L{Layers<Object.Object.Layers>} and
+ added the easier L{layers<Object.Object.layers>}. The old form "Layer"
+ will continue to work.
+
+
+Object
+======
+
+This module provides access to the B{Objects} in Blender.
+
+Example::
+
+ import Blender
+ scn = Blender.Scene.GetCurrent() # get the current scene
+ cam = Blender.Camera.New('ortho') # make ortho camera data object
+ ob = scn.objects.new(cam) # make a new object in this scene using the camera data
+ ob.setLocation (0.0, -5.0, 1.0) # position the object in the scene
+
+ Blender.Redraw() # redraw the scene to show the updates.
+
+@type DrawModes: readonly dictionary
+@var DrawModes: Constant dict used for with L{Object.drawMode} bitfield
+ attribute. Values can be ORed together. Individual bits can also
+ be set/cleared with boolean attributes.
+ - AXIS: Enable display of active object's center and axis.
+ - TEXSPACE: Enable display of active object's texture space.
+ - NAME: Enable display of active object's name.
+ - WIRE: Enable the active object's wireframe over solid drawing.
+ - XRAY: Enable drawing the active object in front of others.
+ - TRANSP: Enable transparent materials for the active object (mesh only).
+
+@type DrawTypes: readonly dictionary
+@var DrawTypes: Constant dict used for with L{Object.drawType} attribute.
+ Only one type can be selected at a time.
+ - BOUNDBOX: Only draw object with bounding box
+ - WIRE: Draw object in wireframe
+ - SOLID: Draw object in solid
+ - SHADED: Draw object with shaded or textured
+
+@type ParentTypes: readonly dictionary
+@var ParentTypes: Constant dict used for with L{Object.parentType} attribute.
+ - OBJECT: Object parent type.
+ - CURVE: Curve deform parent type.
+ - LATTICE: Lattice deform parent type. Note: This is the same as ARMATURE, 2.43 was released with LATTICE as an invalid value.
+ - ARMATURE: Armature deform parent type.
+ - VERT1: 1 mesh vert parent type.
+ - VERT3: 1 mesh verts parent type.
+ - BONE: Armature bone parent type.
+
+
+@type ProtectFlags: readonly dictionary
+@var ProtectFlags: Constant dict used for with L{Object.protectFlags} attribute.
+ Values can be ORed together.
+ - LOCX, LOCY, LOCZ: lock x, y or z location individually
+ - ROTX, ROTY, ROTZ: lock x, y or z rotation individually
+ - SCALEX, SCALEY, SCALEZ: lock x, y or z scale individually
+ - LOC, ROT, SCALE: lock all 3 attributes for location, rotation or scale
+
+@type PITypes: readonly dictionary
+@var PITypes: Constant dict used for with L{Object.piType} attribute.
+ Only one type can be selected at a time.
+ - NONE: No force influence on particles
+ - FORCE: Object center attracts or repels particles ("Spherical")
+ - VORTEX: Particles swirl around Z-axis of the object
+ - WIND: Constant force applied in direction of object Z axis
+ - GUIDE: Use a Curve Path to guide particles
+
+@type RBFlags: readonly dictionary
+@var RBFlags: Constant dict used for with L{Object.rbFlags} attribute.
+ Values can be ORed together.
+ - SECTOR: All game elements should be in the Sector boundbox
+ - PROP: An Object fixed within a sector
+ - BOUNDS: Specify a bounds object for physics
+ - ACTOR: Enables objects that are evaluated by the engine
+ - DYNAMIC: Enables motion defined by laws of physics (requires ACTOR)
+ - GHOST: Enable objects that don't restitute collisions (requires ACTOR)
+ - MAINACTOR: Enables MainActor (requires ACTOR)
+ - RIGIDBODY: Enable rolling physics (requires ACTOR, DYNAMIC)
+ - COLLISION_RESPONSE: Disable auto (de)activation (requires ACTOR, DYNAMIC)
+ - USEFH: Use Fh settings in Materials (requires ACTOR, DYNAMIC)
+ - ROTFH: Use face normal to rotate Object (requires ACTOR, DYNAMIC)
+ - ANISOTROPIC: Enable anisotropic friction (requires ACTOR, DYNAMIC)
+ - CHILD: reserved
+
+@type IpoKeyTypes: readonly dictionary
+@var IpoKeyTypes: Constant dict used for with L{Object.insertIpoKey} attribute.
+ Values can be ORed together.
+ - LOC
+ - ROT
+ - SIZE
+ - LOCROT
+ - LOCROTSIZE
+ - PI_STRENGTH
+ - PI_FALLOFF
+ - PI_SURFACEDAMP
+ - PI_RANDOMDAMP
+ - PI_PERM
+
+@type RBShapes: readonly dictionary
+@var RBShapes: Constant dict used for with L{Object.rbShapeBoundType}
+ attribute. Only one type can be selected at a time. Values are
+ BOX, SPHERE, CYLINDER, CONE, and POLYHEDERON
+
+"""
+
+def New (type, name='type'):
+ """
+ Creates a new Object. Deprecated; instead use Scene.objects.new().
+ @type type: string
+ @param type: The Object type: 'Armature', 'Camera', 'Curve', 'Lamp', 'Lattice',
+ 'Mball', 'Mesh', 'Surf' or 'Empty'.
+ @type name: string
+ @param name: The name of the object. By default, the name will be the same
+ as the object type.
+ If the name is already in use, this new object will have a number at the end of the name.
+ @return: The created Object.
+
+ I{B{Example:}}
+
+ The example below creates a new Lamp object and puts it at the default
+ location (0, 0, 0) in the current scene::
+ import Blender
+
+ object = Blender.Object.New('Lamp')
+ lamp = Blender.Lamp.New('Spot')
+ object.link(lamp)
+ sce = Blender.Scene.GetCurrent()
+ sce.link(object)
+
+ Blender.Redraw()
+ @Note: if an object is created but is not linked to object data, and the
+ object is not linked to a scene, it will be deleted when the Python
+ object is deallocated. This is because Blender does not allow objects
+ to exist without object data unless they are Empty objects. Scene.link()
+ will automatically create object data for an object if it has none.
+ """
+
+def Get (name = None):
+ """
+ Get the Object from Blender.
+ @type name: string
+ @param name: The name of the requested Object.
+ @return: It depends on the 'name' parameter:
+ - (name): The Object with the given name;
+ - (): A list with all Objects in the current scene.
+
+ I{B{Example 1:}}
+
+ The example below works on the default scene. The script returns the plane object and prints the location of the plane::
+ import Blender
+
+ object = Blender.Object.Get ('plane')
+ print object.getLocation()
+
+ I{B{Example 2:}}
+
+ The example below works on the default scene. The script returns all objects
+ in the scene and prints the list of object names::
+ import Blender
+
+ objects = Blender.Object.Get ()
+ print objects
+ @note: Get will return objects from all scenes.
+ Most user tools should only operate on objects from the current scene - Blender.Scene.GetCurrent().getChildren()
+ """
+
+def GetSelected ():
+ """
+ Get the user selection. If no objects are selected, an empty list will be returned.
+
+ @return: A list of all selected Objects in the current scene.
+
+ I{B{Example:}}
+
+ The example below works on the default scene. Select one or more objects and
+ the script will print the selected objects::
+ import Blender
+
+ objects = Blender.Object.GetSelected()
+ print objects
+ @note: The active object will always be the first object in the list (if selected).
+ @note: The user selection is made up of selected objects from Blender's current scene only.
+ @note: The user selection is limited to objects on visible layers;
+ if the user's last active 3d view is in localview then the selection will be limited to the objects in that localview.
+ """
+
+
+def Duplicate (mesh=0, surface=0, curve=0, text=0, metaball=0, armature=0, lamp=0, material=0, texture=0, ipo=0):
+ """
+ Duplicate selected objects on visible layers from Blenders current scene,
+ de-selecting the currently visible, selected objects and making a copy where all new objects are selected.
+ By default no data linked to the object is duplicated; use the keyword arguments to change this.
+ L{Object.GetSelected()<GetSelected>} will return the list of objects resulting from duplication.
+
+ B{Note}: This command will raise an error if used from the command line (background mode) because it uses the 3D view context.
+
+ @type mesh: bool
+ @param mesh: When non-zero, mesh object data will be duplicated with the objects.
+ @type surface: bool
+ @param surface: When non-zero, surface object data will be duplicated with the objects.
+ @type curve: bool
+ @param curve: When non-zero, curve object data will be duplicated with the objects.
+ @type text: bool
+ @param text: When non-zero, text object data will be duplicated with the objects.
+ @type metaball: bool
+ @param metaball: When non-zero, metaball object data will be duplicated with the objects.
+ @type armature: bool
+ @param armature: When non-zero, armature object data will be duplicated with the objects.
+ @type lamp: bool
+ @param lamp: When non-zero, lamp object data will be duplicated with the objects.
+ @type material: bool
+ @param material: When non-zero, materials used by the object or its object data will be duplicated with the objects.
+ @type texture: bool
+ @param texture: When non-zero, texture data used by the object's materials will be duplicated with the objects.
+ @type ipo: bool
+ @param ipo: When non-zero, Ipo data linked to the object will be duplicated with the objects.
+
+ I{B{Example:}}
+
+ The example below creates duplicates the active object 10 times
+ and moves each object 1.0 on the X axis::
+ import Blender
+
+ scn = Scene.GetCurrent()
+ ob_act = scn.objects.active
+
+ # Unselect all
+ scn.objects.selected = []
+ ob_act.sel = 1
+
+ for x in xrange(10):
+ Blender.Object.Duplicate() # Duplicate linked
+ ob_act = scn.objects.active
+ ob_act.LocX += 1
+ Blender.Redraw()
+ """
+
+from IDProp import IDGroup, IDArray
+class Object:
+ """
+ The Object object
+ =================
+ This object gives access to generic data from all objects in Blender.
+
+ B{Note}:
+ When dealing with properties and functions such as LocX/RotY/getLocation(), getSize() and getEuler(),
+ keep in mind that these transformation properties are relative to the object's parent (if any).
+
+ To get these values in worldspace (taking into account vertex parents, constraints, etc.)
+ pass the argument 'worldspace' to these functions.
+
+ @ivar restrictDisplay: Don't display this object in the 3D view: disabled by default, use the outliner to toggle.
+ @type restrictDisplay: bool
+ @ivar restrictSelect: Don't select this object in the 3D view: disabled by default, use the outliner to toggle.
+ @type restrictSelect: bool
+ @ivar restrictRender: Don't render this object: disabled by default, use the outliner to toggle.
+ @type restrictRender: bool
+ @ivar LocX: The X location coordinate of the object.
+ @type LocX: float
+ @ivar LocY: The Y location coordinate of the object.
+ @type LocY: float
+ @ivar LocZ: The Z location coordinate of the object.
+ @type LocZ: float
+ @ivar loc: The (X,Y,Z) location coordinates of the object.
+ @type loc: tuple of 3 floats
+ @ivar dLocX: The delta X location coordinate of the object.
+ This variable applies to IPO Objects only.
+ @type dLocX: float
+ @ivar dLocY: The delta Y location coordinate of the object.
+ This variable applies to IPO Objects only.
+ @type dLocY: float
+ @ivar dLocZ: The delta Z location coordinate of the object.
+ This variable applies to IPO Objects only.
+ @type dLocZ: float
+ @ivar dloc: The delta (X,Y,Z) location coordinates of the object (vector).
+ This variable applies to IPO Objects only.
+ @type dloc: tuple of 3 floats
+ @ivar RotX: The X rotation angle (in radians) of the object.
+ @type RotX: float
+ @ivar RotY: The Y rotation angle (in radians) of the object.
+ @type RotY: float
+ @ivar RotZ: The Z rotation angle (in radians) of the object.
+ @type RotZ: float
+ @ivar rot: The (X,Y,Z) rotation angles (in radians) of the object.
+ @type rot: euler (Py_WRAPPED)
+ @ivar dRotX: The delta X rotation angle (in radians) of the object.
+ This variable applies to IPO Objects only.
+ @type dRotX: float
+ @ivar dRotY: The delta Y rotation angle (in radians) of the object.
+ This variable applies to IPO Objects only.
+ @type dRotY: float
+ @ivar dRotZ: The delta Z rotation angle (in radians) of the object.
+ This variable applies to IPO Objects only.
+ @type dRotZ: float
+ @ivar drot: The delta (X,Y,Z) rotation angles (in radians) of the object.
+ This variable applies to IPO Objects only.
+ @type drot: tuple of 3 floats
+ @ivar SizeX: The X size of the object.
+ @type SizeX: float
+ @ivar SizeY: The Y size of the object.
+ @type SizeY: float
+ @ivar SizeZ: The Z size of the object.
+ @type SizeZ: float
+ @ivar size: The (X,Y,Z) size of the object.
+ @type size: tuple of 3 floats
+ @ivar dSizeX: The delta X size of the object.
+ @type dSizeX: float
+ @ivar dSizeY: The delta Y size of the object.
+ @type dSizeY: float
+ @ivar dSizeZ: The delta Z size of the object.
+ @type dSizeZ: float
+ @ivar dsize: The delta (X,Y,Z) size of the object.
+ @type dsize: tuple of 3 floats
+ @ivar Layers: The object layers (also check the newer attribute
+ L{layers<layers>}). This value is a bitmask with at
+ least one position set for the 20 possible layers starting from the low
+ order bit. The easiest way to deal with these values in in hexadecimal
+ notation.
+ Example::
+ ob.Layer = 0x04 # sets layer 3 ( bit pattern 0100 )
+ After setting the Layer value, call Blender.Redraw( -1 ) to update
+ the interface.
+ @type Layers: integer (bitmask)
+ @type layers: list of integers
+ @ivar layers: The layers this object is visible in (also check the older
+ attribute L{Layers<Layers>}). This returns a list of
+ integers in the range [1, 20], each number representing the respective
+ layer. Setting is done by passing a list of ints or an empty list for
+ no layers.
+ Example::
+ ob.layers = [] # object won't be visible
+ ob.layers = [1, 4] # object visible only in layers 1 and 4
+ ls = o.layers
+ ls.append([10])
+ o.layers = ls
+ print ob.layers # will print: [1, 4, 10]
+ B{Note}: changes will only be visible after the screen (at least
+ the 3d View and Buttons windows) is redrawn.
+ @ivar parent: The parent object of the object (if defined). Read-only.
+ @type parent: Object or None
+ @ivar data: The Datablock object linked to this object. Read-only.
+ @type data: varies
+ @ivar ipo: Contains the Ipo if one is assigned to the object, B{None}
+ otherwise. Setting to B{None} clears the current Ipo.
+ @type ipo: Ipo
+ @ivar mat: The matrix of the object in world space (absolute, takes vertex parents, tracking
+ and Ipos into account). Read-only.
+ @type mat: Matrix
+ @ivar matrix: Same as L{mat}. Read-only.
+ @type matrix: Matrix
+ @ivar matrixLocal: The matrix of the object relative to its parent; if there is no parent,
+ returns the world matrix (L{matrixWorld<Object.Object.matrixWorld>}).
+ @type matrixLocal: Matrix
+ @ivar matrixParentInverse: The inverse if the parents local matrix, set when the objects parent is set (wrapped).
+ @type matrixParentInverse: Matrix
+ @ivar matrixOldWorld: Old-type worldspace matrix (prior to Blender 2.34).
+ Read-only.
+ @type matrixOldWorld: Matrix
+ @ivar matrixWorld: Same as L{mat}. Read-only.
+ @type matrixWorld: Matrix
+ @ivar colbits: The Material usage mask. A set bit #n means: the Material
+ #n in the Object's material list is used. Otherwise, the Material #n
+ of the Objects Data material list is displayed.
+ Example::
+ object.colbits = (1<<0) + (1<<5) # use mesh materials 0 (1<<0) and 5 (1<<5)
+ # use object materials for all others
+ @ivar sel: The selection state of the object in the current scene.
+ True is selected, False is unselected. Setting makes the object active.
+ @type sel: boolean
+ @ivar effects: The list of particle effects associated with the object.
+ Read-only.
+ @type effects: list of Effect objects
+ @ivar parentbonename: The string name of the parent bone (if defined).
+ This can be set to another bone in the armature if the object already has a bone parent.
+ @type parentbonename: string or None
+ @ivar protectFlags: The "transform locking" bitfield flags for the object.
+ See L{ProtectFlags} const dict for values.
+ @type protectFlags: int
+ @ivar DupGroup: The DupliGroup Animation Property. Assign a group to
+ DupGroup to make this object an instance of that group.
+ This does not enable or disable the DupliGroup option, for that use
+ L{enableDupGroup}.
+ The attribute returns None when this object does not have a dupliGroup,
+ and setting the attrbute to None deletes the object from the group.
+ @type DupGroup: Group or None
+ @ivar DupObjects: The Dupli object instances. Read-only.
+ Returns of list of tuples for object duplicated
+ by dupliframe, dupliverts dupligroups and other animation properties.
+ The first tuple item is the original object that is duplicated,
+ the second is the 4x4 worldspace dupli-matrix.
+ Example::
+ import Blender
+ from Blender import Object, Scene, Mathutils
+
+ ob= Object.Get('Cube')
+ dupe_obs= ob.DupObjects
+ scn= Scene.GetCurrent()
+ for dupe_ob, dupe_matrix in dupe_obs:
+ print dupe_ob.name
+ empty_ob = scn.objects.new('Empty')
+ empty_ob.setMatrix(dupe_matrix)
+ Blender.Redraw()
+ @type DupObjects: list of tuples containing (object, matrix)
+ @ivar enableNLAOverride: Whether the object uses NLA or active Action for animation.
+ @type enableNLAOverride: boolean
+ @ivar enableDupVerts: The DupliVerts status of the object.
+ Does not indicate that this object has any dupliVerts,
+ (as returned by L{DupObjects}) just that dupliVerts are enabled.
+ @type enableDupVerts: boolean
+ @ivar enableDupFaces: The DupliFaces status of the object.
+ Does not indicate that this object has any dupliFaces,
+ (as returned by L{DupObjects}) just that dupliFaces are enabled.
+ @type enableDupFaces: boolean
+ @ivar enableDupFacesScale: The DupliFacesScale status of the object.
+ @type enableDupFacesScale: boolean
+ @ivar enableDupFrames: The DupliFrames status of the object.
+ Does not indicate that this object has any dupliFrames,
+ (as returned by L{DupObjects}) just that dupliFrames are enabled.
+ @type enableDupFrames: boolean
+ @ivar enableDupGroup: The DupliGroup status of the object.
+ Set True to make this object an instance of the object's L{DupGroup},
+ and set L{DupGroup} to a group for this to take effect,
+ Use L{DupObjects} to get the object data from this instance.
+ @type enableDupGroup: boolean
+ @ivar enableDupRot: The DupliRot status of the object.
+ Use with L{enableDupVerts} to rotate each instance
+ by the vertex normal.
+ @type enableDupRot: boolean
+ @ivar enableDupNoSpeed: The DupliNoSpeed status of the object.
+ Use with L{enableDupFrames} to ignore dupliFrame speed.
+ @type enableDupNoSpeed: boolean
+ @ivar DupSta: The DupliFrame starting frame. Use with L{enableDupFrames}.
+ Value clamped to [1,32767].
+ @type DupSta: int
+ @ivar DupEnd: The DupliFrame end frame. Use with L{enableDupFrames}.
+ Value clamped to [1,32767].
+ @type DupEnd: int
+ @ivar DupOn: The DupliFrames in succession between DupOff frames.
+ Value is clamped to [1,1500].
+ Use with L{enableDupFrames} and L{DupOff} > 0.
+ @type DupOn: int
+ @ivar DupOff: The DupliFrame removal of every Nth frame for this object.
+ Use with L{enableDupFrames}. Value is clamped to [0,1500].
+ @type DupOff: int
+ @ivar passIndex: Index # for the IndexOB render pass.
+ Value is clamped to [0,1000].
+ @type passIndex: int
+ @ivar activeMaterial: The active material index for this object.
+
+ The active index is used to select the material to edit in the material buttons,
+ new data created will also use the active material.
+
+ Value is clamped to [1,len(ob.materials)]. - [0,0] when there is no materials applied to the object.
+ @type activeMaterial: int
+ @ivar activeShape: The active shape key index for this object.
+
+ The active index is used to select the material to edit in the material buttons,
+ new data created will also use the active material.
+
+ Value is clamped to [1,len(ob.data.key.blocks)]. - [0,0] when there are no keys.
+
+ @type activeShape: int
+
+ @ivar pinShape: If True, only the activeShape will be displayed.
+ @type pinShape: bool
+ @ivar drawSize: The size to display the Empty.
+ Value clamped to [0.01,10.0].
+ @type drawSize: float
+ @ivar modifiers: The modifiers associated with the object.
+ Example::
+ # copy the active objects modifiers to all other visible selected objects
+ from Blender import *
+ scn = Scene.GetCurrent()
+ ob_act = scn.objects.active
+ for ob in scn.objects.context:
+ # Cannot copy modifiers to an object of a different type
+ if ob.type == ob_act.type:
+ ob.modifiers = ob_act.modifiers
+ @type modifiers: L{Modifier Sequence<Modifier.ModSeq>}
+ @ivar constraints: a L{sequence<Constraint.Constraints>} of
+ L{constraints<Constraint.Constraint>} for the object. Read-only.
+ @type constraints: Constraint Sequence
+ @ivar actionStrips: a L{sequence<NLA.ActionStrips>} of
+ L{action strips<NLA.ActionStrip>} for the object. Read-only.
+ @type actionStrips: BPy_ActionStrips
+ @ivar action: The action associated with this object (if defined).
+ @type action: L{Action<NLA.Action>} or None
+ @ivar oopsLoc: Object's (X,Y) OOPs location. Returns None if object
+ is not found in list.
+ @type oopsLoc: tuple of 2 floats
+ @ivar oopsSel: Object OOPs selection flag.
+ @type oopsSel: boolean
+ @ivar game_properties: The object's properties. Read-only.
+ @type game_properties: list of Properties.
+ @ivar timeOffset: The time offset of the object's animation.
+ Value clamped to [-300000.0,300000.0].
+ @type timeOffset: float
+ @ivar track: The object's tracked object. B{None} is returned if no
+ object is tracked. Also, assigning B{None} clear the tracked object.
+ @type track: Object or None
+ @ivar type: The object's type. Read-only.
+ @type type: string
+ @ivar boundingBox: The bounding box of this object. Read-only.
+ @type boundingBox: list of 8 3D vectors
+ @ivar drawType: The object's drawing type.
+ See L{DrawTypes} constant dict for values.
+ @type drawType: int
+ @ivar parentType: The object's parent type. Read-only.
+ See L{ParentTypes} constant dict for values.
+ @type parentType: int
+ @ivar axis: Enable display of active object's center and axis.
+ Also see B{AXIS} bit in L{drawMode} attribute.
+ @type axis: boolean
+ @ivar texSpace: Enable display of active object's texture space.
+ Also see B{TEXSPACE} bit in L{drawMode} attribute.
+ @type texSpace: boolean
+ @ivar nameMode: Enable display of active object's name.
+ Also see B{NAME} bit in L{drawMode} attribute.
+ @type nameMode: boolean
+ @ivar wireMode: Enable the active object's wireframe over solid drawing.
+ Also see B{WIRE} bit in L{drawMode} attribute.
+ @type wireMode: boolean
+ @ivar xRay: Enable drawing the active object in front of others.
+ Also see B{XRAY} bit in L{drawMode} attribute.
+ @type xRay: boolean
+ @ivar transp: Enable transparent materials for the active object
+ (mesh only). Also see B{TRANSP} bit in L{drawMode} attribute.
+ @type transp: boolean
+ @ivar drawMode: The object's drawing mode bitfield.
+ See L{DrawModes} constant dict for values.
+ @type drawMode: int
+
+ @ivar piType: Type of particle interaction.
+ See L{PITypes} constant dict for values.
+ @type piType: int
+ @ivar piFalloff: The particle interaction falloff power.
+ Value clamped to [0.0,10.0].
+ @type piFalloff: float
+ @ivar piMaxDist: Max distance for the particle interaction field to work.
+ Value clamped to [0.0,1000.0].
+ @type piMaxDist: float
+ @ivar piPermeability: Probability that a particle will pass through the
+ mesh. Value clamped to [0.0,1.0].
+ @type piPermeability: float
+ @ivar piRandomDamp: Random variation of particle interaction damping.
+ Value clamped to [0.0,1.0].
+ @type piRandomDamp: float
+ @ivar piSoftbodyDamp: Damping factor for softbody deflection.
+ Value clamped to [0.0,1.0].
+ @type piSoftbodyDamp: float
+ @ivar piSoftbodyIThick: Inner face thickness for softbody deflection.
+ Value clamped to [0.001,1.0].
+ @type piSoftbodyIThick: float
+ @ivar piSoftbodyOThick: Outer face thickness for softbody deflection.
+ Value clamped to [0.001,1.0].
+ @type piSoftbodyOThick: float
+ @ivar piStrength: Particle interaction force field strength.
+ Value clamped to [0.0,1000.0].
+ @type piStrength: float
+ @ivar piSurfaceDamp: Amount of damping during particle collision.
+ Value clamped to [0.0,1.0].
+ @type piSurfaceDamp: float
+ @ivar piUseMaxDist: Use a maximum distance for the field to work.
+ @type piUseMaxDist: boolean
+
+ @ivar isSoftBody: True if object is a soft body. Read-only.
+ @type isSoftBody: boolean
+ @ivar SBDefaultGoal: Default softbody goal value, when no vertex group used.
+ Value clamped to [0.0,1.0].
+ @type SBDefaultGoal: float
+ @ivar SBErrorLimit: Softbody Runge-Kutta ODE solver error limit (low values give more precision).
+ Value clamped to [0.01,1.0].
+ @type SBErrorLimit: float
+ @ivar SBFriction: General media friction for softbody point movements.
+ Value clamped to [0.0,10.0].
+ @type SBFriction: float
+ @ivar SBGoalFriction: Softbody goal (vertex target position) friction.
+ Value clamped to [0.0,10.0].
+ @type SBGoalFriction: float
+ @ivar SBGoalSpring: Softbody goal (vertex target position) spring stiffness.
+ Value clamped to [0.0,0.999].
+ @type SBGoalSpring: float
+ @ivar SBGrav: Apply gravitation to softbody point movement.
+ Value clamped to [0.0,10.0].
+ @type SBGrav: float
+ @ivar SBInnerSpring: Softbody edge spring stiffness.
+ Value clamped to [0.0,0.999].
+ @type SBInnerSpring: float
+ @ivar SBInnerSpringFrict: Softbody edge spring friction.
+ Value clamped to [0.0,10.0].
+ @type SBInnerSpringFrict: float
+ @ivar SBMass: Softbody point mass (heavier is slower).
+ Value clamped to [0.001,50.0].
+ @type SBMass: float
+ @ivar SBMaxGoal: Softbody goal maximum (vertex group weights scaled to
+ match this range). Value clamped to [0.0,1.0].
+ @type SBMaxGoal: float
+ @ivar SBMinGoal: Softbody goal minimum (vertex group weights scaled to
+ match this range). Value clamped to [0.0,1.0].
+ @type SBMinGoal: float
+ @ivar SBSpeed: Tweak timing for physics to control softbody frequency and
+ speed. Value clamped to [0.0,10.0].
+ @type SBSpeed: float
+ @ivar SBStiffQuads: Softbody adds diagonal springs on 4-gons enabled.
+ @type SBStiffQuads: boolean
+ @ivar SBUseEdges: Softbody use edges as springs enabled.
+ @type SBUseEdges: boolean
+ @ivar SBUseGoal: Softbody forces for vertices to stick to animated position enabled.
+ @type SBUseGoal: boolean
+
+ @ivar rbFlags: Rigid body bitfield. See L{RBFlags} for valid values.
+ @type rbFlags: int
+ @ivar rbMass: Rigid body mass. Must be a positive value.
+ @type rbMass: float
+ @ivar rbRadius: Rigid body bounding sphere size. Must be a positive
+ value.
+ @type rbRadius: float
+ @ivar rbShapeBoundType: Rigid body shape bound type. See L{RBShapes}
+ const dict for values.
+ @type rbShapeBoundType: int
+ """
+
+ def buildParts():
+ """
+ Recomputes the particle system. This method only applies to an Object of
+ the type Effect.
+ """
+
+ def insertShapeKey():
+ """
+ Insert a Shape Key in the current object. It applies to Objects of
+ the type Mesh, Lattice, or Curve.
+ """
+
+ def getPose():
+ """
+ Gets the current Pose of the object.
+ @rtype: Pose object
+ @return: the current pose object
+ """
+
+ def evaluatePose(framenumber):
+ """
+ Evaluates the Pose based on its currently bound action at a certain frame.
+ @type framenumber: Int
+ @param framenumber: The frame number to evaluate to.
+ """
+
+ def clearIpo():
+ """
+ Unlinks the ipo from this object.
+ @return: True if there was an ipo linked or False otherwise.
+ """
+
+ def clrParent(mode = 0, fast = 0):
+ """
+ Clears parent object.
+ @type mode: Integer
+ @type fast: Integer
+ @param mode: A mode flag. If mode flag is 2, then the object transform will
+ be kept. Any other value, or no value at all will update the object
+ transform.
+ @param fast: If the value is 0, the scene hierarchy will not be updated. Any
+ other value, or no value at all will update the scene hierarchy.
+ """
+
+ def getData(name_only=False, mesh=False):
+ """
+ Returns the Datablock object (Mesh, Lamp, Camera, etc.) linked to this
+ Object. If the keyword parameter B{name_only} is True, only the Datablock
+ name is returned as a string. It the object is of type Mesh, then the
+ B{mesh} keyword can also be used; the data return is a Mesh object if
+ True, otherwise it is an NMesh object (the default).
+ The B{mesh} keyword is ignored for non-mesh objects.
+ @type name_only: bool
+ @param name_only: This is a keyword parameter. If True (or nonzero),
+ only the name of the data object is returned.
+ @type mesh: bool
+ @param mesh: This is a keyword parameter. If True (or nonzero),
+ a Mesh data object is returned.
+ @rtype: specific Object type or string
+ @return: Depends on the type of Datablock linked to the Object. If
+ B{name_only} is True, it returns a string.
+ @note: Mesh is faster than NMesh because Mesh is a thin wrapper.
+ @note: This function is different from L{NMesh.GetRaw} and L{Mesh.Get}
+ because it keeps a link to the original mesh, which is needed if you are
+ dealing with Mesh weight groups.
+ @note: Make sure the object you are getting the data from isn't in
+ EditMode before calling this function; otherwise you'll get the data
+ before entering EditMode. See L{Window.EditMode}.
+ """
+
+ def getParentBoneName():
+ """
+ Returns None, or the 'sub-name' of the parent (eg. Bone name)
+ @return: string
+ """
+
+ def getDeltaLocation():
+ """
+ Returns the object's delta location in a list (x, y, z)
+ @rtype: A vector triple
+ @return: (x, y, z)
+ """
+
+ def getDrawMode():
+ """
+ Returns the object draw mode.
+ @rtype: Integer
+ @return: a sum of the following:
+ - 2 - axis
+ - 4 - texspace
+ - 8 - drawname
+ - 16 - drawimage
+ - 32 - drawwire
+ - 64 - xray
+ """
+
+ def getDrawType():
+ """
+ Returns the object draw type
+ @rtype: Integer
+ @return: One of the following:
+ - 1 - Bounding box
+ - 2 - Wire
+ - 3 - Solid
+ - 4 - Shaded
+ - 5 - Textured
+ """
+
+ def getEuler(space):
+ """
+ @type space: string
+ @param space: The desired space for the size:
+ - localspace: (default) relative to the object's parent;
+ - worldspace: absolute, taking vertex parents, tracking and
+ Ipo's into account;
+ Returns the object's localspace rotation as Euler rotation vector (rotX, rotY, rotZ). Angles are in radians.
+ @rtype: Py_Euler
+ @return: A python Euler. Data is wrapped when euler is present.
+ """
+
+ def getInverseMatrix():
+ """
+ Returns the object's inverse matrix.
+ @rtype: Py_Matrix
+ @return: A python matrix 4x4
+ """
+
+ def getIpo():
+ """
+ Returns the Ipo associated to this object or None if there's no linked ipo.
+ @rtype: Ipo
+ @return: the wrapped ipo or None.
+ """
+ def isSelected():
+ """
+ Returns the objects selection state in the current scene as a boolean value True or False.
+ @rtype: Boolean
+ @return: Selection state as True or False
+ """
+
+ def getLocation(space):
+ """
+ @type space: string
+ @param space: The desired space for the location:
+ - localspace: (default) relative to the object's parent;
+ - worldspace: absolute, taking vertex parents, tracking and
+ Ipo's into account;
+ Returns the object's location (x, y, z).
+ @return: (x, y, z)
+
+ I{B{Example:}}
+
+ The example below works on the default scene. It retrieves all objects in
+ the scene and prints the name and location of each object::
+ import Blender
+
+ sce = Blender.Scene.GetCurrent()
+
+ for ob in sce.objects:
+ print obj.name
+ print obj.loc
+ @note: the worldspace location is the same as ob.matrixWorld[3][0:3]
+ """
+
+ def getAction():
+ """
+ Returns an action if one is associated with this object (only useful for armature types).
+ @rtype: Py_Action
+ @return: a python action.
+ """
+
+ def getMaterials(what = 0):
+ """
+ Returns a list of materials assigned to the object.
+ @type what: int
+ @param what: if nonzero, empty slots will be returned as None's instead
+ of being ignored (default way). See L{NMesh.NMesh.getMaterials}.
+ @rtype: list of Material Objects
+ @return: list of Material Objects assigned to the object.
+ """
+
+ def getMatrix(space = 'worldspace'):
+ """
+ Returns the object matrix.
+ @type space: string
+ @param space: The desired matrix:
+ - worldspace (default): absolute, taking vertex parents, tracking and
+ Ipo's into account;
+ - localspace: relative to the object's parent (returns worldspace
+ matrix if the object doesn't have a parent);
+ - old_worldspace: old behavior, prior to Blender 2.34, where eventual
+ changes made by the script itself were not taken into account until
+ a redraw happened, either called by the script or upon its exit.
+ Returns the object matrix.
+ @rtype: Py_Matrix (WRAPPED DATA)
+ @return: a python 4x4 matrix object. Data is wrapped for 'worldspace'
+ """
+
+ def getName():
+ """
+ Returns the name of the object
+ @return: The name of the object
+
+ I{B{Example:}}
+
+ The example below works on the default scene. It retrieves all objects in
+ the scene and prints the name of each object::
+ import Blender
+
+ sce= Blender.Scene.GetCurrent()
+
+ for ob in sce.objects:
+ print ob.getName()
+ """
+
+ def getParent():
+ """
+ Returns the object's parent object.
+ @rtype: Object
+ @return: The parent object of the object. If not available, None will be
+ returned.
+ """
+
+ def getSize(space):
+ """
+ @type space: string
+ @param space: The desired space for the size:
+ - localspace: (default) relative to the object's parent;
+ - worldspace: absolute, taking vertex parents, tracking and
+ Ipo's into account;
+ Returns the object's size.
+ @return: (SizeX, SizeY, SizeZ)
+ @note: the worldspace size will not return negative (flipped) scale values.
+ """
+
+ def getParentBoneName():
+ """
+ Returns the object's parent object's sub name, or None.
+ For objects parented to bones, this is the name of the bone.
+ @rtype: String
+ @return: The parent object sub-name of the object.
+ If not available, None will be returned.
+ """
+
+ def getTimeOffset():
+ """
+ Returns the time offset of the object's animation.
+ @return: TimeOffset
+ """
+
+ def getTracked():
+ """
+ Returns the object's tracked object.
+ @rtype: Object
+ @return: The tracked object of the object. If not available, None will be
+ returned.
+ """
+
+ def getType():
+ """
+ Returns the type of the object in 'Armature', 'Camera', 'Curve', 'Lamp', 'Lattice',
+ 'Mball', 'Mesh', 'Surf', 'Empty', 'Wave' (deprecated) or 'unknown' in exceptional cases.
+
+ I{B{Example:}}
+
+ The example below works on the default scene. It retrieves all objects in
+ the scene and updates the location and rotation of the camera. When run,
+ the camera will rotate 180 degrees and moved to the opposite side of the X
+ axis. Note that the number 'pi' in the example is an approximation of the
+ true number 'pi'. A better, less error-prone value of pi is math.pi from the python math module.::
+ import Blender
+
+ sce = Blender.Scene.GetCurrent()
+
+ for obj in sce.objects:
+ if obj.type == 'Camera':
+ obj.LocY = -obj.LocY
+ obj.RotZ = 3.141592 - obj.RotZ
+
+ Blender.Redraw()
+
+ @return: The type of object.
+ @rtype: String
+ """
+
+ def insertIpoKey(keytype):
+ """
+ Inserts keytype values in object ipo at curframe.
+ @type keytype: int
+ @param keytype: A constant from L{IpoKeyTypes<Object.IpoKeyTypes>}
+ @return: None
+ """
+
+ def link(datablock):
+ """
+ Links Object with ObData datablock provided in the argument. The data must match the
+ Object's type, so you cannot link a Lamp to a Mesh type object.
+ @type datablock: Blender ObData datablock
+ @param datablock: A Blender datablock matching the objects type.
+ """
+
+ def makeParent(objects, noninverse = 0, fast = 0):
+ """
+ Makes the object the parent of the objects provided in the argument which
+ must be a list of valid Objects.
+ @type objects: Sequence of Blender Object
+ @param objects: The children of the parent
+ @type noninverse: Integer
+ @param noninverse:
+ 0 - make parent with inverse
+ 1 - make parent without inverse
+ @type fast: Integer
+ @param fast:
+ 0 - update scene hierarchy automatically
+ 1 - don't update scene hierarchy (faster). In this case, you must
+ explicitely update the Scene hierarchy.
+ @warn: objects must first be linked to a scene before they can become
+ parents of other objects. Calling this makeParent method for an
+ unlinked object will result in an error.
+ """
+
+ def join(objects):
+ """
+ Uses the object as a base for all of the objects in the provided list to join into.
+
+ @type objects: Sequence of Blender Object
+ @param objects: A list of objects matching the object's type.
+ @note: Objects in the list will not be removed from the scene.
+ To avoid overlapping data you may want to remove them manually after joining.
+ @note: Join modifies the base object's data in place so that
+ other objects are joined into it. No new object or data is created.
+ @note: Join will only work for object types Mesh, Armature, Curve and Surface;
+ an excption will be raised if the object is not of these types.
+ @note: Objects in the list will be ignored if they to not match the base object.
+ @note: The base object must be in the current scene to be joined.
+ @note: This function will not work in background mode (no user interface).
+ @note: An error in the function input will raise a TypeError or AttributeError,
+ otherwise an error in the data input will raise a RuntimeError.
+ For situations where you don't have tight control on the data that is being joined,
+ you should handle the RuntimeError error, letting the user know the data can't be joined.
+ """
+
+ def makeParentDeform(objects, noninverse = 0, fast = 0):
+ """
+ Makes the object the deformation parent of the objects provided in the argument
+ which must be a list of valid Objects.
+ The parent object must be a Curve or Armature.
+ @type objects: Sequence of Blender Object
+ @param objects: The children of the parent
+ @type noninverse: Integer
+ @param noninverse:
+ 0 - make parent with inverse
+ 1 - make parent without inverse
+ @type fast: Integer
+ @param fast:
+ 0 - update scene hierarchy automatically
+ 1 - don't update scene hierarchy (faster). In this case, you must
+ explicitely update the Scene hierarchy.
+ @warn: objects must first be linked to a scene before they can become
+ parents of other objects. Calling this makeParent method for an
+ unlinked object will result in an error.
+ @warn: child objects must be of mesh type to deform correctly. Other object
+ types will fall back to normal parenting silently.
+ """
+
+ def makeParentVertex(objects, indices, noninverse = 0, fast = 0):
+ """
+ Makes the object the vertex parent of the objects provided in the argument
+ which must be a list of valid Objects.
+ The parent object must be a Mesh, Curve or Surface.
+ @type objects: Sequence of Blender Object
+ @param objects: The children of the parent
+ @type indices: Tuple of Integers
+ @param indices: The indices of the vertices you want to parent to (1 or 3 values)
+ @type noninverse: Integer
+ @param noninverse:
+ 0 - make parent with inverse
+ 1 - make parent without inverse
+ @type fast: Integer
+ @param fast:
+ 0 - update scene hierarchy automatically
+ 1 - don't update scene hierarchy (faster). In this case, you must
+ explicitely update the Scene hierarchy.
+ @warn: objects must first be linked to a scene before they can become
+ parents of other objects. Calling this makeParent method for an
+ unlinked object will result in an error.
+ """
+ def makeParentBone(objects, bonename, noninverse = 0, fast = 0):
+ """
+ Makes one of the object's bones the parent of the objects provided in the argument
+ which must be a list of valid objects. The parent object must be an Armature.
+ @type objects: Sequence of Blender Object
+ @param objects: The children of the parent
+ @type bonename: string
+ @param bonename: a valid bone name from the armature
+ @type noninverse: integer
+ @param noninverse:
+ 0 - make parent with inverse
+ 1 - make parent without inverse
+ @type fast: integer
+ @param fast:
+ 0 - update scene hierarchy automatically
+ 1 - don't update scene hierarchy (faster). In this case, you must
+ explicitly update the Scene hierarchy.
+ @warn: Objects must first be linked to a scene before they can become
+ parents of other objects. Calling this method for an
+ unlinked object will result in an exception.
+ """
+
+ def setDeltaLocation(delta_location):
+ """
+ Sets the object's delta location which must be a vector triple.
+ @type delta_location: A vector triple
+ @param delta_location: A vector triple (x, y, z) specifying the new
+ location.
+ """
+
+ def setDrawMode(drawmode):
+ """
+ Sets the object's drawing mode. The drawing mode can be a mix of modes. To
+ enable these, add up the values.
+ @type drawmode: Integer
+ @param drawmode: A sum of the following:
+ - 2 - axis
+ - 4 - texspace
+ - 8 - drawname
+ - 16 - drawimage
+ - 32 - drawwire
+ - 64 - xray
+ """
+
+ def setDrawType(drawtype):
+ """
+ Sets the object's drawing type.
+ @type drawtype: Integer
+ @param drawtype: One of the following:
+ - 1 - Bounding box
+ - 2 - Wire
+ - 3 - Solid
+ - 4 - Shaded
+ - 5 - Textured
+ """
+
+ def setEuler(euler):
+ """
+ Sets the object's localspace rotation according to the specified Euler angles.
+ @type euler: Py_Euler or a list of floats
+ @param euler: a python Euler or x,y,z rotations as floats
+ """
+
+ def setIpo(ipo):
+ """
+ Links an ipo to this object.
+ @type ipo: Blender Ipo
+ @param ipo: an object type ipo.
+ """
+
+ def setLocation(x, y, z):
+ """
+ Sets the object's location relative to the parent object (if any).
+ @type x: float
+ @param x: The X coordinate of the new location.
+ @type y: float
+ @param y: The Y coordinate of the new location.
+ @type z: float
+ @param z: The Z coordinate of the new location.
+ """
+
+ def setMaterials(materials):
+ """
+ Sets the materials. The argument must be a list 16 items or less. Each
+ list element is either a Material or None. Also see L{colbits}.
+ @type materials: Materials list
+ @param materials: A list of Blender material objects.
+ @note: Materials are assigned to the object's data by default. Unless
+ you know the material is applied to the object or are changing the
+ object's L{colbits}, you need to look at the object data's materials.
+ """
+
+ def setMatrix(matrix):
+ """
+ Sets the object's matrix and updates its transformation. If the object
+ has a parent, the matrix transform is relative to the parent.
+ @type matrix: Py_Matrix 3x3 or 4x4
+ @param matrix: a 3x3 or 4x4 Python matrix. If a 3x3 matrix is given,
+ it is extended to a 4x4 matrix.
+ @Note: This method is "bad": when called it changes the location,
+ rotation and size attributes of the object (since Blender uses these
+ values to calculate the object's transformation matrix). Ton is
+ not happy having a method which "pretends" to do a matrix operation.
+ In the future, this method may be replaced with other methods which
+ make it easier for the user to determine the correct loc/rot/size values
+ for necessary for the object.
+ """
+
+ def setName(name):
+ """
+ Sets the name of the object. A string longer than 20 characters will be shortened.
+ @type name: String
+ @param name: The new name for the object.
+ """
+
+ def setSize(x, y, z):
+ """
+ Sets the object's size, relative to the parent object (if any), clamped
+ @type x: float
+ @param x: The X size multiplier.
+ @type y: float
+ @param y: The Y size multiplier.
+ @type z: float
+ @param z: The Z size multiplier.
+ """
+
+ def setTimeOffset(timeOffset):
+ """
+ Sets the time offset of the object's animation.
+ @type timeOffset: float
+ @param timeOffset: The new time offset for the object's animation.
+ """
+
+ def shareFrom(object):
+ """
+ Link data of a specified argument with this object. This works only
+ if both objects are of the same type.
+ @type object: Blender Object
+ @param object: A Blender Object of the same type.
+ @note: This function is faster than using L{getData()} and setData()
+ because it skips making a Python object from the object's data.
+ """
+
+ def select(boolean):
+ """
+ Sets the object's selection state in the current scene.
+ setting the selection will make this object the active object of this scene.
+ @type boolean: Integer
+ @param boolean:
+ - 0 - unselected
+ - 1 - selected
+ """
+
+ def getBoundBox():
+ """
+ Returns the worldspace bounding box of this object. This works for meshes (out of
+ edit mode) and curves.
+ @rtype: list of 8 (x,y,z) float coordinate vectors (WRAPPED DATA)
+ @return: The coordinates of the 8 corners of the bounding box. Data is wrapped when
+ bounding box is present.
+ """
+
+ def makeDisplayList():
+ """
+ Updates this object's display list. Blender uses display lists to store
+ already transformed data (like a mesh with its vertices already modified
+ by coordinate transformations and armature deformation). If the object
+ isn't modified, there's no need to recalculate this data. This method is
+ here for the *few cases* where a script may need it, like when toggling
+ the "SubSurf" mode for a mesh:
+
+ Example::
+ import Blender
+
+ scn = Blender.Scene.GetCurrent()
+ object = scn.objects.active
+ object.modifiers.append(Blender.Modifier.Type.SUBSURF)
+ object.makeDisplayList()
+ Blender.Window.RedrawAll()
+
+ If you try this example without the line to update the display list, the
+ object will disappear from the screen until you press "SubSurf".
+ @warn: If after running your script objects disappear from the screen or
+ are not displayed correctly, try this method function. But if the script
+ works properly without it, there's no reason to use it.
+ """
+
+ def getScriptLinks (event):
+ """
+ Get a list with this Object's script links of type 'event'.
+ @type event: string
+ @param event: "FrameChanged", "Redraw" or "Render".
+ @rtype: list
+ @return: a list with Blender L{Text} names (the script links of the given
+ 'event' type) or None if there are no script links at all.
+ """
+
+ def clearScriptLinks (links = None):
+ """
+ Delete script links from this Object. If no list is specified, all
+ script links are deleted.
+ @type links: list of strings
+ @param links: None (default) or a list of Blender L{Text} names.
+ """
+
+ def addScriptLink (text, event):
+ """
+ Add a new script link to this Object.
+ @type text: string
+ @param text: the name of an existing Blender L{Text}.
+ @type event: string
+ @param event: "FrameChanged", "Redraw" or "Render".
+ """
+
+ def makeTrack (tracked, fast = 0):
+ """
+ Make this Object track another.
+ @type tracked: Blender Object
+ @param tracked: the object to be tracked.
+ @type fast: int (bool)
+ @param fast: if zero, the scene hierarchy is updated automatically. If
+ you set 'fast' to a nonzero value, don't forget to update the scene
+ yourself (see L{Scene.Scene.update}).
+ @note: you also need to clear the rotation (L{setEuler}) of this object
+ if it was not (0,0,0) already.
+ """
+
+ def clearTrack (mode = 0, fast = 0):
+ """
+ Make this Object not track another anymore.
+ @type mode: int (bool)
+ @param mode: if nonzero the matrix transformation used for tracking is kept.
+ @type fast: int (bool)
+ @param fast: if zero, the scene hierarchy is updated automatically. If
+ you set 'fast' to a nonzero value, don't forget to update the scene
+ yourself (see L{Scene.Scene.update}).
+ """
+
+ def getAllProperties ():
+ """
+ Return a list of all game properties from this object.
+ @rtype: PyList
+ @return: List of Property objects.
+ """
+
+ def getProperty (name):
+ """
+ Return a game property from this object matching the name argument.
+ @type name: string
+ @param name: the name of the property to get.
+ @rtype: Property object
+ @return: The first property that matches name.
+ """
+
+ def addProperty (name_or_property, data, type):
+ """
+ Add or create a game property for an object. If called with only a
+ property object, the property is assigned to the object. If called
+ with a property name string and data object, a new property is
+ created and added to the object.
+ @type name_or_property: string or Property object
+ @param name_or_property: the property name, or a property object.
+ @type data: string, int or float
+ @param data: Only valid when I{name_or_property} is a string.
+ Value depends on what is passed in:
+ - string: string type property
+ - int: integer type property
+ - float: float type property
+ @type type: string (optional)
+ @param type: Only valid when I{name_or_property} is a string.
+ Can be the following:
+ - 'BOOL'
+ - 'INT'
+ - 'FLOAT'
+ - 'TIME'
+ - 'STRING'
+ @warn: If a type is not declared string data will
+ become string type, int data will become int type
+ and float data will become float type. Override type
+ to declare bool type, and time type.
+ @warn: A property object can be added only once to an object;
+ you must remove the property from an object to add it elsewhere.
+ """
+
+ def removeProperty (property):
+ """
+ Remove a game property from an object.
+ @type property: Property object or string
+ @param property: Property object or property name to be removed.
+ """
+
+ def removeAllProperties():
+ """
+ Removes all game properties from an object.
+ """
+
+ def copyAllPropertiesTo (object):
+ """
+ Copies all game properties from one object to another.
+ @type object: Object object
+ @param object: Object that will receive the properties.
+ """
+
+ def getPIStregth():
+ """
+ Get the Object's Particle Interaction Strength.
+ @rtype: float
+ """
+
+ def setPIStrength(strength):
+ """
+ Set the Object's Particle Interaction Strength.
+ Values between -1000.0 to 1000.0
+ @rtype: None
+ @type strength: float
+ @param strength: the Object's Particle Interaction New Strength.
+ """
+
+ def getPIFalloff():
+ """
+ Get the Object's Particle Interaction falloff.
+ @rtype: float
+ """
+
+ def setPIFalloff(falloff):
+ """
+ Set the Object's Particle Interaction falloff.
+ Values between 0 to 10.0
+ @rtype: None
+ @type falloff: float
+ @param falloff: the Object's Particle Interaction New falloff.
+ """
+
+ def getPIMaxDist():
+ """
+ Get the Object's Particle Interaction MaxDist.
+ @rtype: float
+ """
+
+ def setPIMaxDist(MaxDist):
+ """
+ Set the Object's Particle Interaction MaxDist.
+ Values between 0 to 1000.0
+ @rtype: None
+ @type MaxDist: float
+ @param MaxDist: the Object's Particle Interaction New MaxDist.
+ """
+
+ def getPIType():
+ """
+ Get the Object's Particle Interaction Type.
+ @rtype: int
+ """
+
+ def setPIType(type):
+ """
+ Set the Object's Particle Interaction type.
+ Use Module Constants
+ - NONE
+ - WIND
+ - FORCE
+ - VORTEX
+ - MAGNET
+ @rtype: None
+ @type type: int
+ @param type: the Object's Particle Interaction Type.
+ """
+
+ def getPIUseMaxDist():
+ """
+ Get the Object's Particle Interaction if using MaxDist.
+ @rtype: int
+ """
+
+ def setPIUseMaxDist(status):
+ """
+ Set the Object's Particle Interaction MaxDist.
+ 0 = Off, 1 = on
+ @rtype: None
+ @type status: int
+ @param status: the new status
+ """
+
+ def getPIDeflection():
+ """
+ Get the Object's Particle Interaction Deflection Setting.
+ @rtype: int
+ """
+
+ def setPIDeflection(status):
+ """
+ Set the Object's Particle Interaction Deflection Setting.
+ 0 = Off, 1 = on
+ @rtype: None
+ @type status: int
+ @param status: the new status
+ """
+
+ def getPIPermf():
+ """
+ Get the Object's Particle Interaction Permeability.
+ @rtype: float
+ """
+
+ def setPIPerm(perm):
+ """
+ Set the Object's Particle Interaction Permeability.
+ Values between 0 to 10.0
+ @rtype: None
+ @type perm: float
+ @param perm: the Object's Particle Interaction New Permeability.
+ """
+
+ def getPIRandomDamp():
+ """
+ Get the Object's Particle Interaction RandomDamp.
+ @rtype: float
+ """
+
+ def setPIRandomDamp(damp):
+ """
+ Set the Object's Particle Interaction RandomDamp.
+ Values between 0 to 10.0
+ @rtype: None
+ @type damp: float
+ @param damp: the Object's Particle Interaction New RandomDamp.
+ """
+
+ def getPISurfaceDamp():
+ """
+ Get the Object's Particle Interaction SurfaceDamp.
+ @rtype: float
+ """
+
+ def setPISurfaceDamp(damp):
+ """
+ Set the Object's Particle Interaction SurfaceDamp.
+ Values between 0 to 10.0
+ @rtype: None
+ @type damp: float
+ @param damp: the Object's Particle Interaction New SurfaceDamp.
+ """
+
+ def getSBMass():
+ """
+ Get the Object's SoftBody Mass.
+ @rtype: float
+ """
+
+ def setSBMass(mass):
+ """
+ Set the Object's SoftBody Mass.
+ Values between 0 to 50.0
+ @rtype: None
+ @type mass: float
+ @param mass: the Object's SoftBody New mass.
+ """
+
+ def getSBGravity():
+ """
+ Get the Object's SoftBody Gravity.
+ @rtype: float
+ """
+
+ def setSBGravity(grav):
+ """
+ Set the Object's SoftBody Gravity.
+ Values between 0 to 10.0
+ @rtype: None
+ @type grav: float
+ @param grav: the Object's SoftBody New Gravity.
+ """
+
+ def getSBFriction():
+ """
+ Get the Object's SoftBody Friction.
+ @rtype: float
+ """
+
+ def setSBFriction(frict):
+ """
+ Set the Object's SoftBody Friction.
+ Values between 0 to 10.0
+ @rtype: None
+ @type frict: float
+ @param frict: the Object's SoftBody New Friction.
+ """
+
+ def getSBErrorLimit():
+ """
+ Get the Object's SoftBody ErrorLimit.
+ @rtype: float
+ """
+
+ def setSBErrorLimit(err):
+ """
+ Set the Object's SoftBody ErrorLimit.
+ Values between 0 to 1.0
+ @rtype: None
+ @type err: float
+ @param err: the Object's SoftBody New ErrorLimit.
+ """
+
+ def getSBGoalSpring():
+ """
+ Get the Object's SoftBody GoalSpring.
+ @rtype: float
+ """
+
+ def setSBGoalSpring(gs):
+ """
+ Set the Object's SoftBody GoalSpring.
+ Values between 0 to 0.999
+ @rtype: None
+ @type gs: float
+ @param gs: the Object's SoftBody New GoalSpring.
+ """
+
+ def getSBGoalFriction():
+ """
+ Get the Object's SoftBody GoalFriction.
+ @rtype: float
+ """
+
+ def setSBGoalFriction(gf):
+ """
+ Set the Object's SoftBody GoalFriction.
+ Values between 0 to 10.0
+ @rtype: None
+ @type gf: float
+ @param gf: the Object's SoftBody New GoalFriction.
+ """
+
+ def getSBMinGoal():
+ """
+ Get the Object's SoftBody MinGoal.
+ @rtype: float
+ """
+
+ def setSBMinGoal(mg):
+ """
+ Set the Object's SoftBody MinGoal.
+ Values between 0 to 1.0
+ @rtype: None
+ @type mg: float
+ @param mg: the Object's SoftBody New MinGoal.
+ """
+
+ def getSBMaxGoal():
+ """
+ Get the Object's SoftBody MaxGoal.
+ @rtype: float
+ """
+
+ def setSBMaxGoal(mg):
+ """
+ Set the Object's SoftBody MaxGoal.
+ Values between 0 to 1.0
+ @rtype: None
+ @type mg: float
+ @param mg: the Object's SoftBody New MaxGoal.
+ """
+
+ def getSBInnerSpring():
+ """
+ Get the Object's SoftBody InnerSpring.
+ @rtype: float
+ """
+
+ def setSBInnerSpring(sprr):
+ """
+ Set the Object's SoftBody InnerSpring.
+ Values between 0 to 0.999
+ @rtype: None
+ @type sprr: float
+ @param sprr: the Object's SoftBody New InnerSpring.
+ """
+
+ def getSBInnerSpringFriction():
+ """
+ Get the Object's SoftBody InnerSpringFriction.
+ @rtype: float
+ """
+
+ def setSBInnerSpringFriction(sprf):
+ """
+ Set the Object's SoftBody InnerSpringFriction.
+ Values between 0 to 10.0
+ @rtype: None
+ @type sprf: float
+ @param sprf: the Object's SoftBody New InnerSpringFriction.
+ """
+
+ def getSBDefaultGoal():
+ """
+ Get the Object's SoftBody DefaultGoal.
+ @rtype: float
+ """
+
+ def setSBDefaultGoal(goal):
+ """
+ Set the Object's SoftBody DefaultGoal.
+ Values between 0 to 1.0
+ @rtype: None
+ @type goal: float
+ @param goal: the Object's SoftBody New DefaultGoal.
+ """
+
+ def isSB():
+ """
+ Returns the Object's SoftBody enabled state.
+ @rtype: boolean
+ """
+
+ def getSBPostDef():
+ """
+ get SoftBodies PostDef option
+ @rtype: int
+ """
+
+ def setSBPostDef(switch):
+ """
+ Enable / Disable SoftBodies PostDef option
+ 1: on
+ 0: off
+ @rtype: None
+ @type switch: int
+ @param switch: the Object's SoftBody New PostDef Value.
+ """
+
+ def getSBUseGoal():
+ """
+ get SoftBodies UseGoal option
+ @rtype: int
+ """
+
+ def setSBUseGoal(switch):
+ """
+ Enable / Disable SoftBodies UseGoal option
+ 1: on
+ 0: off
+ @rtype: None
+ @type switch: int
+ @param switch: the Object's SoftBody New UseGoal Value.
+ """
+ def getSBUseEdges():
+ """
+ get SoftBodies UseEdges option
+ @rtype: int
+ """
+
+ def setSBUseEdges(switch):
+ """
+ Enable / Disable SoftBodies UseEdges option
+ 1: on
+ 0: off
+ @rtype: None
+ @type switch: int
+ @param switch: the Object's SoftBody New UseEdges Value.
+ """
+
+ def getSBStiffQuads():
+ """
+ get SoftBodies StiffQuads option
+ @rtype: int
+ """
+
+ def setSBStiffQuads(switch):
+ """
+ Enable / Disable SoftBodies StiffQuads option
+ 1: on
+ 0: off
+ @rtype: None
+ @type switch: int
+ @param switch: the Object's SoftBody New StiffQuads Value.
+ """
+
+
+class Property:
+ """
+ The Property object
+ ===================
+ This property gives access to object property data in Blender, used by the game engine.
+ @ivar name: The property name.
+ @ivar data: Data for this property. Depends on property type.
+ @ivar type: The property type.
+ @warn: Comparisons between properties will only be true when
+ both the name and data pairs are the same.
+ """
+
+ def getName ():
+ """
+ Get the name of this property.
+ @rtype: string
+ @return: The property name.
+ """
+
+ def setName (name):
+ """
+ Set the name of this property.
+ @type name: string
+ @param name: The new name of the property
+ """
+
+ def getData():
+ """
+ Get the data for this property.
+ @rtype: string, int, or float
+ """
+
+ def setData(data):
+ """
+ Set the data for this property.
+ @type data: string, int, or float
+ @param data: The data to set for this property.
+ @warn: See object.setProperty(). Changing data
+ which is of a different type then the property is
+ set to (i.e. setting an int value to a float type'
+ property) will change the type of the property
+ automatically.
+ """
+
+ def getType ():
+ """
+ Get the type for this property.
+ @rtype: string
+ """
+
+import id_generics
+Object.__doc__ += id_generics.attributes
diff --git a/source/blender/python/api2_2x/doc/Pose.py b/source/blender/python/api2_2x/doc/Pose.py
new file mode 100644
index 00000000000..ad1b44da5e2
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Pose.py
@@ -0,0 +1,245 @@
+# Blender.Object.Pose module
+
+"""
+The Blender.Object.Pose submodule.
+
+Pose
+====
+
+This module provides access to B{Pose} objects in Blender. This Pose is the
+current object-level (as opposed to armature-data level) transformation.
+
+Example::
+ import Blender
+ from Blender import *
+
+
+ scn= Scene.GetCurrent()
+
+ # New Armature
+ arm_data= Armature.New('myArmature')
+ print arm_data
+ arm_ob = scn.objects.new(arm_data)
+ arm_data.makeEditable()
+
+
+ # Add 4 bones
+ ebones = [Armature.Editbone(), Armature.Editbone(), Armature.Editbone(), Armature.Editbone()]
+
+ # Name the editbones
+ ebones[0].name = 'Bone.001'
+ ebones[1].name = 'Bone.002'
+ ebones[2].name = 'Bone.003'
+ ebones[3].name = 'Bone.004'
+
+ # Assign the editbones to the armature
+ for eb in ebones:
+ arm_data.bones[eb.name]= eb
+
+ # Set the locations of the bones
+ ebones[0].head= Mathutils.Vector(0,0,0)
+ ebones[0].tail= Mathutils.Vector(0,0,1)
+ ebones[1].head= Mathutils.Vector(0,0,1)
+ ebones[1].tail= Mathutils.Vector(0,0,2)
+ ebones[2].head= Mathutils.Vector(0,0,2)
+ ebones[2].tail= Mathutils.Vector(0,0,3)
+ ebones[3].head= Mathutils.Vector(0,0,3)
+ ebones[3].tail= Mathutils.Vector(0,0,4)
+
+ ebones[1].parent= ebones[0]
+ ebones[2].parent= ebones[1]
+ ebones[3].parent= ebones[2]
+
+ arm_data.update()
+ # Done with editing the armature
+
+
+ # Assign the pose animation
+ pose = arm_ob.getPose()
+
+ act = arm_ob.getAction()
+ if not act: # Add a pose action if we dont have one
+ act = Armature.NLA.NewAction()
+ act.setActive(arm_ob)
+
+ xbones=arm_ob.data.bones.values()
+ pbones = pose.bones.values()
+ print xbones
+ print pbones
+
+
+ frame = 1
+ for pbone in pbones: # set bones to no rotation
+ pbone.quat[:] = 1.000,0.000,0.000,0.0000
+ pbone.insertKey(arm_ob, frame, Object.Pose.ROT)
+
+ # Set a different rotation at frame 25
+ pbones[0].quat[:] = 1.000,0.1000,0.2000,0.20000
+ pbones[1].quat[:] = 1.000,0.6000,0.5000,0.40000
+ pbones[2].quat[:] = 1.000,0.1000,0.3000,0.40000
+ pbones[3].quat[:] = 1.000,-0.2000,-0.3000,0.30000
+
+ frame = 25
+ for i in xrange(4):
+ pbones[i].insertKey(arm_ob, frame, Object.Pose.ROT)
+
+ pbones[0].quat[:] = 1.000,0.000,0.000,0.0000
+ pbones[1].quat[:] = 1.000,0.000,0.000,0.0000
+ pbones[2].quat[:] = 1.000,0.000,0.000,0.0000
+ pbones[3].quat[:] = 1.000,0.000,0.000,0.0000
+
+
+ frame = 50
+ for pbone in pbones: # set bones to no rotation
+ pbone.quat[:] = 1.000,0.000,0.000,0.0000
+ pbone.insertKey(arm_ob, frame, Object.Pose.ROT)
+
+
+
+@var ROT:
+@type ROT: Constant
+@var LOC:
+@type LOC: Constant
+@var SIZE:
+@type SIZE: Constant
+"""
+
+class Pose:
+ """
+ The Pose object
+ ===============
+ This object gives access to Pose-specific data in Blender.
+ @ivar bones: A Dictionary of PosePoseBones (PoseDict) that make up this Pose.
+ @type bones: PoseDict Object
+ """
+
+ def update():
+ """
+ Save all changes and update the Pose.
+ @rtype: None
+ """
+
+class PoseBonesDict:
+ """
+ The PoseBonesDict object
+ ========================
+ This object gives dictionary like access to the PoseBones in a Pose.
+ It is internal to blender but is called as 'Pose.bones'
+ """
+
+ def items():
+ """
+ Return the key, value pairs in this dictionary
+ @rtype: string, PosePoseBone
+ @return: All strings, and PosePoseBones in the Pose (in that order)
+ """
+
+ def keys():
+ """
+ Return the keys in this dictionary
+ @rtype: string
+ @return: All strings representing the PosePoseBone names
+ """
+
+ def values():
+ """
+ Return the values in this dictionary
+ @rtype: BPy_PoseBone
+ @return: All PosePoseBones in this dictionary
+ """
+
+class PoseBone:
+ """
+ The PoseBone object
+ ===================
+ This object gives access to PoseBone-specific data in Blender.
+ @ivar name: The name of this PoseBone.
+ @type name: String
+ @ivar loc: The change in location for this PoseBone. this is the equivilent of bone.getLoc() in the old 2.3x python api.
+ @type loc: Vector object
+ @ivar size: The change in size for this PoseBone (no change is 1,1,1)
+ @type size: Vector object
+ @ivar quat: The change in rotation for this PoseBone.
+ @type quat: Quaternion object
+ @ivar head: The final head location for this PoseBone. (not settable)
+ @type head: Vector object
+ @ivar tail: The final tail location for this PoseBone. (not settable)
+ @type tail: Vector object
+ @ivar sel: The selection state of this bone
+ @type sel: Boolean
+ @ivar parent: The parent of this posebone (not settable)
+ @type parent: posebone or None
+ @ivar displayObject: The object to display in place of the bone. (custom bones)
+ @type displayObject: Object or None
+ @ivar localMatrix: The matrix combination of rot/size/loc.
+ @type localMatrix: Matrix object
+ @ivar poseMatrix: The total transformation of this PoseBone including constraints.
+
+ This matrix is in armature space, for the current worldspace location of this pose bone, multiply
+ it with its objects worldspace matrix.
+
+ eg. pose_bone.poseMatrix * object.matrixWorld
+
+ Setting the poseMatrix only sets the loc/size/rot, before constraints are applied (similar to actions).
+ After setting pose matrix, run pose.update() to re-evaluate the pose and see the changes in the 3d view.
+
+ @type poseMatrix: Matrix object
+ @type constraints: BPy_ConstraintSeq
+ @ivar constraints: a sequence of constraints for the object
+ @type limitmin: 3-item sequence
+ @ivar limitmin: The x,y,z minimum limits on rotation when part of an IK
+ @type limitmax: 3-item sequence
+ @ivar limitmax: The x,y,z maximum limits on rotation when part of an IK
+
+ @type hasIK: bool
+ @ivar hasIK: True if this pose bone is a part of an IK (readonly), when False, other IK related values have no affect.
+
+ @type stretch: float
+ @ivar stretch: The amount to stretch to the ik target when part of an IK [0.0 - 1.0]
+
+ @type stiffX: float
+ @ivar stiffX: The x stiffness when part of an IK [0.0 - 0.990]
+ @type stiffY: float
+ @ivar stiffY: The x stiffness when part of an IK [0.0 - 0.990]
+ @type stiffZ: float
+ @ivar stiffZ: The x stiffness when part of an IK [0.0 - 0.990]
+
+ @type limitX: bool
+ @ivar limitX: Limit rotation over X axis when part of an IK.
+ @type limitY: bool
+ @ivar limitY: Limit rotation over Y axis when part of an IK.
+ @type limitZ: bool
+ @ivar limitZ: Limit rotation over Z axis when part of an IK.
+
+ @type lockXRot: bool
+ @ivar lockXRot: Disable X DoF when part of an IK.
+ @type lockYRot: bool
+ @ivar lockYRot: Disable Y DoF when part of an IK.
+ @type lockZRot: bool
+ @ivar lockZRot: Disable Z DoF when part of an IK.
+ @ivar layerMask: Layer bitmask
+ Example::
+ # set bone to layers 14 and 16
+ bone.layerMask = (1<<13) + (1<<15)
+ @type layerMask: Int
+ """
+
+ def insertKey(parentObject, frameNumber, type = "[Pose.LOC, Pose.ROT, Pose.SIZE]", fast = False):
+ """
+ Insert a pose key for this PoseBone at a frame.
+ @type parentObject: Object object
+ @param parentObject: The object the pose came from.
+ @type frameNumber: integer
+ @param frameNumber: The frame number to insert the pose key on.
+ @type type: Constant object
+ @param type: Optional argumentm.
+ Can be any combination of 3 Module constants:
+ - Pose.LOC
+ - Pose.ROT (This adds keyframes to the quat ipo, since quaternions are used for pose bone rotation)
+ - Pose.SIZE
+ If this argument is omitted all keys will be added.
+ @type fast: Bool
+ @param fast: If enabled, the IPOs will not be recalculated, speeds up adding many keyframes at once.
+ @rtype: None
+ """
+
diff --git a/source/blender/python/api2_2x/doc/Radio.py b/source/blender/python/api2_2x/doc/Radio.py
new file mode 100644
index 00000000000..f336ea56765
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Radio.py
@@ -0,0 +1,351 @@
+# Blender.Scene.Radio module and the Radiosity PyType object
+
+"""
+The Blender.Scene.Radio submodule.
+
+Radio
+=====
+
+This module gives access to B{Scene Radiosity Contexts} in Blender.
+
+Example::
+ import Blender
+ from Blender import Scene
+
+ # Only the current scene has a radiosity context.
+ # Naturally, any scene can be made the current one
+ # with scene.makeCurrent()
+
+ scn = Scene.GetCurrent()
+
+ # this is the only way to access the radiosity object:
+
+ radio = scn.getRadiosityContext()
+
+ radio.setDrawType('Gouraud')
+ radio.setMode('ShowLimits', 'Z')
+
+ radio.collectMeshes() # prepare patches
+ radio.go() # calculate radiosity
+ Blender.Redraw(-1)
+
+
+@type Modes: readonly dictionary
+@var Modes:
+ - ShowLimits
+ - Z
+
+@type DrawTypes: readonly dictionary
+@var DrawTypes:
+ - Wire
+ - Solid
+ - Gouraud
+"""
+
+class Radio:
+ """
+ The Radiosity object
+ ====================
+ This object wraps the current Scene's radiosity context in Blender.
+ """
+
+ def go():
+ """
+ Start the radiosity simulation. It is necessary to call L{collectMeshes}
+ first.
+ """
+
+ def collectMeshes():
+ """
+ Convert B{selected} visible meshes to patches for radiosity calculation.
+ @note: L{Object.Object.select} can be used to (un)select objects via
+ bpython.
+ """
+
+ def freeData():
+ """
+ Release all memory used by radiosity.
+ """
+
+ def addMesh():
+ """
+ Add the new mesh created by the radiosity simulation (see L{go}) to
+ Blender. The radiosity results are stored in this mesh's vertex colors.
+ @note: see L{replaceMeshes} for a destructive alternative.
+ """
+
+ def replaceMeshes():
+ """
+ Replace the original input meshes with the B{one} calculated by the
+ radiosity simulation. The radiosity results are stored in this mesh's
+ vertex colors.
+ @note: see L{addMesh} for a non-destructive alternative.
+ """
+
+ def limitSubdivide():
+ """
+ Subdivide patches (optional, it may improve results).
+ """
+
+ def filterFaces():
+ """
+ Force an extra smoothing. This method can be called only after the
+ simulation has been calculated (L{go}).
+ """
+
+ def filterElems():
+ """
+ Filter elements to remove aliasing artifacts. This method can be called
+ only after the simulation has been calculated (L{go}).
+ """
+
+ def subdividePatches():
+ """
+ Pre-subdivision: detect high-energy patches and subdivide them
+ (optional, it may improve results).
+ """
+
+ def subdivideElems():
+ """
+ Pre-subdivision: detect high-energy elements (nodes) and subdivide them
+ (optional, it may improve results).
+ """
+
+ def removeDoubles():
+ """
+ Join elements (nodes) which differ less than the defined element limit.
+ This method can be called only after the simulation has been calculated
+ (L{go}).
+ """
+
+ def getHemiRes():
+ """
+ Get hemicube size.
+ @rtype: int
+ @return: the current hemicube size.
+ """
+
+ def setHemiRes(ival):
+ """
+ Set hemicube size. The range is [100, 1000].
+ @type ival: int
+ @param ival: the new size.
+ """
+
+ def getMaxIter():
+ """
+ Get maximum number of radiosity rounds.
+ @rtype: int
+ @return: the current maxiter value.
+ """
+
+ def setMaxIter(ival):
+ """
+ Set maximum number of radiosity rounds. The range is [0, 10000].
+ @type ival: int
+ @param ival: the maxiter new value.
+ """
+
+ def getSubShPatch():
+ """
+ Get maximum number of times the environment is tested to detect patches.
+ @rtype: int
+ @return: the current value.
+ """
+
+ def setSubShPatch(ival):
+ """
+ Set the maximum number of times the environment is tested to detect
+ patches. The range is [0, 10].
+ @type ival: int
+ @param ival: the new value.
+ """
+
+ def getSubShElem():
+ """
+ Get the number of times the environment is tested to detect elements.
+ @rtype: int
+ @return: the current value.
+ """
+
+ def setSubShElem(ival):
+ """
+ Set number of times the environment is tested to detect elements. The
+ range is [0, 10].
+ @type ival: int
+ @param ival: the new value.
+ """
+
+ def getElemLimit():
+ """
+ Get the range for removing doubles.
+ @rtype: int
+ @return: the current value.
+ """
+
+ def setElemLimit(ival):
+ """
+ Set the range for removing doubles. The range is [0, 50].
+ @type ival: int
+ @param ival: the new value.
+ """
+
+ def getMaxSubdivSh():
+ """
+ Get the maximum number of initial shoot patches evaluated.
+ @rtype: int
+ @return: the current value.
+ """
+
+ def setMaxSubdivSh(ival):
+ """
+ Set the maximum number of initial shoot patches evaluated. The range is
+ [1, 250].
+ @type ival: int
+ @param ival: the new value.
+ """
+
+ def getPatchMax():
+ """
+ Get the maximum size of a patch.
+ @rtype: int
+ @return: the current value.
+ """
+
+ def setPatchMax(ival):
+ """
+ Set the maximum size of a patch. The range is [10, 1000].
+ @type ival: int
+ @param ival: the new value.
+ """
+
+ def getPatchMin():
+ """
+ Get the minimum size of a patch.
+ @rtype: int
+ @return: the current value.
+ """
+
+ def setPatchMin(ival):
+ """
+ Set the minimum size of a patch. The range is [10, 1000].
+ @type ival: int
+ @param ival: the new value.
+ """
+
+ def getElemMax():
+ """
+ Get the maximum size of an element.
+ @rtype: int
+ @return: the current value.
+ """
+
+ def setElemMax(ival):
+ """
+ Set the maximum size of an element. The range is [1, 100].
+ @type ival: int
+ @param ival: the new value.
+ """
+
+ def getElemMin():
+ """
+ Get the minimum size of an element. The range is [1, 100].
+ @rtype: int
+ @return: the current value.
+ """
+
+ def setElemMin(ival):
+ """
+ Set the minimum size of an element. The range is [1, 100].
+ @type ival: int
+ @param ival: the new value.
+ """
+
+ def getMaxElems():
+ """
+ Get the maximum number of elements.
+ @rtype: int
+ @return: the current value.
+ """
+
+ def setMaxElems(ival):
+ """
+ Set the maximum number of elements. The range is [1, 250000].
+ @type ival: int
+ @param ival: the new value.
+ """
+
+ def getConvergence():
+ """
+ Get lower thresholdo of unshot energy.
+ @rtype: float
+ @return: the current value.
+ """
+
+ def setConvergence(fval):
+ """
+ Set lower threshold of unshot energy. The range is [0.0, 1.0].
+ @type fval: float
+ @param fval: the new value.
+ """
+
+ def getMult():
+ """
+ Get the energy value multiplier.
+ @rtype: float
+ @return: the current value.
+ """
+
+ def setMult (fval):
+ """
+ Set the energy value multiplier. The range is [0.001, 250.0].
+ @type fval: float
+ @param fval: the new value.
+ """
+
+ def getGamma():
+ """
+ Get change in the contrast of energy values.
+ @rtype: float
+ @return: the current value.
+ """
+
+ def setGamma (fval):
+ """
+ Set change in the contrast of energy values. The range is [0.2, 10.0].
+ @type fval: float
+ @param fval: the new value.
+ """
+
+ def getDrawType():
+ """
+ Get the draw type: Wire, Solid or Gouraud as an int value, see L{DrawTypes}.
+ @rtype: int
+ @return: the current draw type.
+ """
+
+ def setDrawType (dt):
+ """
+ Set the draw type.
+ @type dt: string or int
+ @param dt: either 'Wire', 'Solid' or 'Gouraud' or the equivalent entry in
+ the L{DrawTypes} dictionary.
+ """
+
+ def getMode():
+ """
+ Get mode as an int (or'ed bitflags), see L{Modes} dictionary.
+ @rtype: int
+ @return: the current value.
+ """
+
+ def setMode (mode1 = None, mode2 = None):
+ """
+ Set mode flags as strings: 'ShowLimits' and 'Z'. To set one give it as
+ only argument. Strings not passed in are unset, so setMode() unsets
+ both.
+ @type mode1: string
+ @param mode1: optional mode string.
+ @type mode2: string
+ @param mode2: optional mode string.
+ """
diff --git a/source/blender/python/api2_2x/doc/Registry.py b/source/blender/python/api2_2x/doc/Registry.py
new file mode 100644
index 00000000000..02ac30e71ac
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Registry.py
@@ -0,0 +1,122 @@
+# Blender.Registry module
+
+"""
+The Blender.Registry submodule.
+
+B{New}: L{GetKey} and L{SetKey} have been updated to save and load scripts
+*configuration data* to files.
+
+Registry
+========
+
+This module provides a way to create, retrieve and edit B{persistent data} in
+Blender.
+
+When a script is executed it has its own private global dictionary,
+which is deleted when the script exits. This is done to avoid problems with
+name clashes and garbage collecting. But because of this, the data created by
+a script isn't kept after it leaves: the data is not persistent. The Registry
+module was created to give programmers a way around this limitation.
+
+Possible uses:
+ - saving arbitrary data from a script that itself or another one will need
+ to access later.
+ - saving configuration data for a script: users can view and edit this data
+ using the "Scripts Configuration Editor" script.
+ - saving the current state of a script's GUI (its button values) to restore it
+ when the script is executed again.
+
+Example::
+
+ import Blender
+ from Blender import Registry
+
+ # this function updates the Registry when we need to:
+ def update_Registry():
+ d = {}
+ d['myvar1'] = myvar1
+ d['myvar2'] = myvar2
+ d['mystr'] = mystr
+ # cache = True: data is also saved to a file
+ Blender.Registry.SetKey('MyScript', d, True)
+
+ # first declare global variables that should go to the Registry:
+ myvar1 = 0
+ myvar2 = 3.2
+ mystr = "hello"
+
+ # then check if they are already there (saved on a
+ # previous execution of this script):
+ rdict = Registry.GetKey('MyScript', True) # True to check on disk also
+ if rdict: # if found, get the values saved there
+ try:
+ myvar1 = rdict['myvar1']
+ myvar2 = rdict['myvar2']
+ mystr = rdict['mystr']
+ except: update_Registry() # if data isn't valid rewrite it
+
+ # ...
+ # here goes the main part of the script ...
+ # ...
+
+ # if at some point the data is changed, we update the Registry:
+ update_Registry()
+
+@note: In Python terms, the Registry holds a dictionary of dictionaries.
+ Technically any Python or BPython object can be stored: there are no
+ restrictions, but ...
+
+@note: We have a few recommendations:
+
+ Data saved to the Registry is kept in memory, so if you decide to store large
+ amounts your script users should be clearly informed about it --
+ always keep in mind that you have no idea about their resources and the
+ applications they are running at a given time (unless you are the only
+ user), so let them decide.
+
+ There are restrictions to the data that gets automatically saved to disk by
+ L{SetKey}(keyname, dict, True): this feature is only meant for simple data
+ (bools, ints, floats, strings and dictionaries or sequences of these types).
+
+ For more demanding needs, it's of course trivial to save data to another
+ file or to a L{Blender Text<Text>}.
+"""
+
+def Keys ():
+ """
+ Get all keys currently in the Registry's dictionary.
+ """
+
+def GetKey (key, cached = False):
+ """
+ Get key 'key' from the Registry.
+ @type key: string
+ @param key: a key from the Registry dictionary.
+ @type cached: bool
+ @param cached: if True and the requested key isn't already loaded in the
+ Registry, it will also be searched on the user or default scripts config
+ data dir (config subdir in L{Blender.Get}('datadir')).
+ @return: the dictionary called 'key'.
+ """
+
+def SetKey (key, dict, cache = False):
+ """
+ Store a new entry in the Registry.
+ @type key: string
+ @param key: the name of the new entry, tipically your script's name.
+ @type dict: dictionary
+ @param dict: a dict with all data you want to save in the Registry.
+ @type cache: bool
+ @param cache: if True the given key data will also be saved as a file
+ in the config subdir of the scripts user or default data dir (see
+ L{Blender.Get}).
+ @warn: as stated in the notes above, there are restrictions to what can
+ be automatically stored in config files.
+ """
+
+def RemoveKey (key):
+ """
+ Remove the dictionary with key 'key' from the Registry.
+ @type key: string
+ @param key: the name of an existing Registry key.
+ """
diff --git a/source/blender/python/api2_2x/doc/Render.py b/source/blender/python/api2_2x/doc/Render.py
new file mode 100644
index 00000000000..61c8eda9026
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Render.py
@@ -0,0 +1,1192 @@
+# Blender.Scene.Render module and the RenderData PyType object
+
+"""
+The Blender.Scene.Render submodule.
+
+Scene.Render
+============
+
+This module provides access to B{Scene Rendering Contexts} in Blender.
+
+Example::
+ import Blender
+ from Blender import *
+ from Blender.Scene import Render
+
+ scn = Scene.GetCurrent()
+ context = scn.getRenderingContext()
+
+ Render.EnableDispWin()
+ context.extensions = True
+ context.renderPath = "//myRenderdir/"
+ context.sizePreset(Render.PC)
+ context.imageType = Render.AVIRAW
+ context.sFrame = 2
+ context.eFrame = 10
+ context.renderAnim()
+
+ context.imageType = Render.TARGA
+ context.fps = 15
+ context.sFrame = 15
+ context.eFrame = 22
+ context.renderAnim()
+
+ Render.CloseRenderWindow()
+ print context.fps
+ print context.cFrame
+
+@type Modes: readonly dictionary
+@var Modes: Constant dict used for with L{RenderData.mode} bitfield attribute.
+Values can be ORed together. Individual bits can also be set/cleared with
+boolean attributes.
+ - OSA: Oversampling (anti-aliasing) enabled
+ - SHADOW: Shadow calculation enabled
+ - GAMMA: Gamma correction enabled
+ - ENVMAP: Environment map rendering enabled
+ - TOONSHADING: Toon edge shading enabled
+ - FIELDRENDER: Field rendering enabled
+ - FIELDTIME: Time difference in field calculations I{disabled}
+ - RADIOSITY: Radiosity rendering enabled
+ - BORDER_RENDER: Small cut-out rendering enabled
+ - PANORAMA: Panorama rendering enabled
+ - CROP: Crop image during border renders
+ - ODDFIELD: Odd field first rendering enabled
+ - MBLUR: Motion blur enabled
+ - UNIFIED: Unified Renderer enabled
+ - RAYTRACING: Ray tracing enabled
+ - THREADS: Render in two threads enabled (Deprecated, use L{RenderData.threads})
+
+@type SceModes: readonly dictionary
+@var SceModes: Constant dict used for with L{RenderData.sceneMode} bitfield attribute.
+Values can be ORed together. Individual bits can also be set/cleared with
+boolean attributes.
+ - SEQUENCER: Enables sequencer output rendering.
+ - EXTENSION: Adds extensions to the output when rendering animations.
+ - SAVE_BUFFERS: Save render tiles to disk to save memory.
+ - FREE_IMAGES: Free images used by textures after each render.
+
+@type FramingModes: readonly dictionary
+@var FramingModes: Constant dict used for with L{RenderData.gameFrame}
+attribute. One of the following modes can be active:
+ - BARS: Show the entire viewport in the display window, using bar
+ horizontally or vertically.
+ - EXTEND: Show the entire viewport in the display window, viewing more
+ horizontally or vertically
+ - SCALE: Stretch or squeeze the viewport to fill the display window.
+
+@var INTERNAL: The internal rendering engine. Use with setRenderer()
+@var YAFRAY: Yafray rendering engine. Use with setRenderer()
+
+@var AVIRAW: Output format. Use with renderdata.imageType / setImageType()
+@var AVIJPEG: Output format. Use with renderdata.imageType / setImageType()
+@var AVICODEC: Output format. Use with renderdata.imageType / setImageType()
+@var QUICKTIME: Output format. Use with renderdata.imageType / setImageType()
+@var TARGA: Output format. Use with renderdata.imageType / setImageType()
+@var RAWTGA: Output format. Use with renderdata.imageType / setImageType()
+@var HDR: Output format. Use with renderdata.imageType / setImageType()
+@var PNG: Output format. Use with renderdata.imageType / setImageType()
+@var BMP: Output format. Use with renderdata.imageType / setImageType()
+@var JPEG: Output format. Use with renderdata.imageType / setImageType()
+@var HAMX: Output format. Use with renderdata.imageType / setImageType()
+@var IRIS: Output format. Use with renderdata.imageType / setImageType()
+@var IRISZ: Output format. Use with renderdata.imageType / setImageType()
+@var FTYPE: Output format. Use with renderdata.imageType / setImageType()
+@var OPENEXR: Output format. Use with renderdata.imageType / setImageType()
+@var TIFF: Output format. Use with renderdata.imageType / setImageType()
+@var FFMPEG: Output format. Use with renderdata.imageType / setImageType()
+@var CINEON: Output format. Use with renderdata.imageType / setImageType()
+@var DPX: Output format. Use with renderdata.imageType / setImageType()
+
+@var PAL: Output format. Use with renderdata.sizePreset()
+@var NTSC: Output format. Use with renderdata.sizePreset()
+@var DEFAULT: Output format. Use with renderdata.sizePreset()
+@var PREVIEW: Output format. Use with renderdata.sizePreset()
+@var PC: Output format. Use with renderdata.sizePreset()
+@var PAL169: Output format. Use with renderdata.sizePreset()
+@var B_PR_FULL: Output format. Use with renderdata.sizePreset()
+
+@var NONE: Yafray GI Quality / Method. Use with renderdata.setYafrayGIQuality()
+@var LOW: Yafray GI Quality. Use with renderdata.setYafrayGIQuality()
+@var MEDIUM: Yafray GI Quality. Use with renderdata.setYafrayGIQuality()
+@var HIGH: Yafray GI Quality. Use with renderdata.setYafrayGIQuality()
+@var HIGHER: Yafray GI Quality. Use with renderdata.setYafrayGIQuality()
+@var BEST: Yafray GI Quality. Use with renderdata.setYafrayGIQuality()
+@var USEAOSETTINGS: Yafray GI Quality. Use with renderdata.setYafrayGIQuality()
+@var SKYDOME: Yafray GI Method. Use with renderdata.setYafrayGIMethod()
+@var GIFULL: Yafray GI Method. Use with renderdata.setYafrayGIMethod()
+"""
+
+def CloseRenderWindow():
+ """
+ Closes the rendering window.
+ """
+
+def EnableDispView():
+ """
+ Render in the 3d View area. B{Note} this method is deprecated;
+ use the l{displayMode} attribute instead.
+ """
+
+def EnableDispWin():
+ """
+ Render in Render window.
+ B{Note} this method is deprecated; use the l{displayMode} attribute instead.
+ """
+
+def SetRenderWinPos(locationList):
+ """
+ Set the position of the Render window on the screen.
+ Possible values are:
+ - S = south
+ - N = north
+ - W = west
+ - E = east
+ - C = center
+ - ne = northeast
+ - nw = northwest
+ - se = southeast
+ - sw = southwest
+ @type locationList: PyList of strings
+ @param locationList: a list of strings that together define
+ the location of the Render window on the screen.
+ """
+
+def EnableEdgeShift():
+ """
+ Globally with the unified renderer enabled the outlines of the render
+ are shifted a bit.
+ """
+
+def EnableEdgeAll():
+ """
+ Globally consider transparent faces for edge-rendering with the unified renderer.
+ """
+
+class RenderData:
+ """
+ The RenderData object
+ =====================
+ This object gives access to Scene rendering contexts in Blender.
+ @ivar unified: Unified Renderer enabled.
+ Also see B{UNIFIED} in L{Modes} constant dict.
+ @type unified: boolean
+ @ivar renderwinSize: Size of the rendering window. Valid values are 25, 50,
+ 75, or 100.
+ @type renderwinSize: int
+ @ivar xParts: Number of horizontal parts for image render.
+ Values are clamped to the range [2,512].
+ @type xParts: int
+ @ivar fieldRendering: Field rendering enabled.
+ Also see B{FIELDRENDER} in L{Modes} constant dict.
+ @type fieldRendering: boolean
+ @ivar gammaCorrection: Gamma correction enabled.
+ Also see B{GAMMA} in L{Modes} constant dict.
+ @type gammaCorrection: boolean
+ @ivar eFrame: Ending frame for rendering.
+ Values are clamped to the range [1,MAXFRAME].
+ @type eFrame: int
+ @ivar radiosityRender: Radiosity rendering enabled.
+ @type radiosityRender: boolean
+ @ivar sizeX: Image width (in pixels).
+ Values are clamped to the range [4,10000].
+ @type sizeX: int
+ @ivar shadow: Shadow calculation enabled.
+ Also see B{SHADOW} in L{Modes} constant dict.
+ @type shadow: boolean
+ @ivar aspectX: Horizontal aspect ratio.
+ Values are clamped to the range [1,200].
+ @type aspectX: int
+ @ivar mode: Mode bitfield. See L{Modes} constant dict for values.
+ @type mode: bitfield
+ @ivar fieldTimeDisable: Time difference in field calculations I{disabled}.
+ @type fieldTimeDisable: int
+ @ivar cFrame: The current frame for rendering.
+ Values are clamped to the range [1,MAXFRAME].
+ @type cFrame: int
+ @ivar crop: Crop image during border renders.
+ Also see B{CROP} in L{Modes} constant dict.
+ @type crop: boolean
+ @ivar sFrame: Starting frame for rendering.
+ Values are clamped to the range [1,MAXFRAME].
+ @type sFrame: int
+ @ivar backbuf: Backbuffer image enabled.
+ @type backbuf: boolean
+ @ivar OSALevel: Oversampling (anti-aliasing) level. Valid values are
+ 5, 8, 11, or 16.
+ @type OSALevel: int
+ @ivar displayMode: Render output in separate window or 3D view.
+ Valid values are 0 (display in image editor view), 1 (display in render
+ window), or 2 (display full screen).
+ @type displayMode: int
+ @ivar threads: Number of threads to render, clamed [1-8]
+ @type threads: int
+ @ivar backbufPath: Path to a background image (setting loads image).
+ @type backbufPath: string
+ @ivar toonShading: Toon edge shading enabled.
+ Also see B{TOONSHADING} in L{Modes} constant dict.
+ @type toonShading: boolean
+ @ivar sceneMode: Scene mode bitfield. See L{SceModes} constant dict for
+ values.
+ @type sceneMode: bitfield
+ @ivar gameFrameColor: RGB color triplet for bars.
+ Values are clamped in the range [0.0,1.0].
+ @type gameFrameColor: list of RGB 3 floats
+ @ivar sizeY: Image height (in pixels).
+ Values are clamped to the range [4,10000].
+ @type sizeY: int
+ @ivar renderer: Rendering engine choice.
+ Valid values are 0 (internal) or 1 (Yafray).
+ @type renderer: int
+
+ @ivar sequencer: Enables sequencer output rendering.
+ Also see B{SEQUENCER} in L{SceModes} constant dict.
+ @type sequencer: boolean
+ @ivar extensions: Add extensions to output (when rendering animations).
+ Also see B{EXTENSION} in L{SceModes} constant dict.
+ @type extensions: boolean
+ @ivar compositor: 'Do Compositor' enabled.
+ @type compositor: boolean
+ @ivar freeImages: 'Do Compositor' enabled.
+ @type freeImages: boolean
+ @ivar singleLayer: Only render the active layer.
+ @type singleLayer: boolean
+ @ivar saveBuffers: Save render buffers to disk while rendering, saves memory.
+ @type saveBuffers: boolean
+ @ivar compositeFree: Free nodes that are not used while composite.
+ @type compositeFree: boolean
+
+ @ivar panorama: Panorama rendering enabled.
+ Also see B{PANORAMA} in L{Modes} constant dict.
+ @type panorama: boolean
+ @ivar rayTracing: Ray tracing enabled.
+ Also see B{RAYTRACING} in L{Modes} constant dict.
+ @type rayTracing: boolean
+ @ivar renderPath: The path to output the rendered images.
+ @type renderPath: string
+ @ivar gameFrame: Game framing type. See L{FramingModes} constant dict.
+ @type gameFrame: int
+ @ivar aspectY: Vertical aspect ratio.
+ Values are clamped to the range [1,200].
+ @type aspectY: int
+ @ivar imageType: File format for saving images. See the module's constants
+ for values.
+ @type imageType: int
+ @ivar ftypePath: The path to Ftype file.
+ @type ftypePath: string
+ @ivar border: The border for border rendering. The format is
+ [xmin,ymin,xmax,ymax]. Values are clamped to [0.0,1.0].
+ @type border: list of 4 floats.
+ @ivar edgeColor: RGB color triplet for edges in Toon shading (unified
+ renderer).
+ Values are clamped in the range [0.0,1.0].
+ @type edgeColor: list of 3 RGB floats
+ @ivar yParts: Number of vertical parts for image render.
+ Values are clamped to the range [2,512].
+ @type yParts: int
+ @ivar imagePlanes: Image depth in bits. Valid values are 8, 24, or 32.
+ @type imagePlanes: int
+ @ivar borderRender: Small cut-out rendering enabled.
+ Also see B{BORDER_RENDER} in L{Modes} constant dict.
+ @type borderRender: boolean
+ @ivar oversampling: Oversampling (anti-aliasing) enabled.
+ Also see B{OSA} in L{Modes} constant dict.
+ @type oversampling: boolean
+ @ivar fps: Frames per second.
+ Values are clamped to the range [1,120].
+ @ivar fps_base: Frames per second base: used to generate fractional frames
+ per second values. For example, setting fps to 30 and fps_base to 1.001
+ will approximate the NTSC frame rate of 29.97 fps.
+ Values are clamped to the range [1,120].
+ @type fps_base: float
+ @ivar timeCode: Get the current frame in HH:MM:SS:FF format. Read-only.
+ @type timeCode: string
+ @ivar environmentMap: Environment map rendering enabled.
+ Also see B{ENVMAP} in L{Modes} constant dict.
+ @type environmentMap: boolean
+ @ivar motionBlur: Motion blur enabled.
+ Also see B{MBLUR} in L{Modes} constant dict.
+ @type motionBlur: boolean
+ @ivar oddFieldFirst: Odd field first rendering enabled.
+ Also see B{ODDFIELD} in L{Modes} constant dict.
+ @type oddFieldFirst: boolean
+ @ivar alphaMode: Setting for sky/background. Valid values are 0 (fill
+ background with sky), 1 (multiply alpha in advance), or 2 (alpha and color
+ values remain unchanged).
+ @type alphaMode: int
+ @ivar gaussFilter: Gauss filter size.
+ Values are clamped to the range [0.5,1.5].
+ @type gaussFilter: float
+ @ivar mblurFactor: Motion blur factor.
+ Values are clamped to the range [0.01,5.0].
+ @type mblurFactor: float
+ @ivar mapOld: Number of frames the Map Old will last
+ Values are clamped to the range [1,900].
+ @type mapOld: int
+ @ivar mapNew: New mapping value (in frames).
+ Values are clamped to the range [1,900].
+ @type mapNew: int
+ @ivar set: The scene linked as a set to this scene. Values are an existing
+ scene or None (setting to None clears the set). The scene argument cannot
+ cause a circular link.
+ @type set: BPy_Scene or None
+ @ivar yafrayGIMethod: Global Illumination method.
+ Valid values are NONE (0), SKYDOME (1) or FULL (2).
+ @type yafrayGIMethod: int {NONE (0), SKYDOME (1), GIFULL (2)}
+ @ivar yafrayGIQuality: Global Illumination quality.
+ @type yafrayGIQuality: int {NONE (0), LOW (1), MEDIUM (2), HIGH (3), HIGHER (4), BEST (5), USEAOSETTINGS (6)}
+ @ivar yafrayExportToXML: If true export to an xml file and call yafray instead of plugin.
+ @type yafrayExportToXML: boolean
+ @ivar yafrayAutoAntiAliasing: Automatic anti-aliasing enabled/disabled.
+ @type yafrayAutoAntiAliasing: boolean
+ @ivar yafrayClampRGB: Clamp RGB enabled/disabled.
+ @type yafrayClampRGB: boolean
+ @ivar yafrayAntiAliasingPasses: Number of anti-aliasing passes (0 is no Anti-Aliasing).
+ @type yafrayAntiAliasingPasses: int [0, 64]
+ @ivar yafrayAntiAliasingSamples: Number of samples per pass.
+ @type yafrayAntiAliasingSamples: int [0, 2048]
+ @ivar yafrayAntiAliasingPixelSize: Anti-aliasing pixel filter size.
+ @type yafrayAntiAliasingPixelSize: float [1.0, 2.0]
+ @ivar yafrayAntiAliasingThreshold: Anti-aliasing threshold.
+ @type yafrayAntiAliasingThreshold: float [0.05, 1.0]
+ @ivar yafrayNumberOfProcessors: Number of processors to use.
+ @type yafrayNumberOfProcessors: int [1, 8]
+ @ivar yafrayGICache: Cache occlusion/irradiance samples (faster).
+ @type yafrayGICache: boolean
+ @ivar yafrayGICacheBumpNormals: Enable/disable bumpnormals for cache.
+ @type yafrayGICacheBumpNormals: boolean
+ @ivar yafrayGICacheShadowQuality: Shadow quality, keep it under 0.95 :-).
+ @type yafrayGICacheShadowQuality: float [0.01, 1.0]
+ @ivar yafrayGICachePixelsPerSample: Maximum number of pixels without samples, the lower the better and slower.
+ @type yafrayGICachePixelsPerSample: int [1, 50]
+ @ivar yafrayGICacheRefinement: Threshold to refine shadows EXPERIMENTAL. 1 = no refinement.
+ @type yafrayGICacheRefinement: float [0.001, 1.0]
+ @ivar yafrayGIPhotons: Enable/disable use of global photons to help in GI.
+ @type yafrayGIPhotons: boolean
+ @ivar yafrayGITunePhotons: If true the photonmap is shown directly in the render for tuning.
+ @type yafrayGITunePhotons: boolean
+ """
+
+ def currentFrame(frame = None):
+ """
+ Get/set the current frame.
+ @type frame: int (optional)
+ @param frame: must be between 1 - 30000
+ @rtype: int (if prototype is empty)
+ @return: Current frame for the scene.
+ """
+
+ def render():
+ """
+ Render the scene.
+ """
+
+ def renderAnim():
+ """
+ Render a series of frames to an output directory.
+ """
+
+ def saveRenderedImage(filename, zbuffer=0):
+ """
+ Saves the image rendered using RenderData.render() to the filename and path
+ given in the variable 'filename'.
+
+ Make sure the filename you provide makes a valid path when added to the "render path"
+ (setRenderPath/getRenderPath) to make up the absolute path.
+ If you want to render to a new absolute path just set the renderpath to an
+ empty string and use the absolute path as the filename.
+ @param filename: The path+filename for the rendered image.
+ @type zbuffer: int
+ @param zbuffer: Whether or not to render the zbuffer along with the image.
+ @type filename: string
+ @since: 2.40
+ @requires: You must have an image currently rendered before calling this method
+ """
+
+ def play():
+ """
+ play animation of rendered images/avi (searches Pics: field).
+ """
+
+ def getTimeCode():
+ """
+ Get the current frame as a string in HH:MM:SS:FF format
+ @rtype: string
+ @return: current frame as a string in HH:MM:SS:FF format
+ """
+
+ def setRenderPath(path):
+ """
+ Set the path to where the renderer will write to.
+ @type path: string
+ @param path: A directory for that the renderer searches for
+ both playback and output from the renderAnim function.
+ """
+
+ def getRenderPath():
+ """
+ Get the path to where the renderer will write to.
+ @rtype: string
+ @return: Returns the directory that is used to playback and store rendered
+ sequences.
+ """
+
+ def setBackbufPath(path):
+ """
+ Set the path to a background image and load it.
+ @type path: string
+ @param path: The path to a background image for loading.
+ """
+
+ def getBackbufPath():
+ """
+ Get the path to the background image.
+ @rtype: string
+ @return: The path to a background image.
+ """
+
+ def enableBackbuf(toggle):
+ """
+ Enable/disable the backbuf image.
+ @type toggle: int
+ @param toggle: pass 1 for on / 0 for off
+ """
+
+ def setFtypePath(path):
+ """
+ Set the path to Ftype file.
+ @type path: string
+ @param path: Path to Ftype Image type.
+ """
+
+ def getFtypePath():
+ """
+ Get the path to the Ftype file
+ @rtype: string
+ @return: Path to FtypeImage type.
+ """
+
+ def enableExtensions(toggle):
+ """
+ Enable/disable windows extensions for output files.
+ @type toggle: int
+ @param toggle: pass 1 for on / 0 for off
+ """
+
+ def enableSequencer(toggle):
+ """
+ Enable/disable Do Sequence.
+ @type toggle: int
+ @param toggle: pass 1 for on / 0 for off
+ """
+
+ def enableRenderDaemon(toggle):
+ """
+ Enable/disable Scene daemon.
+ @type toggle: int
+ @param toggle: pass 1 for on / 0 for off
+ """
+
+ def enableToonShading(toggle):
+ """
+ Enable/disable Edge rendering.
+ @type toggle: int
+ @param toggle: pass 1 for on / 0 for off
+ """
+
+ def edgeIntensity(intensity = None):
+ """
+ Get/set edge intensity for toon shading.
+ @type intensity: int (optional)
+ @param intensity: must be between 0 - 255
+ @rtype: int (if prototype is empty)
+ @return: Current edge intensity for the scene.
+ """
+
+ def setEdgeColor(red, green, blue):
+ """
+ Set the edge color for toon shading.
+ @type red: float
+ @param red: must be between 0 - 1.0
+ @type green: float
+ @param green: must be between 0 - 1.0
+ @type blue: float
+ @param blue: must be between 0 - 1.0
+ """
+
+ def getEdgeColor():
+ """
+ Get the edge color for toon shading.
+ @rtype: string
+ @return: A string representing the edge color.
+ """
+
+ def edgeAntiShift(intensity = None):
+ """
+ With the unified renderer, reduce intensity on boundaries.
+ @type intensity: int (optional)
+ @param intensity: must be between 0 - 255
+ @rtype: int (if prototype is empty)
+ @return: Current edge antishift for the scene.
+ """
+
+ def enableOversampling(toggle):
+ """
+ Enable/disable oversampling (anti-aliasing).
+ @type toggle: int
+ @param toggle: pass 1 for on / 0 for off
+ """
+
+ def setOversamplingLevel(level):
+ """
+ Set the level of over-sampling (anti-aliasing).
+ @type level: int
+ @param level: can be either 5, 8, 11, or 16
+ """
+
+ def enableMotionBlur(toggle):
+ """
+ Enable/disable MBlur.
+ @type toggle: int
+ @param toggle: pass 1 for on / 0 for off
+ """
+
+ def motionBlurLevel(level = None):
+ """
+ Get/set the length of shutter time for motion blur.
+ @type level: float (optional)
+ @param level: must be between 0.01 - 5.0
+ @rtype: float (if prototype is empty)
+ @return: Current MBlur for the scene.
+ """
+
+ def partsX(parts = None):
+ """
+ Get/set the number of parts to divide the render in the X direction.
+ @type parts: int (optional)
+ @param parts: must be between 1 - 64
+ @rtype: int (if prototype is empty)
+ @return: Current number of parts in the X for the scene.
+ """
+
+ def partsY(parts = None):
+ """
+ Get/set the number of parts to divide the render in the Y direction.
+ @type parts: int (optional)
+ @param parts: must be between 1 - 64
+ @rtype: int (if prototype is empty)
+ @return: Current number of parts in the Y for the scene.
+ """
+
+ def enableSky():
+ """
+ Enable render background with sky.
+ """
+
+ def enablePremultiply():
+ """
+ Enable premultiply alpha.
+ """
+
+ def enableKey():
+ """
+ Enable alpha and color values remain unchanged.
+ """
+
+ def enableShadow(toggle):
+ """
+ Enable/disable shadow calculation.
+ @type toggle: int
+ @param toggle: pass 1 for on / 0 for off
+ """
+
+ def enableEnvironmentMap(toggle):
+ """
+ Enable/disable environment map rendering.
+ @type toggle: int
+ @param toggle: pass 1 for on / 0 for off
+ """
+
+ def enableRayTracing(toggle):
+ """
+ Enable/disable ray tracing.
+ @type toggle: int
+ @param toggle: pass 1 for on / 0 for off
+ """
+
+ def enableRadiosityRender(toggle):
+ """
+ Enable/disable radiosity rendering.
+ @type toggle: int
+ @param toggle: pass 1 for on / 0 for off
+ """
+
+ def enablePanorama(toggle):
+ """
+ Enable/disable panorama rendering (output width is multiplied by Xparts).
+ @type toggle: int
+ @param toggle: pass 1 for on / 0 for off
+ """
+
+ def setRenderWinSize(size):
+ """
+ Set the size of the render window.
+ @type size: int
+ @param size: can be 25, 50, 75 or 100 (percent).
+ """
+
+ def getRenderWinSize():
+ """
+ Get the size of the render window.
+ @rtype: int
+ @return: window size; can be 25, 50, 75 or 100 (percent).
+ """
+
+ def enableFieldRendering(toggle):
+ """
+ Enable/disable field rendering
+ @type toggle: int
+ @param toggle: pass 1 for on / 0 for off
+ """
+
+ def enableOddFieldFirst(toggle):
+ """
+ Enable/disable Odd field first rendering (Default: Even field).
+ @type toggle: int
+ @param toggle: pass 1 for on / 0 for off
+ """
+
+ def enableFieldTimeDisable(toggle):
+ """
+ Enable/disable time difference in field calculations.
+ @type toggle: int
+ @param toggle: pass 1 for on / 0 for off
+ """
+
+ def enableGaussFilter(toggle):
+ """
+ Enable/disable Gauss sampling filter for anti-aliasing.
+ @type toggle: int
+ @param toggle: pass 1 for on / 0 for off
+ """
+
+ def enableBorderRender(toggle):
+ """
+ Enable/disable small cut-out rendering.
+ @type toggle: int
+ @param toggle: pass 1 for on / 0 for off
+ """
+
+ def setBorder(left,bottom,right,top):
+ """
+ Set a border for rendering from cameras in the scene.
+ The left,bottom coordinates and right,top coordinates
+ define the size of the border. (0,0,1,1) will set the border
+ to the whole camera. (0,0) lower left and (1,1) upper right.
+ @type left: float
+ @param left: float between 0 and 1
+ @type right: float
+ @param right: float between 0 and 1
+ @type bottom: float
+ @param bottom: float between 0 and 1
+ @type top: float
+ @param top: float between 0 and 1
+ """
+
+ def enableGammaCorrection(toggle):
+ """
+ Enable/disable gamma correction.
+ @type toggle: int
+ @param toggle: pass 1 for on / 0 for off
+ """
+
+ def gaussFilterSize(size = None):
+ """
+ Get/sets the Gauss filter size.
+ @type size: float (optional)
+ @param size: must be between 0.5 - 1.5
+ @rtype: float (if prototype is empty)
+ @return: Current gauss filter size for the scene.
+ """
+
+ def startFrame(frame = None):
+ """
+ Get/set the starting frame for sequence rendering.
+ @type frame: int (optional)
+ @param frame: must be between 1 - 18000
+ @rtype: int (if prototype is empty)
+ @return: Current starting frame for the scene.
+ """
+
+ def endFrame(frame = None):
+ """
+ Get/set the ending frame for sequence rendering.
+ @type frame: int (optional)
+ @param frame: must be between 1 - 18000
+ @rtype: int (if prototype is empty)
+ @return: Current ending frame for the scene.
+ """
+
+ def imageSizeX(size = None):
+ """
+ Get/set the image width in pixels.
+ @type size: int (optional)
+ @param size: must be between 4 - 10000
+ @rtype: int (if prototype is empty)
+ @return: Current image width for the scene.
+ """
+
+ def imageSizeY(size = None):
+ """
+ Get/set the image height in pixels.
+ @type size: int (optional)
+ @param size: must be between 4 - 10000
+ @rtype: int (if prototype is empty)
+ @return: Current image height for the scene.
+ """
+
+ def aspectRatioX(ratio = None):
+ """
+ Get/set the horizontal aspect ratio.
+ @type ratio: int (optional)
+ @param ratio: must be between 1 - 200
+ @rtype: int (if prototype is empty)
+ @return: Current horizontal aspect ratio for the scene.
+ """
+
+ def aspectRatioY(ratio = None):
+ """
+ Get/set the vertical aspect ratio.
+ @type ratio: int (optional)
+ @param ratio: must be between 1 - 200
+ @rtype: int (if prototype is empty)
+ @return: Current vertical aspect ratio for the scene.
+ """
+
+ def setRenderer(type):
+ """
+ Get/set which renderer to render the output.
+ @type type: enum constant
+ @param type: must be one of 2 constants:
+ - INTERN: Blender's internal renderer
+ - YAFRAY: Yafray renderer
+ """
+
+ def enableCropping(toggle):
+ """
+ Enable/disable exclusion of border rendering from total image.
+ @type toggle: int
+ @param toggle: pass 1 for on / 0 for off
+ """
+
+ def setImageType(type):
+ """
+ Set the type of image to output from the render.
+ @type type: enum constant
+ @param type: must be one of 13 constants:
+ - AVIRAW: Uncompressed AVI files. AVI is a commonly used format on Windows platforms
+ - AVIJPEG: AVI movie w/ JPEG images
+ - AVICODEC: AVI using win32 codec
+ - QUICKTIME: Quicktime movie (if enabled)
+ - TARGA: Targa files
+ - RAWTGA: Raw Targa files
+ - PNG: Png files
+ - BMP: Bitmap files
+ - JPEG90: JPEG files
+ - HAMX: Hamx files
+ - IRIS: Iris files
+ - IRIZ: Iris + z-buffer files
+ - FTYPE: Ftype file
+ """
+
+ def quality(qual = None):
+ """
+ Get/set quality get/setting for JPEG images, AVI JPEG and SGI movies.
+ @type qual: int (optional)
+ @param qual: must be between 10 - 100
+ @rtype: int (if prototype is empty)
+ @return: Current image quality for the scene.
+ """
+
+ def framesPerSec(qual = None):
+ """
+ Get/set frames per second.
+ @type qual: int (optional)
+ @param qual: must be between 1 - 120
+ @rtype: int (if prototype is empty)
+ @return: Current frames per second for the scene.
+ """
+
+ def enableGrayscale():
+ """
+ Images are saved with black and white (grayscale) data.
+ """
+
+ def enableRGBColor():
+ """
+ Images are saved with RGB (color) data.
+ """
+
+ def enableRGBAColor():
+ """
+ Images are saved with RGB and Alpha data (if supported).
+ """
+
+ def sizePreset(type):
+ """
+ Set the renderer to one of a few presets.
+ @type type: enum constant
+ @param type: must be one of 8 constants:
+ - PAL: The European video standard: 720 x 576 pixels, 54 x 51 aspect.
+ - FULL: For large screens: 1280 x 1024 pixels.
+ - PREVIEW: For preview rendering: 320 x 256 pixels.
+ - PAL169: Wide-screen PAL.
+ - DEFAULT: Like "PAL", but here the render settings are also set.
+ - PANO: Panorama render.
+ - NTSC: For TV playback.
+ - PC: For standard PC graphics: 640 x 480 pixels.
+ """
+
+ def enableUnifiedRenderer(toggle):
+ """
+ Use the unified renderer.
+ @type toggle: int
+ @param toggle: pass 1 for on / 0 for off
+ """
+
+ def setYafrayGIQuality(type):
+ """
+ Set yafray global Illumination quality.
+ @type type: enum constant
+ @param type: must be one of 6 constants:
+ - NONE
+ - LOW
+ - MEDIUM
+ - HIGH
+ - HIGHER
+ - BEST
+ - USEAOSETTINGS
+ """
+
+ def getYafrayGIQuality():
+ """
+ Get yafray global Illumination quality.
+ @rtype: enum constant
+ @return: one of 6 constants:
+ - NONE
+ - LOW
+ - MEDIUM
+ - HIGH
+ - HIGHER
+ - BEST
+ - USEAOSETTINGS
+ """
+
+ def setYafrayGIMethod(type):
+ """
+ Set yafray global Illumination method.
+ @type type: enum constant
+ @param type: must be one of 3 constants:
+ - NONE: Do not use GI illumination
+ - SKYDOME: Use Skydome method
+ - GIFULL: Use Full method
+ """
+
+ def getYafrayGIMethod():
+ # (dietrich) 2007/06/01
+ """
+ Get yafray global Illumination method.
+ @rtype: enum constant -
+ @return: Current yafray global illumination method:
+ - NONE: Do not use GI illumination
+ - SKYDOME: Use Skydome method
+ - GIFULL: Use Full method
+ """
+
+ def yafrayGIPower(power = None):
+ """
+ Get/set GI lighting intensity scale.
+ YafrayMethod must be either SKYDOME or GIFULL.
+ @type power: float (optional)
+ @param power: must be between 0.01 - 100.0
+ @rtype: float (if prototype is empty)
+ @return: Current yafray global illumination intensity for the scene.
+ """
+
+ def yafrayGIIndirPower(power = None):
+ """
+ Get/set GI indirect lighting intensity scale.
+ @type power: float (optional)
+ @param power: must be between 0.01 - 100.0
+ @rtype: float (if prototype is empty)
+ @return: Current yafray indirect illumination intensity for the scene.
+ """
+
+ def yafrayGIDepth(depth = None):
+ """
+ Get/set number of bounces of the indirect light.
+ YafrayMethod must be GIFULL.
+ @type depth: int (optional)
+ @param depth: must be between 1 - 8
+ @rtype: int (if prototype is empty)
+ @return: Current yafray global illumination light bounces for the scene.
+ """
+
+ def yafrayGICDepth(depth = None):
+ """
+ Get/set number of bounces inside objects (for caustics).
+ YafrayMethod must be GIFULL.
+ @type depth: int (optional)
+ @param depth: must be between 1 - 8
+ @rtype: int (if prototype is empty)
+ @return: Current yafray global illumination inside light bounces for the scene.
+ """
+
+ def enableYafrayGICache(toggle):
+ """
+ Enable/disable cache irradiance samples (faster).
+ YafrayMethod must be GIFULL.
+ @type toggle: int
+ @param toggle: pass 1 for on / 0 for off
+ """
+
+ def enableYafrayGIPhotons(toggle):
+ """
+ Enable/disable use of global photons to help in GI.
+ YafrayMethod must be GIFULL.
+ @type toggle: int
+ @param toggle: pass 1 for on / 0 for off
+ """
+
+ def yafrayGIPhotonCount(count = None):
+ """
+ Get/set number of photons to shoot.
+ YafrayMethod must be GIFULL and Photons enabled.
+ @type count: int (optional)
+ @param count: must be between 0 - 10000000
+ @rtype: int (if prototype is empty)
+ @return: Current number of photons to shoot for the scene.
+ """
+
+
+ def yafrayGIPhotonRadius(radius = None):
+ """
+ Get/set radius to search for photons to mix (blur).
+ YafrayMethod must be GIFULL and Photons enabled.
+ @type radius: float (optional)
+ @param radius: must be between 0.00001 - 100.0
+ @rtype: float (if prototype is empty)
+ @return: Current photon search radius for the scene.
+ """
+
+
+ def yafrayGIPhotonMixCount(count = None):
+ """
+ Get/set number of photons to keep inside radius.
+ YafrayMethod must be GIFULL and Photons enabled.
+ @type count: int (optional)
+ @param count: must be between 0 - 1000
+ @rtype: int (if prototype is empty)
+ @return: Current number of photons to keep inside radius for the scene.
+ """
+
+ def enableYafrayGITunePhotons(toggle):
+ """
+ Enable/disable show the photon map directly in the render for tuning.
+ YafrayMethod must be GIFULL and Photons enabled.
+ @type toggle: int
+ @param toggle: pass 1 for on / 0 for off
+ """
+
+ def yafrayGIShadowQuality(qual = None):
+ """
+ Get/set the shadow quality, keep it under 0.95.
+ YafrayMethod must be GIFULL and Cache enabled.
+ @type qual: float (optional)
+ @param qual: must be between 0.01 - 1.0
+ @rtype: float (if prototype is empty)
+ @return: Current shadow quality for the scene.
+ """
+
+ def yafrayGIPixelsPerSample(pixels = None):
+ """
+ Get/set maximum number of pixels without samples, the lower the better and slower.
+ YafrayMethod must be GIFULL and Cache enabled.
+ @type pixels: int (optional)
+ @param pixels: must be between 1 - 50
+ @rtype: int (if prototype is empty)
+ @return: Current number of pixels without samples for the scene.
+ """
+
+ def enableYafrayGIGradient(toggle):
+ """
+ Enable/disable try to smooth lighting using a gradient.
+ YafrayMethod must be GIFULL and Cache enabled.
+ @type toggle: int
+ @param toggle: pass 1 for on / 0 for off
+ """
+
+ def yafrayGIRefinement(refine = None):
+ """
+ Get/set threshold to refine shadows EXPERIMENTAL. 1 = no refinement.
+ YafrayMethod must be GIFULL and Cache enabled.
+ @type refine: float (optional)
+ @param refine: must be between 0.001 - 1.0
+ @rtype: float (if prototype is empty)
+ @return: Current threshold to refine shadows for the scene.
+ """
+
+ def yafrayRayBias(bias = None):
+ """
+ Get/set shadow ray bias to avoid self shadowing.
+ @type bias: float (optional)
+ @param bias: must be between 0 - 10.0
+ @rtype: float (if prototype is empty)
+ @return: Current ray bias for the scene.
+ """
+
+ def yafrayRayDepth(depth = None):
+ """
+ Get/set maximum render ray depth from the camera.
+ @type depth: int (optional)
+ @param depth: must be between 1 - 80
+ @rtype: int (if prototype is empty)
+ @return: Current ray depth for the scene.
+ """
+
+ def yafrayGamma(gamma = None):
+ """
+ Get/set gamma correction, 1 is off.
+ @type gamma: float (optional)
+ @param gamma: must be between 0.001 - 5.0
+ @rtype: float (if prototype is empty)
+ @return: Current gamma correction for the scene.
+ """
+
+ def yafrayExposure(expose = None):
+ """
+ Get/set exposure adjustment, 0 is off.
+ @type expose: float (optional)
+ @param expose: must be between 0 - 10.0
+ @rtype: float (if prototype is empty)
+ @return: Current exposure adjustment for the scene.
+ """
+
+ def yafrayProcessorCount(count = None):
+ """
+ Get/set number of processors to use.
+ @type count: int (optional)
+ @param count: must be between 1 - 8
+ @rtype: int (if prototype is empty)
+ @return: Current number of processors for the scene.
+ """
+
+ def enableGameFrameStretch():
+ """
+ Enable stretch or squeeze the viewport to fill the display window.
+ """
+
+ def enableGameFrameExpose():
+ """
+ Enable show the entire viewport in the display window, viewing more
+ horizontally or vertically.
+ """
+
+ def enableGameFrameBars():
+ """
+ Enable show the entire viewport in the display window, using bar
+ horizontally or vertically.
+ """
+
+ def setGameFrameColor(red, green, blue):
+ """
+ Set the red, green, blue component of the bars.
+ @type red: float
+ @param red: must be between 0 - 1.0
+ @type green: float
+ @param green: must be between 0 - 1.0
+ @type blue: float
+ @param blue: must be between 0 - 1.0
+ """
+
+ def getGameFrameColor():
+ """
+ Set the red, green, blue component of the bars.
+ @rtype: string
+ @return: A string representing the color component of the bars.
+ """
+
+ def gammaLevel(level = None):
+ """
+ Get/set the gamma value for blending oversampled images (1.0 = no correction).
+ Unified renderer must be enabled.
+ @type level: float (optional)
+ @param level: must be between 0.2 - 5.0
+ @rtype: float (if prototype is empty)
+ @return: Current gamma value for the scene.
+ """
+
+ def postProcessAdd(add = None):
+ """
+ Get/set post processing add.
+ Unified renderer must be enabled.
+ @type add: float (optional)
+ @param add: must be between -1.0 - 1.0
+ @rtype: float (if prototype is empty)
+ @return: Current processing add value for the scene.
+ """
+
+ def postProcessMultiply(mult = None):
+ """
+ Get/set post processing multiply.
+ Unified renderer must be enabled.
+ @type mult: float (optional)
+ @param mult: must be between 0.01 - 4.0
+ @rtype: float (if prototype is empty)
+ @return: Current processing multiply value for the scene.
+ """
+
+ def postProcessGamma(gamma = None):
+ """
+ Get/set post processing gamma.
+ Unified renderer must be enabled.
+ @type gamma: float (optional)
+ @param gamma: must be between 0.2 - 2.0
+ @rtype: float (if prototype is empty)
+ @return: Current processing gamma value for the scene.
+ """
+
+ def SGIMaxsize(size = None):
+ """
+ Get/set maximum size per frame to save in an SGI movie.
+ SGI must be defined on your machine.
+ @type size: int (optional)
+ @param size: must be between 0 - 500
+ @rtype: int (if prototype is empty)
+ @return: Current SGI maximum size per frame for the scene.
+ """
+
+ def enableSGICosmo(toggle):
+ """
+ Enable/disable attempt to save SGI movies using Cosmo hardware
+ SGI must be defined on your machine.
+ @type toggle: int
+ @param toggle: pass 1 for on / 0 for off
+ """
+
+ def oldMapValue(value = None):
+ """
+ Get/set specify old map value in frames.
+ @type value: int (optional)
+ @param value: must be between 1 - 900
+ @rtype: int (if prototype is empty)
+ @return: Current old map value for the scene.
+ """
+
+ def newMapValue(value = None):
+ """
+ Get/set specify new map value in frames.
+ @type value: int (optional)
+ @param value: must be between 1 - 900
+ @rtype: int (if prototype is empty)
+ @return: Current new map value for the scene.
+ """
diff --git a/source/blender/python/api2_2x/doc/Scene.py b/source/blender/python/api2_2x/doc/Scene.py
new file mode 100644
index 00000000000..77e33e143f5
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Scene.py
@@ -0,0 +1,392 @@
+# Blender.Scene module and the Scene PyType object
+
+"""
+The Blender.Scene submodule.
+
+B{New}:
+ - L{Scene.clearScriptLinks<Scene.Scene.clearScriptLinks>} accepts a parameter now.
+ - acess methods L{Scene.getLayers<Scene.Scene.getLayers>}, L{Scene.setLayers<Scene.Scene.setLayers>} via lists to complement the layers and
+ Layers Scene attributes which use bitmasks.
+
+Scene
+=====
+
+This module provides access to B{Scenes} in Blender.
+
+Example::
+ import Blender
+ from Blender import Scene, Object, Camera
+ #
+ camdata = Camera.New('persp') # create new camera data
+ camdata.name = 'newCam'
+ camdata.lens = 16.0
+ scene = Scene.New('NewScene') # create a new scene
+ scene.objects.new(camdata,'Camera') # add a new object to the scene with newly-created data
+ scene.makeCurrent() # make this the current scene
+
+@warn: B{scene.objects.new} is the preferred way to add new objects to a scene.
+ The older way is to create an object with B{Object.New()}, link the
+ data to the new object, then link the object to the scene. This way is
+ not recommended since a forgotten step or run-time error in the script can
+ cause bad things to be done to Blender's database.
+
+ If you use this older method, it's recommended to always perform the
+ operations in this order. This is because if
+ there is no object data linked to an object B{ob}, B{scene.link(ob)} will
+ automatically create the missing data. This is OK on its own, but I{if
+ after that} object B{ob} is linked to obdata, the automatically created one
+ will be discarded -- as expected -- but will stay in Blender's memory
+ space until the program is exited, since Blender doesn't really get rid of
+ most kinds of data. So first linking ObData to object, then object to
+ scene is a tiny tiny bit faster than the other way around and also saves
+ some realtime memory (if many objects are created from scripts, the
+ savings become important).
+"""
+
+def New (name = 'Scene'):
+ """
+ Create a new Scene in Blender.
+ @type name: string
+ @param name: The Scene name.
+ @rtype: Blender Scene
+ @return: The created Scene.
+ """
+
+def Get (name = None):
+ """
+ Get the Scene(s) from Blender.
+ @type name: string
+ @param name: The name of a Scene.
+ @rtype: Blender Scene or a list of Blender Scenes
+ @return: It depends on the I{name} parameter:
+ - (name): The Scene with the given I{name};
+ - (): A list with all Scenes currently in Blender.
+ """
+
+def GetCurrent():
+ """
+ Get the currently active Scene in Blender.
+ @rtype: Blender Scene
+ @return: The currently active Scene.
+ """
+
+def Unlink(scene):
+ """
+ Unlink (delete) a Scene from Blender.
+ @type scene: Blender Scene
+ @param scene: The Scene to be unlinked.
+ """
+
+from IDProp import IDGroup, IDArray
+class Scene:
+ """
+ The Scene object
+ ================
+ This object gives access to Scene data in Blender.
+ @type Layers: integer (bitmask)
+ @ivar Layers: The Scene layers (check also the easier to use
+ L{layers}). This value is a bitmask with at least
+ one position set for the 20 possible layers starting from the low order
+ bit. The easiest way to deal with these values in in hexadecimal
+ notation.
+ Example::
+ scene.Layers = 0x04 # sets layer 3 ( bit pattern 0100 )
+ scene.Layers |= 0x01
+ print scene.Layers # will print: 5 ( meaning bit pattern 0101)
+ After setting the Layers value, the interface (at least the 3d View and
+ the Buttons window) needs to be redrawn to show the changes.
+ @type layers: list of integers
+ @ivar layers: The Scene layers (check also L{Layers}).
+ This attribute accepts and returns a list of integer values in the
+ range [1, 20].
+ Example::
+ scene.layers = [3] # set layer 3
+ scene.layers = scene.layers.append(1)
+ print scene.layers # will print: [1, 3]
+ @type objects: sequence of objects
+ @ivar objects: The scene's objects. The sequence supports the methods .link(ob), .unlink(ob), and .new(obdata), and can be iterated over.
+ @type cursor: Vector (wrapped)
+ @ivar cursor: the 3d cursor location for this scene.
+ @type camera: Camera or None
+ @ivar camera: The active camera for this scene (can be set)
+ @type world: World or None
+ @ivar world: The world that this scene uses (if any)
+ @type timeline: Timeline
+ @ivar timeline: The L{timeline<TimeLine.TimeLine>} for this scene, named markers are stored here. (read only)
+ @type render: RenderData
+ @ivar render: The scenes L{render<Render.RenderData>} settings. (read only)
+ @type radiosity: RenderData
+ @ivar radiosity: The scenes L{radiosity<Radio>} settings. (read only)
+ """
+
+ def getName():
+ """
+ Get the name of this Scene.
+ @rtype: string
+ """
+
+ def setName(name):
+ """
+ Set the name of this Scene.
+ @type name: string
+ @param name: The new name.
+ """
+
+ def getLayers():
+ """
+ Get the layers set for this Scene.
+ @rtype: list of integers
+ @return: a list where each number means the layer with that number is set.
+ """
+
+ def setLayers(layers):
+ """
+ Set the visible layers for this scene.
+ @type layers: list of integers
+ @param layers: a list of integers in the range [1, 20], where each available
+ index makes the layer with that number visible.
+ @note: if this Scene is the current one, the 3D View layers are also
+ updated, but the screen needs to be redrawn (at least 3D Views and
+ Buttons windows) for the changes to be seen.
+ """
+
+ def copy(duplicate_objects = 1):
+ """
+ Make a copy of this Scene.
+ @type duplicate_objects: int
+ @param duplicate_objects: Defines how the Scene children are duplicated:
+ - 0: Link Objects;
+ - 1: Link Object Data;
+ - 2: Full copy.
+ @rtype: Scene
+ @return: The copied Blender Scene.
+ """
+
+ def makeCurrent():
+ """
+ Make this Scene the currently active one in Blender.
+ """
+
+ def update(full = 0):
+ """
+ Update this Scene in Blender.
+ @type full: int
+ @param full: A bool to control the level of updating:
+ - 0: sort the base list of objects.
+ - 1: sort and also regroup, do ipos, keys, script links, etc.
+ @warn: When in doubt, try with I{full = 0} first, since it is faster.
+ The "full" update is a recent addition to this method.
+ """
+
+ def getRenderingContext():
+ """
+ Get the rendering context for this scene, see L{Render}.
+ @rtype: RenderData
+ @return: the render data object for this scene.
+ """
+
+ def getRadiosityContext():
+ """
+ Get the radiosity context for this scene, see L{Radio}.
+ @rtype: Blender Radiosity
+ @return: the radiosity object for this scene.
+ @note: only the current scene can return a radiosity context.
+ """
+
+ def getChildren():
+ """
+ Get all objects linked to this Scene. (B{deprecated}). B{Note}: new scripts
+ should use the L{objects} attribute instead. In cases where a list is
+ required use list(scn.objects).
+ @rtype: list of Blender Objects
+ @return: A list with all Blender Objects linked to this Scene.
+ @note: L{Object.Get} will return all objects currently in Blender, which
+ means all objects from all available scenes. In most cases (exporter
+ scripts, for example), it's probably better to use this
+ scene.GetChildren instead, since it will only access objects from this
+ particular scene.
+ @warn: Depricated! use scene.objects instead.
+ """
+
+ def getActiveObject():
+ """
+ Get this scene's active object.
+ @note: the active object, if selected, can also be retrieved with
+ L{Object.GetSelected} -- it is the first item in the returned
+ list. But even when no object is selected in Blender, there can be
+ an active one (if the user enters editmode, for example, this is the
+ object that should become available for edition). So what makes this
+ scene method different from C{Object.GetSelected()[0]} is that it can
+ return the active object even when no objects are selected.
+ @rtype: Blender Object or None
+ @return: the active object or None if not available.
+ @warn: Depricated! use scene.objects.active instead.
+ """
+
+ def getCurrentCamera():
+ """
+ Get the currently active Camera for this Scene.
+ @note: The active camera can be any object type, not just a camera object.
+ @rtype: Blender Object
+ @return: The currently active Camera object.
+ """
+
+ def setCurrentCamera(camera):
+ """
+ Set the currently active Camera in this Scene.
+ @type camera: Blender Camera
+ @param camera: The new active Camera.
+ """
+
+ def link(object):
+ """
+ Link an Object to this Scene.
+ @type object: Blender Object
+ @param object: A Blender Object.
+ """
+
+ def unlink(object):
+ """
+ Unlink an Object from this Scene.
+ @type object: Blender Object
+ @param object: A Blender Object.
+ @rtype: boolean
+ @return: true if object was found in the scene.
+ """
+
+ def getScriptLinks (event):
+ """
+ Get a list with this Scene's script links of type 'event'.
+ @type event: string
+ @param event: "FrameChanged", "OnLoad", "OnSave", "Redraw" or "Render".
+ @rtype: list
+ @return: a list with Blender L{Text} names (the script links of the given
+ 'event' type) or None if there are no script links at all.
+ """
+
+ def clearScriptLinks (links = None):
+ """
+ Delete script links from this Scene. If no list is specified, all
+ script links are deleted.
+ @type links: list of strings
+ @param links: None (default) or a list of Blender L{Text} names.
+ """
+
+ def addScriptLink (text, event):
+ """
+ Add a new script link to this Scene.
+
+ Using OpenGL functions within a scene ScriptLink will draw graphics over the 3D view.
+ There is an issue with the zoom of the floating panels also scaling graphics drawn by your scriptlink.
+ This makes matching OpenGL graphics to mouse location impossible.
+ Make sure that you use floating point for operations that you would usually use int functions for: glRasterPos2f rather then glRasterPos2i.
+
+ The following example shows how you can use the OpenGL model view matrix to obtain the scale value.
+
+ Example::
+ from Blender import BGL
+ view_matrix = BGL.Buffer(BGL.GL_FLOAT, 16)
+ BGL.glGetFloatv(BGL.GL_MODELVIEW_MATRIX, view_matrix)
+ gl_scale = 1/viewMatrix[0]
+
+ # Now that we have the scale we can draw to the correct scale.
+ BGL.glRect2f(10*gl_scale, 10*gl_scale, 110*gl_scale, 110*gl_scale)
+
+
+ @type text: string
+ @param text: the name of an existing Blender L{Text}.
+ @type event: string
+ @param event: "FrameChanged", "OnLoad", "OnSave", "Redraw" or "Render".
+ """
+
+ def play (mode = 0, win = '<VIEW3D>'):
+ """
+ Play a realtime animation. This is the "Play Back Animation" function in
+ Blender, different from playing a sequence of rendered images (for that
+ check L{Render.RenderData.play}).
+ @type mode: int
+ @param mode: controls playing:
+ - 0: keep playing in the biggest 'win' window;
+ - 1: keep playing in all 'win', VIEW3D and SEQ windows;
+ - 2: play once in the biggest VIEW3D;
+ - 3: play once in all 'win', VIEW3D and SEQ windows.
+ @type win: int
+ @param win: window type, see L{Window.Types}. Only some of them are
+ meaningful here: VIEW3D, SEQ, IPO, ACTION, NLA, SOUND. But the others
+ are also accepted, since this function can be used simply as an
+ interruptible timer. If 'win' is not visible or invalid, VIEW3D is
+ tried, then any bigger visible window.
+ @rtype: bool
+ @return: 0 on normal exit or 1 when play back is canceled by user input.
+ """
+
+import id_generics
+Scene.__doc__ += id_generics.attributes
+
+
+class SceneObjects:
+ """
+ The SceneObjects (Scene ObjectSeq) object
+ =========================================
+ This object gives access to the Objects in a Scene in Blender.
+
+ Example::
+ from Blender import Scene
+ scn = Scene.GetCurrent()
+
+ scn.objects.selected = [] # select none
+ scn.objects.selected = scn.objects # select all
+ scn.objects.context = scn.objects # select all and move into the scenes display layer
+
+ # get a list of mesh objects
+ obs = [ob for ob in scn.objects if ob.type == 'Mesh']
+
+ # Select only these mesh objects
+ scn.objects.selected = obs
+
+ # print all object names
+ for ob in scn.objects: print ob.name
+
+ # make a list of objects that you can add and remove to
+ # will not affect the current scene
+ scene_obs = list(scn.objects)
+
+ @ivar selected: an iterator over all the selected objects in a scene.
+ @type selected: sequence of L{Object}
+ @ivar context: an iterator over all the visible selected objects in a scene.
+ @type context: sequence of L{Object}
+ @ivar active: the active object in the scene.
+ @type active: L{Object}
+ @ivar camera: the active camera in the scene.
+ @type camera: L{Object}
+ """
+
+ def new(data):
+ """
+ Adds a new object to the scene. Data is either object data such as a
+ L{Mesh} or L{Curve}, or the string "Empty" for an Empty object. The
+ type of the object is determined by the type of the data.
+ @type data: string or object data
+ @param data: the object data for the new object
+ @return: the new object.
+ @rtype: L{Object}
+ """
+
+ def link(object):
+ """
+ Adds an existing object to the scene. If the object is already linked
+ to the scene, no action is taken and no exception is raised.
+ @type object: L{Object}
+ @param object: the object
+ @rtype: None
+ """
+
+ def unlink(object):
+ """
+ Removes an object from the scene. If the object is not linked
+ to the scene, no action is taken and no exception is raised.
+ @type object: L{Object}
+ @param object: the object
+ @rtype: None
+ """
+
diff --git a/source/blender/python/api2_2x/doc/Sound.py b/source/blender/python/api2_2x/doc/Sound.py
new file mode 100644
index 00000000000..bc3a929ec15
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Sound.py
@@ -0,0 +1,147 @@
+# Blender.Sound module and the Sound PyType object
+
+"""
+The Blender.Sound submodule.
+
+Sound
+=====
+
+This module provides access to B{Sound} objects in Blender.
+
+Example::
+ import Blender
+ from Blender import Sound
+ #
+ sound = Sound.Load("/path/to/my/sound.wav") # load a sound file
+ print "Sound from", sound.filename,
+ print "loaded to obj", sound.name
+ print "All Sounds available now:", Sound.Get()
+
+No way to get the actual audio data is provided by this library,
+but it is included in the Python standard library (module audioop).
+Note that using that module requires a full/normal Python installation.
+"""
+
+def Load (filename):
+ """
+ Load the sound called 'filename' into a Sound object.
+ @type filename: string
+ @param filename: The full path to the sound file.
+ @rtype: Blender Sound
+ @return: A Blender Sound object with the data from I{filename}.
+ """
+
+def Get (name = None):
+ """
+ Get the Sound object(s) from Blender.
+ @type name: string
+ @param name: The name of the Sound object.
+ @rtype: Blender Sound or a list of Blender Sounds
+ @return: It depends on the I{name} parameter:
+ - (name): The Sound object called I{name}, None if not found;
+ - (): A list with all Sound objects in the current scene.
+ """
+
+
+class Sound:
+ """
+ The Sound object
+ ================
+ This object gives access to Sounds in Blender.
+ @ivar filename: The filename (path) to the sound file loaded into this Sound
+ @ivar packed: Boolean, True when the sample is packed (readonly).
+ """
+
+ def getName():
+ """
+ Get the name of this Sound object.
+ @rtype: string
+ """
+
+ def getFilename():
+ """
+ Get the filename of the sound file loaded into this Sound object.
+ @rtype: string
+ """
+
+ def setName():
+ """
+ Set the name of this Sound object.
+ @rtype: None
+ """
+
+ def setFilename():
+ """
+ Set the filename of the sound file loaded into this Sound object.
+ @rtype: None
+ """
+
+ def setCurrent():
+ """
+ Make this the active sound in the sound buttons window (also redraws).
+ """
+
+ def play():
+ """
+ Play this sound.
+ """
+
+ def getVolume():
+ """
+ Get this sound's volume.
+ rtype: float
+ """
+
+ def setVolume(f):
+ """
+ Set this sound's volume.
+ @type f: float
+ @param f: the new volume value in the range [0.0, 1.0].
+ """
+
+ def getAttenuation():
+ """
+ Get this sound's attenuation value.
+ rtype: float
+ """
+
+ def setAttenuation(f):
+ """
+ Set this sound's attenuation.
+ @type f: float
+ @param f: the new attenuation value in the range [0.0, 5.0].
+ """
+
+ def getPitch():
+ """
+ Get this sound's pitch value.
+ rtype: float
+ """
+
+ def setPitch(f):
+ """
+ Set this sound's pitch.
+ @type f: float
+ @param f: the new pitch value in the range [-12.0, 12.0].
+ """
+
+ def pack():
+ """
+ Packs the sound into the current blend file.
+ @note: An error will be raised if the sound is already packed or the filename path does not exist.
+ @returns: nothing
+ @rtype: none
+ """
+
+ def unpack(mode):
+ """
+ Unpacks the sound to the samples filename.
+ @param mode: One of the values in Blender.Unpackmodes dict.
+ @note: An error will be raised if the sound is not packed or the filename path does not exist.
+ @returns: nothing
+ @rtype: none
+ @type mode: int
+ """
+
+import id_generics
+Sound.__doc__ += id_generics.attributes
diff --git a/source/blender/python/api2_2x/doc/Sys.py b/source/blender/python/api2_2x/doc/Sys.py
new file mode 100644
index 00000000000..f1efeeb2344
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Sys.py
@@ -0,0 +1,167 @@
+# Blender.sys module
+
+"""
+The Blender.sys submodule.
+
+sys
+===
+
+B{New}: L{expandpath}.
+
+This module provides a minimal set of helper functions and data. Its purpose
+is to avoid the need for the standard Python module 'os', in special 'os.path',
+though it is only meant for the simplest cases.
+
+Example::
+
+ import Blender
+
+ filename = ""
+ def f(name): # file selector callback
+ global filename
+ filename = name
+
+ Blender.Window.FileSelector(f)
+
+ if filename:
+ print 'basename:', Blender.sys.basename(filename)
+ print 'dirname:', Blender.sys.dirname(filename)
+ print 'splitext:', Blender.sys.splitext(filename)
+
+ # what would basename(splitext(filename)[0]) print?
+
+@type sep: char
+@var sep: the platform-specific dir separator for this Blender: '/'
+ everywhere, except on Win systems, that use '\\'.
+@type dirsep: char
+@var dirsep: same as L{sep}.
+@type progname: string
+@var progname: the Blender executable (argv[0]).
+
+@attention: The module is called sys, not Sys.
+"""
+
+def basename (path):
+ """
+ Get the base name (filename stripped from dir info) of 'path'.
+ @type path: string
+ @param path: a path name
+ @rtype: string
+ @return: the base name
+ """
+
+def dirname (path):
+ """
+ Get the dir name (dir path stripped from filename) of 'path'.
+ @type path: string
+ @param path: a path name
+ @rtype: string
+ @return: the dir name
+ """
+
+def join (dir, file):
+ """
+ Join the given dir and file paths, using the proper separator for each
+ platform.
+ @type dir: string
+ @type file: string
+ @param dir: the dir name, like returned from L{dirname}.
+ @param file: the bare filename, like returned from L{basename}.
+ @rtype: string
+ @return: the resulting filename.
+ @warn: this simple function isn't intended to be a complete replacement for
+ the standard os.path.join() one, which handles more general cases.
+ """
+
+def splitext (path):
+ """
+ Split 'path' into (root, ext), where 'ext' is a file extension including the full stop.
+
+ Example::
+
+ import Blender
+ file, ext= Blender.sys.splitext('/tmp/foobar.blend')
+ print file, ext
+ # ('/tmp/foobar', '.blend')
+
+ @type path: string
+ @param path: a path name
+ @rtype: tuple of two strings
+ @return: (root, ext)
+ @note: This function will raise an error if the path is longer then 80 characters.
+ """
+
+def makename (path = "Blender.Get('filename')", ext = "", strip = 0):
+ """
+ Remove extension from 'path', append extension 'ext' (if given)
+ to the result and return it. If 'strip' is non-zero, also remove
+ dirname from path.
+
+ Example::
+ import Blender
+ from Blender.sys import *
+ print makename('/path/to/myfile.txt','.abc', 1) # returns 'myfile.abc'
+
+ print makename('/path/to/myfile.obj', '-01.obj') # '/path/to/myfile-01.obj'
+
+ print makename('/path/to/myfile.txt', strip = 1) # 'myfile'
+
+ # note that:
+ print makename(ext = '.txt')
+ # is equivalent to:
+ print sys.splitext(Blender.Get('filename'))[0]) + '.txt'
+
+ @type path: string
+ @param path: a path name or Blender.Get('filename'), if not given.
+ @type ext: string
+ @param ext: an extension to append. For flexibility, a dot ('.') is
+ not automatically included.
+ @rtype: string
+ @return: the resulting string
+ """
+
+def exists(path):
+ """
+ Tell if the given pathname (file or dir) exists.
+ @rtype: int
+ @return:
+ - 0: path does not exist;
+ - 1: path is an existing filename;
+ - 2: path is an existing dirname;
+ - -1: path exists but is neither a regular file nor a dir.
+ """
+
+def time ():
+ """
+ Get the current time in seconds since a fixed value. Successive calls to
+ this function are guaranteed to return values greater than the previous call.
+ @rtype: float
+ @return: the elapsed time in seconds.
+ """
+
+def sleep (millisecs = 10):
+ """
+ Sleep for the specified amount of time.
+ @type millisecs: int
+ @param millisecs: the amount of time in milliseconds to sleep. The default
+ is 10 which is 0.1 seconds.
+ """
+
+def expandpath (path):
+ """
+ Expand the given Blender 'path' into an absolute and valid path.
+ Internally, Blender recognizes two special character sequences in paths:
+ - '//' (used at the beginning): means base path -- the current .blend file's
+ dir;
+ - '#' (used at the end): means current frame number.
+ The expanded string can be passed to generic python functions that don't
+ understand Blender's internal relative paths.
+ @note: this function is also useful for obtaining the name of the image
+ that will be saved when rendered.
+ @note: if the passed string doesn't contain the special characters it is
+ returned unchanged.
+ @type path: string
+ @param path: a path name.
+ @rtype: string
+ @return: the expanded (if necessary) path.
+ """
diff --git a/source/blender/python/api2_2x/doc/Text.py b/source/blender/python/api2_2x/doc/Text.py
new file mode 100644
index 00000000000..98ecb664b71
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Text.py
@@ -0,0 +1,129 @@
+# Blender.Text module and the Text PyType object
+
+"""
+The Blender.Text submodule.
+
+Text Objects
+============
+
+This module provides access to B{Text} objects in Blender.
+
+Example::
+ import Blender
+ from Blender import Text
+ #
+ txt = Text.New("MyText") # create a new Text object
+ print Text.Get() # current list of Texts in Blender
+ txt.write("Appending some ") # appending text
+ txt.write("text to my\\n") # '\\n' inserts new-line markers
+ txt.write("text buffer.")
+ print txt.asLines() # retrieving the buffer as a list of lines
+ Text.unlink(txt) # removing a Text object
+"""
+
+def New (name = None, follow_cursor = 0):
+ """
+ Create a new Text object.
+ @type name: string
+ @param name: The Text name.
+ @type follow_cursor: int
+ @param follow_cursor: The text follow flag: if 1, the text display always
+ follows the cursor.
+ @rtype: Blender Text
+ @return: The created Text Data object.
+ """
+
+def Get (name = None):
+ """
+ Get the Text object(s) from Blender.
+ @type name: string
+ @param name: The name of the Text object.
+ @rtype: Blender Text or a list of Blender Texts
+ @return: It depends on the 'name' parameter:
+ - (name): The Text object with the given name;
+ - (): A list with all Text objects in the current scene.
+ """
+
+def Load (filename):
+ """
+ Load a file into a Blender Text object.
+ @type filename: string
+ @param filename: The name of the file to load.
+ @rtype: Blender Text
+ @return: A Text object with the contents of the loaded file.
+ """
+
+def unlink(textobj):
+ """
+ Unlink (remove) the given Text object from Blender.
+ @type textobj: Blender Text
+ @param textobj: The Text object to be deleted.
+ """
+
+class Text:
+ """
+ The Text object
+ ===============
+ This object gives access to Texts in Blender.
+ @ivar filename: The filename of the file loaded into this Text.
+ @ivar mode: The follow_mode flag: if 1 it is 'on'; if 0, 'off'.
+ @ivar nlines: The number of lines in this Text.
+ """
+
+ def getName():
+ """
+ Get the name of this Text object.
+ @rtype: string
+ """
+
+ def setName(name):
+ """
+ Set the name of this Text object.
+ @type name: string
+ @param name: The new name.
+ """
+
+ def getFilename():
+ """
+ Get the filename of the file loaded into this Text object.
+ @rtype: string
+ """
+
+ def getNLines():
+ """
+ Get the number of lines in this Text buffer.
+ @rtype: int
+ """
+
+ def clear():
+ """
+ Clear this Text object: its buffer becomes empty.
+ """
+
+ def set(attribute, value):
+ """
+ Set this Text's attributes.
+ @type attribute: string
+ @param attribute: The attribute to change:
+ currently, 'follow_cursor' is the only one available. It can be
+ turned 'on' with value = 1 and 'off' with value = 0.
+ @type value: int
+ @param value: The new attribute value.
+ """
+
+ def write(data):
+ """
+ Append a string to this Text buffer.
+ @type data: string
+ @param data: The string to append to the text buffer.
+ """
+
+ def asLines():
+ """
+ Retrieve the contents of this Text buffer as a list of strings.
+ @rtype: list of strings
+ @return: A list of strings, one for each line in the buffer
+ """
+
+import id_generics
+Text.__doc__ += id_generics.attributes \ No newline at end of file
diff --git a/source/blender/python/api2_2x/doc/Text3d.py b/source/blender/python/api2_2x/doc/Text3d.py
new file mode 100644
index 00000000000..78993b9e8f3
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Text3d.py
@@ -0,0 +1,302 @@
+# Blender.Text3d module and the Text3d PyType object
+
+"""
+The Blender.Text3d submodule.
+
+Text3d Objects
+==============
+
+This module provides access to B{Font} objects in Blender.
+
+Example::
+ import Blender
+ from Blender import Curve, Object, Scene, Text3d
+ txt = Text3d.New("MyText") # create a new Text3d object called MyText
+ scn = Scene.GetCurrent() # get current scene
+ ob = scn.objects.new(txt) # create an object from the obdata in the current scene
+ ob.makeDisplayList() # rebuild the display list for this object
+ Window.RedrawAll()
+"""
+
+def New (name = None):
+ """
+ Create a new Text3d object.
+ @type name: string
+ @param name: The name for the new object..
+ @rtype: Blender Text3d
+ @return: The created Text3d Data object.
+ """
+
+def Get (name = None):
+ """
+ Get the Text3d object(s) from Blender.
+ @type name: string
+ @param name: The name of the Text3d object.
+ @rtype: Blender Text3d or a list of Blender Text3d's
+ @return: It depends on the 'name' parameter:
+ - (name): The Text3d object with the given name;
+ - (): A list with all Text3d objects in the current scene.
+ """
+class Text3d:
+ """
+ The Text3d object
+ =================
+ This object gives access Blender's B{Font} objects
+ @ivar frameWidth: The width of the active frame [0.0 - 50.0]
+ @ivar frameHeight: The height of the active frame [0.0 - 50.0]
+ @ivar frameX: The X position of the active frame [0.0 - 50.0]
+ @ivar frameY: The Y position of the active frame [0.0 - 50.0]
+
+ @ivar totalFrames: The total number of text frames (read only)
+ @ivar activeFrame: The active frame for this text data.
+ """
+
+ def getName():
+ """
+ Get the name of this Text3d object.
+ @rtype: string
+ """
+
+ def setName( name ):
+ """
+ Set the name of this Text3d object.
+ @type name: string
+ @param name: The new name.
+ @returns: None
+ """
+
+ def getText():
+ """
+ Get text string for this object
+ @rtype: string
+ """
+
+ def setText( name ):
+ """
+ Set the text string in this Text3d object
+ @type name: string
+ @param name: The new text string for this object.
+ @returns: None
+ """
+
+ def getDrawMode():
+ """
+ Get the drawing mode (3d, front, and/or back)
+ Gets the text3d's drawing modes. Uses module constants
+ - DRAW3D : "3D" is set
+ - DRAWFRONT : "Front" is set
+ - DRAWBACK : "Back" is set
+ @rtype: tuple of module constants
+ """
+
+ def setDrawMode(val):
+ """
+ Set the text3d's drawing mode. Uses module constants
+ - DRAW3D
+ - DRAWFRONT
+ - DRAWBACK
+ @rtype: None
+ @type val: single module constant or tuple of module constants
+ @param val : The Text3d's modes. See L{getDrawMode} for the meaning of
+ the constants.
+ """
+
+ def getUVordco():
+ """
+ Return whether UV coords are used for Texture mapping
+ """
+
+ def setUVordco(val):
+ """
+ Set the font to use UV coords for Texture mapping
+ """
+
+ def getBevelAmount():
+ """
+ Get the Text3d's bevel resolution value.
+ @rtype: float
+ """
+
+ def setBevelAmount(bevelresol):
+ """
+ Set the Text3d's bevel resolution value.
+ @rtype: None
+ @type bevelresol: float
+ @param bevelresol: The new Curve's bevel resolution value.
+ """
+
+ def getDefaultResolution():
+ """
+ Return Default text resolution.
+ @rtype: float
+ """
+
+ def setDefaultResolution(resolu):
+ """
+ Sets Default text Resolution.
+ @rtype: None
+ @type resolu: float
+ @param resolu: The new Curve's U-resolution value.
+ """
+
+ def getWidth():
+ """
+ Get the Text3d's width value.
+ @rtype: float
+ """
+
+ def setWidth(width):
+ """
+ Set the Text3d's width value.
+ @rtype: None
+ @type width: float
+ @param width: The new text3d's width value.
+ """
+
+ def getgetExtrudeDepth():
+ """
+ Get the text3d's ext1 value.
+ @rtype: float
+ """
+
+ def setgetExtrudeDepth(ext1):
+ """
+ Set the text3d's ext1 value.
+ @rtype: None
+ @type ext1: float
+ @param ext1: The new text3d's ext1 value.
+ """
+
+ def getExtrudeBevelDepth():
+ """
+ Get the text3d's ext2 value.
+ @rtype: float
+ """
+
+ def setExtrudeBevelDepth(ext2):
+ """
+ Set the text3d's ext2 value.
+ @rtype: None
+ @type ext2: float
+ @param ext2: The new text3d's ext2 value.
+ """
+
+ def getShear():
+ """
+ Get the text3d's shear value.
+ @rtype: float
+ """
+
+ def setShear(shear):
+ """
+ Set the text3d's shear value.
+ @rtype: None
+ @type shear: float
+ @param shear: The new text3d's shear value.
+ """
+
+ def getSize():
+ """
+ Get the text3d's size value.
+ @rtype: float
+ """
+
+ def setSize(size):
+ """
+ Set the text3d's size value.
+ @rtype: None
+ @type size: float
+ @param size: The new text3d's size value.
+ """
+
+ def getLineSeparation():
+ """
+ Get the text3d's ext2 value.
+ @rtype: float
+ """
+
+ def setLineSeparation(sep):
+ """
+ Set the text3d's ext2 value.
+ @rtype: None
+ @type sep: float
+ @param sep: The new text3d's separation value.
+ """
+
+ def getSpacing():
+ """
+ Get the text3d's spacing value.
+ @rtype: float
+ """
+
+ def setSpacing(spacing):
+ """
+ Set the text3d's spacing value.
+ @rtype: None
+ @type spacing: float
+ @param spacing: The new text3d's spacing value.
+ """
+
+ def getXoffset():
+ """
+ Get the text3d's Xoffset value.
+ @rtype: float
+ """
+
+ def setXoffset(xof):
+ """
+ Set the text3d's Xoffset value.
+ @rtype: None
+ @type xof: float
+ @param xof: The new text3d's Xoffset value.
+ """
+
+ def getYoffset():
+ """
+ Get the text3d's Yoffset value.
+ @rtype: float
+ """
+
+ def setYoffset(yof):
+ """
+ Set the text3d's Yoffset value.
+ @rtype: None
+ @type yof: float
+ @param yof: The new text3d's Yoffset value.
+ """
+
+ def getAlignment():
+ """
+ Get the text3d's alignment value. Uses module constants
+ - LEFT
+ - RIGHT
+ - MIDDLE
+ - FLUSH
+ @rtype: module constant
+ """
+
+ def setAlignment(align):
+ """
+ Set the text3d's Alignment value. Uses module constants
+ - LEFT
+ - RIGHT
+ - MIDDLE
+ - FLUSH
+ @rtype: None
+ @type align: module constant
+ @param align: The new text3d's Alignment value.
+ """
+
+ def addFrame():
+ """
+ Adds a text frame. maximum number of frames is 255.
+ @rtype: None
+ """
+
+ def removeFrame(index):
+ """
+ Removed the frame at this index
+ @rtype: None
+ """
+import id_generics
+Text3d.__doc__ += id_generics.attributes
diff --git a/source/blender/python/api2_2x/doc/Texture.py b/source/blender/python/api2_2x/doc/Texture.py
new file mode 100644
index 00000000000..004cd2df274
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Texture.py
@@ -0,0 +1,555 @@
+#
+# Blender.Texture module and the Texture PyType object
+#
+# Written by Alex Mole
+#
+
+"""
+The Blender.Texture submodule.
+
+B{New}:
+ - many new attributes in L{MTex} submodule
+ - new dictionaries (L{Texture.BlendModes}, L{Texture.Mappings}, L{Texture.Proj}) to use for the values of some of the new L{MTex} attributes.
+
+Texture
+=======
+
+This module provides access to B{Texture} objects in Blender.
+
+Example::
+
+ from Blender import Texture,Image,Material
+
+ footex = Texture.Get('foo') # get texture named 'foo'
+ footex.setType('Image') # make foo be an image texture
+ img = Image.Load('test.png') # load an image
+ footex.image = img # link the image to the texture
+
+ mat = Material.Get('bar') # get a material
+ mtextures = mat.getTextures() # get a list of the MTex objects
+ for mtex in mtextures:
+ if mtex.tex.type == Texture.Types.IMAGE:
+ print mtex.tex.image.filename # print the filenames of all the
+ # images in textures linked to "bar"
+
+ mat.setTexture(0, footex) # set the material's first texture
+ # to be our texture
+
+
+@type Types: readonly dictionary
+@var Types: The available texture types:
+ - NONE - No texture
+ - CLOUDS - Clouds texture
+ - WOOD - Wood texture
+ - MARBLE - Marble texture
+ - MAGIC - Magic texture
+ - BLEND - Blend texture
+ - STUCCI - Stucci texture
+ - NOISE - Noise texture
+ - IMAGE - Image texture
+ - PLUGIN - Plugin texture
+ - ENVMAP - EnvMap texture
+ - MUSGRAVE - Musgrave procedural texture
+ - VORONOI - Voronoi procedural texture
+ - DISTNOISE - Distorted noise texture
+
+@type Flags: readonly dictionary
+@var Flags: The available Texture flags:
+ - FLIPBLEND - Flips the blend texture's X and Y directions
+ - NEGALPHA - Reverse the alpha value
+ - CHECKER_ODD - Fill the "odd" checkerboard tiles
+ - CHECKER_EVEN - Fill the "even" checkerboard tiles
+ - COLORBAND - Enable colorband for this texture
+ - PREVIEW_ALPHA - Show alpha in preview
+ - REPEAT_XMIR - Mirrors X direction repeat
+ - REPEAT_YMIR - Mirrors Y direction repeat
+
+@type ImageFlags: readonly dictionary
+@var ImageFlags: The available image flags for Texture.imageFlags:
+ - INTERPOL - Interpolate pixels of the image
+ - USEALPHA - Use the alpha layer
+ - MIPMAP - Enable mipmapping [cannot be used with FIELDS]
+ - FIELDS - Work with field images [cannot be used with MIPMAP]
+ - ROT90 - Rotate the image 90 degrees when rendering
+ - CALCALPHA - Calculate an alpha from the RGB
+ - STFIELD - Denotes this is a standard field
+ - MOVIE - Use a movie for an image
+ - CYCLIC - Repeat animation image
+ - ANTI - Use anti-aliasing
+ - NORMALMAP - Use image RGB values for normal mapping
+
+@type ExtendModes: readonly dictionary
+@var ExtendModes: Extend, clip, repeat or checker modes for image textures
+ - EXTEND - Extends the colour of the edge
+ - CLIP - Return alpha 0.0 outside image
+ - CLIPCUBE - Return alpha 0.0 around cube-shaped area around image
+ - REPEAT - Repeat image vertically and horizontally
+ - CHECKER - Repeat image in checkerboard pattern
+
+@type Noise: readonly dictionary
+@var Noise: Noise types and bases. SINE, SAW and TRI are only used for
+ marble and wood textures, while the remainder are used for all textures
+ which has a noise basis function (for these textures, the constant should
+ be used with the second noise basis setting).
+ - SINE - Produce bands using sine wave (marble, wood textures)
+ - SAW - Produce bands using saw wave (marble, wood textures)
+ - TRI - Produce bands using triangle wave (marble, wood textures)
+ - BLENDER - Original Blender algorithm
+ - PERLIN - Ken Perlin's original (1985) algorithm
+ - IMPROVEDPERLIN - Ken Perlin's newer (2002) algorithm
+ - VORONOIF1 - none
+ - VORONOIF2 - none
+ - VORONOIF3 - none
+ - VORONOIF4 - none
+ - VORONOIF2F1 - none
+ - VORONOICRACKLE - none
+ - CELLNOISE - Steven Worley's cellular basis algorithm (1996)
+
+@type BlendModes: readonly dictionary
+@var BlendModes: The available texture blending modes:
+ - MIX - mix texture with value
+ - MULTIPLY - multiply texture with value
+ - ADD - add texture to value
+ - SUBTRACT - subtract texture from value
+ - DIVIDE - divide value by texture
+ - DARKEN - replace value with texture if texture is darker
+ - DIFFERENCE - difference of texture from value
+ - LIGHTEN - replace value with texture if texture is lighter
+ - SCREEN - 'screen' mode
+
+@type Mappings: readonly dictionary
+@var Mappings: The available 2D texture coordinate mappings for images:
+ - FLAT - flat projection
+ - CUBE - cube projection
+ - TUBE - cylindrical projection
+ - SPHERE - spherical projection
+
+@type Proj: readonly dictionary
+@var Proj: The available projections per axis:
+ - NONE - axis isn't used
+ - X - axis is used as final x axis
+ - Y - axis is used as final y axis
+ - Z - axis is used as final z axis
+
+@type STypes: readonly dictionary
+@var STypes: Texture-type specific data. Depending on the value of
+ Texture.type, certain groups will make sense. For instance, when a texture
+ is of type CLOUD, the CLD_xxx stypes can be used. Note that the first
+ value in each group is the default.
+ 1. Clouds type
+ - CLD_DEFAULT - Monochromatic noise
+ - CLD_COLOR - RGB noise
+ 2. Wood type
+ - WOD_BANDS - Use standard wood texture
+ - WOD_RINGS - Use wood rings
+ - WOD_BANDNOISE - Add noise to standard wood
+ - WOD_RINGNOISE - Add noise to rings
+ 3. Magic type
+ - MAG_DEFAULT - Magic has no STypes
+ 4. Marble type
+ - MBL_SOFT - Use soft marble
+ - MBL_SHARP - Use more clearly defined marble
+ - MBL_SHARPER - Use very clearly dfefined marble
+ 5. Blend type
+ - BLN_LIN - Use a linear progression
+ - BLN_QUAD - Use a quadratic progression
+ - BLN_EASE - Uses a more complicated blend function
+ - BLN_DIAG - Use a diagonal progression
+ - BLN_SPHERE - Use a progression with the shape of a sphere
+ - BLN_HALO - Use a quadratic progression with the shape of a sphere
+ 6. Stucci type
+ - STC_PLASTIC - Standard stucci
+ - STC_WALLIN - Creates dimples
+ - STC_WALLOUT - Creates ridges
+ 7. Noise type
+ - NSE_DEFAULT - Noise has no STypes
+ 8. Image type
+ - IMG_DEFAULT - Image has no STypes
+ 9. Plugin type
+ - PLG_DEFAULT - Plugin has no STypes
+ 10. Envmap type
+ - ENV_STATIC - Calculate map only once
+ - ENV_ANIM - Calculate map each rendering
+ - ENV_LOAD - Load map from disk
+ 11. Musgrave type
+ - MUS_MFRACTAL - Hetero Multifractal
+ - MUS_RIDGEDMF - Ridged Multifractal
+ - MUS_HYBRIDMF - Hybrid Multifractal
+ - MUS_FBM - Fractal Brownian Motion
+ - MUS_HTERRAIN - Hetero Terrain
+ 12. Voronoi type
+ - VN_INT - Only calculate intensity
+ - VN_COL1 - Color cells by position
+ - VN_COL2 - Same as Col1 plus outline based on F2-F1
+ - VN_COL3 - Same as Col2 multiplied by intensity
+ 13. Distorted noise type
+ - DN_BLENDER - Original Blender algorithm
+ - DN_PERLIN - Ken Perlin's original (1985) algorithm
+ - DN_IMPROVEDPERLIN - Ken Perlin's newer (2002) algorithm
+ - DN_VORONOIF1 - none
+ - DN_VORONOIF2 - none
+ - DN_VORONOIF3 - none
+ - DN_VORONOIF4 - none
+ - DN_VORONOIF2F1 - none
+ - DN_VORONOICRACKLE - none
+ - DN_CELLNOISE - Steven Worley's cellular basis algorithm (1996)
+
+@var TexCo: Flags for MTex.texco.
+ - ORCO - Use the original coordinates of the mesh
+ - REFL - Use reflection vector as texture coordinates
+ - NOR - Use normal vector as texture coordinates
+ - GLOB - Use global coordinates for the texture coordinates
+ - UV - Use UV coordinates for texture coordinates
+ - OBJECT - Use linked object's coordinates for texture coordinates
+ - WIN - Use screen coordinates as texture coordinates
+ - VIEW - Pass camera view vector on to the texture (World texture only!)
+ - STICK - Use mesh sticky coordinates for the texture coordinates
+ - STRESS - Use mesh stress coordinates for the texture coordinates
+ - TANGENT - Use mesh tangent coordinates for the texture coordinates
+@type TexCo: readonly dictionary
+
+@var MapTo: Flags for MTex.mapto.
+ - COL - Make the texture affect the basic colour of the material
+ - NOR - Make the texture affect the rendered normal
+ - CSP - Make the texture affect the specularity colour
+ - CMIR - Make the texture affect the mirror colour
+ - REF - Make the texture affect the diffuse reflectivity value
+ - SPEC - Make the texture affect the specularity value
+ - HARD - Make the texture affect the hardness value
+ - ALPHA - Make the texture affect the alpha value
+ - EMIT - Make the texture affect the emit value
+ - RAYMIR - Make the texture affect the mirror reflectivity value
+ - DISP - Make the texture displace the mesh
+ - TRANSLU - Make the texture affect the translucency value
+ - AMB - Make the texture affect the ambient value
+ - WARP - Make the texture affect texture coordinates for the following textures
+@type MapTo: readonly dictionary
+
+"""
+
+def New (name = 'Tex'):
+ """
+ Create a new Texture object.
+ @type name: string
+ @param name: The Texture name.
+ @rtype: Blender Texture
+ @return: The created Texture object.
+ """
+
+def Get (name = None):
+ """
+ Get the Texture object(s) from Blender.
+ @type name: string
+ @param name: The name of the Texture.
+ @rtype: Blender Texture or a list of Blender Textures
+ @return: It depends on the I{name} parameter:
+ - (name): The Texture object with the given I{name};
+ - (): A list with all Texture objects in the current scene.
+ """
+
+from IDProp import IDGroup, IDArray
+class Texture:
+ """
+ The Texture object
+ ==================
+ This object gives access to Texture-specific data in Blender.
+
+ Note that many of the attributes of this object are only relevant for
+ specific texture types.
+
+ @ivar animFrames: Number of frames of a movie to use.
+ Value is clamped to the range [0,300000].
+ @type animFrames: int
+ @ivar animOffset: Offsets the number of the first movie frame to use.
+ Value is clamped to the range [-300000,300000].
+ @type animOffset: int
+ @ivar animStart: Starting frame of the movie to use.
+ Value is clamped to the range [1,300000].
+ @type animStart: int
+ @ivar anti: Image anti-aliasing enabled. Also see L{ImageFlags}.
+ @type anti: int
+ @ivar brightness: Changes the brightness of a texture's color.
+ Value is clamped to the range [0.0,2.0].
+ @type brightness: float
+ @ivar calcAlpha: Calculation of image's alpha channel enabled. Also see L{ImageFlags}.
+ @type calcAlpha: int
+ @ivar contrast: Changes the contrast of a texture's color.
+ Value is clamped to the range [0.01,5.0].
+ @type contrast: float
+ @ivar crop: Sets the cropping extents (for image textures).
+ @type crop: tuple of 4 ints
+ @ivar cyclic: Looping of animated frames enabled. Also see L{ImageFlags}.
+ @type cyclic: boolean
+ @ivar distAmnt: Amount of distortion (for distorted noise textures).
+ Value is clamped to the range [0.0,10.0].
+ @type distAmnt: float
+ @ivar distMetric: The distance metric (for Voronoi textures).
+ @type distMetric: int
+ @ivar exp: Minkovsky exponent (for Minkovsky Voronoi textures).
+ Value is clamped to the range [0.01,10.0].
+ @type exp: float
+ @ivar extend: Texture's 'Extend' mode (for image textures). See L{ExtendModes}.
+ @type extend: int
+ @ivar fields: Use of image's fields enabled. Also see L{ImageFlags}.
+ @type fields: int
+ @ivar fieldsPerImage: Number of fields per rendered frame.
+ Value is clamped to the range [1,200].
+ @type fieldsPerImage: int
+ @ivar filterSize: The filter size (for image and envmap textures).
+ Value is clamped to the range [0.1,25.0].
+ @type filterSize: float
+ @ivar flags: Texture's 'Flag' bitfield. See L{Flags}.
+ bitmask.
+ @type flags: int
+ @ivar hFracDim: Highest fractional dimension (for Musgrave textures).
+ Value is clamped to the range [0.0001,2.0].
+ @type hFracDim: float
+ @ivar iScale: Intensity output scale (for Musgrave and Voronoi textures).
+ Value is clamped to the range [0.0,10.0].
+ @type iScale: float
+ @ivar image: Texture's image object.
+ @type image: Blender Image (or None)
+ @ivar imageFlags: Texture's 'ImageFlags' bits.
+ @type imageFlags: int
+ @ivar interpol: Interpolate image's pixels to fit texture mapping enabled. Also see L{ImageFlags}.
+ @type interpol: int
+ @ivar ipo: Texture Ipo data.
+ Contains the Ipo if one is assigned to the object, B{None} otherwise. Setting to B{None} clears the current Ipo..
+ @type ipo: Blender Ipo
+ @ivar lacunarity: Gap between succesive frequencies (for Musgrave textures).
+ Value is clamped to the range [0.0,6.0].
+ @type lacunarity: float
+ @ivar mipmap: Mipmaps enabled. Also see L{ImageFlags}.
+ @type mipmap: int
+ @ivar movie: Movie frames as images enabled. Also see L{ImageFlags}.
+ @type movie: int
+ @ivar noiseBasis: Noise basis type (wood, stucci, marble, clouds,
+ Musgrave, distorted). See L{Noise} dictionary.
+ @type noiseBasis: int
+ @ivar noiseBasis2: Additional noise basis type (wood, marble, distorted
+ noise). See L{Noise} dictionary.
+ @type noiseBasis2: int
+ @ivar noiseDepth: Noise depth (magic, marble, clouds).
+ Value is clamped to the range [0,6].
+ @type noiseDepth: int
+ @ivar noiseSize: Noise size (wood, stucci, marble, clouds, Musgrave,
+ distorted noise).
+ Value is clamped to the range [0.0001,2.0].
+ @type noiseSize: float
+ @ivar noiseType: Noise type (for wood, stucci, marble, clouds textures). Valid values are 'hard' or 'soft'.
+ @type noiseType: string
+ @ivar normalMap: Use of image RGB values for normal mapping enabled.
+ Also see L{ImageFlags}.
+ @type normalMap: int
+ @ivar octs: Number of frequencies (for Musgrave textures).
+ Value is clamped to the range [0.0,8.0].
+ @type octs: float
+ @ivar repeat: Repetition multiplier (for image textures).
+ @type repeat: tuple of 2 ints
+ @ivar rgbCol: RGB color tuple.
+ @type rgbCol: tuple of 3 floats
+ @ivar rot90: X/Y flip for rendering enabled. Also see L{ImageFlags}.
+ @type rot90: int
+ @ivar saw: Produce bands using saw wave (marble, wood textures). Also see L{Noise}.
+ @type saw: int
+ @ivar sine: Produce bands using sine wave (marble, wood textures). Also see L{Noise}.
+ @type sine: int
+ @ivar stField: Standard field deinterlacing enabled. Also see L{ImageFlags}.
+ @type stField: int
+ @ivar stype: Texture's 'SType' mode. See L{STypes}.
+ @type stype: int
+ @ivar tri: Produce bands using triangle wave (marble, wood textures). Also see L{Noise}.
+ @type tri: int
+ @ivar turbulence: Turbulence (for magic, wood, stucci, marble textures).
+ Value is clamped to the range [0.0,200.0].
+ @type turbulence: float
+ @ivar type: Texture's 'Type' mode. See L{Types}.
+ Value must be in the range [0,13].
+ @type type: int
+ @ivar useAlpha: Use of image's alpha channel enabled. Also see L{ImageFlags}.
+ @type useAlpha: int
+ @ivar weight1: Weight 1 (for Voronoi textures).
+ Value is clamped to the range [-2.0,2.0].
+ @type weight1: float
+ @ivar weight2: Weight 2 (for Voronoi textures).
+ Value is clamped to the range [-2.0,2.0].
+ @type weight2: float
+ @ivar weight3: Weight 3 (for Voronoi textures).
+ Value is clamped to the range [-2.0,2.0].
+ @type weight3: float
+ @ivar weight4: Weight 4 (for Voronoi textures).
+ Value is clamped to the range [-2.0,2.0].
+ @type weight4: float
+ @ivar colorband: Texture colorband, a list of colors,
+ each color a list of 5 floats [0 - 1], [r,g,b,a,pos].
+ The colorband can have between 1 and 31 colors.
+ @type colorband: list
+ @ivar autoRefresh: Refresh image on frame changes enabled.
+ @type autoRefresh: boolean
+ """
+
+ def getExtend():
+ """
+ Get the extend mode of the texture. See L{setExtend}.
+ @rtype: string.
+ """
+
+ def getImage():
+ """
+ Get the Image associated with this texture (or None).
+ @rtype: Blender Image
+ """
+
+ def getName():
+ """
+ Get the name of this Texture object.
+ @rtype: string
+ """
+
+ def getType():
+ """
+ Get this Texture's type. See L{setType}.
+ @rtype: string
+ """
+
+ def setExtend(extendmode):
+ """
+ Set the extend mode of this texture (only used for IMAGE textures)
+ @param extendmode: The new extend mode. One of:
+ 'Extend', 'Clip', 'ClipCube' and 'Repeat'
+ @type extendmode: string
+ """
+
+ def setFlags(f1=None, f2=None, f3=None, f4=None):
+ """
+ Set this object's flags.
+ @param f1,f2,f3,f4: Flags to be set (omitted flags are cleared). Can be any of
+ 'FlipBlendXY', 'NegAlpha', 'CheckerOdd', and 'CheckerEven'
+ @type f1,f2,f3,f4: string
+ """
+
+ def setImage(image):
+ """
+ Set the Image of this texture.
+ @param image: The new Image.
+ @type image: Blender Image
+ @warning: This sets the texture's type to 'Image' if it is not already.
+ """
+
+ def setImageFlags(f1=None, f2=None, f3=None, etc=None):
+ """
+ Set the Image flags (only makes sense for IMAGE textures). Omitted
+ flags are cleared.
+ @param f1, f2, f3, etc: Flag to set. See L{ImageFlags} for their meanings. Can be
+ any of: 'InterPol', 'UseAlpha', 'MipMap', 'Fields', 'Rot90',
+ 'CalcAlpha', 'Cyclic', 'Movie', 'StField', 'Anti' and 'NormalMap'
+ @type f1, f2, f3, etc: string
+ """
+
+ def setName(name):
+ """
+ Set the name of this Texture object.
+ @param name: The new name.
+ @type name: string
+ """
+
+ def setSType(stype):
+ """
+ Set the SType.
+ @param stype: The new stype. This can be any of the values listed in
+ L{STypes} or 'Default' which sets the stype to the default value.
+ @type stype: string
+
+ @note: the set of valid parameters is dependent on the current
+ texture type. Be sure to always set the texture type B{before}
+ setting the texture's stype; otherwise an exception might occur.
+ """
+
+ def setType(type):
+ """
+ Set this Texture's type.
+ @param type: The new type. Possible options are:
+ 'None', 'Clouds', 'Wood', 'Marble', 'Magic', 'Blend', 'Stucci',
+ 'Noise', 'Image', 'Plugin', 'EnvMap', 'Musgrave', 'Voronoi'
+ and 'DistNoise'
+ @type type: string
+ """
+ def evaluate(coord):
+ """
+ Evaluates the texture at this location and returns the result.
+
+ The return value is a 4D vector where (x,y,z,w) are (red, green, blue, intensity)
+ For greyscale textures, often intensity only will be used.
+ @type coord: vector
+ """
+
+import id_generics
+Texture.__doc__ += id_generics.attributes
+
+class MTex:
+ """
+ The MTex Object
+ ===============
+
+ This object links a material to a texture. It allows the same texture to be
+ used in several different ways.
+
+ @ivar tex: The Texture this is linked to.
+ @type tex: Blender Texture
+ @ivar texco: Texture coordinates ("Map input"). See L{TexCo}
+ @ivar mapto: "Map to" field of texture. OR'd values of L{MapTo}
+ @ivar object: Object whose space to use when texco is Object
+ @type object: Blender Object
+ @ivar col: Color that the texture blends with
+ @ivar dvar: Value that the texture blends with when not blending colors
+ @ivar blendmode: Texture blending mode. L{BlendModes}
+ @ivar colfac: Factor by which texture affects color
+ @ivar norfac: Factor by which texture affects normal
+ @ivar varfac: Factor by which texture affects most variables
+ @ivar dispfac: Factor by which texture affects displacement
+ @ivar warpfac: Factor by which texture affects warp
+ @ivar ofs: Offset to adjust texture space
+ @ivar size: Size to scale texture space
+ @ivar mapping: Mapping of texture coordinates (flat, cube, etc.). L{Mappings}
+ @ivar stencil: Stencil mode
+ @ivar neg: Negate texture values mode
+ @ivar noRGB: Convert texture RGB values to intensity values
+ @ivar correctNor: Correct normal mapping for Texture space and Object space
+ @ivar xproj: Projection of X axis to Texture space. L{Proj}
+ @ivar yproj: Projection of Y axis to Texture space. L{Proj}
+ @ivar zproj: Projection of Z axis to Texture space. L{Proj}
+ @ivar mtCol: How texture maps to color
+ @ivar mtNor: How texture maps to normals
+ @ivar mtCsp: How texture maps to specularity color
+ @ivar mtCmir: How texture maps to mirror color
+ @ivar mtRef: How texture maps to reflectivity
+ @ivar mtSpec: How texture maps to specularity
+ @ivar mtEmit: How texture maps to emit value
+ @ivar mtAlpha: How texture maps to alpha value
+ @ivar mtHard: How texture maps to hardness
+ @ivar mtRayMir: How texture maps to RayMir value
+ @ivar mtTranslu: How texture maps to translucency
+ @ivar mtAmb: How texture maps to ambient value
+ @ivar mtDisp: How texture maps to displacement
+ @ivar mtWarp: How texture maps to warp
+ """
+
+ def getIpo():
+ """
+ Get the Ipo associated with this texture object, if any.
+ @rtype: Ipo
+ @return: the wrapped ipo or None.
+ """
+
+ def setIpo(ipo):
+ """
+ Link an ipo to this texture object.
+ @type ipo: Blender Ipo
+ @param ipo: a "texture data" ipo.
+ """
+
+ def clearIpo():
+ """
+ Unlink the ipo from this texture object.
+ @return: True if there was an ipo linked or False otherwise.
+ """
diff --git a/source/blender/python/api2_2x/doc/Theme.py b/source/blender/python/api2_2x/doc/Theme.py
new file mode 100644
index 00000000000..90d0f8395a3
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Theme.py
@@ -0,0 +1,211 @@
+# Blender.Window.Theme submodule and the Theme PyType object
+
+"""
+The Blender.Window.Theme submodule.
+
+Theme
+=====
+
+This module provides access to B{Theme} objects in Blender.
+
+Example::
+ # this is a simplified version of the save_theme.py script
+ # shipped with Blender:
+ import Blender
+ from Blender.Window import Theme, FileSelector
+
+ theme = Theme.Get()[0] # get current theme
+
+ def write_theme(filename):
+ "Write the current theme as a BPython script"
+
+ f = file(filename, "w")
+
+ f.write("import Blender")
+ f.write("from Blender.Window import Theme")
+ f.write("theme = Theme.New('%s')" % theme.name)
+
+ for tsp in theme.get(): # write each theme space
+ command = "\\n%s = theme.get('%s')" % (tsp, tsp)
+ f.write(command + "\\n")
+ exec(command)
+ exec("vars = dir(%s)" % tsp)
+ vars.remove('theme')
+
+ for var in vars: # write each variable from each theme space
+ v = "%s.%s" % (tsp, var)
+ exec("value = %s" % v)
+ f.write("%s = %s\\n" % (v, value))
+
+ f.write('\\nBlender.Redraw(-1)') # redraw to update the screen
+ f.close()
+
+ FileSelector(write_theme, "Save Current Theme", default_fname)
+"""
+
+def New (name = "New Theme", theme = '<default>'):
+ """
+ Create a new Theme object.
+ @type name: string
+ @param name: The name of the new theme.
+ @type theme: Blender Theme
+ @param theme: a base theme to copy all data from. It defaults to the current
+ one.
+ @rtype: Blender Theme
+ @return: A new Blender Theme object.
+ """
+
+def Get (name = None):
+ """
+ Get the Theme object(s) from Blender.
+ @type name: string
+ @param name: The name of the Theme object.
+ @rtype: Blender Theme or a list of Blender Themes
+ @return: It depends on the I{name} parameter:
+ - (name): The Theme object called I{name}, None if not found;
+ - (): A list with all Theme objects currently in Blender.
+ """
+
+
+class Theme:
+ """
+ The Theme object
+ ================
+ This object gives access to Themes in Blender. Each Theme object is
+ composed of one UI (Use Interface) theme and many Space themes
+ (3d view, Text Editor, Buttons window, etc).
+ @ivar name: The name of this Theme object.
+ """
+
+ def getName():
+ """
+ Get the name of this Theme object.
+ @rtype: string
+ @return: the name of this Theme object.
+ """
+
+ def setName(s):
+ """
+ Rename this theme.
+ @type s: string
+ @param s: the new name.
+ """
+
+ def get(t = None):
+ """
+ Get a space or the ui (sub)theme from this Theme.
+ @type t: string, int or None
+ @param t: the wanted sub-theme as either:
+ - int: -1 for UI or the types in L{Window.Types<Window.Types>} for the others;
+ - string: use get() to know them (they are case insensitive);
+ - nothing: as written above, get() returns a list of names.
+ @rtype: Blender ThemeSpace or ThemeUI or list of sub-theme types as strings.
+ @return: It depends on the given parameter:
+ - (): a list with all available types, as strings;
+ - (type): the chosen sub-theme.
+ """
+
+class ThemeUI:
+ """
+ The User Interface sub-theme
+ ============================
+ This can be accessed with theme.get(t), where t can be 'ui' or -1.
+ The available variables follow the internal (C coded) ThemeUI struct in
+ Blender. Most of them represent rgba (red, green, blue, alpha) colors,
+ with each component in the range [0, 255]. There is more than one way to
+ access them.
+
+ Examples::
+ print outline.R
+ outline.r = 180 # it's case insensitive
+ outline[0] = 94 # 0 for red, 1 for green, ...
+ outline = [200, 200, 200, 255] # setting all components at once
+ @type theme: string
+ @ivar theme: the parent Theme for this object.
+ @ivar outline: theme rgba var.
+ @ivar neutral: theme rgba var.
+ @ivar action: theme rgba var.
+ @ivar setting: theme rgba var.
+ @ivar setting1: theme rgba var.
+ @ivar setting2: theme rgba var.
+ @ivar num: theme rgba var.
+ @ivar textfield: theme rgba var.
+ @ivar textfield_hi: theme rgba var.
+ @ivar popup: theme rgba var.
+ @ivar text: theme rgba var.
+ @ivar text_hi: theme rgba var.
+ @ivar menu_back: theme rgba var.
+ @ivar menu_item: theme rgba var.
+ @ivar menu_hilite: theme rgba var.
+ @ivar menu_text: theme rgba var.
+ @ivar menu_text_hi: theme rgba var.
+ @type drawType: int
+ @ivar drawType: the draw type (minimal, rounded, etc) in the range [1, 4].
+ @type iconTheme: string
+ @ivar iconTheme: the filename (without path) for the icon theme PNG in .blender/icons/
+ """
+
+class ThemeSpace:
+ """
+ The Space sub-themes
+ ====================
+ There is a sub-theme for each space in Blender (except for the Scripts
+ window, but it will be added soon). Please read the information about
+ L{Theme.ThemeUI}, since it is also relevant here. In Blender,
+ all theme spaces share the same C structure. For this reason, all of
+ them here share the same variables, event though some spaces only use
+ a few of them. This lower-level access is acceptable because generally
+ users will prefer to use the interface to change single theme options
+ and only use scripting to save or restore themes. But anyway, checking
+ the Themes tab in the User Preferences space in Blender and using the
+ bundled "Save current theme" script (or its simplified version written
+ on the top of this page) can help you finding out any specific info you
+ may need.
+ @type theme: string
+ @ivar theme: the parent Theme for this object.
+ @ivar back: theme rgba var.
+ @ivar text: theme rgba var.
+ @ivar text_hi: theme rgba var.
+ @ivar header: theme rgba var.
+ @ivar panel: theme rgba var.
+ @ivar shade1: theme rgba var.
+ @ivar shade2: theme rgba var.
+ @ivar hilite: theme rgba var.
+ @ivar grid: theme rgba var.
+ @ivar wire: theme rgba var.
+ @ivar select: theme rgba var.
+ @ivar active: theme rgba var.
+ @ivar transform: theme rgba var.
+ @ivar vertex: theme rgba var.
+ @ivar vertex_select: theme rgba var.
+ @ivar edge: theme rgba var.
+ @ivar edge_select: theme rgba var.
+ @ivar edge_seam: theme rgba var.
+ @ivar edge_facesel: theme rgba var.
+ @ivar face: theme rgba var.
+ @ivar face_select: theme rgba var.
+ @ivar face_dot: theme rgba var.
+ @ivar normal: theme rgba var.
+ @ivar bone_solid: theme rgba var.
+ @ivar bon_pose: theme rgba var.
+ @ivar strip: theme rgba var.
+ @ivar strip_select: theme rgba var.
+ @ivar syntaxl: theme rgba var.
+ @ivar syntaxn: theme rgba var.
+ @ivar syntaxb: theme rgba var.
+ @ivar syntaxv: theme rgba var.
+ @ivar syntaxc: theme rgba var.
+ @ivar movie: theme rgba var.
+ @ivar image: theme rgba var.
+ @ivar scene: theme rgba var.
+ @ivar audio: theme rgba var.
+ @ivar effect: theme rgba var.
+ @ivar plugin: theme rgba var.
+ @ivar transition: theme rgba var.
+ @ivar meta: theme rgba var.
+ @type vertex_size: int
+ @ivar vertex_size: size of the vertices dots on screen in the range [1, 10].
+ @type facedot_size: int
+ @ivar facedot_size: size of the face dots on screen in the range [1, 10].
+ """
+
diff --git a/source/blender/python/api2_2x/doc/TimeLine.py b/source/blender/python/api2_2x/doc/TimeLine.py
new file mode 100644
index 00000000000..0f456189767
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/TimeLine.py
@@ -0,0 +1,80 @@
+# Blender.Scene.TimeLine module
+
+"""
+The Blender.Scene.TimeLine submodule.
+
+TimeLine
+========
+
+This module gives access to B{Scene TimeLine Contexts} in Blender.
+
+Example::
+ import Blender
+ from Blender import Scene
+
+ # Only the current scene has a radiosity context.
+ # Naturally, any scene can be made the current one
+ # with scene.makeCurrent()
+
+ scn = Scene.GetCurrent()
+
+ # this is the only way to access the radiosity object:
+
+ time_line = scn.getTimeLine ()
+ time_line.add (50)
+ time_line.add (100)
+ time_line.setName (50, 'first')
+ time_line.setName (100, 'second')
+
+ Blender.Redraw(-1)
+"""
+
+class TimeLine:
+ """
+ The TimeLine object
+ ===================
+ This object wraps the current Scene's time line context in Blender.
+ """
+
+ def add(ival):
+ """
+ add new marker to time line
+ @type ival: int
+ @param ival: the frame number.
+ """
+
+ def delete(ival):
+ """
+ delete frame.
+ @type ival: int
+ @param ival: the frame number.
+ """
+
+ def setName(ival, sval):
+ """
+ set name of frame.
+ @type ival: int
+ @type sval: string
+ @param ival: the frame number.
+ @param sval: the frame name.
+ """
+
+ def getName(ival):
+ """
+ Get name of frame.
+ @type ival: int
+ @param ival: the frame number.
+ @rtype: string
+ @return: the frame name.
+ """
+
+ def getMarked(ival):
+ """
+ Get name of frame.
+ @type ival: int
+ @param ival: the frame number.
+ @rtype: int|string
+ @return: the list of frame number or name.
+
+ """
+
diff --git a/source/blender/python/api2_2x/doc/Types.py b/source/blender/python/api2_2x/doc/Types.py
new file mode 100644
index 00000000000..a08226e46ee
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Types.py
@@ -0,0 +1,70 @@
+# The Blender.Types submodule
+
+"""
+The Blender.Types submodule
+===========================
+
+This module is a dictionary of Blender Python types, for type checking.
+
+Example::
+ import Blender
+ from Blender import Types, Object, NMesh, Camera, Lamp
+ #
+ objs = Object.Get() # a list of all objects in the current scene
+ for o in objs:
+ print
+ print o, type(o)
+ data = o.getData()
+ print type(data)
+ if type(data) == Types.NMeshType:
+ if len(data.verts):
+ print "its vertices are obviously of type:", type(data.verts[0])
+ print "and its faces:", Types.NMFaceType
+ elif type(data) == Types.CameraType:
+ print "It's a Camera."
+ elif type(data) == Types.LampType:
+ print "Let there be light!"
+
+@var ObjectType: Blender Object. The base object, linked to its specific data
+ at its .data member variable.
+@var GroupType: Blender Group. A Group that references a list of objects that are a part of this group.
+@var NMeshType: Blender NMesh. The mesh structure.
+@var NMFaceType: Blender NMFace. A mesh face, with one (a point), two (an edge),
+ three (a triangular face) or four (a quad face) vertices.
+@var NMVertType: Blender NMVert. A mesh vertex.
+@var NMColType: Blender NMCol. A mesh rgba color.
+@var MeshType: Blender Mesh. The mesh structure.
+@var MFaceType: Blender MFace. A mesh face, with
+ three (a triangular face) or four (a quad face) vertices.
+@var MEdgeType: Blender MEdge. A mesh edge, with two vertices
+@var MVertType: Blender MVert. A mesh vertex which wraps a Blender mesh vertex
+ (typically an object returned from the mesh.verts sequence).
+@var PVertType: Blender MVert. A mesh vertex which does not wrap a Blender
+ mesh vertex (returned from L{Blender.Mesh.MVert()<Mesh.MVert.__init__>}).
+@var MColType: Blender MCol. A mesh rgba color.
+@var ArmatureType: Blender Armature. The "skeleton", for animating and deforming
+objects.
+@var BoneType: Blender Bone. Bones are, obviously, the "pieces" of an Armature.
+@var CurveType: Blender Curve.
+@var IpoType: Blender Ipo.
+@var MetaballType: Blender Metaball.
+@var CameraType: Blender Camera.
+@var ImageType: Blender Image.
+@var LampType: Blender Lamp.
+@var TextType: Blender Text.
+@var Text3dType: Blender Text3d.
+@var MaterialType: Blender Material.
+@var SceneType: A Blender Scene. Container of all other objects.
+@var ButtonType: Blender Button. One of the Draw widgets.
+@var vectorType: Blender vector. Used in NMesh, Mesh and elsewhere.
+@var matrix_Type: Blender matrix.
+@var quaternionType: Blender quaternion. Used in armatures.
+@var eulerType: Blender euler.
+@var bufferType: Blender buffer. A contiguous piece of storage, used in BGL.
+@var constantType: Blender constant. A constant dictionary.
+@var rgbTupleType: Blender rgbTuple. A (red, green, blue) triplet.
+@var TextureType: Blender Texture.
+@var MTexType: Blender MTex. Links materials to a texture.
+@var IDGroupType: Blender IDProperty Group type.
+@var IDArrayType: Blender IDProperty Array type.
+"""
diff --git a/source/blender/python/api2_2x/doc/Window.py b/source/blender/python/api2_2x/doc/Window.py
new file mode 100644
index 00000000000..b5145d34ca2
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Window.py
@@ -0,0 +1,524 @@
+# Blender.Window module and the Window PyType object
+
+"""
+The Blender.Window submodule.
+
+B{New}: renamed ViewLayer to L{ViewLayers} (actually added an alias, so both
+forms will work).
+
+Window
+======
+
+This module provides access to B{Window} functions in Blender.
+
+Example:
+--------
+
+FileSelector::
+
+ import Blender
+ from Blender import Window
+ #
+ def my_callback(filename): # callback for the FileSelector
+ print "You chose the file:", filename # do something with the chosen file
+ #
+ Window.FileSelector (my_callback, "Choose one!")
+
+Example:
+--------
+
+DrawProgressBar::
+
+ import Blender
+ from Blender.Window import DrawProgressBar
+ #
+ # substitute the bogus_*() function calls for your own, of course.
+ #
+ DrawProgressBar (0.0, "Importing data ...")
+ bogus_importData()
+ DrawProgressBar (0.3, "Building something")
+ bogus_build()
+ DrawProgressBar (0.8, "Updating Blender")
+ bogus_update()
+ DrawProgressBar (1.0, "Finished")
+ #
+ # another example:
+ #
+ number = 1
+ while number < 20:
+ file = filename + "00%d" % number
+ DrawProgressBar (number / 20.0, "Loading texture: %s" % file)
+ Blender.Image.Load(file)
+ number += 1
+
+ DrawProgressBar (1.0, "Finished loading")
+
+
+@type Types: readonly dictionary
+@var Types: The available Window Types.
+ - ACTION
+ - BUTS
+ - FILE
+ - IMAGE
+ - IMASEL
+ - INFO
+ - IPO
+ - NLA
+ - OOPS
+ - SCRIPT
+ - SEQ
+ - SOUND
+ - TEXT
+ - VIEW3D
+
+@type Qual: readonly dictionary
+@var Qual: Qualifier keys (shift, control, alt) bitmasks.
+ - LALT: left ALT key
+ - RALT: right ALT key
+ - ALT: any ALT key, ...
+ - LCTRL
+ - RCTRL
+ - CTRL
+ - LSHIFT
+ - RSHIFT
+ - SHIFT
+
+@type MButs: readonly dictionary
+@var MButs: Mouse buttons.
+ - L: left mouse button
+ - M: middle mouse button
+ - R: right mouse button
+
+@warn: The event system in Blender needs a rewrite, though we don't know when that will happen. Until then, event related functions here (L{QAdd}, L{QRead},
+L{QHandle}, etc.) can be used, but they are actually experimental and can be
+substituted for a better method when the rewrite happens. In other words, use
+them at your own risk, because though they should work well and allow many
+interesting and powerful possibilities, they can be deprecated in some future
+version of Blender / Blender Python.
+"""
+
+def Redraw (spacetype = '<Types.VIEW3D>'):
+ """
+ Force a redraw of a specific space type.
+ @type spacetype: int
+ @param spacetype: the space type, see L{Types}. By default the 3d Views are
+ redrawn. If spacetype < 0, all currently visible spaces are redrawn.
+ """
+
+def RedrawAll ():
+ """
+ Redraw all windows.
+ """
+
+def QRedrawAll ():
+ """
+ Redraw all windows by queue event.
+ """
+
+def FileSelector (callback, title = 'SELECT FILE', filename = '<default>'):
+ """
+ Open the file selector window in Blender. After the user selects a filename,
+ it is passed as parameter to the function callback given to FileSelector().
+ Example::
+ import Blender
+ #
+ def my_function(filename):
+ print 'The selected file was:', filename
+ #
+ Blender.Window.FileSelector (my_function, 'SAVE FILE')
+ @type callback: function that accepts a string: f(str)
+ @param callback: The function that must be provided to FileSelector() and
+ will receive the selected filename as parameter.
+ @type title: string
+ @param title: The string that appears in the button to confirm the selection
+ and return from the file selection window.
+ @type filename: string
+ @param filename: A filename. This defaults to Blender.Get('filename').
+ @warn: script links are not allowed to call the File / Image Selectors. This
+ is because script links global dictionaries are removed when they finish
+ execution and the File Selector needs the passed callback to stay around.
+ An alternative is calling the File Selector from another script (see
+ L{Blender.Run}).
+ """
+
+def ImageSelector (callback, title = 'SELECT IMAGE', filename = '<default>'):
+ """
+ Open the image selector window in Blender. After the user selects a filename,
+ it is passed as parameter to the function callback given to ImageSelector().
+ Example::
+ import Blender
+ #
+ def my_function(imagename):
+ print 'The selected image was:', imagename
+ #
+ Blender.Window.ImageSelector (my_function, 'LOAD IMAGE')
+ @type callback: function that accepts a string: f(str)
+ @param callback: The function that must be provided to ImageSelector() and
+ will receive the selected filename as parameter.
+ @type title: string
+ @param title: The string that appears in the button to confirm the selection
+ and return from the image selection window.
+ @type filename: string
+ @param filename: A filename. This defaults to L{Blender.Get}('filename').
+ @warn: script links are not allowed to call the File / Image Selectors. This
+ is because script links global dictionaries are removed when they finish
+ execution and the File Selector needs the passed callback to stay around.
+ An alternative is calling the File Selector from another script (see
+ L{Blender.Run}).
+ """
+
+def DrawProgressBar (done, text):
+ """
+ Draw a progress bar in the upper right corner of the screen. To cancel it
+ prematurely, users can press the "Esc" key. Start it with done = 0 and end
+ it with done = 1.
+ @type done: float
+ @param done: A float in [0.0, 1.0] that tells the advance in the progress
+ bar.
+ @type text: string
+ @param text: Info about what is currently being done "behind the scenes".
+ """
+
+def GetCursorPos ():
+ """
+ Get the current 3d cursor position.
+ @rtype: list of three floats
+ @return: the current position: [x, y, z].
+ """
+
+def GetActiveLayer ():
+ """
+ Get the bitmask for the active layer.
+ @note: if there is no 3d view it will return zero.
+ @rtype: int
+ @return: layer bitmask
+ """
+
+def SetActiveLayer(layermask):
+ """
+ Set the bitmask for the active layer.
+ @type layermask: int
+ @param layermask: An integer bitmask, to use humanly readable values do (1<<0) for the first layer, (1<<19) for the last layer.
+ """
+
+def SetCursorPos (coords):
+ """
+ Change the 3d cursor position.
+ @type coords: 3 floats or a list of 3 floats
+ @param coords: The new x, y, z coordinates.
+ @note: if visible, the 3d View must be redrawn to display the change. This
+ can be done with L{Redraw}.
+ """
+
+def WaitCursor (bool):
+ """
+ Set cursor to wait or back to normal mode.
+
+ Example::
+ Blender.Window.WaitCursor(1)
+ Blender.sys.sleep(2000) # do something that takes some time
+ Blender.Window.WaitCursor(0) # back
+
+ @type bool: int (bool)
+ @param bool: if nonzero the cursor is set to wait mode, otherwise to normal
+ mode.
+ @note: when the script finishes execution, the cursor is set to normal by
+ Blender itself.
+ """
+
+def GetViewVector ():
+ """
+ Get the current 3d view vector.
+ @rtype: list of three floats
+ @return: the current vector: [x, y, z].
+ """
+
+def GetViewMatrix ():
+ """
+ Get the current 3d view matrix.
+ @rtype: 4x4 float matrix (WRAPPED DATA)
+ @return: the current matrix.
+ """
+
+def GetPerspMatrix ():
+ """
+ Get the current 3d perspective matrix.
+ @rtype: 4x4 float matrix (WRAPPED DATA)
+ @return: the current matrix.
+ """
+
+def EditMode(enable = -1, undo_msg = 'From script', undo = 1):
+ """
+ Get and optionally set the current edit mode status: in or out.
+
+ Example::
+ in_editmode = Window.EditMode()
+ # MUST leave edit mode before changing an active mesh:
+ if in_editmode: Window.EditMode(0)
+ # ...
+ # make changes to the mesh
+ # ...
+ # be nice to the user and return things to how they were:
+ if in_editmode: Window.EditMode(1)
+ @type enable: int
+ @param enable: get/set current status:
+ - -1: just return current status (default);
+ - 0: leave edit mode;
+ - 1: enter edit mode.
+
+ It's not an error to try to change to a state that is already the
+ current one, the function simply ignores the request.
+ @type undo_msg: string
+ @param undo_msg: only needed when exiting edit mode (EditMode(0)). This
+ string is used as the undo message in the Mesh->Undo History submenu in
+ the 3d view header. Max length is 63, strings longer than that get
+ clamped.
+ @param undo: don't save Undo information (only needed when exiting edit
+ mode).
+ @type undo: int
+ @rtype: int (bool)
+ @return: 0 if Blender is not in edit mode right now, 1 otherwise.
+ @warn: this is an important function. NMesh operates on normal Blender
+ meshes, not edit mode ones. If a script changes an active mesh while in
+ edit mode, when the user leaves the mode the changes will be lost,
+ because the normal mesh will be rebuilt based on its unchanged edit mesh.
+ """
+
+def PoseMode(enable = -1):
+ """
+ Get and optionally set the current pose mode status: in or out.
+ @type enable: int
+ @param enable: get/set current status:
+ - -1: just return current status (default);
+ - 0: leave edit mode;
+ - 1: enter edit mode.
+
+ @return: 0 if Blender is not in edit mode right now, 1 otherwise.
+ @warn: This uses the active armature objects posemode status, enabling pose
+ mode for non armature objects will always fail.
+ """
+
+def ViewLayers (layers = [], winid = None):
+ """
+ Get and optionally set the currently visible layers in all 3d Views.
+ @type layers: list of ints
+ @param layers: a list with indexes of the layers that will be visible. Each
+ index must be in the range [1, 20]. If not given or equal to [], the
+ function simply returns the visible ones without changing anything.
+ @type winid: window id from as redurned by GetScreenInfo
+ @param winid: An optional argument to set the layer of a window
+ rather then setting the scene layers. For this to display in the 3d view
+ the layer lock must be disabled (unlocked).
+ @rtype: list of ints
+ @return: the currently visible layers.
+ """
+
+def GetViewQuat ():
+ """
+ Get the current VIEW3D view quaternion values.
+ @rtype: list of floats
+ @return: the quaternion as a list of four float values.
+ """
+
+def SetViewQuat (quat):
+ """
+ Set the current VIEW3D view quaternion.
+ @type quat: floats or list of floats
+ @param quat: four floats or a list of four floats.
+ """
+
+def GetViewOffset ():
+ """
+ Get the current VIEW3D offset values.
+ @rtype: list of floats
+ @return: a list with three floats: [x,y,z].
+ @note: The 3 values returned are flipped in comparison object locations.
+ """
+
+def SetViewOffset (ofs):
+ """
+ Set the current VIEW3D offset values.
+ @type ofs: 3 floats or list of 3 floats
+ @param ofs: the new view offset values.
+ @note: The value you give flipped in comparison object locations.
+ """
+
+def CameraView (camtov3d = 0):
+ """
+ Set the current VIEW3D view to the active camera's view. If there's no
+ active object or it is not of type 'Camera', the active camera for the
+ current scene is used instead.
+ @type camtov3d: int (bool)
+ @param camtov3d: if nonzero it's the camera that gets positioned at the
+ current view, instead of the view being changed to that of the camera.
+ """
+
+def QTest ():
+ """
+ Check if there are pending events in the event queue.
+ @rtype: int
+ @return: 0 if there are no pending events, non-zero otherwise.
+ """
+
+def QRead ():
+ """
+ Get the next pending event from the event queue.
+
+ Example::
+ # let's catch all events and move the 3D Cursor when user presses
+ # the left mouse button.
+ from Blender import Draw, Window
+
+ v3d = Window.GetScreenInfo(Window.Types.VIEW3D)
+ id = v3d[0]['id'] # get the (first) VIEW3D's id
+
+ done = 0
+
+ while not done: # enter a 'get event' loop
+ evt, val = Window.QRead() # catch next event
+ if evt in [Draw.MOUSEX, Draw.MOUSEY]:
+ continue # speeds things up, ignores mouse movement
+ elif evt in [Draw.ESCKEY, Draw.QKEY]: done = 1 # end loop
+ elif evt == Draw.SPACEKEY:
+ Draw.PupMenu("Hey!|What did you expect?")
+ elif evt == Draw.Redraw: # catch redraw events to handle them
+ Window.RedrawAll() # redraw all areas
+ elif evt == Draw.LEFTMOUSE: # left button pressed
+ Window.QAdd(id, evt, 1) # add the caught mouse event to our v3d
+ # actually we should check if the event happened inside that area,
+ # using Window.GetMouseCoords() and v3d[0]['vertices'] values.
+ Window.QHandle(id) # process the event
+ # do something fancy like putting some object where the
+ # user positioned the 3d cursor, then:
+ Window.Redraw() # show the change in the VIEW3D areas.
+
+ @rtype: list
+ @return: [event, val], where:
+ - event: int - the key or mouse event (see L{Draw});
+ - val: int - 1 for a key press, 0 for a release, new x or y coordinates
+ for mouse movement events.
+ """
+
+def QAdd (win, event, val, after = 0):
+ """
+ Add an event to some window's (actually called areas in Blender) event queue.
+ @type win: int
+ @param win: the window id, see L{GetScreenInfo}.
+ @type event: positive int
+ @param event: the event to add, see events in L{Draw}.
+ @type val: int
+ @param val: 1 for a key press, 0 for a release.
+ @type after: int (bool)
+ @param after: if nonzero the event is put after the current queue and added
+ later.
+ """
+
+def QHandle (winId):
+ """
+ Process immediately all pending events for the given window (area).
+ @type winId: int
+ @param winId: the window id, see L{GetScreenInfo}.
+ @note: see L{QAdd} for how to send events to a particular window.
+ """
+
+def GetMouseCoords ():
+ """
+ Get mouse's current screen coordinates.
+ @rtype: list with two ints
+ @return: a [x, y] list with the coordinates.
+ """
+
+def SetMouseCoords (coords):
+ """
+ Set mouse's current screen coordinates.
+ @type coords: (list of) two ints
+ @param coords: can be passed as x, y or [x, y] and are clamped to stay inside
+ the screen. If not given they default to the coordinates of the middle
+ of the screen.
+ """
+
+def GetMouseButtons ():
+ """
+ Get the current mouse button state (see / compare against L{MButs}).
+ @rtype: int
+ @return: an OR'ed flag with the currently pressed buttons.
+ """
+
+def GetKeyQualifiers ():
+ """
+ Get the current qualifier keys state (see / compare against L{Qual}).
+ @rtype: int
+ @return: an OR'ed combination of values in L{Qual}.
+ """
+
+def SetKeyQualifiers (qual):
+ """
+ Fake qualifier keys state. This is useful because some key events require
+ one or more qualifiers to be active (see L{QAdd}).
+ @type qual: int
+ @param qual: an OR'ed combination of values in L{Qual}.
+ @rtype: int
+ @return: the current state, that should be equal to 'qual'.
+ @warn: remember to reset the qual keys to 0 once they are not necessary
+ anymore.
+ """
+
+def GetAreaID ():
+ """
+ Get the current area's ID.
+ """
+
+def GetAreaSize ():
+ """
+ Get the current area's size.
+ @rtype: list with two ints
+ @return: a [width, height] list.
+ @note: the returned values are 1 pixel bigger than what L{GetScreenInfo}
+ returns for the 'vertices' of the same area.
+ """
+
+def GetScreenSize ():
+ """
+ Get Blender's screen size.
+ @rtype: list with two ints
+ @return: a [width, height] list.
+ """
+
+def GetScreens ():
+ """
+ Get the names of all available screens.
+ @rtype: list of strings
+ @return: a list of names that can be passed to L{SetScreen}.
+ """
+
+def SetScreen (name):
+ """
+ Set as current screen the one with the given name.
+ @type name: string
+ @param name: the name of an existing screen. Use L{GetScreens} to get
+ a list with all screen names.
+ """
+
+def GetScreenInfo (type = -1, rect = 'win', screen = ''):
+ """
+ Get info about the current screen setup.
+ @type type: int
+ @param type: the space type (see L{Types}) to restrict the
+ results to. If -1 (the default), info is reported about all available
+ areas.
+ @type rect: string
+ @param rect: the rectangle of interest. This defines if the corner
+ coordinates returned will refer to:
+ - the whole area: 'total'
+ - only the header: 'header'
+ - only the window content part (default): 'win'
+ @type screen: string
+ @param screen: the name of an available screen. The current one is used by
+ default.
+ @rtype: list of dictionaries
+ @return: a list of dictionaries, one for each area in the screen. Each
+ dictionary has these keys (all values are ints):
+ - 'vertices': [xmin, ymin, xmax, ymax] area corners;
+ - 'win': window type, see L{Types};
+ - 'id': this area's id.
+ """
diff --git a/source/blender/python/api2_2x/doc/World.py b/source/blender/python/api2_2x/doc/World.py
new file mode 100644
index 00000000000..d9e9bae750d
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/World.py
@@ -0,0 +1,351 @@
+# Blender.World module and the World PyType
+
+"""
+The Blender.World submodule
+
+B{New}: L{World.clearScriptLinks} accepts a parameter now.
+
+World
+=====
+
+The module world allows you to access all the data of a Blender World.
+
+Example::
+ import Blender
+ w = Blender.Get('World') #assume there exists a world named "world"
+ print w.getName()
+ w.hor = [1,1,.2]
+ print w.getHor()
+
+Example::
+ import Blender
+ from Blender import *
+
+ AllWorlds = Blender.World.Get() # returns a list of created world objects
+ AvailWorlds = len(AllWorlds) # returns the number of available world objects
+ PropWorld = dir(AllWorlds[0]) # returns the properties of the class world
+ NameWorld = AllWorlds[0].getName() # get name of the first world object
+
+ MiType = AllWorlds[0].getMistype() # get kind of mist from the first world object
+ MiParam = AllWorlds[0].getMist() # get the parameters intensity, start, end and height of the mist
+
+ HorColor = AllWorlds[0].getHor() # horizon color of the first world object
+ HorColorR = HorColor[0] # get the red channel (RGB) of the horizon color
+
+ ZenColor = AllWorlds[0].getZen() # zenith color of the first world object
+ ZenColorB = ZenColor[2] # get the blue channel (RGB) of the Zenith color
+
+ blending = AllWorlds[0].getSkytype() # get the blending modes (real, blend, paper) of the first world object
+"""
+
+def New (name):
+ """
+ Creates a new World.
+ @type name: string
+ @param name: World's name (optional).
+ @rtype: Blender World
+ @return: The created World. If the "name" parameter has not been provided, it will be automatically be set by blender.
+ """
+
+def Get (name):
+ """
+ Get an World from Blender.
+ @type name: string
+ @param name: The name of the world to retrieve.
+ @rtype: Blender World or a list of Blender Worlds
+ @return:
+ - (name): The World corresponding to the name
+ - (): A list with all Worlds in the current scene.
+ """
+
+
+def GetCurrent ():
+ """
+ Get the active world of the scene.
+ @rtype: Blender World or None
+ """
+
+class World:
+ """
+ The World object
+ ================
+ This object gives access to generic data from all worlds in Blender.
+ Its attributes depend upon its type.
+
+ @ivar skytype: type of the sky. Bit 0 : Blend; Bit 1 : Real; Bit 2 : paper.
+ @ivar mode:
+ @ivar mistype: type of mist : O : quadratic; 1 : linear; 2 : square
+ @ivar hor: the horizon color of a world object.
+ @ivar zen: the zenith color of a world object.
+ @ivar amb: the ambient color of a world object.
+ @ivar star: the star parameters of a world object. See getStar for the semantics of these parameters.
+ @ivar mist: the mist parameters of a world object. See getMist for the semantics of these parameters.
+ @type ipo: Blender Ipo
+ @ivar ipo: The world type ipo linked to this world object.
+ """
+
+ def getRange():
+ """
+ Retrieves the range parameter of a world object.
+ @rtype: float
+ @return: the range
+ """
+
+ def setRange(range):
+ """
+ Sets the range parameter of a world object.
+ @type range: float
+ @param range: the new range parameter
+ @rtype: None
+ @return: None
+ """
+
+ def getName():
+ """
+ Retrieves the name of a world object
+ @rtype: string
+ @return: the name of the world object.
+ """
+
+ def setName(name):
+ """
+ Sets the name of a world object.
+ @type name: string
+ @param name : the new name.
+ @rtype: None
+ @return: None
+ """
+
+ def getIpo():
+ """
+ Get the Ipo associated with this world object, if any.
+ @rtype: Ipo
+ @return: the wrapped ipo or None.
+ """
+
+ def setIpo(ipo):
+ """
+ Link an ipo to this world object.
+ @type ipo: Blender Ipo
+ @param ipo: a "camera data" ipo.
+ """
+
+ def clearIpo():
+ """
+ Unlink the ipo from this world object.
+ @return: True if there was an ipo linked or False otherwise.
+ """
+
+ def getSkytype():
+ """
+ Retrieves the skytype of a world object.
+ The skytype is a combination of 3 bits : Bit 0 : Blend; Bit 1 : Real; Bit 2 : paper.
+ @rtype: int
+ @return: the skytype of the world object.
+ """
+
+ def setSkytype(skytype):
+ """
+ Sets the skytype of a world object.
+ See getSkytype for the semantics of the parameter.
+ @type skytype: int
+ @param skytype : the new skytype.
+ @rtype: None
+ @return: None
+ """
+
+ def getMode():
+ """
+ Retrieves the mode of a world object.
+ The mode is a combination of 5 bits:
+ - Bit 0 : mist simulation
+ - Bit 1 : starfield simulation
+ - Bit 2,3 : reserved
+ - Bit 4 : ambient occlusion
+ @rtype: int
+ @return: the mode of the world object.
+ """
+
+ def setMode(mode):
+ """
+ Sets the mode of a world object.
+ See getMode for the semantics of the parameter.
+ @type mode: int
+ @param mode : the new mode.
+ @rtype: None
+ @return: None
+ """
+
+ def getMistype():
+ """
+ Retrieves the mist type of a world object.
+ The mist type is an integer 0 : quadratic; 1 : linear; 2 : square.
+ @rtype: int
+ @return: the mistype of the world object.
+ """
+
+ def setMistype(mistype):
+ """
+ Sets the mist type of a world object.
+ See getMistype for the semantics of the parameter.
+ @type mistype: int
+ @param mistype : the new mist type.
+ @rtype: None
+ @return: None
+ """
+
+ def getHor():
+ """
+ Retrieves the horizon color of a world object.
+ This color is a list of 3 floats.
+ @rtype: list of three floats
+ @return: the horizon color of the world object.
+ """
+
+ def setHor(hor):
+ """
+ Sets the horizon color of a world object.
+ @type hor: list of three floats
+ @param hor : the new hor.
+ @rtype: None
+ @return: None
+ """
+
+ def getZen():
+ """
+ Retrieves the zenith color of a world object.
+ This color is a list of 3 floats.
+ @rtype: list of three floats
+ @return: the zenith color of the world object.
+ """
+
+ def setZen(zen):
+ """
+ Sets the zenith color of a world object.
+ @type zen: list of three floats
+ @param zen : the new zenith color.
+ @rtype: None
+ @return: None
+ """
+
+ def getAmb():
+ """
+ Retrieves the ambient color of a world object.
+ This color is a list of 3 floats.
+ @rtype: list of three floats
+ @return: the ambient color of the world object.
+ """
+
+ def setAmb(amb):
+ """
+ Sets the ambient color of a world object.
+ @type amb: list of three floats
+ @param amb : the new ambient color.
+ @rtype: None
+ @return: None
+ """
+
+ def getStar():
+ """
+ Retrieves the star parameters of a world object.
+ It is a list of nine floats :
+ red component of the color
+ green component of the color
+ blue component of the color
+ size of the stars
+ minimal distance between the stars
+ average distance between the stars
+ variations of the stars color
+ @rtype: list of nine floats
+ @return: the star parameters
+ """
+
+ def setStar(star):
+ """
+ Sets the star parameters of a world object.
+ See getStar for the semantics of the parameter.
+ @type star: list of 9 floats
+ @param star : the new star parameters.
+ @rtype: None
+ @return: None
+ """
+
+ def getMist():
+ """
+ Retrieves the mist parameters of a world object.
+ It is a list of four floats :
+ intensity of the mist
+ start of the mist
+ end of the mist
+ height of the mist
+ @rtype: list of four floats
+ @return: the mist parameters
+ """
+
+ def setMist(mist):
+ """
+ Sets the mist parameters of a world object.
+ See getMist for the semantics of the parameter.
+ @type mist: list of 4 floats
+ @param mist : the new mist parameters.
+ @rtype: None
+ @return: None
+ """
+
+ def getScriptLinks (event):
+ """
+ Get a list with this World's script links of type 'event'.
+ @type event: string
+ @param event: "FrameChanged", "Redraw", "Render".
+ @rtype: list
+ @return: a list with Blender L{Text} names (the script links of the given
+ 'event' type) or None if there are no script links at all.
+ """
+
+ def clearScriptLinks (links = None):
+ """
+ Delete script links from this World :). If no list is specified, all
+ script links are deleted.
+ @type links: list of strings
+ @param links: None (default) or a list of Blender L{Text} names.
+ """
+
+ def addScriptLink (text, event):
+ """
+ Add a new script link to this World.
+ @type text: string
+ @param text: the name of an existing Blender L{Text}.
+ @type event: string
+ @param event: "FrameChanged", "Redraw" or "Render".
+ """
+
+ def setCurrent ():
+ """
+ Make this world active in the current scene.
+ @rtype: None
+ @return: None
+ """
+
+ def insertIpoKey(keytype):
+ """
+ Inserts keytype values in world ipo at curframe. Uses module constants.
+ @type keytype: Integer
+ @param keytype:
+ -ZENTIH
+ -HORIZON
+ -MIST
+ -STARS
+ -OFFSET
+ -SIZE
+ @return: py_none
+ """
+
+ def __copy__ ():
+ """
+ Make a copy of this world
+ @rtype: World
+ @return: a copy of this world
+ """
+
+import id_generics
+World.__doc__ += id_generics.attributes
diff --git a/source/blender/python/api2_2x/doc/Worlddoc.txt b/source/blender/python/api2_2x/doc/Worlddoc.txt
new file mode 100644
index 00000000000..78e325fd7ce
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/Worlddoc.txt
@@ -0,0 +1,55 @@
+METABALL Module documentation
+
+INTRODUCTION
+The metaball module effect allows you to access all the data of an metaball.
+A metaball consists of several (maybe only one) metaelems, which are spheres, interacting with each other, thus creating soft organic volumes.
+
+functions of the module :
+New(name) : creates ans returns a metaball object.
+Get(opt : name) : if the parameter name is given, returns the metaball object whose name has been passed, or Py_None, if no such metaball exists in the current scene. If no parameter is given, returns a list of all the metaballs in the current scene.
+get : alias for Get
+
+Metaball object member functions :
+
+getName()Return Metaball name
+setName(string newname) - Sets Metaball name
+getWiresize() - Return Metaball wire size
+setWiresize(float val) - Sets Metaball wire size
+getRendersize() - Return Metaball render size
+setRendersize(float newval- Sets Metaball render size
+getThresh()- Return Metaball threshold
+setThresh(float newval)- Sets Metaball threshold
+getBbox,- Return Metaball bounding box(a list of eight lists of three elements)
+getNMetaElems() Returns the number of Metaelems (basic spheres)
+getMetatype(int num_metaelem): returns the type of the metaelem number num_metaelem.
+0 : ball
+1 : tubex
+2 : tubey
+3 : tubez
+setMetatype(int num_metaelem,int newtype) : sets the type of the metaelem number num_metaelem.
+getMetadata(field_name,int num_metaelem) gets Metaball MetaData. Explained later.
+setMetadata(field_name,int num_metaelem,newval) sets Metaball MetaData. Explained later.
+getMetalay(int num_metaelem)
+getMetax(int num_metaelem) : gets the x coordinate of the metaelement
+setMetax(int num_metaelem,float newval) : sets the x coordinate of the metaelement
+getMetay(int num_metaelem) : gets the y coordinate of the metaelement
+setMetay(int num_metaelem,float newval) : sets the y coordinate of the metaelement
+getMetaz(int num_metaelem) : gets the z coordinate of the metaelement
+setMetaz(int num_metaelem,float newval) : sets the z coordinate of the metaelement
+getMetas(int num_metaelem) : gets the s coordinate of the metaelement
+setMetas(int num_metaelem,float newval) : sets the s coordinate of the metaelement
+getMetalen(int num_metaelem) : gets the length of the metaelement. Important for tubes.
+setMetalen(int num_metaelem,float newval) : sets the length of the metaelement. Important for tubes.
+getloc, - Gets Metaball loc values
+setloc, (f f f) - Sets Metaball loc values
+getrot, () - Gets Metaball rot values
+setrot,, (f f f) - Sets Metaball rot values
+getsize,() - Gets Metaball size values
+setsize,(f f f) - Sets Metaball size values
+
+
+
+
+The Object.attribute syntax
+
+The attribute can take these values : seed,nabla,sta,end,lifetime,normfac,obfac,randfac,texfac,randlife,vectsize,totpart,force,mult,life,child,mat,defvec. \ No newline at end of file
diff --git a/source/blender/python/api2_2x/doc/epy_docgen-3.sh b/source/blender/python/api2_2x/doc/epy_docgen-3.sh
new file mode 100644
index 00000000000..bec7653b152
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/epy_docgen-3.sh
@@ -0,0 +1,12 @@
+# epy_docgen.sh
+# generates blender python doc using epydoc
+# requires epydoc in your PATH.
+# run from the doc directory containing the .py files
+# usage: sh epy_docgen.sh
+
+# set posix locale so regex works properly for [A-Z]*.py
+LC_ALL=POSIX
+
+epydoc -o BPY_API --url "http://www.blender.org" --top API_intro \
+ --name "Blender" --no-private --no-frames \
+$( ls [A-Z]*.py )
diff --git a/source/blender/python/api2_2x/doc/epy_docgen.sh b/source/blender/python/api2_2x/doc/epy_docgen.sh
new file mode 100644
index 00000000000..d709ee73190
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/epy_docgen.sh
@@ -0,0 +1,12 @@
+# epy_docgen.sh
+# generates blender python doc using epydoc
+# requires epydoc in your PATH.
+# run from the doc directory containing the .py files
+# usage: sh epy_docgen.sh
+
+# set posix locale so regex works properly for [A-Z]*.py
+LC_ALL=POSIX
+
+epydoc -o BPY_API --url "http://www.blender.org" -t API_intro.py \
+ -n "Blender" --no-private --no-frames \
+$( ls [A-Z]*.py )
diff --git a/source/blender/python/api2_2x/doc/id_generics.py b/source/blender/python/api2_2x/doc/id_generics.py
new file mode 100644
index 00000000000..30c7e5d6a3c
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/id_generics.py
@@ -0,0 +1,30 @@
+attributes = """
+ @ivar name: unique name within each blend file.
+
+ The name is case sensitive and 21 characters maximum length.
+
+ B{Note}: a blend file may have naming collisions when external library data is used,
+ be sure to check the value of L{lib}.
+
+ B{Note}: Setting a value longer then 21 characters will be shortened
+ @type name: string
+ @ivar lib: path to the blend file this datablock is stored in (readonly).
+
+ lib will be None unless you are using external blend files with (File, Append/Link)
+
+ B{Note}: the path may be relative, to get the full path use L{Blender.sys.expandpath<Sys.expandpath>}
+ @type lib: string or None
+
+ @ivar fakeUser: When set to True, this datablock wont be removed, even if nothing is using it.
+ All data has this disabled by default except for Actions.
+ @type fakeUser: bool
+ @ivar tag: A temporary tag that to flag data as being used within a loop.
+ always set all tags to True or False before using since blender uses this flag for its own internal operations.
+ @type tag: bool
+ @ivar users: The number of users this datablock has. (readonly)
+ Zero user datablocks are de-allocated after reloading and saving.
+ @type users: int
+ @ivar properties: Returns an L{IDGroup<IDProp.IDGroup>} reference to this
+ datablocks's ID Properties.
+ @type properties: L{IDGroup<IDProp.IDGroup>}
+""" \ No newline at end of file
diff --git a/source/blender/python/api2_2x/doc/testbgl.py b/source/blender/python/api2_2x/doc/testbgl.py
new file mode 100644
index 00000000000..e895d01df69
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/testbgl.py
@@ -0,0 +1,45 @@
+# Testing the BGL module
+
+import Blender
+from Blender.BGL import *
+from Blender import Draw
+
+R = G = B = 0
+A = 1
+
+instructions = "Hold mouse buttons to change the background color."
+quitting = " Press ESC or q to quit."
+
+def show_win():
+ glClearColor(R,G,B,A) # define color used to clear buffers
+ glClear(GL_COLOR_BUFFER_BIT) # use it to clear the color buffer
+ glColor3f(1,1,1) # change default color
+ glRasterPos2i(50,100) # move cursor to x = 50, y = 100
+ Draw.Text("Testing BGL + Draw") # draw this text there
+ glRasterPos2i(350,20) # move cursor again
+ Draw.Text(instructions + quitting) # draw another msg
+ glBegin(GL_LINE_LOOP) # begin a vertex-data list
+ glVertex2i(46,92)
+ glVertex2i(120,92)
+ glVertex2i(120,115)
+ glVertex2i(46,115)
+ glEnd() # close this list
+ glColor3f(0.35,0.18,0.92) # change default color again
+ glBegin(GL_POLYGON) # another list, for a polygon
+ glVertex2i(315, 292)
+ glVertex2i(412, 200)
+ glVertex2i(264, 256)
+ glEnd()
+ Draw.Redraw(1) # make changes visible.
+
+def ev(evt, val): # this is a callback for Draw.Register()
+ global R,G,B,A # it handles input events
+ if evt == Draw.ESCKEY or evt == Draw.QKEY:
+ Draw.Exit() # this quits the script
+ elif evt == Draw.LEFTMOUSE: R = 1 - R
+ elif evt == Draw.MIDDLEMOUSE: G = 1 - G
+ elif evt == Draw.RIGHTMOUSE: B = 1 - B
+ else:
+ Draw.Register(show_win, ev, None)
+
+Draw.Register(show_win, ev, None) # start the main loop
diff --git a/source/blender/python/api2_2x/doc/testcamera.py b/source/blender/python/api2_2x/doc/testcamera.py
new file mode 100644
index 00000000000..a84b3ac5b15
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/testcamera.py
@@ -0,0 +1,137 @@
+# Blender.Camera module and Camera PyType test file
+# This also works with Lamp and Material, simply uncomment the right
+# line below
+
+MODULE = "Camera"
+#MODULE = "Lamp"
+#MODULE = "Material"
+BPY_OBJECT = MODULE
+
+LONG_STRING = "Supercalifragilisticspialidous"
+
+import types, sys
+import Blender
+exec ("from Blender import %s" % MODULE)
+
+def PRINT_HEADER(header, sep):
+ print "\n", sep * 79
+ print header
+ print sep * 79
+
+def PRINT_UNDERLINED(str):
+ print "\n", str
+ print "-" * len(str)
+
+def PRINT_AND_RM(arg, branch, d):
+ for a in arg:
+ if a in d:
+ d.remove(a)
+ print "\n%s.%s:" % (branch, a),
+ exec("print %s.%s" % (branch, a))
+
+PRINT_HEADER("Testing the Blender.%s module" % MODULE, '=')
+
+exec ("Module_dir = dir (%s)" % MODULE)
+print "\ndir (%s):" % MODULE
+print Module_dir
+
+PRINT_AND_RM (["__name__", "__doc__"], MODULE, Module_dir)
+
+for item in Module_dir:
+ hooked = 0
+ branch = "%s.%s" % (MODULE, item)
+ PRINT_HEADER(branch, "-")
+ exec ("item_type = type (%s)" % branch)
+ print item_type
+ exec ("sub_dir = dir(%s)" % branch)
+ PRINT_AND_RM (["__name__", "__doc__"], branch, sub_dir)
+ if item_type == types.BuiltinFunctionType:
+ PRINT_UNDERLINED ("Executing %s:" % branch)
+ exec ("result = %s()" % branch)
+ print "Returned value is: ", result
+ if item in ["Get", "get"] and not hooked:
+ if len(result):
+ obj = result[0]
+ hooked = 1
+
+if hooked:
+ PRINT_HEADER(obj, "=")
+ exec ("obj_dir = dir(obj)")
+ print "\ndir():"
+ print obj_dir
+
+ methods = []
+ member_vars = []
+
+ for item in obj_dir:
+ exec ("item_type = type (obj.%s)" % item)
+ if item_type == types.BuiltinMethodType:
+ methods.append(item)
+ else:
+ member_vars.append(item)
+
+ PRINT_HEADER("%s Methods" % BPY_OBJECT, '-')
+ if methods: print methods
+ else: print "XXX No methods found in %s" % BPY_OBJECT
+
+ PRINT_HEADER("%s Member Variables" % BPY_OBJECT, '-')
+ if member_vars:
+ for m in member_vars:
+ PRINT_UNDERLINED(m)
+ exec ("mvalue = obj.%s" % m)
+ exec ("mtype = type (obj.%s)" % m)
+ mtype = str(mtype).split("'")[1]
+ print "%s: %s" % (mtype, mvalue)
+
+ M = m[0].upper() + m[1:]
+ setM = "set%s" % M
+ getM = "get%s" % M
+ if setM in methods:
+ print "There is a .%s() method." % setM
+ methods.remove(setM)
+ if mtype == 'str':
+ try:
+ print "Trying to set string to %s" % LONG_STRING
+ exec("obj.%s('%s')" % (setM, LONG_STRING))
+ exec("get_str = obj.%s()" % getM)
+ print "It returned:", get_str
+ len_str = len(get_str)
+ if len_str < 100:
+ print "It correctly clamped the string to %s chars." % len_str
+ except:
+ PRINT_HEADER("FAILED in .%s()" % setM, "X")
+ print sys.exc_info()[0]
+ elif mtype == 'float':
+ try:
+ exec("obj.%s(%d)" % (setM, -999999))
+ exec("result = obj.%s()" % getM)
+ print "%s's minimum value is %f" % (m, result)
+ exec("obj.%s(%d)" % (setM, 999999))
+ exec("result = obj.%s()" % getM)
+ print "%s's maximum value is %f" % (m, result)
+ except:
+ PRINT_HEADER("FAILED in %s or %s" % (setM, getM), "X")
+ print sys.exc_info()[0]
+ elif mtype == 'int':
+ try:
+ dict = M+"s"
+ if dict in member_vars:
+ exec("key = obj.%s.keys()[1]" % dict)
+ exec("obj.%s('%s')" % (setM, key))
+ exec("result = obj.%s()" % getM)
+ except:
+ PRINT_HEADER("FAILED in %s or %s" % (setM, getM), "X")
+ print sys.exc_info()[0]
+
+ if getM in methods:
+ print "There is a .%s() method." % getM,
+ methods.remove(getM)
+ exec("result = obj.%s()" % getM)
+ print "It returned:", result
+
+ else: print "XXX No member variables found in %s" % BPY_OBJECT
+
+else: # the module .Get() function found nothing
+ PRINT_HEADER("Failed trying to %s.Get() a %s object"
+ % (MODULE, BPY_OBJECT), 'X')
+
diff --git a/source/blender/python/api2_2x/doc/testcurve.py b/source/blender/python/api2_2x/doc/testcurve.py
new file mode 100644
index 00000000000..1db037bc385
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/testcurve.py
@@ -0,0 +1,20 @@
+import Blender
+
+
+list = Blender.Curve.Get()
+
+print list
+
+cur = Blender.Curve.Get('Curve')
+
+
+for prop in ["Name","PathLen","Totcol","Flag","Bevresol","Resolu","Resolv","Width","Ext1","Ext2","Loc","Rot","Size"]:
+ value = eval("cur.get%s()"%prop)
+ print prop,"-->",value
+ exec("cur.set%s(value)"%prop)
+
+
+
+for attr in [ "name","pathlen","totcol","flag","bevresol","resolu","resolv","width","ext1","ext2","loc","rot","size"]:
+ value = eval("cur.%s"%attr)
+ exec("cur.%s = value"%attr) \ No newline at end of file
diff --git a/source/blender/python/api2_2x/doc/testeffect.py b/source/blender/python/api2_2x/doc/testeffect.py
new file mode 100644
index 00000000000..5d9b65c36be
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/testeffect.py
@@ -0,0 +1,65 @@
+import Blender
+
+################## WARNING ########################
+#
+# this script tests the Effect module, and its submodules : Wave, Build and Particle
+# an object name "Plane" must be created, with three effects attached to it.
+# the first effect must be a "Build" effect
+# the second effect must be a "Wave" effect
+# the third effect must be a "Particle" effect
+#
+########################################################
+
+
+
+effect = Blender.Effect.New()
+print effect
+
+
+
+build = Blender.Effect.Get('Plane',0)
+
+
+for param in ['Type','Flag','Len','Sfra'] :
+ value = eval("build.get%s()"%param)
+ print param,value
+ value1 = eval("build.set%s(%s)"%(param,value))
+ print value1
+
+for param in ["sfra","len"]:
+ str = "build.%s"%param
+ value = eval(str)
+ print str,value
+ exec("build.%s = value"%param)
+
+
+
+wave = Blender.Effect.Get('Plane',1)
+for param in ['Type','Flag','Startx','Starty','Height', 'Width', 'Narrow', 'Speed', 'Minfac', 'Damp', 'Timeoffs' ,'Lifetime'] :
+ value = eval("wave.get%s()"%param)
+ print param,value
+ value1 = eval("wave.set%s(%s)"%(param,value))
+ print value1
+
+
+for param in ["lifetime","timeoffs","damp","minfac","speed","narrow","width","height","startx","starty"]:
+ str = "wave.%s"%param
+ value = eval(str)
+ print str,value
+ exec("wave.%s = value"%param)
+
+
+
+
+particle = Blender.Effect.Get('Plane',2)
+for param in ['Type','Flag','StartTime','EndTime','Lifetime','Normfac','Obfac','Randfac','Texfac','Randlife','Nabla','Totpart','Totkey','Seed','Force','Mult','Life','Child','Mat','Defvec'] :
+ value = eval("particle.get%s()"%param)
+ print param,value
+ value1 = eval("particle.set%s(%s)"%(param,value))
+ print value1
+
+for param in ['seed','nabla','sta','end','lifetime','normfac','obfac','randfac','texfac','randlife','vectsize','totpart','force','mult','life','child','mat','defvec']:
+ str = "particle.%s"%param
+ value = eval(str)
+ print str,value
+ exec("particle.%s = value"%param) \ No newline at end of file
diff --git a/source/blender/python/api2_2x/doc/testipo.py b/source/blender/python/api2_2x/doc/testipo.py
new file mode 100644
index 00000000000..89db92f03c2
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/testipo.py
@@ -0,0 +1,24 @@
+import Blender
+
+ipo = Blender.Ipo.Get()
+print "Available ipos : ",ipo
+
+ipo = Blender.Ipo.Get('ObIpo')# hope there is an ipo named "ObIpo"...
+
+
+for prop in ["Name","Blocktype","Showkey","Pad","Rctf"]:
+ val = eval("ipo.get%s()"%prop)
+ print prop,"-->",val
+ #exec("ipo.set%s(%s)"%(prop,val))
+
+try :
+ val = ipo.getCurveBP(0)
+ print "CurveBP -->",val
+except : print "error BP"
+val = ipo.getNcurves()
+print "NCurves -->",val
+
+curvebeztriple = ipo.getCurveBeztriple(0,0)
+print "curvebeztriple",curvebeztriple
+ipo.setCurveBeztriple(0,0,[1,2,3,4,5,6,7,8,9])
+print ipo.getCurveBeztriple(0,0)
diff --git a/source/blender/python/api2_2x/doc/testmball.py b/source/blender/python/api2_2x/doc/testmball.py
new file mode 100644
index 00000000000..41c8377193f
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/testmball.py
@@ -0,0 +1,37 @@
+import Blender
+
+
+
+
+d = Blender.Metaball.Get('Meta')
+
+for prop in ["Name","Wiresize","Thresh","Rendersize","loc","rot","size"]:
+ str = "d.get%s()"%prop
+ val = eval(str)
+ print str,"-->",val
+ str1 = "d.set%s(%s)"%(prop,repr(val))
+ val1 = eval(str1)
+ print str1,"-->",val1
+
+
+
+nelem = d.getNMetaElems()
+print "getNMetaElems",nelem
+
+
+for prop in ['lay','type','selcol','flag','pad','x','y','z','expx','expy','expz','rad','rad2','s','len','maxrad2']:
+ str = "d.getMeta%s(0)"%prop
+ value = eval(str)
+ print str,"-->",value
+ str1 = "d.setMeta%s(0,%s)"%(prop,repr(value))
+ value1 = eval(str1)
+ print str1,"-->",value1
+print;print
+
+for field in ["name","loc","rot","size"]:
+ str = "d.%s"%field
+ val = eval(str)
+ print str,"-->",val
+ exec("d.%s = val"%field)
+
+
diff --git a/source/blender/python/api2_2x/doc/testtext.py b/source/blender/python/api2_2x/doc/testtext.py
new file mode 100644
index 00000000000..3e3fd1a5b01
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/testtext.py
@@ -0,0 +1,29 @@
+# Test Blender.Text
+
+import Blender
+from Blender import Text
+
+txt = Text.New("MyText")
+all_texts = Text.Get()
+
+for i in [1,4,7]:
+ txt.write("%d\n%d\n%d little indians\n" % (i, i+1, i+2))
+
+x = txt.getNLines()
+
+txt.write("%d little indian boys!" % x)
+
+lines = txt.asLines()
+
+txt.clear()
+txt.write("... Yo-ho-ho! And a bottle of rum!")
+
+for s in lines:
+ print s
+
+print all_texts
+print txt.asLines()
+
+Text.unlink(txt)
+
+print all_texts
diff --git a/source/blender/python/api2_2x/doc/testworld.py b/source/blender/python/api2_2x/doc/testworld.py
new file mode 100644
index 00000000000..171855f66c9
--- /dev/null
+++ b/source/blender/python/api2_2x/doc/testworld.py
@@ -0,0 +1,21 @@
+import Blender
+#testfile
+list = Blender.World.Get()
+print "available worlds",list
+
+w = Blender.World.Get("World")
+
+for param in ["Name","Colormodel","Fastcol","Skytype","Mode","Totex","Texact","Mistype","Hor","Zen","Amb","Star","Dof","Mist"]:
+ val = eval("w.get%s()"%param)
+ print param,val
+ val1 = eval("w.set%s(val)"%param)
+ print val1
+
+
+for param in ["name","colormodel","fastcol","skytype","mode","totex","texact","mistype","hor","zen","amb","star","dof","mist"]:
+ exec("val = w.%s"%param)
+ print param,val
+ exec ("w.%s = val"%param)
+
+
+
diff --git a/source/blender/python/api2_2x/euler.c b/source/blender/python/api2_2x/euler.c
new file mode 100644
index 00000000000..53489e0f737
--- /dev/null
+++ b/source/blender/python/api2_2x/euler.c
@@ -0,0 +1,502 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Joseph Gilbert
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "Mathutils.h"
+
+#include "BLI_arithb.h"
+#include "BKE_utildefines.h"
+#include "BLI_blenlib.h"
+#include "gen_utils.h"
+
+
+//-------------------------DOC STRINGS ---------------------------
+char Euler_Zero_doc[] = "() - set all values in the euler to 0";
+char Euler_Unique_doc[] ="() - sets the euler rotation a unique shortest arc rotation - tests for gimbal lock";
+char Euler_ToMatrix_doc[] = "() - returns a rotation matrix representing the euler rotation";
+char Euler_ToQuat_doc[] = "() - returns a quaternion representing the euler rotation";
+char Euler_Rotate_doc[] = "() - rotate a euler by certain amount around an axis of rotation";
+char Euler_copy_doc[] = "() - returns a copy of the euler.";
+//-----------------------METHOD DEFINITIONS ----------------------
+struct PyMethodDef Euler_methods[] = {
+ {"zero", (PyCFunction) Euler_Zero, METH_NOARGS, Euler_Zero_doc},
+ {"unique", (PyCFunction) Euler_Unique, METH_NOARGS, Euler_Unique_doc},
+ {"toMatrix", (PyCFunction) Euler_ToMatrix, METH_NOARGS, Euler_ToMatrix_doc},
+ {"toQuat", (PyCFunction) Euler_ToQuat, METH_NOARGS, Euler_ToQuat_doc},
+ {"rotate", (PyCFunction) Euler_Rotate, METH_VARARGS, Euler_Rotate_doc},
+ {"__copy__", (PyCFunction) Euler_copy, METH_VARARGS, Euler_copy_doc},
+ {"copy", (PyCFunction) Euler_copy, METH_VARARGS, Euler_copy_doc},
+ {NULL, NULL, 0, NULL}
+};
+//-----------------------------METHODS----------------------------
+//----------------------------Euler.toQuat()----------------------
+//return a quaternion representation of the euler
+PyObject *Euler_ToQuat(EulerObject * self)
+{
+ float eul[3], quat[4];
+ int x;
+
+ for(x = 0; x < 3; x++) {
+ eul[x] = self->eul[x] * ((float)Py_PI / 180);
+ }
+ EulToQuat(eul, quat);
+ return newQuaternionObject(quat, Py_NEW);
+}
+//----------------------------Euler.toMatrix()---------------------
+//return a matrix representation of the euler
+PyObject *Euler_ToMatrix(EulerObject * self)
+{
+ float eul[3];
+ float mat[9] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
+ int x;
+
+ for(x = 0; x < 3; x++) {
+ eul[x] = self->eul[x] * ((float)Py_PI / 180);
+ }
+ EulToMat3(eul, (float (*)[3]) mat);
+ return newMatrixObject(mat, 3, 3 , Py_NEW);
+}
+//----------------------------Euler.unique()-----------------------
+//sets the x,y,z values to a unique euler rotation
+PyObject *Euler_Unique(EulerObject * self)
+{
+ double heading, pitch, bank;
+ double pi2 = Py_PI * 2.0f;
+ double piO2 = Py_PI / 2.0f;
+ double Opi2 = 1.0f / pi2;
+
+ //radians
+ heading = self->eul[0] * (float)Py_PI / 180;
+ pitch = self->eul[1] * (float)Py_PI / 180;
+ bank = self->eul[2] * (float)Py_PI / 180;
+
+ //wrap heading in +180 / -180
+ pitch += Py_PI;
+ pitch -= floor(pitch * Opi2) * pi2;
+ pitch -= Py_PI;
+
+
+ if(pitch < -piO2) {
+ pitch = -Py_PI - pitch;
+ heading += Py_PI;
+ bank += Py_PI;
+ } else if(pitch > piO2) {
+ pitch = Py_PI - pitch;
+ heading += Py_PI;
+ bank += Py_PI;
+ }
+ //gimbal lock test
+ if(fabs(pitch) > piO2 - 1e-4) {
+ heading += bank;
+ bank = 0.0f;
+ } else {
+ bank += Py_PI;
+ bank -= (floor(bank * Opi2)) * pi2;
+ bank -= Py_PI;
+ }
+
+ heading += Py_PI;
+ heading -= (floor(heading * Opi2)) * pi2;
+ heading -= Py_PI;
+
+ //back to degrees
+ self->eul[0] = (float)(heading * 180 / (float)Py_PI);
+ self->eul[1] = (float)(pitch * 180 / (float)Py_PI);
+ self->eul[2] = (float)(bank * 180 / (float)Py_PI);
+
+ return EXPP_incr_ret((PyObject*)self);
+}
+//----------------------------Euler.zero()-------------------------
+//sets the euler to 0,0,0
+PyObject *Euler_Zero(EulerObject * self)
+{
+ self->eul[0] = 0.0;
+ self->eul[1] = 0.0;
+ self->eul[2] = 0.0;
+
+ return EXPP_incr_ret((PyObject*)self);
+}
+//----------------------------Euler.rotate()-----------------------
+//rotates a euler a certain amount and returns the result
+//should return a unique euler rotation (i.e. no 720 degree pitches :)
+PyObject *Euler_Rotate(EulerObject * self, PyObject *args)
+{
+ float angle = 0.0f;
+ char *axis;
+ int x;
+
+ if(!PyArg_ParseTuple(args, "fs", &angle, &axis)){
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "euler.rotate():expected angle (float) and axis (x,y,z)");
+ }
+ if(!STREQ3(axis,"x","y","z")){
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "euler.rotate(): expected axis to be 'x', 'y' or 'z'");
+ }
+
+ //covert to radians
+ angle *= ((float)Py_PI / 180);
+ for(x = 0; x < 3; x++) {
+ self->eul[x] *= ((float)Py_PI / 180);
+ }
+ euler_rot(self->eul, angle, *axis);
+ //convert back from radians
+ for(x = 0; x < 3; x++) {
+ self->eul[x] *= (180 / (float)Py_PI);
+ }
+
+ return EXPP_incr_ret((PyObject*)self);
+}
+//----------------------------Euler.rotate()-----------------------
+// return a copy of the euler
+PyObject *Euler_copy(EulerObject * self, PyObject *args)
+{
+ return newEulerObject(self->eul, Py_NEW);
+}
+
+
+//----------------------------dealloc()(internal) ------------------
+//free the py_object
+static void Euler_dealloc(EulerObject * self)
+{
+ //only free py_data
+ if(self->data.py_data){
+ PyMem_Free(self->data.py_data);
+ }
+ PyObject_DEL(self);
+}
+//----------------------------getattr()(internal) ------------------
+//object.attribute access (get)
+static PyObject *Euler_getattr(EulerObject * self, char *name)
+{
+ if(STREQ(name,"x")){
+ return PyFloat_FromDouble(self->eul[0]);
+ }else if(STREQ(name, "y")){
+ return PyFloat_FromDouble(self->eul[1]);
+ }else if(STREQ(name, "z")){
+ return PyFloat_FromDouble(self->eul[2]);
+ }
+ if(STREQ(name, "wrapped")){
+ if(self->wrapped == Py_WRAP)
+ return EXPP_incr_ret((PyObject *)Py_True);
+ else
+ return EXPP_incr_ret((PyObject *)Py_False);
+ }
+ return Py_FindMethod(Euler_methods, (PyObject *) self, name);
+}
+//----------------------------setattr()(internal) ------------------
+//object.attribute access (set)
+static int Euler_setattr(EulerObject * self, char *name, PyObject * e)
+{
+ PyObject *f = NULL;
+
+ f = PyNumber_Float(e);
+ if(f == NULL) { // parsed item not a number
+ return EXPP_ReturnIntError(PyExc_TypeError,
+ "euler.attribute = x: argument not a number\n");
+ }
+
+ if(STREQ(name,"x")){
+ self->eul[0] = (float)PyFloat_AS_DOUBLE(f);
+ }else if(STREQ(name, "y")){
+ self->eul[1] = (float)PyFloat_AS_DOUBLE(f);
+ }else if(STREQ(name, "z")){
+ self->eul[2] = (float)PyFloat_AS_DOUBLE(f);
+ }else{
+ Py_DECREF(f);
+ return EXPP_ReturnIntError(PyExc_AttributeError,
+ "euler.attribute = x: unknown attribute\n");
+ }
+
+ Py_DECREF(f);
+ return 0;
+}
+//----------------------------print object (internal)--------------
+//print the object to screen
+static PyObject *Euler_repr(EulerObject * self)
+{
+ int i;
+ char buffer[48], str[1024];
+
+ BLI_strncpy(str,"[",1024);
+ for(i = 0; i < 3; i++){
+ if(i < (2)){
+ sprintf(buffer, "%.6f, ", self->eul[i]);
+ strcat(str,buffer);
+ }else{
+ sprintf(buffer, "%.6f", self->eul[i]);
+ strcat(str,buffer);
+ }
+ }
+ strcat(str, "](euler)");
+
+ return PyString_FromString(str);
+}
+//------------------------tp_richcmpr
+//returns -1 execption, 0 false, 1 true
+static PyObject* Euler_richcmpr(PyObject *objectA, PyObject *objectB, int comparison_type)
+{
+ EulerObject *eulA = NULL, *eulB = NULL;
+ int result = 0;
+
+ if (!EulerObject_Check(objectA) || !EulerObject_Check(objectB)){
+ if (comparison_type == Py_NE){
+ return EXPP_incr_ret(Py_True);
+ }else{
+ return EXPP_incr_ret(Py_False);
+ }
+ }
+ eulA = (EulerObject*)objectA;
+ eulB = (EulerObject*)objectB;
+
+ switch (comparison_type){
+ case Py_EQ:
+ result = EXPP_VectorsAreEqual(eulA->eul, eulB->eul, 3, 1);
+ break;
+ case Py_NE:
+ result = EXPP_VectorsAreEqual(eulA->eul, eulB->eul, 3, 1);
+ if (result == 0){
+ result = 1;
+ }else{
+ result = 0;
+ }
+ break;
+ default:
+ printf("The result of the comparison could not be evaluated");
+ break;
+ }
+ if (result == 1){
+ return EXPP_incr_ret(Py_True);
+ }else{
+ return EXPP_incr_ret(Py_False);
+ }
+}
+//------------------------tp_doc
+static char EulerObject_doc[] = "This is a wrapper for euler objects.";
+//---------------------SEQUENCE PROTOCOLS------------------------
+//----------------------------len(object)------------------------
+//sequence length
+static int Euler_len(EulerObject * self)
+{
+ return 3;
+}
+//----------------------------object[]---------------------------
+//sequence accessor (get)
+static PyObject *Euler_item(EulerObject * self, int i)
+{
+ if(i < 0 || i >= 3)
+ return EXPP_ReturnPyObjError(PyExc_IndexError,
+ "euler[attribute]: array index out of range\n");
+
+ return PyFloat_FromDouble(self->eul[i]);
+
+}
+//----------------------------object[]-------------------------
+//sequence accessor (set)
+static int Euler_ass_item(EulerObject * self, int i, PyObject * ob)
+{
+ PyObject *f = NULL;
+
+ f = PyNumber_Float(ob);
+ if(f == NULL) { // parsed item not a number
+ return EXPP_ReturnIntError(PyExc_TypeError,
+ "euler[attribute] = x: argument not a number\n");
+ }
+
+ if(i < 0 || i >= 3){
+ Py_DECREF(f);
+ return EXPP_ReturnIntError(PyExc_IndexError,
+ "euler[attribute] = x: array assignment index out of range\n");
+ }
+ self->eul[i] = (float)PyFloat_AS_DOUBLE(f);
+ Py_DECREF(f);
+ return 0;
+}
+//----------------------------object[z:y]------------------------
+//sequence slice (get)
+static PyObject *Euler_slice(EulerObject * self, int begin, int end)
+{
+ PyObject *list = NULL;
+ int count;
+
+ CLAMP(begin, 0, 3);
+ if (end<0) end= 4+end;
+ CLAMP(end, 0, 3);
+ begin = MIN2(begin,end);
+
+ list = PyList_New(end - begin);
+ for(count = begin; count < end; count++) {
+ PyList_SetItem(list, count - begin,
+ PyFloat_FromDouble(self->eul[count]));
+ }
+
+ return list;
+}
+//----------------------------object[z:y]------------------------
+//sequence slice (set)
+static int Euler_ass_slice(EulerObject * self, int begin, int end,
+ PyObject * seq)
+{
+ int i, y, size = 0;
+ float eul[3];
+ PyObject *e, *f;
+
+ CLAMP(begin, 0, 3);
+ if (end<0) end= 4+end;
+ CLAMP(end, 0, 3);
+ begin = MIN2(begin,end);
+
+ size = PySequence_Length(seq);
+ if(size != (end - begin)){
+ return EXPP_ReturnIntError(PyExc_TypeError,
+ "euler[begin:end] = []: size mismatch in slice assignment\n");
+ }
+
+ for (i = 0; i < size; i++) {
+ e = PySequence_GetItem(seq, i);
+ if (e == NULL) { // Failed to read sequence
+ return EXPP_ReturnIntError(PyExc_RuntimeError,
+ "euler[begin:end] = []: unable to read sequence\n");
+ }
+
+ f = PyNumber_Float(e);
+ if(f == NULL) { // parsed item not a number
+ Py_DECREF(e);
+ return EXPP_ReturnIntError(PyExc_TypeError,
+ "euler[begin:end] = []: sequence argument not a number\n");
+ }
+
+ eul[i] = (float)PyFloat_AS_DOUBLE(f);
+ EXPP_decr2(f,e);
+ }
+ //parsed well - now set in vector
+ for(y = 0; y < 3; y++){
+ self->eul[begin + y] = eul[y];
+ }
+ return 0;
+}
+//-----------------PROTCOL DECLARATIONS--------------------------
+static PySequenceMethods Euler_SeqMethods = {
+ (inquiry) Euler_len, /* sq_length */
+ (binaryfunc) 0, /* sq_concat */
+ (intargfunc) 0, /* sq_repeat */
+ (intargfunc) Euler_item, /* sq_item */
+ (intintargfunc) Euler_slice, /* sq_slice */
+ (intobjargproc) Euler_ass_item, /* sq_ass_item */
+ (intintobjargproc) Euler_ass_slice, /* sq_ass_slice */
+};
+//------------------PY_OBECT DEFINITION--------------------------
+PyTypeObject euler_Type = {
+ PyObject_HEAD_INIT(NULL) //tp_head
+ 0, //tp_internal
+ "euler", //tp_name
+ sizeof(EulerObject), //tp_basicsize
+ 0, //tp_itemsize
+ (destructor)Euler_dealloc, //tp_dealloc
+ 0, //tp_print
+ (getattrfunc)Euler_getattr, //tp_getattr
+ (setattrfunc) Euler_setattr, //tp_setattr
+ 0, //tp_compare
+ (reprfunc) Euler_repr, //tp_repr
+ 0, //tp_as_number
+ &Euler_SeqMethods, //tp_as_sequence
+ 0, //tp_as_mapping
+ 0, //tp_hash
+ 0, //tp_call
+ 0, //tp_str
+ 0, //tp_getattro
+ 0, //tp_setattro
+ 0, //tp_as_buffer
+ Py_TPFLAGS_DEFAULT, //tp_flags
+ EulerObject_doc, //tp_doc
+ 0, //tp_traverse
+ 0, //tp_clear
+ (richcmpfunc)Euler_richcmpr, //tp_richcompare
+ 0, //tp_weaklistoffset
+ 0, //tp_iter
+ 0, //tp_iternext
+ 0, //tp_methods
+ 0, //tp_members
+ 0, //tp_getset
+ 0, //tp_base
+ 0, //tp_dict
+ 0, //tp_descr_get
+ 0, //tp_descr_set
+ 0, //tp_dictoffset
+ 0, //tp_init
+ 0, //tp_alloc
+ 0, //tp_new
+ 0, //tp_free
+ 0, //tp_is_gc
+ 0, //tp_bases
+ 0, //tp_mro
+ 0, //tp_cache
+ 0, //tp_subclasses
+ 0, //tp_weaklist
+ 0 //tp_del
+};
+//------------------------newEulerObject (internal)-------------
+//creates a new euler object
+/*pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER
+ (i.e. it was allocated elsewhere by MEM_mallocN())
+ pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON
+ (i.e. it must be created here with PyMEM_malloc())*/
+PyObject *newEulerObject(float *eul, int type)
+{
+ EulerObject *self;
+ int x;
+
+ self = PyObject_NEW(EulerObject, &euler_Type);
+ self->data.blend_data = NULL;
+ self->data.py_data = NULL;
+
+ if(type == Py_WRAP){
+ self->data.blend_data = eul;
+ self->eul = self->data.blend_data;
+ self->wrapped = Py_WRAP;
+ }else if (type == Py_NEW){
+ self->data.py_data = PyMem_Malloc(3 * sizeof(float));
+ self->eul = self->data.py_data;
+ if(!eul) { //new empty
+ for(x = 0; x < 3; x++) {
+ self->eul[x] = 0.0f;
+ }
+ }else{
+ for(x = 0; x < 3; x++){
+ self->eul[x] = eul[x];
+ }
+ }
+ self->wrapped = Py_NEW;
+ }else{ //bad type
+ return NULL;
+ }
+ return (PyObject *) self;
+}
+
diff --git a/source/blender/python/api2_2x/euler.h b/source/blender/python/api2_2x/euler.h
new file mode 100644
index 00000000000..62e5855891b
--- /dev/null
+++ b/source/blender/python/api2_2x/euler.h
@@ -0,0 +1,67 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Joseph Gilbert
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ *
+ */
+
+#ifndef EXPP_euler_h
+#define EXPP_euler_h
+
+#include <Python.h>
+
+extern PyTypeObject euler_Type;
+
+#define EulerObject_Check(v) ((v)->ob_type == &euler_Type)
+
+typedef struct {
+ PyObject_VAR_HEAD
+ struct{
+ float *py_data; //python managed
+ float *blend_data; //blender managed
+ }data;
+ float *eul; //1D array of data (alias)
+ int wrapped; //is wrapped data?
+} EulerObject;
+
+/*struct data contains a pointer to the actual data that the
+object uses. It can use either PyMem allocated data (which will
+be stored in py_data) or be a wrapper for data allocated through
+blender (stored in blend_data). This is an either/or struct not both*/
+
+//prototypes
+PyObject *Euler_Zero( EulerObject * self );
+PyObject *Euler_Unique( EulerObject * self );
+PyObject *Euler_ToMatrix( EulerObject * self );
+PyObject *Euler_ToQuat( EulerObject * self );
+PyObject *Euler_Rotate( EulerObject * self, PyObject *args );
+PyObject *Euler_copy( EulerObject * self, PyObject *args );
+PyObject *newEulerObject( float *eul, int type );
+
+#endif /* EXPP_euler_h */
diff --git a/source/blender/python/api2_2x/gen_library.c b/source/blender/python/api2_2x/gen_library.c
new file mode 100644
index 00000000000..8673fefdbb5
--- /dev/null
+++ b/source/blender/python/api2_2x/gen_library.c
@@ -0,0 +1,332 @@
+#include "gen_library.h"
+#include "gen_utils.h" /*This must come first*/
+
+/* use for GenericLib_getProperties */
+#include "BKE_idprop.h"
+#include "IDProp.h"
+
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_library.h"
+#include "BKE_curve.h"
+
+/* GenericLib */
+#include "World.h"
+#include "Font.h"
+#include "Metaball.h"
+#include "Curve.h"
+#include "Camera.h"
+#include "NLA.h"
+#include "Lattice.h"
+#include "Armature.h"
+#include "Lamp.h"
+#include "Text.h"
+#include "Text3d.h"
+#include "Sound.h"
+#include "Scene.h"
+#include "Mesh.h"
+#include "Group.h"
+#include "Object.h"
+#include "Texture.h"
+#include "Ipo.h"
+#include "DNA_object_types.h"
+#include "DNA_ipo_types.h"
+
+
+/* Generic get/set attrs */
+PyObject *GenericLib_getName( void *self )
+{
+ ID *id = ((BPy_GenericLib *)self)->id;
+ if (!id) return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, "data has been removed" ) );
+ return PyString_FromString( id->name + 2 );
+}
+
+int GenericLib_setName( void *self, PyObject *value )
+{
+ ID *id = ((BPy_GenericLib *)self)->id;
+ char *name = NULL;
+ if (!id) return ( EXPP_ReturnIntError( PyExc_RuntimeError, "data has been removed" ) );
+
+ name = PyString_AsString ( value );
+ if( !name )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected string argument" );
+
+ rename_id( id, name );
+
+ return 0;
+}
+
+PyObject *GenericLib_getFakeUser( void *self )
+{
+ ID *id = ((BPy_GenericLib *)self)->id;
+ if (!id) return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, "data has been removed" ) );
+ if (id->flag & LIB_FAKEUSER)
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+}
+
+int GenericLib_setFakeUser( void *self, PyObject *value )
+{
+ int param;
+ ID *id = ((BPy_GenericLib *)self)->id;
+ if (!id) return ( EXPP_ReturnIntError( PyExc_RuntimeError, "data has been removed" ) );
+
+ param = PyObject_IsTrue( value );
+ if( param == -1 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected True/False or 0/1" );
+
+ if (param) {
+ if (!(id->flag & LIB_FAKEUSER)) {
+ id->flag |= LIB_FAKEUSER;
+ id_us_plus(id);
+ }
+ } else {
+ if (id->flag & LIB_FAKEUSER) {
+ id->flag &= ~LIB_FAKEUSER;
+ id->us--;
+ }
+ }
+ return 0;
+}
+
+PyObject *GenericLib_getTag( void *self )
+{
+ ID *id = ((BPy_GenericLib *)self)->id;
+ if (!id) return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, "data has been removed" ) );
+ if (id->flag & LIB_DOIT)
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+}
+
+int GenericLib_setTag( void *self, PyObject *value )
+{
+ int param;
+ ID *id = ((BPy_GenericLib *)self)->id;
+ if (!id) return ( EXPP_ReturnIntError( PyExc_RuntimeError, "data has been removed" ) );
+
+ param = PyObject_IsTrue( value );
+ if( param == -1 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected int argument in range [0,1]" );
+
+ if (param)
+ id->flag |= LIB_DOIT;
+ else
+ id->flag &= ~LIB_DOIT;
+ return 0;
+}
+
+
+/* read only */
+PyObject *GenericLib_getLib( void *self )
+{
+ ID *id = ((BPy_GenericLib *)self)->id;
+ if (!id) return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, "data has been removed" ) );
+
+ if (id->lib)
+ return PyString_FromString(id->lib->name);
+ else
+ return EXPP_incr_ret( Py_None );
+}
+
+PyObject *GenericLib_getUsers( void *self )
+{
+ ID *id = ((BPy_GenericLib *)self)->id;
+ if (!id) return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, "data has been removed" ) );
+ return PyInt_FromLong(id->us);
+}
+
+PyObject *GenericLib_getProperties( void *self )
+{
+ ID *id = ((BPy_GenericLib *)self)->id;
+ if (!id) return ( EXPP_ReturnPyObjError( PyExc_RuntimeError, "data has been removed" ) );
+ return BPy_Wrap_IDProperty( id, IDP_GetProperties(id, 1), NULL );
+}
+
+/* use for any.setName("name")*/
+PyObject * GenericLib_setName_with_method( void *self, PyObject *args )
+{
+ return EXPP_setterWrapper( (void *)self, args, (setter)GenericLib_setName );
+}
+
+
+/*
+ * returns the Blender lib type code from a PyObject
+ * -1 for no match, only give this function libdata
+ *
+ * At the moment this is only used by GenericLib_assignData
+ * so not all types are needed.
+ */
+short GenericLib_getType(PyObject * pydata)
+{
+ //~ if (BPy_Scene_Check(pydata)) return ID_SCE;
+ if (BPy_Object_Check(pydata)) return ID_OB;
+ if (BPy_Mesh_Check(pydata)) return ID_ME;
+ //~ if (BPy_Curve_Check(pydata)) return ID_CU;
+ //~ if (BPy_Metaball_Check(pydata)) return ID_MB;
+ //~ if (BPy_Material_Check(pydata)) return ID_MA;
+ if (BPy_Texture_Check(pydata)) return ID_TE;
+ //~ if (BPy_Image_Check(pydata)) return ID_IM;
+ //~ //if (BPy_Lattice_Check(pydata)) return ID_LT;
+ //~ if (BPy_Lamp_Check(pydata)) return ID_LA;
+ //~ if (BPy_Camera_Check(pydata)) return ID_CA;
+ if (BPy_Ipo_Check(pydata)) return ID_IP;
+ if (BPy_World_Check(pydata)) return ID_WO;
+ //~ //if (BPy_Font_Check(pydata)) return ID_VF;
+ //~ if (BPy_Text_Check(pydata)) return ID_TXT;
+ //~ if (BPy_Sound_Check(pydata)) return ID_SO;
+ if (BPy_Group_Check(pydata)) return ID_GR;
+ //~ if (BPy_Armature_Check(pydata)) return ID_AR;
+ if (BPy_Action_Check(pydata)) return ID_AC;
+
+ return -1;
+}
+
+
+/*
+ * This function is used to assign a PyObject representing
+ * blender libdata to a pointer.
+ *
+ * Python examples of this are...
+ * ob.DupGroup = dupliGroup
+ * mesh.texMesh = texme
+ * ob.ipo = None
+ *
+ * This function deals with type checking, data usercounts,
+ * and raising errors.
+ *
+ * value - python value
+ * data - Blender pointer to assign value to
+ * ndata - Use this if there is a value data cannot be.
+ * for instance, a curve's curve modifier cant point to its self.
+ * refcount - non zero values will modify blenders user count.
+ * type - ID type.
+ * subtype - used only for objects and IPO's to stop the wrong types of obs/ipos
+ * being assigned.
+ *
+ */
+int GenericLib_assignData(PyObject *value, void **data, void **ndata, short refcount, short type, short subtype)
+{
+ ID *id= NULL;
+
+ if (*data) {
+ id = ((ID*)*data);
+
+ if (ndata && *data == *ndata) {
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "Cannot set this data to its self" );
+ }
+ }
+
+ if (value == Py_None) {
+ *data = NULL;
+ if (refcount && id) id->us--;
+ } else if (GenericLib_getType(value) == type) {
+
+ /* object subtypes */
+ if (subtype != 0) {
+ if (type == ID_OB) {
+ Object *ob= (Object *)(((BPy_GenericLib *)value)->id);
+ if (ob->type != subtype)
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "Object type not supported" );
+ }
+
+ if (type == ID_IP) {
+ Ipo *ipo = (Ipo *)(((BPy_GenericLib *)value)->id);
+ if (ipo->blocktype != subtype)
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "Ipo type does is not compatible" );
+ }
+
+
+ }
+ if (refcount && id) id->us--;
+ id = ((BPy_GenericLib *)value)->id;
+ id->us++;
+ *data = id;
+ } else {
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "Could not assign Python Type - None or Library Object" );
+ }
+ return 0;
+}
+
+
+/*
+ * returns the ID of the object with given name
+ * from a given list.
+ */
+ID *GetIdFromList( ListBase * list, char *name )
+{
+ ID *id = list->first;
+
+ while( id ) {
+ if( strcmp( name, id->name + 2 ) == 0 )
+ break;
+ id = id->next;
+ }
+
+ return id;
+}
+
+
+PyObject *GetPyObjectFromID( ID * id )
+{
+ switch ( MAKE_ID2( id->name[0], id->name[1] ) ) {
+ case ID_SCE:
+ return Scene_CreatePyObject( ( Scene *) id );
+ case ID_OB:
+ return Object_CreatePyObject( (Object *) id );
+ case ID_ME:
+ return Mesh_CreatePyObject( (Mesh *)id, NULL );
+ case ID_CU:
+ switch (curve_type((Curve *)id)) {
+ case OB_FONT:
+ return Text3d_CreatePyObject( (Text3d *)id );
+ default:
+ return Curve_CreatePyObject( (Curve *)id );
+ }
+ case ID_MB:
+ return Metaball_CreatePyObject((MetaBall *)id);
+ case ID_MA:
+ return Material_CreatePyObject((Material *)id);
+ case ID_TE:
+ return Texture_CreatePyObject((Tex *)id);
+ case ID_IM:
+ return Image_CreatePyObject((Image *)id);
+ case ID_LT:
+ return Lattice_CreatePyObject((Lattice *)id);
+ case ID_LA:
+ return Lamp_CreatePyObject((Lamp *)id);
+ case ID_CA:
+ return Camera_CreatePyObject((Camera *)id);
+ case ID_IP:
+ return Ipo_CreatePyObject((Ipo *)id);
+ case ID_WO:
+ return World_CreatePyObject((World *)id);
+ case ID_VF:
+ return Font_CreatePyObject((VFont *)id);
+ case ID_TXT:
+ return Text_CreatePyObject((Text *)id);
+ case ID_SO:
+ return Sound_CreatePyObject((bSound *)id);
+ case ID_GR:
+ return Group_CreatePyObject((Group *)id);
+ case ID_AR:
+ return Armature_CreatePyObject((bArmature *)id);
+ case ID_AC:
+ return Action_CreatePyObject((bAction *)id);
+ }
+ Py_RETURN_NONE;
+}
+
+long GenericLib_hash(BPy_GenericLib * pydata)
+{
+ return (long)pydata->id;
+}
+
diff --git a/source/blender/python/api2_2x/gen_library.h b/source/blender/python/api2_2x/gen_library.h
new file mode 100644
index 00000000000..9fb922619c2
--- /dev/null
+++ b/source/blender/python/api2_2x/gen_library.h
@@ -0,0 +1,94 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Michel Selten, Willian P. Germano, Alex Mole, Joseph Gilbert
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_gen_library_h
+#define EXPP_gen_library_h
+
+#include <Python.h>
+
+#include "DNA_ID.h"
+#include "DNA_listBase.h"
+
+/* ID functions for all libdata */
+#define GENERIC_LIB_GETSETATTR \
+ {"name",\
+ (getter)GenericLib_getName, (setter)GenericLib_setName,\
+ "name",\
+ NULL},\
+ {"lib",\
+ (getter)GenericLib_getLib, (setter)NULL,\
+ "external library path",\
+ NULL},\
+ {"users",\
+ (getter)GenericLib_getUsers, (setter)NULL,\
+ "user count",\
+ NULL},\
+ {"fakeUser",\
+ (getter)GenericLib_getFakeUser, (setter)GenericLib_setFakeUser,\
+ "fake user state",\
+ NULL},\
+ {"properties",\
+ (getter)GenericLib_getProperties, (setter)NULL,\
+ "properties",\
+ NULL},\
+ {"tag",\
+ (getter)GenericLib_getTag, (setter)GenericLib_setTag,\
+ "temproary tag",\
+ NULL}
+
+/* Dummy struct for getting the ID from a libdata BPyObject */
+typedef struct {
+ PyObject_HEAD /* required python macro */
+ ID *id;
+} BPy_GenericLib;
+
+int GenericLib_setName( void *self, PyObject *value );
+PyObject *GenericLib_getName( void *self );
+PyObject *GenericLib_getFakeUser( void *self );
+int GenericLib_setFakeUser( void *self, PyObject *value );
+PyObject *GenericLib_getTag( void *self );
+int GenericLib_setTag( void *self, PyObject *value );
+PyObject *GenericLib_getLib( void *self );
+PyObject *GenericLib_getUsers( void *self );
+PyObject *GenericLib_getProperties( void *self );
+
+/* use this for oldstyle somedata.getName("name") */
+PyObject * GenericLib_setName_with_method( void *self, PyObject *value );
+
+int GenericLib_assignData(PyObject *value, void **data, void **ndata, short refcount, short type, short subtype);
+short GenericLib_getType(PyObject * pydata);
+
+/* Other ID functions */
+ID *GetIdFromList( ListBase * list, char *name );
+PyObject *GetPyObjectFromID( ID * id );
+long GenericLib_hash(BPy_GenericLib * pydata);
+#endif /* EXPP_gen_library_h */
diff --git a/source/blender/python/api2_2x/gen_utils.c b/source/blender/python/api2_2x/gen_utils.c
new file mode 100644
index 00000000000..8a98fd279b7
--- /dev/null
+++ b/source/blender/python/api2_2x/gen_utils.c
@@ -0,0 +1,948 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Michel Selten, Willian P. Germano, Alex Mole, Ken Hughes,
+ * Campbell Barton
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#include "gen_utils.h" /*This must come first*/
+
+#include "DNA_text_types.h"
+#include "MEM_guardedalloc.h"
+#include "BLI_blenlib.h"
+#include "BIF_space.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_library.h"
+
+#include "Mathutils.h"
+
+#include "constant.h"
+
+/*---------------------- EXPP_FloatsAreEqual -------------------------
+ Floating point comparisons
+ floatStep = number of representable floats allowable in between
+ float A and float B to be considered equal. */
+int EXPP_FloatsAreEqual(float A, float B, int floatSteps)
+{
+ int a, b, delta;
+ assert(floatSteps > 0 && floatSteps < (4 * 1024 * 1024));
+ a = *(int*)&A;
+ if (a < 0)
+ a = 0x80000000 - a;
+ b = *(int*)&B;
+ if (b < 0)
+ b = 0x80000000 - b;
+ delta = abs(a - b);
+ if (delta <= floatSteps)
+ return 1;
+ return 0;
+}
+/*---------------------- EXPP_VectorsAreEqual -------------------------
+ Builds on EXPP_FloatsAreEqual to test vectors */
+int EXPP_VectorsAreEqual(float *vecA, float *vecB, int size, int floatSteps){
+
+ int x;
+ for (x=0; x< size; x++){
+ if (EXPP_FloatsAreEqual(vecA[x], vecB[x], floatSteps) == 0)
+ return 0;
+ }
+ return 1;
+}
+/*---------------------- EXPP_GetModuleConstant -------------------------
+ Helper function for returning a module constant */
+PyObject *EXPP_GetModuleConstant(char *module, char *constant)
+{
+ PyObject *py_module = NULL, *py_dict = NULL, *py_constant = NULL;
+
+ /*Careful to pass the correct Package.Module string here or
+ * else you add a empty module somewhere*/
+ py_module = PyImport_AddModule(module);
+ if(!py_module){ /*null = error returning module*/
+ return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "error encountered with returning module constant..." ) );
+ }
+ py_dict = PyModule_GetDict(py_module); /*never fails*/
+
+ py_constant = PyDict_GetItemString(py_dict, constant);
+ if(!py_constant){ /*null = key not found*/
+ return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "error encountered with returning module constant..." ) );
+ }
+
+ return EXPP_incr_ret(py_constant);
+}
+
+/*****************************************************************************/
+/* Description: This function clamps an int to the given interval */
+/* [min, max]. */
+/*****************************************************************************/
+int EXPP_ClampInt( int value, int min, int max )
+{
+ if( value < min )
+ return min;
+ else if( value > max )
+ return max;
+ return value;
+}
+
+/*****************************************************************************/
+/* Description: This function clamps a float to the given interval */
+/* [min, max]. */
+/*****************************************************************************/
+float EXPP_ClampFloat( float value, float min, float max )
+{
+ if( value < min )
+ return min;
+ else if( value > max )
+ return max;
+ return value;
+}
+
+/*****************************************************************************/
+/* Description: This function returns true if both given strings are equal, */
+/* otherwise it returns false. */
+/*****************************************************************************/
+int StringEqual( const char *string1, const char *string2 )
+{
+ return ( strcmp( string1, string2 ) == 0 );
+}
+
+
+/*****************************************************************************/
+/* Description: These functions set an internal string with the given type */
+/* and error_msg arguments. */
+/*****************************************************************************/
+
+PyObject *EXPP_ReturnPyObjError( PyObject * type, char *error_msg )
+{ /* same as above, just to change its name smoothly */
+ PyErr_SetString( type, error_msg );
+ return NULL;
+}
+
+int EXPP_ReturnIntError( PyObject * type, char *error_msg )
+{
+ PyErr_SetString( type, error_msg );
+ return -1;
+}
+
+int EXPP_intError(PyObject *type, const char *format, ...)
+{
+ PyObject *error;
+ va_list vlist;
+
+ va_start(vlist, format);
+ error = PyString_FromFormatV(format, vlist);
+ va_end(vlist);
+
+ PyErr_SetObject(type, error);
+ Py_DECREF(error);
+ return -1;
+}
+/*Like EXPP_ReturnPyObjError but takes a printf format string and multiple arguments*/
+PyObject *EXPP_objError(PyObject *type, const char *format, ...)
+{
+ PyObject *error;
+ va_list vlist;
+
+ va_start(vlist, format);
+ error = PyString_FromFormatV(format, vlist);
+ va_end(vlist);
+
+ PyErr_SetObject(type, error);
+ Py_DECREF(error);
+ return NULL;
+}
+
+/*****************************************************************************/
+/* Description: This function increments the reference count of the given */
+/* Python object (usually Py_None) and returns it. */
+/*****************************************************************************/
+
+PyObject *EXPP_incr_ret( PyObject * object )
+{
+ Py_INCREF( object );
+ return ( object );
+}
+
+/* return Py_False - to avoid warnings, we use the fact that
+ * 0 == False in Python: */
+PyObject *EXPP_incr_ret_False()
+{
+ return Py_BuildValue("i", 0);
+}
+
+/* return Py_True - to avoid warnings, we use the fact that
+ * 1 == True in Python: */
+PyObject *EXPP_incr_ret_True()
+{
+ return Py_BuildValue("i", 1);
+}
+
+void EXPP_incr2( PyObject * ob1, PyObject * ob2 )
+{
+ Py_INCREF( ob1 );
+ Py_INCREF( ob2 );
+}
+
+void EXPP_incr3( PyObject * ob1, PyObject * ob2, PyObject * ob3 )
+{
+ Py_INCREF( ob1 );
+ Py_INCREF( ob2 );
+ Py_INCREF( ob3 );
+}
+
+void EXPP_decr2( PyObject * ob1, PyObject * ob2 )
+{
+ Py_DECREF( ob1 );
+ Py_DECREF( ob2 );
+}
+
+void EXPP_decr3( PyObject * ob1, PyObject * ob2, PyObject * ob3 )
+{
+ Py_DECREF( ob1 );
+ Py_DECREF( ob2 );
+ Py_DECREF( ob3 );
+}
+/*****************************************************************************/
+/* Description: This function maps the event identifier to a string. */
+/*****************************************************************************/
+char *event_to_name( short event )
+{
+ switch ( event ) {
+ case SCRIPT_FRAMECHANGED:
+ return "FrameChanged";
+ case SCRIPT_ONLOAD:
+ return "OnLoad";
+ case SCRIPT_ONSAVE:
+ return "OnSave";
+ case SCRIPT_REDRAW:
+ return "Redraw";
+ case SCRIPT_RENDER:
+ return "Render";
+ case SCRIPT_POSTRENDER:
+ return "PostRender";
+ default:
+ return "Unknown";
+ }
+}
+
+/*****************************************************************************/
+/* Description: Checks whether all objects in a PySequence are of a same */
+/* given type. Returns 0 if not, 1 on success. */
+/*****************************************************************************/
+int EXPP_check_sequence_consistency( PyObject * seq, PyTypeObject * against )
+{
+ PyObject *ob;
+ int len = PySequence_Length( seq );
+ int i, result = 1;
+
+ for( i = 0; i < len; i++ ) {
+ ob = PySequence_GetItem( seq, i );
+ if( ob == Py_None )
+ result = 2;
+ else if( ob->ob_type != against ) {
+ Py_DECREF( ob );
+ return 0;
+ }
+ Py_DECREF( ob );
+ }
+ return result; /* 1 if all of 'against' type, 2 if there are (also) Nones */
+}
+
+PyObject *EXPP_tuple_repr( PyObject * self, int size )
+{
+ PyObject *repr, *item;
+ int i;
+
+/*@ note: a value must be built because the list is decrefed!
+ * otherwise we have nirvana pointers inside python.. */
+
+ repr = PyString_FromString( "" );
+ if( !repr )
+ return 0;
+
+ item = PySequence_GetItem( self, 0 );
+ PyString_ConcatAndDel( &repr, PyObject_Repr( item ) );
+ Py_DECREF( item );
+
+ for( i = 1; i < size; i++ ) {
+ item = PySequence_GetItem( self, i );
+ PyString_ConcatAndDel( &repr, PyObject_Repr( item ) );
+ Py_DECREF( item );
+ }
+
+ return repr;
+}
+
+/****************************************************************************/
+/* Description: searches through a map for a pair with a given name. If the */
+/* pair is present, its ival is stored in *ival and nonzero is */
+/* returned. If the pair is absent, zero is returned. */
+/****************************************************************************/
+int EXPP_map_getIntVal( const EXPP_map_pair * map, const char *sval,
+ int *ival )
+{
+ while( map->sval ) {
+ if( StringEqual( sval, map->sval ) ) {
+ *ival = map->ival;
+ return 1;
+ }
+ ++map;
+ }
+ return 0;
+}
+
+/* same as above, but string case is ignored */
+int EXPP_map_case_getIntVal( const EXPP_map_pair * map, const char *sval,
+ int *ival )
+{
+ while( map->sval ) {
+ if( !BLI_strcasecmp( sval, map->sval ) ) {
+ *ival = map->ival;
+ return 1;
+ }
+ ++map;
+ }
+ return 0;
+}
+
+/****************************************************************************/
+/* Description: searches through a map for a pair with a given name. If the */
+/* pair is present, its ival is stored in *ival and nonzero is */
+/* returned. If the pair is absent, zero is returned. */
+/* note: this function is identical to EXPP_map_getIntVal except that the */
+/* output is stored in a short value. */
+/****************************************************************************/
+int EXPP_map_getShortVal( const EXPP_map_pair * map,
+ const char *sval, short *ival )
+{
+ while( map->sval ) {
+ if( StringEqual( sval, map->sval ) ) {
+ *ival = (short)map->ival;
+ return 1;
+ }
+ ++map;
+ }
+ return 0;
+}
+
+/****************************************************************************/
+/* Description: searches through a map for a pair with a given ival. If the */
+/* pair is present, a pointer to its name is stored in *sval */
+/* and nonzero is returned. If the pair is absent, zero is */
+/* returned. */
+/****************************************************************************/
+int EXPP_map_getStrVal( const EXPP_map_pair * map, int ival,
+ const char **sval )
+{
+ while( map->sval ) {
+ if( ival == map->ival ) {
+ *sval = map->sval;
+ return 1;
+ }
+ ++map;
+ }
+ return 0;
+}
+
+/* Redraw wrappers */
+
+/* this queues redraws if we're not in background mode: */
+void EXPP_allqueue(unsigned short event, short val)
+{
+ if (!G.background) allqueue(event, val);
+}
+
+/************************************************************************/
+/* Scriptlink-related functions, used by scene, object, etc. bpyobjects */
+/************************************************************************/
+PyObject *EXPP_getScriptLinks( ScriptLink * slink, PyObject * value,
+ int is_scene )
+{
+ PyObject *list = NULL, *tmpstr;
+ char *eventname = PyString_AsString(value);
+ int i, event = 0;
+
+
+ if( !eventname )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected event name (string) as argument" );
+
+ list = PyList_New( 0 );
+ if( !list )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create PyList!" );
+
+ /* actually !scriptlink shouldn't happen ... */
+ if( !slink || !slink->totscript )
+ return list;
+
+ if( !strcmp( eventname, "FrameChanged" ) )
+ event = SCRIPT_FRAMECHANGED;
+ else if( !strcmp( eventname, "Redraw" ) )
+ event = SCRIPT_REDRAW;
+ else if( !strcmp( eventname, "Render" ) )
+ event = SCRIPT_RENDER;
+ else if( is_scene && !strcmp( eventname, "OnLoad" ) )
+ event = SCRIPT_ONLOAD;
+ else if( is_scene && !strcmp( eventname, "OnSave" ) )
+ event = SCRIPT_ONSAVE;
+ else {
+ Py_DECREF(list);
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "invalid event name" );
+ }
+
+ for( i = 0; i < slink->totscript; i++ ) {
+ if( ( slink->flag[i] == event ) && slink->scripts[i] ) {
+ tmpstr =PyString_FromString( slink->scripts[i]->name + 2 );
+ PyList_Append( list, tmpstr );
+ Py_DECREF(tmpstr);
+ }
+ }
+
+ return list;
+}
+
+PyObject *EXPP_clearScriptLinks( ScriptLink * slink, PyObject * args )
+{
+ int i, j, totLinks, deleted = 0;
+ PyObject *seq = NULL;
+ ID **stmp = NULL;
+ short *ftmp = NULL;
+
+ /* check for an optional list of strings */
+ if( !PyArg_ParseTuple( args, "|O", &seq ) )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_TypeError,
+ "expected no arguments or a list of strings" ) );
+
+
+ /* if there was a parameter, handle it */
+ if ( seq != NULL ) {
+ /* check that parameter IS list of strings */
+ if ( !PyList_Check ( seq ) )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_TypeError,
+ "expected a list of strings" ) );
+
+ totLinks = PyList_Size ( seq );
+ for ( i = 0 ; i < totLinks ; ++i ) {
+ if ( !PyString_Check ( PySequence_GetItem( seq, i ) ) )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_TypeError,
+ "expected list to contain strings" ) );
+ }
+
+ /*
+ parameters OK: now look for each script, and delete
+ its link as we find it (this handles multiple links)
+ */
+ for ( i = 0 ; i < totLinks ; ++i )
+ {
+ char *str;
+ str = PyString_AsString ( PySequence_GetItem( seq, i ) );
+ for ( j = 0 ; j < slink->totscript ; ++j ) {
+ if ( slink->scripts[j] && !strcmp( slink->scripts[j]->name+2, str ) )
+ slink->scripts[j] = NULL;
+ if( !slink->scripts[j] )
+ ++deleted;
+ }
+ }
+ }
+ /* if no parameter, then delete all scripts */
+ else {
+ deleted = slink->totscript;
+ }
+
+ /*
+ if not all scripts deleted, create new lists and copy remaining
+ links to them
+ */
+
+ if ( slink->totscript > deleted ) {
+ slink->totscript = slink->totscript - (short)deleted;
+
+ stmp = slink->scripts;
+ slink->scripts =
+ MEM_mallocN( sizeof( ID * ) * ( slink->totscript ),
+ "bpySlinkL" );
+
+ ftmp = slink->flag;
+ slink->flag =
+ MEM_mallocN( sizeof( short * ) * ( slink->totscript ),
+ "bpySlinkF" );
+
+ for ( i = 0, j = 0 ; i < slink->totscript ; ++j ) {
+ if ( stmp[j] != NULL ) {
+ memcpy( slink->scripts+i, stmp+j, sizeof( ID * ) );
+ memcpy( slink->flag+i, ftmp+j, sizeof( short ) );
+ ++i;
+ }
+ }
+ MEM_freeN( stmp );
+ MEM_freeN( ftmp );
+
+ /*EXPP_allqueue (REDRAWBUTSSCRIPT, 0 );*/
+ slink->actscript = 1;
+ } else {
+
+ /* all scripts deleted, so delete entire list and free memory */
+
+ if( slink->scripts )
+ MEM_freeN( slink->scripts );
+ if( slink->flag )
+ MEM_freeN( slink->flag );
+
+ slink->scripts = NULL;
+ slink->flag = NULL;
+ slink->totscript = slink->actscript = 0;
+ }
+
+ return EXPP_incr_ret( Py_None );
+}
+
+
+PyObject *EXPP_addScriptLink(ScriptLink *slink, PyObject *args, int is_scene)
+{
+ int event = 0, found_txt = 0;
+ void *stmp = NULL, *ftmp = NULL;
+ Text *bltxt = G.main->text.first;
+ char *textname = NULL;
+ char *eventname = NULL;
+
+ /* !scriptlink shouldn't happen ... */
+ if( !slink ) {
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "internal error: no scriptlink!" );
+ }
+
+ if( !PyArg_ParseTuple( args, "ss", &textname, &eventname ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected two strings as arguments" );
+
+ while( bltxt ) {
+ if( !strcmp( bltxt->id.name + 2, textname ) ) {
+ found_txt = 1;
+ break;
+ }
+ bltxt = bltxt->id.next;
+ }
+
+ if( !found_txt )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "no such Blender Text" );
+
+ if( !strcmp( eventname, "FrameChanged" ) )
+ event = SCRIPT_FRAMECHANGED;
+ else if( !strcmp( eventname, "Redraw" ) )
+ event = SCRIPT_REDRAW;
+ else if( !strcmp( eventname, "Render" ) )
+ event = SCRIPT_RENDER;
+ else if( is_scene && !strcmp( eventname, "OnLoad" ) )
+ event = SCRIPT_ONLOAD;
+ else if( is_scene && !strcmp( eventname, "OnSave" ) )
+ event = SCRIPT_ONSAVE;
+ else
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "invalid event name" );
+
+ stmp = slink->scripts;
+ slink->scripts =
+ MEM_mallocN( sizeof( ID * ) * ( slink->totscript + 1 ),
+ "bpySlinkL" );
+
+ ftmp = slink->flag;
+ slink->flag =
+ MEM_mallocN( sizeof( short * ) * ( slink->totscript + 1 ),
+ "bpySlinkF" );
+
+ if( slink->totscript ) {
+ memcpy( slink->scripts, stmp,
+ sizeof( ID * ) * ( slink->totscript ) );
+ MEM_freeN( stmp );
+
+ memcpy( slink->flag, ftmp,
+ sizeof( short ) * ( slink->totscript ) );
+ MEM_freeN( ftmp );
+ }
+
+ slink->scripts[slink->totscript] = ( ID * ) bltxt;
+ slink->flag[slink->totscript] = (short)event;
+
+ slink->totscript++;
+
+ if( slink->actscript < 1 )
+ slink->actscript = 1;
+
+ return EXPP_incr_ret (Py_None); /* normal exit */
+}
+
+/*
+ * Utility routines to clamp and store various datatypes. The object type
+ * is checked and a exception is raised if it's not the correct type.
+ *
+ * Inputs:
+ * value: PyObject containing the new value
+ * param: pointer to destination variable
+ * max, min: range of values for clamping
+ * type: kind of pointer and data (uses the same characters as
+ * PyArgs_ParseTuple() and Py_BuildValue()
+ *
+ * Return 0 on success, -1 on error.
+ */
+
+int EXPP_setFloatClamped( PyObject *value, float *param,
+ float min, float max )
+{
+ if( !PyNumber_Check ( value ) ) {
+ char errstr[128];
+ sprintf ( errstr, "expected float argument in [%f,%f]", min, max );
+ return EXPP_ReturnIntError( PyExc_TypeError, errstr );
+ }
+
+ *param = EXPP_ClampFloat( (float)PyFloat_AsDouble( value ), min, max );
+
+ return 0;
+}
+
+int EXPP_setIValueClamped( PyObject *value, void *param,
+ int min, int max, char type )
+{
+ int number;
+
+ if( !PyInt_Check( value ) ) {
+ char errstr[128];
+ sprintf ( errstr, "expected int argument in [%d,%d]", min, max );
+ return EXPP_ReturnIntError( PyExc_TypeError, errstr );
+ }
+
+ number = PyInt_AS_LONG( value );
+
+ switch ( type ) {
+ case 'b':
+ *(char *)param = (char)EXPP_ClampInt( number, min, max );
+ return 0;
+ case 'h':
+ *(short *)param = (short)EXPP_ClampInt( number, min, max );
+ return 0;
+ case 'H':
+ *(unsigned short *)param = (unsigned short)EXPP_ClampInt( number, min, max );
+ return 0;
+ case 'i':
+ *(int *)param = EXPP_ClampInt( number, min, max );
+ return 0;
+ default:
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "EXPP_setIValueClamped(): invalid type code" );
+ }
+}
+
+int EXPP_setVec3Clamped( PyObject *value, float *param,
+ float min, float max )
+{
+ if( VectorObject_Check( value ) ) {
+ VectorObject *vect = (VectorObject *)value;
+ if( vect->size == 3 ) {
+ param[0] = EXPP_ClampFloat( vect->vec[0], min, max );
+ param[1] = EXPP_ClampFloat( vect->vec[1], min, max );
+ param[2] = EXPP_ClampFloat( vect->vec[2], min, max );
+ return 0;
+ }
+ }
+
+ if (1) {
+ char errstr[128];
+ sprintf ( errstr, "expected vector argument in [%f,%f]", min, max );
+ return EXPP_ReturnIntError( PyExc_TypeError, errstr );
+ }
+}
+
+
+/*
+ * Utility routines to range-check and store various datatypes. The object
+ * type is checked and a exception is raised if it's not the correct type.
+ * An exception is also raised if the value lies outside of the specified
+ * range.
+ *
+ * Inputs:
+ * value: PyObject containing the new value
+ * param: pointer to destination variable
+ * max, min: valid range for value
+ * type: kind of pointer and data (uses the same characters as
+ * PyArgs_ParseTuple() and Py_BuildValue()
+ *
+ * Return 0 on success, -1 on error.
+ */
+
+int EXPP_setFloatRange( PyObject *value, float *param,
+ float min, float max )
+{
+ char errstr[128];
+ float number;
+
+ sprintf ( errstr, "expected int argument in [%f,%f]", min, max );
+
+ if( !PyNumber_Check ( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError, errstr );
+
+ number = (float)PyFloat_AsDouble( value );
+ if ( number < min || number > max )
+ return EXPP_ReturnIntError( PyExc_ValueError, errstr );
+
+ *param = number;
+ return 0;
+}
+
+int EXPP_setIValueRange( PyObject *value, void *param,
+ int min, int max, char type )
+{
+ char errstr[128];
+ int number;
+
+ sprintf ( errstr, "expected int argument in [%d,%d]", min, max );
+
+ if( !PyInt_Check ( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError, errstr );
+
+ number = PyInt_AS_LONG( value );
+ if( number < min || number > max )
+ return EXPP_ReturnIntError( PyExc_ValueError, errstr );
+
+ switch ( type ) {
+ case 'b':
+ *(char *)param = (char)number;
+ return 0;
+ case 'h':
+ *(short *)param = (short)number;
+ return 0;
+ case 'H':
+ *(unsigned short *)param = (unsigned short)number;
+ return 0;
+ case 'i':
+ *(int *)param = number;
+ return 0;
+ default:
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "EXPP_setIValueRange(): invalid type code" );
+ }
+}
+
+/*
+ * Utility routines to handle all attribute setters which use module
+ * constants. Generic pointer to destination variable is used, and typecast
+ * to the appropriate type based on the "type" specifier.
+ *
+ * Inputs:
+ * constant: constant_Type value
+ * param: pointer to destination variable
+ * type: kind of pointer and data
+ *
+ * Return 0 on success, -1 on error.
+ */
+
+int EXPP_setModuleConstant ( BPy_constant *constant, void *param, char type )
+{
+ PyObject *item;
+
+ if( constant->ob_type != &constant_Type )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected module constant" );
+
+ item = PyDict_GetItemString( constant->dict, "value" );
+ if( !item )
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "module constant has no \"value\" key" );
+
+ switch ( type ) {
+ case 'h':
+ *(short *)param = (short)PyInt_AS_LONG( item );
+ return 0;
+ case 'i':
+ *(int *)param = PyInt_AS_LONG( item );
+ return 0;
+ case 'f':
+ *(float *)param = (float)PyFloat_AS_DOUBLE( item );
+ Py_DECREF(item); /* line above increfs */
+ return 0;
+ default:
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "EXPP_setModuleConstant(): invalid type code" );
+ }
+}
+
+/*
+ * Utility routines to get/set bits in bitfields. Adapted from code in
+ * sceneRender.c (thanks, ascotan!).
+ *
+ * Inputs:
+ * param: pointer to source/destination variable
+ * setting: the bit to get/set
+ * type: pointer type ('h' == short, 'i' == integer)
+ */
+
+PyObject *EXPP_getBitfield( void *param, int setting, char type )
+{
+ switch ( type ) {
+ case 'b':
+ return (*(char *)param & setting)
+ ? EXPP_incr_ret_True() : EXPP_incr_ret_False();
+ case 'h':
+ return (*(short *)param & setting)
+ ? EXPP_incr_ret_True() : EXPP_incr_ret_False();
+ case 'i':
+ return (*(int *)param & setting)
+ ? EXPP_incr_ret_True() : EXPP_incr_ret_False();
+ default:
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "EXPP_getBit(): invalid type code" );
+ }
+}
+
+int EXPP_setBitfield( PyObject * value, void *param, int setting, char type )
+{
+ int param_bool = PyObject_IsTrue( value );
+
+ if( param_bool == -1 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected True/False or 0/1" );
+
+ switch ( type ) {
+ case 'b':
+ if ( param_bool )
+ *(char *)param |= setting;
+ else
+ *(char *)param &= ~setting;
+ return 0;
+ case 'h':
+ if ( param_bool )
+ *(short *)param |= setting;
+ else
+ *(short *)param &= ~setting;
+ return 0;
+ case 'i':
+ if ( param_bool )
+ *(int *)param |= setting;
+ else
+ *(int *)param &= ~setting;
+ return 0;
+ default:
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "EXPP_setBit(): invalid type code" );
+ }
+}
+
+/*
+ * Procedure to handle older setStuff() methods. Assumes that argument
+ * is a tuple with one object, and so grabs the object and passes it to
+ * the specified tp_getset setter for the corresponding attribute.
+ */
+
+PyObject *EXPP_setterWrapper ( PyObject * self, PyObject * args,
+ setter func)
+{
+ int error;
+
+ if ( !PyTuple_Check( args ) || PyTuple_Size( args ) != 1 )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "expected tuple of one item" );
+
+ error = func ( self, PyTuple_GET_ITEM( args, 0 ), NULL );
+ if ( !error ) {
+ Py_INCREF( Py_None );
+ return Py_None;
+ } else
+ return NULL;
+}
+
+/*
+ * Procedure to handle older setStuff() methods. Assumes that argument
+ * is a tuple, so just passes it to the specified tp_getset setter for
+ * the corresponding attribute.
+ */
+
+PyObject *EXPP_setterWrapperTuple ( PyObject * self, PyObject * args,
+ setter func)
+{
+ int error;
+
+ if ( !PyTuple_Check( args ) )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "expected tuple" );
+
+ error = func ( self, args, NULL );
+ if ( !error ) {
+ Py_INCREF( Py_None );
+ return Py_None;
+ } else
+ return NULL;
+}
+
+/*
+ * Helper to keep dictionaries from causing memory leaks. When some object
+ * is just created to be added to the dictionary, its reference count needs
+ * to be decremented so it can be reclaimed.
+ */
+
+int EXPP_dict_set_item_str( PyObject *dict, char *key, PyObject *value)
+{
+ /* add value to dictionary */
+ int ret = PyDict_SetItemString(dict, key, value);
+ Py_DECREF( value ); /* delete original */
+ return ret;
+}
+
+/*
+ * Helper function for subtypes that what the base types methods.
+ * The command below needs to have args modified to have 'self' added at the start
+ * ret = PyObject_Call(PyDict_GetItemString(PyList_Type.tp_dict, "sort"), newargs, keywds);
+ *
+ * This is not easy with the python API so adding a function here,
+ * remember to Py_DECREF the tuple after
+ */
+
+PyObject * EXPP_PyTuple_New_Prepend(PyObject *tuple, PyObject *value)
+{
+ PyObject *item;
+ PyObject *new_tuple;
+ int i;
+
+ i = PyTuple_Size(tuple);
+ new_tuple = PyTuple_New(i+1);
+ PyTuple_SetItem(new_tuple, 0, value);
+ Py_INCREF(value);
+ while (i) {
+ i--;
+ item = PyTuple_GetItem(tuple, i);
+ PyTuple_SetItem(new_tuple, i+1, item);
+ Py_INCREF(item);
+ }
+ return new_tuple;
+}
diff --git a/source/blender/python/api2_2x/gen_utils.h b/source/blender/python/api2_2x/gen_utils.h
new file mode 100644
index 00000000000..f13722e03d0
--- /dev/null
+++ b/source/blender/python/api2_2x/gen_utils.h
@@ -0,0 +1,176 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Michel Selten, Willian P. Germano, Alex Mole, Joseph Gilbert
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_gen_utils_h
+#define EXPP_gen_utils_h
+
+#include <Python.h>
+#include "DNA_ID.h"
+#include "DNA_scriptlink_types.h"
+#include "DNA_listBase.h"
+
+#include "constant.h"
+
+#define Py_PI 3.14159265358979323846
+#define Py_WRAP 1024
+#define Py_NEW 2048
+
+/*
+ Py_RETURN_NONE
+ Python 2.4 macro.
+ defined here until we switch to 2.4
+*/
+#ifndef Py_RETURN_NONE
+#define Py_RETURN_NONE return Py_BuildValue("O", Py_None)
+#endif
+#ifndef Py_RETURN_FALSE
+#define Py_RETURN_FALSE return PyBool_FromLong(0)
+#endif
+#ifndef Py_RETURN_TRUE
+#define Py_RETURN_TRUE return PyBool_FromLong(1)
+#endif
+
+/* Py 2.5 adds a new Py_ssize_t type for 64 bit support */
+/* #if'ed for your compiling pleasure */
+#if 1
+
+/* for pre Py 2.5 */
+#if PY_VERSION_HEX < 0x02050000
+typedef int Py_ssize_t;
+#define PY_SSIZE_T_MAX INT_MAX
+#define PY_SSIZE_T_MIN INT_MIN
+#else
+/* Py 2.5 and later */
+#define intargfunc ssizeargfunc
+#define intintargfunc ssizessizeargfunc
+#endif
+
+#endif
+
+/* name of list of Armature weak refs built into __main__ */
+#define ARM_WEAKREF_LIST_NAME "__arm_weakrefs"
+
+int EXPP_FloatsAreEqual(float A, float B, int floatSteps);
+int EXPP_VectorsAreEqual(float *vecA, float *vecB, int size, int floatSteps);
+
+PyObject *EXPP_GetModuleConstant(char *module, char *constant);
+
+int StringEqual( const char *string1, const char *string2 );
+
+PyObject *PythonReturnErrorObject( PyObject * type, char *error_msg );
+PyObject *PythonIncRef( PyObject * object );
+
+char *event_to_name( short event );
+
+float EXPP_ClampFloat( float value, float min, float max );
+int EXPP_ClampInt( int value, int min, int max );
+
+void EXPP_incr2( PyObject * ob1, PyObject * ob2 );
+void EXPP_incr3( PyObject * ob1, PyObject * ob2, PyObject * ob3 );
+void EXPP_decr2( PyObject * ob1, PyObject * ob2 );
+void EXPP_decr3( PyObject * ob1, PyObject * ob2, PyObject * ob3 );
+PyObject *EXPP_incr_ret( PyObject * object );
+PyObject *EXPP_incr_ret_True(void);
+PyObject *EXPP_incr_ret_False(void);
+PyObject *EXPP_ReturnPyObjError( PyObject * type, char *error_msg );
+int EXPP_ReturnIntError( PyObject * type, char *error_msg );
+
+PyObject *EXPP_objError(PyObject *type, const char *format, ...);
+int EXPP_intError(PyObject *type, const char *format, ...);
+
+int EXPP_check_sequence_consistency( PyObject * seq, PyTypeObject * against );
+PyObject *EXPP_tuple_repr( PyObject * self, int size );
+
+/* mapping utilities - see Texture.c for an example of how to use these */
+typedef struct {
+ const char *sval;
+ int ival;
+} EXPP_map_pair;
+
+/* maps must end with a pair that has NULL as sval */
+int EXPP_map_getIntVal( const EXPP_map_pair * map,
+ const char *sval, int *ival );
+int EXPP_map_case_getIntVal( const EXPP_map_pair * map,
+ const char *sval, int *ival );
+int EXPP_map_getShortVal( const EXPP_map_pair * map,
+ const char *sval, short *ival );
+int EXPP_map_getStrVal( const EXPP_map_pair * map,
+ int ival, const char **sval );
+
+/* clamping and range-checking utilities */
+
+int EXPP_setIValueClamped( PyObject *value, void *param,
+ int min, int max, char type );
+int EXPP_setFloatClamped ( PyObject *value, float *param,
+ float min, float max);
+int EXPP_setVec3Clamped ( PyObject *value, float *param,
+ float min, float max);
+int EXPP_setIValueRange( PyObject *value, void *param,
+ int min, int max, char type );
+int EXPP_setFloatRange ( PyObject *value, float *param,
+ float min, float max);
+
+/* utility routine for PyType attributes setters with module constant */
+
+int EXPP_setModuleConstant ( BPy_constant *constant, void *param,
+ char type );
+
+/* utilities to get/set bits in bitfields */
+
+PyObject *EXPP_getBitfield( void *param, int setting, char type );
+int EXPP_setBitfield( PyObject * value, void *param, int setting, char type );
+
+/*
+ * Procedures to handle older setStuff() methods, which now access
+ * a PyType's setter attributes using the tp_getset mechanism.
+ */
+
+PyObject *EXPP_setterWrapper ( PyObject * self, PyObject * args,
+ setter func);
+
+PyObject *EXPP_setterWrapperTuple ( PyObject * self, PyObject * args,
+ setter func);
+
+/* scriplinks-related: */
+PyObject *EXPP_getScriptLinks(ScriptLink *slink, PyObject *value, int is_scene);
+PyObject *EXPP_addScriptLink(ScriptLink *slink, PyObject *args, int is_scene);
+PyObject *EXPP_clearScriptLinks(ScriptLink *slink, PyObject *args);
+
+/* this queues redraws if we're not in background mode: */
+void EXPP_allqueue(unsigned short event, short val);
+
+/* helper to keep dictionaries from causing memory leaks */
+int EXPP_dict_set_item_str( PyObject *dict, char *key, PyObject *value);
+PyObject * EXPP_PyTuple_New_Prepend(PyObject *tuple, PyObject *value);
+
+#endif /* EXPP_gen_utils_h */
+
diff --git a/source/blender/python/api2_2x/logic.c b/source/blender/python/api2_2x/logic.c
new file mode 100644
index 00000000000..a09b7fa48e7
--- /dev/null
+++ b/source/blender/python/api2_2x/logic.c
@@ -0,0 +1,529 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Joseph Gilbert
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#include "logic.h" /*This must come first*/
+
+#include "MEM_guardedalloc.h"
+#include "BLI_blenlib.h"
+#include "gen_utils.h"
+
+//--------------- Python BPy_Property methods declarations:---------------
+static PyObject *Property_getName( BPy_Property * self );
+static PyObject *Property_setName( BPy_Property * self, PyObject * value );
+static PyObject *Property_getData( BPy_Property * self );
+static PyObject *Property_setData( BPy_Property * self, PyObject * args );
+static PyObject *Property_getType( BPy_Property * self );
+//--------------- Python BPy_Property methods table:----------------------
+static PyMethodDef BPy_Property_methods[] = {
+ {"getName", ( PyCFunction ) Property_getName, METH_NOARGS,
+ "() - return Property name"},
+ {"setName", ( PyCFunction ) Property_setName, METH_O,
+ "() - set the name of this Property"},
+ {"getData", ( PyCFunction ) Property_getData, METH_NOARGS,
+ "() - return Property data"},
+ {"setData", ( PyCFunction ) Property_setData, METH_VARARGS,
+ "() - set the data of this Property"},
+ {"getType", ( PyCFunction ) Property_getType, METH_NOARGS,
+ "() - return Property type"},
+ {NULL, NULL, 0, NULL}
+};
+//--------------- Python TypeProperty callback function prototypes--------
+static void Property_dealloc( BPy_Property * Property );
+static PyObject *Property_getAttr( BPy_Property * Property, char *name );
+static int Property_setAttr( BPy_Property * Property, char *name,
+ PyObject * v );
+static PyObject *Property_repr( BPy_Property * Property );
+static int Property_compare( BPy_Property * a1, BPy_Property * a2 );
+//--------------- Python TypeProperty structure definition----------------
+PyTypeObject property_Type = {
+ PyObject_HEAD_INIT( NULL )
+ 0, /* ob_size */
+ "Blender Property", /* tp_name */
+ sizeof( BPy_Property ), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ /* methods */
+ ( destructor ) Property_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ ( getattrfunc ) Property_getAttr, /* tp_getattr */
+ ( setattrfunc ) Property_setAttr, /* tp_setattr */
+ ( cmpfunc ) Property_compare, /* tp_compare */
+ ( reprfunc ) Property_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_as_hash */
+ 0, 0, 0, 0, 0, 0,
+ 0, /* tp_doc */
+ 0, 0, 0, 0, 0, 0,
+ BPy_Property_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+};
+//--------------- Property module internal callbacks-------------------
+
+//--------------- updatePyProperty-------------------------------------
+int updatePyProperty( BPy_Property * self )
+{
+ if( !self->property ) {
+ return 0; //nothing to update - not linked
+ } else {
+ BLI_strncpy( self->name, self->property->name, 32 );
+ self->type = self->property->type;
+ if( self->property->type == PROP_BOOL ) {
+ if( *( ( int * ) &self->property->poin ) ) {
+ self->data = EXPP_incr_ret_True();
+ } else {
+ self->data = EXPP_incr_ret_False();
+ }
+ } else if( self->property->type == PROP_INT ) {
+ self->data = PyInt_FromLong( self->property->data );
+ } else if( self->property->type == PROP_FLOAT ) {
+ self->data =
+ PyFloat_FromDouble( *
+ ( ( float * ) &self->
+ property->data ) );
+ } else if( self->property->type == PROP_TIME ) {
+ self->data =
+ PyFloat_FromDouble( *
+ ( ( float * ) &self->
+ property->data ) );
+ } else if( self->property->type == PROP_STRING ) {
+ self->data =
+ PyString_FromString( self->property->poin );
+ }
+ return 1;
+ }
+}
+
+//--------------- updatePropertyData------------------------------------
+int updateProperyData( BPy_Property * self )
+{
+ if( !self->property ) {
+ //nothing to update - not linked
+ return 0;
+ } else {
+ BLI_strncpy( self->property->name, self->name, 32 );
+ self->property->type = self->type;
+ if( PyInt_Check( self->data ) ) {
+ *( ( int * ) &self->property->data ) =
+ ( int ) PyInt_AsLong( self->data );
+ } else if( PyFloat_Check( self->data ) ) {
+ *( ( float * ) &self->property->data ) =
+ ( float ) PyFloat_AsDouble( self->data );
+ } else if( PyString_Check( self->data ) ) {
+ BLI_strncpy( self->property->poin,
+ PyString_AsString( self->data ),
+ MAX_PROPSTRING );
+ }
+ return 1;
+ }
+}
+
+//--------------- checkValidData_ptr--------------------------------
+static int checkValidData_ptr( BPy_Property * self )
+{
+ int length;
+ /* test pointer to see if data was removed (oops) */
+ /* WARNING!!! - MEMORY LEAK HERE, why not free this??? */
+ length = MEM_allocN_len( self->property );
+ if( length != sizeof( bProperty ) ) { //data was freed
+ self->property = NULL;
+ return 0;
+ } else { //it's ok as far as we can tell
+ return 1;
+ }
+}
+
+//---------------BPy_Property internal callbacks/methods------------
+
+//--------------- dealloc-------------------------------------------
+static void Property_dealloc( BPy_Property * self )
+{
+ PyMem_Free( self->name );
+ PyObject_DEL( self );
+}
+
+//---------------getattr--------------------------------------------
+static PyObject *Property_getAttr( BPy_Property * self, char *name )
+{
+ checkValidData_ptr( self );
+ if( strcmp( name, "name" ) == 0 )
+ return Property_getName( self );
+ else if( strcmp( name, "data" ) == 0 )
+ return Property_getData( self );
+ else if( strcmp( name, "type" ) == 0 )
+ return Property_getType( self );
+ else if( strcmp( name, "__members__" ) == 0 ) {
+ return Py_BuildValue( "[s,s,s]", "name", "data", "type" );
+ }
+
+ return Py_FindMethod( BPy_Property_methods, ( PyObject * ) self, name );
+}
+
+//--------------- setattr-------------------------------------------
+static int
+Property_setAttr( BPy_Property * self, char *name, PyObject * value )
+{
+ PyObject *error = NULL;
+
+ checkValidData_ptr( self );
+
+ if( strcmp( name, "name" ) == 0 ) {
+ error = Property_setName( self, value );
+ } else if( strcmp( name, "data" ) == 0 ) {
+ PyObject *valtuple = Py_BuildValue( "(O)", value );
+ if( !valtuple )
+ return EXPP_ReturnIntError( PyExc_MemoryError,
+ "PropertySetAttr: couldn't create tuple" );
+
+ error = Property_setData( self, valtuple );
+ Py_DECREF( valtuple );
+ } else {
+ return ( EXPP_ReturnIntError
+ ( PyExc_KeyError, "attribute not found" ) );
+ }
+
+
+ if( error != Py_None )
+ return -1;
+
+ Py_DECREF( Py_None );
+ return 0;
+}
+
+//--------------- repr----------------------------------------------
+static PyObject *Property_repr( BPy_Property * self )
+{
+ checkValidData_ptr( self );
+ if( self->property ) {
+ return PyString_FromFormat( "[Property \"%s\"]",
+ self->property->name );
+ } else {
+ return PyString_FromFormat( "[Property \"%s\"]", self->name );
+ }
+}
+
+//--------------- compare-------------------------------------------
+//compares property.name and property.data
+static int Property_compare( BPy_Property * a, BPy_Property * b )
+{
+ BPy_Property *py_propA, *py_propB;
+ int retval = -1;
+
+ checkValidData_ptr( a );
+ checkValidData_ptr( b );
+ //2 python objects
+ if( !a->property && !b->property ) {
+ if( a->type != b->type )
+ retval = -1;
+ if( BLI_streq( a->name, b->name ) ) {
+ retval = PyObject_Compare( a->data, b->data );
+ } else
+ retval = -1;
+ } else if( a->property && b->property ) { //2 real properties
+ if( a->property->type != b->property->type )
+ retval = -1;
+ if( BLI_streq( a->property->name, b->property->name ) ) {
+ if( a->property->type == PROP_BOOL
+ || a->property->type == PROP_INT ) {
+ if( a->property->data == b->property->data )
+ retval = 0;
+ else
+ retval = -1;
+ } else if( a->property->type == PROP_FLOAT
+ || a->property->type == PROP_TIME ) {
+ if( *( ( float * ) &a->property->data ) ==
+ *( ( float * ) &b->property->data ) )
+ retval = 0;
+ else
+ retval = -1;
+ } else if( a->property->type == PROP_STRING ) {
+ if( BLI_streq
+ ( a->property->poin, b->property->poin ) )
+ retval = 0;
+ else
+ retval = -1;
+ }
+ } else
+ retval = -1;
+ } else { //1 real 1 python
+ if( !a->property ) {
+ py_propA = a;
+ py_propB = b;
+ } else {
+ py_propA = b;
+ py_propB = a;
+ }
+ if( py_propB->property->type != py_propA->type )
+ retval = -1;
+ if( BLI_streq( py_propB->property->name, py_propA->name ) ) {
+ if( py_propB->property->type == PROP_BOOL ||
+ py_propB->property->type == PROP_INT ) {
+ retval = PyObject_Compare( py_propA->data,
+ PyInt_FromLong
+ ( py_propB->
+ property->
+ data ) );
+ } else if( py_propB->property->type == PROP_FLOAT
+ || py_propB->property->type == PROP_TIME ) {
+ retval = PyObject_Compare( py_propA->data,
+ PyFloat_FromDouble
+ ( *
+ ( ( float * )
+ &py_propB->
+ property->
+ data ) ) );
+ } else if( py_propB->property->type == PROP_STRING ) {
+ PyObject *tmpstr = PyString_FromString( py_propB->property->poin );
+ retval = PyObject_Compare( py_propA->data, tmpstr );
+ Py_DECREF(tmpstr);
+ }
+ } else
+ retval = -1;
+ }
+ return retval;
+}
+
+//--------------- Property visible functions------------------------
+//--------------- Property_CreatePyObject---------------------------
+PyObject *Property_CreatePyObject( struct bProperty * Property )
+{
+ BPy_Property *py_property;
+
+ py_property =
+ ( BPy_Property * ) PyObject_NEW( BPy_Property,
+ &property_Type );
+
+ //set the struct flag
+ py_property->property = Property;
+
+ //allocate space for python vars
+ py_property->name = PyMem_Malloc( 32 );
+
+ if( !updatePyProperty( py_property ) )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_AttributeError, "Property struct empty" ) );
+
+ return ( ( PyObject * ) py_property );
+}
+
+//--------------- Property_FromPyObject-----------------------------
+struct bProperty *Property_FromPyObject( PyObject * py_obj )
+{
+ BPy_Property *py_property;
+
+ py_property = ( BPy_Property * ) py_obj;
+ if( !py_property->property )
+ return NULL;
+ else
+ return ( py_property->property );
+}
+
+//--------------- newPropertyObject()-------------------------------
+PyObject *newPropertyObject( char *name, PyObject * data, int type )
+{
+ BPy_Property *py_property;
+
+ py_property =
+ ( BPy_Property * ) PyObject_NEW( BPy_Property,
+ &property_Type );
+ py_property->name = PyMem_Malloc( 32 );
+ py_property->property = NULL;
+
+ BLI_strncpy( py_property->name, name, 32 );
+ py_property->data = data;
+ py_property->type = (short)type;
+
+ return ( PyObject * ) py_property;
+}
+
+//--------------- Python BPy_Property methods-----------------------
+//--------------- BPy_Property.getName()----------------------------
+static PyObject *Property_getName( BPy_Property * self )
+{
+ if( !self->property )
+ return PyString_FromString( self->name );
+ else
+ return PyString_FromString( self->property->name );
+}
+
+//--------------- BPy_Property.setName()----------------------------
+static PyObject *Property_setName( BPy_Property * self, PyObject * value )
+{
+ char *name = PyString_AsString(value);
+
+ if( !name )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected string argument" ) );
+
+ if( !self->property ) {
+ BLI_strncpy( self->name, name, 32 );
+ } else {
+ BLI_strncpy( self->property->name, name, 32 );
+ updatePyProperty( self );
+ }
+
+ Py_RETURN_NONE;
+}
+
+//--------------- BPy_Property.getData()----------------------------
+static PyObject *Property_getData( BPy_Property * self )
+{
+ PyObject *attr = NULL;
+
+ if( !self->property ) {
+ attr = EXPP_incr_ret( self->data );
+ } else {
+ if( self->property->type == PROP_BOOL ) {
+ if( self->property->data )
+ attr = EXPP_incr_ret_True();
+ else
+ attr = EXPP_incr_ret_False();
+ } else if( self->property->type == PROP_INT ) {
+ attr = PyInt_FromLong( self->property->data );
+ } else if( self->property->type == PROP_FLOAT ||
+ self->property->type == PROP_TIME ) {
+ attr = PyFloat_FromDouble( *
+ ( ( float * ) &self->
+ property->data ) );
+ } else if( self->property->type == PROP_STRING ) {
+ attr = PyString_FromString( self->property->poin );
+ }
+ }
+ if( attr )
+ return attr;
+
+ return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't get Property.data attribute" ) );
+}
+
+//--------------- BPy_Property.setData()----------------------------
+static PyObject *Property_setData( BPy_Property * self, PyObject * args )
+{
+ PyObject *data;
+ char *type_str = NULL;
+ int type = -1;
+ short *p_type = NULL;
+
+ if( !PyArg_ParseTuple( args, "O|s", &data, &type_str ) )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected object and optional string argument" ) );
+
+ if( !PyInt_Check( data ) && !PyFloat_Check( data )
+ && !PyString_Check( data ) )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_RuntimeError,
+ "float, int, or string expected as data" ) );
+
+ //parse property name
+ if( type_str ) {
+ if( BLI_streq( type_str, "BOOL" ) )
+ type = PROP_BOOL;
+ else if( BLI_streq( type_str, "INT" ) )
+ type = PROP_INT;
+ else if( BLI_streq( type_str, "FLOAT" ) )
+ type = PROP_FLOAT;
+ else if( BLI_streq( type_str, "TIME" ) )
+ type = PROP_TIME;
+ else if( BLI_streq( type_str, "STRING" ) )
+ type = PROP_STRING;
+ else
+ return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "BOOL, INT, FLOAT, TIME or STRING expected" ) );
+ }
+ //get pointer to type
+ if( self->property )
+ p_type = &self->property->type;
+ else
+ p_type = &self->type;
+
+ //set the type
+ if( PyInt_Check( data ) ) {
+ if( type == -1 || type == PROP_INT )
+ *p_type = PROP_INT;
+ else
+ *p_type = PROP_BOOL;
+ } else if( PyFloat_Check( data ) ) {
+ if( type == -1 || type == PROP_FLOAT )
+ *p_type = PROP_FLOAT;
+ else
+ *p_type = PROP_TIME;
+ } else if( PyString_Check( data ) ) {
+ if( type == -1 || type == PROP_STRING )
+ *p_type = PROP_STRING;
+ } else {
+ return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "cant set unknown data type" ) );
+ }
+
+ //set the data
+ if( self->property ) {
+ if( PyInt_Check( data ) ) {
+ *( ( int * ) &self->property->data ) =
+ ( int ) PyInt_AsLong( data );
+ } else if( PyFloat_Check( data ) ) {
+ *( ( float * ) &self->property->data ) =
+ ( float ) PyFloat_AsDouble( data );
+ } else if( PyString_Check( data ) ) {
+ BLI_strncpy( self->property->poin,
+ PyString_AsString( data ),
+ MAX_PROPSTRING );
+ }
+ updatePyProperty( self );
+ } else {
+ self->data = data;
+ }
+ Py_RETURN_NONE;
+}
+
+//--------------- BPy_Property.getType()----------------------------
+static PyObject *Property_getType( BPy_Property * self )
+{
+ int type;
+
+ if( self->property )
+ type = self->property->type;
+ else
+ type = self->type;
+
+ if( type == PROP_BOOL )
+ return PyString_FromString( "BOOL" );
+ else if( type == PROP_INT )
+ return PyString_FromString( "INT" );
+ else if( type == PROP_FLOAT )
+ return PyString_FromString( "FLOAT" );
+ else if( type == PROP_STRING )
+ return PyString_FromString( "STRING" );
+ else if( type == PROP_TIME )
+ return PyString_FromString( "TIME" );
+ Py_RETURN_NONE;
+}
diff --git a/source/blender/python/api2_2x/logic.h b/source/blender/python/api2_2x/logic.h
new file mode 100644
index 00000000000..013c26af4f2
--- /dev/null
+++ b/source/blender/python/api2_2x/logic.h
@@ -0,0 +1,61 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Joseph Gilbert
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_LOGIC_H
+#define EXPP_LOGIC_H
+
+#include <Python.h>
+#include "DNA_property_types.h"
+
+extern PyTypeObject property_Type;
+
+#define BPy_Property_Check(v) ((v)->ob_type == &property_Type)
+
+//--------------------------Python BPy_Property structure definition.----
+typedef struct {
+ PyObject_HEAD
+ //reference to property data if object linked
+ bProperty * property;
+ //list of vars that define the property
+ char *name;
+ PyObject *data;
+ short type;
+} BPy_Property;
+
+//------------------------------visible prototypes-----------------------
+PyObject *Property_CreatePyObject( struct bProperty *prop );
+bProperty *Property_FromPyObject( PyObject * py_obj );
+PyObject *newPropertyObject( char *name, PyObject * data, int type );
+int updatePyProperty( BPy_Property * self );
+int updateProperyData( BPy_Property * self );
+
+#endif
diff --git a/source/blender/python/api2_2x/matrix.c b/source/blender/python/api2_2x/matrix.c
new file mode 100644
index 00000000000..fadadbb5c6a
--- /dev/null
+++ b/source/blender/python/api2_2x/matrix.c
@@ -0,0 +1,975 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Michel Selten & Joseph Gilbert
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "Mathutils.h"
+
+#include "BKE_utildefines.h"
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+#include "gen_utils.h"
+
+/*-------------------------DOC STRINGS ---------------------------*/
+char Matrix_Zero_doc[] = "() - set all values in the matrix to 0";
+char Matrix_Identity_doc[] = "() - set the square matrix to it's identity matrix";
+char Matrix_Transpose_doc[] = "() - set the matrix to it's transpose";
+char Matrix_Determinant_doc[] = "() - return the determinant of the matrix";
+char Matrix_Invert_doc[] = "() - set the matrix to it's inverse if an inverse is possible";
+char Matrix_TranslationPart_doc[] = "() - return a vector encompassing the translation of the matrix";
+char Matrix_RotationPart_doc[] = "() - return a vector encompassing the rotation of the matrix";
+char Matrix_scalePart_doc[] = "() - convert matrix to a 3D vector";
+char Matrix_Resize4x4_doc[] = "() - resize the matrix to a 4x4 square matrix";
+char Matrix_toEuler_doc[] = "() - convert matrix to a euler angle rotation";
+char Matrix_toQuat_doc[] = "() - convert matrix to a quaternion rotation";
+char Matrix_copy_doc[] = "() - return a copy of the matrix";
+/*-----------------------METHOD DEFINITIONS ----------------------*/
+struct PyMethodDef Matrix_methods[] = {
+ {"zero", (PyCFunction) Matrix_Zero, METH_NOARGS, Matrix_Zero_doc},
+ {"identity", (PyCFunction) Matrix_Identity, METH_NOARGS, Matrix_Identity_doc},
+ {"transpose", (PyCFunction) Matrix_Transpose, METH_NOARGS, Matrix_Transpose_doc},
+ {"determinant", (PyCFunction) Matrix_Determinant, METH_NOARGS, Matrix_Determinant_doc},
+ {"invert", (PyCFunction) Matrix_Invert, METH_NOARGS, Matrix_Invert_doc},
+ {"translationPart", (PyCFunction) Matrix_TranslationPart, METH_NOARGS, Matrix_TranslationPart_doc},
+ {"rotationPart", (PyCFunction) Matrix_RotationPart, METH_NOARGS, Matrix_RotationPart_doc},
+ {"scalePart", (PyCFunction) Matrix_scalePart, METH_NOARGS, Matrix_scalePart_doc},
+ {"resize4x4", (PyCFunction) Matrix_Resize4x4, METH_NOARGS, Matrix_Resize4x4_doc},
+ {"toEuler", (PyCFunction) Matrix_toEuler, METH_NOARGS, Matrix_toEuler_doc},
+ {"toQuat", (PyCFunction) Matrix_toQuat, METH_NOARGS, Matrix_toQuat_doc},
+ {"copy", (PyCFunction) Matrix_copy, METH_NOARGS, Matrix_copy_doc},
+ {"__copy__", (PyCFunction) Matrix_copy, METH_NOARGS, Matrix_copy_doc},
+ {NULL, NULL, 0, NULL}
+};
+/*-----------------------------METHODS----------------------------*/
+/*---------------------------Matrix.toQuat() ---------------------*/
+PyObject *Matrix_toQuat(MatrixObject * self)
+{
+ float quat[4];
+
+ /*must be 3-4 cols, 3-4 rows, square matrix*/
+ if(self->colSize < 3 || self->rowSize < 3 || (self->colSize != self->rowSize)) {
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Matrix.toQuat(): inappropriate matrix size - expects 3x3 or 4x4 matrix\n");
+ }
+ if(self->colSize == 3){
+ Mat3ToQuat((float (*)[3])*self->matrix, quat);
+ }else{
+ Mat4ToQuat((float (*)[4])*self->matrix, quat);
+ }
+
+ return newQuaternionObject(quat, Py_NEW);
+}
+/*---------------------------Matrix.toEuler() --------------------*/
+PyObject *Matrix_toEuler(MatrixObject * self)
+{
+ float eul[3];
+
+ int x;
+
+ /*must be 3-4 cols, 3-4 rows, square matrix*/
+ if(self->colSize ==3 && self->rowSize ==3) {
+ Mat3ToEul((float (*)[3])*self->matrix, eul);
+ }else if (self->colSize ==4 && self->rowSize ==4) {
+ float tempmat3[3][3];
+ Mat3CpyMat4(tempmat3, (float (*)[4])*self->matrix);
+ Mat3ToEul(tempmat3, eul);
+ }else
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Matrix.toEuler(): inappropriate matrix size - expects 3x3 or 4x4 matrix\n");
+
+ /*have to convert to degrees*/
+ for(x = 0; x < 3; x++) {
+ eul[x] *= (float) (180 / Py_PI);
+ }
+ return newEulerObject(eul, Py_NEW);
+}
+/*---------------------------Matrix.resize4x4() ------------------*/
+PyObject *Matrix_Resize4x4(MatrixObject * self)
+{
+ int x, first_row_elem, curr_pos, new_pos, blank_columns, blank_rows, index;
+
+ if(self->data.blend_data){
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "cannot resize wrapped data - only python matrices\n");
+ }
+
+ self->data.py_data = PyMem_Realloc(self->data.py_data, (sizeof(float) * 16));
+ if(self->data.py_data == NULL) {
+ return EXPP_ReturnPyObjError(PyExc_MemoryError,
+ "matrix.resize4x4(): problem allocating pointer space\n\n");
+ }
+ self->contigPtr = self->data.py_data; /*force*/
+ self->matrix = PyMem_Realloc(self->matrix, (sizeof(float *) * 4));
+ if(self->matrix == NULL) {
+ return EXPP_ReturnPyObjError(PyExc_MemoryError,
+ "matrix.resize4x4(): problem allocating pointer space\n\n");
+ }
+ /*set row pointers*/
+ for(x = 0; x < 4; x++) {
+ self->matrix[x] = self->contigPtr + (x * 4);
+ }
+ /*move data to new spot in array + clean*/
+ for(blank_rows = (4 - self->rowSize); blank_rows > 0; blank_rows--){
+ for(x = 0; x < 4; x++){
+ index = (4 * (self->rowSize + (blank_rows - 1))) + x;
+ if (index == 10 || index == 15){
+ self->contigPtr[index] = 1.0f;
+ }else{
+ self->contigPtr[index] = 0.0f;
+ }
+ }
+ }
+ for(x = 1; x <= self->rowSize; x++){
+ first_row_elem = (self->colSize * (self->rowSize - x));
+ curr_pos = (first_row_elem + (self->colSize -1));
+ new_pos = (4 * (self->rowSize - x )) + (curr_pos - first_row_elem);
+ for(blank_columns = (4 - self->colSize); blank_columns > 0; blank_columns--){
+ self->contigPtr[new_pos + blank_columns] = 0.0f;
+ }
+ for(curr_pos = curr_pos; curr_pos >= first_row_elem; curr_pos--){
+ self->contigPtr[new_pos] = self->contigPtr[curr_pos];
+ new_pos--;
+ }
+ }
+ self->rowSize = 4;
+ self->colSize = 4;
+ return EXPP_incr_ret((PyObject*)self);
+}
+/*---------------------------Matrix.translationPart() ------------*/
+PyObject *Matrix_TranslationPart(MatrixObject * self)
+{
+ float vec[4];
+
+ if(self->colSize < 3 || self->rowSize < 4){
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Matrix.translationPart: inappropriate matrix size\n");
+ }
+
+ vec[0] = self->matrix[3][0];
+ vec[1] = self->matrix[3][1];
+ vec[2] = self->matrix[3][2];
+
+ return newVectorObject(vec, 3, Py_NEW);
+}
+/*---------------------------Matrix.rotationPart() ---------------*/
+PyObject *Matrix_RotationPart(MatrixObject * self)
+{
+ float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
+
+ if(self->colSize < 3 || self->rowSize < 3){
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Matrix.rotationPart: inappropriate matrix size\n");
+ }
+
+ mat[0] = self->matrix[0][0];
+ mat[1] = self->matrix[0][1];
+ mat[2] = self->matrix[0][2];
+ mat[3] = self->matrix[1][0];
+ mat[4] = self->matrix[1][1];
+ mat[5] = self->matrix[1][2];
+ mat[6] = self->matrix[2][0];
+ mat[7] = self->matrix[2][1];
+ mat[8] = self->matrix[2][2];
+
+ return newMatrixObject(mat, 3, 3, Py_NEW);
+}
+/*---------------------------Matrix.scalePart() --------------------*/
+PyObject *Matrix_scalePart(MatrixObject * self)
+{
+ float scale[3], rot[3];
+ float mat[3][3], imat[3][3], tmat[3][3];
+
+ /*must be 3-4 cols, 3-4 rows, square matrix*/
+ if(self->colSize == 4 && self->rowSize == 4)
+ Mat3CpyMat4(mat, (float (*)[4])*self->matrix);
+ else if(self->colSize == 3 && self->rowSize == 3)
+ Mat3CpyMat3(mat, (float (*)[3])*self->matrix);
+ else
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Matrix.scalePart(): inappropriate matrix size - expects 3x3 or 4x4 matrix\n");
+
+ /* functionality copied from editobject.c apply_obmat */
+ Mat3ToEul(mat, rot);
+ EulToMat3(rot, tmat);
+ Mat3Inv(imat, tmat);
+ Mat3MulMat3(tmat, imat, mat);
+
+ scale[0]= tmat[0][0];
+ scale[1]= tmat[1][1];
+ scale[2]= tmat[2][2];
+ return newVectorObject(scale, 3, Py_NEW);
+}
+/*---------------------------Matrix.invert() ---------------------*/
+PyObject *Matrix_Invert(MatrixObject * self)
+{
+
+ int x, y, z = 0;
+ float det = 0.0f;
+ PyObject *f = NULL;
+ float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
+
+ if(self->rowSize != self->colSize){
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Matrix.invert(ed): only square matrices are supported\n");
+ }
+
+ /*calculate the determinant*/
+ f = Matrix_Determinant(self);
+ det = (float)PyFloat_AS_DOUBLE(f); /*Increfs, so we need to decref*/
+ Py_DECREF(f);
+
+ if(det != 0) {
+ /*calculate the classical adjoint*/
+ if(self->rowSize == 2) {
+ mat[0] = self->matrix[1][1];
+ mat[1] = -self->matrix[1][0];
+ mat[2] = -self->matrix[0][1];
+ mat[3] = self->matrix[0][0];
+ } else if(self->rowSize == 3) {
+ Mat3Adj((float (*)[3]) mat,(float (*)[3]) *self->matrix);
+ } else if(self->rowSize == 4) {
+ Mat4Adj((float (*)[4]) mat, (float (*)[4]) *self->matrix);
+ }
+ /*divide by determinate*/
+ for(x = 0; x < (self->rowSize * self->colSize); x++) {
+ mat[x] /= det;
+ }
+ /*set values*/
+ for(x = 0; x < self->rowSize; x++) {
+ for(y = 0; y < self->colSize; y++) {
+ self->matrix[x][y] = mat[z];
+ z++;
+ }
+ }
+ /*transpose
+ Matrix_Transpose(self);*/
+ } else {
+ return EXPP_ReturnPyObjError(PyExc_ValueError,
+ "matrix does not have an inverse");
+ }
+ return EXPP_incr_ret((PyObject*)self);
+}
+
+
+/*---------------------------Matrix.determinant() ----------------*/
+PyObject *Matrix_Determinant(MatrixObject * self)
+{
+ float det = 0.0f;
+
+ if(self->rowSize != self->colSize){
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Matrix.determinant: only square matrices are supported\n");
+ }
+
+ if(self->rowSize == 2) {
+ det = Det2x2(self->matrix[0][0], self->matrix[0][1],
+ self->matrix[1][0], self->matrix[1][1]);
+ } else if(self->rowSize == 3) {
+ det = Det3x3(self->matrix[0][0], self->matrix[0][1],
+ self->matrix[0][2], self->matrix[1][0],
+ self->matrix[1][1], self->matrix[1][2],
+ self->matrix[2][0], self->matrix[2][1],
+ self->matrix[2][2]);
+ } else {
+ det = Det4x4((float (*)[4]) *self->matrix);
+ }
+
+ return PyFloat_FromDouble( (double) det );
+}
+/*---------------------------Matrix.transpose() ------------------*/
+PyObject *Matrix_Transpose(MatrixObject * self)
+{
+ float t = 0.0f;
+
+ if(self->rowSize != self->colSize){
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Matrix.transpose(d): only square matrices are supported\n");
+ }
+
+ if(self->rowSize == 2) {
+ t = self->matrix[1][0];
+ self->matrix[1][0] = self->matrix[0][1];
+ self->matrix[0][1] = t;
+ } else if(self->rowSize == 3) {
+ Mat3Transp((float (*)[3])*self->matrix);
+ } else {
+ Mat4Transp((float (*)[4])*self->matrix);
+ }
+
+ return EXPP_incr_ret((PyObject*)self);
+}
+
+
+/*---------------------------Matrix.zero() -----------------------*/
+PyObject *Matrix_Zero(MatrixObject * self)
+{
+ int row, col;
+
+ for(row = 0; row < self->rowSize; row++) {
+ for(col = 0; col < self->colSize; col++) {
+ self->matrix[row][col] = 0.0f;
+ }
+ }
+ return EXPP_incr_ret((PyObject*)self);
+}
+/*---------------------------Matrix.identity(() ------------------*/
+PyObject *Matrix_Identity(MatrixObject * self)
+{
+ if(self->rowSize != self->colSize){
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Matrix.identity: only square matrices are supported\n");
+ }
+
+ if(self->rowSize == 2) {
+ self->matrix[0][0] = 1.0f;
+ self->matrix[0][1] = 0.0f;
+ self->matrix[1][0] = 0.0f;
+ self->matrix[1][1] = 1.0f;
+ } else if(self->rowSize == 3) {
+ Mat3One((float (*)[3]) *self->matrix);
+ } else {
+ Mat4One((float (*)[4]) *self->matrix);
+ }
+
+ return EXPP_incr_ret((PyObject*)self);
+}
+
+/*---------------------------Matrix.inverted() ------------------*/
+PyObject *Matrix_copy(MatrixObject * self)
+{
+ return (PyObject*)(MatrixObject*)newMatrixObject((float (*))*self->matrix, self->rowSize, self->colSize, Py_NEW);
+}
+
+/*----------------------------dealloc()(internal) ----------------*/
+/*free the py_object*/
+static void Matrix_dealloc(MatrixObject * self)
+{
+ Py_XDECREF(self->coerced_object);
+ PyMem_Free(self->matrix);
+ /*only free py_data*/
+ if(self->data.py_data){
+ PyMem_Free(self->data.py_data);
+ }
+ PyObject_DEL(self);
+}
+/*----------------------------getattr()(internal) ----------------*/
+/*object.attribute access (get)*/
+static PyObject *Matrix_getattr(MatrixObject * self, char *name)
+{
+ if(STREQ(name, "rowSize")) {
+ return PyInt_FromLong((long) self->rowSize);
+ } else if(STREQ(name, "colSize")) {
+ return PyInt_FromLong((long) self->colSize);
+ }
+ if(STREQ(name, "wrapped")){
+ if(self->wrapped == Py_WRAP)
+ return EXPP_incr_ret((PyObject *)Py_True);
+ else
+ return EXPP_incr_ret((PyObject *)Py_False);
+ }
+ return Py_FindMethod(Matrix_methods, (PyObject *) self, name);
+}
+/*----------------------------setattr()(internal) ----------------*/
+/*object.attribute access (set)*/
+static int Matrix_setattr(MatrixObject * self, char *name, PyObject * v)
+{
+ /* This is not supported. */
+ return (-1);
+}
+/*----------------------------print object (internal)-------------*/
+/*print the object to screen*/
+static PyObject *Matrix_repr(MatrixObject * self)
+{
+ int x, y;
+ char buffer[48], str[1024];
+
+ BLI_strncpy(str,"",1024);
+ for(x = 0; x < self->rowSize; x++){
+ sprintf(buffer, "[");
+ strcat(str,buffer);
+ for(y = 0; y < (self->colSize - 1); y++) {
+ sprintf(buffer, "%.6f, ", self->matrix[x][y]);
+ strcat(str,buffer);
+ }
+ if(x < (self->rowSize-1)){
+ sprintf(buffer, "%.6f](matrix [row %d])\n", self->matrix[x][y], x);
+ strcat(str,buffer);
+ }else{
+ sprintf(buffer, "%.6f](matrix [row %d])", self->matrix[x][y], x);
+ strcat(str,buffer);
+ }
+ }
+
+ return PyString_FromString(str);
+}
+/*------------------------tp_richcmpr*/
+/*returns -1 execption, 0 false, 1 true*/
+static PyObject* Matrix_richcmpr(PyObject *objectA, PyObject *objectB, int comparison_type)
+{
+ MatrixObject *matA = NULL, *matB = NULL;
+ int result = 0;
+
+ if (!MatrixObject_Check(objectA) || !MatrixObject_Check(objectB)){
+ if (comparison_type == Py_NE){
+ return EXPP_incr_ret(Py_True);
+ }else{
+ return EXPP_incr_ret(Py_False);
+ }
+ }
+ matA = (MatrixObject*)objectA;
+ matB = (MatrixObject*)objectB;
+
+ if (matA->colSize != matB->colSize || matA->rowSize != matB->rowSize){
+ if (comparison_type == Py_NE){
+ return EXPP_incr_ret(Py_True);
+ }else{
+ return EXPP_incr_ret(Py_False);
+ }
+ }
+
+ switch (comparison_type){
+ case Py_EQ:
+ /*contigPtr is basically a really long vector*/
+ result = EXPP_VectorsAreEqual(matA->contigPtr, matB->contigPtr,
+ (matA->rowSize * matA->colSize), 1);
+ break;
+ case Py_NE:
+ result = EXPP_VectorsAreEqual(matA->contigPtr, matB->contigPtr,
+ (matA->rowSize * matA->colSize), 1);
+ if (result == 0){
+ result = 1;
+ }else{
+ result = 0;
+ }
+ break;
+ default:
+ printf("The result of the comparison could not be evaluated");
+ break;
+ }
+ if (result == 1){
+ return EXPP_incr_ret(Py_True);
+ }else{
+ return EXPP_incr_ret(Py_False);
+ }
+}
+/*------------------------tp_doc*/
+static char MatrixObject_doc[] = "This is a wrapper for matrix objects.";
+/*---------------------SEQUENCE PROTOCOLS------------------------
+ ----------------------------len(object)------------------------
+ sequence length*/
+static int Matrix_len(MatrixObject * self)
+{
+ return (self->colSize * self->rowSize);
+}
+/*----------------------------object[]---------------------------
+ sequence accessor (get)
+ the wrapped vector gives direct access to the matrix data*/
+static PyObject *Matrix_item(MatrixObject * self, int i)
+{
+ if(i < 0 || i >= self->rowSize)
+ return EXPP_ReturnPyObjError(PyExc_IndexError,
+ "matrix[attribute]: array index out of range\n");
+
+ return newVectorObject(self->matrix[i], self->colSize, Py_WRAP);
+}
+/*----------------------------object[]-------------------------
+ sequence accessor (set)*/
+static int Matrix_ass_item(MatrixObject * self, int i, PyObject * ob)
+{
+ int y, x, size = 0;
+ float vec[4];
+ PyObject *m, *f;
+
+ if(i >= self->rowSize || i < 0){
+ return EXPP_ReturnIntError(PyExc_TypeError,
+ "matrix[attribute] = x: bad row\n");
+ }
+
+ if(PySequence_Check(ob)){
+ size = PySequence_Length(ob);
+ if(size != self->colSize){
+ return EXPP_ReturnIntError(PyExc_TypeError,
+ "matrix[attribute] = x: bad sequence size\n");
+ }
+ for (x = 0; x < size; x++) {
+ m = PySequence_GetItem(ob, x);
+ if (m == NULL) { /*Failed to read sequence*/
+ return EXPP_ReturnIntError(PyExc_RuntimeError,
+ "matrix[attribute] = x: unable to read sequence\n");
+ }
+
+ f = PyNumber_Float(m);
+ if(f == NULL) { /*parsed item not a number*/
+ Py_DECREF(m);
+ return EXPP_ReturnIntError(PyExc_TypeError,
+ "matrix[attribute] = x: sequence argument not a number\n");
+ }
+
+ vec[x] = (float)PyFloat_AS_DOUBLE(f);
+ EXPP_decr2(m, f);
+ }
+ /*parsed well - now set in matrix*/
+ for(y = 0; y < size; y++){
+ self->matrix[i][y] = vec[y];
+ }
+ return 0;
+ }else{
+ return EXPP_ReturnIntError(PyExc_TypeError,
+ "matrix[attribute] = x: expects a sequence of column size\n");
+ }
+}
+/*----------------------------object[z:y]------------------------
+ sequence slice (get)*/
+static PyObject *Matrix_slice(MatrixObject * self, int begin, int end)
+{
+
+ PyObject *list = NULL;
+ int count;
+
+ CLAMP(begin, 0, self->rowSize);
+ CLAMP(end, 0, self->rowSize);
+ begin = MIN2(begin,end);
+
+ list = PyList_New(end - begin);
+ for(count = begin; count < end; count++) {
+ PyList_SetItem(list, count - begin,
+ newVectorObject(self->matrix[count], self->colSize, Py_WRAP));
+ }
+
+ return list;
+}
+/*----------------------------object[z:y]------------------------
+ sequence slice (set)*/
+static int Matrix_ass_slice(MatrixObject * self, int begin, int end,
+ PyObject * seq)
+{
+ int i, x, y, size, sub_size = 0;
+ float mat[16];
+ PyObject *subseq;
+ PyObject *m, *f;
+
+ CLAMP(begin, 0, self->rowSize);
+ CLAMP(end, 0, self->rowSize);
+ begin = MIN2(begin,end);
+
+ if(PySequence_Check(seq)){
+ size = PySequence_Length(seq);
+ if(size != (end - begin)){
+ return EXPP_ReturnIntError(PyExc_TypeError,
+ "matrix[begin:end] = []: size mismatch in slice assignment\n");
+ }
+ /*parse sub items*/
+ for (i = 0; i < size; i++) {
+ /*parse each sub sequence*/
+ subseq = PySequence_GetItem(seq, i);
+ if (subseq == NULL) { /*Failed to read sequence*/
+ return EXPP_ReturnIntError(PyExc_RuntimeError,
+ "matrix[begin:end] = []: unable to read sequence\n");
+ }
+
+ if(PySequence_Check(subseq)){
+ /*subsequence is also a sequence*/
+ sub_size = PySequence_Length(subseq);
+ if(sub_size != self->colSize){
+ Py_DECREF(subseq);
+ return EXPP_ReturnIntError(PyExc_TypeError,
+ "matrix[begin:end] = []: size mismatch in slice assignment\n");
+ }
+ for (y = 0; y < sub_size; y++) {
+ m = PySequence_GetItem(subseq, y);
+ if (m == NULL) { /*Failed to read sequence*/
+ Py_DECREF(subseq);
+ return EXPP_ReturnIntError(PyExc_RuntimeError,
+ "matrix[begin:end] = []: unable to read sequence\n");
+ }
+
+ f = PyNumber_Float(m);
+ if(f == NULL) { /*parsed item not a number*/
+ EXPP_decr2(m, subseq);
+ return EXPP_ReturnIntError(PyExc_TypeError,
+ "matrix[begin:end] = []: sequence argument not a number\n");
+ }
+
+ mat[(i * self->colSize) + y] = (float)PyFloat_AS_DOUBLE(f);
+ EXPP_decr2(f, m);
+ }
+ }else{
+ Py_DECREF(subseq);
+ return EXPP_ReturnIntError(PyExc_TypeError,
+ "matrix[begin:end] = []: illegal argument type for built-in operation\n");
+ }
+ Py_DECREF(subseq);
+ }
+ /*parsed well - now set in matrix*/
+ for(x = 0; x < (size * sub_size); x++){
+ self->matrix[begin + (int)floor(x / self->colSize)][x % self->colSize] = mat[x];
+ }
+ return 0;
+ }else{
+ return EXPP_ReturnIntError(PyExc_TypeError,
+ "matrix[begin:end] = []: illegal argument type for built-in operation\n");
+ }
+}
+/*------------------------NUMERIC PROTOCOLS----------------------
+ ------------------------obj + obj------------------------------*/
+static PyObject *Matrix_add(PyObject * m1, PyObject * m2)
+{
+ int x, y;
+ float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
+ MatrixObject *mat1 = NULL, *mat2 = NULL;
+
+ mat1 = (MatrixObject*)m1;
+ mat2 = (MatrixObject*)m2;
+
+ if(mat1->coerced_object || mat2->coerced_object){
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Matrix addition: arguments not valid for this operation....\n");
+ }
+ if(mat1->rowSize != mat2->rowSize || mat1->colSize != mat2->colSize){
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Matrix addition: matrices must have the same dimensions for this operation\n");
+ }
+
+ for(x = 0; x < mat1->rowSize; x++) {
+ for(y = 0; y < mat1->colSize; y++) {
+ mat[((x * mat1->colSize) + y)] = mat1->matrix[x][y] + mat2->matrix[x][y];
+ }
+ }
+
+ return newMatrixObject(mat, mat1->rowSize, mat1->colSize, Py_NEW);
+}
+/*------------------------obj - obj------------------------------
+ subtraction*/
+static PyObject *Matrix_sub(PyObject * m1, PyObject * m2)
+{
+ int x, y;
+ float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
+ MatrixObject *mat1 = NULL, *mat2 = NULL;
+
+ mat1 = (MatrixObject*)m1;
+ mat2 = (MatrixObject*)m2;
+
+ if(mat1->coerced_object || mat2->coerced_object){
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Matrix addition: arguments not valid for this operation....\n");
+ }
+ if(mat1->rowSize != mat2->rowSize || mat1->colSize != mat2->colSize){
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Matrix addition: matrices must have the same dimensions for this operation\n");
+ }
+
+ for(x = 0; x < mat1->rowSize; x++) {
+ for(y = 0; y < mat1->colSize; y++) {
+ mat[((x * mat1->colSize) + y)] = mat1->matrix[x][y] - mat2->matrix[x][y];
+ }
+ }
+
+ return newMatrixObject(mat, mat1->rowSize, mat1->colSize, Py_NEW);
+}
+/*------------------------obj * obj------------------------------
+ mulplication*/
+static PyObject *Matrix_mul(PyObject * m1, PyObject * m2)
+{
+ int x, y, z;
+ float scalar;
+ float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
+ double dot = 0.0f;
+ MatrixObject *mat1 = NULL, *mat2 = NULL;
+ PyObject *f = NULL;
+ PointObject *pt = NULL;
+
+ mat1 = (MatrixObject*)m1;
+ mat2 = (MatrixObject*)m2;
+
+ if(mat1->coerced_object){
+ if (PyFloat_Check(mat1->coerced_object) ||
+ PyInt_Check(mat1->coerced_object)){ /*FLOAT/INT * MATRIX*/
+ f = PyNumber_Float(mat1->coerced_object);
+ if(f == NULL) { /*parsed item not a number*/
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Matrix multiplication: arguments not acceptable for this operation\n");
+ }
+
+ scalar = (float)PyFloat_AS_DOUBLE(f);
+ Py_DECREF(f);
+ for(x = 0; x < mat2->rowSize; x++) {
+ for(y = 0; y < mat2->colSize; y++) {
+ mat[((x * mat2->colSize) + y)] = scalar * mat2->matrix[x][y];
+ }
+ }
+ return newMatrixObject(mat, mat2->rowSize, mat2->colSize, Py_NEW);
+ }
+ }else{
+ if(mat2->coerced_object){
+ /* MATRIX * VECTOR operation is now being done by vector */
+ /*if(VectorObject_Check(mat2->coerced_object)){
+ vec = (VectorObject*)mat2->coerced_object;
+ return column_vector_multiplication(mat1, vec);
+ }else */
+ if(PointObject_Check(mat2->coerced_object)){ /*MATRIX * POINT*/
+ pt = (PointObject*)mat2->coerced_object;
+ return column_point_multiplication(mat1, pt);
+ }else if (PyFloat_Check(mat2->coerced_object) ||
+ PyInt_Check(mat2->coerced_object)){ /*MATRIX * FLOAT/INT*/
+ f = PyNumber_Float(mat2->coerced_object);
+ if(f == NULL) { /*parsed item not a number*/
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Matrix multiplication: arguments not acceptable for this operation\n");
+ }
+
+ scalar = (float)PyFloat_AS_DOUBLE(f);
+ Py_DECREF(f);
+ for(x = 0; x < mat1->rowSize; x++) {
+ for(y = 0; y < mat1->colSize; y++) {
+ mat[((x * mat1->colSize) + y)] = scalar * mat1->matrix[x][y];
+ }
+ }
+ return newMatrixObject(mat, mat1->rowSize, mat1->colSize, Py_NEW);
+ }
+ }else{ /*MATRIX * MATRIX*/
+ if(mat1->colSize != mat2->rowSize){
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Matrix multiplication: matrix A rowsize must equal matrix B colsize\n");
+ }
+ for(x = 0; x < mat1->rowSize; x++) {
+ for(y = 0; y < mat2->colSize; y++) {
+ for(z = 0; z < mat1->colSize; z++) {
+ dot += (mat1->matrix[x][z] * mat2->matrix[z][y]);
+ }
+ mat[((x * mat1->rowSize) + y)] = (float)dot;
+ dot = 0.0f;
+ }
+ }
+ return newMatrixObject(mat, mat1->rowSize, mat2->colSize, Py_NEW);
+ }
+ }
+
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Matrix multiplication: arguments not acceptable for this operation\n");
+}
+PyObject* Matrix_inv(MatrixObject *self)
+{
+ return Matrix_Invert(self);
+}
+/*------------------------coerce(obj, obj)-----------------------
+ coercion of unknown types to type MatrixObject for numeric protocols.
+
+ Coercion() is called whenever a math operation has 2 operands that
+ it doesn't understand how to evaluate. 2+Matrix for example. We want to
+ evaluate some of these operations like: (vector * 2), however, for math
+ to proceed, the unknown operand must be cast to a type that python math will
+ understand. (e.g. in the case above case, 2 must be cast to a vector and
+ then call vector.multiply(vector, scalar_cast_as_vector)*/
+static int Matrix_coerce(PyObject ** m1, PyObject ** m2)
+{
+ if(VectorObject_Check(*m2) || PyFloat_Check(*m2) || PyInt_Check(*m2) ||
+ PointObject_Check(*m2)) {
+ PyObject *coerced = EXPP_incr_ret(*m2);
+ *m2 = newMatrixObject(NULL,3,3,Py_NEW);
+ ((MatrixObject*)*m2)->coerced_object = coerced;
+ Py_INCREF (*m1);
+ return 0;
+ }
+
+ return EXPP_ReturnIntError(PyExc_TypeError,
+ "matrix.coerce(): unknown operand - can't coerce for numeric protocols");
+}
+/*-----------------PROTOCOL DECLARATIONS--------------------------*/
+static PySequenceMethods Matrix_SeqMethods = {
+ (inquiry) Matrix_len, /* sq_length */
+ (binaryfunc) 0, /* sq_concat */
+ (intargfunc) 0, /* sq_repeat */
+ (intargfunc) Matrix_item, /* sq_item */
+ (intintargfunc) Matrix_slice, /* sq_slice */
+ (intobjargproc) Matrix_ass_item, /* sq_ass_item */
+ (intintobjargproc) Matrix_ass_slice, /* sq_ass_slice */
+};
+static PyNumberMethods Matrix_NumMethods = {
+ (binaryfunc) Matrix_add, /* __add__ */
+ (binaryfunc) Matrix_sub, /* __sub__ */
+ (binaryfunc) Matrix_mul, /* __mul__ */
+ (binaryfunc) 0, /* __div__ */
+ (binaryfunc) 0, /* __mod__ */
+ (binaryfunc) 0, /* __divmod__ */
+ (ternaryfunc) 0, /* __pow__ */
+ (unaryfunc) 0, /* __neg__ */
+ (unaryfunc) 0, /* __pos__ */
+ (unaryfunc) 0, /* __abs__ */
+ (inquiry) 0, /* __nonzero__ */
+ (unaryfunc) Matrix_inv, /* __invert__ */
+ (binaryfunc) 0, /* __lshift__ */
+ (binaryfunc) 0, /* __rshift__ */
+ (binaryfunc) 0, /* __and__ */
+ (binaryfunc) 0, /* __xor__ */
+ (binaryfunc) 0, /* __or__ */
+ (coercion) Matrix_coerce, /* __coerce__ */
+ (unaryfunc) 0, /* __int__ */
+ (unaryfunc) 0, /* __long__ */
+ (unaryfunc) 0, /* __float__ */
+ (unaryfunc) 0, /* __oct__ */
+ (unaryfunc) 0, /* __hex__ */
+};
+/*------------------PY_OBECT DEFINITION--------------------------*/
+PyTypeObject matrix_Type = {
+ PyObject_HEAD_INIT(NULL) /*tp_head*/
+ 0, /*tp_internal*/
+ "matrix", /*tp_name*/
+ sizeof(MatrixObject), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)Matrix_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ (getattrfunc)Matrix_getattr, /*tp_getattr*/
+ (setattrfunc) Matrix_setattr, /*tp_setattr*/
+ 0, /*tp_compare*/
+ (reprfunc) Matrix_repr, /*tp_repr*/
+ &Matrix_NumMethods, /*tp_as_number*/
+ &Matrix_SeqMethods, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash*/
+ 0, /*tp_call*/
+ 0, /*tp_str*/
+ 0, /*tp_getattro*/
+ 0, /*tp_setattro*/
+ 0, /*tp_as_buffer*/
+ Py_TPFLAGS_DEFAULT, /*tp_flags*/
+ MatrixObject_doc, /*tp_doc*/
+ 0, /*tp_traverse*/
+ 0, /*tp_clear*/
+ (richcmpfunc)Matrix_richcmpr, /*tp_richcompare*/
+ 0, /*tp_weaklistoffset*/
+ 0, /*tp_iter*/
+ 0, /*tp_iternext*/
+ 0, /*tp_methods*/
+ 0, /*tp_members*/
+ 0, /*tp_getset*/
+ 0, /*tp_base*/
+ 0, /*tp_dict*/
+ 0, /*tp_descr_get*/
+ 0, /*tp_descr_set*/
+ 0, /*tp_dictoffset*/
+ 0, /*tp_init*/
+ 0, /*tp_alloc*/
+ 0, /*tp_new*/
+ 0, /*tp_free*/
+ 0, /*tp_is_gc*/
+ 0, /*tp_bases*/
+ 0, /*tp_mro*/
+ 0, /*tp_cache*/
+ 0, /*tp_subclasses*/
+ 0, /*tp_weaklist*/
+ 0 /*tp_del*/
+};
+
+/*------------------------newMatrixObject (internal)-------------
+creates a new matrix object
+self->matrix self->contiguous_ptr (reference to data.xxx)
+ [0]------------->[0]
+ [1]
+ [2]
+ [1]------------->[3]
+ [4]
+ [5]
+ ....
+self->matrix[1][1] = self->contiguous_ptr[4] = self->data.xxx_data[4]*/
+
+/*pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER
+ (i.e. it was allocated elsewhere by MEM_mallocN())
+ pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON
+ (i.e. it must be created here with PyMEM_malloc())*/
+PyObject *newMatrixObject(float *mat, int rowSize, int colSize, int type)
+{
+ MatrixObject *self;
+ int x, row, col;
+
+ /*matrix objects can be any 2-4row x 2-4col matrix*/
+ if(rowSize < 2 || rowSize > 4 || colSize < 2 || colSize > 4){
+ return EXPP_ReturnPyObjError(PyExc_RuntimeError,
+ "matrix(): row and column sizes must be between 2 and 4\n");
+ }
+
+ self = PyObject_NEW(MatrixObject, &matrix_Type);
+ self->data.blend_data = NULL;
+ self->data.py_data = NULL;
+ self->rowSize = rowSize;
+ self->colSize = colSize;
+ self->coerced_object = NULL;
+
+ if(type == Py_WRAP){
+ self->data.blend_data = mat;
+ self->contigPtr = self->data.blend_data;
+ /*create pointer array*/
+ self->matrix = PyMem_Malloc(rowSize * sizeof(float *));
+ if(self->matrix == NULL) { /*allocation failure*/
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "matrix(): problem allocating pointer space\n");
+ }
+ /*pointer array points to contigous memory*/
+ for(x = 0; x < rowSize; x++) {
+ self->matrix[x] = self->contigPtr + (x * colSize);
+ }
+ self->wrapped = Py_WRAP;
+ }else if (type == Py_NEW){
+ self->data.py_data = PyMem_Malloc(rowSize * colSize * sizeof(float));
+ if(self->data.py_data == NULL) { /*allocation failure*/
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "matrix(): problem allocating pointer space\n");
+ }
+ self->contigPtr = self->data.py_data;
+ /*create pointer array*/
+ self->matrix = PyMem_Malloc(rowSize * sizeof(float *));
+ if(self->matrix == NULL) { /*allocation failure*/
+ PyMem_Free(self->data.py_data);
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "matrix(): problem allocating pointer space\n");
+ }
+ /*pointer array points to contigous memory*/
+ for(x = 0; x < rowSize; x++) {
+ self->matrix[x] = self->contigPtr + (x * colSize);
+ }
+ /*parse*/
+ if(mat) { /*if a float array passed*/
+ for(row = 0; row < rowSize; row++) {
+ for(col = 0; col < colSize; col++) {
+ self->matrix[row][col] = mat[(row * colSize) + col];
+ }
+ }
+ } else if (rowSize == colSize ) { /*or if no arguments are passed return identity matrix for square matrices */
+ Matrix_Identity(self);
+ Py_DECREF(self);
+ }
+ self->wrapped = Py_NEW;
+ }else{ /*bad type*/
+ return NULL;
+ }
+ return (PyObject *) self;
+}
diff --git a/source/blender/python/api2_2x/matrix.h b/source/blender/python/api2_2x/matrix.h
new file mode 100644
index 00000000000..a2581ab009b
--- /dev/null
+++ b/source/blender/python/api2_2x/matrix.h
@@ -0,0 +1,80 @@
+/*
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Joseph Gilbert
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ *
+ */
+
+#ifndef EXPP_matrix_h
+#define EXPP_matrix_h
+
+#include <Python.h>
+
+extern PyTypeObject matrix_Type;
+
+#define MatrixObject_Check(v) ((v)->ob_type == &matrix_Type)
+
+typedef float **ptRow;
+typedef struct _Matrix {
+ PyObject_VAR_HEAD
+ struct{
+ float *py_data; /*python managed*/
+ float *blend_data; /*blender managed*/
+ }data;
+ ptRow matrix; /*ptr to the contigPtr (accessor)*/
+ float *contigPtr; /*1D array of data (alias)*/
+ int rowSize;
+ int colSize;
+ int wrapped; /*is wrapped data?*/
+ PyObject *coerced_object;
+} MatrixObject;
+/*coerced_object is a pointer to the object that it was
+coerced from when a dummy vector needs to be created from
+the coerce() function for numeric protocol operations*/
+
+/*struct data contains a pointer to the actual data that the
+object uses. It can use either PyMem allocated data (which will
+be stored in py_data) or be a wrapper for data allocated through
+blender (stored in blend_data). This is an either/or struct not both*/
+
+/*prototypes*/
+PyObject *Matrix_Zero( MatrixObject * self );
+PyObject *Matrix_Identity( MatrixObject * self );
+PyObject *Matrix_Transpose( MatrixObject * self );
+PyObject *Matrix_Determinant( MatrixObject * self );
+PyObject *Matrix_Invert( MatrixObject * self );
+PyObject *Matrix_TranslationPart( MatrixObject * self );
+PyObject *Matrix_RotationPart( MatrixObject * self );
+PyObject *Matrix_scalePart( MatrixObject * self );
+PyObject *Matrix_Resize4x4( MatrixObject * self );
+PyObject *Matrix_toEuler( MatrixObject * self );
+PyObject *Matrix_toQuat( MatrixObject * self );
+PyObject *Matrix_copy( MatrixObject * self );
+PyObject *newMatrixObject(float *mat, int rowSize, int colSize, int type);
+
+#endif /* EXPP_matrix_H */
diff --git a/source/blender/python/api2_2x/meshPrimitive.c b/source/blender/python/api2_2x/meshPrimitive.c
new file mode 100644
index 00000000000..098d5f7d5f6
--- /dev/null
+++ b/source/blender/python/api2_2x/meshPrimitive.c
@@ -0,0 +1,279 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender, partially based on NMesh.c API.
+ *
+ * Contributor(s): Ken Hughes
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "Mesh.h" /*This must come first*/
+
+#include "DNA_scene_types.h"
+#include "BDR_editobject.h"
+#include "BIF_editmesh.h"
+#include "BKE_global.h"
+#include "BKE_object.h"
+#include "BKE_scene.h"
+#include "BKE_library.h"
+#include "blendef.h"
+
+#include "gen_utils.h"
+
+/*
+ * local helper procedure which does the dirty work of messing with the
+ * edit mesh, active objects, etc.
+ */
+
+static PyObject *make_mesh( int type, char *name, short tot, short seg,
+ short subdiv, float dia, float height, short ext, short fill )
+{
+ float cent[3] = {0,0,0};
+ float imat[3][3]={{1,0,0},{0,1,0},{0,0,1}};
+ Mesh *me;
+ BPy_Mesh *obj;
+ Object *ob;
+ Base *base;
+
+ /* remember active object (if any) for later, so we can re-activate */
+ base = BASACT;
+
+ /* make a new object, "copy" to the editMesh structure */
+ ob = add_object(OB_MESH);
+ me = (Mesh *)ob->data;
+ G.obedit = BASACT->object;
+ make_editMesh( );
+
+ /* create the primitive in the edit mesh */
+
+ make_prim( type, imat, /* mesh type, transform matrix */
+ tot, seg, /* total vertices, segments */
+ subdiv, /* subdivisions (for Icosphere only) */
+ dia, -height, /* diameter-ish, height */
+ ext, fill, /* extrude, fill end faces */
+ cent ); /* location of center */
+
+ /* copy primitive back to the real mesh */
+ load_editMesh( );
+ free_editMesh( G.editMesh );
+ G.obedit = NULL;
+
+ /* remove object link to the data, then delete the object */
+ ob->data = NULL;
+ me->id.us = 0;
+ free_and_unlink_base(BASACT);
+
+ /* if there was an active object, reactivate it */
+ if( base )
+ scene_select_base(G.scene, base);
+
+ /* create the BPy_Mesh that wraps this mesh */
+ obj = (BPy_Mesh *)PyObject_NEW( BPy_Mesh, &Mesh_Type );
+
+ rename_id( &me->id, name );
+ obj->mesh = me;
+ obj->object = NULL;
+ obj->new = 1;
+ return (PyObject *) obj;
+}
+
+static PyObject *M_MeshPrim_Plane( PyObject *self_unused, PyObject *args )
+{
+ float size = 2.0;
+
+ if( !PyArg_ParseTuple( args, "|f", &size ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected optional float arg" );
+
+ size *= (float)(sqrt(2.0)/2.0);
+ return make_mesh( 0, "Plane", 4, 0, 0, size, -size, 0, 1 );
+}
+
+static PyObject *M_MeshPrim_Cube( PyObject *self_unused, PyObject *args )
+{
+ float height = 2.0;
+ float dia;
+
+ if( !PyArg_ParseTuple( args, "|f", &height ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected optional float arg" );
+
+ height /= 2.0;
+ dia = height * (float)sqrt(2.0);
+ return make_mesh( 1, "Cube", 4, 32, 2, dia, -height, 1, 1 );
+}
+
+static PyObject *M_MeshPrim_Circle( PyObject *self_unused, PyObject *args )
+{
+ int tot = 32;
+ float size = 2;
+
+ if( !PyArg_ParseTuple( args, "|if", &tot, &size ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected int and optional float arg" );
+ if( tot < 3 || tot > 100 )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "number of vertices must be in the range [3:100]" );
+
+ size /= 2.0;
+ return make_mesh( 4, "Circle", tot, 0, 0, size, -size, 0, 0 );
+}
+
+static PyObject *M_MeshPrim_Cylinder( PyObject *self_unused, PyObject *args )
+{
+ int tot = 32;
+ float size = 2.0;
+ float len = 2.0;
+
+ if( !PyArg_ParseTuple( args, "|iff", &tot, &size, &len ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected int and optional float arg" );
+ if( tot < 3 || tot > 100 )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "number of vertices must be in the range [3:100]" );
+
+ return make_mesh( 5, "Cylinder", tot, 0, 0, size/2.0, -len/2.0, 1, 1 );
+}
+
+static PyObject *M_MeshPrim_Tube( PyObject *self_unused, PyObject *args )
+{
+ int tot = 32;
+ float size = 2.0;
+ float len = 2.0;
+
+ if( !PyArg_ParseTuple( args, "|iff", &tot, &size, &len ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected int and optional float arg" );
+ if( tot < 3 || tot > 100 )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "number of vertices must be in the range [3:100]" );
+
+ return make_mesh( 6, "Tube", tot, 0, 0, size/2.0, -len/2.0, 1, 0 );
+}
+
+static PyObject *M_MeshPrim_Cone( PyObject *self_unused, PyObject *args )
+{
+ int tot = 32;
+ float size = 2.0;
+ float len = 2.0;
+
+ if( !PyArg_ParseTuple( args, "|iff", &tot, &size, &len ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected int and optional float arg" );
+ if( tot < 3 || tot > 100 )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "number of vertices must be in the range [3:100]" );
+
+ return make_mesh( 7, "Cone", tot, 0, 0, size/2.0, -len/2.0, 0, 1 );
+}
+
+static PyObject *M_MeshPrim_Grid( PyObject *self_unused, PyObject *args )
+{
+ int xres = 32;
+ int yres = 32;
+ float size = 2.0;
+
+ if( !PyArg_ParseTuple( args, "|iif", &xres, &yres, &size ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected two ints and an optional float arg" );
+ if( xres < 2 || xres > 100 || yres < 2 || yres > 100 )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "resolution must be in the range [2:100]" );
+
+ size /= 2.0;
+ return make_mesh( 10, "Grid", xres, yres, 0, size, -size, 0, 0 );
+}
+
+static PyObject *M_MeshPrim_UVsphere( PyObject *self_unused, PyObject *args )
+{
+ int segs = 32;
+ int rings = 32;
+ float size = 2.0;
+
+ if( !PyArg_ParseTuple( args, "|iif", &segs, &rings, &size ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected two ints and an optional float arg" );
+ if( segs < 3 || segs > 100 || rings < 3 || rings > 100 )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "segments and rings must be in the range [3:100]" );
+
+ size /= 2.0;
+ return make_mesh( 11, "UVsphere", segs, rings, 0, size, -size, 0, 0 );
+}
+
+static PyObject *M_MeshPrim_Icosphere( PyObject *self_unused, PyObject *args )
+{
+ int subdiv = 2;
+ float size = 2.0;
+
+ if( !PyArg_ParseTuple( args, "|if", &subdiv, &size ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected int and an optional float arg" );
+ if( subdiv < 1 || subdiv > 5 )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "subdivisions must be in the range [1:5]" );
+
+ size /= 2.0;
+ return make_mesh( 12, "Icosphere", 0, 0, subdiv, size, -size, 0, 0 );
+}
+
+static PyObject *M_MeshPrim_Suzanne( PyObject *self_unused, PyObject *args )
+{
+ return make_mesh( 13, "Monkey", 0, 0, 0, 0, 0, 0, 0 );
+}
+
+static struct PyMethodDef M_MeshPrim_methods[] = {
+ {"Plane", (PyCFunction)M_MeshPrim_Plane, METH_VARARGS,
+ "Create a plane mesh"},
+ {"Cube", (PyCFunction)M_MeshPrim_Cube, METH_VARARGS,
+ "Create a cube mesh"},
+ {"Circle", (PyCFunction)M_MeshPrim_Circle, METH_VARARGS,
+ "Create a circle mesh"},
+ {"Cylinder", (PyCFunction)M_MeshPrim_Cylinder, METH_VARARGS,
+ "Create a cylindrical mesh"},
+ {"Tube", (PyCFunction)M_MeshPrim_Tube, METH_VARARGS,
+ "Create a tube mesh"},
+ {"Cone", (PyCFunction)M_MeshPrim_Cone, METH_VARARGS,
+ "Create a conic mesh"},
+ {"Grid", (PyCFunction)M_MeshPrim_Grid, METH_VARARGS,
+ "Create a 2D grid mesh"},
+ {"UVsphere", (PyCFunction)M_MeshPrim_UVsphere, METH_VARARGS,
+ "Create a UV sphere mesh"},
+ {"Icosphere", (PyCFunction)M_MeshPrim_Icosphere, METH_VARARGS,
+ "Create a Ico sphere mesh"},
+ {"Monkey", (PyCFunction)M_MeshPrim_Suzanne, METH_NOARGS,
+ "Create a Suzanne mesh"},
+ {NULL, NULL, 0, NULL},
+};
+
+static char M_MeshPrim_doc[] = "The Blender.Mesh.Primitives submodule";
+
+PyObject *MeshPrimitives_Init( void )
+{
+ return Py_InitModule3( "Blender.Mesh.Primitives",
+ M_MeshPrim_methods, M_MeshPrim_doc );
+}
+
diff --git a/source/blender/python/api2_2x/meshPrimitive.h b/source/blender/python/api2_2x/meshPrimitive.h
new file mode 100644
index 00000000000..1aa60c31eb4
--- /dev/null
+++ b/source/blender/python/api2_2x/meshPrimitive.h
@@ -0,0 +1,46 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Ken Hughes
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef EXPP_MESHPRIMITIVES_H
+#define EXPP_MESHPRIMITIVES_H
+
+#include <Python.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* PROTOS */
+
+PyObject *MeshPrimitives_Init( void );
+
+#endif /* EXPP_MESHPRIMITIVES_H */
diff --git a/source/blender/python/api2_2x/modules.h b/source/blender/python/api2_2x/modules.h
new file mode 100644
index 00000000000..fd03469f772
--- /dev/null
+++ b/source/blender/python/api2_2x/modules.h
@@ -0,0 +1,65 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Michel Selten, Willian P. Germano, Nathan Letwory,
+ * Stephen Swaney
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_modules_h
+#define EXPP_modules_h
+
+/************************************************************
+Certain bpy module files ( BPY_interface.c, Blender.c, and Object.c )
+need to know about almost every other module. This file is a
+convenient way to include almost all the necessary declarations.
+
+The #includes commented out below currently do not exist.
+Their *_Init() method declarations are hacked in down below.
+************************************************************/
+
+#include <Python.h>
+
+/*****************************************************************************/
+/* Global variables */
+/*****************************************************************************/
+
+/****************************************************************************
+Module Init functions for modules without a .h file.
+BGL is a special case. It still has data declarations in the .h file
+and cannot be #included until it is cleaned up.
+****************************************************************************/
+
+PyObject *BGL_Init( void );
+
+PyObject *Library_Init( void );
+PyObject *Noise_Init( void );
+
+
+
+#endif /* EXPP_modules_h */
diff --git a/source/blender/python/api2_2x/point.c b/source/blender/python/api2_2x/point.c
new file mode 100644
index 00000000000..686a4529d9b
--- /dev/null
+++ b/source/blender/python/api2_2x/point.c
@@ -0,0 +1,526 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Joseph Gilbert
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+#include "Mathutils.h"
+
+#include "BLI_blenlib.h"
+#include "BKE_utildefines.h"
+#include "gen_utils.h"
+
+//-------------------------DOC STRINGS ---------------------------
+char Point_Zero_doc[] = "() - set all values in the point to 0";
+char Point_toVector_doc[] = "() - create a vector representation of this point";
+//-----------------------METHOD DEFINITIONS ----------------------
+struct PyMethodDef Point_methods[] = {
+ {"zero", (PyCFunction) Point_Zero, METH_NOARGS, Point_Zero_doc},
+ {"toVector", (PyCFunction) Point_toVector, METH_NOARGS, Point_toVector_doc},
+ {NULL, NULL, 0, NULL}
+};
+//-----------------------------METHODS----------------------------
+//--------------------------Vector.toPoint()----------------------
+//create a new point object to represent this vector
+PyObject *Point_toVector(PointObject * self)
+{
+ float vec[3];
+ int x;
+
+ for(x = 0; x < self->size; x++){
+ vec[x] = self->coord[x];
+ }
+
+ return newVectorObject(vec, self->size, Py_NEW);
+}
+//----------------------------Point.zero() ----------------------
+//set the point data to 0,0,0
+PyObject *Point_Zero(PointObject * self)
+{
+ int x;
+ for(x = 0; x < self->size; x++) {
+ self->coord[x] = 0.0f;
+ }
+ return EXPP_incr_ret((PyObject*)self);
+}
+//----------------------------dealloc()(internal) ----------------
+//free the py_object
+static void Point_dealloc(PointObject * self)
+{
+ Py_XDECREF(self->coerced_object);
+ //only free py_data
+ if(self->data.py_data){
+ PyMem_Free(self->data.py_data);
+ }
+ PyObject_DEL(self);
+}
+//----------------------------getattr()(internal) ----------------
+//object.attribute access (get)
+static PyObject *Point_getattr(PointObject * self, char *name)
+{
+ if(STREQ(name,"x")){
+ return PyFloat_FromDouble(self->coord[0]);
+ }else if(STREQ(name, "y")){
+ return PyFloat_FromDouble(self->coord[1]);
+ }else if(STREQ(name, "z")){
+ if(self->size > 2){
+ return PyFloat_FromDouble(self->coord[2]);
+ }else{
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "point.z: illegal attribute access\n");
+ }
+ }
+ if(STREQ(name, "wrapped")){
+ if(self->wrapped == Py_WRAP)
+ return EXPP_incr_ret((PyObject *)Py_True);
+ else
+ return EXPP_incr_ret((PyObject *)Py_False);
+ }
+ return Py_FindMethod(Point_methods, (PyObject *) self, name);
+}
+//----------------------------setattr()(internal) ----------------
+//object.attribute access (set)
+static int Point_setattr(PointObject * self, char *name, PyObject * v)
+{
+ PyObject *f = NULL;
+
+ f = PyNumber_Float(v);
+ if(f == NULL) { // parsed item not a number
+ return EXPP_ReturnIntError(PyExc_TypeError,
+ "point.attribute = x: argument not a number\n");
+ }
+
+ if(STREQ(name,"x")){
+ self->coord[0] = (float)PyFloat_AS_DOUBLE(f);
+ }else if(STREQ(name, "y")){
+ self->coord[1] = (float)PyFloat_AS_DOUBLE(f);
+ }else if(STREQ(name, "z")){
+ if(self->size > 2){
+ self->coord[2] = (float)PyFloat_AS_DOUBLE(f);
+ }else{
+ Py_DECREF(f);
+ return EXPP_ReturnIntError(PyExc_AttributeError,
+ "point.z = x: illegal attribute access\n");
+ }
+ }else{
+ Py_DECREF(f);
+ return EXPP_ReturnIntError(PyExc_AttributeError,
+ "point.attribute = x: unknown attribute\n");
+ }
+
+ Py_DECREF(f);
+ return 0;
+}
+//----------------------------print object (internal)-------------
+//print the object to screen
+static PyObject *Point_repr(PointObject * self)
+{
+ int i;
+ char buffer[48], str[1024];
+
+ BLI_strncpy(str,"[",1024);
+ for(i = 0; i < self->size; i++){
+ if(i < (self->size - 1)){
+ sprintf(buffer, "%.6f, ", self->coord[i]);
+ strcat(str,buffer);
+ }else{
+ sprintf(buffer, "%.6f", self->coord[i]);
+ strcat(str,buffer);
+ }
+ }
+ strcat(str, "](point)");
+
+ return PyString_FromString(str);
+}
+//---------------------SEQUENCE PROTOCOLS------------------------
+//----------------------------len(object)------------------------
+//sequence length
+static int Point_len(PointObject * self)
+{
+ return self->size;
+}
+//----------------------------object[]---------------------------
+//sequence accessor (get)
+static PyObject *Point_item(PointObject * self, int i)
+{
+ if(i < 0 || i >= self->size)
+ return EXPP_ReturnPyObjError(PyExc_IndexError,
+ "point[attribute]: array index out of range\n");
+
+ return PyFloat_FromDouble( (double)self->coord[i] );
+
+}
+//----------------------------object[]-------------------------
+//sequence accessor (set)
+static int Point_ass_item(PointObject * self, int i, PyObject * ob)
+{
+ PyObject *f = NULL;
+
+ f = PyNumber_Float(ob);
+ if(f == NULL) { // parsed item not a number
+ return EXPP_ReturnIntError(PyExc_TypeError,
+ "point[attribute] = x: argument not a number\n");
+ }
+
+ if(i < 0 || i >= self->size){
+ Py_DECREF(f);
+ return EXPP_ReturnIntError(PyExc_IndexError,
+ "point[attribute] = x: array assignment index out of range\n");
+ }
+ self->coord[i] = (float)PyFloat_AS_DOUBLE(f);
+ Py_DECREF(f);
+ return 0;
+}
+//----------------------------object[z:y]------------------------
+//sequence slice (get)
+static PyObject *Point_slice(PointObject * self, int begin, int end)
+{
+ PyObject *list = NULL;
+ int count;
+
+ CLAMP(begin, 0, self->size);
+ CLAMP(end, 0, self->size);
+ begin = MIN2(begin,end);
+
+ list = PyList_New(end - begin);
+ for(count = begin; count < end; count++) {
+ PyList_SetItem(list, count - begin,
+ PyFloat_FromDouble(self->coord[count]));
+ }
+
+ return list;
+}
+//----------------------------object[z:y]------------------------
+//sequence slice (set)
+static int Point_ass_slice(PointObject * self, int begin, int end,
+ PyObject * seq)
+{
+ int i, y, size = 0;
+ float coord[3];
+ PyObject *v, *f;
+
+ CLAMP(begin, 0, self->size);
+ CLAMP(end, 0, self->size);
+ begin = MIN2(begin,end);
+
+ size = PySequence_Length(seq);
+ if(size != (end - begin)){
+ return EXPP_ReturnIntError(PyExc_TypeError,
+ "point[begin:end] = []: size mismatch in slice assignment\n");
+ }
+
+ for (i = 0; i < size; i++) {
+ v = PySequence_GetItem(seq, i);
+ if (v == NULL) { // Failed to read sequence
+ return EXPP_ReturnIntError(PyExc_RuntimeError,
+ "point[begin:end] = []: unable to read sequence\n");
+ }
+ f = PyNumber_Float(v);
+ if(f == NULL) { // parsed item not a number
+ Py_DECREF(v);
+ return EXPP_ReturnIntError(PyExc_TypeError,
+ "point[begin:end] = []: sequence argument not a number\n");
+ }
+
+ coord[i] = (float)PyFloat_AS_DOUBLE(f);
+ EXPP_decr2(f,v);
+ }
+ //parsed well - now set in point
+ for(y = 0; y < size; y++){
+ self->coord[begin + y] = coord[y];
+ }
+ return 0;
+}
+//------------------------NUMERIC PROTOCOLS----------------------
+//------------------------obj + obj------------------------------
+//addition
+static PyObject *Point_add(PyObject * v1, PyObject * v2)
+{
+ int x, size;
+ float coord[3];
+ PointObject *coord1 = NULL, *coord2 = NULL;
+ VectorObject *vec = NULL;
+
+ coord1 = (PointObject*)v1;
+ coord2 = (PointObject*)v2;
+
+ if(!coord1->coerced_object){
+ if(coord2->coerced_object){
+ if(VectorObject_Check(coord2->coerced_object)){ //POINT + VECTOR
+ //Point translation
+ vec = (VectorObject*)coord2->coerced_object;
+ size = coord1->size;
+ if(vec->size == size){
+ for(x = 0; x < size; x++){
+ coord[x] = coord1->coord[x] + vec->vec[x];
+ }
+ }else{
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Point addition: arguments are the wrong size....\n");
+ }
+ return newPointObject(coord, size, Py_NEW);
+ }
+ }else{ //POINT + POINT
+ size = coord1->size;
+ if(coord2->size == size){
+ for(x = 0; x < size; x++) {
+ coord[x] = coord1->coord[x] + coord2->coord[x];
+ }
+ }else{
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Point addition: arguments are the wrong size....\n");
+ }
+ return newPointObject(coord, size, Py_NEW);
+ }
+ }
+
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Point addition: arguments not valid for this operation....\n");
+}
+//------------------------obj - obj------------------------------
+//subtraction
+static PyObject *Point_sub(PyObject * v1, PyObject * v2)
+{
+ int x, size;
+ float coord[3];
+ PointObject *coord1 = NULL, *coord2 = NULL;
+
+ coord1 = (PointObject*)v1;
+ coord2 = (PointObject*)v2;
+
+ if(coord1->coerced_object || coord2->coerced_object){
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Point subtraction: arguments not valid for this operation....\n");
+ }
+ if(coord1->size != coord2->size){
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Point subtraction: points must have the same dimensions for this operation\n");
+ }
+
+ size = coord1->size;
+ for(x = 0; x < size; x++) {
+ coord[x] = coord1->coord[x] - coord2->coord[x];
+ }
+
+ //Point - Point = Vector
+ return newVectorObject(coord, size, Py_NEW);
+}
+//------------------------obj * obj------------------------------
+//mulplication
+static PyObject *Point_mul(PyObject * p1, PyObject * p2)
+{
+ int x, size;
+ float coord[3], scalar;
+ PointObject *coord1 = NULL, *coord2 = NULL;
+ PyObject *f = NULL;
+ MatrixObject *mat = NULL;
+ QuaternionObject *quat = NULL;
+
+ coord1 = (PointObject*)p1;
+ coord2 = (PointObject*)p2;
+
+ if(coord1->coerced_object){
+ if (PyFloat_Check(coord1->coerced_object) ||
+ PyInt_Check(coord1->coerced_object)){ // FLOAT/INT * POINT
+ f = PyNumber_Float(coord1->coerced_object);
+ if(f == NULL) { // parsed item not a number
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Point multiplication: arguments not acceptable for this operation\n");
+ }
+
+ scalar = (float)PyFloat_AS_DOUBLE(f);
+ size = coord2->size;
+ for(x = 0; x < size; x++) {
+ coord[x] = coord2->coord[x] * scalar;
+ }
+ Py_DECREF(f);
+ return newPointObject(coord, size, Py_NEW);
+ }
+ }else{
+ if(coord2->coerced_object){
+ if (PyFloat_Check(coord2->coerced_object) ||
+ PyInt_Check(coord2->coerced_object)){ // POINT * FLOAT/INT
+ f = PyNumber_Float(coord2->coerced_object);
+ if(f == NULL) { // parsed item not a number
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Point multiplication: arguments not acceptable for this operation\n");
+ }
+
+ scalar = (float)PyFloat_AS_DOUBLE(f);
+ size = coord1->size;
+ for(x = 0; x < size; x++) {
+ coord[x] = coord1->coord[x] * scalar;
+ }
+ Py_DECREF(f);
+ return newPointObject(coord, size, Py_NEW);
+ }else if(MatrixObject_Check(coord2->coerced_object)){ //POINT * MATRIX
+ mat = (MatrixObject*)coord2->coerced_object;
+ return row_point_multiplication(coord1, mat);
+ }else if(QuaternionObject_Check(coord2->coerced_object)){ //POINT * QUATERNION
+ quat = (QuaternionObject*)coord2->coerced_object;
+ if(coord1->size != 3){
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Point multiplication: only 3D point rotations (with quats) currently supported\n");
+ }
+ return quat_rotation((PyObject*)coord1, (PyObject*)quat);
+ }
+ }
+ }
+
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Point multiplication: arguments not acceptable for this operation\n");
+}
+//-------------------------- -obj -------------------------------
+//returns the negative of this object
+static PyObject *Point_neg(PointObject *self)
+{
+ int x;
+ float coord[3];
+
+ for(x = 0; x < self->size; x++)
+ coord[x] = -self->coord[x];
+
+ return newPointObject(coord, self->size, Py_NEW);
+}
+
+//------------------------coerce(obj, obj)-----------------------
+//coercion of unknown types to type PointObject for numeric protocols
+/*Coercion() is called whenever a math operation has 2 operands that
+ it doesn't understand how to evaluate. 2+Matrix for example. We want to
+ evaluate some of these operations like: (vector * 2), however, for math
+ to proceed, the unknown operand must be cast to a type that python math will
+ understand. (e.g. in the case above case, 2 must be cast to a vector and
+ then call vector.multiply(vector, scalar_cast_as_vector)*/
+static int Point_coerce(PyObject ** p1, PyObject ** p2)
+{
+ if(VectorObject_Check(*p2) || PyFloat_Check(*p2) || PyInt_Check(*p2) ||
+ MatrixObject_Check(*p2) || QuaternionObject_Check(*p2)) {
+ PyObject *coerced = EXPP_incr_ret(*p2);
+ *p2 = newPointObject(NULL,3,Py_NEW);
+ ((PointObject*)*p2)->coerced_object = coerced;
+ Py_INCREF (*p1);
+ return 0;
+ }
+
+ return EXPP_ReturnIntError(PyExc_TypeError,
+ "point.coerce(): unknown operand - can't coerce for numeric protocols");
+}
+//-----------------PROTOCOL DECLARATIONS--------------------------
+static PySequenceMethods Point_SeqMethods = {
+ (inquiry) Point_len, /* sq_length */
+ (binaryfunc) 0, /* sq_concat */
+ (intargfunc) 0, /* sq_repeat */
+ (intargfunc) Point_item, /* sq_item */
+ (intintargfunc) Point_slice, /* sq_slice */
+ (intobjargproc) Point_ass_item, /* sq_ass_item */
+ (intintobjargproc) Point_ass_slice, /* sq_ass_slice */
+};
+static PyNumberMethods Point_NumMethods = {
+ (binaryfunc) Point_add, /* __add__ */
+ (binaryfunc) Point_sub, /* __sub__ */
+ (binaryfunc) Point_mul, /* __mul__ */
+ (binaryfunc) 0, /* __div__ */
+ (binaryfunc) 0, /* __mod__ */
+ (binaryfunc) 0, /* __divmod__ */
+ (ternaryfunc) 0, /* __pow__ */
+ (unaryfunc) Point_neg, /* __neg__ */
+ (unaryfunc) 0, /* __pos__ */
+ (unaryfunc) 0, /* __abs__ */
+ (inquiry) 0, /* __nonzero__ */
+ (unaryfunc) 0, /* __invert__ */
+ (binaryfunc) 0, /* __lshift__ */
+ (binaryfunc) 0, /* __rshift__ */
+ (binaryfunc) 0, /* __and__ */
+ (binaryfunc) 0, /* __xor__ */
+ (binaryfunc) 0, /* __or__ */
+ (coercion) Point_coerce, /* __coerce__ */
+ (unaryfunc) 0, /* __int__ */
+ (unaryfunc) 0, /* __long__ */
+ (unaryfunc) 0, /* __float__ */
+ (unaryfunc) 0, /* __oct__ */
+ (unaryfunc) 0, /* __hex__ */
+
+};
+//------------------PY_OBECT DEFINITION--------------------------
+PyTypeObject point_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /*ob_size */
+ "point", /*tp_name */
+ sizeof(PointObject), /*tp_basicsize */
+ 0, /*tp_itemsize */
+ (destructor) Point_dealloc, /*tp_dealloc */
+ (printfunc) 0, /*tp_print */
+ (getattrfunc) Point_getattr, /*tp_getattr */
+ (setattrfunc) Point_setattr, /*tp_setattr */
+ 0, /*tp_compare */
+ (reprfunc) Point_repr, /*tp_repr */
+ &Point_NumMethods, /*tp_as_number */
+ &Point_SeqMethods, /*tp_as_sequence */
+};
+//------------------------newPointObject (internal)-------------
+//creates a new point object
+/*pass Py_WRAP - if point is a WRAPPER for data allocated by BLENDER
+ (i.e. it was allocated elsewhere by MEM_mallocN())
+ pass Py_NEW - if point is not a WRAPPER and managed by PYTHON
+ (i.e. it must be created here with PyMEM_malloc())*/
+PyObject *newPointObject(float *coord, int size, int type)
+{
+ PointObject *self;
+ int x;
+
+ point_Type.ob_type = &PyType_Type;
+ self = PyObject_NEW(PointObject, &point_Type);
+ self->data.blend_data = NULL;
+ self->data.py_data = NULL;
+ if(size > 3 || size < 2)
+ return NULL;
+ self->size = size;
+ self->coerced_object = NULL;
+
+ if(type == Py_WRAP){
+ self->data.blend_data = coord;
+ self->coord = self->data.blend_data;
+ self->wrapped = Py_WRAP;
+ }else if (type == Py_NEW){
+ self->data.py_data = PyMem_Malloc(size * sizeof(float));
+ self->coord = self->data.py_data;
+ if(!coord) { //new empty
+ for(x = 0; x < size; x++){
+ self->coord[x] = 0.0f;
+ }
+ }else{
+ for(x = 0; x < size; x++){
+ self->coord[x] = coord[x];
+ }
+ }
+ self->wrapped = Py_NEW;
+ }else{ //bad type
+ return NULL;
+ }
+ return (PyObject *) self;
+}
diff --git a/source/blender/python/api2_2x/point.h b/source/blender/python/api2_2x/point.h
new file mode 100644
index 00000000000..0ea8cb1fe6e
--- /dev/null
+++ b/source/blender/python/api2_2x/point.h
@@ -0,0 +1,67 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Joseph Gilbert
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_point_h
+#define EXPP_point_h
+
+#include <Python.h>
+
+extern PyTypeObject point_Type;
+
+#define PointObject_Check(v) ((v)->ob_type == &point_Type)
+
+typedef struct {
+ PyObject_VAR_HEAD
+ struct{
+ float *py_data; //python managed
+ float *blend_data; //blender managed
+ }data;
+ float *coord; //1D array of data (alias)
+ int size;
+ int wrapped; //is wrapped data?
+ PyObject *coerced_object;
+} PointObject;
+/*coerced_object is a pointer to the object that it was
+coerced from when a dummy vector needs to be created from
+the coerce() function for numeric protocol operations*/
+
+/*struct data contains a pointer to the actual data that the
+object uses. It can use either PyMem allocated data (which will
+be stored in py_data) or be a wrapper for data allocated through
+blender (stored in blend_data). This is an either/or struct not both*/
+
+//prototypes
+PyObject *Point_Zero( PointObject * self );
+PyObject *Point_toVector(PointObject * self);
+PyObject *newPointObject(float *coord, int size, int type);
+
+#endif /* EXPP_point_h */
diff --git a/source/blender/python/api2_2x/quat.c b/source/blender/python/api2_2x/quat.c
new file mode 100644
index 00000000000..3793db47686
--- /dev/null
+++ b/source/blender/python/api2_2x/quat.c
@@ -0,0 +1,668 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Joseph Gilbert
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "Mathutils.h"
+
+#include "BLI_arithb.h"
+#include "BKE_utildefines.h"
+#include "BLI_blenlib.h"
+#include "gen_utils.h"
+
+
+//-------------------------DOC STRINGS ---------------------------
+char Quaternion_Identity_doc[] = "() - set the quaternion to it's identity (1, vector)";
+char Quaternion_Negate_doc[] = "() - set all values in the quaternion to their negative";
+char Quaternion_Conjugate_doc[] = "() - set the quaternion to it's conjugate";
+char Quaternion_Inverse_doc[] = "() - set the quaternion to it's inverse";
+char Quaternion_Normalize_doc[] = "() - normalize the vector portion of the quaternion";
+char Quaternion_ToEuler_doc[] = "() - return a euler rotation representing the quaternion";
+char Quaternion_ToMatrix_doc[] = "() - return a rotation matrix representing the quaternion";
+char Quaternion_copy_doc[] = "() - return a copy of the quat";
+//-----------------------METHOD DEFINITIONS ----------------------
+struct PyMethodDef Quaternion_methods[] = {
+ {"identity", (PyCFunction) Quaternion_Identity, METH_NOARGS, Quaternion_Identity_doc},
+ {"negate", (PyCFunction) Quaternion_Negate, METH_NOARGS, Quaternion_Negate_doc},
+ {"conjugate", (PyCFunction) Quaternion_Conjugate, METH_NOARGS, Quaternion_Conjugate_doc},
+ {"inverse", (PyCFunction) Quaternion_Inverse, METH_NOARGS, Quaternion_Inverse_doc},
+ {"normalize", (PyCFunction) Quaternion_Normalize, METH_NOARGS, Quaternion_Normalize_doc},
+ {"toEuler", (PyCFunction) Quaternion_ToEuler, METH_NOARGS, Quaternion_ToEuler_doc},
+ {"toMatrix", (PyCFunction) Quaternion_ToMatrix, METH_NOARGS, Quaternion_ToMatrix_doc},
+ {"__copy__", (PyCFunction) Quaternion_copy, METH_NOARGS, Quaternion_copy_doc},
+ {"copy", (PyCFunction) Quaternion_copy, METH_NOARGS, Quaternion_copy_doc},
+ {NULL, NULL, 0, NULL}
+};
+//-----------------------------METHODS------------------------------
+//----------------------------Quaternion.toEuler()------------------
+//return the quat as a euler
+PyObject *Quaternion_ToEuler(QuaternionObject * self)
+{
+ float eul[3];
+ int x;
+
+ QuatToEul(self->quat, eul);
+ for(x = 0; x < 3; x++) {
+ eul[x] *= (180 / (float)Py_PI);
+ }
+ return newEulerObject(eul, Py_NEW);
+}
+//----------------------------Quaternion.toMatrix()------------------
+//return the quat as a matrix
+PyObject *Quaternion_ToMatrix(QuaternionObject * self)
+{
+ float mat[9] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
+ QuatToMat3(self->quat, (float (*)[3]) mat);
+
+ return newMatrixObject(mat, 3, 3, Py_NEW);
+}
+//----------------------------Quaternion.normalize()----------------
+//normalize the axis of rotation of [theta,vector]
+PyObject *Quaternion_Normalize(QuaternionObject * self)
+{
+ NormalQuat(self->quat);
+ return EXPP_incr_ret((PyObject*)self);
+}
+//----------------------------Quaternion.inverse()------------------
+//invert the quat
+PyObject *Quaternion_Inverse(QuaternionObject * self)
+{
+ double mag = 0.0f;
+ int x;
+
+ for(x = 1; x < 4; x++) {
+ self->quat[x] = -self->quat[x];
+ }
+ for(x = 0; x < 4; x++) {
+ mag += (self->quat[x] * self->quat[x]);
+ }
+ mag = sqrt(mag);
+ for(x = 0; x < 4; x++) {
+ self->quat[x] /= (float)(mag * mag);
+ }
+
+ return EXPP_incr_ret((PyObject*)self);
+}
+//----------------------------Quaternion.identity()-----------------
+//generate the identity quaternion
+PyObject *Quaternion_Identity(QuaternionObject * self)
+{
+ self->quat[0] = 1.0;
+ self->quat[1] = 0.0;
+ self->quat[2] = 0.0;
+ self->quat[3] = 0.0;
+
+ return EXPP_incr_ret((PyObject*)self);
+}
+//----------------------------Quaternion.negate()-------------------
+//negate the quat
+PyObject *Quaternion_Negate(QuaternionObject * self)
+{
+ int x;
+ for(x = 0; x < 4; x++) {
+ self->quat[x] = -self->quat[x];
+ }
+ return EXPP_incr_ret((PyObject*)self);
+}
+//----------------------------Quaternion.conjugate()----------------
+//negate the vector part
+PyObject *Quaternion_Conjugate(QuaternionObject * self)
+{
+ int x;
+ for(x = 1; x < 4; x++) {
+ self->quat[x] = -self->quat[x];
+ }
+ return EXPP_incr_ret((PyObject*)self);
+}
+//----------------------------Quaternion.copy()----------------
+//return a copy of the quat
+PyObject *Quaternion_copy(QuaternionObject * self)
+{
+ return newQuaternionObject(self->quat, Py_NEW);
+}
+
+//----------------------------dealloc()(internal) ------------------
+//free the py_object
+static void Quaternion_dealloc(QuaternionObject * self)
+{
+ Py_XDECREF(self->coerced_object);
+ //only free py_data
+ if(self->data.py_data){
+ PyMem_Free(self->data.py_data);
+ }
+ PyObject_DEL(self);
+}
+//----------------------------getattr()(internal) ------------------
+//object.attribute access (get)
+static PyObject *Quaternion_getattr(QuaternionObject * self, char *name)
+{
+ int x;
+ double mag = 0.0f;
+ float vec[3];
+
+ if(STREQ(name,"w")){
+ return PyFloat_FromDouble(self->quat[0]);
+ }else if(STREQ(name, "x")){
+ return PyFloat_FromDouble(self->quat[1]);
+ }else if(STREQ(name, "y")){
+ return PyFloat_FromDouble(self->quat[2]);
+ }else if(STREQ(name, "z")){
+ return PyFloat_FromDouble(self->quat[3]);
+ }
+ if(STREQ(name, "magnitude")) {
+ for(x = 0; x < 4; x++) {
+ mag += self->quat[x] * self->quat[x];
+ }
+ mag = sqrt(mag);
+ return PyFloat_FromDouble(mag);
+ }
+ if(STREQ(name, "angle")) {
+ mag = self->quat[0];
+ mag = 2 * (acos(mag));
+ mag *= (180 / Py_PI);
+ return PyFloat_FromDouble(mag);
+ }
+ if(STREQ(name, "axis")) {
+ mag = self->quat[0] * (Py_PI / 180);
+ mag = 2 * (acos(mag));
+ mag = sin(mag / 2);
+ for(x = 0; x < 3; x++) {
+ vec[x] = (float)(self->quat[x + 1] / mag);
+ }
+ Normalize(vec);
+ //If the axis of rotation is 0,0,0 set it to 1,0,0 - for zero-degree rotations
+ if( EXPP_FloatsAreEqual(vec[0], 0.0f, 10) &&
+ EXPP_FloatsAreEqual(vec[1], 0.0f, 10) &&
+ EXPP_FloatsAreEqual(vec[2], 0.0f, 10) ){
+ vec[0] = 1.0f;
+ }
+ return (PyObject *) newVectorObject(vec, 3, Py_NEW);
+ }
+ if(STREQ(name, "wrapped")){
+ if(self->wrapped == Py_WRAP)
+ return EXPP_incr_ret((PyObject *)Py_True);
+ else
+ return EXPP_incr_ret((PyObject *)Py_False);
+ }
+
+ return Py_FindMethod(Quaternion_methods, (PyObject *) self, name);
+}
+//----------------------------setattr()(internal) ------------------
+//object.attribute access (set)
+static int Quaternion_setattr(QuaternionObject * self, char *name, PyObject * q)
+{
+ PyObject *f = NULL;
+
+ f = PyNumber_Float(q);
+ if(f == NULL) { // parsed item not a number
+ return EXPP_ReturnIntError(PyExc_TypeError,
+ "quaternion.attribute = x: argument not a number\n");
+ }
+
+ if(STREQ(name,"w")){
+ self->quat[0] = (float)PyFloat_AS_DOUBLE(f);
+ }else if(STREQ(name, "x")){
+ self->quat[1] = (float)PyFloat_AS_DOUBLE(f);
+ }else if(STREQ(name, "y")){
+ self->quat[2] = (float)PyFloat_AS_DOUBLE(f);
+ }else if(STREQ(name, "z")){
+ self->quat[3] = (float)PyFloat_AS_DOUBLE(f);
+ }else{
+ Py_DECREF(f);
+ return EXPP_ReturnIntError(PyExc_AttributeError,
+ "quaternion.attribute = x: unknown attribute\n");
+ }
+
+ Py_DECREF(f);
+ return 0;
+}
+//----------------------------print object (internal)--------------
+//print the object to screen
+static PyObject *Quaternion_repr(QuaternionObject * self)
+{
+ int i;
+ char buffer[48], str[1024];
+
+ BLI_strncpy(str,"[",1024);
+ for(i = 0; i < 4; i++){
+ if(i < (3)){
+ sprintf(buffer, "%.6f, ", self->quat[i]);
+ strcat(str,buffer);
+ }else{
+ sprintf(buffer, "%.6f", self->quat[i]);
+ strcat(str,buffer);
+ }
+ }
+ strcat(str, "](quaternion)");
+
+ return PyString_FromString(str);
+}
+//------------------------tp_richcmpr
+//returns -1 execption, 0 false, 1 true
+static PyObject* Quaternion_richcmpr(PyObject *objectA, PyObject *objectB, int comparison_type)
+{
+ QuaternionObject *quatA = NULL, *quatB = NULL;
+ int result = 0;
+
+ if (!QuaternionObject_Check(objectA) || !QuaternionObject_Check(objectB)){
+ if (comparison_type == Py_NE){
+ return EXPP_incr_ret(Py_True);
+ }else{
+ return EXPP_incr_ret(Py_False);
+ }
+ }
+ quatA = (QuaternionObject*)objectA;
+ quatB = (QuaternionObject*)objectB;
+
+ switch (comparison_type){
+ case Py_EQ:
+ result = EXPP_VectorsAreEqual(quatA->quat, quatB->quat, 4, 1);
+ break;
+ case Py_NE:
+ result = EXPP_VectorsAreEqual(quatA->quat, quatB->quat, 4, 1);
+ if (result == 0){
+ result = 1;
+ }else{
+ result = 0;
+ }
+ break;
+ default:
+ printf("The result of the comparison could not be evaluated");
+ break;
+ }
+ if (result == 1){
+ return EXPP_incr_ret(Py_True);
+ }else{
+ return EXPP_incr_ret(Py_False);
+ }
+}
+//------------------------tp_doc
+static char QuaternionObject_doc[] = "This is a wrapper for quaternion objects.";
+//---------------------SEQUENCE PROTOCOLS------------------------
+//----------------------------len(object)------------------------
+//sequence length
+static int Quaternion_len(QuaternionObject * self)
+{
+ return 4;
+}
+//----------------------------object[]---------------------------
+//sequence accessor (get)
+static PyObject *Quaternion_item(QuaternionObject * self, int i)
+{
+ if(i < 0 || i >= 4)
+ return EXPP_ReturnPyObjError(PyExc_IndexError,
+ "quaternion[attribute]: array index out of range\n");
+ return PyFloat_FromDouble(self->quat[i]);
+
+}
+//----------------------------object[]-------------------------
+//sequence accessor (set)
+static int Quaternion_ass_item(QuaternionObject * self, int i, PyObject * ob)
+{
+ PyObject *f = NULL;
+
+ f = PyNumber_Float(ob);
+ if(f == NULL) { // parsed item not a number
+ return EXPP_ReturnIntError(PyExc_TypeError,
+ "quaternion[attribute] = x: argument not a number\n");
+ }
+
+ if(i < 0 || i >= 4){
+ Py_DECREF(f);
+ return EXPP_ReturnIntError(PyExc_IndexError,
+ "quaternion[attribute] = x: array assignment index out of range\n");
+ }
+ self->quat[i] = (float)PyFloat_AS_DOUBLE(f);
+ Py_DECREF(f);
+ return 0;
+}
+//----------------------------object[z:y]------------------------
+//sequence slice (get)
+static PyObject *Quaternion_slice(QuaternionObject * self, int begin, int end)
+{
+ PyObject *list = NULL;
+ int count;
+
+ CLAMP(begin, 0, 4);
+ if (end<0) end= 5+end;
+ CLAMP(end, 0, 4);
+ begin = MIN2(begin,end);
+
+ list = PyList_New(end - begin);
+ for(count = begin; count < end; count++) {
+ PyList_SetItem(list, count - begin,
+ PyFloat_FromDouble(self->quat[count]));
+ }
+
+ return list;
+}
+//----------------------------object[z:y]------------------------
+//sequence slice (set)
+static int Quaternion_ass_slice(QuaternionObject * self, int begin, int end,
+ PyObject * seq)
+{
+ int i, y, size = 0;
+ float quat[4];
+ PyObject *q, *f;
+
+ CLAMP(begin, 0, 4);
+ if (end<0) end= 5+end;
+ CLAMP(end, 0, 4);
+ begin = MIN2(begin,end);
+
+ size = PySequence_Length(seq);
+ if(size != (end - begin)){
+ return EXPP_ReturnIntError(PyExc_TypeError,
+ "quaternion[begin:end] = []: size mismatch in slice assignment\n");
+ }
+
+ for (i = 0; i < size; i++) {
+ q = PySequence_GetItem(seq, i);
+ if (q == NULL) { // Failed to read sequence
+ return EXPP_ReturnIntError(PyExc_RuntimeError,
+ "quaternion[begin:end] = []: unable to read sequence\n");
+ }
+
+ f = PyNumber_Float(q);
+ if(f == NULL) { // parsed item not a number
+ Py_DECREF(q);
+ return EXPP_ReturnIntError(PyExc_TypeError,
+ "quaternion[begin:end] = []: sequence argument not a number\n");
+ }
+
+ quat[i] = (float)PyFloat_AS_DOUBLE(f);
+ EXPP_decr2(f,q);
+ }
+ //parsed well - now set in vector
+ for(y = 0; y < size; y++){
+ self->quat[begin + y] = quat[y];
+ }
+ return 0;
+}
+//------------------------NUMERIC PROTOCOLS----------------------
+//------------------------obj + obj------------------------------
+//addition
+static PyObject *Quaternion_add(PyObject * q1, PyObject * q2)
+{
+ int x;
+ float quat[4];
+ QuaternionObject *quat1 = NULL, *quat2 = NULL;
+
+ quat1 = (QuaternionObject*)q1;
+ quat2 = (QuaternionObject*)q2;
+
+ if(quat1->coerced_object || quat2->coerced_object){
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Quaternion addition: arguments not valid for this operation....\n");
+ }
+ for(x = 0; x < 4; x++) {
+ quat[x] = quat1->quat[x] + quat2->quat[x];
+ }
+
+ return newQuaternionObject(quat, Py_NEW);
+}
+//------------------------obj - obj------------------------------
+//subtraction
+static PyObject *Quaternion_sub(PyObject * q1, PyObject * q2)
+{
+ int x;
+ float quat[4];
+ QuaternionObject *quat1 = NULL, *quat2 = NULL;
+
+ quat1 = (QuaternionObject*)q1;
+ quat2 = (QuaternionObject*)q2;
+
+ if(quat1->coerced_object || quat2->coerced_object){
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Quaternion addition: arguments not valid for this operation....\n");
+ }
+ for(x = 0; x < 4; x++) {
+ quat[x] = quat1->quat[x] - quat2->quat[x];
+ }
+
+ return newQuaternionObject(quat, Py_NEW);
+}
+//------------------------obj * obj------------------------------
+//mulplication
+static PyObject *Quaternion_mul(PyObject * q1, PyObject * q2)
+{
+ int x;
+ float quat[4], scalar;
+ double dot = 0.0f;
+ QuaternionObject *quat1 = NULL, *quat2 = NULL;
+ PyObject *f = NULL;
+ VectorObject *vec = NULL;
+ PointObject *pt = NULL;
+
+ quat1 = (QuaternionObject*)q1;
+ quat2 = (QuaternionObject*)q2;
+
+ if(quat1->coerced_object){
+ if (PyFloat_Check(quat1->coerced_object) ||
+ PyInt_Check(quat1->coerced_object)){ // FLOAT/INT * QUAT
+ f = PyNumber_Float(quat1->coerced_object);
+ if(f == NULL) { // parsed item not a number
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Quaternion multiplication: arguments not acceptable for this operation\n");
+ }
+
+ scalar = (float)PyFloat_AS_DOUBLE(f);
+ Py_DECREF(f);
+ for(x = 0; x < 4; x++) {
+ quat[x] = quat2->quat[x] * scalar;
+ }
+ return newQuaternionObject(quat, Py_NEW);
+ }
+ }else{
+ if(quat2->coerced_object){
+ if (PyFloat_Check(quat2->coerced_object) ||
+ PyInt_Check(quat2->coerced_object)){ // QUAT * FLOAT/INT
+ f = PyNumber_Float(quat2->coerced_object);
+ if(f == NULL) { // parsed item not a number
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Quaternion multiplication: arguments not acceptable for this operation\n");
+ }
+
+ scalar = (float)PyFloat_AS_DOUBLE(f);
+ Py_DECREF(f);
+ for(x = 0; x < 4; x++) {
+ quat[x] = quat1->quat[x] * scalar;
+ }
+ return newQuaternionObject(quat, Py_NEW);
+ }else if(VectorObject_Check(quat2->coerced_object)){ //QUAT * VEC
+ vec = (VectorObject*)quat2->coerced_object;
+ if(vec->size != 3){
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Quaternion multiplication: only 3D vector rotations currently supported\n");
+ }
+ return quat_rotation((PyObject*)quat1, (PyObject*)vec);
+ }else if(PointObject_Check(quat2->coerced_object)){ //QUAT * POINT
+ pt = (PointObject*)quat2->coerced_object;
+ if(pt->size != 3){
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Quaternion multiplication: only 3D point rotations currently supported\n");
+ }
+ return quat_rotation((PyObject*)quat1, (PyObject*)pt);
+ }
+ }else{ //QUAT * QUAT (dot product)
+ for(x = 0; x < 4; x++) {
+ dot += quat1->quat[x] * quat1->quat[x];
+ }
+ return PyFloat_FromDouble(dot);
+ }
+ }
+
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Quaternion multiplication: arguments not acceptable for this operation\n");
+}
+//------------------------coerce(obj, obj)-----------------------
+//coercion of unknown types to type QuaternionObject for numeric protocols
+/*Coercion() is called whenever a math operation has 2 operands that
+ it doesn't understand how to evaluate. 2+Matrix for example. We want to
+ evaluate some of these operations like: (vector * 2), however, for math
+ to proceed, the unknown operand must be cast to a type that python math will
+ understand. (e.g. in the case above case, 2 must be cast to a vector and
+ then call vector.multiply(vector, scalar_cast_as_vector)*/
+static int Quaternion_coerce(PyObject ** q1, PyObject ** q2)
+{
+ if(VectorObject_Check(*q2) || PyFloat_Check(*q2) || PyInt_Check(*q2) ||
+ PointObject_Check(*q2)) {
+ PyObject *coerced = EXPP_incr_ret(*q2);
+ *q2 = newQuaternionObject(NULL,Py_NEW);
+ ((QuaternionObject*)*q2)->coerced_object = coerced;
+ Py_INCREF (*q1);
+ return 0;
+ }
+
+ return EXPP_ReturnIntError(PyExc_TypeError,
+ "quaternion.coerce(): unknown operand - can't coerce for numeric protocols");
+}
+//-----------------PROTOCOL DECLARATIONS--------------------------
+static PySequenceMethods Quaternion_SeqMethods = {
+ (inquiry) Quaternion_len, /* sq_length */
+ (binaryfunc) 0, /* sq_concat */
+ (intargfunc) 0, /* sq_repeat */
+ (intargfunc) Quaternion_item, /* sq_item */
+ (intintargfunc) Quaternion_slice, /* sq_slice */
+ (intobjargproc) Quaternion_ass_item, /* sq_ass_item */
+ (intintobjargproc) Quaternion_ass_slice, /* sq_ass_slice */
+};
+static PyNumberMethods Quaternion_NumMethods = {
+ (binaryfunc) Quaternion_add, /* __add__ */
+ (binaryfunc) Quaternion_sub, /* __sub__ */
+ (binaryfunc) Quaternion_mul, /* __mul__ */
+ (binaryfunc) 0, /* __div__ */
+ (binaryfunc) 0, /* __mod__ */
+ (binaryfunc) 0, /* __divmod__ */
+ (ternaryfunc) 0, /* __pow__ */
+ (unaryfunc) 0, /* __neg__ */
+ (unaryfunc) 0, /* __pos__ */
+ (unaryfunc) 0, /* __abs__ */
+ (inquiry) 0, /* __nonzero__ */
+ (unaryfunc) 0, /* __invert__ */
+ (binaryfunc) 0, /* __lshift__ */
+ (binaryfunc) 0, /* __rshift__ */
+ (binaryfunc) 0, /* __and__ */
+ (binaryfunc) 0, /* __xor__ */
+ (binaryfunc) 0, /* __or__ */
+ (coercion) Quaternion_coerce, /* __coerce__ */
+ (unaryfunc) 0, /* __int__ */
+ (unaryfunc) 0, /* __long__ */
+ (unaryfunc) 0, /* __float__ */
+ (unaryfunc) 0, /* __oct__ */
+ (unaryfunc) 0, /* __hex__ */
+
+};
+//------------------PY_OBECT DEFINITION--------------------------
+PyTypeObject quaternion_Type = {
+PyObject_HEAD_INIT(NULL) //tp_head
+ 0, //tp_internal
+ "quaternion", //tp_name
+ sizeof(QuaternionObject), //tp_basicsize
+ 0, //tp_itemsize
+ (destructor)Quaternion_dealloc, //tp_dealloc
+ 0, //tp_print
+ (getattrfunc)Quaternion_getattr, //tp_getattr
+ (setattrfunc) Quaternion_setattr, //tp_setattr
+ 0, //tp_compare
+ (reprfunc) Quaternion_repr, //tp_repr
+ &Quaternion_NumMethods, //tp_as_number
+ &Quaternion_SeqMethods, //tp_as_sequence
+ 0, //tp_as_mapping
+ 0, //tp_hash
+ 0, //tp_call
+ 0, //tp_str
+ 0, //tp_getattro
+ 0, //tp_setattro
+ 0, //tp_as_buffer
+ Py_TPFLAGS_DEFAULT, //tp_flags
+ QuaternionObject_doc, //tp_doc
+ 0, //tp_traverse
+ 0, //tp_clear
+ (richcmpfunc)Quaternion_richcmpr, //tp_richcompare
+ 0, //tp_weaklistoffset
+ 0, //tp_iter
+ 0, //tp_iternext
+ 0, //tp_methods
+ 0, //tp_members
+ 0, //tp_getset
+ 0, //tp_base
+ 0, //tp_dict
+ 0, //tp_descr_get
+ 0, //tp_descr_set
+ 0, //tp_dictoffset
+ 0, //tp_init
+ 0, //tp_alloc
+ 0, //tp_new
+ 0, //tp_free
+ 0, //tp_is_gc
+ 0, //tp_bases
+ 0, //tp_mro
+ 0, //tp_cache
+ 0, //tp_subclasses
+ 0, //tp_weaklist
+ 0 //tp_del
+};
+//------------------------newQuaternionObject (internal)-------------
+//creates a new quaternion object
+/*pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER
+ (i.e. it was allocated elsewhere by MEM_mallocN())
+ pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON
+ (i.e. it must be created here with PyMEM_malloc())*/
+PyObject *newQuaternionObject(float *quat, int type)
+{
+ QuaternionObject *self;
+ int x;
+
+ self = PyObject_NEW(QuaternionObject, &quaternion_Type);
+ self->data.blend_data = NULL;
+ self->data.py_data = NULL;
+ self->coerced_object = NULL;
+
+ if(type == Py_WRAP){
+ self->data.blend_data = quat;
+ self->quat = self->data.blend_data;
+ self->wrapped = Py_WRAP;
+ }else if (type == Py_NEW){
+ self->data.py_data = PyMem_Malloc(4 * sizeof(float));
+ self->quat = self->data.py_data;
+ if(!quat) { //new empty
+ Quaternion_Identity(self);
+ Py_DECREF(self);
+ }else{
+ for(x = 0; x < 4; x++){
+ self->quat[x] = quat[x];
+ }
+ }
+ self->wrapped = Py_NEW;
+ }else{ //bad type
+ return NULL;
+ }
+ return (PyObject *) self;
+}
diff --git a/source/blender/python/api2_2x/quat.h b/source/blender/python/api2_2x/quat.h
new file mode 100644
index 00000000000..2e5f6788b2e
--- /dev/null
+++ b/source/blender/python/api2_2x/quat.h
@@ -0,0 +1,73 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Joseph Gilbert
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ *
+ */
+
+#ifndef EXPP_quat_h
+#define EXPP_quat_h
+
+#include <Python.h>
+
+extern PyTypeObject quaternion_Type;
+
+#define QuaternionObject_Check(v) ((v)->ob_type == &quaternion_Type)
+
+typedef struct {
+ PyObject_VAR_HEAD
+ struct{
+ float *py_data; //python managed
+ float *blend_data; //blender managed
+ }data;
+ float *quat; //1D array of data (alias)
+ int wrapped; //is wrapped data?
+ PyObject *coerced_object;
+} QuaternionObject;
+/*coerced_object is a pointer to the object that it was
+coerced from when a dummy vector needs to be created from
+the coerce() function for numeric protocol operations*/
+
+/*struct data contains a pointer to the actual data that the
+object uses. It can use either PyMem allocated data (which will
+be stored in py_data) or be a wrapper for data allocated through
+blender (stored in blend_data). This is an either/or struct not both*/
+
+//prototypes
+PyObject *Quaternion_Identity( QuaternionObject * self );
+PyObject *Quaternion_Negate( QuaternionObject * self );
+PyObject *Quaternion_Conjugate( QuaternionObject * self );
+PyObject *Quaternion_Inverse( QuaternionObject * self );
+PyObject *Quaternion_Normalize( QuaternionObject * self );
+PyObject *Quaternion_ToEuler( QuaternionObject * self );
+PyObject *Quaternion_ToMatrix( QuaternionObject * self );
+PyObject *Quaternion_copy( QuaternionObject * self );
+PyObject *newQuaternionObject( float *quat, int type );
+
+#endif /* EXPP_quat_h */
diff --git a/source/blender/python/api2_2x/rgbTuple.c b/source/blender/python/api2_2x/rgbTuple.c
new file mode 100644
index 00000000000..d8bfd930752
--- /dev/null
+++ b/source/blender/python/api2_2x/rgbTuple.c
@@ -0,0 +1,420 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#include "rgbTuple.h" /*This must come first */
+
+#include "gen_utils.h"
+
+/* This file is heavily based on the old bpython Constant object code in
+ Blender */
+
+/*****************************************************************************/
+/* Python rgbTuple_Type callback function prototypes: */
+/*****************************************************************************/
+static PyObject *rgbTuple_getAttr( BPy_rgbTuple * self, char *name );
+static int rgbTuple_setAttr( BPy_rgbTuple * self, char *name, PyObject * v );
+static PyObject *rgbTuple_repr( BPy_rgbTuple * self );
+
+static int rgbTupleLength( void );
+
+static PyObject *rgbTupleSubscript( BPy_rgbTuple * self, PyObject * key );
+static int rgbTupleAssSubscript( BPy_rgbTuple * self, PyObject * who,
+ PyObject * cares );
+
+static PyObject *rgbTupleItem( BPy_rgbTuple * self, int i );
+static int rgbTupleAssItem( BPy_rgbTuple * self, int i, PyObject * ob );
+static PyObject *rgbTupleSlice( BPy_rgbTuple * self, int begin, int end );
+static int rgbTupleAssSlice( BPy_rgbTuple * self, int begin, int end,
+ PyObject * seq );
+
+/*****************************************************************************/
+/* Python rgbTuple_Type Mapping Methods table: */
+/*****************************************************************************/
+static PyMappingMethods rgbTupleAsMapping = {
+ ( inquiry ) rgbTupleLength, /* mp_length */
+ ( binaryfunc ) rgbTupleSubscript, /* mp_subscript */
+ ( objobjargproc ) rgbTupleAssSubscript, /* mp_ass_subscript */
+};
+
+/*****************************************************************************/
+/* Python rgbTuple_Type Sequence Methods table: */
+/*****************************************************************************/
+static PySequenceMethods rgbTupleAsSequence = {
+ ( inquiry ) rgbTupleLength, /* sq_length */
+ ( binaryfunc ) 0, /* sq_concat */
+ ( intargfunc ) 0, /* sq_repeat */
+ ( intargfunc ) rgbTupleItem, /* sq_item */
+ ( intintargfunc ) rgbTupleSlice, /* sq_slice */
+ ( intobjargproc ) rgbTupleAssItem, /* sq_ass_item */
+ ( intintobjargproc ) rgbTupleAssSlice, /* sq_ass_slice */
+ 0,0,0
+};
+
+/*****************************************************************************/
+/* Python rgbTuple_Type structure definition: */
+/*****************************************************************************/
+PyTypeObject rgbTuple_Type = {
+ PyObject_HEAD_INIT( NULL )
+ 0, /* ob_size */
+ "rgbTuple", /* tp_name */
+ sizeof( BPy_rgbTuple ), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ /* methods */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ ( getattrfunc ) rgbTuple_getAttr, /* tp_getattr */
+ ( setattrfunc ) rgbTuple_setAttr, /* tp_setattr */
+ 0, /* tp_compare */
+ ( reprfunc ) rgbTuple_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ &rgbTupleAsSequence, /* tp_as_sequence */
+ &rgbTupleAsMapping, /* tp_as_mapping */
+ 0, /* tp_as_hash */
+ 0, 0, 0, 0, 0, Py_TPFLAGS_DEFAULT,
+ 0, /* tp_doc */
+ 0, 0, 0, 0, 0, 0,
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* struct PyGetSetDef *tp_getset; */
+ 0, /* struct _typeobject *tp_base; */
+ 0, /* PyObject *tp_dict; */
+ 0, /* descrgetfunc tp_descr_get; */
+ 0, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ 0, /* initproc tp_init; */
+ 0, /* allocfunc tp_alloc; */
+ 0, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ 0, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ 0, /* inquiry tp_is_gc; */
+ 0, /* PyObject *tp_bases; */
+ /* method resolution order */
+ 0, /* PyObject *tp_mro; */
+ 0, /* PyObject *tp_cache; */
+ 0, /* PyObject *tp_subclasses; */
+ 0, /* PyObject *tp_weaklist; */
+ 0
+};
+
+/*****************************************************************************/
+/* Function: rgbTuple_New */
+/*****************************************************************************/
+PyObject *rgbTuple_New( float *rgb[3] )
+{
+ BPy_rgbTuple *rgbTuple = PyObject_NEW( BPy_rgbTuple, &rgbTuple_Type );
+
+ if( rgbTuple == NULL )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create rgbTuple object" );
+
+ rgbTuple->rgb[0] = rgb[0];
+ rgbTuple->rgb[1] = rgb[1];
+ rgbTuple->rgb[2] = rgb[2];
+
+ return ( PyObject * ) rgbTuple;
+}
+
+/*****************************************************************************/
+/* Functions: rgbTuple_getCol and rgbTuple_setCol */
+/* Description: These functions get/set rgb color triplet values. The */
+/* get function returns a tuple, the set one accepts three */
+/* floats (separated or in a tuple) as arguments. */
+/*****************************************************************************/
+PyObject *rgbTuple_getCol( BPy_rgbTuple * self )
+{
+ return Py_BuildValue( "[fff]", *(self->rgb[0]),
+ *(self->rgb[1]), *(self->rgb[2]));
+}
+
+int rgbTuple_setCol( BPy_rgbTuple * self, PyObject * args )
+{
+ int ok = 0;
+ int i;
+ float num[3]={0,0,0};
+
+ /*
+ * since rgbTuple_getCol() returns a list, be sure we accept a list
+ * as valid input
+ */
+
+ if( PyObject_Length( args ) == 3 ) {
+ if ( PyList_Check ( args ) ) {
+ ok = 1;
+ for( i = 0; i < 3; ++i ) {
+ PyObject *tmp = PyList_GET_ITEM( args, i );
+ if( !PyNumber_Check ( tmp ) ) {
+ ok = 0;
+ break;
+ }
+ num[i] = (float)PyFloat_AsDouble( tmp );
+ }
+ } else
+ ok = PyArg_ParseTuple( args, "fff", &num[0], &num[1], &num[2] );
+ } else
+ ok = PyArg_ParseTuple( args, "|(fff)", &num[0], &num[1], &num[2] );
+
+ if( !ok )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected [f,f,f], (f,f,f) or f,f,f as arguments (or nothing)" );
+
+ for( i = 0; i < 3; ++i )
+ *( self->rgb[i] ) = EXPP_ClampFloat( num[i], 0.0, 1.0 );
+
+ return 0;
+}
+
+/*****************************************************************************/
+/* Function: rgbTuple_getAttr */
+/* Description: This is a callback function for the BPy_rgbTuple type. It is */
+/* the function that accesses BPy_rgbTuple member variables and */
+/* methods. */
+/*****************************************************************************/
+static PyObject *rgbTuple_getAttr( BPy_rgbTuple * self, char *name )
+{
+ int i;
+
+ if( strcmp( name, "__members__" ) == 0 )
+ return Py_BuildValue( "[s,s,s]", "R", "G", "B" );
+
+ else if( !strcmp( name, "R" ) || !strcmp( name, "r" ) )
+ i = 0;
+ else if( !strcmp( name, "G" ) || !strcmp( name, "g" ) )
+ i = 1;
+ else if( !strcmp( name, "B" ) || !strcmp( name, "b" ) )
+ i = 2;
+ else
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "attribute not found" ) );
+
+ return PyFloat_FromDouble( (double)(*( self->rgb[i] )) );
+}
+
+/*****************************************************************************/
+/* Function: rgbTuple_setAttr */
+/* Description: This is a callback function for the BPy_rgbTuple type. It is */
+/* the function that changes BPy_rgbTuple member variables. */
+/*****************************************************************************/
+static int rgbTuple_setAttr( BPy_rgbTuple * self, char *name, PyObject * v )
+{
+ float value;
+
+ if( !PyArg_Parse( v, "f", &value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected float argument" );
+
+ value = EXPP_ClampFloat( value, 0.0, 1.0 );
+
+ if( !strcmp( name, "R" ) || !strcmp( name, "r" ) )
+ *( self->rgb[0] ) = value;
+
+ else if( !strcmp( name, "G" ) || !strcmp( name, "g" ) )
+ *( self->rgb[1] ) = value;
+
+ else if( !strcmp( name, "B" ) || !strcmp( name, "b" ) )
+ *( self->rgb[2] ) = value;
+
+ else
+ return ( EXPP_ReturnIntError( PyExc_AttributeError,
+ "attribute not found" ) );
+
+ return 0;
+}
+
+/*****************************************************************************/
+/* Section: rgbTuple as Mapping */
+/* These functions provide code to access rgbTuple objects as */
+/* mappings. */
+/*****************************************************************************/
+static int rgbTupleLength( void )
+{
+ return 3;
+}
+
+static PyObject *rgbTupleSubscript( BPy_rgbTuple * self, PyObject * key )
+{
+ char *name = NULL;
+ int i;
+
+ if( PyNumber_Check( key ) )
+ return rgbTupleItem( self, ( int ) PyInt_AsLong( key ) );
+
+ if( !PyArg_ParseTuple( key, "s", &name ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected int or string argument" );
+
+ if( !strcmp( name, "R" ) || !strcmp( name, "r" ) )
+ i = 0;
+ else if( !strcmp( name, "G" ) || !strcmp( name, "g" ) )
+ i = 1;
+ else if( !strcmp( name, "B" ) || !strcmp( name, "b" ) )
+ i = 2;
+ else
+ return EXPP_ReturnPyObjError( PyExc_AttributeError, name );
+
+ return PyFloat_FromDouble( (double)(*( self->rgb[i] )) );
+}
+
+static int rgbTupleAssSubscript( BPy_rgbTuple * self, PyObject * key,
+ PyObject * v )
+{
+ char *name = NULL;
+ int i;
+
+ if( !PyNumber_Check( v ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "value to assign must be a number" );
+
+ if( PyNumber_Check( key ) )
+ return rgbTupleAssItem( self, ( int ) PyInt_AsLong( key ), v );
+
+ if( !PyArg_Parse( key, "s", &name ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected int or string argument" );
+
+ if( !strcmp( name, "R" ) || !strcmp( name, "r" ) )
+ i = 0;
+ else if( !strcmp( name, "G" ) || !strcmp( name, "g" ) )
+ i = 1;
+ else if( !strcmp( name, "B" ) || !strcmp( name, "b" ) )
+ i = 2;
+ else
+ return EXPP_ReturnIntError( PyExc_AttributeError, name );
+
+ *( self->rgb[i] ) = EXPP_ClampFloat( (float)PyFloat_AsDouble( v ), 0.0, 1.0 );
+
+ return 0;
+}
+
+/*****************************************************************************/
+/* Section: rgbTuple as Sequence */
+/* These functions provide code to access rgbTuple objects as */
+/* sequences. */
+/*****************************************************************************/
+static PyObject *rgbTupleItem( BPy_rgbTuple * self, int i )
+{
+ if( i < 0 || i >= 3 )
+ return EXPP_ReturnPyObjError( PyExc_IndexError,
+ "array index out of range" );
+
+ return PyFloat_FromDouble( (long)(*( self->rgb[i] )) );
+}
+
+static PyObject *rgbTupleSlice( BPy_rgbTuple * self, int begin, int end )
+{
+ PyObject *list;
+ int count;
+
+ if( begin < 0 )
+ begin = 0;
+ if( end > 3 )
+ end = 3;
+ if( begin > end )
+ begin = end;
+
+ list = PyList_New( end - begin );
+
+ for( count = begin; count < end; count++ )
+ PyList_SetItem( list, count - begin,
+ PyFloat_FromDouble( *( self->rgb[count] ) ) );
+
+ return list;
+}
+
+static int rgbTupleAssItem( BPy_rgbTuple * self, int i, PyObject * ob )
+{
+ if( i < 0 || i >= 3 )
+ return EXPP_ReturnIntError( PyExc_IndexError,
+ "array assignment index out of range" );
+
+ if( !PyNumber_Check( ob ) )
+ return EXPP_ReturnIntError( PyExc_IndexError,
+ "color component must be a number" );
+/* XXX this check above is probably ... */
+ *( self->rgb[i] ) =
+ EXPP_ClampFloat( (float)PyFloat_AsDouble( ob ), 0.0, 1.0 );
+
+ return 0;
+}
+
+static int rgbTupleAssSlice( BPy_rgbTuple * self, int begin, int end,
+ PyObject * seq )
+{
+ int count;
+
+ if( begin < 0 )
+ begin = 0;
+ if( end > 3 )
+ end = 3;
+ if( begin > end )
+ begin = end;
+
+ if( !PySequence_Check( seq ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "illegal argument type for built-in operation" );
+
+ if( PySequence_Length( seq ) != ( end - begin ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "size mismatch in slice assignment" );
+
+ for( count = begin; count < end; count++ ) {
+ float value;
+ PyObject *ob = PySequence_GetItem( seq, count );
+
+ if( !PyArg_Parse( ob, "f", &value ) ) {
+ Py_DECREF( ob );
+ return -1;
+ }
+
+ *( self->rgb[count] ) = EXPP_ClampFloat( value, 0.0, 1.0 );
+
+ Py_DECREF( ob );
+ }
+
+ return 0;
+}
+
+/*****************************************************************************/
+/* Function: rgbTuple_repr */
+/* Description: This is a callback function for the BPy_rgbTuple type. It */
+/* builds a meaninful string to represent rgbTuple objects. */
+/*****************************************************************************/
+static PyObject *rgbTuple_repr( BPy_rgbTuple * self )
+{
+ float r, g, b;
+
+ r = *( self->rgb[0] );
+ g = *( self->rgb[1] );
+ b = *( self->rgb[2] );
+
+ return PyString_FromFormat( "[%f, %f, %f]", r, g, b );
+}
diff --git a/source/blender/python/api2_2x/rgbTuple.h b/source/blender/python/api2_2x/rgbTuple.h
new file mode 100644
index 00000000000..a1af0e27549
--- /dev/null
+++ b/source/blender/python/api2_2x/rgbTuple.h
@@ -0,0 +1,56 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_rgbTuple_H
+#define EXPP_rgbTuple_H
+
+#include <Python.h>
+
+/* Objects of <type 'rgbTuple'> are used inside other Blender Python
+ * objects, so this header file must contain only 'public' declarations */
+
+/*****************************************************************************/
+/* Python BPy_rgbTuple structure definition: */
+/*****************************************************************************/
+typedef struct {
+ PyObject_HEAD float *rgb[3]; /* array of three pointers to floats */
+
+} BPy_rgbTuple;
+
+/*****************************************************************************/
+/* Python API function prototypes for the rgbTuple helper module. */
+/*****************************************************************************/
+PyObject *rgbTuple_New( float *rgb[3] );
+PyObject *rgbTuple_getCol( BPy_rgbTuple * self );
+int rgbTuple_setCol( BPy_rgbTuple * self, PyObject * args );
+
+#endif /* EXPP_rgbTuple_H */
diff --git a/source/blender/python/api2_2x/sceneRadio.c b/source/blender/python/api2_2x/sceneRadio.c
new file mode 100644
index 00000000000..ca76869a615
--- /dev/null
+++ b/source/blender/python/api2_2x/sceneRadio.c
@@ -0,0 +1,893 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can Redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#include "sceneRadio.h" /*This must come first*/
+
+#include "BKE_global.h"
+#include "BKE_object.h" /* disable_where_script() */
+#include "gen_utils.h"
+#include "constant.h"
+#include "radio.h"
+
+
+/* bitflags */
+#define EXPP_RADIO_flag_SHOWLIM 1
+#define EXPP_RADIO_flag_Z 2
+/* shorts */
+#define EXPP_RADIO_hemires_MIN 100
+#define EXPP_RADIO_hemires_MAX 1000
+#define EXPP_RADIO_maxiter_MIN 0
+#define EXPP_RADIO_maxiter_MAX 10000
+#define EXPP_RADIO_subshootp_MIN 0
+#define EXPP_RADIO_subshootp_MAX 10
+#define EXPP_RADIO_subshoote_MIN 0
+#define EXPP_RADIO_subshoote_MAX 10
+#define EXPP_RADIO_nodelim_MIN 0
+#define EXPP_RADIO_nodelim_MAX 50
+#define EXPP_RADIO_maxsublamp_MIN 1
+#define EXPP_RADIO_maxsublamp_MAX 250
+#define EXPP_RADIO_pama_MIN 10
+#define EXPP_RADIO_pama_MAX 1000
+#define EXPP_RADIO_pami_MIN 10
+#define EXPP_RADIO_pami_MAX 1000
+#define EXPP_RADIO_elma_MIN 1
+#define EXPP_RADIO_elma_MAX 500
+#define EXPP_RADIO_elmi_MIN 1
+#define EXPP_RADIO_elmi_MAX 100
+/* ints */
+#define EXPP_RADIO_maxnode_MIN 1
+#define EXPP_RADIO_maxnode_MAX 250000
+/* floats */
+#define EXPP_RADIO_convergence_MIN 0.0
+#define EXPP_RADIO_convergence_MAX 0.1f
+#define EXPP_RADIO_radfac_MIN 0.001f
+#define EXPP_RADIO_radfac_MAX 250.0
+#define EXPP_RADIO_gamma_MIN 0.2f
+#define EXPP_RADIO_gamma_MAX 10.0
+/* drawtypes */
+#define EXPP_RADIO_drawtype_WIRE 0
+#define EXPP_RADIO_drawtype_SOLID 1
+#define EXPP_RADIO_drawtype_GOURAUD 2
+
+static int EXPP_check_scene( Scene * scene )
+{
+ if( scene != G.scene ) {
+ PyErr_SetString( PyExc_EnvironmentError,
+ "\nradiosity only works on the current scene, check scene.makeCurrent()." );
+ return 0;
+ } else if( !scene->radio ) {
+ PyErr_SetString( PyExc_EnvironmentError,
+ "\nradiosity data was deleted from scene!" );
+ return 0;
+ }
+
+ return 1;
+}
+
+static PyObject *Radio_collectMeshes( BPy_Radio * self );
+static PyObject *Radio_go( BPy_Radio * self );
+static PyObject *Radio_freeData( BPy_Radio * self );
+static PyObject *Radio_replaceMeshes( BPy_Radio * self );
+static PyObject *Radio_addMesh( BPy_Radio * self );
+static PyObject *Radio_filterFaces( BPy_Radio * self );
+static PyObject *Radio_filterElems( BPy_Radio * self );
+static PyObject *Radio_limitSubdivide( BPy_Radio * self );
+static PyObject *Radio_subdividePatches( BPy_Radio * self );
+static PyObject *Radio_subdivideElems( BPy_Radio * self );
+static PyObject *Radio_removeDoubles( BPy_Radio * self );
+
+static PyObject *Radio_repr( BPy_Radio * self );
+
+static PyObject *EXPP_create_ret_PyInt( int value )
+{
+ PyObject *pyval = PyInt_FromLong( value );
+
+ if( !pyval )
+ PyErr_SetString( PyExc_MemoryError,
+ "couldn't create py int!" );
+
+ return pyval;
+}
+
+static PyObject *EXPP_create_ret_PyFloat( float value )
+{
+ PyObject *pyval = PyFloat_FromDouble( ( double ) value );
+
+ if( !pyval )
+ PyErr_SetString( PyExc_MemoryError,
+ "couldn't create py int!" );
+
+ return pyval;
+}
+
+static PyObject *Radio_get_hemires( BPy_Radio * self )
+{
+ if( !EXPP_check_scene( self->scene ) )
+ return NULL;
+ return EXPP_create_ret_PyInt( ( int ) self->scene->radio->hemires );
+}
+
+static PyObject *Radio_get_maxiter( BPy_Radio * self )
+{
+ if( !EXPP_check_scene( self->scene ) )
+ return NULL;
+ return EXPP_create_ret_PyInt( ( int ) self->scene->radio->maxiter );
+}
+
+static PyObject *Radio_get_subshootp( BPy_Radio * self )
+{
+ if( !EXPP_check_scene( self->scene ) )
+ return NULL;
+ return EXPP_create_ret_PyInt( ( int ) self->scene->radio->subshootp );
+}
+
+static PyObject *Radio_get_subshoote( BPy_Radio * self )
+{
+ if( !EXPP_check_scene( self->scene ) )
+ return NULL;
+ return EXPP_create_ret_PyInt( ( int ) self->scene->radio->subshoote );
+}
+
+static PyObject *Radio_get_nodelim( BPy_Radio * self )
+{
+ if( !EXPP_check_scene( self->scene ) )
+ return NULL;
+ return EXPP_create_ret_PyInt( ( int ) self->scene->radio->nodelim );
+}
+
+static PyObject *Radio_get_maxsublamp( BPy_Radio * self )
+{
+ if( !EXPP_check_scene( self->scene ) )
+ return NULL;
+ return EXPP_create_ret_PyInt( ( int ) self->scene->radio->maxsublamp );
+}
+
+static PyObject *Radio_get_pama( BPy_Radio * self )
+{
+ if( !EXPP_check_scene( self->scene ) )
+ return NULL;
+ return EXPP_create_ret_PyInt( ( int ) self->scene->radio->pama );
+}
+
+static PyObject *Radio_get_pami( BPy_Radio * self )
+{
+ if( !EXPP_check_scene( self->scene ) )
+ return NULL;
+ return EXPP_create_ret_PyInt( ( int ) self->scene->radio->pami );
+}
+
+static PyObject *Radio_get_elma( BPy_Radio * self )
+{
+ if( !EXPP_check_scene( self->scene ) )
+ return NULL;
+ return EXPP_create_ret_PyInt( ( int ) self->scene->radio->elma );
+}
+
+static PyObject *Radio_get_elmi( BPy_Radio * self )
+{
+ if( !EXPP_check_scene( self->scene ) )
+ return NULL;
+ return EXPP_create_ret_PyInt( ( int ) self->scene->radio->elmi );
+}
+
+static PyObject *Radio_get_drawtype( BPy_Radio * self )
+{
+ if( !EXPP_check_scene( self->scene ) )
+ return NULL;
+ return EXPP_create_ret_PyInt( ( int ) self->scene->radio->drawtype );
+}
+
+static PyObject *Radio_get_flag( BPy_Radio * self )
+{
+ if( !EXPP_check_scene( self->scene ) )
+ return NULL;
+ return EXPP_create_ret_PyInt( ( int ) self->scene->radio->flag );
+}
+
+static PyObject *Radio_get_maxnode( BPy_Radio * self )
+{
+ if( !EXPP_check_scene( self->scene ) )
+ return NULL;
+ return EXPP_create_ret_PyInt( ( int ) self->scene->radio->maxnode );
+}
+
+static PyObject *Radio_get_convergence( BPy_Radio * self )
+{
+ if( !EXPP_check_scene( self->scene ) )
+ return NULL;
+ return EXPP_create_ret_PyFloat( self->scene->radio->convergence );
+}
+
+static PyObject *Radio_get_radfac( BPy_Radio * self )
+{
+ if( !EXPP_check_scene( self->scene ) )
+ return NULL;
+ return EXPP_create_ret_PyFloat( self->scene->radio->radfac );
+}
+
+static PyObject *Radio_get_gamma( BPy_Radio * self )
+{
+ if( !EXPP_check_scene( self->scene ) )
+ return NULL;
+ return EXPP_create_ret_PyFloat( self->scene->radio->gamma );
+}
+
+static PyObject *EXPP_unpack_set_int( PyObject * args, int *ptr,
+ int min, int max )
+{
+ int value;
+
+ if( !PyArg_ParseTuple( args, "i", &value ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected int argument" );
+
+ *ptr = EXPP_ClampInt( value, min, max );
+
+ return EXPP_incr_ret( Py_None );
+}
+
+/* could merge with set_int, but is cleaner this way */
+static PyObject *EXPP_unpack_set_short( PyObject * args, short *ptr,
+ short min, short max )
+{
+ int value;
+
+ if( !PyArg_ParseTuple( args, "i", &value ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected int argument" );
+
+ *ptr = ( short ) EXPP_ClampInt( value, min, max );
+
+ return EXPP_incr_ret( Py_None );
+}
+
+static PyObject *EXPP_unpack_set_float( PyObject * args, float *ptr,
+ float min, float max )
+{
+ float value;
+
+ if( !PyArg_ParseTuple( args, "f", &value ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected float argument" );
+
+ *ptr = EXPP_ClampFloat( value, min, max );
+
+ return EXPP_incr_ret( Py_None );
+}
+
+static PyObject *Radio_set_hemires( BPy_Radio * self, PyObject * args )
+{
+ PyObject *ret;
+
+ if( !EXPP_check_scene( self->scene ) )
+ return NULL;
+ ret = EXPP_unpack_set_short( args, &self->scene->radio->hemires,
+ EXPP_RADIO_hemires_MIN,
+ EXPP_RADIO_hemires_MAX );
+
+ if( ret )
+ rad_setlimits( );
+
+ return ret;
+}
+
+static PyObject *Radio_set_maxiter( BPy_Radio * self, PyObject * args )
+{
+ if( !EXPP_check_scene( self->scene ) )
+ return NULL;
+ return EXPP_unpack_set_short( args, &self->scene->radio->maxiter,
+ EXPP_RADIO_maxiter_MIN,
+ EXPP_RADIO_maxiter_MAX );
+}
+
+static PyObject *Radio_set_subshootp( BPy_Radio * self, PyObject * args )
+{
+ if( !EXPP_check_scene( self->scene ) )
+ return NULL;
+ return EXPP_unpack_set_short( args, &self->scene->radio->subshootp,
+ EXPP_RADIO_subshootp_MIN,
+ EXPP_RADIO_subshootp_MAX );
+}
+
+static PyObject *Radio_set_subshoote( BPy_Radio * self, PyObject * args )
+{
+ if( !EXPP_check_scene( self->scene ) )
+ return NULL;
+ return EXPP_unpack_set_short( args, &self->scene->radio->subshoote,
+ EXPP_RADIO_subshoote_MIN,
+ EXPP_RADIO_subshoote_MAX );
+}
+
+static PyObject *Radio_set_nodelim( BPy_Radio * self, PyObject * args )
+{
+ if( !EXPP_check_scene( self->scene ) )
+ return NULL;
+ return EXPP_unpack_set_short( args, &self->scene->radio->nodelim,
+ EXPP_RADIO_nodelim_MIN,
+ EXPP_RADIO_nodelim_MAX );
+}
+
+static PyObject *Radio_set_maxsublamp( BPy_Radio * self, PyObject * args )
+{
+ if( !EXPP_check_scene( self->scene ) )
+ return NULL;
+ return EXPP_unpack_set_short( args, &self->scene->radio->maxsublamp,
+ EXPP_RADIO_maxsublamp_MIN,
+ EXPP_RADIO_maxsublamp_MAX );
+}
+
+static PyObject *Radio_set_pama( BPy_Radio * self, PyObject * args )
+{
+ PyObject *ret;
+
+ if( !EXPP_check_scene( self->scene ) )
+ return NULL;
+ ret = EXPP_unpack_set_short( args, &self->scene->radio->pama,
+ EXPP_RADIO_pama_MIN,
+ EXPP_RADIO_pama_MAX );
+
+ if( ret )
+ rad_setlimits( );
+
+ return ret;
+}
+
+static PyObject *Radio_set_pami( BPy_Radio * self, PyObject * args )
+{
+ PyObject *ret;
+
+ if( !EXPP_check_scene( self->scene ) )
+ return NULL;
+ ret = EXPP_unpack_set_short( args, &self->scene->radio->pami,
+ EXPP_RADIO_pami_MIN,
+ EXPP_RADIO_pami_MAX );
+
+ if( ret )
+ rad_setlimits( );
+
+ return ret;
+}
+
+static PyObject *Radio_set_elma( BPy_Radio * self, PyObject * args )
+{
+ PyObject *ret;
+
+ if( !EXPP_check_scene( self->scene ) )
+ return NULL;
+ ret = EXPP_unpack_set_short( args, &self->scene->radio->elma,
+ EXPP_RADIO_elma_MIN,
+ EXPP_RADIO_elma_MAX );
+
+ if( ret )
+ rad_setlimits( );
+
+ return ret;
+}
+
+static PyObject *Radio_set_elmi( BPy_Radio * self, PyObject * args )
+{
+ PyObject *ret;
+
+ if( !EXPP_check_scene( self->scene ) )
+ return NULL;
+ ret = EXPP_unpack_set_short( args, &self->scene->radio->elmi,
+ EXPP_RADIO_elmi_MIN,
+ EXPP_RADIO_elmi_MAX );
+
+ if( ret )
+ rad_setlimits( );
+
+ return ret;
+}
+
+static PyObject *Radio_set_drawtype( BPy_Radio * self, PyObject * args )
+{
+ PyObject *pyob = NULL;
+ char *str = NULL;
+ short dt = EXPP_RADIO_drawtype_WIRE;
+
+ if( !EXPP_check_scene( self->scene ) )
+ return NULL;
+
+ if( !PyArg_ParseTuple( args, "O", &pyob ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected int or string and another optional int as arguments" );
+
+ if( PyString_Check( pyob ) ) {
+ str = PyString_AsString( pyob );
+ if( !str )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create py string!" );
+ else if( !strcmp( str, "Wire" ) )
+ dt = EXPP_RADIO_drawtype_WIRE;
+ else if( !strcmp( str, "Solid" ) )
+ dt = EXPP_RADIO_drawtype_SOLID;
+ else if( !strcmp( str, "Gouraud" ) )
+ dt = EXPP_RADIO_drawtype_GOURAUD;
+ else
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "unknown drawtype string" );
+ } else if( PyInt_Check( pyob ) ) {
+ dt = ( short ) EXPP_ClampInt( PyInt_AsLong( pyob ),
+ EXPP_RADIO_drawtype_WIRE,
+ EXPP_RADIO_drawtype_GOURAUD );
+ } else
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected int or string as argument" );
+
+ self->scene->radio->drawtype = dt;
+
+ set_radglobal( ); /* needed to update 3d view(s) */
+
+ return EXPP_incr_ret( Py_None );
+}
+
+static PyObject *Radio_set_flag( BPy_Radio * self, PyObject * args )
+{
+ int i, imode = 0;
+ char *mode[2] = { NULL, NULL };
+
+ if( !EXPP_check_scene( self->scene ) )
+ return NULL;
+
+ if( !PyArg_ParseTuple( args, "|ss", &mode[0], &mode[1] ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string arguments (or nothing)" );
+
+ for( i = 0; i < 2; i++ ) {
+ if( !mode[i] )
+ break;
+ else if( !strcmp( mode[i], "ShowLimits" ) )
+ imode |= EXPP_RADIO_flag_SHOWLIM;
+ else if( !strcmp( mode[i], "Z" ) )
+ imode |= EXPP_RADIO_flag_Z;
+ else
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "unknown mode string" );
+ }
+
+ self->scene->radio->flag = ( short ) EXPP_ClampInt( imode, 0, 3 );
+
+ set_radglobal( ); /* needed to update 3d view(s) */
+
+ return EXPP_incr_ret( Py_None );
+}
+
+static PyObject *Radio_set_maxnode( BPy_Radio * self, PyObject * args )
+{
+ if( !EXPP_check_scene( self->scene ) )
+ return NULL;
+ return EXPP_unpack_set_int( args, &self->scene->radio->maxnode,
+ EXPP_RADIO_maxnode_MIN,
+ EXPP_RADIO_maxnode_MAX );
+}
+
+static PyObject *Radio_set_convergence( BPy_Radio * self, PyObject * args )
+{
+ if( !EXPP_check_scene( self->scene ) )
+ return NULL;
+ return EXPP_unpack_set_float( args, &self->scene->radio->convergence,
+ EXPP_RADIO_convergence_MIN,
+ EXPP_RADIO_convergence_MAX );
+}
+
+static PyObject *Radio_set_radfac( BPy_Radio * self, PyObject * args )
+{
+ PyObject *ret;
+
+ if( !EXPP_check_scene( self->scene ) )
+ return NULL;
+ ret = EXPP_unpack_set_float( args, &self->scene->radio->radfac,
+ EXPP_RADIO_radfac_MIN,
+ EXPP_RADIO_radfac_MAX );
+
+ if( ret ) {
+ set_radglobal( );
+ if( rad_phase( ) & RAD_PHASE_FACES )
+ make_face_tab( );
+ else
+ make_node_display( );
+ }
+
+ return ret;
+}
+
+static PyObject *Radio_set_gamma( BPy_Radio * self, PyObject * args )
+{
+ if( !EXPP_check_scene( self->scene ) )
+ return NULL;
+ return EXPP_unpack_set_float( args, &self->scene->radio->gamma,
+ EXPP_RADIO_gamma_MIN,
+ EXPP_RADIO_gamma_MAX );
+}
+
+static PyMethodDef BPy_Radio_methods[] = {
+ {"collectMeshes", ( PyCFunction ) Radio_collectMeshes, METH_NOARGS,
+ "() - Convert selected meshes to patches."},
+ {"go", ( PyCFunction ) Radio_go, METH_NOARGS,
+ "() - Start radiosity calculations."},
+ {"freeData", ( PyCFunction ) Radio_freeData, METH_NOARGS,
+ "() - Free all memory used by radiosity."},
+ {"addMesh", ( PyCFunction ) Radio_addMesh, METH_NOARGS,
+ "() - Add a new mesh with the radio values as vertex colors to Blender."},
+ {"replaceMeshes", ( PyCFunction ) Radio_replaceMeshes, METH_NOARGS,
+ "() - Replace input meshes with the one created by radiosity simulation."},
+ {"limitSubdivide", ( PyCFunction ) Radio_limitSubdivide, METH_NOARGS,
+ "() - Subdivide patches."},
+ {"filterFaces", ( PyCFunction ) Radio_filterFaces, METH_NOARGS,
+ "() - Force an extra smoothing."},
+ {"filterElems", ( PyCFunction ) Radio_filterElems, METH_NOARGS,
+ "() - Filter elements to remove aliasing artifacts."},
+ {"subdividePatches", ( PyCFunction ) Radio_subdividePatches,
+ METH_NOARGS,
+ "() - Pre-subdivision: detect high-energy patches and subdivide them."},
+ {"subdivideElems", ( PyCFunction ) Radio_subdivideElems, METH_NOARGS,
+ "() - Pre-subdivision: detect high-energy elements and subdivide them."},
+ {"removeDoubles", ( PyCFunction ) Radio_removeDoubles, METH_NOARGS,
+ "() - Join elements which differ less than the defined node limit."},
+ {"getHemiRes", ( PyCFunction ) Radio_get_hemires, METH_NOARGS,
+ "() - Get hemicube size."},
+ {"setHemiRes", ( PyCFunction ) Radio_set_hemires, METH_VARARGS,
+ "(int) - Set hemicube size, the range is [100, 1000]."},
+ {"getMaxIter", ( PyCFunction ) Radio_get_maxiter, METH_NOARGS,
+ "() - Get maximum number of radiosity rounds."},
+ {"setMaxIter", ( PyCFunction ) Radio_set_maxiter, METH_VARARGS,
+ "(i) - Set maximum number of radiosity rounds in [0, 10000]."},
+ {"getSubShPatch", ( PyCFunction ) Radio_get_subshootp, METH_NOARGS,
+ "() - Get max number of times environment is tested to detect patches."},
+ {"setSubShPatch", ( PyCFunction ) Radio_set_subshootp, METH_VARARGS,
+ "(i) - Set max number of times environment is tested to detect patches.\n\
+ Range is [0, 10]."},
+ {"getSubShElem", ( PyCFunction ) Radio_get_subshoote, METH_NOARGS,
+ "() - Get number of times environment is tested to detect elements."},
+ {"setSubShElem", ( PyCFunction ) Radio_set_subshoote, METH_VARARGS,
+ "(i) - Set number of times environment is tested to detect elements.\n\
+ Range is [0, 10]."},
+ {"getElemLimit", ( PyCFunction ) Radio_get_nodelim, METH_NOARGS,
+ "() - Get the range for removing doubles."},
+ {"setElemLimit", ( PyCFunction ) Radio_set_nodelim, METH_VARARGS,
+ "(i) - Set the range for removing doubles in [0, 50]."},
+ {"getMaxSubdivSh", ( PyCFunction ) Radio_get_maxsublamp, METH_NOARGS,
+ "() - Get max number of initial shoot patches evaluated."},
+ {"setMaxSubdivSh", ( PyCFunction ) Radio_set_maxsublamp, METH_VARARGS,
+ "(i) - Set max number of initial shoot patches evaluated in [1, 250]."},
+ {"getPatchMax", ( PyCFunction ) Radio_get_pama, METH_NOARGS,
+ "() - Get max size of a patch."},
+ {"setPatchMax", ( PyCFunction ) Radio_set_pama, METH_VARARGS,
+ "(i) - Set max size of a patch in [10, 1000]."},
+ {"getPatchMin", ( PyCFunction ) Radio_get_pami, METH_NOARGS,
+ "() - Get minimum size of a patch."},
+ {"setPatchMin", ( PyCFunction ) Radio_set_pami, METH_VARARGS,
+ "(i) - Set minimum size of a patch in [10, 1000]."},
+ {"getElemMax", ( PyCFunction ) Radio_get_elma, METH_NOARGS,
+ "() - Get max size of an element."},
+ {"setElemMax", ( PyCFunction ) Radio_set_elma, METH_VARARGS,
+ "(i) - Set max size of an element in [1, 100]."},
+ {"getElemMin", ( PyCFunction ) Radio_get_elmi, METH_NOARGS,
+ "() - Get minimum size of an element."},
+ {"setElemMin", ( PyCFunction ) Radio_set_elmi, METH_VARARGS,
+ "(i) - Set minimum size of an element in [1, 100]."},
+ {"getMaxElems", ( PyCFunction ) Radio_get_maxnode, METH_NOARGS,
+ "() - Get maximum number of elements."},
+ {"setMaxElems", ( PyCFunction ) Radio_set_maxnode, METH_VARARGS,
+ "(i) - Set maximum nunber of elements in [1, 250000]."},
+ {"getConvergence", ( PyCFunction ) Radio_get_convergence, METH_NOARGS,
+ "() - Get lower threshold of unshot energy."},
+ {"setConvergence", ( PyCFunction ) Radio_set_convergence, METH_VARARGS,
+ "(f) - Set lower threshold of unshot energy in [0.0, 1.0]."},
+ {"getMult", ( PyCFunction ) Radio_get_radfac, METH_NOARGS,
+ "() - Get energy value multiplier."},
+ {"setMult", ( PyCFunction ) Radio_set_radfac, METH_VARARGS,
+ "(f) - Set energy value multiplier in [0.001, 250.0]."},
+ {"getGamma", ( PyCFunction ) Radio_get_gamma, METH_NOARGS,
+ "() - Get change in the contrast of energy values."},
+ {"setGamma", ( PyCFunction ) Radio_set_gamma, METH_VARARGS,
+ "(f) - Set change in the contrast of energy values in [0.2, 10.0]."},
+ {"getDrawType", ( PyCFunction ) Radio_get_drawtype, METH_NOARGS,
+ "() - Get the draw type: Wire, Solid or Gouraud as an int value."},
+ {"setDrawType", ( PyCFunction ) Radio_set_drawtype, METH_VARARGS,
+ "(i or s) - Set the draw type: wire, solid (default) or gouraud."},
+ {"getMode", ( PyCFunction ) Radio_get_flag, METH_NOARGS,
+ "() - Get mode as int (or'ed bitflags), see Radio.Modes dict."},
+ {"setMode", ( PyCFunction ) Radio_set_flag, METH_VARARGS,
+ "(|ss) - Set mode flags as strings: 'ShowLimits', 'Z'."},
+ {NULL, NULL, 0, NULL}
+};
+
+static PyTypeObject Radio_Type = {
+ PyObject_HEAD_INIT( NULL )
+ 0, /*ob_size */
+ "Blender Radiosity", /*tp_name */
+ sizeof( BPy_Radio ), /*tp_basicsize */
+ 0, /*tp_itemsize */
+ NULL, /*tp_dealloc */
+ 0, /*tp_print */
+ 0, /*tp_getattr */
+ 0, /*tp_setattr */
+ 0, /*tp_compare */
+ ( reprfunc ) Radio_repr, /*tp_repr */
+ 0, /*tp_as_number */
+ 0, /*tp_as_sequence */
+ 0, /*tp_as_mapping */
+ 0, /*tp_hash */
+ 0, /*tp_call */
+ 0, /*tp_str */
+ 0, /*tp_getattro */
+ 0, /*tp_setattro */
+ 0, /*tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags */
+ "Blender radiosity", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ BPy_Radio_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* up to tp_del, so we don't get a warning */
+};
+
+static PyObject *Radio_repr( BPy_Radio * self )
+{
+ if( self->radio )
+ return PyString_FromFormat( "[Radiosity \"%s\"]",
+ self->scene->id.name + 2 );
+ else
+ return PyString_FromString( "NULL" );
+}
+
+PyObject *Radio_CreatePyObject( struct Scene * scene )
+{
+ BPy_Radio *py_radio;
+
+ if( scene != G.scene ) {
+ return EXPP_ReturnPyObjError( PyExc_EnvironmentError,
+ "\nradiosity only works on the current scene, check scene.makeCurrent()." );
+ }
+
+ py_radio = ( BPy_Radio * ) PyObject_NEW( BPy_Radio, &Radio_Type );
+
+ if( !py_radio )
+ return NULL;
+
+ if( !scene->radio )
+ add_radio( ); /* adds to G.scene */
+
+ py_radio->radio = scene->radio;
+ py_radio->scene = scene;
+
+ return ( ( PyObject * ) py_radio );
+}
+
+static PyObject *Radio_collectMeshes( BPy_Radio * self )
+{
+ if( !EXPP_check_scene( self->scene ) )
+ return NULL;
+
+ disable_where_script( 1 ); /* used to avoid error popups */
+ rad_collect_meshes( );
+ disable_where_script( 0 );
+
+ return EXPP_incr_ret( Py_None );
+}
+
+static PyObject *Radio_freeData( BPy_Radio * self )
+{
+ if( !EXPP_check_scene( self->scene ) )
+ return NULL;
+
+ delete_radio( );
+
+ return EXPP_incr_ret( Py_None );
+}
+
+static PyObject *Radio_go( BPy_Radio * self )
+{
+ if( !EXPP_check_scene( self->scene ) )
+ return NULL;
+
+ if( rad_phase( ) == RAD_PHASE_PATCHES )
+ rad_go( );
+ else
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "you need to call radio.collectMeshes() first." );
+
+ return EXPP_incr_ret( Py_None );
+}
+
+static PyObject *Radio_replaceMeshes( BPy_Radio * self )
+{
+ if( !EXPP_check_scene( self->scene ) )
+ return NULL;
+
+ if( rad_phase( ) & RAD_PHASE_FACES )
+ rad_replacemesh( );
+ else
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "you need to call radio.collectMeshes() and radio.go() first." );
+
+ return EXPP_incr_ret( Py_None );
+}
+
+static PyObject *Radio_addMesh( BPy_Radio * self )
+{
+ if( !EXPP_check_scene( self->scene ) )
+ return NULL;
+
+ if( rad_phase( ) & RAD_PHASE_FACES )
+ rad_addmesh( );
+ else
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "you need to call radio.collectMeshes() and radio.go() first." );
+
+ return EXPP_incr_ret( Py_None );
+}
+
+static PyObject *Radio_filterFaces( BPy_Radio * self )
+{
+ if( !EXPP_check_scene( self->scene ) )
+ return NULL;
+
+ if( rad_phase( ) & RAD_PHASE_FACES )
+ filterFaces( );
+ else
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "you need to call radio.collectMeshes() and radio.go() first." );
+
+ return EXPP_incr_ret( Py_None );
+}
+
+static PyObject *Radio_filterElems( BPy_Radio * self )
+{
+ if( !EXPP_check_scene( self->scene ) )
+ return NULL;
+
+ if( rad_phase( ) & RAD_PHASE_FACES ) {
+ set_radglobal( );
+ filterNodes( );
+ make_face_tab( );
+ } else
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "you need to call radio.collectMeshes() and radio.go() first." );
+
+ return EXPP_incr_ret( Py_None );
+}
+
+static PyObject *Radio_limitSubdivide( BPy_Radio * self )
+{
+ if( !EXPP_check_scene( self->scene ) )
+ return NULL;
+
+ if( rad_phase( ) == RAD_PHASE_PATCHES )
+ rad_limit_subdivide( );
+ else
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "you need to call this before calculating the radiosity simulation." );
+
+ return EXPP_incr_ret( Py_None );
+}
+
+static PyObject *Radio_subdividePatches( BPy_Radio * self )
+{
+ if( !EXPP_check_scene( self->scene ) )
+ return NULL;
+
+ if( rad_phase( ) == RAD_PHASE_PATCHES )
+ rad_subdivshootpatch( );
+ else
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "you need to call this before calculating the radiosity simulation." );
+
+ return EXPP_incr_ret( Py_None );
+}
+
+static PyObject *Radio_subdivideElems( BPy_Radio * self )
+{
+ if( !EXPP_check_scene( self->scene ) )
+ return NULL;
+
+ if( rad_phase( ) == RAD_PHASE_PATCHES )
+ rad_subdivshootelem( );
+ else
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "you need to call radio.collectMeshes() and radio.go() first." );
+
+ return EXPP_incr_ret( Py_None );
+}
+
+static PyObject *Radio_removeDoubles( BPy_Radio * self )
+{
+ if( !EXPP_check_scene( self->scene ) )
+ return NULL;
+
+ if( rad_phase( ) == RAD_PHASE_FACES ) {
+ set_radglobal( );
+ removeEqualNodes( self->scene->radio->nodelim );
+ make_face_tab( );
+ } else
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "you need to call radio.collectMeshes() and radio.go() first." );
+
+ return EXPP_incr_ret( Py_None );
+}
+
+static PyMethodDef M_Radio_methods[] = { {NULL, NULL, 0, NULL} };
+
+PyObject *Radio_Init( void )
+{
+ PyObject *submodule, *Modes, *DrawTypes;
+
+ if( PyType_Ready( &Radio_Type ) < 0 )
+ return NULL;
+
+ submodule = Py_InitModule3( "Blender.Scene.Radio", M_Radio_methods,
+ "The Blender Radiosity submodule" );
+
+ Modes = PyConstant_New( );
+ DrawTypes = PyConstant_New( );
+
+ if( Modes ) {
+ BPy_constant *d = ( BPy_constant * ) Modes;
+
+ PyConstant_Insert( d, "ShowLimits",
+ PyInt_FromLong( EXPP_RADIO_flag_SHOWLIM ) );
+ PyConstant_Insert( d, "Z", PyInt_FromLong( EXPP_RADIO_flag_Z ) );
+
+ PyModule_AddObject( submodule, "Modes", Modes );
+ }
+
+ if( DrawTypes ) {
+ BPy_constant *d = ( BPy_constant * ) DrawTypes;
+
+ PyConstant_Insert( d, "Wire",
+ PyInt_FromLong( EXPP_RADIO_drawtype_WIRE ) );
+ PyConstant_Insert( d, "Solid",
+ PyInt_FromLong( EXPP_RADIO_drawtype_SOLID ) );
+ PyConstant_Insert( d, "Gouraud",
+ PyInt_FromLong
+ ( EXPP_RADIO_drawtype_GOURAUD ) );
+
+ PyModule_AddObject( submodule, "DrawTypes", DrawTypes );
+ }
+
+ return submodule;
+}
diff --git a/source/blender/python/api2_2x/sceneRadio.h b/source/blender/python/api2_2x/sceneRadio.h
new file mode 100644
index 00000000000..9d7d43aed8b
--- /dev/null
+++ b/source/blender/python/api2_2x/sceneRadio.h
@@ -0,0 +1,51 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_SCENERADIO_H
+#define EXPP_SCENERADIO_H
+
+#include <Python.h>
+#include "DNA_radio_types.h"
+#include "DNA_scene_types.h"
+
+/* BPy_Radio declaration */
+typedef struct {
+ PyObject_HEAD
+ struct Radio *radio;
+ struct Scene *scene;
+} BPy_Radio;
+
+PyObject *Radio_Init( void );
+
+PyObject *Radio_CreatePyObject( struct Scene *scene );
+
+#endif /* EXPP_SCENERADIO_H */
diff --git a/source/blender/python/api2_2x/sceneRender.c b/source/blender/python/api2_2x/sceneRender.c
new file mode 100644
index 00000000000..187df27e79a
--- /dev/null
+++ b/source/blender/python/api2_2x/sceneRender.c
@@ -0,0 +1,3216 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can Redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Joseph Gilbert, Dietrich Bollmann
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+struct View3D; /* keep me up here */
+
+#include "sceneRender.h" /*This must come first*/
+
+#include "DNA_image_types.h"
+
+#include "BKE_image.h"
+#include "BKE_global.h"
+#include "BKE_screen.h"
+#include "BKE_scene.h"
+
+#include "BIF_drawscene.h"
+#include "BIF_renderwin.h"
+#include "BIF_writeimage.h"
+
+#include "BLI_blenlib.h"
+
+#include "RE_pipeline.h"
+
+#include "mydevice.h"
+#include "butspace.h"
+#include "blendef.h"
+#include "gen_utils.h"
+
+#include "Scene.h"
+
+/* local defines */
+#define PY_NONE 0
+#define PY_LOW 1
+#define PY_MEDIUM 2
+#define PY_HIGH 3
+#define PY_HIGHER 4
+#define PY_BEST 5
+#define PY_USEAOSETTINGS 6
+#define PY_SKYDOME 1
+#define PY_FULL 2
+
+enum rend_constants {
+ EXPP_RENDER_ATTR_XPARTS = 0,
+ EXPP_RENDER_ATTR_YPARTS,
+ EXPP_RENDER_ATTR_ASPECTX,
+ EXPP_RENDER_ATTR_ASPECTY,
+ EXPP_RENDER_ATTR_CFRAME,
+ EXPP_RENDER_ATTR_SFRAME,
+ EXPP_RENDER_ATTR_EFRAME,
+ EXPP_RENDER_ATTR_FPS,
+ EXPP_RENDER_ATTR_FPS_BASE,
+ EXPP_RENDER_ATTR_SIZEX,
+ EXPP_RENDER_ATTR_SIZEY,
+ EXPP_RENDER_ATTR_GAUSSFILTER,
+ EXPP_RENDER_ATTR_MBLURFACTOR,
+};
+
+#define EXPP_RENDER_ATTR_CFRA 2
+#define EXPP_RENDER_ATTR_ANTISHIFT 3
+#define EXPP_RENDER_ATTR_EDGEINT 4
+#define EXPP_RENDER_ATTR_EFRA 5
+#define EXPP_RENDER_ATTR_QUALITY 11
+#define EXPP_RENDER_ATTR_GAUSS 13
+#define EXPP_RENDER_ATTR_BLURFAC 14
+
+#define EXPP_RENDER_ATTR_YF_EXPOSURE 20
+#define EXPP_RENDER_ATTR_YF_GAMMA 21
+#define EXPP_RENDER_ATTR_YF_GIDEPTH 22
+#define EXPP_RENDER_ATTR_YF_GICDEPTH 23
+#define EXPP_RENDER_ATTR_YF_GIPHOTONCOUNT 24
+#define EXPP_RENDER_ATTR_YF_GIPHOTONMIXCOUNT 25
+#define EXPP_RENDER_ATTR_YF_GIPHOTONRADIUS 26
+#define EXPP_RENDER_ATTR_YF_GIPIXPERSAMPLE 27
+#define EXPP_RENDER_ATTR_YF_GIPOWER 28
+#define EXPP_RENDER_ATTR_YF_GIREFINE 29
+#define EXPP_RENDER_ATTR_YF_GISHADOWQUAL 30
+#define EXPP_RENDER_ATTR_YF_RAYBIAS 31
+#define EXPP_RENDER_ATTR_YF_PROCCOUNT 32
+#define EXPP_RENDER_ATTR_YF_RAYDEPTH 33
+#define EXPP_RENDER_ATTR_YF_GIMETHOD 34
+#define EXPP_RENDER_ATTR_YF_GIQUALITY 35
+
+
+/* Render doc strings */
+static char M_Render_doc[] = "The Blender Render module";
+
+/* deprecated callbacks */
+static PyObject *RenderData_SetRenderPath( BPy_RenderData *self,
+ PyObject *args );
+static PyObject *RenderData_SetBackbufPath( BPy_RenderData *self,
+ PyObject *args );
+static PyObject *RenderData_SetFtypePath( BPy_RenderData *self,
+ PyObject *args );
+static PyObject *RenderData_SetOversamplingLevel( BPy_RenderData * self,
+ PyObject * args );
+static PyObject *RenderData_SetRenderWinSize( BPy_RenderData * self,
+ PyObject * args );
+static PyObject *RenderData_SetBorder( BPy_RenderData * self,
+ PyObject * args );
+static PyObject *RenderData_SetRenderer( BPy_RenderData * self,
+ PyObject * args );
+static PyObject *RenderData_SetImageType( BPy_RenderData * self,
+ PyObject * args );
+static PyObject *RenderData_Render( BPy_RenderData * self );
+
+/* BPy_RenderData Internal Protocols */
+
+static PyObject *RenderData_repr( BPy_RenderData * self )
+{
+ if( self->renderContext )
+ return PyString_FromFormat( "[RenderData \"%s\"]",
+ self->scene->id.name + 2 );
+ else
+ return PyString_FromString( "NULL" );
+}
+
+/***************************************************************************/
+/* local utility routines for manipulating data */
+/***************************************************************************/
+static PyObject *M_Render_BitToggleInt( PyObject * args, int setting,
+ int *structure )
+{
+ int flag;
+
+ if( !PyArg_ParseTuple( args, "i", &flag ) )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_AttributeError,
+ "expected TRUE or FALSE (1 or 0)" ) );
+
+ if( flag < 0 || flag > 1 )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_AttributeError,
+ "expected TRUE or FALSE (1 or 0)" ) );
+
+ if( flag )
+ *structure |= setting;
+ else
+ *structure &= ~setting;
+ EXPP_allqueue( REDRAWBUTSSCENE, 0 );
+
+ Py_RETURN_NONE;
+
+}
+
+static PyObject *M_Render_BitToggleShort( PyObject * args, short setting,
+ short *structure )
+{
+ int flag;
+
+ if( !PyArg_ParseTuple( args, "i", &flag ) )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_AttributeError,
+ "expected TRUE or FALSE (1 or 0)" ) );
+
+ if( flag < 0 || flag > 1 )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_AttributeError,
+ "expected TRUE or FALSE (1 or 0)" ) );
+
+ if( flag )
+ *structure |= setting;
+ else
+ *structure &= ~setting;
+ EXPP_allqueue( REDRAWBUTSSCENE, 0 );
+
+ Py_RETURN_NONE;
+
+}
+
+static PyObject *M_Render_GetSetAttributeFloat( PyObject * args,
+ float *structure, float min,
+ float max )
+{
+ float property = -10.0f;
+ char error[48];
+
+ if( !PyArg_ParseTuple( args, "|f", &property ) )
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_AttributeError, "expected float" ) );
+
+ if( property != -10.0f ) {
+ if( property < min || property > max ) {
+ sprintf( error, "out of range - expected %f to %f",
+ min, max );
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_AttributeError, error ) );
+ }
+
+ *structure = property;
+ EXPP_allqueue( REDRAWBUTSSCENE, 0 );
+ Py_RETURN_NONE;
+ } else
+ return PyFloat_FromDouble( *structure );
+}
+
+static PyObject *M_Render_GetSetAttributeShort( PyObject * args,
+ short *structure, int min,
+ int max )
+{
+ short property = -10;
+ char error[48];
+
+ if( !PyArg_ParseTuple( args, "|h", &property ) )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected int" ) );
+
+ if( property != -10 ) {
+ if( property < min || property > max ) {
+ sprintf( error, "out of range - expected %d to %d",
+ min, max );
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_AttributeError, error ) );
+ }
+
+ *structure = property;
+ EXPP_allqueue( REDRAWBUTSSCENE, 0 );
+ Py_RETURN_NONE;
+ } else
+ return PyInt_FromLong( (long int)*structure );
+}
+
+static PyObject *M_Render_GetSetAttributeInt( PyObject * args, int *structure,
+ int min, int max )
+{
+ int property = -10;
+ char error[48];
+
+ if( !PyArg_ParseTuple( args, "|i", &property ) )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected int" ) );
+
+ if( property != -10 ) {
+ if( property < min || property > max ) {
+ sprintf( error, "out of range - expected %d to %d",
+ min, max );
+ return ( EXPP_ReturnPyObjError
+ ( PyExc_AttributeError, error ) );
+ }
+
+ *structure = property;
+
+ /* compare memory locations, not values */
+ if (&G.scene->r.cfra == structure) {
+ /* are we changing the current frame?
+ update all objects, so python scripts can export all objects
+ in a scene without worrying about the view layers */
+ scene_update_for_newframe(G.scene, (1<<20) - 1);
+ }
+
+ /*I dont think this should be here, whatif the scene is not the current scene - campbell*/
+ EXPP_allqueue( REDRAWBUTSSCENE, 0 );
+
+ Py_RETURN_NONE;
+ } else
+ return PyInt_FromLong( *structure );
+}
+
+
+static void M_Render_DoSizePreset( BPy_RenderData * self, short xsch,
+ short ysch, short xasp, short yasp,
+ short size, short xparts, short yparts,
+ short fps, float fps_base,
+ float a, float b, float c,
+ float d )
+{
+ self->renderContext->xsch = xsch;
+ self->renderContext->ysch = ysch;
+ self->renderContext->xasp = xasp;
+ self->renderContext->yasp = yasp;
+ self->renderContext->size = size;
+ self->renderContext->frs_sec = fps;
+ self->renderContext->frs_sec_base = fps_base;
+ self->renderContext->xparts = xparts;
+ self->renderContext->yparts = yparts;
+
+ BLI_init_rctf( &self->renderContext->safety, a, b, c, d );
+ EXPP_allqueue( REDRAWBUTSSCENE, 0 );
+ EXPP_allqueue( REDRAWVIEWCAM, 0 );
+}
+
+/** set / get boolean */
+
+static int M_Render_setBooleanShort( BPy_RenderData * self, PyObject *value, short* var )
+{
+ if( !PyInt_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected boolean value" );
+
+ *var = (PyInt_AsLong( value )) ? 1 : 0;
+
+ EXPP_allqueue( REDRAWBUTSSCENE, 0 );
+ return 0;
+}
+
+static PyObject *M_Render_getBooleanShort( BPy_RenderData * self, short var )
+{
+ return PyInt_FromLong( (long) var );
+}
+
+/** set / get float */
+
+static int M_Render_setFloat( BPy_RenderData *self, PyObject *value, float *var, float min, float max )
+{
+ float val;
+ char error[48];
+
+ if( !PyFloat_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected float value" );
+
+ val = (float) PyFloat_AsDouble( value );
+
+ /* check range */
+ if ( val < min || val > max ) {
+ sprintf( error, "out of range - expected %f to %f", min, max );
+ return EXPP_ReturnIntError( PyExc_TypeError,error );
+ }
+
+ *var = val;
+
+ EXPP_allqueue( REDRAWBUTSSCENE, 0 );
+ return 0;
+}
+
+static PyObject *M_Render_getFloat( BPy_RenderData *self, float var )
+{
+ return PyFloat_FromDouble( (double) var );
+}
+
+/** set / get integer */
+
+static int M_Render_setInt( BPy_RenderData *self, PyObject *value, int *var, int min, int max )
+{
+ int val;
+ char error[48];
+
+ if( !PyInt_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected integer value" );
+
+ val = (int) PyInt_AsLong( value );
+
+ /* check range */
+ if ( val < min || val > max ) {
+ sprintf( error, "out of range - expected %d to %d", min, max );
+ return EXPP_ReturnIntError( PyExc_TypeError,error );
+ }
+
+ *var = val;
+
+ EXPP_allqueue( REDRAWBUTSSCENE, 0 );
+ return 0;
+}
+
+static PyObject *M_Render_getInt( BPy_RenderData *self, int var )
+{
+ return PyInt_FromLong( (long) var );
+}
+
+/***************************************************************************/
+/* Render Module Function Definitions */
+/***************************************************************************/
+
+PyObject *M_Render_CloseRenderWindow( PyObject * self )
+{
+ BIF_close_render_display( );
+ Py_RETURN_NONE;
+}
+
+PyObject *M_Render_SetRenderWinPos( PyObject * self, PyObject * args )
+{
+ PyObject *list = NULL;
+ char *loc = NULL;
+ int x;
+
+ if( !PyArg_ParseTuple( args, "O!", &PyList_Type, &list ) )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected a list" ) );
+
+ G.winpos = 0;
+ for( x = 0; x < PyList_Size( list ); x++ ) {
+ if( !PyArg_Parse( PyList_GetItem( list, x ), "s", &loc ) ) {
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "python list not parseable" );
+ }
+ if( strcmp( loc, "SW" ) == 0 || strcmp( loc, "sw" ) == 0 )
+ G.winpos |= 1;
+ else if( strcmp( loc, "S" ) == 0 || strcmp( loc, "s" ) == 0 )
+ G.winpos |= 2;
+ else if( strcmp( loc, "SE" ) == 0 || strcmp( loc, "se" ) == 0 )
+ G.winpos |= 4;
+ else if( strcmp( loc, "W" ) == 0 || strcmp( loc, "w" ) == 0 )
+ G.winpos |= 8;
+ else if( strcmp( loc, "C" ) == 0 || strcmp( loc, "c" ) == 0 )
+ G.winpos |= 16;
+ else if( strcmp( loc, "E" ) == 0 || strcmp( loc, "e" ) == 0 )
+ G.winpos |= 32;
+ else if( strcmp( loc, "NW" ) == 0 || strcmp( loc, "nw" ) == 0 )
+ G.winpos |= 64;
+ else if( strcmp( loc, "N" ) == 0 || strcmp( loc, "n" ) == 0 )
+ G.winpos |= 128;
+ else if( strcmp( loc, "NE" ) == 0 || strcmp( loc, "ne" ) == 0 )
+ G.winpos |= 256;
+ else
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "list contains unknown string" );
+ }
+ EXPP_allqueue( REDRAWBUTSSCENE, 0 );
+
+ Py_RETURN_NONE;
+}
+
+PyObject *M_Render_EnableDispView( PyObject * self )
+{
+ G.displaymode = R_DISPLAYIMAGE;
+ EXPP_allqueue( REDRAWBUTSSCENE, 0 );
+
+ Py_RETURN_NONE;
+}
+
+PyObject *M_Render_EnableDispWin( PyObject * self )
+{
+ G.displaymode = R_DISPLAYWIN;
+ EXPP_allqueue( REDRAWBUTSSCENE, 0 );
+
+ Py_RETURN_NONE;
+}
+
+
+/***************************************************************************/
+/* BPy_RenderData Function Definitions */
+/***************************************************************************/
+
+PyObject *RenderData_Render( BPy_RenderData * self )
+{
+ Scene *oldsce;
+
+ if (!G.background) {
+ oldsce = G.scene;
+ set_scene( self->scene );
+ BIF_do_render( 0 );
+ set_scene( oldsce );
+ }
+
+ else { /* background mode (blender -b file.blend -P script) */
+ Render *re= RE_NewRender("Render");
+
+ int end_frame = G.scene->r.efra; /* is of type short currently */
+
+ if (G.scene != self->scene)
+ return EXPP_ReturnPyObjError (PyExc_RuntimeError,
+ "scene to render in bg mode must be the active scene");
+
+ G.scene->r.efra = G.scene->r.sfra;
+
+ RE_BlenderAnim(re, G.scene, G.scene->r.sfra, G.scene->r.efra);
+
+ G.scene->r.efra = (short)end_frame;
+ }
+
+ Py_RETURN_NONE;
+}
+
+/*
+ * This will save the rendered image to an output file path already defined.
+ */
+PyObject *RenderData_SaveRenderedImage ( BPy_RenderData * self, PyObject *args )
+{
+ char dir[FILE_MAXDIR * 2], str[FILE_MAXFILE * 2];
+ char *name_str, filepath[FILE_MAXDIR+FILE_MAXFILE];
+ RenderResult *rr = NULL;
+ int zbuff;
+
+ if( !PyArg_ParseTuple( args, "s|i", &name_str, &zbuff ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected a filename (string) and optional int" );
+
+ if( strlen(self->renderContext->pic) + strlen(name_str)
+ >= sizeof(filepath) )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "full filename too long" );
+
+ if (zbuff !=0 ) zbuff = 1; /*required 1/0 */ /* removed! (ton) */
+
+ BLI_strncpy( filepath, self->renderContext->pic, sizeof(filepath) );
+ strcat(filepath, name_str);
+
+ rr = RE_GetResult(RE_GetRender(G.scene->id.name));
+ if(!rr) {
+ return EXPP_ReturnPyObjError (PyExc_ValueError, "No image rendered");
+ } else {
+ if(G.ima[0]==0) {
+ strcpy(dir, G.sce);
+ BLI_splitdirstring(dir, str);
+ strcpy(G.ima, dir);
+ }
+ BIF_save_rendered_image(filepath);
+ }
+ Py_RETURN_NONE;
+}
+
+PyObject *RenderData_RenderAnim( BPy_RenderData * self )
+{
+ Scene *oldsce;
+
+ if (!G.background) {
+ oldsce = G.scene;
+ set_scene( self->scene );
+ BIF_do_render( 1 );
+ set_scene( oldsce );
+ }
+ else { /* background mode (blender -b file.blend -P script) */
+ Render *re= RE_NewRender("Render");
+
+ if (G.scene != self->scene)
+ return EXPP_ReturnPyObjError (PyExc_RuntimeError,
+ "scene to render in bg mode must be the active scene");
+
+ if (G.scene->r.sfra > G.scene->r.efra)
+ return EXPP_ReturnPyObjError (PyExc_RuntimeError,
+ "start frame must be less or equal to end frame");
+
+ RE_BlenderAnim(re, G.scene, G.scene->r.sfra, G.scene->r.efra);
+ }
+ Py_RETURN_NONE;
+}
+
+PyObject *RenderData_Play( BPy_RenderData * self )
+{
+ char file[FILE_MAXDIR + FILE_MAXFILE];
+ extern char bprogname[];
+ char str[FILE_MAXDIR + FILE_MAXFILE];
+ int pos[2], size[2];
+ char txt[64];
+
+#ifdef WITH_QUICKTIME
+ if( self->renderContext->imtype == R_QUICKTIME ) {
+
+ strcpy( file, self->renderContext->pic );
+ BLI_convertstringcode( file, (char *) self->scene,
+ self->renderContext->cfra );
+ BLI_make_existing_file( file );
+ if( BLI_strcasecmp( file + strlen( file ) - 4, ".mov" ) ) {
+ sprintf( txt, "%04d_%04d.mov",
+ ( self->renderContext->sfra ),
+ ( self->renderContext->efra ) );
+ strcat( file, txt );
+ }
+ } else
+#endif
+ {
+
+ strcpy( file, self->renderContext->pic );
+ BLI_convertstringcode( file, G.sce,
+ self->renderContext->cfra );
+ BLI_make_existing_file( file );
+ if( BLI_strcasecmp( file + strlen( file ) - 4, ".avi" ) ) {
+ sprintf( txt, "%04d_%04d.avi",
+ ( self->renderContext->sfra ),
+ ( self->renderContext->efra ) );
+ strcat( file, txt );
+ }
+ }
+ if( BLI_exist( file ) ) {
+ calc_renderwin_rectangle(640, 480, G.winpos, pos, size);
+ sprintf( str, "%s -a -p %d %d \"%s\"", bprogname, pos[0],
+ pos[1], file );
+ system( str );
+ } else {
+ BKE_makepicstring( file, G.scene->r.pic, self->renderContext->sfra, G.scene->r.imtype);
+ if( BLI_exist( file ) ) {
+ calc_renderwin_rectangle(640, 480, G.winpos, pos, size);
+#ifdef WIN32
+ sprintf( str, "%s -a -p %d %d \"%s\"", bprogname,
+ pos[0], pos[1], file );
+#else
+ sprintf( str, "\"%s\" -a -p %d %d \"%s\"", bprogname,
+ pos[0], pos[1], file );
+#endif
+ system( str );
+ } else
+ sprintf( "Can't find image: %s", file );
+ }
+
+ Py_RETURN_NONE;
+}
+
+PyObject *RenderData_EnableBackbuf( BPy_RenderData * self, PyObject * args )
+{
+ return M_Render_BitToggleShort( args, 1,
+ &self->renderContext->bufflag );
+}
+
+PyObject *RenderData_EnableExtensions( BPy_RenderData * self, PyObject * args )
+{
+ return M_Render_BitToggleShort( args, R_EXTENSION,
+ &self->renderContext->scemode );
+}
+
+PyObject *RenderData_EnableSequencer( BPy_RenderData * self, PyObject * args )
+{
+ return M_Render_BitToggleShort( args, R_DOSEQ,
+ &self->renderContext->scemode );
+}
+
+PyObject *RenderData_EnableRenderDaemon( BPy_RenderData * self,
+ PyObject * args )
+{
+ return M_Render_BitToggleShort( args, R_BG_RENDER,
+ &self->renderContext->scemode );
+}
+
+PyObject *RenderData_EnableToonShading( BPy_RenderData * self,
+ PyObject * args )
+{
+ return M_Render_BitToggleInt( args, R_EDGE,
+ &self->renderContext->mode );
+}
+
+PyObject *RenderData_EdgeIntensity( BPy_RenderData * self, PyObject * args )
+{
+ return M_Render_GetSetAttributeShort( args,
+ &self->renderContext->edgeint, 0,
+ 255 );
+}
+
+PyObject *RenderData_SetEdgeColor( BPy_RenderData * self, PyObject * args )
+{
+ float red, green, blue;
+
+ if( !PyArg_ParseTuple( args, "fff", &red, &green, &blue ) )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected three floats" ) );
+
+ if( red < 0 || red > 1 )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "value out of range 0.000 - 1.000 (red)" ) );
+ if( green < 0 || green > 1 )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "value out of range 0.000 - 1.000 (green)" ) );
+ if( blue < 0 || blue > 1 )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "value out of range 0.000 - 1.000 (blue)" ) );
+
+ self->renderContext->edgeR = red;
+ self->renderContext->edgeG = green;
+ self->renderContext->edgeB = blue;
+
+ Py_RETURN_NONE;
+}
+
+PyObject *RenderData_GetEdgeColor( BPy_RenderData * self )
+{
+ char rgb[24];
+
+ sprintf( rgb, "[%.3f,%.3f,%.3f]", self->renderContext->edgeR,
+ self->renderContext->edgeG, self->renderContext->edgeB );
+ return PyString_FromString( rgb );
+}
+
+PyObject *RenderData_EnableOversampling( BPy_RenderData * self,
+ PyObject * args )
+{
+ return M_Render_BitToggleInt( args, R_OSA,
+ &self->renderContext->mode );
+}
+
+static int RenderData_setOSALevel( BPy_RenderData * self,
+ PyObject * value )
+{
+ int level;
+
+ if( !PyInt_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected int argument" );
+
+ level = PyInt_AsLong( value );
+ if( level != 5 && level != 8 && level != 11 && level != 16 )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "expected 5, 8, 11, or 16" );
+
+ self->renderContext->osa = (short)level;
+ EXPP_allqueue( REDRAWBUTSSCENE, 0 );
+
+ return 0;
+}
+
+PyObject *RenderData_EnableMotionBlur( BPy_RenderData * self, PyObject * args )
+{
+ return M_Render_BitToggleInt( args, R_MBLUR,
+ &self->renderContext->mode );
+}
+
+PyObject *RenderData_MotionBlurLevel( BPy_RenderData * self, PyObject * args )
+{
+ return M_Render_GetSetAttributeFloat( args,
+ &self->renderContext->blurfac,
+ 0.01f, 5.0f );
+}
+
+PyObject *RenderData_PartsX( BPy_RenderData * self, PyObject * args )
+{
+ return M_Render_GetSetAttributeShort( args,
+ &self->renderContext->xparts, 1,
+ 512 );
+}
+
+PyObject *RenderData_PartsY( BPy_RenderData * self, PyObject * args )
+{
+ return M_Render_GetSetAttributeShort( args,
+ &self->renderContext->yparts, 1,
+ 64 );
+}
+
+PyObject *RenderData_EnableSky( BPy_RenderData * self )
+{
+ self->renderContext->alphamode = R_ADDSKY;
+ EXPP_allqueue( REDRAWBUTSSCENE, 0 );
+
+ Py_RETURN_NONE;
+}
+
+PyObject *RenderData_EnablePremultiply( BPy_RenderData * self )
+{
+ self->renderContext->alphamode = R_ALPHAPREMUL;
+ EXPP_allqueue( REDRAWBUTSSCENE, 0 );
+
+ Py_RETURN_NONE;
+}
+
+PyObject *RenderData_EnableKey( BPy_RenderData * self )
+{
+ self->renderContext->alphamode = R_ALPHAKEY;
+ EXPP_allqueue( REDRAWBUTSSCENE, 0 );
+
+ Py_RETURN_NONE;
+}
+
+PyObject *RenderData_EnableShadow( BPy_RenderData * self, PyObject * args )
+{
+ return M_Render_BitToggleInt( args, R_SHADOW,
+ &self->renderContext->mode );
+}
+
+PyObject *RenderData_EnableEnvironmentMap( BPy_RenderData * self,
+ PyObject * args )
+{
+ return M_Render_BitToggleInt( args, R_ENVMAP,
+ &self->renderContext->mode );
+}
+
+PyObject *RenderData_EnablePanorama( BPy_RenderData * self, PyObject * args )
+{
+ return M_Render_BitToggleInt( args, R_PANORAMA,
+ &self->renderContext->mode );
+}
+
+PyObject *RenderData_EnableRayTracing( BPy_RenderData * self, PyObject * args )
+{
+ return M_Render_BitToggleInt( args, R_RAYTRACE,
+ &self->renderContext->mode );
+}
+
+PyObject *RenderData_EnableRadiosityRender( BPy_RenderData * self,
+ PyObject * args )
+{
+ return M_Render_BitToggleInt( args, R_RADIO,
+ &self->renderContext->mode );
+}
+PyObject *RenderData_EnableFieldRendering( BPy_RenderData * self,
+ PyObject * args )
+{
+ return M_Render_BitToggleInt( args, R_FIELDS,
+ &self->renderContext->mode );
+}
+
+PyObject *RenderData_EnableOddFieldFirst( BPy_RenderData * self,
+ PyObject * args )
+{
+ return M_Render_BitToggleInt( args, R_ODDFIELD,
+ &self->renderContext->mode );
+}
+
+PyObject *RenderData_EnableFieldTimeDisable( BPy_RenderData * self,
+ PyObject * args )
+{
+ return M_Render_BitToggleInt( args, R_FIELDSTILL,
+ &self->renderContext->mode );
+}
+
+PyObject *RenderData_EnableGaussFilter( BPy_RenderData * self,
+ PyObject * args )
+{
+ return M_Render_BitToggleInt( args, R_GAUSS,
+ &self->renderContext->mode );
+
+ /* note, this now is obsolete (ton) */
+ /* we now need a call like RenderData_SetFilter() or so */
+ /* choices are listed in DNA_scene_types.h (search filtertype) */
+}
+
+PyObject *RenderData_EnableBorderRender( BPy_RenderData * self,
+ PyObject * args )
+{
+ return M_Render_BitToggleInt( args, R_BORDER,
+ &self->renderContext->mode );
+}
+
+static int RenderData_setBorder( BPy_RenderData * self, PyObject * args )
+{
+ float xmin, ymin, xmax, ymax;
+
+ if( PyList_Check( args ) )
+ args = PySequence_Tuple( args );
+ else
+ Py_INCREF( args );
+
+ if( !PyArg_ParseTuple( args, "ffff", &xmin, &ymin, &xmax, &ymax ) ) {
+ Py_DECREF( args );
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected four floats" );
+ }
+
+ self->renderContext->border.xmin = EXPP_ClampFloat( xmin, 0.0, 1.0 );
+ self->renderContext->border.xmax = EXPP_ClampFloat( xmax, 0.0, 1.0 );
+ self->renderContext->border.ymin = EXPP_ClampFloat( ymin, 0.0, 1.0 );
+ self->renderContext->border.ymax = EXPP_ClampFloat( ymax, 0.0, 1.0 );
+
+ EXPP_allqueue( REDRAWVIEWCAM, 1 );
+
+ Py_DECREF( args );
+ return 0;
+}
+
+static PyObject *RenderData_getBorder( BPy_RenderData * self )
+{
+ return Py_BuildValue( "[ffff]",
+ self->renderContext->border.xmin,
+ self->renderContext->border.ymin,
+ self->renderContext->border.xmax,
+ self->renderContext->border.ymax );
+}
+
+PyObject *RenderData_EnableGammaCorrection( BPy_RenderData * self,
+ PyObject * args )
+{
+ return M_Render_BitToggleInt( args, R_GAMMA,
+ &self->renderContext->mode );
+}
+
+PyObject *RenderData_GaussFilterSize( BPy_RenderData * self, PyObject * args )
+{
+ return M_Render_GetSetAttributeFloat( args,
+ &self->renderContext->gauss,
+ 0.5f, 1.5f );
+}
+
+PyObject *RenderData_StartFrame( BPy_RenderData * self, PyObject * args )
+{
+ return M_Render_GetSetAttributeInt( args, &self->renderContext->sfra,
+ 1, MAXFRAME );
+}
+
+PyObject *RenderData_CurrentFrame( BPy_RenderData * self, PyObject * args )
+{
+ return M_Render_GetSetAttributeInt( args, &self->renderContext->cfra,
+ 1, MAXFRAME );
+}
+
+PyObject *RenderData_EndFrame( BPy_RenderData * self, PyObject * args )
+{
+ return M_Render_GetSetAttributeInt( args, &self->renderContext->efra,
+ 1, MAXFRAME );
+}
+
+PyObject *RenderData_ImageSizeX( BPy_RenderData * self, PyObject * args )
+{
+ return M_Render_GetSetAttributeShort( args, &self->renderContext->xsch,
+ 4, 10000 );
+}
+
+PyObject *RenderData_ImageSizeY( BPy_RenderData * self, PyObject * args )
+{
+ return M_Render_GetSetAttributeShort( args, &self->renderContext->ysch,
+ 4, 10000 );
+}
+
+PyObject *RenderData_AspectRatioX( BPy_RenderData * self, PyObject * args )
+{
+ return M_Render_GetSetAttributeShort( args, &self->renderContext->xasp,
+ 1, 200 );
+}
+
+PyObject *RenderData_AspectRatioY( BPy_RenderData * self, PyObject * args )
+{
+ return M_Render_GetSetAttributeShort( args, &self->renderContext->yasp,
+ 1, 200 );
+}
+
+static int RenderData_setRenderer( BPy_RenderData * self, PyObject * value )
+{
+ int type;
+
+ if( !PyInt_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected constant INTERNAL or YAFRAY" );
+
+ type = PyInt_AsLong( value );
+ if( type == R_INTERN )
+ self->renderContext->renderer = R_INTERN;
+ else if( type == R_YAFRAY )
+ self->renderContext->renderer = R_YAFRAY;
+ else
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "expected constant INTERNAL or YAFRAY" );
+
+ EXPP_allqueue( REDRAWBUTSSCENE, 0 );
+ return 0;
+}
+
+PyObject *RenderData_EnableCropping( void )
+{
+/* return M_Render_BitToggleInt( args, R_MOVIECROP,
+ &self->renderContext->mode );
+*/
+ printf("cropping option is now default, obsolete\n");
+ Py_RETURN_NONE;
+}
+
+
+static int RenderData_setImageType( BPy_RenderData *self, PyObject *value )
+{
+ int type;
+
+ if( !PyInt_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected int constant" );
+
+ type = PyInt_AS_LONG( value );
+
+ /*
+ * this same logic and more is in buttons_scene.c imagetype_pup code but
+ * only in generating strings for the popup menu, no way to reuse that :(
+ */
+
+ switch( type ) {
+ case R_AVIRAW :
+ case R_AVIJPEG :
+ case R_TARGA :
+ case R_RAWTGA :
+ case R_RADHDR :
+ case R_PNG :
+ case R_BMP :
+ case R_JPEG90 :
+ case R_HAMX :
+ case R_IRIS :
+ case R_IRIZ :
+ case R_FTYPE :
+ case R_TIFF :
+ case R_CINEON :
+ case R_DPX :
+#ifdef _WIN32
+ case R_AVICODEC :
+#endif
+#ifdef WITH_OPENEXR
+ case R_OPENEXR :
+#endif
+#ifdef WITH_FFMPEG
+ case R_FFMPEG :
+#endif
+ self->renderContext->imtype = type;
+ break;
+ case R_QUICKTIME :
+ if( G.have_quicktime ) {
+ self->renderContext->imtype = R_QUICKTIME;
+ break;
+ }
+ default:
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "unknown constant - see modules dict for help" );
+ }
+
+ EXPP_allqueue( REDRAWBUTSSCENE, 0 );
+ return 0;
+}
+
+PyObject *RenderData_Quality( BPy_RenderData * self, PyObject * args )
+{
+ return M_Render_GetSetAttributeShort( args,
+ &self->renderContext->quality,
+ 10, 100 );
+}
+
+PyObject *RenderData_FramesPerSec( BPy_RenderData * self, PyObject * args )
+{
+ return M_Render_GetSetAttributeShort( args,
+ &self->renderContext->frs_sec, 1,
+ 120 );
+}
+
+PyObject *RenderData_EnableGrayscale( BPy_RenderData * self )
+{
+ self->renderContext->planes = R_PLANESBW;
+ EXPP_allqueue( REDRAWBUTSSCENE, 0 );
+
+ Py_RETURN_NONE;
+}
+
+PyObject *RenderData_EnableRGBColor( BPy_RenderData * self )
+{
+ self->renderContext->planes = R_PLANES24;
+ EXPP_allqueue( REDRAWBUTSSCENE, 0 );
+
+ Py_RETURN_NONE;
+}
+
+PyObject *RenderData_EnableRGBAColor( BPy_RenderData * self )
+{
+ self->renderContext->planes = R_PLANES32;
+ EXPP_allqueue( REDRAWBUTSSCENE, 0 );
+
+ Py_RETURN_NONE;
+}
+
+PyObject *RenderData_SizePreset( BPy_RenderData * self, PyObject * args )
+{
+ int type;
+
+ if( !PyArg_ParseTuple( args, "i", &type ) )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected constant" ) );
+
+ if( type == B_PR_PAL ) {
+ M_Render_DoSizePreset( self, 720, 576, 54, 51, 100,
+ self->renderContext->xparts,
+ self->renderContext->yparts, 25, 1.0f,
+ 0.1f,
+ 0.9f, 0.1f, 0.9f );
+ self->renderContext->mode &= ~R_PANORAMA;
+ BLI_init_rctf( &self->renderContext->safety, 0.1f, 0.9f, 0.1f,
+ 0.9f );
+ } else if( type == B_PR_NTSC ) {
+ M_Render_DoSizePreset( self, 720, 480, 10, 11, 100, 1, 1,
+ 30, 1.001f,
+ 0.1f, 0.9f, 0.1f, 0.9f );
+ self->renderContext->mode &= ~R_PANORAMA;
+ BLI_init_rctf( &self->renderContext->safety, 0.1f, 0.9f, 0.1f,
+ 0.9f );
+ } else if( type == B_PR_PRESET ) {
+ M_Render_DoSizePreset( self, 720, 576, 54, 51, 100, 1, 1,
+ self->renderContext->frs_sec,
+ self->renderContext->frs_sec_base,
+ 0.1f, 0.9f,
+ 0.1f, 0.9f );
+ self->renderContext->mode = R_OSA + R_SHADOW + R_FIELDS;
+ self->renderContext->imtype = R_TARGA;
+ BLI_init_rctf( &self->renderContext->safety, 0.1f, 0.9f, 0.1f,
+ 0.9f );
+ } else if( type == B_PR_PRV ) {
+ M_Render_DoSizePreset( self, 640, 512, 1, 1, 50, 1, 1,
+ self->renderContext->frs_sec,
+ self->renderContext->frs_sec_base,
+ 0.1f, 0.9f,
+ 0.1f, 0.9f );
+ self->renderContext->mode &= ~R_PANORAMA;
+ BLI_init_rctf( &self->renderContext->safety, 0.1f, 0.9f, 0.1f,
+ 0.9f );
+ } else if( type == B_PR_PC ) {
+ M_Render_DoSizePreset( self, 640, 480, 100, 100, 100, 1, 1,
+ self->renderContext->frs_sec,
+ self->renderContext->frs_sec_base,
+ 0.0f, 1.0f,
+ 0.0f, 1.0f );
+ self->renderContext->mode &= ~R_PANORAMA;
+ BLI_init_rctf( &self->renderContext->safety, 0.0f, 1.0f, 0.0f,
+ 1.0f );
+ } else if( type == B_PR_PAL169 ) {
+ M_Render_DoSizePreset( self, 720, 576, 64, 45, 100, 1, 1,
+ 25, 1.0f, 0.1f, 0.9f, 0.1f, 0.9f );
+ self->renderContext->mode &= ~R_PANORAMA;
+ BLI_init_rctf( &self->renderContext->safety, 0.1f, 0.9f, 0.1f,
+ 0.9f );
+ } else if( type == B_PR_PANO ) {
+ M_Render_DoSizePreset( self, 36, 176, 115, 100, 100, 16, 1,
+ self->renderContext->frs_sec,
+ self->renderContext->frs_sec_base,
+ 0.1f, 0.9f,
+ 0.1f, 0.9f );
+ self->renderContext->mode |= R_PANORAMA;
+ BLI_init_rctf( &self->renderContext->safety, 0.1f, 0.9f, 0.1f,
+ 0.9f );
+ } else if( type == B_PR_FULL ) {
+ M_Render_DoSizePreset( self, 1280, 1024, 1, 1, 100, 1, 1,
+ self->renderContext->frs_sec,
+ self->renderContext->frs_sec_base,
+ 0.1f, 0.9f,
+ 0.1f, 0.9f );
+ self->renderContext->mode &= ~R_PANORAMA;
+ BLI_init_rctf( &self->renderContext->safety, 0.1f, 0.9f, 0.1f,
+ 0.9f );
+ } else
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "unknown constant - see modules dict for help" ) );
+
+ EXPP_allqueue( REDRAWBUTSSCENE, 0 );
+ Py_RETURN_NONE;
+}
+
+/*
+
+PyObject *RenderData_SetYafrayGIQuality( BPy_RenderData * self,
+ PyObject * args )
+{
+ int type;
+
+ if( !PyArg_ParseTuple( args, "i", &type ) )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected constant" ) );
+
+ if( type == PY_NONE || type == PY_LOW ||
+ type == PY_MEDIUM || type == PY_HIGH ||
+ type == PY_HIGHER || type == PY_BEST ) {
+ self->renderContext->GIquality = (short)type;
+ } else
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "unknown constant - see modules dict for help" ) );
+
+ EXPP_allqueue( REDRAWBUTSSCENE, 0 );
+ Py_RETURN_NONE;
+}
+
+PyObject *RenderData_SetYafrayGIMethod( BPy_RenderData * self,
+ PyObject * args )
+{
+ int type;
+
+ if( !PyArg_ParseTuple( args, "i", &type ) )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected constant" ) );
+
+ if( type == PY_NONE || type == PY_SKYDOME || type == PY_FULL ) {
+ self->renderContext->GImethod = (short)type;
+ } else
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "unknown constant - see modules dict for help" ) );
+
+ EXPP_allqueue( REDRAWBUTSSCENE, 0 );
+ Py_RETURN_NONE;
+}
+*/
+
+/* (die) beg */
+
+/* YafRay - Yafray GI Method */
+
+static int RenderData_setYafrayGIQuality( BPy_RenderData * self, PyObject * value )
+{
+ long type;
+
+ if( !PyInt_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected constant" );
+
+ type = PyInt_AsLong( value );
+
+ if( type == PY_NONE || type == PY_LOW ||
+ type == PY_MEDIUM || type == PY_HIGH ||
+ type == PY_HIGHER || type == PY_BEST ||
+ type == PY_USEAOSETTINGS
+ ) {
+ self->renderContext->GIquality = (short)type;
+ } else {
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected constant NONE, LOW, MEDIUM, HIGHER or BEST" );
+ }
+
+ EXPP_allqueue( REDRAWBUTSSCENE, 0 );
+ return 0;
+}
+
+static PyObject *RenderData_getYafrayGIQuality( BPy_RenderData * self )
+{
+ return PyInt_FromLong( (long) self->renderContext->GIquality );
+}
+
+static PyObject *RenderData_SetYafrayGIQuality( BPy_RenderData * self,
+ PyObject * args )
+{
+ return EXPP_setterWrapper( (void*) self, args,
+ (setter) RenderData_setYafrayGIQuality );
+}
+
+static PyObject *RenderData_GetYafrayGIQuality( BPy_RenderData * self )
+{
+ return RenderData_getYafrayGIQuality(self);
+}
+
+/* YafRay - Yafray GI Method */
+
+static int RenderData_setYafrayGIMethod( BPy_RenderData * self, PyObject * value )
+{
+ int type;
+
+ if( !PyInt_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected constant NONE, SKYDOME or FULL" );
+
+ type = PyInt_AsLong( value );
+ if( type == PY_NONE || type == PY_SKYDOME || type == PY_FULL ) {
+ self->renderContext->GImethod = (short)type;
+ } else {
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected constant NONE, SKYDOME or FULL" );
+ }
+
+ EXPP_allqueue( REDRAWBUTSSCENE, 0 );
+ return 0;
+}
+
+static PyObject *RenderData_getYafrayGIMethod( BPy_RenderData * self )
+{
+ return PyInt_FromLong( (long)self->renderContext->GImethod );
+}
+
+static PyObject *RenderData_GetYafrayGIMethod( BPy_RenderData * self )
+{
+ return RenderData_getYafrayGIMethod(self);
+}
+
+static PyObject *RenderData_SetYafrayGIMethod( BPy_RenderData * self,
+ PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args,
+ (setter)RenderData_setYafrayGIMethod );
+}
+
+
+/* YafRay - Export to XML */
+
+static int RenderData_setYafrayExportToXML( BPy_RenderData * self, PyObject * value )
+{
+ return M_Render_setBooleanShort( self, value, &self->renderContext->YFexportxml );
+}
+
+static PyObject *RenderData_getYafrayExportToXML( BPy_RenderData * self )
+{
+ return M_Render_getBooleanShort( self, self->renderContext->YFexportxml );
+}
+
+/** Auto AA */
+
+static int RenderData_setYafrayAutoAntiAliasing( BPy_RenderData * self, PyObject * value )
+{
+ return M_Render_setBooleanShort( self, value, &self->renderContext->YF_AA );
+}
+
+static PyObject *RenderData_getYafrayAutoAntiAliasing( BPy_RenderData * self )
+{
+ return M_Render_getBooleanShort( self, self->renderContext->YF_AA );
+}
+
+/** Clamp RGB */
+
+static int RenderData_setYafrayClampRGB( BPy_RenderData * self, PyObject * value )
+{
+ return M_Render_setBooleanShort( self, value, &self->renderContext->YF_clamprgb );
+}
+
+static PyObject *RenderData_getYafrayClampRGB( BPy_RenderData * self )
+{
+ return M_Render_getBooleanShort( self, self->renderContext->YF_clamprgb );
+}
+
+/** YafRay - Anti-Aliasing Passes */
+
+static int RenderData_setYafrayAntiAliasingPasses( BPy_RenderData * self, PyObject * value )
+{
+ return M_Render_setInt( self, value, &self->renderContext->YF_AApasses, 0, 64 );
+}
+
+static PyObject *RenderData_getYafrayAntiAliasingPasses( BPy_RenderData * self )
+{
+ return M_Render_getInt( self, self->renderContext->YF_AApasses );
+}
+
+/** YafRay - Anti-Aliasing Samples */
+
+static int RenderData_setYafrayAntiAliasingSamples( BPy_RenderData * self, PyObject * value )
+{
+ return M_Render_setInt( self, value, &self->renderContext->YF_AAsamples, 0, 2048 );
+}
+
+static PyObject *RenderData_getYafrayAntiAliasingSamples( BPy_RenderData * self )
+{
+ return M_Render_getInt( self, self->renderContext->YF_AAsamples );
+}
+
+/* YafRay - Anti-Aliasing Pixel Filter Size */
+
+static int RenderData_setYafrayAntiAliasingPixelSize( BPy_RenderData * self, PyObject * value )
+{
+ return M_Render_setFloat( self, value, &self->renderContext->YF_AApixelsize, 1.0, 2.0 );
+}
+
+static PyObject *RenderData_getYafrayAntiAliasingPixelSize( BPy_RenderData * self )
+{
+ return M_Render_getFloat( self, self->renderContext->YF_AApixelsize );
+}
+
+/* YafRay - Anti-Aliasing threshold */
+
+static int RenderData_setYafrayAntiAliasingThreshold( BPy_RenderData * self, PyObject * value )
+{
+ return M_Render_setFloat( self, value, &self->renderContext->YF_AAthreshold, 0.05, 1.0 );
+}
+
+static PyObject *RenderData_getYafrayAntiAliasingThreshold( BPy_RenderData * self )
+{
+ return M_Render_getFloat( self, self->renderContext->YF_AAthreshold );
+}
+
+/** YafRay - Number of processors to use */
+
+static int RenderData_setYafrayNumberOfProcessors( BPy_RenderData * self, PyObject * value )
+{
+ return M_Render_setInt( self, value, &self->renderContext->YF_numprocs, 1, 8 );
+}
+
+static PyObject *RenderData_getYafrayNumberOfProcessors( BPy_RenderData * self )
+{
+ return M_Render_getInt( self, self->renderContext->YF_numprocs );
+}
+
+/* YafRay - Cache occlusion/irradiance samples (faster) */
+
+static int RenderData_setYafrayGICache( BPy_RenderData * self, PyObject * value )
+{
+ return M_Render_setBooleanShort( self, value, &self->renderContext->GIcache );
+}
+
+static PyObject *RenderData_getYafrayGICache( BPy_RenderData * self )
+{
+ return M_Render_getBooleanShort( self, self->renderContext->GIcache );
+}
+
+/* YafRay - Enable/disable bumpnormals for cache
+ (faster, but no bumpmapping in total indirectly lit areas) */
+
+static int RenderData_setYafrayGICacheBumpNormals( BPy_RenderData * self, PyObject * value )
+{
+ return M_Render_setBooleanShort( self, value, &self->renderContext->YF_nobump );
+}
+
+static PyObject *RenderData_getYafrayGICacheBumpNormals( BPy_RenderData * self )
+{
+ return M_Render_getBooleanShort( self, self->renderContext->YF_nobump );
+}
+
+/* YafRay - Shadow quality, keep it under 0.95 :-) */
+
+static int RenderData_setYafrayGICacheShadowQuality( BPy_RenderData * self, PyObject * value )
+{
+ return M_Render_setFloat( self, value, &self->renderContext->GIshadowquality, 0.01, 1.0 );
+}
+
+static PyObject *RenderData_getYafrayGICacheShadowQuality( BPy_RenderData * self )
+{
+ return M_Render_getFloat( self, self->renderContext->GIshadowquality );
+}
+
+/* YafRay - Threshold to refine shadows EXPERIMENTAL. 1 = no refinement */
+
+static int RenderData_setYafrayGICacheRefinement( BPy_RenderData * self, PyObject * value )
+{
+ return M_Render_setFloat( self, value, &self->renderContext->GIrefinement, 0.001, 1.0 );
+}
+
+static PyObject *RenderData_getYafrayGICacheRefinement( BPy_RenderData * self )
+{
+ return M_Render_getFloat( self, self->renderContext->GIrefinement );
+}
+
+/* YafRay - Maximum number of pixels without samples, the lower the better and slower */
+
+static int RenderData_setYafrayGICachePixelsPerSample( BPy_RenderData * self, PyObject * value )
+{
+ return M_Render_setInt( self, value, &self->renderContext->GIpixelspersample, 1, 50 );
+}
+
+static PyObject *RenderData_getYafrayGICachePixelsPerSample( BPy_RenderData * self )
+{
+ return M_Render_getInt( self, self->renderContext->GIpixelspersample );
+}
+
+/** YafRay - Enable/disable use of global photons to help in GI */
+
+static int RenderData_setYafrayGIPhotons( BPy_RenderData * self, PyObject * value )
+{
+ return M_Render_setBooleanShort( self, value, &self->renderContext->GIphotons );
+}
+
+static PyObject *RenderData_getYafrayGIPhotons( BPy_RenderData * self )
+{
+ return M_Render_getBooleanShort( self, self->renderContext->GIphotons );
+}
+
+/** YafRay - If true the photonmap is shown directly in the render for tuning */
+
+static int RenderData_setYafrayGITunePhotons( BPy_RenderData * self, PyObject * value )
+{
+ return M_Render_setBooleanShort( self, value, &self->renderContext->GIdirect );
+}
+
+static PyObject *RenderData_getYafrayGITunePhotons( BPy_RenderData * self )
+{
+ return M_Render_getBooleanShort( self, self->renderContext->GIdirect );
+}
+
+/* (die) end */
+
+PyObject *RenderData_YafrayGIPower( BPy_RenderData * self, PyObject * args )
+{
+ if( self->renderContext->GImethod > 0 ) {
+ return M_Render_GetSetAttributeFloat( args,
+ &self->renderContext->
+ GIpower, 0.01f,
+ 100.00f );
+ } else
+ return ( EXPP_ReturnPyObjError( PyExc_StandardError,
+ "YafrayGIMethod must be set to 'SKYDOME' or 'FULL'" ) );
+}
+
+PyObject *RenderData_YafrayGIIndirPower( BPy_RenderData * self, PyObject * args )
+{
+ return M_Render_GetSetAttributeFloat( args,
+ &self->renderContext->
+ GIindirpower, 0.01f,
+ 100.00f );
+}
+
+PyObject *RenderData_YafrayGIDepth( BPy_RenderData * self, PyObject * args )
+{
+ if( self->renderContext->GImethod == 2 ) {
+ return M_Render_GetSetAttributeInt( args,
+ &self->renderContext->
+ GIdepth, 1, 100 );
+ } else
+ return ( EXPP_ReturnPyObjError( PyExc_StandardError,
+ "YafrayGIMethod must be set to 'FULL'" ) );
+}
+
+PyObject *RenderData_YafrayGICDepth( BPy_RenderData * self, PyObject * args )
+{
+ if( self->renderContext->GImethod == 2 ) {
+ return M_Render_GetSetAttributeInt( args,
+ &self->renderContext->
+ GIcausdepth, 1, 100 );
+ } else
+ return ( EXPP_ReturnPyObjError( PyExc_StandardError,
+ "YafrayGIMethod must be set to 'FULL'" ) );
+}
+
+PyObject *RenderData_EnableYafrayGICache( BPy_RenderData * self,
+ PyObject * args )
+{
+ if( self->renderContext->GImethod == 2 ) {
+ return M_Render_BitToggleShort( args, 1,
+ &self->renderContext->
+ GIcache );
+ } else
+ return ( EXPP_ReturnPyObjError( PyExc_StandardError,
+ "YafrayGIMethod must be set to 'FULL'" ) );
+}
+
+PyObject *RenderData_EnableYafrayGIPhotons( BPy_RenderData * self,
+ PyObject * args )
+{
+ if( self->renderContext->GImethod == 2 ) {
+ return M_Render_BitToggleShort( args, 1,
+ &self->renderContext->
+ GIphotons );;
+ } else
+ return ( EXPP_ReturnPyObjError( PyExc_StandardError,
+ "YafrayGIMethod must be set to 'FULL'" ) );
+}
+
+PyObject *RenderData_YafrayGIPhotonCount( BPy_RenderData * self,
+ PyObject * args )
+{
+ if( self->renderContext->GImethod == 2
+ && self->renderContext->GIphotons == 1 ) {
+ return M_Render_GetSetAttributeInt( args,
+ &self->renderContext->
+ GIphotoncount, 100000,
+ 10000000 );
+ } else
+ return ( EXPP_ReturnPyObjError( PyExc_StandardError,
+ "YafrayGIMethod must be set to 'FULL' and GIPhotons must be enabled" ) );
+}
+
+PyObject *RenderData_YafrayGIPhotonRadius( BPy_RenderData * self,
+ PyObject * args )
+{
+ if( self->renderContext->GImethod == 2
+ && self->renderContext->GIphotons == 1 ) {
+ return M_Render_GetSetAttributeFloat( args,
+ &self->renderContext->
+ GIphotonradius, 0.00001f,
+ 100.0f );
+ } else
+ return ( EXPP_ReturnPyObjError( PyExc_StandardError,
+ "YafrayGIMethod must be set to 'FULL' and GIPhotons must be enabled" ) );
+}
+
+PyObject *RenderData_YafrayGIPhotonMixCount( BPy_RenderData * self,
+ PyObject * args )
+{
+ if( self->renderContext->GImethod == 2
+ && self->renderContext->GIphotons == 1 ) {
+ return M_Render_GetSetAttributeInt( args,
+ &self->renderContext->
+ GImixphotons, 100, 1000 );
+ } else
+ return ( EXPP_ReturnPyObjError( PyExc_StandardError,
+ "YafrayGIMethod must be set to 'FULL' and GIPhotons must be enabled" ) );
+}
+
+PyObject *RenderData_EnableYafrayGITunePhotons( BPy_RenderData * self,
+ PyObject * args )
+{
+ if( self->renderContext->GImethod == 2
+ && self->renderContext->GIphotons == 1 ) {
+ return M_Render_BitToggleShort( args, 1,
+ &self->renderContext->
+ GIdirect );;
+ } else
+ return ( EXPP_ReturnPyObjError( PyExc_StandardError,
+ "YafrayGIMethod must be set to 'FULL' and GIPhotons must be enabled" ) );
+}
+
+PyObject *RenderData_YafrayGIShadowQuality( BPy_RenderData * self,
+ PyObject * args )
+{
+ if( self->renderContext->GImethod == 2
+ && self->renderContext->GIcache == 1 ) {
+ return M_Render_GetSetAttributeFloat( args,
+ &self->renderContext->
+ GIshadowquality, 0.01f,
+ 1.0f );
+ } else
+ return ( EXPP_ReturnPyObjError( PyExc_StandardError,
+ "YafrayGIMethod must be set to 'FULL' and GICache must be enabled" ) );
+}
+
+PyObject *RenderData_YafrayGIPixelsPerSample( BPy_RenderData * self,
+ PyObject * args )
+{
+ if( self->renderContext->GImethod == 2
+ && self->renderContext->GIcache == 1 ) {
+ return M_Render_GetSetAttributeInt( args,
+ &self->renderContext->
+ GIpixelspersample, 1, 50 );
+ } else
+ return ( EXPP_ReturnPyObjError( PyExc_StandardError,
+ "YafrayGIMethod must be set to 'FULL' and GICache must be enabled" ) );
+}
+
+PyObject *RenderData_YafrayGIRefinement( BPy_RenderData * self,
+ PyObject * args )
+{
+ if( self->renderContext->GImethod == 2
+ && self->renderContext->GIcache == 1 ) {
+ return M_Render_GetSetAttributeFloat( args,
+ &self->renderContext->
+ GIrefinement, 0.001f,
+ 1.0f );
+ } else
+ return ( EXPP_ReturnPyObjError( PyExc_StandardError,
+ "YafrayGIMethod must be set to 'FULL' and GICache must be enabled" ) );
+}
+
+PyObject *RenderData_YafrayRayBias( BPy_RenderData * self, PyObject * args )
+{
+ return M_Render_GetSetAttributeFloat( args,
+ &self->renderContext->YF_raybias,
+ 0.0f, 10.0f );
+}
+
+PyObject *RenderData_YafrayRayDepth( BPy_RenderData * self, PyObject * args )
+{
+ return M_Render_GetSetAttributeInt( args,
+ &self->renderContext->YF_raydepth,
+ 1, 80 );
+}
+
+PyObject *RenderData_YafrayGamma( BPy_RenderData * self, PyObject * args )
+{
+ return M_Render_GetSetAttributeFloat( args,
+ &self->renderContext->YF_gamma,
+ 0.001f, 5.0f );
+}
+
+PyObject *RenderData_YafrayExposure( BPy_RenderData * self, PyObject * args )
+{
+ return M_Render_GetSetAttributeFloat( args,
+ &self->renderContext->
+ YF_exposure, 0.0f, 10.0f );
+}
+
+PyObject *RenderData_YafrayProcessorCount( BPy_RenderData * self,
+ PyObject * args )
+{
+ return M_Render_GetSetAttributeInt( args,
+ &self->renderContext->YF_numprocs,
+ 1, 8 );
+}
+
+PyObject *RenderData_EnableGameFrameStretch( BPy_RenderData * self )
+{
+ self->scene->framing.type = SCE_GAMEFRAMING_SCALE;
+ Py_RETURN_NONE;
+}
+
+PyObject *RenderData_EnableGameFrameExpose( BPy_RenderData * self )
+{
+ self->scene->framing.type = SCE_GAMEFRAMING_EXTEND;
+ Py_RETURN_NONE;
+}
+
+PyObject *RenderData_EnableGameFrameBars( BPy_RenderData * self )
+{
+ self->scene->framing.type = SCE_GAMEFRAMING_BARS;
+ Py_RETURN_NONE;
+}
+
+PyObject *RenderData_SetGameFrameColor( BPy_RenderData * self,
+ PyObject * args )
+{
+ float red = 0.0f;
+ float green = 0.0f;
+ float blue = 0.0f;
+
+ if( !PyArg_ParseTuple( args, "fff", &red, &green, &blue ) )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected three floats" ) );
+
+ if( red < 0 || red > 1 )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "value out of range 0.000 - 1.000 (red)" ) );
+ if( green < 0 || green > 1 )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "value out of range 0.000 - 1.000 (green)" ) );
+ if( blue < 0 || blue > 1 )
+ return ( EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "value out of range 0.000 - 1.000 (blue)" ) );
+
+ self->scene->framing.col[0] = red;
+ self->scene->framing.col[1] = green;
+ self->scene->framing.col[2] = blue;
+
+ Py_RETURN_NONE;
+}
+
+PyObject *RenderData_GetGameFrameColor( BPy_RenderData * self )
+{
+ char rgb[24];
+
+ sprintf( rgb, "[%.3f,%.3f,%.3f]", self->scene->framing.col[0],
+ self->scene->framing.col[1], self->scene->framing.col[2] );
+ return PyString_FromString( rgb );
+}
+
+#ifdef __sgi
+PyObject *RenderData_SGIMaxsize( BPy_RenderData * self, PyObject * args )
+{
+ return M_Render_GetSetAttributeShort( args,
+ &self->renderContext->maximsize,
+ 0, 500 );
+}
+
+PyObject *RenderData_EnableSGICosmo( BPy_RenderData *self, PyObject *args )
+{
+ return M_Render_BitToggleInt( args, R_COSMO,
+ &self->renderContext->mode );
+}
+#else
+PyObject *RenderData_SGIMaxsize( void )
+{
+ return EXPP_ReturnPyObjError( PyExc_StandardError,
+ "SGI is not defined on this machine" );
+}
+
+PyObject *RenderData_EnableSGICosmo( void )
+{
+ return EXPP_ReturnPyObjError( PyExc_StandardError,
+ "SGI is not defined on this machine" );
+}
+#endif
+
+PyObject *RenderData_OldMapValue( BPy_RenderData * self, PyObject * args )
+{
+ PyObject *tmp = M_Render_GetSetAttributeInt(args,
+ &self->renderContext->framapto, 1, 900);
+ self->renderContext->framelen =
+ (float)self->renderContext->framapto / self->renderContext->images;
+ return tmp;
+}
+
+PyObject *RenderData_NewMapValue( BPy_RenderData * self, PyObject * args )
+{
+ PyObject *tmp = M_Render_GetSetAttributeInt(args,
+ &self->renderContext->images, 1, 900);
+ self->renderContext->framelen =
+ (float)self->renderContext->framapto / self->renderContext->images;
+ return tmp;
+}
+
+static PyObject *RenderData_getTimeCode( BPy_RenderData * self) {
+ char tc[12];
+ int h, m, s, cfa;
+ double fps;
+
+ fps = (double) self->renderContext->frs_sec /
+ self->renderContext->frs_sec_base;
+ cfa = self->renderContext->cfra-1;
+ s = cfa / fps;
+ m = s / 60;
+ h = m / 60;
+ if( h > 99 )
+ return PyString_FromString("Time Greater than 99 Hours!");
+
+ sprintf( tc, "%02d:%02d:%02d:%02d", h%60, m%60, s%60,
+ (int) (cfa - ((int) (cfa / fps) * fps)));
+ return PyString_FromString(tc);
+}
+
+/***************************************************************************/
+/* generic handlers for getting/setting attributes */
+/***************************************************************************/
+
+/*
+ * get floating point attributes
+ */
+
+static PyObject *RenderData_getFloatAttr( BPy_RenderData *self, void *type )
+{
+ float param;
+
+ switch( (int)type ) {
+ case EXPP_RENDER_ATTR_GAUSSFILTER:
+ param = self->renderContext->gauss;
+ break;
+ case EXPP_RENDER_ATTR_MBLURFACTOR:
+ param = self->renderContext->blurfac;
+ break;
+ case EXPP_RENDER_ATTR_FPS_BASE:
+ param = self->renderContext->frs_sec_base;
+ break;
+ default:
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "undefined type constant in RenderData_getFloatAttr" );
+ }
+ return PyFloat_FromDouble( param );
+}
+
+/*
+ * set floating point attributes which require clamping
+ */
+
+static int RenderData_setFloatAttrClamp( BPy_RenderData *self, PyObject *value,
+ void *type )
+{
+ float *param;
+ float min, max;
+
+ switch( (int)type ) {
+ case EXPP_RENDER_ATTR_GAUSSFILTER:
+ min = 0.5f;
+ max = 1.5f;
+ param = &self->renderContext->gauss;
+ break;
+ case EXPP_RENDER_ATTR_MBLURFACTOR:
+ min = 0.01f;
+ max = 5.0f;
+ param = &self->renderContext->blurfac;
+ break;
+ case EXPP_RENDER_ATTR_FPS_BASE:
+ min = 1.0f;
+ max = 120.0f;
+ param = &self->renderContext->frs_sec_base;
+ break;
+ default:
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "undefined type constant in RenderData_setFloatAttrClamp" );
+ }
+ return EXPP_setFloatClamped( value, param, min, max );
+}
+
+/*
+ * get integer attributes
+ */
+
+static PyObject *RenderData_getIValueAttr( BPy_RenderData *self, void *type )
+{
+ long param;
+
+ switch( (int)type ) {
+ case EXPP_RENDER_ATTR_XPARTS:
+ param = (long)self->renderContext->xparts;
+ break;
+ case EXPP_RENDER_ATTR_YPARTS:
+ param = (long)self->renderContext->yparts;
+ break;
+ case EXPP_RENDER_ATTR_ASPECTX:
+ param = (long)self->renderContext->xasp;
+ break;
+ case EXPP_RENDER_ATTR_ASPECTY:
+ param = (long)self->renderContext->yasp;
+ break;
+ case EXPP_RENDER_ATTR_CFRAME:
+ param = (long)self->renderContext->cfra;
+ break;
+ case EXPP_RENDER_ATTR_EFRAME:
+ param = (long)self->renderContext->efra;
+ break;
+ case EXPP_RENDER_ATTR_SFRAME:
+ param = (long)self->renderContext->sfra;
+ break;
+ case EXPP_RENDER_ATTR_FPS:
+ param = self->renderContext->frs_sec;
+ break;
+ case EXPP_RENDER_ATTR_SIZEX:
+ param = self->renderContext->xsch;
+ break;
+ case EXPP_RENDER_ATTR_SIZEY:
+ param = self->renderContext->ysch;
+ break;
+ default:
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "undefined type constant in RenderData_setIValueAttrClamp" );
+ }
+ return PyInt_FromLong( param );
+}
+
+/*
+ * set integer attributes which require clamping
+ */
+
+static int RenderData_setIValueAttrClamp( BPy_RenderData *self, PyObject *value,
+ void *type )
+{
+ void *param;
+ int min, max, size;
+
+ switch( (int)type ) {
+ case EXPP_RENDER_ATTR_XPARTS:
+ min = 1;
+ max = 512;
+ size = 'h';
+ param = &self->renderContext->xparts;
+ break;
+ case EXPP_RENDER_ATTR_YPARTS:
+ min = 1;
+ max = 64;
+ size = 'h';
+ param = &self->renderContext->yparts;
+ break;
+ case EXPP_RENDER_ATTR_ASPECTX:
+ min = 1;
+ max = 200;
+ size = 'h';
+ param = &self->renderContext->xasp;
+ break;
+ case EXPP_RENDER_ATTR_ASPECTY:
+ min = 1;
+ max = 200;
+ size = 'h';
+ param = &self->renderContext->yasp;
+ break;
+ case EXPP_RENDER_ATTR_CFRAME:
+ min = 1;
+ max = MAXFRAME;
+ size = 'h';
+ param = &self->renderContext->cfra;
+ break;
+ case EXPP_RENDER_ATTR_EFRAME:
+ min = 1;
+ max = MAXFRAME;
+ size = 'h';
+ param = &self->renderContext->efra;
+ break;
+ case EXPP_RENDER_ATTR_SFRAME:
+ min = 1;
+ max = MAXFRAME;
+ size = 'h';
+ param = &self->renderContext->sfra;
+ break;
+ case EXPP_RENDER_ATTR_FPS:
+ min = 1;
+ max = 120;
+ size = 'h';
+ param = &self->renderContext->frs_sec;
+ break;
+ case EXPP_RENDER_ATTR_SIZEX:
+ min = 4;
+ max = 10000;
+ size = 'h';
+ param = &self->renderContext->xsch;
+ break;
+ case EXPP_RENDER_ATTR_SIZEY:
+ min = 4;
+ max = 10000;
+ size = 'h';
+ param = &self->renderContext->ysch;
+ break;
+ default:
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "undefined type constant in RenderData_setIValueAttrClamp" );
+ }
+ return EXPP_setIValueClamped( value, param, min, max, size );
+}
+
+/***************************************************************************/
+/* handlers for other getting/setting attributes */
+/***************************************************************************/
+
+static PyObject *RenderData_getModeBit( BPy_RenderData *self, void* type )
+{
+ return EXPP_getBitfield( &self->renderContext->mode,
+ (int)type, 'i' );
+}
+
+static int RenderData_setModeBit( BPy_RenderData* self, PyObject *value,
+ void* type )
+{
+ return EXPP_setBitfield( value, &self->renderContext->mode,
+ (int)type, 'i' );
+}
+
+#define MODE_MASK ( R_OSA | R_SHADOW | R_GAMMA | R_ENVMAP | R_EDGE | \
+ R_FIELDS | R_FIELDSTILL | R_RADIO | R_BORDER | R_PANORAMA | R_CROP | \
+ R_ODDFIELD | R_MBLUR | R_RAYTRACE | R_THREADS )
+
+static PyObject *RenderData_getMode( BPy_RenderData *self )
+{
+ return PyInt_FromLong( (long)(self->renderContext->mode & MODE_MASK) );
+}
+
+static int RenderData_setMode( BPy_RenderData* self, PyObject *arg )
+{
+ int value;
+
+ if( !PyInt_Check( arg ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected int argument" );
+
+ value = PyInt_AsLong( arg );
+ if( value & ~MODE_MASK )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "unexpected bits set in argument" );
+
+ self->renderContext->mode = (short)value;
+ EXPP_allqueue( REDRAWBUTSSCENE, 0 );
+
+ return 0;
+}
+
+static PyObject *RenderData_getSceModeBits( BPy_RenderData *self, void* type )
+{
+ return EXPP_getBitfield( &self->renderContext->scemode, (int)type, 'h' );
+}
+
+static int RenderData_setSceModeBits( BPy_RenderData* self, PyObject *value,
+ void* type )
+{
+ return EXPP_setBitfield( value, &self->renderContext->scemode,
+ (int)type, 'h' );
+}
+
+static PyObject *RenderData_getSceMode( BPy_RenderData *self )
+{
+ return PyInt_FromLong ( (long)self->renderContext->scemode );
+}
+
+static int RenderData_setSceMode( BPy_RenderData* self, PyObject *arg )
+{
+ int value;
+
+ if( !PyInt_Check( arg ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected int argument" );
+
+ value = PyInt_AsLong( arg );
+ if( value & ~( R_EXTENSION | R_DOSEQ ) )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "unexpected bits set in argument" );
+
+ self->renderContext->scemode = (short)value;
+ EXPP_allqueue( REDRAWBUTSSCENE, 0 );
+
+ return 0;
+}
+
+static PyObject *RenderData_getFramingType( BPy_RenderData *self )
+{
+ return PyInt_FromLong( (long)self->scene->framing.type );
+}
+
+static int RenderData_setFramingType( BPy_RenderData *self, PyObject *value )
+{
+ return EXPP_setIValueRange( value, &self->scene->framing.type,
+ SCE_GAMEFRAMING_BARS, SCE_GAMEFRAMING_SCALE, 'b' );
+}
+
+static PyObject *RenderData_getEdgeColor( BPy_RenderData * self )
+{
+ return Py_BuildValue( "[fff]", self->renderContext->edgeR,
+ self->renderContext->edgeG, self->renderContext->edgeB );
+}
+
+static int RenderData_setEdgeColor( BPy_RenderData * self, PyObject * args )
+{
+ float red, green, blue;
+
+ /* if we get a list, convert to a tuple; otherwise hope for the best */
+ if( PyList_Check( args ) )
+ args = PySequence_Tuple( args );
+ else
+ Py_INCREF( args );
+
+ if( !PyArg_ParseTuple( args, "fff", &red, &green, &blue ) ) {
+ Py_DECREF( args );
+ return EXPP_ReturnIntError( PyExc_TypeError, "expected three floats" );
+ }
+ Py_DECREF( args );
+
+ self->renderContext->edgeR = EXPP_ClampFloat( red, 0.0, 1.0 );
+ self->renderContext->edgeG = EXPP_ClampFloat( green, 0.0, 1.0 );
+ self->renderContext->edgeB = EXPP_ClampFloat( blue, 0.0, 1.0 );
+ return 0;
+}
+
+static PyObject *RenderData_getOSALevel( BPy_RenderData * self )
+{
+ return PyInt_FromLong( (long)self->renderContext->osa );
+}
+
+static PyObject *RenderData_getRenderer( BPy_RenderData * self )
+{
+ return PyInt_FromLong( (long)self->renderContext->renderer );
+}
+
+static PyObject *RenderData_getImageType( BPy_RenderData * self )
+{
+ return PyInt_FromLong( (long) self->renderContext->imtype );
+}
+
+static int RenderData_setGameFrameColor( BPy_RenderData * self,
+ PyObject * args )
+{
+ float red, green, blue;
+
+ /* if we get a list, convert to a tuple; otherwise hope for the best */
+ if( PyList_Check( args ) )
+ args = PySequence_Tuple( args );
+ else
+ Py_INCREF( args );
+
+ if( !PyArg_ParseTuple( args, "fff", &red, &green, &blue ) ) {
+ Py_DECREF( args );
+ return EXPP_ReturnIntError( PyExc_TypeError, "expected three floats" );
+ }
+ Py_DECREF( args );
+
+ self->scene->framing.col[0] = EXPP_ClampFloat( red, 0.0, 1.0 );
+ self->scene->framing.col[1] = EXPP_ClampFloat( green, 0.0, 1.0 );
+ self->scene->framing.col[2] = EXPP_ClampFloat( blue, 0.0, 1.0 );
+ return 0;
+}
+
+static PyObject *RenderData_getGameFrameColor( BPy_RenderData * self )
+{
+ return Py_BuildValue( "[fff]", self->scene->framing.col[0],
+ self->scene->framing.col[1], self->scene->framing.col[2] );
+}
+
+static PyObject *RenderData_getBackbuf( BPy_RenderData * self )
+{
+ return EXPP_getBitfield( &self->renderContext->bufflag,
+ R_BACKBUF, 'h' );
+}
+
+static int RenderData_setBackbuf( BPy_RenderData* self, PyObject *value )
+{
+ return EXPP_setBitfield( value, &self->renderContext->bufflag,
+ R_BACKBUF, 'h' );
+}
+
+static int RenderData_setImagePlanes( BPy_RenderData *self, PyObject *value )
+{
+ int depth;
+ char *errstr = "expected int argument of 8, 24, or 32";
+
+ if( !PyInt_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError, errstr );
+
+ depth = PyInt_AsLong( value );
+ if( depth != 8 && depth != 24 && depth != 32 )
+ return EXPP_ReturnIntError( PyExc_ValueError, errstr );
+
+ self->renderContext->planes = (short)depth;
+
+ return 0;
+}
+
+static PyObject *RenderData_getImagePlanes( BPy_RenderData * self )
+{
+ return PyInt_FromLong( (long) self->renderContext->planes );
+}
+
+static int RenderData_setAlphaMode( BPy_RenderData *self, PyObject *value )
+{
+ return EXPP_setIValueRange( value, &self->renderContext->alphamode,
+ R_ADDSKY, R_ALPHAKEY, 'h' );
+}
+
+static PyObject *RenderData_getAlphaMode( BPy_RenderData * self )
+{
+ return PyInt_FromLong( (long) self->renderContext->alphamode );
+}
+
+static PyObject *RenderData_getDisplayMode( void )
+{
+ return PyInt_FromLong( (long) G.displaymode );
+}
+
+static int RenderData_setDisplayMode( BPy_RenderData *self,
+ PyObject *value )
+{
+ return EXPP_setIValueRange( value, &G.displaymode,
+ R_DISPLAYIMAGE, R_DISPLAYSCREEN, 'h' );
+}
+
+static PyObject *RenderData_getRenderPath( BPy_RenderData * self )
+{
+ return PyString_FromString( self->renderContext->pic );
+}
+
+static int RenderData_setRenderPath( BPy_RenderData * self, PyObject * value )
+{
+ char *name;
+
+ name = PyString_AsString( value );
+ if( !name )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a string" );
+
+ if( strlen( name ) >= sizeof(self->renderContext->pic) )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "render path is too long" );
+
+ strcpy( self->renderContext->pic, name );
+ EXPP_allqueue( REDRAWBUTSSCENE, 0 );
+
+ return 0;
+}
+
+PyObject *RenderData_getBackbufPath( BPy_RenderData * self )
+{
+ return PyString_FromString( self->renderContext->backbuf );
+}
+
+static int RenderData_setBackbufPath( BPy_RenderData *self, PyObject *value )
+{
+ char *name;
+ Image *ima;
+
+ name = PyString_AsString( value );
+ if( !name )
+ return EXPP_ReturnIntError( PyExc_TypeError, "expected a string" );
+
+ if( strlen( name ) >= sizeof(self->renderContext->backbuf) )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "backbuf path is too long" );
+
+ strcpy( self->renderContext->backbuf, name );
+ EXPP_allqueue( REDRAWBUTSSCENE, 0 );
+
+ ima = BKE_add_image_file( name );
+ if( ima )
+ BKE_image_signal( ima, NULL, IMA_SIGNAL_RELOAD );
+
+ return 0;
+}
+
+PyObject *RenderData_getFtypePath( BPy_RenderData * self )
+{
+ return PyString_FromString( self->renderContext->ftype );
+}
+
+static int RenderData_setFtypePath( BPy_RenderData *self, PyObject *value )
+{
+ char *name;
+
+ name = PyString_AsString( value );
+ if( !name )
+ return EXPP_ReturnIntError( PyExc_TypeError, "expected a string" );
+
+ if( strlen( name ) >= sizeof(self->renderContext->ftype) )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "ftype path is too long" );
+
+ strcpy( self->renderContext->ftype, name );
+ EXPP_allqueue( REDRAWBUTSSCENE, 0 );
+
+ return 0;
+}
+
+PyObject *RenderData_getRenderWinSize( BPy_RenderData * self )
+{
+ return PyInt_FromLong( (long) self->renderContext->size );
+}
+
+static int RenderData_setRenderWinSize( BPy_RenderData *self, PyObject *value )
+{
+ int size;
+ char *errstr = "expected int argument of 25, 50, 75, or 100";
+
+ if( !PyInt_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError, errstr );
+
+ size = PyInt_AsLong( value );
+ if( size != 25 && size != 50 && size != 75 && size != 100 )
+ return EXPP_ReturnIntError( PyExc_ValueError, errstr );
+
+ self->renderContext->size = (short)size;
+ EXPP_allqueue( REDRAWBUTSSCENE, 0 );
+
+ return 0;
+}
+
+static PyObject *RenderData_getMapOld( BPy_RenderData *self )
+{
+ return PyInt_FromLong( (long)self->renderContext->framapto );
+}
+
+static int RenderData_setMapOld( BPy_RenderData *self, PyObject *value )
+{
+ int result = EXPP_setIValueClamped( value, &self->renderContext->framapto,
+ 1, 900, 'h' );
+ self->renderContext->framelen =
+ (float)self->renderContext->framapto / self->renderContext->images;
+ return result;
+}
+
+static PyObject *RenderData_getMapNew( BPy_RenderData *self )
+{
+ return PyInt_FromLong( (long)self->renderContext->images );
+}
+
+static int RenderData_setMapNew( BPy_RenderData *self, PyObject *value )
+{
+ int result = EXPP_setIValueClamped( value, &self->renderContext->images,
+ 1, 900, 'h' );
+ self->renderContext->framelen =
+ (float)self->renderContext->framapto / self->renderContext->images;
+ return result;
+}
+
+static PyObject *RenderData_getSet( BPy_RenderData *self )
+{
+ if( self->scene->set )
+ return Scene_CreatePyObject( self->scene->set );
+ Py_RETURN_NONE;
+}
+
+static int RenderData_setSet( BPy_RenderData *self, PyObject *value )
+{
+ BPy_Scene *sc;
+
+ /* if "None", delete the link to the scene */
+ if( value == Py_None ) {
+ self->scene->set = NULL;
+ return 0;
+ }
+
+ /* be sure argument is a Scene */
+ if( !BPy_Scene_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected Scene as argument" );
+
+ /* check for attempt to link to ourselves */
+ sc = (BPy_Scene *)value;
+ if( self->scene == sc->scene )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "cannot link a scene to itself" );
+
+ /*
+ * Accept the set link, then check for a circular link. If circular link
+ * exists, scene_check_setscene() sets self->scene->set to NULL.
+ */
+
+ self->scene->set = sc->scene;
+ if( !scene_check_setscene( self->scene ) )
+ return EXPP_ReturnIntError( PyExc_ValueError,
+ "linking scene would create a cycle" );
+
+ return 0;
+}
+
+
+PyObject *RenderData_getThreads( BPy_RenderData * self )
+{
+ return PyInt_FromLong( (long) self->renderContext->threads );
+}
+
+static int RenderData_setThreads( BPy_RenderData *self, PyObject *value )
+{
+ int threads;
+
+ if( !PyInt_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError, "Error, threads must be an int" );
+
+ threads = PyInt_AsLong( value );
+ if (threads<1) threads = 1;
+ else if (threads>8) threads = 8;
+
+ self->renderContext->threads = (short)threads;
+ EXPP_allqueue( REDRAWBUTSSCENE, 0 );
+ return 0;
+}
+
+/***************************************************************************/
+/* BPy_RenderData attribute def */
+/***************************************************************************/
+static PyGetSetDef BPy_RenderData_getseters[] = {
+ {"oversampling",
+ (getter)RenderData_getModeBit, (setter)RenderData_setModeBit,
+ "Oversampling (anti-aliasing) enabled",
+ (void *)R_OSA},
+ {"shadow",
+ (getter)RenderData_getModeBit, (setter)RenderData_setModeBit,
+ "Shadow calculation enabled",
+ (void *)R_SHADOW},
+ {"gammaCorrection",
+ (getter)RenderData_getModeBit, (setter)RenderData_setModeBit,
+ "Gamma correction enabled",
+ (void *)R_GAMMA},
+/* R_ORTHO unused */
+ {"environmentMap",
+ (getter)RenderData_getModeBit, (setter)RenderData_setModeBit,
+ "Environment map rendering enabled",
+ (void *)R_ENVMAP},
+ {"toonShading",
+ (getter)RenderData_getModeBit, (setter)RenderData_setModeBit,
+ "Toon edge shading enabled",
+ (void *)R_EDGE},
+ {"fieldRendering",
+ (getter)RenderData_getModeBit, (setter)RenderData_setModeBit,
+ "Field rendering enabled",
+ (void *)R_FIELDS},
+ {"fieldTimeDisable",
+ (getter)RenderData_getModeBit, (setter)RenderData_setModeBit,
+ "Time difference in field calculations disabled ('X' in UI)",
+ (void *)R_FIELDSTILL},
+ {"radiosityRender",
+ (getter)RenderData_getModeBit, (setter)RenderData_setModeBit,
+ "Radiosity rendering enabled",
+ (void *)R_RADIO},
+ {"borderRender",
+ (getter)RenderData_getModeBit, (setter)RenderData_setModeBit,
+ "Small cut-out rendering enabled",
+ (void *)R_BORDER},
+ {"panorama",
+ (getter)RenderData_getModeBit, (setter)RenderData_setModeBit,
+ "Panorama rendering enabled",
+ (void *)R_PANORAMA},
+ {"crop",
+ (getter)RenderData_getModeBit, (setter)RenderData_setModeBit,
+ "Crop image during border renders",
+ (void *)R_CROP},
+/* R_COSMO unsupported */
+ {"oddFieldFirst",
+ (getter)RenderData_getModeBit, (setter)RenderData_setModeBit,
+ "Odd field first rendering enabled",
+ (void *)R_ODDFIELD},
+ {"motionBlur",
+ (getter)RenderData_getModeBit, (setter)RenderData_setModeBit,
+ "Motion blur enabled",
+ (void *)R_MBLUR},
+ {"rayTracing",
+ (getter)RenderData_getModeBit, (setter)RenderData_setModeBit,
+ "Ray tracing enabled",
+ (void *)R_RAYTRACE},
+/* R_GAUSS unused */
+/* R_FBUF unused */
+/* R_THREADS unused */
+ {"threads",
+ (getter)RenderData_getThreads, (setter)RenderData_setThreads,
+ "Number of threads used to render",
+ NULL},
+/* R_SPEED unused */
+ {"mode",
+ (getter)RenderData_getMode, (setter)RenderData_setMode,
+ "Mode bitfield",
+ NULL},
+
+ /* scene modes */
+ {"sequencer",
+ (getter)RenderData_getSceModeBits, (setter)RenderData_setSceModeBits,
+ "'Do Sequence' enabled",
+ (void *)R_DOSEQ},
+ {"extensions",
+ (getter)RenderData_getSceModeBits, (setter)RenderData_setSceModeBits,
+ "Add extensions to output (when rendering animations) enabled",
+ (void *)R_EXTENSION},
+ {"compositor",
+ (getter)RenderData_getSceModeBits, (setter)RenderData_setSceModeBits,
+ "'Do Compositor' enabled.",
+ (void *)R_DOCOMP},
+ {"freeImages",
+ (getter)RenderData_getSceModeBits, (setter)RenderData_setSceModeBits,
+ "Free texture images after render.",
+ (void *)R_FREE_IMAGE},
+ {"singleLayer",
+ (getter)RenderData_getSceModeBits, (setter)RenderData_setSceModeBits,
+ "Only render the active layer.",
+ (void *)R_SINGLE_LAYER},
+ {"saveBuffers",
+ (getter)RenderData_getSceModeBits, (setter)RenderData_setSceModeBits,
+ "Save render buffers to disk while rendering, saves memory.",
+ (void *)R_EXR_TILE_FILE},
+ {"compositeFree",
+ (getter)RenderData_getSceModeBits, (setter)RenderData_setSceModeBits,
+ "Free nodes that are not used while composite.",
+ (void *)R_COMP_FREE},
+
+ {"sceneMode",
+ (getter)RenderData_getSceMode, (setter)RenderData_setSceMode,
+ "Scene mode bitfield",
+ NULL},
+/* R_BG_RENDER unused */
+
+ {"gameFrame",
+ (getter)RenderData_getFramingType, (setter)RenderData_setFramingType,
+ "Game framing type",
+ NULL},
+
+ {"renderPath",
+ (getter)RenderData_getRenderPath, (setter)RenderData_setRenderPath,
+ "The path to output the rendered images to",
+ NULL},
+ {"backbufPath",
+ (getter)RenderData_getBackbufPath, (setter)RenderData_setBackbufPath,
+ "Path to a background image (setting loads image)",
+ NULL},
+ {"ftypePath",
+ (getter)RenderData_getFtypePath, (setter)RenderData_setFtypePath,
+ "The path to Ftype file",
+ NULL},
+ {"edgeColor",
+ (getter)RenderData_getEdgeColor, (setter)RenderData_setEdgeColor,
+ "RGB color triplet for edges in Toon shading",
+ NULL},
+ {"OSALevel",
+ (getter)RenderData_getOSALevel, (setter)RenderData_setOSALevel,
+ "Oversampling (anti-aliasing) level",
+ NULL},
+ {"renderwinSize",
+ (getter)RenderData_getRenderWinSize, (setter)RenderData_setRenderWinSize,
+ "Size of the rendering window (25, 50, 75, or 100)",
+ NULL},
+ {"border",
+ (getter)RenderData_getBorder, (setter)RenderData_setBorder,
+ "The border for border rendering",
+ NULL},
+ {"timeCode",
+ (getter)RenderData_getTimeCode, (setter)NULL,
+ "Get the current frame in HH:MM:SS:FF format",
+ NULL},
+ {"renderer",
+ (getter)RenderData_getRenderer, (setter)RenderData_setRenderer,
+ "Rendering engine choice",
+ NULL},
+ {"imageType",
+ (getter)RenderData_getImageType, (setter)RenderData_setImageType,
+ "File format for saving images",
+ NULL},
+ {"gameFrameColor",
+ (getter)RenderData_getGameFrameColor,(setter)RenderData_setGameFrameColor,
+ "RGB color triplet for bars",
+ NULL},
+ {"backbuf",
+ (getter)RenderData_getBackbuf, (setter)RenderData_setBackbuf,
+ "Backbuffer image enabled",
+ NULL},
+ {"imagePlanes",
+ (getter)RenderData_getImagePlanes, (setter)RenderData_setImagePlanes,
+ "Image depth (8, 24, or 32 bits)",
+ NULL},
+ {"alphaMode",
+ (getter)RenderData_getAlphaMode, (setter)RenderData_setAlphaMode,
+ "Setting for sky/background.",
+ NULL},
+ {"displayMode",
+ (getter)RenderData_getDisplayMode, (setter)RenderData_setDisplayMode,
+ "Render output in separate window or 3D view",
+ NULL},
+
+ {"xParts",
+ (getter)RenderData_getIValueAttr, (setter)RenderData_setIValueAttrClamp,
+ "Number of horizontal parts for image render",
+ (void *)EXPP_RENDER_ATTR_XPARTS},
+ {"yParts",
+ (getter)RenderData_getIValueAttr, (setter)RenderData_setIValueAttrClamp,
+ "Number of vertical parts for image render",
+ (void *)EXPP_RENDER_ATTR_YPARTS},
+ {"aspectX",
+ (getter)RenderData_getIValueAttr, (setter)RenderData_setIValueAttrClamp,
+ "Horizontal aspect ratio",
+ (void *)EXPP_RENDER_ATTR_ASPECTX},
+ {"aspectY",
+ (getter)RenderData_getIValueAttr, (setter)RenderData_setIValueAttrClamp,
+ "Vertical aspect ratio",
+ (void *)EXPP_RENDER_ATTR_ASPECTY},
+ {"cFrame",
+ (getter)RenderData_getIValueAttr, (setter)RenderData_setIValueAttrClamp,
+ "The current frame for rendering",
+ (void *)EXPP_RENDER_ATTR_CFRAME},
+ {"sFrame",
+ (getter)RenderData_getIValueAttr, (setter)RenderData_setIValueAttrClamp,
+ "Starting frame for rendering",
+ (void *)EXPP_RENDER_ATTR_SFRAME},
+ {"eFrame",
+ (getter)RenderData_getIValueAttr, (setter)RenderData_setIValueAttrClamp,
+ "Ending frame for rendering",
+ (void *)EXPP_RENDER_ATTR_EFRAME},
+ {"fps",
+ (getter)RenderData_getIValueAttr, (setter)RenderData_setIValueAttrClamp,
+ "Frames per second",
+ (void *)EXPP_RENDER_ATTR_FPS},
+ {"fps_base",
+ (getter)RenderData_getFloatAttr, (setter)RenderData_setFloatAttrClamp,
+ "Frames per second base",
+ (void *)EXPP_RENDER_ATTR_FPS_BASE},
+ {"sizeX",
+ (getter)RenderData_getIValueAttr, (setter)RenderData_setIValueAttrClamp,
+ "Image width (in pixels)",
+ (void *)EXPP_RENDER_ATTR_SIZEX},
+ {"sizeY",
+ (getter)RenderData_getIValueAttr, (setter)RenderData_setIValueAttrClamp,
+ "Image height (in pixels)",
+ (void *)EXPP_RENDER_ATTR_SIZEY},
+
+ {"gaussFilter",
+ (getter)RenderData_getFloatAttr, (setter)RenderData_setFloatAttrClamp,
+ "Gauss filter size",
+ (void *)EXPP_RENDER_ATTR_GAUSSFILTER},
+ {"mblurFactor",
+ (getter)RenderData_getFloatAttr, (setter)RenderData_setFloatAttrClamp,
+ "Motion blur factor",
+ (void *)EXPP_RENDER_ATTR_MBLURFACTOR},
+ {"mapOld",
+ (getter)RenderData_getMapOld, (setter)RenderData_setMapOld,
+ "Number of frames the Map Old will last",
+ NULL},
+ {"mapNew",
+ (getter)RenderData_getMapNew, (setter)RenderData_setMapNew,
+ "New mapping value (in frames)",
+ NULL},
+ {"set",
+ (getter)RenderData_getSet, (setter)RenderData_setSet,
+ "Scene link 'set' value",
+ NULL},
+
+ {"yafrayGIMethod",
+ (getter)RenderData_getYafrayGIMethod, (setter)RenderData_setYafrayGIMethod,
+ "Global illumination method",
+ NULL},
+ {"yafrayGIQuality",
+ (getter)RenderData_getYafrayGIQuality, (setter)RenderData_setYafrayGIQuality,
+ "Global Illumination quality",
+ NULL},
+ {"yafrayExportToXML",
+ (getter)RenderData_getYafrayExportToXML, (setter)RenderData_setYafrayExportToXML,
+ "If true export to an xml file and call yafray instead of plugin",
+ NULL},
+ {"yafrayAutoAntiAliasing",
+ (getter)RenderData_getYafrayAutoAntiAliasing, (setter)RenderData_setYafrayAutoAntiAliasing,
+ "Automatic anti-aliasing enabled/disabled",
+ NULL},
+ {"yafrayClampRGB",
+ (getter)RenderData_getYafrayClampRGB, (setter)RenderData_setYafrayClampRGB,
+ "Clamp RGB enabled/disabled",
+ NULL},
+ {"yafrayAntiAliasingPasses",
+ (getter)RenderData_getYafrayAntiAliasingPasses, (setter)RenderData_setYafrayAntiAliasingPasses,
+ "Number of anti-aliasing passes (0 is no anti-aliasing)",
+ NULL},
+ {"yafrayAntiAliasingSamples",
+ (getter)RenderData_getYafrayAntiAliasingSamples, (setter)RenderData_setYafrayAntiAliasingSamples,
+ "Number of samples per pass",
+ NULL},
+ {"yafrayAntiAliasingPixelSize",
+ (getter)RenderData_getYafrayAntiAliasingPixelSize, (setter)RenderData_setYafrayAntiAliasingPixelSize,
+ "Anti-aliasing pixel filter size",
+ NULL},
+ {"yafrayAntiAliasingThreshold",
+ (getter)RenderData_getYafrayAntiAliasingThreshold, (setter)RenderData_setYafrayAntiAliasingThreshold,
+ "Anti-aliasing threshold",
+ NULL},
+ {"yafrayNumberOfProcessors",
+ (getter)RenderData_getYafrayNumberOfProcessors, (setter)RenderData_setYafrayNumberOfProcessors,
+ "Number of processors to use",
+ NULL},
+ {"yafrayGICache",
+ (getter)RenderData_getYafrayGICache, (setter)RenderData_setYafrayGICache,
+ "Cache occlusion/irradiance samples (faster)",
+ NULL},
+ {"yafrayGICacheBumpNormals",
+ (getter)RenderData_getYafrayGICacheBumpNormals, (setter)RenderData_setYafrayGICacheBumpNormals,
+ "Enable/disable bumpnormals for cache",
+ NULL},
+ {"yafrayGICacheShadowQuality",
+ (getter)RenderData_getYafrayGICacheShadowQuality, (setter)RenderData_setYafrayGICacheShadowQuality,
+ "Shadow quality, keep it under 0.95 :-)",
+ NULL},
+ {"yafrayGICachePixelsPerSample",
+ (getter)RenderData_getYafrayGICachePixelsPerSample, (setter)RenderData_setYafrayGICachePixelsPerSample,
+ "Maximum number of pixels without samples, the lower the better and slower",
+ NULL},
+ {"yafrayGICacheRefinement",
+ (getter)RenderData_getYafrayGICacheRefinement, (setter)RenderData_setYafrayGICacheRefinement,
+ "Threshold to refine shadows EXPERIMENTAL. 1 = no refinement",
+ NULL},
+ {"yafrayGIPhotons",
+ (getter)RenderData_getYafrayGIPhotons, (setter)RenderData_setYafrayGIPhotons,
+ "Enable/disable use of global photons to help in GI",
+ NULL},
+ {"yafrayGITunePhotons",
+ (getter)RenderData_getYafrayGITunePhotons, (setter)RenderData_setYafrayGITunePhotons,
+ "If true the photonmap is shown directly in the render for tuning",
+ NULL},
+
+ {NULL,NULL,NULL,NULL,NULL}
+};
+
+/***************************************************************************/
+/* BPy_RenderData method def */
+/***************************************************************************/
+static PyMethodDef BPy_RenderData_methods[] = {
+ {"render", ( PyCFunction ) RenderData_Render, METH_NOARGS,
+ "() - render the scene"},
+ {"saveRenderedImage", (PyCFunction)RenderData_SaveRenderedImage, METH_VARARGS,
+ "(filename) - save an image generated by a call to render() (set output path first)"},
+ {"renderAnim", ( PyCFunction ) RenderData_RenderAnim, METH_NOARGS,
+ "() - render a sequence from start frame to end frame"},
+ {"play", ( PyCFunction ) RenderData_Play, METH_NOARGS,
+ "() - play animation of rendered images/avi (searches Pics: field)"},
+ {"setRenderPath", ( PyCFunction ) RenderData_SetRenderPath,
+ METH_VARARGS,
+ "(string) - get/set the path to output the rendered images to"},
+ {"getRenderPath", ( PyCFunction ) RenderData_getRenderPath,
+ METH_NOARGS,
+ "() - get the path to directory where rendered images will go"},
+ {"setBackbufPath", ( PyCFunction ) RenderData_SetBackbufPath,
+ METH_VARARGS,
+ "(string) - get/set the path to a background image and load it"},
+ {"getBackbufPath", ( PyCFunction ) RenderData_getBackbufPath,
+ METH_NOARGS,
+ "() - get the path to background image file"},
+ {"enableBackbuf", ( PyCFunction ) RenderData_EnableBackbuf,
+ METH_VARARGS,
+ "(bool) - enable/disable the backbuf image"},
+ {"setFtypePath", ( PyCFunction ) RenderData_SetFtypePath, METH_VARARGS,
+ "(string) - get/set the path to output the Ftype file"},
+ {"getFtypePath", ( PyCFunction ) RenderData_getFtypePath, METH_NOARGS,
+ "() - get the path to Ftype file"},
+ {"enableExtensions", ( PyCFunction ) RenderData_EnableExtensions,
+ METH_VARARGS,
+ "(bool) - enable/disable windows extensions for output files"},
+ {"enableSequencer", ( PyCFunction ) RenderData_EnableSequencer,
+ METH_VARARGS,
+ "(bool) - enable/disable Do Sequence"},
+ {"enableRenderDaemon", ( PyCFunction ) RenderData_EnableRenderDaemon,
+ METH_VARARGS,
+ "(bool) - enable/disable Scene daemon"},
+ {"enableToonShading", ( PyCFunction ) RenderData_EnableToonShading,
+ METH_VARARGS,
+ "(bool) - enable/disable Edge rendering"},
+ {"edgeIntensity", ( PyCFunction ) RenderData_EdgeIntensity,
+ METH_VARARGS,
+ "(int) - get/set edge intensity for toon shading"},
+ {"setEdgeColor", ( PyCFunction ) RenderData_SetEdgeColor, METH_VARARGS,
+ "(f,f,f) - set the edge color for toon shading - Red,Green,Blue expected."},
+ {"getEdgeColor", ( PyCFunction ) RenderData_GetEdgeColor, METH_NOARGS,
+ "() - get the edge color for toon shading - Red,Green,Blue expected."},
+ {"enableOversampling", ( PyCFunction ) RenderData_EnableOversampling,
+ METH_VARARGS,
+ "(bool) - enable/disable oversampling (anit-aliasing)."},
+ {"setOversamplingLevel",
+ ( PyCFunction ) RenderData_SetOversamplingLevel, METH_VARARGS,
+ "(enum) - get/set the level of oversampling (anit-aliasing)."},
+ {"enableMotionBlur", ( PyCFunction ) RenderData_EnableMotionBlur,
+ METH_VARARGS,
+ "(bool) - enable/disable MBlur."},
+ {"motionBlurLevel", ( PyCFunction ) RenderData_MotionBlurLevel,
+ METH_VARARGS,
+ "(float) - get/set the length of shutter time for motion blur."},
+ {"partsX", ( PyCFunction ) RenderData_PartsX, METH_VARARGS,
+ "(int) - get/set the number of parts to divide the render in the X direction"},
+ {"partsY", ( PyCFunction ) RenderData_PartsY, METH_VARARGS,
+ "(int) - get/set the number of parts to divide the render in the Y direction"},
+ {"enableSky", ( PyCFunction ) RenderData_EnableSky, METH_NOARGS,
+ "() - enable render background with sky"},
+ {"enablePremultiply", ( PyCFunction ) RenderData_EnablePremultiply,
+ METH_NOARGS,
+ "() - enable premultiply alpha"},
+ {"enableKey", ( PyCFunction ) RenderData_EnableKey, METH_NOARGS,
+ "() - enable alpha and color values remain unchanged"},
+ {"enableShadow", ( PyCFunction ) RenderData_EnableShadow, METH_VARARGS,
+ "(bool) - enable/disable shadow calculation"},
+ {"enablePanorama", ( PyCFunction ) RenderData_EnablePanorama,
+ METH_VARARGS,
+ "(bool) - enable/disable panorama rendering (output width is multiplied by Xparts)"},
+ {"enableEnvironmentMap",
+ ( PyCFunction ) RenderData_EnableEnvironmentMap, METH_VARARGS,
+ "(bool) - enable/disable environment map rendering"},
+ {"enableRayTracing", ( PyCFunction ) RenderData_EnableRayTracing,
+ METH_VARARGS,
+ "(bool) - enable/disable ray tracing"},
+ {"enableRadiosityRender",
+ ( PyCFunction ) RenderData_EnableRadiosityRender, METH_VARARGS,
+ "(bool) - enable/disable radiosity rendering"},
+ {"getRenderWinSize", ( PyCFunction ) RenderData_getRenderWinSize,
+ METH_NOARGS,
+ "() - get the size of the render window"},
+ {"setRenderWinSize", ( PyCFunction ) RenderData_SetRenderWinSize,
+ METH_VARARGS,
+ "(int) - set the size of the render window"},
+ {"enableFieldRendering",
+ ( PyCFunction ) RenderData_EnableFieldRendering, METH_VARARGS,
+ "(bool) - enable/disable field rendering"},
+ {"enableOddFieldFirst", ( PyCFunction ) RenderData_EnableOddFieldFirst,
+ METH_VARARGS,
+ "(bool) - enable/disable Odd field first rendering (Default: Even field)"},
+ {"enableFieldTimeDisable",
+ ( PyCFunction ) RenderData_EnableFieldTimeDisable, METH_VARARGS,
+ "(bool) - enable/disable time difference in field calculations"},
+ {"enableGaussFilter", ( PyCFunction ) RenderData_EnableGaussFilter,
+ METH_VARARGS,
+ "(bool) - enable/disable Gauss sampling filter for antialiasing"},
+ {"enableBorderRender", ( PyCFunction ) RenderData_EnableBorderRender,
+ METH_VARARGS,
+ "(bool) - enable/disable small cut-out rendering"},
+ {"setBorder", ( PyCFunction ) RenderData_SetBorder, METH_VARARGS,
+ "(f,f,f,f) - set the border for border rendering"},
+ {"gaussFilterSize", ( PyCFunction ) RenderData_GaussFilterSize,
+ METH_VARARGS,
+ "(float) - get/sets the Gauss filter size"},
+ {"startFrame", ( PyCFunction ) RenderData_StartFrame, METH_VARARGS,
+ "(int) - get/set the starting frame for rendering"},
+ {"currentFrame", ( PyCFunction ) RenderData_CurrentFrame, METH_VARARGS,
+ "(int) - get/set the current frame for rendering"},
+ {"endFrame", ( PyCFunction ) RenderData_EndFrame, METH_VARARGS,
+ "(int) - get/set the ending frame for rendering"},
+ {"getTimeCode", ( PyCFunction ) RenderData_getTimeCode, METH_NOARGS,
+ "get the current frame in HH:MM:SS:FF format"},
+ {"imageSizeX", ( PyCFunction ) RenderData_ImageSizeX, METH_VARARGS,
+ "(int) - get/set the image width in pixels"},
+ {"imageSizeY", ( PyCFunction ) RenderData_ImageSizeY, METH_VARARGS,
+ "(int) - get/set the image height in pixels"},
+ {"aspectRatioX", ( PyCFunction ) RenderData_AspectRatioX, METH_VARARGS,
+ "(int) - get/set the horizontal aspect ratio"},
+ {"aspectRatioY", ( PyCFunction ) RenderData_AspectRatioY, METH_VARARGS,
+ "(int) - get/set the vertical aspect ratio"},
+ {"setRenderer", ( PyCFunction ) RenderData_SetRenderer, METH_VARARGS,
+ "(enum) - get/set which renderer to render the output"},
+ {"enableCropping", ( PyCFunction ) RenderData_EnableCropping,
+ METH_VARARGS,
+ "(bool) - enable/disable exclusion of border rendering from total image"},
+ {"setImageType", ( PyCFunction ) RenderData_SetImageType, METH_VARARGS,
+ "(enum) - get/set the type of image to output from the render"},
+ {"quality", ( PyCFunction ) RenderData_Quality, METH_VARARGS,
+ "(int) - get/set quality get/setting for JPEG images, AVI Jpeg and SGI movies"},
+ {"framesPerSec", ( PyCFunction ) RenderData_FramesPerSec, METH_VARARGS,
+ "(int) - get/set frames per second"},
+ {"enableGrayscale", ( PyCFunction ) RenderData_EnableGrayscale,
+ METH_NOARGS,
+ "() - images are saved with BW (grayscale) data"},
+ {"enableRGBColor", ( PyCFunction ) RenderData_EnableRGBColor,
+ METH_NOARGS,
+ "() - images are saved with RGB (color) data"},
+ {"enableRGBAColor", ( PyCFunction ) RenderData_EnableRGBAColor,
+ METH_NOARGS,
+ "() - images are saved with RGB and Alpha data (if supported)"},
+ {"sizePreset", ( PyCFunction ) RenderData_SizePreset, METH_VARARGS,
+ "(enum) - get/set the render to one of a few preget/sets"},
+ {"setYafrayGIQuality", ( PyCFunction ) RenderData_SetYafrayGIQuality,
+ METH_VARARGS,
+ "(enum) - set yafray global Illumination quality"},
+ {"getYafrayGIQuality", ( PyCFunction ) RenderData_GetYafrayGIQuality,
+ METH_VARARGS,
+ "(enum) - get yafray global Illumination quality"},
+ {"setYafrayGIMethod", ( PyCFunction ) RenderData_SetYafrayGIMethod,
+ METH_VARARGS,
+ "(enum) - set yafray global Illumination method"},
+ {"getYafrayGIMethod", ( PyCFunction ) RenderData_GetYafrayGIMethod,
+ METH_VARARGS,
+ "(enum) - get yafray global Illumination method"},
+ {"yafrayGIPower", ( PyCFunction ) RenderData_YafrayGIPower,
+ METH_VARARGS,
+ "(float) - get/set GI lighting intensity scale"},
+ {"yafrayGIIndirPower", ( PyCFunction ) RenderData_YafrayGIIndirPower,
+ METH_VARARGS,
+ "(float) - get/set GI indifect lighting intensity scale"},
+ {"yafrayGIDepth", ( PyCFunction ) RenderData_YafrayGIDepth,
+ METH_VARARGS,
+ "(int) - get/set number of bounces of the indirect light"},
+ {"yafrayGICDepth", ( PyCFunction ) RenderData_YafrayGICDepth,
+ METH_VARARGS,
+ "(int) - get/set number of bounces inside objects (for caustics)"},
+ {"enableYafrayGICache", ( PyCFunction ) RenderData_EnableYafrayGICache,
+ METH_VARARGS,
+ "(bool) - enable/disable cache irradiance samples (faster)"},
+ {"enableYafrayGIPhotons",
+ ( PyCFunction ) RenderData_EnableYafrayGIPhotons, METH_VARARGS,
+ "(bool) - enable/disable use global photons to help in GI"},
+ {"yafrayGIPhotonCount", ( PyCFunction ) RenderData_YafrayGIPhotonCount,
+ METH_VARARGS,
+ "(int) - get/set number of photons to shoot"},
+ {"yafrayGIPhotonRadius",
+ ( PyCFunction ) RenderData_YafrayGIPhotonRadius, METH_VARARGS,
+ "(float) - get/set radius to search for photons to mix (blur)"},
+ {"yafrayGIPhotonMixCount",
+ ( PyCFunction ) RenderData_YafrayGIPhotonMixCount, METH_VARARGS,
+ "(int) - get/set number of photons to mix"},
+ {"enableYafrayGITunePhotons",
+ ( PyCFunction ) RenderData_EnableYafrayGITunePhotons, METH_VARARGS,
+ "(bool) - enable/disable show the photonmap directly in the render for tuning"},
+ {"yafrayGIShadowQuality",
+ ( PyCFunction ) RenderData_YafrayGIShadowQuality, METH_VARARGS,
+ "(float) - get/set the shadow quality, keep it under 0.95"},
+ {"yafrayGIPixelsPerSample",
+ ( PyCFunction ) RenderData_YafrayGIPixelsPerSample, METH_VARARGS,
+ "(int) - get/set maximum number of pixels without samples, the lower the better and slower"},
+ {"yafrayGIRefinement", ( PyCFunction ) RenderData_YafrayGIRefinement,
+ METH_VARARGS,
+ "(float) - get/setthreshold to refine shadows EXPERIMENTAL. 1 = no refinement"},
+ {"yafrayRayBias", ( PyCFunction ) RenderData_YafrayRayBias,
+ METH_VARARGS,
+ "(float) - get/set shadow ray bias to avoid self shadowing"},
+ {"yafrayRayDepth", ( PyCFunction ) RenderData_YafrayRayDepth,
+ METH_VARARGS,
+ "(int) - get/set maximum render ray depth from the camera"},
+ {"yafrayGamma", ( PyCFunction ) RenderData_YafrayGamma, METH_VARARGS,
+ "(float) - get/set gamma correction, 1 is off"},
+ {"yafrayExposure", ( PyCFunction ) RenderData_YafrayExposure,
+ METH_VARARGS,
+ "(float) - get/set exposure adjustment, 0 is off"},
+ {"yafrayProcessorCount",
+ ( PyCFunction ) RenderData_YafrayProcessorCount, METH_VARARGS,
+ "(int) - get/set number of processors to use"},
+ {"enableGameFrameStretch",
+ ( PyCFunction ) RenderData_EnableGameFrameStretch, METH_NOARGS,
+ "(l) - enble stretch or squeeze the viewport to fill the display window"},
+ {"enableGameFrameExpose",
+ ( PyCFunction ) RenderData_EnableGameFrameExpose, METH_NOARGS,
+ "(l) - enable show the entire viewport in the display window, viewing more horizontally or vertically"},
+ {"enableGameFrameBars", ( PyCFunction ) RenderData_EnableGameFrameBars,
+ METH_NOARGS,
+ "() - enable show the entire viewport in the display window, using bar horizontally or vertically"},
+ {"setGameFrameColor", ( PyCFunction ) RenderData_SetGameFrameColor,
+ METH_VARARGS,
+ "(f,f,f) - set the red, green, blue component of the bars"},
+ {"getGameFrameColor", ( PyCFunction ) RenderData_GetGameFrameColor,
+ METH_NOARGS,
+ "() - get the red, green, blue component of the bars"},
+ {"SGIMaxsize", ( PyCFunction ) RenderData_SGIMaxsize, METH_VARARGS,
+ "(int) - get/set maximum size per frame to save in an SGI movie"},
+ {"enableSGICosmo", ( PyCFunction ) RenderData_EnableSGICosmo,
+ METH_VARARGS,
+ "(bool) - enable/disable attempt to save SGI movies using Cosmo hardware"},
+ {"oldMapValue", ( PyCFunction ) RenderData_OldMapValue, METH_VARARGS,
+ "(int) - get/set specify old map value in frames"},
+ {"newMapValue", ( PyCFunction ) RenderData_NewMapValue, METH_VARARGS,
+ "(int) - get/set specify new map value in frames"},
+ {NULL, NULL, 0, NULL}
+};
+
+/*------------------------------------BPy_RenderData Type defintion------ */
+PyTypeObject RenderData_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender RenderData", /* char *tp_name; */
+ sizeof( BPy_RenderData ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ NULL, /* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* cmpfunc tp_compare; */
+ ( reprfunc ) RenderData_repr, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_RenderData_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ BPy_RenderData_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+/***************************************************************************/
+/* Render method def */
+/***************************************************************************/
+struct PyMethodDef M_Render_methods[] = {
+ {"CloseRenderWindow", ( PyCFunction ) M_Render_CloseRenderWindow,
+ METH_NOARGS,
+ "() - close the rendering window"},
+ {"EnableDispView", ( PyCFunction ) M_Render_EnableDispView,
+ METH_NOARGS,
+ "(bool) - enable Sceneing in view"},
+ {"EnableDispWin", ( PyCFunction ) M_Render_EnableDispWin, METH_NOARGS,
+ "(bool) - enable Sceneing in new window"},
+ {"SetRenderWinPos", ( PyCFunction ) M_Render_SetRenderWinPos,
+ METH_VARARGS,
+ "([string list]) - position the rendering window in around the edge of the screen"},
+ {NULL, NULL, 0, NULL}
+};
+
+static PyObject *M_Render_ModesDict( void )
+{
+ PyObject *M = PyConstant_New( );
+
+ if( M ) {
+ BPy_constant *d = ( BPy_constant * ) M;
+ PyConstant_Insert( d, "OSA", PyInt_FromLong( R_OSA ) );
+ PyConstant_Insert( d, "SHADOW", PyInt_FromLong( R_SHADOW ) );
+ PyConstant_Insert( d, "GAMMA", PyInt_FromLong( R_GAMMA ) );
+ PyConstant_Insert( d, "ENVMAP", PyInt_FromLong( R_ENVMAP ) );
+ PyConstant_Insert( d, "TOONSHADING", PyInt_FromLong( R_EDGE ) );
+ PyConstant_Insert( d, "FIELDRENDER", PyInt_FromLong( R_FIELDS ) );
+ PyConstant_Insert( d, "FIELDTIME", PyInt_FromLong( R_FIELDSTILL ) );
+ PyConstant_Insert( d, "RADIOSITY", PyInt_FromLong( R_RADIO ) );
+ PyConstant_Insert( d, "BORDER_RENDER", PyInt_FromLong( R_BORDER ) );
+ PyConstant_Insert( d, "PANORAMA", PyInt_FromLong( R_PANORAMA ) );
+ PyConstant_Insert( d, "CROP", PyInt_FromLong( R_CROP ) );
+ PyConstant_Insert( d, "ODDFIELD", PyInt_FromLong( R_ODDFIELD ) );
+ PyConstant_Insert( d, "MBLUR", PyInt_FromLong( R_MBLUR ) );
+ PyConstant_Insert( d, "RAYTRACING", PyInt_FromLong( R_RAYTRACE ) );
+ PyConstant_Insert( d, "THREADS", PyInt_FromLong( R_THREADS ) );
+ }
+ return M;
+}
+
+static PyObject *M_Render_SceModesDict( void )
+{
+ PyObject *M = PyConstant_New( );
+
+ if( M ) {
+ BPy_constant *d = ( BPy_constant * ) M;
+ PyConstant_Insert( d, "SEQUENCER", PyInt_FromLong( R_DOSEQ ) );
+ PyConstant_Insert( d, "EXTENSION", PyInt_FromLong( R_EXTENSION ) );
+ }
+ return M;
+}
+
+static PyObject *M_Render_GameFramingDict( void )
+{
+ PyObject *M = PyConstant_New( );
+
+ if( M ) {
+ BPy_constant *d = ( BPy_constant * ) M;
+ PyConstant_Insert( d, "BARS",
+ PyInt_FromLong( SCE_GAMEFRAMING_BARS ) );
+ PyConstant_Insert( d, "EXTEND",
+ PyInt_FromLong( SCE_GAMEFRAMING_EXTEND ) );
+ PyConstant_Insert( d, "SCALE",
+ PyInt_FromLong( SCE_GAMEFRAMING_SCALE ) );
+ }
+ return M;
+}
+
+/***************************************************************************/
+/* Render Module Init */
+/***************************************************************************/
+PyObject *Render_Init( void )
+{
+ PyObject *submodule;
+ PyObject *ModesDict = M_Render_ModesDict( );
+ PyObject *SceModesDict = M_Render_SceModesDict( );
+ PyObject *GFramingDict = M_Render_GameFramingDict( );
+
+ if( PyType_Ready( &RenderData_Type ) < 0 )
+ return NULL;
+
+ submodule = Py_InitModule3( "Blender.Scene.Render",
+ M_Render_methods, M_Render_doc );
+
+ if( ModesDict )
+ PyModule_AddObject( submodule, "Modes", ModesDict );
+ if( SceModesDict )
+ PyModule_AddObject( submodule, "SceModes", SceModesDict );
+ if( GFramingDict )
+ PyModule_AddObject( submodule, "FramingModes", GFramingDict );
+
+ /* ugh: why aren't these in a constant dict? */
+
+ PyModule_AddIntConstant( submodule, "INTERNAL", R_INTERN );
+ PyModule_AddIntConstant( submodule, "YAFRAY", R_YAFRAY );
+ PyModule_AddIntConstant( submodule, "AVIRAW", R_AVIRAW );
+ PyModule_AddIntConstant( submodule, "AVIJPEG", R_AVIJPEG );
+ PyModule_AddIntConstant( submodule, "AVICODEC", R_AVICODEC );
+ PyModule_AddIntConstant( submodule, "QUICKTIME", R_QUICKTIME );
+ PyModule_AddIntConstant( submodule, "TARGA", R_TARGA );
+ PyModule_AddIntConstant( submodule, "RAWTGA", R_RAWTGA );
+ PyModule_AddIntConstant( submodule, "HDR", R_RADHDR );
+ PyModule_AddIntConstant( submodule, "PNG", R_PNG );
+ PyModule_AddIntConstant( submodule, "BMP", R_BMP );
+ PyModule_AddIntConstant( submodule, "JPEG", R_JPEG90 );
+ PyModule_AddIntConstant( submodule, "HAMX", R_HAMX );
+ PyModule_AddIntConstant( submodule, "IRIS", R_IRIS );
+ PyModule_AddIntConstant( submodule, "IRISZ", R_IRIZ );
+ PyModule_AddIntConstant( submodule, "FTYPE", R_FTYPE );
+ PyModule_AddIntConstant( submodule, "PAL", B_PR_PAL );
+ PyModule_AddIntConstant( submodule, "NTSC", B_PR_NTSC );
+ PyModule_AddIntConstant( submodule, "DEFAULT", B_PR_PRESET );
+ PyModule_AddIntConstant( submodule, "PREVIEW", B_PR_PRV );
+ PyModule_AddIntConstant( submodule, "PC", B_PR_PC );
+ PyModule_AddIntConstant( submodule, "PAL169", B_PR_PAL169 );
+ PyModule_AddIntConstant( submodule, "PANO", B_PR_PANO );
+ PyModule_AddIntConstant( submodule, "FULL", B_PR_FULL );
+ PyModule_AddIntConstant( submodule, "NONE", PY_NONE );
+ PyModule_AddIntConstant( submodule, "LOW", PY_LOW );
+ PyModule_AddIntConstant( submodule, "MEDIUM", PY_MEDIUM );
+ PyModule_AddIntConstant( submodule, "HIGH", PY_HIGH );
+ PyModule_AddIntConstant( submodule, "HIGHER", PY_HIGHER );
+ PyModule_AddIntConstant( submodule, "BEST", PY_BEST );
+ PyModule_AddIntConstant( submodule, "USEAOSETTINGS", PY_USEAOSETTINGS );
+ PyModule_AddIntConstant( submodule, "SKYDOME", PY_SKYDOME );
+ PyModule_AddIntConstant( submodule, "GIFULL", PY_FULL );
+ PyModule_AddIntConstant( submodule, "OPENEXR", R_OPENEXR );
+ PyModule_AddIntConstant( submodule, "TIFF", R_TIFF );
+ PyModule_AddIntConstant( submodule, "FFMPEG", R_FFMPEG );
+ PyModule_AddIntConstant( submodule, "CINEON", R_CINEON );
+ PyModule_AddIntConstant( submodule, "DPX", R_DPX );
+
+ return ( submodule );
+}
+
+/***************************************************************************/
+/* BPy_RenderData Callbacks */
+/***************************************************************************/
+
+PyObject *RenderData_CreatePyObject( struct Scene * scene )
+{
+ BPy_RenderData *py_renderdata;
+
+ py_renderdata =
+ ( BPy_RenderData * ) PyObject_NEW( BPy_RenderData,
+ &RenderData_Type );
+
+ if( py_renderdata == NULL ) {
+ return ( NULL );
+ }
+ py_renderdata->renderContext = &scene->r;
+ py_renderdata->scene = scene;
+
+ return ( ( PyObject * ) py_renderdata );
+}
+
+/* #####DEPRECATED###### */
+
+static PyObject *RenderData_SetRenderPath( BPy_RenderData *self,
+ PyObject *args )
+{
+ return EXPP_setterWrapper( (void *)self, args,
+ (setter)RenderData_setRenderPath );
+}
+
+static PyObject *RenderData_SetBackbufPath( BPy_RenderData *self,
+ PyObject *args )
+{
+ return EXPP_setterWrapper( (void *)self, args,
+ (setter)RenderData_setBackbufPath );
+}
+
+static PyObject *RenderData_SetFtypePath( BPy_RenderData *self,
+ PyObject *args )
+{
+ return EXPP_setterWrapperTuple( (void *)self, args,
+ (setter)RenderData_setFtypePath );
+}
+
+static PyObject *RenderData_SetOversamplingLevel( BPy_RenderData * self,
+ PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args,
+ (setter)RenderData_setOSALevel );
+}
+
+static PyObject *RenderData_SetRenderWinSize( BPy_RenderData * self,
+ PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args,
+ (setter)RenderData_setRenderWinSize );
+}
+
+static PyObject *RenderData_SetBorder( BPy_RenderData * self,
+ PyObject * args )
+{
+ return EXPP_setterWrapperTuple( (void *)self, args,
+ (setter)RenderData_setBorder );
+}
+
+static PyObject *RenderData_SetRenderer( BPy_RenderData * self,
+ PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args,
+ (setter)RenderData_setRenderer );
+}
+
+static PyObject *RenderData_SetImageType( BPy_RenderData * self,
+ PyObject * args )
+{
+ return EXPP_setterWrapper( (void *)self, args,
+ (setter)RenderData_setImageType );
+}
diff --git a/source/blender/python/api2_2x/sceneRender.h b/source/blender/python/api2_2x/sceneRender.h
new file mode 100644
index 00000000000..73bf71f5c06
--- /dev/null
+++ b/source/blender/python/api2_2x/sceneRender.h
@@ -0,0 +1,52 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Joseph Gilbert
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_SCENERENDER_H
+#define EXPP_SCENERENDER_H
+
+#include <Python.h>
+#include "DNA_scene_types.h"
+
+#define BPy_RenderData_Check(v) ((v)->ob_type == &RenderData_Type)
+
+//------------------------------------Struct definitions-------
+typedef struct {
+ PyObject_HEAD
+ struct RenderData *renderContext;
+ Scene *scene;
+} BPy_RenderData;
+//------------------------------------Visible prototypes-------
+PyObject *Render_Init( void );
+
+PyObject *RenderData_CreatePyObject( struct Scene *scene );
+
+#endif /* EXPP_SCENERENDER_H */
diff --git a/source/blender/python/api2_2x/sceneSequence.c b/source/blender/python/api2_2x/sceneSequence.c
new file mode 100644
index 00000000000..6ddaaf345c3
--- /dev/null
+++ b/source/blender/python/api2_2x/sceneSequence.c
@@ -0,0 +1,1133 @@
+/*
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Campbell Barton
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "sceneSequence.h" /* This must come first */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_sequence_types.h"
+#include "DNA_scene_types.h" /* for Base */
+
+#include "BKE_mesh.h"
+#include "BKE_library.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_scene.h"
+
+#include "BIF_editseq.h" /* get_last_seq */
+#include "BLI_blenlib.h"
+#include "BSE_sequence.h"
+#include "Ipo.h"
+#include "blendef.h" /* CLAMP */
+#include "BKE_utildefines.h"
+#include "Scene.h"
+#include "Sound.h"
+#include "gen_utils.h"
+
+enum seq_consts {
+ EXPP_SEQ_ATTR_TYPE = 0,
+ EXPP_SEQ_ATTR_CHAN,
+ EXPP_SEQ_ATTR_LENGTH,
+ EXPP_SEQ_ATTR_START,
+ EXPP_SEQ_ATTR_STARTOFS,
+ EXPP_SEQ_ATTR_ENDOFS,
+ EXPP_SEQ_ATTR_STARTSTILL,
+ EXPP_SEQ_ATTR_ENDSTILL
+};
+
+
+/*****************************************************************************/
+/* Python API function prototypes for the Blender module. */
+/*****************************************************************************/
+/*PyObject *M_Sequence_Get( PyObject * self, PyObject * args );*/
+
+/*****************************************************************************/
+/* Python method structure definition for Blender.Object module: */
+/*****************************************************************************/
+/*struct PyMethodDef M_Sequence_methods[] = {
+ {"Get", ( PyCFunction ) M_Sequence_Get, METH_VARARGS,
+"(name) - return the sequence with the name 'name',\
+returns None if notfound.\nIf 'name' is not specified, it returns a list of all sequences."},
+ {NULL, NULL, 0, NULL}
+};*/
+
+/*****************************************************************************/
+/* Python BPy_Sequence methods table: */
+/*****************************************************************************/
+static PyObject *Sequence_copy( BPy_Sequence * self );
+static PyObject *Sequence_new( BPy_Sequence * self, PyObject * args );
+static PyObject *Sequence_remove( BPy_Sequence * self, PyObject * args );
+
+static PyObject *SceneSeq_new( BPy_SceneSeq * self, PyObject * args );
+static PyObject *SceneSeq_remove( BPy_SceneSeq * self, PyObject * args );
+static void intern_pos_update(Sequence * seq);
+
+static PyMethodDef BPy_Sequence_methods[] = {
+ /* name, method, flags, doc */
+ {"new", ( PyCFunction ) Sequence_new, METH_VARARGS,
+ "(data) - Return a new sequence."},
+ {"remove", ( PyCFunction ) Sequence_remove, METH_VARARGS,
+ "(data) - Remove a strip."},
+ {"__copy__", ( PyCFunction ) Sequence_copy, METH_NOARGS,
+ "() - Return a copy of the sequence containing the same objects."},
+ {"copy", ( PyCFunction ) Sequence_copy, METH_NOARGS,
+ "() - Return a copy of the sequence containing the same objects."},
+ {NULL, NULL, 0, NULL}
+};
+
+static PyMethodDef BPy_SceneSeq_methods[] = {
+ /* name, method, flags, doc */
+ {"new", ( PyCFunction ) SceneSeq_new, METH_VARARGS,
+ "(data) - Return a new sequence."},
+ {"remove", ( PyCFunction ) SceneSeq_remove, METH_VARARGS,
+ "(data) - Remove a strip."},
+ {NULL, NULL, 0, NULL}
+};
+
+/* use to add a sequence to a scene or its listbase */
+static PyObject *NewSeq_internal(ListBase *seqbase, PyObject * args, Scene *sce)
+{
+ PyObject *py_data = NULL;
+
+ Sequence *seq;
+ int a;
+ Strip *strip;
+ StripElem *se;
+ int start, machine;
+
+ if( !PyArg_ParseTuple( args, "Oii", &py_data, &start, &machine ) )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "expect sequence data then 2 ints - (seqdata, start, track)" );
+
+ seq = alloc_sequence(seqbase, start, machine); /* warning, this sets last */
+
+ if (PyTuple_Check(py_data)) {
+ /* Image */
+ PyObject *list;
+ char *name;
+
+ if (!PyArg_ParseTuple( py_data, "sO!", &name, &PyList_Type, &list)) {
+ BLI_remlink(seqbase, seq);
+ MEM_freeN(seq);
+
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "images data needs to be a tuple of a string and a list of images - (path, [filenames...])" );
+ }
+
+ seq->type= SEQ_IMAGE;
+
+ seq->len = PyList_Size( list );
+
+
+ /* strip and stripdata */
+ seq->strip= strip= MEM_callocN(sizeof(Strip), "strip");
+ strip->len= seq->len;
+ strip->us= 1;
+ strncpy(strip->dir, name, FILE_MAXDIR-1);
+ strip->stripdata= se= MEM_callocN(seq->len*sizeof(StripElem), "stripelem");
+
+ for(a=0; a<seq->len; a++) {
+ name = PyString_AsString(PyList_GetItem( list, a ));
+ strncpy(se->name, name, FILE_MAXFILE-1);
+ se->ok= 1;
+ se++;
+ }
+
+ } else if (BPy_Sound_Check(py_data)) {
+ /* sound */
+ int totframe;
+ bSound *sound = (( BPy_Sound * )py_data)->sound;
+
+
+ seq->type= SEQ_RAM_SOUND;
+ seq->sound = sound;
+
+ totframe= (int) ( ((float)(sound->streamlen-1)/( (float)sce->audio.mixrate*4.0 ))* (float)sce->r.frs_sec / sce->r.frs_sec_base);
+
+ sound->flags |= SOUND_FLAGS_SEQUENCE;
+
+
+ /* strip and stripdata */
+ seq->strip= strip= MEM_callocN(sizeof(Strip), "strip");
+ strip->len= totframe;
+ strip->us= 1;
+ strncpy(strip->dir, sound->name, FILE_MAXDIR-1);
+ strip->stripdata= se= MEM_callocN(totframe*sizeof(StripElem), "stripelem");
+
+ /* name sound in first strip */
+ strncpy(se->name, sound->name, FILE_MAXFILE-1);
+
+ for(a=1; a<=totframe; a++, se++) {
+ se->ok= 2; /* why? */
+ se->ibuf= 0;
+ se->nr= a;
+ }
+
+ } else if (BPy_Scene_Check(py_data)) {
+ /* scene */
+ Scene *sce = ((BPy_Scene *)py_data)->scene;
+
+ seq->type= SEQ_SCENE;
+ seq->scene= sce;
+
+ /*seq->sfra= sce->r.sfra;*/
+ seq->len= sce->r.efra - sce->r.sfra + 1;
+
+ seq->strip= strip= MEM_callocN(sizeof(Strip), "strip");
+ strncpy(seq->name + 2, sce->id.name + 2,
+ sizeof(seq->name) - 2);
+ strip->len= seq->len;
+ strip->us= 1;
+ if(seq->len>0) strip->stripdata= MEM_callocN(seq->len*sizeof(StripElem), "stripelem");
+
+ } else {
+ /* movie, pydata is a path to a movie file */
+ char *name = PyString_AsString ( py_data );
+ if (!name) {
+ /* only free these 2 because other stuff isnt set */
+ BLI_remlink(seqbase, seq);
+ MEM_freeN(seq);
+
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expects a string for chan/bone name and an int for the frame where to put the new key" );
+ }
+
+ seq->type= SEQ_MOVIE;
+ }
+ strncpy(seq->name+2, "Untitled", 21);
+ intern_pos_update(seq);
+ return Sequence_CreatePyObject(seq, NULL, sce);
+}
+
+static PyObject *Sequence_new( BPy_Sequence * self, PyObject * args )
+{
+ return NewSeq_internal(&self->seq->seqbase, args, self->scene);
+}
+
+static PyObject *SceneSeq_new( BPy_SceneSeq * self, PyObject * args )
+{
+ return NewSeq_internal( &((Editing *)self->scene->ed)->seqbase, args, self->scene);
+}
+
+static void del_seq__internal(Sequence *seq)
+{
+ if(seq->ipo) seq->ipo->id.us--;
+
+ if(seq->type==SEQ_RAM_SOUND && seq->sound)
+ seq->sound->id.us--;
+ free_sequence(seq);
+}
+
+static void recurs_del_seq(ListBase *lb)
+{
+ Sequence *seq, *seqn;
+
+ seq= lb->first;
+ while(seq) {
+ seqn= seq->next;
+ BLI_remlink(lb, seq);
+ if(seq->type==SEQ_META) recurs_del_seq(&seq->seqbase);
+ del_seq__internal(seq);
+ seq= seqn;
+ }
+}
+
+static PyObject *RemoveSeq_internal(ListBase *seqbase, PyObject * args, Scene *sce)
+{
+ BPy_Sequence *bpy_seq = NULL;
+
+ if( !PyArg_ParseTuple( args, "O!", &Sequence_Type, &bpy_seq ) )
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "expects a sequence object" );
+
+ /* quick way to tell if we dont have the seq */
+ if (sce != bpy_seq->scene)
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "Sequence does not exist here, cannot remove" );
+
+ recurs_del_seq(&bpy_seq->seq->seqbase);
+ del_seq__internal(bpy_seq->seq);
+ clear_last_seq(); /* just incase */
+ Py_RETURN_NONE;
+}
+
+static PyObject *Sequence_remove( BPy_Sequence * self, PyObject * args )
+{
+ return RemoveSeq_internal(&self->seq->seqbase, args, self->scene);
+}
+
+static PyObject *SceneSeq_remove( BPy_SceneSeq * self, PyObject * args )
+{
+ return RemoveSeq_internal( &((Editing *)self->scene->ed)->seqbase, args, self->scene);
+}
+
+
+static PyObject *Sequence_copy( BPy_Sequence * self )
+{
+ printf("Sequence Copy not implimented yet!\n");
+ Py_RETURN_NONE;
+}
+
+/*****************************************************************************/
+/* PythonTypeObject callback function prototypes */
+/*****************************************************************************/
+static PyObject *Sequence_repr( BPy_Sequence * obj );
+static PyObject *SceneSeq_repr( BPy_SceneSeq * obj );
+static int Sequence_compare( BPy_Sequence * a, BPy_Sequence * b );
+static int SceneSeq_compare( BPy_SceneSeq * a, BPy_SceneSeq * b );
+
+/*****************************************************************************/
+/* Python BPy_Sequence methods: */
+/*****************************************************************************/
+
+
+static PyObject *Sequence_getIter( BPy_Sequence * self )
+{
+ Sequence *iter = self->seq->seqbase.first;
+
+ if (!self->iter) {
+ self->iter = iter;
+ return EXPP_incr_ret ( (PyObject *) self );
+ } else {
+ return Sequence_CreatePyObject(self->seq, iter, self->scene);
+ }
+}
+
+static PyObject *SceneSeq_getIter( BPy_SceneSeq * self )
+{
+ Sequence *iter = ((Editing *)self->scene->ed)->seqbase.first;
+
+ if (!self->iter) {
+ self->iter = iter;
+ return EXPP_incr_ret ( (PyObject *) self );
+ } else {
+ return SceneSeq_CreatePyObject(self->scene, iter);
+ }
+}
+
+
+/*
+ * Return next Seq
+ */
+static PyObject *Sequence_nextIter( BPy_Sequence * self )
+{
+ PyObject *object;
+ if( !(self->iter) ) {
+ self->iter = NULL; /* so we can add objects again */
+ return EXPP_ReturnPyObjError( PyExc_StopIteration,
+ "iterator at end" );
+ }
+
+ object= Sequence_CreatePyObject( self->iter, NULL, self->scene );
+ self->iter= self->iter->next;
+ return object;
+}
+
+
+/*
+ * Return next Seq
+ */
+static PyObject *SceneSeq_nextIter( BPy_Sequence * self )
+{
+ PyObject *object;
+ if( !(self->iter) ) {
+ self->iter = NULL; /* so we can add objects again */
+ return EXPP_ReturnPyObjError( PyExc_StopIteration,
+ "iterator at end" );
+ }
+
+ object= Sequence_CreatePyObject( self->iter, NULL, self->scene );
+ self->iter= self->iter->next;
+ return object;
+}
+
+
+
+static PyObject *Sequence_getName( BPy_Sequence * self )
+{
+ return PyString_FromString( self->seq->name+2 );
+}
+
+static int Sequence_setName( BPy_Sequence * self, PyObject * value )
+{
+ char *name = NULL;
+
+ name = PyString_AsString ( value );
+ if( !name )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected string argument" );
+
+ strncpy(self->seq->name+2, name, 21);
+ return 0;
+}
+
+
+static PyObject *Sequence_getSound( BPy_Sequence * self )
+{
+ if (self->seq->type == SEQ_RAM_SOUND && self->seq->sound)
+ return Sound_CreatePyObject(self->seq->sound);
+ Py_RETURN_NONE;
+}
+
+static PyObject *Sequence_getIpo( BPy_Sequence * self )
+{
+ struct Ipo *ipo;
+
+ ipo = self->seq->ipo;
+
+ if( ipo )
+ return Ipo_CreatePyObject( ipo );
+ Py_RETURN_NONE;
+}
+
+
+static PyObject *SceneSeq_getActive( BPy_SceneSeq * self )
+{
+ Sequence *last_seq = NULL, *seq;
+ Editing *ed = self->scene->ed;
+
+ if (!ed)
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "scene has no sequence data to edit" );
+
+ seq = ed->seqbasep->first;
+
+ while (seq) {
+ if (seq->flag & SELECT)
+ last_seq = seq;
+
+ seq = seq->next;
+ }
+ if (last_seq)
+ return Sequence_CreatePyObject(last_seq, NULL, self->scene );
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *SceneSeq_getMetaStrip( BPy_SceneSeq * self )
+{
+ Sequence *seq = NULL;
+ Editing *ed = self->scene->ed;
+ MetaStack *ms;
+ if (!ed)
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "scene has no sequence data to edit" );
+
+ ms = ed->metastack.last;
+ if (!ms)
+ Py_RETURN_NONE;
+
+ seq = ms->parseq;
+ return Sequence_CreatePyObject(seq, NULL, self->scene);
+}
+
+
+/*
+ * this should accept a Py_None argument and just delete the Ipo link
+ * (as Object_clearIpo() does)
+ */
+
+static int Sequence_setIpo( BPy_Sequence * self, PyObject * value )
+{
+ Ipo *ipo = NULL;
+ Ipo *oldipo;
+ ID *id;
+
+ oldipo = self->seq->ipo;
+
+ /* if parameter is not None, check for valid Ipo */
+
+ if ( value != Py_None ) {
+ if ( !BPy_Ipo_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected an Ipo object" );
+
+ ipo = Ipo_FromPyObject( value );
+
+ if( !ipo )
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "null ipo!" );
+
+ if( ipo->blocktype != ID_SEQ )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "Ipo is not a sequence data Ipo" );
+ }
+
+ /* if already linked to Ipo, delete link */
+
+ if ( oldipo ) {
+ id = &oldipo->id;
+ if( id->us > 0 )
+ id->us--;
+ }
+
+ /* assign new Ipo and increment user count, or set to NULL if deleting */
+
+ self->seq->ipo = ipo;
+ if ( ipo )
+ id_us_plus(&ipo->id);
+
+ return 0;
+}
+
+static PyObject *Sequence_getScene( BPy_Sequence * self )
+{
+ struct Scene *scene;
+
+ scene = self->seq->scene;
+
+ if( scene )
+ return Scene_CreatePyObject( scene );
+ Py_RETURN_NONE;
+}
+
+
+static PyObject *Sequence_getImages( BPy_Sequence * self )
+{
+ Strip *strip;
+ StripElem *se;
+ int i;
+ PyObject *list, *ret;
+
+ if (self->seq->type != SEQ_IMAGE) {
+ list = PyList_New(0);
+ ret= Py_BuildValue( "sO", "", list);
+ Py_DECREF(list);
+ return ret;
+ }
+
+ /*return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "Sequence is not an image type" );*/
+
+
+ strip = self->seq->strip;
+ se = strip->stripdata;
+ list = PyList_New(strip->len);
+
+ for (i=0; i<strip->len; i++, se++) {
+ PyList_SetItem( list, i, PyString_FromString(se->name) );
+ }
+
+ ret= Py_BuildValue( "sO", strip->dir, list);
+ Py_DECREF(list);
+ return ret;
+}
+
+
+
+/*
+ * get floating point attributes
+ */
+static PyObject *getIntAttr( BPy_Sequence *self, void *type )
+{
+ int param;
+ struct Sequence *seq= self->seq;
+
+ /*printf("%i %i %i %i %i %i %i %i %i\n", seq->len, seq->start, seq->startofs, seq->endofs, seq->startstill, seq->endstill, seq->startdisp, seq->enddisp, seq->depth );*/
+ switch( (int)type ) {
+ case EXPP_SEQ_ATTR_TYPE:
+ param = seq->type;
+ break;
+ case EXPP_SEQ_ATTR_CHAN:
+ param = seq->machine;
+ break;
+ case EXPP_SEQ_ATTR_LENGTH:
+ param = seq->len;
+ break;
+ case EXPP_SEQ_ATTR_START:
+ param = seq->start;
+ break;
+ case EXPP_SEQ_ATTR_STARTOFS:
+ param = seq->startofs;
+ break;
+ case EXPP_SEQ_ATTR_ENDOFS:
+ param = seq->endofs;
+ break;
+ case EXPP_SEQ_ATTR_STARTSTILL:
+ param = seq->startstill;
+ break;
+ case EXPP_SEQ_ATTR_ENDSTILL:
+ param = seq->endstill;
+ break;
+ default:
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "undefined type in getFloatAttr" );
+ }
+
+ return PyInt_FromLong( param );
+}
+
+/* internal functions for recursivly updating metastrip locatons */
+static void intern_pos_update(Sequence * seq) {
+ /* update startdisp and enddisp */
+ calc_sequence_disp(seq);
+}
+
+void intern_recursive_pos_update(Sequence * seq, int offset) {
+ Sequence *iterseq;
+ intern_pos_update(seq);
+ if (seq->type != SEQ_META) return;
+
+ for (iterseq = seq->seqbase.first; iterseq; iterseq= iterseq->next) {
+ iterseq->start -= offset;
+ intern_recursive_pos_update(iterseq, offset);
+ }
+}
+
+
+static int setIntAttrClamp( BPy_Sequence *self, PyObject *value, void *type )
+{
+ struct Sequence *seq= self->seq;
+ int number, origval=0;
+
+ if( !PyInt_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError, "expected an int value" );
+
+ number = PyInt_AS_LONG( value );
+
+ switch( (int)type ) {
+ case EXPP_SEQ_ATTR_CHAN:
+ CLAMP(number, 1, 1024);
+ seq->machine = number;
+ break;
+ case EXPP_SEQ_ATTR_START:
+ if (self->seq->type == SEQ_EFFECT)
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "cannot set the location of an effect directly" );
+ CLAMP(number, -MAXFRAME, MAXFRAME);
+ origval = seq->start;
+ seq->start = number;
+ break;
+
+ case EXPP_SEQ_ATTR_STARTOFS:
+ if (self->seq->type == SEQ_EFFECT)
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "This property dosnt apply to an effect" );
+ CLAMP(number, 0, seq->len - seq->endofs);
+ seq->startofs = number;
+ break;
+ case EXPP_SEQ_ATTR_ENDOFS:
+ if (self->seq->type == SEQ_EFFECT)
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "This property dosnt apply to an effect" );
+ CLAMP(number, 0, seq->len - seq->startofs);
+ seq->endofs = number;
+ break;
+ case EXPP_SEQ_ATTR_STARTSTILL:
+ if (self->seq->type == SEQ_EFFECT)
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "This property dosnt apply to an effect" );
+ CLAMP(number, 1, MAXFRAME);
+ seq->startstill = number;
+ break;
+ case EXPP_SEQ_ATTR_ENDSTILL:
+ if (self->seq->type == SEQ_EFFECT)
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "This property dosnt apply to an effect" );
+ CLAMP(number, seq->startstill+1, MAXFRAME);
+ seq->endstill = number;
+ break;
+ case EXPP_SEQ_ATTR_LENGTH:
+ if (self->seq->type == SEQ_EFFECT)
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "cannot set the length of an effect directly" );
+ CLAMP(number, 1, MAXFRAME);
+ origval = seq->len;
+ seq->start = number;
+ break;
+ default:
+ return EXPP_ReturnIntError( PyExc_RuntimeError,
+ "undefined type in setFloatAttrClamp" );
+ }
+
+ intern_pos_update(seq);
+
+ if ((int)type == EXPP_SEQ_ATTR_START && number != origval )
+ intern_recursive_pos_update(seq, origval - seq->start);
+
+ return 0;
+}
+
+
+static PyObject *getFlagAttr( BPy_Sequence *self, void *type )
+{
+ if (self->seq->flag & (int)type)
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+}
+
+
+/*
+ * set floating point attributes which require clamping
+ */
+
+static int setFlagAttr( BPy_Sequence *self, PyObject *value, void *type )
+{
+ int t = (int)type;
+ int param = PyObject_IsTrue( value );
+
+ if( param == -1 )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected True/False or 0/1" );
+
+ if (param)
+ self->seq->flag |= t;
+ else {
+ /* dont allow leftsel and rightsel when its not selected */
+ if (t == SELECT)
+ t = t + SEQ_LEFTSEL + SEQ_RIGHTSEL;
+
+ self->seq->flag &= ~t;
+ }
+ return 0;
+}
+
+
+/*****************************************************************************/
+/* Python attributes get/set structure: */
+/*****************************************************************************/
+static PyGetSetDef BPy_Sequence_getseters[] = {
+ {"name",
+ (getter)Sequence_getName, (setter)Sequence_setName,
+ "Sequence name",
+ NULL},
+ {"ipo",
+ (getter)Sequence_getIpo, (setter)Sequence_setIpo,
+ "Sequence ipo",
+ NULL},
+
+ {"scene",
+ (getter)Sequence_getScene, (setter)NULL,
+ "Sequence scene",
+ NULL},
+ {"sound",
+ (getter)Sequence_getSound, (setter)NULL,
+ "Sequence name",
+ NULL},
+ {"images",
+ (getter)Sequence_getImages, (setter)NULL,
+ "Sequence scene",
+ NULL},
+
+ {"type",
+ (getter)getIntAttr, (setter)NULL,
+ "",
+ (void *) EXPP_SEQ_ATTR_TYPE},
+ {"channel",
+ (getter)getIntAttr, (setter)setIntAttrClamp,
+ "",
+ (void *) EXPP_SEQ_ATTR_CHAN},
+
+ {"length",
+ (getter)getIntAttr, (setter)setIntAttrClamp,
+ "",
+ (void *) EXPP_SEQ_ATTR_LENGTH},
+ {"start",
+ (getter)getIntAttr, (setter)setIntAttrClamp,
+ "",
+ (void *) EXPP_SEQ_ATTR_START},
+ {"startOffset",
+ (getter)getIntAttr, (setter)setIntAttrClamp,
+ "",
+ (void *) EXPP_SEQ_ATTR_STARTOFS},
+ {"endOffset",
+ (getter)getIntAttr, (setter)setIntAttrClamp,
+ "",
+ (void *) EXPP_SEQ_ATTR_ENDOFS},
+ {"startStill",
+ (getter)getIntAttr, (setter)setIntAttrClamp,
+ "",
+ (void *) EXPP_SEQ_ATTR_STARTSTILL},
+ {"endStill",
+ (getter)getIntAttr, (setter)setIntAttrClamp,
+ "",
+ (void *) EXPP_SEQ_ATTR_ENDSTILL},
+
+ {"sel",
+ (getter)getFlagAttr, (setter)setFlagAttr,
+ "Sequence audio mute option",
+ (void *)SELECT},
+ {"selLeft",
+ (getter)getFlagAttr, (setter)setFlagAttr,
+ "",
+ (void *)SEQ_LEFTSEL},
+ {"selRight",
+ (getter)getFlagAttr, (setter)setFlagAttr,
+ "",
+ (void *)SEQ_RIGHTSEL},
+ {"filtery",
+ (getter)getFlagAttr, (setter)setFlagAttr,
+ "",
+ (void *)SEQ_FILTERY},
+ {"mute",
+ (getter)getFlagAttr, (setter)setFlagAttr,
+ "",
+ (void *)SEQ_MUTE},
+ {"premul",
+ (getter)getFlagAttr, (setter)setFlagAttr,
+ "",
+ (void *)SEQ_MAKE_PREMUL},
+ {"reversed",
+ (getter)getFlagAttr, (setter)setFlagAttr,
+ "",
+ (void *)SEQ_REVERSE_FRAMES},
+ {"ipoLocked",
+ (getter)getFlagAttr, (setter)setFlagAttr,
+ "",
+ (void *)SEQ_IPO_FRAME_LOCKED},
+ {"ipoLocked",
+ (getter)getFlagAttr, (setter)setFlagAttr,
+ "",
+ (void *)SEQ_IPO_FRAME_LOCKED},
+
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+/*****************************************************************************/
+/* Python attributes get/set structure: */
+/*****************************************************************************/
+static PyGetSetDef BPy_SceneSeq_getseters[] = {
+ {"active",
+ (getter)SceneSeq_getActive, (setter)NULL,
+ "the active strip",
+ NULL},
+ {"metastrip",
+ (getter)SceneSeq_getMetaStrip, (setter)NULL,
+ "The currently active metastrip the user is editing",
+ NULL},
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+/*****************************************************************************/
+/* Python TypeSequence structure definition: */
+/*****************************************************************************/
+PyTypeObject Sequence_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender Sequence", /* char *tp_name; */
+ sizeof( BPy_Sequence ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ NULL,/* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ ( cmpfunc ) Sequence_compare, /* cmpfunc tp_compare; */
+ ( reprfunc ) Sequence_repr, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ ( getiterfunc ) Sequence_getIter, /* getiterfunc tp_iter; */
+ ( iternextfunc ) Sequence_nextIter, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_Sequence_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ BPy_Sequence_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+
+
+/*****************************************************************************/
+/* Python TypeSequence structure definition: */
+/*****************************************************************************/
+PyTypeObject SceneSeq_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender SceneSeq", /* char *tp_name; */
+ sizeof( BPy_Sequence ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ NULL,/* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ ( cmpfunc ) SceneSeq_compare, /* cmpfunc tp_compare; */
+ ( reprfunc ) SceneSeq_repr, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT, /* long tp_flags; */
+
+ NULL, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ ( getiterfunc ) SceneSeq_getIter, /* getiterfunc tp_iter; */
+ ( iternextfunc ) SceneSeq_nextIter, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ BPy_SceneSeq_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ BPy_SceneSeq_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+
+/*****************************************************************************/
+/* Function: M_Sequence_Get */
+/* Python equivalent: Blender.Sequence.Get */
+/*****************************************************************************/
+/*
+PyObject *M_Sequence_Get( PyObject * self, PyObject * args )
+{
+ return SceneSeq_CreatePyObject( G.scene, NULL );
+}
+*/
+
+/*****************************************************************************/
+/* Function: initObject */
+/*****************************************************************************/
+PyObject *Sequence_Init( void )
+{
+ PyObject *submodule;
+ if( PyType_Ready( &Sequence_Type ) < 0 )
+ return NULL;
+ if( PyType_Ready( &SceneSeq_Type ) < 0 )
+ return NULL;
+
+ /* NULL was M_Sequence_methods*/
+ submodule = Py_InitModule3( "Blender.Scene.Sequence", NULL,
+"The Blender Sequence module\n\n\
+This module provides access to **Sequence Data** in Blender.\n" );
+
+ /*Add SUBMODULES to the module*/
+ /*PyDict_SetItemString(dict, "Constraint", Constraint_Init()); //creates a *new* module*/
+ return submodule;
+}
+
+
+/*****************************************************************************/
+/* Function: Sequence_CreatePyObject */
+/* Description: This function will create a new BlenObject from an existing */
+/* Object structure. */
+/*****************************************************************************/
+PyObject *Sequence_CreatePyObject( struct Sequence * seq, struct Sequence * iter, struct Scene *sce)
+{
+ BPy_Sequence *pyseq;
+
+ if( !seq )
+ Py_RETURN_NONE;
+
+ pyseq =
+ ( BPy_Sequence * ) PyObject_NEW( BPy_Sequence, &Sequence_Type );
+
+ if( pyseq == NULL ) {
+ return ( NULL );
+ }
+ pyseq->seq = seq;
+ pyseq->iter = iter;
+ pyseq->scene = sce;
+
+ return ( ( PyObject * ) pyseq );
+}
+
+/*****************************************************************************/
+/* Function: SceneSeq_CreatePyObject */
+/* Description: This function will create a new BlenObject from an existing */
+/* Object structure. */
+/*****************************************************************************/
+PyObject *SceneSeq_CreatePyObject( struct Scene * scn, struct Sequence * iter)
+{
+ BPy_SceneSeq *pysceseq;
+
+ if( !scn )
+ Py_RETURN_NONE;
+
+ pysceseq =
+ ( BPy_SceneSeq * ) PyObject_NEW( BPy_SceneSeq, &SceneSeq_Type );
+
+ if( pysceseq == NULL ) {
+ return ( NULL );
+ }
+ pysceseq->scene = scn;
+ pysceseq->iter = iter;
+
+ return ( ( PyObject * ) pysceseq );
+}
+
+/*****************************************************************************/
+/* Function: Sequence_FromPyObject */
+/* Description: This function returns the Blender sequence from the given */
+/* PyObject. */
+/*****************************************************************************/
+struct Sequence *Sequence_FromPyObject( PyObject * py_seq )
+{
+ BPy_Sequence *blen_seq;
+
+ blen_seq = ( BPy_Sequence * ) py_seq;
+ return ( blen_seq->seq );
+}
+
+/*****************************************************************************/
+/* Function: Sequence_compare */
+/* Description: This is a callback function for the BPy_Sequence type. It */
+/* compares two Sequence_Type objects. Only the "==" and "!=" */
+/* comparisons are meaninful. Returns 0 for equality and -1 if */
+/* they don't point to the same Blender Object struct. */
+/* In Python it becomes 1 if they are equal, 0 otherwise. */
+/*****************************************************************************/
+static int Sequence_compare( BPy_Sequence * a, BPy_Sequence * b )
+{
+ Sequence *pa = a->seq, *pb = b->seq;
+ return ( pa == pb ) ? 0 : -1;
+}
+
+static int SceneSeq_compare( BPy_SceneSeq * a, BPy_SceneSeq * b )
+{
+
+ Scene *pa = a->scene, *pb = b->scene;
+ return ( pa == pb ) ? 0 : -1;
+}
+
+/*****************************************************************************/
+/* Function: Sequence_repr / SceneSeq_repr */
+/* Description: This is a callback function for the BPy_Sequence type. It */
+/* builds a meaninful string to represent object objects. */
+/*****************************************************************************/
+static PyObject *Sequence_repr( BPy_Sequence * self )
+{
+ return PyString_FromFormat( "[Sequence Strip \"%s\"]",
+ self->seq->name + 2 );
+}
+static PyObject *SceneSeq_repr( BPy_SceneSeq * self )
+{
+ return PyString_FromFormat( "[Scene Sequence \"%s\"]",
+ self->scene->id.name + 2 );
+}
+
diff --git a/source/blender/python/api2_2x/sceneSequence.h b/source/blender/python/api2_2x/sceneSequence.h
new file mode 100644
index 00000000000..952e861f46d
--- /dev/null
+++ b/source/blender/python/api2_2x/sceneSequence.h
@@ -0,0 +1,83 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Michel Selten
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_SEQUENCE_H
+#define EXPP_SEQUENCE_H
+
+#include <Python.h>
+#include "DNA_sequence_types.h"
+
+/* The Sequence PyTypeObject defined in Sequence.c */
+extern PyTypeObject Sequence_Type;
+extern PyTypeObject SceneSeq_Type;
+
+#define BPy_Sequence_Check(v) ((v)->ob_type == &Sequence_Type)
+#define BPy_SceneSeq_Check(v) ((v)->ob_type == &SceneSeq_Type)
+
+
+/*****************************************************************************/
+/* Python BPy_Sequence structure definition. */
+/*****************************************************************************/
+typedef struct {
+ PyObject_HEAD /* required python macro */
+
+ /*one of the folowing must be NULL*/
+ struct Sequence *seq;/* if not NULL, this sequence is a Metaseq */
+
+ /* used for looping over the scene or the strips strips */
+ struct Sequence *iter;/* if not NULL, this sequence is a Metaseq */
+
+ struct Scene *scene;
+
+} BPy_Sequence;
+
+
+
+/*****************************************************************************/
+/* Python BPy_Sequence structure definition. */
+/*****************************************************************************/
+typedef struct {
+ PyObject_HEAD /* required python macro */
+
+ /*one of the folowing must be NULL*/
+ struct Scene *scene; /* if not NULL, this sequence is the root sequence for the scene*/
+
+ /* used for looping over the scene or the strips strips */
+ struct Sequence *iter;/* if not NULL, this sequence is a Metaseq */
+} BPy_SceneSeq;
+
+PyObject *Sequence_Init( void );
+PyObject *Sequence_CreatePyObject( struct Sequence * seq, struct Sequence * iter, struct Scene * scn);
+PyObject *SceneSeq_CreatePyObject( struct Scene * scn, struct Sequence * iter);
+struct Sequence *Sequence_FromPyObject( PyObject * py_obj );
+
+#endif /* EXPP_SEQUENCE_H */
diff --git a/source/blender/python/api2_2x/sceneTimeLine.c b/source/blender/python/api2_2x/sceneTimeLine.c
new file mode 100644
index 00000000000..ab74115574e
--- /dev/null
+++ b/source/blender/python/api2_2x/sceneTimeLine.c
@@ -0,0 +1,319 @@
+/* $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Joilnen Leite
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#include <BLI_blenlib.h>
+#include "Scene.h"
+
+#include <stdio.h>
+#include <MEM_guardedalloc.h> /* for MEM_callocN */
+
+#include "gen_utils.h"
+#include "sceneTimeLine.h"
+
+// static PyObject *TimeLine_New (PyObject *self);
+static PyObject *M_TimeLine_Get (PyObject *self, PyObject *args);
+
+static char M_TimeLine_Get_doc[]= "Return the Scene.TimeLine.";
+
+//----------------------Scene.TimeMarker subsubmodule method def----------------------------
+struct PyMethodDef M_TimeLine_methods[]= {
+// {"New", (PyCFunction) M_TimeMarker_New, METH_NOVAR,
+// M_TimeLine_New_doc},
+ {"Get", (PyCFunction) M_TimeLine_Get, METH_VARARGS,
+ M_TimeLine_Get_doc},
+ {NULL, NULL, 0, NULL}
+};
+
+static PyObject *TimeLine_addMarker (BPy_TimeLine *self, PyObject *args);
+static PyObject *TimeLine_delMarker (BPy_TimeLine *self, PyObject *args);
+static PyObject *TimeLine_setNameMarker (BPy_TimeLine *self, PyObject *args);
+static PyObject *TimeLine_getNameMarker (BPy_TimeLine *self, PyObject *args);
+static PyObject *TimeLine_getFramesMarked (BPy_TimeLine *self, PyObject *args);
+
+static PyObject *TimeLine_repr (BPy_TimeLine *self) {
+
+ return PyString_FromFormat ("[TimeLine]");
+}
+
+static PyMethodDef BPy_TimeLine_methods[] = {
+ {"add", (PyCFunction) TimeLine_addMarker,
+ METH_VARARGS,
+ "() - Add timemarker"},
+ {"delete", (PyCFunction) TimeLine_delMarker,
+ METH_VARARGS,
+ "() - delete timemarker"},
+ {"setName", (PyCFunction) TimeLine_setNameMarker,
+ METH_VARARGS,
+ "() - Get timemarker name"},
+ {"getName", (PyCFunction) TimeLine_getNameMarker,
+ METH_VARARGS,
+ "() - Set timemarker name"},
+ {"getMarked", (PyCFunction) TimeLine_getFramesMarked,
+ METH_VARARGS,
+ "() - Get frames timemarked"},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------dealloc----------------------------------------*/
+static void TimeLine_dealloc( BPy_TimeLine * self )
+{
+ PyObject_DEL( self );
+}
+
+/*-----------------------getattr----------------------------------------*/
+static PyObject *TimeLine_getattr (BPy_TimeLine *self, char *name) {
+ return Py_FindMethod( BPy_TimeLine_methods, ( PyObject * ) self, name );
+}
+
+/*-----------------------setattr----------------------------------------*/
+static int TimeLine_setattr (BPy_TimeLine *self, char *name, PyObject *value) {
+ PyObject *valtuple;
+ PyObject *error= NULL;
+
+ valtuple= Py_BuildValue ("(O)", value);
+
+ if (!valtuple)
+ return EXPP_ReturnIntError( PyExc_MemoryError,
+ "TimeLineSetAttr: couldn't create tuple" );
+ if( strcmp( name, "name" ) == 0 )
+ error = TimeLine_setNameMarker (self, valtuple);
+ Py_DECREF (valtuple);
+ if (error != Py_None)
+ return -1;
+
+ Py_DECREF (Py_None);
+ return 0;
+}
+
+//-----------------------BPy_Scene method def------------------------------
+PyTypeObject TimeLine_Type = {
+ PyObject_HEAD_INIT (NULL) 0, /* ob_size */
+ "TimeLine", /* tp_name */
+ sizeof (BPy_TimeLine), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ /* methods */
+ ( destructor ) TimeLine_dealloc, /* tp_dealloc */
+ (printfunc) 0, /* tp_print */
+ (getattrfunc) TimeLine_getattr, /* tp_getattr */
+ (setattrfunc) TimeLine_setattr, /* tp_setattr */
+ 0,
+ (reprfunc) TimeLine_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0,0,0,0,0,0,0,0,0,
+ BPy_TimeLine_methods,
+ 0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+};
+
+PyObject *TimeLine_Init (void)
+{
+ PyObject *submodule;
+
+ if (PyType_Ready (&TimeLine_Type) < 0)
+ return NULL;
+ submodule= Py_InitModule3 ("Blender.Scene.TimeLine", M_TimeLine_methods,
+ "The Blender TimeLine subsubmodule");
+
+ return submodule;
+}
+
+PyObject *TimeLine_CreatePyObject (BPy_TimeLine *tl) {
+ BPy_TimeLine *bl_tl;
+
+ bl_tl= (BPy_TimeLine *) PyObject_NEW (BPy_TimeLine, &TimeLine_Type);
+
+ return (( PyObject * ) bl_tl);
+}
+
+
+PyObject *M_TimeLine_Get (PyObject *self, PyObject *args) {
+
+ return EXPP_incr_ret (Py_None);
+}
+
+static PyObject *TimeLine_getFramesMarked (BPy_TimeLine *self, PyObject *args) {
+
+ PyObject *marker_dict= NULL;
+ TimeMarker *marker_it= NULL;
+ PyObject *tmarker= NULL, *pyo= NULL, *tmpstr;
+
+ if (!PyArg_ParseTuple (args, "|O", &tmarker))
+ return EXPP_ReturnPyObjError (PyExc_AttributeError,
+ "expected nothing, string or int as arguments.");
+ if (tmarker) {
+ char s[64];
+ int frm= 0;
+
+ if (PyString_Check (tmarker) && (BLI_strncpy(s, PyString_AsString (tmarker), 64)) ) {
+ for (marker_it= self->marker_list->first; marker_it; marker_it= marker_it->next)
+ if (!strcmp (marker_it->name, s)) {
+ frm= (int)marker_it->frame;
+ break;
+ }
+ }
+ else if (PyInt_Check (tmarker))
+ frm= (int)PyInt_AS_LONG (tmarker);
+ else
+ return EXPP_ReturnPyObjError (PyExc_AttributeError,
+ "expected nothing, string or int as arguments.");
+ if (frm>0) {
+ marker_dict= PyDict_New ();
+ for (marker_it= self->marker_list->first; marker_it; marker_it= marker_it->next){
+ if (marker_it->frame==frm) {
+ pyo= PyDict_GetItem ((PyObject*)marker_dict, PyInt_FromLong ((long int)marker_it->frame));
+ tmpstr = PyString_FromString(marker_it->name);
+ if (pyo) {
+ PyList_Append (pyo, tmpstr);
+ Py_INCREF(pyo);
+ }else{
+ pyo = PyList_New(0);
+ PyList_Append (pyo, tmpstr);
+ }
+ Py_DECREF(tmpstr);
+
+ PyDict_SetItem (marker_dict, PyInt_FromLong ((long int)marker_it->frame), pyo);
+ if (pyo) {
+ Py_DECREF (pyo);
+ pyo= NULL;
+ }
+ }
+ }
+ }
+
+ }else {
+ marker_dict= PyDict_New ();
+ for (marker_it= self->marker_list->first; marker_it; marker_it= marker_it->next) {
+ pyo=PyDict_GetItem ((PyObject*)marker_dict, PyInt_FromLong ((long int)marker_it->frame));
+ tmpstr = PyString_FromString(marker_it->name);
+ if (pyo) {
+ PyList_Append (pyo, tmpstr);
+ Py_INCREF (pyo);
+ }else{
+ pyo= PyList_New (0);
+ PyList_Append (pyo, tmpstr);
+ }
+ Py_DECREF(tmpstr);
+
+ PyDict_SetItem (marker_dict, PyInt_FromLong ((long int)marker_it->frame), pyo);
+ if (pyo) {
+ Py_DECREF (pyo);
+ pyo= NULL;
+ }
+ }
+ }
+
+ return marker_dict;
+}
+
+static PyObject *TimeLine_addMarker (BPy_TimeLine *self, PyObject *args) {
+ int frame= 0;
+ TimeMarker *marker= NULL, *marker_it= NULL;
+
+ if (!PyArg_ParseTuple( args, "i", &frame ))
+ return EXPP_ReturnPyObjError (PyExc_TypeError,
+ "expected int as argument.");
+ /* two markers can't be at the same place */
+ for (marker_it= self->marker_list->first; marker_it; marker_it= marker_it->next) {
+ if (marker_it->frame==frame)
+ return EXPP_incr_ret (Py_None);
+ }
+ if (frame<self->sfra || frame>self->efra)
+ return EXPP_ReturnPyObjError (PyExc_TypeError, "frame out of range.");
+ marker= MEM_callocN (sizeof(TimeMarker), "TimeMarker");
+ if (!marker) return EXPP_incr_ret (Py_None);
+ marker->frame= frame;
+ BLI_addtail (self->marker_list, marker);
+ return EXPP_incr_ret (Py_None);
+}
+
+static PyObject *TimeLine_delMarker (BPy_TimeLine *self, PyObject *args) {
+ int frame= 0;
+ TimeMarker *marker= NULL;
+
+ if (!PyArg_ParseTuple (args, "|i", &frame))
+ return EXPP_ReturnPyObjError (PyExc_TypeError,
+ "expected int as argument.");
+
+ for (marker= self->marker_list->first; marker; marker= marker->next) {
+ if (!frame)
+ BLI_freelinkN (self->marker_list, marker);
+ else if (marker->frame == frame) {
+ BLI_freelinkN (self->marker_list, marker);
+ return EXPP_incr_ret (Py_None);
+ }
+ }
+
+ return EXPP_incr_ret (Py_None);
+}
+
+static PyObject *TimeLine_setNameMarker (BPy_TimeLine *self, PyObject *args) {
+ char *buf;
+ char name[64];
+ int frame= 0;
+ TimeMarker *marker= NULL;
+
+ if (!PyArg_ParseTuple( args, "is", &frame, &buf))
+ return EXPP_ReturnPyObjError (PyExc_TypeError,
+ "expected int as argument.");
+ PyOS_snprintf (name, sizeof (name), "%s", buf);
+ for (marker= self->marker_list->first; marker; marker= marker->next) {
+ if (marker->frame == frame) {
+ BLI_strncpy(marker->name, name, sizeof(marker->name));
+ return EXPP_incr_ret (Py_None);
+ }
+ }
+
+ return EXPP_ReturnPyObjError (PyExc_TypeError, "frame not marked.");
+}
+
+static PyObject *TimeLine_getNameMarker (BPy_TimeLine *self, PyObject *args) {
+ int frame= 0;
+ TimeMarker *marker;
+
+ if (!PyArg_ParseTuple (args, "i", &frame))
+ return EXPP_ReturnPyObjError (PyExc_TypeError, "expected int as argument.");
+
+ for (marker= self->marker_list->first; marker; marker= marker->next) {
+ if (marker->frame == frame)
+ return PyString_FromString (marker->name);
+ }
+
+ return EXPP_ReturnPyObjError (PyExc_TypeError, "frame not marked.");
+}
+
+
diff --git a/source/blender/python/api2_2x/sceneTimeLine.h b/source/blender/python/api2_2x/sceneTimeLine.h
new file mode 100644
index 00000000000..ffeff1ef3b7
--- /dev/null
+++ b/source/blender/python/api2_2x/sceneTimeLine.h
@@ -0,0 +1,58 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Joilnen Leite
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_TIMELINE_H
+#define EXPP_TIMELINE_H
+
+#include <Python.h>
+#include <DNA_scene_types.h>
+
+extern PyTypeObject TimeLine_Type;
+#define BPy_TimeLine_Check (v) \
+ ((v)->ob_type == &TimeLine_Type)
+
+typedef struct {
+ PyObject_HEAD
+ ListBase *marker_list;
+ int sfra, efra;
+} BPy_TimeLine;
+
+//---------------------------Python BPy_TimeLine visible prototypes-----------
+// Python TimeLine_Type helper functions needed by Blender (the Init function) and Object modules.
+
+
+PyObject *TimeLine_Init (void);
+PyObject *TimeLine_CreatePyObject (BPy_TimeLine *tl);
+BPy_TimeLine *TimeLine_FromPyObject (PyObject * pyobj);
+
+#endif /* EXPP_TMARKER_H */
+
diff --git a/source/blender/python/api2_2x/vector.c b/source/blender/python/api2_2x/vector.c
new file mode 100644
index 00000000000..2e13122f09f
--- /dev/null
+++ b/source/blender/python/api2_2x/vector.c
@@ -0,0 +1,1264 @@
+/*
+ * $Id$
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Willian P. Germano & Joseph Gilbert, Ken Hughes
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "Mathutils.h"
+
+#include "BLI_blenlib.h"
+#include "BKE_utildefines.h"
+#include "BLI_arithb.h"
+#include "gen_utils.h"
+
+
+/*-------------------------DOC STRINGS ---------------------------*/
+char Vector_Zero_doc[] = "() - set all values in the vector to 0";
+char Vector_Normalize_doc[] = "() - normalize the vector";
+char Vector_Negate_doc[] = "() - changes vector to it's additive inverse";
+char Vector_Resize2D_doc[] = "() - resize a vector to [x,y]";
+char Vector_Resize3D_doc[] = "() - resize a vector to [x,y,z]";
+char Vector_Resize4D_doc[] = "() - resize a vector to [x,y,z,w]";
+char Vector_toPoint_doc[] = "() - create a new Point Object from this vector";
+char Vector_ToTrackQuat_doc[] = "(track, up) - extract a quaternion from the vector and the track and up axis";
+char Vector_copy_doc[] = "() - return a copy of the vector";
+/*-----------------------METHOD DEFINITIONS ----------------------*/
+struct PyMethodDef Vector_methods[] = {
+ {"zero", (PyCFunction) Vector_Zero, METH_NOARGS, Vector_Zero_doc},
+ {"normalize", (PyCFunction) Vector_Normalize, METH_NOARGS, Vector_Normalize_doc},
+ {"negate", (PyCFunction) Vector_Negate, METH_NOARGS, Vector_Negate_doc},
+ {"resize2D", (PyCFunction) Vector_Resize2D, METH_NOARGS, Vector_Resize2D_doc},
+ {"resize3D", (PyCFunction) Vector_Resize3D, METH_NOARGS, Vector_Resize2D_doc},
+ {"resize4D", (PyCFunction) Vector_Resize4D, METH_NOARGS, Vector_Resize2D_doc},
+ {"toPoint", (PyCFunction) Vector_toPoint, METH_NOARGS, Vector_toPoint_doc},
+ {"toTrackQuat", ( PyCFunction ) Vector_ToTrackQuat, METH_VARARGS, Vector_ToTrackQuat_doc},
+ {"copy", (PyCFunction) Vector_copy, METH_NOARGS, Vector_copy_doc},
+ {"__copy__", (PyCFunction) Vector_copy, METH_NOARGS, Vector_copy_doc},
+ {NULL, NULL, 0, NULL}
+};
+
+/*-----------------------------METHODS----------------------------
+ --------------------------Vector.toPoint()----------------------
+ create a new point object to represent this vector */
+PyObject *Vector_toPoint(VectorObject * self)
+{
+ float coord[3];
+ int i;
+
+ if(self->size < 2 || self->size > 3) {
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Vector.toPoint(): inappropriate vector size - expects 2d or 3d vector\n");
+ }
+ for(i = 0; i < self->size; i++){
+ coord[i] = self->vec[i];
+ }
+
+ return newPointObject(coord, self->size, Py_NEW);
+}
+/*----------------------------Vector.zero() ----------------------
+ set the vector data to 0,0,0 */
+PyObject *Vector_Zero(VectorObject * self)
+{
+ int i;
+ for(i = 0; i < self->size; i++) {
+ self->vec[i] = 0.0f;
+ }
+ return EXPP_incr_ret((PyObject*)self);
+}
+/*----------------------------Vector.normalize() -----------------
+ normalize the vector data to a unit vector */
+PyObject *Vector_Normalize(VectorObject * self)
+{
+ int i;
+ float norm = 0.0f;
+
+ for(i = 0; i < self->size; i++) {
+ norm += self->vec[i] * self->vec[i];
+ }
+ norm = (float) sqrt(norm);
+ for(i = 0; i < self->size; i++) {
+ self->vec[i] /= norm;
+ }
+ return EXPP_incr_ret((PyObject*)self);
+}
+
+
+/*----------------------------Vector.resize2D() ------------------
+ resize the vector to x,y */
+PyObject *Vector_Resize2D(VectorObject * self)
+{
+ if(self->wrapped==Py_WRAP)
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "vector.resize2d(): cannot resize wrapped data - only python vectors\n");
+
+ self->vec = PyMem_Realloc(self->vec, (sizeof(float) * 2));
+ if(self->vec == NULL)
+ return EXPP_ReturnPyObjError(PyExc_MemoryError,
+ "vector.resize2d(): problem allocating pointer space\n\n");
+
+ self->size = 2;
+ return EXPP_incr_ret((PyObject*)self);
+}
+/*----------------------------Vector.resize3D() ------------------
+ resize the vector to x,y,z */
+PyObject *Vector_Resize3D(VectorObject * self)
+{
+ if (self->wrapped==Py_WRAP)
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "vector.resize3d(): cannot resize wrapped data - only python vectors\n");
+
+ self->vec = PyMem_Realloc(self->vec, (sizeof(float) * 3));
+ if(self->vec == NULL)
+ return EXPP_ReturnPyObjError(PyExc_MemoryError,
+ "vector.resize3d(): problem allocating pointer space\n\n");
+
+ if(self->size == 2)
+ self->vec[2] = 0.0f;
+
+ self->size = 3;
+ return EXPP_incr_ret((PyObject*)self);
+}
+/*----------------------------Vector.resize4D() ------------------
+ resize the vector to x,y,z,w */
+PyObject *Vector_Resize4D(VectorObject * self)
+{
+ if(self->wrapped==Py_WRAP)
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "vector.resize4d(): cannot resize wrapped data - only python vectors\n");
+
+ self->vec = PyMem_Realloc(self->vec, (sizeof(float) * 4));
+ if(self->vec == NULL)
+ return EXPP_ReturnPyObjError(PyExc_MemoryError,
+ "vector.resize4d(): problem allocating pointer space\n\n");
+
+ if(self->size == 2){
+ self->vec[2] = 0.0f;
+ self->vec[3] = 1.0f;
+ }else if(self->size == 3){
+ self->vec[3] = 1.0f;
+ }
+ self->size = 4;
+ return EXPP_incr_ret((PyObject*)self);
+}
+/*----------------------------Vector.toTrackQuat(track, up) ----------------------
+ extract a quaternion from the vector and the track and up axis */
+PyObject *Vector_ToTrackQuat( VectorObject * self, PyObject * args )
+{
+ float vec[3];
+ char *strack, *sup;
+ short track = 2, up = 1;
+
+ if( !PyArg_ParseTuple ( args, "|ss", &strack, &sup ) ) {
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected optional two strings\n" );
+ }
+ if (self->size != 3) {
+ return EXPP_ReturnPyObjError( PyExc_TypeError, "only for 3D vectors\n" );
+ }
+
+ if (strack) {
+ if (strlen(strack) == 2) {
+ if (strack[0] == '-') {
+ switch(strack[1]) {
+ case 'X':
+ case 'x':
+ track = 3;
+ break;
+ case 'Y':
+ case 'y':
+ track = 4;
+ break;
+ case 'z':
+ case 'Z':
+ track = 5;
+ break;
+ default:
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "only X, -X, Y, -Y, Z or -Z for track axis\n" );
+ }
+ }
+ else {
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "only X, -X, Y, -Y, Z or -Z for track axis\n" );
+ }
+ }
+ else if (strlen(strack) == 1) {
+ switch(strack[0]) {
+ case '-':
+ case 'X':
+ case 'x':
+ track = 0;
+ break;
+ case 'Y':
+ case 'y':
+ track = 1;
+ break;
+ case 'z':
+ case 'Z':
+ track = 2;
+ break;
+ default:
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "only X, -X, Y, -Y, Z or -Z for track axis\n" );
+ }
+ }
+ else {
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "only X, -X, Y, -Y, Z or -Z for track axis\n" );
+ }
+ }
+
+ if (sup) {
+ if (strlen(sup) == 1) {
+ switch(*sup) {
+ case 'X':
+ case 'x':
+ up = 0;
+ break;
+ case 'Y':
+ case 'y':
+ up = 1;
+ break;
+ case 'z':
+ case 'Z':
+ up = 2;
+ break;
+ default:
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "only X, Y or Z for up axis\n" );
+ }
+ }
+ else {
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "only X, Y or Z for up axis\n" );
+ }
+ }
+
+ if (track == up) {
+ return EXPP_ReturnPyObjError( PyExc_ValueError,
+ "Can't have the same axis for track and up\n" );
+ }
+
+ /*
+ flip vector around, since vectoquat expect a vector from target to tracking object
+ and the python function expects the inverse (a vector to the target).
+ */
+ vec[0] = -self->vec[0];
+ vec[1] = -self->vec[1];
+ vec[2] = -self->vec[2];
+
+ return newQuaternionObject(vectoquat(vec, track, up), Py_NEW);
+}
+
+
+
+/*----------------------------Vector.copy() --------------------------------------
+ return a copy of the vector */
+PyObject *Vector_copy(VectorObject * self)
+{
+ return newVectorObject(self->vec, self->size, Py_NEW);
+}
+
+/*----------------------------dealloc()(internal) ----------------
+ free the py_object */
+static void Vector_dealloc(VectorObject * self)
+{
+ /* only free non wrapped */
+ if(self->wrapped != Py_WRAP){
+ PyMem_Free(self->vec);
+ }
+ PyObject_DEL(self);
+}
+
+/*----------------------------print object (internal)-------------
+ print the object to screen */
+static PyObject *Vector_repr(VectorObject * self)
+{
+ int i;
+ char buffer[48], str[1024];
+
+ BLI_strncpy(str,"[",1024);
+ for(i = 0; i < self->size; i++){
+ if(i < (self->size - 1)){
+ sprintf(buffer, "%.6f, ", self->vec[i]);
+ strcat(str,buffer);
+ }else{
+ sprintf(buffer, "%.6f", self->vec[i]);
+ strcat(str,buffer);
+ }
+ }
+ strcat(str, "](vector)");
+
+ return PyString_FromString(str);
+}
+/*---------------------SEQUENCE PROTOCOLS------------------------
+ ----------------------------len(object)------------------------
+ sequence length*/
+static int Vector_len(VectorObject * self)
+{
+ return self->size;
+}
+/*----------------------------object[]---------------------------
+ sequence accessor (get)*/
+static PyObject *Vector_item(VectorObject * self, int i)
+{
+ if(i < 0 || i >= self->size)
+ return EXPP_ReturnPyObjError(PyExc_IndexError,
+ "vector[index]: out of range\n");
+
+ return PyFloat_FromDouble(self->vec[i]);
+
+}
+/*----------------------------object[]-------------------------
+ sequence accessor (set)*/
+static int Vector_ass_item(VectorObject * self, int i, PyObject * ob)
+{
+
+ if(!(PyNumber_Check(ob))) { /* parsed item not a number */
+ return EXPP_ReturnIntError(PyExc_TypeError,
+ "vector[index] = x: index argument not a number\n");
+ }
+
+ if(i < 0 || i >= self->size){
+ return EXPP_ReturnIntError(PyExc_IndexError,
+ "vector[index] = x: assignment index out of range\n");
+ }
+ self->vec[i] = (float)PyFloat_AsDouble(ob);
+ return 0;
+}
+
+/*----------------------------object[z:y]------------------------
+ sequence slice (get) */
+static PyObject *Vector_slice(VectorObject * self, int begin, int end)
+{
+ PyObject *list = NULL;
+ int count;
+
+ CLAMP(begin, 0, self->size);
+ if (end<0) end= self->size+end+1;
+ CLAMP(end, 0, self->size);
+ begin = MIN2(begin,end);
+
+ list = PyList_New(end - begin);
+ for(count = begin; count < end; count++) {
+ PyList_SetItem(list, count - begin,
+ PyFloat_FromDouble(self->vec[count]));
+ }
+
+ return list;
+}
+/*----------------------------object[z:y]------------------------
+ sequence slice (set) */
+static int Vector_ass_slice(VectorObject * self, int begin, int end,
+ PyObject * seq)
+{
+ int i, y, size = 0;
+ float vec[4];
+ PyObject *v;
+
+ CLAMP(begin, 0, self->size);
+ if (end<0) end= self->size+end+1;
+ CLAMP(end, 0, self->size);
+ begin = MIN2(begin,end);
+
+ size = PySequence_Length(seq);
+ if(size != (end - begin)){
+ return EXPP_ReturnIntError(PyExc_TypeError,
+ "vector[begin:end] = []: size mismatch in slice assignment\n");
+ }
+
+ for (i = 0; i < size; i++) {
+ v = PySequence_GetItem(seq, i);
+ if (v == NULL) { /* Failed to read sequence */
+ return EXPP_ReturnIntError(PyExc_RuntimeError,
+ "vector[begin:end] = []: unable to read sequence\n");
+ }
+
+ if(!PyNumber_Check(v)) { /* parsed item not a number */
+ Py_DECREF(v);
+ return EXPP_ReturnIntError(PyExc_TypeError,
+ "vector[begin:end] = []: sequence argument not a number\n");
+ }
+
+ vec[i] = (float)PyFloat_AsDouble(v);
+ Py_DECREF(v);
+ }
+ /*parsed well - now set in vector*/
+ for(y = 0; y < size; y++){
+ self->vec[begin + y] = vec[y];
+ }
+ return 0;
+}
+/*------------------------NUMERIC PROTOCOLS----------------------
+ ------------------------obj + obj------------------------------
+ addition*/
+static PyObject *Vector_add(PyObject * v1, PyObject * v2)
+{
+ int i;
+ float vec[4];
+
+ VectorObject *vec1 = NULL, *vec2 = NULL;
+
+ if VectorObject_Check(v1)
+ vec1= (VectorObject *)v1;
+
+ if VectorObject_Check(v2)
+ vec2= (VectorObject *)v2;
+
+ /* make sure v1 is always the vector */
+ if (vec1 && vec2 ) {
+ /*VECTOR + VECTOR*/
+ if(vec1->size != vec2->size)
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Vector addition: vectors must have the same dimensions for this operation\n");
+
+ for(i = 0; i < vec1->size; i++) {
+ vec[i] = vec1->vec[i] + vec2->vec[i];
+ }
+ return newVectorObject(vec, vec1->size, Py_NEW);
+ }
+
+ if(PointObject_Check(v2)){ /*VECTOR + POINT*/
+ /*Point translation*/
+ PointObject *pt = (PointObject*)v2;
+
+ if(pt->size == vec1->size){
+ for(i = 0; i < vec1->size; i++){
+ vec[i] = vec1->vec[i] + pt->coord[i];
+ }
+ }else{
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Vector addition: arguments are the wrong size....\n");
+ }
+ return newPointObject(vec, vec1->size, Py_NEW);
+ }
+
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Vector addition: arguments not valid for this operation....\n");
+}
+
+/* ------------------------obj += obj------------------------------
+ addition in place */
+static PyObject *Vector_iadd(PyObject * v1, PyObject * v2)
+{
+ int i;
+
+ VectorObject *vec1 = NULL, *vec2 = NULL;
+
+ if VectorObject_Check(v1)
+ vec1= (VectorObject *)v1;
+
+ if VectorObject_Check(v2)
+ vec2= (VectorObject *)v2;
+
+ /* make sure v1 is always the vector */
+ if (vec1 && vec2 ) {
+ /*VECTOR + VECTOR*/
+ if(vec1->size != vec2->size)
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Vector addition: vectors must have the same dimensions for this operation\n");
+
+ for(i = 0; i < vec1->size; i++) {
+ vec1->vec[i] += vec2->vec[i];
+ }
+ Py_INCREF( v1 );
+ return v1;
+ }
+
+ if(PointObject_Check(v2)){ /*VECTOR + POINT*/
+ /*Point translation*/
+ PointObject *pt = (PointObject*)v2;
+
+ if(pt->size == vec1->size){
+ for(i = 0; i < vec1->size; i++){
+ vec1->vec[i] += pt->coord[i];
+ }
+ }else{
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Vector addition: arguments are the wrong size....\n");
+ }
+ Py_INCREF( v1 );
+ return v1;
+ }
+
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Vector addition: arguments not valid for this operation....\n");
+}
+
+/*------------------------obj - obj------------------------------
+ subtraction*/
+static PyObject *Vector_sub(PyObject * v1, PyObject * v2)
+{
+ int i;
+ float vec[4];
+ VectorObject *vec1 = NULL, *vec2 = NULL;
+
+ if (!VectorObject_Check(v1) || !VectorObject_Check(v2))
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Vector subtraction: arguments not valid for this operation....\n");
+
+ vec1 = (VectorObject*)v1;
+ vec2 = (VectorObject*)v2;
+
+ if(vec1->size != vec2->size)
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Vector subtraction: vectors must have the same dimensions for this operation\n");
+
+ for(i = 0; i < vec1->size; i++) {
+ vec[i] = vec1->vec[i] - vec2->vec[i];
+ }
+
+ return newVectorObject(vec, vec1->size, Py_NEW);
+}
+
+/*------------------------obj -= obj------------------------------
+ subtraction*/
+static PyObject *Vector_isub(PyObject * v1, PyObject * v2)
+{
+ int i, size;
+ VectorObject *vec1 = NULL, *vec2 = NULL;
+
+ if (!VectorObject_Check(v1) || !VectorObject_Check(v2))
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Vector subtraction: arguments not valid for this operation....\n");
+
+ vec1 = (VectorObject*)v1;
+ vec2 = (VectorObject*)v2;
+
+ if(vec1->size != vec2->size)
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Vector subtraction: vectors must have the same dimensions for this operation\n");
+
+ size = vec1->size;
+ for(i = 0; i < vec1->size; i++) {
+ vec1->vec[i] = vec1->vec[i] - vec2->vec[i];
+ }
+
+ Py_INCREF( v1 );
+ return v1;
+}
+
+/*------------------------obj * obj------------------------------
+ mulplication*/
+static PyObject *Vector_mul(PyObject * v1, PyObject * v2)
+{
+ VectorObject *vec1 = NULL, *vec2 = NULL;
+
+ if VectorObject_Check(v1)
+ vec1= (VectorObject *)v1;
+
+ if VectorObject_Check(v2)
+ vec2= (VectorObject *)v2;
+
+ /* make sure v1 is always the vector */
+ if (vec1 && vec2 ) {
+ int i;
+ double dot = 0.0f;
+
+ if(vec1->size != vec2->size)
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "Vector multiplication: vectors must have the same dimensions for this operation\n");
+
+ /*dot product*/
+ for(i = 0; i < vec1->size; i++) {
+ dot += vec1->vec[i] * vec2->vec[i];
+ }
+ return PyFloat_FromDouble(dot);
+ }
+
+ /*swap so vec1 is always the vector */
+ if (vec2) {
+ vec1= vec2;
+ v2= v1;
+ }
+
+ if (PyNumber_Check(v2)) {
+ /* VEC * NUM */
+ int i;
+ float vec[4];
+ float scalar = (float)PyFloat_AsDouble( v2 );
+
+ for(i = 0; i < vec1->size; i++) {
+ vec[i] = vec1->vec[i] * scalar;
+ }
+ return newVectorObject(vec, vec1->size, Py_NEW);
+
+ } else if (MatrixObject_Check(v2)) {
+ /* VEC * MATRIX */
+ if (v1==v2) /* mat*vec, we have swapped the order */
+ return column_vector_multiplication((MatrixObject*)v2, vec1);
+ else /* vec*mat */
+ return row_vector_multiplication(vec1, (MatrixObject*)v2);
+ } else if (QuaternionObject_Check(v2)) {
+ QuaternionObject *quat = (QuaternionObject*)v2;
+ if(vec1->size != 3)
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Vector multiplication: only 3D vector rotations (with quats) currently supported\n");
+
+ return quat_rotation((PyObject*)vec1, (PyObject*)quat);
+ }
+
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Vector multiplication: arguments not acceptable for this operation\n");
+}
+
+/*------------------------obj *= obj------------------------------
+ in place mulplication */
+static PyObject *Vector_imul(PyObject * v1, PyObject * v2)
+{
+ VectorObject *vec = (VectorObject *)v1;
+ int i;
+
+ /* only support vec*=float and vec*=mat
+ vec*=vec result is a float so that wont work */
+ if (PyNumber_Check(v2)) {
+ /* VEC * NUM */
+ float scalar = (float)PyFloat_AsDouble( v2 );
+
+ for(i = 0; i < vec->size; i++) {
+ vec->vec[i] *= scalar;
+ }
+
+ Py_INCREF( v1 );
+ return v1;
+
+ } else if (MatrixObject_Check(v2)) {
+ float vecCopy[4];
+ int x,y, size = vec->size;
+ MatrixObject *mat= (MatrixObject*)v2;
+
+ if(mat->colSize != size){
+ if(mat->rowSize == 4 && vec->size != 3){
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "vector * matrix: matrix column size and the vector size must be the same");
+ } else {
+ vecCopy[3] = 1.0f;
+ }
+ }
+
+ for(i = 0; i < size; i++){
+ vecCopy[i] = vec->vec[i];
+ }
+
+ size = MIN2(size, mat->colSize);
+
+ /*muliplication*/
+ for(x = 0, i = 0; x < size; x++, i++) {
+ double dot = 0.0f;
+ for(y = 0; y < mat->rowSize; y++) {
+ dot += mat->matrix[y][x] * vecCopy[y];
+ }
+ vec->vec[i] = (float)dot;
+ }
+ Py_INCREF( v1 );
+ return v1;
+ }
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Vector multiplication: arguments not acceptable for this operation\n");
+}
+
+/*------------------------obj / obj------------------------------
+ divide*/
+static PyObject *Vector_div(PyObject * v1, PyObject * v2)
+{
+ int i, size;
+ float vec[4], scalar;
+ VectorObject *vec1 = NULL;
+
+ if(!VectorObject_Check(v1)) /* not a vector */
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Vector division: Vector must be divided by a float\n");
+
+ vec1 = (VectorObject*)v1; /* vector */
+
+ if(!PyNumber_Check(v2)) /* parsed item not a number */
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Vector division: Vector must be divided by a float\n");
+
+ scalar = (float)PyFloat_AsDouble(v2);
+
+ if(scalar==0.0) /* not a vector */
+ return EXPP_ReturnPyObjError(PyExc_ZeroDivisionError,
+ "Vector division: divide by zero error.\n");
+
+ size = vec1->size;
+ for(i = 0; i < size; i++) {
+ vec[i] = vec1->vec[i] / scalar;
+ }
+ return newVectorObject(vec, size, Py_NEW);
+}
+
+/*------------------------obj / obj------------------------------
+ divide*/
+static PyObject *Vector_idiv(PyObject * v1, PyObject * v2)
+{
+ int i, size;
+ float scalar;
+ VectorObject *vec1 = NULL;
+
+ /*if(!VectorObject_Check(v1))
+ return EXPP_ReturnIntError(PyExc_TypeError,
+ "Vector division: Vector must be divided by a float\n");*/
+
+ vec1 = (VectorObject*)v1; /* vector */
+
+ if(!PyNumber_Check(v2)) /* parsed item not a number */
+ return EXPP_ReturnPyObjError(PyExc_TypeError,
+ "Vector division: Vector must be divided by a float\n");
+
+ scalar = (float)PyFloat_AsDouble(v2);
+
+ if(scalar==0.0) /* not a vector */
+ return EXPP_ReturnPyObjError(PyExc_ZeroDivisionError,
+ "Vector division: divide by zero error.\n");
+
+ size = vec1->size;
+ for(i = 0; i < size; i++) {
+ vec1->vec[i] /= scalar;
+ }
+ Py_INCREF( v1 );
+ return v1;
+}
+
+/*-------------------------- -obj -------------------------------
+ returns the negative of this object*/
+static PyObject *Vector_neg(VectorObject *self)
+{
+ int i;
+ float vec[4];
+ for(i = 0; i < self->size; i++){
+ vec[i] = -self->vec[i];
+ }
+
+ return newVectorObject(vec, self->size, Py_NEW);
+}
+/*------------------------coerce(obj, obj)-----------------------
+ coercion of unknown types to type VectorObject for numeric protocols
+ Coercion() is called whenever a math operation has 2 operands that
+ it doesn't understand how to evaluate. 2+Matrix for example. We want to
+ evaluate some of these operations like: (vector * 2), however, for math
+ to proceed, the unknown operand must be cast to a type that python math will
+ understand. (e.g. in the case above case, 2 must be cast to a vector and
+ then call vector.multiply(vector, scalar_cast_as_vector)*/
+
+
+static int Vector_coerce(PyObject ** v1, PyObject ** v2)
+{
+ /* Just incref, each functon must raise errors for bad types */
+ Py_INCREF (*v1);
+ Py_INCREF (*v2);
+ return 0;
+}
+
+
+/*------------------------tp_doc*/
+static char VectorObject_doc[] = "This is a wrapper for vector objects.";
+/*------------------------vec_magnitude_nosqrt (internal) - for comparing only */
+static double vec_magnitude_nosqrt(float *data, int size)
+{
+ double dot = 0.0f;
+ int i;
+
+ for(i=0; i<size; i++){
+ dot += data[i];
+ }
+ /*return (double)sqrt(dot);*/
+ /* warning, line above removed because we are not using the length,
+ rather the comparing the sizes and for this we do not need the sqrt
+ for the actual length, the dot must be sqrt'd */
+ return (double)dot;
+}
+
+
+/*------------------------tp_richcmpr
+ returns -1 execption, 0 false, 1 true */
+PyObject* Vector_richcmpr(PyObject *objectA, PyObject *objectB, int comparison_type)
+{
+ VectorObject *vecA = NULL, *vecB = NULL;
+ int result = 0;
+ float epsilon = .000001f;
+ double lenA,lenB;
+
+ if (!VectorObject_Check(objectA) || !VectorObject_Check(objectB)){
+ if (comparison_type == Py_NE){
+ return EXPP_incr_ret(Py_True);
+ }else{
+ return EXPP_incr_ret(Py_False);
+ }
+ }
+ vecA = (VectorObject*)objectA;
+ vecB = (VectorObject*)objectB;
+
+ if (vecA->size != vecB->size){
+ if (comparison_type == Py_NE){
+ return EXPP_incr_ret(Py_True);
+ }else{
+ return EXPP_incr_ret(Py_False);
+ }
+ }
+
+ switch (comparison_type){
+ case Py_LT:
+ lenA = vec_magnitude_nosqrt(vecA->vec, vecA->size);
+ lenB = vec_magnitude_nosqrt(vecB->vec, vecB->size);
+ if( lenA < lenB ){
+ result = 1;
+ }
+ break;
+ case Py_LE:
+ lenA = vec_magnitude_nosqrt(vecA->vec, vecA->size);
+ lenB = vec_magnitude_nosqrt(vecB->vec, vecB->size);
+ if( lenA < lenB ){
+ result = 1;
+ }else{
+ result = (((lenA + epsilon) > lenB) && ((lenA - epsilon) < lenB));
+ }
+ break;
+ case Py_EQ:
+ result = EXPP_VectorsAreEqual(vecA->vec, vecB->vec, vecA->size, 1);
+ break;
+ case Py_NE:
+ result = EXPP_VectorsAreEqual(vecA->vec, vecB->vec, vecA->size, 1);
+ if (result == 0){
+ result = 1;
+ }else{
+ result = 0;
+ }
+ break;
+ case Py_GT:
+ lenA = vec_magnitude_nosqrt(vecA->vec, vecA->size);
+ lenB = vec_magnitude_nosqrt(vecB->vec, vecB->size);
+ if( lenA > lenB ){
+ result = 1;
+ }
+ break;
+ case Py_GE:
+ lenA = vec_magnitude_nosqrt(vecA->vec, vecA->size);
+ lenB = vec_magnitude_nosqrt(vecB->vec, vecB->size);
+ if( lenA > lenB ){
+ result = 1;
+ }else{
+ result = (((lenA + epsilon) > lenB) && ((lenA - epsilon) < lenB));
+ }
+ break;
+ default:
+ printf("The result of the comparison could not be evaluated");
+ break;
+ }
+ if (result == 1){
+ return EXPP_incr_ret(Py_True);
+ }else{
+ return EXPP_incr_ret(Py_False);
+ }
+}
+/*-----------------PROTCOL DECLARATIONS--------------------------*/
+static PySequenceMethods Vector_SeqMethods = {
+ (inquiry) Vector_len, /* sq_length */
+ (binaryfunc) 0, /* sq_concat */
+ (intargfunc) 0, /* sq_repeat */
+ (intargfunc) Vector_item, /* sq_item */
+ (intintargfunc) Vector_slice, /* sq_slice */
+ (intobjargproc) Vector_ass_item, /* sq_ass_item */
+ (intintobjargproc) Vector_ass_slice, /* sq_ass_slice */
+};
+
+
+/* For numbers without flag bit Py_TPFLAGS_CHECKTYPES set, all
+ arguments are guaranteed to be of the object's type (modulo
+ coercion hacks -- i.e. if the type's coercion function
+ returns other types, then these are allowed as well). Numbers that
+ have the Py_TPFLAGS_CHECKTYPES flag bit set should check *both*
+ arguments for proper type and implement the necessary conversions
+ in the slot functions themselves. */
+
+static PyNumberMethods Vector_NumMethods = {
+ (binaryfunc) Vector_add, /* __add__ */
+ (binaryfunc) Vector_sub, /* __sub__ */
+ (binaryfunc) Vector_mul, /* __mul__ */
+ (binaryfunc) Vector_div, /* __div__ */
+ (binaryfunc) NULL, /* __mod__ */
+ (binaryfunc) NULL, /* __divmod__ */
+ (ternaryfunc) NULL, /* __pow__ */
+ (unaryfunc) Vector_neg, /* __neg__ */
+ (unaryfunc) NULL, /* __pos__ */
+ (unaryfunc) NULL, /* __abs__ */
+ (inquiry) NULL, /* __nonzero__ */
+ (unaryfunc) NULL, /* __invert__ */
+ (binaryfunc) NULL, /* __lshift__ */
+ (binaryfunc) NULL, /* __rshift__ */
+ (binaryfunc) NULL, /* __and__ */
+ (binaryfunc) NULL, /* __xor__ */
+ (binaryfunc) NULL, /* __or__ */
+ (coercion) Vector_coerce, /* __coerce__ */
+ (unaryfunc) NULL, /* __int__ */
+ (unaryfunc) NULL, /* __long__ */
+ (unaryfunc) NULL, /* __float__ */
+ (unaryfunc) NULL, /* __oct__ */
+ (unaryfunc) NULL, /* __hex__ */
+
+ /* Added in release 2.0 */
+ (binaryfunc) Vector_iadd, /*__iadd__*/
+ (binaryfunc) Vector_isub, /*__isub__*/
+ (binaryfunc) Vector_imul, /*__imul__*/
+ (binaryfunc) Vector_idiv, /*__idiv__*/
+ (binaryfunc) NULL, /*__imod__*/
+ (ternaryfunc) NULL, /*__ipow__*/
+ (binaryfunc) NULL, /*__ilshift__*/
+ (binaryfunc) NULL, /*__irshift__*/
+ (binaryfunc) NULL, /*__iand__*/
+ (binaryfunc) NULL, /*__ixor__*/
+ (binaryfunc) NULL, /*__ior__*/
+
+ /* Added in release 2.2 */
+ /* The following require the Py_TPFLAGS_HAVE_CLASS flag */
+ (binaryfunc) NULL, /*__floordiv__ __rfloordiv__*/
+ (binaryfunc) NULL, /*__truediv__ __rfloordiv__*/
+ (binaryfunc) NULL, /*__ifloordiv__*/
+ (binaryfunc) NULL, /*__itruediv__*/
+};
+/*------------------PY_OBECT DEFINITION--------------------------*/
+
+/*
+ * vector axis, vector.x/y/z/w
+ */
+
+static PyObject *Vector_getAxis( VectorObject * self, void *type )
+{
+ switch( (long)type ) {
+ case 'X': /* these are backwards, but that how it works */
+ return PyFloat_FromDouble(self->vec[0]);
+ case 'Y':
+ return PyFloat_FromDouble(self->vec[1]);
+ case 'Z': /* these are backwards, but that how it works */
+ if(self->size < 3)
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "vector.z: error, cannot get this axis for a 2D vector\n");
+ else
+ return PyFloat_FromDouble(self->vec[2]);
+ case 'W':
+ if(self->size < 4)
+ return EXPP_ReturnPyObjError(PyExc_AttributeError,
+ "vector.w: error, cannot get this axis for a 3D vector\n");
+
+ return PyFloat_FromDouble(self->vec[3]);
+ default:
+ {
+ char errstr[1024];
+ sprintf( errstr, "undefined type '%d' in Vector_getAxis",
+ (int)((long)type & 0xff));
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError, errstr );
+ }
+ }
+}
+
+static int Vector_setAxis( VectorObject * self, PyObject * value, void * type )
+{
+ float param;
+
+ if (!PyNumber_Check(value))
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a number for the vector axis" );
+
+ param= (float)PyFloat_AsDouble( value );
+
+ switch( (long)type ) {
+ case 'X': /* these are backwards, but that how it works */
+ self->vec[0]= param;
+ break;
+ case 'Y':
+ self->vec[1]= param;
+ break;
+ case 'Z': /* these are backwards, but that how it works */
+ if(self->size < 3)
+ return EXPP_ReturnIntError(PyExc_AttributeError,
+ "vector.z: error, cannot get this axis for a 2D vector\n");
+ self->vec[2]= param;
+ break;
+ case 'W':
+ if(self->size < 4)
+ return EXPP_ReturnIntError(PyExc_AttributeError,
+ "vector.w: error, cannot get this axis for a 3D vector\n");
+
+ self->vec[3]= param;
+ break;
+ default:
+ {
+ char errstr[1024];
+ sprintf( errstr, "undefined type '%d' in Vector_setAxis",
+ (int)((long)type & 0xff));
+ return EXPP_ReturnIntError( PyExc_RuntimeError, errstr );
+ }
+ }
+
+ return 0;
+}
+
+/* vector.length */
+static PyObject *Vector_getLength( VectorObject * self, void *type )
+{
+ double dot = 0.0f;
+ int i;
+
+ for(i = 0; i < self->size; i++){
+ dot += (self->vec[i] * self->vec[i]);
+ }
+ return PyFloat_FromDouble(sqrt(dot));
+}
+
+static int Vector_setLength( VectorObject * self, PyObject * value )
+{
+ double dot = 0.0f, param;
+ int i;
+
+ if (!PyNumber_Check(value))
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected a number for the vector axis" );
+
+ param= PyFloat_AsDouble( value );
+
+ if (param < 0)
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "cannot set a vectors length to a negative value" );
+
+ if (param==0) {
+ for(i = 0; i < self->size; i++){
+ self->vec[i]= 0;
+ }
+ return 0;
+ }
+
+ for(i = 0; i < self->size; i++){
+ dot += (self->vec[i] * self->vec[i]);
+ }
+
+ if (!dot) /* cant sqrt zero */
+ return 0;
+
+ dot = sqrt(dot);
+
+ if (dot==param)
+ return 0;
+
+ dot= dot/param;
+
+ for(i = 0; i < self->size; i++){
+ self->vec[i]= self->vec[i] / (float)dot;
+ }
+
+ return 0;
+}
+
+static PyObject *Vector_getWrapped( VectorObject * self, void *type )
+{
+ if (self->wrapped == Py_WRAP)
+ Py_RETURN_TRUE;
+ else
+ Py_RETURN_FALSE;
+}
+
+
+/*****************************************************************************/
+/* Python attributes get/set structure: */
+/*****************************************************************************/
+static PyGetSetDef Vector_getseters[] = {
+ {"x",
+ (getter)Vector_getAxis, (setter)Vector_setAxis,
+ "Vector X axis",
+ (void *)'X'},
+ {"y",
+ (getter)Vector_getAxis, (setter)Vector_setAxis,
+ "Vector Y axis",
+ (void *)'Y'},
+ {"z",
+ (getter)Vector_getAxis, (setter)Vector_setAxis,
+ "Vector Z axis",
+ (void *)'Z'},
+ {"w",
+ (getter)Vector_getAxis, (setter)Vector_setAxis,
+ "Vector Z axis",
+ (void *)'W'},
+ {"length",
+ (getter)Vector_getLength, (setter)Vector_setLength,
+ "Vector Length",
+ NULL},
+ {"magnitude",
+ (getter)Vector_getLength, (setter)Vector_setLength,
+ "Vector Length",
+ NULL},
+ {"wrapped",
+ (getter)Vector_getWrapped, (setter)NULL,
+ "Vector Length",
+ NULL},
+ {NULL,NULL,NULL,NULL,NULL} /* Sentinel */
+};
+
+
+
+/* Note
+ Py_TPFLAGS_CHECKTYPES allows us to avoid casting all types to Vector when coercing
+ but this means for eg that
+ vec*mat and mat*vec both get sent to Vector_mul and it neesd to sort out the order
+*/
+
+PyTypeObject vector_Type = {
+ PyObject_HEAD_INIT( NULL ) /* required py macro */
+ 0, /* ob_size */
+ /* For printing, in format "<module>.<name>" */
+ "Blender Vector", /* char *tp_name; */
+ sizeof( VectorObject ), /* int tp_basicsize; */
+ 0, /* tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ ( destructor ) Vector_dealloc,/* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* cmpfunc tp_compare; */
+ ( reprfunc ) Vector_repr, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ &Vector_NumMethods, /* PyNumberMethods *tp_as_number; */
+ &Vector_SeqMethods, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /*** Flags to define presence of optional/expanded features ***/
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /* long tp_flags; */
+
+ VectorObject_doc, /* char *tp_doc; Documentation string */
+ /*** Assigned meaning in release 2.0 ***/
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /*** Assigned meaning in release 2.1 ***/
+ /*** rich comparisons ***/
+ (richcmpfunc)Vector_richcmpr, /* richcmpfunc tp_richcompare; */
+
+ /*** weak reference enabler ***/
+ 0, /* long tp_weaklistoffset; */
+
+ /*** Added in release 2.2 ***/
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /*** Attribute descriptor and subclassing stuff ***/
+ Vector_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ Vector_getseters, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* long tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ NULL, /* newfunc tp_new; */
+ /* Low-level free-memory routine */
+ NULL, /* freefunc tp_free; */
+ /* For PyObject_IS_GC */
+ NULL, /* inquiry tp_is_gc; */
+ NULL, /* PyObject *tp_bases; */
+ /* method resolution order */
+ NULL, /* PyObject *tp_mro; */
+ NULL, /* PyObject *tp_cache; */
+ NULL, /* PyObject *tp_subclasses; */
+ NULL, /* PyObject *tp_weaklist; */
+ NULL
+};
+
+
+/*------------------------newVectorObject (internal)-------------
+ creates a new vector object
+ pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER
+ (i.e. it was allocated elsewhere by MEM_mallocN())
+ pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON
+ (i.e. it must be created here with PyMEM_malloc())*/
+PyObject *newVectorObject(float *vec, int size, int type)
+{
+ int i;
+ VectorObject *self = PyObject_NEW(VectorObject, &vector_Type);
+
+ if(size > 4 || size < 2)
+ return NULL;
+ self->size = size;
+
+ if(type == Py_WRAP) {
+ self->vec = vec;
+ self->wrapped = Py_WRAP;
+ } else if (type == Py_NEW) {
+ self->vec = PyMem_Malloc(size * sizeof(float));
+ if(!vec) { /*new empty*/
+ for(i = 0; i < size; i++){
+ self->vec[i] = 0.0f;
+ }
+ if(size == 4) /* do the homogenous thing */
+ self->vec[3] = 1.0f;
+ }else{
+ for(i = 0; i < size; i++){
+ self->vec[i] = vec[i];
+ }
+ }
+ self->wrapped = Py_NEW;
+ }else{ /*bad type*/
+ return NULL;
+ }
+ return (PyObject *) self;
+}
+
+/*
+ #############################DEPRECATED################################
+ #######################################################################
+ ----------------------------Vector.negate() --------------------
+ set the vector to it's negative -x, -y, -z */
+PyObject *Vector_Negate(VectorObject * self)
+{
+ int i;
+ for(i = 0; i < self->size; i++) {
+ self->vec[i] = -(self->vec[i]);
+ }
+ /*printf("Vector.negate(): Deprecated: use -vector instead\n");*/
+ return EXPP_incr_ret((PyObject*)self);
+}
+/*###################################################################
+ ###########################DEPRECATED##############################*/
+
diff --git a/source/blender/python/api2_2x/vector.h b/source/blender/python/api2_2x/vector.h
new file mode 100644
index 00000000000..3f58d9fa6d5
--- /dev/null
+++ b/source/blender/python/api2_2x/vector.h
@@ -0,0 +1,61 @@
+/* $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Willian P. Germano & Joseph Gilbert
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ *
+ */
+
+#ifndef EXPP_vector_h
+#define EXPP_vector_h
+
+#include <Python.h>
+
+extern PyTypeObject vector_Type;
+
+#define VectorObject_Check(v) ((v)->ob_type == &vector_Type)
+
+typedef struct {
+ PyObject_VAR_HEAD
+ float *vec; /*1D array of data (alias), wrapped status depends on wrapped status */
+ short size; /* vec size 2,3 or 4 */
+ short wrapped; /* is wrapped data? */
+} VectorObject;
+
+/*prototypes*/
+PyObject *Vector_Zero( VectorObject * self );
+PyObject *Vector_Normalize( VectorObject * self );
+PyObject *Vector_Negate( VectorObject * self );
+PyObject *Vector_Resize2D( VectorObject * self );
+PyObject *Vector_Resize3D( VectorObject * self );
+PyObject *Vector_Resize4D( VectorObject * self );
+PyObject *Vector_toPoint( VectorObject * self );
+PyObject *Vector_ToTrackQuat( VectorObject * self, PyObject * args );
+PyObject *Vector_copy( VectorObject * self );
+PyObject *newVectorObject(float *vec, int size, int type);
+
+#endif /* EXPP_vector_h */
diff --git a/source/blender/python/api2_2x/windowTheme.c b/source/blender/python/api2_2x/windowTheme.c
new file mode 100644
index 00000000000..6a27d59436e
--- /dev/null
+++ b/source/blender/python/api2_2x/windowTheme.c
@@ -0,0 +1,828 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#include "windowTheme.h" /*This must come first*/
+
+#include "BLI_blenlib.h"
+#include "BIF_interface_icons.h"
+#include "BIF_resources.h"
+#include "MEM_guardedalloc.h"
+#include "charRGBA.h"
+#include "gen_utils.h"
+
+
+#define EXPP_THEME_VTX_SIZE_MIN 1
+#define EXPP_THEME_VTX_SIZE_MAX 10
+#define EXPP_THEME_FDOT_SIZE_MIN 1
+#define EXPP_THEME_FDOT_SIZE_MAX 10
+#define EXPP_THEME_DRAWTYPE_MIN 1
+#define EXPP_THEME_DRAWTYPE_MAX 4
+
+#define EXPP_THEME_NUMBEROFTHEMES 16
+static const EXPP_map_pair themes_map[] = {
+ {"ui", -1},
+ {"buts", SPACE_BUTS},
+ {"view3d", SPACE_VIEW3D},
+ {"file", SPACE_FILE},
+ {"ipo", SPACE_IPO},
+ {"info", SPACE_INFO},
+ {"sound", SPACE_SOUND},
+ {"action", SPACE_ACTION},
+ {"nla", SPACE_NLA},
+ {"seq", SPACE_SEQ},
+ {"image", SPACE_IMAGE},
+ {"imasel", SPACE_IMASEL},
+ {"text", SPACE_TEXT},
+ {"oops", SPACE_OOPS},
+ {"time", SPACE_TIME},
+ {"node", SPACE_NODE},
+ {NULL, 0}
+};
+
+static PyObject *M_Theme_New( PyObject * self, PyObject * args );
+static PyObject *M_Theme_Get( PyObject * self, PyObject * args );
+
+static char M_Theme_doc[] = "The Blender Theme module\n\n\
+This module provides access to UI Theme data in Blender";
+
+static char M_Theme_New_doc[] = "Theme.New (name = 'New Theme',\
+theme = <default>):\n\
+ Return a new Theme Data object.\n\
+(name) - string: the Theme's name, it defaults to 'New Theme';\n\
+(theme) - bpy Theme: a base Theme to copy all data from, it defaults to the\n\
+current one.";
+
+static char M_Theme_Get_doc[] = "Theme.Get (name = None):\n\
+ Return the theme data with the given 'name', None if not found, or\n\
+ Return a list with all Theme Data objects if no argument was given.";
+
+/*****************************************************************************/
+/* Python method structure definition for Blender.Theme module: */
+/*****************************************************************************/
+struct PyMethodDef M_Theme_methods[] = {
+ {"New", M_Theme_New, METH_VARARGS, M_Theme_New_doc},
+ {"Get", M_Theme_Get, METH_VARARGS, M_Theme_Get_doc},
+ {NULL, NULL, 0, NULL}
+};
+
+static void ThemeSpace_dealloc( BPy_ThemeSpace * self );
+static int ThemeSpace_compare( BPy_ThemeSpace * a, BPy_ThemeSpace * b );
+static PyObject *ThemeSpace_repr( BPy_ThemeSpace * self );
+static PyObject *ThemeSpace_getAttr( BPy_ThemeSpace * self, char *name );
+static int ThemeSpace_setAttr( BPy_ThemeSpace * self, char *name,
+ PyObject * val );
+
+static PyMethodDef BPy_ThemeSpace_methods[] = {
+ {NULL, NULL, 0, NULL}
+};
+
+PyTypeObject ThemeSpace_Type = {
+ PyObject_HEAD_INIT( NULL ) 0, /* ob_size */
+ "Blender Space Theme", /* tp_name */
+ sizeof( BPy_ThemeSpace ), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ /* methods */
+ ( destructor ) ThemeSpace_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ ( getattrfunc ) ThemeSpace_getAttr, /* tp_getattr */
+ ( setattrfunc ) ThemeSpace_setAttr, /* tp_setattr */
+ ( cmpfunc ) ThemeSpace_compare, /* tp_compare */
+ ( reprfunc ) ThemeSpace_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_as_hash */
+ 0, 0, 0, 0, 0, 0,
+ 0, /* tp_doc */
+ 0, 0, 0, 0, 0, 0,
+ 0, //BPy_ThemeSpace_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+};
+
+static void ThemeSpace_dealloc( BPy_ThemeSpace * self )
+{
+ PyObject_DEL( self );
+}
+
+#define ELSEIF_TSP_RGBA(attr)\
+ else if (!strcmp(name, #attr))\
+ attrib = charRGBA_New(&tsp->attr[0]);
+
+/* Example: ELSEIF_TSP_RGBA(back) becomes:
+ * else if (!strcmp(name, "back")
+ * attrib = charRGBA_New(&tsp->back[0])
+ */
+
+static PyObject *ThemeSpace_getAttr( BPy_ThemeSpace * self, char *name )
+{
+ PyObject *attrib = Py_None;
+ ThemeSpace *tsp = self->tsp;
+
+ if( !strcmp( name, "theme" ) )
+ attrib = PyString_FromString( self->theme->name );
+ ELSEIF_TSP_RGBA( back )
+ ELSEIF_TSP_RGBA( text )
+ ELSEIF_TSP_RGBA( text_hi )
+ ELSEIF_TSP_RGBA( header )
+ ELSEIF_TSP_RGBA( panel )
+ ELSEIF_TSP_RGBA( shade1 )
+ ELSEIF_TSP_RGBA( shade2 )
+ ELSEIF_TSP_RGBA( hilite )
+ ELSEIF_TSP_RGBA( grid )
+ ELSEIF_TSP_RGBA( wire )
+ ELSEIF_TSP_RGBA( select )
+ ELSEIF_TSP_RGBA( lamp )
+ ELSEIF_TSP_RGBA( active )
+ ELSEIF_TSP_RGBA( group )
+ ELSEIF_TSP_RGBA( group_active )
+ ELSEIF_TSP_RGBA( transform )
+ ELSEIF_TSP_RGBA( vertex )
+ ELSEIF_TSP_RGBA( vertex_select )
+ ELSEIF_TSP_RGBA( edge )
+ ELSEIF_TSP_RGBA( edge_select )
+ ELSEIF_TSP_RGBA( edge_seam )
+ ELSEIF_TSP_RGBA( edge_sharp )
+ ELSEIF_TSP_RGBA( editmesh_active )
+ ELSEIF_TSP_RGBA( edge_facesel )
+ ELSEIF_TSP_RGBA( face )
+ ELSEIF_TSP_RGBA( face_select )
+ ELSEIF_TSP_RGBA( face_dot )
+ ELSEIF_TSP_RGBA( normal )
+ ELSEIF_TSP_RGBA( bone_solid )
+ ELSEIF_TSP_RGBA( bone_pose )
+ ELSEIF_TSP_RGBA( strip )
+ ELSEIF_TSP_RGBA( strip_select )
+ ELSEIF_TSP_RGBA( syntaxl )
+ ELSEIF_TSP_RGBA( syntaxn )
+ ELSEIF_TSP_RGBA( syntaxb )
+ ELSEIF_TSP_RGBA( syntaxv )
+ ELSEIF_TSP_RGBA( syntaxc )
+ ELSEIF_TSP_RGBA( movie )
+ ELSEIF_TSP_RGBA( image )
+ ELSEIF_TSP_RGBA( scene )
+ ELSEIF_TSP_RGBA( audio )
+ ELSEIF_TSP_RGBA( effect )
+ ELSEIF_TSP_RGBA( plugin )
+ ELSEIF_TSP_RGBA( transition )
+ ELSEIF_TSP_RGBA( meta )
+ else if( !strcmp( name, "vertex_size" ) )
+ attrib = Py_BuildValue( "i", tsp->vertex_size );
+ else if( !strcmp( name, "facedot_size" ) )
+ attrib = Py_BuildValue( "i", tsp->facedot_size );
+ else if( !strcmp( name, "__members__" ) )
+ attrib = Py_BuildValue("[ssssssssssssssssssssssssssssssssssssssssssssssss]", "theme",
+ "back", "text", "text_hi", "header",
+ "panel", "shade1", "shade2", "hilite",
+ "grid", "wire", "select", "lamp", "active",
+ "group", "group_active",
+ "transform", "vertex", "vertex_select",
+ "edge", "edge_select", "edge_seam", "edge_sharp", "editmesh_active",
+ "edge_facesel", "face", "face_select",
+ "face_dot", "normal", "bone_solid", "bone_pose",
+ "strip", "strip_select",
+ "syntaxl", "syntaxn", "syntaxb", "syntaxv", "syntaxc",
+ "movie", "image", "scene", "audio", "effect", "plugin",
+ "transition", "meta",
+ "vertex_size", "facedot_size" );
+
+ if( attrib != Py_None )
+ return attrib;
+
+ return Py_FindMethod( BPy_ThemeSpace_methods, ( PyObject * ) self,
+ name );
+}
+
+static int ThemeSpace_setAttr( BPy_ThemeSpace * self, char *name,
+ PyObject * value )
+{
+ PyObject *attrib = NULL;
+ ThemeSpace *tsp = self->tsp;
+ int ret = -1;
+
+ if( !strcmp( name, "back" ) )
+ attrib = charRGBA_New( &tsp->back[0] );
+ ELSEIF_TSP_RGBA( text )
+ ELSEIF_TSP_RGBA( text_hi )
+ ELSEIF_TSP_RGBA( header )
+ ELSEIF_TSP_RGBA( panel )
+ ELSEIF_TSP_RGBA( shade1 )
+ ELSEIF_TSP_RGBA( shade2 )
+ ELSEIF_TSP_RGBA( hilite )
+ ELSEIF_TSP_RGBA( grid )
+ ELSEIF_TSP_RGBA( wire )
+ ELSEIF_TSP_RGBA( select )
+ ELSEIF_TSP_RGBA( lamp )
+ ELSEIF_TSP_RGBA( active )
+ ELSEIF_TSP_RGBA( group )
+ ELSEIF_TSP_RGBA( group_active )
+ ELSEIF_TSP_RGBA( transform )
+ ELSEIF_TSP_RGBA( vertex )
+ ELSEIF_TSP_RGBA( vertex_select )
+ ELSEIF_TSP_RGBA( edge )
+ ELSEIF_TSP_RGBA( edge_select )
+ ELSEIF_TSP_RGBA( edge_seam )
+ ELSEIF_TSP_RGBA( edge_sharp )
+ ELSEIF_TSP_RGBA( edge_facesel )
+ ELSEIF_TSP_RGBA( face )
+ ELSEIF_TSP_RGBA( face_select )
+ ELSEIF_TSP_RGBA( face_dot )
+ ELSEIF_TSP_RGBA( normal )
+ ELSEIF_TSP_RGBA( bone_solid )
+ ELSEIF_TSP_RGBA( bone_pose )
+ ELSEIF_TSP_RGBA( strip )
+ ELSEIF_TSP_RGBA( strip_select )
+ ELSEIF_TSP_RGBA( syntaxl )
+ ELSEIF_TSP_RGBA( syntaxn )
+ ELSEIF_TSP_RGBA( syntaxb )
+ ELSEIF_TSP_RGBA( syntaxv )
+ ELSEIF_TSP_RGBA( syntaxc )
+ ELSEIF_TSP_RGBA( movie )
+ ELSEIF_TSP_RGBA( image )
+ ELSEIF_TSP_RGBA( scene )
+ ELSEIF_TSP_RGBA( audio )
+ ELSEIF_TSP_RGBA( effect )
+ ELSEIF_TSP_RGBA( plugin )
+ ELSEIF_TSP_RGBA( transition )
+ ELSEIF_TSP_RGBA( meta )
+ else if( !strcmp( name, "vertex_size" ) ) {
+ int val;
+
+ if( !PyInt_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected integer value" );
+
+ val = ( int ) PyInt_AsLong( value );
+ tsp->vertex_size = (char)EXPP_ClampInt( val,
+ EXPP_THEME_VTX_SIZE_MIN,
+ EXPP_THEME_VTX_SIZE_MAX );
+ ret = 0;
+ }
+ else if( !strcmp( name, "facedot_size" ) ) {
+ int val;
+
+ if( !PyInt_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected integer value" );
+
+ val = ( int ) PyInt_AsLong( value );
+ tsp->vertex_size = (char)EXPP_ClampInt( val,
+ EXPP_THEME_FDOT_SIZE_MIN,
+ EXPP_THEME_FDOT_SIZE_MAX );
+ ret = 0;
+ } else
+ return EXPP_ReturnIntError( PyExc_AttributeError,
+ "attribute not found" );
+
+ if( attrib ) {
+ PyObject *pyret = NULL;
+ PyObject *valtuple = Py_BuildValue( "(O)", value );
+
+ if( !valtuple )
+ return EXPP_ReturnIntError( PyExc_MemoryError,
+ "couldn't create tuple!" );
+
+ pyret = charRGBA_setCol( ( BPy_charRGBA * ) attrib, valtuple );
+ Py_DECREF( valtuple );
+
+ if( pyret == Py_None ) {
+ Py_DECREF( Py_None ); /* was increfed by charRGBA_setCol */
+ ret = 0;
+ }
+
+ Py_DECREF( attrib ); /* we're done with it */
+ }
+
+ return ret; /* 0 if all went well */
+}
+
+static int ThemeSpace_compare( BPy_ThemeSpace * a, BPy_ThemeSpace * b )
+{
+ ThemeSpace *pa = a->tsp, *pb = b->tsp;
+ return ( pa == pb ) ? 0 : -1;
+}
+
+static PyObject *ThemeSpace_repr( BPy_ThemeSpace * self )
+{
+ return PyString_FromFormat( "[Space theme from theme \"%s\"]",
+ self->theme->name );
+}
+
+static void ThemeUI_dealloc( BPy_ThemeUI * self );
+static int ThemeUI_compare( BPy_ThemeUI * a, BPy_ThemeUI * b );
+static PyObject *ThemeUI_repr( BPy_ThemeUI * self );
+static PyObject *ThemeUI_getAttr( BPy_ThemeUI * self, char *name );
+static int ThemeUI_setAttr( BPy_ThemeUI * self, char *name, PyObject * val );
+
+static PyMethodDef BPy_ThemeUI_methods[] = {
+ {NULL, NULL, 0, NULL}
+};
+
+PyTypeObject ThemeUI_Type = {
+ PyObject_HEAD_INIT( NULL ) 0, /* ob_size */
+ "Blender UI Theme", /* tp_name */
+ sizeof( BPy_ThemeUI ), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ /* methods */
+ ( destructor ) ThemeUI_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ ( getattrfunc ) ThemeUI_getAttr, /* tp_getattr */
+ ( setattrfunc ) ThemeUI_setAttr, /* tp_setattr */
+ ( cmpfunc ) ThemeUI_compare, /* tp_compare */
+ ( reprfunc ) ThemeUI_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_as_hash */
+ 0, 0, 0, 0, 0, 0,
+ 0, /* tp_doc */
+ 0, 0, 0, 0, 0, 0,
+ 0, //BPy_ThemeUI_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+};
+
+static void ThemeUI_dealloc( BPy_ThemeUI * self )
+{
+ PyObject_DEL( self );
+}
+
+#define ELSEIF_TUI_RGBA(attr)\
+ else if (!strcmp(name, #attr))\
+ attrib = charRGBA_New(&tui->attr[0]);
+
+/* Example: ELSEIF_TUI_RGBA(outline) becomes:
+ * else if (!strcmp(name, "outline")
+ * attr = charRGBA_New(&tui->outline[0])
+ */
+
+static PyObject *ThemeUI_getAttr( BPy_ThemeUI * self, char *name )
+{
+ PyObject *attrib = Py_None;
+ ThemeUI *tui = self->tui;
+
+ if( !strcmp( name, "theme" ) )
+ attrib = PyString_FromString( self->theme->name );
+ ELSEIF_TUI_RGBA( outline )
+ ELSEIF_TUI_RGBA( neutral )
+ ELSEIF_TUI_RGBA( action )
+ ELSEIF_TUI_RGBA( setting )
+ ELSEIF_TUI_RGBA( setting1 )
+ ELSEIF_TUI_RGBA( setting2 )
+ ELSEIF_TUI_RGBA( num )
+ ELSEIF_TUI_RGBA( textfield )
+ ELSEIF_TUI_RGBA( textfield_hi )
+ ELSEIF_TUI_RGBA( popup )
+ ELSEIF_TUI_RGBA( text )
+ ELSEIF_TUI_RGBA( text_hi )
+ ELSEIF_TUI_RGBA( menu_back )
+ ELSEIF_TUI_RGBA( menu_item )
+ ELSEIF_TUI_RGBA( menu_hilite )
+ ELSEIF_TUI_RGBA( menu_text )
+ ELSEIF_TUI_RGBA( menu_text_hi )
+ else if( !strcmp( name, "drawType" ) )
+ attrib = PyInt_FromLong( ( char ) tui->but_drawtype );
+ else if( !strcmp( name, "iconTheme" ) )
+ attrib = PyString_FromString( tui->iconfile );
+ else if( !strcmp( name, "__members__" ) )
+ attrib = Py_BuildValue( "[ssssssssssssssssssss]", "theme",
+ "outline", "neutral", "action",
+ "setting", "setting1", "setting2",
+ "num", "textfield", "textfield_hi", "popup", "text",
+ "text_hi", "menu_back", "menu_item",
+ "menu_hilite", "menu_text",
+ "menu_text_hi", "drawType", "iconTheme" );
+
+ if( attrib != Py_None )
+ return attrib;
+
+ return Py_FindMethod( BPy_ThemeUI_methods, ( PyObject * ) self, name );
+}
+
+static int ThemeUI_setAttr( BPy_ThemeUI * self, char *name, PyObject * value )
+{
+ PyObject *attrib = NULL;
+ ThemeUI *tui = self->tui;
+ int ret = -1;
+
+ if( !strcmp( name, "outline" ) )
+ attrib = charRGBA_New( &tui->outline[0] );
+ ELSEIF_TUI_RGBA( neutral )
+ ELSEIF_TUI_RGBA( action )
+ ELSEIF_TUI_RGBA( setting )
+ ELSEIF_TUI_RGBA( setting1 )
+ ELSEIF_TUI_RGBA( setting2 )
+ ELSEIF_TUI_RGBA( num )
+ ELSEIF_TUI_RGBA( textfield )
+ ELSEIF_TUI_RGBA( textfield_hi )
+ ELSEIF_TUI_RGBA( popup )
+ ELSEIF_TUI_RGBA( text )
+ ELSEIF_TUI_RGBA( text_hi )
+ ELSEIF_TUI_RGBA( menu_back )
+ ELSEIF_TUI_RGBA( menu_item )
+ ELSEIF_TUI_RGBA( menu_hilite )
+ ELSEIF_TUI_RGBA( menu_text )
+ ELSEIF_TUI_RGBA( menu_text_hi )
+ else if( !strcmp( name, "drawType" ) ) {
+ int val;
+
+ if( !PyInt_Check( value ) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected integer value" );
+
+ val = ( int ) PyInt_AsLong( value );
+ tui->but_drawtype = (char)EXPP_ClampInt( val,
+ EXPP_THEME_DRAWTYPE_MIN,
+ EXPP_THEME_DRAWTYPE_MAX );
+ ret = 0;
+ } else if ( !strcmp( name, "iconTheme" ) ) {
+ if ( !PyString_Check(value) )
+ return EXPP_ReturnIntError( PyExc_TypeError,
+ "expected string value" );
+ BLI_strncpy(tui->iconfile, PyString_AsString(value), 80);
+
+ BIF_icons_free();
+ BIF_icons_init(BIFICONID_LAST+1);
+
+ ret = 0;
+ } else
+ return EXPP_ReturnIntError( PyExc_AttributeError,
+ "attribute not found" );
+
+ if( attrib ) {
+ PyObject *pyret = NULL;
+ PyObject *valtuple = Py_BuildValue( "(O)", value );
+
+ if( !valtuple )
+ return EXPP_ReturnIntError( PyExc_MemoryError,
+ "couldn't create tuple!" );
+
+ pyret = charRGBA_setCol( ( BPy_charRGBA * ) attrib, valtuple );
+ Py_DECREF( valtuple );
+
+ if( pyret == Py_None ) {
+ Py_DECREF( Py_None ); /* was increfed by charRGBA_setCol */
+ ret = 0;
+ }
+
+ Py_DECREF( attrib ); /* we're done with it */
+ }
+
+ return ret; /* 0 if all went well */
+}
+
+
+static int ThemeUI_compare( BPy_ThemeUI * a, BPy_ThemeUI * b )
+{
+ ThemeUI *pa = a->tui, *pb = b->tui;
+ return ( pa == pb ) ? 0 : -1;
+}
+
+static PyObject *ThemeUI_repr( BPy_ThemeUI * self )
+{
+ return PyString_FromFormat( "[UI theme from theme \"%s\"]",
+ self->theme->name );
+}
+
+static void Theme_dealloc( BPy_Theme * self );
+static int Theme_compare( BPy_Theme * a, BPy_Theme * b );
+static PyObject *Theme_getAttr( BPy_Theme * self, char *name );
+static PyObject *Theme_repr( BPy_Theme * self );
+
+static PyObject *Theme_get( BPy_Theme * self, PyObject * args );
+static PyObject *Theme_getName( BPy_Theme * self );
+static PyObject *Theme_setName( BPy_Theme * self, PyObject * value );
+
+static PyMethodDef BPy_Theme_methods[] = {
+ {"get", ( PyCFunction ) Theme_get, METH_VARARGS,
+ "(param) - Return UI or Space theme object.\n\
+(param) - the chosen theme object as an int or a string:\n\
+- () - default: UI;\n\
+- (i) - int: an entry from the Blender.Window.Types dictionary;\n\
+- (s) - string: 'UI' or a space name, like 'VIEW3D', etc."},
+ {"getName", ( PyCFunction ) Theme_getName, METH_NOARGS,
+ "() - Return Theme name"},
+ {"setName", ( PyCFunction ) Theme_setName, METH_O,
+ "(s) - Set Theme name"},
+ {NULL, NULL, 0, NULL}
+};
+
+PyTypeObject Theme_Type = {
+ PyObject_HEAD_INIT( NULL )
+ 0, /* ob_size */
+ "Blender Theme", /* tp_name */
+ sizeof( BPy_Theme ), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ /* methods */
+ ( destructor ) Theme_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ ( getattrfunc ) Theme_getAttr, /* tp_getattr */
+ 0, //(setattrfunc) Theme_setAttr, /* tp_setattr */
+ ( cmpfunc ) Theme_compare, /* tp_compare */
+ ( reprfunc ) Theme_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_as_hash */
+ 0, 0, 0, 0, 0, 0,
+ 0, /* tp_doc */
+ 0, 0, 0, 0, 0, 0,
+ 0, /*BPy_Theme_methods,*/ /* tp_methods */
+ 0, /* tp_members */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+};
+
+static PyObject *M_Theme_New( PyObject * self, PyObject * args )
+{
+ char *name = "New Theme";
+ BPy_Theme *pytheme = NULL, *base_pytheme = NULL;
+ bTheme *btheme = NULL, *newtheme = NULL;
+
+ if( !PyArg_ParseTuple
+ ( args, "|sO!", &name, &Theme_Type, &base_pytheme ) )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "expected nothing or a name and optional theme object as arguments" );
+
+ if( base_pytheme )
+ btheme = base_pytheme->theme;
+ if( !btheme )
+ btheme = U.themes.first;
+
+ newtheme = MEM_callocN( sizeof( bTheme ), "theme" );
+
+ if( newtheme )
+ pytheme = PyObject_New( BPy_Theme, &Theme_Type );
+ if( !pytheme )
+ return EXPP_ReturnPyObjError( PyExc_RuntimeError,
+ "couldn't create Theme Data in Blender" );
+
+ memcpy( newtheme, btheme, sizeof( bTheme ) );
+ BLI_addhead( &U.themes, newtheme );
+ BLI_strncpy( newtheme->name, name, 32 );
+
+ pytheme->theme = newtheme;
+
+ return ( PyObject * ) pytheme;
+}
+
+static PyObject *M_Theme_Get( PyObject * self, PyObject * args )
+{
+ char *name = NULL;
+ bTheme *iter;
+ PyObject *ret;
+
+ if( !PyArg_ParseTuple( args, "|s", &name ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument (or nothing)" );
+
+ iter = U.themes.first;
+
+ if( name ) { /* (name) - return requested theme */
+ BPy_Theme *wanted = NULL;
+
+ while( iter ) {
+ if( strcmp( name, iter->name ) == 0 ) {
+ wanted = PyObject_New( BPy_Theme,
+ &Theme_Type );
+ wanted->theme = iter;
+ break;
+ }
+ iter = iter->next;
+ }
+
+ if( !wanted ) {
+ char emsg[64];
+ PyOS_snprintf( emsg, sizeof( emsg ),
+ "Theme \"%s\" not found", name );
+ return EXPP_ReturnPyObjError( PyExc_NameError, emsg );
+ }
+
+ ret = ( PyObject * ) wanted;
+ }
+
+ else { /* () - return list with all themes */
+ int index = 0;
+ PyObject *list = NULL;
+ BPy_Theme *pytheme = NULL;
+
+ list = PyList_New( BLI_countlist( &( U.themes ) ) );
+
+ if( !list )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create PyList" );
+
+ while( iter ) {
+ pytheme = PyObject_New( BPy_Theme, &Theme_Type );
+ pytheme->theme = iter;
+
+ if( !pytheme ) {
+ Py_DECREF(list);
+ return EXPP_ReturnPyObjError
+ ( PyExc_MemoryError,
+ "couldn't create Theme PyObject" );
+ }
+ PyList_SET_ITEM( list, index, ( PyObject * ) pytheme );
+
+ iter = iter->next;
+ index++;
+ }
+
+ ret = list;
+ }
+
+ return ret;
+}
+
+static PyObject *Theme_get( BPy_Theme * self, PyObject * args )
+{
+ bTheme *btheme = self->theme;
+ ThemeUI *tui = NULL;
+ ThemeSpace *tsp = NULL;
+ PyObject *pyob = NULL;
+ BPy_ThemeUI *retUI = NULL;
+ BPy_ThemeSpace *retSpc = NULL;
+ int type;
+
+ if( !PyArg_ParseTuple( args, "|O", &pyob ) )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string or int argument or nothing" );
+
+ if( !pyob ) { /* (): return list with all names */
+ PyObject *ret = PyList_New( EXPP_THEME_NUMBEROFTHEMES );
+
+ if( !ret )
+ return EXPP_ReturnPyObjError( PyExc_MemoryError,
+ "couldn't create pylist!" );
+
+ type = 0; /* using as a counter only */
+
+ while( type < EXPP_THEME_NUMBEROFTHEMES ) {
+ PyList_SET_ITEM( ret, type,
+ PyString_FromString( themes_map[type].sval ) );
+ type++;
+ }
+
+ return ret;
+ }
+
+ else if( PyInt_Check( pyob ) ) /* (int) */
+ type = ( int ) PyInt_AsLong( pyob );
+ else if( PyString_Check( pyob ) ) { /* (str) */
+ char *str = PyString_AsString( pyob );
+ if( !EXPP_map_case_getIntVal( themes_map, str, &type ) )
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "unknown string argument" );
+ } else
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string or int argument or nothing" );
+
+ switch ( type ) {
+ case -1: /* UI */
+ tui = &btheme->tui;
+ break;
+ case SPACE_BUTS:
+ tsp = &btheme->tbuts;
+ break;
+ case SPACE_VIEW3D:
+ tsp = &btheme->tv3d;
+ break;
+ case SPACE_FILE:
+ tsp = &btheme->tfile;
+ break;
+ case SPACE_IPO:
+ tsp = &btheme->tipo;
+ break;
+ case SPACE_INFO:
+ tsp = &btheme->tinfo;
+ break;
+ case SPACE_SOUND:
+ tsp = &btheme->tsnd;
+ break;
+ case SPACE_ACTION:
+ tsp = &btheme->tact;
+ break;
+ case SPACE_NLA:
+ tsp = &btheme->tnla;
+ break;
+ case SPACE_SEQ:
+ tsp = &btheme->tseq;
+ break;
+ case SPACE_IMAGE:
+ tsp = &btheme->tima;
+ break;
+ case SPACE_IMASEL:
+ tsp = &btheme->timasel;
+ break;
+ case SPACE_TEXT:
+ tsp = &btheme->text;
+ break;
+ case SPACE_OOPS:
+ tsp = &btheme->toops;
+ break;
+ case SPACE_TIME:
+ tsp = &btheme->ttime;
+ break;
+ case SPACE_NODE:
+ tsp = &btheme->tnode;
+ break;
+ }
+
+ if( tui ) {
+ retUI = PyObject_New( BPy_ThemeUI, &ThemeUI_Type );
+ retUI->theme = btheme;
+ retUI->tui = tui;
+ return ( PyObject * ) retUI;
+ } else if( tsp ) {
+ retSpc = PyObject_New( BPy_ThemeSpace, &ThemeSpace_Type );
+ retSpc->theme = btheme;
+ retSpc->tsp = tsp;
+ return ( PyObject * ) retSpc;
+ } else
+ return EXPP_ReturnPyObjError( PyExc_AttributeError,
+ "invalid parameter" );
+}
+
+static PyObject *Theme_getName( BPy_Theme * self )
+{
+ return PyString_FromString( self->theme->name );
+}
+
+static PyObject *Theme_setName( BPy_Theme * self, PyObject * value )
+{
+ char *name = PyString_AsString(value);
+
+ if( !name )
+ return EXPP_ReturnPyObjError( PyExc_TypeError,
+ "expected string argument" );
+
+ BLI_strncpy( self->theme->name, name, 32 );
+
+ return EXPP_incr_ret( Py_None );
+}
+
+PyObject *Theme_Init( void )
+{
+ PyObject *submodule;
+
+ Theme_Type.ob_type = &PyType_Type;
+
+ submodule = Py_InitModule3( "Blender.Window.Theme",
+ M_Theme_methods, M_Theme_doc );
+
+ return submodule;
+}
+
+static void Theme_dealloc( BPy_Theme * self )
+{
+ PyObject_DEL( self );
+}
+
+static PyObject *Theme_getAttr( BPy_Theme * self, char *name )
+{
+ if( !strcmp( name, "name" ) )
+ return PyString_FromString( self->theme->name );
+ else if( !strcmp( name, "__members__" ) )
+ return Py_BuildValue( "[s]", "name" );
+
+ return Py_FindMethod( BPy_Theme_methods, ( PyObject * ) self, name );
+}
+
+static int Theme_compare( BPy_Theme * a, BPy_Theme * b )
+{
+ bTheme *pa = a->theme, *pb = b->theme;
+ return ( pa == pb ) ? 0 : -1;
+}
+
+static PyObject *Theme_repr( BPy_Theme * self )
+{
+ return PyString_FromFormat( "[Theme \"%s\"]", self->theme->name );
+}
diff --git a/source/blender/python/api2_2x/windowTheme.h b/source/blender/python/api2_2x/windowTheme.h
new file mode 100644
index 00000000000..761d509724d
--- /dev/null
+++ b/source/blender/python/api2_2x/windowTheme.h
@@ -0,0 +1,60 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * This is a new part of Blender.
+ *
+ * Contributor(s): Willian P. Germano
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#ifndef EXPP_WINDOWTHEME_H
+#define EXPP_WINDOWTHEME_H
+
+#include <Python.h>
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_userdef_types.h"
+
+typedef struct {
+ PyObject_HEAD struct bTheme *theme;
+ struct ThemeUI *tui;
+
+} BPy_ThemeUI;
+
+typedef struct {
+ PyObject_HEAD struct bTheme *theme;
+ struct ThemeSpace *tsp;
+
+} BPy_ThemeSpace;
+
+typedef struct {
+ PyObject_HEAD struct bTheme *theme;
+
+} BPy_Theme;
+
+PyObject *Theme_Init( void );
+
+#endif /* EXPP_WINDOWTHEME_H */
diff --git a/source/blender/quicktime/CMakeLists.txt b/source/blender/quicktime/CMakeLists.txt
new file mode 100644
index 00000000000..afaaa35cac7
--- /dev/null
+++ b/source/blender/quicktime/CMakeLists.txt
@@ -0,0 +1,58 @@
+# $Id$
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2006, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Jacques Beaurain.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+
+SET(SRC apple/quicktime_import.c apple/quicktime_export.c)
+
+SET(INC
+ .
+ ../quicktime
+ ../makesdna
+ ../../../intern/guardedalloc
+ ../blenlib
+ ../blenkernel
+ ../avi
+ ../imbuf
+ ../imbuf/intern
+ ../blenloader
+ ../render/extern/include
+ ../include
+)
+
+SET(INC ${INC} ${QUICKTIME_INC})
+ADD_DEFINITIONS(-DWITH_QUICKTIME)
+
+BLENDERLIB(bf_quicktime "${SRC}" "${INC}")
+#if env['OURPLATFORM'] in ['win32-vc', 'darwin']:
+# types = ['core', 'player']
+# priorities = [95, 200]
+#else:
+# types = ['core']
+# priorities = [95]
+#
+#env.BlenderLib ('bf_quicktime', sources=source_files, includes=incs, defines=['WITH_QUICKTIME'], libtype=types, priority=priorities)
diff --git a/source/blender/quicktime/Makefile b/source/blender/quicktime/Makefile
new file mode 100644
index 00000000000..c71ebc4325d
--- /dev/null
+++ b/source/blender/quicktime/Makefile
@@ -0,0 +1,40 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+# Bounces make to subdirectories.
+
+SOURCEDIR = source/blender/quicktime
+
+ifeq ($(OS), $(findstring $(OS), "windows, darwin"))
+ DIRS = apple
+endif
+
+include nan_subdirs.mk
diff --git a/source/blender/quicktime/SConscript b/source/blender/quicktime/SConscript
new file mode 100644
index 00000000000..7cdeb44c33f
--- /dev/null
+++ b/source/blender/quicktime/SConscript
@@ -0,0 +1,29 @@
+#!/usr/bin/python
+Import ('env')
+
+source_files = ['apple/quicktime_import.c',
+ 'apple/quicktime_export.c']
+
+incs = ['.',
+ '../quicktime',
+ '../makesdna',
+ '#/intern/guardedalloc',
+ '../blenlib',
+ '../blenkernel',
+ '../avi',
+ '../imbuf',
+ '../imbuf/intern',
+ '../blenloader',
+ '../render/extern/include',
+ '../include']
+
+incs.append(env['BF_QUICKTIME_INC'])
+
+if env['OURPLATFORM'] in ['win32-vc', 'darwin']:
+ types = ['core', 'player']
+ priorities = [95, 200]
+else:
+ types = ['core']
+ priorities = [95]
+
+env.BlenderLib ('bf_quicktime', sources=source_files, includes=incs, defines=['WITH_QUICKTIME'], libtype=types, priority=priorities)
diff --git a/source/blender/quicktime/apple/Makefile b/source/blender/quicktime/apple/Makefile
new file mode 100644
index 00000000000..4620714563e
--- /dev/null
+++ b/source/blender/quicktime/apple/Makefile
@@ -0,0 +1,60 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+#
+
+LIBNAME = blenderqt
+DIR = $(OCGDIR)/blender/$(LIBNAME)
+
+include nan_compile.mk
+
+CFLAGS += $(LEVEL1_C_WARNINGS)
+
+CPPFLAGS += -DWITH_QUICKTIME
+
+ifeq ($(CPU),$(findstring $(CPU), "powerpc mips sparc"))
+ CPPFLAGS += -DWORDS_BIGENDIAN
+else
+ # alpha i386
+ CPPFLAGS += -DWORDS_LITTLEENDIAN
+endif
+
+# path to the guarded memory allocator
+CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
+# our own include
+CPPFLAGS += -I..
+
+# stuff needed by quicktime_[import|export].c
+CPPFLAGS += -I../../blenloader -I../../imbuf/intern -I../../imbuf
+CPPFLAGS += -I../../blenlib -I../../makesdna -I../../include -I../../avi
+CPPFLAGS += -I../../blenkernel -I../../render/extern/include
+
+
diff --git a/source/blender/quicktime/apple/quicktime_export.c b/source/blender/quicktime/apple/quicktime_export.c
new file mode 100644
index 00000000000..d6c4d33a82f
--- /dev/null
+++ b/source/blender/quicktime/apple/quicktime_export.c
@@ -0,0 +1,683 @@
+/**
+ * $Id$
+ *
+ * quicktime_export.c
+ *
+ * Code to create QuickTime Movies with Blender
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * The Original Code is written by Rob Haarsma (phase)
+ *
+ * Contributor(s): Stefan Gartner (sgefant)
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifdef WITH_QUICKTIME
+#if defined(_WIN32) || defined(__APPLE__)
+
+#include "DNA_scene_types.h"
+
+#include "BKE_global.h"
+#include "BKE_scene.h"
+
+#include "BLI_blenlib.h"
+#include "BIF_toolbox.h" /* error() */
+
+#include "BLO_sys_types.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "quicktime_import.h"
+#include "quicktime_export.h"
+
+#ifdef _WIN32
+#include <QTML.h>
+#include <Movies.h>
+#include <QuickTimeComponents.h>
+#include <TextUtils.h>
+#endif /* _WIN32 */
+
+#ifdef __APPLE__
+/* evil */
+#ifndef __AIFF__
+#define __AIFF__
+#endif
+#include <QuickTime/Movies.h>
+#include <QuickTime/QuickTimeComponents.h>
+#include <fcntl.h> /* open() */
+#include <unistd.h> /* close() */
+#include <sys/stat.h> /* file permissions */
+#endif /* __APPLE__ */
+
+#define kMyCreatorType FOUR_CHAR_CODE('TVOD')
+#define kTrackStart 0
+#define kMediaStart 0
+
+static void QT_StartAddVideoSamplesToMedia (const Rect *trackFrame, int rectx, int recty);
+static void QT_DoAddVideoSamplesToMedia (int frame, int *pixels, int rectx, int recty);
+static void QT_EndAddVideoSamplesToMedia (void);
+static void QT_CreateMyVideoTrack (int rectx, int recty);
+static void QT_EndCreateMyVideoTrack (void);
+static void check_renderbutton_framerate(void);
+
+typedef struct QuicktimeExport {
+
+ FSSpec theSpec;
+ short resRefNum;
+ Str255 qtfilename;
+
+ Media theMedia;
+ Movie theMovie;
+ Track theTrack;
+
+ GWorldPtr theGWorld;
+ PixMapHandle thePixMap;
+ ImageDescription **anImageDescription;
+
+ ImBuf *ibuf; //imagedata for Quicktime's Gworld
+ ImBuf *ibuf2; //copy of renderdata, to be Y-flipped
+
+} QuicktimeExport;
+
+typedef struct QuicktimeComponentData {
+
+ ComponentInstance theComponent;
+ SCTemporalSettings gTemporalSettings;
+ SCSpatialSettings gSpatialSettings;
+ SCDataRateSettings aDataRateSetting;
+ TimeValue duration;
+ long kVideoTimeScale;
+
+} QuicktimeComponentData;
+
+static struct QuicktimeExport *qtexport;
+static struct QuicktimeComponentData *qtdata;
+
+static int sframe;
+
+
+static void CheckError(OSErr err, char *msg)
+{
+ if(err != noErr) printf("%s: %d\n", msg, err);
+}
+
+
+static OSErr QT_SaveCodecSettingsToScene(void)
+{
+ QTAtomContainer myContainer = NULL;
+ ComponentResult myErr = noErr;
+ Ptr myPtr;
+ long mySize = 0;
+
+ CodecInfo ci;
+ char str[255];
+
+ QuicktimeCodecData *qcd = G.scene->r.qtcodecdata;
+
+ // check if current scene already has qtcodec settings, and clear them
+ if (qcd) {
+ free_qtcodecdata(qcd);
+ } else {
+ qcd = G.scene->r.qtcodecdata = MEM_callocN(sizeof(QuicktimeCodecData), "QuicktimeCodecData");
+ }
+
+ // obtain all current codec settings
+ SCSetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings);
+ SCSetInfo(qtdata->theComponent, scSpatialSettingsType, &qtdata->gSpatialSettings);
+ SCSetInfo(qtdata->theComponent, scDataRateSettingsType, &qtdata->aDataRateSetting);
+
+ // retreive codecdata from quicktime in a atomcontainer
+ myErr = SCGetSettingsAsAtomContainer(qtdata->theComponent, &myContainer);
+ if (myErr != noErr) {
+ printf("Quicktime: SCGetSettingsAsAtomContainer failed\n");
+ goto bail;
+ }
+
+ // get the size of the atomcontainer
+ mySize = GetHandleSize((Handle)myContainer);
+
+ // lock and convert the atomcontainer to a *valid* pointer
+ QTLockContainer(myContainer);
+ myPtr = *(Handle)myContainer;
+
+ // copy the Quicktime data into the blender qtcodecdata struct
+ if (myPtr) {
+ qcd->cdParms = MEM_mallocN(mySize, "qt.cdParms");
+ memcpy(qcd->cdParms, myPtr, mySize);
+ qcd->cdSize = mySize;
+
+ GetCodecInfo (&ci, qtdata->gSpatialSettings.codecType, 0);
+ CopyPascalStringToC(ci.typeName, str);
+ sprintf(qcd->qtcodecname, "Codec: %s", str);
+ } else {
+ printf("Quicktime: QT_SaveCodecSettingsToScene failed\n");
+ }
+
+ QTUnlockContainer(myContainer);
+
+bail:
+ if (myContainer != NULL)
+ QTDisposeAtomContainer(myContainer);
+
+ return((OSErr)myErr);
+}
+
+
+static OSErr QT_GetCodecSettingsFromScene(void)
+{
+ Handle myHandle = NULL;
+ ComponentResult myErr = noErr;
+// CodecInfo ci;
+// char str[255];
+
+ QuicktimeCodecData *qcd = G.scene->r.qtcodecdata;
+
+ // if there is codecdata in the blendfile, convert it to a Quicktime handle
+ if (qcd) {
+ myHandle = NewHandle(qcd->cdSize);
+ PtrToHand( qcd->cdParms, &myHandle, qcd->cdSize);
+ }
+
+ // restore codecsettings to the quicktime component
+ if(qcd->cdParms && qcd->cdSize) {
+ myErr = SCSetSettingsFromAtomContainer((GraphicsExportComponent)qtdata->theComponent, (QTAtomContainer)myHandle);
+ if (myErr != noErr) {
+ printf("Quicktime: SCSetSettingsFromAtomContainer failed\n");
+ goto bail;
+ }
+
+ // update runtime codecsettings for use with the codec dialog
+ SCGetInfo(qtdata->theComponent, scDataRateSettingsType, &qtdata->aDataRateSetting);
+ SCGetInfo(qtdata->theComponent, scSpatialSettingsType, &qtdata->gSpatialSettings);
+ SCGetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings);
+
+// GetCodecInfo (&ci, qtdata->gSpatialSettings.codecType, 0);
+// CopyPascalStringToC(ci.typeName, str);
+// printf("restored Codec: %s\n", str);
+ } else {
+ printf("Quicktime: QT_GetCodecSettingsFromScene failed\n");
+ }
+bail:
+ if (myHandle != NULL)
+ DisposeHandle(myHandle);
+
+ return((OSErr)myErr);
+}
+
+
+static OSErr QT_AddUserDataTextToMovie (Movie theMovie, char *theText, OSType theType)
+{
+ UserData myUserData = NULL;
+ Handle myHandle = NULL;
+ long myLength = strlen(theText);
+ OSErr myErr = noErr;
+
+ // get the movie's user data list
+ myUserData = GetMovieUserData(theMovie);
+ if (myUserData == NULL)
+ return(paramErr);
+
+ // copy the specified text into a new handle
+ myHandle = NewHandleClear(myLength);
+ if (myHandle == NULL)
+ return(MemError());
+
+ BlockMoveData(theText, *myHandle, myLength);
+
+ // add the data to the movie's user data
+ myErr = AddUserDataText(myUserData, myHandle, theType, 1, (short)GetScriptManagerVariable(smRegionCode));
+
+ // clean up
+ DisposeHandle(myHandle);
+ return(myErr);
+}
+
+
+static void QT_CreateMyVideoTrack(int rectx, int recty)
+{
+ OSErr err = noErr;
+ Rect trackFrame;
+// MatrixRecord myMatrix;
+
+ trackFrame.top = 0;
+ trackFrame.left = 0;
+ trackFrame.bottom = recty;
+ trackFrame.right = rectx;
+
+ qtexport->theTrack = NewMovieTrack (qtexport->theMovie,
+ FixRatio(trackFrame.right,1),
+ FixRatio(trackFrame.bottom,1),
+ 0);
+ CheckError( GetMoviesError(), "NewMovieTrack error" );
+
+// SetIdentityMatrix(&myMatrix);
+// ScaleMatrix(&myMatrix, fixed1, Long2Fix(-1), 0, 0);
+// TranslateMatrix(&myMatrix, 0, Long2Fix(trackFrame.bottom));
+// SetMovieMatrix(qtexport->theMovie, &myMatrix);
+
+ qtexport->theMedia = NewTrackMedia (qtexport->theTrack,
+ VideoMediaType,
+ qtdata->kVideoTimeScale,
+ nil,
+ 0);
+ CheckError( GetMoviesError(), "NewTrackMedia error" );
+
+ err = BeginMediaEdits (qtexport->theMedia);
+ CheckError( err, "BeginMediaEdits error" );
+
+ QT_StartAddVideoSamplesToMedia (&trackFrame, rectx, recty);
+}
+
+
+static void QT_EndCreateMyVideoTrack(void)
+{
+ OSErr err = noErr;
+
+ QT_EndAddVideoSamplesToMedia ();
+
+ err = EndMediaEdits (qtexport->theMedia);
+ CheckError( err, "EndMediaEdits error" );
+
+ err = InsertMediaIntoTrack (qtexport->theTrack,
+ kTrackStart,/* track start time */
+ kMediaStart,/* media start time */
+ GetMediaDuration (qtexport->theMedia),
+ fixed1);
+ CheckError( err, "InsertMediaIntoTrack error" );
+}
+
+
+static void QT_StartAddVideoSamplesToMedia (const Rect *trackFrame, int rectx, int recty)
+{
+ OSErr err = noErr;
+
+ qtexport->ibuf = IMB_allocImBuf (rectx, recty, 32, IB_rect, 0);
+ qtexport->ibuf2 = IMB_allocImBuf (rectx, recty, 32, IB_rect, 0);
+
+ err = NewGWorldFromPtr( &qtexport->theGWorld,
+ k32ARGBPixelFormat,
+ trackFrame,
+ NULL, NULL, 0,
+ (unsigned char *)qtexport->ibuf->rect,
+ rectx * 4 );
+ CheckError (err, "NewGWorldFromPtr error");
+
+ qtexport->thePixMap = GetGWorldPixMap(qtexport->theGWorld);
+ LockPixels(qtexport->thePixMap);
+
+ SCDefaultPixMapSettings (qtdata->theComponent, qtexport->thePixMap, true);
+
+ SCSetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings);
+ SCSetInfo(qtdata->theComponent, scSpatialSettingsType, &qtdata->gSpatialSettings);
+ SCSetInfo(qtdata->theComponent, scDataRateSettingsType, &qtdata->aDataRateSetting);
+
+ err = SCCompressSequenceBegin(qtdata->theComponent, qtexport->thePixMap, NULL, &qtexport->anImageDescription);
+ CheckError (err, "SCCompressSequenceBegin error" );
+}
+
+
+static void QT_DoAddVideoSamplesToMedia (int frame, int *pixels, int rectx, int recty)
+{
+ OSErr err = noErr;
+ Rect imageRect;
+
+ int index;
+ int boxsize;
+ unsigned char *from, *to;
+
+ short syncFlag;
+ long dataSize;
+ Handle compressedData;
+ Ptr myPtr;
+
+
+ //copy and flip renderdata
+ memcpy(qtexport->ibuf2->rect, pixels, 4*rectx*recty);
+ IMB_flipy(qtexport->ibuf2);
+
+ //get pointers to parse bitmapdata
+ myPtr = GetPixBaseAddr(qtexport->thePixMap);
+ imageRect = (**qtexport->thePixMap).bounds;
+
+ from = (unsigned char *) qtexport->ibuf2->rect;
+ to = (unsigned char *) myPtr;
+
+ //parse RGBA bitmap into Quicktime's ARGB GWorld
+ boxsize = rectx * recty;
+ for( index = 0; index < boxsize; index++) {
+ to[0] = from[3];
+ to[1] = from[0];
+ to[2] = from[1];
+ to[3] = from[2];
+ to +=4, from += 4;
+ }
+
+ err = SCCompressSequenceFrame(qtdata->theComponent,
+ qtexport->thePixMap,
+ &imageRect,
+ &compressedData,
+ &dataSize,
+ &syncFlag);
+ CheckError(err, "SCCompressSequenceFrame error");
+
+ err = AddMediaSample(qtexport->theMedia,
+ compressedData,
+ 0,
+ dataSize,
+ qtdata->duration,
+ (SampleDescriptionHandle)qtexport->anImageDescription,
+ 1,
+ syncFlag,
+ NULL);
+ CheckError(err, "AddMediaSample error");
+
+ printf ("added frame %3d (frame %3d in movie): ", frame, frame-sframe);
+}
+
+
+static void QT_EndAddVideoSamplesToMedia (void)
+{
+ SCCompressSequenceEnd(qtdata->theComponent);
+
+ UnlockPixels(qtexport->thePixMap);
+ if (qtexport->theGWorld)
+ DisposeGWorld (qtexport->theGWorld);
+
+ if (qtexport->ibuf)
+ IMB_freeImBuf(qtexport->ibuf);
+
+ if (qtexport->ibuf2)
+ IMB_freeImBuf(qtexport->ibuf2);
+}
+
+
+void makeqtstring (char *string) {
+ char txt[64];
+
+ if (string==0) return;
+
+ strcpy(string, G.scene->r.pic);
+ BLI_convertstringcode(string, G.sce, G.scene->r.cfra);
+
+ BLI_make_existing_file(string);
+
+ if (BLI_strcasecmp(string + strlen(string) - 4, ".mov")) {
+ sprintf(txt, "%04d_%04d.mov", (G.scene->r.sfra) , (G.scene->r.efra) );
+ strcat(string, txt);
+ }
+}
+
+
+void start_qt(struct RenderData *rd, int rectx, int recty) {
+ OSErr err = noErr;
+
+ char name[2048];
+ char theFullPath[255];
+
+#ifdef __APPLE__
+ int myFile;
+ FSRef myRef;
+#else
+ char *qtname;
+#endif
+
+ if(qtexport == NULL) qtexport = MEM_callocN(sizeof(QuicktimeExport), "QuicktimeExport");
+
+ if(qtdata) {
+ if(qtdata->theComponent) CloseComponent(qtdata->theComponent);
+ free_qtcomponentdata();
+ }
+
+ qtdata = MEM_callocN(sizeof(QuicktimeComponentData), "QuicktimeCodecDataExt");
+
+ if(rd->qtcodecdata == NULL && rd->qtcodecdata->cdParms == NULL) {
+ get_qtcodec_settings();
+ } else {
+ qtdata->theComponent = OpenDefaultComponent(StandardCompressionType, StandardCompressionSubType);
+
+ QT_GetCodecSettingsFromScene();
+ check_renderbutton_framerate();
+ }
+
+ if (G.afbreek != 1) {
+ sframe = (rd->sfra);
+
+ makeqtstring(name);
+
+#ifdef __APPLE__
+ sprintf(theFullPath, "%s", name);
+
+ /* hack: create an empty file to make FSPathMakeRef() happy */
+ myFile = open(theFullPath, O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRUSR|S_IWUSR);
+ if (myFile < 0) {
+ printf("error while creating file!\n");
+ /* do something? */
+ }
+ close(myFile);
+ err = FSPathMakeRef(theFullPath, &myRef, 0);
+ CheckError(err, "FsPathMakeRef error");
+ err = FSGetCatalogInfo(&myRef, kFSCatInfoNone, NULL, NULL, &qtexport->theSpec, NULL);
+ CheckError(err, "FsGetCatalogInfoRef error");
+#endif
+#ifdef _WIN32
+ qtname = get_valid_qtname(name);
+ sprintf(theFullPath, "%s", qtname);
+ strcpy(name, qtname);
+ MEM_freeN(qtname);
+
+ CopyCStringToPascal(theFullPath, qtexport->qtfilename);
+ err = FSMakeFSSpec(0, 0L, qtexport->qtfilename, &qtexport->theSpec);
+#endif
+
+ err = CreateMovieFile (&qtexport->theSpec,
+ kMyCreatorType,
+ smCurrentScript,
+ createMovieFileDeleteCurFile | createMovieFileDontCreateResFile,
+ &qtexport->resRefNum,
+ &qtexport->theMovie );
+ CheckError(err, "CreateMovieFile error");
+
+ if(err != noErr) {
+ G.afbreek = 1;
+ error("Unable to create Quicktime movie: %s", name);
+ } else {
+ printf("Created QuickTime movie: %s\n", name);
+
+ QT_CreateMyVideoTrack(rectx, recty);
+ }
+ }
+}
+
+
+void append_qt(int frame, int *pixels, int rectx, int recty) {
+ QT_DoAddVideoSamplesToMedia(frame, pixels, rectx, recty);
+}
+
+
+void end_qt(void) {
+ OSErr err = noErr;
+ short resId = movieInDataForkResID;
+
+ if(qtexport->theMovie) {
+ QT_EndCreateMyVideoTrack();
+
+ err = AddMovieResource (qtexport->theMovie, qtexport->resRefNum, &resId, qtexport->qtfilename);
+ CheckError(err, "AddMovieResource error");
+
+ err = QT_AddUserDataTextToMovie(qtexport->theMovie, "Made with Blender", kUserDataTextInformation);
+ CheckError(err, "AddUserDataTextToMovie error");
+
+ err = UpdateMovieResource(qtexport->theMovie, qtexport->resRefNum, resId, qtexport->qtfilename);
+ CheckError(err, "UpdateMovieResource error");
+
+ if(qtexport->resRefNum) CloseMovieFile(qtexport->resRefNum);
+
+ DisposeMovie(qtexport->theMovie);
+
+ printf("Finished QuickTime movie.\n");
+ }
+
+ if(qtexport) {
+ MEM_freeN(qtexport);
+ qtexport = NULL;
+ }
+}
+
+
+void free_qtcomponentdata(void) {
+ if(qtdata) {
+ if(qtdata->theComponent) CloseComponent(qtdata->theComponent);
+ MEM_freeN(qtdata);
+ qtdata = NULL;
+ }
+}
+
+
+static void check_renderbutton_framerate(void) {
+ // to keep float framerates consistent between the codec dialog and frs/sec button.
+ OSErr err;
+
+ err = SCGetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings);
+ CheckError(err, "SCGetInfo fr error");
+
+ if( (G.scene->r.frs_sec == 24 || G.scene->r.frs_sec == 30 || G.scene->r.frs_sec == 60) &&
+ (qtdata->gTemporalSettings.frameRate == 1571553 ||
+ qtdata->gTemporalSettings.frameRate == 1964113 ||
+ qtdata->gTemporalSettings.frameRate == 3928227)) {;} else
+ qtdata->gTemporalSettings.frameRate =
+ (G.scene->r.frs_sec << 16) / G.scene->r.frs_sec_base ;
+
+ err = SCSetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings);
+ CheckError( err, "SCSetInfo error" );
+
+ if(qtdata->gTemporalSettings.frameRate == 1571553) { // 23.98 fps
+ qtdata->kVideoTimeScale = 2400;
+ qtdata->duration = 1001;
+ } else if (qtdata->gTemporalSettings.frameRate == 1964113) { // 29.97 fps
+ qtdata->kVideoTimeScale = 3000;
+ qtdata->duration = 1001;
+ } else if (qtdata->gTemporalSettings.frameRate == 3928227) { // 59.94 fps
+ qtdata->kVideoTimeScale = 6000;
+ qtdata->duration = 1001;
+ } else {
+ qtdata->kVideoTimeScale = (qtdata->gTemporalSettings.frameRate >> 16) * 100;
+ qtdata->duration = 100;
+ }
+}
+
+
+int get_qtcodec_settings(void)
+{
+ OSErr err = noErr;
+
+ // erase any existing codecsetting
+ if(qtdata) {
+ if(qtdata->theComponent) CloseComponent(qtdata->theComponent);
+ free_qtcomponentdata();
+ }
+
+ // allocate new
+ qtdata = MEM_callocN(sizeof(QuicktimeComponentData), "QuicktimeComponentData");
+ qtdata->theComponent = OpenDefaultComponent(StandardCompressionType, StandardCompressionSubType);
+
+ // get previous selected codecsetting, if any
+ if(G.scene->r.qtcodecdata && G.scene->r.qtcodecdata->cdParms) {
+ QT_GetCodecSettingsFromScene();
+ check_renderbutton_framerate();
+ } else {
+ // configure the standard image compression dialog box
+ // set some default settings
+ qtdata->gSpatialSettings.codec = anyCodec;
+ qtdata->gSpatialSettings.spatialQuality = codecMaxQuality;
+ qtdata->gTemporalSettings.temporalQuality = codecMaxQuality;
+ qtdata->gTemporalSettings.keyFrameRate = 25;
+ qtdata->aDataRateSetting.dataRate = 90 * 1024;
+
+ err = SCSetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings);
+ CheckError(err, "SCSetInfo1 error");
+ err = SCSetInfo(qtdata->theComponent, scSpatialSettingsType, &qtdata->gSpatialSettings);
+ CheckError(err, "SCSetInfo2 error");
+ err = SCSetInfo(qtdata->theComponent, scDataRateSettingsType, &qtdata->aDataRateSetting);
+ CheckError(err, "SCSetInfo3 error");
+ }
+
+ check_renderbutton_framerate();
+
+ // put up the dialog box
+ err = SCRequestSequenceSettings(qtdata->theComponent);
+
+ if (err == scUserCancelled) {
+ G.afbreek = 1;
+ return 0;
+ }
+
+ // get user selected data
+ SCGetInfo(qtdata->theComponent, scTemporalSettingsType, &qtdata->gTemporalSettings);
+ SCGetInfo(qtdata->theComponent, scSpatialSettingsType, &qtdata->gSpatialSettings);
+ SCGetInfo(qtdata->theComponent, scDataRateSettingsType, &qtdata->aDataRateSetting);
+
+ QT_SaveCodecSettingsToScene();
+
+ // framerate jugglin'
+ if(qtdata->gTemporalSettings.frameRate == 1571553) { // 23.98 fps
+ qtdata->kVideoTimeScale = 24000;
+ qtdata->duration = 1001;
+
+ G.scene->r.frs_sec = 24;
+ G.scene->r.frs_sec_base = 1.001;
+ } else if (qtdata->gTemporalSettings.frameRate == 1964113) { // 29.97 fps
+ qtdata->kVideoTimeScale = 3000;
+ qtdata->duration = 1001;
+
+ G.scene->r.frs_sec = 30;
+ G.scene->r.frs_sec_base = 1.001;
+ } else if (qtdata->gTemporalSettings.frameRate == 3928227) { // 59.94 fps
+ qtdata->kVideoTimeScale = 6000;
+ qtdata->duration = 1001;
+
+ G.scene->r.frs_sec = 60;
+ G.scene->r.frs_sec_base = 1.001;
+ } else {
+ double fps = qtdata->gTemporalSettings.frameRate;
+
+ qtdata->kVideoTimeScale = 600;
+ qtdata->duration = qtdata->kVideoTimeScale / (qtdata->gTemporalSettings.frameRate / 65536);
+
+ if ((qtdata->gTemporalSettings.frameRate & 0xffff) == 0) {
+ G.scene->r.frs_sec = fps / 65536;
+ G.scene->r.frs_sec_base = 1;
+ } else {
+ /* we do our very best... */
+ G.scene->r.frs_sec = (fps * 10000 / 65536);
+ G.scene->r.frs_sec_base = 10000;
+ }
+ }
+
+ return 1;
+}
+
+#endif /* _WIN32 || __APPLE__ */
+#endif /* WITH_QUICKTIME */
+
diff --git a/source/blender/quicktime/apple/quicktime_import.c b/source/blender/quicktime/apple/quicktime_import.c
new file mode 100644
index 00000000000..862b20b5260
--- /dev/null
+++ b/source/blender/quicktime/apple/quicktime_import.c
@@ -0,0 +1,779 @@
+/**
+ * $Id$
+ *
+ * quicktime_import.c
+ *
+ * Code to use Quicktime to load images/movies as texture.
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *
+ * The Original Code is written by Rob Haarsma (phase)
+ *
+ * Contributor(s): Stefan Gartner (sgefant)
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#ifdef WITH_QUICKTIME
+
+#if defined(_WIN32) || defined(__APPLE__)
+
+#include "IMB_anim.h"
+#include "BLO_sys_types.h"
+#include "BKE_global.h"
+#include "BLI_dynstr.h"
+
+#ifdef __APPLE__
+#include <QuickTime/Movies.h>
+#include <QuickTime/QuickTimeComponents.h>
+#endif
+
+#ifdef _WIN32
+#include <Movies.h>
+#include <QTML.h>
+#include <TextUtils.h>
+#include <QuickTimeComponents.h>
+#endif /* _WIN32 */
+
+
+#include "quicktime_import.h"
+#include "quicktime_export.h"
+
+
+#define RECT_WIDTH(r) (r.right-r.left)
+#define RECT_HEIGHT(r) (r.bottom-r.top)
+
+#define QTIME_DEBUG 0
+
+
+void quicktime_init(void)
+{
+#ifdef _WIN32
+ if (InitializeQTML(0) != noErr)
+ G.have_quicktime = FALSE;
+ else
+ G.have_quicktime = TRUE;
+#endif /* _WIN32 */
+
+ /* Initialize QuickTime */
+#if defined(_WIN32) || defined (__APPLE__)
+ if (EnterMovies() != noErr)
+ G.have_quicktime = FALSE;
+ else
+#endif /* _WIN32 || __APPLE__ */
+#ifdef __linux__
+ /* inititalize quicktime codec registry */
+ lqt_registry_init();
+#endif
+ G.have_quicktime = TRUE;
+}
+
+
+void quicktime_exit(void)
+{
+#if defined(_WIN32) || defined(__APPLE__)
+#ifdef WITH_QUICKTIME
+ if(G.have_quicktime) {
+ free_qtcomponentdata();
+ ExitMovies();
+#ifdef _WIN32
+ TerminateQTML();
+#endif /* _WIN32 */
+ }
+#endif /* WITH_QUICKTIME */
+#endif /* _WIN32 || __APPLE__ */
+}
+
+
+#ifdef _WIN32
+char *get_valid_qtname(char *name)
+{
+ TCHAR Buffer[MAX_PATH];
+ DWORD dwRet;
+ char *qtname;
+ DynStr *ds= BLI_dynstr_new();
+
+ dwRet = GetCurrentDirectory(MAX_PATH, Buffer);
+
+ if(name[1] != ':') {
+ char drive[2];
+
+ if(name[0] == '/' || name[0] == '\\') {
+ drive[0] = Buffer[0];
+ drive[1] = '\0';
+
+ BLI_dynstr_append(ds, drive);
+ BLI_dynstr_append(ds, ":");
+ BLI_dynstr_append(ds, name);
+ } else {
+ BLI_dynstr_append(ds, Buffer);
+ BLI_dynstr_append(ds, "/");
+ BLI_dynstr_append(ds, name);
+ }
+ } else {
+ BLI_dynstr_append(ds, name);
+ }
+
+ qtname= BLI_dynstr_get_cstring(ds);
+ BLI_dynstr_free(ds);
+
+ return qtname;
+}
+#endif /* _WIN32 */
+
+
+int anim_is_quicktime (char *name)
+{
+ FSSpec theFSSpec;
+ char theFullPath[255];
+
+ Boolean isMovieFile = false;
+ AliasHandle myAlias = NULL;
+ Component myImporter = NULL;
+#ifdef __APPLE__
+ FInfo myFinderInfo;
+ FSRef myRef;
+#else
+ char *qtname;
+ Str255 dst;
+#endif
+ OSErr err = noErr;
+
+ // dont let quicktime movie import handle these
+ if( BLI_testextensie(name, ".swf") ||
+ BLI_testextensie(name, ".txt") ||
+ BLI_testextensie(name, ".mpg") ||
+ BLI_testextensie(name, ".avi") || // wouldnt be appropriate ;)
+ BLI_testextensie(name, ".tga") ||
+ BLI_testextensie(name, ".png") ||
+ BLI_testextensie(name, ".jpg") ||
+ BLI_testextensie(name, ".wav") ||
+ BLI_testextensie(name, ".zip") ||
+ BLI_testextensie(name, ".mp3")) return 0;
+
+ if(QTIME_DEBUG) printf("qt: checking as movie: %s\n", name);
+
+#ifdef __APPLE__
+ sprintf(theFullPath, "%s", name);
+
+ err = FSPathMakeRef(theFullPath, &myRef, 0);
+ err = FSGetCatalogInfo(&myRef, kFSCatInfoNone, NULL, NULL, &theFSSpec, NULL);
+#else
+ qtname = get_valid_qtname(name);
+ sprintf(theFullPath, "%s", qtname);
+ MEM_freeN(qtname);
+
+ CopyCStringToPascal(theFullPath, dst);
+ err = FSMakeFSSpec(0, 0L, dst, &theFSSpec);
+#endif
+
+#ifdef __APPLE__
+ // see whether the file type is MovieFileType; to do this, get the Finder information
+ err = FSpGetFInfo(&theFSSpec, &myFinderInfo);
+ if (err == noErr) {
+ if (myFinderInfo.fdType == kQTFileTypeMovie) {
+ return(true);
+ }
+ }
+#endif
+
+/* on mac os x this results in using quicktime for other formats as well
+ * not sure whether this is intended
+ */
+ // if it isn't a movie file, see whether the file can be imported as a movie
+ err = QTNewAlias(&theFSSpec, &myAlias, true);
+ if (err == noErr) {
+ if (myAlias != NULL) {
+ err = GetMovieImporterForDataRef(rAliasType, (Handle)myAlias, kGetMovieImporterDontConsiderGraphicsImporters, &myImporter);
+ DisposeHandle((Handle)myAlias);
+ }
+ }
+
+ if ((err == noErr) && (myImporter != NULL)) { // this file is a movie file
+ isMovieFile = true;
+ }
+
+ return(isMovieFile);
+}
+
+
+void free_anim_quicktime (struct anim *anim) {
+ if (anim == NULL) return;
+ if (anim->qtime == NULL) return;
+
+ UnlockPixels(anim->qtime->offscreenPixMap);
+
+ if(anim->qtime->have_gw)
+ DisposeGWorld( anim->qtime->offscreenGWorld );
+ if(anim->qtime->ibuf)
+ IMB_freeImBuf(anim->qtime->ibuf);
+
+ DisposeMovie( anim->qtime->movie );
+ CloseMovieFile( anim->qtime->movieRefNum );
+
+ if(anim->qtime->frameIndex) MEM_freeN (anim->qtime->frameIndex);
+ if(anim->qtime) MEM_freeN (anim->qtime);
+
+ anim->qtime = NULL;
+
+ anim->duration = 0;
+}
+
+
+static OSErr QT_get_frameIndexes(struct anim *anim)
+{
+ int i;
+ OSErr anErr = noErr;
+ OSType media = VideoMediaType;
+ TimeValue nextTime = 0;
+ TimeValue startPoint;
+ TimeValue tmpstartPoint;
+ long sampleCount = 0;
+
+ startPoint = -1;
+
+ GetMovieNextInterestingTime(anim->qtime->movie, nextTimeMediaSample+nextTimeEdgeOK, (TimeValue)1, &media, 0,
+ 1, &startPoint, NULL);
+
+ tmpstartPoint = startPoint;
+
+ anim->qtime->framecount = 0;
+
+ sampleCount = GetMediaSampleCount(anim->qtime->theMedia);
+ anErr = GetMoviesError();
+ if (anErr != noErr) return anErr;
+
+ anim->qtime->framecount = sampleCount;
+
+ anim->qtime->frameIndex = (TimeValue *) MEM_callocN(sizeof(TimeValue) * anim->qtime->framecount, "qtframeindex");
+
+ //rewind
+ GetMovieNextInterestingTime(anim->qtime->movie, nextTimeMediaSample, 1, &media, (TimeValue)1, 0, &tmpstartPoint, NULL);
+
+ anim->qtime->frameIndex[0] = startPoint;
+ for(i = 1; i < anim->qtime->framecount; i++) {
+ nextTime = 0;
+ GetMovieNextInterestingTime(anim->qtime->movie, nextTimeMediaSample, 1, &media, startPoint, 0, &nextTime, NULL);
+ startPoint = nextTime;
+ anim->qtime->frameIndex[i] = nextTime;
+ }
+
+ anErr = GetMoviesError();
+ return anErr;
+}
+
+
+ImBuf * qtime_fetchibuf (struct anim *anim, int position)
+{
+ PixMapHandle myPixMap = NULL;
+ Ptr myPtr;
+
+ register int index;
+ register int boxsize;
+
+ register uint32_t *readPos;
+ register uint32_t *changePos;
+
+ ImBuf *ibuf = NULL;
+ unsigned int *rect;
+ unsigned char *from, *to;
+#ifdef _WIN32
+ unsigned char *crect;
+#endif
+
+ if (anim == NULL) {
+ return (NULL);
+ }
+
+ ibuf = IMB_allocImBuf (anim->x, anim->y, 32, IB_rect, 0);
+ rect = ibuf->rect;
+
+ SetMovieTimeValue(anim->qtime->movie, anim->qtime->frameIndex[position]);
+ UpdateMovie(anim->qtime->movie);
+ MoviesTask(anim->qtime->movie, 0);
+
+
+ myPixMap = GetGWorldPixMap(anim->qtime->offscreenGWorld);
+ myPtr = GetPixBaseAddr(myPixMap);
+
+ if (myPtr == NULL) {
+ printf ("Error reading frame from Quicktime");
+ IMB_freeImBuf (ibuf);
+ return NULL;
+ }
+
+ boxsize = anim->x * anim->y;
+ readPos = (uint32_t *) myPtr;
+ changePos = (uint32_t *) rect; //textureIMBuf *THE* data pointerrr
+
+#ifdef __APPLE__
+ // Swap alpha byte to the end, so ARGB become RGBA;
+ from= (unsigned char *)readPos;
+ to= (unsigned char *)changePos;
+
+ for( index = 0; index < boxsize; index++, from+=4, to+=4 ) {
+ to[3] = from[0];
+ to[0] = from[1];
+ to[1] = from[2];
+ to[2] = from[3];
+ }
+#endif
+
+#ifdef _WIN32
+ for( index = 0; index < boxsize; index++, changePos++, readPos++ )
+ *( changePos ) = *(readPos );
+
+ if(anim->qtime->depth < 32) {
+ //add alpha to ibuf
+ boxsize = anim->x * anim->y * 4;
+ crect = (unsigned char *) rect;
+ for( index = 0; index < boxsize; index+=4, crect+=4 )
+ crect[3] = 0xFF;
+ }
+#endif
+
+ IMB_flipy(ibuf);
+ return ibuf;
+}
+
+
+// following two functions only here to get movie pixeldepth
+
+static int GetFirstVideoMedia(struct anim *anim)
+{
+ long numTracks;
+ OSType mediaType;
+
+ numTracks = GetMovieTrackCount(anim->qtime->movie);
+
+ for (anim->qtime->trackIndex=1; anim->qtime->trackIndex<=numTracks; (anim->qtime->trackIndex)++) {
+ anim->qtime->theTrack = GetMovieIndTrack(anim->qtime->movie, anim->qtime->trackIndex);
+
+ if (anim->qtime->theTrack)
+ anim->qtime->theMedia = GetTrackMedia(anim->qtime->theTrack);
+
+ if (anim->qtime->theMedia)
+ GetMediaHandlerDescription(anim->qtime->theMedia,&mediaType, nil, nil);
+ if (mediaType == VideoMediaType) return 1;
+ }
+
+ anim->qtime->trackIndex = 0; // trackIndex can't be 0
+ return 0; // went through all tracks and no video
+}
+
+static short GetFirstVideoTrackPixelDepth(struct anim *anim)
+{
+ SampleDescriptionHandle imageDescH = (SampleDescriptionHandle)NewHandle(sizeof(Handle));
+// long trackIndex = 0; /*unused*/
+
+ if(!GetFirstVideoMedia(anim))
+ return -1;
+
+ if (!anim->qtime->trackIndex || !anim->qtime->theMedia) return -1; // we need both
+ GetMediaSampleDescription(anim->qtime->theMedia, anim->qtime->trackIndex, imageDescH);
+
+ return (*(ImageDescriptionHandle)imageDescH)->depth;
+}
+
+
+int startquicktime (struct anim *anim)
+{
+ FSSpec theFSSpec;
+
+ OSErr err = noErr;
+ char theFullPath[255];
+#ifdef __APPLE__
+ FSRef myRef;
+#else
+ char *qtname;
+ Str255 dst;
+#endif
+ short depth = 0;
+
+ anim->qtime = MEM_callocN (sizeof(QuicktimeMovie),"animqt");
+ anim->qtime->have_gw = FALSE;
+
+ if (anim->qtime == NULL) {
+ if(QTIME_DEBUG) printf("Can't alloc qtime: %s\n", anim->name);
+ return -1;
+ }
+
+ if(QTIME_DEBUG) printf("qt: attempting to load as movie %s\n", anim->name);
+
+#ifdef __APPLE__
+ sprintf(theFullPath, "%s", anim->name);
+
+ err = FSPathMakeRef(theFullPath, &myRef, 0);
+ err = FSGetCatalogInfo(&myRef, kFSCatInfoNone, NULL, NULL, &theFSSpec, NULL);
+#else
+ qtname = get_valid_qtname(anim->name);
+ sprintf(theFullPath, "%s", qtname);
+ MEM_freeN(qtname);
+
+ CopyCStringToPascal(theFullPath, dst);
+ FSMakeFSSpec(0, 0L, dst, &theFSSpec);
+#endif
+
+ err = OpenMovieFile(&theFSSpec, &anim->qtime->movieRefNum, fsRdPerm);
+
+ if (err == noErr) {
+ if(QTIME_DEBUG) printf("qt: movie opened\n");
+ err = NewMovieFromFile(&anim->qtime->movie,
+ anim->qtime->movieRefNum,
+ &anim->qtime->movieResId, NULL, newMovieActive, NULL);
+ }
+
+ if (err) {
+ if(QTIME_DEBUG) printf("qt: bad movie %s\n", anim->name);
+ if (anim->qtime->movie) {
+ DisposeMovie(anim->qtime->movie);
+ MEM_freeN(anim->qtime);
+ if(QTIME_DEBUG) printf("qt: can't load %s\n", anim->name);
+ return -1;
+ }
+ }
+
+ GetMovieBox(anim->qtime->movie, &anim->qtime->movieBounds);
+ anim->x = anim->qtime->movWidth = RECT_WIDTH(anim->qtime->movieBounds);
+ anim->y = anim->qtime->movHeight = RECT_HEIGHT(anim->qtime->movieBounds);
+ if(QTIME_DEBUG) printf("qt: got bounds %s\n", anim->name);
+
+ if(anim->x == 0 && anim->y == 0) {
+ if(QTIME_DEBUG) printf("qt: error, no dimensions\n");
+ free_anim_quicktime(anim);
+ return -1;
+ }
+
+ anim->qtime->ibuf = IMB_allocImBuf (anim->x, anim->y, 32, IB_rect, 0);
+
+#ifdef _WIN32
+ err = NewGWorldFromPtr(&anim->qtime->offscreenGWorld,
+ k32RGBAPixelFormat,
+ &anim->qtime->movieBounds,
+ NULL, NULL, 0,
+ (unsigned char *)anim->qtime->ibuf->rect,
+ anim->x * 4);
+#else
+ err = NewGWorldFromPtr(&anim->qtime->offscreenGWorld,
+ k32ARGBPixelFormat,
+ &anim->qtime->movieBounds,
+ NULL, NULL, 0,
+ (unsigned char *)anim->qtime->ibuf->rect,
+ anim->x * 4);
+#endif /* _WIN32 */
+
+ if(err == noErr) {
+ anim->qtime->have_gw = TRUE;
+
+ SetMovieGWorld(anim->qtime->movie,
+ anim->qtime->offscreenGWorld,
+ GetGWorldDevice(anim->qtime->offscreenGWorld));
+ SetMoviePlayHints(anim->qtime->movie, hintsHighQuality, hintsHighQuality);
+
+ // sets Media and Track!
+ depth = GetFirstVideoTrackPixelDepth(anim);
+
+ QT_get_frameIndexes(anim);
+ }
+
+ anim->qtime->offscreenPixMap = GetGWorldPixMap(anim->qtime->offscreenGWorld);
+ LockPixels(anim->qtime->offscreenPixMap);
+
+ //fill blender's anim struct
+ anim->qtime->depth = depth;
+
+ anim->duration = anim->qtime->framecount;
+ anim->params = 0;
+
+ anim->interlacing = 0;
+ anim->orientation = 0;
+ anim->framesize = anim->x * anim->y * 4;
+
+ anim->curposition = 0;
+
+ if(QTIME_DEBUG) printf("qt: load %s %dx%dx%d frames %d\n", anim->name, anim->qtime->movWidth,
+ anim->qtime->movHeight, anim->qtime->depth, anim->qtime->framecount);
+
+ return 0;
+}
+
+int imb_is_a_quicktime (char *name)
+{
+ GraphicsImportComponent theImporter = NULL;
+
+ FSSpec theFSSpec;
+#ifdef _WIN32
+ Str255 dst; /*unused*/
+#endif
+ char theFullPath[255];
+
+// Boolean isMovieFile = false; /*unused*/
+// AliasHandle myAlias = NULL; /*unused*/
+// Component myImporter = NULL; /*unused*/
+#ifdef __APPLE__
+// FInfo myFinderInfo; /*unused*/
+ FSRef myRef;
+#endif
+ OSErr err = noErr;
+
+ if(QTIME_DEBUG) printf("qt: checking as image %s\n", name);
+
+ // dont let quicktime image import handle these
+ if( BLI_testextensie(name, ".swf") ||
+ BLI_testextensie(name, ".txt") ||
+ BLI_testextensie(name, ".mpg") ||
+ BLI_testextensie(name, ".wav") ||
+ BLI_testextensie(name, ".mov") || // not as image, doesn't work
+ BLI_testextensie(name, ".avi") ||
+ BLI_testextensie(name, ".mp3")) return 0;
+
+ sprintf(theFullPath, "%s", name);
+#ifdef __APPLE__
+ err = FSPathMakeRef(theFullPath, &myRef, 0);
+ err = FSGetCatalogInfo(&myRef, kFSCatInfoNone, NULL, NULL, &theFSSpec, NULL);
+#else
+ CopyCStringToPascal(theFullPath, dst);
+ err = FSMakeFSSpec(0, 0L, dst, &theFSSpec);
+#endif
+
+ GetGraphicsImporterForFile(&theFSSpec, &theImporter);
+
+ if (theImporter != NULL) {
+ if(QTIME_DEBUG) printf("qt: %s valid\n", name);
+ CloseComponent(theImporter);
+ return 1;
+ }
+
+ return 0;
+}
+
+ImBuf *imb_quicktime_decode(unsigned char *mem, int size, int flags)
+{
+ Rect myRect;
+ OSErr err = noErr;
+ GraphicsImportComponent gImporter = NULL;
+
+ ImageDescriptionHandle desc;
+
+ ComponentInstance dataHandler;
+ PointerDataRef dataref = (PointerDataRef)NewHandle(sizeof(PointerDataRefRecord));
+
+ int x, y, depth;
+ int have_gw = FALSE;
+ ImBuf *ibuf = NULL;
+// ImBuf *imbuf = NULL; /*unused*/
+ GWorldPtr offGWorld;
+ PixMapHandle myPixMap = NULL;
+
+#ifdef __APPLE__
+ Ptr myPtr;
+
+ register int index;
+ register int boxsize;
+
+ register uint32_t *readPos;
+ register uint32_t *changePos;
+
+ ImBuf *wbuf = NULL;
+ unsigned int *rect;
+ unsigned char *from, *to;
+#endif
+
+ if (mem == NULL)
+ goto bail;
+
+ if(QTIME_DEBUG) printf("qt: attempt to load mem as image\n");
+
+ (**dataref).data = mem;
+ (**dataref).dataLength = size;
+
+ err = OpenADataHandler((Handle)dataref,
+ PointerDataHandlerSubType,
+ nil,
+ (OSType)0,
+ nil,
+ kDataHCanRead,
+ &dataHandler);
+ if (err != noErr) {
+ if(QTIME_DEBUG) printf("no datahandler\n");
+ goto bail;
+ }
+
+ err = GetGraphicsImporterForDataRef((Handle)dataref, PointerDataHandlerSubType, &gImporter);
+ if (err != noErr) {
+ if(QTIME_DEBUG) printf("no graphimport\n");
+ goto bail;
+ }
+
+ err = GraphicsImportGetNaturalBounds(gImporter, &myRect);
+ if (err != noErr) {
+ if(QTIME_DEBUG) printf("no bounds\n");
+ goto bail;
+ }
+
+ err = GraphicsImportGetImageDescription (gImporter, &desc );
+ if (err != noErr) {
+ if(QTIME_DEBUG) printf("no imagedescription\n");
+ goto bail;
+ }
+
+ x = RECT_WIDTH(myRect);
+ y = RECT_HEIGHT(myRect);
+ depth = (**desc).depth;
+
+ if (flags & IB_test) {
+ ibuf = IMB_allocImBuf(x, y, depth, 0, 0);
+ ibuf->ftype = QUICKTIME;
+ DisposeHandle((Handle)dataref);
+ if (gImporter != NULL) CloseComponent(gImporter);
+ return ibuf;
+ }
+
+#ifdef __APPLE__
+ ibuf = IMB_allocImBuf (x, y, 32, IB_rect, 0);
+ wbuf = IMB_allocImBuf (x, y, 32, IB_rect, 0);
+
+ err = NewGWorldFromPtr(&offGWorld,
+ k32ARGBPixelFormat,
+ &myRect, NULL, NULL, 0,
+ (unsigned char *)wbuf->rect, x * 4);
+#else
+
+ ibuf = IMB_allocImBuf (x, y, 32, IB_rect, 0);
+
+ err = NewGWorldFromPtr(&offGWorld,
+ k32RGBAPixelFormat,
+ &myRect, NULL, NULL, 0,
+ (unsigned char *)ibuf->rect, x * 4);
+#endif
+
+ if (err != noErr) {
+ if(QTIME_DEBUG) printf("no newgworld\n");
+ goto bail;
+ } else {
+ have_gw = TRUE;
+ }
+
+ GraphicsImportSetGWorld(gImporter, offGWorld, NULL);
+ GraphicsImportDraw(gImporter);
+
+#ifdef __APPLE__
+ rect = ibuf->rect;
+
+ myPixMap = GetGWorldPixMap(offGWorld);
+ LockPixels(myPixMap);
+ myPtr = GetPixBaseAddr(myPixMap);
+
+ if (myPtr == NULL) {
+ printf ("Error reading frame from Quicktime");
+ IMB_freeImBuf (ibuf);
+ return NULL;
+ }
+
+ boxsize = x * y;
+ readPos = (uint32_t *) myPtr;
+ changePos = (uint32_t *) rect;
+
+ // Swap alpha byte to the end, so ARGB become RGBA;
+ from= (unsigned char *)readPos;
+ to= (unsigned char *)changePos;
+
+ for( index = 0; index < boxsize; index++, from+=4, to+=4 ) {
+ to[3] = from[0];
+ to[0] = from[1];
+ to[1] = from[2];
+ to[2] = from[3];
+ }
+#endif
+
+bail:
+
+ DisposeHandle((Handle)dataref);
+ UnlockPixels(myPixMap);
+ if(have_gw) DisposeGWorld(offGWorld);
+
+#ifdef __APPLE__
+ if (wbuf) {
+ IMB_freeImBuf (wbuf);
+ wbuf = NULL;
+ }
+#endif
+
+ if (gImporter != NULL) CloseComponent(gImporter);
+
+ if (err != noErr) {
+ if(QTIME_DEBUG) printf("quicktime import unsuccesfull\n");
+ if (ibuf) {
+ IMB_freeImBuf (ibuf);
+ ibuf = NULL;
+ }
+ }
+
+ if(ibuf) {
+
+#ifdef _WIN32
+// add non transparent alpha layer, so images without alpha show up in the sequence editor
+// exception for GIF images since these can be transparent without being 32 bit
+// (might also be nescessary for OSX)
+ int i;
+ int box = x * y;
+ unsigned char *arect = (unsigned char *) ibuf->rect;
+
+ if( depth < 32 && (**desc).cType != kGIFCodecType) {
+ for(i = 0; i < box; i++, arect+=4)
+ arect[3] = 0xFF;
+ }
+#endif
+
+ IMB_flipy(ibuf);
+ ibuf->ftype = QUICKTIME;
+ }
+ return ibuf;
+}
+
+#endif /* _WIN32 || __APPLE__ */
+
+#endif /* WITH_QUICKTIME */
+
+
+#if 0
+
+struct ImageDescription {
+ long idSize;
+ CodecType cType;
+ long resvd1;
+ short resvd2;
+ short dataRefIndex;
+ short version;
+ short revisionLevel;
+ long vendor;
+ CodecQ temporalQuality;
+ CodecQ spatialQuality;
+ short width;
+ short height;
+ Fixed hRes;
+ Fixed vRes;
+ long dataSize;
+ short frameCount;
+ Str31 name;
+ short depth;
+ short clutID;
+};
+
+#endif // 0
diff --git a/source/blender/quicktime/quicktime_export.h b/source/blender/quicktime/quicktime_export.h
new file mode 100644
index 00000000000..5962ae3d713
--- /dev/null
+++ b/source/blender/quicktime/quicktime_export.h
@@ -0,0 +1,52 @@
+/* $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef __QUICKTIME_EXPORT_H__
+#define __QUICKTIME_EXPORT_H__
+
+#if defined (_WIN32) || (__APPLE__)
+
+#define __AIFF__
+
+// quicktime movie output functions
+struct RenderData;
+
+void start_qt(struct RenderData *rd, int rectx, int recty); //for movie handle (BKE writeavi.c now)
+void append_qt(int frame, int *pixels, int rectx, int recty);
+void end_qt(void);
+
+int get_qtcodec_settings(void); //for buttons.c
+void free_qtcomponentdata(void);
+void makeqtstring (char *string); //for playanim.c
+
+#endif //(_WIN32) || (__APPLE__)
+
+#endif // __QUICKTIME_IMP_H__
diff --git a/source/blender/quicktime/quicktime_import.h b/source/blender/quicktime/quicktime_import.h
new file mode 100644
index 00000000000..58f20e4bf16
--- /dev/null
+++ b/source/blender/quicktime/quicktime_import.h
@@ -0,0 +1,105 @@
+/**
+ * Quicktime_import.h
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2002-2003 by TNCCI Inc.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+
+#ifndef __QUICKTIME_IMP_H__
+#define __QUICKTIME_IMP_H__
+
+#define __AIFF__
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "../imbuf/IMB_imbuf.h"
+#include "../imbuf/IMB_imbuf_types.h"
+
+#ifndef __MOVIES__
+#ifdef _WIN32
+#include <Movies.h>
+#elif defined(__APPLE__)
+#define __CARBONSOUND__
+#import <Carbon/Carbon.h>
+#include <QuickTime/Movies.h>
+#endif
+#endif
+
+#ifdef _WIN32
+#ifndef __FIXMATH__
+#include <FixMath.h>
+#endif /* __FIXMATH__ */
+#endif /* _WIN32 _ */
+
+// quicktime structure definition
+// this structure is part of the anim struct
+
+typedef struct _QuicktimeMovie {
+ GWorldPtr offscreenGWorld;
+ PixMapHandle offscreenPixMap;
+
+ Movie movie;
+ short movieRefNum;
+ short movieResId;
+ int movWidth, movHeight;
+ Rect movieBounds;
+
+ int framecount;
+
+ TimeValue *frameIndex;
+ ImBuf *ibuf;
+
+ Media theMedia;
+ Track theTrack;
+ long trackIndex;
+ short depth;
+
+ int have_gw; //ugly
+} QuicktimeMovie;
+
+char *get_valid_qtname(char *name);
+
+
+// quicktime movie import functions
+
+int anim_is_quicktime (char *name);
+int startquicktime (struct anim *anim);
+void free_anim_quicktime (struct anim *anim);
+ImBuf *qtime_fetchibuf (struct anim *anim, int position);
+
+// quicktime image import functions
+
+int imb_is_a_quicktime (char *name);
+ImBuf *imb_quicktime_decode(unsigned char *mem, int size, int flags);
+
+#endif // __QUICKTIME_IMP_H__ \ No newline at end of file
diff --git a/source/blender/radiosity/CMakeLists.txt b/source/blender/radiosity/CMakeLists.txt
new file mode 100644
index 00000000000..14805f5bb8d
--- /dev/null
+++ b/source/blender/radiosity/CMakeLists.txt
@@ -0,0 +1,39 @@
+# $Id$
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2006, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Jacques Beaurain.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+
+FILE(GLOB SRC intern/source/*.c)
+
+SET(INC
+ extern/include ../blenlib ../blenkernel ../makesdna ../include
+ ../../../intern/guardedalloc ../render/extern/include
+ ../render/intern/include
+)
+
+BLENDERLIB_NOLIST(blender_radiosity "${SRC}" "${INC}")
+#env.BlenderLib ( 'blender_radiosity', sources, Split(incs), [], libtype='core', priority=50 )
diff --git a/source/blender/radiosity/Makefile b/source/blender/radiosity/Makefile
new file mode 100644
index 00000000000..9bbb20c3db4
--- /dev/null
+++ b/source/blender/radiosity/Makefile
@@ -0,0 +1,37 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+# Makes module object directory and bounces make to subdirectories.
+
+SOURCEDIR = source/blender/radiosity
+DIRS = intern
+
+include nan_subdirs.mk
diff --git a/source/blender/radiosity/SConscript b/source/blender/radiosity/SConscript
new file mode 100644
index 00000000000..102f79683f9
--- /dev/null
+++ b/source/blender/radiosity/SConscript
@@ -0,0 +1,12 @@
+#!/usr/bin/python
+Import ('env')
+
+sources = env.Glob('intern/source/*.c')
+
+incs = 'extern/include ../blenlib ../blenkernel ../makesdna ../include'
+incs += ' #/intern/guardedalloc ../render/extern/include'
+incs += ' ../render/intern/include'
+
+incs += ' ' + env['BF_OPENGL_INC']
+
+env.BlenderLib ( 'blender_radiosity', sources, Split(incs), [], libtype='core', priority=50 )
diff --git a/source/blender/radiosity/extern/include/radio.h b/source/blender/radiosity/extern/include/radio.h
new file mode 100644
index 00000000000..1bdd847930d
--- /dev/null
+++ b/source/blender/radiosity/extern/include/radio.h
@@ -0,0 +1,174 @@
+/* ***************************************
+
+
+
+ radio.h nov/dec 1992
+ revised for Blender may 1999
+
+ $Id$
+
+ ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version. The Blender
+ Foundation also sells licenses for use in proprietary software under
+ the Blender License. See http://www.blender.org/BL/ for information
+ about this.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ All rights reserved.
+
+ The Original Code is: all of this file.
+
+ Contributor(s): none yet.
+
+ ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef RADIO_H
+#define RADIO_H
+#define RADIO_H
+
+/* type include */
+#include "radio_types.h"
+
+extern RadGlobal RG;
+
+/* radfactors.c */
+extern float calcStokefactor(RPatch *shoot, RPatch *rp, RNode *rn, float *area);
+extern void calcTopfactors(void);
+void calcSidefactors(void);
+extern void initradiosity(void);
+extern void rad_make_hocos(RadView *vw);
+extern void hemizbuf(RadView *vw);
+extern int makeformfactors(RPatch *shoot);
+extern void applyformfactors(RPatch *shoot);
+extern RPatch *findshootpatch(void);
+extern void setnodeflags(RNode *rn, int flag, int set);
+extern void backface_test(RPatch *shoot);
+extern void clear_backface_test(void);
+extern void progressiverad(void);
+extern void minmaxradelem(RNode *rn, float *min, float *max);
+extern void minmaxradelemfilt(RNode *rn, float *min, float *max, float *errmin, float *errmax);
+extern void subdivideshootElements(int it);
+extern void subdivideshootPatches(int it);
+extern void inithemiwindows(void);
+extern void closehemiwindows(void);
+void rad_init_energy(void);
+
+/* radio.c */
+void freeAllRad(void);
+int rad_phase(void);
+void rad_status_str(char *str);
+void rad_printstatus(void);
+void rad_setlimits(void);
+void set_radglobal(void);
+void add_radio(void);
+void delete_radio(void);
+int rad_go(void);
+void rad_subdivshootpatch(void);
+void rad_subdivshootelem(void);
+void rad_limit_subdivide(void);
+
+/* radnode.c */
+extern void setnodelimit(float limit);
+extern float *mallocVert(void);
+extern float *callocVert(void);
+extern void freeVert(float *vert);
+extern int totalRadVert(void);
+extern RNode *mallocNode(void);
+extern RNode *callocNode(void);
+extern void freeNode(RNode *node);
+extern void freeNode_recurs(RNode *node);
+extern RPatch *mallocPatch(void);
+extern RPatch *callocPatch(void);
+extern void freePatch(RPatch *patch);
+extern void replaceAllNode(RNode *, RNode *);
+extern void replaceAllNodeInv(RNode *neighb, RNode *old);
+extern void replaceAllNodeUp(RNode *neighb, RNode *old);
+extern void replaceTestNode(RNode *, RNode **, RNode *, int , float *);
+extern void free_fastAll(void);
+
+/* radnode.c */
+extern void start_fastmalloc(char *str);
+extern int setvertexpointersNode(RNode *neighb, RNode *node, int level, float **v1, float **v2);
+extern float edlen(float *v1, float *v2);
+extern void deleteNodes(RNode *node);
+extern void subdivideTriNode(RNode *node, RNode *edge);
+extern void subdivideNode(RNode *node, RNode *edge);
+extern int comparelevel(RNode *node, RNode *nb, int level);
+
+/* radpreprocess.c */
+extern void splitconnected(void);
+extern int vergedge(const void *v1,const void *v2);
+extern void addedge(float *v1, float *v2, EdSort *es);
+extern void setedgepointers(void);
+extern void rad_collect_meshes(void);
+extern void countelem(RNode *rn);
+extern void countglobaldata(void);
+extern void addelem(RNode ***el, RNode *rn, RPatch *rp);
+extern void makeGlobalElemArray(void);
+extern void remakeGlobaldata(void);
+extern void splitpatch(RPatch *old);
+extern void addpatch(RPatch *old, RNode *rn);
+extern void converttopatches(void);
+extern void make_elements(void);
+extern void subdividelamps(void);
+extern void maxsizePatches(void);
+extern void subdiv_elements(void);
+
+/* radpostprocess.c */
+void addaccu(register char *z, register char *t);
+void addaccuweight(register char *z, register char *t, int w);
+void triaweight(Face *face, int *w1, int *w2, int *w3);
+void init_face_tab(void);
+Face *addface(void);
+Face *makeface(float *v1, float *v2, float *v3, float *v4, RNode *rn);
+void anchorQuadface(RNode *rn, float *v1, float *v2, float *v3, float *v4, int flag);
+void anchorTriface(RNode *rn, float *v1, float *v2, float *v3, int flag);
+float *findmiddlevertex(RNode *node, RNode *nb, float *v1, float *v2);
+void make_face_tab(void);
+void filterFaces(void);
+void calcfiltrad(RNode *rn, float *cd);
+void filterNodes(void);
+void removeEqualNodes(short limit);
+void rad_addmesh(void);
+void rad_replacemesh(void);
+
+/* raddisplay.c */
+extern char calculatecolor(float col);
+extern void make_node_display(void);
+extern void drawnodeWire(RNode *rn);
+extern void drawsingnodeWire(RNode *rn);
+extern void drawnodeSolid(RNode *rn);
+extern void drawnodeGour(RNode *rn);
+extern void drawpatch(RPatch *patch, unsigned int col);
+extern void drawfaceGour(Face *face);
+extern void drawfaceSolid(Face *face);
+extern void drawfaceWire(Face *face);
+extern void drawsquare(float *cent, float size, short cox, short coy);
+extern void drawlimits(void);
+extern void setcolNode(RNode *rn, unsigned int *col);
+extern void pseudoAmb(void);
+extern void rad_forcedraw(void);
+extern void drawpatch_ext(RPatch *patch, unsigned int col);
+extern void RAD_drawall(int depth_is_on);
+
+/* radrender.c */
+struct Render;
+extern void do_radio_render(struct Render *re);
+void end_radio_render(void);
+
+#endif /* RADIO_H */
+
diff --git a/source/blender/radiosity/extern/include/radio_types.h b/source/blender/radiosity/extern/include/radio_types.h
new file mode 100644
index 00000000000..c9a0726e0d8
--- /dev/null
+++ b/source/blender/radiosity/extern/include/radio_types.h
@@ -0,0 +1,175 @@
+/*
+ * radio_types.h
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/* #include "misc_util.h" */ /* for listbase...*/
+
+
+#ifndef RADIO_TYPES_H
+#define RADIO_TYPES_H
+
+#include "DNA_listBase.h"
+#include "DNA_material_types.h"
+
+struct Render;
+struct CustomData;
+
+#define DTWIRE 0
+#define DTGOUR 2
+#define DTSOLID 1
+
+#define PI M_PI
+#define RAD_MAXFACETAB 1024
+#define RAD_NEXTFACE(a) if( ((a) & 1023)==0 ) face= RG.facebase[(a)>>10]; else face++;
+
+/* RG.phase */
+#define RAD_SHOOTE 1
+#define RAD_SHOOTP 2
+#define RAD_SOLVE 3
+
+typedef struct RadView {
+ float cam[3], tar[3], up[3];
+ float wx1, wx2, wy1, wy2;
+ float mynear, myfar;
+ float viewmat[4][4], winmat[4][4];
+ unsigned int *rect, *rectz;
+ short rectx, recty;
+ int wid;
+
+} RadView;
+
+/* rn->f */
+#define RAD_PATCH 1
+#define RAD_SHOOT 2
+#define RAD_SUBDIV 4
+#define RAD_BACKFACE 8
+#define RAD_TWOSIDED 16
+
+
+typedef struct RNode { /* length: 104 */
+ struct RNode *down1, *down2, *up;
+ struct RNode *ed1, *ed2, *ed3, *ed4;
+ struct RPatch *par;
+
+ char lev1, lev2, lev3, lev4; /* edgelevels */
+ short type; /* type: 4==QUAD, 3==TRIA */
+ short f;
+ float *v1, *v2, *v3, *v4;
+ float totrad[3], area;
+
+ unsigned int col;
+ int orig; /* index in custom face data */
+} RNode;
+
+
+typedef struct Face { /* length: 52 */
+ float *v1, *v2, *v3, *v4;
+ unsigned int col, matindex;
+ int orig; /* index in custom face data */
+} Face;
+
+/* rp->f1 */
+#define RAD_NO_SPLIT 1
+
+typedef struct RPatch {
+ struct RPatch *next, *prev;
+ RNode *first; /* first node==patch */
+
+ struct Object *from;
+
+ int type; /* 3: TRIA, 4: QUAD */
+ short f, f1; /* flags f: if node, only for subdiv */
+
+ float ref[3], emit[3], unshot[3];
+ float cent[3], norm[3];
+ float area;
+ int matindex;
+
+} RPatch;
+
+
+typedef struct VeNoCo { /* needed for splitconnected */
+ struct VeNoCo *next;
+ float *v;
+ float *n;
+ float *col;
+ int flag;
+} VeNoCo;
+
+
+typedef struct EdSort { /* sort edges */
+ float *v1, *v2;
+ RNode *node;
+ int nr;
+} EdSort;
+
+typedef struct {
+ struct Radio *radio;
+ unsigned int *hemibuf;
+ struct ListBase patchbase;
+ int totpatch, totelem, totvert, totlamp;
+ RNode **elem; /* global array with all pointers */
+ VeNoCo *verts; /* temporal vertices from patches */
+ float *formfactors; /* 1 factor per element */
+ float *topfactors, *sidefactors; /* LUT for delta's */
+ int *index; /* LUT for above LUT */
+ Face **facebase;
+ int totface;
+ float min[3], max[3], size[3], cent[3]; /* world */
+ float maxsize, totenergy;
+ float patchmin, patchmax;
+ float elemmin, elemmax;
+ float radfactor, lostenergy, igamma; /* radfac is in button, radfactor is calculated */
+ int phase;
+ struct Render *re; /* for calling hemizbuf correctly */
+ /* to preserve materials as used before, max 16 */
+ Material *matar[MAXMAT];
+ int totmat;
+
+ /* for preserving face data */
+ int mfdatatot;
+ struct CustomData *mfdata;
+ struct RNode **mfdatanodes;
+
+ /* this part is a copy of struct Radio */
+ short hemires, maxiter;
+ short drawtype, flag; /* bit 0 en 1: show limits */
+ short subshootp, subshoote, nodelim, maxsublamp;
+ int maxnode;
+ float convergence;
+ float radfac, gamma; /* for display */
+
+} RadGlobal;
+
+#endif /* radio_types.h */
+
diff --git a/source/blender/radiosity/intern/Makefile b/source/blender/radiosity/intern/Makefile
new file mode 100644
index 00000000000..fde495bed85
--- /dev/null
+++ b/source/blender/radiosity/intern/Makefile
@@ -0,0 +1,37 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+# Makes module object directory and bounces make to subdirectories.
+
+SOURCEDIR = source/blender/radiosity/intern
+DIRS = source
+
+include nan_subdirs.mk
diff --git a/source/blender/radiosity/intern/source/Makefile b/source/blender/radiosity/intern/source/Makefile
new file mode 100644
index 00000000000..7791866eeaa
--- /dev/null
+++ b/source/blender/radiosity/intern/source/Makefile
@@ -0,0 +1,56 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+# radiosity uses the render lib
+#
+
+LIBNAME = radiosity
+DIR = $(OCGDIR)/blender/$(LIBNAME)
+
+include nan_compile.mk
+
+CFLAGS += $(LEVEL_1_C_WARNINGS)
+
+CPPFLAGS += -I$(OPENGL_HEADERS)
+
+# not very neat....
+CPPFLAGS += -I../../../blenkernel
+CPPFLAGS += -I../../../blenlib
+CPPFLAGS += -I../../../makesdna
+CPPFLAGS += -I../../../imbuf
+CPPFLAGS += -I../../../
+CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
+
+# first /include is my own includes, second are the external includes
+# third is the external interface. there should be a nicer way to say this
+CPPFLAGS += -I../include -I../../../include -I../../extern/include
+CPPFLAGS += -I../../../render/extern/include
+CPPFLAGS += -I../../../render/intern/include
diff --git a/source/blender/radiosity/intern/source/raddisplay.c b/source/blender/radiosity/intern/source/raddisplay.c
new file mode 100644
index 00000000000..dcd53b61f46
--- /dev/null
+++ b/source/blender/radiosity/intern/source/raddisplay.c
@@ -0,0 +1,490 @@
+/* ***************************************
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+
+
+
+ raddisplay.c nov/dec 1992
+ may 1999
+
+ - drawing
+ - color calculation for display during solving
+
+ $Id$
+
+ *************************************** */
+
+#include <stdlib.h>
+#include <math.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "BLI_blenlib.h"
+
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_global.h"
+#include "BKE_main.h"
+
+#include "BIF_gl.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_mywindow.h"
+
+#include "BSE_view.h"
+
+#include "radio.h"
+
+/* cpack has to be endian-insensitive! (old irisgl function) */
+#define cpack(x) glColor3ub( ((x)&0xFF), (((x)>>8)&0xFF), (((x)>>16)&0xFF) )
+
+char calculatecolor(float col)
+{
+ int b;
+
+ if(RG.gamma==1.0) {
+ b= RG.radfactor*col;
+ }
+ else if(RG.gamma==2.0) {
+ b= RG.radfactor*sqrt(col);
+ }
+ else {
+ b= RG.radfactor*pow(col, RG.igamma);
+ }
+
+ if(b>255) b=255;
+ return b;
+}
+
+void make_node_display()
+{
+ RNode *rn, **el;
+ int a;
+ char *charcol;
+
+ RG.igamma= 1.0/RG.gamma;
+ RG.radfactor= RG.radfac*pow(64*64, RG.igamma);
+
+ el= RG.elem;
+ for(a=RG.totelem; a>0; a--, el++) {
+ rn= *el;
+ charcol= (char *)&( rn->col );
+
+ charcol[3]= calculatecolor(rn->totrad[0]);
+ charcol[2]= calculatecolor(rn->totrad[1]);
+ charcol[1]= calculatecolor(rn->totrad[2]);
+
+ /* gouraudcolor */
+ *(rn->v1+3)= 0;
+ *(rn->v2+3)= 0;
+ *(rn->v3+3)= 0;
+ if(rn->v4) *(rn->v4+3)= 0;
+ }
+
+ el= RG.elem;
+ for(a=RG.totelem; a>0; a--, el++) {
+ rn= *el;
+ addaccuweight( (char *)&(rn->col), (char *)(rn->v1+3), 16 );
+ addaccuweight( (char *)&(rn->col), (char *)(rn->v2+3), 16 );
+ addaccuweight( (char *)&(rn->col), (char *)(rn->v3+3), 16 );
+ if(rn->v4) addaccuweight( (char *)&(rn->col), (char *)(rn->v4+3), 16 );
+ }
+}
+
+void drawnodeWire(RNode *rn)
+{
+
+ if(rn->down1) {
+ drawnodeWire(rn->down1);
+ drawnodeWire(rn->down2);
+ }
+ else {
+ glBegin(GL_LINE_LOOP);
+ glVertex3fv(rn->v1);
+ glVertex3fv(rn->v2);
+ glVertex3fv(rn->v3);
+ if(rn->type==4) glVertex3fv(rn->v4);
+ glEnd();
+ }
+}
+
+void drawsingnodeWire(RNode *rn)
+{
+
+ glBegin(GL_LINE_LOOP);
+ glVertex3fv(rn->v1);
+ glVertex3fv(rn->v2);
+ glVertex3fv(rn->v3);
+ if(rn->type==4) glVertex3fv(rn->v4);
+ glEnd();
+}
+
+void drawnodeSolid(RNode *rn)
+{
+ char *cp;
+
+ if(rn->down1) {
+ drawnodeSolid(rn->down1);
+ drawnodeSolid(rn->down2);
+ }
+ else {
+ cp= (char *)&rn->col;
+ glColor3ub(cp[3], cp[2], cp[1]);
+ glBegin(GL_POLYGON);
+ glVertex3fv(rn->v1);
+ glVertex3fv(rn->v2);
+ glVertex3fv(rn->v3);
+ if(rn->type==4) glVertex3fv(rn->v4);
+ glEnd();
+ }
+}
+
+void drawnodeGour(RNode *rn)
+{
+ char *cp;
+
+ if(rn->down1) {
+ drawnodeGour(rn->down1);
+ drawnodeGour(rn->down2);
+ }
+ else {
+ glBegin(GL_POLYGON);
+ cp= (char *)(rn->v1+3);
+ glColor3ub(cp[3], cp[2], cp[1]);
+ glVertex3fv(rn->v1);
+
+ cp= (char *)(rn->v2+3);
+ glColor3ub(cp[3], cp[2], cp[1]);
+ glVertex3fv(rn->v2);
+
+ cp= (char *)(rn->v3+3);
+ glColor3ub(cp[3], cp[2], cp[1]);
+ glVertex3fv(rn->v3);
+
+ if(rn->type==4) {
+ cp= (char *)(rn->v4+3);
+ glColor3ub(cp[3], cp[2], cp[1]);
+ glVertex3fv(rn->v4);
+ }
+ glEnd();
+ }
+}
+
+void drawpatch_ext(RPatch *patch, unsigned int col)
+{
+ ScrArea *sa, *oldsa;
+ View3D *v3d;
+ glDrawBuffer(GL_FRONT);
+
+ cpack(col);
+
+ oldsa= curarea;
+
+ sa= G.curscreen->areabase.first;
+ while(sa) {
+ if (sa->spacetype==SPACE_VIEW3D) {
+ v3d= sa->spacedata.first;
+
+ /* use mywinget() here: otherwise it draws in header */
+ if(sa->win != mywinget()) areawinset(sa->win);
+ persp(PERSP_VIEW);
+ if(v3d->zbuf) glDisable(GL_DEPTH_TEST);
+ drawnodeWire(patch->first);
+ if(v3d->zbuf) glEnable(GL_DEPTH_TEST); // pretty useless?
+ }
+ sa= sa->next;
+ }
+
+ if(oldsa && oldsa!=curarea) areawinset(oldsa->win);
+
+ glFlush();
+ glDrawBuffer(GL_BACK);
+}
+
+
+void drawfaceGour(Face *face)
+{
+ char *cp;
+
+ glBegin(GL_POLYGON);
+ cp= (char *)(face->v1+3);
+ glColor3ub(cp[3], cp[2], cp[1]);
+ glVertex3fv(face->v1);
+
+ cp= (char *)(face->v2+3);
+ glColor3ub(cp[3], cp[2], cp[1]);
+ glVertex3fv(face->v2);
+
+ cp= (char *)(face->v3+3);
+ glColor3ub(cp[3], cp[2], cp[1]);
+ glVertex3fv(face->v3);
+
+ if(face->v4) {
+ cp= (char *)(face->v4+3);
+ glColor3ub(cp[3], cp[2], cp[1]);
+ glVertex3fv(face->v4);
+ }
+ glEnd();
+
+}
+
+void drawfaceSolid(Face *face)
+{
+ char *cp;
+
+ cp= (char *)&face->col;
+ glColor3ub(cp[3], cp[2], cp[1]);
+
+ glBegin(GL_POLYGON);
+ glVertex3fv(face->v1);
+ glVertex3fv(face->v2);
+ glVertex3fv(face->v3);
+ if(face->v4) {
+ glVertex3fv(face->v4);
+ }
+ glEnd();
+
+}
+
+void drawfaceWire(Face *face)
+{
+ char *cp;
+
+ cp= (char *)&face->col;
+ glColor3ub(cp[3], cp[2], cp[1]);
+
+ glBegin(GL_LINE_LOOP);
+ glVertex3fv(face->v1);
+ glVertex3fv(face->v2);
+ glVertex3fv(face->v3);
+ if(face->v4) {
+ glVertex3fv(face->v4);
+ }
+ glEnd();
+
+}
+
+void drawsquare(float *cent, float size, short cox, short coy)
+{
+ float vec[3];
+
+ vec[0]= cent[0];
+ vec[1]= cent[1];
+ vec[2]= cent[2];
+
+ glBegin(GL_LINE_LOOP);
+ vec[cox]+= .5*size;
+ vec[coy]+= .5*size;
+ glVertex3fv(vec);
+ vec[coy]-= size;
+ glVertex3fv(vec);
+ vec[cox]-= size;
+ glVertex3fv(vec);
+ vec[coy]+= size;
+ glVertex3fv(vec);
+ glEnd();
+}
+
+void drawlimits()
+{
+ /* center around cent */
+ short cox=0, coy=1;
+
+ if((RG.flag & 3)==2) coy= 2;
+ if((RG.flag & 3)==3) {
+ cox= 1;
+ coy= 2;
+ }
+
+ cpack(0);
+ drawsquare(RG.cent, sqrt(RG.patchmax), cox, coy);
+ drawsquare(RG.cent, sqrt(RG.patchmin), cox, coy);
+
+ drawsquare(RG.cent, sqrt(RG.elemmax), cox, coy);
+ drawsquare(RG.cent, sqrt(RG.elemmin), cox, coy);
+
+ cpack(0xFFFFFF);
+ drawsquare(RG.cent, sqrt(RG.patchmax), cox, coy);
+ drawsquare(RG.cent, sqrt(RG.patchmin), cox, coy);
+ cpack(0xFFFF00);
+ drawsquare(RG.cent, sqrt(RG.elemmax), cox, coy);
+ drawsquare(RG.cent, sqrt(RG.elemmin), cox, coy);
+
+}
+
+void setcolNode(RNode *rn, unsigned int *col)
+{
+
+ if(rn->down1) {
+ setcolNode(rn->down1, col);
+ setcolNode(rn->down2, col);
+ }
+ rn->col= *col;
+
+ *((unsigned int *)rn->v1+3)= *col;
+ *((unsigned int *)rn->v2+3)= *col;
+ *((unsigned int *)rn->v3+3)= *col;
+ if(rn->v4) *((unsigned int *)rn->v4+3)= *col;
+}
+
+void pseudoAmb()
+{
+ RPatch *rp;
+ float fac;
+ char col[4];
+
+ /* sets pseudo ambient color in the nodes */
+
+ rp= RG.patchbase.first;
+ while(rp) {
+
+ if(rp->emit[0]!=0.0 || rp->emit[1]!=0.0 || rp->emit[2]!=0.0) {
+ col[1]= col[2]= col[3]= 255;
+ }
+ else {
+ fac= rp->norm[0]+ rp->norm[1]+ rp->norm[2];
+ fac= 225.0*(3+fac)/6.0;
+
+ col[3]= fac*rp->ref[0];
+ col[2]= fac*rp->ref[1];
+ col[1]= fac*rp->ref[2];
+ }
+
+ setcolNode(rp->first, (unsigned int *)col);
+
+ rp= rp->next;
+ }
+}
+
+void RAD_drawall(int depth_is_on)
+{
+ /* displays elements or faces */
+ Face *face = NULL;
+ RNode **el;
+ RPatch *rp;
+ int a;
+
+ if(!depth_is_on) {
+ glEnable(GL_DEPTH_TEST);
+ glClearDepth(1.0); glClear(GL_DEPTH_BUFFER_BIT);
+ }
+
+ if(RG.totface) {
+ if(RG.drawtype==DTGOUR) {
+ glShadeModel(GL_SMOOTH);
+ for(a=0; a<RG.totface; a++) {
+ RAD_NEXTFACE(a);
+
+ drawfaceGour(face);
+ }
+ }
+ else if(RG.drawtype==DTSOLID) {
+ for(a=0; a<RG.totface; a++) {
+ RAD_NEXTFACE(a);
+
+ drawfaceSolid(face);
+ }
+ }
+ else {
+ if(!(get_qual()&LR_SHIFTKEY)) {
+
+ for(a=0; a<RG.totface; a++) {
+ RAD_NEXTFACE(a);
+
+ drawfaceWire(face);
+ }
+ }
+ else {
+ cpack(0);
+ rp= RG.patchbase.first;
+ while(rp) {
+ drawsingnodeWire(rp->first);
+ rp= rp->next;
+ }
+ }
+ }
+ }
+ else {
+ el= RG.elem;
+ if(RG.drawtype==DTGOUR) {
+ glShadeModel(GL_SMOOTH);
+ for(a=RG.totelem; a>0; a--, el++) {
+ drawnodeGour(*el);
+ }
+ }
+ else if(RG.drawtype==DTSOLID) {
+ for(a=RG.totelem; a>0; a--, el++) {
+ drawnodeSolid(*el);
+ }
+ }
+ else {
+ cpack(0);
+ for(a=RG.totelem; a>0; a--, el++) {
+ drawnodeWire(*el);
+ }
+ }
+ }
+ glShadeModel(GL_FLAT);
+
+ if(RG.totpatch) {
+ if(RG.flag & 3) {
+ if(depth_is_on) glDisable(GL_DEPTH_TEST);
+ drawlimits();
+ if(depth_is_on) glEnable(GL_DEPTH_TEST);
+ }
+ }
+ if(!depth_is_on) {
+ glDisable(GL_DEPTH_TEST);
+ }
+}
+
+void rad_forcedraw()
+{
+ ScrArea *sa, *oldsa;
+
+ oldsa= curarea;
+
+ sa= G.curscreen->areabase.first;
+ while(sa) {
+ if (sa->spacetype==SPACE_VIEW3D) {
+ /* use mywinget() here: othwerwise it draws in header */
+ if(sa->win != mywinget()) areawinset(sa->win);
+ scrarea_do_windraw(sa);
+ }
+ sa= sa->next;
+ }
+ screen_swapbuffers();
+
+ if(oldsa && oldsa!=curarea) areawinset(oldsa->win);
+}
+
diff --git a/source/blender/radiosity/intern/source/radfactors.c b/source/blender/radiosity/intern/source/radfactors.c
new file mode 100644
index 00000000000..46fb6b2c910
--- /dev/null
+++ b/source/blender/radiosity/intern/source/radfactors.c
@@ -0,0 +1,946 @@
+/* ***************************************
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+
+
+
+ formfactors.c nov/dec 1992
+
+ $Id$
+
+ *************************************** */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_rand.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+
+#include "BIF_screen.h"
+
+#include "radio.h"
+#include "RE_render_ext.h" /* for `RE_zbufferall_radio and RE_zbufferall_radio */
+
+/* locals */
+void rad_setmatrices(RadView *vw);
+void clearsubflagelem(RNode *rn);
+void setsubflagelem(RNode *rn);
+
+RadView hemitop, hemiside;
+
+float calcStokefactor(RPatch *shoot, RPatch *rp, RNode *rn, float *area)
+{
+ float tvec[3], fac;
+ float vec[4][3]; /* vectors of shoot->cent to vertices rp */
+ float cross[4][3]; /* cross products of this */
+ float rad[4]; /* anlgles between vecs */
+
+ /* test for direction */
+ VecSubf(tvec, shoot->cent, rp->cent);
+ if( tvec[0]*shoot->norm[0]+ tvec[1]*shoot->norm[1]+ tvec[2]*shoot->norm[2]>0.0)
+ return 0.0;
+
+ if(rp->type==4) {
+
+ /* corner vectors */
+ VecSubf(vec[0], shoot->cent, rn->v1);
+ VecSubf(vec[1], shoot->cent, rn->v2);
+ VecSubf(vec[2], shoot->cent, rn->v3);
+ VecSubf(vec[3], shoot->cent, rn->v4);
+
+ Normalize(vec[0]);
+ Normalize(vec[1]);
+ Normalize(vec[2]);
+ Normalize(vec[3]);
+
+ /* cross product */
+ Crossf(cross[0], vec[0], vec[1]);
+ Crossf(cross[1], vec[1], vec[2]);
+ Crossf(cross[2], vec[2], vec[3]);
+ Crossf(cross[3], vec[3], vec[0]);
+ Normalize(cross[0]);
+ Normalize(cross[1]);
+ Normalize(cross[2]);
+ Normalize(cross[3]);
+
+ /* angles */
+ rad[0]= vec[0][0]*vec[1][0]+ vec[0][1]*vec[1][1]+ vec[0][2]*vec[1][2];
+ rad[1]= vec[1][0]*vec[2][0]+ vec[1][1]*vec[2][1]+ vec[1][2]*vec[2][2];
+ rad[2]= vec[2][0]*vec[3][0]+ vec[2][1]*vec[3][1]+ vec[2][2]*vec[3][2];
+ rad[3]= vec[3][0]*vec[0][0]+ vec[3][1]*vec[0][1]+ vec[3][2]*vec[0][2];
+
+ rad[0]= acos(rad[0]);
+ rad[1]= acos(rad[1]);
+ rad[2]= acos(rad[2]);
+ rad[3]= acos(rad[3]);
+
+ /* Stoke formula */
+ VecMulf(cross[0], rad[0]);
+ VecMulf(cross[1], rad[1]);
+ VecMulf(cross[2], rad[2]);
+ VecMulf(cross[3], rad[3]);
+
+ VECCOPY(tvec, shoot->norm);
+ fac= tvec[0]*cross[0][0]+ tvec[1]*cross[0][1]+ tvec[2]*cross[0][2];
+ fac+= tvec[0]*cross[1][0]+ tvec[1]*cross[1][1]+ tvec[2]*cross[1][2];
+ fac+= tvec[0]*cross[2][0]+ tvec[1]*cross[2][1]+ tvec[2]*cross[2][2];
+ fac+= tvec[0]*cross[3][0]+ tvec[1]*cross[3][1]+ tvec[2]*cross[3][2];
+ }
+ else {
+ /* corner vectors */
+ VecSubf(vec[0], shoot->cent, rn->v1);
+ VecSubf(vec[1], shoot->cent, rn->v2);
+ VecSubf(vec[2], shoot->cent, rn->v3);
+
+ Normalize(vec[0]);
+ Normalize(vec[1]);
+ Normalize(vec[2]);
+
+ /* cross product */
+ Crossf(cross[0], vec[0], vec[1]);
+ Crossf(cross[1], vec[1], vec[2]);
+ Crossf(cross[2], vec[2], vec[0]);
+ Normalize(cross[0]);
+ Normalize(cross[1]);
+ Normalize(cross[2]);
+
+ /* angles */
+ rad[0]= vec[0][0]*vec[1][0]+ vec[0][1]*vec[1][1]+ vec[0][2]*vec[1][2];
+ rad[1]= vec[1][0]*vec[2][0]+ vec[1][1]*vec[2][1]+ vec[1][2]*vec[2][2];
+ rad[2]= vec[2][0]*vec[0][0]+ vec[2][1]*vec[0][1]+ vec[2][2]*vec[0][2];
+
+ rad[0]= acos(rad[0]);
+ rad[1]= acos(rad[1]);
+ rad[2]= acos(rad[2]);
+
+ /* Stoke formula */
+ VecMulf(cross[0], rad[0]);
+ VecMulf(cross[1], rad[1]);
+ VecMulf(cross[2], rad[2]);
+
+ VECCOPY(tvec, shoot->norm);
+ fac= tvec[0]*cross[0][0]+ tvec[1]*cross[0][1]+ tvec[2]*cross[0][2];
+ fac+= tvec[0]*cross[1][0]+ tvec[1]*cross[1][1]+ tvec[2]*cross[1][2];
+ fac+= tvec[0]*cross[2][0]+ tvec[1]*cross[2][1]+ tvec[2]*cross[2][2];
+ }
+
+ *area= -fac/(2.0*PI);
+ return (*area * (shoot->area/rn->area));
+}
+
+
+void calcTopfactors()
+{
+ float xsq , ysq, xysq;
+ float n;
+ float *fp;
+ int a, b, hres;
+
+ fp = RG.topfactors;
+ hres= RG.hemires/2;
+ n= hres;
+
+ for (a=0; a<hres; a++) {
+
+ ysq= (n- ((float)a+0.5))/n;
+ ysq*= ysq;
+
+ for ( b=0 ; b<hres ; b++ ) {
+
+ xsq= ( n-((float)b+ 0.5) )/n;
+ xsq*= xsq;
+ xysq= xsq+ ysq+ 1.0 ;
+ xysq*= xysq;
+
+ *fp++ = 1.0/(xysq* PI* n*n);
+ }
+ }
+
+}
+
+void calcSidefactors()
+{
+ float xsq , ysq, xysq;
+ float n, y;
+ float *fp;
+ int a, b, hres;
+
+ fp = RG.sidefactors;
+ hres= RG.hemires/2;
+ n= hres;
+
+ for (a=0; a<hres; a++) {
+
+ y= (n- ((float)a+0.5))/n;
+ ysq= y*y;
+
+ for ( b=0 ; b<hres ; b++ ) {
+
+ xsq= ( n-((float)b+ 0.5) )/n;
+ xsq*= xsq;
+ xysq= xsq+ ysq+ 1.0 ;
+ xysq*= xysq;
+
+ *fp++ = y/(xysq* PI* n*n);
+ }
+ }
+
+}
+
+
+void initradiosity()
+{
+ /* allocates and makes LUTs for top/side factors */
+ /* allocates and makes index array */
+ int a, hres2;
+
+ if(RG.topfactors) MEM_freeN(RG.topfactors);
+ if(RG.sidefactors) MEM_freeN(RG.sidefactors);
+ if(RG.index) MEM_freeN(RG.index);
+
+ RG.topfactors= MEM_callocN(RG.hemires*RG.hemires, "initradiosity");
+ calcTopfactors();
+ RG.sidefactors= MEM_callocN(RG.hemires*RG.hemires, "initradiosity1");
+ calcSidefactors();
+
+ RG.index= MEM_callocN(4*RG.hemires, "initradiosity3");
+ hres2= RG.hemires/2;
+ for(a=0; a<RG.hemires; a++) {
+ RG.index[a]= a<hres2 ? a: (hres2-1-( a % hres2 ));
+ }
+
+}
+
+void rad_make_hocos(RadView *vw)
+{
+ /* float hoco[4]; */
+ /* int a; */
+
+ /* for(a=0; a< R.totvert;a++) { */
+ /* projectvert(vec, ver->ho); */
+ /* ver->clip = testclip(ver->ho); */
+/* */
+ /* } */
+}
+
+void rad_setmatrices(RadView *vw) /* for hemi's */
+{
+ float up1[3], len, twist;
+
+ i_lookat(vw->cam[0], vw->cam[1], vw->cam[2], vw->tar[0], vw->tar[1], vw->tar[2], 0, vw->viewmat);
+ up1[0] = vw->viewmat[0][0]*vw->up[0] + vw->viewmat[1][0]*vw->up[1] + vw->viewmat[2][0]*vw->up[2];
+ up1[1] = vw->viewmat[0][1]*vw->up[0] + vw->viewmat[1][1]*vw->up[1] + vw->viewmat[2][1]*vw->up[2];
+ up1[2] = vw->viewmat[0][2]*vw->up[0] + vw->viewmat[1][2]*vw->up[1] + vw->viewmat[2][2]*vw->up[2];
+
+ len= up1[0]*up1[0]+up1[1]*up1[1];
+ if(len>0.0) {
+ twist= -atan2(up1[0], up1[1]);
+ }
+ else twist= 0.0;
+
+ i_lookat(vw->cam[0], vw->cam[1], vw->cam[2], vw->tar[0], vw->tar[1], vw->tar[2], (180.0*twist/M_PI), vw->viewmat);
+
+ /* window matrix was set in inithemiwindows */
+
+}
+
+
+void hemizbuf(RadView *vw)
+{
+ float *factors;
+ unsigned int *rz;
+ int a, b, inda, hres;
+
+ rad_setmatrices(vw);
+ RE_zbufferall_radio(vw, RG.elem, RG.totelem, RG.re); /* Render for when we got renderfaces */
+
+ /* count factors */
+ if(vw->recty==vw->rectx) factors= RG.topfactors;
+ else factors= RG.sidefactors;
+ hres= RG.hemires/2;
+
+ rz= vw->rect;
+ for(a=0; a<vw->recty; a++) {
+ inda= hres*RG.index[a];
+ for(b=0; b<vw->rectx; b++, rz++) {
+ if(*rz<RG.totelem) {
+ RG.formfactors[*rz]+= factors[inda+RG.index[b]];
+ }
+ }
+ }
+}
+
+int makeformfactors(RPatch *shoot)
+{
+ RNode **re;
+ float len, vec[3], up[3], side[3], tar[5][3], *fp;
+ int a=0, overfl;
+
+ if(RG.totelem==0) return 0;
+
+ memset(RG.formfactors, 0, 4*RG.totelem);
+
+ /* set up hemiview */
+ /* first: random upvector */
+ do {
+ a++;
+ vec[0]= (float)BLI_drand();
+ vec[1]= (float)BLI_drand();
+ vec[2]= (float)BLI_drand();
+ Crossf(up, shoot->norm, vec);
+ len= Normalize(up);
+ /* this safety for input normals that are zero or illegal sized */
+ if(a>3) return 0;
+ } while(len==0.0 || len>1.0);
+
+ VECCOPY(hemitop.up, up);
+ VECCOPY(hemiside.up, shoot->norm);
+
+ Crossf(side, shoot->norm, up);
+
+ /* five targets */
+ VecAddf(tar[0], shoot->cent, shoot->norm);
+ VecAddf(tar[1], shoot->cent, up);
+ VecSubf(tar[2], shoot->cent, up);
+ VecAddf(tar[3], shoot->cent, side);
+ VecSubf(tar[4], shoot->cent, side);
+
+ /* camera */
+ VECCOPY(hemiside.cam, shoot->cent);
+ VECCOPY(hemitop.cam, shoot->cent);
+
+ /* do it! */
+ VECCOPY(hemitop.tar, tar[0]);
+ hemizbuf(&hemitop);
+
+ for(a=1; a<5; a++) {
+ VECCOPY(hemiside.tar, tar[a]);
+ hemizbuf(&hemiside);
+ }
+
+ /* convert factors to real radiosity */
+ re= RG.elem;
+ fp= RG.formfactors;
+
+ overfl= 0;
+ for(a= RG.totelem; a>0; a--, re++, fp++) {
+
+ if(*fp!=0.0) {
+
+ *fp *= shoot->area/(*re)->area;
+
+ if(*fp>1.0) {
+ overfl= 1;
+ *fp= 1.0001;
+ }
+ }
+ }
+
+ if(overfl) {
+ if(shoot->first->down1) {
+ splitpatch(shoot);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+void applyformfactors(RPatch *shoot)
+{
+ RPatch *rp;
+ RNode **el, *rn;
+ float *fp, *ref, unr, ung, unb, r, g, b, w;
+ int a;
+
+ unr= shoot->unshot[0];
+ ung= shoot->unshot[1];
+ unb= shoot->unshot[2];
+
+ fp= RG.formfactors;
+ el= RG.elem;
+ for(a=0; a<RG.totelem; a++, el++, fp++) {
+ rn= *el;
+ if(*fp!= 0.0) {
+ rp= rn->par;
+ ref= rp->ref;
+
+ r= (*fp)*unr*ref[0];
+ g= (*fp)*ung*ref[1];
+ b= (*fp)*unb*ref[2];
+
+ w= rn->area/rp->area;
+ rn->totrad[0]+= r;
+ rn->totrad[1]+= g;
+ rn->totrad[2]+= b;
+
+ rp->unshot[0]+= w*r;
+ rp->unshot[1]+= w*g;
+ rp->unshot[2]+= w*b;
+ }
+ }
+
+ shoot->unshot[0]= shoot->unshot[1]= shoot->unshot[2]= 0.0;
+}
+
+RPatch *findshootpatch()
+{
+ RPatch *rp, *shoot;
+ float energy, maxenergy;
+
+ shoot= 0;
+ maxenergy= 0.0;
+ rp= RG.patchbase.first;
+ while(rp) {
+ energy= rp->unshot[0]*rp->area;
+ energy+= rp->unshot[1]*rp->area;
+ energy+= rp->unshot[2]*rp->area;
+
+ if(energy>maxenergy) {
+ shoot= rp;
+ maxenergy= energy;
+ }
+ rp= rp->next;
+ }
+
+ if(shoot) {
+ maxenergy/= RG.totenergy;
+ if(maxenergy<RG.convergence) return 0;
+ }
+
+ return shoot;
+}
+
+void setnodeflags(RNode *rn, int flag, int set)
+{
+
+ if(rn->down1) {
+ setnodeflags(rn->down1, flag, set);
+ setnodeflags(rn->down2, flag, set);
+ }
+ else {
+ if(set) rn->f |= flag;
+ else rn->f &= ~flag;
+ }
+}
+
+void backface_test(RPatch *shoot)
+{
+ RPatch *rp;
+ float tvec[3];
+
+ rp= RG.patchbase.first;
+ while(rp) {
+ if(rp!=shoot) {
+
+ VecSubf(tvec, shoot->cent, rp->cent);
+ if( tvec[0]*rp->norm[0]+ tvec[1]*rp->norm[1]+ tvec[2]*rp->norm[2]<0.0) {
+ setnodeflags(rp->first, RAD_BACKFACE, 1);
+ }
+ }
+ rp= rp->next;
+ }
+}
+
+void clear_backface_test()
+{
+ RNode **re;
+ int a;
+
+ re= RG.elem;
+ for(a= RG.totelem-1; a>=0; a--, re++) {
+ (*re)->f &= ~RAD_BACKFACE;
+ }
+
+}
+
+void rad_init_energy()
+{
+ /* call before shooting */
+ /* keep patches and elements, clear all data */
+ RNode **el, *rn;
+ RPatch *rp;
+ int a;
+
+ el= RG.elem;
+ for(a=RG.totelem; a>0; a--, el++) {
+ rn= *el;
+ VECCOPY(rn->totrad, rn->par->emit);
+ }
+
+ RG.totenergy= 0.0;
+ rp= RG.patchbase.first;
+ while(rp) {
+ VECCOPY(rp->unshot, rp->emit);
+
+ RG.totenergy+= rp->unshot[0]*rp->area;
+ RG.totenergy+= rp->unshot[1]*rp->area;
+ RG.totenergy+= rp->unshot[2]*rp->area;
+
+ rp->f= 0;
+
+ rp= rp->next;
+ }
+}
+
+void progressiverad()
+{
+ RPatch *shoot;
+ float unshot[3];
+ int it= 0;
+
+ rad_printstatus();
+ rad_init_energy();
+
+ shoot=findshootpatch();
+
+ while( shoot ) {
+
+ setnodeflags(shoot->first, RAD_SHOOT, 1);
+
+ backface_test(shoot);
+
+ drawpatch_ext(shoot, 0x88FF00);
+
+ if(shoot->first->f & RAD_TWOSIDED) {
+ VECCOPY(unshot, shoot->unshot);
+ VecMulf(shoot->norm, -1.0);
+ if(makeformfactors(shoot))
+ applyformfactors(shoot);
+ VecMulf(shoot->norm, -1.0);
+ VECCOPY(shoot->unshot, unshot);
+ }
+
+ if( makeformfactors(shoot) ) {
+ applyformfactors(shoot);
+
+ it++;
+ set_timecursor(it);
+ if( (it & 3)==1 ) {
+ make_node_display();
+ rad_forcedraw();
+ }
+ setnodeflags(shoot->first, RAD_SHOOT, 0);
+ }
+
+ clear_backface_test();
+
+ if(blender_test_break()) break;
+ if(RG.maxiter && RG.maxiter<=it) break;
+
+ shoot=findshootpatch();
+
+ }
+
+}
+
+
+/* ************* subdivideshoot *********** */
+
+void minmaxradelem(RNode *rn, float *min, float *max)
+{
+ int c;
+
+ if(rn->down1) {
+ minmaxradelem(rn->down1, min, max);
+ minmaxradelem(rn->down2, min, max);
+ }
+ else {
+ for(c=0; c<3; c++) {
+ min[c]= MIN2(min[c], rn->totrad[c]);
+ max[c]= MAX2(max[c], rn->totrad[c]);
+ }
+ }
+}
+
+void minmaxradelemfilt(RNode *rn, float *min, float *max, float *errmin, float *errmax)
+{
+ float col[3], area;
+ int c;
+
+ if(rn->down1) {
+ minmaxradelemfilt(rn->down1, min, max, errmin, errmax);
+ minmaxradelemfilt(rn->down2, min, max, errmin, errmax);
+ }
+ else {
+ VECCOPY(col, rn->totrad);
+
+ for(c=0; c<3; c++) {
+ min[c]= MIN2(min[c], col[c]);
+ max[c]= MAX2(max[c], col[c]);
+ }
+
+ VecMulf(col, 2.0);
+ area= 2.0;
+ if(rn->ed1) {
+ VecAddf(col, rn->ed1->totrad, col);
+ area+= 1.0;
+ }
+ if(rn->ed2) {
+ VecAddf(col, rn->ed2->totrad, col);
+ area+= 1.0;
+ }
+ if(rn->ed3) {
+ VecAddf(col, rn->ed3->totrad, col);
+ area+= 1.0;
+ }
+ if(rn->ed4) {
+ VecAddf(col, rn->ed4->totrad, col);
+ area+= 1.0;
+ }
+ VecMulf(col, 1.0/area);
+
+ for(c=0; c<3; c++) {
+ errmin[c]= MIN2(errmin[c], col[c]);
+ errmax[c]= MAX2(errmax[c], col[c]);
+ }
+ }
+}
+
+void setsubflagelem(RNode *rn)
+{
+
+ if(rn->down1) {
+ setsubflagelem(rn->down1);
+ setsubflagelem(rn->down2);
+ }
+ else {
+ rn->f |= RAD_SUBDIV;
+ }
+}
+
+void clearsubflagelem(RNode *rn)
+{
+
+ if(rn->down1) {
+ setsubflagelem(rn->down1);
+ setsubflagelem(rn->down2);
+ }
+ else {
+ rn->f &= ~RAD_SUBDIV;
+ }
+}
+
+void subdivideshootElements(int it)
+{
+ RPatch *rp, *shoot;
+ RNode **el, *rn;
+ float *fp, err, stoke, area, min[3], max[3], errmin[3], errmax[3];
+ int a, b, c, d, e, f, contin;
+ int maxlamp;
+
+ if(RG.maxsublamp==0) maxlamp= RG.totlamp;
+ else maxlamp= RG.maxsublamp;
+
+ while(it) {
+ rad_printstatus();
+ rad_init_energy();
+ it--;
+
+ for(a=0; a<maxlamp; a++) {
+ shoot= findshootpatch();
+ if(shoot==0) break;
+
+ set_timecursor(a);
+ drawpatch_ext(shoot, 0x88FF00);
+
+ setnodeflags(shoot->first, RAD_SHOOT, 1);
+ if( makeformfactors(shoot) ) {
+
+ fp= RG.formfactors;
+ el= RG.elem;
+ for(b=RG.totelem; b>0; b--, el++) {
+ rn= *el;
+
+ if( (rn->f & RAD_SUBDIV)==0 && *fp!=0.0) {
+ if(rn->par->emit[0]+rn->par->emit[1]+rn->par->emit[2]==0.0) {
+
+ stoke= calcStokefactor(shoot, rn->par, rn, &area);
+ if(stoke!= 0.0) {
+
+ err= *fp/stoke;
+
+ /* area error */
+ area*=(0.5*RG.hemires*RG.hemires);
+
+ if(area>35.0) {
+ if(err<0.95 || err>1.05) {
+ if(err>0.05) {
+ rn->f |= RAD_SUBDIV;
+ rn->par->f |= RAD_SUBDIV;
+ }
+ }
+ }
+ }
+
+ }
+ }
+
+ fp++;
+
+ }
+
+ applyformfactors(shoot);
+
+ if( (a & 3)==1 ) {
+ make_node_display();
+ rad_forcedraw();
+ }
+
+ setnodeflags(shoot->first, RAD_SHOOT, 0);
+ }
+ else a--;
+
+ if(blender_test_break()) break;
+ }
+
+ /* test for extreme small color change within a patch with subdivflag */
+
+ rp= RG.patchbase.first;
+
+ while(rp) {
+ if(rp->f & RAD_SUBDIV) { /* rp has elems that need subdiv */
+ /* at least 4 levels deep */
+ rn= rp->first->down1;
+ if(rn) {
+ rn= rn->down1;
+ if(rn) {
+ rn= rn->down1;
+ if(rn) rn= rn->down1;
+ }
+ }
+ if(rn) {
+ min[0]= min[1]= min[2]= 1.0e10;
+ max[0]= max[1]= max[2]= -1.0e10;
+ /* errmin and max are the filtered colors */
+ errmin[0]= errmin[1]= errmin[2]= 1.0e10;
+ errmax[0]= errmax[1]= errmax[2]= -1.0e10;
+ minmaxradelemfilt(rp->first, min, max, errmin, errmax);
+
+ /* if small difference between colors: no subdiv */
+ /* also test for the filtered ones: but with higher critical level */
+
+ contin= 0;
+ a= abs( calculatecolor(min[0])-calculatecolor(max[0]));
+ b= abs( calculatecolor(errmin[0])-calculatecolor(errmax[0]));
+ if(a<15 || b<7) {
+ c= abs( calculatecolor(min[1])-calculatecolor(max[1]));
+ d= abs( calculatecolor(errmin[1])-calculatecolor(errmax[1]));
+ if(c<15 || d<7) {
+ e= abs( calculatecolor(min[2])-calculatecolor(max[2]));
+ f= abs( calculatecolor(errmin[2])-calculatecolor(errmax[2]));
+ if(e<15 || f<7) {
+ contin= 1;
+ clearsubflagelem(rp->first);
+ /* printf("%d %d %d %d %d %d\n", a, b, c, d, e, f); */
+ }
+ }
+ }
+ if(contin) {
+ drawpatch_ext(rp, 0xFFFF);
+ }
+ }
+ }
+ rp->f &= ~RAD_SUBDIV;
+ rp= rp->next;
+ }
+
+ contin= 0;
+
+ el= RG.elem;
+ for(b=RG.totelem; b>0; b--, el++) {
+ rn= *el;
+ if(rn->f & RAD_SUBDIV) {
+ rn->f-= RAD_SUBDIV;
+ subdivideNode(rn, 0);
+ if(rn->down1) {
+ subdivideNode(rn->down1, 0);
+ subdivideNode(rn->down2, 0);
+ contin= 1;
+ }
+ }
+ }
+ makeGlobalElemArray();
+
+ if(contin==0 || blender_test_break()) break;
+ }
+
+ make_node_display();
+}
+
+void subdivideshootPatches(int it)
+{
+ RPatch *rp, *shoot, *next;
+ float *fp, err, stoke, area;
+ int a, contin;
+ int maxlamp;
+
+ if(RG.maxsublamp==0) maxlamp= RG.totlamp;
+ else maxlamp= RG.maxsublamp;
+
+ while(it) {
+ rad_printstatus();
+ rad_init_energy();
+ it--;
+
+ for(a=0; a<maxlamp; a++) {
+ shoot= findshootpatch();
+ if(shoot==0) break;
+
+ set_timecursor(a);
+ drawpatch_ext(shoot, 0x88FF00);
+
+ setnodeflags(shoot->first, RAD_SHOOT, 1);
+
+ if( makeformfactors(shoot) ) {
+
+ fp= RG.formfactors;
+ rp= RG.patchbase.first;
+ while(rp) {
+ if(*fp!=0.0 && rp!=shoot) {
+
+ stoke= calcStokefactor(shoot, rp, rp->first, &area);
+ if(stoke!= 0.0) {
+ if(area>.1) { /* does patch receive more than (about)10% of energy? */
+ rp->f= RAD_SUBDIV;
+ }
+ else {
+
+ err= *fp/stoke;
+
+ /* area error */
+ area*=(0.5*RG.hemires*RG.hemires);
+
+ if(area>45.0) {
+ if(err<0.95 || err>1.05) {
+ if(err>0.05) {
+
+ rp->f= RAD_SUBDIV;
+
+ }
+ }
+ }
+ }
+ }
+ }
+ fp++;
+
+ rp= rp->next;
+ }
+
+ applyformfactors(shoot);
+
+ if( (a & 3)==1 ) {
+ make_node_display();
+ rad_forcedraw();
+ }
+
+ setnodeflags(shoot->first, RAD_SHOOT, 0);
+
+ if(blender_test_break()) break;
+ }
+ else a--;
+
+ }
+
+ contin= 0;
+
+ rp= RG.patchbase.first;
+ while(rp) {
+ next= rp->next;
+ if(rp->f & RAD_SUBDIV) {
+ if(rp->emit[0]+rp->emit[1]+rp->emit[2]==0.0) {
+ contin= 1;
+ subdivideNode(rp->first, 0);
+ if(rp->first->down1) {
+ subdivideNode(rp->first->down1, 0);
+ subdivideNode(rp->first->down2, 0);
+ }
+ }
+ }
+ rp= next;
+ }
+
+ converttopatches();
+ makeGlobalElemArray();
+
+ if(contin==0 || blender_test_break()) break;
+ }
+ make_node_display();
+}
+
+void inithemiwindows()
+{
+ RadView *vw;
+
+ /* the hemiwindows */
+ vw= &(hemitop);
+ memset(vw, 0, sizeof(RadView));
+ vw->rectx= RG.hemires;
+ vw->recty= RG.hemires;
+ vw->rectz= MEM_mallocN(4*vw->rectx*vw->recty, "initwindows");
+ vw->rect= MEM_mallocN(4*vw->rectx*vw->recty, "initwindows");
+ vw->mynear= RG.maxsize/2000.0;
+ vw->myfar= 2.0*RG.maxsize;
+ vw->wx1= -vw->mynear;
+ vw->wx2= vw->mynear;
+ vw->wy1= -vw->mynear;
+ vw->wy2= vw->mynear;
+
+ i_window(vw->wx1, vw->wx2, vw->wy1, vw->wy2, vw->mynear, vw->myfar, vw->winmat);
+
+ hemiside= hemitop;
+
+ vw= &(hemiside);
+ vw->recty/= 2;
+ vw->wy1= vw->wy2;
+ vw->wy2= 0.0;
+
+ i_window(vw->wx1, vw->wx2, vw->wy1, vw->wy2, vw->mynear, vw->myfar, vw->winmat);
+
+}
+
+void closehemiwindows()
+{
+
+ if(hemiside.rect) MEM_freeN(hemiside.rect);
+ if(hemiside.rectz) MEM_freeN(hemiside.rectz);
+ hemiside.rectz= 0;
+ hemiside.rect= 0;
+ hemitop.rectz= 0;
+ hemitop.rect= 0;
+}
diff --git a/source/blender/radiosity/intern/source/radio.c b/source/blender/radiosity/intern/source/radio.c
new file mode 100644
index 00000000000..8d08632aedb
--- /dev/null
+++ b/source/blender/radiosity/intern/source/radio.c
@@ -0,0 +1,397 @@
+/* ***************************************
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+
+
+
+ radio.c nov/dec 1992
+ may 1999
+
+ $Id$
+
+ - mainloop
+ - interactivity
+
+
+ - PREPROCES
+ - collect meshes
+ - spitconnected (all faces with different color and normals)
+ - setedgepointers (nodes pointing to neighbours)
+
+ - EDITING
+ - min-max patch en min-max element size
+ - using this info patches subdividing
+ - lamp subdivide
+
+ - if there are too many lamps for subdivide shooting:
+ - temporal join patches
+
+ - SUBDIVIDE SHOOTING
+ - except for last shooting, this defines patch subdivide
+ - if subdivided patches still > 2*minsize : continue
+ - at the end create as many elements as possible
+ - als store if lamp (can still) cause subdivide.
+
+ - REFINEMENT SHOOTING
+ - test for overflows (shootpatch subdivide)
+ - testen for extreme color transitions:
+ - if possible: shootpatch subdivide
+ - elements subdivide = start over ?
+ - continue itterate until ?
+
+ - DEFINITIVE SHOOTING
+ - user indicates how many faces maximum and duration of itteration.
+
+ - POST PROCESS
+ - join element- nodes when nothing happens in it (filter nodes, filter faces)
+ - define gamma & mul
+
+ *************************************** */
+
+#include <math.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+#include "PIL_time.h"
+
+#include "BLI_blenlib.h"
+
+#include "DNA_object_types.h"
+#include "DNA_radio_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+
+#include "BKE_customdata.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+
+#include "BIF_screen.h" /* curarea */
+#include "BIF_space.h" /* allqueue */
+
+#include "radio.h"
+#include "mydevice.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* locals? This one was already done in radio.h... */
+/* void rad_status_str(char *str); */
+
+RadGlobal RG= {0, 0};
+
+void freeAllRad()
+{
+ Base *base;
+ extern int Ntotvert, Ntotnode, Ntotpatch;
+
+ /* clear flag that disables drawing the meshes */
+ if(G.scene) {
+ base= (G.scene->base.first);
+ while(base) {
+ if(base->object->type==OB_MESH) {
+ base->flag &= ~OB_RADIO;
+ }
+ base= base->next;
+ }
+ }
+
+ free_fastAll(); /* verts, nodes, patches */
+ RG.patchbase.first= RG.patchbase.last= 0;
+ Ntotvert= Ntotnode= Ntotpatch= 0;
+
+ closehemiwindows(); /* not real windows anymore... */
+ if(RG.elem) MEM_freeN(RG.elem);
+ RG.elem= 0;
+ if(RG.verts) MEM_freeN(RG.verts);
+ RG.verts= 0;
+ if(RG.topfactors) MEM_freeN(RG.topfactors);
+ RG.topfactors= 0;
+ if(RG.sidefactors) MEM_freeN(RG.sidefactors);
+ RG.sidefactors= 0;
+ if(RG.formfactors) MEM_freeN(RG.formfactors);
+ RG.formfactors= 0;
+ if(RG.index) MEM_freeN(RG.index);
+ RG.index= 0;
+ if(RG.facebase) {
+ init_face_tab(); /* frees all tables */
+ MEM_freeN(RG.facebase);
+ RG.facebase= 0;
+ }
+
+ if(RG.mfdata) {
+ CustomData_free(RG.mfdata, RG.mfdatatot);
+ MEM_freeN(RG.mfdata);
+ MEM_freeN(RG.mfdatanodes);
+ RG.mfdatanodes= NULL;
+ RG.mfdata= NULL;
+ RG.mfdatatot= 0;
+ }
+ RG.totelem= RG.totpatch= RG.totvert= RG.totface= RG.totlamp= RG.totmat= 0;
+}
+
+int rad_phase()
+{
+ int flag= 0;
+
+ if(RG.totpatch) flag |= RAD_PHASE_PATCHES;
+ if(RG.totface) flag |= RAD_PHASE_FACES;
+
+ return flag;
+}
+
+void rad_status_str(char *str)
+{
+ extern int totfastmem;
+ int tot;
+ char *phase;
+
+ tot= (RG.totface*sizeof(Face))/1024;
+ tot+= totfastmem/1024;
+
+ if(RG.phase==RAD_SHOOTE) phase= "Phase: ELEMENT SUBD, ";
+ else if(RG.phase==RAD_SHOOTP) phase= "Phase: PATCH SUBD, ";
+ else if(RG.phase==RAD_SOLVE) phase= "Phase: SOLVE, ";
+ else if(RG.totpatch==0) phase= "Phase: COLLECT MESHES ";
+ else if(RG.totface) phase= "Phase: FINISHED, ";
+ else phase= "Phase: INIT, ";
+
+ if(RG.totpatch==0) strcpy(str, phase);
+ else sprintf(str, "%s TotPatch: %d TotElem: %d Emit: %d Faces %d Mem: %d k ", phase, RG.totpatch, RG.totelem, RG.totlamp, RG.totface, tot);
+
+ if(RG.phase==RAD_SOLVE) strcat(str, "(press ESC to stop)");
+}
+
+void rad_printstatus()
+{
+ /* actions always are started from a buttonswindow */
+ if(curarea) {
+ scrarea_do_windraw(curarea);
+ screen_swapbuffers();
+ }
+}
+
+void rad_setlimits()
+{
+ Radio *rad= G.scene->radio;
+ float fac;
+
+ fac= 0.0005*rad->pama;
+ RG.patchmax= RG.maxsize*fac;
+ RG.patchmax*= RG.patchmax;
+ fac= 0.0005*rad->pami;
+ RG.patchmin= RG.maxsize*fac;
+ RG.patchmin*= RG.patchmin;
+
+ fac= 0.0005*rad->elma;
+ RG.elemmax= RG.maxsize*fac;
+ RG.elemmax*= RG.elemmax;
+ fac= 0.0005*rad->elmi;
+ RG.elemmin= RG.maxsize*fac;
+ RG.elemmin*= RG.elemmin;
+}
+
+void set_radglobal()
+{
+ /* always call before any action is performed */
+ Radio *rad= G.scene->radio;
+
+ if(RG.radio==0) {
+ /* firsttime and to be sure */
+ memset(&RG, 0, sizeof(RadGlobal));
+ }
+
+ if(rad==0) return;
+
+ if(rad != RG.radio) {
+ if(RG.radio) freeAllRad();
+ memset(&RG, 0, sizeof(RadGlobal));
+ RG.radio= rad;
+ }
+
+ RG.hemires= rad->hemires & 0xFFF0;
+ RG.drawtype= rad->drawtype;
+ RG.flag= rad->flag;
+ RG.subshootp= rad->subshootp;
+ RG.subshoote= rad->subshoote;
+ RG.nodelim= rad->nodelim;
+ RG.maxsublamp= rad->maxsublamp;
+ RG.maxnode= 2*rad->maxnode; /* in button:max elem, subdividing! */
+ RG.convergence= rad->convergence/1000.0;
+ RG.radfac= rad->radfac;
+ RG.gamma= rad->gamma;
+ RG.maxiter= rad->maxiter;
+
+ RG.re= NULL; /* struct render, for when call it from render engine */
+
+ rad_setlimits();
+}
+
+/* called from buttons.c */
+void add_radio()
+{
+ Radio *rad;
+
+ if(G.scene->radio) MEM_freeN(G.scene->radio);
+ rad= G.scene->radio= MEM_callocN(sizeof(Radio), "radio");
+
+ rad->hemires= 300;
+ rad->convergence= 0.1;
+ rad->radfac= 30.0;
+ rad->gamma= 2.0;
+ rad->drawtype= DTSOLID;
+ rad->subshootp= 1;
+ rad->subshoote= 2;
+ rad->maxsublamp= 0;
+
+ rad->pama= 500;
+ rad->pami= 200;
+ rad->elma= 100;
+ rad->elmi= 20;
+ rad->nodelim= 0;
+ rad->maxnode= 10000;
+ rad->maxiter= 120; // arbitrary
+ rad->flag= 2;
+ set_radglobal();
+}
+
+void delete_radio()
+{
+ freeAllRad();
+ if(G.scene->radio) MEM_freeN(G.scene->radio);
+ G.scene->radio= 0;
+
+ RG.radio= 0;
+}
+
+int rad_go(void) /* return 0 when user escapes */
+{
+ double stime= PIL_check_seconds_timer();
+ int retval;
+
+ if(RG.totface) return 0;
+
+ G.afbreek= 0;
+
+ set_radglobal();
+ initradiosity(); /* LUT's */
+ inithemiwindows(); /* views */
+
+ maxsizePatches();
+
+ setnodelimit(RG.patchmin);
+ RG.phase= RAD_SHOOTP;
+ subdivideshootPatches(RG.subshootp);
+
+ setnodelimit(RG.elemmin);
+ RG.phase= RAD_SHOOTE;
+ subdivideshootElements(RG.subshoote);
+
+ setnodelimit(RG.patchmin);
+ subdividelamps();
+
+ setnodelimit(RG.elemmin);
+
+ RG.phase= RAD_SOLVE;
+ subdiv_elements();
+
+ progressiverad();
+
+ removeEqualNodes(RG.nodelim);
+
+ make_face_tab(); /* now anchored */
+
+ closehemiwindows();
+ RG.phase= 0;
+
+ stime= PIL_check_seconds_timer()-stime;
+ printf("Radiosity solving time: %dms\n", (int) (stime*1000));
+
+ if(G.afbreek==1) retval= 1;
+ else retval= 0;
+
+ G.afbreek= 0;
+
+ return retval;
+}
+
+void rad_subdivshootpatch()
+{
+
+ if(RG.totface) return;
+
+ G.afbreek= 0;
+
+ set_radglobal();
+ initradiosity(); /* LUT's */
+ inithemiwindows(); /* views */
+
+ subdivideshootPatches(1);
+
+ removeEqualNodes(RG.nodelim);
+ closehemiwindows();
+
+ allqueue(REDRAWVIEW3D, 1);
+}
+
+void rad_subdivshootelem(void)
+{
+
+ if(RG.totface) return;
+
+ G.afbreek= 0;
+
+ set_radglobal();
+ initradiosity(); /* LUT's */
+ inithemiwindows(); /* views */
+
+ subdivideshootElements(1);
+
+ removeEqualNodes(RG.nodelim);
+ closehemiwindows();
+
+ allqueue(REDRAWVIEW3D, 1);
+}
+
+void rad_limit_subdivide()
+{
+
+ if(G.scene->radio==0) return;
+
+ set_radglobal();
+
+ if(RG.totpatch==0) {
+ /* printf("exit: no relevant data\n"); */
+ return;
+ }
+
+ maxsizePatches();
+
+ init_face_tab(); /* free faces */
+}
diff --git a/source/blender/radiosity/intern/source/radnode.c b/source/blender/radiosity/intern/source/radnode.c
new file mode 100644
index 00000000000..168ad2de725
--- /dev/null
+++ b/source/blender/radiosity/intern/source/radnode.c
@@ -0,0 +1,1106 @@
+/* ***************************************
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+
+
+
+ node.c nov/dec 1992
+ may 1999
+
+ $Id$
+
+ *************************************** */
+
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "BKE_global.h"
+#include "BKE_main.h"
+
+#include "BIF_toolbox.h"
+
+#include "radio.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* locals */
+void *malloc_fast(int size);
+void *calloc_fast(int size);
+void free_fast(void *poin, int siz);
+void deleteTriNodes(RNode *node);
+/* lower because of local type define */
+/* void check_mallocgroup(MallocGroup *mg); */
+
+
+/* ********** fastmalloc ************** */
+
+#define MAL_GROUPSIZE 256
+#define MAL_AVAILABLE 1
+#define MAL_FULL 2
+
+
+
+
+ListBase MallocBase= {0, 0};
+int totfastmem= 0;
+
+typedef struct MallocGroup {
+ struct MallocGroup *next, *prev;
+ short size, flag;
+ short curfree, tot;
+ char flags[MAL_GROUPSIZE];
+ char *data;
+} MallocGroup;
+
+/* one more local */
+void check_mallocgroup(MallocGroup *mg);
+
+void check_mallocgroup(MallocGroup *mg)
+{
+ int a;
+ char *cp;
+
+ if(mg->tot==MAL_GROUPSIZE) {
+ mg->flag= MAL_FULL;
+ return;
+ }
+
+ cp= mg->flags;
+
+ if(mg->curfree<MAL_GROUPSIZE-1) {
+ if(cp[mg->curfree+1]==0) {
+ mg->curfree++;
+ return;
+ }
+ }
+ if(mg->curfree>0) {
+ if(cp[mg->curfree-1]==0) {
+ mg->curfree--;
+ return;
+ }
+ }
+
+ for(a=0; a<MAL_GROUPSIZE; a++) {
+ if(cp[a]==0) {
+ mg->curfree= a;
+ return;
+ }
+ }
+ printf("fastmalloc: shouldnt be here\n");
+}
+
+void *malloc_fast(int size)
+{
+ MallocGroup *mg;
+ void *retval;
+
+ mg= MallocBase.last;
+ while(mg) {
+ if(mg->size==size) {
+ if(mg->flag & MAL_AVAILABLE) {
+ mg->flags[mg->curfree]= 1;
+ mg->tot++;
+ retval= mg->data+mg->curfree*mg->size;
+ check_mallocgroup(mg);
+ return retval;
+ }
+ }
+ mg= mg->prev;
+ }
+
+ /* no free block found */
+ mg= MEM_callocN(sizeof(MallocGroup), "mallocgroup");
+ BLI_addtail(&MallocBase, mg);
+ mg->data= MEM_mallocN(MAL_GROUPSIZE*size, "mallocgroupdata");
+ mg->flag= MAL_AVAILABLE;
+ mg->flags[0]= 1;
+ mg->curfree= 1;
+ mg->size= size;
+ mg->tot= 1;
+
+ totfastmem+= sizeof(MallocGroup)+MAL_GROUPSIZE*size;
+
+ return mg->data;
+}
+
+void *calloc_fast(int size)
+{
+ void *poin;
+
+ poin= malloc_fast(size);
+ memset(poin, 0, size);
+
+ return poin;
+}
+
+void free_fast(void *poin, int size)
+{
+ MallocGroup *mg;
+ long val;
+
+ mg= MallocBase.last;
+ while(mg) {
+ if(mg->size==size) {
+ if( ((long)poin) >= ((long)mg->data) ) {
+ if( ((long)poin) < ((long)(mg->data+MAL_GROUPSIZE*size)) ) {
+ val= ((long)poin) - ((long)mg->data);
+ val/= size;
+ mg->curfree= val;
+ mg->flags[val]= 0;
+ mg->flag= MAL_AVAILABLE;
+
+ mg->tot--;
+ if(mg->tot==0) {
+ BLI_remlink(&MallocBase, mg);
+ MEM_freeN(mg->data);
+ MEM_freeN(mg);
+ totfastmem-= sizeof(MallocGroup)+MAL_GROUPSIZE*size;
+ }
+ return;
+ }
+ }
+ }
+ mg= mg->prev;
+ }
+ printf("fast free: pointer not in memlist %p size %d\n",
+ poin, size);
+}
+
+/* security: only one function in a time can use it */
+static char *fastmallocstr= 0;
+
+void free_fastAll()
+{
+ MallocGroup *mg;
+
+ mg= MallocBase.first;
+ while(mg) {
+ BLI_remlink(&MallocBase, mg);
+ MEM_freeN(mg->data);
+ MEM_freeN(mg);
+ mg= MallocBase.first;
+ }
+ totfastmem= 0;
+ fastmallocstr= 0;
+}
+
+void start_fastmalloc(char *str)
+{
+ if(fastmallocstr) {
+ error("Fastmalloc in use: %s", fastmallocstr);
+ return;
+ }
+ fastmallocstr= str;
+}
+
+/* **************************************** */
+
+float nodelimit;
+
+void setnodelimit(float limit)
+{
+ nodelimit= limit;
+
+}
+
+/* ************ memory management *********** */
+
+int Ntotvert=0, Ntotnode=0, Ntotpatch=0;
+
+float *mallocVert()
+{
+ Ntotvert++;
+ return (float *)malloc_fast(16);
+}
+
+float *callocVert()
+{
+ Ntotvert++;
+ return (float *)calloc_fast(16);
+}
+
+void freeVert(float *vert)
+{
+ free_fast(vert, 16);
+ Ntotvert--;
+}
+
+int totalRadVert()
+{
+ return Ntotvert;
+}
+
+RNode *mallocNode()
+{
+ Ntotnode++;
+ return (RNode *)malloc_fast(sizeof(RNode));
+}
+
+RNode *callocNode()
+{
+ Ntotnode++;
+ return (RNode *)calloc_fast(sizeof(RNode));
+}
+
+void freeNode(RNode *node)
+{
+ free_fast(node, sizeof(RNode));
+ Ntotnode--;
+}
+
+void freeNode_recurs(RNode *node)
+{
+
+ if(node->down1) {
+ freeNode_recurs(node->down1);
+ freeNode_recurs(node->down2);
+ }
+
+ node->down1= node->down2= 0;
+ freeNode(node);
+
+}
+
+RPatch *mallocPatch()
+{
+ Ntotpatch++;
+ return (RPatch *)malloc_fast(sizeof(RPatch));
+}
+
+RPatch *callocPatch()
+{
+ Ntotpatch++;
+ return (RPatch *)calloc_fast(sizeof(RPatch));
+}
+
+void freePatch(RPatch *patch)
+{
+ free_fast(patch, sizeof(RPatch));
+ Ntotpatch--;
+}
+
+/* ************ SUBDIVIDE *********** */
+
+
+void replaceAllNode(RNode *neighb, RNode *newn)
+{
+ /* changes from all neighbours the edgepointers that point to newn->up in new */
+ int ok= 0;
+
+
+ if(neighb==0) return;
+ if(newn->up==0) return;
+
+ if(neighb->ed1==newn->up) {
+ neighb->ed1= newn;
+ ok= 1;
+ }
+ else if(neighb->ed2==newn->up) {
+ neighb->ed2= newn;
+ ok= 1;
+ }
+ else if(neighb->ed3==newn->up) {
+ neighb->ed3= newn;
+ ok= 1;
+ }
+ else if(neighb->ed4==newn->up) {
+ neighb->ed4= newn;
+ ok= 1;
+ }
+
+ if(ok && neighb->down1) {
+ replaceAllNode(neighb->down1, newn);
+ replaceAllNode(neighb->down2, newn);
+ }
+}
+
+void replaceAllNodeInv(RNode *neighb, RNode *old)
+{
+ /* changes from all neighbours the edgepointers that point to old in old->up */
+ if(neighb==0) return;
+ if(old->up==0) return;
+
+ if(neighb->ed1==old) {
+ neighb->ed1= old->up;
+ }
+ else if(neighb->ed2==old) {
+ neighb->ed2= old->up;
+ }
+ else if(neighb->ed3==old) {
+ neighb->ed3= old->up;
+ }
+ else if(neighb->ed4==old) {
+ neighb->ed4= old->up;
+ }
+
+ if(neighb->down1) {
+ replaceAllNodeInv(neighb->down1, old);
+ replaceAllNodeInv(neighb->down2, old);
+ }
+}
+
+void replaceAllNodeUp(RNode *neighb, RNode *old)
+{
+ /* changes from all neighbours the edgepointers that point to old in old->up */
+ if(neighb==0) return;
+ if(old->up==0) return;
+ neighb= neighb->up;
+ if(neighb==0) return;
+
+ if(neighb->ed1==old) {
+ neighb->ed1= old->up;
+ }
+ else if(neighb->ed2==old) {
+ neighb->ed2= old->up;
+ }
+ else if(neighb->ed3==old) {
+ neighb->ed3= old->up;
+ }
+ else if(neighb->ed4==old) {
+ neighb->ed4= old->up;
+ }
+
+ if(neighb->up) {
+ replaceAllNodeUp(neighb, old);
+ }
+}
+
+
+void replaceTestNode(RNode *neighb, RNode **edpp, RNode *newn, int level, float *vert)
+{
+ /* IF neighb->ed points to newn->up
+ * IF edgelevels equal
+ IF testvert is in neighb->ed
+ change pointers both ways
+ ELSE
+ RETURN
+ ELSE
+ IF neighb edgelevel is deeper
+ change neighb pointer
+
+ */
+ int ok= 0;
+
+ if(neighb==0) return;
+ if(newn->up==0) return;
+
+ if(neighb->ed1==newn->up) {
+ if(neighb->lev1==level) {
+ if(vert==neighb->v1 || vert==neighb->v2) {
+ *edpp= neighb;
+ neighb->ed1= newn;
+ }
+ else return;
+ }
+ else if(neighb->lev1>level) {
+ neighb->ed1= newn;
+ }
+ ok= 1;
+ }
+ else if(neighb->ed2==newn->up) {
+ if(neighb->lev2==level) {
+ if(vert==neighb->v2 || vert==neighb->v3) {
+ *edpp= neighb;
+ neighb->ed2= newn;
+ }
+ else return;
+ }
+ else if(neighb->lev2>level) {
+ neighb->ed2= newn;
+ }
+ ok= 1;
+ }
+ else if(neighb->ed3==newn->up) {
+ if(neighb->lev3==level) {
+ if(neighb->type==3) {
+ if(vert==neighb->v3 || vert==neighb->v1) {
+ *edpp= neighb;
+ neighb->ed3= newn;
+ }
+ else return;
+ }
+ else {
+ if(vert==neighb->v3 || vert==neighb->v4) {
+ *edpp= neighb;
+ neighb->ed3= newn;
+ }
+ else return;
+ }
+ }
+ else if(neighb->lev3>level) {
+ neighb->ed3= newn;
+ }
+ ok= 1;
+ }
+ else if(neighb->ed4==newn->up) {
+ if(neighb->lev4==level) {
+ if(vert==neighb->v4 || vert==neighb->v1) {
+ *edpp= neighb;
+ neighb->ed4= newn;
+ }
+ else return;
+ }
+ else if(neighb->lev4>level) {
+ neighb->ed4= newn;
+ }
+ ok= 1;
+ }
+
+ if(ok && neighb->down1) {
+ replaceTestNode(neighb->down1, edpp, newn, level, vert);
+ replaceTestNode(neighb->down2, edpp, newn, level, vert);
+ }
+
+}
+
+int setvertexpointersNode(RNode *neighb, RNode *node, int level, float **v1, float **v2)
+{
+ /* compares edgelevels , if equal it sets the vertexpointers */
+
+ if(neighb==0) return 0;
+
+ if(neighb->ed1==node) {
+ if(neighb->lev1==level) {
+ *v1= neighb->v1;
+ *v2= neighb->v2;
+ return 1;
+ }
+ }
+ else if(neighb->ed2==node) {
+ if(neighb->lev2==level) {
+ *v1= neighb->v2;
+ *v2= neighb->v3;
+ return 1;
+ }
+ }
+ else if(neighb->ed3==node) {
+ if(neighb->lev3==level) {
+ if(neighb->type==3) {
+ *v1= neighb->v3;
+ *v2= neighb->v1;
+ }
+ else {
+ *v1= neighb->v3;
+ *v2= neighb->v4;
+ }
+ return 1;
+ }
+ }
+ else if(neighb->ed4==node) {
+ if(neighb->lev4==level) {
+ *v1= neighb->v4;
+ *v2= neighb->v1;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+float edlen(float *v1, float *v2)
+{
+ return (v1[0]-v2[0])*(v1[0]-v2[0])+ (v1[1]-v2[1])*(v1[1]-v2[1])+ (v1[2]-v2[2])*(v1[2]-v2[2]);
+}
+
+
+void subdivideTriNode(RNode *node, RNode *edge)
+{
+ RNode *n1, *n2, *up;
+ float fu, fv, fl, *v1, *v2; /* , AreaT3Dfl(); ... from arithb... */
+ int uvl;
+
+ if(node->down1 || node->down2) {
+ /* printf("trinode: subd already done\n"); */
+ return;
+ }
+
+ /* defines subdivide direction */
+
+ if(edge==0) {
+ /* areathreshold */
+ if(node->area<nodelimit) return;
+
+ fu= edlen(node->v1, node->v2);
+ fv= edlen(node->v2, node->v3);
+ fl= edlen(node->v3, node->v1);
+
+ if(fu>fv && fu>fl) uvl= 1;
+ else if(fv>fu && fv>fl) uvl= 2;
+ else uvl= 3;
+ }
+ else {
+
+ if(edge==node->ed1) uvl= 1;
+ else if(edge==node->ed2) uvl= 2;
+ else uvl= 3;
+ }
+
+ /* should neighbour nodes be deeper? Recursive! */
+ n1= 0;
+ if(uvl==1) {
+ if(node->ed1 && node->ed1->down1==0) n1= node->ed1;
+ }
+ else if(uvl==2) {
+ if(node->ed2 && node->ed2->down1==0) n1= node->ed2;
+ }
+ else {
+ if(node->ed3 && node->ed3->down1==0) n1= node->ed3;
+ }
+ if(n1) {
+ up= node->up;
+ while(up) { /* also test for ed4 !!! */
+ if(n1->ed1==up || n1->ed2==up || n1->ed3==up || n1->ed4==up) {
+ subdivideNode(n1, up);
+ break;
+ }
+ up= up->up;
+ }
+ }
+
+ /* the subdividing */
+ n1= mallocNode();
+ memcpy(n1, node, sizeof(RNode));
+ n2= mallocNode();
+ memcpy(n2, node, sizeof(RNode));
+
+ n1->up= node;
+ n2->up= node;
+
+ node->down1= n1;
+ node->down2= n2;
+
+ /* subdivide edge 1 */
+ if(uvl==1) {
+
+ /* FIRST NODE gets edge 2 */
+ n1->ed3= n2;
+ n1->lev3= 0;
+ replaceAllNode(n1->ed2, n1);
+ n1->lev1++;
+ replaceTestNode(n1->ed1, &(n1->ed1), n1, n1->lev1, n1->v2);
+
+ /* SECOND NODE gets edge 3 */
+ n2->ed2= n1;
+ n2->lev2= 0;
+ replaceAllNode(n2->ed3, n2);
+ n2->lev1++;
+ replaceTestNode(n2->ed1, &(n2->ed1), n2, n2->lev1, n2->v1);
+
+ /* NEW VERTEX from edge 1 */
+ if( setvertexpointersNode(n1->ed1, n1, n1->lev1, &v1, &v2) ) { /* nodes have equal levels */
+ if(v1== n1->v2) {
+ n1->v1= v2;
+ n2->v2= v2;
+ }
+ else {
+ n1->v1= v1;
+ n2->v2= v1;
+ }
+ }
+ else {
+ n1->v1= n2->v2= mallocVert();
+ n1->v1[0]= 0.5*(node->v1[0]+ node->v2[0]);
+ n1->v1[1]= 0.5*(node->v1[1]+ node->v2[1]);
+ n1->v1[2]= 0.5*(node->v1[2]+ node->v2[2]);
+ n1->v1[3]= node->v1[3]; /* color */
+ }
+ }
+ else if(uvl==2) {
+
+ /* FIRST NODE gets edge 1 */
+ n1->ed3= n2;
+ n1->lev3= 0;
+ replaceAllNode(n1->ed1, n1);
+ n1->lev2++;
+ replaceTestNode(n1->ed2, &(n1->ed2), n1, n1->lev2, n1->v2);
+
+ /* SECOND NODE gets edge 3 */
+ n2->ed1= n1;
+ n2->lev1= 0;
+ replaceAllNode(n2->ed3, n2);
+ n2->lev2++;
+ replaceTestNode(n2->ed2, &(n2->ed2), n2, n2->lev2, n2->v3);
+
+ /* NEW VERTEX from edge 2 */
+ if( setvertexpointersNode(n1->ed2, n1, n1->lev2, &v1, &v2) ) { /* nodes have equal levels */
+ if(v1== n1->v2) {
+ n1->v3= v2;
+ n2->v2= v2;
+ }
+ else {
+ n1->v3= v1;
+ n2->v2= v1;
+ }
+ }
+ else {
+ n1->v3= n2->v2= mallocVert();
+ n1->v3[0]= 0.5*(node->v2[0]+ node->v3[0]);
+ n1->v3[1]= 0.5*(node->v2[1]+ node->v3[1]);
+ n1->v3[2]= 0.5*(node->v2[2]+ node->v3[2]);
+ n1->v3[3]= node->v1[3]; /* color */
+ }
+ }
+ else if(uvl==3) {
+
+ /* FIRST NODE gets edge 1 */
+ n1->ed2= n2;
+ n1->lev2= 0;
+ replaceAllNode(n1->ed1, n1);
+ n1->lev3++;
+ replaceTestNode(n1->ed3, &(n1->ed3), n1, n1->lev3, n1->v1);
+
+ /* SECOND NODE gets edge 2 */
+ n2->ed1= n1;
+ n2->lev1= 0;
+ replaceAllNode(n2->ed2, n2);
+ n2->lev3++;
+ replaceTestNode(n2->ed3, &(n2->ed3), n2, n2->lev3, n2->v3);
+
+ /* NEW VERTEX from edge 3 */
+ if( setvertexpointersNode(n1->ed3, n1, n1->lev3, &v1, &v2) ) { /* nodes have equal levels */
+ if(v1== n1->v1) {
+ n1->v3= v2;
+ n2->v1= v2;
+ }
+ else {
+ n1->v3= v1;
+ n2->v1= v1;
+ }
+ }
+ else {
+ n1->v3= n2->v1= mallocVert();
+ n1->v3[0]= 0.5*(node->v1[0]+ node->v3[0]);
+ n1->v3[1]= 0.5*(node->v1[1]+ node->v3[1]);
+ n1->v3[2]= 0.5*(node->v1[2]+ node->v3[2]);
+ n1->v3[3]= node->v3[3]; /* color */
+ }
+ }
+ n1->area= AreaT3Dfl(n1->v1, n1->v2, n1->v3);
+ n2->area= AreaT3Dfl(n2->v1, n2->v2, n2->v3);
+
+}
+
+
+void subdivideNode(RNode *node, RNode *edge)
+{
+ RNode *n1, *n2, *up;
+ float fu, fv, *v1, *v2;/*, AreaQ3Dfl(); ... from arithb... */
+ int uvl;
+
+ if(Ntotnode>RG.maxnode) return;
+
+ if(node->type==3) {
+ subdivideTriNode(node, edge);
+ return;
+ }
+
+ if(node->down1 || node->down2) {
+ /* printf("subdivide Node: already done \n"); */
+ return;
+ }
+
+ /* defines subdivide direction */
+
+ if(edge==0) {
+ /* areathreshold */
+ if(node->area<nodelimit) {
+ return;
+ }
+ fu= fabs(node->v1[0]- node->v2[0])+ fabs(node->v1[1]- node->v2[1]) +fabs(node->v1[2]- node->v2[2]);
+ fv= fabs(node->v1[0]- node->v4[0])+ fabs(node->v1[1]- node->v4[1]) +fabs(node->v1[2]- node->v4[2]);
+ if(fu>fv) uvl= 1;
+ else uvl= 2;
+ }
+ else {
+ if(edge==node->ed1 || edge==node->ed3) uvl= 1;
+ else uvl= 2;
+ }
+
+ /* do neighbour nodes have to be deeper? Recursive! */
+ n1= n2= 0;
+ if(uvl==1) {
+ if(node->ed1 && node->ed1->down1==0) n1= node->ed1;
+ if(node->ed3 && node->ed3->down1==0) n2= node->ed3;
+ }
+ else {
+ if(node->ed2 && node->ed2->down1==0) n1= node->ed2;
+ if(node->ed4 && node->ed4->down1==0) n2= node->ed4;
+ }
+ if(n1) {
+ up= node->up;
+ while(up) {
+ if(n1->ed1==up || n1->ed2==up || n1->ed3==up || n1->ed4==up) {
+ /* printf("recurs subd\n"); */
+ subdivideNode(n1, up);
+ break;
+ }
+ up= up->up;
+ }
+ }
+ if(n2) {
+ up= node->up;
+ while(up) {
+ if(n2->ed1==up || n2->ed2==up || n2->ed3==up || n2->ed4==up) {
+ /* printf("recurs subd\n"); */
+ subdivideNode(n2, up);
+ break;
+ }
+ up= up->up;
+ }
+ }
+
+ /* the subdividing */
+ n1= mallocNode();
+ memcpy(n1, node, sizeof(RNode));
+ n2= mallocNode();
+ memcpy(n2, node, sizeof(RNode));
+
+ n1->up= node;
+ n2->up= node;
+
+ node->down1= n1;
+ node->down2= n2;
+
+ /* subdivide edge 1 and 3 */
+ if(uvl==1) {
+
+ /* FIRST NODE gets edge 2 */
+ n1->ed4= n2;
+ n1->lev4= 0;
+ replaceAllNode(n1->ed2, n1);
+ n1->lev1++;
+ n1->lev3++;
+ replaceTestNode(n1->ed1, &(n1->ed1), n1, n1->lev1, n1->v2);
+ replaceTestNode(n1->ed3, &(n1->ed3), n1, n1->lev3, n1->v3);
+
+ /* SECOND NODE gets edge 4 */
+ n2->ed2= n1;
+ n2->lev2= 0;
+ replaceAllNode(n2->ed4, n2);
+ n2->lev1++;
+ n2->lev3++;
+ replaceTestNode(n2->ed1, &(n2->ed1), n2, n2->lev1, n2->v1);
+ replaceTestNode(n2->ed3, &(n2->ed3), n2, n2->lev3, n2->v4);
+
+ /* NEW VERTEX from edge 1 */
+ if( setvertexpointersNode(n1->ed1, n1, n1->lev1, &v1, &v2) ) { /* nodes have equal levels */
+ if(v1== n1->v2) {
+ n1->v1= v2;
+ n2->v2= v2;
+ }
+ else {
+ n1->v1= v1;
+ n2->v2= v1;
+ }
+ }
+ else {
+ n1->v1= n2->v2= mallocVert();
+ n1->v1[0]= 0.5*(node->v1[0]+ node->v2[0]);
+ n1->v1[1]= 0.5*(node->v1[1]+ node->v2[1]);
+ n1->v1[2]= 0.5*(node->v1[2]+ node->v2[2]);
+ n1->v1[3]= node->v1[3]; /* color */
+ }
+
+ /* NEW VERTEX from edge 3 */
+ if( setvertexpointersNode(n1->ed3, n1, n1->lev3, &v1, &v2) ) { /* nodes have equal levels */
+ if(v1== n1->v3) {
+ n1->v4= v2;
+ n2->v3= v2;
+ }
+ else {
+ n1->v4= v1;
+ n2->v3= v1;
+ }
+ }
+ else {
+ n1->v4= n2->v3= mallocVert();
+ n1->v4[0]= 0.5*(node->v3[0]+ node->v4[0]);
+ n1->v4[1]= 0.5*(node->v3[1]+ node->v4[1]);
+ n1->v4[2]= 0.5*(node->v3[2]+ node->v4[2]);
+ n1->v4[3]= node->v4[3]; /* color */
+ }
+ }
+ /* subdivide edge 2 and 4 */
+ else if(uvl==2) {
+
+ /* FIRST NODE gets edge 1 */
+ n1->ed3= n2;
+ n1->lev3= 0;
+ replaceAllNode(n1->ed1, n1);
+ n1->lev2++;
+ n1->lev4++;
+ replaceTestNode(n1->ed2, &(n1->ed2), n1, n1->lev2, n1->v2);
+ replaceTestNode(n1->ed4, &(n1->ed4), n1, n1->lev4, n1->v1);
+
+ /* SECOND NODE gets edge 3 */
+ n2->ed1= n1;
+ n2->lev1= 0;
+ replaceAllNode(n2->ed3, n2);
+ n2->lev2++;
+ n2->lev4++;
+ replaceTestNode(n2->ed2, &(n2->ed2), n2, n2->lev2, n2->v3);
+ replaceTestNode(n2->ed4, &(n2->ed4), n2, n2->lev4, n2->v4);
+
+ /* NEW VERTEX from edge 2 */
+ if( setvertexpointersNode(n1->ed2, n1, n1->lev2, &v1, &v2) ) { /* nodes have equal levels */
+ if(v1== n1->v2) {
+ n1->v3= v2;
+ n2->v2= v2;
+ }
+ else {
+ n1->v3= v1;
+ n2->v2= v1;
+ }
+ }
+ else {
+ n1->v3= n2->v2= mallocVert();
+ n1->v3[0]= 0.5*(node->v2[0]+ node->v3[0]);
+ n1->v3[1]= 0.5*(node->v2[1]+ node->v3[1]);
+ n1->v3[2]= 0.5*(node->v2[2]+ node->v3[2]);
+ n1->v3[3]= node->v3[3]; /* color */
+ }
+
+ /* NEW VERTEX from edge 4 */
+ if( setvertexpointersNode(n1->ed4, n1, n1->lev4, &v1, &v2) ) { /* nodes have equal levels */
+ if(v1== n1->v1) {
+ n1->v4= v2;
+ n2->v1= v2;
+ }
+ else {
+ n1->v4= v1;
+ n2->v1= v1;
+ }
+ }
+ else {
+ n1->v4= n2->v1= mallocVert();
+ n1->v4[0]= 0.5*(node->v1[0]+ node->v4[0]);
+ n1->v4[1]= 0.5*(node->v1[1]+ node->v4[1]);
+ n1->v4[2]= 0.5*(node->v1[2]+ node->v4[2]);
+ n1->v4[3]= node->v4[3]; /* color */
+ }
+ }
+
+ n1->area= AreaQ3Dfl(n1->v1, n1->v2, n1->v3, n1->v4);
+ n2->area= AreaQ3Dfl(n2->v1, n2->v2, n2->v3, n2->v4);
+
+}
+
+int comparelevel(RNode *node, RNode *nb, int level)
+{
+ /* recursive descent: test with deepest node */
+ /* return 1 means equal or higher */
+
+ if(nb==0) return 1;
+
+ if(nb->down1) {
+ return 0;
+
+ /* THERE IS AN ERROR HERE, BUT WHAT? (without this function the system
+ works too, but is slower) (ton) */
+
+ /*
+ n1= nb->down1;
+ if(n1->ed1==node) return comparelevel(node, n1, level);
+ if(n1->ed2==node) return comparelevel(node, n1, level);
+ if(n1->ed3==node) return comparelevel(node, n1, level);
+ if(n1->ed4==node) return comparelevel(node, n1, level);
+ n1= nb->down2;
+ if(n1->ed1==node) return comparelevel(node, n1, level);
+ if(n1->ed2==node) return comparelevel(node, n1, level);
+ if(n1->ed3==node) return comparelevel(node, n1, level);
+ if(n1->ed4==node) return comparelevel(node, n1, level);
+ printf(" dit kan niet ");
+ return 0;
+ */
+
+ }
+
+ if(nb->down1==0) {
+ /* if(nb->ed1==node) return (nb->lev1<=level); */
+ /* if(nb->ed2==node) return (nb->lev2<=level); */
+ /* if(nb->ed3==node) return (nb->lev3<=level); */
+ /* if(nb->ed4==node) return (nb->lev4<=level); */
+
+ return 1; /* is higher node */
+ }
+ return 1;
+}
+
+void deleteTriNodes(RNode *node) /* both children of node */
+{
+ RNode *n1, *n2;
+
+ /* if neighbour nodes are deeper: no delete */
+ /* just test 2 nodes, from the others the level doesn't change */
+
+ n1= node->down1;
+ n2= node->down2;
+
+ if(n1==0 || n2==0) return;
+
+ if(n1->down1 || n2->down1) return;
+
+ /* at the edges no subdivided node is allowed */
+
+ if(n1->ed1 && n1->ed1->down1) return;
+ if(n1->ed2 && n1->ed2->down1) return;
+ if(n1->ed3 && n1->ed3->down1) return;
+
+ if(n2->ed1 && n2->ed1->down1) return;
+ if(n2->ed2 && n2->ed2->down1) return;
+ if(n2->ed3 && n2->ed3->down1) return;
+
+ replaceAllNodeInv(n1->ed1, n1);
+ replaceAllNodeInv(n1->ed2, n1);
+ replaceAllNodeInv(n1->ed3, n1);
+
+ replaceAllNodeUp(n1->ed1, n1);
+ replaceAllNodeUp(n1->ed2, n1);
+ replaceAllNodeUp(n1->ed3, n1);
+
+ replaceAllNodeInv(n2->ed1, n2);
+ replaceAllNodeInv(n2->ed2, n2);
+ replaceAllNodeInv(n2->ed3, n2);
+
+ replaceAllNodeUp(n2->ed1, n2);
+ replaceAllNodeUp(n2->ed2, n2);
+ replaceAllNodeUp(n2->ed3, n2);
+
+ n1->down1= (RNode *)12; /* for debug */
+ n2->down1= (RNode *)12;
+
+ freeNode(n1);
+ freeNode(n2);
+ node->down1= node->down2= 0;
+
+}
+
+ /* both children of node */
+void deleteNodes(RNode *node)
+{
+ RNode *n1, *n2;
+
+ /* if neighbour nodes are deeper: no delete */
+ /* just test 2 nodes, from the others the level doesn't change */
+
+ if(node->type==3) {
+ deleteTriNodes(node);
+ return;
+ }
+
+ n1= node->down1;
+ n2= node->down2;
+
+ if(n1==0 || n2==0) return;
+
+ if(n1->down1 || n2->down1) return;
+
+ if(n1->ed3==n2) {
+
+ /* at the edges no subdivided node is allowed */
+
+ if(n1->ed1 && n1->ed1->down1) return;
+ if(n1->ed2 && n1->ed2->down1) return;
+ if(n1->ed4 && n1->ed4->down1) return;
+
+ if(n2->ed2 && n2->ed2->down1) return;
+ if(n2->ed3 && n2->ed3->down1) return;
+ if(n2->ed4 && n2->ed4->down1) return;
+
+ replaceAllNodeInv(n1->ed1, n1);
+ replaceAllNodeInv(n1->ed2, n1);
+ replaceAllNodeInv(n1->ed4, n1);
+
+ replaceAllNodeUp(n1->ed1, n1);
+ replaceAllNodeUp(n1->ed2, n1);
+ replaceAllNodeUp(n1->ed4, n1);
+
+ replaceAllNodeInv(n2->ed2, n2);
+ replaceAllNodeInv(n2->ed3, n2);
+ replaceAllNodeInv(n2->ed4, n2);
+
+ replaceAllNodeUp(n2->ed2, n2);
+ replaceAllNodeUp(n2->ed3, n2);
+ replaceAllNodeUp(n2->ed4, n2);
+
+ n1->down1= (RNode *)12; /* for debug */
+ n2->down1= (RNode *)12;
+
+ freeNode(n1);
+ freeNode(n2);
+ node->down1= node->down2= 0;
+
+ return;
+ }
+ else if(n1->ed4==n2) {
+
+ if(n1->ed1 && n1->ed1->down1) return;
+ if(n1->ed2 && n1->ed2->down1) return;
+ if(n1->ed3 && n1->ed3->down1) return;
+
+ if(n2->ed1 && n2->ed1->down1) return;
+ if(n2->ed3 && n2->ed3->down1) return;
+ if(n2->ed4 && n2->ed4->down1) return;
+
+ replaceAllNodeInv(n1->ed1, n1);
+ replaceAllNodeInv(n1->ed2, n1);
+ replaceAllNodeInv(n1->ed3, n1);
+
+ replaceAllNodeUp(n1->ed1, n1);
+ replaceAllNodeUp(n1->ed2, n1);
+ replaceAllNodeUp(n1->ed3, n1);
+
+ replaceAllNodeInv(n2->ed1, n2);
+ replaceAllNodeInv(n2->ed3, n2);
+ replaceAllNodeInv(n2->ed4, n2);
+
+ replaceAllNodeUp(n2->ed1, n2);
+ replaceAllNodeUp(n2->ed3, n2);
+ replaceAllNodeUp(n2->ed4, n2);
+
+ n1->down1= (RNode *)12; /* for debug */
+ n2->down1= (RNode *)12;
+
+ freeNode(n1);
+ freeNode(n2);
+ node->down1= node->down2= 0;
+
+ return;
+ }
+
+}
+
+
diff --git a/source/blender/radiosity/intern/source/radpostprocess.c b/source/blender/radiosity/intern/source/radpostprocess.c
new file mode 100644
index 00000000000..ec2de5f8712
--- /dev/null
+++ b/source/blender/radiosity/intern/source/radpostprocess.c
@@ -0,0 +1,832 @@
+/* ***************************************
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+
+
+
+ radpostprocess.c nov/dec 1992
+ may 1999
+
+ - faces
+ - filtering and node-limit
+ - apply to meshes
+ $Id$
+
+ *************************************** */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_ghash.h"
+#include "BIF_toolbox.h" // notice()
+
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_radio_types.h"
+
+#include "BKE_customdata.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_screen.h" /* waitcursor */
+#include "BIF_editview.h" /* deselectall */
+
+#include "BDR_editobject.h" /* delete_obj */
+
+#include "radio.h"
+
+/* locals? not. done in radio.h... */
+/* void rad_addmesh(void); */
+/* void rad_replacemesh(void); */
+
+void addaccu(register char *z, register char *t)
+{
+ register int div, mul;
+
+ mul= *t;
+ div= mul+1;
+ (*t)++;
+
+ t[1]= (mul*t[1]+z[1])/div;
+ t[2]= (mul*t[2]+z[2])/div;
+ t[3]= (mul*t[3]+z[3])/div;
+
+}
+
+void addaccuweight(register char *z, register char *t, int w)
+{
+ register int div, mul;
+
+ if(w==0) w= 1;
+
+ mul= *t;
+ div= mul+w;
+ if(div>255) return;
+ (*t)= div;
+
+ t[1]= (mul*t[1]+w*z[1])/div;
+ t[2]= (mul*t[2]+w*z[2])/div;
+ t[3]= (mul*t[3]+w*z[3])/div;
+
+}
+
+void triaweight(Face *face, int *w1, int *w2, int *w3)
+{
+ float n1[3], n2[3], n3[3], temp;
+
+ n1[0]= face->v2[0]-face->v1[0];
+ n1[1]= face->v2[1]-face->v1[1];
+ n1[2]= face->v2[2]-face->v1[2];
+ n2[0]= face->v3[0]-face->v2[0];
+ n2[1]= face->v3[1]-face->v2[1];
+ n2[2]= face->v3[2]-face->v2[2];
+ n3[0]= face->v1[0]-face->v3[0];
+ n3[1]= face->v1[1]-face->v3[1];
+ n3[2]= face->v1[2]-face->v3[2];
+ Normalize(n1);
+ Normalize(n2);
+ Normalize(n3);
+ temp= 32.0/(PI);
+ *w1= 0.5+temp*acos(-n1[0]*n3[0]-n1[1]*n3[1]-n1[2]*n3[2]);
+ *w2= 0.5+temp*acos(-n1[0]*n2[0]-n1[1]*n2[1]-n1[2]*n2[2]);
+ *w3= 0.5+temp*acos(-n2[0]*n3[0]-n2[1]*n3[1]-n2[2]*n3[2]);
+
+}
+
+
+
+void init_face_tab()
+{
+ int a= 0;
+
+ if(RG.facebase==0) {
+ RG.facebase= MEM_callocN(sizeof(void *)*RAD_MAXFACETAB, "init_face_tab");
+ }
+ for(a=0; a<RAD_MAXFACETAB; a++) {
+ if(RG.facebase[a]==0) break;
+ MEM_freeN(RG.facebase[a]);
+ RG.facebase[a]= 0;
+ }
+ RG.totface= 0;
+}
+
+Face *addface()
+{
+ Face *face;
+ int a;
+
+ if(RG.totface<0 || RG.totface>RAD_MAXFACETAB*1024 ) {
+ printf("error in addface: %d\n", RG.totface);
+ return 0;
+ }
+ a= RG.totface>>10;
+ face= RG.facebase[a];
+ if(face==0) {
+ face= MEM_callocN(1024*sizeof(Face),"addface");
+ RG.facebase[a]= face;
+ }
+ face+= (RG.totface & 1023);
+
+ RG.totface++;
+
+ return face;
+
+}
+
+Face * makeface(float *v1, float *v2, float *v3, float *v4, RNode *rn)
+{
+ Face *face;
+
+ face= addface();
+ face->v1= v1;
+ face->v2= v2;
+ face->v3= v3;
+ face->v4= v4;
+ face->col= rn->col;
+ face->matindex= rn->par->matindex;
+ face->orig= rn->orig;
+
+ return face;
+}
+
+void anchorQuadface(RNode *rn, float *v1, float *v2, float *v3, float *v4, int flag)
+{
+ Face *face;
+
+ switch(flag) {
+ case 1:
+ face = makeface(rn->v1, v1, rn->v4, NULL, rn);
+ face = makeface(v1, rn->v3, rn->v4, NULL, rn);
+ face = makeface(v1, rn->v2, rn->v3, NULL, rn);
+ break;
+ case 2:
+ face = makeface(rn->v2, v2, rn->v1, NULL, rn);
+ face = makeface(v2, rn->v4, rn->v1, NULL, rn);
+ face = makeface(v2, rn->v3, rn->v4, NULL, rn);
+ break;
+ case 4:
+ face = makeface(rn->v3, v3, rn->v2, NULL, rn);
+ face = makeface(v3, rn->v1, rn->v2, NULL, rn);
+ face = makeface(v3, rn->v4, rn->v1, NULL, rn);
+ break;
+ case 8:
+ face = makeface(rn->v4, v4, rn->v3, NULL, rn);
+ face = makeface(v4, rn->v2, rn->v3, NULL, rn);
+ face = makeface(v4, rn->v1, rn->v2, NULL, rn);
+ break;
+ case 3:
+ face = makeface(rn->v1, v1, rn->v4, NULL, rn);
+ face = makeface(v1, v2, rn->v4, NULL, rn);
+ face = makeface(v1, rn->v2, v2, NULL, rn);
+ face = makeface(v2, rn->v3, rn->v4, NULL, rn);
+ break;
+ case 6:
+ face = makeface(rn->v2, v2, rn->v1, NULL, rn);
+ face = makeface(v2, v3, rn->v1, NULL, rn);
+ face = makeface(v2, rn->v3, v3, NULL, rn);
+ face = makeface(v3, rn->v4, rn->v1, NULL, rn);
+ break;
+ case 12:
+ face = makeface(rn->v3, v3, rn->v2, NULL, rn);
+ face = makeface(v3, v4, rn->v2, NULL, rn);
+ face = makeface(v3, rn->v4, v4, NULL, rn);
+ face = makeface(v4, rn->v1, rn->v2, NULL, rn);
+ break;
+ case 9:
+ face = makeface(rn->v4, v4, rn->v3, NULL, rn);
+ face = makeface(v4, v1, rn->v3, NULL, rn);
+ face = makeface(v4, rn->v1, v1, NULL, rn);
+ face = makeface(v1, rn->v2, rn->v3, NULL, rn);
+ break;
+ case 5:
+ face = makeface(rn->v1, v1, v3, rn->v4, rn);
+ face = makeface(v1, rn->v2, rn->v3, v3, rn);
+ break;
+ case 10:
+ face = makeface(rn->v1, rn->v2, v2, v4, rn);
+ face = makeface(v4, v2, rn->v3, rn->v4, rn);
+ break;
+ case 7:
+ face = makeface(rn->v1, v1, v3, rn->v4, rn);
+ face = makeface(v1, v2, v3, NULL, rn);
+ face = makeface(v1, rn->v2, v2, NULL, rn);
+ face = makeface(v2, rn->v3, v3, NULL, rn);
+ break;
+ case 14:
+ face = makeface(rn->v2, v2, v4, rn->v1, rn);
+ face = makeface(v2, v3, v4, NULL, rn);
+ face = makeface(v2, rn->v3, v3, NULL, rn);
+ face = makeface(v3, rn->v4, v4, NULL, rn);
+ break;
+ case 13:
+ face = makeface(rn->v3, v3, v1, rn->v2, rn);
+ face = makeface(v3, v4, v1, NULL, rn);
+ face = makeface(v3, rn->v4, v4, NULL, rn);
+ face = makeface(v4, rn->v1, v1, NULL, rn);
+ break;
+ case 11:
+ face = makeface(rn->v4, v4, v2, rn->v3, rn);
+ face = makeface(v4, v1, v2, NULL, rn);
+ face = makeface(v4, rn->v1, v1, NULL, rn);
+ face = makeface(v1, rn->v2, v2, NULL, rn);
+ break;
+ case 15:
+ face = makeface(v1, v2, v3, v4, rn);
+ face = makeface(v1, rn->v2, v2, NULL, rn);
+ face = makeface(v2, rn->v3, v3, NULL, rn);
+ face = makeface(v3, rn->v4, v4, NULL, rn);
+ face = makeface(v4, rn->v1, v1, NULL, rn);
+ break;
+ }
+}
+
+void anchorTriface(RNode *rn, float *v1, float *v2, float *v3, int flag)
+{
+ Face *face;
+
+ switch(flag) {
+ case 1:
+ face = makeface(rn->v1, v1, rn->v3, NULL, rn);
+ face = makeface(v1, rn->v2, rn->v3, NULL, rn);
+ break;
+ case 2:
+ face = makeface(rn->v2, v2, rn->v1, NULL, rn);
+ face = makeface(v2, rn->v3, rn->v1, NULL, rn);
+ break;
+ case 4:
+ face = makeface(rn->v3, v3, rn->v2, NULL, rn);
+ face = makeface(v3, rn->v1, rn->v2, NULL, rn);
+ break;
+ case 3:
+ face = makeface(rn->v1, v2, rn->v3, NULL, rn);
+ face = makeface(rn->v1, v1, v2, NULL, rn);
+ face = makeface(v1, rn->v2, v2, NULL, rn);
+ break;
+ case 6:
+ face = makeface(rn->v2, v3, rn->v1, NULL, rn);
+ face = makeface(rn->v2, v2, v3, NULL, rn);
+ face = makeface(v2, rn->v3, v3, NULL, rn);
+ break;
+ case 5:
+ face = makeface(rn->v3, v1, rn->v2, NULL, rn);
+ face = makeface(rn->v3, v3, v1, NULL, rn);
+ face = makeface(v3, rn->v1, v1, NULL, rn);
+ break;
+
+ case 7:
+ face = makeface(v1, v2, v3, NULL, rn);
+ face = makeface(rn->v1, v1, v3, NULL, rn);
+ face = makeface(rn->v2, v2, v1, NULL, rn);
+ face = makeface(rn->v3, v3, v2, NULL, rn);
+ break;
+ }
+}
+
+
+float *findmiddlevertex(RNode *node, RNode *nb, float *v1, float *v2)
+{
+ int test= 0;
+
+ if(nb==0) return 0;
+
+ if(nb->ed1==node) {
+ if(nb->v1==v1 || nb->v1==v2) test++;
+ if(nb->v2==v1 || nb->v2==v2) test+=2;
+ if(test==1) return nb->v2;
+ else if(test==2) return nb->v1;
+ }
+ else if(nb->ed2==node) {
+ if(nb->v2==v1 || nb->v2==v2) test++;
+ if(nb->v3==v1 || nb->v3==v2) test+=2;
+ if(test==1) return nb->v3;
+ else if(test==2) return nb->v2;
+ }
+ else if(nb->ed3==node) {
+ if(nb->type==4) {
+ if(nb->v3==v1 || nb->v3==v2) test++;
+ if(nb->v4==v1 || nb->v4==v2) test+=2;
+ if(test==1) return nb->v4;
+ else if(test==2) return nb->v3;
+ }
+ else {
+ if(nb->v3==v1 || nb->v3==v2) test++;
+ if(nb->v1==v1 || nb->v1==v2) test+=2;
+ if(test==1) return nb->v1;
+ else if(test==2) return nb->v3;
+ }
+ }
+ else if(nb->ed4==node) {
+ if(nb->v4==v1 || nb->v4==v2) test++;
+ if(nb->v1==v1 || nb->v1==v2) test+=2;
+ if(test==1) return nb->v1;
+ else if(test==2) return nb->v4;
+ }
+ return 0;
+}
+
+void make_face_tab() /* takes care of anchoring */
+{
+ RNode *rn, **el;
+ Face *face = NULL;
+ float *v1, *v2, *v3, *v4;
+ int a, flag, w1, w2, w3;
+ char *charcol;
+
+ if(RG.totelem==0) return;
+
+ init_face_tab();
+
+ RG.igamma= 1.0/RG.gamma;
+ RG.radfactor= RG.radfac*pow(64*64, RG.igamma);
+
+ /* convert face colors */
+ el= RG.elem;
+ for(a=RG.totelem; a>0; a--, el++) {
+ rn= *el;
+ charcol= (char *)&( rn->col );
+
+ charcol[3]= calculatecolor(rn->totrad[0]);
+ charcol[2]= calculatecolor(rn->totrad[1]);
+ charcol[1]= calculatecolor(rn->totrad[2]);
+ }
+
+ /* check nodes and make faces */
+ el= RG.elem;
+ for(a=RG.totelem; a>0; a--, el++) {
+
+ rn= *el;
+
+ rn->v1[3]= 0.0;
+ rn->v2[3]= 0.0;
+ rn->v3[3]= 0.0;
+ if(rn->v4) rn->v4[3]= 0.0;
+
+ /* test edges for subdivide */
+ flag= 0;
+ v1= v2= v3= v4= 0;
+ if(rn->ed1) {
+ v1= findmiddlevertex(rn, rn->ed1->down1, rn->v1, rn->v2);
+ if(v1) flag |= 1;
+ }
+ if(rn->ed2) {
+ v2= findmiddlevertex(rn, rn->ed2->down1, rn->v2, rn->v3);
+ if(v2) flag |= 2;
+ }
+ if(rn->ed3) {
+ if(rn->type==4)
+ v3= findmiddlevertex(rn, rn->ed3->down1, rn->v3, rn->v4);
+ else
+ v3= findmiddlevertex(rn, rn->ed3->down1, rn->v3, rn->v1);
+ if(v3) flag |= 4;
+ }
+ if(rn->ed4) {
+ v4= findmiddlevertex(rn, rn->ed4->down1, rn->v4, rn->v1);
+ if(v4) flag |= 8;
+ }
+
+ /* using flag and vertexpointers now Faces can be made */
+
+ if(flag==0) {
+ makeface(rn->v1, rn->v2, rn->v3, rn->v4, rn);
+ }
+ else if(rn->type==4) anchorQuadface(rn, v1, v2, v3, v4, flag);
+ else anchorTriface(rn, v1, v2, v3, flag);
+ }
+
+ /* add */
+ for(a=0; a<RG.totface; a++) {
+
+ RAD_NEXTFACE(a);
+
+ if(face->v4) {
+ addaccuweight( (char *)&(face->col), (char *)(face->v1+3), 16 );
+ addaccuweight( (char *)&(face->col), (char *)(face->v2+3), 16 );
+ addaccuweight( (char *)&(face->col), (char *)(face->v3+3), 16 );
+ addaccuweight( (char *)&(face->col), (char *)(face->v4+3), 16 );
+ }
+ else {
+ triaweight(face, &w1, &w2, &w3);
+ addaccuweight( (char *)&(face->col), (char *)(face->v1+3), w1 );
+ addaccuweight( (char *)&(face->col), (char *)(face->v2+3), w2 );
+ addaccuweight( (char *)&(face->col), (char *)(face->v3+3), w3 );
+ }
+ }
+
+}
+
+void filterFaces()
+{
+ /* put vertex colors in faces, and put them back */
+
+ Face *face = NULL;
+ int a, w1, w2, w3;
+
+ if(RG.totface==0) return;
+
+ /* clear */
+ for(a=0; a<RG.totface; a++) {
+ RAD_NEXTFACE(a);
+ face->col= 0;
+ }
+
+ /* add: vertices with faces */
+ for(a=0; a<RG.totface; a++) {
+ RAD_NEXTFACE(a);
+
+ if(face->v4) {
+ addaccuweight( (char *)(face->v1+3), (char *)&(face->col), 16 );
+ addaccuweight( (char *)(face->v2+3), (char *)&(face->col), 16 );
+ addaccuweight( (char *)(face->v3+3), (char *)&(face->col), 16 );
+ addaccuweight( (char *)(face->v4+3), (char *)&(face->col), 16 );
+ }
+ else {
+ triaweight(face, &w1, &w2, &w3);
+ addaccuweight( (char *)(face->v1+3), (char *)&(face->col), w1 );
+ addaccuweight( (char *)(face->v2+3), (char *)&(face->col), w2 );
+ addaccuweight( (char *)(face->v3+3), (char *)&(face->col), w3 );
+ }
+ }
+
+ /* clear */
+ for(a=0; a<RG.totface; a++) {
+ RAD_NEXTFACE(a);
+ face->v1[3]= 0.0;
+ face->v2[3]= 0.0;
+ face->v3[3]= 0.0;
+ if(face->v4) face->v4[3]= 0.0;
+ }
+
+
+ /* add: faces with vertices */
+ for(a=0; a<RG.totface; a++) {
+
+ RAD_NEXTFACE(a);
+
+ if(face->v4) {
+ addaccuweight( (char *)&(face->col), (char *)(face->v1+3), 16 );
+ addaccuweight( (char *)&(face->col), (char *)(face->v2+3), 16 );
+ addaccuweight( (char *)&(face->col), (char *)(face->v3+3), 16 );
+ addaccuweight( (char *)&(face->col), (char *)(face->v4+3), 16 );
+ }
+ else {
+ triaweight(face, &w1, &w2, &w3);
+ addaccuweight( (char *)&(face->col), (char *)(face->v1+3), w1 );
+ addaccuweight( (char *)&(face->col), (char *)(face->v2+3), w2 );
+ addaccuweight( (char *)&(face->col), (char *)(face->v3+3), w3 );
+ }
+ }
+}
+
+void calcfiltrad(RNode *rn, float *cd)
+{
+ float area;
+
+ cd[0]= 2.0*rn->totrad[0];
+ cd[1]= 2.0*rn->totrad[1];
+ cd[2]= 2.0*rn->totrad[2];
+ area= 2.0;
+
+ if(rn->ed1) {
+ cd[0]+= rn->ed1->totrad[0];
+ cd[1]+= rn->ed1->totrad[1];
+ cd[2]+= rn->ed1->totrad[2];
+ area+= 1.0;
+ }
+ if(rn->ed2) {
+ cd[0]+= rn->ed2->totrad[0];
+ cd[1]+= rn->ed2->totrad[1];
+ cd[2]+= rn->ed2->totrad[2];
+ area+= 1.0;
+ }
+ if(rn->ed3) {
+ cd[0]+= rn->ed3->totrad[0];
+ cd[1]+= rn->ed3->totrad[1];
+ cd[2]+= rn->ed3->totrad[2];
+ area+= 1.0;
+ }
+ if(rn->ed4) {
+ cd[0]+= rn->ed4->totrad[0];
+ cd[1]+= rn->ed4->totrad[1];
+ cd[2]+= rn->ed4->totrad[2];
+ area+= 1.0;
+ }
+ cd[0]/= area;
+ cd[1]/= area;
+ cd[2]/= area;
+
+}
+
+void filterNodes()
+{
+ /* colors from nodes in tempblock and back */
+
+ RNode *rn, **el;
+ float *coldata, *cd;
+ int a;
+
+ if(RG.totelem==0) return;
+ /* the up-nodes need a color */
+ el= RG.elem;
+ for(a=0; a<RG.totelem; a++, el++) {
+ rn= *el;
+ if(rn->up) {
+ rn->up->totrad[0]= 0.0;
+ rn->up->totrad[1]= 0.0;
+ rn->up->totrad[2]= 0.0;
+ if(rn->up->up) {
+ rn->up->up->totrad[0]= 0.0;
+ rn->up->up->totrad[1]= 0.0;
+ rn->up->up->totrad[2]= 0.0;
+ }
+ }
+ }
+ el= RG.elem;
+ for(a=0; a<RG.totelem; a++, el++) {
+ rn= *el;
+ if(rn->up) {
+ rn->up->totrad[0]+= 0.5*rn->totrad[0];
+ rn->up->totrad[1]+= 0.5*rn->totrad[1];
+ rn->up->totrad[2]+= 0.5*rn->totrad[2];
+ if(rn->up->up) {
+ rn->up->up->totrad[0]+= 0.25*rn->totrad[0];
+ rn->up->up->totrad[1]+= 0.25*rn->totrad[1];
+ rn->up->up->totrad[2]+= 0.25*rn->totrad[2];
+ }
+ }
+ }
+
+ /* add using area */
+ cd= coldata= MEM_mallocN(3*4*RG.totelem, "filterNodes");
+ el= RG.elem;
+ for(a=0; a<RG.totelem; a++, el++) {
+ calcfiltrad(*el, cd);
+ cd+= 3;
+ }
+
+ cd= coldata;
+ el= RG.elem;
+ for(a=0; a<RG.totelem; a++, el++) {
+ rn= *el;
+ VECCOPY(rn->totrad, cd);
+ cd+= 3;
+ }
+ MEM_freeN(coldata);
+}
+
+void removeEqualNodes(short limit)
+{
+ /* nodes with equal colors: remove */
+ RNode **el, *rn, *rn1;
+ float thresh, f1, f2;
+ int a, foundone=1, ok;
+ int c1, c2;
+
+ if(limit==0) return;
+
+ thresh= 1.0/(256.0*RG.radfactor);
+ thresh= 3.0*pow(thresh, RG.gamma);
+
+ waitcursor(1);
+
+ while(foundone) {
+ foundone= 0;
+
+ el= RG.elem;
+ for(a=RG.totelem; a>1; a--, el++) {
+ rn= *el;
+ rn1= *(el+1);
+
+ if(rn!=rn->par->first && rn1!=rn1->par->first) {
+ if(rn->up && rn->up==rn1->up) {
+ f1= rn->totrad[0]+ rn->totrad[1]+ rn->totrad[2];
+ f2= rn1->totrad[0]+ rn1->totrad[1]+ rn1->totrad[2];
+
+ ok= 0;
+ if(f1<thresh && f2<thresh) ok= 1;
+ else {
+ c1= calculatecolor(rn->totrad[0]);
+ c2= calculatecolor(rn1->totrad[0]);
+
+ if( abs(c1-c2)<=limit ) {
+ c1= calculatecolor(rn->totrad[1]);
+ c2= calculatecolor(rn1->totrad[1]);
+
+ if( abs(c1-c2)<=limit ) {
+ c1= calculatecolor(rn->totrad[2]);
+ c2= calculatecolor(rn1->totrad[2]);
+
+ if( abs(c1-c2)<=limit ) {
+ ok= 1;
+ }
+ }
+ }
+ }
+
+ if(ok) {
+ rn->up->totrad[0]= 0.5f*(rn->totrad[0]+rn1->totrad[0]);
+ rn->up->totrad[1]= 0.5f*(rn->totrad[1]+rn1->totrad[1]);
+ rn->up->totrad[2]= 0.5f*(rn->totrad[2]+rn1->totrad[2]);
+ rn1= rn->up;
+ deleteNodes(rn1);
+ if(rn1->down1) ;
+ else {
+ foundone++;
+ a--; el++;
+ }
+ }
+ }
+ }
+ }
+ if(foundone) {
+ makeGlobalElemArray();
+ }
+ }
+ waitcursor(0);
+}
+
+unsigned int rad_find_or_add_mvert(Mesh *me, MFace *mf, RNode *orignode, float *w, float *radco, GHash *hash)
+{
+ MVert *mvert = BLI_ghash_lookup(hash, radco);
+
+ if(!mvert) {
+ mvert = &me->mvert[me->totvert];
+ VECCOPY(mvert->co, radco);
+ me->totvert++;
+
+ BLI_ghash_insert(hash, radco, mvert);
+ }
+
+ InterpWeightsQ3Dfl(orignode->v1, orignode->v2, orignode->v3,
+ orignode->v4, mvert->co, w);
+
+ return (unsigned int)(mvert - me->mvert);
+}
+
+void rad_addmesh(void)
+{
+ Face *face = NULL;
+ Object *ob;
+ Mesh *me;
+ MVert *mvert;
+ MFace *mf;
+ RNode *node;
+ Material *ma=0;
+ GHash *verthash;
+ unsigned int *mcol;
+ float cent[3], min[3], max[3], w[4][4];
+ int a;
+
+ if(RG.totface==0)
+ return;
+
+ if(RG.totmat==MAXMAT)
+ notice("warning: cannot assign more than 16 materials to 1 mesh");
+
+ /* create the mesh */
+ ob= add_object(OB_MESH);
+
+ me= ob->data;
+ me->totvert= totalRadVert();
+ me->totface= RG.totface;
+ me->flag= 0;
+
+ CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, me->totvert);
+ CustomData_add_layer(&me->fdata, CD_MFACE, CD_CALLOC, NULL, me->totface);
+ CustomData_add_layer(&me->fdata, CD_MCOL, CD_CALLOC, NULL, me->totface);
+
+ CustomData_merge(RG.mfdata, &me->fdata, CD_MASK_MESH, CD_CALLOC, me->totface);
+ mesh_update_customdata_pointers(me);
+
+ /* create materials and set vertex color flag */
+ for(a=0; a<RG.totmat; a++) {
+ assign_material(ob, RG.matar[a], a+1);
+ ma= RG.matar[a];
+ if(ma) ma->mode |= MA_VERTEXCOL;
+ }
+
+ /* create vertices and faces in one go, adding vertices to the end of the
+ mvert array if they were not added already */
+ me->totvert= 0;
+ verthash= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
+
+ mcol= (unsigned int*)me->mcol;
+ mf= me->mface;
+
+ for(a=0; a<me->totface; a++, mf++, mcol+=4) {
+ RAD_NEXTFACE(a);
+
+ /* the original node that this node is a subnode of */
+ node= RG.mfdatanodes[face->orig];
+
+ /* set mverts from the radio data, and compute interpolation weights */
+ mf->v1= rad_find_or_add_mvert(me, mf, node, w[0], face->v1, verthash);
+ mf->v2= rad_find_or_add_mvert(me, mf, node, w[1], face->v2, verthash);
+ mf->v3= rad_find_or_add_mvert(me, mf, node, w[2], face->v3, verthash);
+ if(face->v4)
+ mf->v4= rad_find_or_add_mvert(me, mf, node, w[3], face->v4, verthash);
+
+ /* copy face and interpolate data */
+ mf->mat_nr= face->matindex;
+
+ CustomData_copy_data(RG.mfdata, &me->fdata, face->orig, a, 1);
+ CustomData_interp(RG.mfdata, &me->fdata, &face->orig, NULL, (float*)w, 1, a);
+
+ /* load face vertex colors, with alpha added */
+ mcol[0]= *((unsigned int*)face->v1+3) | 0x1000000;
+ mcol[1]= *((unsigned int*)face->v2+3) | 0x1000000;
+ mcol[2]= *((unsigned int*)face->v3+3) | 0x1000000;
+ if(face->v4)
+ mcol[3]= *((unsigned int*)face->v4+3) | 0x1000000;
+
+ /* reorder face indices if needed to make face->v4 == 0 */
+ test_index_face(mf, &me->fdata, a, face->v4? 4: 3);
+ }
+
+ BLI_ghash_free(verthash, NULL, NULL);
+
+ /* boundbox and center new */
+ INIT_MINMAX(min, max);
+
+ mvert= me->mvert;
+ for(a=0; a<me->totvert; a++, mvert++) {
+ DO_MINMAX(mvert->co, min, max);
+ }
+
+ cent[0]= (min[0]+max[0])/2.0f;
+ cent[1]= (min[1]+max[1])/2.0f;
+ cent[2]= (min[2]+max[2])/2.0f;
+
+ mvert= me->mvert;
+ for(a=0; a<me->totvert; a++, mvert++) {
+ VecSubf(mvert->co, mvert->co, cent);
+ }
+
+ VECCOPY(ob->loc, cent);
+
+ /* create edges */
+ make_edges(me, 0);
+}
+
+void rad_replacemesh(void)
+{
+ RPatch *rp;
+
+ deselectall();
+
+ rp= RG.patchbase.first;
+ while(rp) {
+ if( exist_object(rp->from)) {
+ if (rp->from->type == OB_MESH) {
+ rp->from->flag |= SELECT;
+ }
+ }
+ rp= rp->next;
+ }
+
+ copy_objectflags();
+ delete_obj(1);
+
+ rad_addmesh();
+}
+
diff --git a/source/blender/radiosity/intern/source/radpreprocess.c b/source/blender/radiosity/intern/source/radpreprocess.c
new file mode 100644
index 00000000000..0fef1414482
--- /dev/null
+++ b/source/blender/radiosity/intern/source/radpreprocess.c
@@ -0,0 +1,842 @@
+ /* ***************************************
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+
+
+
+ preproces.c nov/dec 1992
+ may 1999
+
+ - collect from meshes
+ - countglobaldata()
+ - makeGlobalElemArray()
+
+ $Id$
+
+ *************************************** */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_customdata.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h" /* during_script() */
+#include "BKE_utildefines.h"
+
+#include "BIF_toolbox.h"
+
+#include "BDR_editface.h"
+
+#include "radio.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+void setparelem(RNode *rn, RPatch *par);
+
+void splitconnected()
+{
+ /* Since input meshes can have faces with sharing vertices, the geometry is being tested here.
+ * Using normals and colors, faces are split separately. we do this by storing for each
+ * vertex a normal and a color
+ */
+ RPatch *rp;
+ RNode *rn;
+ VeNoCo *vnc, *next, *vnc1;
+ int a;
+
+ /* test if we need a split */
+
+ rp= RG.patchbase.first;
+ while(rp) {
+ rn= rp->first;
+ if((rp->f1 & RAD_NO_SPLIT)==0) {
+ for(a=0; a<rp->type; a++) {
+
+ if(a==0) vnc= (VeNoCo *)rn->v1;
+ else if(a==1) vnc= (VeNoCo *)rn->v2;
+ else if(a==2) vnc= (VeNoCo *)rn->v3;
+ else vnc= (VeNoCo *)rn->v4;
+
+ if(vnc->flag==0) {
+ vnc->n= (float *)rp->norm;
+ vnc->col= (float *)rp->ref;
+ vnc->flag= 1;
+ }
+ else { /* is face from this vertex allowed for gouraud? */
+ vnc1= vnc;
+ while(vnc1) {
+ if(VecCompare(vnc1->n, rp->norm, 0.01f)) {
+ if(VecCompare(vnc1->col, rp->ref, 0.01f)) {
+ break;
+ }
+ }
+ vnc= vnc1;
+ vnc1= vnc1->next;
+ }
+ if(vnc1==0) {
+ vnc1= MEM_mallocN(sizeof(VeNoCo), "splitconn");
+ vnc1->next= 0;
+ vnc1->v= mallocVert();
+ vnc->next= vnc1;
+ VECCOPY(vnc1->v, vnc->v);
+ vnc1->n= (float *)rp->norm;
+ vnc1->col= (float *)rp->ref;
+ }
+ if(a==0) rn->v1= (float *)vnc1;
+ else if(a==1) rn->v2= (float *)vnc1;
+ else if(a==2) rn->v3= (float *)vnc1;
+ else rn->v4= (float *)vnc1;
+ }
+ }
+ }
+ rp= rp->next;
+ }
+ /* adapt vertexpointers from nodes */
+
+ rp= RG.patchbase.first;
+ while(rp) {
+ rn= rp->first;
+ rn->v1= ((VeNoCo *)(rn->v1))->v;
+ rn->v2= ((VeNoCo *)(rn->v2))->v;
+ rn->v3= ((VeNoCo *)(rn->v3))->v;
+ if(rp->type==4) rn->v4= ((VeNoCo *)(rn->v4))->v;
+
+ rp= rp->next;
+ }
+
+
+ /* free all */
+ vnc= RG.verts;
+ for(a=0; a<RG.totvert; a++) {
+ vnc1= vnc->next;
+ while(vnc1) {
+ next= vnc1->next;
+ MEM_freeN(vnc1);
+ vnc1= next;
+ }
+ vnc++;
+ }
+ MEM_freeN(RG.verts);
+ RG.verts= 0;
+}
+
+int vergedge(const void *v1,const void *v2)
+{
+ int *e1, *e2;
+
+ e1= (int *)v1;
+ e2= (int *)v2;
+
+ if( e1[0] > e2[0] ) return 1;
+ else if( e1[0] < e2[0] ) return -1;
+ else if( e1[1] > e2[1] ) return 1;
+ else if( e1[1] < e2[1] ) return -1;
+
+ return 0;
+}
+
+
+void addedge(float *v1, float *v2, EdSort *es)
+{
+ if( ((long)v1)<((long)v2) ) {
+ es->v1= v1;
+ es->v2= v2;
+ }
+ else {
+ es->v2= v1;
+ es->v1= v2;
+ }
+}
+
+static void setedge(RNode *node, RNode *nb, int nr, int nrb)
+{
+ switch(nr) {
+ case 1:
+ node->ed1= nb;
+ break;
+ case 2:
+ node->ed2= nb;
+ break;
+ case 3:
+ node->ed3= nb;
+ break;
+ case 4:
+ node->ed4= nb;
+ break;
+ }
+ switch(nrb) {
+ case 1:
+ nb->ed1= node;
+ break;
+ case 2:
+ nb->ed2= node;
+ break;
+ case 3:
+ nb->ed3= node;
+ break;
+ case 4:
+ nb->ed4= node;
+ break;
+ }
+}
+
+void setedgepointers()
+{
+ /* make edge-array and sort it */
+ /* pairs of edges are put together: fill in pointers in nodes */
+ EdSort *es, *esblock;
+ RPatch *rp;
+ RNode *rn;
+ int tot= 0;
+
+ rp= RG.patchbase.first;
+ while(rp) {
+ tot+= rp->type;
+ rp= rp->next;
+ }
+
+ if(tot==0) return;
+
+ es=esblock= MEM_mallocN(tot*sizeof(EdSort), "setedgepointers");
+ rp= RG.patchbase.first;
+ while(rp) {
+ rn= rp->first;
+ addedge(rn->v1, rn->v2, es);
+ es->nr= 1;
+ es->node= rn;
+ es++;
+ addedge(rn->v2, rn->v3, es);
+ es->nr= 2;
+ es->node= rn;
+ es++;
+ if(rp->type==3) {
+ addedge(rn->v3, rn->v1, es);
+ es->nr= 3;
+ es->node= rn;
+ es++;
+ }
+ else {
+ addedge(rn->v3, rn->v4, es);
+ es->nr= 3;
+ es->node= rn;
+ es++;
+ addedge(rn->v4, rn->v1, es);
+ es->nr= 4;
+ es->node= rn;
+ es++;
+ }
+ rp= rp->next;
+ }
+
+ qsort(esblock,tot,sizeof(EdSort),vergedge);
+
+ es= esblock;
+ while(tot>0) {
+ if( es->v1== (es+1)->v1 ) {
+ if( es->v2== (es+1)->v2 ) {
+ setedge(es->node, (es+1)->node, es->nr, (es+1)->nr);
+ tot--;
+ es++;
+ }
+ }
+ es++;
+ tot--;
+ }
+
+ MEM_freeN(esblock);
+}
+
+int materialIndex(Material *ma)
+{
+ int i = 0;
+ for(i=0;i< RG.totmat; i++)
+ {
+ if (RG.matar[i] == ma) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+void rad_collect_meshes()
+{
+ extern Material defmaterial;
+ Base *base;
+ Object *ob;
+ Mesh *me;
+ MVert *mvert;
+ MFace *mface;
+ MTFace *tf, *tface;
+ Material *ma = NULL, *noma= NULL;
+ RPatch *rp;
+ RNode *rn;
+ VeNoCo *vnc, **nodevert;
+ float *vd, *v1, *v2, *v3, *v4 = NULL;
+ int a, b, offs, index, mfdatatot;
+
+ if (G.vd==NULL) {
+ printf("Error, trying to collect radiosity meshes with no 3d view\n");
+ return;
+ }
+
+ if(G.obedit) {
+ if (!during_script()) error("Unable to perform function in EditMode");
+ return;
+ }
+
+ set_radglobal();
+
+ freeAllRad();
+
+ start_fastmalloc("Radiosity");
+
+ /* count the number of verts */
+ RG.totvert= 0;
+ RG.totface= 0;
+ base= (G.scene->base.first);
+ while(base) {
+ if(((base)->flag & SELECT) && ((base)->lay & G.vd->lay) ) {
+ if(base->object->type==OB_MESH) {
+ base->flag |= OB_RADIO;
+ me= base->object->data;
+ RG.totvert+= me->totvert;
+ }
+ }
+ base= base->next;
+ }
+ if(RG.totvert==0) {
+ if (!during_script()) error("No vertices");
+ return;
+ }
+ vnc= RG.verts= MEM_callocN(RG.totvert*sizeof(VeNoCo), "radioverts");
+
+ RG.min[0]= RG.min[1]= RG.min[2]= 1.0e20f;
+ RG.max[0]= RG.max[1]= RG.max[2]= -1.0e20f;
+
+ mfdatatot= 0;
+
+ /* min-max and material array */
+ base= (G.scene->base.first);
+ while(base) {
+ if( ((base)->flag & SELECT) && ((base)->lay & G.vd->lay) ) {
+ if(base->object->type==OB_MESH) {
+ me= base->object->data;
+ mvert= me->mvert;
+ for(a=0; a<me->totvert; a++, mvert++) {
+ vd= mallocVert();
+ VECCOPY(vd, mvert->co);
+ /* Should make MTC its own module... */
+ Mat4MulVecfl(base->object->obmat, vd);
+
+ vnc->v= vd;
+ for(b=0; b<3; b++) {
+ RG.min[b]= MIN2(RG.min[b], vd[b]);
+ RG.max[b]= MAX2(RG.max[b], vd[b]);
+ }
+ vnc++;
+ }
+
+ if(base->object->totcol==0) {
+ if(RG.totmat<MAXMAT) {
+ if(noma==NULL) {
+ noma= add_material("RadioMat");
+ RG.matar[RG.totmat]= noma;
+ RG.totmat++;
+ }
+ }
+ }
+ else {
+ for(a=0; a<base->object->totcol; a++) {
+ if(RG.totmat >= MAXMAT) break;
+
+ ma = give_current_material(base->object, a+1);
+
+ if (materialIndex(ma)!=-1) break;
+
+ RG.matar[RG.totmat]= ma;
+ RG.totmat++;
+ }
+ }
+
+ mfdatatot += me->totface;
+ }
+ }
+ base= base->next;
+ }
+
+ RG.cent[0]= (RG.min[0]+ RG.max[0])/2;
+ RG.cent[1]= (RG.min[1]+ RG.max[1])/2;
+ RG.cent[2]= (RG.min[2]+ RG.max[2])/2;
+ RG.size[0]= (RG.max[0]- RG.min[0]);
+ RG.size[1]= (RG.max[1]- RG.min[1]);
+ RG.size[2]= (RG.max[2]- RG.min[2]);
+ RG.maxsize= MAX3(RG.size[0],RG.size[1],RG.size[2]);
+
+ RG.mfdata= MEM_callocN(sizeof(CustomData), "radiomfdata");
+ RG.mfdatanodes= MEM_mallocN(sizeof(RNode*)*mfdatatot, "radiomfdatanodes");
+ RG.mfdatatot= mfdatatot;
+
+ /* make patches */
+
+ RG.totelem= 0;
+ RG.totpatch= 0;
+ RG.totlamp= 0;
+ offs= 0;
+
+ base= (G.scene->base.first);
+ while(base) {
+ if( ((base)->flag & SELECT) && ((base)->lay & G.vd->lay) ) {
+ if(base->object->type==OB_MESH) {
+ ob= base->object;
+ me= ob->data;
+ mface= me->mface;
+ tface= me->mtface;
+
+ index= -1;
+
+ CustomData_merge(&me->fdata, RG.mfdata, CD_MASK_DERIVEDMESH,
+ CD_DEFAULT, mfdatatot);
+
+ for(a=0; a<me->totface; a++, mface++) {
+ tf= tface? tface+a: NULL;
+
+ if (tf && (tf->mode & TF_INVISIBLE))
+ continue;
+
+ rp= callocPatch();
+ BLI_addtail(&(RG.patchbase), rp);
+ rp->from= ob;
+
+ if(mface->v4) rp->type= 4;
+ else rp->type= 3;
+
+ rp->first= rn= callocNode();
+
+ if(mface->flag & ME_SMOOTH) rp->f1= RAD_NO_SPLIT;
+
+ /* temporal: we store the venoco in the node */
+ rn->v1= (float *)(RG.verts+mface->v1+offs);
+ v1= (RG.verts+mface->v1+offs)->v;
+ rn->v2= (float *)(RG.verts+mface->v2+offs);
+ v2= (RG.verts+mface->v2+offs)->v;
+ rn->v3= (float *)(RG.verts+mface->v3+offs);
+ v3= (RG.verts+mface->v3+offs)->v;
+
+ if(mface->v4) {
+ rn->v4= (float *)(RG.verts+mface->v4+offs);
+ v4= (RG.verts+mface->v4+offs)->v;
+ }
+ rn->par= rp;
+ rn->f= RAD_PATCH; /* this node is a Patch */
+ rn->type= rp->type;
+
+ if(rn->type==4) {
+ rp->area= AreaQ3Dfl(v1, v2, v3, v4);
+ CalcNormFloat4(v1, v2, v3, v4, rp->norm);
+ }
+ else {
+ rp->area= AreaT3Dfl(v1, v2, v3);
+ CalcNormFloat(v1, v2, v3, rp->norm);
+ }
+
+ rn->area= rp->area;
+
+ /* color and emit */
+ if(mface->mat_nr != index) {
+ index= mface->mat_nr;
+ ma= give_current_material(ob, index+1);
+ if(ma==0) ma= &defmaterial;
+ }
+ rp->ref[0]= ma->r;
+ rp->ref[1]= ma->g;
+ rp->ref[2]= ma->b;
+
+ if(ma->emit) RG.totlamp++;
+
+ rp->emit[0]= rp->emit[1]= rp->emit[2]= ma->emit;
+ rp->emit[0]*= rp->ref[0];
+ rp->emit[1]*= rp->ref[1];
+ rp->emit[2]*= rp->ref[2];
+
+// uncommented, this is not satisfying, but i leave it in code for now (ton)
+// if(ma->translucency!=0.0) rn->f |= RAD_TWOSIDED;
+
+ nodevert= (VeNoCo **)&(rn->v1);
+ for(b=0; b<rp->type; b++) {
+ rp->cent[0]+= (*nodevert)->v[0];
+ rp->cent[1]+= (*nodevert)->v[1];
+ rp->cent[2]+= (*nodevert)->v[2];
+ nodevert++;
+ }
+ rp->cent[0]/= (float)rp->type;
+ rp->cent[1]/= (float)rp->type;
+ rp->cent[2]/= (float)rp->type;
+
+ /* for reconstruction materials */
+ rp->matindex= materialIndex(ma);
+ if(rp->matindex==-1) rp->matindex= 1;
+
+ /* these RNode's are stored now for later use in rad_addmesh
+ they should not get deleted before that */
+ rn->orig= RG.totelem;
+ RG.mfdatanodes[RG.totelem]= rn;
+
+ CustomData_copy_data(&me->fdata, RG.mfdata, a, RG.totelem, 1);
+
+ RG.totelem++;
+ RG.totpatch++;
+ }
+
+ offs+= me->totvert;
+ }
+ }
+ base= base->next;
+ }
+
+ splitconnected();
+ setedgepointers();
+
+ makeGlobalElemArray();
+ pseudoAmb();
+ rad_setlimits();
+}
+
+void setparelem(RNode *rn, RPatch *par)
+{
+
+ if(rn->down1) {
+ setparelem(rn->down1, par);
+ setparelem(rn->down2, par);
+ }
+ else {
+ rn->par= par;
+ }
+}
+
+void countelem(RNode *rn)
+{
+
+ if(rn->down1) {
+ countelem(rn->down1);
+ countelem(rn->down2);
+ }
+ else RG.totelem++;
+}
+
+void countglobaldata()
+{
+ /* counts elements and patches*/
+ RPatch *rp;
+
+ RG.totelem= RG.totpatch= 0;
+
+ rp= RG.patchbase.first;
+ while(rp) {
+ RG.totpatch++;
+ countelem(rp->first);
+ rp= rp->next;
+ }
+}
+
+void addelem(RNode ***el, RNode *rn, RPatch *rp)
+{
+ if(rn->down1) {
+ addelem(el, rn->down1, rp);
+ addelem(el, rn->down2, rp);
+ }
+ else {
+ rn->par= rp;
+ **el= rn;
+ (*el)++;
+ }
+}
+
+void makeGlobalElemArray()
+{
+ /* always called when # of elements change */
+ RPatch *rp;
+ RNode **el;
+
+ countglobaldata();
+
+ if(RG.elem) MEM_freeN(RG.elem);
+ if(RG.totelem) {
+ el= RG.elem= MEM_mallocN(sizeof(void *)*RG.totelem, "makeGlobalElemArray");
+ }
+ else {
+ RG.elem= 0;
+ return;
+ }
+
+ /* recursive adding elements */
+ rp= RG.patchbase.first;
+ while(rp) {
+ addelem(&el, rp->first, rp);
+ rp= rp->next;
+ }
+
+ /* formfactor array */
+ if(RG.formfactors) MEM_freeN(RG.formfactors);
+ if(RG.totelem)
+ RG.formfactors= MEM_mallocN(sizeof(float)*RG.totelem, "formfactors");
+ else
+ RG.formfactors= 0;
+}
+
+void splitpatch(RPatch *old) /* in case of overflow during shoot */
+{
+ RNode *rn;
+ float **fpp;
+ RPatch *rp;
+ int a;
+
+ rn= old->first;
+ if(rn->down1==0) return;
+ rn= rn->down1;
+
+ old->unshot[0]/=2.0;
+ old->unshot[1]/=2.0;
+ old->unshot[2]/=2.0;
+ setnodeflags(old->first, 2, 0);
+
+ rp= mallocPatch();
+ *rp= *old;
+ BLI_addhead(&RG.patchbase, rp);
+ rp->first= rn;
+ rp->area= rn->area;
+ rp->cent[0]= rp->cent[1]= rp->cent[2]= 0.0;
+ fpp= &(rn->v1);
+ for(a=0; a<rp->type; a++) {
+ rp->cent[0]+= (*fpp)[0];
+ rp->cent[1]+= (*fpp)[1];
+ rp->cent[2]+= (*fpp)[2];
+ fpp++;
+ }
+ rp->cent[0]/=(float)rp->type;
+ rp->cent[1]/=(float)rp->type;
+ rp->cent[2]/=(float)rp->type;
+
+ setparelem(rn, rp);
+
+ rn= old->first->down2;
+
+ rp= mallocPatch();
+ *rp= *old;
+ BLI_addhead(&RG.patchbase, rp);
+ rp->first= rn;
+ rp->area= rn->area;
+ rp->cent[0]= rp->cent[1]= rp->cent[2]= 0.0;
+ fpp= &(rn->v1);
+ for(a=0; a<rp->type; a++) {
+ rp->cent[0]+= (*fpp)[0];
+ rp->cent[1]+= (*fpp)[1];
+ rp->cent[2]+= (*fpp)[2];
+ fpp++;
+ }
+ rp->cent[0]/=(float)rp->type;
+ rp->cent[1]/=(float)rp->type;
+ rp->cent[2]/=(float)rp->type;
+
+ setparelem(rn, rp);
+
+ BLI_remlink(&RG.patchbase, old);
+ freePatch(old);
+}
+
+
+void addpatch(RPatch *old, RNode *rn)
+{
+ float **fpp;
+ RPatch *rp;
+ int a;
+
+ if(rn->down1) {
+ addpatch(old, rn->down1);
+ addpatch(old, rn->down2);
+ }
+ else {
+ rp= mallocPatch();
+ *rp= *old;
+ BLI_addhead(&RG.patchbase, rp);
+ rp->first= rn;
+
+ rp->area= rn->area;
+ rp->cent[0]= rp->cent[1]= rp->cent[2]= 0.0;
+ fpp= &(rn->v1);
+ for(a=0; a<rp->type; a++) {
+ rp->cent[0]+= (*fpp)[0];
+ rp->cent[1]+= (*fpp)[1];
+ rp->cent[2]+= (*fpp)[2];
+ fpp++;
+ }
+ rp->cent[0]/=(float)rp->type;
+ rp->cent[1]/=(float)rp->type;
+ rp->cent[2]/=(float)rp->type;
+
+ rn->par= rp;
+ }
+}
+
+void converttopatches()
+{
+ /* chacks patches list, if node subdivided: new patch */
+ RPatch *rp, *next;
+
+ rp= RG.patchbase.first;
+ while(rp) {
+ next= rp->next;
+ if(rp->first->down1) {
+ addpatch(rp, rp->first);
+ BLI_remlink(&RG.patchbase, rp);
+ freePatch(rp);
+ }
+ rp= next;
+ }
+
+}
+
+void subdiv_elements()
+{
+ RNode **el, *rn;
+ int a, toobig= 1;
+
+ rad_init_energy();
+
+ /* first maxsize elements */
+
+ while(toobig) {
+ toobig= 0;
+
+ el= RG.elem;
+ for(a=RG.totelem; a>0; a--, el++) {
+ rn= *el;
+ if( rn->totrad[0]==0.0 && rn->totrad[1]==0.0 && rn->totrad[2]==0.0) {
+ if(rn->area>RG.elemmin) {
+ subdivideNode(rn, 0);
+ if(rn->down1 ) {
+ toobig= 1;
+ if(rn->down1->area>RG.elemmin)
+ subdivideNode( rn->down1, 0);
+ if(rn->down2->area>RG.elemmin)
+ subdivideNode( rn->down2, 0);
+ }
+ }
+ }
+ }
+ if(toobig) makeGlobalElemArray();
+ }
+
+ el= RG.elem;
+ for(a=RG.totelem; a>0; a--, el++) {
+ rn= *el;
+ if( rn->totrad[0]==0.0 && rn->totrad[1]==0.0 && rn->totrad[2]==0.0) {
+ subdivideNode(rn, 0);
+ if( rn->down1 ) {
+ subdivideNode( rn->down1, 0);
+ subdivideNode( rn->down2, 0);
+ }
+ }
+ }
+ makeGlobalElemArray();
+}
+
+void subdividelamps()
+{
+ RPatch *rp, *next;
+
+ rp= RG.patchbase.first;
+ while(rp) {
+ next= rp->next;
+ if(rp->emit[0]!=0.0 || rp->emit[1]!=0.0 || rp->emit[2]!=0.0) {
+ subdivideNode( rp->first, 0);
+ if(rp->first->down1) {
+ subdivideNode(rp->first->down1, 0);
+ subdivideNode(rp->first->down2, 0);
+ }
+
+ addpatch(rp, rp->first);
+ BLI_remlink(&RG.patchbase, rp);
+ freePatch(rp);
+ }
+ rp= next;
+ }
+
+}
+
+void maxsizePatches()
+{
+ RPatch *rp;
+ int toobig= 1;
+
+ while(toobig) {
+ toobig= 0;
+ rp= RG.patchbase.first;
+ while(rp) {
+ if(rp->area>RG.patchmax) {
+ subdivideNode( rp->first, 0);
+ if(rp->first->down1) toobig= 1;
+ }
+ rp= rp->next;
+ }
+
+ if(toobig) converttopatches();
+ }
+
+ /* count lamps */
+ rp= RG.patchbase.first;
+ RG.totlamp= 0;
+ while(rp) {
+ if(rp->emit[0]!=0.0 || rp->emit[1]!=0.0 || rp->emit[2]!=0.0) {
+ RG.totlamp++;
+ }
+ rp= rp->next;
+ }
+ makeGlobalElemArray();
+}
+
+
+
diff --git a/source/blender/radiosity/intern/source/radrender.c b/source/blender/radiosity/intern/source/radrender.c
new file mode 100644
index 00000000000..42c7fa58da5
--- /dev/null
+++ b/source/blender/radiosity/intern/source/radrender.c
@@ -0,0 +1,501 @@
+/* ***************************************
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/* radrender.c, aug 2003
+ *
+ * Most of the code here is copied from radiosity code, to optimize for renderfaces.
+ * Shared function calls mostly reside in radfactors.c
+ * No adaptive subdivision takes place
+ *
+ * - do_radio_render(); main call, extern
+ * - initradfaces(); add radface structs in render faces, init radio globals
+ * -
+ * - initradiosity(); LUTs
+ * - inithemiwindows();
+ * - progressiverad(); main itteration loop
+ * - hemi zbuffers
+ * - calc rad factors
+ *
+ * - closehemiwindows();
+ * - freeAllRad();
+ * - make vertex colors
+ *
+ * - during render, materials use totrad as ambient replacement
+ * - free radfaces
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_rand.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+
+#include "BIF_screen.h"
+
+#include "radio.h"
+
+/* the radiosity module uses internal includes from render! */
+#include "renderpipeline.h"
+#include "render_types.h"
+#include "renderdatabase.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* only needed now for a print, if its useful move to RG */
+static float maxenergy;
+
+/* find the face with maximum energy to become shooter */
+/* nb: _rr means rad-render version of existing radio call */
+static VlakRen *findshoot_rr(Render *re)
+{
+ RadFace *rf;
+ VlakRen *vlr=NULL, *shoot;
+ float energy;
+ int a;
+
+ shoot= NULL;
+ maxenergy= 0.0;
+
+ for(a=0; a<re->totvlak; a++) {
+ if((a & 255)==0) vlr= re->vlaknodes[a>>8].vlak; else vlr++;
+ if(vlr->radface) {
+ rf= vlr->radface;
+ rf->flag &= ~RAD_SHOOT;
+
+ energy= rf->unshot[0]*rf->area;
+ energy+= rf->unshot[1]*rf->area;
+ energy+= rf->unshot[2]*rf->area;
+
+ if(energy>maxenergy) {
+ shoot= vlr;
+ maxenergy= energy;
+ }
+ }
+ }
+
+ if(shoot) {
+ maxenergy/= RG.totenergy;
+ if(maxenergy<RG.convergence) return NULL;
+ shoot->radface->flag |= RAD_SHOOT;
+ }
+
+ return shoot;
+}
+
+static void backface_test_rr(Render *re, VlakRen *shoot)
+{
+ VlakRen *vlr=NULL;
+ RadFace *rf;
+ float tvec[3];
+ int a;
+
+ /* backface testing */
+ for(a=0; a<re->totvlak; a++) {
+ if((a & 255)==0) vlr= re->vlaknodes[a>>8].vlak; else vlr++;
+ if(vlr->radface) {
+ if(vlr!=shoot) {
+ rf= vlr->radface;
+ VecSubf(tvec, shoot->radface->cent, rf->cent);
+
+ if( tvec[0]*rf->norm[0]+ tvec[1]*rf->norm[1]+ tvec[2]*rf->norm[2] < 0.0) {
+ rf->flag |= RAD_BACKFACE;
+ }
+ }
+ }
+ }
+}
+
+static void clear_backface_test_rr(Render *re)
+{
+ VlakRen *vlr=NULL;
+ RadFace *rf;
+ int a;
+
+ /* backface flag clear */
+ for(a=0; a<re->totvlak; a++) {
+ if((a & 255)==0) vlr= re->vlaknodes[a>>8].vlak; else vlr++;
+
+ if(vlr->radface) {
+ rf= vlr->radface;
+ rf->flag &= ~RAD_BACKFACE;
+ }
+ }
+}
+
+extern RadView hemitop, hemiside; // radfactors.c
+
+/* hemi-zbuffering, delivers formfactors array */
+static void makeformfactors_rr(Render *re, VlakRen *shoot)
+{
+ VlakRen *vlr=NULL;
+ RadFace *rf;
+ float len, vec[3], up[3], side[3], tar[5][3], *fp;
+ int a;
+
+ memset(RG.formfactors, 0, sizeof(float)*RG.totelem);
+
+ /* set up hemiview */
+ /* first: upvector for hemitop, we use diagonal hemicubes to prevent aliasing */
+
+ VecSubf(vec, shoot->v1->co, shoot->radface->cent);
+ Crossf(up, shoot->radface->norm, vec);
+ len= Normalize(up);
+
+ VECCOPY(hemitop.up, up);
+ VECCOPY(hemiside.up, shoot->radface->norm);
+
+ Crossf(side, shoot->radface->norm, up);
+
+ /* five targets */
+ VecAddf(tar[0], shoot->radface->cent, shoot->radface->norm);
+ VecAddf(tar[1], shoot->radface->cent, up);
+ VecSubf(tar[2], shoot->radface->cent, up);
+ VecAddf(tar[3], shoot->radface->cent, side);
+ VecSubf(tar[4], shoot->radface->cent, side);
+
+ /* camera */
+ VECCOPY(hemiside.cam, shoot->radface->cent);
+ VECCOPY(hemitop.cam, shoot->radface->cent);
+
+ /* do it! */
+ VECCOPY(hemitop.tar, tar[0]);
+ hemizbuf(&hemitop);
+
+ for(a=1; a<5; a++) {
+ VECCOPY(hemiside.tar, tar[a]);
+ hemizbuf(&hemiside);
+ }
+
+ /* convert factors to real radiosity */
+ fp= RG.formfactors;
+
+ for(a=0; a<re->totvlak; a++) {
+ if((a & 255)==0) vlr= re->vlaknodes[a>>8].vlak; else vlr++;
+
+ if(vlr->radface) {
+ rf= vlr->radface;
+ if(*fp!=0.0 && rf->area!=0.0) {
+ *fp *= shoot->radface->area/rf->area;
+ if(*fp>1.0) *fp= 1.0001;
+ }
+ fp++;
+ }
+ }
+}
+
+/* based at RG.formfactors array, distribute shoot energy over other faces */
+static void applyformfactors_rr(Render *re, VlakRen *shoot)
+{
+ VlakRen *vlr=NULL;
+ RadFace *rf;
+ float *fp, *ref, unr, ung, unb, r, g, b;
+ int a;
+
+ unr= shoot->radface->unshot[0];
+ ung= shoot->radface->unshot[1];
+ unb= shoot->radface->unshot[2];
+
+ fp= RG.formfactors;
+
+ for(a=0; a<re->totvlak; a++) {
+ if((a & 255)==0) vlr= re->vlaknodes[a>>8].vlak; else vlr++;
+
+ if(vlr->radface) {
+ rf= vlr->radface;
+ if(*fp!= 0.0) {
+
+ ref= &(vlr->mat->r);
+
+ r= (*fp)*unr*ref[0];
+ g= (*fp)*ung*ref[1];
+ b= (*fp)*unb*ref[2];
+
+ // if(rf->flag & RAD_BACKFACE) {
+
+ rf->totrad[0]+= r;
+ rf->totrad[1]+= g;
+ rf->totrad[2]+= b;
+
+ rf->unshot[0]+= r;
+ rf->unshot[1]+= g;
+ rf->unshot[2]+= b;
+ }
+ fp++;
+ }
+ }
+ /* shoot energy has been shot */
+ shoot->radface->unshot[0]= shoot->radface->unshot[1]= shoot->radface->unshot[2]= 0.0;
+}
+
+
+/* main loop for itterations */
+static void progressiverad_rr(Render *re)
+{
+ VlakRen *shoot;
+ float unshot[3];
+ int it= 0;
+
+ shoot= findshoot_rr(re);
+ while( shoot ) {
+
+ /* backfaces receive no energy, but are zbuffered... */
+ backface_test_rr(re, shoot);
+
+ /* ...unless it's two sided */
+ if(shoot->radface->flag & RAD_TWOSIDED) {
+ VECCOPY(unshot, shoot->radface->unshot);
+ VecMulf(shoot->radface->norm, -1.0);
+ makeformfactors_rr(re, shoot);
+ applyformfactors_rr(re, shoot);
+ VecMulf(shoot->radface->norm, -1.0);
+ VECCOPY(shoot->radface->unshot, unshot);
+ }
+
+ /* hemi-zbuffers */
+ makeformfactors_rr(re, shoot);
+ /* based at RG.formfactors array, distribute shoot energy over other faces */
+ applyformfactors_rr(re, shoot);
+
+ it++;
+ re->timecursor(it);
+
+ clear_backface_test_rr(re);
+
+ if(re->test_break()) break;
+ if(RG.maxiter && RG.maxiter<=it) break;
+
+ shoot= findshoot_rr(re);
+ }
+ printf(" Unshot energy:%f\n", 1000.0*maxenergy);
+
+ re->timecursor((G.scene->r.cfra));
+}
+
+static RadFace *radfaces=NULL;
+
+static void initradfaces(Render *re)
+{
+ VlakRen *vlr= NULL;
+ RadFace *rf;
+ int a, b;
+
+ /* globals */
+ RG.totenergy= 0.0;
+ RG.totpatch= 0; // we count initial emittors here
+ RG.totelem= 0; // total # faces are put here (so we can use radfactors.c calls)
+ /* size is needed for hemicube clipping */
+ RG.min[0]= RG.min[1]= RG.min[2]= 1.0e20;
+ RG.max[0]= RG.max[1]= RG.max[2]= -1.0e20;
+
+ /* count first for fast malloc */
+ for(a=0; a<re->totvlak; a++) {
+ if((a & 255)==0) vlr= re->vlaknodes[a>>8].vlak; else vlr++;
+
+ if(vlr->mat->mode & MA_RADIO) {
+ if(vlr->mat->emit > 0.0) {
+ RG.totpatch++;
+ }
+ RG.totelem++;
+ }
+ }
+
+printf(" Rad elems: %d emittors %d\n", RG.totelem, RG.totpatch);
+ if(RG.totelem==0 || RG.totpatch==0) return;
+
+ /* make/init radfaces */
+ rf=radfaces= MEM_callocN(RG.totelem*sizeof(RadFace), "radfaces");
+ for(a=0; a<re->totvlak; a++) {
+ if((a & 255)==0) vlr= re->vlaknodes[a>>8].vlak; else vlr++;
+
+ if(vlr->mat->mode & MA_RADIO) {
+
+ /* during render, vlr->n gets flipped/corrected, we cannot have that */
+ if(vlr->v4) CalcNormFloat4(vlr->v1->co, vlr->v2->co, vlr->v3->co, vlr->v4->co, rf->norm);
+ else CalcNormFloat(vlr->v1->co, vlr->v2->co, vlr->v3->co, rf->norm);
+
+ rf->totrad[0]= vlr->mat->emit*vlr->mat->r;
+ rf->totrad[1]= vlr->mat->emit*vlr->mat->g;
+ rf->totrad[2]= vlr->mat->emit*vlr->mat->b;
+ VECCOPY(rf->unshot, rf->totrad);
+
+ if(vlr->v4) {
+ rf->area= AreaQ3Dfl(vlr->v1->co, vlr->v2->co, vlr->v3->co, vlr->v4->co);
+ CalcCent4f(rf->cent, vlr->v1->co, vlr->v2->co, vlr->v3->co, vlr->v4->co);
+ }
+ else {
+ rf->area= AreaT3Dfl(vlr->v1->co, vlr->v2->co, vlr->v3->co);
+ CalcCent3f(rf->cent, vlr->v1->co, vlr->v2->co, vlr->v3->co);
+ }
+
+ RG.totenergy+= rf->unshot[0]*rf->area;
+ RG.totenergy+= rf->unshot[1]*rf->area;
+ RG.totenergy+= rf->unshot[2]*rf->area;
+
+ for(b=0; b<3; b++) {
+ RG.min[b]= MIN2(RG.min[b], rf->cent[b]);
+ RG.max[b]= MAX2(RG.max[b], rf->cent[b]);
+ }
+
+// uncommented; this isnt satisfying, but i leave it in the code for now (ton)
+// if(vlr->mat->translucency!=0.0) rf->flag |= RAD_TWOSIDED;
+
+ vlr->radface= rf++;
+ }
+ }
+ RG.size[0]= (RG.max[0]- RG.min[0]);
+ RG.size[1]= (RG.max[1]- RG.min[1]);
+ RG.size[2]= (RG.max[2]- RG.min[2]);
+ RG.maxsize= MAX3(RG.size[0],RG.size[1],RG.size[2]);
+
+ /* formfactor array */
+ if(RG.formfactors) MEM_freeN(RG.formfactors);
+ if(RG.totelem)
+ RG.formfactors= MEM_mallocN(sizeof(float)*RG.totelem, "formfactors");
+ else
+ RG.formfactors= NULL;
+
+}
+
+static void vecaddfac(float *vec, float *v1, float *v2, float fac)
+{
+ vec[0]= v1[0] + fac*v2[0];
+ vec[1]= v1[1] + fac*v2[1];
+ vec[2]= v1[2] + fac*v2[2];
+
+}
+
+/* unused now, doesnt work..., find it in cvs of nov 2005 or older */
+/* static void filter_rad_values(void) */
+
+
+static void make_vertex_rad_values(Render *re)
+{
+ VertRen *v1=NULL;
+ VlakRen *vlr=NULL;
+ RadFace *rf;
+ float *col;
+ int a;
+
+ RG.igamma= 1.0/RG.gamma;
+ RG.radfactor= RG.radfac*pow(64*64, RG.igamma)/128.0; /* compatible with radio-tool */
+
+ /* accumulate vertexcolors */
+ for(a=0; a<re->totvlak; a++) {
+ if((a & 255)==0) vlr= re->vlaknodes[a>>8].vlak; else vlr++;
+
+ if(vlr->radface) {
+ rf= vlr->radface;
+
+ /* apply correction */
+ rf->totrad[0]= RG.radfactor*pow( rf->totrad[0], RG.igamma);
+ rf->totrad[1]= RG.radfactor*pow( rf->totrad[1], RG.igamma);
+ rf->totrad[2]= RG.radfactor*pow( rf->totrad[2], RG.igamma);
+
+ /* correct rf->rad values for color */
+ if(vlr->mat->r > 0.0) rf->totrad[0]/= vlr->mat->r;
+ if(vlr->mat->g > 0.0) rf->totrad[1]/= vlr->mat->g;
+ if(vlr->mat->b > 0.0) rf->totrad[2]/= vlr->mat->b;
+
+ col= RE_vertren_get_rad(re, vlr->v1, 1);
+ vecaddfac(col, col, rf->totrad, rf->area);
+ col[3]+= rf->area;
+
+ col= RE_vertren_get_rad(re, vlr->v2, 1);
+ vecaddfac(col, col, rf->totrad, rf->area);
+ col[3]+= rf->area;
+
+ col= RE_vertren_get_rad(re, vlr->v3, 1);
+ vecaddfac(col, col, rf->totrad, rf->area);
+ col[3]+= rf->area;
+
+ if(vlr->v4) {
+ col= RE_vertren_get_rad(re, vlr->v4, 1);
+ vecaddfac(col, col, rf->totrad, rf->area);
+ col[3]+= rf->area;
+ }
+ }
+ }
+
+ /* make vertex colors */
+ for(a=0; a<re->totvert; a++) {
+ if((a & 255)==0) v1= RE_findOrAddVert(re, a); else v1++;
+
+ col= RE_vertren_get_rad(re, v1, 0);
+ if(col && col[3]>0.0) {
+ col[0]/= col[3];
+ col[1]/= col[3];
+ col[2]/= col[3];
+ }
+ }
+
+}
+
+/* main call, extern */
+void do_radio_render(Render *re)
+{
+ if(G.scene->radio==NULL) add_radio();
+ freeAllRad(); /* just in case radio-tool is still used */
+
+ set_radglobal(); /* init the RG struct */
+ RG.re= re; /* only used by hemizbuf(), prevents polluting radio code all over */
+
+ initradfaces(re); /* add radface structs to render faces */
+ if(RG.totenergy>0.0) {
+
+ initradiosity(); /* LUT's */
+ inithemiwindows(); /* views, need RG.maxsize for clipping */
+
+ progressiverad_rr(re); /* main radio loop */
+
+ make_vertex_rad_values(re); /* convert face energy to vertex ones */
+
+ }
+
+ freeAllRad(); /* luts, hemis, sets vars at zero */
+}
+
+/* free call, after rendering, extern */
+void end_radio_render(void)
+{
+ if(radfaces) MEM_freeN(radfaces);
+ radfaces= NULL;
+}
+
diff --git a/source/blender/readblenfile/BLO_readblenfile.h b/source/blender/readblenfile/BLO_readblenfile.h
new file mode 100644
index 00000000000..d1b89d8dc97
--- /dev/null
+++ b/source/blender/readblenfile/BLO_readblenfile.h
@@ -0,0 +1,84 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ *
+ */
+
+#ifndef BLO_READBLENFILE_H
+#define BLO_READBLENFILE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ BlendFileData *
+BLO_readblenfilename(
+ char *fileName,
+ BlendReadError *error_r);
+
+ BlendFileData *
+BLO_readblenfilehandle(
+ int fileHandle,
+ BlendReadError *error_r);
+
+ BlendFileData *
+BLO_readblenfilememory(
+ char *fromBuffer,
+ int fromBufferSize,
+ BlendReadError *error_r);
+
+
+ void
+BLO_setcurrentversionnumber(
+ char array[4]);
+
+ void
+BLO_setversionnumber(
+ char array[4],
+ int version);
+
+ int
+blo_is_a_runtime(
+ char *file);
+
+ BlendFileData *
+blo_read_runtime(
+ char *file,
+ BlendReadError *error_r);
+
+#define BLO_RESERVEDSIZE 12
+extern char *headerMagic;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BLO_READBLENFILE_H */
+
diff --git a/source/blender/readblenfile/CMakeLists.txt b/source/blender/readblenfile/CMakeLists.txt
new file mode 100644
index 00000000000..491d0fbaaea
--- /dev/null
+++ b/source/blender/readblenfile/CMakeLists.txt
@@ -0,0 +1,37 @@
+# $Id$
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2006, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Jacques Beaurain.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+
+FILE(GLOB SRC intern/*.c)
+
+SET(INC
+ . ../blenloader ../blenloader/intern ../blenkernel ../blenlib ../makesdna ../../kernel/gen_messaging
+)
+
+BLENDERLIB(bf_readblenfile "${SRC}" "${INC}")
+#env.BlenderLib ( 'bf_readblenfile', sources, Split(incs), [], libtype=['common','player'], priority = [0, 220] )
diff --git a/source/blender/readblenfile/Makefile b/source/blender/readblenfile/Makefile
new file mode 100644
index 00000000000..0db2f2aa3b5
--- /dev/null
+++ b/source/blender/readblenfile/Makefile
@@ -0,0 +1,37 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+# Bounces make to subdirectories.
+
+SOURCEDIR = source/blender/readblenfile
+DIRS = intern stub
+
+include nan_subdirs.mk
diff --git a/source/blender/readblenfile/SConscript b/source/blender/readblenfile/SConscript
new file mode 100644
index 00000000000..31ca25eedd7
--- /dev/null
+++ b/source/blender/readblenfile/SConscript
@@ -0,0 +1,8 @@
+#!/usr/bin/python
+Import ('env')
+
+sources = env.Glob('intern/*.c')
+
+incs = '. ../blenloader ../blenloader/intern ../blenkernel ../blenlib ../makesdna ../../kernel/gen_messaging'
+
+env.BlenderLib ( 'bf_readblenfile', sources, Split(incs), [], libtype=['common','player'], priority = [0, 220] )
diff --git a/source/blender/readblenfile/intern/BLO_readblenfile.c b/source/blender/readblenfile/intern/BLO_readblenfile.c
new file mode 100644
index 00000000000..8199c83c3ef
--- /dev/null
+++ b/source/blender/readblenfile/intern/BLO_readblenfile.c
@@ -0,0 +1,175 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ *
+ */
+/**
+ * \file BLO_readblenfile.c
+ * \brief This file handles the loading if .blend files
+ * \ingroup mainmodule
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WIN32
+#include <io.h> // read, open
+#else // ! WIN32
+#include <unistd.h> // read
+#endif
+
+#include "BLO_readfile.h"
+#include "BLO_readblenfile.h"
+
+#include "BKE_blender.h"
+
+#include "BLI_blenlib.h"
+
+/** Magic number for the file header */
+char *headerMagic = "BLENDFI";
+
+/**
+ * \brief Set the version number into the array.
+ *
+ * version contains the integer number of the version
+ * i.e. 227
+ * array[1] gets set to the div of the number by 100 i.e. 2
+ * array[2] gets the remainder i.e. 27
+ */
+void BLO_setversionnumber(char array[4], int version)
+{
+ memset(array, 0, sizeof(array));
+
+ array[1] = version / 100;
+ array[2] = version % 100;
+}
+
+/**
+ * Sets version number using BLENDER_VERSION
+ * Function that calls the setversionnumber(char[],int) with
+ * the BLENDER_VERSION constant and sets the resultant array
+ * with the version parts.
+ * see BLO_setversionnumber(char[],int).
+ */
+void BLO_setcurrentversionnumber(char array[4])
+{
+ BLO_setversionnumber(array, BLENDER_VERSION);
+}
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+/* Runtime reading */
+
+static int handle_read_msb_int(int handle) {
+ unsigned char buf[4];
+
+ if (read(handle, buf, 4)!=4)
+ return -1;
+ else
+ return (buf[0]<<24) + (buf[1]<<16) + (buf[2]<<8) + (buf[3]<<0);
+}
+
+int blo_is_a_runtime(char *path) {
+ int res= 0, fd= open(path, O_BINARY|O_RDONLY, 0);
+ int datastart;
+ char buf[8];
+
+ if (fd==-1)
+ goto cleanup;
+
+ lseek(fd, -12, SEEK_END);
+
+ datastart= handle_read_msb_int(fd);
+ if (datastart==-1)
+ goto cleanup;
+ else if (read(fd, buf, 8)!=8)
+ goto cleanup;
+ else if (memcmp(buf, "BRUNTIME", 8)!=0)
+ goto cleanup;
+ else
+ res= 1;
+
+cleanup:
+ if (fd!=-1)
+ close(fd);
+
+ return res;
+}
+
+BlendFileData *
+blo_read_runtime(
+ char *path,
+ BlendReadError *error_r)
+{
+ BlendFileData *bfd= NULL;
+ int fd, actualsize, datastart;
+ char buf[8];
+
+ fd= open(path, O_BINARY|O_RDONLY, 0);
+ if (fd==-1) {
+ *error_r= BRE_UNABLE_TO_OPEN;
+ goto cleanup;
+ }
+
+ actualsize= BLI_filesize(fd);
+
+ lseek(fd, -12, SEEK_END);
+
+ datastart= handle_read_msb_int(fd);
+ if (datastart==-1) {
+ *error_r= BRE_UNABLE_TO_READ;
+ goto cleanup;
+ } else if (read(fd, buf, 8)!=8) {
+ *error_r= BRE_UNABLE_TO_READ;
+ goto cleanup;
+ } else if (memcmp(buf, "BRUNTIME", 8)!=0) {
+ *error_r= BRE_NOT_A_BLEND;
+ goto cleanup;
+ } else {
+ //printf("starting to read runtime from %s at datastart %d\n", path, datastart);
+ lseek(fd, datastart, SEEK_SET);
+ bfd = blo_read_blendafterruntime(fd, actualsize-datastart, error_r);
+ fd= -1; // file was closed in blo_read_blendafterruntime()
+ }
+
+cleanup:
+ if (fd!=-1)
+ close(fd);
+
+ return bfd;
+}
+
diff --git a/source/blender/readblenfile/intern/Makefile b/source/blender/readblenfile/intern/Makefile
new file mode 100644
index 00000000000..fa9875b8403
--- /dev/null
+++ b/source/blender/readblenfile/intern/Makefile
@@ -0,0 +1,50 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+#
+
+LIBNAME = readblenfile
+DIR = $(OCGDIR)/blender/$(LIBNAME)
+
+include nan_compile.mk
+
+CFLAGS += $(LEVEL_2_C_WARNINGS)
+
+# path to our own external headerfiles
+CPPFLAGS += -I..
+
+# external modules
+CPPFLAGS += -I../../../kernel/gen_messaging
+CPPFLAGS += -I../../readstreamglue
+CPPFLAGS += -I../../blenlib
+CPPFLAGS += -I../../makesdna
+CPPFLAGS += -I../../blenkernel
+CPPFLAGS += -I../../blenloader
diff --git a/source/blender/readblenfile/stub/BLO_readblenfileSTUB.c b/source/blender/readblenfile/stub/BLO_readblenfileSTUB.c
new file mode 100644
index 00000000000..d0e7cd9a117
--- /dev/null
+++ b/source/blender/readblenfile/stub/BLO_readblenfileSTUB.c
@@ -0,0 +1,96 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ *
+ */
+
+#include <stdio.h>
+#include "GEN_messaging.h"
+
+int BLO_readblenfilememory( char *fromBuffer, int fromBufferSize);
+int BLO_readblenfilename( char *fileName);
+int BLO_readblenfilehandle( int fileHandle);
+int BLO_is_a_runtime( char *file);
+int BLO_read_runtime( char *file);
+
+ int
+BLO_readblenfilememory(
+ char *fromBuffer, int fromBufferSize)
+{
+#ifndef NDEBUG
+ fprintf(GEN_errorstream,
+ "Error BLO_readblenfilename is a stub\n");
+#endif
+ return(1);
+}
+
+ int
+BLO_readblenfilename(
+ char *fileName)
+{
+#ifndef NDEBUG
+ fprintf(GEN_errorstream,
+ "Error BLO_readblenfilename is a stub\n");
+#endif
+ return(1);
+}
+
+ int
+BLO_readblenfilehandle(
+ int fileHandle)
+{
+#ifndef NDEBUG
+ fprintf(GEN_errorstream,
+ "Error BLO_readblenfilehandle is a stub\n");
+#endif
+ return(1);
+}
+
+ int
+BLO_is_a_runtime(
+ char *file)
+{
+#ifndef NDEBUG
+ fprintf(GEN_errorstream,
+ "Error BLO_is_a_runtime is a stub\n");
+#endif
+ return 0;
+}
+
+ int
+BLO_read_runtime(
+ char *file)
+{
+#ifndef NDEBUG
+ fprintf(GEN_errorstream,
+ "Error BLO_read_runtime is a stub\n");
+#endif
+ return 0;
+}
diff --git a/source/blender/readblenfile/stub/Makefile b/source/blender/readblenfile/stub/Makefile
new file mode 100644
index 00000000000..ed96e56b8af
--- /dev/null
+++ b/source/blender/readblenfile/stub/Makefile
@@ -0,0 +1,47 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+#
+
+LIBNAME = readblenfileSTUB
+DIR = $(OCGDIR)/blender/$(LIBNAME)
+
+include nan_compile.mk
+
+CFLAGS += $(LEVEL_2_C_WARNINGS)
+CFLAGS += $(FIX_STUBS_WARNINGS)
+
+# path to our own external headerfiles
+CPPFLAGS += -I..
+
+# external modules
+CPPFLAGS += -I../../../kernel/gen_messaging
+
diff --git a/source/blender/readblenfile/test/Makefile b/source/blender/readblenfile/test/Makefile
new file mode 100644
index 00000000000..235abad36b5
--- /dev/null
+++ b/source/blender/readblenfile/test/Makefile
@@ -0,0 +1,49 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+#
+
+LIBNAME = readblenfile
+DIR = $(OCGDIR)/blender/$(LIBNAME)
+ALLTARGETS = $(OBJS) $(DIR)/$(DEBUG_DIR)test$(EXT)
+
+include nan_compile.mk
+
+CFLAGS += $(LEVEL_2_C_WARNINGS)
+
+# path to our own external headerfiles
+CPPFLAGS += -I..
+CPPFLAGS += -I../../readstreamglue
+
+$(DIR)/$(DEBUG_DIR)test$(EXT): $(OBJS) ../intern/BLO_readblenfile.c
+ $(CC) $(LDFLAGS) -o $@ $(OBJS) $(OCGDIR)/blender/readblenfile/$(DEBUG_DIR)libreadblenfile.a
+ $(DIR)/$(DEBUG_DIR)test$(EXT)
+
diff --git a/source/blender/readblenfile/test/test.c b/source/blender/readblenfile/test/test.c
new file mode 100644
index 00000000000..5b2a194e0e0
--- /dev/null
+++ b/source/blender/readblenfile/test/test.c
@@ -0,0 +1,58 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#include <string.h> // strlen
+#include "BLO_readblenfile.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+struct streamGlueControlStruct *Global_streamGlueControl;
+
+ int
+streamGlueWrite(
+ struct streamGlueControlStruct *streamGlueControl,
+ struct streamGlueStruct **streamGlue,
+ unsigned char *data,
+ unsigned int dataIn,
+ int finishUp)
+{
+ printf("called with %d bytes in buffer [%s]\n", dataIn, data);
+ return (0);
+}
+
+main()
+{
+ int err;
+
+ err = BLO_readblenfile();
+}
diff --git a/source/blender/render/CMakeLists.txt b/source/blender/render/CMakeLists.txt
new file mode 100644
index 00000000000..84e9c91e570
--- /dev/null
+++ b/source/blender/render/CMakeLists.txt
@@ -0,0 +1,56 @@
+# $Id$
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2006, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Jacques Beaurain.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+
+FILE(GLOB SRC intern/source/*.c)
+
+SET(INC
+ intern/include ../../../intern/guardedalloc ../blenlib ../makesdna
+ extern/include ../blenkernel ../radiosity/extern/include ../imbuf
+ ../quicktime ../include ../../kernel/gen_messaging ../yafray
+)
+
+IF(WITH_OPENEXR)
+ ADD_DEFINITIONS(-DWITH_OPENEXR)
+ENDIF(WITH_OPENEXR)
+
+IF(WITH_QUICKTIME)
+ SET(INC ${INC} ${QUICKTIME_INC})
+ ADD_DEFINITIONS(-DWITH_QUICKTIME)
+ENDIF(WITH_QUICKTIME)
+
+IF(WITH_FFMPEG)
+ ADD_DEFINITIONS(-DWITH_FFMPEG)
+ENDIF(WITH_FFMPEG)
+
+#TODO
+#if env['OURPLATFORM']=='linux2':
+# cflags='-pthread'
+
+BLENDERLIB_NOLIST(blender_render "${SRC}" "${INC}")
+#env.BlenderLib ( libname = 'blender_render', sources = sources, includes = Split(incs), defines=defs, libtype='core', priority=45, compileflags=cflags )
diff --git a/source/blender/render/Makefile b/source/blender/render/Makefile
new file mode 100644
index 00000000000..5d8fbdd743f
--- /dev/null
+++ b/source/blender/render/Makefile
@@ -0,0 +1,37 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+# Bounces make to subdirectories.
+
+SOURCEDIR = source/blender/render
+DIRS = intern
+
+include nan_subdirs.mk
diff --git a/source/blender/render/SConscript b/source/blender/render/SConscript
new file mode 100644
index 00000000000..b1bc9673f23
--- /dev/null
+++ b/source/blender/render/SConscript
@@ -0,0 +1,31 @@
+#!/usr/bin/python
+Import ('env')
+
+cflags=''
+sources = env.Glob('intern/source/*.c')
+
+incs = 'intern/include #/intern/guardedalloc ../blenlib ../makesdna'
+incs += ' extern/include ../blenkernel ../radiosity/extern/include ../imbuf'
+incs += ' ../quicktime ../include ../../kernel/gen_messaging'
+
+defs = []
+
+if env['WITH_BF_YAFRAY'] == 1:
+ incs += ' ../yafray'
+else:
+ defs.append('DISABLE_YAFRAY')
+
+if env['WITH_BF_QUICKTIME'] == 1:
+ defs.append('WITH_QUICKTIME')
+ incs += ' ' + env['BF_QUICKTIME_INC']
+
+if env['WITH_BF_FFMPEG'] == 1:
+ defs.append('WITH_FFMPEG')
+
+if env['WITH_BF_OPENEXR']:
+ defs.append('WITH_OPENEXR')
+
+if env['OURPLATFORM']=='linux2':
+ cflags='-pthread'
+
+env.BlenderLib ( libname = 'blender_render', sources = sources, includes = Split(incs), defines=defs, libtype='core', priority=45, compileflags=cflags )
diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h
new file mode 100644
index 00000000000..9abc873172f
--- /dev/null
+++ b/source/blender/render/extern/include/RE_pipeline.h
@@ -0,0 +1,217 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef RE_PIPELINE_H
+#define RE_PIPELINE_H
+
+#include "DNA_listBase.h"
+#include "DNA_vec_types.h"
+#include "BKE_utildefines.h"
+
+struct Scene;
+struct RenderData;
+struct NodeBlurData;
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+/* this include is what is exposed of render to outside world */
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+
+#define RE_MAXNAME 32
+
+/* only used as handle */
+typedef struct Render Render;
+
+/* Render Result usage:
+
+- render engine allocates/frees and delivers raw floating point rects
+- right now it's full rects, but might become tiles or file
+- the display client has to allocate display rects, sort out what to display,
+ and how it's converted
+*/
+
+typedef struct RenderPass {
+ struct RenderPass *next, *prev;
+ int passtype, channels;
+ char name[16]; /* amount defined in openexr_multi.h */
+ char chan_id[8]; /* amount defined in openexr_multi.h */
+ float *rect;
+} RenderPass;
+
+/* a renderlayer is a full image, but with all passes and samples */
+/* size of the rects is defined in RenderResult */
+/* after render, the Combined pass is in rectf, for renderlayers read from files it is a real pass */
+typedef struct RenderLayer {
+ struct RenderLayer *next, *prev;
+
+ /* copy of RenderData */
+ char name[RE_MAXNAME];
+ unsigned int lay;
+ int layflag, passflag, pass_xor;
+
+ struct Material *mat_override;
+ struct Group *light_override;
+
+ float *rectf; /* 4 float, standard rgba buffer (read not above!) */
+ float *acolrect; /* 4 float, optional transparent buffer, needs storage for display updates */
+
+ ListBase passes;
+
+} RenderLayer;
+
+typedef struct RenderResult {
+
+ /* target image size */
+ int rectx, recty;
+ short crop, pad;
+
+ /* optional, 32 bits version of picture, used for ogl render and image curves */
+ int *rect32;
+ /* if this exists, a copy of one of layers, or result of composited layers */
+ float *rectf;
+ /* if this exists, a copy of one of layers, or result of composited layers */
+ float *rectz;
+
+ /* coordinates within final image (after cropping) */
+ rcti tilerect;
+ /* offset to apply to get a border render in full image */
+ int xof, yof;
+
+ /* the main buffers */
+ ListBase layers;
+
+ /* allowing live updates: */
+ volatile rcti renrect;
+ volatile RenderLayer *renlay;
+
+ /* optional saved endresult on disk */
+ char exrfile[FILE_MAXDIR];
+ void *exrhandle;
+
+ /* for render results in Image, verify validity for sequences */
+ int framenr;
+
+} RenderResult;
+
+typedef struct RenderStats {
+ int totface, totvert, tothalo, totlamp, totpart;
+ short curfield, curblur, curpart, partsdone, convertdone;
+ double starttime, lastframetime;
+ char *infostr;
+
+} RenderStats;
+
+/* *********************** API ******************** */
+
+/* the name is used as identifier, so elsewhere in blender the result can retrieved */
+/* calling a new render with same name, frees automatic existing render */
+struct Render *RE_NewRender (const char *name);
+struct Render *RE_GetRender(const char *name);
+
+/* use free render as signal to do everything over (previews) */
+void RE_FreeRender (struct Render *re);
+/* only called on exit */
+void RE_FreeAllRender (void);
+
+/* get results and statistics */
+void RE_FreeRenderResult(struct RenderResult *rr);
+struct RenderResult *RE_GetResult(struct Render *re);
+void RE_GetResultImage(struct Render *re, struct RenderResult *rr);
+struct RenderStats *RE_GetStats(struct Render *re);
+void RE_ResultGet32(struct Render *re, unsigned int *rect);
+struct RenderLayer *RE_GetRenderLayer(struct RenderResult *rr, const char *name);
+float *RE_RenderLayerGetPass(struct RenderLayer *rl, int passtype);
+
+/* obligatory initialize call, disprect is optional */
+void RE_InitState (struct Render *re, struct RenderData *rd, int winx, int winy, rcti *disprect);
+
+/* use this to change disprect of active render */
+void RE_SetDispRect (struct Render *re, rcti *disprect);
+
+/* set up the viewplane/perspective matrix, three choices */
+void RE_SetCamera(struct Render *re, struct Object *camera);
+void RE_SetWindow (struct Render *re, rctf *viewplane, float clipsta, float clipend);
+void RE_SetOrtho (struct Render *re, rctf *viewplane, float clipsta, float clipend);
+void RE_SetPixelSize(struct Render *re, float pixsize);
+
+/* option to set viewmatrix before making dbase */
+void RE_SetView (struct Render *re, float mat[][4]);
+
+/* make or free the dbase */
+void RE_Database_FromScene(struct Render *re, struct Scene *scene, int use_camera_view);
+void RE_Database_Free (struct Render *re);
+
+/* project dbase again, when viewplane/perspective changed */
+void RE_DataBase_ApplyWindow(struct Render *re);
+
+/* override the scene setting for amount threads, commandline */
+void RE_set_max_threads(int threads);
+
+/* the main processor, assumes all was set OK! */
+void RE_TileProcessor(struct Render *re, int firsttile, int threaded);
+
+/* only RE_NewRender() needed, main Blender render calls */
+void RE_BlenderFrame(struct Render *re, struct Scene *scene, int frame);
+void RE_BlenderAnim(struct Render *re, struct Scene *scene, int sfra, int efra);
+
+void RE_ReadRenderResult(struct Scene *scene, struct Scene *scenode);
+void RE_WriteRenderResult(RenderResult *rr, char *filename, int compress);
+struct RenderResult *RE_MultilayerConvert(void *exrhandle, int rectx, int recty);
+
+/* ancient stars function... go away! */
+void RE_make_stars(struct Render *re, void (*initfunc)(void),
+ void (*vertexfunc)(float*), void (*termfunc)(void));
+
+/* display and event callbacks */
+void RE_display_init_cb (struct Render *re, void (*f)(RenderResult *rr));
+void RE_display_clear_cb(struct Render *re, void (*f)(RenderResult *rr));
+void RE_display_draw_cb (struct Render *re, void (*f)(RenderResult *rr, volatile struct rcti *rect));
+void RE_stats_draw_cb (struct Render *re, void (*f)(RenderStats *rs));
+void RE_timecursor_cb (struct Render *re, void (*f)(int));
+void RE_test_break_cb (struct Render *re, int (*f)(void));
+void RE_test_return_cb (struct Render *re, int (*f)(void));
+void RE_error_cb (struct Render *re, void (*f)(char *str));
+
+/* should move to kernel once... still unsure on how/where */
+float RE_filter_value(int type, float x);
+/* vector blur zbuffer method */
+void RE_zbuf_accumulate_vecblur(struct NodeBlurData *nbd, int xsize, int ysize, float *newrect, float *imgrect, float *vecbufrect, float *zbufrect);
+
+/* shaded view or baking options */
+#define RE_BAKE_LIGHT 0
+#define RE_BAKE_ALL 1
+#define RE_BAKE_AO 2
+#define RE_BAKE_NORMALS 3
+#define RE_BAKE_TEXTURE 4
+void RE_Database_Baking(struct Render *re, struct Scene *scene, int type);
+
+void RE_DataBase_GetView(struct Render *re, float mat[][4]);
+
+#endif /* RE_PIPELINE_H */
+
diff --git a/source/blender/render/extern/include/RE_raytrace.h b/source/blender/render/extern/include/RE_raytrace.h
new file mode 100644
index 00000000000..095ffcf0c18
--- /dev/null
+++ b/source/blender/render/extern/include/RE_raytrace.h
@@ -0,0 +1,90 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2007 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ * RE_raytrace.h: ray tracing api, can be used independently from the renderer.
+ */
+
+#ifndef RE_RAYTRACE_H
+#define RE_RAYTRACE_H
+
+/* ray types */
+#define RE_RAY_SHADOW 0
+#define RE_RAY_MIRROR 1
+#define RE_RAY_SHADOW_TRA 2
+
+/* spatial tree for raytracing acceleration */
+typedef void RayTree;
+/* abstraction of face type */
+typedef void RayFace;
+
+/* struct for intersection data */
+typedef struct Isect {
+ float start[3]; /* start+vec = end, in ray_tree_intersect */
+ float vec[3];
+ float end[3];
+
+ float labda, u, v; /* distance to hitpoint, uv weights */
+
+ RayFace *face; /* face is where to intersect with */
+ RayFace *faceorig; /* start face */
+ RayFace *face_last; /* for shadow optimize, last intersected face */
+
+ short isect; /* which half of quad */
+ short mode; /* RE_RAYSHADOW, RE_RAYMIRROR, RE_RAYSHADOW_TRA */
+ int lay; /* -1 default, set for layer lamps */
+
+ /* only used externally */
+ float col[4]; /* RGBA for shadow_tra */
+
+ /* octree only */
+ RayFace *facecontr;
+ float ddalabda;
+ short faceisect; /* flag if facecontr was done or not */
+} Isect;
+
+/* function callbacks for face type abstraction */
+typedef void (*RayCoordsFunc)(RayFace *face,
+ float **v1, float **v2, float **v3, float **v4);
+typedef int (*RayCheckFunc)(Isect *is, RayFace *face);
+
+/* tree building and freeing */
+RayTree *RE_ray_tree_create(int ocres, int totface, float *min, float *max,
+ RayCoordsFunc coordfunc, RayCheckFunc checkfunc);
+void RE_ray_tree_add_face(RayTree *tree, RayFace *face);
+void RE_ray_tree_done(RayTree *tree);
+void RE_ray_tree_free(RayTree *tree);
+
+/* intersection with full tree and single face */
+int RE_ray_tree_intersect(RayTree *tree, Isect *is);
+int RE_ray_face_intersection(Isect *is, RayCoordsFunc coordsfunc);
+
+/* retrieve the diameter of the tree structure, for setting intersection
+ end distance */
+float RE_ray_tree_max_size(RayTree *tree);
+
+#endif /*__RE_RAYTRACE_H__*/
+
diff --git a/source/blender/render/extern/include/RE_render_ext.h b/source/blender/render/extern/include/RE_render_ext.h
new file mode 100644
index 00000000000..910be84b795
--- /dev/null
+++ b/source/blender/render/extern/include/RE_render_ext.h
@@ -0,0 +1,57 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 by Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef RE_RENDER_EXT_H
+#define RE_RENDER_EXT_H
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+/* this include is for non-render pipeline exports (still old cruft here) */
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* called by meshtools */
+void RE_make_sticky(void);
+
+/* for radiosity module */
+struct RadView;
+struct RNode;
+struct Render;
+struct MTex;
+struct ImBuf;
+
+void RE_zbufferall_radio(struct RadView *vw, struct RNode **rg_elem, int rg_totelem, struct Render *re);
+
+/* effect.c, editmesh_modes.c and brush.c, returns 1 if rgb, 0 otherwise */
+int externtex(struct MTex *mtex, float *vec, float *tin, float *tr, float *tg, float *tb, float *ta);
+
+/* node_composite.c */
+void ibuf_sample(struct ImBuf *ibuf, float fx, float fy, float dx, float dy, float *result);
+void antialias_tagbuf(int xsize, int ysize, char *rectmove);
+
+#endif /* RE_RENDER_EXT_H */
+
diff --git a/source/blender/render/extern/include/RE_shader_ext.h b/source/blender/render/extern/include/RE_shader_ext.h
new file mode 100644
index 00000000000..364535736ae
--- /dev/null
+++ b/source/blender/render/extern/include/RE_shader_ext.h
@@ -0,0 +1,182 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 by Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef RE_SHADER_EXT_H
+#define RE_SHADER_EXT_H
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+/* this include is for shading and texture exports */
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* localized texture result data */
+/* note; tr tg tb ta has to remain in this order */
+typedef struct TexResult {
+ float tin, tr, tg, tb, ta;
+ int talpha;
+ float *nor;
+} TexResult;
+
+/* localized shade result data */
+typedef struct ShadeResult
+{
+ float combined[4];
+ float col[4];
+ float alpha;
+ float diff[3]; /* no ramps, shadow, etc */
+ float spec[3];
+ float shad[3];
+ float ao[3];
+ float refl[3];
+ float refr[3];
+ float nor[3];
+ float rad[3];
+ float winspeed[4];
+} ShadeResult;
+
+/* only here for quick copy */
+struct ShadeInputCopy {
+
+ struct Material *mat;
+ struct VlakRen *vlr;
+ int facenr;
+ float facenor[3]; /* copy from face */
+ struct VertRen *v1, *v2, *v3; /* vertices can be in any order for quads... */
+ short i1, i2, i3; /* original vertex indices */
+ short puno;
+ short osatex;
+ float vn[3], vno[3]; /* actual render normal, and a copy to restore it */
+ float n1[3], n2[3], n3[3]; /* vertex normals, corrected */
+ int mode; /* base material mode (OR-ed result of entire node tree) */
+};
+
+typedef struct ShadeInputUV {
+ float dxuv[3], dyuv[3], uv[3];
+ char *name;
+} ShadeInputUV;
+
+typedef struct ShadeInputCol {
+ float col[3];
+ char *name;
+} ShadeInputCol;
+
+/* localized renderloop data */
+typedef struct ShadeInput
+{
+ /* copy from face, also to extract tria from quad */
+ /* note it mirrors a struct above for quick copy */
+
+ struct Material *mat;
+ struct VlakRen *vlr;
+ int facenr;
+ float facenor[3]; /* copy from face */
+ struct VertRen *v1, *v2, *v3; /* vertices can be in any order for quads... */
+ short i1, i2, i3; /* original vertex indices */
+ short puno;
+ short osatex;
+ float vn[3], vno[3]; /* actual render normal, and a copy to restore it */
+ float n1[3], n2[3], n3[3]; /* vertex normals, corrected */
+ int mode; /* base material mode (OR-ed result of entire node tree) */
+
+ /* internal face coordinates */
+ float u, v, dx_u, dx_v, dy_u, dy_v;
+ float co[3], view[3];
+
+ /* copy from material, keep synced so we can do memcopy */
+ /* current size: 23*4 */
+ float r, g, b;
+ float specr, specg, specb;
+ float mirr, mirg, mirb;
+ float ambr, ambb, ambg;
+
+ float amb, emit, ang, spectra, ray_mirror;
+ float alpha, refl, spec, zoffs, add;
+ float translucency;
+ /* end direct copy from material */
+
+ /* individual copies: */
+ int har;
+ float layerfac;
+
+ /* texture coordinates */
+ float lo[3], gl[3], ref[3], orn[3], winco[3], sticky[3], vcol[3], rad[3];
+ float refcol[4], displace[3];
+ float strand, tang[3], stress, winspeed[4];
+
+ ShadeInputUV uv[8]; /* 8 = MAX_MTFACE */
+ ShadeInputCol col[8]; /* 8 = MAX_MCOL */
+ int totuv, totcol;
+
+ /* dx/dy OSA coordinates */
+ float dxco[3], dyco[3];
+ float dxlo[3], dylo[3], dxgl[3], dygl[3];
+ float dxref[3], dyref[3], dxorn[3], dyorn[3];
+ float dxno[3], dyno[3], dxview, dyview;
+ float dxlv[3], dylv[3];
+ float dxwin[3], dywin[3];
+ float dxsticky[3], dysticky[3];
+ float dxrefract[3], dyrefract[3];
+ float dxstrand, dystrand;
+
+ /* AO is a pre-process now */
+ float ao[3];
+
+ int xs, ys; /* pixel to be rendered */
+ int mask; /* subsample mask */
+ int samplenr; /* sample counter, to detect if we should do shadow again */
+ int depth; /* 1 or larger on raytrace shading */
+
+ /* stored copy of original face normal (facenor)
+ * before flipping. Used in Front/back output on geometry node */
+ float orignor[3];
+
+ /* from initialize, part or renderlayer */
+ short do_preview; /* for nodes, in previewrender */
+ short thread, sample; /* sample: ShadeSample array index */
+ unsigned int lay;
+ int layflag, passflag, combinedflag;
+ struct Group *light_override;
+ struct Material *mat_override;
+
+} ShadeInput;
+
+
+/* node shaders... */
+struct Tex;
+int multitex_ext(struct Tex *tex, float *texvec, float *dxt, float *dyt, int osatex, struct TexResult *texres);
+
+/* shaded view and bake */
+struct Render;
+struct Image;
+
+void RE_shade_external(struct Render *re, struct ShadeInput *shi, struct ShadeResult *shr);
+int RE_bake_shade_all_selected(struct Render *re, int type);
+struct Image *RE_bake_shade_get_image(void);
+
+#endif /* RE_SHADER_EXT_H */
+
diff --git a/source/blender/render/intern/Makefile b/source/blender/render/intern/Makefile
new file mode 100644
index 00000000000..ee9969a76c8
--- /dev/null
+++ b/source/blender/render/intern/Makefile
@@ -0,0 +1,37 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+# Bounces make to subdirectories.
+
+SOURCEDIR = source/blender/render/intern
+DIRS = source
+
+include nan_subdirs.mk
diff --git a/source/blender/render/intern/include/envmap.h b/source/blender/render/intern/include/envmap.h
new file mode 100644
index 00000000000..32d72555ca4
--- /dev/null
+++ b/source/blender/render/intern/include/envmap.h
@@ -0,0 +1,51 @@
+/*
+ * envmap_ext.h
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef ENVMAP_EXT_H
+#define ENVMAP_EXT_H
+
+/**
+ * Make environment maps for all objects in the scene that have an
+ * environment map as texture.
+ * (initrender.c)
+ */
+
+struct Render;
+struct TexResult;
+
+void make_envmaps(struct Render *re);
+int envmaptex(struct Tex *tex, float *texvec, float *dxt, float *dyt, int osatex, struct TexResult *texres);
+
+#endif /* ENVMAP_EXT_H */
+
diff --git a/source/blender/render/intern/include/gammaCorrectionTables.h b/source/blender/render/intern/include/gammaCorrectionTables.h
new file mode 100644
index 00000000000..3d0928f84a3
--- /dev/null
+++ b/source/blender/render/intern/include/gammaCorrectionTables.h
@@ -0,0 +1,54 @@
+/*
+ * gammacorrectiontables.h
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef GAMMACORRECTIONTABLES_H
+#define GAMMACORRECTIONTABLES_H
+
+/**
+ * Initialise the gamma lookup tables
+ */
+void makeGammaTables(float gamma);
+
+/**
+ * Apply gamma correction on col
+ */
+float gammaCorrect(float col);
+
+/**
+ * Apply inverse gamma correction on col
+ */
+float invGammaCorrect(float col);
+
+#endif
+
diff --git a/source/blender/render/intern/include/initrender.h b/source/blender/render/intern/include/initrender.h
new file mode 100644
index 00000000000..9a94d193990
--- /dev/null
+++ b/source/blender/render/intern/include/initrender.h
@@ -0,0 +1,52 @@
+/*
+ * initrender_ext.h
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef INITRENDER_H
+#define INITRENDER_H
+
+struct Object;
+
+/* Functions */
+
+void free_sample_tables(Render *re);
+void make_sample_tables(Render *re);
+
+void render_scene_set_window(Render *re, struct Object *camera, int blursample);
+
+void initparts(Render *re);
+void freeparts(Render *re);
+
+
+#endif /* INITRENDER_H */
+
diff --git a/source/blender/render/intern/include/pixelblending.h b/source/blender/render/intern/include/pixelblending.h
new file mode 100644
index 00000000000..04c5a3977a3
--- /dev/null
+++ b/source/blender/render/intern/include/pixelblending.h
@@ -0,0 +1,68 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): 2004-2006 Blender Foundation, full recode
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef PIXELBLENDING_EXT_H
+#define PIXELBLENDING_EXT_H
+
+
+/**
+* add 1 pixel to into filtered three lines
+ * (float vecs to float vec)
+ */
+void add_filt_fmask(unsigned int mask, float *col, float *rowbuf, int row_w);
+void add_filt_fmask_pixsize(unsigned int mask, float *in, float *rowbuf, int row_w, int pixsize);
+
+/**
+ * Alpha-over blending for floats.
+ */
+void addAlphaOverFloat(float *dest, float *source);
+
+/**
+ * Alpha-under blending for floats.
+ */
+void addAlphaUnderFloat(float *dest, float *source);
+
+
+/**
+ * Same for floats
+ */
+void addalphaAddfacFloat(float *dest, float *source, char addfac);
+
+/**
+ * dest = dest + source
+ */
+void addalphaAddFloat(float *dest, float *source);
+
+/**
+ * Blend bron under doel, while doing gamma correction
+ */
+void addalphaUnderGammaFloat(float *doel, float *bron);
+
+
+
+#endif /* PIXELBLENDING_EXT_H */
+
diff --git a/source/blender/render/intern/include/pixelshading.h b/source/blender/render/intern/include/pixelshading.h
new file mode 100644
index 00000000000..d2235784a59
--- /dev/null
+++ b/source/blender/render/intern/include/pixelshading.h
@@ -0,0 +1,62 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): 2004-2006, Blender Foundation, full recode
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/* pixelshading.h
+*
+* These functions determine what actual color a pixel will have.
+*/
+
+
+#ifndef PIXELSHADING_H
+#define PIXELSHADING_H
+
+/**
+ * Render the pixel at (x,y) for object ap. Apply the jitter mask.
+ * Output is given in float collector[4]. The type vector:
+ * t[0] - min. distance
+ * t[1] - face/halo index
+ * t[2] - jitter mask
+ * t[3] - type ZB_POLY or ZB_HALO
+ * t[4] - max. distance
+ * mask is pixel coverage in bits
+ * @return pointer to the object
+ */
+void shadeHaloFloat(HaloRen *har,
+ float *col, int zz,
+ float dist, float xn,
+ float yn, short flarec);
+
+/**
+ * Render the sky at pixel (x, y).
+ */
+void shadeSkyPixel(float *collector, float fx, float fy);
+void shadeSkyView(float *colf, float *rco, float *view, float *dxyview);
+
+/* ------------------------------------------------------------------------- */
+
+#endif
+
diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h
new file mode 100644
index 00000000000..abcdf417b62
--- /dev/null
+++ b/source/blender/render/intern/include/render_types.h
@@ -0,0 +1,420 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): (c) 2006 Blender Foundation, full refactor
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef RENDER_TYPES_H
+#define RENDER_TYPES_H
+
+/* ------------------------------------------------------------------------- */
+/* exposed internal in render module only! */
+/* ------------------------------------------------------------------------- */
+
+#include "DNA_color_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_world_types.h"
+#include "DNA_object_types.h"
+#include "DNA_vec_types.h"
+
+#include "BLI_threads.h"
+
+#include "RE_pipeline.h"
+#include "RE_shader_ext.h" /* TexResult, ShadeResult, ShadeInput */
+
+struct Object;
+struct MemArena;
+struct VertTableNode;
+struct VlakTableNode;
+struct GHash;
+
+#define TABLEINITSIZE 1024
+#define LAMPINITSIZE 256
+
+typedef struct SampleTables
+{
+ float centLut[16];
+ float *fmask1[9], *fmask2[9];
+ char cmask[256], *centmask;
+
+} SampleTables;
+
+typedef struct QMCSampler
+{
+ int type;
+ int tot;
+ double *samp2d;
+ double offs[BLENDER_MAX_THREADS][2];
+} QMCSampler;
+
+#define SAMP_TYPE_JITTERED 0
+#define SAMP_TYPE_HALTON 1
+#define SAMP_TYPE_HAMMERSLEY 2
+
+/* this is handed over to threaded hiding/passes/shading engine */
+typedef struct RenderPart
+{
+ struct RenderPart *next, *prev;
+
+ /* result of part rendering */
+ RenderResult *result;
+
+ int *rectp; /* polygon index table */
+ int *rectz; /* zbuffer */
+ long *rectdaps; /* delta acum buffer for pixel structs */
+ int *rectbackp; /* polygon index table for backside sss */
+ int *rectbackz; /* zbuffer for backside sss */
+ long *rectall; /* buffer for all faces for sss */
+
+ rcti disprect; /* part coordinates within total picture */
+ int rectx, recty; /* the size */
+ short crop, ready; /* crop is amount of pixels we crop, for filter */
+ short sample, nr; /* sample can be used by zbuffers, nr is partnr */
+ short thread; /* thread id */
+
+ char *clipflag; /* clipflags for part zbuffering */
+} RenderPart;
+
+/* controls state of render, everything that's read-only during render stage */
+struct Render
+{
+ struct Render *next, *prev;
+ char name[RE_MAXNAME];
+
+ /* state settings */
+ short flag, osa, ok, do_gamma;
+
+ /* result of rendering */
+ RenderResult *result;
+ /* if render with single-layer option, other rendered layers are stored here */
+ RenderResult *pushedresult;
+
+ /* window size, display rect, viewplane */
+ int winx, winy;
+ rcti disprect; /* part within winx winy */
+ rctf viewplane; /* mapped on winx winy */
+ float viewdx, viewdy; /* size of 1 pixel */
+ float clipcrop; /* 2 pixel boundary to prevent clip when filter used */
+
+ /* final picture width and height (within disprect) */
+ int rectx, recty;
+
+ /* real maximum amount of xparts/yparts after correction for minimum */
+ int xparts, yparts;
+ /* real maximum size of parts after correction for minimum
+ partx*xparts can be larger than rectx, in that case last part is smaller */
+ int partx, party;
+
+ /* values for viewing */
+ float lens, ycor, viewfac;
+ float panophi, panosi, panoco, panodxp, panodxv;
+
+ /* Matrices */
+ float grvec[3]; /* for world */
+ float imat[3][3]; /* copy of viewinv */
+ float viewmat[4][4], viewinv[4][4];
+ float winmat[4][4];
+
+ /* clippping */
+ float clipsta;
+ float clipend;
+
+ /* samples */
+ SampleTables *samples;
+ float jit[32][2];
+ QMCSampler *qsa;
+
+ /* scene, and its full copy of renderdata and world */
+ Scene *scene;
+ RenderData r;
+ World wrld;
+
+ ListBase parts;
+
+ /* octree tables and variables for raytrace */
+ void *raytree;
+
+ /* use this instead of R.r.cfra */
+ float cfra;
+
+ /* render database */
+ int totvlak, totvert, tothalo, totlamp;
+ ListBase lights; /* GroupObject pointers */
+ ListBase lampren; /* storage, for free */
+
+ int vertnodeslen;
+ struct VertTableNode *vertnodes;
+ int vlaknodeslen;
+ struct VlakTableNode *vlaknodes;
+ int blohalen;
+ struct HaloRen **bloha;
+ ListBase objecttable;
+
+ struct Image *backbuf, *bakebuf;
+
+ struct GHash *orco_hash;
+
+ struct GHash *sss_hash;
+ ListBase *sss_points;
+ struct Material *sss_mat;
+
+ ListBase customdata_names;
+
+ /* arena for allocating data for use during render, for
+ * example dynamic TFaces to go in the VlakRen structure.
+ */
+ struct MemArena *memArena;
+
+ /* callbacks */
+ void (*display_init)(RenderResult *rr);
+ void (*display_clear)(RenderResult *rr);
+ void (*display_draw)(RenderResult *rr, volatile rcti *rect);
+
+ void (*stats_draw)(RenderStats *ri);
+ void (*timecursor)(int i);
+
+ int (*test_break)(void);
+ int (*test_return)(void);
+ void (*error)(char *str);
+
+ RenderStats i;
+};
+
+/* ------------------------------------------------------------------------- */
+
+struct ISBData;
+
+typedef struct ShadSampleBuf {
+ struct ShadSampleBuf *next, *prev;
+ long *zbuf;
+ char *cbuf;
+} ShadSampleBuf;
+
+typedef struct ShadBuf {
+ /* regular shadowbuffer */
+ short samp, shadhalostep, totbuf;
+ float persmat[4][4];
+ float viewmat[4][4];
+ float winmat[4][4];
+ float *jit, *weight;
+ float d, clipend, pixsize, soft;
+ int co[3];
+ int size, bias;
+ ListBase buffers;
+
+ /* irregular shadowbufer, result stored per thread */
+ struct ISBData *isb_result[BLENDER_MAX_THREADS];
+} ShadBuf;
+
+/* ------------------------------------------------------------------------- */
+/* lookup of objects in database */
+typedef struct ObjectRen {
+ struct ObjectRen *next, *prev;
+ struct Object *ob, *par;
+ int index, startvert, endvert, startface, endface;
+ float *vectors;
+} ObjectRen;
+
+/* ------------------------------------------------------------------------- */
+
+typedef struct VertRen
+{
+ float co[3];
+ float n[3];
+ float ho[4];
+ float *orco;
+ short clip;
+ unsigned short flag; /* in use for clipping zbuffer parts, temp setting stuff in convertblender.c */
+ float accum; /* accum for radio weighting, and for strand texco static particles */
+ int index; /* index allows extending vertren with any property */
+} VertRen;
+
+/* ------------------------------------------------------------------------- */
+
+struct halosort {
+ struct HaloRen *har;
+ int z;
+};
+
+/* ------------------------------------------------------------------------- */
+struct Material;
+struct MTFace;
+
+typedef struct RadFace {
+ float unshot[3], totrad[3];
+ float norm[3], cent[3], area;
+ int flag;
+} RadFace;
+
+typedef struct VlakRen {
+ struct VertRen *v1, *v2, *v3, *v4; /* keep in order for ** addressing */
+ unsigned int lay;
+ float n[3];
+ struct Material *mat;
+ char noflag, puno;
+ char flag, ec;
+ RadFace *radface;
+ Object *ob;
+ int index;
+} VlakRen;
+
+typedef struct HaloRen
+{
+ short miny, maxy;
+ float alfa, xs, ys, rad, radsq, sin, cos, co[3], no[3];
+ float hard, b, g, r;
+ int zs, zd;
+ int zBufDist; /* depth in the z-buffer coordinate system */
+ char starpoints, type, add, tex;
+ char linec, ringc, seed;
+ short flarec; /* used to be a char. why ?*/
+ float hasize;
+ int pixels;
+ unsigned int lay;
+ struct Material *mat;
+} HaloRen;
+
+struct LampRen;
+struct MTex;
+
+/**
+ * For each lamp in a scene, a LampRen is created. It determines the
+ * properties of a lightsource.
+ */
+
+typedef struct LampShadowSubSample {
+ int samplenr;
+ float shadfac[4]; /* rgba shadow */
+} LampShadowSubSample;
+
+typedef struct LampShadowSample {
+ LampShadowSubSample s[16]; /* MAX OSA */
+} LampShadowSample;
+
+typedef struct LampRen {
+ struct LampRen *next, *prev;
+
+ float xs, ys, dist;
+ float co[3];
+ short type, mode;
+ float r, g, b, k;
+ float energy, haint;
+ int lay;
+ float spotsi,spotbl;
+ float vec[3];
+ float xsp, ysp, distkw, inpr;
+ float halokw, halo;
+
+ short falloff_type;
+ float ld1,ld2;
+ struct CurveMapping *curfalloff;
+
+ /* copied from Lamp, to decouple more rendering stuff */
+ /** Size of the shadowbuffer */
+ short bufsize;
+ /** Number of samples for the shadows */
+ short samp;
+ /** Softness factor for shadow */
+ float soft;
+ /** amount of subsample buffers and type of filter for sampling */
+ short buffers, filtertype;
+ /** shadow buffer type (regular, irregular) */
+ short buftype;
+ /** autoclip */
+ short bufflag;
+ /** shadow plus halo: detail level */
+ short shadhalostep;
+ /** Near clip of the lamp */
+ float clipsta;
+ /** Far clip of the lamp */
+ float clipend;
+ /** A small depth offset to prevent self-shadowing. */
+ float bias;
+
+ short ray_samp, ray_sampy, ray_sampz, ray_samp_method, ray_samp_type, area_shape, ray_totsamp;
+ short xold[BLENDER_MAX_THREADS], yold[BLENDER_MAX_THREADS]; /* last jitter table for area lights */
+ float area_size, area_sizey, area_sizez;
+ float adapt_thresh;
+
+ struct ShadBuf *shb;
+ float *jitter;
+ QMCSampler *qsa;
+
+ float imat[3][3];
+ float spottexfac;
+ float sh_invcampos[3], sh_zfac; /* sh_= spothalo */
+
+ float mat[3][3]; /* 3x3 part from lampmat x viewmat */
+ float area[8][3], areasize;
+
+ /* passes & node shader support: all shadow info for a pixel */
+ LampShadowSample *shadsamp;
+
+ /* yafray: photonlight params */
+ int YF_numphotons, YF_numsearch;
+ short YF_phdepth, YF_useqmc, YF_bufsize;
+ float YF_causticblur, YF_ltradius;
+ float YF_glowint, YF_glowofs;
+ short YF_glowtype;
+
+ /* ray optim */
+ VlakRen *vlr_last[BLENDER_MAX_THREADS];
+
+ struct MTex *mtex[MAX_MTEX];
+} LampRen;
+
+/* **************** defines ********************* */
+
+/* R.r.mode flag is same as for renderdata */
+
+/* R.flag */
+#define R_ZTRA 1
+#define R_HALO 2
+#define R_SEC_FIELD 4
+#define R_LAMPHALO 8
+#define R_GLOB_NOPUNOFLIP 16
+
+/* vlakren->flag (vlak = face in dutch) char!!! */
+#define R_SMOOTH 1
+#define R_VISIBLE 2
+/* strand flag, means special handling */
+#define R_STRAND 4
+#define R_NOPUNOFLIP 8
+#define R_FULL_OSA 16
+#define R_FACE_SPLIT 32
+/* Tells render to divide face other way. */
+#define R_DIVIDE_24 64
+/* vertex normals are tangent or view-corrected vector, for hair strands */
+#define R_TANGENT 128
+
+/* vlakren->noflag (char) */
+#define R_SNPROJ_X 1
+#define R_SNPROJ_Y 2
+#define R_SNPROJ_Z 4
+#define R_FLIPPED_NO 8
+
+
+
+#endif /* RENDER_TYPES_H */
+
diff --git a/source/blender/render/intern/include/rendercore.h b/source/blender/render/intern/include/rendercore.h
new file mode 100644
index 00000000000..0d807d56180
--- /dev/null
+++ b/source/blender/render/intern/include/rendercore.h
@@ -0,0 +1,108 @@
+/*
+ * rendercore_ext.h
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef RENDERCORE_H
+#define RENDERCORE_H
+
+#include "render_types.h"
+
+
+/* vector defines */
+
+#define CROSS(dest, a, b) dest[0]= a[1] * b[2] - a[2] * b[1]; dest[1]= a[2] * b[0] - a[0] * b[2]; dest[2]= a[0] * b[1] - a[1] * b[0]
+#define VECMUL(dest, f) dest[0]*= f; dest[1]*= f; dest[2]*= f
+
+struct HaloRen;
+struct ShadeInput;
+struct ShadeResult;
+struct World;
+struct RenderPart;
+struct RenderLayer;
+
+/* ------------------------------------------------------------------------- */
+
+typedef struct PixStr
+{
+ struct PixStr *next;
+ int facenr, z;
+ unsigned short mask;
+ short shadfac;
+} PixStr;
+
+typedef struct PixStrMain
+{
+ struct PixStrMain *next, *prev;
+ struct PixStr *ps;
+ int counter;
+} PixStrMain;
+
+/* ------------------------------------------------------------------------- */
+
+
+void calc_view_vector(float *view, float x, float y);
+float mistfactor(float zcor, float *co); /* dist and height, return alpha */
+
+void renderspothalo(struct ShadeInput *shi, float *col, float alpha);
+void add_halo_flare(Render *re);
+
+void calc_renderco_zbuf(float *co, float *view, int z);
+void calc_renderco_ortho(float *co, float x, float y, int z);
+
+int count_mask(unsigned short mask);
+
+void zbufshade(void);
+void zbufshadeDA(void); /* Delta Accum Pixel Struct */
+
+void zbufshade_tile(struct RenderPart *pa);
+void zbufshadeDA_tile(struct RenderPart *pa);
+
+void zbufshade_sss_tile(struct RenderPart *pa);
+
+/* -------- ray.c ------- */
+
+extern void freeraytree(Render *re);
+extern void makeraytree(Render *re);
+
+extern void ray_shadow(ShadeInput *, LampRen *, float *);
+extern void ray_trace(ShadeInput *, ShadeResult *);
+extern void ray_ao(ShadeInput *, float *);
+extern void init_jitter_plane(LampRen *lar);
+extern void init_ao_sphere(struct World *wrld);
+extern void init_lamp_hammersley(LampRen *lar);
+extern void free_lamp_qmcsampler(LampRen *lar);
+extern void init_render_hammersley(Render *re);
+extern void free_render_qmcsampler(Render *re);
+
+#endif /* RENDER_EXT_H */
+
diff --git a/source/blender/render/intern/include/renderdatabase.h b/source/blender/render/intern/include/renderdatabase.h
new file mode 100644
index 00000000000..75aea05fee2
--- /dev/null
+++ b/source/blender/render/intern/include/renderdatabase.h
@@ -0,0 +1,116 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef RENDERDATABASE_H
+#define RENDERDATABASE_H
+
+struct Object;
+struct VlakRen;
+struct VertRen;
+struct HaloRen;
+struct Material;
+struct Render;
+struct MCol;
+struct MTFace;
+struct CustomData;
+
+#define RE_QUAD_MASK 0x7FFFFFF
+#define RE_QUAD_OFFS 0x8000000
+
+/* render allocates totvert/256 of these nodes, for lookup and quick alloc */
+typedef struct VertTableNode {
+ struct VertRen *vert;
+ float *rad;
+ float *sticky;
+ float *strand;
+ float *tangent;
+ float *stress;
+ float *winspeed;
+} VertTableNode;
+
+typedef struct VlakTableNode {
+ struct VlakRen *vlak;
+ struct MTFace **mtface;
+ struct MCol **mcol;
+ int totmtface, totmcol;
+ struct CustomDataNames **names;
+} VlakTableNode;
+
+typedef struct CustomDataNames{
+ struct CustomDataNames *next, *prev;
+
+ char (*mtface)[32];
+ char (*mcol)[32];
+} CustomDataNames;
+
+/* renderdatabase.c */
+void free_renderdata_tables(struct Render *re);
+void free_renderdata_vertnodes(struct VertTableNode *vertnodes);
+void free_renderdata_vlaknodes(struct VlakTableNode *vlaknodes);
+
+void set_normalflags(Render *re);
+void project_renderdata(struct Render *re, void (*projectfunc)(float *, float mat[][4], float *), int do_pano, float xoffs);
+
+/* functions are not exported... so wrong names */
+
+struct VlakRen *RE_findOrAddVlak(struct Render *re, int nr);
+struct VertRen *RE_findOrAddVert(struct Render *re, int nr);
+struct HaloRen *RE_findOrAddHalo(struct Render *re, int nr);
+struct HaloRen *RE_inithalo(struct Render *re, struct Material *ma, float *vec, float *vec1, float *orco, float hasize,
+ float vectsize, int seed);
+void RE_addRenderObject(struct Render *re, struct Object *ob, struct Object *par, int index, int sve, int eve, int sfa, int efa);
+
+float *RE_vertren_get_sticky(struct Render *re, struct VertRen *ver, int verify);
+float *RE_vertren_get_stress(struct Render *re, struct VertRen *ver, int verify);
+float *RE_vertren_get_rad(struct Render *re, struct VertRen *ver, int verify);
+float *RE_vertren_get_strand(struct Render *re, struct VertRen *ver, int verify);
+float *RE_vertren_get_tangent(struct Render *re, struct VertRen *ver, int verify);
+float *RE_vertren_get_winspeed(struct Render *re, struct VertRen *ver, int verify);
+
+struct MTFace *RE_vlakren_get_tface(struct Render *re, VlakRen *ren, int n, char **name, int verify);
+struct MCol *RE_vlakren_get_mcol(struct Render *re, VlakRen *ren, int n, char **name, int verify);
+
+struct VertRen *RE_vertren_copy(struct Render *re, struct VertRen *ver);
+struct VlakRen *RE_vlakren_copy(struct Render *re, struct VlakRen *vlr);
+
+void RE_vlakren_set_customdata_names(struct Render *re, struct CustomData *data);
+
+/* haloren->type: flags */
+#define HA_ONLYSKY 1
+#define HA_VECT 2
+#define HA_XALPHA 4
+#define HA_FLARECIRC 8
+
+/* convertblender.c */
+void init_render_world(Render *re);
+void RE_Database_FromScene_Vectors(Render *re, struct Scene *sce);
+
+
+#endif /* RENDERDATABASE_H */
+
diff --git a/source/blender/render/intern/include/renderpipeline.h b/source/blender/render/intern/include/renderpipeline.h
new file mode 100644
index 00000000000..f52c8b02a5e
--- /dev/null
+++ b/source/blender/render/intern/include/renderpipeline.h
@@ -0,0 +1,43 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef PIPELINE_H
+#define PIPELINE_H
+
+struct Render;
+struct RenderResult;
+struct RenderLayer;
+
+struct RenderLayer *render_get_active_layer(struct Render *re, struct RenderResult *rr);
+float panorama_pixel_rot(struct Render *re);
+
+#define PASS_VECTOR_MAX 10000.0f
+
+#endif /* PIPELINE_H */
+
diff --git a/source/blender/render/intern/include/shadbuf.h b/source/blender/render/intern/include/shadbuf.h
new file mode 100644
index 00000000000..8b786c6e098
--- /dev/null
+++ b/source/blender/render/intern/include/shadbuf.h
@@ -0,0 +1,110 @@
+/*
+ * shadbuf_ext.h
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef SHADBUF_EXT_H
+#define SHADBUF_EXT_H
+
+#include "render_types.h"
+
+/**
+ * Calculates shadowbuffers for a vector of shadow-giving lamps
+ * @param lar The vector of lamps
+ */
+void makeshadowbuf(struct Render *re, LampRen *lar);
+void freeshadowbuf(struct LampRen *lar);
+
+/**
+ * Determines the shadow factor for a face and lamp. There is some
+ * communication with global variables here.
+ * @returns The shadow factors: 1.0 for no shadow, 0.0 for complete
+ * shadow.
+ * @param shb The shadowbuffer to find the shadow factor in.
+ * @param inp The inproduct between viewvector and ?
+ *
+ */
+float testshadowbuf(struct ShadBuf *shb, float *rco, float *dxco, float *dyco, float inp);
+
+/**
+ * Determines the shadow factor for lamp <lar>, between <p1>
+ * and <p2>. (Which CS?)
+ */
+float shadow_halo(LampRen *lar, float *p1, float *p2);
+
+/**
+ * Irregular shadowbuffer
+ */
+
+struct MemArena;
+struct APixstr;
+
+void ISB_create(RenderPart *pa, struct APixstr *apixbuf);
+void ISB_free(RenderPart *pa);
+float ISB_getshadow(ShadeInput *shi, ShadBuf *shb);
+
+/* data structures have to be accessible both in camview(x, y) as in lampview(x, y) */
+/* since they're created per tile rendered, speed goes over memory requirements */
+
+
+/* buffer samples, allocated in camera buffer and pointed to in lampbuffer nodes */
+typedef struct ISBSample {
+ float zco[3]; /* coordinate in lampview projection */
+ short *shadfac; /* initialized zero = full lighted */
+ int facenr; /* index in faces list */
+} ISBSample;
+
+/* transparent version of buffer sample */
+typedef struct ISBSampleA {
+ float zco[3]; /* coordinate in lampview projection */
+ short *shadfac; /* NULL = full lighted */
+ int facenr; /* index in faces list */
+ struct ISBSampleA *next; /* in end, we want the first items to align with ISBSample */
+} ISBSampleA;
+
+/* used for transparent storage only */
+typedef struct ISBShadfacA {
+ struct ISBShadfacA *next;
+ int facenr;
+ float shadfac;
+} ISBShadfacA;
+
+/* What needs to be stored to evaluate shadow, for each thread in ShadBuf */
+typedef struct ISBData {
+ short *shadfacs; /* simple storage for solid only */
+ ISBShadfacA **shadfaca;
+ struct MemArena *memarena;
+ int minx, miny, rectx, recty; /* copy from part disprect */
+} ISBData;
+
+#endif /* SHADBUF_EXT_H */
+
diff --git a/source/blender/render/intern/include/shading.h b/source/blender/render/intern/include/shading.h
new file mode 100644
index 00000000000..902899bce94
--- /dev/null
+++ b/source/blender/render/intern/include/shading.h
@@ -0,0 +1,83 @@
+/**
+* $Id:
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation
+ * All rights reserved.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+struct ShadeInput;
+struct ShadeResult;
+struct RenderPart;
+struct RenderLayer;
+struct PixStr;
+struct LampRen;
+
+/* shadeinput.c */
+
+#define RE_MAX_OSA 16
+
+/* needed to calculate shadow and AO for an entire pixel */
+typedef struct ShadeSample {
+ int tot; /* amount of shi in use, can be 1 for not FULL_OSA */
+
+ /* could be malloced once */
+ ShadeInput shi[RE_MAX_OSA];
+ ShadeResult shr[RE_MAX_OSA];
+
+ int samplenr; /* counter, detect shadow-reuse for shaders */
+} ShadeSample;
+
+
+ /* also the node shader callback */
+void shade_material_loop(struct ShadeInput *shi, struct ShadeResult *shr);
+
+void shade_input_set_triangle_i(struct ShadeInput *shi, struct VlakRen *vlr, short i1, short i2, short i3);
+void shade_input_set_triangle(struct ShadeInput *shi, volatile int facenr, int normal_flip);
+void shade_input_copy_triangle(struct ShadeInput *shi, struct ShadeInput *from);
+void shade_input_set_viewco(struct ShadeInput *shi, float x, float y, float z);
+void shade_input_set_uv(struct ShadeInput *shi);
+void shade_input_set_normals(struct ShadeInput *shi);
+void shade_input_set_shade_texco(struct ShadeInput *shi);
+void shade_input_do_shade(struct ShadeInput *shi, struct ShadeResult *shr);
+
+void shade_input_initialize(struct ShadeInput *shi, struct RenderPart *pa, struct RenderLayer *rl, int sample);
+
+void shade_sample_initialize(struct ShadeSample *ssamp, struct RenderPart *pa, struct RenderLayer *rl);
+void shade_samples_do_AO(struct ShadeSample *ssamp);
+int shade_samples(struct ShadeSample *ssamp, struct PixStr *ps, int x, int y);
+
+void vlr_set_uv_indices(struct VlakRen *vlr, int *i1, int *i2, int *i3);
+
+void calc_R_ref(struct ShadeInput *shi);
+
+
+/* shadeoutput. */
+void shade_lamp_loop(struct ShadeInput *shi, struct ShadeResult *shr);
+
+void shade_color(struct ShadeInput *shi, ShadeResult *shr);
+
+void ambient_occlusion_to_diffuse(struct ShadeInput *shi, float *diff);
+void ambient_occlusion(struct ShadeInput *shi);
+
+float lamp_get_visibility(struct LampRen *lar, float *co, float *lv, float *dist);
+void lamp_get_shadow(struct LampRen *lar, ShadeInput *shi, float inp, float *shadfac, int do_real);
+
+float fresnel_fac(float *view, float *vn, float fresnel, float fac);
diff --git a/source/blender/render/intern/include/sss.h b/source/blender/render/intern/include/sss.h
new file mode 100644
index 00000000000..660fb544227
--- /dev/null
+++ b/source/blender/render/intern/include/sss.h
@@ -0,0 +1,65 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2007 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef SSS_H
+#define SSS_H
+
+/* Generic multiple scattering API */
+
+struct ScatterSettings;
+typedef struct ScatterSettings ScatterSettings;
+
+struct ScatterTree;
+typedef struct ScatterTree ScatterTree;
+
+ScatterSettings *scatter_settings_new(float refl, float radius, float ior,
+ float reflfac, float frontweight, float backweight);
+void scatter_settings_free(ScatterSettings *ss);
+
+ScatterTree *scatter_tree_new(ScatterSettings *ss[3], float scale, float error,
+ float (*co)[3], float (*color)[3], float *area, int totpoint);
+void scatter_tree_build(ScatterTree *tree);
+void scatter_tree_sample(ScatterTree *tree, float *co, float *color);
+void scatter_tree_free(ScatterTree *tree);
+
+/* Internal renderer API */
+
+struct Render;
+struct Material;
+struct VlakRen;
+
+void make_sss_tree(struct Render *re);
+void sss_add_points(Render *re, float (*co)[3], float (*color)[3], float *area, int totpoint);
+void free_sss(struct Render *re);
+
+int sample_sss(struct Render *re, struct Material *mat, float *co, float *col);
+int has_sss_tree(struct Render *re, struct Material *mat);
+
+#endif /*SSS_H*/
+
diff --git a/source/blender/render/intern/include/texture.h b/source/blender/render/intern/include/texture.h
new file mode 100644
index 00000000000..9175145869c
--- /dev/null
+++ b/source/blender/render/intern/include/texture.h
@@ -0,0 +1,74 @@
+/*
+ * texture_ext.h
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef TEXTURE_EXT_H
+#define TEXTURE_EXT_H
+
+#define BRICONT texres->tin= (texres->tin-0.5)*tex->contrast+tex->bright-0.5; \
+if(texres->tin<0.0) texres->tin= 0.0; else if(texres->tin>1.0) texres->tin= 1.0;
+
+#define BRICONTRGB texres->tr= tex->rfac*((texres->tr-0.5)*tex->contrast+tex->bright-0.5); \
+if(texres->tr<0.0) texres->tr= 0.0; \
+texres->tg= tex->gfac*((texres->tg-0.5)*tex->contrast+tex->bright-0.5); \
+if(texres->tg<0.0) texres->tg= 0.0; \
+texres->tb= tex->bfac*((texres->tb-0.5)*tex->contrast+tex->bright-0.5); \
+if(texres->tb<0.0) texres->tb= 0.0;
+
+
+struct HaloRen;
+struct ShadeInput;
+struct TexResult;
+struct Tex;
+struct Image;
+struct ImBuf;
+
+/* texture.h */
+
+void do_halo_tex(struct HaloRen *har, float xn, float yn, float *colf);
+void do_sky_tex(float *rco, float *lo, float *dxyview, float *hor, float *zen, float *blend, int skyflag);
+void do_material_tex(struct ShadeInput *shi);
+void do_lamp_tex(LampRen *la, float *lavec, struct ShadeInput *shi, float *colf);
+
+void init_render_textures(Render *re);
+
+void render_realtime_texture(struct ShadeInput *shi, struct Image *ima);
+
+/* imagetexture.h */
+
+int imagewraposa(struct Tex *tex, struct Image *ima, struct ImBuf *ibuf, float *texvec, float *dxt, float *dyt, struct TexResult *texres);
+int imagewrap(struct Tex *tex, struct Image *ima, struct ImBuf *ibuf, float *texvec, struct TexResult *texres);
+void image_sample(struct Image *ima, float fx, float fy, float dx, float dy, float *result);
+
+#endif /* TEXTURE_EXT_H */
+
diff --git a/source/blender/render/intern/include/zbuf.h b/source/blender/render/intern/include/zbuf.h
new file mode 100644
index 00000000000..ed3f93adfdd
--- /dev/null
+++ b/source/blender/render/intern/include/zbuf.h
@@ -0,0 +1,111 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Full recode: 2004-2006 Blender Foundation
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef ZBUF_H
+#define ZBUF_H
+
+struct RenderPart;
+struct RenderLayer;
+struct LampRen;
+struct VlakRen;
+struct ListBase;
+
+void fillrect(int *rect, int x, int y, int val);
+
+/**
+ * Converts a world coordinate into a homogenous coordinate in view
+ * coordinates.
+ */
+void projectvert(float *v1, float winmat[][4], float *adr);
+void projectverto(float *v1, float winmat[][4], float *adr);
+int testclip(float *v);
+
+void set_part_zbuf_clipflag(struct RenderPart *pa);
+void zbuffer_shadow(struct Render *re, struct LampRen *lar, int *rectz, int size, float jitx, float jity);
+void zbuffer_solid(struct RenderPart *pa, unsigned int layer, short layflag);
+unsigned short *zbuffer_transp_shade(struct RenderPart *pa, struct RenderLayer *rl, float *pass);
+void convert_zbuf_to_distbuf(struct RenderPart *pa, struct RenderLayer *rl);
+void zbuffer_sss(RenderPart *pa, unsigned int lay, void *handle, void (*func)(void *, int, int, int, int));
+
+typedef struct APixstr {
+ unsigned short mask[4]; /* jitter mask */
+ int z[4]; /* distance */
+ int p[4]; /* index */
+ short shadfac[4]; /* optimize storage for irregular shadow */
+ struct APixstr *next;
+} APixstr;
+
+typedef struct APixstrMain
+{
+ struct APixstrMain *next, *prev;
+ struct APixstr *ps;
+} APixstrMain;
+
+/* span fill in method, is also used to localize data for zbuffering */
+typedef struct ZSpan {
+ int rectx, recty; /* range for clipping */
+
+ int miny1, maxy1, miny2, maxy2; /* actual filled in range */
+ float *minp1, *maxp1, *minp2, *maxp2; /* vertex pointers detect min/max range in */
+ float *span1, *span2;
+
+ float zmulx, zmuly, zofsx, zofsy; /* transform from hoco to zbuf co */
+
+ int *rectz, *arectz; /* zbuffers, arectz is for transparant */
+ int *rectz1; /* seconday z buffer for shadowbuffer (2nd closest z) */
+ int *rectp; /* polygon index buffer */
+ APixstr *apixbuf, *curpstr; /* apixbuf for transparent */
+ struct ListBase *apsmbase;
+
+ int polygon_offset; /* offset in Z */
+ float shad_alpha; /* copy from material, used by irregular shadbuf */
+ int mask, apsmcounter; /* in use by apixbuf */
+
+ void *sss_handle; /* used by sss */
+ void (*sss_func)(void *, int, int, int, int);
+
+ void (*zbuffunc)(struct ZSpan *, int, float *, float *, float *, float *);
+ void (*zbuflinefunc)(struct ZSpan *, int, float *, float *);
+
+} ZSpan;
+
+/* exported to shadbuf.c */
+void zbufclip4(struct ZSpan *zspan, int zvlnr, float *f1, float *f2, float *f3, float *f4, int c1, int c2, int c3, int c4);
+void zbuf_free_span(struct ZSpan *zspan);
+
+/* to rendercore.c */
+void zspan_scanconvert(struct ZSpan *zpan, void *handle, float *v1, float *v2, float *v3, void (*func)(void *, int, int, float, float) );
+
+/* exported to edge render... */
+void zbufclip(struct ZSpan *zspan, int zvlnr, float *f1, float *f2, float *f3, int c1, int c2, int c3);
+void zbuf_alloc_span(struct ZSpan *zspan, int rectx, int recty);
+void zbufclipwire(struct ZSpan *zspan, int zvlnr, struct VlakRen *vlr);
+
+#endif
+
diff --git a/source/blender/render/intern/source/Makefile b/source/blender/render/intern/source/Makefile
new file mode 100644
index 00000000000..95835f212e8
--- /dev/null
+++ b/source/blender/render/intern/source/Makefile
@@ -0,0 +1,68 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+#
+
+LIBNAME = render
+DIR = $(OCGDIR)/blender/$(LIBNAME)
+
+include nan_compile.mk
+
+CFLAGS += $(LEVEL_1_C_WARNINGS)
+
+# first /include is my own includes, second is the external interface.
+# The external modules follow after. There should be a nicer way to say this.
+CPPFLAGS += -I../include
+CPPFLAGS += -I../../extern/include
+CPPFLAGS += -I../../../radiosity/extern/include
+CPPFLAGS += -I../../../blenlib
+CPPFLAGS += -I../../../imbuf
+CPPFLAGS += -I../../../makesdna
+CPPFLAGS += -I../../../blenkernel
+CPPFLAGS += -I../../../quicktime
+CPPFLAGS += -I../../../yafray
+CPPFLAGS += -I../../../../kernel/gen_messaging
+CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
+# not very neat: the rest of blender..
+CPPFLAGS += -I../../../include
+CPPFLAGS += $(NAN_SDLCFLAGS)
+
+ifeq ($(WITH_QUICKTIME), true)
+ CPPFLAGS += -DWITH_QUICKTIME
+endif
+
+ifeq ($(WITH_FFMPEG),true)
+ CPPFLAGS += -DWITH_FFMPEG
+endif
+
+ifeq ($(WITH_OPENEXR),true)
+ CPPFLAGS += -DWITH_OPENEXR
+endif
diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c
new file mode 100644
index 00000000000..29b48413ca7
--- /dev/null
+++ b/source/blender/render/intern/source/convertblender.c
@@ -0,0 +1,4336 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributors: 2004/2005/2006 Blender Foundation, full recode
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+
+#include "blendef.h"
+#include "MTC_matrixops.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+#include "BLI_rand.h"
+#include "BLI_memarena.h"
+#include "BLI_ghash.h"
+
+#include "DNA_armature_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_material_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_effect_types.h"
+#include "DNA_group_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_image_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_object_types.h"
+#include "DNA_object_force.h"
+#include "DNA_object_fluidsim.h"
+#include "DNA_scene_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_anim.h"
+#include "BKE_armature.h"
+#include "BKE_action.h"
+#include "BKE_curve.h"
+#include "BKE_customdata.h"
+#include "BKE_colortools.h"
+#include "BKE_constraint.h"
+#include "BKE_displist.h"
+#include "BKE_deform.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_effect.h"
+#include "BKE_global.h"
+#include "BKE_group.h"
+#include "BKE_key.h"
+#include "BKE_ipo.h"
+#include "BKE_image.h"
+#include "BKE_lattice.h"
+#include "BKE_library.h"
+#include "BKE_material.h"
+#include "BKE_main.h"
+#include "BKE_mball.h"
+#include "BKE_mesh.h"
+#include "BKE_node.h"
+#include "BKE_object.h"
+#include "BKE_scene.h"
+#include "BKE_subsurf.h"
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
+#include "BKE_world.h"
+
+#include "PIL_time.h"
+#include "IMB_imbuf_types.h"
+
+#include "envmap.h"
+#include "multires.h"
+#include "render_types.h"
+#include "rendercore.h"
+#include "renderdatabase.h"
+#include "renderpipeline.h"
+#include "radio.h"
+#include "shadbuf.h"
+#include "shading.h"
+#include "texture.h"
+#include "sss.h"
+#include "zbuf.h"
+
+#ifndef DISABLE_YAFRAY /* disable yafray */
+
+#include "YafRay_Api.h"
+
+/* yafray: Identity transform 'hack' removed, exporter now transforms vertices back to world.
+ * Same is true for lamp coords & vec.
+ * Duplicated data objects & dupliframe/duplivert objects are only stored once,
+ * only the matrix is stored for all others, in yafray these objects are instances of the original.
+ * The main changes are in RE_rotateBlenderScene().
+ */
+
+#endif /* disable yafray */
+
+/* ------------------------------------------------------------------------- */
+/* Local functions */
+/* ------------------------------------------------------------------------- */
+static short test_for_displace(Render *re, Object *ob);
+static void do_displacement(Render *re, Object *ob, int startface, int numface, int startvert, int numvert );
+
+/* 10 times larger than normal epsilon, test it on default nurbs sphere with ray_transp (for quad detection) */
+/* or for checking vertex normal flips */
+#define FLT_EPSILON10 1.19209290e-06F
+
+
+/* ------------------------------------------------------------------------- */
+
+/* Stuff for stars. This sits here because it uses gl-things. Part of
+this code may move down to the converter. */
+/* ------------------------------------------------------------------------- */
+/* this is a bad beast, since it is misused by the 3d view drawing as well. */
+
+static HaloRen *initstar(Render *re, float *vec, float hasize)
+{
+ HaloRen *har;
+ float hoco[4];
+
+ projectverto(vec, re->winmat, hoco);
+
+ har= RE_findOrAddHalo(re, re->tothalo++);
+
+ /* projectvert is done in function zbufvlaggen again, because of parts */
+ VECCOPY(har->co, vec);
+ har->hasize= hasize;
+
+ har->zd= 0.0;
+
+ return har;
+}
+
+/* there must be a 'fixed' amount of stars generated between
+* near and far
+* all stars must by preference lie on the far and solely
+* differ in clarity/color
+*/
+
+void RE_make_stars(Render *re, void (*initfunc)(void),
+ void (*vertexfunc)(float*), void (*termfunc)(void))
+{
+ extern unsigned char hash[512];
+ World *wrld= NULL;
+ HaloRen *har;
+ Scene *scene;
+ Camera *camera;
+ double dblrand, hlfrand;
+ float vec[4], fx, fy, fz;
+ float fac, starmindist, clipend;
+ float mat[4][4], stargrid, maxrand, maxjit, force, alpha;
+ int x, y, z, sx, sy, sz, ex, ey, ez, done = 0;
+
+ if(initfunc) {
+ scene= G.scene;
+ wrld= G.scene->world;
+ }
+ else {
+ scene= re->scene;
+ wrld= &(re->wrld);
+ }
+
+ stargrid = wrld->stardist; /* distance between stars */
+ maxrand = 2.0; /* amount a star can be shifted (in grid units) */
+ maxjit = (wrld->starcolnoise); /* amount a color is being shifted */
+
+ /* size of stars */
+ force = ( wrld->starsize );
+
+ /* minimal free space (starting at camera) */
+ starmindist= wrld->starmindist;
+
+ if (stargrid <= 0.10) return;
+
+ if (re) re->flag |= R_HALO;
+ else stargrid *= 1.0; /* then it draws fewer */
+
+ if(re) MTC_Mat4Invert(mat, re->viewmat);
+
+ /* BOUNDING BOX CALCULATION
+ * bbox goes from z = loc_near_var | loc_far_var,
+ * x = -z | +z,
+ * y = -z | +z
+ */
+
+ if(scene->camera==NULL)
+ return;
+ camera = scene->camera->data;
+ clipend = camera->clipend;
+
+ /* convert to grid coordinates */
+
+ sx = ((mat[3][0] - clipend) / stargrid) - maxrand;
+ sy = ((mat[3][1] - clipend) / stargrid) - maxrand;
+ sz = ((mat[3][2] - clipend) / stargrid) - maxrand;
+
+ ex = ((mat[3][0] + clipend) / stargrid) + maxrand;
+ ey = ((mat[3][1] + clipend) / stargrid) + maxrand;
+ ez = ((mat[3][2] + clipend) / stargrid) + maxrand;
+
+ dblrand = maxrand * stargrid;
+ hlfrand = 2.0 * dblrand;
+
+ if (initfunc) {
+ initfunc();
+ }
+
+ for (x = sx, fx = sx * stargrid; x <= ex; x++, fx += stargrid) {
+ for (y = sy, fy = sy * stargrid; y <= ey ; y++, fy += stargrid) {
+ for (z = sz, fz = sz * stargrid; z <= ez; z++, fz += stargrid) {
+
+ BLI_srand((hash[z & 0xff] << 24) + (hash[y & 0xff] << 16) + (hash[x & 0xff] << 8));
+ vec[0] = fx + (hlfrand * BLI_drand()) - dblrand;
+ vec[1] = fy + (hlfrand * BLI_drand()) - dblrand;
+ vec[2] = fz + (hlfrand * BLI_drand()) - dblrand;
+ vec[3] = 1.0;
+
+ if (vertexfunc) {
+ if(done & 1) vertexfunc(vec);
+ done++;
+ }
+ else {
+ MTC_Mat4MulVecfl(re->viewmat, vec);
+
+ /* in vec are global coordinates
+ * calculate distance to camera
+ * and using that, define the alpha
+ */
+
+ {
+ float tx, ty, tz;
+
+ tx = vec[0];
+ ty = vec[1];
+ tz = vec[2];
+
+ alpha = sqrt(tx * tx + ty * ty + tz * tz);
+
+ if (alpha >= clipend) alpha = 0.0;
+ else if (alpha <= starmindist) alpha = 0.0;
+ else if (alpha <= 2.0 * starmindist) {
+ alpha = (alpha - starmindist) / starmindist;
+ } else {
+ alpha -= 2.0 * starmindist;
+ alpha /= (clipend - 2.0 * starmindist);
+ alpha = 1.0 - alpha;
+ }
+ }
+
+
+ if (alpha != 0.0) {
+ fac = force * BLI_drand();
+
+ har = initstar(re, vec, fac);
+
+ if (har) {
+ har->alfa = sqrt(sqrt(alpha));
+ har->add= 255;
+ har->r = har->g = har->b = 1.0;
+ if (maxjit) {
+ har->r += ((maxjit * BLI_drand()) ) - maxjit;
+ har->g += ((maxjit * BLI_drand()) ) - maxjit;
+ har->b += ((maxjit * BLI_drand()) ) - maxjit;
+ }
+ har->hard = 32;
+ har->lay= -1;
+ har->type |= HA_ONLYSKY;
+ done++;
+ }
+ }
+ }
+ }
+ /* do not call blender_test_break() here, since it is used in UI as well, confusing the callback system */
+ /* main cause is G.afbreek of course, a global again... (ton) */
+ }
+ }
+ if (termfunc) termfunc();
+}
+
+
+/* ------------------------------------------------------------------------- */
+/* tool functions/defines for ad hoc simplification and possible future
+ cleanup */
+/* ------------------------------------------------------------------------- */
+
+#define UVTOINDEX(u,v) (startvlak + (u) * sizev + (v))
+/*
+
+NOTE THAT U/V COORDINATES ARE SOMETIMES SWAPPED !!
+
+^ ()----p4----p3----()
+| | | | |
+u | | F1 | F2 |
+ | | | |
+ ()----p1----p2----()
+ v ->
+*/
+
+/* ------------------------------------------------------------------------- */
+
+static void split_v_renderfaces(Render *re, int startvlak, int startvert, int usize, int vsize, int uIndex, int cyclu, int cyclv)
+{
+ int vLen = vsize-1+(!!cyclv);
+ int v;
+
+ for (v=0; v<vLen; v++) {
+ VlakRen *vlr = RE_findOrAddVlak(re, startvlak + vLen*uIndex + v);
+ VertRen *vert = RE_vertren_copy(re, vlr->v2);
+
+ if (cyclv) {
+ vlr->v2 = vert;
+
+ if (v==vLen-1) {
+ VlakRen *vlr = RE_findOrAddVlak(re, startvlak + vLen*uIndex + 0);
+ vlr->v1 = vert;
+ } else {
+ VlakRen *vlr = RE_findOrAddVlak(re, startvlak + vLen*uIndex + v+1);
+ vlr->v1 = vert;
+ }
+ } else {
+ vlr->v2 = vert;
+
+ if (v<vLen-1) {
+ VlakRen *vlr = RE_findOrAddVlak(re, startvlak + vLen*uIndex + v+1);
+ vlr->v1 = vert;
+ }
+
+ if (v==0) {
+ vlr->v1 = RE_vertren_copy(re, vlr->v1);
+ }
+ }
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int check_vnormal(float *n, float *veno)
+{
+ float inp;
+
+ inp=n[0]*veno[0]+n[1]*veno[1]+n[2]*veno[2];
+ if(inp < -FLT_EPSILON10) return 1;
+ return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void calc_edge_stress_add(float *accum, VertRen *v1, VertRen *v2)
+{
+ float len= VecLenf(v1->co, v2->co)/VecLenf(v1->orco, v2->orco);
+ float *acc;
+
+ acc= accum + 2*v1->index;
+ acc[0]+= len;
+ acc[1]+= 1.0f;
+
+ acc= accum + 2*v2->index;
+ acc[0]+= len;
+ acc[1]+= 1.0f;
+}
+
+static void calc_edge_stress(Render *re, Mesh *me, int startvert, int startvlak)
+{
+ float loc[3], size[3], *accum, *acc, *accumoffs, *stress;
+ int a;
+
+ if(startvert==re->totvert) return;
+
+ mesh_get_texspace(me, loc, NULL, size);
+
+ accum= MEM_callocN(2*sizeof(float)*(re->totvert-startvert), "temp accum for stress");
+
+ /* de-normalize orco */
+ for(a=startvert; a<re->totvert; a++) {
+ VertRen *ver= RE_findOrAddVert(re, a);
+ if(ver->orco) {
+ ver->orco[0]= ver->orco[0]*size[0] +loc[0];
+ ver->orco[1]= ver->orco[1]*size[1] +loc[1];
+ ver->orco[2]= ver->orco[2]*size[2] +loc[2];
+ }
+ }
+
+ /* add stress values */
+ accumoffs= accum - 2*startvert; /* so we can use vertex index */
+ for(a=startvlak; a<re->totvlak; a++) {
+ VlakRen *vlr= RE_findOrAddVlak(re, a);
+
+ if(vlr->v1->orco && vlr->v4) {
+ calc_edge_stress_add(accumoffs, vlr->v1, vlr->v2);
+ calc_edge_stress_add(accumoffs, vlr->v2, vlr->v3);
+ calc_edge_stress_add(accumoffs, vlr->v3, vlr->v1);
+ if(vlr->v4) {
+ calc_edge_stress_add(accumoffs, vlr->v3, vlr->v4);
+ calc_edge_stress_add(accumoffs, vlr->v4, vlr->v1);
+ calc_edge_stress_add(accumoffs, vlr->v2, vlr->v4);
+ }
+ }
+ }
+
+ for(a=startvert; a<re->totvert; a++) {
+ VertRen *ver= RE_findOrAddVert(re, a);
+ if(ver->orco) {
+ /* find stress value */
+ acc= accumoffs + 2*ver->index;
+ if(acc[1]!=0.0f)
+ acc[0]/= acc[1];
+ stress= RE_vertren_get_stress(re, ver, 1);
+ *stress= *acc;
+
+ /* restore orcos */
+ ver->orco[0] = (ver->orco[0]-loc[0])/size[0];
+ ver->orco[1] = (ver->orco[1]-loc[1])/size[1];
+ ver->orco[2] = (ver->orco[2]-loc[2])/size[2];
+ }
+ }
+
+ MEM_freeN(accum);
+}
+
+/* gets tangent from tface or orco */
+static void calc_tangent_vector(Render *re, VlakRen *vlr)
+{
+ MTFace *tface= RE_vlakren_get_tface(re, vlr, 0, NULL, 0);
+ VertRen *v1=vlr->v1, *v2=vlr->v2, *v3=vlr->v3, *v4=vlr->v4;
+ float tang[3], tangv[3], ct[3], e1[3], e2[3], *tav;
+ float *uv1, *uv2, *uv3, *uv4;
+ float s1, s2, t1, t2, det;
+ float uv[4][2];
+
+ if(tface) {
+ uv1= tface->uv[0];
+ uv2= tface->uv[1];
+ uv3= tface->uv[2];
+ uv4= tface->uv[3];
+ }
+ else if(v1->orco) {
+ uv1= uv[0]; uv2= uv[1]; uv3= uv[2]; uv4= uv[3];
+ spheremap(v1->orco[0], v1->orco[1], v1->orco[2], &uv[0][0], &uv[0][1]);
+ spheremap(v2->orco[0], v2->orco[1], v2->orco[2], &uv[1][0], &uv[1][1]);
+ spheremap(v3->orco[0], v3->orco[1], v3->orco[2], &uv[2][0], &uv[2][1]);
+ if(v4)
+ spheremap(v4->orco[0], v4->orco[1], v4->orco[2], &uv[3][0], &uv[3][1]);
+ }
+ else return;
+
+ s1= uv2[0] - uv1[0];
+ s2= uv3[0] - uv1[0];
+ t1= uv2[1] - uv1[1];
+ t2= uv3[1] - uv1[1];
+ det= 1.0f / (s1 * t2 - s2 * t1);
+
+ /* normals in render are inversed... */
+ VecSubf(e1, v1->co, v2->co);
+ VecSubf(e2, v1->co, v3->co);
+ tang[0] = (t2*e1[0] - t1*e2[0])*det;
+ tang[1] = (t2*e1[1] - t1*e2[1])*det;
+ tang[2] = (t2*e1[2] - t1*e2[2])*det;
+ tangv[0] = (s1*e2[0] - s2*e1[0])*det;
+ tangv[1] = (s1*e2[1] - s2*e1[1])*det;
+ tangv[2] = (s1*e2[2] - s2*e1[2])*det;
+ Crossf(ct, tang, tangv);
+ /* check flip */
+ if ((ct[0]*vlr->n[0] + ct[1]*vlr->n[1] + ct[2]*vlr->n[2]) < 0.f)
+ VecMulf(tang, -1.f);
+
+ tav= RE_vertren_get_tangent(re, v1, 1);
+ VECADD(tav, tav, tang);
+ tav= RE_vertren_get_tangent(re, v2, 1);
+ VECADD(tav, tav, tang);
+ tav= RE_vertren_get_tangent(re, v3, 1);
+ VECADD(tav, tav, tang);
+
+ if(v4) {
+ s1= uv3[0] - uv1[0];
+ s2= uv4[0] - uv1[0];
+ t1= uv3[1] - uv1[1];
+ t2= uv4[1] - uv1[1];
+ det= 1.0f / (s1 * t2 - s2 * t1);
+
+ /* normals in render are inversed... */
+ VecSubf(e1, v1->co, v3->co);
+ VecSubf(e2, v1->co, v4->co);
+ tang[0] = (t2*e1[0] - t1*e2[0])*det;
+ tang[1] = (t2*e1[1] - t1*e2[1])*det;
+ tang[2] = (t2*e1[2] - t1*e2[2])*det;
+ tangv[0] = (s1*e2[0] - s2*e1[0])*det;
+ tangv[1] = (s1*e2[1] - s2*e1[1])*det;
+ tangv[2] = (s1*e2[2] - s2*e1[2])*det;
+ Crossf(ct, tang, tangv);
+ if ((ct[0]*vlr->n[0] + ct[1]*vlr->n[1] + ct[2]*vlr->n[2]) < 0.f)
+ VecMulf(tang, -1.f);
+
+ tav= RE_vertren_get_tangent(re, v1, 1);
+ VECADD(tav, tav, tang);
+ tav= RE_vertren_get_tangent(re, v3, 1);
+ VECADD(tav, tav, tang);
+ tav= RE_vertren_get_tangent(re, v4, 1);
+ VECADD(tav, tav, tang);
+ }
+}
+
+
+static void calc_vertexnormals(Render *re, int startvert, int startvlak, int do_tangent)
+{
+ int a;
+
+ /* clear all vertex normals */
+ for(a=startvert; a<re->totvert; a++) {
+ VertRen *ver= RE_findOrAddVert(re, a);
+ ver->n[0]=ver->n[1]=ver->n[2]= 0.0f;
+ }
+
+ /* calculate cos of angles and point-masses, use as weight factor to
+ add face normal to vertex */
+ for(a=startvlak; a<re->totvlak; a++) {
+ VlakRen *vlr= RE_findOrAddVlak(re, a);
+ if(vlr->flag & ME_SMOOTH) {
+ VertRen *v1= vlr->v1;
+ VertRen *v2= vlr->v2;
+ VertRen *v3= vlr->v3;
+ VertRen *v4= vlr->v4;
+ float n1[3], n2[3], n3[3], n4[3];
+ float fac1, fac2, fac3, fac4=0.0f;
+
+ if(re->flag & R_GLOB_NOPUNOFLIP)
+ vlr->flag |= R_NOPUNOFLIP;
+
+ VecSubf(n1, v2->co, v1->co);
+ Normalize(n1);
+ VecSubf(n2, v3->co, v2->co);
+ Normalize(n2);
+ if(v4==NULL) {
+ VecSubf(n3, v1->co, v3->co);
+ Normalize(n3);
+
+ fac1= saacos(-n1[0]*n3[0]-n1[1]*n3[1]-n1[2]*n3[2]);
+ fac2= saacos(-n1[0]*n2[0]-n1[1]*n2[1]-n1[2]*n2[2]);
+ fac3= saacos(-n2[0]*n3[0]-n2[1]*n3[1]-n2[2]*n3[2]);
+ }
+ else {
+ VecSubf(n3, v4->co, v3->co);
+ Normalize(n3);
+ VecSubf(n4, v1->co, v4->co);
+ Normalize(n4);
+
+ fac1= saacos(-n4[0]*n1[0]-n4[1]*n1[1]-n4[2]*n1[2]);
+ fac2= saacos(-n1[0]*n2[0]-n1[1]*n2[1]-n1[2]*n2[2]);
+ fac3= saacos(-n2[0]*n3[0]-n2[1]*n3[1]-n2[2]*n3[2]);
+ fac4= saacos(-n3[0]*n4[0]-n3[1]*n4[1]-n3[2]*n4[2]);
+
+ if(!(vlr->flag & R_NOPUNOFLIP)) {
+ if( check_vnormal(vlr->n, v4->n) ) fac4= -fac4;
+ }
+
+ v4->n[0] +=fac4*vlr->n[0];
+ v4->n[1] +=fac4*vlr->n[1];
+ v4->n[2] +=fac4*vlr->n[2];
+ }
+
+ if(!(vlr->flag & R_NOPUNOFLIP)) {
+ if( check_vnormal(vlr->n, v1->n) ) fac1= -fac1;
+ if( check_vnormal(vlr->n, v2->n) ) fac2= -fac2;
+ if( check_vnormal(vlr->n, v3->n) ) fac3= -fac3;
+ }
+
+ v1->n[0] +=fac1*vlr->n[0];
+ v1->n[1] +=fac1*vlr->n[1];
+ v1->n[2] +=fac1*vlr->n[2];
+
+ v2->n[0] +=fac2*vlr->n[0];
+ v2->n[1] +=fac2*vlr->n[1];
+ v2->n[2] +=fac2*vlr->n[2];
+
+ v3->n[0] +=fac3*vlr->n[0];
+ v3->n[1] +=fac3*vlr->n[1];
+ v3->n[2] +=fac3*vlr->n[2];
+
+ }
+ if(do_tangent) {
+ /* tangents still need to be calculated for flat faces too */
+ /* weighting removed, they are not vertexnormals */
+ calc_tangent_vector(re, vlr);
+ }
+ }
+
+ /* do solid faces */
+ for(a=startvlak; a<re->totvlak; a++) {
+ VlakRen *vlr= RE_findOrAddVlak(re, a);
+ if((vlr->flag & ME_SMOOTH)==0) {
+ float *f1= vlr->v1->n;
+ if(f1[0]==0.0 && f1[1]==0.0 && f1[2]==0.0) VECCOPY(f1, vlr->n);
+ f1= vlr->v2->n;
+ if(f1[0]==0.0 && f1[1]==0.0 && f1[2]==0.0) VECCOPY(f1, vlr->n);
+ f1= vlr->v3->n;
+ if(f1[0]==0.0 && f1[1]==0.0 && f1[2]==0.0) VECCOPY(f1, vlr->n);
+ if(vlr->v4) {
+ f1= vlr->v4->n;
+ if(f1[0]==0.0 && f1[1]==0.0 && f1[2]==0.0) VECCOPY(f1, vlr->n);
+ }
+ }
+ }
+
+ /* normalize vertex normals */
+ for(a=startvert; a<re->totvert; a++) {
+ VertRen *ver= RE_findOrAddVert(re, a);
+ Normalize(ver->n);
+ if(do_tangent) {
+ float *tav= RE_vertren_get_tangent(re, ver, 0);
+ if (tav) {
+ /* orthonorm. */
+ float tdn = tav[0]*ver->n[0] + tav[1]*ver->n[1] + tav[2]*ver->n[2];
+ tav[0] -= ver->n[0]*tdn;
+ tav[1] -= ver->n[1]*tdn;
+ tav[2] -= ver->n[2]*tdn;
+ Normalize(tav);
+ }
+ }
+ }
+
+ /* vertex normal (puno) switch flags for during render */
+ for(a=startvlak; a<re->totvlak; a++) {
+ VlakRen *vlr= RE_findOrAddVlak(re, a);
+
+ if((vlr->flag & R_NOPUNOFLIP)==0) {
+ float *v1= vlr->v1->n;
+ float *v2= vlr->v2->n;
+ float *v3= vlr->v3->n;
+ float *v4= vlr->v4?vlr->v4->n:NULL;
+ float *nor= vlr->n;
+ vlr->puno &= ~15;
+ if ((nor[0]*v1[0] + nor[1]*v1[1] + nor[2]*v1[2]) < -FLT_EPSILON10) vlr->puno= 1;
+ if ((nor[0]*v2[0] + nor[1]*v2[1] + nor[2]*v2[2]) < -FLT_EPSILON10) vlr->puno+= 2;
+ if ((nor[0]*v3[0] + nor[1]*v3[1] + nor[2]*v3[2]) < -FLT_EPSILON10) vlr->puno+= 4;
+ if(v4) {
+ if((nor[0]*v4[0] + nor[1]*v4[1] + nor[2]*v4[2]) < -FLT_EPSILON10 ) vlr->puno+= 8;
+ }
+ }
+ }
+}
+
+// NT same as calc_vertexnormals, but dont modify the existing vertex normals
+// only recalculate other render data. If this is at some point used for other things than fluidsim,
+// this could be made on option for the normal calc_vertexnormals
+static void calc_fluidsimnormals(Render *re, int startvert, int startvlak, int do_tangent)
+{
+ int a;
+
+ /* dont clear vertex normals here */
+ // OFF for(a=startvert; a<re->totvert; a++) { VertRen *ver= RE_findOrAddVert(re, a); ver->n[0]=ver->n[1]=ver->n[2]= 0.0; }
+ /* calculate cos of angles and point-masses, use as weight factor to add face normal to vertex */
+ for(a=startvlak; a<re->totvlak; a++) {
+ VlakRen *vlr= RE_findOrAddVlak(re, a);
+ if(vlr->flag & ME_SMOOTH) {
+ VertRen *v1= vlr->v1;
+ VertRen *v2= vlr->v2;
+ VertRen *v3= vlr->v3;
+ VertRen *v4= vlr->v4;
+ float n1[3], n2[3], n3[3], n4[3];
+ float fac1, fac2, fac3, fac4=0.0f;
+
+ if(re->flag & R_GLOB_NOPUNOFLIP)
+ vlr->flag |= R_NOPUNOFLIP;
+
+ VecSubf(n1, v2->co, v1->co);
+ Normalize(n1);
+ VecSubf(n2, v3->co, v2->co);
+ Normalize(n2);
+ if(v4==NULL) {
+ VecSubf(n3, v1->co, v3->co);
+ Normalize(n3);
+ fac1= saacos(-n1[0]*n3[0]-n1[1]*n3[1]-n1[2]*n3[2]);
+ fac2= saacos(-n1[0]*n2[0]-n1[1]*n2[1]-n1[2]*n2[2]);
+ fac3= saacos(-n2[0]*n3[0]-n2[1]*n3[1]-n2[2]*n3[2]);
+ }
+ else {
+ VecSubf(n3, v4->co, v3->co);
+ Normalize(n3);
+ VecSubf(n4, v1->co, v4->co);
+ Normalize(n4);
+
+ fac1= saacos(-n4[0]*n1[0]-n4[1]*n1[1]-n4[2]*n1[2]);
+ fac2= saacos(-n1[0]*n2[0]-n1[1]*n2[1]-n1[2]*n2[2]);
+ fac3= saacos(-n2[0]*n3[0]-n2[1]*n3[1]-n2[2]*n3[2]);
+ fac4= saacos(-n3[0]*n4[0]-n3[1]*n4[1]-n3[2]*n4[2]);
+
+ if(!(vlr->flag & R_NOPUNOFLIP)) {
+ if( check_vnormal(vlr->n, v4->n) ) fac4= -fac4;
+ }
+ }
+
+ //if(do_tangent)
+ // calc_tangent_vector(re, vlr, fac1, fac2, fac3, fac4);
+ }
+ if(do_tangent) {
+ /* tangents still need to be calculated for flat faces too */
+ /* weighting removed, they are not vertexnormals */
+ calc_tangent_vector(re, vlr);
+ }
+ }
+
+ /* do solid faces */
+ for(a=startvlak; a<re->totvlak; a++) {
+ VlakRen *vlr= RE_findOrAddVlak(re, a);
+ if((vlr->flag & ME_SMOOTH)==0) {
+ float *f1= vlr->v1->n;
+ if(f1[0]==0.0 && f1[1]==0.0 && f1[2]==0.0) VECCOPY(f1, vlr->n);
+ f1= vlr->v2->n;
+ if(f1[0]==0.0 && f1[1]==0.0 && f1[2]==0.0) VECCOPY(f1, vlr->n);
+ f1= vlr->v3->n;
+ if(f1[0]==0.0 && f1[1]==0.0 && f1[2]==0.0) VECCOPY(f1, vlr->n);
+ if(vlr->v4) {
+ f1= vlr->v4->n;
+ if(f1[0]==0.0 && f1[1]==0.0 && f1[2]==0.0) VECCOPY(f1, vlr->n);
+ }
+ }
+ }
+
+ /* normalize vertex normals */
+ for(a=startvert; a<re->totvert; a++) {
+ VertRen *ver= RE_findOrAddVert(re, a);
+ Normalize(ver->n);
+ if(do_tangent) {
+ float *tav= RE_vertren_get_tangent(re, ver, 0);
+ if(tav) Normalize(tav);
+ }
+ }
+
+ /* vertex normal (puno) switch flags for during render */
+ for(a=startvlak; a<re->totvlak; a++) {
+ VlakRen *vlr= RE_findOrAddVlak(re, a);
+ if((vlr->flag & R_NOPUNOFLIP)==0) {
+ VertRen *v1= vlr->v1;
+ VertRen *v2= vlr->v2;
+ VertRen *v3= vlr->v3;
+ VertRen *v4= vlr->v4;
+ vlr->puno &= ~15;
+ if ((vlr->n[0]*v1->n[0]+vlr->n[1]*v1->n[1]+vlr->n[2]*v1->n[2])<0.0) vlr->puno= 1;
+ if ((vlr->n[0]*v2->n[0]+vlr->n[1]*v2->n[1]+vlr->n[2]*v2->n[2])<0.0) vlr->puno+= 2;
+ if ((vlr->n[0]*v3->n[0]+vlr->n[1]*v3->n[1]+vlr->n[2]*v3->n[2])<0.0) vlr->puno+= 4;
+ if(v4) {
+ if((vlr->n[0]*v4->n[0]+vlr->n[1]*v4->n[1]+vlr->n[2]*v4->n[2])<0.0) vlr->puno+= 8;
+ }
+ }
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+/* Autosmoothing: */
+/* ------------------------------------------------------------------------- */
+
+typedef struct ASvert {
+ int totface;
+ ListBase faces;
+} ASvert;
+
+typedef struct ASface {
+ struct ASface *next, *prev;
+ VlakRen *vlr[4];
+ VertRen *nver[4];
+} ASface;
+
+static void as_addvert(ASvert *asv, VertRen *v1, VlakRen *vlr)
+{
+ ASface *asf;
+ int a;
+
+ if(v1 == NULL) return;
+
+ if(asv->faces.first==NULL) {
+ asf= MEM_callocN(sizeof(ASface), "asface");
+ BLI_addtail(&asv->faces, asf);
+ }
+
+ asf= asv->faces.last;
+ for(a=0; a<4; a++) {
+ if(asf->vlr[a]==NULL) {
+ asf->vlr[a]= vlr;
+ asv->totface++;
+ break;
+ }
+ }
+
+ /* new face struct */
+ if(a==4) {
+ asf= MEM_callocN(sizeof(ASface), "asface");
+ BLI_addtail(&asv->faces, asf);
+ asf->vlr[0]= vlr;
+ asv->totface++;
+ }
+}
+
+static int as_testvertex(VlakRen *vlr, VertRen *ver, ASvert *asv, float thresh)
+{
+ /* return 1: vertex needs a copy */
+ ASface *asf;
+ float inp;
+ int a;
+
+ if(vlr==0) return 0;
+
+ asf= asv->faces.first;
+ while(asf) {
+ for(a=0; a<4; a++) {
+ if(asf->vlr[a] && asf->vlr[a]!=vlr) {
+ inp= fabs( vlr->n[0]*asf->vlr[a]->n[0] + vlr->n[1]*asf->vlr[a]->n[1] + vlr->n[2]*asf->vlr[a]->n[2] );
+ if(inp < thresh) return 1;
+ }
+ }
+ asf= asf->next;
+ }
+
+ return 0;
+}
+
+static VertRen *as_findvertex(VlakRen *vlr, VertRen *ver, ASvert *asv, float thresh)
+{
+ /* return when new vertex already was made */
+ ASface *asf;
+ float inp;
+ int a;
+
+ asf= asv->faces.first;
+ while(asf) {
+ for(a=0; a<4; a++) {
+ if(asf->vlr[a] && asf->vlr[a]!=vlr) {
+ /* this face already made a copy for this vertex! */
+ if(asf->nver[a]) {
+ inp= fabs( vlr->n[0]*asf->vlr[a]->n[0] + vlr->n[1]*asf->vlr[a]->n[1] + vlr->n[2]*asf->vlr[a]->n[2] );
+ if(inp >= thresh) {
+ return asf->nver[a];
+ }
+ }
+ }
+ }
+ asf= asf->next;
+ }
+
+ return NULL;
+}
+
+/* note; autosmooth happens in object space still, after applying autosmooth we rotate */
+/* note2; actually, when original mesh and displist are equal sized, face normals are from original mesh */
+static void autosmooth(Render *re, float mat[][4], int startvert, int startvlak, int degr)
+{
+ ASvert *asv, *asverts, *asvertoffs;
+ ASface *asf;
+ VertRen *ver, *v1;
+ VlakRen *vlr;
+ float thresh;
+ int a, b, totvert;
+
+ if(startvert==re->totvert) return;
+ asverts= MEM_callocN(sizeof(ASvert)*(re->totvert-startvert), "all smooth verts");
+ asvertoffs= asverts-startvert; /* se we can use indices */
+
+ thresh= cos( M_PI*(0.5f+(float)degr)/180.0 );
+
+ /* step zero: give faces normals of original mesh, if this is provided */
+
+
+ /* step one: construct listbase of all vertices and pointers to faces */
+ for(a=startvlak; a<re->totvlak; a++) {
+ vlr= RE_findOrAddVlak(re, a);
+ /* skip wire faces */
+ if(vlr->v2 != vlr->v3) {
+ as_addvert(asvertoffs+vlr->v1->index, vlr->v1, vlr);
+ as_addvert(asvertoffs+vlr->v2->index, vlr->v2, vlr);
+ as_addvert(asvertoffs+vlr->v3->index, vlr->v3, vlr);
+ if(vlr->v4)
+ as_addvert(asvertoffs+vlr->v4->index, vlr->v4, vlr);
+ }
+ }
+
+ /* we now test all vertices, when faces have a normal too much different: they get a new vertex */
+ totvert= re->totvert;
+ for(a=startvert, asv=asverts; a<totvert; a++, asv++) {
+ if(asv && asv->totface>1) {
+ ver= RE_findOrAddVert(re, a);
+
+ asf= asv->faces.first;
+ while(asf) {
+ for(b=0; b<4; b++) {
+
+ /* is there a reason to make a new vertex? */
+ vlr= asf->vlr[b];
+ if( as_testvertex(vlr, ver, asv, thresh) ) {
+
+ /* already made a new vertex within threshold? */
+ v1= as_findvertex(vlr, ver, asv, thresh);
+ if(v1==NULL) {
+ /* make a new vertex */
+ v1= RE_vertren_copy(re, ver);
+ }
+ asf->nver[b]= v1;
+ if(vlr->v1==ver) vlr->v1= v1;
+ if(vlr->v2==ver) vlr->v2= v1;
+ if(vlr->v3==ver) vlr->v3= v1;
+ if(vlr->v4==ver) vlr->v4= v1;
+ }
+ }
+ asf= asf->next;
+ }
+ }
+ }
+
+ /* free */
+ for(a=0; a<totvert-startvert; a++) {
+ BLI_freelistN(&asverts[a].faces);
+ }
+ MEM_freeN(asverts);
+
+ /* rotate vertices and calculate normal of faces */
+ for(a=startvert; a<re->totvert; a++) {
+ ver= RE_findOrAddVert(re, a);
+ MTC_Mat4MulVecfl(mat, ver->co);
+ }
+ for(a=startvlak; a<re->totvlak; a++) {
+ vlr= RE_findOrAddVlak(re, a);
+
+ /* skip wire faces */
+ if(vlr->v2 != vlr->v3) {
+ if(vlr->v4)
+ CalcNormFloat4(vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co, vlr->n);
+ else
+ CalcNormFloat(vlr->v3->co, vlr->v2->co, vlr->v1->co, vlr->n);
+ }
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+/* End of autosmoothing: */
+/* ------------------------------------------------------------------------- */
+
+/* ------------------------------------------------------------------------- */
+/* Orco hash */
+/* ------------------------------------------------------------------------- */
+
+
+static float *get_object_orco(Render *re, Object *ob)
+{
+ float *orco;
+
+ if (!re->orco_hash)
+ re->orco_hash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
+
+ orco = BLI_ghash_lookup(re->orco_hash, ob);
+
+ if (!orco) {
+ if (ob->type==OB_MESH) {
+ orco = mesh_create_orco_render(ob);
+ } else if (ELEM(ob->type, OB_CURVE, OB_FONT)) {
+ orco = make_orco_curve(ob);
+ } else if (ob->type==OB_SURF) {
+ orco = make_orco_surf(ob);
+ }
+
+ if (orco)
+ BLI_ghash_insert(re->orco_hash, ob, orco);
+ }
+
+ return orco;
+}
+
+static void free_mesh_orco_hash(Render *re)
+{
+ if (re->orco_hash) {
+ BLI_ghash_free(re->orco_hash, NULL, (GHashValFreeFP)MEM_freeN);
+ re->orco_hash = NULL;
+ }
+}
+
+/* ******************** END ORCO HASH ***************** */
+
+
+static void make_render_halos(Render *re, Object *ob, Mesh *me, int totvert, MVert *mvert, Material *ma, float *orco)
+{
+ HaloRen *har;
+ float xn, yn, zn, nor[3], view[3];
+ float vec[3], hasize, mat[4][4], imat[3][3];
+ int a, ok, seed= ma->seed1;
+
+ MTC_Mat4MulMat4(mat, ob->obmat, re->viewmat);
+ MTC_Mat3CpyMat4(imat, ob->imat);
+
+ re->flag |= R_HALO;
+
+ for(a=0; a<totvert; a++, mvert++) {
+ ok= 1;
+
+ if(ok) {
+ hasize= ma->hasize;
+
+ VECCOPY(vec, mvert->co);
+ MTC_Mat4MulVecfl(mat, vec);
+
+ if(ma->mode & MA_HALOPUNO) {
+ xn= mvert->no[0];
+ yn= mvert->no[1];
+ zn= mvert->no[2];
+
+ /* transpose ! */
+ nor[0]= imat[0][0]*xn+imat[0][1]*yn+imat[0][2]*zn;
+ nor[1]= imat[1][0]*xn+imat[1][1]*yn+imat[1][2]*zn;
+ nor[2]= imat[2][0]*xn+imat[2][1]*yn+imat[2][2]*zn;
+ Normalize(nor);
+
+ VECCOPY(view, vec);
+ Normalize(view);
+
+ zn= nor[0]*view[0]+nor[1]*view[1]+nor[2]*view[2];
+ if(zn>=0.0) hasize= 0.0;
+ else hasize*= zn*zn*zn*zn;
+ }
+
+ if(orco) har= RE_inithalo(re, ma, vec, NULL, orco, hasize, 0.0, seed);
+ else har= RE_inithalo(re, ma, vec, NULL, mvert->co, hasize, 0.0, seed);
+ if(har) har->lay= ob->lay;
+ }
+ if(orco) orco+= 3;
+ seed++;
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+static Material *give_render_material(Render *re, Object *ob, int nr)
+{
+ extern Material defmaterial; /* material.c */
+ Material *ma;
+
+ ma= give_current_material(ob, nr);
+ if(ma==NULL)
+ ma= &defmaterial;
+ else
+ if(ma->mode & MA_ZTRA)
+ re->flag |= R_ZTRA;
+
+ if(re->r.mode & R_SPEED) ma->texco |= NEED_UV;
+
+ /* for light groups */
+ ma->flag |= MA_IS_USED;
+
+ return ma;
+}
+
+
+
+static void render_particle_system(Render *re, Object *ob, Object *par, PartEff *paf)
+{
+ Particle *pa=0;
+ HaloRen *har=0;
+ Material *ma=0;
+ float xn, yn, zn, imat[3][3], tmat[4][4], mat[4][4], hasize, stime, ptime, ctime, vec[3], vec1[3], view[3], nor[3];
+ float haloScale = 1.0; //NT scale halos
+ float iniAlpha = 0.0; // restore material alpha
+ int a, mat_nr=1, seed;
+ int useFluidsimParticles = 0; // FSPARTICLE
+
+ ma= give_render_material(re, ob, paf->omat);
+
+ if( (ob->fluidsimSettings) && (ob->fluidsimSettings->type == OB_FLUIDSIM_PARTICLE)) {
+ useFluidsimParticles = 1;
+ iniAlpha = ma->alpha;
+ }
+
+ pa= paf->keys;
+ if(pa==NULL || paf->disp!=100 || useFluidsimParticles) {
+ build_particle_system(ob);
+ pa= paf->keys;
+ if(pa==NULL) return;
+ }
+
+ MTC_Mat4MulMat4(mat, ob->obmat, re->viewmat);
+ MTC_Mat4Invert(ob->imat, mat); /* this is correct, for imat texture */
+
+ /* enable duplicators to work */
+ if(par) {
+ Mat4MulMat4(tmat, paf->imat, ob->obmat);
+ MTC_Mat4MulMat4(mat, tmat, re->viewmat);
+
+ MTC_Mat4Invert(tmat, mat);
+ MTC_Mat3CpyMat4(imat, tmat);
+ }
+ else {
+ MTC_Mat4CpyMat4(mat, re->viewmat);
+
+ MTC_Mat4Invert(tmat, re->viewmat);
+ MTC_Mat3CpyMat4(imat, tmat);
+
+ }
+
+ re->flag |= R_HALO;
+
+ if(ob->ipoflag & OB_OFFS_PARTICLE) ptime= ob->sf;
+ else ptime= 0.0;
+ ctime= bsystem_time(ob, (float)re->scene->r.cfra, ptime);
+ seed= ma->seed1;
+
+ for(a=0; a<paf->totpart; a++, pa+=paf->totkey, seed++) {
+
+ /* offset time for calculating normal */
+ stime= ctime;
+ ptime= ctime+1.0f;
+ if(ctime < pa->time) {
+ if(paf->flag & PAF_UNBORN)
+ ptime= pa->time+1.0f;
+ else
+ continue;
+ }
+ if(ctime > pa->time+pa->lifetime) {
+ if(paf->flag & PAF_DIED)
+ stime= pa->time+pa->lifetime-1.0f;
+ else
+ continue;
+ }
+
+ /* watch it: also calculate the normal of a particle */
+ if(paf->stype==PAF_VECT || ma->mode & MA_HALO_SHADE) {
+ where_is_particle(paf, pa, stime, vec);
+ MTC_Mat4MulVecfl(mat, vec);
+ where_is_particle(paf, pa, ptime, vec1);
+ MTC_Mat4MulVecfl(mat, vec1);
+ }
+ else {
+ where_is_particle(paf, pa, ctime, vec);
+ MTC_Mat4MulVecfl(mat, vec);
+ }
+
+ if(pa->mat_nr != mat_nr) {
+ mat_nr= pa->mat_nr;
+ ma= give_render_material(re, ob, mat_nr);
+ }
+
+ if(ma->ipo) {
+ /* correction for lifetime */
+ ptime= 100.0*(ctime-pa->time)/pa->lifetime;
+ calc_ipo(ma->ipo, ptime);
+ execute_ipo((ID *)ma, ma->ipo);
+ }
+
+ //NT scale halos FSPARTICLE
+ if(useFluidsimParticles) {
+ // rescale to 1.0-10.0, then div by 5 afterwards, gives values in range 0.2-2.0
+ double fspsize = ((double)pa->rt / 1000.0f) / 5.0 ;
+ haloScale = 1.0/(float)pow(fspsize, (double)ob->fluidsimSettings->particleInfSize);
+ ma->alpha = iniAlpha / (float)pow( fspsize, (double)ob->fluidsimSettings->particleInfAlpha);
+ if(ma->alpha>1.) ma->alpha = 1.;
+ }
+
+ hasize= ma->hasize * haloScale;
+
+ if(ma->mode & MA_HALOPUNO) {
+ xn= pa->no[0];
+ yn= pa->no[1];
+ zn= pa->no[2];
+
+ /* transpose ! */
+ nor[0]= imat[0][0]*xn+imat[0][1]*yn+imat[0][2]*zn;
+ nor[1]= imat[1][0]*xn+imat[1][1]*yn+imat[1][2]*zn;
+ nor[2]= imat[2][0]*xn+imat[2][1]*yn+imat[2][2]*zn;
+ Normalize(nor);
+
+ VECCOPY(view, vec);
+ Normalize(view);
+
+ zn= nor[0]*view[0]+nor[1]*view[1]+nor[2]*view[2];
+ if(zn>=0.0) hasize= 0.0;
+ else hasize*= zn*zn*zn*zn;
+ }
+
+ if(paf->stype==PAF_VECT) har= RE_inithalo(re, ma, vec, vec1, pa->co, hasize, paf->vectsize, seed);
+ else {
+ har= RE_inithalo(re, ma, vec, NULL, pa->co, hasize, 0.0, seed);
+ if(har && ma->mode & MA_HALO_SHADE) {
+ VecSubf(har->no, vec, vec1);
+ Normalize(har->no);
+ }
+ }
+ if(har) har->lay= ob->lay;
+ }
+
+ /* restore material */
+ for(a=1; a<=ob->totcol; a++) {
+ ma= give_render_material(re, ob, a);
+ if(ma) do_mat_ipo(ma);
+ }
+
+ if(paf->disp!=100) {
+ MEM_freeN(paf->keys);
+ paf->keys= NULL;
+ }
+
+ if(useFluidsimParticles) { ma->alpha = iniAlpha; }// FSPARTICLE restore...
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+/* future thread problem... */
+static void static_particle_strand(Render *re, Object *ob, Material *ma, float *orco, float *vec, float *vec1, float ctime, int first)
+{
+ static VertRen *v1= NULL, *v2= NULL;
+ VlakRen *vlr;
+ float nor[3], cross[3], w, dx, dy, width;
+ int flag;
+
+ VecSubf(nor, vec, vec1);
+ Normalize(nor); // nor needed as tangent
+ Crossf(cross, vec, nor);
+
+ /* turn cross in pixelsize */
+ w= vec[2]*re->winmat[2][3] + re->winmat[3][3];
+ dx= re->winx*cross[0]*re->winmat[0][0]/w;
+ dy= re->winy*cross[1]*re->winmat[1][1]/w;
+ w= sqrt(dx*dx + dy*dy);
+ if(w!=0.0f) {
+ float fac;
+ if(ma->strand_ease!=0.0f) {
+ if(ma->strand_ease<0.0f)
+ fac= pow(ctime, 1.0+ma->strand_ease);
+ else
+ fac= pow(ctime, 1.0/(1.0f-ma->strand_ease));
+ }
+ else fac= ctime;
+
+ width= ((1.0f-fac)*ma->strand_sta + (fac)*ma->strand_end)/w;
+ VecMulf(cross, width);
+ }
+ else width= 1.0f;
+
+ if(ma->mode & MA_TANGENT_STR)
+ flag= R_SMOOTH|R_NOPUNOFLIP|R_TANGENT;
+ else
+ flag= R_SMOOTH;
+
+ /* only 1 pixel wide strands filled in as quads now, otherwise zbuf errors */
+ if(ma->strand_sta==1.0f)
+ flag |= R_STRAND;
+
+ /* first two vertices */
+ if(first) {
+ v1= RE_findOrAddVert(re, re->totvert++);
+ v2= RE_findOrAddVert(re, re->totvert++);
+
+ VECCOPY(v1->co, vec);
+ VecAddf(v1->co, v1->co, cross);
+ VECCOPY(v1->n, nor);
+ v1->orco= orco;
+ v1->accum= -1.0f; // accum abuse for strand texco
+
+ VECCOPY(v2->co, vec);
+ VecSubf(v2->co, v2->co, cross);
+ VECCOPY(v2->n, nor);
+ v2->orco= orco;
+ v2->accum= v1->accum;
+ }
+ else {
+
+ vlr= RE_findOrAddVlak(re, re->totvlak++);
+ vlr->flag= flag;
+ vlr->ob= ob;
+ vlr->v1= v1;
+ vlr->v2= v2;
+ vlr->v3= RE_findOrAddVert(re, re->totvert++);
+ vlr->v4= RE_findOrAddVert(re, re->totvert++);
+
+ v1= vlr->v4; // cycle
+ v2= vlr->v3; // cycle
+
+ VECCOPY(vlr->v4->co, vec);
+ VecAddf(vlr->v4->co, vlr->v4->co, cross);
+ VECCOPY(vlr->v4->n, nor);
+ vlr->v4->orco= orco;
+ vlr->v4->accum= -1.0f + 2.0f*ctime; // accum abuse for strand texco
+
+ VECCOPY(vlr->v3->co, vec);
+ VecSubf(vlr->v3->co, vlr->v3->co, cross);
+ VECCOPY(vlr->v3->n, nor);
+ vlr->v3->orco= orco;
+ vlr->v3->accum= vlr->v4->accum;
+
+ CalcNormFloat4(vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co, vlr->n);
+
+ vlr->mat= ma;
+ vlr->ec= ME_V2V3;
+ vlr->lay= ob->lay;
+ }
+}
+
+static void render_static_particle_system(Render *re, Object *ob, PartEff *paf)
+{
+ Particle *pa=0;
+ HaloRen *har=0;
+ Material *ma=0;
+ VertRen *v1= NULL;
+ VlakRen *vlr;
+ float xn, yn, zn, imat[3][3], mat[4][4], hasize;
+ float mtime, ptime, ctime, vec[3], vec1[3], view[3], nor[3];
+ float *orco= NULL, loc_tex[3], size_tex[3];
+ int a, mat_nr=1, seed, totvlako, totverto, first;
+
+ pa= paf->keys;
+ if(pa==NULL || (paf->flag & PAF_ANIMATED) || paf->disp!=100) {
+ build_particle_system(ob);
+ pa= paf->keys;
+ if(pa==NULL) return;
+ }
+
+ totvlako= re->totvlak;
+ totverto= re->totvert;
+
+ ma= give_render_material(re, ob, paf->omat);
+ if(ma->mode & MA_HALO)
+ re->flag |= R_HALO;
+
+ MTC_Mat4MulMat4(mat, ob->obmat, re->viewmat);
+ MTC_Mat4Invert(ob->imat, mat); /* need to be that way, for imat texture */
+
+ MTC_Mat3CpyMat4(imat, ob->imat);
+
+ /* orcos */
+ if(!(ma->mode & (MA_HALO|MA_WIRE))) {
+ orco= MEM_mallocN(3*sizeof(float)*paf->totpart, "static particle orcos");
+ if (!re->orco_hash)
+ re->orco_hash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
+ BLI_ghash_insert(re->orco_hash, paf, orco); /* pointer is particles, otherwise object uses it */
+ }
+
+ mesh_get_texspace(ob->data, loc_tex, NULL, size_tex);
+
+ if(ob->ipoflag & OB_OFFS_PARTICLE) ptime= ob->sf;
+ else ptime= 0.0;
+ ctime= bsystem_time(ob, (float)re->scene->r.cfra, ptime);
+ seed= ma->seed1;
+
+ for(a=0; a<paf->totpart; a++, pa+=paf->totkey) {
+
+ where_is_particle(paf, pa, pa->time, vec1);
+ if(orco) {
+ orco[0] = (vec1[0]-loc_tex[0])/size_tex[0];
+ orco[1] = (vec1[1]-loc_tex[1])/size_tex[1];
+ orco[2] = (vec1[2]-loc_tex[2])/size_tex[2];
+ }
+ MTC_Mat4MulVecfl(mat, vec1);
+ mtime= pa->time+pa->lifetime+paf->staticstep-1;
+
+ first= 1;
+ for(ctime= pa->time; ctime<mtime; ctime+=paf->staticstep) {
+
+ /* make sure hair grows until the end.. */
+ if(ctime>pa->time+pa->lifetime) ctime= pa->time+pa->lifetime;
+
+ /* watch it: also calc the normal of a particle */
+ if(paf->stype==PAF_VECT || ma->mode & MA_HALO_SHADE) {
+ where_is_particle(paf, pa, ctime+1.0, vec);
+ MTC_Mat4MulVecfl(mat, vec);
+ }
+ else {
+ where_is_particle(paf, pa, ctime, vec);
+ MTC_Mat4MulVecfl(mat, vec);
+ }
+
+ if(pa->mat_nr != mat_nr) {
+ mat_nr= pa->mat_nr;
+ ma= give_render_material(re, ob, mat_nr);
+ }
+
+ /* wires */
+ if(ma->mode & MA_WIRE) {
+ if(ctime == pa->time) {
+ v1= RE_findOrAddVert(re, re->totvert++);
+ VECCOPY(v1->co, vec);
+ }
+ else {
+ vlr= RE_findOrAddVlak(re, re->totvlak++);
+ vlr->ob= ob;
+ vlr->v1= v1;
+ vlr->v2= RE_findOrAddVert(re, re->totvert++);
+ vlr->v3= vlr->v2;
+ vlr->v4= NULL;
+
+ v1= vlr->v2; // cycle
+ VECCOPY(v1->co, vec);
+
+ VecSubf(vlr->n, vec, vec1);
+ Normalize(vlr->n);
+ VECCOPY(v1->n, vlr->n);
+
+ vlr->mat= ma;
+ vlr->ec= ME_V1V2;
+ vlr->lay= ob->lay;
+ }
+ }
+ else {
+ if(ma->ipo) {
+ /* correction for lifetime */
+ ptime= 100.0*(ctime-pa->time)/pa->lifetime;
+ calc_ipo(ma->ipo, ptime);
+ execute_ipo((ID *)ma, ma->ipo);
+ }
+
+ if(ma->mode & MA_HALO) {
+ hasize= ma->hasize;
+
+ if(ma->mode & MA_HALOPUNO) {
+ xn= pa->no[0];
+ yn= pa->no[1];
+ zn= pa->no[2];
+
+ /* transpose ! */
+ nor[0]= imat[0][0]*xn+imat[0][1]*yn+imat[0][2]*zn;
+ nor[1]= imat[1][0]*xn+imat[1][1]*yn+imat[1][2]*zn;
+ nor[2]= imat[2][0]*xn+imat[2][1]*yn+imat[2][2]*zn;
+ Normalize(nor);
+
+ VECCOPY(view, vec);
+ Normalize(view);
+
+ zn= nor[0]*view[0]+nor[1]*view[1]+nor[2]*view[2];
+ if(zn>=0.0) hasize= 0.0;
+ else hasize*= zn*zn*zn*zn;
+ }
+
+ if(paf->stype==PAF_VECT) har= RE_inithalo(re, ma, vec, vec1, pa->co, hasize, paf->vectsize, seed);
+ else {
+ har= RE_inithalo(re, ma, vec, NULL, pa->co, hasize, 0.0, seed);
+ if(har && (ma->mode & MA_HALO_SHADE)) {
+ VecSubf(har->no, vec, vec1);
+ Normalize(har->no);
+ har->lay= ob->lay;
+ }
+ }
+ if(har) har->lay= ob->lay;
+ }
+ else { /* generate pixel sized hair strand */
+ float strandco= 1.0f;
+
+ /* last strand, texco to end */
+ if(ctime + paf->staticstep < mtime)
+ strandco= (ctime-pa->time)/(mtime-pa->time);
+
+ static_particle_strand(re, ob, ma, orco, vec, vec1, strandco, first);
+ }
+ }
+
+ VECCOPY(vec1, vec);
+ first= 0;
+ }
+
+ seed++;
+ if(orco) orco+=3;
+ }
+
+ if(paf->disp!=100) {
+ MEM_freeN(paf->keys);
+ paf->keys= NULL;
+ }
+
+ if((ma->mode & MA_TANGENT_STR)==0)
+ calc_vertexnormals(re, totverto, totvlako, 0);
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+static int verghalo(const void *a1, const void *a2)
+{
+ const struct halosort *x1=a1, *x2=a2;
+
+ if( x1->z < x2->z ) return 1;
+ else if( x1->z > x2->z) return -1;
+ return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+static void sort_halos(Render *re)
+{
+ struct halosort *hablock, *haso;
+ HaloRen *har = NULL, **bloha;
+ int a;
+
+ if(re->tothalo==0) return;
+
+ /* make datablock with halo pointers, sort */
+ haso= hablock= MEM_mallocN(sizeof(struct halosort)*re->tothalo, "hablock");
+
+ for(a=0; a<re->tothalo; a++) {
+ if((a & 255)==0) har= re->bloha[a>>8];
+ else har++;
+ haso->har= har;
+ haso->z= har->zs;
+ haso++;
+ }
+
+ qsort(hablock, re->tothalo, sizeof(struct halosort), verghalo);
+
+ /* re-assamble re->bloha */
+
+ bloha= re->bloha;
+ re->bloha= (HaloRen **)MEM_callocN(sizeof(void *)*(re->blohalen),"Bloha");
+
+ haso= hablock;
+ for(a=0; a<re->tothalo; a++) {
+ har= RE_findOrAddHalo(re, a);
+ *har= *(haso->har);
+
+ haso++;
+ }
+
+ /* free */
+ a= 0;
+ while(bloha[a]) {
+ MEM_freeN(bloha[a]);
+ a++;
+ }
+ MEM_freeN(bloha);
+ MEM_freeN(hablock);
+
+}
+
+/* ------------------------------------------------------------------------- */
+static void init_render_mball(Render *re, Object *ob)
+{
+ DispList *dl;
+ VertRen *ver;
+ VlakRen *vlr, *vlr1;
+ Material *ma;
+ float *data, *nors, mat[4][4], imat[3][3], xn, yn, zn;
+ int a, need_orco, startvert, *index;
+
+ if (ob!=find_basis_mball(ob))
+ return;
+
+ MTC_Mat4MulMat4(mat, ob->obmat, re->viewmat);
+ MTC_Mat4Invert(ob->imat, mat);
+ MTC_Mat3CpyMat4(imat, ob->imat);
+
+ ma= give_render_material(re, ob, 1);
+
+ need_orco= 0;
+ if(ma->texco & TEXCO_ORCO) {
+ need_orco= 1;
+ }
+
+ makeDispListMBall(ob);
+ dl= ob->disp.first;
+ if(dl==0) return;
+
+ startvert= re->totvert;
+ data= dl->verts;
+ nors= dl->nors;
+
+ for(a=0; a<dl->nr; a++, data+=3, nors+=3) {
+
+ ver= RE_findOrAddVert(re, re->totvert++);
+ VECCOPY(ver->co, data);
+ MTC_Mat4MulVecfl(mat, ver->co);
+
+ xn= nors[0];
+ yn= nors[1];
+ zn= nors[2];
+
+ /* transpose ! */
+ ver->n[0]= imat[0][0]*xn+imat[0][1]*yn+imat[0][2]*zn;
+ ver->n[1]= imat[1][0]*xn+imat[1][1]*yn+imat[1][2]*zn;
+ ver->n[2]= imat[2][0]*xn+imat[2][1]*yn+imat[2][2]*zn;
+ Normalize(ver->n);
+ //if(ob->transflag & OB_NEG_SCALE) VecMulf(ver->n. -1.0);
+
+ if(need_orco) ver->orco= data;
+ }
+
+ index= dl->index;
+ for(a=0; a<dl->parts; a++, index+=4) {
+
+ vlr= RE_findOrAddVlak(re, re->totvlak++);
+ vlr->ob= ob;
+ vlr->v1= RE_findOrAddVert(re, startvert+index[0]);
+ vlr->v2= RE_findOrAddVert(re, startvert+index[1]);
+ vlr->v3= RE_findOrAddVert(re, startvert+index[2]);
+ vlr->v4= 0;
+
+ if(ob->transflag & OB_NEG_SCALE)
+ CalcNormFloat(vlr->v1->co, vlr->v2->co, vlr->v3->co, vlr->n);
+ else
+ CalcNormFloat(vlr->v3->co, vlr->v2->co, vlr->v1->co, vlr->n);
+
+ vlr->mat= ma;
+ vlr->flag= ME_SMOOTH+R_NOPUNOFLIP;
+ vlr->ec= 0;
+ vlr->lay= ob->lay;
+
+ /* mball -too bad- always has triangles, because quads can be non-planar */
+ if(index[3] && index[3]!=index[2]) {
+ vlr1= RE_findOrAddVlak(re, re->totvlak++);
+ *vlr1= *vlr;
+ vlr1->v2= vlr1->v3;
+ vlr1->v3= RE_findOrAddVert(re, startvert+index[3]);
+ if(ob->transflag & OB_NEG_SCALE)
+ CalcNormFloat(vlr1->v1->co, vlr1->v2->co, vlr1->v3->co, vlr1->n);
+ else
+ CalcNormFloat(vlr1->v3->co, vlr1->v2->co, vlr1->v1->co, vlr1->n);
+ }
+ }
+
+ if(need_orco) {
+ /* store displist and scale */
+ make_orco_mball(ob);
+ }
+ else {
+ /* enforce display lists remade */
+ freedisplist(&ob->disp);
+ }
+
+ /* this enforces remake for real, orco displist is small (in scale) */
+ ob->recalc |= OB_RECALC_DATA;
+}
+/* ------------------------------------------------------------------------- */
+/* convert */
+
+static int vlakren_customdata_layer_num(int n, int active)
+{
+ /* make the active layer the first */
+ if (n == active) return 0;
+ else if (n < active) return n+1;
+ else return n;
+}
+
+struct edgesort {
+ int v1, v2;
+ int f;
+ int i1, i2;
+};
+
+/* edges have to be added with lowest index first for sorting */
+static void to_edgesort(struct edgesort *ed, int i1, int i2, int v1, int v2, int f)
+{
+ if(v1>v2) {
+ SWAP(int, v1, v2);
+ SWAP(int, i1, i2);
+ }
+
+ ed->v1= v1;
+ ed->v2= v2;
+ ed->i1= i1;
+ ed->i2= i2;
+ ed->f = f;
+}
+
+static int vergedgesort(const void *v1, const void *v2)
+{
+ const struct edgesort *x1=v1, *x2=v2;
+
+ if( x1->v1 > x2->v1) return 1;
+ else if( x1->v1 < x2->v1) return -1;
+ else if( x1->v2 > x2->v2) return 1;
+ else if( x1->v2 < x2->v2) return -1;
+
+ return 0;
+}
+
+static struct edgesort *make_mesh_edge_lookup(DerivedMesh *dm, int *totedgesort)
+{
+ MFace *mf, *mface;
+ MTFace *tface=NULL;
+ struct edgesort *edsort, *ed;
+ unsigned int *mcol=NULL;
+ int a, totedge=0, totface;
+
+ mface= dm->getFaceArray(dm);
+ totface= dm->getNumFaces(dm);
+ tface= dm->getFaceDataArray(dm, CD_MTFACE);
+ mcol= dm->getFaceDataArray(dm, CD_MCOL);
+
+ if(mcol==NULL && tface==NULL) return NULL;
+
+ /* make sorted table with edges and face indices in it */
+ for(a= totface, mf= mface; a>0; a--, mf++) {
+ if(mf->v4) totedge+=4;
+ else if(mf->v3) totedge+=3;
+ }
+
+ if(totedge==0)
+ return NULL;
+
+ ed= edsort= MEM_callocN(totedge*sizeof(struct edgesort), "edgesort");
+
+ for(a=0, mf=mface; a<totface; a++, mf++) {
+ to_edgesort(ed++, 0, 1, mf->v1, mf->v2, a);
+ to_edgesort(ed++, 1, 2, mf->v2, mf->v3, a);
+ if(mf->v4) {
+ to_edgesort(ed++, 2, 3, mf->v3, mf->v4, a);
+ to_edgesort(ed++, 3, 0, mf->v4, mf->v1, a);
+ }
+ else if(mf->v3)
+ to_edgesort(ed++, 2, 3, mf->v3, mf->v1, a);
+ }
+
+ qsort(edsort, totedge, sizeof(struct edgesort), vergedgesort);
+
+ *totedgesort= totedge;
+
+ return edsort;
+}
+
+static void use_mesh_edge_lookup(Render *re, DerivedMesh *dm, MEdge *medge, VlakRen *vlr, struct edgesort *edgetable, int totedge)
+{
+ struct edgesort ed, *edp;
+ CustomDataLayer *layer;
+ MTFace *mtface, *mtf;
+ MCol *mcol, *mc;
+ int index, mtfn, mcn, n;
+ char *name;
+
+ if(medge->v1 < medge->v2) {
+ ed.v1= medge->v1;
+ ed.v2= medge->v2;
+ }
+ else {
+ ed.v1= medge->v2;
+ ed.v2= medge->v1;
+ }
+
+ edp= bsearch(&ed, edgetable, totedge, sizeof(struct edgesort), vergedgesort);
+
+ /* since edges have different index ordering, we have to duplicate mcol and tface */
+ if(edp) {
+ mtfn= mcn= 0;
+
+ for(index=0; index<dm->faceData.totlayer; index++) {
+ layer= &dm->faceData.layers[index];
+ name= layer->name;
+
+ if(layer->type == CD_MTFACE && mtfn < MAX_MTFACE) {
+ mtface= &((MTFace*)layer->data)[edp->f];
+ n= vlakren_customdata_layer_num(mtfn++, layer->active_rnd);
+ mtf= RE_vlakren_get_tface(re, vlr, n, &name, 1);
+
+ *mtf= *mtface;
+
+ memcpy(mtf->uv[0], mtface->uv[edp->i1], sizeof(float)*2);
+ memcpy(mtf->uv[1], mtface->uv[edp->i2], sizeof(float)*2);
+ memcpy(mtf->uv[2], mtface->uv[1], sizeof(float)*2);
+ memcpy(mtf->uv[3], mtface->uv[1], sizeof(float)*2);
+ }
+ else if(layer->type == CD_MCOL && mcn < MAX_MCOL) {
+ mcol= &((MCol*)layer->data)[edp->f*4];
+ n= vlakren_customdata_layer_num(mcn++, layer->active_rnd);
+ mc= RE_vlakren_get_mcol(re, vlr, n, &name, 1);
+
+ mc[0]= mcol[edp->i1];
+ mc[1]= mc[2]= mc[3]= mcol[edp->i2];
+ }
+ }
+ }
+}
+
+static void init_render_mesh(Render *re, Object *ob, Object *par, int only_verts)
+{
+ Mesh *me;
+ MVert *mvert = NULL;
+ MFace *mface;
+ VlakRen *vlr; //, *vlr1;
+ VertRen *ver;
+ Material *ma;
+ MSticky *ms = NULL;
+ PartEff *paf;
+ DerivedMesh *dm;
+ float xn, yn, zn, imat[3][3], mat[4][4]; //nor[3],
+ float *orco=0;
+ int a, a1, ok, need_orco=0, need_stress=0, need_tangent=0, totvlako, totverto, vertofs;
+ int end, do_autosmooth=0, totvert = 0;
+ int useFluidmeshNormals= 0; // NT fluidsim, use smoothed normals?
+ int use_original_normals= 0;
+
+ me= ob->data;
+
+ paf = give_parteff(ob);
+ if(paf) {
+ /* warning; build_particle_system does modifier calls itself */
+ if(paf->flag & PAF_STATIC) render_static_particle_system(re, ob, paf);
+ else render_particle_system(re, ob, par, paf);
+ if((paf->flag & PAF_SHOWE)==0) return;
+ }
+
+ MTC_Mat4MulMat4(mat, ob->obmat, re->viewmat);
+ MTC_Mat4Invert(ob->imat, mat);
+ MTC_Mat3CpyMat4(imat, ob->imat);
+
+ if(me->totvert==0) {
+ return;
+ }
+
+ totvlako= re->totvlak;
+ totverto= re->totvert;
+
+ need_orco= 0;
+ for(a=1; a<=ob->totcol; a++) {
+ ma= give_render_material(re, ob, a);
+ if(ma) {
+ if(ma->texco & (TEXCO_ORCO|TEXCO_STRESS))
+ need_orco= 1;
+ if(ma->texco & TEXCO_STRESS)
+ need_stress= 1;
+ /* normalmaps, test if tangents needed, separated from shading */
+ if ((ma->mode_l & MA_TANGENT_V) || (ma->mode_l & MA_NORMAP_TANG)) {
+ need_tangent= 1;
+ if(me->mtface==NULL)
+ need_orco= 1;
+ }
+ /* radio faces need autosmooth, to separate shared vertices in corners */
+ if(re->r.mode & R_RADIO)
+ if(ma->mode & MA_RADIO)
+ do_autosmooth= 1;
+ }
+ }
+
+ /* check autosmooth and displacement, we then have to skip only-verts optimize */
+ do_autosmooth |= (me->flag & ME_AUTOSMOOTH);
+ if(do_autosmooth)
+ only_verts= 0;
+ if(test_for_displace(re, ob ) )
+ only_verts= 0;
+
+ if(!only_verts)
+ if(need_orco) orco = get_object_orco(re, ob);
+
+ dm = mesh_create_derived_render(ob,
+ CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL);
+
+ if(dm==NULL) return; /* in case duplicated object fails? */
+
+ if((ob->fluidsimFlag & OB_FLUIDSIM_ENABLE) &&
+ (ob->fluidsimSettings->type & OB_FLUIDSIM_DOMAIN)&&
+ (ob->fluidsimSettings->meshSurface) ) {
+ useFluidmeshNormals = 1;
+ }
+
+ mvert= dm->getVertArray(dm);
+ totvert= dm->getNumVerts(dm);
+
+ /* attempt to autsmooth on original mesh, only without subsurf */
+ if(do_autosmooth && me->totvert==totvert && me->totface==dm->getNumFaces(dm))
+ use_original_normals= 1;
+
+ ms = (totvert==me->totvert)?me->msticky:NULL;
+
+ ma= give_render_material(re, ob, 1);
+
+ if(ma->mode & MA_HALO) {
+ make_render_halos(re, ob, me, totvert, mvert, ma, orco);
+ }
+ else {
+
+ for(a=0; a<totvert; a++, mvert++) {
+ ver= RE_findOrAddVert(re, re->totvert++);
+ VECCOPY(ver->co, mvert->co);
+ if(do_autosmooth==0) /* autosmooth on original unrotated data to prevent differences between frames */
+ MTC_Mat4MulVecfl(mat, ver->co);
+
+ if(useFluidmeshNormals) {
+ xn = mvert->no[0]/ 32767.0;
+ yn = mvert->no[1]/ 32767.0;
+ zn = mvert->no[2]/ 32767.0;
+ /* transfor to cam space */
+ ver->n[0]= imat[0][0]*xn+imat[0][1]*yn+imat[0][2]*zn;
+ ver->n[1]= imat[1][0]*xn+imat[1][1]*yn+imat[1][2]*zn;
+ ver->n[2]= imat[2][0]*xn+imat[2][1]*yn+imat[2][2]*zn;
+ } // useFluidmeshNormals
+
+ if(orco) {
+ ver->orco= orco;
+ orco+=3;
+ }
+ if(ms) {
+ float *sticky= RE_vertren_get_sticky(re, ver, 1);
+ sticky[0]= ms->co[0];
+ sticky[1]= ms->co[1];
+ ms++;
+ }
+ }
+
+ if(!only_verts) {
+ /* store customdata names, because DerivedMesh is freed */
+ RE_vlakren_set_customdata_names(re, &dm->faceData);
+
+ /* still to do for keys: the correct local texture coordinate */
+
+ /* faces in order of color blocks */
+ vertofs= re->totvert - totvert;
+ for(a1=0; (a1<ob->totcol || (a1==0 && ob->totcol==0)); a1++) {
+
+ ma= give_render_material(re, ob, a1+1);
+
+ /* test for 100% transparant */
+ ok= 1;
+ if(ma->alpha==0.0 && ma->spectra==0.0) {
+ ok= 0;
+ /* texture on transparency? */
+ for(a=0; a<MAX_MTEX; a++) {
+ if(ma->mtex[a] && ma->mtex[a]->tex) {
+ if(ma->mtex[a]->mapto & MAP_ALPHA) ok= 1;
+ }
+ }
+ }
+
+ /* if wire material, and we got edges, don't do the faces */
+ if(ma->mode & MA_WIRE) {
+ end= dm->getNumEdges(dm);
+ if(end) ok= 0;
+ }
+
+ if(ok) {
+ end= dm->getNumFaces(dm);
+ mface= dm->getFaceArray(dm);
+
+ for(a=0; a<end; a++, mface++) {
+ int v1, v2, v3, v4, flag;
+
+ if( mface->mat_nr==a1 ) {
+ float len;
+
+ v1= mface->v1;
+ v2= mface->v2;
+ v3= mface->v3;
+ v4= mface->v4;
+ flag= mface->flag & ME_SMOOTH;
+
+ vlr= RE_findOrAddVlak(re, re->totvlak++);
+ vlr->ob= ob;
+ vlr->v1= RE_findOrAddVert(re, vertofs+v1);
+ vlr->v2= RE_findOrAddVert(re, vertofs+v2);
+ vlr->v3= RE_findOrAddVert(re, vertofs+v3);
+ if(v4) vlr->v4= RE_findOrAddVert(re, vertofs+v4);
+ else vlr->v4= 0;
+
+ /* render normals are inverted in render */
+ if(use_original_normals) {
+ MFace *mf= me->mface+a;
+ MVert *mv= me->mvert;
+
+ if(vlr->v4)
+ len= CalcNormFloat4( mv[mf->v4].co, mv[mf->v3].co, mv[mf->v2].co, mv[mf->v1].co, vlr->n);
+ else
+ len= CalcNormFloat(mv[mf->v3].co, mv[mf->v2].co, mv[mf->v1].co, vlr->n);
+ }
+ else {
+ if(vlr->v4)
+ len= CalcNormFloat4(vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co, vlr->n);
+ else
+ len= CalcNormFloat(vlr->v3->co, vlr->v2->co, vlr->v1->co, vlr->n);
+ }
+
+ vlr->mat= ma;
+ vlr->flag= flag;
+ if((me->flag & ME_NOPUNOFLIP) ) {
+ vlr->flag |= R_NOPUNOFLIP;
+ }
+ vlr->ec= 0; /* mesh edges rendered separately */
+ vlr->lay= ob->lay;
+
+ if(len==0) re->totvlak--;
+ else {
+ CustomDataLayer *layer;
+ MTFace *mtface, *mtf;
+ MCol *mcol, *mc;
+ int index, mtfn= 0, mcn= 0, n;
+ char *name;
+
+ for(index=0; index<dm->faceData.totlayer; index++) {
+ layer= &dm->faceData.layers[index];
+ name= layer->name;
+
+ if(layer->type == CD_MTFACE && mtfn < MAX_MTFACE) {
+ n= vlakren_customdata_layer_num(mtfn++, layer->active_rnd);
+ mtf= RE_vlakren_get_tface(re, vlr, n, &name, 1);
+ mtface= (MTFace*)layer->data;
+ *mtf= mtface[a];
+ }
+ else if(layer->type == CD_MCOL && mcn < MAX_MCOL) {
+ n= vlakren_customdata_layer_num(mcn++, layer->active_rnd);
+ mc= RE_vlakren_get_mcol(re, vlr, n, &name, 1);
+ mcol= (MCol*)layer->data;
+ memcpy(mc, &mcol[a*4], sizeof(MCol)*4);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* exception... we do edges for wire mode. potential conflict when faces exist... */
+ end= dm->getNumEdges(dm);
+ mvert= dm->getVertArray(dm);
+ ma= give_render_material(re, ob, 1);
+ if(end && (ma->mode & MA_WIRE)) {
+ MEdge *medge;
+ struct edgesort *edgetable;
+ int totedge= 0;
+
+ medge= dm->getEdgeArray(dm);
+
+ /* we want edges to have UV and vcol too... */
+ edgetable= make_mesh_edge_lookup(dm, &totedge);
+
+ for(a1=0; a1<end; a1++, medge++) {
+ if (medge->flag&ME_EDGERENDER) {
+ MVert *v0 = &mvert[medge->v1];
+ MVert *v1 = &mvert[medge->v2];
+
+ vlr= RE_findOrAddVlak(re, re->totvlak++);
+ vlr->ob= ob;
+ vlr->v1= RE_findOrAddVert(re, vertofs+medge->v1);
+ vlr->v2= RE_findOrAddVert(re, vertofs+medge->v2);
+ vlr->v3= vlr->v2;
+ vlr->v4= NULL;
+
+ if(edgetable) {
+ use_mesh_edge_lookup(re, dm, medge, vlr, edgetable, totedge);
+ }
+
+ xn= -(v0->no[0]+v1->no[0]);
+ yn= -(v0->no[1]+v1->no[1]);
+ zn= -(v0->no[2]+v1->no[2]);
+ /* transpose ! */
+ vlr->n[0]= imat[0][0]*xn+imat[0][1]*yn+imat[0][2]*zn;
+ vlr->n[1]= imat[1][0]*xn+imat[1][1]*yn+imat[1][2]*zn;
+ vlr->n[2]= imat[2][0]*xn+imat[2][1]*yn+imat[2][2]*zn;
+ Normalize(vlr->n);
+
+ vlr->mat= ma;
+ vlr->flag= 0;
+ vlr->ec= ME_V1V2;
+ vlr->lay= ob->lay;
+ }
+ }
+ if(edgetable)
+ MEM_freeN(edgetable);
+ }
+ }
+ }
+
+ if(!only_verts) {
+ if (test_for_displace(re, ob ) ) {
+ calc_vertexnormals(re, totverto, totvlako, 0);
+ do_displacement(re, ob, totvlako, re->totvlak-totvlako, totverto, re->totvert-totverto);
+ }
+
+ if(do_autosmooth) {
+ autosmooth(re, mat, totverto, totvlako, me->smoothresh);
+ }
+
+ if(useFluidmeshNormals) {
+ // do not recalculate, only init render data
+ calc_fluidsimnormals(re, totverto, totvlako, need_tangent);
+ } else {
+ calc_vertexnormals(re, totverto, totvlako, need_tangent);
+ }
+
+ if(need_stress)
+ calc_edge_stress(re, me, totverto, totvlako);
+ }
+
+ dm->release(dm);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void initshadowbuf(Render *re, LampRen *lar, float mat[][4])
+{
+ struct ShadBuf *shb;
+ float viewinv[4][4];
+
+ /* if(la->spsi<16) return; */
+
+ /* memory alloc */
+ shb= (struct ShadBuf *)MEM_callocN( sizeof(struct ShadBuf),"initshadbuf");
+ lar->shb= shb;
+
+ if(shb==NULL) return;
+
+ VECCOPY(shb->co, lar->co);
+
+ /* percentage render: keep track of min and max */
+ shb->size= (lar->bufsize*re->r.size)/100;
+
+ if(lar->buffers>1) shb->size/= 2;
+
+ if(shb->size<512) shb->size= 512;
+ else if(shb->size > lar->bufsize) shb->size= lar->bufsize;
+
+ shb->size &= ~15; /* make sure its multiples of 16 */
+
+ shb->samp= lar->samp;
+ shb->soft= lar->soft;
+ shb->shadhalostep= lar->shadhalostep;
+
+ MTC_Mat4Ortho(mat);
+ MTC_Mat4Invert(shb->winmat, mat); /* winmat is temp */
+
+ /* matrix: combination of inverse view and lampmat */
+ /* calculate again: the ortho-render has no correct viewinv */
+ MTC_Mat4Invert(viewinv, re->viewmat);
+ MTC_Mat4MulMat4(shb->viewmat, viewinv, shb->winmat);
+
+ /* projection */
+ shb->d= lar->clipsta;
+ shb->clipend= lar->clipend;
+
+ /* bias is percentage, made 2x larger because of correction for angle of incidence */
+ /* when a ray is closer to parallel of a face, bias value is increased during render */
+ shb->bias= (0.02*lar->bias)*0x7FFFFFFF;
+ shb->bias= shb->bias*(100/re->r.size);
+
+ /* halfway method (average of first and 2nd z) reduces bias issues */
+ if(lar->buftype==LA_SHADBUF_HALFWAY)
+ shb->bias= 0.1f*shb->bias;
+
+}
+
+
+static void area_lamp_vectors(LampRen *lar)
+{
+ float xsize= 0.5*lar->area_size, ysize= 0.5*lar->area_sizey;
+
+ /* corner vectors */
+ lar->area[0][0]= lar->co[0] - xsize*lar->mat[0][0] - ysize*lar->mat[1][0];
+ lar->area[0][1]= lar->co[1] - xsize*lar->mat[0][1] - ysize*lar->mat[1][1];
+ lar->area[0][2]= lar->co[2] - xsize*lar->mat[0][2] - ysize*lar->mat[1][2];
+
+ /* corner vectors */
+ lar->area[1][0]= lar->co[0] - xsize*lar->mat[0][0] + ysize*lar->mat[1][0];
+ lar->area[1][1]= lar->co[1] - xsize*lar->mat[0][1] + ysize*lar->mat[1][1];
+ lar->area[1][2]= lar->co[2] - xsize*lar->mat[0][2] + ysize*lar->mat[1][2];
+
+ /* corner vectors */
+ lar->area[2][0]= lar->co[0] + xsize*lar->mat[0][0] + ysize*lar->mat[1][0];
+ lar->area[2][1]= lar->co[1] + xsize*lar->mat[0][1] + ysize*lar->mat[1][1];
+ lar->area[2][2]= lar->co[2] + xsize*lar->mat[0][2] + ysize*lar->mat[1][2];
+
+ /* corner vectors */
+ lar->area[3][0]= lar->co[0] + xsize*lar->mat[0][0] - ysize*lar->mat[1][0];
+ lar->area[3][1]= lar->co[1] + xsize*lar->mat[0][1] - ysize*lar->mat[1][1];
+ lar->area[3][2]= lar->co[2] + xsize*lar->mat[0][2] - ysize*lar->mat[1][2];
+ /* only for correction button size, matrix size works on energy */
+ lar->areasize= lar->dist*lar->dist/(4.0*xsize*ysize);
+}
+
+/* If lar takes more lamp data, the decoupling will be better. */
+static GroupObject *add_render_lamp(Render *re, Object *ob)
+{
+ Lamp *la= ob->data;
+ LampRen *lar;
+ GroupObject *go;
+ float mat[4][4], angle, xn, yn;
+ int c;
+
+ /* previewrender sets this to zero... prevent accidents */
+ if(la==NULL) return NULL;
+
+ /* prevent only shadow from rendering light */
+ if(la->mode & LA_ONLYSHADOW)
+ if((re->r.mode & R_SHADOW)==0)
+ return NULL;
+
+ re->totlamp++;
+
+ /* groups is used to unify support for lightgroups, this is the global lightgroup */
+ go= MEM_callocN(sizeof(GroupObject), "groupobject");
+ BLI_addtail(&re->lights, go);
+ go->ob= ob;
+ /* lamprens are in own list, for freeing */
+ lar= (LampRen *)MEM_callocN(sizeof(LampRen),"lampren");
+ BLI_addtail(&re->lampren, lar);
+ go->lampren= lar;
+
+ MTC_Mat4MulMat4(mat, ob->obmat, re->viewmat);
+ MTC_Mat4Invert(ob->imat, mat);
+
+ MTC_Mat3CpyMat4(lar->mat, mat);
+ MTC_Mat3CpyMat4(lar->imat, ob->imat);
+
+ lar->bufsize = la->bufsize;
+ lar->samp = la->samp;
+ lar->buffers= la->buffers;
+ if(lar->buffers==0) lar->buffers= 1;
+ lar->buftype= la->buftype;
+ lar->filtertype= la->filtertype;
+ lar->soft = la->soft;
+ lar->shadhalostep = la->shadhalostep;
+ lar->clipsta = la->clipsta;
+ lar->clipend = la->clipend;
+
+ lar->bias = la->bias;
+
+ lar->type= la->type;
+ lar->mode= la->mode;
+
+ lar->energy= la->energy;
+ if(la->mode & LA_NEG) lar->energy= -lar->energy;
+
+ lar->vec[0]= -mat[2][0];
+ lar->vec[1]= -mat[2][1];
+ lar->vec[2]= -mat[2][2];
+ Normalize(lar->vec);
+ lar->co[0]= mat[3][0];
+ lar->co[1]= mat[3][1];
+ lar->co[2]= mat[3][2];
+ lar->dist= la->dist;
+ lar->haint= la->haint;
+ lar->distkw= lar->dist*lar->dist;
+ lar->r= lar->energy*la->r;
+ lar->g= lar->energy*la->g;
+ lar->b= lar->energy*la->b;
+ lar->k= la->k;
+
+ // area
+ lar->ray_samp= la->ray_samp;
+ lar->ray_sampy= la->ray_sampy;
+ lar->ray_sampz= la->ray_sampz;
+
+ lar->area_size= la->area_size;
+ lar->area_sizey= la->area_sizey;
+ lar->area_sizez= la->area_sizez;
+
+ lar->area_shape= la->area_shape;
+ lar->ray_samp_method= la->ray_samp_method;
+ lar->ray_samp_type= la->ray_samp_type;
+
+ lar->adapt_thresh= la->adapt_thresh;
+
+ if( ELEM3(lar->type, LA_SPOT, LA_SUN, LA_LOCAL)) {
+ lar->ray_totsamp= lar->ray_samp*lar->ray_samp;
+ lar->area_shape = LA_AREA_SQUARE;
+ lar->area_sizey= lar->area_size;
+ }
+ else if(lar->type==LA_AREA) {
+ switch(lar->area_shape) {
+ case LA_AREA_SQUARE:
+ lar->ray_totsamp= lar->ray_samp*lar->ray_samp;
+ lar->ray_sampy= lar->ray_samp;
+ lar->area_sizey= lar->area_size;
+ break;
+ case LA_AREA_RECT:
+ lar->ray_totsamp= lar->ray_samp*lar->ray_sampy;
+ break;
+ case LA_AREA_CUBE:
+ lar->ray_totsamp= lar->ray_samp*lar->ray_samp*lar->ray_samp;
+ lar->ray_sampy= lar->ray_samp;
+ lar->ray_sampz= lar->ray_samp;
+ lar->area_sizey= lar->area_size;
+ lar->area_sizez= lar->area_size;
+ break;
+ case LA_AREA_BOX:
+ lar->ray_totsamp= lar->ray_samp*lar->ray_sampy*lar->ray_sampz;
+ break;
+ }
+
+ area_lamp_vectors(lar);
+ }
+ else lar->ray_totsamp= 0;
+
+#ifndef DISABLE_YAFRAY
+ /* yafray: photonlight and other params */
+ if (re->r.renderer==R_YAFRAY) {
+ lar->YF_numphotons = la->YF_numphotons;
+ lar->YF_numsearch = la->YF_numsearch;
+ lar->YF_phdepth = la->YF_phdepth;
+ lar->YF_useqmc = la->YF_useqmc;
+ lar->YF_causticblur = la->YF_causticblur;
+ lar->YF_ltradius = la->YF_ltradius;
+ lar->YF_bufsize = la->YF_bufsize;
+ lar->YF_glowint = la->YF_glowint;
+ lar->YF_glowofs = la->YF_glowofs;
+ lar->YF_glowtype = la->YF_glowtype;
+ }
+#endif /* disable yafray */
+
+ lar->spotsi= la->spotsize;
+ if(lar->mode & LA_HALO) {
+ if(lar->spotsi>170.0) lar->spotsi= 170.0;
+ }
+ lar->spotsi= cos( M_PI*lar->spotsi/360.0 );
+ lar->spotbl= (1.0-lar->spotsi)*la->spotblend;
+
+ memcpy(lar->mtex, la->mtex, MAX_MTEX*sizeof(void *));
+
+ lar->lay= ob->lay & 0xFFFFFF; // higher 8 bits are localview layers
+
+ lar->falloff_type = la->falloff_type;
+ lar->ld1= la->att1;
+ lar->ld2= la->att2;
+ lar->curfalloff = curvemapping_copy(la->curfalloff);
+
+ if(lar->type==LA_SPOT) {
+
+ Normalize(lar->imat[0]);
+ Normalize(lar->imat[1]);
+ Normalize(lar->imat[2]);
+
+ xn= saacos(lar->spotsi);
+ xn= sin(xn)/cos(xn);
+ lar->spottexfac= 1.0/(xn);
+
+ if(lar->mode & LA_ONLYSHADOW) {
+ if((lar->mode & (LA_SHAD_BUF|LA_SHAD_RAY))==0) lar->mode -= LA_ONLYSHADOW;
+ }
+
+ }
+
+ /* set flag for spothalo en initvars */
+ if(la->type==LA_SPOT && (la->mode & LA_HALO)) {
+ if(la->haint>0.0) {
+ re->flag |= R_LAMPHALO;
+
+ /* camera position (0,0,0) rotate around lamp */
+ lar->sh_invcampos[0]= -lar->co[0];
+ lar->sh_invcampos[1]= -lar->co[1];
+ lar->sh_invcampos[2]= -lar->co[2];
+ MTC_Mat3MulVecfl(lar->imat, lar->sh_invcampos);
+
+ /* z factor, for a normalized volume */
+ angle= saacos(lar->spotsi);
+ xn= lar->spotsi;
+ yn= sin(angle);
+ lar->sh_zfac= yn/xn;
+ /* pre-scale */
+ lar->sh_invcampos[2]*= lar->sh_zfac;
+
+ }
+ }
+ else if(la->type==LA_HEMI) {
+ lar->mode &= ~(LA_SHAD_RAY|LA_SHAD_BUF);
+ }
+
+ for(c=0; c<MAX_MTEX; c++) {
+ if(la->mtex[c] && la->mtex[c]->tex) {
+ lar->mode |= LA_TEXTURE;
+
+ if(G.rendering) {
+ if(re->osa) {
+ if(la->mtex[c]->tex->type==TEX_IMAGE) lar->mode |= LA_OSATEX;
+ }
+ }
+ }
+ }
+ /* yafray: shadow flag should not be cleared, only used with internal renderer */
+ if (re->r.renderer==R_INTERN) {
+ /* to make sure we can check ray shadow easily in the render code */
+ if(lar->mode & LA_SHAD_RAY) {
+ if( (re->r.mode & R_RAYTRACE)==0)
+ lar->mode &= ~LA_SHAD_RAY;
+ }
+
+
+ if(re->r.mode & R_SHADOW) {
+
+ if ((lar->mode & LA_SHAD_RAY) && (lar->ray_samp_method == LA_SAMP_HAMMERSLEY)) {
+ init_lamp_hammersley(lar);
+ }
+ if(la->type==LA_AREA && (lar->mode & LA_SHAD_RAY) && (lar->ray_samp_method == LA_SAMP_CONSTANT)) {
+ init_jitter_plane(lar);
+ }
+ else if (la->type==LA_SPOT && (lar->mode & LA_SHAD_BUF) ) {
+ /* Per lamp, one shadow buffer is made. */
+ lar->bufflag= la->bufflag;
+ Mat4CpyMat4(mat, ob->obmat);
+ initshadowbuf(re, lar, mat); // mat is altered
+ }
+
+
+ /* this is the way used all over to check for shadow */
+ if(lar->shb || (lar->mode & LA_SHAD_RAY)) {
+ LampShadowSubSample *lss;
+ int a, b, tot= re->r.threads*re->r.osa;
+
+ lar->shadsamp= MEM_mallocN(re->r.threads*sizeof(LampShadowSample), "lamp shadow sample");
+ lss= lar->shadsamp[0].s;
+ /* shadfacs actually mean light, let's put them to 1 to prevent unitialized accidents */
+ for(a=0; a<tot; a++, lss++) {
+ for(b=0; b<4; b++) {
+ lss->samplenr= -1; /* used to detect whether we store or read */
+ lss->shadfac[b]= 1.0f;
+ }
+ }
+ }
+ }
+ }
+
+ return go;
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* returns amount of vertices added for orco */
+static int dl_surf_to_renderdata(Render *re, Object *ob, DispList *dl, Material **matar, float *orco, float mat[4][4])
+{
+ VertRen *v1, *v2, *v3, *v4, *ver;
+ VlakRen *vlr, *vlr1, *vlr2, *vlr3;
+ Curve *cu= ob->data;
+ float *data, n1[3], flen;
+ int u, v, orcoret= 0;
+ int p1, p2, p3, p4, a;
+ int sizeu, nsizeu, sizev, nsizev;
+ int startvert, startvlak;
+
+ startvert= re->totvert;
+ nsizeu = sizeu = dl->parts; nsizev = sizev = dl->nr;
+
+ data= dl->verts;
+ for (u = 0; u < sizeu; u++) {
+ v1 = RE_findOrAddVert(re, re->totvert++); /* save this for possible V wrapping */
+ VECCOPY(v1->co, data); data += 3;
+ if(orco) {
+ v1->orco= orco; orco+= 3; orcoret++;
+ }
+ MTC_Mat4MulVecfl(mat, v1->co);
+
+ for (v = 1; v < sizev; v++) {
+ ver= RE_findOrAddVert(re, re->totvert++);
+ VECCOPY(ver->co, data); data += 3;
+ if(orco) {
+ ver->orco= orco; orco+= 3; orcoret++;
+ }
+ MTC_Mat4MulVecfl(mat, ver->co);
+ }
+ /* if V-cyclic, add extra vertices at end of the row */
+ if (dl->flag & DL_CYCL_U) {
+ ver= RE_findOrAddVert(re, re->totvert++);
+ VECCOPY(ver->co, v1->co);
+ if(orco) {
+ ver->orco= orco; orco+=3; orcoret++; //orcobase + 3*(u*sizev + 0);
+ }
+ }
+ }
+
+ /* Done before next loop to get corner vert */
+ if (dl->flag & DL_CYCL_U) nsizev++;
+ if (dl->flag & DL_CYCL_V) nsizeu++;
+
+ /* if U cyclic, add extra row at end of column */
+ if (dl->flag & DL_CYCL_V) {
+ for (v = 0; v < nsizev; v++) {
+ v1= RE_findOrAddVert(re, startvert + v);
+ ver= RE_findOrAddVert(re, re->totvert++);
+ VECCOPY(ver->co, v1->co);
+ if(orco) {
+ ver->orco= orco; orco+=3; orcoret++; //ver->orco= orcobase + 3*(0*sizev + v);
+ }
+ }
+ }
+
+ sizeu = nsizeu;
+ sizev = nsizev;
+
+ startvlak= re->totvlak;
+
+ for(u = 0; u < sizeu - 1; u++) {
+ p1 = startvert + u * sizev; /* walk through face list */
+ p2 = p1 + 1;
+ p3 = p2 + sizev;
+ p4 = p3 - 1;
+
+ for(v = 0; v < sizev - 1; v++) {
+ v1= RE_findOrAddVert(re, p1);
+ v2= RE_findOrAddVert(re, p2);
+ v3= RE_findOrAddVert(re, p3);
+ v4= RE_findOrAddVert(re, p4);
+
+ vlr= RE_findOrAddVlak(re, re->totvlak++);
+ vlr->ob= ob;
+ vlr->v1= v1; vlr->v2= v2; vlr->v3= v3; vlr->v4= v4;
+
+ flen= CalcNormFloat4(vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co, n1);
+ VECCOPY(vlr->n, n1);
+
+ vlr->lay= ob->lay;
+ vlr->mat= matar[ dl->col];
+ vlr->ec= ME_V1V2+ME_V2V3;
+ vlr->flag= dl->rt;
+ if( (cu->flag & CU_NOPUNOFLIP) ) {
+ vlr->flag |= R_NOPUNOFLIP;
+ }
+
+ VecAddf(v1->n, v1->n, n1);
+ VecAddf(v2->n, v2->n, n1);
+ VecAddf(v3->n, v3->n, n1);
+ VecAddf(v4->n, v4->n, n1);
+
+ p1++; p2++; p3++; p4++;
+ }
+ }
+ /* fix normals for U resp. V cyclic faces */
+ sizeu--; sizev--; /* dec size for face array */
+ if (dl->flag & DL_CYCL_V) {
+
+ for (v = 0; v < sizev; v++)
+ {
+ /* optimize! :*/
+ vlr= RE_findOrAddVlak(re, UVTOINDEX(sizeu - 1, v));
+ vlr1= RE_findOrAddVlak(re, UVTOINDEX(0, v));
+ VecAddf(vlr1->v1->n, vlr1->v1->n, vlr->n);
+ VecAddf(vlr1->v2->n, vlr1->v2->n, vlr->n);
+ VecAddf(vlr->v3->n, vlr->v3->n, vlr1->n);
+ VecAddf(vlr->v4->n, vlr->v4->n, vlr1->n);
+ }
+ }
+ if (dl->flag & DL_CYCL_U) {
+
+ for (u = 0; u < sizeu; u++)
+ {
+ /* optimize! :*/
+ vlr= RE_findOrAddVlak(re, UVTOINDEX(u, 0));
+ vlr1= RE_findOrAddVlak(re, UVTOINDEX(u, sizev-1));
+ VecAddf(vlr1->v2->n, vlr1->v2->n, vlr->n);
+ VecAddf(vlr1->v3->n, vlr1->v3->n, vlr->n);
+ VecAddf(vlr->v1->n, vlr->v1->n, vlr1->n);
+ VecAddf(vlr->v4->n, vlr->v4->n, vlr1->n);
+ }
+ }
+ /* last vertex is an extra case:
+
+ ^ ()----()----()----()
+ | | | || |
+ u | |(0,n)||(0,0)|
+ | | || |
+ ()====()====[]====()
+ | | || |
+ | |(m,n)||(m,0)|
+ | | || |
+ ()----()----()----()
+ v ->
+
+ vertex [] is no longer shared, therefore distribute
+ normals of the surrounding faces to all of the duplicates of []
+ */
+
+ if ((dl->flag & DL_CYCL_V) && (dl->flag & DL_CYCL_U))
+ {
+ vlr= RE_findOrAddVlak(re, UVTOINDEX(sizeu - 1, sizev - 1)); /* (m,n) */
+ vlr1= RE_findOrAddVlak(re, UVTOINDEX(0,0)); /* (0,0) */
+ VecAddf(n1, vlr->n, vlr1->n);
+ vlr2= RE_findOrAddVlak(re, UVTOINDEX(0, sizev-1)); /* (0,n) */
+ VecAddf(n1, n1, vlr2->n);
+ vlr3= RE_findOrAddVlak(re, UVTOINDEX(sizeu-1, 0)); /* (m,0) */
+ VecAddf(n1, n1, vlr3->n);
+ VECCOPY(vlr->v3->n, n1);
+ VECCOPY(vlr1->v1->n, n1);
+ VECCOPY(vlr2->v2->n, n1);
+ VECCOPY(vlr3->v4->n, n1);
+ }
+ for(a = startvert; a < re->totvert; a++) {
+ ver= RE_findOrAddVert(re, a);
+ Normalize(ver->n);
+ }
+
+
+ return orcoret;
+}
+
+static void init_render_surf(Render *re, Object *ob)
+{
+ Nurb *nu=0;
+ Curve *cu;
+ ListBase displist;
+ DispList *dl;
+ Material *matar[32];
+ float *orco=NULL, *orcobase=NULL, mat[4][4];
+ int a, need_orco=0;
+
+ cu= ob->data;
+ nu= cu->nurb.first;
+ if(nu==0) return;
+
+ MTC_Mat4MulMat4(mat, ob->obmat, re->viewmat);
+ MTC_Mat4Invert(ob->imat, mat);
+
+ /* material array */
+ memset(matar, 0, 4*32);
+ matar[0]= give_render_material(re, ob, 0);
+ for(a=0; a<ob->totcol; a++) {
+ matar[a]= give_render_material(re, ob, a+1);
+ if(matar[a] && matar[a]->texco & TEXCO_ORCO) {
+ need_orco= 1;
+ }
+ }
+
+ if(ob->parent && (ob->parent->type==OB_LATTICE)) need_orco= 1;
+
+ if(need_orco) orcobase= orco= get_object_orco(re, ob);
+
+ displist.first= displist.last= 0;
+ makeDispListSurf(ob, &displist, 1);
+
+ dl= displist.first;
+ /* walk along displaylist and create rendervertices/-faces */
+ while(dl) {
+ /* watch out: u ^= y, v ^= x !! */
+ if(dl->type==DL_SURF) {
+ orco+= 3*dl_surf_to_renderdata(re, ob, dl, matar, orco, mat);
+ }
+
+ dl= dl->next;
+ }
+ freedisplist(&displist);
+}
+
+static void init_render_curve(Render *re, Object *ob, int only_verts)
+{
+ Curve *cu;
+ VertRen *ver;
+ VlakRen *vlr;
+ DispList *dl;
+ ListBase olddl={NULL, NULL};
+ Material *matar[32];
+ float len, *data, *fp, *orco=NULL, *orcobase= NULL;
+ float n[3], mat[4][4];
+ int nr, startvert, startvlak, a, b;
+ int frontside, need_orco=0;
+
+ cu= ob->data;
+ if(cu->nurb.first==NULL) return;
+
+ /* no modifier call here, is in makedisp */
+
+ if(cu->resolu_ren)
+ SWAP(ListBase, olddl, cu->disp);
+
+ /* test displist */
+ if(cu->disp.first==NULL)
+ makeDispListCurveTypes(ob, 0);
+ dl= cu->disp.first;
+ if(cu->disp.first==NULL) return;
+
+ MTC_Mat4MulMat4(mat, ob->obmat, re->viewmat);
+ MTC_Mat4Invert(ob->imat, mat);
+
+ /* material array */
+ memset(matar, 0, 4*32);
+ matar[0]= give_render_material(re, ob, 0);
+ for(a=0; a<ob->totcol; a++) {
+ matar[a]= give_render_material(re, ob, a+1);
+ if(matar[a]->texco & TEXCO_ORCO) {
+ need_orco= 1;
+ }
+ }
+
+ if(need_orco) orcobase=orco= get_object_orco(re, ob);
+
+ dl= cu->disp.first;
+ while(dl) {
+ if(dl->type==DL_INDEX3) {
+ int *index;
+
+ startvert= re->totvert;
+ data= dl->verts;
+
+ n[0]= ob->imat[0][2];
+ n[1]= ob->imat[1][2];
+ n[2]= ob->imat[2][2];
+ Normalize(n);
+
+ for(a=0; a<dl->nr; a++, data+=3) {
+ ver= RE_findOrAddVert(re, re->totvert++);
+ VECCOPY(ver->co, data);
+
+ /* flip normal if face is backfacing, also used in face loop below */
+ if(ver->co[2] < 0.0) {
+ VECCOPY(ver->n, n);
+ ver->flag = 1;
+ }
+ else {
+ ver->n[0]= -n[0]; ver->n[1]= -n[1]; ver->n[2]= -n[2];
+ ver->flag = 0;
+ }
+
+ MTC_Mat4MulVecfl(mat, ver->co);
+
+ if (orco) {
+ ver->orco = orco;
+ orco += 3;
+ }
+ }
+
+ if(only_verts==0) {
+ startvlak= re->totvlak;
+ index= dl->index;
+ for(a=0; a<dl->parts; a++, index+=3) {
+
+ vlr= RE_findOrAddVlak(re, re->totvlak++);
+ vlr->ob = ob;
+ vlr->v1= RE_findOrAddVert(re, startvert+index[0]);
+ vlr->v2= RE_findOrAddVert(re, startvert+index[1]);
+ vlr->v3= RE_findOrAddVert(re, startvert+index[2]);
+ vlr->v4= NULL;
+
+ if(vlr->v1->flag) {
+ VECCOPY(vlr->n, n);
+ }
+ else {
+ vlr->n[0]= -n[0]; vlr->n[1]= -n[1]; vlr->n[2]= -n[2];
+ }
+
+ vlr->mat= matar[ dl->col ];
+ vlr->flag= 0;
+ if( (cu->flag & CU_NOPUNOFLIP) ) {
+ vlr->flag |= R_NOPUNOFLIP;
+ }
+ vlr->ec= 0;
+ vlr->lay= ob->lay;
+ }
+ }
+ }
+ else if (dl->type==DL_SURF) {
+
+ /* cyclic U means an extruded full circular curve, we skip bevel splitting then */
+ if (dl->flag & DL_CYCL_U) {
+ orco+= 3*dl_surf_to_renderdata(re, ob, dl, matar, orco, mat);
+ }
+ else {
+ int p1,p2,p3,p4;
+
+ fp= dl->verts;
+ startvert= re->totvert;
+ nr= dl->nr*dl->parts;
+
+ while(nr--) {
+ ver= RE_findOrAddVert(re, re->totvert++);
+
+ VECCOPY(ver->co, fp);
+ MTC_Mat4MulVecfl(mat, ver->co);
+ fp+= 3;
+
+ if (orco) {
+ ver->orco = orco;
+ orco += 3;
+ }
+ }
+
+ if(dl->bevelSplitFlag || only_verts==0) {
+ startvlak= re->totvlak;
+
+ for(a=0; a<dl->parts; a++) {
+
+ frontside= (a >= dl->nr/2);
+
+ DL_SURFINDEX(dl->flag & DL_CYCL_U, dl->flag & DL_CYCL_V, dl->nr, dl->parts);
+ p1+= startvert;
+ p2+= startvert;
+ p3+= startvert;
+ p4+= startvert;
+
+ for(; b<dl->nr; b++) {
+ vlr= RE_findOrAddVlak(re, re->totvlak++);
+ vlr->ob= ob;
+ vlr->v1= RE_findOrAddVert(re, p2);
+ vlr->v2= RE_findOrAddVert(re, p1);
+ vlr->v3= RE_findOrAddVert(re, p3);
+ vlr->v4= RE_findOrAddVert(re, p4);
+ vlr->ec= ME_V2V3+ME_V3V4;
+ if(a==0) vlr->ec+= ME_V1V2;
+
+ vlr->flag= dl->rt;
+ vlr->lay= ob->lay;
+
+ /* this is not really scientific: the vertices
+ * 2, 3 en 4 seem to give better vertexnormals than 1 2 3:
+ * front and backside treated different!!
+ */
+
+ if(frontside)
+ CalcNormFloat(vlr->v2->co, vlr->v3->co, vlr->v4->co, vlr->n);
+ else
+ CalcNormFloat(vlr->v1->co, vlr->v2->co, vlr->v3->co, vlr->n);
+
+ vlr->mat= matar[ dl->col ];
+
+ p4= p3;
+ p3++;
+ p2= p1;
+ p1++;
+ }
+ }
+
+ if (dl->bevelSplitFlag) {
+ for(a=0; a<dl->parts-1+!!(dl->flag&DL_CYCL_V); a++)
+ if(dl->bevelSplitFlag[a>>5]&(1<<(a&0x1F)))
+ split_v_renderfaces(re, startvlak, startvert, dl->parts, dl->nr, a, dl->flag&DL_CYCL_V, dl->flag&DL_CYCL_U);
+ }
+
+ /* vertex normals */
+ for(a= startvlak; a<re->totvlak; a++) {
+ vlr= RE_findOrAddVlak(re, a);
+
+ VecAddf(vlr->v1->n, vlr->v1->n, vlr->n);
+ VecAddf(vlr->v3->n, vlr->v3->n, vlr->n);
+ VecAddf(vlr->v2->n, vlr->v2->n, vlr->n);
+ VecAddf(vlr->v4->n, vlr->v4->n, vlr->n);
+ }
+ for(a=startvert; a<re->totvert; a++) {
+ ver= RE_findOrAddVert(re, a);
+ len= Normalize(ver->n);
+ if(len==0.0) ver->flag= 1; /* flag abuse, its only used in zbuf now */
+ else ver->flag= 0;
+ }
+ for(a= startvlak; a<re->totvlak; a++) {
+ vlr= RE_findOrAddVlak(re, a);
+ if(vlr->v1->flag) VECCOPY(vlr->v1->n, vlr->n);
+ if(vlr->v2->flag) VECCOPY(vlr->v2->n, vlr->n);
+ if(vlr->v3->flag) VECCOPY(vlr->v3->n, vlr->n);
+ if(vlr->v4->flag) VECCOPY(vlr->v4->n, vlr->n);
+ }
+ }
+ }
+ }
+
+ dl= dl->next;
+ }
+
+ /* not very elegant... but we want original displist in UI */
+ if(cu->resolu_ren) {
+ freedisplist(&cu->disp);
+ SWAP(ListBase, olddl, cu->disp);
+ }
+}
+
+/* prevent phong interpolation for giving ray shadow errors (terminator problem) */
+static void set_phong_threshold(Render *re, Object *ob, int startface, int numface, int startvert, int numvert )
+{
+// VertRen *ver;
+ VlakRen *vlr;
+ float thresh= 0.0, dot;
+ int tot=0, i;
+
+ /* Added check for 'pointy' situations, only dotproducts of 0.9 and larger
+ are taken into account. This threshold is meant to work on smooth geometry, not
+ for extreme cases (ton) */
+
+ for(i=startface; i<startface+numface; i++) {
+ vlr= RE_findOrAddVlak(re, i);
+ if(vlr->flag & R_SMOOTH) {
+ dot= INPR(vlr->n, vlr->v1->n);
+ dot= ABS(dot);
+ if(dot>0.9) {
+ thresh+= dot; tot++;
+ }
+ dot= INPR(vlr->n, vlr->v2->n);
+ dot= ABS(dot);
+ if(dot>0.9) {
+ thresh+= dot; tot++;
+ }
+
+ dot= INPR(vlr->n, vlr->v3->n);
+ dot= ABS(dot);
+ if(dot>0.9) {
+ thresh+= dot; tot++;
+ }
+
+ if(vlr->v4) {
+ dot= INPR(vlr->n, vlr->v4->n);
+ dot= ABS(dot);
+ if(dot>0.9) {
+ thresh+= dot; tot++;
+ }
+ }
+ }
+ }
+
+ if(tot) {
+ thresh/= (float)tot;
+ ob->smoothresh= cos(0.5*M_PI-saacos(thresh));
+ }
+}
+
+/* par = pointer to duplicator parent, needed for object lookup table */
+/* index = when duplicater copies same object (particle), the counter */
+static void init_render_object(Render *re, Object *ob, Object *par, int index, int only_verts)
+{
+ static double lasttime= 0.0;
+ double time;
+ float mat[4][4];
+ int startface, startvert;
+
+ startface=re->totvlak;
+ startvert=re->totvert;
+
+ ob->flag |= OB_DONE;
+
+ if(ob->type==OB_LAMP)
+ add_render_lamp(re, ob);
+ else if ELEM(ob->type, OB_FONT, OB_CURVE)
+ init_render_curve(re, ob, only_verts);
+ else if(ob->type==OB_SURF)
+ init_render_surf(re, ob);
+ else if(ob->type==OB_MESH)
+ init_render_mesh(re, ob, par, only_verts);
+ else if(ob->type==OB_MBALL)
+ init_render_mball(re, ob);
+ else {
+ MTC_Mat4MulMat4(mat, ob->obmat, re->viewmat);
+ MTC_Mat4Invert(ob->imat, mat);
+ }
+
+ /* generic post process here */
+ if(startvert!=re->totvert) {
+
+ RE_addRenderObject(re, ob, par, index, startvert, re->totvert, startface, re->totvlak);
+
+ /* the exception below is because displace code now is in init_render_mesh call,
+ I will look at means to have autosmooth enabled for all object types
+ and have it as general postprocess, like displace */
+ if (ob->type!=OB_MESH && test_for_displace(re, ob ) )
+ do_displacement(re, ob, startface, re->totvlak-startface, startvert, re->totvert-startvert);
+
+ /* phong normal interpolation can cause error in tracing (terminator prob) */
+ ob->smoothresh= 0.0;
+ if( (re->r.mode & R_RAYTRACE) && (re->r.mode & R_SHADOW) )
+ set_phong_threshold(re, ob, startface, re->totvlak-startface, startvert, re->totvert-startvert);
+ }
+
+ time= PIL_check_seconds_timer();
+ if(time - lasttime > 1.0) {
+ lasttime= time;
+ /* clumsy copying still */
+ re->i.totvert= re->totvert;
+ re->i.totface= re->totvlak;
+ re->i.tothalo= re->tothalo;
+ re->i.totlamp= re->totlamp;
+ re->stats_draw(&re->i);
+ }
+}
+
+void RE_Database_Free(Render *re)
+{
+ Object *ob = NULL;
+ LampRen *lar;
+
+ /* FREE */
+
+ for(lar= re->lampren.first; lar; lar= lar->next) {
+ freeshadowbuf(lar);
+ if(lar->jitter) MEM_freeN(lar->jitter);
+ if(lar->shadsamp) MEM_freeN(lar->shadsamp);
+ if(lar->qsa) free_lamp_qmcsampler(lar);
+ curvemapping_free(lar->curfalloff);
+ }
+
+ BLI_freelistN(&re->lampren);
+ BLI_freelistN(&re->lights);
+
+ free_renderdata_tables(re);
+
+ /* free orco. check all objects because of duplis and sets */
+ ob= G.main->object.first;
+ while(ob) {
+ if(ob->type==OB_MBALL) {
+ if(ob->disp.first && ob->disp.first!=ob->disp.last) {
+ DispList *dl= ob->disp.first;
+ BLI_remlink(&ob->disp, dl);
+ freedisplist(&ob->disp);
+ BLI_addtail(&ob->disp, dl);
+ }
+ }
+ ob= ob->id.next;
+ }
+
+ free_mesh_orco_hash(re);
+
+ end_radio_render();
+ end_render_materials();
+
+ if(re->wrld.aosphere) {
+ MEM_freeN(re->wrld.aosphere);
+ re->wrld.aosphere= NULL;
+ re->scene->world->aosphere= NULL;
+ }
+ if(re->wrld.aotables) {
+ MEM_freeN(re->wrld.aotables);
+ re->wrld.aotables= NULL;
+ re->scene->world->aotables= NULL;
+ }
+ if((re->r.mode & R_RAYTRACE) && (re->wrld.mode & WO_AMB_OCC) &&
+ (re->wrld.ao_samp_method == WO_AOSAMP_HAMMERSLEY) && (re->qsa))
+ free_render_qmcsampler(re);
+
+ if(re->r.mode & R_RAYTRACE) freeraytree(re);
+
+ free_sss(re);
+
+ re->totvlak=re->totvert=re->totlamp=re->tothalo= 0;
+ re->i.convertdone= 0;
+
+ if(re->scene)
+ if(re->scene->r.scemode & R_FREE_IMAGE)
+ if((re->r.scemode & R_PREVIEWBUTS)==0)
+ BKE_image_free_all_textures();
+
+ if(re->memArena) {
+ BLI_memarena_free(re->memArena);
+ re->memArena = NULL;
+ }
+}
+
+/* per face check if all samples should be taken.
+ if raytrace, do always for raytraced material, or when material full_osa set */
+static void set_fullsample_flag(Render *re)
+{
+ VlakRen *vlr;
+ int a, trace;
+
+ if(re->osa==0)
+ return;
+
+ trace= re->r.mode & R_RAYTRACE;
+
+ for(a=re->totvlak-1; a>=0; a--) {
+ vlr= RE_findOrAddVlak(re, a);
+
+ if(vlr->mat->mode & MA_FULL_OSA) vlr->flag |= R_FULL_OSA;
+ else if(trace) {
+ if(vlr->mat->mode & MA_SHLESS);
+ else if(vlr->mat->mode & (MA_RAYTRANSP|MA_RAYMIRROR))
+ /* for blurry reflect/refract, better to take more samples
+ * inside the raytrace than as OSA samples */
+ if ((vlr->mat->gloss_mir == 1.0) && (vlr->mat->gloss_tra == 1.0))
+ vlr->flag |= R_FULL_OSA;
+ }
+ }
+}
+
+static void check_non_flat_quads(Render *re)
+{
+ VlakRen *vlr, *vlr1;
+ VertRen *v1, *v2, *v3, *v4;
+ float nor[3], xn, flen;
+ int a;
+
+ for(a=re->totvlak-1; a>=0; a--) {
+ vlr= RE_findOrAddVlak(re, a);
+
+ /* test if rendering as a quad or triangle, skip wire */
+ if(vlr->v4 && (vlr->flag & R_STRAND)==0 && (vlr->mat->mode & MA_WIRE)==0) {
+
+ /* check if quad is actually triangle */
+ v1= vlr->v1;
+ v2= vlr->v2;
+ v3= vlr->v3;
+ v4= vlr->v4;
+ VECSUB(nor, v1->co, v2->co);
+ if( ABS(nor[0])<FLT_EPSILON10 && ABS(nor[1])<FLT_EPSILON10 && ABS(nor[2])<FLT_EPSILON10 ) {
+ vlr->v1= v2;
+ vlr->v2= v3;
+ vlr->v3= v4;
+ vlr->v4= NULL;
+ }
+ else {
+ VECSUB(nor, v2->co, v3->co);
+ if( ABS(nor[0])<FLT_EPSILON10 && ABS(nor[1])<FLT_EPSILON10 && ABS(nor[2])<FLT_EPSILON10 ) {
+ vlr->v2= v3;
+ vlr->v3= v4;
+ vlr->v4= NULL;
+ }
+ else {
+ VECSUB(nor, v3->co, v4->co);
+ if( ABS(nor[0])<FLT_EPSILON10 && ABS(nor[1])<FLT_EPSILON10 && ABS(nor[2])<FLT_EPSILON10 ) {
+ vlr->v4= NULL;
+ }
+ else {
+ VECSUB(nor, v4->co, v1->co);
+ if( ABS(nor[0])<FLT_EPSILON10 && ABS(nor[1])<FLT_EPSILON10 && ABS(nor[2])<FLT_EPSILON10 ) {
+ vlr->v4= NULL;
+ }
+ }
+ }
+ }
+
+ if(vlr->v4) {
+
+ /* Face is divided along edge with the least gradient */
+ /* Flagged with R_DIVIDE_24 if divide is from vert 2 to 4 */
+ /* 4---3 4---3 */
+ /* |\ 1| or |1 /| */
+ /* |0\ | |/ 0| */
+ /* 1---2 1---2 0 = orig face, 1 = new face */
+
+ /* render normals are inverted in render! we calculate normal of single tria here */
+ flen= CalcNormFloat(vlr->v4->co, vlr->v3->co, vlr->v1->co, nor);
+ if(flen==0.0) CalcNormFloat(vlr->v4->co, vlr->v2->co, vlr->v1->co, nor);
+
+ xn= nor[0]*vlr->n[0] + nor[1]*vlr->n[1] + nor[2]*vlr->n[2];
+
+ if(ABS(xn) < 0.999995 ) { // checked on noisy fractal grid
+ float d1, d2;
+
+ vlr1= RE_vlakren_copy(re, vlr);
+ vlr1->flag |= R_FACE_SPLIT;
+
+ /* split direction based on vnorms */
+ CalcNormFloat(vlr->v1->co, vlr->v2->co, vlr->v3->co, nor);
+ d1= nor[0]*vlr->v1->n[0] + nor[1]*vlr->v1->n[1] + nor[2]*vlr->v1->n[2];
+
+ CalcNormFloat(vlr->v2->co, vlr->v3->co, vlr->v4->co, nor);
+ d2= nor[0]*vlr->v2->n[0] + nor[1]*vlr->v2->n[1] + nor[2]*vlr->v2->n[2];
+
+ if( fabs(d1) < fabs(d2) ) vlr->flag |= R_DIVIDE_24;
+ else vlr->flag &= ~R_DIVIDE_24;
+
+ /* new vertex pointers */
+ if (vlr->flag & R_DIVIDE_24) {
+ vlr1->v1= vlr->v2;
+ vlr1->v2= vlr->v3;
+ vlr1->v3= vlr->v4;
+
+ vlr->v3 = vlr->v4;
+
+ vlr1->flag |= R_DIVIDE_24;
+ }
+ else {
+ vlr1->v1= vlr->v1;
+ vlr1->v2= vlr->v3;
+ vlr1->v3= vlr->v4;
+
+ vlr1->flag &= ~R_DIVIDE_24;
+ }
+ vlr->v4 = vlr1->v4 = NULL;
+
+ /* new normals */
+ CalcNormFloat(vlr->v3->co, vlr->v2->co, vlr->v1->co, vlr->n);
+ CalcNormFloat(vlr1->v3->co, vlr1->v2->co, vlr1->v1->co, vlr1->n);
+ }
+ /* clear the flag when not divided */
+ else vlr->flag &= ~R_DIVIDE_24;
+ }
+ }
+ }
+}
+
+/* layflag: allows material group to ignore layerflag */
+static void add_lightgroup(Render *re, Group *group, int exclusive)
+{
+ GroupObject *go, *gol;
+
+ group->id.flag &= ~LIB_DOIT;
+
+ /* it's a bit too many loops in loops... but will survive */
+ /* note that 'exclusive' will remove it from the global list */
+ for(go= group->gobject.first; go; go= go->next) {
+ go->lampren= NULL;
+
+ if(go->ob->lay & re->scene->lay) {
+ if(go->ob && go->ob->type==OB_LAMP) {
+ for(gol= re->lights.first; gol; gol= gol->next) {
+ if(gol->ob==go->ob) {
+ go->lampren= gol->lampren;
+ break;
+ }
+ }
+ if(go->lampren==NULL)
+ gol= add_render_lamp(re, go->ob);
+ if(gol && exclusive) {
+ BLI_remlink(&re->lights, gol);
+ MEM_freeN(gol);
+ }
+ }
+ }
+ }
+}
+
+static void set_material_lightgroups(Render *re)
+{
+ Group *group;
+ Material *ma;
+
+ /* not for preview render */
+ if(re->scene->r.scemode & R_PREVIEWBUTS)
+ return;
+
+ for(group= G.main->group.first; group; group=group->id.next)
+ group->id.flag |= LIB_DOIT;
+
+ /* it's a bit too many loops in loops... but will survive */
+ /* hola! materials not in use...? */
+ for(ma= G.main->mat.first; ma; ma=ma->id.next) {
+ if(ma->group && (ma->group->id.flag & LIB_DOIT))
+ add_lightgroup(re, ma->group, ma->mode & MA_GROUP_NOLAY);
+ }
+}
+
+static void set_renderlayer_lightgroups(Render *re, Scene *sce)
+{
+ SceneRenderLayer *srl;
+
+ for(srl= sce->r.layers.first; srl; srl= srl->next) {
+ if(srl->light_override)
+ add_lightgroup(re, srl->light_override, 0);
+ }
+}
+
+void init_render_world(Render *re)
+{
+ int a;
+ char *cp;
+
+ if(re->scene && re->scene->world) {
+ re->wrld= *(re->scene->world);
+
+ cp= (char *)&re->wrld.fastcol;
+
+ cp[0]= 255.0*re->wrld.horr;
+ cp[1]= 255.0*re->wrld.horg;
+ cp[2]= 255.0*re->wrld.horb;
+ cp[3]= 1;
+
+ VECCOPY(re->grvec, re->viewmat[2]);
+ Normalize(re->grvec);
+ Mat3CpyMat4(re->imat, re->viewinv);
+
+ for(a=0; a<MAX_MTEX; a++)
+ if(re->wrld.mtex[a] && re->wrld.mtex[a]->tex) re->wrld.skytype |= WO_SKYTEX;
+
+ /* AO samples should be OSA minimum */
+ if(re->osa)
+ while(re->wrld.aosamp*re->wrld.aosamp < re->osa)
+ re->wrld.aosamp++;
+ if(!(re->r.mode & R_RAYTRACE))
+ re->wrld.mode &= ~WO_AMB_OCC;
+ }
+ else {
+ memset(&re->wrld, 0, sizeof(World));
+ re->wrld.exp= 0.0;
+ re->wrld.range= 1.0;
+ }
+
+ re->wrld.linfac= 1.0 + pow((2.0*re->wrld.exp + 0.5), -10);
+ re->wrld.logfac= log( (re->wrld.linfac-1.0)/re->wrld.linfac )/re->wrld.range;
+}
+
+/* used to be 'rotate scene' */
+void RE_Database_FromScene(Render *re, Scene *scene, int use_camera_view)
+{
+ extern int slurph_opt; /* key.c */
+ Base *base;
+ Object *ob;
+ Scene *sce;
+ float mat[4][4];
+ unsigned int lay;
+
+ re->scene= scene;
+
+ /* per second, per object, stats print this */
+ re->i.infostr= "Preparing Scene data";
+
+ /* XXX add test if dbase was filled already? */
+
+ re->memArena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE);
+ re->totvlak=re->totvert=re->totlamp=re->tothalo= 0;
+ re->lights.first= re->lights.last= NULL;
+ re->lampren.first= re->lampren.last= NULL;
+
+ slurph_opt= 0;
+ re->i.partsdone= 0; /* signal now in use for previewrender */
+
+ /* in localview, lamps are using normal layers, objects only local bits */
+ if(re->scene->lay & 0xFF000000) lay= re->scene->lay & 0xFF000000;
+ else lay= re->scene->lay;
+
+ /* applies changes fully */
+ if((re->r.scemode & R_PREVIEWBUTS)==0)
+ scene_update_for_newframe(re->scene, lay);
+
+ /* if no camera, viewmat should have been set! */
+ if(use_camera_view && re->scene->camera) {
+ Mat4Ortho(re->scene->camera->obmat);
+ Mat4Invert(mat, re->scene->camera->obmat);
+ RE_SetView(re, mat);
+ }
+
+ init_render_world(re); /* do first, because of ambient. also requires re->osa set correct */
+ if(re->wrld.mode & WO_AMB_OCC) {
+ if (re->wrld.ao_samp_method == WO_AOSAMP_HAMMERSLEY)
+ init_render_hammersley(re);
+ else if (re->wrld.ao_samp_method == WO_AOSAMP_CONSTANT)
+ init_ao_sphere(&re->wrld);
+ }
+
+ /* still bad... doing all */
+ init_render_textures(re);
+ init_render_materials(re->r.mode, &re->wrld.ambr);
+ set_node_shader_lamp_loop(shade_material_loop);
+
+ for(SETLOOPER(re->scene, base)) {
+ ob= base->object;
+ /* imat objects has to be done here, since displace can have texture using Object map-input */
+ MTC_Mat4MulMat4(mat, ob->obmat, re->viewmat);
+ MTC_Mat4Invert(ob->imat, mat);
+ /* each object should only be rendered once */
+ ob->flag &= ~OB_DONE;
+ }
+
+ /* MAKE RENDER DATA */
+
+ for(SETLOOPER(re->scene, base)) {
+ ob= base->object;
+
+ /* if the object has been restricted from rendering in the outliner, ignore it */
+ if (ob->restrictflag & OB_RESTRICT_RENDER) continue;
+
+ /* OB_DONE means the object itself got duplicated, so was already converted */
+ if (ob->flag & OB_DONE) {
+#ifndef DISABLE_YAFRAY
+ /* yafray: for some reason this part was removed, but yafray really needs it...
+ Dupliverts objects are treated as instances of an original 'sourceobject',
+ which needs to be included in the renderlist here.
+ exception: lamps, lattices, armatures & camera's */
+ if ((re->r.renderer==R_YAFRAY) && ((ob->type!=OB_LATTICE) && (ob->type!=OB_ARMATURE) &&
+ (ob->type!=OB_LAMP) && (ob->type!=OB_CAMERA)))
+ {
+ printf("Duplivert object %s, adding to renderlist\n", ob->id.name);
+ ob->flag &= ~OB_DONE;
+ init_render_object(re, ob, NULL, 0, 0);
+ ob->flag |= OB_DONE;
+ }
+#endif /* disable yafray */
+ }
+ else if( (base->lay & lay) || (ob->type==OB_LAMP && (base->lay & re->scene->lay)) ) {
+ if(ob->transflag & OB_DUPLI) {
+
+ /* exception: mballs! */
+#ifndef DISABLE_YAFRAY
+ /* yafray: except for mballs, include at least one copy of a dupliframe object in the renderlist. */
+ if (re->r.renderer==R_YAFRAY) {
+ if ((ob->type!=OB_MBALL) && ((ob->transflag & OB_DUPLIFRAMES)!=0)) {
+ printf("Dupliframe Object %s, adding to renderlist\n", ob->id.name);
+ init_render_object(re, ob, NULL, 0, 0);
+ }
+ }
+#endif /* disable yafray */
+ /* before make duplis, update particle for current frame */
+ if(ob->transflag & OB_DUPLIVERTS) {
+ PartEff *paf= give_parteff(ob);
+ if(paf) {
+ if(paf->flag & PAF_ANIMATED) build_particle_system(ob);
+ }
+ }
+
+ if(ob->type==OB_MBALL) {
+ init_render_object(re, ob, NULL, 0, 0);
+ }
+ else {
+ DupliObject *dob;
+ ListBase *lb= object_duplilist(sce, ob);
+
+ for(dob= lb->first; dob; dob= dob->next) {
+ Object *obd= dob->ob;
+
+ if (obd->restrictflag & OB_RESTRICT_RENDER) continue;
+
+ Mat4CpyMat4(obd->obmat, dob->mat);
+
+ /* group duplis need to set ob matrices correct, for deform. so no_draw is part handled */
+ if(dob->no_draw)
+ continue;
+
+ if(obd->type!=OB_MBALL) {
+#ifndef DISABLE_YAFRAY
+ /* yafray: special case handling of duplivert/dupligroup objects.
+ Only one copy included in renderlist(see above), all others treated as instance of that.
+ So only need to store name and matrix. Exception are lamps. lattices, armatures and camera's */
+ if (re->r.renderer==R_YAFRAY) {
+ /* dupligroup obs are included directly */
+ if (obd->flag & OB_FROMGROUP) {
+ printf("Dupligroup object %s, adding to renderlist\n", obd->id.name);
+ init_render_object(re, obd, ob, dob->index, 0);
+ }
+ else if ((obd->type!=OB_LATTICE) && (obd->type!=OB_ARMATURE) &&
+ (obd->type!=OB_LAMP) && (obd->type!=OB_CAMERA))
+ {
+ printf("Adding dupli matrix for object %s\n", obd->id.name);
+ YAF_addDupliMtx(obd);
+ }
+ else init_render_object(re, obd, ob, dob->index, 0);
+ }
+ else init_render_object(re, obd, ob, dob->index, 0);
+#else
+ init_render_object(re, obd, ob, dob->index, 0);
+#endif /* disable yafray */
+ }
+
+ if(re->test_break()) break;
+ }
+ free_object_duplilist(lb);
+ }
+ }
+ else {
+#ifndef DISABLE_YAFRAY
+ /* yafray: linked data objects treated similarly to dupliverts,
+ If object not known yet (not in renderlist), include in the renderlist,
+ otherwise treat as instance of it, so only name and matrix are stored
+ Exception: objects which have materials linked to object instead of mesh */
+ if ((re->r.renderer==R_YAFRAY) && (ob->colbits==0))
+ {
+ /* Special case, parent object dupli's: ignore if object itself is lamp or parent is lattice or empty */
+ if (ob->parent) {
+ if ((ob->type!=OB_LAMP) && (ob->parent->type!=OB_EMPTY) &&
+ (ob->parent->type!=OB_LATTICE) && YAF_objectKnownData(ob))
+ printf("From parent: Added dupli matrix for linked data object %s\n", ob->id.name);
+ else
+ init_render_object(re, ob, NULL, 0, 0);
+ }
+ else if ((ob->type!=OB_EMPTY) && (ob->type!=OB_LAMP) &&
+ (ob->type!=OB_ARMATURE) && YAF_objectKnownData(ob))
+ printf("Added dupli matrix for linked data object %s\n", ob->id.name);
+ else
+ init_render_object(re, ob, NULL, 0, 0);
+ }
+ else init_render_object(re, ob, NULL, 0, 0);
+#else
+ init_render_object(re, ob, NULL, 0, 0);
+#endif /* disable yafray */
+ }
+
+ }
+
+ if(re->test_break()) break;
+ }
+
+
+ if(!re->test_break()) {
+ LampRen *lar;
+
+ sort_halos(re);
+
+ set_material_lightgroups(re);
+ for(sce= re->scene; sce; sce= sce->set)
+ set_renderlayer_lightgroups(re, sce);
+
+ slurph_opt= 1;
+
+ /* for now some clumsy copying still */
+ re->i.totvert= re->totvert;
+ re->i.totface= re->totvlak;
+ re->i.tothalo= re->tothalo;
+ re->i.totlamp= re->totlamp;
+ re->stats_draw(&re->i);
+
+ set_fullsample_flag(re);
+ check_non_flat_quads(re);
+ set_normalflags(re);
+
+ if(!re->test_break())
+ if(re->wrld.mode & WO_STARS)
+ RE_make_stars(re, NULL, NULL, NULL);
+
+ re->i.infostr= "Creating Shadowbuffers";
+ re->stats_draw(&re->i);
+
+ /* SHADOW BUFFER */
+ for(lar=re->lampren.first; lar; lar= lar->next) {
+ if(re->test_break()) break;
+ if(lar->shb) {
+ /* if type is irregular, this only sets the perspective matrix and autoclips */
+ makeshadowbuf(re, lar);
+ }
+ }
+
+ /* yafray: 'direct' radiosity, environment maps and raytree init not needed for yafray render */
+ /* although radio mode could be useful at some point, later */
+ if (re->r.renderer==R_INTERN) {
+ /* RADIO (uses no R anymore) */
+ if(!re->test_break())
+ if(re->r.mode & R_RADIO) do_radio_render(re);
+
+ /* raytree */
+ if(!re->test_break()) {
+ if(re->r.mode & R_RAYTRACE) {
+ makeraytree(re);
+ }
+ }
+ /* ENVIRONMENT MAPS */
+ if(!re->test_break())
+ make_envmaps(re);
+ }
+
+ if(!re->test_break())
+ project_renderdata(re, projectverto, re->r.mode & R_PANORAMA, 0);
+
+ /* SSS */
+ if((re->r.mode & R_SSS) && !re->test_break())
+ if (re->r.renderer==R_INTERN)
+ make_sss_tree(re);
+ }
+
+ if(re->test_break())
+ RE_Database_Free(re);
+ else
+ re->i.convertdone= 1;
+
+ re->i.infostr= NULL;
+ re->stats_draw(&re->i);
+}
+
+static void database_fromscene_vectors(Render *re, Scene *scene, int timeoffset)
+{
+ extern int slurph_opt; /* key.c */
+ Base *base;
+ Object *ob;
+ Scene *sce;
+ float mat[4][4];
+ unsigned int lay;
+
+ re->scene= scene;
+
+ /* XXX add test if dbase was filled already? */
+
+ re->memArena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE);
+ re->totvlak=re->totvert=re->totlamp=re->tothalo= 0;
+ re->i.totface=re->i.totvert=re->i.totlamp=re->i.tothalo= 0;
+ re->lights.first= re->lights.last= NULL;
+
+ slurph_opt= 0;
+
+ /* in localview, lamps are using normal layers, objects only local bits */
+ if(re->scene->lay & 0xFF000000) lay= re->scene->lay & 0xFF000000;
+ else lay= re->scene->lay;
+
+ /* applies changes fully, still using G.scene for timing... */
+ G.scene->r.cfra+=timeoffset;
+ scene_update_for_newframe(re->scene, lay);
+
+ /* if no camera, viewmat should have been set! */
+ if(re->scene->camera) {
+ Mat4Ortho(re->scene->camera->obmat);
+ Mat4Invert(mat, re->scene->camera->obmat);
+ RE_SetView(re, mat);
+ }
+
+ for(SETLOOPER(re->scene, base)) {
+ ob= base->object;
+ /* imat objects has to be done here, since displace can have texture using Object map-input */
+ MTC_Mat4MulMat4(mat, ob->obmat, re->viewmat);
+ MTC_Mat4Invert(ob->imat, mat);
+ /* each object should only be rendered once */
+ ob->flag &= ~OB_DONE;
+ }
+
+ /* MAKE RENDER DATA */
+
+ for(SETLOOPER(re->scene, base)) {
+ ob= base->object;
+
+ if (ob->restrictflag & OB_RESTRICT_RENDER) continue;
+
+ /* OB_DONE means the object itself got duplicated, so was already converted */
+ if(ob->flag & OB_DONE);
+ else if( (base->lay & lay) || (ob->type==OB_LAMP && (base->lay & re->scene->lay)) ) {
+ if(ob->transflag & OB_DUPLI) {
+
+ /* before make duplis, update particle for current frame */
+ if(ob->transflag & OB_DUPLIVERTS) {
+ PartEff *paf= give_parteff(ob);
+ if(paf) {
+ if(paf->flag & PAF_ANIMATED) build_particle_system(ob);
+ }
+ }
+
+ if(ob->type==OB_MBALL) {
+ init_render_object(re, ob, NULL, 0, 1);
+ }
+ else {
+ DupliObject *dob;
+ ListBase *lb= object_duplilist(sce, ob);
+
+ for(dob= lb->first; dob; dob= dob->next) {
+ Object *obd= dob->ob;
+
+ if (obd->restrictflag & OB_RESTRICT_RENDER) continue;
+
+ Mat4CpyMat4(obd->obmat, dob->mat);
+
+ if(obd->type!=OB_MBALL) {
+ init_render_object(re, obd, ob, dob->index, 1);
+ }
+ }
+ free_object_duplilist(lb);
+ }
+ }
+ else {
+ init_render_object(re, ob, NULL, 0, 1);
+ }
+
+ }
+ if(re->test_break()) break;
+ }
+
+ if(!re->test_break())
+ project_renderdata(re, projectverto, re->r.mode & R_PANORAMA, 0);
+
+ /* do this in end, particles for example need cfra */
+ G.scene->r.cfra-=timeoffset;
+}
+
+/* choose to use static, to prevent giving too many args to this call */
+static void speedvector_project(Render *re, float *zco, VertRen *ver)
+{
+ static float pixelphix=0.0f, pixelphiy=0.0f, zmulx=0.0f, zmuly=0.0f;
+ static int pano= 0;
+ float div;
+
+ /* initialize */
+ if(re) {
+ pano= re->r.mode & R_PANORAMA;
+
+ /* precalculate amount of radians 1 pixel rotates */
+ if(pano) {
+ /* size of 1 pixel mapped to viewplane coords */
+ float psize= (re->viewplane.xmax-re->viewplane.xmin)/(float)re->winx;
+ /* x angle of a pixel */
+ pixelphix= atan(psize/re->clipsta);
+
+ psize= (re->viewplane.ymax-re->viewplane.ymin)/(float)re->winy;
+ /* y angle of a pixel */
+ pixelphiy= atan(psize/re->clipsta);
+ }
+ zmulx= re->winx/2;
+ zmuly= re->winy/2;
+
+ return;
+ }
+
+ /* now map hocos to screenspace, uses very primitive clip still */
+ if(ver->ho[3]<0.1f) div= 10.0f;
+ else div= 1.0f/ver->ho[3];
+
+ /* use cylinder projection */
+ if(pano) {
+ float vec[3], ang;
+ /* angle between (0,0,-1) and (ver->co) */
+ VECCOPY(vec, ver->co);
+
+ ang= saacos(-vec[2]/sqrt(vec[0]*vec[0] + vec[2]*vec[2]));
+ if(vec[0]<0.0f) ang= -ang;
+ zco[0]= ang/pixelphix + zmulx;
+
+ ang= 0.5f*M_PI - saacos(vec[1]/sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]));
+ zco[1]= ang/pixelphiy + zmuly;
+
+ }
+ else {
+ zco[0]= zmulx*(1.0f+ver->ho[0]*div);
+ zco[1]= zmuly*(1.0f+ver->ho[1]*div);
+ }
+}
+
+static void calculate_speedvectors(Render *re, float *vectors, int startvert, int endvert, int step)
+{
+ VertRen *ver= NULL;
+ float *speed, zco[2];
+ float len;
+ float winsq= re->winx*re->winy, winroot= sqrt(winsq);
+ int a;
+
+ /* set first vertex OK */
+ a= startvert-1;
+ ver= re->vertnodes[a>>8].vert + (a & 255);
+
+ for(a=startvert; a<endvert; a++, vectors+=2) {
+ if((a & 255)==0)
+ ver= re->vertnodes[a>>8].vert;
+ else
+ ver++;
+
+ speedvector_project(NULL, zco, ver);
+
+ zco[0]= vectors[0] - zco[0];
+ zco[1]= vectors[1] - zco[1];
+
+ /* enable nice masks for hardly moving stuff or float inaccuracy */
+ if(zco[0]<0.1f && zco[0]>-0.1f && zco[1]<0.1f && zco[1]>-0.1f ) {
+ zco[0]= 0.0f;
+ zco[1]= 0.0f;
+ }
+
+ /* maximize speed for image width, otherwise it never looks good */
+ len= zco[0]*zco[0] + zco[1]*zco[1];
+ if(len > winsq) {
+ len= winroot/sqrt(len);
+ zco[0]*= len;
+ zco[1]*= len;
+ }
+
+ speed= RE_vertren_get_winspeed(re, ver, 1);
+ /* note; in main vecblur loop speedvec is negated again */
+ if(step) {
+ speed[2]= -zco[0];
+ speed[3]= -zco[1];
+ }
+ else {
+ speed[0]= zco[0];
+ speed[1]= zco[1];
+ }
+ }
+}
+
+static int load_fluidsimspeedvectors(Render *re, float *vectors, int startvert, int endvert, int step, Object *fsob)
+{
+ VertRen *ver= NULL;
+ float *speed, div, zco[2];
+ float zmulx= re->winx/2, zmuly= re->winy/2, len;
+ float winsq= re->winx*re->winy, winroot= sqrt(winsq);
+ int a, j;
+ float hoco[4], fsvec[4], camco[4];
+ float mat[4][4];
+ float imat[4][4];
+ MVert *vverts;
+
+ /* only one step needed */
+ if(step) return 1;
+
+ Mat4CpyMat4(mat, re->viewmat);
+ MTC_Mat4Invert(imat, mat);
+
+ /* set first vertex OK */
+ a= startvert-1;
+ ver= re->vertnodes[a>>8].vert + (a & 255);
+
+ if( (!fsob->fluidsimSettings) || (!fsob->fluidsimSettings->meshSurfNormals) ) return 0;
+ vverts = fsob->fluidsimSettings->meshSurfNormals;
+ //fprintf(stderr, "GZ_VEL obj '%s', calc load_fluidsimspeedvectors\n",fsob->id.name); // NT DEBUG
+
+ if( endvert-startvert != fsob->fluidsimSettings->meshSurface->totvert ) {
+ //fprintf(stderr, "load_fluidsimspeedvectors - modified fluidsim mesh, not using speed vectors (%d,%d)...\n", endvert-startvert , fsob->fluidsimSettings->meshSurface->totvert); // DEBUG
+ return 0;
+ }
+
+ for(a=startvert; a<endvert; a++, vectors+=2) {
+ if((a & 255)==0)
+ ver= re->vertnodes[a>>8].vert;
+ else
+ ver++;
+
+ // get fluid velocity
+ fsvec[3] = 0.;
+ //fsvec[0] = fsvec[1] = fsvec[2] = fsvec[3] = 0.; fsvec[2] = 2.; // NT fixed test
+ for(j=0;j<3;j++) fsvec[j] = vverts[a-startvert].co[j];
+
+ // transform (=rotate) to cam space
+ camco[0]= imat[0][0]*fsvec[0] + imat[0][1]*fsvec[1] + imat[0][2]*fsvec[2];
+ camco[1]= imat[1][0]*fsvec[0] + imat[1][1]*fsvec[1] + imat[1][2]*fsvec[2];
+ camco[2]= imat[2][0]*fsvec[0] + imat[2][1]*fsvec[1] + imat[2][2]*fsvec[2];
+
+ // get homogenous coordinates
+ projectverto(camco, re->winmat, hoco);
+
+ /* now map hocos to screenspace, uses very primitive clip still */
+ // use ho[3] of original vertex, xy component of vel. direction
+ if(ver->ho[3]<0.1f) div= 10.0f;
+ else div= 1.0f/ver->ho[3];
+ zco[0]= zmulx*hoco[0]*div;
+ zco[1]= zmuly*hoco[1]*div;
+
+ // maximize speed as usual
+ len= zco[0]*zco[0] + zco[1]*zco[1];
+ if(len > winsq) {
+ len= winroot/sqrt(len);
+ zco[0]*= len; zco[1]*= len;
+ }
+
+ speed= RE_vertren_get_winspeed(re, ver, 1);
+ // set both to the same value
+ speed[0]= speed[2]= zco[0];
+ speed[1]= speed[3]= zco[1];
+ //if(a<20) fprintf(stderr,"speed %d %f,%f | camco %f,%f,%f | hoco %f,%f,%f,%f \n", a, speed[0], speed[1], camco[0],camco[1], camco[2], hoco[0],hoco[1], hoco[2],hoco[3]); // NT DEBUG
+ }
+
+ return 1;
+}
+
+/* makes copy per object of all vectors */
+/* result should be that we can free entire database */
+static void copy_dbase_object_vectors(Render *re, ListBase *lb)
+{
+ ObjectRen *obren, *obrenlb;
+ VertRen *ver;
+ float *vec;
+ int a;
+
+ for(obren= re->objecttable.first; obren; obren= obren->next) {
+ obrenlb= MEM_dupallocN(obren);
+ BLI_addtail(lb, obrenlb);
+ if(obren->endvert>obren->startvert) {
+ vec= obrenlb->vectors= MEM_mallocN(2*sizeof(float)*(obren->endvert- obren->startvert), "vector array");
+
+ /* first vertex */
+ a= obren->startvert-1;
+ ver= re->vertnodes[a>>8].vert + (a & 255);
+
+ for(a=obren->startvert; a<obren->endvert; a++, vec+=2) {
+ if((a & 255)==0)
+ ver= re->vertnodes[a>>8].vert;
+ else
+ ver++;
+
+ speedvector_project(NULL, vec, ver);
+ }
+ }
+ }
+}
+
+static void free_dbase_object_vectors(ListBase *lb)
+{
+ ObjectRen *obren;
+
+ for(obren= lb->first; obren; obren= obren->next)
+ if(obren->vectors)
+ MEM_freeN(obren->vectors);
+ BLI_freelistN(lb);
+}
+
+void RE_Database_FromScene_Vectors(Render *re, Scene *sce)
+{
+ ObjectRen *obren, *oldobren;
+ ListBase *table;
+ ListBase oldtable= {NULL, NULL}, newtable= {NULL, NULL};
+ int step;
+
+ re->i.infostr= "Calculating previous vectors";
+ re->r.mode |= R_SPEED;
+
+ speedvector_project(re, NULL, NULL); /* initializes projection code */
+
+ /* creates entire dbase */
+ database_fromscene_vectors(re, sce, -1);
+
+ /* copy away vertex info */
+ copy_dbase_object_vectors(re, &oldtable);
+
+ /* free dbase and make the future one */
+ RE_Database_Free(re);
+
+ if(!re->test_break()) {
+ /* creates entire dbase */
+ re->i.infostr= "Calculating next frame vectors";
+
+ database_fromscene_vectors(re, sce, +1);
+ }
+ /* copy away vertex info */
+ copy_dbase_object_vectors(re, &newtable);
+
+ /* free dbase and make the real one */
+ RE_Database_Free(re);
+
+ if(!re->test_break())
+ RE_Database_FromScene(re, sce, 1);
+
+ if(!re->test_break()) {
+ for(step= 0; step<2; step++) {
+
+ if(step)
+ table= &newtable;
+ else
+ table= &oldtable;
+
+ oldobren= table->first;
+ for(obren= re->objecttable.first; obren && oldobren; obren= obren->next, oldobren= oldobren->next) {
+ int ok= 1;
+
+ /* find matching object in old table */
+ if(oldobren->ob!=obren->ob || oldobren->par!=obren->par || oldobren->index!=obren->index) {
+ ok= 0;
+ for(oldobren= table->first; oldobren; oldobren= oldobren->next)
+ if(oldobren->ob==obren->ob && oldobren->par==obren->par && oldobren->index==obren->index)
+ break;
+ if(oldobren==NULL)
+ oldobren= table->first;
+ else
+ ok= 1;
+ }
+ if(ok==0) {
+ printf("speed table: missing object %s\n", obren->ob->id.name+2);
+ continue;
+ }
+
+ // NT check for fluidsim special treatment
+ if((obren->ob->fluidsimFlag & OB_FLUIDSIM_ENABLE) && (obren->ob->fluidsimSettings->type & OB_FLUIDSIM_DOMAIN)) {
+ // use preloaded per vertex simulation data , only does calculation for step=1
+ // NOTE/FIXME - velocities and meshes loaded unnecessarily often during the database_fromscene_vectors calls...
+ load_fluidsimspeedvectors(re, oldobren->vectors, obren->startvert, obren->endvert, step, obren->ob);
+ } else {
+ /* check if both have same amounts of vertices */
+ if(obren->endvert-obren->startvert != oldobren->endvert-oldobren->startvert) {
+ printf("Warning: object %s has different amount of vertices on other frame\n", obren->ob->id.name+2);
+ continue;
+ }
+
+ calculate_speedvectors(re, oldobren->vectors, obren->startvert, obren->endvert, step);
+ } // not fluidsim
+ }
+ }
+ }
+
+ free_dbase_object_vectors(&oldtable);
+ free_dbase_object_vectors(&newtable);
+
+ re->i.infostr= NULL;
+ re->stats_draw(&re->i);
+}
+
+
+/* exported call to recalculate hoco for vertices, when winmat changed */
+void RE_DataBase_ApplyWindow(Render *re)
+{
+ project_renderdata(re, projectverto, 0, 0);
+}
+
+/* setup for shaded view or bake, so only lamps and materials are initialized */
+/* type:
+ RE_BAKE_LIGHT: for shaded view, only add lamps
+ RE_BAKE_ALL: for baking, all lamps and objects
+ RE_BAKE_NORMALS:for baking, no lamps and only selected objects
+ RE_BAKE_AO: for baking, no lamps, but all objects
+ RE_BAKE_TEXTURE:for baking, no lamps, only selected objects
+*/
+void RE_Database_Baking(Render *re, Scene *scene, int type)
+{
+ Base *base;
+ Object *ob;
+ Scene *sce;
+ float mat[4][4];
+ unsigned int lay;
+
+ re->scene= scene;
+
+ /* renderdata setup and exceptions */
+ re->r= scene->r;
+ re->r.mode &= ~R_OSA;
+ re->flag |= R_GLOB_NOPUNOFLIP;
+
+ if( ELEM3(type, RE_BAKE_LIGHT, RE_BAKE_NORMALS, RE_BAKE_TEXTURE) ) {
+ re->r.mode &= ~R_SHADOW;
+ re->r.mode &= ~R_RAYTRACE;
+ }
+
+ /* setup render stuff */
+ if(type!=RE_BAKE_LIGHT)
+ re->memArena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE);
+
+ re->totvlak=re->totvert=re->totlamp=re->tothalo= 0;
+ re->lights.first= re->lights.last= NULL;
+ re->lampren.first= re->lampren.last= NULL;
+
+ /* in localview, lamps are using normal layers, objects only local bits */
+ if(re->scene->lay & 0xFF000000) lay= re->scene->lay & 0xFF000000;
+ else lay= re->scene->lay;
+
+ /* if no camera, set unit */
+ if(re->scene->camera) {
+ Mat4Ortho(re->scene->camera->obmat);
+ Mat4Invert(mat, re->scene->camera->obmat);
+ RE_SetView(re, mat);
+ }
+ else {
+ Mat4One(mat);
+ RE_SetView(re, mat);
+ }
+
+ init_render_world(re); /* do first, because of ambient. also requires re->osa set correct */
+ if(re->wrld.mode & WO_AMB_OCC) {
+ if (re->wrld.ao_samp_method == WO_AOSAMP_HAMMERSLEY)
+ init_render_hammersley(re);
+ else if (re->wrld.ao_samp_method == WO_AOSAMP_CONSTANT)
+ init_ao_sphere(&re->wrld);
+ }
+
+
+ /* still bad... doing all */
+ init_render_textures(re);
+ init_render_materials(re->r.mode, &re->wrld.ambr);
+ set_node_shader_lamp_loop(shade_material_loop);
+
+ for(SETLOOPER(re->scene, base)) {
+ ob= base->object;
+ /* imat objects has to be done here, since displace can have texture using Object map-input */
+ MTC_Mat4MulMat4(mat, ob->obmat, re->viewmat);
+ MTC_Mat4Invert(ob->imat, mat);
+ /* each object should only be rendered once */
+ ob->flag &= ~OB_DONE;
+ }
+
+ /* MAKE RENDER DATA */
+ for(SETLOOPER(re->scene, base)) {
+ ob= base->object;
+
+ /* if the object has been restricted from rendering in the outliner, ignore it */
+ if (ob->restrictflag & OB_RESTRICT_RENDER) continue;
+
+ /* OB_DONE means the object itself got duplicated, so was already converted */
+ if(ob->flag & OB_DONE);
+ else if( (base->lay & lay) || ((base->lay & re->scene->lay)) ) {
+
+ /* check for dupli lamps or non selected groups */
+ if(ob->transflag & OB_DUPLI) {
+ DupliObject *dob;
+ ListBase *lb= object_duplilist(sce, ob);
+
+ for(dob= lb->first; dob; dob= dob->next) {
+ Object *obd= dob->ob;
+
+ if(obd->type==OB_LAMP) {
+ if( ELEM(type, RE_BAKE_LIGHT, RE_BAKE_ALL) ) {
+ Mat4CpyMat4(obd->obmat, dob->mat);
+ init_render_object(re, obd, ob, dob->index, 0);
+ }
+ }
+ else if( ELEM(type, RE_BAKE_AO, RE_BAKE_ALL) ) {
+ if((base->flag & SELECT)==0) {
+ Mat4CpyMat4(obd->obmat, dob->mat);
+ init_render_object(re, obd, ob, dob->index, 0);
+ }
+ }
+ }
+ free_object_duplilist(lb);
+ }
+ else {
+ if(ob->type==OB_LAMP) {
+ if( ELEM(type, RE_BAKE_LIGHT, RE_BAKE_ALL) )
+ init_render_object(re, ob, NULL, 0, 0);
+ }
+ else if(type!=RE_BAKE_LIGHT) {
+ if( !ELEM(type, RE_BAKE_NORMALS, RE_BAKE_TEXTURE) || (ob->flag & SELECT))
+ init_render_object(re, ob, NULL, 0, 0);
+ }
+ }
+ }
+ }
+ set_material_lightgroups(re);
+
+ check_non_flat_quads(re);
+ /* don't call set_normalflags(), no flipping */
+
+ if(type!=RE_BAKE_LIGHT) {
+ if(re->r.mode & R_SHADOW) {
+ LampRen *lar;
+
+ /* SHADOW BUFFER */
+ for(lar=re->lampren.first; lar; lar= lar->next) {
+
+ if(re->test_break()) break;
+ if(lar->shb) {
+ /* if type is irregular, this only sets the perspective matrix and autoclips */
+ /* but, that's not supported for bake... */
+ makeshadowbuf(re, lar);
+ }
+ }
+ }
+ }
+
+ if(type!=RE_BAKE_LIGHT) {
+ /* raytree */
+ if(!re->test_break()) {
+ if(re->r.mode & R_RAYTRACE) {
+ makeraytree(re);
+ }
+ }
+ }
+}
+
+void RE_DataBase_GetView(Render *re, float mat[][4])
+{
+ Mat4CpyMat4(mat, re->viewmat);
+}
+
+
+
+
+/* **************************************************************** */
+/* sticky texture coords */
+/* **************************************************************** */
+
+void RE_make_sticky(void)
+{
+ Object *ob;
+ Base *base;
+ MVert *mvert;
+ Mesh *me;
+ MSticky *ms;
+ Render *re;
+ float ho[4], mat[4][4];
+ int a;
+
+ if(G.vd==NULL) {
+ printf("Need a 3d view to make sticky\n");
+ return;
+ }
+
+ if(G.scene->camera==NULL) {
+ printf("Need camera to make sticky\n");
+ return;
+ }
+ if(G.obedit) {
+ printf("Unable to make sticky in Edit Mode\n");
+ return;
+ }
+
+ re= RE_NewRender("_make sticky_");
+ RE_InitState(re, &G.scene->r, G.scene->r.xsch, G.scene->r.ysch, NULL);
+
+ /* use renderdata and camera to set viewplane */
+ RE_SetCamera(re, G.scene->camera);
+
+ /* and set view matrix */
+ Mat4Ortho(G.scene->camera->obmat);
+ Mat4Invert(mat, G.scene->camera->obmat);
+ RE_SetView(re, mat);
+
+ for(base= FIRSTBASE; base; base= base->next) {
+ if TESTBASELIB(base) {
+ if(base->object->type==OB_MESH) {
+ ob= base->object;
+
+ me= ob->data;
+ mvert= me->mvert;
+ if(me->msticky)
+ CustomData_free_layer_active(&me->vdata, CD_MSTICKY, me->totvert);
+ me->msticky= CustomData_add_layer(&me->vdata, CD_MSTICKY,
+ CD_CALLOC, NULL, me->totvert);
+
+ where_is_object(ob);
+ Mat4MulMat4(mat, ob->obmat, re->viewmat);
+
+ ms= me->msticky;
+ for(a=0; a<me->totvert; a++, ms++, mvert++) {
+ VECCOPY(ho, mvert->co);
+ Mat4MulVecfl(mat, ho);
+ projectverto(ho, re->winmat, ho);
+ ms->co[0]= ho[0]/ho[3];
+ ms->co[1]= ho[1]/ho[3];
+ }
+ }
+ }
+ }
+}
+
+
+
+/* **************************************************************** */
+/* Displacement mapping */
+/* **************************************************************** */
+static short test_for_displace(Render *re, Object *ob)
+{
+ /* return 1 when this object uses displacement textures. */
+ Material *ma;
+ int i;
+
+ for (i=1; i<=ob->totcol; i++) {
+ ma=give_render_material(re, ob, i);
+ /* ma->mapto is ORed total of all mapto channels */
+ if(ma && (ma->mapto & MAP_DISPLACE)) return 1;
+ }
+ return 0;
+}
+
+static void displace_render_vert(Render *re, ShadeInput *shi, VertRen *vr, int vindex, float *scale)
+{
+ MTFace *tface;
+ short texco= shi->mat->texco;
+ float sample=0;
+ char *name;
+ int i;
+
+ /* shi->co is current render coord, just make sure at least some vector is here */
+ VECCOPY(shi->co, vr->co);
+ /* vertex normal is used for textures type 'col' and 'var' */
+ VECCOPY(shi->vn, vr->n);
+
+ if (texco & TEXCO_UV) {
+ shi->totuv= 0;
+
+ for (i=0; (tface=RE_vlakren_get_tface(re, shi->vlr, i, &name, 0)); i++) {
+ ShadeInputUV *suv= &shi->uv[i];
+
+ /* shi.uv needs scale correction from tface uv */
+ suv->uv[0]= 2*tface->uv[vindex][0]-1.0f;
+ suv->uv[1]= 2*tface->uv[vindex][1]-1.0f;
+ suv->uv[2]= 0.0f;
+ suv->name= name;
+ shi->totuv++;
+ }
+ }
+
+ /* set all rendercoords, 'texco' is an ORed value for all textures needed */
+ if ((texco & TEXCO_ORCO) && (vr->orco)) {
+ VECCOPY(shi->lo, vr->orco);
+ }
+ if (texco & TEXCO_STICKY) {
+ float *sticky= RE_vertren_get_sticky(re, vr, 0);
+ if(sticky) {
+ shi->sticky[0]= sticky[0];
+ shi->sticky[1]= sticky[1];
+ shi->sticky[2]= 0.0f;
+ }
+ }
+ if (texco & TEXCO_GLOB) {
+ VECCOPY(shi->gl, shi->co);
+ MTC_Mat4MulVecfl(re->viewinv, shi->gl);
+ }
+ if (texco & TEXCO_NORM) {
+ VECCOPY(shi->orn, shi->vn);
+ }
+ if(texco & TEXCO_REFL) {
+ /* not (yet?) */
+ }
+
+ shi->displace[0]= shi->displace[1]= shi->displace[2]= 0.0;
+
+ do_material_tex(shi);
+
+ //printf("no=%f, %f, %f\nbefore co=%f, %f, %f\n", vr->n[0], vr->n[1], vr->n[2],
+ //vr->co[0], vr->co[1], vr->co[2]);
+
+ /* 0.5 could become button once? */
+ vr->co[0] += shi->displace[0] * scale[0] ;
+ vr->co[1] += shi->displace[1] * scale[1] ;
+ vr->co[2] += shi->displace[2] * scale[2] ;
+
+ //printf("after co=%f, %f, %f\n", vr->co[0], vr->co[1], vr->co[2]);
+
+ /* we just don't do this vertex again, bad luck for other face using same vertex with
+ different material... */
+ vr->flag |= 1;
+
+ /* Pass sample back so displace_face can decide which way to split the quad */
+ sample = shi->displace[0]*shi->displace[0];
+ sample += shi->displace[1]*shi->displace[1];
+ sample += shi->displace[2]*shi->displace[2];
+
+ vr->accum=sample;
+ /* Should be sqrt(sample), but I'm only looking for "bigger". Save the cycles. */
+ return;
+}
+
+static void displace_render_face(Render *re, VlakRen *vlr, float *scale)
+{
+ ShadeInput shi;
+
+ /* set up shadeinput struct for multitex() */
+ shi.osatex= 0; /* signal not to use dx[] and dy[] texture AA vectors */
+ shi.vlr= vlr; /* current render face */
+ shi.mat= vlr->mat; /* current input material */
+
+ /* Displace the verts, flag is set when done */
+ if (!vlr->v1->flag)
+ displace_render_vert(re, &shi, vlr->v1,0, scale);
+
+ if (!vlr->v2->flag)
+ displace_render_vert(re, &shi, vlr->v2, 1, scale);
+
+ if (!vlr->v3->flag)
+ displace_render_vert(re, &shi, vlr->v3, 2, scale);
+
+ if (vlr->v4) {
+ if (!vlr->v4->flag)
+ displace_render_vert(re, &shi, vlr->v4, 3, scale);
+
+ /* closest in displace value. This will help smooth edges. */
+ if ( fabs(vlr->v1->accum - vlr->v3->accum) > fabs(vlr->v2->accum - vlr->v4->accum))
+ vlr->flag |= R_DIVIDE_24;
+ else vlr->flag &= ~R_DIVIDE_24; // E: typo?, was missing '='
+ }
+
+ /* Recalculate the face normal - if flipped before, flip now */
+ if(vlr->v4) {
+ CalcNormFloat4(vlr->v4->co, vlr->v3->co, vlr->v2->co, vlr->v1->co, vlr->n);
+ }
+ else {
+ CalcNormFloat(vlr->v3->co, vlr->v2->co, vlr->v1->co, vlr->n);
+ }
+}
+
+
+static void do_displacement(Render *re, Object *ob, int startface, int numface, int startvert, int numvert )
+{
+ VertRen *vr;
+ VlakRen *vlr;
+// float min[3]={1e30, 1e30, 1e30}, max[3]={-1e30, -1e30, -1e30};
+ float scale[3]={1.0f, 1.0f, 1.0f}, temp[3];//, xn
+ int i; //, texflag=0;
+ Object *obt;
+
+ /* Object Size with parenting */
+ obt=ob;
+ while(obt){
+ VecAddf(temp, obt->size, obt->dsize);
+ scale[0]*=temp[0]; scale[1]*=temp[1]; scale[2]*=temp[2];
+ obt=obt->parent;
+ }
+
+ /* Clear all flags */
+ for(i=startvert; i<startvert+numvert; i++){
+ vr= RE_findOrAddVert(re, i);
+ vr->flag= 0;
+ }
+
+ for(i=startface; i<startface+numface; i++){
+ vlr=RE_findOrAddVlak(re, i);
+ displace_render_face(re, vlr, scale);
+ }
+
+ /* Recalc vertex normals */
+ calc_vertexnormals(re, startvert, startface, 0);
+}
+
diff --git a/source/blender/render/intern/source/envmap.c b/source/blender/render/intern/source/envmap.c
new file mode 100644
index 00000000000..ebb444833e8
--- /dev/null
+++ b/source/blender/render/intern/source/envmap.c
@@ -0,0 +1,719 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributors: 2004/2005/2006 Blender Foundation, full recode
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <math.h>
+#include <string.h>
+
+/* external modules: */
+#include "MEM_guardedalloc.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+#include "BLI_threads.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h" /* for rectcpy */
+
+#include "DNA_group_types.h"
+#include "DNA_image_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_texture_types.h"
+
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_global.h"
+#include "BKE_image.h" // BKE_write_ibuf
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
+
+#include "MTC_matrixops.h"
+
+/* this module */
+#include "render_types.h"
+#include "renderpipeline.h"
+#include "envmap.h"
+#include "rendercore.h"
+#include "renderdatabase.h"
+#include "texture.h"
+#include "zbuf.h"
+#include "initrender.h"
+
+
+/* ------------------------------------------------------------------------- */
+
+static void envmap_split_ima(EnvMap *env, ImBuf *ibuf)
+{
+ int dx, part;
+
+ BKE_free_envmapdata(env);
+
+ dx= ibuf->y;
+ dx/= 2;
+ if(3*dx != ibuf->x) {
+ printf("Incorrect envmap size\n");
+ env->ok= 0;
+ env->ima->ok= 0;
+ }
+ else {
+ for(part=0; part<6; part++) {
+ env->cube[part]= IMB_allocImBuf(dx, dx, 24, IB_rect, 0);
+ }
+ IMB_rectcpy(env->cube[0], ibuf,
+ 0, 0, 0, 0, dx, dx);
+ IMB_rectcpy(env->cube[1], ibuf,
+ 0, 0, dx, 0, dx, dx);
+ IMB_rectcpy(env->cube[2], ibuf,
+ 0, 0, 2*dx, 0, dx, dx);
+ IMB_rectcpy(env->cube[3], ibuf,
+ 0, 0, 0, dx, dx, dx);
+ IMB_rectcpy(env->cube[4], ibuf,
+ 0, 0, dx, dx, dx, dx);
+ IMB_rectcpy(env->cube[5], ibuf,
+ 0, 0, 2*dx, dx, dx, dx);
+ env->ok= ENV_OSA;
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+/* ****************** RENDER ********************** */
+
+/* copy current render */
+static Render *envmap_render_copy(Render *re, EnvMap *env)
+{
+ Render *envre;
+ int cuberes;
+
+ envre= RE_NewRender("Envmap");
+
+ env->lastsize= re->r.size;
+ cuberes = (env->cuberes * re->r.size) / 100;
+ cuberes &= 0xFFFC;
+
+ /* this flag has R_ZTRA in it for example */
+ envre->flag= re->flag;
+
+ /* set up renderdata */
+ envre->r= re->r;
+ envre->r.mode &= ~(R_BORDER | R_PANORAMA | R_ORTHO | R_MBLUR);
+ envre->r.layers.first= envre->r.layers.last= NULL;
+ envre->r.filtertype= 0;
+ envre->r.xparts= envre->r.yparts= 2;
+ envre->r.bufflag= 0;
+ envre->r.size= 100;
+ envre->r.yasp= envre->r.xasp= 1;
+
+ RE_InitState(envre, &envre->r, cuberes, cuberes, NULL);
+ envre->scene= re->scene; /* unsure about this... */
+
+ /* view stuff in env render */
+ envre->lens= 16.0f;
+ if(env->type==ENV_PLANE)
+ envre->lens*= env->viewscale;
+ envre->ycor= 1.0f;
+ envre->clipsta= env->clipsta; /* render_scene_set_window() respects this for now */
+ envre->clipend= env->clipend;
+
+ RE_SetCamera(envre, env->object);
+
+ /* callbacks */
+ envre->display_draw= re->display_draw;
+ envre->test_break= re->test_break;
+
+ /* and for the evil stuff; copy the database... */
+ envre->totvlak= re->totvlak;
+ envre->totvert= re->totvert;
+ envre->tothalo= re->tothalo;
+ envre->totlamp= re->totlamp;
+ envre->lights= re->lights;
+ envre->vertnodeslen= re->vertnodeslen;
+ envre->vertnodes= re->vertnodes;
+ envre->blohalen= re->blohalen;
+ envre->bloha= re->bloha;
+ envre->vlaknodeslen= re->vlaknodeslen;
+ envre->vlaknodes= re->vlaknodes;
+ envre->customdata_names= re->customdata_names;
+ envre->raytree= re->raytree;
+
+ return envre;
+}
+
+static void envmap_free_render_copy(Render *envre)
+{
+
+ envre->totvlak= 0;
+ envre->totvert= 0;
+ envre->tothalo= 0;
+ envre->totlamp= 0;
+ envre->lights.first= envre->lights.last= NULL;
+ envre->vertnodeslen= 0;
+ envre->vertnodes= NULL;
+ envre->blohalen= 0;
+ envre->bloha= NULL;
+ envre->vlaknodeslen= 0;
+ envre->vlaknodes= NULL;
+ envre->customdata_names.first= envre->customdata_names.last= NULL;
+ envre->raytree= NULL;
+
+ RE_FreeRender(envre);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void envmap_transmatrix(float mat[][4], int part)
+{
+ float tmat[4][4], eul[3], rotmat[4][4];
+
+ eul[0]= eul[1]= eul[2]= 0.0;
+
+ if(part==0) { /* neg z */
+ ;
+ } else if(part==1) { /* pos z */
+ eul[0]= M_PI;
+ } else if(part==2) { /* pos y */
+ eul[0]= M_PI/2.0;
+ } else if(part==3) { /* neg x */
+ eul[0]= M_PI/2.0;
+ eul[2]= M_PI/2.0;
+ } else if(part==4) { /* neg y */
+ eul[0]= M_PI/2.0;
+ eul[2]= M_PI;
+ } else { /* pos x */
+ eul[0]= M_PI/2.0;
+ eul[2]= -M_PI/2.0;
+ }
+
+ MTC_Mat4CpyMat4(tmat, mat);
+ EulToMat4(eul, rotmat);
+ MTC_Mat4MulSerie(mat, tmat, rotmat,
+ 0, 0, 0,
+ 0, 0, 0);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void env_rotate_scene(Render *re, float mat[][4], int mode)
+{
+ GroupObject *go;
+ VlakRen *vlr = NULL;
+ VertRen *ver = NULL;
+ LampRen *lar = NULL;
+ HaloRen *har = NULL;
+ float xn, yn, zn, imat[3][3], pmat[4][4], smat[4][4], tmat[4][4], cmat[3][3];
+ int a;
+
+ if(mode==0) {
+ MTC_Mat4Invert(tmat, mat);
+ MTC_Mat3CpyMat4(imat, tmat);
+ }
+ else {
+ MTC_Mat4CpyMat4(tmat, mat);
+ MTC_Mat3CpyMat4(imat, mat);
+ }
+
+ for(a=0; a<re->totvert; a++) {
+ if((a & 255)==0) ver= RE_findOrAddVert(re, a);
+ else ver++;
+
+ MTC_Mat4MulVecfl(tmat, ver->co);
+
+ xn= ver->n[0];
+ yn= ver->n[1];
+ zn= ver->n[2];
+ /* no transpose ! */
+ ver->n[0]= imat[0][0]*xn+imat[1][0]*yn+imat[2][0]*zn;
+ ver->n[1]= imat[0][1]*xn+imat[1][1]*yn+imat[2][1]*zn;
+ ver->n[2]= imat[0][2]*xn+imat[1][2]*yn+imat[2][2]*zn;
+ Normalize(ver->n);
+ }
+
+ for(a=0; a<re->tothalo; a++) {
+ if((a & 255)==0) har= re->bloha[a>>8];
+ else har++;
+
+ MTC_Mat4MulVecfl(tmat, har->co);
+ }
+
+ for(a=0; a<re->totvlak; a++) {
+ if((a & 255)==0) vlr= re->vlaknodes[a>>8].vlak;
+ else vlr++;
+
+ xn= vlr->n[0];
+ yn= vlr->n[1];
+ zn= vlr->n[2];
+ /* no transpose ! */
+ vlr->n[0]= imat[0][0]*xn+imat[1][0]*yn+imat[2][0]*zn;
+ vlr->n[1]= imat[0][1]*xn+imat[1][1]*yn+imat[2][1]*zn;
+ vlr->n[2]= imat[0][2]*xn+imat[1][2]*yn+imat[2][2]*zn;
+ Normalize(vlr->n);
+ }
+
+ set_normalflags(re);
+
+ for(go=re->lights.first; go; go= go->next) {
+ lar= go->lampren;
+
+ /* removed here some horrible code of someone in NaN who tried to fix
+ prototypes... just solved by introducing a correct cmat[3][3] instead
+ of using smat. this works, check square spots in reflections (ton) */
+ Mat3CpyMat3(cmat, lar->imat);
+ Mat3MulMat3(lar->imat, cmat, imat);
+
+ MTC_Mat3MulVecfl(imat, lar->vec);
+ MTC_Mat4MulVecfl(tmat, lar->co);
+
+ lar->sh_invcampos[0]= -lar->co[0];
+ lar->sh_invcampos[1]= -lar->co[1];
+ lar->sh_invcampos[2]= -lar->co[2];
+ MTC_Mat3MulVecfl(lar->imat, lar->sh_invcampos);
+ lar->sh_invcampos[2]*= lar->sh_zfac;
+
+ if(lar->shb) {
+ if(mode==1) {
+ MTC_Mat4Invert(pmat, mat);
+ MTC_Mat4MulMat4(smat, pmat, lar->shb->viewmat);
+ MTC_Mat4MulMat4(lar->shb->persmat, smat, lar->shb->winmat);
+ }
+ else MTC_Mat4MulMat4(lar->shb->persmat, lar->shb->viewmat, lar->shb->winmat);
+ }
+ }
+
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void env_layerflags(Render *re, unsigned int notlay)
+{
+ VlakRen *vlr = NULL;
+ int a;
+
+ /* invert notlay, so if face is in multiple layers it will still be visible,
+ unless all 'notlay' bits match the face bits.
+ face: 0110
+ not: 0100
+ ~not: 1011
+ now (face & ~not) is true
+ */
+
+ notlay= ~notlay;
+
+ for(a=0; a<re->totvlak; a++) {
+ if((a & 255)==0) vlr= re->vlaknodes[a>>8].vlak;
+ else vlr++;
+ if((vlr->lay & notlay)==0)
+ vlr->flag &= ~R_VISIBLE;
+ }
+}
+
+static void env_hideobject(Render *re, Object *ob)
+{
+ VlakRen *vlr = NULL;
+ int a;
+
+ for(a=0; a<re->totvlak; a++) {
+ if((a & 255)==0) vlr= re->vlaknodes[a>>8].vlak;
+ else vlr++;
+ if(vlr->ob == ob) vlr->flag &= ~R_VISIBLE;
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void env_set_imats(Render *re)
+{
+ Base *base;
+ float mat[4][4];
+
+ base= G.scene->base.first;
+ while(base) {
+ MTC_Mat4MulMat4(mat, base->object->obmat, re->viewmat);
+ MTC_Mat4Invert(base->object->imat, mat);
+
+ base= base->next;
+ }
+
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void render_envmap(Render *re, EnvMap *env)
+{
+ /* only the cubemap and planar map is implemented */
+ Render *envre;
+ ImBuf *ibuf;
+ float orthmat[4][4];
+ float oldviewinv[4][4], mat[4][4], tmat[4][4];
+ short part;
+
+ /* need a recalc: ortho-render has no correct viewinv */
+ MTC_Mat4Invert(oldviewinv, re->viewmat);
+
+ envre= envmap_render_copy(re, env);
+
+ /* precalc orthmat for object */
+ MTC_Mat4CpyMat4(orthmat, env->object->obmat);
+ MTC_Mat4Ortho(orthmat);
+
+ /* need imat later for texture imat */
+ MTC_Mat4MulMat4(mat, orthmat, re->viewmat);
+ MTC_Mat4Invert(tmat, mat);
+ MTC_Mat3CpyMat4(env->obimat, tmat);
+
+ for(part=0; part<6; part++) {
+ if(env->type==ENV_PLANE && part!=1)
+ continue;
+
+ re->display_clear(envre->result);
+
+ MTC_Mat4CpyMat4(tmat, orthmat);
+ envmap_transmatrix(tmat, part);
+ MTC_Mat4Invert(mat, tmat);
+ /* mat now is the camera 'viewmat' */
+
+ MTC_Mat4CpyMat4(envre->viewmat, mat);
+ MTC_Mat4CpyMat4(envre->viewinv, tmat);
+
+ /* we have to correct for the already rotated vertexcoords */
+ MTC_Mat4MulMat4(tmat, oldviewinv, envre->viewmat);
+ MTC_Mat4Invert(env->imat, tmat);
+
+ env_rotate_scene(envre, tmat, 1);
+ init_render_world(envre);
+ project_renderdata(envre, projectverto, 0, 0);
+ env_layerflags(envre, env->notlay);
+ env_hideobject(envre, env->object);
+ env_set_imats(envre);
+
+ if(re->test_break()==0) {
+ RE_TileProcessor(envre, 0, 0);
+ }
+
+ /* rotate back */
+ env_rotate_scene(envre, tmat, 0);
+
+ if(re->test_break()==0) {
+ RenderLayer *rl= envre->result->layers.first;
+
+ ibuf= IMB_allocImBuf(envre->rectx, envre->recty, 24, IB_rect, 0);
+ ibuf->rect_float= rl->rectf;
+ IMB_rect_from_float(ibuf);
+ ibuf->rect_float= NULL;
+
+ env->cube[part]= ibuf;
+ }
+
+ if(re->test_break()) break;
+
+ }
+
+ if(re->test_break()) BKE_free_envmapdata(env);
+ else {
+ if(envre->r.mode & R_OSA) env->ok= ENV_OSA;
+ else env->ok= ENV_NORMAL;
+ env->lastframe= G.scene->r.cfra; /* hurmf */
+ }
+
+ /* restore */
+ envmap_free_render_copy(envre);
+ env_set_imats(re);
+
+}
+
+/* ------------------------------------------------------------------------- */
+
+void make_envmaps(Render *re)
+{
+ Tex *tex;
+ int do_init= 0, depth= 0, trace;
+
+ if (!(re->r.mode & R_ENVMAP)) return;
+
+ /* we dont raytrace, disabling the flag will cause ray_transp render solid */
+ trace= (re->r.mode & R_RAYTRACE);
+ re->r.mode &= ~R_RAYTRACE;
+
+ re->i.infostr= "Creating Environment maps";
+ re->stats_draw(&re->i);
+
+ /* 5 = hardcoded max recursion level */
+ while(depth<5) {
+ tex= G.main->tex.first;
+ while(tex) {
+ if(tex->id.us && tex->type==TEX_ENVMAP) {
+ if(tex->env && tex->env->object) {
+ EnvMap *env= tex->env;
+
+ if(env->object->lay & G.scene->lay) {
+ if(env->stype==ENV_LOAD) {
+ float orthmat[4][4], mat[4][4], tmat[4][4];
+
+ /* precalc orthmat for object */
+ MTC_Mat4CpyMat4(orthmat, env->object->obmat);
+ MTC_Mat4Ortho(orthmat);
+
+ /* need imat later for texture imat */
+ MTC_Mat4MulMat4(mat, orthmat, re->viewmat);
+ MTC_Mat4Invert(tmat, mat);
+ MTC_Mat3CpyMat4(env->obimat, tmat);
+ }
+ else {
+
+ /* decide if to render an envmap (again) */
+ if(env->depth >= depth) {
+
+ /* set 'recalc' to make sure it does an entire loop of recalcs */
+
+ if(env->ok) {
+ /* free when OSA, and old one isn't OSA */
+ if((re->r.mode & R_OSA) && env->ok==ENV_NORMAL)
+ BKE_free_envmapdata(env);
+ /* free when size larger */
+ else if(env->lastsize < re->r.size)
+ BKE_free_envmapdata(env);
+ /* free when env is in recalcmode */
+ else if(env->recalc)
+ BKE_free_envmapdata(env);
+ }
+
+ if(env->ok==0 && depth==0) env->recalc= 1;
+
+ if(env->ok==0) {
+ do_init= 1;
+ render_envmap(re, env);
+
+ if(depth==env->depth) env->recalc= 0;
+ }
+ }
+ }
+ }
+ }
+ }
+ tex= tex->id.next;
+ }
+ depth++;
+ }
+
+ if(do_init) {
+ re->display_init(re->result);
+ re->display_clear(re->result);
+ // re->flag |= R_REDRAW_PRV;
+ }
+ // restore
+ re->r.mode |= trace;
+
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int envcube_isect(EnvMap *env, float *vec, float *answ)
+{
+ float labda;
+ int face;
+
+ if(env->type==ENV_PLANE) {
+ face= 1;
+
+ labda= 1.0/vec[2];
+ answ[0]= env->viewscale*labda*vec[0];
+ answ[1]= -env->viewscale*labda*vec[1];
+ }
+ else {
+ /* which face */
+ if( vec[2]<=-fabs(vec[0]) && vec[2]<=-fabs(vec[1]) ) {
+ face= 0;
+ labda= -1.0/vec[2];
+ answ[0]= labda*vec[0];
+ answ[1]= labda*vec[1];
+ }
+ else if( vec[2]>=fabs(vec[0]) && vec[2]>=fabs(vec[1]) ) {
+ face= 1;
+ labda= 1.0/vec[2];
+ answ[0]= labda*vec[0];
+ answ[1]= -labda*vec[1];
+ }
+ else if( vec[1]>=fabs(vec[0]) ) {
+ face= 2;
+ labda= 1.0/vec[1];
+ answ[0]= labda*vec[0];
+ answ[1]= labda*vec[2];
+ }
+ else if( vec[0]<=-fabs(vec[1]) ) {
+ face= 3;
+ labda= -1.0/vec[0];
+ answ[0]= labda*vec[1];
+ answ[1]= labda*vec[2];
+ }
+ else if( vec[1]<=-fabs(vec[0]) ) {
+ face= 4;
+ labda= -1.0/vec[1];
+ answ[0]= -labda*vec[0];
+ answ[1]= labda*vec[2];
+ }
+ else {
+ face= 5;
+ labda= 1.0/vec[0];
+ answ[0]= -labda*vec[1];
+ answ[1]= labda*vec[2];
+ }
+ }
+
+ answ[0]= 0.5+0.5*answ[0];
+ answ[1]= 0.5+0.5*answ[1];
+ return face;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void set_dxtdyt(float *dxts, float *dyts, float *dxt, float *dyt, int face)
+{
+ if(face==2 || face==4) {
+ dxts[0]= dxt[0];
+ dyts[0]= dyt[0];
+ dxts[1]= dxt[2];
+ dyts[1]= dyt[2];
+ }
+ else if(face==3 || face==5) {
+ dxts[0]= dxt[1];
+ dxts[1]= dxt[2];
+ dyts[0]= dyt[1];
+ dyts[1]= dyt[2];
+ }
+ else {
+ dxts[0]= dxt[0];
+ dyts[0]= dyt[0];
+ dxts[1]= dxt[1];
+ dyts[1]= dyt[1];
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+int envmaptex(Tex *tex, float *texvec, float *dxt, float *dyt, int osatex, TexResult *texres)
+{
+ extern Render R; /* only in this call */
+ /* texvec should be the already reflected normal */
+ EnvMap *env;
+ ImBuf *ibuf;
+ float fac, vec[3], sco[3], dxts[3], dyts[3];
+ int face, face1;
+
+ env= tex->env;
+ if(env==NULL || (env->stype!=ENV_LOAD && env->object==NULL)) {
+ texres->tin= 0.0;
+ return 0;
+ }
+ if(env->stype==ENV_LOAD) {
+ env->ima= tex->ima;
+ if(env->ima && env->ima->ok) {
+ if(env->cube[0]==NULL) {
+ ImBuf *ibuf= BKE_image_get_ibuf(env->ima, NULL);
+ if(ibuf)
+ envmap_split_ima(env, ibuf);
+ else
+ env->ok= 0;
+ }
+ }
+ }
+
+ if(env->ok==0) {
+
+ texres->tin= 0.0;
+ return 0;
+ }
+
+ /* rotate to envmap space, if object is set */
+ VECCOPY(vec, texvec);
+ if(env->object) MTC_Mat3MulVecfl(env->obimat, vec);
+ else MTC_Mat4Mul3Vecfl(R.viewinv, vec);
+
+ face= envcube_isect(env, vec, sco);
+ ibuf= env->cube[face];
+
+ if(osatex) {
+ if(env->object) {
+ MTC_Mat3MulVecfl(env->obimat, dxt);
+ MTC_Mat3MulVecfl(env->obimat, dyt);
+ }
+ else {
+ MTC_Mat4Mul3Vecfl(R.viewinv, dxt);
+ MTC_Mat4Mul3Vecfl(R.viewinv, dyt);
+ }
+ set_dxtdyt(dxts, dyts, dxt, dyt, face);
+ imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, texres);
+
+ /* edges? */
+
+ if(texres->ta<1.0) {
+ TexResult texr1, texr2;
+
+ texr1.nor= texr2.nor= NULL;
+
+ VecAddf(vec, vec, dxt);
+ face1= envcube_isect(env, vec, sco);
+ VecSubf(vec, vec, dxt);
+
+ if(face!=face1) {
+ ibuf= env->cube[face1];
+ set_dxtdyt(dxts, dyts, dxt, dyt, face1);
+ imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, &texr1);
+ }
+ else texr1.tr= texr1.tg= texr1.tb= texr1.ta= 0.0;
+
+ /* here was the nasty bug! results were not zero-ed. FPE! */
+
+ VecAddf(vec, vec, dyt);
+ face1= envcube_isect(env, vec, sco);
+ VecSubf(vec, vec, dyt);
+
+ if(face!=face1) {
+ ibuf= env->cube[face1];
+ set_dxtdyt(dxts, dyts, dxt, dyt, face1);
+ imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, &texr2);
+ }
+ else texr2.tr= texr2.tg= texr2.tb= texr2.ta= 0.0;
+
+ fac= (texres->ta+texr1.ta+texr2.ta);
+ if(fac!=0.0) {
+ fac= 1.0/fac;
+
+ texres->tr= fac*(texres->ta*texres->tr + texr1.ta*texr1.tr + texr2.ta*texr2.tr );
+ texres->tg= fac*(texres->ta*texres->tg + texr1.ta*texr1.tg + texr2.ta*texr2.tg );
+ texres->tb= fac*(texres->ta*texres->tb + texr1.ta*texr1.tb + texr2.ta*texr2.tb );
+ }
+ texres->ta= 1.0;
+ }
+ }
+ else {
+ imagewrap(tex, NULL, ibuf, sco, texres);
+ }
+
+ return 1;
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* eof */
diff --git a/source/blender/render/intern/source/gammaCorrectionTables.c b/source/blender/render/intern/source/gammaCorrectionTables.c
new file mode 100644
index 00000000000..ae54d061eda
--- /dev/null
+++ b/source/blender/render/intern/source/gammaCorrectionTables.c
@@ -0,0 +1,148 @@
+/**
+ * Jitter offset table
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "gammaCorrectionTables.h"
+#include <stdlib.h>
+#include <math.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* WARNING; optimized, cannot be used to do gamma(invgamma()) and expect */
+/* result remain identical (ton) */
+
+/* gamma is only used here for correcting adding colors or alpha */
+#define RE_DEFAULT_GAMMA 2.0
+
+/* This 400 is sort of based on the number of intensity levels needed for */
+/* the typical dynamic range of a medium, in this case CRTs. (Foley) */
+/* (Actually, it says the number should be between 400 and 535.) */
+#define RE_GAMMA_TABLE_SIZE 400
+
+/* These indicate the status of the gamma lookup table --------------------- */
+
+static float gamma_range_table[RE_GAMMA_TABLE_SIZE + 1];
+static float gamfactor_table[RE_GAMMA_TABLE_SIZE];
+static float inv_gamma_range_table[RE_GAMMA_TABLE_SIZE + 1];
+static float inv_gamfactor_table[RE_GAMMA_TABLE_SIZE];
+static float color_domain_table[RE_GAMMA_TABLE_SIZE + 1];
+static float color_step;
+static float inv_color_step;
+static float valid_gamma;
+static float valid_inv_gamma;
+
+/* ------------------------------------------------------------------------- */
+
+float gammaCorrect(float c)
+{
+ int i;
+ float res = 0.0;
+
+ i = floor(c * inv_color_step);
+ /* Clip to range [0,1]: outside, just do the complete calculation. */
+ /* We may have some performance problems here. Stretching up the LUT */
+ /* may help solve that, by exchanging LUT size for the interpolation. */
+ /* Negative colors are explicitly handled. */
+ if (i < 0) res = -pow(abs(c), valid_gamma);
+ else if (i >= RE_GAMMA_TABLE_SIZE ) res = pow(c, valid_gamma);
+ else res = gamma_range_table[i] +
+ ( (c - color_domain_table[i]) * gamfactor_table[i]);
+
+ return res;
+} /* end of float gammaCorrect(float col) */
+
+/* ------------------------------------------------------------------------- */
+
+float invGammaCorrect(float col)
+{
+ int i;
+ float res = 0.0;
+
+ i = floor(col*inv_color_step);
+ /* Negative colors are explicitly handled. */
+ if (i < 0) res = -pow(abs(col), valid_inv_gamma);
+ else if (i >= RE_GAMMA_TABLE_SIZE) res = pow(col, valid_inv_gamma);
+ else res = inv_gamma_range_table[i] +
+ ( (col - color_domain_table[i]) * inv_gamfactor_table[i]);
+
+ return res;
+} /* end of float invGammaCorrect(float col) */
+
+
+/* ------------------------------------------------------------------------- */
+
+void makeGammaTables(float gamma)
+{
+ /* we need two tables: one forward, one backward */
+ int i;
+
+ valid_gamma = gamma;
+ valid_inv_gamma = 1.0 / gamma;
+ color_step = 1.0 / RE_GAMMA_TABLE_SIZE;
+ inv_color_step = (float) RE_GAMMA_TABLE_SIZE;
+
+ /* We could squeeze out the two range tables to gain some memory. */
+ for (i = 0; i < RE_GAMMA_TABLE_SIZE; i++) {
+ color_domain_table[i] = i * color_step;
+ gamma_range_table[i] = pow(color_domain_table[i],
+ valid_gamma);
+ inv_gamma_range_table[i] = pow(color_domain_table[i],
+ valid_inv_gamma);
+ }
+
+ /* The end of the table should match 1.0 carefully. In order to avoid */
+ /* rounding errors, we just set this explicitly. The last segment may */
+ /* have a different lenght than the other segments, but our */
+ /* interpolation is insensitive to that. */
+ color_domain_table[RE_GAMMA_TABLE_SIZE] = 1.0;
+ gamma_range_table[RE_GAMMA_TABLE_SIZE] = 1.0;
+ inv_gamma_range_table[RE_GAMMA_TABLE_SIZE] = 1.0;
+
+ /* To speed up calculations, we make these calc factor tables. They are */
+ /* multiplication factors used in scaling the interpolation. */
+ for (i = 0; i < RE_GAMMA_TABLE_SIZE; i++ ) {
+ gamfactor_table[i] = inv_color_step
+ * (gamma_range_table[i + 1] - gamma_range_table[i]) ;
+ inv_gamfactor_table[i] = inv_color_step
+ * (inv_gamma_range_table[i + 1] - inv_gamma_range_table[i]) ;
+ }
+
+} /* end of void makeGammaTables(float gamma) */
+
+
+
+/* ------------------------------------------------------------------------- */
+
+/* eof */
diff --git a/source/blender/render/intern/source/imagetexture.c b/source/blender/render/intern/source/imagetexture.c
new file mode 100644
index 00000000000..82abab62637
--- /dev/null
+++ b/source/blender/render/intern/source/imagetexture.c
@@ -0,0 +1,972 @@
+/**
+ *
+ * $Id:
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributors: 2004/2005/2006 Blender Foundation, full recode
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+
+
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <math.h>
+#ifndef WIN32
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "DNA_image_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_texture_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_threads.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_image.h"
+#include "BKE_texture.h"
+#include "BKE_library.h"
+
+#include "renderpipeline.h"
+#include "render_types.h"
+#include "texture.h"
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
+/* only to be used here in this file, it's for speed */
+extern struct Render R;
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* *********** IMAGEWRAPPING ****************** */
+
+
+/* x and y have to be checked for image size */
+static void ibuf_get_color(float *col, struct ImBuf *ibuf, int x, int y)
+{
+ int ofs = y * ibuf->x + x;
+
+ if(ibuf->rect_float) {
+ if(ibuf->channels==4) {
+ float *fp= ibuf->rect_float + 4*ofs;
+ QUATCOPY(col, fp);
+ }
+ else if(ibuf->channels==3) {
+ float *fp= ibuf->rect_float + 3*ofs;
+ VECCOPY(col, fp);
+ col[3]= 1.0f;
+ }
+ else {
+ float *fp= ibuf->rect_float + ofs;
+ col[0]= col[1]= col[2]= col[3]= *fp;
+ }
+ }
+ else {
+ char *rect = (char *)( ibuf->rect+ ofs);
+
+ col[0] = ((float)rect[0])/255.0f;
+ col[1] = ((float)rect[1])/255.0f;
+ col[2] = ((float)rect[2])/255.0f;
+ col[3] = ((float)rect[3])/255.0f;
+ }
+}
+
+int imagewrap(Tex *tex, Image *ima, ImBuf *ibuf, float *texvec, TexResult *texres)
+{
+ float fx, fy, val1, val2, val3;
+ int x, y, retval;
+
+ texres->tin= texres->ta= texres->tr= texres->tg= texres->tb= 0.0f;
+
+ /* we need to set retval OK, otherwise texture code generates normals itself... */
+ retval= texres->nor?3:1;
+
+ /* quick tests */
+ if(ibuf==NULL && ima==NULL)
+ return retval;
+ if(ima) {
+
+ /* hack for icon render */
+ if(ima->ibufs.first==NULL && (R.r.scemode & R_NO_IMAGE_LOAD))
+ return retval;
+
+ ibuf= BKE_image_get_ibuf(ima, &tex->iuser);
+ }
+ if(ibuf==NULL || (ibuf->rect==NULL && ibuf->rect_float==NULL))
+ return retval;
+
+ /* setup mapping */
+ if(tex->imaflag & TEX_IMAROT) {
+ fy= texvec[0];
+ fx= texvec[1];
+ }
+ else {
+ fx= texvec[0];
+ fy= texvec[1];
+ }
+
+ if(tex->extend == TEX_CHECKER) {
+ int xs, ys;
+
+ xs= (int)floor(fx);
+ ys= (int)floor(fy);
+ fx-= xs;
+ fy-= ys;
+
+ if( (tex->flag & TEX_CHECKER_ODD)==0) {
+ if((xs+ys) & 1);else return retval;
+ }
+ if( (tex->flag & TEX_CHECKER_EVEN)==0) {
+ if((xs+ys) & 1) return retval;
+ }
+ /* scale around center, (0.5, 0.5) */
+ if(tex->checkerdist<1.0) {
+ fx= (fx-0.5)/(1.0-tex->checkerdist) +0.5;
+ fy= (fy-0.5)/(1.0-tex->checkerdist) +0.5;
+ }
+ }
+
+ x = (int)(fx*ibuf->x);
+ y = (int)(fy*ibuf->y);
+
+ if(tex->extend == TEX_CLIPCUBE) {
+ if(x<0 || y<0 || x>=ibuf->x || y>=ibuf->y || texvec[2]<-1.0 || texvec[2]>1.0) {
+ return retval;
+ }
+ }
+ else if( tex->extend==TEX_CLIP || tex->extend==TEX_CHECKER) {
+ if(x<0 || y<0 || x>=ibuf->x || y>=ibuf->y) {
+ return retval;
+ }
+ }
+ else {
+ if(tex->extend==TEX_EXTEND) {
+ if(x>=ibuf->x) x = ibuf->x-1;
+ else if(x<0) x= 0;
+ }
+ else {
+ x= x % ibuf->x;
+ if(x<0) x+= ibuf->x;
+ }
+ if(tex->extend==TEX_EXTEND) {
+ if(y>=ibuf->y) y = ibuf->y-1;
+ else if(y<0) y= 0;
+ }
+ else {
+ y= y % ibuf->y;
+ if(y<0) y+= ibuf->y;
+ }
+ }
+
+ /* warning, no return before setting back! */
+ if( (R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields) ) {
+ ibuf->rect+= (ibuf->x*ibuf->y);
+ }
+
+ ibuf_get_color(&texres->tr, ibuf, x, y);
+
+ if( (R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields) ) {
+ ibuf->rect-= (ibuf->x*ibuf->y);
+ }
+
+ if(tex->imaflag & TEX_USEALPHA) {
+ if(tex->imaflag & TEX_CALCALPHA);
+ else texres->talpha= 1;
+ }
+
+ if(texres->nor) {
+ if(tex->imaflag & TEX_NORMALMAP) {
+ // qdn: normal from color
+ texres->nor[0] = 2.f*(texres->tr - 0.5f);
+ texres->nor[1] = 2.f*(0.5f - texres->tg);
+ texres->nor[2] = 2.f*(texres->tb - 0.5f);
+ }
+ else {
+ /* bump: take three samples */
+ val1= texres->tr+texres->tg+texres->tb;
+
+ if(x<ibuf->x-1) {
+ float col[4];
+ ibuf_get_color(col, ibuf, x+1, y);
+ val2= (col[0]+col[1]+col[2]);
+ }
+ else val2= val1;
+
+ if(y<ibuf->y-1) {
+ float col[4];
+ ibuf_get_color(col, ibuf, x, y+1);
+ val3= (col[0]+col[1]+col[2]);
+ }
+ else val3= val1;
+
+ /* do not mix up x and y here! */
+ texres->nor[0]= (val1-val2);
+ texres->nor[1]= (val1-val3);
+ }
+ }
+
+ BRICONTRGB;
+
+ if(texres->talpha) texres->tin= texres->ta;
+ else if(tex->imaflag & TEX_CALCALPHA) {
+ texres->ta= texres->tin= MAX3(texres->tr, texres->tg, texres->tb);
+ }
+ else texres->ta= texres->tin= 1.0;
+
+ if(tex->flag & TEX_NEGALPHA) texres->ta= 1.0f-texres->ta;
+
+ return retval;
+}
+
+static void clipx_rctf_swap(rctf *stack, short *count, float x1, float x2)
+{
+ rctf *rf, *newrct;
+ short a;
+
+ a= *count;
+ rf= stack;
+ for(;a>0;a--) {
+ if(rf->xmin<x1) {
+ if(rf->xmax<x1) {
+ rf->xmin+= (x2-x1);
+ rf->xmax+= (x2-x1);
+ }
+ else {
+ if(rf->xmax>x2) rf->xmax= x2;
+ newrct= stack+ *count;
+ (*count)++;
+
+ newrct->xmax= x2;
+ newrct->xmin= rf->xmin+(x2-x1);
+ newrct->ymin= rf->ymin;
+ newrct->ymax= rf->ymax;
+
+ if(newrct->xmin==newrct->xmax) (*count)--;
+
+ rf->xmin= x1;
+ }
+ }
+ else if(rf->xmax>x2) {
+ if(rf->xmin>x2) {
+ rf->xmin-= (x2-x1);
+ rf->xmax-= (x2-x1);
+ }
+ else {
+ if(rf->xmin<x1) rf->xmin= x1;
+ newrct= stack+ *count;
+ (*count)++;
+
+ newrct->xmin= x1;
+ newrct->xmax= rf->xmax-(x2-x1);
+ newrct->ymin= rf->ymin;
+ newrct->ymax= rf->ymax;
+
+ if(newrct->xmin==newrct->xmax) (*count)--;
+
+ rf->xmax= x2;
+ }
+ }
+ rf++;
+ }
+
+}
+
+static void clipy_rctf_swap(rctf *stack, short *count, float y1, float y2)
+{
+ rctf *rf, *newrct;
+ short a;
+
+ a= *count;
+ rf= stack;
+ for(;a>0;a--) {
+ if(rf->ymin<y1) {
+ if(rf->ymax<y1) {
+ rf->ymin+= (y2-y1);
+ rf->ymax+= (y2-y1);
+ }
+ else {
+ if(rf->ymax>y2) rf->ymax= y2;
+ newrct= stack+ *count;
+ (*count)++;
+
+ newrct->ymax= y2;
+ newrct->ymin= rf->ymin+(y2-y1);
+ newrct->xmin= rf->xmin;
+ newrct->xmax= rf->xmax;
+
+ if(newrct->ymin==newrct->ymax) (*count)--;
+
+ rf->ymin= y1;
+ }
+ }
+ else if(rf->ymax>y2) {
+ if(rf->ymin>y2) {
+ rf->ymin-= (y2-y1);
+ rf->ymax-= (y2-y1);
+ }
+ else {
+ if(rf->ymin<y1) rf->ymin= y1;
+ newrct= stack+ *count;
+ (*count)++;
+
+ newrct->ymin= y1;
+ newrct->ymax= rf->ymax-(y2-y1);
+ newrct->xmin= rf->xmin;
+ newrct->xmax= rf->xmax;
+
+ if(newrct->ymin==newrct->ymax) (*count)--;
+
+ rf->ymax= y2;
+ }
+ }
+ rf++;
+ }
+}
+
+static float square_rctf(rctf *rf)
+{
+ float x, y;
+
+ x= rf->xmax- rf->xmin;
+ y= rf->ymax- rf->ymin;
+ return (x*y);
+}
+
+static float clipx_rctf(rctf *rf, float x1, float x2)
+{
+ float size;
+
+ size= rf->xmax - rf->xmin;
+
+ if(rf->xmin<x1) {
+ rf->xmin= x1;
+ }
+ if(rf->xmax>x2) {
+ rf->xmax= x2;
+ }
+ if(rf->xmin > rf->xmax) {
+ rf->xmin = rf->xmax;
+ return 0.0;
+ }
+ else if(size!=0.0) {
+ return (rf->xmax - rf->xmin)/size;
+ }
+ return 1.0;
+}
+
+static float clipy_rctf(rctf *rf, float y1, float y2)
+{
+ float size;
+
+ size= rf->ymax - rf->ymin;
+
+ if(rf->ymin<y1) {
+ rf->ymin= y1;
+ }
+ if(rf->ymax>y2) {
+ rf->ymax= y2;
+ }
+
+ if(rf->ymin > rf->ymax) {
+ rf->ymin = rf->ymax;
+ return 0.0;
+ }
+ else if(size!=0.0) {
+ return (rf->ymax - rf->ymin)/size;
+ }
+ return 1.0;
+
+}
+
+static void boxsampleclip(struct ImBuf *ibuf, rctf *rf, TexResult *texres)
+{
+ /* sample box, is clipped already, and minx etc. have been set at ibuf size.
+ Enlarge with antialiased edges of the pixels */
+
+ float muly, mulx, div, col[4];
+ int x, y, startx, endx, starty, endy;
+
+ startx= (int)floor(rf->xmin);
+ endx= (int)floor(rf->xmax);
+ starty= (int)floor(rf->ymin);
+ endy= (int)floor(rf->ymax);
+
+ if(startx < 0) startx= 0;
+ if(starty < 0) starty= 0;
+ if(endx>=ibuf->x) endx= ibuf->x-1;
+ if(endy>=ibuf->y) endy= ibuf->y-1;
+
+ if(starty==endy && startx==endx) {
+ ibuf_get_color(&texres->tr, ibuf, startx, starty);
+ }
+ else {
+ div= texres->tr= texres->tg= texres->tb= texres->ta= 0.0;
+ for(y=starty; y<=endy; y++) {
+
+ muly= 1.0;
+
+ if(starty==endy);
+ else {
+ if(y==starty) muly= 1.0f-(rf->ymin - y);
+ if(y==endy) muly= (rf->ymax - y);
+ }
+
+ if(startx==endx) {
+ mulx= muly;
+
+ ibuf_get_color(col, ibuf, startx, y);
+
+ texres->ta+= mulx*col[3];
+ texres->tr+= mulx*col[0];
+ texres->tg+= mulx*col[1];
+ texres->tb+= mulx*col[2];
+ div+= mulx;
+ }
+ else {
+ for(x=startx; x<=endx; x++) {
+ mulx= muly;
+ if(x==startx) mulx*= 1.0f-(rf->xmin - x);
+ if(x==endx) mulx*= (rf->xmax - x);
+
+ ibuf_get_color(col, ibuf, x, y);
+
+ if(mulx==1.0) {
+ texres->ta+= col[3];
+ texres->tr+= col[0];
+ texres->tg+= col[1];
+ texres->tb+= col[2];
+ div+= 1.0;
+ }
+ else {
+ texres->ta+= mulx*col[3];
+ texres->tr+= mulx*col[0];
+ texres->tg+= mulx*col[1];
+ texres->tb+= mulx*col[2];
+ div+= mulx;
+ }
+ }
+ }
+ }
+ if(div!=0.0) {
+ div= 1.0f/div;
+ texres->tb*= div;
+ texres->tg*= div;
+ texres->tr*= div;
+ texres->ta*= div;
+ }
+ else {
+ texres->tr= texres->tg= texres->tb= texres->ta= 0.0f;
+ }
+ }
+}
+
+static void boxsample(ImBuf *ibuf, float minx, float miny, float maxx, float maxy, TexResult *texres, int imaprepeat, int imapextend)
+{
+ /* Sample box, performs clip. minx etc are in range 0.0 - 1.0 .
+ * Enlarge with antialiased edges of pixels.
+ * If variable 'imaprepeat' has been set, the
+ * clipped-away parts are sampled as well.
+ */
+ /* note: actually minx etc isnt in the proper range... this due to filter size and offset vectors for bump */
+ TexResult texr;
+ rctf *rf, stack[8];
+ float opp, tot, alphaclip= 1.0;
+ short count=1;
+
+ rf= stack;
+ rf->xmin= minx*(ibuf->x);
+ rf->xmax= maxx*(ibuf->x);
+ rf->ymin= miny*(ibuf->y);
+ rf->ymax= maxy*(ibuf->y);
+
+ texr.talpha= texres->talpha; /* is read by boxsample_clip */
+
+ if(imapextend) {
+ CLAMP(rf->xmin, 0.0f, ibuf->x-1);
+ CLAMP(rf->xmax, 0.0f, ibuf->x-1);
+ }
+ else if(imaprepeat)
+ clipx_rctf_swap(stack, &count, 0.0, (float)(ibuf->x));
+ else {
+ alphaclip= clipx_rctf(rf, 0.0, (float)(ibuf->x));
+
+ if(alphaclip<=0.0) {
+ texres->tr= texres->tb= texres->tg= texres->ta= 0.0;
+ return;
+ }
+ }
+
+ if(imapextend) {
+ CLAMP(rf->ymin, 0.0f, ibuf->y-1);
+ CLAMP(rf->ymax, 0.0f, ibuf->y-1);
+ }
+ else if(imaprepeat)
+ clipy_rctf_swap(stack, &count, 0.0, (float)(ibuf->y));
+ else {
+ alphaclip*= clipy_rctf(rf, 0.0, (float)(ibuf->y));
+
+ if(alphaclip<=0.0) {
+ texres->tr= texres->tb= texres->tg= texres->ta= 0.0;
+ return;
+ }
+ }
+
+ if(count>1) {
+ tot= texres->tr= texres->tb= texres->tg= texres->ta= 0.0;
+ while(count--) {
+ boxsampleclip(ibuf, rf, &texr);
+
+ opp= square_rctf(rf);
+ tot+= opp;
+
+ texres->tr+= opp*texr.tr;
+ texres->tg+= opp*texr.tg;
+ texres->tb+= opp*texr.tb;
+ if(texres->talpha) texres->ta+= opp*texr.ta;
+ rf++;
+ }
+ if(tot!= 0.0) {
+ texres->tr/= tot;
+ texres->tg/= tot;
+ texres->tb/= tot;
+ if(texres->talpha) texres->ta/= tot;
+ }
+ }
+ else {
+ boxsampleclip(ibuf, rf, texres);
+ }
+
+ if(texres->talpha==0) texres->ta= 1.0;
+
+ if(alphaclip!=1.0) {
+ /* this is for later investigation, premul or not? */
+ /* texres->tr*= alphaclip; */
+ /* texres->tg*= alphaclip; */
+ /* texres->tb*= alphaclip; */
+ texres->ta*= alphaclip;
+ }
+}
+
+void image_sample(Image *ima, float fx, float fy, float dx, float dy, float *result)
+{
+ TexResult texres;
+ ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL);
+
+ if(ibuf==NULL) {
+ result[0]= result[1]= result[2]= result[3]= 0.0f;
+ return;
+ }
+
+ if( (R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields) )
+ ibuf->rect+= (ibuf->x*ibuf->y);
+
+ boxsample(ibuf, fx, fy, fx+dx, fy+dy, &texres, 0, 1);
+ result[0]= texres.tr;
+ result[1]= texres.tg;
+ result[2]= texres.tb;
+ result[3]= texres.ta;
+
+ if( (R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields) )
+ ibuf->rect-= (ibuf->x*ibuf->y);
+}
+
+void ibuf_sample(ImBuf *ibuf, float fx, float fy, float dx, float dy, float *result)
+{
+ TexResult texres;
+
+ if(ibuf==NULL) {
+ return;
+ }
+
+ boxsample(ibuf, fx, fy, fx+dx, fy+dy, &texres, 0, 1);
+ result[0]= texres.tr;
+ result[1]= texres.tg;
+ result[2]= texres.tb;
+ result[3]= texres.ta;
+}
+
+
+
+int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, float *texvec, float *dxt, float *dyt, TexResult *texres)
+{
+ TexResult texr;
+ float fx, fy, minx, maxx, miny, maxy, dx, dy;
+ float maxd, pixsize, val1, val2, val3;
+ int curmap, retval, imaprepeat, imapextend;
+
+ texres->tin= texres->ta= texres->tr= texres->tg= texres->tb= 0.0f;
+
+ /* we need to set retval OK, otherwise texture code generates normals itself... */
+ retval= texres->nor?3:1;
+
+ /* quick tests */
+ if(ibuf==NULL && ima==NULL)
+ return retval;
+ if(ima) {
+
+ /* hack for icon render */
+ if(ima->ibufs.first==NULL && (R.r.scemode & R_NO_IMAGE_LOAD))
+ return retval;
+
+ ibuf= BKE_image_get_ibuf(ima, &tex->iuser);
+ }
+ if(ibuf==NULL || (ibuf->rect==NULL && ibuf->rect_float==NULL))
+ return retval;
+
+ /* mipmap test */
+ if(tex->imaflag & TEX_MIPMAP) {
+ if(ibuf->flags & IB_fields);
+ else if(ibuf->mipmap[0]==NULL) {
+ BLI_lock_thread(LOCK_IMAGE);
+
+ if(ibuf->mipmap[0]==NULL)
+ IMB_makemipmap(ibuf, tex->imaflag & TEX_GAUSS_MIP);
+
+ BLI_unlock_thread(LOCK_IMAGE);
+ }
+ }
+
+ if(tex->imaflag & TEX_USEALPHA) {
+ if(tex->imaflag & TEX_CALCALPHA);
+ else texres->talpha= 1;
+ }
+
+ texr.talpha= texres->talpha;
+
+ if(tex->imaflag & TEX_IMAROT) {
+ fy= texvec[0];
+ fx= texvec[1];
+ }
+ else {
+ fx= texvec[0];
+ fy= texvec[1];
+ }
+
+ if(ibuf->flags & IB_fields) {
+ if(R.r.mode & R_FIELDS) { /* field render */
+ if(R.flag & R_SEC_FIELD) { /* correction for 2nd field */
+ /* fac1= 0.5/( (float)ibuf->y ); */
+ /* fy-= fac1; */
+ }
+ else { /* first field */
+ fy+= 0.5f/( (float)ibuf->y );
+ }
+ }
+ }
+
+ /* pixel coordinates */
+
+ minx= MIN3(dxt[0],dyt[0],dxt[0]+dyt[0] );
+ maxx= MAX3(dxt[0],dyt[0],dxt[0]+dyt[0] );
+ miny= MIN3(dxt[1],dyt[1],dxt[1]+dyt[1] );
+ maxy= MAX3(dxt[1],dyt[1],dxt[1]+dyt[1] );
+
+ /* tex_sharper has been removed */
+ minx= tex->filtersize*(maxx-minx)/2.0f;
+ miny= tex->filtersize*(maxy-miny)/2.0f;
+
+ if(tex->filtersize!=1.0f) {
+ dxt[0]*= tex->filtersize;
+ dxt[1]*= tex->filtersize;
+ dyt[0]*= tex->filtersize;
+ dyt[1]*= tex->filtersize;
+ }
+
+ if(tex->imaflag & TEX_IMAROT) SWAP(float, minx, miny);
+
+ if(minx>0.25) minx= 0.25;
+ else if(minx<0.00001f) minx= 0.00001f; /* side faces of unit-cube */
+ if(miny>0.25) miny= 0.25;
+ else if(miny<0.00001f) miny= 0.00001f;
+
+
+ /* repeat and clip */
+ imaprepeat= (tex->extend==TEX_REPEAT);
+ imapextend= (tex->extend==TEX_EXTEND);
+
+ if(tex->extend == TEX_REPEAT) {
+ if(tex->flag & (TEX_REPEAT_XMIR|TEX_REPEAT_YMIR)) {
+ imaprepeat= 0;
+ imapextend= 1;
+ }
+ }
+
+ if(tex->extend == TEX_CHECKER) {
+ int xs, ys, xs1, ys1, xs2, ys2, boundary;
+
+ xs= (int)floor(fx);
+ ys= (int)floor(fy);
+
+ // both checkers available, no boundary exceptions, checkerdist will eat aliasing
+ if( (tex->flag & TEX_CHECKER_ODD) && (tex->flag & TEX_CHECKER_EVEN) ) {
+ fx-= xs;
+ fy-= ys;
+ }
+ else {
+
+ xs1= (int)floor(fx-minx);
+ ys1= (int)floor(fy-miny);
+ xs2= (int)floor(fx+minx);
+ ys2= (int)floor(fy+miny);
+ boundary= (xs1!=xs2) || (ys1!=ys2);
+
+ if(boundary==0) {
+ if( (tex->flag & TEX_CHECKER_ODD)==0) {
+ if((xs+ys) & 1);
+ else return retval;
+ }
+ if( (tex->flag & TEX_CHECKER_EVEN)==0) {
+ if((xs+ys) & 1) return retval;
+ }
+ fx-= xs;
+ fy-= ys;
+ }
+ else {
+ if(tex->flag & TEX_CHECKER_ODD) {
+ if((xs1+ys) & 1) fx-= xs2;
+ else fx-= xs1;
+
+ if((ys1+xs) & 1) fy-= ys2;
+ else fy-= ys1;
+ }
+ if(tex->flag & TEX_CHECKER_EVEN) {
+ if((xs1+ys) & 1) fx-= xs1;
+ else fx-= xs2;
+
+ if((ys1+xs) & 1) fy-= ys1;
+ else fy-= ys2;
+ }
+ }
+ }
+
+ /* scale around center, (0.5, 0.5) */
+ if(tex->checkerdist<1.0) {
+ fx= (fx-0.5)/(1.0-tex->checkerdist) +0.5;
+ fy= (fy-0.5)/(1.0-tex->checkerdist) +0.5;
+ minx/= (1.0-tex->checkerdist);
+ miny/= (1.0-tex->checkerdist);
+ }
+ }
+
+ if(tex->extend == TEX_CLIPCUBE) {
+ if(fx+minx<0.0 || fy+miny<0.0 || fx-minx>1.0 || fy-miny>1.0 || texvec[2]<-1.0 || texvec[2]>1.0) {
+ return retval;
+ }
+ }
+ else if(tex->extend==TEX_CLIP || tex->extend==TEX_CHECKER) {
+ if(fx+minx<0.0 || fy+miny<0.0 || fx-minx>1.0 || fy-miny>1.0) {
+ return retval;
+ }
+ }
+ else {
+ if(imapextend) {
+ if(fx>1.0) fx = 1.0;
+ else if(fx<0.0) fx= 0.0;
+ }
+ else {
+ if(fx>1.0) fx -= (int)(fx);
+ else if(fx<0.0) fx+= 1-(int)(fx);
+ }
+
+ if(imapextend) {
+ if(fy>1.0) fy = 1.0;
+ else if(fy<0.0) fy= 0.0;
+ }
+ else {
+ if(fy>1.0) fy -= (int)(fy);
+ else if(fy<0.0) fy+= 1-(int)(fy);
+ }
+ }
+
+ /* warning no return! */
+ if( (R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields) ) {
+ ibuf->rect+= (ibuf->x*ibuf->y);
+ }
+
+ /* choice: */
+ if(tex->imaflag & TEX_MIPMAP) {
+ ImBuf *previbuf, *curibuf;
+ float bumpscale;
+
+ dx= minx;
+ dy= miny;
+ maxd= MAX2(dx, dy);
+ if(maxd>0.5) maxd= 0.5;
+
+ pixsize = 1.0f/ (float) MIN2(ibuf->x, ibuf->y);
+
+ bumpscale= pixsize/maxd;
+ if(bumpscale>1.0f) bumpscale= 1.0f;
+ else bumpscale*=bumpscale;
+
+ curmap= 0;
+ previbuf= curibuf= ibuf;
+ while(curmap<IB_MIPMAP_LEVELS && ibuf->mipmap[curmap]) {
+ if(maxd < pixsize) break;
+ previbuf= curibuf;
+ curibuf= ibuf->mipmap[curmap];
+ pixsize= 1.0f / (float)MIN2(curibuf->x, curibuf->y);
+ curmap++;
+ }
+
+ if(previbuf!=curibuf || (tex->imaflag & TEX_INTERPOL)) {
+ /* sample at least 1 pixel */
+ if (minx < 0.5f / ibuf->x) minx = 0.5f / ibuf->x;
+ if (miny < 0.5f / ibuf->y) miny = 0.5f / ibuf->y;
+ }
+
+ if(texres->nor && (tex->imaflag & TEX_NORMALMAP)==0) {
+ /* a bit extra filter */
+ //minx*= 1.35f;
+ //miny*= 1.35f;
+
+ boxsample(curibuf, fx-minx, fy-miny, fx+minx, fy+miny, texres, imaprepeat, imapextend);
+ val1= texres->tr+texres->tg+texres->tb;
+ boxsample(curibuf, fx-minx+dxt[0], fy-miny+dxt[1], fx+minx+dxt[0], fy+miny+dxt[1], &texr, imaprepeat, imapextend);
+ val2= texr.tr + texr.tg + texr.tb;
+ boxsample(curibuf, fx-minx+dyt[0], fy-miny+dyt[1], fx+minx+dyt[0], fy+miny+dyt[1], &texr, imaprepeat, imapextend);
+ val3= texr.tr + texr.tg + texr.tb;
+
+ /* don't switch x or y! */
+ texres->nor[0]= (val1-val2);
+ texres->nor[1]= (val1-val3);
+
+ if(previbuf!=curibuf) { /* interpolate */
+
+ boxsample(previbuf, fx-minx, fy-miny, fx+minx, fy+miny, &texr, imaprepeat, imapextend);
+
+ /* calc rgb */
+ dx= 2.0f*(pixsize-maxd)/pixsize;
+ if(dx>=1.0f) {
+ texres->ta= texr.ta; texres->tb= texr.tb;
+ texres->tg= texr.tg; texres->tr= texr.tr;
+ }
+ else {
+ dy= 1.0f-dx;
+ texres->tb= dy*texres->tb+ dx*texr.tb;
+ texres->tg= dy*texres->tg+ dx*texr.tg;
+ texres->tr= dy*texres->tr+ dx*texr.tr;
+ texres->ta= dy*texres->ta+ dx*texr.ta;
+ }
+
+ val1= dy*val1+ dx*(texr.tr + texr.tg + texr.tb);
+ boxsample(previbuf, fx-minx+dxt[0], fy-miny+dxt[1], fx+minx+dxt[0], fy+miny+dxt[1], &texr, imaprepeat, imapextend);
+ val2= dy*val2+ dx*(texr.tr + texr.tg + texr.tb);
+ boxsample(previbuf, fx-minx+dyt[0], fy-miny+dyt[1], fx+minx+dyt[0], fy+miny+dyt[1], &texr, imaprepeat, imapextend);
+ val3= dy*val3+ dx*(texr.tr + texr.tg + texr.tb);
+
+ texres->nor[0]= (val1-val2); /* vals have been interpolated above! */
+ texres->nor[1]= (val1-val3);
+
+ if(dx<1.0f) {
+ dy= 1.0f-dx;
+ texres->tb= dy*texres->tb+ dx*texr.tb;
+ texres->tg= dy*texres->tg+ dx*texr.tg;
+ texres->tr= dy*texres->tr+ dx*texr.tr;
+ texres->ta= dy*texres->ta+ dx*texr.ta;
+ }
+ }
+ texres->nor[0]*= bumpscale;
+ texres->nor[1]*= bumpscale;
+ }
+ else {
+ maxx= fx+minx;
+ minx= fx-minx;
+ maxy= fy+miny;
+ miny= fy-miny;
+
+ boxsample(curibuf, minx, miny, maxx, maxy, texres, imaprepeat, imapextend);
+
+ if(previbuf!=curibuf) { /* interpolate */
+ boxsample(previbuf, minx, miny, maxx, maxy, &texr, imaprepeat, imapextend);
+
+ fx= 2.0f*(pixsize-maxd)/pixsize;
+
+ if(fx>=1.0) {
+ texres->ta= texr.ta; texres->tb= texr.tb;
+ texres->tg= texr.tg; texres->tr= texr.tr;
+ } else {
+ fy= 1.0f-fx;
+ texres->tb= fy*texres->tb+ fx*texr.tb;
+ texres->tg= fy*texres->tg+ fx*texr.tg;
+ texres->tr= fy*texres->tr+ fx*texr.tr;
+ texres->ta= fy*texres->ta+ fx*texr.ta;
+ }
+ }
+ }
+ }
+ else {
+ if((tex->imaflag & TEX_INTERPOL)) {
+ /* sample 1 pixel minimum */
+ if (minx < 0.5f / ibuf->x) minx = 0.5f / ibuf->x;
+ if (miny < 0.5f / ibuf->y) miny = 0.5f / ibuf->y;
+ }
+
+ if(texres->nor && (tex->imaflag & TEX_NORMALMAP)==0) {
+
+ boxsample(ibuf, fx-minx, fy-miny, fx+minx, fy+miny, texres, imaprepeat, imapextend);
+ val1= texres->tr+texres->tg+texres->tb;
+ boxsample(ibuf, fx-minx+dxt[0], fy-miny+dxt[1], fx+minx+dxt[0], fy+miny+dxt[1], &texr, imaprepeat, imapextend);
+ val2= texr.tr + texr.tg + texr.tb;
+ boxsample(ibuf, fx-minx+dyt[0], fy-miny+dyt[1], fx+minx+dyt[0], fy+miny+dyt[1], &texr, imaprepeat, imapextend);
+ val3= texr.tr + texr.tg + texr.tb;
+ /* don't switch x or y! */
+ texres->nor[0]= (val1-val2);
+ texres->nor[1]= (val1-val3);
+ }
+ else {
+ boxsample(ibuf, fx-minx, fy-miny, fx+minx, fy+miny, texres, imaprepeat, imapextend);
+ }
+ }
+
+ BRICONTRGB;
+
+ if(tex->imaflag & TEX_CALCALPHA) {
+ texres->ta= texres->tin= texres->ta*MAX3(texres->tr, texres->tg, texres->tb);
+ }
+ else texres->tin= texres->ta;
+
+ if(tex->flag & TEX_NEGALPHA) texres->ta= 1.0f-texres->ta;
+
+ if( (R.flag & R_SEC_FIELD) && (ibuf->flags & IB_fields) ) {
+ ibuf->rect-= (ibuf->x*ibuf->y);
+ }
+
+ if(texres->nor && (tex->imaflag & TEX_NORMALMAP)) {
+ // qdn: normal from color
+ texres->nor[0] = 2.f*(texres->tr - 0.5f);
+ texres->nor[1] = 2.f*(0.5f - texres->tg);
+ texres->nor[2] = 2.f*(texres->tb - 0.5f);
+ }
+
+ return retval;
+}
diff --git a/source/blender/render/intern/source/initrender.c b/source/blender/render/intern/source/initrender.c
new file mode 100644
index 00000000000..83c0be6283b
--- /dev/null
+++ b/source/blender/render/intern/source/initrender.c
@@ -0,0 +1,680 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributors: 2004/2005/2006 Blender Foundation, full recode
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+
+/* Global includes */
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "PIL_time.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+#include "BLI_jitter.h"
+
+#include "MTC_matrixops.h"
+
+#include "DNA_camera_types.h"
+#include "DNA_group_types.h"
+#include "DNA_image_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_global.h"
+#include "BKE_material.h"
+#include "BKE_object.h"
+#include "BKE_image.h"
+#include "BKE_ipo.h"
+#include "BKE_key.h"
+#include "BKE_action.h"
+#include "BKE_writeavi.h"
+#include "BKE_scene.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#ifdef WITH_QUICKTIME
+#include "quicktime_export.h"
+#endif
+
+/* this module */
+#include "renderpipeline.h"
+#include "render_types.h"
+
+#include "rendercore.h"
+#include "pixelshading.h"
+#include "zbuf.h"
+
+/* Own includes */
+#include "initrender.h"
+
+
+/* ********************** */
+
+static void init_render_jit(Render *re)
+{
+ static float jit[32][2]; /* simple caching */
+ static int lastjit= 0;
+
+ if(lastjit!=re->r.osa) {
+ memset(jit, 0, sizeof(jit));
+ BLI_initjit(jit[0], re->r.osa);
+ }
+
+ lastjit= re->r.osa;
+ memcpy(re->jit, jit, sizeof(jit));
+}
+
+
+/* ****************** MASKS and LUTS **************** */
+
+static float filt_quadratic(float x)
+{
+ if (x < 0.0f) x = -x;
+ if (x < 0.5f) return 0.75f-(x*x);
+ if (x < 1.5f) return 0.50f*(x-1.5f)*(x-1.5f);
+ return 0.0f;
+}
+
+
+static float filt_cubic(float x)
+{
+ float x2= x*x;
+
+ if (x < 0.0f) x = -x;
+
+ if (x < 1.0f) return 0.5*x*x2 - x2 + 2.0f/3.0f;
+ if (x < 2.0f) return (2.0-x)*(2.0-x)*(2.0-x)/6.0f;
+ return 0.0f;
+}
+
+
+static float filt_catrom(float x)
+{
+ float x2= x*x;
+
+ if (x < 0.0f) x = -x;
+ if (x < 1.0f) return 1.5f*x2*x - 2.5f*x2 + 1.0f;
+ if (x < 2.0f) return -0.5f*x2*x + 2.5*x2 - 4.0f*x + 2.0f;
+ return 0.0f;
+}
+
+static float filt_mitchell(float x) /* Mitchell & Netravali's two-param cubic */
+{
+ float b = 1.0f/3.0f, c = 1.0f/3.0f;
+ float p0 = ( 6.0 - 2.0*b ) / 6.0;
+ float p2 = (-18.0 + 12.0*b + 6.0*c) / 6.0;
+ float p3 = ( 12.0 - 9.0*b - 6.0*c) / 6.0;
+ float q0 = ( 8.0*b + 24.0*c) / 6.0;
+ float q1 = ( - 12.0*b - 48.0*c) / 6.0;
+ float q2 = ( 6.0*b + 30.0*c) / 6.0;
+ float q3 = ( - b - 6.0*c) / 6.0;
+
+ if (x<-2.0) return 0.0;
+ if (x<-1.0) return (q0-x*(q1-x*(q2-x*q3)));
+ if (x< 0.0) return (p0+x*x*(p2-x*p3));
+ if (x< 1.0) return (p0+x*x*(p2+x*p3));
+ if (x< 2.0) return (q0+x*(q1+x*(q2+x*q3)));
+ return 0.0;
+}
+
+/* x ranges from -1 to 1 */
+float RE_filter_value(int type, float x)
+{
+ float gaussfac= 1.6f;
+
+ x= ABS(x);
+
+ switch(type) {
+ case R_FILTER_BOX:
+ if(x>1.0) return 0.0f;
+ return 1.0;
+
+ case R_FILTER_TENT:
+ if(x>1.0) return 0.0f;
+ return 1.0f-x;
+
+ case R_FILTER_GAUSS:
+ x*= gaussfac;
+ return (1.0/exp(x*x) - 1.0/exp(gaussfac*gaussfac*2.25));
+
+ case R_FILTER_MITCH:
+ return filt_mitchell(x*gaussfac);
+
+ case R_FILTER_QUAD:
+ return filt_quadratic(x*gaussfac);
+
+ case R_FILTER_CUBIC:
+ return filt_cubic(x*gaussfac);
+
+ case R_FILTER_CATROM:
+ return filt_catrom(x*gaussfac);
+ }
+ return 0.0f;
+}
+
+static float calc_weight(Render *re, float *weight, int i, int j)
+{
+ float x, y, dist, totw= 0.0;
+ int a;
+
+ for(a=0; a<re->osa; a++) {
+ x= re->jit[a][0] + i;
+ y= re->jit[a][1] + j;
+ dist= sqrt(x*x+y*y);
+
+ weight[a]= 0.0;
+
+ /* Weighting choices */
+ switch(re->r.filtertype) {
+ case R_FILTER_BOX:
+ if(i==0 && j==0) weight[a]= 1.0;
+ break;
+
+ case R_FILTER_TENT:
+ if(dist < re->r.gauss)
+ weight[a]= re->r.gauss - dist;
+ break;
+
+ case R_FILTER_GAUSS:
+ x = dist*re->r.gauss;
+ weight[a]= (1.0/exp(x*x) - 1.0/exp(re->r.gauss*re->r.gauss*2.25));
+ break;
+
+ case R_FILTER_MITCH:
+ weight[a]= filt_mitchell(dist*re->r.gauss);
+ break;
+
+ case R_FILTER_QUAD:
+ weight[a]= filt_quadratic(dist*re->r.gauss);
+ break;
+
+ case R_FILTER_CUBIC:
+ weight[a]= filt_cubic(dist*re->r.gauss);
+ break;
+
+ case R_FILTER_CATROM:
+ weight[a]= filt_catrom(dist*re->r.gauss);
+ break;
+
+ }
+
+ totw+= weight[a];
+
+ }
+ return totw;
+}
+
+void free_sample_tables(Render *re)
+{
+ int a;
+
+ if(re->samples) {
+ for(a=0; a<9; a++) {
+ MEM_freeN(re->samples->fmask1[a]);
+ MEM_freeN(re->samples->fmask2[a]);
+ }
+
+ MEM_freeN(re->samples->centmask);
+ MEM_freeN(re->samples);
+ re->samples= NULL;
+ }
+}
+
+/* based on settings in render, it makes the lookup tables */
+void make_sample_tables(Render *re)
+{
+ static int firsttime= 1;
+ SampleTables *st;
+ float flweight[32], fmask[256];
+ float weight[32], totw, val, *fpx1, *fpx2, *fpy1, *fpy2, *m3, *m4;
+ int i, j, a;
+
+ /* optimization tables, only once */
+ if(firsttime) {
+ firsttime= 0;
+ }
+
+ free_sample_tables(re);
+
+ init_render_jit(re); /* needed for mblur too */
+
+ if(re->osa==0) {
+ /* just prevents cpu cycles for larger render and copying */
+ re->r.filtertype= 0;
+ return;
+ }
+
+ st= re->samples= MEM_callocN(sizeof(SampleTables), "sample tables");
+
+ for(a=0; a<9;a++) {
+ st->fmask1[a]= MEM_callocN(256*sizeof(float), "initfilt");
+ st->fmask2[a]= MEM_callocN(256*sizeof(float), "initfilt");
+ }
+ for(a=0; a<256; a++) {
+ st->cmask[a]= 0;
+ if(a & 1) st->cmask[a]++;
+ if(a & 2) st->cmask[a]++;
+ if(a & 4) st->cmask[a]++;
+ if(a & 8) st->cmask[a]++;
+ if(a & 16) st->cmask[a]++;
+ if(a & 32) st->cmask[a]++;
+ if(a & 64) st->cmask[a]++;
+ if(a & 128) st->cmask[a]++;
+ }
+
+ st->centmask= MEM_mallocN((1<<re->osa), "Initfilt3");
+
+ for(a=0; a<16; a++) {
+ st->centLut[a]= -0.45+((float)a)/16.0;
+ }
+
+ val= 1.0/((float)re->osa);
+ for(a=0; a<256; a++) {
+ fmask[a]= ((float)st->cmask[a])*val;
+ }
+
+ /* calculate totw */
+ totw= 0.0;
+ for(j= -1; j<2; j++) {
+ for(i= -1; i<2; i++) {
+ totw+= calc_weight(re, weight, i, j);
+ }
+ }
+
+ for(j= -1; j<2; j++) {
+ for(i= -1; i<2; i++) {
+ /* calculate using jit, with offset the weights */
+
+ memset(weight, 0, sizeof(weight));
+ calc_weight(re, weight, i, j);
+
+ for(a=0; a<16; a++) flweight[a]= weight[a]*(1.0/totw);
+
+ m3= st->fmask1[ 3*(j+1)+i+1 ];
+ m4= st->fmask2[ 3*(j+1)+i+1 ];
+
+ for(a=0; a<256; a++) {
+ if(a & 1) {
+ m3[a]+= flweight[0];
+ m4[a]+= flweight[8];
+ }
+ if(a & 2) {
+ m3[a]+= flweight[1];
+ m4[a]+= flweight[9];
+ }
+ if(a & 4) {
+ m3[a]+= flweight[2];
+ m4[a]+= flweight[10];
+ }
+ if(a & 8) {
+ m3[a]+= flweight[3];
+ m4[a]+= flweight[11];
+ }
+ if(a & 16) {
+ m3[a]+= flweight[4];
+ m4[a]+= flweight[12];
+ }
+ if(a & 32) {
+ m3[a]+= flweight[5];
+ m4[a]+= flweight[13];
+ }
+ if(a & 64) {
+ m3[a]+= flweight[6];
+ m4[a]+= flweight[14];
+ }
+ if(a & 128) {
+ m3[a]+= flweight[7];
+ m4[a]+= flweight[15];
+ }
+ }
+ }
+ }
+
+ /* centmask: the correct subpixel offset per mask */
+
+ fpx1= MEM_mallocN(256*sizeof(float), "initgauss4");
+ fpx2= MEM_mallocN(256*sizeof(float), "initgauss4");
+ fpy1= MEM_mallocN(256*sizeof(float), "initgauss4");
+ fpy2= MEM_mallocN(256*sizeof(float), "initgauss4");
+ for(a=0; a<256; a++) {
+ fpx1[a]= fpx2[a]= 0.0;
+ fpy1[a]= fpy2[a]= 0.0;
+ if(a & 1) {
+ fpx1[a]+= re->jit[0][0];
+ fpy1[a]+= re->jit[0][1];
+ fpx2[a]+= re->jit[8][0];
+ fpy2[a]+= re->jit[8][1];
+ }
+ if(a & 2) {
+ fpx1[a]+= re->jit[1][0];
+ fpy1[a]+= re->jit[1][1];
+ fpx2[a]+= re->jit[9][0];
+ fpy2[a]+= re->jit[9][1];
+ }
+ if(a & 4) {
+ fpx1[a]+= re->jit[2][0];
+ fpy1[a]+= re->jit[2][1];
+ fpx2[a]+= re->jit[10][0];
+ fpy2[a]+= re->jit[10][1];
+ }
+ if(a & 8) {
+ fpx1[a]+= re->jit[3][0];
+ fpy1[a]+= re->jit[3][1];
+ fpx2[a]+= re->jit[11][0];
+ fpy2[a]+= re->jit[11][1];
+ }
+ if(a & 16) {
+ fpx1[a]+= re->jit[4][0];
+ fpy1[a]+= re->jit[4][1];
+ fpx2[a]+= re->jit[12][0];
+ fpy2[a]+= re->jit[12][1];
+ }
+ if(a & 32) {
+ fpx1[a]+= re->jit[5][0];
+ fpy1[a]+= re->jit[5][1];
+ fpx2[a]+= re->jit[13][0];
+ fpy2[a]+= re->jit[13][1];
+ }
+ if(a & 64) {
+ fpx1[a]+= re->jit[6][0];
+ fpy1[a]+= re->jit[6][1];
+ fpx2[a]+= re->jit[14][0];
+ fpy2[a]+= re->jit[14][1];
+ }
+ if(a & 128) {
+ fpx1[a]+= re->jit[7][0];
+ fpy1[a]+= re->jit[7][1];
+ fpx2[a]+= re->jit[15][0];
+ fpy2[a]+= re->jit[15][1];
+ }
+ }
+
+ for(a= (1<<re->osa)-1; a>0; a--) {
+ val= st->cmask[a & 255] + st->cmask[a>>8];
+ i= 8+(15.9*(fpy1[a & 255]+fpy2[a>>8])/val);
+ CLAMP(i, 0, 15);
+ j= 8+(15.9*(fpx1[a & 255]+fpx2[a>>8])/val);
+ CLAMP(j, 0, 15);
+ i= j + (i<<4);
+ st->centmask[a]= i;
+ }
+
+ MEM_freeN(fpx1);
+ MEM_freeN(fpx2);
+ MEM_freeN(fpy1);
+ MEM_freeN(fpy2);
+}
+
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* call this after InitState() */
+/* per render, there's one persistant viewplane. Parts will set their own viewplanes */
+void RE_SetCamera(Render *re, Object *camera)
+{
+ Camera *cam=NULL;
+ rctf viewplane;
+ float pixsize, clipsta, clipend;
+ float lens, shiftx=0.0, shifty=0.0, winside;
+
+ /* question mark */
+ re->ycor= ( (float)re->r.yasp)/( (float)re->r.xasp);
+ if(re->r.mode & R_FIELDS)
+ re->ycor *= 2.0f;
+
+ if(camera->type==OB_CAMERA) {
+ cam= camera->data;
+
+ if(cam->type==CAM_ORTHO) re->r.mode |= R_ORTHO;
+
+ /* solve this too... all time depending stuff is in convertblender.c? */
+ if(cam->ipo) {
+ calc_ipo(cam->ipo, frame_to_float(re->r.cfra));
+ execute_ipo(&cam->id, cam->ipo);
+ }
+ lens= cam->lens;
+ shiftx=cam->shiftx;
+ shifty=cam->shifty;
+
+ clipsta= cam->clipsta;
+ clipend= cam->clipend;
+ }
+ else if(camera->type==OB_LAMP) {
+ Lamp *la= camera->data;
+ float fac= cos( M_PI*la->spotsize/360.0 );
+ float phi= acos(fac);
+
+ lens= 16.0*fac/sin(phi);
+ if(lens==0.0f)
+ lens= 35.0;
+ clipsta= la->clipsta;
+ clipend= la->clipend;
+ }
+ else { /* envmap exception... */
+ lens= re->lens;
+ if(lens==0.0f)
+ lens= 16.0;
+
+ clipsta= re->clipsta;
+ clipend= re->clipend;
+ if(clipsta==0.0f || clipend==0.0f) {
+ clipsta= 0.1f;
+ clipend= 1000.0f;
+ }
+ }
+
+ /* ortho only with camera available */
+ if(cam && (re->r.mode & R_ORTHO)) {
+ if( (re->r.xasp*re->winx) >= (re->r.yasp*re->winy) ) {
+ re->viewfac= re->winx;
+ }
+ else {
+ re->viewfac= re->ycor*re->winy;
+ }
+ /* ortho_scale == 1.0 means exact 1 to 1 mapping */
+ pixsize= cam->ortho_scale/re->viewfac;
+ }
+ else {
+ if( (re->r.xasp*re->winx) >= (re->r.yasp*re->winy) ) {
+ re->viewfac= (re->winx*lens)/32.0;
+ }
+ else {
+ re->viewfac= re->ycor*(re->winy*lens)/32.0;
+ }
+
+ pixsize= clipsta/re->viewfac;
+ }
+
+ /* viewplane fully centered, zbuffer fills in jittered between -.5 and +.5 */
+ winside= MAX2(re->winx, re->winy);
+ viewplane.xmin= -0.5f*(float)re->winx + shiftx*winside;
+ viewplane.ymin= -0.5f*re->ycor*(float)re->winy + shifty*winside;
+ viewplane.xmax= 0.5f*(float)re->winx + shiftx*winside;
+ viewplane.ymax= 0.5f*re->ycor*(float)re->winy + shifty*winside;
+
+ if(re->flag & R_SEC_FIELD) {
+ if(re->r.mode & R_ODDFIELD) {
+ viewplane.ymin-= .5*re->ycor;
+ viewplane.ymax-= .5*re->ycor;
+ }
+ else {
+ viewplane.ymin+= .5*re->ycor;
+ viewplane.ymax+= .5*re->ycor;
+ }
+ }
+ /* the window matrix is used for clipping, and not changed during OSA steps */
+ /* using an offset of +0.5 here would give clip errors on edges */
+ viewplane.xmin= pixsize*(viewplane.xmin);
+ viewplane.xmax= pixsize*(viewplane.xmax);
+ viewplane.ymin= pixsize*(viewplane.ymin);
+ viewplane.ymax= pixsize*(viewplane.ymax);
+
+ re->viewdx= pixsize;
+ re->viewdy= re->ycor*pixsize;
+
+ if(re->r.mode & R_ORTHO)
+ RE_SetOrtho(re, &viewplane, clipsta, clipend);
+ else
+ RE_SetWindow(re, &viewplane, clipsta, clipend);
+
+}
+
+void RE_SetPixelSize(Render *re, float pixsize)
+{
+ re->viewdx= pixsize;
+ re->viewdy= re->ycor*pixsize;
+}
+
+/* ~~~~~~~~~~~~~~~~ part (tile) calculus ~~~~~~~~~~~~~~~~~~~~~~ */
+
+
+void freeparts(Render *re)
+{
+ RenderPart *part= re->parts.first;
+
+ while(part) {
+ if(part->rectp) MEM_freeN(part->rectp);
+ if(part->rectz) MEM_freeN(part->rectz);
+ part= part->next;
+ }
+ BLI_freelistN(&re->parts);
+}
+
+void initparts(Render *re)
+{
+ int nr, xd, yd, partx, party, xparts, yparts;
+ int xminb, xmaxb, yminb, ymaxb;
+
+ freeparts(re);
+
+ /* this is render info for caller, is not reset when parts are freed! */
+ re->i.totpart= 0;
+ re->i.curpart= 0;
+ re->i.partsdone= 0;
+
+ /* just for readable code.. */
+ xminb= re->disprect.xmin;
+ yminb= re->disprect.ymin;
+ xmaxb= re->disprect.xmax;
+ ymaxb= re->disprect.ymax;
+
+ xparts= re->r.xparts;
+ yparts= re->r.yparts;
+
+ /* mininum part size, but for exr tile saving it was checked already */
+ if(!(re->r.scemode & R_EXR_TILE_FILE)) {
+ if(re->r.mode & R_PANORAMA) {
+ if(re->rectx/xparts < 8)
+ xparts= 1 + re->rectx/8;
+ }
+ else
+ if(re->rectx/xparts < 64)
+ xparts= 1 + re->rectx/64;
+
+ if(re->recty/yparts < 64)
+ yparts= 1 + re->recty/64;
+ }
+
+ /* part size */
+ partx= re->rectx/xparts;
+ party= re->recty/yparts;
+
+ /* if remainder pixel, add one, then parts are more equal in size for large panoramas */
+ if(re->rectx % partx)
+ partx++;
+
+ re->xparts= xparts;
+ re->yparts= yparts;
+ re->partx= partx;
+ re->party= party;
+
+ /* calculate rotation factor of 1 pixel */
+ if(re->r.mode & R_PANORAMA)
+ re->panophi= panorama_pixel_rot(re);
+
+ for(nr=0; nr<xparts*yparts; nr++) {
+ rcti disprect;
+ int rectx, recty;
+
+ xd= (nr % xparts);
+ yd= (nr-xd)/xparts;
+
+ disprect.xmin= xminb+ xd*partx;
+ disprect.ymin= yminb+ yd*party;
+
+ /* ensure we cover the entire picture, so last parts go to end */
+ if(xd<xparts-1) {
+ disprect.xmax= disprect.xmin + partx;
+ if(disprect.xmax > xmaxb)
+ disprect.xmax = xmaxb;
+ }
+ else disprect.xmax= xmaxb;
+
+ if(yd<yparts-1) {
+ disprect.ymax= disprect.ymin + party;
+ if(disprect.ymax > ymaxb)
+ disprect.ymax = ymaxb;
+ }
+ else disprect.ymax= ymaxb;
+
+ rectx= disprect.xmax - disprect.xmin;
+ recty= disprect.ymax - disprect.ymin;
+
+ /* so, now can we add this part? */
+ if(rectx>0 && recty>0) {
+ RenderPart *pa= MEM_callocN(sizeof(RenderPart), "new part");
+
+ /* Non-box filters need 2 pixels extra to work */
+ if((re->r.filtertype || (re->r.mode & R_EDGE))) {
+ pa->crop= 2;
+ disprect.xmin -= pa->crop;
+ disprect.ymin -= pa->crop;
+ disprect.xmax += pa->crop;
+ disprect.ymax += pa->crop;
+ rectx+= 2*pa->crop;
+ recty+= 2*pa->crop;
+ }
+ pa->disprect= disprect;
+ pa->rectx= rectx;
+ pa->recty= recty;
+
+ BLI_addtail(&re->parts, pa);
+ re->i.totpart++;
+ }
+ }
+}
+
+
+
diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c
new file mode 100644
index 00000000000..61bc6a84556
--- /dev/null
+++ b/source/blender/render/intern/source/pipeline.c
@@ -0,0 +1,2402 @@
+/**
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <math.h>
+#include <limits.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "DNA_group_types.h"
+#include "DNA_image_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BKE_global.h"
+#include "BKE_image.h"
+#include "BKE_main.h"
+#include "BKE_node.h"
+#include "BKE_object.h"
+#include "BKE_scene.h"
+#include "BKE_writeavi.h" /* <------ should be replaced once with generic movie module */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+#include "BLI_rand.h"
+#include "BLI_threads.h"
+
+#include "PIL_time.h"
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "intern/openexr/openexr_multi.h"
+
+#include "RE_pipeline.h"
+#include "radio.h"
+
+#include "BSE_sequence.h" /* <----------------- bad!!! */
+
+#ifndef DISABLE_YAFRAY
+/* yafray: include for yafray export/render */
+#include "YafRay_Api.h"
+
+#endif /* disable yafray */
+
+/* internal */
+#include "render_types.h"
+#include "renderpipeline.h"
+#include "renderdatabase.h"
+#include "rendercore.h"
+#include "envmap.h"
+#include "initrender.h"
+#include "shadbuf.h"
+#include "zbuf.h"
+
+
+/* render flow
+
+1) Initialize state
+- state data, tables
+- movie/image file init
+- everything that doesn't change during animation
+
+2) Initialize data
+- camera, world, matrices
+- make render verts, faces, halos, strands
+- everything can change per frame/field
+
+3) Render Processor
+- multiple layers
+- tiles, rect, baking
+- layers/tiles optionally to disk or directly in Render Result
+
+4) Composit Render Result
+- also read external files etc
+
+5) Image Files
+- save file or append in movie
+
+*/
+
+
+/* ********* globals ******** */
+
+/* here we store all renders */
+static struct ListBase RenderList= {NULL, NULL};
+
+/* hardcopy of current render, used while rendering for speed */
+Render R;
+
+/* commandline thread override */
+static int commandline_threads= 0;
+
+/* ********* alloc and free ******** */
+
+
+static volatile int g_break= 0;
+static int thread_break(void)
+{
+ return g_break;
+}
+
+/* default callbacks, set in each new render */
+static void result_nothing(RenderResult *rr) {}
+static void result_rcti_nothing(RenderResult *rr, volatile struct rcti *rect) {}
+static void stats_nothing(RenderStats *rs) {}
+static void int_nothing(int val) {}
+static int void_nothing(void) {return 0;}
+static void print_error(char *str) {printf("ERROR: %s\n", str);}
+
+static void stats_background(RenderStats *rs)
+{
+ extern unsigned long mem_in_use;
+ float megs_used_memory= mem_in_use/(1024.0*1024.0);
+ char str[400], *spos= str;
+
+ if(rs->convertdone) {
+
+ spos+= sprintf(spos, "Fra:%d Mem:%.2fM ", G.scene->r.cfra, megs_used_memory);
+
+ if(rs->curfield)
+ spos+= sprintf(spos, "Field %d ", rs->curfield);
+ if(rs->curblur)
+ spos+= sprintf(spos, "Blur %d ", rs->curblur);
+
+ if(rs->infostr) {
+ spos+= sprintf(spos, "| %s", rs->infostr);
+ }
+ else {
+ if(rs->tothalo)
+ spos+= sprintf(spos, "Sce: %s Ve:%d Fa:%d Ha:%d La:%d", G.scene->id.name+2, rs->totvert, rs->totface, rs->tothalo, rs->totlamp);
+ else
+ spos+= sprintf(spos, "Sce: %s Ve:%d Fa:%d La:%d", G.scene->id.name+2, rs->totvert, rs->totface, rs->totlamp);
+ }
+ printf(str); printf("\n");
+ }
+}
+
+void RE_FreeRenderResult(RenderResult *res)
+{
+ if(res==NULL) return;
+
+ while(res->layers.first) {
+ RenderLayer *rl= res->layers.first;
+
+ if(rl->rectf) MEM_freeN(rl->rectf);
+ /* acolrect is optionally allocated in shade_tile, only free here since it can be used for drawing */
+ if(rl->acolrect) MEM_freeN(rl->acolrect);
+
+ while(rl->passes.first) {
+ RenderPass *rpass= rl->passes.first;
+ if(rpass->rect) MEM_freeN(rpass->rect);
+ BLI_remlink(&rl->passes, rpass);
+ MEM_freeN(rpass);
+ }
+ BLI_remlink(&res->layers, rl);
+ MEM_freeN(rl);
+ }
+
+ if(res->rect32)
+ MEM_freeN(res->rect32);
+ if(res->rectz)
+ MEM_freeN(res->rectz);
+ if(res->rectf)
+ MEM_freeN(res->rectf);
+
+ MEM_freeN(res);
+}
+
+/* all layers except the active one get temporally pushed away */
+static void push_render_result(Render *re)
+{
+ /* officially pushed result should be NULL... error can happen with do_seq */
+ RE_FreeRenderResult(re->pushedresult);
+
+ re->pushedresult= re->result;
+ re->result= NULL;
+}
+
+/* if scemode is R_SINGLE_LAYER, at end of rendering, merge the both render results */
+static void pop_render_result(Render *re)
+{
+
+ if(re->result==NULL) {
+ printf("pop render result error; no current result!\n");
+ return;
+ }
+ if(re->pushedresult) {
+ if(re->pushedresult->rectx==re->result->rectx && re->pushedresult->recty==re->result->recty) {
+ /* find which layer in pushedresult should be replaced */
+ SceneRenderLayer *srl;
+ RenderLayer *rlpush;
+ RenderLayer *rl= re->result->layers.first;
+ int nr;
+
+ /* render result should be empty after this */
+ BLI_remlink(&re->result->layers, rl);
+
+ /* reconstruct render result layers */
+ for(nr=0, srl= re->scene->r.layers.first; srl; srl= srl->next, nr++) {
+ if(nr==re->r.actlay)
+ BLI_addtail(&re->result->layers, rl);
+ else {
+ rlpush= RE_GetRenderLayer(re->pushedresult, srl->name);
+ if(rlpush) {
+ BLI_remlink(&re->pushedresult->layers, rlpush);
+ BLI_addtail(&re->result->layers, rlpush);
+ }
+ }
+ }
+ }
+
+ RE_FreeRenderResult(re->pushedresult);
+ re->pushedresult= NULL;
+ }
+}
+
+/* NOTE: OpenEXR only supports 32 chars for layer+pass names
+ In blender we now use max 10 chars for pass, max 20 for layer */
+static char *get_pass_name(int passtype, int channel)
+{
+
+ if(passtype == SCE_PASS_COMBINED) {
+ if(channel==-1) return "Combined";
+ if(channel==0) return "Combined.R";
+ if(channel==1) return "Combined.G";
+ if(channel==2) return "Combined.B";
+ return "Combined.A";
+ }
+ if(passtype == SCE_PASS_Z) {
+ if(channel==-1) return "Depth";
+ return "Depth.Z";
+ }
+ if(passtype == SCE_PASS_VECTOR) {
+ if(channel==-1) return "Vector";
+ if(channel==0) return "Vector.X";
+ if(channel==1) return "Vector.Y";
+ if(channel==2) return "Vector.Z";
+ return "Vector.W";
+ }
+ if(passtype == SCE_PASS_NORMAL) {
+ if(channel==-1) return "Normal";
+ if(channel==0) return "Normal.X";
+ if(channel==1) return "Normal.Y";
+ return "Normal.Z";
+ }
+ if(passtype == SCE_PASS_UV) {
+ if(channel==-1) return "UV";
+ if(channel==0) return "UV.U";
+ if(channel==1) return "UV.V";
+ return "UV.A";
+ }
+ if(passtype == SCE_PASS_RGBA) {
+ if(channel==-1) return "Color";
+ if(channel==0) return "Color.R";
+ if(channel==1) return "Color.G";
+ if(channel==2) return "Color.B";
+ return "Color.A";
+ }
+ if(passtype == SCE_PASS_DIFFUSE) {
+ if(channel==-1) return "Diffuse";
+ if(channel==0) return "Diffuse.R";
+ if(channel==1) return "Diffuse.G";
+ return "Diffuse.B";
+ }
+ if(passtype == SCE_PASS_SPEC) {
+ if(channel==-1) return "Spec";
+ if(channel==0) return "Spec.R";
+ if(channel==1) return "Spec.G";
+ return "Spec.B";
+ }
+ if(passtype == SCE_PASS_SHADOW) {
+ if(channel==-1) return "Shadow";
+ if(channel==0) return "Shadow.R";
+ if(channel==1) return "Shadow.G";
+ return "Shadow.B";
+ }
+ if(passtype == SCE_PASS_AO) {
+ if(channel==-1) return "AO";
+ if(channel==0) return "AO.R";
+ if(channel==1) return "AO.G";
+ return "AO.B";
+ }
+ if(passtype == SCE_PASS_REFLECT) {
+ if(channel==-1) return "Reflect";
+ if(channel==0) return "Reflect.R";
+ if(channel==1) return "Reflect.G";
+ return "Reflect.B";
+ }
+ if(passtype == SCE_PASS_REFRACT) {
+ if(channel==-1) return "Refract";
+ if(channel==0) return "Refract.R";
+ if(channel==1) return "Refract.G";
+ return "Refract.B";
+ }
+ if(passtype == SCE_PASS_RADIO) {
+ if(channel==-1) return "Radio";
+ if(channel==0) return "Radio.R";
+ if(channel==1) return "Radio.G";
+ return "Radio.B";
+ }
+ if(passtype == SCE_PASS_INDEXOB) {
+ if(channel==-1) return "IndexOB";
+ return "IndexOB.X";
+ }
+ return "Unknown";
+}
+
+static int passtype_from_name(char *str)
+{
+
+ if(strcmp(str, "Combined")==0)
+ return SCE_PASS_COMBINED;
+
+ if(strcmp(str, "Depth")==0)
+ return SCE_PASS_Z;
+
+ if(strcmp(str, "Vector")==0)
+ return SCE_PASS_VECTOR;
+
+ if(strcmp(str, "Normal")==0)
+ return SCE_PASS_NORMAL;
+
+ if(strcmp(str, "UV")==0)
+ return SCE_PASS_UV;
+
+ if(strcmp(str, "Color")==0)
+ return SCE_PASS_RGBA;
+
+ if(strcmp(str, "Diffuse")==0)
+ return SCE_PASS_DIFFUSE;
+
+ if(strcmp(str, "Spec")==0)
+ return SCE_PASS_SPEC;
+
+ if(strcmp(str, "Shadow")==0)
+ return SCE_PASS_SHADOW;
+
+ if(strcmp(str, "AO")==0)
+ return SCE_PASS_AO;
+
+ if(strcmp(str, "Reflect")==0)
+ return SCE_PASS_REFLECT;
+
+ if(strcmp(str, "Refract")==0)
+ return SCE_PASS_REFRACT;
+
+ if(strcmp(str, "Radio")==0)
+ return SCE_PASS_RADIO;
+
+ if(strcmp(str, "IndexOB")==0)
+ return SCE_PASS_INDEXOB;
+
+ return 0;
+}
+
+
+
+static void render_unique_exr_name(Render *re, char *str)
+{
+ char di[FILE_MAX], name[FILE_MAXFILE], fi[FILE_MAXFILE];
+
+ BLI_strncpy(di, G.sce, FILE_MAX);
+ BLI_splitdirstring(di, fi);
+ sprintf(name, "%s_%s.exr", fi, re->scene->id.name+2);
+ if(G.background)
+ BLI_make_file_string("/", str, "/tmp/", name);
+ else
+ BLI_make_file_string("/", str, U.tempdir, name);
+
+}
+
+static void render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int channels, int passtype)
+{
+ char *typestr= get_pass_name(passtype, 0);
+ RenderPass *rpass= MEM_callocN(sizeof(RenderPass), typestr);
+ int rectsize= rr->rectx*rr->recty*channels;
+
+ BLI_addtail(&rl->passes, rpass);
+ rpass->passtype= passtype;
+ rpass->channels= channels;
+
+ if(rr->exrhandle) {
+ int a;
+ for(a=0; a<channels; a++)
+ IMB_exr_add_channel(rr->exrhandle, rl->name, get_pass_name(passtype, a), 0, 0, NULL);
+ }
+ else {
+ if(passtype==SCE_PASS_VECTOR) {
+ float *rect;
+ int x;
+
+ /* initialize to max speed */
+ rect= rpass->rect= MEM_mapallocN(sizeof(float)*rectsize, typestr);
+ for(x= rectsize-1; x>=0; x--)
+ rect[x]= PASS_VECTOR_MAX;
+ }
+ else
+ rpass->rect= MEM_mapallocN(sizeof(float)*rectsize, typestr);
+ }
+}
+
+float *RE_RenderLayerGetPass(RenderLayer *rl, int passtype)
+{
+ RenderPass *rpass;
+
+ for(rpass=rl->passes.first; rpass; rpass= rpass->next)
+ if(rpass->passtype== passtype)
+ return rpass->rect;
+ return NULL;
+}
+
+RenderLayer *RE_GetRenderLayer(RenderResult *rr, const char *name)
+{
+ RenderLayer *rl;
+
+ if(rr==NULL) return NULL;
+
+ for(rl= rr->layers.first; rl; rl= rl->next)
+ if(strncmp(rl->name, name, RE_MAXNAME)==0)
+ return rl;
+ return NULL;
+}
+
+#define RR_USEMEM 0
+/* called by main render as well for parts */
+/* will read info from Render *re to define layers */
+/* called in threads */
+/* re->winx,winy is coordinate space of entire image, partrct the part within */
+static RenderResult *new_render_result(Render *re, rcti *partrct, int crop, int savebuffers)
+{
+ RenderResult *rr;
+ RenderLayer *rl;
+ SceneRenderLayer *srl;
+ int rectx, recty, nr;
+
+ rectx= partrct->xmax - partrct->xmin;
+ recty= partrct->ymax - partrct->ymin;
+
+ if(rectx<=0 || recty<=0)
+ return NULL;
+
+ rr= MEM_callocN(sizeof(RenderResult), "new render result");
+ rr->rectx= rectx;
+ rr->recty= recty;
+ rr->renrect.xmin= 0; rr->renrect.xmax= rectx-2*crop;
+ /* crop is one or two extra pixels rendered for filtering, is used for merging and display too */
+ rr->crop= crop;
+
+ /* tilerect is relative coordinates within render disprect. do not subtract crop yet */
+ rr->tilerect.xmin= partrct->xmin - re->disprect.xmin;
+ rr->tilerect.xmax= partrct->xmax - re->disprect.xmax;
+ rr->tilerect.ymin= partrct->ymin - re->disprect.ymin;
+ rr->tilerect.ymax= partrct->ymax - re->disprect.ymax;
+
+ if(savebuffers) {
+ rr->exrhandle= IMB_exr_get_handle();
+ }
+
+ /* check renderdata for amount of layers */
+ for(nr=0, srl= re->r.layers.first; srl; srl= srl->next, nr++) {
+
+ if((re->r.scemode & R_SINGLE_LAYER) && nr!=re->r.actlay)
+ continue;
+ if(srl->layflag & SCE_LAY_DISABLE)
+ continue;
+
+ rl= MEM_callocN(sizeof(RenderLayer), "new render layer");
+ BLI_addtail(&rr->layers, rl);
+
+ strcpy(rl->name, srl->name);
+ rl->lay= srl->lay;
+ rl->layflag= srl->layflag;
+ rl->passflag= srl->passflag;
+ rl->pass_xor= srl->pass_xor;
+ rl->light_override= srl->light_override;
+ rl->mat_override= srl->mat_override;
+
+ if(rr->exrhandle) {
+ IMB_exr_add_channel(rr->exrhandle, rl->name, "Combined.R", 0, 0, NULL);
+ IMB_exr_add_channel(rr->exrhandle, rl->name, "Combined.G", 0, 0, NULL);
+ IMB_exr_add_channel(rr->exrhandle, rl->name, "Combined.B", 0, 0, NULL);
+ IMB_exr_add_channel(rr->exrhandle, rl->name, "Combined.A", 0, 0, NULL);
+ }
+ else
+ rl->rectf= MEM_mapallocN(rectx*recty*sizeof(float)*4, "Combined rgba");
+
+ if(srl->passflag & SCE_PASS_Z)
+ render_layer_add_pass(rr, rl, 1, SCE_PASS_Z);
+ if(srl->passflag & SCE_PASS_VECTOR)
+ render_layer_add_pass(rr, rl, 4, SCE_PASS_VECTOR);
+ if(srl->passflag & SCE_PASS_NORMAL)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_NORMAL);
+ if(srl->passflag & SCE_PASS_UV)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_UV);
+ if(srl->passflag & SCE_PASS_RGBA)
+ render_layer_add_pass(rr, rl, 4, SCE_PASS_RGBA);
+ if(srl->passflag & SCE_PASS_DIFFUSE)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_DIFFUSE);
+ if(srl->passflag & SCE_PASS_SPEC)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_SPEC);
+ if(re->r.mode & R_SHADOW)
+ if(srl->passflag & SCE_PASS_SHADOW)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_SHADOW);
+ if(re->r.mode & R_RAYTRACE) {
+ if(srl->passflag & SCE_PASS_AO)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_AO);
+ if(srl->passflag & SCE_PASS_REFLECT)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_REFLECT);
+ if(srl->passflag & SCE_PASS_REFRACT)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_REFRACT);
+ }
+ if(re->r.mode & R_RADIO)
+ if(srl->passflag & SCE_PASS_RADIO)
+ render_layer_add_pass(rr, rl, 3, SCE_PASS_RADIO);
+ if(srl->passflag & SCE_PASS_INDEXOB)
+ render_layer_add_pass(rr, rl, 1, SCE_PASS_INDEXOB);
+
+ }
+ /* sss, previewrender and envmap don't do layers, so we make a default one */
+ if(rr->layers.first==NULL) {
+ rl= MEM_callocN(sizeof(RenderLayer), "new render layer");
+ BLI_addtail(&rr->layers, rl);
+
+ /* duplicate code... */
+ if(rr->exrhandle) {
+ IMB_exr_add_channel(rr->exrhandle, rl->name, "Combined.R", 0, 0, NULL);
+ IMB_exr_add_channel(rr->exrhandle, rl->name, "Combined.G", 0, 0, NULL);
+ IMB_exr_add_channel(rr->exrhandle, rl->name, "Combined.B", 0, 0, NULL);
+ IMB_exr_add_channel(rr->exrhandle, rl->name, "Combined.A", 0, 0, NULL);
+ }
+ else
+ rl->rectf= MEM_mapallocN(rectx*recty*sizeof(float)*4, "Combined rgba");
+
+ /* note, this has to be in sync with scene.c */
+ rl->lay= (1<<20) -1;
+ rl->layflag= 0x7FFF; /* solid ztra halo strand */
+ rl->passflag= SCE_PASS_COMBINED;
+
+ re->r.actlay= 0;
+ }
+
+ /* border render; calculate offset for use in compositor. compo is centralized coords */
+ rr->xof= re->disprect.xmin + (re->disprect.xmax - re->disprect.xmin)/2 - re->winx/2;
+ rr->yof= re->disprect.ymin + (re->disprect.ymax - re->disprect.ymin)/2 - re->winy/2;
+
+ return rr;
+}
+
+static int render_scene_needs_vector(Render *re)
+{
+ if((re->r.scemode & R_DOCOMP) || re->r.imtype==R_MULTILAYER) {
+ SceneRenderLayer *srl;
+
+ for(srl= re->scene->r.layers.first; srl; srl= srl->next)
+ if(!(srl->layflag & SCE_LAY_DISABLE))
+ if(srl->passflag & SCE_PASS_VECTOR)
+ return 1;
+ }
+ return 0;
+}
+
+static void do_merge_tile(RenderResult *rr, RenderResult *rrpart, float *target, float *tile, int pixsize)
+{
+ int y, ofs, copylen, tilex, tiley;
+
+ copylen= tilex= rrpart->rectx;
+ tiley= rrpart->recty;
+
+ if(rrpart->crop) { /* filters add pixel extra */
+ tile+= pixsize*(rrpart->crop + rrpart->crop*tilex);
+
+ copylen= tilex - 2*rrpart->crop;
+ tiley -= 2*rrpart->crop;
+
+ ofs= (rrpart->tilerect.ymin + rrpart->crop)*rr->rectx + (rrpart->tilerect.xmin+rrpart->crop);
+ target+= pixsize*ofs;
+ }
+ else {
+ ofs= (rrpart->tilerect.ymin*rr->rectx + rrpart->tilerect.xmin);
+ target+= pixsize*ofs;
+ }
+
+ copylen *= sizeof(float)*pixsize;
+ tilex *= pixsize;
+ ofs= pixsize*rr->rectx;
+
+ for(y=0; y<tiley; y++) {
+ memcpy(target, tile, copylen);
+ target+= ofs;
+ tile+= tilex;
+ }
+}
+
+/* used when rendering to a full buffer, or when reading the exr part-layer-pass file */
+/* no test happens here if it fits... we also assume layers are in sync */
+/* is used within threads */
+static void merge_render_result(RenderResult *rr, RenderResult *rrpart)
+{
+ RenderLayer *rl, *rlp;
+ RenderPass *rpass, *rpassp;
+
+ for(rl= rr->layers.first, rlp= rrpart->layers.first; rl && rlp; rl= rl->next, rlp= rlp->next) {
+
+ /* combined */
+ if(rl->rectf && rlp->rectf)
+ do_merge_tile(rr, rrpart, rl->rectf, rlp->rectf, 4);
+
+ /* passes are allocated in sync */
+ for(rpass= rl->passes.first, rpassp= rlp->passes.first; rpass && rpassp; rpass= rpass->next, rpassp= rpassp->next) {
+ do_merge_tile(rr, rrpart, rpass->rect, rpassp->rect, rpass->channels);
+ }
+ }
+}
+
+
+static void save_render_result_tile(Render *re, RenderPart *pa)
+{
+ RenderResult *rrpart= pa->result;
+ RenderLayer *rlp;
+ RenderPass *rpassp;
+ int offs, partx, party;
+
+ BLI_lock_thread(LOCK_IMAGE);
+
+ for(rlp= rrpart->layers.first; rlp; rlp= rlp->next) {
+
+ if(rrpart->crop) { /* filters add pixel extra */
+ offs= (rrpart->crop + rrpart->crop*rrpart->rectx);
+ }
+ else {
+ offs= 0;
+ }
+
+ /* combined */
+ if(rlp->rectf) {
+ int a, xstride= 4;
+ for(a=0; a<xstride; a++)
+ IMB_exr_set_channel(re->result->exrhandle, rlp->name, get_pass_name(SCE_PASS_COMBINED, a),
+ xstride, xstride*pa->rectx, rlp->rectf+a + xstride*offs);
+ }
+
+ /* passes are allocated in sync */
+ for(rpassp= rlp->passes.first; rpassp; rpassp= rpassp->next) {
+ int a, xstride= rpassp->channels;
+ for(a=0; a<xstride; a++)
+ IMB_exr_set_channel(re->result->exrhandle, rlp->name, get_pass_name(rpassp->passtype, a),
+ xstride, xstride*pa->rectx, rpassp->rect+a + xstride*offs);
+ }
+
+ }
+
+ party= rrpart->tilerect.ymin + rrpart->crop;
+ partx= rrpart->tilerect.xmin + rrpart->crop;
+ IMB_exrtile_write_channels(re->result->exrhandle, partx, party);
+
+ BLI_unlock_thread(LOCK_IMAGE);
+
+}
+
+static void save_empty_result_tiles(Render *re)
+{
+ RenderPart *pa;
+
+ IMB_exrtile_clear_channels(re->result->exrhandle);
+
+ for(pa= re->parts.first; pa; pa= pa->next) {
+ if(pa->ready==0) {
+ int party= pa->disprect.ymin - re->disprect.ymin + pa->crop;
+ int partx= pa->disprect.xmin - re->disprect.xmin + pa->crop;
+ IMB_exrtile_write_channels(re->result->exrhandle, partx, party);
+ }
+ }
+}
+
+
+/* for passes read from files, these have names stored */
+static char *make_pass_name(RenderPass *rpass, int chan)
+{
+ static char name[16];
+ int len;
+
+ BLI_strncpy(name, rpass->name, EXR_PASS_MAXNAME);
+ len= strlen(name);
+ name[len]= '.';
+ name[len+1]= rpass->chan_id[chan];
+ name[len+2]= 0;
+
+ return name;
+}
+
+/* filename already made absolute */
+/* called from within UI, saves both rendered result as a file-read result */
+void RE_WriteRenderResult(RenderResult *rr, char *filename, int compress)
+{
+ RenderLayer *rl;
+ RenderPass *rpass;
+ void *exrhandle= IMB_exr_get_handle();
+
+ /* composite result */
+ if(rr->rectf) {
+ IMB_exr_add_channel(exrhandle, "Composite", "Combined.R", 4, 4*rr->rectx, rr->rectf);
+ IMB_exr_add_channel(exrhandle, "Composite", "Combined.G", 4, 4*rr->rectx, rr->rectf+1);
+ IMB_exr_add_channel(exrhandle, "Composite", "Combined.B", 4, 4*rr->rectx, rr->rectf+2);
+ IMB_exr_add_channel(exrhandle, "Composite", "Combined.A", 4, 4*rr->rectx, rr->rectf+3);
+ }
+
+ /* add layers/passes and assign channels */
+ for(rl= rr->layers.first; rl; rl= rl->next) {
+
+ /* combined */
+ if(rl->rectf) {
+ int a, xstride= 4;
+ for(a=0; a<xstride; a++)
+ IMB_exr_add_channel(exrhandle, rl->name, get_pass_name(SCE_PASS_COMBINED, a),
+ xstride, xstride*rr->rectx, rl->rectf+a);
+ }
+
+ /* passes are allocated in sync */
+ for(rpass= rl->passes.first; rpass; rpass= rpass->next) {
+ int a, xstride= rpass->channels;
+ for(a=0; a<xstride; a++) {
+ if(rpass->passtype)
+ IMB_exr_add_channel(exrhandle, rl->name, get_pass_name(rpass->passtype, a),
+ xstride, xstride*rr->rectx, rpass->rect+a);
+ else
+ IMB_exr_add_channel(exrhandle, rl->name, make_pass_name(rpass, a),
+ xstride, xstride*rr->rectx, rpass->rect+a);
+ }
+ }
+ }
+
+ IMB_exr_begin_write(exrhandle, filename, rr->rectx, rr->recty, compress);
+
+ IMB_exr_write_channels(exrhandle);
+ IMB_exr_close(exrhandle);
+}
+
+/* callbacks for RE_MultilayerConvert */
+static void *ml_addlayer_cb(void *base, char *str)
+{
+ RenderResult *rr= base;
+ RenderLayer *rl;
+
+ rl= MEM_callocN(sizeof(RenderLayer), "new render layer");
+ BLI_addtail(&rr->layers, rl);
+
+ BLI_strncpy(rl->name, str, EXR_LAY_MAXNAME);
+ return rl;
+}
+static void ml_addpass_cb(void *base, void *lay, char *str, float *rect, int totchan, char *chan_id)
+{
+ RenderLayer *rl= lay;
+ RenderPass *rpass= MEM_callocN(sizeof(RenderPass), "loaded pass");
+ int a;
+
+ BLI_addtail(&rl->passes, rpass);
+ rpass->channels= totchan;
+
+ rpass->passtype= passtype_from_name(str);
+ if(rpass->passtype==0) printf("unknown pass %s\n", str);
+ rl->passflag |= rpass->passtype;
+
+ BLI_strncpy(rpass->name, str, EXR_PASS_MAXNAME);
+ /* channel id chars */
+ for(a=0; a<totchan; a++)
+ rpass->chan_id[a]= chan_id[a];
+
+ rpass->rect= rect;
+}
+
+/* from imbuf, if a handle was returned we convert this to render result */
+RenderResult *RE_MultilayerConvert(void *exrhandle, int rectx, int recty)
+{
+ RenderResult *rr= MEM_callocN(sizeof(RenderResult), "loaded render result");
+
+ rr->rectx= rectx;
+ rr->recty= recty;
+
+ IMB_exr_multilayer_convert(exrhandle, rr, ml_addlayer_cb, ml_addpass_cb);
+
+ return rr;
+}
+
+/* called in end of render, to add names to passes... for UI only */
+static void renderresult_add_names(RenderResult *rr)
+{
+ RenderLayer *rl;
+ RenderPass *rpass;
+
+ for(rl= rr->layers.first; rl; rl= rl->next)
+ for(rpass= rl->passes.first; rpass; rpass= rpass->next)
+ strcpy(rpass->name, get_pass_name(rpass->passtype, -1));
+}
+
+
+/* only for temp buffer files, makes exact copy of render result */
+static void read_render_result(Render *re)
+{
+ RenderLayer *rl;
+ RenderPass *rpass;
+ void *exrhandle= IMB_exr_get_handle();
+ int rectx, recty;
+ char str[FILE_MAX];
+
+ RE_FreeRenderResult(re->result);
+ re->result= new_render_result(re, &re->disprect, 0, RR_USEMEM);
+
+ render_unique_exr_name(re, str);
+ if(IMB_exr_begin_read(exrhandle, str, &rectx, &recty)==0) {
+ IMB_exr_close(exrhandle);
+ printf("cannot read: %s\n", str);
+ return;
+ }
+
+ if(rectx!=re->result->rectx || recty!=re->result->recty) {
+ printf("error in reading render result\n");
+ }
+ else {
+ for(rl= re->result->layers.first; rl; rl= rl->next) {
+
+ /* combined */
+ if(rl->rectf) {
+ int a, xstride= 4;
+ for(a=0; a<xstride; a++)
+ IMB_exr_set_channel(exrhandle, rl->name, get_pass_name(SCE_PASS_COMBINED, a),
+ xstride, xstride*rectx, rl->rectf+a);
+ }
+
+ /* passes are allocated in sync */
+ for(rpass= rl->passes.first; rpass; rpass= rpass->next) {
+ int a, xstride= rpass->channels;
+ for(a=0; a<xstride; a++)
+ IMB_exr_set_channel(exrhandle, rl->name, get_pass_name(rpass->passtype, a),
+ xstride, xstride*rectx, rpass->rect+a);
+ }
+
+ }
+ IMB_exr_read_channels(exrhandle);
+ renderresult_add_names(re->result);
+ }
+
+ IMB_exr_close(exrhandle);
+}
+
+/* *************************************************** */
+
+Render *RE_GetRender(const char *name)
+{
+ Render *re;
+
+ /* search for existing renders */
+ for(re= RenderList.first; re; re= re->next) {
+ if(strncmp(re->name, name, RE_MAXNAME)==0) {
+ break;
+ }
+ }
+ return re;
+}
+
+/* if you want to know exactly what has been done */
+RenderResult *RE_GetResult(Render *re)
+{
+ if(re)
+ return re->result;
+ return NULL;
+}
+
+RenderLayer *render_get_active_layer(Render *re, RenderResult *rr)
+{
+ RenderLayer *rl= BLI_findlink(&rr->layers, re->r.actlay);
+
+ if(rl)
+ return rl;
+ else
+ return rr->layers.first;
+}
+
+
+/* fill provided result struct with what's currently active or done */
+void RE_GetResultImage(Render *re, RenderResult *rr)
+{
+ memset(rr, 0, sizeof(RenderResult));
+
+ if(re && re->result) {
+ RenderLayer *rl;
+
+ rr->rectx= re->result->rectx;
+ rr->recty= re->result->recty;
+
+ rr->rectf= re->result->rectf;
+ rr->rectz= re->result->rectz;
+ rr->rect32= re->result->rect32;
+
+ /* active layer */
+ rl= render_get_active_layer(re, re->result);
+
+ if(rl) {
+ if(rr->rectf==NULL)
+ rr->rectf= rl->rectf;
+ if(rr->rectz==NULL)
+ rr->rectz= RE_RenderLayerGetPass(rl, SCE_PASS_Z);
+ }
+ }
+}
+
+#define FTOCHAR(val) val<=0.0f?0: (val>=1.0f?255: (char)(255.0f*val))
+/* caller is responsible for allocating rect in correct size! */
+void RE_ResultGet32(Render *re, unsigned int *rect)
+{
+ RenderResult rres;
+
+ RE_GetResultImage(re, &rres);
+ if(rres.rect32)
+ memcpy(rect, rres.rect32, sizeof(int)*rres.rectx*rres.recty);
+ else if(rres.rectf) {
+ float *fp= rres.rectf;
+ int tot= rres.rectx*rres.recty;
+ char *cp= (char *)rect;
+
+ for(;tot>0; tot--, cp+=4, fp+=4) {
+ cp[0] = FTOCHAR(fp[0]);
+ cp[1] = FTOCHAR(fp[1]);
+ cp[2] = FTOCHAR(fp[2]);
+ cp[3] = FTOCHAR(fp[3]);
+ }
+ }
+ else
+ /* else fill with black */
+ memset(rect, 0, sizeof(int)*re->rectx*re->recty);
+}
+
+
+RenderStats *RE_GetStats(Render *re)
+{
+ return &re->i;
+}
+
+Render *RE_NewRender(const char *name)
+{
+ Render *re;
+
+ /* only one render per name exists */
+ re= RE_GetRender(name);
+ if(re==NULL) {
+
+ /* new render data struct */
+ re= MEM_callocN(sizeof(Render), "new render");
+ BLI_addtail(&RenderList, re);
+ strncpy(re->name, name, RE_MAXNAME);
+ }
+
+ /* set default empty callbacks */
+ re->display_init= result_nothing;
+ re->display_clear= result_nothing;
+ re->display_draw= result_rcti_nothing;
+ re->timecursor= int_nothing;
+ re->test_break= void_nothing;
+ re->test_return= void_nothing;
+ re->error= print_error;
+ if(G.background)
+ re->stats_draw= stats_background;
+ else
+ re->stats_draw= stats_nothing;
+
+ /* init some variables */
+ re->ycor= 1.0f;
+
+ return re;
+}
+
+/* only call this while you know it will remove the link too */
+void RE_FreeRender(Render *re)
+{
+
+ free_renderdata_tables(re);
+ free_sample_tables(re);
+
+ RE_FreeRenderResult(re->result);
+ RE_FreeRenderResult(re->pushedresult);
+
+ BLI_remlink(&RenderList, re);
+ MEM_freeN(re);
+}
+
+/* exit blender */
+void RE_FreeAllRender(void)
+{
+ while(RenderList.first) {
+ RE_FreeRender(RenderList.first);
+ }
+}
+
+/* ********* initialize state ******** */
+
+
+/* what doesn't change during entire render sequence */
+/* disprect is optional, if NULL it assumes full window render */
+void RE_InitState(Render *re, RenderData *rd, int winx, int winy, rcti *disprect)
+{
+ re->ok= TRUE; /* maybe flag */
+
+ re->i.starttime= PIL_check_seconds_timer();
+ re->r= *rd; /* hardcopy */
+
+ re->winx= winx;
+ re->winy= winy;
+ if(disprect) {
+ re->disprect= *disprect;
+ re->rectx= disprect->xmax-disprect->xmin;
+ re->recty= disprect->ymax-disprect->ymin;
+ }
+ else {
+ re->disprect.xmin= re->disprect.ymin= 0;
+ re->disprect.xmax= winx;
+ re->disprect.ymax= winy;
+ re->rectx= winx;
+ re->recty= winy;
+ }
+
+ if(re->rectx < 2 || re->recty < 2) {
+ re->error("Image too small");
+ re->ok= 0;
+ }
+ else {
+ /* check state variables, osa? */
+ if(re->r.mode & (R_OSA)) {
+ re->osa= re->r.osa;
+ if(re->osa>16) re->osa= 16;
+ }
+ else re->osa= 0;
+
+ /* always call, checks for gamma, gamma tables and jitter too */
+ make_sample_tables(re);
+
+ /* make empty render result, so display callbacks can initialize */
+ RE_FreeRenderResult(re->result);
+ re->result= MEM_callocN(sizeof(RenderResult), "new render result");
+ re->result->rectx= re->rectx;
+ re->result->recty= re->recty;
+
+ /* we clip faces with a minimum of 2 pixel boundary outside of image border. see zbuf.c */
+ re->clipcrop= 1.0f + 2.0f/(float)(re->winx>re->winy?re->winy:re->winx);
+
+ if(commandline_threads>0 && commandline_threads<=BLENDER_MAX_THREADS)
+ re->r.threads= commandline_threads;
+ }
+}
+
+void RE_SetDispRect (struct Render *re, rcti *disprect)
+{
+ re->disprect= *disprect;
+ re->rectx= disprect->xmax-disprect->xmin;
+ re->recty= disprect->ymax-disprect->ymin;
+
+ /* initialize render result */
+ RE_FreeRenderResult(re->result);
+ re->result= new_render_result(re, &re->disprect, 0, RR_USEMEM);
+}
+
+void RE_SetWindow(Render *re, rctf *viewplane, float clipsta, float clipend)
+{
+ /* re->ok flag? */
+
+ re->viewplane= *viewplane;
+ re->clipsta= clipsta;
+ re->clipend= clipend;
+ re->r.mode &= ~R_ORTHO;
+
+ i_window(re->viewplane.xmin, re->viewplane.xmax, re->viewplane.ymin, re->viewplane.ymax, re->clipsta, re->clipend, re->winmat);
+
+}
+
+void RE_SetOrtho(Render *re, rctf *viewplane, float clipsta, float clipend)
+{
+ /* re->ok flag? */
+
+ re->viewplane= *viewplane;
+ re->clipsta= clipsta;
+ re->clipend= clipend;
+ re->r.mode |= R_ORTHO;
+
+ i_ortho(re->viewplane.xmin, re->viewplane.xmax, re->viewplane.ymin, re->viewplane.ymax, re->clipsta, re->clipend, re->winmat);
+}
+
+void RE_SetView(Render *re, float mat[][4])
+{
+ /* re->ok flag? */
+ Mat4CpyMat4(re->viewmat, mat);
+ Mat4Invert(re->viewinv, re->viewmat);
+}
+
+/* image and movie output has to move to either imbuf or kernel */
+void RE_display_init_cb(Render *re, void (*f)(RenderResult *rr))
+{
+ re->display_init= f;
+}
+void RE_display_clear_cb(Render *re, void (*f)(RenderResult *rr))
+{
+ re->display_clear= f;
+}
+void RE_display_draw_cb(Render *re, void (*f)(RenderResult *rr, volatile rcti *rect))
+{
+ re->display_draw= f;
+}
+
+void RE_stats_draw_cb(Render *re, void (*f)(RenderStats *rs))
+{
+ re->stats_draw= f;
+}
+void RE_timecursor_cb(Render *re, void (*f)(int))
+{
+ re->timecursor= f;
+}
+
+void RE_test_break_cb(Render *re, int (*f)(void))
+{
+ re->test_break= f;
+}
+void RE_test_return_cb(Render *re, int (*f)(void))
+{
+ re->test_return= f;
+}
+void RE_error_cb(Render *re, void (*f)(char *str))
+{
+ re->error= f;
+}
+
+
+/* ********* add object data (later) ******** */
+
+/* object is considered fully prepared on correct time etc */
+/* includes lights */
+void RE_AddObject(Render *re, Object *ob)
+{
+
+}
+
+/* *************************************** */
+
+static int render_display_draw_enabled(Render *re)
+{
+ /* don't show preprocess for previewrender sss */
+ if(re->sss_points)
+ return !(re->r.scemode & R_PREVIEWBUTS);
+ else
+ return 1;
+}
+
+static void *do_part_thread(void *pa_v)
+{
+ RenderPart *pa= pa_v;
+
+ /* need to return nicely all parts on esc */
+ if(R.test_break()==0) {
+ pa->result= new_render_result(&R, &pa->disprect, pa->crop, RR_USEMEM);
+
+ if(R.sss_points)
+ zbufshade_sss_tile(pa);
+ else if(R.osa)
+ zbufshadeDA_tile(pa);
+ else
+ zbufshade_tile(pa);
+
+ /* merge too on break! */
+ if(R.result->exrhandle)
+ save_render_result_tile(&R, pa);
+ else if(render_display_draw_enabled(&R))
+ merge_render_result(R.result, pa->result);
+ }
+
+ pa->ready= 1;
+
+ return NULL;
+}
+
+/* returns with render result filled, not threaded, used for preview now only */
+static void render_tile_processor(Render *re, int firsttile)
+{
+ RenderPart *pa;
+
+ if(re->test_break())
+ return;
+
+ /* hrmf... exception, this is used for preview render, re-entrant, so render result has to be re-used */
+ if(re->result==NULL || re->result->layers.first==NULL) {
+ if(re->result) RE_FreeRenderResult(re->result);
+ re->result= new_render_result(re, &re->disprect, 0, RR_USEMEM);
+ }
+
+ re->stats_draw(&re->i);
+
+ if(re->result==NULL)
+ return;
+
+ initparts(re);
+
+ /* assuming no new data gets added to dbase... */
+ R= *re;
+
+ for(pa= re->parts.first; pa; pa= pa->next) {
+ if(firsttile) {
+ re->i.partsdone++; /* was reset in initparts */
+ firsttile--;
+ }
+ else {
+ do_part_thread(pa);
+
+ if(pa->result) {
+ if(!re->test_break()) {
+ if(render_display_draw_enabled(re))
+ re->display_draw(pa->result, NULL);
+
+ re->i.partsdone++;
+ re->stats_draw(&re->i);
+ }
+ RE_FreeRenderResult(pa->result);
+ pa->result= NULL;
+ }
+ if(re->test_break())
+ break;
+ }
+ }
+
+ freeparts(re);
+}
+
+/* calculus for how much 1 pixel rendered should rotate the 3d geometry */
+/* is not that simple, needs to be corrected for errors of larger viewplane sizes */
+/* called in initrender.c, initparts() and convertblender.c, for speedvectors */
+float panorama_pixel_rot(Render *re)
+{
+ float psize, phi, xfac;
+
+ /* size of 1 pixel mapped to viewplane coords */
+ psize= (re->viewplane.xmax-re->viewplane.xmin)/(float)re->winx;
+ /* angle of a pixel */
+ phi= atan(psize/re->clipsta);
+
+ /* correction factor for viewplane shifting, first calculate how much the viewplane angle is */
+ xfac= ((re->viewplane.xmax-re->viewplane.xmin))/(float)re->xparts;
+ xfac= atan(0.5f*xfac/re->clipsta);
+ /* and how much the same viewplane angle is wrapped */
+ psize= 0.5f*phi*((float)re->partx);
+
+ /* the ratio applied to final per-pixel angle */
+ phi*= xfac/psize;
+
+ return phi;
+}
+
+/* call when all parts stopped rendering, to find the next Y slice */
+/* if slice found, it rotates the dbase */
+static RenderPart *find_next_pano_slice(Render *re, int *minx, rctf *viewplane)
+{
+ RenderPart *pa, *best= NULL;
+
+ *minx= re->winx;
+
+ /* most left part of the non-rendering parts */
+ for(pa= re->parts.first; pa; pa= pa->next) {
+ if(pa->ready==0 && pa->nr==0) {
+ if(pa->disprect.xmin < *minx) {
+ best= pa;
+ *minx= pa->disprect.xmin;
+ }
+ }
+ }
+
+ if(best) {
+ float phi= panorama_pixel_rot(re);
+
+ R.panodxp= (re->winx - (best->disprect.xmin + best->disprect.xmax) )/2;
+ R.panodxv= ((viewplane->xmax-viewplane->xmin)*R.panodxp)/(float)R.winx;
+
+ /* shift viewplane */
+ R.viewplane.xmin = viewplane->xmin + R.panodxv;
+ R.viewplane.xmax = viewplane->xmax + R.panodxv;
+ RE_SetWindow(re, &R.viewplane, R.clipsta, R.clipend);
+ Mat4CpyMat4(R.winmat, re->winmat);
+
+ /* rotate database according to part coordinates */
+ project_renderdata(re, projectverto, 1, -R.panodxp*phi);
+ R.panosi= sin(R.panodxp*phi);
+ R.panoco= cos(R.panodxp*phi);
+ }
+ return best;
+}
+
+static RenderPart *find_next_part(Render *re, int minx)
+{
+ RenderPart *pa, *best= NULL;
+ int centx=re->winx/2, centy=re->winy/2, tot=1;
+ int mindist, distx, disty;
+
+ /* find center of rendered parts, image center counts for 1 too */
+ for(pa= re->parts.first; pa; pa= pa->next) {
+ if(pa->ready) {
+ centx+= (pa->disprect.xmin+pa->disprect.xmax)/2;
+ centy+= (pa->disprect.ymin+pa->disprect.ymax)/2;
+ tot++;
+ }
+ }
+ centx/=tot;
+ centy/=tot;
+
+ /* closest of the non-rendering parts */
+ mindist= re->winx*re->winy;
+ for(pa= re->parts.first; pa; pa= pa->next) {
+ if(pa->ready==0 && pa->nr==0) {
+ distx= centx - (pa->disprect.xmin+pa->disprect.xmax)/2;
+ disty= centy - (pa->disprect.ymin+pa->disprect.ymax)/2;
+ distx= (int)sqrt(distx*distx + disty*disty);
+ if(distx<mindist) {
+ if(re->r.mode & R_PANORAMA) {
+ if(pa->disprect.xmin==minx) {
+ best= pa;
+ mindist= distx;
+ }
+ }
+ else {
+ best= pa;
+ mindist= distx;
+ }
+ }
+ }
+ }
+ return best;
+}
+
+static void print_part_stats(Render *re, RenderPart *pa)
+{
+ char str[64];
+
+ sprintf(str, "Part %d-%d", pa->nr, re->i.totpart);
+ re->i.infostr= str;
+ re->stats_draw(&re->i);
+ re->i.infostr= NULL;
+}
+
+static void threaded_tile_processor(Render *re)
+{
+ ListBase threads;
+ RenderPart *pa, *nextpa;
+ RenderResult *rr;
+ rctf viewplane= re->viewplane;
+ int rendering=1, counter= 1, drawtimer=0, hasdrawn, minx=0;
+
+ /* first step; the entire render result, or prepare exr buffer saving */
+ RE_FreeRenderResult(re->result);
+ rr= re->result= new_render_result(re, &re->disprect, 0, re->r.scemode & R_EXR_TILE_FILE);
+
+ if(rr==NULL)
+ return;
+ /* warning; no return here without closing exr file */
+// if(re->re->test_break())
+// return;
+
+ initparts(re);
+
+ if(rr->exrhandle) {
+ char str[FILE_MAX];
+
+ render_unique_exr_name(re, str);
+
+ printf("write exr tmp file, %dx%d, %s\n", rr->rectx, rr->recty, str);
+ IMB_exrtile_begin_write(rr->exrhandle, str, rr->rectx, rr->recty, rr->rectx/re->xparts, rr->recty/re->yparts);
+ }
+
+ BLI_init_threads(&threads, do_part_thread, re->r.threads);
+
+ /* assuming no new data gets added to dbase... */
+ R= *re;
+
+ /* set threadsafe break */
+ R.test_break= thread_break;
+
+ /* timer loop demands to sleep when no parts are left, so we enter loop with a part */
+ if(re->r.mode & R_PANORAMA)
+ nextpa= find_next_pano_slice(re, &minx, &viewplane);
+ else
+ nextpa= find_next_part(re, 0);
+
+ while(rendering) {
+
+ if(re->test_break())
+ PIL_sleep_ms(50);
+ else if(nextpa && BLI_available_threads(&threads)) {
+ drawtimer= 0;
+ nextpa->nr= counter++; /* for nicest part, and for stats */
+ nextpa->thread= BLI_available_thread_index(&threads); /* sample index */
+ BLI_insert_thread(&threads, nextpa);
+
+ nextpa= find_next_part(re, minx);
+ }
+ else if(re->r.mode & R_PANORAMA) {
+ if(nextpa==NULL && BLI_available_threads(&threads)==re->r.threads)
+ nextpa= find_next_pano_slice(re, &minx, &viewplane);
+ else {
+ PIL_sleep_ms(50);
+ drawtimer++;
+ }
+ }
+ else {
+ PIL_sleep_ms(50);
+ drawtimer++;
+ }
+
+ /* check for ready ones to display, and if we need to continue */
+ rendering= 0;
+ hasdrawn= 0;
+ for(pa= re->parts.first; pa; pa= pa->next) {
+ if(pa->ready) {
+
+ BLI_remove_thread(&threads, pa);
+
+ if(pa->result) {
+ if(render_display_draw_enabled(re))
+ re->display_draw(pa->result, NULL);
+ print_part_stats(re, pa);
+
+ RE_FreeRenderResult(pa->result);
+ pa->result= NULL;
+ re->i.partsdone++;
+ hasdrawn= 1;
+ }
+ }
+ else {
+ rendering= 1;
+ if(pa->nr && pa->result && drawtimer>20) {
+ if(render_display_draw_enabled(re))
+ re->display_draw(pa->result, &pa->result->renrect);
+ hasdrawn= 1;
+ }
+ }
+ }
+ if(hasdrawn)
+ drawtimer= 0;
+
+ /* on break, wait for all slots to get freed */
+ if( (g_break=re->test_break()) && BLI_available_threads(&threads)==re->r.threads)
+ rendering= 0;
+
+ }
+
+ if(rr->exrhandle) {
+ save_empty_result_tiles(re);
+ IMB_exr_close(rr->exrhandle);
+ rr->exrhandle= NULL;
+ read_render_result(re);
+ }
+
+ /* unset threadsafety */
+ g_break= 0;
+
+ BLI_end_threads(&threads);
+ freeparts(re);
+ re->viewplane= viewplane; /* restore viewplane, modified by pano render */
+
+}
+
+/* currently only called by preview renders and envmap */
+void RE_TileProcessor(Render *re, int firsttile, int threaded)
+{
+ /* the partsdone variable has to be reset to firsttile, to survive esc before it was set to zero */
+
+ re->i.partsdone= firsttile;
+
+ re->i.starttime= PIL_check_seconds_timer();
+
+ if(threaded)
+ threaded_tile_processor(re);
+ else
+ render_tile_processor(re, firsttile);
+
+ re->i.lastframetime= PIL_check_seconds_timer()- re->i.starttime;
+ re->stats_draw(&re->i);
+}
+
+
+/* ************ This part uses API, for rendering Blender scenes ********** */
+
+static void do_render_3d(Render *re)
+{
+
+// re->cfra= cfra; /* <- unused! */
+
+ /* make render verts/faces/halos/lamps */
+ if(render_scene_needs_vector(re))
+ RE_Database_FromScene_Vectors(re, re->scene);
+ else
+ RE_Database_FromScene(re, re->scene, 1);
+
+ threaded_tile_processor(re);
+
+ /* do left-over 3d post effects (flares) */
+ if(re->flag & R_HALO)
+ if(!re->test_break())
+ add_halo_flare(re);
+
+
+ /* free all render verts etc */
+ RE_Database_Free(re);
+}
+
+/* called by blur loop, accumulate renderlayers */
+static void addblur_rect(RenderResult *rr, float *rectf, float *rectf1, float blurfac, int channels)
+{
+ float mfac= 1.0f - blurfac;
+ int a, b, stride= channels*rr->rectx;
+ int len= stride*sizeof(float);
+
+ for(a=0; a<rr->recty; a++) {
+ if(blurfac==1.0f) {
+ memcpy(rectf, rectf1, len);
+ }
+ else {
+ float *rf= rectf, *rf1= rectf1;
+
+ for( b= rr->rectx*channels; b>0; b--, rf++, rf1++) {
+ rf[0]= mfac*rf[0] + blurfac*rf1[0];
+ }
+ }
+ rectf+= stride;
+ rectf1+= stride;
+ }
+}
+
+/* called by blur loop, accumulate renderlayers */
+static void merge_renderresult_blur(RenderResult *rr, RenderResult *brr, float blurfac)
+{
+ RenderLayer *rl, *rl1;
+ RenderPass *rpass, *rpass1;
+
+ rl1= brr->layers.first;
+ for(rl= rr->layers.first; rl && rl1; rl= rl->next, rl1= rl1->next) {
+
+ /* combined */
+ if(rl->rectf && rl1->rectf)
+ addblur_rect(rr, rl->rectf, rl1->rectf, blurfac, 4);
+
+ /* passes are allocated in sync */
+ rpass1= rl1->passes.first;
+ for(rpass= rl->passes.first; rpass && rpass1; rpass= rpass->next, rpass1= rpass1->next) {
+ addblur_rect(rr, rpass->rect, rpass1->rect, blurfac, rpass->channels);
+ }
+ }
+}
+
+/* main blur loop, can be called by fields too */
+static void do_render_blur_3d(Render *re)
+{
+ RenderResult *rres;
+ float blurfac;
+ int blur= re->r.osa;
+
+ /* create accumulation render result */
+ rres= new_render_result(re, &re->disprect, 0, RR_USEMEM);
+
+ /* do the blur steps */
+ while(blur--) {
+ set_mblur_offs( re->r.blurfac*((float)(re->r.osa-blur))/(float)re->r.osa );
+
+ re->i.curblur= re->r.osa-blur; /* stats */
+
+ do_render_3d(re);
+
+ blurfac= 1.0f/(float)(re->r.osa-blur);
+
+ merge_renderresult_blur(rres, re->result, blurfac);
+ if(re->test_break()) break;
+ }
+
+ /* swap results */
+ RE_FreeRenderResult(re->result);
+ re->result= rres;
+
+ set_mblur_offs(0.0f);
+ re->i.curblur= 0; /* stats */
+
+ /* weak... the display callback wants an active renderlayer pointer... */
+ re->result->renlay= render_get_active_layer(re, re->result);
+ re->display_draw(re->result, NULL);
+}
+
+
+/* function assumes rectf1 and rectf2 to be half size of rectf */
+static void interleave_rect(RenderResult *rr, float *rectf, float *rectf1, float *rectf2, int channels)
+{
+ int a, stride= channels*rr->rectx;
+ int len= stride*sizeof(float);
+
+ for(a=0; a<rr->recty; a+=2) {
+ memcpy(rectf, rectf1, len);
+ rectf+= stride;
+ rectf1+= stride;
+ memcpy(rectf, rectf2, len);
+ rectf+= stride;
+ rectf2+= stride;
+ }
+}
+
+/* merge render results of 2 fields */
+static void merge_renderresult_fields(RenderResult *rr, RenderResult *rr1, RenderResult *rr2)
+{
+ RenderLayer *rl, *rl1, *rl2;
+ RenderPass *rpass, *rpass1, *rpass2;
+
+ rl1= rr1->layers.first;
+ rl2= rr2->layers.first;
+ for(rl= rr->layers.first; rl && rl1 && rl2; rl= rl->next, rl1= rl1->next, rl2= rl2->next) {
+
+ /* combined */
+ if(rl->rectf && rl1->rectf && rl2->rectf)
+ interleave_rect(rr, rl->rectf, rl1->rectf, rl2->rectf, 4);
+
+ /* passes are allocated in sync */
+ rpass1= rl1->passes.first;
+ rpass2= rl2->passes.first;
+ for(rpass= rl->passes.first; rpass && rpass1 && rpass2; rpass= rpass->next, rpass1= rpass1->next, rpass2= rpass2->next) {
+ interleave_rect(rr, rpass->rect, rpass1->rect, rpass2->rect, rpass->channels);
+ }
+ }
+}
+
+
+/* interleaves 2 frames */
+static void do_render_fields_3d(Render *re)
+{
+ RenderResult *rr1, *rr2= NULL;
+
+ /* no render result was created, we can safely halve render y */
+ re->winy /= 2;
+ re->recty /= 2;
+ re->disprect.ymin /= 2;
+ re->disprect.ymax /= 2;
+
+ re->i.curfield= 1; /* stats */
+
+ /* first field, we have to call camera routine for correct aspect and subpixel offset */
+ RE_SetCamera(re, re->scene->camera);
+ if(re->r.mode & R_MBLUR)
+ do_render_blur_3d(re);
+ else
+ do_render_3d(re);
+ rr1= re->result;
+ re->result= NULL;
+
+ /* second field */
+ if(!re->test_break()) {
+
+ re->i.curfield= 2; /* stats */
+
+ re->flag |= R_SEC_FIELD;
+ if((re->r.mode & R_FIELDSTILL)==0)
+ set_field_offs(0.5f);
+ RE_SetCamera(re, re->scene->camera);
+ if(re->r.mode & R_MBLUR)
+ do_render_blur_3d(re);
+ else
+ do_render_3d(re);
+ re->flag &= ~R_SEC_FIELD;
+ set_field_offs(0.0f);
+
+ rr2= re->result;
+ }
+
+ /* allocate original height new buffers */
+ re->winy *= 2;
+ re->recty *= 2;
+ re->disprect.ymin *= 2;
+ re->disprect.ymax *= 2;
+ re->result= new_render_result(re, &re->disprect, 0, RR_USEMEM);
+
+ if(rr2) {
+ if(re->r.mode & R_ODDFIELD)
+ merge_renderresult_fields(re->result, rr2, rr1);
+ else
+ merge_renderresult_fields(re->result, rr1, rr2);
+
+ RE_FreeRenderResult(rr2);
+ }
+ RE_FreeRenderResult(rr1);
+
+ re->i.curfield= 0; /* stats */
+
+ /* weak... the display callback wants an active renderlayer pointer... */
+ re->result->renlay= render_get_active_layer(re, re->result);
+ re->display_draw(re->result, NULL);
+}
+
+static void load_backbuffer(Render *re)
+{
+ if(re->r.alphamode == R_ADDSKY) {
+ ImBuf *ibuf;
+ char name[256];
+
+ strcpy(name, re->r.backbuf);
+ BLI_convertstringcode(name, G.sce, re->r.cfra);
+
+ if(re->backbuf) {
+ re->backbuf->id.us--;
+ if(re->backbuf->id.us<1)
+ BKE_image_signal(re->backbuf, NULL, IMA_SIGNAL_RELOAD);
+ }
+
+ re->backbuf= BKE_add_image_file(name);
+ ibuf= BKE_image_get_ibuf(re->backbuf, NULL);
+ if(ibuf==NULL) {
+ // error() doesnt work with render window open
+ //error("No backbuf there!");
+ printf("Error: No backbuf %s\n", name);
+ }
+ else {
+ if (re->r.mode & R_FIELDS)
+ image_de_interlace(re->backbuf, re->r.mode & R_ODDFIELD);
+ }
+ }
+}
+
+/* main render routine, no compositing */
+static void do_render_fields_blur_3d(Render *re)
+{
+ /* also check for camera here */
+ if(re->scene->camera==NULL) {
+ printf("ERROR: Cannot render, no camera\n");
+ G.afbreek= 1;
+ return;
+ }
+
+ /* backbuffer initialize */
+ if(re->r.bufflag & 1)
+ load_backbuffer(re);
+
+ /* now use renderdata and camera to set viewplane */
+ RE_SetCamera(re, re->scene->camera);
+
+ if(re->r.mode & R_FIELDS)
+ do_render_fields_3d(re);
+ else if(re->r.mode & R_MBLUR)
+ do_render_blur_3d(re);
+ else
+ do_render_3d(re);
+
+ /* when border render, check if we have to insert it in black */
+ if(re->result) {
+ if(re->r.mode & R_BORDER) {
+ if((re->r.mode & R_CROP)==0) {
+ RenderResult *rres;
+
+ /* sub-rect for merge call later on */
+ re->result->tilerect= re->disprect;
+
+ /* this copying sequence could become function? */
+ re->disprect.xmin= re->disprect.ymin= 0;
+ re->disprect.xmax= re->winx;
+ re->disprect.ymax= re->winy;
+ re->rectx= re->winx;
+ re->recty= re->winy;
+
+ rres= new_render_result(re, &re->disprect, 0, RR_USEMEM);
+
+ merge_render_result(rres, re->result);
+ RE_FreeRenderResult(re->result);
+ re->result= rres;
+
+ /* weak... the display callback wants an active renderlayer pointer... */
+ re->result->renlay= render_get_active_layer(re, re->result);
+
+ re->display_init(re->result);
+ re->display_draw(re->result, NULL);
+ }
+ }
+ }
+}
+
+
+/* within context of current Render *re, render another scene.
+ it uses current render image size and disprect, but doesn't execute composite
+*/
+static void render_scene(Render *re, Scene *sce, int cfra)
+{
+ Render *resc= RE_NewRender(sce->id.name);
+
+ sce->r.cfra= cfra;
+
+ /* initial setup */
+ RE_InitState(resc, &sce->r, re->winx, re->winy, &re->disprect);
+
+ /* this to enable this scene to create speed vectors */
+ resc->r.scemode |= R_DOCOMP;
+
+ /* still unsure entity this... */
+ resc->scene= sce;
+
+ /* ensure scene has depsgraph, base flags etc OK. Warning... also sets G.scene */
+ set_scene_bg(sce);
+
+ /* copy callbacks */
+ resc->display_draw= re->display_draw;
+ resc->test_break= re->test_break;
+ resc->stats_draw= re->stats_draw;
+
+ do_render_fields_blur_3d(resc);
+}
+
+static void ntree_render_scenes(Render *re)
+{
+ bNode *node;
+ int cfra= re->scene->r.cfra;
+
+ if(re->scene->nodetree==NULL) return;
+
+ /* check for render-layers nodes using other scenes, we tag them LIB_DOIT */
+ for(node= re->scene->nodetree->nodes.first; node; node= node->next) {
+ if(node->type==CMP_NODE_R_LAYERS) {
+ if(node->id) {
+ if(node->id != (ID *)re->scene)
+ node->id->flag |= LIB_DOIT;
+ else
+ node->id->flag &= ~LIB_DOIT;
+ }
+ }
+ }
+
+ /* now foreach render-result node tagged we do a full render */
+ /* results are stored in a way compisitor will find it */
+ for(node= re->scene->nodetree->nodes.first; node; node= node->next) {
+ if(node->type==CMP_NODE_R_LAYERS) {
+ if(node->id && node->id != (ID *)re->scene) {
+ if(node->id->flag & LIB_DOIT) {
+ render_scene(re, (Scene *)node->id, cfra);
+ node->id->flag &= ~LIB_DOIT;
+ }
+ }
+ }
+ }
+
+ /* still the global... */
+ if(G.scene!=re->scene)
+ set_scene_bg(re->scene);
+
+}
+
+/* helper call to detect if theres a composite with render-result node */
+static int composite_needs_render(Scene *sce)
+{
+ bNodeTree *ntree= sce->nodetree;
+ bNode *node;
+
+ if(ntree==NULL) return 1;
+ if(sce->use_nodes==0) return 1;
+ if((sce->r.scemode & R_DOCOMP)==0) return 1;
+
+ for(node= ntree->nodes.first; node; node= node->next) {
+ if(node->type==CMP_NODE_R_LAYERS)
+ if(node->id==NULL || node->id==&sce->id)
+ return 1;
+ }
+ return 0;
+}
+
+/* bad call... need to think over proper method still */
+static void render_composit_stats(char *str)
+{
+ R.i.infostr= str;
+ R.stats_draw(&R.i);
+ R.i.infostr= NULL;
+}
+
+/* returns fully composited render-result on given time step (in RenderData) */
+static void do_render_composite_fields_blur_3d(Render *re)
+{
+ bNodeTree *ntree= re->scene->nodetree;
+
+ /* INIT seeding, compositor can use random texture */
+ BLI_srandom(re->r.cfra);
+
+ if(composite_needs_render(re->scene)) {
+ /* save memory... free all cached images */
+ ntreeFreeCache(ntree);
+
+ do_render_fields_blur_3d(re);
+ }
+
+ /* swap render result */
+ if(re->r.scemode & R_SINGLE_LAYER)
+ pop_render_result(re);
+
+ if(!re->test_break() && ntree) {
+ ntreeCompositTagRender(re->scene);
+ ntreeCompositTagAnimated(ntree);
+
+ if(re->r.scemode & R_DOCOMP) {
+ /* checks if there are render-result nodes that need scene */
+ if((re->r.scemode & R_SINGLE_LAYER)==0)
+ ntree_render_scenes(re);
+
+ if(!re->test_break()) {
+ ntree->stats_draw= render_composit_stats;
+ ntree->test_break= re->test_break;
+ /* in case it was never initialized */
+ R.stats_draw= re->stats_draw;
+
+ ntreeCompositExecTree(ntree, &re->r, G.background==0);
+ ntree->stats_draw= NULL;
+ ntree->test_break= NULL;
+ }
+ }
+ }
+
+ /* weak... the display callback wants an active renderlayer pointer... */
+ re->result->renlay= render_get_active_layer(re, re->result);
+ re->display_draw(re->result, NULL);
+}
+
+#ifndef DISABLE_YAFRAY
+/* yafray: main yafray render/export call */
+static void yafrayRender(Render *re)
+{
+ RE_FreeRenderResult(re->result);
+ re->result= new_render_result(re, &re->disprect, 0, RR_USEMEM);
+
+ // need this too, for aspect/ortho/etc info
+ RE_SetCamera(re, re->scene->camera);
+
+ // switch must be done before prepareScene()
+ if (!re->r.YFexportxml)
+ YAF_switchFile();
+ else
+ YAF_switchPlugin();
+
+ printf("Starting scene conversion.\n");
+ RE_Database_FromScene(re, re->scene, 1);
+ printf("Scene conversion done.\n");
+
+ re->i.starttime = PIL_check_seconds_timer();
+
+ YAF_exportScene(re);
+
+ /* also needed for yafray border render, straight copy from do_render_fields_blur_3d() */
+ /* when border render, check if we have to insert it in black */
+ if(re->result) {
+ if(re->r.mode & R_BORDER) {
+ if((re->r.mode & R_CROP)==0) {
+ RenderResult *rres;
+
+ /* sub-rect for merge call later on */
+ re->result->tilerect= re->disprect;
+
+ /* this copying sequence could become function? */
+ re->disprect.xmin= re->disprect.ymin= 0;
+ re->disprect.xmax= re->winx;
+ re->disprect.ymax= re->winy;
+ re->rectx= re->winx;
+ re->recty= re->winy;
+
+ rres= new_render_result(re, &re->disprect, 0, RR_USEMEM);
+
+ merge_render_result(rres, re->result);
+ RE_FreeRenderResult(re->result);
+ re->result= rres;
+
+ re->display_init(re->result);
+ re->display_draw(re->result, NULL);
+ }
+ }
+ }
+
+ re->i.lastframetime = PIL_check_seconds_timer()- re->i.starttime;
+ re->stats_draw(&re->i);
+
+ RE_Database_Free(re);
+}
+
+
+
+#endif /* disable yafray */
+
+static void renderresult_stampinfo()
+{
+ RenderResult rres;
+ /* this is the basic trick to get the displayed float or char rect from render result */
+ RE_GetResultImage(RE_GetRender(G.scene->id.name), &rres);
+ BKE_stamp_buf((unsigned char *)rres.rect32, rres.rectf, rres.rectx, rres.recty);
+}
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* main loop: doing sequence + fields + blur + 3d render + compositing */
+static void do_render_all_options(Render *re)
+{
+ re->i.starttime= PIL_check_seconds_timer();
+
+ /* ensure no images are in memory from previous animated sequences */
+ BKE_image_all_free_anim_ibufs(re->r.cfra);
+
+ if(re->r.scemode & R_DOSEQ) {
+ /* note: do_render_seq() frees rect32 when sequencer returns float images */
+ if(!re->test_break())
+ do_render_seq(re->result, re->r.cfra);
+
+ re->stats_draw(&re->i);
+ re->display_draw(re->result, NULL);
+
+ }
+ else {
+#ifndef DISABLE_YAFRAY
+ if(re->r.renderer==R_YAFRAY)
+ yafrayRender(re);
+ else
+ do_render_composite_fields_blur_3d(re);
+#else
+ do_render_composite_fields_blur_3d(re);
+#endif
+ }
+
+ /* for UI only */
+ renderresult_add_names(re->result);
+
+ re->i.lastframetime= PIL_check_seconds_timer()- re->i.starttime;
+
+ re->stats_draw(&re->i);
+
+ /* stamp image info here */
+ if((G.scene->r.scemode & R_STAMP_INFO) && (G.scene->r.stamp & R_STAMP_DRAW)) {
+ renderresult_stampinfo();
+ re->display_draw(re->result, NULL);
+ }
+}
+
+static int is_rendering_allowed(Render *re)
+{
+ SceneRenderLayer *srl;
+
+ /* forbidden combinations */
+ if(re->r.mode & R_PANORAMA) {
+ if(re->r.mode & R_BORDER) {
+ re->error("No border supported for Panorama");
+ return 0;
+ }
+ if(re->r.mode & R_ORTHO) {
+ re->error("No Ortho render possible for Panorama");
+ return 0;
+ }
+ }
+
+ if(re->r.mode & R_BORDER) {
+ if(re->r.border.xmax <= re->r.border.xmin ||
+ re->r.border.ymax <= re->r.border.ymin) {
+ re->error("No border area selected.");
+ return 0;
+ }
+ if(re->r.scemode & R_EXR_TILE_FILE) {
+ re->error("Border render and Buffer-save not supported yet");
+ return 0;
+ }
+ }
+
+ if(re->r.scemode & R_EXR_TILE_FILE) {
+ char str[FILE_MAX];
+
+ render_unique_exr_name(re, str);
+
+ if (BLI_is_writable(str)==0) {
+ re->error("Can not save render buffers, check the temp default path");
+ return 0;
+ }
+
+ }
+
+ if(re->r.scemode & R_DOCOMP) {
+ if(re->scene->use_nodes) {
+ bNodeTree *ntree= re->scene->nodetree;
+ bNode *node;
+
+ if(ntree==NULL) {
+ re->error("No Nodetree in Scene");
+ return 0;
+ }
+
+ for(node= ntree->nodes.first; node; node= node->next)
+ if(node->type==CMP_NODE_COMPOSITE)
+ break;
+
+
+ if(node==NULL) {
+ re->error("No Render Output Node in Scene");
+ return 0;
+ }
+ }
+ }
+
+ /* check valid camera, without camera render is OK (compo, seq) */
+ if(re->scene->camera==NULL)
+ re->scene->camera= scene_find_camera(re->scene);
+
+ if(!(re->r.scemode & (R_DOSEQ|R_DOCOMP))) {
+ if(re->scene->camera==NULL) {
+ re->error("No camera");
+ return 0;
+ }
+ }
+
+ /* layer flag tests */
+ if(re->r.scemode & R_SINGLE_LAYER) {
+ srl= BLI_findlink(&re->scene->r.layers, re->r.actlay);
+ /* force layer to be enabled */
+ srl->layflag &= ~SCE_LAY_DISABLE;
+ }
+
+ for(srl= re->scene->r.layers.first; srl; srl= srl->next)
+ if(!(srl->layflag & SCE_LAY_DISABLE))
+ break;
+ if(srl==NULL) {
+ re->error("All RenderLayers are disabled");
+ return 0;
+ }
+
+ /* renderer */
+ if(!ELEM(re->r.renderer, R_INTERN, R_YAFRAY)) {
+ re->error("Unknown render engine set");
+ return 0;
+ }
+ return 1;
+}
+
+/* evaluating scene options for general Blender render */
+static int render_initialize_from_scene(Render *re, Scene *scene)
+{
+ int winx, winy;
+ rcti disprect;
+
+ /* r.xsch and r.ysch has the actual view window size
+ r.border is the clipping rect */
+
+ /* calculate actual render result and display size */
+ winx= (scene->r.size*scene->r.xsch)/100;
+ winy= (scene->r.size*scene->r.ysch)/100;
+
+ /* we always render smaller part, inserting it in larger image is compositor bizz, it uses disprect for it */
+ if(scene->r.mode & R_BORDER) {
+ disprect.xmin= scene->r.border.xmin*winx;
+ disprect.xmax= scene->r.border.xmax*winx;
+
+ disprect.ymin= scene->r.border.ymin*winy;
+ disprect.ymax= scene->r.border.ymax*winy;
+ }
+ else {
+ disprect.xmin= disprect.ymin= 0;
+ disprect.xmax= winx;
+ disprect.ymax= winy;
+ }
+
+ if(scene->r.scemode & R_EXR_TILE_FILE) {
+ int partx= winx/scene->r.xparts, party= winy/scene->r.yparts;
+
+ /* stupid exr tiles dont like different sizes */
+ if(winx != partx*scene->r.xparts || winy != party*scene->r.yparts) {
+ re->error("Sorry... exr tile saving only allowed with equally sized parts");
+ return 0;
+ }
+ if((scene->r.mode & R_FIELDS) && (party & 1)) {
+ re->error("Sorry... exr tile saving only allowed with equally sized parts");
+ return 0;
+ }
+ }
+
+ if(scene->r.scemode & R_SINGLE_LAYER)
+ push_render_result(re);
+
+ RE_InitState(re, &scene->r, winx, winy, &disprect);
+
+ /* initstate makes new result, have to send changed tags around */
+ ntreeCompositTagRender(re->scene);
+
+ re->scene= scene;
+ if(!is_rendering_allowed(re))
+ return 0;
+
+ re->display_init(re->result);
+ re->display_clear(re->result);
+
+ return 1;
+}
+
+/* general Blender frame render call */
+void RE_BlenderFrame(Render *re, Scene *scene, int frame)
+{
+ /* ugly global still... is to prevent renderwin events and signal subsurfs etc to make full resol */
+ /* is also set by caller renderwin.c */
+ G.rendering= 1;
+
+ scene->r.cfra= frame;
+
+ if(render_initialize_from_scene(re, scene)) {
+ do_render_all_options(re);
+ }
+
+ /* UGLY WARNING */
+ G.rendering= 0;
+}
+
+static void do_write_image_or_movie(Render *re, Scene *scene, bMovieHandle *mh)
+{
+ char name[FILE_MAX];
+ RenderResult rres;
+
+ RE_GetResultImage(re, &rres);
+
+ /* write movie or image */
+ if(BKE_imtype_is_movie(scene->r.imtype)) {
+ int dofree = 0;
+ /* note; the way it gets 32 bits rects is weak... */
+ if(rres.rect32==NULL) {
+ rres.rect32= MEM_mapallocN(sizeof(int)*rres.rectx*rres.recty, "temp 32 bits rect");
+ dofree = 1;
+ }
+ RE_ResultGet32(re, (unsigned int *)rres.rect32);
+ mh->append_movie(scene->r.cfra, rres.rect32, rres.rectx, rres.recty);
+ if(dofree) {
+ MEM_freeN(rres.rect32);
+ }
+ printf("Append frame %d", scene->r.cfra);
+ }
+ else {
+ BKE_makepicstring(name, scene->r.pic, scene->r.cfra, scene->r.imtype);
+
+ if(re->r.imtype==R_MULTILAYER) {
+ if(re->result) {
+ RE_WriteRenderResult(re->result, name, scene->r.quality);
+ printf("Saved: %s", name);
+ }
+ }
+ else {
+ ImBuf *ibuf= IMB_allocImBuf(rres.rectx, rres.recty, scene->r.planes, 0, 0);
+ int ok;
+
+ /* if not exists, BKE_write_ibuf makes one */
+ ibuf->rect= (unsigned int *)rres.rect32;
+ ibuf->rect_float= rres.rectf;
+ ibuf->zbuf_float= rres.rectz;
+
+ /* float factor for random dither, imbuf takes care of it */
+ ibuf->dither= scene->r.dither_intensity;
+
+ ok= BKE_write_ibuf(ibuf, name, scene->r.imtype, scene->r.subimtype, scene->r.quality);
+
+ if(ok==0) {
+ printf("Render error: cannot save %s\n", name);
+ G.afbreek=1;
+ }
+ else printf("Saved: %s", name);
+
+ /* optional preview images for exr */
+ if(ok && scene->r.imtype==R_OPENEXR && (scene->r.subimtype & R_PREVIEW_JPG)) {
+ if(BLI_testextensie(name, ".exr"))
+ name[strlen(name)-4]= 0;
+ BKE_add_image_extension(name, R_JPEG90);
+ ibuf->depth= 24;
+ BKE_write_ibuf(ibuf, name, R_JPEG90, scene->r.subimtype, scene->r.quality);
+ printf("\nSaved: %s", name);
+ }
+
+ /* imbuf knows which rects are not part of ibuf */
+ IMB_freeImBuf(ibuf);
+ }
+ }
+
+ BLI_timestr(re->i.lastframetime, name);
+ printf(" Time: %s\n", name);
+ fflush(stdout); /* needed for renderd !! (not anymore... (ton)) */
+}
+
+/* saves images to disk */
+void RE_BlenderAnim(Render *re, Scene *scene, int sfra, int efra)
+{
+ bMovieHandle *mh= BKE_get_movie_handle(scene->r.imtype);
+ int cfrao= scene->r.cfra;
+
+ /* do not call for each frame, it initializes & pops output window */
+ if(!render_initialize_from_scene(re, scene))
+ return;
+
+ /* ugly global still... is to prevent renderwin events and signal subsurfs etc to make full resol */
+ /* is also set by caller renderwin.c */
+ G.rendering= 1;
+
+ if(BKE_imtype_is_movie(scene->r.imtype))
+ mh->start_movie(&re->r, re->rectx, re->recty);
+
+ if (mh->get_next_frame) {
+ while (!(G.afbreek == 1)) {
+ int nf = mh->get_next_frame();
+ if (nf >= 0 && nf >= scene->r.sfra && nf <= scene->r.efra) {
+ scene->r.cfra = re->r.cfra = nf;
+
+ do_render_all_options(re);
+
+ if(re->test_break() == 0) {
+ do_write_image_or_movie(re, scene, mh);
+ }
+ } else {
+ re->test_break();
+ }
+ }
+ } else {
+ for(scene->r.cfra= sfra;
+ scene->r.cfra<=efra; scene->r.cfra++) {
+ re->r.cfra= scene->r.cfra; /* weak.... */
+
+ do_render_all_options(re);
+
+ if(re->test_break() == 0) {
+ do_write_image_or_movie(re, scene, mh);
+ }
+
+ if(G.afbreek==1) break;
+ }
+ }
+
+ /* end movie */
+ if(BKE_imtype_is_movie(scene->r.imtype))
+ mh->end_movie();
+
+ scene->r.cfra= cfrao;
+
+ /* UGLY WARNING */
+ G.rendering= 0;
+}
+
+/* note; repeated win/disprect calc... solve that nicer, also in compo */
+
+/* only temp file! */
+void RE_ReadRenderResult(Scene *scene, Scene *scenode)
+{
+ Render *re;
+ int winx, winy;
+ rcti disprect;
+
+ /* calculate actual render result and display size */
+ winx= (scene->r.size*scene->r.xsch)/100;
+ winy= (scene->r.size*scene->r.ysch)/100;
+
+ /* only in movie case we render smaller part */
+ if(scene->r.mode & R_BORDER) {
+ disprect.xmin= scene->r.border.xmin*winx;
+ disprect.xmax= scene->r.border.xmax*winx;
+
+ disprect.ymin= scene->r.border.ymin*winy;
+ disprect.ymax= scene->r.border.ymax*winy;
+ }
+ else {
+ disprect.xmin= disprect.ymin= 0;
+ disprect.xmax= winx;
+ disprect.ymax= winy;
+ }
+
+ if(scenode)
+ scene= scenode;
+
+ re= RE_NewRender(scene->id.name);
+ RE_InitState(re, &scene->r, winx, winy, &disprect);
+ re->scene= scene;
+
+ read_render_result(re);
+}
+
+void RE_set_max_threads(int threads)
+{
+ if(threads>0 && threads<=BLENDER_MAX_THREADS)
+ commandline_threads= threads;
+ else
+ printf("Error, threads has to be in range 1-%d\n", BLENDER_MAX_THREADS);
+}
diff --git a/source/blender/render/intern/source/pixelblending.c b/source/blender/render/intern/source/pixelblending.c
new file mode 100644
index 00000000000..119cceaf3c2
--- /dev/null
+++ b/source/blender/render/intern/source/pixelblending.c
@@ -0,0 +1,288 @@
+/*
+ * pixelblending.c
+ *
+ * Functions to blend pixels with or without alpha, in various formats
+ * nzc - June 2000
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Full recode, 2004-2006 Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <math.h>
+
+/* global includes */
+#include "BLI_arithb.h"
+#include "BLI_rand.h"
+
+/* own includes */
+#include "render_types.h"
+#include "renderpipeline.h"
+#include "pixelblending.h"
+#include "gammaCorrectionTables.h"
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
+/* only to be used here in this file, it's for speed */
+extern struct Render R;
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+
+/* ------------------------------------------------------------------------- */
+/* Debug/behaviour defines */
+/* if defined: alpha blending with floats clips color, as with shorts */
+/* #define RE_FLOAT_COLOR_CLIPPING */
+/* if defined: alpha values are clipped */
+/* For now, we just keep alpha clipping. We run into thresholding and */
+/* blending difficulties otherwise. Be careful here. */
+#define RE_ALPHA_CLIPPING
+
+
+
+/* Threshold for a 'full' pixel: pixels with alpha above this level are */
+/* considered opaque This is the decimal value for 0xFFF0 / 0xFFFF */
+#define RE_FULL_COLOR_FLOAT 0.9998
+/* Threshold for an 'empty' pixel: pixels with alpha above this level are */
+/* considered completely transparent. This is the decimal value */
+/* for 0x000F / 0xFFFF */
+#define RE_EMPTY_COLOR_FLOAT 0.0002
+
+
+/* ------------------------------------------------------------------------- */
+
+void addAlphaOverFloat(float *dest, float *source)
+{
+ /* d = s + (1-alpha_s)d*/
+ float mul;
+
+ mul= 1.0 - source[3];
+
+ dest[0]= (mul*dest[0]) + source[0];
+ dest[1]= (mul*dest[1]) + source[1];
+ dest[2]= (mul*dest[2]) + source[2];
+ dest[3]= (mul*dest[3]) + source[3];
+
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+void addAlphaUnderFloat(float *dest, float *source)
+{
+ float mul;
+
+ if( (-RE_EMPTY_COLOR_FLOAT < dest[3])
+ && (dest[3] < RE_EMPTY_COLOR_FLOAT) ) {
+ dest[0] = source[0];
+ dest[1] = source[1];
+ dest[2] = source[2];
+ dest[3] = source[3];
+ return;
+ }
+
+ mul= 1.0 - dest[3];
+
+ dest[0]+= (mul*source[0]);
+ dest[1]+= (mul*source[1]);
+ dest[2]+= (mul*source[2]);
+ dest[3]+= (mul*source[3]);
+}
+
+
+/* ------------------------------------------------------------------------- */
+void addalphaAddfacFloat(float *dest, float *source, char addfac)
+{
+ float m; /* weiging factor of destination */
+ float c; /* intermediate color */
+
+ /* Addfac is a number between 0 and 1: rescale */
+ /* final target is to diminish the influence of dest when addfac rises */
+ m = 1.0 - ( source[3] * ((255.0 - addfac) / 255.0));
+
+ /* blend colors*/
+ c= (m * dest[0]) + source[0];
+#ifdef RE_FLOAT_COLOR_CLIPPING
+ if(c >= RE_FULL_COLOR_FLOAT) dest[0] = RE_FULL_COLOR_FLOAT;
+ else
+#endif
+ dest[0]= c;
+
+ c= (m * dest[1]) + source[1];
+#ifdef RE_FLOAT_COLOR_CLIPPING
+ if(c >= RE_FULL_COLOR_FLOAT) dest[1] = RE_FULL_COLOR_FLOAT;
+ else
+#endif
+ dest[1]= c;
+
+ c= (m * dest[2]) + source[2];
+#ifdef RE_FLOAT_COLOR_CLIPPING
+ if(c >= RE_FULL_COLOR_FLOAT) dest[2] = RE_FULL_COLOR_FLOAT;
+ else
+#endif
+ dest[2]= c;
+
+ c= (m * dest[3]) + source[3];
+#ifdef RE_ALPHA_CLIPPING
+ if(c >= RE_FULL_COLOR_FLOAT) dest[3] = RE_FULL_COLOR_FLOAT;
+ else
+#endif
+ dest[3]= c;
+
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+/* filtered adding to scanlines */
+void add_filt_fmask(unsigned int mask, float *col, float *rowbuf, int row_w)
+{
+ /* calc the value of mask */
+ float **fmask1= R.samples->fmask1, **fmask2=R.samples->fmask2;
+ float *rb1, *rb2, *rb3;
+ float val, r, g, b, al;
+ unsigned int a, maskand, maskshift;
+ int j;
+
+ r= col[0];
+ g= col[1];
+ b= col[2];
+ al= col[3];
+
+ rb2= rowbuf-4;
+ rb3= rb2-4*row_w;
+ rb1= rb2+4*row_w;
+
+ maskand= (mask & 255);
+ maskshift= (mask >>8);
+
+ for(j=2; j>=0; j--) {
+
+ a= j;
+
+ val= *(fmask1[a] +maskand) + *(fmask2[a] +maskshift);
+ if(val!=0.0) {
+ rb1[0]+= val*r;
+ rb1[1]+= val*g;
+ rb1[2]+= val*b;
+ rb1[3]+= val*al;
+ }
+ a+=3;
+
+ val= *(fmask1[a] +maskand) + *(fmask2[a] +maskshift);
+ if(val!=0.0) {
+ rb2[0]+= val*r;
+ rb2[1]+= val*g;
+ rb2[2]+= val*b;
+ rb2[3]+= val*al;
+ }
+ a+=3;
+
+ val= *(fmask1[a] +maskand) + *(fmask2[a] +maskshift);
+ if(val!=0.0) {
+ rb3[0]+= val*r;
+ rb3[1]+= val*g;
+ rb3[2]+= val*b;
+ rb3[3]+= val*al;
+ }
+
+ rb1+= 4;
+ rb2+= 4;
+ rb3+= 4;
+ }
+}
+
+void add_filt_fmask_pixsize(unsigned int mask, float *in, float *rowbuf, int row_w, int pixsize)
+{
+ /* calc the value of mask */
+ float **fmask1= R.samples->fmask1, **fmask2=R.samples->fmask2;
+ float *rb1, *rb2, *rb3;
+ float val;
+ unsigned int a, maskand, maskshift;
+ int i, j;
+
+ rb2= rowbuf-pixsize;
+ rb3= rb2-pixsize*row_w;
+ rb1= rb2+pixsize*row_w;
+
+ maskand= (mask & 255);
+ maskshift= (mask >>8);
+
+ for(j=2; j>=0; j--) {
+
+ a= j;
+
+ val= *(fmask1[a] +maskand) + *(fmask2[a] +maskshift);
+ if(val!=0.0) {
+ for(i= 0; i<pixsize; i++)
+ rb1[i]+= val*in[i];
+ }
+ a+=3;
+
+ val= *(fmask1[a] +maskand) + *(fmask2[a] +maskshift);
+ if(val!=0.0) {
+ for(i= 0; i<pixsize; i++)
+ rb2[i]+= val*in[i];
+ }
+ a+=3;
+
+ val= *(fmask1[a] +maskand) + *(fmask2[a] +maskshift);
+ if(val!=0.0) {
+ for(i= 0; i<pixsize; i++)
+ rb3[i]+= val*in[i];
+ }
+
+ rb1+= pixsize;
+ rb2+= pixsize;
+ rb3+= pixsize;
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+void addalphaAddFloat(float *dest, float *source)
+{
+
+ /* Makes me wonder whether this is required... */
+ if( dest[3] < RE_EMPTY_COLOR_FLOAT) {
+ dest[0] = source[0];
+ dest[1] = source[1];
+ dest[2] = source[2];
+ dest[3] = source[3];
+ return;
+ }
+
+ /* no clipping! */
+ dest[0] = dest[0]+source[0];
+ dest[1] = dest[1]+source[1];
+ dest[2] = dest[2]+source[2];
+ dest[3] = dest[3]+source[3];
+
+}
+
+
+/* ---------------------------------------------------------------------------- */
+
+
+/* eof pixelblending.c */
+
+
diff --git a/source/blender/render/intern/source/pixelshading.c b/source/blender/render/intern/source/pixelshading.c
new file mode 100644
index 00000000000..cffed99c738
--- /dev/null
+++ b/source/blender/render/intern/source/pixelshading.c
@@ -0,0 +1,571 @@
+/**
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): 2004-2006, Blender Foundation, full recode
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <math.h>
+#include "BLI_arithb.h"
+
+/* External modules: */
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+#include "MTC_matrixops.h"
+#include "MTC_vectorops.h"
+
+#include "DNA_camera_types.h"
+#include "DNA_group_types.h"
+#include "DNA_material_types.h"
+#include "DNA_object_types.h"
+#include "DNA_image_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_lamp_types.h"
+
+#include "BKE_image.h"
+#include "BKE_global.h"
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
+
+/* own module */
+#include "render_types.h"
+#include "renderpipeline.h"
+#include "renderdatabase.h"
+#include "texture.h"
+#include "pixelblending.h"
+#include "rendercore.h"
+#include "shadbuf.h"
+#include "pixelshading.h"
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
+/* only to be used here in this file, it's for speed */
+extern struct Render R;
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+
+extern float hashvectf[];
+
+static void render_lighting_halo(HaloRen *har, float *colf)
+{
+ GroupObject *go;
+ LampRen *lar;
+ float i, inp, inpr, rco[3], dco[3], lv[3], lampdist, ld, t, *vn;
+ float ir, ig, ib, shadfac, soft, lacol[3];
+
+ ir= ig= ib= 0.0;
+
+ VECCOPY(rco, har->co);
+ dco[0]=dco[1]=dco[2]= 1.0/har->rad;
+
+ vn= har->no;
+
+ for(go=R.lights.first; go; go= go->next) {
+ lar= go->lampren;
+
+ /* test for lamplayer */
+ if(lar->mode & LA_LAYER) if((lar->lay & har->lay)==0) continue;
+
+ /* lampdist cacluation */
+ if(lar->type==LA_SUN || lar->type==LA_HEMI) {
+ VECCOPY(lv, lar->vec);
+ lampdist= 1.0;
+ }
+ else {
+ lv[0]= rco[0]-lar->co[0];
+ lv[1]= rco[1]-lar->co[1];
+ lv[2]= rco[2]-lar->co[2];
+ ld= sqrt(lv[0]*lv[0]+lv[1]*lv[1]+lv[2]*lv[2]);
+ lv[0]/= ld;
+ lv[1]/= ld;
+ lv[2]/= ld;
+
+ /* ld is re-used further on (texco's) */
+
+ if(lar->mode & LA_QUAD) {
+ t= 1.0;
+ if(lar->ld1>0.0)
+ t= lar->dist/(lar->dist+lar->ld1*ld);
+ if(lar->ld2>0.0)
+ t*= lar->distkw/(lar->distkw+lar->ld2*ld*ld);
+
+ lampdist= t;
+ }
+ else {
+ lampdist= (lar->dist/(lar->dist+ld));
+ }
+
+ if(lar->mode & LA_SPHERE) {
+ t= lar->dist - ld;
+ if(t<0.0) continue;
+
+ t/= lar->dist;
+ lampdist*= (t);
+ }
+
+ }
+
+ lacol[0]= lar->r;
+ lacol[1]= lar->g;
+ lacol[2]= lar->b;
+
+ if(lar->mode & LA_TEXTURE) {
+ ShadeInput shi;
+ VECCOPY(shi.co, rco);
+ shi.osatex= 0;
+ do_lamp_tex(lar, lv, &shi, lacol);
+ }
+
+ if(lar->type==LA_SPOT) {
+
+ if(lar->mode & LA_SQUARE) {
+ if(lv[0]*lar->vec[0]+lv[1]*lar->vec[1]+lv[2]*lar->vec[2]>0.0) {
+ float x, lvrot[3];
+
+ /* rotate view to lampspace */
+ VECCOPY(lvrot, lv);
+ MTC_Mat3MulVecfl(lar->imat, lvrot);
+
+ x= MAX2(fabs(lvrot[0]/lvrot[2]) , fabs(lvrot[1]/lvrot[2]));
+ /* 1.0/(sqrt(1+x*x)) is equivalent to cos(atan(x)) */
+
+ inpr= 1.0/(sqrt(1.0+x*x));
+ }
+ else inpr= 0.0;
+ }
+ else {
+ inpr= lv[0]*lar->vec[0]+lv[1]*lar->vec[1]+lv[2]*lar->vec[2];
+ }
+
+ t= lar->spotsi;
+ if(inpr<t) continue;
+ else {
+ t= inpr-t;
+ i= 1.0;
+ soft= 1.0;
+ if(t<lar->spotbl && lar->spotbl!=0.0) {
+ /* soft area */
+ i= t/lar->spotbl;
+ t= i*i;
+ soft= (3.0*t-2.0*t*i);
+ inpr*= soft;
+ }
+ if(lar->mode & LA_ONLYSHADOW) {
+ /* if(ma->mode & MA_SHADOW) { */
+ /* dot product positive: front side face! */
+ inp= vn[0]*lv[0] + vn[1]*lv[1] + vn[2]*lv[2];
+ if(inp>0.0) {
+ /* testshadowbuf==0.0 : 100% shadow */
+ shadfac = testshadowbuf(lar->shb, rco, dco, dco, inp);
+ if( shadfac>0.0 ) {
+ shadfac*= inp*soft*lar->energy;
+ ir -= shadfac;
+ ig -= shadfac;
+ ib -= shadfac;
+
+ continue;
+ }
+ }
+ /* } */
+ }
+ lampdist*=inpr;
+ }
+ if(lar->mode & LA_ONLYSHADOW) continue;
+
+ }
+
+ /* dot product and reflectivity*/
+
+ inp= 1.0-fabs(vn[0]*lv[0] + vn[1]*lv[1] + vn[2]*lv[2]);
+
+ /* inp= cos(0.5*M_PI-acos(inp)); */
+
+ i= inp;
+
+ if(lar->type==LA_HEMI) {
+ i= 0.5*i+0.5;
+ }
+ if(i>0.0) {
+ i*= lampdist;
+ }
+
+ /* shadow */
+ if(i> -0.41) { /* heuristic valua! */
+ shadfac= 1.0;
+ if(lar->shb) {
+ shadfac = testshadowbuf(lar->shb, rco, dco, dco, inp);
+ if(shadfac==0.0) continue;
+ i*= shadfac;
+ }
+ }
+
+ if(i>0.0) {
+ ir+= i*lacol[0];
+ ig+= i*lacol[1];
+ ib+= i*lacol[2];
+ }
+ }
+
+ if(ir<0.0) ir= 0.0;
+ if(ig<0.0) ig= 0.0;
+ if(ib<0.0) ib= 0.0;
+
+ colf[0]*= ir;
+ colf[1]*= ig;
+ colf[2]*= ib;
+
+}
+
+
+
+void shadeHaloFloat(HaloRen *har, float *col, int zz,
+ float dist, float xn, float yn, short flarec)
+{
+ /* fill in col */
+ float t, zn, radist, ringf=0.0f, linef=0.0f, alpha, si, co;
+ int a;
+
+ if(R.wrld.mode & WO_MIST) {
+ if(har->type & HA_ONLYSKY) {
+ /* stars but no mist */
+ alpha= har->alfa;
+ }
+ else {
+ /* a bit patchy... */
+ alpha= mistfactor(-har->co[2], har->co)*har->alfa;
+ }
+ }
+ else alpha= har->alfa;
+
+ if(alpha==0.0) {
+ col[0] = 0.0;
+ col[1] = 0.0;
+ col[2] = 0.0;
+ col[3] = 0.0;
+ return;
+ }
+
+ radist= sqrt(dist);
+
+ /* watch it: not used nicely: flarec is set at zero in pixstruct */
+ if(flarec) har->pixels+= (int)(har->rad-radist);
+
+ if(har->ringc) {
+ float *rc, fac;
+ int ofs;
+
+ /* per ring an antialised circle */
+ ofs= har->seed;
+
+ for(a= har->ringc; a>0; a--, ofs+=2) {
+
+ rc= hashvectf + (ofs % 768);
+
+ fac= fabs( rc[1]*(har->rad*fabs(rc[0]) - radist) );
+
+ if(fac< 1.0) {
+ ringf+= (1.0-fac);
+ }
+ }
+ }
+
+ if(har->type & HA_VECT) {
+ dist= fabs( har->cos*(yn) - har->sin*(xn) )/har->rad;
+ if(dist>1.0) dist= 1.0;
+ if(har->tex) {
+ zn= har->sin*xn - har->cos*yn;
+ yn= har->cos*xn + har->sin*yn;
+ xn= zn;
+ }
+ }
+ else dist= dist/har->radsq;
+
+ if(har->type & HA_FLARECIRC) {
+
+ dist= 0.5+fabs(dist-0.5);
+
+ }
+
+ if(har->hard>=30) {
+ dist= sqrt(dist);
+ if(har->hard>=40) {
+ dist= sin(dist*M_PI_2);
+ if(har->hard>=50) {
+ dist= sqrt(dist);
+ }
+ }
+ }
+ else if(har->hard<20) dist*=dist;
+
+ if(dist < 1.0f)
+ dist= (1.0f-dist);
+ else
+ dist= 0.0f;
+
+ if(har->linec) {
+ float *rc, fac;
+ int ofs;
+
+ /* per starpoint an antialiased line */
+ ofs= har->seed;
+
+ for(a= har->linec; a>0; a--, ofs+=3) {
+
+ rc= hashvectf + (ofs % 768);
+
+ fac= fabs( (xn)*rc[0]+(yn)*rc[1]);
+
+ if(fac< 1.0f )
+ linef+= (1.0f-fac);
+ }
+
+ linef*= dist;
+ }
+
+ if(har->starpoints) {
+ float ster, angle;
+ /* rotation */
+ angle= atan2(yn, xn);
+ angle*= (1.0+0.25*har->starpoints);
+
+ co= cos(angle);
+ si= sin(angle);
+
+ angle= (co*xn+si*yn)*(co*yn-si*xn);
+
+ ster= fabs(angle);
+ if(ster>1.0) {
+ ster= (har->rad)/(ster);
+
+ if(ster<1.0) dist*= sqrt(ster);
+ }
+ }
+
+ /* halo being intersected? */
+ if(har->zs> zz-har->zd) {
+ t= ((float)(zz-har->zs))/(float)har->zd;
+ alpha*= sqrt(sqrt(t));
+ }
+
+ /* disputable optimize... (ton) */
+ if(dist<=0.00001) {
+ col[0] = 0.0;
+ col[1] = 0.0;
+ col[2] = 0.0;
+ col[3] = 0.0;
+ return;
+ }
+
+ dist*= alpha;
+ ringf*= dist;
+ linef*= alpha;
+
+ /* The color is either the rgb spec-ed by the user, or extracted from */
+ /* the texture */
+ if(har->tex) {
+ col[0]= har->r;
+ col[1]= har->g;
+ col[2]= har->b;
+ col[3]= dist;
+
+ do_halo_tex(har, xn, yn, col);
+
+ col[0]*= col[3];
+ col[1]*= col[3];
+ col[2]*= col[3];
+
+ }
+ else {
+ col[0]= dist*har->r;
+ col[1]= dist*har->g;
+ col[2]= dist*har->b;
+ if(har->type & HA_XALPHA) col[3]= dist*dist;
+ else col[3]= dist;
+ }
+
+ if(har->mat) {
+ if(har->mat->mode & MA_HALO_SHADE) {
+ /* we test for lights because of preview... */
+ if(R.lights.first) render_lighting_halo(har, col);
+ }
+
+ /* Next, we do the line and ring factor modifications. */
+ if(linef!=0.0) {
+ Material *ma= har->mat;
+
+ col[0]+= linef * ma->specr;
+ col[1]+= linef * ma->specg;
+ col[2]+= linef * ma->specb;
+
+ if(har->type & HA_XALPHA) col[3]+= linef*linef;
+ else col[3]+= linef;
+ }
+ if(ringf!=0.0) {
+ Material *ma= har->mat;
+
+ col[0]+= ringf * ma->mirr;
+ col[1]+= ringf * ma->mirg;
+ col[2]+= ringf * ma->mirb;
+
+ if(har->type & HA_XALPHA) col[3]+= ringf*ringf;
+ else col[3]+= ringf;
+ }
+ }
+
+ /* alpha requires clip, gives black dots */
+ if(col[3] > 1.0f)
+ col[3]= 1.0f;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void fillBackgroundImage(float *collector, float fx, float fy)
+{
+ collector[0] = 0.0;
+ collector[1] = 0.0;
+ collector[2] = 0.0;
+ collector[3] = 0.0;
+
+ if(R.backbuf) {
+ float dx= 1.0f/(float)R.winx;
+ float dy= 1.0f/(float)R.winy;
+
+ image_sample(R.backbuf, fx*dx, fy*dy, dx, dy, collector);
+ }
+}
+
+/* Only view vector is important here. Result goes to colf[3] */
+void shadeSkyView(float *colf, float *rco, float *view, float *dxyview)
+{
+ float lo[3], zen[3], hor[3], blend, blendm;
+ int skyflag;
+
+ /* flag indicating if we render the top hemisphere */
+ skyflag = WO_ZENUP;
+
+ /* Some view vector stuff. */
+ if(R.wrld.skytype & WO_SKYREAL) {
+
+ blend= view[0]*R.grvec[0]+ view[1]*R.grvec[1]+ view[2]*R.grvec[2];
+
+ if(blend<0.0) skyflag= 0;
+
+ blend= fabs(blend);
+ }
+ else if(R.wrld.skytype & WO_SKYPAPER) {
+ blend= 0.5+ 0.5*view[1];
+ }
+ else {
+ /* the fraction of how far we are above the bottom of the screen */
+ blend= fabs(0.5+ view[1]);
+ }
+
+ hor[0]= R.wrld.horr; hor[1]= R.wrld.horg; hor[2]= R.wrld.horb;
+ zen[0]= R.wrld.zenr; zen[1]= R.wrld.zeng; zen[2]= R.wrld.zenb;
+
+ /* Careful: SKYTEX and SKYBLEND are NOT mutually exclusive! If */
+ /* SKYBLEND is active, the texture and color blend are added. */
+ if(R.wrld.skytype & WO_SKYTEX) {
+ VECCOPY(lo, view);
+ if(R.wrld.skytype & WO_SKYREAL) {
+
+ MTC_Mat3MulVecfl(R.imat, lo);
+
+ SWAP(float, lo[1], lo[2]);
+
+ }
+ do_sky_tex(rco, lo, dxyview, hor, zen, &blend, skyflag);
+ }
+
+ if(blend>1.0) blend= 1.0;
+ blendm= 1.0-blend;
+
+ /* No clipping, no conversion! */
+ if(R.wrld.skytype & WO_SKYBLEND) {
+ colf[0] = (blendm*hor[0] + blend*zen[0]);
+ colf[1] = (blendm*hor[1] + blend*zen[1]);
+ colf[2] = (blendm*hor[2] + blend*zen[2]);
+ } else {
+ /* Done when a texture was grabbed. */
+ colf[0]= hor[0];
+ colf[1]= hor[1];
+ colf[2]= hor[2];
+ }
+}
+
+/*
+ Stuff the sky color into the collector.
+ */
+void shadeSkyPixel(float *collector, float fx, float fy)
+{
+ float view[3], dxyview[2];
+
+ /*
+ The rules for sky:
+ 1. Draw an image, if a background image was provided. Stop
+ 2. get texture and color blend, and combine these.
+ */
+
+ float fac;
+
+ /* 1. Do a backbuffer image: */
+ if(R.r.bufflag & 1) {
+ fillBackgroundImage(collector, fx, fy);
+ return;
+ }
+ else if((R.wrld.skytype & (WO_SKYBLEND+WO_SKYTEX))==0) {
+ /* 2. solid color */
+ collector[0] = R.wrld.horr;
+ collector[1] = R.wrld.horg;
+ collector[2] = R.wrld.horb;
+ collector[3] = 0.0f;
+ }
+ else {
+ /* 3. */
+
+ /* This one true because of the context of this routine */
+ if(R.wrld.skytype & WO_SKYPAPER) {
+ view[0]= -1.0f + 2.0f*(fx/(float)R.winx);
+ view[1]= -1.0f + 2.0f*(fy/(float)R.winy);
+ view[2]= 0.0;
+
+ dxyview[0]= 1.0f/(float)R.winx;
+ dxyview[1]= 1.0f/(float)R.winy;
+ }
+ else {
+ calc_view_vector(view, fx, fy);
+ fac= Normalize(view);
+
+ if(R.wrld.skytype & WO_SKYTEX) {
+ dxyview[0]= -R.viewdx/fac;
+ dxyview[1]= -R.viewdy/fac;
+ }
+ }
+
+ /* get sky color in the collector */
+ shadeSkyView(collector, NULL, view, dxyview);
+ collector[3] = 0.0f;
+ }
+}
+
+
+/* eof */
diff --git a/source/blender/render/intern/source/rayshade.c b/source/blender/render/intern/source/rayshade.c
new file mode 100644
index 00000000000..49448f2d727
--- /dev/null
+++ b/source/blender/render/intern/source/rayshade.c
@@ -0,0 +1,2025 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 1990-1998 NeoGeo BV.
+ * All rights reserved.
+ *
+ * Contributors: 2004/2005 Blender Foundation, full recode
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <math.h>
+#include <string.h>
+#include <stdlib.h>
+#include <float.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_material_types.h"
+#include "DNA_lamp_types.h"
+
+#include "BKE_global.h"
+#include "BKE_node.h"
+#include "BKE_utildefines.h"
+
+#include "BLI_arithb.h"
+#include "BLI_rand.h"
+#include "BLI_jitter.h"
+
+#include "PIL_time.h"
+
+#include "render_types.h"
+#include "renderpipeline.h"
+#include "rendercore.h"
+#include "renderdatabase.h"
+#include "pixelblending.h"
+#include "pixelshading.h"
+#include "shading.h"
+#include "texture.h"
+
+#include "RE_raytrace.h"
+
+#define RAY_TRA 1
+#define RAY_TRAFLIP 2
+
+#define DEPTH_SHADOW_TRA 10
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
+/* only to be used here in this file, it's for speed */
+extern struct Render R;
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+static void vlr_face_coords(RayFace *face, float **v1, float **v2, float **v3, float **v4)
+{
+ VlakRen *vlr= (VlakRen*)face;
+
+ *v1 = (vlr->v1)? vlr->v1->co: NULL;
+ *v2 = (vlr->v2)? vlr->v2->co: NULL;
+ *v3 = (vlr->v3)? vlr->v3->co: NULL;
+ *v4 = (vlr->v4)? vlr->v4->co: NULL;
+}
+
+static int vlr_check_intersect(Isect *is, RayFace *face)
+{
+ VlakRen *vlr = (VlakRen*)face;
+
+ /* I know... cpu cycle waste, might do smarter once */
+ if(is->mode==RE_RAY_MIRROR)
+ return !(vlr->mat->mode & MA_ONLYCAST);
+ else
+ return (is->lay & vlr->lay);
+}
+
+void freeraytree(Render *re)
+{
+ if(re->raytree) {
+ RE_ray_tree_free(re->raytree);
+ re->raytree= NULL;
+ }
+}
+
+void makeraytree(Render *re)
+{
+ VlakRen *vlr= NULL;
+ float min[3], max[3];
+ double lasttime= PIL_check_seconds_timer();
+ int v, totface = 0;
+
+ INIT_MINMAX(min, max);
+
+ /* first min max raytree space */
+ for(v=0;v<re->totvlak;v++) {
+ if((v & 255)==0) vlr= re->vlaknodes[v>>8].vlak;
+ else vlr++;
+ if(vlr->mat->mode & MA_TRACEBLE) {
+ if((vlr->mat->mode & MA_WIRE)==0) {
+
+ DO_MINMAX(vlr->v1->co, min, max);
+ DO_MINMAX(vlr->v2->co, min, max);
+ DO_MINMAX(vlr->v3->co, min, max);
+ if(vlr->v4) {
+ DO_MINMAX(vlr->v4->co, min, max);
+ }
+
+ totface++;
+ }
+ }
+ }
+
+ re->raytree= RE_ray_tree_create(re->r.ocres, totface, min, max, vlr_face_coords, vlr_check_intersect);
+
+ if(min[0] > max[0]) { /* empty raytree */
+ RE_ray_tree_done(re->raytree);
+ return;
+ }
+
+ for(v=0; v<re->totvlak; v++) {
+ if((v & 255)==0) {
+ double time= PIL_check_seconds_timer();
+
+ vlr= re->vlaknodes[v>>8].vlak;
+ if(re->test_break())
+ break;
+ if(time-lasttime>1.0f) {
+ char str[32];
+ sprintf(str, "Filling Octree: %d", v);
+ re->i.infostr= str;
+ re->stats_draw(&re->i);
+ re->i.infostr= NULL;
+ lasttime= time;
+ }
+ }
+ else vlr++;
+
+ if(vlr->mat->mode & MA_TRACEBLE) {
+ if((vlr->mat->mode & MA_WIRE)==0) {
+ RE_ray_tree_add_face(re->raytree, (RayFace*)vlr);
+ }
+ }
+ }
+
+ RE_ray_tree_done(re->raytree);
+
+ re->i.infostr= NULL;
+ re->stats_draw(&re->i);
+}
+
+static void shade_ray(Isect *is, ShadeInput *shi, ShadeResult *shr)
+{
+ VlakRen *vlr= (VlakRen*)is->face;
+ int osatex= 0, norflip;
+
+ /* set up view vector */
+ VECCOPY(shi->view, is->vec);
+
+ /* render co */
+ shi->co[0]= is->start[0]+is->labda*(shi->view[0]);
+ shi->co[1]= is->start[1]+is->labda*(shi->view[1]);
+ shi->co[2]= is->start[2]+is->labda*(shi->view[2]);
+
+ Normalize(shi->view);
+
+ shi->vlr= vlr;
+ shi->mat= vlr->mat;
+ memcpy(&shi->r, &shi->mat->r, 23*sizeof(float)); // note, keep this synced with render_types.h
+ shi->har= shi->mat->har;
+
+ // Osa structs we leave unchanged now
+ SWAP(int, osatex, shi->osatex);
+
+ shi->dxco[0]= shi->dxco[1]= shi->dxco[2]= 0.0f;
+ shi->dyco[0]= shi->dyco[1]= shi->dyco[2]= 0.0f;
+
+ // but, set Osa stuff to zero where it can confuse texture code
+ if(shi->mat->texco & (TEXCO_NORM|TEXCO_REFL) ) {
+ shi->dxno[0]= shi->dxno[1]= shi->dxno[2]= 0.0f;
+ shi->dyno[0]= shi->dyno[1]= shi->dyno[2]= 0.0f;
+ }
+
+ /* face normal, check for flip, need to set puno here */
+ norflip= (vlr->n[0]*shi->view[0]+vlr->n[1]*shi->view[1]+vlr->n[2]*shi->view[2]) < 0.0f;
+
+ if(norflip)
+ shi->puno= vlr->puno ^ 15;// only flip lower 4 bits
+ else
+ shi->puno= vlr->puno;
+
+ if(vlr->v4) {
+ if(is->isect==2)
+ shade_input_set_triangle_i(shi, vlr, 2, 1, 3);
+ else
+ shade_input_set_triangle_i(shi, vlr, 0, 1, 3);
+ }
+ else {
+ shade_input_set_triangle_i(shi, vlr, 0, 1, 2);
+ }
+
+ /* shade_input_set_triangle_i() sets facenor, now we flip */
+ if(norflip) {
+ shi->facenor[0]= -vlr->n[0];
+ shi->facenor[1]= -vlr->n[1];
+ shi->facenor[2]= -vlr->n[2];
+ }
+
+ shi->u= is->u;
+ shi->v= is->v;
+ shi->dx_u= shi->dx_v= shi->dy_u= shi->dy_v= 0.0f;
+ shade_input_set_normals(shi);
+ shade_input_set_shade_texco(shi);
+
+ if(is->mode==RE_RAY_SHADOW_TRA)
+ shade_color(shi, shr);
+ else {
+ if(shi->mat->nodetree && shi->mat->use_nodes) {
+ ntreeShaderExecTree(shi->mat->nodetree, shi, shr);
+ shi->mat= vlr->mat; /* shi->mat is being set in nodetree */
+ }
+ else
+ shade_material_loop(shi, shr);
+
+ /* raytrace likes to separate the spec color */
+ VECSUB(shr->diff, shr->combined, shr->spec);
+ }
+
+ SWAP(int, osatex, shi->osatex); // XXXXX!!!!
+
+}
+
+static int refraction(float *refract, float *n, float *view, float index)
+{
+ float dot, fac;
+
+ VECCOPY(refract, view);
+
+ dot= view[0]*n[0] + view[1]*n[1] + view[2]*n[2];
+
+ if(dot>0.0f) {
+ index = 1.0f/index;
+ fac= 1.0f - (1.0f - dot*dot)*index*index;
+ if(fac<= 0.0f) return 0;
+ fac= -dot*index + sqrt(fac);
+ }
+ else {
+ fac= 1.0f - (1.0f - dot*dot)*index*index;
+ if(fac<= 0.0f) return 0;
+ fac= -dot*index - sqrt(fac);
+ }
+
+ refract[0]= index*view[0] + fac*n[0];
+ refract[1]= index*view[1] + fac*n[1];
+ refract[2]= index*view[2] + fac*n[2];
+
+ return 1;
+}
+
+/* orn = original face normal */
+static void reflection(float *ref, float *n, float *view, float *orn)
+{
+ float f1;
+
+ f1= -2.0f*(n[0]*view[0]+ n[1]*view[1]+ n[2]*view[2]);
+
+ ref[0]= (view[0]+f1*n[0]);
+ ref[1]= (view[1]+f1*n[1]);
+ ref[2]= (view[2]+f1*n[2]);
+
+ if(orn) {
+ /* test phong normals, then we should prevent vector going to the back */
+ f1= ref[0]*orn[0]+ ref[1]*orn[1]+ ref[2]*orn[2];
+ if(f1>0.0f) {
+ f1+= .01f;
+ ref[0]-= f1*orn[0];
+ ref[1]-= f1*orn[1];
+ ref[2]-= f1*orn[2];
+ }
+ }
+}
+
+#if 0
+static void color_combine(float *result, float fac1, float fac2, float *col1, float *col2)
+{
+ float col1t[3], col2t[3];
+
+ col1t[0]= sqrt(col1[0]);
+ col1t[1]= sqrt(col1[1]);
+ col1t[2]= sqrt(col1[2]);
+ col2t[0]= sqrt(col2[0]);
+ col2t[1]= sqrt(col2[1]);
+ col2t[2]= sqrt(col2[2]);
+
+ result[0]= (fac1*col1t[0] + fac2*col2t[0]);
+ result[0]*= result[0];
+ result[1]= (fac1*col1t[1] + fac2*col2t[1]);
+ result[1]*= result[1];
+ result[2]= (fac1*col1t[2] + fac2*col2t[2]);
+ result[2]*= result[2];
+}
+#endif
+
+static float shade_by_transmission(Isect *is, ShadeInput *shi, ShadeResult *shr)
+{
+ float dx, dy, dz, d, p;
+
+ if (0 == (shi->mat->mode & (MA_RAYTRANSP|MA_ZTRA)))
+ return -1;
+
+ if (shi->mat->tx_limit <= 0.0f) {
+ d= 1.0f;
+ }
+ else {
+ /* shi.co[] calculated by shade_ray() */
+ dx= shi->co[0] - is->start[0];
+ dy= shi->co[1] - is->start[1];
+ dz= shi->co[2] - is->start[2];
+ d= sqrt(dx*dx+dy*dy+dz*dz);
+ if (d > shi->mat->tx_limit)
+ d= shi->mat->tx_limit;
+
+ p = shi->mat->tx_falloff;
+ if(p < 0.0f) p= 0.0f;
+ else if (p > 10.0f) p= 10.0f;
+
+ shr->alpha *= pow(d, p);
+ if (shr->alpha > 1.0f)
+ shr->alpha= 1.0f;
+ }
+
+ return d;
+}
+
+static void ray_fadeout_endcolor(float *col, ShadeInput *origshi, ShadeInput *shi, ShadeResult *shr, Isect *isec, float *vec)
+{
+ /* un-intersected rays get either rendered material colour or sky colour */
+ if (origshi->mat->fadeto_mir == MA_RAYMIR_FADETOMAT) {
+ VECCOPY(col, shr->combined);
+ } else if (origshi->mat->fadeto_mir == MA_RAYMIR_FADETOSKY) {
+ VECCOPY(shi->view, vec);
+ Normalize(shi->view);
+
+ shadeSkyView(col, isec->start, shi->view, NULL);
+ }
+}
+
+static void ray_fadeout(Isect *is, ShadeInput *shi, float *col, float *blendcol, float dist_mir)
+{
+ /* if fading out, linear blend against fade colour */
+ float blendfac;
+
+ blendfac = 1.0 - VecLenf(shi->co, is->start)/dist_mir;
+
+ col[0] = col[0]*blendfac + (1.0 - blendfac)*blendcol[0];
+ col[1] = col[1]*blendfac + (1.0 - blendfac)*blendcol[1];
+ col[2] = col[2]*blendfac + (1.0 - blendfac)*blendcol[2];
+}
+
+/* the main recursive tracer itself */
+static void traceray(ShadeInput *origshi, ShadeResult *origshr, short depth, float *start, float *vec, float *col, VlakRen *vlr, int traflag)
+{
+ ShadeInput shi;
+ ShadeResult shr;
+ Isect isec;
+ float f, f1, fr, fg, fb;
+ float ref[3], maxsize=RE_ray_tree_max_size(R.raytree);
+ float dist_mir = origshi->mat->dist_mir;
+
+ VECCOPY(isec.start, start);
+ if (dist_mir > 0.0) {
+ isec.end[0]= start[0]+dist_mir*vec[0];
+ isec.end[1]= start[1]+dist_mir*vec[1];
+ isec.end[2]= start[2]+dist_mir*vec[2];
+ } else {
+ isec.end[0]= start[0]+maxsize*vec[0];
+ isec.end[1]= start[1]+maxsize*vec[1];
+ isec.end[2]= start[2]+maxsize*vec[2];
+ }
+ isec.mode= RE_RAY_MIRROR;
+ isec.faceorig= (RayFace*)vlr;
+
+ if(RE_ray_tree_intersect(R.raytree, &isec)) {
+ float d= 1.0f;
+
+ shi.mask= origshi->mask;
+ shi.osatex= origshi->osatex;
+ shi.depth= 1; /* only used to indicate tracing */
+ shi.thread= origshi->thread;
+ shi.sample= 0;
+ shi.xs= origshi->xs;
+ shi.ys= origshi->ys;
+ shi.lay= origshi->lay;
+ shi.passflag= SCE_PASS_COMBINED; /* result of tracing needs no pass info */
+ shi.combinedflag= 0xFFFFFF; /* ray trace does all options */
+ shi.do_preview= 0;
+ shi.light_override= origshi->light_override;
+ shi.mat_override= origshi->mat_override;
+
+ memset(&shr, 0, sizeof(ShadeResult));
+
+ shade_ray(&isec, &shi, &shr);
+ if (traflag & RAY_TRA)
+ d= shade_by_transmission(&isec, &shi, &shr);
+
+ if(depth>0) {
+
+ if(shi.mat->mode_l & (MA_RAYTRANSP|MA_ZTRA) && shr.alpha < 1.0f) {
+ float nf, f, f1, refract[3], tracol[4];
+
+ tracol[0]= shi.r;
+ tracol[1]= shi.g;
+ tracol[2]= shi.b;
+ tracol[3]= col[3]; // we pass on and accumulate alpha
+
+ if(shi.mat->mode & MA_RAYTRANSP) {
+ /* odd depths: use normal facing viewer, otherwise flip */
+ if(traflag & RAY_TRAFLIP) {
+ float norm[3];
+ norm[0]= - shi.vn[0];
+ norm[1]= - shi.vn[1];
+ norm[2]= - shi.vn[2];
+ if (!refraction(refract, norm, shi.view, shi.ang))
+ reflection(refract, norm, shi.view, shi.vn);
+ }
+ else {
+ if (!refraction(refract, shi.vn, shi.view, shi.ang))
+ reflection(refract, shi.vn, shi.view, shi.vn);
+ }
+ traflag |= RAY_TRA;
+ traceray(origshi, origshr, depth-1, shi.co, refract, tracol, shi.vlr, traflag ^ RAY_TRAFLIP);
+ }
+ else
+ traceray(origshi, origshr, depth-1, shi.co, shi.view, tracol, shi.vlr, 0);
+
+ f= shr.alpha; f1= 1.0f-f;
+ nf= d * shi.mat->filter;
+ fr= 1.0f+ nf*(shi.r-1.0f);
+ fg= 1.0f+ nf*(shi.g-1.0f);
+ fb= 1.0f+ nf*(shi.b-1.0f);
+ shr.diff[0]= f*shr.diff[0] + f1*fr*tracol[0];
+ shr.diff[1]= f*shr.diff[1] + f1*fg*tracol[1];
+ shr.diff[2]= f*shr.diff[2] + f1*fb*tracol[2];
+
+ shr.spec[0] *=f;
+ shr.spec[1] *=f;
+ shr.spec[2] *=f;
+
+ col[3]= f1*tracol[3] + f;
+ }
+ else
+ col[3]= 1.0f;
+
+ if(shi.mat->mode_l & MA_RAYMIRROR) {
+ f= shi.ray_mirror;
+ if(f!=0.0f) f*= fresnel_fac(shi.view, shi.vn, shi.mat->fresnel_mir_i, shi.mat->fresnel_mir);
+ }
+ else f= 0.0f;
+
+ if(f!=0.0f) {
+ float mircol[4];
+
+ reflection(ref, shi.vn, shi.view, NULL);
+ traceray(origshi, origshr, depth-1, shi.co, ref, mircol, shi.vlr, 0);
+
+ f1= 1.0f-f;
+
+ /* combine */
+ //color_combine(col, f*fr*(1.0f-shr.spec[0]), f1, col, shr.diff);
+ //col[0]+= shr.spec[0];
+ //col[1]+= shr.spec[1];
+ //col[2]+= shr.spec[2];
+
+ fr= shi.mirr;
+ fg= shi.mirg;
+ fb= shi.mirb;
+
+ col[0]= f*fr*(1.0f-shr.spec[0])*mircol[0] + f1*shr.diff[0] + shr.spec[0];
+ col[1]= f*fg*(1.0f-shr.spec[1])*mircol[1] + f1*shr.diff[1] + shr.spec[1];
+ col[2]= f*fb*(1.0f-shr.spec[2])*mircol[2] + f1*shr.diff[2] + shr.spec[2];
+ }
+ else {
+ col[0]= shr.diff[0] + shr.spec[0];
+ col[1]= shr.diff[1] + shr.spec[1];
+ col[2]= shr.diff[2] + shr.spec[2];
+ }
+
+ if (dist_mir > 0.0) {
+ float blendcol[3];
+
+ /* max ray distance set, but found an intersection, so fade this colour
+ * out towards the sky/material colour for a smooth transition */
+ ray_fadeout_endcolor(blendcol, origshi, &shi, origshr, &isec, vec);
+ ray_fadeout(&isec, &shi, col, blendcol, dist_mir);
+ }
+ }
+ else {
+ col[0]= shr.diff[0] + shr.spec[0];
+ col[1]= shr.diff[1] + shr.spec[1];
+ col[2]= shr.diff[2] + shr.spec[2];
+ }
+
+ }
+ else {
+ ray_fadeout_endcolor(col, origshi, &shi, origshr, &isec, vec);
+ }
+}
+
+/* **************** jitter blocks ********** */
+
+/* calc distributed planar energy */
+
+static void DP_energy(float *table, float *vec, int tot, float xsize, float ysize)
+{
+ int x, y, a;
+ float *fp, force[3], result[3];
+ float dx, dy, dist, min;
+
+ min= MIN2(xsize, ysize);
+ min*= min;
+ result[0]= result[1]= 0.0f;
+
+ for(y= -1; y<2; y++) {
+ dy= ysize*y;
+ for(x= -1; x<2; x++) {
+ dx= xsize*x;
+ fp= table;
+ for(a=0; a<tot; a++, fp+= 2) {
+ force[0]= vec[0] - fp[0]-dx;
+ force[1]= vec[1] - fp[1]-dy;
+ dist= force[0]*force[0] + force[1]*force[1];
+ if(dist < min && dist>0.0f) {
+ result[0]+= force[0]/dist;
+ result[1]+= force[1]/dist;
+ }
+ }
+ }
+ }
+ vec[0] += 0.1*min*result[0]/(float)tot;
+ vec[1] += 0.1*min*result[1]/(float)tot;
+ // cyclic clamping
+ vec[0]= vec[0] - xsize*floor(vec[0]/xsize + 0.5);
+ vec[1]= vec[1] - ysize*floor(vec[1]/ysize + 0.5);
+}
+
+// random offset of 1 in 2
+static void jitter_plane_offset(float *jitter1, float *jitter2, int tot, float sizex, float sizey, float ofsx, float ofsy)
+{
+ float dsizex= sizex*ofsx;
+ float dsizey= sizey*ofsy;
+ float hsizex= 0.5*sizex, hsizey= 0.5*sizey;
+ int x;
+
+ for(x=tot; x>0; x--, jitter1+=2, jitter2+=2) {
+ jitter2[0]= jitter1[0] + dsizex;
+ jitter2[1]= jitter1[1] + dsizey;
+ if(jitter2[0] > hsizex) jitter2[0]-= sizex;
+ if(jitter2[1] > hsizey) jitter2[1]-= sizey;
+ }
+}
+
+/* called from convertBlenderScene.c */
+/* we do this in advance to get consistant random, not alter the render seed, and be threadsafe */
+void init_jitter_plane(LampRen *lar)
+{
+ float *fp;
+ int x, iter=12, tot= lar->ray_totsamp;
+
+ /* at least 4, or max threads+1 tables */
+ if(BLENDER_MAX_THREADS < 4) x= 4;
+ else x= BLENDER_MAX_THREADS+1;
+ fp= lar->jitter= MEM_mallocN(x*tot*2*sizeof(float), "lamp jitter tab");
+
+ /* set per-lamp fixed seed */
+ BLI_srandom(tot);
+
+ /* fill table with random locations, area_size large */
+ for(x=0; x<tot; x++, fp+=2) {
+ fp[0]= (BLI_frand()-0.5)*lar->area_size;
+ fp[1]= (BLI_frand()-0.5)*lar->area_sizey;
+ }
+
+ while(iter--) {
+ fp= lar->jitter;
+ for(x=tot; x>0; x--, fp+=2) {
+ DP_energy(lar->jitter, fp, tot, lar->area_size, lar->area_sizey);
+ }
+ }
+
+ /* create the dithered tables (could just check lamp type!) */
+ jitter_plane_offset(lar->jitter, lar->jitter+2*tot, tot, lar->area_size, lar->area_sizey, 0.5f, 0.0f);
+ jitter_plane_offset(lar->jitter, lar->jitter+4*tot, tot, lar->area_size, lar->area_sizey, 0.5f, 0.5f);
+ jitter_plane_offset(lar->jitter, lar->jitter+6*tot, tot, lar->area_size, lar->area_sizey, 0.0f, 0.5f);
+}
+
+/* table around origin, -0.5*size to 0.5*size */
+static float *give_jitter_plane(LampRen *lar, int thread, int xs, int ys)
+{
+ int tot;
+
+ tot= lar->ray_totsamp;
+
+ if(lar->ray_samp_type & LA_SAMP_JITTER) {
+ /* made it threadsafe */
+
+ if(lar->xold[thread]!=xs || lar->yold[thread]!=ys) {
+ jitter_plane_offset(lar->jitter, lar->jitter+2*(thread+1)*tot, tot, lar->area_size, lar->area_sizey, BLI_thread_frand(thread), BLI_thread_frand(thread));
+ lar->xold[thread]= xs;
+ lar->yold[thread]= ys;
+ }
+ return lar->jitter+2*(thread+1)*tot;
+ }
+ if(lar->ray_samp_type & LA_SAMP_DITHER) {
+ return lar->jitter + 2*tot*((xs & 1)+2*(ys & 1));
+ }
+
+ return lar->jitter;
+}
+
+
+/* **************** QMC sampling *************** */
+
+static void halton_sample(double *ht_invprimes, double *ht_nums, double *v)
+{
+ // incremental halton sequence generator, from:
+ // "Instant Radiosity", Keller A.
+ unsigned int i;
+
+ for (i = 0; i < 2; i++)
+ {
+ double r = fabs((1.0 - ht_nums[i]) - 1e-10);
+
+ if (ht_invprimes[i] >= r)
+ {
+ double lasth;
+ double h = ht_invprimes[i];
+
+ do {
+ lasth = h;
+ h *= ht_invprimes[i];
+ } while (h >= r);
+
+ ht_nums[i] += ((lasth + h) - 1.0);
+ }
+ else
+ ht_nums[i] += ht_invprimes[i];
+
+ v[i] = (float)ht_nums[i];
+ }
+}
+
+/* Generate Hammersley points in [0,1)^2
+ * From Lucille renderer */
+static void hammersley_create(double *out, int n)
+{
+ double p, t;
+ int k, kk;
+
+ for (k = 0; k < n; k++) {
+ t = 0;
+ for (p = 0.5, kk = k; kk; p *= 0.5, kk >>= 1) {
+ if (kk & 1) { /* kk mod 2 = 1 */
+ t += p;
+ }
+ }
+
+ out[2 * k + 0] = (double)k / (double)n;
+ out[2 * k + 1] = t;
+ }
+}
+
+struct QMCSampler *QMC_initSampler(int type, int tot)
+{
+ QMCSampler *qsa = MEM_mallocN(sizeof(QMCSampler), "qmc sampler");
+ qsa->samp2d = MEM_mallocN(2*sizeof(double)*tot, "qmc sample table");
+
+ qsa->tot = tot;
+ qsa->type = type;
+
+ if (qsa->type==SAMP_TYPE_HAMMERSLEY)
+ hammersley_create(qsa->samp2d, qsa->tot);
+
+ return qsa;
+}
+
+static void QMC_initPixel(QMCSampler *qsa, int thread)
+{
+ if (qsa->type==SAMP_TYPE_HAMMERSLEY)
+ {
+ /* hammersley sequence is fixed, already created in QMCSampler init.
+ * per pixel, gets a random offset. We create separate offsets per thread, for write-safety */
+ qsa->offs[thread][0] = 0.5 * BLI_thread_frand(thread);
+ qsa->offs[thread][1] = 0.5 * BLI_thread_frand(thread);
+ }
+ else { /* SAMP_TYPE_HALTON */
+
+ /* generate a new randomised halton sequence per pixel
+ * to alleviate qmc artifacts and make it reproducable
+ * between threads/frames */
+ double ht_invprimes[2], ht_nums[2];
+ double r[2];
+ int i;
+
+ ht_nums[0] = BLI_thread_frand(thread);
+ ht_nums[1] = BLI_thread_frand(thread);
+ ht_invprimes[0] = 0.5;
+ ht_invprimes[1] = 1.0/3.0;
+
+ for (i=0; i< qsa->tot; i++) {
+ halton_sample(ht_invprimes, ht_nums, r);
+ qsa->samp2d[2*i+0] = r[0];
+ qsa->samp2d[2*i+1] = r[1];
+ }
+ }
+}
+
+static void QMC_freeSampler(QMCSampler *qsa)
+{
+ MEM_freeN(qsa->samp2d);
+ MEM_freeN(qsa);
+}
+
+static void QMC_getSample(double *s, QMCSampler *qsa, int thread, int num)
+{
+ if (qsa->type == SAMP_TYPE_HAMMERSLEY) {
+ s[0] = fmod(qsa->samp2d[2*num+0] + qsa->offs[thread][0], 1.0f);
+ s[1] = fmod(qsa->samp2d[2*num+1] + qsa->offs[thread][1], 1.0f);
+ }
+ else { /* SAMP_TYPE_HALTON */
+ s[0] = qsa->samp2d[2*num+0];
+ s[1] = qsa->samp2d[2*num+1];
+ }
+}
+
+/* phong weighted disc using 'blur' for exponent, centred on 0,0 */
+static void QMC_samplePhong(float *vec, QMCSampler *qsa, int thread, int num, float blur)
+{
+ double s[2];
+ float phi, pz, sqr;
+
+ QMC_getSample(s, qsa, thread, num);
+
+ phi = s[0]*2*M_PI;
+ pz = pow(s[1], blur);
+ sqr = sqrt(1.0f-pz*pz);
+
+ vec[0] = cos(phi)*sqr;
+ vec[1] = sin(phi)*sqr;
+ vec[2] = 0.0f;
+}
+
+/* rect of edge lengths sizex, sizey, centred on 0.0,0.0 i.e. ranging from -sizex/2 to +sizey/2 */
+static void QMC_sampleRect(float *vec, QMCSampler *qsa, int thread, int num, float sizex, float sizey)
+{
+ double s[2];
+
+ QMC_getSample(s, qsa, thread, num);
+
+ vec[0] = (s[0] - 0.5) * sizex;
+ vec[1] = (s[1] - 0.5) * sizey;
+ vec[2] = 0.0f;
+}
+
+/* disc of radius 'radius', centred on 0,0 */
+static void QMC_sampleDisc(float *vec, QMCSampler *qsa, int thread, int num, float radius)
+{
+ double s[2];
+ float phi, sqr;
+
+ QMC_getSample(s, qsa, thread, num);
+
+ phi = s[0]*2*M_PI;
+ sqr = sqrt(s[1]);
+
+ vec[0] = cos(phi)*sqr* radius/2.0;
+ vec[1] = sin(phi)*sqr* radius/2.0;
+ vec[2] = 0.0f;
+}
+
+/* uniform hemisphere sampling */
+static void QMC_sampleHemi(float *vec, QMCSampler *qsa, int thread, int num)
+{
+ double s[2];
+ float phi, sqr;
+
+ QMC_getSample(s, qsa, thread, num);
+
+ phi = s[0]*2.f*M_PI;
+ sqr = sqrt(s[1]);
+
+ vec[0] = cos(phi)*sqr;
+ vec[1] = sin(phi)*sqr;
+ vec[2] = 1.f - s[1]*s[1];
+}
+
+#if 0 /* currently not used */
+/* cosine weighted hemisphere sampling */
+static void QMC_sampleHemiCosine(float *vec, QMCSampler *qsa, int thread, int num)
+{
+ double s[2];
+ float phi, sqr;
+
+ QMC_getSample(s, qsa, thread, num);
+
+ phi = s[0]*2.f*M_PI;
+ sqr = s[1]*sqrt(2-s[1]*s[1]);
+
+ vec[0] = cos(phi)*sqr;
+ vec[1] = sin(phi)*sqr;
+ vec[2] = 1.f - s[1]*s[1];
+
+}
+#endif
+
+/* called from convertBlenderScene.c */
+/* samples don't change per pixel, so build the samples in advance for efficiency */
+void init_lamp_hammersley(LampRen *lar)
+{
+ lar->qsa = QMC_initSampler(SAMP_TYPE_HAMMERSLEY, lar->ray_totsamp);
+}
+
+void init_render_hammersley(Render *re)
+{
+ re->qsa = QMC_initSampler(SAMP_TYPE_HAMMERSLEY, (re->wrld.aosamp * re->wrld.aosamp));
+}
+
+void free_lamp_qmcsampler(LampRen *lar)
+{
+ QMC_freeSampler(lar->qsa);
+}
+
+void free_render_qmcsampler(Render *re)
+{
+ QMC_freeSampler(re->qsa);
+}
+
+static int adaptive_sample_variance(int samples, float *col, float *colsq, float thresh)
+{
+ float var[3], mean[3];
+
+ /* scale threshold just to give a bit more precision in input rather than dealing with
+ * tiny tiny numbers in the UI */
+ thresh /= 2;
+
+ mean[0] = col[0] / (float)samples;
+ mean[1] = col[1] / (float)samples;
+ mean[2] = col[2] / (float)samples;
+
+ var[0] = (colsq[0] / (float)samples) - (mean[0]*mean[0]);
+ var[1] = (colsq[1] / (float)samples) - (mean[1]*mean[1]);
+ var[2] = (colsq[2] / (float)samples) - (mean[2]*mean[2]);
+
+ if ((var[0] * 0.4 < thresh) && (var[1] * 0.3 < thresh) && (var[2] * 0.6 < thresh))
+ return 1;
+ else
+ return 0;
+}
+
+static int adaptive_sample_contrast_val(int samples, float prev, float val, float thresh)
+{
+ /* if the last sample's contribution to the total value was below a small threshold
+ * (i.e. the samples taken are very similar), then taking more samples that are probably
+ * going to be the same is wasting effort */
+ if (fabs( prev/(float)(samples-1) - val/(float)samples ) < thresh) {
+ return 1;
+ } else
+ return 0;
+}
+
+static float get_avg_speed(ShadeInput *shi)
+{
+ float pre_x, pre_y, post_x, post_y, speedavg;
+
+ pre_x = (shi->winspeed[0] == PASS_VECTOR_MAX)?0.0:shi->winspeed[0];
+ pre_y = (shi->winspeed[1] == PASS_VECTOR_MAX)?0.0:shi->winspeed[1];
+ post_x = (shi->winspeed[2] == PASS_VECTOR_MAX)?0.0:shi->winspeed[2];
+ post_y = (shi->winspeed[3] == PASS_VECTOR_MAX)?0.0:shi->winspeed[3];
+
+ speedavg = (sqrt(pre_x*pre_x + pre_y*pre_y) + sqrt(post_x*post_x + post_y*post_y)) / 2.0;
+
+ return speedavg;
+}
+
+/* ***************** main calls ************** */
+
+
+static void trace_refract(float *col, ShadeInput *shi, ShadeResult *shr)
+{
+ QMCSampler *qsa=NULL;
+ int samp_type;
+
+ float samp3d[3], orthx[3], orthy[3];
+ float v_refract[3], v_refract_new[3];
+ float sampcol[4], colsq[4];
+
+ float blur = pow(1.0 - shi->mat->gloss_tra, 3);
+ short max_samples = shi->mat->samp_gloss_tra;
+ float adapt_thresh = shi->mat->adapt_thresh_tra;
+
+ int samples=0;
+
+ colsq[0] = colsq[1] = colsq[2] = 0.0;
+ col[0] = col[1] = col[2] = 0.0;
+ col[3]= shr->alpha;
+
+ if (blur > 0.0) {
+ if (adapt_thresh != 0.0) samp_type = SAMP_TYPE_HALTON;
+ else samp_type = SAMP_TYPE_HAMMERSLEY;
+
+ /* all samples are generated per pixel */
+ qsa = QMC_initSampler(samp_type, max_samples);
+ QMC_initPixel(qsa, shi->thread);
+ } else
+ max_samples = 1;
+
+
+ while (samples < max_samples) {
+ refraction(v_refract, shi->vn, shi->view, shi->ang);
+
+ if (max_samples > 1) {
+ /* get a quasi-random vector from a phong-weighted disc */
+ QMC_samplePhong(samp3d, qsa, shi->thread, samples, blur);
+
+ VecOrthoBasisf(v_refract, orthx, orthy);
+ VecMulf(orthx, samp3d[0]);
+ VecMulf(orthy, samp3d[1]);
+
+ /* and perturb the refraction vector in it */
+ VecAddf(v_refract_new, v_refract, orthx);
+ VecAddf(v_refract_new, v_refract_new, orthy);
+
+ Normalize(v_refract_new);
+ } else {
+ /* no blurriness, use the original normal */
+ VECCOPY(v_refract_new, v_refract);
+ }
+
+ traceray(shi, shr, shi->mat->ray_depth_tra, shi->co, v_refract_new, sampcol, shi->vlr, RAY_TRA|RAY_TRAFLIP);
+
+ col[0] += sampcol[0];
+ col[1] += sampcol[1];
+ col[2] += sampcol[2];
+ col[3] += sampcol[3];
+
+ /* for variance calc */
+ colsq[0] += sampcol[0]*sampcol[0];
+ colsq[1] += sampcol[1]*sampcol[1];
+ colsq[2] += sampcol[2]*sampcol[2];
+
+ samples++;
+
+ /* adaptive sampling */
+ if (adapt_thresh < 1.0 && samples > max_samples/2)
+ {
+ if (adaptive_sample_variance(samples, col, colsq, adapt_thresh))
+ break;
+
+ /* if the pixel so far is very dark, we can get away with less samples */
+ if ( (col[0] + col[1] + col[2])/3.0/(float)samples < 0.01 )
+ max_samples--;
+ }
+ }
+
+ col[0] /= (float)samples;
+ col[1] /= (float)samples;
+ col[2] /= (float)samples;
+ col[3] /= (float)samples;
+
+ if (qsa) QMC_freeSampler(qsa);
+}
+
+static void trace_reflect(float *col, ShadeInput *shi, ShadeResult *shr, float fresnelfac)
+{
+ QMCSampler *qsa=NULL;
+ int samp_type;
+
+ float samp3d[3], orthx[3], orthy[3];
+ float v_nor_new[3], v_facenor_new[3], v_reflect[3];
+ float sampcol[4], colsq[4];
+
+ float blur = pow(1.0 - shi->mat->gloss_mir, 3);
+ short max_samples = shi->mat->samp_gloss_mir;
+ float adapt_thresh = shi->mat->adapt_thresh_mir;
+ float aniso = 1.0 - shi->mat->aniso_gloss_mir;
+
+ int samples=0;
+
+ col[0] = col[1] = col[2] = 0.0;
+ colsq[0] = colsq[1] = colsq[2] = 0.0;
+
+ if (blur > 0.0) {
+ if (adapt_thresh != 0.0) samp_type = SAMP_TYPE_HALTON;
+ else samp_type = SAMP_TYPE_HAMMERSLEY;
+
+ /* all samples are generated per pixel */
+ qsa = QMC_initSampler(samp_type, max_samples);
+ QMC_initPixel(qsa, shi->thread);
+ } else
+ max_samples = 1;
+
+ VECCOPY(v_facenor_new, shi->facenor);
+
+ while (samples < max_samples) {
+
+ if (max_samples > 1) {
+ /* get a quasi-random vector from a phong-weighted disc */
+ QMC_samplePhong(samp3d, qsa, shi->thread, samples, blur);
+
+ /* find the normal's perpendicular plane, blurring along tangents
+ * if tangent shading enabled */
+ if (shi->mat->mode & (MA_TANGENT_V)) {
+ Crossf(orthx, shi->vn, shi->tang); // bitangent
+ VECCOPY(orthy, shi->tang);
+ VecMulf(orthx, samp3d[0]);
+ VecMulf(orthy, samp3d[1]*aniso);
+ } else {
+ VecOrthoBasisf(shi->vn, orthx, orthy);
+ VecMulf(orthx, samp3d[0]);
+ VecMulf(orthy, samp3d[1]);
+ }
+
+ /* and perturb the normal in it */
+ VecAddf(v_nor_new, shi->vn, orthx);
+ VecAddf(v_nor_new, v_nor_new, orthy);
+ VecAddf(v_facenor_new, shi->facenor, orthx);
+ VecAddf(v_facenor_new, v_facenor_new, orthy);
+ Normalize(v_nor_new);
+ Normalize(v_facenor_new);
+ } else {
+ /* no blurriness, use the original normal */
+ VECCOPY(v_nor_new, shi->vn);
+ }
+
+ if((shi->vlr->flag & R_SMOOTH))
+ reflection(v_reflect, v_nor_new, shi->view, v_facenor_new);
+ else
+ reflection(v_reflect, v_nor_new, shi->view, NULL);
+
+ traceray(shi, shr, shi->mat->ray_depth, shi->co, v_reflect, sampcol, shi->vlr, 0);
+
+
+ col[0] += sampcol[0];
+ col[1] += sampcol[1];
+ col[2] += sampcol[2];
+
+ /* for variance calc */
+ colsq[0] += sampcol[0]*sampcol[0];
+ colsq[1] += sampcol[1]*sampcol[1];
+ colsq[2] += sampcol[2]*sampcol[2];
+
+ samples++;
+
+ /* adaptive sampling */
+ if (adapt_thresh > 0.0 && samples > max_samples/3)
+ {
+ if (adaptive_sample_variance(samples, col, colsq, adapt_thresh))
+ break;
+
+ /* if the pixel so far is very dark, we can get away with less samples */
+ if ( (col[0] + col[1] + col[2])/3.0/(float)samples < 0.01 )
+ max_samples--;
+
+ /* reduce samples when reflection is dim due to low ray mirror blend value or fresnel factor
+ * and when reflection is blurry */
+ if (fresnelfac < 0.1 * (blur+1)) {
+ max_samples--;
+
+ /* even more for very dim */
+ if (fresnelfac < 0.05 * (blur+1))
+ max_samples--;
+ }
+ }
+ }
+
+ col[0] /= (float)samples;
+ col[1] /= (float)samples;
+ col[2] /= (float)samples;
+
+ if (qsa) QMC_freeSampler(qsa);
+}
+
+/* extern call from render loop */
+void ray_trace(ShadeInput *shi, ShadeResult *shr)
+{
+ VlakRen *vlr;
+ float i, f, f1, fr, fg, fb;
+ float mircol[4], tracol[4];
+ float diff[3];
+ int do_tra, do_mir;
+
+ do_tra= ((shi->mat->mode & (MA_RAYTRANSP)) && shr->alpha!=1.0f);
+ do_mir= ((shi->mat->mode & MA_RAYMIRROR) && shi->ray_mirror!=0.0f);
+ vlr= shi->vlr;
+
+ /* raytrace mirror amd refract like to separate the spec color */
+ if(shi->combinedflag & SCE_PASS_SPEC)
+ VECSUB(diff, shr->combined, shr->spec) /* no ; */
+ else
+ VECCOPY(diff, shr->combined);
+
+ if(do_tra) {
+ float olddiff[3];
+
+ trace_refract(tracol, shi, shr);
+
+ f= shr->alpha; f1= 1.0f-f;
+ fr= 1.0f+ shi->mat->filter*(shi->r-1.0f);
+ fg= 1.0f+ shi->mat->filter*(shi->g-1.0f);
+ fb= 1.0f+ shi->mat->filter*(shi->b-1.0f);
+
+ /* for refract pass */
+ VECCOPY(olddiff, diff);
+
+ diff[0]= f*diff[0] + f1*fr*tracol[0];
+ diff[1]= f*diff[1] + f1*fg*tracol[1];
+ diff[2]= f*diff[2] + f1*fb*tracol[2];
+
+ if(shi->passflag & SCE_PASS_REFRACT)
+ VECSUB(shr->refr, diff, olddiff);
+
+ if(!(shi->combinedflag & SCE_PASS_REFRACT))
+ VECSUB(diff, diff, shr->refr);
+
+ shr->alpha= tracol[3];
+ }
+
+ if(do_mir) {
+
+ i= shi->ray_mirror*fresnel_fac(shi->view, shi->vn, shi->mat->fresnel_mir_i, shi->mat->fresnel_mir);
+ if(i!=0.0f) {
+
+ trace_reflect(mircol, shi, shr, i);
+
+ fr= i*shi->mirr;
+ fg= i*shi->mirg;
+ fb= i*shi->mirb;
+
+ if(shi->passflag & SCE_PASS_REFLECT) {
+ /* mirror pass is not blocked out with spec */
+ shr->refl[0]= fr*mircol[0] - fr*diff[0];
+ shr->refl[1]= fg*mircol[1] - fg*diff[1];
+ shr->refl[2]= fb*mircol[2] - fb*diff[2];
+ }
+
+ if(shi->combinedflag & SCE_PASS_REFLECT) {
+
+ f= fr*(1.0f-shr->spec[0]); f1= 1.0f-i;
+ diff[0]= f*mircol[0] + f1*diff[0];
+
+ f= fg*(1.0f-shr->spec[1]); f1= 1.0f-i;
+ diff[1]= f*mircol[1] + f1*diff[1];
+
+ f= fb*(1.0f-shr->spec[2]); f1= 1.0f-i;
+ diff[2]= f*mircol[2] + f1*diff[2];
+ }
+ }
+ }
+ /* put back together */
+ if(shi->combinedflag & SCE_PASS_SPEC)
+ VECADD(shr->combined, diff, shr->spec) /* no ; */
+ else
+ VECCOPY(shr->combined, diff);
+}
+
+/* color 'shadfac' passes through 'col' with alpha and filter */
+/* filter is only applied on alpha defined transparent part */
+static void addAlphaLight(float *shadfac, float *col, float alpha, float filter)
+{
+ float fr, fg, fb;
+
+ fr= 1.0f+ filter*(col[0]-1.0f);
+ fg= 1.0f+ filter*(col[1]-1.0f);
+ fb= 1.0f+ filter*(col[2]-1.0f);
+
+ shadfac[0]= alpha*col[0] + fr*(1.0f-alpha)*shadfac[0];
+ shadfac[1]= alpha*col[1] + fg*(1.0f-alpha)*shadfac[1];
+ shadfac[2]= alpha*col[2] + fb*(1.0f-alpha)*shadfac[2];
+
+ shadfac[3]= (1.0f-alpha)*shadfac[3];
+}
+
+static void ray_trace_shadow_tra(Isect *is, int depth, int traflag)
+{
+ /* ray to lamp, find first face that intersects, check alpha properties,
+ if it has col[3]>0.0f continue. so exit when alpha is full */
+ ShadeInput shi;
+ ShadeResult shr;
+
+ if(RE_ray_tree_intersect(R.raytree, is)) {
+ float d= 1.0f;
+ /* we got a face */
+
+ shi.depth= 1; /* only used to indicate tracing */
+ shi.mask= 1;
+ shi.osatex= 0;
+ shi.thread= shi.sample= 0;
+ shi.lay= 0;
+ shi.passflag= 0;
+ shi.combinedflag= 0;
+ shi.do_preview= 0;
+ shi.light_override= NULL;
+ shi.mat_override= NULL;
+
+ shade_ray(is, &shi, &shr);
+ if (traflag & RAY_TRA)
+ d= shade_by_transmission(is, &shi, &shr);
+
+ /* mix colors based on shadfac (rgb + amount of light factor) */
+ addAlphaLight(is->col, shr.diff, shr.alpha, d*shi.mat->filter);
+
+ if(depth>0 && is->col[3]>0.0f) {
+
+ /* adapt isect struct */
+ VECCOPY(is->start, shi.co);
+ is->faceorig= (RayFace*)shi.vlr;
+
+ ray_trace_shadow_tra(is, depth-1, traflag | RAY_TRA);
+ }
+ }
+}
+
+/* not used, test function for ambient occlusion (yaf: pathlight) */
+/* main problem; has to be called within shading loop, giving unwanted recursion */
+int ray_trace_shadow_rad(ShadeInput *ship, ShadeResult *shr)
+{
+ static int counter=0, only_one= 0;
+ extern float hashvectf[];
+ Isect isec;
+ ShadeInput shi;
+ ShadeResult shr_t;
+ float vec[3], accum[3], div= 0.0f, maxsize= RE_ray_tree_max_size(R.raytree);
+ int a;
+
+ if(only_one) {
+ return 0;
+ }
+ only_one= 1;
+
+ accum[0]= accum[1]= accum[2]= 0.0f;
+ isec.mode= RE_RAY_MIRROR;
+ isec.faceorig= (RayFace*)ship->vlr;
+
+ for(a=0; a<8*8; a++) {
+
+ counter+=3;
+ counter %= 768;
+ VECCOPY(vec, hashvectf+counter);
+ if(ship->vn[0]*vec[0]+ship->vn[1]*vec[1]+ship->vn[2]*vec[2]>0.0f) {
+ vec[0]-= vec[0];
+ vec[1]-= vec[1];
+ vec[2]-= vec[2];
+ }
+ VECCOPY(isec.start, ship->co);
+ isec.end[0]= isec.start[0] + maxsize*vec[0];
+ isec.end[1]= isec.start[1] + maxsize*vec[1];
+ isec.end[2]= isec.start[2] + maxsize*vec[2];
+
+ if(RE_ray_tree_intersect(R.raytree, &isec)) {
+ float fac;
+ shade_ray(&isec, &shi, &shr_t);
+ fac= isec.labda*isec.labda;
+ fac= 1.0f;
+ accum[0]+= fac*(shr_t.diff[0]+shr_t.spec[0]);
+ accum[1]+= fac*(shr_t.diff[1]+shr_t.spec[1]);
+ accum[2]+= fac*(shr_t.diff[2]+shr_t.spec[2]);
+ div+= fac;
+ }
+ else div+= 1.0f;
+ }
+
+ if(div!=0.0f) {
+ shr->diff[0]+= accum[0]/div;
+ shr->diff[1]+= accum[1]/div;
+ shr->diff[2]+= accum[2]/div;
+ }
+ shr->alpha= 1.0f;
+
+ only_one= 0;
+ return 1;
+}
+
+/* aolight: function to create random unit sphere vectors for total random sampling */
+static void RandomSpherical(float *v)
+{
+ float r;
+ v[2] = 2.f*BLI_frand()-1.f;
+ if ((r = 1.f - v[2]*v[2])>0.f) {
+ float a = 6.283185307f*BLI_frand();
+ r = sqrt(r);
+ v[0] = r * cos(a);
+ v[1] = r * sin(a);
+ }
+ else v[2] = 1.f;
+}
+
+/* calc distributed spherical energy */
+static void DS_energy(float *sphere, int tot, float *vec)
+{
+ float *fp, fac, force[3], res[3];
+ int a;
+
+ res[0]= res[1]= res[2]= 0.0f;
+
+ for(a=0, fp=sphere; a<tot; a++, fp+=3) {
+ VecSubf(force, vec, fp);
+ fac= force[0]*force[0] + force[1]*force[1] + force[2]*force[2];
+ if(fac!=0.0f) {
+ fac= 1.0f/fac;
+ res[0]+= fac*force[0];
+ res[1]+= fac*force[1];
+ res[2]+= fac*force[2];
+ }
+ }
+
+ VecMulf(res, 0.5);
+ VecAddf(vec, vec, res);
+ Normalize(vec);
+
+}
+
+/* called from convertBlenderScene.c */
+/* creates an equally distributed spherical sample pattern */
+/* and allocates threadsafe memory */
+void init_ao_sphere(World *wrld)
+{
+ float *fp;
+ int a, tot, iter= 16;
+
+ /* we make twice the amount of samples, because only a hemisphere is used */
+ tot= 2*wrld->aosamp*wrld->aosamp;
+
+ wrld->aosphere= MEM_mallocN(3*tot*sizeof(float), "AO sphere");
+
+ /* fixed random */
+ BLI_srandom(tot);
+
+ /* init */
+ fp= wrld->aosphere;
+ for(a=0; a<tot; a++, fp+= 3) {
+ RandomSpherical(fp);
+ }
+
+ while(iter--) {
+ for(a=0, fp= wrld->aosphere; a<tot; a++, fp+= 3) {
+ DS_energy(wrld->aosphere, tot, fp);
+ }
+ }
+
+ /* tables */
+ wrld->aotables= MEM_mallocN(BLENDER_MAX_THREADS*3*tot*sizeof(float), "AO tables");
+}
+
+/* give per thread a table, we have to compare xs ys because of way OSA works... */
+static float *threadsafe_table_sphere(int test, int thread, int xs, int ys, int tot)
+{
+ static int xso[BLENDER_MAX_THREADS], yso[BLENDER_MAX_THREADS];
+ static int firsttime= 1;
+
+ if(firsttime) {
+ memset(xso, 255, sizeof(xso));
+ memset(yso, 255, sizeof(yso));
+ firsttime= 0;
+ }
+
+ if(xs==xso[thread] && ys==yso[thread]) return R.wrld.aotables+ thread*tot*3;
+ if(test) return NULL;
+ xso[thread]= xs; yso[thread]= ys;
+ return R.wrld.aotables+ thread*tot*3;
+}
+
+static float *sphere_sampler(int type, int resol, int thread, int xs, int ys)
+{
+ int tot;
+ float *vec;
+
+ if(resol>16) resol= 16;
+
+ tot= 2*resol*resol;
+
+ if (type & WO_AORNDSMP) {
+ static float sphere[2*3*256];
+ int a;
+
+ /* total random sampling. NOT THREADSAFE! (should be removed, is not useful) */
+ vec= sphere;
+ for (a=0; a<tot; a++, vec+=3) {
+ RandomSpherical(vec);
+ }
+
+ return sphere;
+ }
+ else {
+ float *sphere;
+ float cosfi, sinfi, cost, sint;
+ float ang, *vec1;
+ int a;
+
+ sphere= threadsafe_table_sphere(1, thread, xs, ys, tot); // returns table if xs and ys were equal to last call
+ if(sphere==NULL) {
+ sphere= threadsafe_table_sphere(0, thread, xs, ys, tot);
+
+ // random rotation
+ ang= BLI_thread_frand(thread);
+ sinfi= sin(ang); cosfi= cos(ang);
+ ang= BLI_thread_frand(thread);
+ sint= sin(ang); cost= cos(ang);
+
+ vec= R.wrld.aosphere;
+ vec1= sphere;
+ for (a=0; a<tot; a++, vec+=3, vec1+=3) {
+ vec1[0]= cost*cosfi*vec[0] - sinfi*vec[1] + sint*cosfi*vec[2];
+ vec1[1]= cost*sinfi*vec[0] + cosfi*vec[1] + sint*sinfi*vec[2];
+ vec1[2]= -sint*vec[0] + cost*vec[2];
+ }
+ }
+ return sphere;
+ }
+}
+
+void ray_ao_qmc(ShadeInput *shi, float *shadfac)
+{
+ Isect isec;
+ QMCSampler *qsa=NULL;
+ float samp3d[3];
+ float up[3], side[3], dir[3], nrm[3];
+
+ float maxdist = R.wrld.aodist;
+ float fac=0.0f, prev=0.0f;
+ float adapt_thresh = G.scene->world->ao_adapt_thresh;
+ float adapt_speed_fac = G.scene->world->ao_adapt_speed_fac;
+ float bias = G.scene->world->aobias;
+
+ int samples=0;
+ int max_samples = R.wrld.aosamp*R.wrld.aosamp;
+
+ float dxyview[3], skyadded=0, div;
+ int aocolor;
+
+ isec.faceorig= (RayFace*)shi->vlr;
+ isec.face_last= NULL;
+ isec.mode= (R.wrld.aomode & WO_AODIST)?RE_RAY_SHADOW_TRA:RE_RAY_SHADOW;
+ isec.lay= -1;
+ VECCOPY(isec.start, shi->co);
+
+ shadfac[0]= shadfac[1]= shadfac[2]= 0.0f;
+
+ /* prevent sky colors to be added for only shadow (shadow becomes alpha) */
+ aocolor= R.wrld.aocolor;
+ if(shi->mat->mode & MA_ONLYSHADOW)
+ aocolor= WO_AOPLAIN;
+
+ if(aocolor == WO_AOSKYTEX) {
+ dxyview[0]= 1.0f/(float)R.wrld.aosamp;
+ dxyview[1]= 1.0f/(float)R.wrld.aosamp;
+ dxyview[2]= 0.0f;
+ }
+
+ /* bias prevents smoothed faces to appear flat */
+ if(shi->vlr->flag & R_SMOOTH) {
+ bias= G.scene->world->aobias;
+ VECCOPY(nrm, shi->vn);
+ }
+ else {
+ bias= 0.0f;
+ VECCOPY(nrm, shi->facenor);
+ }
+
+ VecOrthoBasisf(nrm, up, side);
+
+ /* sampling init */
+ if (R.wrld.ao_samp_method==WO_AOSAMP_HALTON) {
+ float speedfac;
+
+ speedfac = get_avg_speed(shi) * adapt_speed_fac;
+ CLAMP(speedfac, 1.0, 1000.0);
+ max_samples /= speedfac;
+ if (max_samples < 5) max_samples = 5;
+
+ qsa = QMC_initSampler(SAMP_TYPE_HALTON, max_samples);
+ } else if (R.wrld.ao_samp_method==WO_AOSAMP_HAMMERSLEY)
+ qsa = R.qsa;
+
+ QMC_initPixel(qsa, shi->thread);
+
+ while (samples < max_samples) {
+
+ /* sampling, returns quasi-random vector in unit hemisphere */
+ QMC_sampleHemi(samp3d, qsa, shi->thread, samples);
+
+ dir[0] = (samp3d[0]*up[0] + samp3d[1]*side[0] + samp3d[2]*nrm[0]);
+ dir[1] = (samp3d[0]*up[1] + samp3d[1]*side[1] + samp3d[2]*nrm[1]);
+ dir[2] = (samp3d[0]*up[2] + samp3d[1]*side[2] + samp3d[2]*nrm[2]);
+
+ Normalize(dir);
+
+ isec.end[0] = shi->co[0] - maxdist*dir[0];
+ isec.end[1] = shi->co[1] - maxdist*dir[1];
+ isec.end[2] = shi->co[2] - maxdist*dir[2];
+
+ prev = fac;
+
+ if(RE_ray_tree_intersect(R.raytree, &isec)) {
+ if (R.wrld.aomode & WO_AODIST) fac+= exp(-isec.labda*R.wrld.aodistfac);
+ else fac+= 1.0f;
+ }
+ else if(aocolor!=WO_AOPLAIN) {
+ float skycol[4];
+ float skyfac, view[3];
+
+ view[0]= -dir[0];
+ view[1]= -dir[1];
+ view[2]= -dir[2];
+ Normalize(view);
+
+ if(aocolor==WO_AOSKYCOL) {
+ skyfac= 0.5*(1.0f+view[0]*R.grvec[0]+ view[1]*R.grvec[1]+ view[2]*R.grvec[2]);
+ shadfac[0]+= (1.0f-skyfac)*R.wrld.horr + skyfac*R.wrld.zenr;
+ shadfac[1]+= (1.0f-skyfac)*R.wrld.horg + skyfac*R.wrld.zeng;
+ shadfac[2]+= (1.0f-skyfac)*R.wrld.horb + skyfac*R.wrld.zenb;
+ }
+ else { /* WO_AOSKYTEX */
+ shadeSkyView(skycol, isec.start, view, dxyview);
+ shadfac[0]+= skycol[0];
+ shadfac[1]+= skycol[1];
+ shadfac[2]+= skycol[2];
+ }
+ skyadded++;
+ }
+
+ samples++;
+
+ if (qsa->type == SAMP_TYPE_HALTON) {
+ /* adaptive sampling - consider samples below threshold as in shadow (or vice versa) and exit early */
+ if (adapt_thresh > 0.0 && (samples > max_samples/2) ) {
+
+ if (adaptive_sample_contrast_val(samples, prev, fac, adapt_thresh)) {
+ break;
+ }
+ }
+ }
+ }
+
+ if(aocolor!=WO_AOPLAIN && skyadded) {
+ div= (1.0f - fac/(float)samples)/((float)skyadded);
+
+ shadfac[0]*= div; // average color times distances/hits formula
+ shadfac[1]*= div; // average color times distances/hits formula
+ shadfac[2]*= div; // average color times distances/hits formula
+ } else {
+ shadfac[0]= shadfac[1]= shadfac[2]= 1.0f - fac/(float)samples;
+ }
+
+ if ((qsa) && (qsa->type == SAMP_TYPE_HALTON)) QMC_freeSampler(qsa);
+}
+
+/* extern call from shade_lamp_loop, ambient occlusion calculus */
+void ray_ao_spheresamp(ShadeInput *shi, float *shadfac)
+{
+ Isect isec;
+ float *vec, *nrm, div, bias, sh=0.0f;
+ float maxdist = R.wrld.aodist;
+ float dxyview[3];
+ int j= -1, tot, actual=0, skyadded=0, aocolor;
+
+ isec.faceorig= (RayFace*)shi->vlr;
+ isec.face_last= NULL;
+ isec.mode= (R.wrld.aomode & WO_AODIST)?RE_RAY_SHADOW_TRA:RE_RAY_SHADOW;
+ isec.lay= -1;
+
+
+ shadfac[0]= shadfac[1]= shadfac[2]= 0.0f;
+
+ /* bias prevents smoothed faces to appear flat */
+ if(shi->vlr->flag & R_SMOOTH) {
+ bias= G.scene->world->aobias;
+ nrm= shi->vn;
+ }
+ else {
+ bias= 0.0f;
+ nrm= shi->facenor;
+ }
+
+ /* prevent sky colors to be added for only shadow (shadow becomes alpha) */
+ aocolor= R.wrld.aocolor;
+ if(shi->mat->mode & MA_ONLYSHADOW)
+ aocolor= WO_AOPLAIN;
+
+ vec= sphere_sampler(R.wrld.aomode, R.wrld.aosamp, shi->thread, shi->xs, shi->ys);
+
+ // warning: since we use full sphere now, and dotproduct is below, we do twice as much
+ tot= 2*R.wrld.aosamp*R.wrld.aosamp;
+
+ if(aocolor == WO_AOSKYTEX) {
+ dxyview[0]= 1.0f/(float)R.wrld.aosamp;
+ dxyview[1]= 1.0f/(float)R.wrld.aosamp;
+ dxyview[2]= 0.0f;
+ }
+
+ while(tot--) {
+
+ if ((vec[0]*nrm[0] + vec[1]*nrm[1] + vec[2]*nrm[2]) > bias) {
+ /* only ao samples for mask */
+ if(R.r.mode & R_OSA) {
+ j++;
+ if(j==R.osa) j= 0;
+ if(!(shi->mask & (1<<j))) {
+ vec+=3;
+ continue;
+ }
+ }
+
+ actual++;
+
+ /* always set start/end, RE_ray_tree_intersect clips it */
+ VECCOPY(isec.start, shi->co);
+ isec.end[0] = shi->co[0] - maxdist*vec[0];
+ isec.end[1] = shi->co[1] - maxdist*vec[1];
+ isec.end[2] = shi->co[2] - maxdist*vec[2];
+
+ /* do the trace */
+ if(RE_ray_tree_intersect(R.raytree, &isec)) {
+ if (R.wrld.aomode & WO_AODIST) sh+= exp(-isec.labda*R.wrld.aodistfac);
+ else sh+= 1.0f;
+ }
+ else if(aocolor!=WO_AOPLAIN) {
+ float skycol[4];
+ float fac, view[3];
+
+ view[0]= -vec[0];
+ view[1]= -vec[1];
+ view[2]= -vec[2];
+ Normalize(view);
+
+ if(aocolor==WO_AOSKYCOL) {
+ fac= 0.5*(1.0f+view[0]*R.grvec[0]+ view[1]*R.grvec[1]+ view[2]*R.grvec[2]);
+ shadfac[0]+= (1.0f-fac)*R.wrld.horr + fac*R.wrld.zenr;
+ shadfac[1]+= (1.0f-fac)*R.wrld.horg + fac*R.wrld.zeng;
+ shadfac[2]+= (1.0f-fac)*R.wrld.horb + fac*R.wrld.zenb;
+ }
+ else { /* WO_AOSKYTEX */
+ shadeSkyView(skycol, isec.start, view, dxyview);
+ shadfac[0]+= skycol[0];
+ shadfac[1]+= skycol[1];
+ shadfac[2]+= skycol[2];
+ }
+ skyadded++;
+ }
+ }
+ // samples
+ vec+= 3;
+ }
+
+ if(actual==0) sh= 1.0f;
+ else sh = 1.0f - sh/((float)actual);
+
+ if(aocolor!=WO_AOPLAIN && skyadded) {
+ div= sh/((float)skyadded);
+
+ shadfac[0]*= div; // average color times distances/hits formula
+ shadfac[1]*= div; // average color times distances/hits formula
+ shadfac[2]*= div; // average color times distances/hits formula
+ }
+ else {
+ shadfac[0]= shadfac[1]= shadfac[2]= sh;
+ }
+}
+
+void ray_ao(ShadeInput *shi, float *shadfac)
+{
+ /* Unfortunately, the unusual way that the sphere sampler calculates roughly twice as many
+ * samples as are actually traced, and skips them based on bias and OSA settings makes it very difficult
+ * to reuse code between these two functions. This is the easiest way I can think of to do it
+ * --broken */
+ if (ELEM(R.wrld.ao_samp_method, WO_AOSAMP_HAMMERSLEY, WO_AOSAMP_HALTON))
+ ray_ao_qmc(shi, shadfac);
+ else if (R.wrld.ao_samp_method == WO_AOSAMP_CONSTANT)
+ ray_ao_spheresamp(shi, shadfac);
+}
+
+
+static void ray_shadow_qmc(ShadeInput *shi, LampRen *lar, float *lampco, float *shadfac, Isect *isec)
+{
+ QMCSampler *qsa=NULL;
+ QMCSampler *qsa_jit=NULL;
+ int samples=0;
+ float samp3d[3], jit[3];
+
+ float fac=0.0f, vec[3];
+ float colsq[4];
+ float adapt_thresh = lar->adapt_thresh;
+ int max_samples = lar->ray_totsamp;
+ float pos[3];
+ int do_soft=1, full_osa=0;
+
+ colsq[0] = colsq[1] = colsq[2] = 0.0;
+ if(isec->mode==RE_RAY_SHADOW_TRA) {
+ shadfac[0]= shadfac[1]= shadfac[2]= shadfac[3]= 0.0f;
+ } else
+ shadfac[3]= 1.0f;
+
+ if (lar->ray_totsamp < 2) do_soft = 0;
+ if ((R.r.mode & R_OSA) && (R.osa > 0) && (shi->vlr->flag & R_FULL_OSA)) full_osa = 1;
+
+ if (full_osa) {
+ if (do_soft) max_samples = max_samples/R.osa + 1;
+ else max_samples = 1;
+ } else {
+ if (do_soft) max_samples = lar->ray_totsamp;
+ else max_samples = (R.osa > 4)?R.osa:5;
+ }
+
+ /* sampling init */
+ if (lar->ray_samp_method==LA_SAMP_HALTON) {
+ qsa = QMC_initSampler(SAMP_TYPE_HALTON, max_samples);
+ qsa_jit = QMC_initSampler(SAMP_TYPE_HALTON, max_samples);
+ } else if (lar->ray_samp_method==LA_SAMP_HAMMERSLEY) {
+ qsa = lar->qsa;
+ qsa_jit = QMC_initSampler(SAMP_TYPE_HAMMERSLEY, max_samples);
+ }
+
+ QMC_initPixel(qsa, shi->thread);
+ QMC_initPixel(qsa_jit, shi->thread);
+
+ VECCOPY(vec, lampco);
+
+
+ while (samples < max_samples) {
+ isec->faceorig= (RayFace*)shi->vlr;
+
+ /* manually jitter the start shading co-ord per sample
+ * based on the pre-generated OSA texture sampling offsets,
+ * for anti-aliasing sharp shadow edges. */
+ VECCOPY(pos, shi->co);
+ if (shi->vlr && !full_osa) {
+ QMC_sampleRect(jit, qsa_jit, shi->thread, samples, 1.0, 1.0);
+
+ pos[0] += shi->dxco[0]*jit[0] + shi->dyco[0]*jit[1];
+ pos[1] += shi->dxco[1]*jit[0] + shi->dyco[1]*jit[1];
+ pos[2] += shi->dxco[2]*jit[0] + shi->dyco[2]*jit[1];
+ }
+
+ if (do_soft) {
+ /* sphere shadow source */
+ if (lar->type == LA_LOCAL) {
+ float ru[3], rv[3], v[3], s[3];
+
+ /* calc tangent plane vectors */
+ v[0] = pos[0] - lampco[0];
+ v[1] = pos[1] - lampco[1];
+ v[2] = pos[2] - lampco[2];
+ Normalize(v);
+ VecOrthoBasisf(v, ru, rv);
+
+ /* sampling, returns quasi-random vector in area_size disc */
+ QMC_sampleDisc(samp3d, qsa, shi->thread, samples,lar->area_size);
+
+ /* distribute disc samples across the tangent plane */
+ s[0] = samp3d[0]*ru[0] + samp3d[1]*rv[0];
+ s[1] = samp3d[0]*ru[1] + samp3d[1]*rv[1];
+ s[2] = samp3d[0]*ru[2] + samp3d[1]*rv[2];
+
+ VECCOPY(samp3d, s);
+ }
+ else {
+ /* sampling, returns quasi-random vector in [sizex,sizey]^2 plane */
+ QMC_sampleRect(samp3d, qsa, shi->thread, samples, lar->area_size, lar->area_sizey);
+
+ /* align samples to lamp vector */
+ Mat3MulVecfl(lar->mat, samp3d);
+ }
+ isec->end[0]= vec[0]+samp3d[0];
+ isec->end[1]= vec[1]+samp3d[1];
+ isec->end[2]= vec[2]+samp3d[2];
+ } else {
+ VECCOPY(isec->end, vec);
+ }
+ VECCOPY(isec->start, pos);
+
+
+ /* trace the ray */
+ if(isec->mode==RE_RAY_SHADOW_TRA) {
+ isec->col[0]= isec->col[1]= isec->col[2]= 1.0f;
+ isec->col[3]= 1.0f;
+
+ ray_trace_shadow_tra(isec, DEPTH_SHADOW_TRA, 0);
+ shadfac[0] += isec->col[0];
+ shadfac[1] += isec->col[1];
+ shadfac[2] += isec->col[2];
+ shadfac[3] += isec->col[3];
+
+ /* for variance calc */
+ colsq[0] += isec->col[0]*isec->col[0];
+ colsq[1] += isec->col[1]*isec->col[1];
+ colsq[2] += isec->col[2]*isec->col[2];
+ }
+ else {
+ if( RE_ray_tree_intersect(R.raytree, isec) ) fac+= 1.0f;
+ }
+
+ samples++;
+
+ if ((lar->ray_samp_method == LA_SAMP_HALTON)) {
+
+ /* adaptive sampling - consider samples below threshold as in shadow (or vice versa) and exit early */
+ if ((max_samples > 4) && (adapt_thresh > 0.0) && (samples > max_samples / 3)) {
+ if (isec->mode==RE_RAY_SHADOW_TRA) {
+ if ((shadfac[3] / samples > (1.0-adapt_thresh)) || (shadfac[3] / samples < adapt_thresh))
+ break;
+ else if (adaptive_sample_variance(samples, shadfac, colsq, adapt_thresh))
+ break;
+ } else {
+ if ((fac / samples > (1.0-adapt_thresh)) || (fac / samples < adapt_thresh))
+ break;
+ }
+ }
+ }
+ }
+
+ if(isec->mode==RE_RAY_SHADOW_TRA) {
+ shadfac[0] /= samples;
+ shadfac[1] /= samples;
+ shadfac[2] /= samples;
+ shadfac[3] /= samples;
+ } else
+ shadfac[3]= 1.0f-fac/samples;
+
+ if (qsa_jit) QMC_freeSampler(qsa_jit);
+ if ((qsa) && (qsa->type == SAMP_TYPE_HALTON)) QMC_freeSampler(qsa);
+}
+
+static void ray_shadow_jitter(ShadeInput *shi, LampRen *lar, float *lampco, float *shadfac, Isect *isec)
+{
+ /* area soft shadow */
+ float *jitlamp;
+ float fac=0.0f, div=0.0f, vec[3];
+ int a, j= -1, mask;
+
+ if(isec->mode==RE_RAY_SHADOW_TRA) {
+ shadfac[0]= shadfac[1]= shadfac[2]= shadfac[3]= 0.0f;
+ }
+ else shadfac[3]= 1.0f;
+
+ fac= 0.0f;
+ jitlamp= give_jitter_plane(lar, shi->thread, shi->xs, shi->ys);
+
+ a= lar->ray_totsamp;
+
+ /* this correction to make sure we always take at least 1 sample */
+ mask= shi->mask;
+ if(a==4) mask |= (mask>>4)|(mask>>8);
+ else if(a==9) mask |= (mask>>9);
+
+ while(a--) {
+
+ if(R.r.mode & R_OSA) {
+ j++;
+ if(j>=R.osa) j= 0;
+ if(!(mask & (1<<j))) {
+ jitlamp+= 2;
+ continue;
+ }
+ }
+
+ isec->faceorig= (RayFace*)shi->vlr;
+
+ vec[0]= jitlamp[0];
+ vec[1]= jitlamp[1];
+ vec[2]= 0.0f;
+ Mat3MulVecfl(lar->mat, vec);
+
+ /* set start and end, RE_ray_tree_intersect clips it */
+ VECCOPY(isec->start, shi->co);
+ isec->end[0]= lampco[0]+vec[0];
+ isec->end[1]= lampco[1]+vec[1];
+ isec->end[2]= lampco[2]+vec[2];
+
+ if(isec->mode==RE_RAY_SHADOW_TRA) {
+ /* isec.col is like shadfac, so defines amount of light (0.0 is full shadow) */
+ isec->col[0]= isec->col[1]= isec->col[2]= 1.0f;
+ isec->col[3]= 1.0f;
+
+ ray_trace_shadow_tra(isec, DEPTH_SHADOW_TRA, 0);
+ shadfac[0] += isec->col[0];
+ shadfac[1] += isec->col[1];
+ shadfac[2] += isec->col[2];
+ shadfac[3] += isec->col[3];
+ }
+ else if( RE_ray_tree_intersect(R.raytree, isec) ) fac+= 1.0f;
+
+ div+= 1.0f;
+ jitlamp+= 2;
+ }
+
+ if(isec->mode==RE_RAY_SHADOW_TRA) {
+ shadfac[0] /= div;
+ shadfac[1] /= div;
+ shadfac[2] /= div;
+ shadfac[3] /= div;
+ }
+ else {
+ // sqrt makes nice umbra effect
+ if(lar->ray_samp_type & LA_SAMP_UMBRA)
+ shadfac[3]= sqrt(1.0f-fac/div);
+ else
+ shadfac[3]= 1.0f-fac/div;
+ }
+}
+/* extern call from shade_lamp_loop */
+void ray_shadow(ShadeInput *shi, LampRen *lar, float *shadfac)
+{
+ Isect isec;
+ float lampco[3], maxsize;
+
+ /* setup isec */
+ if(shi->mat->mode & MA_SHADOW_TRA) isec.mode= RE_RAY_SHADOW_TRA;
+ else isec.mode= RE_RAY_SHADOW;
+
+ if(lar->mode & LA_LAYER) isec.lay= lar->lay; else isec.lay= -1;
+
+ /* only when not mir tracing, first hit optimm */
+ if(shi->depth==0)
+ isec.face_last= (RayFace*)lar->vlr_last[shi->thread];
+ else
+ isec.face_last= NULL;
+
+ if(lar->type==LA_SUN || lar->type==LA_HEMI) {
+ maxsize= RE_ray_tree_max_size(R.raytree);
+ lampco[0]= shi->co[0] - maxsize*lar->vec[0];
+ lampco[1]= shi->co[1] - maxsize*lar->vec[1];
+ lampco[2]= shi->co[2] - maxsize*lar->vec[2];
+ }
+ else {
+ VECCOPY(lampco, lar->co);
+ }
+
+ if (ELEM(lar->ray_samp_method, LA_SAMP_HALTON, LA_SAMP_HAMMERSLEY)) {
+
+ ray_shadow_qmc(shi, lar, lampco, shadfac, &isec);
+
+ } else {
+ if(lar->ray_totsamp<2) {
+
+ isec.faceorig= (RayFace*)shi->vlr;
+ shadfac[3]= 1.0f; // 1.0=full light
+
+ /* set up isec vec */
+ VECCOPY(isec.start, shi->co);
+ VECCOPY(isec.end, lampco);
+
+ if(isec.mode==RE_RAY_SHADOW_TRA) {
+ /* isec.col is like shadfac, so defines amount of light (0.0 is full shadow) */
+ isec.col[0]= isec.col[1]= isec.col[2]= 1.0f;
+ isec.col[3]= 1.0f;
+
+ ray_trace_shadow_tra(&isec, DEPTH_SHADOW_TRA, 0);
+ QUATCOPY(shadfac, isec.col);
+ }
+ else if(RE_ray_tree_intersect(R.raytree, &isec)) shadfac[3]= 0.0f;
+ }
+ else {
+ ray_shadow_jitter(shi, lar, lampco, shadfac, &isec);
+ }
+ }
+
+ /* for first hit optim, set last interesected shadow face */
+ if(shi->depth==0)
+ lar->vlr_last[shi->thread]= (VlakRen*)isec.face_last;
+
+}
+
+/* only when face points away from lamp, in direction of lamp, trace ray and find first exit point */
+void ray_translucent(ShadeInput *shi, LampRen *lar, float *distfac, float *co)
+{
+ Isect isec;
+ float lampco[3], maxsize;
+
+ /* setup isec */
+ isec.mode= RE_RAY_SHADOW_TRA;
+
+ if(lar->mode & LA_LAYER) isec.lay= lar->lay; else isec.lay= -1;
+
+ if(lar->type==LA_SUN || lar->type==LA_HEMI) {
+ maxsize= RE_ray_tree_max_size(R.raytree);
+ lampco[0]= shi->co[0] - maxsize*lar->vec[0];
+ lampco[1]= shi->co[1] - maxsize*lar->vec[1];
+ lampco[2]= shi->co[2] - maxsize*lar->vec[2];
+ }
+ else {
+ VECCOPY(lampco, lar->co);
+ }
+
+ isec.faceorig= (RayFace*)shi->vlr;
+
+ /* set up isec vec */
+ VECCOPY(isec.start, shi->co);
+ VECCOPY(isec.end, lampco);
+
+ if(RE_ray_tree_intersect(R.raytree, &isec)) {
+ /* we got a face */
+
+ /* render co */
+ co[0]= isec.start[0]+isec.labda*(isec.vec[0]);
+ co[1]= isec.start[1]+isec.labda*(isec.vec[1]);
+ co[2]= isec.start[2]+isec.labda*(isec.vec[2]);
+
+ *distfac= VecLength(isec.vec);
+ }
+ else
+ *distfac= 0.0f;
+}
+
+
diff --git a/source/blender/render/intern/source/raytrace.c b/source/blender/render/intern/source/raytrace.c
new file mode 100644
index 00000000000..f86032b5d68
--- /dev/null
+++ b/source/blender/render/intern/source/raytrace.c
@@ -0,0 +1,1353 @@
+/**
+ * $Id: $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 1990-1998 NeoGeo BV.
+ * All rights reserved.
+ *
+ * Contributors: 2004/2005 Blender Foundation, full recode
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/* IMPORTANT NOTE: this code must be independent of any other render code
+ to use it outside the renderer! */
+
+#include <math.h>
+#include <string.h>
+#include <stdlib.h>
+#include <float.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_material_types.h"
+
+#include "BKE_utildefines.h"
+
+#include "BLI_arithb.h"
+
+#include "RE_raytrace.h"
+
+/* ********** structs *************** */
+
+#define BRANCH_ARRAY 1024
+#define NODE_ARRAY 4096
+
+typedef struct Branch
+{
+ struct Branch *b[8];
+} Branch;
+
+typedef struct OcVal
+{
+ short ocx, ocy, ocz;
+} OcVal;
+
+typedef struct Node
+{
+ struct RayFace *v[8];
+ struct OcVal ov[8];
+ struct Node *next;
+} Node;
+
+typedef struct Octree {
+ struct Branch **adrbranch;
+ struct Node **adrnode;
+ float ocsize; /* ocsize: mult factor, max size octree */
+ float ocfacx,ocfacy,ocfacz;
+ float min[3], max[3];
+ int ocres;
+ int branchcount, nodecount;
+ char *ocface; /* during building only */
+ RayCoordsFunc coordsfunc;
+ RayCheckFunc checkfunc;
+} Octree;
+
+/* ******** globals ***************** */
+
+/* just for statistics */
+static int raycount;
+static int accepted, rejected, coherent_ray;
+
+
+/* **************** ocval method ******************* */
+/* within one octree node, a set of 3x15 bits defines a 'boundbox' to OR with */
+
+#define OCVALRES 15
+#define BROW16(min, max) (((max)>=OCVALRES? 0xFFFF: (1<<(max+1))-1) - ((min>0)? ((1<<(min))-1):0) )
+
+static void calc_ocval_face(float *v1, float *v2, float *v3, float *v4, short x, short y, short z, OcVal *ov)
+{
+ float min[3], max[3];
+ int ocmin, ocmax;
+
+ VECCOPY(min, v1);
+ VECCOPY(max, v1);
+ DO_MINMAX(v2, min, max);
+ DO_MINMAX(v3, min, max);
+ if(v4) {
+ DO_MINMAX(v4, min, max);
+ }
+
+ ocmin= OCVALRES*(min[0]-x);
+ ocmax= OCVALRES*(max[0]-x);
+ ov->ocx= BROW16(ocmin, ocmax);
+
+ ocmin= OCVALRES*(min[1]-y);
+ ocmax= OCVALRES*(max[1]-y);
+ ov->ocy= BROW16(ocmin, ocmax);
+
+ ocmin= OCVALRES*(min[2]-z);
+ ocmax= OCVALRES*(max[2]-z);
+ ov->ocz= BROW16(ocmin, ocmax);
+
+}
+
+static void calc_ocval_ray(OcVal *ov, float xo, float yo, float zo, float *vec1, float *vec2)
+{
+ int ocmin, ocmax;
+
+ if(vec1[0]<vec2[0]) {
+ ocmin= OCVALRES*(vec1[0] - xo);
+ ocmax= OCVALRES*(vec2[0] - xo);
+ } else {
+ ocmin= OCVALRES*(vec2[0] - xo);
+ ocmax= OCVALRES*(vec1[0] - xo);
+ }
+ ov->ocx= BROW16(ocmin, ocmax);
+
+ if(vec1[1]<vec2[1]) {
+ ocmin= OCVALRES*(vec1[1] - yo);
+ ocmax= OCVALRES*(vec2[1] - yo);
+ } else {
+ ocmin= OCVALRES*(vec2[1] - yo);
+ ocmax= OCVALRES*(vec1[1] - yo);
+ }
+ ov->ocy= BROW16(ocmin, ocmax);
+
+ if(vec1[2]<vec2[2]) {
+ ocmin= OCVALRES*(vec1[2] - zo);
+ ocmax= OCVALRES*(vec2[2] - zo);
+ } else {
+ ocmin= OCVALRES*(vec2[2] - zo);
+ ocmax= OCVALRES*(vec1[2] - zo);
+ }
+ ov->ocz= BROW16(ocmin, ocmax);
+}
+
+/* ************* octree ************** */
+
+static Branch *addbranch(Octree *oc, Branch *br, short ocb)
+{
+ int index;
+
+ if(br->b[ocb]) return br->b[ocb];
+
+ oc->branchcount++;
+ index= oc->branchcount>>12;
+
+ if(oc->adrbranch[index]==NULL)
+ oc->adrbranch[index]= MEM_callocN(4096*sizeof(Branch), "new oc branch");
+
+ if(oc->branchcount>= BRANCH_ARRAY*4096) {
+ printf("error; octree branches full\n");
+ oc->branchcount=0;
+ }
+
+ return br->b[ocb]= oc->adrbranch[index]+(oc->branchcount & 4095);
+}
+
+static Node *addnode(Octree *oc)
+{
+ int index;
+
+ oc->nodecount++;
+ index= oc->nodecount>>12;
+
+ if(oc->adrnode[index]==NULL)
+ oc->adrnode[index]= MEM_callocN(4096*sizeof(Node),"addnode");
+
+ if(oc->nodecount> NODE_ARRAY*NODE_ARRAY) {
+ printf("error; octree nodes full\n");
+ oc->nodecount=0;
+ }
+
+ return oc->adrnode[index]+(oc->nodecount & 4095);
+}
+
+static int face_in_node(RayFace *face, short x, short y, short z, float rtf[][3])
+{
+ static float nor[3], d;
+ float fx, fy, fz;
+
+ // init static vars
+ if(face) {
+ CalcNormFloat(rtf[0], rtf[1], rtf[2], nor);
+ d= -nor[0]*rtf[0][0] - nor[1]*rtf[0][1] - nor[2]*rtf[0][2];
+ return 0;
+ }
+
+ fx= x;
+ fy= y;
+ fz= z;
+
+ if((fx)*nor[0] + (fy)*nor[1] + (fz)*nor[2] + d > 0.0f) {
+ if((fx+1)*nor[0] + (fy )*nor[1] + (fz )*nor[2] + d < 0.0f) return 1;
+ if((fx )*nor[0] + (fy+1)*nor[1] + (fz )*nor[2] + d < 0.0f) return 1;
+ if((fx+1)*nor[0] + (fy+1)*nor[1] + (fz )*nor[2] + d < 0.0f) return 1;
+
+ if((fx )*nor[0] + (fy )*nor[1] + (fz+1)*nor[2] + d < 0.0f) return 1;
+ if((fx+1)*nor[0] + (fy )*nor[1] + (fz+1)*nor[2] + d < 0.0f) return 1;
+ if((fx )*nor[0] + (fy+1)*nor[1] + (fz+1)*nor[2] + d < 0.0f) return 1;
+ if((fx+1)*nor[0] + (fy+1)*nor[1] + (fz+1)*nor[2] + d < 0.0f) return 1;
+ }
+ else {
+ if((fx+1)*nor[0] + (fy )*nor[1] + (fz )*nor[2] + d > 0.0f) return 1;
+ if((fx )*nor[0] + (fy+1)*nor[1] + (fz )*nor[2] + d > 0.0f) return 1;
+ if((fx+1)*nor[0] + (fy+1)*nor[1] + (fz )*nor[2] + d > 0.0f) return 1;
+
+ if((fx )*nor[0] + (fy )*nor[1] + (fz+1)*nor[2] + d > 0.0f) return 1;
+ if((fx+1)*nor[0] + (fy )*nor[1] + (fz+1)*nor[2] + d > 0.0f) return 1;
+ if((fx )*nor[0] + (fy+1)*nor[1] + (fz+1)*nor[2] + d > 0.0f) return 1;
+ if((fx+1)*nor[0] + (fy+1)*nor[1] + (fz+1)*nor[2] + d > 0.0f) return 1;
+ }
+
+ return 0;
+}
+
+static void ocwrite(Octree *oc, RayFace *face, int quad, short x, short y, short z, float rtf[][3])
+{
+ Branch *br;
+ Node *no;
+ short a, oc0, oc1, oc2, oc3, oc4, oc5;
+
+ x<<=2;
+ y<<=1;
+
+ br= oc->adrbranch[0];
+
+ if(oc->ocres==512) {
+ oc0= ((x & 1024)+(y & 512)+(z & 256))>>8;
+ br= addbranch(oc, br, oc0);
+ }
+ if(oc->ocres>=256) {
+ oc0= ((x & 512)+(y & 256)+(z & 128))>>7;
+ br= addbranch(oc, br, oc0);
+ }
+ if(oc->ocres>=128) {
+ oc0= ((x & 256)+(y & 128)+(z & 64))>>6;
+ br= addbranch(oc, br, oc0);
+ }
+
+ oc0= ((x & 128)+(y & 64)+(z & 32))>>5;
+ oc1= ((x & 64)+(y & 32)+(z & 16))>>4;
+ oc2= ((x & 32)+(y & 16)+(z & 8))>>3;
+ oc3= ((x & 16)+(y & 8)+(z & 4))>>2;
+ oc4= ((x & 8)+(y & 4)+(z & 2))>>1;
+ oc5= ((x & 4)+(y & 2)+(z & 1));
+
+ br= addbranch(oc, br,oc0);
+ br= addbranch(oc, br,oc1);
+ br= addbranch(oc, br,oc2);
+ br= addbranch(oc, br,oc3);
+ br= addbranch(oc, br,oc4);
+ no= (Node *)br->b[oc5];
+ if(no==NULL) br->b[oc5]= (Branch *)(no= addnode(oc));
+
+ while(no->next) no= no->next;
+
+ a= 0;
+ if(no->v[7]) { /* node full */
+ no->next= addnode(oc);
+ no= no->next;
+ }
+ else {
+ while(no->v[a]!=NULL) a++;
+ }
+
+ no->v[a]= face;
+
+ if(quad)
+ calc_ocval_face(rtf[0], rtf[1], rtf[2], rtf[3], x>>2, y>>1, z, &no->ov[a]);
+ else
+ calc_ocval_face(rtf[0], rtf[1], rtf[2], NULL, x>>2, y>>1, z, &no->ov[a]);
+}
+
+static void d2dda(Octree *oc, short b1, short b2, short c1, short c2, char *ocface, short rts[][3], float rtf[][3])
+{
+ int ocx1,ocx2,ocy1,ocy2;
+ int x,y,dx=0,dy=0;
+ float ox1,ox2,oy1,oy2;
+ float labda,labdao,labdax,labday,ldx,ldy;
+
+ ocx1= rts[b1][c1];
+ ocy1= rts[b1][c2];
+ ocx2= rts[b2][c1];
+ ocy2= rts[b2][c2];
+
+ if(ocx1==ocx2 && ocy1==ocy2) {
+ ocface[oc->ocres*ocx1+ocy1]= 1;
+ return;
+ }
+
+ ox1= rtf[b1][c1];
+ oy1= rtf[b1][c2];
+ ox2= rtf[b2][c1];
+ oy2= rtf[b2][c2];
+
+ if(ox1!=ox2) {
+ if(ox2-ox1>0.0f) {
+ labdax= (ox1-ocx1-1.0f)/(ox1-ox2);
+ ldx= -1.0f/(ox1-ox2);
+ dx= 1;
+ } else {
+ labdax= (ox1-ocx1)/(ox1-ox2);
+ ldx= 1.0f/(ox1-ox2);
+ dx= -1;
+ }
+ } else {
+ labdax=1.0f;
+ ldx=0;
+ }
+
+ if(oy1!=oy2) {
+ if(oy2-oy1>0.0f) {
+ labday= (oy1-ocy1-1.0f)/(oy1-oy2);
+ ldy= -1.0f/(oy1-oy2);
+ dy= 1;
+ } else {
+ labday= (oy1-ocy1)/(oy1-oy2);
+ ldy= 1.0f/(oy1-oy2);
+ dy= -1;
+ }
+ } else {
+ labday=1.0f;
+ ldy=0;
+ }
+
+ x=ocx1; y=ocy1;
+ labda= MIN2(labdax, labday);
+
+ while(TRUE) {
+
+ if(x<0 || y<0 || x>=oc->ocres || y>=oc->ocres);
+ else ocface[oc->ocres*x+y]= 1;
+
+ labdao=labda;
+ if(labdax==labday) {
+ labdax+=ldx;
+ x+=dx;
+ labday+=ldy;
+ y+=dy;
+ } else {
+ if(labdax<labday) {
+ labdax+=ldx;
+ x+=dx;
+ } else {
+ labday+=ldy;
+ y+=dy;
+ }
+ }
+ labda=MIN2(labdax,labday);
+ if(labda==labdao) break;
+ if(labda>=1.0f) break;
+ }
+ ocface[oc->ocres*ocx2+ocy2]=1;
+}
+
+static void filltriangle(Octree *oc, short c1, short c2, char *ocface, short *ocmin)
+{
+ short *ocmax;
+ int a, x, y, y1, y2;
+
+ ocmax=ocmin+3;
+
+ for(x=ocmin[c1];x<=ocmax[c1];x++) {
+ a= oc->ocres*x;
+ for(y=ocmin[c2];y<=ocmax[c2];y++) {
+ if(ocface[a+y]) {
+ y++;
+ while(ocface[a+y] && y!=ocmax[c2]) y++;
+ for(y1=ocmax[c2];y1>y;y1--) {
+ if(ocface[a+y1]) {
+ for(y2=y;y2<=y1;y2++) ocface[a+y2]=1;
+ y1=0;
+ }
+ }
+ y=ocmax[c2];
+ }
+ }
+ }
+}
+
+void RE_ray_tree_free(RayTree *tree)
+{
+ Octree *oc= (Octree*)tree;
+
+#if 0
+ printf("branches %d nodes %d\n", oc->branchcount, oc->nodecount);
+ printf("raycount %d \n", raycount);
+ printf("ray coherent %d \n", coherent_ray);
+ printf("accepted %d rejected %d\n", accepted, rejected);
+#endif
+ if(oc->ocface)
+ MEM_freeN(oc->ocface);
+
+ if(oc->adrbranch) {
+ int a= 0;
+ while(oc->adrbranch[a]) {
+ MEM_freeN(oc->adrbranch[a]);
+ oc->adrbranch[a]= NULL;
+ a++;
+ }
+ MEM_freeN(oc->adrbranch);
+ oc->adrbranch= NULL;
+ }
+ oc->branchcount= 0;
+
+ if(oc->adrnode) {
+ int a= 0;
+ while(oc->adrnode[a]) {
+ MEM_freeN(oc->adrnode[a]);
+ oc->adrnode[a]= NULL;
+ a++;
+ }
+ MEM_freeN(oc->adrnode);
+ oc->adrnode= NULL;
+ }
+ oc->nodecount= 0;
+
+ MEM_freeN(oc);
+}
+
+RayTree *RE_ray_tree_create(int ocres, int totface, float *min, float *max, RayCoordsFunc coordsfunc, RayCheckFunc checkfunc)
+{
+ Octree *oc;
+ float t00, t01, t02;
+ int c, ocres2;
+
+ oc= MEM_callocN(sizeof(Octree), "Octree");
+ oc->adrbranch= MEM_callocN(sizeof(void *)*BRANCH_ARRAY, "octree branches");
+ oc->adrnode= MEM_callocN(sizeof(void *)*NODE_ARRAY, "octree nodes");
+
+ oc->coordsfunc= coordsfunc;
+ oc->checkfunc= checkfunc;
+
+ /* only for debug info */
+ raycount=0;
+ accepted= 0;
+ rejected= 0;
+ coherent_ray= 0;
+
+ /* fill main octree struct */
+ oc->ocres= ocres;
+ ocres2= oc->ocres*oc->ocres;
+
+ VECCOPY(oc->min, min);
+ VECCOPY(oc->max, max);
+
+ oc->adrbranch[0]=(Branch *)MEM_callocN(4096*sizeof(Branch), "makeoctree");
+
+ /* the lookup table, per face, for which nodes to fill in */
+ oc->ocface= MEM_callocN( 3*ocres2 + 8, "ocface");
+ memset(oc->ocface, 0, 3*ocres2);
+
+ for(c=0;c<3;c++) { /* octree enlarge, still needed? */
+ oc->min[c]-= 0.01f;
+ oc->max[c]+= 0.01f;
+ }
+
+ t00= oc->max[0]-oc->min[0];
+ t01= oc->max[1]-oc->min[1];
+ t02= oc->max[2]-oc->min[2];
+
+ /* this minus 0.1 is old safety... seems to be needed? */
+ oc->ocfacx= (oc->ocres-0.1)/t00;
+ oc->ocfacy= (oc->ocres-0.1)/t01;
+ oc->ocfacz= (oc->ocres-0.1)/t02;
+
+ oc->ocsize= sqrt(t00*t00+t01*t01+t02*t02); /* global, max size octree */
+
+ return (RayTree*)oc;
+}
+
+void RE_ray_tree_add_face(RayTree *tree, RayFace *face)
+{
+ Octree *oc = (Octree*)tree;
+ float *v1, *v2, *v3, *v4, ocfac[3], rtf[4][3];
+ short rts[4][3], ocmin[6], *ocmax;
+ char *ocface= oc->ocface; // front, top, size view of face, to fill in
+ int a, b, c, oc1, oc2, oc3, oc4, x, y, z, ocres2;
+
+ ocfac[0]= oc->ocfacx;
+ ocfac[1]= oc->ocfacy;
+ ocfac[2]= oc->ocfacz;
+
+ ocres2= oc->ocres*oc->ocres;
+
+ ocmax= ocmin+3;
+
+ oc->coordsfunc(face, &v1, &v2, &v3, &v4);
+
+ for(c=0;c<3;c++) {
+ rtf[0][c]= (v1[c]-oc->min[c])*ocfac[c] ;
+ rts[0][c]= (short)rtf[0][c];
+ rtf[1][c]= (v2[c]-oc->min[c])*ocfac[c] ;
+ rts[1][c]= (short)rtf[1][c];
+ rtf[2][c]= (v3[c]-oc->min[c])*ocfac[c] ;
+ rts[2][c]= (short)rtf[2][c];
+ if(v4) {
+ rtf[3][c]= (v4[c]-oc->min[c])*ocfac[c] ;
+ rts[3][c]= (short)rtf[3][c];
+ }
+ }
+
+ for(c=0;c<3;c++) {
+ oc1= rts[0][c];
+ oc2= rts[1][c];
+ oc3= rts[2][c];
+ if(v4==NULL) {
+ ocmin[c]= MIN3(oc1,oc2,oc3);
+ ocmax[c]= MAX3(oc1,oc2,oc3);
+ }
+ else {
+ oc4= rts[3][c];
+ ocmin[c]= MIN4(oc1,oc2,oc3,oc4);
+ ocmax[c]= MAX4(oc1,oc2,oc3,oc4);
+ }
+ if(ocmax[c]>oc->ocres-1) ocmax[c]=oc->ocres-1;
+ if(ocmin[c]<0) ocmin[c]=0;
+ }
+
+ if(ocmin[0]==ocmax[0] && ocmin[1]==ocmax[1] && ocmin[2]==ocmax[2]) {
+ ocwrite(oc, face, (v4 != NULL), ocmin[0], ocmin[1], ocmin[2], rtf);
+ }
+ else {
+
+ d2dda(oc, 0,1,0,1,ocface+ocres2,rts,rtf);
+ d2dda(oc, 0,1,0,2,ocface,rts,rtf);
+ d2dda(oc, 0,1,1,2,ocface+2*ocres2,rts,rtf);
+ d2dda(oc, 1,2,0,1,ocface+ocres2,rts,rtf);
+ d2dda(oc, 1,2,0,2,ocface,rts,rtf);
+ d2dda(oc, 1,2,1,2,ocface+2*ocres2,rts,rtf);
+ if(v4==NULL) {
+ d2dda(oc, 2,0,0,1,ocface+ocres2,rts,rtf);
+ d2dda(oc, 2,0,0,2,ocface,rts,rtf);
+ d2dda(oc, 2,0,1,2,ocface+2*ocres2,rts,rtf);
+ }
+ else {
+ d2dda(oc, 2,3,0,1,ocface+ocres2,rts,rtf);
+ d2dda(oc, 2,3,0,2,ocface,rts,rtf);
+ d2dda(oc, 2,3,1,2,ocface+2*ocres2,rts,rtf);
+ d2dda(oc, 3,0,0,1,ocface+ocres2,rts,rtf);
+ d2dda(oc, 3,0,0,2,ocface,rts,rtf);
+ d2dda(oc, 3,0,1,2,ocface+2*ocres2,rts,rtf);
+ }
+ /* nothing todo with triangle..., just fills :) */
+ filltriangle(oc, 0,1,ocface+ocres2,ocmin);
+ filltriangle(oc, 0,2,ocface,ocmin);
+ filltriangle(oc, 1,2,ocface+2*ocres2,ocmin);
+
+ /* init static vars here */
+ face_in_node(face, 0,0,0, rtf);
+
+ for(x=ocmin[0];x<=ocmax[0];x++) {
+ a= oc->ocres*x;
+ for(y=ocmin[1];y<=ocmax[1];y++) {
+ if(ocface[a+y+ocres2]) {
+ b= oc->ocres*y+2*ocres2;
+ for(z=ocmin[2];z<=ocmax[2];z++) {
+ if(ocface[b+z] && ocface[a+z]) {
+ if(face_in_node(NULL, x, y, z, rtf))
+ ocwrite(oc, face, (v4 != NULL), x,y,z, rtf);
+ }
+ }
+ }
+ }
+ }
+
+ /* same loops to clear octree, doubt it can be done smarter */
+ for(x=ocmin[0];x<=ocmax[0];x++) {
+ a= oc->ocres*x;
+ for(y=ocmin[1];y<=ocmax[1];y++) {
+ /* x-y */
+ ocface[a+y+ocres2]= 0;
+
+ b= oc->ocres*y + 2*ocres2;
+ for(z=ocmin[2];z<=ocmax[2];z++) {
+ /* y-z */
+ ocface[b+z]= 0;
+ /* x-z */
+ ocface[a+z]= 0;
+ }
+ }
+ }
+ }
+}
+
+void RE_ray_tree_done(RayTree *tree)
+{
+ Octree *oc= (Octree*)tree;
+
+ MEM_freeN(oc->ocface);
+ oc->ocface= NULL;
+}
+
+/* ************ raytracer **************** */
+
+/* only for self-intersecting test with current render face (where ray left) */
+static int intersection2(RayFace *face, RayCoordsFunc coordsfunc, float r0, float r1, float r2, float rx1, float ry1, float rz1)
+{
+ float *v1, *v2, *v3, *v4;
+ float x0,x1,x2,t00,t01,t02,t10,t11,t12,t20,t21,t22;
+ float m0, m1, m2, divdet, det, det1;
+ float u1, v, u2;
+
+ coordsfunc(face, &v1, &v2, &v3, &v4);
+
+ /* happens for baking with non existing face */
+ if(v1==NULL)
+ return 1;
+
+ if (v4) {
+ SWAP(float*, v3, v4);
+ }
+
+ t00= v3[0]-v1[0];
+ t01= v3[1]-v1[1];
+ t02= v3[2]-v1[2];
+ t10= v3[0]-v2[0];
+ t11= v3[1]-v2[1];
+ t12= v3[2]-v2[2];
+
+ x0= t11*r2-t12*r1;
+ x1= t12*r0-t10*r2;
+ x2= t10*r1-t11*r0;
+
+ divdet= t00*x0+t01*x1+t02*x2;
+
+ m0= rx1-v3[0];
+ m1= ry1-v3[1];
+ m2= rz1-v3[2];
+ det1= m0*x0+m1*x1+m2*x2;
+
+ if(divdet!=0.0f) {
+ u1= det1/divdet;
+
+ if(u1<=0.0f) {
+ det= t00*(m1*r2-m2*r1);
+ det+= t01*(m2*r0-m0*r2);
+ det+= t02*(m0*r1-m1*r0);
+ v= det/divdet;
+
+ if(v<=0.0f && (u1 + v) >= -1.0f) {
+ return 1;
+ }
+ }
+ }
+
+ if(v4) {
+
+ t20= v3[0]-v4[0];
+ t21= v3[1]-v4[1];
+ t22= v3[2]-v4[2];
+
+ divdet= t20*x0+t21*x1+t22*x2;
+ if(divdet!=0.0f) {
+ u2= det1/divdet;
+
+ if(u2<=0.0f) {
+ det= t20*(m1*r2-m2*r1);
+ det+= t21*(m2*r0-m0*r2);
+ det+= t22*(m0*r1-m1*r0);
+ v= det/divdet;
+
+ if(v<=0.0f && (u2 + v) >= -1.0f) {
+ return 2;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+#if 0
+/* ray - line intersection */
+/* disabled until i got real & fast cylinder checking, this code doesnt work proper
+for faster strands */
+
+static int intersection_strand(Isect *is)
+{
+ float v1[3], v2[3]; /* length of strand */
+ float axis[3], rc[3], nor[3], radline, dist, len;
+
+ /* radius strand */
+ radline= 0.5f*VecLenf(is->vlr->v1->co, is->vlr->v2->co);
+
+ VecMidf(v1, is->vlr->v1->co, is->vlr->v2->co);
+ VecMidf(v2, is->vlr->v3->co, is->vlr->v4->co);
+
+ VECSUB(rc, v1, is->start); /* vector from base ray to base cylinder */
+ VECSUB(axis, v2, v1); /* cylinder axis */
+
+ CROSS(nor, is->vec, axis);
+ len= VecLength(nor);
+
+ if(len<FLT_EPSILON)
+ return 0;
+
+ dist= INPR(rc, nor)/len; /* distance between ray and axis cylinder */
+
+ if(dist<radline && dist>-radline) {
+ float dot1, dot2, dot3, rlen, alen, div;
+ float labda;
+
+ /* calculating the intersection point of shortest distance */
+ dot1 = INPR(rc, is->vec);
+ dot2 = INPR(is->vec, axis);
+ dot3 = INPR(rc, axis);
+ rlen = INPR(is->vec, is->vec);
+ alen = INPR(axis, axis);
+
+ div = alen * rlen - dot2 * dot2;
+ if (ABS(div) < FLT_EPSILON)
+ return 0;
+
+ labda = (dot1*dot2 - dot3*rlen)/div;
+
+ radline/= sqrt(alen);
+
+ /* labda: where on axis do we have closest intersection? */
+ if(labda >= -radline && labda <= 1.0f+radline) {
+ VlakRen *vlr= is->faceorig;
+ VertRen *v1= is->vlr->v1, *v2= is->vlr->v2, *v3= is->vlr->v3, *v4= is->vlr->v4;
+ /* but we dont do shadows from faces sharing edge */
+
+ if(v1==vlr->v1 || v2==vlr->v1 || v3==vlr->v1 || v4==vlr->v1) return 0;
+ if(v1==vlr->v2 || v2==vlr->v2 || v3==vlr->v2 || v4==vlr->v2) return 0;
+ if(v1==vlr->v3 || v2==vlr->v3 || v3==vlr->v3 || v4==vlr->v3) return 0;
+ if(vlr->v4) {
+ if(v1==vlr->v4 || v2==vlr->v4 || v3==vlr->v4 || v4==vlr->v4) return 0;
+ }
+ return 1;
+ }
+ }
+ return 0;
+}
+#endif
+
+/* ray - triangle or quad intersection */
+int RE_ray_face_intersection(Isect *is, RayCoordsFunc coordsfunc)
+{
+ RayFace *face= is->face;
+ float *v1,*v2,*v3,*v4;
+ float x0,x1,x2,t00,t01,t02,t10,t11,t12,t20,t21,t22,r0,r1,r2;
+ float m0, m1, m2, divdet, det1;
+ short ok=0;
+
+ /* disabled until i got real & fast cylinder checking, this code doesnt work proper
+ for faster strands */
+// if(is->mode==RE_RAY_SHADOW && is->vlr->flag & R_STRAND)
+// return intersection_strand(is);
+
+ coordsfunc(face, &v1, &v2, &v3, &v4);
+
+ if (v4) {
+ SWAP(float*, v3, v4);
+ }
+
+ t00= v3[0]-v1[0];
+ t01= v3[1]-v1[1];
+ t02= v3[2]-v1[2];
+ t10= v3[0]-v2[0];
+ t11= v3[1]-v2[1];
+ t12= v3[2]-v2[2];
+
+ r0= is->vec[0];
+ r1= is->vec[1];
+ r2= is->vec[2];
+
+ x0= t12*r1-t11*r2;
+ x1= t10*r2-t12*r0;
+ x2= t11*r0-t10*r1;
+
+ divdet= t00*x0+t01*x1+t02*x2;
+
+ m0= is->start[0]-v3[0];
+ m1= is->start[1]-v3[1];
+ m2= is->start[2]-v3[2];
+ det1= m0*x0+m1*x1+m2*x2;
+
+ if(divdet!=0.0f) {
+ float u;
+
+ divdet= 1.0f/divdet;
+ u= det1*divdet;
+ if(u<0.0f && u>-1.0f) {
+ float v, cros0, cros1, cros2;
+
+ cros0= m1*t02-m2*t01;
+ cros1= m2*t00-m0*t02;
+ cros2= m0*t01-m1*t00;
+ v= divdet*(cros0*r0 + cros1*r1 + cros2*r2);
+
+ if(v<0.0f && (u + v) > -1.0f) {
+ float labda;
+ labda= divdet*(cros0*t10 + cros1*t11 + cros2*t12);
+
+ if(labda>0.0f && labda<1.0f) {
+ is->labda= labda;
+ is->u= u; is->v= v;
+ ok= 1;
+ }
+ }
+ }
+ }
+
+ if(ok==0 && v4) {
+
+ t20= v3[0]-v4[0];
+ t21= v3[1]-v4[1];
+ t22= v3[2]-v4[2];
+
+ divdet= t20*x0+t21*x1+t22*x2;
+ if(divdet!=0.0f) {
+ float u;
+ divdet= 1.0f/divdet;
+ u = det1*divdet;
+
+ if(u<0.0f && u>-1.0f) {
+ float v, cros0, cros1, cros2;
+ cros0= m1*t22-m2*t21;
+ cros1= m2*t20-m0*t22;
+ cros2= m0*t21-m1*t20;
+ v= divdet*(cros0*r0 + cros1*r1 + cros2*r2);
+
+ if(v<0.0f && (u + v) > -1.0f) {
+ float labda;
+ labda= divdet*(cros0*t10 + cros1*t11 + cros2*t12);
+
+ if(labda>0.0f && labda<1.0f) {
+ ok= 2;
+ is->labda= labda;
+ is->u= u; is->v= v;
+ }
+ }
+ }
+ }
+ }
+
+ if(ok) {
+ is->isect= ok; // wich half of the quad
+
+ if(is->mode!=RE_RAY_SHADOW) {
+ /* for mirror & tra-shadow: large faces can be filled in too often, this prevents
+ a face being detected too soon... */
+ if(is->labda > is->ddalabda) {
+ return 0;
+ }
+ }
+
+ /* when a shadow ray leaves a face, it can be little outside the edges of it, causing
+ intersection to be detected in its neighbour face */
+
+ if(is->facecontr && is->faceisect); // optimizing, the tests below are not needed
+ else if(is->labda< .1) {
+ RayFace *face= is->faceorig;
+ float *origv1, *origv2, *origv3, *origv4;
+ short de= 0;
+
+ coordsfunc(face, &origv1, &origv2, &origv3, &origv4);
+
+ if(v1==origv1 || v2==origv1 || v3==origv1 || v4==origv1) de++;
+ if(v1==origv2 || v2==origv2 || v3==origv2 || v4==origv2) de++;
+ if(v1==origv3 || v2==origv3 || v3==origv3 || v4==origv3) de++;
+ if(origv4) {
+ if(v1==origv4 || v2==origv4 || v3==origv4 || v4==origv4) de++;
+ }
+ if(de) {
+ /* so there's a shared edge or vertex, let's intersect ray with face
+ itself, if that's true we can safely return 1, otherwise we assume
+ the intersection is invalid, 0 */
+
+ if(is->facecontr==NULL) {
+ is->facecontr= face;
+ is->faceisect= intersection2(face, coordsfunc, -r0, -r1, -r2, is->start[0], is->start[1], is->start[2]);
+ }
+
+ if(is->faceisect) return 1;
+ return 0;
+ }
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+/* check all faces in this node */
+static int testnode(Octree *oc, Isect *is, Node *no, OcVal ocval)
+{
+ RayFace *face;
+ short nr=0;
+ OcVal *ov;
+
+ /* return on any first hit */
+ if(is->mode==RE_RAY_SHADOW) {
+
+ face= no->v[0];
+ while(face) {
+
+ if(is->faceorig != face) {
+
+ if(oc->checkfunc(is, face)) {
+
+ ov= no->ov+nr;
+ if( (ov->ocx & ocval.ocx) && (ov->ocy & ocval.ocy) && (ov->ocz & ocval.ocz) ) {
+ //accepted++;
+ is->face= face;
+
+ if(RE_ray_face_intersection(is, oc->coordsfunc)) {
+ is->face_last= face;
+ return 1;
+ }
+ }
+ //else rejected++;
+ }
+ }
+
+ nr++;
+ if(nr==8) {
+ no= no->next;
+ if(no==0) return 0;
+ nr=0;
+ }
+ face= no->v[nr];
+ }
+ }
+ else { /* else mirror or glass or shadowtra, return closest face */
+ Isect isect;
+ int found= 0;
+
+ is->labda= 1.0f; /* needed? */
+ isect= *is; /* copy for sorting */
+
+ face= no->v[0];
+ while(face) {
+
+ if(is->faceorig != face) {
+ if(oc->checkfunc(is, face)) {
+ ov= no->ov+nr;
+ if( (ov->ocx & ocval.ocx) && (ov->ocy & ocval.ocy) && (ov->ocz & ocval.ocz) ) {
+ //accepted++;
+
+ isect.face= face;
+ if(RE_ray_face_intersection(&isect, oc->coordsfunc)) {
+ if(isect.labda<is->labda) *is= isect;
+ found= 1;
+ }
+ }
+ //else rejected++;
+ }
+ }
+
+ nr++;
+ if(nr==8) {
+ no= no->next;
+ if(no==NULL) break;
+ nr=0;
+ }
+ face= no->v[nr];
+ }
+
+ return found;
+ }
+
+ return 0;
+}
+
+/* find the Node for the octree coord x y z */
+static Node *ocread(Octree *oc, int x, int y, int z)
+{
+ Branch *br;
+ int oc1;
+
+ x<<=2;
+ y<<=1;
+
+ br= oc->adrbranch[0];
+
+ if(oc->ocres==512) {
+ oc1= ((x & 1024)+(y & 512)+(z & 256))>>8;
+ br= br->b[oc1];
+ if(br==NULL) {
+ return NULL;
+ }
+ }
+ if(oc->ocres>=256) {
+ oc1= ((x & 512)+(y & 256)+(z & 128))>>7;
+ br= br->b[oc1];
+ if(br==NULL) {
+ return NULL;
+ }
+ }
+ if(oc->ocres>=128) {
+ oc1= ((x & 256)+(y & 128)+(z & 64))>>6;
+ br= br->b[oc1];
+ if(br==NULL) {
+ return NULL;
+ }
+ }
+
+ oc1= ((x & 128)+(y & 64)+(z & 32))>>5;
+ br= br->b[oc1];
+ if(br) {
+ oc1= ((x & 64)+(y & 32)+(z & 16))>>4;
+ br= br->b[oc1];
+ if(br) {
+ oc1= ((x & 32)+(y & 16)+(z & 8))>>3;
+ br= br->b[oc1];
+ if(br) {
+ oc1= ((x & 16)+(y & 8)+(z & 4))>>2;
+ br= br->b[oc1];
+ if(br) {
+ oc1= ((x & 8)+(y & 4)+(z & 2))>>1;
+ br= br->b[oc1];
+ if(br) {
+ oc1= ((x & 4)+(y & 2)+(z & 1));
+ return (Node *)br->b[oc1];
+ }
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static int cliptest(float p, float q, float *u1, float *u2)
+{
+ float r;
+
+ if(p<0.0f) {
+ if(q<p) return 0;
+ else if(q<0.0f) {
+ r= q/p;
+ if(r>*u2) return 0;
+ else if(r>*u1) *u1=r;
+ }
+ }
+ else {
+ if(p>0.0f) {
+ if(q<0.0f) return 0;
+ else if(q<p) {
+ r= q/p;
+ if(r<*u1) return 0;
+ else if(r<*u2) *u2=r;
+ }
+ }
+ else if(q<0.0f) return 0;
+ }
+ return 1;
+}
+
+/* extensive coherence checks/storage cancels out the benefit of it, and gives errors... we
+ need better methods, sample code commented out below (ton) */
+
+/*
+
+in top: static int coh_nodes[16*16*16][6];
+in makeoctree: memset(coh_nodes, 0, sizeof(coh_nodes));
+
+static void add_coherence_test(int ocx1, int ocx2, int ocy1, int ocy2, int ocz1, int ocz2)
+{
+ short *sp;
+
+ sp= coh_nodes[ (ocx2 & 15) + 16*(ocy2 & 15) + 256*(ocz2 & 15) ];
+ sp[0]= ocx1; sp[1]= ocy1; sp[2]= ocz1;
+ sp[3]= ocx2; sp[4]= ocy2; sp[5]= ocz2;
+
+}
+
+static int do_coherence_test(int ocx1, int ocx2, int ocy1, int ocy2, int ocz1, int ocz2)
+{
+ short *sp;
+
+ sp= coh_nodes[ (ocx2 & 15) + 16*(ocy2 & 15) + 256*(ocz2 & 15) ];
+ if(sp[0]==ocx1 && sp[1]==ocy1 && sp[2]==ocz1 &&
+ sp[3]==ocx2 && sp[4]==ocy2 && sp[5]==ocz2) return 1;
+ return 0;
+}
+
+*/
+
+/* return 1: found valid intersection */
+/* starts with is->faceorig */
+int RE_ray_tree_intersect(RayTree *tree, Isect *is)
+{
+ Octree *oc= (Octree*)tree;
+ Node *no;
+ OcVal ocval;
+ float vec1[3], vec2[3];
+ float u1,u2,ox1,ox2,oy1,oy2,oz1,oz2;
+ float labdao,labdax,ldx,labday,ldy,labdaz,ldz, ddalabda;
+ int dx,dy,dz;
+ int xo,yo,zo,c1=0;
+ int ocx1,ocx2,ocy1, ocy2,ocz1,ocz2;
+
+ /* clip with octree */
+ if(oc->branchcount==0) return 0;
+
+ /* do this before intersect calls */
+ is->facecontr= NULL; /* to check shared edge */
+ is->faceisect= is->isect= 0; /* shared edge, quad half flag */
+
+ /* only for shadow! */
+ if(is->mode==RE_RAY_SHADOW) {
+
+ /* check with last intersected shadow face */
+ if(is->face_last!=NULL && is->face_last!=is->faceorig) {
+ if(oc->checkfunc(is, is->face_last)) {
+ is->face= is->face_last;
+ VECSUB(is->vec, is->end, is->start);
+ if(RE_ray_face_intersection(is, oc->coordsfunc)) return 1;
+ }
+ }
+ }
+
+ ldx= is->end[0] - is->start[0];
+ u1= 0.0f;
+ u2= 1.0f;
+
+ /* clip with octree cube */
+ if(cliptest(-ldx, is->start[0]-oc->min[0], &u1,&u2)) {
+ if(cliptest(ldx, oc->max[0]-is->start[0], &u1,&u2)) {
+ ldy= is->end[1] - is->start[1];
+ if(cliptest(-ldy, is->start[1]-oc->min[1], &u1,&u2)) {
+ if(cliptest(ldy, oc->max[1]-is->start[1], &u1,&u2)) {
+ ldz= is->end[2] - is->start[2];
+ if(cliptest(-ldz, is->start[2]-oc->min[2], &u1,&u2)) {
+ if(cliptest(ldz, oc->max[2]-is->start[2], &u1,&u2)) {
+ c1=1;
+ if(u2<1.0f) {
+ is->end[0]= is->start[0]+u2*ldx;
+ is->end[1]= is->start[1]+u2*ldy;
+ is->end[2]= is->start[2]+u2*ldz;
+ }
+ if(u1>0.0f) {
+ is->start[0]+=u1*ldx;
+ is->start[1]+=u1*ldy;
+ is->start[2]+=u1*ldz;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if(c1==0) return 0;
+
+ /* reset static variables in ocread */
+ //ocread(oc, oc->ocres, 0, 0);
+
+ /* setup 3dda to traverse octree */
+ ox1= (is->start[0]-oc->min[0])*oc->ocfacx;
+ oy1= (is->start[1]-oc->min[1])*oc->ocfacy;
+ oz1= (is->start[2]-oc->min[2])*oc->ocfacz;
+ ox2= (is->end[0]-oc->min[0])*oc->ocfacx;
+ oy2= (is->end[1]-oc->min[1])*oc->ocfacy;
+ oz2= (is->end[2]-oc->min[2])*oc->ocfacz;
+
+ ocx1= (int)ox1;
+ ocy1= (int)oy1;
+ ocz1= (int)oz1;
+ ocx2= (int)ox2;
+ ocy2= (int)oy2;
+ ocz2= (int)oz2;
+
+ /* for intersection */
+ VECSUB(is->vec, is->end, is->start);
+
+ if(ocx1==ocx2 && ocy1==ocy2 && ocz1==ocz2) {
+ no= ocread(oc, ocx1, ocy1, ocz1);
+ if(no) {
+ /* exact intersection with node */
+ vec1[0]= ox1; vec1[1]= oy1; vec1[2]= oz1;
+ vec2[0]= ox2; vec2[1]= oy2; vec2[2]= oz2;
+ calc_ocval_ray(&ocval, (float)ocx1, (float)ocy1, (float)ocz1, vec1, vec2);
+ is->ddalabda= 1.0f;
+ if( testnode(oc, is, no, ocval) ) return 1;
+ }
+ }
+ else {
+ //static int coh_ocx1,coh_ocx2,coh_ocy1, coh_ocy2,coh_ocz1,coh_ocz2;
+ float dox, doy, doz;
+ int eqval;
+
+ /* calc labda en ld */
+ dox= ox1-ox2;
+ doy= oy1-oy2;
+ doz= oz1-oz2;
+
+ if(dox<-FLT_EPSILON) {
+ ldx= -1.0f/dox;
+ labdax= (ocx1-ox1+1.0f)*ldx;
+ dx= 1;
+ } else if(dox>FLT_EPSILON) {
+ ldx= 1.0f/dox;
+ labdax= (ox1-ocx1)*ldx;
+ dx= -1;
+ } else {
+ labdax=1.0f;
+ ldx=0;
+ dx= 0;
+ }
+
+ if(doy<-FLT_EPSILON) {
+ ldy= -1.0f/doy;
+ labday= (ocy1-oy1+1.0f)*ldy;
+ dy= 1;
+ } else if(doy>FLT_EPSILON) {
+ ldy= 1.0f/doy;
+ labday= (oy1-ocy1)*ldy;
+ dy= -1;
+ } else {
+ labday=1.0f;
+ ldy=0;
+ dy= 0;
+ }
+
+ if(doz<-FLT_EPSILON) {
+ ldz= -1.0f/doz;
+ labdaz= (ocz1-oz1+1.0f)*ldz;
+ dz= 1;
+ } else if(doz>FLT_EPSILON) {
+ ldz= 1.0f/doz;
+ labdaz= (oz1-ocz1)*ldz;
+ dz= -1;
+ } else {
+ labdaz=1.0f;
+ ldz=0;
+ dz= 0;
+ }
+
+ xo=ocx1; yo=ocy1; zo=ocz1;
+ labdao= ddalabda= MIN3(labdax,labday,labdaz);
+
+ vec2[0]= ox1;
+ vec2[1]= oy1;
+ vec2[2]= oz1;
+
+ /* this loop has been constructed to make sure the first and last node of ray
+ are always included, even when ddalabda==1.0f or larger */
+
+ while(TRUE) {
+
+ no= ocread(oc, xo, yo, zo);
+ if(no) {
+
+ /* calculate ray intersection with octree node */
+ VECCOPY(vec1, vec2);
+ // dox,y,z is negative
+ vec2[0]= ox1-ddalabda*dox;
+ vec2[1]= oy1-ddalabda*doy;
+ vec2[2]= oz1-ddalabda*doz;
+ calc_ocval_ray(&ocval, (float)xo, (float)yo, (float)zo, vec1, vec2);
+
+ is->ddalabda= ddalabda;
+ if( testnode(oc, is, no, ocval) ) return 1;
+ }
+
+ labdao= ddalabda;
+
+ /* traversing ocree nodes need careful detection of smallest values, with proper
+ exceptions for equal labdas */
+ eqval= (labdax==labday);
+ if(labday==labdaz) eqval += 2;
+ if(labdax==labdaz) eqval += 4;
+
+ if(eqval) { // only 4 cases exist!
+ if(eqval==7) { // x=y=z
+ xo+=dx; labdax+=ldx;
+ yo+=dy; labday+=ldy;
+ zo+=dz; labdaz+=ldz;
+ }
+ else if(eqval==1) { // x=y
+ if(labday < labdaz) {
+ xo+=dx; labdax+=ldx;
+ yo+=dy; labday+=ldy;
+ }
+ else {
+ zo+=dz; labdaz+=ldz;
+ }
+ }
+ else if(eqval==2) { // y=z
+ if(labdax < labday) {
+ xo+=dx; labdax+=ldx;
+ }
+ else {
+ yo+=dy; labday+=ldy;
+ zo+=dz; labdaz+=ldz;
+ }
+ }
+ else { // x=z
+ if(labday < labdax) {
+ yo+=dy; labday+=ldy;
+ }
+ else {
+ xo+=dx; labdax+=ldx;
+ zo+=dz; labdaz+=ldz;
+ }
+ }
+ }
+ else { // all three different, just three cases exist
+ eqval= (labdax<labday);
+ if(labday<labdaz) eqval += 2;
+ if(labdax<labdaz) eqval += 4;
+
+ if(eqval==7 || eqval==5) { // x smallest
+ xo+=dx; labdax+=ldx;
+ }
+ else if(eqval==2 || eqval==6) { // y smallest
+ yo+=dy; labday+=ldy;
+ }
+ else { // z smallest
+ zo+=dz; labdaz+=ldz;
+ }
+
+ }
+
+ ddalabda=MIN3(labdax,labday,labdaz);
+ if(ddalabda==labdao) break;
+ /* to make sure the last node is always checked */
+ if(labdao>=1.0f) break;
+ }
+ }
+
+ /* reached end, no intersections found */
+ is->face_last= NULL;
+ return 0;
+}
+
+float RE_ray_tree_max_size(RayTree *tree)
+{
+ return ((Octree*)tree)->ocsize;
+}
+
diff --git a/source/blender/render/intern/source/rendercore.c b/source/blender/render/intern/source/rendercore.c
new file mode 100644
index 00000000000..b12d6094f2b
--- /dev/null
+++ b/source/blender/render/intern/source/rendercore.c
@@ -0,0 +1,1961 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributors: Hos, Robert Wenzlaff.
+ * Contributors: 2004/2005/2006 Blender Foundation, full recode
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/* system includes */
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+
+/* External modules: */
+#include "MEM_guardedalloc.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+#include "BLI_jitter.h"
+#include "BLI_rand.h"
+#include "BLI_threads.h"
+
+#include "BKE_utildefines.h"
+
+#include "DNA_image_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_material_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_global.h"
+#include "BKE_image.h"
+#include "BKE_main.h"
+#include "BKE_node.h"
+#include "BKE_texture.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+/* local include */
+#include "renderpipeline.h"
+#include "render_types.h"
+#include "renderdatabase.h"
+#include "pixelblending.h"
+#include "pixelshading.h"
+#include "shadbuf.h"
+#include "shading.h"
+#include "sss.h"
+#include "zbuf.h"
+
+#include "PIL_time.h"
+
+/* own include */
+#include "rendercore.h"
+
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
+/* only to be used here in this file, it's for speed */
+extern struct Render R;
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* x and y are current pixels in rect to be rendered */
+/* do not normalize! */
+void calc_view_vector(float *view, float x, float y)
+{
+
+ view[2]= -ABS(R.clipsta);
+
+ if(R.r.mode & R_ORTHO) {
+ view[0]= view[1]= 0.0f;
+ }
+ else {
+
+ if(R.r.mode & R_PANORAMA)
+ x-= R.panodxp;
+
+ /* move x and y to real viewplane coords */
+ x= (x/(float)R.winx);
+ view[0]= R.viewplane.xmin + x*(R.viewplane.xmax - R.viewplane.xmin);
+
+ y= (y/(float)R.winy);
+ view[1]= R.viewplane.ymin + y*(R.viewplane.ymax - R.viewplane.ymin);
+
+// if(R.flag & R_SEC_FIELD) {
+// if(R.r.mode & R_ODDFIELD) view[1]= (y+R.ystart)*R.ycor;
+// else view[1]= (y+R.ystart+1.0)*R.ycor;
+// }
+// else view[1]= (y+R.ystart+R.bluroffsy+0.5)*R.ycor;
+
+ if(R.r.mode & R_PANORAMA) {
+ float u= view[0] + R.panodxv; float v= view[2];
+ view[0]= R.panoco*u + R.panosi*v;
+ view[2]= -R.panosi*u + R.panoco*v;
+ }
+ }
+}
+
+void calc_renderco_ortho(float *co, float x, float y, int z)
+{
+ /* x and y 3d coordinate can be derived from pixel coord and winmat */
+ float fx= 2.0f/(R.winx*R.winmat[0][0]);
+ float fy= 2.0f/(R.winy*R.winmat[1][1]);
+ float zco;
+
+ co[0]= (x - 0.5f*R.winx)*fx - R.winmat[3][0]/R.winmat[0][0];
+ co[1]= (y - 0.5f*R.winy)*fy - R.winmat[3][1]/R.winmat[1][1];
+
+ zco= ((float)z)/2147483647.0f;
+ co[2]= R.winmat[3][2]/( R.winmat[2][3]*zco - R.winmat[2][2] );
+}
+
+void calc_renderco_zbuf(float *co, float *view, int z)
+{
+ float fac, zco;
+
+ /* inverse of zbuf calc: zbuf = MAXZ*hoco_z/hoco_w */
+ zco= ((float)z)/2147483647.0f;
+ co[2]= R.winmat[3][2]/( R.winmat[2][3]*zco - R.winmat[2][2] );
+
+ fac= co[2]/view[2];
+ co[0]= fac*view[0];
+ co[1]= fac*view[1];
+}
+
+/* also used in zbuf.c and shadbuf.c */
+int count_mask(unsigned short mask)
+{
+ if(R.samples)
+ return (R.samples->cmask[mask & 255]+R.samples->cmask[mask>>8]);
+ return 0;
+}
+
+static int calchalo_z(HaloRen *har, int zz)
+{
+
+ if(har->type & HA_ONLYSKY) {
+ if(zz!=0x7FFFFFFF) zz= - 0x7FFFFF;
+ }
+ else {
+ zz= (zz>>8);
+ }
+ return zz;
+}
+
+static void halo_pixelstruct(HaloRen *har, float *rb, float dist, float xn, float yn, PixStr *ps)
+{
+ float col[4], accol[4];
+ int amount, amountm, zz, flarec;
+
+ amount= 0;
+ accol[0]=accol[1]=accol[2]=accol[3]= 0.0f;
+ flarec= har->flarec;
+
+ while(ps) {
+ amountm= count_mask(ps->mask);
+ amount+= amountm;
+
+ zz= calchalo_z(har, ps->z);
+ if(zz> har->zs) {
+ float fac;
+
+ shadeHaloFloat(har, col, zz, dist, xn, yn, flarec);
+ fac= ((float)amountm)/(float)R.osa;
+ accol[0]+= fac*col[0];
+ accol[1]+= fac*col[1];
+ accol[2]+= fac*col[2];
+ accol[3]+= fac*col[3];
+ flarec= 0;
+ }
+
+ ps= ps->next;
+ }
+ /* now do the sky sub-pixels */
+ amount= R.osa-amount;
+ if(amount) {
+ float fac;
+
+ shadeHaloFloat(har, col, 0x7FFFFF, dist, xn, yn, flarec);
+ fac= ((float)amount)/(float)R.osa;
+ accol[0]+= fac*col[0];
+ accol[1]+= fac*col[1];
+ accol[2]+= fac*col[2];
+ accol[3]+= fac*col[3];
+ }
+ col[0]= accol[0];
+ col[1]= accol[1];
+ col[2]= accol[2];
+ col[3]= accol[3];
+
+ addalphaAddfacFloat(rb, col, har->add);
+
+}
+
+static void halo_tile(RenderPart *pa, float *pass, unsigned int lay)
+{
+ HaloRen *har = NULL;
+ rcti disprect= pa->disprect, testrect= pa->disprect;
+ float dist, xsq, ysq, xn, yn, *rb;
+ float col[4];
+ long *rd= NULL;
+ int a, *rz, zz, y;
+ short minx, maxx, miny, maxy, x;
+
+ /* we don't render halos in the cropped area, gives errors in flare counter */
+ if(pa->crop) {
+ testrect.xmin+= pa->crop;
+ testrect.xmax-= pa->crop;
+ testrect.ymin+= pa->crop;
+ testrect.ymax-= pa->crop;
+ }
+
+ for(a=0; a<R.tothalo; a++) {
+ if((a & 255)==0)
+ har= R.bloha[a>>8];
+ else har++;
+
+ /* layer test, clip halo with y */
+ if((har->lay & lay)==0);
+ else if(testrect.ymin > har->maxy);
+ else if(testrect.ymax < har->miny);
+ else {
+
+ minx= floor(har->xs-har->rad);
+ maxx= ceil(har->xs+har->rad);
+
+ if(testrect.xmin > maxx);
+ else if(testrect.xmax < minx);
+ else {
+
+ minx= MAX2(minx, testrect.xmin);
+ maxx= MIN2(maxx, testrect.xmax);
+
+ miny= MAX2(har->miny, testrect.ymin);
+ maxy= MIN2(har->maxy, testrect.ymax);
+
+ for(y=miny; y<maxy; y++) {
+ int rectofs= (y-disprect.ymin)*pa->rectx + (minx - disprect.xmin);
+ rb= pass + 4*rectofs;
+ rz= pa->rectz + rectofs;
+
+ if(pa->rectdaps)
+ rd= pa->rectdaps + rectofs;
+
+ yn= (y-har->ys)*R.ycor;
+ ysq= yn*yn;
+
+ for(x=minx; x<maxx; x++, rb+=4, rz++) {
+ xn= x- har->xs;
+ xsq= xn*xn;
+ dist= xsq+ysq;
+ if(dist<har->radsq) {
+ if(rd && *rd) {
+ halo_pixelstruct(har, rb, dist, xn, yn, (PixStr *)*rd);
+ }
+ else {
+ zz= calchalo_z(har, *rz);
+ if(zz> har->zs) {
+ shadeHaloFloat(har, col, zz, dist, xn, yn, har->flarec);
+ addalphaAddfacFloat(rb, col, har->add);
+ }
+ }
+ }
+ if(rd) rd++;
+ }
+ }
+ }
+ }
+ if(R.test_break() ) break;
+ }
+}
+
+static void lamphalo_tile(RenderPart *pa, RenderLayer *rl)
+{
+ ShadeInput shi;
+ float *pass= rl->rectf;
+ float fac;
+ long *rd= pa->rectdaps;
+ int x, y, *rz= pa->rectz;
+
+ shade_input_initialize(&shi, pa, rl, 0);
+
+ for(y=pa->disprect.ymin; y<pa->disprect.ymax; y++) {
+ for(x=pa->disprect.xmin; x<pa->disprect.xmax; x++, rz++, pass+=4) {
+
+ calc_view_vector(shi.view, x, y);
+
+ if(rd && *rd) {
+ PixStr *ps= (PixStr *)*rd;
+ int samp, totsamp= 0;
+
+ while(ps) {
+ if(R.r.mode & R_ORTHO)
+ calc_renderco_ortho(shi.co, (float)x, (float)y, ps->z);
+ else
+ calc_renderco_zbuf(shi.co, shi.view, ps->z);
+
+ totsamp+= samp= count_mask(ps->mask);
+ fac= ((float)samp)/(float)R.osa;
+ renderspothalo(&shi, pass, fac);
+ ps= ps->next;
+ }
+ if(totsamp<R.osa) {
+ fac= ((float)R.osa-totsamp)/(float)R.osa;
+ shi.co[2]= 0.0f;
+ renderspothalo(&shi, pass, fac);
+ }
+ }
+ else {
+ if(R.r.mode & R_ORTHO)
+ calc_renderco_ortho(shi.co, (float)x, (float)y, *rz);
+ else
+ calc_renderco_zbuf(shi.co, shi.view, *rz);
+
+ renderspothalo(&shi, pass, 1.0f);
+ }
+
+ if(rd) rd++;
+ }
+ if(y&1)
+ if(R.test_break()) break;
+ }
+}
+
+
+/* ********************* MAINLOOPS ******************** */
+
+/* osa version */
+static void add_filt_passes(RenderLayer *rl, int curmask, int rectx, int offset, ShadeInput *shi, ShadeResult *shr)
+{
+ RenderPass *rpass;
+
+ for(rpass= rl->passes.first; rpass; rpass= rpass->next) {
+ float *fp, *col= NULL;
+ int pixsize= 3;
+
+ switch(rpass->passtype) {
+ case SCE_PASS_RGBA:
+ col= shr->col;
+ pixsize= 4;
+ break;
+ case SCE_PASS_DIFFUSE:
+ col= shr->diff;
+ break;
+ case SCE_PASS_SPEC:
+ col= shr->spec;
+ break;
+ case SCE_PASS_SHADOW:
+ col= shr->shad;
+ break;
+ case SCE_PASS_AO:
+ col= shr->ao;
+ break;
+ case SCE_PASS_REFLECT:
+ col= shr->refl;
+ break;
+ case SCE_PASS_REFRACT:
+ col= shr->refr;
+ break;
+ case SCE_PASS_RADIO:
+ col= shr->rad;
+ break;
+ case SCE_PASS_NORMAL:
+ col= shr->nor;
+ break;
+ case SCE_PASS_UV:
+ /* box filter only, gauss will screwup UV too much */
+ if(shi->totuv) {
+ float mult= (float)count_mask(curmask)/(float)R.osa;
+ fp= rpass->rect + 3*offset;
+ fp[0]+= mult*(0.5f + 0.5f*shi->uv[0].uv[0]);
+ fp[1]+= mult*(0.5f + 0.5f*shi->uv[0].uv[1]);
+ fp[2]+= mult;
+ }
+ break;
+ case SCE_PASS_INDEXOB:
+ /* no filter */
+ if(shi->vlr) {
+ fp= rpass->rect + offset;
+ if(*fp==0.0f)
+ *fp= (float)shi->vlr->ob->index;
+ }
+ break;
+ case SCE_PASS_VECTOR:
+ {
+ /* add minimum speed in pixel, no filter */
+ fp= rpass->rect + 4*offset;
+ if( (ABS(shr->winspeed[0]) + ABS(shr->winspeed[1]))< (ABS(fp[0]) + ABS(fp[1])) ) {
+ fp[0]= shr->winspeed[0];
+ fp[1]= shr->winspeed[1];
+ }
+ if( (ABS(shr->winspeed[2]) + ABS(shr->winspeed[3]))< (ABS(fp[2]) + ABS(fp[3])) ) {
+ fp[2]= shr->winspeed[2];
+ fp[3]= shr->winspeed[3];
+ }
+ }
+ break;
+ }
+ if(col) {
+ fp= rpass->rect + pixsize*offset;
+ add_filt_fmask_pixsize(curmask, col, fp, rectx, pixsize);
+ }
+ }
+}
+
+/* non-osa version */
+static void add_passes(RenderLayer *rl, int offset, ShadeInput *shi, ShadeResult *shr)
+{
+ RenderPass *rpass;
+
+ for(rpass= rl->passes.first; rpass; rpass= rpass->next) {
+ float *fp, *col= NULL, uvcol[3];
+ int a, pixsize= 3;
+
+ switch(rpass->passtype) {
+ case SCE_PASS_RGBA:
+ col= shr->col;
+ pixsize= 4;
+ break;
+ case SCE_PASS_DIFFUSE:
+ col= shr->diff;
+ break;
+ case SCE_PASS_SPEC:
+ col= shr->spec;
+ break;
+ case SCE_PASS_SHADOW:
+ col= shr->shad;
+ break;
+ case SCE_PASS_AO:
+ col= shr->ao;
+ break;
+ case SCE_PASS_REFLECT:
+ col= shr->refl;
+ break;
+ case SCE_PASS_REFRACT:
+ col= shr->refr;
+ break;
+ case SCE_PASS_RADIO:
+ col= shr->rad;
+ break;
+ case SCE_PASS_NORMAL:
+ col= shr->nor;
+ break;
+ case SCE_PASS_UV:
+ if(shi->totuv) {
+ uvcol[0]= 0.5f + 0.5f*shi->uv[0].uv[0];
+ uvcol[1]= 0.5f + 0.5f*shi->uv[0].uv[1];
+ uvcol[2]= 1.0f;
+ col= uvcol;
+ }
+ break;
+ case SCE_PASS_VECTOR:
+ col= shr->winspeed;
+ pixsize= 4;
+ break;
+ case SCE_PASS_INDEXOB:
+ if(shi->vlr) {
+ fp= rpass->rect + offset;
+ *fp= (float)shi->vlr->ob->index;
+ }
+ break;
+ }
+ if(col) {
+ fp= rpass->rect + pixsize*offset;
+ for(a=0; a<pixsize; a++)
+ fp[a]= col[a];
+ }
+ }
+}
+
+/* only do sky, is default in the solid layer (shade_tile) btw */
+static void sky_tile(RenderPart *pa, float *pass)
+{
+ float col[4];
+ int x, y;
+
+ if(R.r.alphamode!=R_ADDSKY)
+ return;
+
+ for(y=pa->disprect.ymin; y<pa->disprect.ymax; y++) {
+ for(x=pa->disprect.xmin; x<pa->disprect.xmax; x++, pass+=4) {
+ if(pass[3]<1.0f) {
+ if(pass[3]==0.0f)
+ shadeSkyPixel(pass, x, y);
+ else {
+ shadeSkyPixel(col, x, y);
+ addAlphaOverFloat(col, pass);
+ QUATCOPY(pass, col);
+ }
+ }
+ }
+
+ if(y&1)
+ if(R.test_break()) break;
+ }
+}
+
+static void shadeDA_tile(RenderPart *pa, RenderLayer *rl)
+{
+ RenderResult *rr= pa->result;
+ ShadeSample ssamp;
+ float *fcol, *rf, *rectf= rl->rectf;
+ long *rd, *rectdaps= pa->rectdaps;
+ int samp;
+ int x, y, seed, crop=0, offs=0, od, addpassflag;
+
+ if(R.test_break()) return;
+
+ /* irregular shadowb buffer creation */
+ if(R.r.mode & R_SHADOW)
+ ISB_create(pa, NULL);
+
+ /* we set per pixel a fixed seed, for random AO and shadow samples */
+ seed= pa->rectx*pa->disprect.ymin;
+
+ /* general shader info, passes */
+ shade_sample_initialize(&ssamp, pa, rl);
+ addpassflag= rl->passflag & ~(SCE_PASS_Z|SCE_PASS_COMBINED);
+
+ /* filtered render, for now we assume only 1 filter size */
+ if(pa->crop) {
+ crop= 1;
+ rectf+= 4*(pa->rectx + 1);
+ rectdaps+= pa->rectx + 1;
+ offs= pa->rectx + 1;
+ }
+
+ /* scanline updates have to be 2 lines behind */
+ rr->renrect.ymin= 0;
+ rr->renrect.ymax= -2*crop;
+ rr->renlay= rl;
+
+ for(y=pa->disprect.ymin+crop; y<pa->disprect.ymax-crop; y++, rr->renrect.ymax++) {
+ rf= rectf;
+ rd= rectdaps;
+ od= offs;
+
+ for(x=pa->disprect.xmin+crop; x<pa->disprect.xmax-crop; x++, rd++, rf+=4, od++) {
+ BLI_thread_srandom(pa->thread, seed++);
+
+ if(*rd) {
+ if(shade_samples(&ssamp, (PixStr *)(*rd), x, y)) {
+ for(samp=0; samp<ssamp.tot; samp++) {
+
+ fcol= ssamp.shr[samp].combined;
+ add_filt_fmask(ssamp.shi[samp].mask, fcol, rf, pa->rectx);
+
+ if(addpassflag)
+ add_filt_passes(rl, ssamp.shi[samp].mask, pa->rectx, od, &ssamp.shi[samp], &ssamp.shr[samp]);
+ }
+ }
+ }
+ }
+
+ rectf+= 4*pa->rectx;
+ rectdaps+= pa->rectx;
+ offs+= pa->rectx;
+
+ if(y&1) if(R.test_break()) break;
+ }
+
+ /* disable scanline updating */
+ rr->renlay= NULL;
+
+ if(R.r.mode & R_SHADOW)
+ ISB_free(pa);
+}
+
+/* ************* pixel struct ******** */
+
+
+static PixStrMain *addpsmain(ListBase *lb)
+{
+ PixStrMain *psm;
+
+ psm= (PixStrMain *)MEM_mallocN(sizeof(PixStrMain),"pixstrMain");
+ BLI_addtail(lb, psm);
+
+ psm->ps= (PixStr *)MEM_mallocN(4096*sizeof(PixStr),"pixstr");
+ psm->counter= 0;
+
+ return psm;
+}
+
+static void freeps(ListBase *lb)
+{
+ PixStrMain *psm, *psmnext;
+
+ for(psm= lb->first; psm; psm= psmnext) {
+ psmnext= psm->next;
+ if(psm->ps)
+ MEM_freeN(psm->ps);
+ MEM_freeN(psm);
+ }
+ lb->first= lb->last= NULL;
+}
+
+static void addps(ListBase *lb, long *rd, int facenr, int z, unsigned short mask)
+{
+ PixStrMain *psm;
+ PixStr *ps, *last= NULL;
+
+ if(*rd) {
+ ps= (PixStr *)(*rd);
+
+ while(ps) {
+ if( ps->facenr == facenr ) {
+ ps->mask |= mask;
+ return;
+ }
+ last= ps;
+ ps= ps->next;
+ }
+ }
+
+ /* make new PS (pixel struct) */
+ psm= lb->last;
+
+ if(psm->counter==4095)
+ psm= addpsmain(lb);
+
+ ps= psm->ps + psm->counter++;
+
+ if(last) last->next= ps;
+ else *rd= (long)ps;
+
+ ps->next= NULL;
+ ps->facenr= facenr;
+ ps->z= z;
+ ps->mask = mask;
+ ps->shadfac= 0;
+}
+
+static void make_pixelstructs(RenderPart *pa, ListBase *lb)
+{
+ long *rd= pa->rectdaps;
+ int *rp= pa->rectp;
+ int *rz= pa->rectz;
+ int x, y;
+ int mask= 1<<pa->sample;
+
+ for(y=0; y<pa->recty; y++) {
+ for(x=0; x<pa->rectx; x++, rd++, rp++) {
+ if(*rp) {
+ addps(lb, rd, *rp, *(rz+x), mask);
+ }
+ }
+ rz+= pa->rectx;
+ }
+}
+
+static void edge_enhance_add(RenderPart *pa, float *rectf, float *arect)
+{
+ float addcol[4];
+ int pix;
+
+ if(arect==NULL)
+ return;
+
+ for(pix= pa->rectx*pa->recty; pix>0; pix--, arect++, rectf+=4) {
+ if(*arect != 0.0f) {
+ addcol[0]= *arect * R.r.edgeR;
+ addcol[1]= *arect * R.r.edgeG;
+ addcol[2]= *arect * R.r.edgeB;
+ addcol[3]= *arect;
+ addAlphaOverFloat(rectf, addcol);
+ }
+ }
+}
+
+
+static void convert_to_key_alpha(RenderPart *pa, float *rectf)
+{
+ int y;
+
+ for(y= pa->rectx*pa->recty; y>0; y--, rectf+=4) {
+ if(rectf[3] >= 1.0f);
+ else if(rectf[3] > 0.0f) {
+ rectf[0] /= rectf[3];
+ rectf[1] /= rectf[3];
+ rectf[2] /= rectf[3];
+ }
+ }
+}
+
+/* adds only alpha values */
+static void edge_enhance_tile(RenderPart *pa, float *rectf)
+{
+ /* use zbuffer to define edges, add it to the image */
+ int y, x, col, *rz, *rz1, *rz2, *rz3;
+ int zval1, zval2, zval3;
+ float *rf;
+
+ /* shift values in zbuffer 4 to the right (anti overflows), for filter we need multiplying with 12 max */
+ rz= pa->rectz;
+ if(rz==NULL) return;
+
+ for(y=0; y<pa->recty; y++)
+ for(x=0; x<pa->rectx; x++, rz++) (*rz)>>= 4;
+
+ rz1= pa->rectz;
+ rz2= rz1+pa->rectx;
+ rz3= rz2+pa->rectx;
+
+ rf= rectf+pa->rectx+1;
+
+ for(y=0; y<pa->recty-2; y++) {
+ for(x=0; x<pa->rectx-2; x++, rz1++, rz2++, rz3++, rf++) {
+
+ /* prevent overflow with sky z values */
+ zval1= rz1[0] + 2*rz1[1] + rz1[2];
+ zval2= 2*rz2[0] + 2*rz2[2];
+ zval3= rz3[0] + 2*rz3[1] + rz3[2];
+
+ col= ( 4*rz2[1] - (zval1 + zval2 + zval3)/3 );
+ if(col<0) col= -col;
+
+ col >>= 5;
+ if(col > (1<<16)) col= (1<<16);
+ else col= (R.r.edgeint*col)>>8;
+
+ if(col>0) {
+ float fcol;
+
+ if(col>255) fcol= 1.0f;
+ else fcol= (float)col/255.0f;
+
+ if(R.osa)
+ *rf+= fcol/(float)R.osa;
+ else
+ *rf= fcol;
+ }
+ }
+ rz1+= 2;
+ rz2+= 2;
+ rz3+= 2;
+ rf+= 2;
+ }
+
+ /* shift back zbuf values, we might need it still */
+ rz= pa->rectz;
+ for(y=0; y<pa->recty; y++)
+ for(x=0; x<pa->rectx; x++, rz++) (*rz)<<= 4;
+
+}
+
+static void reset_sky_speed(RenderPart *pa, RenderLayer *rl)
+{
+ /* for all pixels with max speed, set to zero */
+ float *fp;
+ int a;
+
+ fp= RE_RenderLayerGetPass(rl, SCE_PASS_VECTOR);
+ if(fp==NULL) return;
+
+ for(a= 4*pa->rectx*pa->recty - 1; a>=0; a--)
+ if(fp[a] == PASS_VECTOR_MAX) fp[a]= 0.0f;
+}
+
+
+static unsigned short *make_solid_mask(RenderPart *pa)
+{
+ long *rd= pa->rectdaps;
+ unsigned short *solidmask, *sp;
+ int x;
+
+ if(rd==NULL) return NULL;
+
+ sp=solidmask= MEM_mallocN(sizeof(short)*pa->rectx*pa->recty, "solidmask");
+
+ for(x=pa->rectx*pa->recty; x>0; x--, rd++, sp++) {
+ if(*rd) {
+ PixStr *ps= (PixStr *)*rd;
+
+ *sp= ps->mask;
+ for(ps= ps->next; ps; ps= ps->next)
+ *sp |= ps->mask;
+ }
+ else
+ *sp= 0;
+ }
+
+ return solidmask;
+}
+
+static void addAlphaOverFloatMask(float *dest, float *source, unsigned short dmask, unsigned short smask)
+{
+ unsigned short shared= dmask & smask;
+ float mul= 1.0 - source[3];
+
+ if(shared) { /* overlapping masks */
+
+ /* masks differ, we make a mixture of 'add' and 'over' */
+ if(shared!=dmask) {
+ float shared_bits= (float)count_mask(shared); /* alpha over */
+ float tot_bits= (float)count_mask(smask|dmask); /* alpha add */
+
+ float add= (tot_bits - shared_bits)/tot_bits; /* add level */
+ mul= add + (1.0f-add)*mul;
+ }
+ }
+ else if(dmask && smask) {
+ /* works for premul only, of course */
+ dest[0]+= source[0];
+ dest[1]+= source[1];
+ dest[2]+= source[2];
+ dest[3]+= source[3];
+
+ return;
+ }
+
+ dest[0]= (mul*dest[0]) + source[0];
+ dest[1]= (mul*dest[1]) + source[1];
+ dest[2]= (mul*dest[2]) + source[2];
+ dest[3]= (mul*dest[3]) + source[3];
+}
+
+
+/* main call for shading Delta Accum, for OSA */
+/* supposed to be fully threadable! */
+void zbufshadeDA_tile(RenderPart *pa)
+{
+ RenderResult *rr= pa->result;
+ RenderLayer *rl;
+ ListBase psmlist= {NULL, NULL};
+ float *edgerect= NULL;
+
+ set_part_zbuf_clipflag(pa);
+
+ /* allocate the necessary buffers */
+ /* zbuffer inits these rects */
+ pa->rectp= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectp");
+ pa->rectz= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectz");
+
+ for(rl= rr->layers.first; rl; rl= rl->next) {
+
+ /* initialize pixelstructs and edge buffer */
+ addpsmain(&psmlist);
+ pa->rectdaps= MEM_callocN(sizeof(long)*pa->rectx*pa->recty+4, "zbufDArectd");
+
+ if(rl->layflag & SCE_LAY_EDGE)
+ if(R.r.mode & R_EDGE)
+ edgerect= MEM_callocN(sizeof(float)*pa->rectx*pa->recty, "rectedge");
+
+ /* always fill visibility */
+ for(pa->sample=0; pa->sample<R.osa; pa->sample++) {
+ zbuffer_solid(pa, rl->lay, rl->layflag);
+ make_pixelstructs(pa, &psmlist);
+
+ if(rl->layflag & SCE_LAY_EDGE)
+ if(R.r.mode & R_EDGE)
+ edge_enhance_tile(pa, edgerect);
+
+ if(R.test_break()) break;
+ }
+
+ /* shades solid */
+ if(rl->layflag & SCE_LAY_SOLID)
+ shadeDA_tile(pa, rl);
+
+ /* lamphalo after solid, before ztra, looks nicest because ztra does own halo */
+ if(R.flag & R_LAMPHALO)
+ if(rl->layflag & SCE_LAY_HALO)
+ lamphalo_tile(pa, rl);
+
+ /* halo before ztra, because ztra fills in zbuffer now */
+ if(R.flag & R_HALO)
+ if(rl->layflag & SCE_LAY_HALO)
+ halo_tile(pa, rl->rectf, rl->lay);
+
+ /* transp layer */
+ if(R.flag & R_ZTRA) {
+ if(rl->layflag & SCE_LAY_ZTRA) {
+ unsigned short *ztramask, *solidmask= NULL; /* 16 bits, MAX_OSA */
+
+ /* allocate, but not free here, for asynchronous display of this rect in main thread */
+ rl->acolrect= MEM_callocN(4*sizeof(float)*pa->rectx*pa->recty, "alpha layer");
+
+ /* swap for live updates, and it is used in zbuf.c!!! */
+ SWAP(float *, rl->acolrect, rl->rectf);
+ ztramask= zbuffer_transp_shade(pa, rl, rl->rectf);
+ SWAP(float *, rl->acolrect, rl->rectf);
+
+ /* zbuffer transp only returns ztramask if there's solid rendered */
+ if(ztramask)
+ solidmask= make_solid_mask(pa);
+
+ if(ztramask && solidmask) {
+ unsigned short *sps= solidmask, *spz= ztramask;
+ unsigned short fullmask= (1<<R.osa)-1;
+ float *fcol= rl->rectf; float *acol= rl->acolrect;
+ int x;
+
+ for(x=pa->rectx*pa->recty; x>0; x--, acol+=4, fcol+=4, sps++, spz++) {
+ if(*sps == fullmask)
+ addAlphaOverFloat(fcol, acol);
+ else
+ addAlphaOverFloatMask(fcol, acol, *sps, *spz);
+ }
+ }
+ else {
+ float *fcol= rl->rectf; float *acol= rl->acolrect;
+ int x;
+ for(x=pa->rectx*pa->recty; x>0; x--, acol+=4, fcol+=4) {
+ addAlphaOverFloat(fcol, acol);
+ }
+ }
+ if(solidmask) MEM_freeN(solidmask);
+ if(ztramask) MEM_freeN(ztramask);
+ }
+ }
+ /* sky before edge */
+ if(rl->layflag & SCE_LAY_SKY)
+ sky_tile(pa, rl->rectf);
+
+ /* extra layers */
+ if(rl->layflag & SCE_LAY_EDGE)
+ if(R.r.mode & R_EDGE)
+ edge_enhance_add(pa, rl->rectf, edgerect);
+
+ if(rl->passflag & SCE_PASS_Z)
+ convert_zbuf_to_distbuf(pa, rl);
+
+ if(rl->passflag & SCE_PASS_VECTOR)
+ reset_sky_speed(pa, rl);
+
+ /* de-premul alpha */
+ if(R.r.alphamode & R_ALPHAKEY)
+ convert_to_key_alpha(pa, rl->rectf);
+
+ /* free stuff within loop! */
+ MEM_freeN(pa->rectdaps); pa->rectdaps= NULL;
+ freeps(&psmlist);
+
+ if(edgerect) MEM_freeN(edgerect);
+ edgerect= NULL;
+ }
+
+ /* free all */
+ MEM_freeN(pa->rectp); pa->rectp= NULL;
+ MEM_freeN(pa->rectz); pa->rectz= NULL;
+ MEM_freeN(pa->clipflag); pa->clipflag= NULL;
+
+ /* display active layer */
+ rr->renrect.ymin=rr->renrect.ymax= 0;
+ rr->renlay= render_get_active_layer(&R, rr);
+}
+
+
+/* ------------------------------------------------------------------------ */
+
+/* non OSA case, full tile render */
+/* supposed to be fully threadable! */
+void zbufshade_tile(RenderPart *pa)
+{
+ ShadeSample ssamp;
+ RenderResult *rr= pa->result;
+ RenderLayer *rl;
+ PixStr ps;
+ float *edgerect= NULL;
+ int addpassflag;
+
+ /* fake pixel struct, to comply to osa render */
+ ps.next= NULL;
+ ps.mask= 0xFFFF;
+
+ set_part_zbuf_clipflag(pa);
+
+ /* zbuffer code clears/inits rects */
+ pa->rectp= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectp");
+ pa->rectz= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectz");
+
+ for(rl= rr->layers.first; rl; rl= rl->next) {
+
+ /* general shader info, passes */
+ shade_sample_initialize(&ssamp, pa, rl);
+ addpassflag= rl->passflag & ~(SCE_PASS_Z|SCE_PASS_COMBINED);
+
+ zbuffer_solid(pa, rl->lay, rl->layflag);
+
+ if(!R.test_break()) { /* NOTE: this if() is not consistant */
+
+ /* edges only for solid part, ztransp doesn't support it yet anti-aliased */
+ if(rl->layflag & SCE_LAY_EDGE) {
+ if(R.r.mode & R_EDGE) {
+ edgerect= MEM_callocN(sizeof(float)*pa->rectx*pa->recty, "rectedge");
+ edge_enhance_tile(pa, edgerect);
+ }
+ }
+
+ /* initialize scanline updates for main thread */
+ rr->renrect.ymin= 0;
+ rr->renlay= rl;
+
+ if(rl->layflag & SCE_LAY_SOLID) {
+ float *fcol= rl->rectf;
+ int x, y, *rp= pa->rectp, *rz= pa->rectz, offs=0, seed;
+
+ /* we set per pixel a fixed seed, for random AO and shadow samples */
+ seed= pa->rectx*pa->disprect.ymin;
+
+ /* irregular shadowb buffer creation */
+ if(R.r.mode & R_SHADOW)
+ ISB_create(pa, NULL);
+
+ for(y=pa->disprect.ymin; y<pa->disprect.ymax; y++, rr->renrect.ymax++) {
+ for(x=pa->disprect.xmin; x<pa->disprect.xmax; x++, rz++, rp++, fcol+=4, offs++) {
+ /* per pixel fixed seed */
+ BLI_thread_srandom(pa->thread, seed++);
+
+ if(*rp) {
+ ps.facenr= *rp;
+ ps.z= *rz;
+ if(shade_samples(&ssamp, &ps, x, y)) {
+ QUATCOPY(fcol, ssamp.shr[0].combined);
+
+ /* passes */
+ if(addpassflag)
+ add_passes(rl, offs, ssamp.shi, ssamp.shr);
+ }
+ }
+ }
+ if(y&1)
+ if(R.test_break()) break;
+ }
+
+ if(R.r.mode & R_SHADOW)
+ ISB_free(pa);
+ }
+
+ /* disable scanline updating */
+ rr->renlay= NULL;
+ }
+
+ /* lamphalo after solid, before ztra, looks nicest because ztra does own halo */
+ if(R.flag & R_LAMPHALO)
+ if(rl->layflag & SCE_LAY_HALO)
+ lamphalo_tile(pa, rl);
+
+ /* halo before ztra, because ztra fills in zbuffer now */
+ if(R.flag & R_HALO)
+ if(rl->layflag & SCE_LAY_HALO)
+ halo_tile(pa, rl->rectf, rl->lay);
+
+ if(R.flag & R_ZTRA) {
+ if(rl->layflag & SCE_LAY_ZTRA) {
+ float *fcol, *acol;
+ int x;
+
+ /* allocate, but not free here, for asynchronous display of this rect in main thread */
+ rl->acolrect= MEM_callocN(4*sizeof(float)*pa->rectx*pa->recty, "alpha layer");
+
+ /* swap for live updates */
+ SWAP(float *, rl->acolrect, rl->rectf);
+ zbuffer_transp_shade(pa, rl, rl->rectf);
+ SWAP(float *, rl->acolrect, rl->rectf);
+
+ fcol= rl->rectf; acol= rl->acolrect;
+ for(x=pa->rectx*pa->recty; x>0; x--, acol+=4, fcol+=4) {
+ addAlphaOverFloat(fcol, acol);
+ }
+ }
+ }
+
+ /* sky before edge */
+ if(rl->layflag & SCE_LAY_SKY)
+ sky_tile(pa, rl->rectf);
+
+ if(!R.test_break()) {
+ if(rl->layflag & SCE_LAY_EDGE)
+ if(R.r.mode & R_EDGE)
+ edge_enhance_add(pa, rl->rectf, edgerect);
+ }
+
+ if(rl->passflag & SCE_PASS_Z)
+ convert_zbuf_to_distbuf(pa, rl);
+
+ if(rl->passflag & SCE_PASS_VECTOR)
+ reset_sky_speed(pa, rl);
+
+ /* de-premul alpha */
+ if(R.r.alphamode & R_ALPHAKEY)
+ convert_to_key_alpha(pa, rl->rectf);
+
+ if(edgerect) MEM_freeN(edgerect);
+ edgerect= NULL;
+ }
+
+ /* display active layer */
+ rr->renrect.ymin=rr->renrect.ymax= 0;
+ rr->renlay= render_get_active_layer(&R, rr);
+
+ MEM_freeN(pa->rectp); pa->rectp= NULL;
+ MEM_freeN(pa->rectz); pa->rectz= NULL;
+ MEM_freeN(pa->clipflag); pa->clipflag= NULL;
+}
+
+/* SSS preprocess tile render, fully threadable */
+typedef struct ZBufSSSHandle {
+ RenderPart *pa;
+ ListBase psmlist;
+ int totps;
+} ZBufSSSHandle;
+
+static void addps_sss(void *cb_handle, int facenr, int x, int y, int z)
+{
+ ZBufSSSHandle *handle = cb_handle;
+ RenderPart *pa= handle->pa;
+
+ /* extra border for filter gives double samples on part edges,
+ don't use those */
+ if(x<pa->crop || x>=pa->rectx-pa->crop)
+ return;
+ if(y<pa->crop || y>=pa->recty-pa->crop)
+ return;
+
+ if(pa->rectall) {
+ long *rs= pa->rectall + pa->rectx*y + x;
+
+ addps(&handle->psmlist, rs, facenr, z, 0);
+ handle->totps++;
+ }
+ if(pa->rectz) {
+ int *rz= pa->rectz + pa->rectx*y + x;
+ int *rp= pa->rectp + pa->rectx*y + x;
+
+ if(z < *rz) {
+ if(*rp == 0)
+ handle->totps++;
+ *rz= z;
+ *rp= facenr;
+ }
+ }
+ if(pa->rectbackz) {
+ int *rz= pa->rectbackz + pa->rectx*y + x;
+ int *rp= pa->rectbackp + pa->rectx*y + x;
+
+ if(z >= *rz) {
+ if(*rp == 0)
+ handle->totps++;
+ *rz= z;
+ *rp= facenr;
+ }
+ }
+}
+
+static void shade_sample_sss(ShadeSample *ssamp, Material *mat, VlakRen *vlr, int quad, float x, float y, float z, float *co, float *color, float *area)
+{
+ ShadeInput *shi= ssamp->shi;
+ ShadeResult shr;
+ float texfac, orthoarea, nor[3];
+
+ /* normal flipping must be disabled to make back scattering work, so that
+ backside faces actually face any lighting from the back */
+ shi->puno= 0;
+
+ /* cache for shadow */
+ shi->samplenr++;
+
+ if(quad)
+ shade_input_set_triangle_i(shi, vlr, 0, 2, 3);
+ else
+ shade_input_set_triangle_i(shi, vlr, 0, 1, 2);
+
+ /* we don't want flipped normals, they screw up back scattering */
+ if(vlr->noflag & R_FLIPPED_NO) {
+ shi->facenor[0]= -shi->facenor[0];
+ shi->facenor[1]= -shi->facenor[1];
+ shi->facenor[2]= -shi->facenor[2];
+ }
+
+ /* center pixel */
+ x += 0.5f;
+ y += 0.5f;
+
+ /* we estimate the area here using shi->dxco and shi->dyco. we need to
+ enabled shi->osatex these are filled. we compute two areas, one with
+ the normal pointed at the camera and one with the original normal, and
+ then clamp to avoid a too large contribution from a single pixel */
+ shi->osatex= 1;
+
+ VECCOPY(nor, shi->facenor);
+ calc_view_vector(shi->facenor, x, y);
+ Normalize(shi->facenor);
+ shade_input_set_viewco(shi, x, y, z);
+ orthoarea= VecLength(shi->dxco)*VecLength(shi->dyco);
+
+ VECCOPY(shi->facenor, nor);
+ shade_input_set_viewco(shi, x, y, z);
+ *area= VecLength(shi->dxco)*VecLength(shi->dyco);
+ *area= MIN2(*area, 2.0f*orthoarea);
+
+ shi->osatex= 0;
+
+ shade_input_set_uv(shi);
+ shade_input_set_normals(shi);
+
+ /* if nodetree, use the material that we are currently preprocessing
+ instead of the node material */
+ if(shi->mat->nodetree && shi->mat->use_nodes)
+ shi->mat= mat;
+
+ /* init material vars */
+ // note, keep this synced with render_types.h
+ memcpy(&shi->r, &shi->mat->r, 23*sizeof(float));
+ shi->har= shi->mat->har;
+
+ /* render */
+ shade_input_set_shade_texco(shi);
+
+ shade_samples_do_AO(ssamp);
+ shade_material_loop(shi, &shr);
+
+ VECCOPY(co, shi->co);
+ VECCOPY(color, shr.combined);
+
+ /* texture blending */
+ texfac= shi->mat->sss_texfac;
+
+ if(texfac == 0.0f) {
+ if(shr.col[0]!=0.0f) color[0] /= shr.col[0];
+ if(shr.col[1]!=0.0f) color[1] /= shr.col[1];
+ if(shr.col[2]!=0.0f) color[2] /= shr.col[2];
+ }
+ else if(texfac != 1.0f) {
+ if(shr.col[0]!=0.0f) color[0] *= pow(shr.col[0], texfac)/shr.col[0];
+ if(shr.col[1]!=0.0f) color[1] *= pow(shr.col[1], texfac)/shr.col[1];
+ if(shr.col[2]!=0.0f) color[2] *= pow(shr.col[2], texfac)/shr.col[2];
+ }
+}
+
+static void zbufshade_sss_free(RenderPart *pa)
+{
+ MEM_freeN(pa->clipflag); pa->clipflag= NULL;
+#if 0
+ MEM_freeN(pa->rectall); pa->rectall= NULL;
+ freeps(&handle.psmlist);
+#else
+ MEM_freeN(pa->rectz); pa->rectz= NULL;
+ MEM_freeN(pa->rectp); pa->rectp= NULL;
+ MEM_freeN(pa->rectbackz); pa->rectbackz= NULL;
+ MEM_freeN(pa->rectbackp); pa->rectbackp= NULL;
+#endif
+}
+
+void zbufshade_sss_tile(RenderPart *pa)
+{
+ Render *re= &R;
+ ShadeSample ssamp;
+ ZBufSSSHandle handle;
+ RenderResult *rr= pa->result;
+ RenderLayer *rl= rr->layers.first;
+ VlakRen *vlr;
+ Material *mat= re->sss_mat;
+ float (*co)[3], (*color)[3], *area, *fcol= rl->rectf;
+ int x, y, seed, quad, totpoint, display = !(re->r.scemode & R_PREVIEWBUTS);
+ int *rz, *rp, *rbz, *rbp;
+#if 0
+ PixStr *ps;
+ long *rs;
+ int z;
+#endif
+
+ set_part_zbuf_clipflag(pa);
+
+ /* setup pixelstr list and buffer for zbuffering */
+ handle.pa= pa;
+ handle.totps= 0;
+
+#if 0
+ handle.psmlist.first= handle.psmlist.last= NULL;
+ addpsmain(&handle.psmlist);
+
+ pa->rectall= MEM_callocN(sizeof(long)*pa->rectx*pa->recty+4, "rectall");
+#else
+ pa->rectp= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectp");
+ pa->rectz= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectz");
+ pa->rectbackp= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectbackp");
+ pa->rectbackz= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "rectbackz");
+#endif
+
+ /* create the pixelstrs to be used later */
+ zbuffer_sss(pa, rl->lay, &handle, addps_sss);
+
+ if(handle.totps==0) {
+ zbufshade_sss_free(pa);
+ return;
+ }
+
+ co= MEM_mallocN(sizeof(float)*3*handle.totps, "SSSCo");
+ color= MEM_mallocN(sizeof(float)*3*handle.totps, "SSSColor");
+ area= MEM_mallocN(sizeof(float)*handle.totps, "SSSArea");
+
+#if 0
+ /* create ISB (does not work currently!) */
+ if(re->r.mode & R_SHADOW)
+ ISB_create(pa, NULL);
+#endif
+
+ /* setup shade sample with correct passes */
+ memset(&ssamp, 0, sizeof(ssamp));
+ shade_sample_initialize(&ssamp, pa, rl);
+ ssamp.shi[0].passflag= SCE_PASS_DIFFUSE|SCE_PASS_AO|SCE_PASS_RADIO;
+ ssamp.shi[0].passflag |= SCE_PASS_RGBA;
+ ssamp.shi[0].combinedflag= ~(SCE_PASS_SPEC);
+ ssamp.tot= 1;
+
+ if(display) {
+ /* initialize scanline updates for main thread */
+ rr->renrect.ymin= 0;
+ rr->renlay= rl;
+ }
+
+ seed= pa->rectx*pa->disprect.ymin;
+#if 0
+ rs= pa->rectall;
+#else
+ rz= pa->rectz;
+ rp= pa->rectp;
+ rbz= pa->rectbackz;
+ rbp= pa->rectbackp;
+#endif
+ totpoint= 0;
+
+ for(y=pa->disprect.ymin; y<pa->disprect.ymax; y++, rr->renrect.ymax++) {
+ for(x=pa->disprect.xmin; x<pa->disprect.xmax; x++, fcol+=4) {
+ /* per pixel fixed seed */
+ BLI_thread_srandom(pa->thread, seed++);
+
+#if 0
+ if(rs) {
+ /* for each sample in this pixel, shade it */
+ for(ps=(PixStr*)*rs; ps; ps=ps->next) {
+ vlr= RE_findOrAddVlak(re, (ps->facenr-1) & RE_QUAD_MASK);
+ quad= (ps->facenr & RE_QUAD_OFFS);
+ z= ps->z;
+
+ shade_sample_sss(&ssamp, mat, vlr, quad, x, y, z,
+ co[totpoint], color[totpoint], &area[totpoint]);
+
+ totpoint++;
+
+ VECADD(fcol, fcol, color);
+ fcol[3]= 1.0f;
+ }
+
+ rs++;
+ }
+#else
+ if(rp) {
+ if(*rp != 0) {
+ /* shade front */
+ vlr= RE_findOrAddVlak(re, (*rp-1) & RE_QUAD_MASK);
+ quad= ((*rp) & RE_QUAD_OFFS);
+
+ shade_sample_sss(&ssamp, mat, vlr, quad, x, y, *rz,
+ co[totpoint], color[totpoint], &area[totpoint]);
+
+ VECADD(fcol, fcol, color[totpoint]);
+ fcol[3]= 1.0f;
+ totpoint++;
+ }
+
+ rp++; rz++;
+ }
+
+ if(rbp) {
+ if(*rbp != 0 && *rbp != *(rp-1)) {
+ /* shade back */
+ vlr= RE_findOrAddVlak(re, (*rbp-1) & RE_QUAD_MASK);
+ quad= ((*rbp) & RE_QUAD_OFFS);
+
+ shade_sample_sss(&ssamp, mat, vlr, quad, x, y, *rbz,
+ co[totpoint], color[totpoint], &area[totpoint]);
+
+ /* to indicate this is a back sample */
+ area[totpoint]= -area[totpoint];
+
+ VECADD(fcol, fcol, color[totpoint]);
+ fcol[3]= 1.0f;
+ totpoint++;
+ }
+
+ rbz++; rbp++;
+ }
+#endif
+ }
+
+ if(y&1)
+ if(re->test_break()) break;
+ }
+
+ /* note: after adding we do not free these arrays, sss keeps them */
+ if(totpoint > 0) {
+ sss_add_points(re, co, color, area, totpoint);
+ }
+ else {
+ MEM_freeN(co);
+ MEM_freeN(color);
+ MEM_freeN(area);
+ }
+
+#if 0
+ if(re->r.mode & R_SHADOW)
+ ISB_free(pa);
+#endif
+
+ if(display) {
+ /* display active layer */
+ rr->renrect.ymin=rr->renrect.ymax= 0;
+ rr->renlay= render_get_active_layer(&R, rr);
+ }
+
+ zbufshade_sss_free(pa);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static void renderhalo_post(RenderResult *rr, float *rectf, HaloRen *har) /* postprocess version */
+{
+ float dist, xsq, ysq, xn, yn, colf[4], *rectft, *rtf;
+ float haloxs, haloys;
+ int minx, maxx, miny, maxy, x, y;
+
+ /* calculate the disprect mapped coordinate for halo. note: rectx is disprect corrected */
+ haloxs= har->xs - R.disprect.xmin;
+ haloys= har->ys - R.disprect.ymin;
+
+ har->miny= miny= haloys - har->rad/R.ycor;
+ har->maxy= maxy= haloys + har->rad/R.ycor;
+
+ if(maxy<0);
+ else if(rr->recty<miny);
+ else {
+ minx= floor(haloxs-har->rad);
+ maxx= ceil(haloxs+har->rad);
+
+ if(maxx<0);
+ else if(rr->rectx<minx);
+ else {
+
+ if(minx<0) minx= 0;
+ if(maxx>=rr->rectx) maxx= rr->rectx-1;
+ if(miny<0) miny= 0;
+ if(maxy>rr->recty) maxy= rr->recty;
+
+ rectft= rectf+ 4*rr->rectx*miny;
+
+ for(y=miny; y<maxy; y++) {
+
+ rtf= rectft+4*minx;
+
+ yn= (y - haloys)*R.ycor;
+ ysq= yn*yn;
+
+ for(x=minx; x<=maxx; x++) {
+ xn= x - haloxs;
+ xsq= xn*xn;
+ dist= xsq+ysq;
+ if(dist<har->radsq) {
+
+ shadeHaloFloat(har, colf, 0x7FFFFF, dist, xn, yn, har->flarec);
+ addalphaAddfacFloat(rtf, colf, har->add);
+ }
+ rtf+=4;
+ }
+
+ rectft+= 4*rr->rectx;
+
+ if(R.test_break()) break;
+ }
+ }
+ }
+}
+/* ------------------------------------------------------------------------ */
+
+static void renderflare(RenderResult *rr, float *rectf, HaloRen *har)
+{
+ extern float hashvectf[];
+ HaloRen fla;
+ Material *ma;
+ float *rc, rad, alfa, visifac, vec[3];
+ int b, type;
+
+ fla= *har;
+ fla.linec= fla.ringc= fla.flarec= 0;
+
+ rad= har->rad;
+ alfa= har->alfa;
+
+ visifac= R.ycor*(har->pixels);
+ /* all radials added / r^3 == 1.0f! */
+ visifac /= (har->rad*har->rad*har->rad);
+ visifac*= visifac;
+
+ ma= har->mat;
+
+ /* first halo: just do */
+
+ har->rad= rad*ma->flaresize*visifac;
+ har->radsq= har->rad*har->rad;
+ har->zs= fla.zs= 0;
+
+ har->alfa= alfa*visifac;
+
+ renderhalo_post(rr, rectf, har);
+
+ /* next halo's: the flares */
+ rc= hashvectf + ma->seed2;
+
+ for(b=1; b<har->flarec; b++) {
+
+ fla.r= fabs(rc[0]);
+ fla.g= fabs(rc[1]);
+ fla.b= fabs(rc[2]);
+ fla.alfa= ma->flareboost*fabs(alfa*visifac*rc[3]);
+ fla.hard= 20.0f + fabs(70*rc[7]);
+ fla.tex= 0;
+
+ type= (int)(fabs(3.9*rc[6]));
+
+ fla.rad= ma->subsize*sqrt(fabs(2.0f*har->rad*rc[4]));
+
+ if(type==3) {
+ fla.rad*= 3.0f;
+ fla.rad+= R.rectx/10;
+ }
+
+ fla.radsq= fla.rad*fla.rad;
+
+ vec[0]= 1.4*rc[5]*(har->xs-R.winx/2);
+ vec[1]= 1.4*rc[5]*(har->ys-R.winy/2);
+ vec[2]= 32.0f*sqrt(vec[0]*vec[0] + vec[1]*vec[1] + 1.0f);
+
+ fla.xs= R.winx/2 + vec[0] + (1.2+rc[8])*R.rectx*vec[0]/vec[2];
+ fla.ys= R.winy/2 + vec[1] + (1.2+rc[8])*R.rectx*vec[1]/vec[2];
+
+ if(R.flag & R_SEC_FIELD) {
+ if(R.r.mode & R_ODDFIELD) fla.ys += 0.5;
+ else fla.ys -= 0.5;
+ }
+ if(type & 1) fla.type= HA_FLARECIRC;
+ else fla.type= 0;
+ renderhalo_post(rr, rectf, &fla);
+
+ fla.alfa*= 0.5;
+ if(type & 2) fla.type= HA_FLARECIRC;
+ else fla.type= 0;
+ renderhalo_post(rr, rectf, &fla);
+
+ rc+= 7;
+ }
+}
+
+/* needs recode... integrate this better! */
+void add_halo_flare(Render *re)
+{
+ RenderResult *rr= re->result;
+ RenderLayer *rl;
+ HaloRen *har = NULL;
+ int a, mode, do_draw=0;
+
+ /* for now, we get the first renderlayer in list with halos set */
+ for(rl= rr->layers.first; rl; rl= rl->next)
+ if(rl->layflag & SCE_LAY_HALO)
+ break;
+
+ if(rl==NULL || rl->rectf==NULL)
+ return;
+
+ mode= R.r.mode;
+ R.r.mode &= ~R_PANORAMA;
+
+ project_renderdata(&R, projectverto, 0, 0);
+
+ for(a=0; a<R.tothalo; a++) {
+ if((a & 255)==0) har= R.bloha[a>>8];
+ else har++;
+
+ if(har->flarec) {
+ do_draw= 1;
+ renderflare(rr, rl->rectf, har);
+ }
+ }
+
+ if(do_draw) {
+ /* weak... the display callback wants an active renderlayer pointer... */
+ rr->renlay= rl;
+ re->display_draw(rr, NULL);
+ }
+
+ R.r.mode= mode;
+}
+
+/* ************************* used for shaded view ************************ */
+
+/* if *re, then initialize, otherwise execute */
+void RE_shade_external(Render *re, ShadeInput *shi, ShadeResult *shr)
+{
+ static VlakRen vlr;
+
+ /* init */
+ if(re) {
+ R= *re;
+
+ /* fake render face */
+ memset(&vlr, 0, sizeof(VlakRen));
+ vlr.lay= -1;
+
+ return;
+ }
+ shi->vlr= &vlr;
+
+ if(shi->mat->nodetree && shi->mat->use_nodes)
+ ntreeShaderExecTree(shi->mat->nodetree, shi, shr);
+ else {
+ /* copy all relevant material vars, note, keep this synced with render_types.h */
+ memcpy(&shi->r, &shi->mat->r, 23*sizeof(float));
+ shi->har= shi->mat->har;
+
+ shade_material_loop(shi, shr);
+ }
+}
+
+/* ************************* bake ************************ */
+
+#define FTOCHAR(val) val<=0.0f?0: (val>=1.0f?255: (char)(255.0f*val))
+
+typedef struct BakeShade {
+ ShadeSample ssamp;
+ VlakRen *vlr;
+
+ ZSpan *zspan;
+ Image *ima;
+ ImBuf *ibuf;
+
+ int rectx, recty, quad, type, vdone, ready;
+
+ unsigned int *rect;
+ float *rect_float;
+} BakeShade;
+
+static void do_bake_shade(void *handle, int x, int y, float u, float v)
+{
+ BakeShade *bs= handle;
+ ShadeSample *ssamp= &bs->ssamp;
+ ShadeInput *shi= ssamp->shi;
+ ShadeResult shr;
+ VlakRen *vlr= bs->vlr;
+ float l, *v1, *v2, *v3;
+
+ /* fast threadsafe break test */
+ if(R.test_break())
+ return;
+
+ /* setup render coordinates */
+ if(bs->quad) {
+ v1= vlr->v1->co;
+ v2= vlr->v3->co;
+ v3= vlr->v4->co;
+ }
+ else {
+ v1= vlr->v1->co;
+ v2= vlr->v2->co;
+ v3= vlr->v3->co;
+ }
+
+ /* renderco */
+ l= 1.0f-u-v;
+
+ shi->co[0]= l*v3[0]+u*v1[0]+v*v2[0];
+ shi->co[1]= l*v3[1]+u*v1[1]+v*v2[1];
+ shi->co[2]= l*v3[2]+u*v1[2]+v*v2[2];
+
+ /* set up view vector */
+ VECCOPY(shi->view, shi->co);
+ Normalize(shi->view);
+
+ /* no face normal flip */
+ shi->puno= 0;
+
+ /* cache for shadow */
+ shi->samplenr++;
+
+ if(bs->quad)
+ shade_input_set_triangle_i(shi, vlr, 0, 2, 3);
+ else
+ shade_input_set_triangle_i(shi, vlr, 0, 1, 2);
+
+ shi->u= -u;
+ shi->v= -v;
+ shi->xs= x;
+ shi->ys= y;
+
+ shade_input_set_normals(shi);
+
+ /* init material vars */
+ memcpy(&shi->r, &shi->mat->r, 23*sizeof(float)); // note, keep this synced with render_types.h
+ shi->har= shi->mat->har;
+
+ if(bs->type==RE_BAKE_AO) {
+ ambient_occlusion(shi);
+ ambient_occlusion_to_diffuse(shi, shr.combined);
+ }
+ else {
+
+ shade_input_set_shade_texco(shi);
+
+ shade_samples_do_AO(ssamp);
+
+ if(shi->mat->nodetree && shi->mat->use_nodes) {
+ ntreeShaderExecTree(shi->mat->nodetree, shi, &shr);
+ shi->mat= vlr->mat; /* shi->mat is being set in nodetree */
+ }
+ else
+ shade_material_loop(shi, &shr);
+
+ if(bs->type==RE_BAKE_NORMALS) {
+ shr.combined[0]= shi->vn[0]/2.0f + 0.5f;
+ shr.combined[1]= 0.5f - shi->vn[1]/2.0f;
+ shr.combined[2]= shi->vn[2]/2.0f + 0.5f;
+ }
+ else if(bs->type==RE_BAKE_TEXTURE) {
+ shr.combined[0]= shi->r;
+ shr.combined[1]= shi->g;
+ shr.combined[2]= shi->b;
+ }
+ }
+
+ if(bs->rect) {
+ char *col= (char *)(bs->rect + bs->rectx*y + x);
+ col[0]= FTOCHAR(shr.combined[0]);
+ col[1]= FTOCHAR(shr.combined[1]);
+ col[2]= FTOCHAR(shr.combined[2]);
+ col[3]= 255;
+ }
+ else {
+ float *col= bs->rect_float + 4*(bs->rectx*y + x);
+ VECCOPY(col, shr.combined);
+ col[3]= 1.0f;
+ }
+}
+
+static int get_next_bake_face(BakeShade *bs)
+{
+ VlakRen *vlr;
+ MTFace *tface;
+ static int v= 0, vdone= 0;
+
+ if(bs==NULL) {
+ vlr= NULL;
+ v= vdone= 0;
+ return 0;
+ }
+
+ BLI_lock_thread(LOCK_CUSTOM1);
+
+ for(; v<R.totvlak; v++) {
+ vlr= RE_findOrAddVlak(&R, v);
+
+ if(vlr->ob->flag & SELECT) {
+ tface= RE_vlakren_get_tface(&R, vlr, 0, NULL, 0);
+
+ if(tface && tface->tpage) {
+ Image *ima= tface->tpage;
+ ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL);
+ float vec[4]= {0.0f, 0.0f, 0.0f, 0.0f};
+
+ if(ibuf==NULL)
+ continue;
+
+ if(ibuf->rect==NULL && ibuf->rect_float==NULL)
+ continue;
+
+ if(ibuf->rect_float && !(ibuf->channels==0 || ibuf->channels==4))
+ continue;
+
+ /* find the image for the first time? */
+ if(ima->id.flag & LIB_DOIT) {
+ ima->id.flag &= ~LIB_DOIT;
+
+ /* we either fill in float or char, this ensures things go fine */
+ if(ibuf->rect_float)
+ imb_freerectImBuf(ibuf);
+ /* clear image */
+ if(R.r.bake_flag & R_BAKE_CLEAR)
+ IMB_rectfill(ibuf, vec);
+
+ /* might be read by UI to set active image for display */
+ R.bakebuf= ima;
+ }
+
+ bs->vlr= vlr;
+
+ bs->vdone++; /* only for error message if nothing was rendered */
+ v++;
+
+ BLI_unlock_thread(LOCK_CUSTOM1);
+ return 1;
+ }
+ }
+ }
+
+ BLI_unlock_thread(LOCK_CUSTOM1);
+ return 0;
+}
+
+/* already have tested for tface and ima and zspan */
+static void shade_tface(BakeShade *bs)
+{
+ VlakRen *vlr= bs->vlr;
+ MTFace *tface= RE_vlakren_get_tface(&R, vlr, 0, NULL, 0);
+ Image *ima= tface->tpage;
+ float vec[4][2];
+ int a, i1, i2, i3;
+
+ /* check valid zspan */
+ if(ima!=bs->ima) {
+ bs->ima= ima;
+ bs->ibuf= BKE_image_get_ibuf(ima, NULL);
+ /* note, these calls only free/fill contents of zspan struct, not zspan itself */
+ zbuf_free_span(bs->zspan);
+ zbuf_alloc_span(bs->zspan, bs->ibuf->x, bs->ibuf->y);
+ }
+
+ bs->rectx= bs->ibuf->x;
+ bs->recty= bs->ibuf->y;
+ bs->rect= bs->ibuf->rect;
+ bs->rect_float= bs->ibuf->rect_float;
+ bs->quad= 0;
+
+ /* get pixel level vertex coordinates */
+ for(a=0; a<4; a++) {
+ vec[a][0]= tface->uv[a][0]*(float)bs->rectx - 0.5f;
+ vec[a][1]= tface->uv[a][1]*(float)bs->recty - 0.5f;
+ }
+
+ /* UV indices have to be corrected for possible quad->tria splits */
+ i1= 0; i2= 1; i3= 2;
+ vlr_set_uv_indices(vlr, &i1, &i2, &i3);
+ zspan_scanconvert(bs->zspan, bs, vec[i1], vec[i2], vec[i3], do_bake_shade);
+
+ if(vlr->v4) {
+ bs->quad= 1;
+ zspan_scanconvert(bs->zspan, bs, vec[0], vec[2], vec[3], do_bake_shade);
+ }
+}
+
+static void *do_bake_thread(void *bs_v)
+{
+ BakeShade *bs= bs_v;
+
+ while(get_next_bake_face(bs)) {
+ shade_tface(bs);
+
+ /* fast threadsafe break test */
+ if(R.test_break())
+ break;
+ }
+ bs->ready= 1;
+
+ return NULL;
+}
+
+/* using object selection tags, the faces with UV maps get baked */
+/* render should have been setup */
+/* returns 0 if nothing was handled */
+int RE_bake_shade_all_selected(Render *re, int type)
+{
+ BakeShade handles[BLENDER_MAX_THREADS];
+ ListBase threads;
+ Image *ima;
+ int a, vdone=0;
+
+ /* initialize static vars */
+ get_next_bake_face(NULL);
+
+ /* baker uses this flag to detect if image was initialized */
+ for(ima= G.main->image.first; ima; ima= ima->id.next)
+ ima->id.flag |= LIB_DOIT;
+
+ /* initialize render global */
+ R= *re;
+ R.bakebuf= NULL;
+
+ BLI_init_threads(&threads, do_bake_thread, re->r.threads);
+
+ /* get the threads running */
+ for(a=0; a<re->r.threads; a++) {
+ /* set defaults in handles */
+ memset(&handles[a], 0, sizeof(BakeShade));
+
+ handles[a].ssamp.shi[0].lay= re->scene->lay;
+ handles[a].ssamp.shi[0].passflag= SCE_PASS_COMBINED;
+ handles[a].ssamp.shi[0].combinedflag= ~(SCE_PASS_SPEC);
+ handles[a].ssamp.shi[0].thread= a;
+ handles[a].ssamp.tot= 1;
+
+ handles[a].type= type;
+ handles[a].zspan= MEM_callocN(sizeof(ZSpan), "zspan for bake");
+
+ BLI_insert_thread(&threads, &handles[a]);
+ }
+
+ /* wait for everything to be done */
+ a= 0;
+ while(a!=re->r.threads) {
+
+ PIL_sleep_ms(50);
+
+ for(a=0; a<re->r.threads; a++)
+ if(handles[a].ready==0)
+ break;
+ }
+
+ /* filter images */
+ for(ima= G.main->image.first; ima; ima= ima->id.next) {
+ if((ima->id.flag & LIB_DOIT)==0) {
+ ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL);
+ for(a=0; a<re->r.bake_filter; a++)
+ IMB_filter_extend(ibuf);
+ ibuf->userflags |= IB_BITMAPDIRTY;
+ }
+ }
+
+ /* calculate return value */
+ for(a=0; a<re->r.threads; a++) {
+ vdone+= handles[a].vdone;
+
+ zbuf_free_span(handles[a].zspan);
+ MEM_freeN(handles[a].zspan);
+ }
+
+ BLI_end_threads(&threads);
+ return vdone;
+}
+
+struct Image *RE_bake_shade_get_image(void)
+{
+ return R.bakebuf;
+}
+
diff --git a/source/blender/render/intern/source/renderdatabase.c b/source/blender/render/intern/source/renderdatabase.c
new file mode 100644
index 00000000000..6d9f0e4eb01
--- /dev/null
+++ b/source/blender/render/intern/source/renderdatabase.c
@@ -0,0 +1,938 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): 2004-2006, Blender Foundation, full recode
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/*
+ * Storage, retrieval and query of render specific data.
+ *
+ * All data from a Blender scene is converted by the renderconverter/
+ * into a special format that is used by the render module to make
+ * images out of. These functions interface to the render-specific
+ * database.
+ *
+ * The blo{ha/ve/vl} arrays store pointers to blocks of 256 data
+ * entries each.
+ *
+ * The index of an entry is >>8 (the highest 24 * bits), to find an
+ * offset in a 256-entry block.
+ *
+ * - If the 256-entry block entry has an entry in the
+ * vertnodes/vlaknodes/bloha array of the current block, the i-th entry in
+ * that block is allocated to this entry.
+ *
+ * - If the entry has no block allocated for it yet, memory is
+ * allocated.
+ *
+ * The pointer to the correct entry is returned. Memory is guarateed
+ * to exist (as long as the malloc does not break). Since guarded
+ * allocation is used, memory _must_ be available. Otherwise, an
+ * exit(0) would occur.
+ *
+ */
+
+#include <limits.h>
+#include <math.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+#include "BKE_utildefines.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+#include "BLI_memarena.h"
+
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_texture_types.h"
+
+#include "BKE_customdata.h"
+#include "BKE_texture.h"
+
+#include "RE_render_ext.h" /* externtex */
+
+#include "renderpipeline.h"
+#include "render_types.h"
+#include "renderdatabase.h"
+#include "texture.h"
+#include "zbuf.h"
+
+/* ------------------------------------------------------------------------- */
+
+/* More dynamic allocation of options for render vertices and faces, so we dont
+ have to reserve this space inside vertices.
+ Important; vertices and faces, should have been created already (to get tables
+ checked) that's a reason why the calls demand VertRen/VlakRen * as arg, not
+ the index */
+
+/* NOTE! the hardcoded table size 256 is used still in code for going quickly over vertices/faces */
+
+#define RE_STICKY_ELEMS 2
+#define RE_STRESS_ELEMS 1
+#define RE_RAD_ELEMS 4
+#define RE_STRAND_ELEMS 1
+#define RE_TANGENT_ELEMS 3
+#define RE_STRESS_ELEMS 1
+#define RE_WINSPEED_ELEMS 4
+#define RE_MTFACE_ELEMS 1
+#define RE_MCOL_ELEMS 4
+
+float *RE_vertren_get_sticky(Render *re, VertRen *ver, int verify)
+{
+ float *sticky;
+ int nr= ver->index>>8;
+
+ sticky= re->vertnodes[nr].sticky;
+ if(sticky==NULL) {
+ if(verify)
+ sticky= re->vertnodes[nr].sticky= MEM_mallocN(256*RE_STICKY_ELEMS*sizeof(float), "sticky table");
+ else
+ return NULL;
+ }
+ return sticky + (ver->index & 255)*RE_STICKY_ELEMS;
+}
+
+float *RE_vertren_get_stress(Render *re, VertRen *ver, int verify)
+{
+ float *stress;
+ int nr= ver->index>>8;
+
+ stress= re->vertnodes[nr].stress;
+ if(stress==NULL) {
+ if(verify)
+ stress= re->vertnodes[nr].stress= MEM_mallocN(256*RE_STRESS_ELEMS*sizeof(float), "stress table");
+ else
+ return NULL;
+ }
+ return stress + (ver->index & 255)*RE_STRESS_ELEMS;
+}
+
+/* this one callocs! */
+float *RE_vertren_get_rad(Render *re, VertRen *ver, int verify)
+{
+ float *rad;
+ int nr= ver->index>>8;
+
+ rad= re->vertnodes[nr].rad;
+ if(rad==NULL) {
+ if(verify)
+ rad= re->vertnodes[nr].rad= MEM_callocN(256*RE_RAD_ELEMS*sizeof(float), "rad table");
+ else
+ return NULL;
+ }
+ return rad + (ver->index & 255)*RE_RAD_ELEMS;
+}
+
+float *RE_vertren_get_strand(Render *re, VertRen *ver, int verify)
+{
+ float *strand;
+ int nr= ver->index>>8;
+
+ strand= re->vertnodes[nr].strand;
+ if(strand==NULL) {
+ if(verify)
+ strand= re->vertnodes[nr].strand= MEM_mallocN(256*RE_STRAND_ELEMS*sizeof(float), "strand table");
+ else
+ return NULL;
+ }
+ return strand + (ver->index & 255)*RE_STRAND_ELEMS;
+}
+
+/* needs calloc */
+float *RE_vertren_get_tangent(Render *re, VertRen *ver, int verify)
+{
+ float *tangent;
+ int nr= ver->index>>8;
+
+ tangent= re->vertnodes[nr].tangent;
+ if(tangent==NULL) {
+ if(verify)
+ tangent= re->vertnodes[nr].tangent= MEM_callocN(256*RE_TANGENT_ELEMS*sizeof(float), "tangent table");
+ else
+ return NULL;
+ }
+ return tangent + (ver->index & 255)*RE_TANGENT_ELEMS;
+}
+
+/* needs calloc! not all renderverts have them */
+float *RE_vertren_get_winspeed(Render *re, VertRen *ver, int verify)
+{
+ float *winspeed;
+ int nr= ver->index>>8;
+
+ winspeed= re->vertnodes[nr].winspeed;
+ if(winspeed==NULL) {
+ if(verify)
+ winspeed= re->vertnodes[nr].winspeed= MEM_callocN(256*RE_WINSPEED_ELEMS*sizeof(float), "winspeed table");
+ else
+ return NULL;
+ }
+ return winspeed + (ver->index & 255)*RE_WINSPEED_ELEMS;
+}
+
+VertRen *RE_vertren_copy(Render *re, VertRen *ver)
+{
+ VertRen *v1= RE_findOrAddVert(re, re->totvert++);
+ float *fp1, *fp2;
+ int index= v1->index;
+
+ *v1= *ver;
+ v1->index= index;
+
+ fp1= RE_vertren_get_sticky(re, ver, 0);
+ if(fp1) {
+ fp2= RE_vertren_get_sticky(re, v1, 1);
+ memcpy(fp2, fp1, RE_STICKY_ELEMS*sizeof(float));
+ }
+ fp1= RE_vertren_get_stress(re, ver, 0);
+ if(fp1) {
+ fp2= RE_vertren_get_stress(re, v1, 1);
+ memcpy(fp2, fp1, RE_STRESS_ELEMS*sizeof(float));
+ }
+ fp1= RE_vertren_get_rad(re, ver, 0);
+ if(fp1) {
+ fp2= RE_vertren_get_rad(re, v1, 1);
+ memcpy(fp2, fp1, RE_RAD_ELEMS*sizeof(float));
+ }
+ fp1= RE_vertren_get_strand(re, ver, 0);
+ if(fp1) {
+ fp2= RE_vertren_get_strand(re, v1, 1);
+ memcpy(fp2, fp1, RE_STRAND_ELEMS*sizeof(float));
+ }
+ fp1= RE_vertren_get_tangent(re, ver, 0);
+ if(fp1) {
+ fp2= RE_vertren_get_tangent(re, v1, 1);
+ memcpy(fp2, fp1, RE_TANGENT_ELEMS*sizeof(float));
+ }
+ fp1= RE_vertren_get_winspeed(re, ver, 0);
+ if(fp1) {
+ fp2= RE_vertren_get_winspeed(re, v1, 1);
+ memcpy(fp2, fp1, RE_WINSPEED_ELEMS*sizeof(float));
+ }
+ return v1;
+}
+
+VertRen *RE_findOrAddVert(Render *re, int nr)
+{
+ VertTableNode *temp;
+ VertRen *v;
+ int a;
+
+ if(nr<0) {
+ printf("error in findOrAddVert: %d\n",nr);
+ return NULL;
+ }
+ a= nr>>8;
+
+ if (a>=re->vertnodeslen-1) { /* Need to allocate more columns..., and keep last element NULL for free loop */
+ temp= re->vertnodes;
+
+ re->vertnodes= MEM_mallocN(sizeof(VertTableNode)*(re->vertnodeslen+TABLEINITSIZE) , "vertnodes");
+ if(temp) memcpy(re->vertnodes, temp, re->vertnodeslen*sizeof(VertTableNode));
+ memset(re->vertnodes+re->vertnodeslen, 0, TABLEINITSIZE*sizeof(VertTableNode));
+
+ re->vertnodeslen+=TABLEINITSIZE;
+ if(temp) MEM_freeN(temp);
+ }
+
+ v= re->vertnodes[a].vert;
+ if(v==NULL) {
+ int i;
+
+ v= (VertRen *)MEM_callocN(256*sizeof(VertRen),"findOrAddVert");
+ re->vertnodes[a].vert= v;
+
+ for(i= (nr & 0xFFFFFF00), a=0; a<256; a++, i++) {
+ v[a].index= i;
+ }
+ }
+ v+= (nr & 255);
+ return v;
+}
+
+/* ------------------------------------------------------------------------ */
+
+MTFace *RE_vlakren_get_tface(Render *re, VlakRen *vlr, int n, char **name, int verify)
+{
+ VlakTableNode *node;
+ int nr= vlr->index>>8, vlakindex= (vlr->index&255);
+ int index= (n<<8) + vlakindex;
+
+ node= &re->vlaknodes[nr];
+
+ if(verify) {
+ if(n>=node->totmtface) {
+ MTFace **mtface= node->mtface;
+ int size= size= (n+1)*256;
+
+ node->mtface= MEM_callocN(size*sizeof(MTFace*), "Vlak mtface");
+
+ if(mtface) {
+ size= node->totmtface*256;
+ memcpy(node->mtface, mtface, size*sizeof(MTFace*));
+ MEM_freeN(mtface);
+ }
+
+ node->totmtface= n+1;
+
+ if (!node->names) {
+ size= sizeof(*node->names)*256;
+ node->names= MEM_callocN(size, "Vlak names");
+ }
+ }
+
+ if(node->mtface[index]==NULL) {
+ node->mtface[index]= BLI_memarena_alloc(re->memArena,
+ sizeof(MTFace)*RE_MTFACE_ELEMS);
+
+ node->names[vlakindex]= re->customdata_names.last;
+ }
+ }
+ else {
+ if(n>=node->totmtface || node->mtface[index]==NULL)
+ return NULL;
+
+ if(name) *name= node->names[vlakindex]->mtface[n];
+ }
+
+ return node->mtface[index];
+}
+
+MCol *RE_vlakren_get_mcol(Render *re, VlakRen *vlr, int n, char **name, int verify)
+{
+ VlakTableNode *node;
+ int nr= vlr->index>>8, vlakindex= (vlr->index&255);
+ int index= (n<<8) + vlakindex;
+
+ node= &re->vlaknodes[nr];
+
+ if(verify) {
+ if(n>=node->totmcol) {
+ MCol **mcol= node->mcol;
+ int size= (n+1)*256;
+
+ node->mcol= MEM_callocN(size*sizeof(MCol*), "Vlak mcol");
+
+ if(mcol) {
+ size= node->totmcol*256;
+ memcpy(node->mcol, mcol, size*sizeof(MCol*));
+ MEM_freeN(mcol);
+ }
+
+ node->totmcol= n+1;
+
+ if (!node->names) {
+ size= sizeof(*node->names)*256;
+ node->names= MEM_callocN(size, "Vlak names");
+ }
+ }
+
+ if(node->mcol[index]==NULL) {
+ node->mcol[index]= BLI_memarena_alloc(re->memArena,
+ sizeof(MCol)*RE_MCOL_ELEMS);
+
+ node->names[vlakindex]= re->customdata_names.last;
+ }
+ }
+ else {
+ if(n>=node->totmcol || node->mcol[index]==NULL)
+ return NULL;
+
+ if(name) *name= node->names[vlakindex]->mcol[n];
+ }
+
+ return node->mcol[index];
+}
+
+VlakRen *RE_vlakren_copy(Render *re, VlakRen *vlr)
+{
+ VlakRen *vlr1 = RE_findOrAddVlak(re, re->totvlak++);
+ MTFace *mtface, *mtface1;
+ MCol *mcol, *mcol1;
+ VlakTableNode *node = &re->vlaknodes[vlr->index>>8];
+ VlakTableNode *node1 = &re->vlaknodes[vlr1->index>>8];
+ int i, index = vlr1->index;
+ char *name;
+
+ *vlr1= *vlr;
+ vlr1->index= index;
+
+ for (i=0; (mtface=RE_vlakren_get_tface(re, vlr, i, &name, 0)) != NULL; i++) {
+ mtface1= RE_vlakren_get_tface(re, vlr1, i, &name, 1);
+ memcpy(mtface1, mtface, sizeof(MTFace)*RE_MTFACE_ELEMS);
+ }
+
+ for (i=0; (mcol=RE_vlakren_get_mcol(re, vlr, i, &name, 0)) != NULL; i++) {
+ mcol1= RE_vlakren_get_mcol(re, vlr1, i, &name, 1);
+ memcpy(mcol1, mcol, sizeof(MCol)*RE_MCOL_ELEMS);
+ }
+
+ if (node->names && node1->names)
+ node1->names[vlr1->index&255] = node->names[vlr->index&255];
+
+ return vlr1;
+}
+
+static int vlakren_remap_layer_num(int n, int active)
+{
+ /* make the active layer the first */
+ if (n == active) return 0;
+ else if (n < active) return n+1;
+ else return n;
+}
+
+void RE_vlakren_set_customdata_names(Render *re, CustomData *data)
+{
+ /* CustomData layer names are stored per object here, because the
+ DerivedMesh which stores the layers is freed */
+
+ CustomDataNames *cdn= MEM_callocN(sizeof(*cdn), "CustomDataNames");
+ CustomDataLayer *layer;
+ int numlayers, i, mtfn, mcn, n;
+
+ BLI_addtail(&re->customdata_names, cdn);
+
+ if (CustomData_has_layer(data, CD_MTFACE)) {
+ numlayers= CustomData_number_of_layers(data, CD_MTFACE);
+ cdn->mtface= MEM_callocN(sizeof(*cdn->mtface)*numlayers, "mtfacenames");
+ }
+
+ if (CustomData_has_layer(data, CD_MCOL)) {
+ numlayers= CustomData_number_of_layers(data, CD_MCOL);
+ cdn->mcol= MEM_callocN(sizeof(*cdn->mcol)*numlayers, "mcolnames");
+ }
+
+ for (i=0, mtfn=0, mcn=0; i < data->totlayer; i++) {
+ layer= &data->layers[i];
+
+ if (layer->type == CD_MTFACE) {
+ n= vlakren_remap_layer_num(mtfn++, layer->active_rnd);
+ strcpy(cdn->mtface[n], layer->name);
+ }
+ else if (layer->type == CD_MCOL) {
+ n= vlakren_remap_layer_num(mcn++, layer->active_rnd);
+ strcpy(cdn->mcol[n], layer->name);
+ }
+ }
+}
+
+VlakRen *RE_findOrAddVlak(Render *re, int nr)
+{
+ VlakTableNode *temp;
+ VlakRen *v;
+ int a;
+
+ if(nr<0) {
+ printf("error in findOrAddVlak: %d\n",nr);
+ return re->vlaknodes[0].vlak;
+ }
+ a= nr>>8;
+
+ if (a>=re->vlaknodeslen-1){ /* Need to allocate more columns..., and keep last element NULL for free loop */
+ temp= re->vlaknodes;
+
+ re->vlaknodes= MEM_mallocN(sizeof(VlakTableNode)*(re->vlaknodeslen+TABLEINITSIZE) , "vlaknodes");
+ if(temp) memcpy(re->vlaknodes, temp, re->vlaknodeslen*sizeof(VlakTableNode));
+ memset(re->vlaknodes+re->vlaknodeslen, 0, TABLEINITSIZE*sizeof(VlakTableNode));
+
+ re->vlaknodeslen+=TABLEINITSIZE; /*Does this really need to be power of 2?*/
+ if(temp) MEM_freeN(temp);
+ }
+
+ v= re->vlaknodes[a].vlak;
+
+ if(v==NULL) {
+ int i;
+
+ v= (VlakRen *)MEM_callocN(256*sizeof(VlakRen),"findOrAddVlak");
+ re->vlaknodes[a].vlak= v;
+
+ for(i= (nr & 0xFFFFFF00), a=0; a<256; a++, i++)
+ v[a].index= i;
+ }
+ v+= (nr & 255);
+ return v;
+}
+
+/* ------------------------------------------------------------------------ */
+
+void RE_addRenderObject(Render *re, Object *ob, Object *par, int index, int sve, int eve, int sfa, int efa)
+{
+ ObjectRen *obr= MEM_mallocN(sizeof(ObjectRen), "object render struct");
+
+ BLI_addtail(&re->objecttable, obr);
+ obr->ob= ob;
+ obr->par= par;
+ obr->index= index;
+ obr->startvert= sve;
+ obr->endvert= eve;
+ obr->startface= sfa;
+ obr->endface= efa;
+}
+
+void free_renderdata_vertnodes(VertTableNode *vertnodes)
+{
+ int a;
+
+ if(vertnodes==NULL) return;
+
+ for(a=0; vertnodes[a].vert; a++) {
+ MEM_freeN(vertnodes[a].vert);
+
+ if(vertnodes[a].rad)
+ MEM_freeN(vertnodes[a].rad);
+ if(vertnodes[a].sticky)
+ MEM_freeN(vertnodes[a].sticky);
+ if(vertnodes[a].strand)
+ MEM_freeN(vertnodes[a].strand);
+ if(vertnodes[a].tangent)
+ MEM_freeN(vertnodes[a].tangent);
+ if(vertnodes[a].stress)
+ MEM_freeN(vertnodes[a].stress);
+ if(vertnodes[a].winspeed)
+ MEM_freeN(vertnodes[a].winspeed);
+ }
+
+ MEM_freeN(vertnodes);
+}
+
+void free_renderdata_vlaknodes(VlakTableNode *vlaknodes)
+{
+ int a;
+
+ if(vlaknodes==NULL) return;
+
+ for(a=0; vlaknodes[a].vlak; a++) {
+ MEM_freeN(vlaknodes[a].vlak);
+
+ if(vlaknodes[a].mtface)
+ MEM_freeN(vlaknodes[a].mtface);
+ if(vlaknodes[a].mcol)
+ MEM_freeN(vlaknodes[a].mcol);
+ if(vlaknodes[a].names)
+ MEM_freeN(vlaknodes[a].names);
+ }
+
+ MEM_freeN(vlaknodes);
+}
+
+void free_renderdata_tables(Render *re)
+{
+ int a=0;
+ CustomDataNames *cdn;
+
+ if(re->bloha) {
+ for(a=0; re->bloha[a]; a++)
+ MEM_freeN(re->bloha[a]);
+
+ MEM_freeN(re->bloha);
+ re->bloha= NULL;
+ re->blohalen= 0;
+ }
+
+ if(re->vertnodes) {
+ free_renderdata_vertnodes(re->vertnodes);
+ re->vertnodes= NULL;
+ re->vertnodeslen= 0;
+ }
+
+ if(re->vlaknodes) {
+ free_renderdata_vlaknodes(re->vlaknodes);
+ re->vlaknodes= NULL;
+ re->vlaknodeslen= 0;
+ }
+
+ for(cdn=re->customdata_names.first; cdn; cdn=cdn->next) {
+ if(cdn->mtface)
+ MEM_freeN(cdn->mtface);
+ if(cdn->mcol)
+ MEM_freeN(cdn->mcol);
+ }
+
+ BLI_freelistN(&re->customdata_names);
+ BLI_freelistN(&re->objecttable);
+}
+
+
+/* ------------------------------------------------------------------------ */
+
+HaloRen *RE_findOrAddHalo(Render *re, int nr)
+{
+ HaloRen *h, **temp;
+ int a;
+
+ if(nr<0) {
+ printf("error in findOrAddHalo: %d\n",nr);
+ return NULL;
+ }
+ a= nr>>8;
+
+ if (a>=re->blohalen-1){ /* Need to allocate more columns..., and keep last element NULL for free loop */
+ //printf("Allocating %i more halo groups. %i total.\n",
+ // TABLEINITSIZE, re->blohalen+TABLEINITSIZE );
+ temp=re->bloha;
+
+ re->bloha=(HaloRen**)MEM_callocN(sizeof(void*)*(re->blohalen+TABLEINITSIZE) , "Bloha");
+ if(temp) memcpy(re->bloha, temp, re->blohalen*sizeof(void*));
+ memset(&(re->bloha[re->blohalen]), 0, TABLEINITSIZE*sizeof(void*));
+ re->blohalen+=TABLEINITSIZE; /*Does this really need to be power of 2?*/
+ if(temp) MEM_freeN(temp);
+ }
+
+ h= re->bloha[a];
+ if(h==NULL) {
+ h= (HaloRen *)MEM_callocN(256*sizeof(HaloRen),"findOrAdHalo");
+ re->bloha[a]= h;
+ }
+ h+= (nr & 255);
+ return h;
+}
+
+/* ------------------------------------------------------------------------- */
+
+HaloRen *RE_inithalo(Render *re, Material *ma, float *vec, float *vec1,
+ float *orco, float hasize, float vectsize, int seed)
+{
+ HaloRen *har;
+ MTex *mtex;
+ float tin, tr, tg, tb, ta;
+ float xn, yn, zn, texvec[3], hoco[4], hoco1[4];
+
+ if(hasize==0.0) return NULL;
+
+ projectverto(vec, re->winmat, hoco);
+ if(hoco[3]==0.0) return NULL;
+ if(vec1) {
+ projectverto(vec1, re->winmat, hoco1);
+ if(hoco1[3]==0.0) return NULL;
+ }
+
+ har= RE_findOrAddHalo(re, re->tothalo++);
+ VECCOPY(har->co, vec);
+ har->hasize= hasize;
+
+ /* actual projectvert is done in function project_renderdata() because of parts/border/pano */
+ /* we do it here for sorting of halos */
+ zn= hoco[3];
+ har->xs= 0.5*re->winx*(hoco[0]/zn);
+ har->ys= 0.5*re->winy*(hoco[1]/zn);
+ har->zs= 0x7FFFFF*(hoco[2]/zn);
+
+ har->zBufDist = 0x7FFFFFFF*(hoco[2]/zn);
+
+ /* halovect */
+ if(vec1) {
+
+ har->type |= HA_VECT;
+
+ xn= har->xs - 0.5*re->winx*(hoco1[0]/hoco1[3]);
+ yn= har->ys - 0.5*re->winy*(hoco1[1]/hoco1[3]);
+ if(xn==0.0 || (xn==0.0 && yn==0.0)) zn= 0.0;
+ else zn= atan2(yn, xn);
+
+ har->sin= sin(zn);
+ har->cos= cos(zn);
+ zn= VecLenf(vec1, vec);
+
+ har->hasize= vectsize*zn + (1.0-vectsize)*hasize;
+
+ VecSubf(har->no, vec, vec1);
+ Normalize(har->no);
+ }
+
+ if(ma->mode & MA_HALO_XALPHA) har->type |= HA_XALPHA;
+
+ har->alfa= ma->alpha;
+ har->r= ma->r;
+ har->g= ma->g;
+ har->b= ma->b;
+ har->add= (255.0*ma->add);
+ har->mat= ma;
+ har->hard= ma->har;
+ har->seed= seed % 256;
+
+ if(ma->mode & MA_STAR) har->starpoints= ma->starc;
+ if(ma->mode & MA_HALO_LINES) har->linec= ma->linec;
+ if(ma->mode & MA_HALO_RINGS) har->ringc= ma->ringc;
+ if(ma->mode & MA_HALO_FLARE) har->flarec= ma->flarec;
+
+
+ if(ma->mtex[0]) {
+
+ if( (ma->mode & MA_HALOTEX) ) har->tex= 1;
+ else {
+
+ mtex= ma->mtex[0];
+ VECCOPY(texvec, vec);
+
+ if(mtex->texco & TEXCO_NORM) {
+ ;
+ }
+ else if(mtex->texco & TEXCO_OBJECT) {
+ /* texvec[0]+= imatbase->ivec[0]; */
+ /* texvec[1]+= imatbase->ivec[1]; */
+ /* texvec[2]+= imatbase->ivec[2]; */
+ /* Mat3MulVecfl(imatbase->imat, texvec); */
+ }
+ else {
+ if(orco) {
+ VECCOPY(texvec, orco);
+ }
+ }
+
+ externtex(mtex, texvec, &tin, &tr, &tg, &tb, &ta);
+
+ yn= tin*mtex->colfac;
+ zn= tin*mtex->varfac;
+
+ if(mtex->mapto & MAP_COL) {
+ zn= 1.0-yn;
+ har->r= (yn*tr+ zn*ma->r);
+ har->g= (yn*tg+ zn*ma->g);
+ har->b= (yn*tb+ zn*ma->b);
+ }
+ if(mtex->texco & 16) {
+ har->alfa= tin;
+ }
+ }
+ }
+
+ return har;
+}
+
+/* -------------------------- operations on entire database ----------------------- */
+
+/* ugly function for halos in panorama */
+static int panotestclip(Render *re, int do_pano, float *v)
+{
+ /* to be used for halos en infos */
+ float abs4;
+ short c=0;
+
+ if(do_pano==0) return testclip(v);
+
+ abs4= fabs(v[3]);
+
+ if(v[2]< -abs4) c=16; /* this used to be " if(v[2]<0) ", see clippz() */
+ else if(v[2]> abs4) c+= 32;
+
+ if( v[1]>abs4) c+=4;
+ else if( v[1]< -abs4) c+=8;
+
+ abs4*= re->xparts;
+ if( v[0]>abs4) c+=2;
+ else if( v[0]< -abs4) c+=1;
+
+ return c;
+}
+
+/*
+ This adds the hcs coordinates to vertices. It iterates over all
+ vertices, halos and faces. After the conversion, we clip in hcs.
+
+ Elsewhere, all primites are converted to vertices.
+ Called in
+ - envmapping (envmap.c)
+ - shadow buffering (shadbuf.c)
+*/
+
+void project_renderdata(Render *re, void (*projectfunc)(float *, float mat[][4], float *), int do_pano, float xoffs)
+{
+ VlakRen *vlr = NULL;
+ VertRen *ver = NULL;
+ HaloRen *har = NULL;
+ float zn, vec[3], hoco[4];
+ int a;
+
+ if(do_pano) {
+ float panophi= xoffs;
+
+ re->panosi= sin(panophi);
+ re->panoco= cos(panophi);
+ }
+
+ /* calculate view coordinates (and zbuffer value) */
+ for(a=0; a< re->totvert;a++) {
+ if((a & 255)==0) ver= RE_findOrAddVert(re, a);
+ else ver++;
+
+ if(do_pano) {
+ vec[0]= re->panoco*ver->co[0] + re->panosi*ver->co[2];
+ vec[1]= ver->co[1];
+ vec[2]= -re->panosi*ver->co[0] + re->panoco*ver->co[2];
+ }
+ else {
+ VECCOPY(vec, ver->co);
+ }
+ /* Go from wcs to hcs ... */
+ projectfunc(vec, re->winmat, ver->ho);
+ /* ... and clip in that system. */
+ ver->clip = testclip(ver->ho);
+ /*
+ Because all other ops are performed in other systems, this is
+ the only thing that has to be done.
+ */
+ }
+
+ /* calculate view coordinates (and zbuffer value) */
+ for(a=0; a<re->tothalo; a++) {
+ if((a & 255)==0) har= re->bloha[a>>8];
+ else har++;
+
+ if(do_pano) {
+ vec[0]= re->panoco*har->co[0] + re->panosi*har->co[2];
+ vec[1]= har->co[1];
+ vec[2]= -re->panosi*har->co[0] + re->panoco*har->co[2];
+ }
+ else {
+ VECCOPY(vec, har->co);
+ }
+
+ projectfunc(vec, re->winmat, hoco);
+
+ /* we clip halos less critical, but not for the Z */
+ hoco[0]*= 0.5;
+ hoco[1]*= 0.5;
+
+ if( panotestclip(re, do_pano, hoco) ) {
+ har->miny= har->maxy= -10000; /* that way render clips it */
+ }
+ else if(hoco[3]<0.0) {
+ har->miny= har->maxy= -10000; /* render clips it */
+ }
+ else /* do the projection...*/
+ {
+ /* bring back hocos */
+ hoco[0]*= 2.0;
+ hoco[1]*= 2.0;
+
+ zn= hoco[3];
+ har->xs= 0.5*re->winx*(1.0+hoco[0]/zn); /* the 0.5 negates the previous 2...*/
+ har->ys= 0.5*re->winy*(1.0+hoco[1]/zn);
+
+ /* this should be the zbuffer coordinate */
+ har->zs= 0x7FFFFF*(hoco[2]/zn);
+ /* taking this from the face clip functions? seems ok... */
+ har->zBufDist = 0x7FFFFFFF*(hoco[2]/zn);
+
+ vec[0]+= har->hasize;
+ projectfunc(vec, re->winmat, hoco);
+ vec[0]-= har->hasize;
+ zn= hoco[3];
+ har->rad= fabs(har->xs- 0.5*re->winx*(1.0+hoco[0]/zn));
+
+ /* this clip is not really OK, to prevent stars to become too large */
+ if(har->type & HA_ONLYSKY) {
+ if(har->rad>3.0) har->rad= 3.0;
+ }
+
+ har->radsq= har->rad*har->rad;
+
+ har->miny= har->ys - har->rad/re->ycor;
+ har->maxy= har->ys + har->rad/re->ycor;
+
+ /* the Zd value is still not really correct for pano */
+
+ vec[2]-= har->hasize; /* z negative, otherwise it's clipped */
+ projectfunc(vec, re->winmat, hoco);
+ zn= hoco[3];
+ zn= fabs( (float)har->zs - 0x7FFFFF*(hoco[2]/zn));
+ har->zd= CLAMPIS(zn, 0, INT_MAX);
+
+ }
+
+ }
+
+ /* set flags at 0 if clipped away */
+ for(a=0; a<re->totvlak; a++) {
+ if((a & 255)==0) vlr= re->vlaknodes[a>>8].vlak;
+ else vlr++;
+
+ vlr->flag |= R_VISIBLE;
+ if(vlr->v4) {
+ if(vlr->v1->clip & vlr->v2->clip & vlr->v3->clip & vlr->v4->clip) vlr->flag &= ~R_VISIBLE;
+ }
+ else if(vlr->v1->clip & vlr->v2->clip & vlr->v3->clip) vlr->flag &= ~R_VISIBLE;
+
+ }
+
+}
+
+/* ------------------------------------------------------------------------- */
+
+void set_normalflags(Render *re)
+{
+ VlakRen *vlr = NULL;
+ float *v1, xn, yn, zn;
+ int a1, doflip;
+
+ /* switch normal 'snproj' values (define which axis is the optimal one for calculations) */
+ for(a1=0; a1<re->totvlak; a1++) {
+ if((a1 & 255)==0) vlr= re->vlaknodes[a1>>8].vlak;
+ else vlr++;
+
+ vlr->noflag= 0;
+
+ /* abuse of this flag... this is code that just sets face normal in direction of camera */
+ /* that convention we should get rid of */
+ if((vlr->flag & R_NOPUNOFLIP)==0) {
+
+ doflip= 0;
+ if(re->r.mode & R_ORTHO) {
+ if(vlr->n[2]>0.0) doflip= 1;
+ }
+ else {
+ v1= vlr->v1->co;
+ if( (v1[0]*vlr->n[0] +v1[1]*vlr->n[1] +v1[2]*vlr->n[2])<0.0 ) doflip= 1;
+ }
+ if(doflip) {
+ vlr->n[0]= -vlr->n[0];
+ vlr->n[1]= -vlr->n[1];
+ vlr->n[2]= -vlr->n[2];
+ vlr->noflag |= R_FLIPPED_NO;
+ }
+ }
+
+ /* recalculate puno. Displace & flipped matrices can screw up */
+ vlr->puno= 0;
+ if(!(vlr->flag & R_TANGENT)) {
+ if( Inpf(vlr->n, vlr->v1->n) < 0.0 ) vlr->puno |= ME_FLIPV1;
+ if( Inpf(vlr->n, vlr->v2->n) < 0.0 ) vlr->puno |= ME_FLIPV2;
+ if( Inpf(vlr->n, vlr->v3->n) < 0.0 ) vlr->puno |= ME_FLIPV3;
+ if(vlr->v4 && Inpf(vlr->n, vlr->v4->n) < 0.0 ) vlr->puno |= ME_FLIPV4;
+ }
+ xn= fabs(vlr->n[0]);
+ yn= fabs(vlr->n[1]);
+ zn= fabs(vlr->n[2]);
+ if(zn>=xn && zn>=yn) vlr->noflag |= R_SNPROJ_X;
+ else if(yn>=xn && yn>=zn) vlr->noflag |= R_SNPROJ_Y;
+ else vlr->noflag |= R_SNPROJ_Z;
+
+ }
+}
+
+
+
diff --git a/source/blender/render/intern/source/shadbuf.c b/source/blender/render/intern/source/shadbuf.c
new file mode 100644
index 00000000000..5e010080ac0
--- /dev/null
+++ b/source/blender/render/intern/source/shadbuf.c
@@ -0,0 +1,2050 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): 2004-2006, Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <math.h>
+#include <string.h>
+
+#include "MTC_matrixops.h"
+#include "MEM_guardedalloc.h"
+
+#include "DNA_group_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_material_types.h"
+
+#include "BKE_global.h"
+#include "BKE_utildefines.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+#include "BLI_jitter.h"
+#include "BLI_memarena.h"
+#include "BLI_rand.h"
+
+#include "renderpipeline.h"
+#include "render_types.h"
+#include "renderdatabase.h"
+#include "rendercore.h"
+
+#include "shadbuf.h"
+#include "zbuf.h"
+
+/* XXX, could be better implemented... this is for endian issues
+*/
+#if defined(__sgi) || defined(__sparc) || defined(__sparc__) || defined (__PPC__) || defined (__ppc__) || defined (__BIG_ENDIAN__)
+#define RCOMP 3
+#define GCOMP 2
+#define BCOMP 1
+#define ACOMP 0
+#else
+#define RCOMP 0
+#define GCOMP 1
+#define BCOMP 2
+#define ACOMP 3
+#endif
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
+/* only to be used here in this file, it's for speed */
+extern struct Render R;
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+/* ------------------------------------------------------------------------- */
+
+/* initshadowbuf() in convertBlenderScene.c */
+
+/* ------------------------------------------------------------------------- */
+
+static void copy_to_ztile(int *rectz, int size, int x1, int y1, int tile, char *r1)
+{
+ int len4, *rz;
+ int x2, y2;
+
+ x2= x1+tile;
+ y2= y1+tile;
+ if(x2>=size) x2= size-1;
+ if(y2>=size) y2= size-1;
+
+ if(x1>=x2 || y1>=y2) return;
+
+ len4= 4*(x2- x1);
+ rz= rectz + size*y1 + x1;
+ for(; y1<y2; y1++) {
+ memcpy(r1, rz, len4);
+ rz+= size;
+ r1+= len4;
+ }
+}
+
+#if 0
+static int sizeoflampbuf(ShadBuf *shb)
+{
+ int num,count=0;
+ char *cp;
+
+ cp= shb->cbuf;
+ num= (shb->size*shb->size)/256;
+
+ while(num--) count+= *(cp++);
+
+ return 256*count;
+}
+#endif
+
+/* not threadsafe... */
+static float *give_jitter_tab(int samp)
+{
+ /* these are all possible jitter tables, takes up some
+ * 12k, not really bad!
+ * For soft shadows, it saves memory and render time
+ */
+ static int tab[17]={1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, 256};
+ static float jit[1496][2];
+ static char ctab[17]= {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ int a, offset=0;
+
+ if(samp<2) samp= 2;
+ else if(samp>16) samp= 16;
+
+ for(a=0; a<samp-1; a++) offset+= tab[a];
+
+ if(ctab[samp]==0) {
+ ctab[samp]= 1;
+ BLI_initjit(jit[offset], samp*samp);
+ }
+
+ return jit[offset];
+
+}
+
+static void make_jitter_weight_tab(ShadBuf *shb, short filtertype)
+{
+ float *jit, totw= 0.0f;
+ int a, tot=shb->samp*shb->samp;
+
+ shb->weight= MEM_mallocN(sizeof(float)*tot, "weight tab lamp");
+
+ for(jit= shb->jit, a=0; a<tot; a++, jit+=2) {
+ if(filtertype==LA_SHADBUF_TENT)
+ shb->weight[a]= 0.71f - sqrt(jit[0]*jit[0] + jit[1]*jit[1]);
+ else if(filtertype==LA_SHADBUF_GAUSS)
+ shb->weight[a]= RE_filter_value(R_FILTER_GAUSS, 1.8f*sqrt(jit[0]*jit[0] + jit[1]*jit[1]));
+ else
+ shb->weight[a]= 1.0f;
+
+ totw+= shb->weight[a];
+ }
+
+ totw= 1.0f/totw;
+ for(a=0; a<tot; a++) {
+ shb->weight[a]*= totw;
+ }
+}
+
+/* create Z tiles (for compression): this system is 24 bits!!! */
+static void compress_shadowbuf(ShadBuf *shb, int *rectz, int square)
+{
+ ShadSampleBuf *shsample;
+ float dist;
+ unsigned long *ztile;
+ int *rz, *rz1, verg, verg1, size= shb->size;
+ int a, x, y, minx, miny, byt1, byt2;
+ char *rc, *rcline, *ctile, *zt;
+
+ shsample= MEM_mallocN( sizeof(ShadSampleBuf), "shad sample buf");
+ BLI_addtail(&shb->buffers, shsample);
+
+ shsample->zbuf= MEM_mallocN( sizeof(unsigned long)*(size*size)/256, "initshadbuf2");
+ shsample->cbuf= MEM_callocN( (size*size)/256, "initshadbuf3");
+
+ ztile= (unsigned long *)shsample->zbuf;
+ ctile= shsample->cbuf;
+
+ /* help buffer */
+ rcline= MEM_mallocN(256*4+sizeof(int), "makeshadbuf2");
+
+ for(y=0; y<size; y+=16) {
+ if(y< size/2) miny= y+15-size/2;
+ else miny= y-size/2;
+
+ for(x=0; x<size; x+=16) {
+
+ /* is tile within spotbundle? */
+ a= size/2;
+ if(x< a) minx= x+15-a;
+ else minx= x-a;
+
+ dist= sqrt( (float)(minx*minx+miny*miny) );
+
+ if(square==0 && dist>(float)(a+12)) { /* 12, tested with a onlyshadow lamp */
+ a= 256; verg= 0; /* 0x80000000; */ /* 0x7FFFFFFF; */
+ rz1= (&verg)+1;
+ }
+ else {
+ copy_to_ztile(rectz, size, x, y, 16, rcline);
+ rz1= (int *)rcline;
+
+ verg= (*rz1 & 0xFFFFFF00);
+
+ for(a=0;a<256;a++,rz1++) {
+ if( (*rz1 & 0xFFFFFF00) !=verg) break;
+ }
+ }
+ if(a==256) { /* complete empty tile */
+ *ctile= 0;
+ *ztile= *(rz1-1);
+ }
+ else {
+
+ /* ACOMP etc. are defined to work L/B endian */
+
+ rc= rcline;
+ rz1= (int *)rcline;
+ verg= rc[ACOMP];
+ verg1= rc[BCOMP];
+ rc+= 4;
+ byt1= 1; byt2= 1;
+ for(a=1;a<256;a++,rc+=4) {
+ byt1 &= (verg==rc[ACOMP]);
+ byt2 &= (verg1==rc[BCOMP]);
+
+ if(byt1==0) break;
+ }
+ if(byt1 && byt2) { /* only store byte */
+ *ctile= 1;
+ *ztile= (unsigned long)MEM_mallocN(256+4, "tile1");
+ rz= (int *)*ztile;
+ *rz= *rz1;
+
+ zt= (char *)(rz+1);
+ rc= rcline;
+ for(a=0; a<256; a++, zt++, rc+=4) *zt= rc[GCOMP];
+ }
+ else if(byt1) { /* only store short */
+ *ctile= 2;
+ *ztile= (unsigned long)MEM_mallocN(2*256+4,"Tile2");
+ rz= (int *)*ztile;
+ *rz= *rz1;
+
+ zt= (char *)(rz+1);
+ rc= rcline;
+ for(a=0; a<256; a++, zt+=2, rc+=4) {
+ zt[0]= rc[BCOMP];
+ zt[1]= rc[GCOMP];
+ }
+ }
+ else { /* store triple */
+ *ctile= 3;
+ *ztile= (unsigned long)MEM_mallocN(3*256,"Tile3");
+
+ zt= (char *)*ztile;
+ rc= rcline;
+ for(a=0; a<256; a++, zt+=3, rc+=4) {
+ zt[0]= rc[ACOMP];
+ zt[1]= rc[BCOMP];
+ zt[2]= rc[GCOMP];
+ }
+ }
+ }
+ ztile++;
+ ctile++;
+ }
+ }
+
+ MEM_freeN(rcline);
+
+}
+
+/* sets start/end clipping. lar->shb should be initialized */
+static void shadowbuf_autoclip(Render *re, LampRen *lar)
+{
+ VlakRen *vlr= NULL;
+ VertRen *ver= NULL;
+ Material *ma= NULL;
+ float minz, maxz, vec[3], viewmat[4][4];
+ unsigned int lay = -1;
+ int a, ok= 1;
+
+ minz= 1.0e30f; maxz= -1.0e30f;
+ Mat4CpyMat4(viewmat, lar->shb->viewmat);
+
+ if(lar->mode & LA_LAYER) lay= lar->lay;
+
+ /* clear clip, is being set if face is visible (clip is calculated for real later) */
+ for(a=0; a<re->totvert; a++) {
+ if((a & 255)==0) ver= RE_findOrAddVert(re, a);
+ else ver++;
+
+ ver->clip= 0;
+ }
+
+ /* set clip in vertices when face visible */
+ for(a=0; a<re->totvlak; a++) {
+
+ if((a & 255)==0) vlr= re->vlaknodes[a>>8].vlak;
+ else vlr++;
+
+ /* note; these conditions are copied from zbuffer_shadow() */
+ if(vlr->mat!= ma) {
+ ma= vlr->mat;
+ ok= 1;
+ if((ma->mode & MA_SHADBUF)==0) ok= 0;
+ }
+
+ if(ok && (vlr->lay & lay)) {
+ vlr->v1->clip= 1;
+ vlr->v2->clip= 1;
+ vlr->v3->clip= 1;
+ if(vlr->v4) vlr->v4->clip= 1;
+ }
+ }
+
+ /* calculate min and max */
+ for(a=0; a< re->totvert;a++) {
+ if((a & 255)==0) ver= RE_findOrAddVert(re, a);
+ else ver++;
+
+ if(ver->clip) {
+ VECCOPY(vec, ver->co);
+ Mat4MulVecfl(viewmat, vec);
+ /* Z on visible side of lamp space */
+ if(vec[2] < 0.0f) {
+ float inpr, z= -vec[2];
+
+ /* since vec is rotated in lampspace, this is how to get the cosine of angle */
+ /* precision is set 20% larger */
+ vec[2]*= 1.2f;
+ Normalize(vec);
+ inpr= - vec[2];
+
+ if(inpr>=lar->spotsi) {
+ if(z<minz) minz= z;
+ if(z>maxz) maxz= z;
+ }
+ }
+ }
+ }
+
+ /* set clipping min and max */
+ if(minz < maxz) {
+ float delta= (maxz - minz); /* threshold to prevent precision issues */
+
+ //printf("minz %f maxz %f delta %f\n", minz, maxz, delta);
+ if(lar->bufflag & LA_SHADBUF_AUTO_START)
+ lar->shb->d= minz - delta*0.02f; /* 0.02 is arbitrary... needs more thinking! */
+ if(lar->bufflag & LA_SHADBUF_AUTO_END)
+ lar->shb->clipend= maxz + delta*0.1f;
+
+ /* bias was calculated as percentage, we scale it to prevent animation issues */
+ delta= (lar->clipend-lar->clipsta)/(lar->shb->clipend-lar->shb->d);
+ //printf("bias delta %f\n", delta);
+ lar->shb->bias= (int) (delta*(float)lar->shb->bias);
+ }
+}
+
+void makeshadowbuf(Render *re, LampRen *lar)
+{
+ ShadBuf *shb= lar->shb;
+ float wsize, *jitbuf, twozero[2]= {0.0f, 0.0f}, angle, temp;
+ int *rectz, samples;
+
+ /* XXXX EVIL! this global is used in clippyra(), zbuf.c */
+ R.clipcrop= 1.0f;
+
+ if(lar->bufflag & (LA_SHADBUF_AUTO_START|LA_SHADBUF_AUTO_END))
+ shadowbuf_autoclip(re, lar);
+
+ /* just to enforce identical behaviour of all irregular buffers */
+ if(lar->buftype==LA_SHADBUF_IRREGULAR)
+ shb->size= 1024;
+
+ /* matrices and window: in winmat the transformation is being put,
+ transforming from observer view to lamp view, including lamp window matrix */
+
+ angle= saacos(lar->spotsi);
+ temp= 0.5f*shb->size*cos(angle)/sin(angle);
+ shb->pixsize= (shb->d)/temp;
+ wsize= shb->pixsize*(shb->size/2.0);
+
+ i_window(-wsize, wsize, -wsize, wsize, shb->d, shb->clipend, shb->winmat);
+ MTC_Mat4MulMat4(shb->persmat, shb->viewmat, shb->winmat);
+
+ if(ELEM(lar->buftype, LA_SHADBUF_REGULAR, LA_SHADBUF_HALFWAY)) {
+ /* jitter, weights */
+ shb->jit= give_jitter_tab(shb->samp);
+ make_jitter_weight_tab(shb, lar->filtertype);
+
+ shb->totbuf= lar->buffers;
+ if(shb->totbuf==4) jitbuf= give_jitter_tab(2);
+ else if(shb->totbuf==9) jitbuf= give_jitter_tab(3);
+ else jitbuf= twozero;
+
+ /* temp, will be restored */
+ MTC_Mat4SwapMat4(shb->persmat, re->winmat);
+
+ project_renderdata(re, projectvert, 0, 0);
+
+ /* zbuffering */
+ rectz= MEM_mapallocN(sizeof(int)*shb->size*shb->size, "makeshadbuf");
+
+ for(samples=0; samples<shb->totbuf; samples++) {
+ zbuffer_shadow(re, lar, rectz, shb->size, jitbuf[2*samples], jitbuf[2*samples+1]);
+ /* create Z tiles (for compression): this system is 24 bits!!! */
+ compress_shadowbuf(shb, rectz, lar->mode & LA_SQUARE);
+ }
+
+ MEM_freeN(rectz);
+
+ /* old matrix back */
+ MTC_Mat4SwapMat4(shb->persmat, re->winmat);
+
+ /* printf("lampbuf %d\n", sizeoflampbuf(shb)); */
+ }
+}
+
+void freeshadowbuf(LampRen *lar)
+{
+ if(lar->shb) {
+ ShadBuf *shb= lar->shb;
+ ShadSampleBuf *shsample;
+ int b, v;
+
+ v= (shb->size*shb->size)/256;
+
+ for(shsample= shb->buffers.first; shsample; shsample= shsample->next) {
+ long *ztile= shsample->zbuf;
+ char *ctile= shsample->cbuf;
+
+ for(b=0; b<v; b++, ztile++, ctile++)
+ if(*ctile) MEM_freeN((void *) *ztile);
+
+ MEM_freeN(shsample->zbuf);
+ MEM_freeN(shsample->cbuf);
+ }
+ BLI_freelistN(&shb->buffers);
+
+ if(shb->weight) MEM_freeN(shb->weight);
+ MEM_freeN(lar->shb);
+
+ lar->shb= NULL;
+ }
+}
+
+
+static int firstreadshadbuf(ShadBuf *shb, ShadSampleBuf *shsample, int **rz, int xs, int ys, int nr)
+{
+ /* return a 1 if fully compressed shadbuf-tile && z==const */
+ int ofs;
+ char *ct;
+
+ /* always test borders of shadowbuffer */
+ if(xs<0) xs= 0; else if(xs>=shb->size) xs= shb->size-1;
+ if(ys<0) ys= 0; else if(ys>=shb->size) ys= shb->size-1;
+
+ /* calc z */
+ ofs= (ys>>4)*(shb->size>>4) + (xs>>4);
+ ct= shsample->cbuf+ofs;
+ if(*ct==0) {
+ if(nr==0) {
+ *rz= *( (int **)(shsample->zbuf+ofs) );
+ return 1;
+ }
+ else if(*rz!= *( (int **)(shsample->zbuf+ofs) )) return 0;
+
+ return 1;
+ }
+
+ return 0;
+}
+
+/* return 1.0 : fully in light */
+static float readshadowbuf(ShadBuf *shb, ShadSampleBuf *shsample, int bias, int xs, int ys, int zs)
+{
+ float temp;
+ int *rz, ofs;
+ int zsamp=0;
+ char *ct, *cz;
+
+ /* simpleclip */
+ /* if(xs<0 || ys<0) return 1.0; */
+ /* if(xs>=shb->size || ys>=shb->size) return 1.0; */
+
+ /* always test borders of shadowbuffer */
+ if(xs<0) xs= 0; else if(xs>=shb->size) xs= shb->size-1;
+ if(ys<0) ys= 0; else if(ys>=shb->size) ys= shb->size-1;
+
+ /* calc z */
+ ofs= (ys>>4)*(shb->size>>4) + (xs>>4);
+ ct= shsample->cbuf+ofs;
+ rz= *( (int **)(shsample->zbuf+ofs) );
+
+ if(*ct==3) {
+ ct= ((char *)rz)+3*16*(ys & 15)+3*(xs & 15);
+ cz= (char *)&zsamp;
+ cz[ACOMP]= ct[0];
+ cz[BCOMP]= ct[1];
+ cz[GCOMP]= ct[2];
+ }
+ else if(*ct==2) {
+ ct= ((char *)rz);
+ ct+= 4+2*16*(ys & 15)+2*(xs & 15);
+ zsamp= *rz;
+
+ cz= (char *)&zsamp;
+ cz[BCOMP]= ct[0];
+ cz[GCOMP]= ct[1];
+ }
+ else if(*ct==1) {
+ ct= ((char *)rz);
+ ct+= 4+16*(ys & 15)+(xs & 15);
+ zsamp= *rz;
+
+ cz= (char *)&zsamp;
+ cz[GCOMP]= ct[0];
+
+ }
+ else {
+ /* got warning on this for 64 bits.... */
+ /* but it's working code! in this case rz is not a pointer but zvalue (ton) */
+ zsamp= (int) rz;
+ }
+
+ /* tricky stuff here; we use ints which can overflow easily with bias values */
+
+ if(zsamp > zs) return 1.0; /* absolute no shadow */
+ else if(zs < - 0x7FFFFE00 + bias) return 1.0; /* extreme close to clipstart */
+ else if(zsamp < zs-bias) return 0.0 ; /* absolute in shadow */
+ else { /* soft area */
+
+ temp= ( (float)(zs- zsamp) )/(float)bias;
+ return 1.0 - temp*temp;
+
+ }
+}
+
+/* the externally called shadow testing (reading) function */
+/* return 1.0: no shadow at all */
+float testshadowbuf(ShadBuf *shb, float *rco, float *dxco, float *dyco, float inp)
+{
+ ShadSampleBuf *shsample;
+ float fac, co[4], dx[3], dy[3], shadfac=0.0f;
+ float xs1,ys1, siz, *jit, *weight, xres, yres;
+ int xs, ys, zs, bias, *rz;
+ short a, num;
+
+ /* crash preventer */
+ if(shb->buffers.first==NULL)
+ return 1.0f;
+
+ if(inp <= 0.0f) return 0.0f;
+
+ /* rotate renderco en osaco */
+ siz= 0.5f*(float)shb->size;
+ VECCOPY(co, rco);
+ co[3]= 1.0f;
+
+ MTC_Mat4MulVec4fl(shb->persmat, co); /* rational hom co */
+
+ xs1= siz*(1.0f+co[0]/co[3]);
+ ys1= siz*(1.0f+co[1]/co[3]);
+
+ /* Clip for z: clipsta and clipend clip values of the shadow buffer. We
+ * can test for -1.0/1.0 because of the properties of the
+ * coordinate transformations. */
+ fac= (co[2]/co[3]);
+
+ if(fac>=1.0f) {
+ return 0.0f;
+ } else if(fac<= -1.0f) {
+ return 1.0f;
+ }
+
+ zs= ((float)0x7FFFFFFF)*fac;
+
+ /* take num*num samples, increase area with fac */
+ num= shb->samp*shb->samp;
+ fac= shb->soft;
+
+ /* with inp==1.0, bias is half the size. correction value was 1.1, giving errors
+ on cube edges, with one side being almost frontal lighted (ton) */
+ bias= (1.5f-inp*inp)*shb->bias;
+
+ if(num==1) {
+ for(shsample= shb->buffers.first; shsample; shsample= shsample->next)
+ shadfac += readshadowbuf(shb, shsample, bias, (int)xs1, (int)ys1, zs);
+
+ return shadfac/(float)shb->totbuf;
+ }
+
+ /* calculate filter size */
+ co[0]= rco[0]+dxco[0];
+ co[1]= rco[1]+dxco[1];
+ co[2]= rco[2]+dxco[2];
+ co[3]= 1.0;
+ MTC_Mat4MulVec4fl(shb->persmat,co); /* rational hom co */
+ dx[0]= xs1- siz*(1.0+co[0]/co[3]);
+ dx[1]= ys1- siz*(1.0+co[1]/co[3]);
+
+ co[0]= rco[0]+dyco[0];
+ co[1]= rco[1]+dyco[1];
+ co[2]= rco[2]+dyco[2];
+ co[3]= 1.0;
+ MTC_Mat4MulVec4fl(shb->persmat,co); /* rational hom co */
+ dy[0]= xs1- siz*(1.0+co[0]/co[3]);
+ dy[1]= ys1- siz*(1.0+co[1]/co[3]);
+
+ xres= fac*( fabs(dx[0])+fabs(dy[0]) );
+ yres= fac*( fabs(dx[1])+fabs(dy[1]) );
+ if(xres<fac) xres= fac;
+ if(yres<fac) yres= fac;
+
+ xs1-= (xres)/2;
+ ys1-= (yres)/2;
+
+ if(xres<16.0f && yres<16.0f) {
+ shsample= shb->buffers.first;
+ if(firstreadshadbuf(shb, shsample, &rz, (int)xs1, (int)ys1, 0)) {
+ if(firstreadshadbuf(shb, shsample, &rz, (int)(xs1+xres), (int)ys1, 1)) {
+ if(firstreadshadbuf(shb, shsample, &rz, (int)xs1, (int)(ys1+yres), 1)) {
+ if(firstreadshadbuf(shb, shsample, &rz, (int)(xs1+xres), (int)(ys1+yres), 1)) {
+ return readshadowbuf(shb, shsample, bias,(int)xs1, (int)ys1, zs);
+ }
+ }
+ }
+ }
+ }
+
+ for(shsample= shb->buffers.first; shsample; shsample= shsample->next) {
+ jit= shb->jit;
+ weight= shb->weight;
+
+ for(a=num; a>0; a--, jit+=2, weight++) {
+ /* instead of jit i tried random: ugly! */
+ /* note: the plus 0.5 gives best sampling results, jit goes from -0.5 to 0.5 */
+ /* xs1 and ys1 are already corrected to be corner of sample area */
+ xs= xs1 + xres*(jit[0] + 0.5f);
+ ys= ys1 + yres*(jit[1] + 0.5f);
+
+ shadfac+= *weight * readshadowbuf(shb, shsample, bias, xs, ys, zs);
+ }
+ }
+
+ /* Renormalizes for the sample number: */
+ return shadfac/(float)shb->totbuf;
+}
+
+/* different function... sampling behind clipend can be LIGHT, bias is negative! */
+/* return: light */
+static float readshadowbuf_halo(ShadBuf *shb, ShadSampleBuf *shsample, int xs, int ys, int zs)
+{
+ float temp;
+ int *rz, ofs;
+ int bias, zbias, zsamp;
+ char *ct, *cz;
+
+ /* negative! The other side is more important */
+ bias= -shb->bias;
+
+ /* simpleclip */
+ if(xs<0 || ys<0) return 0.0;
+ if(xs>=shb->size || ys>=shb->size) return 0.0;
+
+ /* calc z */
+ ofs= (ys>>4)*(shb->size>>4) + (xs>>4);
+ ct= shsample->cbuf+ofs;
+ rz= *( (int **)(shsample->zbuf+ofs) );
+
+ if(*ct==3) {
+ ct= ((char *)rz)+3*16*(ys & 15)+3*(xs & 15);
+ cz= (char *)&zsamp;
+ zsamp= 0;
+ cz[ACOMP]= ct[0];
+ cz[BCOMP]= ct[1];
+ cz[GCOMP]= ct[2];
+ }
+ else if(*ct==2) {
+ ct= ((char *)rz);
+ ct+= 4+2*16*(ys & 15)+2*(xs & 15);
+ zsamp= *rz;
+
+ cz= (char *)&zsamp;
+ cz[BCOMP]= ct[0];
+ cz[GCOMP]= ct[1];
+ }
+ else if(*ct==1) {
+ ct= ((char *)rz);
+ ct+= 4+16*(ys & 15)+(xs & 15);
+ zsamp= *rz;
+
+ cz= (char *)&zsamp;
+ cz[GCOMP]= ct[0];
+
+ }
+ else {
+ /* same as before */
+ /* still working code! (ton) */
+ zsamp= (int) rz;
+ }
+
+ /* NO schadow when sampled at 'eternal' distance */
+
+ if(zsamp >= 0x7FFFFE00) return 1.0;
+
+ if(zsamp > zs) return 1.0; /* absolute no shadww */
+ else {
+ /* bias is negative, so the (zs-bias) can be beyond 0x7fffffff */
+ zbias= 0x7fffffff - zs;
+ if(zbias > -bias) {
+ if( zsamp < zs-bias) return 0.0 ; /* absolute in shadow */
+ }
+ else return 0.0 ; /* absolute shadow */
+ }
+
+ /* soft area */
+
+ temp= ( (float)(zs- zsamp) )/(float)bias;
+ return 1.0 - temp*temp;
+}
+
+
+float shadow_halo(LampRen *lar, float *p1, float *p2)
+{
+ /* p1 p2 already are rotated in spot-space */
+ ShadBuf *shb= lar->shb;
+ ShadSampleBuf *shsample;
+ float co[4], siz;
+ float labda, labdao, labdax, labday, ldx, ldy;
+ float zf, xf1, yf1, zf1, xf2, yf2, zf2;
+ float count, lightcount;
+ int x, y, z, xs1, ys1;
+ int dx = 0, dy = 0;
+
+ siz= 0.5*(float)shb->size;
+
+ co[0]= p1[0];
+ co[1]= p1[1];
+ co[2]= p1[2]/lar->sh_zfac;
+ co[3]= 1.0;
+ MTC_Mat4MulVec4fl(shb->winmat, co); /* rational hom co */
+ xf1= siz*(1.0+co[0]/co[3]);
+ yf1= siz*(1.0+co[1]/co[3]);
+ zf1= (co[2]/co[3]);
+
+
+ co[0]= p2[0];
+ co[1]= p2[1];
+ co[2]= p2[2]/lar->sh_zfac;
+ co[3]= 1.0;
+ MTC_Mat4MulVec4fl(shb->winmat, co); /* rational hom co */
+ xf2= siz*(1.0+co[0]/co[3]);
+ yf2= siz*(1.0+co[1]/co[3]);
+ zf2= (co[2]/co[3]);
+
+ /* the 2dda (a pixel line formula) */
+
+ xs1= (int)xf1;
+ ys1= (int)yf1;
+
+ if(xf1 != xf2) {
+ if(xf2-xf1 > 0.0) {
+ labdax= (xf1-xs1-1.0)/(xf1-xf2);
+ ldx= -shb->shadhalostep/(xf1-xf2);
+ dx= shb->shadhalostep;
+ }
+ else {
+ labdax= (xf1-xs1)/(xf1-xf2);
+ ldx= shb->shadhalostep/(xf1-xf2);
+ dx= -shb->shadhalostep;
+ }
+ }
+ else {
+ labdax= 1.0;
+ ldx= 0.0;
+ }
+
+ if(yf1 != yf2) {
+ if(yf2-yf1 > 0.0) {
+ labday= (yf1-ys1-1.0)/(yf1-yf2);
+ ldy= -shb->shadhalostep/(yf1-yf2);
+ dy= shb->shadhalostep;
+ }
+ else {
+ labday= (yf1-ys1)/(yf1-yf2);
+ ldy= shb->shadhalostep/(yf1-yf2);
+ dy= -shb->shadhalostep;
+ }
+ }
+ else {
+ labday= 1.0;
+ ldy= 0.0;
+ }
+
+ x= xs1;
+ y= ys1;
+ labda= count= lightcount= 0.0;
+
+/* printf("start %x %x \n", (int)(0x7FFFFFFF*zf1), (int)(0x7FFFFFFF*zf2)); */
+
+ while(1) {
+ labdao= labda;
+
+ if(labdax==labday) {
+ labdax+= ldx;
+ x+= dx;
+ labday+= ldy;
+ y+= dy;
+ }
+ else {
+ if(labdax<labday) {
+ labdax+= ldx;
+ x+= dx;
+ } else {
+ labday+= ldy;
+ y+= dy;
+ }
+ }
+
+ labda= MIN2(labdax, labday);
+ if(labda==labdao || labda>=1.0) break;
+
+ zf= zf1 + labda*(zf2-zf1);
+ count+= (float)shb->totbuf;
+
+ if(zf<= -1.0) lightcount += 1.0; /* close to the spot */
+ else {
+
+ /* make sure, behind the clipend we extend halolines. */
+ if(zf>=1.0) z= 0x7FFFF000;
+ else z= (int)(0x7FFFF000*zf);
+
+ for(shsample= shb->buffers.first; shsample; shsample= shsample->next)
+ lightcount+= readshadowbuf_halo(shb, shsample, x, y, z);
+
+ }
+ }
+
+ if(count!=0.0) return (lightcount/count);
+ return 0.0;
+
+}
+
+
+/* ********************* Irregular Shadow Buffer (ISB) ************* */
+/* ********** storage of all view samples in a raster of lists ***** */
+
+/* based on several articles describing this method, like:
+The Irregular Z-Buffer and its Application to Shadow Mapping
+Gregory S. Johnson - William R. Mark - Christopher A. Burns
+and
+Alias-Free Shadow Maps
+Timo Aila and Samuli Laine
+*/
+
+/* bsp structure (actually kd tree) */
+
+#define BSPMAX_SAMPLE 128
+#define BSPMAX_DEPTH 32
+
+/* aligned with struct rctf */
+typedef struct Boxf {
+ float xmin, xmax;
+ float ymin, ymax;
+ float zmin, zmax;
+} Boxf;
+
+typedef struct ISBBranch {
+ struct ISBBranch *left, *right;
+ float divider[2];
+ Boxf box;
+ short totsamp, index, full, unused;
+ ISBSample **samples;
+} ISBBranch;
+
+typedef struct BSPFace {
+ Boxf box;
+ float *v1, *v2, *v3, *v4;
+ int facenr; /* index to retrieve VlakRen */
+ int type; /* only for strand now */
+ short shad_alpha, is_full;
+
+ /* strand caching data, optimize for point_behind_strand() */
+ float radline, radline_end, len;
+ float vec1[3], vec2[3], rc[3];
+} BSPFace;
+
+/* boxes are in lamp projection */
+static void init_box(Boxf *box)
+{
+ box->xmin= 1000000.0f;
+ box->xmax= 0;
+ box->ymin= 1000000.0f;
+ box->ymax= 0;
+ box->zmin= 0x7FFFFFFF;
+ box->zmax= - 0x7FFFFFFF;
+}
+
+/* use v1 to calculate boundbox */
+static void bound_boxf(Boxf *box, float *v1)
+{
+ if(v1[0] < box->xmin) box->xmin= v1[0];
+ if(v1[0] > box->xmax) box->xmax= v1[0];
+ if(v1[1] < box->ymin) box->ymin= v1[1];
+ if(v1[1] > box->ymax) box->ymax= v1[1];
+ if(v1[2] < box->zmin) box->zmin= v1[2];
+ if(v1[2] > box->zmax) box->zmax= v1[2];
+}
+
+/* use v1 to calculate boundbox */
+static void bound_rectf(rctf *box, float *v1)
+{
+ if(v1[0] < box->xmin) box->xmin= v1[0];
+ if(v1[0] > box->xmax) box->xmax= v1[0];
+ if(v1[1] < box->ymin) box->ymin= v1[1];
+ if(v1[1] > box->ymax) box->ymax= v1[1];
+}
+
+
+/* halfway splitting, for initializing a more regular tree */
+static void isb_bsp_split_init(ISBBranch *root, MemArena *mem, int level)
+{
+
+ /* if level > 0 we create new branches and go deeper*/
+ if(level > 0) {
+ ISBBranch *left, *right;
+ int i;
+
+ /* splitpoint */
+ root->divider[0]= 0.5f*(root->box.xmin+root->box.xmax);
+ root->divider[1]= 0.5f*(root->box.ymin+root->box.ymax);
+
+ /* find best splitpoint */
+ if(root->box.xmax-root->box.xmin > root->box.ymax-root->box.ymin)
+ i= root->index= 0;
+ else
+ i= root->index= 1;
+
+ left= root->left= BLI_memarena_alloc(mem, sizeof(ISBBranch));
+ right= root->right= BLI_memarena_alloc(mem, sizeof(ISBBranch));
+
+ /* box info */
+ left->box= root->box;
+ right->box= root->box;
+ if(i==0) {
+ left->box.xmax= root->divider[0];
+ right->box.xmin= root->divider[0];
+ }
+ else {
+ left->box.ymax= root->divider[1];
+ right->box.ymin= root->divider[1];
+ }
+ isb_bsp_split_init(left, mem, level-1);
+ isb_bsp_split_init(right, mem, level-1);
+ }
+ else {
+ /* we add sample array */
+ root->samples= BLI_memarena_alloc(mem, BSPMAX_SAMPLE*sizeof(void *));
+ }
+}
+
+/* note; if all samples on same location we just spread them over 2 new branches */
+static void isb_bsp_split(ISBBranch *root, MemArena *mem)
+{
+ ISBBranch *left, *right;
+ ISBSample *samples[BSPMAX_SAMPLE];
+ int a, i;
+
+ /* splitpoint */
+ root->divider[0]= root->divider[1]= 0.0f;
+ for(a=BSPMAX_SAMPLE-1; a>=0; a--) {
+ root->divider[0]+= root->samples[a]->zco[0];
+ root->divider[1]+= root->samples[a]->zco[1];
+ }
+ root->divider[0]/= BSPMAX_SAMPLE;
+ root->divider[1]/= BSPMAX_SAMPLE;
+
+ /* find best splitpoint */
+ if(root->box.xmax-root->box.xmin > root->box.ymax-root->box.ymin)
+ i= root->index= 0;
+ else
+ i= root->index= 1;
+
+ /* new branches */
+ left= root->left= BLI_memarena_alloc(mem, sizeof(ISBBranch));
+ right= root->right= BLI_memarena_alloc(mem, sizeof(ISBBranch));
+
+ /* new sample array */
+ left->samples= BLI_memarena_alloc(mem, BSPMAX_SAMPLE*sizeof(void *));
+ right->samples= samples; // tmp
+
+ /* split samples */
+ for(a=BSPMAX_SAMPLE-1; a>=0; a--) {
+ int comp= 0;
+ /* this prevents adding samples all to 1 branch when divider is equal to samples */
+ if(root->samples[a]->zco[i] == root->divider[i])
+ comp= a & 1;
+ else if(root->samples[a]->zco[i] < root->divider[i])
+ comp= 1;
+
+ if(comp==1) {
+ left->samples[left->totsamp]= root->samples[a];
+ left->totsamp++;
+ }
+ else {
+ right->samples[right->totsamp]= root->samples[a];
+ right->totsamp++;
+ }
+ }
+
+ /* copy samples from tmp */
+ memcpy(root->samples, samples, right->totsamp*(sizeof(void *)));
+ right->samples= root->samples;
+ root->samples= NULL;
+
+ /* box info */
+ left->box= root->box;
+ right->box= root->box;
+ if(i==0) {
+ left->box.xmax= root->divider[0];
+ right->box.xmin= root->divider[0];
+ }
+ else {
+ left->box.ymax= root->divider[1];
+ right->box.ymin= root->divider[1];
+ }
+}
+
+/* inserts sample in main tree, also splits on threshold */
+/* returns 1 if error */
+static int isb_bsp_insert(ISBBranch *root, MemArena *memarena, ISBSample *sample)
+{
+ ISBBranch *bspn= root;
+ float *zco= sample->zco;
+ int i= 0;
+
+ /* debug counter, also used to check if something was filled in ever */
+ root->totsamp++;
+
+ /* going over branches until last one found */
+ while(bspn->left) {
+ if(zco[bspn->index] <= bspn->divider[bspn->index])
+ bspn= bspn->left;
+ else
+ bspn= bspn->right;
+ i++;
+ }
+ /* bspn now is the last branch */
+
+ if(bspn->totsamp==BSPMAX_SAMPLE) {
+ printf("error in bsp branch\n"); /* only for debug, cannot happen */
+ return 1;
+ }
+
+ /* insert */
+ bspn->samples[bspn->totsamp]= sample;
+ bspn->totsamp++;
+
+ /* split if allowed and needed */
+ if(bspn->totsamp==BSPMAX_SAMPLE) {
+ if(i==BSPMAX_DEPTH) {
+ bspn->totsamp--; /* stop filling in... will give errors */
+ return 1;
+ }
+ isb_bsp_split(bspn, memarena);
+ }
+ return 0;
+}
+
+static float VecLen2f( float *v1, float *v2)
+{
+ float x= v1[0]-v2[0];
+ float y= v1[1]-v2[1];
+ return (float)sqrt(x*x+y*y);
+}
+
+/* initialize vars in face, for optimal point-in-face test */
+static void bspface_init_strand(BSPFace *face)
+{
+
+ face->radline= 0.5f*VecLen2f(face->v1, face->v2);
+
+ VecMidf(face->vec1, face->v1, face->v2);
+ if(face->v4)
+ VecMidf(face->vec2, face->v3, face->v4);
+ else
+ VECCOPY(face->vec2, face->v3);
+
+ face->rc[0]= face->vec2[0]-face->vec1[0];
+ face->rc[1]= face->vec2[1]-face->vec1[1];
+ face->rc[2]= face->vec2[2]-face->vec1[2];
+
+ face->len= face->rc[0]*face->rc[0]+ face->rc[1]*face->rc[1];
+
+ if(face->len!=0.0f) {
+ face->radline_end= face->radline/sqrt(face->len);
+ face->len= 1.0f/face->len;
+ }
+}
+
+/* brought back to a simple 2d case */
+static int point_behind_strand(float *p, BSPFace *face)
+{
+ /* v1 - v2 is radius, v1 - v3 length */
+ float dist, rc[2], pt[2];
+
+ /* using code from PdistVL2Dfl(), distance vec to line-piece */
+
+ if(face->len==0.0f) {
+ rc[0]= p[0]-face->vec1[0];
+ rc[1]= p[1]-face->vec1[1];
+ dist= (float)(sqrt(rc[0]*rc[0]+ rc[1]*rc[1]));
+
+ if(dist < face->radline)
+ return 1;
+ }
+ else {
+ float labda= ( face->rc[0]*(p[0]-face->vec1[0]) + face->rc[1]*(p[1]-face->vec1[1]) )*face->len;
+
+ if(labda > -face->radline_end && labda < 1.0f+face->radline_end) {
+ /* hesse for dist: */
+ //dist= (float)(fabs( (p[0]-vec2[0])*rc[1] + (p[1]-vec2[1])*rc[0])/len);
+
+ pt[0]= labda*face->rc[0]+face->vec1[0];
+ pt[1]= labda*face->rc[1]+face->vec1[1];
+
+ rc[0]= pt[0]-p[0];
+ rc[1]= pt[1]-p[1];
+ dist= (float)sqrt(rc[0]*rc[0]+ rc[1]*rc[1]);
+
+ if(dist < face->radline) {
+ float zval= face->vec1[2] + labda*face->rc[2];
+ if(p[2] > zval)
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+
+/* return 1 if inside. code derived from src/parametrizer.c */
+static int point_behind_tria2d(float *p, float *v1, float *v2, float *v3)
+{
+ float a[2], c[2], h[2], div;
+ float u, v;
+
+ a[0] = v2[0] - v1[0];
+ a[1] = v2[1] - v1[1];
+ c[0] = v3[0] - v1[0];
+ c[1] = v3[1] - v1[1];
+
+ div = a[0]*c[1] - a[1]*c[0];
+ if(div==0.0f)
+ return 0;
+
+ h[0] = p[0] - v1[0];
+ h[1] = p[1] - v1[1];
+
+ div = 1.0f/div;
+
+ u = (h[0]*c[1] - h[1]*c[0])*div;
+ if(u >= 0.0f) {
+ v = (a[0]*h[1] - a[1]*h[0])*div;
+ if(v >= 0.0f) {
+ if( u + v <= 1.0f) {
+ /* inside, now check if point p is behind */
+ float z= (1.0f-u-v)*v1[2] + u*v2[2] + v*v3[2];
+ if(z <= p[2])
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+#if 0
+/* tested these calls, but it gives inaccuracy, 'side' cannot be found reliably using v3 */
+
+/* check if line v1-v2 has all rect points on other side of point v3 */
+static int rect_outside_line(rctf *rect, float *v1, float *v2, float *v3)
+{
+ float a, b, c;
+ int side;
+
+ /* line formula for v1-v2 */
+ a= v2[1]-v1[1];
+ b= v1[0]-v2[0];
+ c= -a*v1[0] - b*v1[1];
+ side= a*v3[0] + b*v3[1] + c < 0.0f;
+
+ /* the four quad points */
+ if( side==(rect->xmin*a + rect->ymin*b + c >= 0.0f) )
+ if( side==(rect->xmax*a + rect->ymin*b + c >= 0.0f) )
+ if( side==(rect->xmax*a + rect->ymax*b + c >= 0.0f) )
+ if( side==(rect->xmin*a + rect->ymax*b + c >= 0.0f) )
+ return 1;
+ return 0;
+}
+
+/* check if one of the triangle edges separates all rect points on 1 side */
+static int rect_isect_tria(rctf *rect, float *v1, float *v2, float *v3)
+{
+ if(rect_outside_line(rect, v1, v2, v3))
+ return 0;
+ if(rect_outside_line(rect, v2, v3, v1))
+ return 0;
+ if(rect_outside_line(rect, v3, v1, v2))
+ return 0;
+ return 1;
+}
+#endif
+
+/* if face overlaps a branch, it executes func. recursive */
+static void isb_bsp_face_inside(ISBBranch *bspn, BSPFace *face)
+{
+
+ /* are we descending? */
+ if(bspn->left) {
+ /* hrmf, the box struct cannot be addressed with index */
+ if(bspn->index==0) {
+ if(face->box.xmin <= bspn->divider[0])
+ isb_bsp_face_inside(bspn->left, face);
+ if(face->box.xmax > bspn->divider[0])
+ isb_bsp_face_inside(bspn->right, face);
+ }
+ else {
+ if(face->box.ymin <= bspn->divider[1])
+ isb_bsp_face_inside(bspn->left, face);
+ if(face->box.ymax > bspn->divider[1])
+ isb_bsp_face_inside(bspn->right, face);
+ }
+ }
+ else {
+ /* else: end branch reached */
+ int a;
+
+ if(bspn->totsamp==0) return;
+
+ /* check for nodes entirely in shadow, can be skipped */
+ if(bspn->totsamp==bspn->full)
+ return;
+
+ /* if bsp node is entirely in front of face, give up */
+ if(bspn->box.zmax < face->box.zmin)
+ return;
+
+ /* if face boundbox is outside of branch rect, give up */
+ if(0==BLI_isect_rctf((rctf *)&face->box, (rctf *)&bspn->box, NULL))
+ return;
+
+ /* test all points inside branch */
+ for(a=bspn->totsamp-1; a>=0; a--) {
+ ISBSample *samp= bspn->samples[a];
+
+ if(samp->facenr!=face->facenr && samp->shadfac) {
+ if(face->box.zmin < samp->zco[2]) {
+ if(BLI_in_rctf((rctf *)&face->box, samp->zco[0], samp->zco[1])) {
+ int inshadow= 0;
+
+ if(face->type) {
+ if(point_behind_strand(samp->zco, face))
+ inshadow= 1;
+ }
+ else if( point_behind_tria2d(samp->zco, face->v1, face->v2, face->v3))
+ inshadow= 1;
+ else if(face->v4 && point_behind_tria2d(samp->zco, face->v1, face->v3, face->v4))
+ inshadow= 1;
+
+ if(inshadow) {
+ *(samp->shadfac) += face->shad_alpha;
+ /* optimize; is_full means shad_alpha==4096 */
+ if(*(samp->shadfac) >= 4096 || face->is_full) {
+ bspn->full++;
+ samp->shadfac= NULL;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+/* based on available samples, recalculate the bounding box for bsp nodes, recursive */
+static void isb_bsp_recalc_box(ISBBranch *root)
+{
+ if(root->left) {
+ isb_bsp_recalc_box(root->left);
+ isb_bsp_recalc_box(root->right);
+ }
+ else if(root->totsamp) {
+ int a;
+
+ init_box(&root->box);
+ for(a=root->totsamp-1; a>=0; a--)
+ bound_boxf(&root->box, root->samples[a]->zco);
+ }
+}
+
+/* callback function for zbuf clip */
+static void isb_bsp_test_strand(ZSpan *zspan, int zvlnr, float *v1, float *v2, float *v3, float *v4)
+{
+ BSPFace face;
+
+ face.v1= v1;
+ face.v2= v2;
+ face.v3= v3;
+ face.v4= v4;
+ face.facenr= zvlnr & ~RE_QUAD_OFFS;
+ face.type= R_STRAND;
+ if(R.osa)
+ face.shad_alpha= (short)ceil(4096.0f*zspan->shad_alpha/(float)R.osa);
+ else
+ face.shad_alpha= (short)ceil(4096.0f*zspan->shad_alpha);
+
+ face.is_full= (zspan->shad_alpha==1.0f);
+
+ /* setup boundbox */
+ init_box(&face.box);
+ bound_boxf(&face.box, v1);
+ bound_boxf(&face.box, v2);
+ bound_boxf(&face.box, v3);
+ if(v4)
+ bound_boxf(&face.box, v4);
+
+ /* optimize values */
+ bspface_init_strand(&face);
+
+ isb_bsp_face_inside((ISBBranch *)zspan->rectz, &face);
+
+}
+
+/* callback function for zbuf clip */
+static void isb_bsp_test_face(ZSpan *zspan, int zvlnr, float *v1, float *v2, float *v3, float *v4)
+{
+ BSPFace face;
+
+ face.v1= v1;
+ face.v2= v2;
+ face.v3= v3;
+ face.v4= v4;
+ face.facenr= zvlnr & ~RE_QUAD_OFFS;
+ face.type= 0;
+ if(R.osa)
+ face.shad_alpha= (short)ceil(4096.0f*zspan->shad_alpha/(float)R.osa);
+ else
+ face.shad_alpha= (short)ceil(4096.0f*zspan->shad_alpha);
+
+ face.is_full= (zspan->shad_alpha==1.0f);
+
+ /* setup boundbox */
+ init_box(&face.box);
+ bound_boxf(&face.box, v1);
+ bound_boxf(&face.box, v2);
+ bound_boxf(&face.box, v3);
+ if(v4)
+ bound_boxf(&face.box, v4);
+
+ isb_bsp_face_inside((ISBBranch *)zspan->rectz, &face);
+}
+
+static int testclip_minmax(float *ho, float *minmax)
+{
+ float wco= ho[3];
+ int flag= 0;
+
+ if( ho[0] > minmax[1]*wco) flag = 1;
+ else if( ho[0]< minmax[0]*wco) flag = 2;
+
+ if( ho[1] > minmax[3]*wco) flag |= 4;
+ else if( ho[1]< minmax[2]*wco) flag |= 8;
+
+ return flag;
+}
+
+/* main loop going over all faces and check in bsp overlaps, fill in shadfac values */
+static void isb_bsp_fillfaces(Render *re, LampRen *lar, ISBBranch *root)
+{
+ ShadBuf *shb= lar->shb;
+ ZSpan zspan, zspanstrand;
+ VlakRen *vlr= NULL;
+ Material *ma= NULL;
+ float minmaxf[4];
+ int size= shb->size;
+ int a, ok=1, lay= -1;
+
+ /* further optimize, also sets minz maxz */
+ isb_bsp_recalc_box(root);
+
+ /* extra clipping for minmax */
+ minmaxf[0]= (2.0f*root->box.xmin - size-2.0f)/size;
+ minmaxf[1]= (2.0f*root->box.xmax - size+2.0f)/size;
+ minmaxf[2]= (2.0f*root->box.ymin - size-2.0f)/size;
+ minmaxf[3]= (2.0f*root->box.ymax - size+2.0f)/size;
+
+ if(lar->mode & LA_LAYER) lay= lar->lay;
+
+ /* (ab)use zspan, since we use zbuffer clipping code */
+ zbuf_alloc_span(&zspan, size, size);
+
+ zspan.zmulx= ((float)size)/2.0f;
+ zspan.zmuly= ((float)size)/2.0f;
+ zspan.zofsx= -0.5f;
+ zspan.zofsy= -0.5f;
+
+ /* pass on bsp root to zspan */
+ zspan.rectz= (int *)root;
+
+ /* filling methods */
+ zspanstrand= zspan;
+ // zspan.zbuflinefunc= zbufline_onlyZ;
+ zspan.zbuffunc= isb_bsp_test_face;
+ zspanstrand.zbuffunc= isb_bsp_test_strand;
+
+ for(a=0; a<re->totvlak; a++) {
+
+ if((a & 255)==0) vlr= re->vlaknodes[a>>8].vlak;
+ else vlr++;
+
+ /* note, these conditions are copied in shadowbuf_autoclip() */
+ if(vlr->mat!= ma) {
+ ma= vlr->mat;
+ ok= 1;
+ if((ma->mode & MA_SHADBUF)==0) ok= 0;
+ if(ma->mode & MA_WIRE) ok= 0;
+ zspanstrand.shad_alpha= zspan.shad_alpha= ma->shad_alpha;
+ }
+
+ if(ok && (vlr->lay & lay)) {
+ float hoco[4][4];
+ int c1, c2, c3, c4=0;
+ int d1, d2, d3, d4=0;
+ int partclip;
+
+ /* create hocos per face, it is while render */
+ projectvert(vlr->v1->co, shb->persmat, hoco[0]); d1= testclip_minmax(hoco[0], minmaxf);
+ projectvert(vlr->v2->co, shb->persmat, hoco[1]); d2= testclip_minmax(hoco[1], minmaxf);
+ projectvert(vlr->v3->co, shb->persmat, hoco[2]); d3= testclip_minmax(hoco[2], minmaxf);
+ if(vlr->v4) {
+ projectvert(vlr->v4->co, shb->persmat, hoco[3]); d4= testclip_minmax(hoco[3], minmaxf);
+ }
+
+ /* minmax clipping */
+ if(vlr->v4) partclip= d1 & d2 & d3 & d4;
+ else partclip= d1 & d2 & d3;
+
+ if(partclip==0) {
+
+ /* window clipping */
+ c1= testclip(hoco[0]);
+ c2= testclip(hoco[1]);
+ c3= testclip(hoco[2]);
+ if(vlr->v4)
+ c4= testclip(hoco[3]);
+
+ /* ***** NO WIRE YET */
+ if(ma->mode & MA_WIRE)
+ zbufclipwire(&zspan, a+1, vlr);
+ else if(vlr->v4) {
+ if(vlr->flag & R_STRAND)
+ zbufclip4(&zspanstrand, a+1, hoco[0], hoco[1], hoco[2], hoco[3], c1, c2, c3, c4);
+ else
+ zbufclip4(&zspan, a+1, hoco[0], hoco[1], hoco[2], hoco[3], c1, c2, c3, c4);
+ }
+ else
+ zbufclip(&zspan, a+1, hoco[0], hoco[1], hoco[2], c1, c2, c3);
+
+ }
+ }
+ }
+
+ zbuf_free_span(&zspan);
+
+}
+
+
+/* returns 1 when the viewpixel is visible in lampbuffer */
+static int viewpixel_to_lampbuf(ShadBuf *shb, VlakRen *vlr, float x, float y, float *co)
+{
+ float hoco[4], *v1= vlr->v1->co, *nor= vlr->n;
+ float dface, fac, siz;
+
+ /* from shadepixel() */
+ dface= v1[0]*nor[0] + v1[1]*nor[1] + v1[2]*nor[2];
+ hoco[3]= 1.0f;
+
+ /* ortho viewplane cannot intersect using view vector originating in (0,0,0) */
+ if(R.r.mode & R_ORTHO) {
+ /* x and y 3d coordinate can be derived from pixel coord and winmat */
+ float fx= 2.0/(R.winx*R.winmat[0][0]);
+ float fy= 2.0/(R.winy*R.winmat[1][1]);
+
+ hoco[0]= (x - 0.5*R.winx)*fx - R.winmat[3][0]/R.winmat[0][0];
+ hoco[1]= (y - 0.5*R.winy)*fy - R.winmat[3][1]/R.winmat[1][1];
+
+ /* using a*x + b*y + c*z = d equation, (a b c) is normal */
+ if(nor[2]!=0.0f)
+ hoco[2]= (dface - nor[0]*hoco[0] - nor[1]*hoco[1])/nor[2];
+ else
+ hoco[2]= 0.0f;
+ }
+ else {
+ float div, view[3];
+
+ calc_view_vector(view, x, y);
+
+ div= nor[0]*view[0] + nor[1]*view[1] + nor[2]*view[2];
+ if (div==0.0f)
+ return 0;
+
+ fac= dface/div;
+
+ hoco[0]= fac*view[0];
+ hoco[1]= fac*view[1];
+ hoco[2]= fac*view[2];
+ }
+
+ /* move 3d vector to lampbuf */
+ MTC_Mat4MulVec4fl(shb->persmat, hoco); /* rational hom co */
+
+ /* clip We can test for -1.0/1.0 because of the properties of the
+ * coordinate transformations. */
+ fac= fabs(hoco[3]);
+ if(hoco[0]<-fac || hoco[0]>fac)
+ return 0;
+ if(hoco[1]<-fac || hoco[1]>fac)
+ return 0;
+ if(hoco[2]<-fac || hoco[2]>fac)
+ return 0;
+
+ siz= 0.5f*(float)shb->size;
+ co[0]= siz*(1.0f+hoco[0]/hoco[3]) -0.5f;
+ co[1]= siz*(1.0f+hoco[1]/hoco[3]) -0.5f;
+ co[2]= ((float)0x7FFFFFFF)*(hoco[2]/hoco[3]);
+
+ /* XXXX bias, much less than normal shadbuf, or do we need a constant? */
+ co[2] -= 0.05f*shb->bias;
+
+ return 1;
+}
+
+/* storage of shadow results, solid osa and transp case */
+static void isb_add_shadfac(ISBShadfacA **isbsapp, MemArena *mem, int facenr, short shadfac, short samples)
+{
+ ISBShadfacA *new;
+ float shadfacf;
+
+ /* in osa case, the samples were filled in with factor 1.0/R.osa. if fewer samples we have to correct */
+ if(R.osa)
+ shadfacf= ((float)shadfac*R.osa)/(4096.0*samples);
+ else
+ shadfacf= ((float)shadfac)/(4096.0);
+
+ new= BLI_memarena_alloc(mem, sizeof(ISBShadfacA));
+ new->facenr= facenr & ~RE_QUAD_OFFS;
+ new->shadfac= shadfacf;
+ if(*isbsapp)
+ new->next= (*isbsapp);
+ else
+ new->next= NULL;
+
+ *isbsapp= new;
+}
+
+/* adding samples, solid case */
+static int isb_add_samples(RenderPart *pa, ISBBranch *root, MemArena *memarena, ISBSample **samplebuf)
+{
+ int xi, yi, *xcos, *ycos;
+ int sample, bsp_err= 0;
+
+ /* bsp split doesn't like to handle regular sequenes */
+ xcos= MEM_mallocN( pa->rectx*sizeof(int), "xcos");
+ ycos= MEM_mallocN( pa->recty*sizeof(int), "ycos");
+ for(xi=0; xi<pa->rectx; xi++)
+ xcos[xi]= xi;
+ for(yi=0; yi<pa->recty; yi++)
+ ycos[yi]= yi;
+ BLI_array_randomize(xcos, sizeof(int), pa->rectx, 12345);
+ BLI_array_randomize(ycos, sizeof(int), pa->recty, 54321);
+
+ for(sample=0; sample<(R.osa?R.osa:1); sample++) {
+ ISBSample *samp= samplebuf[sample], *samp1;
+
+ for(yi=0; yi<pa->recty; yi++) {
+ int y= ycos[yi];
+ for(xi=0; xi<pa->rectx; xi++) {
+ int x= xcos[xi];
+ samp1= samp + y*pa->rectx + x;
+ if(samp1->facenr)
+ bsp_err |= isb_bsp_insert(root, memarena, samp1);
+ }
+ if(bsp_err) break;
+ }
+ }
+
+ MEM_freeN(xcos);
+ MEM_freeN(ycos);
+
+ return bsp_err;
+}
+
+/* solid version */
+/* lar->shb, pa->rectz and pa->rectp should exist */
+static void isb_make_buffer(RenderPart *pa, LampRen *lar)
+{
+ ShadBuf *shb= lar->shb;
+ ISBData *isbdata;
+ ISBSample *samp, *samplebuf[16]; /* should be RE_MAX_OSA */
+ ISBBranch root;
+ MemArena *memarena;
+ long *rd;
+ int *rectp, x, y, sindex, sample, bsp_err=0;
+
+ /* storage for shadow, per thread */
+ isbdata= shb->isb_result[pa->thread];
+
+ /* to map the shi->xs and ys coordinate */
+ isbdata->minx= pa->disprect.xmin;
+ isbdata->miny= pa->disprect.ymin;
+ isbdata->rectx= pa->rectx;
+ isbdata->recty= pa->recty;
+
+ /* branches are added using memarena (32k branches) */
+ memarena = BLI_memarena_new(0x8000 * sizeof(ISBBranch));
+ BLI_memarena_use_calloc(memarena);
+
+ /* samplebuf is in camera view space (pixels) */
+ for(sample=0; sample<(R.osa?R.osa:1); sample++)
+ samplebuf[sample]= MEM_callocN(sizeof(ISBSample)*pa->rectx*pa->recty, "isb samplebuf");
+
+ /* for end result, ISBSamples point to this in non OSA case, otherwise to pixstruct->shadfac */
+ if(R.osa==0)
+ isbdata->shadfacs= MEM_callocN(pa->rectx*pa->recty*sizeof(short), "isb shadfacs");
+
+ /* setup bsp root */
+ memset(&root, 0, sizeof(ISBBranch));
+ root.box.xmin= (float)shb->size;
+ root.box.ymin= (float)shb->size;
+
+ /* create the sample buffers */
+ for(sindex=0, y=0; y<pa->recty; y++) {
+ for(x=0; x<pa->rectx; x++, sindex++) {
+
+ /* this makes it a long function, but splitting it out would mean 10+ arguments */
+ /* first check OSA case */
+ if(R.osa) {
+ rd= pa->rectdaps + sindex;
+ if(*rd) {
+ float xs= (float)(x + pa->disprect.xmin);
+ float ys= (float)(y + pa->disprect.ymin);
+
+ for(sample=0; sample<R.osa; sample++) {
+ PixStr *ps= (PixStr *)(*rd);
+ int mask= (1<<sample);
+
+ while(ps) {
+ if(ps->mask & mask)
+ break;
+ ps= ps->next;
+ }
+ if(ps && ps->facenr>0) {
+ VlakRen *vlr= RE_findOrAddVlak(&R, (ps->facenr-1) & RE_QUAD_MASK);
+
+ samp= samplebuf[sample] + sindex;
+ /* convert image plane pixel location to lamp buffer space */
+ if(viewpixel_to_lampbuf(shb, vlr, xs + R.jit[sample][0], ys + R.jit[sample][1], samp->zco)) {
+ samp->facenr= ps->facenr & ~RE_QUAD_OFFS;
+ ps->shadfac= 0;
+ samp->shadfac= &ps->shadfac;
+ bound_rectf((rctf *)&root.box, samp->zco);
+ }
+ }
+ }
+ }
+ }
+ else {
+ rectp= pa->rectp + sindex;
+ if(*rectp>0) {
+ VlakRen *vlr= RE_findOrAddVlak(&R, (*rectp-1) & RE_QUAD_MASK);
+ float xs= (float)(x + pa->disprect.xmin);
+ float ys= (float)(y + pa->disprect.ymin);
+
+ samp= samplebuf[0] + sindex;
+ /* convert image plane pixel location to lamp buffer space */
+ if(viewpixel_to_lampbuf(shb, vlr, xs, ys, samp->zco)) {
+ samp->facenr= *rectp & ~RE_QUAD_OFFS;
+ samp->shadfac= isbdata->shadfacs + sindex;
+ bound_rectf((rctf *)&root.box, samp->zco);
+ }
+ }
+ }
+ }
+ }
+
+ /* simple method to see if we have samples */
+ if(root.box.xmin != (float)shb->size) {
+ /* now create a regular split, root.box has the initial bounding box of all pixels */
+ /* split bsp 8 levels deep, in regular grid (16 x 16) */
+ isb_bsp_split_init(&root, memarena, 8);
+
+ /* insert all samples in BSP now */
+ bsp_err= isb_add_samples(pa, &root, memarena, samplebuf);
+
+ if(bsp_err==0) {
+ /* go over all faces and fill in shadow values */
+
+ isb_bsp_fillfaces(&R, lar, &root); /* shb->persmat should have been calculated */
+
+ /* copy shadow samples to persistant buffer, reduce memory overhead */
+ if(R.osa) {
+ ISBShadfacA **isbsa= isbdata->shadfaca= MEM_callocN(pa->rectx*pa->recty*sizeof(void *), "isb shadfacs");
+
+ isbdata->memarena = BLI_memarena_new(0x8000 * sizeof(ISBSampleA));
+ BLI_memarena_use_calloc(isbdata->memarena);
+
+ for(rd= pa->rectdaps, x=pa->rectx*pa->recty; x>0; x--, rd++, isbsa++) {
+
+ if(*rd) {
+ PixStr *ps= (PixStr *)(*rd);
+ while(ps) {
+ if(ps->shadfac)
+ isb_add_shadfac(isbsa, isbdata->memarena, ps->facenr, ps->shadfac, count_mask(ps->mask));
+ ps= ps->next;
+ }
+ }
+ }
+ }
+ }
+ }
+ else {
+ if(isbdata->shadfacs) {
+ MEM_freeN(isbdata->shadfacs);
+ isbdata->shadfacs= NULL;
+ }
+ }
+
+ /* free BSP */
+ BLI_memarena_free(memarena);
+
+ /* free samples */
+ for(x=0; x<(R.osa?R.osa:1); x++)
+ MEM_freeN(samplebuf[x]);
+
+ if(bsp_err) printf("error in filling bsp\n");
+}
+
+/* add sample to buffer, isbsa is the root sample in a buffer */
+static ISBSampleA *isb_alloc_sample_transp(ISBSampleA **isbsa, MemArena *mem)
+{
+ ISBSampleA *new;
+
+ new= BLI_memarena_alloc(mem, sizeof(ISBSampleA));
+ if(*isbsa)
+ new->next= (*isbsa);
+ else
+ new->next= NULL;
+
+ *isbsa= new;
+ return new;
+}
+
+/* adding samples in BSP, transparent case */
+static int isb_add_samples_transp(RenderPart *pa, ISBBranch *root, MemArena *memarena, ISBSampleA ***samplebuf)
+{
+ int xi, yi, *xcos, *ycos;
+ int sample, bsp_err= 0;
+
+ /* bsp split doesn't like to handle regular sequenes */
+ xcos= MEM_mallocN( pa->rectx*sizeof(int), "xcos");
+ ycos= MEM_mallocN( pa->recty*sizeof(int), "ycos");
+ for(xi=0; xi<pa->rectx; xi++)
+ xcos[xi]= xi;
+ for(yi=0; yi<pa->recty; yi++)
+ ycos[yi]= yi;
+ BLI_array_randomize(xcos, sizeof(int), pa->rectx, 12345);
+ BLI_array_randomize(ycos, sizeof(int), pa->recty, 54321);
+
+ for(sample=0; sample<(R.osa?R.osa:1); sample++) {
+ ISBSampleA **samp= samplebuf[sample], *samp1;
+
+ for(yi=0; yi<pa->recty; yi++) {
+ int y= ycos[yi];
+ for(xi=0; xi<pa->rectx; xi++) {
+ int x= xcos[xi];
+
+ samp1= *(samp + y*pa->rectx + x);
+ while(samp1) {
+ bsp_err |= isb_bsp_insert(root, memarena, (ISBSample *)samp1);
+ samp1= samp1->next;
+ }
+ }
+ if(bsp_err) break;
+ }
+ }
+
+ MEM_freeN(xcos);
+ MEM_freeN(ycos);
+
+ return bsp_err;
+}
+
+
+/* Ztransp version */
+/* lar->shb, pa->rectz and pa->rectp should exist */
+static void isb_make_buffer_transp(RenderPart *pa, APixstr *apixbuf, LampRen *lar)
+{
+ ShadBuf *shb= lar->shb;
+ ISBData *isbdata;
+ ISBSampleA *samp, **samplebuf[16]; /* MAX_OSA */
+ ISBBranch root;
+ MemArena *memarena;
+ APixstr *ap;
+ int x, y, sindex, sample, bsp_err=0;
+
+ /* storage for shadow, per thread */
+ isbdata= shb->isb_result[pa->thread];
+
+ /* to map the shi->xs and ys coordinate */
+ isbdata->minx= pa->disprect.xmin;
+ isbdata->miny= pa->disprect.ymin;
+ isbdata->rectx= pa->rectx;
+ isbdata->recty= pa->recty;
+
+ /* branches are added using memarena (32k branches) */
+ memarena = BLI_memarena_new(0x8000 * sizeof(ISBBranch));
+ BLI_memarena_use_calloc(memarena);
+
+ /* samplebuf is in camera view space (pixels) */
+ for(sample=0; sample<(R.osa?R.osa:1); sample++)
+ samplebuf[sample]= MEM_callocN(sizeof(void *)*pa->rectx*pa->recty, "isb alpha samplebuf");
+
+ /* setup bsp root */
+ memset(&root, 0, sizeof(ISBBranch));
+ root.box.xmin= (float)shb->size;
+ root.box.ymin= (float)shb->size;
+
+ /* create the sample buffers */
+ for(ap= apixbuf, sindex=0, y=0; y<pa->recty; y++) {
+ for(x=0; x<pa->rectx; x++, sindex++, ap++) {
+
+ if(ap->p[0]) {
+ APixstr *apn;
+ float xs= (float)(x + pa->disprect.xmin);
+ float ys= (float)(y + pa->disprect.ymin);
+
+ for(apn=ap; apn; apn= apn->next) {
+ int a;
+ for(a=0; a<4; a++) {
+ if(apn->p[a]) {
+ VlakRen *vlr= RE_findOrAddVlak(&R, (apn->p[a]-1) & RE_QUAD_MASK);
+ float zco[3];
+
+ /* here we store shadfac, easier to create the end storage buffer. needs zero'ed, multiple shadowbufs use it */
+ apn->shadfac[a]= 0;
+
+ if(R.osa) {
+ for(sample=0; sample<R.osa; sample++) {
+ int mask= (1<<sample);
+
+ if(apn->mask[a] & mask) {
+
+ /* convert image plane pixel location to lamp buffer space */
+ if(viewpixel_to_lampbuf(shb, vlr, xs + R.jit[sample][0], ys + R.jit[sample][1], zco)) {
+ samp= isb_alloc_sample_transp(samplebuf[sample] + sindex, memarena);
+ samp->facenr= apn->p[a] & ~RE_QUAD_OFFS;
+ samp->shadfac= &apn->shadfac[a];
+
+ VECCOPY(samp->zco, zco);
+ bound_rectf((rctf *)&root.box, samp->zco);
+ }
+ }
+ }
+ }
+ else {
+
+ /* convert image plane pixel location to lamp buffer space */
+ if(viewpixel_to_lampbuf(shb, vlr, xs, ys, zco)) {
+
+ samp= isb_alloc_sample_transp(samplebuf[0] + sindex, memarena);
+ samp->facenr= apn->p[a] & ~RE_QUAD_OFFS;
+ samp->shadfac= &apn->shadfac[a];
+
+ VECCOPY(samp->zco, zco);
+ bound_rectf((rctf *)&root.box, samp->zco);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* simple method to see if we have samples */
+ if(root.box.xmin != (float)shb->size) {
+ /* now create a regular split, root.box has the initial bounding box of all pixels */
+ /* split bsp 8 levels deep, in regular grid (16 x 16) */
+ isb_bsp_split_init(&root, memarena, 8);
+
+ /* insert all samples in BSP now */
+ bsp_err= isb_add_samples_transp(pa, &root, memarena, samplebuf);
+
+ if(bsp_err==0) {
+ ISBShadfacA **isbsa;
+
+ /* go over all faces and fill in shadow values */
+ isb_bsp_fillfaces(&R, lar, &root); /* shb->persmat should have been calculated */
+
+ /* copy shadow samples to persistant buffer, reduce memory overhead */
+ isbsa= isbdata->shadfaca= MEM_callocN(pa->rectx*pa->recty*sizeof(void *), "isb shadfacs");
+
+ isbdata->memarena = BLI_memarena_new(0x8000 * sizeof(ISBSampleA));
+
+ for(ap= apixbuf, x=pa->rectx*pa->recty; x>0; x--, ap++, isbsa++) {
+
+ if(ap->p[0]) {
+ APixstr *apn;
+ for(apn=ap; apn; apn= apn->next) {
+ int a;
+ for(a=0; a<4; a++) {
+ if(apn->p[a] && apn->shadfac[a]) {
+ if(R.osa)
+ isb_add_shadfac(isbsa, isbdata->memarena, apn->p[a], apn->shadfac[a], count_mask(apn->mask[a]));
+ else
+ isb_add_shadfac(isbsa, isbdata->memarena, apn->p[a], apn->shadfac[a], 0);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* free BSP */
+ BLI_memarena_free(memarena);
+
+ /* free samples */
+ for(x=0; x<(R.osa?R.osa:1); x++)
+ MEM_freeN(samplebuf[x]);
+
+ if(bsp_err) printf("error in filling bsp\n");
+}
+
+
+
+/* exported */
+
+/* returns amount of light (1.0 = no shadow) */
+/* note, shadepixel() rounds the coordinate, not the real sample info */
+float ISB_getshadow(ShadeInput *shi, ShadBuf *shb)
+{
+ /* if raytracing, we can't accept irregular shadow */
+ if(shi->depth==0) {
+ ISBData *isbdata= shb->isb_result[shi->thread];
+
+ if(isbdata) {
+ if(isbdata->shadfacs || isbdata->shadfaca) {
+ int x= shi->xs - isbdata->minx;
+
+ if(x >= 0 && x < isbdata->rectx) {
+ int y= shi->ys - isbdata->miny;
+
+ if(y >= 0 && y < isbdata->recty) {
+ if(isbdata->shadfacs) {
+ short *sp= isbdata->shadfacs + y*isbdata->rectx + x;
+ return *sp>=4096?0.0f:1.0f - ((float)*sp)/4096.0f;
+ }
+ else {
+ int sindex= y*isbdata->rectx + x;
+ ISBShadfacA *isbsa= *(isbdata->shadfaca + sindex);
+
+ while(isbsa) {
+ if(isbsa->facenr==shi->facenr+1)
+ return isbsa->shadfac>=1.0f?0.0f:1.0f - isbsa->shadfac;
+ isbsa= isbsa->next;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return 1.0f;
+}
+
+/* part is supposed to be solid zbuffered (apixbuf==NULL) or transparent zbuffered */
+void ISB_create(RenderPart *pa, APixstr *apixbuf)
+{
+ GroupObject *go;
+
+ /* go over all lamps, and make the irregular buffers */
+ for(go=R.lights.first; go; go= go->next) {
+ LampRen *lar= go->lampren;
+
+ if(lar->type==LA_SPOT && lar->shb && lar->buftype==LA_SHADBUF_IRREGULAR) {
+
+ /* create storage for shadow, per thread */
+ lar->shb->isb_result[pa->thread]= MEM_callocN(sizeof(ISBData), "isb data");
+
+ if(apixbuf)
+ isb_make_buffer_transp(pa, apixbuf, lar);
+ else
+ isb_make_buffer(pa, lar);
+ }
+ }
+}
+
+
+/* end of part rendering, free stored shadow data for this thread from all lamps */
+void ISB_free(RenderPart *pa)
+{
+ GroupObject *go;
+
+ /* go over all lamps, and free the irregular buffers */
+ for(go=R.lights.first; go; go= go->next) {
+ LampRen *lar= go->lampren;
+
+ if(lar->type==LA_SPOT && lar->shb && lar->buftype==LA_SHADBUF_IRREGULAR) {
+ ISBData *isbdata= lar->shb->isb_result[pa->thread];
+
+ if(isbdata) {
+ if(isbdata->shadfacs)
+ MEM_freeN(isbdata->shadfacs);
+ if(isbdata->shadfaca)
+ MEM_freeN(isbdata->shadfaca);
+
+ if(isbdata->memarena)
+ BLI_memarena_free(isbdata->memarena);
+
+ MEM_freeN(isbdata);
+ lar->shb->isb_result[pa->thread]= NULL;
+ }
+ }
+ }
+}
+
+
+
+
+
diff --git a/source/blender/render/intern/source/shadeinput.c b/source/blender/render/intern/source/shadeinput.c
new file mode 100644
index 00000000000..ca661469b36
--- /dev/null
+++ b/source/blender/render/intern/source/shadeinput.c
@@ -0,0 +1,1016 @@
+/**
+* $Id:
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation
+ * All rights reserved.
+ *
+ * Contributors: Hos, Robert Wenzlaff.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+
+#include "MTC_matrixops.h"
+#include "BLI_arithb.h"
+
+#include "DNA_curve_types.h"
+#include "DNA_group_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_material_types.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_node.h"
+
+/* local include */
+#include "renderpipeline.h"
+#include "render_types.h"
+#include "renderdatabase.h"
+#include "rendercore.h"
+#include "shadbuf.h"
+#include "shading.h"
+#include "texture.h"
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
+/* only to be used here in this file, it's for speed */
+extern struct Render R;
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+
+#define VECADDISFAC(v1,v3,fac) {*(v1)+= *(v3)*(fac); *(v1+1)+= *(v3+1)*(fac); *(v1+2)+= *(v3+2)*(fac);}
+
+
+
+/* Shade Sample order:
+
+- shade_samples_fill_with_ps()
+ - for each sample
+ - shade_input_set_triangle() <- if prev sample-face is same, use shade_input_copy_triangle()
+ - if vlr
+ - shade_input_set_viewco() <- not for ray or bake
+ - shade_input_set_uv() <- not for ray or bake
+ - shade_input_set_normals()
+- shade_samples()
+ - if AO
+ - shade_samples_do_AO()
+ - if shading happens
+ - for each sample
+ - shade_input_set_shade_texco()
+ - shade_samples_do_shade()
+- OSA: distribute sample result with filter masking
+
+ */
+
+
+/* also used as callback for nodes */
+/* delivers a fully filled in ShadeResult, for all passes */
+void shade_material_loop(ShadeInput *shi, ShadeResult *shr)
+{
+
+ shade_lamp_loop(shi, shr); /* clears shr */
+
+ if(shi->translucency!=0.0f) {
+ ShadeResult shr_t;
+ float fac= shi->translucency;
+
+ /* gotta copy it again */
+ memcpy(&shi->r, &shi->mat->r, 23*sizeof(float));
+ shi->har= shi->mat->har;
+
+ VECCOPY(shi->vn, shi->vno);
+ VECMUL(shi->vn, -1.0f);
+ VECMUL(shi->facenor, -1.0f);
+ shi->depth++; /* hack to get real shadow now */
+ shade_lamp_loop(shi, &shr_t);
+ shi->depth--;
+
+ /* a couple of passes */
+ VECADDISFAC(shr->combined, shr_t.combined, fac);
+ if(shi->passflag & SCE_PASS_SPEC)
+ VECADDISFAC(shr->spec, shr_t.spec, fac);
+ if(shi->passflag & SCE_PASS_DIFFUSE)
+ VECADDISFAC(shr->diff, shr_t.diff, fac);
+ if(shi->passflag & SCE_PASS_SHADOW)
+ VECADDISFAC(shr->shad, shr_t.shad, fac);
+
+ VECMUL(shi->vn, -1.0f);
+ VECMUL(shi->facenor, -1.0f);
+ }
+
+ /* depth >= 1 when ray-shading */
+ if(shi->depth==0) {
+ if(R.r.mode & R_RAYTRACE) {
+ if(shi->ray_mirror!=0.0f || ((shi->mat->mode & MA_RAYTRANSP) && shr->alpha!=1.0f)) {
+
+ /* ray trace works on combined, but gives pass info */
+ ray_trace(shi, shr);
+ }
+ }
+ /* disable adding of sky for raytransp */
+ if(shi->mat->mode & MA_RAYTRANSP)
+ if(shi->layflag & SCE_LAY_SKY)
+ shr->alpha= 1.0f;
+ }
+}
+
+
+/* do a shade, finish up some passes, apply mist */
+void shade_input_do_shade(ShadeInput *shi, ShadeResult *shr)
+{
+ float alpha;
+
+ /* ------ main shading loop -------- */
+
+ if(shi->mat->nodetree && shi->mat->use_nodes) {
+ ntreeShaderExecTree(shi->mat->nodetree, shi, shr);
+ }
+ else {
+ /* copy all relevant material vars, note, keep this synced with render_types.h */
+ memcpy(&shi->r, &shi->mat->r, 23*sizeof(float));
+ shi->har= shi->mat->har;
+
+ shade_material_loop(shi, shr);
+ }
+
+ /* copy additional passes */
+ if(shi->passflag & (SCE_PASS_VECTOR|SCE_PASS_NORMAL|SCE_PASS_RADIO)) {
+ QUATCOPY(shr->winspeed, shi->winspeed);
+ VECCOPY(shr->nor, shi->vn);
+ VECCOPY(shr->rad, shi->rad);
+ }
+
+ /* MIST */
+ if((R.wrld.mode & WO_MIST) && (shi->mat->mode & MA_NOMIST)==0 ) {
+ if(R.r.mode & R_ORTHO)
+ alpha= mistfactor(-shi->co[2], shi->co);
+ else
+ alpha= mistfactor(VecLength(shi->co), shi->co);
+ }
+ else alpha= 1.0f;
+
+ /* add mist and premul color */
+ if(shr->alpha!=1.0f || alpha!=1.0f) {
+ float fac= alpha*(shr->alpha);
+
+ shr->combined[3]= fac;
+ shr->combined[0]*= fac;
+ shr->combined[1]*= fac;
+ shr->combined[2]*= fac;
+ }
+ else shr->combined[3]= 1.0f;
+
+}
+
+/* **************************************************************************** */
+/* ShadeInput */
+/* **************************************************************************** */
+
+
+void vlr_set_uv_indices(VlakRen *vlr, int *i1, int *i2, int *i3)
+{
+ /* to prevent storing new tfaces or vcols, we check a split runtime */
+ /* 4---3 4---3 */
+ /* |\ 1| or |1 /| */
+ /* |0\ | |/ 0| */
+ /* 1---2 1---2 0 = orig face, 1 = new face */
+
+ /* Update vert nums to point to correct verts of original face */
+ if(vlr->flag & R_DIVIDE_24) {
+ if(vlr->flag & R_FACE_SPLIT) {
+ (*i1)++; (*i2)++; (*i3)++;
+ }
+ else {
+ (*i3)++;
+ }
+ }
+ else if(vlr->flag & R_FACE_SPLIT) {
+ (*i2)++; (*i3)++;
+ }
+}
+
+
+/* copy data from face to ShadeInput, general case */
+/* indices 0 1 2 3 only. shi->puno should be set! */
+void shade_input_set_triangle_i(ShadeInput *shi, VlakRen *vlr, short i1, short i2, short i3)
+{
+ VertRen **vpp= &vlr->v1;
+
+ shi->vlr= vlr;
+
+ shi->v1= vpp[i1];
+ shi->v2= vpp[i2];
+ shi->v3= vpp[i3];
+
+ shi->i1= i1;
+ shi->i2= i2;
+ shi->i3= i3;
+
+ /* note, shi->mat is set in node shaders */
+ shi->mat= shi->mat_override?shi->mat_override:vlr->mat;
+
+ shi->osatex= (shi->mat->texco & TEXCO_OSA);
+ shi->mode= shi->mat->mode_l; /* or-ed result for all nodes */
+
+ /* calculate vertexnormals */
+ if(vlr->flag & R_SMOOTH) {
+ float *n1= shi->v1->n, *n2= shi->v2->n, *n3= shi->v3->n;
+ char p1, p2, p3;
+
+ p1= 1<<i1;
+ p2= 1<<i2;
+ p3= 1<<i3;
+
+ if(shi->puno & p1) {
+ shi->n1[0]= -n1[0]; shi->n1[1]= -n1[1]; shi->n1[2]= -n1[2];
+ } else {
+ VECCOPY(shi->n1, n1);
+ }
+ if(shi->puno & p2) {
+ shi->n2[0]= -n2[0]; shi->n2[1]= -n2[1]; shi->n2[2]= -n2[2];
+ } else {
+ VECCOPY(shi->n2, n2);
+ }
+ if(shi->puno & p3) {
+ shi->n3[0]= -n3[0]; shi->n3[1]= -n3[1]; shi->n3[2]= -n3[2];
+ } else {
+ VECCOPY(shi->n3, n3);
+ }
+ }
+ /* facenormal copy, can get flipped */
+ VECCOPY(shi->facenor, vlr->n);
+
+ /* copy of original pre-flipped normal, for geometry->front/back node output */
+ VECCOPY(shi->orignor, vlr->n);
+ if (vlr->noflag & R_FLIPPED_NO) {
+ VECMUL(shi->orignor, -1.0f);
+ }
+}
+
+/* note, facenr declared volatile due to over-eager -O2 optimizations
+ * on cygwin (particularly -frerun-cse-after-loop)
+ */
+
+/* copy data from face to ShadeInput, scanline case */
+void shade_input_set_triangle(ShadeInput *shi, volatile int facenr, int normal_flip)
+{
+ if(facenr>0) {
+ shi->facenr= (facenr-1) & RE_QUAD_MASK;
+ if( shi->facenr < R.totvlak ) {
+ VlakRen *vlr= RE_findOrAddVlak(&R, shi->facenr);
+
+ shi->puno= normal_flip?vlr->puno:0;
+
+ if(facenr & RE_QUAD_OFFS)
+ shade_input_set_triangle_i(shi, vlr, 0, 2, 3);
+ else
+ shade_input_set_triangle_i(shi, vlr, 0, 1, 2);
+ }
+ else
+ shi->vlr= NULL; /* general signal we got sky */
+ }
+ else
+ shi->vlr= NULL; /* general signal we got sky */
+
+}
+
+/* full osa case: copy static info */
+void shade_input_copy_triangle(ShadeInput *shi, ShadeInput *from)
+{
+ /* not so nice, but works... warning is in RE_shader_ext.h */
+ memcpy(shi, from, sizeof(struct ShadeInputCopy));
+}
+
+
+/* scanline pixel coordinates */
+/* requires set_triangle */
+void shade_input_set_viewco(ShadeInput *shi, float x, float y, float z)
+{
+ float fac;
+
+ /* currently in use for dithering (soft shadow), node preview, irregular shad */
+ shi->xs= (int)(x);
+ shi->ys= (int)(y);
+
+ calc_view_vector(shi->view, x, y); /* returns not normalized, so is in viewplane coords */
+
+ /* wire cannot use normal for calculating shi->co */
+ if(shi->mat->mode & MA_WIRE) {
+
+ if(R.r.mode & R_ORTHO)
+ calc_renderco_ortho(shi->co, x, y, z);
+ else
+ calc_renderco_zbuf(shi->co, shi->view, z);
+ }
+ else {
+ float dface, *v1= shi->v1->co;
+
+ dface= v1[0]*shi->facenor[0]+v1[1]*shi->facenor[1]+v1[2]*shi->facenor[2];
+
+ /* ortho viewplane cannot intersect using view vector originating in (0,0,0) */
+ if(R.r.mode & R_ORTHO) {
+ /* x and y 3d coordinate can be derived from pixel coord and winmat */
+ float fx= 2.0f/(R.winx*R.winmat[0][0]);
+ float fy= 2.0f/(R.winy*R.winmat[1][1]);
+
+ shi->co[0]= (x - 0.5f*R.winx)*fx - R.winmat[3][0]/R.winmat[0][0];
+ shi->co[1]= (y - 0.5f*R.winy)*fy - R.winmat[3][1]/R.winmat[1][1];
+
+ /* using a*x + b*y + c*z = d equation, (a b c) is normal */
+ if(shi->facenor[2]!=0.0f)
+ shi->co[2]= (dface - shi->facenor[0]*shi->co[0] - shi->facenor[1]*shi->co[1])/shi->facenor[2];
+ else
+ shi->co[2]= 0.0f;
+
+ if(shi->osatex || (R.r.mode & R_SHADOW) ) {
+ shi->dxco[0]= fx;
+ shi->dxco[1]= 0.0f;
+ if(shi->facenor[2]!=0.0f)
+ shi->dxco[2]= (shi->facenor[0]*fx)/shi->facenor[2];
+ else
+ shi->dxco[2]= 0.0f;
+
+ shi->dyco[0]= 0.0f;
+ shi->dyco[1]= fy;
+ if(shi->facenor[2]!=0.0f)
+ shi->dyco[2]= (shi->facenor[1]*fy)/shi->facenor[2];
+ else
+ shi->dyco[2]= 0.0f;
+
+ if( (shi->mat->texco & TEXCO_REFL) ) {
+ if(shi->co[2]!=0.0f) fac= 1.0f/shi->co[2]; else fac= 0.0f;
+ shi->dxview= -R.viewdx*fac;
+ shi->dyview= -R.viewdy*fac;
+ }
+ }
+ }
+ else {
+ float div;
+
+ div= shi->facenor[0]*shi->view[0] + shi->facenor[1]*shi->view[1] + shi->facenor[2]*shi->view[2];
+ if (div!=0.0f) fac= dface/div;
+ else fac= 0.0f;
+
+ shi->co[0]= fac*shi->view[0];
+ shi->co[1]= fac*shi->view[1];
+ shi->co[2]= fac*shi->view[2];
+
+ /* pixel dx/dy for render coord */
+ if(shi->osatex || (R.r.mode & R_SHADOW) ) {
+ float u= dface/(div - R.viewdx*shi->facenor[0]);
+ float v= dface/(div - R.viewdy*shi->facenor[1]);
+
+ shi->dxco[0]= shi->co[0]- (shi->view[0]-R.viewdx)*u;
+ shi->dxco[1]= shi->co[1]- (shi->view[1])*u;
+ shi->dxco[2]= shi->co[2]- (shi->view[2])*u;
+
+ shi->dyco[0]= shi->co[0]- (shi->view[0])*v;
+ shi->dyco[1]= shi->co[1]- (shi->view[1]-R.viewdy)*v;
+ shi->dyco[2]= shi->co[2]- (shi->view[2])*v;
+
+ if( (shi->mat->texco & TEXCO_REFL) ) {
+ if(fac!=0.0f) fac= 1.0f/fac;
+ shi->dxview= -R.viewdx*fac;
+ shi->dyview= -R.viewdy*fac;
+ }
+ }
+ }
+ }
+
+ /* cannot normalize earlier, code above needs it at viewplane level */
+ Normalize(shi->view);
+}
+
+/* calculate U and V, for scanline (silly render face u and v are in range -1 to 0) */
+void shade_input_set_uv(ShadeInput *shi)
+{
+ VlakRen *vlr= shi->vlr;
+
+ if( (vlr->flag & R_SMOOTH) || (shi->mat->texco & NEED_UV) || (shi->passflag & SCE_PASS_UV)) {
+ float *v1= shi->v1->co, *v2= shi->v2->co, *v3= shi->v3->co;
+
+ /* exception case for wire render of edge */
+ if(vlr->v2==vlr->v3) {
+ float lend, lenc;
+
+ lend= VecLenf(v2, v1);
+ lenc= VecLenf(shi->co, v1);
+
+ if(lend==0.0f) {
+ shi->u=shi->v= 0.0f;
+ }
+ else {
+ shi->u= - (1.0f - lenc/lend);
+ shi->v= 0.0f;
+ }
+
+ if(shi->osatex) {
+ shi->dx_u= 0.0f;
+ shi->dx_v= 0.0f;
+ shi->dy_u= 0.0f;
+ shi->dy_v= 0.0f;
+ }
+ }
+ else {
+ /* most of this could become re-used for faces */
+ float detsh, t00, t10, t01, t11;
+
+ if(vlr->noflag & R_SNPROJ_X) {
+ t00= v3[0]-v1[0]; t01= v3[1]-v1[1];
+ t10= v3[0]-v2[0]; t11= v3[1]-v2[1];
+ }
+ else if(vlr->noflag & R_SNPROJ_Y) {
+ t00= v3[0]-v1[0]; t01= v3[2]-v1[2];
+ t10= v3[0]-v2[0]; t11= v3[2]-v2[2];
+ }
+ else {
+ t00= v3[1]-v1[1]; t01= v3[2]-v1[2];
+ t10= v3[1]-v2[1]; t11= v3[2]-v2[2];
+ }
+
+ detsh= 1.0f/(t00*t11-t10*t01);
+ t00*= detsh; t01*=detsh;
+ t10*=detsh; t11*=detsh;
+
+ if(vlr->noflag & R_SNPROJ_X) {
+ shi->u= (shi->co[0]-v3[0])*t11-(shi->co[1]-v3[1])*t10;
+ shi->v= (shi->co[1]-v3[1])*t00-(shi->co[0]-v3[0])*t01;
+ if(shi->osatex) {
+ shi->dx_u= shi->dxco[0]*t11- shi->dxco[1]*t10;
+ shi->dx_v= shi->dxco[1]*t00- shi->dxco[0]*t01;
+ shi->dy_u= shi->dyco[0]*t11- shi->dyco[1]*t10;
+ shi->dy_v= shi->dyco[1]*t00- shi->dyco[0]*t01;
+ }
+ }
+ else if(vlr->noflag & R_SNPROJ_Y) {
+ shi->u= (shi->co[0]-v3[0])*t11-(shi->co[2]-v3[2])*t10;
+ shi->v= (shi->co[2]-v3[2])*t00-(shi->co[0]-v3[0])*t01;
+ if(shi->osatex) {
+ shi->dx_u= shi->dxco[0]*t11- shi->dxco[2]*t10;
+ shi->dx_v= shi->dxco[2]*t00- shi->dxco[0]*t01;
+ shi->dy_u= shi->dyco[0]*t11- shi->dyco[2]*t10;
+ shi->dy_v= shi->dyco[2]*t00- shi->dyco[0]*t01;
+ }
+ }
+ else {
+ shi->u= (shi->co[1]-v3[1])*t11-(shi->co[2]-v3[2])*t10;
+ shi->v= (shi->co[2]-v3[2])*t00-(shi->co[1]-v3[1])*t01;
+ if(shi->osatex) {
+ shi->dx_u= shi->dxco[1]*t11- shi->dxco[2]*t10;
+ shi->dx_v= shi->dxco[2]*t00- shi->dxco[1]*t01;
+ shi->dy_u= shi->dyco[1]*t11- shi->dyco[2]*t10;
+ shi->dy_v= shi->dyco[2]*t00- shi->dyco[1]*t01;
+ }
+ }
+ /* u and v are in range -1 to 0, we allow a little bit extra but not too much, screws up speedvectors */
+ CLAMP(shi->u, -2.0f, 1.0f);
+ CLAMP(shi->v, -2.0f, 1.0f);
+ }
+ }
+}
+
+void shade_input_set_normals(ShadeInput *shi)
+{
+ float u= shi->u, v= shi->v;
+ float l= 1.0f+u+v;
+
+ /* calculate vertexnormals */
+ if(shi->vlr->flag & R_SMOOTH) {
+ float *n1= shi->n1, *n2= shi->n2, *n3= shi->n3;
+
+ shi->vn[0]= l*n3[0]-u*n1[0]-v*n2[0];
+ shi->vn[1]= l*n3[1]-u*n1[1]-v*n2[1];
+ shi->vn[2]= l*n3[2]-u*n1[2]-v*n2[2];
+
+ Normalize(shi->vn);
+ }
+ else {
+ VECCOPY(shi->vn, shi->facenor);
+ }
+
+ /* used in nodes */
+ VECCOPY(shi->vno, shi->vn);
+
+}
+
+void shade_input_set_shade_texco(ShadeInput *shi)
+{
+ VertRen *v1= shi->v1, *v2= shi->v2, *v3= shi->v3;
+ float u= shi->u, v= shi->v;
+ float l= 1.0f+u+v, dl;
+ int mode= shi->mode; /* or-ed result for all nodes */
+ short texco= shi->mat->texco;
+
+ /* calculate dxno and tangents */
+ if(shi->vlr->flag & R_SMOOTH) {
+
+ if(shi->osatex && (texco & (TEXCO_NORM|TEXCO_REFL)) ) {
+ float *n1= shi->n1, *n2= shi->n2, *n3= shi->n3;
+
+ dl= shi->dx_u+shi->dx_v;
+ shi->dxno[0]= dl*n3[0]-shi->dx_u*n1[0]-shi->dx_v*n2[0];
+ shi->dxno[1]= dl*n3[1]-shi->dx_u*n1[1]-shi->dx_v*n2[1];
+ shi->dxno[2]= dl*n3[2]-shi->dx_u*n1[2]-shi->dx_v*n2[2];
+ dl= shi->dy_u+shi->dy_v;
+ shi->dyno[0]= dl*n3[0]-shi->dy_u*n1[0]-shi->dy_v*n2[0];
+ shi->dyno[1]= dl*n3[1]-shi->dy_u*n1[1]-shi->dy_v*n2[1];
+ shi->dyno[2]= dl*n3[2]-shi->dy_u*n1[2]-shi->dy_v*n2[2];
+
+ }
+
+ /* qdn: normalmap tangent space */
+ if (mode & (MA_TANGENT_V|MA_NORMAP_TANG)) {
+ float *s1, *s2, *s3;
+
+ s1= RE_vertren_get_tangent(&R, v1, 0);
+ s2= RE_vertren_get_tangent(&R, v2, 0);
+ s3= RE_vertren_get_tangent(&R, v3, 0);
+ if(s1 && s2 && s3) {
+ shi->tang[0]= (l*s3[0] - u*s1[0] - v*s2[0]);
+ shi->tang[1]= (l*s3[1] - u*s1[1] - v*s2[1]);
+ shi->tang[2]= (l*s3[2] - u*s1[2] - v*s2[2]);
+ /* qdn: normalize just in case */
+ Normalize(shi->tang);
+ }
+ else shi->tang[0]= shi->tang[1]= shi->tang[2]= 0.0f;
+ }
+ }
+ else {
+ /* qdn: normalmap tangent space */
+ if (mode & (MA_TANGENT_V|MA_NORMAP_TANG)) {
+ /* qdn: flat faces have tangents too,
+ could pick either one, using average here */
+ float *s1 = RE_vertren_get_tangent(&R, v1, 0);
+ float *s2 = RE_vertren_get_tangent(&R, v2, 0);
+ float *s3 = RE_vertren_get_tangent(&R, v3, 0);
+ if (s1 && s2 && s3) {
+ shi->tang[0] = (s1[0] + s2[0] + s3[0]);
+ shi->tang[1] = (s1[1] + s2[1] + s3[1]);
+ shi->tang[2] = (s1[2] + s2[2] + s3[2]);
+ Normalize(shi->tang);
+ }
+ }
+ }
+
+ if(R.r.mode & R_SPEED) {
+ float *s1, *s2, *s3;
+
+ s1= RE_vertren_get_winspeed(&R, v1, 0);
+ s2= RE_vertren_get_winspeed(&R, v2, 0);
+ s3= RE_vertren_get_winspeed(&R, v3, 0);
+ if(s1 && s2 && s3) {
+ shi->winspeed[0]= (l*s3[0] - u*s1[0] - v*s2[0]);
+ shi->winspeed[1]= (l*s3[1] - u*s1[1] - v*s2[1]);
+ shi->winspeed[2]= (l*s3[2] - u*s1[2] - v*s2[2]);
+ shi->winspeed[3]= (l*s3[3] - u*s1[3] - v*s2[3]);
+ }
+ else {
+ shi->winspeed[0]= shi->winspeed[1]= shi->winspeed[2]= shi->winspeed[3]= 0.0f;
+ }
+ }
+
+ /* pass option forces UV calc */
+ if(shi->passflag & SCE_PASS_UV)
+ texco |= (NEED_UV|TEXCO_UV);
+
+ /* texture coordinates. shi->dxuv shi->dyuv have been set */
+ if(texco & NEED_UV) {
+
+ if(texco & TEXCO_ORCO) {
+ if(v1->orco) {
+ float *o1, *o2, *o3;
+
+ o1= v1->orco;
+ o2= v2->orco;
+ o3= v3->orco;
+
+ shi->lo[0]= l*o3[0]-u*o1[0]-v*o2[0];
+ shi->lo[1]= l*o3[1]-u*o1[1]-v*o2[1];
+ shi->lo[2]= l*o3[2]-u*o1[2]-v*o2[2];
+
+ if(shi->osatex) {
+ dl= shi->dx_u+shi->dx_v;
+ shi->dxlo[0]= dl*o3[0]-shi->dx_u*o1[0]-shi->dx_v*o2[0];
+ shi->dxlo[1]= dl*o3[1]-shi->dx_u*o1[1]-shi->dx_v*o2[1];
+ shi->dxlo[2]= dl*o3[2]-shi->dx_u*o1[2]-shi->dx_v*o2[2];
+ dl= shi->dy_u+shi->dy_v;
+ shi->dylo[0]= dl*o3[0]-shi->dy_u*o1[0]-shi->dy_v*o2[0];
+ shi->dylo[1]= dl*o3[1]-shi->dy_u*o1[1]-shi->dy_v*o2[1];
+ shi->dylo[2]= dl*o3[2]-shi->dy_u*o1[2]-shi->dy_v*o2[2];
+ }
+ }
+ }
+
+ if(texco & TEXCO_GLOB) {
+ VECCOPY(shi->gl, shi->co);
+ MTC_Mat4MulVecfl(R.viewinv, shi->gl);
+ if(shi->osatex) {
+ VECCOPY(shi->dxgl, shi->dxco);
+ MTC_Mat3MulVecfl(R.imat, shi->dxco);
+ VECCOPY(shi->dygl, shi->dyco);
+ MTC_Mat3MulVecfl(R.imat, shi->dyco);
+ }
+ }
+
+ if(texco & TEXCO_STRAND) {
+ shi->strand= (l*v3->accum - u*v1->accum - v*v2->accum);
+ if(shi->osatex) {
+ dl= shi->dx_u+shi->dx_v;
+ shi->dxstrand= dl*v3->accum-shi->dx_u*v1->accum-shi->dx_v*v2->accum;
+ dl= shi->dy_u+shi->dy_v;
+ shi->dystrand= dl*v3->accum-shi->dy_u*v1->accum-shi->dy_v*v2->accum;
+ }
+ }
+
+ if((texco & TEXCO_UV) || (mode & (MA_VERTEXCOL|MA_VERTEXCOLP|MA_FACETEXTURE))) {
+ VlakRen *vlr= shi->vlr;
+ MTFace *tface;
+ MCol *mcol;
+ char *name;
+ int i, j1=shi->i1, j2=shi->i2, j3=shi->i3;
+
+ /* uv and vcols are not copied on split, so set them according vlr divide flag */
+ vlr_set_uv_indices(vlr, &j1, &j2, &j3);
+
+ shi->totuv= 0;
+ shi->totcol= 0;
+
+ if(mode & (MA_VERTEXCOL|MA_VERTEXCOLP)) {
+ for (i=0; (mcol=RE_vlakren_get_mcol(&R, vlr, i, &name, 0)); i++) {
+ ShadeInputCol *scol= &shi->col[i];
+ char *cp1, *cp2, *cp3;
+
+ shi->totcol++;
+ scol->name= name;
+
+ cp1= (char *)(mcol+j1);
+ cp2= (char *)(mcol+j2);
+ cp3= (char *)(mcol+j3);
+
+ scol->col[0]= (l*((float)cp3[3]) - u*((float)cp1[3]) - v*((float)cp2[3]))/255.0f;
+ scol->col[1]= (l*((float)cp3[2]) - u*((float)cp1[2]) - v*((float)cp2[2]))/255.0f;
+ scol->col[2]= (l*((float)cp3[1]) - u*((float)cp1[1]) - v*((float)cp2[1]))/255.0f;
+ }
+
+ if(shi->totcol) {
+ shi->vcol[0]= shi->col[0].col[0];
+ shi->vcol[1]= shi->col[0].col[1];
+ shi->vcol[2]= shi->col[0].col[2];
+ }
+ else {
+ shi->vcol[0]= 0.0f;
+ shi->vcol[1]= 0.0f;
+ shi->vcol[2]= 0.0f;
+ }
+ }
+
+ for (i=0; (tface=RE_vlakren_get_tface(&R, vlr, i, &name, 0)); i++) {
+ ShadeInputUV *suv= &shi->uv[i];
+ float *uv1, *uv2, *uv3;
+
+ shi->totuv++;
+ suv->name= name;
+
+ uv1= tface->uv[j1];
+ uv2= tface->uv[j2];
+ uv3= tface->uv[j3];
+
+ suv->uv[0]= -1.0f + 2.0f*(l*uv3[0]-u*uv1[0]-v*uv2[0]);
+ suv->uv[1]= -1.0f + 2.0f*(l*uv3[1]-u*uv1[1]-v*uv2[1]);
+ suv->uv[2]= 0.0f; /* texture.c assumes there are 3 coords */
+
+ if(shi->osatex) {
+ float duv[2];
+
+ dl= shi->dx_u+shi->dx_v;
+ duv[0]= shi->dx_u;
+ duv[1]= shi->dx_v;
+
+ suv->dxuv[0]= 2.0f*(dl*uv3[0]-duv[0]*uv1[0]-duv[1]*uv2[0]);
+ suv->dxuv[1]= 2.0f*(dl*uv3[1]-duv[0]*uv1[1]-duv[1]*uv2[1]);
+
+ dl= shi->dy_u+shi->dy_v;
+ duv[0]= shi->dy_u;
+ duv[1]= shi->dy_v;
+
+ suv->dyuv[0]= 2.0f*(dl*uv3[0]-duv[0]*uv1[0]-duv[1]*uv2[0]);
+ suv->dyuv[1]= 2.0f*(dl*uv3[1]-duv[0]*uv1[1]-duv[1]*uv2[1]);
+ }
+
+ if((mode & MA_FACETEXTURE) && i==0) {
+ if((mode & (MA_VERTEXCOL|MA_VERTEXCOLP))==0) {
+ shi->vcol[0]= 1.0f;
+ shi->vcol[1]= 1.0f;
+ shi->vcol[2]= 1.0f;
+ }
+ if(tface && tface->tpage)
+ render_realtime_texture(shi, tface->tpage);
+ }
+ }
+
+ if(shi->totuv == 0) {
+ ShadeInputUV *suv= &shi->uv[0];
+
+ suv->uv[0]= 2.0f*(u+.5f);
+ suv->uv[1]= 2.0f*(v+.5f);
+ suv->uv[2]= 0.0f; /* texture.c assumes there are 3 coords */
+
+ if(mode & MA_FACETEXTURE) {
+ /* no tface? set at 1.0f */
+ shi->vcol[0]= 1.0f;
+ shi->vcol[1]= 1.0f;
+ shi->vcol[2]= 1.0f;
+ }
+ }
+ }
+
+ if(texco & TEXCO_NORM) {
+ shi->orn[0]= -shi->vn[0];
+ shi->orn[1]= -shi->vn[1];
+ shi->orn[2]= -shi->vn[2];
+ }
+
+ if(mode & MA_RADIO) {
+ float *r1, *r2, *r3;
+
+ r1= RE_vertren_get_rad(&R, v1, 0);
+ r2= RE_vertren_get_rad(&R, v2, 0);
+ r3= RE_vertren_get_rad(&R, v3, 0);
+
+ if(r1 && r2 && r3) {
+ shi->rad[0]= (l*r3[0] - u*r1[0] - v*r2[0]);
+ shi->rad[1]= (l*r3[1] - u*r1[1] - v*r2[1]);
+ shi->rad[2]= (l*r3[2] - u*r1[2] - v*r2[2]);
+ }
+ else {
+ shi->rad[0]= shi->rad[1]= shi->rad[2]= 0.0f;
+ }
+ }
+ else {
+ shi->rad[0]= shi->rad[1]= shi->rad[2]= 0.0f;
+ }
+
+ if(texco & TEXCO_REFL) {
+ /* mirror reflection color textures (and envmap) */
+ calc_R_ref(shi); /* wrong location for normal maps! XXXXXXXXXXXXXX */
+ }
+
+ if(texco & TEXCO_STRESS) {
+ float *s1, *s2, *s3;
+
+ s1= RE_vertren_get_stress(&R, v1, 0);
+ s2= RE_vertren_get_stress(&R, v2, 0);
+ s3= RE_vertren_get_stress(&R, v3, 0);
+ if(s1 && s2 && s3) {
+ shi->stress= l*s3[0] - u*s1[0] - v*s2[0];
+ if(shi->stress<1.0f) shi->stress-= 1.0f;
+ else shi->stress= (shi->stress-1.0f)/shi->stress;
+ }
+ else shi->stress= 0.0f;
+ }
+
+ if(texco & TEXCO_TANGENT) {
+ if((mode & MA_TANGENT_V)==0) {
+ /* just prevent surprises */
+ shi->tang[0]= shi->tang[1]= shi->tang[2]= 0.0f;
+ }
+ }
+ }
+ else {
+ shi->rad[0]= shi->rad[1]= shi->rad[2]= 0.0f;
+ }
+
+ /* this only avalailable for scanline renders */
+ if(shi->depth==0) {
+ float x= shi->xs;
+ float y= shi->ys;
+
+ if(texco & TEXCO_WINDOW) {
+ shi->winco[0]= -1.0f + 2.0f*x/(float)R.winx;
+ shi->winco[1]= -1.0f + 2.0f*y/(float)R.winy;
+ shi->winco[2]= 0.0f;
+ if(shi->osatex) {
+ shi->dxwin[0]= 2.0f/(float)R.winx;
+ shi->dywin[1]= 2.0f/(float)R.winy;
+ shi->dxwin[1]= shi->dxwin[2]= 0.0f;
+ shi->dywin[0]= shi->dywin[2]= 0.0f;
+ }
+ }
+
+ if(texco & TEXCO_STICKY) {
+ float *s1, *s2, *s3;
+
+ s1= RE_vertren_get_sticky(&R, v1, 0);
+ s2= RE_vertren_get_sticky(&R, v2, 0);
+ s3= RE_vertren_get_sticky(&R, v3, 0);
+
+ if(s1 && s2 && s3) {
+ float Zmulx, Zmuly;
+ float hox, hoy, l, dl, u, v;
+ float s00, s01, s10, s11, detsh;
+
+ /* old globals, localized now */
+ Zmulx= ((float)R.winx)/2.0f; Zmuly= ((float)R.winy)/2.0f;
+
+ s00= v3->ho[0]/v3->ho[3] - v1->ho[0]/v1->ho[3];
+ s01= v3->ho[1]/v3->ho[3] - v1->ho[1]/v1->ho[3];
+ s10= v3->ho[0]/v3->ho[3] - v2->ho[0]/v2->ho[3];
+ s11= v3->ho[1]/v3->ho[3] - v2->ho[1]/v2->ho[3];
+
+ detsh= s00*s11-s10*s01;
+ s00/= detsh; s01/=detsh;
+ s10/=detsh; s11/=detsh;
+
+ /* recalc u and v again */
+ hox= x/Zmulx -1.0f;
+ hoy= y/Zmuly -1.0f;
+ u= (hox - v3->ho[0]/v3->ho[3])*s11 - (hoy - v3->ho[1]/v3->ho[3])*s10;
+ v= (hoy - v3->ho[1]/v3->ho[3])*s00 - (hox - v3->ho[0]/v3->ho[3])*s01;
+ l= 1.0f+u+v;
+
+ shi->sticky[0]= l*s3[0]-u*s1[0]-v*s2[0];
+ shi->sticky[1]= l*s3[1]-u*s1[1]-v*s2[1];
+ shi->sticky[2]= 0.0f;
+
+ if(shi->osatex) {
+ float dxuv[2], dyuv[2];
+ dxuv[0]= s11/Zmulx;
+ dxuv[1]= - s01/Zmulx;
+ dyuv[0]= - s10/Zmuly;
+ dyuv[1]= s00/Zmuly;
+
+ dl= dxuv[0] + dxuv[1];
+ shi->dxsticky[0]= dl*s3[0] - dxuv[0]*s1[0] - dxuv[1]*s2[0];
+ shi->dxsticky[1]= dl*s3[1] - dxuv[0]*s1[1] - dxuv[1]*s2[1];
+ dl= dyuv[0] + dyuv[1];
+ shi->dysticky[0]= dl*s3[0] - dyuv[0]*s1[0] - dyuv[1]*s2[0];
+ shi->dysticky[1]= dl*s3[1] - dyuv[0]*s1[1] - dyuv[1]*s2[1];
+ }
+ }
+ }
+ }
+}
+
+/* ****************** ShadeSample ************************************** */
+
+/* initialize per part, not per pixel! */
+void shade_input_initialize(ShadeInput *shi, RenderPart *pa, RenderLayer *rl, int sample)
+{
+
+ memset(shi, 0, sizeof(ShadeInput));
+
+ shi->sample= sample;
+ shi->thread= pa->thread;
+ shi->do_preview= R.r.scemode & R_NODE_PREVIEW;
+ shi->lay= rl->lay;
+ shi->layflag= rl->layflag;
+ shi->passflag= rl->passflag;
+ shi->combinedflag= ~rl->pass_xor;
+ shi->mat_override= rl->mat_override;
+ shi->light_override= rl->light_override;
+
+ /* note shi.depth==0 means first hit, not raytracing */
+}
+
+/* initialize per part, not per pixel! */
+void shade_sample_initialize(ShadeSample *ssamp, RenderPart *pa, RenderLayer *rl)
+{
+ int a, tot;
+
+ tot= R.osa==0?1:R.osa;
+
+ for(a=0; a<tot; a++) {
+ shade_input_initialize(&ssamp->shi[a], pa, rl, a);
+ memset(&ssamp->shr[a], 0, sizeof(ShadeResult));
+ }
+
+ ssamp->samplenr= 0; /* counter, detect shadow-reuse for shaders */
+}
+
+/* Do AO or (future) GI */
+void shade_samples_do_AO(ShadeSample *ssamp)
+{
+ ShadeInput *shi;
+ int sample;
+
+ if(!(R.r.mode & R_SHADOW))
+ return;
+ if(!(R.r.mode & R_RAYTRACE))
+ return;
+
+ if(R.wrld.mode & WO_AMB_OCC)
+ if(ssamp->shi[0].passflag & (SCE_PASS_COMBINED|SCE_PASS_AO))
+ for(sample=0, shi= ssamp->shi; sample<ssamp->tot; shi++, sample++)
+ if(!(shi->mode & MA_SHLESS))
+ ambient_occlusion(shi); /* stores in shi->ao[] */
+
+}
+
+
+static void shade_samples_fill_with_ps(ShadeSample *ssamp, PixStr *ps, int x, int y)
+{
+ ShadeInput *shi;
+ float xs, ys;
+
+ ssamp->tot= 0;
+
+ for(shi= ssamp->shi; ps; ps= ps->next) {
+ shade_input_set_triangle(shi, ps->facenr, 1);
+
+ if(shi->vlr) { /* NULL happens for env material or for 'all z' */
+ unsigned short curmask= ps->mask;
+
+ /* full osa is only set for OSA renders */
+ if(shi->vlr->flag & R_FULL_OSA) {
+ short shi_cp= 0, samp;
+
+ for(samp=0; samp<R.osa; samp++) {
+ if(curmask & (1<<samp)) {
+ xs= (float)x + R.jit[samp][0] + 0.5f; /* zbuffer has this inverse corrected, ensures xs,ys are inside pixel */
+ ys= (float)y + R.jit[samp][1] + 0.5f;
+
+ if(shi_cp)
+ shade_input_copy_triangle(shi, shi-1);
+
+ shi->mask= (1<<samp);
+ shi->samplenr= ssamp->samplenr++;
+ shade_input_set_viewco(shi, xs, ys, (float)ps->z);
+ shade_input_set_uv(shi);
+ shade_input_set_normals(shi);
+
+ shi_cp= 1;
+ shi++;
+ }
+ }
+ }
+ else {
+ if(R.osa) {
+ short b= R.samples->centmask[curmask];
+ xs= (float)x + R.samples->centLut[b & 15] + 0.5f;
+ ys= (float)y + R.samples->centLut[b>>4] + 0.5f;
+ }
+ else {
+ xs= (float)x + 0.5f;
+ ys= (float)y + 0.5f;
+ }
+ shi->mask= curmask;
+ shi->samplenr= ssamp->samplenr++;
+ shade_input_set_viewco(shi, xs, ys, (float)ps->z);
+ shade_input_set_uv(shi);
+ shade_input_set_normals(shi);
+ shi++;
+ }
+
+ /* total sample amount, shi->sample is static set in initialize */
+ if(shi!=ssamp->shi)
+ ssamp->tot= (shi-1)->sample + 1;
+ }
+ }
+}
+
+/* shades samples, returns true if anything happened */
+int shade_samples(ShadeSample *ssamp, PixStr *ps, int x, int y)
+{
+ shade_samples_fill_with_ps(ssamp, ps, x, y);
+
+ if(ssamp->tot) {
+ ShadeInput *shi= ssamp->shi;
+ ShadeResult *shr= ssamp->shr;
+ int samp;
+
+ /* if shadow or AO? */
+ shade_samples_do_AO(ssamp);
+
+ /* if shade (all shadepinputs have same passflag) */
+ if(ssamp->shi[0].passflag & ~(SCE_PASS_Z|SCE_PASS_INDEXOB)) {
+
+ for(samp=0; samp<ssamp->tot; samp++, shi++, shr++) {
+ shade_input_set_shade_texco(shi);
+ shade_input_do_shade(shi, shr);
+ }
+ }
+
+ return 1;
+ }
+ return 0;
+}
+
diff --git a/source/blender/render/intern/source/shadeoutput.c b/source/blender/render/intern/source/shadeoutput.c
new file mode 100644
index 00000000000..f50028e4c83
--- /dev/null
+++ b/source/blender/render/intern/source/shadeoutput.c
@@ -0,0 +1,1653 @@
+/**
+* $Id:
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation
+ * All rights reserved.
+ *
+ * Contributors: Hos, Robert Wenzlaff.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+
+#include "MTC_matrixops.h"
+#include "BLI_arithb.h"
+
+#include "BKE_colortools.h"
+#include "BKE_material.h"
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
+
+#include "DNA_group_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_material_types.h"
+
+/* local include */
+#include "renderpipeline.h"
+#include "render_types.h"
+#include "pixelblending.h"
+#include "rendercore.h"
+#include "shadbuf.h"
+#include "sss.h"
+#include "texture.h"
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
+/* only to be used here in this file, it's for speed */
+extern struct Render R;
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+static ListBase *get_lights(ShadeInput *shi)
+{
+
+ if(shi->light_override)
+ return &shi->light_override->gobject;
+ else if(shi->mat && shi->mat->group)
+ return &shi->mat->group->gobject;
+ else
+ return &R.lights;
+}
+
+#if 0
+static void fogcolor(float *colf, float *rco, float *view)
+{
+ float alpha, stepsize, startdist, dist, hor[4], zen[3], vec[3], dview[3];
+ float div=0.0f, distfac;
+
+ hor[0]= R.wrld.horr; hor[1]= R.wrld.horg; hor[2]= R.wrld.horb;
+ zen[0]= R.wrld.zenr; zen[1]= R.wrld.zeng; zen[2]= R.wrld.zenb;
+
+ VECCOPY(vec, rco);
+
+ /* we loop from cur coord to mist start in steps */
+ stepsize= 1.0f;
+
+ div= ABS(view[2]);
+ dview[0]= view[0]/(stepsize*div);
+ dview[1]= view[1]/(stepsize*div);
+ dview[2]= -stepsize;
+
+ startdist= -rco[2] + BLI_frand();
+ for(dist= startdist; dist>R.wrld.miststa; dist-= stepsize) {
+
+ hor[0]= R.wrld.horr; hor[1]= R.wrld.horg; hor[2]= R.wrld.horb;
+ alpha= 1.0f;
+ do_sky_tex(vec, vec, NULL, hor, zen, &alpha);
+
+ distfac= (dist-R.wrld.miststa)/R.wrld.mistdist;
+
+ hor[3]= hor[0]*distfac*distfac;
+
+ /* premul! */
+ alpha= hor[3];
+ hor[0]= hor[0]*alpha;
+ hor[1]= hor[1]*alpha;
+ hor[2]= hor[2]*alpha;
+ addAlphaOverFloat(colf, hor);
+
+ VECSUB(vec, vec, dview);
+ }
+}
+#endif
+
+/* zcor is distance, co the 3d coordinate in eye space, return alpha */
+float mistfactor(float zcor, float *co)
+{
+ float fac, hi;
+
+ fac= zcor - R.wrld.miststa; /* zcor is calculated per pixel */
+
+ /* fac= -co[2]-R.wrld.miststa; */
+
+ if(fac>0.0f) {
+ if(fac< R.wrld.mistdist) {
+
+ fac= (fac/(R.wrld.mistdist));
+
+ if(R.wrld.mistype==0) fac*= fac;
+ else if(R.wrld.mistype==1);
+ else fac= sqrt(fac);
+ }
+ else fac= 1.0f;
+ }
+ else fac= 0.0f;
+
+ /* height switched off mist */
+ if(R.wrld.misthi!=0.0f && fac!=0.0f) {
+ /* at height misthi the mist is completely gone */
+
+ hi= R.viewinv[0][2]*co[0]+R.viewinv[1][2]*co[1]+R.viewinv[2][2]*co[2]+R.viewinv[3][2];
+
+ if(hi>R.wrld.misthi) fac= 0.0f;
+ else if(hi>0.0f) {
+ hi= (R.wrld.misthi-hi)/R.wrld.misthi;
+ fac*= hi*hi;
+ }
+ }
+
+ return (1.0f-fac)* (1.0f-R.wrld.misi);
+}
+
+static void spothalo(struct LampRen *lar, ShadeInput *shi, float *intens)
+{
+ double a, b, c, disc, nray[3], npos[3];
+ float t0, t1 = 0.0f, t2= 0.0f, t3, haint;
+ float p1[3], p2[3], ladist, maxz = 0.0f, maxy = 0.0f;
+ int snijp, doclip=1, use_yco=0;
+ int ok1=0, ok2=0;
+
+ *intens= 0.0f;
+ haint= lar->haint;
+
+ if(R.r.mode & R_ORTHO) {
+ /* camera pos (view vector) cannot be used... */
+ /* camera position (cox,coy,0) rotate around lamp */
+ p1[0]= shi->co[0]-lar->co[0];
+ p1[1]= shi->co[1]-lar->co[1];
+ p1[2]= -lar->co[2];
+ MTC_Mat3MulVecfl(lar->imat, p1);
+ VECCOPY(npos, p1); // npos is double!
+ }
+ else {
+ VECCOPY(npos, lar->sh_invcampos); /* in initlamp calculated */
+ }
+
+ /* rotate view */
+ VECCOPY(nray, shi->view);
+ MTC_Mat3MulVecd(lar->imat, nray);
+
+ if(R.wrld.mode & WO_MIST) {
+ /* patchy... */
+ haint *= mistfactor(-lar->co[2], lar->co);
+ if(haint==0.0f) {
+ return;
+ }
+ }
+
+
+ /* rotate maxz */
+ if(shi->co[2]==0.0f) doclip= 0; /* for when halo at sky */
+ else {
+ p1[0]= shi->co[0]-lar->co[0];
+ p1[1]= shi->co[1]-lar->co[1];
+ p1[2]= shi->co[2]-lar->co[2];
+
+ maxz= lar->imat[0][2]*p1[0]+lar->imat[1][2]*p1[1]+lar->imat[2][2]*p1[2];
+ maxz*= lar->sh_zfac;
+ maxy= lar->imat[0][1]*p1[0]+lar->imat[1][1]*p1[1]+lar->imat[2][1]*p1[2];
+
+ if( fabs(nray[2]) <0.000001f ) use_yco= 1;
+ }
+
+ /* scale z to make sure volume is normalized */
+ nray[2]*= lar->sh_zfac;
+ /* nray does not need normalization */
+
+ ladist= lar->sh_zfac*lar->dist;
+
+ /* solve */
+ a = nray[0] * nray[0] + nray[1] * nray[1] - nray[2]*nray[2];
+ b = nray[0] * npos[0] + nray[1] * npos[1] - nray[2]*npos[2];
+ c = npos[0] * npos[0] + npos[1] * npos[1] - npos[2]*npos[2];
+
+ snijp= 0;
+ if (fabs(a) < 0.00000001) {
+ /*
+ * Only one intersection point...
+ */
+ return;
+ }
+ else {
+ disc = b*b - a*c;
+
+ if(disc==0.0) {
+ t1=t2= (-b)/ a;
+ snijp= 2;
+ }
+ else if (disc > 0.0) {
+ disc = sqrt(disc);
+ t1 = (-b + disc) / a;
+ t2 = (-b - disc) / a;
+ snijp= 2;
+ }
+ }
+ if(snijp==2) {
+ /* sort */
+ if(t1>t2) {
+ a= t1; t1= t2; t2= a;
+ }
+
+ /* z of intersection points with diabolo */
+ p1[2]= npos[2] + t1*nray[2];
+ p2[2]= npos[2] + t2*nray[2];
+
+ /* evaluate both points */
+ if(p1[2]<=0.0f) ok1= 1;
+ if(p2[2]<=0.0f && t1!=t2) ok2= 1;
+
+ /* at least 1 point with negative z */
+ if(ok1==0 && ok2==0) return;
+
+ /* intersction point with -ladist, the bottom of the cone */
+ if(use_yco==0) {
+ t3= (-ladist-npos[2])/nray[2];
+
+ /* de we have to replace one of the intersection points? */
+ if(ok1) {
+ if(p1[2]<-ladist) t1= t3;
+ }
+ else {
+ ok1= 1;
+ t1= t3;
+ }
+ if(ok2) {
+ if(p2[2]<-ladist) t2= t3;
+ }
+ else {
+ ok2= 1;
+ t2= t3;
+ }
+ }
+ else if(ok1==0 || ok2==0) return;
+
+ /* at least 1 visible interesction point */
+ if(t1<0.0f && t2<0.0f) return;
+
+ if(t1<0.0f) t1= 0.0f;
+ if(t2<0.0f) t2= 0.0f;
+
+ if(t1==t2) return;
+
+ /* sort again to be sure */
+ if(t1>t2) {
+ a= t1; t1= t2; t2= a;
+ }
+
+ /* calculate t0: is the maximum visible z (when halo is intersected by face) */
+ if(doclip) {
+ if(use_yco==0) t0= (maxz-npos[2])/nray[2];
+ else t0= (maxy-npos[1])/nray[1];
+
+ if(t0<t1) return;
+ if(t0<t2) t2= t0;
+ }
+
+ /* calc points */
+ p1[0]= npos[0] + t1*nray[0];
+ p1[1]= npos[1] + t1*nray[1];
+ p1[2]= npos[2] + t1*nray[2];
+ p2[0]= npos[0] + t2*nray[0];
+ p2[1]= npos[1] + t2*nray[1];
+ p2[2]= npos[2] + t2*nray[2];
+
+
+ /* now we have 2 points, make three lengths with it */
+
+ a= sqrt(p1[0]*p1[0]+p1[1]*p1[1]+p1[2]*p1[2]);
+ b= sqrt(p2[0]*p2[0]+p2[1]*p2[1]+p2[2]*p2[2]);
+ c= VecLenf(p1, p2);
+
+ a/= ladist;
+ a= sqrt(a);
+ b/= ladist;
+ b= sqrt(b);
+ c/= ladist;
+
+ *intens= c*( (1.0-a)+(1.0-b) );
+
+ /* WATCH IT: do not clip a,b en c at 1.0, this gives nasty little overflows
+ at the edges (especially with narrow halos) */
+ if(*intens<=0.0f) return;
+
+ /* soft area */
+ /* not needed because t0 has been used for p1/p2 as well */
+ /* if(doclip && t0<t2) { */
+ /* *intens *= (t0-t1)/(t2-t1); */
+ /* } */
+
+ *intens *= haint;
+
+ if(lar->shb && lar->shb->shadhalostep) {
+ *intens *= shadow_halo(lar, p1, p2);
+ }
+
+ }
+}
+
+void renderspothalo(ShadeInput *shi, float *col, float alpha)
+{
+ ListBase *lights;
+ GroupObject *go;
+ LampRen *lar;
+ float i;
+
+ if(alpha==0.0f) return;
+
+ lights= get_lights(shi);
+ for(go=lights->first; go; go= go->next) {
+ lar= go->lampren;
+ if(lar==NULL) continue;
+
+ if(lar->type==LA_SPOT && (lar->mode & LA_HALO) && lar->haint>0) {
+
+ if(lar->mode & LA_LAYER)
+ if(shi->vlr && (lar->lay & shi->vlr->lay)==0)
+ continue;
+ if((lar->lay & shi->lay)==0)
+ continue;
+
+ spothalo(lar, shi, &i);
+ if(i>0.0f) {
+ col[3]+= i*alpha; // all premul
+ col[0]+= i*lar->r*alpha;
+ col[1]+= i*lar->g*alpha;
+ col[2]+= i*lar->b*alpha;
+ }
+ }
+ }
+ /* clip alpha, is needed for unified 'alpha threshold' (vanillaRenderPipe.c) */
+ if(col[3]>1.0f) col[3]= 1.0f;
+}
+
+
+
+/* ---------------- shaders ----------------------- */
+
+static double Normalize_d(double *n)
+{
+ double d;
+
+ d= n[0]*n[0]+n[1]*n[1]+n[2]*n[2];
+
+ if(d>0.00000000000000001) {
+ d= sqrt(d);
+
+ n[0]/=d;
+ n[1]/=d;
+ n[2]/=d;
+ } else {
+ n[0]=n[1]=n[2]= 0.0;
+ d= 0.0;
+ }
+ return d;
+}
+
+/* mix of 'real' fresnel and allowing control. grad defines blending gradient */
+float fresnel_fac(float *view, float *vn, float grad, float fac)
+{
+ float t1, t2;
+
+ if(fac==0.0f) return 1.0f;
+
+ t1= (view[0]*vn[0] + view[1]*vn[1] + view[2]*vn[2]);
+ if(t1>0.0f) t2= 1.0f+t1;
+ else t2= 1.0f-t1;
+
+ t2= grad + (1.0f-grad)*pow(t2, fac);
+
+ if(t2<0.0f) return 0.0f;
+ else if(t2>1.0f) return 1.0f;
+ return t2;
+}
+
+static double saacos_d(double fac)
+{
+ if(fac<= -1.0f) return M_PI;
+ else if(fac>=1.0f) return 0.0;
+ else return acos(fac);
+}
+
+/* Stoke's form factor. Need doubles here for extreme small area sizes */
+static float area_lamp_energy(float *co, float *vn, LampRen *lar)
+{
+ double fac;
+ double vec[4][3]; /* vectors of rendered co to vertices lamp */
+ double cross[4][3]; /* cross products of this */
+ double rad[4]; /* angles between vecs */
+
+ VECSUB(vec[0], co, lar->area[0]);
+ VECSUB(vec[1], co, lar->area[1]);
+ VECSUB(vec[2], co, lar->area[2]);
+ VECSUB(vec[3], co, lar->area[3]);
+
+ Normalize_d(vec[0]);
+ Normalize_d(vec[1]);
+ Normalize_d(vec[2]);
+ Normalize_d(vec[3]);
+
+ /* cross product */
+ CROSS(cross[0], vec[0], vec[1]);
+ CROSS(cross[1], vec[1], vec[2]);
+ CROSS(cross[2], vec[2], vec[3]);
+ CROSS(cross[3], vec[3], vec[0]);
+
+ Normalize_d(cross[0]);
+ Normalize_d(cross[1]);
+ Normalize_d(cross[2]);
+ Normalize_d(cross[3]);
+
+ /* angles */
+ rad[0]= vec[0][0]*vec[1][0]+ vec[0][1]*vec[1][1]+ vec[0][2]*vec[1][2];
+ rad[1]= vec[1][0]*vec[2][0]+ vec[1][1]*vec[2][1]+ vec[1][2]*vec[2][2];
+ rad[2]= vec[2][0]*vec[3][0]+ vec[2][1]*vec[3][1]+ vec[2][2]*vec[3][2];
+ rad[3]= vec[3][0]*vec[0][0]+ vec[3][1]*vec[0][1]+ vec[3][2]*vec[0][2];
+
+ rad[0]= saacos_d(rad[0]);
+ rad[1]= saacos_d(rad[1]);
+ rad[2]= saacos_d(rad[2]);
+ rad[3]= saacos_d(rad[3]);
+
+ /* Stoke formula */
+ fac= rad[0]*(vn[0]*cross[0][0]+ vn[1]*cross[0][1]+ vn[2]*cross[0][2]);
+ fac+= rad[1]*(vn[0]*cross[1][0]+ vn[1]*cross[1][1]+ vn[2]*cross[1][2]);
+ fac+= rad[2]*(vn[0]*cross[2][0]+ vn[1]*cross[2][1]+ vn[2]*cross[2][2]);
+ fac+= rad[3]*(vn[0]*cross[3][0]+ vn[1]*cross[3][1]+ vn[2]*cross[3][2]);
+
+ if(fac<=0.0) return 0.0;
+ return pow(fac*lar->areasize, lar->k); // corrected for buttons size and lar->dist^2
+}
+
+static float spec(float inp, int hard)
+{
+ float b1;
+
+ if(inp>=1.0f) return 1.0f;
+ else if (inp<=0.0f) return 0.0f;
+
+ b1= inp*inp;
+ /* avoid FPE */
+ if(b1<0.01f) b1= 0.01f;
+
+ if((hard & 1)==0) inp= 1.0f;
+ if(hard & 2) inp*= b1;
+ b1*= b1;
+ if(hard & 4) inp*= b1;
+ b1*= b1;
+ if(hard & 8) inp*= b1;
+ b1*= b1;
+ if(hard & 16) inp*= b1;
+ b1*= b1;
+
+ /* avoid FPE */
+ if(b1<0.001f) b1= 0.0f;
+
+ if(hard & 32) inp*= b1;
+ b1*= b1;
+ if(hard & 64) inp*=b1;
+ b1*= b1;
+ if(hard & 128) inp*=b1;
+
+ if(b1<0.001f) b1= 0.0f;
+
+ if(hard & 256) {
+ b1*= b1;
+ inp*=b1;
+ }
+
+ return inp;
+}
+
+static float Phong_Spec( float *n, float *l, float *v, int hard, int tangent )
+{
+ float h[3];
+ float rslt;
+
+ h[0] = l[0] + v[0];
+ h[1] = l[1] + v[1];
+ h[2] = l[2] + v[2];
+ Normalize(h);
+
+ rslt = h[0]*n[0] + h[1]*n[1] + h[2]*n[2];
+ if(tangent) rslt= sasqrt(1.0f - rslt*rslt);
+
+ if( rslt > 0.0f ) rslt= spec(rslt, hard);
+ else rslt = 0.0f;
+
+ return rslt;
+}
+
+
+/* reduced cook torrance spec (for off-specular peak) */
+static float CookTorr_Spec(float *n, float *l, float *v, int hard, int tangent)
+{
+ float i, nh, nv, h[3];
+
+ h[0]= v[0]+l[0];
+ h[1]= v[1]+l[1];
+ h[2]= v[2]+l[2];
+ Normalize(h);
+
+ nh= n[0]*h[0]+n[1]*h[1]+n[2]*h[2];
+ if(tangent) nh= sasqrt(1.0f - nh*nh);
+ else if(nh<0.0f) return 0.0f;
+
+ nv= n[0]*v[0]+n[1]*v[1]+n[2]*v[2];
+ if(tangent) nv= sasqrt(1.0f - nv*nv);
+ else if(nv<0.0f) nv= 0.0f;
+
+ i= spec(nh, hard);
+
+ i= i/(0.1+nv);
+ return i;
+}
+
+/* Blinn spec */
+static float Blinn_Spec(float *n, float *l, float *v, float refrac, float spec_power, int tangent)
+{
+ float i, nh, nv, nl, vh, h[3];
+ float a, b, c, g=0.0f, p, f, ang;
+
+ if(refrac < 1.0f) return 0.0f;
+ if(spec_power == 0.0f) return 0.0f;
+
+ /* conversion from 'hardness' (1-255) to 'spec_power' (50 maps at 0.1) */
+ if(spec_power<100.0f)
+ spec_power= sqrt(1.0f/spec_power);
+ else spec_power= 10.0f/spec_power;
+
+ h[0]= v[0]+l[0];
+ h[1]= v[1]+l[1];
+ h[2]= v[2]+l[2];
+ Normalize(h);
+
+ nh= n[0]*h[0]+n[1]*h[1]+n[2]*h[2]; /* Dot product between surface normal and half-way vector */
+ if(tangent) nh= sasqrt(1.0f - nh*nh);
+ else if(nh<0.0f) return 0.0f;
+
+ nv= n[0]*v[0]+n[1]*v[1]+n[2]*v[2]; /* Dot product between surface normal and view vector */
+ if(tangent) nv= sasqrt(1.0f - nv*nv);
+ if(nv<=0.01f) nv= 0.01f; /* hrms... */
+
+ nl= n[0]*l[0]+n[1]*l[1]+n[2]*l[2]; /* Dot product between surface normal and light vector */
+ if(tangent) nl= sasqrt(1.0f - nl*nl);
+ if(nl<=0.01f) {
+ return 0.0f;
+ }
+
+ vh= v[0]*h[0]+v[1]*h[1]+v[2]*h[2]; /* Dot product between view vector and half-way vector */
+ if(vh<=0.0f) vh= 0.01f;
+
+ a = 1.0f;
+ b = (2.0f*nh*nv)/vh;
+ c = (2.0f*nh*nl)/vh;
+
+ if( a < b && a < c ) g = a;
+ else if( b < a && b < c ) g = b;
+ else if( c < a && c < b ) g = c;
+
+ p = sqrt( (double)((refrac * refrac)+(vh*vh)-1.0f) );
+ f = (((p-vh)*(p-vh))/((p+vh)*(p+vh)))*(1+((((vh*(p+vh))-1.0f)*((vh*(p+vh))-1.0f))/(((vh*(p-vh))+1.0f)*((vh*(p-vh))+1.0f))));
+ ang = saacos(nh);
+
+ i= f * g * exp((double)(-(ang*ang) / (2.0f*spec_power*spec_power)));
+ if(i<0.0f) i= 0.0f;
+
+ return i;
+}
+
+/* cartoon render spec */
+static float Toon_Spec( float *n, float *l, float *v, float size, float smooth, int tangent)
+{
+ float h[3];
+ float ang;
+ float rslt;
+
+ h[0] = l[0] + v[0];
+ h[1] = l[1] + v[1];
+ h[2] = l[2] + v[2];
+ Normalize(h);
+
+ rslt = h[0]*n[0] + h[1]*n[1] + h[2]*n[2];
+ if(tangent) rslt = sasqrt(1.0f - rslt*rslt);
+
+ ang = saacos( rslt );
+
+ if( ang < size ) rslt = 1.0f;
+ else if( ang >= (size + smooth) || smooth == 0.0f ) rslt = 0.0f;
+ else rslt = 1.0f - ((ang - size) / smooth);
+
+ return rslt;
+}
+
+/* Ward isotropic gaussian spec */
+static float WardIso_Spec( float *n, float *l, float *v, float rms, int tangent)
+{
+ float i, nh, nv, nl, h[3], angle, alpha;
+
+
+ /* half-way vector */
+ h[0] = l[0] + v[0];
+ h[1] = l[1] + v[1];
+ h[2] = l[2] + v[2];
+ Normalize(h);
+
+ nh = n[0]*h[0]+n[1]*h[1]+n[2]*h[2]; /* Dot product between surface normal and half-way vector */
+ if(tangent) nh = sasqrt(1.0f - nh*nh);
+ if(nh<=0.0f) nh = 0.001f;
+
+ nv = n[0]*v[0]+n[1]*v[1]+n[2]*v[2]; /* Dot product between surface normal and view vector */
+ if(tangent) nv = sasqrt(1.0f - nv*nv);
+ if(nv<=0.0f) nv = 0.001f;
+
+ nl = n[0]*l[0]+n[1]*l[1]+n[2]*l[2]; /* Dot product between surface normal and light vector */
+ if(tangent) nl = sasqrt(1.0f - nl*nl);
+ if(nl<=0.0f) nl = 0.001f;
+
+ angle = tan(saacos(nh));
+ alpha = MAX2(rms, 0.001f);
+
+ i= nl * (1.0f/(4.0f*M_PI*alpha*alpha)) * (exp( -(angle*angle)/(alpha*alpha))/(sqrt(nv*nl)));
+
+ return i;
+}
+
+/* cartoon render diffuse */
+static float Toon_Diff( float *n, float *l, float *v, float size, float smooth )
+{
+ float rslt, ang;
+
+ rslt = n[0]*l[0] + n[1]*l[1] + n[2]*l[2];
+
+ ang = saacos( (double)(rslt) );
+
+ if( ang < size ) rslt = 1.0f;
+ else if( ang >= (size + smooth) || smooth == 0.0f ) rslt = 0.0f;
+ else rslt = 1.0f - ((ang - size) / smooth);
+
+ return rslt;
+}
+
+/* Oren Nayar diffuse */
+
+/* 'nl' is either dot product, or return value of area light */
+/* in latter case, only last multiplication uses 'nl' */
+static float OrenNayar_Diff(float nl, float *n, float *l, float *v, float rough )
+{
+ float i, nh, nv, vh, realnl, h[3];
+ float a, b, t, A, B;
+ float Lit_A, View_A, Lit_B[3], View_B[3];
+
+ h[0]= v[0]+l[0];
+ h[1]= v[1]+l[1];
+ h[2]= v[2]+l[2];
+ Normalize(h);
+
+ nh= n[0]*h[0]+n[1]*h[1]+n[2]*h[2]; /* Dot product between surface normal and half-way vector */
+ if(nh<0.0f) nh = 0.0f;
+
+ nv= n[0]*v[0]+n[1]*v[1]+n[2]*v[2]; /* Dot product between surface normal and view vector */
+ if(nv<=0.0f) nv= 0.0f;
+
+ realnl= n[0]*l[0]+n[1]*l[1]+n[2]*l[2]; /* Dot product between surface normal and light vector */
+ if(realnl<=0.0f) return 0.0f;
+ if(nl<0.0f) return 0.0f; /* value from area light */
+
+ vh= v[0]*h[0]+v[1]*h[1]+v[2]*h[2]; /* Dot product between view vector and halfway vector */
+ if(vh<=0.0f) vh= 0.0f;
+
+ Lit_A = saacos(realnl);
+ View_A = saacos( nv );
+
+ Lit_B[0] = l[0] - (realnl * n[0]);
+ Lit_B[1] = l[1] - (realnl * n[1]);
+ Lit_B[2] = l[2] - (realnl * n[2]);
+ Normalize( Lit_B );
+
+ View_B[0] = v[0] - (nv * n[0]);
+ View_B[1] = v[1] - (nv * n[1]);
+ View_B[2] = v[2] - (nv * n[2]);
+ Normalize( View_B );
+
+ t = Lit_B[0]*View_B[0] + Lit_B[1]*View_B[1] + Lit_B[2]*View_B[2];
+ if( t < 0 ) t = 0;
+
+ if( Lit_A > View_A ) {
+ a = Lit_A;
+ b = View_A;
+ }
+ else {
+ a = View_A;
+ b = Lit_A;
+ }
+
+ A = 1.0f - (0.5f * ((rough * rough) / ((rough * rough) + 0.33f)));
+ B = 0.45f * ((rough * rough) / ((rough * rough) + 0.09f));
+
+ b*= 0.95f; /* prevent tangens from shooting to inf, 'nl' can be not a dot product here. */
+ /* overflow only happens with extreme size area light, and higher roughness */
+ i = nl * ( A + ( B * t * sin(a) * tan(b) ) );
+
+ return i;
+}
+
+/* Minnaert diffuse */
+static float Minnaert_Diff(float nl, float *n, float *v, float darkness)
+{
+
+ float i, nv;
+
+ /* nl = dot product between surface normal and light vector */
+ if (nl <= 0.0f)
+ return 0.0f;
+
+ /* nv = dot product between surface normal and view vector */
+ nv = n[0]*v[0]+n[1]*v[1]+n[2]*v[2];
+ if (nv < 0.0f)
+ nv = 0.0f;
+
+ if (darkness <= 1.0f)
+ i = nl * pow(MAX2(nv*nl, 0.1f), (darkness - 1.0f) ); /*The Real model*/
+ else
+ i = nl * pow( (1.001f - nv), (darkness - 1.0f) ); /*Nvidia model*/
+
+ return i;
+}
+
+static float Fresnel_Diff(float *vn, float *lv, float *view, float fac_i, float fac)
+{
+ return fresnel_fac(lv, vn, fac_i, fac);
+}
+
+/* --------------------------------------------- */
+/* also called from texture.c */
+void calc_R_ref(ShadeInput *shi)
+{
+ float i;
+
+ /* shi->vn dot shi->view */
+ i= -2*(shi->vn[0]*shi->view[0]+shi->vn[1]*shi->view[1]+shi->vn[2]*shi->view[2]);
+
+ shi->ref[0]= (shi->view[0]+i*shi->vn[0]);
+ shi->ref[1]= (shi->view[1]+i*shi->vn[1]);
+ shi->ref[2]= (shi->view[2]+i*shi->vn[2]);
+ if(shi->osatex) {
+ if(shi->vlr->flag & R_SMOOTH) {
+ i= -2*( (shi->vn[0]+shi->dxno[0])*(shi->view[0]+shi->dxview) +
+ (shi->vn[1]+shi->dxno[1])*shi->view[1]+ (shi->vn[2]+shi->dxno[2])*shi->view[2] );
+
+ shi->dxref[0]= shi->ref[0]- ( shi->view[0]+shi->dxview+i*(shi->vn[0]+shi->dxno[0]));
+ shi->dxref[1]= shi->ref[1]- (shi->view[1]+ i*(shi->vn[1]+shi->dxno[1]));
+ shi->dxref[2]= shi->ref[2]- (shi->view[2]+ i*(shi->vn[2]+shi->dxno[2]));
+
+ i= -2*( (shi->vn[0]+shi->dyno[0])*shi->view[0]+
+ (shi->vn[1]+shi->dyno[1])*(shi->view[1]+shi->dyview)+ (shi->vn[2]+shi->dyno[2])*shi->view[2] );
+
+ shi->dyref[0]= shi->ref[0]- (shi->view[0]+ i*(shi->vn[0]+shi->dyno[0]));
+ shi->dyref[1]= shi->ref[1]- (shi->view[1]+shi->dyview+i*(shi->vn[1]+shi->dyno[1]));
+ shi->dyref[2]= shi->ref[2]- (shi->view[2]+ i*(shi->vn[2]+shi->dyno[2]));
+
+ }
+ else {
+
+ i= -2*( shi->vn[0]*(shi->view[0]+shi->dxview) +
+ shi->vn[1]*shi->view[1]+ shi->vn[2]*shi->view[2] );
+
+ shi->dxref[0]= shi->ref[0]- (shi->view[0]+shi->dxview+i*shi->vn[0]);
+ shi->dxref[1]= shi->ref[1]- (shi->view[1]+ i*shi->vn[1]);
+ shi->dxref[2]= shi->ref[2]- (shi->view[2]+ i*shi->vn[2]);
+
+ i= -2*( shi->vn[0]*shi->view[0]+
+ shi->vn[1]*(shi->view[1]+shi->dyview)+ shi->vn[2]*shi->view[2] );
+
+ shi->dyref[0]= shi->ref[0]- (shi->view[0]+ i*shi->vn[0]);
+ shi->dyref[1]= shi->ref[1]- (shi->view[1]+shi->dyview+i*shi->vn[1]);
+ shi->dyref[2]= shi->ref[2]- (shi->view[2]+ i*shi->vn[2]);
+ }
+ }
+
+}
+
+/* called from ray.c */
+void shade_color(ShadeInput *shi, ShadeResult *shr)
+{
+ Material *ma= shi->mat;
+
+ if(ma->mode & (MA_VERTEXCOLP|MA_FACETEXTURE)) {
+ shi->r= shi->vcol[0];
+ shi->g= shi->vcol[1];
+ shi->b= shi->vcol[2];
+ }
+
+ if(ma->texco)
+ do_material_tex(shi);
+
+ if(ma->fresnel_tra!=0.0f)
+ shi->alpha*= fresnel_fac(shi->view, shi->vn, ma->fresnel_tra_i, ma->fresnel_tra);
+
+ shr->diff[0]= shi->r;
+ shr->diff[1]= shi->g;
+ shr->diff[2]= shi->b;
+ shr->alpha= shi->alpha;
+}
+
+/* ramp for at end of shade */
+static void ramp_diffuse_result(float *diff, ShadeInput *shi)
+{
+ Material *ma= shi->mat;
+ float col[4], fac=0;
+
+ if(ma->ramp_col) {
+ if(ma->rampin_col==MA_RAMP_IN_RESULT) {
+
+ fac= 0.3*diff[0] + 0.58*diff[1] + 0.12*diff[2];
+ do_colorband(ma->ramp_col, fac, col);
+
+ /* blending method */
+ fac= col[3]*ma->rampfac_col;
+
+ ramp_blend(ma->rampblend_col, diff, diff+1, diff+2, fac, col);
+ }
+ }
+}
+
+/* r,g,b denote energy, ramp is used with different values to make new material color */
+static void add_to_diffuse(float *diff, ShadeInput *shi, float is, float r, float g, float b)
+{
+ Material *ma= shi->mat;
+ float col[4], colt[3], fac=0;
+
+ if(ma->ramp_col && (ma->mode & MA_RAMP_COL)) {
+
+ /* MA_RAMP_IN_RESULT is exceptional */
+ if(ma->rampin_col==MA_RAMP_IN_RESULT) {
+ // normal add
+ diff[0] += r * shi->r;
+ diff[1] += g * shi->g;
+ diff[2] += b * shi->b;
+ }
+ else {
+ /* input */
+ switch(ma->rampin_col) {
+ case MA_RAMP_IN_ENERGY:
+ fac= 0.3*r + 0.58*g + 0.12*b;
+ break;
+ case MA_RAMP_IN_SHADER:
+ fac= is;
+ break;
+ case MA_RAMP_IN_NOR:
+ fac= shi->view[0]*shi->vn[0] + shi->view[1]*shi->vn[1] + shi->view[2]*shi->vn[2];
+ break;
+ }
+
+ do_colorband(ma->ramp_col, fac, col);
+
+ /* blending method */
+ fac= col[3]*ma->rampfac_col;
+ colt[0]= shi->r;
+ colt[1]= shi->g;
+ colt[2]= shi->b;
+
+ ramp_blend(ma->rampblend_col, colt, colt+1, colt+2, fac, col);
+
+ /* output to */
+ diff[0] += r * colt[0];
+ diff[1] += g * colt[1];
+ diff[2] += b * colt[2];
+ }
+ }
+ else {
+ diff[0] += r * shi->r;
+ diff[1] += g * shi->g;
+ diff[2] += b * shi->b;
+ }
+}
+
+static void ramp_spec_result(float *specr, float *specg, float *specb, ShadeInput *shi)
+{
+ Material *ma= shi->mat;
+ float col[4];
+ float fac;
+
+ if(ma->ramp_spec && (ma->rampin_spec==MA_RAMP_IN_RESULT)) {
+ fac= 0.3*(*specr) + 0.58*(*specg) + 0.12*(*specb);
+ do_colorband(ma->ramp_spec, fac, col);
+
+ /* blending method */
+ fac= col[3]*ma->rampfac_spec;
+
+ ramp_blend(ma->rampblend_spec, specr, specg, specb, fac, col);
+
+ }
+}
+
+/* is = dot product shade, t = spec energy */
+static void do_specular_ramp(ShadeInput *shi, float is, float t, float *spec)
+{
+ Material *ma= shi->mat;
+ float col[4];
+ float fac=0.0f;
+
+ spec[0]= shi->specr;
+ spec[1]= shi->specg;
+ spec[2]= shi->specb;
+
+ /* MA_RAMP_IN_RESULT is exception */
+ if(ma->ramp_spec && (ma->rampin_spec!=MA_RAMP_IN_RESULT)) {
+
+ /* input */
+ switch(ma->rampin_spec) {
+ case MA_RAMP_IN_ENERGY:
+ fac= t;
+ break;
+ case MA_RAMP_IN_SHADER:
+ fac= is;
+ break;
+ case MA_RAMP_IN_NOR:
+ fac= shi->view[0]*shi->vn[0] + shi->view[1]*shi->vn[1] + shi->view[2]*shi->vn[2];
+ break;
+ }
+
+ do_colorband(ma->ramp_spec, fac, col);
+
+ /* blending method */
+ fac= col[3]*ma->rampfac_spec;
+
+ ramp_blend(ma->rampblend_spec, spec, spec+1, spec+2, fac, col);
+ }
+}
+
+/* pure AO, check for raytrace and world should have been done */
+void ambient_occlusion(ShadeInput *shi)
+{
+
+ if((R.r.mode & R_RAYTRACE) && shi->mat->amb!=0.0f)
+ ray_ao(shi, shi->ao);
+ else
+ shi->ao[0]= shi->ao[1]= shi->ao[2]= 1.0f;
+}
+
+
+/* wrld mode was checked for */
+void ambient_occlusion_to_diffuse(ShadeInput *shi, float *diff)
+{
+
+ if((R.r.mode & R_RAYTRACE) && shi->mat->amb!=0.0f) {
+ float f= R.wrld.aoenergy*shi->mat->amb;
+
+ if (R.wrld.aomix==WO_AOADDSUB) {
+ diff[0] = 2.0f*shi->ao[0]-1.0f;
+ diff[1] = 2.0f*shi->ao[1]-1.0f;
+ diff[2] = 2.0f*shi->ao[2]-1.0f;
+ }
+ else if (R.wrld.aomix==WO_AOSUB) {
+ diff[0] = shi->ao[0]-1.0f;
+ diff[1] = shi->ao[1]-1.0f;
+ diff[2] = shi->ao[2]-1.0f;
+ }
+ else {
+ VECCOPY(diff, shi->ao);
+ }
+
+ VECMUL(diff, f);
+ }
+ else
+ diff[0]= diff[1]= diff[2]= 0.0f;
+}
+
+/* result written in shadfac */
+void lamp_get_shadow(LampRen *lar, ShadeInput *shi, float inp, float *shadfac, int do_real)
+{
+ LampShadowSubSample *lss= &(lar->shadsamp[shi->thread].s[shi->sample]);
+
+ if(do_real || lss->samplenr!=shi->samplenr) {
+
+ shadfac[0]= shadfac[1]= shadfac[2]= shadfac[3]= 1.0f;
+
+ if(lar->shb) {
+ if(lar->buftype==LA_SHADBUF_IRREGULAR)
+ shadfac[3]= ISB_getshadow(shi, lar->shb);
+ else
+ shadfac[3] = testshadowbuf(lar->shb, shi->co, shi->dxco, shi->dyco, inp);
+ }
+ else if(lar->mode & LA_SHAD_RAY) {
+ ray_shadow(shi, lar, shadfac);
+ }
+
+ if(shi->depth==0) {
+ QUATCOPY(lss->shadfac, shadfac);
+ lss->samplenr= shi->samplenr;
+ }
+ }
+ else {
+ QUATCOPY(shadfac, lss->shadfac);
+ }
+}
+
+/* lampdistance and spot angle, writes in lv and dist */
+float lamp_get_visibility(LampRen *lar, float *co, float *lv, float *dist)
+{
+ if(lar->type==LA_SUN || lar->type==LA_HEMI) {
+ *dist= 1.0f;
+ VECCOPY(lv, lar->vec);
+ return 1.0f;
+ }
+ else {
+ float visifac= 1.0f, t;
+
+ VECSUB(lv, co, lar->co);
+ *dist= sqrt( INPR(lv, lv));
+ t= 1.0f/dist[0];
+ VECMUL(lv, t);
+
+ /* area type has no quad or sphere option */
+ if(lar->type==LA_AREA) {
+ /* area is single sided */
+ if(INPR(lv, lar->vec) > 0.0f)
+ visifac= 1.0f;
+ else
+ visifac= 0.0f;
+ }
+ else {
+ switch(lar->falloff_type)
+ {
+ case LA_FALLOFF_CONSTANT:
+ visifac = 1.0f;
+ break;
+ case LA_FALLOFF_INVLINEAR:
+ visifac = lar->dist/(lar->dist + dist[0]);
+ break;
+ case LA_FALLOFF_INVSQUARE:
+ visifac = lar->dist / (lar->dist + dist[0]*dist[0]);
+ break;
+ case LA_FALLOFF_SLIDERS:
+ if(lar->ld1>0.0f)
+ visifac= lar->dist/(lar->dist+lar->ld1*dist[0]);
+ if(lar->ld2>0.0f)
+ visifac*= lar->distkw/(lar->distkw+lar->ld2*dist[0]*dist[0]);
+ break;
+ case LA_FALLOFF_CURVE:
+ visifac = curvemapping_evaluateF(lar->curfalloff, 0, dist[0]/lar->dist);
+ break;
+ }
+
+ if(lar->mode & LA_SPHERE) {
+ float t= lar->dist - dist[0];
+ if(t<=0.0f)
+ visifac= 0.0f;
+ else
+ visifac*= t/lar->dist;
+ }
+
+ if(visifac > 0.0f) {
+ if(lar->type==LA_SPOT) {
+ float inpr;
+
+ if(lar->mode & LA_SQUARE) {
+ if(lv[0]*lar->vec[0]+lv[1]*lar->vec[1]+lv[2]*lar->vec[2]>0.0f) {
+ float lvrot[3], x;
+
+ /* rotate view to lampspace */
+ VECCOPY(lvrot, lv);
+ MTC_Mat3MulVecfl(lar->imat, lvrot);
+
+ x= MAX2(fabs(lvrot[0]/lvrot[2]) , fabs(lvrot[1]/lvrot[2]));
+ /* 1.0f/(sqrt(1+x*x)) is equivalent to cos(atan(x)) */
+
+ inpr= 1.0f/(sqrt(1.0f+x*x));
+ }
+ else inpr= 0.0f;
+ }
+ else {
+ inpr= lv[0]*lar->vec[0]+lv[1]*lar->vec[1]+lv[2]*lar->vec[2];
+ }
+
+ t= lar->spotsi;
+ if(inpr<=t)
+ visifac= 0.0f;
+ else {
+ t= inpr-t;
+ if(t<lar->spotbl && lar->spotbl!=0.0f) {
+ /* soft area */
+ float i= t/lar->spotbl;
+ t= i*i;
+ inpr*= (3.0f*t-2.0f*t*i);
+ }
+ visifac*= inpr;
+ }
+ }
+ }
+ }
+ if (visifac <= 0.001) visifac = 0.0f;
+ return visifac;
+ }
+}
+
+/* function returns raw diff, spec and full shadowed diff in the 'shad' pass */
+static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int passflag)
+{
+ Material *ma= shi->mat;
+ VlakRen *vlr= shi->vlr;
+ float lv[3], lampdist, lacol[3], shadfac[4];
+ float i, is, i_noshad, inp, *vn, *view, vnor[3], phongcorr=1.0f;
+ float visifac;
+
+ vn= shi->vn;
+ view= shi->view;
+
+ if (lar->energy == 0.0) return;
+
+ /* lampdist, spot angle, area side, ... */
+ visifac= lamp_get_visibility(lar, shi->co, lv, &lampdist);
+ if(visifac==0.0f)
+ return;
+
+ if(lar->type==LA_SPOT) {
+ if(lar->mode & LA_OSATEX) {
+ shi->osatex= 1; /* signal for multitex() */
+
+ shi->dxlv[0]= lv[0] - (shi->co[0]-lar->co[0]+shi->dxco[0])/lampdist;
+ shi->dxlv[1]= lv[1] - (shi->co[1]-lar->co[1]+shi->dxco[1])/lampdist;
+ shi->dxlv[2]= lv[2] - (shi->co[2]-lar->co[2]+shi->dxco[2])/lampdist;
+
+ shi->dylv[0]= lv[0] - (shi->co[0]-lar->co[0]+shi->dyco[0])/lampdist;
+ shi->dylv[1]= lv[1] - (shi->co[1]-lar->co[1]+shi->dyco[1])/lampdist;
+ shi->dylv[2]= lv[2] - (shi->co[2]-lar->co[2]+shi->dyco[2])/lampdist;
+ }
+ }
+
+ /* lamp color texture */
+ lacol[0]= lar->r;
+ lacol[1]= lar->g;
+ lacol[2]= lar->b;
+
+ if(lar->mode & LA_TEXTURE) do_lamp_tex(lar, lv, shi, lacol);
+
+ /* tangent case; calculate fake face normal, aligned with lampvector */
+ /* note, vnor==vn is used as tangent trigger for buffer shadow */
+ if(vlr->flag & R_TANGENT) {
+ float cross[3];
+ Crossf(cross, lv, vn);
+ Crossf(vnor, cross, vn);
+ vnor[0]= -vnor[0];vnor[1]= -vnor[1];vnor[2]= -vnor[2];
+ vn= vnor;
+ }
+ else if (ma->mode & MA_TANGENT_V) {
+ float cross[3];
+ Crossf(cross, lv, shi->tang);
+ Crossf(vnor, cross, shi->tang);
+ vnor[0]= -vnor[0];vnor[1]= -vnor[1];vnor[2]= -vnor[2];
+ vn= vnor;
+ }
+
+ /* dot product and reflectivity */
+ /* inp = dotproduct, is = shader result, i = lamp energy (with shadow), i_noshad = i without shadow */
+ inp= vn[0]*lv[0] + vn[1]*lv[1] + vn[2]*lv[2];
+
+ /* phong threshold to prevent backfacing faces having artefacts on ray shadow (terminator problem) */
+ /* this complex construction screams for a nicer implementation! (ton) */
+ if(R.r.mode & R_SHADOW) {
+ if(ma->mode & MA_SHADOW) {
+ if(lar->type==LA_HEMI);
+ else if((ma->mode & MA_RAYBIAS) && (lar->mode & LA_SHAD_RAY) && (vlr->flag & R_SMOOTH)) {
+ float thresh= vlr->ob->smoothresh;
+ if(inp>thresh)
+ phongcorr= (inp-thresh)/(inp*(1.0f-thresh));
+ else
+ phongcorr= 0.0f;
+ }
+ else if(ma->sbias!=0.0f && ((lar->mode & LA_SHAD_RAY) || lar->shb)) {
+ if(inp>ma->sbias)
+ phongcorr= (inp-ma->sbias)/(inp*(1.0f-ma->sbias));
+ else
+ phongcorr= 0.0f;
+ }
+ }
+ }
+
+ /* diffuse shaders */
+ if(lar->mode & LA_NO_DIFF) {
+ is= 0.0f; // skip shaders
+ }
+ else if(lar->type==LA_HEMI) {
+ is= 0.5f*inp + 0.5f;
+ }
+ else {
+
+ if(lar->type==LA_AREA)
+ inp= area_lamp_energy(shi->co, vn, lar);
+
+ /* diffuse shaders (oren nayer gets inp from area light) */
+ if(ma->diff_shader==MA_DIFF_ORENNAYAR) is= OrenNayar_Diff(inp, vn, lv, view, ma->roughness);
+ else if(ma->diff_shader==MA_DIFF_TOON) is= Toon_Diff(vn, lv, view, ma->param[0], ma->param[1]);
+ else if(ma->diff_shader==MA_DIFF_MINNAERT) is= Minnaert_Diff(inp, vn, view, ma->darkness);
+ else if(ma->diff_shader==MA_DIFF_FRESNEL) is= Fresnel_Diff(vn, lv, view, ma->param[0], ma->param[1]);
+ else is= inp; // Lambert
+ }
+
+ /* i is diffuse */
+ i= is*phongcorr;
+
+ if(i>0.0f) {
+ i*= visifac*shi->refl;
+ }
+ i_noshad= i;
+
+ vn= shi->vn; // bring back original vector, we use special specular shaders for tangent
+ if(ma->mode & MA_TANGENT_V)
+ vn= shi->tang;
+
+ /* init transp shadow */
+ shadfac[0]= shadfac[1]= shadfac[2]= shadfac[3]= 1.0f;
+
+ /* shadow and spec, (visifac==0 outside spot) */
+ if(visifac> 0.0f) {
+
+ if((R.r.mode & R_SHADOW)) {
+ if(ma->mode & MA_SHADOW) {
+ if(lar->shb || (lar->mode & LA_SHAD_RAY)) {
+
+ if(vn==vnor) /* tangent trigger */
+ lamp_get_shadow(lar, shi, INPR(shi->vn, lv), shadfac, shi->depth);
+ else
+ lamp_get_shadow(lar, shi, inp, shadfac, shi->depth);
+
+ /* warning, here it skips the loop */
+ if((lar->mode & LA_ONLYSHADOW) && i>0.0) {
+
+ shadfac[3]= i*lar->energy*(1.0f-shadfac[3]);
+ shr->shad[0] -= shadfac[3]*shi->r;
+ shr->shad[1] -= shadfac[3]*shi->g;
+ shr->shad[2] -= shadfac[3]*shi->b;
+
+ shr->spec[0] -= shadfac[3]*shi->specr;
+ shr->spec[1] -= shadfac[3]*shi->specg;
+ shr->spec[2] -= shadfac[3]*shi->specb;
+
+ return;
+ }
+
+ i*= shadfac[3];
+ }
+ }
+ }
+
+ /* in case 'no diffuse' we still do most calculus, spec can be in shadow.*/
+ if(!(lar->mode & LA_NO_DIFF)) {
+ if(i>0.0f) {
+ if(ma->mode & MA_SHADOW_TRA)
+ add_to_diffuse(shr->shad, shi, is, i*shadfac[0]*lacol[0], i*shadfac[1]*lacol[1], i*shadfac[2]*lacol[2]);
+ else
+ add_to_diffuse(shr->shad, shi, is, i*lacol[0], i*lacol[1], i*lacol[2]);
+ }
+ if(i_noshad>0.0f) {
+ if(passflag & (SCE_PASS_DIFFUSE|SCE_PASS_SHADOW)) {
+ if(ma->mode & MA_SHADOW_TRA)
+ add_to_diffuse(shr->diff, shi, is, i_noshad*shadfac[0]*lacol[0], i_noshad*shadfac[1]*lacol[1], i_noshad*shadfac[2]*lacol[2]);
+ else
+ add_to_diffuse(shr->diff, shi, is, i_noshad*lacol[0], i_noshad*lacol[1], i_noshad*lacol[2]);
+ }
+ else
+ VECCOPY(shr->diff, shr->shad);
+ }
+ }
+
+ /* specularity */
+ if(shadfac[3]>0.0f && shi->spec!=0.0f && !(lar->mode & LA_NO_SPEC) && !(lar->mode & LA_ONLYSHADOW)) {
+
+ if(!(passflag & (SCE_PASS_COMBINED|SCE_PASS_SPEC)));
+ else if(lar->type==LA_HEMI) {
+ float t;
+ /* hemi uses no spec shaders (yet) */
+
+ lv[0]+= view[0];
+ lv[1]+= view[1];
+ lv[2]+= view[2];
+
+ Normalize(lv);
+
+ t= vn[0]*lv[0]+vn[1]*lv[1]+vn[2]*lv[2];
+
+ if(lar->type==LA_HEMI) {
+ t= 0.5*t+0.5;
+ }
+
+ t= shadfac[3]*shi->spec*spec(t, shi->har);
+
+ shr->spec[0]+= t*(lacol[0] * shi->specr);
+ shr->spec[1]+= t*(lacol[1] * shi->specg);
+ shr->spec[2]+= t*(lacol[2] * shi->specb);
+ }
+ else {
+ /* specular shaders */
+ float specfac, t;
+
+ if(ma->spec_shader==MA_SPEC_PHONG)
+ specfac= Phong_Spec(vn, lv, view, shi->har, (vlr->flag & R_TANGENT) || (ma->mode & MA_TANGENT_V));
+ else if(ma->spec_shader==MA_SPEC_COOKTORR)
+ specfac= CookTorr_Spec(vn, lv, view, shi->har, (vlr->flag & R_TANGENT) || (ma->mode & MA_TANGENT_V));
+ else if(ma->spec_shader==MA_SPEC_BLINN)
+ specfac= Blinn_Spec(vn, lv, view, ma->refrac, (float)shi->har, (vlr->flag & R_TANGENT) || (ma->mode & MA_TANGENT_V));
+ else if(ma->spec_shader==MA_SPEC_WARDISO)
+ specfac= WardIso_Spec( vn, lv, view, ma->rms, (vlr->flag & R_TANGENT) || (ma->mode & MA_TANGENT_V));
+ else
+ specfac= Toon_Spec(vn, lv, view, ma->param[2], ma->param[3], (vlr->flag & R_TANGENT) || (ma->mode & MA_TANGENT_V));
+
+ /* area lamp correction */
+ if(lar->type==LA_AREA) specfac*= inp;
+
+ t= shadfac[3]*shi->spec*visifac*specfac;
+
+ if(ma->mode & MA_RAMP_SPEC) {
+ float spec[3];
+ do_specular_ramp(shi, specfac, t, spec);
+ shr->spec[0]+= t*(lacol[0] * spec[0]);
+ shr->spec[1]+= t*(lacol[1] * spec[1]);
+ shr->spec[2]+= t*(lacol[2] * spec[2]);
+ }
+ else {
+ shr->spec[0]+= t*(lacol[0] * shi->specr);
+ shr->spec[1]+= t*(lacol[1] * shi->specg);
+ shr->spec[2]+= t*(lacol[2] * shi->specb);
+ }
+ }
+ }
+ }
+}
+
+static void shade_lamp_loop_only_shadow(ShadeInput *shi, ShadeResult *shr)
+{
+
+ if(R.r.mode & R_SHADOW) {
+ ListBase *lights;
+ LampRen *lar;
+ GroupObject *go;
+ float inpr, lv[3];
+ float *vn, *view, shadfac[4];
+ float ir, accum, visifac, lampdist;
+
+ vn= shi->vn;
+ view= shi->view;
+
+ accum= ir= 0.0f;
+
+ lights= get_lights(shi);
+ for(go=lights->first; go; go= go->next) {
+ lar= go->lampren;
+ if(lar==NULL) continue;
+
+ /* yafray: ignore shading by photonlights, not used in Blender */
+ if (lar->type==LA_YF_PHOTON) continue;
+
+ if(lar->mode & LA_LAYER) if((lar->lay & shi->vlr->lay)==0) continue;
+ if((lar->lay & shi->lay)==0) continue;
+
+ if(lar->shb || (lar->mode & LA_SHAD_RAY)) {
+ visifac= lamp_get_visibility(lar, shi->co, lv, &lampdist);
+ if(visifac <= 0.0f) {
+ ir+= 1.0f;
+ accum+= 1.0f;
+ continue;
+ }
+ inpr= INPR(shi->vn, lv);
+ if(inpr <= 0.0f) {
+ ir+= 1.0f;
+ accum+= 1.0f;
+ continue;
+ }
+ lamp_get_shadow(lar, shi, inpr, shadfac, shi->depth);
+
+ ir+= 1.0f;
+ accum+= (1.0f-visifac) + (visifac)*shadfac[3];
+ }
+ }
+ if(ir>0.0f) {
+ accum/= ir;
+ shr->alpha= (shi->mat->alpha)*(1.0f-accum);
+ }
+ else shr->alpha= shi->mat->alpha;
+ }
+
+ /* quite disputable this... also note it doesn't mirror-raytrace */
+ if((R.wrld.mode & WO_AMB_OCC) && shi->amb!=0.0f) {
+ float f;
+
+ f= 1.0f - shi->ao[0];
+ f= R.wrld.aoenergy*f*shi->amb;
+
+ if(R.wrld.aomix==WO_AOADD) {
+ shr->alpha += f;
+ shr->alpha *= f;
+ }
+ else if(R.wrld.aomix==WO_AOSUB) {
+ shr->alpha += f;
+ }
+ else {
+ shr->alpha *= f;
+ shr->alpha += f;
+ }
+ }
+}
+
+static void wrld_exposure_correct(float *diff)
+{
+ diff[0]= R.wrld.linfac*(1.0f-exp( diff[0]*R.wrld.logfac) );
+ diff[1]= R.wrld.linfac*(1.0f-exp( diff[1]*R.wrld.logfac) );
+ diff[2]= R.wrld.linfac*(1.0f-exp( diff[2]*R.wrld.logfac) );
+}
+
+void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
+{
+ Material *ma= shi->mat;
+ VlakRen *vlr= shi->vlr;
+ int passflag= shi->passflag;
+
+ memset(shr, 0, sizeof(ShadeResult));
+
+ /* separate loop */
+ if(ma->mode & MA_ONLYSHADOW) {
+ shade_lamp_loop_only_shadow(shi, shr);
+ return;
+ }
+
+ /* envmap hack, always reset */
+ shi->refcol[0]= shi->refcol[1]= shi->refcol[2]= shi->refcol[3]= 0.0f;
+
+ /* material color itself */
+ if(passflag & (SCE_PASS_COMBINED|SCE_PASS_RGBA)) {
+ if(ma->mode & (MA_VERTEXCOLP|MA_FACETEXTURE)) {
+ shi->r= shi->vcol[0];
+ shi->g= shi->vcol[1];
+ shi->b= shi->vcol[2];
+ }
+ if(ma->texco)
+ do_material_tex(shi);
+
+ shr->col[0]= shi->r*shi->alpha;
+ shr->col[1]= shi->g*shi->alpha;
+ shr->col[2]= shi->b*shi->alpha;
+ shr->col[3]= shi->alpha;
+ }
+
+ if(ma->mode & MA_SHLESS) {
+ shr->combined[0]= shi->r;
+ shr->combined[1]= shi->g;
+ shr->combined[2]= shi->b;
+ shr->alpha= shi->alpha;
+ return;
+ }
+
+ if( (ma->mode & (MA_VERTEXCOL|MA_VERTEXCOLP))== MA_VERTEXCOL ) { // vertexcolor light
+ shr->diff[0]= shi->r*(shi->emit+shi->vcol[0]);
+ shr->diff[1]= shi->g*(shi->emit+shi->vcol[1]);
+ shr->diff[2]= shi->b*(shi->emit+shi->vcol[2]);
+ }
+ else {
+ shr->diff[0]= shi->r*shi->emit;
+ shr->diff[1]= shi->g*shi->emit;
+ shr->diff[2]= shi->b*shi->emit;
+ }
+ VECCOPY(shr->shad, shr->diff);
+
+ /* AO pass */
+ if(R.wrld.mode & WO_AMB_OCC) {
+ if(passflag & (SCE_PASS_COMBINED|SCE_PASS_AO)) {
+ /* AO was calculated for scanline already */
+ if(shi->depth)
+ ambient_occlusion(shi);
+ VECCOPY(shr->ao, shi->ao);
+ }
+ }
+
+ /* lighting pass */
+ if(passflag & (SCE_PASS_COMBINED|SCE_PASS_DIFFUSE|SCE_PASS_SPEC|SCE_PASS_SHADOW)) {
+ GroupObject *go;
+ ListBase *lights;
+ LampRen *lar;
+
+ lights= get_lights(shi);
+ for(go=lights->first; go; go= go->next) {
+ lar= go->lampren;
+ if(lar==NULL) continue;
+
+ /* yafray: ignore shading by photonlights, not used in Blender */
+ if (lar->type==LA_YF_PHOTON) continue;
+
+ /* test for lamp layer */
+ if(lar->mode & LA_LAYER) if((lar->lay & vlr->lay)==0) continue;
+ if((lar->lay & shi->lay)==0) continue;
+
+ /* accumulates in shr->diff and shr->spec and shr->shad (diffuse with shadow!) */
+ shade_one_light(lar, shi, shr, passflag);
+ }
+
+ /*this check is to prevent only shadow lamps from producing negative
+ colors.*/
+ if (shr->spec[0] < 0) shr->spec[0] = 0;
+ if (shr->spec[1] < 0) shr->spec[1] = 0;
+ if (shr->spec[2] < 0) shr->spec[2] = 0;
+
+ if (shr->shad[0] < 0) shr->shad[0] = 0;
+ if (shr->shad[1] < 0) shr->shad[1] = 0;
+ if (shr->shad[2] < 0) shr->shad[2] = 0;
+
+ if(ma->sss_flag & MA_DIFF_SSS) {
+ float sss[3], col[3], texfac= ma->sss_texfac;
+
+ /* this will return false in the preprocess stage */
+ if(sample_sss(&R, ma, shi->co, sss)) {
+ if(texfac==0.0f) {
+ VECCOPY(col, shr->col);
+ }
+ else if(texfac==1.0f) {
+ col[0]= col[1]= col[2]= 1.0f;
+ }
+ else {
+ col[0]= pow(shr->col[0], 1.0f-texfac);
+ col[1]= pow(shr->col[1], 1.0f-texfac);
+ col[2]= pow(shr->col[2], 1.0f-texfac);
+ }
+
+ shr->diff[0]= sss[0]*col[0];
+ shr->diff[1]= sss[1]*col[1];
+ shr->diff[2]= sss[2]*col[2];
+
+ if(shi->combinedflag & SCE_PASS_SHADOW) {
+ shr->shad[0]= sss[0]*col[0];
+ shr->shad[1]= sss[1]*col[1];
+ shr->shad[2]= sss[2]*col[2];
+ }
+ }
+ }
+
+ if(shi->combinedflag & SCE_PASS_SHADOW)
+ VECCOPY(shr->combined, shr->shad) /* note, no ';' ! */
+ else
+ VECCOPY(shr->combined, shr->diff);
+
+ /* calculate shadow pass, we use a multiplication mask */
+ if(passflag & SCE_PASS_SHADOW) {
+ if(shr->diff[0]!=0.0f) shr->shad[0]= shr->shad[0]/shr->diff[0];
+ if(shr->diff[1]!=0.0f) shr->shad[1]= shr->shad[1]/shr->diff[1];
+ if(shr->diff[2]!=0.0f) shr->shad[2]= shr->shad[2]/shr->diff[2];
+ }
+
+ /* exposure correction */
+ if(R.wrld.exp!=0.0f || R.wrld.range!=1.0f) {
+ wrld_exposure_correct(shr->combined); /* has no spec! */
+ wrld_exposure_correct(shr->spec);
+ }
+ }
+
+ /* alpha in end, spec can influence it */
+ if(passflag & (SCE_PASS_COMBINED)) {
+ if(ma->fresnel_tra!=0.0f)
+ shi->alpha*= fresnel_fac(shi->view, shi->vn, ma->fresnel_tra_i, ma->fresnel_tra);
+
+ /* note: shi->mode! */
+ if(shi->mode & (MA_ZTRA|MA_RAYTRANSP)) {
+ if(shi->spectra!=0.0f) {
+ float t = MAX3(shr->spec[0], shr->spec[1], shr->spec[2]);
+ t *= shi->spectra;
+ if(t>1.0f) t= 1.0f;
+ shi->alpha= (1.0f-t)*shi->alpha+t;
+ }
+ }
+ }
+ shr->alpha= shi->alpha;
+
+ /* from now stuff everything in shr->combined: ambient, AO, radio, ramps, exposure */
+ if(!(ma->sss_flag & MA_DIFF_SSS) || !has_sss_tree(&R, ma)) {
+ shr->combined[0]+= shi->ambr + shi->r*shi->amb*shi->rad[0];
+ shr->combined[1]+= shi->ambg + shi->g*shi->amb*shi->rad[1];
+ shr->combined[2]+= shi->ambb + shi->b*shi->amb*shi->rad[2];
+
+ /* add AO in combined? */
+ if(R.wrld.mode & WO_AMB_OCC) {
+ if(shi->combinedflag & SCE_PASS_AO) {
+ float aodiff[3];
+ ambient_occlusion_to_diffuse(shi, aodiff);
+
+ shr->combined[0] += shi->r*aodiff[0];
+ shr->combined[1] += shi->g*aodiff[1];
+ shr->combined[2] += shi->b*aodiff[2];
+ }
+ }
+
+ if(ma->mode & MA_RAMP_COL) ramp_diffuse_result(shr->combined, shi);
+ }
+
+ if(ma->mode & MA_RAMP_SPEC) ramp_spec_result(shr->spec, shr->spec+1, shr->spec+2, shi);
+
+ /* refcol is for envmap only */
+ if(shi->refcol[0]!=0.0f) {
+ float result[3];
+
+ result[0]= shi->mirr*shi->refcol[1] + (1.0f - shi->mirr*shi->refcol[0])*shr->combined[0];
+ result[1]= shi->mirg*shi->refcol[2] + (1.0f - shi->mirg*shi->refcol[0])*shr->combined[1];
+ result[2]= shi->mirb*shi->refcol[3] + (1.0f - shi->mirb*shi->refcol[0])*shr->combined[2];
+
+ if(passflag & SCE_PASS_REFLECT)
+ VECSUB(shr->refl, result, shr->combined);
+
+ if(shi->combinedflag & SCE_PASS_REFLECT)
+ VECCOPY(shr->combined, result);
+
+ }
+
+ /* and add spec */
+ if(shi->combinedflag & SCE_PASS_SPEC)
+ VECADD(shr->combined, shr->combined, shr->spec);
+
+ shr->combined[3]= shr->alpha;
+}
+
+
diff --git a/source/blender/render/intern/source/sss.c b/source/blender/render/intern/source/sss.c
new file mode 100644
index 00000000000..c4438a22ce5
--- /dev/null
+++ b/source/blender/render/intern/source/sss.c
@@ -0,0 +1,1024 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2007 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/* Possible Improvements:
+ - add fresnel terms
+ - adapt Rd table to scale, now with small scale there are a lot of misses?
+ - possible interesting method: perform sss on all samples in the tree,
+ and then use those values interpolated somehow later. can also do this
+ filtering on demand for speed. since we are doing things in screen
+ space now there is an exact correspondence
+ - avoid duplicate shading (filtering points in advance, irradiance cache
+ like lookup?)
+ - lower resolution samples
+*/
+
+#include <math.h>
+#include <string.h>
+#include <stdio.h>
+#include <string.h>
+
+/* external modules: */
+#include "MEM_guardedalloc.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
+#include "BLI_memarena.h"
+#include "PIL_time.h"
+
+#include "DNA_material_types.h"
+
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_node.h"
+#include "BKE_utildefines.h"
+
+/* this module */
+#include "render_types.h"
+#include "rendercore.h"
+#include "renderdatabase.h"
+#include "shading.h"
+#include "sss.h"
+#include "zbuf.h"
+
+extern Render R; // meh
+
+/* Generic Multiple Scattering API */
+
+/* Relevant papers:
+ [1] A Practical Model for Subsurface Light Transport
+ [2] A Rapid Hierarchical Rendering Technique for Translucent Materials
+ [3] Efficient Rendering of Local Subsurface Scattering
+ [4] Implementing a skin BSSRDF (or several...)
+*/
+
+/* Defines */
+
+#define RD_TABLE_RANGE 100.0f
+#define RD_TABLE_RANGE_2 10000.0f
+#define RD_TABLE_SIZE 10000
+
+#define MAX_OCTREE_NODE_POINTS 8
+#define MAX_OCTREE_DEPTH 15
+
+/* Struct Definitions */
+
+struct ScatterSettings {
+ float eta; /* index of refraction */
+ float sigma_a; /* absorption coefficient */
+ float sigma_s_; /* reduced scattering coefficient */
+ float sigma_t_; /* reduced extinction coefficient */
+ float sigma; /* effective extinction coefficient */
+ float Fdr; /* diffuse fresnel reflectance */
+ float D; /* diffusion constant */
+ float A;
+ float alpha_; /* reduced albedo */
+ float zr; /* distance of virtual lightsource above surface */
+ float zv; /* distance of virtual lightsource below surface */
+ float ld; /* mean free path */
+ float ro; /* diffuse reflectance */
+ float color;
+ float invsigma_t_;
+ float frontweight;
+ float backweight;
+
+ float *tableRd; /* lookup table to avoid computing Rd */
+ float *tableRd2; /* lookup table to avoid computing Rd for bigger values */
+};
+
+typedef struct ScatterPoint {
+ float co[3];
+ float rad[3];
+ float area;
+ int back;
+} ScatterPoint;
+
+typedef struct ScatterNode {
+ float co[3];
+ float rad[3];
+ float backrad[3];
+ float area, backarea;
+
+ int totpoint;
+ ScatterPoint *points;
+
+ float split[3];
+ struct ScatterNode *child[8];
+} ScatterNode;
+
+struct ScatterTree {
+ MemArena *arena;
+
+ ScatterSettings *ss[3];
+ float error, scale;
+
+ ScatterNode *root;
+ ScatterPoint *points;
+ ScatterPoint **refpoints;
+ ScatterPoint **tmppoints;
+ int totpoint;
+ float min[3], max[3];
+};
+
+typedef struct ScatterResult {
+ float rad[3];
+ float backrad[3];
+ float rdsum[3];
+ float backrdsum[3];
+} ScatterResult;
+
+/* Functions for BSSRDF reparametrization in to more intuitive parameters,
+ see [2] section 4 for more info. */
+
+static float f_Rd(float alpha_, float A, float ro)
+{
+ float sq;
+
+ sq= sqrt(3.0f*(1.0f - alpha_));
+ return (alpha_/2.0f)*(1.0f + exp((-4.0f/3.0f)*A*sq))*exp(-sq) - ro;
+}
+
+static float compute_reduced_albedo(ScatterSettings *ss)
+{
+ const float tolerance= 1e-8;
+ const int max_iteration_count= 20;
+ float d, fsub, xn_1= 0.0f , xn= 1.0f, fxn, fxn_1;
+ int i;
+
+ /* use secant method to compute reduced albedo using Rd function inverse
+ with a given reflectance */
+ fxn= f_Rd(xn, ss->A, ss->ro);
+ fxn_1= f_Rd(xn_1, ss->A, ss->ro);
+
+ for(i= 0; i < max_iteration_count; i++) {
+ fsub= (fxn - fxn_1);
+ if(fabs(fsub) < tolerance)
+ break;
+ d= ((xn - xn_1)/fsub)*fxn;
+ if(fabs(d) < tolerance)
+ break;
+
+ xn_1= xn;
+ fxn_1= fxn;
+ xn= xn - d;
+
+ if(xn > 1.0f) xn= 1.0f;
+ if(xn_1 > 1.0f) xn_1= 1.0f;
+
+ fxn= f_Rd(xn, ss->A, ss->ro);
+ }
+
+ /* avoid division by zero later */
+ if(xn <= 0.0f)
+ xn= 0.00001f;
+
+ return xn;
+}
+
+/* Exponential falloff functions */
+
+static float Rd_rsquare(ScatterSettings *ss, float rr)
+{
+ float sr, sv, Rdr, Rdv;
+
+ sr= sqrt(rr + ss->zr*ss->zr);
+ sv= sqrt(rr + ss->zv*ss->zv);
+
+ Rdr= ss->zr*(1.0f + ss->sigma*sr)*exp(-ss->sigma*sr)/(sr*sr*sr);
+ Rdv= ss->zv*(1.0f + ss->sigma*sv)*exp(-ss->sigma*sv)/(sv*sv*sv);
+
+ return /*ss->alpha_*/(1.0f/(4.0f*M_PI))*(Rdr + Rdv);
+}
+
+static float Rd(ScatterSettings *ss, float r)
+{
+ return Rd_rsquare(ss, r*r);
+}
+
+/* table lookups for Rd. this avoids expensive exp calls. we use two
+ separate tables as well for lower and higher numbers to improve
+ precision, since the number are poorly distributed because we do
+ a lookup with the squared distance for smaller distances, saving
+ another sqrt. */
+
+static void approximate_Rd_rgb(ScatterSettings **ss, float rr, float *rd)
+{
+ float indexf, t, idxf;
+ int index;
+
+ if(rr > (RD_TABLE_RANGE_2*RD_TABLE_RANGE_2)) {
+ rd[0]= Rd_rsquare(ss[0], rr);
+ rd[1]= Rd_rsquare(ss[1], rr);
+ rd[2]= Rd_rsquare(ss[2], rr);
+ }
+ else if(rr > RD_TABLE_RANGE) {
+ rr= sqrt(rr);
+ indexf= rr*(RD_TABLE_SIZE/RD_TABLE_RANGE_2);
+ index= (int)indexf;
+ idxf= (float)index;
+ t= indexf - idxf;
+
+ rd[0]= (ss[0]->tableRd2[index]*(1-t) + ss[0]->tableRd2[index+1]*t);
+ rd[1]= (ss[1]->tableRd2[index]*(1-t) + ss[1]->tableRd2[index+1]*t);
+ rd[2]= (ss[2]->tableRd2[index]*(1-t) + ss[2]->tableRd2[index+1]*t);
+ }
+ else {
+ indexf= rr*(RD_TABLE_SIZE/RD_TABLE_RANGE);
+ index= (int)indexf;
+ idxf= (float)index;
+ t= indexf - idxf;
+
+ rd[0]= (ss[0]->tableRd[index]*(1-t) + ss[0]->tableRd[index+1]*t);
+ rd[1]= (ss[1]->tableRd[index]*(1-t) + ss[1]->tableRd[index+1]*t);
+ rd[2]= (ss[2]->tableRd[index]*(1-t) + ss[2]->tableRd[index+1]*t);
+ }
+}
+
+static void build_Rd_table(ScatterSettings *ss)
+{
+ float r;
+ int i, size = RD_TABLE_SIZE+1;
+
+ ss->tableRd= MEM_mallocN(sizeof(float)*size, "scatterTableRd");
+ ss->tableRd2= MEM_mallocN(sizeof(float)*size, "scatterTableRd");
+
+ for(i= 0; i < size; i++) {
+ r= i*(RD_TABLE_RANGE/RD_TABLE_SIZE);
+ /*if(r < ss->invsigma_t_*ss->invsigma_t_)
+ r= ss->invsigma_t_*ss->invsigma_t_;*/
+ ss->tableRd[i]= Rd(ss, sqrt(r));
+
+ r= i*(RD_TABLE_RANGE_2/RD_TABLE_SIZE);
+ /*if(r < ss->invsigma_t_)
+ r= ss->invsigma_t_;*/
+ ss->tableRd2[i]= Rd(ss, r);
+ }
+}
+
+ScatterSettings *scatter_settings_new(float refl, float radius, float ior, float reflfac, float frontweight, float backweight)
+{
+ ScatterSettings *ss;
+
+ ss= MEM_callocN(sizeof(ScatterSettings), "ScatterSettings");
+
+ /* see [1] and [3] for these formulas */
+ ss->eta= ior;
+ ss->Fdr= -1.440f/ior*ior + 0.710f/ior + 0.668f + 0.0636f*ior;
+ ss->A= (1.0f + ss->Fdr)/(1.0f - ss->Fdr);
+ ss->ld= radius;
+ ss->ro= MIN2(refl, 0.999f);
+ ss->color= ss->ro*reflfac + (1.0f-reflfac);
+
+ ss->alpha_= compute_reduced_albedo(ss);
+
+ ss->sigma= 1.0f/ss->ld;
+ ss->sigma_t_= ss->sigma/sqrt(3.0f*(1.0f - ss->alpha_));
+ ss->sigma_s_= ss->alpha_*ss->sigma_t_;
+ ss->sigma_a= ss->sigma_t_ - ss->sigma_s_;
+
+ ss->D= 1.0f/(3.0f*ss->sigma_t_);
+
+ ss->zr= 1.0f/ss->sigma_t_;
+ ss->zv= ss->zr + 4.0f*ss->A*ss->D;
+
+ ss->invsigma_t_= 1.0f/ss->sigma_t_;
+
+ ss->frontweight= frontweight;
+ ss->backweight= backweight;
+
+ /* precompute a table of Rd values for quick lookup */
+ build_Rd_table(ss);
+
+ return ss;
+}
+
+void scatter_settings_free(ScatterSettings *ss)
+{
+ MEM_freeN(ss->tableRd);
+ MEM_freeN(ss->tableRd2);
+ MEM_freeN(ss);
+}
+
+/* Hierarchical method as in [2]. */
+
+/* traversal */
+
+#define SUBNODE_INDEX(co, split) \
+ ((co[0]>=split[0]) + (co[1]>=split[1])*2 + (co[2]>=split[2])*4)
+
+static void add_radiance(ScatterTree *tree, float *frontrad, float *backrad, float area, float backarea, float rr, ScatterResult *result)
+{
+ float rd[3], frontrd[3], backrd[3];
+
+ approximate_Rd_rgb(tree->ss, rr, rd);
+
+ if(frontrad && area) {
+ frontrd[0] = rd[0]*area;
+ frontrd[1] = rd[1]*area;
+ frontrd[2] = rd[2]*area;
+
+ result->rad[0] += frontrad[0]*frontrd[0];
+ result->rad[1] += frontrad[1]*frontrd[1];
+ result->rad[2] += frontrad[2]*frontrd[2];
+
+ result->rdsum[0] += frontrd[0];
+ result->rdsum[1] += frontrd[1];
+ result->rdsum[2] += frontrd[2];
+ }
+ if(backrad && backarea) {
+ backrd[0] = rd[0]*backarea;
+ backrd[1] = rd[1]*backarea;
+ backrd[2] = rd[2]*backarea;
+
+ result->backrad[0] += backrad[0]*backrd[0];
+ result->backrad[1] += backrad[1]*backrd[1];
+ result->backrad[2] += backrad[2]*backrd[2];
+
+ result->backrdsum[0] += backrd[0];
+ result->backrdsum[1] += backrd[1];
+ result->backrdsum[2] += backrd[2];
+ }
+}
+
+static void traverse_octree(ScatterTree *tree, ScatterNode *node, float *co, int self, ScatterResult *result)
+{
+ float sub[3], dist;
+ int i, index = 0;
+
+ if(node->totpoint > 0) {
+ /* leaf - add radiance from all samples */
+ for(i=0; i<node->totpoint; i++) {
+ ScatterPoint *p= &node->points[i];
+
+ VECSUB(sub, co, p->co);
+ dist= INPR(sub, sub);
+
+ if(p->back)
+ add_radiance(tree, NULL, p->rad, 0.0f, p->area, dist, result);
+ else
+ add_radiance(tree, p->rad, NULL, p->area, 0.0f, dist, result);
+ }
+ }
+ else {
+ /* branch */
+ if (self)
+ index = SUBNODE_INDEX(co, node->split);
+
+ for(i=0; i<8; i++) {
+ if(node->child[i]) {
+ ScatterNode *subnode= node->child[i];
+
+ if(self && index == i) {
+ /* always traverse node containing the point */
+ traverse_octree(tree, subnode, co, 1, result);
+ }
+ else {
+ /* decide subnode traversal based on maximum solid angle */
+ VECSUB(sub, co, subnode->co);
+ dist= INPR(sub, sub);
+
+ /* actually area/dist > error, but this avoids division */
+ if(subnode->area+subnode->backarea>tree->error*dist) {
+ traverse_octree(tree, subnode, co, 0, result);
+ }
+ else {
+ add_radiance(tree, subnode->rad, subnode->backrad,
+ subnode->area, subnode->backarea, dist, result);
+ }
+ }
+ }
+ }
+ }
+}
+
+static void compute_radiance(ScatterTree *tree, float *co, float *rad)
+{
+ ScatterResult result;
+ float rdsum[3], backrad[3], backrdsum[3];
+
+ memset(&result, 0, sizeof(result));
+
+ traverse_octree(tree, tree->root, co, 1, &result);
+
+ /* the original paper doesn't do this, but we normalize over the
+ sampled area and multiply with the reflectance. this is because
+ our point samples are incomplete, there are no samples on parts
+ of the mesh not visible from the camera. this can not only make
+ it darker, but also lead to ugly color shifts */
+
+ VecMulf(result.rad, tree->ss[0]->frontweight);
+ VecMulf(result.backrad, tree->ss[0]->backweight);
+
+ VECCOPY(rad, result.rad);
+ VECADD(backrad, result.rad, result.backrad);
+
+ VECCOPY(rdsum, result.rdsum);
+ VECADD(backrdsum, result.rdsum, result.backrdsum);
+
+ if(rdsum[0] > 0.0f) rad[0]= tree->ss[0]->color*rad[0]/rdsum[0];
+ if(rdsum[1] > 0.0f) rad[1]= tree->ss[1]->color*rad[1]/rdsum[1];
+ if(rdsum[2] > 0.0f) rad[2]= tree->ss[2]->color*rad[2]/rdsum[2];
+
+ if(backrdsum[0] > 0.0f) backrad[0]= tree->ss[0]->color*backrad[0]/backrdsum[0];
+ if(backrdsum[1] > 0.0f) backrad[1]= tree->ss[1]->color*backrad[1]/backrdsum[1];
+ if(backrdsum[2] > 0.0f) backrad[2]= tree->ss[2]->color*backrad[2]/backrdsum[2];
+
+ rad[0]= MAX2(rad[0], backrad[0]);
+ rad[1]= MAX2(rad[1], backrad[1]);
+ rad[2]= MAX2(rad[2], backrad[2]);
+}
+
+/* building */
+
+static void sum_leaf_radiance(ScatterTree *tree, ScatterNode *node)
+{
+ ScatterPoint *p;
+ float rad, totrad= 0.0f, inv;
+ int i;
+
+ node->co[0]= node->co[1]= node->co[2]= 0.0;
+ node->rad[0]= node->rad[1]= node->rad[2]= 0.0;
+ node->backrad[0]= node->backrad[1]= node->backrad[2]= 0.0;
+
+ /* compute total rad, rad weighted average position,
+ and total area */
+ for(i=0; i<node->totpoint; i++) {
+ p= &node->points[i];
+
+ rad= p->area*fabs(p->rad[0] + p->rad[1] + p->rad[2]);
+ totrad += rad;
+
+ node->co[0] += rad*p->co[0];
+ node->co[1] += rad*p->co[1];
+ node->co[2] += rad*p->co[2];
+
+ if(p->back) {
+ node->backrad[0] += p->rad[0]*p->area;
+ node->backrad[1] += p->rad[1]*p->area;
+ node->backrad[2] += p->rad[2]*p->area;
+
+ node->backarea += p->area;
+ }
+ else {
+ node->rad[0] += p->rad[0]*p->area;
+ node->rad[1] += p->rad[1]*p->area;
+ node->rad[2] += p->rad[2]*p->area;
+
+ node->area += p->area;
+ }
+ }
+
+ if(node->area > 0) {
+ inv= 1.0/node->area;
+ node->rad[0] *= inv;
+ node->rad[1] *= inv;
+ node->rad[2] *= inv;
+ }
+ if(node->backarea > 0) {
+ inv= 1.0/node->backarea;
+ node->backrad[0] *= inv;
+ node->backrad[1] *= inv;
+ node->backrad[2] *= inv;
+ }
+
+ if(totrad > 0.0f) {
+ inv= 1.0/totrad;
+ node->co[0] *= inv;
+ node->co[1] *= inv;
+ node->co[2] *= inv;
+ }
+ else {
+ /* make sure that if radiance is 0.0f, we still have these points in
+ the tree at a good position, they count for rdsum too */
+ for(i=0; i<node->totpoint; i++) {
+ p= &node->points[i];
+
+ node->co[0] += p->co[0];
+ node->co[1] += p->co[1];
+ node->co[2] += p->co[2];
+ }
+
+ node->co[0] /= node->totpoint;
+ node->co[1] /= node->totpoint;
+ node->co[2] /= node->totpoint;
+ }
+}
+
+static void sum_branch_radiance(ScatterTree *tree, ScatterNode *node)
+{
+ ScatterNode *subnode;
+ float rad, totrad= 0.0f, inv;
+ int i, totnode;
+
+ node->co[0]= node->co[1]= node->co[2]= 0.0;
+ node->rad[0]= node->rad[1]= node->rad[2]= 0.0;
+ node->backrad[0]= node->backrad[1]= node->backrad[2]= 0.0;
+
+ /* compute total rad, rad weighted average position,
+ and total area */
+ for(i=0; i<8; i++) {
+ if(node->child[i] == NULL)
+ continue;
+
+ subnode= node->child[i];
+
+ rad= subnode->area*fabs(subnode->rad[0] + subnode->rad[1] + subnode->rad[2]);
+ rad += subnode->backarea*fabs(subnode->backrad[0] + subnode->backrad[1] + subnode->backrad[2]);
+ totrad += rad;
+
+ node->co[0] += rad*subnode->co[0];
+ node->co[1] += rad*subnode->co[1];
+ node->co[2] += rad*subnode->co[2];
+
+ node->rad[0] += subnode->rad[0]*subnode->area;
+ node->rad[1] += subnode->rad[1]*subnode->area;
+ node->rad[2] += subnode->rad[2]*subnode->area;
+
+ node->backrad[0] += subnode->backrad[0]*subnode->backarea;
+ node->backrad[1] += subnode->backrad[1]*subnode->backarea;
+ node->backrad[2] += subnode->backrad[2]*subnode->backarea;
+
+ node->area += subnode->area;
+ node->backarea += subnode->backarea;
+ }
+
+ if(node->area > 0) {
+ inv= 1.0/node->area;
+ node->rad[0] *= inv;
+ node->rad[1] *= inv;
+ node->rad[2] *= inv;
+ }
+ if(node->backarea > 0) {
+ inv= 1.0/node->backarea;
+ node->backrad[0] *= inv;
+ node->backrad[1] *= inv;
+ node->backrad[2] *= inv;
+ }
+
+ if(totrad > 0.0f) {
+ inv= 1.0/totrad;
+ node->co[0] *= inv;
+ node->co[1] *= inv;
+ node->co[2] *= inv;
+ }
+ else {
+ /* make sure that if radiance is 0.0f, we still have these points in
+ the tree at a good position, they count for rdsum too */
+ totnode= 0;
+
+ for(i=0; i<8; i++) {
+ if(node->child[i]) {
+ subnode= node->child[i];
+
+ node->co[0] += subnode->co[0];
+ node->co[1] += subnode->co[1];
+ node->co[2] += subnode->co[2];
+
+ totnode++;
+ }
+ }
+
+ node->co[0] /= totnode;
+ node->co[1] /= totnode;
+ node->co[2] /= totnode;
+ }
+}
+
+static void sum_radiance(ScatterTree *tree, ScatterNode *node)
+{
+ if(node->totpoint > 0) {
+ sum_leaf_radiance(tree, node);
+ }
+ else {
+ int i;
+
+ for(i=0; i<8; i++)
+ if(node->child[i])
+ sum_radiance(tree, node->child[i]);
+
+ sum_branch_radiance(tree, node);
+ }
+}
+
+static void subnode_middle(int i, float *mid, float *subsize, float *submid)
+{
+ int x= i & 1, y= i & 2, z= i & 4;
+
+ submid[0]= mid[0] + ((x)? subsize[0]: -subsize[0]);
+ submid[1]= mid[1] + ((y)? subsize[1]: -subsize[1]);
+ submid[2]= mid[2] + ((z)? subsize[2]: -subsize[2]);
+}
+
+static void create_octree_node(ScatterTree *tree, ScatterNode *node, float *mid, float *size, ScatterPoint **refpoints, int depth)
+{
+ ScatterNode *subnode;
+ ScatterPoint **subrefpoints, **tmppoints= tree->tmppoints;
+ int index, nsize[8], noffset[8], i, subco, usednodes, usedi;
+ float submid[3], subsize[3];
+
+ /* stopping condition */
+ if(node->totpoint <= MAX_OCTREE_NODE_POINTS || depth == MAX_OCTREE_DEPTH) {
+ for(i=0; i<node->totpoint; i++)
+ node->points[i]= *(refpoints[i]);
+
+ return;
+ }
+
+ subsize[0]= size[0]*0.5;
+ subsize[1]= size[1]*0.5;
+ subsize[2]= size[2]*0.5;
+
+ node->split[0]= mid[0];
+ node->split[1]= mid[1];
+ node->split[2]= mid[2];
+
+ memset(nsize, 0, sizeof(nsize));
+ memset(noffset, 0, sizeof(noffset));
+
+ /* count points in subnodes */
+ for(i=0; i<node->totpoint; i++) {
+ index= SUBNODE_INDEX(refpoints[i]->co, node->split);
+ tmppoints[i]= refpoints[i];
+ nsize[index]++;
+ }
+
+ /* here we check if only one subnode is used. if this is the case, we don't
+ create a new node, but rather call this function again, with different
+ size and middle position for the same node. */
+ for(usedi=0, usednodes=0, i=0; i<8; i++) {
+ if(nsize[i]) {
+ usednodes++;
+ usedi = i;
+ }
+ if(i != 0)
+ noffset[i]= noffset[i-1]+nsize[i-1];
+ }
+
+ if(usednodes<=1) {
+ subnode_middle(usedi, mid, subsize, submid);
+ create_octree_node(tree, node, submid, subsize, refpoints, depth+1);
+ return;
+ }
+
+ /* reorder refpoints by subnode */
+ for(i=0; i<node->totpoint; i++) {
+ index= SUBNODE_INDEX(tmppoints[i]->co, node->split);
+ refpoints[noffset[index]]= tmppoints[i];
+ noffset[index]++;
+ }
+
+ /* create subnodes */
+ for(subco=0, i=0; i<8; subco+=nsize[i], i++) {
+ if(nsize[i] > 0) {
+ subnode= BLI_memarena_alloc(tree->arena, sizeof(ScatterNode));
+ node->child[i]= subnode;
+ subnode->points= node->points + subco;
+ subnode->totpoint= nsize[i];
+ subrefpoints= refpoints + subco;
+
+ subnode_middle(i, mid, subsize, submid);
+
+ create_octree_node(tree, subnode, submid, subsize, subrefpoints,
+ depth+1);
+ }
+ else
+ node->child[i]= NULL;
+ }
+
+ node->points= NULL;
+ node->totpoint= 0;
+}
+
+/* public functions */
+
+ScatterTree *scatter_tree_new(ScatterSettings *ss[3], float scale, float error,
+ float (*co)[3], float (*color)[3], float *area, int totpoint)
+{
+ ScatterTree *tree;
+ ScatterPoint *points, **refpoints;
+ int i;
+
+ /* allocate tree */
+ tree= MEM_callocN(sizeof(ScatterTree), "ScatterTree");
+ tree->scale= scale;
+ tree->error= error;
+ tree->totpoint= totpoint;
+
+ tree->ss[0]= ss[0];
+ tree->ss[1]= ss[1];
+ tree->ss[2]= ss[2];
+
+ points= MEM_callocN(sizeof(ScatterPoint)*totpoint, "ScatterPoints");
+ refpoints= MEM_callocN(sizeof(ScatterPoint*)*totpoint, "ScatterRefPoints");
+
+ tree->points= points;
+ tree->refpoints= refpoints;
+
+ /* build points */
+ INIT_MINMAX(tree->min, tree->max);
+
+ for(i=0; i<totpoint; i++) {
+ VECCOPY(points[i].co, co[i]);
+ VECCOPY(points[i].rad, color[i]);
+ points[i].area= fabs(area[i])/(tree->scale*tree->scale);
+ points[i].back= (area[i] < 0.0f);
+
+ VecMulf(points[i].co, 1.0f/tree->scale);
+ DO_MINMAX(points[i].co, tree->min, tree->max);
+
+ refpoints[i]= points + i;
+ }
+
+ return tree;
+}
+
+void scatter_tree_build(ScatterTree *tree)
+{
+ ScatterPoint *newpoints, **tmppoints;
+ float mid[3], size[3];
+ int totpoint= tree->totpoint;
+
+ newpoints= MEM_callocN(sizeof(ScatterPoint)*totpoint, "ScatterPoints");
+ tmppoints= MEM_callocN(sizeof(ScatterPoint*)*totpoint, "ScatterTmpPoints");
+ tree->tmppoints= tmppoints;
+
+ tree->arena= BLI_memarena_new(0x8000 * sizeof(ScatterNode));
+ BLI_memarena_use_calloc(tree->arena);
+
+ /* build tree */
+ tree->root= BLI_memarena_alloc(tree->arena, sizeof(ScatterNode));
+ tree->root->points= newpoints;
+ tree->root->totpoint= totpoint;
+
+ mid[0]= (tree->min[0]+tree->max[0])*0.5;
+ mid[1]= (tree->min[1]+tree->max[1])*0.5;
+ mid[2]= (tree->min[2]+tree->max[2])*0.5;
+
+ size[0]= (tree->max[0]-tree->min[0])*0.5;
+ size[1]= (tree->max[1]-tree->min[1])*0.5;
+ size[2]= (tree->max[2]-tree->min[2])*0.5;
+
+ create_octree_node(tree, tree->root, mid, size, tree->refpoints, 0);
+
+ MEM_freeN(tree->points);
+ MEM_freeN(tree->refpoints);
+ MEM_freeN(tree->tmppoints);
+ tree->refpoints= NULL;
+ tree->tmppoints= NULL;
+ tree->points= newpoints;
+
+ /* sum radiance at nodes */
+ sum_radiance(tree, tree->root);
+}
+
+void scatter_tree_sample(ScatterTree *tree, float *co, float *color)
+{
+ float sco[3];
+
+ VECCOPY(sco, co);
+ VecMulf(sco, 1.0f/tree->scale);
+
+ compute_radiance(tree, sco, color);
+}
+
+void scatter_tree_free(ScatterTree *tree)
+{
+ if (tree->arena) BLI_memarena_free(tree->arena);
+ if (tree->points) MEM_freeN(tree->points);
+ if (tree->refpoints) MEM_freeN(tree->refpoints);
+
+ MEM_freeN(tree);
+}
+
+/* Internal Renderer API */
+
+/* sss tree building */
+
+typedef struct SSSData {
+ ScatterTree *tree;
+ ScatterSettings *ss[3];
+} SSSData;
+
+typedef struct SSSPoints {
+ struct SSSPoints *next, *prev;
+
+ float (*co)[3];
+ float (*color)[3];
+ float *area;
+ int totpoint;
+} SSSPoints;
+
+static void sss_create_tree_mat(Render *re, Material *mat)
+{
+ SSSPoints *p;
+ RenderResult *rr;
+ ListBase layers, points;
+ float (*co)[3] = NULL, (*color)[3] = NULL, *area = NULL;
+ int totpoint = 0, osa, osaflag, partsdone;
+
+ if(re->test_break())
+ return;
+
+ points.first= points.last= NULL;
+
+ /* TODO: this is getting a bit ugly, copying all those variables and
+ setting them back, maybe we need to create our own Render? */
+
+ /* do SSS preprocessing render */
+ layers= re->r.layers;
+ osa= re->osa;
+ osaflag= re->r.mode & R_OSA;
+ partsdone= re->i.partsdone;
+ rr= re->result;
+
+ re->r.layers.first= re->r.layers.last= NULL;
+ re->osa= 0;
+ re->r.mode &= ~R_OSA;
+ re->sss_points= &points;
+ re->sss_mat= mat;
+ re->i.partsdone= 0;
+ re->result= NULL;
+
+ RE_TileProcessor(re, 0, !(re->r.mode & R_PREVIEWBUTS));
+ RE_FreeRenderResult(re->result);
+
+ re->result= rr;
+ re->i.partsdone= partsdone;
+ re->sss_mat= NULL;
+ re->sss_points= NULL;
+ re->r.layers= layers;
+ re->osa= osa;
+ if (osaflag) re->r.mode |= R_OSA;
+
+ /* no points? no tree */
+ if(!points.first)
+ return;
+
+ /* merge points together into a single buffer */
+ if(!re->test_break()) {
+ for(totpoint=0, p=points.first; p; p=p->next)
+ totpoint += p->totpoint;
+
+ co= MEM_mallocN(sizeof(*co)*totpoint, "SSSCo");
+ color= MEM_mallocN(sizeof(*color)*totpoint, "SSSColor");
+ area= MEM_mallocN(sizeof(*area)*totpoint, "SSSArea");
+
+ for(totpoint=0, p=points.first; p; p=p->next) {
+ memcpy(co+totpoint, p->co, sizeof(*co)*p->totpoint);
+ memcpy(color+totpoint, p->color, sizeof(*color)*p->totpoint);
+ memcpy(area+totpoint, p->area, sizeof(*area)*p->totpoint);
+ totpoint += p->totpoint;
+ }
+ }
+
+ /* free points */
+ for(p=points.first; p; p=p->next) {
+ MEM_freeN(p->co);
+ MEM_freeN(p->color);
+ MEM_freeN(p->area);
+ }
+ BLI_freelistN(&points);
+
+ /* build tree */
+ if(!re->test_break()) {
+ SSSData *sss= MEM_callocN(sizeof(*sss), "SSSData");
+ float ior= mat->sss_ior, cfac= mat->sss_colfac;
+ float *col= mat->sss_col, *radius= mat->sss_radius;
+ float fw= mat->sss_front, bw= mat->sss_back;
+ float error = mat->sss_error;
+
+ if((re->r.scemode & R_PREVIEWBUTS) && error < 0.5f)
+ error= 0.5f;
+
+ sss->ss[0]= scatter_settings_new(col[0], radius[0], ior, cfac, fw, bw);
+ sss->ss[1]= scatter_settings_new(col[1], radius[1], ior, cfac, fw, bw);
+ sss->ss[2]= scatter_settings_new(col[2], radius[2], ior, cfac, fw, bw);
+ sss->tree= scatter_tree_new(sss->ss, mat->sss_scale, error,
+ co, color, area, totpoint);
+
+ MEM_freeN(co);
+ MEM_freeN(color);
+ MEM_freeN(area);
+
+ scatter_tree_build(sss->tree);
+
+ BLI_ghash_insert(re->sss_hash, mat, sss);
+ }
+ else {
+ if (co) MEM_freeN(co);
+ if (color) MEM_freeN(color);
+ if (area) MEM_freeN(area);
+ }
+}
+
+void sss_add_points(Render *re, float (*co)[3], float (*color)[3], float *area, int totpoint)
+{
+ SSSPoints *p;
+
+ if(totpoint > 0) {
+ p= MEM_callocN(sizeof(SSSPoints), "SSSPoints");
+
+ p->co= co;
+ p->color= color;
+ p->area= area;
+ p->totpoint= totpoint;
+
+ BLI_lock_thread(LOCK_CUSTOM1);
+ BLI_addtail(re->sss_points, p);
+ BLI_unlock_thread(LOCK_CUSTOM1);
+ }
+}
+
+static void sss_free_tree(SSSData *sss)
+{
+ scatter_tree_free(sss->tree);
+ scatter_settings_free(sss->ss[0]);
+ scatter_settings_free(sss->ss[1]);
+ scatter_settings_free(sss->ss[2]);
+ MEM_freeN(sss);
+}
+
+/* public functions */
+
+void make_sss_tree(Render *re)
+{
+ Material *mat;
+
+ re->sss_hash= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
+
+ re->i.infostr= "SSS preprocessing";
+ re->stats_draw(&re->i);
+
+ for(mat= G.main->mat.first; mat; mat= mat->id.next)
+ if(mat->id.us && (mat->sss_flag & MA_DIFF_SSS))
+ sss_create_tree_mat(re, mat);
+}
+
+void free_sss(Render *re)
+{
+ if(re->sss_hash) {
+ GHashIterator *it= BLI_ghashIterator_new(re->sss_hash);
+
+ while(!BLI_ghashIterator_isDone(it)) {
+ sss_free_tree(BLI_ghashIterator_getValue(it));
+ BLI_ghashIterator_step(it);
+ }
+
+ BLI_ghashIterator_free(it);
+ BLI_ghash_free(re->sss_hash, NULL, NULL);
+ re->sss_hash= NULL;
+ }
+}
+
+int sample_sss(Render *re, Material *mat, float *co, float *color)
+{
+ if(re->sss_hash) {
+ SSSData *sss= BLI_ghash_lookup(re->sss_hash, mat);
+
+ if(sss) {
+ scatter_tree_sample(sss->tree, co, color);
+ return 1;
+ }
+ else {
+ color[0]= 0.0f;
+ color[1]= 0.0f;
+ color[2]= 0.0f;
+ }
+ }
+
+ return 0;
+}
+
+int has_sss_tree(struct Render *re, struct Material *mat)
+{
+ return (re->sss_hash && BLI_ghash_lookup(re->sss_hash, mat));
+}
+
diff --git a/source/blender/render/intern/source/texture.c b/source/blender/render/intern/source/texture.c
new file mode 100644
index 00000000000..8c366593034
--- /dev/null
+++ b/source/blender/render/intern/source/texture.c
@@ -0,0 +1,2455 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): 2004-2006, Blender Foundation, full recode
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "MTC_matrixops.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_rand.h"
+
+#include "DNA_texture_types.h"
+#include "DNA_object_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_material_types.h"
+#include "DNA_image_types.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "BKE_image.h"
+#include "BKE_plugin_types.h"
+#include "BKE_utildefines.h"
+
+#include "BKE_global.h"
+#include "BKE_main.h"
+
+#include "BKE_library.h"
+#include "BKE_image.h"
+#include "BKE_texture.h"
+#include "BKE_key.h"
+#include "BKE_ipo.h"
+
+#include "envmap.h"
+#include "renderpipeline.h"
+#include "render_types.h"
+#include "rendercore.h"
+#include "shading.h"
+#include "texture.h"
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
+/* only to be used here in this file, it's for speed */
+extern struct Render R;
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+
+
+
+/* note; this is called WITH RENDER IS NULL in src/drawview.c for animated
+ background image, option should move to kernel */
+void init_render_texture(Render *re, Tex *tex)
+{
+ int cfra= G.scene->r.cfra;
+
+ if(re) cfra= re->r.cfra;
+
+ /* imap test */
+ if(tex->ima && ELEM(tex->ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) {
+ BKE_image_user_calc_imanr(&tex->iuser, cfra, re?re->flag & R_SEC_FIELD:0);
+ }
+
+ if(tex->type==TEX_PLUGIN) {
+ if(tex->plugin && tex->plugin->doit) {
+ if(tex->plugin->cfra) {
+ *(tex->plugin->cfra)= frame_to_float(cfra);
+ }
+ }
+ }
+ else if(tex->type==TEX_ENVMAP) {
+ /* just in case */
+ tex->imaflag= TEX_INTERPOL | TEX_MIPMAP;
+ tex->extend= TEX_CLIP;
+
+ if(tex->env) {
+ if(tex->env->type==ENV_PLANE)
+ tex->extend= TEX_EXTEND;
+
+ /* only free envmap when rendermode was set to render envmaps, for previewrender */
+ if(G.rendering && re) {
+ if (re->r.mode & R_ENVMAP)
+ if(tex->env->stype==ENV_ANIM)
+ BKE_free_envmapdata(tex->env);
+ }
+ }
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+void init_render_textures(Render *re)
+{
+ Tex *tex;
+
+ tex= G.main->tex.first;
+ while(tex) {
+ if(tex->id.us) init_render_texture(re, tex);
+ tex= tex->id.next;
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+
+/* this allows colorbanded textures to control normals as well */
+static void tex_normal_derivate(Tex *tex, TexResult *texres)
+{
+ if (tex->flag & TEX_COLORBAND) {
+ float col[4];
+ if (do_colorband(tex->coba, texres->tin, col)) {
+ float fac0, fac1, fac2, fac3;
+
+ fac0= (col[0]+col[1]+col[2]);
+ do_colorband(tex->coba, texres->nor[0], col);
+ fac1= (col[0]+col[1]+col[2]);
+ do_colorband(tex->coba, texres->nor[1], col);
+ fac2= (col[0]+col[1]+col[2]);
+ do_colorband(tex->coba, texres->nor[2], col);
+ fac3= (col[0]+col[1]+col[2]);
+
+ texres->nor[0]= 0.3333*(fac0 - fac1);
+ texres->nor[1]= 0.3333*(fac0 - fac2);
+ texres->nor[2]= 0.3333*(fac0 - fac3);
+
+ return;
+ }
+ }
+ texres->nor[0]= texres->tin - texres->nor[0];
+ texres->nor[1]= texres->tin - texres->nor[1];
+ texres->nor[2]= texres->tin - texres->nor[2];
+}
+
+
+
+static int blend(Tex *tex, float *texvec, TexResult *texres)
+{
+ float x, y, t;
+
+ if(tex->flag & TEX_FLIPBLEND) {
+ x= texvec[1];
+ y= texvec[0];
+ }
+ else {
+ x= texvec[0];
+ y= texvec[1];
+ }
+
+ if(tex->stype==TEX_LIN) { /* lin */
+ texres->tin= (1.0+x)/2.0;
+ }
+ else if(tex->stype==TEX_QUAD) { /* quad */
+ texres->tin= (1.0+x)/2.0;
+ if(texres->tin<0.0) texres->tin= 0.0;
+ else texres->tin*= texres->tin;
+ }
+ else if(tex->stype==TEX_EASE) { /* ease */
+ texres->tin= (1.0+x)/2.0;
+ if(texres->tin<=.0) texres->tin= 0.0;
+ else if(texres->tin>=1.0) texres->tin= 1.0;
+ else {
+ t= texres->tin*texres->tin;
+ texres->tin= (3.0*t-2.0*t*texres->tin);
+ }
+ }
+ else if(tex->stype==TEX_DIAG) { /* diag */
+ texres->tin= (2.0+x+y)/4.0;
+ }
+ else if(tex->stype==TEX_RAD) { /* radial */
+ texres->tin= (atan2(y,x) / (2*M_PI) + 0.5);
+ }
+ else { /* sphere TEX_SPHERE */
+ texres->tin= 1.0-sqrt(x*x+ y*y+texvec[2]*texvec[2]);
+ if(texres->tin<0.0) texres->tin= 0.0;
+ if(tex->stype==TEX_HALO) texres->tin*= texres->tin; /* halo */
+ }
+
+ BRICONT;
+
+ return TEX_INT;
+}
+
+/* ------------------------------------------------------------------------- */
+/* ************************************************************************* */
+
+/* newnoise: all noisebased types now have different noisebases to choose from */
+
+static int clouds(Tex *tex, float *texvec, TexResult *texres)
+{
+ int rv = TEX_INT;
+
+ texres->tin = BLI_gTurbulence(tex->noisesize, texvec[0], texvec[1], texvec[2], tex->noisedepth, (tex->noisetype!=TEX_NOISESOFT), tex->noisebasis);
+
+ if (texres->nor!=NULL) {
+ // calculate bumpnormal
+ texres->nor[0] = BLI_gTurbulence(tex->noisesize, texvec[0] + tex->nabla, texvec[1], texvec[2], tex->noisedepth, (tex->noisetype!=TEX_NOISESOFT), tex->noisebasis);
+ texres->nor[1] = BLI_gTurbulence(tex->noisesize, texvec[0], texvec[1] + tex->nabla, texvec[2], tex->noisedepth, (tex->noisetype!=TEX_NOISESOFT), tex->noisebasis);
+ texres->nor[2] = BLI_gTurbulence(tex->noisesize, texvec[0], texvec[1], texvec[2] + tex->nabla, tex->noisedepth, (tex->noisetype!=TEX_NOISESOFT), tex->noisebasis);
+
+ tex_normal_derivate(tex, texres);
+ rv |= TEX_NOR;
+ }
+
+ if (tex->stype==TEX_COLOR) {
+ // in this case, int. value should really be computed from color,
+ // and bumpnormal from that, would be too slow, looks ok as is
+ texres->tr = texres->tin;
+ texres->tg = BLI_gTurbulence(tex->noisesize, texvec[1], texvec[0], texvec[2], tex->noisedepth, (tex->noisetype!=TEX_NOISESOFT), tex->noisebasis);
+ texres->tb = BLI_gTurbulence(tex->noisesize, texvec[1], texvec[2], texvec[0], tex->noisedepth, (tex->noisetype!=TEX_NOISESOFT), tex->noisebasis);
+ BRICONTRGB;
+ texres->ta = 1.0;
+ return (rv | TEX_RGB);
+ }
+
+ BRICONT;
+
+ return rv;
+
+}
+
+/* creates a sine wave */
+static float tex_sin(float a)
+{
+ a = 0.5 + 0.5*sin(a);
+
+ return a;
+}
+
+/* creates a saw wave */
+static float tex_saw(float a)
+{
+ const float b = 2*M_PI;
+
+ int n = (int)(a / b);
+ a -= n*b;
+ if (a < 0) a += b;
+ return a / b;
+}
+
+/* creates a triangle wave */
+static float tex_tri(float a)
+{
+ const float b = 2*M_PI;
+ const float rmax = 1.0;
+
+ a = rmax - 2.0*fabs(floor((a*(1.0/b))+0.5) - (a*(1.0/b)));
+
+ return a;
+}
+
+/* computes basic wood intensity value at x,y,z */
+static float wood_int(Tex *tex, float x, float y, float z)
+{
+ float wi=0;
+ short wf = tex->noisebasis2; /* wave form: TEX_SIN=0, TEX_SAW=1, TEX_TRI=2 */
+ short wt = tex->stype; /* wood type: TEX_BAND=0, TEX_RING=1, TEX_BANDNOISE=2, TEX_RINGNOISE=3 */
+
+ float (*waveform[3])(float); /* create array of pointers to waveform functions */
+ waveform[0] = tex_sin; /* assign address of tex_sin() function to pointer array */
+ waveform[1] = tex_saw;
+ waveform[2] = tex_tri;
+
+ if ((wf>TEX_TRI) || (wf<TEX_SIN)) wf=0; /* check to be sure noisebasis2 is initialized ahead of time */
+
+ if (wt==TEX_BAND) {
+ wi = waveform[wf]((x + y + z)*10.0);
+ }
+ else if (wt==TEX_RING) {
+ wi = waveform[wf](sqrt(x*x + y*y + z*z)*20.0);
+ }
+ else if (wt==TEX_BANDNOISE) {
+ wi = tex->turbul*BLI_gNoise(tex->noisesize, x, y, z, (tex->noisetype!=TEX_NOISESOFT), tex->noisebasis);
+ wi = waveform[wf]((x + y + z)*10.0 + wi);
+ }
+ else if (wt==TEX_RINGNOISE) {
+ wi = tex->turbul*BLI_gNoise(tex->noisesize, x, y, z, (tex->noisetype!=TEX_NOISESOFT), tex->noisebasis);
+ wi = waveform[wf](sqrt(x*x + y*y + z*z)*20.0 + wi);
+ }
+
+ return wi;
+}
+
+static int wood(Tex *tex, float *texvec, TexResult *texres)
+{
+ int rv=TEX_INT;
+
+ texres->tin = wood_int(tex, texvec[0], texvec[1], texvec[2]);
+ if (texres->nor!=NULL) {
+ /* calculate bumpnormal */
+ texres->nor[0] = wood_int(tex, texvec[0] + tex->nabla, texvec[1], texvec[2]);
+ texres->nor[1] = wood_int(tex, texvec[0], texvec[1] + tex->nabla, texvec[2]);
+ texres->nor[2] = wood_int(tex, texvec[0], texvec[1], texvec[2] + tex->nabla);
+
+ tex_normal_derivate(tex, texres);
+ rv |= TEX_NOR;
+ }
+
+ BRICONT;
+
+ return rv;
+}
+
+/* computes basic marble intensity at x,y,z */
+static float marble_int(Tex *tex, float x, float y, float z)
+{
+ float n, mi;
+ short wf = tex->noisebasis2; /* wave form: TEX_SIN=0, TEX_SAW=1, TEX_TRI=2 */
+ short mt = tex->stype; /* marble type: TEX_SOFT=0, TEX_SHARP=1,TEX_SHAPER=2 */
+
+ float (*waveform[3])(float); /* create array of pointers to waveform functions */
+ waveform[0] = tex_sin; /* assign address of tex_sin() function to pointer array */
+ waveform[1] = tex_saw;
+ waveform[2] = tex_tri;
+
+ if ((wf>TEX_TRI) || (wf<TEX_SIN)) wf=0; /* check to be sure noisebasis2 isn't initialized ahead of time */
+
+ n = 5.0 * (x + y + z);
+
+ mi = n + tex->turbul * BLI_gTurbulence(tex->noisesize, x, y, z, tex->noisedepth, (tex->noisetype!=TEX_NOISESOFT), tex->noisebasis);
+
+ if (mt>=TEX_SOFT) { /* TEX_SOFT always true */
+ mi = waveform[wf](mi);
+ if (mt==TEX_SHARP) {
+ mi = sqrt(mi);
+ }
+ else if (mt==TEX_SHARPER) {
+ mi = sqrt(sqrt(mi));
+ }
+ }
+
+ return mi;
+}
+
+static int marble(Tex *tex, float *texvec, TexResult *texres)
+{
+ int rv=TEX_INT;
+
+ texres->tin = marble_int(tex, texvec[0], texvec[1], texvec[2]);
+
+ if (texres->nor!=NULL) {
+ /* calculate bumpnormal */
+ texres->nor[0] = marble_int(tex, texvec[0] + tex->nabla, texvec[1], texvec[2]);
+ texres->nor[1] = marble_int(tex, texvec[0], texvec[1] + tex->nabla, texvec[2]);
+ texres->nor[2] = marble_int(tex, texvec[0], texvec[1], texvec[2] + tex->nabla);
+
+ tex_normal_derivate(tex, texres);
+
+ rv |= TEX_NOR;
+ }
+
+ BRICONT;
+
+ return rv;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int magic(Tex *tex, float *texvec, TexResult *texres)
+{
+ float x, y, z, turb=1.0;
+ int n;
+
+ n= tex->noisedepth;
+ turb= tex->turbul/5.0;
+
+ x= sin( ( texvec[0]+texvec[1]+texvec[2])*5.0 );
+ y= cos( (-texvec[0]+texvec[1]-texvec[2])*5.0 );
+ z= -cos( (-texvec[0]-texvec[1]+texvec[2])*5.0 );
+ if(n>0) {
+ x*= turb;
+ y*= turb;
+ z*= turb;
+ y= -cos(x-y+z);
+ y*= turb;
+ if(n>1) {
+ x= cos(x-y-z);
+ x*= turb;
+ if(n>2) {
+ z= sin(-x-y-z);
+ z*= turb;
+ if(n>3) {
+ x= -cos(-x+y-z);
+ x*= turb;
+ if(n>4) {
+ y= -sin(-x+y+z);
+ y*= turb;
+ if(n>5) {
+ y= -cos(-x+y+z);
+ y*= turb;
+ if(n>6) {
+ x= cos(x+y+z);
+ x*= turb;
+ if(n>7) {
+ z= sin(x+y-z);
+ z*= turb;
+ if(n>8) {
+ x= -cos(-x-y+z);
+ x*= turb;
+ if(n>9) {
+ y= -sin(x-y+z);
+ y*= turb;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if(turb!=0.0) {
+ turb*= 2.0;
+ x/= turb;
+ y/= turb;
+ z/= turb;
+ }
+ texres->tr= 0.5-x;
+ texres->tg= 0.5-y;
+ texres->tb= 0.5-z;
+
+ texres->tin= 0.3333*(texres->tr+texres->tg+texres->tb);
+
+ BRICONTRGB;
+ texres->ta= 1.0;
+
+ return TEX_RGB;
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* newnoise: stucci also modified to use different noisebasis */
+static int stucci(Tex *tex, float *texvec, TexResult *texres)
+{
+ float nor[3], b2, ofs;
+ int retval= TEX_INT;
+
+ b2= BLI_gNoise(tex->noisesize, texvec[0], texvec[1], texvec[2], (tex->noisetype!=TEX_NOISESOFT), tex->noisebasis);
+
+ ofs= tex->turbul/200.0;
+
+ if(tex->stype) ofs*=(b2*b2);
+ nor[0] = BLI_gNoise(tex->noisesize, texvec[0]+ofs, texvec[1], texvec[2], (tex->noisetype!=TEX_NOISESOFT), tex->noisebasis);
+ nor[1] = BLI_gNoise(tex->noisesize, texvec[0], texvec[1]+ofs, texvec[2], (tex->noisetype!=TEX_NOISESOFT), tex->noisebasis);
+ nor[2] = BLI_gNoise(tex->noisesize, texvec[0], texvec[1], texvec[2]+ofs, (tex->noisetype!=TEX_NOISESOFT), tex->noisebasis);
+
+ texres->tin= nor[2];
+
+ if(texres->nor) {
+
+ VECCOPY(texres->nor, nor);
+ tex_normal_derivate(tex, texres);
+
+ if(tex->stype==TEX_WALLOUT) {
+ texres->nor[0]= -texres->nor[0];
+ texres->nor[1]= -texres->nor[1];
+ texres->nor[2]= -texres->nor[2];
+ }
+
+ retval |= TEX_NOR;
+ }
+
+ if(tex->stype==TEX_WALLOUT)
+ texres->tin= 1.0f-texres->tin;
+
+ if(texres->tin<0.0f)
+ texres->tin= 0.0f;
+
+ return retval;
+}
+
+/* ------------------------------------------------------------------------- */
+/* newnoise: musgrave terrain noise types */
+
+static float mg_mFractalOrfBmTex(Tex *tex, float *texvec, TexResult *texres)
+{
+ int rv = TEX_INT;
+ float (*mgravefunc)(float, float, float, float, float, float, int);
+
+ if (tex->stype==TEX_MFRACTAL)
+ mgravefunc = mg_MultiFractal;
+ else
+ mgravefunc = mg_fBm;
+
+ texres->tin = tex->ns_outscale*mgravefunc(texvec[0], texvec[1], texvec[2], tex->mg_H, tex->mg_lacunarity, tex->mg_octaves, tex->noisebasis);
+
+ if (texres->nor!=NULL) {
+ float offs= tex->nabla/tex->noisesize; // also scaling of texvec
+
+ /* calculate bumpnormal */
+ texres->nor[0] = tex->ns_outscale*mgravefunc(texvec[0] + offs, texvec[1], texvec[2], tex->mg_H, tex->mg_lacunarity, tex->mg_octaves, tex->noisebasis);
+ texres->nor[1] = tex->ns_outscale*mgravefunc(texvec[0], texvec[1] + offs, texvec[2], tex->mg_H, tex->mg_lacunarity, tex->mg_octaves, tex->noisebasis);
+ texres->nor[2] = tex->ns_outscale*mgravefunc(texvec[0], texvec[1], texvec[2] + offs, tex->mg_H, tex->mg_lacunarity, tex->mg_octaves, tex->noisebasis);
+
+ tex_normal_derivate(tex, texres);
+ rv |= TEX_NOR;
+ }
+
+ BRICONT;
+
+ return rv;
+
+}
+
+static float mg_ridgedOrHybridMFTex(Tex *tex, float *texvec, TexResult *texres)
+{
+ int rv = TEX_INT;
+ float (*mgravefunc)(float, float, float, float, float, float, float, float, int);
+
+ if (tex->stype==TEX_RIDGEDMF)
+ mgravefunc = mg_RidgedMultiFractal;
+ else
+ mgravefunc = mg_HybridMultiFractal;
+
+ texres->tin = tex->ns_outscale*mgravefunc(texvec[0], texvec[1], texvec[2], tex->mg_H, tex->mg_lacunarity, tex->mg_octaves, tex->mg_offset, tex->mg_gain, tex->noisebasis);
+
+ if (texres->nor!=NULL) {
+ float offs= tex->nabla/tex->noisesize; // also scaling of texvec
+
+ /* calculate bumpnormal */
+ texres->nor[0] = tex->ns_outscale*mgravefunc(texvec[0] + offs, texvec[1], texvec[2], tex->mg_H, tex->mg_lacunarity, tex->mg_octaves, tex->mg_offset, tex->mg_gain, tex->noisebasis);
+ texres->nor[1] = tex->ns_outscale*mgravefunc(texvec[0], texvec[1] + offs, texvec[2], tex->mg_H, tex->mg_lacunarity, tex->mg_octaves, tex->mg_offset, tex->mg_gain, tex->noisebasis);
+ texres->nor[2] = tex->ns_outscale*mgravefunc(texvec[0], texvec[1], texvec[2] + offs, tex->mg_H, tex->mg_lacunarity, tex->mg_octaves, tex->mg_offset, tex->mg_gain, tex->noisebasis);
+
+ tex_normal_derivate(tex, texres);
+ rv |= TEX_NOR;
+ }
+
+ BRICONT;
+
+ return rv;
+
+}
+
+
+static float mg_HTerrainTex(Tex *tex, float *texvec, TexResult *texres)
+{
+ int rv = TEX_INT;
+
+ texres->tin = tex->ns_outscale*mg_HeteroTerrain(texvec[0], texvec[1], texvec[2], tex->mg_H, tex->mg_lacunarity, tex->mg_octaves, tex->mg_offset, tex->noisebasis);
+
+ if (texres->nor!=NULL) {
+ float offs= tex->nabla/tex->noisesize; // also scaling of texvec
+
+ /* calculate bumpnormal */
+ texres->nor[0] = tex->ns_outscale*mg_HeteroTerrain(texvec[0] + offs, texvec[1], texvec[2], tex->mg_H, tex->mg_lacunarity, tex->mg_octaves, tex->mg_offset, tex->noisebasis);
+ texres->nor[1] = tex->ns_outscale*mg_HeteroTerrain(texvec[0], texvec[1] + offs, texvec[2], tex->mg_H, tex->mg_lacunarity, tex->mg_octaves, tex->mg_offset, tex->noisebasis);
+ texres->nor[2] = tex->ns_outscale*mg_HeteroTerrain(texvec[0], texvec[1], texvec[2] + offs, tex->mg_H, tex->mg_lacunarity, tex->mg_octaves, tex->mg_offset, tex->noisebasis);
+
+ tex_normal_derivate(tex, texres);
+ rv |= TEX_NOR;
+ }
+
+ BRICONT;
+
+ return rv;
+
+}
+
+
+static float mg_distNoiseTex(Tex *tex, float *texvec, TexResult *texres)
+{
+ int rv = TEX_INT;
+
+ texres->tin = mg_VLNoise(texvec[0], texvec[1], texvec[2], tex->dist_amount, tex->noisebasis, tex->noisebasis2);
+
+ if (texres->nor!=NULL) {
+ float offs= tex->nabla/tex->noisesize; // also scaling of texvec
+
+ /* calculate bumpnormal */
+ texres->nor[0] = mg_VLNoise(texvec[0] + offs, texvec[1], texvec[2], tex->dist_amount, tex->noisebasis, tex->noisebasis2);
+ texres->nor[1] = mg_VLNoise(texvec[0], texvec[1] + offs, texvec[2], tex->dist_amount, tex->noisebasis, tex->noisebasis2);
+ texres->nor[2] = mg_VLNoise(texvec[0], texvec[1], texvec[2] + offs, tex->dist_amount, tex->noisebasis, tex->noisebasis2);
+
+ tex_normal_derivate(tex, texres);
+ rv |= TEX_NOR;
+ }
+
+ BRICONT;
+
+
+ return rv;
+
+}
+
+
+/* ------------------------------------------------------------------------- */
+/* newnoise: Voronoi texture type, probably the slowest, especially with minkovsky, bumpmapping, could be done another way */
+
+static float voronoiTex(Tex *tex, float *texvec, TexResult *texres)
+{
+ int rv = TEX_INT;
+ float da[4], pa[12]; /* distance and point coordinate arrays of 4 nearest neighbours */
+ float aw1 = fabs(tex->vn_w1);
+ float aw2 = fabs(tex->vn_w2);
+ float aw3 = fabs(tex->vn_w3);
+ float aw4 = fabs(tex->vn_w4);
+ float sc = (aw1 + aw2 + aw3 + aw4);
+ if (sc!=0.f) sc = tex->ns_outscale/sc;
+
+ voronoi(texvec[0], texvec[1], texvec[2], da, pa, tex->vn_mexp, tex->vn_distm);
+ texres->tin = sc * fabs(tex->vn_w1*da[0] + tex->vn_w2*da[1] + tex->vn_w3*da[2] + tex->vn_w4*da[3]);
+
+ if (tex->vn_coltype) {
+ float ca[3]; /* cell color */
+ cellNoiseV(pa[0], pa[1], pa[2], ca);
+ texres->tr = aw1*ca[0];
+ texres->tg = aw1*ca[1];
+ texres->tb = aw1*ca[2];
+ cellNoiseV(pa[3], pa[4], pa[5], ca);
+ texres->tr += aw2*ca[0];
+ texres->tg += aw2*ca[1];
+ texres->tb += aw2*ca[2];
+ cellNoiseV(pa[6], pa[7], pa[8], ca);
+ texres->tr += aw3*ca[0];
+ texres->tg += aw3*ca[1];
+ texres->tb += aw3*ca[2];
+ cellNoiseV(pa[9], pa[10], pa[11], ca);
+ texres->tr += aw4*ca[0];
+ texres->tg += aw4*ca[1];
+ texres->tb += aw4*ca[2];
+ if (tex->vn_coltype>=2) {
+ float t1 = (da[1]-da[0])*10;
+ if (t1>1) t1=1;
+ if (tex->vn_coltype==3) t1*=texres->tin; else t1*=sc;
+ texres->tr *= t1;
+ texres->tg *= t1;
+ texres->tb *= t1;
+ }
+ else {
+ texres->tr *= sc;
+ texres->tg *= sc;
+ texres->tb *= sc;
+ }
+ }
+
+ if (texres->nor!=NULL) {
+ float offs= tex->nabla/tex->noisesize; // also scaling of texvec
+
+ /* calculate bumpnormal */
+ voronoi(texvec[0] + offs, texvec[1], texvec[2], da, pa, tex->vn_mexp, tex->vn_distm);
+ texres->nor[0] = sc * fabs(tex->vn_w1*da[0] + tex->vn_w2*da[1] + tex->vn_w3*da[2] + tex->vn_w4*da[3]);
+ voronoi(texvec[0], texvec[1] + offs, texvec[2], da, pa, tex->vn_mexp, tex->vn_distm);
+ texres->nor[1] = sc * fabs(tex->vn_w1*da[0] + tex->vn_w2*da[1] + tex->vn_w3*da[2] + tex->vn_w4*da[3]);
+ voronoi(texvec[0], texvec[1], texvec[2] + offs, da, pa, tex->vn_mexp, tex->vn_distm);
+ texres->nor[2] = sc * fabs(tex->vn_w1*da[0] + tex->vn_w2*da[1] + tex->vn_w3*da[2] + tex->vn_w4*da[3]);
+
+ tex_normal_derivate(tex, texres);
+ rv |= TEX_NOR;
+ }
+
+ if (tex->vn_coltype) {
+ BRICONTRGB;
+ texres->ta = 1.0;
+ return (rv | TEX_RGB);
+ }
+
+ BRICONT;
+
+ return rv;
+
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+static int texnoise(Tex *tex, TexResult *texres)
+{
+ float div=3.0;
+ int val, ran, loop;
+
+ ran= BLI_rand();
+ val= (ran & 3);
+
+ loop= tex->noisedepth;
+ while(loop--) {
+ ran= (ran>>2);
+ val*= (ran & 3);
+ div*= 3.0;
+ }
+
+ texres->tin= ((float)val)/div;;
+
+ BRICONT;
+ return TEX_INT;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int plugintex(Tex *tex, float *texvec, float *dxt, float *dyt, int osatex, TexResult *texres)
+{
+ PluginTex *pit;
+ int rgbnor=0;
+
+ texres->tin= 0.0;
+
+ pit= tex->plugin;
+ if(pit && pit->doit) {
+ if(texres->nor) {
+ VECCOPY(pit->result+5, texres->nor);
+ }
+ if(osatex) rgbnor= ((TexDoit)pit->doit)(tex->stype, pit->data, texvec, dxt, dyt);
+ else rgbnor= ((TexDoit)pit->doit)(tex->stype, pit->data, texvec, 0, 0);
+
+ texres->tin= pit->result[0];
+
+ if(rgbnor & TEX_NOR) {
+ if(texres->nor) {
+ VECCOPY(texres->nor, pit->result+5);
+ }
+ }
+
+ if(rgbnor & TEX_RGB) {
+ texres->tr= pit->result[1];
+ texres->tg= pit->result[2];
+ texres->tb= pit->result[3];
+ texres->ta= pit->result[4];
+
+ BRICONTRGB;
+ }
+
+ BRICONT;
+ }
+
+ return rgbnor;
+}
+
+
+static int cubemap_glob(VlakRen *vlr, float x, float y, float z, float *adr1, float *adr2)
+{
+ float x1, y1, z1, nor[3];
+ int ret;
+
+ if(vlr==NULL) {
+ nor[0]= x; nor[1]= y; nor[2]= z; // use local render coord
+ }
+ else {
+ VECCOPY(nor, vlr->n);
+ }
+ MTC_Mat4Mul3Vecfl(R.viewinv, nor);
+
+ x1= fabs(nor[0]);
+ y1= fabs(nor[1]);
+ z1= fabs(nor[2]);
+
+ if(z1>=x1 && z1>=y1) {
+ *adr1 = (x + 1.0) / 2.0;
+ *adr2 = (y + 1.0) / 2.0;
+ ret= 0;
+ }
+ else if(y1>=x1 && y1>=z1) {
+ *adr1 = (x + 1.0) / 2.0;
+ *adr2 = (z + 1.0) / 2.0;
+ ret= 1;
+ }
+ else {
+ *adr1 = (y + 1.0) / 2.0;
+ *adr2 = (z + 1.0) / 2.0;
+ ret= 2;
+ }
+ return ret;
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* mtex argument only for projection switches */
+static int cubemap(MTex *mtex, VlakRen *vlr, float x, float y, float z, float *adr1, float *adr2)
+{
+ int proj[4]={0, ME_PROJXY, ME_PROJXZ, ME_PROJYZ}, ret= 0;
+
+ if(vlr) {
+ int index;
+
+ /* Mesh vertices have such flags, for others we calculate it once based on orco */
+ if((vlr->puno & (ME_PROJXY|ME_PROJXZ|ME_PROJYZ))==0) {
+ /* test for v1, vlr can be faked for baking */
+ if(vlr->v1 && vlr->v1->orco) {
+ float nor[3];
+ CalcNormFloat(vlr->v1->orco, vlr->v2->orco, vlr->v3->orco, nor);
+
+ if( fabs(nor[0])<fabs(nor[2]) && fabs(nor[1])<fabs(nor[2]) ) vlr->puno |= ME_PROJXY;
+ else if( fabs(nor[0])<fabs(nor[1]) && fabs(nor[2])<fabs(nor[1]) ) vlr->puno |= ME_PROJXZ;
+ else vlr->puno |= ME_PROJYZ;
+ }
+ else return cubemap_glob(vlr, x, y, z, adr1, adr2);
+ }
+
+ if(mtex) {
+ /* the mtex->proj{xyz} have type char. maybe this should be wider? */
+ /* casting to int ensures that the index type is right. */
+ index = (int) mtex->projx;
+ proj[index]= ME_PROJXY;
+
+ index = (int) mtex->projy;
+ proj[index]= ME_PROJXZ;
+
+ index = (int) mtex->projz;
+ proj[index]= ME_PROJYZ;
+ }
+
+ if(vlr->puno & proj[1]) {
+ *adr1 = (x + 1.0) / 2.0;
+ *adr2 = (y + 1.0) / 2.0;
+ }
+ else if(vlr->puno & proj[2]) {
+ *adr1 = (x + 1.0) / 2.0;
+ *adr2 = (z + 1.0) / 2.0;
+ ret= 1;
+ }
+ else {
+ *adr1 = (y + 1.0) / 2.0;
+ *adr2 = (z + 1.0) / 2.0;
+ ret= 2;
+ }
+ }
+ else {
+ return cubemap_glob(vlr, x, y, z, adr1, adr2);
+ }
+
+ return ret;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int cubemap_ob(Object *ob, VlakRen *vlr, float x, float y, float z, float *adr1, float *adr2)
+{
+ float x1, y1, z1, nor[3];
+ int ret;
+
+ if(vlr==NULL) return 0;
+
+ VECCOPY(nor, vlr->n);
+ if(ob) MTC_Mat4Mul3Vecfl(ob->imat, nor);
+
+ x1= fabs(nor[0]);
+ y1= fabs(nor[1]);
+ z1= fabs(nor[2]);
+
+ if(z1>=x1 && z1>=y1) {
+ *adr1 = (x + 1.0) / 2.0;
+ *adr2 = (y + 1.0) / 2.0;
+ ret= 0;
+ }
+ else if(y1>=x1 && y1>=z1) {
+ *adr1 = (x + 1.0) / 2.0;
+ *adr2 = (z + 1.0) / 2.0;
+ ret= 1;
+ }
+ else {
+ *adr1 = (y + 1.0) / 2.0;
+ *adr2 = (z + 1.0) / 2.0;
+ ret= 2;
+ }
+ return ret;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void do_2d_mapping(MTex *mtex, float *t, VlakRen *vlr, float *dxt, float *dyt)
+{
+ Tex *tex;
+ Object *ob= NULL;
+ float fx, fy, fac1, area[8];
+ int ok, proj, areaflag= 0, wrap, texco;
+
+ /* mtex variables localized, only cubemap doesn't cooperate yet... */
+ wrap= mtex->mapping;
+ tex= mtex->tex;
+ ob= mtex->object;
+ texco= mtex->texco;
+
+ if(R.osa==0) {
+
+ if(wrap==MTEX_FLAT) {
+ fx = (t[0] + 1.0) / 2.0;
+ fy = (t[1] + 1.0) / 2.0;
+ }
+ else if(wrap==MTEX_TUBE) tubemap(t[0], t[1], t[2], &fx, &fy);
+ else if(wrap==MTEX_SPHERE) spheremap(t[0], t[1], t[2], &fx, &fy);
+ else {
+ if(texco==TEXCO_OBJECT) cubemap_ob(ob, vlr, t[0], t[1], t[2], &fx, &fy);
+ else if(texco==TEXCO_GLOB) cubemap_glob(vlr, t[0], t[1], t[2], &fx, &fy);
+ else cubemap(mtex, vlr, t[0], t[1], t[2], &fx, &fy);
+ }
+
+ /* repeat */
+ if(tex->extend==TEX_REPEAT) {
+ if(tex->xrepeat>1) {
+ float origf= fx *= tex->xrepeat;
+
+ if(fx>1.0) fx -= (int)(fx);
+ else if(fx<0.0) fx+= 1-(int)(fx);
+
+ if(tex->flag & TEX_REPEAT_XMIR) {
+ int orig= (int)floor(origf);
+ if(orig & 1)
+ fx= 1.0-fx;
+ }
+ }
+ if(tex->yrepeat>1) {
+ float origf= fy *= tex->yrepeat;
+
+ if(fy>1.0) fy -= (int)(fy);
+ else if(fy<0.0) fy+= 1-(int)(fy);
+
+ if(tex->flag & TEX_REPEAT_YMIR) {
+ int orig= (int)floor(origf);
+ if(orig & 1)
+ fy= 1.0-fy;
+ }
+ }
+ }
+ /* crop */
+ if(tex->cropxmin!=0.0 || tex->cropxmax!=1.0) {
+ fac1= tex->cropxmax - tex->cropxmin;
+ fx= tex->cropxmin+ fx*fac1;
+ }
+ if(tex->cropymin!=0.0 || tex->cropymax!=1.0) {
+ fac1= tex->cropymax - tex->cropymin;
+ fy= tex->cropymin+ fy*fac1;
+ }
+
+ t[0]= fx;
+ t[1]= fy;
+ }
+ else {
+
+ if(wrap==MTEX_FLAT) {
+ fx= (t[0] + 1.0) / 2.0;
+ fy= (t[1] + 1.0) / 2.0;
+ dxt[0]/= 2.0;
+ dxt[1]/= 2.0;
+ dxt[2]/= 2.0;
+ dyt[0]/= 2.0;
+ dyt[1]/= 2.0;
+ dyt[2]/= 2.0;
+ }
+ else if ELEM(wrap, MTEX_TUBE, MTEX_SPHERE) {
+ /* exception: the seam behind (y<0.0) */
+ ok= 1;
+ if(t[1]<=0.0) {
+ fx= t[0]+dxt[0];
+ fy= t[0]+dyt[0];
+ if(fx>=0.0 && fy>=0.0 && t[0]>=0.0);
+ else if(fx<=0.0 && fy<=0.0 && t[0]<=0.0);
+ else ok= 0;
+ }
+ if(ok) {
+ if(wrap==MTEX_TUBE) {
+ tubemap(t[0], t[1], t[2], area, area+1);
+ tubemap(t[0]+dxt[0], t[1]+dxt[1], t[2]+dxt[2], area+2, area+3);
+ tubemap(t[0]+dyt[0], t[1]+dyt[1], t[2]+dyt[2], area+4, area+5);
+ }
+ else {
+ spheremap(t[0], t[1], t[2],area,area+1);
+ spheremap(t[0]+dxt[0], t[1]+dxt[1], t[2]+dxt[2], area+2, area+3);
+ spheremap(t[0]+dyt[0], t[1]+dyt[1], t[2]+dyt[2], area+4, area+5);
+ }
+ areaflag= 1;
+ }
+ else {
+ if(wrap==MTEX_TUBE) tubemap(t[0], t[1], t[2], &fx, &fy);
+ else spheremap(t[0], t[1], t[2], &fx, &fy);
+ dxt[0]/= 2.0;
+ dxt[1]/= 2.0;
+ dyt[0]/= 2.0;
+ dyt[1]/= 2.0;
+ }
+ }
+ else {
+
+ if(texco==TEXCO_OBJECT) proj = cubemap_ob(ob, vlr, t[0], t[1], t[2], &fx, &fy);
+ else if (texco==TEXCO_GLOB) proj = cubemap_glob(vlr, t[0], t[1], t[2], &fx, &fy);
+ else proj = cubemap(mtex, vlr, t[0], t[1], t[2], &fx, &fy);
+
+ if(proj==1) {
+ SWAP(float, dxt[1], dxt[2]);
+ SWAP(float, dyt[1], dyt[2]);
+ }
+ else if(proj==2) {
+ float f1= dxt[0], f2= dyt[0];
+ dxt[0]= dxt[1];
+ dyt[0]= dyt[1];
+ dxt[1]= dxt[2];
+ dyt[1]= dyt[2];
+ dxt[2]= f1;
+ dyt[2]= f2;
+ }
+ dxt[0]/= 2.0;
+ dxt[1]/= 2.0;
+ dxt[2]/= 2.0;
+
+ dyt[0]/= 2.0;
+ dyt[1]/= 2.0;
+ dyt[2]/= 2.0;
+ }
+
+ /* if area, then reacalculate dxt[] and dyt[] */
+ if(areaflag) {
+ fx= area[0];
+ fy= area[1];
+ dxt[0]= area[2]-fx;
+ dxt[1]= area[3]-fy;
+ dyt[0]= area[4]-fx;
+ dyt[1]= area[5]-fy;
+ }
+
+ /* repeat */
+ if(tex->extend==TEX_REPEAT) {
+ float max= 1.0f;
+ if(tex->xrepeat>1) {
+ float origf= fx *= tex->xrepeat;
+
+ if(fx>1.0f) fx -= (int)(fx);
+ else if(fx<0.0f) fx+= 1-(int)(fx);
+
+ if(tex->flag & TEX_REPEAT_XMIR) {
+ int orig= (int)floor(origf);
+ if(orig & 1)
+ fx= 1.0f-fx;
+ }
+
+ max= tex->xrepeat;
+
+ dxt[0]*= tex->xrepeat;
+ dyt[0]*= tex->xrepeat;
+ }
+ if(tex->yrepeat>1) {
+ float origf= fy *= tex->yrepeat;
+
+ if(fy>1.0f) fy -= (int)(fy);
+ else if(fy<0.0f) fy+= 1-(int)(fy);
+
+ if(tex->flag & TEX_REPEAT_YMIR) {
+ int orig= (int)floor(origf);
+ if(orig & 1)
+ fy= 1.0f-fy;
+ }
+
+ if(max<tex->yrepeat)
+ max= tex->yrepeat;
+
+ dxt[1]*= tex->yrepeat;
+ dyt[1]*= tex->yrepeat;
+ }
+ if(max!=1.0f) {
+ dxt[2]*= max;
+ dyt[2]*= max;
+ }
+
+ }
+ /* crop */
+ if(tex->cropxmin!=0.0 || tex->cropxmax!=1.0) {
+ fac1= tex->cropxmax - tex->cropxmin;
+ fx= tex->cropxmin+ fx*fac1;
+ dxt[0]*= fac1;
+ dyt[0]*= fac1;
+ }
+ if(tex->cropymin!=0.0 || tex->cropymax!=1.0) {
+ fac1= tex->cropymax - tex->cropymin;
+ fy= tex->cropymin+ fy*fac1;
+ dxt[1]*= fac1;
+ dyt[1]*= fac1;
+ }
+
+ t[0]= fx;
+ t[1]= fy;
+
+ }
+}
+
+/* ************************************** */
+
+static int multitex(Tex *tex, float *texvec, float *dxt, float *dyt, int osatex, TexResult *texres)
+{
+ float tmpvec[3];
+ int retval=0; /* return value, int:0, col:1, nor:2, everything:3 */
+
+ texres->talpha= 0; /* is set when image texture returns alpha (considered premul) */
+
+ switch(tex->type) {
+
+ case 0:
+ texres->tin= 0.0f;
+ return 0;
+ case TEX_CLOUDS:
+ retval= clouds(tex, texvec, texres);
+ break;
+ case TEX_WOOD:
+ retval= wood(tex, texvec, texres);
+ break;
+ case TEX_MARBLE:
+ retval= marble(tex, texvec, texres);
+ break;
+ case TEX_MAGIC:
+ retval= magic(tex, texvec, texres);
+ break;
+ case TEX_BLEND:
+ retval= blend(tex, texvec, texres);
+ break;
+ case TEX_STUCCI:
+ retval= stucci(tex, texvec, texres);
+ break;
+ case TEX_NOISE:
+ retval= texnoise(tex, texres);
+ break;
+ case TEX_IMAGE:
+ if(osatex) retval= imagewraposa(tex, tex->ima, NULL, texvec, dxt, dyt, texres);
+ else retval= imagewrap(tex, tex->ima, NULL, texvec, texres);
+ tag_image_time(tex->ima); /* tag image as having being used */
+ break;
+ case TEX_PLUGIN:
+ retval= plugintex(tex, texvec, dxt, dyt, osatex, texres);
+ break;
+ case TEX_ENVMAP:
+ retval= envmaptex(tex, texvec, dxt, dyt, osatex, texres);
+ break;
+ case TEX_MUSGRAVE:
+ /* newnoise: musgrave types */
+
+ /* ton: added this, for Blender convention reason.
+ * artificer: added the use of tmpvec to avoid scaling texvec
+ */
+ VECCOPY(tmpvec, texvec);
+ VecMulf(tmpvec, 1.0/tex->noisesize);
+
+ switch(tex->stype) {
+ case TEX_MFRACTAL:
+ case TEX_FBM:
+ retval= mg_mFractalOrfBmTex(tex, tmpvec, texres);
+ break;
+ case TEX_RIDGEDMF:
+ case TEX_HYBRIDMF:
+ retval= mg_ridgedOrHybridMFTex(tex, tmpvec, texres);
+ break;
+ case TEX_HTERRAIN:
+ retval= mg_HTerrainTex(tex, tmpvec, texres);
+ break;
+ }
+ break;
+ /* newnoise: voronoi type */
+ case TEX_VORONOI:
+ /* ton: added this, for Blender convention reason.
+ * artificer: added the use of tmpvec to avoid scaling texvec
+ */
+ VECCOPY(tmpvec, texvec);
+ VecMulf(tmpvec, 1.0/tex->noisesize);
+
+ retval= voronoiTex(tex, tmpvec, texres);
+ break;
+ case TEX_DISTNOISE:
+ /* ton: added this, for Blender convention reason.
+ * artificer: added the use of tmpvec to avoid scaling texvec
+ */
+ VECCOPY(tmpvec, texvec);
+ VecMulf(tmpvec, 1.0/tex->noisesize);
+
+ retval= mg_distNoiseTex(tex, tmpvec, texres);
+ break;
+ }
+
+ if (tex->flag & TEX_COLORBAND) {
+ float col[4];
+ if (do_colorband(tex->coba, texres->tin, col)) {
+ texres->talpha= 1;
+ texres->tr= col[0];
+ texres->tg= col[1];
+ texres->tb= col[2];
+ texres->ta= col[3];
+ retval |= 1;
+ }
+ }
+ return retval;
+}
+
+int multitex_ext(Tex *tex, float *texvec, float *dxt, float *dyt, int osatex, TexResult *texres)
+{
+
+ if(tex==NULL) {
+ memset(texres, 0, sizeof(TexResult));
+ return 0;
+ }
+
+ /* Image requires 2d mapping conversion */
+ if(tex->type==TEX_IMAGE) {
+ MTex mtex;
+ float texvec_l[3], dxt_l[3], dyt_l[3];
+
+ mtex.mapping= MTEX_FLAT;
+ mtex.tex= tex;
+ mtex.object= NULL;
+ mtex.texco= TEXCO_ORCO;
+
+ VECCOPY(texvec_l, texvec);
+ if(dxt && dyt) {
+ VECCOPY(dxt_l, dxt);
+ VECCOPY(dyt_l, dyt);
+ }
+ else {
+ dxt_l[0]= dxt_l[1]= dxt_l[2]= 0.0f;
+ dyt_l[0]= dyt_l[1]= dyt_l[2]= 0.0f;
+ }
+
+ do_2d_mapping(&mtex, texvec_l, NULL, dxt_l, dyt_l);
+
+ return multitex(tex, texvec_l, dxt_l, dyt_l, osatex, texres);
+ }
+ else
+ return multitex(tex, texvec, dxt, dyt, osatex, texres);
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* in = destination, tex = texture, out = previous color */
+/* fact = texture strength, facg = button strength value */
+static void texture_rgb_blend(float *in, float *tex, float *out, float fact, float facg, int blendtype)
+{
+ float facm, col;
+
+ switch(blendtype) {
+ case MTEX_BLEND:
+ fact*= facg;
+ facm= 1.0-fact;
+
+ in[0]= (fact*tex[0] + facm*out[0]);
+ in[1]= (fact*tex[1] + facm*out[1]);
+ in[2]= (fact*tex[2] + facm*out[2]);
+ break;
+
+ case MTEX_MUL:
+ fact*= facg;
+ facm= 1.0-facg;
+ in[0]= (facm+fact*tex[0])*out[0];
+ in[1]= (facm+fact*tex[1])*out[1];
+ in[2]= (facm+fact*tex[2])*out[2];
+ break;
+
+ case MTEX_SCREEN:
+ fact*= facg;
+ facm= 1.0-facg;
+ in[0]= 1.0 - (facm+fact*(1.0-tex[0])) * (1.0-out[0]);
+ in[1]= 1.0 - (facm+fact*(1.0-tex[1])) * (1.0-out[1]);
+ in[2]= 1.0 - (facm+fact*(1.0-tex[2])) * (1.0-out[2]);
+ break;
+
+ case MTEX_SUB:
+ fact= -fact;
+ case MTEX_ADD:
+ fact*= facg;
+ in[0]= (fact*tex[0] + out[0]);
+ in[1]= (fact*tex[1] + out[1]);
+ in[2]= (fact*tex[2] + out[2]);
+ break;
+
+ case MTEX_DIV:
+ fact*= facg;
+ facm= 1.0-fact;
+
+ if(tex[0]!=0.0)
+ in[0]= facm*out[0] + fact*out[0]/tex[0];
+ if(tex[1]!=0.0)
+ in[1]= facm*out[1] + fact*out[1]/tex[1];
+ if(tex[2]!=0.0)
+ in[2]= facm*out[2] + fact*out[2]/tex[2];
+
+ break;
+
+ case MTEX_DIFF:
+ fact*= facg;
+ facm= 1.0-fact;
+ in[0]= facm*out[0] + fact*fabs(tex[0]-out[0]);
+ in[1]= facm*out[1] + fact*fabs(tex[1]-out[1]);
+ in[2]= facm*out[2] + fact*fabs(tex[2]-out[2]);
+ break;
+
+ case MTEX_DARK:
+ fact*= facg;
+ facm= 1.0-fact;
+
+ col= fact*tex[0];
+ if(col < out[0]) in[0]= col; else in[0]= out[0];
+ col= fact*tex[1];
+ if(col < out[1]) in[1]= col; else in[1]= out[1];
+ col= fact*tex[2];
+ if(col < out[2]) in[2]= col; else in[2]= out[2];
+ break;
+
+ case MTEX_LIGHT:
+ fact*= facg;
+ facm= 1.0-fact;
+
+ col= fact*tex[0];
+ if(col > out[0]) in[0]= col; else in[0]= out[0];
+ col= fact*tex[1];
+ if(col > out[1]) in[1]= col; else in[1]= out[1];
+ col= fact*tex[2];
+ if(col > out[2]) in[2]= col; else in[2]= out[2];
+ break;
+ }
+
+
+}
+
+static float texture_value_blend(float tex, float out, float fact, float facg, int blendtype, int flip)
+{
+ float in=0.0, facm, col;
+
+ fact*= facg;
+ facm= 1.0-fact;
+ if(flip) SWAP(float, fact, facm);
+
+ switch(blendtype) {
+ case MTEX_BLEND:
+ in= fact*tex + facm*out;
+ break;
+
+ case MTEX_MUL:
+ facm= 1.0-facg;
+ in= (facm+fact*tex)*out;
+ break;
+
+ case MTEX_SCREEN:
+ facm= 1.0-facg;
+ in= 1.0-(facm+fact*(1.0-tex))*(1.0-out);
+ break;
+
+ case MTEX_SUB:
+ fact= -fact;
+ case MTEX_ADD:
+ in= fact*tex + out;
+ break;
+
+ case MTEX_DIV:
+ if(tex!=0.0)
+ in= facm*out + fact*out/tex;
+ break;
+
+ case MTEX_DIFF:
+ in= facm*out + fact*fabs(tex-out);
+ break;
+
+ case MTEX_DARK:
+ col= fact*tex;
+ if(col < out) in= col; else in= out;
+ break;
+
+ case MTEX_LIGHT:
+ col= fact*tex;
+ if(col > out) in= col; else in= out;
+ break;
+ }
+
+ return in;
+}
+
+
+void do_material_tex(ShadeInput *shi)
+{
+ MTex *mtex;
+ Tex *tex;
+ TexResult texres= {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, NULL};
+ float *co = NULL, *dx = NULL, *dy = NULL;
+ float fact, facm, factt, facmm, stencilTin=1.0;
+ float texvec[3], dxt[3], dyt[3], tempvec[3], norvec[3], warpvec[3]={0.0f, 0.0f, 0.0f}, Tnor=1.0;
+ int tex_nr, rgbnor= 0, warpdone=0;
+
+ if (R.r.scemode & R_NO_TEX) return;
+ /* here: test flag if there's a tex (todo) */
+
+ for(tex_nr=0; tex_nr<MAX_MTEX; tex_nr++) {
+
+ /* separate tex switching */
+ if(shi->mat->septex & (1<<tex_nr)) continue;
+
+ if(shi->mat->mtex[tex_nr]) {
+ mtex= shi->mat->mtex[tex_nr];
+
+ tex= mtex->tex;
+ if(tex==0) continue;
+
+ /* which coords */
+ if(mtex->texco==TEXCO_ORCO) {
+ co= shi->lo; dx= shi->dxlo; dy= shi->dylo;
+ }
+ else if(mtex->texco==TEXCO_STICKY) {
+ co= shi->sticky; dx= shi->dxsticky; dy= shi->dysticky;
+ }
+ else if(mtex->texco==TEXCO_OBJECT) {
+ Object *ob= mtex->object;
+ if(ob) {
+ co= tempvec;
+ dx= dxt;
+ dy= dyt;
+ VECCOPY(tempvec, shi->co);
+ MTC_Mat4MulVecfl(ob->imat, tempvec);
+ if(shi->osatex) {
+ VECCOPY(dxt, shi->dxco);
+ VECCOPY(dyt, shi->dyco);
+ MTC_Mat4Mul3Vecfl(ob->imat, dxt);
+ MTC_Mat4Mul3Vecfl(ob->imat, dyt);
+ }
+ }
+ else {
+ /* if object doesn't exist, do not use orcos (not initialized) */
+ co= shi->co;
+ dx= shi->dxco; dy= shi->dyco;
+ }
+ }
+ else if(mtex->texco==TEXCO_REFL) {
+ co= shi->ref; dx= shi->dxref; dy= shi->dyref;
+ }
+ else if(mtex->texco==TEXCO_NORM) {
+ co= shi->orn; dx= shi->dxno; dy= shi->dyno;
+ }
+ else if(mtex->texco==TEXCO_TANGENT) {
+ co= shi->tang; dx= shi->dxno; dy= shi->dyno;
+ }
+ else if(mtex->texco==TEXCO_GLOB) {
+ co= shi->gl; dx= shi->dxco; dy= shi->dyco;
+ }
+ else if(mtex->texco==TEXCO_UV) {
+ ShadeInputUV *suv= &shi->uv[0];
+ int i;
+
+ if(mtex->uvname[0] != 0) {
+ for(i = 0; i < shi->totuv; i++) {
+ if(strcmp(shi->uv[i].name, mtex->uvname)==0) {
+ suv= &shi->uv[i];
+ break;
+ }
+ }
+ }
+
+ co= suv->uv;
+ dx= suv->dxuv;
+ dy= suv->dyuv;
+ }
+ else if(mtex->texco==TEXCO_WINDOW) {
+ co= shi->winco; dx= shi->dxwin; dy= shi->dywin;
+ }
+ else if(mtex->texco==TEXCO_STRAND) {
+ co= tempvec; dx= dxt; dy= dyt;
+ co[0]= shi->strand;
+ co[1]= co[2]= 0.0f;
+ dx[0]= shi->dxstrand;
+ dx[1]= dx[2]= 0.0f;
+ dy[0]= shi->dystrand;
+ dy[1]= dy[2]= 0.0f;
+ }
+ else if(mtex->texco==TEXCO_STRESS) {
+ co= tempvec; dx= dxt; dy= dyt;
+ co[0]= shi->stress;
+ co[1]= co[2]= 0.0f;
+ dx[0]= 0.0f;
+ dx[1]= dx[2]= 0.0f;
+ dy[0]= 0.0f;
+ dy[1]= dy[2]= 0.0f;
+ }
+ else continue; // can happen when texco defines disappear and it renders old files
+
+ /* de pointer defines if bumping happens */
+ if(mtex->mapto & (MAP_NORM|MAP_DISPLACE|MAP_WARP)) {
+ texres.nor= norvec;
+ norvec[0]= norvec[1]= norvec[2]= 0.0;
+ }
+ else texres.nor= NULL;
+
+ if(warpdone) {
+ VECADD(tempvec, co, warpvec);
+ co= tempvec;
+ }
+
+ if(tex->type==TEX_IMAGE) {
+
+ /* new: first swap coords, then map, then trans/scale */
+
+ /* placement */
+ if(mtex->projx) texvec[0]= co[mtex->projx-1];
+ else texvec[0]= 0.0;
+ if(mtex->projy) texvec[1]= co[mtex->projy-1];
+ else texvec[1]= 0.0;
+ if(mtex->projz) texvec[2]= co[mtex->projz-1];
+ else texvec[2]= 0.0;
+
+ if(shi->osatex) {
+
+ if(mtex->projx) {
+ dxt[0]= dx[mtex->projx-1];
+ dyt[0]= dy[mtex->projx-1];
+ }
+ else dxt[0]= dyt[0]= 0.0f;
+
+ if(mtex->projy) {
+ dxt[1]= dx[mtex->projy-1];
+ dyt[1]= dy[mtex->projy-1];
+ }
+ else dxt[1]= dyt[1]= 0.0f;
+ if(mtex->projz) {
+ dxt[2]= dx[mtex->projz-1];
+ dyt[2]= dy[mtex->projz-1];
+ }
+ else dxt[2]= dyt[2]= 0.0;
+ }
+
+ do_2d_mapping(mtex, texvec, shi->vlr, dxt, dyt);
+
+ /* translate and scale */
+ texvec[0]= mtex->size[0]*(texvec[0]-0.5) +mtex->ofs[0]+0.5;
+ texvec[1]= mtex->size[1]*(texvec[1]-0.5) +mtex->ofs[1]+0.5;
+ if(shi->osatex) {
+ dxt[0]= mtex->size[0]*dxt[0];
+ dxt[1]= mtex->size[1]*dxt[1];
+ dyt[0]= mtex->size[0]*dyt[0];
+ dyt[1]= mtex->size[1]*dyt[1];
+ }
+
+ /* problem: repeat-mirror is not a 'repeat' but 'extend' in imagetexture.c */
+ if(tex->flag & TEX_REPEAT_XMIR) {
+ if(texvec[0]>1.0f) texvec[0] -= (int)(texvec[0]);
+ else if(texvec[0]<0.0f) texvec[0]+= 1-(int)(texvec[0]);
+ }
+ if(tex->flag & TEX_REPEAT_YMIR) {
+ if(texvec[1]>1.0f) texvec[1] -= (int)(texvec[1]);
+ else if(texvec[1]<0.0f) texvec[1]+= 1-(int)(texvec[1]);
+ }
+
+ }
+ else {
+
+ /* placement */
+ if(mtex->projx) texvec[0]= mtex->size[0]*(co[mtex->projx-1]+mtex->ofs[0]);
+ else texvec[0]= mtex->size[0]*(mtex->ofs[0]);
+
+ if(mtex->projy) texvec[1]= mtex->size[1]*(co[mtex->projy-1]+mtex->ofs[1]);
+ else texvec[1]= mtex->size[1]*(mtex->ofs[1]);
+
+ if(mtex->projz) texvec[2]= mtex->size[2]*(co[mtex->projz-1]+mtex->ofs[2]);
+ else texvec[2]= mtex->size[2]*(mtex->ofs[2]);
+
+ if(shi->osatex) {
+ if(mtex->projx) {
+ dxt[0]= mtex->size[0]*dx[mtex->projx-1];
+ dyt[0]= mtex->size[0]*dy[mtex->projx-1];
+ }
+ else dxt[0]= 0.0;
+ if(mtex->projy) {
+ dxt[1]= mtex->size[1]*dx[mtex->projy-1];
+ dyt[1]= mtex->size[1]*dy[mtex->projy-1];
+ }
+ else dxt[1]= 0.0;
+ if(mtex->projz) {
+ dxt[2]= mtex->size[2]*dx[mtex->projz-1];
+ dyt[2]= mtex->size[2]*dy[mtex->projz-1];
+ }
+ else dxt[2]= 0.0;
+ }
+ }
+
+ rgbnor= multitex(tex, texvec, dxt, dyt, shi->osatex, &texres);
+
+ /* texture output */
+
+ if( (rgbnor & TEX_RGB) && (mtex->texflag & MTEX_RGBTOINT)) {
+ texres.tin= (0.35*texres.tr+0.45*texres.tg+0.2*texres.tb);
+ rgbnor-= TEX_RGB;
+ }
+ if(mtex->texflag & MTEX_NEGATIVE) {
+ if(rgbnor & TEX_RGB) {
+ texres.tr= 1.0-texres.tr;
+ texres.tg= 1.0-texres.tg;
+ texres.tb= 1.0-texres.tb;
+ }
+ texres.tin= 1.0-texres.tin;
+ }
+ if(mtex->texflag & MTEX_STENCIL) {
+ if(rgbnor & TEX_RGB) {
+ fact= texres.ta;
+ texres.ta*= stencilTin;
+ stencilTin*= fact;
+ }
+ else {
+ fact= texres.tin;
+ texres.tin*= stencilTin;
+ stencilTin*= fact;
+ }
+ }
+ else {
+ Tnor*= stencilTin;
+ }
+
+ if(texres.nor) {
+ if((rgbnor & TEX_NOR)==0) {
+ /* make our own normal */
+ if(rgbnor & TEX_RGB) {
+ texres.nor[0]= texres.tr;
+ texres.nor[1]= texres.tg;
+ texres.nor[2]= texres.tb;
+ }
+ else {
+ float co= 0.5*cos(texres.tin-0.5);
+ float si= 0.5*sin(texres.tin-0.5);
+ float f1, f2;
+
+ f1= shi->vn[0];
+ f2= shi->vn[1];
+ texres.nor[0]= f1*co+f2*si;
+ texres.nor[1]= f2*co-f1*si;
+ f1= shi->vn[1];
+ f2= shi->vn[2];
+ texres.nor[1]= f1*co+f2*si;
+ texres.nor[2]= f2*co-f1*si;
+ }
+ }
+ // warping, local space
+ if(mtex->mapto & MAP_WARP) {
+ warpvec[0]= mtex->warpfac*texres.nor[0];
+ warpvec[1]= mtex->warpfac*texres.nor[1];
+ warpvec[2]= mtex->warpfac*texres.nor[2];
+ warpdone= 1;
+ }
+#if 0
+ if(mtex->texflag & MTEX_VIEWSPACE) {
+ // rotate to global coords
+ if(mtex->texco==TEXCO_ORCO || mtex->texco==TEXCO_UV) {
+ if(shi->vlr && shi->vlr->ob) {
+ float len= Normalize(texres.nor);
+ // can be optimized... (ton)
+ Mat4Mul3Vecfl(shi->vlr->ob->obmat, texres.nor);
+ Mat4Mul3Vecfl(R.viewmat, texres.nor);
+ Normalize(texres.nor);
+ VecMulf(texres.nor, len);
+ }
+ }
+ }
+#endif
+ }
+
+ /* mapping */
+ if(mtex->mapto & (MAP_COL+MAP_COLSPEC+MAP_COLMIR)) {
+ float tcol[3], colfac;
+
+ /* stencil maps on the texture control slider, not texture intensity value */
+ colfac= mtex->colfac*stencilTin;
+
+ tcol[0]=texres.tr; tcol[1]=texres.tg; tcol[2]=texres.tb;
+
+ if((rgbnor & TEX_RGB)==0) {
+ tcol[0]= mtex->r;
+ tcol[1]= mtex->g;
+ tcol[2]= mtex->b;
+ }
+ else if(mtex->mapto & MAP_ALPHA) {
+ texres.tin= stencilTin;
+ }
+ else texres.tin= texres.ta;
+
+ if(mtex->mapto & MAP_COL) {
+ texture_rgb_blend(&shi->r, tcol, &shi->r, texres.tin, colfac, mtex->blendtype);
+ }
+ if(mtex->mapto & MAP_COLSPEC) {
+ texture_rgb_blend(&shi->specr, tcol, &shi->specr, texres.tin, colfac, mtex->blendtype);
+ }
+ if(mtex->mapto & MAP_COLMIR) {
+ // exception for envmap only
+ if(tex->type==TEX_ENVMAP && mtex->blendtype==MTEX_BLEND) {
+ fact= texres.tin*colfac;
+ facm= 1.0- fact;
+ shi->refcol[0]= fact + facm*shi->refcol[0];
+ shi->refcol[1]= fact*tcol[0] + facm*shi->refcol[1];
+ shi->refcol[2]= fact*tcol[1] + facm*shi->refcol[2];
+ shi->refcol[3]= fact*tcol[2] + facm*shi->refcol[3];
+ }
+ else {
+ texture_rgb_blend(&shi->mirr, tcol, &shi->mirr, texres.tin, colfac, mtex->blendtype);
+ }
+ }
+ }
+ if( (mtex->mapto & MAP_NORM) ) {
+ if(texres.nor) {
+
+ if(mtex->maptoneg & MAP_NORM) tex->norfac= -mtex->norfac;
+ else tex->norfac= mtex->norfac;
+
+ /* we need to code blending modes for normals too once.. now 1 exception hardcoded */
+
+ if ((tex->type==TEX_IMAGE) && (tex->imaflag & TEX_NORMALMAP)) {
+ /* qdn: for normalmaps, to invert the normalmap vector,
+ it is better to negate x & y instead of subtracting the vector as was done before */
+ tex->norfac = mtex->norfac;
+ if (mtex->maptoneg & MAP_NORM) {
+ texres.nor[0] = -texres.nor[0];
+ texres.nor[1] = -texres.nor[1];
+ }
+ fact = Tnor*tex->norfac;
+ if (fact>1.f) fact = 1.f;
+ facm = 1.f-fact;
+ if (shi->mat->mode & MA_NORMAP_TANG) {
+ /* qdn: tangent space */
+ float B[3], tv[3];
+ Crossf(B, shi->vn, shi->tang); /* bitangent */
+ /* transform norvec from tangent space to object surface in camera space */
+ tv[0] = texres.nor[0]*shi->tang[0] + texres.nor[1]*B[0] + texres.nor[2]*shi->vn[0];
+ tv[1] = texres.nor[0]*shi->tang[1] + texres.nor[1]*B[1] + texres.nor[2]*shi->vn[1];
+ tv[2] = texres.nor[0]*shi->tang[2] + texres.nor[1]*B[2] + texres.nor[2]*shi->vn[2];
+ shi->vn[0]= facm*shi->vn[0] + fact*tv[0];
+ shi->vn[1]= facm*shi->vn[1] + fact*tv[1];
+ shi->vn[2]= facm*shi->vn[2] + fact*tv[2];
+ }
+ else {
+ /* qdn: worldspace */
+ shi->vn[0]= facm*shi->vn[0] + fact*texres.nor[0];
+ shi->vn[1]= facm*shi->vn[1] + fact*texres.nor[1];
+ shi->vn[2]= facm*shi->vn[2] + fact*texres.nor[2];
+ }
+ }
+ else {
+ if(shi->mat->mode & MA_TANGENT_V) {
+ shi->tang[0]+= Tnor*tex->norfac*texres.nor[0];
+ shi->tang[1]+= Tnor*tex->norfac*texres.nor[1];
+ shi->tang[2]+= Tnor*tex->norfac*texres.nor[2];
+ }
+ else {
+ float nor[3], dot;
+ /* prevent bump to become negative normal */
+ nor[0]= Tnor*tex->norfac*texres.nor[0];
+ nor[1]= Tnor*tex->norfac*texres.nor[1];
+ nor[2]= Tnor*tex->norfac*texres.nor[2];
+
+ dot= 0.5f + 0.5f*INPR(nor, shi->vn);
+
+ shi->vn[0]+= dot*nor[0];
+ shi->vn[1]+= dot*nor[1];
+ shi->vn[2]+= dot*nor[2];
+ }
+ }
+ Normalize(shi->vn);
+
+ /* this makes sure the bump is passed on to the next texture */
+ shi->orn[0]= -shi->vn[0];
+ shi->orn[1]= -shi->vn[1];
+ shi->orn[2]= -shi->vn[2];
+
+ /* reflection vector */
+ calc_R_ref(shi);
+ }
+ }
+
+ if( mtex->mapto & MAP_DISPLACE ) {
+ /* Now that most textures offer both Nor and Intensity, allow */
+ /* both to work, and let user select with slider. */
+ if(texres.nor) {
+ if(mtex->maptoneg & MAP_DISPLACE) tex->norfac= -mtex->norfac;
+ else tex->norfac= mtex->norfac;
+
+ shi->displace[0]+= 0.2f*Tnor*tex->norfac*texres.nor[0];
+ shi->displace[1]+= 0.2f*Tnor*tex->norfac*texres.nor[1];
+ shi->displace[2]+= 0.2f*Tnor*tex->norfac*texres.nor[2];
+ }
+
+ if(rgbnor & TEX_RGB) {
+ if(texres.talpha) texres.tin= texres.ta;
+ else texres.tin= (0.35f*texres.tr+0.45f*texres.tg+0.2f*texres.tb);
+ }
+
+ if(mtex->maptoneg & MAP_DISPLACE) {
+ factt= (texres.tin-0.5f)*mtex->dispfac*stencilTin; facmm= 1.0f-factt;
+ }
+ else {
+ factt= (0.5f-texres.tin)*mtex->dispfac*stencilTin; facmm= 1.0f-factt;
+ }
+
+ if(mtex->blendtype==MTEX_BLEND) {
+ shi->displace[0]= factt*shi->vn[0] + facmm*shi->displace[0];
+ shi->displace[1]= factt*shi->vn[1] + facmm*shi->displace[1];
+ shi->displace[2]= factt*shi->vn[2] + facmm*shi->displace[2];
+ }
+ else if(mtex->blendtype==MTEX_MUL) {
+ shi->displace[0]*= factt*shi->vn[0];
+ shi->displace[1]*= factt*shi->vn[1];
+ shi->displace[2]*= factt*shi->vn[2];
+ }
+ else { /* add or sub */
+ if(mtex->blendtype==MTEX_SUB) factt= -factt;
+ else factt= factt;
+ shi->displace[0]+= factt*shi->vn[0];
+ shi->displace[1]+= factt*shi->vn[1];
+ shi->displace[2]+= factt*shi->vn[2];
+ }
+ }
+
+ if(mtex->mapto & MAP_VARS) {
+ /* stencil maps on the texture control slider, not texture intensity value */
+ float varfac= mtex->varfac*stencilTin;
+
+ if(rgbnor & TEX_RGB) {
+ if(texres.talpha) texres.tin= texres.ta;
+ else texres.tin= (0.35*texres.tr+0.45*texres.tg+0.2*texres.tb);
+ }
+
+ if(mtex->mapto & MAP_REF) {
+ int flip= mtex->maptoneg & MAP_REF;
+
+ shi->refl= texture_value_blend(mtex->def_var, shi->refl, texres.tin, varfac, mtex->blendtype, flip);
+ if(shi->refl<0.0) shi->refl= 0.0;
+ }
+ if(mtex->mapto & MAP_SPEC) {
+ int flip= mtex->maptoneg & MAP_SPEC;
+
+ shi->spec= texture_value_blend(mtex->def_var, shi->spec, texres.tin, varfac, mtex->blendtype, flip);
+ if(shi->spec<0.0) shi->spec= 0.0;
+ }
+ if(mtex->mapto & MAP_EMIT) {
+ int flip= mtex->maptoneg & MAP_EMIT;
+
+ shi->emit= texture_value_blend(mtex->def_var, shi->emit, texres.tin, varfac, mtex->blendtype, flip);
+ if(shi->emit<0.0) shi->emit= 0.0;
+ }
+ if(mtex->mapto & MAP_ALPHA) {
+ int flip= mtex->maptoneg & MAP_ALPHA;
+
+ shi->alpha= texture_value_blend(mtex->def_var, shi->alpha, texres.tin, varfac, mtex->blendtype, flip);
+ if(shi->alpha<0.0) shi->alpha= 0.0;
+ else if(shi->alpha>1.0) shi->alpha= 1.0;
+ }
+ if(mtex->mapto & MAP_HAR) {
+ int flip= mtex->maptoneg & MAP_HAR;
+ float har; // have to map to 0-1
+
+ har= ((float)shi->har)/128.0;
+ har= 128.0*texture_value_blend(mtex->def_var, har, texres.tin, varfac, mtex->blendtype, flip);
+
+ if(har<1.0) shi->har= 1;
+ else if(har>511.0) shi->har= 511;
+ else shi->har= (int)har;
+ }
+ if(mtex->mapto & MAP_RAYMIRR) {
+ int flip= mtex->maptoneg & MAP_RAYMIRR;
+
+ shi->ray_mirror= texture_value_blend(mtex->def_var, shi->ray_mirror, texres.tin, varfac, mtex->blendtype, flip);
+ if(shi->ray_mirror<0.0) shi->ray_mirror= 0.0;
+ else if(shi->ray_mirror>1.0) shi->ray_mirror= 1.0;
+ }
+ if(mtex->mapto & MAP_TRANSLU) {
+ int flip= mtex->maptoneg & MAP_TRANSLU;
+
+ shi->translucency= texture_value_blend(mtex->def_var, shi->translucency, texres.tin, varfac, mtex->blendtype, flip);
+ if(shi->translucency<0.0) shi->translucency= 0.0;
+ else if(shi->translucency>1.0) shi->translucency= 1.0;
+ }
+ if(mtex->mapto & MAP_LAYER) {
+ int flip= mtex->maptoneg & MAP_LAYER;
+
+ shi->layerfac= texture_value_blend(mtex->def_var, shi->layerfac, texres.tin, varfac, mtex->blendtype, flip);
+ if(shi->layerfac<0.0) shi->layerfac= 0.0;
+ else if(shi->layerfac>1.0) shi->layerfac= 1.0;
+ }
+ if(mtex->mapto & MAP_AMB) {
+ int flip= mtex->maptoneg & MAP_AMB;
+
+ shi->amb= texture_value_blend(mtex->def_var, shi->amb, texres.tin, varfac, mtex->blendtype, flip);
+ if(shi->amb<0.0) shi->amb= 0.0;
+ else if(shi->amb>1.0) shi->amb= 1.0;
+ }
+ }
+ }
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+void do_halo_tex(HaloRen *har, float xn, float yn, float *colf)
+{
+ MTex *mtex;
+ TexResult texres= {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, NULL};
+ float texvec[3], dxt[3], dyt[3], fact, facm, dx;
+ int rgb, osatex;
+
+ if (R.r.scemode & R_NO_TEX) return;
+
+ mtex= har->mat->mtex[0];
+ if(mtex->tex==NULL) return;
+
+ /* no normal mapping */
+ texres.nor= NULL;
+
+ texvec[0]= xn/har->rad;
+ texvec[1]= yn/har->rad;
+ texvec[2]= 0.0;
+
+ osatex= (har->mat->texco & TEXCO_OSA);
+
+ /* placement */
+ if(mtex->projx) texvec[0]= mtex->size[0]*(texvec[mtex->projx-1]+mtex->ofs[0]);
+ else texvec[0]= mtex->size[0]*(mtex->ofs[0]);
+
+ if(mtex->projy) texvec[1]= mtex->size[1]*(texvec[mtex->projy-1]+mtex->ofs[1]);
+ else texvec[1]= mtex->size[1]*(mtex->ofs[1]);
+
+ if(mtex->projz) texvec[2]= mtex->size[2]*(texvec[mtex->projz-1]+mtex->ofs[2]);
+ else texvec[2]= mtex->size[2]*(mtex->ofs[2]);
+
+ if(osatex) {
+
+ dx= 1.0/har->rad;
+
+ if(mtex->projx) {
+ dxt[0]= mtex->size[0]*dx;
+ dyt[0]= mtex->size[0]*dx;
+ }
+ else dxt[0]= dyt[0]= 0.0;
+
+ if(mtex->projy) {
+ dxt[1]= mtex->size[1]*dx;
+ dyt[1]= mtex->size[1]*dx;
+ }
+ else dxt[1]= dyt[1]= 0.0;
+
+ if(mtex->projz) {
+ dxt[2]= 0.0;
+ dyt[2]= 0.0;
+ }
+ else dxt[2]= dyt[2]= 0.0;
+
+ }
+
+ if(mtex->tex->type==TEX_IMAGE) do_2d_mapping(mtex, texvec, NULL, dxt, dyt);
+
+ rgb= multitex(mtex->tex, texvec, dxt, dyt, osatex, &texres);
+
+ /* texture output */
+ if(rgb && (mtex->texflag & MTEX_RGBTOINT)) {
+ texres.tin= (0.35*texres.tr+0.45*texres.tg+0.2*texres.tb);
+ rgb= 0;
+ }
+ if(mtex->texflag & MTEX_NEGATIVE) {
+ if(rgb) {
+ texres.tr= 1.0-texres.tr;
+ texres.tg= 1.0-texres.tg;
+ texres.tb= 1.0-texres.tb;
+ }
+ else texres.tin= 1.0-texres.tin;
+ }
+
+ /* mapping */
+ if(mtex->mapto & MAP_COL) {
+
+ if(rgb==0) {
+ texres.tr= mtex->r;
+ texres.tg= mtex->g;
+ texres.tb= mtex->b;
+ }
+ else if(mtex->mapto & MAP_ALPHA) {
+ texres.tin= 1.0;
+ }
+ else texres.tin= texres.ta;
+
+ fact= texres.tin*mtex->colfac;
+ facm= 1.0-fact;
+
+ if(mtex->blendtype==MTEX_MUL) {
+ facm= 1.0-mtex->colfac;
+ }
+
+ if(mtex->blendtype==MTEX_SUB) fact= -fact;
+
+ if(mtex->blendtype==MTEX_BLEND) {
+ colf[0]= (fact*texres.tr + facm*har->r);
+ colf[1]= (fact*texres.tg + facm*har->g);
+ colf[2]= (fact*texres.tb + facm*har->b);
+ }
+ else if(mtex->blendtype==MTEX_MUL) {
+ colf[0]= (facm+fact*texres.tr)*har->r;
+ colf[1]= (facm+fact*texres.tg)*har->g;
+ colf[2]= (facm+fact*texres.tb)*har->b;
+ }
+ else {
+ colf[0]= (fact*texres.tr + har->r);
+ colf[1]= (fact*texres.tg + har->g);
+ colf[2]= (fact*texres.tb + har->b);
+
+ CLAMP(colf[0], 0.0, 1.0);
+ CLAMP(colf[1], 0.0, 1.0);
+ CLAMP(colf[2], 0.0, 1.0);
+ }
+ }
+ if(mtex->mapto & MAP_ALPHA) {
+ if(rgb) {
+ if(texres.talpha) texres.tin= texres.ta;
+ else texres.tin= (0.35*texres.tr+0.45*texres.tg+0.2*texres.tb);
+ }
+
+ colf[3]*= texres.tin;
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* hor and zen are RGB vectors, blend is 1 float, should all be initialized */
+void do_sky_tex(float *rco, float *lo, float *dxyview, float *hor, float *zen, float *blend, int skyflag)
+{
+ MTex *mtex;
+ TexResult texres= {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, NULL};
+ float *co, fact, stencilTin=1.0;
+ float tempvec[3], texvec[3], dxt[3], dyt[3];
+ int tex_nr, rgb= 0, ok;
+
+ if (R.r.scemode & R_NO_TEX) return;
+ /* todo: add flag to test if there's a tex */
+ texres.nor= NULL;
+
+ for(tex_nr=0; tex_nr<MAX_MTEX; tex_nr++) {
+ if(R.wrld.mtex[tex_nr]) {
+ mtex= R.wrld.mtex[tex_nr];
+
+ if(mtex->tex==0) continue;
+ /* if(mtex->mapto==0) continue; */
+
+ /* which coords */
+ co= lo;
+
+ /* dxt dyt just from 1 value */
+ if(dxyview) {
+ dxt[0]= dxt[1]= dxt[2]= dxyview[0];
+ dyt[0]= dyt[1]= dyt[2]= dxyview[1];
+ }
+ else {
+ dxt[0]= dxt[1]= dxt[2]= 0.0;
+ dyt[0]= dyt[1]= dyt[2]= 0.0;
+ }
+
+ /* Grab the mapping settings for this texture */
+ switch(mtex->texco) {
+ case TEXCO_ANGMAP:
+ /* only works with texture being "real" */
+ fact= (1.0/M_PI)*acos(lo[2])/(sqrt(lo[0]*lo[0] + lo[1]*lo[1]));
+ tempvec[0]= lo[0]*fact;
+ tempvec[1]= lo[1]*fact;
+ tempvec[2]= 0.0;
+ co= tempvec;
+ break;
+
+ case TEXCO_H_SPHEREMAP:
+ case TEXCO_H_TUBEMAP:
+ if(skyflag & WO_ZENUP) {
+ if(mtex->texco==TEXCO_H_TUBEMAP) tubemap(lo[0], lo[2], lo[1], tempvec, tempvec+1);
+ else spheremap(lo[0], lo[2], lo[1], tempvec, tempvec+1);
+ /* tube/spheremap maps for outside view, not inside */
+ tempvec[0]= 1.0-tempvec[0];
+ /* only top half */
+ tempvec[1]= 2.0*tempvec[1]-1.0;
+ tempvec[2]= 0.0;
+ /* and correction for do_2d_mapping */
+ tempvec[0]= 2.0*tempvec[0]-1.0;
+ tempvec[1]= 2.0*tempvec[1]-1.0;
+ co= tempvec;
+ }
+ else {
+ /* potentially dangerous... check with multitex! */
+ continue;
+ }
+ break;
+ case TEXCO_OBJECT:
+ if(mtex->object) {
+ VECCOPY(tempvec, lo);
+ MTC_Mat4MulVecfl(mtex->object->imat, tempvec);
+ co= tempvec;
+ }
+ break;
+
+ case TEXCO_GLOB:
+ if(rco) {
+ VECCOPY(tempvec, rco);
+ MTC_Mat4MulVecfl(R.viewinv, tempvec);
+ co= tempvec;
+ }
+ else
+ co= lo;
+
+// VECCOPY(shi->dxgl, shi->dxco);
+// MTC_Mat3MulVecfl(R.imat, shi->dxco);
+// VECCOPY(shi->dygl, shi->dyco);
+// MTC_Mat3MulVecfl(R.imat, shi->dyco);
+ break;
+ }
+
+ /* placement */
+ if(mtex->projx) texvec[0]= mtex->size[0]*(co[mtex->projx-1]+mtex->ofs[0]);
+ else texvec[0]= mtex->size[0]*(mtex->ofs[0]);
+
+ if(mtex->projy) texvec[1]= mtex->size[1]*(co[mtex->projy-1]+mtex->ofs[1]);
+ else texvec[1]= mtex->size[1]*(mtex->ofs[1]);
+
+ if(mtex->projz) texvec[2]= mtex->size[2]*(co[mtex->projz-1]+mtex->ofs[2]);
+ else texvec[2]= mtex->size[2]*(mtex->ofs[2]);
+
+ /* texture */
+ if(mtex->tex->type==TEX_IMAGE) do_2d_mapping(mtex, texvec, NULL, dxt, dyt);
+
+ rgb= multitex(mtex->tex, texvec, dxt, dyt, R.osa, &texres);
+
+ /* texture output */
+ if(rgb && (mtex->texflag & MTEX_RGBTOINT)) {
+ texres.tin= (0.35*texres.tr+0.45*texres.tg+0.2*texres.tb);
+ rgb= 0;
+ }
+ if(mtex->texflag & MTEX_NEGATIVE) {
+ if(rgb) {
+ texres.tr= 1.0-texres.tr;
+ texres.tg= 1.0-texres.tg;
+ texres.tb= 1.0-texres.tb;
+ }
+ else texres.tin= 1.0-texres.tin;
+ }
+ if(mtex->texflag & MTEX_STENCIL) {
+ if(rgb) {
+ fact= texres.ta;
+ texres.ta*= stencilTin;
+ stencilTin*= fact;
+ }
+ else {
+ fact= texres.tin;
+ texres.tin*= stencilTin;
+ stencilTin*= fact;
+ }
+ }
+ else {
+ if(rgb) texres.ta *= stencilTin;
+ else texres.tin*= stencilTin;
+ }
+
+ /* color mapping */
+ if(mtex->mapto & (WOMAP_HORIZ+WOMAP_ZENUP+WOMAP_ZENDOWN)) {
+ float tcol[3];
+
+ if(rgb==0) {
+ texres.tr= mtex->r;
+ texres.tg= mtex->g;
+ texres.tb= mtex->b;
+ }
+ else texres.tin= texres.ta;
+
+ tcol[0]= texres.tr; tcol[1]= texres.tg; tcol[2]= texres.tb;
+
+ if(mtex->mapto & WOMAP_HORIZ) {
+ texture_rgb_blend(hor, tcol, hor, texres.tin, mtex->colfac, mtex->blendtype);
+ }
+ if(mtex->mapto & (WOMAP_ZENUP+WOMAP_ZENDOWN)) {
+ ok= 0;
+ if(R.wrld.skytype & WO_SKYREAL) {
+ if((skyflag & WO_ZENUP)) {
+ if(mtex->mapto & WOMAP_ZENUP) ok= 1;
+ }
+ else if(mtex->mapto & WOMAP_ZENDOWN) ok= 1;
+ }
+ else ok= 1;
+
+ if(ok) {
+ texture_rgb_blend(zen, tcol, zen, texres.tin, mtex->colfac, mtex->blendtype);
+ }
+ }
+ }
+ if(mtex->mapto & WOMAP_BLEND) {
+ if(rgb) texres.tin= (0.35*texres.tr+0.45*texres.tg+0.2*texres.tb);
+
+ *blend= texture_value_blend(mtex->def_var, *blend, texres.tin, mtex->varfac, mtex->blendtype, 0);
+ }
+ }
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+/* colf supposed to be initialized with la->r,g,b */
+
+void do_lamp_tex(LampRen *la, float *lavec, ShadeInput *shi, float *colf)
+{
+ Object *ob;
+ MTex *mtex;
+ Tex *tex;
+ TexResult texres= {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, NULL};
+ float *co = NULL, *dx = NULL, *dy = NULL, fact, stencilTin=1.0;
+ float texvec[3], dxt[3], dyt[3], tempvec[3];
+ int tex_nr, rgb= 0;
+
+ if (R.r.scemode & R_NO_TEX) return;
+ tex_nr= 0;
+
+ for(; tex_nr<MAX_MTEX; tex_nr++) {
+
+ if(la->mtex[tex_nr]) {
+ mtex= la->mtex[tex_nr];
+
+ tex= mtex->tex;
+ if(tex==NULL) continue;
+ texres.nor= NULL;
+
+ /* which coords */
+ if(mtex->texco==TEXCO_OBJECT) {
+ ob= mtex->object;
+ if(ob) {
+ co= tempvec;
+ dx= dxt;
+ dy= dyt;
+ VECCOPY(tempvec, shi->co);
+ MTC_Mat4MulVecfl(ob->imat, tempvec);
+ if(shi->osatex) {
+ VECCOPY(dxt, shi->dxco);
+ VECCOPY(dyt, shi->dyco);
+ MTC_Mat4Mul3Vecfl(ob->imat, dxt);
+ MTC_Mat4Mul3Vecfl(ob->imat, dyt);
+ }
+ }
+ else {
+ co= shi->co;
+ dx= shi->dxco; dy= shi->dyco;
+ }
+ }
+ else if(mtex->texco==TEXCO_GLOB) {
+ co= shi->gl; dx= shi->dxco; dy= shi->dyco;
+ VECCOPY(shi->gl, shi->co);
+ MTC_Mat4MulVecfl(R.viewinv, shi->gl);
+ }
+ else if(mtex->texco==TEXCO_VIEW) {
+
+ VECCOPY(tempvec, lavec);
+ MTC_Mat3MulVecfl(la->imat, tempvec);
+
+ if(la->type==LA_SPOT) {
+ tempvec[0]*= la->spottexfac;
+ tempvec[1]*= la->spottexfac;
+ }
+ co= tempvec;
+
+ dx= dxt; dy= dyt;
+ if(shi->osatex) {
+ VECCOPY(dxt, shi->dxlv);
+ VECCOPY(dyt, shi->dylv);
+ /* need some matrix conversion here? la->imat is a [3][3] matrix!!! **/
+ MTC_Mat3MulVecfl(la->imat, dxt);
+ MTC_Mat3MulVecfl(la->imat, dyt);
+
+ VecMulf(dxt, la->spottexfac);
+ VecMulf(dyt, la->spottexfac);
+ }
+ }
+
+
+ /* placement */
+ if(mtex->projx) texvec[0]= mtex->size[0]*(co[mtex->projx-1]+mtex->ofs[0]);
+ else texvec[0]= mtex->size[0]*(mtex->ofs[0]);
+
+ if(mtex->projy) texvec[1]= mtex->size[1]*(co[mtex->projy-1]+mtex->ofs[1]);
+ else texvec[1]= mtex->size[1]*(mtex->ofs[1]);
+
+ if(mtex->projz) texvec[2]= mtex->size[2]*(co[mtex->projz-1]+mtex->ofs[2]);
+ else texvec[2]= mtex->size[2]*(mtex->ofs[2]);
+
+ if(shi->osatex) {
+ if(mtex->projx) {
+ dxt[0]= mtex->size[0]*dx[mtex->projx-1];
+ dyt[0]= mtex->size[0]*dy[mtex->projx-1];
+ }
+ else dxt[0]= 0.0;
+ if(mtex->projy) {
+ dxt[1]= mtex->size[1]*dx[mtex->projy-1];
+ dyt[1]= mtex->size[1]*dy[mtex->projy-1];
+ }
+ else dxt[1]= 0.0;
+ if(mtex->projx) {
+ dxt[2]= mtex->size[2]*dx[mtex->projz-1];
+ dyt[2]= mtex->size[2]*dy[mtex->projz-1];
+ }
+ else dxt[2]= 0.0;
+ }
+
+ /* texture */
+ if(tex->type==TEX_IMAGE) {
+ do_2d_mapping(mtex, texvec, NULL, dxt, dyt);
+ }
+
+ rgb= multitex(tex, texvec, dxt, dyt, shi->osatex, &texres);
+
+ /* texture output */
+ if(rgb && (mtex->texflag & MTEX_RGBTOINT)) {
+ texres.tin= (0.35*texres.tr+0.45*texres.tg+0.2*texres.tb);
+ rgb= 0;
+ }
+ if(mtex->texflag & MTEX_NEGATIVE) {
+ if(rgb) {
+ texres.tr= 1.0-texres.tr;
+ texres.tg= 1.0-texres.tg;
+ texres.tb= 1.0-texres.tb;
+ }
+ else texres.tin= 1.0-texres.tin;
+ }
+ if(mtex->texflag & MTEX_STENCIL) {
+ if(rgb) {
+ fact= texres.ta;
+ texres.ta*= stencilTin;
+ stencilTin*= fact;
+ }
+ else {
+ fact= texres.tin;
+ texres.tin*= stencilTin;
+ stencilTin*= fact;
+ }
+ }
+ else {
+ if(rgb) texres.ta*= stencilTin;
+ else texres.tin*= stencilTin;
+ }
+
+ /* mapping */
+ if(mtex->mapto & LAMAP_COL) {
+ float col[3];
+
+ if(rgb==0) {
+ texres.tr= mtex->r;
+ texres.tg= mtex->g;
+ texres.tb= mtex->b;
+ }
+ else if(mtex->mapto & MAP_ALPHA) {
+ texres.tin= stencilTin;
+ }
+ else texres.tin= texres.ta;
+
+ /* lamp colors were premultiplied with this */
+ col[0]= texres.tr*la->energy;
+ col[1]= texres.tg*la->energy;
+ col[2]= texres.tb*la->energy;
+
+ texture_rgb_blend(colf, col, colf, texres.tin, mtex->colfac, mtex->blendtype);
+ }
+ }
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+int externtex(MTex *mtex, float *vec, float *tin, float *tr, float *tg, float *tb, float *ta)
+{
+ Tex *tex;
+ TexResult texr;
+ float dxt[3], dyt[3], texvec[3];
+ int rgb;
+
+ tex= mtex->tex;
+ if(tex==NULL) return 0;
+ texr.nor= NULL;
+
+ /* placement */
+ if(mtex->projx) texvec[0]= mtex->size[0]*(vec[mtex->projx-1]+mtex->ofs[0]);
+ else texvec[0]= mtex->size[0]*(mtex->ofs[0]);
+
+ if(mtex->projy) texvec[1]= mtex->size[1]*(vec[mtex->projy-1]+mtex->ofs[1]);
+ else texvec[1]= mtex->size[1]*(mtex->ofs[1]);
+
+ if(mtex->projz) texvec[2]= mtex->size[2]*(vec[mtex->projz-1]+mtex->ofs[2]);
+ else texvec[2]= mtex->size[2]*(mtex->ofs[2]);
+
+ /* texture */
+ if(tex->type==TEX_IMAGE) {
+ do_2d_mapping(mtex, texvec, NULL, dxt, dyt);
+ }
+
+ rgb= multitex(tex, texvec, dxt, dyt, 0, &texr);
+
+ if(rgb) {
+ texr.tin= (0.35*texr.tr+0.45*texr.tg+0.2*texr.tb);
+ }
+ else {
+ texr.tr= mtex->r;
+ texr.tg= mtex->g;
+ texr.tb= mtex->b;
+ }
+
+ *tin= texr.tin;
+ *tr= texr.tr;
+ *tg= texr.tg;
+ *tb= texr.tb;
+ *ta= texr.ta;
+
+ return (rgb != 0);
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+void render_realtime_texture(ShadeInput *shi, Image *ima)
+{
+ TexResult texr;
+ static Tex tex1, tex2; // threadsafe
+ static int firsttime= 1;
+ Tex *tex;
+ float texvec[3], dx[2], dy[2];
+
+ if(firsttime) {
+ firsttime= 0;
+ default_tex(&tex1);
+ default_tex(&tex2);
+ tex1.type= TEX_IMAGE;
+ tex2.type= TEX_IMAGE;
+ }
+
+ if(shi->ys & 1) tex= &tex1; else tex= &tex2; // threadsafe
+
+ texvec[0]= 0.5+0.5*shi->uv[0].uv[0];
+ texvec[1]= 0.5+0.5*shi->uv[0].uv[1];
+ texvec[2] = 0; // initalize it because imagewrap looks at it.
+ if(shi->osatex) {
+ dx[0]= 0.5*shi->uv[0].dxuv[0];
+ dx[1]= 0.5*shi->uv[0].dxuv[1];
+ dy[0]= 0.5*shi->uv[0].dyuv[0];
+ dy[1]= 0.5*shi->uv[0].dyuv[1];
+ }
+
+ texr.nor= NULL;
+
+ if(shi->osatex) imagewraposa(tex, ima, NULL, texvec, dx, dy, &texr);
+ else imagewrap(tex, ima, NULL, texvec, &texr);
+
+ shi->vcol[0]*= texr.tr;
+ shi->vcol[1]*= texr.tg;
+ shi->vcol[2]*= texr.tb;
+}
+
+/* eof */
diff --git a/source/blender/render/intern/source/zbuf.c b/source/blender/render/intern/source/zbuf.c
new file mode 100644
index 00000000000..80b20a8e18e
--- /dev/null
+++ b/source/blender/render/intern/source/zbuf.c
@@ -0,0 +1,3438 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributors: Hos, RPW
+ * 2004-2006 Blender Foundation, full recode
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+
+/*---------------------------------------------------------------------------*/
+/* Common includes */
+/*---------------------------------------------------------------------------*/
+
+#include <math.h>
+#include <float.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+#include "BLI_threads.h"
+#include "BLI_jitter.h"
+
+#include "MTC_matrixops.h"
+#include "MEM_guardedalloc.h"
+
+#include "DNA_lamp_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_node_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_global.h"
+#include "BKE_material.h"
+#include "BKE_utildefines.h"
+
+#include "radio_types.h"
+#include "radio.h" /* needs RG, some root data for radiosity */
+
+#include "RE_render_ext.h"
+
+/* local includes */
+#include "gammaCorrectionTables.h"
+#include "pixelblending.h"
+#include "render_types.h"
+#include "renderpipeline.h"
+#include "renderdatabase.h"
+#include "rendercore.h"
+#include "shadbuf.h"
+#include "shading.h"
+#include "sss.h"
+
+/* own includes */
+#include "zbuf.h"
+
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+/* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
+/* only to be used here in this file, it's for speed */
+extern struct Render R;
+/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+
+
+/* ****************** Spans ******************************* */
+
+/* each zbuffer has coordinates transformed to local rect coordinates, so we can simply clip */
+void zbuf_alloc_span(ZSpan *zspan, int rectx, int recty)
+{
+ memset(zspan, 0, sizeof(ZSpan));
+
+ zspan->rectx= rectx;
+ zspan->recty= recty;
+
+ zspan->span1= MEM_mallocN(recty*sizeof(float), "zspan");
+ zspan->span2= MEM_mallocN(recty*sizeof(float), "zspan");
+}
+
+void zbuf_free_span(ZSpan *zspan)
+{
+ if(zspan) {
+ if(zspan->span1) MEM_freeN(zspan->span1);
+ if(zspan->span2) MEM_freeN(zspan->span2);
+ zspan->span1= zspan->span2= NULL;
+ }
+}
+
+/* reset range for clipping */
+static void zbuf_init_span(ZSpan *zspan)
+{
+ zspan->miny1= zspan->miny2= zspan->recty+1;
+ zspan->maxy1= zspan->maxy2= -1;
+ zspan->minp1= zspan->maxp1= zspan->minp2= zspan->maxp2= NULL;
+}
+
+static void zbuf_add_to_span(ZSpan *zspan, float *v1, float *v2)
+{
+ float *minv, *maxv, *span;
+ float xx1, dx0, xs0;
+ int y, my0, my2;
+
+ if(v1[1]<v2[1]) {
+ minv= v1; maxv= v2;
+ }
+ else {
+ minv= v2; maxv= v1;
+ }
+
+ my0= ceil(minv[1]);
+ my2= floor(maxv[1]);
+
+ if(my2<0 || my0>= zspan->recty) return;
+
+ /* clip top */
+ if(my2>=zspan->recty) my2= zspan->recty-1;
+ /* clip bottom */
+ if(my0<0) my0= 0;
+
+ if(my0>my2) return;
+ /* if(my0>my2) should still fill in, that way we get spans that skip nicely */
+
+ xx1= maxv[1]-minv[1];
+ if(xx1>FLT_EPSILON) {
+ dx0= (minv[0]-maxv[0])/xx1;
+ xs0= dx0*(minv[1]-my2) + minv[0];
+ }
+ else {
+ dx0= 0.0f;
+ xs0= MIN2(minv[0],maxv[0]);
+ }
+
+ /* empty span */
+ if(zspan->maxp1 == NULL) {
+ span= zspan->span1;
+ }
+ else { /* does it complete left span? */
+ if( maxv == zspan->minp1 || minv==zspan->maxp1) {
+ span= zspan->span1;
+ }
+ else {
+ span= zspan->span2;
+ }
+ }
+
+ if(span==zspan->span1) {
+// printf("left span my0 %d my2 %d\n", my0, my2);
+ if(zspan->minp1==NULL || zspan->minp1[1] > minv[1] ) {
+ zspan->minp1= minv;
+ }
+ if(zspan->maxp1==NULL || zspan->maxp1[1] < maxv[1] ) {
+ zspan->maxp1= maxv;
+ }
+ if(my0<zspan->miny1) zspan->miny1= my0;
+ if(my2>zspan->maxy1) zspan->maxy1= my2;
+ }
+ else {
+// printf("right span my0 %d my2 %d\n", my0, my2);
+ if(zspan->minp2==NULL || zspan->minp2[1] > minv[1] ) {
+ zspan->minp2= minv;
+ }
+ if(zspan->maxp2==NULL || zspan->maxp2[1] < maxv[1] ) {
+ zspan->maxp2= maxv;
+ }
+ if(my0<zspan->miny2) zspan->miny2= my0;
+ if(my2>zspan->maxy2) zspan->maxy2= my2;
+ }
+
+ for(y=my2; y>=my0; y--, xs0+= dx0) {
+ /* xs0 is the xcoord! */
+ span[y]= xs0;
+ }
+}
+
+/*-----------------------------------------------------------*/
+/* Functions */
+/*-----------------------------------------------------------*/
+
+
+void fillrect(int *rect, int x, int y, int val)
+{
+ int len, *drect;
+
+ len= x*y;
+ drect= rect;
+ while(len>0) {
+ len--;
+ *drect= val;
+ drect++;
+ }
+}
+
+/* based on Liang&Barsky, for clipping of pyramidical volume */
+static short cliptestf(float p, float q, float *u1, float *u2)
+{
+ float r;
+
+ if(p<0.0) {
+ if(q<p) return 0;
+ else if(q<0.0) {
+ r= q/p;
+ if(r>*u2) return 0;
+ else if(r>*u1) *u1=r;
+ }
+ }
+ else {
+ if(p>0.0) {
+ if(q<0.0) return 0;
+ else if(q<p) {
+ r= q/p;
+ if(r<*u1) return 0;
+ else if(r<*u2) *u2=r;
+ }
+ }
+ else if(q<0.0) return 0;
+ }
+ return 1;
+}
+
+int testclip(float *v)
+{
+ float abs4; /* WATCH IT: this function should do the same as cliptestf, otherwise troubles in zbufclip()*/
+ short c=0;
+
+ /* if we set clip flags, the clipping should be at least larger than epsilon.
+ prevents issues with vertices lying exact on borders */
+ abs4= fabs(v[3]) + FLT_EPSILON;
+
+ if(v[2]< -abs4) c=16; /* this used to be " if(v[2]<0) ", see clippz() */
+ else if(v[2]> abs4) c+= 32;
+
+ if( v[0]>abs4) c+=2;
+ else if( v[0]< -abs4) c+=1;
+
+ if( v[1]>abs4) c+=4;
+ else if( v[1]< -abs4) c+=8;
+
+ return c;
+}
+
+
+
+/* ************* ACCUMULATION ZBUF ************ */
+
+
+static APixstr *addpsmainA(ListBase *lb)
+{
+ APixstrMain *psm;
+
+ psm= MEM_mallocN(sizeof(APixstrMain), "addpsmainA");
+ BLI_addtail(lb, psm);
+ psm->ps= MEM_callocN(4096*sizeof(APixstr),"pixstr");
+
+ return psm->ps;
+}
+
+static void freepsA(ListBase *lb)
+{
+ APixstrMain *psm, *psmnext;
+
+ for(psm= lb->first; psm; psm= psmnext) {
+ psmnext= psm->next;
+ if(psm->ps)
+ MEM_freeN(psm->ps);
+ MEM_freeN(psm);
+ }
+}
+
+static APixstr *addpsA(ZSpan *zspan)
+{
+ /* make new PS */
+ if(zspan->apsmcounter==0) {
+ zspan->curpstr= addpsmainA(zspan->apsmbase);
+ zspan->apsmcounter= 4095;
+ }
+ else {
+ zspan->curpstr++;
+ zspan->apsmcounter--;
+ }
+ return zspan->curpstr;
+}
+
+static void zbuffillAc4(ZSpan *zspan, int zvlnr, float *v1, float *v2, float *v3, float *v4)
+{
+ APixstr *ap, *apofs, *apn;
+ double zxd, zyd, zy0, zverg;
+ float x0,y0,z0;
+ float x1,y1,z1,x2,y2,z2,xx1;
+ float *span1, *span2;
+ int *rz, x, y;
+ int sn1, sn2, rectx, *rectzofs, my0, my2, mask;
+
+ /* init */
+ zbuf_init_span(zspan);
+
+ /* set spans */
+ zbuf_add_to_span(zspan, v1, v2);
+ zbuf_add_to_span(zspan, v2, v3);
+ if(v4) {
+ zbuf_add_to_span(zspan, v3, v4);
+ zbuf_add_to_span(zspan, v4, v1);
+ }
+ else
+ zbuf_add_to_span(zspan, v3, v1);
+
+ /* clipped */
+ if(zspan->minp2==NULL || zspan->maxp2==NULL) return;
+
+ if(zspan->miny1 < zspan->miny2) my0= zspan->miny2; else my0= zspan->miny1;
+ if(zspan->maxy1 > zspan->maxy2) my2= zspan->maxy2; else my2= zspan->maxy1;
+
+ if(my2<my0) return;
+
+ /* ZBUF DX DY, in floats still */
+ x1= v1[0]- v2[0];
+ x2= v2[0]- v3[0];
+ y1= v1[1]- v2[1];
+ y2= v2[1]- v3[1];
+ z1= v1[2]- v2[2];
+ z2= v2[2]- v3[2];
+ x0= y1*z2-z1*y2;
+ y0= z1*x2-x1*z2;
+ z0= x1*y2-y1*x2;
+
+ if(z0==0.0) return;
+
+ xx1= (x0*v1[0] + y0*v1[1])/z0 + v1[2];
+
+ zxd= -(double)x0/(double)z0;
+ zyd= -(double)y0/(double)z0;
+ zy0= ((double)my2)*zyd + (double)xx1;
+
+ /* start-offset in rect */
+ rectx= zspan->rectx;
+ rectzofs= (int *)(zspan->arectz+rectx*(my2));
+ apofs= (zspan->apixbuf+ rectx*(my2));
+ mask= zspan->mask;
+
+ /* correct span */
+ sn1= (my0 + my2)/2;
+ if(zspan->span1[sn1] < zspan->span2[sn1]) {
+ span1= zspan->span1+my2;
+ span2= zspan->span2+my2;
+ }
+ else {
+ span1= zspan->span2+my2;
+ span2= zspan->span1+my2;
+ }
+
+ for(y=my2; y>=my0; y--, span1--, span2--) {
+
+ sn1= floor(*span1);
+ sn2= floor(*span2);
+ sn1++;
+
+ if(sn2>=rectx) sn2= rectx-1;
+ if(sn1<0) sn1= 0;
+
+ if(sn2>=sn1) {
+ zverg= (double)sn1*zxd + zy0;
+ rz= rectzofs+sn1;
+ ap= apofs+sn1;
+ x= sn2-sn1;
+
+ zverg-= zspan->polygon_offset;
+
+ while(x>=0) {
+ if( (int)zverg < *rz) {
+// int i= zvlnr & 3;
+
+ apn= ap;
+ while(apn) {
+ if(apn->p[0]==0) {apn->p[0]= zvlnr; apn->z[0]= zverg; apn->mask[0]= mask; break; }
+ if(apn->p[0]==zvlnr) {apn->mask[0]|= mask; break; }
+ if(apn->p[1]==0) {apn->p[1]= zvlnr; apn->z[1]= zverg; apn->mask[1]= mask; break; }
+ if(apn->p[1]==zvlnr) {apn->mask[1]|= mask; break; }
+ if(apn->p[2]==0) {apn->p[2]= zvlnr; apn->z[2]= zverg; apn->mask[2]= mask; break; }
+ if(apn->p[2]==zvlnr) {apn->mask[2]|= mask; break; }
+ if(apn->p[3]==0) {apn->p[3]= zvlnr; apn->z[3]= zverg; apn->mask[3]= mask; break; }
+ if(apn->p[3]==zvlnr) {apn->mask[3]|= mask; break; }
+// if(apn->p[i]==0) {apn->p[i]= zvlnr; apn->z[i]= zverg; apn->mask[i]= mask; break; }
+// if(apn->p[i]==zvlnr) {apn->mask[i]|= mask; break; }
+ if(apn->next==NULL) apn->next= addpsA(zspan);
+ apn= apn->next;
+ }
+ }
+ zverg+= zxd;
+ rz++;
+ ap++;
+ x--;
+ }
+ }
+
+ zy0-=zyd;
+ rectzofs-= rectx;
+ apofs-= rectx;
+ }
+}
+
+
+
+static void zbuflineAc(ZSpan *zspan, int zvlnr, float *vec1, float *vec2)
+{
+ APixstr *ap, *apn;
+ int *rectz;
+ int start, end, x, y, oldx, oldy, ofs;
+ int dz, vergz, mask, maxtest=0;
+ float dx, dy;
+ float v1[3], v2[3];
+
+ dx= vec2[0]-vec1[0];
+ dy= vec2[1]-vec1[1];
+
+ mask= zspan->mask;
+
+ if(fabs(dx) > fabs(dy)) {
+
+ /* all lines from left to right */
+ if(vec1[0]<vec2[0]) {
+ VECCOPY(v1, vec1);
+ VECCOPY(v2, vec2);
+ }
+ else {
+ VECCOPY(v2, vec1);
+ VECCOPY(v1, vec2);
+ dx= -dx; dy= -dy;
+ }
+
+ start= floor(v1[0]);
+ end= start+floor(dx);
+ if(end>=zspan->rectx) end= zspan->rectx-1;
+
+ oldy= floor(v1[1]);
+ dy/= dx;
+
+ vergz= v1[2];
+ vergz-= zspan->polygon_offset;
+ dz= (v2[2]-v1[2])/dx;
+ if(vergz>0x50000000 && dz>0) maxtest= 1; // prevent overflow
+
+ rectz= (int *)(zspan->arectz+zspan->rectx*(oldy) +start);
+ ap= (zspan->apixbuf+ zspan->rectx*(oldy) +start);
+
+ if(dy<0) ofs= -zspan->rectx;
+ else ofs= zspan->rectx;
+
+ for(x= start; x<=end; x++, rectz++, ap++) {
+
+ y= floor(v1[1]);
+ if(y!=oldy) {
+ oldy= y;
+ rectz+= ofs;
+ ap+= ofs;
+ }
+
+ if(x>=0 && y>=0 && y<zspan->recty) {
+ if(vergz<*rectz) {
+
+ apn= ap;
+ while(apn) { /* loop unrolled */
+ if(apn->p[0]==0) {apn->p[0]= zvlnr; apn->z[0]= vergz; apn->mask[0]= mask; break; }
+ if(apn->p[0]==zvlnr) {apn->mask[0]|= mask; break; }
+ if(apn->p[1]==0) {apn->p[1]= zvlnr; apn->z[1]= vergz; apn->mask[1]= mask; break; }
+ if(apn->p[1]==zvlnr) {apn->mask[1]|= mask; break; }
+ if(apn->p[2]==0) {apn->p[2]= zvlnr; apn->z[2]= vergz; apn->mask[2]= mask; break; }
+ if(apn->p[2]==zvlnr) {apn->mask[2]|= mask; break; }
+ if(apn->p[3]==0) {apn->p[3]= zvlnr; apn->z[3]= vergz; apn->mask[3]= mask; break; }
+ if(apn->p[3]==zvlnr) {apn->mask[3]|= mask; break; }
+ if(apn->next==0) apn->next= addpsA(zspan);
+ apn= apn->next;
+ }
+
+ }
+ }
+
+ v1[1]+= dy;
+ if(maxtest && (vergz > 0x7FFFFFF0 - dz)) vergz= 0x7FFFFFF0;
+ else vergz+= dz;
+ }
+ }
+ else {
+
+ /* all lines from top to bottom */
+ if(vec1[1]<vec2[1]) {
+ VECCOPY(v1, vec1);
+ VECCOPY(v2, vec2);
+ }
+ else {
+ VECCOPY(v2, vec1);
+ VECCOPY(v1, vec2);
+ dx= -dx; dy= -dy;
+ }
+
+ start= floor(v1[1]);
+ end= start+floor(dy);
+
+ if(start>=zspan->recty || end<0) return;
+
+ if(end>=zspan->recty) end= zspan->recty-1;
+
+ oldx= floor(v1[0]);
+ dx/= dy;
+
+ vergz= v1[2];
+ vergz-= zspan->polygon_offset;
+ dz= (v2[2]-v1[2])/dy;
+ if(vergz>0x50000000 && dz>0) maxtest= 1; // prevent overflow
+
+ rectz= (int *)( zspan->arectz+ (start)*zspan->rectx+ oldx );
+ ap= (zspan->apixbuf+ zspan->rectx*(start) +oldx);
+
+ if(dx<0) ofs= -1;
+ else ofs= 1;
+
+ for(y= start; y<=end; y++, rectz+=zspan->rectx, ap+=zspan->rectx) {
+
+ x= floor(v1[0]);
+ if(x!=oldx) {
+ oldx= x;
+ rectz+= ofs;
+ ap+= ofs;
+ }
+
+ if(x>=0 && y>=0 && x<zspan->rectx) {
+ if(vergz<*rectz) {
+
+ apn= ap;
+ while(apn) { /* loop unrolled */
+ if(apn->p[0]==0) {apn->p[0]= zvlnr; apn->z[0]= vergz; apn->mask[0]= mask; break; }
+ if(apn->p[0]==zvlnr) {apn->mask[0]|= mask; break; }
+ if(apn->p[1]==0) {apn->p[1]= zvlnr; apn->z[1]= vergz; apn->mask[1]= mask; break; }
+ if(apn->p[1]==zvlnr) {apn->mask[1]|= mask; break; }
+ if(apn->p[2]==0) {apn->p[2]= zvlnr; apn->z[2]= vergz; apn->mask[2]= mask; break; }
+ if(apn->p[2]==zvlnr) {apn->mask[2]|= mask; break; }
+ if(apn->p[3]==0) {apn->p[3]= zvlnr; apn->z[3]= vergz; apn->mask[3]= mask; break; }
+ if(apn->p[3]==zvlnr) {apn->mask[3]|= mask; break; }
+ if(apn->next==0) apn->next= addpsA(zspan);
+ apn= apn->next;
+ }
+
+ }
+ }
+
+ v1[0]+= dx;
+ if(maxtest && (vergz > 0x7FFFFFF0 - dz)) vergz= 0x7FFFFFF0;
+ else vergz+= dz;
+ }
+ }
+}
+
+/* ************* NORMAL ZBUFFER ************ */
+
+static void zbufline(ZSpan *zspan, int zvlnr, float *vec1, float *vec2)
+{
+ int *rectz, *rectp;
+ int start, end, x, y, oldx, oldy, ofs;
+ int dz, vergz, maxtest= 0;
+ float dx, dy;
+ float v1[3], v2[3];
+
+ dx= vec2[0]-vec1[0];
+ dy= vec2[1]-vec1[1];
+
+ if(fabs(dx) > fabs(dy)) {
+
+ /* all lines from left to right */
+ if(vec1[0]<vec2[0]) {
+ VECCOPY(v1, vec1);
+ VECCOPY(v2, vec2);
+ }
+ else {
+ VECCOPY(v2, vec1);
+ VECCOPY(v1, vec2);
+ dx= -dx; dy= -dy;
+ }
+
+ start= floor(v1[0]);
+ end= start+floor(dx);
+ if(end>=zspan->rectx) end= zspan->rectx-1;
+
+ oldy= floor(v1[1]);
+ dy/= dx;
+
+ vergz= floor(v1[2]);
+ dz= floor((v2[2]-v1[2])/dx);
+ if(vergz>0x50000000 && dz>0) maxtest= 1; // prevent overflow
+
+ rectz= zspan->rectz + oldy*zspan->rectx+ start;
+ rectp= zspan->rectp + oldy*zspan->rectx+ start;
+
+ if(dy<0) ofs= -zspan->rectx;
+ else ofs= zspan->rectx;
+
+ for(x= start; x<=end; x++, rectz++, rectp++) {
+
+ y= floor(v1[1]);
+ if(y!=oldy) {
+ oldy= y;
+ rectz+= ofs;
+ rectp+= ofs;
+ }
+
+ if(x>=0 && y>=0 && y<zspan->recty) {
+ if(vergz<*rectz) {
+ *rectz= vergz;
+ *rectp= zvlnr;
+ }
+ }
+
+ v1[1]+= dy;
+
+ if(maxtest && (vergz > 0x7FFFFFF0 - dz)) vergz= 0x7FFFFFF0;
+ else vergz+= dz;
+ }
+ }
+ else {
+ /* all lines from top to bottom */
+ if(vec1[1]<vec2[1]) {
+ VECCOPY(v1, vec1);
+ VECCOPY(v2, vec2);
+ }
+ else {
+ VECCOPY(v2, vec1);
+ VECCOPY(v1, vec2);
+ dx= -dx; dy= -dy;
+ }
+
+ start= floor(v1[1]);
+ end= start+floor(dy);
+
+ if(end>=zspan->recty) end= zspan->recty-1;
+
+ oldx= floor(v1[0]);
+ dx/= dy;
+
+ vergz= floor(v1[2]);
+ dz= floor((v2[2]-v1[2])/dy);
+ if(vergz>0x50000000 && dz>0) maxtest= 1; // prevent overflow
+
+ rectz= zspan->rectz + start*zspan->rectx+ oldx;
+ rectp= zspan->rectp + start*zspan->rectx+ oldx;
+
+ if(dx<0) ofs= -1;
+ else ofs= 1;
+
+ for(y= start; y<=end; y++, rectz+=zspan->rectx, rectp+=zspan->rectx) {
+
+ x= floor(v1[0]);
+ if(x!=oldx) {
+ oldx= x;
+ rectz+= ofs;
+ rectp+= ofs;
+ }
+
+ if(x>=0 && y>=0 && x<zspan->rectx) {
+ if(vergz<*rectz) {
+ *rectz= vergz;
+ *rectp= zvlnr;
+ }
+ }
+
+ v1[0]+= dx;
+ if(maxtest && (vergz > 0x7FFFFFF0 - dz)) vergz= 0x7FFFFFF0;
+ else vergz+= dz;
+ }
+ }
+}
+
+static void zbufline_onlyZ(ZSpan *zspan, int zvlnr, float *vec1, float *vec2)
+{
+ int *rectz, *rectz1= NULL;
+ int start, end, x, y, oldx, oldy, ofs;
+ int dz, vergz, maxtest= 0;
+ float dx, dy;
+ float v1[3], v2[3];
+
+ dx= vec2[0]-vec1[0];
+ dy= vec2[1]-vec1[1];
+
+ if(fabs(dx) > fabs(dy)) {
+
+ /* all lines from left to right */
+ if(vec1[0]<vec2[0]) {
+ VECCOPY(v1, vec1);
+ VECCOPY(v2, vec2);
+ }
+ else {
+ VECCOPY(v2, vec1);
+ VECCOPY(v1, vec2);
+ dx= -dx; dy= -dy;
+ }
+
+ start= floor(v1[0]);
+ end= start+floor(dx);
+ if(end>=zspan->rectx) end= zspan->rectx-1;
+
+ oldy= floor(v1[1]);
+ dy/= dx;
+
+ vergz= floor(v1[2]);
+ dz= floor((v2[2]-v1[2])/dx);
+ if(vergz>0x50000000 && dz>0) maxtest= 1; // prevent overflow
+
+ rectz= zspan->rectz + oldy*zspan->rectx+ start;
+ if(zspan->rectz1)
+ rectz1= zspan->rectz1 + oldy*zspan->rectx+ start;
+
+ if(dy<0) ofs= -zspan->rectx;
+ else ofs= zspan->rectx;
+
+ for(x= start; x<=end; x++, rectz++) {
+
+ y= floor(v1[1]);
+ if(y!=oldy) {
+ oldy= y;
+ rectz+= ofs;
+ if(rectz1) rectz1+= ofs;
+ }
+
+ if(x>=0 && y>=0 && y<zspan->recty) {
+ if(vergz < *rectz) {
+ if(rectz1) *rectz1= *rectz;
+ *rectz= vergz;
+ }
+ else if(rectz1 && vergz < *rectz1)
+ *rectz1= vergz;
+ }
+
+ v1[1]+= dy;
+
+ if(maxtest && (vergz > 0x7FFFFFF0 - dz)) vergz= 0x7FFFFFF0;
+ else vergz+= dz;
+
+ if(rectz1) rectz1++;
+ }
+ }
+ else {
+ /* all lines from top to bottom */
+ if(vec1[1]<vec2[1]) {
+ VECCOPY(v1, vec1);
+ VECCOPY(v2, vec2);
+ }
+ else {
+ VECCOPY(v2, vec1);
+ VECCOPY(v1, vec2);
+ dx= -dx; dy= -dy;
+ }
+
+ start= floor(v1[1]);
+ end= start+floor(dy);
+
+ if(end>=zspan->recty) end= zspan->recty-1;
+
+ oldx= floor(v1[0]);
+ dx/= dy;
+
+ vergz= floor(v1[2]);
+ dz= floor((v2[2]-v1[2])/dy);
+ if(vergz>0x50000000 && dz>0) maxtest= 1; // prevent overflow
+
+ rectz= zspan->rectz + start*zspan->rectx+ oldx;
+ if(zspan->rectz1)
+ rectz1= zspan->rectz1 + start*zspan->rectx+ oldx;
+
+ if(dx<0) ofs= -1;
+ else ofs= 1;
+
+ for(y= start; y<=end; y++, rectz+=zspan->rectx) {
+
+ x= floor(v1[0]);
+ if(x!=oldx) {
+ oldx= x;
+ rectz+= ofs;
+ if(rectz1) rectz1+= ofs;
+ }
+
+ if(x>=0 && y>=0 && x<zspan->rectx) {
+ if(vergz < *rectz) {
+ if(rectz1) *rectz1= *rectz;
+ *rectz= vergz;
+ }
+ else if(rectz1 && vergz < *rectz1)
+ *rectz1= vergz;
+ }
+
+ v1[0]+= dx;
+ if(maxtest && (vergz > 0x7FFFFFF0 - dz)) vergz= 0x7FFFFFF0;
+ else vergz+= dz;
+
+ if(rectz1)
+ rectz1+=zspan->rectx;
+ }
+ }
+}
+
+
+static int clipline(float *v1, float *v2) /* return 0: do not draw */
+{
+ float dz,dw, u1=0.0, u2=1.0;
+ float dx, dy, v13;
+
+ dz= v2[2]-v1[2];
+ dw= v2[3]-v1[3];
+
+ /* this 1.01 is for clipping x and y just a tinsy larger. that way it is
+ filled in with zbufwire correctly when rendering in parts. otherwise
+ you see line endings at edges... */
+
+ if(cliptestf(-dz-dw, v1[3]+v1[2], &u1,&u2)) {
+ if(cliptestf(dz-dw, v1[3]-v1[2], &u1,&u2)) {
+
+ dx= v2[0]-v1[0];
+ dz= 1.01*(v2[3]-v1[3]);
+ v13= 1.01*v1[3];
+
+ if(cliptestf(-dx-dz, v1[0]+v13, &u1,&u2)) {
+ if(cliptestf(dx-dz, v13-v1[0], &u1,&u2)) {
+
+ dy= v2[1]-v1[1];
+
+ if(cliptestf(-dy-dz, v1[1]+v13, &u1,&u2)) {
+ if(cliptestf(dy-dz, v13-v1[1], &u1,&u2)) {
+
+ if(u2<1.0) {
+ v2[0]= v1[0]+u2*dx;
+ v2[1]= v1[1]+u2*dy;
+ v2[2]= v1[2]+u2*dz;
+ v2[3]= v1[3]+u2*dw;
+ }
+ if(u1>0.0) {
+ v1[0]= v1[0]+u1*dx;
+ v1[1]= v1[1]+u1*dy;
+ v1[2]= v1[2]+u1*dz;
+ v1[3]= v1[3]+u1*dw;
+ }
+ return 1;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+static void hoco_to_zco(ZSpan *zspan, float *zco, float *hoco)
+{
+ float div;
+
+ div= 1.0f/hoco[3];
+ zco[0]= zspan->zmulx*(1.0+hoco[0]*div) + zspan->zofsx;
+ zco[1]= zspan->zmuly*(1.0+hoco[1]*div) + zspan->zofsy;
+ zco[2]= 0x7FFFFFFF *(hoco[2]*div);
+}
+
+void zbufclipwire(ZSpan *zspan, int zvlnr, VlakRen *vlr)
+{
+ float vez[20], *f1, *f2, *f3, *f4= 0;
+ int c1, c2, c3, c4, ec, and, or;
+
+ /* edgecode: 1= draw */
+ ec = vlr->ec;
+ if(ec==0) return;
+
+ c1= vlr->v1->clip;
+ c2= vlr->v2->clip;
+ c3= vlr->v3->clip;
+ f1= vlr->v1->ho;
+ f2= vlr->v2->ho;
+ f3= vlr->v3->ho;
+
+ if(vlr->v4) {
+ f4= vlr->v4->ho;
+ c4= vlr->v4->clip;
+
+ and= (c1 & c2 & c3 & c4);
+ or= (c1 | c2 | c3 | c4);
+ }
+ else {
+ and= (c1 & c2 & c3);
+ or= (c1 | c2 | c3);
+ }
+
+ if(or) { /* not in the middle */
+ if(and) { /* out completely */
+ return;
+ }
+ else { /* clipping */
+
+ if(ec & ME_V1V2) {
+ QUATCOPY(vez, f1);
+ QUATCOPY(vez+4, f2);
+ if( clipline(vez, vez+4)) {
+ hoco_to_zco(zspan, vez, vez);
+ hoco_to_zco(zspan, vez+4, vez+4);
+ zspan->zbuflinefunc(zspan, zvlnr, vez, vez+4);
+ }
+ }
+ if(ec & ME_V2V3) {
+ QUATCOPY(vez, f2);
+ QUATCOPY(vez+4, f3);
+ if( clipline(vez, vez+4)) {
+ hoco_to_zco(zspan, vez, vez);
+ hoco_to_zco(zspan, vez+4, vez+4);
+ zspan->zbuflinefunc(zspan, zvlnr, vez, vez+4);
+ }
+ }
+ if(vlr->v4) {
+ if(ec & ME_V3V4) {
+ QUATCOPY(vez, f3);
+ QUATCOPY(vez+4, f4);
+ if( clipline(vez, vez+4)) {
+ hoco_to_zco(zspan, vez, vez);
+ hoco_to_zco(zspan, vez+4, vez+4);
+ zspan->zbuflinefunc(zspan, zvlnr, vez, vez+4);
+ }
+ }
+ if(ec & ME_V4V1) {
+ QUATCOPY(vez, f4);
+ QUATCOPY(vez+4, f1);
+ if( clipline(vez, vez+4)) {
+ hoco_to_zco(zspan, vez, vez);
+ hoco_to_zco(zspan, vez+4, vez+4);
+ zspan->zbuflinefunc(zspan, zvlnr, vez, vez+4);
+ }
+ }
+ }
+ else {
+ if(ec & ME_V3V1) {
+ QUATCOPY(vez, f3);
+ QUATCOPY(vez+4, f1);
+ if( clipline(vez, vez+4)) {
+ hoco_to_zco(zspan, vez, vez);
+ hoco_to_zco(zspan, vez+4, vez+4);
+ zspan->zbuflinefunc(zspan, zvlnr, vez, vez+4);
+ }
+ }
+ }
+
+ return;
+ }
+ }
+
+ hoco_to_zco(zspan, vez, f1);
+ hoco_to_zco(zspan, vez+4, f2);
+ hoco_to_zco(zspan, vez+8, f3);
+ if(vlr->v4) {
+ hoco_to_zco(zspan, vez+12, f4);
+
+ if(ec & ME_V3V4) zspan->zbuflinefunc(zspan, zvlnr, vez+8, vez+12);
+ if(ec & ME_V4V1) zspan->zbuflinefunc(zspan, zvlnr, vez+12, vez);
+ }
+ else {
+ if(ec & ME_V3V1) zspan->zbuflinefunc(zspan, zvlnr, vez+8, vez);
+ }
+
+ if(ec & ME_V1V2) zspan->zbuflinefunc(zspan, zvlnr, vez, vez+4);
+ if(ec & ME_V2V3) zspan->zbuflinefunc(zspan, zvlnr, vez+4, vez+8);
+
+}
+
+/**
+ * Fill the z buffer, but invert z order, and add the face index to
+ * the corresponing face buffer.
+ *
+ * This is one of the z buffer fill functions called in zbufclip() and
+ * zbufwireclip().
+ *
+ * @param v1 [4 floats, world coordinates] first vertex
+ * @param v2 [4 floats, world coordinates] second vertex
+ * @param v3 [4 floats, world coordinates] third vertex
+ */
+static void zbuffillGLinv4(ZSpan *zspan, int zvlnr, float *v1, float *v2, float *v3, float *v4)
+{
+ double zxd, zyd, zy0, zverg;
+ float x0,y0,z0;
+ float x1,y1,z1,x2,y2,z2,xx1;
+ float *span1, *span2;
+ int *rectpofs, *rp;
+ int *rz, x, y;
+ int sn1, sn2, rectx, *rectzofs, my0, my2;
+
+ /* init */
+ zbuf_init_span(zspan);
+
+ /* set spans */
+ zbuf_add_to_span(zspan, v1, v2);
+ zbuf_add_to_span(zspan, v2, v3);
+ if(v4) {
+ zbuf_add_to_span(zspan, v3, v4);
+ zbuf_add_to_span(zspan, v4, v1);
+ }
+ else
+ zbuf_add_to_span(zspan, v3, v1);
+
+ /* clipped */
+ if(zspan->minp2==NULL || zspan->maxp2==NULL) return;
+
+ if(zspan->miny1 < zspan->miny2) my0= zspan->miny2; else my0= zspan->miny1;
+ if(zspan->maxy1 > zspan->maxy2) my2= zspan->maxy2; else my2= zspan->maxy1;
+
+ // printf("my %d %d\n", my0, my2);
+ if(my2<my0) return;
+
+
+ /* ZBUF DX DY, in floats still */
+ x1= v1[0]- v2[0];
+ x2= v2[0]- v3[0];
+ y1= v1[1]- v2[1];
+ y2= v2[1]- v3[1];
+ z1= v1[2]- v2[2];
+ z2= v2[2]- v3[2];
+ x0= y1*z2-z1*y2;
+ y0= z1*x2-x1*z2;
+ z0= x1*y2-y1*x2;
+
+ if(z0==0.0) return;
+
+ xx1= (x0*v1[0] + y0*v1[1])/z0 + v1[2];
+
+ zxd= -(double)x0/(double)z0;
+ zyd= -(double)y0/(double)z0;
+ zy0= ((double)my2)*zyd + (double)xx1;
+
+ /* start-offset in rect */
+ rectx= zspan->rectx;
+ rectzofs= (zspan->rectz+rectx*my2);
+ rectpofs= (zspan->rectp+rectx*my2);
+
+ /* correct span */
+ sn1= (my0 + my2)/2;
+ if(zspan->span1[sn1] < zspan->span2[sn1]) {
+ span1= zspan->span1+my2;
+ span2= zspan->span2+my2;
+ }
+ else {
+ span1= zspan->span2+my2;
+ span2= zspan->span1+my2;
+ }
+
+ for(y=my2; y>=my0; y--, span1--, span2--) {
+
+ sn1= floor(*span1);
+ sn2= floor(*span2);
+ sn1++;
+
+ if(sn2>=rectx) sn2= rectx-1;
+ if(sn1<0) sn1= 0;
+
+ if(sn2>=sn1) {
+ zverg= (double)sn1*zxd + zy0;
+ rz= rectzofs+sn1;
+ rp= rectpofs+sn1;
+ x= sn2-sn1;
+
+ while(x>=0) {
+ if( (int)zverg > *rz || *rz==0x7FFFFFFF) {
+ *rz= (int)zverg;
+ *rp= zvlnr;
+ }
+ zverg+= zxd;
+ rz++;
+ rp++;
+ x--;
+ }
+ }
+
+ zy0-=zyd;
+ rectzofs-= rectx;
+ rectpofs-= rectx;
+ }
+}
+
+/* uses spanbuffers */
+
+static void zbuffillGL4(ZSpan *zspan, int zvlnr, float *v1, float *v2, float *v3, float *v4)
+{
+ double zxd, zyd, zy0, zverg;
+ float x0,y0,z0;
+ float x1,y1,z1,x2,y2,z2,xx1;
+ float *span1, *span2;
+ int *rectpofs, *rp;
+ int *rz, x, y;
+ int sn1, sn2, rectx, *rectzofs, my0, my2;
+
+ /* init */
+ zbuf_init_span(zspan);
+
+ /* set spans */
+ zbuf_add_to_span(zspan, v1, v2);
+ zbuf_add_to_span(zspan, v2, v3);
+ if(v4) {
+ zbuf_add_to_span(zspan, v3, v4);
+ zbuf_add_to_span(zspan, v4, v1);
+ }
+ else
+ zbuf_add_to_span(zspan, v3, v1);
+
+ /* clipped */
+ if(zspan->minp2==NULL || zspan->maxp2==NULL) return;
+
+ if(zspan->miny1 < zspan->miny2) my0= zspan->miny2; else my0= zspan->miny1;
+ if(zspan->maxy1 > zspan->maxy2) my2= zspan->maxy2; else my2= zspan->maxy1;
+
+// printf("my %d %d\n", my0, my2);
+ if(my2<my0) return;
+
+
+ /* ZBUF DX DY, in floats still */
+ x1= v1[0]- v2[0];
+ x2= v2[0]- v3[0];
+ y1= v1[1]- v2[1];
+ y2= v2[1]- v3[1];
+ z1= v1[2]- v2[2];
+ z2= v2[2]- v3[2];
+ x0= y1*z2-z1*y2;
+ y0= z1*x2-x1*z2;
+ z0= x1*y2-y1*x2;
+
+ if(z0==0.0) return;
+
+ xx1= (x0*v1[0] + y0*v1[1])/z0 + v1[2];
+
+ zxd= -(double)x0/(double)z0;
+ zyd= -(double)y0/(double)z0;
+ zy0= ((double)my2)*zyd + (double)xx1;
+
+ /* start-offset in rect */
+ rectx= zspan->rectx;
+ rectzofs= (zspan->rectz+rectx*my2);
+ rectpofs= (zspan->rectp+rectx*my2);
+
+ /* correct span */
+ sn1= (my0 + my2)/2;
+ if(zspan->span1[sn1] < zspan->span2[sn1]) {
+ span1= zspan->span1+my2;
+ span2= zspan->span2+my2;
+ }
+ else {
+ span1= zspan->span2+my2;
+ span2= zspan->span1+my2;
+ }
+
+ for(y=my2; y>=my0; y--, span1--, span2--) {
+
+ sn1= floor(*span1);
+ sn2= floor(*span2);
+ sn1++;
+
+ if(sn2>=rectx) sn2= rectx-1;
+ if(sn1<0) sn1= 0;
+
+ if(sn2>=sn1) {
+ zverg= (double)sn1*zxd + zy0;
+ rz= rectzofs+sn1;
+ rp= rectpofs+sn1;
+ x= sn2-sn1;
+
+ while(x>=0) {
+ if( (int)zverg < *rz) {
+ *rz= (int)zverg;
+ *rp= zvlnr;
+ }
+ zverg+= zxd;
+ rz++;
+ rp++;
+ x--;
+ }
+ }
+
+ zy0-=zyd;
+ rectzofs-= rectx;
+ rectpofs-= rectx;
+ }
+}
+
+/**
+ * Fill the z buffer. The face buffer is not operated on!
+ *
+ * This is one of the z buffer fill functions called in zbufclip() and
+ * zbufwireclip().
+ *
+ * @param v1 [4 floats, world coordinates] first vertex
+ * @param v2 [4 floats, world coordinates] second vertex
+ * @param v3 [4 floats, world coordinates] third vertex
+ */
+
+/* now: filling two Z values, the closest and 2nd closest */
+static void zbuffillGL_onlyZ(ZSpan *zspan, int zvlnr, float *v1, float *v2, float *v3, float *v4)
+{
+ double zxd, zyd, zy0, zverg;
+ float x0,y0,z0;
+ float x1,y1,z1,x2,y2,z2,xx1;
+ float *span1, *span2;
+ int *rz, *rz1, x, y;
+ int sn1, sn2, rectx, *rectzofs, *rectzofs1= NULL, my0, my2;
+
+ /* init */
+ zbuf_init_span(zspan);
+
+ /* set spans */
+ zbuf_add_to_span(zspan, v1, v2);
+ zbuf_add_to_span(zspan, v2, v3);
+ if(v4) {
+ zbuf_add_to_span(zspan, v3, v4);
+ zbuf_add_to_span(zspan, v4, v1);
+ }
+ else
+ zbuf_add_to_span(zspan, v3, v1);
+
+ /* clipped */
+ if(zspan->minp2==NULL || zspan->maxp2==NULL) return;
+
+ if(zspan->miny1 < zspan->miny2) my0= zspan->miny2; else my0= zspan->miny1;
+ if(zspan->maxy1 > zspan->maxy2) my2= zspan->maxy2; else my2= zspan->maxy1;
+
+ // printf("my %d %d\n", my0, my2);
+ if(my2<my0) return;
+
+
+ /* ZBUF DX DY, in floats still */
+ x1= v1[0]- v2[0];
+ x2= v2[0]- v3[0];
+ y1= v1[1]- v2[1];
+ y2= v2[1]- v3[1];
+ z1= v1[2]- v2[2];
+ z2= v2[2]- v3[2];
+ x0= y1*z2-z1*y2;
+ y0= z1*x2-x1*z2;
+ z0= x1*y2-y1*x2;
+
+ if(z0==0.0) return;
+
+ xx1= (x0*v1[0] + y0*v1[1])/z0 + v1[2];
+
+ zxd= -(double)x0/(double)z0;
+ zyd= -(double)y0/(double)z0;
+ zy0= ((double)my2)*zyd + (double)xx1;
+
+ /* start-offset in rect */
+ rectx= zspan->rectx;
+ rectzofs= (zspan->rectz+rectx*my2);
+ if(zspan->rectz1)
+ rectzofs1= (zspan->rectz1+rectx*my2);
+
+ /* correct span */
+ sn1= (my0 + my2)/2;
+ if(zspan->span1[sn1] < zspan->span2[sn1]) {
+ span1= zspan->span1+my2;
+ span2= zspan->span2+my2;
+ }
+ else {
+ span1= zspan->span2+my2;
+ span2= zspan->span1+my2;
+ }
+
+ for(y=my2; y>=my0; y--, span1--, span2--) {
+
+ sn1= floor(*span1);
+ sn2= floor(*span2);
+ sn1++;
+
+ if(sn2>=rectx) sn2= rectx-1;
+ if(sn1<0) sn1= 0;
+
+ if(sn2>=sn1) {
+ zverg= (double)sn1*zxd + zy0;
+ rz= rectzofs+sn1;
+ rz1= rectzofs1+sn1;
+ x= sn2-sn1;
+
+ while(x>=0) {
+ int zvergi= (int)zverg;
+ /* option: maintain two depth values, closest and 2nd closest */
+ if(zvergi < *rz) {
+ if(rectzofs1) *rz1= *rz;
+ *rz= zvergi;
+ }
+ else if(rectzofs1 && zvergi < *rz1)
+ *rz1= zvergi;
+
+ zverg+= zxd;
+
+ rz++;
+ rz1++;
+ x--;
+ }
+ }
+
+ zy0-=zyd;
+ rectzofs-= rectx;
+ if(rectzofs1) rectzofs1-= rectx;
+ }
+}
+
+/* 2d scanconvert for tria, calls func for each x,y coordinate and gives UV barycentrics */
+/* zspan should be initialized, has rect size and span buffers */
+
+void zspan_scanconvert(ZSpan *zspan, void *handle, float *v1, float *v2, float *v3, void (*func)(void *, int, int, float, float) )
+{
+ float x0, y0, x1, y1, x2, y2, z0, z1, z2;
+ float u, v, uxd, uyd, vxd, vyd, uy0, vy0, xx1;
+ float *span1, *span2;
+ int x, y, sn1, sn2, rectx= zspan->rectx, my0, my2;
+
+ /* init */
+ zbuf_init_span(zspan);
+
+ /* set spans */
+ zbuf_add_to_span(zspan, v1, v2);
+ zbuf_add_to_span(zspan, v2, v3);
+ zbuf_add_to_span(zspan, v3, v1);
+
+ /* clipped */
+ if(zspan->minp2==NULL || zspan->maxp2==NULL) return;
+
+ if(zspan->miny1 < zspan->miny2) my0= zspan->miny2; else my0= zspan->miny1;
+ if(zspan->maxy1 > zspan->maxy2) my2= zspan->maxy2; else my2= zspan->maxy1;
+
+ // printf("my %d %d\n", my0, my2);
+ if(my2<my0) return;
+
+ /* ZBUF DX DY, in floats still */
+ x1= v1[0]- v2[0];
+ x2= v2[0]- v3[0];
+ y1= v1[1]- v2[1];
+ y2= v2[1]- v3[1];
+
+ z1= 1.0f; // (u1 - u2)
+ z2= 0.0f; // (u2 - u3)
+
+ x0= y1*z2-z1*y2;
+ y0= z1*x2-x1*z2;
+ z0= x1*y2-y1*x2;
+
+ if(z0==0.0f) return;
+
+ xx1= (x0*v1[0] + y0*v1[1])/z0 + 1.0f;
+ uxd= -(double)x0/(double)z0;
+ uyd= -(double)y0/(double)z0;
+ uy0= ((double)my2)*uyd + (double)xx1;
+
+ z1= -1.0f; // (v1 - v2)
+ z2= 1.0f; // (v2 - v3)
+
+ x0= y1*z2-z1*y2;
+ y0= z1*x2-x1*z2;
+
+ xx1= (x0*v1[0] + y0*v1[1])/z0;
+ vxd= -(double)x0/(double)z0;
+ vyd= -(double)y0/(double)z0;
+ vy0= ((double)my2)*vyd + (double)xx1;
+
+ /* correct span */
+ sn1= (my0 + my2)/2;
+ if(zspan->span1[sn1] < zspan->span2[sn1]) {
+ span1= zspan->span1+my2;
+ span2= zspan->span2+my2;
+ }
+ else {
+ span1= zspan->span2+my2;
+ span2= zspan->span1+my2;
+ }
+
+ for(y=my2; y>=my0; y--, span1--, span2--) {
+
+ sn1= floor(*span1);
+ sn2= floor(*span2);
+ sn1++;
+
+ if(sn2>=rectx) sn2= rectx-1;
+ if(sn1<0) sn1= 0;
+
+ u= (double)sn1*uxd + uy0;
+ v= (double)sn1*vxd + vy0;
+
+ for(x= sn1; x<=sn2; x++, u+=uxd, v+=vxd)
+ func(handle, x, y, u, v);
+
+ uy0 -= uyd;
+ vy0 -= vyd;
+ }
+}
+
+
+
+/**
+ * (clip pyramid)
+ * Sets labda: flag, and parametrize the clipping of vertices in
+ * viewspace coordinates. labda = -1 means no clipping, labda in [0,
+ * 1] means a clipping.
+ * Note: uses globals.
+ * @param v1 start coordinate s
+ * @param v2 target coordinate t
+ * @param b1
+ * @param b2
+ * @param b3
+ * @param a index for coordinate (x, y, or z)
+ */
+
+static void clippyra(float *labda, float *v1, float *v2, int *b2, int *b3, int a)
+{
+ float da,dw,u1=0.0,u2=1.0;
+ float v13;
+
+ labda[0]= -1.0;
+ labda[1]= -1.0;
+
+ da= v2[a]-v1[a];
+ /* prob; we clip slightly larger, osa renders add 2 pixels on edges, should become variable? */
+ /* or better; increase r.winx/y size, but thats quite a complex one. do it later */
+ if(a==2) {
+ dw= (v2[3]-v1[3]);
+ v13= v1[3];
+ }
+ else {
+ /* XXXXX EVIL! this is a R global, whilst this function can be called for shadow, before R was set */
+ dw= R.clipcrop*(v2[3]-v1[3]);
+ v13= R.clipcrop*v1[3];
+ }
+ /* according the original article by Liang&Barsky, for clipping of
+ * homogenous coordinates with viewplane, the value of "0" is used instead of "-w" .
+ * This differs from the other clipping cases (like left or top) and I considered
+ * it to be not so 'homogenic'. But later it has proven to be an error,
+ * who would have thought that of L&B!
+ */
+
+ if(cliptestf(-da-dw, v13+v1[a], &u1,&u2)) {
+ if(cliptestf(da-dw, v13-v1[a], &u1,&u2)) {
+ *b3=1;
+ if(u2<1.0) {
+ labda[1]= u2;
+ *b2=1;
+ }
+ else labda[1]=1.0; /* u2 */
+ if(u1>0.0) {
+ labda[0]= u1;
+ *b2=1;
+ } else labda[0]=0.0;
+ }
+ }
+}
+
+/**
+ * (make vertex pyramide clip)
+ * Checks labda and uses this to make decision about clipping the line
+ * segment from v1 to v2. labda is the factor by which the vector is
+ * cut. ( calculate s + l * ( t - s )). The result is appended to the
+ * vertex list of this face.
+ *
+ *
+ * @param v1 start coordinate s
+ * @param v2 target coordinate t
+ * @param b1
+ * @param b2
+ * @param clve vertex vector.
+ */
+
+static void makevertpyra(float *vez, float *labda, float **trias, float *v1, float *v2, int *b1, int *clve)
+{
+ float l1, l2, *adr;
+
+ l1= labda[0];
+ l2= labda[1];
+
+ if(l1!= -1.0) {
+ if(l1!= 0.0) {
+ adr= vez+4*(*clve);
+ trias[*b1]=adr;
+ (*clve)++;
+ adr[0]= v1[0]+l1*(v2[0]-v1[0]);
+ adr[1]= v1[1]+l1*(v2[1]-v1[1]);
+ adr[2]= v1[2]+l1*(v2[2]-v1[2]);
+ adr[3]= v1[3]+l1*(v2[3]-v1[3]);
+ }
+ else trias[*b1]= v1;
+
+ (*b1)++;
+ }
+ if(l2!= -1.0) {
+ if(l2!= 1.0) {
+ adr= vez+4*(*clve);
+ trias[*b1]=adr;
+ (*clve)++;
+ adr[0]= v1[0]+l2*(v2[0]-v1[0]);
+ adr[1]= v1[1]+l2*(v2[1]-v1[1]);
+ adr[2]= v1[2]+l2*(v2[2]-v1[2]);
+ adr[3]= v1[3]+l2*(v2[3]-v1[3]);
+ (*b1)++;
+ }
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+void projectverto(float *v1, float winmat[][4], float *adr)
+{
+ /* calcs homogenic coord of vertex v1 */
+ float x,y,z;
+
+ x= v1[0];
+ y= v1[1];
+ z= v1[2];
+ adr[0]= x*winmat[0][0] + z*winmat[2][0] + winmat[3][0];
+ adr[1]= y*winmat[1][1] + z*winmat[2][1] + winmat[3][1];
+ adr[2]= z*winmat[2][2] + winmat[3][2];
+ adr[3]= z*winmat[2][3] + winmat[3][3];
+
+ //printf("hoco %f %f %f %f\n", adr[0], adr[1], adr[2], adr[3]);
+}
+
+/* ------------------------------------------------------------------------- */
+
+void projectvert(float *v1, float winmat[][4], float *adr)
+{
+ /* calcs homogenic coord of vertex v1 */
+ float x,y,z;
+
+ x= v1[0];
+ y= v1[1];
+ z= v1[2];
+ adr[0]= x*winmat[0][0]+ y*winmat[1][0]+ z*winmat[2][0]+ winmat[3][0];
+ adr[1]= x*winmat[0][1]+ y*winmat[1][1]+ z*winmat[2][1]+ winmat[3][1];
+ adr[2]= x*winmat[0][2]+ y*winmat[1][2]+ z*winmat[2][2]+ winmat[3][2];
+ adr[3]= x*winmat[0][3]+ y*winmat[1][3]+ z*winmat[2][3]+ winmat[3][3];
+}
+
+/* do zbuffering and clip, f1 f2 f3 are hocos, c1 c2 c3 are clipping flags */
+
+void zbufclip(ZSpan *zspan, int zvlnr, float *f1, float *f2, float *f3, int c1, int c2, int c3)
+{
+ float *vlzp[32][3], labda[3][2];
+ float vez[400], *trias[40];
+
+ if(c1 | c2 | c3) { /* not in middle */
+ if(c1 & c2 & c3) { /* completely out */
+ return;
+ } else { /* clipping */
+ int arg, v, b, clipflag[3], b1, b2, b3, c4, clve=3, clvlo, clvl=1;
+
+ vez[0]= f1[0]; vez[1]= f1[1]; vez[2]= f1[2]; vez[3]= f1[3];
+ vez[4]= f2[0]; vez[5]= f2[1]; vez[6]= f2[2]; vez[7]= f2[3];
+ vez[8]= f3[0]; vez[9]= f3[1]; vez[10]= f3[2];vez[11]= f3[3];
+
+ vlzp[0][0]= vez;
+ vlzp[0][1]= vez+4;
+ vlzp[0][2]= vez+8;
+
+ clipflag[0]= ( (c1 & 48) | (c2 & 48) | (c3 & 48) );
+ if(clipflag[0]==0) { /* othwerwise it needs to be calculated again, after the first (z) clip */
+ clipflag[1]= ( (c1 & 3) | (c2 & 3) | (c3 & 3) );
+ clipflag[2]= ( (c1 & 12) | (c2 & 12) | (c3 & 12) );
+ }
+ else clipflag[1]=clipflag[2]= 0;
+
+ for(b=0;b<3;b++) {
+
+ if(clipflag[b]) {
+
+ clvlo= clvl;
+
+ for(v=0; v<clvlo; v++) {
+
+ if(vlzp[v][0]!=NULL) { /* face is still there */
+ b2= b3 =0; /* clip flags */
+
+ if(b==0) arg= 2;
+ else if (b==1) arg= 0;
+ else arg= 1;
+
+ clippyra(labda[0], vlzp[v][0],vlzp[v][1], &b2,&b3, arg);
+ clippyra(labda[1], vlzp[v][1],vlzp[v][2], &b2,&b3, arg);
+ clippyra(labda[2], vlzp[v][2],vlzp[v][0], &b2,&b3, arg);
+
+ if(b2==0 && b3==1) {
+ /* completely 'in', but we copy because of last for() loop in this section */;
+ vlzp[clvl][0]= vlzp[v][0];
+ vlzp[clvl][1]= vlzp[v][1];
+ vlzp[clvl][2]= vlzp[v][2];
+ vlzp[v][0]= NULL;
+ clvl++;
+ } else if(b3==0) {
+ vlzp[v][0]= NULL;
+ /* completely 'out' */;
+ } else {
+ b1=0;
+ makevertpyra(vez, labda[0], trias, vlzp[v][0],vlzp[v][1], &b1,&clve);
+ makevertpyra(vez, labda[1], trias, vlzp[v][1],vlzp[v][2], &b1,&clve);
+ makevertpyra(vez, labda[2], trias, vlzp[v][2],vlzp[v][0], &b1,&clve);
+
+ /* after front clip done: now set clip flags */
+ if(b==0) {
+ clipflag[1]= clipflag[2]= 0;
+ f1= vez;
+ for(b3=0; b3<clve; b3++) {
+ c4= testclip(f1);
+ clipflag[1] |= (c4 & 3);
+ clipflag[2] |= (c4 & 12);
+ f1+= 4;
+ }
+ }
+
+ vlzp[v][0]= NULL;
+ if(b1>2) {
+ for(b3=3; b3<=b1; b3++) {
+ vlzp[clvl][0]= trias[0];
+ vlzp[clvl][1]= trias[b3-2];
+ vlzp[clvl][2]= trias[b3-1];
+ clvl++;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* warning, this should never happen! */
+ if(clve>38 || clvl>31) printf("clip overflow: clve clvl %d %d\n",clve,clvl);
+
+ /* perspective division */
+ f1=vez;
+ for(c1=0;c1<clve;c1++) {
+ hoco_to_zco(zspan, f1, f1);
+ f1+=4;
+ }
+ for(b=1;b<clvl;b++) {
+ if(vlzp[b][0]) {
+ zspan->zbuffunc(zspan, zvlnr, vlzp[b][0],vlzp[b][1],vlzp[b][2], NULL);
+ }
+ }
+ return;
+ }
+ }
+
+ /* perspective division: HCS to ZCS */
+ hoco_to_zco(zspan, vez, f1);
+ hoco_to_zco(zspan, vez+4, f2);
+ hoco_to_zco(zspan, vez+8, f3);
+ zspan->zbuffunc(zspan, zvlnr, vez,vez+4,vez+8, NULL);
+}
+
+void zbufclip4(ZSpan *zspan, int zvlnr, float *f1, float *f2, float *f3, float *f4, int c1, int c2, int c3, int c4)
+{
+ float vez[16];
+
+ if(c1 | c2 | c3 | c4) { /* not in middle */
+ if(c1 & c2 & c3 & c4) { /* completely out */
+ return;
+ } else { /* clipping */
+ zbufclip(zspan, zvlnr, f1, f2, f3, c1, c2, c3);
+ zbufclip(zspan, zvlnr, f1, f3, f4, c1, c3, c4);
+ }
+ return;
+ }
+
+ /* perspective division: HCS to ZCS */
+ hoco_to_zco(zspan, vez, f1);
+ hoco_to_zco(zspan, vez+4, f2);
+ hoco_to_zco(zspan, vez+8, f3);
+ hoco_to_zco(zspan, vez+12, f4);
+
+ zspan->zbuffunc(zspan, zvlnr, vez, vez+4, vez+8, vez+12);
+}
+
+
+/* ***************** ZBUFFER MAIN ROUTINES **************** */
+
+void set_part_zbuf_clipflag(RenderPart *pa)
+{
+ VertRen *ver=NULL;
+ float minx, miny, maxx, maxy, wco;
+ int v;
+ char *clipflag;
+
+ /* flags stored in part now */
+ clipflag= pa->clipflag= MEM_mallocN(R.totvert+1, "part clipflags");
+
+ minx= (2*pa->disprect.xmin - R.winx-1)/(float)R.winx;
+ maxx= (2*pa->disprect.xmax - R.winx+1)/(float)R.winx;
+ miny= (2*pa->disprect.ymin - R.winy-1)/(float)R.winy;
+ maxy= (2*pa->disprect.ymax - R.winy+1)/(float)R.winy;
+
+ for(v=0; v<R.totvert; v++, clipflag++) {
+ if((v & 255)==0)
+ ver= RE_findOrAddVert(&R, v);
+ else ver++;
+
+ wco= ver->ho[3];
+
+ *clipflag= 0;
+ if( ver->ho[0] > maxx*wco) *clipflag |= 1;
+ else if( ver->ho[0]< minx*wco) *clipflag |= 2;
+ if( ver->ho[1] > maxy*wco) *clipflag |= 4;
+ else if( ver->ho[1]< miny*wco) *clipflag |= 8;
+ }
+}
+
+void zbuffer_solid(RenderPart *pa, unsigned int lay, short layflag)
+{
+ ZSpan zspan;
+ VlakRen *vlr= NULL;
+ VertRen *v1, *v2, *v3, *v4;
+ Material *ma=0;
+ int v, zvlnr;
+ short nofill=0, env=0, wire=0, all_z= layflag & SCE_LAY_ALL_Z;
+ char *clipflag= pa->clipflag;
+
+ zbuf_alloc_span(&zspan, pa->rectx, pa->recty);
+
+ /* needed for transform from hoco to zbuffer co */
+ zspan.zmulx= ((float)R.winx)/2.0;
+ zspan.zmuly= ((float)R.winy)/2.0;
+
+ if(R.osa) {
+ zspan.zofsx= -pa->disprect.xmin - R.jit[pa->sample][0];
+ zspan.zofsy= -pa->disprect.ymin - R.jit[pa->sample][1];
+ }
+ else if(R.i.curblur) {
+ zspan.zofsx= -pa->disprect.xmin - R.jit[R.i.curblur-1][0];
+ zspan.zofsy= -pa->disprect.ymin - R.jit[R.i.curblur-1][1];
+ }
+ else {
+ zspan.zofsx= -pa->disprect.xmin;
+ zspan.zofsy= -pa->disprect.ymin;
+ }
+ /* to center the sample position */
+ zspan.zofsx -= 0.5f;
+ zspan.zofsy -= 0.5f;
+
+ /* the buffers */
+ zspan.rectz= pa->rectz;
+ zspan.rectp= pa->rectp;
+ fillrect(pa->rectp, pa->rectx, pa->recty, 0);
+ fillrect(pa->rectz, pa->rectx, pa->recty, 0x7FFFFFFF);
+
+ /* filling methods */
+ zspan.zbuffunc= zbuffillGL4;
+ zspan.zbuflinefunc= zbufline;
+
+ for(v=0; v<R.totvlak; v++) {
+
+ if((v & 255)==0) vlr= R.vlaknodes[v>>8].vlak;
+ else vlr++;
+
+ if((vlr->flag & R_VISIBLE)) {
+ /* three cases, visible for render, only z values and nothing */
+ if(vlr->lay & lay) {
+ if(vlr->mat!=ma) {
+ ma= vlr->mat;
+ nofill= ma->mode & (MA_ZTRA|MA_ONLYCAST);
+ env= (ma->mode & MA_ENV);
+ wire= (ma->mode & MA_WIRE);
+
+ if(ma->mode & MA_ZINV) zspan.zbuffunc= zbuffillGLinv4;
+ else zspan.zbuffunc= zbuffillGL4;
+ }
+ }
+ else if(all_z) {
+ env= 1;
+ nofill= 0;
+ ma= NULL;
+ }
+ else {
+ nofill= 1;
+ ma= NULL; /* otherwise nofill can hang */
+ }
+
+ if(nofill==0) {
+ unsigned short partclip;
+
+ v1= vlr->v1;
+ v2= vlr->v2;
+ v3= vlr->v3;
+ v4= vlr->v4;
+
+ /* partclipping doesn't need viewplane clipping */
+ partclip= clipflag[v1->index] & clipflag[v2->index] & clipflag[v3->index];
+ if(v4)
+ partclip &= clipflag[v4->index];
+
+ if(partclip==0) {
+
+ if(env) zvlnr= -1;
+ else zvlnr= v+1;
+
+ if(wire) zbufclipwire(&zspan, zvlnr, vlr);
+ else {
+ /* strands allow to be filled in as quad */
+ if(v4 && (vlr->flag & R_STRAND)) {
+ zbufclip4(&zspan, zvlnr, v1->ho, v2->ho, v3->ho, v4->ho, v1->clip, v2->clip, v3->clip, v4->clip);
+ }
+ else {
+ zbufclip(&zspan, zvlnr, v1->ho, v2->ho, v3->ho, v1->clip, v2->clip, v3->clip);
+ if(v4) {
+ if(zvlnr>0) zvlnr+= RE_QUAD_OFFS;
+ zbufclip(&zspan, zvlnr, v1->ho, v3->ho, v4->ho, v1->clip, v3->clip, v4->clip);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ zbuf_free_span(&zspan);
+}
+
+typedef struct {
+ float *vert;
+ float hoco[4];
+ int clip;
+} VertBucket;
+
+/* warning, not threaded! */
+static int hashlist_projectvert(float *v1, float winmat[][4], float *hoco)
+{
+ static VertBucket bucket[256], *buck;
+
+ /* init static bucket */
+ if(v1==NULL) {
+ memset(bucket, 0, 256*sizeof(VertBucket));
+ return 0;
+ }
+
+ buck= &bucket[ (((long)v1)/16) & 255 ];
+ if(buck->vert==v1) {
+ QUATCOPY(hoco, buck->hoco);
+ return buck->clip;
+ }
+
+ projectvert(v1, winmat, hoco);
+ buck->clip = testclip(hoco);
+ buck->vert= v1;
+ QUATCOPY(buck->hoco, hoco);
+ return buck->clip;
+}
+
+/* used for booth radio 'tool' as during render */
+void RE_zbufferall_radio(struct RadView *vw, RNode **rg_elem, int rg_totelem, Render *re)
+{
+ ZSpan zspan;
+ float hoco[4][4], winmat[4][4];
+ int a, zvlnr;
+ int c1, c2, c3, c4= 0;
+
+ if(rg_totelem==0) return;
+
+ hashlist_projectvert(NULL, winmat, NULL);
+
+ /* needed for projectvert */
+ MTC_Mat4MulMat4(winmat, vw->viewmat, vw->winmat);
+
+ /* for clipping... bad stuff actually */
+ R.clipcrop= 1.0f;
+
+ zbuf_alloc_span(&zspan, vw->rectx, vw->recty);
+ zspan.zmulx= ((float)vw->rectx)/2.0;
+ zspan.zmuly= ((float)vw->recty)/2.0;
+ zspan.zofsx= -0.5f;
+ zspan.zofsy= -0.5f;
+
+ /* the buffers */
+ zspan.rectz= (int *)vw->rectz;
+ zspan.rectp= (int *)vw->rect;
+ fillrect(zspan.rectz, vw->rectx, vw->recty, 0x7FFFFFFF);
+ fillrect(zspan.rectp, vw->rectx, vw->recty, 0xFFFFFF);
+
+ /* filling methods */
+ zspan.zbuffunc= zbuffillGL4;
+
+ if(rg_elem) { /* radio tool */
+ RNode **re, *rn;
+
+ re= rg_elem;
+ re+= (rg_totelem-1);
+ for(a= rg_totelem-1; a>=0; a--, re--) {
+ rn= *re;
+ if( (rn->f & RAD_SHOOT)==0 ) { /* no shootelement */
+
+ if( rn->f & RAD_TWOSIDED) zvlnr= a;
+ else if( rn->f & RAD_BACKFACE) zvlnr= 0xFFFFFF;
+ else zvlnr= a;
+
+ c1= hashlist_projectvert(rn->v1, winmat, hoco[0]);
+ c2= hashlist_projectvert(rn->v2, winmat, hoco[1]);
+ c3= hashlist_projectvert(rn->v3, winmat, hoco[2]);
+
+ if(rn->v4) {
+ c4= hashlist_projectvert(rn->v4, winmat, hoco[3]);
+ }
+
+ if(rn->v4)
+ zbufclip4(&zspan, zvlnr, hoco[0], hoco[1], hoco[2], hoco[3], c1, c2, c3, c4);
+ else
+ zbufclip(&zspan, zvlnr, hoco[0], hoco[1], hoco[2], c1, c2, c3);
+ }
+ }
+ }
+ else { /* radio render */
+ VlakRen *vlr=NULL;
+ RadFace *rf;
+ int totface=0;
+
+ for(a=0; a<re->totvlak; a++) {
+ if((a & 255)==0) vlr= re->vlaknodes[a>>8].vlak; else vlr++;
+
+ if(vlr->radface) {
+ rf= vlr->radface;
+ if( (rf->flag & RAD_SHOOT)==0 ) { /* no shootelement */
+
+ if( rf->flag & RAD_TWOSIDED) zvlnr= totface;
+ else if( rf->flag & RAD_BACKFACE) zvlnr= 0xFFFFFF; /* receives no energy, but is zbuffered */
+ else zvlnr= totface;
+
+ c1= hashlist_projectvert(vlr->v1->co, winmat, hoco[0]);
+ c2= hashlist_projectvert(vlr->v2->co, winmat, hoco[1]);
+ c3= hashlist_projectvert(vlr->v3->co, winmat, hoco[2]);
+
+ if(vlr->v4) {
+ c4= hashlist_projectvert(vlr->v4->co, winmat, hoco[3]);
+ }
+
+ if(vlr->v4)
+ zbufclip4(&zspan, zvlnr, hoco[0], hoco[1], hoco[2], hoco[3], c1, c2, c3, c4);
+ else
+ zbufclip(&zspan, zvlnr, hoco[0], hoco[1], hoco[2], c1, c2, c3);
+ }
+ totface++;
+ }
+ }
+ }
+
+ zbuf_free_span(&zspan);
+}
+
+void zbuffer_shadow(Render *re, LampRen *lar, int *rectz, int size, float jitx, float jity)
+{
+ ZSpan zspan;
+ VlakRen *vlr= NULL;
+ Material *ma= NULL;
+ int a, ok=1, lay= -1;
+
+ if(lar->mode & LA_LAYER) lay= lar->lay;
+
+ zbuf_alloc_span(&zspan, size, size);
+ zspan.zmulx= ((float)size)/2.0;
+ zspan.zmuly= ((float)size)/2.0;
+ zspan.zofsx= jitx;
+ zspan.zofsy= jity;
+
+ /* the buffers */
+ zspan.rectz= rectz;
+ fillrect(rectz, size, size, 0x7FFFFFFE);
+ if(lar->buftype==LA_SHADBUF_HALFWAY) {
+ zspan.rectz1= MEM_mallocN(size*size*sizeof(int), "seconday z buffer");
+ fillrect(zspan.rectz1, size, size, 0x7FFFFFFE);
+ }
+
+ /* filling methods */
+ zspan.zbuflinefunc= zbufline_onlyZ;
+ zspan.zbuffunc= zbuffillGL_onlyZ;
+
+ for(a=0; a<re->totvlak; a++) {
+
+ if((a & 255)==0) vlr= re->vlaknodes[a>>8].vlak;
+ else vlr++;
+
+ /* note, these conditions are copied in shadowbuf_autoclip() */
+ if(vlr->mat!= ma) {
+ ma= vlr->mat;
+ ok= 1;
+ if((ma->mode & MA_SHADBUF)==0) ok= 0;
+ }
+
+ if(ok && (vlr->flag & R_VISIBLE) && (vlr->lay & lay)) {
+ if(ma->mode & MA_WIRE) zbufclipwire(&zspan, a+1, vlr);
+ else if(vlr->flag & R_STRAND) zbufclipwire(&zspan, a+1, vlr);
+ else {
+ if(vlr->v4)
+ zbufclip4(&zspan, 0, vlr->v1->ho, vlr->v2->ho, vlr->v3->ho, vlr->v4->ho, vlr->v1->clip, vlr->v2->clip, vlr->v3->clip, vlr->v4->clip);
+ else
+ zbufclip(&zspan, 0, vlr->v1->ho, vlr->v2->ho, vlr->v3->ho, vlr->v1->clip, vlr->v2->clip, vlr->v3->clip);
+ }
+ }
+ }
+
+ /* merge buffers */
+ if(lar->buftype==LA_SHADBUF_HALFWAY) {
+ for(a=size*size -1; a>=0; a--)
+ rectz[a]= (rectz[a]>>1) + (zspan.rectz1[a]>>1);
+
+ MEM_freeN(zspan.rectz1);
+ }
+
+ zbuf_free_span(&zspan);
+}
+
+static void zbuffill_sss(ZSpan *zspan, int zvlnr, float *v1, float *v2, float *v3, float *v4)
+{
+ double zxd, zyd, zy0, z;
+ float x0, y0, x1, y1, x2, y2, z0, z1, z2, xx1, *span1, *span2;
+ int x, y, sn1, sn2, rectx= zspan->rectx, my0, my2;
+
+ /* init */
+ zbuf_init_span(zspan);
+
+ /* set spans */
+ zbuf_add_to_span(zspan, v1, v2);
+ zbuf_add_to_span(zspan, v2, v3);
+ if(v4) {
+ zbuf_add_to_span(zspan, v3, v4);
+ zbuf_add_to_span(zspan, v4, v1);
+ }
+ else
+ zbuf_add_to_span(zspan, v3, v1);
+
+ /* clipped */
+ if(zspan->minp2==NULL || zspan->maxp2==NULL) return;
+
+ if(zspan->miny1 < zspan->miny2) my0= zspan->miny2; else my0= zspan->miny1;
+ if(zspan->maxy1 > zspan->maxy2) my2= zspan->maxy2; else my2= zspan->maxy1;
+
+ if(my2<my0) return;
+
+ /* ZBUF DX DY, in floats still */
+ x1= v1[0]- v2[0];
+ x2= v2[0]- v3[0];
+ y1= v1[1]- v2[1];
+ y2= v2[1]- v3[1];
+ z1= v1[2]- v2[2];
+ z2= v2[2]- v3[2];
+
+ x0= y1*z2-z1*y2;
+ y0= z1*x2-x1*z2;
+ z0= x1*y2-y1*x2;
+
+ if(z0==0.0f) return;
+
+ xx1= (x0*v1[0] + y0*v1[1])/z0 + v1[2];
+ zxd= -(double)x0/(double)z0;
+ zyd= -(double)y0/(double)z0;
+ zy0= ((double)my2)*zyd + (double)xx1;
+
+ /* correct span */
+ sn1= (my0 + my2)/2;
+ if(zspan->span1[sn1] < zspan->span2[sn1]) {
+ span1= zspan->span1+my2;
+ span2= zspan->span2+my2;
+ }
+ else {
+ span1= zspan->span2+my2;
+ span2= zspan->span1+my2;
+ }
+
+ for(y=my2; y>=my0; y--, span1--, span2--) {
+ sn1= floor(*span1);
+ sn2= floor(*span2);
+ sn1++;
+
+ if(sn2>=rectx) sn2= rectx-1;
+ if(sn1<0) sn1= 0;
+
+ z= (double)sn1*zxd + zy0;
+
+ for(x= sn1; x<=sn2; x++, z+=zxd)
+ zspan->sss_func(zspan->sss_handle, zvlnr, x, y, z);
+
+ zy0 -= zyd;
+ }
+}
+
+void zbuffer_sss(RenderPart *pa, unsigned int lay, void *handle, void (*func)(void *, int, int, int, int))
+{
+ ZSpan zspan;
+ VlakRen *vlr= NULL;
+ VertRen *v1, *v2, *v3, *v4;
+ Material *ma=0, *sss_ma= R.sss_mat;
+ short nofill=0, env=0, wire=0;
+ char *clipflag= pa->clipflag;
+ int v, zvlnr;
+
+ zbuf_alloc_span(&zspan, pa->rectx, pa->recty);
+
+ zspan.sss_handle= handle;
+ zspan.sss_func= func;
+
+ /* needed for transform from hoco to zbuffer co */
+ zspan.zmulx= ((float)R.winx)/2.0;
+ zspan.zmuly= ((float)R.winy)/2.0;
+
+ /* -0.5f to center the sample position */
+ zspan.zofsx= -pa->disprect.xmin - 0.5f;
+ zspan.zofsy= -pa->disprect.ymin - 0.5f;
+
+ /* filling methods */
+ zspan.zbuffunc= zbuffill_sss;
+
+ /* fill front and back zbuffer */
+ if(pa->rectz) {
+ fillrect(pa->rectp, pa->rectx, pa->recty, 0);
+ fillrect(pa->rectz, pa->rectx, pa->recty, 0x7FFFFFFF);
+ }
+ if(pa->rectbackz) {
+ fillrect(pa->rectbackp, pa->rectx, pa->recty, 0);
+ fillrect(pa->rectbackz, pa->rectx, pa->recty, -0x7FFFFFFF);
+ }
+
+ for(v=0; v<R.totvlak; v++) {
+ if((v & 255)==0) vlr= R.vlaknodes[v>>8].vlak;
+ else vlr++;
+
+ if((vlr->flag & R_VISIBLE) && material_in_material(vlr->mat, sss_ma)) {
+ /* three cases, visible for render, only z values and nothing */
+ if(vlr->lay & lay) {
+ if(vlr->mat!=ma) {
+ ma= vlr->mat;
+ nofill= ma->mode & MA_ONLYCAST;
+ env= (ma->mode & MA_ENV);
+ wire= (ma->mode & MA_WIRE);
+ }
+ }
+ else {
+ nofill= 1;
+ ma= NULL; /* otherwise nofill can hang */
+ }
+
+ if(nofill==0 && wire==0 && env==0) {
+ unsigned short partclip;
+
+ v1= vlr->v1;
+ v2= vlr->v2;
+ v3= vlr->v3;
+ v4= vlr->v4;
+
+ /* partclipping doesn't need viewplane clipping */
+ partclip= clipflag[v1->index] & clipflag[v2->index] & clipflag[v3->index];
+ if(v4)
+ partclip &= clipflag[v4->index];
+
+
+ if(partclip==0) {
+ zvlnr= v+1;
+ zbufclip(&zspan, zvlnr, v1->ho, v2->ho, v3->ho, v1->clip, v2->clip, v3->clip);
+ if(v4) {
+ zvlnr+= RE_QUAD_OFFS;
+ zbufclip(&zspan, zvlnr, v1->ho, v3->ho, v4->ho, v1->clip, v3->clip, v4->clip);
+ }
+ }
+ }
+ }
+ }
+
+ zbuf_free_span(&zspan);
+}
+
+/* ******************** VECBLUR ACCUM BUF ************************* */
+
+typedef struct DrawBufPixel {
+ float *colpoin;
+ float alpha;
+} DrawBufPixel;
+
+
+static void zbuf_fill_in_rgba(ZSpan *zspan, DrawBufPixel *col, float *v1, float *v2, float *v3, float *v4)
+{
+ DrawBufPixel *rectpofs, *rp;
+ double zxd, zyd, zy0, zverg;
+ float x0,y0,z0;
+ float x1,y1,z1,x2,y2,z2,xx1;
+ float *span1, *span2;
+ float *rectzofs, *rz;
+ int x, y;
+ int sn1, sn2, rectx, my0, my2;
+
+ /* init */
+ zbuf_init_span(zspan);
+
+ /* set spans */
+ zbuf_add_to_span(zspan, v1, v2);
+ zbuf_add_to_span(zspan, v2, v3);
+ zbuf_add_to_span(zspan, v3, v4);
+ zbuf_add_to_span(zspan, v4, v1);
+
+ /* clipped */
+ if(zspan->minp2==NULL || zspan->maxp2==NULL) return;
+
+ if(zspan->miny1 < zspan->miny2) my0= zspan->miny2; else my0= zspan->miny1;
+ if(zspan->maxy1 > zspan->maxy2) my2= zspan->maxy2; else my2= zspan->maxy1;
+
+ // printf("my %d %d\n", my0, my2);
+ if(my2<my0) return;
+
+ /* ZBUF DX DY, in floats still */
+ x1= v1[0]- v2[0];
+ x2= v2[0]- v3[0];
+ y1= v1[1]- v2[1];
+ y2= v2[1]- v3[1];
+ z1= v1[2]- v2[2];
+ z2= v2[2]- v3[2];
+ x0= y1*z2-z1*y2;
+ y0= z1*x2-x1*z2;
+ z0= x1*y2-y1*x2;
+
+ if(z0==0.0) return;
+
+ xx1= (x0*v1[0] + y0*v1[1])/z0 + v1[2];
+
+ zxd= -(double)x0/(double)z0;
+ zyd= -(double)y0/(double)z0;
+ zy0= ((double)my2)*zyd + (double)xx1;
+
+ /* start-offset in rect */
+ rectx= zspan->rectx;
+ rectzofs= (float *)(zspan->rectz + rectx*my2);
+ rectpofs= ((DrawBufPixel *)zspan->rectp) + rectx*my2;
+
+ /* correct span */
+ sn1= (my0 + my2)/2;
+ if(zspan->span1[sn1] < zspan->span2[sn1]) {
+ span1= zspan->span1+my2;
+ span2= zspan->span2+my2;
+ }
+ else {
+ span1= zspan->span2+my2;
+ span2= zspan->span1+my2;
+ }
+
+ for(y=my2; y>=my0; y--, span1--, span2--) {
+
+ sn1= floor(*span1);
+ sn2= floor(*span2);
+ sn1++;
+
+ if(sn2>=rectx) sn2= rectx-1;
+ if(sn1<0) sn1= 0;
+
+ if(sn2>=sn1) {
+ zverg= (double)sn1*zxd + zy0;
+ rz= rectzofs+sn1;
+ rp= rectpofs+sn1;
+ x= sn2-sn1;
+
+ while(x>=0) {
+ if( zverg < *rz) {
+ *rz= zverg;
+ *rp= *col;
+ }
+ zverg+= zxd;
+ rz++;
+ rp++;
+ x--;
+ }
+ }
+
+ zy0-=zyd;
+ rectzofs-= rectx;
+ rectpofs-= rectx;
+ }
+}
+
+/* char value==255 is filled in, rest should be zero */
+/* returns alpha values, but sets alpha to 1 for zero alpha pixels that have an alpha value as neighbour */
+void antialias_tagbuf(int xsize, int ysize, char *rectmove)
+{
+ char *row1, *row2, *row3;
+ char prev, next;
+ int a, x, y, step;
+
+ /* 1: tag pixels to be candidate for AA */
+ for(y=2; y<ysize; y++) {
+ /* setup rows */
+ row1= rectmove + (y-2)*xsize;
+ row2= row1 + xsize;
+ row3= row2 + xsize;
+ for(x=2; x<xsize; x++, row1++, row2++, row3++) {
+ if(row2[1]) {
+ if(row2[0]==0 || row2[2]==0 || row1[1]==0 || row3[1]==0)
+ row2[1]= 128;
+ }
+ }
+ }
+
+ /* 2: evaluate horizontal scanlines and calculate alphas */
+ row1= rectmove;
+ for(y=0; y<ysize; y++) {
+ row1++;
+ for(x=1; x<xsize; x++, row1++) {
+ if(row1[0]==128 && row1[1]==128) {
+ /* find previous color and next color and amount of steps to blend */
+ prev= row1[-1];
+ step= 1;
+ while(x+step<xsize && row1[step]==128)
+ step++;
+
+ if(x+step!=xsize) {
+ /* now we can blend values */
+ next= row1[step];
+
+ /* note, prev value can be next value, but we do this loop to clear 128 then */
+ for(a=0; a<step; a++) {
+ int fac, mfac;
+
+ fac= ((a+1)<<8)/(step+1);
+ mfac= 255-fac;
+
+ row1[a]= (prev*mfac + next*fac)>>8;
+ }
+ }
+ }
+ }
+ }
+
+ /* 3: evaluate vertical scanlines and calculate alphas */
+ /* use for reading a copy of the original tagged buffer */
+ for(x=0; x<xsize; x++) {
+ row1= rectmove + x+xsize;
+
+ for(y=1; y<ysize; y++, row1+=xsize) {
+ if(row1[0]==128 && row1[xsize]==128) {
+ /* find previous color and next color and amount of steps to blend */
+ prev= row1[-xsize];
+ step= 1;
+ while(y+step<ysize && row1[step*xsize]==128)
+ step++;
+
+ if(y+step!=ysize) {
+ /* now we can blend values */
+ next= row1[step*xsize];
+ /* note, prev value can be next value, but we do this loop to clear 128 then */
+ for(a=0; a<step; a++) {
+ int fac, mfac;
+
+ fac= ((a+1)<<8)/(step+1);
+ mfac= 255-fac;
+
+ row1[a*xsize]= (prev*mfac + next*fac)>>8;
+ }
+ }
+ }
+ }
+ }
+
+ /* last: pixels with 0 we fill in zbuffer, with 1 we skip for mask */
+ for(y=2; y<ysize; y++) {
+ /* setup rows */
+ row1= rectmove + (y-2)*xsize;
+ row2= row1 + xsize;
+ row3= row2 + xsize;
+ for(x=2; x<xsize; x++, row1++, row2++, row3++) {
+ if(row2[1]==0) {
+ if(row2[0]>1 || row2[2]>1 || row1[1]>1 || row3[1]>1)
+ row2[1]= 1;
+ }
+ }
+ }
+}
+
+void RE_zbuf_accumulate_vecblur(NodeBlurData *nbd, int xsize, int ysize, float *newrect, float *imgrect, float *vecbufrect, float *zbufrect)
+{
+ ZSpan zspan;
+ DrawBufPixel *rectdraw, *dr;
+ static float jit[16][2];
+ float v1[3], v2[3], v3[3], v4[3], fx, fy;
+ float *rectvz, *dvz, *dimg, *dvec1, *dvec2, *dz1, *dz2, *rectz, *minvecbufrect= NULL;
+ float maxspeedsq= (float)nbd->maxspeed*nbd->maxspeed;
+ int y, x, step, maxspeed=nbd->maxspeed, samples= nbd->samples;
+ int tsktsk= 0;
+ static int firsttime= 1;
+ char *rectmove, *dm;
+
+ zbuf_alloc_span(&zspan, xsize, ysize);
+ zspan.zmulx= ((float)xsize)/2.0;
+ zspan.zmuly= ((float)ysize)/2.0;
+ zspan.zofsx= 0.0f;
+ zspan.zofsy= 0.0f;
+
+ /* the buffers */
+ rectz= MEM_mapallocN(sizeof(float)*xsize*ysize, "zbuf accum");
+ zspan.rectz= (int *)rectz;
+
+ rectmove= MEM_mapallocN(xsize*ysize, "rectmove");
+ rectdraw= MEM_mapallocN(sizeof(DrawBufPixel)*xsize*ysize, "rect draw");
+ zspan.rectp= (int *)rectdraw;
+
+ /* debug... check if PASS_VECTOR_MAX still is in buffers */
+ dvec1= vecbufrect;
+ for(x= 4*xsize*ysize; x>0; x--, dvec1++) {
+ if(dvec1[0]==PASS_VECTOR_MAX) {
+ dvec1[0]= 0.0f;
+ tsktsk= 1;
+ }
+ }
+ if(tsktsk) printf("Found uninitialized speed in vector buffer... fixed.\n");
+
+ /* min speed? then copy speedbuffer to recalculate speed vectors */
+ if(nbd->minspeed) {
+ float minspeed= (float)nbd->minspeed;
+ float minspeedsq= minspeed*minspeed;
+
+ minvecbufrect= MEM_mapallocN(4*sizeof(float)*xsize*ysize, "minspeed buf");
+
+ dvec1= vecbufrect;
+ dvec2= minvecbufrect;
+ for(x= 2*xsize*ysize; x>0; x--, dvec1+=2, dvec2+=2) {
+ if(dvec1[0]==0.0f && dvec1[1]==0.0f) {
+ dvec2[0]= dvec1[0];
+ dvec2[1]= dvec1[1];
+ }
+ else {
+ float speedsq= dvec1[0]*dvec1[0] + dvec1[1]*dvec1[1];
+ if(speedsq <= minspeedsq) {
+ dvec2[0]= 0.0f;
+ dvec2[1]= 0.0f;
+ }
+ else {
+ speedsq= 1.0f - minspeed/sqrt(speedsq);
+ dvec2[0]= speedsq*dvec1[0];
+ dvec2[1]= speedsq*dvec1[1];
+ }
+ }
+ }
+ SWAP(float *, minvecbufrect, vecbufrect);
+ }
+
+ /* make vertex buffer with averaged speed and zvalues */
+ rectvz= MEM_mapallocN(5*sizeof(float)*(xsize+1)*(ysize+1), "vertices");
+ dvz= rectvz;
+ for(y=0; y<=ysize; y++) {
+
+ if(y==0) {
+ dvec1= vecbufrect + 4*y*xsize;
+ dz1= zbufrect + y*xsize;
+ }
+ else {
+ dvec1= vecbufrect + 4*(y-1)*xsize;
+ dz1= zbufrect + (y-1)*xsize;
+ }
+
+ if(y==ysize) {
+ dvec2= vecbufrect + 4*(y-1)*xsize;
+ dz2= zbufrect + (y-1)*xsize;
+ }
+ else {
+ dvec2= vecbufrect + 4*y*xsize;
+ dz2= zbufrect + y*xsize;
+ }
+
+ for(x=0; x<=xsize; x++, dz1++, dz2++) {
+
+ /* two vectors, so a step loop */
+ for(step=0; step<2; step++, dvec1+=2, dvec2+=2, dvz+=2) {
+ /* average on minimal speed */
+ int div= 0;
+
+ if(x!=0) {
+ if(dvec1[-4]!=0.0f || dvec1[-3]!=0.0f) {
+ dvz[0]= dvec1[-4];
+ dvz[1]= dvec1[-3];
+ div++;
+ }
+ if(dvec2[-4]!=0.0f || dvec2[-3]!=0.0f) {
+ if(div==0) {
+ dvz[0]= dvec2[-4];
+ dvz[1]= dvec2[-3];
+ div++;
+ }
+ else if( (ABS(dvec2[-4]) + ABS(dvec2[-3]))< (ABS(dvz[0]) + ABS(dvz[1])) ) {
+ dvz[0]= dvec2[-4];
+ dvz[1]= dvec2[-3];
+ }
+ }
+ }
+
+ if(x!=xsize) {
+ if(dvec1[0]!=0.0f || dvec1[1]!=0.0f) {
+ if(div==0) {
+ dvz[0]= dvec1[0];
+ dvz[1]= dvec1[1];
+ div++;
+ }
+ else if( (ABS(dvec1[0]) + ABS(dvec1[1]))< (ABS(dvz[0]) + ABS(dvz[1])) ) {
+ dvz[0]= dvec1[0];
+ dvz[1]= dvec1[1];
+ }
+ }
+ if(dvec2[0]!=0.0f || dvec2[1]!=0.0f) {
+ if(div==0) {
+ dvz[0]= dvec2[0];
+ dvz[1]= dvec2[1];
+ }
+ else if( (ABS(dvec2[0]) + ABS(dvec2[1]))< (ABS(dvz[0]) + ABS(dvz[1])) ) {
+ dvz[0]= dvec2[0];
+ dvz[1]= dvec2[1];
+ }
+ }
+ }
+ if(maxspeed) {
+ float speedsq= dvz[0]*dvz[0] + dvz[1]*dvz[1];
+ if(speedsq > maxspeedsq) {
+ speedsq= (float)maxspeed/sqrt(speedsq);
+ dvz[0]*= speedsq;
+ dvz[1]*= speedsq;
+ }
+ }
+ }
+ /* the z coordinate */
+ if(x!=0) {
+ if(x!=xsize)
+ dvz[0]= 0.25f*(dz1[-1] + dz2[-1] + dz1[0] + dz2[0]);
+ else dvz[0]= 0.5f*(dz1[0] + dz2[0]);
+ }
+ else dvz[0]= 0.5f*(dz1[-1] + dz2[-1]);
+
+ dvz++;
+ }
+ }
+
+ /* set border speeds to keep border speeds on border */
+ dz1= rectvz;
+ dz2= rectvz+5*(ysize)*(xsize+1);
+ for(x=0; x<=xsize; x++, dz1+=5, dz2+=5) {
+ dz1[1]= 0.0f;
+ dz2[1]= 0.0f;
+ dz1[3]= 0.0f;
+ dz2[3]= 0.0f;
+ }
+ dz1= rectvz;
+ dz2= rectvz+5*(xsize);
+ for(y=0; y<=ysize; y++, dz1+=5*(xsize+1), dz2+=5*(xsize+1)) {
+ dz1[0]= 0.0f;
+ dz2[0]= 0.0f;
+ dz1[2]= 0.0f;
+ dz2[2]= 0.0f;
+ }
+
+ /* tag moving pixels, only these faces we draw */
+ dm= rectmove;
+ dvec1= vecbufrect;
+ for(x=xsize*ysize; x>0; x--, dm++, dvec1+=4) {
+ if(dvec1[0]!=0.0f || dvec1[1]!=0.0f || dvec1[2]!=0.0f || dvec1[3]!=0.0f)
+ *dm= 255;
+ }
+
+ antialias_tagbuf(xsize, ysize, rectmove);
+
+ /* has to become static, the init-jit calls a random-seed, screwing up texture noise node */
+ if(firsttime) {
+ firsttime= 0;
+ BLI_initjit(jit[0], 16);
+ }
+
+ /* accumulate */
+ samples/= 2;
+ for(step= 1; step<=samples; step++) {
+ float speedfac= 0.5f*nbd->fac*(float)step/(float)(samples+1);
+ float blendfac= 1.0f/(ABS(step)+1);
+ int side, z= 4;
+
+ for(side=0; side<2; side++) {
+
+ /* clear zbuf, if we draw future we fill in not moving pixels */
+ if(0)
+ for(x= xsize*ysize-1; x>=0; x--) rectz[x]= 10e16;
+ else
+ for(x= xsize*ysize-1; x>=0; x--) {
+ if(rectmove[x]==0)
+ rectz[x]= zbufrect[x];
+ else
+ rectz[x]= 10e16;
+ }
+
+ /* clear drawing buffer */
+ for(x= xsize*ysize-1; x>=0; x--) rectdraw[x].colpoin= NULL;
+
+ dimg= imgrect;
+ dm= rectmove;
+ dz1= rectvz;
+ dz2= rectvz + 5*(xsize + 1);
+
+ if(side) {
+ dz1+= 2;
+ dz2+= 2;
+ z= 2;
+ speedfac= -speedfac;
+ }
+
+ for(fy= -0.5f+jit[step & 15][0], y=0; y<ysize; y++, fy+=1.0f) {
+ for(fx= -0.5f+jit[step & 15][1], x=0; x<xsize; x++, fx+=1.0f, dimg+=4, dz1+=5, dz2+=5, dm++) {
+ if(*dm>1) {
+ DrawBufPixel col;
+
+ /* make vertices */
+ v1[0]= speedfac*dz1[0]+fx; v1[1]= speedfac*dz1[1]+fy; v1[2]= dz1[z];
+ v2[0]= speedfac*dz1[5]+fx+1.0f; v2[1]= speedfac*dz1[6]+fy; v2[2]= dz1[z+5];
+ v3[0]= speedfac*dz2[5]+fx+1.0f; v3[1]= speedfac*dz2[6]+fy+1.0f; v3[2]= dz2[z+5];
+ v4[0]= speedfac*dz2[0]+fx; v4[1]= speedfac*dz2[1]+fy+1.0f; v4[2]= dz2[z];
+
+ if(*dm==255) col.alpha= 1.0f;
+ else if(*dm<2) col.alpha= 0.0f;
+ else col.alpha= ((float)*dm)/255.0f;
+ col.colpoin= dimg;
+
+ zbuf_fill_in_rgba(&zspan, &col, v1, v2, v3, v4);
+ }
+ }
+ dz1+=5;
+ dz2+=5;
+ }
+
+ /* accum */
+ for(dr= rectdraw, dz2=newrect, x= xsize*ysize-1; x>=0; x--, dr++, dz2+=4) {
+ if(dr->colpoin) {
+ float bfac= dr->alpha*blendfac;
+ float mf= 1.0f - bfac;
+
+ dz2[0]= mf*dz2[0] + bfac*dr->colpoin[0];
+ dz2[1]= mf*dz2[1] + bfac*dr->colpoin[1];
+ dz2[2]= mf*dz2[2] + bfac*dr->colpoin[2];
+ dz2[3]= mf*dz2[3] + bfac*dr->colpoin[3];
+ }
+ }
+ }
+ }
+
+ MEM_freeN(rectz);
+ MEM_freeN(rectmove);
+ MEM_freeN(rectdraw);
+ MEM_freeN(rectvz);
+ if(minvecbufrect) MEM_freeN(vecbufrect); /* rects were swapped! */
+ zbuf_free_span(&zspan);
+}
+
+/* ******************** ABUF ************************* */
+
+/**
+ * Copy results from the solid face z buffering to the transparent
+ * buffer.
+ */
+static void copyto_abufz(RenderPart *pa, int *arectz, int sample)
+{
+ PixStr *ps;
+ int x, y, *rza;
+ long *rd;
+
+ if(R.osa==0) {
+ memcpy(arectz, pa->rectz, 4*pa->rectx*pa->recty);
+ return;
+ }
+
+ rza= arectz;
+ rd= pa->rectdaps;
+
+ sample= (1<<sample);
+
+ for(y=0; y<pa->recty; y++) {
+ for(x=0; x<pa->rectx; x++) {
+
+ *rza= 0x7FFFFFFF;
+ if(*rd) {
+ /* when there's a sky pixstruct, fill in sky-Z, otherwise solid Z */
+ for(ps= (PixStr *)(*rd); ps; ps= ps->next) {
+ if(sample & ps->mask) {
+ *rza= ps->z;
+ break;
+ }
+ }
+ }
+
+ rd++; rza++;
+ }
+ }
+}
+
+
+/* ------------------------------------------------------------------------ */
+
+/**
+ * Do accumulation z buffering.
+ */
+
+static int zbuffer_abuf(RenderPart *pa, APixstr *APixbuf, ListBase *apsmbase, unsigned int lay)
+{
+ ZSpan zspan;
+ Material *ma=NULL;
+ VlakRen *vlr=NULL;
+ VertRen *v1, *v2, *v3, *v4;
+ float vec[3], hoco[4], mul, zval, fval;
+ int v, zvlnr= 0, zsample, dofill= 0;
+ char *clipflag= pa->clipflag;
+
+ zbuf_alloc_span(&zspan, pa->rectx, pa->recty);
+
+ /* needed for transform from hoco to zbuffer co */
+ zspan.zmulx= ((float)R.winx)/2.0;
+ zspan.zmuly= ((float)R.winy)/2.0;
+
+ /* the buffers */
+ zspan.arectz= MEM_mallocN(sizeof(int)*pa->rectx*pa->recty, "Arectz");
+ zspan.apixbuf= APixbuf;
+ zspan.apsmbase= apsmbase;
+
+ /* filling methods */
+ zspan.zbuffunc= zbuffillAc4;
+ zspan.zbuflinefunc= zbuflineAc;
+
+ for(zsample=0; zsample<R.osa || R.osa==0; zsample++) {
+
+ copyto_abufz(pa, zspan.arectz, zsample); /* init zbuffer */
+ zspan.mask= 1<<zsample;
+
+ if(R.osa) {
+ zspan.zofsx= -pa->disprect.xmin - R.jit[zsample][0];
+ zspan.zofsy= -pa->disprect.ymin - R.jit[zsample][1];
+ }
+ else if(R.i.curblur) {
+ zspan.zofsx= -pa->disprect.xmin - R.jit[R.i.curblur-1][0];
+ zspan.zofsy= -pa->disprect.ymin - R.jit[R.i.curblur-1][1];
+ }
+ else {
+ zspan.zofsx= -pa->disprect.xmin;
+ zspan.zofsy= -pa->disprect.ymin;
+ }
+ /* to center the sample position */
+ zspan.zofsx -= 0.5f;
+ zspan.zofsy -= 0.5f;
+
+ /* we use this to test if nothing was filled in */
+ zvlnr= 0;
+
+ for(v=0; v<R.totvlak; v++) {
+ if((v & 255)==0)
+ vlr= R.vlaknodes[v>>8].vlak;
+ else vlr++;
+
+ if(vlr->mat!=ma) {
+ ma= vlr->mat;
+ dofill= (ma->mode & MA_ZTRA) && !(ma->mode & MA_ONLYCAST);
+ }
+
+ if(dofill) {
+ if((vlr->flag & R_VISIBLE) && (vlr->lay & lay)) {
+ unsigned short partclip;
+
+ v1= vlr->v1;
+ v2= vlr->v2;
+ v3= vlr->v3;
+ v4= vlr->v4;
+
+ /* partclipping doesn't need viewplane clipping */
+ partclip= clipflag[v1->index] & clipflag[v2->index] & clipflag[v3->index];
+ if(v4)
+ partclip &= clipflag[v4->index];
+
+ if(partclip==0) {
+ /* a little advantage for transp rendering (a z offset) */
+ if( ma->zoffs != 0.0) {
+ mul= 0x7FFFFFFF;
+ zval= mul*(1.0+v1->ho[2]/v1->ho[3]);
+
+ VECCOPY(vec, v1->co);
+ /* z is negative, otherwise its being clipped */
+ vec[2]-= ma->zoffs;
+ projectverto(vec, R.winmat, hoco);
+ fval= mul*(1.0+hoco[2]/hoco[3]);
+
+ zspan.polygon_offset= (int) fabs(zval - fval );
+ }
+ else zspan.polygon_offset= 0;
+
+ zvlnr= v+1;
+
+ if(ma->mode & (MA_WIRE)) zbufclipwire(&zspan, zvlnr, vlr);
+ else {
+ if(v4 && (vlr->flag & R_STRAND)) {
+ zbufclip4(&zspan, zvlnr, v1->ho, v2->ho, v3->ho, v4->ho, v1->clip, v2->clip, v3->clip, v4->clip);
+ }
+ else {
+ zbufclip(&zspan, zvlnr, v1->ho, v2->ho, v3->ho, v1->clip, v2->clip, v3->clip);
+ if(v4) {
+ zvlnr+= RE_QUAD_OFFS;
+ zbufclip(&zspan, zvlnr, v1->ho, v3->ho, v4->ho, v1->clip, v3->clip, v4->clip);
+ }
+ }
+ }
+ }
+ }
+ if( (v & 255)==255)
+ if(R.test_break())
+ break;
+ }
+ }
+
+ if(R.osa==0) break;
+ if(R.test_break()) break;
+ if(zvlnr==0) break;
+ }
+
+ MEM_freeN(zspan.arectz);
+ zbuf_free_span(&zspan);
+
+ return zvlnr;
+}
+
+/* different rules for speed in transparent pass... */
+/* speed pointer NULL = sky, we clear */
+/* else if either alpha is full or no solid was filled in: copy speed */
+/* else fill in minimum speed */
+static void add_transp_speed(RenderLayer *rl, int offset, float *speed, float alpha, long *rdrect)
+{
+ RenderPass *rpass;
+
+ for(rpass= rl->passes.first; rpass; rpass= rpass->next) {
+ if(rpass->passtype==SCE_PASS_VECTOR) {
+ float *fp= rpass->rect + 4*offset;
+
+ if(speed==NULL) {
+ /* clear */
+ if(fp[0]==PASS_VECTOR_MAX) fp[0]= 0.0f;
+ if(fp[1]==PASS_VECTOR_MAX) fp[1]= 0.0f;
+ if(fp[2]==PASS_VECTOR_MAX) fp[2]= 0.0f;
+ if(fp[3]==PASS_VECTOR_MAX) fp[3]= 0.0f;
+ }
+ else if(rdrect==NULL || rdrect[offset]==0 || alpha>0.95f) {
+ QUATCOPY(fp, speed);
+ }
+ else {
+ /* add minimum speed in pixel */
+ if( (ABS(speed[0]) + ABS(speed[1]))< (ABS(fp[0]) + ABS(fp[1])) ) {
+ fp[0]= speed[0];
+ fp[1]= speed[1];
+ }
+ if( (ABS(speed[2]) + ABS(speed[3]))< (ABS(fp[2]) + ABS(fp[3])) ) {
+ fp[2]= speed[2];
+ fp[3]= speed[3];
+ }
+
+ }
+ break;
+ }
+ }
+}
+
+static void add_transp_obindex(RenderLayer *rl, int offset, int facenr)
+{
+ VlakRen *vlr= RE_findOrAddVlak(&R, (facenr-1) & RE_QUAD_MASK);
+ if(vlr && vlr->ob) {
+ RenderPass *rpass;
+
+ for(rpass= rl->passes.first; rpass; rpass= rpass->next) {
+ if(rpass->passtype == SCE_PASS_INDEXOB) {
+ float *fp= rpass->rect + offset;
+ *fp= (float)vlr->ob->index;
+ break;
+ }
+ }
+ }
+}
+
+/* ONLY OSA! merge all shaderesult samples to one */
+/* target should have been cleared */
+static void merge_transp_passes(RenderLayer *rl, ShadeResult *shr)
+{
+ RenderPass *rpass;
+ float weight= 1.0f/((float)R.osa);
+ int delta= sizeof(ShadeResult)/4;
+
+ for(rpass= rl->passes.first; rpass; rpass= rpass->next) {
+ float *col= NULL;
+ int pixsize= 0;
+
+ switch(rpass->passtype) {
+ case SCE_PASS_RGBA:
+ col= shr->col;
+ pixsize= 4;
+ break;
+ case SCE_PASS_DIFFUSE:
+ col= shr->diff;
+ break;
+ case SCE_PASS_SPEC:
+ col= shr->spec;
+ break;
+ case SCE_PASS_SHADOW:
+ col= shr->shad;
+ break;
+ case SCE_PASS_AO:
+ col= shr->ao;
+ break;
+ case SCE_PASS_REFLECT:
+ col= shr->refl;
+ break;
+ case SCE_PASS_RADIO:
+ col= shr->rad;
+ break;
+ case SCE_PASS_REFRACT:
+ col= shr->refr;
+ break;
+ case SCE_PASS_NORMAL:
+ col= shr->nor;
+ break;
+ case SCE_PASS_VECTOR:
+
+ {
+ ShadeResult *shr_t= shr+1;
+ float *fp= shr->winspeed; /* was initialized */
+ int samp;
+
+ /* add minimum speed in pixel */
+ for(samp= 1; samp<R.osa; samp++, shr_t++) {
+
+ if(shr_t->combined[3] > 0.0f) {
+ float *speed= shr_t->winspeed;
+
+ if( (ABS(speed[0]) + ABS(speed[1]))< (ABS(fp[0]) + ABS(fp[1])) ) {
+ fp[0]= speed[0];
+ fp[1]= speed[1];
+ }
+ if( (ABS(speed[2]) + ABS(speed[3]))< (ABS(fp[2]) + ABS(fp[3])) ) {
+ fp[2]= speed[2];
+ fp[3]= speed[3];
+ }
+ }
+ }
+ }
+ break;
+ }
+ if(col) {
+ float *fp= col+delta;
+ int samp;
+
+ for(samp= 1; samp<R.osa; samp++, fp+=delta) {
+ col[0]+= fp[0];
+ col[1]+= fp[1];
+ col[2]+= fp[2];
+ if(pixsize) col[3]+= fp[3];
+ }
+ col[0]*= weight;
+ col[1]*= weight;
+ col[2]*= weight;
+ if(pixsize) col[3]*= weight;
+ }
+ }
+
+}
+
+static void add_transp_passes(RenderLayer *rl, int offset, ShadeResult *shr, float alpha)
+{
+ RenderPass *rpass;
+
+ for(rpass= rl->passes.first; rpass; rpass= rpass->next) {
+ float *fp, *col= NULL;
+
+ switch(rpass->passtype) {
+ case SCE_PASS_RGBA:
+ fp= rpass->rect + 4*offset;
+ addAlphaOverFloat(fp, shr->col);
+ break;
+ case SCE_PASS_DIFFUSE:
+ col= shr->diff;
+ break;
+ case SCE_PASS_SPEC:
+ col= shr->spec;
+ break;
+ case SCE_PASS_SHADOW:
+ col= shr->shad;
+ break;
+ case SCE_PASS_AO:
+ col= shr->ao;
+ break;
+ case SCE_PASS_REFLECT:
+ col= shr->refl;
+ break;
+ case SCE_PASS_REFRACT:
+ col= shr->refr;
+ break;
+ case SCE_PASS_RADIO:
+ col= shr->rad;
+ break;
+ case SCE_PASS_NORMAL:
+ col= shr->nor;
+ break;
+ }
+ if(col) {
+
+ fp= rpass->rect + 3*offset;
+ fp[0]= alpha*col[0] + (1.0f-alpha)*fp[0];
+ fp[1]= alpha*col[1] + (1.0f-alpha)*fp[1];
+ fp[2]= alpha*col[2] + (1.0f-alpha)*fp[2];
+ }
+ }
+}
+
+
+
+static int vergzvlak(const void *a1, const void *a2)
+{
+ const int *x1=a1, *x2=a2;
+
+ if( x1[0] < x2[0] ) return 1;
+ else if( x1[0] > x2[0]) return -1;
+ return 0;
+}
+
+
+static void shade_tra_samples_fill(ShadeSample *ssamp, int x, int y, int z, int facenr, int curmask)
+{
+ ShadeInput *shi= ssamp->shi;
+ float xs, ys;
+
+ ssamp->tot= 0;
+
+ shade_input_set_triangle(shi, facenr, 1);
+
+ /* officially should always be true... we have no sky info */
+ if(shi->vlr) {
+
+ /* full osa is only set for OSA renders */
+ if(shi->vlr->flag & R_FULL_OSA) {
+ short shi_inc= 0, samp;
+
+ for(samp=0; samp<R.osa; samp++) {
+ if(curmask & (1<<samp)) {
+ xs= (float)x + R.jit[samp][0] + 0.5f; /* zbuffer has this inverse corrected, ensures xs,ys are inside pixel */
+ ys= (float)y + R.jit[samp][1] + 0.5f;
+
+ if(shi_inc) {
+ shade_input_copy_triangle(shi+1, shi);
+ shi++;
+ }
+ shi->mask= (1<<samp);
+ shi->samplenr= ssamp->samplenr++;
+ shade_input_set_viewco(shi, xs, ys, (float)z);
+ shade_input_set_uv(shi);
+ shade_input_set_normals(shi);
+
+ shi_inc= 1;
+ }
+ }
+ }
+ else {
+ if(R.osa) {
+ short b= R.samples->centmask[curmask];
+ xs= (float)x + R.samples->centLut[b & 15] + 0.5f;
+ ys= (float)y + R.samples->centLut[b>>4] + 0.5f;
+ }
+ else {
+ xs= (float)x + 0.5f;
+ ys= (float)y + 0.5f;
+ }
+ shi->mask= curmask;
+ shi->samplenr= ssamp->samplenr++;
+ shade_input_set_viewco(shi, xs, ys, (float)z);
+ shade_input_set_uv(shi);
+ shade_input_set_normals(shi);
+ }
+
+ /* total sample amount, shi->sample is static set in initialize */
+ ssamp->tot= shi->sample+1;
+ }
+}
+
+static int shade_tra_samples(ShadeSample *ssamp, int x, int y, int z, int facenr, int mask)
+{
+ shade_tra_samples_fill(ssamp, x, y, z, facenr, mask);
+
+ if(ssamp->tot) {
+ ShadeInput *shi= ssamp->shi;
+ ShadeResult *shr= ssamp->shr;
+ int samp;
+
+ /* if AO? */
+ shade_samples_do_AO(ssamp);
+
+ /* if shade (all shadepinputs have same passflag) */
+ if(shi->passflag & ~(SCE_PASS_Z|SCE_PASS_INDEXOB)) {
+ for(samp=0; samp<ssamp->tot; samp++, shi++, shr++) {
+ shade_input_set_shade_texco(shi);
+ shade_input_do_shade(shi, shr);
+
+ /* include lamphalos for ztra, since halo layer was added already */
+ if(R.flag & R_LAMPHALO)
+ if(shi->layflag & SCE_LAY_HALO)
+ renderspothalo(shi, shr->combined, shr->combined[3]);
+ }
+ }
+ return 1;
+ }
+ return 0;
+}
+
+static void addvecmul(float *v1, float *v2, float fac)
+{
+ v1[0]= v1[0]+fac*v2[0];
+ v1[1]= v1[1]+fac*v2[1];
+ v1[2]= v1[2]+fac*v2[2];
+}
+
+static int addtosamp_shr(ShadeResult *samp_shr, ShadeSample *ssamp, int addpassflag)
+{
+ int a, sample, retval = R.osa;
+
+ for(a=0; a < R.osa; a++, samp_shr++) {
+ ShadeInput *shi= ssamp->shi;
+ ShadeResult *shr= ssamp->shr;
+
+ for(sample=0; sample<ssamp->tot; sample++, shi++, shr++) {
+
+ if(shi->mask & (1<<a)) {
+ float fac= (1.0f - samp_shr->combined[3])*shr->combined[3];
+
+ addAlphaUnderFloat(samp_shr->combined, shr->combined);
+
+ if(addpassflag & SCE_PASS_VECTOR) {
+ QUATCOPY(samp_shr->winspeed, shr->winspeed);
+ }
+ /* optim... */
+ if(addpassflag & ~(SCE_PASS_VECTOR)) {
+
+ if(addpassflag & SCE_PASS_RGBA)
+ addAlphaUnderFloat(samp_shr->col, shr->col);
+
+ if(addpassflag & SCE_PASS_NORMAL)
+ addvecmul(samp_shr->nor, shr->nor, fac);
+
+ if(addpassflag & SCE_PASS_DIFFUSE)
+ addvecmul(samp_shr->diff, shr->diff, fac);
+
+ if(addpassflag & SCE_PASS_SPEC)
+ addvecmul(samp_shr->spec, shr->spec, fac);
+
+ if(addpassflag & SCE_PASS_SHADOW)
+ addvecmul(samp_shr->shad, shr->shad, fac);
+
+ if(addpassflag & SCE_PASS_AO)
+ addvecmul(samp_shr->ao, shr->ao, fac);
+
+ if(addpassflag & SCE_PASS_REFLECT)
+ addvecmul(samp_shr->refl, shr->refl, fac);
+
+ if(addpassflag & SCE_PASS_REFRACT)
+ addvecmul(samp_shr->refr, shr->refr, fac);
+
+ if(addpassflag & SCE_PASS_RADIO)
+ addvecmul(samp_shr->refr, shr->rad, fac);
+ }
+ }
+ }
+
+ if(samp_shr->combined[3]>0.999f) retval--;
+ }
+ return retval;
+}
+
+static void reset_sky_speedvectors(RenderPart *pa, RenderLayer *rl)
+{
+ /* speed vector exception... if solid render was done, sky pixels are set to zero already */
+ /* for all pixels with alpha zero, we re-initialize speed again then */
+ float *fp, *col;
+ int a;
+
+ fp= RE_RenderLayerGetPass(rl, SCE_PASS_VECTOR);
+ if(fp==NULL) return;
+ col= rl->acolrect+3;
+
+ for(a= 4*pa->rectx*pa->recty -4; a>=0; a-=4) {
+ if(col[a]==0.0f) {
+ fp[a]= PASS_VECTOR_MAX;
+ fp[a+1]= PASS_VECTOR_MAX;
+ fp[a+2]= PASS_VECTOR_MAX;
+ fp[a+3]= PASS_VECTOR_MAX;
+ }
+ }
+}
+
+#define MAX_ZROW 2000
+/* main render call to fill in pass the full transparent layer */
+/* returns a mask, only if a) transp rendered and b) solid was rendered */
+unsigned short *zbuffer_transp_shade(RenderPart *pa, RenderLayer *rl, float *pass)
+{
+ RenderResult *rr= pa->result;
+ ShadeSample ssamp;
+ APixstr *APixbuf; /* Zbuffer: linked list of face samples */
+ APixstr *ap, *aprect, *apn;
+ ListBase apsmbase={NULL, NULL};
+ ShadeResult samp_shr[16]; /* MAX_OSA */
+ float sampalpha, *passrect= pass;
+ long *rdrect;
+ int x, y, crop=0, a, zrow[MAX_ZROW][3], totface;
+ int addpassflag, offs= 0, od, addzbuf;
+ unsigned short *ztramask= NULL;
+
+ /* looks nicer for calling code */
+ if(R.test_break())
+ return NULL;
+
+ if(R.osa>16) { /* MAX_OSA */
+ printf("zbuffer_transp_shade: osa too large\n");
+ G.afbreek= 1;
+ return NULL;
+ }
+
+ APixbuf= MEM_callocN(pa->rectx*pa->recty*sizeof(APixstr), "APixbuf");
+
+ /* general shader info, passes */
+ shade_sample_initialize(&ssamp, pa, rl);
+ addpassflag= rl->passflag & ~(SCE_PASS_Z|SCE_PASS_COMBINED);
+ addzbuf= rl->passflag & SCE_PASS_Z;
+
+ if(R.osa)
+ sampalpha= 1.0f/(float)R.osa;
+ else
+ sampalpha= 1.0f;
+
+ /* fill the Apixbuf */
+ if(0 == zbuffer_abuf(pa, APixbuf, &apsmbase, rl->lay)) {
+ /* nothing filled in */
+ MEM_freeN(APixbuf);
+ freepsA(&apsmbase);
+ return NULL;
+ }
+
+ aprect= APixbuf;
+ rdrect= pa->rectdaps;
+
+ /* irregular shadowb buffer creation */
+ if(R.r.mode & R_SHADOW)
+ ISB_create(pa, APixbuf);
+
+ /* masks, to have correct alpha combine */
+ if(R.osa && (rl->layflag & SCE_LAY_SOLID))
+ ztramask= MEM_callocN(pa->rectx*pa->recty*sizeof(short), "ztramask");
+
+ /* zero alpha pixels get speed vector max again */
+ if(addpassflag & SCE_PASS_VECTOR)
+ if(rl->layflag & SCE_LAY_SOLID)
+ reset_sky_speedvectors(pa, rl);
+
+ /* filtered render, for now we assume only 1 filter size */
+ if(pa->crop) {
+ crop= 1;
+ offs= pa->rectx + 1;
+ passrect+= 4*offs;
+ aprect+= offs;
+ }
+
+ /* init scanline updates */
+ rr->renrect.ymin= 0;
+ rr->renrect.ymax= -pa->crop;
+ rr->renlay= rl;
+
+ /* render the tile */
+ for(y=pa->disprect.ymin+crop; y<pa->disprect.ymax-crop; y++, rr->renrect.ymax++) {
+ pass= passrect;
+ ap= aprect;
+ od= offs;
+
+ if(R.test_break())
+ break;
+
+ for(x=pa->disprect.xmin+crop; x<pa->disprect.xmax-crop; x++, ap++, pass+=4, od++) {
+
+ if(ap->p[0]==0) {
+ if(addpassflag & SCE_PASS_VECTOR)
+ add_transp_speed(rl, od, NULL, 0.0f, rdrect);
+ }
+ else {
+ /* sort in z */
+ totface= 0;
+ apn= ap;
+ while(apn) {
+ for(a=0; a<4; a++) {
+ if(apn->p[a]) {
+ zrow[totface][0]= apn->z[a];
+ zrow[totface][1]= apn->p[a];
+ zrow[totface][2]= apn->mask[a];
+ totface++;
+ if(totface>=MAX_ZROW) totface= MAX_ZROW-1;
+ }
+ else break;
+ }
+ apn= apn->next;
+ }
+
+ if(totface==2) {
+ if(zrow[0][0] < zrow[1][0]) {
+ a= zrow[0][0]; zrow[0][0]= zrow[1][0]; zrow[1][0]= a;
+ a= zrow[0][1]; zrow[0][1]= zrow[1][1]; zrow[1][1]= a;
+ a= zrow[0][2]; zrow[0][2]= zrow[1][2]; zrow[1][2]= a;
+ }
+
+ }
+ else if(totface>2) {
+ qsort(zrow, totface, sizeof(int)*3, vergzvlak);
+ }
+
+ /* zbuffer and index pass for transparent, no AA or filters */
+ if(addzbuf)
+ if(pa->rectz[od]>zrow[totface-1][0])
+ pa->rectz[od]= zrow[totface-1][0];
+
+ if(addpassflag & SCE_PASS_INDEXOB)
+ add_transp_obindex(rl, od, zrow[totface-1][1]);
+
+
+ if(R.osa==0) {
+ while(totface>0) {
+ totface--;
+
+ if(shade_tra_samples(&ssamp, x, y, zrow[totface][0], zrow[totface][1], zrow[totface][2])) {
+ if(addpassflag)
+ add_transp_passes(rl, od, ssamp.shr, (1.0f-pass[3])*ssamp.shr[0].combined[3]);
+
+ addAlphaUnderFloat(pass, ssamp.shr[0].combined);
+ if(pass[3]>=0.999) break;
+ }
+ }
+ if(addpassflag & SCE_PASS_VECTOR)
+ add_transp_speed(rl, od, ssamp.shr[0].winspeed, pass[3], rdrect);
+ }
+ else {
+ short filled, *sp= (short *)(ztramask+od);
+
+ /* for each mask-sample we alpha-under colors. then in end it's added using filter */
+ memset(samp_shr, 0, sizeof(ShadeResult)*R.osa);
+
+ /* nice this memset, but speed vectors are not initialized OK then. it is sufficient to only clear 1 (see merge_transp_passes) */
+ if(addpassflag & SCE_PASS_VECTOR)
+ samp_shr->winspeed[0]= samp_shr->winspeed[1]= samp_shr->winspeed[2]= samp_shr->winspeed[3]= PASS_VECTOR_MAX;
+
+ while(totface>0) {
+ totface--;
+
+ if(shade_tra_samples(&ssamp, x, y, zrow[totface][0], zrow[totface][1], zrow[totface][2])) {
+ filled= addtosamp_shr(samp_shr, &ssamp, addpassflag);
+
+ if(ztramask)
+ *sp |= zrow[totface][2];
+ if(filled==0)
+ break;
+ }
+ }
+
+ for(a=0; a<R.osa; a++) {
+ add_filt_fmask(1<<a, samp_shr[a].combined, pass, rr->rectx);
+ }
+
+ if(addpassflag) {
+ /* merge all in one, and then add */
+ merge_transp_passes(rl, samp_shr);
+ add_transp_passes(rl, od, samp_shr, pass[3]);
+
+ if(addpassflag & SCE_PASS_VECTOR)
+ add_transp_speed(rl, od, samp_shr[0].winspeed, pass[3], rdrect);
+ }
+ }
+ }
+ }
+
+ aprect+= pa->rectx;
+ passrect+= 4*pa->rectx;
+ offs+= pa->rectx;
+ }
+
+ /* disable scanline updating */
+ rr->renlay= NULL;
+
+ MEM_freeN(APixbuf);
+ freepsA(&apsmbase);
+
+ if(R.r.mode & R_SHADOW)
+ ISB_free(pa);
+
+ return ztramask;
+}
+
+/* *************** */
+
+/* uses part zbuffer values to convert into distances from camera in renderlayer */
+void convert_zbuf_to_distbuf(RenderPart *pa, RenderLayer *rl)
+{
+ RenderPass *rpass;
+ float *rectzf, zco;
+ int a, *rectz, ortho= R.r.mode & R_ORTHO;
+
+ if(pa->rectz==NULL) return;
+ for(rpass= rl->passes.first; rpass; rpass= rpass->next)
+ if(rpass->passtype==SCE_PASS_Z)
+ break;
+
+ if(rpass==NULL) {
+ printf("called convert zbuf wrong...\n");
+ return;
+ }
+
+ rectzf= rpass->rect;
+ rectz= pa->rectz;
+
+ for(a=pa->rectx*pa->recty; a>0; a--, rectz++, rectzf++) {
+ if(*rectz>=0x7FFFFFF0)
+ *rectzf= 10e10;
+ else {
+ /* inverse of zbuf calc: zbuf = MAXZ*hoco_z/hoco_w */
+ /* or: (R.winmat[3][2] - zco*R.winmat[3][3])/(R.winmat[2][2] - R.winmat[2][3]*zco); */
+ /* if ortho [2][3] is zero, else [3][3] is zero */
+
+ zco= ((float)*rectz)/2147483647.0f;
+ if(ortho)
+ *rectzf= (R.winmat[3][2] - zco*R.winmat[3][3])/(R.winmat[2][2]);
+ else
+ *rectzf= (R.winmat[3][2])/(R.winmat[2][2] - R.winmat[2][3]*zco);
+ }
+ }
+}
+
+
+/* end of zbuf.c */
+
+
+
+
diff --git a/source/blender/src/.BCkey b/source/blender/src/.BCkey
new file mode 100644
index 00000000000..a0fd5e817d4
--- /dev/null
+++ b/source/blender/src/.BCkey
@@ -0,0 +1 @@
+0xffffffff 0xfffffff0 fffffffe
diff --git a/source/blender/src/B.blend.c b/source/blender/src/B.blend.c
new file mode 100644
index 00000000000..0a33fc99013
--- /dev/null
+++ b/source/blender/src/B.blend.c
@@ -0,0 +1,3076 @@
+/* DataToC output of file <B_blend> */
+
+int datatoc_B_blend_size= 98212;
+char datatoc_B_blend[]= {
+ 66, 76, 69, 78,
+ 68, 69, 82, 95,118, 50, 52, 49, 82, 69, 78, 68, 32, 0, 0, 0,144,240,255,191, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
+250, 0, 0, 0, 83, 99,101,110,101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 83, 82, 0, 0,
+116, 0, 0, 0, 8,237,195, 8,109, 0, 0, 0, 1, 0, 0, 0, 96, 40,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 83, 82, 49, 45, 65,110,105,109, 97,116,105,111,110, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+232,150,192, 8,168,240,195, 8,232,240,195, 8, 24,247,195, 8, 96,247,195, 8,152, 31,196, 8,136,251,196, 8, 0, 0,231, 3,
+143, 1,174, 4,232, 3, 32, 3, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0,232,150,192, 8,110, 0, 0, 0, 1, 0, 0, 0,168,237,195, 8, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0,168,237,195, 8,110, 0, 0, 0, 1, 0, 0, 0,
+232,237,195, 8,232,150,192, 8, 0, 0, 0, 0, 0, 0, 32, 3, 0, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0,232,237,195, 8,
+110, 0, 0, 0, 1, 0, 0, 0, 40,238,195, 8,168,237,195, 8, 0, 0, 0, 0,232, 3, 32, 3, 0, 0, 0, 0, 68, 65, 84, 65,
+ 20, 0, 0, 0, 40,238,195, 8,110, 0, 0, 0, 1, 0, 0, 0,104,238,195, 8,232,237,195, 8, 0, 0, 0, 0,232, 3, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0,104,238,195, 8,110, 0, 0, 0, 1, 0, 0, 0,168,238,195, 8, 40,238,195, 8,
+ 0, 0, 0, 0,232, 3,248, 0, 0, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0,168,238,195, 8,110, 0, 0, 0, 1, 0, 0, 0,
+232,238,195, 8,104,238,195, 8, 0, 0, 0, 0, 0, 0, 6, 3, 0, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0,232,238,195, 8,
+110, 0, 0, 0, 1, 0, 0, 0, 40,239,195, 8,168,238,195, 8, 0, 0, 0, 0,232, 3, 6, 3, 0, 0, 0, 0, 68, 65, 84, 65,
+ 20, 0, 0, 0, 40,239,195, 8,110, 0, 0, 0, 1, 0, 0, 0,104,239,195, 8,232,238,195, 8, 0, 0, 0, 0,160, 2,248, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0,104,239,195, 8,110, 0, 0, 0, 1, 0, 0, 0,168,239,195, 8, 40,239,195, 8,
+ 0, 0, 0, 0,160, 2, 6, 3, 0, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0,168,239,195, 8,110, 0, 0, 0, 1, 0, 0, 0,
+232,239,195, 8,104,239,195, 8, 0, 0, 0, 0, 0, 0,188, 0, 0, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0,232,239,195, 8,
+110, 0, 0, 0, 1, 0, 0, 0, 40,240,195, 8,168,239,195, 8, 0, 0, 0, 0,232, 3,188, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+ 20, 0, 0, 0, 40,240,195, 8,110, 0, 0, 0, 1, 0, 0, 0,104,240,195, 8,232,239,195, 8, 0, 0, 0, 0,204, 0,248, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0,104,240,195, 8,110, 0, 0, 0, 1, 0, 0, 0,168,240,195, 8, 40,240,195, 8,
+ 0, 0, 0, 0,204, 0, 6, 3, 0, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0,168,240,195, 8,110, 0, 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0,104,240,195, 8, 0, 0, 0, 0,204, 0,188, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,232,240,195, 8,
+111, 0, 0, 0, 1, 0, 0, 0, 48,241,195, 8, 0, 0, 0, 0,168,237,195, 8,232,237,195, 8, 1, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65, 24, 0, 0, 0, 48,241,195, 8,111, 0, 0, 0, 1, 0, 0, 0,120,241,195, 8,232,240,195, 8,232,150,192, 8,
+ 40,238,195, 8, 1, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,120,241,195, 8,111, 0, 0, 0, 1, 0, 0, 0,
+192,241,195, 8, 48,241,195, 8,168,237,195, 8,168,238,195, 8, 1, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,
+192,241,195, 8,111, 0, 0, 0, 1, 0, 0, 0, 8,242,195, 8,120,241,195, 8,232,237,195, 8,232,238,195, 8, 1, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0, 8,242,195, 8,111, 0, 0, 0, 1, 0, 0, 0, 80,242,195, 8,192,241,195, 8,
+168,238,195, 8,232,238,195, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0, 80,242,195, 8,111, 0, 0, 0,
+ 1, 0, 0, 0,152,242,195, 8, 8,242,195, 8,104,238,195, 8, 40,239,195, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+ 24, 0, 0, 0,152,242,195, 8,111, 0, 0, 0, 1, 0, 0, 0,224,242,195, 8, 80,242,195, 8,232,238,195, 8,104,239,195, 8,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,224,242,195, 8,111, 0, 0, 0, 1, 0, 0, 0, 40,243,195, 8,
+152,242,195, 8, 40,239,195, 8,104,239,195, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0, 40,243,195, 8,
+111, 0, 0, 0, 1, 0, 0, 0,112,243,195, 8,224,242,195, 8,104,238,195, 8,232,238,195, 8, 1, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65, 24, 0, 0, 0,112,243,195, 8,111, 0, 0, 0, 1, 0, 0, 0,184,243,195, 8, 40,243,195, 8,232,150,192, 8,
+168,239,195, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,184,243,195, 8,111, 0, 0, 0, 1, 0, 0, 0,
+ 0,244,195, 8,112,243,195, 8,104,238,195, 8,232,239,195, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,
+ 0,244,195, 8,111, 0, 0, 0, 1, 0, 0, 0, 72,244,195, 8,184,243,195, 8, 40,238,195, 8,232,239,195, 8, 0, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0, 72,244,195, 8,111, 0, 0, 0, 1, 0, 0, 0,144,244,195, 8, 0,244,195, 8,
+168,239,195, 8,232,239,195, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,144,244,195, 8,111, 0, 0, 0,
+ 1, 0, 0, 0,216,244,195, 8, 72,244,195, 8, 40,239,195, 8, 40,240,195, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+ 24, 0, 0, 0,216,244,195, 8,111, 0, 0, 0, 1, 0, 0, 0, 32,245,195, 8,144,244,195, 8,168,238,195, 8,104,240,195, 8,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0, 32,245,195, 8,111, 0, 0, 0, 1, 0, 0, 0,104,245,195, 8,
+216,244,195, 8,104,239,195, 8,104,240,195, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,104,245,195, 8,
+111, 0, 0, 0, 1, 0, 0, 0,176,245,195, 8, 32,245,195, 8, 40,240,195, 8,104,240,195, 8, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65, 24, 0, 0, 0,176,245,195, 8,111, 0, 0, 0, 1, 0, 0, 0,248,245,195, 8,104,245,195, 8,168,239,195, 8,
+168,240,195, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,248,245,195, 8,111, 0, 0, 0, 1, 0, 0, 0,
+ 64,246,195, 8,176,245,195, 8,232,239,195, 8,168,240,195, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,
+ 64,246,195, 8,111, 0, 0, 0, 1, 0, 0, 0,136,246,195, 8,248,245,195, 8,104,238,195, 8, 40,240,195, 8, 0, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,136,246,195, 8,111, 0, 0, 0, 1, 0, 0, 0,208,246,195, 8, 64,246,195, 8,
+ 40,240,195, 8,168,240,195, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,208,246,195, 8,111, 0, 0, 0,
+ 1, 0, 0, 0, 24,247,195, 8,136,246,195, 8,168,238,195, 8,168,239,195, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+ 24, 0, 0, 0, 24,247,195, 8,111, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,208,246,195, 8,104,240,195, 8,168,240,195, 8,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,204, 0, 0, 0, 96,247,195, 8,113, 0, 0, 0, 1, 0, 0, 0,104, 5,196, 8,
+ 0, 0, 0, 0,232,150,192, 8,168,239,195, 8,232,239,195, 8, 40,238,195, 8, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0,232, 3, 0, 0,
+ 0, 0, 0, 0,187, 0, 0, 0, 0, 0, 0, 0,232, 3, 0, 0,161, 0, 0, 0,187, 0, 0, 0, 0, 0, 0, 0,232, 3, 0, 0,
+ 0, 0, 0, 0,160, 0, 0, 0, 0, 0, 0, 0, 2, 0, 4, 4,233, 3,161, 0, 3, 0, 3, 0, 79, 1, 0, 0, 7, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,232, 2,196, 8,232, 3,196, 8, 0, 0, 0, 0, 0, 0, 0, 0,
+ 88,248,195, 8, 24, 2,196, 8, 68, 65, 84, 65,164, 0, 0, 0, 88,248,195, 8,112, 0, 0, 0, 1, 0, 0, 0, 40,249,195, 8,
+ 0, 0, 0, 0, 76,105,110,107, 32, 97,110,100, 32, 77, 97,116,101,114,105, 97,108,115, 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, 69,100,105,116,105,110,103, 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, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65,164, 0, 0, 0, 40,249,195, 8,112, 0, 0, 0, 1, 0, 0, 0,248,249,195, 8, 88,248,195, 8, 77,101,115,104,
+ 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, 69,100,105,116,
+105,110,103, 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, 70, 1, 0, 0,
+ 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0,
+248,249,195, 8,112, 0, 0, 0, 1, 0, 0, 0,200,250,195, 8, 40,249,195, 8, 65,110,105,109, 32,115,101,116,116,105,110,103,
+115, 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, 79, 98,106,101, 99,116, 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, 62, 1,204, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0,200,250,195, 8,112, 0, 0, 0,
+ 1, 0, 0, 0,152,251,195, 8,248,249,195, 8, 68,114, 97,119, 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, 79, 98,106,101, 99,116, 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, 70, 1, 0, 0, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0,152,251,195, 8,112, 0, 0, 0, 1, 0, 0, 0,104,252,195, 8,
+200,250,195, 8, 67,111,110,115,116,114, 97,105,110,116,115, 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, 79, 98,106,101, 99,116, 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,140, 2, 0, 0, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65,164, 0, 0, 0,104,252,195, 8,112, 0, 0, 0, 1, 0, 0, 0, 56,253,195, 8,152,251,195, 8, 69,102,102,101,
+ 99,116,115, 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, 79, 98,106,101,
+ 99,116, 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,210, 3, 0, 0,
+162, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0,
+ 56,253,195, 8,112, 0, 0, 0, 1, 0, 0, 0, 8,254,195, 8,104,252,195, 8, 72,111,111,107,115, 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, 79, 98,106,101, 99,116, 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, 70, 1, 0, 0, 62, 1,204, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,200,250,195, 8, 68, 65, 84, 65,164, 0, 0, 0, 8,254,195, 8,112, 0, 0, 0,
+ 1, 0, 0, 0,216,254,195, 8, 56,253,195, 8, 80, 97,114,116,105, 99,108,101, 32, 73,110,116,101,114, 97, 99,116,105,111,110,
+ 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, 79, 98,106,101, 99,116, 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,140, 2, 0, 0, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,152,251,195, 8, 68, 65, 84, 65,164, 0, 0, 0,216,254,195, 8,112, 0, 0, 0, 1, 0, 0, 0,168,255,195, 8,
+ 8,254,195, 8, 83,111,102,116, 98,111,100,121, 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, 79, 98,106,101, 99,116, 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,140, 2, 0, 0, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,152,251,195, 8,
+ 68, 65, 84, 65,164, 0, 0, 0,168,255,195, 8,112, 0, 0, 0, 1, 0, 0, 0,120, 0,196, 8,216,254,195, 8, 79,117,116,112,
+117,116, 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, 82,101,110,100,
+101,114, 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,
+ 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0,
+120, 0,196, 8,112, 0, 0, 0, 1, 0, 0, 0, 72, 1,196, 8,168,255,195, 8, 82,101,110,100,101,114, 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, 82,101,110,100,101,114, 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, 70, 1, 0, 0, 62, 1,204, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0, 72, 1,196, 8,112, 0, 0, 0,
+ 1, 0, 0, 0, 24, 2,196, 8,120, 0,196, 8, 65,110,105,109, 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, 82,101,110,100,101,114, 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,140, 2, 0, 0, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0, 24, 2,196, 8,112, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 72, 1,196, 8, 70,111,114,109, 97,116, 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, 82,101,110,100,101,114, 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,210, 3, 0, 0, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65,212, 0, 0, 0,232, 2,196, 8, 94, 0, 0, 0, 1, 0, 0, 0,232, 3,196, 8, 0, 0, 0, 0, 4, 0, 0, 0,
+ 51, 51, 51, 63, 1, 86,141, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
+ 0, 0, 0,193, 0, 64,212, 68, 0, 0, 0,193, 0, 0,104, 67, 0, 0, 0,193,145,133,185, 68, 0, 0, 0,193, 0, 0,104, 67,
+ 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,128, 67, 0, 0, 40, 66, 0, 0,200, 68, 0, 0,225, 67,
+ 0, 0, 0, 63,225,122,180, 63, 0, 0, 1, 0, 1, 0, 1, 0,233, 3,161, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,150, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 84, 1, 0, 0,232, 3,196, 8, 96, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+232, 2,196, 8, 5, 0, 0, 0, 51, 51, 51, 63, 1, 86,141, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 20, 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,
+ 47, 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,
+ 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, 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, 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, 8, 0, 0, 0, 0, 0, 0, 0, 57, 0, 2, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,255,255, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,204, 0, 0, 0,104, 5,196, 8,113, 0, 0, 0,
+ 1, 0, 0, 0, 96, 6,196, 8, 96,247,195, 8,168,238,195, 8,168,237,195, 8,232,237,195, 8,232,238,195, 8, 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, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,232, 3, 0, 0, 7, 3, 0, 0, 32, 3, 0, 0, 0, 0, 0, 0,232, 3, 0, 0, 7, 3, 0, 0, 33, 3, 0, 0,
+ 0, 0, 0, 0,232, 3, 0, 0, 32, 3, 0, 0, 32, 3, 0, 0, 0, 0, 0, 0, 1, 0, 7, 7,233, 3, 1, 0, 3, 0, 3, 1,
+196, 2, 0, 0, 7, 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, 68, 65, 84, 65,204, 0, 0, 0, 96, 6,196, 8,113, 0, 0, 0,
+ 1, 0, 0, 0, 88, 13,196, 8,104, 5,196, 8, 40,240,195, 8,104,240,195, 8,104,239,195, 8, 40,239,195, 8, 0, 0, 0, 0,
+ 71,187,204, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,186,252,191, 61, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,128, 0, 0, 0,128,111, 18, 3,187, 0, 0, 0,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63,
+205, 0, 0, 0,159, 2, 0, 0,249, 0, 0, 0, 5, 3, 0, 0,205, 0, 0, 0,159, 2, 0, 0,249, 0, 0, 0, 19, 1, 0, 0,
+205, 0, 0, 0,159, 2, 0, 0, 20, 1, 0, 0, 5, 3, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1,211, 1,242, 1, 1, 0, 3, 0,
+251, 2, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,248, 8,196, 8,216, 11,196, 8,
+ 0, 0, 0, 0, 0, 0, 0, 0, 88, 7,196, 8, 40, 8,196, 8, 68, 65, 84, 65,164, 0, 0, 0, 88, 7,196, 8,112, 0, 0, 0,
+ 1, 0, 0, 0, 40, 8,196, 8, 0, 0, 0, 0, 84,114, 97,110,115,102,111,114,109, 32, 80,114,111,112,101,114,116,105,101,115,
+ 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, 86,105,101,119, 51,100, 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,140, 0,210, 0, 62, 1,204, 0, 0, 0, 0, 0,162, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0, 40, 8,196, 8,112, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 88, 7,196, 8, 51, 68, 32, 86,105,101,119,112,111,114,116, 32,112,114,111,112,101,114,116,105,101,115, 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, 86,105,101,119, 51,100, 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, 8, 0, 8, 0, 62, 1,204, 0, 0, 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65,180, 2, 0, 0,248, 8,196, 8, 89, 0, 0, 0, 1, 0, 0, 0,216, 11,196, 8, 0, 0, 0, 0, 1, 0, 0, 0,
+ 51, 51, 51, 63, 1, 86,156, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0,128, 63, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 71,187,204, 61, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,186,252,191, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+111, 18, 3,187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63,178, 13, 32, 65, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,148,173, 42, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+255,255,249,195, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 71,187,204, 61, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,186,252,191, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 0, 0, 0,128,
+111, 18, 3,187, 0, 0, 0,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0,128, 63, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0,128, 63, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,148,173, 42, 65, 0, 0, 7, 0, 40, 9,197, 8, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 3, 0, 0, 0, 8, 24, 0, 0, 12, 66, 0, 0,128, 63, 0, 0,128, 63, 0, 0, 0, 0,
+205,204,204, 61, 0, 0,250, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 32, 0, 1, 0, 7, 0,175, 0, 0, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0, 0,221,162, 77, 64, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,221,162, 77, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,221,162, 77, 64,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 84, 1, 0, 0,216, 11,196, 8, 96, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+248, 8,196, 8, 5, 0, 0, 0, 51, 51, 51, 63, 1, 86,156, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 20, 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,
+ 47, 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,
+ 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, 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, 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, 8, 0, 0, 0, 0, 0, 0, 0, 57, 0, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,255,255, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,204, 0, 0, 0, 88, 13,196, 8,113, 0, 0, 0,
+ 1, 0, 0, 0,240, 24,196, 8, 96, 6,196, 8, 40,239,195, 8,104,239,195, 8,232,238,195, 8,104,238,195, 8, 0, 0, 0, 0,
+ 1,184,157, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,140, 63, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 80, 1,128,191, 0, 0,128,191, 0, 0, 0, 0, 0, 0, 0, 0,225,215,163,188, 0, 0, 0, 0,
+161, 2, 0, 0,232, 3, 0, 0,249, 0, 0, 0, 5, 3, 0, 0,161, 2, 0, 0,232, 3, 0, 0,249, 0, 0, 0, 19, 1, 0, 0,
+161, 2, 0, 0,232, 3, 0, 0, 20, 1, 0, 0, 5, 3, 0, 0, 0, 0, 0, 0, 1, 0, 2, 2, 72, 1,242, 1, 3, 0, 3, 0,
+203, 1, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 15,196, 8,112, 23,196, 8,
+ 0, 0, 0, 0, 0, 0, 0, 0, 80, 14,196, 8, 80, 14,196, 8, 68, 65, 84, 65,164, 0, 0, 0, 80, 14,196, 8,112, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84,114, 97,110,115,102,111,114,109, 32, 80,114,111,112,101,114,116,105,101,115,
+ 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, 73,112,111, 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, 33, 0,167, 0, 62, 1,204, 0, 0, 0, 0, 0,162, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 40, 1, 0, 0, 32, 15,196, 8, 93, 0, 0, 0, 1, 0, 0, 0,120, 16,196, 8,
+ 0, 0, 0, 0, 2, 0, 0, 0, 51, 51, 51, 63, 1, 86,160, 92, 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,122, 67,205,204,204,189,205,204,140, 63, 0, 0, 0, 0, 0, 0,122, 67,
+ 0, 0,160,192, 0, 0,160, 64, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0,242, 1, 0, 0, 16, 0, 0, 0, 7, 1, 0, 0,
+ 0, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 7, 1, 0, 0, 16, 0, 0, 0,242, 1, 0, 0, 10,215, 35, 60, 10,215, 35, 60,
+ 0, 96,106, 70, 0, 0,122, 68, 0, 0, 0, 0, 0, 0, 0, 0, 9, 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, 72, 12,197, 8, 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, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 79, 66,
+ 1, 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,122, 67,205,204,204,189,
+205,204,140, 63, 68, 65, 84, 65,196, 0, 0, 0,120, 16,196, 8, 97, 0, 0, 0, 1, 0, 0, 0,104, 17,196, 8, 32, 15,196, 8,
+ 3, 0, 0, 0, 51, 51, 51, 63, 1, 86,160, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,182, 67, 0, 0,209,195, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,182, 67, 0, 0,190,195, 0, 0, 0,181, 0, 0, 0, 0,
+ 16, 0, 0, 0, 0, 0, 0, 0,124, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0,
+124, 1, 0, 0, 0, 0, 0, 0,124, 1, 0, 0, 0, 0,190,195, 0, 0,190,195, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63,
+ 0, 0,128, 63, 1, 0, 1, 0, 1, 0, 1, 0,108, 1,124, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,142, 3,
+ 1, 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, 68, 65, 84, 65,
+160, 0, 0, 0,104, 17,196, 8,166, 0, 0, 0, 1, 0, 0, 0, 56, 18,196, 8,120, 16,196, 8, 11, 0, 0, 0, 51, 51, 51, 63,
+ 1, 86,160, 92, 0, 0,128,192, 0, 0,122, 67, 0, 0,128,192, 0, 0,127, 67, 0, 0,128,192, 0, 0, 72, 66, 0, 0,128,192,
+ 0, 0,127, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,124, 1, 0, 0, 0, 0, 0, 0,
+ 16, 0, 0, 0, 0, 0, 0, 0,124, 1, 0, 0, 16, 0, 0, 0,124, 1, 0, 0, 0, 0,128, 63, 0,128,129, 67, 0, 0,250, 70,
+ 0,128,129, 67,205,204,204, 61, 0, 0, 32, 65, 8, 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, 68, 65, 84, 65,120, 0, 0, 0, 56, 18,196, 8,100, 0, 0, 0,
+ 1, 0, 0, 0,224, 18,196, 8,104, 17,196, 8, 9, 0, 0, 0, 51, 51, 51, 63, 1, 86,160, 92, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,240, 3,197, 8, 0, 0, 0, 0, 31, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 12, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,205,204,204, 61, 5, 0, 0, 0,
+ 17, 0, 0, 0,114, 1, 0, 0,116, 1, 0, 0, 5, 0, 0, 0, 17, 0, 0, 0, 2, 0, 0, 0,116, 1, 0, 0, 68, 65, 84, 65,
+164, 0, 0, 0,224, 18,196, 8, 99, 0, 0, 0, 1, 0, 0, 0,176, 19,196, 8, 56, 18,196, 8, 13, 0, 0, 0, 51, 51, 51, 63,
+ 1, 86,160, 92, 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,128, 63,
+ 0, 0,122, 68, 0, 0, 0, 0, 0, 0,122, 68, 0, 0,160,192, 0, 0,130, 66, 0, 0, 0, 0, 0, 0,182, 67,108, 1, 0, 0,
+124, 1, 0, 0, 0, 0, 0, 0,124, 1, 0, 0,196, 0, 0, 0,108, 1, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0,196, 0, 0, 0,
+108, 1, 0, 0, 16, 0, 0, 0,124, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,122, 68, 0, 0,122, 68,205,204,204, 61,
+ 0, 0, 72, 66, 10, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,176, 0, 0, 0,176, 19,196, 8,
+177, 0, 0, 0, 1, 0, 0, 0,144, 20,196, 8,224, 18,196, 8, 12, 0, 0, 0, 51, 51, 51, 63, 1, 86,160, 92, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,191, 0, 0, 2, 66, 0, 0,128,193, 0, 0,247, 67, 0, 0, 0,191,
+ 0, 0, 2, 66, 0, 0,128,193, 0, 0,247, 67,108, 1, 0, 0,124, 1, 0, 0, 0, 0, 0, 0, 14, 2, 0, 0,128, 0, 0, 0,
+108, 1, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0,128, 0, 0, 0,108, 1, 0, 0, 16, 0, 0, 0, 14, 2, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,250, 70, 0, 0,122, 68, 10,215, 35, 60, 0, 0, 72, 66, 10, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,180, 2, 0, 0,
+144, 20,196, 8, 89, 0, 0, 0, 1, 0, 0, 0,112, 23,196, 8,176, 19,196, 8, 1, 0, 0, 0, 51, 51, 51, 63, 1, 86,160, 92,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32,193, 0, 0,128, 63, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 65, 0, 0,128, 63, 1,184,157, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,140, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 1,128,191, 0, 0,128,191,
+ 0, 0, 0, 0, 0, 0, 0, 0,184,175, 31, 65, 0, 0, 32, 65, 33,195, 79, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,161, 14,106, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29,254,249,195,125,254, 71,194,
+ 0, 0, 0, 0, 0, 0, 0, 0,173,128,249, 67,138, 0, 72, 66, 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, 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, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 32, 65, 1, 0, 7, 0, 40, 9,197, 8, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
+ 1, 0, 3, 0, 0, 0, 0, 24, 0, 0, 12, 66, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 10,215, 35, 60, 0, 0,250, 67,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 7, 0, 0, 0,
+ 0, 0, 0, 0, 1, 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, 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, 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,
+ 68, 65, 84, 65, 84, 1, 0, 0,112, 23,196, 8, 96, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,144, 20,196, 8, 5, 0, 0, 0,
+ 51, 51, 51, 63, 1, 86,160, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 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, 47, 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, 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, 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, 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, 8, 0, 0, 0, 0, 0, 0, 0, 57, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255,255,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,204, 0, 0, 0,240, 24,196, 8,113, 0, 0, 0, 1, 0, 0, 0,152, 31,196, 8,
+ 88, 13,196, 8,168,240,195, 8, 40,240,195, 8,104,238,195, 8,232,239,195, 8, 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, 0, 0, 0, 0, 0,205, 0, 0, 0,232, 3, 0, 0,
+189, 0, 0, 0,247, 0, 0, 0,205, 0, 0, 0,232, 3, 0, 0,189, 0, 0, 0,215, 0, 0, 0,205, 0, 0, 0,232, 3, 0, 0,
+216, 0, 0, 0,247, 0, 0, 0, 0, 0, 0, 0, 1, 0, 15, 15, 28, 3, 32, 0, 3, 0, 3, 0,192, 2, 0, 0, 7, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,136, 27,196, 8, 24, 30,196, 8, 0, 0, 0, 0, 0, 0, 0, 0,
+232, 25,196, 8,184, 26,196, 8, 68, 65, 84, 65,164, 0, 0, 0,232, 25,196, 8,112, 0, 0, 0, 1, 0, 0, 0,184, 26,196, 8,
+ 0, 0, 0, 0, 76,105,110,107, 32, 97,110,100, 32, 77, 97,116,101,114,105, 97,108,115, 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, 69,100,105,116,105,110,103, 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, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65,164, 0, 0, 0,184, 26,196, 8,112, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,232, 25,196, 8, 77,101,115,104,
+ 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, 69,100,105,116,
+105,110,103, 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, 70, 1, 0, 0,
+ 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,148, 0, 0, 0,
+136, 27,196, 8,102, 0, 0, 0, 1, 0, 0, 0, 72, 28,196, 8, 0, 0, 0, 0, 15, 0, 0, 0, 51, 51, 51, 63, 1, 86,170, 76,
+ 0, 0,128,192, 0, 0,122, 67, 0, 0, 0, 0, 0, 0, 16, 66,123, 10, 4,194,181,186,152, 67, 0, 0, 0, 0, 0, 0, 16, 66,
+ 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, 28, 3, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0,128, 63, 0, 0, 16, 66, 0, 0,250, 70, 0, 0, 16, 66,
+205,204,204, 61, 0, 0, 32, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0,
+ 68, 65, 84, 65,160, 0, 0, 0, 72, 28,196, 8,166, 0, 0, 0, 1, 0, 0, 0, 24, 29,196, 8,136, 27,196, 8, 11, 0, 0, 0,
+ 51, 51, 51, 63, 1, 86,170, 76, 0, 0,128,192, 0, 0,122, 67, 0, 0,128,192, 0, 0,127, 67, 0, 0,128,192, 0, 0, 72, 66,
+ 0, 0,128,192, 0, 0,127, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,233, 3, 0, 0,
+ 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0,233, 3, 0, 0, 16, 0, 0, 0, 36, 0, 0, 0, 0, 0,128, 63, 0,128,129, 67,
+ 0, 0,250, 70, 0,128,129, 67,205,204,204, 61, 0, 0, 32, 65, 8, 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, 68, 65, 84, 65,212, 0, 0, 0, 24, 29,196, 8,
+ 94, 0, 0, 0, 1, 0, 0, 0, 24, 30,196, 8, 72, 28,196, 8, 4, 0, 0, 0, 51, 51, 51, 63, 1, 86,170, 76, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,193, 0, 0, 35, 68, 0, 0, 0,193,
+ 0, 0,104, 67,135, 22, 0,193,178, 16, 96, 68,112, 74,103, 67, 0, 0,104, 67, 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,128, 67, 0, 0, 40, 66, 0, 0,200, 68, 0, 0,225, 67, 0, 0, 0, 63,225,122,180, 63, 0, 0, 1, 0,
+ 1, 0, 1, 0,251, 4, 1, 0, 0, 0, 0, 0, 4, 0, 1, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,150, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+ 84, 1, 0, 0, 24, 30,196, 8, 96, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 24, 29,196, 8, 5, 0, 0, 0, 51, 51, 51, 63,
+ 1, 86,170, 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 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, 47, 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, 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, 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, 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, 8, 0, 0, 0, 0, 0, 0, 0, 57, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255,255, 0, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65,204, 0, 0, 0,152, 31,196, 8,113, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,240, 24,196, 8,
+168,239,195, 8,168,238,195, 8,104,240,195, 8,168,240,195, 8, 0, 0, 0, 0,159,125, 11, 63, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,186,252,191, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 0, 0, 0,128,111, 18, 3,187,
+ 0, 0, 0,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0,203, 0, 0, 0,189, 0, 0, 0,
+ 5, 3, 0, 0, 0, 0, 0, 0,203, 0, 0, 0,189, 0, 0, 0,215, 0, 0, 0, 0, 0, 0, 0,203, 0, 0, 0,216, 0, 0, 0,
+ 5, 3, 0, 0, 0, 0, 0, 0, 1, 0, 3, 3,204, 0, 46, 2, 3, 0, 3, 0,145, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 34,196, 8,224, 38,196, 8, 0, 0, 0, 0, 0, 0, 0, 0,144, 32,196, 8,
+ 96, 33,196, 8, 68, 65, 84, 65,164, 0, 0, 0,144, 32,196, 8,112, 0, 0, 0, 1, 0, 0, 0, 96, 33,196, 8, 0, 0, 0, 0,
+ 84,114, 97,110,115,102,111,114,109, 32, 80,114,111,112,101,114,116,105,101,115, 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,
+ 86,105,101,119, 51,100, 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,
+140, 0,210, 0, 62, 1,204, 0, 0, 0, 0, 0,162, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+164, 0, 0, 0, 96, 33,196, 8,112, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,144, 32,196, 8, 51, 68, 32, 86,105,101,119,112,
+111,114,116, 32,112,114,111,112,101,114,116,105,101,115, 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, 86,105,101,119, 51,100, 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, 8, 0, 8, 0, 62, 1,204, 0,
+ 0, 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,196, 0, 0, 0, 48, 34,196, 8,
+ 97, 0, 0, 0, 1, 0, 0, 0, 0, 36,196, 8, 0, 0, 0, 0, 3, 0, 0, 0, 51, 51, 51, 63, 1, 89, 2, 28, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 67, 0, 0,190,194, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 60, 67, 0,128, 11,196, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 46, 2, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0,204, 0, 0, 0, 0, 0, 0, 0, 46, 2, 0, 0, 0, 0,192,194,
+ 0,128, 11,196, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0,128, 63, 1, 0, 1, 0, 1, 0, 1, 0,188, 0, 46, 2,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,142, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 32, 35,196, 8, 1, 0, 0, 0, 1, 0, 0, 0, 68, 65, 84, 65, 12, 0, 0, 0, 32, 35,196, 8,128, 0, 0, 0, 1, 0, 0, 0,
+ 10, 0, 0, 0, 10, 0, 0, 0, 88, 35,196, 8, 68, 65, 84, 65,120, 0, 0, 0, 88, 35,196, 8,127, 0, 0, 0, 10, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, 0,136,251,196, 8, 0, 0, 0, 0, 1, 0, 1, 0,160, 2,197, 8, 0, 0, 0, 0, 1, 0, 1, 0,
+ 72, 12,197, 8, 0, 0, 0, 0, 1, 0, 1, 0, 24, 22,197, 8, 0, 0, 0, 0, 1, 0, 1, 0,184, 18,197, 8, 0, 0, 0, 0,
+ 1, 0, 1, 0, 8, 21,197, 8, 0, 0, 0, 0, 1, 0, 1, 0,152, 15,197, 8, 0, 0, 0, 0, 1, 0, 1, 0,120, 1,197, 8,
+ 0, 0, 0, 0, 1, 0, 1, 0, 40, 9,197, 8, 0, 0, 0, 0, 1, 0, 1, 0,216, 0,197, 8, 68, 65, 84, 65,180, 2, 0, 0,
+ 0, 36,196, 8, 89, 0, 0, 0, 1, 0, 0, 0,224, 38,196, 8, 48, 34,196, 8, 1, 0, 0, 0, 51, 51, 51, 63, 1, 89, 2, 28,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63,159,125, 11, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,186,252,191, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,111, 18, 3,187, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63,102,233,234, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,148,173, 42, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255,255,249,195, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63,159,125, 11, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,186,252,191, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 0, 0, 0,128,111, 18, 3,187, 0, 0, 0,128,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+148,173, 42, 65, 0, 0, 7, 0, 40, 9,197, 8, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
+ 1, 0, 3, 0, 0, 0, 8, 24, 0, 0, 12, 66, 0, 0,128, 63, 0, 0,128, 63, 0, 0, 0, 0,205,204,204, 61, 0, 0,250, 67,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 1, 0, 7, 0,175, 0,
+ 0, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0, 0, 88,134, 55, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 88,134, 55, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 88,134, 55, 64, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65, 84, 1, 0, 0,224, 38,196, 8, 96, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 36,196, 8, 5, 0, 0, 0,
+ 51, 51, 51, 63, 1, 89, 2, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 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, 47, 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, 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, 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, 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, 8, 0, 0, 0, 0, 0, 0, 0, 57, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255,255,
+ 0, 0, 0, 0, 0, 0, 0, 0, 83, 82, 0, 0,116, 0, 0, 0, 96, 40,196, 8,109, 0, 0, 0, 1, 0, 0, 0,192, 99,196, 8,
+ 8,237,195, 8, 0, 0, 0, 0, 0, 0, 0, 0, 83, 82, 50, 45, 77,111,100,101,108, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 41,196, 8,192, 42,196, 8, 0, 43,196, 8,136, 45,196, 8,208, 45,196, 8,
+144, 86,196, 8,136,251,196, 8, 1, 0, 0, 5,254,255,253, 3, 0, 5, 0, 4, 1, 0, 2, 0, 0, 0, 0, 0, 1, 0, 8, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0, 0, 41,196, 8,110, 0, 0, 0,
+ 1, 0, 0, 0, 64, 41,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0,
+ 64, 41,196, 8,110, 0, 0, 0, 1, 0, 0, 0,128, 41,196, 8, 0, 41,196, 8, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0,
+ 68, 65, 84, 65, 20, 0, 0, 0,128, 41,196, 8,110, 0, 0, 0, 1, 0, 0, 0,192, 41,196, 8, 64, 41,196, 8, 0, 0, 0, 0,
+ 0, 5, 0, 4, 0, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0,192, 41,196, 8,110, 0, 0, 0, 1, 0, 0, 0, 0, 42,196, 8,
+128, 41,196, 8, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0, 0, 42,196, 8,110, 0, 0, 0,
+ 1, 0, 0, 0, 64, 42,196, 8,192, 41,196, 8, 0, 0, 0, 0, 0, 0,236, 0, 0, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0,
+ 64, 42,196, 8,110, 0, 0, 0, 1, 0, 0, 0,128, 42,196, 8, 0, 42,196, 8, 0, 0, 0, 0, 0, 5,236, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65, 20, 0, 0, 0,128, 42,196, 8,110, 0, 0, 0, 1, 0, 0, 0,192, 42,196, 8, 64, 42,196, 8, 0, 0, 0, 0,
+ 0, 0,224, 3, 0, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0,192, 42,196, 8,110, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+128, 42,196, 8, 0, 0, 0, 0, 0, 5,224, 3, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0, 0, 43,196, 8,111, 0, 0, 0,
+ 1, 0, 0, 0, 72, 43,196, 8, 0, 0, 0, 0, 64, 41,196, 8,128, 41,196, 8, 1, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+ 24, 0, 0, 0, 72, 43,196, 8,111, 0, 0, 0, 1, 0, 0, 0,144, 43,196, 8, 0, 43,196, 8, 0, 41,196, 8,192, 41,196, 8,
+ 1, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,144, 43,196, 8,111, 0, 0, 0, 1, 0, 0, 0,216, 43,196, 8,
+ 72, 43,196, 8, 0, 41,196, 8, 0, 42,196, 8, 1, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,216, 43,196, 8,
+111, 0, 0, 0, 1, 0, 0, 0, 32, 44,196, 8,144, 43,196, 8,192, 41,196, 8, 64, 42,196, 8, 1, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65, 24, 0, 0, 0, 32, 44,196, 8,111, 0, 0, 0, 1, 0, 0, 0,104, 44,196, 8,216, 43,196, 8, 0, 42,196, 8,
+ 64, 42,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,104, 44,196, 8,111, 0, 0, 0, 1, 0, 0, 0,
+176, 44,196, 8, 32, 44,196, 8, 64, 41,196, 8,128, 42,196, 8, 1, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,
+176, 44,196, 8,111, 0, 0, 0, 1, 0, 0, 0,248, 44,196, 8,104, 44,196, 8,128, 41,196, 8,192, 42,196, 8, 1, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,248, 44,196, 8,111, 0, 0, 0, 1, 0, 0, 0, 64, 45,196, 8,176, 44,196, 8,
+128, 42,196, 8,192, 42,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0, 64, 45,196, 8,111, 0, 0, 0,
+ 1, 0, 0, 0,136, 45,196, 8,248, 44,196, 8, 0, 42,196, 8,128, 42,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+ 24, 0, 0, 0,136, 45,196, 8,111, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 64, 45,196, 8, 64, 42,196, 8,192, 42,196, 8,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,204, 0, 0, 0,208, 45,196, 8,113, 0, 0, 0, 1, 0, 0, 0,152, 85,196, 8,
+ 0, 0, 0, 0, 0, 41,196, 8, 0, 42,196, 8, 64, 42,196, 8,192, 41,196, 8, 0, 0, 0, 0, 0, 0,140, 63, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,183, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 80, 1,128,191, 0, 0,128,191, 0, 0, 0, 0, 0, 0, 0, 0,226,215,163,188, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0,
+ 0, 0, 0, 0,235, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0,209, 0, 0, 0,235, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0,
+ 0, 0, 0, 0,208, 0, 0, 0, 5, 0, 4, 0, 2, 0, 4, 4, 1, 5,209, 0, 1, 1, 1, 0, 79, 1, 0, 0, 7, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 72, 79,196, 8, 24, 84,196, 8, 56,189,193, 8,112,188,195, 8,
+200, 46,196, 8,144,165,193, 8, 68, 65, 84, 65,164, 0, 0, 0,200, 46,196, 8,112, 0, 0, 0, 1, 0, 0, 0,152, 47,196, 8,
+ 0, 0, 0, 0, 80,114,101,118,105,101,119, 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, 76, 97,109,112, 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, 0, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65,164, 0, 0, 0,152, 47,196, 8,112, 0, 0, 0, 1, 0, 0, 0,104, 48,196, 8,200, 46,196, 8, 76, 97,109,112,
+ 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, 76, 97,109,112,
+ 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, 70, 1, 0, 0,
+ 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0,
+104, 48,196, 8,112, 0, 0, 0, 1, 0, 0, 0, 56, 49,196, 8,152, 47,196, 8, 83,112,111,116, 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, 76, 97,109,112, 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,140, 2, 0, 0, 62, 1,204, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0, 56, 49,196, 8,112, 0, 0, 0,
+ 1, 0, 0, 0, 8, 50,196, 8,104, 48,196, 8, 84,101,120,116,117,114,101, 32, 97,110,100, 32, 73,110,112,117,116, 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, 76, 97,109,112, 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,210, 3, 0, 0, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0, 8, 50,196, 8,112, 0, 0, 0, 1, 0, 0, 0,216, 50,196, 8,
+ 56, 49,196, 8, 77, 97,112, 32, 84,111, 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, 76, 97,109,112, 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,210, 3, 0, 0, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 49,196, 8,
+ 68, 65, 84, 65,164, 0, 0, 0,216, 50,196, 8,112, 0, 0, 0, 1, 0, 0, 0,168, 51,196, 8, 8, 50,196, 8, 80,114,101,118,
+105,101,119, 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, 77, 97,116,101,
+114,105, 97,108, 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,
+ 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0,
+168, 51,196, 8,112, 0, 0, 0, 1, 0, 0, 0,120, 52,196, 8,216, 50,196, 8, 77, 97,116,101,114,105, 97,108, 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, 77, 97,116,101,114,105, 97,108, 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, 70, 1, 0, 0, 62, 1,204, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0,120, 52,196, 8,112, 0, 0, 0,
+ 1, 0, 0, 0, 72, 53,196, 8,168, 51,196, 8, 80,114,101,118,105,101,119, 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, 87,111,114,108,100, 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, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0, 72, 53,196, 8,112, 0, 0, 0, 1, 0, 0, 0, 24, 54,196, 8,
+120, 52,196, 8, 87,111,114,108,100, 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, 87,111,114,108,100, 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, 70, 1, 0, 0, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65,164, 0, 0, 0, 24, 54,196, 8,112, 0, 0, 0, 1, 0, 0, 0,232, 54,196, 8, 72, 53,196, 8, 77,105,115,116,
+ 32, 83,116, 97,114,115, 32, 80,104,121,115,105, 99,115, 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, 87,111,114,108,
+100, 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,140, 2, 0, 0,
+ 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0,
+232, 54,196, 8,112, 0, 0, 0, 1, 0, 0, 0,184, 55,196, 8, 24, 54,196, 8, 84,101,120,116,117,114,101, 32, 97,110,100, 32,
+ 73,110,112,117,116, 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, 87,111,114,108,100, 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,210, 3, 0, 0, 62, 1,204, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0,184, 55,196, 8,112, 0, 0, 0,
+ 1, 0, 0, 0,136, 56,196, 8,232, 54,196, 8, 77, 97,112, 32, 84,111, 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, 87,111,114,108,100, 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,210, 3, 0, 0, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,232, 54,196, 8, 68, 65, 84, 65,164, 0, 0, 0,136, 56,196, 8,112, 0, 0, 0, 1, 0, 0, 0, 88, 57,196, 8,
+184, 55,196, 8, 79,117,116,112,117,116, 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, 82,101,110,100,101,114, 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, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65,164, 0, 0, 0, 88, 57,196, 8,112, 0, 0, 0, 1, 0, 0, 0, 40, 58,196, 8,136, 56,196, 8, 82,101,110,100,
+101,114, 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, 82,101,110,100,
+101,114, 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, 70, 1, 0, 0,
+ 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0,
+ 40, 58,196, 8,112, 0, 0, 0, 1, 0, 0, 0,248, 58,196, 8, 88, 57,196, 8, 65,110,105,109, 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, 82,101,110,100,101,114, 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,140, 2, 0, 0, 62, 1,204, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0,248, 58,196, 8,112, 0, 0, 0,
+ 1, 0, 0, 0,200, 59,196, 8, 40, 58,196, 8, 70,111,114,109, 97,116, 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, 82,101,110,100,101,114, 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,210, 3, 0, 0, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0,200, 59,196, 8,112, 0, 0, 0, 1, 0, 0, 0,152, 60,196, 8,
+248, 58,196, 8, 76,105,110,107, 32, 97,110,100, 32, 77, 97,116,101,114,105, 97,108,115, 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, 69,100,105,116,105,110,103, 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, 62, 1,204, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65,164, 0, 0, 0,152, 60,196, 8,112, 0, 0, 0, 1, 0, 0, 0,104, 61,196, 8,200, 59,196, 8, 77,101,115,104,
+ 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, 69,100,105,116,
+105,110,103, 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, 70, 1, 0, 0,
+ 62, 1,204, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0,
+104, 61,196, 8,112, 0, 0, 0, 1, 0, 0, 0, 56, 62,196, 8,152, 60,196, 8, 77,101,115,104, 32, 84,111,111,108,115, 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, 69,100,105,116,105,110,103, 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,140, 2, 0, 0, 62, 1,204, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0, 56, 62,196, 8,112, 0, 0, 0,
+ 1, 0, 0, 0, 8, 63,196, 8,104, 61,196, 8, 77,101,115,104, 32, 84,111,111,108,115, 32, 49, 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, 69,100,105,116,105,110,103, 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, 24, 5, 0, 0, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 2, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0, 8, 63,196, 8,112, 0, 0, 0, 1, 0, 0, 0,216, 63,196, 8,
+ 56, 62,196, 8, 67, 97,109,101,114, 97, 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, 69,100,105,116,105,110,103, 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, 70, 1, 0, 0, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65,164, 0, 0, 0,216, 63,196, 8,112, 0, 0, 0, 1, 0, 0, 0,168, 64,196, 8, 8, 63,196, 8, 83,104, 97,100,
+101,114,115, 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, 77, 97,116,101,
+114,105, 97,108, 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,140, 2, 0, 0,
+ 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 76,196, 8, 68, 65, 84, 65,164, 0, 0, 0,
+168, 64,196, 8,112, 0, 0, 0, 1, 0, 0, 0,120, 65,196, 8,216, 63,196, 8, 84,101,120,116,117,114,101, 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, 77, 97,116,101,114,105, 97,108, 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,210, 3, 0, 0, 62, 1,204, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0,120, 65,196, 8,112, 0, 0, 0,
+ 1, 0, 0, 0, 72, 66,196, 8,168, 64,196, 8, 65,110,105,109, 32,115,101,116,116,105,110,103,115, 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, 79, 98,106,101, 99,116, 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, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0, 72, 66,196, 8,112, 0, 0, 0, 1, 0, 0, 0, 24, 67,196, 8,
+120, 65,196, 8, 68,114, 97,119, 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, 79, 98,106,101, 99,116, 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, 70, 1, 0, 0, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65,164, 0, 0, 0, 24, 67,196, 8,112, 0, 0, 0, 1, 0, 0, 0,232, 67,196, 8, 72, 66,196, 8, 67,111,110,115,
+116,114, 97,105,110,116,115, 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, 79, 98,106,101,
+ 99,116, 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,140, 2, 0, 0,
+ 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0,
+232, 67,196, 8,112, 0, 0, 0, 1, 0, 0, 0,184, 68,196, 8, 24, 67,196, 8, 83, 99,114,105,112,116,108,105,110,107,115, 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, 83, 99,114,105,112,116, 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, 62, 1,204, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0,184, 68,196, 8,112, 0, 0, 0,
+ 1, 0, 0, 0,136, 69,196, 8,232, 67,196, 8, 69,102,102,101, 99,116,115, 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, 79, 98,106,101, 99,116, 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,140, 2, 0, 0,162, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 24, 67,196, 8, 68, 65, 84, 65,164, 0, 0, 0,136, 69,196, 8,112, 0, 0, 0, 1, 0, 0, 0, 88, 70,196, 8,
+184, 68,196, 8, 77, 97,112, 32, 73,110,112,117,116, 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, 77, 97,116,101,114,105, 97,108, 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,210, 3, 0, 0, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,168, 64,196, 8,
+ 68, 65, 84, 65,164, 0, 0, 0, 88, 70,196, 8,112, 0, 0, 0, 1, 0, 0, 0, 40, 71,196, 8,136, 69,196, 8, 77, 97,112, 32,
+ 84,111, 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, 77, 97,116,101,
+114,105, 97,108, 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,210, 3, 0, 0,
+ 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,168, 64,196, 8, 68, 65, 84, 65,164, 0, 0, 0,
+ 40, 71,196, 8,112, 0, 0, 0, 1, 0, 0, 0,248, 71,196, 8, 88, 70,196, 8, 65,110,105,109, 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, 65,110,105,109, 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, 0, 62, 1,204, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0,248, 71,196, 8,112, 0, 0, 0,
+ 1, 0, 0, 0,200, 72,196, 8, 40, 71,196, 8, 83,111,117,110,100, 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, 83,111,117,110,100, 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, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0,200, 72,196, 8,112, 0, 0, 0, 1, 0, 0, 0,152, 73,196, 8,
+248, 71,196, 8, 76,105,115,116,101,110,101,114, 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, 83,111,117,110,100, 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, 70, 1, 0, 0, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65,164, 0, 0, 0,152, 73,196, 8,112, 0, 0, 0, 1, 0, 0, 0,104, 74,196, 8,200, 72,196, 8, 83,101,113,117,
+101,110, 99,101,114, 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, 83,111,117,110,
+100, 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,140, 2, 0, 0,
+ 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0,
+104, 74,196, 8,112, 0, 0, 0, 1, 0, 0, 0, 56, 75,196, 8,152, 73,196, 8, 65,114,109, 97,116,117,114,101, 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, 69,100,105,116,105,110,103, 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, 70, 1, 0, 0, 62, 1,204, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0, 56, 75,196, 8,112, 0, 0, 0,
+ 1, 0, 0, 0, 8, 76,196, 8,104, 74,196, 8, 82, 97,109,112,115, 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, 77, 97,116,101,114,105, 97,108, 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, 70, 1, 0, 0, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,168, 51,196, 8, 68, 65, 84, 65,164, 0, 0, 0, 8, 76,196, 8,112, 0, 0, 0, 1, 0, 0, 0,216, 76,196, 8,
+ 56, 75,196, 8, 77,105,114,114,111,114, 32, 84,114, 97,110,115,112, 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, 77, 97,116,101,114,105, 97,108, 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,140, 2, 0, 0, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65,164, 0, 0, 0,216, 76,196, 8,112, 0, 0, 0, 1, 0, 0, 0,168, 77,196, 8, 8, 76,196, 8, 77,105,115,116,
+ 32, 47, 32, 83,116, 97,114,115, 32, 47, 32, 80,104,121,115,105, 99,115, 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, 87,111,114,108,
+100, 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,140, 2, 0, 0,
+ 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0,
+168, 77,196, 8,112, 0, 0, 0, 1, 0, 0, 0,120, 78,196, 8,216, 76,196, 8, 65,109, 98, 32, 79, 99, 99, 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, 87,111,114,108,100, 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,140, 2, 0, 0, 62, 1,204, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,216, 76,196, 8, 68, 65, 84, 65,164, 0, 0, 0,120, 78,196, 8,112, 0, 0, 0,
+ 1, 0, 0, 0, 8,158,193, 8,168, 77,196, 8, 83,104, 97,100,111,119, 32, 97,110,100, 32, 83,112,111,116, 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, 76, 97,109,112, 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,140, 2, 0, 0, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0, 8,158,193, 8,112, 0, 0, 0, 1, 0, 0, 0,144,165,193, 8,
+120, 78,196, 8, 77,111,100,105,102,105,101,114,115, 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, 69,100,105,116,105,110,103, 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,140, 2, 0, 0, 62, 1,204, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65,164, 0, 0, 0,144,165,193, 8,112, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 8,158,193, 8, 83,104, 97,112,
+101,115, 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, 69,100,105,116,
+105,110,103, 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,140, 2, 0, 0,
+ 62, 1,204, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 8,158,193, 8, 68, 65, 84, 65,212, 0, 0, 0,
+ 72, 79,196, 8, 94, 0, 0, 0, 1, 0, 0, 0, 72, 80,196, 8, 0, 0, 0, 0, 4, 0, 0, 0, 51, 51, 51, 63,208, 45,196, 8,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,193, 0,192,202, 68,
+ 0, 0, 0,193, 0, 0,104, 67, 0, 0, 0,193, 40,224,182, 68, 0, 0, 0,193, 0, 0,104, 67, 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,128, 67, 0, 0, 40, 66, 0, 0,200, 68, 0, 0,225, 67, 0, 0, 0, 63,225,122,180, 63,
+ 0, 0, 1, 0, 1, 0, 1, 0, 1, 5,209, 0, 0, 0, 0, 0, 4, 0, 1, 0, 0, 0, 4, 0, 24, 22,197, 8, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,141, 0, 0, 0, 0, 0,109, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65,180, 2, 0, 0, 72, 80,196, 8, 89, 0, 0, 0, 1, 0, 0, 0, 40, 83,196, 8, 72, 79,196, 8, 1, 0, 0, 0,
+ 51, 51, 51, 63,208, 45,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32,193, 0, 0,128, 63, 0, 0,128, 63, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 65, 0, 0,128, 63, 0, 0,140, 63, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,183, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 80, 1,128,191, 0, 0,128,191, 0, 0, 0, 0, 0, 0, 0, 0,184,175, 31, 65, 0, 0, 32, 65,161, 14,106, 63, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 99, 15, 51, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 29,254,249,195,125,254, 71,194, 0, 0, 0, 0, 0, 0, 0, 0,173,128,249, 67,138, 0, 72, 66, 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, 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, 0, 0, 0, 0,128, 63, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 65, 1, 0, 7, 0, 40, 9,197, 8, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 3, 0, 0, 0, 0, 24, 0, 0, 12, 66, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0,
+ 10,215, 35, 60, 0, 0,250, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 16, 0, 1, 0, 7, 0, 0, 0, 0, 0, 0, 0, 1, 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, 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, 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, 68, 65, 84, 65,196, 0, 0, 0, 40, 83,196, 8, 97, 0, 0, 0, 1, 0, 0, 0, 24, 84,196, 8,
+ 72, 80,196, 8, 3, 0, 0, 0, 51, 51, 51, 63,208, 45,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,192,192, 0, 0,160, 64, 0, 0, 0, 0,205,204,140, 65,201, 82, 5,194,124,171, 30, 66, 49,238,226, 64,140,108,168, 65,
+ 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, 1, 5, 0, 0, 0, 0, 0, 0,245, 0, 0, 0, 0, 0, 32, 65, 0, 0,128, 64, 0, 0,160, 67, 0, 0,160, 67,
+ 10,215, 35, 60, 0, 0, 0, 64, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,142, 3, 1, 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,
+ 68, 65, 84, 65, 84, 1, 0, 0, 24, 84,196, 8, 96, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 40, 83,196, 8, 5, 0, 0, 0,
+ 51, 51, 51, 63,208, 45,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 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, 47, 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, 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, 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, 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, 8, 0, 0, 0, 0, 0, 0, 0, 57, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255,255,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,204, 0, 0, 0,152, 85,196, 8,113, 0, 0, 0, 1, 0, 0, 0,144, 86,196, 8,
+208, 45,196, 8,128, 42,196, 8, 64, 41,196, 8,128, 41,196, 8,192, 42,196, 8, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0,
+225, 3, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0,225, 3, 0, 0,251, 3, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0,
+252, 3, 0, 0, 0, 4, 0, 0, 7, 0, 6, 0, 1, 0, 7, 7, 1, 5, 5, 0, 1, 1, 1, 1,196, 2, 0, 0, 7, 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, 32, 27,194, 8,176,231,195, 8,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,204, 0, 0, 0,144, 86,196, 8,113, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+152, 85,196, 8, 0, 42,196, 8,128, 42,196, 8,192, 42,196, 8, 64, 42,196, 8, 0, 0, 0, 0,184,119,162, 61, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,183,240, 14, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+111, 18,131,187, 0, 0, 0, 0, 0, 0, 0,128, 0, 0, 0,128, 0, 0, 0,128, 0, 0,128, 63, 0, 0, 0, 0, 0, 5, 0, 0,
+237, 0, 0, 0,223, 3, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0,237, 0, 0, 0, 7, 1, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0,
+ 8, 1, 0, 0,223, 3, 0, 0, 9, 0, 8, 0, 1, 0, 1, 1, 1, 5,216, 2, 1, 0, 1, 0, 5, 3, 0, 0, 7, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 89,196, 8, 64, 98,196, 8,104,176,195, 8,104,176,195, 8,
+136, 87,196, 8, 88, 88,196, 8, 68, 65, 84, 65,164, 0, 0, 0,136, 87,196, 8,112, 0, 0, 0, 1, 0, 0, 0, 88, 88,196, 8,
+ 0, 0, 0, 0, 84,114, 97,110,115,102,111,114,109, 32, 80,114,111,112,101,114,116,105,101,115, 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, 86,105,101,119, 51,100, 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, 44, 0, 21, 2, 62, 1,204, 0, 0, 0, 0, 0,162, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65,164, 0, 0, 0, 88, 88,196, 8,112, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,136, 87,196, 8, 86,105,101,119,
+ 32, 80,114,111,112,101,114,116,105,101,115, 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, 86,105,101,119,
+ 51,100, 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, 84, 1, 8, 0,
+ 62, 1,204, 0, 0, 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,180, 2, 0, 0,
+ 40, 89,196, 8, 89, 0, 0, 0, 1, 0, 0, 0, 8, 92,196, 8, 0, 0, 0, 0, 1, 0, 0, 0, 51, 51, 51, 63,144, 86,196, 8,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63,184,119,162, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,183,240, 14, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,111, 18,131,187, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63,123,176, 73, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 25, 62,229, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255,255,121,195, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63,184,119,162, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,183,240, 14, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,111, 18,131,187, 0, 0, 0, 0,
+ 0, 0, 0,128, 0, 0, 0,128, 0, 0, 0,128, 0, 0,128, 63, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+123,176, 73, 65, 0, 0, 7, 0, 40, 9,197, 8, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
+ 1, 0, 3, 0,251,255, 8, 8, 0, 0, 12, 66, 0, 0,128, 63, 0, 0,128, 63,189, 57,161, 60,205,204,204, 61, 0, 0,250, 67,
+ 0, 0, 0,128, 0, 0, 0,128, 0, 0, 0,128,193, 55,143, 63, 0,174,255,192, 88, 23,141,191, 60, 0, 1, 0, 7, 0,175, 0,
+ 0, 0, 0, 0, 1, 0, 0, 0, 3, 0,255,255,170,239,188, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+170,239,188, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,170,239,188, 63, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65, 40, 1, 0, 0, 8, 92,196, 8, 93, 0, 0, 0, 1, 0, 0, 0, 96, 93,196, 8, 40, 89,196, 8, 2, 0, 0, 0,
+ 51, 51, 51, 63,144, 86,196, 8, 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,122, 67,205,204,204,189,205,204,140, 63, 0, 0, 0, 0, 0, 0,122, 67, 0, 0,160,192, 0, 0,160, 64,
+ 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 50, 2, 0, 0, 16, 0, 0, 0,168, 3, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0,
+ 16, 0, 0, 0,168, 3, 0, 0, 16, 0, 0, 0, 50, 2, 0, 0, 10,215, 35, 60, 10,215, 35, 60, 0, 96,106, 70, 0, 0,122, 68,
+ 0, 0, 0, 0, 0, 0, 0, 0, 9, 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, 72, 12,197, 8, 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, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 79, 66, 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,122, 67,205,204,204,189,205,204,140, 63, 68, 65, 84, 65,
+196, 0, 0, 0, 96, 93,196, 8, 97, 0, 0, 0, 1, 0, 0, 0, 96, 96,196, 8, 8, 92,196, 8, 3, 0, 0, 0, 51, 51, 51, 63,
+144, 86,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,246, 24,167, 65,102,102,174,193,
+122, 20,238, 65, 75, 95,116,194, 75, 95,116, 66, 51, 51, 9,194, 51, 51, 9, 66, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0,
+ 50, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,233, 3, 0, 0, 0, 0, 0, 0,
+ 50, 2, 0, 0, 0, 0, 32, 65, 0, 0,128, 64, 0, 0,160, 67, 0, 0,160, 67, 10,215, 35, 60, 0, 0, 0, 64, 0, 0, 0, 0,
+ 1, 0, 0, 0,233, 3, 50, 2, 0, 0, 0, 0, 80, 94,196, 8, 8, 96,196, 8, 0, 0,143, 3, 1, 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, 68, 65, 84, 65, 44, 0, 0, 0, 80, 94,196, 8,
+129, 0, 0, 0, 1, 0, 0, 0,168, 94,196, 8, 0, 0, 0, 0, 66, 79, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0,113, 61, 10,192,
+ 0, 0, 0, 0, 0, 0, 0, 0, 72, 12,197, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 44, 0, 0, 0,168, 94,196, 8,
+129, 0, 0, 0, 1, 0, 0, 0, 0, 95,196, 8, 80, 94,196, 8, 69, 77, 4, 0, 0, 0, 0, 0, 0, 0,192, 64,205,204,124, 65,
+ 0, 0, 0, 0, 0, 0, 0, 0, 24, 22,197, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 44, 0, 0, 0, 0, 95,196, 8,
+129, 0, 0, 0, 1, 0, 0, 0, 88, 95,196, 8,168, 94,196, 8, 65, 77, 5, 0, 0, 0, 0, 0,235, 49,126, 65, 98, 62,200, 65,
+ 0, 0, 0, 0, 0, 0, 0, 0,184, 18,197, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 44, 0, 0, 0, 88, 95,196, 8,
+129, 0, 0, 0, 1, 0, 0, 0,176, 95,196, 8, 0, 95,196, 8, 66, 79, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 65,
+ 0, 0, 0, 0, 0, 0, 0, 0,152, 15,197, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 44, 0, 0, 0,176, 95,196, 8,
+129, 0, 0, 0, 1, 0, 0, 0, 8, 96,196, 8, 88, 95,196, 8, 66, 79, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0,164,112, 61, 65,
+ 0, 0, 0, 0, 0, 0, 0, 0, 40, 9,197, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 44, 0, 0, 0, 8, 96,196, 8,
+129, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,176, 95,196, 8, 67, 83, 0, 0, 0, 0, 0, 0, 0, 0,192, 64,102,102,174,193,
+ 0, 0, 0, 0, 0, 0, 0, 0,136,251,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,176, 0, 0, 0, 96, 96,196, 8,
+177, 0, 0, 0, 1, 0, 0, 0, 64, 97,196, 8, 96, 93,196, 8, 12, 0, 0, 0, 51, 51, 51, 63,144, 86,196, 8, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0,122, 68, 0, 0, 0, 0, 0, 0,122, 68, 0, 0,160,192,
+ 0, 0,130, 66, 0, 0, 0, 0, 0,128, 8, 68,217, 3, 0, 0,233, 3, 0, 0, 0, 0, 0, 0, 50, 2, 0, 0,128, 0, 0, 0,
+217, 3, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0,128, 0, 0, 0,217, 3, 0, 0, 16, 0, 0, 0, 50, 2, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,250, 70, 0, 0,122, 68, 10,215, 35, 60, 0, 0, 72, 66, 10, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255,255, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,212, 0, 0, 0,
+ 64, 97,196, 8, 94, 0, 0, 0, 1, 0, 0, 0, 64, 98,196, 8, 96, 96,196, 8, 4, 0, 0, 0, 51, 51, 51, 63,144, 86,196, 8,
+ 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,224,159, 68,
+ 0, 0,160,193, 0, 0,100, 67,246, 56,165, 67, 26, 29,110, 68, 13,102,183,193,246, 25,161, 67, 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,128, 67, 0, 0, 40, 66, 0, 0,200, 68, 0, 0,225, 67, 0, 0, 0, 63,225,122,180, 63,
+ 0, 0, 1, 0, 1, 0, 1, 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,150, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65, 84, 1, 0, 0, 64, 98,196, 8, 96, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 64, 97,196, 8, 5, 0, 0, 0,
+ 51, 51, 51, 63,144, 86,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 76, 0, 0, 0,
+ 83, 97,118,101, 32, 70,105,108,101, 0, 78, 84, 0, 32, 80, 73, 67, 84, 85, 82, 69, 83, 0, 0, 47, 85,115,101,114,115, 47,116,
+111,110, 47, 68,101,115,107,116,111,112, 47, 0,117,109,112, 98,117,103, 32, 70,111,108,100,101,114, 47, 0,101,110,100,101,114,
+ 46, 97,112,112, 47, 67,111,110,116,101,110,116,115, 47, 82,101,115,111,117,114, 99,101,115, 47, 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, 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,117,110,116,105,116,108,101,100,
+ 46, 98,108,101,110,100, 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, 0, 0, 0, 8, 0, 11, 0, 1, 0, 0, 0,251, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0,255,255,
+ 0, 0, 0, 0, 0, 0, 0, 0, 83, 82, 0, 0,116, 0, 0, 0,192, 99,196, 8,109, 0, 0, 0, 1, 0, 0, 0,232,163,196, 8,
+ 96, 40,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 83, 82, 51, 45, 77, 97,116,101,114,105, 97,108, 0,111,100,101,108, 32, 83,105,
+110,103, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 96,100,196, 8,160,103,196, 8,224,103,196, 8, 16,110,196, 8, 88,110,196, 8,
+ 56,156,196, 8,136,251,196, 8, 0, 0,231, 3,143, 1,174, 4,232, 3, 32, 3, 1, 0, 3, 0, 0, 0, 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0, 96,100,196, 8,110, 0, 0, 0,
+ 1, 0, 0, 0,160,100,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0,
+160,100,196, 8,110, 0, 0, 0, 1, 0, 0, 0,224,100,196, 8, 96,100,196, 8, 0, 0, 0, 0, 0, 0, 32, 3, 0, 0, 0, 0,
+ 68, 65, 84, 65, 20, 0, 0, 0,224,100,196, 8,110, 0, 0, 0, 1, 0, 0, 0, 32,101,196, 8,160,100,196, 8, 0, 0, 0, 0,
+232, 3, 32, 3, 0, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0, 32,101,196, 8,110, 0, 0, 0, 1, 0, 0, 0, 96,101,196, 8,
+224,100,196, 8, 0, 0, 0, 0,232, 3, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0, 96,101,196, 8,110, 0, 0, 0,
+ 1, 0, 0, 0,160,101,196, 8, 32,101,196, 8, 0, 0, 0, 0, 0, 0, 60, 0, 0, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0,
+160,101,196, 8,110, 0, 0, 0, 1, 0, 0, 0,224,101,196, 8, 96,101,196, 8, 0, 0, 0, 0,232, 3, 60, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65, 20, 0, 0, 0,224,101,196, 8,110, 0, 0, 0, 1, 0, 0, 0, 32,102,196, 8,160,101,196, 8, 0, 0, 0, 0,
+ 0, 0, 6, 3, 0, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0, 32,102,196, 8,110, 0, 0, 0, 1, 0, 0, 0, 96,102,196, 8,
+224,101,196, 8, 0, 0, 0, 0,232, 3, 6, 3, 0, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0, 96,102,196, 8,110, 0, 0, 0,
+ 1, 0, 0, 0,160,102,196, 8, 32,102,196, 8, 0, 0, 0, 0, 44, 3, 60, 0, 0, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0,
+160,102,196, 8,110, 0, 0, 0, 1, 0, 0, 0,224,102,196, 8, 96,102,196, 8, 0, 0, 0, 0, 44, 3, 6, 3, 0, 0, 0, 0,
+ 68, 65, 84, 65, 20, 0, 0, 0,224,102,196, 8,110, 0, 0, 0, 1, 0, 0, 0, 32,103,196, 8,160,102,196, 8, 0, 0, 0, 0,
+ 0, 0,176, 1, 0, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0, 32,103,196, 8,110, 0, 0, 0, 1, 0, 0, 0, 96,103,196, 8,
+224,102,196, 8, 0, 0, 0, 0, 44, 3,176, 1, 0, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0, 96,103,196, 8,110, 0, 0, 0,
+ 1, 0, 0, 0,160,103,196, 8, 32,103,196, 8, 0, 0, 0, 0,164, 1,176, 1, 0, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0,
+160,103,196, 8,110, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 96,103,196, 8, 0, 0, 0, 0,164, 1, 6, 3, 0, 0, 0, 0,
+ 68, 65, 84, 65, 24, 0, 0, 0,224,103,196, 8,111, 0, 0, 0, 1, 0, 0, 0, 40,104,196, 8, 0, 0, 0, 0,160,100,196, 8,
+224,100,196, 8, 1, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0, 40,104,196, 8,111, 0, 0, 0, 1, 0, 0, 0,
+112,104,196, 8,224,103,196, 8, 96,100,196, 8, 32,101,196, 8, 1, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,
+112,104,196, 8,111, 0, 0, 0, 1, 0, 0, 0,184,104,196, 8, 40,104,196, 8, 96,100,196, 8, 96,101,196, 8, 1, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,184,104,196, 8,111, 0, 0, 0, 1, 0, 0, 0, 0,105,196, 8,112,104,196, 8,
+ 32,101,196, 8,160,101,196, 8, 1, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0, 0,105,196, 8,111, 0, 0, 0,
+ 1, 0, 0, 0, 72,105,196, 8,184,104,196, 8, 96,101,196, 8,160,101,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+ 24, 0, 0, 0, 72,105,196, 8,111, 0, 0, 0, 1, 0, 0, 0,144,105,196, 8, 0,105,196, 8,160,100,196, 8,224,101,196, 8,
+ 1, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,144,105,196, 8,111, 0, 0, 0, 1, 0, 0, 0,216,105,196, 8,
+ 72,105,196, 8,224,100,196, 8, 32,102,196, 8, 1, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,216,105,196, 8,
+111, 0, 0, 0, 1, 0, 0, 0, 32,106,196, 8,144,105,196, 8,224,101,196, 8, 32,102,196, 8, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65, 24, 0, 0, 0, 32,106,196, 8,111, 0, 0, 0, 1, 0, 0, 0,104,106,196, 8,216,105,196, 8,160,101,196, 8,
+ 32,102,196, 8, 1, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,104,106,196, 8,111, 0, 0, 0, 1, 0, 0, 0,
+176,106,196, 8, 32,106,196, 8, 96,101,196, 8, 96,102,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,
+176,106,196, 8,111, 0, 0, 0, 1, 0, 0, 0,248,106,196, 8,104,106,196, 8,160,101,196, 8, 96,102,196, 8, 0, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,248,106,196, 8,111, 0, 0, 0, 1, 0, 0, 0, 64,107,196, 8,176,106,196, 8,
+ 32,102,196, 8,160,102,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0, 64,107,196, 8,111, 0, 0, 0,
+ 1, 0, 0, 0,136,107,196, 8,248,106,196, 8, 96,102,196, 8,160,102,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+ 24, 0, 0, 0,136,107,196, 8,111, 0, 0, 0, 1, 0, 0, 0,208,107,196, 8, 64,107,196, 8, 96,101,196, 8,224,102,196, 8,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,208,107,196, 8,111, 0, 0, 0, 1, 0, 0, 0, 24,108,196, 8,
+136,107,196, 8,224,101,196, 8,224,102,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0, 24,108,196, 8,
+111, 0, 0, 0, 1, 0, 0, 0, 96,108,196, 8,208,107,196, 8,160,102,196, 8, 32,103,196, 8, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65, 24, 0, 0, 0, 96,108,196, 8,111, 0, 0, 0, 1, 0, 0, 0,168,108,196, 8, 24,108,196, 8, 96,102,196, 8,
+ 32,103,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,168,108,196, 8,111, 0, 0, 0, 1, 0, 0, 0,
+240,108,196, 8, 96,108,196, 8,224,102,196, 8, 32,103,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,
+240,108,196, 8,111, 0, 0, 0, 1, 0, 0, 0, 56,109,196, 8,168,108,196, 8,224,102,196, 8, 96,103,196, 8, 0, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0, 56,109,196, 8,111, 0, 0, 0, 1, 0, 0, 0,128,109,196, 8,240,108,196, 8,
+ 32,103,196, 8, 96,103,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,128,109,196, 8,111, 0, 0, 0,
+ 1, 0, 0, 0,200,109,196, 8, 56,109,196, 8,224,101,196, 8,160,103,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+ 24, 0, 0, 0,200,109,196, 8,111, 0, 0, 0, 1, 0, 0, 0, 16,110,196, 8,128,109,196, 8,160,102,196, 8,160,103,196, 8,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0, 16,110,196, 8,111, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+200,109,196, 8, 96,103,196, 8,160,103,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,204, 0, 0, 0, 88,110,196, 8,
+113, 0, 0, 0, 1, 0, 0, 0,112,122,196, 8, 0, 0, 0, 0, 96,100,196, 8, 96,101,196, 8,160,101,196, 8, 32,101,196, 8,
+ 0, 0, 0, 0, 0, 0,140, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,183, 64, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 1,128,191, 0, 0,128,191, 0, 0, 0, 0, 0, 0, 0, 0,226,215,163,188,
+ 0, 0, 0, 0, 0, 0, 0, 0,232, 3, 0, 0, 0, 0, 0, 0, 59, 0, 0, 0, 0, 0, 0, 0,232, 3, 0, 0, 0, 0, 0, 0,
+ 26, 0, 0, 0, 0, 0, 0, 0,232, 3, 0, 0, 27, 0, 0, 0, 59, 0, 0, 0, 0, 0, 0, 0, 1, 0, 15, 15,233, 3, 33, 0,
+ 1, 1, 1, 0,192, 2, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,144,114,196, 8,
+240,120,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 80,111,196, 8,192,113,196, 8, 68, 65, 84, 65,164, 0, 0, 0, 80,111,196, 8,
+112, 0, 0, 0, 1, 0, 0, 0, 32,112,196, 8, 0, 0, 0, 0, 79,117,116,112,117,116, 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, 82,101,110,100,101,114, 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, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0, 32,112,196, 8,112, 0, 0, 0, 1, 0, 0, 0,
+240,112,196, 8, 80,111,196, 8, 82,101,110,100,101,114, 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, 82,101,110,100,101,114, 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, 70, 1, 0, 0, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0,240,112,196, 8,112, 0, 0, 0, 1, 0, 0, 0,192,113,196, 8, 32,112,196, 8,
+ 65,110,105,109, 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,
+ 82,101,110,100,101,114, 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,
+140, 2, 0, 0, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+164, 0, 0, 0,192,113,196, 8,112, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,240,112,196, 8, 70,111,114,109, 97,116, 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, 82,101,110,100,101,114, 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,210, 3, 0, 0, 62, 1,204, 0,
+ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,148, 0, 0, 0,144,114,196, 8,
+102, 0, 0, 0, 1, 0, 0, 0, 80,115,196, 8, 0, 0, 0, 0, 15, 0, 0, 0, 51, 51, 51, 63, 1, 86,239, 92, 0, 0,128,192,
+ 0, 0,126, 67, 0, 0, 0, 0, 0, 0, 16, 65, 0, 0,128,192, 0, 0,126, 67, 0, 0, 0, 0, 0, 0, 16, 65, 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,
+233, 3, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 0,128, 63, 0, 0, 16, 65, 0, 0,250, 70, 0, 0, 16, 65,205,204,204, 61,
+ 0, 0, 32, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 6, 0, 0, 0, 68, 65, 84, 65,
+160, 0, 0, 0, 80,115,196, 8,166, 0, 0, 0, 1, 0, 0, 0, 32,116,196, 8,144,114,196, 8, 11, 0, 0, 0, 51, 51, 51, 63,
+ 1, 86,239, 92, 0, 0,128,192, 0, 0,122, 67, 0, 0,128,192, 0, 0,127, 67, 0, 0,128,192, 0, 0, 72, 66, 0, 0,128,192,
+ 0, 0,127, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,233, 3, 0, 0, 0, 0, 0, 0,
+ 16, 0, 0, 0, 0, 0, 0, 0,233, 3, 0, 0, 16, 0, 0, 0, 9, 0, 0, 0, 0, 0,128, 63, 0,128,129, 67, 0, 0,250, 70,
+ 0,128,129, 67,205,204,204, 61, 0, 0, 32, 65, 8, 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, 68, 65, 84, 65,212, 0, 0, 0, 32,116,196, 8, 94, 0, 0, 0,
+ 1, 0, 0, 0, 32,117,196, 8, 80,115,196, 8, 4, 0, 0, 0, 51, 51, 51, 63, 1, 86,239, 92, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,193, 0, 0,163, 68, 0, 0, 0,193, 0, 0,104, 67,
+ 63, 0, 0,193,172, 3,182, 68, 0, 0, 0,193, 0, 0,104, 67, 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,128, 67, 0, 0, 40, 66, 0, 0,200, 68, 0, 0,225, 67, 0, 0, 0, 63,225,122,180, 63, 0, 0, 1, 0, 1, 0, 1, 0,
+251, 4,209, 0, 0, 0, 0, 0, 0, 0,255,255, 0, 0, 0, 0, 0, 0, 0, 0,255,255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,109, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,180, 2, 0, 0,
+ 32,117,196, 8, 89, 0, 0, 0, 1, 0, 0, 0, 0,120,196, 8, 32,116,196, 8, 1, 0, 0, 0, 51, 51, 51, 63, 1, 86,239, 92,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32,193, 0, 0,128, 63, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 65, 0, 0,128, 63, 0, 0,140, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,183, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 1,128,191, 0, 0,128,191,
+ 0, 0, 0, 0, 0, 0, 0, 0,184,175, 31, 65, 0, 0, 32, 65,161, 14,106, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 99, 15, 51, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29,254,249,195,125,254, 71,194,
+ 0, 0, 0, 0, 0, 0, 0, 0,173,128,249, 67,138, 0, 72, 66, 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, 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, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 32, 65, 1, 0, 7, 0, 40, 9,197, 8, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
+ 1, 0, 3, 0, 0, 0, 0, 24, 0, 0, 12, 66, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 10,215, 35, 60, 0, 0,250, 67,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 1, 0, 7, 0, 0, 0,
+ 0, 0, 0, 0, 1, 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, 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, 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,
+ 68, 65, 84, 65,196, 0, 0, 0, 0,120,196, 8, 97, 0, 0, 0, 1, 0, 0, 0,240,120,196, 8, 32,117,196, 8, 3, 0, 0, 0,
+ 51, 51, 51, 63, 1, 86,239, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,192,192, 0, 0,160, 64,
+ 0, 0, 0, 0,205,204,140, 65,201, 82, 5,194,124,171, 30, 66, 49,238,226, 64,140,108,168, 65, 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, 1, 5, 0, 0,
+ 0, 0, 0, 0,245, 0, 0, 0, 0, 0, 32, 65, 0, 0,128, 64, 0, 0,160, 67, 0, 0,160, 67, 10,215, 35, 60, 0, 0, 0, 64,
+ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,142, 3, 1, 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, 68, 65, 84, 65, 84, 1, 0, 0,
+240,120,196, 8, 96, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,120,196, 8, 5, 0, 0, 0, 51, 51, 51, 63, 1, 86,239, 92,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 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, 47, 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, 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, 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, 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,
+ 8, 0, 0, 0, 0, 0, 0, 0, 57, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255,255, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65,204, 0, 0, 0,112,122,196, 8,113, 0, 0, 0, 1, 0, 0, 0,104,123,196, 8, 88,110,196, 8,224,101,196, 8,
+160,100,196, 8,224,100,196, 8, 32,102,196, 8, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0,232, 3, 0, 0, 7, 3, 0, 0, 32, 3, 0, 0,
+ 0, 0, 0, 0,232, 3, 0, 0, 7, 3, 0, 0, 33, 3, 0, 0, 0, 0, 0, 0,232, 3, 0, 0, 32, 3, 0, 0, 32, 3, 0, 0,
+ 0, 0, 0, 0, 1, 0, 7, 7,233, 3, 1, 0, 1, 1, 1, 1,196, 2, 0, 0, 7, 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,
+ 68, 65, 84, 65,204, 0, 0, 0,104,123,196, 8,113, 0, 0, 0, 1, 0, 0, 0,216,140,196, 8,112,122,196, 8, 96,102,196, 8,
+160,102,196, 8, 32,102,196, 8,160,101,196, 8, 0, 0, 0, 0,255,255, 71, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,255,255,139, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 13,128,191, 0, 0,128,191,
+ 0, 0, 0,128, 0, 0, 0,128, 74,215, 76,190, 0, 0, 0,128, 45, 3, 0, 0,232, 3, 0, 0, 61, 0, 0, 0, 5, 3, 0, 0,
+ 45, 3, 0, 0,232, 3, 0, 0, 61, 0, 0, 0, 87, 0, 0, 0, 45, 3, 0, 0,232, 3, 0, 0, 88, 0, 0, 0, 5, 3, 0, 0,
+ 0, 0, 0, 0, 1, 0, 4, 4,188, 0,174, 2, 1, 1, 1, 0,179, 1,126, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 32,134,196, 8, 88,139,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 96,124,196, 8, 80,133,196, 8,
+ 68, 65, 84, 65,164, 0, 0, 0, 96,124,196, 8,112, 0, 0, 0, 1, 0, 0, 0, 48,125,196, 8, 0, 0, 0, 0, 79,117,116,112,
+117,116, 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, 82,101,110,100,
+101,114, 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,
+ 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0,
+ 48,125,196, 8,112, 0, 0, 0, 1, 0, 0, 0, 0,126,196, 8, 96,124,196, 8, 82,101,110,100,101,114, 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, 82,101,110,100,101,114, 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, 24,255, 62, 1,204, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0, 0,126,196, 8,112, 0, 0, 0,
+ 1, 0, 0, 0,208,126,196, 8, 48,125,196, 8, 65,110,105,109, 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, 82,101,110,100,101,114, 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, 48,254, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0,208,126,196, 8,112, 0, 0, 0, 1, 0, 0, 0,160,127,196, 8,
+ 0,126,196, 8, 70,111,114,109, 97,116, 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, 82,101,110,100,101,114, 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, 72,253, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65,164, 0, 0, 0,160,127,196, 8,112, 0, 0, 0, 1, 0, 0, 0,112,128,196, 8,208,126,196, 8, 80,114,101,118,
+105,101,119, 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, 77, 97,116,101,
+114,105, 97,108, 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,
+ 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0,
+112,128,196, 8,112, 0, 0, 0, 1, 0, 0, 0, 64,129,196, 8,160,127,196, 8, 77, 97,116,101,114,105, 97,108, 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, 77, 97,116,101,114,105, 97,108, 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, 24,255, 62, 1,204, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0, 64,129,196, 8,112, 0, 0, 0,
+ 1, 0, 0, 0, 16,130,196, 8,112,128,196, 8, 83,104, 97,100,101,114,115, 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, 77, 97,116,101,114,105, 97,108, 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, 48,254, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0, 16,130,196, 8,112, 0, 0, 0, 1, 0, 0, 0,224,130,196, 8,
+ 64,129,196, 8, 84,101,120,116,117,114,101, 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, 77, 97,116,101,114,105, 97,108, 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, 68,252, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65,164, 0, 0, 0,224,130,196, 8,112, 0, 0, 0, 1, 0, 0, 0,176,131,196, 8, 16,130,196, 8, 77, 97,112, 32,
+ 73,110,112,117,116, 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, 77, 97,116,101,
+114,105, 97,108, 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, 92,251,
+ 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0,
+176,131,196, 8,112, 0, 0, 0, 1, 0, 0, 0,128,132,196, 8,224,130,196, 8, 77, 97,112, 32, 84,111, 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, 77, 97,116,101,114,105, 97,108, 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, 96,252, 62, 1,204, 0, 4, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0,128,132,196, 8,112, 0, 0, 0,
+ 1, 0, 0, 0, 80,133,196, 8,176,131,196, 8, 82, 97,109,112,115, 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, 77, 97,116,101,114,105, 97,108, 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, 24,255, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,112,128,196, 8, 68, 65, 84, 65,164, 0, 0, 0, 80,133,196, 8,112, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+128,132,196, 8, 77,105,114,114,111,114, 32, 84,114, 97,110,115,112, 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, 77, 97,116,101,114,105, 97,108, 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, 72,253, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65,212, 0, 0, 0, 32,134,196, 8, 94, 0, 0, 0, 1, 0, 0, 0, 32,135,196, 8, 0, 0, 0, 0, 4, 0, 0, 0,
+ 51, 51, 51, 63, 1, 86,249,156, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
+ 0, 0, 0,193, 0, 0,163, 67, 0,128,148,196, 0, 0,104, 67, 0, 0, 0,193, 0, 0,163, 67,170,175,118,196,255,255,103, 67,
+ 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,128, 67, 0, 0, 40, 66, 0, 0,200, 68, 0, 0,225, 67,
+ 0, 0, 0, 63,225,122,180, 63, 0, 0, 1, 0, 1, 0, 1, 0,188, 0,174, 2, 0, 0, 0, 0, 3, 0, 1, 0, 0, 0, 3, 0,
+ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,141, 0, 0, 0, 0, 0,150, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,180, 2, 0, 0, 32,135,196, 8, 89, 0, 0, 0, 1, 0, 0, 0, 0,138,196, 8,
+ 32,134,196, 8, 1, 0, 0, 0, 51, 51, 51, 63, 1, 86,249,156, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+188, 74,140, 62,166,194, 72,191, 33,132, 14, 63, 0, 0, 0, 0, 41,120,117, 63,135,105, 54, 62,200, 80, 98,190, 0, 0, 0, 0,
+239,220,151, 61, 31, 40, 24, 63, 94,255, 76, 63, 0, 0, 0, 0,175,149, 97, 63,230,187,142,189,122,166,182,193, 0, 0,128, 63,
+186, 74,140, 62, 35,120,117, 63,254,220,151, 61, 0, 0, 0, 0,160,194, 72,191,131,105, 54, 62, 30, 40, 24, 63, 0, 0, 0, 0,
+ 32,132, 14, 63,190, 80, 98,190, 94,255, 76, 63, 0, 0, 0, 0, 92,160, 70, 65,162, 28,188,192,224, 17,146, 65, 0, 0,128, 63,
+197, 52, 91, 63,228,148, 91,191,186,146, 14,191, 33,132, 14,191,223,197, 63, 64,106,131, 71, 62,246,103, 98, 62,200, 80, 98, 62,
+ 52, 73,109, 62,225,107, 38, 63, 93, 20, 77,191, 94,255, 76,191,240, 60, 48, 64,130, 29,156,189,128, 31,181, 65,122,166,182, 65,
+252,146,179, 61,173, 25,157, 62, 75, 99,194, 60, 0, 0,165, 50,214,141, 55,191,192,199, 38, 62,176, 28, 11, 63, 0,128, 24,181,
+167, 58,120,194,184, 22,235, 65, 49,140,182,194, 27,247,159,192, 5, 26,118, 66, 44,106,233,193,230, 4,181, 66,126, 7,160, 64,
+255,255, 71, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255,255,139, 63, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 28, 13,128,191, 0, 0,128,191, 0, 0, 0,128, 0, 0, 0,128, 74,215, 76,190, 0, 0, 0,128,
+188, 74,140, 62,166,194, 72,191, 33,132, 14, 63, 0, 0, 0, 0, 41,120,117, 63,135,105, 54, 62,200, 80, 98,190, 0, 0, 0, 0,
+239,220,151, 61, 31, 40, 24, 63, 94,255, 76, 63, 0, 0, 0, 0,175,149, 97, 63,230,187,142,189,122,166,182,193, 0, 0,128, 63,
+218, 31, 64, 63, 36, 17,139,190,182,154, 36,190,156,165, 20,191,221, 79,187, 65, 1, 0, 0, 0, 40, 9,197, 8, 0, 0, 0, 0,
+ 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 3, 0, 10, 0, 0, 24, 0, 0, 12, 66, 0, 0,128, 63,
+ 0, 0, 0, 0, 0, 0, 0, 0,205,204,204, 61, 0, 0,250, 67,104,217, 30, 63,106, 40, 52, 63,116, 39,251, 62, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,100, 0, 0, 0, 7, 0,175, 0, 0, 0, 0, 0, 1, 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, 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, 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, 68, 65, 84, 65, 40, 1, 0, 0, 0,138,196, 8, 93, 0, 0, 0,
+ 1, 0, 0, 0, 88,139,196, 8, 32,135,196, 8, 2, 0, 0, 0, 51, 51, 51, 63, 1, 86,249,156, 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,122, 67, 0, 0, 32,193, 0, 0, 32, 65,
+ 0, 0, 0, 0, 0, 0,122, 67, 0, 0, 32,193, 0, 0, 32, 65, 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,
+ 10,215, 35, 60, 10,215, 35, 60, 0, 96,106, 70, 0, 0,122, 68, 0, 0, 0, 0, 0, 0, 0, 0, 9, 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, 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, 79, 66, 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, 68, 65, 84, 65, 84, 1, 0, 0, 88,139,196, 8, 96, 0, 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0,138,196, 8, 5, 0, 0, 0, 51, 51, 51, 63, 1, 86,249,156, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 59, 0, 0, 0, 83, 65, 86, 69, 32, 70, 73, 76, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 47,117,115,114, 47,104,111,109,101, 47,105,110,116,114,114, 47, 98,108,101,110,100,101,114, 47, 98,108,101,110,
+100, 47, 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, 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,
+ 0, 0, 0, 0,117,110,116,105,116,108,101,100, 46, 98,108,101,110,100, 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, 0, 0, 0, 8, 0, 24, 0, 1, 0, 0, 0,203, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255,255, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,204, 0, 0, 0,216,140,196, 8,
+113, 0, 0, 0, 1, 0, 0, 0,136,148,196, 8,104,123,196, 8, 96,101,196, 8,224,102,196, 8, 32,103,196, 8, 96,102,196, 8,
+ 0, 0, 0, 0, 85,240, 46, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,237,119,206, 61, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,128, 0, 0, 0,128,111, 18, 3,187, 0, 0, 0,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,128, 63, 0, 0, 0, 0, 43, 3, 0, 0, 61, 0, 0, 0,175, 1, 0, 0, 0, 0, 0, 0, 43, 3, 0, 0, 61, 0, 0, 0,
+ 87, 0, 0, 0, 0, 0, 0, 0, 43, 3, 0, 0, 88, 0, 0, 0,175, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 44, 3, 88, 1,
+ 1, 0, 1, 0,251, 2, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,208,141,196, 8,
+ 8,147,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,180, 2, 0, 0,208,141,196, 8,
+ 89, 0, 0, 0, 1, 0, 0, 0,176,144,196, 8, 0, 0, 0, 0, 1, 0, 0, 0, 51, 51, 51, 63, 1, 87, 7,236, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0,104,217, 30, 63,
+106, 40, 52, 63,116, 39,251, 62, 0, 0,128, 63, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0,104,217, 30,191,
+106, 40, 52,191,116, 39,251,190, 0, 0,128, 63, 85,240, 46, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+237,119,206, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,111, 18, 3,187, 0, 0, 0, 0,202, 25,217, 60,
+235, 76,145, 61, 70,151,128,186, 0, 0,128, 63,172, 79,187, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1,181, 30, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 0, 0, 0,128,255,255,249,195, 0, 0, 0, 0,103,217, 30,191,
+106, 40, 52,191,116, 39,251,190, 0, 0,128, 63, 85,240, 46, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+237,119,206, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 0, 0, 0,128,111, 18, 3,187, 0, 0, 0,128, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0,104,217, 30, 63,
+106, 40, 52, 63,116, 39,251, 62, 0, 0,128, 63, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,172, 79,187, 65,
+ 0, 0, 7, 0, 40, 9,197, 8, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 3, 0,
+ 10, 0, 8, 24, 0, 0, 12, 66, 0, 0,128, 63, 0, 0,128, 63, 0, 0, 0, 0,205,204,204, 61, 0, 0,250, 67,104,217, 30, 63,
+106, 40, 52, 63,116, 39,251, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,100, 0, 1, 0, 7, 0,175, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 3, 0, 0, 0, 69,104,138, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69,104,138, 64,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69,104,138, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,128, 63, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+212, 0, 0, 0,176,144,196, 8, 94, 0, 0, 0, 1, 0, 0, 0,176,145,196, 8,208,141,196, 8, 4, 0, 0, 0, 51, 51, 51, 63,
+ 1, 87, 7,236, 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,224,159, 68, 0, 0, 0, 0, 0, 0,100, 67,172, 62, 57, 67, 44,184,136, 68,169,101, 28,195, 16,147,173, 67, 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,128, 67, 0, 0, 40, 66, 0, 0,200, 68, 0, 0,225, 67, 0, 0, 0, 63,
+225,122,180, 63, 0, 0, 1, 0, 1, 0, 1, 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,150, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65, 40, 1, 0, 0,176,145,196, 8, 93, 0, 0, 0, 1, 0, 0, 0, 8,147,196, 8,176,144,196, 8,
+ 2, 0, 0, 0, 51, 51, 51, 63, 1, 87, 7,236, 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,122, 67, 0, 0, 32,193, 0, 0, 32, 65, 0, 0, 0, 0, 0, 0,122, 67, 0, 0, 32,193,
+ 0, 0, 32, 65, 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, 10,215, 35, 60, 10,215, 35, 60, 0, 96,106, 70,
+ 0, 0,122, 68, 0, 0, 0, 0, 0, 0, 0, 0, 9, 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, 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, 79, 66, 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,
+ 68, 65, 84, 65, 84, 1, 0, 0, 8,147,196, 8, 96, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,176,145,196, 8, 5, 0, 0, 0,
+ 51, 51, 51, 63, 1, 87, 7,236, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0,
+ 83, 65, 86, 69, 32, 70, 73, 76, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 85,115,101,114,115, 47,116,
+111,110, 47, 68,101,115,107,116,111,112, 47, 0,100,101,114, 47, 98,108,101,110,100, 47, 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, 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, 0, 0, 0, 0,117,110,116,105,116,108,101,100,
+ 46, 98,108,101,110,100, 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, 0, 0, 0, 8, 0, 0, 0, 1, 0, 0, 0,203, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255,255,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,204, 0, 0, 0,136,148,196, 8,113, 0, 0, 0, 1, 0, 0, 0, 56,156,196, 8,
+216,140,196, 8, 96,103,196, 8,160,103,196, 8,160,102,196, 8, 32,103,196, 8, 0, 0, 0, 0,173,101,182, 63, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66, 36,209, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+154, 65,128,191, 0, 0,128,191, 0, 0, 0,128, 0, 0, 0,128, 72, 1, 77,190, 0, 0, 0,128,165, 1, 0, 0, 43, 3, 0, 0,
+177, 1, 0, 0, 5, 3, 0, 0,165, 1, 0, 0, 43, 3, 0, 0,177, 1, 0, 0,177, 1, 0, 0,165, 1, 0, 0, 43, 3, 0, 0,
+177, 1, 0, 0, 5, 3, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,135, 1, 85, 1, 3, 0, 1, 0, 83, 2, 0, 0, 7, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128,149,196, 8,184,154,196, 8, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,180, 2, 0, 0,128,149,196, 8, 89, 0, 0, 0, 1, 0, 0, 0, 96,152,196, 8,
+ 0, 0, 0, 0, 1, 0, 0, 0, 51, 51, 51, 63, 1, 87, 12,124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+221,149, 47, 63, 85,126,162,190, 8,165, 39, 63, 0, 0, 0, 0, 51, 70, 58, 63,225,251,159, 62,149, 84, 28,191, 0, 0, 0, 0,
+191, 56, 49,188, 54, 53,101, 63, 50,247,227, 62, 0, 0, 0, 0, 90, 38,173,190,254,221,192,190,152, 9, 52,193, 0, 0,128, 63,
+223,149, 47, 63, 55, 70, 58, 63,192, 56, 49,188, 0, 0, 0, 0, 87,126,162,190,228,251,159, 62, 56, 53,101, 63, 0, 0, 0, 0,
+ 7,165, 39, 63,150, 84, 28,191, 50,247,227, 62, 0, 0, 0, 0,110,101,239, 64,151, 62,208,192, 77,255,170, 64, 0, 0,128, 63,
+144, 52,122, 63, 39,192, 4,191,244,250, 39,191, 8,165, 39,191,228,183,132, 63, 75,179, 2, 63,180,164, 28, 63,149, 84, 28, 63,
+118,137,124,188,232, 64,187, 63, 8,108,228,190, 50,247,227,190, 18,188,246,190,141,144, 29,191,216, 49, 49, 65,152, 9, 52, 65,
+116,112,246, 62,142,184, 2, 63, 64,191,248,187, 0, 0,144,179, 64,230, 70,190,226,211, 67, 62,254, 71, 12, 63, 0, 0, 0, 52,
+211,120, 21,194,144, 5, 2, 66, 7,136,213,193,193,214,159,192,219, 38, 19, 66,196,173,255,193,155,101,210, 65,173, 40,160, 64,
+173,101,182, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66, 36,209, 63, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,154, 65,128,191, 0, 0,128,191, 0, 0, 0,128, 0, 0, 0,128, 72, 1, 77,190, 0, 0, 0,128,
+221,149, 47, 63, 85,126,162,190, 8,165, 39, 63, 0, 0, 0, 0, 51, 70, 58, 63,225,251,159, 62,149, 84, 28,191, 0, 0, 0, 0,
+191, 56, 49,188, 54, 53,101, 63, 50,247,227, 62, 0, 0, 0, 0, 90, 38,173,190,254,221,192,190,152, 9, 52,193, 0, 0,128, 63,
+241, 22, 72, 63, 78,162,246,190, 44, 8, 90,190, 3, 35,171,190,221, 79,187, 65, 2, 0, 0, 0, 40, 9,197, 8, 0, 0, 0, 0,
+ 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 3, 0, 10, 0, 8, 24, 0, 0, 12, 66, 0, 0,128, 63,
+ 0, 0,128, 63, 0, 0, 0, 0,205,204,204, 61, 0, 0,250, 67,104,217, 30, 63,106, 40, 52, 63,116, 39,251, 62, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,100, 0, 0, 0, 7, 0,175, 0, 0, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0, 0,221,224, 65, 64,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,221,224, 65, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,221,224, 65, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 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, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,212, 0, 0, 0, 96,152,196, 8, 94, 0, 0, 0,
+ 1, 0, 0, 0, 96,153,196, 8,128,149,196, 8, 4, 0, 0, 0, 51, 51, 51, 63, 1, 87, 12,124, 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,224,159, 68, 0, 0, 0, 0, 0, 0,100, 67,
+172, 62, 57, 67, 44,184,136, 68,169,101, 28,195, 16,147,173, 67, 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,128, 67, 0, 0, 40, 66, 0, 0,200, 68, 0, 0,225, 67, 0, 0, 0, 63,225,122,180, 63, 0, 0, 1, 0, 1, 0, 1, 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,150, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 40, 1, 0, 0,
+ 96,153,196, 8, 93, 0, 0, 0, 1, 0, 0, 0,184,154,196, 8, 96,152,196, 8, 2, 0, 0, 0, 51, 51, 51, 63, 1, 87, 12,124,
+ 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,122, 67,
+ 0, 0, 32,193, 0, 0, 32, 65, 0, 0, 0, 0, 0, 0,122, 67, 0, 0, 32,193, 0, 0, 32, 65, 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, 10,215, 35, 60, 10,215, 35, 60, 0, 96,106, 70, 0, 0,122, 68, 0, 0, 0, 0, 0, 0, 0, 0,
+ 9, 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,
+ 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, 79, 66, 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, 68, 65, 84, 65, 84, 1, 0, 0,184,154,196, 8,
+ 96, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 96,153,196, 8, 5, 0, 0, 0, 51, 51, 51, 63, 1, 87, 12,124, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 83, 65, 86, 69, 32, 70, 73, 76, 69, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 85,115,101,114,115, 47,116,111,110, 47, 68,101,115,107,116,111,112, 47, 0,
+100,101,114, 47, 98,108,101,110,100, 47, 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, 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, 0, 0, 0, 0,117,110,116,105,116,108,101,100, 46, 98,108,101,110,100, 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, 0, 0, 0, 8, 0, 0, 0,
+ 1, 0, 0, 0,203, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255,255, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+204, 0, 0, 0, 56,156,196, 8,113, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,136,148,196, 8,224,102,196, 8,224,101,196, 8,
+160,103,196, 8, 96,103,196, 8, 0, 0, 0, 0,152, 38,151, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 7, 43,186, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 0, 0, 0,128,111, 18, 3,187, 0, 0, 0,128, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0,163, 1, 0, 0,177, 1, 0, 0, 5, 3, 0, 0, 0, 0, 0, 0,
+163, 1, 0, 0,177, 1, 0, 0,177, 1, 0, 0, 0, 0, 0, 0,163, 1, 0, 0,177, 1, 0, 0, 5, 3, 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 1,164, 1, 85, 1, 3, 0, 1, 0, 83, 2, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 48,157,196, 8,104,162,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+180, 2, 0, 0, 48,157,196, 8, 89, 0, 0, 0, 1, 0, 0, 0, 16,160,196, 8, 0, 0, 0, 0, 1, 0, 0, 0, 51, 51, 51, 63,
+ 1, 87, 17, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0,128,
+ 0, 0, 0, 0, 0, 0, 0,128,174, 2, 19, 51,255,255,127,191, 0, 0, 0, 0, 0, 0, 0, 0,255,255,127, 63,174, 2, 19, 51,
+ 0, 0, 0, 0, 58,248, 30,192, 45,161,118,192,107, 40, 52,191, 0, 0,128, 63, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 1, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,128,191,176, 2, 19, 51,
+ 0, 0, 0, 0, 59,248, 30, 64,107, 40, 52,191, 48,161,118, 64, 0, 0,128, 63,152, 38,151, 61, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 80,209, 85, 49,110, 18, 3, 59, 0, 0, 0, 0, 0, 0, 0, 0, 6, 43,186, 61,234,137,150,174,
+ 0, 0, 0, 0,195,184, 59,190,143, 90,179,190, 79,123,184, 58, 0, 0,128, 63, 74,202, 88, 65, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 53, 0, 0,128, 52, 85, 3, 48, 65, 0, 0, 0, 0, 0, 0,128,171, 1, 0,250, 67,160,144,143,183,
+ 0, 0, 0, 0, 59,248, 30, 64,106, 40, 52,191, 48,161,118, 64, 0, 0,128, 63,152, 38,151, 61, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 7, 43,186, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 0, 0, 0,128,111, 18, 3,187,
+ 0, 0, 0,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0,128,
+ 0, 0, 0, 0, 0, 0, 0,128,174, 2, 19, 51,255,255,127,191, 0, 0, 0, 0, 0, 0, 0, 0,255,255,127, 63,174, 2, 19, 51,
+ 0, 0, 0, 0, 58,248, 30,192, 45,161,118,192,107, 40, 52,191, 0, 0,128, 63,243, 4, 53, 63,243, 4, 53,191, 0, 0, 0, 0,
+ 0, 0, 0, 0, 73,202, 88, 65, 0, 0, 1, 0, 40, 9,197, 8, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0, 3, 0, 10, 0, 8, 24, 0, 0, 12, 66, 0, 0,128, 63, 0, 0,128, 63, 0, 0, 0, 0,205,204,204, 61,
+ 0, 0,250, 67, 58,248, 30,192,106, 40, 52, 63, 46,161,118,192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,100, 0, 2, 0,
+ 7, 0,175, 0, 0, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0, 0,162,217,154, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,162,217,154, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,162,217,154, 64, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65,212, 0, 0, 0, 16,160,196, 8, 94, 0, 0, 0, 1, 0, 0, 0, 16,161,196, 8, 48,157,196, 8,
+ 4, 0, 0, 0, 51, 51, 51, 63, 1, 87, 17, 12, 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,224,159, 68, 0, 0, 0, 0, 0, 0,100, 67,172, 62, 57, 67, 44,184,136, 68,169,101, 28,195,
+ 16,147,173, 67, 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,128, 67, 0, 0, 40, 66, 0, 0,200, 68,
+ 0, 0,225, 67, 0, 0, 0, 63,225,122,180, 63, 0, 0, 1, 0, 1, 0, 1, 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,150, 1, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 40, 1, 0, 0, 16,161,196, 8, 93, 0, 0, 0, 1, 0, 0, 0,
+104,162,196, 8, 16,160,196, 8, 2, 0, 0, 0, 51, 51, 51, 63, 1, 87, 17, 12, 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,122, 67, 0, 0, 32,193, 0, 0, 32, 65, 0, 0, 0, 0,
+ 0, 0,122, 67, 0, 0, 32,193, 0, 0, 32, 65, 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, 10,215, 35, 60,
+ 10,215, 35, 60, 0, 96,106, 70, 0, 0,122, 68, 0, 0, 0, 0, 0, 0, 0, 0, 9, 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, 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, 79, 66, 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, 68, 65, 84, 65, 84, 1, 0, 0,104,162,196, 8, 96, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 16,161,196, 8, 5, 0, 0, 0, 51, 51, 51, 63, 1, 87, 17, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 32, 0, 0, 0, 83, 65, 86, 69, 32, 70, 73, 76, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 47, 85,115,101,114,115, 47,116,111,110, 47, 68,101,115,107,116,111,112, 47, 0,100,101,114, 47, 98,108,101,110,100, 47, 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, 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, 0, 0, 0, 0,
+117,110,116,105,116,108,101,100, 46, 98,108,101,110,100, 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, 0, 0, 0, 8, 0, 0, 0, 1, 0, 0, 0,203, 0, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,255,255, 0, 0, 0, 0, 0, 0, 0, 0, 83, 82, 0, 0,116, 0, 0, 0,232,163,196, 8,109, 0, 0, 0,
+ 1, 0, 0, 0,136,207,196, 8,192, 99,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 83, 82, 52, 45, 83,101,113,117,101,110, 99,101,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,136,164,196, 8,200,167,196, 8, 8,168,196, 8,
+168,173,196, 8,240,173,196, 8, 96,201,196, 8,136,251,196, 8, 0, 0,231, 3,143, 1,174, 4,232, 3, 32, 3, 1, 0, 4, 0,
+ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0,
+136,164,196, 8,110, 0, 0, 0, 1, 0, 0, 0,200,164,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65, 20, 0, 0, 0,200,164,196, 8,110, 0, 0, 0, 1, 0, 0, 0, 8,165,196, 8,136,164,196, 8, 0, 0, 0, 0,
+ 0, 0, 32, 3, 0, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0, 8,165,196, 8,110, 0, 0, 0, 1, 0, 0, 0, 72,165,196, 8,
+200,164,196, 8, 0, 0, 0, 0,232, 3, 32, 3, 0, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0, 72,165,196, 8,110, 0, 0, 0,
+ 1, 0, 0, 0,136,165,196, 8, 8,165,196, 8, 0, 0, 0, 0,232, 3, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0,
+136,165,196, 8,110, 0, 0, 0, 1, 0, 0, 0,200,165,196, 8, 72,165,196, 8, 0, 0, 0, 0, 0, 0,200, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65, 20, 0, 0, 0,200,165,196, 8,110, 0, 0, 0, 1, 0, 0, 0, 8,166,196, 8,136,165,196, 8, 0, 0, 0, 0,
+232, 3,200, 0, 0, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0, 8,166,196, 8,110, 0, 0, 0, 1, 0, 0, 0, 72,166,196, 8,
+200,165,196, 8, 0, 0, 0, 0, 0, 0, 6, 3, 1, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0, 72,166,196, 8,110, 0, 0, 0,
+ 1, 0, 0, 0,136,166,196, 8, 8,166,196, 8, 0, 0, 0, 0,232, 3, 6, 3, 1, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0,
+136,166,196, 8,110, 0, 0, 0, 1, 0, 0, 0,200,166,196, 8, 72,166,196, 8, 0, 0, 0, 0, 0, 0,244, 1, 0, 0, 0, 0,
+ 68, 65, 84, 65, 20, 0, 0, 0,200,166,196, 8,110, 0, 0, 0, 1, 0, 0, 0, 8,167,196, 8,136,166,196, 8, 0, 0, 0, 0,
+232, 3,244, 1, 0, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0, 8,167,196, 8,110, 0, 0, 0, 1, 0, 0, 0, 72,167,196, 8,
+200,166,196, 8, 0, 0, 0, 0, 84, 2,244, 1, 0, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0, 72,167,196, 8,110, 0, 0, 0,
+ 1, 0, 0, 0,136,167,196, 8, 8,167,196, 8, 0, 0, 0, 0, 84, 2, 6, 3, 1, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0,
+136,167,196, 8,110, 0, 0, 0, 1, 0, 0, 0,200,167,196, 8, 72,167,196, 8, 0, 0, 0, 0, 0, 0, 4, 1, 0, 0, 0, 0,
+ 68, 65, 84, 65, 20, 0, 0, 0,200,167,196, 8,110, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,136,167,196, 8, 0, 0, 0, 0,
+232, 3, 4, 1, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0, 8,168,196, 8,111, 0, 0, 0, 1, 0, 0, 0, 80,168,196, 8,
+ 0, 0, 0, 0,200,164,196, 8, 8,165,196, 8, 1, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0, 80,168,196, 8,
+111, 0, 0, 0, 1, 0, 0, 0,152,168,196, 8, 8,168,196, 8,136,164,196, 8, 72,165,196, 8, 1, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65, 24, 0, 0, 0,152,168,196, 8,111, 0, 0, 0, 1, 0, 0, 0,224,168,196, 8, 80,168,196, 8,136,164,196, 8,
+136,165,196, 8, 1, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,224,168,196, 8,111, 0, 0, 0, 1, 0, 0, 0,
+ 40,169,196, 8,152,168,196, 8, 72,165,196, 8,200,165,196, 8, 1, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,
+ 40,169,196, 8,111, 0, 0, 0, 1, 0, 0, 0,112,169,196, 8,224,168,196, 8,136,165,196, 8,200,165,196, 8, 0, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,112,169,196, 8,111, 0, 0, 0, 1, 0, 0, 0,184,169,196, 8, 40,169,196, 8,
+200,164,196, 8, 8,166,196, 8, 1, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,184,169,196, 8,111, 0, 0, 0,
+ 1, 0, 0, 0, 0,170,196, 8,112,169,196, 8, 8,165,196, 8, 72,166,196, 8, 1, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+ 24, 0, 0, 0, 0,170,196, 8,111, 0, 0, 0, 1, 0, 0, 0, 72,170,196, 8,184,169,196, 8, 8,166,196, 8, 72,166,196, 8,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0, 72,170,196, 8,111, 0, 0, 0, 1, 0, 0, 0,144,170,196, 8,
+ 0,170,196, 8, 8,166,196, 8,136,166,196, 8, 1, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,144,170,196, 8,
+111, 0, 0, 0, 1, 0, 0, 0,216,170,196, 8, 72,170,196, 8, 72,166,196, 8,200,166,196, 8, 1, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65, 24, 0, 0, 0,216,170,196, 8,111, 0, 0, 0, 1, 0, 0, 0, 32,171,196, 8,144,170,196, 8,136,166,196, 8,
+200,166,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0, 32,171,196, 8,111, 0, 0, 0, 1, 0, 0, 0,
+104,171,196, 8,216,170,196, 8,136,166,196, 8, 8,167,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,
+104,171,196, 8,111, 0, 0, 0, 1, 0, 0, 0,176,171,196, 8, 32,171,196, 8,200,166,196, 8, 8,167,196, 8, 0, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,176,171,196, 8,111, 0, 0, 0, 1, 0, 0, 0,248,171,196, 8,104,171,196, 8,
+ 8,166,196, 8, 72,167,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,248,171,196, 8,111, 0, 0, 0,
+ 1, 0, 0, 0, 64,172,196, 8,176,171,196, 8, 72,166,196, 8, 72,167,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+ 24, 0, 0, 0, 64,172,196, 8,111, 0, 0, 0, 1, 0, 0, 0,136,172,196, 8,248,171,196, 8, 8,167,196, 8, 72,167,196, 8,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,136,172,196, 8,111, 0, 0, 0, 1, 0, 0, 0,208,172,196, 8,
+ 64,172,196, 8,136,165,196, 8,136,167,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,208,172,196, 8,
+111, 0, 0, 0, 1, 0, 0, 0, 24,173,196, 8,136,172,196, 8,136,166,196, 8,136,167,196, 8, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65, 24, 0, 0, 0, 24,173,196, 8,111, 0, 0, 0, 1, 0, 0, 0, 96,173,196, 8,208,172,196, 8,200,166,196, 8,
+200,167,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0, 96,173,196, 8,111, 0, 0, 0, 1, 0, 0, 0,
+168,173,196, 8, 24,173,196, 8,200,165,196, 8,200,167,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,
+168,173,196, 8,111, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 96,173,196, 8,136,167,196, 8,200,167,196, 8, 0, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65,204, 0, 0, 0,240,173,196, 8,113, 0, 0, 0, 1, 0, 0, 0,168,180,196, 8, 0, 0, 0, 0,
+136,164,196, 8,136,165,196, 8,200,165,196, 8, 72,165,196, 8, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0,232, 3, 0, 0, 0, 0, 0, 0,
+199, 0, 0, 0, 0, 0, 0, 0,232, 3, 0, 0,173, 0, 0, 0,199, 0, 0, 0, 0, 0, 0, 0,232, 3, 0, 0, 0, 0, 0, 0,
+172, 0, 0, 0, 0, 0, 0, 0, 2, 0, 4, 4,233, 3,173, 0, 1, 0, 1, 1,139, 1, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40,178,196, 8, 40,179,196, 8, 0, 0, 0, 0, 0, 0, 0, 0,232,174,196, 8,
+ 88,177,196, 8, 68, 65, 84, 65,164, 0, 0, 0,232,174,196, 8,112, 0, 0, 0, 1, 0, 0, 0,184,175,196, 8, 0, 0, 0, 0,
+ 79,117,116,112,117,116, 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,
+ 82,101,110,100,101,114, 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, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+164, 0, 0, 0,184,175,196, 8,112, 0, 0, 0, 1, 0, 0, 0,136,176,196, 8,232,174,196, 8, 82,101,110,100,101,114, 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, 82,101,110,100,101,114, 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, 70, 1, 0, 0, 62, 1,204, 0,
+ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0,136,176,196, 8,
+112, 0, 0, 0, 1, 0, 0, 0, 88,177,196, 8,184,175,196, 8, 65,110,105,109, 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, 82,101,110,100,101,114, 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,140, 2, 0, 0, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0, 88,177,196, 8,112, 0, 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0,136,176,196, 8, 70,111,114,109, 97,116, 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, 82,101,110,100,101,114, 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,210, 3, 0, 0, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65,212, 0, 0, 0, 40,178,196, 8, 94, 0, 0, 0, 1, 0, 0, 0, 40,179,196, 8, 0, 0, 0, 0,
+ 4, 0, 0, 0, 51, 51, 51, 63, 1, 87, 30,252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0,193, 0, 0,163, 68, 0, 0, 0,193, 0, 0,104, 67, 0, 0, 0,193,118,149,172, 68, 0, 0, 0,193,
+ 0, 0,104, 67, 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,128, 67, 0, 0, 40, 66, 0, 0,200, 68,
+ 0, 0,225, 67, 0, 0, 0, 63,225,122,180, 63, 0, 0, 1, 0, 1, 0, 1, 0,233, 3,173, 0, 0, 0, 0, 0, 0, 0,255,255,
+ 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,150, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 84, 1, 0, 0, 40,179,196, 8, 96, 0, 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 40,178,196, 8, 5, 0, 0, 0, 51, 51, 51, 63, 1, 87, 30,252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 20, 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, 47, 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, 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, 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, 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, 8, 0, 0, 0, 0, 0, 0, 0, 57, 0, 2, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255,255, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,204, 0, 0, 0,168,180,196, 8,
+113, 0, 0, 0, 1, 0, 0, 0,160,181,196, 8,240,173,196, 8, 8,166,196, 8,200,164,196, 8, 8,165,196, 8, 72,166,196, 8,
+ 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, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,232, 3, 0, 0, 7, 3, 0, 0, 32, 3, 0, 0, 0, 0, 0, 0,232, 3, 0, 0, 7, 3, 0, 0,
+ 33, 3, 0, 0, 0, 0, 0, 0,232, 3, 0, 0, 32, 3, 0, 0, 32, 3, 0, 0, 0, 0, 0, 0, 1, 0, 7, 7,233, 3, 1, 0,
+ 1, 0, 1, 1,196, 2, 0, 0, 7, 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, 68, 65, 84, 65,204, 0, 0, 0,160,181,196, 8,
+113, 0, 0, 0, 1, 0, 0, 0,136,188,196, 8,168,180,196, 8,136,165,196, 8,136,167,196, 8,200,167,196, 8,200,165,196, 8,
+ 0, 0, 0, 0,228, 56,142, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,185,206,105, 62, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,111, 18, 3,187, 0, 0, 0, 0, 0, 0, 0,128, 0, 0, 0,128, 0, 0, 0,128,
+ 0, 0,128, 63, 0, 0, 0, 0,232, 3, 0, 0,201, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0,232, 3, 0, 0,201, 0, 0, 0,
+227, 0, 0, 0, 0, 0, 0, 0,232, 3, 0, 0,228, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 1, 0, 15, 15,233, 3, 32, 0,
+ 1, 0, 1, 1,192, 2, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,152,182,196, 8,
+ 8,187,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,148, 0, 0, 0,152,182,196, 8,
+102, 0, 0, 0, 1, 0, 0, 0, 88,183,196, 8, 0, 0, 0, 0, 15, 0, 0, 0, 51, 51, 51, 63, 1, 87, 38,188, 0, 0,128,192,
+ 0, 0,126, 67, 0, 0, 0, 0, 0, 0, 0, 66, 0, 0,128,192, 0, 0,126, 67, 0, 0, 0, 0, 0, 0, 0, 66, 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,
+233, 3, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 66, 0, 0,250, 70, 0, 0, 0, 66,205,204,204, 61,
+ 0, 0, 32, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 6, 0, 0, 0, 68, 65, 84, 65,
+164, 0, 0, 0, 88,183,196, 8, 95, 0, 0, 0, 1, 0, 0, 0, 40,184,196, 8,152,182,196, 8, 8, 0, 0, 0, 51, 51, 51, 63,
+ 1, 87, 38,188, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,122, 67, 0, 0, 0, 0,
+ 0, 0, 0, 65, 0, 0, 0, 0, 0, 0,122, 67, 0, 0, 0, 0, 0, 0, 0, 65, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0,
+ 32, 0, 0, 0, 16, 0, 0, 0,233, 3, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0,233, 3, 0, 0, 16, 0, 0, 0,
+ 32, 0, 0, 0, 0, 0, 32, 65, 0, 0,128, 64, 0, 0,250, 70, 0, 0, 0, 66,205,204,204, 61, 0, 0, 32, 65, 9, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 68, 65, 84, 65,180, 2, 0, 0, 40,184,196, 8,
+ 89, 0, 0, 0, 1, 0, 0, 0, 8,187,196, 8, 88,183,196, 8, 1, 0, 0, 0, 51, 51, 51, 63, 1, 87, 38,188, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63,228, 56,142, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+185,206,105, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,111, 18, 3,187, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63,102,102,102, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 38,140, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255,255,249,195, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 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, 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, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,102,102,102, 65,
+ 0, 0, 7, 0, 40, 9,197, 8, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 3, 0,
+ 0, 0, 0, 24, 0, 0, 12, 66, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 10,215, 35, 60, 0, 0,250, 67, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0,
+ 1, 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,
+ 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, 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, 68, 65, 84, 65,
+ 84, 1, 0, 0, 8,187,196, 8, 96, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 40,184,196, 8, 5, 0, 0, 0, 51, 51, 51, 63,
+ 1, 87, 38,188, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 65, 86, 69,
+ 32, 84, 65, 82, 71, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 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, 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, 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,116, 49, 46, 98,108,101,110,100, 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, 0, 0, 0, 0,
+ 0, 0, 0, 0, 8, 0, 0, 0, 2, 0, 0, 0, 57, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255,255, 0, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65,204, 0, 0, 0,136,188,196, 8,113, 0, 0, 0, 1, 0, 0, 0,176,194,196, 8,160,181,196, 8,
+ 8,167,196, 8, 72,167,196, 8, 72,166,196, 8,200,166,196, 8, 0, 0, 0, 0,228, 56,142, 61, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,191, 72, 20, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,111, 18, 3,187,
+ 0, 0, 0, 0, 0, 0, 0,128, 0, 0, 0,128, 0, 0, 0,128, 0, 0,128, 63, 85, 2, 0, 0,232, 3, 0, 0,245, 1, 0, 0,
+ 5, 3, 0, 0, 85, 2, 0, 0,232, 3, 0, 0,245, 1, 0, 0,245, 1, 0, 0, 85, 2, 0, 0,232, 3, 0, 0,245, 1, 0, 0,
+ 5, 3, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8,148, 1, 17, 1, 3, 0, 1, 1, 9, 1, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128,189,196, 8, 48,193,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0,128,189,196, 8, 95, 0, 0, 0, 1, 0, 0, 0, 80,190,196, 8, 0, 0, 0, 0,
+ 8, 0, 0, 0, 51, 51, 51, 63, 1, 87, 42,204, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,122, 67, 0, 0, 0, 0, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0,122, 67, 0, 0, 0, 0, 0, 0, 0, 65, 0, 0, 0, 0,
+ 16, 0, 0, 0, 0, 0, 0, 0, 49, 1, 0, 0, 17, 0, 0, 0,124, 2, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 17, 0, 0, 0,
+124, 2, 0, 0, 17, 0, 0, 0, 49, 1, 0, 0, 0, 0, 32, 65, 0, 0,128, 64, 0, 0,250, 70, 0, 0, 0, 66,205,204,204, 61,
+ 0, 0, 32, 65, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+180, 2, 0, 0, 80,190,196, 8, 89, 0, 0, 0, 1, 0, 0, 0, 48,193,196, 8,128,189,196, 8, 1, 0, 0, 0, 51, 51, 51, 63,
+ 1, 87, 42,204, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63,228, 56,142, 61, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,191, 72, 20, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,111, 18, 3,187,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63,102,102,102, 65, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 42,251,220, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255,255,249,195,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 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, 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, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,102,102,102, 65, 0, 0, 7, 0, 40, 9,197, 8, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0, 3, 0, 0, 0, 0, 24, 0, 0, 12, 66, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 10,215, 35, 60,
+ 0, 0,250, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0,
+ 7, 0, 0, 0, 0, 0, 0, 0, 1, 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, 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, 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, 68, 65, 84, 65, 84, 1, 0, 0, 48,193,196, 8, 96, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 80,190,196, 8,
+ 5, 0, 0, 0, 51, 51, 51, 63, 1, 87, 42,204, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 20, 0, 0, 0, 0, 65, 86, 69, 32, 84, 65, 82, 71, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 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, 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, 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,116, 49, 46,
+ 98,108,101,110,100, 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, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 2, 0, 0, 0, 57, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,255,255, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,204, 0, 0, 0,176,194,196, 8,113, 0, 0, 0, 1, 0, 0, 0,
+ 96,201,196, 8,136,188,196, 8,136,166,196, 8, 8,166,196, 8, 72,167,196, 8, 8,167,196, 8, 0, 0, 0, 0,228, 56,142, 61,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,205,220, 29, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,111, 18, 3,187, 0, 0, 0, 0, 0, 0, 0,128, 0, 0, 0,128, 0, 0, 0,128, 0, 0,128, 63, 0, 0, 0, 0,
+ 83, 2, 0, 0,245, 1, 0, 0, 5, 3, 0, 0, 0, 0, 0, 0, 83, 2, 0, 0,245, 1, 0, 0, 15, 2, 0, 0, 0, 0, 0, 0,
+ 83, 2, 0, 0, 16, 2, 0, 0, 5, 3, 0, 0, 0, 0, 0, 0, 1, 0, 2, 2, 84, 2,246, 0, 1, 0, 1, 0,203, 1, 0, 0,
+ 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,168,195,196, 8,224,199,196, 8, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 40, 1, 0, 0,168,195,196, 8, 93, 0, 0, 0, 1, 0, 0, 0,
+ 0,197,196, 8, 0, 0, 0, 0, 2, 0, 0, 0, 51, 51, 51, 63, 1, 87, 46, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,160,192, 0, 0,210, 66,205,204,204,189,205,204,140, 63, 0, 0,160,192,
+ 0, 0,210, 66,205,204,204,189,205,204,140, 63, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0,246, 0, 0, 0, 16, 0, 0, 0,
+ 19, 2, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 19, 2, 0, 0, 16, 0, 0, 0,246, 0, 0, 0, 10,215, 35, 60,
+ 10,215, 35, 60, 0, 96,106, 70, 0, 0,122, 68, 0, 0, 0, 0, 0, 0, 0, 0, 9, 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, 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, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 83, 81, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,160,192, 0, 0,210, 66,
+205,204,204,189,205,204,140, 63, 68, 65, 84, 65,180, 2, 0, 0, 0,197,196, 8, 89, 0, 0, 0, 1, 0, 0, 0,224,199,196, 8,
+168,195,196, 8, 1, 0, 0, 0, 51, 51, 51, 63, 1, 87, 46, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63,
+ 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63,
+228, 56,142, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,205,220, 29, 62, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,111, 18, 3,187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63,
+102,102,102, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,179,146,207, 64, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,255,255,249,195, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63,
+ 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, 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, 0, 0,
+ 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,102,102,102, 65, 0, 0, 7, 0, 40, 9,197, 8, 0, 0, 0, 0,
+ 0, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 3, 0, 0, 0, 0, 24, 0, 0, 12, 66, 0, 0,128, 63,
+ 0, 0, 0, 0, 0, 0, 0, 0, 10,215, 35, 60, 0, 0,250, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 1, 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, 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, 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, 68, 65, 84, 65, 84, 1, 0, 0,224,199,196, 8, 96, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0,197,196, 8, 5, 0, 0, 0, 51, 51, 51, 63, 1, 87, 46, 28, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 79, 65, 68, 32, 70, 73, 76, 69, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 47, 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, 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, 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, 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, 8, 0, 0, 0, 0, 0, 0, 0,
+ 57, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255,255, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,204, 0, 0, 0,
+ 96,201,196, 8,113, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,176,194,196, 8,136,167,196, 8,136,166,196, 8,200,166,196, 8,
+200,167,196, 8, 0, 0, 0, 0,228, 56,142, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,185,206,105, 62,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,111, 18, 3,187, 0, 0, 0, 0, 0, 0, 0,128, 0, 0, 0,128,
+ 0, 0, 0,128, 0, 0,128, 63, 0, 0, 0, 0,232, 3, 0, 0, 5, 1, 0, 0,243, 1, 0, 0, 0, 0, 0, 0,232, 3, 0, 0,
+ 5, 1, 0, 0, 31, 1, 0, 0, 0, 0, 0, 0,232, 3, 0, 0, 32, 1, 0, 0,243, 1, 0, 0, 0, 0, 0, 0, 1, 0, 8, 8,
+233, 3,212, 0, 1, 0, 1, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 88,202,196, 8, 8,206,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0,
+ 88,202,196, 8, 95, 0, 0, 0, 1, 0, 0, 0, 40,203,196, 8, 0, 0, 0, 0, 8, 0, 0, 0, 51, 51, 51, 63, 1, 87, 49,172,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,122, 67, 0, 0, 0, 0, 0, 0, 0, 65,
+ 0, 0, 0, 0, 0, 0,122, 67, 0, 0, 0, 0, 0, 0, 0, 65, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0,212, 0, 0, 0,
+ 16, 0, 0, 0,233, 3, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0,233, 3, 0, 0, 16, 0, 0, 0,212, 0, 0, 0,
+ 0, 0, 32, 65, 0, 0,128, 64, 0, 0,250, 70, 0, 0, 0, 66,205,204,204, 61, 0, 0, 32, 65, 9, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 68, 65, 84, 65,180, 2, 0, 0, 40,203,196, 8, 89, 0, 0, 0,
+ 1, 0, 0, 0, 8,206,196, 8, 88,202,196, 8, 1, 0, 0, 0, 51, 51, 51, 63, 1, 87, 49,172, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,128, 63, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,128, 63,228, 56,142, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,185,206,105, 62,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,111, 18, 3,187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,128, 63,102,102,102, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 38,140, 64,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255,255,249,195, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,128, 63, 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, 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, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,102,102,102, 65, 0, 0, 7, 0,
+ 40, 9,197, 8, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 3, 0, 0, 0, 0, 24,
+ 0, 0, 12, 66, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 10,215, 35, 60, 0, 0,250, 67, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 1, 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, 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, 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, 68, 65, 84, 65, 84, 1, 0, 0,
+ 8,206,196, 8, 96, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 40,203,196, 8, 5, 0, 0, 0, 51, 51, 51, 63, 1, 87, 49,172,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 65, 86, 69, 32, 84, 65, 82,
+ 71, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 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, 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, 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,116, 49, 46, 98,108,101,110,100, 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, 0, 0, 0, 0, 0, 0, 0, 0,
+ 8, 0, 0, 0, 2, 0, 0, 0, 57, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255,255, 0, 0, 0, 0, 0, 0, 0, 0,
+ 83, 82, 0, 0,116, 0, 0, 0,136,207,196, 8,109, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,232,163,196, 8, 0, 0, 0, 0,
+ 0, 0, 0, 0, 83, 82, 53, 45, 83, 99,114,105,112,116,105,110,103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 40,208,196, 8,104,210,196, 8,168,210,196, 8,152,214,196, 8,224,214,196, 8,176,236,196, 8,136,251,196, 8,
+ 0, 0,231, 3,143, 1,174, 4,232, 3, 32, 3, 1, 0, 5, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0, 40,208,196, 8,110, 0, 0, 0, 1, 0, 0, 0,104,208,196, 8,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0,104,208,196, 8,110, 0, 0, 0,
+ 1, 0, 0, 0,168,208,196, 8, 40,208,196, 8, 0, 0, 0, 0, 0, 0, 32, 3, 0, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0,
+168,208,196, 8,110, 0, 0, 0, 1, 0, 0, 0,232,208,196, 8,104,208,196, 8, 0, 0, 0, 0,232, 3, 32, 3, 0, 0, 0, 0,
+ 68, 65, 84, 65, 20, 0, 0, 0,232,208,196, 8,110, 0, 0, 0, 1, 0, 0, 0, 40,209,196, 8,168,208,196, 8, 0, 0, 0, 0,
+232, 3, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0, 40,209,196, 8,110, 0, 0, 0, 1, 0, 0, 0,104,209,196, 8,
+232,208,196, 8, 0, 0, 0, 0, 0, 0,212, 0, 0, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0,104,209,196, 8,110, 0, 0, 0,
+ 1, 0, 0, 0,168,209,196, 8, 40,209,196, 8, 0, 0, 0, 0, 0, 0, 6, 3, 0, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0,
+168,209,196, 8,110, 0, 0, 0, 1, 0, 0, 0,232,209,196, 8,104,209,196, 8, 0, 0, 0, 0,232, 3, 6, 3, 0, 0, 0, 0,
+ 68, 65, 84, 65, 20, 0, 0, 0,232,209,196, 8,110, 0, 0, 0, 1, 0, 0, 0, 40,210,196, 8,168,209,196, 8, 0, 0, 0, 0,
+156, 1,212, 0, 0, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0, 40,210,196, 8,110, 0, 0, 0, 1, 0, 0, 0,104,210,196, 8,
+232,209,196, 8, 0, 0, 0, 0,156, 1, 6, 3, 0, 0, 0, 0, 68, 65, 84, 65, 20, 0, 0, 0,104,210,196, 8,110, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 40,210,196, 8, 0, 0, 0, 0,156, 1, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,
+168,210,196, 8,111, 0, 0, 0, 1, 0, 0, 0,240,210,196, 8, 0, 0, 0, 0,104,208,196, 8,168,208,196, 8, 1, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,240,210,196, 8,111, 0, 0, 0, 1, 0, 0, 0, 56,211,196, 8,168,210,196, 8,
+104,208,196, 8,104,209,196, 8, 1, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0, 56,211,196, 8,111, 0, 0, 0,
+ 1, 0, 0, 0,128,211,196, 8,240,210,196, 8,168,208,196, 8,168,209,196, 8, 1, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+ 24, 0, 0, 0,128,211,196, 8,111, 0, 0, 0, 1, 0, 0, 0,200,211,196, 8, 56,211,196, 8,104,209,196, 8,168,209,196, 8,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,200,211,196, 8,111, 0, 0, 0, 1, 0, 0, 0, 16,212,196, 8,
+128,211,196, 8, 40,209,196, 8,232,209,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0, 16,212,196, 8,
+111, 0, 0, 0, 1, 0, 0, 0, 88,212,196, 8,200,211,196, 8,104,209,196, 8, 40,210,196, 8, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65, 24, 0, 0, 0, 88,212,196, 8,111, 0, 0, 0, 1, 0, 0, 0,160,212,196, 8, 16,212,196, 8,168,209,196, 8,
+ 40,210,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,160,212,196, 8,111, 0, 0, 0, 1, 0, 0, 0,
+232,212,196, 8, 88,212,196, 8,232,209,196, 8, 40,210,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,
+232,212,196, 8,111, 0, 0, 0, 1, 0, 0, 0, 48,213,196, 8,160,212,196, 8, 40,209,196, 8,104,209,196, 8, 1, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0, 48,213,196, 8,111, 0, 0, 0, 1, 0, 0, 0,120,213,196, 8,232,212,196, 8,
+ 40,208,196, 8, 40,209,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,120,213,196, 8,111, 0, 0, 0,
+ 1, 0, 0, 0,192,213,196, 8, 48,213,196, 8, 40,208,196, 8,104,210,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+ 24, 0, 0, 0,192,213,196, 8,111, 0, 0, 0, 1, 0, 0, 0, 8,214,196, 8,120,213,196, 8,232,208,196, 8,104,210,196, 8,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0, 8,214,196, 8,111, 0, 0, 0, 1, 0, 0, 0, 80,214,196, 8,
+192,213,196, 8,232,209,196, 8,104,210,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0, 80,214,196, 8,
+111, 0, 0, 0, 1, 0, 0, 0,152,214,196, 8, 8,214,196, 8, 40,210,196, 8,104,210,196, 8, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65, 24, 0, 0, 0,152,214,196, 8,111, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 80,214,196, 8,232,208,196, 8,
+168,209,196, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,204, 0, 0, 0,224,214,196, 8,113, 0, 0, 0, 1, 0, 0, 0,
+216,215,196, 8, 0, 0, 0, 0,104,209,196, 8,104,208,196, 8,168,208,196, 8,168,209,196, 8, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+232, 3, 0, 0, 7, 3, 0, 0, 32, 3, 0, 0, 0, 0, 0, 0,232, 3, 0, 0, 7, 3, 0, 0, 33, 3, 0, 0, 0, 0, 0, 0,
+232, 3, 0, 0, 32, 3, 0, 0, 32, 3, 0, 0, 0, 0, 0, 0, 1, 0, 7, 7,233, 3, 1, 0, 3, 0, 3, 1,196, 2, 0, 0,
+ 7, 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, 68, 65, 84, 65,204, 0, 0, 0,216,215,196, 8,113, 0, 0, 0, 1, 0, 0, 0,
+208,222,196, 8,224,214,196, 8, 40,209,196, 8,104,209,196, 8, 40,210,196, 8,232,209,196, 8, 0, 0, 0, 0,122,214,248, 61,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,186,252,191, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128,
+ 0, 0, 0,128,111, 18, 3,187, 0, 0, 0,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0,
+155, 1, 0, 0,213, 0, 0, 0, 5, 3, 0, 0, 0, 0, 0, 0,155, 1, 0, 0,213, 0, 0, 0,239, 0, 0, 0, 0, 0, 0, 0,
+155, 1, 0, 0,240, 0, 0, 0, 5, 3, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1,156, 1, 22, 2, 1, 0, 3, 0,251, 2, 0, 0,
+ 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,112,218,196, 8, 80,221,196, 8, 0, 0, 0, 0,
+ 0, 0, 0, 0,208,216,196, 8,160,217,196, 8, 68, 65, 84, 65,164, 0, 0, 0,208,216,196, 8,112, 0, 0, 0, 1, 0, 0, 0,
+160,217,196, 8, 0, 0, 0, 0, 84,114, 97,110,115,102,111,114,109, 32, 80,114,111,112,101,114,116,105,101,115, 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, 86,105,101,119, 51,100, 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,140, 0,210, 0, 62, 1,204, 0, 0, 0, 0, 0,162, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0,160,217,196, 8,112, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,208,216,196, 8,
+ 51, 68, 32, 86,105,101,119,112,111,114,116, 32,112,114,111,112,101,114,116,105,101,115, 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,
+ 86,105,101,119, 51,100, 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,
+ 8, 0, 8, 0, 62, 1,204, 0, 0, 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+180, 2, 0, 0,112,218,196, 8, 89, 0, 0, 0, 1, 0, 0, 0, 80,221,196, 8, 0, 0, 0, 0, 1, 0, 0, 0, 51, 51, 51, 63,
+ 1, 89, 46,124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63,122,214,248, 61, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,186,252,191, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,111, 18, 3,187,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 38,175, 3, 65, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,148,173, 42, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,255,255,249,195,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63,122,214,248, 61, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,186,252,191, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 0, 0, 0,128,111, 18, 3,187,
+ 0, 0, 0,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,148,173, 42, 65, 0, 0, 7, 0, 40, 9,197, 8, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0, 3, 0, 0, 0, 8, 24, 0, 0, 12, 66, 0, 0,128, 63, 0, 0,128, 63, 0, 0, 0, 0,205,204,204, 61,
+ 0, 0,250, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 1, 0,
+ 7, 0,175, 0, 0, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0, 0,232,197, 63, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,232,197, 63, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,232,197, 63, 64, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65, 84, 1, 0, 0, 80,221,196, 8, 96, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,112,218,196, 8,
+ 5, 0, 0, 0, 51, 51, 51, 63, 1, 89, 46,124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 20, 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, 47, 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, 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, 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, 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, 8, 0, 0, 0, 0, 0, 0, 0, 57, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,255,255, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,204, 0, 0, 0,208,222,196, 8,113, 0, 0, 0, 1, 0, 0, 0,
+176,236,196, 8,216,215,196, 8,104,210,196, 8, 40,210,196, 8,168,209,196, 8,232,208,196, 8, 0, 0, 0, 0, 1,184,157, 63,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,140, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 80, 1,128,191, 0, 0,128,191, 0, 0, 0, 0, 0, 0, 0, 0,225,215,163,188, 0, 0, 0, 0,157, 1, 0, 0,
+232, 3, 0, 0, 0, 0, 0, 0, 5, 3, 0, 0,157, 1, 0, 0,232, 3, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0,157, 1, 0, 0,
+232, 3, 0, 0, 27, 0, 0, 0, 5, 3, 0, 0, 0, 0, 0, 0, 1, 0, 9, 9, 76, 2,235, 2, 3, 0, 3, 0,165, 2, 0, 0,
+ 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,152,224,196, 8, 48,235,196, 8, 0, 0, 0, 0,
+ 0, 0, 0, 0,200,223,196, 8,200,223,196, 8, 68, 65, 84, 65,164, 0, 0, 0,200,223,196, 8,112, 0, 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 84,114, 97,110,115,102,111,114,109, 32, 80,114,111,112,101,114,116,105,101,115, 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, 73,112,111, 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, 33, 0,167, 0, 62, 1,204, 0, 0, 0, 0, 0,162, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65,120, 0, 0, 0,152,224,196, 8,100, 0, 0, 0, 1, 0, 0, 0, 64,225,196, 8, 0, 0, 0, 0,
+ 9, 0, 0, 0, 51, 51, 51, 63, 1, 89, 47,124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,240, 3,197, 8,
+ 0, 0, 0, 0, 62, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,205,204,204, 61, 5, 0, 0, 0, 17, 0, 0, 0,225, 2, 0, 0,227, 2, 0, 0,
+ 5, 0, 0, 0, 17, 0, 0, 0,207, 2, 0, 0,227, 2, 0, 0, 68, 65, 84, 65,184, 0, 0, 0, 64,225,196, 8, 98, 0, 0, 0,
+ 1, 0, 0, 0, 40,226,196, 8,152,224,196, 8, 6, 0, 0, 0, 51, 51, 51, 63, 1, 89, 47,124, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 67, 0, 0, 0, 0, 0, 0,128, 67, 0, 0,120,190, 0, 0,159, 63,
+ 0, 0,242,190, 0,128,188, 63, 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,124, 1, 0, 0, 0, 0, 0, 0,242, 1, 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,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+ 40, 1, 0, 0, 40,226,196, 8, 93, 0, 0, 0, 1, 0, 0, 0,128,227,196, 8, 64,225,196, 8, 2, 0, 0, 0, 51, 51, 51, 63,
+ 1, 89, 47,124, 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,122, 67,205,204,204,189,205,204,140, 63, 0, 0, 0, 0, 0, 0,122, 67, 0, 0,160,192, 0, 0,160, 64, 0, 0, 0, 0,
+ 16, 0, 0, 0, 0, 0, 0, 0,242, 1, 0, 0, 16, 0, 0, 0, 59, 1, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0,
+ 59, 1, 0, 0, 16, 0, 0, 0,242, 1, 0, 0, 10,215, 35, 60, 10,215, 35, 60, 0, 96,106, 70, 0, 0,122, 68, 0, 0, 0, 0,
+ 0, 0, 0, 0, 9, 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, 72, 12,197, 8, 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, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 79, 66, 1, 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,122, 67,205,204,204,189,205,204,140, 63, 68, 65, 84, 65,196, 0, 0, 0,
+128,227,196, 8, 97, 0, 0, 0, 1, 0, 0, 0,208,229,196, 8, 40,226,196, 8, 3, 0, 0, 0, 51, 51, 51, 63, 1, 89, 47,124,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,182, 67, 0, 0,209,195, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,182, 67, 0, 0,190,195, 0, 0, 0,181, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0,124, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0,124, 1, 0, 0, 0, 0, 0, 0,124, 1, 0, 0,
+ 0, 0,190,195, 0, 0,190,195, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0,128, 63, 1, 0, 1, 0, 1, 0, 1, 0,
+108, 1,124, 1, 0, 0, 0, 0,112,228,196, 8,120,229,196, 8, 0, 0,142, 3, 1, 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, 68, 65, 84, 65, 44, 0, 0, 0,112,228,196, 8,129, 0, 0, 0,
+ 1, 0, 0, 0,200,228,196, 8, 0, 0, 0, 0, 66, 79, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 65, 0, 0, 0, 0,
+ 0, 0, 0, 0,152, 15,197, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 44, 0, 0, 0,200,228,196, 8,129, 0, 0, 0,
+ 1, 0, 0, 0, 32,229,196, 8,112,228,196, 8, 66, 79, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,164,112, 61, 65, 0, 0, 0, 0,
+ 0, 0, 0, 0, 40, 9,197, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 44, 0, 0, 0, 32,229,196, 8,129, 0, 0, 0,
+ 1, 0, 0, 0,120,229,196, 8,200,228,196, 8, 66, 79, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,113, 61, 10,192, 0, 0, 0, 0,
+ 0, 0, 0, 0, 72, 12,197, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 44, 0, 0, 0,120,229,196, 8,129, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 32,229,196, 8, 69, 77, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21,174,143, 65, 0, 0, 0, 0,
+ 0, 0, 0, 0, 24, 22,197, 8, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,160, 0, 0, 0,208,229,196, 8,166, 0, 0, 0,
+ 1, 0, 0, 0,160,230,196, 8,128,227,196, 8, 11, 0, 0, 0, 51, 51, 51, 63, 1, 89, 47,124, 0, 0,128,192, 0, 0,122, 67,
+ 0, 0,128,192, 0, 0,127, 67, 0, 0,128,192, 0, 0, 72, 66, 0, 0,128,192, 0, 0,127, 67, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,124, 1, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0,124, 1, 0, 0,
+ 16, 0, 0, 0,124, 1, 0, 0, 0, 0,128, 63, 0,128,129, 67, 0, 0,250, 70, 0,128,129, 67,205,204,204, 61, 0, 0, 32, 65,
+ 8, 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, 68, 65, 84, 65,164, 0, 0, 0,160,230,196, 8, 99, 0, 0, 0, 1, 0, 0, 0,112,231,196, 8,208,229,196, 8,
+ 13, 0, 0, 0, 51, 51, 51, 63, 1, 89, 47,124, 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,128, 63, 0, 0,122, 68, 0, 0, 0, 0, 0, 0,122, 68, 0, 0,160,192, 0, 0,130, 66, 0, 0, 0, 0,
+ 0, 0,182, 67,108, 1, 0, 0,124, 1, 0, 0, 0, 0, 0, 0,124, 1, 0, 0,196, 0, 0, 0,108, 1, 0, 0, 0, 0, 0, 0,
+ 16, 0, 0, 0,196, 0, 0, 0,108, 1, 0, 0, 16, 0, 0, 0,124, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,122, 68,
+ 0, 0,122, 68,205,204,204, 61, 0, 0, 72, 66, 10, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+176, 0, 0, 0,112,231,196, 8,177, 0, 0, 0, 1, 0, 0, 0, 80,232,196, 8,160,230,196, 8, 12, 0, 0, 0, 51, 51, 51, 63,
+ 1, 89, 47,124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,191, 0, 0, 2, 66, 0, 0,128,193,
+ 0, 0,247, 67, 0, 0, 0,191, 0, 0, 2, 66, 0, 0,128,193, 0, 0,247, 67,108, 1, 0, 0,124, 1, 0, 0, 0, 0, 0, 0,
+ 14, 2, 0, 0,128, 0, 0, 0,108, 1, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0,128, 0, 0, 0,108, 1, 0, 0, 16, 0, 0, 0,
+ 14, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,250, 70, 0, 0,122, 68, 10,215, 35, 60, 0, 0, 72, 66, 10, 0, 0, 0,
+ 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65,180, 2, 0, 0, 80,232,196, 8, 89, 0, 0, 0, 1, 0, 0, 0, 48,235,196, 8,112,231,196, 8, 1, 0, 0, 0,
+ 51, 51, 51, 63, 1, 89, 47,124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32,193, 0, 0,128, 63, 0, 0,128, 63, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 65, 0, 0,128, 63, 1,184,157, 63, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,140, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 80, 1,128,191, 0, 0,128,191, 0, 0, 0, 0, 0, 0, 0, 0,184,175, 31, 65, 0, 0, 32, 65, 33,195, 79, 63, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,161, 14,106, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 29,254,249,195,125,254, 71,194, 0, 0, 0, 0, 0, 0, 0, 0,173,128,249, 67,138, 0, 72, 66, 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, 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, 0, 0, 0, 0,128, 63, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 65, 1, 0, 7, 0, 40, 9,197, 8, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 3, 0, 0, 0, 0, 24, 0, 0, 12, 66, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0,
+ 10,215, 35, 60, 0, 0,250, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 20, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 1, 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, 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, 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, 68, 65, 84, 65, 84, 1, 0, 0, 48,235,196, 8, 96, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 80,232,196, 8, 5, 0, 0, 0, 51, 51, 51, 63, 1, 89, 47,124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 20, 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,
+ 47, 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,
+ 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, 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, 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, 8, 0, 0, 0, 0, 0, 0, 0, 57, 0, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,255,255, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,204, 0, 0, 0,176,236,196, 8,113, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0,208,222,196, 8, 40,208,196, 8, 40,209,196, 8,232,209,196, 8,104,210,196, 8, 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, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,155, 1, 0, 0, 0, 0, 0, 0,211, 0, 0, 0, 0, 0, 0, 0,155, 1, 0, 0,185, 0, 0, 0,211, 0, 0, 0,
+ 0, 0, 0, 0,155, 1, 0, 0, 0, 0, 0, 0,184, 0, 0, 0, 0, 0, 0, 0, 2, 0, 4, 4,156, 1,185, 0, 3, 0, 3, 0,
+ 79, 1, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8,249,196, 8, 8,250,196, 8,
+ 0, 0, 0, 0, 0, 0, 0, 0,168,237,196, 8, 56,248,196, 8, 68, 65, 84, 65,164, 0, 0, 0,168,237,196, 8,112, 0, 0, 0,
+ 1, 0, 0, 0,120,238,196, 8, 0, 0, 0, 0, 76,105,110,107, 32, 97,110,100, 32, 77, 97,116,101,114,105, 97,108,115, 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, 69,100,105,116,105,110,103, 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, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0,120,238,196, 8,112, 0, 0, 0, 1, 0, 0, 0, 72,239,196, 8,
+168,237,196, 8, 77,101,115,104, 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, 69,100,105,116,105,110,103, 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, 70, 1, 0, 0, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65,164, 0, 0, 0, 72,239,196, 8,112, 0, 0, 0, 1, 0, 0, 0, 24,240,196, 8,120,238,196, 8, 65,110,105,109,
+ 32,115,101,116,116,105,110,103,115, 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, 79, 98,106,101,
+ 99,116, 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,
+ 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0,
+ 24,240,196, 8,112, 0, 0, 0, 1, 0, 0, 0,232,240,196, 8, 72,239,196, 8, 68,114, 97,119, 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, 79, 98,106,101, 99,116, 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, 70, 1, 0, 0, 62, 1,204, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0,232,240,196, 8,112, 0, 0, 0,
+ 1, 0, 0, 0,184,241,196, 8, 24,240,196, 8, 67,111,110,115,116,114, 97,105,110,116,115, 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, 79, 98,106,101, 99,116, 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,140, 2, 0, 0, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0,184,241,196, 8,112, 0, 0, 0, 1, 0, 0, 0,136,242,196, 8,
+232,240,196, 8, 69,102,102,101, 99,116,115, 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, 79, 98,106,101, 99,116, 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,210, 3, 0, 0,162, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65,164, 0, 0, 0,136,242,196, 8,112, 0, 0, 0, 1, 0, 0, 0, 88,243,196, 8,184,241,196, 8, 72,111,111,107,
+115, 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, 79, 98,106,101,
+ 99,116, 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, 70, 1, 0, 0,
+ 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24,240,196, 8, 68, 65, 84, 65,164, 0, 0, 0,
+ 88,243,196, 8,112, 0, 0, 0, 1, 0, 0, 0, 40,244,196, 8,136,242,196, 8, 80, 97,114,116,105, 99,108,101, 32, 73,110,116,
+101,114, 97, 99,116,105,111,110, 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, 79, 98,106,101, 99,116, 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,140, 2, 0, 0, 62, 1,204, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,232,240,196, 8, 68, 65, 84, 65,164, 0, 0, 0, 40,244,196, 8,112, 0, 0, 0,
+ 1, 0, 0, 0,248,244,196, 8, 88,243,196, 8, 83,111,102,116, 98,111,100,121, 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, 79, 98,106,101, 99,116, 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,140, 2, 0, 0, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,232,240,196, 8, 68, 65, 84, 65,164, 0, 0, 0,248,244,196, 8,112, 0, 0, 0, 1, 0, 0, 0,200,245,196, 8,
+ 40,244,196, 8, 79,117,116,112,117,116, 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, 82,101,110,100,101,114, 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, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65,164, 0, 0, 0,200,245,196, 8,112, 0, 0, 0, 1, 0, 0, 0,152,246,196, 8,248,244,196, 8, 82,101,110,100,
+101,114, 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, 82,101,110,100,
+101,114, 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, 70, 1, 0, 0,
+ 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0,
+152,246,196, 8,112, 0, 0, 0, 1, 0, 0, 0,104,247,196, 8,200,245,196, 8, 65,110,105,109, 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, 82,101,110,100,101,114, 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,140, 2, 0, 0, 62, 1,204, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0,104,247,196, 8,112, 0, 0, 0,
+ 1, 0, 0, 0, 56,248,196, 8,152,246,196, 8, 70,111,114,109, 97,116, 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, 82,101,110,100,101,114, 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,210, 3, 0, 0, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,164, 0, 0, 0, 56,248,196, 8,112, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+104,247,196, 8, 83, 99,114,105,112,116,108,105,110,107,115, 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, 83, 99,114,105,112,116, 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, 62, 1,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65,212, 0, 0, 0, 8,249,196, 8, 94, 0, 0, 0, 1, 0, 0, 0, 8,250,196, 8, 0, 0, 0, 0, 4, 0, 0, 0,
+ 51, 51, 51, 63, 1, 89, 48,124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
+ 0, 0, 0,193, 0, 0,163, 67, 0, 0, 0,193, 0, 0,104, 67, 0, 0, 0,193, 35,159, 3, 68, 0, 0, 0,193, 0, 0,104, 67,
+ 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,128, 67, 0, 0, 40, 66, 0, 0,200, 68, 0, 0,225, 67,
+ 0, 0, 0, 63,225,122,180, 63, 0, 0, 1, 0, 1, 0, 1, 0,156, 1,185, 0, 0, 0, 0, 0, 5, 0,255,255, 0, 0, 5, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,150, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 84, 1, 0, 0, 8,250,196, 8, 96, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 8,249,196, 8, 5, 0, 0, 0, 51, 51, 51, 63, 1, 89, 48,124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 20, 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,
+ 47, 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,
+ 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, 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, 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, 8, 0, 0, 0, 0, 0, 0, 0, 57, 0, 2, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,255,255, 0, 0, 0, 0, 0, 0, 0, 0, 83, 67, 0, 0,244, 3, 0, 0,136,251,196, 8, 87, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 67, 83, 99,101,110,101, 0,116, 97,103,101,
+ 0, 97,105,110, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 40, 9,197, 8,160, 2,197, 8, 0, 0, 0, 0,
+ 0, 0, 0, 0,168,255,196, 8, 56, 0,197, 8,168,255,196, 8, 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, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,205,204,204, 61, 0, 0, 0, 0,128, 0,197, 8, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 49,197, 8, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0,
+250, 0,100, 0,100, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,128, 2,224, 1, 60, 0, 32, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 5, 0, 0, 0,100, 0,141, 0, 32, 3, 88, 2,
+100, 0,100, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 4, 0, 0, 0, 90, 0, 16, 0, 23, 0, 1, 0, 0, 0,128, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 8, 0, 25, 0, 10, 0, 0, 0, 0, 0, 0, 64, 0, 0,128, 63, 0, 0,128, 63, 0, 0,128, 63, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0,205,204, 76, 63,102,102,102, 63, 0, 0,128, 63, 0, 0,128, 64,
+ 0, 0, 32, 65, 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, 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, 47, 47, 98, 97, 99,107, 98,117,102, 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, 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, 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, 47,116,109,112, 47, 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, 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, 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, 47, 47,102,116,121,112,101, 0, 64, 38, 35, 0, 0, 0, 0, 0, 64, 94, 0, 0, 64, 38, 94, 0, 0, 0, 35, 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, 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, 0, 0, 0,
+ 0, 0, 0, 0, 68,172, 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, 72,226,187, 8, 1, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 28, 0, 0, 0,
+168,255,196, 8, 79, 0, 0, 0, 1, 0, 0, 0,240,255,196, 8, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
+128, 2,108, 1, 72, 12,197, 8, 68, 65, 84, 65, 28, 0, 0, 0,240,255,196, 8, 79, 0, 0, 0, 1, 0, 0, 0, 56, 0,197, 8,
+168,255,196, 8, 1, 0, 0, 0, 2, 0, 0, 0, 0, 4, 0, 0, 78, 3,159, 1,152, 15,197, 8, 68, 65, 84, 65, 28, 0, 0, 0,
+ 56, 0,197, 8, 79, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,240,255,196, 8, 1, 0, 0, 0, 3, 0, 0, 0, 0, 4, 0, 0,
+251, 3, 33, 0, 40, 9,197, 8, 68, 65, 84, 65, 40, 0, 0, 0,128, 0,197, 8, 78, 0, 0, 0, 1, 0, 0, 0, 44, 1, 0, 0,
+ 1, 0, 2, 0, 1, 0, 2, 0, 0, 0, 1, 0,244, 1,200, 0,100, 0, 20, 0, 16, 39, 0, 0,205,204,204, 61, 0, 0,240, 65,
+ 0, 0, 0, 64, 68, 65, 84, 65, 28, 0, 0, 0, 48, 49,197, 8, 86, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 90, 0, 9, 0,
+ 1, 0, 0, 0, 0, 0,128, 63,111, 18,131, 58, 32, 0, 32, 0, 32, 0, 0, 0, 67, 65, 0, 0,116, 0, 0, 0,216, 0,197, 8,
+ 23, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 65, 67, 97,109,101,114, 97,
+ 0, 97,109,101,114, 97, 46, 48, 48, 49, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0,205,204, 76, 62,
+ 0, 0, 0, 0,205,204,204, 61, 0, 0,200, 66, 0, 0, 12, 66,161, 14,234, 64, 0, 0, 0, 63, 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, 76, 65, 0, 0,
+252, 0, 0, 0,120, 1,197, 8, 31, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 76, 65, 83,112,111,116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 32, 0, 0, 0, 0, 0, 0,128, 63, 0, 0,128, 63, 0, 0,128, 63, 0, 0,128, 63, 0, 0,128, 63,247,255,239, 65,
+ 0, 0,150, 66,154,153, 25, 62, 0, 0,128, 63, 0, 0, 0, 0, 0, 0,128, 63, 64, 11, 3, 0, 46, 26,128, 63, 25, 4,240, 65,
+ 0, 0, 52, 66, 0, 0,128, 63, 0, 0, 64, 64, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0,128, 63,
+ 0, 0,128, 63, 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, 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, 87, 79, 0, 0, 32, 1, 0, 0,160, 2,197, 8, 77, 0, 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 87, 79, 87,111,114,108,100, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128,174,103, 61,112, 29, 98, 62,
+205,204,204, 62, 0, 0, 0, 0,205,204,204, 61,205,204,204, 61,205,204,204, 61, 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,128, 63, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0,
+205,204, 28, 65, 0, 0, 0, 0, 0, 0, 0, 0, 2, 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, 64, 0, 0, 0, 0, 0, 0,112, 65, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 65, 0, 0, 0, 0, 0, 0,128, 63,205,204, 76, 61, 0, 0, 5, 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, 0, 0, 0, 0, 0, 0,
+ 84, 88, 0, 0,100, 0, 0, 0,240, 3,197, 8, 21, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 84, 88, 84,101,120,116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 1, 0, 0, 0,128, 4,197, 8,128, 4,197, 8,128, 4,197, 8,128, 4,197, 8,
+ 0, 0, 0, 0, 0, 0, 0, 0,248, 4,197, 8,255,255,255,255, 0, 4, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 24, 0, 0, 0,
+128, 4,197, 8, 20, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,200, 4,197, 8, 0, 0, 0, 0, 0, 0, 0, 0,
+ 69, 69, 82, 70, 68, 65, 84, 65, 4, 0, 0, 0,200, 4,197, 8, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 79, 66, 0, 0,
+244, 2, 0, 0, 40, 9,197, 8, 71, 0, 0, 0, 1, 0, 0, 0, 72, 12,197, 8, 0, 0, 0, 0, 1, 89, 70,108, 0, 0, 0, 0,
+ 79, 66, 67, 97,109,101,114, 97, 0, 97,109,101,114, 97, 46, 48, 48, 49, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 11, 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,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,216, 0,197, 8, 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,110,101,239, 64,150, 62,208,192, 78,255,170, 64, 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,128, 63, 0, 0,128, 63, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 42,254,141, 63,192, 57, 49, 60, 34,159, 80, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0,222,149, 47, 63,
+ 53, 70, 58, 63,222, 56, 49,188, 0, 0, 0, 0, 86,126,162,190,227,251,159, 62, 55, 53,101, 63, 0, 0, 0, 0, 7,165, 39, 63,
+149, 84, 28,191, 51,247,227, 62, 0, 0, 0, 0,110,101,239, 64,150, 62,208,192, 78,255,170, 64, 0, 0,128, 63, 0, 0,128, 63,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0,128, 63,
+157,190,215, 49,167,170, 4, 52, 0, 0, 0,128,129,116,157,178, 1, 0,128, 63, 33, 69, 15, 51, 0, 0, 0,128, 73,254, 67, 51,
+243, 97,106, 49, 0, 0,128, 63, 0, 0, 0,128, 3, 0, 64, 52,183,164,157, 39, 0, 0,128, 53, 0, 0,128, 63, 1, 0, 0, 0,
+ 0, 4, 0, 0, 0, 0, 0, 0, 5, 0, 1, 0, 0, 0, 0, 0, 79, 66, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0,100, 0,
+ 0, 0, 0, 0, 0, 0,128, 63, 0, 0,128, 63, 6, 41,100, 63, 0, 0,128, 63,205,204,204, 62, 0, 0, 0, 0, 6, 41,100, 63,
+ 0, 0, 0, 0, 2, 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, 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,128, 63, 0, 0,128, 63, 0, 0,128, 63, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 79, 66, 0, 0,244, 2, 0, 0, 72, 12,197, 8, 71, 0, 0, 0, 1, 0, 0, 0,152, 15,197, 8, 40, 9,197, 8,
+ 1, 89,123, 92, 0, 0, 0, 0, 79, 66, 67,117, 98,101, 0,112,104,101,114,101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 22,197, 8, 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,104, 15,197, 8, 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,128, 63, 0, 0,128, 63, 0, 0,128, 63,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,128, 63, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,128, 63,222,149, 47, 63, 52, 70, 58, 63,179, 56, 49,188, 0, 0, 0,128, 86,126,162,190,227,251,159, 62, 56, 53,101, 63,
+ 0, 0, 0,128, 7,165, 39, 63,149, 84, 28,191, 50,247,227, 62, 0, 0, 0,128,110,101,239, 64,151, 62,208,192, 77,255,170, 64,
+ 0, 0,128, 63, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 68, 0, 1, 0, 2, 0, 0, 0, 0, 0, 79, 66, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,100, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0,128, 63, 10,215, 35, 61, 0, 0,128, 63,205,204,204, 62,
+ 0, 0, 0, 0,205,204,204, 61, 0, 0, 0, 0, 4, 0, 1, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,128, 63, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0,128, 63, 0, 0,128, 63, 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, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 24,218,193, 8,200, 29,197, 8, 68, 65, 84, 65, 4, 0, 0, 0,104, 15,197, 8, 0, 0, 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 79, 66, 0, 0,244, 2, 0, 0,152, 15,197, 8, 71, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 72, 12,197, 8,
+ 1, 89,121, 92, 0, 0, 0, 0, 79, 66, 76, 97,109,112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0, 10, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,120, 1,197, 8, 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,154,112,130, 64,183,178,128, 63,112,236,188, 64, 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,128, 63, 0, 0,128, 63, 0, 0,128, 63,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,229,123, 38, 63, 87, 43, 98, 61,229,229,238, 63, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0,
+ 0, 0, 0, 0, 54,236,148,190, 25,134,116, 63,236, 13, 98,189, 0, 0, 0, 0,221,102, 69,191, 57,174, 76,190, 34,194, 26, 63,
+ 0, 0, 0, 0, 37,255, 16, 63,241,161, 95, 62,164,111, 75, 63, 0, 0, 0, 0,154,112,130, 64,183,178,128, 63,112,236,188, 64,
+ 0, 0,128, 63, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,128, 63, 53,236,148,190,222,102, 69,191, 37,255, 16, 63, 0, 0, 0,128, 24,134,116, 63, 57,174, 76,190,240,161, 95, 62,
+ 0, 0, 0,128,235, 13, 98,189, 34,194, 26, 63,166,111, 75, 63, 0, 0, 0,128,208, 19, 13, 63,234, 65,102,190, 10, 10,231,192,
+ 0, 0,128, 63, 1, 0, 0, 0, 0, 4, 0, 0, 0, 0, 68, 0, 5, 0, 1, 0, 0, 0, 0, 0, 79, 66, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 1, 0,100, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0,128, 63, 10,215, 35, 61, 0, 0,128, 63,205,204,204, 62,
+ 0, 0, 0, 0,205,204,204, 61, 0, 0, 0, 0, 4, 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, 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, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0,128, 63, 0, 0,128, 63, 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, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 77, 65, 0, 0,156, 1, 0, 0,184, 18,197, 8, 33, 0, 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 77, 65, 77, 97,116,101,114,105, 97,108, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,205,204, 76, 63,205,204, 76, 63,205,204, 76, 63,
+ 0, 0,128, 63, 0, 0,128, 63, 0, 0,128, 63, 0, 0,128, 63, 0, 0,128, 63, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0,128, 63, 0, 0,128, 63, 0, 0, 0, 0, 0, 0,128, 63,205,204, 76, 63,
+ 0, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,160, 63, 0, 0, 0, 0, 0, 0,160, 63,
+ 0, 0, 0, 0, 2, 0, 2, 0, 50, 0, 0, 6, 3, 0, 1, 3, 0, 0, 0, 0, 1, 0, 4, 0, 12, 0, 4, 0, 0, 0, 0, 63,
+ 0, 0,128, 63, 0, 0,128, 63, 0, 0,128, 63, 0, 0,128, 63, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 3, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0,128, 64, 0, 0, 0, 63,205,204,204, 61, 0, 0, 0, 63,
+205,204,204, 61,205,204,204, 61, 0, 0,128, 63, 1, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,128, 63, 0, 0,128, 63,128, 20,197, 8, 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, 63, 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, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+ 88, 0, 0, 0,128, 20,197, 8, 25, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 21,197, 8,
+ 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0,128, 63, 0, 0,128, 63, 16, 0, 0, 0,
+ 0, 0,128, 63, 0, 0, 0, 0, 0, 0,128, 63, 0, 0,128, 63, 0, 0,128, 63, 0, 0,128, 63, 0, 0, 0, 63, 0, 0,128, 63,
+205,204, 76, 62, 0, 0, 0, 0, 84, 69, 0, 0,228, 0, 0, 0, 8, 21,197, 8, 30, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 69, 84,101,120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 62, 0, 0,160, 64, 0, 0,128, 63, 0, 0,128, 63, 0, 0,128, 63,
+ 0, 0,128, 63, 0, 0,128, 63, 0, 0,128, 63, 0, 0,128, 63, 0, 0, 0, 64, 0, 0, 0, 64, 0, 0,128, 63, 0, 0,128, 63,
+ 0, 0,128, 63, 0, 0,128, 63, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 64, 0, 0, 0, 0,
+ 2, 0, 0, 0, 0, 0, 0, 0, 5, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 0, 0,128, 63,
+ 1, 0, 1, 0, 3, 0, 0, 0, 0, 0, 0, 0,205,204,204, 60, 0, 0, 0, 0, 1, 0, 2, 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,
+ 77, 69, 0, 0,188, 0, 0, 0, 24, 22,197, 8, 46, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 77, 69, 67,117, 98,101, 0,112,104,101,114,101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0,232, 31,194, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23,197, 8, 88, 0,194, 8,
+ 0, 0, 0, 0, 0, 0, 0, 0,216, 21,194, 8,120, 28,194, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 12, 0, 0, 0, 6, 0, 0, 0, 1, 0, 0, 0, 0, 0,128, 51, 0, 0, 0,180,
+ 0, 0, 0, 0, 4, 0,128, 63, 4, 0,128, 63, 0, 0,128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 30, 0, 4, 0, 1, 0, 1, 0, 1, 0, 0, 0, 68, 65, 84, 65, 4, 0, 0, 0, 0, 23,197, 8, 0, 0, 0, 0,
+ 1, 0, 0, 0,184, 18,197, 8, 68, 65, 84, 65,160, 0, 0, 0,216, 21,194, 8, 51, 0, 0, 0, 8, 0, 0, 0, 0, 0,128, 63,
+255,255,127, 63, 0, 0,128,191,230, 73,230, 73, 26,182, 3,255, 0, 0,128, 63, 0, 0,128,191, 0, 0,128,191,230, 73, 26,182,
+ 26,182, 3,255, 1, 0,128,191,253,255,127,191, 0, 0,128,191, 26,182, 26,182, 26,182, 3,255,250,255,127,191, 3, 0,128, 63,
+ 0, 0,128,191, 26,182,230, 73, 26,182, 3,255, 4, 0,128, 63,247,255,127, 63, 0, 0,128, 63,230, 73,230, 73,230, 73, 3,255,
+245,255,127, 63, 5, 0,128,191, 0, 0,128, 63,230, 73, 26,182,230, 73, 3,255, 3, 0,128,191,250,255,127,191, 0, 0,128, 63,
+ 26,182, 26,182,230, 73, 3,255,255,255,127,191, 0, 0,128, 63, 0, 0,128, 63, 26,182,230, 73,230, 73, 3,255, 68, 65, 84, 65,
+144, 0, 0, 0,120, 28,194, 8, 48, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 35, 0, 0, 0, 0, 0,
+ 3, 0, 0, 0, 0, 0, 35, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 35, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 35, 0,
+ 1, 0, 0, 0, 5, 0, 0, 0, 0, 0, 35, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 35, 0, 2, 0, 0, 0, 6, 0, 0, 0,
+ 0, 0, 35, 0, 3, 0, 0, 0, 7, 0, 0, 0, 0, 0, 35, 0, 4, 0, 0, 0, 5, 0, 0, 0, 0, 0, 35, 0, 4, 0, 0, 0,
+ 7, 0, 0, 0, 0, 0, 35, 0, 5, 0, 0, 0, 6, 0, 0, 0, 0, 0, 35, 0, 6, 0, 0, 0, 7, 0, 0, 0, 0, 0, 35, 0,
+ 68, 65, 84, 65,120, 0, 0, 0, 88, 0,194, 8, 47, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0,
+ 3, 0, 0, 0, 0, 0, 0, 2, 4, 0, 0, 0, 7, 0, 0, 0, 6, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0,
+ 4, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 2, 1, 0, 0, 0, 5, 0, 0, 0, 6, 0, 0, 0, 2, 0, 0, 0,
+ 0, 0, 0, 2, 2, 0, 0, 0, 6, 0, 0, 0, 7, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0,
+ 3, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 2, 71, 76, 79, 66, 24, 0, 0, 0,160,240,255,191,114, 0, 0, 0, 1, 0, 0, 0,
+ 96, 40,196, 8,136,251,196, 8, 1, 0, 0, 1, 0, 0, 0, 0,128, 32, 4, 0, 0, 0, 0, 0, 85, 83, 69, 82,168, 7, 0, 0,
+224,226,172, 8,108, 0, 0, 0, 1, 0, 0, 0, 33, 24, 0, 0, 63, 2, 0, 0, 5, 0, 0, 0, 47,116,109,112, 47, 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, 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, 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, 47, 47, 0, 85,115,101,114,115,
+ 47,116,111,110, 47, 68,101,115,107,116,111,112, 47, 0, 45,112,111,119,101,114,112, 99, 47, 98,105,110, 47, 98,108,101,110,100,
+101,114, 46, 97,112,112, 47, 67,111,110,116,101,110,116,115, 47, 82,101,115,111,117,114, 99,101, 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, 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, 47, 47, 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, 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, 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, 47, 47, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 47, 47, 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, 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, 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, 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, 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, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+ 3, 0, 0, 0, 48, 52, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 8, 0, 0, 11, 0, 0, 0, 0, 0, 64, 0,
+ 5, 0, 2, 0, 0,104, 97,108,107, 98,111, 97,114,100, 46,116,116,102, 0, 55, 46, 53, 46, 48, 45,112,111,119,101,114,112, 99,
+ 47, 98,105,110, 47, 98,108,101,110,100,101,114, 46, 97,112,112, 47, 67,111,110,116,101,110,116,115, 47, 82,101,115,111,117,114,
+ 99,101,115, 47, 46, 98,102,111,110,116, 46,116,116,102, 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, 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, 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,200, 32,197, 8,216, 40,197, 8, 32, 0, 0, 0, 5, 0, 5, 0, 1, 0, 0, 0, 0, 0, 0, 0,205,204, 76, 63,
+205,204, 76, 63,205,204, 76, 63, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0,128, 63, 30, 90,100,191,
+154,153,153, 62,102,102,102, 63, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 31,250,254, 62, 9, 0, 0, 63,156,153, 25, 63,
+ 0, 0, 0, 0,205,204, 76, 62,205,204, 76, 62,205,204, 76, 62, 0, 0,128, 63, 44,135, 22, 63, 32,133,235, 62,184,243,125, 62,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,195, 73, 76, 63, 42,135, 86, 63, 0, 0,128, 63, 0, 0, 0, 0, 1, 43,135, 61,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 63, 16, 47, 93, 62, 58,180,200,190, 24, 47, 93,190, 0, 0, 0, 0, 14, 0, 0, 0,
+ 25, 0, 15, 0,120, 0, 0, 0, 60, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,224, 7, 0, 0,200, 32,197, 8,
+106, 0, 0, 0, 1, 0, 0, 0,216, 40,197, 8, 0, 0, 0, 0, 68,101,102, 97,117,108,116, 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,160,160,160,255,160,160,160,255,173,160,147,255,138,158,161,255,
+161,161,174,255,161,153,167,255,144,144,144,255,144,144,144,255,198,119,119,255,160,160,160,255, 0, 0, 0,255,255,255,255,255,
+210,210,210,255,218,218,218,255,127,127,127,255, 0, 0, 0,255,255,255,255,255, 1, 0, 0, 0,180,180,180,255, 0, 0, 0,255,
+255,255,255,255,195,195,195,255,255,255,255, 40,160,160,160,100,127,112,112,100, 0, 0, 0, 0, 92, 92, 92,255, 0, 0, 0,255,
+255,136,255,255, 0, 0, 0, 40,255,187,255,255,255,255,255,255,255,112,255,255,255,255,112,255, 0, 0, 0,255,176,176, 48,255,
+230,150, 50,255, 75, 75, 75,255, 0, 50,150, 30,200,100,200, 60,255,138, 48,255, 34,221,221,255,200,200,200,255, 80,200,255, 80,
+ 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+115,115,115,255, 0, 0, 0,255,255,255,255,255,195,195,195,255,165,165,165,127,160,160,160,100,127,112,112,100, 0, 0, 0, 0,
+ 92, 92, 92,255, 0, 0, 0,255,255,136,255,255, 0, 0, 0, 40,255,187,255,255,255,255,255,255,255,112,255,255,255,255,112,255,
+ 0, 0, 0,255,176,176, 48,255,230,150, 50,255, 75, 75, 75,255, 0, 50,150, 30,200,100,200, 60,255,138, 48,255, 34,221,221,255,
+200,200,200,255, 80,200,255, 80, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,128,128,128,255, 0, 0, 0,255,255,255,255,255,182,182,182,255,165,165,165,127,160,160,160,100,
+127,112,112,100,160,160,208,255, 92, 92, 92,255, 0, 0, 0,255,255,136,255,255, 0, 0, 0, 40,255,187,255,255,255,255,255,255,
+255,112,255,255,255,255,112,255, 0, 0, 0,255,176,176, 48,255,230,150, 50,255, 75, 75, 75,255, 0, 50,150, 30,200,100,200, 60,
+255,138, 48,255, 34,221,221,255,200,200,200,255, 80,200,255, 80, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,120,120,120,255, 0, 0, 0,255,255,255,255,255,195,195,195,255,
+255,255,255,150,172,172,172,100,112,112,112,100, 96,192, 64,255, 94, 94, 94,255, 0, 0, 0,255,255,136,255,255, 0, 0, 0, 40,
+255,187,255,255,255,255,255,255,255,112,255,255,255,255,112,255, 0, 0, 0,255,176,176, 48,255,230,150, 50,255, 75, 75, 75,255,
+ 0, 50,150, 30,200,100,200, 60,255,138, 48,255, 34,221,221,255,200,200,200,255, 80,200,255, 80, 0, 0, 0, 0, 0, 0, 0, 0,
+ 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,153,153,153,255, 0, 0, 0,255,
+255,255,255,255,195,195,195,255,165,165,165,127,160,160,160,100,127,112,112,100, 0, 0, 0, 0, 92, 92, 92,255, 0, 0, 0,255,
+255,136,255,255, 0, 0, 0, 40,255,187,255,255,255,255,255,255,255,112,255,255,255,255,112,255, 0, 0, 0,255,176,176, 48,255,
+230,150, 50,255, 75, 75, 75,255, 0, 50,150, 30,200,100,200, 60,255,138, 48,255, 34,221,221,255,200,200,200,255, 80,200,255, 80,
+ 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+153,153,153,255, 0, 0, 0,255,255,255,255,255,195,195,195,255,165,165,165,127,173,173,173,255,127,112,112,100, 0, 0, 0, 0,
+140,140,140,255, 0, 0, 0,255,255,136,255,255, 0, 0, 0, 40,255,187,255,255,255,255,255,255,255,112,255,255,255,255,112,255,
+ 0, 0, 0,255,176,176, 48,255,230,150, 50,255, 75, 75, 75,255, 0, 50,150, 30,200,100,200, 60,255,138, 48,255, 34,221,221,255,
+200,200,200,255, 80,200,255, 80, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,116,116,116,255, 0, 0, 0,255,255,255,255,255,182,182,182,255,165,165,165,127,172,172,172,255,
+ 84, 44, 31,100, 17, 27, 60,100, 94, 94, 94,255, 0, 0, 0,255,255,136,255,255, 0, 0, 0, 40,255,187,255,255,255,255,255,255,
+255,112,255,255,255,255,112,255, 0, 0, 0,255,176,176, 48,255,230,150, 50,255, 75, 75, 75,255,166,166,166,255,200,100,200, 60,
+255,138, 48,255, 34,221,221,255,200,200,200,255, 80,200,255, 80, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,116,116,116,255, 0, 0, 0,255,255,255,255,255,182,182,182,255,
+165,165,165,127,172,172,172,255, 84, 44, 31,100, 17, 27, 60,100, 94, 94, 94,255, 0, 0, 0,255,255,136,255,255, 0, 0, 0, 40,
+255,187,255,255,255,255,255,255,255,112,255,255,255,255,112,255, 0, 0, 0,255,176,176, 48,255,230,150, 50,255, 75, 75, 75,255,
+ 0, 50,150, 30,200,100,200, 60,255,138, 48,255, 34,221,221,255,200,200,200,255, 80,200,255, 80,228,156,198,255,255,255,170,255,
+ 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,115,115,115,255, 0, 0, 0,255,
+255,255,255,255,195,195,195,255,165,165,165,127,160,160,160,100,127,112,112,100, 0, 0, 0, 0, 92, 92, 92,255, 0, 0, 0,255,
+255,136,255,255, 0, 0, 0, 40,255,187,255,255,255,255,255,255,255,112,255,255,255,255,112,255, 0, 0, 0,255,176,176, 48,255,
+230,150, 50,255, 75, 75, 75,255, 0, 50,150, 30,200,100,200, 60,255,138, 48,255, 34,221,221,255,200,200,200,255, 80,200,255, 80,
+ 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 53, 53, 53,255, 0, 0, 0,255,255,255,255,255,195,195,195,255,165,165,165,127,160,160,160,100,127,112,112,100, 0, 0, 0, 0,
+ 92, 92, 92,255, 0, 0, 0,255,255,136,255,255, 0, 0, 0, 40,255,187,255,255,255,255,255,255,255,112,255,255,255,255,112,255,
+ 0, 0, 0,255,176,176, 48,255,230,150, 50,255, 75, 75, 75,255, 0, 50,150, 40,200,100,200, 80,255,138, 48,255, 34,221,221,255,
+200,200,200,255, 80,200,255, 80, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,110,110,110,255, 0, 0, 0,255,255,255,255,255,195,195,195,255,165,165,165,127,170,170,186,255,
+127,112,112,100, 0, 0, 0, 0, 92, 92, 92,255, 0, 0, 0,255,255,136,255,255, 0, 0, 0, 40,255,187,255,255,255,255,255,255,
+255,112,255,255,255,255,112,255, 0, 0, 0,255,176,176, 48,255,230,150, 50,255, 75, 75, 75,255, 0, 50,150, 30,200,100,200, 60,
+255,138, 48,255, 34,221,221,255,200,200,200,255, 80,200,255, 80, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,153,153,153,255, 0, 0, 0,255,255,255,255,255,195,195,195,255,
+165,165,165,127,143,143,143,255,198,119,119,255,255, 0, 0,255, 92, 92, 92,255, 0, 0, 0,255,255,136,255,255, 0, 0, 0, 40,
+255,187,255,255,255,255,255,255,255,112,255,255,255,255,112,255, 0, 0, 0,255,176,176, 48,255,230,150, 50,255, 75, 75, 75,255,
+ 0, 50,150, 30,200,100,200, 60,255,138, 48,255, 34,221,221,255,200,200,200,255, 80,200,255, 80, 0, 0, 0, 0, 0, 0, 0, 0,
+ 2, 4, 0, 0,100, 0, 0,255, 0, 0,200,255,128, 0, 80,255, 95, 95, 0,255, 0,100, 50,255,153,153,153,255, 0, 0, 0,255,
+255,255,255,255,195,195,195,255,165,165,165,127,160,160,160,100,127,112,112,100, 0, 0, 0, 0, 92, 92, 92,255, 0, 0, 0,255,
+255,136,255,255, 0, 0, 0, 40,255,187,255,255,255,255,255,255,255,112,255,255,255,255,112,255, 0, 0, 0,255,176,176, 48,255,
+230,150, 50,255, 75, 75, 75,255, 0, 50,150, 30,200,100,200, 60,255,138, 48,255, 34,221,221,255,200,200,200,255, 80,200,255, 80,
+ 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+153,153,153,255, 0, 0, 0,255,255,255,255,255,195,195,195,255,165,165,165,127,173,173,173,255,127,112,112,100, 0, 0, 0, 0,
+140,140,140,255, 0, 0, 0,255,255,136,255,255, 0, 0, 0, 40,255,187,255,255,255,255,255,255,255,112,255,255,255,255,112,255,
+ 0, 0, 0,255,176,176, 48,255,230,150, 50,255, 75, 75, 75,255, 0, 50,150, 30,200,100,200, 60,255,138, 48,255, 34,221,221,255,
+200,200,200,255, 80,200,255, 80, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,224, 7, 0, 0,216, 40,197, 8,106, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+200, 32,197, 8, 82,111,117,110,100,101,100, 0, 0,101,119, 32, 85,115,101,114, 32, 84,104,101,109,101, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,176,176,176,255,107,107,107,255,177,177,177,255,178,178,178,255,143,143,143,255,143,143,143,255,
+107,107,107,255,198,119,119,255,143,143,143,255, 0, 0, 0,255,255,255,255,255, 0, 0, 0,111, 0, 0, 33, 83,255,130, 0,255,
+255,255,255,255, 0, 0, 0,255, 2, 0, 0, 0,107,107,107,255, 0, 0, 0,255,255,255,255,255,107,107,107,255,175,175,175, 51,
+160,160,160,100,127,112,112,100, 0, 0, 0, 0, 88, 88, 88,255, 0, 0, 0,255,255,136,255,255, 0, 0, 0, 0,255,187,255,255,
+255,255,255,255,255,112,255,255,255,255,112,255, 0, 0, 0,255,144,144, 48,255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50,150, 30,
+200,100,200, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,107,107,107,255, 0, 0, 0,255,255,255,255,255,
+107,107,107,255, 0, 0, 0, 51,160,160,160,100,127,112,112,100, 0, 0, 0, 0,143,143,143,255, 0, 0, 0,255,217,217,217,255,
+ 0, 0, 0, 40,255,255,255,255,255,130, 0,255, 0, 0, 0,255,255,130, 0,255, 0, 0, 0,255,255,255,255,255,230,150, 50,255,
+ 0, 0, 0, 0,255,255,255, 10,255,130, 0, 60,255,138, 48,255, 34,221,221,255,200,200,200,255, 80,200,255, 80, 0, 0, 0, 0,
+ 0, 0, 0, 0, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,107,107,107,255,
+ 0, 0, 0,255,255,255,255,255,107,107,107,255,165,165,165,150,160,160,160,100,127,112,112,100,255,130, 0,255, 88, 88, 88,255,
+ 0, 0, 0,255,255,136,255,255, 0, 0, 0, 0,255,187,255,255,255,255,255,255,255,112,255,255,255,255,112,255, 0, 0, 0,255,
+144,144, 48,255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50,150, 30,200,100,200, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,107,107,107,255, 0, 0, 0,255,255,255,255,255,107,107,107,255,107,107,107,150,107,107,107,100,143,143,143,100,
+ 96,192, 64,255, 94, 94, 94,255, 0, 0, 0,255,255,136,255,255, 0, 0, 0, 0,255,187,255,255,255,255,255,255,255,255,255,255,
+255,130, 0,255, 0, 0, 0,255,144,144, 48,255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50,150, 30,200,100,200, 60, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,107,107,107,255, 0, 0, 0,255,255,255,255,255,107,107,107,255,165,165,165,150,
+160,160,160,100,127,112,112,100, 0, 0, 0, 0, 88, 88, 88,255, 0, 0, 0,255,255,136,255,255, 0, 0, 0, 0,255,187,255,255,
+255,255,255,255,255,112,255,255,255,255,112,255, 0, 0, 0,255,144,144, 48,255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50,150, 30,
+200,100,200, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,158,158,158,255, 0, 0, 0,255,255,255,255,255,
+158,158,158,255,165,165,165,150,140,140,140,255,127,112,112,100, 0, 0, 0, 0,112,112, 96,255, 0, 0, 0,255,255,136,255,255,
+ 0, 0, 0, 0,255,187,255,255,255,255,255,255,255,112,255,255,255,255,112,255, 0, 0, 0,255,144,144, 48,255, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 50,150, 30,200,100,200, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,107,107,107,255,
+ 0, 0, 0,255,255,255,255,255,107,107,107,255,165,165,165,150,107,107,107,255,178,178,178,100,255,130, 0,100, 94, 94, 94,255,
+ 0, 0, 0,255,255,136,255,255, 0, 0, 0, 0,255,187,255,255,255,255,255,255,255,112,255,255,255,255,112,255, 0, 0, 0,255,
+144,144, 48,255, 0, 0, 0, 0, 0, 0, 0, 0,143,143,143,255,200,100,200, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,107,107,107,255, 0, 0, 0,255,255,255,255,255,143,143,143,255,165,165,165,150,107,107,107,255,178,178,178,100,
+255,130, 0,100, 94, 94, 94,255, 0, 0, 0,255,255,136,255,255, 0, 0, 0, 0,255,187,255,255,255,255,255,255,255,112,255,255,
+255,255,112,255, 0, 0, 0,255,144,144, 48,255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50,150, 30,200,100,200, 60, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,228,156,198,255,255,255,170,255, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,107,107,107,255, 0, 0, 0,255,255,255,255,255,107,107,107,255,165,165,165,150,
+160,160,160,100,127,112,112,100, 0, 0, 0, 0, 88, 88, 88,255, 0, 0, 0,255,255,136,255,255, 0, 0, 0, 0,255,187,255,255,
+255,255,255,255,255,112,255,255,255,255,112,255, 0, 0, 0,255,144,144, 48,255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50,150, 30,
+200,100,200, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 53, 53,255, 0, 0, 0,255,255,255,255,255,
+195,195,195,255,165,165,165,150,160,160,160,100,127,112,112,100, 0, 0, 0, 0, 88, 88, 88,255, 0, 0, 0,255,255,136,255,255,
+ 0, 0, 0, 0,255,187,255,255,255,255,255,255,255,112,255,255,255,255,112,255, 0, 0, 0,255,144,144, 48,255, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 50,150, 30,200,100,200, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,107,107,107,255,
+ 0, 0, 0,255,255,255,255,255,195,195,195,255,165,165,165,150,143,143,143,255,127,112,112,100, 0, 0, 0, 0, 88, 88, 88,255,
+ 0, 0, 0,255,255,136,255,255, 0, 0, 0, 0,255,187,255,255,255,255,255,255,255,112,255,255,255,255,112,255, 0, 0, 0,255,
+144,144, 48,255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50,150, 30,200,100,200, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,153,153,153,255, 0, 0, 0,255,255,255,255,255,153,153,153,255,165,165,165,150,143,143,143,255,198,119,119,255,
+255, 0, 0,255, 88, 88, 88,255, 0, 0, 0,255,255,136,255,255, 0, 0, 0, 0,255,187,255,255,255,255,255,255,255,112,255,255,
+255,255,112,255, 0, 0, 0,255,144,144, 48,255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50,150, 30,200,100,200, 60, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,100, 0, 0,255, 0, 0,200,255,
+128, 0, 80,255, 95, 95, 0,255, 0,100, 50,255,107,107,107,255, 0, 0, 0,255,255,255,255,255,107,107,107,255,165,165,165,150,
+160,160,160,100,127,112,112,100, 0, 0, 0, 0, 88, 88, 88,255, 0, 0, 0,255,255,136,255,255, 0, 0, 0, 0,255,187,255,255,
+255,255,255,255,255,112,255,255,255,255,112,255, 0, 0, 0,255,144,144, 48,255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50,150, 30,
+200,100,200, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,158,158,158,255, 0, 0, 0,255,255,255,255,255,
+158,158,158,255,165,165,165,150,140,140,140,255,127,112,112,100, 0, 0, 0, 0,112,112, 96,255, 0, 0, 0,255,255,136,255,255,
+ 0, 0, 0, 0,255,187,255,255,255,255,255,255,255,112,255,255,255,255,112,255, 0, 0, 0,255,144,144, 48,255, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 50,150, 30,200,100,200, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 78, 65, 49,
+ 60,100, 0, 0, 16,170,197, 8, 0, 0, 0, 0, 1, 0, 0, 0, 83, 68, 78, 65, 78, 65, 77, 69,196, 5, 0, 0, 42,110,101,120,
+116, 0, 42,112,114,101,118, 0, 42,102,105,114,115,116, 0, 42,108, 97,115,116, 0,120, 0,121, 0,122, 0,119, 0,120,109,105,
+110, 0,120,109, 97,120, 0,121,109,105,110, 0,121,109, 97,120, 0, 42,110,101,119,105,100, 0, 42,108,105, 98, 0,110, 97,109,
+101, 91, 50, 52, 93, 0,117,115, 0,102,108, 97,103, 0,112, 97,100, 0,105,100, 0, 42,105,100, 98,108,111, 99,107, 0, 42,102,
+105,108,101,100, 97,116, 97, 0,110, 97,109,101, 91, 49, 54, 48, 93, 0,116,111,116, 0, 99,117,114,118,101, 0, 99,117,114, 0,
+ 98,108,111, 99,107,116,121,112,101, 0,115,104,111,119,107,101,121, 0,112,111,115, 0, 99,117,114,118, 97,108, 0,116,121,112,
+101, 0, 97,100,114, 99,111,100,101, 0,116,111,116,101,108,101,109, 0, 42,100, 97,116, 97, 0, 42,119,101,105,103,104,116,115,
+ 0,110, 97,109,101, 91, 51, 50, 93, 0,118,103,114,111,117,112, 91, 51, 50, 93, 0,115,108,105,100,101,114,109,105,110, 0,115,
+108,105,100,101,114,109, 97,120, 0, 42,114,101,102,107,101,121, 0,101,108,101,109,115,116,114, 91, 51, 50, 93, 0,101,108,101,
+109,115,105,122,101, 0, 98,108,111, 99,107, 0, 42,105,112,111, 0, 42,102,114,111,109, 0,116,111,116,107,101,121, 0,115,108,
+117,114,112,104, 0, 42, 42,115, 99,114,105,112,116,115, 0, 42,102,108, 97,103, 0, 97, 99,116,115, 99,114,105,112,116, 0,116,
+111,116,115, 99,114,105,112,116, 0, 42,108,105,110,101, 0, 42,102,111,114,109, 97,116, 0,108,101,110, 0, 98,108,101,110, 0,
+ 42,110, 97,109,101, 0,102,108, 97,103,115, 0,110,108,105,110,101,115, 0,108,105,110,101,115, 0, 42, 99,117,114,108, 0, 42,
+115,101,108,108, 0, 99,117,114, 99, 0,115,101,108, 99, 0, 42,117,110,100,111, 95, 98,117,102, 0,117,110,100,111, 95,112,111,
+115, 0,117,110,100,111, 95,108,101,110, 0, 42, 99,111,109,112,105,108,101,100, 0,115,105,122,101, 0,115,101,101,107, 0,112,
+ 97,115,115,101,112, 97,114,116, 97,108,112,104, 97, 0,112, 97,100, 49, 0, 99,108,105,112,115,116, 97, 0, 99,108,105,112,101,
+110,100, 0,108,101,110,115, 0,111,114,116,104,111, 95,115, 99, 97,108,101, 0,100,114, 97,119,115,105,122,101, 0, 89, 70, 95,
+100,111,102,100,105,115,116, 0, 89, 70, 95, 97,112,101,114,116,117,114,101, 0, 89, 70, 95, 98,107,104,116,121,112,101, 0, 89,
+ 70, 95, 98,107,104, 98,105, 97,115, 0, 89, 70, 95, 98,107,104,114,111,116, 0,115, 99,114,105,112,116,108,105,110,107, 0, 42,
+ 97,110,105,109, 0, 42,105, 98,117,102, 0, 42,109,105,112,109, 97,112, 91, 49, 48, 93, 0,111,107, 0,108, 97,115,116,102,114,
+ 97,109,101, 0,108, 97,115,116,113,117, 97,108,105,116,121, 0,116,112, 97,103,101,102,108, 97,103, 0,116,111,116, 98,105,110,
+100, 0,120,114,101,112, 0,121,114,101,112, 0,116,119,115,116, 97, 0,116,119,101,110,100, 0, 98,105,110,100, 99,111,100,101,
+ 0, 42,114,101,112, 98,105,110,100, 0, 42,112, 97, 99,107,101,100,102,105,108,101, 0,108, 97,115,116,117,112,100, 97,116,101,
+ 0,108, 97,115,116,117,115,101,100, 0, 97,110,105,109,115,112,101,101,100, 0,114,101,115,101,114,118,101,100, 49, 0,114,101,
+115,101,114,118,101,100, 50, 0,116,101,120, 99,111, 0,109, 97,112,116,111, 0,109, 97,112,116,111,110,101,103, 0, 98,108,101,
+110,100,116,121,112,101, 0, 42,111, 98,106,101, 99,116, 0, 42,116,101,120, 0,112,114,111,106,120, 0,112,114,111,106,121, 0,
+112,114,111,106,122, 0,109, 97,112,112,105,110,103, 0,111,102,115, 91, 51, 93, 0,115,105,122,101, 91, 51, 93, 0,116,101,120,
+102,108, 97,103, 0, 99,111,108,111,114,109,111,100,101,108, 0,114, 0,103, 0, 98, 0,107, 0,100,101,102, 95,118, 97,114, 0,
+ 99,111,108,102, 97, 99, 0,110,111,114,102, 97, 99, 0,118, 97,114,102, 97, 99, 0,100,105,115,112,102, 97, 99, 0,119, 97,114,
+112,102, 97, 99, 0, 42,104, 97,110,100,108,101, 0, 42,112,110, 97,109,101, 0, 42,115,116,110, 97,109,101,115, 0,115,116,121,
+112,101,115, 0,118, 97,114,115, 0, 42,118, 97,114,115,116,114, 0, 42,114,101,115,117,108,116, 0, 42, 99,102,114, 97, 0,100,
+ 97,116, 97, 91, 51, 50, 93, 0, 40, 42,100,111,105,116, 41, 40, 41, 0, 40, 42, 99, 97,108,108, 98, 97, 99,107, 41, 40, 41, 0,
+118,101,114,115,105,111,110, 0, 97, 0,105,112,111,116,121,112,101, 0,100, 97,116, 97, 91, 49, 54, 93, 0, 42,105,109, 97, 0,
+ 42, 99,117, 98,101, 91, 54, 93, 0,105,109, 97,116, 91, 52, 93, 91, 52, 93, 0,115,116,121,112,101, 0,110,111,116,108, 97,121,
+ 0, 99,117, 98,101,114,101,115, 0,100,101,112,116,104, 0,114,101, 99, 97,108, 99, 0,108, 97,115,116,115,105,122,101, 0,110,
+111,105,115,101,115,105,122,101, 0,116,117,114, 98,117,108, 0, 98,114,105,103,104,116, 0, 99,111,110,116,114, 97,115,116, 0,
+114,102, 97, 99, 0,103,102, 97, 99, 0, 98,102, 97, 99, 0,102,105,108,116,101,114,115,105,122,101, 0,109,103, 95, 72, 0,109,
+103, 95,108, 97, 99,117,110, 97,114,105,116,121, 0,109,103, 95,111, 99,116, 97,118,101,115, 0,109,103, 95,111,102,102,115,101,
+116, 0,109,103, 95,103, 97,105,110, 0,100,105,115,116, 95, 97,109,111,117,110,116, 0,110,115, 95,111,117,116,115, 99, 97,108,
+101, 0,118,110, 95,119, 49, 0,118,110, 95,119, 50, 0,118,110, 95,119, 51, 0,118,110, 95,119, 52, 0,118,110, 95,109,101,120,
+112, 0,118,110, 95,100,105,115,116,109, 0,118,110, 95, 99,111,108,116,121,112,101, 0,110,111,105,115,101,100,101,112,116,104,
+ 0,110,111,105,115,101,116,121,112,101, 0,110,111,105,115,101, 98, 97,115,105,115, 0,110,111,105,115,101, 98, 97,115,105,115,
+ 50, 0,105,109, 97,102,108, 97,103, 0, 99,114,111,112,120,109,105,110, 0, 99,114,111,112,121,109,105,110, 0, 99,114,111,112,
+120,109, 97,120, 0, 99,114,111,112,121,109, 97,120, 0,120,114,101,112,101, 97,116, 0,121,114,101,112,101, 97,116, 0,101,120,
+116,101,110,100, 0, 99,104,101, 99,107,101,114,100,105,115,116, 0,110, 97, 98,108, 97, 0,102,114, 97,109,101,115, 0,111,102,
+102,115,101,116, 0,115,102,114, 97, 0,102,105,101, 95,105,109, 97, 0, 42,112,108,117,103,105,110, 0, 42, 99,111, 98, 97, 0,
+ 42,101,110,118, 0,102,114, 97,100,117,114, 91, 52, 93, 91, 50, 93, 0,109,111,100,101, 0,116,111,116,101,120, 0,101,110,101,
+114,103,121, 0,100,105,115,116, 0,115,112,111,116,115,105,122,101, 0,115,112,111,116, 98,108,101,110,100, 0,104, 97,105,110,
+116, 0, 97,116,116, 49, 0, 97,116,116, 50, 0, 98,117,102,115,105,122,101, 0,115, 97,109,112, 0,115,104, 97,100,115,112,111,
+116,115,105,122,101, 0, 98,105, 97,115, 0,115,111,102,116, 0,114, 97,121, 95,115, 97,109,112, 0,114, 97,121, 95,115, 97,109,
+112,121, 0,114, 97,121, 95,115, 97,109,112,122, 0,114, 97,121, 95,115, 97,109,112, 95,116,121,112,101, 0, 97,114,101, 97, 95,
+115,104, 97,112,101, 0, 97,114,101, 97, 95,115,105,122,101, 0, 97,114,101, 97, 95,115,105,122,101,121, 0, 97,114,101, 97, 95,
+115,105,122,101,122, 0,116,101,120, 97, 99,116, 0,115,104, 97,100,104, 97,108,111,115,116,101,112, 0, 89, 70, 95,110,117,109,
+112,104,111,116,111,110,115, 0, 89, 70, 95,110,117,109,115,101, 97,114, 99,104, 0, 89, 70, 95,112,104,100,101,112,116,104, 0,
+ 89, 70, 95,117,115,101,113,109, 99, 0, 89, 70, 95, 98,117,102,115,105,122,101, 0, 89, 70, 95,112, 97,100, 0, 89, 70, 95, 99,
+ 97,117,115,116,105, 99, 98,108,117,114, 0, 89, 70, 95,108,116,114, 97,100,105,117,115, 0, 89, 70, 95,103,108,111,119,105,110,
+116, 0, 89, 70, 95,103,108,111,119,111,102,115, 0, 89, 70, 95,112, 97,100, 51, 0, 89, 70, 95,103,108,111,119,116,121,112,101,
+ 0, 89, 70, 95,112, 97,100, 50, 0, 42,109,116,101,120, 91, 49, 48, 93, 0,108, 97,121, 0,115,112,101, 99,114, 0,115,112,101,
+ 99,103, 0,115,112,101, 99, 98, 0,109,105,114,114, 0,109,105,114,103, 0,109,105,114, 98, 0, 97,109, 98,114, 0, 97,109, 98,
+ 98, 0, 97,109, 98,103, 0, 97,109, 98, 0,101,109,105,116, 0, 97,110,103, 0,115,112,101, 99,116,114, 97, 0,114, 97,121, 95,
+109,105,114,114,111,114, 0, 97,108,112,104, 97, 0,114,101,102, 0,115,112,101, 99, 0,122,111,102,102,115, 0, 97,100,100, 0,
+116,114, 97,110,115,108,117, 99,101,110, 99,121, 0,102,114,101,115,110,101,108, 95,109,105,114, 0,102,114,101,115,110,101,108,
+ 95,109,105,114, 95,105, 0,102,114,101,115,110,101,108, 95,116,114, 97, 0,102,114,101,115,110,101,108, 95,116,114, 97, 95,105,
+ 0,102,105,108,116,101,114, 0,114, 97,121, 95,100,101,112,116,104, 0,114, 97,121, 95,100,101,112,116,104, 95,116,114, 97, 0,
+104, 97,114, 0,115,101,101,100, 49, 0,115,101,101,100, 50, 0,109,111,100,101, 50, 0,102,108, 97,114,101, 99, 0,115,116, 97,
+114, 99, 0,108,105,110,101, 99, 0,114,105,110,103, 99, 0,104, 97,115,105,122,101, 0,102,108, 97,114,101,115,105,122,101, 0,
+115,117, 98,115,105,122,101, 0,102,108, 97,114,101, 98,111,111,115,116, 0,115,116,114, 97,110,100, 95,115,116, 97, 0,115,116,
+114, 97,110,100, 95,101,110,100, 0,115,116,114, 97,110,100, 95,101, 97,115,101, 0,114,103, 98,115,101,108, 0,112,114, 95,116,
+121,112,101, 0,112,114, 95, 98, 97, 99,107, 0,112,114, 95,108, 97,109,112, 0,115,101,112,116,101,120, 0,112, 97,100, 52, 0,
+112, 97,100, 53, 0,100,105,102,102, 95,115,104, 97,100,101,114, 0,115,112,101, 99, 95,115,104, 97,100,101,114, 0,114,111,117,
+103,104,110,101,115,115, 0,114,101,102,114, 97, 99, 0,112, 97,114, 97,109, 91, 52, 93, 0,114,109,115, 0,100, 97,114,107,110,
+101,115,115, 0, 42,114, 97,109,112, 95, 99,111,108, 0, 42,114, 97,109,112, 95,115,112,101, 99, 0,114, 97,109,112,105,110, 95,
+ 99,111,108, 0,114, 97,109,112,105,110, 95,115,112,101, 99, 0,114, 97,109,112, 98,108,101,110,100, 95, 99,111,108, 0,114, 97,
+109,112, 98,108,101,110,100, 95,115,112,101, 99, 0,114, 97,109,112, 95,115,104,111,119, 0,112, 97,100, 51, 0,114, 97,109,112,
+102, 97, 99, 95, 99,111,108, 0,114, 97,109,112,102, 97, 99, 95,115,112,101, 99, 0,102,114,105, 99,116,105,111,110, 0,102,104,
+ 0,114,101,102,108,101, 99,116, 0,102,104,100,105,115,116, 0,120,121,102,114,105, 99,116, 0,100,121,110, 97,109,111,100,101,
+ 0,112, 97,100, 50, 0, 89, 70, 95, 97,114, 0, 89, 70, 95, 97,103, 0, 89, 70, 95, 97, 98, 0, 89, 70, 95,100,115, 99, 97,108,
+101, 0, 89, 70, 95,100,112,119,114, 0, 89, 70, 95,100,115,109,112, 0, 89, 70, 95,112,114,101,115,101,116, 0, 89, 70, 95,100,
+106,105,116, 0,110, 97,109,101, 91, 50, 53, 54, 93, 0,115, 99, 97,108,101, 0, 42, 98, 98, 0,105, 49, 0,106, 49, 0,107, 49,
+ 0,105, 50, 0,106, 50, 0,107, 50, 0,115,101,108, 99,111,108, 49, 0,115,101,108, 99,111,108, 50, 0,113,117, 97,116, 91, 52,
+ 93, 0,101,120,112,120, 0,101,120,112,121, 0,101,120,112,122, 0,114, 97,100, 0,114, 97,100, 50, 0,115, 0, 42,109, 97,116,
+ 0, 42,105,109, 97,116, 0,101,108,101,109,115, 0,100,105,115,112, 0, 42, 42,109, 97,116, 0,116,111,116, 99,111,108, 0,108,
+111, 99, 91, 51, 93, 0,114,111,116, 91, 51, 93, 0,119,105,114,101,115,105,122,101, 0,114,101,110,100,101,114,115,105,122,101,
+ 0,116,104,114,101,115,104, 0,118,101, 99, 91, 51, 93, 91, 51, 93, 0, 97,108,102, 97, 0,119,101,105,103,104,116, 0,104, 49,
+ 0,104, 50, 0,102, 49, 0,102, 50, 0,102, 51, 0,104,105,100,101, 0,118,101, 99, 91, 52, 93, 0,109, 97,116, 95,110,114, 0,
+112,110,116,115,117, 0,112,110,116,115,118, 0,114,101,115,111,108,117, 0,114,101,115,111,108,118, 0,111,114,100,101,114,117,
+ 0,111,114,100,101,114,118, 0,102,108, 97,103,117, 0,102,108, 97,103,118, 0, 42,107,110,111,116,115,117, 0, 42,107,110,111,
+116,115,118, 0, 42, 98,112, 0, 42, 98,101,122,116, 0, 99,104, 97,114,105,100,120, 0,107,101,114,110, 0,104, 0,110,117,114,
+ 98, 0, 42, 98,101,118,111, 98,106, 0, 42,116, 97,112,101,114,111, 98,106, 0, 42,116,101,120,116,111,110, 99,117,114,118,101,
+ 0, 42,112, 97,116,104, 0, 42,107,101,121, 0, 98,101,118, 0,112, 97,116,104,108,101,110, 0, 98,101,118,114,101,115,111,108,
+ 0,119,105,100,116,104, 0,101,120,116, 49, 0,101,120,116, 50, 0,115,112, 97, 99,101,109,111,100,101, 0,115,112, 97, 99,105,
+110,103, 0,108,105,110,101,100,105,115,116, 0,115,104,101, 97,114, 0,102,115,105,122,101, 0,119,111,114,100,115,112, 97, 99,
+101, 0,117,108,112,111,115, 0,117,108,104,101,105,103,104,116, 0,120,111,102, 0,121,111,102, 0,108,105,110,101,119,105,100,
+116,104, 0, 42,115,116,114, 0,102, 97,109,105,108,121, 91, 50, 52, 93, 0, 42,118,102,111,110,116, 0, 42,118,102,111,110,116,
+ 98, 0, 42,118,102,111,110,116,105, 0, 42,118,102,111,110,116, 98,105, 0,115,101,112, 99,104, 97,114, 0,116,111,116, 98,111,
+120, 0, 97, 99,116, 98,111,120, 0, 42,116, 98, 0,115,101,108,115,116, 97,114,116, 0,115,101,108,101,110,100, 0, 42,115,116,
+114,105,110,102,111, 0, 99,117,114,105,110,102,111, 0, 42,111, 98, 0,110, 97,109,101, 91, 49, 50, 56, 93, 0,109, 97,120,114,
+ 99,116, 0,116,111,116,114, 99,116, 0,118, 97,114,116,121,112,101, 0,116,111,116,118,101,114,116, 0,105,112,111, 0,101,120,
+116,114, 97,112, 0,114,116, 0, 98,105,116,109, 97,115,107, 0, 42,100,114,105,118,101,114, 0, 42,116,112, 97,103,101, 0,117,
+118, 91, 52, 93, 91, 50, 93, 0, 99,111,108, 91, 52, 93, 0,116,114, 97,110,115,112, 0,116,105,108,101, 0,117,110,119,114, 97,
+112, 0,101,102,102,101, 99,116, 0, 42,109,102, 97, 99,101, 0, 42,116,102, 97, 99,101, 0, 42,100,102, 97, 99,101, 0, 42,109,
+118,101,114,116, 0, 42,109,101,100,103,101, 0, 42,100,118,101,114,116, 0, 42,109, 99,111,108, 0, 42,109,115,116,105, 99,107,
+121, 0, 42,116,101,120, 99,111,109,101,115,104, 0, 42,111, 99, 0, 42,115,117,109,111,104, 97,110,100,108,101, 0,116,111,116,
+101,100,103,101, 0,116,111,116,102, 97, 99,101, 0, 99,117, 98,101,109, 97,112,115,105,122,101, 0,115,109,111,111,116,104,114,
+101,115,104, 0,115,117, 98,100,105,118, 0,115,117, 98,100,105,118,114, 0,115,117, 98,115,117,114,102,116,121,112,101, 0,118,
+ 49, 0,118, 50, 0,118, 51, 0,118, 52, 0,101,100, 99,111,100,101, 0, 99,114,101, 97,115,101, 0,100,101,102, 95,110,114, 0,
+ 42,100,119, 0,116,111,116,119,101,105,103,104,116, 0, 99,111, 91, 51, 93, 0,110,111, 91, 51, 93, 0, 99,111, 91, 50, 93, 0,
+ 42,101,114,114,111,114, 0,109,111,100,105,102,105,101,114, 0,115,117, 98,100,105,118, 84,121,112,101, 0,108,101,118,101,108,
+115, 0,114,101,110,100,101,114, 76,101,118,101,108,115, 0, 42,101,109, 67, 97, 99,104,101, 0, 42,109, 67, 97, 99,104,101, 0,
+115,116, 97,114,116, 0,108,101,110,103,116,104, 0,114, 97,110,100,111,109,105,122,101, 0,115,101,101,100, 0, 97,120,105,115,
+ 0,116,111,108,101,114, 97,110, 99,101, 0,112,101,114, 99,101,110,116, 0,102, 97, 99,101, 67,111,117,110,116, 0,115,116, 97,
+114,116,120, 0,115,116, 97,114,116,121, 0,104,101,105,103,104,116, 0,110, 97,114,114,111,119, 0,115,112,101,101,100, 0,100,
+ 97,109,112, 0,116,105,109,101,111,102,102,115, 0,108,105,102,101,116,105,109,101, 0,100,101,102,111,114,109,102,108, 97,103,
+ 0,112, 97,114,101,110,116,105,110,118, 91, 52, 93, 91, 52, 93, 0, 99,101,110,116, 91, 51, 93, 0,102, 97,108,108,111,102,102,
+ 0, 42,105,110,100,101,120, 97,114, 0,116,111,116,105,110,100,101,120, 0,102,111,114, 99,101, 0,111,112,101,114, 97,116,105,
+111,110, 0,112,110,116,115,119, 0,111,112,110,116,115,117, 0,111,112,110,116,115,118, 0,111,112,110,116,115,119, 0,116,121,
+112,101,117, 0,116,121,112,101,118, 0,116,121,112,101,119, 0,102,117, 0,102,118, 0,102,119, 0,100,117, 0,100,118, 0,100,
+119, 0, 42,100,101,102, 0,118,101, 99, 91, 56, 93, 91, 51, 93, 0,100,118,101, 99, 91, 51, 93, 0,109, 97,120, 0, 42, 42,111,
+ 98, 0,112, 97,114,116,121,112,101, 0,112, 97,114, 49, 0,112, 97,114, 50, 0,112, 97,114, 51, 0,112, 97,114,115,117, 98,115,
+116,114, 91, 51, 50, 93, 0, 42,112, 97,114,100, 97,116, 97, 0, 42,112, 97,114,101,110,116, 0, 42,116,114, 97, 99,107, 0, 42,
+ 97, 99,116,105,111,110, 0, 42,112,111,115,101, 0, 99,111,110,115,116,114, 97,105,110,116, 67,104, 97,110,110,101,108,115, 0,
+110,101,116,119,111,114,107, 0,100,101,102, 98, 97,115,101, 0,109,111,100,105,102,105,101,114,115, 0,100,108,111, 99, 91, 51,
+ 93, 0,111,114,105,103, 91, 51, 93, 0,100,115,105,122,101, 91, 51, 93, 0,100,114,111,116, 91, 51, 93, 0,100,113,117, 97,116,
+ 91, 52, 93, 0,111, 98,109, 97,116, 91, 52, 93, 91, 52, 93, 0, 99,111,108, 98,105,116,115, 0,116,114, 97,110,115,102,108, 97,
+103, 0,105,112,111,102,108, 97,103, 0,116,114, 97, 99,107,102,108, 97,103, 0,117,112,102,108, 97,103, 0,110,108, 97,102,108,
+ 97,103, 0,112,114,111,116,101, 99,116,102,108, 97,103, 0,105,112,111,119,105,110, 0,115, 99, 97,102,108, 97,103, 0,115, 99,
+ 97,118,105,115,102,108, 97,103, 0, 98,111,117,110,100,116,121,112,101, 0,100,117,112,111,110, 0,100,117,112,111,102,102, 0,
+100,117,112,115,116, 97, 0,100,117,112,101,110,100, 0,115,102, 0, 99,116,105,109,101, 0,109, 97,115,115, 0,100, 97,109,112,
+105,110,103, 0,105,110,101,114,116,105, 97, 0,102,111,114,109,102, 97, 99,116,111,114, 0,115,111,102,116,116,105,109,101, 0,
+114,100, 97,109,112,105,110,103, 0,115,105,122,101,102, 97, 99, 0,100,116, 0,100,116,120, 0, 97, 99,116, 99,111,108, 0,112,
+114,111,112, 0,115,101,110,115,111,114,115, 0, 99,111,110,116,114,111,108,108,101,114,115, 0, 97, 99,116,117, 97,116,111,114,
+115, 0, 98, 98,115,105,122,101, 91, 51, 93, 0,100,102,114, 97,115, 0, 97, 99,116,100,101,102, 0,103, 97,109,101,102,108, 97,
+103, 0,103, 97,109,101,102,108, 97,103, 50, 0,115,111,102,116,102,108, 97,103, 0, 97,110,105,115,111,116,114,111,112,105, 99,
+ 70,114,105, 99,116,105,111,110, 91, 51, 93, 0, 99,111,110,115,116,114, 97,105,110,116,115, 0,110,108, 97,115,116,114,105,112,
+115, 0,104,111,111,107,115, 0, 42,112,100, 0, 42,115,111,102,116, 0, 42,108,105,102,101, 0,108, 98,117,102, 0,112,111,114,
+116, 0,102,108,117,105,100,115,105,109, 70,108, 97,103, 0,115,104, 97,112,101,110,114, 0,115,104, 97,112,101,102,108, 97,103,
+ 0, 42,102,108,117,105,100,115,105,109, 83,101,116,116,105,110,103,115, 0, 42,100,101,114,105,118,101,100, 68,101,102,111,114,
+109, 0, 42,100,101,114,105,118,101,100, 70,105,110, 97,108, 0,109, 97,116, 91, 52, 93, 91, 52, 93, 0, 99,117,114,105,110,100,
+101,120, 0, 97, 99,116,105,118,101, 0,100,101,102,108,101, 99,116, 0,102,111,114, 99,101,102,105,101,108,100, 0,112,100,101,
+102, 95,100, 97,109,112, 0,112,100,101,102, 95,114,100, 97,109,112, 0,112,100,101,102, 95,112,101,114,109, 0,102, 95,115,116,
+114,101,110,103,116,104, 0,102, 95,112,111,119,101,114, 0,109, 97,120,100,105,115,116, 0,112,100,101,102, 95,115, 98,100, 97,
+109,112, 0,112,100,101,102, 95,115, 98,105,102,116, 0,112,100,101,102, 95,115, 98,111,102,116, 0,116,111,116,112,111,105,110,
+116, 0,116,111,116,115,112,114,105,110,103, 0, 42, 98,112,111,105,110,116, 0, 42, 98,115,112,114,105,110,103, 0,110,111,100,
+101,109, 97,115,115, 0,103,114, 97,118, 0,109,101,100,105, 97,102,114,105, 99,116, 0,114,107,108,105,109,105,116, 0,112,104,
+121,115,105, 99,115, 95,115,112,101,101,100, 0,103,111, 97,108,115,112,114,105,110,103, 0,103,111, 97,108,102,114,105, 99,116,
+ 0,109,105,110,103,111, 97,108, 0,109, 97,120,103,111, 97,108, 0,100,101,102,103,111, 97,108, 0,118,101,114,116,103,114,111,
+117,112, 0,105,110,115,112,114,105,110,103, 0,105,110,102,114,105, 99,116, 0,101,102,114, 97, 0,105,110,116,101,114,118, 97,
+108, 0, 42, 42,107,101,121,115, 0,116,111,116,112,111,105,110,116,107,101,121, 0,115,104,111,119, 95, 97,100,118, 97,110, 99,
+101,100,111,112,116,105,111,110,115, 0,114,101,115,111,108,117,116,105,111,110,120,121,122, 0,112,114,101,118,105,101,119,114,
+101,115,120,121,122, 0,114,101, 97,108,115,105,122,101, 0,103,117,105, 68,105,115,112,108, 97,121, 77,111,100,101, 0,114,101,
+110,100,101,114, 68,105,115,112,108, 97,121, 77,111,100,101, 0,118,105,115, 99,111,115,105,116,121, 86, 97,108,117,101, 0,118,
+105,115, 99,111,115,105,116,121, 77,111,100,101, 0,118,105,115, 99,111,115,105,116,121, 69,120,112,111,110,101,110,116, 0,103,
+114, 97,118,120, 0,103,114, 97,118,121, 0,103,114, 97,118,122, 0, 97,110,105,109, 83,116, 97,114,116, 0, 97,110,105,109, 69,
+110,100, 0,103,115,116, 97,114, 0,109, 97,120, 82,101,102,105,110,101, 0,105,110,105, 86,101,108,120, 0,105,110,105, 86,101,
+108,121, 0,105,110,105, 86,101,108,122, 0, 42,111,114,103, 77,101,115,104, 0, 42,109,101,115,104, 83,117,114,102, 97, 99,101,
+ 0, 42,109,101,115,104, 66, 66, 0,115,117,114,102,100, 97,116, 97, 80, 97,116,104, 91, 50, 52, 48, 93, 0, 98, 98, 83,116, 97,
+114,116, 91, 51, 93, 0, 98, 98, 83,105,122,101, 91, 51, 93, 0,109,105,115,116,121,112,101, 0,104,111,114,114, 0,104,111,114,
+103, 0,104,111,114, 98, 0,104,111,114,107, 0,122,101,110,114, 0,122,101,110,103, 0,122,101,110, 98, 0,122,101,110,107, 0,
+ 97,109, 98,107, 0,102, 97,115,116, 99,111,108, 0,101,120,112,111,115,117,114,101, 0,101,120,112, 0,114, 97,110,103,101, 0,
+108,105,110,102, 97, 99, 0,108,111,103,102, 97, 99, 0,103,114, 97,118,105,116,121, 0, 97, 99,116,105,118,105,116,121, 66,111,
+120, 82, 97,100,105,117,115, 0,115,107,121,116,121,112,101, 0,112,104,121,115,105, 99,115, 69,110,103,105,110,101, 0,109,105,
+115,105, 0,109,105,115,116,115,116, 97, 0,109,105,115,116,100,105,115,116, 0,109,105,115,116,104,105, 0,115,116, 97,114,114,
+ 0,115,116, 97,114,103, 0,115,116, 97,114, 98, 0,115,116, 97,114,107, 0,115,116, 97,114,115,105,122,101, 0,115,116, 97,114,
+109,105,110,100,105,115,116, 0,115,116, 97,114,100,105,115,116, 0,115,116, 97,114, 99,111,108,110,111,105,115,101, 0,100,111,
+102,115,116, 97, 0,100,111,102,101,110,100, 0,100,111,102,109,105,110, 0,100,111,102,109, 97,120, 0, 97,111,100,105,115,116,
+ 0, 97,111,100,105,115,116,102, 97, 99, 0, 97,111,101,110,101,114,103,121, 0, 97,111, 98,105, 97,115, 0, 97,111,109,111,100,
+101, 0, 97,111,115, 97,109,112, 0, 97,111,109,105,120, 0, 97,111, 99,111,108,111,114, 0, 42, 97,111,115,112,104,101,114,101,
+ 0,104,101,109,105,114,101,115, 0,109, 97,120,105,116,101,114, 0,100,114, 97,119,116,121,112,101, 0,115,117, 98,115,104,111,
+111,116,112, 0,115,117, 98,115,104,111,111,116,101, 0,110,111,100,101,108,105,109, 0,109, 97,120,115,117, 98,108, 97,109,112,
+ 0,112, 97,109, 97, 0,112, 97,109,105, 0,101,108,109, 97, 0,101,108,109,105, 0,109, 97,120,110,111,100,101, 0, 99,111,110,
+118,101,114,103,101,110, 99,101, 0,114, 97,100,102, 97, 99, 0,103, 97,109,109, 97, 0,115,101,108, 99,111,108, 0,115,120, 0,
+115,121, 0, 42,108,112, 70,111,114,109, 97,116, 0, 42,108,112, 80, 97,114,109,115, 0, 99, 98, 70,111,114,109, 97,116, 0, 99,
+ 98, 80, 97,114,109,115, 0,102, 99, 99, 84,121,112,101, 0,102, 99, 99, 72, 97,110,100,108,101,114, 0,100,119, 75,101,121, 70,
+114, 97,109,101, 69,118,101,114,121, 0,100,119, 81,117, 97,108,105,116,121, 0,100,119, 66,121,116,101,115, 80,101,114, 83,101,
+ 99,111,110,100, 0,100,119, 70,108, 97,103,115, 0,100,119, 73,110,116,101,114,108,101, 97,118,101, 69,118,101,114,121, 0, 97,
+118,105, 99,111,100,101, 99,110, 97,109,101, 91, 49, 50, 56, 93, 0, 42, 99,100, 80, 97,114,109,115, 0, 42,112, 97,100, 0, 99,
+100, 83,105,122,101, 0,113,116, 99,111,100,101, 99,110, 97,109,101, 91, 49, 50, 56, 93, 0,109,105,120,114, 97,116,101, 0,109,
+ 97,105,110, 0,112, 97,100, 91, 51, 93, 0, 42, 97,118,105, 99,111,100,101, 99,100, 97,116, 97, 0, 42,113,116, 99,111,100,101,
+ 99,100, 97,116, 97, 0, 99,102,114, 97, 0,105,109, 97,103,101,115, 0,102,114, 97,109, 97,112,116,111, 0,102,114, 97,109,101,
+108,101,110, 0, 98,108,117,114,102, 97, 99, 0,101,100,103,101, 82, 0,101,100,103,101, 71, 0,101,100,103,101, 66, 0,102,117,
+108,108,115, 99,114,101,101,110, 0,120,112,108, 97,121, 0,121,112,108, 97,121, 0,102,114,101,113,112,108, 97,121, 0, 97,116,
+116,114,105, 98, 0,114,116, 49, 0,114,116, 50, 0,115,116,101,114,101,111,109,111,100,101, 0,100,105,109,101,110,115,105,111,
+110,115,112,114,101,115,101,116, 0,102,105,108,116,101,114,116,121,112,101, 0,109, 97,120,105,109,115,105,122,101, 0,120,115,
+ 99,104, 0,121,115, 99,104, 0,120, 97,115,112, 0,121, 97,115,112, 0,120,112, 97,114,116,115, 0,121,112, 97,114,116,115, 0,
+115, 97,102,101,116,121, 0, 98,111,114,100,101,114, 0,119,105,110,112,111,115, 0,112,108, 97,110,101,115, 0,105,109,116,121,
+112,101, 0, 98,117,102,102,108, 97,103, 0,113,117, 97,108,105,116,121, 0,115, 99,101,109,111,100,101, 0,114,101,110,100,101,
+114,101,114, 0,111, 99,114,101,115, 0,114,112, 97,100, 91, 50, 93, 0, 97,108,112,104, 97,109,111,100,101, 0,100,111,103, 97,
+109,109, 97, 0,111,115, 97, 0,102,114,115, 95,115,101, 99, 0,101,100,103,101,105,110,116, 0,115, 97,109,101, 95,109, 97,116,
+ 95,114,101,100,117,120, 0,103, 97,117,115,115, 0,112,111,115,116,109,117,108, 0,112,111,115,116,103, 97,109,109, 97, 0,112,
+111,115,116, 97,100,100, 0,112,111,115,116,105,103, 97,109,109, 97, 0,112,111,115,116,104,117,101, 0,112,111,115,116,115, 97,
+116, 0,100,105,116,104,101,114, 95,105,110,116,101,110,115,105,116,121, 0,122,109,105,110, 0,102,111, 99,117,115, 0,122,103,
+ 97,109,109, 97, 0,122,115,105,103,109, 97, 0,122, 98,108,117,114, 0, 71, 73,113,117, 97,108,105,116,121, 0, 71, 73, 99, 97,
+ 99,104,101, 0, 71, 73,109,101,116,104,111,100, 0, 71, 73,112,104,111,116,111,110,115, 0, 71, 73,100,105,114,101, 99,116, 0,
+ 89, 70, 95, 65, 65, 0, 89, 70,101,120,112,111,114,116,120,109,108, 0, 89, 70, 95,110,111, 98,117,109,112, 0, 89, 70, 95, 99,
+108, 97,109,112,114,103, 98, 0,121,102,112, 97,100, 49, 0, 71, 73,100,101,112,116,104, 0, 71, 73, 99, 97,117,115,100,101,112,
+116,104, 0, 71, 73,112,105,120,101,108,115,112,101,114,115, 97,109,112,108,101, 0, 71, 73,112,104,111,116,111,110, 99,111,117,
+110,116, 0, 71, 73,109,105,120,112,104,111,116,111,110,115, 0, 71, 73,112,104,111,116,111,110,114, 97,100,105,117,115, 0, 89,
+ 70, 95,110,117,109,112,114,111, 99,115, 0, 89, 70, 95,114, 97,121,100,101,112,116,104, 0, 89, 70, 95, 65, 65,112, 97,115,115,
+101,115, 0, 89, 70, 95, 65, 65,115, 97,109,112,108,101,115, 0, 71, 73,115,104, 97,100,111,119,113,117, 97,108,105,116,121, 0,
+ 71, 73,114,101,102,105,110,101,109,101,110,116, 0, 71, 73,112,111,119,101,114, 0, 71, 73,105,110,100,105,114,112,111,119,101,
+114, 0, 89, 70, 95,103, 97,109,109, 97, 0, 89, 70, 95,101,120,112,111,115,117,114,101, 0, 89, 70, 95,114, 97,121, 98,105, 97,
+115, 0, 89, 70, 95, 65, 65,112,105,120,101,108,115,105,122,101, 0, 89, 70, 95, 65, 65,116,104,114,101,115,104,111,108,100, 0,
+ 98, 97, 99,107, 98,117,102, 91, 49, 54, 48, 93, 0,112,105, 99, 91, 49, 54, 48, 93, 0,102,116,121,112,101, 91, 49, 54, 48, 93,
+ 0, 99,111,108, 91, 51, 93, 0,102,114, 97,109,101, 0,110, 97,109,101, 91, 54, 52, 93, 0, 99,111,114,110,101,114,116,121,112,
+101, 0,101,100,105,116, 98,117,116,102,108, 97,103, 0,100,101,103,114, 0,115,116,101,112, 0,116,117,114,110, 0,101,120,116,
+114, 95,111,102,102,115, 0,100,111,117, 98,108,105,109,105,116, 0,115,101,103,109,101,110,116,115, 0,114,105,110,103,115, 0,
+118,101,114,116,105, 99,101,115, 0, 42, 99, 97,109,101,114, 97, 0, 42,119,111,114,108,100, 0, 42,115,101,116, 0, 98, 97,115,
+101, 0, 42, 98, 97,115, 97, 99,116, 0, 42,103,114,111,117,112, 0, 99,117,114,115,111,114, 91, 51, 93, 0,116,119, 99,101,110,
+116, 91, 51, 93, 0,116,119,109,105,110, 91, 51, 93, 0,116,119,109, 97,120, 91, 51, 93, 0,115,101,108,101, 99,116,109,111,100,
+101, 0,112,114,111,112,111,114,116,105,111,110, 97,108, 0,112,114,111,112, 95,109,111,100,101, 0,101,100,105,116, 98,117,116,
+115,105,122,101, 0, 42,101,100, 0, 42,114, 97,100,105,111, 0,102,114, 97,109,105,110,103, 0, 42,116,111,111,108,115,101,116,
+116,105,110,103,115, 0, 97,117,100,105,111, 0,109, 97,114,107,101,114,115, 0, 42,116,104,101, 68, 97,103, 0,100, 97,103,105,
+115,118, 97,108,105,100, 0,100, 97,103,102,108, 97,103,115, 0,100,105,114,116,121, 0,122,111,111,109, 0, 98,108,101,110,100,
+ 0,120,105,109, 0,121,105,109, 0, 42,114,101, 99,116, 0,115,112, 97, 99,101,116,121,112,101, 0, 98,108,111, 99,107,115, 99,
+ 97,108,101, 0, 42, 97,114,101, 97, 0, 98,108,111, 99,107,104, 97,110,100,108,101,114, 91, 56, 93, 0,118,105,101,119,109, 97,
+116, 91, 52, 93, 91, 52, 93, 0,118,105,101,119,105,110,118, 91, 52, 93, 91, 52, 93, 0,112,101,114,115,109, 97,116, 91, 52, 93,
+ 91, 52, 93, 0,112,101,114,115,105,110,118, 91, 52, 93, 91, 52, 93, 0,119,105,110,109, 97,116, 49, 91, 52, 93, 91, 52, 93, 0,
+118,105,101,119,109, 97,116, 49, 91, 52, 93, 91, 52, 93, 0,118,105,101,119,113,117, 97,116, 91, 52, 93, 0,112,101,114,115,112,
+ 0,118,105,101,119, 0, 42, 98,103,112,105, 99, 0, 42,108,111, 99, 97,108,118,100, 0,108,111, 99, 97,108,118,105,101,119, 0,
+108, 97,121, 97, 99,116, 0,115, 99,101,110,101,108,111, 99,107, 0, 97,114,111,117,110,100, 0, 99, 97,109,122,111,111,109, 0,
+103,114,105,100, 0,103,114,105,100,118,105,101,119, 0,112,105,120,115,105,122,101, 0,110,101, 97,114, 0,102, 97,114, 0,103,
+114,105,100,108,105,110,101,115, 0,118,105,101,119, 98,117,116, 0,103,114,105,100,102,108, 97,103, 0,109,111,100,101,115,101,
+108,101, 99,116, 0,109,101,110,117,110,114, 0,116,101,120,110,114, 0,116,119,116,121,112,101, 0,116,119,109,111,100,101, 0,
+116,119,102,108, 97,103, 0,116,119,100,114, 97,119,102,108, 97,103, 0,116,119,109, 97,116, 91, 52, 93, 91, 52, 93, 0, 99,108,
+105,112, 91, 52, 93, 91, 52, 93, 0, 42, 99,108,105,112, 98, 98, 0, 97,102,116,101,114,100,114, 97,119, 0,122, 98,117,102, 0,
+120,114, 97,121, 0,118,101,114,116, 0,104,111,114, 0,109, 97,115,107, 0,109,105,110, 91, 50, 93, 0,109, 97,120, 91, 50, 93,
+ 0,109,105,110,122,111,111,109, 0,109, 97,120,122,111,111,109, 0,115, 99,114,111,108,108, 0,107,101,101,112,116,111,116, 0,
+107,101,101,112, 97,115,112,101, 99,116, 0,107,101,101,112,122,111,111,109, 0,111,108,100,119,105,110,120, 0,111,108,100,119,
+105,110,121, 0,114,111,119, 98,117,116, 0,118, 50,100, 0, 42,101,100,105,116,105,112,111, 0,105,112,111,107,101,121, 0, 97,
+ 99,116,110, 97,109,101, 91, 51, 50, 93, 0, 99,111,110,115,116,110, 97,109,101, 91, 51, 50, 93, 0,116,111,116,105,112,111, 0,
+112,105,110, 0, 98,117,116,111,102,115, 0, 99,104, 97,110,110,101,108, 0,108,111, 99,107, 0,109,101,100,105, 97,110, 91, 51,
+ 93, 0, 99,117,114,115,101,110,115, 0, 99,117,114, 97, 99,116, 0, 97,108,105,103,110, 0,116, 97, 98,111, 0,109, 97,105,110,
+ 98, 0,109, 97,105,110, 98,111, 0, 42,108,111, 99,107,112,111,105,110, 0,116,101,120,102,114,111,109, 0,115,104,111,119,103,
+114,111,117,112, 0,114,101, 99,116,120, 0,114,101, 99,116,121, 0, 99,117,114,121, 0,109,111,100,101,108,116,121,112,101, 0,
+115, 99,114,105,112,116, 98,108,111, 99,107, 0,114,101, 95, 97,108,105,103,110, 0,111,108,100,107,101,121,112,114,101,115,115,
+ 0,116, 97, 98, 91, 55, 93, 0, 42,102,105,108,101,108,105,115,116, 0,116,111,116,102,105,108,101, 0,116,105,116,108,101, 91,
+ 50, 52, 93, 0,100,105,114, 91, 49, 54, 48, 93, 0,102,105,108,101, 91, 56, 48, 93, 0,111,102,115, 0,115,111,114,116, 0,109,
+ 97,120,110, 97,109,101,108,101,110, 0, 99,111,108,108,117,109,115, 0, 42,108,105, 98,102,105,108,101,100, 97,116, 97, 0,114,
+101,116,118, 97,108, 0,109,101,110,117, 0, 97, 99,116, 0, 40, 42,114,101,116,117,114,110,102,117,110, 99, 41, 40, 41, 0, 42,
+109,101,110,117,112, 0,111,111,112,115, 0,118,105,115,105,102,108, 97,103, 0,116,114,101,101, 0, 42,116,114,101,101,115,116,
+111,114,101, 0,111,117,116,108,105,110,101,118,105,115, 0,115,116,111,114,101,102,108, 97,103, 0,100,101,112,115, 95,102,108,
+ 97,103,115, 0, 42,105,109, 97,103,101, 0,105,109, 97,110,114, 0, 99,117,114,116,105,108,101, 0, 42,116,101,120,116, 0,116,
+111,112, 0,118,105,101,119,108,105,110,101,115, 0,102,111,110,116, 95,105,100, 0,108,104,101,105,103,104,116, 0,108,101,102,
+116, 0,115,104,111,119,108,105,110,101,110,114,115, 0,116, 97, 98,110,117,109, 98,101,114, 0, 99,117,114,114,116, 97, 98, 95,
+115,101,116, 0,115,104,111,119,115,121,110,116, 97,120, 0,117,110,117,115,101,100, 95,112, 97,100,100, 0,112,105,120, 95,112,
+101,114, 95,108,105,110,101, 0,116,120,116,115, 99,114,111,108,108, 0,116,120,116, 98, 97,114, 0, 42,115, 99,114,105,112,116,
+ 0,114,101,100,114, 97,119,115, 0,116,105,116,108,101, 91, 50, 56, 93, 0,102, 97,115,101, 0,115,117, 98,102, 97,115,101, 0,
+109,111,117,115,101, 95,109,111,118,101, 95,114,101,100,114, 97,119, 0,105,109, 97,102, 97,115,101, 0,109,120, 0,109,121, 0,
+100,105,114,115,108,105, 0,100,105,114,115,108,105, 95,108,105,110,101,115, 0,100,105,114,115,108,105, 95,115,120, 0,100,105,
+114,115,108,105, 95,101,121, 0,100,105,114,115,108,105, 95,101,120, 0,100,105,114,115,108,105, 95,104, 0,105,109, 97,115,108,
+105, 0,102,105,108,101,115,101,108,109,101,110,117,105,116,101,109, 0,105,109, 97,115,108,105, 95,115,120, 0,105,109, 97,115,
+108,105, 95,101,121, 0,105,109, 97,115,108,105, 95,101,120, 0,105,109, 97,115,108,105, 95,104, 0,100,115,115,120, 0,100,115,
+115,121, 0,100,115,101,120, 0,100,115,101,121, 0,100,101,115,120, 0,100,101,115,121, 0,100,101,101,120, 0,100,101,101,121,
+ 0,102,115,115,120, 0,102,115,115,121, 0,102,115,101,120, 0,102,115,101,121, 0,100,115,100,104, 0,102,115,100,104, 0,102,
+101,115,120, 0,102,101,115,121, 0,102,101,101,120, 0,102,101,101,121, 0,105,110,102,115,120, 0,105,110,102,115,121, 0,105,
+110,102,101,120, 0,105,110,102,101,121, 0,100,110,115,120, 0,100,110,115,121, 0,100,110,119, 0,100,110,104, 0,102,110,115,
+120, 0,102,110,115,121, 0,102,110,119, 0,102,110,104, 0,102,111,108,101, 91, 49, 50, 56, 93, 0,100,111,114, 91, 49, 50, 56,
+ 93, 0,102,105,108,101, 91, 49, 50, 56, 93, 0,100,105,114, 91, 49, 50, 56, 93, 0, 42,102,105,114,115,116,100,105,114, 0, 42,
+102,105,114,115,116,102,105,108,101, 0,116,111,112,100,105,114, 0,116,111,116, 97,108,100,105,114,115, 0,104,105,108,105,116,
+101, 0,116,111,112,102,105,108,101, 0,116,111,116, 97,108,102,105,108,101,115, 0,105,109, 97,103,101, 95,115,108,105,100,101,
+114, 0,115,108,105,100,101,114, 95,104,101,105,103,104,116, 0,115,108,105,100,101,114, 95,115,112, 97, 99,101, 0,116,111,112,
+105,109, 97, 0,116,111,116, 97,108,105,109, 97, 0, 99,117,114,105,109, 97,120, 0, 99,117,114,105,109, 97,121, 0, 42,102,105,
+114,115,116, 95,115,101,108, 95,105,109, 97, 0, 42,104,105,108,105,116,101, 95,105,109, 97, 0,116,111,116, 97,108, 95,115,101,
+108,101, 99,116,101,100, 0,105,109, 97, 95,114,101,100,114, 97,119, 0, 42, 99,109, 97,112, 0, 42, 97,114,103, 49, 0,111,117,
+116,108,105,110,101, 91, 52, 93, 0,110,101,117,116,114, 97,108, 91, 52, 93, 0, 97, 99,116,105,111,110, 91, 52, 93, 0,115,101,
+116,116,105,110,103, 91, 52, 93, 0,115,101,116,116,105,110,103, 49, 91, 52, 93, 0,115,101,116,116,105,110,103, 50, 91, 52, 93,
+ 0,110,117,109, 91, 52, 93, 0,116,101,120,116,102,105,101,108,100, 91, 52, 93, 0,116,101,120,116,102,105,101,108,100, 95,104,
+105, 91, 52, 93, 0,112,111,112,117,112, 91, 52, 93, 0,116,101,120,116, 91, 52, 93, 0,116,101,120,116, 95,104,105, 91, 52, 93,
+ 0,109,101,110,117, 95, 98, 97, 99,107, 91, 52, 93, 0,109,101,110,117, 95,105,116,101,109, 91, 52, 93, 0,109,101,110,117, 95,
+104,105,108,105,116,101, 91, 52, 93, 0,109,101,110,117, 95,116,101,120,116, 91, 52, 93, 0,109,101,110,117, 95,116,101,120,116,
+ 95,104,105, 91, 52, 93, 0, 98,117,116, 95,100,114, 97,119,116,121,112,101, 0,112, 97,100, 49, 91, 51, 93, 0, 98, 97, 99,107,
+ 91, 52, 93, 0,104,101, 97,100,101,114, 91, 52, 93, 0,112, 97,110,101,108, 91, 52, 93, 0,115,104, 97,100,101, 49, 91, 52, 93,
+ 0,115,104, 97,100,101, 50, 91, 52, 93, 0,104,105,108,105,116,101, 91, 52, 93, 0,103,114,105,100, 91, 52, 93, 0,119,105,114,
+101, 91, 52, 93, 0,115,101,108,101, 99,116, 91, 52, 93, 0,108, 97,109,112, 91, 52, 93, 0, 97, 99,116,105,118,101, 91, 52, 93,
+ 0,116,114, 97,110,115,102,111,114,109, 91, 52, 93, 0,118,101,114,116,101,120, 91, 52, 93, 0,118,101,114,116,101,120, 95,115,
+101,108,101, 99,116, 91, 52, 93, 0,101,100,103,101, 91, 52, 93, 0,101,100,103,101, 95,115,101,108,101, 99,116, 91, 52, 93, 0,
+101,100,103,101, 95,115,101, 97,109, 91, 52, 93, 0,101,100,103,101, 95,102, 97, 99,101,115,101,108, 91, 52, 93, 0,102, 97, 99,
+101, 91, 52, 93, 0,102, 97, 99,101, 95,115,101,108,101, 99,116, 91, 52, 93, 0,102, 97, 99,101, 95,100,111,116, 91, 52, 93, 0,
+110,111,114,109, 97,108, 91, 52, 93, 0, 98,111,110,101, 95,115,111,108,105,100, 91, 52, 93, 0, 98,111,110,101, 95,112,111,115,
+101, 91, 52, 93, 0,115,116,114,105,112, 91, 52, 93, 0,115,116,114,105,112, 95,115,101,108,101, 99,116, 91, 52, 93, 0,118,101,
+114,116,101,120, 95,115,105,122,101, 0,102, 97, 99,101,100,111,116, 95,115,105,122,101, 0, 98,112, 97,100, 91, 50, 93, 0,115,
+121,110,116, 97,120,108, 91, 52, 93, 0,115,121,110,116, 97,120,110, 91, 52, 93, 0,115,121,110,116, 97,120, 98, 91, 52, 93, 0,
+115,121,110,116, 97,120,118, 91, 52, 93, 0,115,121,110,116, 97,120, 99, 91, 52, 93, 0,116,117,105, 0,116, 98,117,116,115, 0,
+116,118, 51,100, 0,116,102,105,108,101, 0,116,105,112,111, 0,116,105,110,102,111, 0,116,115,110,100, 0,116, 97, 99,116, 0,
+116,110,108, 97, 0,116,115,101,113, 0,116,105,109, 97, 0,116,105,109, 97,115,101,108, 0,116,101,120,116, 0,116,111,111,112,
+115, 0,116,116,105,109,101, 0,115,112,101, 99, 91, 52, 93, 0,100,117,112,102,108, 97,103, 0,115, 97,118,101,116,105,109,101,
+ 0,116,101,109,112,100,105,114, 91, 49, 54, 48, 93, 0,102,111,110,116,100,105,114, 91, 49, 54, 48, 93, 0,114,101,110,100,101,
+114,100,105,114, 91, 49, 54, 48, 93, 0,116,101,120,116,117,100,105,114, 91, 49, 54, 48, 93, 0,112,108,117,103,116,101,120,100,
+105,114, 91, 49, 54, 48, 93, 0,112,108,117,103,115,101,113,100,105,114, 91, 49, 54, 48, 93, 0,112,121,116,104,111,110,100,105,
+114, 91, 49, 54, 48, 93, 0,115,111,117,110,100,100,105,114, 91, 49, 54, 48, 93, 0,121,102,101,120,112,111,114,116,100,105,114,
+ 91, 49, 54, 48, 93, 0,118,101,114,115,105,111,110,115, 0,118,114,109,108,102,108, 97,103, 0,103, 97,109,101,102,108, 97,103,
+115, 0,119,104,101,101,108,108,105,110,101,115, 99,114,111,108,108, 0,117,105,102,108, 97,103, 0,108, 97,110,103,117, 97,103,
+101, 0,117,115,101,114,112,114,101,102, 0,118,105,101,119,122,111,111,109, 0, 99,111,110,115,111,108,101, 95, 98,117,102,102,
+101,114, 0, 99,111,110,115,111,108,101, 95,111,117,116, 0,109,105,120, 98,117,102,115,105,122,101, 0,102,111,110,116,115,105,
+122,101, 0,101,110, 99,111,100,105,110,103, 0,116,114, 97,110,115,111,112,116,115, 0,109,101,110,117,116,104,114,101,115,104,
+111,108,100, 49, 0,109,101,110,117,116,104,114,101,115,104,111,108,100, 50, 0,102,111,110,116,110, 97,109,101, 91, 50, 53, 54,
+ 93, 0,116,104,101,109,101,115, 0,117,110,100,111,115,116,101,112,115, 0, 99,117,114,115,115,105,122,101, 0,116, 98, 95,108,
+101,102,116,109,111,117,115,101, 0,116, 98, 95,114,105,103,104,116,109,111,117,115,101, 0,108,105,103,104,116, 91, 51, 93, 0,
+116,119, 95,104,111,116,115,112,111,116, 0,116,119, 95,102,108, 97,103, 0,116,119, 95,104, 97,110,100,108,101,115,105,122,101,
+ 0,116,119, 95,115,105,122,101, 0,116,101,120,116,105,109,101,111,117,116, 0,116,101,120, 99,111,108,108,101, 99,116,114, 97,
+116,101, 0,111, 98, 99,101,110,116,101,114, 95,100,105, 97, 0,118,101,114,116, 98, 97,115,101, 0,101,100,103,101, 98, 97,115,
+101, 0, 97,114,101, 97, 98, 97,115,101, 0, 42,115, 99,101,110,101, 0,101,110,100,120, 0,101,110,100,121, 0,115,105,122,101,
+120, 0,115,105,122,101,121, 0,115, 99,101,110,101,110,114, 0,115, 99,114,101,101,110,110,114, 0,102,117,108,108, 0,109, 97,
+105,110,119,105,110, 0,119,105,110, 97,107,116, 0,104, 97,110,100,108,101,114, 91, 56, 93, 0, 42,110,101,119,118, 0,118,101,
+ 99, 0, 42,118, 49, 0, 42,118, 50, 0,112, 97,110,101,108,110, 97,109,101, 91, 54, 52, 93, 0,116, 97, 98,110, 97,109,101, 91,
+ 54, 52, 93, 0,111,102,115,120, 0,111,102,115,121, 0, 99,111,110,116,114,111,108, 0,111,108,100, 95,111,102,115,120, 0,111,
+108,100, 95,111,102,115,121, 0,115,111,114,116, 99,111,117,110,116,101,114, 0, 42,112, 97,110,101,108,116, 97, 98, 0, 42,118,
+ 51, 0, 42,118, 52, 0, 42,102,117,108,108, 0,119,105,110,109, 97,116, 91, 52, 93, 91, 52, 93, 0,104,101, 97,100,114, 99,116,
+ 0,119,105,110,114, 99,116, 0,104,101, 97,100,119,105,110, 0,119,105,110, 0,104,101, 97,100,101,114,116,121,112,101, 0, 98,
+117,116,115,112, 97, 99,101,116,121,112,101, 0,119,105,110,120, 0,119,105,110,121, 0,104,101, 97,100, 95,115,119, 97,112, 0,
+104,101, 97,100, 95,101,113,117, 97,108, 0,119,105,110, 95,115,119, 97,112, 0,119,105,110, 95,101,113,117, 97,108, 0,104,101,
+ 97,100, 98,117,116,108,101,110, 0,104,101, 97,100, 98,117,116,111,102,115, 0, 99,117,114,115,111,114, 0,115,112, 97, 99,101,
+100, 97,116, 97, 0,117,105, 98,108,111, 99,107,115, 0,112, 97,110,101,108,115, 0, 42, 99,117,114,115, 99,114,101,101,110, 0,
+ 42, 99,117,114,115, 99,101,110,101, 0,100,105,115,112,108, 97,121,109,111,100,101, 0,102,105,108,101,102,108, 97,103,115, 0,
+103,108,111, 98, 97,108,102, 0,110, 97,109,101, 91, 56, 48, 93, 0, 42,115,101, 49, 0, 42,115,101, 50, 0, 42,115,101, 51, 0,
+110,114, 0,100,111,110,101, 0, 42,115,116,114,105,112,100, 97,116, 97, 0,111,114,120, 0,111,114,121, 0, 42,110,101,119,115,
+101,113, 0,115,116, 97,114,116,111,102,115, 0,101,110,100,111,102,115, 0,115,116, 97,114,116,115,116,105,108,108, 0,101,110,
+100,115,116,105,108,108, 0,109, 97, 99,104,105,110,101, 0,115,116, 97,114,116,100,105,115,112, 0,101,110,100,100,105,115,112,
+ 0,109,117,108, 0,104, 97,110,100,115,105,122,101, 0, 42,115,116,114,105,112, 0, 42, 99,117,114,101,108,101,109, 0,102, 97,
+ 99,102, 48, 0,102, 97, 99,102, 49, 0, 42,115,101,113, 49, 0, 42,115,101,113, 50, 0, 42,115,101,113, 51, 0,115,101,113, 98,
+ 97,115,101, 0, 42,115,111,117,110,100, 0,108,101,118,101,108, 0,112, 97,110, 0, 99,117,114,112,111,115, 0,115,116,114,111,
+ 98,101, 0, 42,101,102,102,101, 99,116,100, 97,116, 97, 0, 42,111,108,100, 98, 97,115,101,112, 0, 42,112, 97,114,115,101,113,
+ 0, 42,115,101,113, 98, 97,115,101,112, 0,109,101,116, 97,115,116, 97, 99,107, 0,101,100,103,101, 87,105,100,116,104, 0, 97,
+110,103,108,101, 0,102,111,114,119, 97,114,100, 0,119,105,112,101,116,121,112,101, 0,102, 77,105,110,105, 0,102, 67,108, 97,
+109,112, 0,102, 66,111,111,115,116, 0,100, 68,105,115,116, 0,100, 81,117, 97,108,105,116,121, 0, 98, 78,111, 67,111,109,112,
+ 0, 98,117,116,116,121,112,101, 0,117,115,101,114,106,105,116, 0,115,116, 97, 0,101,110,100, 0,116,111,116,112, 97,114,116,
+ 0,110,111,114,109,102, 97, 99, 0,111, 98,102, 97, 99, 0,114, 97,110,100,102, 97, 99, 0,116,101,120,102, 97, 99, 0,114, 97,
+110,100,108,105,102,101, 0,102,111,114, 99,101, 91, 51, 93, 0,118,101, 99,116,115,105,122,101, 0,100,101,102,118,101, 99, 91,
+ 51, 93, 0,109,117,108,116, 91, 52, 93, 0,108,105,102,101, 91, 52, 93, 0, 99,104,105,108,100, 91, 52, 93, 0,109, 97,116, 91,
+ 52, 93, 0,116,101,120,109, 97,112, 0, 99,117,114,109,117,108,116, 0,115,116, 97,116,105, 99,115,116,101,112, 0,111,109, 97,
+116, 0,116,105,109,101,116,101,120, 0,115,112,101,101,100,116,101,120, 0,102,108, 97,103, 50, 0,102,108, 97,103, 50,110,101,
+103, 0,118,101,114,116,103,114,111,117,112, 95,118, 0,118,103,114,111,117,112,110, 97,109,101, 91, 51, 50, 93, 0,118,103,114,
+111,117,112,110, 97,109,101, 95,118, 91, 51, 50, 93, 0, 42,107,101,121,115, 0,109,105,110,102, 97, 99, 0,117,115,101,100, 0,
+ 42,105,100, 0,117,115,101,100,101,108,101,109, 0,100,120, 0,100,121, 0,108,105,110,107, 0,111,116,121,112,101, 0,100, 97,
+116, 97, 0,111,108,100, 0, 42,112,111,105,110, 0, 42,111,108,100,112,111,105,110, 0,114,101,115,101,116,100,105,115,116, 0,
+108, 97,115,116,118, 97,108, 0, 42,109, 97, 0,107,101,121, 0,113,117, 97,108, 0,113,117, 97,108, 50, 0,116, 97,114,103,101,
+116, 78, 97,109,101, 91, 51, 50, 93, 0,116,111,103,103,108,101, 78, 97,109,101, 91, 51, 50, 93, 0,118, 97,108,117,101, 91, 51,
+ 50, 93, 0,109, 97,120,118, 97,108,117,101, 91, 51, 50, 93, 0,109, 97,116,101,114,105, 97,108, 78, 97,109,101, 91, 51, 50, 93,
+ 0,100, 97,109,112,116,105,109,101,114, 0,100,101,108, 97,121, 0,112,114,111,112,110, 97,109,101, 91, 51, 50, 93, 0,109, 97,
+116,110, 97,109,101, 91, 51, 50, 93, 0, 97,120,105,115,102,108, 97,103, 0, 42,102,114,111,109, 79, 98,106,101, 99,116, 0,115,
+117, 98,106,101, 99,116, 91, 51, 50, 93, 0, 98,111,100,121, 91, 51, 50, 93, 0,112,117,108,115,101, 0,102,114,101,113, 0,116,
+111,116,108,105,110,107,115, 0, 42, 42,108,105,110,107,115, 0,105,110,118,101,114,116, 0,102,114,101,113, 50, 0, 97,120,105,
+115,102, 0, 98,117,116,116,111,110, 0, 98,117,116,116,111,110,102, 0,104, 97,116, 0,104, 97,116,102, 0,112,114,101, 99,105,
+115,105,111,110, 0,115,116,114, 91, 49, 50, 56, 93, 0, 42,109,121,110,101,119, 0,105,110,112,117,116,115, 0,116,111,116,115,
+108,105,110,107,115, 0, 42, 42,115,108,105,110,107,115, 0,118, 97,108, 0,118, 97,108,111, 0,116,105,109,101, 0, 42, 97, 99,
+116, 0, 98,108,101,110,100,105,110, 0,112,114,105,111,114,105,116,121, 0,115,116,114,105,100,101,108,101,110,103,116,104, 0,
+115,116,114,105,100,101, 97,120,105,115, 0,114,101,115,101,114,118,101,100, 51, 0,115,110,100,110,114, 0,109, 97,107,101, 99,
+111,112,121, 0, 99,111,112,121,109, 97,100,101, 0,112, 97,100, 91, 49, 93, 0,116,114, 97, 99,107, 0,118,111,108,117,109,101,
+ 0, 42,109,101, 0,108,105,110, 86,101,108,111, 99,105,116,121, 91, 51, 93, 0,108,111, 99, 97,108,102,108, 97,103, 0,102,111,
+114, 99,101,108,111, 99, 91, 51, 93, 0,102,111,114, 99,101,114,111,116, 91, 51, 93, 0,108,105,110,101, 97,114,118,101,108,111,
+ 99,105,116,121, 91, 51, 93, 0, 97,110,103,117,108, 97,114,118,101,108,111, 99,105,116,121, 91, 51, 93, 0, 97,100,100,101,100,
+108,105,110,101, 97,114,118,101,108,111, 99,105,116,121, 91, 51, 93, 0, 97,110,111,116,104,101,114,112, 97,100, 91, 52, 93, 0,
+ 98,117,116,115,116, 97, 0, 98,117,116,101,110,100, 0,109,105,110, 0,102, 97, 99, 0,118,105,115,105,102, 97, 99, 0,115,108,
+111,119, 0,109,105,110,108,111, 99, 91, 51, 93, 0,109, 97,120,108,111, 99, 91, 51, 93, 0,109,105,110,114,111,116, 91, 51, 93,
+ 0,109, 97,120,114,111,116, 91, 51, 93, 0,100,105,115,116,114,105, 98,117,116,105,111,110, 0,105,110,116, 95, 97,114,103, 95,
+ 49, 0,105,110,116, 95, 97,114,103, 95, 50, 0,102,108,111, 97,116, 95, 97,114,103, 95, 49, 0,102,108,111, 97,116, 95, 97,114,
+103, 95, 50, 0,116,111, 80,114,111,112, 78, 97,109,101, 91, 51, 50, 93, 0, 42,116,111, 79, 98,106,101, 99,116, 0, 98,111,100,
+121, 84,121,112,101, 0,102,105,108,101,110, 97,109,101, 91, 54, 52, 93, 0,108,111, 97,100, 97,110,105,110, 97,109,101, 91, 54,
+ 52, 93, 0,103,111, 0, 97, 99, 99,101,108,108,101,114, 97,116,105,111,110, 0,109, 97,120,115,112,101,101,100, 0,109, 97,120,
+114,111,116,115,112,101,101,100, 0,109, 97,120,116,105,108,116,115,112,101,101,100, 0,114,111,116,100, 97,109,112, 0,116,105,
+108,116,100, 97,109,112, 0,115,112,101,101,100,100, 97,109,112, 0, 42,115, 97,109,112,108,101, 0, 42,115,116,114,101, 97,109,
+ 0, 42,110,101,119,112, 97, 99,107,101,100,102,105,108,101, 0, 42,115,110,100, 95,115,111,117,110,100, 0,112, 97,110,110,105,
+110,103, 0, 97,116,116,101,110,117, 97,116,105,111,110, 0,112,105,116, 99,104, 0,109,105,110, 95,103, 97,105,110, 0,109, 97,
+120, 95,103, 97,105,110, 0,100,105,115,116, 97,110, 99,101, 0,115,116,114,101, 97,109,108,101,110, 0,108,111,111,112,115,116,
+ 97,114,116, 0,108,111,111,112,101,110,100, 0, 99,104, 97,110,110,101,108,115, 0,104,105,103,104,112,114,105,111, 0,112, 97,
+100, 91, 49, 48, 93, 0,103, 97,105,110, 0,100,111,112,112,108,101,114,102, 97, 99,116,111,114, 0,100,111,112,112,108,101,114,
+118,101,108,111, 99,105,116,121, 0,110,117,109,115,111,117,110,100,115, 98,108,101,110,100,101,114, 0,110,117,109,115,111,117,
+110,100,115,103, 97,109,101,101,110,103,105,110,101, 0, 42,103,107,101,121, 0,112, 97,100,102, 0,111,107,101,121, 0,103,111,
+ 98,106,101, 99,116, 0,103,107,101,121, 0, 42, 97, 99,116,105,118,101, 0, 99,104,105,108,100, 98, 97,115,101, 0,114,111,108,
+108, 0,104,101, 97,100, 91, 51, 93, 0,116, 97,105,108, 91, 51, 93, 0, 98,111,110,101, 95,109, 97,116, 91, 51, 93, 91, 51, 93,
+ 0, 97,114,109, 95,104,101, 97,100, 91, 51, 93, 0, 97,114,109, 95,116, 97,105,108, 91, 51, 93, 0, 97,114,109, 95,109, 97,116,
+ 91, 52, 93, 91, 52, 93, 0,120,119,105,100,116,104, 0,122,119,105,100,116,104, 0,101, 97,115,101, 49, 0,101, 97,115,101, 50,
+ 0,114, 97,100, 95,104,101, 97,100, 0,114, 97,100, 95,116, 97,105,108, 0, 98,111,110,101, 99,108, 97,115,115, 0, 98,111,110,
+101, 98, 97,115,101, 0, 99,104, 97,105,110, 98, 97,115,101, 0,103,104,111,115,116,101,112, 0,103,104,111,115,116,115,105,122,
+101, 0, 99,111,110,115,116,102,108, 97,103, 0,105,107,102,108, 97,103, 0, 42, 98,111,110,101, 0, 42, 99,104,105,108,100, 0,
+105,107,116,114,101,101, 0, 42, 98, 95, 98,111,110,101, 95,109, 97,116,115, 0, 99,104, 97,110, 95,109, 97,116, 91, 52, 93, 91,
+ 52, 93, 0,112,111,115,101, 95,109, 97,116, 91, 52, 93, 91, 52, 93, 0,112,111,115,101, 95,104,101, 97,100, 91, 51, 93, 0,112,
+111,115,101, 95,116, 97,105,108, 91, 51, 93, 0,108,105,109,105,116,109,105,110, 91, 51, 93, 0,108,105,109,105,116,109, 97,120,
+ 91, 51, 93, 0,115,116,105,102,102,110,101,115,115, 91, 51, 93, 0,105,107,115,116,114,101,116, 99,104, 0, 99,104, 97,110, 98,
+ 97,115,101, 0,115,116,114,105,100,101, 95,111,102,102,115,101,116, 91, 51, 93, 0, 97, 99,116,110,114, 0,116,105,109,101,115,
+108,105,100,101, 0,110, 97,109,101, 91, 51, 48, 93, 0,101,110,102,111,114, 99,101, 0, 42,116, 97,114, 0,105,116,101,114, 97,
+116,105,111,110,115, 0,114,111,111,116, 98,111,110,101, 0,115,117, 98,116, 97,114,103,101,116, 91, 51, 50, 93, 0,111,114,105,
+101,110,116,119,101,105,103,104,116, 0,103,114, 97, 98,116, 97,114,103,101,116, 91, 51, 93, 0,109,105,110,109, 97,120,102,108,
+ 97,103, 0,115,116,105, 99,107,121, 0,115,116,117, 99,107, 0, 99, 97, 99,104,101, 91, 51, 93, 0,108,111, 99, 97,108, 0,108,
+111, 99,107,102,108, 97,103, 0,102,111,108,108,111,119,102,108, 97,103, 0,111,102,102,115,101,116, 91, 51, 93, 0,122,109, 97,
+120, 0,118,111,108,109,111,100,101, 0,112,108, 97,110,101, 0,111,114,103,108,101,110,103,116,104, 0, 98,117,108,103,101, 0,
+115,116,114,105,100,101, 95, 97,120,105,115, 0, 97, 99,116,115,116, 97,114,116, 0, 97, 99,116,101,110,100, 0,115,116,114,105,
+100,101,108,101,110, 0,114,101,112,101, 97,116, 0, 98,108,101,110,100,111,117,116, 0,115,116,114,105,100,101, 99,104, 97,110,
+110,101,108, 91, 51, 50, 93, 0, 84, 89, 80, 69,219, 0, 0, 0, 99,104, 97,114, 0,117, 99,104, 97,114, 0,115,104,111,114,116,
+ 0,117,115,104,111,114,116, 0,105,110,116, 0,108,111,110,103, 0,117,108,111,110,103, 0,102,108,111, 97,116, 0,100,111,117,
+ 98,108,101, 0,118,111,105,100, 0, 76,105,110,107, 0, 76,105,115,116, 66, 97,115,101, 0,118,101, 99, 50,115, 0,118,101, 99,
+ 50,105, 0,118,101, 99, 50,102, 0,118,101, 99, 50,100, 0,118,101, 99, 51,105, 0,118,101, 99, 51,102, 0,118,101, 99, 51,100,
+ 0,118,101, 99, 52,105, 0,118,101, 99, 52,102, 0,118,101, 99, 52,100, 0,114, 99,116,105, 0,114, 99,116,102, 0, 73, 68, 0,
+ 76,105, 98,114, 97,114,121, 0, 70,105,108,101, 68, 97,116, 97, 0, 73,112,111, 0, 75,101,121, 66,108,111, 99,107, 0, 75,101,
+121, 0, 83, 99,114,105,112,116, 76,105,110,107, 0, 84,101,120,116, 76,105,110,101, 0, 84,101,120,116, 0, 80, 97, 99,107,101,
+100, 70,105,108,101, 0, 67, 97,109,101,114, 97, 0, 73,109, 97,103,101, 0, 97,110,105,109, 0, 73,109, 66,117,102, 0, 77, 84,
+101,120, 0, 79, 98,106,101, 99,116, 0, 84,101,120, 0, 80,108,117,103,105,110, 84,101,120, 0, 67, 66, 68, 97,116, 97, 0, 67,
+111,108,111,114, 66, 97,110,100, 0, 69,110,118, 77, 97,112, 0, 76, 97,109,112, 0, 87, 97,118,101, 0, 77, 97,116,101,114,105,
+ 97,108, 0, 86, 70,111,110,116, 0, 86, 70,111,110,116, 68, 97,116, 97, 0, 77,101,116, 97, 69,108,101,109, 0, 66,111,117,110,
+100, 66,111,120, 0, 77,101,116, 97, 66, 97,108,108, 0, 66,101,122, 84,114,105,112,108,101, 0, 66, 80,111,105,110,116, 0, 78,
+117,114, 98, 0, 67,104, 97,114, 73,110,102,111, 0, 84,101,120,116, 66,111,120, 0, 67,117,114,118,101, 0, 80, 97,116,104, 0,
+ 73,112,111, 68,114,105,118,101,114, 0, 73,112,111, 67,117,114,118,101, 0, 84, 70, 97, 99,101, 0, 77,101,115,104, 0, 77, 70,
+ 97, 99,101, 0, 77, 86,101,114,116, 0, 77, 69,100,103,101, 0, 77, 68,101,102,111,114,109, 86,101,114,116, 0, 77, 67,111,108,
+ 0, 77, 83,116,105, 99,107,121, 0, 79, 99, 73,110,102,111, 0, 77, 68,101,102,111,114,109, 87,101,105,103,104,116, 0, 77,111,
+100,105,102,105,101,114, 68, 97,116, 97, 0, 83,117, 98,115,117,114,102, 77,111,100,105,102,105,101,114, 68, 97,116, 97, 0, 76,
+ 97,116,116,105, 99,101, 77,111,100,105,102,105,101,114, 68, 97,116, 97, 0, 67,117,114,118,101, 77,111,100,105,102,105,101,114,
+ 68, 97,116, 97, 0, 66,117,105,108,100, 77,111,100,105,102,105,101,114, 68, 97,116, 97, 0, 77,105,114,114,111,114, 77,111,100,
+105,102,105,101,114, 68, 97,116, 97, 0, 68,101, 99,105,109, 97,116,101, 77,111,100,105,102,105,101,114, 68, 97,116, 97, 0, 87,
+ 97,118,101, 77,111,100,105,102,105,101,114, 68, 97,116, 97, 0, 65,114,109, 97,116,117,114,101, 77,111,100,105,102,105,101,114,
+ 68, 97,116, 97, 0, 72,111,111,107, 77,111,100,105,102,105,101,114, 68, 97,116, 97, 0, 83,111,102,116, 98,111,100,121, 77,111,
+100,105,102,105,101,114, 68, 97,116, 97, 0, 66,111,111,108,101, 97,110, 77,111,100,105,102,105,101,114, 68, 97,116, 97, 0, 76,
+ 97,116,116,105, 99,101, 0, 98, 68,101,102,111,114,109, 71,114,111,117,112, 0, 76, 66,117,102, 0, 98, 65, 99,116,105,111,110,
+ 0, 98, 80,111,115,101, 0, 80, 97,114,116, 68,101,102,108,101, 99,116, 0, 83,111,102,116, 66,111,100,121, 0, 76,105,102,101,
+ 0, 70,108,117,105,100,115,105,109, 83,101,116,116,105,110,103,115, 0, 68,101,114,105,118,101,100, 77,101,115,104, 0, 79, 98,
+ 72,111,111,107, 0, 83, 66, 86,101,114,116,101,120, 0, 66,111,100,121, 80,111,105,110,116, 0, 66,111,100,121, 83,112,114,105,
+110,103, 0, 87,111,114,108,100, 0, 82, 97,100,105,111, 0, 66, 97,115,101, 0, 65,118,105, 67,111,100,101, 99, 68, 97,116, 97,
+ 0, 81,117,105, 99,107,116,105,109,101, 67,111,100,101, 99, 68, 97,116, 97, 0, 65,117,100,105,111, 68, 97,116, 97, 0, 82,101,
+110,100,101,114, 68, 97,116, 97, 0, 71, 97,109,101, 70,114, 97,109,105,110,103, 0, 84,105,109,101, 77, 97,114,107,101,114, 0,
+ 84,111,111,108, 83,101,116,116,105,110,103,115, 0, 83, 99,101,110,101, 0, 71,114,111,117,112, 0, 68, 97,103, 70,111,114,101,
+115,116, 0, 66, 71,112,105, 99, 0, 86,105,101,119, 51, 68, 0, 83,112, 97, 99,101, 76,105,110,107, 0, 83, 99,114, 65,114,101,
+ 97, 0, 86,105,101,119, 50, 68, 0, 83,112, 97, 99,101, 73,110,102,111, 0, 83,112, 97, 99,101, 73,112,111, 0, 83,112, 97, 99,
+101, 66,117,116,115, 0, 83,112, 97, 99,101, 83,101,113, 0, 83,112, 97, 99,101, 70,105,108,101, 0,100,105,114,101,110,116,114,
+121, 0, 66,108,101,110,100, 72, 97,110,100,108,101, 0, 83,112, 97, 99,101, 79,111,112,115, 0, 84,114,101,101, 83,116,111,114,
+101, 0, 83,112, 97, 99,101, 73,109, 97,103,101, 0, 83,112, 97, 99,101, 78,108, 97, 0, 83,112, 97, 99,101, 84,101,120,116, 0,
+ 83,112, 97, 99,101, 83, 99,114,105,112,116, 0, 83, 99,114,105,112,116, 0, 83,112, 97, 99,101, 84,105,109,101, 0, 83,112, 97,
+ 99,101, 73,109, 97, 83,101,108, 0, 73,109, 97, 68,105,114, 0, 79,110,101, 83,101,108,101, 99,116, 97, 98,108,101, 73,109, 97,
+ 0, 84,104,101,109,101, 85, 73, 0, 84,104,101,109,101, 83,112, 97, 99,101, 0, 98, 84,104,101,109,101, 0, 83,111,108,105,100,
+ 76,105,103,104,116, 0, 85,115,101,114, 68,101,102, 0, 98, 83, 99,114,101,101,110, 0, 83, 99,114, 86,101,114,116, 0, 83, 99,
+114, 69,100,103,101, 0, 80, 97,110,101,108, 0, 70,105,108,101, 71,108,111, 98, 97,108, 0, 83,116,114,105,112, 69,108,101,109,
+ 0, 83,116,114,105,112, 0, 80,108,117,103,105,110, 83,101,113, 0, 83,101,113,117,101,110, 99,101, 0, 98, 83,111,117,110,100,
+ 0, 77,101,116, 97, 83,116, 97, 99,107, 0, 69,100,105,116,105,110,103, 0, 87,105,112,101, 86, 97,114,115, 0, 71,108,111,119,
+ 86, 97,114,115, 0, 69,102,102,101, 99,116, 0, 66,117,105,108,100, 69,102,102, 0, 80, 97,114,116, 69,102,102, 0, 80, 97,114,
+116,105, 99,108,101, 0, 87, 97,118,101, 69,102,102, 0, 84,114,101,101, 83,116,111,114,101, 69,108,101,109, 0, 79,111,112,115,
+ 0, 98, 80,114,111,112,101,114,116,121, 0, 98, 78,101, 97,114, 83,101,110,115,111,114, 0, 98, 77,111,117,115,101, 83,101,110,
+115,111,114, 0, 98, 84,111,117, 99,104, 83,101,110,115,111,114, 0, 98, 75,101,121, 98,111, 97,114,100, 83,101,110,115,111,114,
+ 0, 98, 80,114,111,112,101,114,116,121, 83,101,110,115,111,114, 0, 98, 67,111,108,108,105,115,105,111,110, 83,101,110,115,111,
+114, 0, 98, 82, 97,100, 97,114, 83,101,110,115,111,114, 0, 98, 82, 97,110,100,111,109, 83,101,110,115,111,114, 0, 98, 82, 97,
+121, 83,101,110,115,111,114, 0, 98, 77,101,115,115, 97,103,101, 83,101,110,115,111,114, 0, 98, 83,101,110,115,111,114, 0, 98,
+ 67,111,110,116,114,111,108,108,101,114, 0, 98, 74,111,121,115,116,105, 99,107, 83,101,110,115,111,114, 0, 98, 69,120,112,114,
+101,115,115,105,111,110, 67,111,110,116, 0, 98, 80,121,116,104,111,110, 67,111,110,116, 0, 98, 65, 99,116,117, 97,116,111,114,
+ 0, 98, 65,100,100, 79, 98,106,101, 99,116, 65, 99,116,117, 97,116,111,114, 0, 98, 65, 99,116,105,111,110, 65, 99,116,117, 97,
+116,111,114, 0, 98, 83,111,117,110,100, 65, 99,116,117, 97,116,111,114, 0, 98, 67, 68, 65, 99,116,117, 97,116,111,114, 0, 98,
+ 69,100,105,116, 79, 98,106,101, 99,116, 65, 99,116,117, 97,116,111,114, 0, 98, 83, 99,101,110,101, 65, 99,116,117, 97,116,111,
+114, 0, 98, 80,114,111,112,101,114,116,121, 65, 99,116,117, 97,116,111,114, 0, 98, 79, 98,106,101, 99,116, 65, 99,116,117, 97,
+116,111,114, 0, 98, 73,112,111, 65, 99,116,117, 97,116,111,114, 0, 98, 67, 97,109,101,114, 97, 65, 99,116,117, 97,116,111,114,
+ 0, 98, 67,111,110,115,116,114, 97,105,110,116, 65, 99,116,117, 97,116,111,114, 0, 98, 71,114,111,117,112, 65, 99,116,117, 97,
+116,111,114, 0, 98, 82, 97,110,100,111,109, 65, 99,116,117, 97,116,111,114, 0, 98, 77,101,115,115, 97,103,101, 65, 99,116,117,
+ 97,116,111,114, 0, 98, 71, 97,109,101, 65, 99,116,117, 97,116,111,114, 0, 98, 86,105,115,105, 98,105,108,105,116,121, 65, 99,
+116,117, 97,116,111,114, 0, 70,114,101,101, 67, 97,109,101,114, 97, 0, 98, 83, 97,109,112,108,101, 0, 98, 83,111,117,110,100,
+ 76,105,115,116,101,110,101,114, 0, 83,112, 97, 99,101, 83,111,117,110,100, 0, 71,114,111,117,112, 75,101,121, 0, 79, 98,106,
+101, 99,116, 75,101,121, 0, 71,114,111,117,112, 79, 98,106,101, 99,116, 0, 66,111,110,101, 0, 98, 65,114,109, 97,116,117,114,
+101, 0, 98, 80,111,115,101, 67,104, 97,110,110,101,108, 0, 98, 65, 99,116,105,111,110, 67,104, 97,110,110,101,108, 0, 83,112,
+ 97, 99,101, 65, 99,116,105,111,110, 0, 98, 67,111,110,115,116,114, 97,105,110,116, 67,104, 97,110,110,101,108, 0, 98, 67,111,
+110,115,116,114, 97,105,110,116, 0, 98, 75,105,110,101,109, 97,116,105, 99, 67,111,110,115,116,114, 97,105,110,116, 0, 98, 84,
+114, 97, 99,107, 84,111, 67,111,110,115,116,114, 97,105,110,116, 0, 98, 82,111,116, 97,116,101, 76,105,107,101, 67,111,110,115,
+116,114, 97,105,110,116, 0, 98, 76,111, 99, 97,116,101, 76,105,107,101, 67,111,110,115,116,114, 97,105,110,116, 0, 98, 77,105,
+110, 77, 97,120, 67,111,110,115,116,114, 97,105,110,116, 0, 98, 65, 99,116,105,111,110, 67,111,110,115,116,114, 97,105,110,116,
+ 0, 98, 76,111, 99,107, 84,114, 97, 99,107, 67,111,110,115,116,114, 97,105,110,116, 0, 98, 70,111,108,108,111,119, 80, 97,116,
+104, 67,111,110,115,116,114, 97,105,110,116, 0, 98, 68,105,115,116, 97,110, 99,101, 76,105,109,105,116, 67,111,110,115,116,114,
+ 97,105,110,116, 0, 98, 82,111,116, 97,116,105,111,110, 67,111,110,115,116,114, 97,105,110,116, 0, 98, 83,116,114,101,116, 99,
+104, 84,111, 67,111,110,115,116,114, 97,105,110,116, 0, 98, 65, 99,116,105,111,110, 83,116,114,105,112, 0, 0, 84, 76, 69, 78,
+ 1, 0, 1, 0, 2, 0, 2, 0, 4, 0, 4, 0, 4, 0, 4, 0, 8, 0, 0, 0, 8, 0, 8, 0, 4, 0, 8, 0, 8, 0, 16, 0,
+ 12, 0, 12, 0, 24, 0, 16, 0, 16, 0, 32, 0, 16, 0, 16, 0, 48, 0,224, 0, 0, 0, 80, 0,104, 0,116, 0, 16, 0, 24, 0,
+100, 0, 20, 0,116, 0, 48, 1, 0, 0, 0, 0, 88, 0,244, 2,228, 0, 80, 1, 24, 0,136, 1,128, 0,252, 0, 52, 0,156, 1,
+ 64, 1, 0, 0,108, 0, 96, 0,132, 0, 56, 0, 28, 0, 56, 0, 8, 0, 16, 0, 44, 1, 0, 0,140, 0, 84, 0, 60, 0,188, 0,
+ 20, 0, 20, 0, 12, 0, 12, 0, 4, 0, 8, 0, 24, 0, 8, 0, 52, 0, 68, 0, 88, 0, 88, 0, 68, 0, 60, 0, 60, 0, 92, 0,
+ 64, 0,180, 0, 52, 0, 64, 0,108, 0, 40, 0, 12, 0, 56, 0, 24, 0, 44, 0, 92, 0, 0, 0, 84, 1, 0, 0,208, 0, 16, 0,
+ 0, 0, 0, 0, 32, 1, 40, 0, 28, 0,176, 0,144, 0, 16, 0, 16, 3, 16, 0, 80, 0, 28, 0,244, 3, 68, 0, 0, 0, 36, 0,
+180, 2, 36, 0,204, 0,120, 0, 36, 0, 40, 1,212, 0,164, 0, 84, 1, 0, 0, 0, 0,196, 0, 12, 0,184, 0,164, 0,120, 0,
+ 32, 0, 0, 0,148, 0,224, 2, 0, 0, 0, 0, 72, 0,136, 0,224, 7, 56, 0,168, 7,116, 0, 20, 0, 24, 0,164, 0, 24, 0,
+104, 0,188, 0,160, 1,172, 0, 32, 1, 16, 0, 28, 0, 12, 0, 24, 0, 16, 0, 24, 0,236, 0, 0, 0, 56, 0, 12, 0, 44, 0,
+ 64, 0, 48, 0, 8, 0, 44, 0, 72, 0,104, 0, 72, 0, 44, 0, 40, 0,108, 0, 68, 0, 76, 0, 80, 0, 64, 0,128, 0, 4, 0,
+ 60, 0, 12, 0, 60, 0, 20, 0, 16, 0, 64, 0, 16, 0, 76, 0,120, 0, 48, 0, 28, 0, 56, 0, 52, 0, 56, 0,108, 0,136, 0,
+ 4, 0, 40, 0, 0, 0, 64, 0,160, 0, 48, 0,112, 1, 20, 0, 4, 1, 80, 0, 68, 1, 60, 0,176, 0, 44, 0, 52, 0, 76, 0,
+ 44, 0, 44, 0, 44, 0, 60, 0, 56, 0, 44, 0, 20, 0, 60, 0, 24, 0, 52, 0, 88, 0, 0, 0, 83, 84, 82, 67,192, 0, 0, 0,
+ 10, 0, 2, 0, 10, 0, 0, 0, 10, 0, 1, 0, 11, 0, 2, 0, 9, 0, 2, 0, 9, 0, 3, 0, 12, 0, 2, 0, 2, 0, 4, 0,
+ 2, 0, 5, 0, 13, 0, 2, 0, 4, 0, 4, 0, 4, 0, 5, 0, 14, 0, 2, 0, 7, 0, 4, 0, 7, 0, 5, 0, 15, 0, 2, 0,
+ 8, 0, 4, 0, 8, 0, 5, 0, 16, 0, 3, 0, 4, 0, 4, 0, 4, 0, 5, 0, 4, 0, 6, 0, 17, 0, 3, 0, 7, 0, 4, 0,
+ 7, 0, 5, 0, 7, 0, 6, 0, 18, 0, 3, 0, 8, 0, 4, 0, 8, 0, 5, 0, 8, 0, 6, 0, 19, 0, 4, 0, 4, 0, 4, 0,
+ 4, 0, 5, 0, 4, 0, 6, 0, 4, 0, 7, 0, 20, 0, 4, 0, 7, 0, 4, 0, 7, 0, 5, 0, 7, 0, 6, 0, 7, 0, 7, 0,
+ 21, 0, 4, 0, 8, 0, 4, 0, 8, 0, 5, 0, 8, 0, 6, 0, 8, 0, 7, 0, 22, 0, 4, 0, 4, 0, 8, 0, 4, 0, 9, 0,
+ 4, 0, 10, 0, 4, 0, 11, 0, 23, 0, 4, 0, 7, 0, 8, 0, 7, 0, 9, 0, 7, 0, 10, 0, 7, 0, 11, 0, 24, 0, 8, 0,
+ 9, 0, 0, 0, 9, 0, 1, 0, 24, 0, 12, 0, 25, 0, 13, 0, 0, 0, 14, 0, 2, 0, 15, 0, 2, 0, 16, 0, 4, 0, 17, 0,
+ 25, 0, 6, 0, 24, 0, 18, 0, 24, 0, 19, 0, 26, 0, 20, 0, 0, 0, 21, 0, 4, 0, 22, 0, 4, 0, 17, 0, 27, 0, 6, 0,
+ 24, 0, 18, 0, 11, 0, 23, 0, 23, 0, 24, 0, 2, 0, 25, 0, 2, 0, 26, 0, 4, 0, 17, 0, 28, 0, 13, 0, 28, 0, 0, 0,
+ 28, 0, 1, 0, 7, 0, 27, 0, 7, 0, 28, 0, 2, 0, 29, 0, 2, 0, 30, 0, 4, 0, 31, 0, 9, 0, 32, 0, 7, 0, 33, 0,
+ 0, 0, 34, 0, 0, 0, 35, 0, 7, 0, 36, 0, 7, 0, 37, 0, 29, 0, 12, 0, 24, 0, 18, 0, 28, 0, 38, 0, 0, 0, 39, 0,
+ 4, 0, 40, 0, 7, 0, 28, 0, 11, 0, 41, 0, 27, 0, 42, 0, 24, 0, 43, 0, 2, 0, 29, 0, 2, 0, 44, 0, 2, 0, 45, 0,
+ 2, 0, 16, 0, 30, 0, 5, 0, 24, 0, 46, 0, 2, 0, 47, 0, 2, 0, 48, 0, 2, 0, 49, 0, 4, 0, 17, 0, 31, 0, 6, 0,
+ 31, 0, 0, 0, 31, 0, 1, 0, 0, 0, 50, 0, 0, 0, 51, 0, 4, 0, 52, 0, 4, 0, 53, 0, 32, 0, 13, 0, 24, 0, 18, 0,
+ 0, 0, 54, 0, 4, 0, 55, 0, 4, 0, 56, 0, 11, 0, 57, 0, 31, 0, 58, 0, 31, 0, 59, 0, 4, 0, 60, 0, 4, 0, 61, 0,
+ 0, 0, 62, 0, 4, 0, 63, 0, 4, 0, 64, 0, 9, 0, 65, 0, 33, 0, 5, 0, 4, 0, 66, 0, 4, 0, 67, 0, 4, 0, 55, 0,
+ 4, 0, 17, 0, 9, 0, 32, 0, 34, 0, 17, 0, 24, 0, 18, 0, 2, 0, 29, 0, 2, 0, 16, 0, 7, 0, 68, 0, 7, 0, 69, 0,
+ 7, 0, 70, 0, 7, 0, 71, 0, 7, 0, 72, 0, 7, 0, 73, 0, 7, 0, 74, 0, 7, 0, 75, 0, 7, 0, 76, 0, 2, 0, 77, 0,
+ 2, 0, 78, 0, 7, 0, 79, 0, 27, 0, 42, 0, 30, 0, 80, 0, 35, 0, 23, 0, 24, 0, 18, 0, 0, 0, 21, 0, 36, 0, 81, 0,
+ 37, 0, 82, 0, 37, 0, 83, 0, 2, 0, 84, 0, 2, 0, 16, 0, 2, 0, 85, 0, 2, 0, 86, 0, 2, 0, 87, 0, 2, 0, 88, 0,
+ 2, 0, 89, 0, 2, 0, 90, 0, 2, 0, 91, 0, 2, 0, 92, 0, 4, 0, 93, 0, 4, 0, 94, 0, 33, 0, 95, 0, 7, 0, 96, 0,
+ 4, 0, 97, 0, 2, 0, 98, 0, 2, 0, 99, 0, 4, 0,100, 0, 38, 0, 24, 0, 2, 0,101, 0, 2, 0,102, 0, 2, 0,103, 0,
+ 2, 0,104, 0, 39, 0,105, 0, 40, 0,106, 0, 0, 0,107, 0, 0, 0,108, 0, 0, 0,109, 0, 0, 0,110, 0, 7, 0,111, 0,
+ 7, 0,112, 0, 2, 0,113, 0, 2, 0,114, 0, 7, 0,115, 0, 7, 0,116, 0, 7, 0,117, 0, 7, 0,118, 0, 7, 0,119, 0,
+ 7, 0,120, 0, 7, 0,121, 0, 7, 0,122, 0, 7, 0,123, 0, 7, 0,124, 0, 41, 0, 14, 0, 0, 0, 21, 0, 9, 0,125, 0,
+ 0, 0,126, 0, 0, 0,127, 0, 4, 0,128, 0, 4, 0,129, 0, 9, 0,130, 0, 7, 0,131, 0, 7, 0,132, 0, 7, 0,133, 0,
+ 4, 0,134, 0, 9, 0,135, 0, 4, 0,136, 0, 4, 0, 17, 0, 42, 0, 6, 0, 7, 0,115, 0, 7, 0,116, 0, 7, 0,117, 0,
+ 7, 0,137, 0, 7, 0, 27, 0, 4, 0, 24, 0, 43, 0, 5, 0, 2, 0, 16, 0, 2, 0, 22, 0, 2, 0, 24, 0, 2, 0,138, 0,
+ 42, 0,139, 0, 44, 0, 16, 0, 39, 0,105, 0, 35, 0,140, 0, 35, 0,141, 0, 7, 0,142, 0, 2, 0, 29, 0, 2, 0,143, 0,
+ 7, 0, 70, 0, 7, 0, 71, 0, 4, 0,144, 0, 2, 0,145, 0, 2, 0,146, 0, 2, 0, 84, 0, 2, 0, 85, 0, 2, 0,147, 0,
+ 2, 0,148, 0, 4, 0, 69, 0, 40, 0, 52, 0, 24, 0, 18, 0, 7, 0,149, 0, 7, 0,150, 0, 7, 0,151, 0, 7, 0,152, 0,
+ 7, 0,153, 0, 7, 0,154, 0, 7, 0,155, 0, 7, 0,156, 0, 7, 0,157, 0, 7, 0,158, 0, 7, 0,159, 0, 7, 0,160, 0,
+ 7, 0,161, 0, 7, 0,162, 0, 7, 0,163, 0, 7, 0,164, 0, 7, 0,165, 0, 7, 0,166, 0, 7, 0,167, 0, 7, 0,168, 0,
+ 2, 0,169, 0, 2, 0,170, 0, 2, 0,171, 0, 2, 0,172, 0, 2, 0,173, 0, 2, 0,174, 0, 2, 0,175, 0, 2, 0, 16, 0,
+ 2, 0, 29, 0, 2, 0,143, 0, 7, 0,176, 0, 7, 0,177, 0, 7, 0,178, 0, 7, 0,179, 0, 2, 0,180, 0, 2, 0,181, 0,
+ 2, 0,182, 0, 2, 0, 52, 0, 7, 0,183, 0, 7, 0,184, 0, 2, 0,185, 0, 2, 0,186, 0, 2, 0,187, 0, 2, 0,188, 0,
+ 7, 0,121, 0, 27, 0, 42, 0, 35, 0,140, 0, 41, 0,189, 0, 43, 0,190, 0, 44, 0,191, 0, 2, 0,192, 0, 45, 0, 50, 0,
+ 24, 0, 18, 0, 2, 0, 29, 0, 2, 0,193, 0, 2, 0,114, 0, 2, 0,194, 0, 7, 0,115, 0, 7, 0,116, 0, 7, 0,117, 0,
+ 7, 0,118, 0, 7, 0,195, 0, 7, 0,196, 0, 7, 0,197, 0, 7, 0,198, 0, 7, 0,199, 0, 7, 0,200, 0, 7, 0,201, 0,
+ 2, 0,202, 0, 2, 0,203, 0, 7, 0, 70, 0, 7, 0, 71, 0, 7, 0,204, 0, 7, 0,205, 0, 7, 0,206, 0, 2, 0,207, 0,
+ 2, 0,208, 0, 2, 0,209, 0, 2, 0,210, 0, 2, 0,211, 0, 2, 0, 17, 0, 7, 0,212, 0, 7, 0,213, 0, 7, 0,214, 0,
+ 2, 0,215, 0, 2, 0,216, 0, 4, 0,217, 0, 4, 0,218, 0, 2, 0,219, 0, 2, 0,220, 0, 2, 0,221, 0, 2, 0,222, 0,
+ 7, 0,223, 0, 7, 0,224, 0, 7, 0,225, 0, 7, 0,226, 0, 7, 0,227, 0, 2, 0,228, 0, 2, 0,229, 0, 38, 0,230, 0,
+ 27, 0, 42, 0, 30, 0, 80, 0, 46, 0, 2, 0, 24, 0, 18, 0, 27, 0, 42, 0, 47, 0, 95, 0, 24, 0, 18, 0, 2, 0,114, 0,
+ 2, 0,231, 0, 7, 0,115, 0, 7, 0,116, 0, 7, 0,117, 0, 7, 0,232, 0, 7, 0,233, 0, 7, 0,234, 0, 7, 0,235, 0,
+ 7, 0,236, 0, 7, 0,237, 0, 7, 0,238, 0, 7, 0,239, 0, 7, 0,240, 0, 7, 0,241, 0, 7, 0,242, 0, 7, 0,243, 0,
+ 7, 0,244, 0, 7, 0,245, 0, 7, 0,246, 0, 7, 0,247, 0, 7, 0,248, 0, 7, 0,249, 0, 7, 0,250, 0, 7, 0,251, 0,
+ 7, 0,252, 0, 7, 0,253, 0, 7, 0,254, 0, 7, 0,255, 0, 7, 0, 0, 1, 2, 0, 1, 1, 2, 0, 2, 1, 2, 0, 3, 1,
+ 0, 0, 4, 1, 0, 0, 5, 1, 4, 0,193, 0, 4, 0, 6, 1, 2, 0, 7, 1, 2, 0, 8, 1, 2, 0, 9, 1, 2, 0, 10, 1,
+ 7, 0, 11, 1, 7, 0, 12, 1, 7, 0, 13, 1, 7, 0, 14, 1, 7, 0, 15, 1, 7, 0, 16, 1, 7, 0, 17, 1, 0, 0, 18, 1,
+ 0, 0,215, 0, 0, 0, 19, 1, 0, 0, 17, 0, 2, 0, 20, 1, 2, 0, 21, 1, 2, 0, 22, 1, 2, 0, 23, 1, 4, 0, 24, 1,
+ 2, 0, 25, 1, 2, 0, 26, 1, 7, 0, 27, 1, 7, 0, 28, 1, 7, 0, 29, 1, 7, 0, 30, 1, 7, 0, 31, 1, 2, 0,101, 0,
+ 2, 0,102, 0, 43, 0, 32, 1, 43, 0, 33, 1, 0, 0, 34, 1, 0, 0, 35, 1, 0, 0, 36, 1, 0, 0, 37, 1, 2, 0, 38, 1,
+ 2, 0, 39, 1, 7, 0, 40, 1, 7, 0, 41, 1, 38, 0,230, 0, 27, 0, 42, 0, 7, 0, 42, 1, 7, 0, 43, 1, 7, 0, 44, 1,
+ 7, 0, 45, 1, 7, 0, 46, 1, 2, 0, 47, 1, 2, 0, 48, 1, 7, 0, 49, 1, 7, 0, 50, 1, 7, 0, 51, 1, 7, 0, 52, 1,
+ 7, 0, 53, 1, 4, 0, 54, 1, 4, 0, 55, 1, 4, 0, 56, 1, 30, 0, 80, 0, 48, 0, 6, 0, 24, 0, 18, 0, 0, 0, 57, 1,
+ 7, 0, 58, 1, 7, 0, 17, 0, 49, 0, 32, 0, 33, 0, 95, 0, 50, 0, 26, 0, 50, 0, 0, 0, 50, 0, 1, 0, 51, 0, 59, 1,
+ 4, 0, 60, 1, 4, 0, 61, 1, 4, 0, 62, 1, 4, 0, 63, 1, 4, 0, 64, 1, 4, 0, 65, 1, 2, 0, 29, 0, 2, 0, 16, 0,
+ 2, 0, 66, 1, 2, 0, 67, 1, 7, 0, 4, 0, 7, 0, 5, 0, 7, 0, 6, 0, 7, 0, 68, 1, 7, 0, 69, 1, 7, 0, 70, 1,
+ 7, 0, 71, 1, 7, 0, 72, 1, 7, 0, 73, 1, 7, 0, 74, 1, 7, 0, 52, 0, 7, 0, 75, 1, 7, 0, 76, 1, 52, 0, 15, 0,
+ 24, 0, 18, 0, 51, 0, 59, 1, 11, 0, 77, 1, 11, 0, 78, 1, 27, 0, 42, 0, 47, 0, 79, 1, 2, 0, 16, 0, 2, 0, 80, 1,
+ 4, 0,113, 0, 7, 0, 81, 1, 7, 0,112, 0, 7, 0, 82, 1, 7, 0, 83, 1, 7, 0, 84, 1, 7, 0, 85, 1, 53, 0, 10, 0,
+ 7, 0, 86, 1, 7, 0, 87, 1, 7, 0, 88, 1, 7, 0, 17, 0, 2, 0, 89, 1, 2, 0, 90, 1, 0, 0, 91, 1, 0, 0, 92, 1,
+ 0, 0, 93, 1, 0, 0, 94, 1, 54, 0, 5, 0, 7, 0, 95, 1, 7, 0, 87, 1, 7, 0, 88, 1, 2, 0, 91, 1, 2, 0, 94, 1,
+ 55, 0, 20, 0, 55, 0, 0, 0, 55, 0, 1, 0, 2, 0, 29, 0, 2, 0, 96, 1, 2, 0, 94, 1, 2, 0, 16, 0, 2, 0, 97, 1,
+ 2, 0, 98, 1, 2, 0, 99, 1, 2, 0,100, 1, 2, 0,101, 1, 2, 0,102, 1, 2, 0,103, 1, 2, 0,104, 1, 7, 0,105, 1,
+ 7, 0,106, 1, 54, 0,107, 1, 53, 0,108, 1, 4, 0,109, 1, 4, 0, 17, 0, 56, 0, 5, 0, 2, 0,110, 1, 2, 0, 96, 1,
+ 0, 0, 16, 0, 0, 0, 17, 0, 2, 0, 48, 1, 57, 0, 4, 0, 7, 0, 4, 0, 7, 0, 5, 0, 7, 0, 7, 0, 7, 0,111, 1,
+ 58, 0, 54, 0, 24, 0, 18, 0, 51, 0, 59, 1, 11, 0,112, 1, 11, 0, 78, 1, 39, 0,113, 1, 39, 0,114, 1, 39, 0,115, 1,
+ 27, 0, 42, 0, 59, 0,116, 1, 29, 0,117, 1, 47, 0, 79, 1, 11, 0,118, 1, 7, 0, 81, 1, 7, 0,112, 0, 7, 0, 82, 1,
+ 4, 0,113, 0, 2, 0,119, 1, 2, 0, 80, 1, 2, 0, 16, 0, 2, 0,120, 1, 7, 0,121, 1, 7, 0,122, 1, 7, 0,123, 1,
+ 2, 0, 99, 1, 2, 0,100, 1, 2, 0, 52, 0, 2, 0, 57, 0, 2, 0, 27, 0, 2, 0,124, 1, 7, 0,125, 1, 7, 0,126, 1,
+ 7, 0,127, 1, 7, 0,128, 1, 7, 0,129, 1, 7, 0,130, 1, 7, 0,131, 1, 7, 0,132, 1, 7, 0,133, 1, 7, 0,134, 1,
+ 0, 0,135, 1, 0, 0,136, 1, 48, 0,137, 1, 48, 0,138, 1, 48, 0,139, 1, 48, 0,140, 1, 4, 0,141, 1, 4, 0,142, 1,
+ 4, 0,143, 1, 4, 0, 17, 0, 57, 0,144, 1, 4, 0,145, 1, 4, 0,146, 1, 56, 0,147, 1, 56, 0,148, 1, 60, 0, 6, 0,
+ 39, 0,149, 1, 2, 0, 25, 0, 2, 0, 30, 0, 2, 0, 29, 0, 2, 0, 16, 0, 0, 0,150, 1, 61, 0, 19, 0, 61, 0, 0, 0,
+ 61, 0, 1, 0, 54, 0,107, 1, 53, 0,108, 1, 23, 0,151, 1, 23, 0,152, 1, 2, 0, 25, 0, 2, 0, 30, 0, 2, 0,153, 1,
+ 2, 0,154, 1, 2, 0,155, 1, 2, 0,156, 1, 2, 0, 16, 0, 2, 0,157, 1, 7, 0, 10, 0, 7, 0, 11, 0, 4, 0,158, 1,
+ 7, 0, 28, 0, 60, 0,159, 1, 62, 0, 8, 0, 9, 0,160, 1, 7, 0,161, 1, 4, 0,162, 1, 0, 0, 16, 0, 0, 0,163, 1,
+ 2, 0,193, 0, 2, 0,164, 1, 2, 0,165, 1, 63, 0, 32, 0, 24, 0, 18, 0, 51, 0, 59, 1, 11, 0,166, 1, 27, 0, 42, 0,
+ 29, 0,117, 1, 47, 0, 79, 1, 64, 0,167, 1, 62, 0,168, 1, 9, 0,169, 1, 65, 0,170, 1, 66, 0,171, 1, 67, 0,172, 1,
+ 68, 0,173, 1, 69, 0,174, 1, 63, 0,175, 1, 70, 0,176, 1, 9, 0,177, 1, 4, 0,154, 1, 4, 0,178, 1, 4, 0,179, 1,
+ 4, 0,113, 0, 7, 0, 81, 1, 7, 0,112, 0, 7, 0, 82, 1, 7, 0,180, 1, 7, 0, 17, 0, 2, 0,181, 1, 2, 0, 16, 0,
+ 2, 0,182, 1, 2, 0,183, 1, 2, 0, 80, 1, 2, 0,184, 1, 64, 0, 8, 0, 4, 0,185, 1, 4, 0,186, 1, 4, 0,187, 1,
+ 4, 0,188, 1, 0, 0, 17, 0, 0, 0, 96, 1, 0, 0,189, 1, 0, 0, 16, 0, 66, 0, 5, 0, 4, 0,185, 1, 4, 0,186, 1,
+ 0, 0,190, 1, 0, 0, 17, 0, 2, 0, 16, 0, 71, 0, 2, 0, 4, 0,191, 1, 7, 0, 88, 1, 67, 0, 3, 0, 71, 0,192, 1,
+ 4, 0,193, 1, 4, 0, 16, 0, 65, 0, 4, 0, 7, 0,194, 1, 2, 0,195, 1, 0, 0, 16, 0, 0, 0, 96, 1, 68, 0, 4, 0,
+ 0, 0,137, 0, 0, 0,115, 0, 0, 0,116, 0, 0, 0,117, 0, 69, 0, 1, 0, 7, 0,196, 1, 72, 0, 6, 0, 72, 0, 0, 0,
+ 72, 0, 1, 0, 4, 0, 29, 0, 4, 0,193, 0, 0, 0, 34, 0, 0, 0,197, 1, 73, 0, 7, 0, 72, 0,198, 1, 2, 0,199, 1,
+ 2, 0,200, 1, 2, 0,201, 1, 2, 0, 55, 0, 9, 0,202, 1, 9, 0,203, 1, 74, 0, 3, 0, 72, 0,198, 1, 39, 0,105, 0,
+ 0, 0, 34, 0, 75, 0, 3, 0, 72, 0,198, 1, 39, 0,105, 0, 0, 0, 34, 0, 76, 0, 5, 0, 72, 0,198, 1, 7, 0,204, 1,
+ 7, 0,205, 1, 4, 0,206, 1, 4, 0,207, 1, 77, 0, 4, 0, 72, 0,198, 1, 2, 0,208, 1, 2, 0, 16, 0, 7, 0,209, 1,
+ 78, 0, 3, 0, 72, 0,198, 1, 7, 0,210, 1, 4, 0,211, 1, 79, 0, 12, 0, 72, 0,198, 1, 2, 0, 16, 0, 2, 0, 17, 0,
+ 7, 0,212, 1, 7, 0,213, 1, 7, 0,214, 1, 7, 0,121, 1, 7, 0,215, 1, 7, 0,216, 1, 7, 0,217, 1, 7, 0,218, 1,
+ 7, 0,219, 1, 80, 0, 5, 0, 72, 0,198, 1, 2, 0,220, 1, 2, 0, 69, 0, 4, 0, 48, 1, 39, 0,105, 0, 81, 0, 9, 0,
+ 72, 0,198, 1, 39, 0,105, 0, 7, 0,221, 1, 7, 0,222, 1, 7, 0,223, 1, 4, 0,224, 1, 4, 0,225, 1, 7, 0,226, 1,
+ 0, 0, 34, 0, 82, 0, 1, 0, 72, 0,198, 1, 83, 0, 4, 0, 72, 0,198, 1, 39, 0,105, 0, 4, 0,227, 1, 4, 0, 17, 0,
+ 84, 0, 23, 0, 24, 0, 18, 0, 2, 0, 97, 1, 2, 0, 98, 1, 2, 0,228, 1, 2, 0, 16, 0, 2, 0,229, 1, 2, 0,230, 1,
+ 2, 0,231, 1, 2, 0, 48, 1, 0, 0,232, 1, 0, 0,233, 1, 0, 0,234, 1, 0, 0, 29, 0, 4, 0, 17, 0, 7, 0,235, 1,
+ 7, 0,236, 1, 7, 0,237, 1, 7, 0,238, 1, 7, 0,239, 1, 7, 0,240, 1, 54, 0,241, 1, 27, 0, 42, 0, 29, 0,117, 1,
+ 85, 0, 3, 0, 85, 0, 0, 0, 85, 0, 1, 0, 0, 0, 34, 0, 51, 0, 1, 0, 7, 0,242, 1, 70, 0, 2, 0, 7, 0,243, 1,
+ 7, 0,112, 0, 86, 0, 4, 0, 2, 0, 22, 0, 2, 0,244, 1, 4, 0, 17, 0, 39, 0,245, 1, 39, 0, 95, 0, 24, 0, 18, 0,
+ 2, 0, 29, 0, 2, 0,246, 1, 4, 0,247, 1, 4, 0,248, 1, 4, 0,249, 1, 0, 0,250, 1, 9, 0,251, 1, 39, 0,252, 1,
+ 39, 0,253, 1, 27, 0, 42, 0, 59, 0,116, 1, 51, 0, 59, 1, 87, 0,254, 1, 88, 0,255, 1, 9, 0, 32, 0, 11, 0, 0, 2,
+ 11, 0,166, 1, 11, 0, 1, 2, 11, 0, 78, 1, 11, 0, 2, 2, 11, 0, 3, 2, 47, 0, 79, 1, 7, 0, 81, 1, 7, 0, 4, 2,
+ 7, 0, 5, 2, 7, 0,112, 0, 7, 0, 6, 2, 7, 0, 82, 1, 7, 0, 7, 2, 7, 0, 68, 1, 7, 0, 8, 2, 7, 0, 9, 2,
+ 7, 0,221, 1, 7, 0,142, 0, 4, 0,231, 0, 2, 0, 16, 0, 2, 0, 10, 2, 2, 0, 11, 2, 2, 0, 12, 2, 2, 0, 13, 2,
+ 2, 0, 14, 2, 2, 0, 15, 2, 2, 0, 16, 2, 2, 0, 17, 2, 2, 0, 18, 2, 2, 0, 19, 2, 2, 0, 20, 2, 2, 0, 21, 2,
+ 2, 0, 22, 2, 2, 0, 23, 2, 2, 0, 24, 2, 7, 0, 25, 2, 7, 0, 26, 2, 7, 0, 27, 2, 7, 0, 28, 2, 7, 0, 29, 2,
+ 7, 0, 30, 2, 7, 0, 31, 2, 7, 0, 32, 2, 7, 0, 33, 2, 0, 0, 34, 2, 0, 0, 35, 2, 0, 0, 80, 1, 0, 0, 36, 2,
+ 30, 0, 80, 0, 11, 0, 37, 2, 11, 0, 38, 2, 11, 0, 39, 2, 11, 0, 40, 2, 9, 0,177, 1, 7, 0, 41, 2, 2, 0, 42, 2,
+ 2, 0, 43, 2, 7, 0,162, 1, 4, 0, 44, 2, 4, 0, 45, 2, 2, 0, 46, 2, 2, 0,147, 0, 7, 0, 47, 2, 11, 0, 48, 2,
+ 11, 0, 49, 2, 11, 0, 50, 2, 89, 0, 51, 2, 90, 0, 52, 2, 91, 0, 53, 2, 86, 0, 54, 2, 86, 0, 55, 2, 2, 0, 56, 2,
+ 0, 0, 57, 2, 0, 0, 58, 2, 7, 0,181, 1, 92, 0, 59, 2, 93, 0, 60, 2, 93, 0, 61, 2, 94, 0, 14, 0, 94, 0, 0, 0,
+ 94, 0, 1, 0, 39, 0,252, 1, 7, 0,221, 1, 7, 0, 62, 2, 7, 0,222, 1, 7, 0,223, 1, 0, 0, 34, 0, 4, 0,224, 1,
+ 4, 0,225, 1, 4, 0, 63, 2, 2, 0, 29, 0, 2, 0, 64, 2, 7, 0,226, 1, 89, 0, 13, 0, 2, 0, 65, 2, 2, 0, 66, 2,
+ 2, 0, 16, 0, 2, 0, 17, 0, 7, 0, 67, 2, 7, 0, 68, 2, 7, 0, 69, 2, 7, 0, 70, 2, 7, 0, 71, 2, 7, 0, 72, 2,
+ 7, 0, 73, 2, 7, 0, 74, 2, 7, 0, 75, 2, 95, 0, 1, 0, 7, 0, 95, 1, 90, 0, 26, 0, 4, 0, 76, 2, 4, 0, 77, 2,
+ 96, 0, 78, 2, 97, 0, 79, 2, 7, 0, 26, 2, 7, 0, 80, 2, 7, 0, 81, 2, 7, 0, 82, 2, 7, 0, 83, 2, 7, 0, 84, 2,
+ 7, 0, 85, 2, 7, 0, 86, 2, 7, 0, 87, 2, 7, 0, 88, 2, 7, 0, 89, 2, 2, 0, 90, 2, 2, 0, 69, 0, 7, 0, 91, 2,
+ 7, 0, 92, 2, 2, 0,187, 0, 2, 0, 93, 2, 2, 0, 94, 2, 2, 0, 48, 1, 95, 0, 95, 2, 4, 0, 96, 2, 4, 0, 44, 0,
+ 92, 0, 26, 0, 2, 0, 29, 0, 2, 0, 97, 2, 2, 0, 98, 2, 2, 0, 99, 2, 7, 0,100, 2, 2, 0,101, 2, 2, 0,102, 2,
+ 7, 0,103, 2, 2, 0,104, 2, 2, 0,105, 2, 7, 0,106, 2, 7, 0,107, 2, 7, 0,108, 2, 7, 0,109, 2, 7, 0,110, 2,
+ 7, 0,111, 2, 4, 0,112, 2, 7, 0,113, 2, 7, 0,114, 2, 7, 0,115, 2, 63, 0,116, 2, 63, 0,117, 2, 63, 0,118, 2,
+ 0, 0,119, 2, 7, 0,120, 2, 7, 0,121, 2, 98, 0, 56, 0, 24, 0, 18, 0, 2, 0,114, 0, 2, 0,194, 0, 2, 0,215, 0,
+ 2, 0,122, 2, 7, 0,123, 2, 7, 0,124, 2, 7, 0,125, 2, 7, 0,126, 2, 7, 0,127, 2, 7, 0,128, 2, 7, 0,129, 2,
+ 7, 0,130, 2, 7, 0,238, 0, 7, 0,240, 0, 7, 0,239, 0, 7, 0,131, 2, 4, 0,132, 2, 7, 0,133, 2, 7, 0,134, 2,
+ 7, 0,135, 2, 7, 0,136, 2, 7, 0,137, 2, 7, 0,138, 2, 7, 0,139, 2, 2, 0,140, 2, 2, 0,193, 0, 4, 0,141, 2,
+ 7, 0,142, 2, 7, 0,143, 2, 7, 0,144, 2, 7, 0,145, 2, 7, 0,146, 2, 7, 0,147, 2, 7, 0,148, 2, 7, 0,149, 2,
+ 7, 0,150, 2, 7, 0,151, 2, 7, 0,152, 2, 7, 0,153, 2, 2, 0,154, 2, 2, 0,155, 2, 2, 0,156, 2, 2, 0,157, 2,
+ 7, 0,158, 2, 7, 0,159, 2, 7, 0,160, 2, 7, 0,161, 2, 2, 0,162, 2, 2, 0,163, 2, 2, 0,164, 2, 2, 0,165, 2,
+ 7, 0,166, 2, 27, 0, 42, 0, 38, 0,230, 0, 30, 0, 80, 0, 99, 0, 16, 0, 2, 0,167, 2, 2, 0,168, 2, 2, 0,169, 2,
+ 2, 0, 16, 0, 2, 0,170, 2, 2, 0,171, 2, 2, 0,172, 2, 2, 0,173, 2, 2, 0,174, 2, 2, 0,175, 2, 2, 0,176, 2,
+ 2, 0,177, 2, 4, 0,178, 2, 7, 0,179, 2, 7, 0,180, 2, 7, 0,181, 2,100, 0, 8, 0,100, 0, 0, 0,100, 0, 1, 0,
+ 4, 0,231, 0, 4, 0,182, 2, 4, 0, 16, 0, 2, 0,183, 2, 2, 0,184, 2, 39, 0,105, 0,101, 0, 13, 0, 9, 0,185, 2,
+ 9, 0,186, 2, 4, 0,187, 2, 4, 0,188, 2, 4, 0,189, 2, 4, 0,190, 2, 4, 0,191, 2, 4, 0,192, 2, 4, 0,193, 2,
+ 4, 0,194, 2, 4, 0,195, 2, 4, 0, 17, 0, 0, 0,196, 2,102, 0, 5, 0, 9, 0,197, 2, 9, 0,198, 2, 4, 0,199, 2,
+ 4, 0, 48, 1, 0, 0,200, 2,103, 0, 4, 0, 4, 0,201, 2, 7, 0,202, 2, 2, 0, 16, 0, 2, 0,203, 2,104, 0, 98, 0,
+101, 0,204, 2,102, 0,205, 2, 2, 0,206, 2, 2, 0,187, 0, 2, 0, 93, 2, 2, 0,207, 2, 2, 0,208, 2, 2, 0, 16, 0,
+ 7, 0, 26, 2, 7, 0,209, 2, 7, 0,210, 2, 7, 0,211, 2, 7, 0,212, 2, 7, 0,213, 2, 2, 0,214, 2, 2, 0,215, 2,
+ 2, 0,216, 2, 2, 0,217, 2, 2, 0,146, 0, 2, 0,218, 2, 2, 0,219, 2, 2, 0,220, 2, 2, 0,221, 2, 2, 0,222, 2,
+ 2, 0,223, 2, 2, 0, 17, 0, 2, 0, 66, 0, 2, 0,224, 2, 2, 0,225, 2, 2, 0,226, 2, 2, 0,227, 2, 2, 0,228, 2,
+ 2, 0,229, 2, 2, 0,230, 2, 23, 0,231, 2, 23, 0,232, 2, 2, 0,233, 2, 2, 0,234, 2, 2, 0,235, 2, 2, 0,236, 2,
+ 2, 0,237, 2, 2, 0,238, 2, 4, 0,193, 0, 2, 0,239, 2, 2, 0,240, 2, 2, 0,241, 2, 2, 0,242, 2, 2, 0,243, 2,
+ 2, 0,244, 2, 2, 0,245, 2, 2, 0,246, 2, 2, 0,247, 2, 7, 0,181, 2, 7, 0,248, 2, 7, 0,249, 2, 7, 0,250, 2,
+ 7, 0,251, 2, 7, 0,252, 2, 7, 0,253, 2, 7, 0,254, 2, 7, 0,255, 2, 7, 0, 0, 3, 7, 0, 1, 3, 7, 0, 2, 3,
+ 7, 0, 3, 3, 7, 0, 4, 3, 2, 0, 5, 3, 2, 0, 6, 3, 2, 0, 7, 3, 2, 0, 8, 3, 2, 0, 9, 3, 2, 0, 10, 3,
+ 2, 0, 11, 3, 2, 0, 12, 3, 2, 0, 13, 3, 2, 0, 14, 3, 4, 0, 15, 3, 4, 0, 16, 3, 4, 0, 17, 3, 4, 0, 18, 3,
+ 4, 0, 19, 3, 7, 0, 20, 3, 4, 0, 21, 3, 4, 0, 22, 3, 4, 0, 23, 3, 4, 0, 24, 3, 7, 0, 25, 3, 7, 0, 26, 3,
+ 7, 0, 27, 3, 7, 0, 28, 3, 7, 0, 29, 3, 7, 0, 30, 3, 7, 0, 31, 3, 7, 0, 32, 3, 7, 0, 33, 3, 0, 0, 34, 3,
+ 0, 0, 35, 3, 0, 0, 36, 3,105, 0, 5, 0, 7, 0, 37, 3, 0, 0, 29, 0, 0, 0, 69, 0, 0, 0, 48, 1, 0, 0, 39, 1,
+106, 0, 5, 0,106, 0, 0, 0,106, 0, 1, 0, 4, 0, 38, 3, 0, 0, 39, 3, 4, 0, 16, 0,107, 0, 13, 0, 2, 0, 40, 3,
+ 2, 0, 41, 3, 2, 0, 42, 3, 2, 0, 43, 3, 2, 0, 44, 3, 2, 0, 69, 0, 7, 0, 45, 3, 7, 0, 46, 3, 2, 0, 47, 3,
+ 2, 0, 48, 3, 2, 0, 49, 3, 0, 0, 48, 1, 0, 0, 39, 1,108, 0, 31, 0, 24, 0, 18, 0, 39, 0, 50, 3, 98, 0, 51, 3,
+108, 0, 52, 3, 35, 0,140, 0, 11, 0, 53, 3,100, 0, 54, 3,109, 0, 55, 3, 7, 0, 56, 3, 7, 0, 57, 3, 7, 0, 58, 3,
+ 7, 0, 59, 3, 4, 0,231, 0, 2, 0, 60, 3, 2, 0, 17, 0, 2, 0, 61, 3, 2, 0, 62, 3, 7, 0, 63, 3, 9, 0, 64, 3,
+ 99, 0, 65, 3, 9, 0,177, 1,105, 0, 66, 3,107, 0, 67, 3,104, 0,115, 0,103, 0, 68, 3, 30, 0, 80, 0, 11, 0, 69, 3,
+110, 0, 70, 3, 2, 0, 71, 3, 2, 0, 72, 3, 4, 0, 73, 3,111, 0, 10, 0, 35, 0,140, 0, 40, 0,106, 0, 7, 0,132, 1,
+ 7, 0,133, 1, 7, 0, 66, 0, 7, 0, 74, 3, 7, 0, 75, 3, 2, 0, 76, 3, 2, 0, 77, 3, 4, 0, 78, 3,112, 0, 53, 0,
+113, 0, 0, 0,113, 0, 1, 0, 4, 0, 79, 3, 7, 0, 80, 3,114, 0, 81, 3, 2, 0, 82, 3, 7, 0, 83, 3, 7, 0, 84, 3,
+ 7, 0, 85, 3, 7, 0, 86, 3, 7, 0, 87, 3, 7, 0, 88, 3, 7, 0, 89, 3, 7, 0,196, 0, 2, 0, 90, 3, 2, 0, 91, 3,
+ 39, 0, 50, 3,111, 0, 92, 3,112, 0, 93, 3, 2, 0,169, 2, 2, 0, 94, 3, 4, 0,231, 0, 4, 0, 95, 3, 2, 0, 96, 3,
+ 2, 0, 97, 3, 2, 0, 98, 3, 2, 0, 16, 0, 7, 0, 72, 0, 7, 0, 99, 3, 7, 0,100, 3, 7, 0,101, 3, 7, 0,102, 3,
+ 7, 0,103, 3, 7, 0,111, 0, 7, 0, 56, 3, 2, 0,104, 3, 2, 0,105, 3, 2, 0,106, 3, 2, 0,107, 3, 2, 0,108, 3,
+ 2, 0,109, 3, 2, 0,110, 3, 2, 0,111, 3, 2, 0,112, 3, 2, 0,113, 3, 7, 0,114, 3, 7, 0,115, 3, 51, 0,116, 3,
+ 11, 0,117, 3, 2, 0,118, 3, 2, 0,163, 1, 2, 0,119, 3, 2, 0, 48, 1,115, 0, 16, 0, 23, 0, 22, 0, 23, 0, 24, 0,
+ 22, 0,120, 3, 22, 0,121, 3, 22, 0,122, 3, 7, 0,123, 3, 7, 0,124, 3, 7, 0,125, 3, 7, 0,126, 3, 2, 0,127, 3,
+ 2, 0,128, 3, 2, 0,129, 3, 2, 0,130, 3, 2, 0,131, 3, 2, 0,132, 3, 4, 0, 16, 0,113, 0, 6, 0,113, 0, 0, 0,
+113, 0, 1, 0, 4, 0, 79, 3, 7, 0, 80, 3,114, 0, 81, 3, 2, 0, 82, 3,116, 0, 6, 0,113, 0, 0, 0,113, 0, 1, 0,
+ 4, 0, 79, 3, 7, 0, 80, 3,114, 0, 81, 3, 2, 0, 82, 3,117, 0, 26, 0,113, 0, 0, 0,113, 0, 1, 0, 4, 0, 79, 3,
+ 7, 0, 80, 3,114, 0, 81, 3, 2, 0, 82, 3, 4, 0,133, 3, 4, 0, 48, 1,115, 0,134, 3, 9, 0,135, 3, 11, 0,136, 3,
+ 27, 0, 42, 0, 24, 0, 43, 0, 0, 0,137, 3, 0, 0,138, 3, 2, 0,139, 3, 2, 0,140, 3, 2, 0,141, 3, 2, 0,142, 3,
+ 2, 0, 26, 0, 2, 0, 25, 0, 2, 0,108, 3, 2, 0,143, 3, 4, 0, 16, 0, 7, 0,144, 3, 23, 0, 22, 0,118, 0, 31, 0,
+113, 0, 0, 0,113, 0, 1, 0, 4, 0, 79, 3, 7, 0, 80, 3,114, 0, 81, 3, 2, 0, 82, 3, 2, 0,145, 3, 2, 0,146, 3,
+ 2, 0,147, 3, 2, 0,148, 3,115, 0,134, 3, 2, 0,149, 3, 2, 0,108, 3, 2, 0,140, 3, 2, 0,150, 3, 9, 0,151, 3,
+ 2, 0,109, 3, 0, 0,152, 3, 0, 0,153, 3, 2, 0,154, 3, 2, 0,155, 3, 4, 0, 78, 3, 2, 0,156, 3, 2, 0,157, 3,
+ 2, 0,158, 3, 2, 0, 18, 2, 2, 0,159, 3, 2, 0, 69, 0, 4, 0,160, 3, 0, 0,215, 0, 0, 0,161, 3,119, 0, 10, 0,
+113, 0, 0, 0,113, 0, 1, 0, 4, 0, 79, 3, 7, 0, 80, 3,114, 0, 81, 3, 2, 0, 82, 3,115, 0,134, 3, 2, 0,149, 3,
+ 2, 0, 74, 3, 4, 0, 48, 1,120, 0, 24, 0,113, 0, 0, 0,113, 0, 1, 0, 4, 0, 79, 3, 7, 0, 80, 3,114, 0, 81, 3,
+ 2, 0, 82, 3,121, 0,162, 3, 4, 0,163, 3, 0, 0,164, 3, 0, 0,165, 3, 0, 0,166, 3, 2, 0, 29, 0, 2, 0,167, 3,
+ 2, 0, 16, 0, 2, 0,168, 3, 2, 0,169, 3, 2, 0,170, 3,122, 0,171, 3, 2, 0,172, 3, 2, 0,138, 0, 2, 0,173, 3,
+ 2, 0,174, 3, 9, 0,175, 3, 2, 0,176, 3,123, 0, 19, 0,113, 0, 0, 0,113, 0, 1, 0, 4, 0, 79, 3, 7, 0, 80, 3,
+114, 0, 81, 3, 2, 0, 82, 3,115, 0,134, 3, 11, 0,177, 3, 2, 0,140, 3, 2, 0,178, 3, 2, 0, 16, 0, 2, 0,157, 1,
+ 9, 0,151, 3, 11, 0,179, 3,124, 0,180, 3, 2, 0, 29, 0, 2, 0,181, 3, 2, 0,182, 3, 2, 0,183, 3,125, 0, 17, 0,
+113, 0, 0, 0,113, 0, 1, 0, 4, 0, 79, 3, 7, 0, 80, 3,114, 0, 81, 3, 2, 0, 82, 3,115, 0,134, 3, 35, 0,184, 3,
+ 7, 0, 74, 3, 2, 0,193, 0, 2, 0,108, 3, 2, 0,185, 3, 2, 0,186, 3, 7, 0,132, 1, 7, 0,133, 1, 2, 0, 16, 0,
+ 2, 0,143, 3,126, 0, 10, 0,113, 0, 0, 0,113, 0, 1, 0, 4, 0, 79, 3, 7, 0, 80, 3,114, 0, 81, 3, 2, 0, 82, 3,
+ 2, 0,108, 3, 2, 0,143, 3, 4, 0, 17, 0,115, 0,134, 3,127, 0, 22, 0,113, 0, 0, 0,113, 0, 1, 0, 4, 0, 79, 3,
+ 7, 0, 80, 3,114, 0, 81, 3, 2, 0, 82, 3, 32, 0,187, 3, 4, 0,188, 3, 4, 0,189, 3, 2, 0, 55, 0, 2, 0,108, 3,
+ 4, 0,190, 3, 4, 0,191, 3, 4, 0,192, 3, 4, 0,193, 3, 4, 0,194, 3, 4, 0,195, 3, 4, 0,196, 3, 4, 0,197, 3,
+ 7, 0,198, 3, 22, 0,199, 3, 22, 0,200, 3,128, 0, 9, 0,113, 0, 0, 0,113, 0, 1, 0, 4, 0, 79, 3, 7, 0, 80, 3,
+114, 0, 81, 3,129, 0,201, 3, 4, 0, 48, 1, 2, 0, 55, 0, 2, 0,108, 3,130, 0, 8, 0,113, 0, 0, 0,113, 0, 1, 0,
+ 4, 0, 79, 3, 7, 0, 80, 3,114, 0, 81, 3,115, 0,134, 3, 4, 0, 16, 0, 4, 0,202, 3,131, 0, 81, 0,113, 0, 0, 0,
+113, 0, 1, 0, 4, 0, 79, 3, 7, 0, 80, 3,114, 0, 81, 3, 0, 0,203, 3, 4, 0,204, 3, 2, 0,193, 0, 2, 0,205, 3,
+ 2, 0,206, 3, 2, 0,207, 3, 2, 0,208, 3, 2, 0,209, 3, 2, 0,210, 3, 2, 0,211, 3, 2, 0,212, 3, 2, 0,213, 3,
+ 2, 0,214, 3, 2, 0,215, 3, 2, 0,216, 3, 2, 0,217, 3, 2, 0,218, 3, 2, 0,219, 3, 2, 0,220, 3, 2, 0,221, 3,
+ 2, 0,222, 3, 2, 0,223, 3, 2, 0,224, 3, 2, 0,225, 3, 2, 0,226, 3, 2, 0,227, 3, 2, 0,228, 3, 2, 0,229, 3,
+ 2, 0,230, 3, 2, 0,231, 3, 2, 0,232, 3, 2, 0,233, 3, 2, 0,234, 3, 2, 0,235, 3, 2, 0,236, 3, 2, 0,237, 3,
+ 2, 0,238, 3, 2, 0,239, 3, 2, 0,240, 3, 2, 0,241, 3, 2, 0,242, 3, 2, 0,243, 3, 2, 0,244, 3, 2, 0,245, 3,
+ 2, 0,246, 3, 2, 0,247, 3, 2, 0,248, 3, 2, 0,249, 3, 2, 0,250, 3, 2, 0,251, 3, 0, 0,252, 3, 0, 0,253, 3,
+ 0, 0,254, 3, 0, 0,255, 3,132, 0, 0, 4,132, 0, 1, 4, 4, 0, 2, 4, 4, 0, 3, 4, 4, 0, 4, 4, 4, 0, 5, 4,
+ 4, 0, 6, 4, 7, 0, 7, 4, 7, 0, 8, 4, 7, 0, 9, 4, 2, 0, 10, 4, 2, 0, 11, 4, 2, 0, 12, 4, 2, 0, 13, 4,
+133, 0, 14, 4,133, 0, 15, 4, 2, 0, 16, 4, 2, 0, 17, 4, 4, 0, 48, 1, 37, 0, 18, 4, 9, 0,175, 3, 9, 0, 19, 4,
+134, 0, 19, 0, 0, 0, 20, 4, 0, 0, 21, 4, 0, 0, 22, 4, 0, 0, 23, 4, 0, 0, 24, 4, 0, 0, 25, 4, 0, 0, 26, 4,
+ 0, 0, 27, 4, 0, 0, 28, 4, 0, 0, 29, 4, 0, 0, 30, 4, 0, 0, 31, 4, 0, 0, 32, 4, 0, 0, 33, 4, 0, 0, 34, 4,
+ 0, 0, 35, 4, 0, 0, 36, 4, 0, 0, 37, 4, 0, 0, 38, 4,135, 0, 36, 0, 0, 0, 39, 4, 0, 0, 30, 4, 0, 0, 31, 4,
+ 0, 0, 40, 4, 0, 0, 41, 4, 0, 0, 42, 4, 0, 0, 43, 4, 0, 0, 44, 4, 0, 0, 45, 4, 0, 0, 46, 4, 0, 0, 47, 4,
+ 0, 0, 48, 4, 0, 0, 49, 4, 0, 0, 50, 4, 0, 0, 51, 4, 0, 0, 52, 4, 0, 0, 53, 4, 0, 0, 54, 4, 0, 0, 55, 4,
+ 0, 0, 56, 4, 0, 0, 57, 4, 0, 0, 58, 4, 0, 0, 59, 4, 0, 0, 60, 4, 0, 0, 61, 4, 0, 0, 62, 4, 0, 0, 63, 4,
+ 0, 0, 64, 4, 0, 0, 65, 4, 0, 0, 66, 4, 0, 0, 67, 4, 0, 0, 68, 4, 0, 0, 69, 4, 0, 0, 70, 4, 0, 0, 71, 4,
+ 0, 0, 72, 4,136, 0, 18, 0,136, 0, 0, 0,136, 0, 1, 0, 0, 0, 34, 0,134, 0, 73, 4,135, 0, 74, 4,135, 0, 75, 4,
+135, 0, 76, 4,135, 0, 77, 4,135, 0, 78, 4,135, 0, 79, 4,135, 0, 80, 4,135, 0, 81, 4,135, 0, 82, 4,135, 0, 83, 4,
+135, 0, 84, 4,135, 0, 85, 4,135, 0, 86, 4,135, 0, 87, 4,137, 0, 5, 0, 4, 0, 16, 0, 4, 0, 17, 0, 7, 0,162, 1,
+ 7, 0, 88, 4, 7, 0, 95, 1,138, 0, 45, 0, 4, 0, 16, 0, 4, 0, 89, 4, 4, 0, 90, 4, 0, 0, 91, 4, 0, 0, 92, 4,
+ 0, 0, 93, 4, 0, 0, 94, 4, 0, 0, 95, 4, 0, 0, 96, 4, 0, 0, 97, 4, 0, 0, 98, 4, 0, 0, 99, 4, 2, 0,100, 4,
+ 2, 0,101, 4, 4, 0,102, 4, 4, 0,103, 4, 4, 0,104, 4, 4, 0,105, 4, 2, 0,106, 4, 2, 0,107, 4, 2, 0,108, 4,
+ 2, 0,109, 4, 4, 0,110, 4, 4, 0,111, 4, 2, 0,112, 4, 2, 0,113, 4, 2, 0,114, 4, 2, 0,115, 4, 0, 0,116, 4,
+ 11, 0,117, 4, 2, 0,118, 4, 2, 0,119, 4, 2, 0,120, 4, 2, 0,121, 4,137, 0,122, 4, 2, 0,123, 4, 2, 0,124, 4,
+ 2, 0,125, 4, 2, 0,126, 4, 4, 0,127, 4, 4, 0,128, 4, 2, 0,129, 4, 2, 0, 69, 0, 2, 0, 48, 1, 2, 0, 39, 1,
+139, 0, 18, 0, 24, 0, 18, 0, 11, 0,130, 4, 11, 0,131, 4, 11, 0,132, 4,108, 0,133, 4, 2, 0,212, 1, 2, 0,134, 4,
+ 2, 0,213, 1, 2, 0,135, 4, 2, 0,136, 4, 2, 0,137, 4, 2, 0,138, 4, 2, 0,139, 4, 2, 0,140, 4, 2, 0, 17, 0,
+ 2, 0,141, 4, 2, 0,142, 4, 2, 0,143, 4,140, 0, 5, 0,140, 0, 0, 0,140, 0, 1, 0,140, 0,144, 4, 12, 0,145, 4,
+ 4, 0, 16, 0,141, 0, 7, 0,141, 0, 0, 0,141, 0, 1, 0,140, 0,146, 4,140, 0,147, 4, 2, 0,232, 2, 2, 0, 16, 0,
+ 4, 0, 17, 0,142, 0, 16, 0,142, 0, 0, 0,142, 0, 1, 0, 0, 0,148, 4, 0, 0,149, 4, 2, 0,150, 4, 2, 0,151, 4,
+ 2, 0,136, 4, 2, 0,137, 4, 2, 0, 16, 0, 2, 0, 64, 2, 2, 0,152, 4, 2, 0, 17, 0, 2, 0,153, 4, 2, 0,154, 4,
+ 4, 0,155, 4,142, 0,156, 4,114, 0, 30, 0,114, 0, 0, 0,114, 0, 1, 0,140, 0,146, 4,140, 0,147, 4,140, 0,157, 4,
+140, 0,158, 4,139, 0,159, 4, 7, 0,160, 4, 22, 0,152, 1, 22, 0,161, 4, 22, 0,162, 4, 2, 0,163, 4, 2, 0,164, 4,
+ 2, 0,165, 4, 0, 0, 79, 3, 0, 0,166, 4, 2, 0,167, 4, 2, 0,168, 4, 0, 0,169, 4, 0, 0,170, 4, 0, 0,171, 4,
+ 0, 0,172, 4, 2, 0,173, 4, 2, 0,174, 4, 2, 0,175, 4, 2, 0, 16, 0, 30, 0, 80, 0, 11, 0,176, 4, 11, 0,177, 4,
+ 11, 0,178, 4,143, 0, 7, 0, 9, 0,179, 4, 9, 0,180, 4, 2, 0,181, 4, 2, 0,233, 2, 4, 0,182, 4, 4, 0,183, 4,
+ 4, 0, 17, 0,144, 0, 8, 0, 0, 0,184, 4, 37, 0, 82, 0,144, 0,185, 4,144, 0,186, 4,144, 0,187, 4, 2, 0, 84, 0,
+ 2, 0,188, 4, 4, 0, 17, 0,145, 0, 11, 0,145, 0, 0, 0,145, 0, 1, 0, 2, 0,157, 1, 2, 0, 52, 0, 2, 0, 15, 0,
+ 2, 0,189, 4,144, 0,190, 4, 0, 0,165, 3, 2, 0,191, 4, 2, 0,192, 4, 4, 0, 17, 0,146, 0, 10, 0, 0, 0, 57, 1,
+ 9, 0,125, 0, 0, 0,126, 0, 4, 0,129, 0, 4, 0,136, 0, 9, 0,130, 0, 7, 0,132, 0, 7, 0,133, 0, 9, 0,134, 0,
+ 9, 0,135, 0,147, 0, 38, 0,147, 0, 0, 0,147, 0, 1, 0,147, 0,193, 4, 9, 0, 13, 0, 0, 0, 14, 0, 2, 0, 16, 0,
+ 2, 0, 29, 0, 4, 0, 52, 0, 4, 0,204, 1, 4, 0,194, 4, 4, 0,195, 4, 4, 0,196, 4, 4, 0,197, 4, 4, 0,198, 4,
+ 4, 0,146, 0, 4, 0,199, 4, 4, 0,200, 4, 7, 0,201, 4, 7, 0,202, 4, 4, 0,187, 0,145, 0,203, 4,144, 0,204, 4,
+ 27, 0, 42, 0,108, 0,133, 4, 36, 0, 81, 0, 7, 0,205, 4, 7, 0,206, 4,146, 0,189, 0,147, 0,207, 4,147, 0,208, 4,
+147, 0,209, 4, 11, 0,210, 4,148, 0,211, 4, 7, 0,212, 4, 7, 0,213, 4, 4, 0,214, 4, 7, 0,215, 4, 9, 0,216, 4,
+149, 0, 4, 0,149, 0, 0, 0,149, 0, 1, 0, 11, 0,217, 4,147, 0,218, 4,150, 0, 6, 0, 11, 0,219, 4, 11, 0,210, 4,
+ 11, 0,220, 4, 2, 0, 16, 0, 2, 0,157, 1, 4, 0, 17, 0,151, 0, 4, 0, 7, 0,221, 4, 7, 0,222, 4, 2, 0,223, 4,
+ 2, 0,224, 4,152, 0, 6, 0, 7, 0,225, 4, 7, 0,226, 4, 7, 0,227, 4, 7, 0,228, 4, 4, 0,229, 4, 4, 0,230, 4,
+153, 0, 6, 0,153, 0, 0, 0,153, 0, 1, 0, 2, 0, 29, 0, 2, 0, 16, 0, 2, 0,231, 4, 2, 0,157, 1,154, 0, 8, 0,
+154, 0, 0, 0,154, 0, 1, 0, 2, 0, 29, 0, 2, 0, 16, 0, 2, 0,231, 4, 2, 0,157, 1, 7, 0, 52, 0, 7, 0,187, 0,
+155, 0, 41, 0,155, 0, 0, 0,155, 0, 1, 0, 2, 0, 29, 0, 2, 0, 16, 0, 2, 0,231, 4, 2, 0,143, 0, 2, 0, 90, 2,
+ 2, 0,232, 4, 7, 0,233, 4, 7, 0,234, 4, 7, 0,219, 1, 4, 0,235, 4, 4, 0, 44, 0, 4, 0,207, 1, 7, 0,236, 4,
+ 7, 0,237, 4, 7, 0,238, 4, 7, 0,239, 4, 7, 0,240, 4, 7, 0,241, 4, 7, 0,217, 1, 7, 0,184, 0, 7, 0,242, 4,
+ 7, 0,243, 4, 7, 0,244, 4, 7, 0,245, 4, 2, 0,246, 4, 2, 0,247, 4, 2, 0,248, 4, 2, 0,249, 4, 2, 0,250, 4,
+ 2, 0,251, 4, 2, 0,252, 4, 2, 0,253, 4, 2, 0,254, 4, 2, 0,255, 4, 2, 0, 78, 1, 2, 0, 0, 5, 0, 0, 1, 5,
+ 0, 0, 2, 5,156, 0, 3, 5,157, 0, 16, 0,157, 0, 0, 0,157, 0, 1, 0, 2, 0, 29, 0, 2, 0, 16, 0, 2, 0,231, 4,
+ 2, 0,143, 0, 7, 0,212, 1, 7, 0,213, 1, 7, 0,214, 1, 7, 0,121, 1, 7, 0,215, 1, 7, 0,216, 1, 7, 0, 4, 5,
+ 7, 0,217, 1, 7, 0,218, 1, 7, 0,219, 1,158, 0, 5, 0, 2, 0, 29, 0, 2, 0,188, 4, 2, 0, 16, 0, 2, 0, 5, 5,
+ 24, 0, 6, 5,124, 0, 3, 0, 4, 0, 31, 0, 4, 0, 7, 5,158, 0, 32, 0,159, 0, 12, 0,159, 0, 0, 0,159, 0, 1, 0,
+ 2, 0, 29, 0, 2, 0, 16, 0, 2, 0, 34, 2, 2, 0, 94, 1, 7, 0, 4, 0, 7, 0, 5, 0, 7, 0, 8, 5, 7, 0, 9, 5,
+ 24, 0, 6, 5, 11, 0, 10, 5,160, 0, 11, 0,160, 0, 0, 0,160, 0, 1, 0, 0, 0, 34, 0, 2, 0, 29, 0, 2, 0, 11, 5,
+ 4, 0, 12, 5, 4, 0, 13, 5, 2, 0, 16, 0, 2, 0, 17, 0, 9, 0, 14, 5, 9, 0, 15, 5,161, 0, 5, 0, 0, 0, 34, 0,
+ 7, 0,196, 0, 7, 0, 16, 5, 4, 0, 17, 5, 4, 0, 17, 0,162, 0, 4, 0, 2, 0, 29, 0, 2, 0, 16, 0, 2, 0, 69, 0,
+ 2, 0, 48, 1,163, 0, 4, 0, 0, 0, 34, 0, 47, 0, 18, 5, 7, 0,196, 0, 7, 0, 17, 0,164, 0, 6, 0, 2, 0, 19, 5,
+ 2, 0, 20, 5, 2, 0, 29, 0, 2, 0, 21, 5, 0, 0, 22, 5, 0, 0, 23, 5,165, 0, 5, 0, 4, 0, 29, 0, 4, 0, 17, 0,
+ 0, 0, 34, 0, 0, 0, 24, 5, 0, 0, 25, 5,166, 0, 6, 0, 0, 0, 34, 0, 0, 0, 26, 5, 2, 0, 27, 5, 2, 0,217, 1,
+ 2, 0,193, 0, 2, 0, 48, 1,167, 0, 5, 0, 0, 0, 34, 0, 7, 0,222, 4, 7, 0,135, 2, 2, 0, 16, 0, 2, 0,208, 1,
+168, 0, 3, 0, 0, 0, 34, 0, 4, 0,207, 1, 4, 0, 28, 5,169, 0, 7, 0, 0, 0, 34, 0, 7, 0,135, 2, 0, 0, 29, 5,
+ 0, 0, 30, 5, 2, 0,193, 0, 2, 0, 69, 0, 4, 0, 31, 5,170, 0, 3, 0, 39, 0, 32, 5, 0, 0, 33, 5, 0, 0, 34, 5,
+171, 0, 17, 0,171, 0, 0, 0,171, 0, 1, 0, 2, 0, 29, 0, 2, 0, 11, 5, 2, 0, 16, 0, 2, 0, 35, 5, 2, 0, 36, 5,
+ 2, 0, 37, 5, 2, 0, 69, 0, 2, 0, 48, 1, 0, 0, 34, 0, 9, 0, 32, 0,172, 0, 38, 5, 39, 0,149, 1, 2, 0, 39, 5,
+ 2, 0, 40, 5, 4, 0, 17, 0,173, 0, 10, 0, 0, 0, 34, 0, 2, 0, 29, 0, 2, 0, 17, 0, 4, 0,208, 1, 4, 0, 41, 5,
+ 4, 0, 42, 5, 4, 0, 43, 5, 4, 0, 44, 5, 4, 0, 45, 5, 4, 0, 46, 5,174, 0, 1, 0, 0, 0, 47, 5,175, 0, 1, 0,
+ 32, 0,187, 3,172, 0, 18, 0,172, 0, 0, 0,172, 0, 1, 0,172, 0, 48, 5, 2, 0, 29, 0, 2, 0, 16, 0, 2, 0, 49, 5,
+ 2, 0, 37, 5, 2, 0, 11, 5, 2, 0, 50, 5, 2, 0, 48, 1, 2, 0, 39, 1, 0, 0, 34, 0, 9, 0, 32, 0,176, 0, 38, 5,
+171, 0, 51, 5, 2, 0, 52, 5, 2, 0, 53, 5, 4, 0, 24, 1,177, 0, 3, 0, 4, 0, 54, 5, 4, 0, 17, 0, 39, 0,149, 1,
+178, 0, 13, 0, 87, 0, 55, 5, 2, 0, 29, 0, 2, 0, 16, 0, 2, 0,233, 4, 2, 0,234, 4, 0, 0, 34, 0, 2, 0, 56, 5,
+ 2, 0, 57, 5, 7, 0, 58, 5, 2, 0, 59, 5, 2, 0, 99, 0, 2, 0,100, 0, 2, 0, 60, 5,179, 0, 9, 0, 2, 0, 16, 0,
+ 2, 0, 61, 5, 2, 0,233, 4, 2, 0,234, 4,148, 0,211, 4, 2, 0, 29, 0, 2, 0, 62, 5, 2, 0, 63, 5, 2, 0, 64, 5,
+180, 0, 7, 0, 2, 0, 16, 0, 2, 0, 61, 5, 2, 0,233, 4, 2, 0,234, 4, 2, 0, 29, 0, 2, 0, 65, 5, 7, 0, 66, 5,
+181, 0, 9, 0, 4, 0, 54, 5, 2, 0, 29, 0, 2, 0, 16, 0, 39, 0,149, 1, 63, 0, 67, 5, 0, 0, 34, 0, 7, 0, 68, 5,
+ 2, 0, 69, 5, 2, 0, 17, 0,182, 0, 5, 0, 2, 0, 29, 0, 2, 0, 16, 0, 4, 0, 17, 0,108, 0,133, 4, 39, 0, 50, 3,
+183, 0, 5, 0, 4, 0, 16, 0, 4, 0, 29, 0, 0, 0, 34, 0, 0, 0, 24, 5, 39, 0,149, 1,184, 0, 12, 0, 4, 0, 16, 0,
+ 4, 0, 29, 0, 7, 0, 70, 5, 7, 0, 71, 5, 7, 0, 81, 1, 7, 0, 82, 1, 7, 0, 4, 2, 7, 0, 7, 2, 7, 0, 72, 5,
+ 7, 0, 73, 5, 7, 0, 74, 5, 0, 0, 75, 5,185, 0, 9, 0, 2, 0, 16, 0, 2, 0, 29, 0, 2, 0,233, 4, 2, 0,234, 4,
+ 0, 0, 34, 0, 2, 0, 69, 0, 2, 0, 24, 0, 2, 0, 76, 5, 2, 0, 77, 5,186, 0, 8, 0, 39, 0,149, 1, 7, 0,214, 1,
+ 7, 0, 78, 5, 7, 0,244, 1, 7, 0, 79, 5, 2, 0, 16, 0, 2, 0,208, 1, 7, 0, 80, 5,187, 0, 7, 0, 2, 0, 16, 0,
+ 2, 0,217, 1, 7, 0, 81, 5, 7, 0, 82, 5, 7, 0, 83, 5, 7, 0, 84, 5, 7, 0, 85, 5,188, 0, 10, 0, 2, 0, 16, 0,
+ 2, 0, 29, 0, 2, 0,233, 4, 2, 0,234, 4, 0, 0, 34, 0, 2, 0, 69, 0, 2, 0, 24, 0, 2, 0, 76, 5, 2, 0, 77, 5,
+109, 0, 55, 3,189, 0, 7, 0, 4, 0,207, 1, 4, 0, 86, 5, 4, 0, 87, 5, 4, 0, 88, 5, 7, 0, 89, 5, 7, 0, 90, 5,
+ 0, 0, 29, 5,190, 0, 7, 0, 0, 0, 91, 5, 39, 0, 92, 5, 0, 0, 33, 5, 2, 0, 93, 5, 2, 0, 69, 0, 4, 0, 48, 1,
+ 0, 0, 34, 5,191, 0, 6, 0, 2, 0, 16, 0, 2, 0, 29, 0, 2, 0,233, 4, 2, 0,234, 4, 0, 0, 94, 5, 0, 0, 95, 5,
+192, 0, 1, 0, 4, 0, 16, 0,176, 0, 10, 0,176, 0, 0, 0,176, 0, 1, 0,176, 0, 48, 5, 2, 0, 29, 0, 2, 0, 16, 0,
+ 2, 0, 11, 5, 2, 0, 96, 5, 0, 0, 34, 0, 9, 0, 32, 0, 39, 0,149, 1,193, 0, 10, 0, 7, 0, 27, 2, 7, 0, 97, 5,
+ 7, 0, 98, 5, 7, 0, 99, 5, 7, 0,100, 5, 4, 0, 16, 0, 7, 0,101, 5, 7, 0,102, 5, 7, 0,103, 5, 7, 0, 17, 0,
+148, 0, 22, 0, 24, 0, 18, 0, 0, 0, 21, 0,194, 0,104, 5, 9, 0,105, 5, 33, 0, 95, 0, 33, 0,106, 5, 9, 0,107, 5,
+ 27, 0, 42, 0, 7, 0, 66, 5, 7, 0,108, 5, 7, 0,109, 5, 7, 0,110, 5, 7, 0,111, 5, 7, 0,112, 5, 7, 0,113, 5,
+ 4, 0, 55, 0, 4, 0,114, 5, 4, 0,115, 5, 4, 0,116, 5, 0, 0,117, 5, 0, 0,118, 5, 0, 0,119, 5,195, 0, 6, 0,
+ 24, 0, 18, 0, 7, 0,120, 5, 7, 0,121, 5, 7, 0,122, 5, 2, 0,123, 5, 2, 0,124, 5,196, 0, 14, 0,113, 0, 0, 0,
+113, 0, 1, 0, 4, 0, 79, 3, 7, 0, 80, 3,114, 0, 81, 3,115, 0,134, 3,148, 0,211, 4, 2, 0,193, 0, 2, 0, 61, 5,
+ 2, 0,132, 1, 2, 0,133, 1, 2, 0, 16, 0, 2, 0,143, 3, 4, 0, 48, 1,197, 0, 6, 0,197, 0, 0, 0,197, 0, 1, 0,
+ 2, 0,187, 0, 2, 0, 93, 2, 7, 0,206, 2, 0, 0, 34, 0,198, 0, 31, 0,198, 0, 0, 0,198, 0, 1, 0,197, 0,125, 5,
+ 2, 0,246, 1, 2, 0, 17, 0, 4, 0,247, 1, 4, 0,248, 1, 4, 0,249, 1, 39, 0,252, 1, 39, 0,253, 1, 27, 0, 42, 0,
+ 7, 0, 81, 1, 7, 0, 4, 2, 7, 0, 5, 2, 7, 0,112, 0, 7, 0, 6, 2, 7, 0, 82, 1, 7, 0, 7, 2, 7, 0, 68, 1,
+ 7, 0, 8, 2, 7, 0, 9, 2, 7, 0,221, 1, 7, 0,142, 0, 4, 0,231, 0, 0, 0, 11, 2, 0, 0, 12, 2, 0, 0, 13, 2,
+ 0, 0, 14, 2, 7, 0, 25, 2, 7, 0, 26, 2, 7, 0,126, 5,199, 0, 4, 0,199, 0, 0, 0,199, 0, 1, 0, 39, 0,149, 1,
+ 11, 0,127, 5,109, 0, 4, 0, 24, 0, 18, 0, 11, 0,128, 5, 11, 0,129, 5,197, 0,130, 5,200, 0, 25, 0,200, 0, 0, 0,
+200, 0, 1, 0,200, 0,252, 1, 11, 0,131, 5, 0, 0, 34, 0, 7, 0,132, 5, 7, 0,133, 5, 7, 0,134, 5, 7, 0,135, 5,
+ 4, 0, 16, 0, 7, 0,136, 5, 7, 0,137, 5, 7, 0,138, 5, 7, 0,196, 0, 7, 0, 88, 1, 7, 0,139, 5, 7, 0,205, 1,
+ 7, 0,140, 5, 7, 0,141, 5, 7, 0,142, 5, 7, 0,143, 5, 7, 0,144, 5, 7, 0,112, 0, 2, 0,145, 5, 2, 0, 47, 3,
+201, 0, 8, 0, 24, 0, 18, 0, 11, 0,146, 5, 11, 0,147, 5, 4, 0, 16, 0, 4, 0,169, 2, 4, 0,220, 1, 2, 0,148, 5,
+ 2, 0,149, 5,202, 0, 29, 0,202, 0, 0, 0,202, 0, 1, 0, 11, 0, 48, 2, 0, 0, 34, 0, 2, 0, 16, 0, 2, 0,150, 5,
+ 2, 0,151, 5, 2, 0,119, 1, 2, 0, 16, 2, 2, 0, 17, 0, 2, 0, 69, 0, 2, 0, 48, 1,200, 0,152, 5,202, 0,252, 1,
+202, 0,153, 5, 11, 0,154, 5, 9, 0,155, 5, 7, 0, 81, 1, 7, 0,112, 0, 7, 0, 68, 1, 7, 0,156, 5, 7, 0,157, 5,
+ 7, 0,158, 5, 7, 0,159, 5, 7, 0,160, 5, 7, 0,161, 5, 7, 0,162, 5, 7, 0,163, 5, 7, 0,116, 1, 88, 0, 3, 0,
+ 11, 0,164, 5, 4, 0, 16, 0, 7, 0,165, 5,203, 0, 7, 0,203, 0, 0, 0,203, 0, 1, 0, 27, 0, 42, 0, 11, 0, 0, 2,
+ 4, 0, 16, 0, 0, 0, 34, 0, 4, 0, 99, 0, 87, 0, 2, 0, 24, 0, 18, 0, 11, 0,164, 5,204, 0, 14, 0,113, 0, 0, 0,
+113, 0, 1, 0, 4, 0, 79, 3, 7, 0, 80, 3,114, 0, 81, 3, 2, 0, 82, 3,115, 0,134, 3, 87, 0,254, 1, 4, 0, 16, 0,
+ 2, 0,140, 3, 2, 0,166, 5, 2, 0,143, 3, 2, 0, 17, 0, 7, 0,167, 5,205, 0, 5, 0,205, 0, 0, 0,205, 0, 1, 0,
+ 27, 0, 42, 0, 2, 0, 16, 0, 0, 0,168, 5,206, 0, 8, 0,206, 0, 0, 0,206, 0, 1, 0, 9, 0, 32, 0, 2, 0, 29, 0,
+ 2, 0, 16, 0, 2, 0, 99, 0, 0, 0,168, 5, 7, 0,169, 5,207, 0, 11, 0, 39, 0,170, 5, 7, 0,209, 1, 2, 0,171, 5,
+ 2, 0, 16, 0, 4, 0,172, 5, 4, 0, 17, 0, 0, 0,173, 5, 7, 0, 88, 1, 7, 0,174, 5, 7, 0,175, 5, 7, 0, 48, 1,
+208, 0, 4, 0, 39, 0,170, 5, 4, 0, 99, 0, 4, 0,100, 0, 0, 0,173, 5,209, 0, 4, 0, 39, 0,170, 5, 4, 0, 16, 0,
+ 4, 0, 99, 0, 0, 0,173, 5,210, 0, 4, 0, 39, 0,170, 5, 4, 0, 16, 0, 4, 0, 99, 0, 0, 0,173, 5,211, 0, 7, 0,
+ 39, 0,170, 5, 4, 0,176, 5, 7, 0,186, 0, 2, 0,177, 5, 2, 0,178, 5, 7, 0,179, 5, 0, 0,173, 5,212, 0, 9, 0,
+ 39, 0,170, 5, 2, 0, 29, 0, 2, 0,180, 5, 2, 0,204, 1, 2, 0,234, 4, 7, 0, 78, 5, 7, 0,244, 1, 87, 0, 55, 5,
+ 0, 0,173, 5,213, 0, 4, 0, 39, 0,170, 5, 4, 0, 13, 2, 4, 0,181, 5, 0, 0,173, 5,214, 0, 5, 0, 39, 0,170, 5,
+ 7, 0,186, 0, 4, 0,182, 5, 4, 0, 13, 2, 4, 0, 14, 2,215, 0, 6, 0, 39, 0,170, 5, 0, 0,173, 5, 7, 0, 69, 0,
+ 7, 0, 48, 1, 7, 0,113, 5, 7, 0,183, 5,216, 0, 6, 0, 7, 0, 8, 0, 7, 0, 9, 0, 7, 0, 10, 0, 7, 0, 11, 0,
+ 7, 0, 0, 3, 7, 0,184, 5,217, 0, 6, 0, 39, 0,170, 5, 4, 0,185, 5, 4, 0,186, 5, 7, 0,187, 5, 7, 0,188, 5,
+ 0, 0,173, 5,218, 0, 17, 0,218, 0, 0, 0,218, 0, 1, 0, 2, 0, 16, 0, 2, 0,193, 0, 2, 0,189, 5, 2, 0, 17, 0,
+ 27, 0, 42, 0, 87, 0, 55, 5, 7, 0,204, 1, 7, 0,234, 4, 7, 0,190, 5, 7, 0,191, 5, 7, 0,192, 5, 7, 0,193, 5,
+ 7, 0, 56, 5, 7, 0,194, 5, 0, 0,195, 5, 69, 78, 68, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
diff --git a/source/blender/src/Bfont.c b/source/blender/src/Bfont.c
new file mode 100644
index 00000000000..2d442e2cf73
--- /dev/null
+++ b/source/blender/src/Bfont.c
@@ -0,0 +1,139 @@
+/* DataToC output of file <Bfont> */
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+int datatoc_Bfont_size= 25181;
+char datatoc_Bfont[]= {"\x80\x01\xe4\x01\x00\x00\x25\x21\x50\x53\x2d\x41\x64\x6f\x62\x65\x46\x6f\x6e\x74\x2d\x31\x2e\x30\x3a\x20\x42\x66\x6f\x6e\x74\x20\x30\x30\x31\x2e\x30\x30\x31\x0a\x31\x31\x20\x64\x69\x63\x74\x20\x62\x65\x67\x69\x6e\x0a\x2f\x46\x6f\x6e\x74\x49\x6e\x66\x6f\x20\x31\x30\x20\x64\x69\x63\x74\x20\x64\x75\x70\x20\x62\x65\x67\x69\x6e\x0a\x2f\x76\x65\x72\x73\x69\x6f\x6e\x20\x28" \
+"\x30\x30\x31\x2e\x30\x30\x31\x29\x20\x72\x65\x61\x64\x6f\x6e\x6c\x79\x20\x64\x65\x66\x0a\x2f\x46\x75\x6c\x6c\x4e\x61\x6d\x65\x20\x28\x42\x66\x6f\x6e\x74\x29\x20\x72\x65\x61\x64\x6f\x6e\x6c\x79\x20\x64\x65\x66\x0a\x2f\x46\x61\x6d\x69\x6c\x79\x4e\x61\x6d\x65\x20\x28\x42\x66\x6f\x6e\x74\x29\x20\x72\x65\x61\x64\x6f\x6e\x6c\x79\x20\x64\x65\x66\x0a\x2f\x57\x65\x69\x67\x68\x74\x20\x28\x52\x65\x67\x75\x6c\x61\x72\x29\x20\x72\x65\x61\x64\x6f\x6e\x6c\x79\x20\x64\x65\x66\x0a\x2f\x49\x74\x61\x6c\x69\x63\x41\x6e\x67\x6c\x65\x20\x30\x20\x64\x65\x66\x0a\x2f\x69\x73\x46\x69\x78\x65\x64\x50\x69\x74\x63\x68\x20\x66\x61\x6c\x73\x65\x20\x64\x65\x66\x0a\x2f\x55\x6e\x64\x65\x72\x6c\x69\x6e\x65\x50\x6f\x73\x69\x74\x69\x6f\x6e\x20\x2d\x31\x30\x30\x20\x64\x65\x66\x0a\x2f\x55\x6e\x64\x65\x72\x6c\x69\x6e\x65\x54\x68\x69\x63\x6b\x6e\x65\x73\x73\x20\x35\x30\x20\x64\x65\x66\x0a\x65\x6e\x64\x20\x72\x65\x61\x64\x6f\x6e\x6c\x79\x20\x64\x65\x66\x0a\x2f\x46\x6f\x6e\x74\x4e\x61\x6d\x65\x20\x2f\x42\x66\x6f\x6e\x74\x20\x64\x65\x66\x0a\x2f\x45\x6e" \
+"\x63\x6f\x64\x69\x6e\x67\x20\x53\x74\x61\x6e\x64\x61\x72\x64\x45\x6e\x63\x6f\x64\x69\x6e\x67\x20\x64\x65\x66\x0a\x2f\x50\x61\x69\x6e\x74\x54\x79\x70\x65\x20\x30\x20\x64\x65\x66\x0a\x2f\x46\x6f\x6e\x74\x54\x79\x70\x65\x20\x31\x20\x64\x65\x66\x0a\x2f\x46\x6f\x6e\x74\x4d\x61\x74\x72\x69\x78\x20\x5b\x30\x2e\x30\x30\x31\x20\x30\x20\x30\x20\x30\x2e\x30\x30\x31\x20\x30\x20\x30\x5d\x20\x72\x65\x61\x64\x6f\x6e\x6c\x79\x20\x64\x65\x66\x0a\x63\x75\x72\x72\x65\x6e\x74\x64\x69\x63\x74\x20\x65\x6e\x64\x0a\x63\x75\x72\x72\x65\x6e\x74\x66\x69\x6c\x65\x20\x65\x65\x78\x65\x63\x0a\x80\x02\x92\x5e\x00\x00\xd9\xd6\x6f\x63\x3b\x84\x6a\x98\x9b\x99\x74\xb0\x17\x9f\xc6\xcc\x44\x5b\xc2\xc0\x31\x03\xc6\x85\x70\xa7\xb3\x54\xa4\xa2\x80\xae\x6f\xbf\x7f\x98\xf7\x5a\x84\xba\xce\x2d\x03\x6a\x6b\x51\xb8\x48\x49\x31\x59\x1d\x92\xe5\x06\x9e\x62\x26\xd5\xad\xcc\x5d\xe4\xf8\x10\x7a\xa6\x9a\x35\xb5\x5f\x6a\x9b\x4b\x4f\x93\xc5\x6c\x23\xbc\xc6\x1d\xd7\xbf\x8f\x32\xf2\x1d\x58\xe4\x1a\x5f\x79\x0c\xee\x2f\x02\xaf\x49\x86\x95\xe9\x0c\x1d\x0b\xd2\x59\xe7" \
+"\x5b\x02\x19\x30\x0b\x0f\x69\x2c\x33\x77\x9c\x2a\xa6\x7a\xe8\x51\x7a\xbe\x12\x30\x08\x45\x22\x4a\xf6\xad\x5d\xa9\xdb\x9a\x1a\x3a\x40\xfb\x06\xb3\x6a\x9c\xcd\x69\x12\x55\x07\xfc\x2d\xe9\xd0\x41\x84\xc7\x60\x42\xf0\x3f\xcf\xd1\x53\x84\x00\x23\x97\x2a\x81\x2a\xb9\xb3\xcb\x56\x70\xc1\xce\x27\x59\x71\x1c\x75\x29\x42\x62\xd6\xf2\x91\xaf\x9b\x7c\x76\x07\x1e\xda\x7e\x7a\xd0\x26\x21\x62\x32\x22\xb9\x36\x08\x7a\xb2\x7f\xfe\x5f\x07\x86\x47\x06\x65\x92\x18\x3d\xc3\x47\xae\x92\xe6\xbf\x56\xb1\x7b\xed\xce\x13\x68\x46\xf6\xa2\xa3\x76\xab\x8c\x0b\xc0\xff\x4e\x34\x7d\x20\xfd\x0e\xc7\x7e\xfa\xb1\xf0\x63\x31\x00\x14\x8d\x2a\x7d\x2f\xd2\x1f\x12\x5a\xaa\xcd\x8f\xdb\x99\x79\x83\x2b\x67\x0d\x8a\xaa\x76\xd2\x12\xba\xb5\x61\x46\x19\x90\x96\x0c\x35\x6e\xb8\xd8\xe9\xf3\xc6\x5d\x9d\xfe\x7f\x8c\x2c\x8a\x7b\x2b\xe9\x9e\x63\xff\x6c\x86\x88\x3c\x1d\xe5\x07\x8d\xa3\xb9\x1e\x03\xe4\x84\x0d\xdd\x6d\x30\xe3\x3c\xe3\x87\x75\xdc\x80\x43\xc3\x93\x20\x76\x47\xbe\x83\x0b\xf5\xc8\x5d\x1e\xe2\x20\x72\x1a\x27\xe8\x8a\x21\x6d\xe8\x01\x0b\xe9\xd4\x4e\xdd" \
+"\x58\x9e\x87\x5f\x9f\x0e\x26\x1f\x0c\x6a\xff\x33\x93\x2a\x8b\xfe\xd2\x77\x06\x60\xdd\xe2\x8c\xb7\xd5\xde\x05\xcd\x0d\x8c\xfd\xd6\x7d\x67\xe3\x34\x3c\x66\x1f\xfa\xa3\x93\xe4\xa7\x3a\xcf\x9c\x44\xa6\x96\xa7\xa9\x74\x53\xc2\x96\x68\x98\x1f\x07\x9d\x26\x4c\x1d\x0a\xf7\x3f\x39\xc2\x6a\xe6\xb7\x78\x87\xbb\xc9\xd3\x52\xea\xa8\xb6\xa7\x5a\x38\x25\x6d\xa0\x90\x0d\x30\xcc\xbe\x0e\xa9\x67\x7f\x88\x66\x18\x51\x3d\x20\xe9\xe4\x9e\x12\xeb\xbd\x1c\x00\xde\x43\x11\x6e\x8f\x47\xdf\xb5\x21\x11\x42\x51\xd2\x07\x17\xba\xf5\xe5\xc6\x8f\x3e\x71\x21\x50\xec\x57\x94\x41\x2a\x1b\x6f\x80\xdf\xc4\x8c\x2d\x20\x5b\x7b\x9e\x88\x99\xa6\x90\x7e\x73\x85\xdc\xfe\xea\xc0\x7b\x0e\xef\x4b\xc7\x74\x1c\xf1\x19\x1e\x42\xe2\xf8\x9f\x8e\x2e\x29\x0a\xed\x6f\xcd\x1f\xe6\x48\xc4\x31\xc8\x32\x1d\x73\x99\x8d\xc6\xe1\xda\x9d\x56\x38\x43\xf9\x63\x32\x19\x97\x0e\xc8\x23\xba\xfa\xcc\x97\xbb\xd1\x33\x81\xa1\x44\x76\x82\x1f\x19\x86\xff\x4b\xaa\xf0\xe1\x71\x90\x05\xb2\x85\x2d\x55\xf2\x42\x0a\x0a\x41\x8a\x5d\x93\x48\xd2\xfa\xd1\x7b\x94\x87\x0c\x9c\x5e\x0d\xfa\x1f" \
+"\xd3\x9d\x52\x80\x84\x8f\x0b\x9b\x2f\xd3\x97\xe8\x8e\xfd\x52\x68\xea\xe7\xbe\xa9\x4e\x20\x5a\x02\x29\xc9\x7a\x8e\xcd\x90\xea\xcc\xc6\xe3\x38\x39\x06\x3f\x08\xed\x59\xc7\x1e\xe2\xa9\x30\xc6\xbf\x26\x72\x57\x87\xbd\x62\xfb\xe0\xd2\x9a\x3a\x57\x1a\x38\x29\xdb\x77\x7c\x6d\x53\xb6\xa9\xa6\x7b\xff\xbe\x23\x79\xb1\x25\x5c\x80\xf2\xf7\x84\xda\x95\x8c\x74\xb8\xa3\x0d\xf8\x8a\x44\x7c\xe5\xd3\x59\xd2\x65\xac\x95\xdd\xb6\x71\x24\xb6\x2e\x05\x8d\x7f\x93\x36\x76\x43\x6b\x69\xbb\x28\x35\xd0\xaa\x19\x2d\x71\xd8\x6e\x87\x38\x07\x1a\x0e\xe1\x3d\x4f\xe4\x48\x1e\x27\xdc\xc3\xe3\xe5\x99\xc4\x1c\x06\x6b\xf0\x36\x43\x06\x5e\x8f\x00\x22\xb4\x31\x0e\x29\x6f\x09\x29\x5e\xcb\xb8\x8b\x8e\x22\x8c\x8a\x5a\x19\xd8\x59\xfc\x2d\x2e\x84\xa9\x9a\xe6\x83\x0f\x14\x64\x63\xeb\x6a\x49\xb9\x59\x06\x42\xe6\xab\xca\x16\xd5\xe3\xb7\x20\x8a\x74\xfd\xd0\xe6\x79\x10\x3f\xee\x84\x45\x1c\x87\x58\x73\x12\x15\x0b\x66\xac\xc8\x25\xde\xff\x64\xdd\x50\xad\xda\x35\xd2\xfa\x94\xd3\xf1\x61\x96\xb9\x2b\xfa\x8a\x0e\x7a\x85\x1e\xbf\x36\x9e\x76\x16\x0c\xe8\x19\xe4\x3c" \
+"\x65\xce\x77\x1d\x39\x0c\x63\x24\xa7\xb6\x99\x56\xc3\x15\x46\x9a\x66\x6a\x2d\xec\x46\x97\x8f\xb9\xcf\xfc\x6a\x2e\xa8\x50\xd8\xce\x9d\xab\x76\x4d\x52\x99\x18\x36\xa5\x80\xa0\x1b\xc3\x75\xf1\x8d\x5d\x97\xe9\xef\xf4\x49\x7b\x85\x2a\x8a\x7b\x44\x9f\xe1\xd1\xab\xf2\x46\xd4\x06\xa8\x13\x74\xe4\x00\x0e\x94\xbf\x84\x0a\xfe\x53\x7d\x14\x11\x47\x7e\x8e\x38\x50\x37\x30\x7d\xb8\xac\x9c\xa3\xa1\x48\xf9\x69\xcc\xcf\xb3\xd9\x73\xb1\x02\x52\xdc\x8e\x0e\xb4\x8a\xfe\x53\x8b\x24\x46\xcb\x5b\x51\x52\xe5\x14\xfd\x4e\x84\xd5\x40\x9a\xa3\x3b\x5d\xf5\xa8\x26\x94\x30\xe4\x0d\xba\xcc\x5f\x8c\xb8\x76\x16\x82\x6f\x1b\x26\x8b\x7f\x6a\xac\xa1\xfe\x88\xbb\xa6\x30\xa2\x98\x7c\x45\x1b\xba\x32\x7e\x07\x90\x2b\x4b\xb0\x91\x9f\xca\xf4\x07\x4e\xcb\xfa\x20\x2a\xc3\x47\xba\x5a\x5c\xa2\x7e\x62\x2c\xc3\xa3\x2f\x58\x7c\x2b\xb1\x7a\xfb\xfe\x1d\xa1\x46\x62\xeb\x85\x34\x0c\x1c\xb8\x43\x91\x49\x58\x63\x45\x3c\xe3\x8e\x0f\xda\x52\xa7\x39\xe1\xe6\xda\x83\xfb\xab\x0b\x3f\xbf\x41\xec\xb2\x3f\x9f\xd5\xd3\x72\x40\xc8\x55\x49\x28\x5e\x7b\x6c\xab\x59\xa9\xce\x63" \
+"\xc4\x1f\x0f\x98\x8a\x4d\x89\xd2\xc5\xe4\xff\x49\x7e\x78\xf9\xd6\xaa\xd4\xa8\x49\x36\x7d\x71\x4e\xe2\x25\x89\xf9\xbc\xef\x21\xe7\xf4\x7d\x74\x89\x7e\xbb\x1f\xc1\xc2\x76\x79\x13\x50\xfa\x57\x30\x50\x3e\xf6\x1d\x79\xf7\x87\xc6\xc1\xfd\x94\xd3\x11\xd2\x11\xf7\x2c\xcd\x5b\x01\xbe\xc3\xec\x42\x5f\x90\x3a\xeb\x02\x2a\x4f\x19\x52\xa4\xa7\xf4\x72\xbc\xc0\x65\x17\x37\x45\x8d\xa8\x1c\x59\x3c\x74\x5b\xa2\x79\x1c\x7b\x60\xfc\xa5\xb4\x45\x38\xe8\x36\x7a\x8a\xdf\x9e\x83\x5e\xab\x52\x04\x70\x0d\xa0\x75\xaa\x92\x1c\xf1\x9a\xd3\x77\x10\xe9\x8d\x60\x5e\xa7\x0d\x25\x76\x69\x49\xd3\x61\x6d\x94\x83\xbe\x77\x2d\x7c\xd0\xe1\x27\x5e\x30\x3e\x21\xbc\xf8\x9a\xe9\x2e\x9e\x07\x90\x01\x79\x00\xeb\x47\x19\x34\x0d\x2e\x01\x19\xab\x1b\xb3\xaa\xa4\xe7\x02\x19\xb6\xe2\xfa\x60\xc0\x17\xb9\xda\xda\x10\x8c\x24\xb4\xd8\x3b\x5f\x31\xa5\xa2\x86\xfc\x2f\xa8\x41\xf2\xb2\xd3\x3e\x0a\xef\x99\x41\xdb\xf7\x48\x11\x69\x31\xfe\x55\x88\xd3\x75\xf0\xda\x4d\xdd\xa6\x29\x91\xc6\x04\x68\x88\xf1\x30\x00\x9e\xd2\xec\xcf\x1a\x91\x8c\x5f\xa4\x75\xc6\x00\xb7\x68\xa1" \
+"\x3b\x09\xbd\x08\x20\x2c\x1a\xff\x9d\x77\xf5\xfa\x31\xb0\x9c\xe3\x66\xe4\x69\x53\x18\x99\x55\xc4\x81\x85\x80\xd0\x81\xca\x3e\xcc\xad\x89\x5b\xdf\x70\xd0\xf3\x57\xb4\x6d\x52\x8d\x38\xef\xd2\x28\x56\xc8\xad\x1f\x20\xe6\x8c\xca\x3d\xdc\xb0\x5c\x6c\xcf\xb1\xd5\xa9\xee\xac\x9e\xfe\x26\xf2\x8d\x06\x73\xd9\xc1\x86\xa6\xe3\x24\xd0\x77\x56\x2c\x22\xc3\x47\x77\x5e\xea\xf1\x7a\x4f\xa9\xad\x24\xdd\x78\x44\x17\x03\x2c\x7d\x26\x4e\x48\xe6\x19\x3e\x12\xcd\xce\x42\x8c\x4f\x7d\xe5\xdf\x00\x5c\x19\x76\xfd\xa1\xdb\x33\xe4\xe5\xd4\x0d\x9b\x1a\x32\x36\x69\x36\x26\x55\x98\x31\x96\xe9\x58\xbf\x6f\x00\x7a\x93\x5f\xd7\x32\x21\xb0\xd1\x4d\x88\xc6\x06\x47\x61\x64\x98\x00\x9f\x5e\x5b\xca\x07\x94\x7d\xfe\x3a\x26\x6b\x31\x65\x0e\xc2\xa3\x0c\x4f\xfd\x99\x96\x36\x1e\x25\x8c\xbd\xf1\x8d\x2f\x39\x8b\x91\x4a\x58\x0f\xb2\xb3\x3f\xf1\x5b\x81\x1e\x4f\x13\x68\x48\x38\xd7\x25\x7c\xf2\x4d\x51\x6d\x9b\x00\xe9\x7a\xba\x6b\x5b\x91\x5c\xa2\x5a\x04\x71\xaa\x54\xd3\x84\x8e\x40\x1b\x5d\x98\xf8\x6b\x5e\x5d\xa0\x6d\xf9\xf1\xfb\x66\x82\x42\x60\x33\x70\x8c\xf5" \
+"\x97\x41\x2d\xbd\x9d\x75\xbc\x5b\x61\x31\x8a\x6b\x6a\x87\xcc\xcb\x26\x77\x21\x95\x57\x7a\x9e\xc6\x08\x8e\xda\x03\x38\xf9\x50\x56\xfd\x52\xf6\xcb\xe7\x39\xa0\x32\x34\xbb\x18\x6c\x82\xfd\xc1\x18\x33\xc9\x32\x03\x43\xb0\xbb\x7c\xa5\xac\x8e\xfc\x9c\x9b\xdc\xfc\x33\xed\x69\x5e\x30\x2c\xe9\xbb\xbc\x7b\x64\xda\xdf\x24\x72\x36\xdb\xdf\x27\x9c\x70\xce\x2e\x13\x0a\xd5\x8b\x45\x0c\x8a\x86\x2c\x82\x5e\x88\x04\x6f\x4d\x15\x73\xe1\xa2\x0f\x26\x9f\xda\x8a\x66\xab\x02\x8e\x30\x9e\x39\x5e\x3b\xb6\x11\x7f\xbe\xdf\xc4\x42\xee\x6b\x32\x9a\x02\x8e\xa7\x98\x12\x19\xe2\x01\xfd\xfb\x11\x66\x14\x6f\x1c\x61\x88\x0f\x3c\x41\xe6\x27\x31\x19\xa6\x1f\x12\x36\x04\x18\x59\xd3\xe2\xfa\x4a\xe2\xb9\x43\x8a\x1d\x12\x55\x9c\x7c\x91\x54\x11\xaf\xa7\x33\x0d\x36\x52\x61\x40\xce\xc9\x6f\xc7\xd6\xd2\xeb\x94\x37\xb5\xf1\x88\x56\xfe\xdb\x7a\x40\x67\xb3\x4f\x71\xa3\x7e\x4b\x6b\x4f\x66\xf4\x15\x93\xc6\xd2\xfb\x23\x88\x49\x0f\x20\x2d\x96\x86\xfd\x71\x53\x6f\xa1\x6e\xd4\xf2\x21\x0c\x0c\x10\x8f\xc2\xc7\x25\xe4\xfb\x6e\x07\xd5\xc6\x37\x50\x20\xd1\x8c\x22\x2f" \
+"\x66\xf9\xd9\xa6\x76\x1f\x6a\x02\x12\x6a\x2e\x92\x94\x7d\x00\xd0\x59\xd1\xf7\x37\x8f\xb1\x13\xb7\x7f\x47\x76\x14\x88\x03\xe9\x6d\x77\xb5\x73\xdf\x6e\x8b\xb6\xab\x6d\x68\x48\x3e\x98\x8f\x0e\x9d\x52\x9a\xfd\x8e\xd7\x3b\x01\x0b\x62\x6b\x8c\x0c\xf0\x90\x38\x26\x0e\xdc\xed\x9a\xae\x97\xb3\xcf\x68\xea\xde\x54\x7e\x9d\x5a\x34\x76\x7e\x60\x17\xcb\x87\x86\x29\x10\xc4\xd2\x2c\x7d\x44\x91\xe8\xec\x34\xde\x66\x83\x50\x65\xed\xda\xf4\xd7\xcd\x5f\x3a\x60\x12\x42\xd5\x5b\xf7\x3a\x2c\x39\x96\xc1\x8b\x87\x24\x8f\xec\x5e\xd1\xec\xd5\xe3\x2a\xb0\xad\xce\x57\x97\xf0\x91\xb9\x2d\xd1\xb1\xc9\x7b\x20\xc4\x2c\x9e\x53\xcb\xca\x06\x6a\x36\x5d\x2b\xd1\x0c\x72\x4c\x64\xf2\x68\xa5\x8a\x0f\x8f\x05\x21\xe4\xc3\xf3\x6f\x51\xf9\xae\x0f\xa7\x28\xa5\x33\x61\xb9\xd7\x96\x76\xfd\x16\x67\x09\x15\xb9\xee\xbd\x5e\x31\x68\x64\x62\xa5\xc4\x1f\x94\x70\x7d\xc7\x2e\x67\xfc\x4f\x64\xa5\x70\x68\x52\xf9\xdb\xcd\x22\xc6\x1f\xc6\xbf\xb5\x48\xd4\xb6\x3e\x57\x0d\x35\xab\x54\xde\x9c\x83\xc9\xa2\xad\x2f\x2c\xbb\x69\x77\x84\x2f\xe4\xb8\x24\x55\xda\x0b\xfb\xf2\x7c" \
+"\xcd\xa8\xfc\x18\xf5\x31\x54\xa1\x6b\xd3\x15\x3f\xdb\x59\x0f\x74\xc0\x12\xd0\x56\x5f\x4b\x47\xef\xf7\x69\x7c\x55\xae\x90\xdc\x18\xbc\x5e\x28\xd1\x84\xea\xe1\x35\x45\xf0\x2a\x2f\x5c\x12\xf0\x78\xd2\x8c\xa8\xda\x69\x3c\xf6\xf7\xee\xbc\xf7\x0a\xa2\x18\x88\xe2\x5b\x6b\x9d\xa8\x33\xba\x0f\x4f\x44\x9a\xe1\x34\x29\xe4\x7f\x23\x29\xe0\x61\xe1\x2c\x55\x10\xe1\x63\xc6\x30\xb6\x62\xeb\xff\xb2\x18\xd2\x3a\x0e\xc8\x54\x12\x84\x89\x23\xab\x3f\xc3\xee\xc3\xa7\xa7\x08\xcf\xe8\xd6\x64\x5b\xc3\x5a\xe9\x56\x62\xcf\xb9\xe5\xc4\x8c\xfd\xec\xdb\x96\x3e\x3e\x02\x0f\x33\xe8\x9d\x2c\xea\x6b\xbc\xdc\xd6\xd1\x2a\xa5\x12\x5e\x8f\xeb\xf1\xc0\xfe\x6a\x9b\x30\xf6\xef\x7b\x11\x8c\x0c\x65\xfb\x66\x9c\x7e\x82\x02\x26\x3e\xff\x1b\x86\xb6\x78\x17\x9e\x67\x04\x30\x9a\x4e\xec\x0e\xfe\xde\xef\x2a\xe4\xe0\x8a\x57\xd3\xec\x4e\xd4\x01\x6b\x8b\x51\x05\xee\xb9\x54\xcd\x33\x53\x43\x34\x2a\x87\xff\xf4\x7b\x9d\xb9\x74\x72\xa0\x74\xf6\x1e\x93\x7f\x81\x9c\x33\xe5\x27\x7a\x02\x7a\x91\xe5\x19\x7a\x02\x97\x07\x7d\xf6\x4c\x81\xd1\x6e\x8a\xf6\xd3\x21\xb7\x3c\xc0" \
+"\x6c\xa7\xa1\x9d\xad\xbc\x86\xc0\xb3\xcb\xc3\x88\x54\x29\x6e\xc1\x7a\x83\x0b\x4b\x7c\x53\x8b\x50\x0c\x47\x5d\xd6\xb3\x2b\x46\x8b\x5b\x35\xe4\x61\x69\x43\xe6\x76\x5c\xb7\x83\x72\xe7\x4a\x8c\x30\x87\xb4\x0a\xb8\x94\x2e\x4b\xb6\xcd\x53\x2f\x97\xce\x54\xf3\xe8\xe9\x7e\x8e\x1e\x0b\x71\xdb\xfc\x99\x12\x10\xd7\xee\x79\x9b\xff\x15\xd6\x59\x06\xc4\x03\xc9\x83\x30\xbb\x9f\xeb\x0e\x1b\x9b\xf5\x4d\xe5\x82\x70\xa8\xa4\xfd\x45\x17\xfd\xf2\xaf\x13\xe8\x9b\xa1\x1b\x9e\x5f\xa0\x5a\x4f\x6d\x85\xcb\x2a\x46\xb5\x78\xf7\xf4\x55\xbf\xa7\xff\x24\xfb\x73\x36\xbf\x4e\xd3\xb6\xfc\x05\x0c\x64\x20\x30\xc8\x1a\xea\x7b\x19\xa1\xfd\x86\xa8\x3c\x0f\xbb\x3e\x18\xef\xb1\x62\x5c\x6d\xc3\x70\x4e\xf2\xa1\xfa\xe0\xd2\x5e\x6f\x22\x64\xc4\x47\x67\x4a\x7b\xd8\xd9\xb4\xa0\x21\x40\x69\x7b\xb7\x7d\x54\x4d\x50\x63\x6d\xf7\xad\xa8\xef\x7a\x58\xe9\x75\xed\x94\x2b\x90\xc3\xff\xde\x7c\xd6\x85\x9c\x75\xf4\x07\x49\x0d\x64\xa4\x44\xaf\xbf\x5d\xe1\xfc\x80\x60\x4d\xe7\xc4\x96\xdf\x78\x38\x17\x65\x5e\x17\x32\x4c\x26\x1b\x59\xb8\x5d\x8c\x25\x4f\xf9\x42\xc7\x1b\xdc" \
+"\xe6\x72\xb0\xb3\xe4\xc9\x0c\x38\x71\x01\x19\xcf\x68\xb1\xbf\x4f\xed\x8f\xe2\x68\x5c\x15\xf9\x62\xcd\x16\x69\xd7\xb8\x8e\xb2\x6b\x08\xc2\x0d\x20\x9c\x54\x6d\x92\x98\x39\xf1\x48\x3e\x4a\x7a\xd4\x58\xb3\x39\x17\xba\x4a\x49\x52\x25\x50\xb6\xa5\x28\x59\x1e\xf4\xd1\x6e\xa3\x18\xb6\xc9\x8b\x91\xe1\x94\xdb\xb8\x01\x6d\x63\x9c\x25\xf7\xb1\x6f\x32\xd1\xdd\xd0\x4e\x00\x48\x06\xec\x4c\x4f\x3f\x84\x1a\xe3\x48\x8e\xe5\xf8\x78\xa0\x94\x9b\x5b\x33\x3d\x28\x16\xc0\x60\x8b\xc1\xc0\x29\x74\x4f\x8c\x74\x9e\xf8\x40\xa8\xe3\xae\x38\x72\x5c\xa0\x1f\xc8\x5e\x52\x63\x8b\x43\x5f\x2f\x4c\xb4\x98\x2b\x83\x95\xb1\x04\xd4\x38\xd1\xbe\xd1\x66\x7a\xe0\x48\xea\xf4\x6f\xaf\x8a\x78\x17\xcb\x09\x92\xea\xef\x5e\xf1\x1c\x15\xaa\x33\x02\xb0\x7d\xb3\xd9\x63\x53\x11\x10\x71\x7b\x6f\x44\x5e\x9c\xc8\x5a\x75\x1e\xae\x83\x2a\xa1\x5b\x4c\x55\xc7\x2c\x4b\xc7\x00\x9f\x6f\x9e\xec\x3f\xfc\x49\x43\xdc\x71\xa9\x9e\x4a\x07\x51\xd6\x95\x9b\xde\x81\x5b\x3f\xa9\xc4\xa8\xd0\xe6\x53\xa8\x04\x13\x1b\xb0\x9d\x92\x38\x2a\xfe\x8f\xab\x77\x3c\x7f\x39\x25\x6b\x54\xff\xf6" \
+"\x4c\x9f\x26\xb0\xe9\x0d\x61\x6b\x40\x37\xce\xc9\xcc\xda\x03\x8b\x7b\x96\x97\x6e\x1c\xc6\x63\xf7\xa7\x9b\x25\xb8\xfd\xd6\x15\xfd\xfa\xb3\x1a\xe9\x62\xcd\x75\x6d\x5e\xde\x0f\x97\xb8\x77\xdb\x9f\x1a\x34\xea\x37\x42\x64\x6c\xaf\xae\x11\x6f\x87\xbd\xf4\xee\xad\x17\x11\xf1\x88\x4e\x7c\x4b\xcb\x72\x87\xe4\xdd\x4f\xf4\xb4\x54\xd7\x78\x3a\xc1\xea\x11\x15\x84\x6e\x0a\x5d\x5d\x00\xb7\xf5\x86\x3d\x5f\x44\xbf\x8d\xed\x5f\x7e\x57\x3a\x95\x86\xd5\x6e\x74\xd8\xc0\x0a\x70\x26\xe8\x32\x23\x78\x39\x2d\xac\xe8\x25\x4d\xe2\x99\x6e\x83\xfd\xd2\xa8\xb4\x53\x38\x33\x38\xbd\xde\x61\xc1\x88\x8a\x2a\x94\x32\x6f\x18\x13\xfe\xb1\x6d\x2a\x04\x41\xac\x60\xfb\xa0\x36\x3a\xa5\xca\x40\x4b\x26\x3a\x4b\xb0\xd8\x62\x92\x7d\x76\xf8\x0e\x6a\xe4\xe2\x51\xf1\xfb\x7f\x1b\x17\x5c\x9d\x8c\x0c\x3b\x56\xfc\x7a\x0d\x80\x0e\xb8\x37\x9b\x2c\xfd\x1d\x2f\x7b\xbf\xb9\x9a\xa3\x72\xfa\xd8\x30\xda\x18\x29\x89\xba\xc8\xd1\x93\x56\xea\x0b\xfb\x2a\x38\xb5\xf3\xee\xa6\x87\x5c\x97\x56\xae\x59\x4f\x47\x0e\x18\x05\xb3\x57\x83\x87\x66\x3b\xba\x42\x01\x06\x48\x05\x1c\x4f" \
+"\x31\xba\xc2\x3e\xb3\x35\xba\x1f\x8f\x0f\x69\x20\xfb\xbc\x8a\x0b\xf4\x24\x64\x65\x50\xbb\xfd\x35\x5a\x9a\xd4\xb5\x7e\xd1\x3a\x0a\x37\xa8\x1b\xec\x73\x65\xe0\xc1\x67\xe7\xe7\x4c\x82\xa9\x40\xf7\x8f\xa0\x06\x0c\xbb\x3e\x73\x55\x85\x61\x83\x9d\xa4\x05\x12\x33\x45\x35\xe2\xaa\x20\xf8\x85\xc2\x3a\x72\xf3\x9c\x35\xdb\xe4\x25\x33\x96\xf0\xe3\x4a\x64\x42\x8c\x73\x64\x67\x2f\xa0\x91\x27\xa0\x4b\xde\xda\x1c\x6c\xe8\x6b\x5b\x00\x39\xfa\x88\x06\x21\x76\x73\x67\xb3\xdd\x6c\x28\x8e\xaf\xb9\x02\x0c\xc0\x42\xd5\x98\x29\xe9\xdf\x29\xd4\x55\x11\x34\x3a\xd3\xb5\x2e\xd3\xce\xbd\x1a\x08\x5a\x73\xe0\x97\xc3\xe0\xd5\x22\xa2\xbd\xde\xda\x9b\x4e\xc9\x65\xf2\x09\x38\xd7\x98\xef\xf7\x79\x03\x10\xdd\x38\x2d\x23\xf3\x92\x80\x2c\x72\xd7\x84\x65\xdc\xe9\xb4\x02\x1d\x57\xcb\xb9\x90\x10\x25\x71\x3c\xf4\xd6\x8c\xbf\x18\xc0\x25\xff\xa1\x93\xd8\x1e\x28\x9b\x58\x3c\xba\x87\x0b\x17\xe4\x2b\x9d\xcb\x66\xc4\xc5\x01\x01\x57\xda\x7e\x50\x4c\x1e\xb6\xcf\x99\x87\xf8\x06\xb5\xd7\x4d\x80\xc8\x0a\x13\x6b\x8a\xca\x54\x78\xbf\x8c\x75\x32\x20\x1b\x69\xae\xe0" \
+"\xaa\x7b\x35\x4c\x30\xd2\x06\xe3\xc3\x72\xeb\x57\x91\x96\x1a\x15\x11\xd6\xc6\xf5\x7d\x6d\x9c\xaa\xcc\x8f\xe4\x3e\xc4\x80\x15\xf3\x99\x5b\x47\xa4\x71\xa4\xff\x30\x24\xee\x69\xdc\xa3\x5d\x03\x21\x2f\x96\xf1\xd3\xbe\x6f\x9d\xea\xbd\x19\x3a\xf7\x4b\x76\xf7\xa7\xab\x76\xdf\x01\xb4\x62\x53\x00\x02\x6d\x11\xff\x74\xf4\x6b\x65\xdc\x64\x46\x15\x85\xb3\x5a\xd2\x74\x20\xc5\x18\x52\x72\x78\xda\x0e\x93\x50\xc2\x50\x45\x4e\xdf\x9d\xb7\x82\x31\x8b\xa2\x22\x0c\xb0\x2d\xf2\x67\xe8\x80\x44\x58\xe1\xb5\x95\x03\xd2\x14\x26\x9b\x06\xce\x88\x16\xaa\x5c\x9c\xa5\x74\x8e\xfa\x48\xcb\xeb\xc1\x74\xf4\x04\xd1\x37\xba\x1d\x08\x21\xc1\xdd\x49\x1b\xd4\xcc\x16\xc5\xb3\x08\x7a\x86\x08\xff\x60\x33\x02\xa9\xc1\x60\x80\xb2\x6d\x8f\x83\x32\xdb\xd0\x3a\x9f\x67\xe9\x64\x1a\x02\xb1\x81\x7a\xa8\x78\x47\x27\x73\xe4\x6c\x72\xa1\xf3\x18\x0a\xdd\x69\x00\x20\xe6\x4b\xd0\xe9\x04\x46\xf9\x62\x25\x2e\x57\x9e\x91\x3c\x55\xe5\xc7\xec\x7e\x50\xb7\xb5\x0c\x44\x03\x0f\x17\x24\x5c\x92\x6d\x3d\x18\x80\x4e\xef\x58\xe6\xd7\xcc\x5a\x93\x76\xab\x33\xa8\x5f\x5d\x17\x5a" \
+"\xf4\xa4\xac\xc9\xde\x70\x8f\xc1\xd1\x82\xc9\xcf\x76\xaf\x33\x03\x53\x90\x35\x07\x02\xdf\x92\x32\x65\xa8\x9f\x85\x1c\x42\x1d\x40\xe9\x4c\xb6\x85\xac\x44\xdf\x72\xfe\xec\x6f\x1e\x49\x89\x82\xa4\x83\xc4\xbd\x6f\x9b\x93\xd9\x40\xc2\x73\x8f\xc9\x4d\x16\x99\xe4\x53\xbf\x35\xd2\x57\xea\x15\x22\xbb\xb8\x1c\x3f\xb3\xd6\x53\x0e\x70\x20\xa9\x9f\x85\xcf\x13\xa9\xbc\x93\x6f\xba\x72\x2b\x76\x98\x19\x47\xb8\xf7\xef\x3e\x27\x7d\x08\xb0\x5b\x2e\x7f\x25\xa9\xf7\xba\xaa\xe7\x6a\x7c\x5d\x52\xcb\x87\x32\xb1\x55\x4a\x73\xdb\x4c\x60\xad\x2c\xf2\x26\xa3\xab\x0e\x00\x5f\x4c\x63\x4b\x0e\x27\xd5\x74\xb6\x48\x02\xea\xb0\x41\x62\x96\x24\x46\x56\x89\x97\xda\xf5\x8d\x11\x18\xe9\x29\xb9\x3a\xb2\x38\x36\x7a\x94\xe7\x97\x29\xd6\x60\x04\xf3\x2e\x3f\xc8\xe9\x80\xa1\x5f\x8a\xf4\xb7\x8d\x91\x0e\x19\x5b\xc5\x46\x03\xe3\xbb\xcb\xdf\x30\x78\x71\x07\x00\x82\xc1\xa0\x43\x6c\xb9\x47\xed\xab\x65\x9f\x60\x62\x22\x04\x8e\x72\x9b\xa0\x93\xc1\xaa\x30\x73\xfd\xac\xf5\x3b\x91\xb0\x37\xcb\xf5\x3c\x18\xf7\xeb\x4f\x0c\x75\x4a\x12\x97\x0e\xd0\x07\xe3\xe6\x8a\xb6" \
+"\x6b\x21\xac\xd3\xe8\xf4\x5b\x56\x50\xed\x37\x9a\xaf\x20\xdd\x11\x97\x4f\x68\xee\x19\xe2\x4c\x9b\x48\x27\x5a\xd1\x5d\x77\x36\x11\x09\xde\x3e\x12\x88\x19\x0f\x3b\xc2\xcb\x39\x96\x00\x34\x7a\x68\x54\xc7\x68\xb4\x9a\xb4\xb1\x8d\xad\xa9\x9a\x71\x23\x4b\xc6\x9d\x96\x50\x2c\xd4\xf8\xae\xe8\xfb\x8c\x4a\xd6\xbd\x29\x78\x71\x9c\x41\x10\x0f\xc9\x12\x2d\x10\xd2\x68\xf7\x26\x21\x28\xf9\x3d\x77\x99\xb3\x48\x58\x7a\x6d\xd0\x5b\xba\xe7\xf6\xc9\x9a\x1a\x24\x73\x7e\xd9\x2c\xc2\x8c\x67\xe5\x0f\xfa\xe3\x8c\x6a\xcc\x76\xa9\x9d\x54\x96\x1f\x80\xc2\xfe\x90\xdd\x54\x4f\xd3\x94\x21\x3c\x6b\xd3\xaa\x9f\xf8\x69\x3f\x72\x00\x17\xea\x5c\xe6\xf0\x76\x06\xfa\xb5\xb8\xe3\x40\xba\x28\x5e\x43\xe1\x85\x59\x0f\x10\xae\x90\xa5\x3b\x06\x49\x0d\x12\x1d\x0a\x2e\xed\x17\x33\x21\x1b\xc1\xd4\x3f\xc2\x05\x4f\x42\xb1\x51\xc8\x54\xfe\xe1\x24\x6e\xd0\xe1\xca\xd5\x59\xd6\x8c\x8e\xe3\xdf\x3c\xd6\x13\x91\x5c\x5c\xa4\xcf\xde\x9e\xfa\x0c\x92\x96\x43\xcc\x78\xd3\x6d\x5f\xba\x28\xa7\xb2\x5a\x22\x2e\xea\x1c\x6d\xab\xb6\x53\xc5\x24\x33\x45\x98\xa8\x79\x30\x47\xb3" \
+"\x16\xda\xa8\xb6\xa0\x93\xc3\xb1\xb0\xc9\xea\xd5\xd1\x87\xde\x09\x01\x9d\xaa\xf0\xaf\xf6\xda\xff\x5c\x35\x66\xab\x16\xeb\xb4\xf8\x76\x0a\x55\x0e\x18\xda\xb8\x84\xbf\xe1\x70\x42\x03\xe7\x24\xeb\x22\xd6\xb5\x39\x68\x97\x4c\x45\x65\x53\x14\x27\xaa\x6c\xa1\xef\xec\x7e\x09\x90\x1b\x75\xd1\xae\xad\x5c\x10\xb9\x19\x08\x41\x1d\x86\x43\x01\xf8\x3e\xdd\xef\x86\x0c\x0f\xfc\xcb\x8c\xb3\x34\xf7\x03\xe6\x22\xb8\x66\x52\x76\x4c\xda\xfe\xf2\x18\x73\x16\x77\x5a\x04\x95\xec\xb0\x74\x44\x4d\x7b\xc9\xc0\xff\xbc\x6b\xc3\x03\xd9\xb8\x6a\xdb\x74\x51\xcf\xc1\xe3\x65\x29\x1d\xe8\x48\x55\xec\x97\x4a\x5d\x96\xa6\xab\x9b\x51\x83\x51\x6d\xab\xb8\x25\xbe\x72\x6a\x71\x90\xea\x4c\x8f\x5c\x62\xbe\x70\x97\xc6\x97\xb5\x63\x07\xb6\x32\xbe\x9d\x8d\x11\xc7\x94\xe6\x0e\xf0\x5f\xee\x8b\xa1\x60\x55\x89\x9a\x4f\x43\xa8\x65\xfd\x7e\x17\xa5\x8f\x2f\x21\x9d\x64\x06\x82\xfd\xbc\x42\x15\xcd\xf3\x74\x3e\xf1\xa1\xb1\xc7\xea\x3d\x87\x37\x71\x19\x99\x1b\x81\x95\xbd\x8c\x70\xd3\x31\xb0\x26\x2c\x6e\x1d\x87\xb2\x7a\xe9\x03\xa6\x61\xaf\x3d\x9f\x62\x3d\x36\x2e\x3e" \
+"\xf6\x89\x11\x96\xf9\xa5\x63\xd3\xac\x4c\x07\x68\x27\x6a\x77\xdd\x9f\xd2\x60\x21\xec\x57\xa4\x70\x2f\xe2\xf7\xec\x8c\xb9\xb6\x14\xc9\x33\x58\x61\x34\xc6\x46\x31\xf8\x60\x33\x52\x73\xa9\x4e\x49\x70\x7b\x6a\x78\x71\xb8\x5d\xc2\xe0\x44\xd3\xc8\xed\xd1\x29\xa0\x7f\x59\xa3\x37\x09\x1b\xfc\x4e\x5d\x93\x8d\x0c\x9c\x2c\xe2\x6a\x7e\x9f\xb5\x6a\x54\x19\x27\xdc\x29\x86\xb8\xad\x45\x8d\x80\xdd\x39\xc2\x38\x29\x94\x6b\xf2\xf1\xae\x81\x98\x7b\x51\x65\x01\xcc\x09\x6d\x9a\x61\xa9\x3f\xa7\x34\x60\xef\x3f\x74\xa3\x7a\x9e\x5e\xdd\x23\x5a\xb8\x45\xba\xdc\x9b\xcd\x41\xbf\x1f\xd1\x3e\x78\x9c\x4d\x9a\xd4\x3a\xa5\xd0\xfe\x41\xcc\x94\xc8\x79\x4e\x81\x4f\x79\x27\x22\x03\xa9\x76\x78\x34\x23\x77\x8e\x1d\x0f\x90\x9c\x5a\x86\x65\x69\x0b\x70\x20\x4a\x00\xdb\x9f\x84\x64\x07\x6a\x58\x8e\x2a\x9f\x9f\x85\x0b\xaf\x5c\x58\x90\x0c\x37\xb9\x2f\x8e\x1f\x2b\x27\x10\x53\x7a\x36\x07\x96\x9e\xd7\x0e\x8f\x88\x93\x8d\xe7\x9d\x43\x98\x77\xa4\x72\x9f\x47\xd2\x90\x62\x7f\x2c\x84\xda\xaa\xb7\x06\xb9\xd2\x5e\x5f\x63\xf0\x74\x1e\x7e\x4c\x73\xd4\xf6\x66\x5c\x60" \
+"\x9f\xfc\xb1\xad\xee\x57\x91\x78\xef\x53\x67\x94\x6f\xc1\xc8\x9d\xc7\x54\xf5\xa7\x44\x2b\x09\x45\x37\x53\xa4\x6d\x5a\x2e\x65\xd7\x24\x17\x4a\xaa\x49\x1f\x97\x3f\x0d\xe9\x97\x6b\xf8\x1c\x5c\x23\x46\x05\xeb\x55\xdb\x14\xd5\x99\x9d\xf9\xb0\x25\xff\xbf\x31\xdd\xc3\xf3\xcd\x96\xee\xea\xa8\x89\x99\xc9\xde\xcd\xc7\xa2\x77\x92\x29\x59\x69\x72\x90\x1b\xc2\xa7\x0f\x11\x66\x9b\x51\x14\x40\x19\xeb\xd9\x3f\x9a\xf2\xe1\x0d\x21\xb6\x26\x74\x2f\x6b\x32\xcf\x6e\x1d\x88\x37\x21\x8b\x88\xd6\x3f\x5c\x7d\x5a\x76\xca\x07\x0d\x2d\x2b\xa2\x6a\x35\x8f\x0d\xbe\xab\xe2\xc4\x90\x11\x31\x88\x78\xf6\x63\x1c\xdb\xb8\xab\x91\xe8\xf2\xe1\x56\xd8\x1d\xfb\xf9\x29\xf4\x90\x6f\x02\x0d\x43\x45\x61\x3b\xca\x5c\xfe\x47\xbd\x06\x77\xb4\xba\xcb\x22\x12\x55\x73\x67\xb2\x0f\x8b\x2a\x9a\x27\x18\x00\x13\x16\xf0\xff\xfc\x5d\xd9\x97\x76\x59\x4c\xe4\x75\xc8\x89\x0d\xbe\xf7\xff\x18\xfd\xa2\x18\xb8\x14\x46\xad\xf2\x41\xff\x0e\x55\xeb\x63\x67\x83\xb5\x54\x50\x3f\x9c\xb8\xcc\xbf\x3d\x9c\xfc\x3b\x25\x6d\xe5\x66\x8b\x5e\xb2\xb2\xa4\xe7\x31\x9b\x23\x38\xc4\x0f\xa9" \
+"\x90\xfb\xd7\x59\x81\xe6\x48\xdb\x8b\xc5\x4e\x6d\x66\x19\x30\x2c\x7b\xd3\xd8\x6a\xb9\xed\x7c\x85\x27\x25\xa2\x14\xd3\x86\x9b\xa8\x0b\xde\x98\x8f\xd3\x70\x85\x88\x15\xa9\x59\xbb\x5c\x3d\x90\x7e\x8e\xa5\x5b\x40\x2d\x29\x38\xa4\x6c\x31\xf1\x89\x63\x2c\xbf\x64\x0b\xe1\xa6\xf4\xb7\x0e\x45\x8d\xb8\xc1\xdc\x48\xd3\x43\xdf\x10\x2b\xe3\x22\x57\x5b\x20\xe5\x54\xa2\x71\xfb\x7d\xda\x76\x1f\xfe\x10\x21\xaa\xc9\xd1\x31\x1e\x71\x68\xc1\xd4\x52\x40\x50\xd6\x20\x95\xd9\xf4\xed\xc1\xdf\x68\x4d\x80\xe4\x8c\x37\xfc\xcc\xe5\xbb\x24\x63\x99\xf1\x8a\x87\xab\xa9\x3e\xfa\xb8\x3f\xa7\x8b\xb7\x39\xaa\x24\xd9\xc9\x81\xa9\xde\x4e\x99\x41\x99\xc3\xd3\xe5\x9f\xbf\x00\x91\x0c\xd1\x19\xf7\x7a\x13\x6c\xad\xa3\xbb\xeb\xfe\x57\x50\x19\x6e\xb3\x9e\x30\xe8\x14\x8a\x51\xc6\x4e\x12\x2c\x4b\xb5\x12\xee\x60\x3d\xf7\xe5\xfe\x02\x37\xa9\x20\xb4\x88\xb1\xa1\xd5\x84\x80\x6c\x5d\x9f\xc9\xd4\xee\xdf\xe9\xba\xf3\x04\xf8\x05\x21\xd6\xc1\xd6\x5f\x33\x8d\x3c\x48\x3f\x8e\xb8\x25\x7a\x76\x88\x61\x5d\x8e\xf5\x08\x93\xe0\x7e\x43\x5d\xaa\x69\x79\xe7\xab\x55\x69\xbf" \
+"\x7e\x58\x39\x2a\xfd\xb3\x55\xfb\xc1\xa3\x70\x47\x1c\x89\x68\xc7\x79\x0d\x7a\x3a\xe7\xa0\xb0\x32\xc8\x50\x41\x63\x19\x43\x81\x5b\x61\xb2\x83\xc3\x6f\x94\x86\x47\x39\x91\x71\xd1\xb1\x33\x9a\x1d\x1c\xb4\x4a\x0d\x45\x93\x60\xd2\x6c\xb0\x59\xf8\xee\x40\x8c\x55\xc4\xa9\x14\xfb\xee\xc2\x29\x38\x27\x3b\xe2\xbd\x82\xb2\x5a\xb0\xe2\x2e\x6c\x9c\xcc\xae\x55\x76\xa5\x89\xb8\xa0\x85\x59\xaa\xb8\x25\x30\x41\xf1\xe0\x75\xa4\xf8\xd5\x70\x8f\x80\x17\x82\x85\xd8\x42\xbe\x3f\xee\xb3\x54\x47\x1b\x32\x53\xc7\x5b\x7e\xa4\xc0\x4c\x6b\x64\xe5\x06\x19\xa4\x59\xeb\x75\xf7\x3d\x6d\xcd\x4c\x80\xe6\x29\xf3\x55\x3a\xbd\x80\xd8\x15\x35\x44\x50\x01\x19\xab\xcb\x47\xb0\x2e\x06\x54\x23\x96\x5f\x90\x90\xfd\xd2\x4e\x0a\x1f\xda\xb3\xf8\x5f\x51\xf4\x4f\xd7\x3f\xc4\x64\xa5\x78\x36\x0e\xb4\x7d\x98\x6a\xad\x7d\x0e\x6c\xd3\xa1\x83\xe5\x72\x38\xfc\x10\xdd\x10\xf2\x4a\x57\xa8\x79\x7f\xf7\xd4\xc8\x47\xcc\x74\xf6\xff\x9a\x18\x89\x7f\x2d\xb1\xd4\x11\xd4\x66\xec\x1d\x58\xb1\xa6\x87\x6b\xd2\xe6\xdb\x7c\x47\x62\x32\xe6\x6b\xde\x4f\xde\xbe\x25\xf1\xf2\xa7\x1b" \
+"\x75\xfd\xc9\x4c\xfb\xba\x12\x87\x60\xbf\xcf\x0f\x6b\x43\x92\xfb\x69\x66\x19\xc8\x47\xd1\xa5\x7d\xc0\x12\xe4\xa2\xee\xd6\xdd\x8a\x31\x28\x64\x7a\xf9\x14\x79\x39\xc7\x0b\x00\xf3\x4c\x39\x17\xd3\x6e\xd4\xfa\xda\x5f\x9a\x91\xb3\xad\x2d\xe9\x9b\xf6\x43\x23\xcb\x5d\x05\x02\x5b\x79\x74\x5d\x40\x45\x1f\xb6\xb3\x4a\x3b\xc6\x29\x13\x66\x33\x4c\x7e\xe0\x99\x41\xfe\xba\x5a\x10\x5b\xdc\x9a\x82\x14\xbb\x67\x8d\xf8\xbc\xf5\xfa\x8b\xbf\x30\x8a\x28\xc7\xc9\x9b\x93\x53\x3e\xfe\x50\x03\x6b\x68\x24\x67\xba\x5e\xba\xe1\x6b\xa7\x76\xe6\xc7\x55\xf1\xdb\x8b\x14\x1c\xe9\x05\x83\x90\x65\x15\xe4\xec\xf9\x73\x52\x3e\x93\xaf\xfb\xae\x80\xb0\xff\xf8\x8e\xef\x71\xa5\xfe\xee\x16\x63\xa2\xca\x6c\x4f\xeb\xf6\x20\xdc\x0b\x33\xef\x6d\x04\xcc\xb3\xd4\x56\x26\x05\xe8\xaa\x4c\x97\x83\xa5\xce\x7a\x69\x7c\x6b\x1c\x89\xc4\x63\xc2\x06\x7a\x1d\x4b\xb2\x1a\xe8\x46\x21\xe7\x18\x49\x21\xbb\xb5\xf0\x4b\x16\x72\xa3\x62\x72\x06\x5d\x02\x20\x10\x4f\x5d\x77\xdb\x99\x0f\xb6\x81\x7b\xf2\xa2\xb6\x98\xc8\x18\x0e\x5f\x30\x23\x3c\xed\x47\xb7\x98\x5c\x86\x1f\x52\xae" \
+"\x35\x9b\xaa\x60\xdd\x5d\x89\x5a\x1f\x80\x14\x83\x0f\x56\x9a\x5d\xbe\xb2\x7c\xd6\x82\x2b\x40\x86\xf9\x00\x30\xd7\x5c\xec\xca\x18\x2f\x3c\xe8\xbe\x7c\x03\x47\x91\xb7\xd7\xf0\x01\x64\xeb\xcb\xb9\xcd\x7a\xde\x29\xc7\x7f\x04\x4a\x39\x5c\x50\xe3\x6d\x51\xc5\x20\x26\x23\x35\x5e\xf5\x09\x8d\xf5\xdf\xdf\x5f\x2a\xaf\x9d\xd1\xd7\x5a\x40\x00\xf8\xf4\xf6\x19\x3c\x07\xa9\x8a\xf6\xb8\x60\x9b\x44\x5e\x9b\x16\x0f\xf1\xa9\x14\x31\xd7\xd1\x6f\xef\xc8\x90\x05\x21\x99\x8e\xef\x94\x6e\x75\x6d\xf8\x43\x62\x6d\x9d\xbb\xac\xa0\xa9\x55\x36\x00\x99\x81\xd9\x96\x43\x7c\x97\x65\x6a\x83\xcf\x86\x05\xff\x8b\x92\xc0\x00\x73\x5b\x06\x81\x3a\x3c\x67\x6a\xdf\x34\xd3\x66\xfc\x99\x07\x24\x22\x20\x88\x6f\x18\xe7\xda\x65\x72\x31\x80\xb9\x3a\xeb\x1a\x6c\x94\xd8\x02\x6d\x7f\x4c\xaa\xe6\xa7\x4d\xe6\x90\x78\xea\xb7\x4e\xf6\xcc\xe4\x86\xf9\x58\x64\xc4\xc6\xa8\x71\xd8\x2a\x23\xc1\xea\x22\xc3\x98\x7d\x4f\x4f\x18\xa1\xad\x10\xae\x2e\x43\xaa\x83\x9c\xe8\x56\x59\xad\x1e\x27\xd1\xb1\x32\x89\x54\x6d\xcb\x19\xb3\x69\x2a\x97\x8d\x38\x2f\x92\x6d\xaf\xe1\xf3\xd2" \
+"\xce\x51\xc4\xed\x9f\xc9\xa5\x37\xb5\x99\x45\x99\x75\x76\xd9\x82\x41\x8b\x44\x76\x3b\xc9\xca\x52\x81\xa2\x17\x66\x3d\x9b\x6d\xce\x7d\x29\x6f\x8b\x53\xae\x85\xf2\x2c\x02\xeb\xba\x3a\xf7\x63\x88\xad\x6a\xfa\xf8\x22\x98\x85\x03\xd0\xaa\x81\x17\x3c\x49\xd4\x2e\xbf\xbe\x58\xcf\xdd\xa4\xb2\x2d\xd7\x83\xcc\xe1\x75\xad\x8a\xb4\x03\x00\x0f\x0e\xdd\x49\xb8\x16\xa7\x53\xd8\x1f\x89\xfe\x6c\x5a\x15\xeb\x05\x44\x8f\xec\xda\xb1\xaa\xef\xb4\x08\xa8\x8c\xe2\xbd\x10\x91\x3e\xa3\xe1\x5d\xcd\x25\x78\x62\x81\xf9\x81\xfd\xd5\xae\xc8\x13\x8f\x8c\x09\xb1\x32\x69\x86\x45\x71\xf4\x85\x06\x78\x19\x9b\x84\xfe\xe2\xcf\x2b\x38\xa8\x45\xa9\x5f\x53\xa6\x22\x45\xd5\xbb\x62\xf3\x77\x8f\x79\xf9\x77\x81\xa5\x67\x92\x8c\x0d\x88\xee\xa0\xaa\xfd\xab\xd4\x62\xef\xac\xc3\xf9\x44\xcf\x3c\x18\x82\x80\xa7\xa3\xb2\x82\xdc\x06\x8b\xc6\xc9\x6e\x1a\x5b\x9b\x90\x8f\xd4\x55\x6a\x32\xc6\x4a\xd2\xa8\x92\xe8\xac\x1e\x98\xce\x45\x2c\x2f\x58\xa5\xb4\xdd\x2d\xfc\xf8\x2f\x1a\x21\x8e\xbd\x4d\x4d\x14\xb9\xf7\xf9\x58\x43\x75\xf9\x97\x76\x39\x12\x89\x80\xbd\x86\x94\x55" \
+"\x07\x2f\x3c\x8e\x6e\x69\xfc\x2d\xa5\xbb\x86\x32\xff\xb4\x38\x82\x89\x4c\xbd\xda\x98\x2e\x94\x2c\x01\xef\x2f\x48\xc0\x46\x0e\x4a\x5a\x88\xf5\x23\x28\xab\x1d\x11\x61\x4d\xb8\x20\x26\x26\xfc\x0c\x00\xe2\x0b\xde\x84\xb7\x79\xd1\x53\x03\xa4\xf3\x20\x6f\x6d\x91\xcb\x39\xf1\xc0\x05\x6b\xa4\x80\x03\xda\x45\xb2\xc8\xde\x2d\x41\x69\x6e\x73\xb8\x4b\xf3\xdd\x31\xe2\xaa\xbd\x31\xf6\x81\x21\x96\x26\xcb\x03\xd6\x6f\xce\x96\xa8\x89\xa2\xe4\x03\x60\x69\xb8\x1b\x6a\x51\x20\x93\xe6\x3c\xdb\xc7\xb0\x4a\x64\x12\x50\x8c\x46\x80\x73\x77\x6f\x52\xac\x08\x06\xa8\xbc\x38\xc5\x70\x9f\xa9\xd8\xc8\x5a\xfb\x68\x70\x13\xb3\x47\x3b\xb5\x8a\xe0\x9e\xfc\x94\x32\x41\x37\x21\x78\x8e\x89\x6c\x14\x8e\xec\x90\x59\xc5\xbe\xbc\x13\x66\xe3\xf0\x26\xaa\x81\x7b\x45\x7b\xc1\x0d\x25\x85\x2c\xa7\xd2\x8d\xac\x9a\xd0\x2a\x9c\x23\x7e\xb0\x01\x62\xc1\x87\x66\xeb\xe5\x16\x22\xbb\x12\x6f\x40\x53\x6b\x11\x9d\xf1\x75\x3b\x08\xd3\x3c\xc8\x57\xb8\x59\x84\xf9\x3c\x12\x51\xed\xe1\x35\xdd\x83\xff\xda\x40\xef\xc2\x07\xb5\x28\x03\x2e\x6c\xdc\x34\x6c\x3e\xfe\x8c\x25\x74" \
+"\x0f\x28\xa9\x5a\x2f\x88\x66\xfd\x07\xdf\x84\xcf\x3c\xea\x15\x86\x9b\x3f\x70\x25\x48\xde\x37\x3b\x14\x22\xa7\x47\xde\xdd\xa4\xa1\x5c\x83\xf4\xeb\xf3\xed\xb8\x81\x4d\xa5\xa0\x8b\xab\xea\xea\x45\x71\x80\x5d\xd7\x09\x54\x29\xd5\x23\xa4\x18\x78\xcc\xb4\xb2\x99\x2f\xf5\x39\x16\xaf\xce\x0c\xaf\xcb\x81\x27\x5d\x7f\x12\x0c\x37\x2b\x24\xfc\x01\x68\x74\x3b\x87\xc1\x91\xb7\x29\x3e\x4e\xa5\xbd\xe8\x80\xe0\x0b\x8e\xff\x02\xdf\x5f\x50\xdb\x57\xf9\x79\x1f\xb5\x32\xf1\x1f\x7f\xae\x63\xee\xb0\x74\x41\xdc\xa0\xbd\x19\xcc\x67\x14\xe7\x2a\xc3\x22\xb4\x69\x79\x6e\x63\x95\x8b\x01\xdd\x7c\x43\xac\x2f\xbd\xcf\x0e\xe5\x4f\x9e\xbb\xcb\x7e\xec\x0e\x35\x79\xf3\x84\x4e\x27\x48\x07\xa5\x16\x4e\x29\x65\x80\x14\xa8\x88\xc6\x6d\xe2\x20\x87\xa8\x68\x9b\x73\x39\x32\x42\x11\x48\xf5\x7c\x46\xbc\xc2\x90\x59\x8c\x55\x08\x0a\x81\xe3\xa7\x0f\x0f\xc9\x36\xef\xc2\x9a\xcc\x81\x1b\xbe\xf5\x66\xa6\xb2\xc9\x07\xc5\x4e\x95\x45\xf5\x04\x8f\x04\x54\x0d\xd9\x3b\xf2\xdf\xe2\xc7\xe7\x76\xbc\x37\x73\x38\x0f\xd9\x03\x00\xb5\xbe\x03\xa2\x7f\x78\xce\xb5\x08\xe1\x9b" \
+"\x94\xca\x75\x46\x60\x51\xf6\xa5\xfd\x73\x94\xd9\x8a\x2c\xcb\x24\x2c\xdd\x3b\x7a\x44\xaa\xf8\xeb\x58\xf2\xd1\x2a\x47\x1f\x75\x05\x95\xdd\xd8\x9a\x74\x29\xe7\x8a\x7b\x55\x80\x47\x6d\x6f\x11\x48\xa3\xe1\x6d\x07\x28\x85\x4a\x4c\x9b\x6b\x22\xc1\x72\xf0\x3d\x1f\x18\x2e\xd7\xc5\x60\x72\xd5\x12\xd6\x39\x77\x32\x12\x05\xaf\xfe\x15\xf6\x40\x91\xab\xd9\xf3\x9f\xfa\xe7\xe4\x40\xa4\x61\x3d\x96\x09\xe6\x0b\x8a\x84\x5f\xd1\x8a\x61\x57\x8b\xbe\xab\x87\x9e\xaa\x63\xc6\x12\x7f\x2c\x66\x01\xec\x5a\x49\xd6\x87\x74\x6b\xf7\xaf\x2e\xee\x33\x4f\xa3\xf9\x05\x89\x91\x5c\x8a\x17\xcf\x9e\x32\x6d\x83\x54\x3d\xb8\xfc\xe8\x14\x43\x6b\xbd\x3d\xc6\x1b\x06\xbd\x77\x22\xec\x5e\x69\x41\x8c\xb5\xf8\x20\x0c\x77\x7e\x00\x0e\xe2\x4e\x07\x79\x6f\x2f\x1e\x31\xce\xbb\x7d\xf7\xeb\x06\xe5\x22\xa1\xae\x48\x9a\x25\x5e\x08\x58\x7d\x36\xb6\x64\x2e\x54\x90\xd5\xfb\x3e\x47\xb1\x78\xff\xc2\x0e\x69\xce\x97\xb3\x90\x8c\xbf\xa7\xf8\x2c\x46\xe3\x9a\x8e\x20\xae\x9f\xc7\x9a\x4e\xa5\x44\x60\x49\x08\x0d\xf6\xa2\x9b\x30\x07\x79\x5a\xad\x28\xe2\xa6\xbd\x23\x57\xe1\x2d" \
+"\xd1\xdc\x46\x16\x9c\xd8\x27\x7e\x54\x8e\xcf\x64\xdb\x9b\xa6\x2b\xfd\xa1\xff\x8f\x94\x5d\x11\x07\x6d\xb0\x70\x0e\x57\x93\xba\x7b\x20\x9f\xfc\x53\x6f\xb6\xfa\x1c\xef\xcf\x5c\x40\x11\x1a\xd8\x00\x29\x18\x8e\xf6\x13\xac\x20\x89\xea\x45\x93\xfb\xea\xcf\x5f\x06\x71\xd1\x6b\x45\x7a\xc6\x94\x0d\x12\x1c\xee\xbf\xa8\xcd\x90\xea\xb5\xf7\xc0\x97\xb0\x5f\x9d\x3c\xe0\x1a\x78\x18\x10\x42\x66\x33\xb9\x6f\x27\x06\xcd\xbb\x10\x01\x8d\x2d\xea\x30\x90\x1a\x5c\x9b\xd5\xda\x58\x97\x00\x6f\x6d\x1c\x2c\xac\x18\xd7\xcd\xba\x2a\x77\x7c\x30\x29\xc7\x55\x51\xf4\x18\xaa\x47\x9c\x8d\xf9\xea\xc1\xae\x4d\xb8\x2f\x6b\x70\xeb\x7c\xfe\x07\xa3\x9c\x47\x3b\x7a\xe0\xc4\xd7\x47\x51\x91\xcf\xb2\x61\x76\x2d\x9a\x6d\xbe\x8f\x3f\x53\x87\x6e\xa6\xae\x2f\xc3\x21\x00\xea\xd4\xdf\x0b\xf8\xd2\x9e\x11\x8b\xef\x0f\x39\x85\xb9\x98\x47\x38\x02\x3e\x0a\x67\xf3\xf7\xb6\x51\x0a\x26\x31\x07\x83\x0a\xca\xb8\x4f\x95\x54\xd5\x7a\x85\xd0\x18\x8d\x84\x0c\xf4\xfb\xa0\x29\x38\xdb\x7b\x78\x17\xf0\x28\x1d\x20\xd5\xde\x24\x31\xad\xb0\x0b\xd1\x91\x68\x9a\x9a\xb6\xb7\x05\x3c" \
+"\x83\x46\xe0\x2f\x7d\x6e\x2f\xf6\xb4\xde\x7d\xf3\xfb\x37\x19\x93\x4d\xa4\x74\xda\x98\xbf\xf4\x2f\xc7\x44\xd0\xd1\x31\x5a\xc5\xb0\x02\xbf\x7f\xc6\x30\x10\xa8\xf3\x29\xc3\x32\xaf\x21\xac\x5c\xb9\xfe\x60\xdd\x41\x18\x24\xbb\x0a\x68\xf2\x65\xb9\xb0\xce\xd7\xa6\x52\xbd\xf5\xd0\x3e\x26\xcf\x61\xc0\x2d\x2e\x62\x42\xc9\x45\x5f\xce\xd3\xcc\xe1\x89\xcc\x64\x6e\x3a\x54\x1d\x70\x90\x33\x0f\x01\xaa\x4f\x29\xef\x4d\x01\xd0\xd1\x50\xd0\xd6\x1b\xa8\x99\xe5\xbc\x28\xfa\x0d\xf0\x17\x60\x36\xeb\x17\xca\xa5\xd7\x6d\x8f\xa3\xa1\x88\x65\x6d\x62\x66\x36\xe7\x8d\x9d\x16\x05\xc9\x59\x0a\xf1\x71\xe1\xb9\xea\x80\xd4\xce\xba\x3b\x72\x4f\x45\x2b\xab\xd0\xdb\x3f\xdb\x70\x36\x4d\x9c\x74\x96\x8c\x71\xba\x4f\x83\x6d\xe7\xcd\xaa\xfd\x83\x61\x8d\x6b\xf2\x05\xee\xa7\x20\x87\xc2\x8f\x97\x47\x16\x51\xfe\x54\x78\x67\x83\x3d\x56\x7e\x42\x33\xc9\x00\xaa\x46\x12\x26\x98\xe1\x03\x75\x62\x64\x8d\x72\x27\xa1\xbd\x92\x94\x2b\x37\xbd\x12\x9d\xb5\xb9\x07\x75\x4d\x38\xe5\x5b\x50\xe9\x4f\xa5\x8c\x18\x62\xc5\x82\x32\x46\x2c\x6f\xe6\xf1\x5c\xcc\xf6\x4e\x13\x12" \
+"\xe7\xdb\xc9\xcf\x54\xcd\x89\x8a\x71\x2d\x04\x48\x91\xcc\x03\x56\xe6\xc8\xd0\xa6\xda\xb7\xd9\x15\x59\x17\x28\x6b\xa1\x44\xe6\x60\xec\x5b\x6a\x0f\x26\xff\x84\x0d\xf8\x62\x6a\xb1\xdf\x36\xf7\x72\x52\x93\xa1\x2a\x2b\x0a\xc0\x0c\x5e\xc8\xf8\xc8\x55\xe7\xf7\xf6\xc9\xdd\xb4\xd9\x71\x0c\xde\x58\x35\x15\x06\x1a\xd6\xdc\x98\xfd\x5c\x38\x9e\x11\xe9\xda\x5f\xea\x5b\x61\x47\x94\x0b\x03\xe2\xc7\xfa\xc9\x84\x5c\xf4\x12\xd2\xf8\xd4\x59\xb6\x60\x49\x79\xfa\xde\x3b\x79\x76\x13\x1c\xdd\x7e\x30\x77\xbe\xd9\x48\xc2\x5b\x04\xd5\x11\x89\x22\xf6\x07\x06\x8f\xf5\x61\xc0\xfc\x37\x91\x52\x0a\x4d\x6f\x1f\x50\x4a\x9c\x0e\x44\x6f\x52\x4c\xa8\xcb\x09\xdc\x36\xe9\xaf\xba\xa9\x68\xf3\x02\x8f\x6d\xd5\xf7\xa3\xc4\xb5\x25\x10\x32\xda\x1c\x81\x76\xa2\xbb\x62\xca\xe2\xf4\x27\x1b\x5a\xff\xeb\x7d\x62\xce\x9b\xb3\xd3\x3a\x87\x50\x61\xdc\x20\x88\x12\xe2\x3c\xfb\x33\xaa\xa5\x2f\x04\x3f\xa0\x29\x69\x55\x17\x7a\x20\x91\x45\x55\x9f\x93\x49\xd1\xc9\xa9\x19\xe1\xa4\x06\x97\x5c\x09\xdf\x37\x89\xca\x43\xdd\x64\xa1\xf8\x0a\xd1\xc3\x1b\x92\x04\xdb\xe3\xbe\xcb" \
+"\x86\xe4\x0a\xa0\x22\xdd\xfa\x6e\xcb\x21\xba\x3c\x88\xb9\xeb\x48\x2d\x69\xb0\xa1\x24\xa9\xb9\xae\xa8\x92\x17\x39\x80\xc6\xa2\xc2\xc5\x3e\xfe\x66\xc8\x9a\x8c\x62\x28\xd0\x80\x5f\x97\x4d\x28\xbe\x58\x4b\x9c\x2f\xcf\xdc\x0b\x7d\x9f\x18\x59\x8e\x3c\x02\x9c\x19\x2c\xcb\x27\xde\xa6\x7a\x5d\xd7\x5b\x57\x39\xc7\x45\xd3\xf4\x8c\xf1\x6a\x2b\xc1\x0a\x96\x41\xe2\xa3\xca\xa5\x9b\x5d\xdb\xcf\x1c\xae\x9d\xc9\xc7\xa9\xae\x1c\x24\x75\x6a\x9b\x57\xd1\xdf\xab\x68\x48\x4c\xb4\x65\xc4\xf8\xa3\xfc\x96\x21\xe0\x76\x80\x82\x91\xd3\x1c\x50\x11\xae\x21\x9c\x6c\x8b\x78\xe1\x6f\x09\x2e\xe4\x4f\x70\x79\x23\xb5\xaa\x0c\x83\xad\xa9\x04\x28\x08\x65\x22\x9a\xe3\xc8\x39\x32\x76\xdc\x80\x15\xd0\x3e\x83\x44\xc1\x34\xa3\x23\x60\x2d\xe1\x1a\xdb\x32\xc2\x2c\x16\xb5\x53\x15\x52\x23\x64\x0a\xf1\xda\x0c\x68\xf0\xfe\xbe\x36\x30\xd5\x57\x41\xb7\x1b\xe8\x17\xf6\xa9\xb3\xa4\x37\x42\x46\xdb\x07\xd6\x80\x3a\xf4\x78\x34\xff\xd5\xaa\x51\xeb\x10\x2e\x12\xe5\xba\x8b\x76\x7f\x0c\x4a\xad\x6a\xab\xa1\x03\x6c\x03\x71\xd3\x02\x58\x5a\xe3\xca\xc4\xc3\x45\x58\xa8\x28" \
+"\x57\xf7\xd2\x05\x1a\x75\x9f\x2a\x03\x49\x94\xf7\xec\x6e\x10\xec\xa9\xb3\x16\xc6\x20\x4f\x8a\x60\x46\x06\xa1\x1b\x47\x9b\xf1\x70\x3c\xbc\x33\x86\x9a\x00\xcf\xcb\x2b\x66\x58\xb4\x8b\xef\x48\x1a\x2e\xae\x4c\x41\x0e\x87\xca\xd3\x7c\xc9\x04\xe3\x28\x77\x2e\x66\x17\x47\x8f\xa7\xa4\x4d\xc0\x87\x10\x1b\x94\x7f\x7b\xbf\xd1\xa0\x31\x5d\x8a\x5e\xa1\xb5\xcd\x50\x50\x21\x49\xcb\x2d\x24\xc2\xad\x56\x07\xea\xc8\x8a\x14\x3e\x14\x6e\x54\x10\xee\xcf\x7b\xaf\xe9\x28\x87\x33\x55\x88\x40\xcc\xc6\xcf\x97\xa2\x85\xcf\x3a\xf6\xbb\xc9\x5b\xb9\x4c\x2e\xd1\xad\x99\x47\x9e\xf1\x6d\x42\x81\x6d\x13\x46\x1e\xba\x4c\xf9\x7d\xc5\xf3\xdf\xdb\x10\x5d\x86\xe8\x3b\xbc\x2a\x04\x9b\x81\xec\x91\xa6\xf4\xde\x67\x03\xa6\x91\x96\x39\x81\x13\xfd\x9d\xf2\x42\x61\xa5\x6b\x57\xb4\xf5\xf7\x2f\x13\x22\x87\xdb\x5e\x4c\x76\x9c\xf7\x94\x2c\x8e\xa4\x14\xb8\x60\xb3\x8a\x36\x27\xd4\xeb\x60\xd7\x27\x2d\x33\xd7\x27\x2f\x77\x78\x16\xc5\xa6\x9e\x1a\x73\x15\x10\x6e\x17\xa6\x84\xd1\xe8\x67\xf8\xc8\x85\xee\xe0\x0d\x32\x6e\x21\xd3\x9a\x05\xef\x89\xe2\x57\x83\x98\xe1\x3b" \
+"\xd0\x31\xcc\xed\x51\x95\x22\xa7\x2e\xb5\x79\x6e\x1f\x6c\xe2\x0a\x50\x06\x2f\x54\xb4\xb0\x56\x46\xab\xdd\x55\x8f\xac\xe3\x78\xe5\x4b\x8c\x85\xc3\xb0\xad\x5c\x52\xb3\x61\x73\x74\xec\xe0\x46\x2c\xa6\xce\x17\x63\x00\xd5\x2f\xcb\x99\xdd\xb2\xf6\xc4\x1e\x4a\xd0\x64\xf5\x55\x88\x84\x06\xd5\x49\xc7\xf8\x3d\xce\x8d\x4a\x3d\x64\xb5\x9d\x33\x83\x5f\x74\xd9\xda\xa2\x20\x88\x0a\x73\xdd\x41\x10\xdf\x13\xa3\xac\x49\x8c\x61\x45\x43\xc7\x74\x89\xfb\xbc\x6a\x44\x4e\x19\xe1\xca\x28\x75\xa1\x72\x0a\xd0\x1d\x30\xd9\x52\xea\x4b\x86\x9c\x09\xfd\xf1\x90\x16\xba\x8b\x65\x6f\x25\x48\x5f\x21\xb1\x14\xf6\xd2\x84\x01\xff\x54\x99\xab\x8c\xde\x39\x56\x22\xb5\xe4\x27\x0d\x9e\x23\x39\x71\x10\x3d\x61\x6f\x27\x30\xc0\x58\x66\xc9\x53\x49\x71\xe3\x74\x14\x49\xa9\x87\x6b\x08\x60\xfa\x17\x19\xf2\x33\xa6\x1d\xa0\xa9\x2b\xef\x5a\xfe\xc6\xd1\x36\xf9\x1f\xd9\x17\x76\x39\xc0\x14\x45\x4d\x32\x18\x22\xbe\xa6\x1c\xb5\x31\x7e\xde\x85\xab\x00\x55\xd4\xe2\x5e\x23\x0b\xba\xfd\x2a\xa2\xe7\x6f\x29\x35\x15\x00\xc4\xd3\x11\x49\xb4\xd3\x2b\x0a\x0b\xa9\x2a\xd9\x64" \
+"\xdc\x6a\xd3\x08\x44\x2c\x41\x7c\xd6\x67\xc6\x1e\xbf\x19\x47\x36\xaf\x26\xb3\xc7\x46\x8a\x61\x6c\xff\x8a\x7d\x28\xe3\xa1\x4c\xed\x89\xb5\x97\x82\xc7\x93\x32\xca\x3f\xcc\xc9\xd2\xb0\x60\x22\x38\x43\x7b\xb7\x01\x4c\x9a\xeb\xb3\xd8\x0c\x75\xbc\x2e\x9c\xfc\x71\xa0\xe9\xc5\x55\x88\x1e\xf8\x8c\x0c\x5e\x86\x41\x56\xc3\xea\xf6\x5b\xa9\x16\xf6\xb3\x32\x09\x72\xdd\xb5\x75\x4b\xf8\xfa\xb2\x0d\x1b\x11\xfd\xf2\x2e\xd9\x26\xad\x29\xc7\x1d\x4a\x28\x23\x44\xd2\xd0\x3a\xb4\x85\xf4\x8a\x71\xcf\x22\xe1\x7a\x5c\x6f\xdd\xb7\x18\x96\x31\x07\x15\x42\x38\x3a\xa5\x72\x53\x1b\x1f\x30\x0e\x06\xa0\x42\x2d\x40\x57\xb8\x07\x1d\x7b\xf8\xe7\x4c\x01\x85\x52\x7a\x36\xc6\x2b\x8f\x87\x05\xad\x5a\xea\xc1\x0b\x0d\x9e\xc8\xd2\xeb\x22\x10\x93\x22\x0c\xa2\x7d\x11\x2a\x78\xb2\xfe\x46\xf7\x62\xef\xfd\x79\x06\xe4\x88\x8e\xe0\x54\xb5\xf4\x7a\x82\xa5\xf7\x1a\x28\x07\xc2\x4b\x45\x6d\x9a\x08\x45\x49\x13\xbb\x5d\x8d\x85\xa3\x8e\x66\xe6\xa7\x40\x3c\x52\x8c\x49\xcd\xdd\x2c\x8b\x6a\x43\x4b\xe8\xc0\xc9\xc7\xc6\x03\x8a\xe4\x8c\xa1\xd4\x39\x37\x33\x5e\x26\x59\xe1" \
+"\x5c\x25\xef\x38\x23\x32\xcb\x7b\x91\x8c\x3e\x25\x4e\x11\xdf\xec\xd3\x03\x98\x30\xc8\x49\x12\xca\xcb\x64\xb9\xab\x33\xfe\x8f\x27\x8d\x7d\x1c\xec\xb3\x2d\xea\x7e\x14\x41\xae\x61\xf1\xf2\x2d\x3f\x31\x0a\x89\xea\x89\xba\xe1\x84\x24\x36\xc3\xad\x15\xb9\xa3\x76\x7d\xf4\x42\xac\x91\x7c\xf2\x05\x15\xe6\x33\xa5\x18\x47\x9d\x74\xac\xb7\x93\xb0\x94\x88\x58\x54\x0a\x53\x16\xad\x43\xe4\x11\x25\x88\xf8\xea\x4d\xe9\x91\x6f\xfd\x1f\x4d\xd4\x6f\xde\xd7\x2e\x4d\x1d\x0a\xc0\x79\x11\xad\x46\xfc\x35\x88\x10\xb1\xa2\x1c\x71\x7c\xb5\x92\xeb\xf8\x50\x50\xf2\x5e\x15\xc0\xa2\xec\x15\xa3\xf4\xd9\x0f\xa7\x54\xc3\x2b\xd8\xdc\xb1\x45\x63\x23\x3a\xd9\xfc\xc3\x66\x0d\xc4\x69\x06\xd9\x30\xd1\xc7\x8f\x8b\x33\xe3\xb4\x50\x94\xce\xb7\x99\x1f\xf5\x3c\xb6\xcd\xc7\x99\xf4\xe8\xfb\xd1\xa9\x2a\xa3\x43\xd9\xb5\x1b\x39\x73\x6b\x4e\xc0\xfe\xec\xb7\xe6\x72\x2a\x9b\x13\x8e\x53\xcf\xac\x35\x14\xfa\x02\x96\x25\xd6\xba\x23\x08\xb3\xaa\x5a\xd6\xa0\xda\xfb\x82\xc5\x18\xbf\x17\xec\xe3\x9d\x03\x60\x20\xa8\xad\xf8\xd7\x29\x0e\x0e\x50\x86\x22\x41\x6c\x6a\x2e\xc3" \
+"\x96\x96\x7b\x67\x38\x79\xca\xd5\x6b\xf5\xbf\x81\xc0\x28\x5a\x05\x1e\x64\x77\x9c\xd0\x16\xce\x77\x30\x45\x36\x16\xe6\xd9\x61\xa7\x72\x69\x9b\xbc\x4e\x03\xaa\xe2\xd1\xa7\x93\x9a\x5a\x7e\xc1\x0c\xfd\xe4\xa5\x03\x1f\x66\x6a\x02\xeb\x12\x27\x98\xad\xb6\xc2\x7e\xb7\x72\xca\xd1\x20\x44\x62\x63\xb9\x37\x15\x74\x59\xe0\x4f\xa0\xa6\xab\x27\xb3\xad\x92\x4f\xa7\x24\x4b\xc3\x16\xf8\xb1\x61\x7a\x0e\x56\xea\x63\x14\x8a\xfc\x02\x1f\x2f\xbf\xbb\x88\xe0\xe9\xac\x1c\x3b\x4d\xe7\x7c\x56\x43\x19\x09\xde\x77\x9d\x1d\x1e\xa6\x6f\x6b\x8a\x99\xfe\x1a\x69\xf3\x5b\xd0\x02\xf9\xbc\x28\x22\x8a\x5b\x20\xab\xf6\x40\x39\x07\x91\xf3\x9b\x5d\xe4\xe4\x9e\x5e\xb9\x95\x3f\xec\xb0\xba\x23\x91\xab\xd1\xd5\xd6\x01\x9e\x8f\xb9\x21\xf8\x54\x01\x5b\xc9\x00\xae\x70\x34\xa5\xca\x18\x14\xea\x7d\xff\x8e\x23\x8a\x15\x57\x9d\x28\x57\x96\xde\xe2\x72\x77\x7f\xbe\x7b\x19\x0a\xaf\x14\x42\x23\x08\xfd\xcb\x11\x4f\xef\x4f\x31\x5c\x6f\x3e\x40\x5e\x96\x5f\x32\xf6\x13\x4e\x59\xf7\x04\x19\x92\x8e\xc9\x65\x89\x24\xb3\x5d\x50\x9e\x90\x22\xf8\xad\x14\xf5\xb4\x1e\x84\xf1" \
+"\x0a\x78\xcd\x0a\xc8\x77\xc3\xc1\x30\xcd\x8f\x30\x35\x9b\xf2\x32\x63\xb5\x9a\xb6\x2c\xf3\x05\x12\x79\x8c\x3c\x38\x8d\xd5\x9c\x9e\x7a\x1c\x7d\x2a\x98\x53\x2f\x84\x10\x36\xf6\xa4\x7b\x44\xed\x97\x14\xa1\x80\x18\xfb\x99\x24\x09\x64\xe3\xeb\x0f\xcc\x21\x45\x5a\xaf\x47\xc8\xd7\x18\x1c\x88\x7b\xe0\x70\xcd\xb7\xab\x82\x77\x9d\x57\x9b\x37\x59\x32\x79\x8f\x0c\x76\x33\x83\x6d\x6f\x27\xc2\xce\x77\x96\x59\x09\xc7\x56\x58\xcf\x20\xf1\x8d\x6a\x0b\x13\xf1\x8c\x4a\x13\xf1\x74\xba\xe0\xd8\x8b\x53\x23\xba\xbd\x7a\x40\xa8\x79\x3f\xb6\x65\xe8\x98\x60\x04\xa2\xbf\x98\x49\x0c\xf0\x37\x33\x70\xda\xd8\x81\x1e\x27\x31\xd1\x84\x18\x8c\x16\x11\xd8\xda\x78\xdd\xf8\x28\xa9\x18\x4e\xc6\xdb\x63\x56\xe1\xe9\xff\xef\x76\x0d\x2c\xbe\x91\x98\xcf\x65\x66\xa8\xcc\xd4\xb3\x6d\x36\x65\x30\x9b\x5b\xaa\x0a\x57\x83\x31\x5f\xa5\xc7\x3e\xa2\xbb\xef\xba\x07\xe1\x80\xb2\xc9\x27\xdf\xd5\xc2\xca\x41\xd8\xbc\xcc\xa1\x35\x67\xc8\x6c\x38\x77\xcd\x98\xe3\x69\x08\x37\x63\x64\xe2\xe3\xce\x68\xac\xf9\x7e\x27\xb9\x01\xf3\x86\xe2\x68\x24\xb0\xf2\x33\x1b\x53\xfc\xfa" \
+"\xdb\x02\xc9\xc5\x40\x9c\x66\xab\xac\x3b\x23\x3c\x9a\x70\x20\x0e\xfc\x4e\x5b\xa2\x36\x8b\xdf\x9a\x61\x9d\xec\x31\x21\xfd\x43\x3c\x64\x7f\xcc\x53\xeb\x07\xd9\xd7\x88\x55\x4c\xac\xa1\xb4\x36\x3d\x2b\xbb\xcf\x7d\x32\x9d\xf6\x60\x9f\xcb\x11\x3d\x1a\xb8\xce\xce\xe8\x49\x20\xde\xfc\x40\x9c\x4e\x8c\x29\x79\x49\xde\x85\x48\x62\x2d\xa1\xac\x2a\xe6\xa4\xf8\x8b\xff\x8c\x54\x05\xf4\x83\x9e\xb9\xb1\x05\x1b\xc9\x44\x45\x25\x20\x0b\x4f\x0f\xda\xc9\x29\x3d\xdc\x52\x66\x8f\x89\x5d\xa1\x5d\xb8\x85\x8c\x09\x76\xdc\xd9\xb8\x9d\xe3\xb8\x01\xdb\x23\xb7\xb7\x9a\xc3\x7b\x3b\x7c\xa6\xfb\x97\xf8\x53\xc7\x9e\xa3\xce\x04\x83\x20\x45\x89\x5d\x34\xd5\x54\xdb\xe1\x55\x92\x1a\x15\x7a\x8a\x6c\xbd\x5d\x1d\x24\x13\x7f\xb9\xfb\xba\x86\x01\x8b\x82\x94\x18\x93\x71\x99\x12\x9c\x71\xdc\x88\x63\xcf\x10\xe0\x76\x05\x7d\xf7\xdf\xbb\xff\xb0\x2d\xe1\x64\x41\xe6\x5e\xf7\x6a\xec\x8b\x30\xaa\x87\xbc\x6e\x48\xf5\x4d\xe5\x77\x79\xdd\x75\x50\xa1\x0b\x53\x6f\x68\x07\x10\xd7\xc8\x4c\x46\x1e\xeb\x6d\xff\x6c\x33\x16\x27\x76\xa6\xb9\x0a\xc9\x19\x87\x8b\x7b\x2f\xe7" \
+"\x5e\xed\x2c\xcd\xe0\x65\x9f\xdb\x34\x4b\xdb\x75\x7f\x5e\x25\x62\xa6\x1a\xda\xb6\x87\x4f\x61\x80\x2f\x50\x0b\x81\xe8\xc7\x49\xee\x14\x60\x49\x08\x0d\xf6\x96\x71\x10\x5d\x1d\x3f\x63\xb8\x7f\x30\xb8\x0f\xc9\x29\x08\x49\x14\xfe\xba\xbe\x55\x39\x6a\xdb\x32\xde\xf5\x13\x01\xe0\x7e\xcc\xb0\xd4\x2e\xca\xfd\xf6\x8b\x8b\x9d\xa5\xe0\x64\x10\x30\x32\x92\x92\xbd\xd7\x69\xfa\xdb\x07\x69\x1b\xc3\x3a\xb9\xdf\x18\x84\xc7\x79\xb7\x1c\x0f\xf2\xaa\xc4\x78\x74\x10\xc5\xd1\xe2\x39\xdd\x06\x14\x9a\x62\x32\x64\xd1\x44\x23\x39\x4d\xa8\x8b\x65\xb3\x49\xb6\x9e\xed\x36\x8c\x27\xb5\x6c\x9a\x8b\x70\xb9\x70\x58\x33\x7d\x5d\x1a\xca\x4d\x9d\x30\x58\x42\x4a\x40\x37\x99\x4e\x7b\x9c\xab\x3b\x2b\x0b\x8e\xf9\x89\x19\x88\xdb\xf4\xd2\x75\x2c\x9c\x88\x50\xe0\xec\xd5\xbe\x47\xfc\x87\x25\x5f\x07\x05\x1c\xac\xf1\x1b\xd9\x8c\x13\x2a\x8a\x6b\x47\x0c\x4b\xb3\x70\x1d\x81\xbf\x09\x8d\xb3\xff\x01\xa2\x07\x76\x69\x2f\x31\x69\x2c\x14\x56\xb9\x02\x7d\x92\xf1\x9f\x69\xb0\xdd\x73\xd5\x0e\x42\xca\x5f\xfa\xd5\x2b\xf8\xb0\x04\x2e\x27\x54\x13\xba\x50\xf2\x35\xb6\x9c" \
+"\x03\x2b\x08\x4f\x58\x9c\x7f\x0b\xf7\xb3\xc7\xd0\xfb\x25\xd9\x16\xcf\xbf\x80\x35\xa0\x10\x9f\xc5\x13\xd6\xf0\x1d\xc1\xd4\x49\xbf\xf4\x1b\xbd\xe5\x63\xfb\xfe\x32\x2a\xbf\xc7\x0f\x95\x8d\x51\x3c\x19\x87\x78\xe7\x28\x54\x7f\x3b\x96\x7f\x2d\x9a\x87\x7c\x6d\xfc\xba\xcc\x62\x94\xa2\x85\x0a\xea\xe8\x98\x58\xd8\x36\xf2\xce\x4e\xa0\x0c\x4e\x0a\xe4\x02\xee\x32\x09\xe6\x74\xcc\xce\xa0\x09\xc7\x0c\x0c\xe0\x0d\x99\x51\x33\xfd\x8c\xc5\x94\x2f\xc0\x0e\xbb\xff\xd8\x6e\x8d\xc6\x23\xd4\xf4\x43\x4d\x30\x57\x2e\x2e\x71\xcd\xdc\x51\x69\x6d\x09\xf8\xc2\x64\x47\xbb\xa0\x09\xdd\xb2\xb0\x77\xc4\x24\x88\x0c\x44\x22\x71\xdd\xfa\xfa\x04\xfb\x14\x89\x46\xf1\xac\xb2\xb9\xd6\x17\x37\xc4\x1f\xa0\x4c\xd6\xe6\x8b\xc0\x90\x78\xbc\xe1\xd7\x84\x21\x69\xb2\x53\x45\x5c\xc0\x70\x7b\xdd\x22\x07\x49\x91\xe9\x38\x0c\x43\x6a\x98\x4d\x8f\x4d\xd9\x66\x06\xc7\x35\x0e\xa2\x0c\x86\x5b\x3b\xa9\xb5\x12\x2f\x0b\xce\x45\x41\x42\x1b\xa0\x62\x95\x16\x18\x35\xc4\x77\xe7\x54\xd3\xf6\xe7\xda\x63\x78\xc5\x97\x1e\x99\xc0\x78\xfd\x46\xea\xfd\xef\x22\x4a\x06\xe9\x95\x9b" \
+"\xd6\x0c\x7f\x39\x5c\xe1\xc9\xe9\x74\x30\xe2\x5e\x9f\xd4\x4e\xde\x63\x74\x1d\xbb\x03\x3b\xa7\x44\x6c\xa2\x92\x7d\x06\xb2\xe6\x3c\x9e\x3c\x55\x5e\x71\x5d\x02\x4b\xc3\xea\x42\xc8\x94\x80\x32\x38\x3a\xcd\x4f\xe2\x0b\xbd\xbd\x58\x20\x43\x53\x54\xbc\x1f\xb4\x4f\xfc\x09\xb1\xc7\x35\xa3\x42\x36\x6e\xf5\xae\x71\xe1\xcc\xb4\x95\x06\x8d\x12\xfa\x96\xa8\xe5\x63\x6b\x6e\x6c\x3f\x46\x2b\x92\xd8\x40\x2a\x03\xe3\x92\xdf\xe9\x06\x8c\x6c\xee\x15\xf5\x46\x0e\x98\x5c\x6d\x8a\x68\xc8\xc3\xf8\x7d\xe6\x08\x04\x8a\x7d\xe4\xdd\xe1\x62\x92\xe6\x5b\xe1\xf7\xcf\x1d\x70\xb9\xca\x9d\xda\x12\xc1\x2d\x36\x2f\xd7\xa2\x1d\x5c\x5f\x0d\x58\x28\x81\x01\x96\x6a\xcb\x75\x4c\xb0\x9d\xa9\x3d\x2d\xc9\x43\x23\xee\x95\x15\xae\x32\xa2\x96\x78\x16\x90\xc3\xbb\xd6\xef\xb2\xe7\xa5\xc8\xa7\xaa\x6b\x62\xf2\xcd\x48\x71\xa6\xa3\x06\xc5\x39\xd2\x6a\xe7\xc0\x11\x70\x4d\x53\xab\xd8\x7f\x49\x8f\xb6\xe0\x6f\x68\x89\x7b\x77\x34\x99\x2a\xcd\xa1\x91\xae\xa7\x26\x75\x82\x52\x1f\xe4\x66\xea\x1e\xc7\xc2\xcf\x49\x6d\x40\xe7\x37\xdd\x41\xe1\xcb\x1c\x71\x02\x78\xc9\x16\x7d" \
+"\xd3\x4c\x52\x3a\x4b\xb5\x21\x79\xbd\x8a\x46\x7a\x9b\xfc\x85\x33\x23\xf1\xc1\x79\x94\x30\x2c\x9b\x7b\xf0\x09\xa9\x91\x0f\x4f\xd5\xb4\xa0\x1e\xc6\xe1\xd1\xba\x7c\xba\x35\xf0\xf6\x0d\xbc\x34\xd3\xdd\xb5\xd4\x8c\x8f\xbb\xb2\x0b\xb5\xca\x4e\x32\x37\x77\xe4\x71\x78\xe7\xb8\xa5\x7a\x79\x5e\xb5\xde\xf8\xe1\xcc\xf5\xae\xcd\x3f\xdb\xc0\xf6\x52\x65\x6d\x73\xa0\x99\x52\x83\x26\xdb\xe5\x3a\x72\xcd\x8a\x8d\x89\xed\x59\x5e\xf5\x54\xb1\xa6\x00\x26\x10\xad\x38\xf8\x43\x37\x72\xfc\x59\xfb\x92\x5d\x18\x68\x71\xb5\x25\xa4\x25\x9e\x60\x89\xbf\xd6\x15\x33\xd7\x3a\x7b\x6f\xa1\x74\x9d\x70\xd3\xbc\xd2\x34\x69\xdb\x5b\xd5\xbf\x85\xab\x2f\x66\xae\x33\xaa\xb4\x0a\x1e\xb5\x11\x2b\x4c\x0d\xf2\x88\x29\x2d\x9b\x18\x2d\x4f\x92\xda\x06\x6b\x2f\x8e\x20\x8d\x5e\xa5\x0c\x95\x54\xaa\x7a\xca\x43\x82\x7e\x27\x81\xf4\xbb\x13\xe3\x16\x6c\xea\x5e\x62\x3d\x9b\xfb\xe4\xd4\x2b\x25\xfe\x51\xde\x29\x43\x05\xe1\x7c\x35\xcb\x6f\x18\xd4\x40\x11\x55\xc2\xff\x38\xbe\x73\xc0\xcb\x37\xaa\x98\xbb\xa6\x74\x55\x42\xa7\xd5\xf7\x81\x0f\x76\x56\x68\xe0\xc3\x6c\x6d\x06" \
+"\xc8\xbf\x22\x8a\x75\x4a\xb6\xd1\x12\xcc\xb6\x8b\xb8\x1b\x6b\xaf\x0e\x91\x9b\xc5\xfb\x35\x8d\xd1\x62\x82\xe6\x02\x5b\x5b\x5a\xfe\x83\xfc\x5b\x55\x27\xd4\x49\x5a\x39\xb8\x90\x1a\xa3\x06\x20\xf3\xea\xa2\xea\xec\xa7\xea\x49\x71\x32\x4d\xa5\x81\x7a\xd3\x06\x22\xc2\xb8\x1d\x87\xe2\x5b\x72\x0e\x60\xf6\xf3\x16\xc8\xf2\xdc\xae\xe3\xf4\xa8\xc7\xc5\x37\x72\x3e\xd7\xac\x3a\x3c\x52\x29\xcd\x08\x6b\xfd\x3e\x6c\x7a\xf9\x4e\x89\x27\xa7\x0e\x23\x99\x88\x3e\xc1\xd3\x78\x31\xed\xe8\x16\xd7\xbe\x84\xa1\xfa\xf9\xae\xfd\x5a\x5d\xd2\x23\xde\x23\x3e\x3c\xcc\x6b\x3f\xc6\x79\x93\x44\xd5\x4b\x31\x32\x03\x05\x4a\x1e\x5c\x77\x0b\xdf\x85\xde\x1d\xe9\xf8\x5d\x57\xc2\x8b\x54\x34\xd6\x2c\x92\x13\xf1\x52\xcc\xa3\x9a\xfd\x82\x9f\x58\x94\x74\xcf\x1d\x72\x75\x96\x9a\x18\x51\x4e\x5f\x01\xd0\x54\xc5\xac\x8d\x03\x6b\x12\xc0\x78\xc4\x5b\x1e\x52\x5a\xe8\xa3\x0a\x8e\x60\xc6\x3e\x7e\xd4\x99\x64\xcf\x92\x7a\xe9\x5c\xbc\x93\x1b\x09\x66\xcc\x77\xd1\xf2\x47\xde\x6c\x72\xf9\xad\x3b\x0e\x43\x1a\x68\xf0\x88\xc7\x46\x83\x27\x86\x12\x01\x98\x4f\xe0\x82\x68\xc3" \
+"\xb3\xd7\x5a\xba\xf4\xee\x0c\x5a\xb5\x91\x4b\xee\x54\x9e\x6f\x3f\xbb\x79\x98\x84\xa7\x96\x8a\x3e\xcb\x28\x46\x8a\x9a\xd2\x25\x32\xe2\x45\xfd\x8f\x1a\x00\xf3\x83\x05\x8b\x4f\x30\x30\x73\x7a\x3d\x47\x29\x01\xe8\xef\x04\x60\x4a\xd1\xfd\x80\xe0\xde\x9e\x61\x96\x10\x1e\x84\xf0\xc7\xc5\x76\x0d\x47\x38\xa0\xbe\x23\xd7\x6e\xa5\xfe\x1a\x45\x2b\xc3\xa3\x1e\xf5\x8a\x30\x50\x8c\xf5\x59\x53\xa5\x41\x27\x14\x53\x73\x77\x6f\x5a\xca\x65\xac\x5b\xb2\x23\x11\x78\x2d\x76\x5b\x3c\xbd\xb4\x85\x22\x13\x89\x98\x8f\x10\xba\xd6\x04\x2e\xf2\x17\xb3\xe5\xcc\x37\xda\x16\xbc\x05\xde\x8c\x45\xc3\x2b\x1f\x22\x9f\x83\x35\x1c\x53\xd0\x9e\x70\xa3\x10\x3d\xaf\x03\x45\x71\x86\xae\x15\x7d\xa2\x5b\xb6\xfb\x78\x11\x5e\x64\xfc\xc7\x76\x23\xf8\x40\xce\xb3\x26\x79\xb0\x54\xc5\x09\x02\x2d\x6f\xf4\xa1\xfa\xc7\x82\xd0\xa7\xfa\x00\x9b\x39\x00\x5f\x27\xce\xed\x05\x17\x3a\x8e\x89\x4d\xa4\x98\xdb\x5e\x39\xed\x10\xdb\x77\x39\x3a\x65\xbd\x68\xcd\xe4\x1c\xed\x77\x8f\x63\xf1\x05\xa0\x73\x5b\xd7\xf6\xc6\x99\x3c\xba\x40\xf8\x7e\x43\x38\x9b\xb3\x37\x66\x03\x2f\x44" \
+"\x91\x29\xd1\x2d\x94\x6a\x0b\x47\xbf\xab\xf5\x21\x06\x85\xd8\x01\x6d\x80\x38\x78\xf7\x11\xa9\x96\xad\x3d\x6f\x00\x41\x02\x5f\xe5\x3f\x3b\xb9\x94\xd5\x95\x8c\xbe\x39\x97\xa3\x49\x09\xe7\xfa\x4c\x7e\xd3\x0c\xaf\x0e\x26\x92\x1e\x66\x16\x7c\x3a\x89\xef\xb5\x63\xb0\x02\xb8\x30\xc4\x84\xf8\x8c\x5a\xc2\x5f\x06\x5a\xf2\xab\xfe\xbd\xeb\x08\x44\xf4\x73\x59\xd9\x0a\x3d\xac\xfc\x4b\xba\x75\xd4\xd8\x3e\xfd\x62\x9c\xe9\x60\x8b\x37\x5b\xfb\xa8\xdd\x43\xe7\x12\x8c\xfa\x26\xe8\x8f\x41\xdc\xea\x81\x6a\xb8\x3f\xab\x77\x60\x20\x09\x2d\x97\x4a\x47\x51\xa2\x6d\x3a\xc2\x7d\xbf\xa9\xf4\x09\xbe\x25\x26\x62\x24\xee\xb0\x26\x96\x1e\xe3\x00\xbf\x3c\xbd\x00\x04\xb2\xc4\xee\xb6\xe9\x08\x7e\x0e\xec\x49\x64\x10\x96\x31\x1a\x68\x98\xc5\x84\x35\xe5\x64\xc4\xce\x07\x4a\x5b\x8f\x17\xce\x78\xfc\x34\x49\xa1\x94\x29\xa0\x89\x1d\xcf\xde\x0d\x80\x90\xbf\xa2\x3c\x18\xe2\xbb\xfa\x49\x4c\xf6\xf0\x1f\xfe\x6d\x90\x66\xf8\xcf\xd7\x2c\xb6\x1d\xca\x36\x8d\x6b\x7c\xef\xcd\xf3\x36\x9e\x00\x94\xca\x62\x41\xe9\xc9\x3c\xa9\x22\x40\x51\x3e\xcd\xe1\xe4\xe9\xfa\x17" \
+"\x92\x35\x68\x78\x44\x47\xb3\x1a\x9c\xe6\x19\xe1\xeb\x8a\x14\xc4\xdf\x48\xb0\xed\x43\x6b\xca\xd3\x20\x1f\xb8\x1a\xb2\x40\x86\xe1\x73\x08\xe3\x09\xc8\x21\x1f\x1f\x3a\x52\xfb\xf9\x36\x2e\x3c\x0c\xe9\x42\xde\x90\xf3\x6f\x6e\x19\x75\x4d\x6c\xdf\xd3\xd1\x17\x4e\xa2\x9a\x4d\x54\xfb\xa6\x59\xcf\x2d\x4e\x33\x55\x12\x33\x0e\x38\x09\x83\xba\x6f\xe5\xe6\x0b\xc5\xc4\xc9\xb8\x86\x93\x34\x0e\xb9\x91\x0e\x09\xa4\x9d\x52\x03\xfc\x2a\xf4\x8c\xcf\xbd\x4d\x0d\xe8\xf8\x8b\x0a\x89\x1e\xbd\x5b\x5c\xca\x3f\xf9\x61\xd4\x8b\x27\x9b\xfb\xfd\x0a\xf9\x0d\x73\xee\xcb\x70\x93\xba\xb9\x2e\xef\x33\x8f\x94\xfb\xa3\xd0\xfe\x79\xf0\xf3\x16\xa2\x2f\xc4\x2c\xf9\x00\x3b\x7f\x90\x52\x0b\x45\x7c\x4c\x83\xe7\xec\xa9\x61\xac\xa8\x9d\x18\x11\x3d\x6c\xe5\xb6\x99\x00\xc4\x17\x76\x28\x46\xa7\xb2\x4f\x2f\x71\x4b\x5d\x2e\x87\x94\x79\x39\x14\x96\x1c\x42\xd2\x8d\x8e\x5b\x83\x70\xef\xbc\x23\x05\xb5\x80\x02\x3b\x78\x06\xe4\xce\x82\x84\x68\x1e\xdb\x93\x52\x0c\x30\x09\x62\x33\x22\xc4\x87\xec\x73\xb2\x0a\x19\x08\xcd\x1c\xe7\x8c\xc7\xe0\xe0\xa2\x7b\x58\xc2\xca\xda" \
+"\x74\x31\xe9\x89\x70\x48\xeb\x9d\x7d\x89\x4a\x84\x31\x45\xe8\xf9\xf7\xf1\x2f\x08\x70\x05\x48\x8a\x95\x79\x02\x94\xcc\x5d\xe7\x2c\x81\x8c\x95\xce\x68\x25\xd0\xb5\x56\x43\x7a\xa7\x72\xa6\xc8\x86\xb4\xb3\x8b\x78\x10\x6a\xab\x5d\x3a\xb3\xaf\xb3\xf4\x94\x24\x53\xab\x9d\xb6\x92\x6f\x16\x00\x90\x6e\x69\x2f\x5a\xec\xb1\x2f\x2c\x23\xfa\xed\x6f\x8d\x59\x06\xba\x16\xc4\x20\xa6\x17\x8f\x11\x60\x7f\x3a\x8b\x89\x1d\xfa\xa4\x34\x8d\x01\x0d\x75\x52\x5d\xf1\xfe\x78\x8b\xa5\x01\x72\x69\x07\x87\xb4\x39\xfc\xca\xe9\x45\xfd\x26\x0b\x58\xdf\x11\xcb\x40\xa2\xaa\x7f\x3b\xa3\x5a\x08\x3a\x95\x14\xd6\x9f\x1a\xa0\x78\xf4\x7b\x5b\xcb\x1f\x56\xed\x14\xf2\x42\x0e\xb6\xce\x7f\x36\x77\x24\xb6\x29\x81\x80\xc1\x51\x13\xb6\x78\x55\x17\xd2\xdc\xb1\xca\xcc\x66\x8f\x51\xf3\xe9\x0f\x43\xb7\x9d\x60\x7a\x78\x82\x4f\x9a\x76\x24\x4e\x98\x18\x7b\x5a\x56\xa9\xc8\x14\x1d\x39\xd2\x85\x10\x34\x18\xca\x14\xad\x65\xe6\x3d\x2f\x69\x5e\xf4\x2f\xd9\xcf\x57\x57\x5d\xcc\x8a\x6e\x08\x96\xc8\xf8\x81\x8b\x86\xe1\x22\x22\x96\xf7\x46\xc2\x90\xa7\x15\x62\xa1\x07\x26\x4e" \
+"\x03\x24\x2a\x86\xa1\x9d\xcb\x57\x22\xab\x1c\xc7\x40\xba\x82\xdf\x67\x79\x58\x82\x32\xae\x0a\x32\x4f\x0d\x5c\xa2\x63\x01\x55\xa8\x7a\x3d\x84\x50\x55\x70\xee\x06\xb3\xcf\xa2\x35\x10\xc6\xfa\xda\xce\xca\xf2\xf8\x1f\x4a\x56\xc5\x85\xc1\x24\x63\x85\xa0\xdf\x37\x24\x99\x65\xa5\xbc\xb8\xb3\xbd\x24\xc6\xfe\x33\xc7\x0d\x74\x18\x0a\x87\x65\xd0\xa6\x36\x6b\x01\xa6\x61\x26\xc9\x2d\x56\xda\x2c\xa3\x3c\xad\x81\x45\x11\xcc\x37\x55\x8d\x50\x64\x58\x7f\x6c\xcd\x41\x49\x9f\xcc\xd8\xfa\xf0\x11\x79\xc4\xc4\x79\x2e\x40\x19\xd7\x58\x66\xdd\xf4\x23\xf8\x60\x72\x42\x7d\x86\x07\x53\x61\x00\x50\xa6\xe0\xd8\x16\xd5\x12\x2a\xf2\x7e\xb6\x51\xe0\x0a\x25\xc1\x2b\xae\x4a\x9f\x93\x3a\x41\xd9\x93\x6e\xd6\x5f\x7a\xae\x7d\x79\x4a\x42\x90\x4a\x63\x34\x84\x68\x69\x8b\xe1\x80\x3e\x01\xbc\x07\x2b\xb9\xde\x86\x06\xd8\x34\xd3\xd5\x53\x6d\xb0\xa6\x98\xa1\x30\xd3\x7c\xc6\xf1\x34\xed\x8b\x9b\x14\xe9\x8c\x37\x93\x44\x4d\xa6\x6a\x51\xd5\xfa\x4a\x7d\xa5\xd5\x41\x93\x5c\x1f\xd0\xf2\xa9\x5a\x1e\xef\xa5\x8f\xc4\x55\xf7\x79\x93\x26\xb5\xaa\x4b\x1e\xe0\x69\x79" \
+"\x1b\xc5\xf6\xac\x27\x6d\x06\xd1\x2a\xd0\x0d\x94\x99\x61\xf7\x26\xa8\xb9\x4c\x2a\x66\x91\xa6\x1b\xf2\x25\x88\x2d\xf5\x20\xc8\xb1\xe1\xf8\x9a\x75\xac\xb8\x25\x9c\xd0\x64\x97\x40\x10\xc1\xfe\xd5\xcd\x8c\xcf\x99\x40\x9b\x39\x2f\xed\x3b\xe7\x0a\x82\xcc\x48\x1e\x11\x3c\x4c\x73\xa1\xed\x68\x05\x26\xfe\x5a\x98\xd0\x31\xc2\xa0\xf3\x6a\x4e\x29\xfb\x8f\x68\x82\xb4\xf1\x62\xd3\xee\xc2\xe0\x24\xf2\x27\x6d\xb4\x43\x82\xd2\x2c\x08\xa2\x96\x10\x4c\x53\x28\x56\x61\x57\xbb\x2a\x32\x3f\x23\x62\xc0\x17\x8a\xec\x5a\x03\x9d\x13\x05\xfc\xe4\xd3\xef\x01\x55\xbe\x36\x90\xda\xdd\xb8\x13\x59\x4b\x8a\x35\x73\xce\x1f\x64\x63\xbb\x50\xa2\xde\x86\xa7\xee\x75\x54\x24\x3e\xb2\xe0\x93\x77\xa0\x41\xf4\xf5\x9d\xbc\xb8\xde\x2a\x35\xbc\x54\x33\x05\x16\xd6\xe5\x5c\xf9\x11\x4e\x06\x4f\x91\x5c\xc9\x35\x3a\x2d\x57\x5a\x13\xc2\xfd\x12\x44\x57\x3a\x30\xce\x55\xf1\xad\x28\x00\x26\x4b\xd2\xe3\xfe\x96\x75\xa8\x58\x29\xb4\x1f\x4d\xef\x88\x25\x6a\xde\x21\x3f\xef\xd9\xf5\x1d\x0b\xff\x5e\xb5\x84\x5b\x50\x98\x0f\xe0\xfd\xbb\x68\xbf\x5f\xb4\x37\x6c\x18\x41\x20" \
+"\x1b\x93\xc9\x66\x66\x40\xf5\x0e\xc4\x9a\xa9\x85\xbf\x75\x31\x6c\x4b\x85\x48\x5f\x30\x7e\x01\xa6\xbb\x81\xdf\x5e\x60\x27\xe1\xde\xc4\xd2\x81\x23\x18\xba\x91\x06\xad\x52\x43\x82\x61\xa7\x8a\xa7\x39\xb5\xe4\xf9\xf7\x2c\x1d\x09\x8c\xf5\x31\xa4\xd2\x77\x5b\xb0\x0f\x1f\xce\x58\xe5\x9b\x17\x48\x72\xe0\xed\xbe\xc2\x93\x85\xe9\xaa\x16\x40\xf1\xa2\xcc\x34\xd0\x8a\x9f\x1d\x5e\x19\x75\x67\x84\xe8\x41\xc6\x5a\xb7\x71\x06\x4c\x34\x8d\xc7\xa6\xaa\x80\xc7\xfb\x3c\x89\x56\x4e\x34\x10\x48\x40\x70\xae\x43\x36\x49\x3f\x37\xb7\x1e\x0b\x30\x83\x07\x5e\x97\x11\xa6\x73\x3e\x05\xdd\x47\x1e\x89\x23\xb5\xfa\xbb\x44\x1a\xbb\x33\xca\xf9\x4c\xa2\x3f\x0a\x90\x7b\x77\xd9\x9b\x0f\xd6\xd4\x34\x27\xd0\x6d\xd2\xce\xe6\xf2\xba\xfe\xaa\x8a\x34\x28\x82\x07\x66\x43\x1c\x26\x6a\x98\x7a\xac\xb8\xa6\x51\x1e\xec\x95\xd5\xec\xae\x82\x8c\x2c\x8f\xc7\x09\x76\x3a\x0b\x1e\x7e\x8b\x27\x80\x5c\x53\xf2\xcf\xc8\x9d\xf5\x93\x54\xcf\x8c\x78\x3b\x38\xe4\x91\xb1\x82\x30\x8b\x4e\x65\x7c\x2a\xe4\x81\xac\x0e\xf8\x90\x8e\xbd\x26\x9e\x3a\x55\x54\x4b\x88\xb4\xaf\x0d\xb8" \
+"\x00\x1a\x80\xea\x97\xa7\x28\x06\xa3\x08\x17\x39\x45\x2a\x59\xae\x32\x00\xd8\xba\xa6\x07\x8f\x7b\x5f\x17\x1a\x86\x7f\x7d\xc7\x75\x1a\xd7\x81\xd4\x77\x53\x02\x42\x60\xf7\x7e\xf1\x31\xab\xba\xde\x92\xea\x73\xc7\x7b\x70\x4f\x93\x35\xd2\x5f\xc0\xa6\x31\x89\xf5\x50\x78\x0e\xb8\xf2\xed\x83\x1b\x8d\x64\xb2\xb9\x36\xf5\x98\x37\xf3\x58\x2d\x7a\x30\xe5\xd6\x37\x76\x69\xde\x1a\xbd\x44\x2a\x15\x22\x39\xa5\xf6\x6d\x23\x54\x2d\x4c\xc4\x74\x7f\x58\xb4\x0a\xb3\x67\xe2\xd0\x21\x5b\x6f\x0c\xe7\xdd\xa6\x40\xc7\x5d\x57\x3a\xa4\x6c\x17\x7e\xa9\xd8\x77\x44\x68\x18\x33\x9c\x47\xaf\xb5\x5d\xb8\x7c\xab\x22\x48\x73\x5f\x94\x48\xa6\xf1\xb2\xdf\x24\x0a\x0c\xdb\x32\xac\x8b\x98\x1a\xe8\xb9\xf9\x5f\xf9\x08\xf4\x14\x4e\x88\x8d\x91\xa9\xa8\x02\xd0\x09\x1e\x25\x32\x95\x2f\x32\x11\x40\xd6\xa8\x20\x17\xe4\xe8\x1f\x4e\xdb\x4d\x08\x50\xfd\x29\x4f\x08\x7b\x41\xea\x24\x4e\x97\x17\x44\x12\x46\x0a\x09\x09\x21\x8e\x81\x73\x8f\xbf\x7f\xd1\x8d\xca\xbd\x37\x78\x10\x94\xb8\x7a\xb2\x4d\x0a\x95\x12\x1e\x06\x65\x35\x5a\x9b\xef\xfd\x52\x39\x0b\x7d\x54\x07\xaf" \
+"\x74\x3e\xd2\xe8\x70\x82\xfd\x69\x99\xcb\x1f\x78\xfb\xf1\x2d\x29\x7f\x60\x92\x0b\xbb\xb4\x73\x15\x3f\xb6\xd5\xc4\xaf\xff\xa2\x1f\xe9\x41\xc5\x6e\x2a\x88\x36\x76\xea\xb0\x03\xfc\x53\x04\x6b\x85\x13\xe2\x22\xa3\xe8\x1f\x27\xab\xb2\xf2\x24\x45\x40\x21\xa7\x8b\x51\xb8\xa0\xcf\x77\x25\x89\x28\xa5\x32\xa7\xf3\xbc\x52\x8e\x5b\x02\x00\xd1\x10\xa6\x98\x86\x71\xb9\xec\xfd\xa1\x78\x5a\x5e\xbd\x51\xc9\xe0\x3c\x42\x52\x17\x0c\xc7\xc5\x56\xc6\x10\x36\xae\xed\x79\xba\xf4\x8d\x32\x1a\x98\x78\x4e\x34\x47\x73\x28\x5e\x9c\x16\xa2\xf1\xdb\x5a\xd4\xec\x15\x99\xaa\x8e\x14\xc8\xfb\x31\x62\xc0\xad\x0e\xa7\xc7\xa7\xb0\xeb\x6f\x3d\xf3\x1e\xd7\x23\x71\x7f\x7a\xfa\x4f\xa2\x28\x82\x51\x1f\x33\xb1\xf0\x09\x1f\xc0\xd2\x97\xab\x4e\xc9\x32\x66\xe3\x4b\xc4\xef\xe8\xaf\xf0\x77\xcd\xbf\xb4\xd1\x44\x7b\x56\xf4\x72\xf4\xd1\x07\x23\x11\x10\x59\x85\x59\x2a\x09\x12\x7c\x15\xfc\x65\xf4\x58\x4f\xd6\xea\x91\x8c\x34\x76\x2f\x2c\x79\x2b\x0e\x06\x9d\x1a\x10\xac\xfc\x55\x5e\x54\x3b\x86\x13\x77\x0a\x46\x5b\x9d\xf6\x08\x4a\x20\x0f\x17\xe6\x02\xcd\xbc\x67\xed" \
+"\x5c\x13\x58\x15\x93\x87\x75\x7c\x6b\x8c\x27\x98\x33\x38\xf6\x7a\x99\xae\x6a\x91\x8c\x92\x4e\xb4\xf3\xd4\x3e\x2e\x03\x83\x89\x4e\x38\x4f\xa0\xfc\x75\x54\x7e\xc7\xc2\xf0\xe3\x17\xbc\x28\xce\x48\x44\x28\x3a\x5b\xb7\x50\x28\x1f\x41\x09\x46\x17\x22\x40\xc7\xd5\x8a\x50\x8c\x3a\xca\xd7\x73\xdf\x5c\xb5\xda\x74\xfc\xd2\xbe\xd2\x36\xa6\xf1\x42\x84\x3e\x62\x6d\x9e\x33\x34\x59\x45\x18\xab\xb0\xeb\x74\xaf\x12\x6f\x50\xa7\xd1\xaa\x96\xc2\x98\x17\x60\xa2\x29\xf4\xe8\x50\x55\x4c\xe2\x7e\xf0\xc4\xd6\x51\x28\xb7\xe1\x66\x0a\xa6\x39\xe7\xe6\xe8\x95\xa4\x74\x70\x7a\x00\xb6\x35\xc7\xfc\x37\x32\x6f\xf3\xc8\x40\xbf\x1d\xf0\x56\xbb\x7e\x85\x79\xf9\xf9\x25\x3a\xae\xd1\x27\x98\x67\x97\x83\x7f\xcf\x9a\x0e\xbc\xef\x1c\x6b\x21\x0a\x39\x52\x9e\x74\x3f\xe1\x1d\x67\x50\x86\x54\xf5\x25\x0d\x01\x46\x5f\xb4\x52\xbf\x00\x43\xf3\x43\xda\x94\x1e\xf8\xa0\x85\x5c\x53\xbe\xc5\xfb\x96\x75\x1c\xb2\x79\x11\x10\xd1\x04\xbc\x9b\x37\x52\x86\x80\x03\x68\x8e\x84\x90\x20\x65\x00\xdf\xa6\x4f\x31\x6c\x40\xe7\xa2\x06\x1b\x5e\x74\x44\xeb\xa8\x24\x73\x27\xbf\x97" \
+"\x1c\xca\xe4\x23\x5a\x35\xac\xaa\xad\x97\xec\xae\xc5\x13\x55\xd8\xc0\x9e\x80\x23\x06\x58\x15\x19\x9e\x5c\x12\xd5\x16\x88\x77\x95\x7c\xd5\x67\xc5\x06\xce\xae\x24\xc4\xc7\xd0\x44\x39\x54\x1c\xda\xfb\xd6\x4b\x9d\xfe\x2e\x3d\xe4\xbc\x57\x5d\x7d\x9b\x26\xaf\x04\x24\xa0\x1f\xb1\x46\xde\xf5\x55\xf6\x45\x6d\x2d\x4d\x97\xaf\xca\x17\x11\x8b\x42\x4d\xa6\x9b\xfb\x52\x9c\x0b\x4d\x66\xde\x14\xaa\xff\xe8\xa2\x29\x49\x1a\x59\x76\x3a\x7e\xd4\xcf\x6c\x37\x05\x88\x96\xf0\xdf\xb9\x67\xe7\x73\xb6\xbd\x27\xa4\xa2\xb6\x70\x71\x0b\x5d\xfa\x6c\xf7\xe7\x8f\xac\x43\xdf\xdd\xe0\x18\x74\x80\x77\xe8\x8f\x5a\x1b\x95\x31\xe2\xc3\xee\x42\xe9\x0f\x61\x89\xaa\x9b\xec\x7c\xb9\x5f\xc0\x79\x24\x52\x4c\xf9\x1f\x2e\x66\xb9\x0e\xf3\x1e\xf4\xd9\xb8\x9c\x9c\xcf\x23\x26\x59\x6b\xd4\x8b\x4b\xa1\x10\x4e\xe8\x4c\xd1\x07\x5c\x5e\x50\x9f\x3a\xa2\x8a\xd8\xce\xe7\x5d\x55\xc6\x8c\x5a\xc8\xaa\x4f\x76\x1a\x34\xa8\x6f\xa5\xe0\x5b\x2d\x55\x2a\xa2\x8e\x37\x00\x13\xa7\x8e\x56\x4a\xeb\x2b\xe6\x03\xa2\x5d\x21\xef\x2b\xb5\xfd\x9b\x6a\x1c\x30\x96\x2b\xea\x66\xbb\xf7\xbb" \
+"\x28\x2b\x9e\x21\x30\xf2\xd6\x5f\xb6\x7e\x03\x19\xda\x2f\xa3\x8c\xd9\x06\xdd\xc7\x39\x4c\xb6\xf4\x6e\x31\xa8\xf0\x81\x1f\xe2\xb9\x23\x12\xb9\xbd\x02\x11\xbe\x86\x89\x1d\x4c\x76\x30\xd8\x21\xbc\x67\xa0\x42\x8f\x17\xe6\xff\x18\xee\x06\x6f\x12\xd6\xa3\xf4\x1e\x24\x04\xd8\x1f\xa2\x3c\x7f\xeb\xcb\x43\x22\x45\x14\xe3\xdc\x38\x6b\x4e\x51\x0a\xa0\xa9\x13\xff\xd3\x7e\x2e\x4d\x2e\x98\x2e\x72\x87\x8b\x17\x03\xac\x34\x50\x56\x0b\x05\xbe\x33\x56\xbe\x43\x00\x4b\x11\xa0\xe5\x0c\xfe\x98\xdd\x03\xd5\xdc\xd5\xf4\x33\x9d\x49\xfb\xce\xd5\x2b\x71\xf7\xf5\xbd\x34\xe2\xfa\x6d\xd4\x04\xa8\x84\x18\x89\xa0\xaf\xdb\xcc\x9c\x20\xfd\x79\x08\xd1\xc8\x60\x58\x5d\x42\xf3\x54\x4c\x94\x8e\xe5\x56\x1f\x6a\x0a\x17\x88\xc8\x84\x98\x96\x33\x7d\xca\x0d\xca\x3f\x6e\x26\x7d\x0c\x71\x11\xa2\x5c\xd9\x18\x6c\xeb\xd1\x51\x41\xca\xb3\x3c\xb0\x0b\x5b\x3e\x2d\x7e\x60\x09\x42\x99\x86\x0b\x28\xe7\xcd\x42\x05\xf9\x5c\x63\x77\xce\x69\x6c\xcf\x4f\x2c\x3d\x0a\xb3\x12\x07\x21\x0f\x44\xcc\x28\xd6\xab\xdf\xb1\x62\x5e\xb0\xf3\xa5\x98\xe7\x9a\x01\x43\xe2\xec\x6d\x89" \
+"\xca\x48\xea\xf3\x17\x9c\x29\x69\x76\x28\x48\x70\x93\x35\x4c\x7e\x9e\xff\x91\xd5\xd6\x2b\xf1\xc2\x7d\xe3\x68\xf1\xc4\xf4\xed\x8c\xd6\x3e\xd2\xf9\xcf\x8f\x3a\x6a\xb6\x0a\x4b\xf7\x72\x13\x7f\xd2\xd9\x66\xbe\xc8\x95\x24\x3b\x89\xcc\xde\xdf\x7b\x3f\xd7\x54\xf9\x31\x95\x53\x89\xcd\xe0\xc0\x2c\xa6\x65\x6d\xb5\x62\xdb\x11\xa9\xba\x23\x0b\x6c\x83\x4b\xb9\xdc\x3a\xd6\x81\x43\x0f\x6a\xdc\x43\x4c\x07\xf7\x9a\xc9\x92\x19\xe0\x33\xa9\xb4\x3d\x49\xa9\xd8\xa3\x40\xb3\x90\x3d\xb8\xa3\xa3\x08\x71\x28\x2a\x35\x2e\x50\x32\xc7\x9c\x06\x8a\x2c\x56\x82\x0c\xc3\xfb\xbf\x63\x7a\x7f\x74\x9b\xf8\xcd\x56\xac\x31\xc5\x84\x65\x7c\x20\x17\xe1\x4e\xfc\x17\xb6\x1b\x0a\x5d\x87\xdc\x62\xf6\x3e\x9d\x86\x66\x01\x71\xf4\x41\x27\x03\x6a\xa8\x16\x8e\x10\x40\x8c\x0f\x50\x63\x23\x16\xb3\xa5\xa6\x55\x64\xe9\x5a\xe5\x12\x4e\x5c\xcc\xff\xda\xe0\x79\xda\x95\x92\x65\x5a\xed\xd1\x8d\xac\x47\xc1\x5a\xaf\xbd\xa5\xa9\x58\x1b\x0f\xc5\xe1\x84\x20\x7a\xd7\x59\x5c\x82\xaf\xa0\xba\xc9\x14\x3d\x40\xa2\x85\x03\x2b\xf2\x01\xfd\xfc\xb5\x88\xfd\xda\xa3\x82\x6f\x24\x0e" \
+"\x85\x07\xdb\xcc\x91\x22\x20\xaa\xc1\xec\x97\x4a\x4a\x93\x4c\x8a\x6b\x79\x7a\x75\x9e\x1c\xf6\x32\xff\x87\x8a\xa4\x11\x26\xa4\xd2\x4b\xae\x74\xd0\x92\x91\xa3\x36\xa1\x8e\x68\xf2\xfd\x4c\x61\xba\x5c\x83\x45\xbd\xd9\xf1\xe1\x9d\x4e\x25\x4e\x60\xdc\xc2\x03\xf6\xd6\x79\xb2\x5d\x1a\x2e\xa5\x89\x04\xdf\x61\x0e\x5e\x32\x34\xea\x32\x56\x45\x8d\xa5\x79\xca\x98\x25\x55\x16\x87\xd4\xe9\x1e\x6a\xd0\x98\x0a\xc4\x17\x90\x02\xc7\x12\x2b\x2f\xec\x53\x1e\x36\xf9\x07\x91\x74\xef\x24\xbf\x73\xab\x65\x4d\x27\x66\xa7\xf9\x98\xea\xc1\x8d\x18\x8f\xfe\x84\xf1\x31\xdd\xdf\xbd\x67\x0c\xf5\x14\xf0\xd5\x79\x98\x52\x45\xb3\xc0\xba\x06\x42\x38\x16\x16\x90\xf0\x7d\x57\x0d\xf8\x5d\x6c\xe5\xf5\x94\x0e\x3e\x83\x2d\x64\xc9\x3f\x44\x76\xf9\x42\x62\x84\x8d\x4a\x8c\x14\xdc\x51\x86\x8d\xac\xbe\xc7\x95\xcd\x5d\x39\x2d\x71\xf0\x0f\xa1\x04\x7a\xe4\x1c\x96\xdc\xb7\x58\xe2\x33\x75\x06\x6b\x7a\x27\xa5\x19\x0f\xc5\xc7\x95\x9d\x83\xd6\x2c\xfd\xf0\xf7\xf1\x8b\xe5\xe8\xd4\xda\x71\x17\xbc\x84\x93\xfa\xfc\x0e\x91\x07\xf6\x65\x1b\xbe\x9b\x1b\xe0\x14\x25\x3f\x02" \
+"\x36\x26\x05\x22\xba\x02\x6b\xdd\xa1\x42\xf8\xd9\x3f\x4f\xca\x53\x35\xfd\x7f\x57\xfc\x6c\x85\xaf\x0e\x52\x8c\x84\x96\x5e\xea\x78\x78\xd6\x20\xea\x35\x51\x3c\x6b\xff\xa6\xbc\x59\x99\x09\xad\xea\x55\xf4\x0b\x4c\xd9\xbe\x16\x10\x93\x50\x17\x71\x7e\xf1\x54\x39\x86\x54\x98\x2a\x61\x9e\xb0\xf7\x8a\xf9\x36\x6e\x67\x70\xaa\x34\xee\x6d\x1b\x83\x89\x54\x25\x35\xa2\x2d\x0c\x87\xe4\xb3\xc5\x2c\xa3\x8f\x21\x00\x7d\xc6\x2d\x7a\x5d\xfc\x94\xd0\xa3\xf2\x63\x7e\xc3\x7a\xf7\x67\x8d\x16\xd0\x94\x71\xec\xd2\xdf\x39\xf1\x80\x09\x28\x69\xcf\x6d\x45\xe5\xcc\xee\x62\x7c\x64\xe3\x11\xb9\xe2\x12\x77\xc0\x32\x18\x62\xc4\xbb\xe6\xe0\x3c\xbf\x9d\x29\xb3\x5f\x4c\x99\x06\xd9\xe8\x5d\x02\x6e\x29\x94\x8c\xcb\x09\x9c\xe1\xae\x1a\x10\x01\xb6\x14\xf2\xdd\x72\x48\x15\x8d\xe2\xd5\xc8\x11\xc6\x10\x64\xb0\xd8\x49\xf0\x4c\x06\xed\x4e\xc8\x77\x4d\x27\xf0\x9e\x1f\x94\x83\xbb\x3f\xe8\xd2\x40\xb3\xfa\xe8\x35\x4e\x28\x12\x59\x21\x27\x8c\xd1\x38\x70\xf9\x92\xde\x07\x7f\xa1\x41\x92\x21\x92\x7f\x38\x72\x20\x54\x50\x18\x70\xe5\xe6\xd5\x5e\x5b\x94\xf4\x6d\x0d" \
+"\x9d\x6f\x33\xc9\xad\xad\x42\x88\x96\x06\x6f\x6f\x9a\x0b\x11\x74\x0d\x1b\xd1\xf2\x3b\x63\x15\xa9\xde\x44\x48\xde\xa4\x3d\xd9\xc9\x35\xcd\x21\x0f\x8d\x0a\x50\x0a\xd7\x52\x7d\x2b\xa5\x36\xb8\x1a\x97\x47\xcb\xce\x32\x3a\x39\xa1\x34\xa8\x16\xf2\xb3\x7d\x6f\x2b\x5b\x57\x03\x07\x7e\xb1\x36\xa3\x94\x5d\xff\x37\x7c\x2b\x8d\x48\xa6\x22\x93\xa3\x87\x00\x32\x7e\x98\xa5\x01\xf4\x76\x5f\x60\x50\x04\xbb\xce\x6e\xef\xd6\xb7\xd1\x7d\xfc\x28\xb6\x7e\x86\x02\x2d\xb6\x8a\xb3\x02\x66\x8a\x65\x13\x5c\x86\x27\x45\x78\x39\xbe\x39\x82\xf5\x49\xdd\x17\xae\xb7\x5d\x1c\x9d\x2a\xe7\xd9\xce\x8b\x73\x26\xbc\x81\x7c\x0c\x6e\x59\x6c\x84\x33\x8e\xf4\x87\xf5\xfb\x44\x80\x38\xda\x1a\xf8\x81\x22\x9d\xa7\x54\x8a\xf5\x5f\x40\xac\x4a\x09\xfc\x11\xbc\x49\x6e\xe5\x4e\xe6\x99\xe7\x2c\xbf\x2e\x7e\x27\xf1\x7b\xdf\x2e\x2f\x27\x45\x8b\x76\x07\xb8\xb7\xa6\xab\x3d\x70\xc8\x6f\xc4\x3d\x7b\xd9\xbc\xc1\x66\xd4\x69\x5c\x00\x9f\x1b\xb0\x4a\x32\xfa\x6b\x44\x1a\xc4\xcb\xef\x00\x2a\xb8\x23\x8f\x0e\x6a\xac\x4c\x93\x70\x64\x19\xd7\x29\xaa\x7e\x5f\x6c\xda\x52\x24\x09" \
+"\x74\xb1\xb6\x7b\xfe\xbe\x38\x35\x7d\xef\x42\xf3\x91\x0a\x3d\x66\x39\x6d\xc5\x50\x9f\x61\xfd\x78\x30\xf9\x61\xb1\x02\xb9\x99\x0e\xc9\x79\xa5\x6b\x85\x76\xf8\xdc\x44\xce\x60\x89\x9a\x79\xd7\xd9\xbd\x4a\x4c\xcc\xde\x23\xde\xe3\x53\x34\x4d\xb4\x7a\x7b\xb8\xf9\xd4\xf0\x16\xc8\x88\xc2\xce\x6f\x78\xa2\xfd\xba\x9b\xd5\x95\x27\x61\xfc\x84\x5f\x46\xf1\x2f\x36\x13\x8f\xbc\x95\x94\xee\xa1\xc2\x79\x11\x5d\x6f\x85\xf2\xc9\xd4\xb7\x8a\x98\xb2\x25\xe6\x8c\x6b\x89\x7a\xa3\x4b\x05\x87\xe1\xba\x20\x32\x83\x68\xc5\x10\x57\xa3\xb4\xfb\xaa\x1b\xb5\xf1\x55\xb3\x7e\x74\xdb\xce\x4f\xf2\x05\x65\x29\xa5\x50\xdf\x42\x20\x44\x47\x58\x35\x75\xd8\xd1\xac\x70\xd4\x81\x98\x31\x6d\x3d\xec\x4f\xde\x9c\x0b\xef\x1f\xca\x3d\x7b\xcd\x3a\x80\x07\x5f\x1b\x8b\x87\x5b\x77\xc0\xbb\x0d\x63\xa5\x67\xfe\x8c\xc3\xea\x64\x4f\xe7\x9a\xb0\xe9\x52\xd6\xbf\x3c\xc1\x35\x8f\xd5\xfa\x83\x5b\x28\x91\xe1\xd4\x6a\x4d\xc9\x6a\xb9\x78\x8d\xe1\xc3\x05\x6e\x84\xeb\xbd\x5f\x2a\x5a\x37\xc2\x74\xde\x93\x5b\xac\xaf\xdc\xe8\x17\x5f\xc9\x04\x96\x66\xfa\x17\xc4\x56\x78\x1c\x2a" \
+"\xbc\x30\x2e\x90\x42\x55\x7c\x2a\xbb\x89\xd4\xc4\xe6\xf5\x6f\x93\xcc\xa1\x3f\x23\x64\x16\x90\xe8\xd0\x58\x65\x97\x0a\x1f\xd2\x5a\x01\x04\xca\x87\x78\x66\x51\x79\xbd\xc9\x2c\xde\xd1\x30\xbc\x98\x6c\xfa\x41\xad\x0d\xf0\x01\x7b\x6d\x24\xa3\x89\xac\x45\xfa\xa2\x0a\x4b\x59\x39\x66\x93\x4d\x12\x5d\x04\x68\xd8\xe1\xcf\xe5\x18\x39\xbb\xe4\x63\xda\xcc\x3a\x73\x2c\x78\xd1\x63\xc8\xd6\x9c\xdd\x8b\x11\x83\x9f\xa4\xe9\xa0\x06\x02\x1b\x0f\x3c\xcc\xdb\x12\xbe\xa4\xd2\xcb\xbc\x22\x74\x24\x86\x65\xc1\x4b\x58\xbd\xde\xf5\xae\xcb\x00\xc7\xa1\x39\x16\x04\xdb\x4d\x18\x24\x8d\x46\xd7\xdb\x1f\x5c\x69\x0a\x46\x66\xa9\xf4\xd7\xe6\xa9\x58\xf0\x9d\xbe\x05\x82\xba\xe8\x4c\x75\x2d\xe6\xb5\x73\x43\x23\xac\x0f\xa5\x1e\x7d\xb4\x39\xf5\x19\x61\xf4\xaa\xb6\xb4\x6b\x18\xe7\xc3\x8c\x61\x32\xdc\xdc\xc1\xc4\x90\x31\x20\x5a\x3e\xce\x6d\x55\x23\x87\xdc\xf9\xff\x4e\x67\xcf\x62\x9c\xe4\xd5\xfe\x16\xe7\xf7\xbf\x98\xfa\x25\x08\xac\xcc\x88\xb5\x1e\x4b\x09\xae\xe2\xaf\xac\xee\xed\x6b\x1b\xe6\x2e\xc5\xf0\x8c\xa2\xe1\x41\xa5\xf9\xd1\x31\x98\x13\x66\x60\x60" \
+"\xce\x91\x28\x27\x9b\x44\x08\xe4\xb0\x00\x70\x06\x1b\xa4\x0c\xdc\xb9\x8c\x5f\x47\xca\x7d\xea\x0f\xf6\x34\xce\x05\x67\xc6\x06\x41\x0c\xd1\x57\xdf\x79\xef\x7c\x78\x80\x9c\xc2\xfa\xef\x85\xf7\xe3\x4c\x6b\x49\x26\xe4\xf1\x21\x13\x3d\x8a\x46\x25\x2d\x3a\xef\x0d\xb0\x1b\x11\x29\xca\xe9\x3e\xdf\xaf\x9d\x24\xea\xc0\x17\xb4\x40\x3d\xe7\x67\xad\x53\xa9\xf1\x33\xc9\x51\x43\xd9\x4f\xf6\xcb\xf7\xe9\x75\xfd\x99\xfc\x32\x36\xfb\x78\xfe\xd7\x69\xa8\x2f\x80\x3d\x8b\xf3\x5b\x8e\xa6\xb3\x1a\x61\x41\xab\xa7\xf4\x72\xbc\xc0\x65\x17\x37\x73\xcd\xde\xd1\x3b\x6f\x53\x93\xbc\x1a\xa3\x7b\xf4\xfc\x62\x94\x68\x6e\x51\x1b\xa7\x43\xc8\x55\xfb\x50\xa3\x75\x24\x4e\x89\x5f\x22\x3b\xa3\xac\xa4\x59\xf7\x48\x40\xb5\x29\x56\xff\xb8\x9e\xee\xb9\xe2\x46\x70\x7b\xb3\x03\x49\x01\x6f\x6e\xa1\x31\x1d\x70\x7c\xf4\x6e\xee\xf7\x0e\x0e\x4c\xc7\x9f\xc5\xb3\xfa\xf4\xf7\x55\xac\x38\x62\x46\xe8\x63\xcc\xe2\x4b\x79\x49\xef\xcd\xbf\xd2\x4a\x5c\x04\x00\xea\xc1\xc4\xc2\xad\x44\x2c\x0f\x28\x9b\xa6\xcd\xc5\x34\xcf\xa9\x7b\x8f\x05\xb3\xea\x1f\xca\x56\x38\x18\xe9\x3e" \
+"\x79\xd3\x85\x13\xd1\x58\x20\x9e\x55\x46\x55\xf8\xf9\x30\xe1\x2f\x56\x0d\x80\x06\x8c\x24\x1f\x80\x3a\xd7\xb0\x51\x81\x7d\xac\xe0\xd1\xcf\xf6\xad\xcf\xc1\x16\x61\x3c\xad\xb7\x4d\xfd\x9b\x12\xb2\x24\x71\xba\xd8\x46\x35\x2f\xb0\xb0\x6e\x58\x86\x51\xda\xa4\xe6\x2d\xf1\x1b\x50\x64\x61\x07\xf1\x76\x48\xc8\xa5\xbb\x9b\xbe\x5e\x28\x1e\xcd\x99\x47\x68\x8d\x0f\xdc\x0f\x99\xb1\xc8\x9b\xef\x78\x65\x88\x11\x99\xff\x58\xa3\xb9\xdd\xc7\xd8\x62\x45\x5f\x3b\xaf\xa4\xe9\xfd\x85\xe1\x02\x9c\x79\x5d\xe9\x0b\xac\xa4\xfc\x42\x19\x3b\x8d\xc3\x72\x83\xe0\x32\x8b\xe3\x87\xf0\x04\xab\x0e\xce\x8c\xcf\x37\xd3\x9f\x87\x08\xc1\xef\xe9\xcf\x35\xf4\xee\x54\x13\x49\x01\x5e\x68\x2a\x94\x1a\x03\x65\xc6\x99\xef\xef\x22\xe6\xfd\x6c\x06\x36\x3b\x36\xfc\x31\x56\x43\x5a\xae\xc4\x8c\xef\xb5\x40\x55\x0b\x2c\x09\xe5\xf9\x88\x48\x7d\xc7\xbf\xf2\x9c\x91\x51\x46\xc1\x2c\xb5\x85\x24\xd3\xf2\x1e\x90\xf4\x07\x59\x61\x62\xf4\x3d\xb8\x03\xae\x65\xad\xdd\xef\x91\xa6\xe1\xb6\x52\xca\x4c\x4c\x96\xc6\x5d\x78\x64\xfe\x2f\x15\xa8\x3d\x26\xa5\x30\x1f\x4c\x3b\x25\x59" \
+"\x6a\x57\xcb\xb3\xf8\x9c\xa2\x40\x32\x4c\x05\x7b\x71\x09\xd7\xe2\x17\xcd\x2c\xf5\x75\xb3\xfb\xa0\x6a\xcd\x82\xbb\xfd\x97\xe0\x18\x20\x6b\xd2\xdd\x3e\x09\x85\xc0\x77\x8f\xe8\x45\xcc\x62\x05\x56\x79\x11\xf5\xb4\xf9\xe9\x30\xb9\x38\x3e\x14\xd7\x8c\x06\xdc\x8b\x2c\x2e\xb4\xec\xd7\xfa\x51\xc3\xfe\x65\x87\x28\x87\xeb\x8d\x16\xb7\x01\x1f\x03\x59\xfc\x57\xcf\x3a\x18\xa1\xe1\x1c\xd9\xae\x7a\x47\x2e\x64\x19\x55\xbd\xb1\x2d\xb9\x35\xd2\x6d\xde\xf0\xf4\x52\x4b\xbc\x11\xbf\x2d\xb8\xdc\x84\x69\x4b\x97\x0c\x05\xec\x94\x96\x0a\x16\xc7\x1a\x8f\x8e\x9f\x89\x57\x8e\x46\xf1\x43\x05\x0f\xeb\x57\x14\xe0\xcf\xd2\x26\x3c\xf5\x22\xee\x6c\xc1\xcc\xc2\xb3\x07\x83\x9e\x3f\xf5\xff\x5f\x22\xf7\x3f\x64\x27\x55\x33\xb6\xdc\x45\x7d\x58\xdf\x27\xa0\xb0\x73\x64\xe8\x96\x14\x28\xcd\x84\xe7\xc9\x61\x28\x42\xcf\x35\xc3\x27\x3b\x04\xbf\x8c\xd2\x42\x2e\x68\xc4\x40\x23\x16\x97\xd2\x58\xdc\x6c\x60\x5f\xaf\x61\x46\x19\x5a\x6f\x70\x7b\x6a\xcc\x16\x3b\x6a\xf8\xe8\xb2\x95\x20\x24\x10\xfe\xbf\xca\x5f\xb1\xb1\x74\x5f\xd5\xcd\xaa\xfe\x60\xb8\xe9\xa6\x0a\x9c" \
+"\x5f\xfe\x69\xcd\x37\x9e\x3d\x81\xd7\x62\xe6\x6b\x03\x3f\x9d\x9b\xcf\xf7\x9d\x4f\xfe\x8a\xbd\x5e\xf8\xf4\x98\xa7\x6f\x10\xca\xea\x51\x26\xfd\x01\xb4\xd2\x18\x59\xb8\xfc\x55\x06\x23\xdf\x09\x22\x53\xfe\xe0\x45\x8a\xc7\x25\x5a\x18\x15\x88\x0f\x33\x32\x1e\x36\xd8\xe3\x9c\x75\xf2\x64\x34\xa3\x59\x21\xa4\x62\x11\x59\xb0\x15\x9b\x0f\x92\xd8\x56\x75\xa8\x03\x79\x4b\xfc\x74\x50\xc7\xa2\xd7\x4a\x04\x1f\x76\xba\xce\xf9\x74\xdd\x63\x41\x36\x21\x0d\x4e\xd2\x23\xd2\x35\x7a\xbe\xc6\xdd\xb7\x86\xcc\x4f\x08\x19\xd2\xbc\xfd\x55\xc9\x2e\xfa\x03\xe8\xd0\x25\x0c\xdf\x48\x97\x94\xee\xa8\xcc\xfc\x1f\x01\x1c\x76\xf8\xaa\x95\x49\x3b\x20\xca\x65\x97\x0f\x08\xbd\xa3\xd9\x8d\x96\x74\x41\x81\xa6\x93\x36\x01\x42\xd6\xe4\x4d\x4c\x0c\x69\x01\x52\x81\x7b\x1c\x32\x6a\xef\x73\xbd\x51\xa5\x59\x40\xa2\x48\xad\xa2\x0c\x8f\xa1\x2a\xc3\x34\x31\x4f\x82\xe7\xcf\x7d\x71\x15\x2b\xb8\x78\x61\x4f\xa2\x24\x7d\xcc\xfd\x17\xeb\x16\x57\xfa\x81\x2e\x33\x8c\xb8\x7a\x05\xb0\x5b\x4d\x79\x63\x5e\xf6\xd9\xf7\xb5\x64\xbe\x51\x2b\x47\x61\xd8\x52\x90\x32\xd7\x48\x58" \
+"\x88\xca\xa7\x92\x14\x6c\x6f\x30\x08\x80\x4d\x3b\xb3\xe3\x74\x66\x6a\xaa\x7b\xb7\x96\x0f\x14\xe2\xb1\xf4\xc7\xd2\xe1\x60\x0b\xe8\xe6\x6b\xe6\x5c\x58\x07\xc8\xfa\xa2\x8f\xf5\xd7\xc2\xae\x7e\x1f\x91\xd3\x9e\xd2\x7d\xde\x56\x50\x69\xcf\x60\xc5\xf0\x10\x79\xe5\x10\x2b\x20\x12\x61\x74\xf9\x69\x35\x0a\x6d\xa3\xe2\x5a\x2b\xcd\x1b\xbe\x14\x4b\x05\x77\x61\x51\x64\xec\x1e\x0d\x2a\x1e\x94\xed\xe1\x95\x23\x11\x11\x05\x8e\x23\xfa\xd7\xc5\x9b\x11\x6f\x91\x81\x35\x39\x00\xc8\xf9\x59\xb0\xbd\x01\x74\x24\x0f\x8c\xb6\x5f\xd6\x8f\x74\xeb\x52\xa5\x35\xc0\xb5\xb7\x83\x6a\x05\x8e\x23\x1f\xeb\xb1\x5a\xcb\x79\xa7\xd8\xa5\x21\x2f\xe1\x15\xe3\xde\xeb\x52\x4a\xc3\xc5\xd7\x4f\xcd\x6c\x91\xb9\x58\xe0\xcf\xb9\x2b\x94\xc7\x37\xce\x37\x35\x24\x53\xe4\x0f\x9b\xf0\x34\x8b\x24\xa9\xca\x8c\x0b\x94\xc9\x64\x74\x05\x04\x5d\xd1\xff\x0e\x68\x1b\x1e\x8a\xe0\xb6\x88\x44\x1b\x12\x7f\x3d\xe7\x0d\x4f\xd3\x81\xaa\x53\x85\x79\x2a\xc9\x5b\xa1\x9d\x5d\x5c\xe4\xe6\x55\x2a\x48\xfc\x8e\x55\x31\x31\x5a\xf8\x69\x40\x65\x11\xb7\x68\x47\x42\x58\xe7\xf3\xb9\x7f\x6d" \
+"\x60\x10\x90\x43\x89\x8e\x33\x0f\xb0\xe5\xc3\xf4\x79\xe1\xeb\x01\x2f\x1a\xbb\xc7\x1d\x54\x2a\xd1\xc0\x17\x18\x42\x8b\x69\x3b\x2a\x62\x2a\x3b\x79\x2a\x13\xfc\xd8\x53\xaa\x0f\x99\xe3\xd1\xf2\xc0\x54\x7f\xe1\x07\x6a\x34\x7a\x0b\xc5\x0d\x72\xc4\xc2\x43\xd9\x6a\xc9\x09\x21\xbc\x2c\x50\x9c\x8a\x0d\xea\xbd\x1d\xf0\xbe\xf7\xe7\xc2\x71\x91\xb6\x3f\xb8\x51\xcb\x58\xad\x2b\x94\x7e\x3f\x37\x1e\xb3\xa9\x08\x04\xd3\x07\x49\x30\x98\xa9\x41\x8b\xef\x27\x2a\x42\x43\xd1\x04\x14\x66\xc1\x3a\x16\x9b\xe5\xf8\xe9\x63\xee\x3e\xad\x47\x38\x2b\x99\x81\xfd\xa1\x45\x57\x5e\x32\x35\x01\x12\xa7\xb3\xfd\xe8\x05\xf4\xb4\x49\xca\xce\xc7\xb1\x9c\xa8\x90\x9c\x70\xf7\xbb\x5d\x79\xe9\x95\x10\x50\x91\x43\xaf\x39\xfc\xb9\xda\x38\x0d\x00\xa4\xa0\x54\x13\x44\xa8\x0e\x59\x4d\xe1\x02\x0e\x53\x7c\x38\x37\xa2\xe5\x27\xc4\xf9\x1b\xf0\x5a\x85\xf1\xed\x4f\xa9\xe9\xad\x8f\xff\x24\xf9\xa6\x74\x74\xb1\xd8\x95\xe0\x1a\x40\x2c\xb1\x19\x05\xfd\x0d\x32\x41\xed\x0f\x8a\x2b\x5f\x6c\x14\x81\xb8\x8a\x79\x6e\xf0\x5b\x0c\x66\xbb\xb7\xe8\xc4\xfd\x8c\x5a\xae\xab\x09\x96" \
+"\x9f\x58\x61\x38\xe3\x9e\x5c\xe3\xd1\xe3\x89\xf8\xf8\xb6\xa7\xe5\x6e\xbc\x55\x1e\x4a\x07\x48\x63\x6a\xb2\xb5\x5a\xf8\x65\x3b\xb8\x40\x1a\xbc\x01\x4c\x91\xbf\x76\x4e\xa1\x5a\x9d\x6c\x79\xeb\x9a\x5a\x70\xec\xcc\xe2\x43\xc1\xcc\x88\x54\xe0\x2f\xa5\x00\x2c\x2e\xe2\x90\x71\x92\x85\x49\x49\x65\x3d\x31\xb7\x2d\x88\xd1\x0a\xb9\xcf\x18\xf1\xfd\x86\x71\xf8\xe9\x71\x4b\xa1\xb1\x02\x42\xd8\x3e\xb0\x3b\x04\xa3\x5a\xaf\x60\xee\xf3\xc3\x3e\x20\x3d\xe1\x4b\xb2\x7e\x60\x6d\x7a\xe7\xef\xb4\xc4\xcb\x14\xc1\x00\xcb\x31\x92\x22\x7f\xfa\xc0\xcc\x59\xff\x56\x09\x9b\x78\xa1\xed\x40\x94\x32\x36\x78\x5f\xbe\x79\x5d\x41\x7d\xbf\xca\xbe\x10\x70\xbf\x4d\x1c\x7d\x5a\x54\x80\x07\xda\xfb\xb1\x47\x90\xa2\x3c\x2b\xd9\xff\x31\x35\x65\x83\x2a\xc0\x40\x7b\xbc\x21\xd9\x93\xf8\x3f\x4b\x3d\x45\x95\xf8\x5a\x70\x94\x84\x0f\x72\x72\x42\xeb\xc6\xde\xa6\x6c\x8c\xac\xf8\x0e\xfc\x3f\x9e\x99\x91\x3d\x73\xa0\xc2\x1e\xca\x22\x12\x9e\x8b\x84\xaf\x49\x4d\x24\x0a\x55\x9c\xb4\x2c\x5c\xf5\x43\x7c\x15\x37\x03\xb5\xd0\x10\x4e\x90\x2d\x96\x99\xab\x63\xcb\x78\x66\x90" \
+"\xcd\x95\x10\xa8\xf5\x3c\x43\xab\x69\xa3\x4a\x65\xc5\xf3\x4d\xce\xbb\x4f\x7d\x36\xe8\x32\x63\x3c\xd1\x15\xe0\xcb\xf0\x36\x05\x40\xbe\x71\x34\x2b\x72\x99\x39\x18\xf6\xf9\x43\x05\x74\x6c\xa7\x18\x98\x9d\x91\x91\xb8\x87\x09\x15\x13\x28\xd0\x57\xfe\x30\xf9\xff\xa2\x27\x4b\x77\x14\xbc\xf5\xa6\x17\x86\x45\x40\x07\xf2\xb8\x59\x11\xa6\x24\x9e\x4c\x69\xeb\xd4\x4b\x0e\xb3\xa8\x33\xcc\x2a\x32\xbb\x05\x76\x4c\xad\x3a\x9b\xac\xc3\xa8\x2c\x1c\x81\x09\xbc\x08\x72\x4f\x39\xe9\x96\xaf\x24\xd5\x3b\xb0\xcf\x19\x0a\x94\x50\x03\x74\x0e\x78\xa1\xe9\xfa\x24\xd4\x74\x1a\xcb\x25\x81\x2a\x18\x41\xbe\x9d\x41\xc1\x84\xc3\xb5\x1b\x7d\xa1\xed\x11\x35\xcb\x20\x1d\x86\x78\xda\x78\x54\x8b\x27\x79\xf4\xbe\xa7\xb3\xa5\x71\xa9\xdb\x1f\x89\x56\x0f\x2b\xed\x63\x47\x2b\x97\xa7\xdd\xb6\x70\x9d\x6f\x28\x5b\x85\x11\x57\xde\x53\xdd\x27\xbc\x95\x33\x2d\x87\x68\x1b\x94\xf6\xf8\x1c\xa0\xdb\x7d\xc6\x29\x97\xce\x1a\xa7\xa7\x5e\x29\x69\xfb\x04\x23\xfb\xa6\x01\x6f\x9c\xd1\x7e\x27\x5d\x69\xea\xc5\x40\xb9\xb1\x30\xb6\x99\x63\x22\x1b\x6d\x7e\xc0\xb7\x14\x75\x83" \
+"\xd1\x5d\x25\x47\x60\x57\x04\xb7\x34\x10\x04\x7d\x0c\x35\x09\x4c\x68\x97\xaa\x09\xba\x4a\x98\x8c\xad\xe7\x34\x71\x0b\x73\x06\x4b\x3e\xd0\xc0\x66\x47\x70\xcc\x4a\xce\x14\x52\x05\x99\x10\xc2\xba\xb3\xbe\xaa\xdb\xfb\x6d\x18\x58\xdf\x89\xb9\xbe\xd9\xa8\x50\x65\xd2\x69\xdf\x73\x7c\x47\x5b\xc0\x30\x2a\xce\xdc\x0e\x30\x03\xe8\x63\x33\xf7\x27\x92\x97\x94\xe6\x5c\x71\x7b\xb8\x7c\xa9\x37\x05\xf9\xe2\x9c\x56\x51\xa7\x90\xa4\xa9\x49\xf1\x3d\x38\x14\xf7\x74\xac\x93\xaa\x03\x06\x50\xbd\x03\xdc\x0b\x3e\x38\x81\xb3\x91\xcd\x5b\x2e\x41\x1d\x72\xb8\xd0\x76\xef\x67\x21\xe0\xb1\x6d\x96\x13\x13\x64\x88\xa6\x61\x65\xa8\x09\x07\x1d\x8f\xa9\x5d\xba\x4c\x17\x03\xe3\x5d\xf0\xeb\x5e\xc3\x02\x2e\xbc\x4b\x25\xfc\x3c\x3e\xba\xfa\x8f\x85\x60\x7f\xd0\x7f\x37\xb0\xf7\xe8\x63\xc4\x63\xc5\x6b\xa2\xea\x2f\x6d\x1b\x79\x42\x49\xa0\x01\x34\x1d\x48\x59\xfc\xe7\x41\xec\xfa\xc6\xba\x81\x15\x66\x62\x39\x14\xb8\xdd\xae\x30\x25\x0b\xb9\x7b\xbb\x66\x4e\x5c\x03\x45\xa1\xde\x21\x96\xfa\x75\x55\x76\x6f\x04\x91\xf2\x3e\xff\x1b\x30\x48\x57\xfd\x20\x9d\x82\x44" \
+"\x3f\xe0\xdf\xe3\x1d\xd9\xb1\xad\x3d\xce\x22\x0e\xcd\x46\xa1\xe0\x1c\x83\xc5\xcb\x69\x21\xb2\x83\x90\xba\x93\x77\xa7\xac\x07\x74\x34\xd6\x34\xbf\x10\x14\x8a\xf1\x96\x3c\x11\x1e\x5a\x16\x90\xbb\xe3\xa3\x86\xb0\x42\x79\x0e\x01\xe8\x63\x5d\x39\x19\x71\xb1\xf3\x7e\x2e\x31\x00\x43\xcf\xc6\xff\x26\xa4\x34\xdd\x34\xdc\x5a\xc4\xbf\x49\x21\x88\x63\x4a\xc3\x1f\xe7\xc2\xc7\xb6\x8c\x52\x9d\xbc\x08\x0c\x51\x54\x6b\x02\x02\x23\x59\xa8\x3a\x82\x10\x3c\x58\xa3\xd4\x57\x84\xc2\xc2\x3f\xbb\x62\xf3\x73\x40\xf5\xaf\x09\xda\x00\x20\xd2\xc5\x28\xa6\x2c\x0f\xea\xee\x21\x99\xe0\xfa\x78\x33\x00\xe3\x78\xdb\x2c\x1e\x56\x40\x68\xea\xab\x89\x4e\x7d\xcc\xfd\x3c\x86\xd3\xda\x2f\x0f\x91\x32\xe7\x6c\x8f\x7e\x63\x50\x6d\xf2\xd3\x92\x8e\x53\x16\xea\x96\x30\x7b\xe3\x34\xd0\xd5\x89\x53\xd9\x52\x2b\x9b\xd4\xe6\xa2\x8b\x6b\xf3\xdc\x2d\xfd\xdc\xfa\x61\x67\xef\x36\x0e\x16\x83\x4a\xab\x63\xdb\x62\x28\xd8\xb0\x9e\x52\xfa\x6a\xfe\x02\x63\x31\x38\xa8\x77\xb8\x8c\xb6\x74\xba\x1d\x67\xdf\x14\x09\x5f\x06\x24\x1c\x86\x5a\x08\x39\x41\x9e\x21\xee\x9b\x3d\xd2" \
+"\xec\x7e\x6d\x90\xfc\xde\x2c\x68\x6a\xd4\x8c\xc3\x1f\xde\x8d\x83\x37\x01\xa0\xec\x34\x9b\xaa\xad\x9a\x55\xee\x06\x9a\x5d\xf4\xac\x14\xcf\x03\xf9\x8f\x34\x16\x4d\x64\x0e\xe3\xfe\x23\x42\x1b\x25\xde\x62\x07\x16\x91\xca\xd6\x74\xd6\x21\xde\x8a\x20\x9a\x33\x56\x68\x77\x1c\x6b\x44\x0d\xd9\x9b\xc4\xdf\xcd\xb4\x5e\x16\x95\x9c\xa7\xca\x2d\x7d\x25\x69\xcf\x91\x1a\xa2\x9b\xa7\x07\x9b\x33\xc9\x03\x48\xb6\x9a\xd1\x0e\xc5\xd7\x8c\x72\xba\x79\xac\x5e\x4d\x10\x8e\x00\x67\xb8\x17\x1d\x37\x65\xd3\x3c\xe5\x36\x4e\x79\xf6\x4f\xd4\x60\xef\x34\xb6\x84\x2a\xd6\xd0\x1c\x30\xfc\x4f\x71\x91\x5a\x6e\x2e\x91\xbe\x50\x3f\xa6\xd2\x4d\x22\x6f\x7d\x33\x66\x0a\x03\xc2\xd1\x09\xa0\x0f\x9b\x24\xeb\x8e\xfc\x7d\xae\x2c\xba\x4e\xab\x36\x3e\x0e\xe3\xbf\xc0\xea\x2b\x54\x63\x60\xc9\x01\x0c\x65\x62\xed\x0c\xf9\xba\x94\xdd\x11\xd1\x0b\xb5\x94\xa6\xb1\x2c\xa2\x10\x55\x23\xd6\x55\x72\x64\xf9\x4c\x52\x4a\x46\x1e\x92\x63\xe6\x0f\x9d\x75\x9a\xdb\x83\xa3\xc1\xaf\xd8\x1e\x93\xb0\xe0\x74\x52\x90\xe0\x83\xf9\x32\xf7\xc4\xed\x41\xb2\x66\x69\xfc\x14\x1f\xa6\x11" \
+"\xd9\xcf\x8c\xd8\xfe\x7b\x3b\x4d\x11\x6f\x62\xa8\xd2\xed\x4c\x6e\x6b\x10\x64\x28\x2e\xd0\x51\xc9\xa0\x34\x89\x19\xb4\x88\x25\xd6\xad\xac\x5f\x71\xd2\xc3\x5f\xde\xac\x76\x77\xbd\x62\xfd\x7b\x6b\x12\x62\x6f\xc9\xe0\xc5\x6d\x88\x96\x95\x05\x57\x7c\xbc\x25\xc9\x49\xc6\x1a\x06\x3e\x86\xbc\x88\xce\x7e\x65\x2e\xea\x11\xca\x2f\x87\xdf\x39\x3b\x35\x72\x26\x59\x1f\x01\x4c\x4c\xee\x8f\x0b\xbe\x1e\x4c\xe6\x2e\xa2\x33\x00\xba\xcf\x7e\x6b\xdb\x9c\x12\x68\xf7\x9e\xf4\x91\x14\x54\x1f\x44\x8d\x37\xbe\xdd\x69\x66\x38\x51\x9a\x7d\x47\x7b\x7e\xec\xb3\x51\xe7\xdc\xa7\x77\xce\x73\x6a\x3b\xa6\xa6\x03\x89\x2b\x38\x20\x05\x2d\xd7\x91\xa2\x2f\x94\xea\x72\x12\x03\xa6\xf8\xd1\x75\xc0\x67\x23\x53\x4f\x13\xd4\xe6\x0c\x80\xd6\x8e\x94\xad\xea\xd4\x3e\x4e\x90\x08\x8d\x3f\xfc\xff\xbc\x1b\xbf\x84\x35\xd7\xdc\x13\xbf\x4b\xfd\x91\xe6\x7a\x9c\x73\xfa\x49\xab\xd2\x16\xe9\xf4\x5b\x3a\x2f\x4b\x44\x74\xb6\x62\xb6\x4b\x42\x24\x9f\x40\xcd\xb0\x66\x32\xed\x26\x6b\x94\x3a\x3d\x40\x01\xf9\x44\x4b\xeb\x68\x19\xe4\x93\xe9\x2e\x19\xbe\x76\xc4\x22\x27\x01\x3c" \
+"\xc9\x43\x4d\x40\x09\x2b\x00\x96\x29\x49\x39\xfe\xd3\x60\x5d\x81\xe7\x3f\x0c\xb1\x6a\xee\x46\x49\x57\xfb\x07\xfe\x33\xd4\x22\x22\x89\x7f\xd1\xcf\x46\x3c\x44\x47\x4a\xd0\x77\xd3\x99\x64\xad\x15\xb2\x5f\x71\x06\x67\xf4\xcc\xc8\x8d\x3a\x9c\x0d\x15\x6d\xa9\xd7\xce\xb8\x0a\xf8\xd6\xdb\x02\x16\x6c\x25\xf7\x9d\x66\xa7\xfd\x8e\x8b\xb1\x3e\xf3\x3b\x93\x45\xe7\x96\x7b\xb1\xe7\xe0\x21\x1d\x4b\xb8\x73\x8f\xda\x04\x0a\x7d\x23\x32\xc9\x8f\x2c\xaf\x6c\xce\xf7\x98\x51\xf9\x87\xdd\x17\x84\x50\x68\x18\x06\x0a\xd0\x9b\x61\x2d\x09\x34\x1d\xe8\x98\xb0\x4b\xf2\xf1\x6f\x80\x7f\x90\x60\x9f\xab\x49\xfa\x34\xa3\x2b\x9e\xe8\x59\xe3\x41\xdb\x97\x99\xe3\x3d\x2e\xe8\xb1\xaa\xcb\xed\x09\xfd\xe1\xde\xe0\xc8\x56\x92\xb4\x68\x08\x0f\xbd\xb8\x5e\xb1\x24\x39\xaa\xce\x3e\x2f\x98\x43\x4d\x6a\x0a\x1a\xb4\x2c\x7c\xaf\x05\x51\x60\xd7\x8f\x8e\x98\x3d\x02\x51\xd8\x42\x8e\xd8\x47\x08\xaf\xf5\x33\x90\xba\xa6\x1c\xe6\x40\x9f\x96\x5a\xf9\x41\x97\x0a\x88\x5b\x26\x92\x01\xf3\x17\x8d\xe0\x7d\x6c\x04\xa6\xba\xf1\x37\x0a\xca\xfb\xe6\x60\xfc\xf8\xc5\x30\x1d\xef" \
+"\x81\xcc\xb8\x0f\x0a\x59\x82\xaf\x90\x3b\x9b\x21\xab\x79\x20\x13\xfc\x6d\xdc\xbf\x73\xed\x25\xf3\xe9\x79\x7a\x5a\xfa\x42\x8e\x2c\x23\xcb\xda\x91\xf3\x8c\x1c\xa1\xd5\x99\xe7\x4c\x8a\x4c\xfb\x97\x07\x0b\x40\xc1\x49\xe6\xbf\xc4\x99\x53\x05\x5e\x6b\x68\x01\x41\xcb\x95\x99\xd1\x4c\x52\x3c\x00\x15\x99\x3f\xac\x77\x6a\xdf\x33\xd4\xf4\x90\x19\x19\x7e\xd8\x09\x5d\x2a\x2e\xbc\x86\x9a\xc3\x54\x2e\x7e\x80\x88\x6f\x15\x5a\x67\xdb\xc6\x27\xa1\x35\xff\x97\xd5\x69\x87\x73\xe2\x5e\x1c\x30\xfc\x50\x21\x3c\xd5\xce\xf7\xbf\xaf\xc3\xe3\x76\x36\xb9\xcd\xc3\xf8\x0b\xee\xca\x0d\xec\x26\xb6\x01\x01\x33\x6f\xbe\xea\xf9\x57\xbd\xea\x23\x94\xe2\x48\x83\x4d\xf9\xd6\x30\x24\x74\x3a\xe4\x4d\xa8\xde\xbe\x73\xc1\x9d\xae\xd5\x69\x78\x17\x62\x86\x16\xcd\x96\xc0\xca\x80\x41\x80\x55\xfe\x63\x87\xe3\xaa\x50\x60\xea\xe1\xad\xac\x9c\xb3\xea\x51\xb9\x22\xe3\x9b\x29\xf2\xf4\x8a\x94\x3a\xff\xe8\x3f\x92\xb8\xe9\x9d\x69\xce\xb5\x35\x2a\xa5\x3b\x4d\x47\xce\xdb\xa9\xa8\xf6\x3d\x72\xab\x93\x16\x65\xda\x5c\x5d\x3a\x67\x50\xf0\x98\x50\x89\xb3\xb5\xaf\xcb\xf5" \
+"\x6f\xe7\x04\x29\x9e\x5e\xe0\xbd\xac\x7a\x61\x5c\x5d\x7e\x2f\xe5\xef\x34\xe1\x66\x26\x19\x3d\xc4\x79\xe3\x5e\x1b\x94\x85\x3d\x62\xf7\x07\x52\xbb\x9f\x6a\x4a\x33\xf5\xab\x2a\x45\xbc\xe3\x22\xb2\x88\xd2\x89\x3e\x56\x65\x08\xcc\x6a\x06\xea\x69\x85\x33\x45\x32\xa4\x54\xb6\x49\x5e\x6b\x0a\x86\x13\xa5\x6f\xbf\x91\xee\x00\x08\xbc\x39\x7b\xb9\x84\x09\xa9\x2b\xd7\x5c\x4a\x6c\xb0\xdb\x58\x1a\xe3\xff\xac\xc6\xaf\x28\x6a\x78\xe3\x94\x18\x97\xc3\x79\xb6\x46\xb1\xfb\x69\x1b\xa8\x10\x8e\xcf\xb0\x4a\x2f\xd9\xa1\x8b\x1c\x3c\xe4\xc4\xf6\xe9\xf9\xb8\xd4\x24\xc4\x60\x7d\x4f\xc5\x25\x11\x85\xfb\x59\xe2\xbb\xe8\x26\xee\x9e\xb7\x5c\x60\x23\x03\x1c\xf7\x44\x6f\x67\xae\x6e\x51\xa4\x92\xa5\xc3\xdb\x72\x1b\xcf\x53\xff\xfd\x7e\x58\xf2\xc6\x6f\x66\xda\xf9\x72\x09\x99\xdd\xdf\xb0\xbc\x58\x11\xd0\x2e\xb2\xee\x24\xfd\x6d\xe0\xde\x4f\x9a\x7d\x12\xc8\x65\x74\x39\x01\x81\x61\xc9\x97\x6f\xb7\xde\x8c\x87\x72\x9c\x5f\x54\xb2\xf1\x9f\xb1\x70\x3e\x19\x7d\x73\xe8\x66\xfb\x3e\xcb\x0e\x05\x96\x5c\x63\xf1\xdb\x35\xfa\x45\x30\x41\x8d\xf3\x82\x7c\xe1\x1e" \
+"\xb0\x3b\x11\xaf\x91\xfe\x31\xf1\xeb\x89\xe2\x88\x2a\x00\xfb\xa0\xcd\x9c\xc0\x0a\x09\x55\x37\x0e\x3b\x26\xac\xc0\x18\xdd\x42\x36\xed\xee\x93\x5a\xe4\xbd\x16\x09\xdc\xa4\x64\xda\x4c\xb0\x80\xb8\x88\x98\xfc\x43\xa2\xe3\x77\x85\x05\x0f\x6c\x82\xa5\xd3\x18\x13\x22\x4a\xea\xd1\xce\xcb\x05\xe8\x05\x85\x5c\xfb\x6f\xf2\x51\x39\x64\x0c\x74\x8b\xbd\x71\xa7\x8d\xb5\xae\x2f\x0a\x69\xed\x0a\xaa\xc3\x8c\xf5\xb8\xce\x2c\x07\xaf\xb6\x94\x9f\xd1\xef\x8d\xc0\xc2\x07\xbd\xe1\x5d\x25\xa1\x5a\x51\xa7\x61\x20\xa1\x0c\x93\x6e\x51\x80\x0e\x4e\x92\xfc\x13\xfc\xdd\x39\xc4\xe9\x62\xc0\xa6\x31\xc7\x96\x60\x1e\xf7\xa9\xb7\xfc\xd2\xc9\xe2\x17\x72\xc1\xe5\x7b\xfb\x5d\xbb\xbf\x2c\xc3\xd6\xde\xf3\x09\xb4\xd7\x22\x59\x43\xdc\xa2\xc3\xc8\x43\x7e\xf7\x3b\x8e\x23\x52\xee\x80\x19\x33\x87\x98\xee\x64\x34\x3b\x76\x98\x93\x6f\x85\x8a\x29\xc4\xd2\x18\xf1\x0a\x23\x49\xa3\x5e\x61\xb5\x20\x90\x18\xac\xbf\xcd\x0c\x19\xe6\x6c\x82\x8a\xf8\xa4\x62\x8d\x5c\x63\x38\xb4\xc0\x37\x3f\x46\xad\xa4\x39\x1a\x5f\x87\xf3\xff\x9f\xd3\xa3\x2f\x80\x47\x9b\x62\xbb\x51\x9f" \
+"\xbf\x01\x37\xe1\xf1\x10\xae\xf0\xa8\x7a\x25\x28\x61\xcf\x9d\x9d\xb0\x07\xfc\x51\x85\xd6\x80\x53\xf9\x21\x48\x8f\x04\x57\x08\xc5\xe7\x15\xde\x4a\x8a\x84\x95\x6c\x66\x18\xdd\x9a\x53\xbb\x50\x1f\x07\x3f\x74\xb4\xa9\x54\xca\x12\xbc\x0e\x76\x62\xa6\x4b\xf4\x0a\x01\xdb\x4f\x69\xa3\x00\xf9\xfd\x60\x56\xc9\x27\x61\x53\x53\xae\x30\xf9\x49\x27\xbf\xd0\xa8\x22\x43\x97\xfe\x10\x12\x87\x5c\x9d\xe0\xe1\x29\xfe\x2d\xcb\x29\xc5\xd8\x8d\x0f\xd2\x21\xdb\x43\xbd\xdc\x45\x32\x13\x4f\x2b\x4b\x7a\x01\x5d\x2c\x41\xc5\x0f\x1d\xea\x27\xaf\xe9\x88\x05\x41\x7b\x74\x6d\x88\x3f\x5c\x3b\x1f\x9e\x01\x28\xdb\x9e\x5e\x27\xec\xcf\xc6\x7c\xf7\xd1\x96\xa8\x92\x1b\xa4\x50\x6d\xfb\xdc\x65\x96\x1d\x8e\x2c\xc7\x47\xe8\x1b\x24\x76\x45\xe6\x54\x1a\xac\xfc\xe3\x2e\x13\x23\xa8\xef\x05\x0f\xdc\x80\x5f\xd4\x6a\xcd\xf2\x38\x80\x09\x14\x1c\x18\x21\x0b\xb1\xf4\x6e\xed\x83\xe9\xb7\xdf\x79\x73\x5a\xe1\xdf\xa0\x53\x42\x88\x46\x3a\x99\x0d\x68\x88\xcf\x27\xea\x81\x8c\xf7\xdb\xb0\x48\x78\xd3\xb9\x85\x76\x83\xd4\x3b\xba\xb2\xc7\xe4\x36\xe7\x61\xbb\xe0\x61\xed\xce" \
+"\xd7\x09\x16\x0c\x0c\x93\x15\x26\xa5\x4e\x95\xf5\x91\x76\x67\xf5\x81\x78\x05\x8e\x31\x00\xd3\xe0\xef\x4d\x72\x30\xac\x9e\xab\x13\xe0\xc9\x52\xda\x4e\xa8\x5b\x86\x0f\x28\xbb\x72\x2a\x1a\x08\x8e\xd3\x3d\xe9\x08\x9b\xb1\x93\x95\xe8\xa0\x01\xb1\x87\xf5\x90\x45\x16\x9d\x9c\xc8\x6d\x85\xc9\x9d\xd4\xfe\x86\xd5\xbf\xff\x65\xff\x14\xeb\x69\x3e\xdd\xd2\x9f\x40\xf6\x88\xb5\x3c\x29\x95\x81\xe0\x2e\x4f\xad\x88\x69\x7d\xc0\xf4\x10\xec\xac\xc2\xf7\x88\xa0\xbf\xdb\x18\x65\x97\xcc\xbd\xfe\x45\xa0\x4f\x54\x95\x2b\x6c\x5a\x41\x10\x4b\x31\xb6\x1d\xd3\xbc\x87\x91\x83\x6c\x8f\x61\x5f\x26\x26\xf4\x75\x5c\x9d\x5b\x26\x76\x76\x86\x6c\x7b\x53\xd7\xef\xe4\xba\x2d\x70\xca\xa6\x7f\xc7\x50\xb7\xfb\x70\x71\xed\x31\x94\x5c\x1f\x36\xf2\xd0\x0c\x2f\x65\x4a\x4f\x13\x4e\x7a\x3c\x7d\x55\x85\x03\x34\x7b\xec\x3c\x3e\xb2\x65\x6f\x5b\x59\xe4\x3f\x3e\x74\x35\x94\x47\x2e\x99\x85\xf4\x3b\x57\x75\xab\x43\xb6\x77\x03\xcc\xd7\xcd\x80\xf8\x0b\x3b\x22\x0f\x73\xf9\xb1\xf0\xc6\x3a\x34\x17\x65\x84\x76\x27\xb5\xc7\x31\x27\x62\xc4\x17\xb3\xc7\x3e\x41\xa5\xf6\xda" \
+"\xa1\x96\xa3\xfd\x5e\x7c\xd7\x0a\xf5\x47\x87\xa8\x3b\xfb\xe5\x9d\x27\x4b\xb3\xd3\x53\x21\xac\x51\x02\x1e\xde\xae\x42\x50\x0b\xc4\xbb\x7b\xff\x7f\xbb\xd0\xec\x6a\x58\x36\x5d\xfd\x25\x21\x9b\x52\x1a\x9c\x39\x57\x94\x82\x2c\x54\xcf\xab\xc8\x83\x52\x1c\x3d\x7a\x9b\x72\xa0\xfd\x1d\xb1\x32\xa8\x64\x49\x12\x84\x5c\x88\x43\x18\x9c\x95\xa4\x78\x6d\x82\xaa\x9c\xa4\xf8\x68\x53\x98\xe7\xd3\x64\x4e\x3b\xaa\x93\x65\x56\xfe\x7f\x8f\x7c\xb2\xe8\x23\x23\xf3\x03\xdc\xc6\xb6\x92\x47\xfa\x32\x3d\x98\xfd\x65\xdb\xdb\x9f\x3a\x22\xef\x6f\x90\x1d\x08\x63\x18\xd4\x7b\xb0\xab\x00\x84\xfd\x23\x8c\xa6\x9d\x44\xd7\xd9\x69\x4e\xe0\x12\x76\xd8\x4f\xe3\x65\x3b\x99\x1b\xd9\xf3\xfa\xc1\xd5\x64\xb8\x45\x4e\xe5\x07\x90\x6b\x05\xd6\xdf\x8b\x7b\x2c\x8c\xa5\x83\xd7\x41\x4d\xb5\x8f\x65\xda\xc6\x57\x2f\xbf\x0a\x66\xe7\x00\xef\x17\x80\x53\x0b\xda\x3e\x68\xb9\x49\xd3\xd8\x28\x46\xe7\x5c\xbb\xac\xff\x42\x9f\x5d\x9c\x23\xac\x7b\x02\xe6\x7b\xec\xf1\x9a\x58\x88\xb3\x93\xae\x59\x32\x05\x9e\xa9\x80\x7f\xd7\xe7\x52\x53\x9f\x42\xf1\xcd\x67\x8f\x14\xf8\xef\x8f" \
+"\x1f\xd2\xf9\x27\x19\x08\x08\xf2\x6f\x6f\xbc\x23\xbe\xfb\x11\x72\xa4\x31\x18\x71\x9f\x32\x73\x38\xbe\xb4\x5b\x7d\xed\x63\x74\xd3\x24\xd0\x73\x0c\x49\x3d\x63\x6e\x51\x40\x53\xa3\x83\x9a\xd3\x09\xa5\x0b\x1e\xb1\xb1\x2b\xf1\x07\x6c\xcb\xe0\x4b\x19\xf6\xa0\x21\x94\x20\x83\xb7\xbe\x00\xdb\x1c\xd0\xf2\x86\xae\x5b\x5c\x33\x24\xf0\x2b\x8b\x93\x65\xb7\x33\xd8\xf9\x2a\xa6\x34\x85\x73\xf9\x06\xf0\x17\x1b\x17\x4d\xb4\x28\xaf\xf0\xad\x68\x46\x89\x53\x52\xab\x9b\xd7\x88\x83\x04\xac\x13\x64\xff\x92\xa0\xc7\x80\xb1\x82\xa3\x38\x68\x6b\x66\x2c\xb2\xc4\xbb\x00\x26\x35\xe6\xbf\x94\xda\xcf\x69\x42\x6a\x67\x34\xf1\x77\xe9\x3f\x3f\xb6\x2d\x65\x3d\xd2\x59\xaf\x65\x62\x59\xac\xfc\xec\x24\x36\x8f\x83\x37\x23\xbd\x80\x39\x49\x22\xe5\xfa\xce\xfd\x2b\x25\x35\x88\xac\x49\xdd\x1b\xcd\xcf\x15\x78\x5c\x06\xdc\xa6\x42\x5f\x2d\xf1\xd1\x70\x48\x16\x1f\xdd\xe8\xdc\x9d\xf8\x4e\x69\xd6\xe6\x29\xc1\xd3\x2e\xf9\x1a\x0b\xf2\x2a\xe1\x74\xcf\xa6\x8d\x74\xb9\xdf\x56\xda\xbe\xff\xb9\xfa\xc7\xb5\x38\xbc\x84\x25\x1b\x55\xf8\x70\xa1\xb6\xa4\x99\x81\x28\x25" \
+"\x0d\x08\x43\xec\x24\xb6\x97\x82\x60\x83\x41\x1a\x67\xef\x41\xf3\xea\xa2\x07\x5a\xed\x18\x63\x91\x2f\xb5\x63\x41\x26\x24\x70\x9d\xef\xe1\x7f\xa1\xa8\x06\x42\xe7\xfc\x8e\x9a\xe1\x8a\xbd\xf3\x42\x8e\x47\x3d\xef\x37\xe6\x3b\x28\xe0\x86\x68\x64\xbd\xa6\xf9\x42\x5b\x92\x9a\x1c\x43\x4e\x8a\x28\x72\x47\xac\x03\xa8\xe9\x09\x6a\xe4\x8f\x38\xc1\xe3\xf3\x90\x33\xde\x5e\xe0\x2b\x4f\x95\xd4\xf5\x34\x44\xc8\x11\xeb\x2d\xa4\x93\x3e\x76\x34\xd8\xc3\x4e\x0d\x42\xbe\xbc\xf1\x8e\xea\xb6\x55\x30\x94\xd6\x7b\x39\xdf\xbc\xe5\x77\xa9\xb4\xc1\x46\xfa\xd7\xf9\x1d\x58\x7b\x58\xe2\xd2\xab\xaa\x20\x50\x55\x03\x1a\xdb\x6d\x61\x86\x0b\x60\x76\x47\x82\x56\xb6\x4d\x74\x89\xd6\x1c\x8c\xf2\xe3\xb2\xa7\xc8\xd6\xaf\x6b\x60\x84\x21\x28\x40\x5d\xce\x5a\x81\x84\xdd\xaa\xf2\x71\xeb\xfb\xac\xc1\x23\x3a\x55\x46\x09\x4b\x68\x47\xa1\x63\xd6\x06\x21\xcc\xfa\xac\xc7\x21\xb7\xf6\xfa\x6d\xfb\x32\x6a\x72\x10\x86\x96\x13\xdb\x15\x3c\x3f\xfb\xcc\x9d\x2d\x6a\xe9\x85\x9a\x91\x87\xc9\x4d\x3b\xb2\xb0\xd9\x6d\xec\x13\x13\xc8\x05\xa5\xeb\x51\x0e\x2a\x99\x28\xbd\x56" \
+"\x5c\x5a\xef\x4d\x35\x88\x41\x70\x5e\x82\x68\x47\x37\x4f\x16\xfa\x22\xb2\x0e\x5b\x18\x91\xfa\x04\xc5\x60\x48\x76\x8e\x1f\x53\x89\x0e\x39\x73\x24\xca\x90\x0a\x13\x7b\xb0\x17\x5d\x23\x5a\x91\x49\xa3\x7c\x42\x9c\x08\x52\xf3\x16\xcc\x3b\x4d\x31\xde\x01\xf6\x07\x4b\x0f\xea\x6e\x09\xe8\x1d\x9c\xef\xfa\x58\x18\xf4\x7b\x0f\xa9\x42\xb4\xfe\xd2\xe9\x86\x1b\x64\xa2\x67\x9e\xdf\x95\xe2\xa7\x8c\x35\x22\x39\x69\xdd\x70\x74\x48\xcf\xa9\x62\xc8\xbd\x21\x48\xb5\xa2\xa6\x04\x1d\x62\x9d\xb8\xf4\xbc\x7f\xba\x23\xba\xca\x18\x15\xb9\xa0\x3f\x11\x70\x4e\x60\x31\x57\x3c\x9a\xd7\x31\xc4\xb3\x7a\x3c\xfd\x9a\x56\xb1\xe3\x46\x01\x50\xcd\x3a\x42\x67\x92\xaa\x6c\x22\x86\x95\x86\xa0\xe1\x98\x3f\x12\xc7\x65\x9e\xc7\xeb\x7c\x62\x69\x08\x3e\x64\x5c\xf8\x51\x3b\x6c\xbe\x9c\xd8\x6a\x67\x5a\x45\xc7\xa0\x15\x42\xcb\x7d\x9d\xbd\x08\x73\x0f\x9e\x4d\x69\x7c\xab\xb4\xe3\x86\x32\xd0\xf5\xfe\x23\xe7\xd7\xe7\xc1\xda\xd8\x44\xcc\xe5\xe9\x5f\x78\xb1\x69\x6c\x5c\x09\xb5\x77\xc4\x13\x61\x05\x91\xfe\x70\x9c\x46\x09\x44\x27\x54\x21\x50\x02\x15\xe4\xb8\x91\xda" \
+"\x13\xca\xe7\x90\x03\x1d\x16\x0e\x92\xc1\x5a\xd8\x3f\x5f\xc5\x46\xc6\x44\xeb\x84\x10\x1f\x64\xb3\x13\x69\x13\xb2\xd2\xde\x76\x94\x25\xca\x32\xde\x54\xf6\x59\x24\x19\xb7\x50\xaf\x4f\x9a\x26\x77\x59\x7d\x85\x38\x15\x3d\xbb\x7b\x50\xe0\xbb\x0f\x54\x2e\x13\x01\x18\xf6\xfa\x20\xe2\xc1\x31\x76\xfc\x01\x2f\xac\xa1\xaf\x3c\x71\x38\xf8\xc6\x64\x75\x4e\x8a\x9a\x28\xe7\x76\x78\x17\xdf\x08\xef\x91\x33\x2b\x52\x92\x53\x81\x2b\x92\x4b\xab\x14\xba\x9d\xae\x89\xcd\xbb\xc6\x25\x0a\x6c\x41\x9a\xd4\xcf\x3f\xb2\x0b\x33\x05\x3e\xac\x7a\xdb\x93\x10\xdf\xf3\x86\x92\xa1\xad\x76\x71\xb9\xd4\xc7\x1d\x53\x05\xf1\x2a\x36\xa0\x39\x64\x74\x6f\xda\xc1\x27\x42\x43\x8d\xa1\xb3\x8d\x36\x57\x10\x2b\x0f\x5d\x29\xf0\x3e\x42\xe7\x3b\x2a\x30\x2e\xcf\x8d\x1b\xa0\x9c\xf7\x8a\x81\x82\x44\x22\x42\x45\xb1\x2d\x6c\x1a\x24\x32\x6d\x2e\xee\x52\xbb\xdb\xa6\xe1\x73\xcc\x79\xe4\x7a\x5c\x41\x43\x45\xa2\x68\x0a\x75\x11\x21\x71\x6e\x0a\x09\x02\x29\x18\xe3\xad\x31\x0a\x02\x93\x73\xc5\x5d\x85\x8b\x56\x26\x8a\x66\x5c\x11\x5e\x73\x4a\x65\x05\x0c\xde\xba\xe5\x10\x7e" \
+"\x10\xea\x69\xbf\xb8\xb6\x1b\x3b\x98\x76\xb3\x72\x4e\x41\x0f\x15\x2b\xd7\x07\xd7\x6e\xcf\x98\x80\x0e\x6a\xbc\x49\xe6\xb7\x17\x65\x5c\x5f\xfa\x73\xf5\x28\x3a\xa7\x9d\xc9\x01\xe5\xe9\x27\xf3\x67\xfd\x68\x87\xf8\xdb\x4a\x7f\x5b\x87\xe0\xf0\x2a\x06\x46\x46\x30\x17\x34\x4e\x0c\xd4\xcb\x37\x86\x6c\x6b\xb9\xed\x81\x78\xea\x36\xf3\xfc\xe7\x13\xbe\xbe\x2e\x30\x73\xc8\x91\x77\xc3\x8c\x7a\x15\x55\x78\xbd\x21\xd0\x3b\x27\xb5\x39\x37\x80\x90\x95\x78\x41\x4d\x71\x4b\xcb\xc2\xfb\xd9\x4d\x6e\x38\x36\x5d\xf0\x65\xdb\x34\xae\xa3\x99\xc1\x18\x10\x70\x67\xb2\xfc\x39\x02\x07\x37\xb8\x50\xb0\xf8\x80\xec\x49\xfa\x42\xda\x3f\x10\xe6\x95\x20\x95\xed\xc7\xa8\x51\x93\x3f\xd3\xfb\x70\xdf\x3e\x5c\x3c\x72\x9c\xcb\x0c\xe1\xe8\xfa\xa6\x7b\xc2\xe3\x38\x52\x04\x68\xa8\xaa\x26\x5d\x7a\xe8\xcf\xe4\x44\x3a\xf7\xa2\x60\x80\x14\xf9\x72\x5d\x25\xc7\xe5\x98\x86\xa8\x0e\xd4\x99\x89\x1f\xf1\xbd\xa3\xdf\xf7\xc4\x16\x43\x1b\x69\x0a\xeb\x1c\x18\xb1\xf9\xe6\x13\xf7\x91\xe4\x97\xc3\x11\xc9\x5d\xe2\xa7\x4c\xe3\x55\xcf\xc8\x8b\x25\x94\x28\xf3\xd6\x3c\x37\xf1" \
+"\xb7\x7e\xa0\x61\x06\x81\x68\xb6\xcf\xfa\x4d\x7b\xeb\xd3\x9e\xab\x34\xab\xba\x35\x79\x18\x89\x69\xa4\xf7\xac\x84\xc9\x1f\x87\x7b\x00\xa4\xa4\xeb\xa7\x67\x3f\x28\x36\x66\x2e\xc5\xb9\xc2\x0e\xc3\x9f\xb6\x78\x04\x24\x0e\xc2\xdb\x9b\x17\xe9\x94\xa9\x71\x9e\x5c\x67\x44\xf7\x85\xd6\xfc\x09\xdc\x32\xc6\xfb\x4b\x22\x0a\x73\xd1\xac\x93\xa8\xb9\x51\x46\xae\x9b\x50\x6f\xf6\x4e\xc7\x9b\xc0\x02\xf1\xa2\x7b\x7b\x4d\xe4\x65\x16\xf1\x59\xf5\x3f\x03\xeb\x4c\xa2\x14\x0c\x51\xe4\xfe\x32\x92\x4c\x95\x70\xe2\x58\xe7\xa7\xe5\x1b\xfa\x15\x62\x54\xeb\xfb\xd5\xee\xd1\x6f\x22\x90\xb5\xbe\x16\x3c\x70\xf4\x62\xf1\x13\x33\xa3\x04\xc6\x08\x32\xc2\xc8\xf1\x9b\xc0\x61\x5f\xad\x31\x5e\xa9\x70\x15\x57\x17\xe5\xe2\x4b\x3c\x86\x7e\x15\x0a\x56\x54\xee\x71\x13\x4d\xcd\x03\x9e\x69\xf1\x62\x56\xed\xe9\xbe\x61\x88\xca\xea\x93\x79\xfd\x9c\xb0\xee\xde\x47\x23\xb9\x7f\xd4\xd3\x00\x56\x81\x83\x5d\x6f\xa7\x79\x8a\x45\xfb\x04\x5a\xe5\x2b\x30\x90\x8a\x00\x30\xf9\xca\xcb\x2e\x75\xaf\x1b\x60\xe6\x77\x5d\x9c\x81\xba\x7a\x85\x72\xa0\xc4\x32\x51\x61\x3f\x0d\xbc" \
+"\x92\x3f\x04\xdc\xde\xa5\x09\xec\x7c\x75\x91\x5b\xf4\xba\xe9\x23\x4e\xf1\x2d\x26\x7f\xb3\xa5\x14\xfd\x83\xab\x29\xe6\x9e\xa2\x53\x32\x13\x17\x53\x80\x79\x43\xf8\x11\x91\x62\x70\xbe\xfa\xed\xf3\xf8\x40\x92\x29\x10\x2c\x9a\x21\x3c\xa2\xa1\x9c\xe5\xb0\xac\x31\x2a\xf0\xeb\x55\x5a\xa2\x97\xaa\xb7\x1b\x15\xb7\x28\x86\xbb\xc1\x4b\xb7\x4c\x3f\xeb\x1b\x5a\x85\x1a\x8a\x53\x96\x4d\xce\xe9\xa6\xcc\x5a\x7d\xd3\x85\xe5\x0a\xa6\x0c\x92\xb8\x98\x6b\xf2\xf5\x34\x91\x9a\x22\xf9\x0d\x66\xfd\xd1\x14\x03\xe1\x58\x9c\x89\x1e\xb6\xce\xd3\xff\x95\x27\x40\x85\x10\x7d\x05\x73\xdc\x33\x7a\xf2\x79\xde\xd4\xef\xed\xd0\x1f\x48\x62\x24\x83\xb9\x09\x7c\x0e\x37\xec\xc4\x26\x44\x52\x11\xc5\xff\xa8\xc7\x9e\x5e\x34\x3a\x7e\x64\x39\x76\xb8\xd6\x2a\x41\xf9\x9c\x80\x52\x8b\xea\x3f\x77\x37\x59\x6c\xcf\xd1\xe2\x22\xc6\x86\x36\x83\x9a\x57\x60\x1f\x0b\xf1\x01\x0b\x61\x3d\xa7\x14\xdf\xbc\xa3\x1f\xfa\xbd\x0d\x1d\xc4\xd1\xda\x77\x66\x0d\xac\x95\x95\xdb\xfb\x40\xee\xd3\xd4\x88\x52\xed\x96\x8c\xbc\xc9\x7b\xbf\x53\x85\xc1\xfd\x19\x1b\xf6\x48\x3c\xd4\xe3\xf1" \
+"\xd1\xce\x8e\x1d\x0b\x0b\x92\xb6\xcb\xd6\x19\xc0\xec\xc5\xb0\x06\xd8\x69\x91\xbf\x73\xa1\x6b\xaa\xc2\x79\x94\xcd\x41\x74\x9d\x60\xad\xd9\x1e\x60\xae\xef\xb2\x97\x79\x2e\x03\x56\x41\x20\x78\xc3\x42\x56\x90\xce\x5b\x24\x94\x2a\xd8\xd0\xa4\xcb\x95\x45\xe6\x31\x4e\xe0\xb1\x17\xaf\x67\xbf\x6f\xb5\x82\xff\xd7\xbd\xad\x86\xbd\x40\x24\xe2\x86\x59\x74\x8a\x5c\x51\xf6\xca\x0a\xf3\x15\x51\xa5\xd2\xeb\x31\x63\xd9\x13\xb8\x36\x47\x66\x84\x31\x87\xe4\x9c\x43\xaa\x26\xad\xc8\xef\xf4\xff\x41\xd3\x64\xa1\x76\x6f\xda\xdb\x57\x17\x39\x09\xf6\x66\xfc\x9d\xcd\x62\x0c\x61\xc6\xb7\x8d\xdf\x9a\x17\xb4\x7b\x50\x9c\x90\xe7\x5f\x2a\x87\x1f\xf4\xa4\x79\x8a\x74\x9a\xcf\xde\x8a\x20\x54\xb9\x38\x72\x09\xf4\x0b\xd5\xed\xa6\x5b\x1f\xd9\x14\xb3\xa8\x79\x8b\xed\xb5\xdd\x5a\xae\x02\xb0\x22\xd2\x82\xf1\x82\xf0\xb2\x59\xb0\x82\xb9\xf3\x34\x65\x74\x70\x06\x3c\x54\x06\x6e\x1d\xf6\x42\x0a\xa4\x82\x2e\x4b\xa3\xb3\x2d\xfa\x20\x39\x30\x4a\xa9\x85\x2c\xa7\xf1\x67\x1f\x77\xf3\x4a\xd0\x04\xa2\x11\x0b\x48\x7e\x0a\x51\x75\xbc\x67\xde\xa3\x4e\xce\x48\xd8\x49" \
+"\x02\xdd\xe6\x7a\x6b\x8d\x7e\x01\xec\x3f\x33\xa9\xa0\x0e\xa5\xd0\xae\x09\x5b\x4a\xfc\x92\xc6\x4f\xee\xaf\x27\x66\x4b\x96\x28\x6d\x8f\x75\x4d\x99\xea\x52\x26\xa2\x17\xf2\x6b\x7c\xd9\x0d\x33\x37\x5c\x01\x1c\x8a\x3e\xd1\x45\xde\x3f\x3e\x96\xdd\x4a\xe8\xdc\xb5\x15\x24\xcb\xb6\xc1\xb7\xad\x71\x9d\xf1\xd0\x83\xac\x00\xb0\x37\xe5\x3f\x36\x54\xc5\x69\xc4\x9a\x3c\x34\x32\xbf\xe6\xca\x81\x55\xeb\x4b\xf5\xac\x3a\xe6\x00\xfb\xfa\x68\x7b\xf7\xe0\x78\x76\x1e\x32\xdf\x90\xe9\xf3\xd5\x3a\xe4\x7c\x18\xa8\xc2\x18\xc0\x04\x3f\x6b\x27\x37\xca\xc4\xfe\x95\x8d\xbd\x88\xda\x6c\xcb\x64\xc6\x79\xf0\xfc\xd0\xc8\xe6\xb2\x75\xc7\x02\x37\xa5\xd6\xd2\xf6\x8e\xb2\x3f\x56\xf9\x9c\x64\xac\xca\xc5\x94\xde\x4c\xb9\xdd\xf8\x47\x07\xe7\xe0\x9e\xec\x1b\x2c\x35\x3a\xb5\x41\xb0\x92\xdf\xfe\x05\xf9\xcf\xda\xa0\xd4\xf5\x0e\x72\xf6\x99\x8b\x37\xe6\x59\x8f\x7d\x85\x67\xf9\x7b\x5b\xe5\xc3\xd6\x41\xfb\xdb\x0b\x30\xa7\x48\x09\x83\x6e\xcf\xf4\xc5\x9f\x17\x33\xa1\x87\xfb\xdc\x34\xf2\x7a\xc7\x15\xe7\x22\xb9\x54\x8c\x70\x03\xa4\xe7\x40\xa2\xc0\x67\xb6\xa2\x70" \
+"\x02\x8e\x16\x94\x3e\x47\x4f\xe8\x55\x26\x0f\x57\xe6\xe8\x70\xcb\x5e\xe6\xac\xe9\xdb\x9e\xf6\x57\x3d\x9b\x16\x0e\x9d\x17\x3d\x63\xc4\x61\x46\xd8\xad\xec\xd3\x78\xc5\x1c\xe7\x2f\xd7\x42\x47\x2e\x42\x1c\x1d\xdf\x4d\xad\x90\x52\xdc\xde\x63\xe5\x4a\x35\x58\x74\x7b\xa2\xf0\xa8\xd8\x8e\xcd\x90\xb7\x7f\x87\x04\xa2\x5b\xb0\x4e\x1a\xb2\xf9\x68\xc3\x4c\x69\xce\x8f\x14\x9e\xdc\x16\x43\xc9\xed\x4e\xf1\x38\x6f\x3f\xa0\xf0\xa8\x83\xfd\x3e\x08\x33\x58\x2b\xae\xd9\xeb\xf3\x47\x32\xd2\x07\xeb\x38\x3f\x80\x6f\x20\xf4\xbb\xd9\xaa\x4d\x98\x41\x07\xc8\x1e\x2f\x53\x7e\x8b\xaa\x8e\xdb\xb8\x9c\x36\x66\xf9\x5e\x20\x02\xcc\xce\x4d\xe6\x3c\xb8\x8f\xa7\x6e\xf1\xcb\x3c\x2c\xae\x80\x96\xba\xd7\xda\xbd\x57\x6b\xd8\x54\x4c\xa6\xab\x5b\x17\x10\xd0\xd3\xb5\xea\x3d\xcb\xe0\xac\x80\x81\x42\x07\xf9\x00\x4b\x9d\xeb\x31\xf4\x9a\x9d\x6b\xcd\x46\x92\x26\xbc\x06\xda\x85\xe7\xcc\xa8\xea\x85\x11\xf5\x55\xfd\xa3\xf2\xa8\x38\x09\x63\x8e\xec\xed\x43\x14\xe2\x3c\x04\x56\x53\xd0\xf3\x13\x7f\xa8\x06\x9c\x43\xb3\x42\xaa\xf2\xd3\xaa\xc7\xbc\x47\xe7\xbf\x43\x2a" \
+"\x6d\x25\x75\x9a\xe7\x74\x3f\xe8\xce\x6b\x8d\x11\x7f\x8f\x4f\xf7\xa0\x3e\x97\xea\x74\x7e\x0e\xdf\x08\x05\x34\x52\x08\x63\x11\x09\x07\x04\xd0\x6a\x0b\xd0\x9c\x9d\x55\x33\xec\x80\x29\x42\x63\xf3\xdc\x99\x83\x6f\x4e\xbd\x5f\xdb\x33\x64\x29\x96\xbc\xda\x23\x25\xb0\x1f\x7a\xfc\xcf\xde\xd6\x8e\x5f\x13\x88\x9f\xc3\xd1\x27\xb6\x13\x61\xb9\x48\x53\xa5\xd0\xf9\x53\x04\xf4\xe6\x1e\x07\x0d\xa1\x5a\xc8\x79\x8a\x43\x97\xfc\xc5\xa5\x2c\xd7\x09\x51\x76\xb3\x9f\x0f\x03\x9c\x69\x97\x68\x6d\xa1\xca\x8f\xc7\x29\xbb\xac\x9a\x40\x69\x45\x43\xad\xe2\x22\xea\x6f\x45\xf4\x2d\xe6\x31\x0b\x12\x9e\x38\xb8\x37\x7c\x2e\xfc\xd7\x6d\xec\x7c\x9c\xac\x94\x9f\x2c\x93\x81\x32\x31\xe6\x80\xd5\x89\xa1\x7d\x8c\xde\x24\x5a\x75\xdf\x92\xed\x7a\x27\x76\xbc\x5d\x0b\x28\x31\x72\xe6\x50\x1f\xdd\x3a\xc7\xae\xc0\x70\x1f\xec\x62\x38\x4c\x1b\xc7\x4e\x1c\x30\x3e\xf6\xcf\x1e\x55\x32\x1f\x04\x8f\x3a\xf1\x83\x53\xcb\x46\xf1\x7c\x96\xa0\x58\x1e\xe3\xb1\xd5\x4b\x8b\x7a\x53\x53\x29\x61\x8c\x4e\x9d\xbc\xac\x55\x34\xca\x4c\x2f\x91\x4c\x7e\x90\xe4\x31\xef\x67\xc4\x95" \
+"\xcb\x85\x9f\xc9\xd7\xf1\x47\xf5\x72\x31\x7d\xe4\x16\xc0\xeb\xe6\xf6\xf7\x64\x6e\x4c\x4a\xd6\xe2\xdd\x78\x8c\xfa\x6c\x09\xcb\x28\x5c\x13\xb8\x88\x56\x4c\xfa\xb1\x40\x4c\xd6\x4f\xbe\x56\x08\x83\xb2\x00\xc8\xab\xf5\x90\x5e\x02\xec\x0b\xbb\x77\xa5\x53\x82\xfc\x31\x7e\xfe\x83\x26\x2b\xf5\xaa\x35\x07\xb7\xcd\x54\x47\x10\x7f\x56\xf9\x1f\xa9\x41\x21\xcf\x92\x6f\x9b\x2b\x91\x55\xfa\xd8\x26\x5f\x12\x81\xba\x0e\x03\x9e\x2b\xb7\x2c\xcd\x5a\x25\x8d\x1b\x82\x73\x04\x79\x43\x71\x2b\x6d\xfb\x47\x67\x20\x81\xa3\x49\x74\xfc\x20\x95\x11\x96\x75\xa8\xda\x38\xa3\xad\x7d\x54\x67\x88\xc3\x59\x2e\x1b\x2d\x99\x06\xb8\x51\x5d\x83\x1c\x2a\xab\x57\xb1\x87\x6d\x18\x4e\x50\x67\x6e\xa8\x03\xfb\xa5\x8b\xab\x19\x4d\xa6\xfa\xc1\xa6\xa8\xc3\xa0\x0c\x19\x6e\x24\x00\x84\xf7\xc7\xc3\x1e\xb1\x0e\xb0\xc5\x3a\x8e\x5d\x2b\x97\x7e\x1c\xb8\xe7\xb3\x71\xe3\x1a\xa5\x62\xb4\xb7\xda\xb6\x96\x7d\xe7\x66\xe7\xce\x27\x39\x79\xc1\x2b\x0b\xfe\xad\x1d\xfb\x2d\xab\x6a\x57\x72\x26\x3a\x99\x48\x54\xc1\x24\x02\x8e\xd7\x79\x93\xa0\x0b\x25\xf3\xd5\xd9\xb5\x98\x70\xbf" \
+"\x9b\xd9\x88\x75\xaf\xb6\x7d\x86\xda\x3a\xd4\xef\x27\xfa\x77\xdc\x71\xd6\x8f\xcc\x7c\x0b\x99\xc8\x9e\xd7\xfd\x28\x23\x11\xe8\x2d\xd9\x2f\xbf\x9f\xc7\x52\x29\x6a\x9e\xf4\xde\xfe\x85\x6d\x97\x2b\xbb\xcb\xa5\x3d\xa3\xcd\x07\xd9\x0c\xfc\x7b\x5a\xff\xff\x58\xdd\x7a\x4c\xad\xb9\x55\xb9\x21\xe4\xe2\xa1\x48\xd9\x22\xc5\x8c\xbe\x12\x07\x8e\xb1\xcb\x31\x5d\x5b\x0c\x0c\x1d\x23\x64\x88\x3a\x16\xae\x31\x47\xd1\xda\xc7\x7d\x33\x6e\x75\x2d\xcd\x8d\x51\xc0\x94\xd3\xee\xda\x54\xe3\xbf\xa0\x31\x6e\xcf\xbe\x08\x9c\xb8\xa7\x94\xe4\x45\x13\x27\x03\xd2\xcc\xc4\xe6\x7b\x40\x7b\x85\x73\x21\x55\x0f\x2d\x90\xda\x1f\xc0\x22\x3c\xd0\xa6\x71\x97\x7a\xf9\xab\xcf\x08\xa4\xcf\x8a\xf6\xd9\xfb\x22\x1b\x91\x90\x39\x3c\xa5\xcb\x75\xc7\x50\x8d\xda\x24\x41\x18\x73\x21\x98\x8b\x98\x22\x48\x63\xc0\xdb\x31\x41\xbb\xd9\x0e\xd0\x38\x3e\x8f\x0c\x33\xe1\xbb\x26\x13\x72\x53\x76\x75\x11\xf9\xe0\xb9\xe1\xed\x47\x4f\x43\x4b\x33\x00\x5c\x7b\x9b\x7a\x9a\x69\x65\xeb\x11\xa0\x23\x98\x6c\x2d\x97\x9a\x5c\x95\x3f\xff\x4d\x99\x68\x62\xd0\xfb\x70\xbd\x26\x66\xcd\x75" \
+"\xff\xe8\x96\x6d\x33\x46\x05\x0b\xe0\x29\x8d\xc8\xe3\xaa\x01\xdc\x22\x67\x70\xb9\xa9\xcf\x8d\xb7\xac\x3d\x81\x71\x7e\xc8\x3b\xc5\x5d\xf5\xf0\x3a\xe8\x28\x5a\x7d\x25\x86\xd2\x52\x76\xea\xc8\x73\xa9\x7c\xbc\x01\xac\xec\x1f\x4f\xd3\xd5\x92\xc3\xce\x69\x39\xf1\x3b\xed\x91\x20\x06\x18\xfd\x17\x3c\xd3\x02\x5e\x2a\xbe\xb4\xd5\xb1\x17\xa7\x68\x03\xe2\xab\xd0\x5f\x60\x39\x35\x8d\x73\x58\xae\x0a\xce\xea\x96\xb6\x9d\xf2\x5d\x61\x50\x09\x9a\x98\xa6\x5e\x8d\xee\xd4\x44\xe7\xf4\x00\x24\xa7\x02\x09\xa9\x10\x97\xaa\x21\x33\x01\x69\xd2\xc2\xe0\x92\xdd\xe3\x89\x3f\x90\x0e\x05\x8c\x1e\xc1\xcb\x2f\x5a\x14\xe9\xa9\x42\xc0\x5b\xfc\xa1\x8c\x43\xca\x0c\x18\xbe\xf2\x2e\xd0\x79\x08\xc2\xa4\xa4\x7d\xd8\xc2\xf2\x7d\x83\x23\x05\x2d\x12\x98\x9d\xf0\x23\x38\xf6\x90\xaf\x02\x07\x7b\x0d\x9e\xa8\x73\xdd\xc3\x36\xec\x23\x84\xf6\x07\x64\x6c\x78\x11\x17\xd2\x3d\xee\x26\x49\x95\x1c\xf9\x1d\x05\xe8\x1c\x83\x54\x4f\x9b\x1a\x52\x60\x96\xdb\x7a\xa7\xe7\x38\xe9\xb0\x9a\xd5\x7e\x0e\x9b\x0d\x44\x9d\x19\xec\xf4\x40\x7d\x4a\xf7\xf1\x7b\xb1\x66\x2b\xf4\x7a" \
+"\xad\x4b\x84\xf4\xf8\xec\xf6\xa1\x8a\x44\x56\x02\x34\x79\xe8\x60\x64\xcf\xee\xdb\x40\xc5\xa2\x08\x61\x90\x59\x79\x42\x92\xa6\xe9\x07\x91\xd9\xdf\x33\xfe\x80\x01\xd3\x01\x00\x00\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x0a\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x0a\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x0a\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30" \
+"\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x0a\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x0a\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x0a\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x0a\x63\x6c\x65\x61\x72\x74\x6f\x6d\x61\x72\x6b\x0a\x80" \
+"\x03"};
diff --git a/source/blender/src/CMakeLists.txt b/source/blender/src/CMakeLists.txt
new file mode 100644
index 00000000000..176ec036ada
--- /dev/null
+++ b/source/blender/src/CMakeLists.txt
@@ -0,0 +1,85 @@
+# $Id$
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2006, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Jacques Beaurain.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+
+FILE(GLOB SRC *.c)
+
+SET(INC
+ ../../../intern/guardedalloc ../../../intern/memutil
+ ../blenlib ../makesdna ../blenkernel
+ ../include ../../../intern/bmfont ../imbuf ../render/extern/include
+ ../../../intern/bsp/extern ../radiosity/extern/include
+ ../../../intern/decimation/extern ../blenloader ../python
+ ../../kernel/gen_system ../../../intern/SoundSystem ../readstreamglue
+ ../quicktime ../../../intern/elbeem/extern
+ ../../../intern/ghost ../../../intern/opennl/extern
+ ../nodes
+ ${PYTHON_INC}
+ ${SDL_INC}
+)
+
+IF(WITH_INTERNATIONAL)
+ SET(INC ${INC} ../ftfont)
+ ADD_DEFINITIONS(-DINTERNATIONAL)
+ ADD_DEFINITIONS(-DFTGL_STATIC_LIBRARY)
+ENDIF(WITH_INTERNATIONAL)
+
+IF(WITH_OPENEXR)
+ ADD_DEFINITIONS(-DWITH_OPENEXR)
+ENDIF(WITH_OPENEXR)
+
+IF(WITH_QUICKTIME)
+ SET(INC ${INC} ${QUICKTIME_INC})
+ ADD_DEFINITIONS(-DWITH_QUICKTIME)
+ENDIF(WITH_QUICKTIME)
+
+IF(WITH_FFMPEG)
+ SET(INC ${INC} ${FFMPEG_INC})
+ ADD_DEFINITIONS(-DWITH_FFMPEG)
+ENDIF(WITH_FFMPEG)
+
+IF(WIN32)
+ SET(INC ${INC} ${PTHREADS_INC})
+ENDIF(WIN32)
+
+IF(WITH_VERSE)
+ SET(INC ${INC} ${VERSE_INC})
+ ADD_DEFINITIONS(-DWITH_VERSE)
+ENDIF(WITH_VERSE)
+
+# TODO buildinfo
+IF(BF_BUILDINFO)
+ ADD_DEFINITIONS(-DNAN_BUILDINFO)
+ENDIF(BF_BUILDINFO)
+
+BLENDERLIB_NOLIST(src "${SRC}" "${INC}")
+
+IF(WITH_VERSE)
+ ADD_DEPENDENCIES(src mkprot verse)
+ENDIF(WITH_VERSE)
+
diff --git a/source/blender/src/Makefile b/source/blender/src/Makefile
new file mode 100644
index 00000000000..5038c294bc6
--- /dev/null
+++ b/source/blender/src/Makefile
@@ -0,0 +1,149 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+#
+
+ORGLIBNAME = src
+LIBNAME ?= $(ORGLIBNAME)
+DIR ?= $(OCGDIR)/blender/$(ORGLIBNAME)
+
+CSRCS ?= $(wildcard *.c)
+PUB_CSRCS ?= $(CSRCS)
+CRE_CSRCS ?= $(CSRCS) $(wildcard cre/*.c)
+
+OBJS = $(OCGDIR)/blender/makesdna/$(DEBUG_DIR)DNA.o
+
+ALLTARGETS = publisher
+
+include nan_compile.mk
+
+# Cflags stuff ------------------------------------------
+
+CFLAGS += $(LEVEL_1_C_WARNINGS)
+#CFLAGS += $(LEVEL_1_C_WARNINGS) -diag_error 1196
+
+# PreProcessor stuff ------------------------------------------
+
+CPPFLAGS += -I$(NAN_PYTHON)/include/python$(NAN_PYTHON_VERSION)
+CPPFLAGS += -I$(NAN_GHOST)/include
+CPPFLAGS += -I$(NAN_BMFONT)/include
+CPPFLAGS += -I$(NAN_ELBEEM)/include
+CPPFLAGS += -I$(NAN_SOUNDSYSTEM)/include $(NAN_SDLCFLAGS)
+
+# External interfaces of modules:
+CPPFLAGS += -I../render/extern/include
+CPPFLAGS += -I../blenkernel
+CPPFLAGS += -I../blenlib
+CPPFLAGS += -I../nodes
+CPPFLAGS += -I../python
+CPPFLAGS += -I../makesdna
+CPPFLAGS += -I../imbuf
+CPPFLAGS += -I../blenloader
+CPPFLAGS += -I..
+CPPFLAGS += -I../../kernel/gen_system
+CPPFLAGS += -I../../gameengine/SoundSystem
+CPPFLAGS += -I../ftfont
+
+# Only used by py_demo.c !!!
+CPPFLAGS += -I../radiosity/extern/include
+
+CPPFLAGS += -I$(SRCHOME)/gameengine/Physics/Sumo/include
+CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
+CPPFLAGS += -I$(NAN_MEMUTIL)/include
+
+CPPFLAGS += -I$(NAN_DECIMATION)/include
+CPPFLAGS += -I$(NAN_BSP)/include
+CPPFLAGS += -I$(NAN_OPENNL)/include
+
+CPPFLAGS += -I../readstreamglue
+CPPFLAGS += -I../include
+
+ifdef NAN_BUILDINFO
+ CPPFLAGS += -DNAN_BUILDINFO
+endif
+
+ifeq ($(OS),linux)
+ ifeq ($(CPU),alpha)
+ CPPFLAGS += -I$(NAN_MESA)/include
+ endif
+ ifeq ($(CPU),i386)
+ CPPFLAGS += -I$(NAN_MESA)/include
+ endif
+ ifeq ($(CPU),powerpc)
+ CPPFLAGS += -I/usr/src/MesaCVS/include
+ endif
+endif
+
+ifeq ($(WITH_QUICKTIME),true)
+ CPPFLAGS += -I../quicktime
+ CPPFLAGS += -DWITH_QUICKTIME
+endif
+
+ifeq ($(WITH_ICONV), true)
+ CPPFLAGS += -DWITH_ICONV
+ CPPFLAGS += $(NAN_ICONV_INC)
+endif
+
+ifeq ($(WITH_FFMPEG),true)
+ CPPFLAGS += -DWITH_FFMPEG
+ CPPFLAGS += $(NAN_FFMPEGCFLAGS)
+endif
+
+ifdef NAN_PTHREADS
+ CPPFLAGS += -I$(NAN_PTHREADS)/include
+endif
+
+ifeq ($(WITH_OPENEXR),true)
+ CPPFLAGS += -DWITH_OPENEXR
+endif
+
+ifeq ($(WITH_DDS),true)
+ CPPFLAGS += -DWITH_DDS
+endif
+
+ifeq ($(INTERNATIONAL), true)
+ CPPFLAGS += -DINTERNATIONAL
+endif
+
+ifeq ($(WITH_VERSE), true)
+ CPPFLAGS += -DWITH_VERSE
+ CPPFLAGS += -I$(NAN_VERSE)/include
+ # print some other debug information
+ ifeq ($(VERSE_DEBUG_PRINT), true)
+ CPPFLAGS += -DVERSE_DEBUG_PRINT
+ endif
+endif
+
+ifeq ($(NAN_TWEAK_MODE), true)
+ CPPFLAGS += -DTWEAK_MODE
+endif
+
+CPPFLAGS += -I$(OPENGL_HEADERS)
diff --git a/source/blender/src/SConscript b/source/blender/src/SConscript
new file mode 100644
index 00000000000..ba3e03ea1eb
--- /dev/null
+++ b/source/blender/src/SConscript
@@ -0,0 +1,64 @@
+#!/usr/bin/python
+Import ('env')
+
+# TODO: src_env.Append (CCFLAGS = user_options_dict['SDL_CFLAGS'])
+
+sources = env.Glob('*.c')
+
+incs = ' #/intern/guardedalloc #/intern/memutil'
+incs += ' ../blenlib ../makesdna ../blenkernel'
+incs += ' ../include #/intern/bmfont ../imbuf ../render/extern/include'
+incs += ' #/intern/bsp/extern ../radiosity/extern/include'
+incs += ' #/intern/decimation/extern ../blenloader ../python'
+incs += ' ../../kernel/gen_system #/intern/SoundSystem ../readstreamglue ../nodes'
+incs += ' ../quicktime #/intern/elbeem/extern'
+incs += ' #/intern/ghost #/intern/opennl/extern'
+
+
+incs += ' ' + env['BF_PYTHON_INC']
+incs += ' ' + env['BF_SDL_INC']
+incs += ' ' + env['BF_OPENGL_INC']
+
+defs = []
+
+if env['BF_TWEAK_MODE'] == 1:
+ defs.append('TWEAK_MODE')
+
+if env['WITH_BF_YAFRAY'] == 0:
+ defs.append('DISABLE_YAFRAY')
+
+if env['WITH_BF_INTERNATIONAL'] == 1:
+ incs += ' ../ftfont'
+ defs.append('INTERNATIONAL')
+ defs.append('FTGL_STATIC_LIBRARY')
+
+if env['WITH_BF_OPENEXR'] == 1:
+ defs.append('WITH_OPENEXR')
+
+if env['WITH_BF_DDS'] == 1:
+ defs.append('WITH_DDS')
+
+if env['WITH_BF_QUICKTIME']==1:
+ incs += ' ' + env['BF_QUICKTIME_INC']
+ defs.append('WITH_QUICKTIME')
+
+if env['WITH_BF_ICONV'] == 1:
+ incs += ' ' + env['BF_ICONV_INC']
+ defs.append('WITH_ICONV')
+
+if env['WITH_BF_FFMPEG'] == 1:
+ defs.append('WITH_FFMPEG')
+ incs += ' ' + env['BF_FFMPEG_INC']
+
+if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw'):
+ incs += ' ' + env['BF_PTHREADS_INC']
+
+if env['WITH_BF_VERSE']:
+ defs.append('WITH_VERSE')
+ incs += ' ' + env['BF_VERSE_INCLUDE']
+
+# TODO buildinfo
+if env['BF_BUILDINFO'] == 1:
+ defs.append('NAN_BUILDINFO')
+
+env.BlenderLib ( libname = 'src', sources = sources, includes = Split(incs), defines = defs, libtype=['core', 'intern'], priority = [5, 25] )
diff --git a/source/blender/src/bfont.ttf.c b/source/blender/src/bfont.ttf.c
new file mode 100644
index 00000000000..a52d6ded28a
--- /dev/null
+++ b/source/blender/src/bfont.ttf.c
@@ -0,0 +1,5992 @@
+/* DataToC output of file <bfont_ttf> */
+
+int datatoc_bfont_ttf_size= 191532;
+char datatoc_bfont_ttf[]= {
+ 0, 1, 0, 0, 0, 17, 1, 0, 0, 4, 0, 16,
+ 79, 83, 47, 50,150,230,175, 11, 0, 0, 1,152, 0, 0, 0, 86, 99,109, 97,112, 83, 13, 80,227, 0, 0, 28, 64, 0, 0, 3,138,
+ 99,118,116, 32, 0,105, 29, 57, 0, 0, 37,224, 0, 0, 1,254,102,101, 97,116,128, 29, 10, 57, 0, 2,233,124, 0, 0, 0, 80,
+102,112,103,109,113, 52,118,106, 0, 0, 31,204, 0, 0, 0,171,103,108,121,102, 31, 47,248,201, 0, 0, 53, 40, 0, 1,229,240,
+104,101, 97,100,232, 93,169,219, 0, 0, 1, 28, 0, 0, 0, 54,104,104,101, 97, 12,184, 14,241, 0, 0, 1, 84, 0, 0, 0, 36,
+104,109,116,120,203, 81,215, 70, 0, 0, 1,240, 0, 0, 26, 78,107,101,114,110,239,172, 97,238, 0, 2, 27, 24, 0, 0, 60, 6,
+108,111, 99, 97,253, 73,117,214, 0, 0, 39,224, 0, 0, 13, 72,109, 97,120,112, 10,234, 6,122, 0, 0, 1,120, 0, 0, 0, 32,
+109,111,114,120,223,111, 12,226, 0, 2,213, 8, 0, 0, 20,116,110, 97,109,101,179,203,190,182, 0, 2, 87, 32, 0, 0, 65, 55,
+112,111,115,116, 15, 42,244, 94, 0, 2,152, 88, 0, 0, 60,174,112,114,101,112, 59, 7,241, 0, 0, 0, 32,120, 0, 0, 5,104,
+112,114,111,112, 68,181,210, 32, 0, 2,233,204, 0, 0, 2, 96, 0, 1, 0, 0, 0, 2,204,204, 16,228, 33, 70, 95, 15, 60,245,
+ 2, 27, 8, 0, 0, 0, 0, 0,192,243, 73,110, 0, 0, 0, 0,192,243, 73,110,247,214,252,235, 13,114, 8, 75, 0, 0, 0, 8,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 7,109,254, 29, 0, 0, 13,226,247,214,252,109, 13,114, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6,132, 0, 1, 0, 0, 6,163, 0, 93, 0, 9, 0,112, 0, 8, 0, 2, 0, 16, 0, 64,
+ 0, 8, 0, 0, 4, 21, 5,104, 0, 8, 0, 3, 0, 1, 4, 14, 1,144, 0, 5, 0, 0, 5, 51, 5,153, 0, 0, 3,215, 5, 51,
+ 5,153, 0, 0, 0, 0, 0,102, 2, 18, 0, 0, 2, 11, 6, 3, 3, 8, 4, 2, 2, 4,224, 0, 38,255, 64, 0, 4,255, 0, 4,
+ 0, 32, 0, 0, 0, 0, 80,102, 69,100, 0, 64, 0, 13,255,253, 6, 20,254, 20, 1,154, 7,109, 1,227, 96, 0, 1,255,191,255,
+ 0, 0, 0, 0, 4,205, 0,102, 0, 0, 0, 0, 2,170, 0, 0, 2,139, 0, 0, 3, 53, 1, 53, 3,174, 0,197, 6,180, 0,158,
+ 5, 23, 0,170, 7,154, 0,113, 6, 61, 0,129, 2, 51, 0,197, 3, 31, 0,176, 3, 31, 0,164, 4, 0, 0, 61, 6,180, 0,217,
+ 2,139, 0,158, 2,227, 0,100, 2,139, 0,219, 2,178, 0, 0, 5, 23, 0,135, 5, 23, 0,225, 5, 23, 0,150, 5, 23, 0,156,
+ 5, 23, 0,100, 5, 23, 0,158, 5, 23, 0,143, 5, 23, 0,168, 5, 23, 0,139, 5, 23, 0,129, 2,178, 0,240, 2,178, 0,158,
+ 6,180, 0,217, 6,180, 0,217, 6,180, 0,217, 4, 63, 0,147, 8, 0, 0,135, 5,121, 0, 16, 5,125, 0,201, 5,150, 0,115,
+ 6, 41, 0,201, 5, 14, 0,201, 4,154, 0,201, 6, 51, 0,115, 6, 4, 0,201, 2, 92, 0,201, 2, 92,255,150, 5, 63, 0,201,
+ 4,117, 0,201, 6,231, 0,201, 5,252, 0,201, 6, 76, 0,115, 4,211, 0,201, 6, 76, 0,115, 5,143, 0,201, 5, 20, 0,135,
+ 4,227,255,250, 5,219, 0,178, 5,121, 0, 16, 7,233, 0, 68, 5,123, 0, 61, 4,227,255,252, 5,123, 0, 92, 3, 31, 0,176,
+ 2,178, 0, 0, 3, 31, 0,199, 6,180, 0,217, 4, 0,255,236, 4, 0, 0,170, 4,231, 0,123, 5, 20, 0,186, 4,102, 0,113,
+ 5, 20, 0,113, 4,236, 0,113, 2,209, 0, 47, 5, 20, 0,113, 5, 18, 0,186, 2, 57, 0,193, 2, 57,255,219, 4,162, 0,186,
+ 2, 57, 0,193, 7,203, 0,186, 5, 18, 0,186, 4,229, 0,113, 5, 20, 0,186, 5, 20, 0,113, 3, 74, 0,186, 4, 43, 0,111,
+ 3, 35, 0, 55, 5, 18, 0,174, 4,188, 0, 61, 6,139, 0, 86, 4,188, 0, 59, 4,188, 0, 61, 4, 51, 0, 88, 5, 23, 1, 0,
+ 2,178, 1, 4, 5, 23, 1, 0, 6,180, 0,217, 5, 23, 0, 0, 3, 53, 1, 53, 5, 23, 0,172, 5, 23, 0,129, 5, 23, 0, 94,
+ 5, 23, 0, 82, 2,178, 1, 4, 4, 0, 0, 92, 4, 0, 0,215, 8, 0, 1, 27, 3,197, 0,115, 4,229, 0,158, 6,180, 0,217,
+ 2,227, 0,100, 8, 0, 1, 27, 4, 0, 0,213, 4, 0, 0,195, 6,180, 0,217, 3, 53, 0, 94, 3, 53, 0, 98, 4, 0, 1,115,
+ 5, 23, 0,174, 5, 23, 0,158, 2,139, 0,219, 4, 0, 1, 35, 3, 53, 0,137, 3,197, 0, 96, 4,229, 0,193, 7,193, 0,137,
+ 7,193, 0,137, 7,193, 0, 98, 4, 63, 0,143, 5,121, 0, 16, 5,121, 0, 16, 5,121, 0, 16, 5,121, 0, 16, 5,121, 0, 16,
+ 5,121, 0, 16, 7,203, 0, 8, 5,150, 0,115, 5, 14, 0,201, 5, 14, 0,201, 5, 14, 0,201, 5, 14, 0,201, 2, 92, 0,201,
+ 2, 92, 0,201, 2, 92, 0,201, 2, 92, 0,201, 6, 51, 0, 10, 5,252, 0,201, 6, 76, 0,115, 6, 76, 0,115, 6, 76, 0,115,
+ 6, 76, 0,115, 6, 76, 0,115, 6,180, 1, 25, 6, 76, 0,102, 5,219, 0,178, 5,219, 0,178, 5,219, 0,178, 5,219, 0,178,
+ 4,227,255,252, 4,215, 0,201, 5, 10, 0,186, 4,231, 0,123, 4,231, 0,123, 4,231, 0,123, 4,231, 0,123, 4,231, 0,123,
+ 4,231, 0,123, 7,219, 0,123, 4,102, 0,113, 4,236, 0,113, 4,236, 0,113, 4,236, 0,113, 4,236, 0,113, 2, 57,255,199,
+ 2, 57, 0,144, 2, 57,255,222, 2, 57,255,244, 4,229, 0,113, 5, 18, 0,186, 4,229, 0,113, 4,229, 0,113, 4,229, 0,113,
+ 4,229, 0,113, 4,229, 0,113, 6,180, 0,217, 4,229, 0, 72, 5, 18, 0,174, 5, 18, 0,174, 5, 18, 0,174, 5, 18, 0,174,
+ 4,188, 0, 61, 5, 20, 0,186, 4,188, 0, 61, 5,121, 0, 16, 4,231, 0,123, 5,121, 0, 16, 4,231, 0,123, 5,121, 0, 16,
+ 4,231, 0,123, 5,150, 0,115, 4,102, 0,113, 5,150, 0,115, 4,102, 0,113, 5,150, 0,115, 4,102, 0,113, 5,150, 0,115,
+ 4,102, 0,113, 6, 41, 0,201, 5, 20, 0,113, 6, 51, 0, 10, 5, 20, 0,113, 5, 14, 0,201, 4,236, 0,113, 5, 14, 0,201,
+ 4,236, 0,113, 5, 14, 0,201, 4,236, 0,113, 5, 14, 0,201, 4,236, 0,113, 5, 14, 0,201, 4,236, 0,113, 6, 51, 0,115,
+ 5, 20, 0,113, 6, 51, 0,115, 5, 20, 0,113, 6, 51, 0,115, 5, 20, 0,113, 6, 51, 0,115, 5, 20, 0,113, 6, 4, 0,201,
+ 5, 18, 0,186, 7, 84, 0,201, 5,143, 0,120, 2, 92, 0,201, 2, 57,255,211, 2, 92, 0, 3, 2, 57,255,242, 2, 92, 0,201,
+ 2, 57,255,228, 2, 92, 0,176, 2, 57, 0,150, 2, 92, 0,201, 2, 57, 0,193, 4,184, 0,201, 4,114, 0,193, 2, 92,255,150,
+ 2, 57,255,219, 5, 63, 0,201, 4,162, 0,186, 4,162, 0,186, 4,117, 0,201, 2, 88, 0,193, 4,117, 0,201, 2, 57, 0,136,
+ 4,117, 0,201, 3, 0, 0,193, 4,117, 0,201, 2,188, 0,193, 4,127,255,242, 2, 70, 0, 2, 5,252, 0,201, 5, 18, 0,186,
+ 5,252, 0,201, 5, 18, 0,186, 5,252, 0,201, 5, 18, 0,186, 6,130, 0,205, 5,252, 0,213, 5, 18, 0,186, 6, 76, 0,115,
+ 4,229, 0,113, 6, 76, 0,115, 4,229, 0,113, 6, 76, 0,115, 4,229, 0,113, 8,143, 0,115, 8, 47, 0,113, 5,143, 0,201,
+ 3, 74, 0,186, 5,143, 0,201, 3, 74, 0,130, 5,143, 0,201, 3, 74, 0,186, 5, 20, 0,135, 4, 43, 0,111, 5, 20, 0,135,
+ 4, 43, 0,111, 5, 20, 0,135, 4, 43, 0,111, 5, 20, 0,135, 4, 43, 0,111, 4,227,255,250, 3, 35, 0, 55, 4,227,255,250,
+ 3, 35, 0, 55, 4,227,255,250, 3, 35, 0, 55, 5,219, 0,178, 5, 18, 0,174, 5,219, 0,178, 5, 18, 0,174, 5,219, 0,178,
+ 5, 18, 0,174, 5,219, 0,178, 5, 18, 0,174, 5,219, 0,178, 5, 18, 0,174, 5,219, 0,178, 5, 18, 0,174, 7,233, 0, 68,
+ 6,139, 0, 86, 4,227,255,252, 4,188, 0, 61, 4,227,255,252, 5,123, 0, 92, 4, 51, 0, 88, 5,123, 0, 92, 4, 51, 0, 88,
+ 5,123, 0, 92, 4, 51, 0, 88, 2,209, 0, 47, 5, 20, 0, 32, 5,225,255,151, 5,125, 0,201, 5, 20, 0,186, 5,125, 0, 0,
+ 5, 20, 0, 0, 5,160, 0,115, 5,150, 0,115, 4,102, 0,113, 6, 51, 0, 10, 6,141,255,151, 5,125, 0,201, 5, 20, 0,113,
+ 4,229, 0,113, 5, 14, 0,131, 6, 76, 0,117, 4,234, 0,164, 4,154,255,150, 2,209,255,127, 6, 51, 0,115, 5,126, 0, 8,
+ 7,180, 0,186, 2,212, 0,201, 2, 92, 0, 10, 5,133, 0,201, 4,162, 0,185, 2, 57, 0, 10, 4,188, 0, 61, 7,203, 0,178,
+ 5,252,255,150, 5, 18, 0,186, 6, 76, 0,115, 7, 78, 0,103, 4,229, 0,118, 7,151, 0,115, 6, 19, 0,113, 5, 55,255,151,
+ 5, 20, 0,184, 4,215, 0,201, 5, 20, 0, 69, 4, 43, 0,100, 5, 14, 0,201, 2,176,254,242, 3, 35, 0, 55, 4,227, 0, 24,
+ 3, 35, 0, 55, 4,227,255,250, 6,221, 0,173, 5, 18, 0,176, 6, 29, 0, 78, 5,196, 0,201, 5,145,255,252, 6,112, 0, 61,
+ 5,123, 0, 92, 4, 51, 0, 88, 5, 84, 0,160, 5, 84, 0, 92, 4,159, 0,104, 4, 51, 0,113, 5, 23, 0,150, 5, 84, 0, 93,
+ 4,159, 0,104, 4, 21, 0, 88, 5, 20, 0,186, 2, 92, 0,201, 3,240, 0,201, 3,172, 0, 20, 2, 93, 0,201, 11, 96, 0,201,
+ 10,100, 0,201, 9, 60, 0,113, 6,175, 0,201, 6, 75, 0,201, 3,167, 0,193, 7,115, 0,201, 7,100, 0,201, 6, 97, 0,186,
+ 5,121, 0, 16, 4,231, 0,123, 2, 92, 0,201, 2, 57,255,224, 6, 76, 0,115, 4,229, 0,113, 5,219, 0,178, 5, 18, 0,174,
+ 5,219, 0,178, 5, 18, 0,174, 5,219, 0,178, 5, 18, 0,174, 5,219, 0,178, 5, 18, 0,174, 5,219, 0,178, 5, 18, 0,174,
+ 4,236, 0, 0, 5,121, 0, 16, 4,231, 0,123, 5,121, 0, 16, 4,231, 0,123, 7,203, 0, 8, 7,219, 0,123, 6, 51, 0,115,
+ 5, 20, 0,113, 6, 51, 0,115, 5, 20, 0,113, 5, 63, 0,201, 4,162, 0,186, 6, 76, 0,115, 4,229, 0,113, 6, 76, 0,115,
+ 4,229, 0,113, 5, 84, 0,160, 4,159, 0,220, 2, 57,255,219, 11, 96, 0,201, 10,100, 0,201, 9, 60, 0,113, 6, 51, 0,115,
+ 5, 20, 0,113, 8,231, 0,201, 5,117, 0,201, 5,252, 0,201, 5, 18, 0,186, 5,121, 0, 16, 4,231, 0,123, 7,203, 0, 8,
+ 7,219, 0,123, 6, 76, 0,102, 4,229, 0, 72, 5,121, 0, 16, 4,231, 0,123, 5,121, 0, 16, 4,231, 0,123, 5, 14, 0,201,
+ 4,236, 0,113, 5, 14, 0,201, 4,236, 0,113, 2, 92, 0,201, 2, 57,255,195, 2, 92, 0,201, 2, 57,255,228, 6, 76, 0,115,
+ 4,229, 0,113, 6, 76, 0,115, 4,229, 0,113, 5,143, 0,201, 3, 74, 0,130, 5,143, 0,201, 3, 74, 0,186, 5,219, 0,178,
+ 5, 18, 0,174, 5,219, 0,178, 5, 18, 0,174, 5, 20, 0,135, 4, 43, 0,111, 4,227,255,250, 3, 35, 0, 55, 5, 4, 0,156,
+ 4, 44, 0, 71, 6, 4, 0,201, 5, 18, 0,186, 5,226, 0,201, 6,180, 0,113, 5,150, 0,113, 4,226, 0,113, 5,123, 0, 92,
+ 4, 51, 0, 88, 5,121, 0, 16, 4,231, 0,123, 5, 14, 0,201, 4,236, 0,113, 6, 76, 0,115, 4,229, 0,113, 6, 76, 0,115,
+ 4,229, 0,113, 6, 76, 0,115, 4,229, 0,113, 6, 76, 0,115, 4,229, 0,113, 4,227,255,252, 4,188, 0, 61, 3,204, 0,138,
+ 6,190, 0,186, 3,209, 0, 55, 2, 57,255,219, 7,252, 0,113, 7,252, 0,113, 5,121,255,253, 5,150, 0, 11, 4,102, 0, 9,
+ 4,117, 0, 10, 4,227,255,178, 4, 43, 0,111, 4, 51, 0, 88, 4,211, 0, 80, 8, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0,
+ 8, 0, 0, 0, 8, 0, 0, 0, 3, 60, 0,117, 3, 49, 0,117, 1,102,255,233, 2, 18, 0,117, 2, 93, 0, 71, 2, 94, 0, 71,
+ 3, 8, 0, 32, 4, 31, 0, 54, 2,251, 0, 38, 2, 51, 0,197, 3,174, 0,197, 2,139, 0,174, 2,139, 0,178, 2,139, 0,196,
+ 2,117, 0,117, 2,117, 0,117, 2,245, 0,117, 2,245, 0,117, 4, 0, 1, 11, 4, 0, 1, 11, 4, 0, 0,193, 4, 0, 0,193,
+ 4, 0, 0,193, 4, 0, 0,193, 2, 51, 0,214, 4, 0, 0,213, 4, 0, 1,115, 4, 0, 0,170, 2, 51, 0,214, 4, 0, 0,213,
+ 4, 0, 0,170, 4, 0, 1,115, 2,178, 0,111, 2,178, 0,111, 2,117, 0,117, 2,117, 0,117, 4, 0, 1, 31, 4, 0, 1, 31,
+ 3, 77, 0,193, 4, 0, 1, 31, 4, 0, 0,199, 4, 0, 1,154, 4, 0, 0,238, 4, 0, 1, 76, 4, 0, 0,182, 4, 0, 0,240,
+ 2,134,255,255, 4, 0, 0,239, 3,104, 0,117, 1, 84, 0,121, 2,252, 0,117, 3,141, 0,117, 2,245, 0,117, 3,242, 0,214,
+ 3,242, 0,214, 3,242, 0,214, 3,242, 0,214, 3,242, 0,214, 4, 0, 0,193, 4, 0, 0,213, 4, 0, 1, 21, 4, 0, 0,238,
+ 4, 0, 0,182, 0, 0,252,168, 0, 0,253,113, 0, 0,252,191, 0, 0,252,180, 0, 0,252,217, 0, 0,251,236, 0, 0,252,191,
+ 0, 0,253,164, 0, 0,252,213, 0, 0,253, 55, 0, 0,252,236, 0, 0,252,244, 0, 0,252,197, 0, 0,253,188, 0, 0,252,240,
+ 0, 0,252, 93, 0, 0,252,191, 0, 0,252,191, 0, 0,254, 31, 0, 0,253,144, 0, 0,253,144, 0, 0,255,121, 0, 0,252,168,
+ 0, 0,253,113, 0, 0,253, 12, 0, 0,253,188, 0, 0,254, 85, 0, 0,254,240, 0, 0,253,129, 0, 0,253, 11, 0, 0,253, 11,
+ 0, 0,253, 11, 0, 0,253, 11, 0, 0,253,122, 0, 0,253,119, 0, 0,253,154, 0, 0,252,213, 0, 0,252,236, 0, 0,253,106,
+ 0, 0,253, 35, 0, 0,253, 76, 0, 0,253,188, 0, 0,252,240, 0, 0,252, 99, 0, 0,252,197, 0, 0,252,191, 0, 0,252,191,
+ 0, 0,252,191, 0, 0,252,180, 0, 0,252,217, 0, 0,251,236, 0, 0,251,236, 0, 0,251,140, 0, 0,253,120, 0, 0,250,237,
+ 0, 0,251,104, 0, 0,250, 18, 0, 0,253,249, 0, 0,252,241, 0, 0,252,240, 0, 0,252, 99, 0, 0,253, 43, 0, 0,254, 6,
+ 0, 0,251,236, 0, 0,252,168, 0, 0,253,113, 0, 0,252,180, 0, 0,253,133, 0, 0,252,231, 0, 0,253,198, 0, 0,252,213,
+ 0, 0,253, 31, 0, 0,253, 21, 0, 0,253, 31, 0, 0,252,182, 0, 0,253, 72, 0, 0, 0, 0, 0, 0,252, 99, 0, 0,253, 51,
+ 0, 0,253,120, 0, 0,252,191, 0, 0,253, 43, 0, 0,253,120, 0, 0,255, 46, 0, 0,252,112, 0, 0,252,112, 0, 0,253, 42,
+ 0, 0,252,112, 0, 0,252,119, 2, 58, 0,160, 2, 58, 0,160, 4, 0, 1,182, 2,178, 0,158, 4, 0, 1,115, 4, 0, 0,215,
+ 5,138, 0, 16, 2,139, 0,219, 5,248,255,231, 6,248,255,243, 3, 68,255,237, 6,128,255,242, 6,153,255,225, 6,155,255,219,
+ 2,181, 0, 5, 5,121, 0, 16, 5,125, 0,201, 4,117, 0,201, 5,121, 0, 16, 5, 14, 0,201, 5,123, 0, 92, 6, 4, 0,201,
+ 6, 76, 0,115, 2, 92, 0,201, 5, 63, 0,201, 5,121, 0, 16, 6,231, 0,201, 5,252, 0,201, 5, 14, 0,201, 6, 76, 0,115,
+ 6, 4, 0,201, 4,211, 0,201, 5, 14, 0,201, 4,227,255,250, 4,227,255,252, 6, 76, 0,115, 5,123, 0, 61, 6, 76, 0,115,
+ 6, 29, 0, 78, 2, 92, 0,201, 4,227,255,252, 5, 70, 0,113, 4, 99, 0,133, 5, 60, 0,186, 2,181, 0,166, 4,161, 0,149,
+ 5, 70, 0,113, 5, 27, 0,191, 4,188, 0, 32, 4,229, 0,113, 4, 83, 0,133, 4, 90, 0,107, 5, 18, 0,186, 4,229, 0,113,
+ 2,181, 0,166, 4,183, 0,191, 4,188, 0, 61, 5, 23, 0,174, 4,120, 0, 74, 4,118, 0,107, 4,229, 0,113, 4,209, 0, 74,
+ 5, 20, 0,186, 4,178, 0,113, 5, 18, 0,113, 4,209, 0,100, 4,161, 0,149, 5, 71, 0,111, 4,159, 0, 59, 5, 71, 0,112,
+ 6,179, 0,135, 2,181, 0, 5, 4,161, 0,149, 4,229, 0,113, 4,161, 0,149, 6,179, 0,135, 4,234, 0,166, 4,244, 0,112,
+ 5,151, 0, 87, 6,189,255,225, 5,151, 0, 87, 5, 71, 0,112, 6,179, 0, 65, 5, 79, 0,111, 6, 76, 0,115, 4,229, 0,113,
+ 5, 48, 0,139, 4,178, 0,113, 4,154, 0,201, 3,171,255, 64, 5, 71, 0,179, 5, 71, 0,191, 6,236, 0,114, 5, 5, 0,119,
+ 7,120, 0,115, 6,179, 0,135, 6, 17, 0,115, 5, 70, 0,113, 6, 85, 0,201, 4,235, 0, 45, 5,126, 0, 79, 4,219, 0,100,
+ 6, 36, 0,115, 5, 0, 0, 54, 5,152, 0,115, 4,229, 0,113, 4,227, 0, 44, 4, 74, 0, 55, 5, 79, 0,111, 5, 20, 0,183,
+ 4,102, 0,113, 2, 57,255,219, 6, 76, 0,115, 4,236, 0,113, 4,236, 0,196, 4,215, 0,201, 5, 20, 0,186, 5,150, 0,115,
+ 6,231, 0,201, 5, 53, 0,127, 5, 20, 0, 85, 5,160, 0,115, 5,150, 0,115, 5,160, 0,115, 5, 14, 0,201, 5, 14, 0,201,
+ 6, 74,255,250, 4,117, 0,201, 5,150, 0,115, 5, 20, 0,135, 2, 92, 0,201, 2, 92, 0,201, 2, 92,255,150, 8,192, 0, 54,
+ 8, 92, 0,201, 6, 74,255,250, 5, 63, 0,201, 5,252, 0,201, 4,224, 0, 35, 6, 4, 0,201, 5,121, 0, 16, 5,125, 0,201,
+ 5,125, 0,201, 4,117, 0,201, 6, 54, 0, 49, 5, 14, 0,201, 6,232, 0, 59, 5, 23, 0,156, 5,252, 0,201, 5,252, 0,201,
+ 5, 63, 0,201, 6, 4, 0, 54, 6,231, 0,201, 6, 4, 0,201, 6, 76, 0,115, 6, 4, 0,201, 4,211, 0,201, 5,150, 0,115,
+ 4,227,255,250, 4,224, 0, 35, 6, 76, 0,115, 5,123, 0, 61, 6, 54, 0,201, 5,124, 0,175, 8, 6, 0,201, 8, 52, 0,201,
+ 6,169, 0, 50, 7, 15, 0,201, 5,125, 0,201, 5,150, 0,111, 8, 63, 0,211, 5,143, 0, 59, 4,231, 0,123, 4,229, 0,113,
+ 4,176, 0,186, 3,238, 0,186, 5, 96, 0, 50, 4,236, 0,113, 5,222, 0, 50, 4, 83, 0,133, 5, 65, 0,193, 5, 65, 0,193,
+ 4,213, 0,191, 5, 29, 0, 46, 6, 9, 0,193, 5, 73, 0,193, 4,229, 0,113, 5, 71, 0,193, 5, 20, 0,186, 4,102, 0,113,
+ 4, 59, 0, 5, 4,188, 0, 61, 7, 85, 0,113, 4,188, 0, 59, 5,114, 0,193, 4,186, 0,150, 6,251, 0,193, 7, 36, 0,193,
+ 5,160, 0, 42, 6, 31, 0,193, 4,183, 0,193, 4,100, 0,113, 6,128, 0,193, 4,208, 0, 50, 4,236, 0,113, 4,236, 0,113,
+ 5, 39, 0, 40, 3,238, 0,186, 4,100, 0,113, 4, 43, 0,111, 2, 57, 0,193, 2, 57,255,244, 2, 57,255,219, 7, 48, 0, 46,
+ 7, 34, 0,193, 5, 25, 0, 40, 4,213, 0,191, 5, 65, 0,193, 4,188, 0, 61, 5, 76, 0,193, 7,120, 0,115, 6,179, 0,135,
+ 5,125, 0, 33, 4,183, 0, 58, 7,138, 0,211, 5,254, 0,193, 7, 9, 0, 16, 6, 68, 0, 51, 9, 71, 0,201, 8, 3, 0,193,
+ 6, 76, 0,115, 4,229, 0,107, 8, 55, 0,201, 6,152, 0,193, 5, 23, 0,115, 4, 83, 0, 91, 6, 76, 0,115, 5, 71, 0,112,
+ 6, 76, 0,115, 4,229, 0,113, 6, 64, 0, 16, 5, 82, 0, 50, 6, 64, 0, 16, 5, 82, 0, 50, 5,150, 0,113, 4,226, 0,113,
+ 7,160, 0,115, 6, 17, 0,113, 7,120, 0,115, 6,179, 0,135, 7,120, 0,115, 6,179, 0,135, 5,150, 0,115, 4,102, 0,113,
+ 4,192, 0, 50, 0, 0,251,218, 0, 0,251,247, 0, 0,252, 34, 0, 0,252, 34, 3, 88,247,214, 3, 88,248, 88, 6, 46, 0,201,
+ 5,106, 0,193, 5,125, 0, 33, 4,183, 0, 38, 4,211, 0,201, 5, 20, 0,186, 4,117, 0,201, 3,238, 0,186, 4,117, 0, 71,
+ 3,238, 0, 56, 4,254, 0,201, 4, 61, 0,186, 6,232, 0, 59, 5,222, 0, 50, 5, 23, 0,156, 4, 83, 0,133, 5, 63, 0,201,
+ 4,213, 0,191, 5, 63, 0,201, 4,213, 0,191, 5, 63, 0, 33, 4,162, 0, 61, 6,107, 0, 50, 5,191, 0, 42, 6, 4, 0,201,
+ 5, 73, 0,193, 8, 29, 0,201, 7, 4, 0,193, 8,166, 0,201, 7, 83, 0,193, 6, 94, 0,115, 5, 54, 0,113, 5,150, 0,115,
+ 4,102, 0,113, 4,227,255,250, 4, 59, 0, 5, 4,227,255,252, 4,188, 0, 61, 4,227,255,252, 4,188, 0, 61, 5,123, 0, 61,
+ 4,188, 0, 59, 7,121,255,250, 6,116, 0, 5, 5,124, 0,175, 4,186, 0,150, 5,124, 0,175, 4,186, 0,150, 5,124, 0,175,
+ 5, 18, 0,186, 7,135, 0, 20, 5,211, 0, 15, 7,135, 0, 20, 5,211, 0, 15, 2, 57, 0,193, 6,232, 0, 59, 5,222, 0, 50,
+ 5, 63, 0,201, 4,213, 0,191, 6, 53, 0, 54, 5, 93, 0, 46, 6, 4, 0,201, 5, 73, 0,193, 6, 54, 0,201, 5,114, 0,193,
+ 5,124, 0,175, 4,186, 0,150, 7, 26, 0,201, 6, 50, 0,193, 5,121, 0, 16, 4,231, 0,123, 5,121, 0, 16, 4,231, 0,123,
+ 7,203, 0, 8, 7,219, 0,123, 5, 14, 0,201, 4,236, 0,113, 6, 76, 0,117, 4,236, 0, 0, 6, 76, 0,117, 4,236, 1, 43,
+ 6,232, 0, 59, 5,222, 0, 50, 5, 23, 0,156, 4, 83, 0,133, 5, 84, 0,160, 4,159, 0, 0, 5,252, 0,201, 5, 65, 0,193,
+ 5,252, 0,201, 5, 65, 0,193, 6, 76, 0,115, 4,229, 0,113, 6, 76, 0,115, 4,229, 0, 0, 6, 76, 0,115, 4,229, 1, 74,
+ 5,150, 0,111, 4,100, 0,113, 4,224, 0, 35, 4,188, 0, 61, 4,224, 0, 35, 4,188, 0, 61, 4,224, 0, 35, 4,188, 0, 61,
+ 5,124, 0,175, 4,186, 0,150, 4,117, 0,201, 3,238, 0,186, 7, 15, 0,201, 6, 31, 0,193, 5,125, 0,145, 4,183, 0,113,
+ 8, 12, 0,145, 7, 45, 0,113, 7,204, 0,201, 6,244, 0,171, 5,110, 0,201, 4,181, 0,171, 8,147, 0, 54, 7,168, 0, 46,
+ 8,148, 0,201, 7,189, 0,193, 6, 51, 0,115, 5, 71, 0, 0, 6, 47,255,250, 5,176, 0, 5, 6,239, 0,178, 5,219, 0,178,
+ 7, 15, 0,178, 7, 15, 0,178, 5,219, 0,178, 5, 38, 0,155, 5,219, 0,178, 5,219, 0,178, 6,206, 0,178, 7, 15, 0,178,
+ 5,219, 0,178, 5, 8, 0,178, 6,151, 0,178, 7,228, 0, 65, 5,219, 0,178, 5,168, 0,178, 5, 38, 0,143, 7, 15, 0,178,
+ 6, 55, 0, 92, 7, 15, 0,178, 5,219, 0,140, 6,185, 0, 92, 5,219, 0,178, 5,219, 0,178, 5,219, 0,178, 6, 83, 0,178,
+ 5, 38, 0,155, 7, 15, 0,178, 5,219, 0,178, 7, 15, 0,178, 5, 20, 0,135, 5,219, 0,178, 5,219, 0,140, 6,101, 0,178,
+ 6, 76, 0,115, 6, 82, 0, 92, 6, 76, 0,115, 5, 20, 0,135, 2,117, 0,117, 2,139, 0,178, 4, 0, 0, 94, 4, 0, 0,120,
+ 3, 34, 0,158, 4, 54, 0, 94, 4, 0, 0, 90, 7,203, 0,186, 5, 18, 0,186, 5,147, 0,113, 5,157, 0,186, 5, 18, 0,174,
+ 5,147, 0,113, 4, 68, 0,174, 5, 18, 0,186, 5,154, 0,186, 5,147, 0,113, 5, 18, 0,186, 3, 59, 0,193, 7,189, 0,186,
+ 5, 32, 0,113, 5, 18, 0,174, 5, 18, 0,186, 5, 20, 0,113, 5,157, 0,186, 5, 18, 0,174, 5, 70, 0,174, 2, 57,255,219,
+ 6, 20, 0, 49, 4, 32, 0,159, 5, 18, 0,186, 3,159, 0, 70, 7,203, 0, 0, 4, 32, 0,159, 5, 18, 0,186, 5, 18, 0,174,
+ 5,145, 0,174, 7,202, 0,174, 5, 18, 0,186, 5, 20, 0,113, 3, 59, 0,193, 7,202, 0,174, 5, 47, 0, 0, 4,229, 0,113,
+ 5, 8, 0,122, 6, 26, 0,174, 2,178, 0,240, 3,119, 0, 96, 2,149, 0,219, 5,121, 0, 16, 4,231, 0,123, 5,125, 0,201,
+ 5, 20, 0,186, 5,125, 0,201, 5, 20, 0,186, 5,125, 0,201, 5, 20, 0,186, 5,150, 0,115, 4,102, 0,113, 6, 41, 0,201,
+ 5, 20, 0,113, 6, 41, 0,201, 5, 20, 0,113, 6, 41, 0,201, 5, 20, 0,113, 6, 41, 0,201, 5, 20, 0,113, 6, 41, 0,201,
+ 5, 20, 0,113, 5, 14, 0,201, 4,236, 0,113, 5, 14, 0,201, 4,236, 0,113, 5, 14, 0,201, 4,236, 0,113, 5, 14, 0,201,
+ 4,236, 0,113, 5, 14, 0,201, 4,236, 0,113, 4,154, 0,201, 2,209, 0, 47, 6, 51, 0,115, 5, 20, 0,113, 6, 4, 0,201,
+ 5, 18, 0,186, 6, 4, 0,201, 5, 18, 0,186, 6, 4, 0,201, 5, 18,255,235, 6, 4, 0, 17, 5, 18, 0, 2, 6, 4, 0,201,
+ 5, 18, 0,186, 2, 92, 0, 0, 2, 57, 0, 39, 2, 92, 0,201, 2, 57, 0,193, 5, 63, 0,201, 4,162, 0,186, 5, 63, 0,201,
+ 4,162, 0,186, 5, 63, 0,201, 4,162, 0,186, 4,117, 0,201, 2, 57, 0,182, 4,117, 0, 3, 2, 57,255,242, 4,117, 0,201,
+ 2, 57, 0, 39, 4,117, 0,201, 2, 57,255,222, 6,231, 0,201, 7,203, 0,186, 6,231, 0,201, 7,203, 0,186, 6,231, 0,201,
+ 7,203, 0,186, 5,252, 0,201, 5, 18, 0,186, 5,252, 0,201, 5, 18, 0,186, 5,252, 0,201, 5, 18, 0,186, 5,252, 0,201,
+ 5, 18, 0,186, 6, 76, 0,115, 4,229, 0,113, 6, 76, 0,115, 4,229, 0,113, 6, 76, 0,115, 4,229, 0,113, 6, 76, 0,115,
+ 4,229, 0,113, 4,211, 0,201, 5, 20, 0,186, 4,211, 0,201, 5, 20, 0,186, 5,143, 0,201, 3, 74, 0,186, 5,143, 0,201,
+ 3, 74, 0,186, 5,143, 0,201, 3, 74, 0,186, 5,143, 0,201, 3, 74, 0, 84, 5, 20, 0,135, 4, 43, 0,111, 5, 20, 0,135,
+ 4, 43, 0,111, 5, 20, 0,135, 4, 43, 0,111, 5, 20, 0,135, 4, 43, 0,111, 5, 20, 0,135, 4, 43, 0,111, 4,227,255,250,
+ 3, 35, 0, 55, 4,227,255,250, 3, 35, 0, 55, 4,227,255,250, 3, 35, 0, 55, 4,227,255,250, 3, 35, 0, 55, 5,219, 0,178,
+ 5, 18, 0,174, 5,219, 0,178, 5, 18, 0,174, 5,219, 0,178, 5, 18, 0,174, 5,219, 0,178, 5, 18, 0,174, 5,219, 0,178,
+ 5, 18, 0,174, 5,121, 0, 16, 4,188, 0, 61, 5,121, 0, 16, 4,188, 0, 61, 7,233, 0, 68, 6,139, 0, 86, 7,233, 0, 68,
+ 6,139, 0, 86, 7,233, 0, 68, 6,139, 0, 86, 7,233, 0, 68, 6,139, 0, 86, 7,233, 0, 68, 6,139, 0, 86, 5,123, 0, 61,
+ 4,188, 0, 59, 5,123, 0, 61, 4,188, 0, 59, 4,227,255,252, 4,188, 0, 61, 5,123, 0, 92, 4, 51, 0, 88, 5,123, 0, 92,
+ 4, 51, 0, 88, 5,123, 0, 92, 4, 51, 0, 88, 5, 18, 0,186, 3, 35, 0, 4, 6,139, 0, 86, 4,188, 0, 61, 4,231, 0,123,
+ 2,209, 0, 47, 5,121, 0, 16, 4,231, 0,123, 5,121, 0, 16, 4,231, 0,123, 5,121, 0, 16, 4,231, 0,123, 5,121, 0, 16,
+ 4,231, 0,123, 5,121, 0, 16, 4,231, 0,123, 5,121, 0, 16, 4,231, 0,123, 5,121, 0, 16, 4,231, 0,123, 5,121, 0, 16,
+ 4,231, 0,123, 5,121, 0, 16, 4,231, 0,123, 5,121, 0, 16, 4,231, 0,123, 5,121, 0, 16, 4,231, 0,123, 5,121, 0, 16,
+ 4,231, 0,123, 5, 14, 0,201, 4,236, 0,113, 5, 14, 0,201, 4,236, 0,113, 5, 14, 0,201, 4,236, 0,113, 5, 14, 0,201,
+ 4,236, 0,113, 5, 14, 0,201, 4,236, 0,113, 5, 14, 0,201, 4,236, 0,113, 5, 14, 0,201, 4,236, 0,113, 5, 14, 0,201,
+ 4,236, 0,113, 2, 92, 0, 90, 2, 57, 0, 68, 2, 92, 0,200, 2, 57, 0,183, 6, 76, 0,115, 4,229, 0,113, 6, 76, 0,115,
+ 4,229, 0,113, 6, 76, 0,115, 4,229, 0,113, 6, 76, 0,115, 4,229, 0,113, 6, 76, 0,115, 4,229, 0,113, 6, 76, 0,115,
+ 4,229, 0,113, 6, 76, 0,115, 4,229, 0,113, 7, 78, 0,103, 4,229, 0,118, 7, 78, 0,103, 4,229, 0,118, 7, 78, 0,103,
+ 4,229, 0,118, 7, 78, 0,103, 4,229, 0,118, 7, 78, 0,103, 4,229, 0,118, 5,219, 0,178, 5, 18, 0,174, 5,219, 0,178,
+ 5, 18, 0,174, 6,221, 0,173, 5, 18, 0,176, 6,221, 0,173, 5, 18, 0,176, 6,221, 0,173, 5, 18, 0,176, 6,221, 0,173,
+ 5, 18, 0,176, 6,221, 0,173, 5, 18, 0,176, 4,227,255,252, 4,188, 0, 61, 4,227,255,252, 4,188, 0, 61, 4,227,255,252,
+ 4,188, 0, 61, 4,227,255,252, 4,188, 0, 61, 4, 0, 1,134, 4, 0, 1,115, 4, 0, 1,134, 4, 0, 0, 0, 8, 0, 0, 0,
+ 4, 0, 0, 0, 8, 0, 0, 0, 2,163, 0, 0, 2, 0, 0, 0, 1, 86, 0, 0, 5, 23, 0, 0, 2,139, 0, 0, 1,153, 0, 0,
+ 0,204, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,227, 0,100, 2,227, 0,100,
+ 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 8, 0, 0, 0, 4, 0, 1, 4, 4, 0,255,236, 2,139, 0,174, 2,139, 0,178,
+ 2,139, 0,174, 2,139, 0,178, 4, 37, 0,174, 4, 37, 0,174, 4, 37, 0,174, 4, 37, 0,174, 4, 0, 0, 57, 4, 0, 0, 57,
+ 4,184, 1, 51, 4,184, 1, 51, 2,173, 0,236, 5, 87, 0,236, 8, 0, 0,236, 2,139, 0,220, 10,188, 0,113, 13,226, 0,113,
+ 1,209, 0, 40, 2,253, 0, 40, 4, 41, 0, 40, 1,209, 0, 40, 2,253, 0, 40, 4, 41, 0, 40, 2,182, 0, 11, 3, 51, 0,158,
+ 3, 51, 0,193, 6,180, 0,195, 3,226, 0,147, 4, 63, 0,147, 4, 0,255,236, 6,110,255,167, 6,110,255,167, 2, 0,255,170,
+ 8, 0, 0, 61, 4, 0, 0,221, 1, 86,254,137, 3, 31, 0,176, 3, 31, 0,176, 7, 96, 0, 73, 5,221, 0,147, 5,221, 0,147,
+ 3,240, 0,111, 5, 23, 0,236, 4, 0, 0,216, 4, 0, 0,216, 4, 0, 0, 61, 2,178, 1, 29, 6,110,255,167, 4, 0, 0, 61,
+ 3,153, 0,145, 6,180, 0,217, 6,110,255,167, 6,180, 1, 56, 4,176, 0,250, 5, 78, 0, 40, 6,180, 1,102, 6,180, 1,102,
+ 2,139, 0,219, 6, 97, 0,100, 6,180, 0,112, 2,139, 0,219, 2,139, 0,219, 3, 53, 0, 87, 1,110, 0,121, 3, 53, 0, 63,
+ 3, 53, 0,102, 3, 53, 0, 92, 3, 53, 0,108, 3, 53, 0, 89, 3, 53, 0, 83, 4, 57, 0,137, 4, 57, 0,137, 4, 57, 0,137,
+ 1,247, 0,111, 1,247, 0,103, 3, 49, 0,117, 3, 53, 0, 87, 3, 53, 0,137, 3, 53, 0, 94, 3, 53, 0, 98, 3, 53, 0, 63,
+ 3, 53, 0,102, 3, 53, 0, 92, 3, 53, 0,108, 3, 53, 0, 89, 3, 53, 0, 83, 4, 57, 0,137, 4, 57, 0,137, 4, 57, 0,137,
+ 1,247, 0,111, 1,247, 0,103, 7, 4, 0, 86, 5, 23, 0,115, 5, 23, 0, 96, 5, 23, 0,133, 5, 23, 0,129, 7,203, 0,186,
+ 5,252, 0,117, 10, 46, 0,201, 8,151, 0,201, 7,233, 0, 59, 6, 70, 0, 95, 5, 23, 0,129, 5, 23, 0, 0, 5, 23, 0, 40,
+ 5, 23, 0, 20, 8,117, 0, 27, 5, 23, 0, 68, 6, 49, 0,117, 5, 33, 0,170, 0, 0,252, 61, 0, 0,252, 61, 8, 38, 0, 67,
+ 8,252, 0,195, 5, 35,255,214, 8, 38, 0, 60, 8,137, 0, 60, 7,157, 0,195, 5, 18, 0, 72, 5, 18, 0, 34, 5,148, 0,106,
+ 3, 78,255,228, 9, 81, 0,201, 8, 0, 1, 27, 5,148, 0,110, 6,131, 0, 83, 6, 87, 0,118, 7, 44, 0,169, 8, 40, 1, 3,
+ 8,152,255,252, 8, 0, 1, 39, 6, 29, 0, 78, 6, 29, 0, 78, 5, 63, 0,201, 5,121, 0, 16, 6,214, 0,125, 4,154, 0,201,
+ 3,178, 0,104, 5,246, 0,103, 9,141, 0,151, 6, 61, 0, 59, 7,193, 0,137, 7,193, 0, 94, 7,193, 0,137, 7,193, 0, 94,
+ 7,193, 0, 98, 7,193, 0, 63, 7,193, 0,137, 7,193, 0,102, 7,193, 0,137, 7,193, 0, 98, 7,193, 0,102, 7,193, 0,108,
+ 4,139, 0,137, 2, 92, 0,201, 3,240, 0,201, 5,132, 0,201, 7, 98, 0,201, 5,121, 0, 16, 7, 97, 0, 16, 8,245, 0, 16,
+ 10,137, 0, 16, 7, 87, 0,201, 5,123, 0, 61, 7,119, 0, 61, 9, 13, 0, 61, 4,117, 0,201, 5,150, 0,115, 6, 41, 0,201,
+ 6,231, 0,201, 2, 57, 0,193, 3,169, 0,193, 5, 25, 0,193, 6,126, 0,193, 4,188, 0, 61, 6,125, 0, 61, 7,237, 0, 61,
+ 9, 93, 0, 61, 6,141, 0,193, 4,188, 0, 59, 6,148, 0, 59, 8, 4, 0, 59, 2, 57, 0,193, 4,102, 0,113, 5, 20, 0,113,
+ 7,203, 0,186, 9,246, 0,121, 6, 41, 0,201, 9,246, 0,121, 5,160, 0,115, 6,180, 0,100, 6,180, 1,163, 6,180, 0,117,
+ 6,180, 1,163, 6,180, 0,100, 6,180, 1,163, 6,180, 1, 32, 6,180, 1, 32, 6,180, 1, 32, 6,180, 1, 32, 6,180, 0,100,
+ 6,180, 0,217, 6,180, 0,217, 6,180, 0,217, 1, 86,254,137, 5, 24, 1,138, 5, 2, 0,190, 5, 2, 1, 68, 2,139, 0,219,
+ 5, 25, 0, 61, 5, 25, 0, 61, 5, 25, 0, 61, 5,106, 0,221, 6,170, 0,221, 8, 0, 0,247, 6,180, 0,217, 8, 0, 0,172,
+ 3, 31, 0,183, 3, 31, 0,164, 7, 44, 0,152, 7, 44, 0,152, 7, 44, 0,152, 7, 44, 0,152, 7, 44, 0,152, 7, 44, 0,152,
+ 7, 44, 0,152, 7, 44, 0,152, 7, 44, 0,152, 7, 44, 0,152, 7, 44, 0,170, 5, 30, 0,170, 5,220, 0, 0, 5,131, 0, 47,
+ 5, 10, 0, 47, 5, 10, 0, 47, 7,188, 0, 47, 7,188, 0, 47, 5,125, 0, 47, 6,227, 0,111, 9,157, 0,170, 9,157, 0,174,
+ 9,145, 0,174, 9,125, 0,174, 12, 60, 0,174, 8, 52, 0, 30, 8, 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, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 28,
+ 0, 1, 0, 0, 0, 0, 2,132, 0, 3, 0, 1, 0, 0, 0, 28, 0, 4, 2,104, 0, 0, 0,150, 0,128, 0, 6, 0, 22, 0, 0,
+ 0,126, 2, 65, 2, 89, 2, 98, 2,112, 2,117, 2,146, 2,233, 2,238, 2,243, 2,247, 3, 78, 3, 83, 3, 88, 3, 93, 3, 98,
+ 3,117, 3,122, 3,126, 3,138, 3,140, 3,161, 3,206, 4,134, 4,206, 4,249, 5, 15, 5, 86, 5, 95, 5,135, 5,138, 6, 12,
+ 30,155, 30,249, 31,191, 31,254, 32, 39, 32, 94, 32,113, 32,142, 32,175, 32,177, 32,181, 32,215, 33, 0, 33, 6, 33, 9, 33, 15,
+ 33, 17, 33, 19, 33, 24, 33, 30, 33, 34, 33, 39, 33, 43, 33, 46, 33, 50, 33, 53, 33, 59, 33, 75, 33,131, 33,153, 33,181, 34, 30,
+ 35, 25, 35, 37, 35, 42, 36,105, 38,177, 40, 0,251, 6,251, 23,255,253,255,255, 0, 0, 0, 0, 0, 32, 0,160, 2, 89, 2, 98,
+ 2,112, 2,117, 2,146, 2,176, 2,236, 2,243, 2,247, 3, 0, 3, 81, 3, 87, 3, 92, 3, 96, 3,116, 3,122, 3,126, 3,132,
+ 3,140, 3,142, 3,163, 3,208, 4,136, 4,208, 5, 0, 5, 49, 5, 89, 5, 97, 5,137, 6, 12, 30, 0, 30,160, 31,191, 31,253,
+ 32, 0, 32, 48, 32,112, 32,116, 32,160, 32,177, 32,180, 32,214, 33, 0, 33, 3, 33, 9, 33, 14, 33, 17, 33, 19, 33, 22, 33, 28,
+ 33, 32, 33, 38, 33, 42, 33, 46, 33, 50, 33, 52, 33, 59, 33, 75, 33, 83, 33,144, 33,181, 34, 18, 35, 24, 35, 37, 35, 41, 36, 96,
+ 38,176, 40, 0,251, 0,251, 19,255,253,255,255, 0, 0,255,227,255,194,255,171,255,163,255,150,255,146,255,118,255, 89,255, 87,
+255, 83,255, 80,255, 72,255, 70,255, 67,255, 64,255, 62,255, 45,255, 41,255, 38,255, 33,255, 32,255, 31,255, 30,255, 29,255, 28,
+255, 27,255, 21,254,244,254,242,254,241,254,240,254,111,230,124,230,120,229,179,229,118,229,117,229,109,229, 92,229, 90,229, 73,
+229, 72,229, 70,229, 38,228,254,228,252,228,250,228,246,228,245,228,244,228,242,228,239,228,238,228,235,228,233,228,231,228,228,
+228,227,228,222,228,207,228,200,228,188,228,161,228, 69,227, 76,227, 65,227, 62,226, 9,223,195,222,117, 11,118, 11,106, 6,133,
+ 0, 1, 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, 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,
+ 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, 1, 6, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+ 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68,
+ 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 0,134,135,
+137,139,147,152,158,163,162,164,166,165,167,169,171,170,172,173,175,174,176,177,179,181,180,182,184,183,188,187,189,190, 0,114,
+100,101,105, 0,120,161,112,107, 0,118,106, 0,136,154, 0,115, 0, 0,103,119, 0, 0, 0, 0, 0,108,124, 0,168,186,129, 99,
+110, 0, 0, 0, 0,109,125, 0, 98,130,133,151, 0, 0, 0, 0, 0, 0, 0, 0,185, 0,193, 0, 0, 0, 0, 0, 0, 0, 0,121,
+ 0, 0, 0,132,140,131,141,138,143,144,145,142,149,150, 0,148,156,157,155, 0, 0, 0,113, 0, 0, 0,122, 0, 0, 0, 0, 0,
+183, 7, 6, 5, 4, 3, 2, 1, 0, 44, 32, 16,176, 2, 37, 73,100,176, 64, 81, 88, 32,200, 89, 33, 45, 44,176, 2, 37, 73,100,
+176, 64, 81, 88, 32,200, 89, 33, 45, 44, 32, 16, 7, 32,176, 0, 80,176, 13,121, 32,184,255,255, 80, 88, 4, 27, 5, 89,176, 5,
+ 28,176, 3, 37, 8,176, 4, 37, 35,225, 32,176, 0, 80,176, 13,121, 32,184,255,255, 80, 88, 4, 27, 5, 89,176, 5, 28,176, 3,
+ 37, 8,225, 45, 44, 75, 80, 88, 32,176,253, 69, 68, 89, 33, 45, 44,176, 2, 37, 69, 96, 68, 45, 44, 75, 83, 88,176, 2, 37,176,
+ 2, 37, 69, 68, 89, 33, 33, 45, 44, 69, 68, 45, 44,176, 2, 37,176, 2, 37, 73,176, 5, 37,176, 5, 37, 73, 96,176, 32, 99,104,
+ 32,138, 16,138, 35, 58,138, 16,101, 58, 45, 0,184, 2,128, 64,255,251,254, 3,250, 20, 3,249, 37, 3,248, 50, 3,247,150, 3,
+246, 14, 3,245,254, 3,244,254, 3,243, 37, 3,242, 14, 3,241,150, 3,240, 37, 3,239,138, 65, 5,239,254, 3,238,150, 3,237,
+150, 3,236,250, 3,235,250, 3,234,254, 3,233, 58, 3,232, 66, 3,231,254, 3,230, 50, 3,229,228, 83, 5,229,150, 3,228,138,
+ 65, 5,228, 83, 3,227,226, 47, 5,227,250, 3,226, 47, 3,225,254, 3,224,254, 3,223, 50, 3,222, 20, 3,221,150, 3,220,254,
+ 3,219, 18, 3,218,125, 3,217,187, 3,216,254, 3,214,138, 65, 5,214,125, 3,213,212, 71, 5,213,125, 3,212, 71, 3,211,210,
+ 27, 5,211,254, 3,210, 27, 3,209,254, 3,208,254, 3,207,254, 3,206,254, 3,205,150, 3,204,203, 30, 5,204,254, 3,203, 30,
+ 3,202, 50, 3,201,254, 3,198,133, 17, 5,198, 28, 3,197, 22, 3,196,254, 3,195,254, 3,194,254, 3,193,254, 3,192,254, 3,
+191,254, 3,190,254, 3,189,254, 3,188,254, 3,187,254, 3,186, 17, 3,185,134, 37, 5,185,254, 3,184,183,187, 5,184,254, 3,
+183,182, 93, 5,183,187, 3,183,128, 4,182,181, 37, 5,182, 93, 64,255, 3,182, 64, 4,181, 37, 3,180,254, 3,179,150, 3,178,
+254, 3,177,254, 3,176,254, 3,175,254, 3,174,100, 3,173, 14, 3,172,171, 37, 5,172,100, 3,171,170, 18, 5,171, 37, 3,170,
+ 18, 3,169,138, 65, 5,169,250, 3,168,254, 3,167,254, 3,166,254, 3,165, 18, 3,164,254, 3,163,162, 14, 5,163, 50, 3,162,
+ 14, 3,161,100, 3,160,138, 65, 5,160,150, 3,159,254, 3,158,157, 12, 5,158,254, 3,157, 12, 3,156,155, 25, 5,156,100, 3,
+155,154, 16, 5,155, 25, 3,154, 16, 3,153, 10, 3,152,254, 3,151,150, 13, 5,151,254, 3,150, 13, 3,149,138, 65, 5,149,150,
+ 3,148,147, 14, 5,148, 40, 3,147, 14, 3,146,250, 3,145,144,187, 5,145,254, 3,144,143, 93, 5,144,187, 3,144,128, 4,143,
+142, 37, 5,143, 93, 3,143, 64, 4,142, 37, 3,141,254, 3,140,139, 46, 5,140,254, 3,139, 46, 3,138,134, 37, 5,138, 65, 3,
+137,136, 11, 5,137, 20, 3,136, 11, 3,135,134, 37, 5,135,100, 3,134,133, 17, 5,134, 37, 3,133, 17, 3,132,254, 3,131,130,
+ 17, 5,131,254, 3,130, 17, 3,129,254, 3,128,254, 3,127,254, 3, 64,255,126,125,125, 5,126,254, 3,125,125, 3,124,100, 3,
+123, 84, 21, 5,123, 37, 3,122,254, 3,121,254, 3,120, 14, 3,119, 12, 3,118, 10, 3,117,254, 3,116,250, 3,115,250, 3,114,
+250, 3,113,250, 3,112,254, 3,111,254, 3,110,254, 3,108, 33, 3,107,254, 3,106, 17, 66, 5,106, 83, 3,105,254, 3,104,125,
+ 3,103, 17, 66, 5,102,254, 3,101,254, 3,100,254, 3, 99,254, 3, 98,254, 3, 97, 58, 3, 96,250, 3, 94, 12, 3, 93,254, 3,
+ 91,254, 3, 90,254, 3, 89, 88, 10, 5, 89,250, 3, 88, 10, 3, 87, 22, 25, 5, 87, 50, 3, 86,254, 3, 85, 84, 21, 5, 85, 66,
+ 3, 84, 21, 3, 83, 1, 16, 5, 83, 24, 3, 82, 20, 3, 81, 74, 19, 5, 81,254, 3, 80, 11, 3, 79,254, 3, 78, 77, 16, 5, 78,
+254, 3, 77, 16, 3, 76,254, 3, 75, 74, 19, 5, 75,254, 3, 74, 73, 16, 5, 74, 19, 3, 73, 29, 13, 5, 73, 16, 3, 72, 13, 3,
+ 71,254, 3, 70,150, 3, 69,150, 3, 68,254, 3, 67, 2, 45, 5, 67,250, 3, 66,187, 3, 65, 75, 3, 64,254, 3, 63,254, 3, 62,
+ 61, 18, 5, 62, 20, 3, 61, 60, 15, 5, 61, 18, 3, 60, 59, 13, 5, 60, 64,255, 15, 3, 59, 13, 3, 58,254, 3, 57,254, 3, 56,
+ 55, 20, 5, 56,250, 3, 55, 54, 16, 5, 55, 20, 3, 54, 53, 11, 5, 54, 16, 3, 53, 11, 3, 52, 30, 3, 51, 13, 3, 50, 49, 11,
+ 5, 50,254, 3, 49, 11, 3, 48, 47, 11, 5, 48, 13, 3, 47, 11, 3, 46, 45, 9, 5, 46, 16, 3, 45, 9, 3, 44, 50, 3, 43, 42,
+ 37, 5, 43,100, 3, 42, 41, 18, 5, 42, 37, 3, 41, 18, 3, 40, 39, 37, 5, 40, 65, 3, 39, 37, 3, 38, 37, 11, 5, 38, 15, 3,
+ 37, 11, 3, 36,254, 3, 35,254, 3, 34, 15, 3, 33, 1, 16, 5, 33, 18, 3, 32,100, 3, 31,250, 3, 30, 29, 13, 5, 30,100, 3,
+ 29, 13, 3, 28, 17, 66, 5, 28,254, 3, 27,250, 3, 26, 66, 3, 25, 17, 66, 5, 25,254, 3, 24,100, 3, 23, 22, 25, 5, 23,254,
+ 3, 22, 1, 16, 5, 22, 25, 3, 21,254, 3, 20,254, 3, 19,254, 3, 18, 17, 66, 5, 18,254, 3, 17, 2, 45, 5, 17, 66, 3, 16,
+125, 3, 15,100, 3, 14,254, 3, 13, 12, 22, 5, 13,254, 3, 12, 1, 16, 5, 12, 22, 3, 11,254, 3, 10, 16, 3, 9,254, 3, 8,
+ 2, 45, 5, 8,254, 3, 7, 20, 3, 6,100, 3, 4, 1, 16, 5, 4,254, 3, 64, 21, 3, 2, 45, 5, 3,254, 3, 2, 1, 16, 5,
+ 2, 45, 3, 1, 16, 3, 0,254, 3, 1,184, 1,100,133,141, 1, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+ 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+ 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+ 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+ 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+ 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 0, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+ 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+ 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+ 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+ 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+ 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 29, 1, 53, 0,184, 0,203, 0,203, 0,193, 0,170,
+ 0,156, 1,166, 0,184, 0,102, 0, 0, 0,113, 0,203, 0,160, 2,178, 0,133, 0,117, 0,184, 0,195, 1,203, 1,137, 2, 45,
+ 0,203, 0,166, 0,240, 0,211, 0,170, 0,135, 0,203, 3,170, 4, 0, 1, 74, 0, 51, 0,203, 0, 0, 0,217, 5, 2, 0,244,
+ 1, 84, 0,180, 0,156, 1, 57, 1, 20, 1, 57, 7, 6, 4, 0, 4, 78, 4,180, 4, 82, 4,184, 4,231, 4,205, 0, 55, 4,115,
+ 4,205, 4, 96, 4,115, 1, 51, 3,162, 5, 86, 5,166, 5, 86, 5, 57, 3,197, 2, 18, 0,201, 0, 31, 0,184, 1,223, 0,115,
+ 0,186, 3,233, 3, 51, 3,188, 4, 68, 4, 14, 0,223, 3,205, 3,170, 0,229, 3,170, 4, 4, 0, 0, 0,203, 0,143, 0,164,
+ 0,123, 0,184, 0, 20, 1,111, 0,127, 2,123, 2, 82, 0,143, 0,199, 5,205, 0,154, 0,154, 0,111, 0,203, 0,205, 1,158,
+ 1,211, 0,240, 0,186, 1,131, 0,213, 0,152, 3, 4, 2, 72, 0,158, 1,213, 0,193, 0,203, 0,246, 0,131, 3, 84, 2,127,
+ 0, 0, 3, 51, 2,102, 0,211, 0,199, 0,164, 0,205, 0,143, 0,154, 0,115, 4, 0, 5,213, 1, 10, 0,254, 2, 43, 0,164,
+ 0,180, 0,156, 0, 0, 0, 98, 0,156, 0, 0, 0, 29, 3, 45, 5,213, 5,213, 5,213, 5,240, 0,127, 0,123, 0, 84, 0,164,
+ 6,184, 6, 20, 7, 35, 1,211, 0,184, 0,203, 0,166, 1,195, 1,236, 6,147, 0,160, 0,211, 3, 92, 3,113, 3,219, 1,133,
+ 4, 35, 4,168, 4, 72, 0,143, 1, 57, 1, 20, 1, 57, 3, 96, 0,143, 5,213, 1,154, 6, 20, 7, 35, 6,102, 1,121, 4, 96,
+ 4, 96, 4, 96, 4,123, 0,156, 0, 0, 2,119, 4, 96, 1,170, 0,233, 4, 96, 7, 98, 0,123, 0,197, 0,127, 2,123, 0, 0,
+ 0,180, 2, 82, 5,205, 0,102, 0,188, 0,102, 0,119, 6, 16, 0,205, 1, 59, 1,133, 3,137, 0,143, 0,123, 0, 0, 0, 29,
+ 0,205, 7, 74, 4, 47, 0,156, 0,156, 0, 0, 7,125, 0,111, 0, 0, 0,111, 3, 53, 0,106, 0,111, 0,123, 0,174, 0,178,
+ 0, 45, 3,150, 0,143, 2,123, 0,246, 0,131, 3, 84, 6, 55, 5,246, 0,143, 0,156, 4,225, 2,102, 0,143, 1,141, 2,246,
+ 0,205, 3, 68, 0, 41, 0,102, 4,238, 0,115, 0, 0, 20, 0, 0,150, 0, 0, 0, 0, 0, 34, 0, 34, 0, 34, 0, 34, 0, 84,
+ 0,138, 0,246, 1,162, 2, 54, 3,106, 3,148, 3,204, 3,248, 4, 70, 4,112, 4,140, 4,162, 4,182, 4,220, 5, 30, 5, 86,
+ 5,212, 6, 72, 6,166, 7, 6, 7,114, 7,184, 8, 34, 8,140, 8,172, 8,212, 9, 16, 9, 50, 9,110, 9,218, 10,154, 11, 20,
+ 11,108, 11,184, 11,248, 12, 40, 12, 82, 12,166, 12,212, 12,248, 13, 48, 13,196, 13,230, 14,100, 14,184, 14,254, 15, 62, 15,164,
+ 16, 46, 16,170, 16,226, 17, 36, 17,148, 18,114, 18,196, 19, 38, 19,134, 19,182, 19,220, 20, 6, 20, 40, 20, 62, 20,102, 20,252,
+ 21, 72, 21,148, 21,224, 22, 74, 22,150, 22,250, 23, 54, 23, 94, 23,156, 24, 20, 24, 50, 24,148, 24,208, 25, 34, 25,114, 25,194,
+ 25,250, 26,170, 26,232, 27, 36, 27,182, 28,200, 29,138, 30,112, 30,214, 31, 68, 31, 92, 31,210, 32, 20, 32, 20, 32, 92, 32,194,
+ 33, 30, 33,170, 34, 60, 34, 96, 35, 4, 35, 96, 35,242, 36, 96, 36,198, 36,226, 36,248, 37,158, 37,196, 38, 0, 38, 56, 38,136,
+ 38,230, 39, 14, 39,104, 39,150, 39,172, 39,220, 40, 8, 40, 76, 40,180, 40,196, 40,212, 40,228, 41, 96, 41,108, 41,120, 41,142,
+ 41,166, 41,190, 42, 94, 42,202, 42,214, 42,226, 42,238, 43, 0, 43, 18, 43, 30, 43, 42, 43, 60, 43, 78, 43,180, 43,204, 43,216,
+ 43,228, 43,250, 44, 20, 44, 44, 44,144, 45, 44, 45, 56, 45, 68, 45, 92, 45,120, 45,132, 45,200, 46, 92, 46,110, 46,128, 46,144,
+ 46,166, 46,194, 46,226, 47,192, 47,204, 47,216, 47,228, 47,246, 48, 8, 48, 20, 48, 32, 48, 50, 48, 68, 49, 28, 49, 40, 49, 52,
+ 49, 64, 49, 80, 49,102, 49,124, 49,170, 50,100, 50,112, 50,124, 50,140, 50,164, 50,176, 51, 0, 51, 24, 51, 46, 51, 66, 51, 88,
+ 51,104, 51,116, 51,128, 51,140, 51,152, 51,170, 51,182, 51,194, 51,206, 51,224, 51,236, 51,248, 52, 12, 52, 20, 52,114, 52,126,
+ 52,144, 52,162, 52,180, 52,192, 52,204, 52,216, 52,228, 52,246, 53, 12, 53, 30, 53, 48, 53, 60, 53, 72, 53, 90, 53,102, 53,114,
+ 53,126, 53,150, 53,184, 53,252, 54, 70, 54, 88, 54,106, 54,124, 54,142, 54,160, 54,178, 54,190, 54,202, 54,226, 55, 0, 55, 18,
+ 55, 36, 55, 54, 55, 72, 55, 84, 55, 96, 55,216, 55,228, 56, 0, 56, 12, 56, 30, 56, 42, 56, 60, 56, 72, 56, 98, 56,160, 56,232,
+ 56,250, 57, 12, 57, 24, 57, 36, 57, 60, 57, 82, 57, 94, 57,166, 57,244, 58, 10, 58, 26, 58, 48, 58, 64, 58, 76, 58, 88, 58,168,
+ 59, 60, 59, 72, 59, 84, 59, 96, 59,108, 59,126, 59,146, 59,158, 59,170, 59,190, 59,208, 59,220, 59,232, 59,252, 60, 14, 60, 26,
+ 60, 38, 60, 60, 60, 78, 60,144, 60,220, 60,242, 61, 4, 61, 28, 61, 46, 61, 68, 61, 86, 61,104, 61,122, 61,134, 61,146, 61,158,
+ 61,170, 61,188, 61,206, 61,224, 61,240, 62, 2, 62, 14, 62, 26, 62, 38, 62, 50, 62, 62, 62, 82, 62,126, 62,228, 63, 72, 63, 80,
+ 63,170, 63,240, 64, 68, 64,140, 64,202, 65, 0, 65, 8, 65, 82, 65,144, 65,192, 66, 8, 66, 54, 66,142, 66,234, 67, 42, 67,134,
+ 67,234, 68,116, 68,212, 69, 2, 69, 58, 69, 98, 69,230, 70, 22, 70, 58, 70,112, 70,216, 70,224, 71, 48, 71, 60, 71, 72, 71,130,
+ 71,184, 72, 4, 72,102, 72,164, 72,226, 73,134, 73,142, 73,196, 73,240, 74, 56, 74,134, 74,204, 74,216, 74,228, 75, 58, 75,106,
+ 75,142, 75,186, 75,222, 76, 2, 76, 62, 76,122, 76,180, 76,234, 77, 32, 77, 96, 77,156, 77,214, 78, 0, 78, 14, 78, 26, 78, 60,
+ 78, 68, 78, 80, 78, 92, 78,104, 78,116, 78,128, 78,140, 78,152, 78,164, 78,176, 78,192, 78,208, 78,228, 78,248, 79, 4, 79, 20,
+ 79, 36, 79, 54, 79, 66, 79, 78, 79, 90, 79,102, 79,114, 79,126, 79,138, 79,150, 79,158, 79,170, 79,182, 79,194, 79,206, 79,218,
+ 79,230, 80, 38, 80,118, 80,140, 80,152, 80,164, 80,198, 80,210, 80,222, 80,234, 80,246, 81, 2, 81, 14, 81, 34, 81, 46, 81, 58,
+ 81, 70, 81, 84, 81, 96, 81,146, 81,190, 81,202, 81,214, 81,226, 81,238, 81,250, 82, 6, 82, 18, 82, 30, 82, 42, 82, 54, 82, 66,
+ 82, 78, 82, 90, 82,102, 82,114, 82,126, 82,138, 82,150, 82,162, 82,174, 82,186, 82,198, 82,210, 82,222, 82,234, 82,246, 83, 2,
+ 83, 14, 83, 26, 83, 38, 83, 50, 83, 62, 83, 74, 83, 86, 83, 98, 83,110, 83,186, 84, 8, 84, 20, 84, 54, 84, 94, 84,176, 85, 10,
+ 85, 92, 85,130, 85,168, 85,180, 85,192, 85,204, 85,216, 85,228, 85,240, 85,252, 86, 8, 86, 20, 86, 32, 86, 44, 86, 56, 86, 68,
+ 86, 80, 86,122, 86,188, 86,240, 87, 34, 87,112, 87,190, 87,246, 88, 62, 88,128, 88,154, 88,194, 89, 22, 89, 66, 89,108, 89,108,
+ 89,108, 89,108, 89,108, 89,108, 89,166, 89,238, 90, 30, 90, 78, 90,116, 90,166, 90,220, 90,248, 91, 26, 91, 34, 91, 42, 91, 50,
+ 91, 58, 91, 76, 91,104, 91,134, 91,180, 91,228, 91,248, 92, 12, 92, 32, 92, 52, 92, 98, 92,144, 92,168, 92,176, 92,190, 92,206,
+ 92,230, 92,240, 93, 0, 93, 14, 93, 34, 93, 48, 93, 58, 93, 68, 93, 86, 93,104, 93,126, 93,140, 93,210, 93,234, 94, 32, 94, 80,
+ 94,176, 94,230, 95, 2, 95, 28, 95, 70, 95, 90, 95,166, 95,194, 95,242, 96, 12, 96, 50, 96, 82, 96,120, 96,146, 96,156, 96,168,
+ 96,188, 96,198, 96,244, 96,254, 97, 8, 97, 18, 97, 28, 97, 38, 97, 48, 97, 58, 97, 68, 97, 78, 97,136, 97,146, 97,156, 97,166,
+ 97,180, 97,194, 97,216, 97,230, 97,240, 98, 4, 98, 24, 98, 42, 98, 56, 98, 66, 98, 76, 98, 94, 98,112, 98,128, 98,186, 98,214,
+ 98,232, 98,250, 99, 16, 99, 30, 99, 54, 99, 78, 99, 88, 99, 98, 99,108, 99,126, 99,136, 99,146, 99,160, 99,178, 99,214, 99,224,
+ 99,234, 99,244, 99,254,100, 8,100, 18,100, 28,100, 38,100, 84,100, 98,100,112,100,128,100,144,100,154,100,164,100,186,100,222,
+100,248,101, 40,101, 54,101, 64,101, 74,101, 84,101, 94,101,104,101,114,101,132,101,152,101,172,101,188,101,250,102, 14,102, 26,
+102, 54,102, 74,102,106,102,118,102,128,102,160,102,170,102,180,102,190,102,248,103, 2,103, 22,103, 46,103, 70,103, 96,103,104,
+103,144,103,168,103,180,103,188,103,202,103,216,103,230,103,242,104, 0,104, 12,104, 24,104, 32,104, 40,104, 68,104,122,104,130,
+104,138,104,146,104,234,104,242,104,250,105, 44,105, 52,105, 60,105,108,105,116,105,124,105,132,105,194,105,202,105,210,105,218,
+105,226,106, 44,106,132,106,150,106,168,106,180,106,192,106,204,106,216,106,228,107,144,107,228,108, 36,108,150,108,254,109, 80,
+109,142,109,234,110, 18,110, 82,110,148,110,156,110,228,111, 66,111, 74,111,136,111,210,112, 40,112,116,112,164,112,234,113, 78,
+113,184,114, 2,114, 80,114, 92,114,104,114,116,114,128,114,140,114,228,115, 40,115, 92,115,106,115,118,115,218,116, 16,116, 96,
+116,150,116,200,117, 2,117, 56,117, 64,117,118,117,164,117,186,117,248,118, 38,118,134,118,200,118,252,119, 40,119,102,119,218,
+120, 22,120, 78,120,168,121, 2,121, 76,121,152,121,182,121,210,122, 26,122, 80,122, 88,122, 96,122,154,122,210,123, 8,123, 16,
+123, 24,123, 32,123, 62,123, 92,123,148,123,156,123,168,123,180,123,192,123,204,123,250,124, 6,124, 96,124,104,124,112,124,130,
+124,138,124,196,124,246,125, 26,125, 38,125, 50,125, 62,125, 86,125, 94,125,158,125,166,125,194,126, 10,126, 18,126,118,126,126,
+126,212,126,224,126,232,127, 26,127, 34,127, 42,127, 50,127, 86,127, 94,127,102,127,110,127,178,128, 18,128, 26,128, 70,128,118,
+128,162,128,216,129, 24,129, 44,129,102,129,192,130, 32,130,116,130,124,130,234,131, 64,131, 92,131,162,131,170,132, 14,132,116,
+132,172,132,184,132,246,133, 40,133,108,133,152,133,160,133,200,133,208,133,216,133,254,134, 6,134,142,134,150,134,194,134,242,
+135, 30,135, 84,135,150,135,170,135,230,136, 22,136,110,136,200,136,212,136,224,137, 26,137, 38,137,114,137,122,137,130,137,148,
+137,156,137,214,138, 10,138, 56,138, 68,138, 80,138, 92,138,116,138,196,138,204,138,212,139, 8,139, 80,139,136,139,172,139,208,
+140, 0,140, 48,140,100,140,152,140,214,141, 18,141,124,141,240,141,248,142, 0,142, 66,142,132,142,172,143,114,143,170,143,182,
+143,190,143,198,144, 66,144,184,144,196,144,208,145, 50,145,118,145,164,145,206,146, 0,146, 76,146,108,146,126,146,144,146,190,
+147, 28,147, 58,147,108,147,156,147,208,147,254,148, 58,148, 90,148,122,148,148,148,174,148,218,149, 10,149, 58,149,106,149,118,
+149,130,149,162,149,192,149,230,150, 10,150, 46,150, 82,150,114,150,144,150,174,150,204,150,232,151, 4,151, 52,151,102,151,200,
+152, 38,152, 50,152, 62,152, 86,152,110,152,118,152,142,152,174,152,206,152,242,153, 22,153, 52,153, 82,153,118,153,154,153,194,
+153,232,154, 8,154, 16,154, 88,154,156,154,168,154,180,154,188,154,206,154,224,155, 14,155, 64,155,102,155,144,155,182,155,218,
+155,248,156, 22,156, 58,156, 94,156,132,156,170,156,192,156,208,156,232,157, 4,157, 12,157, 20,157, 38,157, 56,157, 64,157, 72,
+157, 84,157, 96,157,114,157,126,157,138,157,150,157,158,157,166,157,178,157,190,157,202,157,214,157,238,158, 4,158, 12,158, 20,
+158, 32,158, 44,158, 56,158, 68,158, 80,158, 92,158,104,158,116,158,128,158,140,158,152,158,164,158,186,158,208,158,220,158,232,
+159, 18,159, 60,159,136,159,206,160, 30,160,108,160,170,160,232,161, 32,161, 86,161, 94,161,140,161,148,161,156,161,198,161,240,
+162, 36,162, 86,162,150,162,200,162,250,163, 64,163,110,163,160,163,244,164, 52,164, 86,164,116,164,162,164,240,165, 18,165, 54,
+165,144,165,192,166, 2,166, 52,166,120,166,170,166,226,167, 4,167, 60,167,102,167,174,167,224,167,232,168, 24,168, 32,168, 66,
+168,154,168,190,168,198,169, 30,169, 38,169,114,169,122,169,130,169,144,169,176,169,184,169,222,169,240,170, 88,170,158,170,242,
+171, 54,171,128,171,210,172, 10,172, 76,172,200,173, 22,173, 82,173,114,173,226,174, 92,174,154,174,162,175, 34,175,100,175,218,
+176, 58,176, 66,176,154,176,250,177, 2,177,104,177,112,177,228,178, 70,178, 78,178,144,178,252,179, 58,179, 66,179, 96,179,206,
+180, 50,180, 58,180,204,181, 12,181, 44,181, 70,181, 86,181, 98,181,110,181,122,181,134,181,146,181,158,181,170,181,182,181,196,
+181,208,181,220,181,232,181,244,182, 0,182, 12,182, 24,182, 36,182, 48,182, 60,182, 72,182, 84,182, 96,182,108,182,120,182,132,
+182,144,182,156,182,168,182,186,182,202,182,214,182,226,182,238,182,250,183, 6,183, 18,183, 30,183, 42,183, 54,183, 66,183, 78,
+183, 90,183,102,183,114,183,126,183,140,183,152,183,164,183,178,183,190,183,202,183,214,183,226,183,238,183,250,184, 6,184, 22,
+184, 34,184, 46,184, 60,184, 72,184, 84,184, 98,184,110,184,122,184,134,184,146,184,158,184,170,184,182,184,194,184,206,184,218,
+184,230,184,242,184,254,185, 10,185, 22,185, 34,185, 50,185, 62,185, 74,185, 86,185, 98,185,112,185,124,185,136,185,148,185,160,
+185,172,185,184,185,196,185,210,185,222,185,234,185,246,186, 2,186, 14,186, 26,186, 38,186, 56,186, 72,186, 84,186, 96,186,108,
+186,120,186,132,186,144,186,156,186,168,186,180,186,194,186,206,186,218,186,230,186,242,186,254,187, 10,187, 22,187, 34,187, 46,
+187, 58,187, 70,187, 82,187, 94,187,106,187,118,187,130,187,142,187,154,187,166,187,178,187,190,187,202,187,214,187,226,187,238,
+187,250,188, 6,188, 18,188, 30,188, 42,188, 54,188, 66,188, 80,188, 92,188,104,188,116,188,128,188,140,188,152,188,164,188,176,
+188,188,188,200,188,212,188,224,188,236,188,248,189, 4,189, 16,189, 28,189, 40,189, 52,189, 64,189, 76,189, 88,189,100,189,112,
+189,124,189,136,189,148,189,160,189,172,189,184,189,196,189,208,189,220,189,232,189,244,190, 0,190, 12,190, 24,190, 36,190, 50,
+190, 62,190, 74,190, 86,190, 98,190,110,190,122,190,134,190,146,190,158,190,170,190,186,190,198,190,210,190,222,190,234,190,246,
+191, 2,191, 14,191, 26,191, 38,191, 50,191, 62,191, 74,191, 86,191, 98,191,110,191,122,191,134,191,150,191,162,191,174,191,186,
+191,198,191,210,191,222,191,234,191,246,192, 2,192, 14,192, 26,192, 38,192, 50,192, 62,192, 74,192, 86,192, 98,192,110,192,122,
+192,134,192,146,192,158,192,170,192,182,192,194,192,206,192,218,192,230,192,242,192,254,193, 12,193, 24,193, 80,193, 88,193,142,
+193,142,193,142,193,142,193,142,193,142,193,142,193,142,193,142,193,142,193,142,193,142,193,142,193,142,193,142,193,142,193,142,
+193,164,193,172,193,194,193,216,193,236,194, 0,194, 12,194, 24,194, 54,194, 84,194,112,194,130,194,176,194,222,195, 12,195, 38,
+195, 82,195,148,195,180,195,194,195,206,195,224,196, 10,196, 22,196,220,197,100,197,116,197,128,197,144,197,158,197,170,197,186,
+197,204,198, 4,198, 62,198, 86,198,100,198,162,198,172,198,220,199, 12,199, 34,199, 52,199, 64,199,100,199,124,199,148,199,160,
+199,172,199,186,199,220,199,248,200, 16,200, 40,200, 50,200, 72,200, 84,200, 98,200,116,200,124,200,134,200,176,200,202,200,222,
+200,254,201, 36,201, 54,201, 84,201,134,201,158,201,188,201,230,202, 8,202,142,202,192,203, 8,203, 28,203,116,203,186,203,212,
+203,226,203,246,204, 18,204, 48,204,106,204,116,204,126,204,136,204,146,204,156,204,166,204,176,204,186,204,196,204,206,204,216,
+204,226,204,236,204,246,205, 0,205, 58,205,146,205,218,205,250,206, 46,206,112,206,178,207, 36,207,140,207,226,208, 20,208, 32,
+208,250,209, 30,209, 74,209,174,209,250,210, 74,210,148,210,168,210,188,211, 28,211, 42,211,190,212, 12,212, 88,212,100,212,146,
+212,198,213, 16,213, 80,213, 92,213,176,214, 10,214,136,214,222,215,106,215,186,215,234,216, 48,216, 56,216,112,216,120,216,128,
+216,196,216,218,217, 4,217, 88,217,154,217,232,217,248,218, 8,218, 24,218, 40,218, 56,218, 72,218, 88,218,104,218,120,218,136,
+218,152,218,168,218,180,218,188,218,200,218,216,218,228,218,236,218,248,219, 8,219, 28,219, 40,219, 48,219, 60,219, 76,219, 84,
+219, 92,219,100,219,108,219,116,219,128,219,144,219,156,219,164,219,176,219,192,219,212,219,224,219,232,219,244,220, 4,220, 12,
+220, 20,220, 28,220, 36,220,102,221, 36,221,146,221,154,221,242,222, 74,222,162,222,250,223,138,224, 28,224, 52,224, 76,224,100,
+224,124,224,152,224,174,224,204,225, 22,225, 58,225, 68,225, 78,225, 88,225,110,225,158,225,170,225,182,225,242,226,184,227, 54,
+227, 72,227,100,227,120,227,140,228, 68,229, 70,230,142,231, 86,232, 92,233,142,234, 74,235,200,236,252,238, 50,238, 74,238,126,
+238,126,238,214,239, 32,239, 96,239,208,240, 48,240,112,240,236,241, 84,241,168,241,246,242, 78,242,178,242,248,242,248,242,248,
+242,248,242,248,242,248,242,248,242,248,242,248,242,248,242,248,242,248,242,248,242,248,242,248,242,248,242,248,242,248,242,248,
+242,248,242,248,242,248,242,248,242,248,242,248,242,248,242,248,242,248,242,248,242,248,242,248,242,248,242,248, 0, 2, 0,102,
+254,150, 4,102, 5,164, 0, 3, 0, 7, 0, 26, 64, 12, 4,251, 0, 6,251, 1, 8, 5,127, 2, 4, 0, 47,196,212,236, 49, 0,
+ 16,212,236,212,236, 48, 19, 17, 33, 17, 37, 33, 17, 33,102, 4, 0,252,115, 3, 27,252,229,254,150, 7, 14,248,242,114, 6, 41,
+ 0, 2, 1, 53, 0, 0, 2, 0, 5,213, 0, 3, 0, 9, 0, 53, 64, 15, 7, 0,131, 4,129, 2, 8, 7, 5, 1, 3, 4, 0, 0,
+ 10, 16,252, 75,176, 11, 84, 88,185, 0, 0,255,192, 56, 89, 60,236, 50, 57, 57, 49, 0, 47,228,252,204, 48, 1,182, 0, 11, 32,
+ 11, 80, 11, 3, 93, 37, 51, 21, 35, 17, 51, 17, 3, 35, 3, 1, 53,203,203,203, 20,162, 21,254,254, 5,213,253,113,254,155, 1,
+101, 0, 0, 0, 0, 2, 0,197, 3,170, 2,233, 5,213, 0, 3, 0, 7, 0, 66, 64, 15, 5, 1,132, 4, 0,129, 8, 4, 5, 6,
+ 0, 5, 2, 4, 8, 16,252, 75,176, 18, 84, 75,176, 19, 84, 91, 88,185, 0, 2,255,192, 56, 89,252,220,236, 49, 0, 16,244, 60,
+236, 50, 48, 1, 64, 15, 48, 9, 64, 9, 80, 9, 96, 9,112, 9,160, 9,191, 9, 7, 93, 1, 17, 35, 17, 33, 17, 35, 17, 1,111,
+170, 2, 36,170, 5,213,253,213, 2, 43,253,213, 2, 43, 0, 0, 0, 2, 0,158, 0, 0, 6, 23, 5,190, 0, 3, 0, 31, 0, 96,
+ 64, 49, 27, 11, 0,135, 7, 4, 29, 9, 5, 25, 13, 2,135, 23, 19, 15, 21, 17, 31, 30, 28, 27, 26, 23, 22, 21, 20, 19, 18, 17,
+ 16, 14, 13, 12, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 26, 10, 24, 6, 32, 16,252,204, 23, 57, 49, 0, 47, 60,212, 60, 60,252,
+ 60, 60,212, 60, 60,196, 50,236, 50, 50, 48, 64, 17, 11, 1, 11, 2, 11, 12, 11, 13, 20, 4, 26, 17, 26, 18, 20, 31, 8, 1, 93,
+ 1, 33, 3, 33, 11, 1, 33, 19, 51, 3, 33, 21, 33, 3, 33, 21, 33, 3, 35, 19, 33, 3, 35, 19, 33, 53, 33, 19, 33, 53, 33, 19,
+ 4, 23,254,221, 84, 1, 37, 68,104, 1, 36,105,160,103, 1, 56,254,161, 82, 1, 62,254,155,104,160,103,254,219,103,161,104,254,
+197, 1, 96, 84,254,190, 1,105,102, 3,133,254,178, 3,135,254, 97, 1,159,254, 97,154,254,178,153,254, 98, 1,158,254, 98, 1,
+158,153, 1, 78,154, 1,159, 0, 0, 3, 0,170,254,211, 4,109, 6, 20, 0, 33, 0, 40, 0, 47, 0,189, 64, 85, 34, 2, 10, 11,
+ 10, 39, 1, 38, 40, 2, 11, 11, 10, 29, 1, 30, 28, 2, 47, 41, 47, 27, 2, 41, 41, 47, 66, 19, 17, 16, 34, 10, 27, 41, 4, 23,
+ 6, 9, 42, 33, 5, 2, 23,134, 22, 6,134, 5, 17, 35, 26,138, 22,137, 16, 0, 42,138, 5,137, 2, 45, 8, 22, 10, 30, 7, 41,
+ 26, 18, 3, 0, 9, 34, 16, 9, 3, 1, 7, 38, 8, 13, 5, 6, 48, 16,252, 75,176, 9, 84, 88,185, 0, 5,255,192, 56, 89, 75,
+176, 12, 84, 75,176, 16, 84, 91, 75,176, 15, 84, 91, 88,185, 0, 5, 0, 64, 56, 89, 60,236,244, 23, 60,252, 23, 60,244,228,236,
+ 49, 0, 47,228,236,196,212,228,236, 50,196, 16,238, 16,238, 17, 18, 57, 17, 57, 17, 18, 23, 57, 17, 18, 57, 48, 75, 83, 88, 7,
+ 16, 4,237, 7, 16, 14,237, 17, 23, 57, 7, 16, 14,237, 17, 23, 57, 7, 16, 4,237, 89, 34, 1, 35, 3, 46, 1, 39, 53, 30, 1,
+ 23, 17, 46, 1, 53, 52, 54, 55, 53, 51, 21, 30, 1, 23, 21, 46, 1, 39, 17, 30, 1, 21, 20, 6, 7, 3, 17, 14, 1, 21, 20, 22,
+ 23, 17, 62, 1, 53, 52, 38, 2,180,100, 1,105,210,106,102,209,111,221,201,218,204,100, 93,174, 83, 83,175, 92,227,214,227,214,
+100,116,122,113,225,127,129,123,254,211, 1, 45, 2, 45, 45,180, 64, 65, 1, 1,200, 36,172,150,163,188, 14,235,232, 4, 31, 27,
+175, 42, 46, 4,254, 85, 35,180,156,169,195, 15, 3, 0, 1,154, 13,106, 88, 86, 96,213,254, 79, 17,110, 90, 88,104, 0, 0, 0,
+ 0, 5, 0,113,255,227, 7, 41, 5,240, 0, 11, 0, 23, 0, 35, 0, 39, 0, 51, 0,137, 64, 54, 36, 15, 37, 38, 37, 38, 15, 39,
+ 36, 39, 66, 0,146, 12, 30,146, 46,141, 24,146, 36, 6,146, 12,141, 38, 18,140, 40, 36,145, 52, 39, 33, 27, 37, 9, 3, 13, 21,
+ 14, 9, 13, 15, 33, 13, 43, 14, 27, 13, 15, 49, 11, 52, 16,252, 75,176, 9, 84, 75,176, 11, 84, 91, 75,176, 12, 84, 91, 75,176,
+ 20, 84, 91, 75,176, 14, 84, 91, 75,176, 13, 84, 91, 88,185, 0, 49,255,192, 56, 89,196,236,244,236, 16,238,246,238, 17, 57, 17,
+ 18, 57, 49, 0, 16,228, 50,244, 60,228,236, 16,238,246,238, 16,238, 48, 75, 83, 88, 7, 16, 5,237, 7, 16, 5,237, 89, 34, 1,
+ 34, 6, 21, 20, 22, 51, 50, 54, 53, 52, 38, 39, 50, 22, 21, 20, 6, 35, 34, 38, 53, 52, 54, 1, 34, 6, 21, 20, 22, 51, 50, 54,
+ 53, 52, 38, 37, 51, 1, 35, 19, 50, 22, 21, 20, 6, 35, 34, 38, 53, 52, 54, 5,209, 87, 99, 99, 87, 85, 99, 99, 85,158,186,187,
+157,160,186,187,252,151, 86, 99, 98, 87, 87, 99,100, 3, 49,160,252, 90,160, 31,158,188,187,159,159,185,186, 2,145,148,132,130,
+149,149,130,131,149,127,220,187,187,219,219,187,188,219, 2, 97,149,130,132,148,148,132,129,150,127,249,243, 6, 13,219,187,189,
+218,219,188,186,220, 0, 0, 0, 0, 2, 0,129,255,227, 5,254, 5,240, 0, 9, 0, 48, 1,205, 64,150, 13, 1, 14, 12,134, 17,
+ 18, 17, 11,134, 10, 11, 18, 18, 17, 9,134, 0, 9, 21, 22, 21, 7, 1, 6, 8,134, 22, 22, 21, 2, 1, 3, 1,134, 29, 30, 29,
+ 0,134, 9, 0, 30, 30, 29, 32, 31, 2, 33, 30, 17, 10, 19, 10, 23, 22, 21, 3, 24, 20, 17, 19, 10, 7, 8, 2, 6, 9, 17, 19,
+ 19, 10, 2, 1, 2, 3, 0, 17, 10, 19, 10, 23, 22, 2, 24, 21, 17, 19, 10, 20, 17, 19, 19, 10, 66, 18, 11, 9, 3, 6, 0, 10,
+ 30, 3, 40, 21, 14, 6, 40, 39, 6,149, 24, 43,149, 39,148, 36,145, 24,140, 14, 19, 10, 46, 11, 14, 9, 0, 46, 18, 21, 39, 14,
+ 30, 3, 46, 18, 39, 33, 14, 17, 15, 19, 33, 3, 18, 27, 16, 49, 16,252,236,196,212,212,236, 16,198,238, 17, 57, 17, 18, 57, 57,
+ 17, 57, 57, 17, 57, 17, 57, 49, 0, 47,198,228,246,230,238, 16,238, 16,198, 17, 18, 57, 17, 23, 57, 17, 23, 57, 48, 75, 83, 88,
+ 7, 16, 5,237, 7, 5,237, 17, 23, 57, 7, 16, 5,237, 17, 23, 57, 7, 16, 5,237, 17, 23, 57, 7, 5,237, 17, 23, 57, 7, 16,
+ 5,237, 17, 23, 57, 7, 16, 8,237, 7, 16, 14,237, 17, 23, 57, 7, 16, 14,237, 17, 23, 57, 7, 16, 8,237, 7, 16, 8,237, 7,
+ 16, 14,237, 17, 23, 57, 89, 34,178, 15, 50, 1, 1, 93, 64,178, 7, 11, 5, 34, 9, 41, 28, 0, 28, 1, 31, 2, 23, 11, 42, 0,
+ 42, 1, 38, 18, 58, 0, 52, 18, 68, 11, 94, 0, 89, 1, 90, 10, 85, 18, 90, 26, 90, 31, 89, 48,103, 30,123, 0,155, 0,154, 1,
+153, 2,151, 8,149, 11,147, 21,149, 22,149, 34,153, 45, 31, 9, 11, 9, 12, 8, 17, 12, 39, 12, 40, 24, 2, 27, 9, 25, 11, 25,
+ 12, 25, 17, 28, 20, 28, 21, 22, 29, 31, 50, 39, 0, 39, 1, 41, 9, 35, 18, 42, 19, 42, 20, 40, 21, 47, 50, 59, 9, 52, 18, 57,
+ 19, 63, 50, 74, 9, 76, 20, 75, 21, 70, 25, 79, 50, 86, 1, 90, 9, 89, 12, 85, 18, 89, 19, 92, 31, 95, 50,106, 12,105, 17, 96,
+ 50,117, 1,121, 12,122, 17,147, 0,147, 1,151, 2,149, 5,156, 7,156, 8,159, 8,154, 9,155, 11,154, 12,144, 50,160, 50,176,
+ 50, 57, 93, 0, 93, 1, 14, 1, 21, 20, 22, 51, 50, 54, 55, 9, 1, 62, 1, 55, 51, 6, 2, 7, 1, 35, 39, 14, 1, 35, 34, 0,
+ 53, 52, 54, 55, 46, 1, 53, 52, 54, 51, 50, 22, 23, 21, 46, 1, 35, 34, 6, 21, 20, 22, 1,242, 91, 85,212,160, 95,166, 73,254,
+123, 1,252, 59, 66, 6,186, 12,104, 93, 1, 23,252,143,104,228,131,241,254,206,134,134, 48, 50,222,184, 83,165, 85, 87,158, 68,
+105,131, 59, 3, 35, 81,161, 88,146,194, 63, 64, 2,143,253,248, 89,203,114,132,254,254,126,254,227,147, 89, 87, 1, 19,215,128,
+225, 99, 63,125, 60,162,197, 36, 36,182, 47, 49,111, 88, 51,103, 0, 1, 0,197, 3,170, 1,111, 5,213, 0, 3, 0, 55, 64, 10,
+ 1,132, 0,129, 4, 0, 5, 2, 4, 4, 16,252, 75,176, 18, 84, 75,176, 19, 84, 91, 88,185, 0, 2,255,192, 56, 89,236, 49, 0,
+ 16,244,236, 48, 1, 64, 13, 64, 5, 80, 5, 96, 5,112, 5,144, 5,160, 5, 6, 93, 1, 17, 35, 17, 1,111,170, 5,213,253,213,
+ 2, 43, 0, 0, 0, 1, 0,176,254,242, 2,123, 6, 18, 0, 13, 0, 55, 64, 15, 6,152, 0,151, 14, 13, 7, 0, 3, 18, 6, 0,
+ 19, 10, 14, 16,220, 75,176, 19, 84, 88,185, 0, 10,255,192, 56, 89, 75,176, 15, 84, 88,185, 0, 10, 0, 64, 56, 89,228, 50,236,
+ 17, 57, 57, 49, 0, 16,252,236, 48, 1, 6, 2, 21, 20, 18, 23, 35, 38, 2, 53, 52, 18, 55, 2,123,134,130,131,133,160,150,149,
+148,151, 6, 18,230,254, 62,231,231,254, 59,229,235, 1,198,224,223, 1,196,236, 0, 1, 0,164,254,242, 2,111, 6, 18, 0, 13,
+ 0, 31, 64, 15, 7,152, 0,151, 14, 7, 1, 0, 11, 18, 4, 19, 8, 0, 14, 16,220, 60,244,236, 17, 57, 57, 49, 0, 16,252,236,
+ 48, 19, 51, 22, 18, 21, 20, 2, 7, 35, 54, 18, 53, 52, 2,164,160,150,149,149,150,160,133,131,131, 6, 18,236,254, 60,223,224,
+254, 58,235,229, 1,197,231,231, 1,194, 0, 0, 0, 1, 0, 61, 2, 74, 3,195, 5,240, 0, 17, 0, 78, 64, 44, 16, 13, 11, 0,
+ 4, 12, 9, 7, 4, 2, 4, 8, 3,153, 5, 17, 12,153, 10, 1, 14,145, 18, 8, 12, 10, 3, 9, 6, 17, 3, 1, 3, 2, 0, 20,
+ 15, 4, 11, 9, 20, 13, 6, 18, 16,212, 60,228, 50,220, 60,228, 50, 23, 57, 17, 18, 23, 57, 49, 0, 16,244,212, 60,236, 50,196,
+236, 50, 23, 57, 18, 23, 57, 48, 1, 13, 1, 7, 37, 17, 35, 17, 5, 39, 45, 1, 55, 5, 17, 51, 17, 37, 3,195,254,153, 1,103,
+ 58,254,176,114,254,176, 58, 1,103,254,153, 58, 1, 80,114, 1, 80, 4,223,194,195, 98,203,254,135, 1,121,203, 98,195,194, 99,
+203, 1,121,254,135,203, 0, 0, 0, 1, 0,217, 0, 0, 5,219, 5, 4, 0, 11, 0, 35, 64, 17, 0, 9, 1,156, 7, 3, 5, 2,
+ 21, 4, 0, 23, 10, 6, 21, 8, 12, 16,220,252, 60,252, 60,236, 49, 0, 47,212, 60,252, 60,196, 48, 1, 17, 33, 21, 33, 17, 35,
+ 17, 33, 53, 33, 17, 3,174, 2, 45,253,211,168,253,211, 2, 45, 5, 4,253,211,170,253,211, 2, 45,170, 2, 45, 0, 1, 0,158,
+255, 18, 1,195, 0,254, 0, 5, 0, 25, 64, 12, 3,158, 0,131, 6, 3, 4, 1, 25, 0, 24, 6, 16,252,236,212,204, 49, 0, 16,
+252,236, 48, 55, 51, 21, 3, 35, 19,240,211,164,129, 82,254,172,254,192, 1, 64, 0, 1, 0,100, 1,223, 2,127, 2,131, 0, 3,
+ 0, 17,182, 0,156, 2, 4, 1, 0, 4, 16,220,204, 49, 0, 16,212,236, 48, 19, 33, 21, 33,100, 2, 27,253,229, 2,131,164, 0,
+ 0, 1, 0,219, 0, 0, 1,174, 0,254, 0, 3, 0, 17,183, 0,131, 2, 1, 25, 0, 24, 4, 16,252,236, 49, 0, 47,236, 48, 55,
+ 51, 21, 35,219,211,211,254,254, 0, 1, 0, 0,255, 66, 2,178, 5,213, 0, 3, 0, 45, 64, 20, 0, 26, 1, 2, 1, 2, 26, 3,
+ 0, 3, 66, 2,159, 0,129, 4, 2, 0, 1, 3, 47,196, 57, 57, 49, 0, 16,244,236, 48, 75, 83, 88, 7, 16, 5,237, 7, 16, 5,
+237, 89, 34, 1, 51, 1, 35, 2, 8,170,253,248,170, 5,213,249,109, 0, 0, 0, 0, 2, 0,135,255,227, 4,143, 5,240, 0, 11,
+ 0, 23, 0, 35, 64, 19, 6,160, 18, 0,160, 12,145, 18,140, 24, 9, 28, 15, 30, 3, 28, 21, 27, 24, 16,252,236,244,236, 49, 0,
+ 16,228,244,236, 16,238, 48, 1, 34, 2, 17, 16, 18, 51, 50, 18, 17, 16, 2, 39, 50, 0, 17, 16, 0, 35, 34, 0, 17, 16, 0, 2,
+139,156,157,157,156,157,157,157,157,251, 1, 9,254,247,251,251,254,247, 1, 9, 5, 80,254,205,254,204,254,205,254,205, 1, 51,
+ 1, 51, 1, 52, 1, 51,160,254,115,254,134,254,135,254,115, 1,141, 1,121, 1,122, 1,141, 0, 0, 1, 0,225, 0, 0, 4, 90,
+ 5,213, 0, 10, 0, 64, 64, 21, 66, 3,160, 4, 2,160, 5,129, 7, 0,160, 9, 8, 31, 6, 28, 3, 0, 31, 1, 11, 16,212, 75,
+176, 15, 84, 88,185, 0, 1, 0, 64, 56, 89,236,196,252,236, 49, 0, 47,236, 50,244,236,212,236, 48, 75, 83, 88, 89, 34, 1,180,
+ 15, 3, 15, 4, 2, 93, 55, 33, 17, 5, 53, 37, 51, 17, 33, 21, 33,254, 1, 74,254,153, 1,101,202, 1, 74,252,164,170, 4,115,
+ 72,184, 72,250,213,170, 0, 0, 0, 1, 0,150, 0, 0, 4, 74, 5,240, 0, 28, 0,154, 64, 39, 25, 26, 27, 3, 24, 28, 17, 5,
+ 4, 0, 17, 5, 5, 4, 66, 16,161, 17,148, 13,160, 20,145, 4, 0,160, 2, 0, 16, 10, 2, 1, 10, 28, 23, 16, 3, 6, 29, 16,
+252, 75,176, 21, 84, 75,176, 22, 84, 91, 75,176, 20, 84, 91, 88,185, 0, 3,255,192, 56, 89,196,212,236,192,192, 17, 18, 57, 49,
+ 0, 47,236, 50,244,236,244,236, 48, 75, 83, 88, 7, 16, 5,237, 7, 5,237, 17, 23, 57, 89, 34, 1, 64, 50, 85, 4, 86, 5, 86,
+ 7,122, 4,122, 5,118, 27,135, 25, 7, 4, 0, 4, 25, 4, 26, 4, 27, 5, 28,116, 0,118, 6,117, 26,115, 27,116, 28,130, 0,
+134, 25,130, 26,130, 27,130, 28,168, 0,168, 27, 17, 93, 0, 93, 37, 33, 21, 33, 53, 54, 0, 55, 62, 1, 53, 52, 38, 35, 34, 6,
+ 7, 53, 62, 1, 51, 50, 4, 21, 20, 6, 7, 6, 0, 1,137, 2,193,252, 76,115, 1,141, 51, 97, 77,167,134, 95,211,120,122,212,
+ 88,232, 1, 20, 69, 91, 25,254,244,170,170,170,119, 1,145, 58,109,151, 73,119,150, 66, 67,204, 49, 50,232,194, 92,165,112, 29,
+254,235, 0, 0, 0, 1, 0,156,255,227, 4,115, 5,240, 0, 40, 0,112, 64, 46, 0, 21, 19, 10,134, 9, 31,134, 32, 19,160, 21,
+ 13,160, 9,147, 6, 28,160, 32,147, 35,145, 6,140, 21,163, 41, 22, 28, 19, 0, 3, 20, 25, 28, 38, 32, 16, 28, 3, 20, 31, 9,
+ 6, 41, 16,252, 75,176, 22, 84, 75,176, 20, 84, 91, 88,185, 0, 9,255,192, 56, 89,196,196,212,236,244,236, 17, 23, 57, 57, 49,
+ 0, 16,236,228,244,228,236, 16,230,238, 16,238, 16,238, 16,238, 17, 18, 57, 48, 1, 64, 9,100, 30, 97, 31, 97, 32,100, 33, 4,
+ 0, 93, 1, 30, 1, 21, 20, 4, 33, 34, 38, 39, 53, 30, 1, 51, 50, 54, 53, 52, 38, 43, 1, 53, 51, 50, 54, 53, 52, 38, 35, 34,
+ 6, 7, 53, 62, 1, 51, 50, 4, 21, 20, 6, 3, 63,145,163,254,208,254,232, 94,199,106, 84,200,109,190,199,185,165,174,182,149,
+158,163,152, 83,190,114,115,201, 89,230, 1, 12,142, 3, 37, 31,196,144,221,242, 37, 37,195, 49, 50,150,143,132,149,166,119,112,
+115,123, 36, 38,180, 32, 32,209,178,124,171, 0, 0, 2, 0,100, 0, 0, 4,164, 5,213, 0, 2, 0, 13, 0,129, 64, 29, 1, 13,
+ 3, 13, 0, 3, 3, 13, 66, 0, 3, 11, 7,160, 5, 1, 3,129, 9, 1, 12, 10, 0, 28, 6, 8, 4, 12, 14, 16,220, 75,176, 11,
+ 84, 75,176, 13, 84, 91, 88,185, 0, 12,255,192, 56, 89,212, 60,196,236, 50, 17, 57, 49, 0, 47,228,212, 60,236, 50, 18, 57, 48,
+ 75, 83, 88, 7, 16, 4,201, 7, 16, 5,201, 89, 34, 1, 64, 42, 11, 0, 42, 0, 72, 0, 89, 0,105, 0,119, 0,138, 0, 7, 22,
+ 1, 43, 0, 38, 1, 43, 3, 54, 1, 78, 1, 79, 12, 79, 13, 86, 1,102, 1,117, 1,122, 3,133, 1, 13, 93, 0, 93, 9, 1, 33,
+ 3, 51, 17, 51, 21, 35, 17, 35, 17, 33, 53, 3, 6,254, 2, 1,254, 53,254,213,213,201,253, 94, 5, 37,252,227, 3,205,252, 51,
+168,254,160, 1, 96,195, 0, 0, 0, 1, 0,158,255,227, 4,100, 5,213, 0, 29, 0, 94, 64, 35, 4, 26, 7, 17,134, 16, 29, 26,
+160, 7, 20,160, 16,137, 13, 2,160, 0,129, 13,140, 7,164, 30, 23, 28, 1, 10, 3, 28, 0, 10, 16, 6, 30, 16,252, 1, 75,176,
+ 22, 84, 75,176, 20, 84, 91, 88,185, 0, 16,255,192, 56, 89, 75,176, 15, 84, 88,185, 0, 16, 0, 64, 56, 89,196,212,236, 16,196,
+238, 49, 0, 16,228,228,244,236, 16,230,238, 16,254,196, 16,238, 17, 18, 57, 48, 19, 33, 21, 33, 17, 62, 1, 51, 50, 0, 21, 20,
+ 0, 33, 34, 38, 39, 53, 30, 1, 51, 50, 54, 53, 52, 38, 35, 34, 6, 7,221, 3, 25,253,160, 44, 88, 44,250, 1, 36,254,212,254,
+239, 94,195,104, 90,192,107,173,202,202,173, 81,161, 84, 5,213,170,254,146, 15, 15,254,238,234,241,254,245, 32, 32,203, 49, 48,
+182,156,156,182, 36, 38, 0, 0, 0, 2, 0,143,255,227, 4,150, 5,240, 0, 11, 0, 36, 0, 88, 64, 36, 19, 6, 0, 13,134, 12,
+ 0,160, 22, 6,160, 28, 22,165, 16,160, 12,137, 34,145, 28,140, 37, 12, 34, 9, 28, 25, 30, 19, 28, 3, 33, 31, 27, 37, 16,252,
+236,236,244,236,228, 49, 0, 16,228,244,228,252,228, 16,238, 16,238, 16,238, 17, 18, 57, 48, 64, 20,203, 0,203, 1,205, 2,205,
+ 3,205, 4,203, 5,203, 6, 7,164, 30,178, 30, 2, 93, 1, 93, 1, 34, 6, 21, 20, 22, 51, 50, 54, 53, 52, 38, 1, 21, 46, 1,
+ 35, 34, 2, 3, 62, 1, 51, 50, 0, 21, 20, 0, 35, 32, 0, 17, 16, 0, 33, 50, 22, 2,164,136,159,159,136,136,159,159, 1, 9,
+ 76,155, 76,200,211, 15, 59,178,107,225, 1, 5,254,240,226,254,253,254,238, 1, 80, 1, 27, 76,155, 3, 59,186,162,161,187,187,
+161,162,186, 2,121,184, 36, 38,254,242,254,239, 87, 93,254,239,235,230,254,234, 1,141, 1,121, 1, 98, 1,165, 30, 0, 0, 0,
+ 0, 1, 0,168, 0, 0, 4,104, 5,213, 0, 6, 0, 99, 64, 24, 5, 17, 2, 3, 2, 3, 17, 4, 5, 4, 66, 5,160, 0,129, 3,
+ 5, 3, 1, 4, 1, 0, 6, 7, 16,252,204,196, 17, 57, 57, 49, 0, 47,244,236, 48, 75, 83, 88, 7, 16, 5,237, 7, 16, 5,237,
+ 89, 34, 1, 75,176, 22, 84, 88,189, 0, 7, 0, 64, 0, 1, 0, 7, 0, 7,255,192, 56, 17, 55, 56, 89, 64, 18, 88, 2, 1, 6,
+ 3, 26, 5, 57, 5, 72, 5,103, 3,176, 0,176, 6, 7, 93, 0, 93, 19, 33, 21, 1, 35, 1, 33,168, 3,192,253,226,211, 1,254,
+253, 51, 5,213, 86,250,129, 5, 43, 0, 0, 0, 0, 3, 0,139,255,227, 4,139, 5,240, 0, 11, 0, 35, 0, 47, 0, 67, 64, 37,
+ 24, 12, 0,160, 39, 6,160, 30, 45,160, 18,145, 30,140, 39,163, 48, 24, 12, 36, 42, 28, 21, 36, 28, 15, 9, 28, 21, 27, 30, 3,
+ 28, 15, 33, 27, 48, 16,252,196,236,244,196,236, 16,238, 16,238, 17, 57, 57, 49, 0, 16,236,228,244,236, 16,238, 16,238, 57, 57,
+ 48, 1, 34, 6, 21, 20, 22, 51, 50, 54, 53, 52, 38, 37, 46, 1, 53, 52, 36, 51, 50, 22, 21, 20, 6, 7, 30, 1, 21, 20, 4, 35,
+ 34, 36, 53, 52, 54, 19, 20, 22, 51, 50, 54, 53, 52, 38, 35, 34, 6, 2,139,144,165,165,144,144,166,165,254,165,130,145, 0,255,
+222,223,254,145,129,146,163,254,247,247,247,254,247,164, 72,145,131,130,147,147,130,131,145, 2,197,154,135,135,154,155,134,135,
+154, 86, 32,178,128,179,208,208,179,128,178, 32, 34,198,143,217,232,232,217,143,198, 1, 97,116,130,130,116,116,130,130, 0, 0,
+ 0, 2, 0,129,255,227, 4,135, 5,240, 0, 24, 0, 36, 0, 88, 64, 35, 7, 31, 25, 1,134, 0, 25,160, 10,165, 4,160, 0,137,
+ 22, 31,160, 16,145, 22,140, 37, 7, 28, 28, 33, 19, 30, 0, 34, 34, 28, 13, 27, 37, 16,252,236,228,244,236,236, 49, 0, 16,228,
+244,236, 16,230,254,245,238, 16,238, 17, 18, 57, 48, 64, 22,196, 25,194, 26,192, 27,192, 28,192, 29,194, 30,196, 31, 7,170, 18,
+188, 18,233, 18, 3, 93, 1, 93, 55, 53, 30, 1, 51, 50, 18, 19, 14, 1, 35, 34, 0, 53, 52, 0, 51, 32, 0, 17, 16, 0, 33, 34,
+ 38, 1, 50, 54, 53, 52, 38, 35, 34, 6, 21, 20, 22,225, 76,156, 75,200,211, 15, 58,178,108,224,254,251, 1, 16,226, 1, 3, 1,
+ 17,254,177,254,229, 76,156, 1, 62,136,159,159,136,136,159,159, 31,184, 36, 38, 1, 13, 1, 18, 86, 92, 1, 15,235,230, 1, 22,
+254,115,254,134,254,159,254, 91, 30, 2,151,186,162,161,187,187,161,162,186, 0, 0, 2, 0,240, 0, 0, 1,195, 4, 35, 0, 3,
+ 0, 7, 0, 28, 64, 14, 6,131, 4,166, 0,131, 2, 5, 1, 3, 4, 0, 24, 8, 16,252, 60,236, 50, 49, 0, 47,236,244,236, 48,
+ 55, 51, 21, 35, 17, 51, 21, 35,240,211,211,211,211,254,254, 4, 35,254, 0, 0, 0, 2, 0,158,255, 18, 1,195, 4, 35, 0, 3,
+ 0, 9, 0, 37, 64, 19, 2,131, 0, 7,158, 4,131, 0,166, 10, 7, 8, 5, 1, 25, 4, 0, 24, 10, 16,252, 60,236, 50,212,204,
+ 49, 0, 16,228,252,236, 16,238, 48, 19, 51, 21, 35, 17, 51, 21, 3, 35, 19,240,211,211,211,164,129, 82, 4, 35,254,253,217,172,
+254,192, 1, 64, 0, 1, 0,217, 0, 94, 5,219, 4,166, 0, 6, 0, 77, 64, 42, 2,156, 3, 4, 3, 1,156, 0, 1, 4, 4, 3,
+ 1,156, 2, 1, 5, 6, 5, 0,156, 6, 5, 66, 5, 4, 2, 1, 0, 5, 3,168, 6,167, 7, 1, 2, 0, 36, 4, 35, 7, 16,252,
+236, 50, 57, 49, 0, 16,244,236, 23, 57, 48, 75, 83, 88, 7, 4,237, 7, 16, 8,237, 7, 16, 8,237, 7, 16, 4,237, 89, 34, 9,
+ 2, 21, 1, 53, 1, 5,219,251,248, 4, 8,250,254, 5, 2, 3,240,254,145,254,147,182, 1,209,166, 1,209, 0, 0, 2, 0,217,
+ 1, 96, 5,219, 3,162, 0, 3, 0, 7, 0, 28, 64, 13, 0,156, 2, 6,156, 4, 8, 5, 1, 4, 0, 35, 8, 16,252, 60,196, 50,
+ 49, 0, 16,212,236,212,236, 48, 19, 33, 21, 33, 21, 33, 21, 33,217, 5, 2,250,254, 5, 2,250,254, 3,162,168,240,170, 0, 0,
+ 0, 1, 0,217, 0, 94, 5,219, 4,166, 0, 6, 0, 79, 64, 43, 6,156, 0, 6, 3, 4, 3, 5,156, 4, 4, 3, 0,156, 1, 2,
+ 1, 6,156, 5, 6, 2, 2, 1, 66, 6, 5, 3, 2, 0, 5, 4,168, 1,167, 7, 6, 2, 36, 4, 0, 35, 7, 16,252, 60,236, 57,
+ 49, 0, 16,244,236, 23, 57, 48, 75, 83, 88, 7, 16, 8,237, 7, 16, 4,237, 7, 16, 4,237, 7, 16, 8,237, 89, 34, 19, 53, 1,
+ 21, 1, 53, 1,217, 5, 2,250,254, 4, 6, 3,240,182,254, 47,166,254, 47,182, 1,109, 0, 0, 0, 2, 0,147, 0, 0, 3,176,
+ 5,240, 0, 3, 0, 36, 0,101, 64, 43, 36, 30, 9, 6, 4, 10, 29, 19, 4, 0, 20,134, 19,136, 16,149, 23,145, 0,131, 2, 29,
+ 26, 13, 9, 5, 4, 10, 30, 1, 13, 28, 26, 4, 28, 5, 1, 3, 0, 38, 26, 19, 37, 16,220, 75,176, 12, 84, 88,185, 0, 19,255,
+192, 56, 89,196,252,236,212,236, 16,238, 17, 57, 57, 17, 18, 57, 17, 18, 57, 49, 0, 47,238,246,254,244,238, 16,205, 17, 57, 57,
+ 23, 57, 48, 1,182,121, 9,122, 10,122, 32, 3, 93, 37, 51, 21, 35, 19, 35, 53, 52, 54, 63, 1, 62, 1, 53, 52, 38, 35, 34, 6,
+ 7, 53, 62, 1, 51, 50, 22, 21, 20, 6, 15, 1, 14, 1, 7, 14, 1, 21, 1,135,203,203,197,191, 56, 90, 90, 57, 51,131,108, 79,
+179, 97, 94,193,103,184,223, 72, 90, 88, 47, 39, 8, 6, 6,254,254, 1,145,154,101,130, 86, 89, 53, 94, 49, 89,110, 70, 67,188,
+ 57, 56,194,159, 76,137, 86, 86, 47, 53, 25, 21, 60, 52, 0, 0, 0, 2, 0,135,254,156, 7,113, 5,162, 0, 11, 0, 76, 0,149,
+ 64, 50, 24, 12, 3, 9,169, 25, 21, 27, 3,169, 76, 15, 52, 51, 15,172, 48,169, 55, 21,172, 36,169, 55, 67, 77, 51, 52, 30, 26,
+ 0, 40, 18, 6, 24, 12, 40, 26, 43, 30, 40, 73, 18, 43, 42, 40, 73, 44, 61, 77, 16,220,236,252,236, 16,254,253,254, 60,198, 16,
+238, 17, 18, 57, 57, 49, 0, 16,212,196,252,236, 16,254,237,212,198, 16,197,238, 50, 16,196,238, 17, 57, 57, 48, 0, 75,176, 9,
+ 84, 75,176, 12, 84, 91, 75,176, 16, 84, 91, 75,176, 19, 84, 91, 75,176, 20, 84, 91, 88,189, 0, 77,255,192, 0, 1, 0, 77, 0,
+ 77, 0, 64, 56, 17, 55, 56, 89, 64, 9, 15, 78, 31, 78, 47, 78, 63, 78, 4, 1, 93, 1, 20, 22, 51, 50, 54, 53, 52, 38, 35, 34,
+ 6, 1, 14, 1, 35, 34, 38, 53, 52, 54, 51, 50, 22, 23, 53, 51, 17, 62, 1, 53, 52, 38, 39, 38, 36, 35, 34, 6, 7, 6, 2, 21,
+ 20, 18, 23, 22, 4, 51, 50, 54, 55, 23, 6, 4, 35, 34, 36, 39, 38, 2, 53, 52, 18, 55, 54, 36, 51, 50, 4, 23, 30, 1, 21, 16,
+ 0, 5, 2,250,142,124,123,141,144,122,121,143, 2, 33, 60,155,103,172,215,216,171,103,156, 59,143,146,165, 63, 64,104,254,213,
+176,123,226, 96,157,177,115,109,105, 1, 20,157,129,249,104, 90,125,254,217,152,185,254,184,128,128,134,136,126,129, 1, 82,189,
+212, 1,107,123, 75, 79,254,194,254,232, 2, 25,143,163,164,142,140,165,164,254, 72, 77, 73,249,200,200,250, 75, 76,131,253, 32,
+ 22,223,177,107,188, 80,131,139, 65, 64,102,254,181,193,159,254,234,106,104,109, 87, 81,111, 97,103,131,125,125, 1, 73,189,182,
+ 1, 74,125,127,135,174,160, 98,230,123,254,249,254,208, 6, 0, 0, 2, 0, 16, 0, 0, 5,104, 5,213, 0, 2, 0, 10, 0,186,
+ 64, 65, 0, 17, 1, 0, 4, 5, 4, 2, 17, 5, 5, 4, 1, 17, 10, 3, 10, 0, 17, 2, 0, 3, 3, 10, 7, 17, 5, 4, 6, 17,
+ 5, 5, 4, 9, 17, 3, 10, 8, 17, 10, 3, 10, 66, 0, 3, 7,149, 1, 3,129, 9, 5, 9, 8, 7, 6, 4, 3, 2, 1, 0, 9,
+ 5, 10, 11, 16,212,196, 23, 57, 49, 0, 47, 60,228,212,236, 18, 57, 48, 75, 83, 88, 7, 16, 5,237, 7, 5,237, 7, 16, 5,237,
+ 7, 5,237, 7, 16, 8,237, 7, 16, 5,237, 7, 16, 5,237, 7, 16, 8,237, 89, 34,178, 32, 12, 1, 1, 93, 64, 58, 15, 0, 88,
+ 0,118, 0,112, 0,140, 0, 5, 7, 1, 8, 2, 6, 3, 9, 4, 22, 1, 25, 2, 86, 1, 88, 2, 80, 12,103, 1,104, 2,120, 1,
+118, 2,124, 3,114, 4,119, 7,120, 8,135, 1,136, 2,128, 12,152, 2,153, 3,150, 4, 23, 93, 0, 93, 9, 1, 33, 1, 51, 1,
+ 35, 3, 33, 3, 35, 2,188,254,238, 2, 37,254,123,229, 2, 57,210,136,253, 95,136,213, 5, 14,253, 25, 3,174,250, 43, 1,127,
+254,129, 0, 0, 0, 3, 0,201, 0, 0, 4,236, 5,213, 0, 8, 0, 17, 0, 32, 0, 67, 64, 35, 25, 0,149, 10, 9,149, 18,129,
+ 1,149, 10,173, 31, 17, 11, 8, 2, 19, 25, 31, 5, 0, 14, 28, 22, 5, 25, 28, 46, 9, 0, 28, 18, 4, 33, 16,252,236, 50,252,
+236,212,236, 17, 23, 57, 57, 57, 49, 0, 47,236,236,244,236, 16,238, 57, 48,178, 15, 34, 1, 1, 93, 1, 17, 33, 50, 54, 53, 52,
+ 38, 35, 1, 17, 33, 50, 54, 53, 52, 38, 35, 37, 33, 50, 22, 21, 20, 6, 7, 30, 1, 21, 20, 4, 35, 33, 1,147, 1, 68,163,157,
+157,163,254,188, 1, 43,148,145,145,148,254, 11, 2, 4,231,250,128,124,149,165,254,240,251,253,232, 2,201,253,221,135,139,140,
+133, 2,102,254, 62,111,114,113,112,166,192,177,137,162, 20, 32,203,152,200,218, 0, 1, 0,115,255,227, 5, 39, 5,240, 0, 25,
+ 0, 54, 64, 26, 13,161, 14,174, 10,149, 17, 1,161, 0,174, 4,149, 23,145, 17,140, 26, 7, 25, 13, 0, 48, 20, 16, 26, 16,252,
+236, 50,236, 49, 0, 16,228,244,236,244,236, 16,238,246,238, 48,180, 15, 27, 31, 27, 2, 1, 93, 1, 21, 46, 1, 35, 32, 0, 17,
+ 16, 0, 33, 50, 54, 55, 21, 14, 1, 35, 32, 0, 17, 16, 0, 33, 50, 22, 5, 39,102,231,130,255, 0,254,240, 1, 16, 1, 0,130,
+231,102,106,237,132,254,173,254,122, 1,134, 1, 83,134,237, 5, 98,213, 95, 94,254,199,254,216,254,217,254,199, 94, 95,211, 72,
+ 72, 1,159, 1,103, 1,104, 1,159, 71, 0, 0, 0, 2, 0,201, 0, 0, 5,176, 5,213, 0, 8, 0, 17, 0, 46, 64, 21, 0,149,
+ 9,129, 1,149, 16, 8, 2, 16, 10, 0, 5, 25, 13, 50, 0, 28, 9, 4, 18, 16,252,236,244,236, 17, 57, 57, 57, 57, 49, 0, 47,
+236,244,236, 48,178, 96, 19, 1, 1, 93, 1, 17, 51, 32, 0, 17, 16, 0, 33, 37, 33, 32, 0, 17, 16, 0, 41, 1, 1,147,244, 1,
+ 53, 1, 31,254,225,254,203,254, 66, 1,159, 1,178, 1,150,254,104,254, 80,254, 97, 5, 47,251,119, 1, 24, 1, 46, 1, 44, 1,
+ 23,166,254,151,254,128,254,126,254,150, 0, 0, 0, 1, 0,201, 0, 0, 4,139, 5,213, 0, 11, 0, 46, 64, 21, 6,149, 4, 2,
+149, 0,129, 8,149, 4,173, 10, 5, 1, 9, 7, 3, 28, 0, 4, 12, 16,252,236, 50,212,196,196, 49, 0, 47,236,236,244,236, 16,
+238, 48,178, 31, 13, 1, 1, 93, 19, 33, 21, 33, 17, 33, 21, 33, 17, 33, 21, 33,201, 3,176,253, 26, 2,199,253, 57, 2,248,252,
+ 62, 5,213,170,254, 70,170,253,227,170, 0, 0, 0, 1, 0,201, 0, 0, 4, 35, 5,213, 0, 9, 0, 41, 64, 18, 6,149, 4, 2,
+149, 0,129, 4,173, 8, 5, 1, 7, 3, 28, 0, 4, 10, 16,252,236, 50,212,196, 49, 0, 47,236,244,236, 16,238, 48,178, 15, 11,
+ 1, 1, 93, 19, 33, 21, 33, 17, 33, 21, 33, 17, 35,201, 3, 90,253,112, 2, 80,253,176,202, 5,213,170,254, 72,170,253, 55, 0,
+ 0, 1, 0,115,255,227, 5,139, 5,240, 0, 29, 0, 57, 64, 32, 0, 5, 27, 1,149, 3, 27,149, 8, 18,161, 17,174, 21,149, 14,
+145, 8,140, 30, 2, 0, 28, 17, 52, 4, 51, 24, 25, 11, 16, 30, 16,252,236,252,228,252,196, 49, 0, 16,228,244,236,244,236, 16,
+254,212,238, 17, 57, 57, 48, 37, 17, 33, 53, 33, 17, 6, 4, 35, 32, 0, 17, 16, 0, 33, 50, 4, 23, 21, 46, 1, 35, 32, 0, 17,
+ 16, 0, 33, 50, 54, 4,195,254,182, 2, 18,117,254,230,160,254,162,254,117, 1,139, 1, 94,146, 1, 7,111,112,252,139,254,238,
+254,237, 1, 19, 1, 18,107,168,213, 1,145,166,253,127, 83, 85, 1,153, 1,109, 1,110, 1,153, 72, 70,215, 95, 96,254,206,254,
+209,254,210,254,206, 37, 0, 0, 0, 1, 0,201, 0, 0, 5, 59, 5,213, 0, 11, 0, 44, 64, 20, 8,149, 2,173, 4, 0,129, 10,
+ 6, 7, 3, 28, 5, 56, 9, 1, 28, 0, 4, 12, 16,252,236, 50,252,236, 50, 49, 0, 47, 60,228, 50,252,236, 48,178, 80, 13, 1,
+ 1, 93, 19, 51, 17, 33, 17, 51, 17, 35, 17, 33, 17, 35,201,202, 2,222,202,202,253, 34,202, 5,213,253,156, 2,100,250, 43, 2,
+199,253, 57, 0, 0, 1, 0,201, 0, 0, 1,147, 5,213, 0, 3, 0, 46,183, 0,175, 2, 1, 28, 0, 4, 4, 16,252, 75,176, 16,
+ 84, 88,185, 0, 0, 0, 64, 56, 89,236, 49, 0, 47,236, 48, 1, 64, 13, 48, 5, 64, 5, 80, 5, 96, 5,143, 5,159, 5, 6, 93,
+ 19, 51, 17, 35,201,202,202, 5,213,250, 43, 0, 0, 1,255,150,254,102, 1,147, 5,213, 0, 11, 0, 66, 64, 19, 11, 2, 0, 7,
+149, 5,176, 0,129, 12, 5, 8, 6, 57, 1, 28, 0, 4, 12, 16,252, 75,176, 16, 84, 88,185, 0, 0, 0, 64, 56, 89,236,228, 57,
+ 57, 49, 0, 16,228,252,236, 17, 57, 57, 48, 1, 64, 13, 48, 13, 64, 13, 80, 13, 96, 13,143, 13,159, 13, 6, 93, 19, 51, 17, 16,
+ 6, 43, 1, 53, 51, 50, 54, 53,201,202,205,227, 77, 63,134,110, 5,213,250,147,254,242,244,170,150,194, 0, 0, 0, 1, 0,201,
+ 0, 0, 5,106, 5,213, 0, 10, 0,239, 64, 40, 8, 17, 5, 6, 5, 7, 17, 6, 6, 5, 3, 17, 4, 5, 4, 2, 17, 5, 5, 4,
+ 66, 8, 5, 2, 3, 3, 0,175, 9, 6, 5, 1, 4, 6, 8, 1, 28, 0, 4, 11, 16,252,236, 50,212,196, 17, 57, 49, 0, 47, 60,
+236, 50, 23, 57, 48, 75, 83, 88, 7, 16, 4,237, 7, 16, 5,237, 7, 16, 5,237, 7, 16, 4,237, 89, 34,178, 8, 3, 1, 1, 93,
+ 64,146, 20, 2, 1, 4, 2, 9, 8, 22, 2, 40, 5, 40, 8, 55, 2, 54, 5, 52, 8, 71, 2, 70, 5, 67, 8, 85, 2,103, 2,118,
+ 2,119, 5,131, 2,136, 5,143, 8,148, 2,155, 8,231, 2, 21, 6, 3, 9, 5, 9, 6, 27, 3, 25, 7, 5, 10, 3, 10, 7, 24,
+ 3, 40, 5, 43, 6, 42, 7, 54, 4, 54, 5, 54, 6, 53, 7, 48, 12, 65, 3, 64, 4, 69, 5, 64, 6, 64, 7, 64, 12, 98, 3, 96,
+ 4,104, 5,103, 7,119, 5,112, 12,139, 3,139, 5,142, 6,143, 7,143, 12,154, 3,157, 6,157, 7,182, 3,181, 7,197, 3,197,
+ 7,215, 3,214, 7,232, 3,233, 4,232, 5,234, 6,247, 3,248, 5,249, 6, 44, 93,113, 0, 93,113, 19, 51, 17, 1, 33, 9, 1,
+ 33, 1, 17, 35,201,202, 2,158, 1, 4,253, 27, 3, 26,254,246,253, 51,202, 5,213,253,137, 2,119,253, 72,252,227, 2,207,253,
+ 49, 0, 0, 0, 0, 1, 0,201, 0, 0, 4,106, 5,213, 0, 5, 0, 37, 64, 12, 2,149, 0,129, 4, 1, 28, 3, 58, 0, 4, 6,
+ 16,252,236,236, 49, 0, 47,228,236, 48, 64, 9, 48, 7, 80, 7,128, 3,128, 4, 4, 1, 93, 19, 51, 17, 33, 21, 33,201,202, 2,
+215,252, 95, 5,213,250,213,170, 0, 1, 0,201, 0, 0, 6, 31, 5,213, 0, 12, 0,191, 64, 52, 3, 17, 7, 8, 7, 2, 17, 1,
+ 2, 8, 8, 7, 2, 17, 3, 2, 9, 10, 9, 1, 17, 10, 10, 9, 66, 10, 7, 2, 3, 8, 3, 0,175, 8, 11, 5, 9, 8, 3, 2,
+ 1, 5, 10, 6, 28, 4, 62, 10, 28, 0, 4, 13, 16,252,236,252,236, 17, 23, 57, 49, 0, 47, 60,196,236, 50, 17, 23, 57, 48, 75,
+ 83, 88, 7, 16, 5,237, 7, 16, 8,237, 7, 16, 8,237, 7, 16, 5,237, 89, 34,178,112, 14, 1, 1, 93, 64, 86, 3, 7, 15, 8,
+ 15, 9, 2, 10, 21, 2, 20, 7, 19, 10, 38, 2, 38, 7, 32, 7, 38, 10, 32, 10, 52, 7, 53, 10,105, 2,124, 2,123, 7,121, 10,
+128, 2,130, 7,130, 10,144, 2, 22, 4, 1, 11, 3, 19, 1, 27, 3, 35, 1, 44, 3, 39, 8, 40, 9, 52, 1, 60, 3, 86, 8, 89,
+ 9,101, 8,106, 9,118, 8,121, 9,129, 1,141, 3,149, 1,155, 3, 20, 93, 0, 93, 19, 33, 9, 1, 33, 17, 35, 17, 1, 35, 1,
+ 17, 35,201, 1, 45, 1,125, 1,127, 1, 45,197,254,127,203,254,127,196, 5,213,252, 8, 3,248,250, 43, 5, 31,252, 0, 4, 0,
+250,225, 0, 0, 0, 1, 0,201, 0, 0, 5, 51, 5,213, 0, 9, 0,121, 64, 30, 7, 17, 1, 2, 1, 2, 17, 6, 7, 6, 66, 7,
+ 2, 3, 0,175, 8, 5, 6, 1, 7, 2, 28, 4, 54, 7, 28, 0, 4, 10, 16,252,236,252,236, 17, 57, 57, 49, 0, 47, 60,236, 50,
+ 57, 57, 48, 75, 83, 88, 7, 16, 4,237, 7, 16, 4,237, 89, 34,178, 31, 11, 1, 1, 93, 64, 48, 54, 2, 56, 7, 72, 2, 71, 7,
+105, 2,102, 7,128, 2, 7, 6, 1, 9, 6, 21, 1, 26, 6, 70, 1, 73, 6, 87, 1, 88, 6,101, 1,105, 6,121, 6,133, 1,138,
+ 6,149, 1,154, 6,159, 11, 16, 93, 0, 93, 19, 33, 1, 17, 51, 17, 33, 1, 17, 35,201, 1, 16, 2,150,196,254,240,253,106,196,
+ 5,213,251, 31, 4,225,250, 43, 4,225,251, 31, 0, 2, 0,115,255,227, 5,217, 5,240, 0, 11, 0, 23, 0, 35, 64, 19, 6,149,
+ 18, 0,149, 12,145, 18,140, 24, 9, 25, 15, 51, 3, 25, 21, 16, 24, 16,252,236,252,236, 49, 0, 16,228,244,236, 16,238, 48, 1,
+ 34, 0, 17, 16, 0, 51, 50, 0, 17, 16, 0, 39, 32, 0, 17, 16, 0, 33, 32, 0, 17, 16, 0, 3, 39,220,254,253, 1, 3,220,220,
+ 1, 1,254,255,220, 1, 58, 1,120,254,136,254,198,254,197,254,135, 1,121, 5, 76,254,184,254,229,254,230,254,184, 1, 72, 1,
+ 26, 1, 27, 1, 72,164,254, 91,254,158,254,159,254, 91, 1,164, 1, 98, 1, 98, 1,165, 0, 0, 0, 2, 0,201, 0, 0, 4,141,
+ 5,213, 0, 8, 0, 19, 0, 58, 64, 24, 1,149, 16, 0,149, 9,129, 18, 16, 10, 8, 2, 4, 0, 5, 25, 13, 63, 17, 0, 28, 9,
+ 4, 20, 16,252,236, 50,252,236, 17, 23, 57, 49, 0, 47,244,236,212,236, 48, 64, 11, 15, 21, 31, 21, 63, 21, 95, 21,175, 21, 5,
+ 1, 93, 1, 17, 51, 50, 54, 53, 52, 38, 35, 37, 33, 50, 4, 21, 20, 4, 43, 1, 17, 35, 1,147,254,141,154,154,141,254, 56, 1,
+200,251, 1, 1,254,255,251,254,202, 5, 47,253,207,146,135,134,146,166,227,219,221,226,253,168, 0, 2, 0,115,254,248, 5,217,
+ 5,240, 0, 11, 0, 29, 0, 82, 64, 42, 17, 16, 2, 15, 1, 12, 13, 12, 14, 1, 13, 13, 12, 66, 15, 30, 12, 6,149, 18, 0,149,
+ 24,145, 18,140, 13, 30, 13, 27, 15, 12, 3, 9, 25, 27, 51, 3, 25, 21, 16, 30, 16,252,236,252,236, 17, 57, 57, 17, 57, 49, 0,
+ 16,196,228,244,236, 16,238, 57, 18, 57, 48, 75, 83, 88, 7, 16, 5,237, 7, 16, 5,237, 23, 57, 89, 34, 1, 34, 0, 17, 16, 0,
+ 51, 50, 0, 17, 16, 0, 19, 1, 35, 39, 14, 1, 35, 32, 0, 17, 16, 0, 33, 32, 0, 17, 16, 2, 3, 39,220,254,253, 1, 3,220,
+220, 1, 1,254,255, 63, 1, 10,244,221, 33, 35, 16,254,197,254,135, 1,121, 1, 59, 1, 58, 1,120,209, 5, 76,254,184,254,229,
+254,230,254,184, 1, 72, 1, 26, 1, 27, 1, 72,250,207,254,221,239, 2, 2, 1,165, 1, 97, 1, 98, 1,165,254, 91,254,158,254,
+252,254,142, 0, 0, 2, 0,201, 0, 0, 5, 84, 5,213, 0, 19, 0, 28, 0,177, 64, 53, 9, 8, 7, 3, 10, 6, 17, 3, 4, 3,
+ 5, 17, 4, 4, 3, 66, 6, 4, 0, 21, 3, 4, 21,149, 9, 20,149, 13,129, 11, 4, 5, 6, 3, 17, 9, 0, 28, 22, 14, 5, 10,
+ 25, 25, 4, 17, 63, 20, 10, 28, 12, 4, 29, 16,252,236, 50,252,196,236, 17, 23, 57, 17, 57, 57, 57, 49, 0, 47, 60,244,236,212,
+236, 18, 57, 18, 57, 18, 57, 48, 75, 83, 88, 7, 16, 5,237, 7, 16, 5,237, 17, 23, 57, 89, 34,178, 64, 30, 1, 1, 93, 64, 66,
+122, 19, 1, 5, 0, 5, 1, 5, 2, 6, 3, 7, 4, 21, 0, 21, 1, 20, 2, 22, 3, 23, 4, 37, 0, 37, 1, 37, 2, 38, 3, 39,
+ 6, 38, 7, 38, 8, 38, 9, 32, 30, 54, 1, 54, 2, 70, 1, 70, 2,104, 5,117, 4,117, 5,119, 19,136, 6,136, 7,152, 6,152,
+ 7, 31, 93, 0, 93, 1, 30, 1, 23, 19, 35, 3, 46, 1, 43, 1, 17, 35, 17, 33, 32, 22, 21, 20, 6, 1, 17, 51, 50, 54, 53, 52,
+ 38, 35, 3,141, 65,123, 62,205,217,191, 74,139,120,220,202, 1,200, 1, 0,252,131,253,137,254,146,149,149,146, 2,188, 22,144,
+126,254,104, 1,127,150, 98,253,137, 5,213,214,216,141,186, 2, 79,253,238,135,131,131,133, 0, 0, 1, 0,135,255,227, 4,162,
+ 5,240, 0, 39, 0,126, 64, 60, 13, 12, 2, 14, 11, 2, 30, 31, 30, 8, 9, 2, 7, 10, 2, 31, 31, 30, 66, 10, 11, 30, 31, 4,
+ 21, 1, 0, 21,161, 20,148, 24,149, 17, 4,149, 0,148, 37,145, 17,140, 40, 30, 10, 11, 31, 27, 7, 0, 34, 27, 25, 14, 45, 7,
+ 25, 20, 34, 40, 16,220,196,236,252,236,228, 17, 18, 57, 57, 57, 57, 49, 0, 16,228,244,228,236, 16,238,246,238, 16,198, 17, 23,
+ 57, 48, 75, 83, 88, 7, 16, 14,237, 17, 23, 57, 7, 16, 14,237, 17, 23, 57, 89, 34,178, 15, 41, 1, 1, 93,182, 31, 41, 47, 41,
+ 79, 41, 3, 93, 1, 21, 46, 1, 35, 34, 6, 21, 20, 22, 31, 1, 30, 1, 21, 20, 4, 33, 34, 38, 39, 53, 30, 1, 51, 50, 54, 53,
+ 52, 38, 47, 1, 46, 1, 53, 52, 36, 51, 50, 22, 4, 72,115,204, 95,165,179,119,166,122,226,215,254,221,254,231,106,239,128,123,
+236,114,173,188,135,154,123,226,202, 1, 23,245,105,218, 5,164,197, 55, 54,128,118, 99,101, 31, 25, 43,217,182,217,224, 48, 47,
+208, 69, 70,136,126,110,124, 31, 24, 45,192,171,198,228, 38, 0, 0, 1,255,250, 0, 0, 4,233, 5,213, 0, 7, 0, 74, 64, 14,
+ 6, 2,149, 0,129, 4, 1, 64, 3, 28, 0, 64, 5, 8, 16,212,228,252,228, 49, 0, 47,244,236, 50, 48, 1, 75,176, 10, 84, 88,
+189, 0, 8, 0, 64, 0, 1, 0, 8, 0, 8,255,192, 56, 17, 55, 56, 89, 64, 19, 0, 9, 31, 0, 16, 1, 16, 2, 31, 7, 16, 9,
+ 64, 9,112, 9,159, 9, 9, 93, 3, 33, 21, 33, 17, 35, 17, 33, 6, 4,239,253,238,203,253,238, 5,213,170,250,213, 5, 43, 0,
+ 0, 1, 0,178,255,227, 5, 41, 5,213, 0, 17, 0, 64, 64, 22, 8, 2, 17, 11, 0, 5,149, 14,140, 9, 0,129, 18, 8, 28, 10,
+ 56, 1, 28, 0, 65, 18, 16,252, 75,176, 16, 84, 88,185, 0, 0,255,192, 56, 89,236,252,236, 49, 0, 16,228, 50,244,236, 17, 57,
+ 57, 57, 57, 48, 1,182, 31, 19,143, 19,159, 19, 3, 93, 19, 51, 17, 20, 22, 51, 50, 54, 53, 17, 51, 17, 16, 0, 33, 32, 0, 17,
+178,203,174,195,194,174,203,254,223,254,230,254,229,254,223, 5,213,252,117,240,211,211,240, 3,139,252, 92,254,220,254,214, 1,
+ 42, 1, 36, 0, 0, 1, 0, 16, 0, 0, 5,104, 5,213, 0, 6, 0,183, 64, 39, 4, 17, 5, 6, 5, 3, 17, 2, 3, 6, 6, 5,
+ 3, 17, 4, 3, 0, 1, 0, 2, 17, 1, 1, 0, 66, 3, 4, 1,175, 0, 6, 4, 3, 2, 0, 5, 5, 1, 7, 16,212,196, 23, 57,
+ 49, 0, 47,236, 50, 57, 48, 75, 83, 88, 7, 16, 5,237, 7, 16, 8,237, 7, 16, 8,237, 7, 16, 5,237, 89, 34,178, 80, 8, 1,
+ 1, 93, 64, 98, 0, 3, 42, 3, 71, 4, 71, 5, 90, 3,125, 3,131, 3, 7, 6, 0, 7, 2, 8, 4, 9, 6, 21, 1, 20, 2, 26,
+ 4, 26, 5, 42, 0, 38, 1, 38, 2, 41, 4, 41, 5, 37, 6, 32, 8, 56, 0, 51, 1, 51, 2, 60, 4, 60, 5, 55, 6, 72, 0, 69,
+ 1, 69, 2, 73, 4, 73, 5, 71, 6, 89, 0, 86, 6,102, 2,105, 4,105, 5,122, 0,118, 1,118, 2,121, 4,121, 5,117, 6,128,
+ 8,152, 0,151, 6, 41, 93, 0, 93, 33, 1, 51, 9, 1, 51, 1, 2, 74,253,198,211, 1,217, 1,218,210,253,199, 5,213,251, 23,
+ 4,233,250, 43, 0, 1, 0, 68, 0, 0, 7,166, 5,213, 0, 12, 1,123, 64, 73, 5, 26, 6, 5, 9, 10, 9, 4, 26, 10, 9, 3,
+ 26, 10, 11, 10, 2, 26, 1, 2, 11, 11, 10, 6, 17, 7, 8, 7, 5, 17, 4, 5, 8, 8, 7, 2, 17, 3, 2, 12, 0, 12, 1, 17,
+ 0, 0, 12, 66, 10, 5, 2, 3, 6, 3, 0,175, 11, 8, 12, 11, 10, 9, 8, 6, 5, 4, 3, 2, 1, 11, 7, 0, 13, 16,212,204,
+ 23, 57, 49, 0, 47, 60,236, 50, 50, 23, 57, 48, 75, 83, 88, 7, 16, 5,237, 7, 16, 8,237, 7, 16, 8,237, 7, 16, 5,237, 7,
+ 16, 8,237, 7, 16, 5,237, 7, 5,237, 7, 16, 8,237, 89, 34,178, 0, 14, 1, 1, 93, 64,242, 6, 2, 6, 5, 2, 10, 0, 10,
+ 0, 10, 18, 10, 40, 5, 36, 10, 32, 10, 62, 2, 62, 5, 52, 10, 48, 10, 76, 2, 77, 5, 66, 10, 64, 10, 89, 2,106, 2,107, 5,
+103, 10, 96, 10,123, 2,127, 2,124, 5,127, 5,128, 10,150, 2,149, 5, 29, 7, 0, 9, 2, 8, 3, 0, 4, 6, 5, 0, 5, 0,
+ 6, 1, 7, 4, 8, 0, 8, 7, 9, 0, 9, 4, 10, 10, 12, 0, 14, 26, 3, 21, 4, 21, 8, 25, 12, 16, 14, 32, 4, 33, 5, 32,
+ 6, 32, 7, 32, 8, 35, 9, 36, 10, 37, 11, 32, 14, 32, 14, 60, 2, 58, 3, 53, 4, 51, 5, 48, 8, 54, 9, 57, 11, 63, 12, 48,
+ 14, 70, 0, 70, 1, 74, 2, 64, 4, 69, 5, 64, 5, 66, 6, 66, 7, 66, 8, 64, 8, 64, 9, 68, 10, 77, 12, 64, 14, 64, 14, 88,
+ 2, 86, 8, 89, 12, 80, 14,102, 2,103, 3, 97, 4, 98, 5, 96, 6, 96, 7, 96, 8,100, 9,100, 10,100, 11,119, 0,118, 1,123,
+ 2,120, 3,119, 4,116, 5,121, 6,121, 7,119, 8,112, 8,120, 12,127, 12,127, 14,134, 2,135, 3,136, 4,137, 5,133, 9,138,
+ 11,143, 14,151, 4,159, 14,175, 14, 91, 93, 0, 93, 19, 51, 9, 1, 51, 9, 1, 51, 1, 35, 9, 1, 35, 68,204, 1, 58, 1, 57,
+227, 1, 58, 1, 57,205,254,137,254,254,197,254,194,254, 5,213,251, 18, 4,238,251, 18, 4,238,250, 43, 5, 16,250,240, 0, 0,
+ 0, 1, 0, 61, 0, 0, 5, 59, 5,213, 0, 11, 0,102, 64, 6, 13, 4, 6, 0, 10, 12, 16,212,196,220,196,196, 49,180,128, 0,
+127, 10, 2, 93, 0, 64, 5, 3, 0,175, 9, 6, 47, 60,236, 50, 48, 75,176, 66, 80, 88, 64, 20, 7, 17, 6, 6, 5, 9, 17, 10,
+ 11, 10, 3, 17, 4, 5, 4, 1, 17, 0, 11, 0, 5, 7, 16,236, 7, 16,236, 7, 16,236, 7, 16,236, 64, 20, 11, 10, 3, 7, 0,
+ 8, 9, 4, 7, 0, 5, 9, 4, 6, 1, 2, 10, 3, 6, 1, 15, 15, 15, 15, 89, 19, 51, 9, 1, 51, 9, 1, 35, 9, 1, 35, 1,
+129,217, 1,115, 1,117,217,254, 32, 2, 0,217,254, 92,254, 89,218, 2, 21, 5,213,253,213, 2, 43,253, 51,252,248, 2,123,253,
+133, 3, 29, 0, 0, 1,255,252, 0, 0, 4,231, 5,213, 0, 8, 0,148, 64, 40, 3, 17, 4, 5, 4, 2, 17, 1, 2, 5, 5, 4,
+ 2, 17, 3, 2, 8, 0, 8, 1, 17, 0, 0, 8, 66, 2, 3, 0,175, 6, 2, 7, 4, 64, 5, 28, 0, 64, 7, 9, 16,212,228,252,
+228, 18, 57, 49, 0, 47,236, 50, 57, 48, 75, 83, 88, 7, 16, 5,237, 7, 16, 8,237, 7, 16, 8,237, 7, 16, 5,237, 89, 34,178,
+ 0, 10, 1, 1, 93, 64, 60, 5, 2, 20, 2, 53, 2, 48, 2, 48, 5, 48, 8, 70, 2, 64, 2, 64, 5, 64, 8, 81, 2, 81, 5, 81,
+ 8,101, 2,132, 2,147, 2, 16, 22, 1, 26, 3, 31, 10, 38, 1, 41, 3, 55, 1, 56, 3, 64, 10,103, 1,104, 3,120, 3,112, 10,
+159, 10, 13, 93, 0, 93, 3, 51, 9, 1, 51, 1, 17, 35, 17, 4,217, 1,158, 1,155,217,253,240,203, 5,213,253,154, 2,102,252,
+242,253, 57, 2,199, 0, 0, 0, 0, 1, 0, 92, 0, 0, 5, 31, 5,213, 0, 9, 0,144, 64, 27, 3, 17, 7, 8, 7, 8, 17, 2,
+ 3, 2, 66, 8,149, 0,129, 3,149, 5, 8, 3, 0, 1, 66, 4, 0, 6, 10, 16,220, 75,176, 9, 84, 75,176, 10, 84, 91, 88,185,
+ 0, 6,255,192, 56, 89,196,212,228, 17, 57, 57, 49, 0, 47,236,244,236, 48, 75, 83, 88, 7, 16, 5,237, 7, 16, 5,237, 89, 34,
+ 1, 64, 64, 5, 2, 10, 7, 24, 7, 41, 2, 38, 7, 56, 7, 72, 2, 71, 7, 72, 8, 9, 5, 3, 11, 8, 0, 11, 22, 3, 26, 8,
+ 16, 11, 47, 11, 53, 3, 57, 8, 63, 11, 71, 3, 74, 8, 79, 11, 85, 3, 89, 8,102, 3,105, 8,111, 11,119, 3,120, 8,127, 11,
+159, 11, 22, 93, 0, 93, 19, 33, 21, 1, 33, 21, 33, 53, 1, 33,115, 4,149,252, 80, 3,199,251, 61, 3,176,252,103, 5,213,154,
+251,111,170,154, 4,145, 0, 0, 0, 1, 0,176,254,242, 2, 88, 6, 20, 0, 7, 0, 59, 64, 15, 4,169, 6,178, 2,169, 0,177,
+ 8, 5, 1, 3, 67, 0, 8, 16,220, 75,176, 12, 84, 88,185, 0, 0, 0, 64, 56, 89, 75,176, 18, 84, 75,176, 19, 84, 91, 88,185,
+ 0, 0,255,192, 56, 89,252,204, 50, 49, 0, 16,252,236,244,236, 48, 19, 33, 21, 35, 17, 51, 21, 33,176, 1,168,240,240,254, 88,
+ 6, 20,143,249,252,143, 0, 0, 0, 1, 0, 0,255, 66, 2,178, 5,213, 0, 3, 0, 45, 64, 20, 2, 26, 1, 1, 0, 0, 26, 3,
+ 3, 2, 66, 1,159, 0,129, 4, 2, 0, 1, 3, 47,196, 57, 57, 49, 0, 16,244,236, 48, 75, 83, 88, 7, 16, 5,237, 7, 16, 5,
+237, 89, 34, 19, 1, 35, 1,170, 2, 8,170,253,248, 5,213,249,109, 6,147, 0, 0, 1, 0,199,254,242, 2,111, 6, 20, 0, 7,
+ 0, 48, 64, 16, 3,169, 1,178, 5,169, 0,177, 8, 0, 67, 4, 6, 2, 4, 8, 16,252, 75,176, 15, 84, 75,176, 16, 84, 91, 88,
+185, 0, 2, 0, 64, 56, 89, 60,220,236, 49, 0, 16,252,236,244,236, 48, 1, 17, 33, 53, 51, 17, 35, 53, 2,111,254, 88,239,239,
+ 6, 20,248,222,143, 6, 4,143, 0, 1, 0,217, 3,168, 5,219, 5,213, 0, 6, 0, 24, 64, 10, 3, 4, 1, 0,129, 7, 3, 1,
+ 5, 7, 16,220,204, 57, 49, 0, 16,244,204, 50, 57, 48, 9, 1, 35, 9, 1, 35, 1, 3,188, 2, 31,201,254, 72,254, 72,201, 2,
+ 31, 5,213,253,211, 1,139,254,117, 2, 45, 0, 0, 1,255,236,254, 29, 4, 20,254,172, 0, 3, 0, 15,181, 0,169, 1, 0, 2,
+ 4, 16,196,196, 49, 0,212,236, 48, 1, 21, 33, 53, 4, 20,251,216,254,172,143,143, 0, 0, 0, 0, 1, 0,170, 4,240, 2,137,
+ 6,102, 0, 3, 0, 49, 64, 9, 1,180, 0,179, 4, 3, 68, 1, 4, 16,220,236, 49, 0, 16,244,236, 48, 0, 75,176, 9, 84, 75,
+176, 14, 84, 91, 88,189, 0, 4,255,192, 0, 1, 0, 4, 0, 4, 0, 64, 56, 17, 55, 56, 89, 9, 1, 35, 1, 1,111, 1, 26,153,
+254,186, 6,102,254,138, 1,118, 0, 2, 0,123,255,227, 4, 45, 4,123, 0, 10, 0, 37, 0,188, 64, 39, 25, 31, 11, 23, 9, 14,
+ 0,169, 23, 6,185, 14, 17, 32,134, 31,186, 28,185, 35,184, 17,140, 23, 12, 0, 23, 3, 24, 13, 9, 8, 11, 31, 3, 8, 20, 69,
+ 38, 16,252,236,204,212,236, 50, 50, 17, 57, 57, 49, 0, 47,196,228,244,252,244,236, 16,198,238, 16,238, 17, 57, 17, 57, 18, 57,
+ 48, 64,110, 48, 29, 48, 30, 48, 31, 48, 32, 48, 33, 48, 34, 63, 39, 64, 29, 64, 30, 64, 31, 64, 32, 64, 33, 64, 34, 80, 29, 80,
+ 30, 80, 31, 80, 32, 80, 33, 80, 34, 80, 39,112, 39,133, 29,135, 30,135, 31,135, 32,135, 33,133, 34,144, 39,160, 39,240, 39, 30,
+ 48, 30, 48, 31, 48, 32, 48, 33, 64, 30, 64, 31, 64, 32, 64, 33, 80, 30, 80, 31, 80, 32, 80, 33, 96, 30, 96, 31, 96, 32, 96, 33,
+112, 30,112, 31,112, 32,112, 33,128, 30,128, 31,128, 32,128, 33, 24, 93, 1, 93, 1, 34, 6, 21, 20, 22, 51, 50, 54, 61, 1, 55,
+ 17, 35, 53, 14, 1, 35, 34, 38, 53, 52, 54, 51, 33, 53, 52, 38, 35, 34, 6, 7, 53, 62, 1, 51, 50, 22, 2,190,223,172,129,111,
+153,185,184,184, 63,188,136,172,203,253,251, 1, 2,167,151, 96,182, 84,101,190, 90,243,240, 2, 51,102,123, 98,115,217,180, 41,
+ 76,253,129,170,102, 97,193,162,189,192, 18,127,139, 46, 46,170, 39, 39,252, 0, 0, 2, 0,186,255,227, 4,164, 6, 20, 0, 11,
+ 0, 28, 0, 56, 64, 25, 3,185, 12, 15, 9,185, 24, 21,140, 15,184, 27,151, 25, 0, 18, 18, 71, 24, 12, 6, 8, 26, 70, 29, 16,
+252,236, 50, 50,244,236, 49, 0, 47,236,228,244,196,236, 16,198,238, 48,182, 96, 30,128, 30,160, 30, 3, 1, 93, 1, 52, 38, 35,
+ 34, 6, 21, 20, 22, 51, 50, 54, 1, 62, 1, 51, 50, 0, 17, 16, 2, 35, 34, 38, 39, 21, 35, 17, 51, 3,229,167,146,146,167,167,
+146,146,167,253,142, 58,177,123,204, 0,255,255,204,123,177, 58,185,185, 2, 47,203,231,231,203,203,231,231, 2, 82,100, 97,254,
+188,254,248,254,248,254,188, 97,100,168, 6, 20, 0, 1, 0,113,255,227, 3,231, 4,123, 0, 25, 0, 63, 64, 27, 0,134, 1,136,
+ 4, 14,134, 13,136, 10,185, 17, 4,185, 23,184, 17,140, 26, 7, 18, 13, 0, 72, 20, 69, 26, 16,252,228, 50,236, 49, 0, 16,228,
+244,236, 16,254,244,238, 16,245,238, 48, 64, 11, 15, 27, 16, 27,128, 27,144, 27,160, 27, 5, 1, 93, 1, 21, 46, 1, 35, 34, 6,
+ 21, 20, 22, 51, 50, 54, 55, 21, 14, 1, 35, 34, 0, 17, 16, 0, 33, 50, 22, 3,231, 78,157, 80,179,198,198,179, 80,157, 78, 77,
+165, 93,253,254,214, 1, 45, 1, 6, 85,162, 4, 53,172, 43, 43,227,205,205,227, 43, 43,170, 36, 36, 1, 62, 1, 14, 1, 18, 1,
+ 58, 35, 0, 0, 0, 2, 0,113,255,227, 4, 90, 6, 20, 0, 16, 0, 28, 0, 56, 64, 25, 26,185, 0, 14, 20,185, 5, 8,140, 14,
+184, 1,151, 3, 23, 4, 0, 8, 2, 71, 17, 18, 11, 69, 29, 16,252,236,244,236, 50, 50, 49, 0, 47,236,228,244,196,236, 16,196,
+238, 48,182, 96, 30,128, 30,160, 30, 3, 1, 93, 1, 17, 51, 17, 35, 53, 14, 1, 35, 34, 2, 17, 16, 0, 51, 50, 22, 1, 20, 22,
+ 51, 50, 54, 53, 52, 38, 35, 34, 6, 3,162,184,184, 58,177,124,203,255, 0,255,203,124,177,253,199,167,146,146,168,168,146,146,
+167, 3,182, 2, 94,249,236,168,100, 97, 1, 68, 1, 8, 1, 8, 1, 68, 97,254, 21,203,231,231,203,203,231,231, 0, 2, 0,113,
+255,227, 4,127, 4,123, 0, 20, 0, 27, 0,112, 64, 36, 0, 21, 1, 9,134, 8,136, 5, 21,169, 1, 5,185, 12, 1,187, 24,185,
+ 18,184, 12,140, 28, 27, 21, 2, 8, 21, 8, 0, 75, 2, 18, 15, 69, 28, 16,252,236,244,236,196, 17, 18, 57, 49, 0, 16,228,244,
+236,228, 16,238, 16,238, 16,244,238, 17, 18, 57, 48, 64, 41, 63, 29,112, 29,160, 29,208, 29,240, 29, 5, 63, 0, 63, 1, 63, 2,
+ 63, 21, 63, 27, 5, 44, 7, 47, 8, 47, 9, 44, 10,111, 0,111, 1,111, 2,111, 21,111, 27, 9, 93,113, 1, 93, 1, 21, 33, 30,
+ 1, 51, 50, 54, 55, 21, 14, 1, 35, 32, 0, 17, 16, 0, 51, 50, 0, 7, 46, 1, 35, 34, 6, 7, 4,127,252,178, 12,205,183,106,
+199, 98, 99,208,107,254,244,254,199, 1, 41,252,226, 1, 7,184, 2,165,136,154,185, 14, 2, 94, 90,190,199, 52, 52,174, 42, 44,
+ 1, 56, 1, 10, 1, 19, 1, 67,254,221,196,151,180,174,158, 0, 0, 1, 0, 47, 0, 0, 2,248, 6, 20, 0, 19, 0, 89, 64, 28,
+ 5, 16, 1, 12, 8,169, 6, 1,135, 0,151, 14, 6,188, 10, 2, 19, 7, 0, 7, 9, 5, 8, 13, 15, 11, 76, 20, 16,252, 75,176,
+ 10, 84, 88,185, 0, 11, 0, 64, 56, 89, 75,176, 14, 84, 88,185, 0, 11,255,192, 56, 89, 60,196,252, 60,196,196, 18, 57, 57, 49,
+ 0, 47,228, 50,252,236, 16,238, 50, 18, 57, 57, 48, 1,182, 64, 21, 80, 21,160, 21, 3, 93, 1, 21, 35, 34, 6, 29, 1, 33, 21,
+ 33, 17, 35, 17, 35, 53, 51, 53, 52, 54, 51, 2,248,176, 99, 77, 1, 47,254,209,185,176,176,174,189, 6, 20,153, 80,104, 99,143,
+252, 47, 3,209,143, 78,187,171, 0, 2, 0,113,254, 86, 4, 90, 4,123, 0, 11, 0, 40, 0, 74, 64, 35, 25, 12, 29, 9, 18,134,
+ 19, 22,185, 15, 3,185, 38, 35,184, 39,188, 9,185, 15,189, 26, 29, 38, 25, 0, 8, 12, 71, 6, 18, 18, 32, 69, 41, 16,252,196,
+236,244,236, 50, 50, 49, 0, 47,196,228,236,228,244,196,236, 16,254,213,238, 17, 18, 57, 57, 48,182, 96, 42,128, 42,160, 42, 3,
+ 1, 93, 1, 52, 38, 35, 34, 6, 21, 20, 22, 51, 50, 54, 23, 16, 2, 33, 34, 38, 39, 53, 30, 1, 51, 50, 54, 61, 1, 14, 1, 35,
+ 34, 2, 17, 16, 18, 51, 50, 22, 23, 53, 51, 3,162,165,149,148,165,165,148,149,165,184,254,254,250, 97,172, 81, 81,158, 82,181,
+180, 57,178,124,206,252,252,206,124,178, 57,184, 2, 61,200,220,220,200,199,220,220,235,254,226,254,233, 29, 30,179, 44, 42,189,
+191, 91, 99, 98, 1, 58, 1, 3, 1, 4, 1, 58, 98, 99,170, 0, 0, 1, 0,186, 0, 0, 4,100, 6, 20, 0, 19, 0, 52, 64, 25,
+ 3, 9, 0, 3, 14, 1, 6,135, 14, 17,184, 12,151, 10, 1, 2, 8, 0, 78, 13, 9, 8, 11, 70, 20, 16,252,236, 50,244,236, 49,
+ 0, 47, 60,236,244,196,236, 17, 18, 23, 57, 48,178, 96, 21, 1, 1, 93, 1, 17, 35, 17, 52, 38, 35, 34, 6, 21, 17, 35, 17, 51,
+ 17, 62, 1, 51, 50, 22, 4,100,184,124,124,149,172,185,185, 66,179,117,193,198, 2,164,253, 92, 2,158,159,158,190,164,253,135,
+ 6, 20,253,158,101,100,239, 0, 0, 2, 0,193, 0, 0, 1,121, 6, 20, 0, 3, 0, 7, 0, 43, 64, 14, 6,190, 4,177, 0,188,
+ 2, 5, 1, 8, 4, 0, 70, 8, 16,252, 60,236, 50, 49, 0, 47,228,252,236, 48, 64, 11, 16, 9, 64, 9, 80, 9, 96, 9,112, 9,
+ 5, 1, 93, 19, 51, 17, 35, 17, 51, 21, 35,193,184,184,184,184, 4, 96,251,160, 6, 20,233, 0, 0, 2,255,219,254, 86, 1,121,
+ 6, 20, 0, 11, 0, 15, 0, 68, 64, 28, 11, 2, 7, 0, 14,190, 12, 7,135, 5,189, 0,188, 12,177, 16, 8, 16, 5, 6, 79, 13,
+ 1, 8, 12, 0, 70, 16, 16,252, 60,236, 50,228, 57, 18, 57, 49, 0, 16,236,228,244,236, 16,238, 17, 18, 57, 57, 48, 64, 11, 16,
+ 17, 64, 17, 80, 17, 96, 17,112, 17, 5, 1, 93, 19, 51, 17, 20, 6, 43, 1, 53, 51, 50, 54, 53, 17, 51, 21, 35,193,184,163,181,
+ 70, 49,105, 76,184,184, 4, 96,251,140,214,192,156, 97,153, 6, 40,233, 0, 0, 0, 1, 0,186, 0, 0, 4,156, 6, 20, 0, 10,
+ 0,188, 64, 41, 8, 17, 5, 6, 5, 7, 17, 6, 6, 5, 3, 17, 4, 5, 4, 2, 17, 5, 5, 4, 66, 8, 5, 2, 3, 3,188, 0,
+151, 9, 6, 5, 1, 4, 6, 8, 1, 8, 0, 70, 11, 16,252,236, 50,212,196, 17, 57, 49, 0, 47, 60,236,228, 23, 57, 48, 75, 83,
+ 88, 7, 16, 4,237, 7, 16, 5,237, 7, 16, 5,237, 7, 16, 4,237, 89, 34,178, 16, 12, 1, 1, 93, 64, 95, 4, 2, 10, 8, 22,
+ 2, 39, 2, 41, 5, 43, 8, 86, 2,102, 2,103, 8,115, 2,119, 5,130, 2,137, 5,142, 8,147, 2,150, 5,151, 8,163, 2, 18,
+ 9, 5, 9, 6, 2, 11, 3, 10, 7, 40, 3, 39, 4, 40, 5, 43, 6, 43, 7, 64, 12,104, 3, 96, 12,137, 3,133, 4,137, 5,141,
+ 6,143, 7,154, 3,151, 7,170, 3,167, 5,182, 7,197, 7,214, 7,247, 3,240, 3,247, 4,240, 4, 26, 93,113, 0, 93, 19, 51,
+ 17, 1, 51, 9, 1, 35, 1, 17, 35,186,185, 2, 37,235,253,174, 2,107,240,253,199,185, 6, 20,252,105, 1,227,253,244,253,172,
+ 2, 35,253,221, 0, 1, 0,193, 0, 0, 1,121, 6, 20, 0, 3, 0, 34,183, 0,151, 2, 1, 8, 0, 70, 4, 16,252,236, 49, 0,
+ 47,236, 48, 64, 13, 16, 5, 64, 5, 80, 5, 96, 5,112, 5,240, 5, 6, 1, 93, 19, 51, 17, 35,193,184,184, 6, 20,249,236, 0,
+ 0, 1, 0,186, 0, 0, 7, 29, 4,123, 0, 34, 0, 90, 64, 38, 6, 18, 9, 24, 15, 0, 6, 29, 7, 21, 12,135, 29, 32, 3,184,
+ 27,188, 25, 16, 7, 0, 17, 15, 8, 8, 6, 80, 17, 8, 15, 80, 28, 24, 8, 26, 70, 35, 16,252,236, 50,252,252,252,236, 17, 18,
+ 57, 49, 0, 47, 60, 60,228,244, 60,196,236, 50, 17, 18, 23, 57, 48, 64, 19, 48, 36, 80, 36,112, 36,144, 36,160, 36,160, 36,191,
+ 36,223, 36,255, 36, 9, 1, 93, 1, 62, 1, 51, 50, 22, 21, 17, 35, 17, 52, 38, 35, 34, 6, 21, 17, 35, 17, 52, 38, 35, 34, 6,
+ 21, 17, 35, 17, 51, 21, 62, 1, 51, 50, 22, 4, 41, 69,192,130,175,190,185,114,117,143,166,185,114,119,141,166,185,185, 63,176,
+121,122,171, 3,137,124,118,245,226,253, 92, 2,158,161,156,190,164,253,135, 2,158,162,155,191,163,253,135, 4, 96,174,103, 98,
+124, 0, 0, 0, 0, 1, 0,186, 0, 0, 4,100, 4,123, 0, 19, 0, 54, 64, 25, 3, 9, 0, 3, 14, 1, 6,135, 14, 17,184, 12,
+188, 10, 1, 2, 8, 0, 78, 13, 9, 8, 11, 70, 20, 16,252,236, 50,244,236, 49, 0, 47, 60,228,244,196,236, 17, 18, 23, 57, 48,
+180, 96, 21,207, 21, 2, 1, 93, 1, 17, 35, 17, 52, 38, 35, 34, 6, 21, 17, 35, 17, 51, 21, 62, 1, 51, 50, 22, 4,100,184,124,
+124,149,172,185,185, 66,179,117,193,198, 2,164,253, 92, 2,158,159,158,190,164,253,135, 4, 96,174,101,100,239, 0, 2, 0,113,
+255,227, 4,117, 4,123, 0, 11, 0, 23, 0, 74, 64, 19, 6,185, 18, 0,185, 12,184, 18,140, 24, 9, 18, 15, 81, 3, 18, 21, 69,
+ 24, 16,252,236,244,236, 49, 0, 16,228,244,236, 16,238, 48, 64, 35, 63, 25,123, 0,123, 6,127, 7,127, 8,127, 9,127, 10,127,
+ 11,123, 12,127, 13,127, 14,127, 15,127, 16,127, 17,123, 18,160, 25,240, 25, 17, 1, 93, 1, 34, 6, 21, 20, 22, 51, 50, 54, 53,
+ 52, 38, 39, 50, 0, 17, 16, 0, 35, 34, 0, 17, 16, 0, 2,115,148,172,171,149,147,172,172,147,240, 1, 18,254,238,240,241,254,
+239, 1, 17, 3,223,231,201,201,231,232,200,199,233,156,254,200,254,236,254,237,254,199, 1, 57, 1, 19, 1, 20, 1, 56, 0, 0,
+ 0, 2, 0,186,254, 86, 4,164, 4,123, 0, 16, 0, 28, 0, 62, 64, 27, 26,185, 0, 14, 20,185, 5, 8,184, 14,140, 1,189, 3,
+188, 29, 17, 18, 11, 71, 23, 4, 0, 8, 2, 70, 29, 16,252,236, 50, 50,244,236, 49, 0, 16,228,228,228,244,196,236, 16,196,238,
+ 48, 64, 9, 96, 30,128, 30,160, 30,224, 30, 4, 1, 93, 37, 17, 35, 17, 51, 21, 62, 1, 51, 50, 0, 17, 16, 2, 35, 34, 38, 1,
+ 52, 38, 35, 34, 6, 21, 20, 22, 51, 50, 54, 1,115,185,185, 58,177,123,204, 0,255,255,204,123,177, 2, 56,167,146,146,167,167,
+146,146,167,168,253,174, 6, 10,170,100, 97,254,188,254,248,254,248,254,188, 97, 1,235,203,231,231,203,203,231,231, 0, 0, 0,
+ 0, 2, 0,113,254, 86, 4, 90, 4,123, 0, 11, 0, 28, 0, 62, 64, 27, 3,185, 12, 15, 9,185, 24, 21,184, 15,140, 27,189, 25,
+188, 29, 24, 12, 6, 8, 26, 71, 0, 18, 18, 69, 29, 16,252,236,244,236, 50, 50, 49, 0, 16,228,228,228,244,196,236, 16,198,238,
+ 48, 64, 9, 96, 30,128, 30,160, 30,224, 30, 4, 1, 93, 1, 20, 22, 51, 50, 54, 53, 52, 38, 35, 34, 6, 1, 14, 1, 35, 34, 2,
+ 17, 16, 0, 51, 50, 22, 23, 53, 51, 17, 35, 1, 47,167,146,146,168,168,146,146,167, 2,115, 58,177,124,203,255, 0,255,203,124,
+177, 58,184,184, 2, 47,203,231,231,203,203,231,231,253,174,100, 97, 1, 68, 1, 8, 1, 8, 1, 68, 97,100,170,249,246, 0, 0,
+ 0, 1, 0,186, 0, 0, 3, 74, 4,123, 0, 17, 0, 48, 64, 20, 6, 11, 7, 0, 17, 11, 3,135, 14,184, 9,188, 7, 10, 6, 8,
+ 0, 8, 70, 18, 16,252,196,236, 50, 49, 0, 47,228,244,236,196,212,204, 17, 18, 57, 48,180, 80, 19,159, 19, 2, 1, 93, 1, 46,
+ 1, 35, 34, 6, 21, 17, 35, 17, 51, 21, 62, 1, 51, 50, 22, 23, 3, 74, 31, 73, 44,156,167,185,185, 58,186,133, 19, 46, 28, 3,
+180, 18, 17,203,190,253,178, 4, 96,174,102, 99, 5, 5, 0, 0, 0, 1, 0,111,255,227, 3,199, 4,123, 0, 39, 0,231, 64, 60,
+ 13, 12, 2, 14, 11, 83, 31, 30, 8, 9, 2, 7, 10, 83, 30, 31, 30, 66, 10, 11, 30, 31, 4, 21, 0,134, 1,137, 4, 20,134, 21,
+137, 24,185, 17, 4,185, 37,184, 17,140, 40, 30, 10, 11, 31, 27, 7, 0, 82, 27, 8, 14, 7, 8, 20, 34, 69, 40, 16,252,196,236,
+212,236,228, 17, 18, 57, 57, 57, 57, 49, 0, 16,228,244,236, 16,254,245,238, 16,245,238, 18, 23, 57, 48, 75, 83, 88, 7, 16, 14,
+237, 17, 23, 57, 7, 14,237, 17, 23, 57, 89, 34,178, 0, 39, 1, 1, 93, 64,109, 28, 10, 28, 11, 28, 12, 46, 9, 44, 10, 44, 11,
+ 44, 12, 59, 9, 59, 10, 59, 11, 59, 12, 11, 32, 0, 32, 1, 36, 2, 40, 10, 40, 11, 42, 19, 47, 20, 47, 21, 42, 22, 40, 30, 40,
+ 31, 41, 32, 41, 33, 36, 39,134, 10,134, 11,134, 12,134, 13, 18, 0, 0, 0, 1, 2, 2, 6, 10, 6, 11, 3, 12, 3, 13, 3, 14,
+ 3, 15, 3, 16, 3, 25, 3, 26, 3, 27, 3, 28, 4, 29, 9, 39, 47, 41, 63, 41, 95, 41,127, 41,128, 41,144, 41,160, 41,240, 41,
+ 24, 93, 0, 93,113, 1, 21, 46, 1, 35, 34, 6, 21, 20, 22, 31, 1, 30, 1, 21, 20, 6, 35, 34, 38, 39, 53, 30, 1, 51, 50, 54,
+ 53, 52, 38, 47, 1, 46, 1, 53, 52, 54, 51, 50, 22, 3,139, 78,168, 90,137,137, 98,148, 63,196,165,247,216, 90,195,108,102,198,
+ 97,130,140,101,171, 64,171,152,224,206,102,180, 4, 63,174, 40, 40, 84, 84, 64, 73, 33, 14, 42,153,137,156,182, 35, 35,190, 53,
+ 53, 89, 81, 75, 80, 37, 15, 36,149,130,158,172, 30, 0, 0, 0, 0, 1, 0, 55, 0, 0, 2,242, 5,158, 0, 19, 0, 56, 64, 25,
+ 14, 5, 8, 15, 3,169, 0, 17, 1,188, 8,135, 10, 11, 8, 9, 2, 4, 0, 8, 16, 18, 14, 70, 20, 16,252, 60,196,252, 60,196,
+ 50, 57, 57, 49, 0, 47,236,244, 60,196,236, 50, 17, 57, 57, 48,178,175, 21, 1, 1, 93, 1, 17, 33, 21, 33, 17, 20, 22, 59, 1,
+ 21, 35, 34, 38, 53, 17, 35, 53, 51, 17, 1,119, 1,123,254,133, 75,115,189,189,213,162,135,135, 5,158,254,194,143,253,160,137,
+ 78,154,159,210, 2, 96,143, 1, 62, 0, 0, 0, 0, 1, 0,174,255,227, 4, 88, 4, 96, 0, 19, 0, 54, 64, 25, 3, 9, 0, 3,
+ 14, 1, 6,135, 14, 17,140, 10, 1,188, 12, 13, 9, 8, 11, 78, 2, 8, 0, 70, 20, 16,252,236,244,236, 50, 49, 0, 47,228, 50,
+244,196,236, 17, 18, 23, 57, 48,180, 96, 21,207, 21, 2, 1, 93, 19, 17, 51, 17, 20, 22, 51, 50, 54, 53, 17, 51, 17, 35, 53, 14,
+ 1, 35, 34, 38,174,184,124,124,149,173,184,184, 67,177,117,193,200, 1,186, 2,166,253, 97,159,159,190,164, 2,123,251,160,172,
+102, 99,240, 0, 0, 1, 0, 61, 0, 0, 4,127, 4, 96, 0, 6, 0,251, 64, 39, 3, 17, 4, 5, 4, 2, 17, 1, 2, 5, 5, 4,
+ 2, 17, 3, 2, 6, 0, 6, 1, 17, 0, 0, 6, 66, 2, 3, 0,191, 5, 6, 5, 3, 2, 1, 5, 4, 0, 7, 16,212, 75,176, 10,
+ 84, 88,185, 0, 0, 0, 64, 56, 89, 75,176, 20, 84, 75,176, 21, 84, 91, 88,185, 0, 0,255,192, 56, 89,196, 23, 57, 49, 0, 47,
+236, 50, 57, 48, 75, 83, 88, 7, 16, 5,237, 7, 16, 8,237, 7, 16, 8,237, 7, 16, 5,237, 89, 34, 1, 64,142, 72, 2,106, 2,
+123, 2,127, 2,134, 2,128, 2,145, 2,164, 2, 8, 6, 0, 6, 1, 9, 3, 9, 4, 21, 0, 21, 1, 26, 3, 26, 4, 38, 0, 38,
+ 1, 41, 3, 41, 4, 32, 8, 53, 0, 53, 1, 58, 3, 58, 4, 48, 8, 70, 0, 70, 1, 73, 3, 73, 4, 70, 5, 72, 6, 64, 8, 86,
+ 0, 86, 1, 89, 3, 89, 4, 80, 8,102, 0,102, 1,105, 3,105, 4,103, 5,104, 6, 96, 8,117, 0,116, 1,123, 3,123, 4,117,
+ 5,122, 6,133, 0,133, 1,137, 3,137, 4,137, 5,134, 6,150, 0,150, 1,151, 2,154, 3,152, 4,152, 5,151, 6,168, 5,167,
+ 6,176, 8,192, 8,223, 8,255, 8, 62, 93, 0, 93, 19, 51, 9, 1, 51, 1, 35, 61,195, 1, 94, 1, 94,195,254, 92,250, 4, 96,
+252, 84, 3,172,251,160, 0, 0, 0, 1, 0, 86, 0, 0, 6, 53, 4, 96, 0, 12, 1,235, 64, 73, 5, 85, 6, 5, 9, 10, 9, 4,
+ 85, 10, 9, 3, 85, 10, 11, 10, 2, 85, 1, 2, 11, 11, 10, 6, 17, 7, 8, 7, 5, 17, 4, 5, 8, 8, 7, 2, 17, 3, 2, 12,
+ 0, 12, 1, 17, 0, 0, 12, 66, 10, 5, 2, 3, 6, 3, 0,191, 11, 8, 12, 11, 10, 9, 8, 6, 5, 4, 3, 2, 1, 11, 7, 0,
+ 13, 16,212, 75,176, 10, 84, 75,176, 17, 84, 91, 75,176, 18, 84, 91, 75,176, 19, 84, 91, 75,176, 11, 84, 91, 88,185, 0, 0, 0,
+ 64, 56, 89, 1, 75,176, 12, 84, 75,176, 13, 84, 91, 75,176, 16, 84, 91, 88,185, 0, 0,255,192, 56, 89,204, 23, 57, 49, 0, 47,
+ 60,236, 50, 50, 23, 57, 48, 75, 83, 88, 7, 16, 5,237, 7, 16, 8,237, 7, 16, 8,237, 7, 16, 5,237, 7, 16, 8,237, 7, 16,
+ 5,237, 7, 5,237, 7, 16, 8,237, 89, 34, 1, 64,255, 5, 2, 22, 2, 22, 5, 34, 10, 53, 10, 73, 2, 73, 5, 70, 10, 64, 10,
+ 91, 2, 91, 5, 85, 10, 80, 10,110, 2,110, 5,102, 10,121, 2,127, 2,121, 5,127, 5,135, 2,153, 2,152, 5,148, 10,188, 2,
+188, 5,206, 2,199, 3,207, 5, 29, 5, 2, 9, 3, 6, 4, 11, 5, 10, 8, 11, 9, 4, 11, 5, 12, 21, 2, 25, 3, 22, 4, 26,
+ 5, 27, 8, 27, 9, 20, 11, 21, 12, 37, 0, 37, 1, 35, 2, 39, 3, 33, 4, 37, 5, 34, 6, 34, 7, 37, 8, 39, 9, 36, 10, 33,
+ 11, 35, 12, 57, 3, 54, 4, 54, 8, 57, 12, 48, 14, 70, 2, 72, 3, 70, 4, 64, 4, 66, 5, 64, 6, 64, 7, 64, 8, 68, 9, 68,
+ 10, 68, 11, 64, 14, 64, 14, 86, 0, 86, 1, 86, 2, 80, 4, 81, 5, 82, 6, 82, 7, 80, 8, 83, 9, 84, 10, 85, 11, 99, 0,100,
+ 1,101, 2,106, 3,101, 4,106, 5,106, 6,106, 7,110, 9, 97, 11,103, 12,111, 14,117, 0,117, 1,121, 2,125, 3,120, 4,125,
+ 5,122, 6,127, 6,122, 7,127, 7,120, 8,121, 9,127, 9,123, 10,118, 11,125, 12,135, 2,136, 5,143, 14,151, 0,151, 1,148,
+ 2,147, 3,156, 4,155, 5,152, 6,152, 7,153, 8, 64, 47,150, 12,159, 14,166, 0,166, 1,164, 2,164, 3,171, 4,171, 5,169,
+ 6,169, 7,171, 8,164, 12,175, 14,181, 2,177, 3,189, 4,187, 5,184, 9,191, 14,196, 2,195, 3,204, 4,202, 5,121, 93, 0,
+ 93, 19, 51, 27, 1, 51, 27, 1, 51, 1, 35, 11, 1, 35, 86,184,230,229,217,230,229,184,254,219,217,241,242,217, 4, 96,252,150,
+ 3,106,252,150, 3,106,251,160, 3,150,252,106, 0, 1, 0, 59, 0, 0, 4,121, 4, 96, 0, 11, 1, 67, 64, 70, 5, 17, 6, 7,
+ 6, 4, 17, 3, 4, 7, 7, 6, 4, 17, 5, 4, 1, 2, 1, 3, 17, 2, 2, 1, 11, 17, 0, 1, 0, 10, 17, 9, 10, 1, 1, 0,
+ 10, 17, 11, 10, 7, 8, 7, 9, 17, 8, 8, 7, 66, 10, 7, 4, 1, 4, 8, 0,191, 5, 2, 10, 7, 4, 1, 4, 8, 0, 2, 8,
+ 6, 12, 16,212, 75,176, 10, 84, 75,176, 15, 84, 91, 75,176, 16, 84, 91, 75,176, 17, 84, 91, 88,185, 0, 6, 0, 64, 56, 89, 75,
+176, 20, 84, 88,185, 0, 6,255,192, 56, 89,196,212,196, 17, 23, 57, 49, 0, 47, 60,236, 50, 23, 57, 48, 75, 83, 88, 7, 16, 5,
+237, 7, 16, 8,237, 7, 16, 8,237, 7, 16, 5,237, 7, 16, 5,237, 7, 16, 8,237, 7, 16, 8,237, 7, 16, 5,237, 89, 34, 1,
+ 64,152, 10, 4, 4, 10, 26, 4, 21, 10, 38, 10, 61, 4, 49, 10, 85, 4, 87, 7, 88, 10,102, 10,118, 1,122, 4,118, 7,116, 10,
+141, 4,130, 10,153, 4,159, 4,151, 7,146, 10,144, 10,166, 1,169, 4,175, 4,165, 7,163, 10,160, 10, 28, 10, 3, 4, 5, 5,
+ 9, 10, 11, 26, 3, 21, 5, 21, 9, 26, 11, 41, 3, 38, 5, 37, 9, 42, 11, 32, 13, 58, 1, 57, 3, 55, 5, 52, 7, 54, 9, 57,
+ 11, 48, 13, 73, 3, 70, 5, 69, 9, 74, 11, 64, 13, 89, 0, 86, 1, 89, 2, 89, 3, 87, 5, 86, 6, 89, 7, 86, 8, 86, 9, 89,
+ 11, 80, 13,111, 13,120, 1,127, 13,155, 1,148, 7,171, 1,164, 7,176, 13,207, 13,223, 13,255, 13, 47, 93, 0, 93, 9, 2, 35,
+ 9, 1, 35, 9, 1, 51, 9, 1, 4,100,254,107, 1,170,217,254,186,254,186,217, 1,179,254,114,217, 1, 41, 1, 41, 4, 96,253,
+223,253,193, 1,184,254, 72, 2, 74, 2, 22,254,113, 1,143, 0, 0, 1, 0, 61,254, 86, 4,127, 4, 96, 0, 15, 1,139, 64, 67,
+ 7, 8, 2, 9, 17, 0, 15, 10, 17, 11, 10, 0, 0, 15, 14, 17, 15, 0, 15, 13, 17, 12, 13, 0, 0, 15, 13, 17, 14, 13, 10, 11,
+ 10, 12, 17, 11, 11, 10, 66, 13, 11, 9, 16, 0, 11, 5,135, 3,189, 14, 11,188, 16, 14, 13, 12, 10, 9, 6, 3, 0, 8, 15, 4,
+ 15, 11, 16, 16,212, 75,176, 10, 84, 75,176, 8, 84, 91, 88,185, 0, 11, 0, 64, 56, 89, 75,176, 20, 84, 88,185, 0, 11,255,192,
+ 56, 89,196,196, 17, 23, 57, 49, 0, 16,228, 50,244,236, 17, 57, 17, 57, 18, 57, 48, 75, 83, 88, 7, 16, 5,237, 7, 16, 8,237,
+ 7, 16, 8,237, 7, 16, 5,237, 7, 16, 8,237, 7, 5,237, 23, 50, 89, 34, 1, 64,240, 6, 0, 5, 8, 6, 9, 3, 13, 22, 10,
+ 23, 13, 16, 13, 35, 13, 53, 13, 73, 10, 79, 10, 78, 13, 90, 9, 90, 10,106, 10,135, 13,128, 13,147, 13, 18, 10, 0, 10, 9, 6,
+ 11, 5, 12, 11, 14, 11, 15, 23, 1, 21, 2, 16, 4, 16, 5, 23, 10, 20, 11, 20, 12, 26, 14, 26, 15, 39, 0, 36, 1, 36, 2, 32,
+ 4, 32, 5, 41, 8, 40, 9, 37, 10, 36, 11, 36, 12, 39, 13, 42, 14, 42, 15, 32, 17, 55, 0, 53, 1, 53, 2, 48, 4, 48, 5, 56,
+ 10, 54, 11, 54, 12, 56, 13, 57, 14, 57, 15, 48, 17, 65, 0, 64, 1, 64, 2, 64, 3, 64, 4, 64, 5, 64, 6, 64, 7, 64, 8, 66,
+ 9, 69, 10, 71, 13, 73, 14, 73, 15, 64, 17, 84, 0, 81, 1, 81, 2, 85, 3, 80, 4, 80, 5, 86, 6, 85, 7, 86, 8, 87, 9, 87,
+ 10, 85, 11, 85, 12, 89, 14, 89, 15, 80, 17,102, 1,102, 2,104, 10,105, 14,105, 15, 96, 17,123, 8,120, 14,120, 15,137, 0,138,
+ 9,133, 11,133, 12,137, 13,137, 14,137, 15,153, 9,149, 11,149, 12,154, 14,154, 15,164, 11,164, 12,171, 14,171, 15,176, 17,207,
+ 17,223, 17,255, 17,101, 93, 0, 93, 5, 14, 1, 43, 1, 53, 51, 50, 54, 63, 1, 1, 51, 9, 1, 51, 2,147, 78,148,124,147,108,
+ 76, 84, 51, 33,254, 59,195, 1, 94, 1, 94,195,104,200,122,154, 72,134, 84, 4, 78,252,148, 3,108, 0, 0, 0, 0, 1, 0, 88,
+ 0, 0, 3,219, 4, 96, 0, 9, 0,157, 64, 26, 8, 17, 2, 3, 2, 3, 17, 7, 8, 7, 66, 8,169, 0,188, 3,169, 5, 8, 3,
+ 1, 0, 4, 1, 6, 10, 16,220, 75,176, 11, 84, 75,176, 12, 84, 91, 88,185, 0, 6,255,192, 56, 89, 75,176, 19, 84, 88,185, 0,
+ 6, 0, 64, 56, 89,196, 50,196, 17, 57, 57, 49, 0, 47,236,244,236, 48, 75, 83, 88, 7, 16, 5,237, 7, 16, 5,237, 89, 34, 1,
+ 64, 66, 5, 2, 22, 2, 38, 2, 71, 2, 73, 7, 5, 11, 8, 15, 11, 24, 3, 27, 8, 43, 8, 32, 11, 54, 3, 57, 8, 48, 11, 64,
+ 1, 64, 2, 69, 3, 64, 4, 64, 5, 67, 8, 87, 3, 89, 8, 95, 11, 96, 1, 96, 2,102, 3, 96, 4, 96, 5, 98, 8,127, 11,128,
+ 11,175, 11, 27, 93, 0, 93, 19, 33, 21, 1, 33, 21, 33, 53, 1, 33,113, 3,106,253, 76, 2,180,252,125, 2,180,253,101, 4, 96,
+168,252,219,147,168, 3, 37, 0, 0, 1, 1, 0,254,178, 4, 23, 6, 20, 0, 36, 0,119, 64, 52, 25, 15, 21, 11, 6, 37, 9, 26,
+ 16, 21, 29, 11, 5, 32, 33, 3, 0, 11,169, 9, 0,169, 1,192, 9, 21,169, 19,177, 37, 12, 9, 10, 5, 36, 22, 25, 0, 29, 10,
+ 5, 19, 2, 20, 0, 32, 25, 67, 10, 15, 5, 37, 16,212, 75,176, 12, 84, 88,185, 0, 5, 0, 64, 56, 89, 60,196,252, 60,196, 50,
+ 57, 57, 17, 18, 57, 17, 18, 57, 57, 17, 18, 57, 57, 49, 0, 16,252,236,196,244,236, 16,238, 18, 23, 57, 18, 57, 17, 57, 57, 17,
+ 18, 57, 17, 18, 57, 57, 48, 1,178, 0, 38, 1, 93, 5, 21, 35, 34, 38, 61, 1, 52, 38, 43, 1, 53, 51, 50, 54, 61, 1, 52, 54,
+ 59, 1, 21, 35, 34, 6, 29, 1, 20, 6, 7, 30, 1, 29, 1, 20, 22, 51, 4, 23, 62,249,169,108,142, 61, 61,143,107,169,249, 62,
+ 68,141, 86, 91,110,111, 90, 86,141,190,144,148,221,239,151,116,143,115,149,240,221,147,143, 88,141,248,157,142, 25, 27,142,156,
+248,141, 88, 0, 0, 1, 1, 4,254, 29, 1,174, 6, 29, 0, 3, 0, 18,183, 1, 0,177, 4, 0, 5, 2, 4, 16,212,236, 49, 0,
+ 16,252,204, 48, 1, 17, 35, 17, 1,174,170, 6, 29,248, 0, 8, 0, 0, 0, 0, 0, 1, 1, 0,254,178, 4, 23, 6, 20, 0, 36,
+ 0,135, 64, 54, 31, 37, 27, 22, 12, 15, 8, 27, 11, 21, 25, 15, 4, 5, 32, 3, 0, 25,169, 27, 0,169, 35,192, 27, 15,169, 17,
+177, 37, 28, 25, 26, 21, 15, 1, 4, 0, 8, 26, 21, 35, 18, 4, 0, 26, 31, 21, 67, 16, 0, 11, 4, 37, 16,212, 75,176, 10, 84,
+ 88,185, 0, 4,255,192, 56, 89, 75,176, 14, 84, 88,185, 0, 4, 0, 64, 56, 89, 60,196, 50,252, 60,196, 17, 18, 57, 57, 17, 18,
+ 57, 17, 18, 57, 57, 17, 18, 57, 57, 49, 0, 16,252,236,196,244,236, 16,238, 18, 23, 57, 17, 18, 57, 57, 17, 57, 17, 57, 57, 17,
+ 18, 57, 48, 1,178, 0, 38, 1, 93, 5, 51, 50, 54, 61, 1, 52, 54, 55, 46, 1, 61, 1, 52, 38, 43, 1, 53, 51, 50, 22, 29, 1,
+ 20, 22, 59, 1, 21, 35, 34, 6, 29, 1, 20, 6, 43, 1, 1, 0, 70,140, 85, 90,111,111, 90, 85,140, 70, 63,249,167,108,142, 62,
+ 62,142,108,167,249, 63,190, 86,143,248,156,142, 27, 25,142,157,248,142, 87,143,147,221,240,149,115,143,116,151,239,221,148, 0,
+ 0, 1, 0,217, 1,211, 5,219, 3, 49, 0, 29, 0, 35, 64, 16, 1, 16, 27, 12, 0, 19, 4,156, 27, 19,156, 12, 30, 0, 15, 30,
+ 16,212,196, 49, 0, 16,212,252,212,236, 16,192, 17, 18, 57, 57, 48, 1, 21, 14, 1, 35, 34, 39, 38, 39, 38, 39, 38, 35, 34, 6,
+ 7, 53, 62, 1, 51, 50, 23, 22, 23, 22, 23, 22, 51, 50, 54, 5,219,105,179, 97,110,146, 11, 5, 7, 15,155, 94, 88,172, 98,105,
+179, 97,110,147, 10, 5, 8, 14,155, 94, 86,169, 3, 49,178, 79, 68, 59, 4, 2, 3, 5, 62, 77, 83,178, 79, 69, 60, 4, 2, 3,
+ 5, 62, 76, 0, 0, 2, 1, 53, 0, 0, 2, 0, 5,213, 0, 3, 0, 9, 0, 98, 64, 15, 7, 0,131, 2,129, 4, 8, 7, 4, 0,
+ 3, 5, 1, 0, 10, 16,252, 60,236, 50, 57, 57, 49, 0, 47,244,252,204, 48, 1, 75,176, 11, 84, 88,189, 0, 10, 0, 64, 0, 1,
+ 0, 10, 0, 10,255,192, 56, 17, 55, 56, 89, 1, 75,176, 15, 84, 75,176, 16, 84, 91, 75,176, 19, 84, 91, 88,189, 0, 10,255,192,
+ 0, 1, 0, 10, 0, 10, 0, 64, 56, 17, 55, 56, 89,182, 0, 11, 32, 11, 80, 11, 3, 93, 1, 35, 53, 51, 17, 35, 17, 19, 51, 19,
+ 2, 0,203,203,203, 21,162, 20, 4,215,254,250, 43, 2,143, 1,101,254,155, 0, 0, 2, 0,172,254,199, 4, 35, 5,152, 0, 6,
+ 0, 33, 0, 81, 64, 43, 19, 22, 20, 0, 15, 12, 1, 11, 7,134, 8,136, 11, 16,134, 15,136, 12,185, 20, 22, 11,185, 29, 31, 28,
+184, 22,140, 34, 28, 21, 0, 9, 30, 19, 11, 15, 7, 4, 18, 25, 34, 16,220,236,212, 60,212, 60, 60,236, 50, 50, 49, 0, 16,228,
+244, 60,196,236, 16,196,254,244,238, 16,245,238, 18, 57, 17, 18, 57, 17, 18, 57, 48, 37, 17, 14, 1, 21, 20, 22, 1, 21, 46, 1,
+ 39, 3, 62, 1, 55, 21, 14, 1, 7, 17, 35, 17, 38, 0, 17, 16, 0, 55, 17, 51, 19, 30, 1, 2,166,147,164,164, 2, 16, 74,136,
+ 68, 1, 70,137, 72, 65,137, 77,102,241,254,247, 1, 9,241,102, 1, 73,137,131, 3, 88, 18,226,184,185,226, 3,161,172, 41, 42,
+ 3,252,160, 5, 42, 39,170, 30, 35, 7,254,228, 1, 32, 20, 1, 51, 1, 1, 1, 2, 1, 50, 22, 1, 31,254,225, 4, 33, 0, 0,
+ 0, 1, 0,129, 0, 0, 4, 98, 5,240, 0, 27, 0, 96, 64, 33, 7, 22, 8, 1,134, 0, 18, 10,169, 20, 8, 12, 4,160, 0,148,
+ 25,145, 16, 12,160, 14, 0, 13, 9, 11, 7, 28, 19, 15, 21, 17, 28, 16,220, 60,204,204,252, 60,196,212,196, 49, 0, 47,236, 50,
+244,228,236, 16,212, 60,238, 50, 16,238, 17, 57, 57, 48, 1, 75,176, 12, 84, 88,189, 0, 28,255,192, 0, 1, 0, 28, 0, 28, 0,
+ 64, 56, 17, 55, 56, 89,180, 54, 1, 54, 2, 2, 0, 93, 1, 21, 46, 1, 35, 34, 6, 29, 1, 33, 21, 33, 17, 33, 21, 33, 53, 51,
+ 17, 35, 53, 51, 53, 16, 54, 51, 50, 22, 4, 78, 76,136, 61,148,116, 1,135,254,121, 2, 45,252, 31,236,199,199,214,232, 61,151,
+ 5,180,182, 41, 41,155,212,215,143,254, 47,170,170, 1,209,143,238, 1, 5,243, 31, 0, 0, 0, 0, 2, 0, 94, 0, 82, 4,188,
+ 4,178, 0, 35, 0, 47, 0,131, 64, 73, 3, 9, 27, 21, 4, 45, 30, 0, 39, 28, 2, 33, 29, 12, 18, 45, 20, 11, 10, 3, 19, 15,
+ 1, 29, 45,185, 19,235, 15,236, 39,185, 29,235, 33, 48, 30, 12, 0, 18, 4, 42, 36, 20, 48, 28, 21, 27, 42, 29, 19, 28, 24, 9,
+ 3, 36, 11, 10, 1, 3, 2, 36, 40, 2,115, 6,116, 42, 40, 28,115, 24, 48, 16,220,228,236,244,228,236, 18, 23, 57, 18, 57, 57,
+ 17, 18, 57, 57, 18, 57, 57, 17, 18, 57, 17, 18, 23, 57, 49, 0, 16,212,228,236,244,228,236, 16,192, 17, 18, 23, 57, 18, 57, 57,
+ 17, 18, 57, 57, 17, 57, 57, 18, 23, 57, 48, 1, 55, 23, 7, 30, 1, 21, 20, 6, 7, 23, 7, 39, 14, 1, 35, 34, 38, 39, 7, 39,
+ 55, 46, 1, 53, 52, 54, 55, 39, 55, 23, 62, 1, 51, 50, 22, 19, 52, 38, 35, 34, 6, 21, 20, 22, 51, 50, 54, 3,123,207,114,206,
+ 37, 36, 38, 40,209,114,207, 59,116, 61, 58,120, 61,207,113,207, 37, 37, 38, 38,207,115,207, 55,116, 64, 60,117, 92,155,114,112,
+158,157,113,113,156, 3,225,209,115,206, 59,119, 62, 63,115, 57,207,113,207, 40, 38, 37, 37,207,115,206, 62,118, 58, 64,116, 56,
+206,115,207, 39, 37, 36,254,124,112,154,154,112,114,156,157, 0, 0, 1, 0, 82, 0, 0, 4,195, 5,213, 0, 24, 0,198, 64, 70,
+ 16, 2, 17, 22, 17, 15, 2, 14, 15, 22, 22, 17, 15, 2, 16, 15, 8, 13, 8, 14, 2, 13, 13, 8, 66, 15, 11, 9, 4, 0,211, 23,
+ 6, 18, 11,211, 20, 9, 16, 13,129, 2, 12, 9, 14, 3, 5, 22, 15, 3, 21, 18, 16, 3, 0, 17,102, 19, 0,101, 1, 28, 13,102,
+ 10, 5,101, 7, 3, 25, 16,212, 60,236, 50,236,252,236, 50,236, 18, 23, 57, 18, 57, 57, 17, 23, 57, 49, 0, 47,228, 50,212, 60,
+236, 50,212, 60,236, 50, 17, 18, 57, 48, 75, 83, 88, 7, 16, 5,237, 7, 16, 8,237, 7, 16, 8,237, 7, 16, 5,237, 89, 34, 1,
+ 75,176, 12, 84, 88,189, 0, 25,255,192, 0, 1, 0, 25, 0, 25, 0, 64, 56, 17, 55, 56, 89, 64, 40,134, 15,144, 15,166, 15,160,
+ 15,181, 15, 5, 39, 12, 39, 13, 39, 14, 41, 16, 40, 17, 40, 18, 55, 14, 57, 16,135, 12,136, 18,166, 13,165, 14,170, 16,169, 17,
+ 14, 93, 0, 93, 1, 33, 17, 35, 17, 33, 53, 33, 53, 39, 33, 53, 33, 1, 51, 9, 1, 51, 1, 33, 21, 33, 7, 21, 33, 4,141,254,
+ 99,201,254, 96, 1,160, 84,254,180, 1, 8,254,195,190, 1,123, 1,121,191,254,194, 1, 8,254,181, 84, 1,159, 1,199,254, 57,
+ 1,199,123, 51,155,123, 2, 74,253, 68, 2,188,253,182,123,155, 51, 0, 0, 0, 0, 2, 1, 4,254,162, 1,174, 5,152, 0, 3,
+ 0, 7, 0, 28, 64, 13, 1,245, 0, 4,245, 5, 8, 4, 0, 5, 6, 2, 8, 16,220, 60,236, 50, 49, 0, 16,212,236,212,236, 48,
+ 1, 17, 35, 17, 19, 17, 35, 17, 1,174,170,170,170, 1,152,253, 10, 2,246, 4, 0,253, 10, 2,246, 0, 0, 0, 0, 2, 0, 92,
+255, 61, 3,162, 5,240, 0, 11, 0, 62, 0,145, 64, 60, 47, 48, 42, 6, 0, 23, 29, 48, 54, 4, 13, 39,138, 38, 13,138, 12, 42,
+198, 38,197, 35, 16,198, 12,197, 60,145, 35, 63, 47, 6, 0, 23, 48, 4, 19, 29, 45, 9, 54, 3, 19, 87, 57, 45, 87, 32, 9, 87,
+ 12, 34, 26, 57, 38, 34, 3, 87, 51, 63, 16,220,236,228,196,212,228,236,212,236, 16,238, 17, 57, 17, 18, 57, 17, 23, 57, 57, 49,
+ 0, 16,196,244,228,236, 16,230,238, 16,238, 16,238, 17, 23, 57, 57, 57, 17, 18, 57, 48, 1, 75,176, 10, 84, 75,176, 11, 84, 91,
+ 75,176, 12, 84, 91, 75,176, 14, 84, 91, 88,189, 0, 63, 0, 64, 0, 1, 0, 63, 0, 63,255,192, 56, 17, 55, 56, 89, 1, 14, 1,
+ 21, 20, 22, 23, 62, 1, 53, 52, 38, 19, 21, 46, 1, 35, 34, 6, 21, 20, 23, 22, 23, 30, 1, 21, 20, 6, 7, 30, 1, 21, 20, 6,
+ 35, 34, 38, 39, 53, 30, 1, 51, 50, 54, 53, 52, 47, 1, 46, 1, 53, 52, 54, 55, 46, 1, 53, 52, 54, 51, 50, 22, 1,123, 63, 62,
+139,250, 63, 62,143,204, 83,143, 56, 97,108,206, 26, 14,211,131, 92, 93, 62, 57,204,173, 73,154, 88, 87,148, 58,102,113,221, 25,
+214,128, 93, 91, 59, 59,200,166, 73,153, 3,168, 46, 90, 46, 76,133,135, 45, 91, 46, 75,136, 2,147,164, 39, 39, 80, 71, 90,115,
+ 15, 8,119,154,101, 90,140, 53, 52,109, 64,142,168, 29, 29,164, 39, 39, 84, 76,102,123, 14,120,153,102, 91,143, 49, 44,112, 69,
+130,159, 29, 0, 0, 2, 0,215, 5, 70, 3, 41, 6, 16, 0, 3, 0, 7, 0,146, 64, 14, 6, 2,206, 4, 0,205, 8, 1,100, 0,
+ 5,100, 4, 8, 16,220,252,212,236, 49, 0, 16,252, 60,236, 50, 48, 0, 75,176, 10, 84, 75,176, 13, 84, 91, 88,189, 0, 8, 0,
+ 64, 0, 1, 0, 8, 0, 8,255,192, 56, 17, 55, 56, 89, 1, 75,176, 12, 84, 75,176, 13, 84, 91, 75,176, 14, 84, 91, 75,176, 23,
+ 84, 91, 88,189, 0, 8,255,192, 0, 1, 0, 8, 0, 8, 0, 64, 56, 17, 55, 56, 89, 1, 75,176, 15, 84, 75,176, 25, 84, 91, 88,
+189, 0, 8, 0, 64, 0, 1, 0, 8, 0, 8,255,192, 56, 17, 55, 56, 89, 64, 17, 96, 1, 96, 2, 96, 5, 96, 6,112, 1,112, 2,
+112, 5,112, 6, 8, 93, 1, 51, 21, 35, 37, 51, 21, 35, 2, 94,203,203,254,121,203,203, 6, 16,202,202,202, 0, 0, 3, 1, 27,
+ 0, 0, 6,229, 5,205, 0, 23, 0, 47, 0, 73, 0, 67, 64, 38, 61,203, 62, 58,204, 65,202, 36, 49,203, 48, 52,204, 71,202, 24,
+201, 0,200, 36,201, 12, 55, 97, 68, 61, 48, 94, 42, 9, 6, 68, 94, 30, 9, 6, 18, 74, 16,220,204,252,236, 16,254,237, 50, 16,
+238, 49, 0, 47,238,246,254,253,238,214,238, 16,253,238,214,238, 48, 1, 50, 4, 23, 22, 18, 21, 20, 2, 7, 6, 4, 35, 34, 36,
+ 39, 38, 2, 53, 52, 18, 55, 54, 36, 23, 34, 6, 7, 14, 1, 21, 20, 22, 23, 30, 1, 51, 50, 54, 55, 62, 1, 53, 52, 38, 39, 46,
+ 1, 23, 21, 46, 1, 35, 34, 6, 21, 20, 22, 51, 50, 54, 55, 21, 14, 1, 35, 34, 38, 53, 52, 54, 51, 50, 22, 4, 0,152, 1, 7,
+109,109,108,108,109,109,254,249,152,152,254,249,109,109,108,108,109,109, 1, 7,152,131,226, 94, 94, 96, 96, 94, 94,226,131,132,
+227, 94, 93, 93, 94, 92, 94,227,167, 66,130, 66,149,167,171,155, 64,122, 66, 67,137, 70,216,251,251,216, 73,136, 5,205,110,109,
+109,254,250,154,152,254,251,109,109,110,110,109,109, 1, 5,152,154, 1, 6,109,109,110,103, 94, 94, 94,229,130,129,227, 94, 94,
+ 95, 95, 94, 93,226,131,133,227, 93, 94, 94,245,129, 33, 32,175,157,159,174, 31, 34,127, 29, 28,244,208,209,242, 28, 0, 0, 0,
+ 0, 3, 0,115, 1,213, 3, 59, 5,240, 0, 3, 0, 30, 0, 41, 0, 95, 64, 51, 40, 7, 37, 4, 31, 18, 24, 16, 2,227, 0, 31,
+221, 16, 0,225, 37,221, 5, 10, 25,223, 24,222, 21,221, 10,224, 28,145, 42, 0, 24, 13, 31, 16, 34, 6, 2, 1, 40, 17, 6,107,
+ 4,108, 24, 34,107, 13, 42, 16,220,236,204,252,236, 50, 50,192,192, 17, 18, 57, 57, 17, 18, 57, 49, 0, 16,244,228,252,244,236,
+ 16,196,238,237,214,238, 16,238, 17, 18, 57, 18, 57, 17, 57, 57, 48, 19, 33, 21, 33, 1, 17, 35, 53, 14, 1, 35, 34, 38, 53, 52,
+ 54, 59, 1, 53, 52, 38, 35, 34, 6, 7, 53, 62, 1, 51, 50, 22, 5, 34, 6, 21, 20, 22, 51, 50, 54, 61, 1,139, 2,176,253, 80,
+ 2,174,149, 44,144, 93,128,152,191,188,182,117,117, 62,136, 68, 73,145, 69,183,179,254,236,161,126, 98, 82,104,130, 2, 80,123,
+ 2,184,254, 64,112, 63, 68,135,113,135,138, 4, 91, 91, 34, 34,127, 28, 28,176,240, 67, 79, 64, 77,144,114, 29, 0, 2, 0,158,
+ 0,141, 4, 37, 4, 35, 0, 6, 0, 13, 0,134, 64, 73, 3,232, 4, 5, 4, 2,232, 1, 2, 5, 5, 4, 2,232, 3, 2, 6, 0,
+ 6, 1,232, 0, 0, 6, 10,232, 11, 12, 11, 9,232, 8, 9, 12, 12, 11, 9,232, 10, 9, 13, 7, 13, 8,232, 7, 7, 13, 66, 9,
+ 2, 11, 4,231, 7, 0,166, 14, 9, 12, 5, 2, 7, 3, 0,111, 5, 10, 7,111, 12,110, 14, 16,252,252, 60,212,236, 50, 17, 57,
+ 17, 18, 57, 49, 0, 16,244, 60,236, 50, 57, 57, 48, 75, 83, 88, 7, 16, 4,237, 7, 16, 8,237, 7, 16, 8,237, 7, 16, 4,237,
+ 7, 16, 4,237, 7, 16, 8,237, 7, 16, 8,237, 7, 16, 4,237, 89, 34, 1, 21, 9, 1, 21, 1, 53, 19, 21, 9, 1, 21, 1, 53,
+ 4, 37,254,211, 1, 45,254, 43, 35,254,211, 1, 45,254, 43, 4, 35,191,254,244,254,244,191, 1,162, 82, 1,162,191,254,244,254,
+244,191, 1,162, 82, 0, 0, 0, 0, 1, 0,217, 1, 31, 5,219, 3, 94, 0, 5, 0, 23, 64, 10, 4,156, 2, 0, 6, 3, 23, 1,
+ 0, 6, 16,220,212,236, 49, 0, 16,212,196,236, 48, 19, 33, 17, 35, 17, 33,217, 5, 2,168,251,166, 3, 94,253,193, 1,149, 0,
+ 0, 1, 0,100, 1,223, 2,127, 2,131, 0, 3, 0, 17,182, 0,156, 2, 4, 1, 0, 4, 16,220,204, 49, 0, 16,212,236, 48, 19,
+ 33, 21, 33,100, 2, 27,253,229, 2,131,164, 0, 0, 4, 1, 27, 0, 0, 6,229, 5,205, 0, 23, 0, 47, 0, 56, 0, 76, 0, 96,
+ 64, 54, 69, 66, 67, 63, 50,201, 72, 48,201, 57, 74, 67,202, 12, 57,202, 0,201, 24,200, 12,201, 36, 72, 69, 51, 48, 4, 49, 66,
+ 60, 63, 57, 54, 73, 49, 96, 75, 54, 96, 67, 60, 94, 18, 9, 30, 75, 94, 6, 9, 30, 95, 42, 77, 16,220,228,252,236, 16,254,253,
+196,238, 16,238, 50, 17, 57, 57, 18, 57, 18, 23, 57, 49, 0, 47,238,246,254,237, 16,237, 50, 16,238,214,238, 57, 18, 57, 57, 48,
+ 1, 34, 6, 7, 14, 1, 21, 20, 22, 23, 30, 1, 51, 50, 54, 55, 62, 1, 53, 52, 38, 39, 46, 1, 39, 50, 4, 23, 22, 18, 21, 20,
+ 2, 7, 6, 4, 35, 34, 36, 39, 38, 2, 53, 52, 18, 55, 54, 36, 19, 35, 17, 51, 50, 54, 53, 52, 38, 39, 50, 22, 21, 20, 6, 7,
+ 30, 1, 31, 1, 35, 39, 46, 1, 43, 1, 17, 35, 17, 4, 0,131,226, 94, 94, 96, 96, 94, 94,226,131,132,227, 94, 93, 93, 94, 92,
+ 94,227,132,152, 1, 7,109,109,108,108,109,109,254,249,152,152,254,249,109,109,108,108,109,109, 1, 7,125,123,123,110, 87, 88,
+102,176,174,105, 96, 24, 67, 46,137,172,129, 59, 73, 54, 66,155, 5,102, 94, 94, 94,229,130,129,227, 94, 94, 95, 95, 94, 93,226,
+131,133,227, 93, 94, 94,103,110,109,109,254,250,154,152,254,251,109,109,110,110,109,109, 1, 5,152,154, 1, 6,109,109,110,254,
+ 98,254,236, 62, 75, 76, 63,103,119,121, 86,112, 17, 8, 77, 73,223,209, 96, 51,254,156, 3, 68, 0, 1, 0,213, 5, 98, 3, 43,
+ 5,246, 0, 3, 0, 47,183, 2,239, 0,238, 4, 1, 0, 4, 16,212,204, 49, 0, 16,252,236, 48, 0, 75,176, 9, 84, 75,176, 14,
+ 84, 91, 88,189, 0, 4,255,192, 0, 1, 0, 4, 0, 4, 0, 64, 56, 17, 55, 56, 89, 19, 33, 21, 33,213, 2, 86,253,170, 5,246,
+148, 0, 0, 0, 0, 2, 0,195, 3,117, 3, 61, 5,240, 0, 11, 0, 26, 0, 32, 64, 17, 6,195, 21,196, 0,195, 12,145, 27, 9,
+ 90, 18, 91, 3, 90, 24, 27, 16,220,236,252,236, 49, 0, 16,244,236,252,236, 48, 1, 34, 6, 21, 20, 22, 51, 50, 54, 53, 52, 38,
+ 39, 50, 22, 23, 30, 1, 21, 20, 6, 35, 34, 38, 53, 52, 54, 2, 0, 80,110,110, 80, 80,110,111, 79, 64,118, 43, 46, 46,185,134,
+135,180,184, 5,111,111, 80, 79,109,109, 79, 79,112,129, 49, 46, 45,114, 66,132,183,180,135,134,186, 0, 0, 0, 0, 2, 0,217,
+ 0, 0, 5,219, 5, 4, 0, 11, 0, 15, 0, 46, 64, 24, 5,208, 7, 3,156, 0,208, 9, 1, 12,156, 14, 13, 2, 21, 4, 0, 23,
+ 12, 8, 21, 10, 6, 16, 16,212, 60,236, 50,252, 60,236, 50, 49, 0, 47,236,212, 60,236,252, 60,236, 48, 1, 17, 33, 21, 33, 17,
+ 35, 17, 33, 53, 33, 17, 1, 33, 21, 33, 3,174, 2, 45,253,211,168,253,211, 2, 45,253,211, 5, 2,250,254, 5, 4,254,125,170,
+254,125, 1,131,170, 1,131,251,166,170, 0, 0, 0, 1, 0, 94, 2,156, 2,180, 5,240, 0, 24, 0, 74, 64, 36, 0,125, 6, 4,
+ 0, 23,125, 6, 6, 4, 66, 4, 2, 0, 14,221, 15, 0,221, 2,247, 11,221, 15, 18,145, 25, 0, 14, 8,126, 1, 21, 14, 3, 25,
+ 16,220,196,212,196,236, 17, 57, 49, 0, 16,244,196,236,252,236, 16,238, 17, 18, 57, 48, 75, 83, 88, 7, 16, 5,237, 23, 50, 7,
+ 5,237, 89, 34, 1, 33, 21, 33, 53, 54, 55, 0, 53, 52, 38, 35, 34, 6, 7, 53, 62, 1, 51, 50, 22, 21, 20, 1, 6, 1, 12, 1,
+168,253,170, 34, 63, 1, 88,104, 85, 52,122, 72, 77,133, 57,145,174,254,181, 56, 3, 14,114,110, 31, 56, 1, 49, 94, 66, 81, 35,
+ 35,123, 28, 28,132,108,139,254,228, 48, 0, 0, 0, 1, 0, 98, 2,141, 2,205, 5,240, 0, 40, 0, 72, 64, 39, 0, 21, 19, 10,
+221, 9, 31,221, 32, 19,221, 21, 13,221, 9,248, 6,247, 28,221, 32,248, 35,145, 41, 22, 19, 0, 20, 25,126, 38, 16,126, 3, 20,
+ 31, 9, 41, 16,220,196,196,212,236,212,236, 17, 57, 57, 57, 49, 0, 16,244,228,236,252,228,236,212,236, 16,238, 16,238, 17, 18,
+ 57, 48, 1, 30, 1, 21, 20, 6, 35, 34, 38, 39, 53, 30, 1, 51, 50, 54, 53, 52, 38, 43, 1, 53, 51, 50, 54, 53, 52, 38, 35, 34,
+ 6, 7, 53, 62, 1, 51, 50, 22, 21, 20, 6, 2, 12, 92,101,190,177, 57,125, 70, 52,119, 67,109,120,111,108, 86, 94, 94, 97,100,
+ 95, 40,102, 81, 73,128, 55,144,169, 90, 4, 96, 18,109, 82,124,134, 21, 20,121, 27, 26, 79, 70, 74, 76,108, 63, 60, 58, 61, 18,
+ 23,115, 17, 18,118, 99, 69, 96, 0, 1, 1,115, 4,238, 3, 82, 6,102, 0, 3, 0, 49, 64, 9, 2,180, 0,179, 4, 3, 68, 1,
+ 4, 16,212,236, 49, 0, 16,244,236, 48, 0, 75,176, 9, 84, 75,176, 14, 84, 91, 88,189, 0, 4,255,192, 0, 1, 0, 4, 0, 4,
+ 0, 64, 56, 17, 55, 56, 89, 1, 51, 1, 35, 2,139,199,254,186,153, 6,102,254,136, 0, 0, 0, 0, 1, 0,174,254, 86, 4,229,
+ 4, 96, 0, 32, 0, 77, 64, 37, 19, 25, 31, 3, 22, 6, 3, 9, 12, 3, 1, 18, 15, 6,135, 28, 22,140, 10, 1,188, 0,189, 33,
+ 25, 9, 18, 9, 8, 11, 78, 31, 2, 8, 0, 70, 33, 16,252,236, 50,244,236,196, 18, 57, 49, 0, 16,228,228, 50,244, 60,236,220,
+196, 17, 23, 57, 17, 18, 23, 57, 48,182, 31, 34, 96, 34,207, 34, 3, 1, 93, 19, 17, 51, 17, 20, 22, 51, 50, 54, 53, 17, 51, 17,
+ 20, 22, 51, 50, 54, 55, 21, 14, 1, 35, 34, 38, 39, 14, 1, 35, 34, 38, 39, 17,174,184,138,135,148,149,184, 35, 37, 9, 32, 28,
+ 41, 73, 35, 69, 82, 15, 50,145, 98,102,143, 42,254, 86, 6, 10,253, 72,145,148,168,168, 2,141,252,162, 60, 57, 11, 12,148, 23,
+ 22, 78, 80, 79, 79, 78, 78,253,215, 0, 0, 0, 0, 1, 0,158,255, 59, 4, 57, 5,213, 0, 13, 0, 37, 64, 18, 8, 2, 4,193,
+ 0,129, 6, 2, 14, 0, 7, 93, 5, 3, 93, 1, 11, 14, 16,212,212,252,220,236, 57, 49, 0, 16,196, 50,244,236, 17, 57, 48, 1,
+ 33, 17, 35, 17, 35, 17, 35, 17, 46, 1, 53, 52, 36, 2,121, 1,192,141,190,142,215,235, 1, 4, 5,213,249,102, 6, 31,249,225,
+ 3, 78, 17,221,184,190,232, 0, 0, 1, 0,219, 2, 72, 1,174, 3, 70, 0, 3, 0, 18,183, 2,131, 0, 4, 1, 25, 0, 4, 16,
+212,236, 49, 0, 16,212,236, 48, 19, 51, 21, 35,219,211,211, 3, 70,254, 0, 0, 0, 1, 1, 35,254,117, 2,193, 0, 0, 0, 19,
+ 0, 31, 64, 14, 9, 6, 10, 13,243, 6, 0, 19, 0, 16, 39, 3, 9, 20, 16,220,212,236,212,204, 49, 0, 47,212,252,196, 18, 57,
+ 48, 33, 30, 1, 21, 20, 6, 35, 34, 38, 39, 53, 30, 1, 51, 50, 54, 53, 52, 38, 39, 2, 84, 55, 54,120,118, 46, 87, 43, 34, 74,
+ 47, 59, 60, 43, 45, 62,105, 48, 89, 91, 12, 12,131, 17, 15, 48, 46, 30, 87, 61, 0, 1, 0,137, 2,156, 2,197, 5,223, 0, 10,
+ 0, 44, 64, 24, 7, 0,221, 9, 3,221, 4, 2,221, 9,247, 5,145, 11, 8,124, 6, 93, 3,124, 1,124, 0, 11, 16,220,244,228,
+252,228, 49, 0, 16,244,236,236,212,236, 16,238, 50, 48, 19, 51, 17, 7, 53, 55, 51, 17, 51, 21, 33,156,204,223,230,137,205,253,
+215, 3, 10, 2, 99, 41,116, 39,253, 43,110, 0, 0, 3, 0, 96, 1,213, 3,100, 5,240, 0, 3, 0, 15, 0, 27, 0, 46, 64, 25,
+ 2,227, 0,225, 22,221, 10,224, 16,221, 4,145, 28, 0, 19, 13, 1, 25,107, 7,108, 19,107, 13, 28, 16,220,236,252,236, 57, 17,
+ 18, 57, 49, 0, 16,244,236,244,236,252,236, 48, 19, 33, 21, 33, 1, 50, 22, 21, 20, 6, 35, 34, 38, 53, 52, 54, 23, 34, 6, 21,
+ 20, 22, 51, 50, 54, 53, 52, 38,139, 2,176,253, 80, 1, 88,179,206,206,179,179,208,208,179,105,126,127,104,105,125,124, 2, 80,
+123, 4, 27,221,191,191,219,220,190,191,221,115,161,136,133,160,160,133,137,160, 0, 2, 0,193, 0,141, 4, 72, 4, 35, 0, 6,
+ 0, 13, 0,134, 64, 73, 12,232, 13, 12, 9, 10, 9, 11,232, 10, 10, 9, 13,232, 7, 8, 7, 12,232, 11, 12, 8, 8, 7, 5,232,
+ 6, 5, 2, 3, 2, 4,232, 3, 3, 2, 6,232, 0, 1, 0, 5,232, 4, 5, 1, 1, 0, 66, 12, 5, 10, 3,231, 7, 0,166, 14,
+ 12, 8, 1, 5, 0, 8,111, 10, 7, 1,111, 3, 0,112, 14, 16,252, 60,252,212, 60,236, 18, 57, 17, 18, 57, 49, 0, 16,244, 60,
+236, 50, 57, 57, 48, 75, 83, 88, 7, 16, 8,237, 7, 16, 4,237, 7, 16, 4,237, 7, 16, 8,237, 7, 16, 8,237, 7, 16, 4,237,
+ 7, 16, 4,237, 7, 16, 8,237, 89, 34, 19, 1, 21, 1, 53, 9, 1, 37, 1, 21, 1, 53, 9, 1,193, 1,213,254, 43, 1, 45,254,
+211, 1,178, 1,213,254, 43, 1, 45,254,211, 4, 35,254, 94, 82,254, 94,191, 1, 12, 1, 12,191,254, 94, 82,254, 94,191, 1, 12,
+ 1, 12, 0, 0,255,255, 0,137,255,227, 7,127, 5,240, 16, 39, 5,206, 4,139,253,100, 16, 38, 0,123, 0, 0, 16, 7, 6, 90,
+ 3, 53, 0, 0,255,255, 0,137,255,227, 7, 63, 5,240, 16, 38, 0,123, 0, 0, 16, 39, 6, 90, 3, 53, 0, 0, 16, 7, 0,116,
+ 4,139,253,100,255,255, 0, 98,255,227, 7,127, 5,240, 16, 39, 5,206, 4,139,253,100, 16, 38, 0,117, 0, 0, 16, 7, 6, 90,
+ 3, 53, 0, 0, 0, 2, 0,143,255,227, 3,172, 5,213, 0, 32, 0, 36, 0,134, 64, 47, 32, 26, 5, 2, 4, 6, 25, 0, 16,134,
+ 15,136, 12, 0, 33,131, 35, 12,149, 19,140, 35,129, 37, 6, 34, 25, 22, 9, 5, 1, 0, 26, 34, 9, 0, 28, 1, 34, 28, 33, 38,
+ 15, 9, 28, 22, 37, 16,220,236,212,252,236,212,236, 17, 18, 57, 17, 18, 57, 17, 18, 57, 18, 57, 49, 0, 16,228,244,236, 16,254,
+205, 16,244,238, 18, 57, 57, 23, 57, 48, 1, 75,176, 16, 84, 75,176, 18, 84, 91, 75,176, 19, 84, 91, 88,189, 0, 37,255,192, 0,
+ 1, 0, 37, 0, 37, 0, 64, 56, 17, 55, 56, 89, 64, 11,116, 4,116, 5,116, 6,116, 7,118, 28, 5, 93, 1, 51, 21, 20, 6, 15,
+ 1, 14, 1, 21, 20, 22, 51, 50, 54, 55, 21, 14, 1, 35, 34, 38, 53, 52, 54, 63, 1, 62, 1, 55, 62, 1, 53, 19, 35, 53, 51, 1,
+244,190, 55, 90, 90, 58, 51,131,109, 78,180, 96, 94,192,103,184,224, 73, 89, 88, 48, 38, 8, 7, 6,196,202,202, 4, 68,156,101,
+130, 87, 88, 53, 94, 49, 89,110, 70, 67,188, 57, 56,194,159, 76,137, 86, 86, 47, 53, 25, 21, 60, 54, 1, 14,254,255,255, 0, 16,
+ 0, 0, 5,104, 5,213, 18, 38, 0, 36, 0, 0, 16, 7, 6,135, 4,188, 1,117,255,255, 0, 16, 0, 0, 5,104, 5,213, 18, 38,
+ 0, 36, 0, 0, 16, 7, 6,133, 4,188, 1,117,255,255, 0, 16, 0, 0, 5,104, 5,213, 18, 38, 0, 36, 0, 0, 17, 7, 6,136,
+ 4,188, 1,117, 0, 16,180, 5, 13, 17, 10, 7, 43, 64, 5, 15, 13, 0, 17, 2, 93, 49, 0, 0,255,255, 0, 16, 0, 0, 5,104,
+ 5,213, 18, 38, 0, 36, 0, 0, 17, 7, 6,134, 4,188, 1,117, 0, 20,180, 10, 20, 35, 5, 7, 43, 64, 9, 64, 20, 79, 35, 32,
+ 20, 47, 35, 4, 93, 49, 0, 0,255,255, 0, 16, 0, 0, 5,104, 5,213, 18, 38, 0, 36, 0, 0, 17, 7, 6,132, 4,188, 1,117,
+ 0, 20,180, 10, 18, 13, 5, 7, 43, 64, 9, 48, 18, 63, 13, 0, 18, 15, 13, 4, 93, 49, 0, 0, 0, 3, 0, 16, 0, 0, 5,104,
+ 7,109, 0, 11, 0, 14, 0, 33, 0,203, 64, 84, 12, 17, 13, 12, 27, 28, 27, 14, 17, 28, 27, 30, 17, 28, 27, 29, 17, 28, 28, 27,
+ 13, 17, 33, 15, 33, 12, 17, 14, 12, 15, 15, 33, 32, 17, 15, 33, 31, 17, 33, 15, 33, 66, 12, 27, 15, 13, 9, 3,193, 21, 9, 30,
+149, 13, 9,142, 32, 28, 30, 29, 28, 24, 32, 31, 33, 13, 18, 6, 14, 24, 12, 6, 27, 0, 86, 24, 28, 15, 6, 86, 18, 28, 33, 34,
+ 16,212,196,212,236, 50, 16,212,238, 50, 17, 57, 17, 57, 17, 18, 57, 17, 57, 57, 17, 18, 57, 57, 49, 0, 47, 60,230,214,238, 16,
+212,238, 17, 18, 57, 57, 57, 48, 75, 83, 88, 7, 16, 5,237, 7, 5,237, 7, 16, 8,237, 7, 16, 5,237, 7, 16, 5,237, 7, 5,
+237, 7, 5,237, 7, 16, 8,237, 89, 34,178, 32, 35, 1, 1, 93, 64, 32, 26, 12,115, 12,155, 12, 3, 7, 15, 8, 27, 80, 35,102,
+ 13,105, 14,117, 13,123, 14,121, 28,121, 29,118, 32,118, 33,128, 35, 12, 93, 0, 93, 1, 52, 38, 35, 34, 6, 21, 20, 22, 51, 50,
+ 54, 3, 1, 33, 1, 46, 1, 53, 52, 54, 51, 50, 22, 21, 20, 6, 7, 1, 35, 3, 33, 3, 35, 3, 84, 89, 63, 64, 87, 88, 63, 63,
+ 89,152,254,240, 2, 33,254, 88, 61, 62,159,115,114,161, 63, 60, 2, 20,210,136,253, 95,136,213, 6, 90, 63, 89, 87, 65, 63, 88,
+ 88,254,243,253, 25, 3, 78, 41,115, 73,115,160,161,114, 70,118, 41,250,139, 1,127,254,129, 0, 0, 2, 0, 8, 0, 0, 7, 72,
+ 5,213, 0, 15, 0, 19, 0,135, 64, 57, 17, 17, 14, 15, 14, 16, 17, 15, 15, 14, 13, 17, 15, 14, 12, 17, 14, 15, 14, 66, 5,149,
+ 3, 11,149, 17, 1,149, 16,149, 0,129, 17, 7,149, 3,173, 13, 9, 17, 16, 15, 13, 12, 5, 14, 10, 0, 4, 8, 6, 2, 28, 18,
+ 10, 14, 20, 16,212,212, 60,236, 50,212,196,196, 17, 18, 23, 57, 49, 0, 47, 60,236,236,196,244,236,236, 16,238, 16,238, 48, 75,
+ 83, 88, 7, 16, 5,237, 7, 5,237, 7, 16, 5,237, 7, 16, 5,237, 89, 34,178,128, 21, 1, 1, 93, 64, 19,103, 17,119, 16,119,
+ 17,134, 12,133, 16,150, 17,144, 21,160, 21,191, 21, 9, 93, 1, 21, 33, 17, 33, 21, 33, 17, 33, 21, 33, 17, 33, 3, 35, 1, 23,
+ 1, 33, 17, 7, 53,253, 27, 2,199,253, 57, 2,248,252, 61,253,240,160,205, 2,113,139,254,182, 1,203, 5,213,170,254, 70,170,
+253,227,170, 1,127,254,129, 5,213,158,252,240, 3, 16, 0, 0,255,255, 0,115,254,117, 5, 39, 5,240, 18, 38, 0, 38, 0, 0,
+ 16, 7, 0,122, 1, 45, 0, 0,255,255, 0,201, 0, 0, 4,139, 5,213, 18, 38, 0, 40, 0, 0, 16, 7, 6,135, 4,158, 1,117,
+255,255, 0,201, 0, 0, 4,139, 5,213, 18, 38, 0, 40, 0, 0, 16, 7, 6,133, 4,158, 1,117,255,255, 0,201, 0, 0, 4,139,
+ 5,213, 18, 38, 0, 40, 0, 0, 17, 7, 6,136, 4,158, 1,117, 0, 7, 64, 3, 64, 12, 1, 93, 49, 0, 0, 0,255,255, 0,201,
+ 0, 0, 4,139, 5,213, 18, 38, 0, 40, 0, 0, 17, 7, 6,132, 4,158, 1,117, 0, 9, 64, 5, 64, 12, 64, 16, 2, 93, 49, 0,
+255,255, 0,201, 0, 0, 1,147, 5,213, 18, 38, 0, 44, 0, 0, 16, 7, 6,135, 3, 47, 1,117,255,255, 0,201, 0, 0, 1,147,
+ 5,213, 18, 38, 0, 44, 0, 0, 16, 7, 6,133, 3, 47, 1,117,255,255, 0,201, 0, 0, 1,147, 5,213, 18, 38, 0, 44, 0, 0,
+ 17, 7, 6,136, 3, 47, 1,117, 0, 8,180, 1, 6, 10, 0, 7, 43, 49, 0, 0,255,255, 0,201, 0, 0, 1,147, 5,213, 18, 38,
+ 0, 44, 0, 0, 17, 7, 6,132, 3, 47, 1,117, 0, 8,180, 0, 10, 7, 1, 7, 43, 49, 0, 0, 0, 2, 0, 10, 0, 0, 5,186,
+ 5,213, 0, 12, 0, 25, 0,103, 64, 32, 16, 9,169, 11, 13,149, 0,129, 18,149, 14, 11, 7, 7, 1, 25, 19, 4, 15, 13, 22, 25,
+ 4, 50, 10, 17, 13, 28, 8, 0,121, 26, 16,244, 60,236, 50,196,244,236, 16,196, 23, 57, 49, 0, 47,198, 50,238,246,238, 16,238,
+ 50, 48, 64, 40, 32, 27,127, 27,176, 27, 3,159, 9,159, 10,159, 11,159, 12,159, 14,159, 15,159, 16,159, 17,191, 9,191, 10,191,
+ 11,191, 12,191, 14,191, 15,191, 16,191, 17, 16, 93, 1, 93, 19, 33, 32, 0, 17, 16, 0, 41, 1, 17, 35, 53, 51, 19, 17, 33, 21,
+ 33, 17, 51, 32, 0, 17, 16, 0, 33,211, 1,160, 1,177, 1,150,254,105,254, 80,254, 96,201,201,203, 1, 80,254,176,243, 1, 53,
+ 1, 31,254,225,254,203, 5,213,254,151,254,128,254,126,254,150, 2,188,144, 1,227,254, 29,144,253,234, 1, 24, 1, 46, 1, 44,
+ 1, 23, 0, 0,255,255, 0,201, 0, 0, 5, 51, 5,213, 18, 38, 0, 49, 0, 0, 17, 7, 6,134, 4,254, 1,117, 0, 20,180, 0,
+ 19, 34, 4, 7, 43, 64, 9, 48, 19, 63, 34, 16, 19, 31, 34, 4, 93, 49, 0, 0,255,255, 0,115,255,227, 5,217, 5,240, 18, 38,
+ 0, 50, 0, 0, 16, 7, 6,135, 5, 39, 1,117,255,255, 0,115,255,227, 5,217, 5,240, 18, 38, 0, 50, 0, 0, 16, 7, 6,133,
+ 5, 39, 1,117,255,255, 0,115,255,227, 5,217, 5,240, 18, 38, 0, 50, 0, 0, 17, 7, 6,136, 5, 39, 1,117, 0, 16,180, 15,
+ 26, 30, 21, 7, 43, 64, 5, 31, 26, 16, 30, 2, 93, 49, 0, 0,255,255, 0,115,255,227, 5,217, 5,240, 18, 38, 0, 50, 0, 0,
+ 17, 7, 6,134, 5, 39, 1,117, 0, 24,180, 3, 33, 48, 9, 7, 43, 64, 13, 48, 33, 63, 48, 32, 33, 47, 48, 16, 33, 31, 48, 6,
+ 93, 49, 0, 0,255,255, 0,115,255,227, 5,217, 5,240, 18, 38, 0, 50, 0, 0, 17, 7, 6,132, 5, 39, 1,117, 0, 20,180, 3,
+ 31, 26, 9, 7, 43, 64, 9, 64, 31, 79, 26, 16, 31, 31, 26, 4, 93, 49, 0, 0, 0, 1, 1, 25, 0, 63, 5,156, 4,197, 0, 11,
+ 0,133, 64, 77, 10,156, 11, 10, 7, 8, 7, 9,156, 8, 8, 7, 4,156, 3, 4, 7, 7, 6, 5,156, 6, 7, 6, 4,156, 5, 4,
+ 1, 2, 1, 3,156, 2, 2, 1, 11,156, 0, 1, 0, 10,156, 9, 10, 1, 1, 0, 66, 10, 8, 7, 6, 4, 2, 1, 0, 8, 5, 3,
+ 11, 9, 12, 11, 10, 9, 7, 5, 4, 3, 1, 8, 2, 0, 8, 6, 12, 16,212, 60,204, 50, 23, 57, 49, 0, 16,212, 60,204, 50, 23,
+ 57, 48, 75, 83, 88, 7, 16, 8,237, 7, 16, 5,237, 7, 16, 5,237, 7, 16, 8,237, 7, 16, 5,237, 7, 16, 8,237, 7, 16, 5,
+237, 7, 16, 8,237, 89, 34, 9, 2, 7, 9, 1, 39, 9, 1, 55, 9, 1, 5,156,254, 55, 1,201,119,254, 53,254, 53,118, 1,200,
+254, 56,118, 1,203, 1,203, 4, 76,254, 53,254, 55,121, 1,203,254, 53,121, 1,201, 1,203,121,254, 53, 1,203, 0, 3, 0,102,
+255,186, 5,229, 6, 23, 0, 9, 0, 19, 0, 43, 0,158, 64, 60, 29, 31, 26, 13, 43, 44, 19, 10, 1, 0, 4, 13, 41, 38, 32, 20,
+ 13, 4, 42, 38, 30, 26, 4,149, 38, 13,149, 26,145, 38,140, 44, 43, 44, 42, 20, 23, 16, 32, 30, 35, 19, 10, 1, 0, 4, 29, 41,
+ 16, 7, 31, 7, 25, 35, 51, 16, 25, 23, 16, 44, 16,252,236,252,236,192, 17, 18, 57, 57, 23, 57, 18, 57, 57, 17, 18, 57, 57, 17,
+ 57, 49, 0, 16,228,244,236, 16,238, 16,192, 16,192, 17, 18, 57, 57, 18, 57, 18, 23, 57, 18, 57, 17, 18, 57, 57, 48, 64, 42, 87,
+ 0, 90, 21, 87, 25, 85, 33,106, 21,101, 33,123, 21,118, 28,117, 33, 9, 70, 19, 89, 0, 86, 19,106, 0,100, 19,100, 28,106, 40,
+124, 0,115, 19,118, 28,122, 40, 11, 93, 1, 93, 9, 1, 30, 1, 51, 50, 0, 17, 52, 38, 39, 46, 1, 35, 34, 0, 17, 20, 22, 23,
+ 7, 38, 2, 53, 16, 0, 33, 50, 22, 23, 55, 23, 7, 22, 18, 21, 16, 0, 33, 34, 38, 39, 7, 39, 4,182,253, 51, 62,161, 95,220,
+ 1, 1, 39,121, 61,161, 95,220,254,253, 39, 39,134, 78, 79, 1,121, 1, 59,130,221, 87,162,102,170, 78, 80,254,136,254,198,128,
+221, 91,162,103, 4, 88,252,178, 64, 67, 1, 72, 1, 26,112,184,184, 64, 67,254,184,254,229,112,188, 68,158,102, 1, 8,160, 1,
+ 98, 1,165, 77, 75,191, 89,198,103,254,246,158,254,159,254, 91, 75, 75,191, 88,255,255, 0,178,255,227, 5, 41, 5,213, 18, 38,
+ 0, 56, 0, 0, 16, 7, 6,135, 4,238, 1,117,255,255, 0,178,255,227, 5, 41, 5,213, 18, 38, 0, 56, 0, 0, 16, 7, 6,133,
+ 4,238, 1,117,255,255, 0,178,255,227, 5, 41, 5,213, 18, 38, 0, 56, 0, 0, 17, 7, 6,136, 4,238, 1,117, 0, 20,180, 10,
+ 20, 24, 0, 7, 43, 64, 9, 47, 20, 32, 24, 31, 20, 16, 24, 4, 93, 49, 0, 0,255,255, 0,178,255,227, 5, 41, 5,213, 18, 38,
+ 0, 56, 0, 0, 17, 7, 6,132, 4,238, 1,117, 0, 28,180, 1, 25, 20, 9, 7, 43, 64, 17, 80, 25, 95, 20, 64, 25, 79, 20, 32,
+ 25, 47, 20, 16, 25, 31, 20, 8, 93, 49, 0, 0,255,255,255,252, 0, 0, 4,231, 5,213, 18, 38, 0, 60, 0, 0, 16, 7, 6,133,
+ 4,115, 1,117, 0, 2, 0,201, 0, 0, 4,141, 5,213, 0, 12, 0, 21, 0, 61, 64, 27, 14,149, 9, 13,149, 2,246, 0,129, 11,
+ 21, 15, 9, 3, 4, 1, 18, 25, 6, 63, 13, 10, 1, 28, 0, 4, 22, 16,252,236, 50, 50,252,236, 17, 23, 57, 49, 0, 47,244,252,
+236,212,236, 48, 64, 9, 15, 23, 31, 23, 63, 23, 95, 23, 4, 1, 93, 19, 51, 17, 51, 50, 4, 21, 20, 4, 43, 1, 17, 35, 19, 17,
+ 51, 50, 54, 53, 52, 38, 35,201,202,254,251, 1, 1,254,255,251,254,202,202,254,141,154,153,142, 5,213,254,248,225,220,220,226,
+254,174, 4, 39,253,209,146,134,134,145, 0, 0, 0, 1, 0,186,255,227, 4,172, 6, 20, 0, 47, 0,154, 64, 48, 45, 39, 33, 12,
+ 4, 6, 13, 32, 0, 4, 42, 22,134, 23, 26,185, 19, 42,185, 3,151, 19,140, 46, 12, 9, 13, 29, 32, 33, 39, 9, 8, 36, 39, 8,
+ 6, 29, 8, 36, 16, 22, 45, 8, 16, 0, 70, 48, 16,252,196,252,204, 16,198,238,212,238, 16,238, 17, 57, 57, 18, 57, 18, 57, 49,
+ 0, 47,228,254,238, 16,254,213,238, 18, 23, 57, 23, 57, 48, 64, 64, 15, 5, 15, 6, 15, 7, 15, 39, 15, 40,138, 12,138, 13, 7,
+ 10, 6, 10, 7, 10, 11, 10, 12, 10, 13, 10, 31, 13, 32, 10, 33, 12, 34, 4, 38, 25, 13, 25, 31, 25, 32, 58, 32, 58, 33, 77, 31,
+ 77, 32, 73, 33, 73, 34,106, 31,106, 32,165, 6,165, 7,166, 32, 24, 93, 1, 93, 19, 52, 54, 51, 50, 22, 23, 14, 1, 21, 20, 22,
+ 31, 1, 30, 1, 21, 20, 6, 35, 34, 38, 39, 53, 30, 1, 51, 50, 54, 53, 52, 38, 47, 1, 46, 1, 53, 52, 54, 55, 46, 1, 35, 34,
+ 6, 21, 17, 35,186,239,218,208,219, 3,151,168, 58, 65, 57,166, 96,225,211, 64,136, 73, 80,140, 65,116,120, 59,101, 92, 96, 87,
+167,151, 8,131,113,130,136,187, 4,113,200,219,232,224, 8,115, 96, 47, 81, 42, 37,106,142,100,172,183, 25, 24,164, 30, 29, 95,
+ 91, 63, 84, 62, 55, 59,135, 91,127,172, 29,103,112,139,131,251,147, 0, 0, 0,255,255, 0,123,255,227, 4, 45, 6,102, 18, 38,
+ 0, 68, 0, 0, 17, 6, 0, 67, 82, 0, 0, 11, 64, 7, 63, 38, 47, 38, 31, 38, 3, 93, 49, 0,255,255, 0,123,255,227, 4, 45,
+ 6,102, 18, 38, 0, 68, 0, 0, 17, 6, 0,118, 82, 0, 0, 11, 64, 7, 63, 38, 47, 38, 31, 38, 3, 93, 49, 0,255,255, 0,123,
+255,227, 4, 45, 6,102, 18, 38, 0, 68, 0, 0, 17, 6, 2, 31, 82, 0, 0, 8,180, 11, 40, 44, 20, 7, 43, 49,255,255, 0,123,
+255,227, 4, 45, 6, 55, 18, 38, 0, 68, 0, 0, 17, 6, 2, 53, 82, 0, 0, 20,180, 20, 46, 60, 11, 7, 43, 64, 9, 32, 46, 47,
+ 60, 16, 46, 31, 60, 4, 93, 49,255,255, 0,123,255,227, 4, 45, 6, 16, 18, 38, 0, 68, 0, 0, 17, 6, 0,106, 82, 0, 0, 32,
+180, 20, 45, 40, 11, 7, 43, 64, 21,127, 40,111, 40, 80, 45, 95, 40, 64, 45, 79, 40, 48, 45, 63, 40, 0, 45, 15, 40, 10, 93, 49,
+255,255, 0,123,255,227, 4, 45, 7, 6, 18, 38, 0, 68, 0, 0, 17, 6, 2, 51, 82, 0, 0, 37, 64, 14, 38, 44, 20, 44, 38, 11,
+ 7, 50, 56, 20, 56, 50, 11, 7, 43, 16,196, 43, 16,196, 49, 0, 64, 9, 63, 53, 63, 47, 15, 53, 15, 47, 4, 93, 48, 0, 0, 0,
+ 0, 3, 0,123,255,227, 7,111, 4,123, 0, 6, 0, 51, 0, 62, 1, 3, 64, 67, 39, 45, 37, 61, 14, 13, 0, 52,169, 37, 22,134,
+ 21,136, 18, 0,169, 14, 58, 18,185, 28, 25, 46,134, 45,186, 42, 3,185, 14,187, 7, 49, 10,184, 31, 25,140, 37, 63, 52, 55, 38,
+ 6, 15, 0, 37, 55, 28, 7, 38, 15, 21, 0, 8, 13, 61, 38, 8, 15, 45, 55, 8, 34, 69, 63, 16,252,236,204,212,252, 60,212,236,
+196, 17, 18, 57, 57, 17, 57, 17, 18, 57, 17, 18, 57, 49, 0, 16,196,228, 50,244, 60,196,228,252, 60,244,236, 16,196,238, 50, 16,
+238, 16,244,238, 16,238, 17, 57, 17, 57, 17, 18, 57, 48, 64,129, 48, 43, 48, 44, 48, 45, 48, 46, 48, 47, 48, 48, 64, 43, 64, 44,
+ 64, 45, 64, 46, 64, 47, 64, 48, 80, 43, 80, 44, 80, 45, 80, 46, 80, 47, 80, 48,133, 43,133, 48,128, 64,144, 64,160, 64,176, 64,
+192, 64,208, 64,224, 64,224, 64,240, 64, 29, 63, 0, 63, 6, 63, 13, 63, 14, 63, 15, 5, 48, 44, 48, 45, 48, 46, 48, 47, 64, 44,
+ 64, 45, 64, 46, 64, 47, 80, 44, 80, 45, 80, 46, 80, 47,111, 0,111, 6,111, 13,111, 14,111, 15, 96, 44, 96, 45, 96, 46, 96, 47,
+112, 44,112, 45,112, 46,112, 47,128, 44,128, 45,128, 46,128, 47, 29, 93,113, 1, 93, 1, 46, 1, 35, 34, 6, 7, 3, 62, 1, 51,
+ 50, 0, 29, 1, 33, 30, 1, 51, 50, 54, 55, 21, 14, 1, 35, 34, 38, 39, 14, 1, 35, 34, 38, 53, 52, 54, 51, 33, 53, 52, 38, 35,
+ 34, 6, 7, 53, 62, 1, 51, 50, 22, 3, 34, 6, 21, 20, 22, 51, 50, 54, 61, 1, 6,182, 1,165,137,153,185, 14, 68, 74,212,132,
+226, 1, 8,252,178, 12,204,183,104,200,100,100,208,106,167,248, 77, 73,216,143,189,210,253,251, 1, 2,167,151, 96,182, 84,101,
+190, 90,142,213,239,223,172,129,111,153,185, 2,148,151,180,174,158, 1, 48, 90, 94,254,221,250, 90,191,200, 53, 53,174, 42, 44,
+121,119,120,120,187,168,189,192, 18,127,139, 46, 46,170, 39, 39, 96,254, 24,102,123, 98,115,217,180, 41, 0, 0,255,255, 0,113,
+254,117, 3,231, 4,123, 18, 38, 0, 70, 0, 0, 16, 7, 0,122, 0,143, 0, 0,255,255, 0,113,255,227, 4,127, 6,102, 18, 38,
+ 0, 72, 0, 0, 16, 7, 0, 67, 0,139, 0, 0,255,255, 0,113,255,227, 4,127, 6,102, 18, 38, 0, 72, 0, 0, 16, 7, 0,118,
+ 0,139, 0, 0,255,255, 0,113,255,227, 4,127, 6,102, 18, 38, 0, 72, 0, 0, 17, 7, 2, 31, 0,139, 0, 0, 0, 8,180, 21,
+ 30, 34, 27, 7, 43, 49, 0, 0,255,255, 0,113,255,227, 4,127, 6, 16, 18, 38, 0, 72, 0, 0, 17, 7, 0,106, 0,139, 0, 0,
+ 0, 7, 64, 3, 64, 32, 1, 93, 49, 0, 0, 0,255,255,255,199, 0, 0, 1,166, 6,102, 18, 38, 0,243, 0, 0, 16, 7, 0, 67,
+255, 29, 0, 0,255,255, 0,144, 0, 0, 2,111, 6,102, 18, 38, 0,243, 0, 0, 16, 7, 0,118,255, 29, 0, 0,255,255,255,222,
+ 0, 0, 2, 92, 6,102, 18, 38, 0,243, 0, 0, 17, 7, 2, 31,255, 29, 0, 0, 0, 8,180, 1, 6, 10, 0, 7, 43, 49, 0, 0,
+255,255,255,244, 0, 0, 2, 70, 6, 16, 18, 38, 0,243, 0, 0, 17, 7, 0,106,255, 29, 0, 0, 0, 8,180, 0, 10, 7, 1, 7,
+ 43, 49, 0, 0, 0, 2, 0,113,255,227, 4,117, 6, 20, 0, 14, 0, 40, 1, 39, 64, 94, 37,123, 38, 37, 30, 35, 30, 36,123, 35,
+ 35, 30, 15,123, 35, 30, 40,123, 39, 40, 30, 35, 30, 38, 39, 40, 39, 37, 36, 37, 40, 40, 39, 34, 35, 34, 31, 32, 31, 33, 32, 32,
+ 31, 66, 40, 39, 38, 37, 34, 33, 32, 31, 8, 35, 30, 3, 15, 35, 3,185, 27, 9,185, 21,140, 27, 35,177, 41, 38, 39, 18, 12, 33,
+ 32, 24, 40, 37, 35, 34, 31, 5, 30, 15, 6, 12, 18, 18, 81, 6, 18, 24, 69, 41, 16,252,236,244,236, 17, 57, 57, 23, 57, 18, 57,
+ 57, 17, 18, 57, 57, 49, 0, 16,236,196,244,236, 16,238, 18, 57, 18, 57, 18, 23, 57, 48, 75, 83, 88, 7, 16, 14,201, 7, 16, 8,
+201, 7, 16, 8,201, 7, 16, 14,201, 7, 16, 8,237, 7, 14,237, 7, 16, 5,237, 7, 16, 8,237, 89, 34,178, 63, 42, 1, 1, 93,
+ 64,118, 22, 37, 43, 31, 40, 34, 47, 35, 47, 36, 41, 37, 45, 38, 45, 39, 42, 40, 54, 37, 70, 37, 88, 32, 88, 33, 96, 32, 96, 33,
+102, 34,117, 32,117, 33,117, 34, 19, 37, 35, 37, 36, 38, 38, 38, 39, 39, 40, 54, 36, 54, 37, 70, 36, 69, 37, 90, 32, 90, 33, 98,
+ 32, 98, 33,127, 0,127, 1,127, 2,122, 3,123, 9,127, 10,127, 11,127, 12,127, 13,127, 14,127, 15,127, 16,127, 17,127, 18,127,
+ 19,127, 20,123, 21,122, 27,122, 28,127, 29,127, 30,118, 32,118, 33,120, 34,160, 42,240, 42, 39, 93, 0, 93, 1, 46, 1, 35, 34,
+ 6, 21, 20, 22, 51, 50, 54, 53, 52, 38, 19, 22, 18, 21, 20, 0, 35, 34, 0, 17, 52, 0, 51, 50, 22, 23, 39, 5, 39, 37, 39, 51,
+ 23, 37, 23, 5, 3, 70, 50, 88, 41,167,185,174,146,145,174, 54, 9,126,114,254,228,230,231,254,229, 1, 20,221, 18, 52, 42,159,
+254,193, 33, 1, 25,181,228,127, 1, 77, 33,254,217, 3,147, 17, 16,216,195,188,222,222,188,122,188, 1, 38,143,254,224,173,255,
+254,201, 1, 55, 0,255,250, 1, 55, 5, 5,180,107, 99, 92,204,145,111, 97, 98,255,255, 0,186, 0, 0, 4,100, 6, 55, 18, 38,
+ 0, 81, 0, 0, 16, 7, 2, 53, 0,152, 0, 0,255,255, 0,113,255,227, 4,117, 6,102, 18, 38, 0, 82, 0, 0, 16, 6, 0, 67,
+115, 0, 0, 0,255,255, 0,113,255,227, 4,117, 6,102, 18, 38, 0, 82, 0, 0, 16, 6, 0,118,115, 0, 0, 0,255,255, 0,113,
+255,227, 4,117, 6,102, 18, 38, 0, 82, 0, 0, 17, 6, 2, 31,115, 0, 0, 8,180, 15, 26, 30, 21, 7, 43, 49,255,255, 0,113,
+255,227, 4,117, 6, 55, 18, 38, 0, 82, 0, 0, 17, 6, 2, 53,115, 0, 0, 20,180, 21, 32, 46, 15, 7, 43, 64, 9, 32, 32, 47,
+ 46, 16, 32, 31, 46, 4, 93, 49,255,255, 0,113,255,227, 4,117, 6, 16, 18, 38, 0, 82, 0, 0, 17, 6, 0,106,115, 0, 0, 20,
+180, 3, 31, 26, 9, 7, 43, 64, 9, 64, 31, 79, 26, 48, 31, 63, 26, 4, 93, 49, 0, 3, 0,217, 0,150, 5,219, 4,111, 0, 3,
+ 0, 7, 0, 11, 0, 41, 64, 20, 0,234, 2, 6,234, 4, 2, 8,156, 4, 10, 12, 9, 5, 1,114, 4, 0, 8, 12, 16,220,212, 60,
+252, 60,196, 49, 0, 16,212,196,252,196, 16,238, 16,238, 48, 1, 51, 21, 35, 17, 51, 21, 35, 1, 33, 21, 33, 2,223,246,246,246,
+246,253,250, 5, 2,250,254, 4,111,246,254, 18,245, 2, 65,170, 0, 3, 0, 72,255,162, 4,156, 4,188, 0, 9, 0, 19, 0, 43,
+ 0,228, 64, 60, 43, 44, 38, 31, 29, 26, 19, 10, 1, 0, 4, 13, 41, 38, 32, 20, 13, 4, 42, 38, 30, 26, 4,185, 38, 13,185, 26,
+184, 38,140, 44, 43, 44, 42, 20, 23, 16, 32, 30, 35, 19, 10, 1, 0, 4, 16, 7, 31, 29, 7, 18, 35, 81, 41, 16, 18, 23, 69, 44,
+ 16,252,236, 50,244,236, 50,192, 17, 18, 23, 57, 18, 57, 57, 17, 18, 57, 57, 17, 57, 49, 0, 16,228,244,236, 16,238, 16,192, 16,
+192, 17, 18, 57, 57, 18, 57, 18, 23, 57, 17, 57, 57, 17, 18, 57, 48, 64,112, 40, 1, 63, 45, 89, 20, 86, 28, 85, 29, 86, 32,106,
+ 21,102, 33,127, 0,123, 4,127, 5,127, 6,127, 7,127, 8,127, 9,127, 10,127, 11,127, 12,123, 13,122, 21,123, 26,127, 27,127,
+ 28,127, 29,127, 30,127, 31,127, 32,123, 33,127, 34,127, 35,127, 36,127, 37,123, 38,155, 25,149, 37,168, 25,160, 45,240, 45, 38,
+ 89, 0, 86, 19, 85, 29, 90, 40,105, 0,102, 19,101, 28,106, 40,122, 0,116, 19,118, 28,122, 40,137, 30,149, 24,154, 36,162, 24,
+173, 36, 17, 93, 1, 93, 9, 1, 30, 1, 51, 50, 54, 53, 52, 38, 39, 46, 1, 35, 34, 6, 21, 20, 22, 23, 7, 46, 1, 53, 16, 0,
+ 51, 50, 22, 23, 55, 23, 7, 30, 1, 21, 16, 0, 35, 34, 38, 39, 7, 39, 3,137,254, 25, 41,103, 65,147,172, 20, 92, 42,103, 62,
+151,169, 19, 20,125, 54, 54, 1, 17,241, 93,159, 67,139, 95,146, 53, 54,254,238,240, 96,161, 63,139, 96, 3, 33,253,176, 42, 40,
+232,200, 79,117,154, 41, 41,235,211, 72,110, 46,151, 77,197,119, 1, 20, 1, 56, 51, 52,168, 79,179, 77,198,120,254,237,254,199,
+ 52, 51,168, 78,255,255, 0,174,255,227, 4, 88, 6,102, 18, 38, 0, 88, 0, 0, 16, 6, 0, 67,123, 0, 0, 0,255,255, 0,174,
+255,227, 4, 88, 6,102, 18, 38, 0, 88, 0, 0, 16, 6, 0,118,123, 0, 0, 0,255,255, 0,174,255,227, 4, 88, 6,102, 18, 38,
+ 0, 88, 0, 0, 17, 6, 2, 31,123, 0, 0, 8,180, 11, 22, 26, 1, 7, 43, 49,255,255, 0,174,255,227, 4, 88, 6, 16, 18, 38,
+ 0, 88, 0, 0, 17, 6, 0,106,123, 0, 0, 24,180, 2, 26, 23, 10, 7, 43, 64, 13, 64, 26, 79, 23, 48, 26, 63, 23, 0, 26, 15,
+ 23, 6, 93, 49,255,255, 0, 61,254, 86, 4,127, 6,102, 18, 38, 0, 92, 0, 0, 16, 6, 0,118, 94, 0, 0, 0, 0, 2, 0,186,
+254, 86, 4,164, 6, 20, 0, 16, 0, 28, 0, 62, 64, 27, 20,185, 5, 8, 26,185, 0, 14,140, 8,184, 1,189, 3,151, 29, 17, 18,
+ 11, 71, 23, 4, 0, 8, 2, 70, 29, 16,252,236, 50, 50,244,236, 49, 0, 16,236,228,228,244,196,236, 16,198,238, 48, 64, 9, 96,
+ 30,128, 30,160, 30,224, 30, 4, 1, 93, 37, 17, 35, 17, 51, 17, 62, 1, 51, 50, 0, 17, 16, 2, 35, 34, 38, 1, 52, 38, 35, 34,
+ 6, 21, 20, 22, 51, 50, 54, 1,115,185,185, 58,177,123,204, 0,255,255,204,123,177, 2, 56,167,146,146,167,167,146,146,167,168,
+253,174, 7,190,253,162,100, 97,254,188,254,248,254,248,254,188, 97, 1,235,203,231,231,203,203,231,231, 0, 0,255,255, 0, 61,
+254, 86, 4,127, 6, 16, 18, 38, 0, 92, 0, 0, 17, 6, 0,106, 94, 0, 0, 22,180, 24, 23, 18, 25, 7, 43, 64, 11, 48, 23, 63,
+ 18, 32, 23, 47, 18, 31, 18, 5, 93, 49, 0, 0,255,255, 0, 16, 0, 0, 5,104, 7, 49, 16, 39, 0,113, 0,188, 1, 59, 19, 6,
+ 0, 36, 0, 0, 0, 16,180, 14, 3, 2, 9, 7, 43, 64, 5, 64, 3, 79, 2, 2, 93, 49, 0, 0,255,255, 0,123,255,227, 4, 45,
+ 5,246, 16, 38, 0,113, 74, 0, 19, 6, 0, 68, 0, 0, 0, 16,180, 24, 3, 2, 15, 7, 43, 64, 5,111, 2,127, 3, 2, 93, 49,
+255,255, 0, 16, 0, 0, 5,104, 7,146, 16, 39, 2, 49, 0,206, 1, 74, 19, 6, 0, 36, 0, 0, 0, 18,180, 24, 0, 8, 19, 7,
+ 43, 49, 0, 64, 5,111, 0,111, 8, 2, 93, 48,255,255, 0,123,255,227, 4, 45, 6, 31, 16, 38, 2, 49, 79,215, 19, 6, 0, 68,
+ 0, 0, 0, 8,180, 34, 0, 8, 25, 7, 43, 49,255,255, 0, 16,254,117, 5,165, 5,213, 16, 39, 2, 52, 2,228, 0, 0, 18, 6,
+ 0, 36, 0, 0,255,255, 0,123,254,117, 4,128, 4,123, 16, 39, 2, 52, 1,191, 0, 0, 18, 6, 0, 68, 0, 0,255,255, 0,115,
+255,227, 5, 39, 5,240, 18, 38, 0, 38, 0, 0, 16, 7, 6,133, 5, 45, 1,117,255,255, 0,113,255,227, 3,231, 6,102, 18, 38,
+ 0, 70, 0, 0, 16, 7, 0,118, 0,137, 0, 0,255,255, 0,115,255,227, 5, 39, 5,240, 16, 39, 6,136, 5, 76, 1,117, 19, 6,
+ 0, 38, 0, 0, 0, 9,178, 4, 4, 30, 16, 60, 61, 47, 49, 0,255,255, 0,113,255,227, 3,231, 6,102, 16, 39, 2, 31, 0,164,
+ 0, 0, 18, 6, 0, 70, 0, 0,255,255, 0,115,255,227, 5, 39, 5,240, 16, 39, 6,140, 5, 76, 1,117, 18, 6, 0, 38, 0, 0,
+255,255, 0,113,255,227, 3,231, 6, 16, 16, 39, 2, 50, 0,164, 0, 0, 18, 6, 0, 70, 0, 0,255,255, 0,115,255,227, 5, 39,
+ 5,240, 18, 38, 0, 38, 0, 0, 17, 7, 6,137, 5, 45, 1,117, 0, 7, 64, 3, 31, 29, 1, 93, 49, 0, 0, 0,255,255, 0,113,
+255,227, 3,231, 6,102, 18, 38, 0, 70, 0, 0, 16, 7, 2, 32, 0,137, 0, 0,255,255, 0,201, 0, 0, 5,176, 5,213, 16, 38,
+ 0, 39, 0, 0, 16, 7, 6,137, 4,236, 1,137,255,255, 0,113,255,227, 4, 90, 6, 20, 18, 38, 0, 71, 0, 0, 17, 7, 6,131,
+ 5, 20, 0, 0, 0, 11, 64, 7, 95, 29, 63, 29, 31, 29, 3, 93, 49, 0, 0, 0,255,255, 0, 10, 0, 0, 5,186, 5,213, 16, 6,
+ 0,146, 0, 0, 0, 2, 0,113,255,227, 4,244, 6, 20, 0, 24, 0, 36, 0, 74, 64, 36, 7, 3,211, 9, 1,249, 34,185, 0, 22,
+ 28,185, 13, 16,140, 22,184, 5,151, 11, 2, 31, 12, 4, 3, 0, 8, 8, 10, 6, 71, 25, 18, 19, 69, 37, 16,252,236,244, 60,196,
+252, 23, 60,196, 49, 0, 47,236,228,244,196,236, 16,196,238,253, 60,238, 50, 48,182, 96, 38,128, 38,160, 38, 3, 1, 93, 1, 17,
+ 33, 53, 33, 53, 51, 21, 51, 21, 35, 17, 35, 53, 14, 1, 35, 34, 2, 17, 16, 0, 51, 50, 22, 1, 20, 22, 51, 50, 54, 53, 52, 38,
+ 35, 34, 6, 3,162,254,186, 1, 70,184,154,154,184, 58,177,124,203,255, 0,255,203,124,177,253,199,167,146,146,168,168,146,146,
+167, 3,182, 1, 78,125,147,147,125,250,252,168,100, 97, 1, 68, 1, 8, 1, 8, 1, 68, 97,254, 21,203,231,231,203,203,231,231,
+255,255, 0,201, 0, 0, 4,139, 7, 51, 16, 39, 0,113, 0,161, 1, 61, 18, 6, 0, 40, 0, 0,255,255, 0,113,255,227, 4,127,
+ 5,246, 16, 39, 0,113, 0,150, 0, 0, 19, 6, 0, 72, 0, 0, 0, 7, 64, 3,112, 0, 1, 93, 49, 0, 0, 0,255,255, 0,201,
+ 0, 0, 4,139, 5,213, 16, 39, 6,139, 4,161, 1,117, 19, 6, 0, 40, 0, 0, 0, 7, 64, 3, 64, 0, 1, 93, 49, 0, 0, 0,
+255,255, 0,113,255,227, 4,127, 6, 72, 16, 39, 2, 49, 0,150, 0, 0, 19, 6, 0, 72, 0, 0, 0, 7, 64, 3,112, 0, 1, 93,
+ 49, 0, 0, 0,255,255, 0,201, 0, 0, 4,139, 5,213, 16, 39, 6,140, 4,161, 1,117, 18, 6, 0, 40, 0, 0,255,255, 0,113,
+255,227, 4,127, 6, 16, 16, 39, 2, 50, 0,150, 0, 0, 18, 6, 0, 72, 0, 0,255,255, 0,201,254,117, 4,141, 5,213, 16, 39,
+ 2, 52, 1,204, 0, 0, 18, 6, 0, 40, 0, 0,255,255, 0,113,254,117, 4,127, 4,123, 16, 39, 2, 52, 1,120, 0, 0, 18, 6,
+ 0, 72, 0, 0,255,255, 0,201, 0, 0, 4,139, 5,213, 18, 38, 0, 40, 0, 0, 17, 7, 6,137, 4,166, 1,111, 0, 7, 64, 3,
+ 64, 12, 1, 93, 49, 0, 0, 0,255,255, 0,113,255,227, 4,127, 6, 97, 18, 38, 0, 72, 0, 0, 17, 7, 2, 32, 0,148,255,251,
+ 0, 16,180, 0, 33, 29, 15, 7, 43, 64, 5, 15, 33, 0, 29, 2, 93, 49, 0, 0,255,255, 0,115,255,227, 5,139, 5,240, 16, 39,
+ 6,136, 5, 92, 1,117, 19, 6, 0, 42, 0, 0, 0, 9,178, 4, 4, 21, 16, 60, 61, 47, 49, 0,255,255, 0,113,254, 86, 4, 90,
+ 6,102, 16, 38, 2, 31,104, 0, 19, 6, 0, 74, 0, 0, 0, 9,178, 4, 4, 10, 16, 60, 61, 47, 49, 0, 0, 0,255,255, 0,115,
+255,227, 5,139, 5,240, 18, 38, 0, 42, 0, 0, 16, 7, 6,139, 5, 27, 1,117,255,255, 0,113,254, 86, 4, 90, 6, 72, 18, 38,
+ 0, 74, 0, 0, 16, 7, 2, 49, 0,139, 0, 0,255,255, 0,115,255,227, 5,139, 5,240, 16, 39, 6,140, 5, 92, 1,117, 19, 6,
+ 0, 42, 0, 0, 0, 8, 0, 64, 3, 63, 0, 1, 93, 48, 0, 0,255,255, 0,113,254, 86, 4, 90, 6, 16, 16, 38, 2, 50,104, 0,
+ 18, 6, 0, 74, 0, 0, 0, 0,255,255, 0,115,254, 1, 5,139, 5,240, 16, 39, 2,110, 5, 94,255,237, 18, 6, 0, 42, 0, 0,
+255,255, 0,113,254, 86, 4, 90, 6, 52, 16, 39, 2, 90, 3,224, 1, 12, 18, 6, 0, 74, 0, 0,255,255, 0,201, 0, 0, 5, 59,
+ 5,213, 16, 39, 6,136, 5, 2, 1,117, 19, 6, 0, 43, 0, 0, 0, 20,180, 12, 2, 6, 7, 7, 43, 64, 9, 47, 2, 32, 6, 31,
+ 2, 16, 6, 4, 93, 49, 0, 0,255,255, 0,186, 0, 0, 4,100, 6, 20, 16, 39, 6,136, 3, 22, 1,117, 19, 6, 0, 75, 0, 0,
+ 0, 42,180, 20, 2, 6, 19, 7, 43, 49, 0, 75,176, 14, 81, 88,187, 0, 20,255,192, 0, 19,255,192, 56, 56, 89, 64, 13,144, 20,
+144, 19,128, 20,128, 19, 64, 20, 64, 19, 6, 93, 0, 2, 0,201, 0, 0, 6,139, 5,213, 0, 19, 0, 23, 0, 58, 64, 30, 6, 2,
+ 18,149, 9, 20, 17, 12,149, 21,173, 4, 0,129, 14, 10, 7, 12, 23, 4, 28, 5, 56, 18, 13, 20, 1, 28, 0, 24, 16,220,236, 50,
+ 50,204,252,236, 50, 50,204, 49, 0, 47, 60,228, 50,252,236,220, 50, 50,236, 50, 50, 48, 1, 51, 21, 33, 53, 51, 21, 51, 21, 35,
+ 17, 35, 17, 33, 17, 35, 17, 35, 53, 51, 23, 21, 33, 53, 1,113,202, 2,222,202,168,168,202,253, 34,202,168,168,202, 2,222, 5,
+213,224,224,224,164,251,175, 2,199,253, 57, 4, 81,164,164,224,224, 0, 0, 0, 0, 1, 0,120, 0, 0, 4,159, 6, 20, 0, 27,
+ 0, 62, 64, 33, 3, 9, 0, 3, 22, 1, 14, 18,135, 13, 21, 6,135, 22, 25,184, 16,151, 10, 1, 2, 8, 0, 78, 19, 14, 17, 21,
+ 9, 8, 16, 11, 28, 16,220, 50,236, 50, 50,204,204,244,236, 49, 0, 47, 60,236,244,196,236,220, 50,236, 50, 17, 18, 23, 57, 48,
+ 1, 17, 35, 17, 52, 38, 35, 34, 6, 21, 17, 35, 17, 35, 53, 51, 53, 51, 21, 33, 21, 33, 17, 62, 1, 51, 50, 22, 4,159,184,124,
+124,149,172,185,125,125,185, 1, 96,254,160, 66,179,117,193,198, 2,164,253, 92, 2,158,159,158,190,164,253,135, 4,246,164,122,
+122,164,254,188,101,100,239, 0,255,255, 0,201, 0, 0, 1,147, 5,213, 16, 39, 6,134, 3, 46, 1,117, 19, 6, 0, 44, 0, 0,
+ 0, 8,180, 30, 9, 24, 31, 7, 43, 49, 0, 0,255,255,255,211, 0, 0, 2,103, 6, 55, 16, 39, 2, 53,255, 29, 0, 0, 19, 6,
+ 0,243, 0, 0, 0, 8,180, 28, 8, 22, 29, 7, 43, 49, 0, 0,255,255, 0, 3, 0, 0, 2, 89, 7, 49, 16, 39, 0,113,255, 46,
+ 1, 59, 19, 6, 0, 44, 0, 0, 0, 8,180, 4, 3, 2, 5, 7, 43, 49, 0, 0,255,255,255,242, 0, 0, 2, 72, 5,245, 16, 39,
+ 0,113,255, 29,255,255, 19, 6, 0,243, 0, 0, 0, 8,180, 4, 3, 2, 5, 7, 43, 49, 0, 0,255,255, 0,201, 0, 0, 1,147,
+ 5,213, 16, 39, 6,139, 3, 46, 1,117, 19, 6, 0, 44, 0, 0, 0, 8,180, 14, 0, 8, 15, 7, 43, 49, 0, 0,255,255,255,228,
+ 0, 0, 2, 86, 6, 72, 16, 39, 2, 49,255, 29, 0, 0, 19, 6, 0,243, 0, 0, 0, 8,180, 14, 0, 8, 15, 7, 43, 49, 0, 0,
+255,255, 0,176,254,117, 2, 37, 5,213, 16, 39, 2, 52,255,100, 0, 0, 18, 6, 0, 44, 0, 0,255,255, 0,150,254,117, 2, 11,
+ 6, 20, 16, 39, 2, 52,255, 74, 0, 0, 18, 6, 0, 76, 0, 0,255,255, 0,201, 0, 0, 1,147, 5,213, 18, 38, 0, 44, 0, 0,
+ 17, 7, 6,140, 3, 47, 1,117, 0, 19,179, 6, 1, 7, 0, 16, 60, 16, 60, 49, 0,180, 63, 7, 63, 6, 2, 93, 48, 0, 0, 0,
+ 0, 1, 0,193, 0, 0, 1,121, 4, 96, 0, 3, 0, 32,183, 0,191, 2, 1, 8, 0, 70, 4, 16,252,236, 49, 0, 47,236, 48, 64,
+ 11, 16, 5, 64, 5, 80, 5, 96, 5,112, 5, 5, 1, 93, 19, 51, 17, 35,193,184,184, 4, 96,251,160, 0, 0, 0,255,255, 0,201,
+254,102, 3,239, 5,213, 16, 39, 0, 45, 2, 92, 0, 0, 17, 6, 0, 44, 0, 0, 0, 8, 64, 3, 17, 4, 1, 16,236, 49, 0, 0,
+255,255, 0,193,254, 86, 3,177, 6, 20, 16, 39, 0, 77, 2, 56, 0, 0, 17, 6, 0, 76, 0, 0, 0, 8, 64, 3, 25, 70, 1, 16,
+236, 49, 0, 0,255,255,255,150,254,102, 1,147, 5,213, 16, 39, 6,136, 3, 46, 1,117, 19, 6, 0, 45, 0, 0, 0, 8,180, 8,
+ 2, 6, 7, 7, 43, 49, 0, 0,255,255,255,219,254, 86, 2, 92, 6,102, 16, 39, 2, 31,255, 29, 0, 0, 19, 6, 1,249, 0, 0,
+ 0, 8,180, 8, 2, 6, 7, 7, 43, 49, 0, 0,255,255, 0,201,254, 30, 5,106, 5,213, 16, 39, 2,110, 5, 27, 0, 10, 18, 6,
+ 0, 46, 0, 0,255,255, 0,186,254, 30, 4,156, 6, 20, 16, 39, 2,110, 4,172, 0, 10, 18, 6, 0, 78, 0, 0, 0, 1, 0,186,
+ 0, 0, 4,156, 4, 96, 0, 10, 0,187, 64, 40, 8, 17, 5, 6, 5, 7, 17, 6, 6, 5, 3, 17, 4, 5, 4, 2, 17, 5, 5, 4,
+ 66, 8, 5, 2, 3, 3, 0,188, 9, 6, 5, 1, 4, 6, 8, 1, 8, 0, 70, 11, 16,252,236, 50,212,196, 17, 57, 49, 0, 47, 60,
+236, 50, 23, 57, 48, 75, 83, 88, 7, 16, 4,237, 7, 16, 5,237, 7, 16, 5,237, 7, 16, 4,237, 89, 34,178, 16, 12, 1, 1, 93,
+ 64, 95, 4, 2, 10, 8, 22, 2, 39, 2, 41, 5, 43, 8, 86, 2,102, 2,103, 8,115, 2,119, 5,130, 2,137, 5,142, 8,147, 2,
+150, 5,151, 8,163, 2, 18, 9, 5, 9, 6, 2, 11, 3, 10, 7, 40, 3, 39, 4, 40, 5, 43, 6, 43, 7, 64, 12,104, 3, 96, 12,
+137, 3,133, 4,137, 5,141, 6,143, 7,154, 3,151, 7,170, 3,167, 5,182, 7,197, 7,214, 7,247, 3,240, 3,247, 4,240, 4,
+ 26, 93,113, 0, 93, 19, 51, 17, 1, 51, 9, 1, 35, 1, 17, 35,186,185, 2, 37,235,253,174, 2,107,240,253,199,185, 4, 96,254,
+ 27, 1,229,253,242,253,174, 2, 33,253,223, 0,255,255, 0,201, 0, 0, 4,106, 5,213, 16, 39, 6,133, 3,110, 1,118, 18, 6,
+ 0, 47, 0, 0,255,255, 0,193, 0, 0, 1,121, 6, 20, 16, 39, 6,133, 3, 90, 1,118, 19, 6, 0, 79, 0, 0, 0, 30,177, 3,
+ 4, 16, 60, 49, 0, 75,176, 14, 81, 88,185, 0, 0, 0, 64, 56, 89, 64, 7,159, 0,143, 0, 79, 0, 3, 93, 48,255,255, 0,201,
+254, 30, 4,106, 5,213, 16, 39, 2,110, 4,155, 0, 10, 18, 6, 0, 47, 0, 0,255,255, 0,136,254, 30, 1,174, 6, 20, 16, 39,
+ 2,110, 3, 30, 0, 10, 19, 6, 0, 79, 0, 0, 0, 7, 64, 3, 64, 0, 1, 93, 49, 0, 0, 0,255,255, 0,201, 0, 0, 4,106,
+ 5,213, 16, 39, 6,131, 2,159,255,195, 18, 6, 0, 47, 0, 0,255,255, 0,193, 0, 0, 1,121, 6, 20, 16, 39, 6,131, 2, 57,
+ 0, 2, 17, 6, 0, 79, 0, 0, 0, 9, 64, 5,143, 0, 31, 0, 2, 93, 49, 0,255,255, 0,201, 0, 0, 4,106, 5,213, 16, 39,
+ 0,121, 2, 49, 0,119, 18, 6, 0, 47, 0, 0,255,255, 0,193, 0, 0, 2,132, 6, 20, 16, 39, 0,121, 0,214, 0,115, 17, 6,
+ 0, 79, 0, 0, 0, 23, 75,176, 13, 81, 75,176, 17, 83, 75,176, 24, 81, 90, 91, 88,185, 0, 0, 0, 64, 56, 89, 49, 0, 0, 0,
+ 0, 1,255,242, 0, 0, 4,117, 5,213, 0, 13, 0, 63, 64, 30, 12, 11, 10, 4, 3, 2, 6, 0, 6,149, 0,129, 8, 3, 4, 1,
+ 11, 14, 0, 4, 5, 1, 28, 12, 7, 58, 9, 0,121, 14, 16,244, 60,236,196,252, 60,196, 17, 18, 57, 17, 18, 57, 49, 0, 47,228,
+236, 17, 23, 57, 48,180, 48, 15, 80, 15, 2, 1, 93, 19, 51, 17, 37, 23, 1, 17, 33, 21, 33, 17, 7, 39, 55,211,203, 1, 57, 80,
+254,119, 2,215,252, 94,148, 77,225, 5,213,253,152,219,111,254,238,253,227,170, 2, 59,106,110,158, 0, 0, 0, 0, 1, 0, 2,
+ 0, 0, 2, 72, 6, 20, 0, 11, 0, 94, 64, 26, 10, 9, 8, 4, 3, 2, 6, 0,151, 6, 3, 4, 1, 9, 10, 0, 4,122, 5, 1,
+ 8, 10,122, 7, 0, 12, 16,212, 60,228,252, 60,228, 17, 18, 57, 17, 18, 57, 49, 0, 47,236, 23, 57, 48, 1, 75,176, 16, 84, 88,
+189, 0, 12, 0, 64, 0, 1, 0, 12, 0, 12,255,192, 56, 17, 55, 56, 89, 64, 19, 16, 13, 64, 13, 80, 13, 96, 13,115, 4,122, 10,
+112, 13,224, 13,240, 13, 9, 93, 19, 51, 17, 55, 23, 7, 17, 35, 17, 7, 39, 55,199,184,125, 76,201,184,123, 74,197, 6, 20,253,
+166, 90,106,141,252,227, 2,154, 88,106,141, 0,255,255, 0,201, 0, 0, 5, 51, 5,213, 16, 39, 6,133, 4,197, 1,118, 19, 6,
+ 0, 49, 0, 0, 0, 7, 64, 3, 79, 0, 1, 93, 49, 0, 0, 0,255,255, 0,186, 0, 0, 4,100, 6,109, 16, 38, 0,118, 66, 7,
+ 19, 6, 0, 81, 0, 0, 0, 9, 64, 5, 63, 0, 79, 0, 2, 93, 49, 0, 0, 0,255,255, 0,201,254, 30, 5, 51, 5,213, 16, 39,
+ 2,110, 5, 0, 0, 10, 18, 6, 0, 49, 0, 0,255,255, 0,186,254, 30, 4,100, 4,123, 16, 39, 2,110, 4,144, 0, 10, 18, 6,
+ 0, 81, 0, 0,255,255, 0,201, 0, 0, 5, 51, 5,213, 18, 38, 0, 49, 0, 0, 17, 7, 6,137, 4,245, 1,103, 0, 20,180, 4,
+ 15, 11, 0, 7, 43, 64, 9, 47, 15, 32, 11, 31, 15, 16, 11, 4, 93, 49, 0, 0,255,255, 0,186, 0, 0, 4,100, 6,102, 18, 38,
+ 0, 81, 0, 0, 17, 7, 2, 32, 0,141, 0, 0, 0, 16,180, 0, 25, 21, 12, 7, 43, 64, 5, 15, 25, 0, 21, 2, 93, 49, 0, 0,
+255,255, 0,205, 0, 0, 5,185, 5,213, 16, 39, 0, 81, 1, 85, 0, 0, 16, 6, 2, 21, 27, 0, 0, 1, 0,213,254, 86, 5, 39,
+ 5,213, 0, 19, 0, 74, 64, 33, 17, 17, 1, 2, 1, 2, 17, 16, 17, 16, 66, 11,149, 10, 17, 2, 3, 0,175, 16, 19, 11, 16, 1,
+ 17, 2, 28, 4, 54, 17, 28, 0, 20, 16,220,236,252,236, 17, 57, 57,204, 49, 0, 47, 60,236, 50, 57, 57,220,236, 48, 75, 83, 88,
+ 7, 16, 4,237, 7, 16, 4,237, 89, 34,178, 31, 21, 1, 1, 93, 19, 51, 1, 17, 51, 17, 20, 7, 6, 43, 1, 53, 51, 50, 55, 54,
+ 53, 1, 17, 35,213,184, 2,226,184, 82, 81,181,254,233,105, 38, 38,253, 30,184, 5,213,251,131, 4,125,250, 23,214, 96, 96,156,
+ 48, 49,173, 4,125,251,131, 0, 0, 1, 0,186,254, 86, 4,100, 4,123, 0, 31, 0, 59, 64, 28, 13, 19, 0, 3, 24, 21, 7,135,
+ 6, 16,135, 24, 28,184, 22,188, 21, 7, 13, 8, 0, 78, 19, 23, 8, 22, 70, 32, 16,252,236, 50,244,236,196, 49, 0, 47,228,244,
+196,236,212,236, 17, 18, 23, 57, 48,180, 96, 33,207, 33, 2, 1, 93, 1, 17, 20, 7, 6, 43, 1, 53, 51, 50, 55, 54, 53, 17, 52,
+ 38, 35, 34, 6, 21, 17, 35, 17, 51, 21, 54, 55, 54, 51, 50, 23, 22, 4,100, 82, 81,181,254,233,105, 38, 38,124,124,149,172,185,
+185, 66, 89, 90,117,193, 99, 99, 2,164,253, 72,214, 96, 96,156, 48, 49,153, 2,178,159,158,190,164,253,135, 4, 96,174,101, 50,
+ 50,119,120, 0,255,255, 0,115,255,227, 5,217, 7, 49, 16, 39, 0,113, 1, 39, 1, 59, 19, 6, 0, 50, 0, 0, 0, 16,180, 13,
+ 2, 3, 7, 7, 43, 64, 5, 31, 2, 16, 3, 2, 93, 49, 0, 0,255,255, 0,113,255,227, 4,117, 5,245, 16, 38, 0,113,115,255,
+ 19, 6, 0, 82, 0, 0, 0, 8,180, 19, 2, 3, 25, 7, 43, 49,255,255, 0,115,255,227, 5,217, 5,240, 16, 39, 6,139, 5, 39,
+ 1,117, 19, 6, 0, 50, 0, 0, 0, 16,180, 17, 0, 8, 23, 7, 43, 64, 5, 16, 0, 31, 8, 2, 93, 49, 0, 0,255,255, 0,113,
+255,227, 4,117, 6, 72, 16, 38, 2, 49,115, 0, 19, 6, 0, 82, 0, 0, 0, 8,180, 29, 8, 0, 35, 7, 43, 49,255,255, 0,115,
+255,227, 5,217, 5,240, 16, 39, 6,141, 5, 39, 1,117, 18, 6, 0, 50, 0, 0,255,255, 0,113,255,227, 4,117, 6,102, 16, 39,
+ 2, 54, 0,160, 0, 0, 18, 6, 0, 82, 0, 0, 0, 2, 0,115, 0, 0, 8, 12, 5,213, 0, 16, 0, 25, 0, 59, 64, 31, 5,149,
+ 3, 17, 1,149, 0,129, 24, 7,149, 3,173, 9, 24, 18, 16, 10, 21, 6, 2, 28, 17, 0, 4, 8, 21, 25, 13, 16, 26, 16,252,236,
+212,196,196,212,236, 50, 18, 57, 57, 57, 57, 49, 0, 47,236,236, 50,244,236, 50, 16,238, 48, 1, 21, 33, 17, 33, 21, 33, 17, 33,
+ 21, 33, 32, 0, 17, 16, 0, 33, 23, 35, 32, 0, 17, 16, 0, 33, 51, 7,250,253, 26, 2,199,253, 57, 2,248,251,215,254, 79,254,
+ 65, 1,191, 1,177,103,129,254,191,254,192, 1, 64, 1, 65,129, 5,213,170,254, 70,170,253,227,170, 1,124, 1,112, 1,109, 1,
+124,170,254,225,254,224,254,223,254,223, 0, 0, 0, 3, 0,113,255,227, 7,195, 4,123, 0, 6, 0, 39, 0, 51, 0,132, 64, 49,
+ 7, 8, 0, 16,134, 15,136, 12, 0,169, 8, 46, 12,185, 22, 19, 40, 3,185, 8,187, 34, 37, 31,184, 25, 19,140, 52, 6, 0, 22,
+ 34, 49, 9, 15, 0, 8, 7, 75, 49, 18, 9, 81, 43, 18, 28, 69, 52, 16,252,236,244,252,244,236,196, 17, 18, 57, 57, 18, 57, 49,
+ 0, 16,228, 50,244, 60,196,228,236, 50, 16,196,238, 50, 16,238, 16,244,238, 17, 18, 57, 48, 64, 37, 63, 53, 95, 53,112, 53,159,
+ 53,207, 53,208, 53,240, 53, 7, 63, 0, 63, 6, 63, 7, 63, 8, 63, 9, 5,111, 0,111, 6,111, 7,111, 8,111, 9, 5, 93,113,
+ 1, 93, 1, 46, 1, 35, 34, 6, 7, 5, 21, 33, 30, 1, 51, 50, 54, 55, 21, 14, 1, 35, 34, 38, 39, 14, 1, 35, 34, 0, 17, 16,
+ 0, 51, 50, 22, 23, 62, 1, 51, 50, 0, 37, 34, 6, 21, 20, 22, 51, 50, 54, 53, 52, 38, 7, 10, 2,164,137,153,185, 14, 3, 72,
+252,178, 12,204,183,106,200, 98,100,208,106,160,242, 81, 71,209,140,241,254,239, 1, 17,241,140,211, 66, 78,232,143,226, 1, 8,
+250,176,148,172,171,149,147,172,172, 2,148,152,179,174,158, 53, 90,190,199, 52, 52,174, 42, 44,110,109,110,109, 1, 57, 1, 19,
+ 1, 20, 1, 56,111,108,107,112,254,221,135,231,201,201,231,232,200,199,233, 0,255,255, 0,201, 0, 0, 5, 84, 5,213, 16, 39,
+ 6,133, 4,149, 1,118, 18, 6, 0, 53, 0, 0,255,255, 0,186, 0, 0, 3,149, 6,109, 16, 38, 0,118, 66, 7, 18, 6, 0, 85,
+ 0, 0, 0, 0,255,255, 0,201,254, 30, 5, 84, 5,213, 16, 39, 2,110, 5, 16, 0, 10, 18, 6, 0, 53, 0, 0,255,255, 0,130,
+254, 30, 3, 74, 4,123, 16, 39, 2,110, 3, 24, 0, 10, 18, 6, 0, 85, 0, 0,255,255, 0,201, 0, 0, 5, 84, 5,213, 18, 38,
+ 0, 53, 0, 0, 17, 7, 6,137, 4,125, 1,103, 0, 8, 0, 64, 3, 95, 29, 1, 93, 48, 0, 0,255,255, 0,186, 0, 0, 3, 90,
+ 6,102, 18, 38, 0, 85, 0, 0, 17, 6, 2, 32, 27, 0, 0, 16,180, 17, 23, 19, 9, 7, 43, 64, 5, 15, 23, 0, 19, 2, 93, 49,
+255,255, 0,135,255,227, 4,162, 5,240, 16, 39, 6,133, 4,149, 1,118, 18, 6, 0, 54, 0, 0,255,255, 0,111,255,227, 3,199,
+ 6,109, 16, 38, 0,118, 66, 7, 18, 6, 0, 86, 0, 0, 0, 0,255,255, 0,135,255,227, 4,162, 5,240, 16, 39, 6,136, 4,147,
+ 1,117, 19, 6, 0, 54, 0, 0, 0, 11,180, 4, 32, 21, 41, 41, 16, 73, 99, 58, 49, 0, 0, 0,255,255, 0,111,255,227, 3,199,
+ 6,102, 16, 38, 2, 31, 37, 0, 19, 6, 0, 86, 0, 0, 0, 11,180, 4, 32, 21, 41, 41, 16, 73, 99, 58, 49, 0,255,255, 0,135,
+254,117, 4,162, 5,240, 18, 38, 0, 54, 0, 0, 16, 7, 0,122, 0,139, 0, 0,255,255, 0,111,254,117, 3,199, 4,123, 18, 38,
+ 0, 86, 0, 0, 16, 6, 0,122, 23, 0, 0, 0,255,255, 0,135,255,227, 4,162, 5,240, 18, 38, 0, 54, 0, 0, 17, 7, 6,137,
+ 4,139, 1,117, 0, 11,180, 43, 32, 14, 34, 34, 16, 73, 99, 58, 49, 0, 0, 0,255,255, 0,111,255,227, 3,199, 6,102, 18, 38,
+ 0, 86, 0, 0, 17, 6, 2, 32, 23, 0, 0, 11,180, 43, 32, 14, 34, 34, 16, 73, 99, 58, 49, 0,255,255,255,250,254,117, 4,233,
+ 5,213, 16, 38, 0,122, 80, 0, 18, 6, 0, 55, 0, 0, 0, 0,255,255, 0, 55,254,117, 2,242, 5,158, 16, 38, 0,122,225, 0,
+ 18, 6, 0, 87, 0, 0, 0, 0,255,255,255,250, 0, 0, 4,233, 5,213, 18, 38, 0, 55, 0, 0, 17, 7, 6,137, 4,115, 1,103,
+ 0, 16,180, 1, 13, 9, 0, 7, 43, 49, 0, 64, 3, 95, 8, 1, 93, 48, 0, 0,255,255, 0, 55, 0, 0, 2,242, 5,158, 18, 38,
+ 0, 87, 0, 0, 17, 7, 6,131, 2, 55, 0,112, 0, 7, 64, 3,143, 20, 1, 93, 49, 0, 0, 0, 0, 1,255,250, 0, 0, 4,233,
+ 5,213, 0, 15, 0, 70, 64, 24, 7, 11,149, 4, 12, 9, 3, 15,149, 0,129, 9, 5, 1, 64, 7, 3, 28, 12, 0, 64, 10, 14, 16,
+ 16,212, 60,228,204,252, 60,228,204, 49, 0, 47,244,236, 50, 16,212, 60,236, 50, 48, 1, 64, 19, 0, 17, 31, 0, 16, 1, 16, 2,
+ 31, 15, 16, 17, 64, 17,112, 17,159, 17, 9, 93, 3, 33, 21, 33, 17, 33, 21, 33, 17, 35, 17, 33, 53, 33, 17, 33, 6, 4,239,253,
+238, 1, 9,254,247,203,254,247, 1, 9,253,238, 5,213,170,253,192,170,253,191, 2, 65,170, 2, 64, 0, 0, 0, 0, 1, 0, 55,
+ 0, 0, 2,242, 5,158, 0, 29, 0, 67, 64, 31, 8, 22,169, 5, 23, 4, 26,169, 0, 1, 27,188, 13,135, 16, 16, 13, 14, 2, 6,
+ 8, 4, 0, 8, 23, 27, 21, 25, 29, 70, 30, 16,252, 60, 60,196, 50,252, 60, 60,196,196, 50, 57, 57, 49, 0, 47,236,244, 60,196,
+252, 60,220, 60,236, 50, 48,178,175, 31, 1, 1, 93, 1, 17, 33, 21, 33, 21, 51, 21, 35, 21, 20, 23, 22, 59, 1, 21, 35, 34, 39,
+ 38, 61, 1, 35, 53, 51, 53, 35, 53, 51, 17, 1,119, 1,123,254,133,190,190, 37, 38,115,189,189,213, 81, 81,135,135,135,135, 5,
+158,254,194,143,233,142,233,137, 39, 39,154, 80, 79,210,233,142,233,143, 1, 62,255,255, 0,178,255,227, 5, 41, 5,213, 16, 39,
+ 6,134, 4,238, 1,117, 19, 6, 0, 56, 0, 0, 0, 16,180, 31, 9, 24, 39, 7, 43, 64, 5, 16, 9, 31, 24, 2, 93, 49, 0, 0,
+255,255, 0,174,255,227, 4, 88, 6, 55, 16, 39, 2, 53, 0,131, 0, 0, 19, 6, 0, 88, 0, 0, 0, 8,180, 30, 8, 22, 38, 7,
+ 43, 49, 0, 0,255,255, 0,178,255,227, 5, 41, 7, 49, 16, 39, 0,113, 0,238, 1, 59, 19, 6, 0, 56, 0, 0, 0, 20,180, 5,
+ 3, 2, 13, 7, 43, 64, 9, 47, 2, 32, 3, 31, 2, 16, 3, 4, 93, 49, 0, 0,255,255, 0,174,255,227, 4, 88, 5,245, 16, 39,
+ 0,113, 0,131,255,255, 19, 6, 0, 88, 0, 0, 0, 8,180, 6, 3, 2, 14, 7, 43, 49, 0, 0,255,255, 0,178,255,227, 5, 41,
+ 5,213, 16, 39, 6,139, 4,238, 1,117, 19, 6, 0, 56, 0, 0, 0, 16,180, 15, 0, 8, 23, 7, 43, 64, 5, 16, 0, 31, 8, 2,
+ 93, 49, 0, 0,255,255, 0,174,255,227, 4, 88, 6, 72, 16, 39, 2, 49, 0,131, 0, 0, 19, 6, 0, 88, 0, 0, 0, 8,180, 16,
+ 0, 8, 24, 7, 43, 49, 0, 0,255,255, 0,178,255,227, 5, 41, 8, 75, 18, 38, 0, 56, 0, 0, 17, 7, 2, 51, 0,240, 1, 69,
+ 0, 9, 64, 5, 64, 30, 64, 18, 2, 93, 49, 0,255,255, 0,174,255,227, 4, 88, 6,202, 18, 38, 0, 88, 0, 0, 17, 6, 2, 51,
+124,196, 0, 9, 64, 5, 64, 20, 64, 32, 2, 93, 49, 0, 0, 0,255,255, 0,178,255,227, 5, 41, 5,213, 16, 39, 6,141, 4,238,
+ 1,117, 18, 6, 0, 56, 0, 0,255,255, 0,174,255,227, 4, 94, 6,102, 16, 39, 2, 54, 0,176, 0, 0, 18, 6, 0, 88, 0, 0,
+255,255, 0,178,254,101, 5, 41, 5,213, 18, 38, 0, 56, 0, 0, 16, 7, 2, 52, 0,250,255,240,255,255, 0,174,254,117, 4,232,
+ 4, 96, 18, 38, 0, 88, 0, 0, 16, 7, 2, 52, 2, 39, 0, 0,255,255, 0, 68, 0, 0, 7,166, 5,213, 16, 39, 6,136, 5,245,
+ 1,124, 19, 6, 0, 58, 0, 0, 0, 8,180, 21, 2, 6, 20, 7, 43, 49, 0, 0,255,255, 0, 86, 0, 0, 6, 53, 6,109, 16, 39,
+ 2, 31, 1, 69, 0, 7, 19, 6, 0, 90, 0, 0, 0, 8,180, 21, 2, 6, 20, 7, 43, 49, 0, 0,255,255,255,252, 0, 0, 4,231,
+ 5,213, 16, 39, 6,136, 4,114, 1,124, 19, 6, 0, 60, 0, 0, 0, 8,180, 11, 2, 6, 7, 7, 43, 49, 0, 0,255,255, 0, 61,
+254, 86, 4,127, 6,109, 16, 38, 2, 31, 94, 7, 19, 6, 0, 92, 0, 0, 0, 8,180, 24, 2, 6, 23, 7, 43, 49,255,255,255,252,
+ 0, 0, 4,231, 5,213, 18, 38, 0, 60, 0, 0, 17, 7, 6,132, 4,115, 1,117, 0, 8,180, 0, 16, 11, 4, 7, 43, 49, 0, 0,
+255,255, 0, 92, 0, 0, 5, 31, 5,213, 16, 39, 6,133, 4,149, 1,118, 18, 6, 0, 61, 0, 0,255,255, 0, 88, 0, 0, 3,219,
+ 6,109, 16, 38, 0,118, 66, 7, 18, 6, 0, 93, 0, 0, 0, 0,255,255, 0, 92, 0, 0, 5, 31, 5,213, 16, 39, 6,140, 4,168,
+ 1, 98, 18, 6, 0, 61, 0, 0,255,255, 0, 88, 0, 0, 3,219, 6, 16, 16, 38, 2, 50, 0, 0, 18, 6, 0, 93, 0, 0, 0, 0,
+255,255, 0, 92, 0, 0, 5, 31, 5,213, 18, 38, 0, 61, 0, 0, 16, 7, 6,137, 4,190, 1,117,255,255, 0, 88, 0, 0, 3,219,
+ 6,102, 18, 38, 0, 93, 0, 0, 17, 6, 2, 32, 27, 0, 0, 16,180, 1, 15, 11, 0, 7, 43, 64, 5, 15, 15, 0, 11, 2, 93, 49,
+ 0, 1, 0, 47, 0, 0, 2,248, 6, 20, 0, 16, 0, 35, 64, 18, 11,135, 10,151, 1, 2,169, 5,188, 1, 10, 16, 8, 4, 6, 2,
+ 76, 17, 16,252, 60,204,252,204, 49, 0, 47,244,236, 16,244,236, 48, 33, 35, 17, 35, 53, 51, 53, 52, 54, 59, 1, 21, 35, 34, 7,
+ 6, 21, 1,152,185,176,176,174,189,174,176, 99, 39, 38, 3,209,143, 78,187,171,153, 40, 41,103, 0, 2, 0, 32,255,227, 4,164,
+ 6, 20, 0, 15, 0, 44, 0, 68, 64, 37, 4,185, 16, 20, 12,185, 32, 28,140, 20,184, 34, 41, 37,169, 44, 36, 39,151, 34, 46, 69,
+ 0, 18, 24, 71, 42, 32, 6, 44, 40, 8, 37, 35, 39, 70, 45, 16,252, 60,204,236, 50, 50, 50,204,244,236,236, 49, 0, 47,244,220,
+ 60,236, 50, 16,228,244,196,236, 16,198,238, 48, 1, 52, 39, 38, 35, 34, 7, 6, 21, 20, 23, 22, 51, 50, 55, 54, 1, 54, 55, 54,
+ 51, 50, 23, 22, 17, 16, 7, 6, 35, 34, 39, 38, 39, 21, 35, 17, 35, 53, 51, 53, 51, 21, 33, 21, 33, 3,229, 83, 84,146,146, 84,
+ 83, 83, 84,146,146, 84, 83,253,142, 58, 89, 88,123,204,127,128,128,127,204,123, 88, 89, 58,185,154,154,185, 1, 69,254,187, 2,
+ 47,203,116,115,115,116,203,203,116,115,115,116, 2, 82,100, 48, 49,162,162,254,248,254,248,162,162, 49, 48,100,168, 5, 4,125,
+147,147,125, 0, 0, 3,255,151, 0, 0, 5, 80, 5,213, 0, 8, 0, 17, 0, 41, 0, 67, 64, 35, 25, 0,149, 10, 9,149, 18,129,
+ 1,149, 10,173, 31, 17, 11, 8, 2, 19, 25, 31, 5, 0, 14, 28, 22, 5, 25, 28, 46, 9, 0, 28, 18, 4, 42, 16,252,236, 50,252,
+236,212,236, 17, 23, 57, 57, 57, 49, 0, 47,236,236,244,236, 16,238, 57, 48,178, 15, 34, 1, 1, 93, 1, 17, 33, 50, 54, 53, 52,
+ 38, 35, 1, 17, 33, 50, 54, 53, 52, 38, 35, 37, 33, 50, 22, 21, 20, 6, 7, 30, 1, 21, 20, 4, 35, 33, 17, 34, 6, 29, 1, 35,
+ 53, 52, 54, 1,247, 1, 68,163,157,157,163,254,188, 1, 43,148,145,145,148,254, 11, 2, 4,231,250,128,124,149,165,254,240,251,
+253,232,132,118,156,192, 2,201,253,221,135,139,140,133, 2,102,254, 62,111,114,113,112,166,192,177,137,162, 20, 32,203,152,200,
+218, 5, 48, 95,105, 49, 70,181,163, 0, 0, 0,255,255, 0,201, 0, 0, 4,236, 5,213, 18, 6, 3, 46, 0, 0, 0, 2, 0,186,
+255,227, 4,164, 6, 20, 0, 22, 0, 38, 0, 56, 64, 31, 27,185, 0, 4, 35,185, 16, 12,140, 4,184, 18, 22,169, 19,151, 18, 40,
+ 69, 20, 23, 18, 8, 71, 16, 31, 22, 8, 19, 70, 39, 16,252,236, 50, 50,244,236,196,236, 49, 0, 47,244,236, 16,228,244,196,236,
+ 16,198,238, 48, 1, 54, 55, 54, 51, 50, 23, 22, 17, 16, 7, 6, 35, 34, 39, 38, 39, 21, 35, 17, 33, 21, 37, 1, 52, 39, 38, 35,
+ 34, 7, 6, 21, 20, 23, 22, 51, 50, 55, 54, 1,115, 58, 89, 88,123,204,127,128,128,127,204,123, 88, 89, 58,185, 3, 78,253,107,
+ 2,114, 83, 84,146,146, 84, 83, 83, 84,146,146, 84, 83, 3,182,100, 48, 49,162,162,254,248,254,248,162,162, 49, 48,100,168, 6,
+ 20,166, 1,252,192,203,116,115,115,116,203,203,116,115,115,116, 0, 2, 0, 0, 0, 0, 4,236, 5,213, 0, 10, 0, 23, 0, 51,
+ 64, 12, 23, 11, 25, 0, 25, 16, 46, 5, 11, 28, 21, 22, 47,220,236, 50,252,236,196, 16,204, 49, 64, 9, 5,149, 12,173, 11,129,
+ 6,149, 20, 0, 47,236,228,244,236,179, 21, 21, 11, 20, 17, 18, 57, 47, 48, 1, 52, 39, 38, 35, 33, 17, 33, 50, 55, 54, 1, 17,
+ 33, 50, 4, 21, 20, 4, 35, 33, 17, 35, 1, 4, 23, 79, 78,163,254,188, 1, 68,163, 78, 79,253,124, 1, 78,251, 1, 16,254,240,
+251,253,232,201, 1, 56, 1,183,139, 68, 67,253,221, 68, 67, 4,168,253,154,218,222,221,218, 4, 68, 1,145, 0, 0, 2, 0, 0,
+255,227, 4,164, 6, 21, 0, 18, 0, 30, 0, 62, 64, 13, 17, 18, 32, 19, 18, 6, 71, 13, 25, 18, 8, 15, 16, 47,220,236, 50, 50,
+244,236,196, 16,204, 49, 64, 14, 0, 22,185, 3,184, 14, 12, 28,185, 9,140, 17,151, 14, 0, 47,228,244,236,196, 16,244,236,196,
+179, 15, 15, 17, 14, 17, 18, 57, 47, 48, 1, 62, 1, 51, 50, 0, 17, 16, 2, 35, 34, 38, 39, 21, 35, 17, 35, 1, 51, 1, 52, 38,
+ 35, 34, 6, 21, 20, 22, 51, 50, 54, 1,115, 58,177,123,204, 0,255,255,204,123,177, 58,185,186, 1, 34, 81, 2,114,167,146,146,
+167,167,146,146,167, 3,182,100, 97,254,188,254,248,254,248,254,188, 97,100,168, 4, 68, 1,209,252, 26,203,231,231,203,203,231,
+231, 0, 0, 0, 0, 1, 0,115,255,227, 5, 39, 5,240, 0, 25, 0, 48, 64, 27, 25,134, 0,136, 22,149, 3,145, 26, 13,134, 12,
+136, 16,149, 9,140, 26, 27, 16, 19, 25, 6, 48, 13, 0, 26, 16,220, 60,244,236,236, 49, 0, 16,244,236,244,236, 16,244,236,244,
+236, 48, 19, 62, 1, 51, 32, 0, 17, 16, 0, 33, 34, 38, 39, 53, 30, 1, 51, 32, 0, 17, 16, 0, 33, 34, 6, 7,115,104,237,134,
+ 1, 83, 1,134,254,122,254,173,132,237,106,102,231,130, 1, 0, 1, 16,254,240,255, 0,130,231,102, 5, 98, 71, 71,254, 97,254,
+152,254,153,254, 97, 72, 72,211, 95, 94, 1, 57, 1, 39, 1, 40, 1, 57, 94, 95, 0, 1, 0,115,255,227, 6, 90, 7,100, 0, 36,
+ 0, 0, 1, 54, 55, 54, 59, 1, 21, 35, 34, 6, 29, 1, 46, 1, 35, 32, 0, 17, 16, 0, 33, 50, 54, 55, 21, 14, 1, 35, 32, 0,
+ 17, 16, 0, 33, 50, 23, 22, 4, 97, 16, 83,102,227, 77, 63,134,110,102,231,130,255, 0,254,240, 1, 16, 1, 0,130,231,102,106,
+237,132,254,173,254,122, 1,134, 1, 83,134,118, 13, 5,197,195, 98,122,170,150,194,213, 95, 94,254,199,254,216,254,217,254,199,
+ 94, 95,211, 72, 72, 1,159, 1,103, 1,104, 1,159, 36, 3, 0, 0, 1, 0,113,255,227, 4,205, 5,203, 0, 33, 0, 0, 1, 54,
+ 55, 54, 59, 1, 21, 35, 34, 6, 29, 1, 46, 1, 35, 34, 6, 16, 22, 51, 50, 54, 55, 21, 14, 1, 35, 34, 0, 17, 16, 0, 33, 50,
+ 3, 49, 9, 70, 82,181, 70, 49,105, 76, 78,157, 80,179,198,198,179, 80,157, 78, 77,165, 93,253,254,214, 1, 45, 1, 6, 72, 4,
+111,169, 83, 96,156, 97,153,172, 43, 43,227,254,102,227, 43, 43,170, 36, 36, 1, 62, 1, 14, 1, 18, 1, 58, 0,255,255, 0, 10,
+ 0, 0, 5,186, 5,213, 16, 6, 0,146, 0, 0, 0, 2,255,151, 0, 0, 6, 20, 5,213, 0, 8, 0, 26, 0, 46, 64, 21, 0,149,
+ 9,129, 1,149, 16, 8, 2, 16, 10, 0, 5, 25, 13, 50, 0, 28, 9, 4, 27, 16,252,236,244,236, 17, 57, 57, 57, 57, 49, 0, 47,
+236,244,236, 48,178, 96, 19, 1, 1, 93, 1, 17, 51, 32, 0, 17, 16, 0, 33, 37, 33, 32, 0, 17, 16, 0, 41, 1, 17, 34, 6, 29,
+ 1, 35, 53, 52, 54, 1,247,244, 1, 53, 1, 31,254,225,254,203,254, 66, 1,159, 1,178, 1,150,254,104,254, 80,254, 97,132,118,
+156,192, 5, 47,251,119, 1, 24, 1, 46, 1, 44, 1, 23,166,254,151,254,128,254,126,254,150, 5, 48, 95,105, 49, 70,181,163, 0,
+ 0, 2, 0,201, 0, 0, 4,236, 5,213, 0, 7, 0, 20, 0, 46, 64, 12, 22, 8, 4, 19, 28, 10, 46, 0, 25, 14, 16, 21, 16,252,
+236,244,236, 50,196,196, 49, 64, 12, 19,149, 9,129, 10, 4,149, 18,173, 3,149, 10, 0, 47,236,244,236, 16,244,236, 48, 1, 16,
+ 41, 1, 17, 33, 34, 6, 17, 33, 17, 33, 34, 36, 53, 52, 36, 51, 33, 17, 33, 1,158, 1, 64, 1, 68,254,188,163,157, 3, 78,253,
+232,251,254,240, 1, 16,251, 1, 78,253,124, 1,183,254,239, 2, 35,135, 3,147,250, 43,218,222,221,218, 1,192, 0, 2, 0,113,
+255,227, 4, 90, 6, 20, 0, 17, 0, 25, 0, 0, 1, 17, 5, 53, 33, 17, 35, 53, 14, 1, 35, 34, 2, 16, 0, 51, 50, 22, 0, 16,
+ 22, 32, 54, 16, 38, 32, 3,162,253,107, 3, 77,184, 58,177,123,204,255, 0,255,204,123,177,253,200,167, 1, 36,167,167,254,220,
+ 3,182, 1,185, 1,166,249,236,168,100, 97, 1, 68, 2, 16, 1, 68, 97,254,224,254,106,231,231, 1,150,231, 0, 0, 2, 0,113,
+254, 86, 4,117, 4, 99, 0, 28, 0, 45, 0, 0, 23, 22, 51, 50, 53, 52, 37, 38, 39, 38, 17, 16, 55, 54, 51, 50, 23, 22, 17, 20,
+ 7, 6, 7, 22, 21, 16, 33, 34, 39, 1, 54, 55, 54, 53, 52, 39, 38, 35, 34, 6, 21, 20, 23, 22, 23, 22,250,102,239,253,254,248,
+208,117,142,137,137,240,239,138,137,137, 53, 75,156,254, 71,221,120, 1,232, 68, 55, 86, 85, 86,149,147,172, 91, 97,126, 64,203,
+ 70,117, 92, 48, 37,112,135, 1, 21, 1, 9,156,157,157,156,254,237,204,165, 64, 36, 79,141,254,240, 70, 1,216, 29, 73,113,204,
+203,114,115,232,190,199, 96,103, 11, 6, 0, 0, 0, 1, 0,131, 0, 0, 4, 69, 5,213, 0, 11, 0, 43, 64, 9, 13, 5, 9, 28,
+ 0, 11, 7, 2, 12, 16,220,196,196,212,236, 50,196, 49, 64, 12, 10,149, 11,129, 2, 6,149, 7,173, 3,149, 2, 0, 47,236,244,
+236, 16,244,236, 48, 1, 17, 33, 53, 33, 17, 33, 53, 33, 17, 33, 53, 4, 69,252, 62, 2,248,253, 57, 2,199,253, 26, 5,213,250,
+ 43,170, 2, 29,170, 1,186,170, 0, 2, 0,117,255,227, 5,217, 5,240, 0, 19, 0, 26, 0, 68, 64, 38, 1, 20, 0, 8,161, 7,
+174, 4, 0,149, 20, 23,149, 17, 0,149, 20,173, 4,149, 11,145, 17,140, 27, 1, 20, 26, 26, 25, 15, 51, 20, 25, 7, 0, 16, 27,
+ 16,252,196,236,244,236, 17, 18, 57, 49, 0, 16,228,244,236,244,228, 16,238, 16,238, 16,244,238, 17, 18, 57, 48, 19, 33, 16, 0,
+ 33, 34, 6, 7, 53, 54, 36, 51, 32, 0, 17, 16, 0, 33, 32, 0, 55, 22, 0, 51, 50, 0, 55,117, 4,143,254,237,254,238,139,252,
+112,111, 1, 7,146, 1, 94, 1,139,254,136,254,198,254,183,254,151,220, 13, 0,255,202,202, 0,255, 13, 3, 12, 1, 12, 1, 50,
+ 96, 95,215, 70, 72,254,103,254,146,254,159,254, 91, 1,183,204,195,254,228, 1, 28,195, 0, 0, 0, 1, 0,164,255,227, 4,123,
+ 5,240, 0, 40, 0, 64, 64, 36, 10,134, 9,136, 13,149, 6,145, 41, 0, 22,149, 19,173, 41, 31,134, 32,136, 28,149, 35,140, 41,
+ 42, 20, 9, 31, 16, 25, 3, 25, 25, 38, 16, 41, 16,252,236,212,236,212,196,196,204, 49, 0, 16,244,236,244,236, 16,244,236, 57,
+ 16,244,236,244,236, 48, 1, 46, 1, 53, 52, 36, 51, 50, 22, 23, 21, 46, 1, 35, 34, 6, 21, 20, 22, 59, 1, 21, 35, 34, 6, 21,
+ 20, 22, 51, 50, 54, 55, 21, 14, 1, 35, 32, 36, 53, 52, 54, 1,216,131,142, 1, 12,230, 89,201,115,114,190, 83,152,163,158,149,
+182,174,165,185,199,190,109,200, 84,106,199, 94,254,232,254,208,163, 3, 37, 33,171,124,178,209, 32, 32,180, 38, 36,123,115,112,
+119,166,149,132,143,150, 50, 49,195, 37, 37,242,221,144,196, 0, 0, 1,255,150,254,102, 4, 35, 5,213, 0, 17, 0, 65, 64, 31,
+ 17, 8, 18, 13,149, 12,176, 18, 6,149, 4, 2,149, 0,129, 4,173, 18, 17, 8, 0, 7, 12, 5, 1, 7, 3, 28, 0, 4, 18, 16,
+252,236, 50,212,196,196, 17, 18, 57, 57, 49, 0, 16,236,244,236, 16,238, 16,244,236, 16, 57, 57, 48,178, 15, 11, 1, 1, 93, 19,
+ 33, 21, 33, 17, 33, 21, 33, 17, 16, 6, 43, 1, 53, 51, 50, 54, 53,201, 3, 90,253,112, 2, 80,253,176,205,227, 77, 63,134,110,
+ 5,213,170,254, 72,170,253,159,254,242,244,170,150,194, 0, 0, 0, 1,255,127,254, 86, 2,248, 6, 20, 0, 27, 0,101, 64, 35,
+ 19, 10, 15,135, 13,189, 29, 5, 24, 1, 20, 8,169, 6, 1,135, 0,151, 22, 6,188, 28, 2, 27, 7, 0, 7, 9, 5, 8, 21, 23,
+ 19, 76, 28, 16,252, 75,176, 10, 84, 88,185, 0, 19, 0, 64, 56, 89, 75,176, 22, 84, 88,185, 0, 19,255,192, 56, 89, 60,196,252,
+ 60,196,196, 18, 57, 57, 49, 0, 16,228, 50,252,236, 16,238, 50, 18, 57, 57, 16,244,236, 57, 57, 48, 1,182, 64, 29, 80, 29,160,
+ 29, 3, 93, 1, 21, 35, 34, 6, 29, 1, 33, 21, 33, 17, 20, 6, 43, 1, 53, 51, 50, 54, 53, 17, 35, 53, 51, 53, 52, 54, 51, 2,
+248,176, 99, 77, 1, 47,254,209,174,189,174,176, 99, 77,176,176,174,189, 6, 20,153, 80,104, 99,143,251,235,187,171,153, 80,104,
+ 4, 42,143, 78,187,171, 0, 0, 0, 1, 0,115,255,227, 6,151, 7,100, 0, 38, 0, 70, 64, 39, 22,149, 21, 39, 0, 5, 36, 1,
+149, 3, 36,149, 8, 26,161, 27, 30,149, 14,145, 8,140, 39, 21, 2, 0, 28, 4, 17, 28, 26, 52, 4, 51, 33, 25, 11, 70, 39, 16,
+252,236,252,244,236, 16,252,196,196, 49, 0, 16,228,244,252,244,204, 16,254,212,238, 17, 57, 57, 16,220,236, 48, 37, 17, 33, 53,
+ 33, 17, 6, 4, 35, 32, 0, 17, 16, 0, 33, 50, 22, 23, 52, 54, 59, 1, 21, 35, 34, 6, 29, 1, 46, 1, 35, 32, 0, 17, 16, 0,
+ 33, 50, 54, 4,195,254,182, 2, 18,117,254,230,160,254,162,254,117, 1,139, 1, 94, 91,163, 68,201,227, 77, 63,134,110,112,252,
+139,254,238,254,237, 1, 19, 1, 18,107,168,213, 1,145,166,253,127, 83, 85, 1,153, 1,109, 1,110, 1,153, 25, 25,188,234,170,
+150,194,215, 95, 96,254,206,254,209,254,210,254,206, 37, 0, 0, 0, 2, 0, 8,254, 82, 5,118, 5,213, 0, 15, 0, 37, 0,149,
+ 64, 13, 39, 80, 18, 1, 18, 4, 25, 23, 12, 25, 31, 36, 38, 16,212,212,236,212,236,212, 93,196,181, 16, 8, 0, 3, 4, 12, 17,
+ 18, 23, 57, 49, 64, 10, 0,149, 27,189, 17, 37, 18, 36,129, 38, 0, 16,228, 50, 50, 50,244,236,179, 31, 23, 8, 27, 17, 18, 57,
+ 57, 48, 64, 12, 19, 17, 17, 18, 18, 8, 35, 37, 17, 36, 36, 8, 7, 5, 16,236, 60, 7, 16,236, 60,182, 19, 17, 8, 18, 8, 36,
+ 8, 7, 8, 16,236,182, 35, 17, 8, 36, 8, 18, 8, 7, 8, 16,236,180, 16, 37, 19, 17, 35, 15, 64, 16, 22, 21, 20, 3, 23, 19,
+ 36, 8, 34, 33, 32, 3, 31, 35, 18, 8, 4, 7, 17, 18, 23, 57, 7, 17, 18, 23, 57, 1, 50, 55, 54, 53, 52, 39, 38, 39, 6, 7,
+ 6, 21, 20, 23, 22, 19, 1, 51, 1, 22, 23, 22, 21, 20, 7, 6, 35, 34, 39, 38, 53, 52, 55, 54, 55, 1, 51, 2,191, 54, 44, 28,
+ 31, 51, 44, 44, 51, 31, 28, 44, 54, 1,217,222,253,186,104, 67, 46, 75,100,155,155,100, 75, 46, 67,104,253,186,222,254,253, 32,
+ 20, 66, 57, 73,121, 92, 92,121, 73, 57, 66, 20, 32, 3,122, 3, 94,251,207,200,174,119, 66,139, 65, 87, 87, 65,139, 66,119,174,
+200, 4, 49, 0, 0, 1, 0,186, 0, 0, 7, 71, 6, 20, 0, 67, 0, 0, 1, 52, 38, 35, 34, 6, 7, 17, 35, 17, 51, 17, 52, 54,
+ 51, 50, 22, 21, 17, 20, 23, 22, 59, 1, 50, 63, 1, 53, 51, 63, 2, 53, 51, 55, 53, 51, 53, 55, 51, 53, 63, 2, 54, 53, 52, 39,
+ 38, 39, 33, 22, 23, 22, 23, 22, 23, 22, 21, 20, 7, 6, 35, 7, 6, 39, 38, 53, 4,100,198,193,117,179, 66,185,185,172,149,124,
+124, 81, 82,181, 70,225,142, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 35, 30, 66, 54, 56,114,254,190, 46, 76, 77, 55, 15, 24,
+ 66, 88, 88,144, 51,103, 40, 38, 2,164,232,239,100,101, 2, 98,249,236, 2,121,164,190,158,156,254,245,214, 96, 96,146, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 42, 47,119,161,136,110,113,100, 12, 44, 45, 72, 21, 36,100,146,158, 98, 97, 1, 2, 50,
+ 49,153, 0, 0, 0, 1, 0,201, 0, 0, 2,198, 5,213, 0, 11, 0, 46, 64, 16, 11, 2, 0, 6,149, 0,129, 7, 5, 8, 6, 1,
+ 28, 0, 4, 12, 16,252, 75,176, 16, 84, 88,185, 0, 0, 0, 64, 56, 89,236,196, 57, 57, 49, 0, 47,228,236, 17, 57, 57, 48, 1,
+ 19, 51, 17, 20, 22, 59, 1, 21, 35, 34, 38, 17,201,202,110,134, 63, 77,227,205, 5,213,252, 45,194,150,170,244, 1, 14, 0, 0,
+ 0, 1, 0, 10, 0, 0, 2, 82, 5,213, 0, 11, 0, 69, 64, 17, 2, 11,149, 5, 8, 0,175, 6, 3, 5, 1, 28, 10, 8, 0, 4,
+ 12, 16,252, 60,196, 75,176, 16, 84, 88,187, 0, 8, 0, 64, 0, 0, 0, 64, 56, 56, 89,236, 50,196, 49, 0, 47,236,220, 60,244,
+ 50, 48, 1, 64, 13, 48, 13, 64, 13, 80, 13, 96, 13,143, 13,159, 13, 6, 93, 19, 51, 17, 51, 21, 35, 17, 35, 17, 35, 53, 51,201,
+202,191,191,202,191,191, 5,213,253, 22,170,253,191, 2, 65,170, 0, 1, 0,201, 0, 0, 5,221, 5,222, 0, 18, 0, 0, 1, 54,
+ 31, 1, 55, 39, 38, 7, 6, 7, 1, 17, 35, 17, 51, 17, 1, 33, 1, 4, 80, 62, 58,172,105,237, 96, 76, 53, 71,253,203,202,202,
+ 2,205, 1, 10,252,230, 4,254, 59, 33,141,116,176, 72, 39, 27, 67,253,236, 2,119,250, 43, 2,207,253, 49, 3, 29, 0, 0, 0,
+ 0, 1, 0,185, 0, 0, 4,156, 6, 20, 0, 18, 0,193, 64, 44, 16, 17, 13, 14, 13, 15, 17, 14, 14, 13, 11, 17, 12, 13, 12, 10,
+ 17, 13, 13, 12, 66, 16, 13, 10, 3, 6,149, 3,151, 11,188, 17, 14, 4, 13, 9, 12, 14, 16, 9, 8, 0, 70, 19, 16,252,236, 50,
+212,196, 17, 57,196, 49, 0, 47, 60,228,252,228, 23, 57, 48, 75, 83, 88, 7, 16, 4,237, 7, 16, 5,237, 7, 16, 5,237, 7, 16,
+ 4,237, 89, 34,178, 16, 12, 1, 1, 93, 64, 95, 4, 10, 10, 16, 22, 10, 39, 10, 41, 13, 43, 16, 86, 10,102, 10,103, 16,115, 10,
+119, 13,130, 10,137, 13,142, 16,147, 10,150, 13,151, 16,163, 10, 18, 17, 5, 17, 6, 10, 11, 11, 10, 15, 40, 11, 39, 12, 40, 13,
+ 43, 14, 43, 15, 64, 20,104, 11, 96, 20,137, 11,133, 12,137, 13,141, 14,143, 15,154, 11,151, 15,170, 11,167, 13,182, 15,197, 15,
+214, 15,247, 11,240, 11,247, 12,240, 12, 26, 93,113, 0, 93, 19, 52, 54, 59, 1, 21, 35, 34, 6, 21, 17, 1, 51, 9, 1, 35, 1,
+ 17, 35,185,163,181,191,168,105, 76, 2, 37,235,253,174, 2,107,240,253,199,185, 4,126,214,192,156, 97,153,253,255, 1,227,253,
+244,253,172, 2, 35,253,221, 0, 0, 1, 0, 10, 0, 0, 2, 42, 6, 20, 0, 11, 0, 50, 64, 7, 5, 1, 8, 8, 0, 70, 12, 16,
+252, 60,236, 50, 49, 0, 64, 8, 2, 11,169, 5, 8, 0,151, 6, 47,236,212, 60,236, 50, 48, 64, 13, 16, 13, 64, 13, 80, 13, 96,
+ 13,112, 13,240, 13, 6, 1, 93, 19, 51, 17, 51, 21, 35, 17, 35, 17, 35, 53, 51,193,184,177,177,184,183,183, 6, 20,253, 56,144,
+253, 68, 2,188,144, 0, 0, 0, 0, 1, 0, 61, 0, 0, 4,127, 6, 20, 0, 15, 0, 0, 51, 1, 39, 5, 39, 37, 39, 51, 23, 37,
+ 23, 5, 1, 35, 9, 1, 61, 1,235, 71,254,212, 33, 1, 41, 75,200, 52, 1, 58, 33,254,201, 1,237,195,254,198,254,126, 4, 50,
+188,101, 99, 99,197,138,104, 97,104,250,215, 3, 60,252,196, 0, 0, 1, 0,178,255,227, 7, 39, 5,213, 0, 35, 0, 0, 37, 14,
+ 1, 35, 34, 38, 53, 17, 51, 17, 20, 23, 22, 51, 50, 54, 53, 17, 51, 17, 20, 22, 51, 50, 54, 53, 17, 51, 17, 35, 53, 14, 1, 35,
+ 34, 38, 3,166, 69,192,130,175,190,203, 39, 57,117,143,166,203,114,119,123,166,203,203, 63,176,121,122,171,213,124,118,245,226,
+ 4, 27,251,239,186, 53, 78,190,164, 3,236,251,239,162,155,191,163, 3,236,250, 41,174,103, 98,124, 0, 0, 0, 0, 1,255,150,
+254,102, 5, 51, 5,213, 0, 17, 0,140, 64, 41, 7, 17, 1, 2, 1, 2, 17, 6, 7, 6, 66, 8, 17, 0, 13,149, 12,176, 18, 7,
+ 2, 3, 0,175, 5, 6, 1, 7, 2, 28, 4, 54, 11, 14, 12, 57, 7, 28, 0, 4, 18, 16,252,236,228, 57, 57,252,236, 17, 57, 57,
+ 49, 0, 47,236, 50, 57, 57, 16,252,236, 17, 57, 57, 48, 75, 83, 88, 7, 16, 4,237, 7, 16, 4,237, 89, 34,178, 31, 11, 1, 1,
+ 93, 64, 48, 54, 2, 56, 7, 72, 2, 71, 7,105, 2,102, 7,128, 2, 7, 6, 1, 9, 6, 21, 1, 26, 6, 70, 1, 73, 6, 87, 1,
+ 88, 6,101, 1,105, 6,121, 6,133, 1,138, 6,149, 1,154, 6,159, 19, 16, 93, 0, 93, 19, 33, 1, 17, 51, 17, 33, 1, 17, 16,
+ 6, 43, 1, 53, 51, 50, 54, 53,201, 1, 16, 2,150,196,254,240,253,106,205,227, 71, 63,134,110, 5,213,251, 31, 4,225,250, 43,
+ 4,225,251,135,254,242,244,170,150,194, 0, 0,255,255, 0,186,254, 86, 4,100, 4,123, 16, 6, 2,213, 0, 0, 0, 3, 0,115,
+255,227, 5,217, 5,240, 0, 11, 0, 18, 0, 25, 0, 47, 64, 11, 25, 16, 25, 6, 51, 15, 19, 25, 0, 16, 26, 16,252,236, 50,244,
+236, 50, 49, 0, 64, 14, 22,149, 9, 15,149, 19,173, 12,149, 3,145, 9,140, 26, 16,228,244,236,244,228, 16,236, 48, 19, 16, 0,
+ 33, 32, 0, 17, 16, 0, 33, 32, 0, 1, 34, 2, 7, 33, 38, 2, 1, 22, 0, 51, 50, 0, 55,115, 1,121, 1, 59, 1, 58, 1,120,
+254,136,254,198,254,197,254,135, 2,180,232,239, 6, 3,186, 6,239,253, 66, 13, 0,255,202,202, 0,255, 13, 2,233, 1, 98, 1,
+165,254, 91,254,158,254,159,254, 91, 1,164, 3,197,254,172,236,236, 1, 84,253, 26,195,254,228, 1, 28,195, 0,255,255, 0,103,
+255,227, 6,195, 5,240, 16, 38, 0, 50,244, 0, 16, 7, 2, 99, 6, 72, 0, 11,255,255, 0,118,255,227, 4,211, 4,235, 16, 39,
+ 2, 99, 4, 88, 0, 11, 16, 6, 0, 82, 5, 0, 0, 2, 0,115,255,227, 6,207, 5,240, 0, 10, 0, 30, 0, 0, 1, 34, 0, 17,
+ 16, 0, 51, 50, 55, 17, 38, 1, 17, 52, 38, 35, 17, 6, 33, 32, 0, 16, 0, 33, 50, 23, 33, 50, 22, 25, 1, 3, 39,220,254,253,
+ 1, 3,220,175,128,138, 2, 57,110,122,188,254,198,254,197,254,135, 1,121, 1, 59,112, 97, 1, 39,227,205, 5, 76,254,184,254,
+229,254,230,254,184,164, 3,125,164,250,180, 3,211,194,150,251,139,211, 1,164, 2,196, 1,165, 27,244,254,242,252, 45, 0, 0,
+ 0, 2, 0,113,254, 86, 5, 89, 4,123, 0, 9, 0, 30, 0, 0, 1, 38, 7, 6, 16, 22, 32, 55, 17, 38, 1, 17, 52, 38, 35, 17,
+ 6, 35, 34, 0, 17, 16, 0, 51, 50, 23, 51, 50, 22, 21, 17, 2,115,147, 87, 86,171, 1, 42, 44, 44, 1,153, 76,105,137,240,241,
+254,239, 1, 17,241,100, 82,216,181,163, 3,223, 2,117,116,254,110,231, 89, 2,168, 95,250,119, 4,116,153, 97,252,188,157, 1,
+ 57, 1, 19, 1, 20, 1, 56, 27,192,214,251,140, 0, 2,255,151, 0, 0, 4,241, 5,213, 0, 8, 0, 28, 0, 58, 64, 24, 1,149,
+ 16, 0,149, 9,129, 18, 16, 10, 8, 2, 4, 0, 5, 25, 13, 63, 17, 0, 28, 9, 4, 29, 16,252,236, 50,252,236, 17, 23, 57, 49,
+ 0, 47,244,236,212,236, 48, 64, 11, 15, 21, 31, 21, 63, 21, 95, 21,175, 21, 5, 1, 93, 1, 17, 51, 50, 54, 53, 52, 38, 35, 37,
+ 33, 50, 4, 21, 20, 4, 43, 1, 17, 35, 17, 34, 6, 29, 1, 35, 53, 52, 54, 1,247,254,141,154,154,141,254, 56, 1,200,251, 1,
+ 1,254,255,251,254,202,132,118,156,192, 5, 47,253,207,146,135,134,146,166,227,219,221,226,253,168, 5, 48, 95,105, 49, 70,181,
+163, 0, 0, 0, 0, 2, 0,184,254, 86, 4,164, 6, 20, 0, 24, 0, 36, 0, 79, 64, 36, 35,185, 0, 23, 29,185, 14, 17,184, 23,
+140, 1,189, 37, 3, 12, 9,169, 6,151, 37, 26, 18, 20, 71, 6, 9, 3, 7, 32, 12, 0, 8, 2, 70, 37, 16,252,236, 50, 50,204,
+ 17, 57, 57,244,236, 49, 0, 16,244,236, 57, 57, 16,228,228,244,196,236, 16,196,238, 48, 64, 9, 96, 39,128, 39,160, 39,224, 39,
+ 4, 1, 93, 37, 17, 35, 3, 52, 54, 59, 1, 21, 35, 34, 6, 29, 1, 62, 1, 51, 50, 0, 17, 16, 2, 35, 34, 38, 1, 52, 38, 35,
+ 34, 6, 21, 20, 22, 51, 50, 54, 1,115,185, 1,163,181,254,231,105, 76, 58,177,123,204, 0,255,255,204,123,177, 2, 56,167,146,
+146,167,167,146,146,167,168,253,174, 6, 40,214,192,156, 97,153,200,100, 97,254,188,254,248,254,248,254,188, 97, 1,235,203,231,
+231,203,203,231,231, 0, 0, 0, 0, 2, 0,201,254, 86, 4,166, 5,213, 0, 29, 0, 38, 0, 0, 19, 51, 17, 51, 50, 4, 16, 7,
+ 6, 7, 22, 23, 19, 22, 23, 22, 59, 1, 21, 35, 34, 39, 38, 39, 3, 38, 43, 1, 17, 35, 1, 51, 50, 54, 16, 38, 43, 1, 17,201,
+202,254,251, 1, 1,129,101,178, 10, 9,144, 54, 39, 42, 76, 59, 98,127, 71, 74, 78,153, 21, 46,119,202, 1, 2,198,141,154,153,
+142,254, 5,213,254,248,225,254, 72,113, 89, 19, 20, 23,254,146,136, 34, 36,154, 61, 63,198, 1,133, 53,254,174, 1,248,146, 1,
+ 12,145,253,209, 0, 1, 0, 69,255,227, 4, 96, 5,240, 0, 39, 0, 0, 19, 62, 1, 51, 50, 4, 21, 20, 6, 15, 1, 14, 1, 21,
+ 20, 22, 51, 50, 54, 55, 21, 14, 1, 35, 32, 36, 53, 52, 54, 63, 1, 62, 1, 53, 52, 38, 35, 34, 6, 7,159,114,218,105,245, 1,
+ 23,202,226,123,154,135,188,173,114,236,123,128,239,106,254,231,254,221,215,226,122,166,119,179,165, 95,204,115, 5,164, 38, 38,
+228,198,171,192, 45, 24, 31,124,110,126,136, 70, 69,208, 47, 48,224,217,182,217, 43, 25, 31,101, 99,118,128, 54, 55, 0, 0, 0,
+ 0, 1, 0,100,255,227, 3,188, 4,123, 0, 39, 0,207, 64, 17, 10, 30, 29, 9, 13, 33, 20, 33, 8, 6, 13, 8, 0, 82, 26, 69,
+ 40, 16,252,228,236,212,236,196, 17, 18, 57, 57, 57, 57, 49, 64, 25, 30, 29, 10, 9, 4, 19, 0,134, 39,137, 36, 20,134, 19,137,
+ 16,185, 23, 36,185, 3,184, 23,140, 40, 0, 16,228,244,236, 16,254,245,238, 16,245,238, 18, 23, 57, 48, 64, 18, 27, 28, 2, 26,
+ 29, 83, 9, 10, 32, 31, 2, 33, 30, 83, 10, 10, 9, 66, 75, 83, 88, 7, 16, 14,237, 17, 23, 57, 7, 14,237, 17, 23, 57, 89, 34,
+178, 0, 1, 1, 1, 93, 64, 17, 47, 41, 63, 41, 95, 41,127, 41,128, 41,144, 41,160, 41,240, 41, 8, 93, 64, 37, 32, 0, 32, 39,
+ 36, 38, 40, 30, 40, 29, 42, 21, 47, 20, 47, 19, 42, 18, 40, 10, 40, 9, 41, 8, 41, 7, 36, 1,134, 30,134, 29,134, 28,134, 27,
+ 18, 0, 93, 64, 23, 28, 30, 28, 29, 28, 28, 46, 31, 44, 30, 44, 29, 44, 28, 59, 31, 59, 30, 59, 29, 59, 28, 11,113, 19, 62, 1,
+ 51, 50, 22, 21, 20, 6, 15, 1, 14, 1, 21, 20, 22, 51, 50, 54, 55, 21, 14, 1, 35, 34, 38, 53, 52, 54, 63, 1, 62, 1, 53, 52,
+ 38, 35, 34, 6, 7,160, 76,180,102,206,224,152,171, 64,171,101,140,130, 97,198,102,108,195, 90,216,247,165,196, 63,148, 98,137,
+137, 90,168, 78, 4, 63, 30, 30,172,158,130,149, 36, 15, 37, 80, 75, 81, 89, 53, 53,190, 35, 35,182,156,137,153, 42, 14, 33, 73,
+ 64, 84, 84, 40, 40, 0, 0, 0,255,255, 0,201, 0, 0, 4,139, 5,213, 16, 6, 2,193, 0, 0, 0, 2,254,242,254, 86, 2,215,
+ 6, 20, 0, 8, 0, 33, 0, 0, 19, 38, 39, 38, 35, 34, 7, 6, 51, 5, 3, 20, 23, 22, 59, 1, 21, 35, 34, 39, 38, 53, 17, 35,
+ 32, 53, 52, 33, 50, 23, 22, 23, 51, 21,180, 7, 18, 33,110,124, 3, 3,119, 1,120, 2, 39, 37,100,176,174,195, 81, 87,190,254,
+242, 1, 47,181, 82, 53, 18,191, 5, 4, 45, 23, 48, 65, 51,154,251, 61,103, 41, 40,153, 86, 92,180, 4,174,210,216, 96, 64,111,
+155, 0, 0, 0, 0, 1, 0, 55,254, 86, 2,242, 5,158, 0, 29, 0, 0, 1, 17, 33, 21, 33, 17, 20, 22, 59, 1, 21, 20, 6, 43,
+ 1, 53, 51, 50, 54, 61, 1, 35, 34, 38, 53, 17, 35, 53, 51, 17, 1,119, 1,123,254,133, 75,115,189,164,180, 70, 48,106, 76, 5,
+213,162,135,135, 5,158,254,194,143,253,160,137, 78,174,214,192,156, 97,153, 20,159,210, 2, 96,143, 1, 62, 0, 0, 1, 0, 24,
+ 0, 0, 4,233, 5,213, 0, 15, 0, 88, 64, 21, 13, 10, 12, 6, 2,149, 0,129, 4, 0, 7, 1, 64, 3, 28, 5, 11, 28, 13, 5,
+ 16, 16,212,212,236, 16,252,228, 57, 57, 49, 0, 47,244,236, 50,196, 57, 57, 48, 1, 75,176, 10, 84, 88,189, 0, 16, 0, 64, 0,
+ 1, 0, 16, 0, 16,255,192, 56, 17, 55, 56, 89, 64, 19, 0, 17, 31, 0, 16, 1, 16, 2, 31, 7, 16, 17, 64, 17,112, 17,159, 17,
+ 9, 93, 1, 33, 21, 33, 17, 35, 17, 35, 34, 6, 29, 1, 35, 53, 52, 54, 1,174, 3, 59,253,238,203, 94,132,118,156,192, 5,213,
+170,250,213, 5, 43, 90,105, 49, 70,181,163, 0, 0, 1, 0, 55, 0, 0, 2,242, 6, 20, 0, 27, 0, 73, 64, 16, 25, 22, 11, 8,
+ 4, 23, 9, 2, 4, 0, 8, 16, 19, 14, 70, 28, 16,252, 60,196,252, 60,196, 50, 50, 23, 57, 49, 0, 64, 19, 19, 0, 25,135, 22,
+151, 10, 14, 5, 8, 15, 3,169, 17, 1,188, 8,135, 10, 47,236,244, 60,236, 50, 17, 57, 57, 16,244,236, 57, 57, 48,178,175, 21,
+ 1, 1, 93, 1, 21, 33, 21, 33, 17, 20, 22, 59, 1, 21, 35, 34, 38, 53, 17, 35, 53, 51, 53, 52, 54, 59, 1, 21, 35, 34, 6, 1,
+119, 1,123,254,133, 75,115,189,189,213,162,135,135,174,189,174,176, 99, 77, 4,195, 99,143,253,160,137, 78,154,159,210, 2, 96,
+143, 78,187,171,153, 81, 0, 0, 0, 1,255,250,254,102, 4,233, 5,213, 0, 15, 0, 84, 64, 20, 7,149, 10,189, 16, 14, 2,149,
+ 0,129, 16, 8, 1, 64, 3, 28, 0, 64, 13, 16, 16,212,228,252,228,196, 49, 0, 16,244,236, 50, 16,244,236, 48, 1, 75,176, 10,
+ 84, 88,189, 0, 16, 0, 64, 0, 1, 0, 16, 0, 16,255,192, 56, 17, 55, 56, 89, 64, 19, 0, 17, 31, 0, 16, 1, 16, 2, 31, 15,
+ 16, 17, 64, 17,112, 17,159, 17, 17, 93, 3, 33, 21, 33, 17, 20, 22, 59, 1, 21, 35, 34, 38, 25, 1, 33, 6, 4,239,253,238,110,
+134, 63, 78,227,205,253,238, 5,213,170,251, 61,194,150,170,244, 1, 14, 4,195,255,255, 0,173,255,247, 6, 95, 5,233, 16, 38,
+ 0, 56,251, 20, 16, 7, 2, 99, 5,228, 0, 11,255,255, 0,176,255,227, 5,105, 4,235, 16, 39, 2, 99, 4,238, 0, 11, 16, 6,
+ 0, 88, 2, 0, 0, 1, 0, 78,255,227, 5,207, 5,202, 0, 31, 0, 58, 64, 16, 3, 6, 25, 40, 16, 0, 28, 51, 22, 15, 12, 25,
+ 18, 22, 16, 32, 16,252,196,252,196, 16,244,196,236,252,196, 49, 0, 64, 14, 19, 15, 31, 3,149, 2, 16,129, 32, 9,149, 25,140,
+ 32, 16,244,236, 16,252, 60,236, 50, 50, 50, 48, 1, 53, 33, 21, 22, 18, 21, 20, 0, 35, 34, 0, 53, 52, 18, 55, 53, 33, 21, 33,
+ 6, 2, 21, 16, 0, 33, 32, 0, 17, 52, 2, 39, 5,207,253,168,177,198,254,248,216,216,254,247,199,178,253,168, 1, 63,158,145,
+ 1,127, 1, 49, 1, 47, 1,129,142,161, 5, 24,178,178, 97,254,180,202,240,254,222, 1, 35,239,202, 1, 76, 97,178,178,139,254,
+214,184,254,194,254,118, 1,137, 1, 53,194, 1, 40,141, 0, 0, 0, 1, 0,201,255,254, 5,118, 5,213, 0, 26, 0, 0, 37, 35,
+ 34, 38, 53, 17, 35, 17, 16, 23, 22, 31, 1, 32, 0, 17, 52, 2, 47, 1, 21, 22, 23, 22, 21, 20, 0, 2,198, 63,134,110,202,103,
+ 97,232, 77, 1, 47, 1,129,142,161,179,110, 65, 99,254,248,170,150,194, 3,211,252, 45,254,242,122,116, 6, 2, 1,137, 1, 53,
+194, 1, 40,141, 1, 68, 87,109,166,202,240,254,222, 0, 0, 0, 0, 1,255,252, 0, 0, 5,220, 5,237, 0, 16, 0, 0, 9, 1,
+ 54, 55, 54, 23, 5, 7, 39, 6, 7, 1, 17, 35, 17, 1, 51, 2,115, 1, 72, 52, 49, 66,109, 1, 13, 78,198, 85, 38,254,138,203,
+253,240,217, 3,111, 1,235, 78, 40, 54, 49,122,135,101, 6, 57,253,205,253, 57, 2,199, 3, 14, 0, 1, 0, 61,254, 86, 5,150,
+ 4,112, 0, 23, 0, 0, 5, 14, 1, 43, 1, 53, 51, 50, 54, 63, 1, 1, 51, 9, 1, 54, 55, 54, 31, 1, 7, 39, 38, 7, 2,147,
+ 78,148,124,147,108, 76, 84, 51, 33,254, 59,195, 1, 94, 1, 23, 50, 81, 97,101,215, 53,195, 81, 28,104,200,122,154, 72,134, 84,
+ 4, 78,252,148, 2,187,126, 41, 50, 48,101,147, 94, 39, 69, 0, 0, 1, 0, 92, 0, 0, 5, 31, 5,213, 0, 17, 0, 0, 19, 33,
+ 21, 1, 33, 21, 33, 1, 33, 21, 33, 53, 1, 33, 53, 33, 1, 33,115, 4,149,254,112, 1, 25,254,115,254, 84, 3,199,251, 61, 1,
+185,254,213, 1,159, 1,131,252,103, 5,213,154,254, 17,144,253,238,170,154, 2, 34,144, 1,223, 0, 1, 0, 88, 0, 0, 3,219,
+ 4, 96, 0, 17, 0, 0, 19, 33, 21, 3, 51, 21, 33, 1, 33, 21, 33, 53, 1, 35, 53, 33, 1, 33,113, 3,106,251,194,254,194,254,
+195, 2,180,252,125, 1, 43,212, 1, 80, 1, 13,253,101, 4, 96,168,254,220,144,254,143,147,168, 1, 92,144, 1, 57, 0, 0, 0,
+ 0, 1, 0,160,255,193, 4,248, 5,213, 0, 37, 0, 0, 37, 50, 55, 54, 53, 52, 39, 38, 43, 1, 53, 1, 33, 53, 33, 21, 1, 50,
+ 23, 22, 23, 22, 21, 20, 15, 1, 6, 7, 6, 33, 34, 39, 38, 39, 53, 22, 23, 22, 2,168,192, 99,100, 92, 93,165,174, 1,129,252,
+252, 4, 0,254,101,106,128, 98, 86, 81, 59, 28, 20, 45,152,254,232,119,125,126,134,106,127,126,107, 75, 75,143,134, 73, 74,166,
+ 1,220,170,168,254, 36, 56, 42,109,104,138,151, 85, 41, 29, 36,121, 19, 18, 37,195, 49, 25, 25, 0, 1, 0, 92,255,193, 4,180,
+ 5,213, 0, 37, 0, 0, 37, 50, 55, 54, 55, 21, 6, 7, 6, 35, 32, 39, 38, 47, 1, 38, 53, 52, 55, 54, 55, 54, 51, 1, 53, 33,
+ 21, 33, 1, 21, 35, 34, 7, 6, 21, 20, 23, 22, 2,172,137,126,127,106,134,126,125,119,254,232,152, 45, 20, 28, 59, 81, 86, 98,
+128,106,254,101, 4, 0,252,252, 1,129,174,165, 93, 92,100, 99,107, 25, 25, 49,195, 37, 18, 19,121, 36, 29, 41, 85,151,138,104,
+109, 42, 56, 1,220,168,170,254, 36,166, 74, 73,134,143, 75, 75, 0, 1, 0,104,254, 76, 4, 63, 4, 96, 0, 36, 0, 0, 1, 34,
+ 7, 6, 7, 6, 21, 20, 31, 1, 22, 23, 22, 33, 50, 55, 54, 55, 53, 14, 1, 35, 34, 39, 38, 53, 52, 55, 54, 59, 1, 53, 1, 33,
+ 53, 33, 21, 2, 91,106,128, 98, 86, 81, 59, 28, 28, 37,152, 1, 24, 94, 99,100,106, 84,200,109,190, 99,100, 92, 93,165,174,254,
+ 82, 2,155,252,150, 1,220, 56, 42,109,104,138,138, 98, 41, 36, 29,121, 18, 19, 37,195, 49, 50, 75, 75,143,132, 75, 74,166, 1,
+243,147,168, 0, 0, 1, 0,113,254, 86, 3,232, 4, 96, 0, 31, 0, 0, 1, 50, 55, 54, 55, 21, 6, 7, 6, 35, 32, 17, 52, 37,
+ 36, 53, 52, 35, 33, 1, 33, 53, 33, 21, 1, 32, 21, 16, 5, 6, 21, 20, 2,127, 84, 77, 79, 81, 87, 80, 86, 97,254, 32, 1,150,
+ 1, 28,235,254,222, 1,229,253,101, 3,106,254,158, 1,111,254, 48,226,254,238, 21, 21, 44,179, 32, 13, 14, 1, 25,238, 53, 37,
+ 98,124, 2, 56,147,168,254,100,229,254,236, 49, 24, 97,139, 0, 0, 1, 0,150, 0, 0, 4, 74, 5,240, 0, 34, 0, 0, 37, 33,
+ 21, 33, 53, 1, 55, 33, 53, 33, 54, 55, 54, 53, 52, 38, 35, 34, 6, 7, 53, 62, 1, 51, 50, 4, 21, 20, 7, 6, 7, 51, 21, 35,
+ 7, 1,137, 2,193,252, 76, 1, 58,115,254,167, 1,226, 95, 37, 39,167,134, 95,211,120,122,212, 88,232, 1, 20, 34, 31, 74,104,
+236, 48,170,170,170, 1, 64,117,144,109, 72, 76, 73,119,150, 66, 67,204, 49, 50,232,194, 92, 82, 73, 96,144, 49, 0, 1, 0, 93,
+255,193, 4,249, 5,213, 0, 40, 0, 0, 1, 50, 23, 22, 23, 22, 21, 20, 15, 1, 6, 7, 6, 33, 32, 39, 38, 47, 1, 38, 53, 51,
+ 20, 23, 22, 32, 55, 54, 53, 52, 39, 38, 35, 33, 21, 35, 17, 33, 21, 33, 17, 3, 6,104,130, 99, 85, 81, 59, 28, 20, 45,152,254,
+232,254,220,152, 45, 20, 28, 59,201,100, 99, 1,124, 99,100, 92, 93,165,254,193,202, 3,161,253, 41, 3, 81, 56, 43,108,104,138,
+151, 85, 41, 29, 36,121,121, 36, 29, 41, 85,151,143, 75, 75, 75, 75,143,134, 73, 74, 1, 3, 45,170,254, 37, 0, 0, 1, 0,104,
+254, 76, 4, 63, 4, 96, 0, 37, 0, 0, 1, 50, 23, 22, 23, 22, 21, 20, 15, 1, 6, 7, 6, 33, 34, 39, 38, 39, 53, 30, 1, 51,
+ 50, 55, 54, 53, 52, 39, 38, 35, 33, 53, 51, 19, 33, 21, 33, 3, 2, 76,105,129, 99, 85, 81, 59, 28, 20, 45,152,254,232, 94, 99,
+100,106, 84,200,109,190, 99,100, 92, 93,165,254,158, 1, 3, 3, 22,253,162, 3, 1,220, 56, 43,108,104,138,151, 85, 41, 29, 36,
+121, 18, 19, 37,195, 49, 50, 75, 75,143,134, 73, 74,168, 2,132,170,254, 38, 0, 0, 1, 0, 88,255,227, 3,165, 5,158, 0, 36,
+ 0, 0, 1, 7, 22, 23, 22, 21, 20, 7, 6, 33, 34, 39, 38, 39, 53, 22, 23, 22, 51, 50, 55, 54, 55, 52, 39, 38, 43, 1, 19, 35,
+ 53, 51, 17, 51, 17, 51, 21, 2, 33, 2,170,112,108,110,137,254,237, 85, 81, 81, 76, 73, 84, 78, 80,179, 99, 57, 1, 58, 86,192,
+ 62, 2,229,229,202,231, 3,230,125, 30,119,115,170,186,125,157, 18, 17, 35,172, 40, 24, 22,114, 65,133, 98, 76,114, 1, 15,164,
+ 1, 20,254,236,164, 0, 0, 0, 0, 2, 0,186,254, 86, 4,164, 4,123, 0, 14, 0, 23, 0, 0, 5, 17, 35, 17, 51, 21, 54, 55,
+ 54, 51, 50, 23, 22, 21, 16, 1, 0, 53, 52, 39, 38, 35, 34, 7, 1,115,185,185, 52,135, 81,210,184, 77, 78,252,207, 2,114, 57,
+ 56,120,220,173,122,254,208, 6, 10,170, 66, 82, 49,112,113,153,254, 87,254,228, 1,144,249,133, 66, 65,239, 0, 0, 1, 0,201,
+254, 86, 1,147, 5,213, 0, 3, 0, 0, 19, 51, 17, 35,201,202,202, 5,213,248,129, 0, 0, 0,255,255, 0,201,254, 86, 3, 39,
+ 5,213, 16, 39, 1,130, 1,148, 0, 0, 16, 6, 1,130, 0, 0, 0, 1, 0, 20,254, 86, 3,156, 5,213, 0, 19, 0, 0, 1, 51,
+ 17, 33, 21, 33, 21, 33, 21, 33, 17, 35, 17, 33, 53, 33, 53, 33, 53, 33, 1,115,202, 1, 95,254,161, 1, 95,254,161,202,254,161,
+ 1, 95,254,161, 1, 95, 5,213,253,151,168,240,170,253, 44, 2,212,170,240,168,255,255, 0,201, 0, 0, 1,148, 5,213, 16, 6,
+ 0, 4,148, 0,255,255, 0,201, 0, 0, 10,208, 5,213, 16, 39, 1, 63, 5,177, 0, 0, 16, 6, 0, 39, 0, 0,255,255, 0,201,
+ 0, 0, 9,176, 6,102, 16, 39, 1, 64, 5,213, 0, 0, 16, 6, 0, 39, 0, 0,255,255, 0,113,255,227, 8,145, 6,102, 16, 39,
+ 1, 64, 4,182, 0, 0, 16, 6, 0, 71, 0, 0,255,255, 0,201,254,102, 6, 36, 5,213, 16, 39, 0, 45, 4,145, 0, 0, 16, 6,
+ 0, 47, 0, 0,255,255, 0,201,254, 86, 5,222, 6, 20, 16, 39, 0, 77, 4,101, 0, 0, 16, 6, 0, 47, 0, 0,255,255, 0,193,
+254, 86, 2,239, 6, 20, 16, 39, 0, 77, 1,118, 0, 0, 16, 6, 0, 79, 0, 0,255,255, 0,201,254,102, 6,242, 5,213, 16, 39,
+ 0, 45, 5, 95, 0, 0, 16, 6, 0, 49, 0, 0,255,255, 0,201,254, 86, 6,183, 6, 20, 16, 39, 0, 77, 5, 62, 0, 0, 16, 6,
+ 0, 49, 0, 0,255,255, 0,186,254, 86, 5,222, 6, 20, 16, 39, 0, 77, 4,101, 0, 0, 16, 6, 0, 81, 0, 0,255,255, 0, 16,
+ 0, 0, 5,104, 5,213, 18, 38, 0, 36, 0, 0, 17, 7, 6,137, 4,190, 1,117, 0, 6,177, 14, 0, 16, 60, 49,255,255, 0,123,
+255,227, 4, 45, 6,102, 18, 38, 0, 68, 0, 0, 17, 6, 2, 32, 90, 0, 0, 8,180, 11, 43, 39, 20, 7, 43, 49,255,255, 0,201,
+ 0, 0, 1,147, 5,213, 18, 38, 0, 44, 0, 0, 17, 7, 6,137, 3, 47, 1,117, 0, 11,180, 7, 32, 1, 0, 0, 16, 73, 99, 58,
+ 49, 0, 0, 0,255,255,255,224, 0, 0, 2, 94, 6,102, 18, 38, 0,243, 0, 0, 17, 7, 2, 32,255, 31, 0, 0, 0, 11,180, 7,
+ 32, 1, 0, 0, 16, 73, 99, 58, 49, 0, 0, 0,255,255, 0,115,255,227, 5,217, 5,240, 18, 38, 0, 50, 0, 0, 16, 7, 6,137,
+ 5, 39, 1,117,255,255, 0,113,255,227, 4,117, 6,102, 18, 38, 0, 82, 0, 0, 17, 6, 2, 32,118, 0, 0, 6,177, 27, 12, 16,
+ 60, 49, 0, 0,255,255, 0,178,255,227, 5, 41, 5,213, 18, 38, 0, 56, 0, 0, 17, 7, 6,137, 4,246, 1,117, 0, 6,177, 21,
+ 5, 16, 60, 49,255,255, 0,174,255,227, 4, 88, 6,102, 18, 38, 0, 88, 0, 0, 17, 6, 2, 32,118, 0, 0, 11,180, 23, 32, 11,
+ 1, 1, 16, 73, 99, 58, 49, 0,255,255, 0,178,255,227, 5, 41, 5,213, 16, 38, 6,143, 48, 0, 18, 2, 0, 56, 0, 0, 0, 0,
+255,255, 0,174,255,227, 4, 88, 7, 49, 16, 39, 0,113, 0,123, 1, 59, 18, 6, 0,190, 0, 0,255,255, 0,178,255,227, 5, 41,
+ 5,213, 16, 38, 0, 56, 0, 0, 16, 6, 6,146, 54, 0, 0, 0,255,255, 0,174,255,227, 4, 88, 4, 96, 16, 38, 0, 88, 0, 0,
+ 16, 7, 6,146,255,190,254,200,255,255, 0,178,255,227, 5, 41, 5,213, 16, 38, 0, 56, 0, 0, 16, 6, 6,151, 48, 0, 0, 0,
+255,255, 0,174,255,227, 4, 88, 4, 96, 16, 38, 0, 88, 0, 0, 16, 7, 6,151,255,196,254,200,255,255, 0,178,255,227, 5, 41,
+ 5,213, 16, 38, 0, 56, 0, 0, 16, 6, 6,147, 48, 6, 0, 0,255,255, 0,174,255,227, 4, 88, 4, 96, 16, 38, 0, 88, 0, 0,
+ 16, 7, 6,147,255,190,254,200,255,255, 0, 0, 0, 0, 0, 0, 0, 0, 16, 6, 2, 4, 0, 0,255,255, 0, 16, 0, 0, 5,104,
+ 5,213, 18, 34, 0, 36, 0, 0, 16, 6, 6,143, 0, 0, 0, 0,255,255, 0,123,255,227, 4, 45, 7, 49, 18, 38, 0,166, 0, 0,
+ 16, 7, 0,113, 0, 82, 1, 59,255,255, 0, 16, 0, 0, 5,104, 5,213, 18, 34, 0, 36, 0, 0, 16, 6, 6,145, 0, 0, 0, 0,
+255,255, 0,123,255,227, 4, 45, 4,123, 18, 34, 0, 68, 0, 0, 16, 7, 6,145,255,147,254,193,255,255, 0, 8, 0, 0, 7, 72,
+ 7, 52, 16, 39, 0,113, 2,215, 1, 62, 18, 6, 0,136, 0, 0,255,255, 0,123,255,227, 7,111, 5,242, 16, 39, 0,113, 1,232,
+255,252, 18, 6, 0,168, 0, 0, 0, 1, 0,115,255,227, 6, 4, 5,240, 0, 37, 0, 0, 1, 21, 6, 4, 35, 32, 0, 17, 16, 0,
+ 33, 50, 4, 23, 21, 46, 1, 35, 32, 0, 17, 16, 0, 33, 50, 54, 55, 53, 35, 53, 51, 53, 33, 53, 33, 17, 51, 21, 5,139,117,254,
+230,160,254,162,254,117, 1,139, 1, 94,146, 1, 7,111,112,252,139,254,238,254,237, 1, 19, 1, 18,107,168, 67,253,253,254,182,
+ 2, 18,121, 1,138,255, 83, 85, 1,153, 1,109, 1,110, 1,153, 72, 70,215, 95, 96,254,206,254,209,254,210,254,206, 37, 39,181,
+ 88,132,166,254,214, 88, 0, 0, 0, 2, 0,113,254, 86, 4,250, 4,123, 0, 11, 0, 52, 0, 0, 1, 52, 38, 35, 34, 6, 21, 20,
+ 22, 51, 50, 54, 3, 54, 61, 1, 14, 1, 35, 34, 2, 17, 16, 18, 51, 50, 22, 23, 53, 51, 17, 20, 7, 51, 21, 35, 6, 7, 6, 33,
+ 34, 38, 39, 53, 30, 1, 51, 50, 55, 54, 55, 5, 53, 3,162,165,149,148,165,165,148,149,165, 22, 22, 57,178,124,206,252,252,206,
+124,178, 57,184, 19,179,198, 31, 58,127,254,250, 97,172, 81, 81,158, 82,181, 90, 21, 17,253,132, 2, 61,200,220,220,200,199,220,
+220,254, 79, 71, 94, 91, 99, 98, 1, 58, 1, 3, 1, 4, 1, 58, 98, 99,170,252, 43,110, 88, 70, 93, 64,140, 29, 30,179, 44, 42,
+ 95, 23, 28, 1, 70, 0, 0, 0,255,255, 0,115,255,227, 5,139, 5,240, 18, 34, 0, 42, 0, 0, 17, 7, 6,137, 5, 74, 1,117,
+ 0, 16,177, 33, 14, 16, 60, 64, 7,148, 33, 84, 33, 36, 33, 3, 93, 49, 0, 0,255,255, 0,113,254, 86, 4, 90, 6, 99, 16, 34,
+ 2, 32, 74,253, 18, 2, 0, 74, 0, 0, 0, 0,255,255, 0,201, 0, 0, 5,106, 5,213, 16, 39, 6,137, 4,162, 1,117, 18, 2,
+ 0, 46, 0, 0,255,255, 0,186, 0, 0, 4,156, 6, 20, 18, 34, 0, 78, 0, 0, 17, 7, 6,137, 3, 26, 1,117, 0, 42,180, 1,
+ 16, 12, 0, 7, 43, 49, 0, 75,176, 14, 81, 88,187, 0, 1,255,192, 0, 0,255,192, 56, 56, 89, 64, 13,144, 1,144, 0,128, 1,
+128, 0, 64, 1, 64, 0, 6, 93,255,255, 0,115,254,101, 5,217, 5,240, 16, 39, 2, 52, 1, 52,255,240, 18, 6, 0, 50, 0, 0,
+255,255, 0,113,254,101, 4,117, 4,123, 16, 39, 2, 52, 0,128,255,240, 18, 6, 0, 82, 0, 0,255,255, 0,115,254,101, 5,217,
+ 7, 49, 16, 39, 0,113, 1, 39, 1, 59, 18, 6, 1,172, 0, 0,255,255, 0,113,254,101, 4,117, 5,245, 16, 38, 0,113,115,255,
+ 18, 6, 1,173, 0, 0, 0, 0,255,255, 0,160,255,193, 4,248, 5,213, 16, 39, 6,137, 4,190, 1,117, 18, 2, 1,121, 0, 0,
+255,255, 0,220, 4,238, 3, 90, 6,102, 16, 38, 2, 32, 27, 0, 16, 6, 2, 8, 0, 0, 0, 0,255,255,255,219,254, 86, 2,100,
+ 6,102, 16, 39, 2, 32,255, 37, 0, 0, 17, 6, 1,249, 0, 0, 0, 11,180, 3, 32, 8, 7, 7, 16, 73, 99, 58, 49, 0, 0, 0,
+255,255, 0,201, 0, 0, 10,208, 5,213, 16, 39, 0, 61, 5,177, 0, 0, 16, 6, 0, 39, 0, 0,255,255, 0,201, 0, 0, 9,176,
+ 5,213, 16, 39, 0, 93, 5,213, 0, 0, 16, 6, 0, 39, 0, 0,255,255, 0,113,255,227, 8,145, 6, 20, 16, 39, 0, 93, 4,182,
+ 0, 0, 16, 6, 0, 71, 0, 0,255,255, 0,115,255,227, 5,139, 7,107, 18, 34, 0, 42, 0, 0, 16, 67, 0,118, 1, 22, 2,240,
+ 64, 0, 44,204,255,255, 0,113,254, 86, 4, 90, 6, 99, 18, 34, 0, 74, 0, 0, 16, 2, 0,118, 27,253, 0, 0, 0, 1, 0,201,
+255,227, 8, 45, 5,213, 0, 29, 0, 0, 1, 17, 20, 7, 6, 33, 32, 39, 38, 53, 17, 33, 17, 35, 17, 51, 17, 33, 17, 51, 17, 20,
+ 23, 22, 23, 50, 55, 54, 53, 17, 8, 45,100, 96,254,230,254,237,103,100,253, 34,202,202, 2,222,202, 62, 61,153,148, 66, 62, 4,
+ 96,253, 90,223,128,120,120,118,233, 1, 13,253, 57, 5,213,253,156, 2,100,251,236,159, 80, 78, 1, 79, 75,164, 2,159, 0, 0,
+ 0, 2, 0,201,254, 86, 5, 2, 5,240, 0, 14, 0, 23, 0, 0, 37, 17, 35, 17, 51, 21, 54, 55, 54, 51, 50, 23, 22, 21, 16, 1,
+ 0, 17, 52, 39, 38, 35, 34, 3, 1,147,202,202, 56,145, 87,226,198, 83, 84,252,145, 2,161, 61, 60,129,237,186,156,253,186, 7,
+127,185, 72, 87, 53,120,122,164,254, 55,254,206, 1,174, 1, 12,143, 71, 70,254,255, 0, 0, 0,255,255, 0,201, 0, 0, 5, 51,
+ 5,213, 16, 39, 6,135, 5, 30, 1,117, 18, 2, 0, 49, 0, 0,255,255, 0,186, 0, 0, 4,100, 6,100, 18, 34, 0, 81, 0, 0,
+ 16, 3, 0, 67, 1, 24,255,254,255,255, 0, 16, 0, 0, 5,104, 7,109, 16, 34, 0,135, 0, 0, 16, 7, 6,133, 6, 92, 1,125,
+255,255, 0,123,255,227, 4, 45, 7, 6, 16, 34, 0,167, 0, 0, 16, 7, 6,133, 5,236, 1,125,255,255, 0, 8, 0, 0, 7, 72,
+ 5,213, 16, 39, 6,133, 6, 92, 1,118, 18, 2, 0,136, 0, 0,255,255, 0,123,255,227, 7,111, 6, 99, 18, 34, 0,168, 0, 0,
+ 16, 3, 0,118, 1,101,255,253,255,255, 0,102,255,186, 5,229, 6, 23, 16, 39, 6,133, 4,254, 1,118, 18, 2, 0,154, 0, 0,
+255,255, 0, 72,255,162, 4,156, 6, 99, 18, 34, 0,186, 0, 0, 16, 2, 0,118, 28,253, 0, 0,255,255, 0, 16, 0, 0, 5,104,
+ 5,213, 18, 34, 0, 36, 0, 0, 16, 7, 6,142, 4,229, 1,122,255,255, 0,123,255,227, 4, 45, 6,100, 16, 35, 2, 87, 4,152,
+255,254, 18, 2, 0, 68, 0, 0,255,255, 0, 16, 0, 0, 5,104, 5,213, 18, 34, 0, 36, 0, 0, 16, 7, 6,138, 4,188, 1, 62,
+255,255, 0,123,255,227, 4, 45, 6, 72, 16, 35, 2, 89, 4,101, 0, 0, 18, 6, 0, 68, 0, 0,255,255, 0,201, 0, 0, 4,139,
+ 5,213, 18, 34, 0, 40, 0, 0, 16, 7, 6,142, 4,165, 1,122,255,255, 0,113,255,227, 4,127, 6, 99, 16, 35, 2, 87, 4,186,
+255,253, 18, 2, 0, 72, 0, 0,255,255, 0,201, 0, 0, 4,139, 5,213, 18, 34, 0, 40, 0, 0, 16, 7, 6,138, 4,166, 1, 62,
+255,255, 0,113,255,227, 4,127, 6, 72, 16, 35, 2, 89, 4,169, 0, 0, 18, 2, 0, 72, 0, 0,255,255, 0,201, 0, 0, 1,147,
+ 5,213, 18, 34, 0, 44, 0, 0, 16, 7, 6,142, 3, 89, 1,122,255,255,255,195, 0, 0, 2,129, 6, 99, 16, 35, 2, 87, 3,102,
+255,253, 18, 2, 0,243, 0, 0,255,255, 0,201, 0, 0, 1,147, 5,213, 18, 34, 0, 44, 0, 0, 16, 7, 6,138, 3, 62, 1, 62,
+255,255,255,227, 0, 0, 2, 86, 6, 72, 16, 35, 2, 89, 3, 36, 0, 0, 18, 2, 0,243, 0, 0,255,255, 0,115,255,227, 5,217,
+ 5,240, 18, 34, 0, 50, 0, 0, 16, 7, 6,142, 5, 65, 1,122,255,255, 0,113,255,227, 4,117, 6,100, 16, 35, 2, 87, 4,159,
+255,254, 18, 2, 0, 82, 0, 0,255,255, 0,115,255,227, 5,217, 5,240, 18, 34, 0, 50, 0, 0, 16, 7, 6,138, 5, 28, 1, 62,
+255,255, 0,113,255,227, 4,117, 6, 72, 16, 35, 2, 89, 4,152, 0, 0, 18, 2, 0, 82, 0, 0,255,255, 0,201, 0, 0, 5, 84,
+ 5,213, 18, 34, 0, 53, 0, 0, 16, 7, 6,142, 4,121, 1,122,255,255, 0,130, 0, 0, 3, 74, 6, 99, 16, 35, 2, 87, 4, 37,
+255,253, 18, 2, 0, 85, 0, 0,255,255, 0,201, 0, 0, 5, 84, 5,213, 18, 34, 0, 53, 0, 0, 16, 7, 6,138, 4,128, 1, 62,
+255,255, 0,186, 0, 0, 3, 94, 6, 72, 16, 35, 2, 89, 4, 45, 0, 0, 18, 2, 0, 85, 0, 0,255,255, 0,178,255,227, 5, 41,
+ 5,213, 18, 34, 0, 56, 0, 0, 16, 7, 6,142, 5, 21, 1,122,255,255, 0,174,255,227, 4, 88, 6,100, 16, 35, 2, 87, 4,212,
+255,254, 18, 2, 0, 88, 0, 0,255,255, 0,178,255,227, 5, 41, 5,213, 18, 34, 0, 56, 0, 0, 16, 7, 6,138, 4,236, 1, 62,
+255,255, 0,174,255,227, 4, 88, 6, 72, 16, 35, 2, 89, 4,171, 0, 0, 18, 2, 0, 88, 0, 0,255,255, 0,135,254, 20, 4,162,
+ 5,240, 16, 39, 2,110, 4,118, 0, 0, 18, 6, 0, 54, 0, 0,255,255, 0,111,254, 20, 3,199, 4,123, 16, 39, 2,110, 4, 44,
+ 0, 0, 18, 6, 0, 86, 0, 0,255,255,255,250,254, 20, 4,233, 5,213, 16, 39, 2,110, 4, 83, 0, 0, 18, 6, 0, 55, 0, 0,
+255,255, 0, 55,254, 20, 2,242, 5,158, 16, 39, 2,110, 4, 0, 0, 0, 18, 6, 0, 87, 0, 0, 0, 1, 0,156,254, 82, 4,115,
+ 5,240, 0, 49, 0, 0, 19, 54, 55, 54, 55, 54, 53, 52, 38, 35, 34, 15, 1, 53, 55, 54, 55, 54, 53, 52, 39, 38, 7, 34, 7, 6,
+ 7, 53, 54, 55, 54, 51, 50, 23, 22, 21, 20, 7, 6, 7, 22, 23, 22, 21, 20, 7, 6, 5, 6, 7,156,199,194,165,126, 98,146, 91,
+ 63, 70,240,248,142,106, 79, 81, 95, 99,105,113, 89,120,119, 96,129,101,192,132,134, 71, 82,120,138, 81, 89,150,130,254,208,218,
+181,254,242, 64, 88, 75,121, 94,142,113,134, 31,106,171,106, 61,118, 88,144,123, 53, 63, 1, 58, 46, 80,190, 66, 42, 56,104,105,
+178,170, 99,113, 77, 19,109,119,113,218,142,123,129, 92, 40, 0, 0, 1, 0, 71,254, 79, 3,188, 4,123, 0, 50, 0, 0, 19, 54,
+ 55, 54, 55, 54, 53, 52, 39, 38, 35, 34, 15, 1, 53, 55, 54, 55, 54, 53, 52, 39, 38, 35, 34, 7, 6, 7, 53, 54, 55, 54, 51, 50,
+ 23, 22, 21, 20, 7, 6, 7, 22, 23, 22, 21, 20, 7, 6, 5, 6, 7, 71,178,176,148,114, 88, 66, 65, 82, 57, 63,216,223,124, 99,
+ 71, 73, 78, 96, 92,104, 79,109, 96, 98,115, 91,171,121,120, 64, 73,108,124, 73, 80,135,120,254,241,196,163,254,209, 51, 72, 60,
+ 99, 76,115, 91, 55, 54, 25, 86,139, 85, 47, 99, 71,116, 96, 47, 50, 47, 35, 67,154, 48, 39, 46, 85, 85,144,137, 81, 91, 63, 15,
+ 88, 97, 91,177,115,102,102, 74, 33, 0, 0, 0,255,255, 0,201, 0, 0, 5, 59, 5,213, 16, 39, 6,137, 5, 4, 1,117, 18, 2,
+ 0, 43, 0, 0,255,255, 0,186, 0, 0, 4,100, 6, 20, 16, 39, 6,137, 3, 33, 1,117, 19, 2, 0, 75, 0, 0, 0, 42,180, 20,
+ 5, 1, 19, 7, 43, 49, 0, 75,176, 14, 81, 88,187, 0, 20,255,192, 0, 19,255,192, 56, 56, 89, 64, 13,144, 20,144, 19,128, 20,
+128, 19, 64, 20, 64, 19, 6, 93, 0, 1, 0,201,254, 86, 5, 25, 5,240, 0, 23, 0, 0, 1, 17, 35, 17, 52, 39, 38, 35, 34, 7,
+ 6, 21, 17, 35, 17, 51, 21, 54, 55, 54, 51, 50, 23, 22, 5, 25,201, 78, 76,153,179,109,106,202,202, 78,105,105,154,227,116,117,
+ 3,125,250,217, 5, 41,212,109,107,129,126,222,252,178, 5,213,241,135, 66, 67,159,159, 0, 0, 0, 3, 0,113,255,112, 6, 68,
+ 6, 20, 0, 7, 0, 40, 0, 52, 0, 0, 37, 22, 51, 50, 53, 52, 39, 34, 7, 54, 51, 50, 21, 16, 33, 34, 39, 6, 7, 35, 54, 55,
+ 38, 53, 6, 7, 6, 35, 34, 39, 38, 16, 55, 54, 51, 50, 23, 22, 23, 17, 51, 0, 16, 23, 22, 32, 55, 54, 16, 39, 38, 32, 7, 4,
+182, 17, 37,160, 52, 52,202,110,136,244,254,170, 73, 53, 34, 24,196, 29, 67, 48, 58, 88, 89,124,203,128,127,127,128,203,124, 89,
+ 88, 58,184,252,213, 83, 84, 1, 36, 84, 84, 84, 84,254,220, 84,130, 5,175, 45, 1, 32,184,206,254,191, 15, 72, 58, 69,147, 60,
+ 36,100, 48, 49,162,162, 2, 16,162,162, 49, 48,100, 2, 94,252,230,254,106,116,115,115,116, 1,150,116,115,115, 0, 2, 0,113,
+255,227, 5, 37, 5,240, 0, 12, 0, 59, 0, 0, 1, 34, 7, 6, 16, 23, 22, 32, 55, 54, 53, 52, 38, 3, 14, 1, 21, 20, 23, 22,
+ 51, 50, 55, 54, 53, 52, 39, 38, 39, 53, 50, 23, 22, 21, 20, 6, 7, 22, 23, 22, 21, 20, 7, 6, 32, 39, 38, 53, 52, 55, 54, 55,
+ 38, 39, 38, 53, 52, 55, 54, 33, 2,203,184,106,107,107,106, 1,112,107,107,212,244,130,170, 95, 59,204,168, 95, 96, 76,109,130,
+228,150,139,170,152,172, 95, 96,156,155,253,186,155,156, 96, 97,171,171, 67, 85,130,116, 1, 1, 2,197, 77, 77,254,242, 77, 77,
+ 77, 78,134,135,154, 2, 39, 3,124, 79, 69, 72, 45, 65, 65,136,158, 43, 77, 8,100,104, 97,186,128,178, 32, 34, 99, 99,143,217,
+116,116,116,116,217,143, 99, 99, 34, 31, 70, 89, 88,130, 83, 74, 0, 2, 0,113,255,227, 4,113, 5, 47, 0, 13, 0, 52, 0, 0,
+ 1, 34, 7, 6, 16, 23, 22, 32, 55, 54, 53, 52, 39, 38, 19, 22, 21, 20, 7, 6, 7, 22, 23, 22, 21, 20, 7, 6, 32, 39, 38, 53,
+ 52, 54, 55, 38, 39, 38, 53, 52, 55, 23, 6, 20, 23, 22, 51, 50, 55, 54, 53, 52, 39, 2,113,144, 83, 82, 82, 83, 1, 32, 83, 83,
+ 83, 82,254, 58, 52, 73,129,146, 82, 81,133,132,254, 18,132,133,164,146,142, 61, 52, 63,161, 43, 73, 72,131,130, 73, 74, 44, 2,
+197, 77, 77,254,242, 77, 77, 77, 78,134,135, 77, 77, 2,106, 82,112,153, 64, 89, 32, 34, 99, 99,143,217,116,116,116,116,217,143,
+198, 34, 35, 86, 75,142,106, 88, 32, 65,232, 65, 65, 65, 65,116,119, 62, 0, 0, 0, 1, 0, 92,254, 86, 5, 31, 5,213, 0, 21,
+ 0, 0, 5, 16, 7, 6, 43, 1, 53, 51, 50, 55, 54, 61, 1, 33, 53, 1, 33, 53, 33, 21, 1, 33, 5, 31,158, 72,114,254,233,105,
+ 38, 38,251,245, 3,176,252,103, 4,149,252, 80, 3,199, 20,254,223, 80, 37,156, 48, 49,153, 20,154, 4,145,170,154,251,111, 0,
+ 0, 1, 0, 88,254, 86, 3,219, 4, 96, 0, 21, 0, 0, 5, 16, 7, 6, 43, 1, 53, 51, 50, 55, 54, 61, 1, 33, 53, 1, 33, 53,
+ 33, 21, 1, 33, 3,219,158, 72,114,254,233,105, 38, 38,253, 53, 2,180,253,101, 3,106,253, 76, 2,180, 20,254,223, 80, 37,156,
+ 48, 49,153, 20,168, 3, 37,147,168,252,219, 0,255,255, 0, 16, 0, 0, 5,104, 7, 80, 18, 34, 0, 36, 0, 0, 16, 3, 2, 50,
+ 0,196, 1, 64,255,255, 0,123,255,227, 4, 45, 6, 18, 18, 34, 0, 68, 0, 0, 16, 2, 2, 50, 95, 2, 0, 0,255,255, 0,201,
+254,117, 4,139, 5,213, 18, 34, 0, 40, 0, 0, 16, 3, 0,122, 0,162, 0, 0,255,255, 0,113,254,117, 4,127, 4,123, 18, 34,
+ 0, 72, 0, 0, 16, 2, 0,122,123, 0, 0, 0,255,255, 0,115,255,227, 5,217, 5,240, 18, 34, 0, 50, 0, 0, 16, 6, 6,143,
+ 98, 0, 0, 0,255,255, 0,113,255,227, 4,117, 7, 49, 18, 38, 0,184, 0, 0, 16, 7, 0,113, 0,115, 1, 59,255,255, 0,115,
+255,227, 5,217, 5,240, 18, 34, 0, 50, 0, 0, 16, 6, 6,150,105, 0, 0, 0,255,255, 0,113,255,227, 4,117, 4,123, 16, 38,
+ 0, 82, 0, 0, 16, 7, 6,150,255,181,254,182,255,255, 0,115,255,227, 5,217, 5,240, 16, 39, 6,140, 5, 39, 1,116, 18, 6,
+ 0, 50, 0, 0,255,255, 0,113,255,227, 4,117, 6, 16, 16, 38, 2, 50,115, 0, 18, 6, 0, 82, 0, 0, 0, 0,255,255, 0,115,
+255,227, 5,217, 5,240, 18, 34, 0, 50, 0, 0, 16, 6, 6,145,106, 0, 0, 0,255,255, 0,113,255,227, 4,117, 7, 49, 18, 38,
+ 1,241, 0, 0, 16, 7, 0,113, 0,115, 1, 59,255,255,255,252, 0, 0, 4,231, 7, 49, 16, 39, 0,113, 0,114, 1, 59, 18, 6,
+ 0, 60, 0, 0,255,255, 0, 61,254, 86, 4,127, 5,245, 16, 38, 0,113, 94,255, 18, 6, 0, 92, 0, 0, 0, 0, 0, 2, 0,138,
+255,112, 3, 92, 6, 14, 0, 7, 0, 25, 0, 0, 37, 22, 51, 50, 53, 52, 39, 34, 7, 54, 51, 50, 21, 16, 33, 34, 39, 6, 7, 35,
+ 54, 55, 38, 55, 17, 51, 1,206, 17, 37,160, 52, 52,202,110,136,244,254,170, 73, 53, 34, 24,196, 29, 67, 49, 1,184,130, 5,175,
+ 45, 1, 32,184,206,254,191, 15, 72, 58, 69,147, 60, 90, 5, 48, 0, 2, 0,186,255,112, 6, 78, 4,123, 0, 7, 0, 43, 0, 0,
+ 37, 22, 51, 50, 53, 52, 39, 34, 7, 54, 51, 50, 21, 16, 33, 34, 39, 6, 7, 35, 54, 55, 38, 55, 17, 52, 38, 35, 34, 6, 21, 17,
+ 35, 17, 51, 21, 54, 55, 54, 51, 50, 23, 22, 21, 4,192, 17, 37,160, 52, 52,202,110,136,244,254,170, 73, 53, 34, 24,196, 29, 67,
+ 49, 1,124,124,149,172,185,185, 66, 89, 90,117,193, 99, 99,130, 5,175, 45, 1, 32,184,206,254,191, 15, 72, 58, 69,147, 60, 90,
+ 1,192,159,158,190,164,253,135, 4, 96,174,101, 50, 50,119,120,232, 0, 0, 0, 0, 2, 0, 55,255,112, 3, 97, 5,158, 0, 7,
+ 0, 33, 0, 0, 37, 22, 51, 50, 53, 52, 39, 34, 7, 54, 51, 50, 21, 16, 33, 34, 39, 6, 7, 35, 54, 55, 38, 53, 17, 35, 53, 51,
+ 17, 51, 17, 33, 21, 33, 1,211, 17, 37,160, 52, 52,202,110,136,244,254,170, 73, 54, 33, 24,196, 29, 67, 49,135,135,185, 1,123,
+254,133,130, 5,175, 45, 1, 32,184,206,254,191, 15, 72, 58, 69,147, 60, 90, 2,243,143, 1, 62,254,194,143, 0, 0, 1,255,219,
+254, 86, 1,121, 4, 96, 0, 11, 0, 56, 64, 21, 11, 2, 7, 0, 7,135, 5,189, 0,188, 12, 8, 12, 5, 6, 79, 1, 8, 0, 70,
+ 12, 16,252,236,228, 57, 18, 57, 49, 0, 16,228,244,236, 17, 18, 57, 57, 48, 64, 11, 16, 13, 64, 13, 80, 13, 96, 13,112, 13, 5,
+ 1, 93, 19, 51, 17, 20, 6, 43, 1, 53, 51, 50, 54, 53,193,184,163,181, 70, 49,105, 76, 4, 96,251,140,214,192,156, 97,153, 0,
+ 0, 3, 0,113,255,227, 7,140, 6, 20, 0, 7, 0, 37, 0, 45, 0, 0, 0, 16, 22, 32, 54, 16, 38, 32, 5, 62, 1, 51, 50, 0,
+ 16, 2, 35, 34, 38, 39, 21, 43, 1, 53, 14, 1, 35, 34, 2, 16, 0, 51, 50, 22, 23, 17, 59, 1, 0, 16, 38, 32, 6, 16, 22, 32,
+ 1, 47,167, 1, 36,168,168,254,220, 2,133, 58,177,123,204, 0,255,255,204,123,177, 58, 1,184, 58,177,124,203,255, 0,255,203,
+124,177, 58,184, 1, 2,114,167,254,220,167,167, 1, 36, 2,250,254,106,231,231, 1,150,231, 43,100, 97,254,188,253,240,254,188,
+ 97,100,168,168,100, 97, 1, 68, 2, 16, 1, 68, 97,100, 2, 94,251, 80, 1,150,231,231,254,106,231, 0, 0, 0, 0, 3, 0,113,
+254, 86, 7,140, 4,123, 0, 7, 0, 37, 0, 45, 0, 0, 0, 16, 38, 32, 6, 16, 22, 32, 37, 17, 43, 1, 17, 14, 1, 35, 34, 2,
+ 16, 0, 51, 50, 22, 23, 53, 59, 1, 21, 62, 1, 51, 50, 0, 16, 2, 35, 34, 38, 0, 16, 22, 32, 54, 16, 38, 32, 6,205,167,254,
+220,167,167, 1, 36,254, 53, 1,184, 58,177,124,203,255, 0,255,203,124,177, 58,184, 1, 58,177,123,204, 0,255,255,204,123,177,
+252,154,167, 1, 36,168,168,254,220, 1,100, 1,150,231,231,254,106,231, 43,253,174, 2, 82,100, 97, 1, 68, 2, 16, 1, 68, 97,
+100,170,170,100, 97,254,188,253,240,254,188, 97, 2,182,254,106,231,231, 1,150,231, 0, 0, 0, 0, 3,255,253,255,186, 5,124,
+ 6, 23, 0, 18, 0, 22, 0, 25, 0, 0, 1, 51, 19, 1, 23, 9, 1, 35, 3, 33, 15, 1, 35, 7, 39, 35, 55, 39, 55, 9, 1, 51,
+ 1, 3, 33, 3, 2, 74,229,134, 1, 97,102,254,112, 1,124,210,136,253,214,205, 50, 70, 59, 82, 2, 1, 20, 47, 2,144,254,238,
+ 22, 1,111,189, 1, 93,106, 5,213,254,161, 1,161, 89,254, 39,252, 27, 1,127,241,142, 70, 70, 1, 17, 56, 4,196,253, 25, 1,
+177,254, 79, 1, 31, 0, 0, 0, 0, 2, 0, 11,255,186, 5,139, 6, 23, 0, 31, 0, 40, 0, 0, 23, 39, 19, 38, 17, 16, 0, 33,
+ 50, 23, 22, 23, 55, 23, 7, 21, 38, 39, 1, 22, 23, 22, 33, 50, 54, 55, 21, 14, 1, 35, 32, 39, 19, 1, 35, 38, 35, 32, 0, 17,
+ 20,114,102,220,117, 1,134, 1, 83,134,118, 61, 58,101,102, 99, 46, 49,252,244, 9, 11,136, 1, 0,130,231,102,106,237,132,254,
+180,194, 57, 2,216, 1,116,130,255, 0,254,240, 70, 88, 1, 5,187, 1, 23, 1,104, 1,159, 36, 18, 27,120, 89,118,187, 43, 33,
+252,102, 13, 12,157, 94, 95,211, 72, 72,199, 1, 21, 3, 92, 47,254,199,254,216,173, 0, 0, 0, 0, 2, 0, 9,255,162, 4, 93,
+ 4,188, 0, 31, 0, 39, 0, 0, 23, 39, 55, 38, 53, 16, 0, 33, 50, 23, 22, 23, 55, 23, 7, 21, 38, 39, 1, 22, 23, 22, 51, 50,
+ 54, 55, 21, 14, 1, 35, 34, 39, 19, 1, 38, 35, 34, 6, 21, 20,105, 96,189, 85, 1, 45, 1, 6, 85, 81, 46, 45, 89, 95,118, 25,
+ 24,253,211, 7, 6, 99,179, 80,157, 78, 77,165, 93,240,147, 55, 1,238, 71, 71,179,198, 94, 78,230,141,204, 1, 18, 1, 58, 17,
+ 10, 16,108, 79,143, 85, 14, 11,253, 94, 8, 8,113, 43, 43,170, 36, 36,144, 1, 5, 2, 86, 17,227,205,103, 0, 0, 1, 0, 10,
+ 0, 0, 4,106, 5,213, 0, 13, 0, 0, 19, 51, 17, 51, 21, 35, 17, 33, 21, 33, 17, 35, 53, 51,201,202,191,191, 2,215,252, 95,
+191,191, 5,213,253,119,144,253,238,170, 2,188,144, 0, 0, 0, 0, 2,255,178,255,186, 5, 49, 6, 23, 0, 15, 0, 18, 0, 0,
+ 3, 39, 55, 23, 33, 21, 33, 17, 1, 7, 1, 17, 35, 17, 1, 35, 1, 17, 33, 6, 72,102, 56, 4,153,253,238, 2, 90,103,254, 13,
+203,254, 34, 52, 2, 18,254,212, 5,105, 85, 89, 66,170,253,174,253, 57, 88, 2, 77,253,249, 2,247, 2, 52,254,158, 1, 98, 0,
+ 0, 1, 0,111,254, 16, 4, 25, 4,123, 0, 55, 0, 0, 1, 52, 38, 47, 1, 46, 1, 53, 52, 54, 51, 50, 22, 23, 21, 46, 1, 35,
+ 34, 6, 21, 20, 22, 31, 1, 22, 23, 22, 21, 20, 7, 6, 7, 31, 1, 22, 51, 21, 35, 34, 39, 38, 47, 1, 38, 39, 38, 39, 38, 39,
+ 53, 30, 1, 51, 50, 54, 3, 10,101,171, 64,171,152,224,206,102,180, 76, 78,168, 90,137,137, 98,148, 63,198, 80, 83,123, 87,132,
+159,147, 42, 76, 39, 84,114, 71, 89,237, 30, 36, 16, 17, 97,108,102,198, 97,130,140, 1, 39, 75, 80, 37, 15, 36,149,130,158,172,
+ 30, 30,174, 40, 40, 84, 84, 64, 73, 33, 14, 44, 75, 76,137,156, 91, 64, 19,159,126, 36,154, 61, 38, 91,243, 30, 16, 3, 2, 18,
+ 35,190, 53, 53, 89, 0, 0, 0, 0, 1, 0, 88,254, 16, 4, 51, 4, 96, 0, 24, 0, 0, 19, 33, 21, 1, 22, 23, 1, 23, 22, 59,
+ 1, 21, 35, 34, 39, 38, 47, 1, 38, 43, 1, 61, 1, 1, 33,113, 3,106,253, 78, 92, 49, 1, 8,147, 42, 76,108,147, 84,114, 71,
+ 89,237, 61, 90, 94, 2,180,253,101, 4, 96,168,252,221, 16, 49,254,248,126, 36,154, 61, 38, 91,243, 63,156, 12, 3, 37, 0, 0,
+ 0, 1, 0, 80, 0, 0, 4,141, 5,213, 0, 25, 0, 0, 1, 51, 50, 54, 16, 38, 43, 1, 34, 7, 6, 7, 53, 54, 55, 54, 59, 1,
+ 50, 4, 16, 4, 43, 1, 17, 35, 1,160,241,141,154,153,142,254, 69, 90, 86, 78, 76, 81, 81, 85,254,251, 1, 1,254,255,251, 39,
+202, 3, 0,146, 1, 12,145, 22, 21, 43,182, 35, 17, 18,225,254, 72,226,253,166, 0, 1, 0,117, 2,156, 2,197, 6, 4, 0, 19,
+ 0, 48, 64, 7, 21, 0, 3, 14, 10, 11, 20, 16,212,220, 60, 47,204,204, 75,176, 13, 81, 88,177, 21, 64, 56, 89, 49,178,127, 21,
+ 1, 93, 0, 64, 6, 6, 17, 12, 2, 11, 20, 16,212, 60,196,212,204, 48, 1, 17, 35, 17, 52, 38, 35, 34, 6, 21, 17, 35, 17, 51,
+ 17, 62, 1, 51, 50, 22, 2,196,116, 78, 78, 94,108,117,117, 41,113, 74,121,125, 4, 23,254,133, 1,119, 89, 89,107, 92,254,158,
+ 3,103,254,171, 56, 56,134, 0, 0, 1, 0,117, 2,156, 2,197, 6, 4, 0, 27, 0, 59, 64, 8, 29, 0, 3, 16, 22, 10, 11, 28,
+ 16,212,220, 60,204, 47,204,204, 75,176, 13, 81, 88,177, 29, 64, 56, 89, 49,178,127, 29, 1, 93, 0, 64, 7, 6, 25, 17, 15, 2,
+ 11, 28, 16,212, 60,212,204,212,204,180, 13,131, 25,131, 6, 93, 48, 1, 17, 35, 17, 52, 38, 35, 34, 6, 21, 17, 35, 17, 52, 54,
+ 59, 1, 21, 35, 34, 6, 29, 1, 62, 1, 51, 50, 22, 2,196,116, 78, 78, 94,108,117,103,114,160,146, 66, 48, 41,113, 74,121,125,
+ 4, 23,254,133, 1,119, 89, 89,107, 92,254,158, 2,132,120,107, 87, 54, 86,114, 56, 56,134, 0, 0, 2,255,233, 1,173, 0,238,
+ 6, 3, 0, 13, 0, 17, 0, 35, 64, 7, 19, 15, 1, 8, 14, 0, 18, 16,220, 60,204,220, 60,204, 49, 0, 64, 7, 14, 17, 0, 8,
+ 7, 0, 18, 16,212,212,204, 16,220,204, 48, 19, 51, 17, 20, 7, 6, 43, 1, 53, 51, 50, 55, 54, 53, 17, 51, 21, 35,122,116, 52,
+ 51,114, 44, 31, 66, 24, 24,116,116, 5, 15,253,130,120, 54, 54, 88, 27, 27, 86, 3,114,130, 0, 0, 1, 0,117, 2,156, 2, 19,
+ 5, 31, 0, 17, 0, 31, 64, 5, 17, 11, 7, 8, 18, 16,220,204, 0,204, 49, 0, 64, 7, 0, 17, 7, 3, 14, 9, 8, 47,196,212,
+204, 16,212,204, 48, 1, 46, 1, 35, 34, 6, 21, 17, 35, 17, 51, 21, 62, 1, 51, 50, 22, 23, 2, 18, 19, 46, 28, 98,105,117,117,
+ 36,117, 84, 12, 29, 18, 4,175, 10, 9,113,107,254,182, 2,115, 97, 57, 55, 2, 3, 0, 0, 0, 0, 1, 0, 71, 2,141, 1,228,
+ 5, 15, 0, 21, 0, 0, 19, 22, 23, 22, 51, 50, 55, 54, 53, 17, 51, 17, 35, 53, 6, 7, 6, 35, 34, 39, 38, 39, 71, 20, 23, 23,
+ 27, 99, 52, 53,116,116, 37, 58, 59, 84, 12, 14, 15, 17, 2,252, 10, 5, 4, 57, 56,107, 1, 74,253,141, 97, 57, 27, 28, 1, 2,
+ 2, 0, 0, 0, 0, 1, 0, 71, 1,173, 2,117, 5, 15, 0, 32, 0, 0, 19, 22, 23, 22, 51, 50, 55, 54, 53, 17, 51, 17, 21, 20,
+ 22, 59, 1, 21, 35, 34, 38, 61, 1, 35, 53, 6, 7, 6, 35, 34, 39, 38, 39, 71, 20, 23, 23, 27, 99, 52, 53,116, 48, 66, 31, 44,
+114,102, 1, 37, 58, 60, 83, 12, 14, 15, 17, 2,252, 10, 5, 4, 57, 56,107, 1, 74,253,141, 11, 86, 54, 88,108,120, 11, 97, 57,
+ 27, 28, 1, 2, 2, 0, 0, 0, 0, 2, 0, 32, 2,156, 2,143, 5, 15, 0, 22, 0, 33, 0, 0, 1, 30, 1, 21, 20, 7, 6, 43,
+ 1, 17, 51, 17, 51, 50, 55, 54, 63, 1, 51, 7, 6, 7, 6, 1, 51, 50, 55, 54, 53, 52, 39, 38, 43, 1, 1,155, 67, 70, 67, 68,
+137,244,116,107, 61, 37, 37, 40,102,123,110, 33, 33, 34,254,215,125, 75, 39, 41, 41, 39, 75,125, 3,233, 15, 78, 59, 91, 45, 45,
+ 2,115,254,247, 21, 20, 63,161,171, 53, 30, 30,255, 0, 23, 24, 47, 46, 24, 25, 0, 1, 0, 54, 2,156, 3,233, 5, 15, 0, 12,
+ 0, 0, 19, 51, 27, 1, 51, 27, 1, 51, 3, 35, 11, 1, 35, 54,116,145,144,137,145,144,116,185,136,152,153,136, 5, 15,254, 23,
+ 1,233,254, 23, 1,233,253,141, 2, 2,253,254, 0, 1, 0, 38, 1,173, 2,213, 5, 15, 0, 17, 0, 0, 1, 6, 7, 6, 43, 1,
+ 53, 51, 50, 55, 54, 63, 1, 1, 51, 27, 1, 51, 1,159, 49, 47, 46, 78, 93, 68, 48, 26, 27, 32, 21,254,226,123,221,220,123, 2,
+ 98,112, 34, 35, 87, 20, 20, 75, 47, 2,105,254, 22, 1,234, 0,255,255, 0,197, 3,170, 1,111, 5,213, 18, 2, 0, 10, 0, 0,
+255,255, 0,197, 3,170, 2,233, 5,213, 18, 2, 0, 5, 0, 0,255,255, 0,174, 3,233, 1,211, 5,213, 16, 6, 5,141, 0, 0,
+255,255, 0,178, 3,254, 1,215, 5,213, 16, 6, 5,142, 0, 0, 0, 1, 0,196, 4,238, 1,233, 6,218, 0, 5, 0, 0, 1, 21,
+ 19, 35, 3, 53, 1,151, 82,129,164, 6,218,172,254,192, 1, 64,172, 0, 0, 0, 0, 1, 0,117, 3,239, 1,135, 6, 20, 0, 16,
+ 0, 0, 19, 52, 53, 50, 54, 53, 52, 38, 35, 52, 53, 50, 23, 22, 20, 7, 6,117, 64, 88, 88, 64,115, 80, 79, 79, 80, 3,239, 61,
+ 62, 88, 64, 63, 88, 61, 62, 80, 79,230, 80, 80, 0, 1, 0,117, 3,239, 1,135, 6, 20, 0, 16, 0, 0, 1, 34, 39, 38, 52, 55,
+ 54, 51, 20, 21, 34, 6, 21, 20, 22, 51, 20, 1,135,115, 80, 79, 79, 80,115, 64, 88, 88, 64, 3,239, 80, 80,230, 79, 80, 62, 61,
+ 88, 63, 64, 88, 62, 0, 0, 0, 0, 1, 0,117, 2,156, 2,137, 6, 2, 0, 28, 0, 0, 1, 51, 50, 55, 54, 53, 38, 39, 38, 35,
+ 34, 7, 6, 7, 53, 54, 55, 54, 51, 50, 23, 22, 21, 20, 7, 6, 7, 17, 35, 1, 20, 39,121, 55, 36, 1, 35, 63,113, 50, 50, 49,
+ 49, 48, 51, 51, 53,174, 87, 68, 68, 70,107,128, 4, 91, 64, 42, 55, 75, 36, 64, 12, 12, 24, 96, 20, 9, 10, 88, 70,104, 95, 64,
+ 67, 17,254,147, 0, 1, 0,117, 2,156, 2,137, 6, 2, 0, 28, 0, 0, 1, 17, 35, 17, 38, 39, 38, 53, 52, 55, 54, 51, 50, 23,
+ 22, 23, 21, 38, 39, 38, 35, 34, 7, 6, 7, 20, 23, 22, 51, 1,234,127,107, 71, 68, 69, 87,173, 53, 51, 51, 48, 49, 50, 49, 50,
+113, 62, 36, 1, 37, 54,121, 4, 91,254, 65, 1,109, 17, 67, 64, 95,104, 70, 88, 10, 9, 20, 96, 24, 12, 12, 64, 36, 75, 55, 42,
+ 64, 0, 0, 0, 0, 1, 1, 11, 4, 50, 2,245, 6,176, 0, 6, 0, 0, 1, 37, 21, 13, 1, 21, 37, 1, 11, 1,234,254,153, 1,
+103,254, 22, 5,187,245,139,180,180,139,245, 0, 0, 1, 1, 11, 4, 50, 2,245, 6,176, 0, 6, 0, 0, 1, 5, 53, 45, 1, 53,
+ 5, 2,245,254, 22, 1,103,254,153, 1,234, 5, 39,245,139,180,180,139,245, 0, 0, 1, 0,193, 4,124, 3, 63, 6,102, 0, 6,
+ 0, 0, 1, 3, 51, 27, 1, 51, 3, 1,182,245,139,180,180,139,245, 4,124, 1,234,254,153, 1,103,254, 22, 0, 0, 1, 0,193,
+ 4,124, 3, 63, 6,102, 0, 6, 0, 0, 1, 51, 19, 35, 11, 1, 35, 1,182,148,245,139,180,180,139, 6,102,254, 22, 1,103,254,
+153, 0, 0, 0, 0, 1, 0,193, 4,238, 3, 63, 6,102, 0, 6, 0, 55, 64, 12, 4, 5, 2,180, 0,179, 7, 4, 2,117, 6, 7,
+ 16,220,236, 57, 49, 0, 16,244,236, 50, 57, 48, 0, 75,176, 9, 84, 75,176, 14, 84, 91, 88,189, 0, 7,255,192, 0, 1, 0, 7,
+ 0, 7, 0, 64, 56, 17, 55, 56, 89, 1, 51, 19, 35, 39, 7, 35, 1,182,148,245,139,180,180,139, 6,102,254,136,245,245, 0, 0,
+ 0, 1, 0,193, 4,238, 3, 63, 6,102, 0, 6, 0, 55, 64, 12, 3, 0,180, 4, 1,179, 7, 3, 5,117, 1, 7, 16,220,236, 57,
+ 49, 0, 16,244, 60,236, 57, 48, 0, 75,176, 9, 84, 75,176, 14, 84, 91, 88,189, 0, 7,255,192, 0, 1, 0, 7, 0, 7, 0, 64,
+ 56, 17, 55, 56, 89, 1, 3, 51, 23, 55, 51, 3, 1,182,245,139,180,180,139,245, 4,238, 1,120,245,245,254,136, 0, 1, 0,214,
+ 3,231, 1, 94, 6, 18, 0, 3, 0, 19, 64, 4, 5, 0, 3, 4, 16,220,220,204, 49, 0, 64, 2, 3, 2, 47,196, 48, 1, 17, 35,
+ 17, 1, 94,136, 6, 18,253,213, 2, 43, 0, 0,255,255, 0,213, 5, 98, 3, 43, 5,246, 16, 6, 0,113, 0, 0, 0, 1, 1,115,
+ 4,238, 3, 82, 6,102, 0, 3, 0, 0, 1, 51, 1, 35, 2,139,199,254,186,153, 6,102,254,136, 0, 1, 0,170, 4,240, 2,137,
+ 6,102, 0, 3, 0, 0, 9, 1, 35, 1, 1,111, 1, 26,153,254,186, 6,102,254,138, 1,118, 0, 0, 1, 0,214,254,209, 1, 94,
+ 0,252, 0, 3, 0, 19, 64, 4, 5, 0, 3, 4, 16,220,220,204, 49, 0, 64, 2, 3, 2, 47,196, 48, 37, 17, 35, 17, 1, 94,136,
+252,253,213, 2, 43, 0, 0, 0,255,255, 0,213,254,192, 3, 43,255, 84, 16, 7, 0,113, 0, 0,249, 94, 0, 0, 0, 1, 0,170,
+254, 28, 2,137,255,146, 0, 3, 0, 0, 5, 1, 35, 1, 1,111, 1, 26,153,254,186,110,254,138, 1,118, 0, 0, 0, 1, 1,115,
+254, 28, 3, 82,255,148, 0, 3, 0, 0, 5, 51, 1, 35, 2,139,199,254,186,153,108,254,136, 0, 0, 2, 0,111, 0, 0, 1,212,
+ 4, 35, 0, 2, 0, 5, 0, 0, 1, 3, 33, 3, 19, 33, 1, 33,178, 1,101,179,179,254,155, 2,217, 1, 74,253, 39,254,182, 0,
+ 0, 1, 0,111, 2,216, 1,212, 4, 35, 0, 2, 0, 0, 1, 3, 33, 1, 33,178, 1,101, 2,217, 1, 74, 0, 0,255,255, 0,117,
+ 1,254, 1,135, 4, 35, 16, 7, 2, 23, 0, 0,254, 15, 0, 0,255,255, 0,117, 1,254, 1,135, 4, 35, 16, 7, 2, 24, 0, 0,
+254, 15, 0, 0, 0, 1, 1, 31, 1,212, 2,225, 3,150, 0, 7, 0, 0, 1, 21, 33, 53, 51, 17, 51, 17, 2,225,254, 62,150,150,
+ 2,106,150,150, 1, 44,254,212, 0, 1, 1, 31, 1,212, 2,225, 3,150, 0, 7, 0, 0, 1, 53, 33, 21, 35, 17, 35, 17, 1, 31,
+ 1,194,150,150, 3, 0,150,150,254,212, 1, 44, 0, 1, 0,193, 1,137, 3, 23, 3,223, 0, 11, 0, 0, 1, 53, 51, 21, 51, 21,
+ 35, 21, 35, 53, 35, 53, 1,162,148,225,225,148,225, 2,254,225,225,148,225,225,148, 0, 0, 0, 0, 1, 1, 31, 2,106, 2,225,
+ 3, 0, 0, 3, 0, 0, 1, 33, 53, 33, 2,225,254, 62, 1,194, 2,106,150, 0, 0, 1, 0,199, 5, 41, 3, 57, 6, 72, 0, 13,
+ 0, 87, 64, 14, 11,240, 4, 7, 0,179, 14, 7, 86, 8, 1, 86, 0, 14, 16,220,236,212,236, 49, 0, 16,244, 60,212,236, 48, 0,
+ 75,176, 9, 84, 88,189, 0, 14,255,192, 0, 1, 0, 14, 0, 14, 0, 64, 56, 17, 55, 56, 89, 0, 75,176, 15, 84, 75,176, 16, 84,
+ 91, 75,176, 17, 84, 91, 88,189, 0, 14, 0, 64, 0, 1, 0, 14, 0, 14,255,192, 56, 17, 55, 56, 89, 19, 51, 30, 1, 51, 50, 54,
+ 55, 51, 14, 1, 35, 34, 38,199,118, 11, 97, 87, 86, 96, 13,118, 10,158,145,145,158, 6, 72, 75, 75, 74, 76,143,144,144, 0, 0,
+ 0, 1, 1,154, 5, 68, 2,102, 6, 16, 0, 3, 0, 21, 64, 9, 2,131, 0,205, 4, 1, 25, 0, 4, 16,212,236, 49, 0, 16,252,
+236, 48, 0, 1, 51, 21, 35, 1,154,204,204, 6, 16,204, 0, 0, 0, 2, 0,238, 4,225, 3, 18, 7, 6, 0, 11, 0, 23, 0, 32,
+ 64, 17, 3,193, 21,242, 9,193, 15,241, 24, 0, 86, 12,120, 6, 86, 18, 24, 16,212,236,244,236, 49, 0, 16,244,236,244,236, 48,
+ 1, 52, 38, 35, 34, 6, 21, 20, 22, 51, 50, 54, 55, 20, 6, 35, 34, 38, 53, 52, 54, 51, 50, 22, 2,152, 88, 64, 65, 87, 87, 65,
+ 64, 88,122,159,115,115,159,159,115,115,159, 5,244, 63, 88, 87, 64, 65, 87, 88, 64,115,160,160,115,115,159,159, 0, 1, 1, 76,
+254,117, 2,193, 0, 0, 0, 19, 0, 32, 64, 15, 11, 14, 10, 7,243, 14,244, 0, 1, 0, 10, 4, 39, 17, 20, 16,212,236,196,212,
+204, 49, 0, 47,252,252,196, 18, 57, 48, 33, 51, 14, 1, 21, 20, 22, 51, 50, 54, 55, 21, 14, 1, 35, 34, 38, 53, 52, 54, 1,184,
+119, 45, 43, 55, 54, 32, 62, 31, 38, 68, 30,122,115, 53, 61, 88, 31, 46, 46, 15, 15,133, 10, 10, 87, 93, 48,105, 0, 1, 0,182,
+ 5, 29, 3, 74, 6, 55, 0, 27, 0, 99, 64, 36, 0, 18, 7, 14, 11, 4, 1, 18, 7, 15, 11, 4, 18,195, 25, 7, 4,195, 21, 11,
+237, 28, 15, 1, 14, 0, 7, 21, 86, 22,119, 7, 86, 8,118, 28, 16,244,236,252,236, 17, 57, 57, 57, 57, 49, 0, 16,252, 60,252,
+212, 60,236, 17, 18, 57, 17, 18, 57, 17, 18, 57, 17, 18, 57, 48, 0, 75,176, 9, 84, 75,176, 12, 84, 91, 88,189, 0, 28,255,192,
+ 0, 1, 0, 28, 0, 28, 0, 64, 56, 17, 55, 56, 89, 1, 39, 46, 1, 35, 34, 6, 7, 35, 62, 1, 51, 50, 22, 31, 1, 30, 1, 51,
+ 50, 54, 55, 51, 14, 1, 35, 34, 38, 1,252, 57, 22, 33, 13, 38, 36, 2,125, 2,102, 91, 38, 64, 37, 57, 22, 33, 13, 38, 36, 2,
+125, 2,102, 91, 38, 64, 5, 90, 55, 20, 19, 73, 82,135,147, 28, 33, 55, 20, 19, 73, 82,135,147, 28, 0, 0, 0, 0, 2, 0,240,
+ 4,238, 3,174, 6,102, 0, 3, 0, 7, 0, 66, 64, 17, 6, 2,180, 4, 0,179, 8, 4, 7, 3, 0, 5, 1, 3, 5, 7, 8, 16,
+212,220,212,204, 17, 57, 17, 18, 57, 49, 0, 16,244, 60,236, 50, 48, 0, 75,176, 9, 84, 75,176, 14, 84, 91, 88,189, 0, 8,255,
+192, 0, 1, 0, 8, 0, 8, 0, 64, 56, 17, 55, 56, 89, 1, 51, 3, 35, 3, 51, 3, 35, 2,252,178,248,135,129,170,223,137, 6,
+102,254,136, 1,120,254,136, 0, 0, 1,255,255, 1,222, 2,173, 4, 8, 0, 15, 0, 0, 3, 37, 51, 21, 20, 23, 22, 59, 1, 21,
+ 35, 34, 39, 38, 53, 5, 1, 1, 22,184, 38, 38,105, 43, 64,175, 87, 82,254,235, 3,100,164,148,153, 49, 48,156, 96, 90,200,162,
+ 0, 1, 0,239, 4,238, 3, 16, 6,102, 0, 11, 0, 0, 1, 39, 7, 35, 55, 39, 51, 23, 55, 51, 7, 23, 2, 92, 92, 93,180,181,
+181,180, 93, 92,180,182,182, 4,238, 97, 97,187,189, 96, 96,189,187, 0, 0, 0, 0, 2, 0,117, 1,170, 2,253, 5, 15, 0, 13,
+ 0, 21, 0, 0, 1, 22, 21, 20, 7, 4, 39, 38, 55, 3, 51, 23, 55, 51, 1, 6, 23, 22, 51, 50, 55, 52, 2, 5,178,242,254,246,
+ 1, 1,182,250,137,191,183,137,254,188,140, 3, 2,134,128, 1, 3,220,249,180,129, 3, 3,135,192,241, 1, 47,224,224,254,138,
+174,152, 77, 77,140, 0, 0, 0, 0, 1, 0,121, 2,156, 0,238, 6, 4, 0, 3, 0, 13,177, 2, 3, 47,204, 49, 0,177, 0, 3,
+ 47,196, 48, 19, 51, 17, 35,122,116,116, 6, 3,252,153, 0, 0, 0, 1, 0,117, 2,156, 2,144, 5, 47, 0, 50, 0, 0, 1, 21,
+ 38, 39, 38, 35, 34, 7, 6, 21, 20, 23, 22, 31, 1, 22, 23, 22, 21, 20, 7, 6, 35, 34, 39, 38, 39, 53, 22, 23, 22, 51, 50, 54,
+ 53, 52, 39, 38, 47, 1, 38, 39, 38, 53, 52, 55, 54, 51, 50, 23, 22, 2,106, 49, 53, 52, 57, 87, 43, 43, 31, 31, 93, 40,125, 50,
+ 52, 78, 77,136, 57, 62, 61, 68, 64, 63, 62, 61, 82, 88, 32, 28,111, 40,108, 48, 48, 71, 70,130, 64, 57, 57, 5, 13, 97, 22, 11,
+ 11, 23, 24, 47, 36, 20, 21, 18, 8, 24, 42, 43, 77, 87, 51, 51, 10, 10, 19,107, 30, 15, 15, 50, 45, 42, 23, 20, 23, 8, 21, 41,
+ 42, 73, 88, 48, 49, 9, 8, 0, 0, 1, 0,117, 2,156, 3, 33, 5, 15, 0, 11, 0, 0, 1, 3, 1, 35, 39, 7, 35, 1, 3, 51,
+ 23, 55, 3, 20,255, 1, 12,137,205,205,137, 1, 18,251,137,187,187, 5, 15,254,207,254,190,246,246, 1, 72, 1, 43,223,223, 0,
+ 0, 1, 0,117, 2,156, 2,137, 6, 2, 0, 28, 0, 0, 1, 17, 35, 17, 38, 39, 38, 53, 52, 55, 54, 51, 50, 23, 22, 23, 21, 38,
+ 39, 38, 35, 34, 7, 6, 7, 20, 23, 22, 51, 1,234,127,107, 71, 68, 69, 87,173, 53, 51, 51, 48, 49, 50, 49, 50,113, 62, 36, 1,
+ 37, 54,121, 4, 91,254, 65, 1,109, 17, 67, 64, 95,104, 70, 88, 10, 9, 20, 96, 24, 12, 12, 64, 36, 75, 55, 42, 64, 0, 0, 0,
+ 0, 1, 0,214, 0, 0, 3, 29, 5, 88, 0, 5, 0, 21, 64, 9, 1,169, 3, 0, 0, 8, 4, 2, 6, 16,196,212,236, 49, 0, 47,
+212,236, 48, 33, 17, 33, 53, 33, 17, 2,149,254, 65, 2, 71, 4,208,136,250,168, 0, 1, 0,214, 0, 0, 3, 29, 5, 88, 0, 7,
+ 0, 39, 64, 24, 63, 4, 63, 1, 47, 4, 47, 1, 31, 4, 31, 1, 6, 1,169, 4, 5, 0, 0, 4, 8, 6, 2, 8, 16,196,212,236,
+ 50, 49, 0, 47,212,220,236, 93, 48, 33, 17, 33, 53, 33, 17, 51, 17, 2,149,254, 65, 1,191,136, 3,156,136, 1, 52,250,168, 0,
+ 0, 1, 0,214, 0, 0, 3, 29, 5, 88, 0, 7, 0, 25, 64, 11, 1,169, 4, 5, 0, 0, 4, 8, 6, 2, 8, 16,196,212,236, 50,
+ 49, 0, 47,212,220,236, 48, 33, 17, 33, 53, 33, 17, 51, 17, 2,149,254, 65, 1,191,136, 2,104,136, 2,104,250,168, 0, 0, 0,
+ 0, 1, 0,214, 0, 0, 3, 29, 5, 88, 0, 7, 0, 39, 64, 24,112, 4,112, 1, 48, 4, 48, 1, 16, 4, 16, 1, 6, 4,169, 1,
+ 5, 0, 0, 4, 8, 6, 2, 8, 16,196,212,236, 50, 49, 0, 47,212,220,236, 93, 48, 33, 17, 33, 53, 33, 17, 51, 17, 2,149,254,
+ 65, 1,191,136, 1, 52,136, 3,156,250,168, 0, 0, 1, 0,214, 0, 0, 3, 29, 5, 88, 0, 5, 0, 21, 64, 9, 1, 0,169, 4,
+ 0, 8, 2, 4, 6, 16,196,212,236, 49, 0, 47,236,196, 48, 37, 17, 51, 17, 33, 53, 2,149,136,253,185,136, 4,208,250,168,136,
+255,255, 0,193,253,236, 3, 63,255,214, 16, 3, 2, 29, 0, 0,249,112, 0, 0,255,255, 0,213, 4,226, 3, 43, 6,118, 18, 35,
+ 0,113, 0, 0, 0,128, 18, 2, 0,113, 0,128, 0, 2, 1, 21, 4,238, 2,235, 6,102, 0, 3, 0, 7, 0, 0, 1, 51, 17, 35,
+ 1, 51, 17, 35, 1, 21,150,150, 1, 64,150,150, 6,102,254,136, 1,120,254,136,255,255, 0,238,253, 46, 3, 18,255, 83, 16, 7,
+ 2, 51, 0, 0,248, 77, 0, 0, 0, 1, 0,182,254,118, 3, 74,255,144, 0, 27, 0, 0, 1, 39, 46, 1, 35, 34, 6, 7, 35, 62,
+ 1, 51, 50, 22, 31, 1, 30, 1, 51, 50, 54, 55, 51, 14, 1, 35, 34, 38, 1,252, 57, 22, 33, 13, 38, 36, 2,125, 2,102, 91, 38,
+ 64, 37, 57, 22, 33, 13, 38, 36, 2,125, 2,102, 91, 38, 64,254,179, 55, 20, 19, 73, 82,135,147, 28, 33, 55, 20, 19, 73, 82,135,
+147, 28, 0, 0,255,255,252,168, 4,240,254,135, 6,102, 16, 7, 0, 67,251,254, 0, 0, 0, 0,255,255,253,113, 4,238,255, 80,
+ 6,102, 16, 7, 0,118,251,254, 0, 0, 0, 0,255,255,252,191, 4,238,255, 61, 6,102, 16, 7, 2, 31,251,254, 0, 0, 0, 0,
+255,255,252,180, 5, 29,255, 72, 6, 55, 16, 7, 2, 53,251,254, 0, 0, 0, 0,255,255,252,217, 5, 98,255, 47, 5,246, 16, 7,
+ 0,113,252, 4, 0, 0, 0, 0,255,255,251,236, 5,124, 0, 20, 6, 11, 16, 7, 5,171,252, 0, 0, 0, 0, 0,255,255,252,191,
+ 5, 41,255, 49, 6, 72, 16, 7, 2, 49,251,248, 0, 0, 0, 0,255,255,253,164, 5, 68,254,112, 6, 16, 16, 7, 2, 50,252, 10,
+ 0, 0, 0, 0,255,255,252,213, 5, 70,255, 39, 6, 16, 16, 7, 0,106,251,254, 0, 0, 0, 0, 0, 1,253, 55, 4,242,254,247,
+ 6,123, 0, 25, 0, 34, 64, 9, 20, 86, 64, 5,128, 12, 86, 25, 13, 47,204,236, 26,220, 26,236, 49, 0, 64, 6, 23,193, 64, 2,
+192, 13, 47, 26,220, 26,236, 48, 1, 54, 51, 50, 22, 21, 20, 15, 1, 6, 7, 6, 21, 35, 53, 52, 54, 63, 1, 54, 53, 52, 38, 35,
+ 34, 7,253, 55,112,105,104,127, 88, 44, 35, 4, 7,119, 30, 51, 45, 46, 62, 71, 90,100, 6, 72, 51, 85, 67, 61, 65, 32, 26, 9,
+ 16, 32, 12, 40, 54, 37, 34, 34, 40, 21, 36, 52,255,255,252,236, 4,225,255, 16, 7, 6, 16, 7, 2, 51,251,254, 0, 0, 0, 0,
+255,255,252,244, 4,238,255,178, 6,102, 16, 7, 2, 54,252, 4, 0, 0, 0, 0,255,255,252,197, 4,238,255, 67, 6,102, 16, 7,
+ 2, 32,252, 4, 0, 0, 0, 0, 0, 1,253,188, 4,236,254, 68, 6,168, 0, 3, 0, 0, 1, 17, 35, 17,254, 68,136, 6,168,254,
+ 68, 1,188, 0,255,255,252,240, 4,236,255, 16, 6,168, 16, 39, 2, 85,255, 52, 0, 0, 16, 7, 2, 85, 0,204, 0, 0, 0, 0,
+ 0, 2,252, 93, 4,238,255, 27, 6,102, 0, 3, 0, 7, 0, 0, 1, 19, 35, 3, 33, 19, 35, 3,253, 15,205,135,248, 2, 0,190,
+137,223, 6,102,254,136, 1,120,254,136, 1,120,255,255,252,191, 5, 41,255, 49, 6,214, 16, 39, 2, 50,252, 4, 0,198, 16, 7,
+ 2, 49,251,248, 0, 0, 0, 0,255,255,252,191, 5, 41,255, 49, 6, 72, 16, 15, 2, 49,255,248, 11,113,192, 0, 0, 1,254, 31,
+ 3,233,255, 68, 5, 40, 0, 3, 0, 10, 64, 3, 2, 1, 4, 0, 16,212,204, 48, 1, 35, 19, 51,254,242,211,164,129, 3,233, 1,
+ 63, 0, 0, 0, 0, 1,253,144, 4,194,254,130, 6,193, 0, 8, 0, 0, 1, 16, 35, 53, 22, 53, 35, 53, 51,254,130,242,112,112,
+242, 5,195,254,255,123, 3,137,254, 0, 0, 0, 0, 1,253,144, 4,194,254,130, 6,193, 0, 8, 0, 0, 1, 53, 51, 21, 35, 20,
+ 55, 21, 34,253,144,241,111,112,242, 5,195,254,254,137, 3,123, 0, 1,255,121, 4,154, 0,135, 6, 18, 0, 3, 0, 0, 3, 51,
+ 3, 35, 64,199,117,153, 6, 18,254,136, 0, 0,255,255,252,168,253,223,254,135,255, 85, 16, 7, 0, 67,251,254,248,239, 0, 0,
+255,255,253,113,253,221,255, 80,255, 85, 16, 7, 0,118,251,254,248,239, 0, 0, 0, 1,253, 12,253, 38,254, 68,255, 16, 0, 7,
+ 0, 0, 1, 53, 51, 17, 35, 53, 35, 53,253,188,136,136,176,254, 95,177,254, 22,177,136, 0, 0, 0, 1,253,188,253, 38,254,244,
+255, 16, 0, 7, 0, 0, 1, 51, 21, 35, 21, 35, 17, 51,254, 68,176,176,136,136,254, 95,136,177, 1,234, 0, 0, 0, 1,254, 85,
+ 5,134, 0, 63, 7,112, 0, 5, 0, 0, 3, 33, 53, 33, 17, 35, 73,254,158, 1,234,136, 6,232,136,254, 22, 0, 0, 1,254,240,
+ 3,107, 0,123, 4,224, 0, 19, 0, 49, 64, 6, 7, 86, 14, 4, 17, 0, 47, 75,176, 12, 84, 75,176, 13, 84, 91, 75,176, 14, 84,
+ 91, 88,185, 0, 0, 0, 64, 56, 89,220, 50,220,236, 49, 0, 64, 5, 10, 4,193, 0, 17, 47,196,252,204, 48, 1, 53, 30, 1, 51,
+ 50, 54, 53, 52, 38, 39, 51, 30, 1, 21, 20, 6, 35, 34, 38,254,240, 61, 88, 31, 46, 46, 15, 15,133, 10, 10, 87, 93, 48,105, 3,
+215,119, 45, 43, 55, 54, 32, 62, 31, 38, 68, 30,122,115, 53, 0, 0, 1,253,129,252,235,254,147,255, 16, 0, 16, 0, 0, 5, 20,
+ 21, 34, 6, 21, 20, 22, 51, 20, 21, 34, 39, 38, 52, 55, 54,254,147, 64, 88, 88, 64,115, 80, 79, 79, 80,240, 62, 61, 88, 64, 63,
+ 88, 62, 61, 79, 80,230, 80, 80, 0, 1,253, 11,253,215,254,245,255, 16, 0, 7, 0, 0, 1, 51, 21, 33, 53, 51, 53, 51,254, 68,
+177,254, 22,177,136,254, 95,136,136,177, 0, 0, 0, 1,253, 11,253,215,254,245,255, 16, 0, 7, 0, 0, 1, 35, 53, 33, 21, 35,
+ 21, 35,253,188,177, 1,234,177,136,254,136,136,136,177, 0, 0, 0, 1,253, 11,253, 38,254,245,255, 16, 0, 11, 0, 0, 1, 35,
+ 53, 51, 53, 51, 21, 51, 21, 35, 21, 35,253,188,177,177,136,177,177,136,253,215,136,177,177,136,177, 0, 0, 0, 0, 1,253, 11,
+254,136,254,245,255, 16, 0, 3, 0, 0, 1, 53, 33, 21,253, 11, 1,234,254,136,136,136, 0, 0, 0, 1,253,122,254, 86,255,208,
+ 0,128, 0, 13, 0, 0, 39, 21, 20, 7, 6, 43, 1, 53, 51, 50, 55, 54, 61, 1, 48, 82, 81,181,254,233,105, 38, 38,128,148,214,
+ 96, 96,156, 48, 49,153,148, 0, 0, 1,253,119,254, 86,255,205, 0,128, 0, 13, 0, 0, 37, 51, 21, 20, 23, 22, 59, 1, 21, 35,
+ 34, 39, 38, 53,253,119,184, 38, 38,105,233,254,181, 81, 82,128,148,153, 49, 48,156, 96, 96,214,255,255,253,154,254,135,254,102,
+255, 83, 16, 7, 2, 50,252, 0,249, 67, 0, 0,255,255,252,213,254,137,255, 39,255, 83, 16, 7, 0,106,251,254,249, 67, 0, 0,
+255,255,252,236,253, 46,255, 16,255, 83, 16, 7, 2, 51,251,254,248, 77, 0, 0, 0, 1,253,106,254, 20,254,143,255, 84, 0, 3,
+ 0, 10, 64, 3, 3, 0, 4, 0, 16,212,204, 48, 5, 51, 3, 35,253,188,211,164,129,172,254,192,255,255,253, 35,254,117,254,193,
+ 0, 0, 16, 7, 0,122,252, 0, 0, 0, 0, 0,255,255,253, 76,254,117,254,193, 0, 0, 16, 7, 2, 52,252, 0, 0, 0, 0, 0,
+ 0, 1,253,188,253,152,254, 68,255, 84, 0, 3, 0, 0, 5, 17, 35, 17,254, 68,136,172,254, 68, 1,188, 0, 0, 0, 1,252,240,
+254, 10,255, 23,255, 84, 0, 7, 0, 0, 7, 17, 35, 53, 33, 21, 35, 17,233,137,254,235,137,172,254,182,194,194, 1, 74, 0, 0,
+ 0, 1,252, 99,254, 57,255,152,255, 88, 0, 20, 0, 0, 1, 6, 35, 34, 3, 52, 53, 51, 22, 51, 50, 55, 51, 22, 23, 50, 55, 51,
+ 2, 7, 34,253,254, 60,116,218, 17,117, 14,104,101, 15,118, 12,105,102, 15,118, 15,220,116,254,139, 82, 1, 26, 2, 3,150,150,
+149, 1,150,254,226, 1, 0, 0,255,255,252,197,253,218,255, 67,255, 82, 16, 7, 2, 32,252, 4,248,236, 0, 0,255,255,252,191,
+253,221,255, 61,255, 85, 16, 7, 2, 31,251,254,248,239, 0, 0,255,255,252,191,254, 57,255, 49,255, 88, 16, 7, 2, 49,251,248,
+249, 16, 0, 0,255,255,252,191,254, 54,255, 49,255, 85, 16, 15, 2, 49,255,248, 4,126,192, 0,255,255,252,180,254, 57,255, 72,
+255, 83, 16, 7, 2, 53,251,254,249, 28, 0, 0,255,255,252,217,254,192,255, 47,255, 84, 16, 7, 2, 38,252, 4, 0, 0, 0, 0,
+255,255,251,236,254, 29, 0, 20,254,172, 16, 7, 0, 66,252, 0, 0, 0, 0, 0,255,255,251,236,254, 29, 0, 20,255,238, 16, 7,
+ 5,140,252, 0, 0, 0, 0, 0, 0, 1,251,140, 1,236,255,173, 3, 12, 0, 27, 0, 0, 3, 21, 14, 1, 35, 34, 39, 38, 39, 46,
+ 1, 35, 34, 6, 7, 53, 62, 1, 51, 50, 22, 23, 22, 23, 22, 51, 50, 54, 83, 75,143, 79, 90,113, 22, 11, 77,103, 51, 79,141, 73,
+ 78,146, 83, 53,100, 74, 12, 21,116, 93, 70,137, 3, 12,174, 59, 55, 51, 10, 4, 33, 24, 59, 63,174, 60, 54, 22, 31, 5, 10, 55,
+ 61, 0, 0, 0, 0, 1,253,119, 1,196,255,136, 2,104, 0, 3, 0, 0, 3, 21, 33, 53,120,253,240, 2,104,164,164, 0, 0, 0,
+ 0, 1,250,237, 1,196,255,255, 2,104, 0, 3, 0, 0, 1, 53, 33, 21,250,237, 5, 18, 1,196,164,164, 0, 0, 0, 1,251,104,
+255,162,255,188, 4,188, 0, 3, 0, 0, 5, 39, 1, 23,251,200, 96, 3,245, 95, 94, 78, 4,204, 79, 0, 0, 0, 0, 1,250, 18,
+255,186,255,145, 6, 23, 0, 3, 0, 0, 5, 39, 1, 23,250,121,103, 5, 25,102, 70, 88, 6, 5, 89, 0, 0, 0,255,255,253,249,
+253, 59,255, 11,255, 96, 16, 15, 2,100,252,140,252, 75,192, 0,255,255,252,241,254, 91,255, 24,255,165, 16, 15, 2,114,252, 8,
+253,175,192, 0, 0, 2,252,240,253, 46,255, 23,255, 84, 0, 3, 0, 7, 0, 0, 7, 17, 33, 17, 1, 17, 33, 17,233,253,217, 1,
+158,254,235,172,253,218, 2, 38,254, 98, 1, 22,254,234, 0, 0, 0, 1,252, 99,254, 57,255,152,255, 88, 0, 20, 0, 0, 5, 54,
+ 51, 50, 19, 20, 21, 35, 38, 35, 34, 7, 35, 38, 39, 34, 7, 35, 18, 55, 50,253,254, 59,116,218, 17,118, 13,103,102, 16,118, 11,
+105,102, 15,118, 15,220,116,250, 82,254,230, 2, 3,150,150,149, 1,150, 1, 30, 1, 0, 0, 0, 0, 1,253, 42, 4,242,254,230,
+ 6,174, 0, 11, 0, 0, 1, 7, 39, 55, 39, 55, 23, 55, 23, 7, 23, 7,254, 8,125, 96,125,125, 96,125,125, 96,125,125, 96, 5,
+112,125, 96,125,125, 96,125,125, 96,125,125, 96, 0, 1,254, 6, 4,194,255, 32, 6,210, 0, 29, 0, 0, 1, 46, 1, 53, 52, 54,
+ 55, 21, 14, 1, 21, 20, 23, 22, 31, 1, 30, 1, 21, 20, 6, 7, 53, 62, 1, 53, 52, 39, 38, 39,254, 67, 33, 28,147,135, 82, 73,
+ 9, 12, 18, 55, 33, 28,147,135, 82, 73, 9, 12, 18, 5,199, 28, 48, 28, 80, 81, 2,110, 2, 27, 28, 10, 12, 15, 14, 43, 28, 48,
+ 28, 80, 81, 2,110, 2, 27, 28, 10, 12, 15, 14,255,255,251,236, 4, 58, 0, 20, 6, 11, 16, 39, 5,171,252, 0, 0, 0, 16, 7,
+ 5,171,252, 0,254,190, 0, 0,255,255,252,168, 4,240,254,135, 6,102, 16, 7, 0, 67,251,254, 0, 0, 0, 0,255,255,253,113,
+ 4,238,255, 80, 6,102, 16, 7, 0,118,251,254, 0, 0, 0, 0,255,255,252,180, 5, 29,255, 72, 6, 55, 16, 7, 2, 53,251,254,
+ 0, 0, 0, 0,255,255,253,132, 4,194,254,118, 6, 97, 16, 7, 5,114,251,254, 0, 0, 0, 0,255,255,252,231, 5, 70,255, 98,
+ 7,210, 16, 7, 2,166,252, 16, 0, 0, 0, 0,255,255,253,198,254, 86,254,162,255,164, 16, 7, 2,163,252, 16, 0, 0, 0, 0,
+ 0, 1,252,213, 5, 29,255, 43, 6, 73, 0, 7, 0, 0, 3, 35, 53, 33, 21, 35, 17, 33,213,150,254,214,150, 2, 86, 5, 29,150,
+150, 1, 44, 0, 0, 2,253, 31,254, 50,254,225,255,184, 0, 3, 0, 7, 0, 0, 1, 33, 53, 33, 53, 33, 53, 33,254,225,254, 62,
+ 1,194,254, 62, 1,194,254, 50,120,150,120, 0, 0, 2,253, 21,254, 20,254,235,255,140, 0, 3, 0, 7, 0, 0, 5, 51, 17, 35,
+ 1, 51, 17, 35,253, 21,150,150, 1, 64,150,150,116,254,136, 1,120,254,136, 0, 0, 1,253, 31,254, 20,254,225,255,214, 0, 5,
+ 0, 0, 5, 33, 17, 35, 17, 33,253, 31, 1,194,150,254,212, 42,254, 62, 1, 44, 0, 1,252,182, 4,238,255, 74, 6,102, 0, 39,
+ 0, 0, 1, 55, 51, 7, 22, 23, 22, 51, 50, 55, 54, 55, 51, 6, 7, 6, 35, 34, 39, 38, 39, 7, 35, 55, 38, 39, 38, 35, 34, 7,
+ 6, 7, 35, 54, 55, 54, 51, 50, 23, 22,253,255, 66,109,107, 11, 22, 16, 13, 38, 18, 18, 2,125, 2, 51, 51, 91, 38, 32, 30, 33,
+ 66,110,107, 13, 20, 16, 13, 38, 18, 18, 2,125, 2, 51, 51, 91, 38, 32, 30, 5,255,103,169, 9, 14, 10, 36, 37, 82,135, 74, 73,
+ 14, 13, 29,103,168, 11, 13, 10, 36, 37, 82,135, 74, 73, 14, 13, 0, 2,253, 72, 4,137,254,176, 6,204, 0, 3, 0, 7, 0, 0,
+ 1, 51, 21, 35, 19, 51, 21, 35,253, 72,150,150,210,150,150, 5, 31,150, 2, 67,150, 0, 0, 0,255,255, 0, 0, 0, 0, 0, 0,
+ 0, 0, 16, 34, 6,134, 0,183, 16, 3, 6,134, 0, 0, 0,167, 0, 1,252, 99,254, 40,255,157,255,194, 0, 13, 0, 0, 1, 55,
+ 33, 23, 35, 39, 55, 51, 7, 33, 39, 51, 23, 7,254,112,132,254, 25,132,127,175,175,127,132, 1,231,132,126,175,175,254, 40,155,
+155,205,205,155,155,205,205, 0, 0, 1,253, 51,254, 20,254,205,255,164, 0, 8, 0, 0, 1, 35, 53, 7, 53, 55, 23, 21, 39,254,
+ 50,100,155,205,205,155,254, 20,231,132,126,175,175,126,132, 0, 0, 1,253,120, 4,225,254,136, 7, 6, 0, 16, 0, 0, 1, 6,
+ 7, 6, 21, 20, 23, 22, 23, 21, 38, 39, 38, 52, 55, 54, 55,254,136, 64, 42, 44, 44, 42, 64,114, 78, 80, 80, 78,114, 6,139, 1,
+ 42, 44, 64, 65, 43, 43, 1,123, 1, 79, 80,230, 80, 78, 1, 0,255,255,252,191, 5, 41,255, 49, 6,216, 16, 39, 2, 89, 0, 0,
+ 0,144, 16, 6, 2, 79, 0,229,255,255,253, 42,253, 84,254,230,255, 16, 16, 7, 2,133, 0, 0,248, 98, 0, 0, 0, 1,253,120,
+ 4,225,254,136, 7, 6, 0, 16, 0, 0, 1, 53, 22, 23, 22, 20, 7, 6, 7, 53, 54, 55, 54, 53, 52, 39, 38,253,120,114, 78, 80,
+ 80, 78,114, 64, 42, 44, 44, 42, 6,139,123, 1, 78, 80,230, 80, 79, 1,123, 1, 43, 43, 65, 64, 44, 42, 0, 0,255,255,255, 46,
+ 5, 68,255,250, 6, 16, 16, 7, 2, 50,253,148, 0, 0, 0, 0,255,255,252,112,254, 27, 3,144,255,133, 16, 7, 5,172,252,201,
+ 0, 0, 0, 0,255,255,252,112, 6,107, 3,144, 7,213, 16, 7, 5,172,252,201, 8, 80, 0, 0, 0, 1,253, 42, 5, 29, 2,214,
+ 6, 55, 0, 35, 0, 0, 3, 39, 38, 39, 38, 35, 34, 7, 6, 7, 35, 54, 55, 54, 51, 50, 23, 22, 31, 1, 22, 23, 22, 51, 50, 55,
+ 54, 55, 51, 6, 7, 6, 35, 34, 39, 38, 4,144, 28, 79, 44, 36,101, 53, 70, 5,162, 4,113,112,200, 91, 63, 57, 90,144, 28, 79,
+ 44, 36, 97, 57, 71, 4,162, 4,113,112,200, 91, 63, 57, 5, 90, 55, 11, 18, 10, 36, 48, 71,135, 74, 73, 14, 13, 34, 55, 11, 18,
+ 10, 36, 44, 75,135, 74, 73, 14, 13, 0, 0, 0,255,255,252,112, 6, 4, 3,144, 7,110, 16, 7, 5,173,252,201, 0, 0, 0, 0,
+ 0, 1,252,119,254, 40, 3,147,255,194, 0, 8, 0, 0, 1, 53, 33, 39, 51, 23, 7, 35, 55,252,119, 6,115,132,126,175,175,126,
+132,254,195,100,155,205,205,155, 0, 1, 0,160, 4,116, 1,159, 6,102, 0, 3, 0, 17, 64, 6, 1, 0, 4, 2, 0, 4, 16,212,
+204, 49, 0, 16,212,204, 48, 27, 1, 51, 3,160, 65,190,110, 4,116, 1,242,254, 14, 0, 0, 0, 0, 1, 0,160,254, 86, 1,159,
+ 0, 72, 0, 3, 0, 17, 64, 6, 2, 3, 4, 0, 2, 4, 16,212,204, 49, 0, 16,212,204, 48, 37, 3, 35, 19, 1,159, 65,190,110,
+ 72,254, 14, 1,242, 0, 0, 0, 0, 1, 1,182,254, 86, 2,146,255,164, 0, 13, 0, 0, 1, 35, 34, 39, 38, 61, 1, 51, 21, 20,
+ 23, 22, 59, 1, 2,146,148, 26, 26, 20,149, 10, 12, 14, 35,254, 86, 33, 26, 46,229,229, 14, 12, 13, 0, 0, 0,255,255, 0,158,
+255, 18, 1,195, 4, 35, 18, 6, 0, 30, 0, 0, 0, 1, 1,115, 4,238, 3, 82, 6,102, 0, 3, 0, 49, 64, 9, 2,180, 0,179,
+ 4, 3, 68, 1, 4, 16,212,236, 49, 0, 16,244,236, 48, 0, 75,176, 9, 84, 75,176, 14, 84, 91, 88,189, 0, 4,255,192, 0, 1,
+ 0, 4, 0, 4, 0, 64, 56, 17, 55, 56, 89, 1, 51, 1, 35, 2,139,199,254,186,153, 6,102,254,136, 0, 0, 0,255,255, 0,215,
+ 5, 70, 3, 82, 7,210, 18, 38, 0,106, 0, 0, 17, 7, 2,165, 0, 0, 1,108, 0, 20, 0, 64, 7,175, 8,159, 8, 95, 8, 3,
+ 93, 64, 5, 95, 8, 15, 8, 2,113, 48, 0, 0,255,255, 0, 16, 0, 0, 5,104, 6,102, 16, 39, 2,165,254,218, 0, 0, 16, 6,
+ 2,176, 0, 0,255,255, 0,219, 2, 72, 1,174, 3, 70, 18, 6, 0,121, 0, 0,255,255,255,231, 0, 0, 5,117, 6,102, 16, 39,
+ 2,165,254,116, 0, 0, 16, 7, 2,180, 0,234, 0, 0, 0, 0,255,255,255,243, 0, 0, 6, 31, 6,102, 16, 39, 2,165,254,128,
+ 0, 0, 16, 7, 2,182, 0,228, 0, 0, 0, 0,255,255,255,237, 0, 0, 2,125, 6,102, 16, 39, 2,165,254,122, 0, 0, 16, 7,
+ 2,184, 0,234, 0, 0, 0, 0,255,255,255,242,255,227, 6, 1, 6,102, 16, 39, 2,165,254,127, 0, 0, 16, 6, 2,190, 40, 0,
+255,255,255,225, 0, 0, 6,145, 6,102, 16, 39, 2,165,254,110, 0, 0, 16, 7, 2,195, 1,170, 0, 0, 0, 0,255,255,255,219,
+ 0, 0, 6, 5, 6,102, 16, 39, 2,165,254,104, 0, 0, 16, 6, 2,199, 54, 0,255,255, 0, 5, 0, 0, 2,128, 7,210, 16, 39,
+ 2,166,255, 46, 0, 0, 18, 6, 2,215, 15, 0,255,255, 0, 16, 0, 0, 5,104, 5,213, 18, 6, 0, 36, 0, 0,255,255, 0,201,
+ 0, 0, 4,236, 5,213, 18, 6, 0, 37, 0, 0, 0, 1, 0,201, 0, 0, 4,106, 5,213, 0, 5, 0, 25, 64, 12, 4,149, 1,129,
+ 0, 7, 2, 4, 28, 1, 4, 6, 16,252,252,204,196, 49, 0, 47,244,236, 48, 51, 17, 33, 21, 33, 17,201, 3,161,253, 41, 5,213,
+170,250,213, 0, 0, 2, 0, 16, 0, 0, 5,104, 5,213, 0, 2, 0, 6, 0, 61, 64, 12, 66, 0,149, 4,129, 1,149, 3, 8, 6,
+ 3, 7, 16,212,196,196, 49, 0, 47,236,244,236, 48, 75, 83, 88, 64, 18, 0, 17, 5, 4, 3, 2, 17, 6, 6, 5, 0, 17, 4, 1,
+ 17, 3, 3, 4, 5, 7, 16,236, 16,236, 7, 16,236, 8, 16,236, 89, 9, 1, 33, 5, 1, 51, 1, 2,188,254,102, 3, 53,251,185,
+ 2, 58,229, 2, 57, 5, 14,251,154,168, 5,213,250, 43, 0, 0,255,255, 0,201, 0, 0, 4,139, 5,213, 18, 6, 0, 40, 0, 0,
+255,255, 0, 92, 0, 0, 5, 31, 5,213, 18, 6, 0, 61, 0, 0,255,255, 0,201, 0, 0, 5, 59, 5,213, 18, 6, 0, 43, 0, 0,
+ 0, 3, 0,115,255,227, 5,217, 5,240, 0, 3, 0, 18, 0, 33, 0, 50, 64, 28, 4,149, 19,145, 34, 3,149, 0,173, 34, 11,149,
+ 26,140, 34, 35, 16, 1, 15, 25, 22, 51, 0, 8, 25, 30, 16, 34, 16,252,236,196,244,236,196,236, 49, 0, 16,244,236, 16,244,236,
+ 16,244,236, 48, 1, 33, 21, 33, 1, 34, 7, 6, 17, 16, 0, 51, 50, 55, 54, 17, 16, 39, 38, 39, 32, 0, 17, 16, 7, 6, 33, 32,
+ 39, 38, 17, 16, 55, 54, 1,197, 2,194,253, 62, 1, 98,220,129,130, 1, 3,220,220,129,128,128,129,220, 1, 58, 1,120,188,188,
+254,198,254,197,188,189,189,188, 3,112,170, 2,134,164,164,254,229,254,230,254,184,164,164, 1, 26, 1, 27,164,164,164,254, 91,
+254,158,254,159,210,211,210,210, 1, 98, 1, 98,211,210, 0, 0,255,255, 0,201, 0, 0, 1,147, 5,213, 18, 6, 0, 44, 0, 0,
+255,255, 0,201, 0, 0, 5,106, 5,213, 18, 6, 0, 46, 0, 0, 0, 1, 0, 16, 0, 0, 5,104, 5,213, 0, 6, 0, 60, 64, 11,
+ 66, 6,149, 2,129, 5, 1, 8, 4, 1, 7, 16,212,196,196, 49, 0, 47, 60,244,236, 48, 75, 83, 88, 64, 18, 6, 17, 3, 2, 1,
+ 5, 17, 4, 4, 3, 6, 17, 2, 0, 17, 1, 1, 2, 5, 7, 16,236, 16,236, 7, 16,236, 8, 16,236, 89, 51, 35, 1, 51, 1, 35,
+ 1,229,213, 2, 58,229, 2, 57,210,254, 38, 5,213,250, 43, 5, 14, 0, 0, 0,255,255, 0,201, 0, 0, 6, 31, 5,213, 18, 6,
+ 0, 48, 0, 0,255,255, 0,201, 0, 0, 5, 51, 5,213, 18, 6, 0, 49, 0, 0, 0, 3, 0,201, 0, 0, 4, 98, 5,213, 0, 3,
+ 0, 7, 0, 11, 0, 42, 64, 22, 7,149, 4,129, 11, 3,149, 0,173, 8,149, 11, 13, 4, 1, 9, 5, 0, 8, 4, 4, 12, 16,252,
+ 60,196,212, 60,196,236, 49, 0, 47,236,244,236, 16,244,236, 48, 1, 33, 21, 33, 3, 33, 21, 33, 17, 33, 21, 33, 1, 50, 2,199,
+253, 57,105, 3,153,252,103, 3,153,252,103, 3,113,170, 3, 14,170,251,127,170,255,255, 0,115,255,227, 5,217, 5,240, 18, 6,
+ 0, 50, 0, 0,255,255, 0,201, 0, 0, 5, 59, 5,213, 18, 6, 3, 60, 0, 0,255,255, 0,201, 0, 0, 4,141, 5,213, 18, 6,
+ 0, 51, 0, 0, 0, 1, 0,201, 0, 0, 4,139, 5,213, 0, 11, 0, 70, 64, 17, 66, 10, 6,149, 7,129, 0, 4,149, 3, 13, 1,
+ 8, 4, 7, 4, 12, 16,252, 60,212, 60,204, 49, 0, 47,236, 50,244,236, 50, 48, 75, 83, 88, 64, 18, 11, 17, 5, 5, 4, 10, 17,
+ 6, 6, 5, 11, 17, 5, 0, 17, 4, 5, 4, 5, 7, 16,236, 16,236, 7, 16,236, 8, 16,236, 89, 37, 33, 21, 33, 53, 9, 1, 53,
+ 33, 21, 33, 1, 1,177, 2,218,252, 62, 1,223,254, 33, 3,176,253, 56, 1,223,170,170,170, 2,112, 2, 17,170,170,253,243, 0,
+255,255,255,250, 0, 0, 4,233, 5,213, 18, 6, 0, 55, 0, 0,255,255,255,252, 0, 0, 4,231, 5,213, 18, 6, 0, 60, 0, 0,
+255,255, 0,115, 0, 0, 5,217, 5,213, 18, 6, 3, 65, 0, 0,255,255, 0, 61, 0, 0, 5, 59, 5,213, 18, 6, 0, 59, 0, 0,
+ 0, 1, 0,115, 0, 0, 5,219, 5,213, 0, 29, 0, 46, 64, 23, 16, 13,149, 27, 2, 21, 14, 7,129, 0, 31, 21, 28, 22, 2, 14,
+ 28, 27, 15, 8, 28, 7, 30, 16,220,236,212, 60,252, 60,212,236,204, 49, 0, 47,228, 50, 50,220, 60,236, 50, 48, 33, 54, 39, 34,
+ 39, 38, 3, 17, 51, 17, 16, 23, 22, 23, 17, 51, 17, 54, 55, 54, 25, 1, 51, 17, 2, 7, 6, 35, 6, 23, 2,194, 1, 1,214,188,
+184, 5,213,130,110,138,202,138,110,130,213, 5,184,188,214, 1, 1,134,176,210,204, 1,104, 1,153,254,103,254,230,164,140, 14,
+ 3,241,252, 15, 14,140,164, 1, 26, 1,153,254,103,254,152,204,210, 72,238, 0, 0, 1, 0, 78, 0, 0, 5,207, 5,231, 0, 38,
+ 0, 51, 64, 27, 11,149, 30,145, 38, 3, 18, 21,149, 2, 20, 3, 7, 25, 40, 16, 0, 34, 51, 26, 18, 14, 25, 21, 26, 16, 39, 16,
+252,196,252,196, 16,244,196,236,252,196, 49, 0, 47, 60,236, 50, 50, 50,244,236, 48, 37, 21, 33, 53, 54, 55, 54, 53, 52, 39, 38,
+ 35, 34, 0, 21, 20, 23, 22, 23, 21, 33, 53, 33, 38, 39, 38, 53, 16, 55, 54, 33, 32, 23, 22, 17, 20, 7, 6, 7, 5,207,253,168,
+177, 99, 99,132,132,216,216,254,247, 99,100,178,253,168, 1, 63,158, 73, 72,192,191, 1, 49, 1, 47,193,192, 71, 71,161,178,178,
+178, 97,166,166,202,240,145,145,254,221,239,202,166,166, 97,178,178,139,149,149,184, 1, 62,197,197,197,196,254,203,194,148,148,
+141, 0, 0, 0,255,255, 0,201, 0, 0, 1,147, 5,213, 16, 39, 6,132, 3, 47, 1,117, 19, 6, 2,184, 0, 0, 0, 8,180, 9,
+ 3, 6, 8, 7, 43, 49, 0, 0,255,255,255,252, 0, 0, 4,231, 5,213, 16, 39, 6,132, 4,113, 1,117, 19, 6, 2,195, 0, 0,
+ 0, 8,180, 12, 2, 7, 8, 7, 43, 49, 0, 0,255,255, 0,113,255,230, 4,229, 6,102, 18, 38, 2,207, 0, 0, 16, 6, 2,165,
+110, 0, 0, 0,255,255, 0,133,255,227, 3,200, 6,102, 16, 38, 2,165, 80, 0, 18, 6, 2,211, 0, 0, 0, 0,255,255, 0,186,
+254, 86, 4,100, 6,102, 16, 39, 2,165, 0,198, 0, 0, 18, 6, 2,213, 0, 0,255,255, 0,166, 0, 0, 2,152, 6,102, 18, 38,
+ 2,215, 0, 0, 16, 7, 2,165,255, 70, 0, 0,255,255, 0,149,255,226, 4, 42, 7,210, 18, 38, 2,227, 0, 0, 16, 6, 2,166,
+ 27, 0, 0, 0, 0, 2, 0,113,255,230, 4,229, 4,122, 0, 13, 0, 42, 0,200, 64, 11, 18, 17, 7, 44, 16, 23, 7, 18, 37, 69,
+ 43, 16,252,236,212,196,196, 18, 57, 57, 64, 10, 63, 16, 47, 16, 31, 16, 3,143, 16, 1, 93,113, 0, 64, 17, 18, 17, 11, 3,185,
+ 41,184, 25, 11,185, 33,140, 15,188, 22,135, 25, 47,236,228,244,236, 16,244,236, 17, 57, 57, 5, 64, 20, 29, 17, 0, 17, 14, 17,
+ 18, 17, 17, 16, 15, 17, 14, 17, 0, 17, 29, 17, 17, 16, 7, 16, 60,236,236,236, 8, 7, 16, 60,236,236, 49, 48, 1, 64, 11,132,
+ 18,134, 17,136, 1,137, 13,128, 16, 5, 93, 64, 19, 73, 19, 73, 18, 73, 28, 74, 29, 78, 13, 76, 0, 78, 1, 73, 14, 75, 17, 9,
+ 93, 64, 17, 58, 14, 57, 18, 58, 17, 56, 29, 56, 17, 63, 13, 60, 0, 62, 1, 8, 93, 64, 11, 43, 13, 43, 1, 42, 0, 41, 14, 41,
+ 17, 5, 93, 64, 13, 25, 15, 24, 14, 27, 13, 27, 1, 26, 0, 25, 17, 6, 93, 0, 64, 5, 43, 30, 43, 31, 2, 93, 1, 39, 38, 39,
+ 38, 7, 6, 21, 20, 23, 22, 51, 50, 55, 27, 1, 51, 3, 23, 22, 23, 22, 59, 1, 21, 35, 34, 39, 38, 39, 6, 7, 6, 39, 38, 39,
+ 38, 17, 16, 55, 54, 55, 36, 3, 78, 44, 45,178,134, 61, 77, 75, 76,121,134, 72,164, 99,164,205, 40, 9, 35, 41, 32, 88,110, 94,
+ 84, 41, 17, 44, 96, 44,143,234,115,117,127,141,198, 1, 55, 2, 9,231,236, 1, 1,111,137,183,220,105,107,213, 1,231, 1, 37,
+253,161,219, 49, 41, 48,156, 84, 42, 88,107, 91, 42, 1, 2,150,156, 1, 20, 1, 41,135,151, 3, 5, 0, 0, 0, 0, 2, 0,191,
+254, 86, 4,137, 6, 33, 0, 14, 0, 28, 0, 55, 64, 15, 24, 18, 7, 30, 69, 19, 18, 11, 22, 0, 28, 8, 3, 70, 29, 16,252,236,
+ 50,196,212,236,228,212,236, 49, 0, 64, 14, 26,185, 5, 9, 21,185, 22, 17,185, 13,140, 2,189, 29, 16,236,244,236,212,252, 57,
+212,236, 48, 37, 17, 35, 17, 16, 33, 32, 19, 18, 7, 4, 19, 18, 37, 38, 3, 22, 55, 32, 17, 16, 5, 53, 4, 17, 52, 7, 32, 17,
+ 1,121,185, 1,170, 1,176, 2, 3,175, 1, 23, 1, 2,254, 28,212, 89,111,197, 1, 32,254, 48, 1,107,234,254,251, 69,254, 17,
+ 6, 3, 1,200,254,127,254,238,100, 90,254,245,254, 37, 1, 1, 1, 73,174, 1, 1, 58, 1, 26, 22,170, 6, 1, 70,220, 1,254,
+200, 0, 0, 0, 0, 1, 0, 32,254, 86, 4,127, 4, 96, 0, 14, 0, 64, 64, 7, 16, 3, 7, 8, 4, 12, 15, 16,212,212,252,212,
+196, 49, 0, 64, 7, 2, 12,191, 6,189, 4, 7, 47, 60,236,228, 50, 48, 5, 64, 18, 1, 17, 8, 7, 2, 17, 3, 4, 3, 14, 13,
+ 1, 17, 0, 17, 7, 8, 7, 7, 16,236,236, 57, 57, 7, 16,236, 8,236, 1, 19, 1, 51, 1, 17, 35, 17, 1, 38, 43, 1, 53, 51,
+ 50, 1,105,245, 1, 94,195,254, 59,184,254,218, 44, 95, 49, 70,197, 3,176,253, 76, 3,100,251,160,254, 86, 1,170, 3, 68,126,
+158, 0, 0, 0, 0, 2, 0,113,255,227, 4,117, 5,240, 0, 28, 0, 45, 0, 84, 64, 20, 6, 5, 40, 4, 47, 69, 28, 40, 18, 10,
+ 81, 18, 4, 18, 24, 33, 18, 18, 69, 46, 16,252,236,212,236, 16,244,178,127, 10, 1, 93,236,196,236, 17, 18, 57, 57, 0, 64, 14,
+ 6, 5, 37, 2, 28, 0, 2,185, 26, 37,185, 14,140, 46, 16,244,236,212,252,212,204, 17, 18, 57, 57, 64, 6, 22, 29, 83, 5, 6,
+ 5, 7, 14, 16,236, 57, 49, 48, 1, 38, 35, 34, 21, 20, 5, 22, 23, 22, 17, 16, 7, 6, 35, 34, 39, 38, 17, 52, 55, 54, 55, 38,
+ 53, 16, 33, 50, 23, 1, 6, 7, 6, 21, 20, 23, 22, 51, 50, 54, 53, 52, 39, 38, 39, 38, 3,236,102,239,253, 1, 8,208,117,142,
+137,137,240,239,138,137,137, 53, 75,156, 1,185,221,120,254, 24, 68, 55, 86, 85, 86,149,147,172, 91, 97,126, 64, 5, 17, 70,117,
+ 92, 48, 37,112,135,254,235,254,247,156,157,157,156, 1, 19,204,165, 64, 36, 79,141, 1, 16, 70,254, 40, 29, 73,113,204,203,114,
+115,232,190,199, 96,103, 11, 6, 0, 1, 0,133,255,227, 3,200, 4,124, 0, 50, 0, 61, 64, 34, 12,134, 11,136, 16,185, 8,184,
+ 51, 27,169, 24, 51, 39,134, 40,136, 35,185, 44,140, 51, 52, 25, 11, 39, 20, 8, 4, 31, 8, 48, 69, 51, 16,252,236,212,236,212,
+196,196,196, 49, 0, 16,244,236,244,236, 16,212,236, 16,244,236,244,236, 48, 1, 38, 39, 38, 53, 52, 55, 54, 51, 50, 22, 23, 21,
+ 38, 39, 38, 35, 34, 7, 6, 21, 20, 23, 22, 59, 1, 21, 35, 34, 7, 6, 21, 20, 23, 22, 51, 50, 55, 54, 55, 21, 6, 7, 6, 35,
+ 34, 39, 38, 53, 52, 54, 1,139,112, 60, 60,114,113,196, 76,170, 98, 97, 80, 81, 71,119, 69, 70, 68, 67,116,155,148,137, 72, 78,
+ 84, 85,151, 93, 85, 85, 71, 90, 84, 85, 80,238,129,129,138, 2, 92, 24, 65, 64, 93,141, 79, 78, 24, 24,167, 29, 13, 13, 46, 46,
+ 64, 70, 45, 44,152, 51, 56, 88, 90, 56, 56, 18, 19, 37,171, 28, 14, 14, 91, 91,173,108,146, 0, 0, 1, 0,107,254, 82, 3,248,
+ 6, 20, 0, 29, 0, 62, 64, 11, 10, 14, 18, 31, 4, 25, 24, 28, 18, 20, 30, 16,212,236,212,212,212,196,252,204, 75,176, 16, 81,
+ 88,185, 0, 22, 0, 64, 56, 89, 49, 0, 64, 14, 8,185, 10, 0,185, 18,140, 30, 26, 23,135, 24,151, 30, 16,244,236, 50, 16,244,
+236,220,236, 48, 37, 22, 23, 22, 21, 20, 7, 6, 35, 52, 53, 22, 55, 54, 53, 52, 39, 38, 35, 32, 3, 16, 1, 33, 53, 33, 21, 0,
+ 17, 16, 2,202,132, 79, 84, 74, 80,163, 69, 42, 32, 32, 31, 58,253,162, 1, 2, 59,253,236, 3,102,253, 44,127, 1, 75, 79,120,
+115, 80, 87, 75, 76, 5, 44, 35, 37, 53, 44, 42, 2, 51, 1,236, 1, 89,185,185,254,148,254, 39,254,105, 0, 0, 0, 1, 0,186,
+254, 86, 4,100, 4,123, 0, 21, 0, 49, 64, 22, 6,135, 14, 18,184, 12,188, 2,189, 11, 23, 70, 3, 8, 0, 78, 9, 13, 8, 12,
+ 70, 22, 16,252,236, 50,244,236,236, 49, 0, 47,236,228,244,196,236, 48, 64, 5,160, 23,128, 23, 2, 1, 93, 1, 17, 35, 17, 52,
+ 38, 35, 34, 6, 21, 17, 35, 17, 51, 21, 54, 55, 54, 51, 50, 23, 22, 4,100,184,124,124,149,172,185,185, 66, 89, 90,117,193, 99,
+ 99, 2,164,251,178, 4, 72,159,158,190,164,253,135, 4, 96,174,101, 50, 50,119,120, 0, 0, 0, 0, 3, 0,113,255,233, 4,117,
+ 6, 36, 0, 8, 0, 17, 0, 33, 0, 63, 64, 27, 13,185, 18,151, 34, 1,149, 17, 34, 5,185, 26,140, 34, 35, 69, 0, 9, 18, 22,
+ 81, 1, 17, 18, 30, 69, 34, 16,252,236, 50,244,178,127, 22, 1, 93,236, 50,236, 49, 0, 16,244,236, 16,212,236, 16,244,236, 48,
+ 64, 5,160, 35,128, 35, 2, 1, 93, 1, 33, 18, 23, 22, 51, 50, 55, 54, 19, 2, 39, 38, 35, 34, 7, 6, 3, 1, 50, 23, 22, 17,
+ 16, 7, 6, 35, 34, 39, 38, 17, 16, 55, 54, 3,177,253,131, 15, 69, 86,149,150, 83, 73, 9, 28, 54, 86,147,153, 81, 64, 19, 1,
+ 61,240,137,137,137,137,240,241,136,137,137,136, 2,198,254,213,127,156,157,138, 1,201, 1, 28,100,158,156,126,254,252, 2,180,
+212,211,254,138,254,139,212,213,213,212, 1,117, 1,118,211,212, 0, 1, 0,166, 0, 0, 2,110, 4, 96, 0, 13, 0, 27, 64, 7,
+ 15, 6, 0, 8, 13, 70, 14, 16,252,252,212,196, 49, 0, 64, 5, 13,188, 5,135, 8, 47,236,228, 48, 1, 17, 20, 23, 22, 59, 1,
+ 21, 35, 34, 39, 38, 53, 3, 1, 99, 34, 36,108, 89,111,180, 82, 82, 1, 4, 96,253, 43,145, 46, 48,156, 96, 98,212, 2,202, 0,
+ 0, 1, 0,191, 0, 0, 4,133, 4, 96, 0, 11, 0, 73, 64, 9, 13, 6, 4, 9, 1, 8, 11, 70, 12, 16,252,236, 50,196,212,196,
+ 49, 0, 64, 5, 3, 0,188, 7, 11, 47, 60,228, 50, 48, 64, 22, 8, 17, 9, 4, 5, 7, 17, 6, 6, 5, 8, 5, 9, 4, 3, 17,
+ 4, 2, 17, 9, 9, 4, 7, 16, 4,236, 16, 5,236, 9, 60, 60, 7, 16, 5,236, 16, 8,236, 19, 51, 17, 1, 51, 9, 1, 35, 1,
+ 7, 17, 35,191,190, 1,227,224,254, 71, 1,254,225,254, 98,137,190, 4, 96,254, 47, 1,209,254, 90,253, 70, 2, 66,129,254, 63,
+ 0, 1, 0, 61, 0, 0, 4,127, 6, 21, 0, 13, 0, 70, 64, 5, 15, 1, 11, 5, 14, 16,212,196,212,196, 49, 0, 64, 6, 10,135,
+ 11,151, 2, 5, 47, 60,244,236, 48, 64, 24, 3, 17, 1, 0, 6, 4, 17, 5, 6, 5, 7, 17, 6, 17, 3, 17, 1, 0, 0, 2, 17,
+ 0, 1, 0, 7, 16, 5,236, 16, 9,236,236, 5,236, 7, 16, 5,236, 16, 8,236, 9, 1, 35, 9, 1, 35, 1, 39, 38, 43, 1, 53,
+ 23, 22, 2,122, 2, 5,195,254,198,254,126,195, 1,235, 74, 47,107, 96,117,226, 5,101,250,155, 3, 60,252,196, 4, 50,198,126,
+158, 2, 3, 0,255,255, 0,174,254, 86, 4,229, 4, 96, 16, 6, 0,119, 0, 0, 0, 1, 0, 74, 0, 0, 4, 24, 4, 96, 0, 21,
+ 0, 65, 64, 7, 23, 7, 18, 17, 0, 1, 22, 16,212,196,212,236,196, 49, 64, 4, 11, 1,188, 0, 0, 47,228, 50, 48, 64, 21, 20,
+ 19, 18, 17, 21, 17, 6, 5, 4, 3, 7, 3, 17, 1, 0, 0, 2, 17, 1, 1, 0, 7, 16, 5,236, 16, 9,236, 18, 23, 57, 5,236,
+ 18, 23, 57, 33, 1, 51, 1, 54, 55, 54, 55, 54, 39, 38, 39, 51, 49, 22, 23, 22, 21, 20, 7, 6, 7, 1,160,254,170,198, 1, 33,
+120,100, 76, 4, 2, 24, 28,106,186, 69, 46, 42,136,177,123, 4, 96,252, 84,124,172,129,112, 53,100,119,131, 89,124,114, 78,196,
+175,228,116, 0, 0, 1, 0,107,254, 82, 4, 1, 6, 20, 0, 38, 0, 64, 64, 15, 10, 14, 18, 40, 4, 34, 29, 28, 32, 18, 24, 37,
+ 18, 20, 39, 16,212,236,212,236,212,212,196,212,196,252,204, 49, 64, 18, 8,185, 10, 0,185, 18,140, 39, 22, 35,135, 34, 30, 27,
+135, 28,151, 39, 0, 16,244,252, 60,212,236, 57, 16,244,236,220,236, 48, 37, 22, 23, 22, 21, 20, 7, 6, 35, 52, 53, 22, 55, 54,
+ 53, 52, 39, 38, 35, 32, 17, 16, 37, 36, 17, 52, 55, 35, 53, 33, 21, 32, 17, 20, 5, 21, 36, 19, 18, 2,218,132, 79, 84, 74, 80,
+163, 69, 42, 32, 32, 31, 58,253,145, 1, 77,254,232,220,208, 3, 21,253,139, 2, 16,253,198, 2, 1,127, 1, 75, 79,120,115, 80,
+ 87, 75, 76, 5, 44, 35, 37, 53, 44, 42, 1,181, 1, 44, 88, 36, 1, 4,197, 82,185,185,254,221,191, 9,170, 22,254,188,254,241,
+255,255, 0,113,255,227, 4,117, 4,123, 18, 6, 0, 82, 0, 0, 0, 1, 0, 74,255,217, 4,152, 4, 96, 0, 23, 0, 47, 64, 11,
+ 25, 10, 1, 18, 8, 3, 19, 8, 0, 22, 24, 16,220,196,236,212,236,196,196,204, 49, 64, 12, 7,135, 14,140, 21, 3, 19, 23,135,
+ 0,188, 21, 0, 47,244,236, 50, 50, 16,244,236, 48, 19, 33, 21, 35, 17, 20, 22, 51, 50, 54, 55, 21, 14, 1, 35, 34, 38, 53, 17,
+ 33, 17, 35, 17, 35, 74, 4, 49,141, 49, 55, 15, 44, 7, 35, 74, 37,120, 92,254, 99,188,143, 4, 96,184,253, 80, 72, 63, 5, 1,
+133, 13, 12,131,176, 2,156,252, 88, 3,168, 0, 0, 2, 0,186,254, 86, 4,164, 4,123, 0, 17, 0, 29, 0, 49, 64, 25, 21,185,
+ 4,184, 30, 27,185, 10,140, 15,189, 30, 31, 69, 18, 18, 7, 81, 13, 8, 24, 18, 16, 70, 30, 16,252,236,236,244,178,127, 7, 1,
+ 93,236,236, 49, 0, 16,236,244,236, 16,244,236, 48, 1, 54, 55, 54, 51, 50, 0, 17, 16, 2, 35, 34, 38, 39, 17, 35, 17, 52, 5,
+ 52, 38, 35, 34, 6, 21, 20, 22, 51, 50, 54, 1, 20, 61,151, 59,182,204, 0,255,255,204,123,177, 58,185, 3, 43,167,146,146,167,
+167,146,146,167, 3,152,102, 90, 35,254,188,254,248,254,248,254,188, 97,100,253,174, 3,207,231,221,203,231,231,203,203,231,231,
+ 0, 1, 0,113,254, 82, 3,231, 4,123, 0, 36, 0, 54, 64, 12, 29, 33, 18, 23, 38, 9, 72, 16, 18, 3, 69, 37, 16,252,236,244,
+204,212,252,196, 49, 64, 17, 27,185, 29, 19,185, 0,140, 37, 9,134, 10,136, 13,185, 6,184, 37, 0, 16,244,252,244,236, 16,244,
+236,220,236, 48, 5, 32, 0, 17, 16, 0, 33, 50, 22, 23, 21, 46, 1, 35, 34, 6, 21, 20, 22, 51, 50, 23, 22, 21, 20, 7, 6, 35,
+ 52, 53, 22, 55, 54, 53, 52, 39, 38, 2,168,254,243,254,214, 1, 45, 1, 6, 85,162, 76, 78,157, 80,179,198,198,175,131, 80, 84,
+ 74, 80,163, 69, 42, 32, 32, 31, 29, 1, 62, 1, 14, 1, 18, 1, 58, 35, 35,172, 43, 43,227,205,205,227, 76, 79,120,115, 80, 87,
+ 75, 76, 5, 44, 35, 37, 53, 44, 42, 0, 0, 0, 0, 2, 0,113,255,227, 4,214, 4, 98, 0, 13, 0, 30, 0, 49, 64, 11, 32, 15,
+ 10, 18, 19, 81, 4, 18, 27, 69, 31, 16,252,236,244,178,127, 19, 1, 93,236,212,196, 49, 64, 12, 7,185, 23,140, 31, 17,135, 0,
+185, 14,188, 31, 0, 16,244,236,236, 16,244,236, 48, 1, 34, 7, 6, 21, 20, 22, 51, 50, 54, 53, 52, 39, 38, 39, 5, 21, 35, 22,
+ 21, 16, 7, 6, 35, 34, 39, 38, 17, 16, 55, 54, 2,115,152, 82, 86,171,149,147,172, 86, 79,154, 2, 99,206,109,137,137,240,241,
+136,137,137,114, 3,206,110,115,190,201,231,232,200,183,122,110,147, 1,184,156,221,254,237,156,157,157,156, 1, 19, 1, 20,156,
+130, 0, 0, 0, 0, 1, 0,100, 0, 0, 4,109, 4, 96, 0, 17, 0, 35, 64, 8, 19, 13, 3, 15, 8, 12, 10, 18, 16,212,196,252,
+196,196,196, 49, 0, 64, 8, 15, 11,135, 12,188, 2,185, 5, 47,236,244,236, 50, 48, 37, 22, 59, 1, 21, 35, 34, 39, 38, 53, 17,
+ 33, 53, 33, 21, 33, 17, 20, 2,230, 36,108, 89,111,180, 82, 82,254, 92, 4, 9,254, 87,204, 48,156, 96, 98,212, 2, 18,184,184,
+253,227,145, 0, 0, 1, 0,149,255,226, 4, 42, 4, 96, 0, 28, 0, 43, 64, 10, 30, 69, 9, 18, 19, 0, 8, 28, 70, 29, 16,252,
+236,212,236,228, 64, 7, 63, 30, 63, 9, 63, 19, 3, 93, 49, 0, 64, 6, 13, 28,188, 5,185, 23, 47,236,244, 60, 48, 1, 17, 20,
+ 23, 22, 51, 50, 55, 54, 55, 54, 39, 38, 39, 51, 49, 22, 23, 22, 21, 20, 7, 6, 39, 34, 39, 38, 53, 3, 1, 82, 50, 55,107,150,
+105, 59, 15, 8, 30, 28,106,186, 70, 45, 42,128,156,254,179,101, 98, 1, 4, 96,253, 43,135, 64, 69,208,118,187,102,128,119,131,
+ 90,123,115,154,253,187,228, 1,120,118,197, 2,202, 0, 0, 0, 0, 2, 0,111,254, 86, 4,210, 4,104, 0, 10, 0, 41, 0, 61,
+ 64, 16, 43, 69, 7, 18, 15, 19, 2, 8, 30, 22, 40, 35, 18, 26, 69, 42, 16,252,236,212, 60,204,252, 60,212,236,236, 49, 0, 64,
+ 16, 0, 31,185, 11, 30,184, 42, 3, 39,135, 19, 22,140, 21,189, 42, 16,236,244, 60,236, 50, 16,244, 60,236, 50, 48, 1, 34, 21,
+ 17, 50, 55, 54, 39, 38, 39, 38, 39, 50, 23, 22, 19, 18, 7, 6, 35, 17, 35, 17, 34, 39, 38, 17, 2, 55, 54, 55, 21, 6, 7, 6,
+ 23, 22, 23, 22, 51, 17, 16, 3, 61, 65, 94, 96, 86, 1, 1, 85, 70, 54,144,123,133, 4, 4,141,133,199,183,199,134,136, 1,137,
+104,164, 66, 58, 87, 1, 1, 85, 76,113, 3,203,145,253, 82,104, 93,223,208,112, 91,157,132,141,254,217,254,241,161,152,254,110,
+ 1,145,153,156, 1, 19, 1, 30,146,109, 28,163, 23, 78,115,190,202,115,103, 2,175, 1, 46, 0, 0, 1, 0, 59,254, 85, 4,100,
+ 4, 97, 0, 23, 0,118, 64, 12, 17, 16, 5, 4, 4, 9, 25, 20, 15, 3, 9, 24, 16,212,196,212,196,196, 18, 23, 57, 0, 64, 18,
+ 17, 16, 5, 4, 4, 19, 8,135, 14, 9,188, 24, 19,135, 22, 3,189, 24, 16,244, 60,236, 16,244, 60,236, 17, 23, 57, 5, 64, 20,
+ 14, 17, 15, 16, 15, 12, 17, 5, 5, 4, 2, 17, 3, 4, 3, 0, 17, 17, 17, 16, 7, 16,236, 7, 16,236, 7, 16,236, 7, 16,236,
+ 64, 20, 16, 17, 12, 15, 2, 13, 17, 12, 14, 3, 4, 14, 3, 5, 0, 1, 15, 2, 5, 0, 15, 15, 15, 15, 49, 48, 5, 3, 1, 35,
+ 1, 3, 38, 43, 1, 53, 23, 4, 23, 19, 1, 51, 1, 19, 22, 59, 1, 21, 39, 36, 2,220,149,254,205,217, 1,178,182, 49,154, 49,
+ 70, 1, 2, 65,148, 1, 51,217,254, 78,182, 49,154, 49, 70,254,254,250, 1,127,253,208, 3, 24, 1,215,126,158, 2, 7,167,254,
+129, 2, 48,252,232,254, 41,126,158, 2, 7, 0, 0, 1, 0,112,254, 86, 4,209, 4, 96, 0, 27, 0, 54, 64, 13, 29, 19, 8, 20,
+ 25, 13, 8, 0, 12, 6, 8, 5, 28, 16,220,236,212, 60,252, 60,212,236,204, 49, 0, 64, 14, 19, 12, 5,188, 28, 14, 11,135, 25,
+ 0,140, 27,189, 28, 16,236,244, 60,236, 50, 16,244, 60, 60, 48, 5, 38, 39, 38, 53, 17, 51, 17, 20, 23, 22, 23, 17, 51, 17, 54,
+ 55, 54, 53, 17, 51, 17, 20, 7, 6, 7, 17, 35, 2, 69,231,107,131,186, 85, 74,124,183,131, 67, 85,186,131,118,220,183, 25, 37,
+ 97,119,243, 2,137,253,126,183, 76, 66, 14, 3,213,252, 44, 14, 66, 84,175, 2,129,253,120,252,110, 99, 35,254,110, 0, 0, 0,
+ 0, 1, 0,135,255,226, 6, 40, 4, 96, 0, 26, 0, 56, 64, 20, 18, 18, 19, 28, 69, 16, 18, 21, 11, 8, 12, 7, 18, 2, 5, 18,
+ 4, 2, 69, 27, 16,252,220,236, 16,236,212,252,212,236,236,220,236, 49, 0, 64, 9, 11, 18, 4,188, 14, 9,135, 23, 0, 47, 60,
+236, 50,244, 60,196, 48, 5, 32, 17, 52, 19, 51, 2, 21, 2, 51, 50, 3, 51, 2, 55, 54, 17, 52, 3, 51, 18, 21, 18, 37, 36, 3,
+ 2, 2, 38,254, 97,155,198,143, 1,223,207, 4,170, 4,207,222,143,198,155, 2,254, 95,254,241, 34, 41, 29, 2, 82,235, 1, 64,
+254,192,240,254, 79, 2, 26,253,227, 3, 2, 1,175,240, 1, 64,254,192,235,253,173, 1, 1, 1, 42,254,213, 0,255,255, 0, 5,
+ 0, 0, 2,125, 6, 16, 18, 38, 2,215, 15, 0, 16, 7, 0,106,255, 46, 0, 0,255,255, 0,149,255,226, 4, 42, 6, 16, 16, 38,
+ 0,106, 29, 0, 18, 6, 2,227, 0, 0, 0, 0,255,255, 0,113,255,227, 4,117, 6,102, 16, 38, 2,165,125, 0, 18, 6, 2,221,
+ 0, 0, 0, 0,255,255, 0,149,255,226, 4, 42, 6,102, 16, 38, 2,165, 34, 0, 18, 6, 2,227, 0, 0, 0, 0,255,255, 0,135,
+255,226, 6, 40, 6,102, 18, 38, 2,231, 0, 0, 16, 7, 2,165, 1, 89, 0, 0, 0, 3, 0,166,255,233, 4, 77, 6, 36, 0, 13,
+ 0, 37, 0, 53, 0, 0, 1, 50, 55, 54, 55, 54, 53, 52, 39, 38, 39, 38, 7, 6, 1, 22, 23, 22, 21, 20, 7, 6, 35, 34, 39, 38,
+ 3, 2, 55, 54, 23, 22, 23, 22, 23, 22, 7, 6, 7, 6, 7, 6, 35, 16, 23, 22, 51, 50, 55, 54, 55, 52, 39, 38, 1,105, 80, 84,
+119, 68,121, 36, 50,117,122, 93, 54, 1,238, 96, 59, 91, 59,126,246,252,139,111, 1, 1,120,134,210,164,107,111, 1, 1, 55, 38,
+251, 67, 93, 74, 78, 58, 80,174,143, 87, 24, 1, 79, 94, 3,112, 1, 3, 61,108,147, 87, 53, 73, 9, 10,196,112,254,203, 65, 75,
+117,143,130, 95,213,213,168, 1,161, 1,139,190,213, 1, 1,111,115,155,128,107, 75,150, 15, 3, 2,254,234,128,176,156, 45, 86,
+123, 72, 86, 0, 0, 2, 0,112,255,233, 4,118, 6, 36, 0, 11, 0, 40, 0, 0, 1, 54, 39, 38, 35, 34, 7, 6, 21, 20, 23, 22,
+ 5, 4, 39, 38, 17, 52, 55, 54, 51, 50, 23, 22, 3, 2, 7, 6, 35, 34, 39, 38, 19, 23, 2, 23, 22, 51, 50, 55, 54, 3,174, 6,
+ 55, 75,140, 83, 64, 56,121, 74, 1, 19,254,204,131,211,104,104,175,209,135,128, 9, 9,128,137,240,237,140,149, 12,195, 33,117,
+ 85,150,144, 89, 95, 3,112,246,126,170, 71, 66, 90,153,107, 65,160, 9, 74,120, 1, 39,160,110,112,212,200,254,127,254,125,198,
+213,213,225, 1,210, 1,254,130,215,155,156,166, 0, 1, 0, 87, 0, 0, 5, 81, 5,223, 0, 27, 0, 0, 1, 6, 3, 6, 21, 17,
+ 35, 17, 52, 39, 2, 39, 38, 7, 53, 54, 23, 4, 19, 18, 37, 54, 23, 22, 7, 6, 39, 38, 4, 70,160, 82, 42,203, 42, 82,160,116,
+120, 67,160, 1, 67, 72,107, 1, 31,111, 64,120, 54, 33,117, 86, 5, 17, 72,254,243,141,165,253,118, 2,138,165,141, 1, 13, 72,
+ 52, 26,170, 21, 24, 48,254,114, 1,123, 67, 26, 49, 93,150, 86, 26, 18, 0, 0,255,255,255,225, 0, 0, 6,161, 6,102, 16, 39,
+ 2,165,254,110, 0, 0, 16, 7, 2,239, 1, 80, 0, 0, 0, 0,255,255, 0, 87, 0, 0, 5, 81, 5,223, 16, 39, 6,132, 4,197,
+ 1,117, 18, 6, 2,239, 0, 0, 0, 3, 0,112,254, 86, 4,209, 6, 20, 0, 21, 0, 30, 0, 39, 0, 65, 64, 16, 41, 26, 18, 6,
+ 9, 1, 30, 8, 12, 20, 32, 36, 18, 16, 69, 40, 16,252,236,212, 60, 60,252, 60, 60,212,236,196, 49, 64, 18, 30, 32,135, 1, 20,
+184, 40, 22, 31,135, 9, 12,140, 21,151, 11,189, 40, 0, 16,236,228,244, 60,252, 60, 16,244, 60,252, 60, 48, 1, 17, 50, 23, 22,
+ 17, 16, 7, 6, 35, 17, 35, 17, 34, 39, 38, 17, 16, 55, 54, 51, 17, 19, 50, 55, 54, 55, 54, 39, 38, 35, 3, 17, 34, 7, 6, 23,
+ 22, 23, 22, 2,252,199,133,137,137,133,199,183,199,134,136,136,134,199,183,113, 77, 84, 1, 1, 86, 77,113,183,113, 76, 87, 1,
+ 1, 85, 76, 6, 20,254, 99,153,156,254,237,254,237,156,153,254,111, 1,145,153,156, 1, 19, 1, 19,156,153, 1,157,250,119,103,
+115,202,200,117,103,252,184, 3, 72,103,117,200,202,115,103, 0, 0, 2, 0, 65,255,226, 6,109, 4, 96, 0, 16, 0, 30, 0, 0,
+ 19, 53, 33, 21, 35, 22, 21, 16, 37, 36, 3, 2, 33, 32, 17, 52, 55, 41, 1, 6, 21, 16, 51, 50, 3, 51, 2, 55, 54, 17, 52, 65,
+ 6, 44,147, 77,254, 97,254,241, 34, 41,254,248,254, 97, 77, 4, 58,252,146, 71,222,207, 4,170, 4,207,222, 3,168,184,184,207,
+164,253,173, 1, 1, 1, 42,254,213, 2, 82,164,207,209,167,254, 79, 2, 26,253,227, 3, 3, 1,174,167, 0, 0, 0, 1, 0,111,
+254, 91, 4,206, 4,103, 0, 47, 0, 0, 5, 38, 39, 38, 55, 7, 2, 7, 6, 39, 38, 55, 54, 55, 54, 39, 38, 35, 34, 7, 53, 54,
+ 23, 22, 23, 22, 7, 55, 18, 55, 54, 23, 22, 7, 6, 7, 6, 23, 22, 51, 50, 55, 2, 7, 6, 39, 53, 4, 3,249,246, 33, 21, 24,
+189, 96,200,141, 3, 1, 61, 96,136, 91, 43, 26,142, 57, 91, 82,126,246, 33, 19, 42,189, 96,200,141, 3, 1, 61, 96,136, 91, 43,
+ 26,142, 57, 91, 38,205,152,173, 1, 55, 10, 32,240,156, 99,108,254,247,124, 89,145, 68, 84,132,124,203,169,104,108,224, 61, 17,
+ 34,238,140,112,108, 1, 9,124, 89,145, 68, 84,132,124,203,169,104,108,253,224,102, 77, 90,160,160, 0, 0, 0, 0, 2, 0,115,
+254, 88, 5,217, 5,240, 0, 15, 0, 25, 0, 0, 5, 17, 35, 17, 38, 39, 38, 16, 0, 33, 32, 0, 17, 16, 7, 6, 2, 32, 0, 17,
+ 16, 0, 32, 0, 17, 16, 3,132,184,252,160,189, 1,121, 1, 59, 1, 58, 1,120,188,159,123,254, 72,254,253, 1, 3, 1,184, 1,
+ 1, 24,254,112, 1,144, 26,179,210, 2,196, 1,165,254, 91,254,158,254,159,210,179, 5, 73,254,184,254,229,254,230,254,184, 1,
+ 72, 1, 26, 1, 27, 0, 0, 0, 0, 2, 0,113,254, 86, 4,117, 4,123, 0, 10, 0, 27, 0, 0, 1, 34, 6, 16, 22, 51, 50, 54,
+ 53, 52, 38, 3, 17, 35, 17, 38, 39, 38, 17, 16, 0, 51, 50, 0, 17, 16, 7, 6, 2,115,148,172,171,149,147,172,172, 57,170,190,
+107,137, 1, 17,241,240, 1, 18,137,106, 3,223,231,254,110,231,232,200,199,233,252, 9,254,110, 1,146, 27,125,156, 1, 19, 1,
+ 20, 1, 56,254,200,254,236,254,237,156,123, 0, 0, 1, 0,139,254, 82, 4,171, 5,213, 0, 36, 0, 0, 1, 32, 7, 6, 17, 16,
+ 23, 22, 51, 50, 23, 22, 21, 20, 7, 6, 35, 52, 53, 22, 55, 54, 53, 52, 39, 38, 35, 32, 39, 38, 17, 16, 55, 54, 41, 1, 21, 3,
+ 70,254,243, 96,123, 91,109,200,122, 89, 84, 74, 80,163, 69, 42, 32, 32, 31, 58,254,192,142,149,185,138, 1,120, 1,101, 5, 43,
+119,152,254,205,254,181,127,152, 84, 79,120,115, 80, 87, 75, 76, 5, 44, 35, 37, 53, 44, 42,203,214, 1,101, 1, 78,237,177,170,
+ 0, 1, 0,113,254, 82, 4, 81, 4, 97, 0, 34, 0, 0, 1, 34, 7, 6, 21, 20, 22, 51, 50, 23, 22, 21, 20, 7, 6, 35, 52, 53,
+ 22, 55, 54, 53, 52, 39, 38, 35, 34, 0, 17, 52, 55, 54, 5, 33, 21, 2,172,216, 62, 99,198,110,131, 80, 84, 74, 80,163, 69, 42,
+ 32, 32, 32, 57,204,254,214,151,104, 1, 52, 1,173, 3,168, 72,113,192,205,227, 76, 79,120,115, 80, 87, 75, 76, 5, 44, 35, 37,
+ 53, 44, 42, 1, 62, 1, 14,243,188,131, 1,184,255,255, 0,201, 0, 0, 4, 35, 5,213, 18, 6, 0, 41, 0, 0, 0, 1,255, 64,
+254, 86, 3, 70, 6, 20, 0, 35, 0, 0, 51, 17, 52, 55, 54, 51, 50, 22, 23, 21, 46, 1, 35, 34, 7, 6, 21, 17, 33, 21, 33, 17,
+ 20, 7, 6, 35, 34, 38, 39, 53, 30, 1, 51, 50, 55, 54,238,136, 96,169, 49, 99, 51, 36, 82, 44,120, 58, 75, 1, 65,254,191,139,
+ 98,173, 57,102, 46, 49,100, 48, 87, 64, 82, 4,130,160,142,100, 18, 18,164, 28, 29, 62, 81,111,254,201,143,253, 63,146,165,115,
+ 21, 22,164, 31, 33, 75, 95, 0, 0, 1, 0,179,255,252, 4,212, 5,213, 0, 23, 0, 0, 1, 3, 1, 3, 6, 23, 22, 55, 21, 34,
+ 39, 38, 55, 19, 1, 19, 54, 39, 38, 7, 53, 50, 23, 22, 2, 54,110, 3, 12,234, 39, 27, 66,131,230, 81, 95, 19,154,253, 6,172,
+ 39, 27, 66,131,230, 81, 95, 4,135,254, 91, 1,126,253, 44, 96, 42,108, 35,189, 70, 82,182, 1,218,254,145, 2,144, 96, 42,108,
+ 35,189, 70, 82, 0, 1, 0,191, 0, 0, 4,136, 6, 19, 0, 7, 0, 0, 9, 1, 35, 19, 33, 1, 51, 3, 4,136,254,231,184,226,
+253, 38, 1, 25,184,226, 3,112,252,144, 2,198, 3, 77,253, 93, 0, 1, 0,114,254, 86, 6, 96, 5,241, 0, 33, 0, 0, 1, 17,
+ 35, 17, 6, 7, 53, 54, 5, 4, 19, 18, 17, 16, 3, 35, 0, 17, 16, 39, 6, 7, 6, 23, 17, 35, 54, 17, 52, 63, 1, 38, 37, 38,
+ 2, 81,170,205,104,208, 1,130, 1,217,237,214,246,225, 1, 4, 82, 56,121, 69, 5,205, 2,182,187,208,254,164, 48, 5, 58,253,
+140, 2, 73, 75,105,198,215, 8, 10,254,216,254,241,253,189,254, 88,254,146, 1, 76, 1,202, 1,209,125, 32, 92, 52,208,253,198,
+ 33, 2, 20,247,143,141,249, 11, 1, 0, 0, 0, 0, 1, 0,119,254,144, 4,150, 4,120, 0, 22, 0, 0, 1, 3, 35, 1, 38, 39,
+ 1, 35, 1, 38, 39, 38, 35, 53, 32, 23, 22, 19, 18, 17, 35, 16, 39, 3,110,239,185, 1,100, 14, 50,254, 70,185, 2, 31, 98, 46,
+188,211, 1, 45,242,224,172,116,168, 96, 1, 52,254,204, 1,192, 35, 77,253,208, 2,176,127, 33,132,164,216,200,254, 80,254,223,
+254,137, 1, 94,246, 0, 0, 0, 0, 1, 0,115,254, 75, 7, 5, 5,213, 0, 61, 0, 0, 1, 52, 3, 38, 39, 35, 22, 19, 22, 21,
+ 16, 7, 6, 35, 34, 39, 38, 61, 1, 35, 21, 20, 7, 6, 35, 34, 39, 38, 17, 52, 55, 18, 55, 35, 6, 7, 2, 21, 16, 23, 22, 51,
+ 50, 55, 54, 55, 22, 23, 22, 23, 6, 7, 6, 7, 23, 54, 55, 36, 55, 54, 55, 54, 7, 5,100, 56, 95,250, 84,135, 67, 71, 65,134,
+116, 70, 70,199, 71, 72,114,125, 73, 72, 67,135, 84,249, 93, 59,100,123,121,211,146,101,100, 39, 39,100, 68,103,164,205,121,138,
+ 97,140,118, 1, 20,180,219, 68, 61, 2,224,194, 1, 21,156,130, 70,254,191,159,183,254,217,119,109,105,104,198,241,241,198,104,
+105,109,107, 1, 51,183,159, 1, 65, 70,127,159,254,242,201,254,104,180,177, 94, 94,173,173, 94, 65, 23,128, 81, 48, 24,133, 23,
+ 42,100,136,166,230,203, 0, 0, 0, 1, 0,135,254, 85, 6, 40, 4, 96, 0, 37, 0, 0, 33, 36, 3, 2, 33, 32, 17, 52, 19, 51,
+ 2, 21, 2, 23, 22, 3, 51, 2, 55, 54, 17, 52, 3, 51, 18, 21, 22, 7, 6, 7, 6, 7, 6, 7, 39, 54, 55, 54, 4,136,254,237,
+ 30, 35,254,242,254, 97,135,218,143, 1,223,208, 5,170, 3,206,222,143,218,135, 1, 57,105,197,154,210,107,112, 91, 81,139,199,
+ 1, 1, 13,254,242, 2, 53,235, 1, 64,254,192,240,254,151, 1, 1, 1,212,254, 43, 2, 2, 1,104,240, 1, 64,254,192,235,209,
+132,244,158,123, 73, 37, 16,108, 11, 43, 63, 0, 0, 1, 0,115,254, 86, 5, 72, 5,240, 0, 29, 0, 0, 1, 6, 7, 6, 17, 20,
+ 23, 22, 51, 50, 55, 54, 25, 1, 51, 17, 35, 17, 6, 7, 6, 35, 32, 39, 38, 17, 16, 19, 54, 37, 2,236,180, 96,133,110, 98,195,
+196, 98, 99,217,217, 68,104,104,170,255, 0,156,162,186,151, 1, 40, 5, 74, 18,132,185,254,238,249,171,152,152,153, 1, 11, 2,
+236,248,129, 2,144,132, 64, 63,213,221, 1, 71, 1, 54, 1, 8,213, 1, 0, 0, 0, 1, 0,113,254, 86, 4,140, 4,123, 0, 26,
+ 0, 0, 1, 6, 7, 6, 21, 20, 23, 22, 32, 54, 53, 17, 51, 17, 35, 17, 14, 1, 35, 34, 39, 38, 53, 52, 55, 54, 51, 2,139,154,
+ 80,114, 94, 83, 1, 76,168,184,184, 58,177,144,218,133,137,158,127,253, 3,253, 14, 99,141,208,189,129,116,231,203, 2, 49,249,
+246, 2, 82,100, 97,162,168,248,236,200,162, 0, 0, 1, 0,201,254, 75, 5,226, 5,213, 0, 37, 0, 0, 1, 32, 23, 22, 17, 20,
+ 7, 6, 7, 6, 7, 6, 7, 39, 54, 55, 54, 55, 54, 55, 54, 53, 52, 39, 38, 35, 34, 7, 6, 21, 17, 35, 17, 51, 17, 54, 55, 54,
+ 3, 76, 1, 39,177,190, 60, 67,170,195,241,185, 73, 97,134,125,217,152,136, 44, 54,126,115,205,203,115,113,202,202, 78,105,105,
+ 4,123,179,194,254,253,204,161,178,128,147, 69, 53, 12,133, 22, 50, 87,122,109,104,127,192,157,150,134,129,126,222,254, 39, 5,
+213,253,154,135, 66, 67, 0, 0, 0, 2, 0, 45,255,227, 4,146, 4,154, 0, 23, 0, 77, 0, 0, 1, 38, 35, 34, 7, 6, 7, 6,
+ 7, 6, 21, 20, 23, 22, 23, 22, 23, 22, 51, 50, 55, 54, 55, 54, 37, 22, 21, 20, 7, 6, 33, 34, 39, 38, 35, 34, 7, 39, 54, 51,
+ 50, 23, 22, 51, 50, 55, 54, 53, 52, 39, 6, 7, 6, 7, 6, 39, 38, 39, 38, 39, 38, 39, 38, 53, 52, 55, 54, 55, 54, 55, 54, 51,
+ 50, 23, 54, 55, 23, 6, 3, 44,127,141, 31, 55, 29, 37, 29, 16, 14, 12, 15, 24, 26, 35, 32, 30, 25, 71, 59, 73, 36, 1, 11,108,
+127,111,254,247,141, 99, 75, 53, 65, 81, 84,135, 95,130, 82, 63, 91,157, 79, 75, 49, 27, 31, 70,117,102, 71, 41, 72, 50, 64, 48,
+ 41, 30, 29, 31, 46, 62, 80,101, 94,210,144, 56, 42,136, 55, 3, 68,152, 22, 11, 33, 26, 32, 27, 33, 32, 21, 28, 17, 20, 6, 5,
+ 25, 20, 49, 24, 50,192,212,176,156,136, 46, 35, 65,147, 76, 46, 35, 94, 89,127,140,113, 25, 23, 52, 43, 38, 2, 1, 10, 7, 34,
+ 26, 72, 52, 66, 59, 59, 61, 47, 63, 34, 43,159, 86,104, 80,146, 0, 1, 0, 79,254, 86, 5, 11, 5,246, 0, 33, 0, 0, 5, 4,
+ 33, 32, 1, 0, 55, 54, 53, 52, 39, 38, 35, 34, 7, 6, 7, 35, 54, 55, 54, 33, 32, 23, 22, 21, 20, 7, 0, 1, 22, 51, 32, 55,
+ 4,250,255, 0,254,237,254,175,254,185, 2,186,179,108,108, 99,164,180, 94, 35, 24,240, 44, 86,163, 1, 24, 1, 19,161,162,162,
+254,247,254, 24,156,213, 1, 41,232,236,190, 1,163, 1,241,219,132,156,141,101, 93,146, 54, 63,161,102,194,144,145,241,216,182,
+254,242,254,133,181,179, 0, 0, 0, 1, 0,100,254, 86, 4,106, 4,123, 0, 32, 0, 0, 1, 6, 35, 32, 1, 0, 55, 54, 53, 52,
+ 39, 38, 35, 34, 7, 6, 7, 35, 54, 55, 54, 51, 50, 4, 21, 20, 7, 6, 1, 22, 51, 50, 55, 4, 92,218,234,254,238,254,222, 2,
+ 66,167, 92, 92, 84,139,153, 80, 30, 20,204, 37, 73,139,238,232, 1, 20,138,175,254, 47,145,169,253,197,254,239,153, 1,121, 1,
+ 89,194,107,125,111, 83, 75,117, 44, 50,129, 82,156,232,194,164,156,197,254,224,186,144, 0, 0, 0, 2, 0,115, 0, 0, 5,182,
+ 5,239, 0, 2, 0, 53, 0, 0, 37, 33, 9, 3, 38, 39, 38, 35, 34, 15, 1, 53, 54, 55, 54, 51, 50, 23, 22, 23, 9, 1, 54, 55,
+ 54, 51, 50, 23, 22, 23, 21, 39, 38, 35, 34, 7, 6, 7, 9, 1, 22, 23, 22, 59, 1, 21, 33, 53, 51, 50, 55, 54, 1,218, 2,110,
+254,205,254, 20, 1,128,254,220, 19, 26, 34, 63, 25, 22, 69, 33, 32, 31, 28,114, 75, 44, 47, 1, 2, 1, 9, 52, 39, 75,114, 29,
+ 30, 32, 33, 68, 23, 24, 60, 38, 19, 26,254,210, 1,116, 6, 7, 29, 69, 71,250,195, 71, 72, 26, 12,170, 1,202,254,104, 2, 61,
+ 1,187, 29, 26, 34, 4, 10,187, 11, 5, 5, 67, 40, 70,254,129, 1,127, 75, 35, 67, 5, 5, 11,187, 10, 4, 34, 17, 38,254, 69,
+253,195, 9, 8, 33,170,170, 33, 15, 0, 0, 0, 0, 3, 0, 54, 0, 0, 4,203, 4,123, 0, 0, 0, 3, 0, 54, 0, 0, 37, 41,
+ 1, 3, 9, 1, 3, 38, 39, 38, 35, 34, 15, 1, 53, 54, 55, 54, 51, 50, 23, 22, 23, 27, 1, 54, 55, 54, 51, 50, 23, 22, 23, 21,
+ 39, 38, 35, 34, 7, 6, 7, 3, 1, 22, 23, 22, 59, 1, 21, 33, 53, 51, 50, 55, 54, 4,203,252,207, 1,204,228,254, 91, 1, 57,
+239, 21, 17, 29, 54, 21, 19, 58, 28, 27, 26, 24,131, 64, 37, 40,197,197, 40, 37, 64,131, 24, 26, 27, 28, 58, 19, 21, 54, 29, 17,
+ 21,246, 1, 45, 6, 5, 25, 58, 73,251,107, 73, 58, 25, 5,158, 1, 56,254,238, 1,164, 1, 61, 28, 14, 25, 3, 7,141, 8, 4,
+ 4, 51, 30, 53,254,250, 1, 6, 53, 30, 51, 4, 4, 8,141, 7, 3, 25, 14, 28,254,184,254,103, 8, 5, 25,158,158, 25, 5, 0,
+ 0, 2, 0,115,255,227, 5, 37, 6, 16, 0, 29, 0, 43, 0, 0, 1, 36, 7, 6, 7, 54, 55, 54, 51, 50, 0, 16, 0, 33, 32, 39,
+ 38, 17, 16, 55, 54, 33, 50, 55, 54, 55, 21, 6, 7, 6, 18, 16, 38, 35, 34, 7, 6, 21, 20, 23, 22, 51, 50, 55, 3, 42,254,214,
+ 87, 56, 22, 81, 85,123,130,245, 1, 50,254,206,254,249,254,206,164,163,139,124, 1,176,115,149,160, 75, 94,151,108,142,200,186,
+188,104,105,105,101,191,188, 98, 5, 45, 2,115, 74,160, 86, 34, 49,254,188,253,240,254,188,156,155, 1, 80, 1,222,210,187, 10,
+ 10, 39,177, 36, 8, 6,252, 65, 1,130,230,115,116,192,189,120,115,115, 0, 0, 0, 2, 0,113,255,227, 4, 91, 6, 16, 0, 31,
+ 0, 47, 0, 0, 1, 38, 7, 6, 7, 54, 55, 54, 51, 50, 23, 22, 16, 7, 6, 35, 34, 39, 38, 17, 16, 55, 54, 33, 50, 55, 54, 55,
+ 21, 6, 7, 6, 19, 52, 39, 38, 35, 34, 7, 6, 21, 20, 23, 22, 51, 50, 55, 54, 2,155,227, 73, 44, 20, 41,101, 91,120,204,127,
+128,128,127,219,255,137,136,116,103, 1, 79, 95, 92, 83, 71, 93, 69, 90,168, 83, 84,146,149, 86, 88, 88, 84,151,148, 82, 83, 5,
+ 55, 2,120, 74,169, 70, 54, 49,162,162,253,240,162,162,156,155, 1, 80, 1,222,210,187, 10, 10, 39,167, 39, 5, 6,252,248,205,
+114,115,115,116,203,199,120,115,115,116, 0, 0, 0, 1, 0, 44,254, 86, 4,183, 5,213, 0, 15, 0, 0, 1, 17, 35, 53, 33, 17,
+ 35, 17, 33, 21, 35, 17, 33, 17, 51, 17, 4,183,203,254,235,203,254,235,203, 1,224,203, 4, 96,254,242,100,250,160, 5, 96,100,
+ 1, 14, 1,117,254,139, 0, 0, 0, 1, 0, 55,254, 85, 4, 20, 5,207, 0, 15, 0, 0, 1, 17, 35, 53, 35, 17, 35, 17, 35, 21,
+ 35, 17, 33, 17, 51, 17, 4, 20,173,229,185,229,173, 1,146,185, 4, 95,255, 0,112,250,134, 5,122,112, 1, 0, 1,112,254,144,
+ 0, 1, 0,111,255,242, 4,206, 4,103, 0, 43, 0, 0, 1, 2, 7, 6, 39, 38, 55, 54, 55, 54, 39, 38, 35, 34, 7, 53, 54, 23,
+ 22, 23, 22, 7, 55, 18, 55, 54, 23, 22, 7, 6, 7, 6, 23, 22, 51, 50, 55, 21, 6, 39, 38, 39, 38, 55, 2, 40, 96,200,141, 3,
+ 1, 61, 96,136, 91, 43, 26,142, 57, 91, 82,126,246, 33, 19, 42,189, 96,200,141, 3, 1, 61, 96,136, 91, 43, 26,142, 57, 91, 82,
+126,246, 33, 19, 42, 1,153,254,247,124, 89,145, 68, 84,132,124,203,169,104,108,224, 61, 17, 32,240,140,112,108, 1, 9,124, 89,
+145, 68, 84,132,124,203,169,104,108,224, 61, 17, 32,240,140,112, 0, 2, 0,183,254, 86, 4,164, 4,123, 0, 21, 0, 29, 0, 0,
+ 19, 54, 55, 54, 55, 54, 51, 50, 0, 16, 2, 35, 34, 38, 39, 18, 41, 1, 21, 33, 32, 19, 36, 16, 38, 32, 6, 16, 22, 32,186, 2,
+ 88, 61,151, 59,182,204, 0,255,255,204,123,177, 58, 5, 1, 32, 1,244,254, 28,254, 10, 6, 3, 45,167,254,220,167,167, 1, 36,
+ 2, 37,204,167,102, 90, 35,254,188,253,240,254,188, 97,100,254, 88,170, 2,218, 52, 1,150,231,231,254,106,231,255,255, 0,113,
+255,227, 3,231, 4,123, 18, 6, 0, 70, 0, 0,255,255,255,219,254, 86, 1,121, 6, 20, 18, 6, 0, 77, 0, 0, 0, 3, 0,115,
+255,227, 5,217, 5,240, 0, 7, 0, 15, 0, 26, 0, 0, 1, 33, 18, 23, 22, 32, 55, 54, 19, 38, 39, 38, 32, 7, 6, 7, 1, 32,
+ 0, 17, 16, 0, 33, 32, 0, 16, 0, 5, 3,252, 69, 8,122,129, 1,184,129,119, 1, 22, 98,129,254, 72,129, 96, 25, 1,214, 1,
+ 58, 1,120,254,136,254,198,254,197,254,135, 1,121, 2,198,254,255,154,164,164,153, 1,172,186,126,164,164,121,191, 2,128,254,
+ 91,254,158,254,159,254, 91, 1,164, 2,196, 1,165, 0, 0, 0, 0, 1, 0,113,255,227, 3,216, 4,123, 0, 33, 0, 0, 1, 38,
+ 39, 38, 35, 34, 7, 6, 7, 33, 21, 33, 22, 23, 22, 51, 50, 63, 1, 21, 7, 6, 35, 32, 39, 38, 16, 55, 54, 33, 50, 23, 22, 23,
+ 3,216, 37, 37, 99,106,183,102, 95, 18, 2,165,253, 91, 18, 95,102,183,128, 77, 74, 79,104,107,254,244,156,157,157,156, 1, 12,
+101,110, 40, 39, 3,174, 13, 10, 26, 99, 92,169,144,169, 92, 99, 26, 25,167, 18, 22,156,156, 2, 40,156,156, 22, 8, 12, 0, 0,
+ 0, 1, 0,196,255,227, 4, 43, 4,123, 0, 33, 0, 0, 19, 53, 54, 55, 54, 51, 32, 23, 22, 16, 7, 6, 33, 34, 47, 1, 53, 23,
+ 22, 51, 50, 55, 54, 55, 33, 53, 33, 38, 39, 38, 35, 34, 7, 6,196, 39, 40,110,101, 1, 12,156,157,157,156,254,244,107,104, 79,
+ 74, 77,128,183,102, 95, 18,253, 91, 2,165, 18, 95,102,183,106, 99, 37, 3,174,163, 12, 8, 22,156,156,253,216,156,156, 22, 18,
+167, 25, 26, 99, 92,169,144,169, 92, 99, 26, 10,255,255, 0,201, 0, 0, 4,141, 5,213, 18, 6, 0,160, 0, 0,255,255, 0,186,
+254, 86, 4,164, 6, 20, 18, 6, 0,192, 0, 0,255,255, 0,115,255,227, 5, 39, 5,240, 18, 6, 0, 38, 0, 0, 0, 1, 0,201,
+ 0, 0, 6, 31, 5,213, 0, 12, 0, 0, 19, 33, 9, 1, 33, 17, 35, 17, 1, 35, 1, 17, 35,201, 1, 45, 1,125, 1,127, 1, 45,
+197,254,127,203,254,127,196, 5,213,254, 33, 1,223,250, 43, 5, 31,254, 25, 1,231,250,225, 0, 0, 1, 0,127,254, 86, 4,179,
+ 4, 96, 0, 12, 0, 0, 19, 33, 19, 1, 33, 17, 35, 17, 1, 35, 1, 17, 35,127, 1, 27,254, 1, 0, 1, 27,185,254,236,153,254,
+235,185, 4, 96,254,123, 1,133,251,160, 3,178,254, 96, 1,160,250,164, 0, 0, 0, 2, 0, 85,254, 86, 4,164, 4,123, 0, 24,
+ 0, 32, 0, 0, 23, 17, 52, 55, 54, 55, 54, 51, 50, 0, 16, 2, 35, 34, 38, 39, 17, 33, 21, 33, 21, 35, 53, 35, 53, 0, 16, 38,
+ 32, 6, 16, 22, 32,186, 90, 61,151, 59,182,204, 0,255,255,204,123,177, 58, 1,229,254, 27,185,101, 3,144,167,254,220,167,167,
+ 1, 36,144, 2,181,231,140,102, 90, 35,254,188,253,240,254,188, 97,100,254,200,170,112,112,170, 1,244, 1,150,231,231,254,106,
+231, 0, 0, 0,255,255, 0,115,255,227, 5, 39, 5,240, 18, 6, 1, 72, 0, 0,255,255, 0,115,255,227, 5, 39, 5,240, 18, 38,
+ 3, 22, 0, 0, 16, 7, 0,121, 2, 51, 0, 0,255,255, 0,115,255,227, 5, 39, 5,240, 16, 39, 0,121, 0,228, 0, 0, 18, 6,
+ 3, 26, 0, 0,255,255, 0,201, 0, 0, 4,139, 5,213, 18, 38, 3, 50, 0, 0, 16, 7, 6,135, 4,238, 1,117,255,255, 0,201,
+ 0, 0, 4,139, 5,213, 18, 38, 3, 50, 0, 0, 16, 7, 6,132, 4,229, 1,117, 0, 1,255,250,254,102, 5,172, 5,213, 0, 29,
+ 0, 0, 37, 16, 6, 43, 1, 53, 51, 50, 55, 54, 53, 17, 52, 38, 35, 33, 17, 35, 17, 33, 53, 33, 21, 33, 17, 33, 50, 23, 22, 21,
+ 5,172,204,228, 76, 62,134, 56, 55,124,124,254,136,203,254, 82, 4,139,253,238, 1,161,186,113,109,104,254,242,244,170, 75, 75,
+194, 1, 34,159,158,253, 57, 5, 43,170,170,254, 70,119,114,238,255,255, 0,201, 0, 0, 4,106, 5,213, 18, 38, 3, 48, 0, 0,
+ 16, 7, 6,133, 4,174, 1,117, 0, 1, 0,115,255,227, 5, 39, 5,240, 0, 36, 0, 58, 64, 32, 36,149, 35,173, 37, 26,161, 25,
+174, 30,149, 21,145, 37, 8,161, 9,174, 4,149, 13,140, 37, 38, 35, 25, 8, 34, 0, 25, 17, 37, 16,220,236, 50,212, 60,204,204,
+ 49, 0, 16,244,236,244,236, 16,244,236,244,236, 16,244,236, 48, 1, 18, 23, 22, 33, 50, 55, 54, 55, 21, 6, 7, 6, 35, 32, 39,
+ 38, 17, 16, 55, 54, 33, 50, 23, 22, 23, 21, 38, 39, 38, 35, 32, 7, 6, 7, 33, 21, 1, 72, 7,129,136, 1, 0,130,116,115,102,
+106,119,118,132,254,173,195,195,195,195, 1, 83,134,118,119,104,102,115,116,130,255, 0,136,103, 25, 2,178, 2,199,254,242,147,
+157, 47, 47, 95,211, 72, 36, 36,207,208, 1,103, 1,104,207,208, 36, 35, 71,213, 95, 47, 47,156,119,198,170, 0,255,255, 0,135,
+255,227, 4,162, 5,240, 18, 6, 0, 54, 0, 0,255,255, 0,201, 0, 0, 1,147, 5,213, 18, 6, 0, 44, 0, 0,255,255, 0,201,
+ 0, 0, 1,147, 5,213, 18, 38, 3, 35, 0, 0, 17, 7, 6,132, 3, 47, 1,117, 0, 8,180, 0, 10, 7, 1, 7, 43, 49, 0, 0,
+255,255,255,150,254,102, 1,147, 5,213, 18, 6, 0, 45, 0, 0, 0, 2, 0, 54,255,227, 8, 47, 5,213, 0, 22, 0, 33, 0, 0,
+ 1, 33, 21, 16, 3, 6, 5, 53, 54, 55, 18, 25, 1, 33, 17, 51, 50, 4, 21, 20, 4, 35, 33, 1, 52, 39, 38, 43, 1, 17, 51, 50,
+ 55, 54, 4,112,254, 27,132, 98,254,145,212, 67,117, 3,120,234,251, 1, 16,254,240,251,254, 76, 2,234, 79, 78,163,224,224,161,
+ 80, 79, 5, 43,213,254, 24,254,170,253, 56,167, 46,168, 1, 37, 2, 53, 1, 27,253,154,218,222,221,218, 1,183,139, 68, 67,253,
+221, 68, 67, 0, 0, 2, 0,201, 0, 0, 7,204, 5,213, 0, 18, 0, 29, 0, 0, 33, 17, 33, 17, 35, 17, 51, 17, 33, 17, 51, 17,
+ 51, 50, 4, 21, 20, 4, 35, 1, 52, 39, 38, 43, 1, 17, 51, 50, 55, 54, 4, 13,253,134,202,202, 2,122,202,234,251, 1, 16,254,
+240,251, 1, 54, 79, 78,163,224,224,161, 80, 79, 2,199,253, 57, 5,213,253,156, 2,100,253,154,218,222,221,218, 1,183,139, 68,
+ 67,253,221, 68, 67, 0, 0, 0, 0, 1,255,250, 0, 0, 5,172, 5,213, 0, 20, 0, 0, 1, 50, 23, 22, 21, 17, 35, 17, 52, 38,
+ 35, 33, 17, 35, 17, 33, 53, 33, 21, 33, 17, 4, 20,186,113,109,201,124,124,254,136,203,254, 82, 4,139,253,238, 3,113,119,114,
+238,254,102, 1,138,159,158,253, 57, 5, 43,170,170,254, 70, 0,255,255, 0,201, 0, 0, 5,106, 5,213, 18, 38, 3, 55, 0, 0,
+ 16, 7, 6,133, 4,238, 1,117,255,255, 0,201, 0, 0, 5, 51, 5,213, 18, 38, 3, 53, 0, 0, 16, 7, 6,135, 4,229, 1,117,
+255,255, 0, 35,255,227, 4,189, 5,213, 16, 39, 6,139, 4,114, 1,117, 18, 6, 3, 64, 0, 0, 0, 1, 0,201,254, 86, 5, 59,
+ 5,213, 0, 11, 0, 0, 41, 1, 17, 51, 17, 33, 17, 51, 17, 33, 17, 35, 2,188,254, 13,202, 2,222,202,254, 74,201, 5,213,250,
+213, 5, 43,250, 43,254, 86, 0,255,255, 0, 16, 0, 0, 5,104, 5,213, 18, 6, 0, 36, 0, 0, 0, 2, 0,201, 0, 0, 4,236,
+ 5,213, 0, 10, 0, 23, 0, 44, 64, 24, 13,149, 23,129, 22, 5,149, 14,173, 6,149, 22, 25, 11, 0, 25, 18, 46, 5, 13, 28, 23,
+ 4, 24, 16,252,236, 50,244,236,196,204, 49, 0, 47,236,244,236, 16,244,236, 48, 1, 52, 39, 38, 35, 33, 17, 33, 50, 55, 54, 17,
+ 21, 33, 17, 33, 50, 4, 21, 20, 4, 35, 33, 17, 4, 23, 79, 78,163,254,188, 1, 68,163, 78, 79,253,124, 1, 78,251, 1, 16,254,
+240,251,253,232, 1,183,139, 68, 67,253,221, 68, 67, 4,168,166,254, 64,218,222,221,218, 5,213,255,255, 0,201, 0, 0, 4,236,
+ 5,213, 18, 6, 0, 37, 0, 0, 0, 1, 0,201, 0, 0, 4,106, 5,213, 0, 5, 0, 25, 64, 12, 4,149, 1,129, 0, 7, 2, 4,
+ 28, 1, 4, 6, 16,252,252,204,196, 49, 0, 47,244,236, 48, 51, 17, 33, 21, 33, 17,201, 3,161,253, 41, 5,213,170,250,213, 0,
+ 0, 2, 0, 49,254, 86, 6, 3, 5,213, 0, 7, 0, 23, 0, 53, 64, 15, 2, 28, 14, 25, 19, 28, 16, 23, 3, 28, 13, 20, 28, 23,
+ 24, 16,220,236,212,236, 16,212,236,204,212,236, 49, 0, 64, 12, 3,149, 13,129, 18, 22,189, 15, 0, 23,149, 20, 47,236, 50, 50,
+236, 50,244,236, 48, 37, 33, 17, 33, 21, 16, 3, 6, 5, 54, 55, 18, 25, 1, 33, 17, 51, 17, 35, 17, 33, 17, 35, 17, 1,200, 2,
+168,254, 27,132, 24,254,168,132, 50,117, 3,120,201,201,251,192,201,170, 4,129,212,254, 17,254,177, 61, 50, 57,126, 1, 37, 2,
+ 53, 1, 26,250,213,253,172, 1,170,254, 86, 2, 84, 0, 0, 0,255,255, 0,201, 0, 0, 4,139, 5,213, 18, 6, 0, 40, 0, 0,
+ 0, 1, 0, 59, 0, 0, 6,173, 5,213, 0, 21, 0,110, 64, 22, 66, 2, 20, 16,129, 14, 8, 12,149, 0, 18,173, 6, 10, 14, 23,
+ 8, 21, 28, 11, 20, 22, 16,212, 60,252, 60,196, 49, 0, 47, 60, 60,244, 60,236, 50, 16,244, 60, 60, 48, 75, 83, 88, 64, 36, 4,
+ 17, 7, 2, 1, 5, 17, 6, 7, 6, 4, 17, 1, 3, 17, 2, 2, 1, 15, 17, 18, 13, 12, 16, 17, 17, 18, 17, 15, 17, 12, 14, 17,
+ 13, 13, 12, 5, 7, 16,236, 16,236, 7, 16,236, 8, 16,236, 5, 7, 16,236, 16,236, 7, 16,236, 8, 16,236, 89, 1, 51, 1, 51,
+ 9, 1, 35, 1, 35, 17, 35, 17, 35, 1, 35, 9, 1, 51, 1, 51, 17, 51, 3,217,149, 1, 52,217,254,162, 1,144,217,254,155,150,
+202,150,254,155,217, 1,144,254,162,217, 1, 52,149,202, 3,113, 2,100,253, 71,252,228, 2,199,253, 57, 2,199,253, 57, 3, 28,
+ 2,185,253,156, 2,100, 0, 0,255,255, 0,156,255,227, 4,115, 5,240, 18, 6, 0, 22, 0, 0, 0, 1, 0,201, 0, 0, 5, 51,
+ 5,213, 0, 9, 0,121, 64, 30, 3, 17, 9, 9, 8, 8, 17, 4, 4, 3, 66, 8, 3, 9, 6,175, 2, 5, 9, 4, 7, 3, 28, 0,
+ 54, 7, 28, 6, 4, 10, 16,252,236,252,236, 17, 57, 57, 49, 0, 47, 60,236, 50, 57, 57, 48, 75, 83, 88, 7, 16, 4,237, 7, 16,
+ 4,237, 89, 34,178, 31, 11, 1, 1, 93, 64, 48, 54, 8, 56, 3, 72, 8, 71, 3,105, 8,102, 3,128, 8, 7, 6, 4, 9, 9, 21,
+ 4, 26, 9, 70, 4, 73, 9, 87, 4, 88, 9,101, 4,105, 9,121, 9,133, 4,138, 9,149, 4,154, 9,159, 11, 16, 93, 0, 93, 1,
+ 17, 35, 17, 1, 33, 17, 51, 17, 1, 5, 51,196,253,106,254,240,196, 2,150, 5,213,250, 43, 4,225,251, 31, 5,213,251, 31, 4,
+225, 0, 0, 0,255,255, 0,201, 0, 0, 5, 51, 5,213, 16, 39, 6,139, 4,245, 1,117, 18, 6, 3, 53, 0, 0,255,255, 0,201,
+ 0, 0, 5,106, 5,213, 18, 6, 0, 46, 0, 0, 0, 1, 0, 54,255,228, 5, 58, 5,213, 0, 15, 0, 38, 64, 20, 11,149, 6,129,
+ 9, 1,149, 0,140, 9, 17, 4, 10, 28, 7, 11, 28, 6, 1, 16, 16,212,212,236,212,236,236, 49, 0, 47,244,236, 16,244,236, 48,
+ 23, 53, 54, 55, 18, 25, 1, 33, 17, 35, 17, 33, 21, 16, 3, 6, 54,212, 67,117, 3,120,202,254, 27,132, 98, 28,167, 46,168, 1,
+ 37, 2, 53, 1, 26,250, 43, 5, 43,212,254, 24,254,170,253, 0,255,255, 0,201, 0, 0, 6, 31, 5,213, 18, 6, 0, 48, 0, 0,
+255,255, 0,201, 0, 0, 5, 59, 5,213, 18, 6, 0, 43, 0, 0,255,255, 0,115,255,227, 5,217, 5,240, 18, 6, 0, 50, 0, 0,
+ 0, 1, 0,201, 0, 0, 5, 59, 5,213, 0, 7, 0, 31, 64, 16, 4,149, 7,129, 2, 6, 9, 4, 3, 28, 0, 4, 28, 7, 4, 8,
+ 16,252,236,212,236,236, 49, 0, 47, 60,244,236, 48, 1, 17, 35, 17, 33, 17, 35, 17, 5, 59,202,253, 34,202, 5,213,250, 43, 5,
+ 43,250,213, 5,213, 0, 0, 0,255,255, 0,201, 0, 0, 4,141, 5,213, 18, 6, 0, 51, 0, 0,255,255, 0,115,255,227, 5, 39,
+ 5,240, 18, 6, 0, 38, 0, 0,255,255,255,250, 0, 0, 4,233, 5,213, 18, 6, 0, 55, 0, 0, 0, 1, 0, 35,255,227, 4,189,
+ 5,213, 0, 17, 0, 65, 64, 14, 66, 6,149, 5,140, 16, 13,129, 18, 19, 17, 6, 13, 18, 16,212,196,212,196, 49, 0, 16,228, 50,
+244,236, 48, 75, 83, 88, 64, 18, 15, 17, 0, 13, 12, 16, 17, 17, 17, 0, 15, 17, 12, 14, 17, 13, 13, 12, 5, 7, 16,236, 16,236,
+ 7, 16,236, 8, 16,236, 89, 37, 6, 7, 6, 43, 1, 53, 51, 50, 55, 54, 63, 1, 1, 51, 9, 1, 51, 2,143, 22, 31,103,227, 77,
+ 63,140, 49, 14, 8, 45,254, 33,217, 1,115, 1,117,217,181, 51, 37,122,170, 75, 22, 18,106, 4,107,252,148, 3,108, 0, 0, 0,
+ 0, 3, 0,115, 0, 0, 5,217, 5,213, 0, 8, 0, 17, 0, 39, 0, 59, 64, 31, 17, 0,149, 29, 26, 27,129, 39, 9, 8,149, 37,
+ 18, 39, 41, 16, 13, 25, 33, 18, 0, 27, 28, 37, 17, 28, 4, 25, 22, 16, 40, 16,252,236,212, 60, 60,252, 60, 60,212,236,236, 49,
+ 0, 47,220, 60,236, 50, 16,244,220, 60,236, 50, 48, 1, 6, 7, 6, 21, 20, 23, 22, 23, 51, 54, 55, 54, 53, 52, 39, 38, 39, 3,
+ 38, 39, 38, 17, 16, 55, 54, 55, 53, 51, 21, 22, 23, 22, 17, 16, 7, 6, 7, 21, 35, 2,194,150, 98,130,130, 98,150,202,150, 98,
+128,128, 98,150,202,244,158,189,189,157,245,202,244,157,188,188,157,244,202, 4,142, 21, 87,115,198,197,115, 87, 21, 21, 87,115,
+197,198,115, 87, 21,252, 16, 22,134,160, 1, 15, 1, 15,161,135, 22,159,159, 23,134,161,254,241,254,242,161,134, 23,157, 0, 0,
+255,255, 0, 61, 0, 0, 5, 59, 5,213, 18, 6, 0, 59, 0, 0, 0, 1, 0,201,254, 86, 6, 4, 5,213, 0, 11, 0, 40, 64, 21,
+ 6, 2,129, 11,189, 8, 4,149, 1, 13, 0, 28, 9, 6, 28, 7, 3, 28, 2, 4, 12, 16,252,236,212,236,212,236,204, 49, 0, 47,
+236, 50,236,244, 60, 48, 41, 1, 17, 51, 17, 33, 17, 51, 17, 51, 17, 35, 5, 59,251,142,202, 2,222,202,201,201, 5,213,250,213,
+ 5, 43,250,213,253,172, 0, 0, 0, 1, 0,175, 0, 0, 4,179, 5,213, 0, 16, 0, 35, 64, 18, 2,149, 12,173, 14, 7,129, 0,
+ 18, 4, 1, 14, 28, 15, 8, 28, 7, 17, 16,220,236,212,236, 50,236, 49, 0, 47,228, 50,244,236, 48, 33, 17, 33, 34, 39, 38, 53,
+ 17, 51, 17, 20, 22, 51, 33, 17, 51, 17, 3,232,254, 95,186,113,109,201,124,124, 1,120,203, 2,199,119,114,238, 1, 55,254,217,
+159,158, 2,100,250, 43, 0, 0, 0, 1, 0,201, 0, 0, 7, 57, 5,213, 0, 11, 0, 40, 64, 21, 10, 2, 6,129, 0, 8,149, 5,
+ 13, 4, 2, 28, 3, 10, 28, 11, 7, 28, 6, 4, 12, 16,252,236,212,252,212,236,236, 49, 0, 47,236, 50,244, 60,196, 48, 37, 33,
+ 17, 51, 17, 33, 17, 51, 17, 33, 17, 51, 4,102, 2, 9,202,249,144,202, 2, 9,202,170, 5, 43,250, 43, 5,213,250,213, 4,221,
+ 0, 1, 0,201,254, 86, 8, 2, 5,213, 0, 15, 0, 49, 64, 26, 6, 10, 2,129, 15,189, 12, 8, 4,149, 1, 17, 0, 28, 13, 10,
+ 28, 11, 6, 28, 7, 3, 28, 2, 4, 16, 16,252,236,212,252,212,236,212,236,204, 49, 0, 47,236, 50, 50,236,244, 60,196, 48, 41,
+ 1, 17, 51, 17, 33, 17, 51, 17, 33, 17, 51, 17, 51, 17, 35, 7, 57,249,144,202, 2, 9,202, 2, 9,202,201,201, 5,213,250,213,
+ 4,221,251, 35, 5, 43,250,213,253,172, 0, 0, 0, 2, 0, 50, 0, 0, 6, 24, 5,213, 0, 12, 0, 23, 0, 42, 64, 22, 2,149,
+ 3,129, 0, 18,149, 5,173, 19,149, 0, 16, 13, 25, 9, 18, 4, 28, 1, 3, 24, 16,204,220,236, 50,212,236,204, 49, 0, 47,236,
+244,236, 16,244,236, 48, 33, 17, 33, 53, 33, 17, 33, 50, 4, 21, 20, 4, 35, 1, 52, 39, 38, 35, 33, 17, 33, 50, 55, 54, 1,245,
+254, 61, 2,141, 1, 78,251, 1, 16,254,240,251, 1, 54, 79, 78,163,254,188, 1, 68,161, 80, 79, 5, 43,170,253,154,218,222,221,
+218, 1,183,139, 68, 67,253,221, 68, 67, 0, 0,255,255, 0,201, 0, 0, 6, 70, 5,213, 16, 39, 0, 44, 4,179, 0, 0, 17, 6,
+ 3, 73, 0, 0, 0, 13, 64, 6, 27, 4, 1, 28, 0, 21, 16,220,252,236, 49, 0, 0, 2, 0,201, 0, 0, 4,236, 5,213, 0, 10,
+ 0, 21, 0, 36, 64, 19, 5,149, 13,173, 11,129, 6,149, 21, 23, 0, 25, 17, 5, 12, 28, 11, 4, 22, 16,252,236, 50,212,236,204,
+ 49, 0, 47,236,228,244,236, 48, 1, 52, 39, 38, 35, 33, 17, 33, 50, 55, 54, 1, 51, 17, 33, 50, 4, 21, 20, 4, 35, 33, 4, 23,
+ 79, 78,163,254,188, 1, 68,163, 78, 79,252,178,202, 1, 78,251, 1, 16,254,240,251,253,232, 1,183,139, 68, 67,253,221, 68, 67,
+ 4,168,253,154,218,222,221,218, 0, 1, 0,111,255,227, 5, 35, 5,240, 0, 36, 0, 58, 64, 32, 1,149, 2,173, 37, 11,161, 12,
+174, 7,149, 16,145, 37, 29,161, 28,174, 33,149, 24,140, 37, 38, 0, 3, 25, 20, 2, 29, 12, 37, 16,220, 60,204,212,236, 50,204,
+ 49, 0, 16,244,236,244,236, 16,244,236,244,236, 16,244,236, 48, 1, 33, 53, 33, 38, 39, 38, 33, 34, 7, 6, 7, 53, 54, 55, 54,
+ 51, 32, 23, 22, 17, 16, 7, 6, 33, 34, 39, 38, 39, 53, 22, 23, 22, 51, 32, 55, 54, 4, 78,253, 70, 2,178, 25,103,136,255, 0,
+130,116,115,102,104,119,118,134, 1, 83,195,195,195,195,254,173,132,118,119,106,102,115,116,130, 1, 0,136,129, 2,199,170,198,
+119,156, 47, 47, 95,213, 71, 35, 36,208,207,254,152,254,153,208,207, 36, 36, 72,211, 95, 47, 47,157,147, 0, 0, 0, 2, 0,211,
+255,227, 7,204, 5,240, 0, 15, 0, 38, 0, 56, 64, 31, 0,149, 20,145, 39, 8,149, 28,140, 39, 33,149, 38,173, 36,129, 35, 40,
+ 12, 25, 24, 4, 25, 32, 16, 33, 37, 28, 36, 4, 39, 16,252,236, 50,212, 60,236,212,236,204, 49, 0, 47,228,244,236, 16,244,236,
+ 16,244,236, 48, 1, 34, 7, 6, 17, 16, 23, 22, 51, 50, 55, 54, 17, 16, 39, 38, 1, 18, 55, 54, 33, 32, 23, 22, 17, 16, 7, 6,
+ 33, 32, 39, 38, 3, 35, 17, 35, 17, 51, 17, 5, 26,220,130,129,129,130,220,220,128,129,129,128,252,119, 30,151,189, 1, 59, 1,
+ 58,188,188,188,188,254,198,254,197,189,179, 9,201,202,202, 5, 76,164,164,254,229,254,230,164,164,164,164, 1, 26, 1, 27,164,
+164,254, 37, 1, 5,168,210,210,211,254,158,254,159,210,211,210,200, 1, 74,253, 57, 5,213,253,156, 0, 0, 0, 0, 2, 0, 59,
+ 0, 0, 4,198, 5,213, 0, 19, 0, 28, 0, 69, 64, 22, 66, 21,149, 6,129, 16, 11,149, 27,173, 9, 16, 30, 4, 10, 20, 28, 7,
+ 24, 25, 3, 29, 16,212,236,212,236, 50,236, 49, 0, 47, 60,244,236, 16,244,236, 48, 75, 83, 88, 64, 13, 13, 12, 11, 3, 10, 14,
+ 17, 17, 15, 17, 16, 17, 16, 5, 7, 16,236, 16,236, 17, 23, 57, 89, 1, 46, 1, 53, 52, 54, 41, 1, 17, 35, 17, 35, 34, 6, 7,
+ 3, 35, 19, 62, 1, 1, 35, 34, 6, 21, 20, 22, 59, 1, 2, 2,125,131,252, 1, 0, 1,200,202,220,120,139, 74,191,217,205, 62,
+123, 2, 59,254,146,149,149,146,254, 2,188, 36,186,141,216,214,250, 43, 2,119, 98,150,254,129, 1,152,126,144, 2,137,133,131,
+131,135, 0, 0,255,255, 0,123,255,227, 4, 45, 4,123, 18, 6, 0, 68, 0, 0, 0, 2, 0,113,255,227, 4,117, 5,240, 0, 28,
+ 0, 45, 0, 73, 64, 40, 29, 22, 44,185, 6, 46, 0,134, 28,136, 2,185, 26, 46, 37,185, 14,140, 46, 29, 40, 22, 33, 4, 47, 69,
+ 28, 40, 18, 10, 81, 18, 4, 18, 24, 33, 18, 18, 69, 46, 16,252,236,212,236, 16,244,236,196,236, 17, 18, 57, 18, 57, 49, 0, 16,
+244,236, 16,212,236,244,236, 16,212,236, 57, 57, 48, 1, 38, 35, 34, 21, 20, 5, 22, 23, 22, 17, 16, 7, 6, 35, 34, 39, 38, 17,
+ 52, 55, 54, 55, 38, 53, 16, 33, 50, 23, 1, 6, 7, 6, 21, 20, 23, 22, 51, 50, 54, 53, 52, 39, 38, 39, 38, 3,236,102,239,253,
+ 1, 8,208,117,142,137,137,240,239,138,137,137, 53, 75,156, 1,185,221,120,254, 24, 68, 55, 86, 85, 86,149,147,172, 91, 97,126,
+ 64, 5, 17, 70,117, 92, 48, 37,112,135,254,235,254,247,156,157,157,156, 1, 19,204,165, 64, 36, 79,141, 1, 16, 70,254, 40, 29,
+ 73,113,204,203,114,115,232,190,199, 96,103, 11, 6, 0, 0, 0, 0, 3, 0,186, 0, 0, 4, 62, 4, 96, 0, 10, 0, 21, 0, 38,
+ 0, 45, 64, 24, 0,169, 12, 38, 11,169, 22,188, 1,169, 38, 17, 18, 26, 40, 6, 18, 33, 0, 11, 8, 22, 70, 39, 16,252,236, 50,
+212,236,204,212,236, 49, 0, 47,236,244,236, 16,212,236, 48, 1, 17, 33, 50, 55, 54, 53, 52, 39, 38, 35, 1, 17, 51, 50, 55, 54,
+ 53, 52, 39, 38, 35, 37, 33, 50, 22, 21, 20, 7, 6, 7, 30, 1, 21, 20, 7, 6, 35, 33, 1,114, 1, 6,129, 66, 63, 63, 69,126,
+254,250,242,117, 61, 58, 58, 61,117,254, 86, 1,182,197,212, 54, 54,106,127,140,116,115,214,254, 57, 2, 2,254,151, 46, 44, 91,
+ 94, 41, 45, 1,197,254,218, 38, 36, 75, 72, 36, 37,153,144,133,103, 60, 61, 15, 24,152,114,150, 82, 82, 0, 0, 0, 1, 0,186,
+ 0, 0, 3,208, 4, 96, 0, 5, 0, 25, 64, 12, 4,169, 1,188, 0, 7, 2, 4, 8, 1, 70, 6, 16,252,252,204,196, 49, 0, 47,
+244,236, 48, 51, 17, 33, 21, 33, 17,186, 3, 22,253,162, 4, 96,170,252, 74, 0, 0, 2, 0, 50,254, 86, 5, 46, 4, 96, 0, 7,
+ 0, 23, 0, 53, 64, 15, 2, 8, 14, 25, 19, 8, 16, 23, 3, 8, 13, 20, 8, 23, 24, 16,220,236,212,236, 16,212,236,204,212,236,
+ 49, 0, 64, 12, 3,169, 13,188, 18, 22,189, 15, 0, 23,169, 20, 47,236, 50, 50,236, 50,244,236, 48, 37, 33, 17, 33, 21, 16, 7,
+ 6, 5, 54, 55, 54, 17, 53, 33, 17, 51, 17, 35, 17, 33, 17, 35, 17, 1,166, 2, 24,254,123,118, 20,254,237, 91, 40, 98, 2,245,
+184,184,252,116,184,153, 3, 46,134,254,109,223, 17, 37, 40, 85,211, 1,163,212,252, 57,253,189, 1,170,254, 86, 2, 67, 0, 0,
+255,255, 0,113,255,227, 4,127, 4,123, 18, 6, 0, 72, 0, 0, 0, 1, 0, 50, 0, 0, 5,173, 4, 96, 0, 21, 0,109, 64, 21,
+ 66, 2, 20, 16,188, 14, 8, 12,169, 0, 18, 6, 10, 14, 23, 8, 21, 8, 11, 20, 22, 16,212, 60,252, 60,196, 49, 0, 47, 60, 60,
+212, 60,236, 50, 16,244, 60, 60, 48, 75, 83, 88, 64, 36, 4, 17, 7, 2, 1, 5, 17, 6, 7, 6, 4, 17, 1, 3, 17, 2, 2, 1,
+ 15, 17, 18, 13, 12, 16, 17, 17, 18, 17, 15, 17, 12, 14, 17, 13, 13, 12, 5, 7, 16,236, 16,236, 7, 16,236, 8, 16,236, 5, 7,
+ 16,236, 16,236, 7, 16,236, 8, 16,236, 89, 1, 51, 1, 51, 9, 1, 35, 1, 35, 17, 35, 17, 35, 1, 35, 9, 1, 51, 1, 51, 17,
+ 51, 3, 75,113, 1, 2,196,254,215, 1, 84,197,254,213,114,183,114,254,213,197, 1, 84,254,215,196, 1, 2,113,183, 2,161, 1,
+191,253,245,253,171, 2, 9,253,247, 2, 9,253,247, 2, 85, 2, 11,254, 65, 1,191, 0, 0, 0, 0, 1, 0,133,255,227, 3,200,
+ 4,124, 0, 49, 0, 60, 64, 33, 38,134, 39,136, 34,185, 42,184, 50, 24,169, 25, 50, 11,134, 10,136, 15,185, 6,140, 50, 30, 18,
+ 46, 51, 19, 18, 3, 25, 39, 11, 50, 16,220,196,196,212,236,204,212,236, 49, 0, 16,244,236,252,236, 16,212,236, 16,244,236,252,
+236, 48, 1, 30, 1, 21, 20, 4, 35, 34, 39, 38, 39, 53, 22, 23, 22, 51, 50, 55, 54, 53, 52, 39, 38, 43, 1, 53, 51, 50, 55, 54,
+ 53, 52, 39, 38, 35, 34, 7, 6, 7, 53, 62, 1, 51, 50, 23, 22, 21, 20, 7, 6, 2,194,124,138,254,254,238, 80, 85, 84, 90, 71,
+ 85, 85, 93,151, 85, 84, 78, 72,137,148,155,116, 67, 68, 70, 69,119, 71, 81, 80, 97, 98,170, 76,196,113,114, 60, 60, 2, 92, 24,
+146,108,173,182, 14, 14, 28,171, 37, 19, 18, 56, 56, 90, 88, 56, 51,152, 44, 45, 70, 64, 46, 46, 13, 13, 29,167, 24, 24, 78, 79,
+141, 93, 64, 65, 0, 1, 0,193, 0, 0, 4,128, 4, 96, 0, 9, 0, 63, 64, 21, 66, 8, 3, 9, 6,188, 2, 5, 11, 70, 9, 4,
+ 7, 3, 8, 0, 7, 8, 6, 70, 10, 16,252,236,212,236, 17, 57, 57,236, 49, 0, 47, 60,228, 50, 57, 57, 48, 75, 83, 88, 64, 10,
+ 3, 17, 9, 9, 8, 8, 17, 4, 4, 3, 7, 16,236, 7, 16,236, 89, 1, 17, 35, 17, 1, 35, 17, 51, 17, 1, 4,128,183,253,228,
+236,183, 2, 27, 4, 96,251,160, 3,131,252,125, 4, 96,252,127, 3,129, 0, 0,255,255, 0,193, 0, 0, 4,128, 6, 20, 16, 39,
+ 2, 49, 0,160,255,204, 18, 6, 3, 85, 0, 0, 0, 1, 0,191, 0, 0, 4,161, 4, 96, 0, 10, 0, 70, 64, 17, 66, 3, 0,188,
+ 7, 10, 12, 5, 1, 4, 6, 8, 1, 8, 0, 70, 11, 16,252,236, 50,212,196, 17, 57,196, 49, 0, 47, 60,228, 50, 48, 75, 83, 88,
+ 64, 16, 7, 17, 6, 8, 17, 5, 6, 5, 2, 17, 5, 3, 17, 4, 5, 4, 5, 7, 16,236, 4, 16,236, 7, 16,236, 5, 16,236, 89,
+ 19, 51, 17, 1, 51, 9, 1, 35, 1, 17, 35,191,185, 2, 37,235,253,174, 2,107,240,253,199,185, 4, 96,254, 29, 1,227,253,244,
+253,172, 2, 35,253,221, 0, 0, 0, 1, 0, 46,255,227, 4,115, 4, 96, 0, 15, 0, 38, 64, 20, 11,169, 6,188, 9, 1,169, 0,
+140, 9, 17, 70, 10, 8, 7, 11, 8, 6, 1, 16, 16,212,212,236,212,236,236, 49, 0, 47,244,236, 16,244,236, 48, 23, 53, 54, 55,
+ 54, 17, 53, 33, 17, 35, 17, 33, 21, 16, 3, 6, 46,179, 59, 98, 2,245,184,254,123,118, 94, 29,153, 27,127,207, 1,167,212,251,
+160, 3,199,134,254,146,254,252,207, 0, 0, 0, 0, 1, 0,193, 0, 0, 5, 72, 4, 96, 0, 12, 0, 77, 64, 22, 66, 10, 7, 2,
+ 3, 8, 3, 0,188, 9, 6, 12, 14, 70, 7, 8, 4, 10, 8, 0, 70, 13, 16,252,236,220,236,236, 49, 0, 47, 60,196,236, 50, 17,
+ 23, 57, 48, 75, 83, 88, 64, 18, 2, 17, 8, 10, 9, 3, 17, 7, 8, 7, 2, 17, 9, 1, 17, 10, 10, 9, 5, 7, 16,237, 16,237,
+ 7, 16,237, 8, 16,237, 89, 19, 33, 9, 1, 33, 17, 35, 17, 1, 35, 1, 17, 35,193, 1, 6, 1, 62, 1, 63, 1, 4,178,254,203,
+184,254,202,178, 4, 96,253, 18, 2,238,251,160, 3,176,253, 39, 2,217,252, 80, 0, 1, 0,193, 0, 0, 4,136, 4, 96, 0, 11,
+ 0, 39, 64, 20, 9,169, 2, 4, 0,188, 7, 11, 13, 70, 8, 4, 8, 5, 9, 1, 8, 0, 70, 12, 16,252,236, 50,220,236, 50,236,
+ 49, 0, 47, 60,228, 50,220,236, 48, 19, 51, 17, 33, 17, 51, 17, 35, 17, 33, 17, 35,193,184, 2, 87,184,184,253,169,184, 4, 96,
+254, 51, 1,205,251,160, 2, 4,253,252, 0, 0,255,255, 0,113,255,227, 4,117, 4,123, 18, 6, 0, 82, 0, 0, 0, 1, 0,193,
+ 0, 0, 4,136, 4, 96, 0, 7, 0, 40, 64, 16, 4,169, 7,188, 2, 6, 3, 8, 9, 70, 0, 4, 8, 7, 70, 8, 16,252,236,212,
+236,236, 49, 0, 47, 60,244,236, 48, 64, 5,160, 9,128, 9, 2, 1, 93, 1, 17, 35, 17, 33, 17, 35, 17, 4,136,184,253,169,184,
+ 4, 96,251,160, 3,198,252, 58, 4, 96, 0, 0,255,255, 0,186,254, 86, 4,164, 4,123, 18, 6, 0, 83, 0, 0,255,255, 0,113,
+255,227, 3,231, 4,123, 18, 6, 0, 70, 0, 0, 0, 1, 0, 5, 0, 0, 4, 54, 4, 96, 0, 7, 0, 37, 64, 13, 3, 7,169, 0,
+188, 5, 9, 1, 3, 8, 0, 6, 8, 16,212,204,252,204,204, 49, 0, 47,244,236, 50, 48, 64, 5,160, 9,128, 9, 2, 1, 93, 19,
+ 33, 21, 33, 17, 35, 17, 33, 5, 4, 49,254, 66,181,254, 66, 4, 96,170,252, 74, 3,182, 0, 0,255,255, 0, 61,254, 86, 4,127,
+ 4, 96, 18, 6, 0, 92, 0, 0, 0, 3, 0,113,254, 86, 6,228, 5,213, 0, 15, 0, 52, 0, 67, 0, 64, 64, 35, 57, 12,185, 39,
+ 28,184, 33,151, 68, 64, 4,185, 47, 21,140, 16,189, 68, 69, 69, 53, 18, 43, 17, 8, 33, 8, 51, 61, 34, 0, 18, 25, 69, 68, 16,
+252,236,212, 60, 60,252, 60, 60,212,236,236, 49, 0, 16,236,244, 60,236, 50, 16,228,244, 60,236, 50, 48, 1, 20, 23, 22, 51, 50,
+ 55, 54, 53, 52, 39, 38, 35, 34, 7, 6, 1, 17, 6, 7, 6, 35, 34, 39, 38, 17, 16, 18, 51, 50, 23, 22, 23, 17, 51, 17, 54, 55,
+ 54, 51, 50, 23, 22, 17, 16, 7, 6, 35, 34, 39, 38, 39, 17, 1, 52, 39, 38, 35, 34, 7, 6, 21, 20, 22, 51, 50, 55, 54, 1, 52,
+ 68, 67,133,133, 69, 68, 68, 69,133,133, 67, 68, 2, 26, 45, 77, 76,101,201,116,117,232,202,100, 77, 76, 46,185, 46, 77, 76,100,
+203,115,116,116,116,202,102, 76, 77, 44, 2, 28, 67, 68,133,134, 69, 69,138,134,133, 68, 67, 2, 47,214,109,109,109,110,213,213,
+110,109,109,109,251, 81, 2, 57, 83, 44, 45,155,156, 1, 17, 1, 22, 1, 58, 43, 44, 83, 2, 4,253,252, 83, 44, 43,157,157,254,
+234,254,239,156,155, 43, 44, 83,253,201, 3,217,214,109,109,109,110,213,212,220,109,109, 0, 0,255,255, 0, 59, 0, 0, 4,121,
+ 4, 96, 18, 6, 0, 91, 0, 0, 0, 1, 0,193,254, 86, 5, 64, 4, 96, 0, 11, 0, 40, 64, 21, 6, 2,188, 11,189, 8, 4,169,
+ 1, 13, 0, 8, 9, 6, 8, 7, 3, 8, 2, 70, 12, 16,252,236,212,236,212,236,204, 49, 0, 47,236, 50,236,244, 60, 48, 41, 1,
+ 17, 51, 17, 33, 17, 51, 17, 51, 17, 35, 4,136,252, 57,184, 2, 87,184,184,184, 4, 96,252, 57, 3,199,252, 57,253,189, 0, 0,
+ 0, 1, 0,150, 0, 0, 4, 0, 4, 96, 0, 17, 0, 34, 64, 17, 2,169, 13, 15, 7,188, 0, 19, 70, 1, 15, 8, 16, 8, 8, 7,
+ 18, 16,220,236,212,236, 50,236, 49, 0, 47,228, 50,212,236, 48, 33, 17, 33, 34, 39, 38, 61, 1, 51, 21, 20, 23, 22, 51, 33, 17,
+ 51, 17, 3, 72,254,169,153,102, 92,184, 52, 53,104, 1, 41,184, 2, 9, 95, 86,184,234,211,117, 59, 59, 1,190,251,160, 0, 0,
+ 0, 1, 0,193, 0, 0, 6, 58, 4, 96, 0, 11, 0, 40, 64, 21, 10, 2, 6,188, 0, 8,169, 5, 13, 70, 2, 8, 3, 10, 8, 11,
+ 7, 8, 6, 70, 12, 16,252,236,212,252,212,236,236, 49, 0, 47,236, 50,244, 60,196, 48, 37, 33, 17, 51, 17, 33, 17, 51, 17, 33,
+ 17, 51, 3,217, 1,169,184,250,135,184, 1,168,184,153, 3,199,251,160, 4, 96,252, 57, 3,140, 0, 1, 0,193,254, 86, 6,242,
+ 4, 96, 0, 15, 0, 49, 64, 26, 6, 10, 2,188, 15,189, 12, 8, 4,169, 1, 17, 0, 8, 13, 10, 8, 11, 6, 8, 7, 3, 8, 2,
+ 70, 16, 16,252,236,212,252,212,236,212,236,204, 49, 0, 47,236, 50, 50,236,244, 60,196, 48, 41, 1, 17, 51, 17, 33, 17, 51, 17,
+ 33, 17, 51, 17, 51, 17, 35, 6, 58,250,135,184, 1,168,184, 1,169,184,184,184, 4, 96,252, 57, 3,140,252,116, 3,199,252, 57,
+253,189, 0, 0, 0, 2, 0, 42, 0, 0, 5, 46, 4, 96, 0, 10, 0, 25, 0, 42, 64, 22, 12,169, 13,188, 25, 5,169, 15, 6,169,
+ 25, 27, 69, 0, 18, 20, 5, 14, 8, 11, 13, 26, 16,204,220,236, 50,212,236,236, 49, 0, 47,236,212,236, 16,244,236, 48, 1, 52,
+ 39, 38, 35, 33, 17, 33, 50, 55, 54, 1, 33, 53, 33, 17, 33, 50, 23, 22, 21, 20, 7, 6, 35, 33, 4,106, 62, 67,128,254,249, 1,
+ 7,129, 66, 62,253, 64,254,128, 2, 56, 1, 15,208,121,116,116,115,214,254, 57, 1, 76, 94, 42, 46,254,151, 46, 43, 2,212,154,
+254, 59, 85, 82,168,168, 82, 82,255,255, 0,193, 0, 0, 5,105, 4, 96, 16, 38, 3,105, 0, 0, 17, 7, 0,243, 3,240, 0, 0,
+ 0, 13, 64, 6, 29, 70, 25, 8, 24, 18, 16,220,252,236, 49, 0, 0, 2, 0,193, 0, 0, 4, 69, 4, 96, 0, 10, 0, 23, 0, 36,
+ 64, 19, 5,169, 13, 11,188, 6,169, 23, 25, 69, 0, 18, 18, 5, 12, 8, 11, 70, 24, 16,252,236, 50,212,236,236, 49, 0, 47,236,
+228,212,236, 48, 1, 52, 39, 38, 35, 33, 17, 33, 50, 55, 54, 1, 51, 17, 33, 50, 23, 22, 21, 20, 7, 6, 35, 33, 3,129, 62, 67,
+128,254,249, 1, 7,129, 66, 62,253, 64,184, 1, 15,208,121,116,116,115,214,254, 57, 1, 76, 94, 42, 46,254,151, 46, 43, 3,110,
+254, 59, 85, 82,168,168, 82, 82, 0, 1, 0,113,255,227, 3,231, 4,123, 0, 28, 0, 0, 1, 34, 7, 21, 54, 51, 50, 23, 22, 23,
+ 33, 21, 33, 6, 7, 6, 35, 34, 39, 21, 22, 51, 32, 55, 54, 17, 16, 39, 38, 1,180,166,157,161,154,230, 92, 34, 12,254, 52, 1,
+212, 13,158, 85,120,157,158,147,189, 1, 11,148,135,151,148, 4,123, 70,172, 86,180, 65, 87,143,244, 94, 51, 86,170, 72,172,157,
+ 1, 3, 1, 17,157,158, 0, 0, 0, 2, 0,193,255,227, 6, 16, 4,123, 0, 14, 0, 36, 0, 56, 64, 31, 0,185, 19,184, 37, 8,
+185, 26,140, 37, 31,169, 36, 34,188, 33, 38, 69, 11, 18, 22, 4, 18, 30, 15, 31, 35, 8, 34, 70, 37, 16,252,236, 50,212, 60,236,
+212,236,236, 49, 0, 47,228,212,236, 16,244,236, 16,244,236, 48, 1, 34, 7, 6, 21, 20, 23, 22, 51, 50, 54, 53, 52, 39, 38, 1,
+ 54, 55, 54, 51, 50, 0, 17, 16, 7, 6, 35, 34, 39, 38, 39, 35, 17, 35, 17, 51, 17, 4, 14,148, 86, 86, 85, 86,149,147,172, 86,
+ 86,253,113, 19,112,137,240,240, 1, 18,137,137,240,241,136,127, 9,148,184,184, 3,223,115,116,201,201,116,115,232,200,199,116,
+117,254,194,190,128,156,254,200,254,236,254,237,156,157,157,145,248,253,247, 4, 96,254, 65, 0, 0, 2, 0, 50, 0, 0, 4, 15,
+ 4, 96, 0, 22, 0, 33, 0, 68, 64, 21, 66, 24,169, 7,188, 18, 12,169, 32, 10, 18, 35, 70, 11, 23, 8, 8, 28, 18, 3, 34, 16,
+212,236,212,236, 50,236, 49, 0, 47, 60,212,236, 16,244,236, 48, 75, 83, 88, 64, 13, 15, 14, 13, 3, 12, 16, 17, 19, 17, 17, 18,
+ 19, 18, 5, 7, 16,236, 16,236, 17, 23, 57, 89, 1, 46, 1, 53, 52, 55, 54, 51, 33, 17, 35, 17, 35, 34, 7, 6, 7, 3, 35, 19,
+ 54, 55, 54, 1, 35, 34, 7, 6, 21, 20, 23, 22, 59, 1, 1,181,106,112,107,108,217, 1,132,185,169, 97, 59, 59, 63,162,195,174,
+ 53, 52, 53, 1,216,198,119, 63, 64, 64, 63,119,198, 2, 13, 27,140,105,162, 81, 80,251,160, 1,217, 37, 36,113,254,225, 1, 50,
+ 94, 54, 54, 1,201, 42, 42, 84, 83, 43, 43, 0,255,255, 0,113,255,227, 4,127, 6,107, 16, 38, 0, 67, 90, 5, 18, 6, 3, 82,
+ 0, 0, 0, 0,255,255, 0,113,255,227, 4,127, 6, 16, 16, 39, 0,106, 0,150, 0, 0, 18, 6, 3, 82, 0, 0, 0, 1, 0, 40,
+254, 86, 4,107, 6, 20, 0, 40, 0, 0, 19, 35, 53, 51, 53, 51, 21, 33, 21, 33, 17, 54, 55, 54, 51, 50, 23, 22, 21, 17, 20, 7,
+ 6, 43, 1, 53, 51, 50, 55, 54, 53, 17, 52, 38, 35, 34, 7, 6, 21, 17, 35,193,153,153,185, 1, 70,254,186, 66, 89, 90,117,185,
+107, 99, 82, 81,181, 70, 49,110, 33, 38,124,124,154, 81, 86,185, 5, 4,125,147,147,125,254, 87,101, 50, 50,119,110,242,253,159,
+214, 96, 96,156, 48, 55,147, 2, 91,159,158, 95,101,158,253,222,255,255, 0,186, 0, 0, 3,216, 6,109, 16, 39, 0,118, 0,134,
+ 0, 7, 18, 6, 3, 80, 0, 0, 0, 1, 0,113,255,227, 3,231, 4,123, 0, 28, 0, 58, 64, 33, 2,134, 3,136, 5, 19,134, 18,
+136, 16,185, 21, 10,169, 11,187, 5,185, 0,184, 21,140, 29, 10, 12, 9, 18, 18, 2, 72, 25, 69, 29, 16,252,228, 50,252, 50,204,
+ 49, 0, 16,228,244,236,244,238, 16,254,244,238, 16,245,238, 48, 1, 50, 23, 21, 38, 35, 34, 7, 6, 7, 33, 21, 33, 22, 23, 22,
+ 51, 50, 55, 21, 6, 35, 32, 39, 38, 17, 16, 55, 54, 2,164,166,157,161,154,230, 92, 34, 12, 1,204,254, 44, 13,158, 85,120,157,
+158,147,188,254,243,148,134,151,149, 4,123, 70,172, 86,180, 65, 87,143,244, 94, 51, 86,170, 72,173,157, 1, 2, 1, 17,157,158,
+255,255, 0,111,255,227, 3,199, 4,123, 18, 6, 0, 86, 0, 0,255,255, 0,193, 0, 0, 1,121, 6, 20, 18, 6, 0, 76, 0, 0,
+255,255,255,244, 0, 0, 2, 70, 6, 16, 18, 38, 0,243, 0, 0, 17, 7, 0,106,255, 29, 0, 0, 0, 8,180, 0, 10, 7, 1, 7,
+ 43, 49, 0, 0,255,255,255,219,254, 86, 1,121, 6, 20, 18, 6, 0, 77, 0, 0, 0, 2, 0, 46,255,227, 6,190, 4, 96, 0, 23,
+ 0, 34, 0, 0, 1, 33, 21, 16, 3, 6, 5, 53, 54, 55, 54, 17, 53, 33, 17, 51, 50, 23, 22, 16, 7, 6, 35, 33, 1, 52, 39, 38,
+ 43, 1, 17, 51, 50, 55, 54, 3,158,254,152,118, 94,254,204,179, 59, 98, 2,216,171,208,121,116,116,115,214,254,157, 2, 92, 62,
+ 67,128,163,163,129, 66, 62, 3,199,134,254,146,254,252,207, 29,153, 27,127,207, 1,167,212,254, 59, 85, 82,254,176, 82, 82, 1,
+ 76, 94, 42, 46,254,151, 46, 43, 0, 2, 0,193, 0, 0, 6,188, 4, 96, 0, 10, 0, 30, 0, 0, 1, 52, 39, 38, 43, 1, 17, 51,
+ 50, 55, 54, 5, 17, 33, 17, 35, 17, 51, 17, 33, 17, 51, 17, 51, 50, 23, 22, 16, 7, 6, 35, 5,248, 62, 66,129,163,163,129, 66,
+ 62,253,164,253,221,184,184, 2, 35,184,171,208,121,116,116,115,214, 1, 76, 95, 42, 45,254,151, 46, 43,242, 2, 2,253,254, 4,
+ 96,254, 59, 1,197,254, 59, 85, 82,254,176, 82, 82, 0, 0, 0, 0, 1, 0, 40, 0, 0, 4,107, 6, 20, 0, 30, 0, 0, 19, 35,
+ 53, 51, 53, 51, 21, 33, 21, 33, 17, 54, 55, 54, 51, 50, 23, 22, 21, 17, 35, 17, 52, 38, 35, 34, 7, 6, 21, 17, 35,193,153,153,
+185, 1, 70,254,186, 66, 89, 90,117,189,103, 99,184,124,124,152, 83, 86,185, 5, 4,125,147,147,125,254, 87,101, 50, 50,119,115,
+237,253,179, 2, 71,159,158, 95, 98,161,253,222,255,255, 0,191, 0, 0, 4,161, 6,109, 16, 39, 0,118, 0,228, 0, 7, 18, 6,
+ 3, 87, 0, 0,255,255, 0,193, 0, 0, 4,128, 6,107, 16, 38, 0, 67,100, 5, 18, 6, 3, 85, 0, 0, 0, 0,255,255, 0, 61,
+254, 86, 4,127, 6, 20, 16, 38, 2, 49, 94,204, 18, 6, 3, 96, 0, 0, 0, 0, 0, 1, 0,193,254, 86, 4,136, 4, 96, 0, 11,
+ 0, 0, 33, 17, 35, 17, 33, 17, 51, 17, 33, 17, 51, 17, 2,255,184,254,122,184, 2, 87,184,254, 86, 1,170, 4, 96,252, 58, 3,
+198,251,160, 0, 0, 1, 0,115,255,227, 7, 5, 5,213, 0, 52, 0, 0, 1, 22, 51, 50, 55, 54, 61, 1, 51, 21, 20, 23, 22, 51,
+ 50, 55, 54, 17, 52, 39, 2, 39, 51, 22, 23, 18, 21, 16, 7, 6, 35, 34, 39, 38, 39, 6, 7, 6, 35, 34, 39, 38, 17, 52, 19, 54,
+ 55, 51, 6, 3, 6, 21, 16, 1,146, 73,125,114, 72, 71,199, 70, 70,116,134, 65, 71, 67,135, 84,250, 95, 56,100,123,123,209,146,
+101,100, 39, 39,100,101,146,211,121,123,100, 59, 93,249, 84,135, 67, 1, 90,109,105,104,198,241,241,198,104,105,109,119, 1, 39,
+183,159, 1, 65, 70,130,156,254,231,190,254,102,178,177, 94, 94,173,173, 94, 94,177,180, 1,152,201, 1, 14,159,127, 70,254,191,
+159,183,254,205,255,255, 0,135,255,226, 6, 40, 4, 96, 16, 2, 2,231, 0, 0,255,255, 0, 33, 0, 0, 4,236, 5,213, 16, 2,
+ 3,168, 0, 0, 0, 2, 0, 58, 0, 0, 4, 69, 5,213, 0, 19, 0, 30, 0, 0, 1, 17, 33, 50, 23, 22, 16, 7, 6, 35, 33, 17,
+ 35, 53, 51, 17, 51, 17, 51, 21, 1, 52, 39, 38, 35, 33, 17, 33, 50, 55, 54, 1,121, 1, 15,208,121,116,116,115,214,254, 57,135,
+135,184,175, 1, 89, 62, 67,128,254,249, 1, 7,129, 66, 62, 3,209,254,202, 85, 82,254,176, 82, 82, 3,209,143, 1,117,254,139,
+143,253,123, 94, 42, 46,254,151, 46, 43, 0, 0, 0, 1, 0,211,255,227, 7, 27, 5,240, 0, 43, 0, 0, 1, 17, 35, 17, 51, 17,
+ 51, 18, 55, 54, 33, 50, 23, 22, 23, 21, 38, 39, 38, 35, 32, 7, 6, 7, 33, 21, 33, 18, 23, 22, 33, 50, 55, 54, 55, 21, 6, 7,
+ 6, 35, 32, 39, 38, 3, 1,157,202,202,210, 30,157,195, 1, 83,134,118,119,104,102,115,116,130,255, 0,136,103, 25, 2,178,253,
+ 70, 7,129,137, 0,255,130,116,115,102,106,119,118,132,254,173,195,186, 9, 2,199,253, 57, 5,213,253,156, 1, 8,167,208, 36,
+ 35, 71,213, 95, 47, 47,156,119,198,170,254,243,148,157, 47, 47, 95,211, 72, 36, 36,207,198, 1, 79, 0, 0, 0, 0, 1, 0,193,
+255,227, 5,129, 4,123, 0, 35, 0, 0, 1, 50, 23, 21, 38, 35, 34, 7, 6, 7, 33, 21, 33, 22, 23, 22, 51, 50, 55, 21, 6, 35,
+ 32, 39, 38, 39, 35, 17, 35, 17, 51, 17, 51, 54, 55, 54, 4, 62,166,157,161,154,230, 92, 34, 12, 1,204,254, 44, 13,158, 85,120,
+157,158,147,188,254,243,148,123, 10,147,184,184,152, 23,122,151, 4,123, 70,172, 86,180, 65, 87,143,244, 94, 51, 86,170, 72,173,
+144,228,253,252, 4, 96,254, 51,202,128,158, 0, 0, 2, 0, 16, 0, 0, 6,248, 5,213, 0, 3, 0, 15, 0, 0, 1, 11, 1, 31,
+ 1, 17, 35, 17, 39, 1, 35, 1, 51, 1, 35, 1, 4,106,230,231,231,102,202,222,254,175,225, 3, 2,229, 3, 1,225,254,175, 3,
+ 63, 1,192,254, 64,119,172,253,228, 2, 27,114,253,115, 5,213,250, 43, 2,142, 0, 2, 0, 51, 0, 0, 6, 17, 4, 96, 0, 3,
+ 0, 15, 0, 0, 1, 11, 1, 31, 1, 17, 35, 17, 39, 1, 35, 1, 51, 1, 35, 1, 3,226,192,192,192, 93,184,179,254,226,195, 2,
+142,195, 2,141,195,254,226, 2,112, 1, 74,254,182, 87,131,254,106, 1,149, 81,254, 26, 4, 96,251,160, 1,231, 0, 2, 0,201,
+ 0, 0, 9, 20, 5,213, 0, 3, 0, 23, 0, 0, 1, 11, 1, 23, 5, 33, 17, 35, 17, 51, 17, 33, 1, 51, 1, 35, 1, 7, 17, 35,
+ 17, 39, 1, 35, 6,134,230,231,231,253,251,253,248,202,202, 2, 95, 1, 60,229, 3, 1,225,254,175,220,202,222,254,175,225, 3,
+ 63, 1,192,254, 64,119, 1,253, 57, 5,213,253,156, 2,100,250, 43, 2,142,114,253,228, 2, 27,114,253,115, 0, 0, 2, 0,193,
+ 0, 0, 7,208, 4, 96, 0, 3, 0, 23, 0, 0, 1, 11, 1, 23, 5, 33, 17, 35, 17, 51, 17, 33, 1, 51, 1, 35, 1, 7, 17, 35,
+ 17, 39, 1, 35, 5,161,192,192,192,254, 45,254,107,184,184, 1,233, 1, 30,195, 2,141,195,254,226,177,184,179,254,226,195, 2,
+112, 1, 74,254,182, 87, 50,254, 25, 4, 96,254, 23, 1,233,251,160, 1,231, 81,254,106, 1,149, 81,254, 26, 0, 0, 2, 0,115,
+ 0, 0, 5,217, 5,213, 0, 23, 0, 26, 0, 0, 1, 17, 35, 17, 6, 7, 6, 17, 35, 16, 55, 54, 55, 1, 33, 1, 22, 23, 22, 17,
+ 35, 16, 39, 38, 39, 1, 33, 3,139,202,147,100,130,213,189,120,170,254, 81, 5, 18,254, 80,164,116,188,213,128, 96,248, 1, 62,
+253,131, 2, 89,253,167, 2, 89, 28,126,164,254,229, 1, 98,210,134, 49, 2,234,253, 19, 50,130,210,254,158, 1, 30,161,122,202,
+ 2, 40, 0, 0, 0, 2, 0,107, 0, 0, 4,123, 4, 96, 0, 2, 0, 26, 0, 0, 1, 33, 19, 9, 1, 22, 23, 22, 17, 35, 52, 39,
+ 38, 39, 17, 35, 17, 6, 7, 6, 21, 35, 16, 55, 54, 55, 1, 3, 69,254, 93,209, 2, 8,254,187,107, 75,137,195, 86, 58, 86,184,
+ 83, 56, 86,194,137, 74,108,254,187, 3,182,254,150, 2, 20,253,204, 38, 86,156,254,236,199,116, 79, 26,254, 92, 1,162, 26, 75,
+116,201, 1, 20,156, 85, 39, 2, 52, 0, 0, 0, 0, 2, 0,201, 0, 0, 7,196, 5,213, 0, 30, 0, 33, 0, 0, 9, 1, 33, 1,
+ 22, 23, 22, 17, 35, 16, 39, 38, 39, 17, 35, 17, 6, 7, 6, 17, 35, 16, 55, 54, 55, 33, 17, 35, 17, 51, 17, 5, 1, 33, 3,239,
+254,159, 5, 18,254, 80,164,116,188,213,128, 96,153,202,147,100,130,213,189, 85,110,253,181,202,202, 3,132, 1, 62,253,131, 3,
+113, 2,100,253, 19, 50,130,210,254,158, 1, 30,161,122, 32,253,167, 2, 89, 28,126,164,254,229, 1, 98,210, 95, 52,253, 57, 5,
+213,253,156,110, 2, 40, 0, 0, 0, 2, 0,193, 0, 0, 6, 46, 4, 96, 0, 30, 0, 33, 0, 0, 9, 1, 33, 1, 22, 23, 22, 17,
+ 35, 52, 39, 38, 39, 17, 35, 17, 6, 7, 6, 21, 35, 16, 55, 54, 55, 33, 17, 35, 17, 51, 17, 1, 33, 19, 3, 55,254,231, 4, 16,
+254,187,107, 75,137,195, 86, 58, 86,184, 83, 56, 86,194,137, 27, 31,254,146,184,184, 3,127,254, 93,209, 2,119, 1,233,253,204,
+ 38, 86,156,254,236,199,116, 79, 26,254, 92, 1,162, 26, 75,116,201, 1, 20,156, 31, 24,254, 25, 4, 96,254, 23, 1, 63,254,150,
+ 0, 1, 0,115,254, 86, 4,115, 5,240, 0, 75, 0, 0, 5, 50, 23, 22, 23, 21, 38, 39, 38, 35, 32, 39, 38, 53, 52, 55, 54, 51,
+ 50, 23, 22, 51, 50, 55, 54, 53, 52, 39, 38, 43, 1, 53, 51, 50, 55, 54, 53, 52, 39, 38, 35, 34, 6, 7, 53, 54, 55, 54, 51, 50,
+ 23, 22, 21, 20, 7, 6, 7, 22, 23, 22, 21, 20, 7, 6, 35, 34, 39, 38, 35, 34, 7, 6, 21, 20, 23, 22, 2,187, 60, 91, 96, 86,
+ 71,103,134, 25,254,205,114,163, 63, 71, 99, 46,132, 73,100, 91, 85, 63, 92, 91,167,174,182,149, 79, 79, 81, 82,152, 83,190,114,
+115,100,101, 89,230,134,134, 71, 71,131,147, 80, 81,115,152,198, 86, 76, 85, 42, 40, 32, 24,117, 94,209, 6, 6, 38,167, 41, 8,
+ 10, 67, 96,147,144, 72, 81, 45, 25, 90, 65,121,122, 74, 73,166, 59, 60,112,115, 61, 62, 36, 38,180, 32, 16, 16,104,105,178,124,
+ 85, 86, 33, 31, 96, 98,134,208,102,136, 36, 42, 36, 27, 67, 87, 39, 32, 0, 0, 0, 2, 0, 91,254,116, 3,200, 6,102, 0, 73,
+ 0, 80, 0, 0, 37, 50, 55, 54, 53, 52, 39, 38, 43, 1, 53, 51, 50, 55, 54, 53, 52, 39, 38, 35, 34, 7, 6, 7, 53, 62, 1, 51,
+ 50, 23, 22, 21, 20, 7, 6, 7, 30, 1, 21, 20, 6, 39, 38, 39, 38, 35, 34, 7, 6, 21, 20, 23, 22, 51, 50, 23, 22, 23, 21, 38,
+ 39, 38, 35, 32, 39, 38, 53, 52, 55, 54, 51, 50, 23, 22, 11, 1, 51, 23, 55, 51, 3, 2, 75, 87, 59, 54, 78, 72,137,148,155,116,
+ 67, 68, 70, 69,119, 71, 81, 80, 97, 98,170, 76,196,113,114, 60, 60,112,124,138,238,168, 78, 59, 75, 32, 36, 25, 19, 98,106,140,
+ 82, 46, 93, 59, 59, 88,132, 1,254,254, 96,137, 52, 58, 86, 51,103, 62, 62,245,139,180,180,139,245,153, 49, 45, 91, 76, 56, 51,
+152, 44, 45, 70, 64, 46, 46, 13, 13, 29,167, 24, 24, 78, 79,141, 93, 64, 65, 24, 24,146, 96,161,182, 5, 2, 28, 35, 30, 23, 76,
+ 99, 25, 27, 5, 11, 26,139, 34, 6, 9, 56, 81,152,141, 59, 68, 36, 21, 4, 85, 1,120,245,245,254,136, 0, 0,255,255, 0,115,
+ 0, 0, 5,219, 5,213, 18, 2, 2,198, 0, 0,255,255, 0,112,254, 86, 4,209, 4, 96, 18, 2, 2,230, 0, 0, 0, 3, 0,115,
+255,227, 5,217, 5,240, 0, 9, 0, 20, 0, 35, 0, 0, 1, 5, 39, 5, 18, 23, 22, 32, 55, 54, 17, 38, 39, 38, 35, 34, 7, 6,
+ 7, 37, 23, 3, 32, 23, 22, 17, 16, 7, 6, 33, 32, 39, 38, 16, 55, 54, 5, 4,254,104,230,254,194, 8,122,129, 1,184,129,120,
+ 25, 95,129,220,218,131, 98, 24, 1,144,230,159, 1, 58,188,188,188,188,254,198,254,197,188,189,189,188, 2,199,110,200, 90,254,
+255,155,164,164,152, 1,174,189,122,164,164,123,188,110,200, 2,217,210,211,254,158,254,159,210,211,210,210, 2,196,211,210, 0,
+ 0, 3, 0,113,255,227, 4,117, 4,123, 0, 10, 0, 21, 0, 36, 0, 0, 1, 37, 23, 55, 38, 39, 38, 35, 34, 7, 6, 3, 22, 23,
+ 22, 51, 50, 55, 54, 55, 5, 39, 19, 50, 0, 17, 16, 7, 6, 35, 34, 39, 38, 17, 16, 55, 54, 1, 57, 1, 7,150,213, 17, 62, 86,
+147,149, 85, 63, 22, 8, 76, 86,149,147, 86, 76, 9,254,243,150,101,240, 1, 18,137,137,240,241,136,137,137,136, 2,148, 70,120,
+ 50,129, 85,117,115, 85,254,237,173,101,115,116,103,170, 70,130, 2, 59,254,200,254,236,254,237,156,157,157,156, 1, 19, 1, 20,
+156,156, 0, 0, 0, 1, 0, 16, 0, 0, 6, 39, 5,240, 0, 20, 0, 0, 33, 35, 1, 51, 9, 1, 18, 55, 54, 51, 50, 22, 23, 21,
+ 39, 38, 35, 34, 7, 6, 7, 3, 47,229,253,198,211, 1,217, 1, 56,115, 96, 78,148, 31, 62, 33, 68, 22, 25, 73, 34, 71, 84, 5,
+213,251, 23, 3, 61, 1, 50, 82, 67, 10, 11,187, 10, 4, 34, 67,221, 0, 0, 0, 0, 1, 0, 50, 0, 0, 5, 31, 4,123, 0, 21,
+ 1, 56, 64, 5, 23, 8, 4, 19, 22, 16, 75,176, 10, 84, 88,185, 0, 19, 0, 64, 56, 89, 75,176, 20, 84, 75,176, 21, 84, 91, 88,
+185, 0, 19,255,192, 56, 89,212,212,196,196,180, 21, 17, 18, 4, 19, 17, 18, 57, 57, 57, 49, 64, 10, 9,134, 8, 12,185, 4,184,
+ 19,188, 18, 0, 47,228,244,228,212,236, 48,182, 21, 17, 20, 17, 19, 19, 18, 7, 5, 16,236, 4,236,183, 3, 2, 1, 0, 17, 16,
+ 16, 17, 7, 5, 16,236, 50, 50, 50, 64, 26, 12, 15, 15, 9, 15, 8, 11, 16, 10, 3, 10, 2, 12, 1, 10, 0, 8, 21, 9, 17, 8,
+ 18, 8, 20, 7, 19, 64, 16, 25, 16, 25, 0, 31, 22, 26, 17, 29, 18, 28, 21, 29, 20, 29, 19, 64, 12, 43, 1, 41, 16, 41, 0, 40,
+ 21, 38, 20, 38, 19, 64, 18, 51, 15, 52, 1, 50, 16, 51, 0, 54, 21, 54, 20, 54, 19, 55, 17, 52, 18, 64, 24, 74, 2, 74, 16, 74,
+ 0, 77, 1, 72, 21, 70, 19, 70, 20, 70, 17, 74, 18, 79, 9, 79, 8, 79, 23, 64, 28, 90, 2, 92, 1, 91, 16, 91, 0, 95, 22, 93,
+ 21, 94, 20, 95, 19, 94, 18, 90, 17, 90, 15, 95, 23, 95, 9, 95, 8, 64, 26,107, 15,107, 2,105, 1,111, 1,106, 16,106, 0,105,
+ 21,102, 20,102, 19,105, 18,111, 9,111, 8,111, 23, 64, 18,124, 2,127, 1,122, 16,122, 21,122, 0,119, 17,124, 18,117, 20,118,
+ 19,176, 84, 1, 93, 64, 17, 6, 21, 25, 21, 39, 21, 54, 21, 74, 21, 91, 21,106, 21,127, 21, 8, 0, 93, 1, 54, 55, 54, 51, 50,
+ 23, 22, 23, 21, 39, 38, 35, 34, 7, 6, 7, 1, 35, 1, 51, 1, 3, 59, 80,102, 66,129, 26, 26, 27, 28, 58, 19, 21, 54, 29, 65,
+ 61,254,228,250,254, 92,195, 1, 94, 3, 36,213, 79, 51, 4, 4, 8,141, 7, 3, 25, 55,162,253, 10, 4, 96,252, 84, 0, 0, 0,
+ 0, 3, 0, 16, 0, 0, 6, 39, 7,108, 0, 3, 0, 7, 0, 28, 0, 0, 1, 19, 35, 3, 37, 19, 35, 3, 19, 35, 1, 51, 9, 1,
+ 18, 55, 54, 51, 50, 22, 23, 21, 39, 38, 35, 34, 7, 6, 7, 1,253,144,135,174, 1,238,134,137,157,137,229,253,198,211, 1,217,
+ 1, 56,115, 96, 78,148, 31, 62, 33, 68, 22, 25, 73, 34, 71, 84, 7,107,254,248, 1, 8, 1,254,247, 1, 9,248,148, 5,213,251,
+ 23, 3, 61, 1, 50, 82, 67, 10, 11,187, 10, 4, 34, 67,221, 0,255,255, 0, 50, 0, 0, 5, 31, 6,102, 16, 35, 2, 87, 4,194,
+ 0, 0, 18, 2, 3,146, 0, 0,255,255, 0,113,255,227, 5, 37, 5,240, 16, 2, 1,228, 0, 0,255,255, 0,113,255,227, 4,113,
+ 5, 47, 16, 2, 1,229, 0, 0, 0, 2, 0,115,255,227, 7, 45, 5,240, 0, 41, 0, 82, 0, 0, 37, 51, 50, 55, 54, 53, 52, 39,
+ 38, 43, 1, 6, 7, 6, 7, 6, 34, 39, 38, 39, 38, 39, 35, 34, 7, 6, 21, 20, 23, 22, 59, 1, 54, 55, 54, 55, 54, 50, 23, 22,
+ 23, 22, 7, 35, 32, 39, 38, 16, 55, 54, 33, 51, 54, 55, 54, 55, 54, 50, 23, 22, 23, 22, 23, 51, 32, 23, 22, 17, 16, 7, 6, 33,
+ 35, 6, 7, 6, 7, 6, 34, 39, 38, 39, 38, 4, 93, 30,235,114,128,128,114,235, 30, 11, 15, 22, 27, 26, 62, 26, 27, 22, 16, 10,
+ 46,235,114,130,130,114,235, 46, 10, 16, 22, 27, 26, 62, 26, 27, 22, 16,254, 46,254,161,152,189,189,152, 1, 95, 45, 11, 16, 22,
+ 27, 26, 62, 26, 31, 18, 16, 11, 29, 1, 94,152,188,188,152,254,162, 29, 10, 17, 22, 27, 26, 62, 26, 31, 18, 16,194,145,164,242,
+243,164,145, 20, 14, 21, 12, 11, 11, 12, 21, 16, 18,145,164,243,242,164,145, 18, 16, 21, 12, 11, 11, 12, 21, 16,161,170,210, 2,
+116,211,170, 21, 15, 21, 12, 11, 11, 14, 19, 17, 19,170,211,254,198,254,199,210,171, 19, 17, 21, 12, 11, 11, 14, 19, 17, 0, 0,
+ 0, 2, 0,113,255,227, 5,161, 4,123, 0, 38, 0, 80, 0, 0, 37, 51, 50, 55, 54, 53, 52, 39, 38, 43, 1, 6, 7, 14, 1, 34,
+ 38, 39, 38, 39, 35, 34, 7, 6, 21, 20, 23, 22, 59, 1, 54, 55, 62, 1, 50, 23, 22, 23, 22, 7, 35, 32, 39, 38, 53, 52, 55, 54,
+ 33, 51, 54, 55, 54, 55, 54, 50, 23, 22, 23, 22, 23, 51, 32, 23, 22, 21, 20, 7, 6, 33, 35, 6, 7, 6, 7, 6, 34, 39, 38, 39,
+ 38, 3,114, 45,161, 72, 86, 86, 63,170, 45, 7, 10, 18, 44, 52, 44, 18, 10, 7, 45,163, 71, 86, 85, 72,163, 45, 7, 10, 18, 44,
+ 52, 22, 27, 13, 9,201, 46,254,255,120,137,137,116, 1, 5, 46, 7, 9, 13, 27, 22, 52, 22, 27, 13, 9, 7, 46, 1, 2,119,137,
+137,116,254,251, 46, 7, 9, 13, 27, 22, 52, 22, 27, 13, 9,164, 96,116,183,167,131, 97, 11, 10, 17, 20, 20, 17, 10, 11, 95,116,
+184,188,112, 95, 11, 10, 17, 20, 10, 12, 15, 10,147,137,156,238,233,162,136, 10, 10, 15, 12, 10, 10, 12, 15, 10, 10,136,156,239,
+232,162,137, 10, 10, 15, 12, 10, 10, 12, 15, 10,255,255, 0,115,255,227, 7, 5, 7,183, 16, 35, 3,160, 6, 44, 1, 61, 16, 2,
+ 3,125, 0, 0,255,255, 0,135,255,226, 6, 40, 6,100, 16, 35, 3,160, 5,196,255,234, 16, 2, 3,126, 0, 0, 0, 2, 0,115,
+255,227, 7, 5, 7, 51, 0, 11, 0, 64, 0, 0, 1, 7, 35, 39, 35, 7, 35, 39, 35, 7, 35, 39, 3, 22, 51, 50, 55, 54, 61, 1,
+ 51, 21, 20, 23, 22, 51, 50, 55, 54, 17, 52, 39, 2, 39, 51, 22, 23, 18, 21, 16, 7, 6, 35, 34, 39, 38, 39, 6, 7, 6, 35, 34,
+ 39, 38, 17, 52, 19, 54, 55, 51, 6, 3, 6, 21, 16, 5,126,100, 50, 50,175, 50, 50, 50,175, 50, 50,100,104, 73,125,114, 72, 71,
+199, 70, 70,116,134, 65, 71, 67,135, 84,250, 95, 56,100,123,123,209,146,101,100, 39, 39,100,101,146,211,121,123,100, 59, 93,249,
+ 84,135, 67, 7, 51,200,100,100,100,100,200,250, 39,109,105,104,198,241,241,198,104,105,109,119, 1, 39,183,159, 1, 65, 70,130,
+156,254,231,190,254,102,178,177, 94, 94,173,173, 94, 94,177,180, 1,152,201, 1, 14,159,127, 70,254,191,159,183,254,205, 0, 0,
+ 0, 2, 0,135,255,226, 6, 40, 5,224, 0, 11, 0, 38, 0, 0, 1, 7, 35, 39, 35, 7, 35, 39, 35, 7, 35, 39, 19, 32, 17, 52,
+ 19, 51, 2, 21, 2, 51, 50, 3, 51, 2, 55, 54, 17, 52, 3, 51, 18, 21, 18, 37, 36, 3, 2, 5, 27,100, 50, 50,175, 50, 50, 50,
+175, 50, 50,100,143,254, 97,155,198,143, 1,223,207, 4,170, 4,207,222,143,198,155, 2,254, 95,254,241, 34, 41, 5,224,200,100,
+100,100,100,200,250, 3, 2, 82,235, 1, 64,254,192,240,254, 79, 2, 26,253,227, 3, 2, 1,175,240, 1, 64,254,192,235,253,173,
+ 1, 1, 1, 42,254,213, 0, 0, 0, 1, 0,115,254, 86, 5, 39, 5,240, 0, 25, 0, 0, 33, 35, 32, 39, 38, 17, 16, 0, 33, 50,
+ 22, 23, 21, 46, 1, 35, 32, 0, 17, 16, 23, 22, 51, 33, 17, 35, 3,250,174,254,165,187,195, 1,134, 1, 83,134,237,104,102,231,
+130,255, 0,254,240,136,152,240, 1,107,201,198,208, 1, 83, 1,104, 1,159, 71, 71,213, 95, 94,254,199,254,216,254,211,130,148,
+253,176, 0, 0, 0, 1, 0,113,254, 86, 3,231, 4,123, 0, 24, 0, 0, 33, 32, 39, 38, 53, 16, 0, 33, 50, 22, 23, 21, 46, 1,
+ 35, 34, 6, 21, 20, 22, 59, 1, 17, 35, 17, 2,152,254,251,141,149, 1, 45, 1, 6, 85,162, 76, 78,157, 80,179,198,198,179,245,
+201,150,159,250, 1, 18, 1, 58, 35, 35,172, 43, 43,227,205,185,227,253,195, 1,170, 0, 0, 0, 0, 1, 0, 50, 0, 52, 4,142,
+ 5,188, 0, 27, 0, 0, 1, 55, 39, 55, 23, 55, 23, 7, 23, 7, 39, 7, 23, 7, 39, 7, 23, 7, 39, 7, 39, 55, 39, 55, 23, 55,
+ 39, 55, 2, 59,105,216,100,216,125,174,125,216,100,216,105,216,100,216,105,216,100,216,125,174,125,216,100,216,105,216,100, 3,
+129,181,125,174,125,216,100,216,125,174,125,181,125,174,125,181,125,174,125,216,100,216,125,174,125,181,125,174, 0, 1,251,218,
+ 4,222,255, 66, 6,122, 0, 47, 0, 0, 1, 33, 20, 7, 6, 7, 6, 7, 6, 34, 39, 38, 39, 38, 39, 38, 53, 52, 55, 54, 55, 54,
+ 55, 54, 51, 33, 52, 55, 54, 55, 54, 55, 54, 50, 23, 22, 23, 22, 23, 22, 21, 20, 7, 6, 7, 6, 7, 6,254,185,254, 51, 10, 11,
+ 19, 20, 25, 24, 56, 24, 25, 20, 19, 11, 10, 10, 11, 19, 20, 25, 24, 28, 1,205, 10, 11, 19, 20, 25, 24, 56, 24, 25, 20, 20, 10,
+ 10, 10, 11, 19, 20, 25, 24, 5,103, 27, 25, 27, 18, 19, 11, 10, 10, 11, 19, 18, 27, 25, 27, 28, 25, 27, 18, 19, 11, 10, 27, 25,
+ 27, 18, 19, 11, 10, 10, 11, 19, 21, 24, 25, 28, 27, 25, 27, 18, 19, 11, 10, 0, 0, 1,251,247, 5, 41,254,249, 6, 77, 0, 17,
+ 0, 0, 1, 54, 51, 50, 23, 22, 23, 51, 38, 39, 38, 35, 34, 7, 6, 7, 21, 54,253, 18, 93, 91, 70, 56, 48, 11,118, 10, 79, 86,
+138,124,120, 72,141,138, 5,149, 47, 42, 36, 77,143, 72, 77, 67, 41, 40,134, 23, 0, 1,252, 34, 4,227,254,248, 6,117, 0, 7,
+ 0, 0, 1, 21, 33, 21, 35, 17, 51, 21,254,248,253,192,150,150, 5,247,150,126, 1,146,126, 0, 0, 1,252, 34, 4,227,254,248,
+ 6,117, 0, 7, 0, 0, 1, 33, 53, 51, 17, 35, 53, 33,252, 34, 2, 64,150,150,253,192, 5,247,126,254,110,126,255,255,247,214,
+254,144, 3, 70, 7, 96, 16, 43, 2, 49,255,142, 4,216,192, 0, 16, 43, 2, 49,251, 15, 8,177,192, 0, 16, 43, 2, 49, 4, 13,
+ 8,177,192, 0, 16, 43, 2, 49,252, 96, 5,249,192, 0, 16, 43, 2, 49, 2,188, 5,249,192, 0, 16, 43, 2, 49,252, 96, 11,105,
+192, 0, 16, 43, 2, 49, 2,188, 11,105,192, 0, 16, 11, 2, 49,255,142, 12,137,192, 0, 0, 0, 0, 8,248, 88,253,195, 2,194,
+ 8, 45, 0, 5, 0, 11, 0, 17, 0, 23, 0, 29, 0, 35, 0, 41, 0, 47, 0, 0, 39, 55, 23, 19, 7, 3, 1, 7, 39, 3, 55, 19,
+ 1, 39, 55, 37, 23, 5, 1, 23, 7, 5, 39, 37, 1, 53, 51, 5, 21, 45, 1, 21, 35, 37, 53, 5, 1, 35, 53, 19, 51, 11, 1, 51,
+ 21, 3, 35, 19,107,150,121,111, 92,169,251,119,150,121,111, 92,169, 5, 31,150,122, 1, 86, 92,254,227,250, 76,149,121,254,169,
+ 91, 1, 28, 6, 96,172, 1, 64,254,192,248,194,172,254,192, 1, 64, 4, 95,211,164,129, 82,211,211,164,129, 82, 90,150,121,254,
+169, 92, 1, 29, 5,181,150,121, 1, 87, 92,254,227,254,241,149,122,110, 91,169,251,119,150,121,111, 92,168, 2, 24,212,164,130,
+ 82,212,212,164,130, 82, 2,223,172, 1, 64,254,192,248,194,172,254,192, 1, 64, 0, 1, 0,201,254, 86, 5,252, 5,213, 0, 14,
+ 0, 0, 33, 35, 17, 1, 33, 17, 51, 17, 1, 33, 17, 51, 21, 1, 35, 5, 51,196,253,106,254,240,196, 2,150, 1, 16,201,254,146,
+134, 4,225,251, 31, 5,213,251, 31, 4,225,250,213,170,254, 86, 0, 2, 0,193,254, 86, 5, 56, 6, 20, 0, 14, 0, 28, 0, 0,
+ 33, 35, 17, 1, 35, 17, 51, 17, 1, 51, 17, 51, 21, 1, 35, 1, 51, 30, 1, 51, 50, 54, 55, 51, 14, 1, 35, 34, 38, 4,128,183,
+253,228,236,183, 2, 27,237,184,254,222,123,253,205,118, 10, 98, 86, 86, 96, 14,118, 10,158,146,144,158, 3,131,252,125, 4, 96,
+252,127, 3,129,252, 57,153,254, 86, 7,190, 75, 75, 74, 76,143,144,144, 0, 0, 0, 2, 0, 33, 0, 0, 4,236, 5,213, 0, 18,
+ 0, 29, 0, 0, 1, 21, 33, 50, 4, 21, 20, 4, 35, 33, 17, 35, 53, 51, 53, 51, 21, 51, 21, 1, 52, 39, 38, 35, 33, 17, 33, 50,
+ 55, 54, 1,147, 1, 78,251, 1, 16,254,240,251,253,232,168,168,202,168, 1,220, 79, 78,163,254,188, 1, 68,163, 78, 79, 4, 81,
+226,218,222,221,218, 4, 81,164,224,224,164,253,102,139, 68, 67,253,221, 68, 67, 0, 2, 0, 38, 0, 0, 4, 69, 5,158, 0, 10,
+ 0, 30, 0, 0, 1, 52, 39, 38, 35, 33, 17, 33, 50, 55, 54, 1, 17, 33, 50, 23, 22, 16, 7, 6, 35, 33, 17, 35, 53, 51, 17, 51,
+ 17, 51, 21, 3,129, 62, 67,128,254,249, 1, 7,129, 66, 62,253,248, 1, 15,208,121,116,116,115,214,254, 57,155,155,184,157, 1,
+ 76, 94, 42, 46,254,151, 46, 43, 2,223,254,202, 85, 82,254,176, 82, 82, 3,209,143, 1, 62,254,194,143, 0, 0, 0, 2, 0,201,
+ 0, 0, 4,225, 5,213, 0, 14, 0, 27, 0, 0, 1, 23, 7, 39, 6, 43, 1, 17, 35, 17, 33, 50, 4, 21, 20, 39, 54, 55, 52, 38,
+ 43, 1, 17, 51, 50, 55, 39, 55, 4, 85,140,106,146,126,214,254,202, 1,200,251, 1, 1,226, 12, 1,154,141,254,254,114, 71,215,
+106, 3, 35,117,126,123, 83,253,168, 5,213,227,219,146, 45, 44, 57,134,146,253,207, 47,180,126, 0, 2, 0,186,254, 86, 4,164,
+ 4,123, 0, 13, 0, 35, 0, 0, 37, 39, 55, 23, 54, 53, 52, 38, 32, 6, 16, 22, 51, 50, 5, 23, 7, 39, 6, 35, 34, 38, 39, 17,
+ 35, 17, 51, 21, 62, 1, 51, 50, 0, 16, 7, 6, 3, 42,140,110,138, 79,167,254,220,167,167,146, 70, 1, 27,147,111,149, 87,108,
+123,177, 58,185,185, 58,177,123,204, 0,255,128, 12,152,167, 93,165,115,197,203,231,231,254,106,231, 20,174, 93,179, 46, 97,100,
+253,174, 6, 10,170,100, 97,254,188,253,240,162, 15, 0, 0, 0, 0, 1, 0,201, 0, 0, 4,106, 7, 7, 0, 7, 0, 27, 64, 13,
+ 3, 6,149, 1,129, 0, 3, 4, 6, 28, 1, 4, 8, 16,252,252,220,204, 49, 0, 47,244,236,204, 48, 51, 17, 33, 17, 51, 17, 33,
+ 17,201, 2,216,201,253, 41, 5,213, 1, 50,254, 36,250,213, 0, 0, 1, 0,186, 0, 0, 3,208, 5,154, 0, 7, 0, 27, 64, 13,
+ 3, 6,169, 1,188, 0, 3, 4, 6, 8, 1, 70, 8, 16,252,252,220,204, 49, 0, 47,244,236,204, 48, 51, 17, 33, 17, 51, 17, 33,
+ 17,186, 2, 94,184,253,162, 4, 96, 1, 58,254, 28,252, 74, 0, 0, 1, 0, 71, 0, 0, 4,106, 5,213, 0, 13, 0, 0, 19, 51,
+ 17, 33, 21, 33, 17, 33, 21, 33, 17, 35, 17, 35, 71,130, 3,161,253, 41, 2, 35,253,221,202,130, 3,232, 1,237,170,254,189,170,
+252,194, 3, 62, 0, 1, 0, 56, 0, 0, 3,208, 4, 96, 0, 13, 0, 0, 51, 17, 35, 53, 51, 17, 33, 21, 33, 17, 33, 21, 33, 17,
+186,130,130, 3, 22,253,162, 1,160,254, 96, 1,244,170, 1,194,170,254,232,170,254, 12, 0, 0, 0, 1, 0,201,254,102, 4,204,
+ 5,213, 0, 27, 0, 0, 1, 17, 35, 17, 33, 21, 33, 17, 33, 50, 23, 22, 21, 17, 16, 6, 43, 1, 53, 51, 50, 55, 54, 53, 17, 52,
+ 38, 35, 1,147,202, 3,161,253, 41, 1,161,186,113,109,204,228, 76, 62,134, 56, 55,124,124, 2,199,253, 57, 5,213,170,254, 70,
+119,114,238,254,206,254,242,244,170, 75, 75,194, 1, 34,159,158, 0, 1, 0,186,254, 86, 4, 11, 4, 96, 0, 29, 0, 0, 1, 17,
+ 35, 17, 33, 21, 33, 17, 51, 32, 23, 22, 21, 17, 20, 7, 6, 43, 1, 53, 51, 50, 55, 54, 53, 17, 52, 39, 38, 35, 1,114,184, 3,
+ 22,253,162,250, 1, 7, 70, 82, 82, 81,181,193,172,110, 33, 38, 38, 49,134, 1,231,254, 25, 4, 96,170,254,193, 71, 81,229,254,
+242,214, 96, 96,156, 48, 55,147, 1, 8,170, 32, 41, 0, 0, 0, 0, 1, 0, 59,254, 86, 6,194, 5,213, 0, 25, 0, 0, 37, 51,
+ 17, 35, 17, 35, 1, 35, 17, 35, 17, 35, 1, 35, 9, 1, 51, 1, 51, 17, 51, 17, 51, 1, 51, 1, 6, 87,107,197, 41,254,155,150,
+202,150,254,155,217, 1,144,254,162,217, 1, 52,149,202,149, 1, 52,217,254,162,170,253,172, 1,170, 2,199,253, 57, 2,199,253,
+ 57, 3, 28, 2,185,253,156, 2,100,253,156, 2,100,253, 71, 0, 0, 1, 0, 50,254, 86, 5,193, 4, 96, 0, 25, 0, 0, 37, 51,
+ 17, 35, 17, 35, 1, 35, 17, 35, 17, 35, 1, 35, 9, 1, 51, 1, 51, 17, 51, 17, 51, 1, 51, 1, 5, 85,108,184, 33,254,213,114,
+183,114,254,213,197, 1, 84,254,215,196, 1, 2,113,183,113, 1, 2,196,254,215,153,253,189, 1,170, 2, 9,253,247, 2, 9,253,
+247, 2, 85, 2, 11,254, 65, 1,191,254, 65, 1,191,253,245, 0,255,255, 0,156,254,117, 4,115, 5,240, 16, 38, 0,122, 57, 0,
+ 16, 6, 3, 52, 0, 0, 0, 0,255,255, 0,133,254,117, 3,200, 4,124, 16, 38, 0,122,206, 0, 16, 6, 3, 84, 0, 0, 0, 0,
+ 0, 1, 0,201,254, 86, 5,106, 5,213, 0, 14, 0, 0, 37, 51, 17, 35, 17, 35, 1, 17, 35, 17, 51, 17, 1, 33, 1, 4,193,169,
+197, 69,253, 51,202,202, 2,158, 1, 4,253, 27,170,253,172, 1,170, 2,207,253, 49, 5,213,253,137, 2,119,253, 72, 0, 0, 0,
+ 0, 1, 0,191,254, 86, 4,161, 4, 96, 0, 14, 0, 0, 37, 51, 17, 35, 17, 35, 1, 17, 35, 17, 51, 17, 1, 51, 1, 4, 2,159,
+184, 56,253,199,185,185, 2, 37,235,253,174,153,253,189, 1,170, 2, 35,253,221, 4, 96,254, 29, 1,227,253,244, 0, 1, 0,201,
+ 0, 0, 5,106, 5,213, 0, 18, 0, 0, 1, 39, 17, 35, 17, 51, 17, 55, 17, 51, 21, 1, 33, 9, 1, 33, 1, 21, 35, 1,224, 77,
+202,202, 77,100, 1,237, 1, 4,253, 27, 3, 26,254,246,253,228,100, 2,130, 77,253, 49, 5,213,253,137, 73, 1, 81,243, 1,208,
+253, 72,252,227, 2, 30,248, 0, 0, 1, 0,191, 0, 0, 4,161, 4, 96, 0, 18, 0, 0, 1, 21, 35, 53, 39, 17, 35, 17, 51, 17,
+ 55, 53, 55, 21, 1, 51, 9, 1, 35, 2, 29,101, 64,185,185, 64,101, 1,128,235,253,174, 2,107,240, 1,132,138,235, 62,253,221,
+ 4, 96,254, 29, 56,217, 2,130, 1, 82,253,244,253,172, 0, 0, 0, 1, 0, 33, 0, 0, 5,106, 5,213, 0, 18, 0, 0, 19, 35,
+ 53, 51, 53, 51, 21, 51, 21, 35, 21, 1, 33, 9, 1, 33, 1, 17, 35,201,168,168,202,168,168, 2,158, 1, 4,253, 27, 3, 26,254,
+246,253, 51,202, 4, 81,164,224,224,164,243, 2,119,253, 72,252,227, 2,207,253, 49, 0, 0, 0, 0, 1, 0, 61, 0, 0, 4,156,
+ 6, 20, 0, 18, 0, 0, 1, 17, 1, 51, 9, 1, 35, 1, 17, 35, 17, 35, 53, 51, 53, 51, 21, 33, 21, 1,115, 2, 37,235,253,174,
+ 2,107,240,253,199,185,125,125,185, 1, 96, 4,246,253,135, 1,227,253,244,253,172, 2, 35,253,221, 4,246,164,122,122,164, 0,
+ 0, 1, 0, 50, 0, 0, 6,150, 5,213, 0, 12, 0, 0, 1, 33, 53, 33, 17, 1, 33, 9, 1, 33, 1, 17, 35, 1,245,254, 61, 2,
+141, 2,158, 1, 4,253, 27, 3, 26,254,246,253, 51,202, 5, 43,170,253,137, 2,119,253, 72,252,227, 2,207,253, 49, 0, 0, 0,
+ 0, 1, 0, 42, 0, 0, 5,139, 4, 96, 0, 12, 0, 0, 1, 33, 53, 33, 17, 1, 51, 9, 1, 35, 1, 17, 35, 1,169,254,129, 2,
+ 56, 2, 37,235,253,174, 2,107,240,253,199,185, 3,198,154,254, 29, 1,227,253,244,253,172, 2, 35,253,221, 0, 0, 1, 0,201,
+254, 86, 6, 4, 5,213, 0, 15, 0, 0, 33, 17, 33, 17, 35, 17, 51, 17, 33, 17, 51, 17, 51, 17, 35, 17, 4,113,253, 34,202,202,
+ 2,222,202,201,201, 2,199,253, 57, 5,213,253,156, 2,100,250,213,253,172, 1,170, 0, 0, 0, 0, 1, 0,193,254, 86, 5, 64,
+ 4, 96, 0, 15, 0, 0, 37, 51, 17, 35, 17, 35, 17, 33, 17, 35, 17, 51, 17, 33, 17, 51, 4,136,184,184,184,253,169,184,184, 2,
+ 87,184,153,253,189, 1,170, 2, 4,253,252, 4, 96,254, 51, 1,205, 0, 0, 0, 0, 1, 0,201, 0, 0, 8, 18, 5,213, 0, 13,
+ 0, 0, 1, 17, 35, 17, 33, 17, 35, 17, 51, 17, 33, 17, 33, 21, 5, 59,202,253, 34,202,202, 2,222, 3,161, 5, 43,250,213, 2,
+199,253, 57, 5,213,253,156, 2,100,170, 0, 0, 0, 1, 0,193, 0, 0, 6,230, 4, 96, 0, 13, 0, 0, 1, 17, 35, 17, 33, 17,
+ 35, 17, 51, 17, 33, 17, 33, 21, 4,136,184,253,169,184,184, 2, 87, 3, 22, 3,182,252, 74, 2, 4,253,252, 4, 96,254, 51, 1,
+205,170, 0, 0, 0, 1, 0,201,254,102, 8,116, 5,213, 0, 29, 0, 0, 1, 17, 35, 17, 33, 17, 35, 17, 33, 17, 33, 50, 23, 22,
+ 21, 17, 16, 6, 43, 1, 53, 51, 50, 55, 54, 53, 17, 52, 38, 35, 5, 59,202,253, 34,202, 4,114, 1,161,186,113,109,204,228, 76,
+ 62,134, 56, 55,124,124, 2,199,253, 57, 5, 43,250,213, 5,213,253,156,119,114,238,254,206,254,242,244,170, 75, 75,194, 1, 34,
+159,158, 0, 0, 0, 1, 0,193,254, 86, 7, 33, 4, 96, 0, 31, 0, 0, 1, 17, 35, 17, 33, 17, 35, 17, 33, 17, 51, 32, 23, 22,
+ 21, 17, 20, 7, 6, 43, 1, 53, 51, 50, 55, 54, 53, 17, 52, 39, 38, 7, 4,136,184,253,169,184, 3,199,250, 1, 7, 70, 82, 82,
+ 81,181,193,172,110, 33, 38, 38, 49,134, 1,231,254, 25, 3,198,252, 58, 4, 96,254, 23, 71, 81,229,254,242,214, 96, 96,156, 48,
+ 55,147, 1, 8,164, 38, 46, 5, 0, 2, 0,115,255, 45, 6, 39, 5,240, 0, 50, 0, 64, 0, 0, 37, 38, 17, 52, 55, 54, 51, 50,
+ 22, 21, 20, 7, 6, 7, 22, 51, 50, 55, 21, 6, 35, 4, 39, 6, 35, 36, 39, 38, 17, 16, 55, 54, 33, 50, 23, 22, 23, 21, 38, 39,
+ 38, 35, 32, 7, 6, 17, 16, 23, 22, 51, 50, 55, 54, 55, 54, 53, 52, 39, 38, 35, 34, 7, 6, 21, 16, 3, 69,100, 96, 95,169,168,
+192,102, 74,120,117,142, 84, 71, 73, 82,254,233,190, 68, 76,254,197,188,189,195,195, 1, 83,117,135,129, 94, 92,125,125,121,255,
+ 0,136,136,130,129,220, 15,217, 73, 48, 97, 43, 43, 73, 74, 43, 43,136,185, 1, 19,220,125,125,250,220,214,157,115, 63, 93, 24,
+166, 22, 1,192, 10, 1,209,210, 1, 98, 1,104,207,208, 36, 34, 62,183, 55, 47, 47,156,157,254,216,254,232,166,164, 46, 36, 63,
+127,214,120, 69, 71, 69, 70,121,254,228, 0, 0, 0, 2, 0,113,255, 82, 5, 4, 4,123, 0, 12, 0, 63, 0, 0, 37, 54, 55, 54,
+ 53, 52, 38, 35, 34, 7, 6, 21, 20, 7, 38, 53, 52, 55, 54, 51, 22, 23, 22, 21, 20, 7, 6, 7, 22, 51, 50, 55, 21, 6, 35, 34,
+ 39, 6, 35, 32, 39, 38, 17, 16, 55, 54, 33, 50, 23, 22, 23, 21, 38, 39, 38, 35, 34, 7, 6, 21, 20, 23, 22, 51, 3, 87, 33, 22,
+ 86, 48, 41, 44, 24, 27,143, 51, 77, 78,131,132, 78, 77,137, 39, 56, 72,101, 90, 62, 70, 82,235,137, 53, 60,254,253,138,137,151,
+150, 1, 6, 85, 81, 81, 76, 67, 90, 73, 85,179, 99, 99, 85, 84,171,173, 21, 29,113,135, 72, 84, 42, 46, 78,179,155,133,194,155,
+ 87, 88, 1, 88, 87,165,181,154, 44, 30, 52, 20,158, 18,151, 6,157,156, 1, 19, 1, 18,157,157, 17, 18, 35,152, 25, 22, 19,113,
+114,205,201,116,115, 0, 0, 0,255,255, 0,115,254,117, 5, 39, 5,240, 16, 39, 0,122, 1, 45, 0, 0, 16, 6, 3, 62, 0, 0,
+255,255, 0,113,254,117, 3,231, 4,123, 16, 39, 0,122, 0,143, 0, 0, 16, 6, 3, 94, 0, 0, 0, 1,255,250,254, 86, 4,233,
+ 5,213, 0, 11, 0, 0, 37, 51, 17, 35, 17, 35, 17, 33, 53, 33, 21, 33, 2,215,201,201,203,253,238, 4,239,253,238,170,253,172,
+ 1,170, 5, 43,170,170, 0, 0, 0, 1, 0, 5,254, 86, 4, 54, 4, 96, 0, 11, 0, 0, 37, 51, 17, 35, 17, 35, 17, 33, 53, 33,
+ 21, 33, 2,120,184,184,181,254, 66, 4, 49,254, 66,153,253,189, 1,170, 3,182,170,170, 0, 0,255,255,255,252, 0, 0, 4,231,
+ 5,213, 18, 6, 0, 60, 0, 0, 0, 1, 0, 61,254, 86, 4,127, 4, 96, 0, 8, 0, 0, 37, 17, 35, 17, 1, 51, 9, 1, 51, 2,
+197,195,254, 59,195, 1, 94, 1, 94,195, 18,254, 68, 1,188, 4, 78,252,148, 3,108, 0, 0, 0, 0, 1,255,252, 0, 0, 4,231,
+ 5,213, 0, 14, 0, 0, 9, 1, 51, 9, 1, 51, 1, 33, 21, 33, 17, 35, 17, 33, 53, 2, 12,253,240,217, 1,158, 1,155,217,253,
+240, 2, 12,253,244,203,253,244, 2,199, 3, 14,253,154, 2,102,252,242,170,253,227, 2, 29,170, 0, 1, 0, 61,254, 86, 4,127,
+ 4, 96, 0, 14, 0, 0, 5, 17, 35, 17, 33, 53, 33, 1, 51, 9, 1, 51, 1, 33, 21, 2,197,195,254, 59, 1,197,254, 59,195, 1,
+ 94, 1, 94,195,254, 70, 1,186,124,254,210, 1, 46,142, 4, 78,252,148, 3,108,251,178,142, 0, 0, 1, 0, 61,254, 86, 5, 59,
+ 5,213, 0, 15, 0, 0, 37, 51, 17, 35, 17, 35, 9, 1, 35, 9, 1, 51, 9, 1, 51, 1, 4,203,112,197, 20,254, 92,254, 89,218,
+ 2, 21,254, 47,217, 1,115, 1,117,217,254, 32,170,253,172, 1,170, 2,123,253,133, 3, 29, 2,184,253,213, 2, 43,253, 51, 0,
+ 0, 1, 0, 59,254, 86, 4,121, 4, 96, 0, 15, 0, 0, 37, 51, 17, 35, 17, 35, 9, 1, 35, 9, 1, 51, 9, 1, 51, 1, 4, 8,
+113,184, 33,254,186,254,186,217, 1,179,254,114,217, 1, 41, 1, 41,217,254,107,153,253,189, 1,170, 1,184,254, 72, 2, 74, 2,
+ 22,254,113, 1,143,253,223, 0, 0, 1,255,250,254, 86, 7, 71, 5,213, 0, 15, 0, 0, 37, 33, 17, 51, 17, 51, 17, 35, 17, 33,
+ 17, 33, 53, 33, 21, 33, 2,214, 2,222,202,201,201,251,142,253,238, 4,239,253,238,170, 5, 43,250,213,253,172, 1,170, 5, 43,
+170,170, 0, 0, 0, 1, 0, 5,254, 86, 6, 66, 4, 96, 0, 15, 0, 0, 37, 33, 17, 51, 17, 51, 17, 35, 17, 33, 17, 33, 53, 33,
+ 21, 33, 2,120, 2, 90,184,184,184,252, 57,254, 66, 4, 49,254, 66,153, 3,199,252, 57,253,189, 1,170, 3,182,170,170, 0, 0,
+ 0, 1, 0,175,254, 86, 5,124, 5,213, 0, 20, 0, 0, 37, 51, 17, 35, 17, 35, 17, 33, 34, 39, 38, 53, 17, 51, 17, 20, 22, 51,
+ 33, 17, 51, 4,179,201,201,203,254, 95,186,113,109,201,124,124, 1,120,203,170,253,172, 1,170, 2,199,119,114,238, 1, 55,254,
+217,159,158, 2,100, 0, 0, 0, 0, 1, 0,150,254, 86, 4,184, 4, 96, 0, 21, 0, 0, 37, 51, 17, 35, 17, 35, 17, 33, 34, 39,
+ 38, 61, 1, 51, 21, 20, 23, 22, 51, 33, 17, 51, 4, 0,184,184,184,254,169,153,102, 92,184, 52, 53,104, 1, 41,184,153,253,189,
+ 1,170, 2, 9, 95, 86,184,234,211,117, 59, 59, 1,190, 0, 0, 0, 1, 0,175, 0, 0, 4,179, 5,213, 0, 24, 0, 0, 1, 35,
+ 34, 39, 38, 53, 17, 51, 17, 20, 22, 59, 1, 17, 51, 17, 51, 17, 51, 17, 35, 17, 35, 17, 35, 2,130, 59,186,113,109,201,124,124,
+ 18,144,214,203,203,214,144, 2,199,119,114,238, 1, 55,254,217,159,158, 1, 57,254,199, 2,100,250, 43, 2,199,254,207, 0, 0,
+ 0, 1, 0,150, 0, 0, 4, 0, 4, 96, 0, 24, 0, 0, 1, 53, 51, 21, 51, 17, 51, 17, 35, 17, 35, 21, 35, 53, 35, 34, 39, 38,
+ 61, 1, 51, 21, 20, 23, 22, 1,249,160,175,184,184,175,160, 8,153,102, 92,184, 52, 43, 2,164,194,196, 1,190,251,160, 2, 9,
+196,196, 95, 86,184,234,211,117, 59, 48, 0, 0, 0, 1, 0,175, 0, 0, 4,179, 5,213, 0, 16, 0, 0, 1, 17, 33, 50, 23, 22,
+ 21, 17, 35, 17, 52, 38, 35, 33, 17, 35, 17, 1,122, 1,161,186,113,109,201,124,124,254,136,203, 5,213,253,156,119,114,238,254,
+102, 1,138,159,158,253, 57, 5,213, 0, 0, 0,255,255, 0,186, 0, 0, 4,100, 6, 20, 16, 6, 0, 75, 0, 0, 0, 2, 0, 20,
+255,227, 7, 20, 5,240, 0, 33, 0, 41, 0, 0, 1, 18, 55, 54, 33, 32, 23, 22, 19, 33, 16, 0, 33, 50, 54, 55, 21, 6, 4, 35,
+ 32, 39, 38, 3, 6, 39, 38, 61, 1, 51, 21, 20, 23, 22, 37, 33, 38, 39, 38, 32, 7, 6, 1,178, 34,150,188, 1, 58, 1, 67,181,
+187, 1,251,112, 1, 18, 1, 18,139,252,112,111,254,249,146,254,162,197,188, 10,170,118,122,170, 75, 66, 1, 64, 3,173, 24, 98,
+130,254, 72,128, 97, 3,109, 1, 7,170,210,210,219,254,132,254,244,254,206, 96, 95,215, 70, 72,205,194, 1, 85, 1,103,107,223,
+ 76, 62,157, 68, 57, 2,191,124,164,164,124, 0, 0, 2, 0, 15,255,226, 5,102, 4,123, 0, 34, 0, 41, 0, 0, 1, 34, 39, 38,
+ 61, 1, 51, 21, 20, 23, 22, 51, 54, 55, 54, 33, 50, 0, 29, 1, 33, 30, 1, 51, 50, 54, 55, 21, 6, 7, 6, 39, 36, 39, 38, 1,
+ 46, 1, 35, 34, 6, 7, 1, 88,144, 89, 96,156, 48, 57, 74, 26,116,146, 0,255,226, 1, 7,252,178, 12,205,183,106,199, 98, 99,
+104,110,101,254,243,156,148, 3, 78, 2,165,136,154,185, 14, 2, 4, 82, 90,172, 70, 49,151, 33, 38,197,130,161,254,221,250, 90,
+190,199, 52, 52,174, 42, 22, 23, 1, 5,151,144, 1,133,151,180,174,158, 0, 0,255,255, 0, 20,254,117, 7, 20, 5,240, 16, 39,
+ 2, 52, 2,188, 0, 0, 16, 6, 3,216, 0, 0,255,255, 0, 15,254,117, 5,102, 4,123, 16, 39, 2, 52, 1,231, 0, 0, 16, 6,
+ 3,217, 0, 0,255,255, 0,193, 0, 0, 1,121, 6, 20, 16, 6, 0, 79, 0, 0,255,255, 0, 59, 0, 0, 6,173, 5,213, 16, 39,
+ 6,139, 5,116, 1,117, 17, 6, 3, 51, 0, 0, 0, 8,180, 34, 0, 8, 35, 7, 43, 49, 0, 0,255,255, 0, 50, 0, 0, 5,173,
+ 6, 72, 16, 39, 2, 49, 0,240, 0, 0, 19, 6, 3, 83, 0, 0, 0, 8,180, 34, 0, 8, 35, 7, 43, 49, 0, 0, 0, 1, 0,201,
+254,102, 5, 53, 5,213, 0, 28, 0, 0, 1, 51, 50, 23, 22, 21, 17, 16, 6, 43, 1, 53, 51, 50, 55, 54, 53, 17, 52, 38, 35, 33,
+ 17, 35, 17, 51, 17, 1, 33, 2,169,139,186,113,109,204,228, 76, 62,134, 56, 55,124,124,254,136,202,202, 2,158, 1, 4, 3,113,
+119,114,238,254,206,254,242,244,170, 75, 75,194, 1, 34,159,158,253, 57, 5,213,253,137, 2,119, 0, 1, 0,191,254, 86, 4,136,
+ 4, 96, 0, 30, 0, 0, 1, 51, 32, 23, 22, 21, 17, 20, 7, 6, 43, 1, 53, 51, 50, 55, 54, 53, 17, 52, 39, 38, 35, 33, 17, 35,
+ 17, 51, 17, 1, 51, 2, 94, 20, 1, 5, 72, 82, 82, 81,181,193,172,110, 33, 38, 38, 44,139,254,252,185,185, 2, 37,235, 2,119,
+ 71, 81,229,254,242,214, 96, 96,156, 48, 55,147, 1, 8,166, 36, 41,254, 25, 4, 96,254, 29, 1,227, 0, 0, 0, 0, 1, 0, 54,
+254, 86, 6, 3, 5,213, 0, 20, 0, 0, 33, 35, 17, 33, 21, 16, 3, 6, 5, 53, 54, 55, 18, 25, 1, 33, 17, 51, 21, 1, 35, 5,
+ 58,202,254, 27,132, 98,254,145,212, 67,117, 3,120,201,254,146,134, 5, 43,212,254, 24,254,170,253, 56,167, 46,168, 1, 37, 2,
+ 53, 1, 26,250,213,170,254, 86, 0, 2, 0, 46,254, 86, 5, 43, 4, 96, 0, 0, 0, 21, 0, 0, 9, 1, 51, 21, 1, 35, 19, 35,
+ 17, 33, 21, 16, 3, 6, 5, 53, 54, 55, 54, 17, 53, 33,253,180, 6,191,184,254,222,123,229,184,254,123,118, 94,254,204,179, 59,
+ 98, 2,245, 8, 0,248,153,153,254, 86, 1,170, 3,199,134,254,146,254,252,207, 29,153, 27,127,207, 1,167,212, 0, 1, 0,201,
+254,102, 5, 59, 5,213, 0, 21, 0, 0, 37, 17, 33, 17, 35, 17, 51, 17, 33, 17, 51, 17, 16, 7, 6, 43, 1, 53, 51, 50, 55, 54,
+ 4,113,253, 34,202,202, 2,222,202,103,103,227, 76, 62,134, 56, 55,104, 2, 95,253, 57, 5,213,253,156, 2,100,250,147,254,242,
+122,122,170, 75, 75, 0, 0, 0, 0, 1, 0,193,254, 86, 4,136, 4, 96, 0, 21, 0, 0, 5, 17, 33, 17, 35, 17, 51, 17, 33, 17,
+ 51, 17, 20, 7, 6, 43, 1, 53, 51, 50, 55, 54, 3,208,253,169,184,184, 2, 87,184, 82, 81,181,193,172,110, 33, 38, 20, 2, 24,
+253,252, 4, 96,254, 51, 1,205,251,140,214, 96, 96,156, 48, 55, 0, 1, 0,201,254, 86, 6, 4, 5,213, 0, 16, 0, 0, 33, 35,
+ 17, 33, 17, 35, 17, 51, 17, 33, 17, 51, 17, 51, 21, 1, 35, 5, 59,202,253, 34,202,202, 2,222,202,201,254,146,134, 2,199,253,
+ 57, 5,213,253,156, 2,100,250,213,170,254, 86, 0, 1, 0,193,254, 86, 5, 64, 4, 96, 0, 16, 0, 0, 33, 35, 17, 33, 17, 35,
+ 17, 51, 17, 33, 17, 51, 17, 51, 21, 1, 35, 4,136,184,253,169,184,184, 2, 87,184,184,254,222,123, 2, 4,253,252, 4, 96,254,
+ 51, 1,205,252, 57,153,254, 86, 0, 1, 0,175,254, 86, 4,179, 5,213, 0, 20, 0, 0, 37, 17, 33, 34, 39, 38, 53, 17, 51, 17,
+ 20, 22, 51, 33, 17, 51, 17, 35, 17, 35, 17, 3,232,254, 95,186,113,109,201,124,124, 1,120,203,203,201,170, 2, 29,119,114,238,
+ 1, 55,254,217,159,158, 2,100,250, 43,254, 86, 2, 84, 0, 0, 0, 1, 0,150,254, 86, 4, 0, 4, 96, 0, 21, 0, 0, 37, 17,
+ 33, 34, 39, 38, 61, 1, 51, 21, 20, 23, 22, 51, 33, 17, 51, 17, 35, 17, 35, 17, 3, 72,254,169,153,102, 92,184, 52, 53,104, 1,
+ 41,184,184,184,153, 1,112, 95, 86,184,234,211,117, 59, 59, 1,190,251,160,254, 86, 2, 67, 0, 0, 1, 0,201,254, 86, 6,232,
+ 5,213, 0, 17, 0, 0, 37, 51, 21, 1, 35, 1, 35, 17, 1, 35, 1, 17, 35, 17, 33, 9, 1, 33, 6, 31,201,254,146,134, 1, 43,
+197,254,127,203,254,127,196, 1, 45, 1,125, 1,127, 1, 45,170,170,254, 86, 1,170, 5, 31,252, 0, 4, 0,250,225, 5,213,252,
+ 8, 3,248, 0, 0, 1, 0,193,254, 86, 6, 0, 4, 96, 0, 17, 0, 0, 37, 51, 21, 1, 35, 19, 35, 17, 1, 35, 1, 17, 35, 17,
+ 33, 9, 1, 33, 5, 72,184,254,222,123,229,178,254,203,184,254,202,178, 1, 6, 1, 62, 1, 63, 1, 4,153,153,254, 86, 1,170,
+ 3,176,253, 39, 2,217,252, 80, 4, 96,253, 18, 2,238, 0, 0,255,255, 0, 16, 0, 0, 5,104, 7,146, 16, 39, 2, 49, 0,206,
+ 1, 74, 17, 6, 3, 45, 0, 0, 0, 18,180, 24, 0, 8, 19, 7, 43, 49, 0, 64, 5,111, 0,111, 8, 2, 93, 48,255,255, 0,123,
+255,227, 4, 45, 6, 31, 16, 38, 2, 49, 79,215, 19, 6, 3, 77, 0, 0, 0, 8,180, 34, 0, 8, 25, 7, 43, 49,255,255, 0, 16,
+ 0, 0, 5,104, 5,213, 16, 38, 3, 45, 0, 0, 17, 7, 6,132, 4,188, 1,117, 0, 20,180, 10, 18, 13, 5, 7, 43, 64, 9, 48,
+ 18, 63, 13, 0, 18, 15, 13, 4, 93, 49, 0, 0,255,255, 0,123,255,227, 4, 45, 6, 16, 18, 38, 3, 77, 0, 0, 17, 6, 0,106,
+ 82, 0, 0, 32,180, 20, 45, 40, 11, 7, 43, 64, 21,127, 40,111, 40, 80, 45, 95, 40, 64, 45, 79, 40, 48, 45, 63, 40, 0, 45, 15,
+ 40, 10, 93, 49,255,255, 0, 8, 0, 0, 7, 72, 5,213, 18, 6, 0,136, 0, 0,255,255, 0,123,255,227, 7,111, 4,123, 18, 6,
+ 0,168, 0, 0,255,255, 0,201, 0, 0, 4,139, 5,213, 16, 39, 6,139, 4,161, 1,117, 17, 6, 3, 50, 0, 0, 0, 7, 64, 3,
+ 64, 0, 1, 93, 49, 0, 0, 0,255,255, 0,113,255,227, 4,127, 6, 72, 16, 39, 2, 49, 0,150, 0, 0, 19, 6, 3, 82, 0, 0,
+ 0, 7, 64, 3,112, 0, 1, 93, 49, 0, 0, 0,255,255, 0,117,255,227, 5,217, 5,240, 16, 6, 1, 81, 0, 0,255,255, 0, 0,
+ 0, 0, 0, 0, 0, 0, 16, 6, 2, 4, 0, 0,255,255, 0,117,255,227, 5,217, 5,240, 16, 39, 6,132, 5, 32, 1,117, 16, 6,
+ 3,243, 0, 0,255,255, 1, 43, 5, 70, 3,125, 6, 16, 16, 38, 0,106, 84, 0, 16, 6, 3,244, 0, 0, 0, 0,255,255, 0, 59,
+ 0, 0, 6,173, 5,213, 16, 39, 6,132, 5,116, 1,117, 17, 6, 3, 51, 0, 0, 0, 8,180, 28, 7, 2, 29, 7, 43, 49, 0, 0,
+255,255, 0, 50, 0, 0, 5,173, 6, 16, 16, 39, 0,106, 0,240, 0, 0, 18, 6, 3, 83, 0, 0,255,255, 0,156,255,227, 4,115,
+ 5,240, 16, 39, 6,132, 4,135, 1,117, 16, 6, 3, 52, 0, 0,255,255, 0,133,255,227, 3,200, 6, 16, 16, 38, 0,106, 58, 0,
+ 16, 6, 3, 84, 0, 0, 0, 0,255,255, 0,160,255,193, 4,248, 5,213, 16, 6, 1,121, 0, 0,255,255, 0, 0, 0, 0, 0, 0,
+ 0, 0, 16, 6, 2, 8, 0, 0,255,255, 0,201, 0, 0, 5, 51, 7, 49, 16, 39, 0,113, 0,245, 1, 59, 16, 6, 3, 53, 0, 0,
+255,255, 0,193, 0, 0, 4,128, 5,245, 16, 39, 0,113, 0,137,255,255, 16, 6, 3, 85, 0, 0,255,255, 0,201, 0, 0, 5, 51,
+ 5,213, 16, 39, 6,132, 4,245, 1,117, 16, 6, 3, 53, 0, 0,255,255, 0,193, 0, 0, 4,128, 6, 16, 16, 39, 0,106, 0,137,
+ 0, 0, 16, 6, 3, 85, 0, 0,255,255, 0,115,255,227, 5,217, 5,240, 16, 38, 3, 59, 0, 0, 17, 7, 6,132, 5, 39, 1,117,
+ 0, 20,180, 3, 31, 26, 9, 7, 43, 64, 9, 64, 31, 79, 26, 16, 31, 31, 26, 4, 93, 49, 0, 0,255,255, 0,113,255,227, 4,117,
+ 6, 16, 18, 38, 3, 91, 0, 0, 17, 6, 0,106,115, 0, 0, 20,180, 3, 31, 26, 9, 7, 43, 64, 9, 64, 31, 79, 26, 48, 31, 63,
+ 26, 4, 93, 49,255,255, 0,115,255,227, 5,217, 5,240, 16, 6, 3, 17, 0, 0,255,255, 0, 0, 0, 0, 0, 0, 0, 0, 16, 6,
+ 2, 7, 0, 0,255,255, 0,115,255,227, 5,217, 5,240, 18, 38, 4, 3, 0, 0, 16, 7, 6,132, 5, 39, 1,117,255,255, 1, 74,
+ 5, 70, 3,156, 6, 16, 18, 38, 4, 4, 0, 0, 16, 6, 0,106,115, 0, 0, 0,255,255, 0,111,255,227, 5, 35, 5,240, 16, 39,
+ 6,132, 4,103, 1,117, 16, 6, 3, 74, 0, 0,255,255, 0,113,255,227, 3,231, 6, 16, 16, 38, 0,106,226, 0, 16, 6, 3,106,
+ 0, 0, 0, 0,255,255, 0, 35,255,227, 4,189, 7, 49, 16, 39, 0,113, 0,114, 1, 59, 16, 6, 3, 64, 0, 0,255,255, 0, 61,
+254, 86, 4,127, 5,245, 16, 38, 0,113, 94,255, 16, 6, 3, 96, 0, 0, 0, 0,255,255, 0, 35,255,227, 4,189, 5,213, 16, 39,
+ 6,132, 4,114, 1,117, 16, 6, 3, 64, 0, 0,255,255, 0, 61,254, 86, 4,127, 6, 16, 16, 38, 0,106, 94, 0, 16, 6, 3, 96,
+ 0, 0, 0, 0,255,255, 0, 35,255,227, 4,189, 5,213, 16, 39, 6,141, 4,114, 1,117, 16, 6, 3, 64, 0, 0,255,255, 0, 61,
+254, 86, 4,127, 6,102, 16, 38, 2, 54, 94, 0, 16, 6, 3, 96, 0, 0, 0, 0,255,255, 0,175, 0, 0, 4,179, 5,213, 16, 39,
+ 6,132, 4,204, 1,117, 16, 6, 3, 68, 0, 0,255,255, 0,150, 0, 0, 4, 0, 6, 16, 16, 38, 0,106, 94, 0, 16, 6, 3,100,
+ 0, 0, 0, 0, 0, 1, 0,201,254, 86, 4,106, 5,213, 0, 9, 0, 0, 37, 51, 17, 35, 17, 35, 17, 33, 21, 33, 1,147,201,201,
+202, 3,161,253, 41,170,253,172, 1,170, 5,213,170, 0, 0, 0, 0, 1, 0,186,254, 86, 3,208, 4, 96, 0, 9, 0, 0, 37, 51,
+ 17, 35, 17, 35, 17, 33, 21, 33, 1,114,184,184,184, 3, 22,253,162,153,253,189, 1,170, 4, 96,170, 0, 0, 0,255,255, 0,201,
+ 0, 0, 6, 70, 5,213, 18, 38, 3, 72, 0, 0, 16, 7, 6,132, 5,183, 1,117,255,255, 0,193, 0, 0, 5,105, 6, 16, 16, 38,
+ 3,104, 0, 0, 16, 7, 0,106, 1, 8, 0, 0, 0, 2, 0,145, 0, 0, 4,180, 5,213, 0, 10, 0, 21, 0, 0, 1, 20, 23, 22,
+ 51, 33, 17, 33, 34, 7, 6, 1, 17, 33, 34, 36, 53, 52, 36, 51, 33, 17, 1,102, 79, 78,163, 1, 68,254,188,163, 78, 79, 3, 78,
+253,232,251,254,240, 1, 16,251, 1, 78, 1,183,138, 67, 68, 2, 35, 67, 68, 3,147,250, 43,218,221,222,218, 2,102, 0, 0, 0,
+ 0, 2, 0,113, 0, 0, 3,245, 4, 96, 0, 10, 0, 22, 0, 0, 1, 20, 23, 22, 51, 33, 17, 33, 34, 7, 6, 1, 17, 33, 34, 39,
+ 38, 16, 55, 54, 51, 33, 17, 1, 53, 62, 66,129, 1, 7,254,249,128, 67, 62, 2,192,254, 57,214,115,116,116,121,208, 1, 15, 1,
+ 76, 90, 43, 46, 1,105, 46, 42, 2,182,251,160, 82, 82, 1, 80, 82, 85, 1,197, 0, 2, 0,145,255,227, 7, 67, 5,213, 0, 12,
+ 0, 48, 0, 0, 1, 33, 34, 7, 6, 16, 23, 22, 51, 50, 55, 54, 53, 19, 6, 7, 6, 7, 6, 35, 34, 39, 38, 53, 52, 36, 51, 33,
+ 17, 51, 3, 20, 23, 22, 51, 50, 55, 54, 53, 17, 51, 17, 20, 7, 6, 35, 34, 39, 38, 3,234,254,188,163, 78, 79, 79, 95,129,180,
+ 75, 86, 33, 12, 14, 51,106, 94,110,238,129,136, 1, 16,251, 1, 78,202, 1, 63, 52,112,105, 59, 63,202,110,104,215,217,102, 49,
+ 2,201, 67, 68,254,234, 80, 95,109,125,159,254,221, 29, 28, 96, 54, 49,129,137,202,222,218, 2,102,251,236,143, 91, 74, 74, 79,
+155, 2,159,253, 90,224,127,120,120, 57, 0, 0, 0, 2, 0,113,255,227, 6,115, 4, 96, 0, 12, 0, 46, 0, 0, 1, 33, 34, 7,
+ 6, 21, 20, 22, 51, 50, 55, 54, 53, 19, 6, 7, 6, 35, 34, 38, 53, 52, 55, 54, 51, 33, 17, 51, 17, 20, 23, 22, 51, 50, 55, 54,
+ 53, 17, 51, 17, 20, 7, 6, 35, 34, 39, 38, 3, 61,254,249,128, 67, 62,129,106,148, 92, 45, 49, 67, 93, 94,136,172,203,116,121,
+208, 1, 15,184, 62, 60,106,104, 60, 62,184,100,104,206,211,100, 31, 2, 2, 46, 42, 94, 92,115,109, 52,156,254,246,108, 48, 49,
+193,166,170, 82, 85, 1,197,253, 97,159, 80, 79, 79, 82,157, 1, 65,254,184,236,115,120,120, 37, 0, 1, 0,201,255,227, 7, 3,
+ 5,240, 0, 55, 0, 0, 1, 52, 39, 38, 43, 1, 53, 51, 50, 55, 54, 53, 52, 39, 38, 35, 34, 6, 7, 53, 54, 55, 54, 51, 50, 23,
+ 22, 21, 20, 7, 6, 7, 22, 23, 22, 21, 20, 23, 22, 51, 50, 55, 54, 53, 17, 51, 17, 20, 7, 6, 35, 34, 39, 38, 39, 38, 3,170,
+ 92, 93,165,174,182,149, 79, 79, 81, 82,152, 83,190,114,115,100,101, 89,230,134,134, 71, 71,131,145, 82, 81, 63, 52,112,105, 59,
+ 63,202,110,104,215,217,102, 48, 28, 33, 1,178,132, 74, 75,166, 59, 60,112,115, 61, 62, 36, 38,180, 32, 16, 16,104,105,178,124,
+ 85, 86, 33, 31, 98, 98,144,128, 91, 74, 74, 79,155, 2,159,253, 90,224,127,120,120, 56, 80, 97, 0, 1, 0,171,255,227, 6, 70,
+ 4,124, 0, 53, 0, 0, 1, 52, 39, 38, 43, 1, 53, 51, 50, 55, 54, 53, 52, 39, 38, 35, 34, 7, 6, 7, 53, 62, 1, 51, 50, 23,
+ 22, 21, 20, 7, 6, 7, 22, 23, 22, 21, 20, 23, 22, 51, 50, 55, 54, 53, 17, 51, 17, 20, 7, 6, 35, 34, 39, 38, 3, 19, 78, 72,
+137,148,155,116, 67, 68, 70, 69,119, 71, 81, 80, 97, 98,170, 76,196,113,114, 60, 60,112,129, 64, 69, 62, 61,105,104, 60, 62,184,
+100,104,206,199,112, 98, 1, 56,102, 56, 51,152, 44, 45, 70, 64, 46, 46, 13, 13, 29,167, 24, 24, 78, 79,141, 93, 64, 65, 24, 25,
+ 72, 79, 72, 88, 68, 69, 79, 82,157, 1, 65,254,184,236,115,120,117,101, 0, 0, 0, 1, 0,201,254, 86, 5, 60, 5,240, 0, 41,
+ 0, 0, 33, 35, 17, 52, 39, 38, 43, 1, 53, 51, 50, 55, 54, 53, 52, 39, 38, 35, 34, 6, 7, 53, 54, 55, 54, 51, 50, 23, 22, 21,
+ 20, 7, 6, 7, 22, 23, 22, 21, 17, 51, 17, 35, 4,115,201, 92, 93,165,174,182,149, 79, 79, 81, 82,152, 83,190,114,115,100,101,
+ 89,230,134,134, 71, 71,131,145, 82, 81,201,201, 1,177,133, 74, 75,166, 59, 60,112,115, 61, 62, 36, 38,180, 32, 16, 16,104,105,
+178,124, 85, 86, 33, 31, 98, 97,146,254,249,253,172, 0, 0, 0, 0, 1, 0,171,254, 86, 4,131, 4,124, 0, 41, 0, 0, 37, 51,
+ 17, 35, 17, 35, 17, 52, 39, 38, 43, 1, 53, 51, 50, 55, 54, 53, 52, 39, 38, 35, 34, 7, 6, 7, 53, 62, 1, 51, 50, 23, 22, 21,
+ 20, 7, 6, 7, 22, 23, 22, 21, 3,200,187,184,184, 78, 72,137,148,155,116, 67, 68, 70, 69,119, 71, 81, 80, 97, 98,170, 76,196,
+113,114, 60, 60,112,126, 67, 69,153,253,189, 1,170, 1, 70, 88, 56, 51,152, 44, 45, 70, 64, 46, 46, 13, 13, 29,167, 24, 24, 78,
+ 79,141, 93, 64, 65, 24, 24, 73, 75,106, 0, 0, 0, 1, 0, 54,255,227, 7,202, 5,213, 0, 33, 0, 0, 1, 17, 20, 23, 22, 51,
+ 50, 55, 54, 53, 17, 51, 17, 20, 7, 6, 35, 34, 39, 38, 53, 17, 33, 21, 16, 3, 6, 5, 53, 54, 55, 18, 25, 1, 5, 58, 63, 52,
+112,105, 59, 63,202,110,104,215,214,105,110,254, 27,132, 98,254,145,212, 67,117, 5,213,251,236,143, 91, 74, 74, 79,155, 2,159,
+253, 90,224,127,120,120,125,226, 3,113,212,254, 24,254,170,253, 56,167, 46,168, 1, 37, 2, 53, 1, 26, 0, 0, 0, 1, 0, 46,
+255,227, 6,238, 4, 96, 0, 32, 0, 0, 1, 17, 20, 22, 51, 50, 55, 54, 53, 17, 51, 17, 20, 7, 6, 35, 34, 39, 38, 53, 17, 33,
+ 21, 16, 3, 6, 5, 53, 54, 55, 54, 17, 53, 4,115,122,103,104, 60, 62,184,100,104,206,199,112, 98,254,123,118, 94,254,204,179,
+ 59, 98, 4, 96,253, 4, 87,138, 79, 82,157, 1, 65,254,184,236,115,120,117,101,123, 2,143,134,254,146,254,252,207, 29,153, 27,
+127,207, 1,167,212, 0, 0, 0,255,255, 0,201,255,227, 8, 45, 5,213, 16, 2, 1,184, 0, 0, 0, 1, 0,193,255,227, 7, 3,
+ 4, 96, 0, 28, 0, 0, 1, 17, 20, 22, 51, 50, 55, 54, 53, 17, 51, 17, 20, 7, 6, 35, 34, 39, 38, 61, 1, 33, 17, 35, 17, 51,
+ 17, 33, 17, 4,136,122,103,104, 60, 62,184,100,104,206,199,112, 98,253,169,184,184, 2, 87, 4, 96,253, 4, 87,138, 79, 82,157,
+ 1, 65,254,184,236,115,120,117,101,123,204,253,252, 4, 96,254, 51, 1,205, 0,255,255, 0,115,255,227, 5,139, 5,240, 16, 2,
+ 0, 42, 0, 0,255,255, 0, 0, 0, 0, 0, 0, 0, 0, 16, 2, 2, 5, 0, 0, 0, 1,255,250,255,227, 5,102, 5,213, 0, 25,
+ 0, 0, 1, 17, 20, 23, 22, 51, 50, 55, 54, 53, 17, 51, 17, 20, 7, 6, 35, 34, 39, 38, 53, 17, 33, 53, 33, 21, 2,215, 63, 52,
+111,105, 59, 63,202,110,104,215,214,105,110,253,238, 4,239, 5, 43,252,150,143, 91, 74, 74, 79,155, 2,159,253, 90,224,127,120,
+120,125,226, 3,113,170,170, 0, 0, 1, 0, 5,255,227, 4,246, 4, 96, 0, 25, 0, 0, 1, 17, 20, 23, 22, 51, 50, 55, 54, 53,
+ 17, 51, 17, 20, 7, 6, 35, 34, 39, 38, 53, 17, 33, 53, 33, 21, 2,120, 62, 61,105,104, 60, 62,184,100,104,206,199,112, 98,254,
+ 66, 4, 49, 3,182,253,174, 86, 70, 69, 79, 82,157, 1, 65,254,184,236,115,120,117,101,123, 2,126,170,170, 0, 0, 1, 0,178,
+255,227, 6,160, 5,213, 0, 33, 0, 0, 37, 6, 7, 6, 33, 32, 0, 25, 1, 51, 17, 20, 22, 51, 50, 54, 53, 17, 51, 17, 20, 7,
+ 51, 50, 23, 22, 29, 1, 35, 53, 52, 39, 38, 35, 4,239, 42, 45,144,254,230,254,229,254,223,203,174,195,194,174,203, 9, 44,148,
+ 96, 96,156, 48, 55, 81,248, 82, 46,149, 1, 42, 1, 36, 3,164,252,117,240,211,211,240, 3,139,252, 92, 71, 67, 91, 91,171, 70,
+ 49,108, 42, 49, 0, 1, 0,178, 0, 0, 5, 41, 5,242, 0, 32, 0, 0, 33, 35, 17, 16, 0, 33, 32, 23, 22, 17, 21, 35, 53, 52,
+ 38, 35, 34, 6, 29, 1, 33, 50, 23, 22, 29, 1, 35, 53, 52, 39, 38, 35, 33, 1,125,203, 1, 33, 1, 27, 1, 23,147,145,203,174,
+194,195,174, 2, 88,149, 95, 96,156, 48, 55, 81,253,168, 3,164, 1, 36, 1, 42,149,146,254,217, 57, 32,240,211,211,240,157, 91,
+ 91,171, 70, 49,108, 42, 49, 0, 0, 2, 0,178, 0, 0, 6,196, 5,242, 0, 28, 0, 40, 0, 0, 1, 51, 50, 23, 22, 29, 1, 35,
+ 53, 52, 39, 38, 43, 1, 17, 35, 17, 33, 34, 39, 38, 53, 52, 55, 54, 33, 32, 0, 17, 3, 17, 52, 38, 35, 34, 6, 21, 20, 23, 22,
+ 51, 5, 41, 71,149, 95, 96,156, 48, 55, 81, 71,203,254, 42,201,159,110,144,152, 1, 19, 1, 27, 1, 33,203,174,195,194,174, 53,
+ 90,166, 2,114, 91, 91,171, 70, 49,108, 42, 49,254, 61, 1,195,179,124,224,253,142,149,254,214,254,220,254,206, 1, 25,240,211,
+211,175,149, 73,124, 0, 0, 0, 0, 1, 0,178, 0, 0, 6,196, 5,242, 0, 32, 0, 0, 1, 51, 50, 23, 22, 29, 1, 35, 53, 52,
+ 39, 38, 43, 1, 17, 35, 17, 52, 38, 35, 34, 7, 6, 29, 1, 35, 53, 16, 0, 33, 32, 23, 22, 5, 23, 89,149, 95, 96,156, 48, 55,
+ 81, 71,203,174,194,195, 87, 87,203, 1, 33, 1, 27, 1, 26,144, 90, 4, 96, 91, 91,171, 70, 49,108, 42, 49,252, 79, 3,139,240,
+211,106,106,239, 32, 57, 1, 36, 1, 42,149, 92, 0, 1, 0,178,255,227, 5, 41, 5,213, 0, 32, 0, 0, 19, 16, 0, 33, 32, 55,
+ 54, 61, 1, 35, 21, 20, 6, 35, 34, 38, 53, 17, 33, 50, 23, 22, 29, 1, 51, 53, 52, 39, 38, 35, 33, 17, 35,178, 1, 33, 1, 27,
+ 1, 23,147,145,203,174,194,195,174, 2, 88, 81, 55, 48,156, 96, 95,149,253,168,203, 2, 49,254,220,254,214,149,146,227, 57, 32,
+172,211,211,240, 1,103, 49, 42,108, 49, 70,171, 91, 91, 1,117, 0, 2, 0,155,255, 8, 4,186, 5,240, 0, 33, 0, 43, 0, 0,
+ 37, 33, 54, 55, 6, 7, 6, 35, 34, 0, 53, 52, 0, 51, 32, 23, 22, 3, 2, 3, 50, 23, 22, 29, 1, 35, 53, 52, 39, 38, 35, 33,
+ 17, 51, 18, 32, 54, 53, 52, 38, 32, 6, 21, 20, 1,102, 1, 15,232, 60, 48, 28, 73,124,224,254,251, 1, 16,226, 1, 8,131,155,
+ 58, 52,231,149, 95, 96,156, 48, 55, 81,253, 53,203,167, 1, 16,159,159,254,240,159,175,225,208, 39, 17, 46, 1, 15,235,230, 1,
+ 22,198,234,254,169,254,207,254,247, 91, 91,171, 70, 49,108, 42, 49, 1, 76, 1, 76,186,162,161,187,187,161,162, 0, 1, 0,178,
+255, 8, 5, 41, 5,213, 0, 29, 0, 0, 37, 33, 50, 23, 22, 29, 1, 35, 53, 52, 39, 38, 35, 33, 17, 51, 17, 33, 50, 23, 22, 29,
+ 1, 35, 53, 52, 39, 38, 35, 33, 1,125, 1,133,149, 95, 96,156, 48, 55, 81,253,176,203, 2, 88,149, 95, 96,156, 48, 55, 81,253,
+168,175, 91, 91,171, 70, 49,108, 42, 49, 5,213,254,139, 91, 91,171, 70, 49,108, 42, 49, 0, 0, 0, 1, 0,178,255, 8, 5, 41,
+ 5,242, 0, 31, 0, 0, 51, 17, 16, 0, 33, 32, 23, 22, 17, 21, 35, 53, 52, 38, 35, 34, 7, 6, 21, 17, 33, 50, 23, 22, 29, 1,
+ 35, 53, 52, 39, 38, 35,178, 1, 33, 1, 27, 1, 19,151,145,203,174,194,197, 85, 87, 2, 88,149, 95, 96,156, 48, 55, 81, 3,164,
+ 1, 36, 1, 42,149,142,254,213, 57, 32,240,211,106,108,237,253, 36, 91, 91,171, 70, 49,108, 42, 49, 0, 0, 0, 0, 2, 0,178,
+ 0, 0, 6,142, 5,242, 0, 43, 0, 56, 0, 0, 1, 35, 21, 20, 7, 6, 7, 6, 39, 38, 39, 38, 55, 54, 51, 33, 38, 39, 38, 35,
+ 34, 6, 21, 17, 35, 17, 16, 0, 33, 32, 23, 22, 23, 51, 50, 23, 22, 29, 1, 35, 53, 52, 39, 38, 33, 35, 34, 21, 20, 23, 22, 51,
+ 50, 55, 54, 53, 52, 5, 58, 17,103,105,152,146,109,130, 2, 1, 73, 78, 75, 1, 40, 22, 42, 87,194,195,174,203, 1, 33, 1, 27,
+ 1, 19,151, 92, 33, 37,149, 95, 96,156, 48, 53,254,208,187,153, 57, 58, 69, 53, 58, 46, 3,177, 32,223,114,115, 10, 10, 84,102,
+189,147, 76, 81, 82, 50,106,211,240,252,117, 3,164, 1, 36, 1, 42,149, 91,162, 91, 91,171, 70, 49,106, 44, 49,135,105, 45, 45,
+ 81, 64,147, 17, 0, 2, 0,178, 0, 0, 6,196, 5,242, 0, 28, 0, 40, 0, 0, 1, 35, 17, 16, 0, 33, 32, 39, 38, 17, 52, 55,
+ 54, 51, 33, 17, 51, 17, 51, 50, 23, 22, 29, 1, 35, 53, 52, 39, 38, 41, 1, 34, 7, 6, 21, 20, 22, 51, 50, 54, 53, 5,112, 71,
+254,223,254,229,254,237,152,144,110,159,201, 1,214,203, 71,149, 95, 96,156, 48, 55,254,157,254, 84,166, 90, 53,174,194,195,174,
+ 3,177,254,157,254,220,254,214,149,142, 1, 46,224,124,179, 1,146,254,110, 91, 91,171, 70, 49,108, 42, 49,125, 72,149,224,211,
+211,240, 0, 0, 0, 1, 0,178, 0, 0, 5, 41, 5,213, 0, 20, 0, 0, 19, 51, 17, 54, 51, 32, 23, 22, 17, 21, 35, 53, 52, 38,
+ 35, 34, 7, 6, 21, 17, 35,178,203,160,209, 1, 19,151,145,203,174,194,193, 89, 87,203, 5,213,254, 59,100,149,142,254,213, 75,
+ 50,240,211,106,103,242,253,243, 0, 1, 0,178,255, 8, 4, 86, 5,213, 0, 15, 0, 0, 1, 17, 33, 50, 23, 22, 29, 1, 35, 53,
+ 52, 39, 38, 35, 33, 17, 1,125, 1,133,149, 95, 96,156, 48, 55, 81,253,176, 5,213,250,218, 91, 91,171, 70, 49,108, 42, 49, 5,
+213, 0, 0, 0, 0, 1, 0,178,255,227, 5,231, 5,213, 0, 27, 0, 0, 1, 17, 16, 23, 22, 51, 50, 55, 54, 53, 17, 51, 17, 20,
+ 7, 6, 35, 34, 39, 38, 25, 1, 33, 17, 35, 17, 51, 17, 3,124, 37, 51,120,129, 42, 37,203,113, 88,210,198,100,113,254,204,203,
+203, 4, 96,253,215,254,229, 62, 87, 87, 75,135, 2,176,253, 55,213,125, 98, 98,112, 1,105, 1,147,252, 79, 5,213,254,139, 0,
+ 0, 2, 0, 65,255,227, 7,153, 6,205, 0, 34, 0, 47, 0, 0, 1, 22, 17, 16, 0, 33, 32, 0, 17, 16, 55, 35, 6, 39, 38, 61,
+ 1, 51, 21, 20, 23, 22, 51, 33, 50, 23, 22, 29, 1, 35, 53, 52, 39, 38, 35, 37, 34, 7, 6, 17, 16, 0, 32, 0, 17, 16, 39, 38,
+ 5,214,201,254,136,254,198,254,197,254,135,195,103,148, 96, 96,156, 48, 55, 81, 4,176,149, 95, 96,156, 48, 55, 81,253,168,225,
+124,130, 1, 3, 1,184, 1, 1,128,121, 5, 38,225,254,164,254,159,254, 91, 1,164, 1, 98, 1, 99,218, 1, 92, 91,171, 70, 49,
+108, 42, 49, 91, 91,171, 70, 49,108, 42, 49, 32,158,164,254,229,254,230,254,184, 1, 72, 1, 26, 1, 22,169,158, 0, 1, 0,178,
+ 0, 0, 5, 41, 5,213, 0, 20, 0, 0, 33, 35, 17, 6, 35, 32, 39, 38, 25, 1, 51, 17, 20, 22, 51, 50, 55, 54, 61, 1, 51, 5,
+ 41,203,160,209,254,237,152,144,203,174,194,193, 89, 87,203, 1,197,100,149,142, 1, 43, 2, 38,253,243,240,211,105,104,242,152,
+ 0, 1, 0,178,255, 8, 5, 41, 5,213, 0, 18, 0, 0, 9, 2, 33, 50, 23, 22, 29, 1, 35, 53, 52, 39, 38, 35, 33, 53, 9, 1,
+ 3,117, 1,119,252,201, 2, 32,149, 95, 96,156, 48, 55, 81,252,221, 3, 49,254,107, 5,213,254,174,252, 44, 91, 91,171, 70, 49,
+108, 42, 49,175, 3,192, 1,102, 0, 3, 0,143,255,210, 4,201, 5,240, 0, 38, 0, 44, 0, 54, 0, 0, 37, 6, 35, 34, 39, 38,
+ 55, 54, 51, 50, 23, 54, 55, 6, 7, 6, 35, 34, 0, 53, 52, 0, 51, 32, 23, 22, 3, 2, 7, 6, 7, 22, 55, 54, 55, 21, 6, 7,
+ 6, 37, 38, 7, 6, 23, 22, 18, 32, 54, 53, 52, 38, 32, 6, 21, 20, 2,174,110, 86,172, 73,103, 2, 5,201,178,148,131,114, 48,
+ 28, 73,124,224,254,251, 1, 16,226, 1, 8,131,155, 58, 55,190, 32, 36, 84, 46,129,126,103,152,154,254,206, 93, 42, 86, 31, 24,
+181, 1, 16,159,159,254,240,159, 28, 64, 35, 50,110,245,154,119,239, 39, 17, 46, 1, 15,235,230, 1, 22,198,234,254,169,254,191,
+204, 34, 37, 22, 3, 7,100,192, 89, 1, 3,198, 81, 4, 8, 60, 45, 2, 38,186,162,161,187,187,161,162, 0, 0, 0, 1, 0,178,
+255, 8, 6,196, 5,242, 0, 30, 0, 0, 33, 17, 52, 38, 35, 34, 7, 6, 29, 1, 35, 53, 16, 0, 33, 32, 0, 25, 1, 51, 50, 23,
+ 22, 29, 1, 35, 53, 52, 39, 38, 35, 4, 94,174,194,197, 85, 87,203, 1, 33, 1, 27, 1, 26, 1, 33, 71,149, 95, 96,156, 48, 55,
+ 81, 3,139,240,211,106,106,239, 32, 57, 1, 36, 1, 42,254,214,254,220,253, 11, 91, 91,171, 70, 49,108, 42, 49, 0, 2, 0, 92,
+255,226, 5,133, 5,213, 0, 13, 0, 43, 0, 0, 1, 17, 20, 22, 51, 50, 55, 54, 61, 1, 52, 39, 38, 35, 33, 35, 53, 51, 53, 52,
+ 55, 54, 51, 33, 21, 33, 34, 7, 6, 21, 33, 50, 23, 22, 21, 17, 35, 53, 6, 35, 32, 39, 38, 17, 1,217,174,194,193, 89, 87, 48,
+ 55, 81,253, 12,178,178, 96, 95,149, 3, 35,253, 12, 81, 55, 48, 2, 88,149, 95, 96,203,160,209,254,231,146,144, 3,177,254,152,
+240,211,106,103,242,161,108, 42, 49,175, 20,171, 91, 91,175, 49, 42,107, 91, 91,171,253, 1, 70,100,149,148, 1, 37, 0, 0, 0,
+ 0, 1, 0,178,255,227, 6,196, 5,213, 0, 29, 0, 0, 1, 17, 16, 0, 33, 32, 0, 25, 1, 51, 17, 20, 22, 51, 50, 54, 53, 17,
+ 33, 50, 23, 22, 29, 1, 35, 53, 52, 39, 38, 35, 5, 41,254,223,254,230,254,229,254,223,203,174,195,194,174, 1, 18,149, 95, 96,
+156, 48, 55, 81, 5, 38,253, 11,254,220,254,214, 1, 42, 1, 36, 3,164,252,117,240,211,211,240, 3,139, 91, 91,171, 70, 49,108,
+ 42, 49, 0, 0, 0, 1, 0,140,255,227, 5, 83, 5,242, 0, 44, 0, 0, 19, 52, 55, 54, 33, 32, 23, 22, 21, 20, 7, 6, 7, 30,
+ 1, 21, 20, 4, 32, 36, 53, 51, 20, 23, 22, 32, 54, 53, 52, 38, 35, 33, 53, 33, 50, 54, 53, 52, 39, 38, 35, 34, 7, 6, 7,173,
+155,144, 1, 23, 1, 20,147,155, 73, 73,129,146,163,254,247,253, 74,254,248,202, 82, 83, 1,232,166,165,245,253,191, 2, 65,230,
+147, 99, 97,181,181, 97, 87, 11, 4,171,143, 96, 88, 88, 96,143,128, 91, 89, 32, 34,198,175,245,232,231,246,162, 78, 77,155,162,
+167,154,159,130,116, 89, 49, 48, 48, 43, 74, 0, 0, 1, 0, 92,255,227, 6,110, 6,205, 0, 30, 0, 0, 1, 17, 20, 22, 51, 50,
+ 55, 54, 61, 1, 51, 21, 16, 0, 33, 32, 0, 25, 1, 35, 34, 39, 38, 61, 1, 51, 21, 20, 23, 22, 51, 2,194,174,194,197, 85, 87,
+203,254,223,254,229,254,230,254,223, 71,149, 95, 96,156, 48, 55, 81, 5,213,252,117,240,211,105,107,239, 32, 57,254,220,254,214,
+ 1, 42, 1, 36, 2,245, 91, 91,171, 70, 49,108, 42, 49, 0, 0, 0, 1, 0,178,255,225, 5, 41, 6,147, 0, 32, 0, 0, 1, 20,
+ 23, 22, 51, 50, 55, 54, 61, 1, 51, 21, 16, 7, 6, 37, 36, 39, 38, 53, 16, 55, 54, 37, 55, 37, 53, 5, 21, 5, 4, 7, 6, 1,
+122, 90, 91,190,195, 87, 87,203,145,159,254,244,254,208,123,144, 61,129, 1,115,150,253, 57, 4, 17,254,164,254,153, 87, 47, 2,
+ 7,175,104,105,105,107,239, 32, 57,254,220,149,165, 16, 18,131,155,234, 1, 38,100,224,161, 65,140,190,190,190,156,161,158, 85,
+ 0, 1, 0,178, 0, 0, 5, 41, 5,242, 0, 17, 0, 0, 51, 17, 16, 0, 33, 32, 0, 25, 1, 35, 17, 52, 38, 35, 34, 6, 21, 17,
+178, 1, 33, 1, 27, 1, 26, 1, 33,203,174,194,195,174, 3,164, 1, 36, 1, 42,254,214,254,220,252, 92, 3,139,240,211,211,240,
+252,117, 0, 0, 0, 1, 0,178,255, 66, 5, 41, 5,244, 0, 32, 0, 0, 1, 52, 39, 38, 35, 34, 7, 6, 29, 1, 35, 53, 16, 55,
+ 54, 5, 4, 23, 22, 21, 16, 7, 6, 5, 7, 5, 21, 37, 53, 37, 36, 55, 54, 4, 97, 90, 91,190,195, 87, 87,203,144,160, 1, 12,
+ 1, 48,122,145, 61,129,254,141,150, 2,199,251,239, 1, 92, 1,103, 87, 47, 3,206,175,103,106,106,106,239, 32, 57, 1, 36,149,
+165, 16, 18,131,155,234,254,218,100,224,161, 65,140,190,190,190,156,161,158, 85, 0, 1, 0,178, 0, 0, 5,161, 5,242, 0, 24,
+ 0, 0, 1, 17, 35, 17, 6, 7, 6, 29, 1, 35, 53, 16, 55, 54, 33, 32, 23, 22, 25, 1, 35, 17, 52, 39, 38, 3,144,203,136, 75,
+117,203,174,145, 1, 57, 1, 41,159,175,203,117, 66, 5, 71,252,148, 3,108, 19, 80,124,221, 32, 57, 1, 5,180,149,149,163,254,
+234,252, 92, 3,139,204,141, 80, 0, 2, 0,155,255, 8, 4,186, 5,240, 0, 29, 0, 43, 0, 0, 37, 38, 39, 38, 17, 52, 0, 51,
+ 32, 23, 22, 3, 2, 3, 50, 23, 22, 29, 1, 35, 53, 52, 39, 38, 35, 33, 17, 51, 21, 33, 55, 54, 55, 54, 39, 38, 39, 38, 32, 6,
+ 21, 20, 23, 22, 2,162, 69,240,202, 1, 16,226, 1, 8,131,155, 58, 52,231,149, 95, 96,156, 48, 55, 81,253, 53,203, 1, 20,171,
+101, 15, 63, 28, 25, 55, 79,254,240,159,151,163,220,220,170,142, 1, 4,230, 1, 22,198,234,254,169,254,207,254,247, 91, 91,171,
+ 70, 49,108, 42, 49, 1, 76,157,195,194, 44,189,215,190, 64, 94,187,161,170,116,126, 0, 0, 0, 0, 1, 0,178, 0, 0, 6,196,
+ 5,242, 0, 31, 0, 0, 1, 51, 50, 23, 22, 29, 1, 35, 53, 52, 39, 38, 43, 1, 17, 35, 17, 52, 38, 35, 34, 6, 21, 17, 35, 17,
+ 16, 0, 33, 32, 23, 22, 5, 23, 89,149, 95, 96,156, 48, 55, 81, 71,203,174,194,195,174,203, 1, 33, 1, 27, 1, 26,144, 90, 4,
+ 96, 91, 91,171, 70, 49,108, 42, 49,252, 79, 3,139,240,211,211,240,252,117, 3,164, 1, 36, 1, 42,149, 92, 0,255,255, 0,178,
+255,227, 5, 41, 5,213, 18, 6, 0, 56, 0, 0, 0, 1, 0,178,255, 8, 6,196, 5,213, 0, 32, 0, 0, 41, 1, 50, 23, 22, 29,
+ 1, 51, 53, 52, 39, 38, 43, 1, 17, 35, 17, 20, 7, 6, 35, 34, 38, 61, 1, 35, 21, 16, 23, 22, 33, 50, 55, 4, 94, 1, 18, 81,
+ 55, 48,156, 96, 95,149, 71,203, 87, 89,193,194,174,203,144,152, 1, 19,209,160, 49, 42,108, 49, 70,171, 91, 91, 5, 38,253,243,
+242,104,105,211,240,152,177,254,215,144,149,100,255,255, 0,135,255,227, 4,162, 5,240, 18, 6, 0, 54, 0, 0, 0, 1, 0,178,
+ 0, 0, 5, 41, 5,242, 0, 18, 0, 0, 51, 17, 16, 0, 33, 32, 23, 22, 17, 21, 35, 53, 52, 38, 35, 34, 6, 21, 17,178, 1, 33,
+ 1, 27, 1, 19,151,145,203,174,194,195,174, 3,164, 1, 36, 1, 42,149,142,254,213, 57, 32,240,211,211,240,252,117, 0, 0, 0,
+ 0, 2, 0,140,255,227, 5, 83, 5,242, 0, 43, 0, 57, 0, 0, 1, 30, 1, 21, 20, 4, 32, 36, 53, 51, 20, 23, 22, 32, 54, 53,
+ 52, 38, 35, 34, 7, 6, 7, 34, 35, 54, 55, 54, 55, 38, 39, 38, 53, 52, 55, 54, 33, 32, 23, 22, 21, 20, 7, 6, 1, 34, 7, 6,
+ 21, 20, 22, 51, 50, 54, 53, 52, 39, 38, 4, 30,146,163,254,247,253, 74,254,248,202, 82, 83, 1,232,166,165,245,226,101, 31, 5,
+102,103, 3, 35, 82,146,129, 72, 74,155,147, 1, 19, 1, 20,147,155, 73, 73,254, 80,180, 97, 99,147,229,230,147, 99, 97, 3, 87,
+ 34,198,175,245,232,231,246,162, 78, 77,155,162,167,154, 77, 28, 12, 28, 42, 99, 34, 32, 89, 91,128,143, 96, 88, 88, 94,145,128,
+ 91, 89, 1,217, 48, 49, 89,116,130,130,116, 89, 49, 48, 0, 0, 0, 1, 0,178, 0, 0, 6, 12, 5,213, 0, 21, 0, 0, 1, 53,
+ 52, 38, 35, 34, 7, 6, 21, 17, 35, 17, 51, 17, 54, 51, 32, 23, 22, 23, 51, 21, 4, 94,174,194,193, 89, 87,203,203,160,209, 1,
+ 19,151,117, 24,231, 1,219, 50,240,211,106,103,242,253,243, 5,213,254, 59,100,149,115,226,175,255,255, 0,115, 0, 0, 5,217,
+ 5,213, 18, 6, 2,196, 0, 0, 0, 2, 0, 92, 0, 0, 5,227, 5,242, 0, 44, 0, 60, 0, 0, 1, 17, 52, 55, 54, 51, 50, 23,
+ 22, 21, 20, 7, 6, 35, 34, 39, 21, 33, 50, 23, 22, 29, 1, 35, 53, 52, 39, 38, 35, 33, 17, 35, 17, 35, 34, 39, 38, 61, 1, 51,
+ 21, 20, 23, 22, 51, 1, 6, 7, 6, 21, 20, 23, 22, 23, 22, 55, 54, 53, 52, 39, 38, 1,208,146,141,235,244,132,145,145,132,244,
+246, 73, 1,244,149, 95, 96,156, 48, 55, 81,254, 12,203, 32,149, 95, 96,156, 48, 55, 81, 2, 42,138, 93, 87, 87, 93,138,136, 95,
+ 87, 87, 95, 2,114, 2, 8,149,115,112,112,122,144,149,122,112, 83,218, 91, 91,171, 70, 49,108, 42, 49,254, 61, 1,195, 91, 91,
+171, 70, 49,108, 42, 49, 2,220, 1, 65, 62, 84, 93, 61, 66, 1, 1, 68, 61, 91, 86, 62, 67, 0,255,255, 0,115,255,227, 5,217,
+ 5,240, 18, 6, 0, 50, 0, 0, 0, 3, 0,135,255,227, 4,162, 5,240, 0, 8, 0, 19, 0, 46, 0, 0, 1, 17, 54, 55, 54, 53,
+ 52, 39, 38, 1, 17, 52, 39, 34, 7, 6, 21, 20, 23, 22, 5, 23, 30, 1, 21, 20, 4, 33, 34, 38, 39, 53, 22, 23, 22, 23, 17, 38,
+ 39, 38, 53, 52, 55, 54, 51, 50, 21, 2,185,113, 71, 94, 67, 67,254,188, 57, 53, 43, 26, 60, 38, 1, 5, 48,226,215,254,221,254,
+231,106,239,128,123,118, 69, 66,190, 91,101, 75, 91,165,231, 2,148,253,248, 11, 52, 68,126,110, 62, 61, 1, 18, 1,132, 62, 2,
+ 64, 37,145, 99, 51, 31, 65, 10, 43,217,182,217,224, 48, 47,208, 69, 35, 20, 10, 2, 44, 44, 87, 96,171,215, 97,114,201, 0, 0,
+255,255, 0,117, 3,239, 1,135, 6, 20, 16, 6, 2, 24, 0, 0,255,255, 0,178, 3,254, 1,215, 5,213, 16, 6, 2, 21, 0, 0,
+ 0, 1, 0, 94, 4,241, 3,169, 6,194, 0, 3, 0, 0, 1, 35, 1, 51, 1, 51,213, 2,118,213, 4,241, 1,209, 0, 1, 0,120,
+ 4,241, 3,134, 7, 37, 0, 17, 0, 0, 1, 34, 7, 6, 21, 35, 52, 55, 54, 51, 50, 55, 54, 53, 51, 20, 7, 6, 1,255, 91, 82,
+ 66,152,104,106,181, 91, 82, 66,152,104,106, 5,205, 84, 68, 68,130,106,108, 84, 68, 68,130,106,108, 0, 0, 0,255,255, 0,158,
+ 4,240, 2,125, 6,102, 16, 6, 0, 67,244, 0, 0, 1, 0, 94, 4,229, 3,189, 7, 55, 0, 21, 0, 0, 19, 35, 52, 55, 18, 33,
+ 32, 23, 18, 33, 34, 17, 51, 20, 51, 50, 39, 38, 39, 38, 7, 6,252,158, 32,113, 1, 51, 1, 85, 55, 75,254,193,251,152, 97,121,
+ 38, 34,205,206, 57, 25, 4,241,211, 83, 1, 32,252,254,170, 1, 8,122,158,140, 2, 1,179, 78, 0, 1, 0, 90, 4,241, 3,178,
+ 7, 37, 0, 5, 0, 0, 27, 1, 51, 3, 33, 21, 90,170,170,125, 2,129, 4,241, 2, 52,254, 98,150, 0, 0, 0, 0, 1, 0,186,
+255,230, 7, 29, 4, 98, 0, 38, 0, 94, 64, 17, 0, 18, 20, 30, 27, 8, 29, 80, 18, 8, 20, 80, 10, 8, 8, 70, 39, 16,252,236,
+252,252,252,252, 60, 17, 18, 57, 49, 64, 22, 7, 20, 10, 26, 17, 0, 6, 31, 8, 13, 23,135, 31, 4, 35,140, 29, 27, 18, 8,188,
+ 29, 0, 47,244, 60, 60, 16,244, 60,196,236, 50, 17, 18, 23, 57, 48, 64, 19, 48, 40, 80, 40,112, 40,144, 40,160, 40,160, 40,191,
+ 40,223, 40,255, 40, 9, 1, 93, 37, 6, 7, 6, 35, 34, 38, 53, 17, 51, 17, 20, 22, 51, 50, 55, 54, 53, 17, 51, 17, 20, 22, 51,
+ 50, 54, 53, 17, 51, 17, 35, 53, 6, 7, 6, 35, 34, 39, 38, 3,174, 69, 96, 96,130,175,190,185,114,117,143, 83, 83,185,114,119,
+141,166,185,185, 63, 88, 88,121,122, 86, 85,216,124, 58, 60,246,226, 2,164,253, 98,162,156, 96, 94,164, 2,122,253, 98,162,156,
+192,162, 2,122,251,160,174,104, 48, 50, 62, 62, 0, 1, 0,186,254, 86, 4,100, 4,123, 0, 23, 0, 63, 64, 30, 1, 7, 22, 3,
+ 16, 10, 4,135, 16, 19,184, 14,188, 10, 23, 9,169, 10, 0, 8, 9, 22, 78, 11, 15, 7, 8, 13, 70, 24, 16,252,236, 50, 50,244,
+ 60,236, 49, 0, 47,252,204, 16,228,244,196,236, 17, 18, 23, 57, 48,180, 96, 25,207, 25, 2, 1, 93, 1, 17, 52, 38, 35, 34, 6,
+ 21, 17, 33, 21, 33, 17, 35, 17, 51, 21, 62, 1, 51, 50, 22, 21, 17, 3,172,124,124,149,172, 2,241,253, 15,185,185, 66,179,117,
+193,198, 1, 44, 1,114,159,158,190,164,254, 54,175,254, 86, 6, 10,174,101,100,239,232,254,136, 0, 2, 0,113,254, 86, 5, 47,
+ 4,123, 0, 11, 0, 32, 0, 60, 64, 14, 34, 30, 26, 14, 6, 8, 12, 28, 71, 0, 18, 20, 69, 33, 16,252,236,244, 60,236, 50, 50,
+220,212, 49, 64, 18, 3,185, 14, 17, 9,185, 26, 23,184, 17,140, 30,169, 12,189, 27,188, 33, 0, 16,228,228,236,228,244,196,236,
+ 16,198,238, 48, 1, 20, 22, 51, 50, 54, 53, 52, 38, 35, 34, 6, 1, 35, 17, 14, 1, 35, 34, 2, 17, 16, 0, 51, 50, 22, 23, 53,
+ 51, 17, 51, 21, 35, 1, 47,167,146,146,168,168,146,146,167, 3, 43,184, 58,177,124,203,255, 0,255,203,124,177, 58,184,213,213,
+ 2, 47,203,231,231,203,203,231,231,251, 92, 2, 82,100, 97, 1, 68, 1, 8, 1, 8, 1, 68, 97,100,170,252, 79,175, 0, 0, 0,
+ 0, 1, 0,186,254, 86, 5, 57, 4,123, 0, 23, 0, 61, 64, 13, 25, 22, 3, 8, 0, 21, 78, 9, 13, 8, 12, 70, 24, 16,252,236,
+ 50,244, 60,236,220,196, 49, 64, 13, 6,135, 14, 17,184, 12,188, 2,189, 21,169, 11, 0, 0, 47, 60,236,236,228,244,196,236,181,
+ 9, 3, 20, 3, 14, 10, 17, 18, 23, 57, 48, 33, 17, 35, 17, 52, 38, 35, 34, 6, 21, 17, 35, 17, 51, 21, 62, 1, 51, 50, 22, 21,
+ 17, 51, 21, 4,100,184,124,124,149,172,185,185, 66,179,117,193,198,213,254, 86, 4, 72,159,158,190,164,253,135, 4, 96,174,101,
+100,239,232,254, 11,175, 0, 0, 0, 1, 0,174,255,227, 4, 88, 6, 20, 0, 26, 0, 63, 64, 30, 7, 15, 0, 3, 20, 3, 11,135,
+ 20, 23,140, 18, 17, 5,169, 4,188, 18, 19, 15, 8, 4, 17, 78, 6, 2, 8, 0, 70, 27, 16,252,236, 50,244, 60,236, 50, 49, 0,
+ 47,244,252,204, 16,244,196,236, 17, 18, 23, 57, 48,180, 96, 28,207, 28, 2, 1, 93, 19, 17, 51, 17, 33, 21, 33, 17, 20, 23, 22,
+ 51, 50, 55, 54, 53, 17, 51, 17, 35, 53, 14, 1, 35, 34, 39, 38,174,184, 2,242,253, 14, 62, 62,124,152, 84, 86,184,184, 67,177,
+117,193,100,100, 1,186, 4, 90,254, 76,170,254, 11,159, 80, 79, 95, 98,161, 1, 59,252,224,172,102, 99,120,120, 0, 2, 0,113,
+254, 86, 5, 47, 4,123, 0, 18, 0, 30, 0, 60, 64, 13, 32, 1, 16, 4, 25, 8, 18, 71, 19, 18, 10, 69, 31, 16,252,236,244,236,
+ 50, 50,220,212, 49, 64, 19, 22,185, 4, 7, 28,185, 16, 13,184, 7,140, 31, 1,169, 2,189, 17,188, 31, 0, 16,228,244,236, 16,
+228,244,196,236, 16,198,238, 48, 1, 51, 21, 33, 17, 14, 1, 35, 34, 2, 17, 16, 0, 51, 50, 22, 23, 53, 51, 1, 20, 22, 51, 50,
+ 54, 53, 52, 38, 35, 34, 6, 4, 90,213,254,115, 58,177,124,203,255, 0,255,203,124,177, 58,184,252,213,167,146,146,168,168,146,
+146,167,254,248,162, 2, 82,100, 97, 1, 68, 1, 8, 1, 8, 1, 68, 97,100,170,253,207,203,231,231,203,203,231,231, 0, 0, 0,
+ 0, 1, 0,174,255, 26, 3,224, 6, 20, 0, 19, 0, 44, 64, 12, 21, 5, 15, 18, 14, 5, 8, 3, 8, 1, 70, 20, 16,252,252, 60,
+220,212,236, 16,196, 49, 64, 10, 7,169, 4,188, 14, 9,169, 2,151, 1, 0, 47,228,236,204,244,236, 48, 41, 1, 17, 51, 17, 33,
+ 21, 33, 17, 51, 50, 23, 22, 29, 1, 35, 53, 52, 39, 38, 2, 83,254, 91,184, 2,122,253,134,237,152, 77, 96,156, 48, 49, 6, 20,
+254, 76,170,252,249, 73, 91,171, 70, 49,105, 38, 38, 0, 0, 0, 0, 1, 0,186,254, 86, 4,100, 4,123, 0, 21, 0, 62, 64, 30,
+ 1, 7, 20, 3, 14, 21, 4,135, 14, 17,184, 12,188, 21, 9,169, 10,189, 21, 0, 8, 9, 20, 78, 13, 7, 8, 11, 70, 22, 16,252,
+236, 50,244, 60,236, 49, 0, 47,252,236, 16,228,244,196,236, 17, 18, 23, 57, 48,180, 96, 23,207, 23, 2, 1, 93, 33, 17, 52, 38,
+ 35, 34, 6, 21, 17, 33, 21, 33, 17, 51, 21, 62, 1, 51, 50, 22, 21, 17, 3,172,124,124,149,172, 2,241,252, 86,185, 66,179,117,
+193,198, 2,158,159,158,190,164,252,140,175, 6, 10,174,101,100,239,232,253, 92, 0, 2, 0,186,254, 86, 5, 54, 4,123, 0, 32,
+ 0, 41, 0,117, 64, 12, 43, 19, 1, 18, 18, 71, 7, 11, 8, 9, 70, 42, 16,252,236, 50,244,236,220,196,179, 36, 18, 29, 7, 16,
+220,252,179, 33, 18, 21, 18, 16,212,236,178, 0, 33, 36, 73, 83, 88,179, 29, 9, 36, 7, 16, 60, 16, 60, 89, 49, 64, 15, 38,185,
+ 25,140, 42, 4,185, 12, 15,184, 11,188, 9,189, 42, 0, 16,236,228,244,196,236, 16,244,236, 64, 6, 18, 1,169, 21, 33, 38, 16,
+220, 60,252, 60,178, 0, 4, 1, 73, 83, 88,181, 18, 1,169, 21, 33, 38, 16, 60, 60,252, 60, 89, 48, 1, 51, 52, 38, 35, 34, 6,
+ 21, 17, 35, 17, 51, 21, 62, 1, 51, 50, 0, 17, 51, 21, 35, 6, 7, 6, 7, 6, 39, 38, 53, 52, 55, 54, 5, 35, 34, 23, 22, 51,
+ 50, 55, 54, 3, 35,194,167,146,146,167,185,185, 58,177,123,204, 0,255,146,162, 29, 53, 96,172,160, 52,120, 66,100, 1, 66,152,
+159, 5, 5,139, 74, 52, 28, 2, 47,203,231,231,203,252, 39, 6, 10,170,100, 97,254,188,254,248,175,161, 90,161, 1, 2, 43,104,
+124,123, 78,118,175,144,113,113, 60, 0, 0, 0, 0, 2, 0,113,255,227, 5, 47, 6, 20, 0, 12, 0, 31, 0, 52, 64, 13, 33, 30,
+ 0, 27, 8, 13, 29, 71, 5, 18, 21, 69, 32, 16,252,236,244, 60,236, 50,220,196, 49, 64, 14, 8,185, 18,140, 32, 31, 0,169, 26,
+ 29,188, 28,151, 32, 0, 16,228,244, 60,252, 60, 16,244,236, 48, 1, 33, 34, 7, 6, 21, 20, 22, 51, 50, 55, 54, 53, 19, 17, 16,
+ 5, 6, 35, 34, 2, 17, 52, 55, 54, 51, 33, 17, 51, 17, 51, 21, 3,162,254,198,136, 98, 79,167,146,154, 77, 83,184,254,236, 75,
+149,246,255,127,125,249, 1, 60,184,213, 3,182,122, 97,172,203,231,107,115,212, 1,135,254, 67,254,175,154, 43, 1, 68, 1, 8,
+223,171,167, 1,180,254, 76,170, 0, 1, 0,186,254, 86, 4,100, 6, 20, 0, 19, 0, 53, 64, 26, 3, 9, 0, 3, 14, 1, 6,135,
+ 14, 17,184, 12,151, 10,189, 1, 2, 8, 0, 78, 13, 9, 8, 11, 70, 20, 16,252,236, 50,244,236, 49, 0, 47,236,236,244,196,236,
+ 17, 18, 23, 57, 48,178, 96, 21, 1, 1, 93, 1, 17, 35, 17, 52, 38, 35, 34, 6, 21, 17, 35, 17, 51, 17, 62, 1, 51, 50, 22, 4,
+100,184,124,124,149,172,185,185, 66,179,117,193,198, 2,164,253, 92, 2,158,159,158,190,164,251,221, 7,190,253,158,101,100,239,
+ 0, 1, 0,193,254, 86, 2,215, 4, 96, 0, 5, 0, 32, 64, 7, 7, 1, 5, 8, 3, 70, 6, 16,252,252,212,196, 49, 0, 64, 8,
+ 4,188, 6, 0,169, 3,189, 6, 16,244,228, 16,228, 48, 1, 33, 21, 33, 17, 51, 1,121, 1, 94,253,234,184,254,248,162, 6, 10,
+ 0, 1, 0,186,254, 86, 7, 28, 6, 20, 0, 40, 0,105, 64, 15, 32, 29, 8, 31, 80, 40, 8, 20, 80, 8, 11, 8, 9, 70, 41, 16,
+252,236, 50,244,252,244,252, 60, 49, 64, 18, 4,135, 12, 16,184, 31, 25,135, 33, 36,140, 29,188, 10,151, 8,189, 31, 0, 47,236,
+228,228,244,196,236, 16,244,196,236,181, 40, 21, 28, 3, 33, 29, 17, 18, 23, 57,181, 20, 0, 7, 3, 12, 32, 17, 18, 23, 57, 48,
+ 64, 19, 48, 41, 80, 41,112, 41,144, 41,160, 41,160, 41,191, 41,223, 41,255, 41, 9, 1, 93, 1, 52, 39, 38, 35, 34, 6, 21, 17,
+ 35, 17, 51, 17, 54, 55, 54, 51, 50, 23, 22, 29, 1, 20, 23, 22, 51, 50, 54, 53, 17, 51, 17, 35, 53, 14, 1, 35, 34, 39, 38, 53,
+ 3,143, 62, 62,124,120,172,185,185, 99, 38, 89,107,193, 99, 99, 62, 56,110,140,173,184,184, 67,177,108,175, 98,100, 2,158,159,
+ 79, 79,190,164,251,221, 7,190,253,158,129, 22, 50,119,120,232,227,151, 88, 79,190,164, 2,123,251,160,172,102, 99,120,123,228,
+ 0, 2, 0,113,255,226, 4,188, 6, 20, 0, 14, 0, 48, 0, 92, 64, 11, 50, 32, 12, 18, 36, 71, 5, 18, 44, 69, 49, 16,252,236,
+244,236,220,196,180, 18, 18, 27, 23, 44, 16,220,220,236, 49, 64, 17, 1, 32,169, 48, 31,188, 49, 24,169, 23,151, 49, 8,185, 40,
+140, 49, 0, 16,244,236, 16,244,236, 16,244, 60,252, 60, 48,180, 33, 30, 34, 29, 34, 5, 7, 16, 60, 60,181, 0, 17, 33, 15, 17,
+ 30, 16,236, 16,236,178, 14, 16, 0, 16, 60, 60, 1, 35, 34, 7, 6, 21, 20, 22, 51, 50, 55, 54, 55, 54, 39, 1, 39, 38, 53, 52,
+ 55, 54, 59, 1, 21, 35, 38, 23, 22, 31, 1, 33, 21, 33, 19, 22, 21, 20, 7, 6, 39, 38, 39, 38, 17, 52, 55, 54, 51, 2,195, 91,
+165, 65, 83,167,146,173, 93, 46, 3, 2, 23,254,221, 83, 22, 68, 56, 49,147, 78, 47, 1, 1, 15, 86, 1,144,254,201,174, 33,133,
+135,226,247,127,127,127,113,218, 3,182, 90,115,186,203,231,150, 73, 82, 92, 43, 2, 43,152, 40, 86, 76, 45, 37,175, 1, 41, 36,
+ 27,158,170,254,182, 63,137,166,141,143, 1, 1,161,162, 1, 8,235,174,152, 0, 0, 1, 0,174,254, 86, 4, 88, 6, 20, 0, 19,
+ 0, 58, 64, 28, 3, 9, 0, 3, 14, 10, 6,135, 14, 17,140, 1,151, 10,188, 12,189, 20, 13, 9, 8, 11, 78, 2, 8, 0, 70, 20,
+ 16,252,236,244,236, 50, 49, 0, 16,236,228,228,244,196,236, 17, 18, 23, 57, 48,180, 96, 21,207, 21, 2, 1, 93, 19, 17, 51, 17,
+ 20, 22, 51, 50, 54, 53, 17, 51, 17, 35, 17, 14, 1, 35, 34, 38,174,184,124,124,149,173,184,184, 67,177,117,193,200, 1,186, 4,
+ 90,251,173,159,159,190,164, 2,123,249,246, 2, 86,102, 99,240,255,255, 0,186, 0, 0, 4,100, 6, 20, 18, 6, 0, 75, 0, 0,
+ 0, 2, 0,113,255,227, 4, 90, 6, 20, 0, 11, 0, 52, 0,101, 64, 10, 18, 6, 8, 16, 71, 0, 18, 25, 69, 53, 16,252,236,244,
+252, 60, 64, 13, 40, 18, 39, 39, 42, 37, 37, 18, 42, 30, 18, 51, 16, 16,220,252,212,236, 17, 18, 57, 47,236,178, 12, 16, 28, 17,
+ 18, 57, 49, 64, 16, 46,169, 32, 9,185, 28,184, 18, 3,185, 19, 22,140, 39,151, 18, 0, 47,228,244,196,236, 16,244,236,220,236,
+178, 12, 9, 28, 17, 18, 57, 48, 64, 9, 96, 54,128, 54,160, 54,224, 54, 4, 1, 93, 1, 20, 22, 51, 50, 54, 53, 52, 38, 35, 34,
+ 6, 1, 22, 23, 22, 25, 1, 35, 53, 14, 1, 35, 34, 2, 17, 16, 0, 51, 50, 53, 38, 43, 1, 34, 39, 38, 53, 52, 55, 51, 6, 21,
+ 20, 23, 22, 59, 1, 50, 23, 22, 21, 20, 1, 47,167,146,146,168,168,146,146,167, 1,233,110, 68,144,184, 58,177,124,203,255, 1,
+ 0,202, 87, 1, 67,118, 62, 31, 30, 33,184, 37, 8, 17, 26,147, 55, 41, 29, 2, 47,203,231,231,203,203,231,231, 1,107, 29, 80,
+168,254,219,253,213,168,100, 97, 1, 68, 1, 8, 1, 8, 1, 69, 60, 54, 29, 29,112, 71, 53, 80, 48, 14, 7, 15, 44, 33, 75, 55,
+ 0, 1, 0,186,254, 86, 5, 57, 4,123, 0, 21, 0, 59, 64, 12, 23, 0, 3, 8, 21, 78, 9, 13, 8, 12, 70, 22, 16,252,236, 50,
+244,236,220,196, 49, 64, 13, 6,135, 14, 17,184, 12,188, 11, 0,169, 2,189, 11, 0, 47,252,236, 16,228,244,196,236,181, 9, 3,
+ 20, 3, 14, 10, 17, 18, 23, 57, 48, 1, 21, 33, 17, 52, 38, 35, 34, 6, 21, 17, 35, 17, 51, 21, 62, 1, 51, 50, 22, 21, 17, 5,
+ 57,254,115,124,124,149,172,185,185, 66,179,117,193,198,254,248,162, 4, 72,159,158,190,164,253,135, 4, 96,174,101,100,239,232,
+252, 84, 0, 0, 0, 2, 0,174,255,227, 4, 88, 6, 20, 0, 29, 0, 45, 0, 98, 64, 12, 2, 40, 8, 20, 0, 78, 32, 8, 14, 10,
+ 70, 46, 16,252, 60,236,244, 60,236, 50,182, 16, 13, 45, 26, 4, 0, 14, 17, 18, 23, 57,183, 25, 8, 16, 30, 8, 13, 16, 13, 7,
+ 16,236, 16,236, 1,176, 13, 47, 49, 64, 18, 37,135, 3, 6,140, 1, 30, 14,169, 25, 15,188, 1, 21,134, 20,151, 1, 0, 47,244,
+236, 16,244, 60,252, 60, 16,244,196,236,181, 33, 10, 40, 3, 15, 3, 17, 18, 23, 57, 48, 1, 17, 35, 53, 14, 1, 35, 34, 39, 38,
+ 61, 1, 52, 55, 35, 53, 51, 54, 55, 36, 55, 21, 6, 7, 6, 7, 51, 50, 23, 22, 37, 6, 29, 1, 20, 23, 22, 51, 50, 54, 61, 1,
+ 52, 39, 38, 35, 4, 88,184, 67,177,117,195, 98,100,122,122,218,112,152, 1, 27,173,141,221, 62, 66,105,176,130, 79,253,152,138,
+ 62, 65,121,149,173, 26, 99, 87, 2, 32,253,224,172,102, 99,120,123,228, 73,233,202,170,128, 96,174, 38,175, 36,132, 37, 56,195,
+118,143,198,229, 74,162, 77, 79,190,164, 59,207, 41,158, 0, 0, 0, 1, 0,174,255,227, 5, 10, 6, 20, 0, 43, 0, 63, 64, 15,
+ 45, 23, 17, 18, 28, 37, 9, 8, 36, 78, 2, 8, 0, 70, 44, 16,252,236,244,236, 50,220,236,220,196, 49, 64, 19, 0, 3, 9, 3,
+ 38, 1, 23,169, 22,151, 36, 6,135, 38, 41,140, 1,188, 36, 0, 47,228,244,196,236, 16,244,236, 17, 18, 23, 57, 48, 19, 17, 51,
+ 17, 20, 22, 51, 50, 54, 53, 17, 52, 39, 38, 47, 1, 38, 55, 54, 55, 54, 59, 1, 21, 35, 34, 7, 6, 21, 20, 31, 1, 22, 23, 22,
+ 21, 17, 35, 53, 14, 1, 35, 34, 38,174,184,124,124,149,173, 3, 3, 10, 77, 46, 1, 4, 61, 60,139,236,236, 40, 21, 24, 17, 96,
+ 19, 4, 7,184, 67,177,117,193,200, 1,186, 2,166,253, 97,159,159,190,164, 1,151, 19, 22, 32, 23,188,112, 48,129, 46, 45,175,
+ 9, 11, 23, 31, 42,243, 47, 23, 40, 20,252,132,172,102, 99,240,255,255,255,219,254, 86, 1,121, 4, 96, 18, 6, 1,249, 0, 0,
+ 0, 1, 0, 49,255,227, 5, 90, 6, 20, 0, 35, 0, 71, 64, 15, 37, 14, 11, 8, 12, 78, 3, 8, 22, 27, 33, 0, 18, 27, 36, 16,
+212,252,204, 16,220,236,244,236, 50,196, 49, 64, 23, 10, 4, 21, 3, 15, 12, 33,169, 32,151, 13, 22,169, 3, 12,188, 13, 7,135,
+ 15, 18,140, 13, 0, 47,244,196,236, 16,244, 60,236, 16,244,236, 17, 18, 23, 57, 48, 19, 20, 59, 1, 17, 20, 22, 51, 50, 54, 53,
+ 17, 51, 17, 35, 53, 14, 1, 35, 34, 38, 53, 17, 35, 34, 39, 38, 55, 54, 55, 54, 59, 1, 21, 35, 34,242,131,243,124,124,149,173,
+184,184, 67,177,117,193,200, 59,149, 94, 83, 3, 3, 87,115,118, 89, 89,131, 4,234,138,253, 97,159,159,190,164, 2,123,251,160,
+172,102, 99,240,231, 1,252, 94, 83,145,131, 66, 87,175, 0, 0, 0, 1, 0,159,254, 86, 3,150, 4,124, 0, 31, 0, 84, 64, 12,
+ 33, 69, 16, 18, 5, 29, 2, 18, 11, 22, 70, 32, 16,252, 60,236,212, 60,236,228, 49, 64, 13, 5,169, 6,189, 32, 22,134, 23, 20,
+185, 25,184, 32, 0, 16,244,236,212,236, 16,252,236, 48, 64, 10, 0, 31, 29, 31, 17, 0, 17, 13, 14, 13, 7, 5, 16,236,236, 1,
+ 73, 80, 88,177, 31, 29, 16, 60, 89,179, 30, 31, 14, 13, 7, 4, 16, 60, 5, 6, 21, 20, 51, 33, 21, 33, 34, 39, 38, 39, 38, 55,
+ 1, 54, 39, 38, 39, 38, 7, 6, 7, 53, 54, 23, 22, 23, 22, 21, 20, 7, 1,134, 14, 47, 1,238,253,195, 87, 58, 37, 2, 2, 38,
+ 1,205, 68, 1, 1, 47, 67,141,120,188,188,161,195,132, 81, 69,192, 19, 21, 32,162, 69, 44, 65, 56, 56, 2,173,102, 93, 68, 64,
+ 90, 1, 1,120,198,106, 1, 1,170,104,136,154,101, 0, 0, 0,255,255, 0,186, 0, 0, 4,100, 4,123, 18, 6, 0, 81, 0, 0,
+ 0, 1, 0, 70,254, 86, 3, 59, 4, 96, 0, 37, 0, 88, 64, 17, 16, 18, 35, 35, 5, 26, 39, 5, 11, 26, 30, 18, 21, 2, 18, 11,
+ 38, 16,212,236,220,236,204, 16,220,196, 17, 18, 57, 47,236, 49, 64, 14, 35, 16, 5, 27, 27,169, 26,188, 38, 5,169, 6,189, 38,
+ 0, 16,252,236, 16,244,236, 17, 18, 57, 57, 48,182, 37, 17, 0, 17, 13, 14, 13, 7, 4, 16,236,236,182, 19, 17, 18, 17, 32, 33,
+ 32, 7, 4, 16,236,236, 5, 6, 21, 20, 51, 33, 21, 33, 34, 39, 38, 53, 52, 55, 1, 54, 55, 54, 47, 1, 38, 53, 52, 55, 54, 59,
+ 1, 21, 35, 38, 21, 20, 31, 1, 22, 21, 20, 7, 1, 40, 14, 51, 1,238,253,195, 87, 58, 39, 36, 1, 70, 31, 1, 2, 91,149, 76,
+ 22, 50,214,115,101, 96, 54,142,103, 43,182, 17, 33, 32,162, 69, 47, 62, 65, 47, 1,173, 40, 60, 69, 99,163, 83,101, 40, 50,122,
+175, 1, 58, 46, 59,155,112,110,117, 57, 0, 0,255,255, 0, 0, 0, 0, 0, 0, 0, 0, 16, 6, 2, 6, 0, 0, 0, 2, 0,159,
+254, 86, 3,150, 4,123, 0, 27, 0, 41, 0, 99, 64, 14, 43, 69, 40, 18, 5, 25, 2, 18, 11, 34, 18, 17, 69, 42, 16,252,236, 60,
+236,212, 60,236,228, 49, 64, 10, 5,169, 6,189, 42, 30,185, 21,184, 42, 0, 16,244,236, 16,252,236, 48, 64, 11, 26, 27, 27, 17,
+ 0, 17, 37, 14, 13, 38, 13, 7, 5, 16, 60, 60,236,236, 4, 16, 60,178, 0, 27, 25, 1, 73, 80, 88,177, 27, 25, 16, 60, 89, 64,
+ 9, 37, 17, 36, 17, 14, 38, 13, 15, 14, 7, 8, 16,236,236, 5, 6, 21, 20, 51, 33, 21, 33, 34, 39, 38, 39, 38, 63, 1, 3, 38,
+ 53, 52, 55, 54, 51, 50, 23, 22, 21, 20, 7, 3, 38, 35, 34, 7, 6, 21, 20, 23, 27, 1, 54, 39, 38, 1,134, 14, 47, 1,238,253,
+195, 87, 58, 37, 2, 2, 38,145,141, 40, 96, 91,175,212,115, 68, 69,159, 72,100, 59, 54, 59, 33, 88,191, 68, 1, 1,192, 19, 21,
+ 32,162, 69, 44, 65, 55, 57,217, 1,228,137, 70,163,109,103,171,101,139,154,101, 1,139, 89, 45, 49,103, 60,120,254,191, 1, 26,
+101, 94, 89, 0, 0, 1, 0,186, 0, 0, 4,116, 4,123, 0, 28, 0,103, 64, 13, 28, 9, 2, 18, 25, 21, 78, 13, 9, 8, 11, 70,
+ 29, 16,252,236, 50,244, 60,236, 16,220, 49, 64, 12, 6,135, 14, 17,184, 12,188, 28, 25,169, 26, 10, 0, 47, 60,236, 50,228,244,
+196,236,181, 21, 2, 9, 3, 14, 10, 17, 18, 23, 57, 48,177, 23, 0, 16, 60, 64, 8, 23, 17, 0, 24, 17, 28, 0, 28, 7, 5, 16,
+236, 16,236, 1,178, 0, 23, 21, 73, 80, 88,177, 23, 21, 16, 60, 89,180, 96, 30,207, 30, 2, 1, 93, 1, 54, 55, 54, 39, 38, 35,
+ 34, 6, 21, 17, 35, 17, 51, 21, 62, 1, 51, 50, 23, 22, 21, 20, 7, 1, 33, 21, 33, 53, 3, 82, 90, 1, 1, 64, 62,124,149,172,
+185,185, 66,179,117,205,127, 65, 71,254,250, 1, 87,253,223, 1,232,110,132, 96, 82, 79,190,164,253,135, 4, 96,174,101,100,185,
+ 94,119,176, 85,254,199,175,175,255,255, 0,174,255,227, 4, 88, 4, 96, 18, 6, 0, 88, 0, 0, 0, 1, 0,174,254, 86, 5, 45,
+ 6, 20, 0, 21, 0, 61, 64, 12, 23, 13, 15, 9, 8, 11, 78, 2, 8, 0, 70, 22, 16,252,236,244,236, 50,220,196, 49, 64, 21, 3,
+ 9, 0, 3, 16, 1, 6,135, 16, 19,140, 10,151, 1,188, 22, 13,169, 15,189, 22, 0, 16,252,236, 16,228,228,244,196,236, 17, 18,
+ 23, 57, 48, 19, 17, 51, 17, 20, 22, 51, 50, 54, 53, 17, 51, 17, 51, 21, 33, 17, 14, 1, 35, 34, 38,174,184,124,124,149,173,184,
+213,254,115, 67,177,117,193,200, 1,186, 2,166,253, 97,159,159,190,164, 4, 47,248,228,162, 2, 86,102, 99,240, 0, 1, 0,174,
+255,227, 7, 28, 4,123, 0, 37, 0,105, 64, 15, 12, 8, 10, 80, 21, 1, 8, 2, 20, 80, 31, 8, 29, 70, 38, 16,252,236,252, 60,
+252, 60,252,236, 49, 64, 17, 15,135, 3, 6,184, 10, 34,135, 22, 25,140, 10, 1, 29,188, 20, 10, 0, 47, 60,244, 60, 16,244,196,
+236, 16,244,196,236,181, 28, 31, 0, 3, 22, 29, 17, 18, 23, 57,181, 9, 12, 19, 3, 3, 10, 17, 18, 23, 57, 48, 64, 19, 48, 39,
+ 80, 39,112, 39,144, 39,160, 39,160, 39,191, 39,223, 39,255, 39, 9, 1, 93, 1, 17, 51, 21, 62, 1, 51, 50, 22, 21, 17, 35, 17,
+ 52, 38, 35, 34, 7, 6, 21, 17, 35, 53, 14, 1, 35, 34, 38, 53, 17, 51, 17, 20, 22, 51, 50, 55, 54, 3,143,184, 66,179, 89,193,
+198,184,124,124,122, 85, 86,184, 67,177,100,193,200,184,124,124,130, 88, 87, 1,229, 2,123,174,101,100,239,232,253, 92, 2,158,
+159,158, 95, 96,163,253,135,172,102, 99,240,231, 2,166,253, 97,159,159, 95, 92, 0, 1, 0,186,254, 86, 4,100, 4,123, 0, 19,
+ 0, 55, 64, 26, 3, 9, 0, 3, 14, 1, 6,135, 14, 17,184, 12,188, 10,189, 1, 2, 8, 0, 78, 13, 9, 8, 11, 70, 20, 16,252,
+236, 50,244,236, 49, 0, 47,236,228,244,196,236, 17, 18, 23, 57, 48,180, 96, 21,207, 21, 2, 1, 93, 1, 17, 35, 17, 52, 38, 35,
+ 34, 6, 21, 17, 35, 17, 51, 21, 62, 1, 51, 50, 22, 4,100,184,124,124,149,172,185,185, 66,179,117,193,198, 2,164,253, 92, 2,
+158,159,158,190,164,251,221, 6, 10,174,101,100,239, 0, 0, 0,255,255, 0,113,254, 86, 4, 90, 4,123, 18, 6, 0, 74, 0, 0,
+ 0, 1, 0,193, 0, 0, 2,215, 4, 96, 0, 5, 0, 29, 64, 7, 7, 1, 5, 8, 3, 70, 6, 16,252,252,212,196, 49, 0, 64, 6,
+ 4,188, 3, 1,169, 2, 47,236, 16,228, 48, 37, 33, 21, 33, 17, 51, 1,121, 1, 94,253,234,184,175,175, 4, 96, 0, 1, 0,174,
+254, 86, 7, 28, 6, 20, 0, 37, 0,107, 64, 15, 12, 8, 10, 80, 21, 1, 8, 2, 20, 80, 31, 8, 29, 70, 38, 16,252,236,252, 60,
+252, 60,252,236, 49, 64, 19, 15,135, 3, 6,184, 10, 34,135, 22, 25,140, 10, 29,188, 1,151, 20,189, 10, 0, 47,236,228,244, 16,
+244,196,236, 16,244,196,236,181, 28, 31, 0, 3, 22, 29, 17, 18, 23, 57,181, 9, 12, 19, 3, 3, 10, 17, 18, 23, 57, 48, 64, 19,
+ 48, 39, 80, 39,112, 39,144, 39,160, 39,160, 39,191, 39,223, 39,255, 39, 9, 1, 93, 1, 17, 51, 17, 62, 1, 51, 50, 22, 21, 17,
+ 35, 17, 52, 38, 35, 34, 7, 6, 21, 17, 35, 17, 14, 1, 35, 34, 38, 53, 17, 51, 17, 20, 22, 51, 50, 55, 54, 3,143,184, 66,179,
+ 89,193,198,184,124,124,118, 89, 86,184, 67,177,100,193,200,184,124,124,130, 88, 87, 1,229, 4, 47,253,158,101,100,239,232,253,
+ 92, 2,158,159,158, 95, 92,167,251,221, 2, 86,102, 99,240,231, 2,166,253, 97,159,159, 95, 92, 0, 2, 0, 0,254, 86, 4,191,
+ 4,123, 0, 24, 0, 36, 0, 85, 64, 16, 38, 69, 11, 19, 25, 18, 11, 71, 31, 22, 4, 18, 8, 23, 2, 1, 47,220, 60,236, 50, 50,
+ 50,244,236,196, 16,228, 49, 64, 22, 34,185, 17, 14, 28,185, 5, 8,184, 14,140, 37, 20, 24,169, 18, 2, 22,189, 3,188, 37, 0,
+ 16,228,236,220, 60,252, 60, 16,228,244,196,236, 16,196,238,178, 0, 22, 24, 73, 80, 88,177, 22, 24, 16, 60, 89, 48, 21, 53, 51,
+ 17, 51, 21, 62, 1, 51, 50, 0, 17, 16, 2, 35, 34, 38, 39, 17, 33, 21, 33, 21, 35, 53, 1, 52, 38, 35, 34, 6, 21, 20, 22, 51,
+ 50, 54,213,185, 58,177,123,204, 0,255,255,204,123,177, 58, 2,233,253, 23,185, 3, 43,167,146,146,167,167,146,146,167,250,150,
+ 4,196,170,100, 97,254,188,254,248,254,248,254,188, 97,100,254,244,150,176,176, 3, 41,203,231,231,203,203,231,231, 0, 0, 0,
+255,255, 0,113,255,227, 4,117, 4,123, 18, 6, 0, 82, 0, 0, 0, 3, 0,122,254, 86, 4,150, 6, 43, 0, 34, 0, 45, 0, 54,
+ 0,117, 64, 17, 56, 51, 18, 28, 32, 22, 46, 8, 0, 35, 10, 42, 18, 5, 14, 69, 55, 16,252, 60,236,220, 60, 60,252, 60, 60,220,
+236,196, 49, 64, 18, 5,134, 4, 38,185, 18,151, 55, 47, 9,135, 4, 32, 0,140, 34,189, 55, 0, 16,236,244, 60,196,236, 50, 16,
+244,236, 16,236,179, 23, 35, 0, 18, 17, 18, 57, 57,178, 14, 35, 18, 17, 18, 57,182, 26, 51, 46, 10, 4, 32, 23, 17, 18, 23, 57,
+ 48,180, 23, 35, 24, 24, 44, 7, 4, 16, 60, 60,181, 46, 17, 23, 10, 17, 35, 16,236, 16,236, 5, 38, 39, 38, 39, 53, 22, 23, 22,
+ 23, 17, 38, 39, 38, 53, 52, 55, 54, 55, 54, 23, 22, 21, 17, 23, 22, 23, 22, 21, 16, 7, 6, 35, 17, 35, 25, 1, 52, 39, 38, 7,
+ 6, 21, 22, 23, 22, 5, 17, 50, 55, 54, 53, 52, 39, 38, 2, 44, 68,100,125,141, 49,211, 75, 99,231,102,101,112, 95,152,123, 53,
+ 83, 35,194, 97,108,146,126,162,184, 69, 85, 24, 64, 1, 59, 39, 1, 71, 93, 55, 95, 69, 56, 24, 2, 17, 21, 71,187, 31, 73, 26,
+ 1, 2,163, 45, 97, 96,165,147,113, 96, 1, 2, 52, 79,148,254,169, 7, 45, 98,108,235,254,218,105, 90,254,110, 5,141, 1, 33,
+115, 3, 2, 29, 79, 59,115, 58, 36,246,253,129, 43, 73,191,179, 74, 62, 0, 0, 0, 1, 0,174,255,227, 5,182, 6, 20, 0, 21,
+ 0, 56, 64, 12, 23, 13, 15, 9, 8, 11, 78, 2, 8, 0, 70, 22, 16,252,236,244,236, 50,220,196, 49, 64, 18, 3, 9, 0, 3, 16,
+ 10, 6,135, 16, 19,140, 1,151, 10,188, 13,169, 15, 0, 47,236,228,228,244,196,236, 17, 18, 23, 57, 48, 19, 17, 51, 17, 20, 22,
+ 51, 50, 54, 53, 17, 51, 17, 33, 21, 33, 53, 14, 1, 35, 34, 38,174,184,124,124,149,173,184, 1, 94,253,234, 67,177,117,193,200,
+ 1,186, 4, 90,251,173,159,159,190,164, 2,123,252, 79,175,172,102, 99,240, 0, 0, 2, 0,240, 0, 0, 1,195, 3, 82, 0, 3,
+ 0, 7, 0, 29, 64, 7, 5, 1, 3, 4, 0, 24, 8, 16,252, 60,236, 50, 49, 0, 64, 6, 6,131, 4, 0,131, 2, 47,236, 47,236,
+ 48, 55, 51, 21, 35, 17, 51, 21, 35,240,211,211,211,211,254,254, 3, 82,254, 0, 0, 1, 0, 96, 1,164, 3, 33, 2,238, 0, 11,
+ 0, 0, 1, 30, 1, 55, 21, 14, 1, 34, 38, 39, 51, 22, 1, 85, 32,222,205, 44,228,255,157, 20,167, 16, 2, 99, 24, 1, 65,162,
+ 14, 55,170,159, 87, 0, 0, 0, 0, 1, 0,219, 0, 0, 2, 0, 1,236, 0, 5, 0, 0, 33, 35, 53, 19, 51, 3, 1,174,211,164,
+129, 82,172, 1, 64,254,192, 0,255,255, 0, 16,253, 46, 5,104, 5,213, 16, 39, 2, 70, 0,183, 0, 0, 18, 2, 0, 36, 0, 0,
+255,255, 0,123,253, 46, 4, 45, 4,123, 16, 38, 2, 70,107, 0, 18, 2, 0, 68, 0, 0, 0, 0,255,255, 0,201, 0, 0, 4,236,
+ 7, 80, 18, 34, 0, 37, 0, 0, 16, 3, 2, 50, 0,173, 1, 64,255,255, 0,186,255,227, 4,164, 7,133, 16, 39, 2, 79, 3, 22,
+ 1,117, 18, 6, 0, 69, 0, 0,255,255, 0,201,254,135, 4,236, 5,213, 18, 34, 0, 37, 0, 0, 16, 3, 2,107, 4,165, 0, 0,
+255,255, 0,186,254,135, 4,164, 6, 20, 18, 34, 0, 69, 0, 0, 16, 3, 2,107, 4,154, 0, 0,255,255, 0,201,254,192, 4,236,
+ 5,213, 18, 34, 0, 37, 0, 0, 16, 3, 2, 38, 0,151, 0, 0,255,255, 0,186,254,192, 4,164, 6, 20, 18, 34, 0, 69, 0, 0,
+ 16, 3, 2, 38, 0,143, 0, 0,255,255, 0,115,254,117, 5, 39, 7,107, 18, 34, 0,137, 0, 0, 16, 67, 0,118, 0,254, 2,240,
+ 64, 0, 44,204,255,255, 0,113,254,117, 3,231, 6,102, 18, 34, 0,169, 0, 0, 16, 2, 0,118, 67, 0, 0, 0,255,255, 0,201,
+ 0, 0, 5,176, 7, 80, 18, 34, 0, 39, 0, 0, 16, 3, 2, 50, 0,253, 1, 64,255,255, 0,113,255,227, 4,110, 7,133, 16, 39,
+ 2, 79, 5,254, 1,117, 18, 6, 0, 71, 0, 0,255,255, 0,201,254,135, 5,176, 5,213, 16, 35, 2,107, 4,174, 0, 0, 16, 2,
+ 0, 39, 0, 0,255,255, 0,113,254,135, 4, 90, 6, 20, 16, 35, 2,107, 4,122, 0, 0, 16, 2, 0, 71, 0, 0,255,255, 0,201,
+254,192, 5,176, 5,213, 18, 34, 0, 39, 0, 0, 16, 3, 2, 38, 0,232, 0, 0,255,255, 0,113,254,192, 4, 90, 6, 20, 18, 34,
+ 0, 71, 0, 0, 16, 2, 2, 38, 79, 0, 0, 0,255,255, 0,201,254,119, 5,176, 5,213, 18, 34, 0, 39, 0, 0, 16, 2, 0,122,
+ 91, 2, 0, 0,255,255, 0,113,254,117, 4, 90, 6, 20, 18, 34, 0, 71, 0, 0, 16, 2, 0,122,246, 0, 0, 0,255,255, 0,201,
+254, 24, 5,176, 5,213, 16, 39, 2, 31, 0,166,249, 42, 18, 6, 0, 39, 0, 0,255,255, 0,113,254, 24, 4, 90, 6, 20, 16, 39,
+ 2, 31, 0, 94,249, 42, 18, 6, 0, 71, 0, 0,255,255, 0,201, 0, 0, 4,139, 5,213, 18, 34, 0, 40, 0, 0, 16, 6, 6,149,
+238, 0, 0, 0,255,255, 0,113,255,227, 4,127, 4,123, 16, 39, 6,149,255,217,255, 4, 16, 6, 0, 72, 0, 0,255,255, 0,201,
+ 0, 0, 4,139, 5,213, 18, 34, 0, 40, 0, 0, 16, 6, 6,148,236, 0, 0, 0,255,255, 0,113,255,227, 4,127, 4,123, 16, 38,
+ 0, 72, 0, 0, 16, 7, 6,148,255,215,255, 4,255,255, 0,201,253,221, 4,139, 5,213, 18, 34, 0, 40, 0, 0, 16, 3, 2,117,
+ 4,177, 0, 0,255,255, 0,113,253,221, 4,127, 4,123, 18, 34, 0, 72, 0, 0, 16, 3, 2,117, 4,176, 0, 0,255,255, 0,201,
+254,118, 4,139, 5,213, 18, 34, 0, 40, 0, 0, 16, 3, 2, 71, 0,179, 0, 0,255,255, 0,113,254,118, 4,127, 4,123, 18, 34,
+ 0, 72, 0, 0, 16, 3, 2, 71, 0,155, 0, 0,255,255, 0,201,254,117, 4,139, 7,102, 18, 34, 0, 40, 0, 0, 16, 99, 2, 49,
+ 0,218, 1,190, 64, 0, 57,153, 16, 3, 0,122, 0,190, 0, 0,255,255, 0,113,254,117, 4,127, 6, 72, 18, 34, 0, 72, 0, 0,
+ 16, 35, 2, 49, 0,135, 0, 0, 16, 2, 0,122, 75, 0, 0, 0,255,255, 0,201, 0, 0, 4, 35, 7, 80, 18, 34, 0, 41, 0, 0,
+ 16, 3, 2, 50, 0,118, 1, 64,255,255, 0, 47, 0, 0, 2,248, 7, 80, 18, 34, 0, 73, 0, 0, 16, 3, 2, 50, 0, 12, 1, 64,
+255,255, 0,115,255,227, 5,139, 7, 24, 18, 34, 0, 42, 0, 0, 16, 3, 2, 34, 1, 50, 1, 34,255,255, 0,113,254, 86, 4, 90,
+ 5,246, 18, 34, 0, 74, 0, 0, 16, 2, 2, 34, 73, 0, 0, 0,255,255, 0,201, 0, 0, 5, 59, 7, 80, 18, 34, 0, 43, 0, 0,
+ 16, 3, 2, 50, 1, 20, 1, 64,255,255, 0,186, 0, 0, 4,100, 7,133, 16, 39, 2, 79, 3, 22, 1,117, 18, 6, 0, 75, 0, 0,
+255,255, 0,201,254,135, 5, 59, 5,213, 16, 35, 2,107, 5, 2, 0, 0, 16, 2, 0, 43, 0, 0,255,255, 0,186,254,135, 4,100,
+ 6, 20, 16, 35, 2,107, 4,143, 0, 0, 16, 2, 0, 75, 0, 0,255,255, 0,201, 0, 0, 5, 59, 7, 80, 18, 34, 0, 43, 0, 0,
+ 16, 3, 0,106, 1, 8, 1, 64,255,255,255,235, 0, 0, 4,100, 7,133, 16, 39, 2, 80, 3, 22, 1,117, 18, 6, 0, 75, 0, 0,
+255,255, 0, 17,254,116, 5, 59, 5,213, 18, 34, 0, 43, 0, 0, 16, 3, 0,122,254,238,255,255,255,255, 0, 2,254,116, 4,100,
+ 6, 20, 18, 34, 0, 75, 0, 0, 16, 3, 0,122,254,223,255,255,255,255, 0,201,254, 57, 5, 59, 5,213, 18, 34, 0, 43, 0, 0,
+ 16, 3, 2,118, 5, 10, 0, 0,255,255, 0,186,254, 57, 4,100, 6, 20, 18, 34, 0, 75, 0, 0, 16, 3, 2,118, 4,149, 0, 0,
+255,255, 0, 0,254,118, 2,148, 5,213, 18, 34, 0, 44, 0, 0, 16, 3, 2, 71,255, 74, 0, 0,255,255, 0, 39,254,118, 2, 56,
+ 6, 20, 18, 34, 0, 76, 0, 0, 16, 66, 2, 71,150, 0, 51, 51, 64, 0, 0, 0,255,255, 0,201, 0, 0, 1,147, 5,213, 18, 34,
+ 0, 44, 0, 0, 16, 7, 6,146,254,116, 0, 0,255,255, 0,193, 0, 0, 1,121, 4, 96, 18, 34, 0,243, 0, 0, 16, 7, 6,146,
+254, 97,254,188,255,255, 0,201, 0, 0, 5,106, 7,107, 18, 34, 0, 46, 0, 0, 16, 67, 0,118, 0,164, 2,240, 64, 0, 44,204,
+255,255, 0,186, 0, 0, 4,156, 6, 20, 16, 39, 6,133, 3, 90, 1,118, 18, 2, 0, 78, 0, 0,255,255, 0,201,254,135, 5,106,
+ 5,213, 18, 34, 0, 46, 0, 0, 16, 3, 2,107, 4,220, 0, 0,255,255, 0,186,254,135, 4,156, 6, 20, 18, 34, 0, 78, 0, 0,
+ 16, 3, 2,107, 4,145, 0, 0,255,255, 0,201,254,192, 5,106, 5,213, 18, 34, 0, 46, 0, 0, 16, 3, 2, 38, 1, 13, 0, 0,
+255,255, 0,186,254,192, 4,156, 6, 20, 18, 34, 0, 78, 0, 0, 16, 2, 2, 38,118, 0, 0, 0,255,255, 0,201,254,135, 4,106,
+ 5,213, 16, 35, 2,107, 4,154, 0, 0, 16, 2, 0, 47, 0, 0,255,255, 0,182,254,135, 1,131, 6, 20, 16, 35, 2,107, 3, 28,
+ 0, 0, 16, 2, 0, 79, 0, 0,255,255, 0, 3,254,136, 4,106, 7,107, 16, 39, 2, 76, 3, 42, 1,117, 16, 39, 2,107, 4,153,
+ 0, 1, 18, 6, 0, 47, 0, 0,255,255,255,241,254,135, 2, 72, 7, 49, 16, 35, 0,113,255, 28, 1, 59, 16, 2, 4,179, 0, 0,
+255,255, 0,201,254,192, 4,106, 5,213, 18, 34, 0, 47, 0, 0, 16, 3, 2, 38, 0,142, 0, 0,255,255, 0, 39,254,192, 2, 7,
+ 6, 20, 18, 34, 0, 79, 0, 0, 16, 67, 2, 38,255,125, 0, 0, 51, 51, 64, 0,255,255, 0,201,254, 23, 4,106, 5,213, 16, 39,
+ 2, 31, 0,151,249, 41, 18, 6, 0, 47, 0, 0,255,255,255,222,254, 23, 2, 92, 6, 20, 16, 39, 2, 31,255, 29,249, 41, 18, 6,
+ 0, 79, 0, 0,255,255, 0,201, 0, 0, 6, 31, 7,107, 18, 34, 0, 48, 0, 0, 16, 67, 0,118, 1, 66, 2,240, 64, 0, 44,204,
+255,255, 0,186, 0, 0, 7, 29, 6,102, 18, 34, 0, 80, 0, 0, 16, 3, 0,118, 1,148, 0, 0,255,255, 0,201, 0, 0, 6, 31,
+ 7, 80, 18, 34, 0, 48, 0, 0, 16, 3, 2, 50, 1,119, 1, 64,255,255, 0,186, 0, 0, 7, 29, 6, 16, 16, 39, 2, 50, 2, 70,
+ 0, 0, 18, 6, 0, 80, 0, 0,255,255, 0,201,254,135, 6, 31, 5,213, 16, 35, 2,107, 5,116, 0, 0, 16, 2, 0, 48, 0, 0,
+255,255, 0,186,254,135, 7, 29, 4,123, 16, 35, 2,107, 5,230, 0, 0, 16, 2, 0, 80, 0, 0,255,255, 0,201, 0, 0, 5, 51,
+ 5,213, 16, 39, 6,140, 4,254, 1, 92, 18, 6, 0, 49, 0, 0,255,255, 0,186, 0, 0, 4,100, 5,193, 16, 39, 2, 50, 0,143,
+255,177, 18, 6, 0, 81, 0, 0,255,255, 0,201,254,135, 5, 51, 5,213, 16, 35, 2,107, 4,254, 0, 0, 16, 2, 0, 49, 0, 0,
+255,255, 0,186,254,135, 4,100, 4,123, 16, 35, 2,107, 4,143, 0, 0, 16, 2, 0, 81, 0, 0,255,255, 0,201,254,192, 5, 51,
+ 5,213, 18, 34, 0, 49, 0, 0, 16, 3, 2, 38, 0,247, 0, 0,255,255, 0,186,254,192, 4,100, 4,123, 18, 34, 0, 81, 0, 0,
+ 16, 3, 2, 38, 0,140, 0, 0,255,255, 0,201,254, 21, 5, 51, 5,213, 16, 39, 2, 31, 0,254,249, 39, 18, 6, 0, 49, 0, 0,
+255,255, 0,186,254, 21, 4,100, 4,123, 16, 39, 2, 31, 0,149,249, 39, 18, 6, 0, 81, 0, 0,255,255, 0,115,255,227, 5,217,
+ 5,240, 18, 34, 0, 50, 0, 0, 16, 6, 6,154,102, 0, 0, 0,255,255, 0,113,255,227, 4,117, 4,123, 18, 34, 0, 82, 0, 0,
+ 16, 7, 6,154,255,178,254,178,255,255, 0,115,255,227, 5,217, 5,240, 18, 34, 0, 50, 0, 0, 16, 6, 6,152,108, 0, 0, 0,
+255,255, 0,113,255,227, 4,117, 7, 15, 18, 34, 0, 82, 0, 0, 16, 39, 0,106, 0,111, 0,255, 16, 7, 6,134, 4,114, 0, 18,
+255,255, 0,115,255,227, 5,217, 5,240, 18, 34, 0, 50, 0, 0, 16, 6, 6,149,106, 0, 0, 0,255,255, 0,113,255,227, 4,117,
+ 4,123, 16, 38, 0, 82, 0, 0, 16, 7, 6,149,255,181,255, 4,255,255, 0,115,255,227, 5,217, 5,240, 18, 34, 0, 50, 0, 0,
+ 16, 6, 6,148,104, 0, 0, 0,255,255, 0,113,255,227, 4,117, 4,123, 16, 39, 6,148,255,185,255, 4, 16, 6, 0, 82, 0, 0,
+255,255, 0,201, 0, 0, 4,141, 7,107, 18, 34, 0, 51, 0, 0, 16, 67, 0,118, 0, 65, 2,240, 64, 0, 44,204,255,255, 0,186,
+254, 86, 4,164, 6,102, 18, 34, 0, 83, 0, 0, 16, 2, 0,118, 50, 0, 0, 0,255,255, 0,201, 0, 0, 4,141, 7, 80, 18, 34,
+ 0, 51, 0, 0, 16, 3, 2, 50, 0,132, 1, 64,255,255, 0,186,254, 86, 4,164, 6, 16, 16, 39, 2, 50, 0,217, 0, 0, 18, 6,
+ 0, 83, 0, 0,255,255, 0,201, 0, 0, 5, 84, 7, 80, 18, 34, 0, 53, 0, 0, 16, 3, 2, 50, 0,131, 1, 64,255,255, 0,186,
+ 0, 0, 3, 74, 6, 18, 18, 34, 0, 85, 0, 0, 16, 2, 2, 50, 19, 2, 0, 0,255,255, 0,201,254,135, 5, 84, 5,213, 16, 35,
+ 2,107, 4,125, 0, 0, 16, 2, 0, 53, 0, 0,255,255, 0,186,254,135, 3, 74, 4,123, 16, 35, 2,107, 3, 32, 0, 0, 16, 2,
+ 0, 85, 0, 0,255,255, 0,201,254,135, 5, 84, 7, 51, 16, 99, 0,113, 0,122, 1, 50, 64, 0, 64,110, 16, 2, 4,214, 0, 0,
+255,255, 0,186,254,135, 3, 74, 5,245, 16, 34, 0,113, 24,255, 16, 2, 4,215, 0, 0, 0, 0,255,255, 0,201,254,192, 5, 84,
+ 5,213, 18, 34, 0, 53, 0, 0, 16, 3, 2, 38, 0,229, 0, 0,255,255, 0, 84,254,192, 3, 74, 4,123, 18, 34, 0, 85, 0, 0,
+ 16, 3, 2, 38,255,127, 0, 0,255,255, 0,135,255,227, 4,162, 7, 80, 18, 34, 0, 54, 0, 0, 16, 3, 2, 50, 0,184, 1, 64,
+255,255, 0,111,255,227, 3,199, 6, 16, 16, 38, 2, 50, 37, 0, 18, 6, 0, 86, 0, 0, 0, 0,255,255, 0,135,254,135, 4,162,
+ 5,240, 16, 35, 2,107, 4,138, 0, 0, 16, 2, 0, 54, 0, 0,255,255, 0,111,254,135, 3,199, 4,123, 16, 35, 2,107, 4, 21,
+ 0, 0, 16, 2, 0, 86, 0, 0,255,255, 0,135,255,227, 4,162, 7,107, 18, 34, 0, 54, 0, 0, 16, 35, 2, 50,255,164, 1, 90,
+ 16, 67, 0,118, 0,242, 2,240, 64, 0, 44,204,255,255, 0,111,255,227, 3,226, 6,102, 18, 34, 0, 86, 0, 0, 16, 34, 2, 50,
+140, 86, 16, 3, 0,118, 0,144, 0, 0, 0, 0,255,255, 0,135,255,227, 4,162, 5,240, 16, 38, 6,153,228, 0, 18, 2, 0, 54,
+ 0, 0, 0, 0,255,255, 0,111,255,227, 3,199, 7,176, 16, 38, 1, 35, 0, 0, 16, 7, 2, 50, 0, 34, 1,160,255,255, 0,135,
+254,135, 4,162, 7, 80, 18, 34, 4,222, 0, 0, 16, 3, 2, 50, 0,155, 1, 64,255,255, 0,111,254,135, 3,199, 6, 18, 18, 34,
+ 4,223, 0, 0, 16, 2, 2, 50, 42, 2, 0, 0,255,255,255,250, 0, 0, 4,233, 7, 80, 18, 34, 0, 55, 0, 0, 16, 3, 2, 50,
+ 0,114, 1, 64,255,255, 0, 55, 0, 0, 2,242, 7, 47, 18, 34, 0, 87, 0, 0, 16, 3, 2, 50,255, 35, 1, 31,255,255,255,250,
+254,135, 4,233, 5,213, 16, 35, 2,107, 4,113, 0, 0, 16, 2, 0, 55, 0, 0,255,255, 0, 55,254,135, 2,242, 5,158, 16, 35,
+ 2,107, 3,232, 0, 0, 16, 2, 0, 87, 0, 0,255,255,255,250,254,192, 4,233, 5,213, 18, 34, 0, 55, 0, 0, 16, 2, 2, 38,
+ 98, 0, 0, 0,255,255, 0, 55,254,192, 2,242, 5,158, 18, 34, 0, 87, 0, 0, 16, 66, 2, 38, 60, 0, 51, 51, 64, 0, 0, 0,
+255,255,255,250,254, 21, 4,233, 5,213, 16, 39, 2, 31, 0,114,249, 39, 18, 6, 0, 55, 0, 0,255,255, 0, 55,254, 20, 3, 39,
+ 5,158, 16, 39, 2, 31,255,232,249, 38, 18, 6, 0, 87, 0, 0,255,255, 0,178,254,137, 5, 41, 5,213, 16, 35, 2,108, 4,240,
+ 0, 0, 18, 2, 0, 56, 0, 0,255,255, 0,174,254,137, 4, 88, 4, 96, 16, 35, 2,108, 4,123, 0, 0, 18, 2, 0, 88, 0, 0,
+255,255, 0,178,254,118, 5, 41, 5,213, 18, 34, 0, 56, 0, 0, 16, 3, 2, 71, 0,242, 0, 0,255,255, 0,174,254,118, 4, 88,
+ 4, 96, 18, 34, 0, 88, 0, 0, 16, 3, 2, 71, 0,143, 0, 0,255,255, 0,178,253,221, 5, 41, 5,213, 18, 34, 0, 56, 0, 0,
+ 16, 3, 2,117, 4,224, 0, 0,255,255, 0,174,253,221, 4, 88, 4, 96, 18, 34, 0, 88, 0, 0, 16, 3, 2,117, 4,117, 0, 0,
+255,255, 0,178,255,227, 5, 41, 5,213, 16, 38, 6,154, 46, 0, 18, 2, 0, 56, 0, 0, 0, 0,255,255, 0,174,255,227, 4, 88,
+ 7,236, 16, 38, 1, 43, 0, 0, 16, 7, 0,118, 0,150, 1,134,255,255, 0,178,255,227, 5, 41, 5,213, 16, 38, 6,144, 50, 0,
+ 18, 2, 0, 56, 0, 0, 0, 0,255,255, 0,174,255,227, 4, 88, 4, 96, 16, 39, 6,144,255,200,254,192, 18, 2, 0, 88, 0, 0,
+255,255, 0, 16, 0, 0, 5,104, 7,125, 18, 34, 0, 57, 0, 0, 16, 3, 2, 53, 0,237, 1, 70,255,255, 0, 61, 0, 0, 4,127,
+ 6, 55, 18, 34, 0, 89, 0, 0, 16, 2, 2, 53,109, 0, 0, 0,255,255, 0, 16,254,135, 5,104, 5,213, 16, 38, 0, 57, 0, 0,
+ 16, 7, 2,107, 4,188, 0, 0,255,255, 0, 61,254,135, 4,127, 4, 96, 16, 38, 0, 89, 0, 0, 16, 7, 2,107, 4, 94, 0, 0,
+255,255, 0, 68, 0, 0, 7,166, 5,213, 16, 39, 6,135, 5,245, 1,124, 18, 6, 0, 58, 0, 0,255,255, 0, 86, 0, 0, 6, 53,
+ 6,107, 16, 39, 0, 67, 1, 9, 0, 5, 18, 6, 0, 90, 0, 0,255,255, 0, 68, 0, 0, 7,166, 5,213, 16, 39, 6,133, 5,245,
+ 1,124, 18, 6, 0, 58, 0, 0,255,255, 0, 86, 0, 0, 6, 53, 6,109, 16, 39, 0,118, 1,134, 0, 7, 18, 6, 0, 90, 0, 0,
+255,255, 0, 68, 0, 0, 7,166, 7, 52, 16, 39, 0,106, 1,245, 1, 36, 18, 6, 0, 58, 0, 0,255,255, 0, 86, 0, 0, 6, 53,
+ 5,191, 16, 39, 0,106, 1, 69,255,175, 18, 6, 0, 90, 0, 0,255,255, 0, 68, 0, 0, 7,166, 7, 80, 18, 34, 0, 58, 0, 0,
+ 16, 3, 2, 50, 1,245, 1, 64,255,255, 0, 86, 0, 0, 6, 53, 6, 18, 18, 34, 0, 90, 0, 0, 16, 3, 2, 50, 1, 71, 0, 2,
+255,255, 0, 68,254,135, 7,166, 5,213, 18, 34, 0, 58, 0, 0, 16, 3, 2,107, 5,251, 0, 0,255,255, 0, 86,254,135, 6, 53,
+ 4, 96, 18, 34, 0, 90, 0, 0, 16, 3, 2,107, 5, 74, 0, 0,255,255, 0, 61, 0, 0, 5, 59, 7, 80, 18, 34, 0, 59, 0, 0,
+ 16, 3, 2, 50, 0,202, 1, 64,255,255, 0, 59, 0, 0, 4,121, 6, 18, 18, 34, 0, 91, 0, 0, 16, 2, 2, 50,103, 2, 0, 0,
+255,255, 0, 61, 0, 0, 5, 59, 7, 78, 18, 34, 0, 59, 0, 0, 16, 3, 0,106, 0,202, 1, 62,255,255, 0, 59, 0, 0, 4,121,
+ 6, 16, 18, 34, 0, 91, 0, 0, 16, 2, 0,106,102, 0, 0, 0,255,255,255,252, 0, 0, 4,231, 7, 80, 18, 34, 0, 60, 0, 0,
+ 16, 3, 2, 50, 0,112, 1, 64,255,255, 0, 61,254, 86, 4,127, 6, 16, 18, 34, 0, 92, 0, 0, 16, 2, 2, 50,102, 0, 0, 0,
+255,255, 0, 92, 0, 0, 5, 31, 7,107, 18, 34, 0, 61, 0, 0, 16, 67, 2, 31, 0,190, 2,240, 64, 0, 44,204,255,255, 0, 88,
+ 0, 0, 3,219, 6,102, 18, 34, 0, 93, 0, 0, 16, 2, 2, 31, 26, 0, 0, 0,255,255, 0, 92,254,135, 5, 31, 5,213, 18, 34,
+ 0, 61, 0, 0, 16, 3, 2,107, 4,217, 0, 0,255,255, 0, 88,254,135, 3,219, 4, 96, 18, 34, 0, 93, 0, 0, 16, 3, 2,107,
+ 4, 49, 0, 0,255,255, 0, 92,254,192, 5, 31, 5,213, 18, 34, 0, 61, 0, 0, 16, 3, 2, 38, 0,199, 0, 0,255,255, 0, 88,
+254,192, 3,219, 4, 96, 18, 34, 0, 93, 0, 0, 16, 2, 2, 38, 27, 0, 0, 0,255,255, 0,186,254,192, 4,100, 6, 20, 18, 34,
+ 0, 75, 0, 0, 16, 2, 2, 38,102, 0, 0, 0,255,255, 0, 4, 0, 0, 2,242, 7, 78, 18, 34, 0, 87, 0, 0, 16, 3, 0,106,
+255, 45, 1, 62,255,255, 0, 86, 0, 0, 6, 53, 7, 6, 18, 34, 0, 90, 0, 0, 16, 3, 2, 51, 1, 66, 0, 0,255,255, 0, 61,
+254, 86, 4,127, 7, 6, 18, 34, 0, 92, 0, 0, 16, 3, 2, 51, 0,129, 0, 0,255,255, 0,123,255,227, 5, 97, 6, 20, 18, 34,
+ 0, 68, 0, 0, 16, 3, 2, 23, 3,218, 0, 0,255,255, 0, 47, 0, 0, 2,248, 7, 80, 18, 34, 1, 65, 0, 0, 16, 3, 2, 50,
+255,253, 1, 64,255,255, 0, 16,254,135, 5,104, 5,213, 16, 35, 2,107, 4,183, 0, 0, 18, 2, 0, 36, 0, 0,255,255, 0,123,
+254,135, 4, 45, 4,123, 16, 35, 2,107, 4, 33, 0, 0, 18, 2, 0, 68, 0, 0,255,255, 0, 16, 0, 0, 5,104, 7,240, 18, 38,
+ 0, 36, 0, 0, 16, 7, 2, 81, 4,188, 1,117,255,255, 0,123,255,227, 4, 45, 6,123, 18, 38, 0, 68, 0, 0, 16, 7, 2, 81,
+ 4, 84, 0, 0,255,255, 0, 16, 0, 0, 5,104, 5,213, 18, 34, 0, 36, 0, 0, 16, 6, 6,155, 0, 0, 0, 0,255,255, 0,123,
+255,227, 4, 45, 4,123, 16, 39, 6,155,255,151,254,139, 16, 6, 0, 68, 0, 0,255,255, 0, 16, 0, 0, 5,104, 5,213, 18, 34,
+ 0, 36, 0, 0, 16, 6, 6,156, 0, 0, 0, 0,255,255, 0,123,255,227, 4, 45, 4,123, 16, 38, 0, 68, 0, 0, 16, 7, 6,156,
+255,148,254,140,255,255, 0, 16, 0, 0, 5,104, 5,213, 18, 34, 0, 36, 0, 0, 16, 6, 6,162, 0, 0, 0, 0,255,255, 0,123,
+255,227, 4, 45, 4,123, 16, 39, 6,162,255,150,254,139, 16, 6, 0, 68, 0, 0,255,255, 0, 16, 0, 0, 5,104, 5,213, 18, 34,
+ 0, 36, 0, 0, 16, 6, 6,157, 0, 0, 0, 0,255,255, 0,123,255,227, 4, 45, 4,123, 16, 39, 6,157,255,150,254,139, 16, 6,
+ 0, 68, 0, 0,255,255, 0, 16,254,135, 5,104, 5,213, 16, 35, 2,107, 4,175, 0, 0, 18, 2, 0,132, 0, 0,255,255, 0,123,
+254,135, 4, 45, 6,102, 18, 34, 0,164, 0, 0, 16, 3, 2,107, 4, 34, 0, 0,255,255, 0, 16, 0, 0, 5,104, 5,213, 18, 34,
+ 0, 36, 0, 0, 16, 6, 6,159, 0, 0, 0, 0,255,255, 0,123,255,227, 4, 45, 4,123, 16, 39, 6,159,255,145,254,170, 16, 6,
+ 0, 68, 0, 0,255,255, 0, 16, 0, 0, 5,104, 5,213, 18, 34, 0, 36, 0, 0, 16, 6, 6,160, 0, 0, 0, 0,255,255, 0,123,
+255,227, 4, 45, 4,123, 16, 39, 6,160,255,146,254,170, 16, 6, 0, 68, 0, 0,255,255, 0, 16, 0, 0, 5,104, 5,213, 18, 34,
+ 0, 36, 0, 0, 16, 6, 6,161, 0, 0, 0, 0,255,255, 0,123,255,227, 4, 45, 4,123, 16, 39, 6,161,255,148,254,170, 16, 6,
+ 0, 68, 0, 0,255,255, 0, 16, 0, 0, 5,104, 5,213, 18, 34, 0, 36, 0, 0, 16, 6, 6,158, 0, 0, 0, 0,255,255, 0,123,
+255,227, 4, 45, 4,123, 16, 38, 0, 68, 0, 0, 16, 7, 6,158,255,146,254,170,255,255, 0, 16,254,135, 5,104, 7,146, 18, 34,
+ 0,196, 0, 0, 16, 3, 2,107, 4,192, 0, 0,255,255, 0,123,254,135, 4, 45, 6, 31, 18, 34, 0,197, 0, 0, 16, 3, 2,107,
+ 4, 51, 0, 0,255,255, 0,201,254,135, 4,139, 5,213, 16, 38, 0, 40, 0, 0, 16, 7, 2,107, 4,158, 0, 0,255,255, 0,113,
+254,135, 4,127, 4,123, 16, 38, 0, 72, 0, 0, 16, 7, 2,107, 4,139, 0, 0,255,255, 0,201, 0, 0, 4,139, 7,240, 18, 38,
+ 0, 40, 0, 0, 16, 7, 2, 81, 4,158, 1,117,255,255, 0,113,255,227, 4,127, 6,123, 18, 38, 0, 72, 0, 0, 16, 7, 2, 81,
+ 4,141, 0, 0,255,255, 0,201, 0, 0, 4,139, 7, 69, 16, 99, 2, 53, 0,185, 2, 76, 64, 0, 51, 51, 18, 2, 0, 40, 0, 0,
+255,255, 0,113,255,227, 4,127, 6, 55, 16, 35, 2, 53, 0,151, 0, 0, 18, 2, 0, 72, 0, 0,255,255, 0,201, 0, 0, 4,139,
+ 5,213, 18, 34, 0, 40, 0, 0, 16, 6, 6,155, 0, 0, 0, 0,255,255, 0,113,255,227, 4,127, 4,123, 16, 39, 6,155,255,208,
+254,139, 16, 6, 0, 72, 0, 0,255,255, 0,201, 0, 0, 4,139, 5,213, 18, 34, 0, 40, 0, 0, 16, 6, 6,156,238, 0, 0, 0,
+255,255, 0,113,255,227, 4,127, 4,123, 16, 39, 6,156,255,208,254,140, 16, 6, 0, 72, 0, 0,255,255, 0,201, 0, 0, 4,139,
+ 5,213, 18, 34, 0, 40, 0, 0, 16, 6, 6,162,238, 0, 0, 0,255,255, 0,113,255,227, 4,127, 4,123, 16, 38, 0, 72, 0, 0,
+ 16, 7, 6,162,255,208,254,139,255,255, 0,201, 0, 0, 4,139, 5,213, 18, 34, 0, 40, 0, 0, 16, 6, 6,157,234, 0, 0, 0,
+255,255, 0,113,255,227, 4,127, 4,123, 16, 39, 6,157,255,209,254,139, 16, 6, 0, 72, 0, 0,255,255, 0,201,254,135, 4,139,
+ 5,213, 18, 34, 0,140, 0, 0, 16, 7, 2,107, 4,158, 0, 0,255,255, 0,113,254,135, 4,127, 6,102, 16, 39, 2,107, 4,139,
+ 0, 0, 16, 38, 5, 49, 0, 0, 16, 7, 2, 31, 0,139, 0, 0,255,255, 0, 90, 0, 0, 2, 26, 7,240, 18, 38, 0, 44, 0, 0,
+ 16, 7, 2, 81, 3, 35, 1,117,255,255, 0, 68, 0, 0, 2, 4, 6,124, 18, 34, 0,243, 0, 0, 16, 7, 2, 81, 3, 13, 0, 1,
+255,255, 0,200,254,135, 1,148, 5,213, 16, 38, 0, 44, 0, 0, 16, 7, 2,107, 3, 46, 0, 0,255,255, 0,183,254,135, 1,131,
+ 6, 20, 16, 38, 0, 76, 0, 0, 16, 7, 2,107, 3, 29, 0, 0,255,255, 0,115,254,135, 5,217, 5,240, 16, 38, 0, 50, 0, 0,
+ 16, 7, 2,107, 5, 39, 0, 0,255,255, 0,113,254,135, 4,117, 4,123, 16, 38, 0, 82, 0, 0, 16, 7, 2,107, 4,115, 0, 0,
+255,255, 0,115,255,227, 5,217, 7,240, 18, 38, 0, 50, 0, 0, 16, 7, 2, 81, 5, 39, 1,117,255,255, 0,113,255,227, 4,117,
+ 6,123, 18, 38, 0, 82, 0, 0, 16, 7, 2, 81, 4,125, 0, 0,255,255, 0,115,255,227, 5,217, 5,240, 18, 34, 0, 50, 0, 0,
+ 16, 6, 6,155,108, 0, 0, 0,255,255, 0,113,255,227, 4,117, 4,123, 16, 39, 6,155,255,182,254,139, 16, 6, 0, 82, 0, 0,
+255,255, 0,115,255,227, 5,217, 5,240, 18, 34, 0, 50, 0, 0, 16, 6, 6,156,106, 0, 0, 0,255,255, 0,113,255,227, 4,117,
+ 4,123, 16, 39, 6,156,255,181,254,140, 16, 6, 0, 82, 0, 0,255,255, 0,115,255,227, 5,217, 5,240, 18, 34, 0, 50, 0, 0,
+ 16, 6, 6,162,106, 0, 0, 0,255,255, 0,113,255,227, 4,117, 4,123, 16, 39, 6,162,255,182,254,139, 16, 6, 0, 82, 0, 0,
+255,255, 0,115,255,227, 5,217, 5,240, 18, 34, 0, 50, 0, 0, 16, 6, 6,157,101, 0, 0, 0,255,255, 0,113,255,227, 4,117,
+ 4,123, 16, 39, 6,157,255,182,254,139, 16, 6, 0, 82, 0, 0,255,255, 0,115,254,135, 5,217, 5,240, 18, 34, 0,150, 0, 0,
+ 16, 7, 2,107, 5, 39, 0, 0,255,255, 0,113,254,135, 4,117, 6,102, 16, 39, 2,107, 4,115, 0, 0, 16, 38, 5, 69, 0, 0,
+ 16, 6, 2, 31,115, 0, 0, 0,255,255, 0,103,255,227, 6,195, 5,240, 16, 39, 6,133, 5, 39, 1,117, 18, 2, 1, 98, 0, 0,
+255,255, 0,118,255,227, 4,211, 6,102, 16, 38, 0,118,115, 0, 18, 2, 1, 99, 0, 0, 0, 0,255,255, 0,103,255,227, 6,195,
+ 5,240, 16, 39, 6,135, 5, 39, 1,117, 18, 2, 1, 98, 0, 0,255,255, 0,118,255,227, 4,211, 6,102, 16, 38, 0, 67,115, 0,
+ 18, 2, 1, 99, 0, 0, 0, 0,255,255, 0,103,255,227, 6,195, 7,240, 18, 34, 1, 98, 0, 0, 16, 7, 2, 81, 5, 39, 1,117,
+255,255, 0,118,255,227, 4,211, 6,123, 18, 38, 1, 99, 0, 0, 16, 7, 2, 81, 4,125, 0, 0,255,255, 0,103,255,227, 6,195,
+ 5,240, 16, 39, 6,134, 5, 39, 1,117, 18, 2, 1, 98, 0, 0,255,255, 0,118,255,227, 4,211, 6, 55, 16, 38, 2, 53,115, 0,
+ 18, 2, 1, 99, 0, 0, 0, 0,255,255, 0,103,254,135, 6,195, 5,240, 18, 34, 1, 98, 0, 0, 16, 7, 2,107, 5, 39, 0, 0,
+255,255, 0,118,254,135, 4,211, 4,235, 18, 34, 1, 99, 0, 0, 16, 7, 2,107, 4,115, 0, 0,255,255, 0,178,254,135, 5, 41,
+ 5,213, 16, 38, 0, 56, 0, 0, 16, 7, 2,107, 4,245, 0, 0,255,255, 0,174,254,135, 4, 88, 4, 96, 16, 38, 0, 88, 0, 0,
+ 16, 7, 2,107, 4,123, 0, 0,255,255, 0,178,255,227, 5, 41, 7,240, 18, 38, 0, 56, 0, 0, 16, 7, 2, 81, 4,238, 1,117,
+255,255, 0,174,255,227, 4, 88, 6,123, 18, 38, 0, 88, 0, 0, 16, 7, 2, 81, 4,125, 0, 0,255,255, 0,173,255,247, 6, 95,
+ 5,233, 16, 39, 6,133, 4,238, 1,117, 18, 2, 1,113, 0, 0,255,255, 0,176,255,227, 5,105, 6,102, 16, 38, 0,118,123, 0,
+ 18, 2, 1,114, 0, 0, 0, 0,255,255, 0,173,255,247, 6, 95, 5,233, 16, 39, 6,135, 4,238, 1,117, 18, 2, 1,113, 0, 0,
+255,255, 0,176,255,227, 5,105, 6,102, 16, 38, 0, 67,123, 0, 18, 2, 1,114, 0, 0, 0, 0,255,255, 0,173,255,247, 6, 95,
+ 7,240, 18, 34, 1,113, 0, 0, 16, 7, 2, 81, 4,238, 1,117,255,255, 0,176,255,227, 5,105, 6,123, 18, 34, 1,114, 0, 0,
+ 16, 7, 2, 81, 4,125, 0, 0,255,255, 0,173,255,247, 6, 95, 5,233, 16, 39, 6,134, 4,238, 1,117, 18, 2, 1,113, 0, 0,
+255,255, 0,176,255,227, 5,105, 6, 55, 16, 35, 2, 53, 0,128, 0, 0, 18, 2, 1,114, 0, 0,255,255, 0,173,254,135, 6, 95,
+ 5,233, 18, 34, 1,113, 0, 0, 16, 7, 2,107, 4,245, 0, 0,255,255, 0,176,254,135, 5,105, 4,235, 18, 34, 1,114, 0, 0,
+ 16, 7, 2,107, 4,123, 0, 0,255,255,255,252, 0, 0, 4,231, 5,213, 18, 38, 0, 60, 0, 0, 16, 7, 6,135, 4,114, 1,124,
+255,255, 0, 61,254, 86, 4,127, 6,107, 18, 38, 0, 92, 0, 0, 16, 6, 0, 67, 33, 5, 0, 0,255,255,255,252,254,130, 4,231,
+ 5,213, 16, 35, 2,107, 4,118,255,251, 18, 2, 0, 60, 0, 0,255,255, 0, 61,254, 86, 4,127, 4, 96, 16, 35, 2,107, 5,116,
+ 0, 0, 18, 2, 0, 92, 0, 0,255,255,255,252, 0, 0, 4,231, 7,247, 18, 38, 0, 60, 0, 0, 16, 7, 2, 81, 4,114, 1,124,
+255,255, 0, 61,254, 86, 4,127, 6,130, 18, 38, 0, 92, 0, 0, 16, 7, 2, 81, 4, 96, 0, 7,255,255,255,252, 0, 0, 4,231,
+ 7, 69, 16, 99, 2, 53, 0,121, 2, 76, 64, 0, 51, 51, 18, 2, 0, 60, 0, 0,255,255, 0, 61,254, 86, 4,127, 6, 55, 16, 34,
+ 2, 53,119, 0, 18, 2, 0, 92, 0, 0, 0, 0, 0, 1, 1,134, 4,194, 2,120, 6, 97, 0, 8, 0, 72,180, 5, 8, 7, 2, 9,
+ 16,212, 60,220,178, 63, 8, 1, 93,192, 49,182, 0, 6, 7, 6, 3, 2, 9, 0, 16,212,180, 63, 2, 95, 2, 2, 93,176, 17, 75,
+ 80, 88,204, 27,192, 89,204,204,178, 63, 7, 1, 93, 17, 57, 48,177, 6, 3, 73,177, 7, 6, 73, 80, 88,179, 5, 64, 6, 64, 56,
+ 56, 89, 1, 16, 35, 53, 22, 53, 35, 53, 51, 2,120,242,134,133,241, 5,205,254,245,103, 3,157,158, 0, 0, 0,255,255, 1,115,
+ 4,238, 3, 82, 6,102, 16, 6, 0,118, 0, 0, 0, 1, 1,134, 4,194, 2,120, 6, 97, 0, 8, 0, 72,180, 2, 7, 4, 0, 9,
+ 16,212,192,220,178, 63, 7, 1, 93, 60, 49,182, 0, 3, 2, 3, 6, 7, 9, 0, 16,212,180, 63, 7, 95, 7, 2, 93,176, 17, 75,
+ 80, 88,204, 27,192, 89,204,204,178, 63, 2, 1, 93, 17, 57, 48,177, 3, 6, 73,177, 2, 3, 73, 80, 88,179, 3, 64, 4, 64, 56,
+ 56, 89, 1, 53, 51, 21, 35, 20, 55, 21, 34, 1,134,242,134,134,242, 5,205,148,158,157, 3,103, 0, 1, 0,100, 1,223, 2,127,
+ 2,131, 0, 3, 0, 17,182, 0,156, 2, 4, 1, 0, 4, 16,220,204, 49, 0, 16,212,236, 48, 19, 33, 21, 33,100, 2, 27,253,229,
+ 2,131,164, 0,255,255, 0,100, 1,223, 2,127, 2,131, 18, 6, 5,133, 0, 0, 0, 1, 0, 0, 1,233, 4, 0, 2,121, 0, 3,
+ 0, 16,182, 2,169, 0,233, 4, 1, 0, 47,198, 49, 0, 16,252,236, 48, 17, 33, 21, 33, 4, 0,252, 0, 2,121,144, 0, 0, 0,
+ 0, 1, 0, 0, 1,233, 4, 0, 2,121, 0, 3, 0, 16,182, 2,169, 0,233, 4, 1, 0, 47,198, 49, 0, 16,252,236, 48, 17, 33,
+ 21, 33, 4, 0,252, 0, 2,121,144, 0, 0, 0, 0, 1, 0, 0, 1,233, 8, 0, 2,121, 0, 3, 0, 15,181, 2,169, 0, 4, 1,
+ 0, 47,204, 49, 0, 16,212,236, 48, 17, 33, 21, 33, 8, 0,248, 0, 2,121,144, 0, 1, 0, 0, 1,233, 8, 0, 2,121, 0, 3,
+ 0, 15,181, 2,169, 0, 4, 1, 0, 47,204, 49, 0, 16,212,236, 48, 17, 33, 21, 33, 8, 0,248, 0, 2,121,144,255,255, 1, 4,
+254, 29, 2,248, 6, 29, 16, 34, 0, 95, 0, 0, 16, 3, 0, 95, 1, 74, 0, 0,255,255,255,236,254, 29, 4, 20,255,238, 16, 38,
+ 0, 66, 0, 0, 16, 7, 0, 66, 0, 0, 1, 66, 0, 1, 0,174, 3,233, 1,211, 5,213, 0, 5, 0, 24, 64, 11, 0,158, 3,129,
+ 6, 3, 4, 0, 25, 1, 6, 16,220,252,212,204, 49, 0, 16,244,236, 48, 1, 35, 53, 19, 51, 3, 1,129,211,164,129, 82, 3,233,
+173, 1, 63,254,193, 0, 0, 0, 0, 1, 0,178, 3,254, 1,215, 5,213, 0, 5, 0, 24, 64, 11, 3,158, 0,129, 6, 3, 4, 1,
+ 25, 0, 6, 16,220,236,212,204, 49, 0, 16,244,236, 48, 1, 51, 21, 3, 35, 19, 1, 4,211,164,129, 82, 5,213,152,254,193, 1,
+ 63, 0, 0, 0, 0, 1, 0,174,255, 18, 1,211, 0,254, 0, 5, 0, 24, 64, 11, 3,158, 0,131, 6, 3, 4, 1, 25, 0, 6, 16,
+212,236,212,204, 49, 0, 16,252,236, 48, 37, 51, 21, 3, 35, 19, 1, 0,211,164,129, 82,254,172,254,192, 1, 64, 0, 1, 0,178,
+ 3,254, 1,215, 5,213, 0, 5, 0, 0, 1, 21, 19, 35, 3, 53, 1,133, 82,129,164, 5,213,152,254,193, 1, 63,152, 0, 0, 0,
+ 0, 2, 0,174, 3,233, 3,109, 5,213, 0, 5, 0, 11, 0, 39, 64, 19, 6, 0,158, 9, 3,129, 12, 9, 10, 6, 25, 7, 3, 4,
+ 7, 0, 25, 1, 12, 16,220,252,204,212,204, 16,254,212,206, 49, 0, 16,244, 60,236, 50, 48, 1, 35, 53, 19, 51, 3, 5, 35, 53,
+ 19, 51, 3, 1,129,211,164,129, 82, 1,154,211,164,129, 82, 3,233,173, 1, 63,254,193,173,173, 1, 63,254,193, 0, 2, 0,174,
+ 3,233, 3,109, 5,213, 0, 5, 0, 11, 0, 39, 64, 19, 9, 3,158, 6, 0,129, 12, 9, 10, 7, 25, 6, 1, 3, 4, 1, 25, 0,
+ 12, 16,220,236,212,204, 16,220,238,212,206, 49, 0, 16,244, 60,236, 50, 48, 1, 51, 21, 3, 35, 19, 37, 51, 21, 3, 35, 19, 1,
+ 0,211,164,129, 82, 1,154,211,164,129, 82, 5,213,172,254,192, 1, 64,172,172,254,192, 1, 64, 0, 2, 0,174,255, 18, 3,109,
+ 0,254, 0, 5, 0, 11, 0, 39, 64, 19, 9, 3,158, 6, 0,131, 12, 3, 4, 1, 25, 0, 7, 9, 10, 7, 25, 6, 12, 16,220,236,
+212,204, 16,220,238,212,206, 49, 0, 16,252, 60,236, 50, 48, 37, 51, 21, 3, 35, 19, 37, 51, 21, 3, 35, 19, 2,154,211,164,129,
+ 82,254,102,211,164,129, 82,254,172,254,192, 1, 64,172,172,254,192, 1, 64, 0, 0, 2, 0,174, 3,233, 3,109, 5,213, 0, 5,
+ 0, 11, 0, 0, 1, 21, 19, 35, 3, 53, 33, 21, 19, 35, 3, 53, 1,129, 82,129,164, 2,109, 82,129,164, 5,213,173,254,193, 1,
+ 63,173,173,254,193, 1, 63,173, 0, 1, 0, 57,255, 59, 3,199, 5,213, 0, 11, 0, 39, 64, 20, 8, 4,185, 10, 2, 0,129, 6,
+194, 12, 3, 89, 5, 1, 87, 9, 89, 7, 0, 12, 16,212, 60,236,252, 60,236, 49, 0, 16,228,244,212, 60,236, 50, 48, 1, 51, 17,
+ 33, 21, 33, 17, 35, 17, 33, 53, 33, 1,168,176, 1,111,254,145,176,254,145, 1,111, 5,213,254, 92,153,251,163, 4, 93,153, 0,
+ 0, 1, 0, 57,255, 59, 3,199, 5,213, 0, 19, 0, 62, 64, 32, 18, 6,185, 0, 16, 8,185, 10, 4, 0, 2, 14, 10, 12,129, 2,
+194, 20, 15, 0, 89, 17, 13, 1, 87, 9, 5, 89, 11, 7, 3, 20, 16,212, 60, 60,236, 50,252, 60, 60,236, 50, 49, 0, 16,228,244,
+196, 50, 16,196, 50, 16,238, 50, 16,238, 50, 48, 37, 33, 17, 35, 17, 33, 53, 33, 17, 33, 53, 33, 17, 51, 17, 33, 21, 33, 17, 33,
+ 3,199,254,145,176,254,145, 1,111,254,145, 1,111,176, 1,111,254,145, 1,111,223,254, 92, 1,164,154, 2, 31,153, 1,164,254,
+ 92,153,253,225, 0, 1, 1, 51, 1,209, 3,133, 4, 33, 0, 11, 0, 18,183, 9,199, 3, 12, 6, 92, 0, 12, 16,212,236, 49, 0,
+ 16,212,236, 48, 1, 52, 54, 51, 50, 22, 21, 20, 6, 35, 34, 38, 1, 51,173,126,124,171,172,125,125,172, 2,250,124,171,171,124,
+125,172,172, 0, 0, 1, 1, 51, 1,129, 3,213, 4,113, 0, 2, 0, 0, 1, 17, 1, 1, 51, 2,162, 1,129, 2,240,254,136, 0,
+ 0, 1, 0,236, 0, 0, 1,193, 0,254, 0, 3, 0, 0, 55, 51, 21, 35,236,213,213,254,254, 0, 0, 2, 0,236, 0, 0, 4,107,
+ 0,254, 0, 3, 0, 7, 0, 0, 37, 51, 21, 35, 37, 51, 21, 35, 3,150,213,213,253, 86,213,213,254,254,254,254, 0, 3, 0,236,
+ 0, 0, 7, 20, 0,254, 0, 3, 0, 7, 0, 11, 0, 35, 64, 17, 8, 4, 0,131, 10, 6, 2, 4, 25, 5, 0, 25, 1, 9, 25, 8,
+ 12, 16,212,252,212,236,212,236, 49, 0, 47, 60, 60,236, 50, 50, 48, 37, 51, 21, 35, 37, 51, 21, 35, 37, 51, 21, 35, 3,150,212,
+212, 2,169,213,213,250,173,213,213,254,254,254,254,254,254, 0, 0, 1, 0,220, 2,107, 1,175, 3,105, 0, 3, 0, 0, 19, 51,
+ 21, 35,220,211,211, 3,105,254, 0, 7, 0,113,255,227, 10, 76, 5,240, 0, 11, 0, 23, 0, 35, 0, 39, 0, 51, 0, 63, 0, 75,
+ 0,174, 64, 68, 36, 15, 37, 38, 37, 38, 15, 39, 36, 39, 66, 64, 0,146, 12, 46,146, 30,141, 40,146, 24, 70, 6,146, 52, 12,141,
+ 58, 38, 18,140, 36, 24,145, 76, 37, 73, 67, 39, 49, 43, 67, 13, 61, 9, 13, 15, 14, 3, 13, 21, 49, 13, 27, 61, 14, 73, 13, 21,
+ 55, 43, 13, 27, 14, 33, 11, 76, 16,252,228,236,212,196,236,228, 16,238, 16,238,246,238, 16,238, 17, 18, 57, 17, 18, 57, 49, 0,
+ 16,228, 50,244, 60, 60,228, 50,236, 50, 16,238,246,238, 16,238, 50, 48, 75, 83, 88, 7, 16, 5,237, 7, 16, 5,237, 89, 34, 1,
+ 75,176, 20, 84, 75,176, 9, 84, 91, 75,176, 11, 84, 91, 75,176, 12, 84, 91, 75,176, 13, 84, 91, 75,176, 14, 84, 91, 88,189, 0,
+ 76, 0, 64, 0, 1, 0, 76, 0, 76,255,192, 56, 17, 55, 56, 89, 1, 34, 6, 21, 20, 22, 51, 50, 54, 53, 52, 38, 39, 50, 22, 21,
+ 20, 6, 35, 34, 38, 53, 52, 54, 1, 50, 22, 21, 20, 6, 35, 34, 38, 53, 52, 54, 33, 51, 1, 35, 19, 34, 6, 21, 20, 22, 51, 50,
+ 54, 53, 52, 38, 1, 50, 22, 21, 20, 6, 35, 34, 38, 53, 52, 54, 23, 34, 6, 21, 20, 22, 51, 50, 54, 53, 52, 38, 8,244, 87,100,
+100, 87, 85, 99, 99, 85,158,186,187,157,160,186,187,249,116,158,188,187,159,159,185,186, 4, 37,160,252, 90,160, 31, 86, 99, 98,
+ 87, 87, 99,100, 3,178,158,186,187,157,160,186,187,159, 87, 99, 99, 87, 85, 99, 99, 2,145,148,132,130,149,149,130,131,149,127,
+220,187,187,219,219,187,188,219, 2,224,219,187,189,218,219,188,186,220,249,243, 5,142,149,130,132,148,148,132,129,150,253,159,
+220,187,187,219,219,187,188,219,127,148,132,130,149,149,130,131,149, 0, 0, 0, 0, 9, 0,113,255,227, 13,114, 5,240, 0, 11,
+ 0, 22, 0, 34, 0, 45, 0, 55, 0, 59, 0, 69, 0, 80, 0, 92, 0, 0, 1, 34, 6, 21, 20, 22, 51, 50, 54, 53, 52, 38, 39, 50,
+ 22, 16, 6, 35, 34, 38, 53, 52, 54, 5, 34, 6, 21, 20, 22, 51, 50, 54, 53, 52, 38, 39, 50, 22, 16, 6, 35, 34, 38, 53, 52, 54,
+ 0, 32, 22, 21, 20, 6, 32, 38, 53, 52, 37, 51, 1, 35, 18, 34, 6, 21, 20, 22, 50, 54, 53, 52, 1, 50, 22, 16, 6, 35, 34, 38,
+ 53, 52, 54, 23, 34, 6, 21, 20, 22, 51, 50, 54, 53, 52, 38, 12, 26, 87,100,100, 87, 85, 99, 99, 85,158,186,187,157,160,186,187,
+253,121, 87,100,100, 87, 85, 99, 99, 85,158,186,187,157,160,186,187,248,214, 1, 60,188,187,254,194,185, 4,223,160,252, 90,160,
+117,172, 99, 98,174, 99, 3, 78,158,186,187,157,160,186,187,159, 87, 99, 99, 87, 85, 99, 99, 2,145,148,132,130,149,149,130,131,
+149,127,220,254,138,219,219,187,188,219,127,148,132,130,149,149,130,131,149,127,220,254,138,219,219,187,188,219, 2,224,219,187,
+189,218,219,188,186,220,249,243, 5,142,149,130,132,148,148,132,129,254, 53,220,254,138,219,219,187,188,219,127,148,132,130,149,
+149,130,131,149, 0, 1, 0, 40, 4, 96, 1,160, 5,213, 0, 3, 0, 0, 27, 1, 51, 1, 40,173,203,254,223, 4, 96, 1,117,254,
+139, 0, 0, 0,255,255, 0, 40, 4, 96, 2,204, 5,213, 16, 38, 5,159, 0, 0, 16, 7, 5,159, 1, 44, 0, 0,255,255, 0, 40,
+ 4, 96, 3,248, 5,213, 16, 39, 5,159, 1, 44, 0, 0, 16, 38, 5,159, 0, 0, 16, 7, 5,159, 2, 88, 0, 0, 0, 1, 0, 40,
+ 4, 96, 1,160, 5,213, 0, 3, 0, 0, 1, 35, 1, 51, 1,160, 87,254,223,203, 4, 96, 1,117,255,255, 0, 40, 4, 96, 2,204,
+ 5,213, 16, 38, 5,162, 0, 0, 16, 7, 5,162, 1, 44, 0, 0,255,255, 0, 40, 4, 96, 3,248, 5,213, 16, 38, 5,162, 0, 0,
+ 16, 39, 5,162, 2, 88, 0, 0, 16, 7, 5,162, 1, 44, 0, 0, 0, 1, 0, 11,254, 29, 2,171,255,195, 0, 5, 0, 0, 1, 35,
+ 39, 7, 35, 1, 2,171,148,187,188,149, 1, 82,254, 29,249,249, 1,166, 0, 0, 0, 1, 0,158, 0,141, 2,115, 4, 35, 0, 6,
+ 0, 71, 64, 37, 3,232, 4, 5, 4, 2,232, 1, 2, 5, 5, 4, 2,232, 3, 2, 6, 0, 6, 1,232, 0, 6, 66, 2, 4,231, 0,
+166, 7, 2, 3, 0,111, 5,110, 7, 16,252,236, 50, 57, 49, 0, 16,244,236, 57, 48, 75, 83, 88, 7, 4,237, 7, 16, 8,237, 7,
+ 16, 8,237, 7, 16, 4,237, 89, 34, 1, 21, 9, 1, 21, 1, 53, 2,115,254,211, 1, 45,254, 43, 4, 35,191,254,244,254,244,191,
+ 1,162, 82, 0, 0, 1, 0,193, 0,141, 2,150, 4, 35, 0, 6, 0, 73, 64, 38, 5,232, 6, 5, 2, 3, 2, 4,232, 3, 3, 2,
+ 6,232, 0, 1, 0, 5,232, 4, 5, 1, 1, 0, 66, 5, 3,231, 0,166, 7, 5, 1,111, 3, 0,112, 7, 16,252, 60,236, 57, 49,
+ 0, 16,244,236, 57, 48, 75, 83, 88, 7, 16, 8,237, 7, 16, 4,237, 7, 16, 4,237, 7, 16, 8,237, 89, 34, 19, 1, 21, 1, 53,
+ 9, 1,193, 1,213,254, 43, 1, 45,254,211, 4, 35,254, 94, 82,254, 94,191, 1, 12, 1, 12, 0,255,255, 0,195, 0, 4, 5,235,
+ 5,204, 18, 34, 0,153, 0, 75, 16, 35, 0, 17,255,232, 2, 78, 16, 35, 0, 17, 2, 22, 0, 4, 16, 35, 0, 17, 4, 61, 2, 78,
+ 16, 3, 0, 17, 2, 22, 4,206,255,255, 0,147, 0, 0, 3, 79, 5,213, 16, 39, 0, 4,255, 94, 0, 0, 16, 7, 0, 4, 1, 79,
+ 0, 0, 0, 0, 0, 3, 0,147, 0, 0, 3,176, 5,240, 0, 23, 0, 27, 0, 36, 0, 0, 1, 35, 17, 6, 7, 6, 7, 53, 62, 1,
+ 51, 50, 22, 21, 20, 6, 15, 1, 14, 1, 7, 14, 1, 21, 3, 51, 21, 35, 19, 17, 55, 62, 1, 53, 52, 39, 38, 2, 76,191, 31, 32,
+ 90, 97, 94,193,103,184,223, 72, 90, 88, 47, 39, 8, 6, 6,197,203,203,197, 45, 57, 51, 65, 37, 1,145, 3,173, 8, 13, 35, 67,
+188, 57, 56,194,159, 76,137, 86, 86, 47, 53, 25, 21, 60, 52,254,242,254, 5, 66,254, 82, 45, 53, 94, 49, 89, 55, 31, 0, 0, 0,
+255,255,255,236, 5,124, 4, 20, 6, 11, 16, 7, 0, 66, 0, 0, 7, 95, 0, 0, 0, 1,255,167,254, 27, 6,199,255,133, 0, 13,
+ 0, 37,179, 4, 15, 10, 14, 16,196,212,196,179, 7, 0, 15, 14, 17, 18, 57, 57, 49, 64, 7, 11, 3, 10, 4, 7, 0, 14, 0, 16,
+212,220,220, 60,204, 50, 48, 1, 50, 36, 55, 21, 6, 4, 35, 34, 36, 39, 53, 22, 4, 3, 54,231, 1,197,229,235,254, 58,224,223,
+254, 60,236,230, 1,194,254,181,104,104,126,118,118,117,119,126,105,103, 0, 0, 0, 1,255,167, 6, 4, 6,199, 7,110, 0, 13,
+ 0, 37,179, 4, 15, 10, 14, 16,196,212,196,179, 7, 0, 15, 14, 17, 18, 57, 57, 49, 64, 7, 10, 4, 11, 3, 0, 7, 14, 0, 16,
+212,220,220, 60,204, 50, 48, 1, 50, 4, 23, 21, 38, 36, 35, 34, 4, 7, 53, 54, 36, 3, 54,224, 1,198,235,229,254, 59,231,231,
+254, 62,230,236, 1,196, 7,110,118,118,126,104,104,103,105,126,119,117, 0, 0, 0, 1,255,170,254, 29, 2, 73, 1,213, 0, 7,
+ 0, 0, 1, 51, 9, 1, 35, 11, 1, 35, 1,231, 98,254,226, 1, 30, 98,237,237, 99, 1,213,254, 36,254, 36, 1,138,254,118, 0,
+255,255, 0, 61,255,197, 7,195, 6,131, 16, 35, 0, 13, 0, 0,253,123, 16, 35, 0, 13, 4, 0,253,123, 16, 3, 0, 13, 2, 0,
+ 0,147, 0, 0,255,255, 0,221, 2,129, 3, 51, 3, 95, 18, 67, 2, 34, 0, 8,250,110, 64, 0, 96, 0, 0, 0, 0, 1,254,137,
+255,227, 2,205, 5,240, 0, 3, 0, 43, 64, 19, 0, 15, 1, 2, 1, 2, 15, 3, 0, 3, 66, 2,140, 0,145, 4, 1, 3, 4, 16,
+212,204, 49, 0, 16,228,228, 48, 75, 83, 88, 7, 16, 5,237, 7, 16, 5,237, 89, 34, 1, 51, 1, 35, 2, 45,160,252, 92,160, 5,
+240,249,243, 0, 0, 1, 0,176,254,242, 2, 88, 6, 20, 0, 11, 0, 0, 1, 17, 51, 21, 33, 17, 33, 21, 35, 17, 51, 21, 1,104,
+240,254, 88, 1,168,240,240, 2, 94,253, 35,143, 7, 34,143,253, 35, 74, 0, 0, 0, 1, 0,176,254,242, 2, 88, 6, 20, 0, 11,
+ 0, 0, 19, 53, 51, 17, 35, 53, 33, 17, 33, 53, 51, 17,176,240,240, 1,168,254, 88,240, 2, 94, 74, 2,221,143,248,222,143, 2,
+221, 0, 0, 0,255,255, 0, 73, 0, 0, 7, 23, 5,240, 16, 38, 0, 34,182, 0, 16, 7, 0, 34, 3,102, 0, 0,255,255, 0,147,
+ 0, 0, 5, 74, 5,240, 16, 38, 0, 34, 0, 0, 16, 7, 0, 4, 3, 74, 0, 0,255,255, 0,147, 0, 0, 5, 74, 5,240, 16, 39,
+ 0, 4,255, 94, 0, 0, 16, 7, 0, 34, 1,154, 0, 0, 0, 0, 0, 1, 0,111, 0, 0, 3,161, 4,132, 0, 19, 0, 0, 37, 51,
+ 21, 35, 53, 7, 35, 19, 35, 53, 33, 19, 33, 53, 33, 21, 3, 51, 21, 35, 1,254,169,209, 3,180,224,249, 1, 36,168,253,157, 3,
+ 50,195,165,208,102,102, 7, 7, 2, 15,102, 1,139,132, 67,254, 52,102, 0, 0, 0, 1, 0,236,255, 59, 4,135, 5,213, 0, 13,
+ 0, 0, 1, 33, 17, 51, 17, 51, 17, 51, 17, 62, 1, 53, 52, 36, 2,172,254, 64,141,190,142,215,235,254,252, 5,213,249,102, 6,
+ 31,249,225, 3, 78, 17,221,184,190,232, 0, 0, 0, 2, 0,216, 1,194, 3, 40, 4, 18, 0, 3, 0, 11, 0, 0, 1, 51, 17, 7,
+ 43, 1, 34, 38, 53, 52, 54, 51, 2,121,175,175,118, 2,125,172,173,126, 4, 18,253,177, 1,172,125,124,171, 0, 0, 2, 0,216,
+ 1,194, 3, 40, 4, 18, 0, 3, 0, 11, 0, 0, 1, 39, 17, 59, 1, 50, 22, 21, 20, 6, 43, 1, 1,135,175,175,118,126,173,172,
+125, 2, 1,194, 1, 2, 79,171,124,125,172, 0,255,255, 0, 61,255,197, 3,195, 3,107, 18, 3, 0, 13, 0, 0,253,123, 0, 0,
+ 0, 2, 1, 29,255, 18, 2, 66, 4, 35, 0, 3, 0, 9, 0, 0, 1, 35, 21, 51, 17, 35, 21, 19, 51, 3, 1,240,211,211,211,164,
+129, 82, 4, 35,254,253,217,172,254,192, 1, 64,255,255,255,167,254, 27, 6,199, 7,110, 16, 38, 5,172, 0, 0, 16, 6, 5,173,
+ 0, 0, 0, 0,255,255, 0, 61,255,242, 3,195, 7,111, 18, 35, 0, 13, 0, 0,253,168, 16, 3, 0, 13, 0, 0, 1,127, 0, 0,
+255,255, 0,145,255, 66, 3, 67, 5,213, 16, 35, 0, 18, 0,145, 0, 0, 16, 35, 0, 17, 1,142, 0, 0, 16, 3, 0, 17,255,217,
+ 4, 72, 0, 0,255,255, 0,217, 1,211, 5,219, 3, 49, 18, 2, 0, 97, 0, 0,255,255,255,167,254, 20, 6,199,255,126, 16, 7,
+ 5,173, 0, 0,248, 16, 0, 0, 0, 1, 1, 56, 0,200, 5,124, 5, 13, 0, 23, 0, 0, 1, 17, 35, 17, 7, 39, 55, 33, 53, 33,
+ 39, 55, 23, 17, 51, 17, 55, 23, 7, 33, 21, 33, 23, 7, 3,170,160,249,113,249,254,159, 1, 97,250,113,250,160,250,113,250, 1,
+ 97,254,159,250,113, 2, 41,254,159, 1, 96,249,114,249,160,250,114,251, 1, 98,254,158,250,113,250,160,249,114, 0, 3, 0,250,
+ 1, 50, 3,182, 4,182, 0, 3, 0, 7, 0, 11, 0, 0, 19, 53, 51, 21, 1, 53, 51, 21, 3, 53, 51, 21,250,200, 1, 44,200,200,
+200, 2,144,200,200,254,162,200,200, 2,188,200,200, 0, 0, 0,255,255, 0, 40, 4, 96, 5, 36, 5,213, 16, 39, 5,159, 1, 44,
+ 0, 0, 16, 38, 5,159, 0, 0, 16, 39, 5,159, 3,132, 0, 0, 16, 7, 5,159, 2, 88, 0, 0, 0, 4, 1,102, 1, 0, 5, 78,
+ 4,232, 0, 3, 0, 7, 0, 11, 0, 15, 0, 0, 1, 53, 51, 21, 33, 53, 51, 21, 1, 53, 51, 21, 3, 53, 51, 21, 1,102,200, 2,
+ 88,200,253,168,200,200,200, 2,144,200,200,200,200,254,112,200,200, 3, 32,200,200, 0, 0, 0, 0, 5, 1,102, 0,246, 5, 78,
+ 4,222, 0, 3, 0, 7, 0, 11, 0, 15, 0, 19, 0, 0, 1, 53, 51, 21, 19, 53, 51, 21, 3, 53, 51, 21, 1, 53, 51, 21, 3, 53,
+ 51, 21, 2,246,200,200,200,200,200,252, 44,200,220,200, 2,134,200,200,254,112,200,200, 3, 32,200,200,252,244,200,200, 3, 12,
+200,200, 0, 0, 0, 2, 0,219, 0, 0, 1,174, 5,213, 0, 3, 0, 7, 0, 0, 19, 51, 21, 35, 17, 51, 21, 35,219,211,211,211,
+211, 5,213,254,252, 39,254, 0, 0, 4, 0,100,254,229, 5,253, 6,239, 0, 3, 0, 7, 0, 11, 0, 15, 0, 0, 19, 51, 21, 35,
+ 37, 51, 21, 35, 1, 51, 21, 35, 17, 51, 21, 35,100,211,211, 4,198,211,211,253,157,211,211,211,211, 3,105,254,254,254, 4,132,
+254,249,242,254, 0, 5, 0,112, 0, 0, 6, 68, 5,213, 0, 3, 0, 7, 0, 11, 0, 15, 0, 27, 0, 0, 37, 53, 51, 21, 3, 53,
+ 51, 21, 1, 53, 51, 21, 3, 53, 51, 21, 1, 17, 35, 17, 33, 53, 33, 17, 51, 17, 33, 21, 4,134,200,200,200,252, 44,200,220,200,
+ 1,124,160,253,102, 2,154,160, 2,154,246,200,200, 3, 32,200,200,252,244,200,200, 3, 12,200,200,254,132,253,102, 2,154,160,
+ 2,155,253,101,160, 0, 0, 0, 0, 3, 0,219, 0, 80, 1,174, 5, 62, 0, 3, 0, 7, 0, 11, 0, 0, 19, 51, 21, 35, 17, 51,
+ 21, 35, 17, 51, 21, 35,219,211,211,211,211,211,211, 5, 62,254,253, 14,254, 2,246,254, 0, 0, 0, 4, 0,219, 0, 17, 1,174,
+ 5,119, 0, 3, 0, 7, 0, 11, 0, 15, 0, 0, 19, 51, 21, 35, 17, 51, 21, 35, 17, 51, 21, 35, 17, 51, 21, 35,219,211,211,211,
+211,211,211,211,211, 2,137,254, 3,236,254,252,150,254, 3,240,254, 0, 0, 0, 0, 2, 0, 87, 2,141, 2,238, 5,240, 0, 13,
+ 0, 25, 0, 0, 0, 34, 7, 6, 21, 20, 23, 22, 50, 55, 54, 53, 52, 47, 1, 50, 22, 21, 20, 6, 35, 34, 38, 53, 52, 54, 2, 8,
+202, 50, 51, 51, 50,202, 50, 51, 51,151,161,170,170,161,162,170,170, 5,151, 86, 86,172,173, 86, 86, 86, 86,173,172, 86,175,222,
+211,212,222,222,212,211,222, 0, 0, 2, 0,121, 2,156, 0,238, 6, 4, 0, 3, 0, 7, 0, 31, 64, 6, 9, 5, 1, 4, 0, 8,
+ 16,220, 60,220, 60,204, 49, 0, 64, 6, 4, 7, 0, 3, 0, 8, 16,212,196, 16,220,204, 48, 19, 51, 17, 35, 17, 51, 21, 35,122,
+116,116,116,116, 5, 15,253,141, 3,103,130, 0, 0, 2, 0, 63, 2,156, 2,244, 5,223, 0, 2, 0, 13, 0,212, 64, 22, 0, 3,
+ 11, 7,221, 5, 1, 9,247, 3,145, 14, 1, 12, 10, 0, 93, 6, 8, 4, 12, 14, 16,220,212, 60,196,236, 50, 17, 57, 49, 0, 16,
+244,252,212, 60,236, 50, 18, 57, 48, 1, 75,176, 14, 84, 75,176, 15, 84, 91, 75,176, 16, 84, 91, 75,176, 17, 84, 91, 75,176, 11,
+ 84, 91, 75,176, 10, 84, 91, 88,189, 0, 14, 0, 64, 0, 1, 0, 14, 0, 14,255,192, 56, 17, 55, 56, 89, 0, 75,176, 17, 84, 75,
+176, 14, 84, 91, 88,189, 0, 14,255,192, 0, 1, 0, 14, 0, 14, 0, 64, 56, 17, 55, 56, 89, 64, 84, 11, 1, 29, 1, 47, 1, 57,
+ 1, 73, 1, 70, 3, 89, 3,105, 3,139, 3,171, 3,187, 3, 11, 1, 0, 15, 1, 15, 2, 15, 5, 15, 6, 15, 7, 15, 8, 15, 11,
+ 15, 12, 15, 13, 19, 0, 31, 1, 31, 2, 31, 5, 31, 6, 31, 7, 31, 8, 31, 11, 31, 12, 31, 13, 34, 0, 53, 0, 71, 0, 75, 13,
+ 83, 0, 91, 13,101, 0,132, 0,165, 0,181, 0, 30, 93, 1, 93, 9, 1, 33, 3, 51, 17, 51, 21, 35, 21, 35, 53, 33, 53, 1,221,
+254,203, 1, 53, 22,166,135,135,144,254, 98, 5,102,254, 93, 2, 28,253,228,109,186,186,121, 0, 0, 1, 0,102, 2,141, 2,211,
+ 5,223, 0, 32, 0, 0, 19, 33, 21, 33, 21, 54, 55, 54, 51, 50, 23, 22, 21, 20, 7, 6, 35, 34, 38, 39, 53, 22, 23, 22, 51, 50,
+ 54, 52, 38, 35, 34, 6, 7,142, 1,254,254,121, 28, 29, 28, 28,161, 94, 94, 97, 96,176, 60,126, 66, 57, 62, 62, 69,111,130,130,
+111, 52,104, 54, 5,223, 95,204, 9, 4, 4, 77, 76,131,135, 75, 74, 18, 18,113, 27, 14, 13,102,174,102, 20, 21, 0, 2, 0, 92,
+ 2,141, 2,243, 5,240, 0, 15, 0, 47, 0, 0, 1, 34, 7, 6, 21, 20, 23, 22, 51, 50, 55, 54, 53, 52, 39, 38, 19, 21, 38, 39,
+ 38, 35, 34, 7, 6, 7, 54, 55, 54, 51, 50, 23, 22, 21, 20, 7, 6, 35, 34, 38, 53, 52, 55, 54, 51, 50, 23, 22, 1,179, 88, 51,
+ 51, 51, 51, 88, 87, 51, 51, 51, 51,171, 49, 50, 50, 49,128, 68, 68, 10, 38, 57, 58, 68,145, 84, 84, 88, 87,145,167,176,108,108,
+182, 49, 50, 50, 4,109, 52, 53, 91, 90, 52, 53, 53, 52, 90, 91, 53, 52, 1, 98,103, 20, 10, 11, 75, 76,153, 49, 26, 26, 76, 77,
+132,127, 79, 78,222,212,198,117,118, 8, 9, 0, 0, 1, 0,108, 2,156, 2,213, 5,223, 0, 6, 0, 0, 19, 33, 21, 1, 35, 1,
+ 33,108, 2,105,254,164,136, 1, 72,254, 51, 5,223, 48,252,237, 2,228, 0, 0, 0, 3, 0, 89, 2,141, 2,236, 5,240, 0, 12,
+ 0, 42, 0, 58, 0, 0, 0, 34, 7, 6, 21, 20, 22, 51, 50, 55, 54, 52, 39, 37, 38, 39, 38, 53, 52, 54, 32, 23, 22, 21, 20, 7,
+ 6, 7, 22, 23, 22, 21, 20, 7, 6, 35, 34, 39, 38, 53, 52, 55, 54, 55, 20, 23, 22, 51, 50, 55, 54, 53, 52, 39, 38, 35, 34, 7,
+ 6, 2, 0,186, 53, 53,106, 93, 92, 54, 53, 53,254,236, 84, 46, 47,164, 1, 30, 82, 81, 46, 47, 83, 90, 56, 53, 85, 86,158,159,
+ 85, 86, 53, 54, 45, 47, 46, 85, 81, 49, 48, 48, 47, 83, 83, 48, 47, 4, 42, 44, 43, 75, 76, 86, 44, 43,150, 43, 93, 18, 49, 50,
+ 72,100,116, 58, 58,100, 74, 48, 49, 18, 18, 58, 55, 80,121, 65, 65, 65, 65,121, 78, 57, 56,198, 63, 38, 37, 37, 36, 65, 63, 38,
+ 37, 37, 36, 0, 0, 2, 0, 83, 2,141, 2,233, 5,240, 0, 31, 0, 46, 0, 0, 19, 53, 22, 23, 22, 51, 50, 55, 54, 55, 6, 7,
+ 6, 35, 34, 38, 53, 52, 55, 54, 51, 50, 23, 22, 21, 20, 7, 6, 35, 34, 39, 38, 19, 50, 54, 53, 52, 39, 38, 35, 34, 7, 6, 21,
+ 20, 23, 22,145, 49, 50, 50, 48,129, 68, 67, 10, 35, 60, 57, 69,144,168, 87, 88,145,167, 87, 88,107,108,182, 49, 50, 50,204, 88,
+102, 51, 51, 88, 85, 53, 52, 52, 51, 2,174,103, 20, 11, 10, 75, 75,154, 47, 27, 26,152,132,129, 77, 78,111,111,212,198,117,118,
+ 8, 9, 1,114,104, 92, 90, 52, 53, 53, 52, 90, 92, 52, 52, 0, 0, 1, 0,137, 2,156, 3,176, 5,107, 0, 11, 0, 0, 1, 17,
+ 33, 21, 33, 17, 35, 17, 33, 53, 33, 17, 2, 81, 1, 95,254,161,105,254,161, 1, 95, 5,107,254,200, 95,254,200, 1, 56, 95, 1,
+ 56, 0, 0, 0, 0, 1, 0,137, 3,212, 3,176, 4, 51, 0, 3, 0, 0, 19, 33, 21, 33,137, 3, 39,252,217, 4, 51, 95, 0, 0,
+ 0, 2, 0,137, 3, 97, 3,176, 4,165, 0, 3, 0, 7, 0, 0, 19, 33, 21, 33, 21, 33, 21, 33,137, 3, 39,252,217, 3, 39,252,
+217, 4,165, 94,135, 95, 0, 0, 0, 1, 0,111, 2, 5, 1,144, 6, 2, 0, 13, 0, 0, 1, 14, 1, 16, 22, 23, 35, 38, 39, 38,
+ 52, 55, 54, 55, 1,144, 84, 82, 82, 84,101, 94, 47, 47, 47, 46, 95, 6, 2,129,252,254,254,254,128,131,128,127,250,127,126,132,
+ 0, 1, 0,103, 2, 5, 1,136, 6, 2, 0, 15, 0, 0, 19, 51, 22, 23, 22, 20, 7, 6, 7, 35, 54, 55, 54, 16, 39, 38,103,101,
+ 95, 47, 46, 46, 47, 95,101, 84, 41, 42, 42, 41, 6, 2,132,126,127,250,127,128,131,128,127,127, 1, 2,126,126, 0, 1, 0,117,
+ 2,156, 2,197, 5, 31, 0, 19, 0, 48, 64, 7, 21, 0, 3, 14, 10, 11, 20, 16,212,220, 60, 47,204,204, 75,176, 13, 81, 88,177,
+ 21, 64, 56, 89, 49,178,127, 21, 1, 93, 0, 64, 6, 6, 17, 12, 2, 11, 20, 16,212, 60,196,212,204, 48, 1, 17, 35, 17, 52, 38,
+ 35, 34, 6, 21, 17, 35, 17, 51, 21, 62, 1, 51, 50, 22, 2,196,116, 78, 78, 94,108,117,117, 41,113, 74,121,125, 4, 23,254,133,
+ 1,119, 89, 89,107, 92,254,158, 2,115, 97, 56, 56,134, 0, 0,255,255, 0, 87,255,241, 2,238, 3, 84, 16, 7, 5,204, 0, 0,
+253,100, 0, 0,255,255, 0,137, 0, 0, 2,197, 3, 67, 16, 7, 0,123, 0, 0,253,100, 0, 0,255,255, 0, 94, 0, 0, 2,180,
+ 3, 84, 16, 7, 0,116, 0, 0,253,100, 0, 0,255,255, 0, 98,255,241, 2,205, 3, 84, 16, 7, 0,117, 0, 0,253,100, 0, 0,
+255,255, 0, 63, 0, 0, 2,244, 3, 67, 16, 7, 5,206, 0, 0,253,100, 0, 0,255,255, 0,102,255,241, 2,211, 3, 67, 16, 7,
+ 5,207, 0, 0,253,100, 0, 0,255,255, 0, 92,255,241, 2,243, 3, 84, 16, 7, 5,208, 0, 0,253,100, 0, 0,255,255, 0,108,
+ 0, 0, 2,213, 3, 67, 16, 7, 5,209, 0, 0,253,100, 0, 0,255,255, 0, 89,255,241, 2,236, 3, 84, 16, 7, 5,210, 0, 0,
+253,100, 0, 0,255,255, 0, 83,255,241, 2,233, 3, 84, 16, 7, 5,211, 0, 0,253,100, 0, 0,255,255, 0,137, 0, 0, 3,176,
+ 2,207, 16, 7, 5,212, 0, 0,253,100, 0, 0,255,255, 0,137, 1, 56, 3,176, 1,151, 16, 7, 5,213, 0, 0,253,100, 0, 0,
+255,255, 0,137, 0,197, 3,176, 2, 9, 16, 7, 5,214, 0, 0,253,100, 0, 0,255,255, 0,111,255,105, 1,144, 3,102, 16, 7,
+ 5,215, 0, 0,253,100, 0, 0,255,255, 0,103,255,105, 1,136, 3,102, 16, 7, 5,216, 0, 0,253,100, 0, 0, 0, 1, 0, 86,
+ 0, 0, 6,174, 5,214, 0, 35, 0, 0, 1, 14, 1, 35, 34, 0, 16, 0, 51, 50, 22, 23, 21, 46, 1, 35, 34, 6, 16, 22, 51, 50,
+ 54, 55, 17, 33, 21, 33, 17, 33, 21, 33, 17, 33, 21, 33, 3,221, 79,178, 99,254,254,219, 1, 37,254,101,177, 78, 76,173, 98,192,
+204,204,192, 98,173, 76, 2,196,253,211, 2, 22,253,234, 2, 58,253, 47, 1,184, 54, 54, 1, 55, 2, 28, 1, 55, 53, 54,159, 71,
+ 70,234,254, 68,234, 70, 71, 2, 10,128,254,181,128,254,107,128, 0, 3, 0,115,255,166, 4,190, 6, 57, 0, 39, 0, 46, 0, 52,
+ 0, 0, 1, 22, 23, 55, 51, 7, 22, 23, 21, 38, 39, 1, 51, 50, 54, 55, 21, 14, 1, 35, 34, 39, 7, 35, 55, 38, 39, 7, 35, 55,
+ 38, 39, 38, 17, 16, 55, 54, 37, 55, 51, 7, 6, 7, 6, 17, 20, 23, 1, 38, 39, 1, 22, 23, 3,104, 65, 62, 30,155, 47, 40, 37,
+ 58, 64,254,193, 18,119,211, 93, 97,216,121, 27, 26, 18,155, 25, 65, 57, 38,155, 65, 19, 17,178,178,160, 1, 8, 21,156,227,145,
+ 88,125, 82, 2, 52, 62, 67,254,193, 53, 65, 5,235, 8, 19,105,165, 22, 28,213, 60, 41,251,151, 94, 95,211, 72, 72, 2, 63, 87,
+ 18, 30,135,230, 18, 21,207, 1,103, 1,104,208,185, 20, 75,252, 31,112,157,254,216,238,148, 3,203, 19, 4,251,149, 40, 21, 0,
+ 0, 1, 0, 96,255,228, 4,179, 5,240, 0, 44, 0, 0, 37, 54, 55, 54, 55, 21, 14, 1, 35, 32, 0, 17, 16, 0, 33, 50, 22, 23,
+ 21, 46, 1, 35, 34, 2, 17, 16, 23, 22, 23, 17, 51, 21, 62, 1, 51, 50, 22, 31, 1, 46, 1, 35, 34, 6, 21, 3, 46, 97, 88,106,
+ 93, 97,217,121,254,202,254,155, 1,101, 1, 54,123,217, 95, 93,212,119,234,249,124, 94,153,152, 48,154,110, 15, 38, 23, 1, 26,
+ 60, 36,128,139,138, 7, 39, 47, 95,211, 72, 71, 1,158, 1,103, 1,104, 1,159, 71, 71,213, 95, 94,254,199,254,216,254,217,156,
+117, 30, 3, 93,157, 92, 89, 4, 5,170, 16, 15,182,171, 0, 0, 0, 1, 0,133, 0, 0, 4,203, 5,213, 0, 17, 0, 0, 1, 17,
+ 33, 21, 33, 17, 33, 21, 33, 17, 51, 21, 35, 17, 35, 17, 35, 53, 1,113, 3, 90,253,112, 2, 80,253,176,250,250,202,236, 1,126,
+ 4, 87,170,254, 72,170,254,181, 69,254,199, 1, 57, 69, 0, 0, 0, 1, 0,129, 0, 0, 4, 98, 5,240, 0, 35, 0, 0, 1, 17,
+ 33, 21, 33, 53, 51, 17, 35, 53, 51, 53, 35, 53, 51, 53, 16, 54, 51, 50, 22, 23, 21, 46, 1, 35, 34, 6, 29, 1, 33, 21, 33, 21,
+ 33, 21, 2, 53, 2, 45,252, 31,236,191,191,199,199,214,232, 61,151, 79, 76,136, 61,148,116, 1,135,254,121, 1,143, 1,236,254,
+190,170,170, 1, 66,143,143,143, 95, 1, 5,243, 31, 29,182, 41, 41,155,212, 72,143,143,143, 0, 0, 1, 0,186,255,189, 7, 29,
+ 4,171, 0, 42, 0, 0, 1, 22, 23, 62, 1, 51, 50, 22, 21, 17, 35, 17, 52, 38, 35, 34, 6, 21, 17, 35, 17, 52, 39, 1, 35, 1,
+ 38, 35, 34, 6, 21, 17, 35, 17, 51, 21, 62, 1, 51, 50, 23, 55, 51, 3,204, 61, 32, 69,192,130,175,190,185,114,117,143,166,185,
+ 14,254,240,128, 1, 59, 53, 81,141,166,185,185, 63,176,121, 74, 60, 22,128, 4, 33, 59, 93,124,118,245,226,253, 92, 2,158,161,
+156,190,164,253,135, 2,158, 82, 60,252,145, 3,250, 36,191,163,253,135, 4, 96,174,103, 98, 23, 71, 0, 0, 0, 0, 5, 0,117,
+ 0, 0, 5,135, 5,213, 0, 2, 0, 6, 0, 34, 0, 38, 0, 41, 0, 0, 1, 39, 21, 19, 39, 35, 21, 3, 33, 19, 51, 17, 51, 17,
+ 51, 21, 35, 21, 51, 21, 35, 17, 33, 3, 35, 17, 35, 17, 35, 53, 51, 53, 35, 53, 51, 5, 23, 51, 53, 3, 23, 53, 2, 75, 79,182,
+ 56,126,196, 1, 16,211,229,196,195,195,195,195,254,240,211,229,196,195,195,195,195, 2, 18, 56,126, 79, 79, 3,175,206,206,254,
+242,147,147, 3, 52,253,218, 2, 38,253,218,123,147,123,253,218, 2, 38,253,218, 2, 38,123,147,123,123,147,147,254,242,206,206,
+ 0, 2, 0,201,255,227, 9,206, 5,213, 0, 8, 0, 80, 0, 0, 1, 17, 51, 50, 54, 53, 52, 38, 35, 1, 6, 7, 6, 43, 1, 17,
+ 35, 17, 33, 50, 23, 22, 23, 51, 17, 51, 17, 33, 21, 33, 17, 20, 22, 59, 1, 53, 30, 1, 51, 50, 54, 53, 52, 38, 47, 1, 46, 1,
+ 53, 52, 54, 51, 50, 22, 23, 21, 46, 1, 35, 34, 6, 21, 20, 22, 31, 1, 30, 1, 21, 20, 6, 35, 34, 38, 39, 53, 35, 34, 38, 53,
+ 17, 1,135,239,133,145,145,133, 1,221, 6,113,122,236,239,190, 1,173,236,122, 87, 24, 81,174, 1,101,254,155, 71,108,171, 96,
+187, 91,122,132, 95,161, 60,161,143,211,194, 96,169, 72, 74,158, 85,129,129, 93,139, 59,185,155,233,203, 85,183,102,171,201,152,
+ 5, 47,253,207,146,135,134,146,254,204,200,106,113,253,168, 5,213,113, 82,136, 1, 62,254,194,143,253,160,137, 78, 35, 53, 53,
+ 89, 81, 75, 80, 37, 15, 36,149,130,158,172, 30, 30,174, 40, 40, 84, 84, 64, 73, 33, 14, 42,153,137,156,182, 35, 35, 1,159,210,
+ 2, 96, 0, 0, 0, 2, 0,201,255,227, 8, 51, 5,213, 0, 7, 0, 69, 0, 0, 1, 17, 51, 50, 54, 16, 38, 35, 1, 23, 35, 3,
+ 46, 1, 43, 1, 17, 35, 17, 33, 32, 22, 21, 20, 6, 7, 30, 1, 31, 1, 22, 23, 22, 51, 50, 54, 53, 52, 38, 47, 1, 46, 1, 53,
+ 52, 54, 51, 50, 22, 23, 21, 46, 1, 35, 34, 6, 21, 20, 22, 31, 1, 30, 1, 21, 20, 6, 35, 34, 39, 38, 1,147,254,146,149,149,
+146, 2,191, 4,217,191, 74,139,120,220,202, 1,200, 1, 0,252,131,125, 65,123, 62, 91, 98, 96, 99, 97,130,140,101,171, 64,171,
+152,224,206,102,180, 76, 78,168, 90,137,137, 98,148, 63,196,165,247,216, 90, 97, 44, 5, 47,253,238,135, 1, 6,133,250,216, 7,
+ 1,127,150, 98,253,137, 5,213,214,216,141,186, 36, 22,144,126,180, 51, 25, 27, 89, 81, 75, 80, 37, 15, 36,149,130,158,172, 30,
+ 30,174, 40, 40, 84, 84, 64, 73, 33, 14, 42,153,137,156,182, 18, 8, 0, 0, 0, 0, 6, 0, 59, 0, 0, 7,174, 5,213, 0, 31,
+ 0, 34, 0, 38, 0, 41, 0, 45, 0, 49, 0, 0, 19, 39, 35, 53, 51, 39, 51, 23, 33, 55, 51, 23, 33, 55, 51, 7, 51, 21, 35, 7,
+ 51, 21, 35, 3, 35, 3, 35, 3, 35, 3, 35, 53, 5, 27, 1, 1, 23, 33, 55, 1, 27, 2, 7, 51, 39, 33, 23, 33, 55,182, 30, 93,
+ 58, 49,204, 48, 2, 19, 48,227, 48, 2, 19, 48,205, 49, 57, 93, 29,122,158,225,254,218,195,220,254,224,159, 4,192,165,165,254,
+117, 29, 1,145, 29,251, 32,165,165,229, 29,125, 28,253, 76, 29, 1,145, 29, 4, 15,117,143,194,194,194,194,194,194,143,117,143,
+252,128, 3,128,252,128, 3,128,143,143,253,103, 2,153, 1, 4,117,117,254,252,253,103, 2,153, 1, 4,117,117,117,117, 0, 0,
+ 0, 2, 0, 95,255,227, 5,241, 5,213, 0, 13, 0, 27, 0, 0, 19, 37, 32, 0, 25, 1, 35, 17, 52, 38, 35, 33, 17, 35, 41, 1,
+ 34, 0, 25, 1, 51, 17, 20, 22, 51, 33, 3, 51, 95, 2, 7, 0,255, 1, 6,184,157,176,254,177,184, 5,142,253,253,255,254,250,
+184,157,176, 1, 83, 4,184, 5,210, 3,254,214,254,220,254,145, 1, 86,240,211,250,178, 1, 42, 1, 36, 1,111,254,170,240,211,
+ 5, 78, 0, 0,255,255, 0,129,254,192, 5, 4, 6, 20, 18, 34, 0,211, 16, 0, 16, 3, 2, 38, 0,138, 0, 0, 0, 1, 0, 0,
+255,227, 4,143, 5,240, 0, 49, 1, 28, 64, 58, 32, 18,211, 34, 16, 43, 7,211, 9, 25,161, 26,174, 22,149, 29, 1,161, 0,174,
+ 4,149, 47,145, 29,140, 41, 9, 50, 43, 34, 33, 41, 35, 38, 18, 16, 10, 3, 13, 9, 17, 8, 44, 32, 38, 19, 7, 17, 8, 17, 13,
+ 28, 25, 0, 38, 42, 33, 47, 60,212,196, 50,252,196,196, 18, 57, 57, 18, 57, 57, 17, 18, 57, 17, 23, 57, 18, 57, 57, 17, 57, 57,
+ 49, 0, 16,196, 50,228,244,236,244,236, 16,238,246,238, 16,238, 50,221, 60,238, 50, 48, 1, 75,176, 9, 84, 75,176, 12, 84, 91,
+ 75,176, 13, 84, 91, 75,176, 15, 84, 91, 75,176, 23, 84, 91, 75,176, 24, 84, 91, 88,189, 0, 50,255,192, 0, 1, 0, 50, 0, 50,
+ 0, 64, 56, 17, 55, 56, 89, 64,122, 14, 0, 14, 1, 11, 2, 11, 49, 84, 20,105, 12,108, 14,110, 15,111, 16,111, 17,111, 18,111,
+ 19,105, 20,107, 31,111, 32,111, 33,111, 34,111, 35,110, 36,108, 37,105, 39,105, 45,159, 7,159, 8,159, 9,159, 10,159, 11,159,
+ 12,159, 13,159, 14,159, 15,159, 16,159, 17,159, 18,159, 19,150, 31,159, 32,159, 33,159, 34,159, 35,159, 36,159, 37,159, 38,159,
+ 39,159, 40,159, 41,159, 42,159, 43,159, 44,157, 45, 50, 0, 8, 0, 9, 16, 8, 16, 9, 32, 8, 32, 9, 85, 21, 83, 30,106, 21,
+103, 31, 10, 93, 0, 93, 1, 21, 46, 1, 35, 34, 6, 7, 33, 7, 33, 14, 1, 21, 20, 22, 23, 33, 7, 33, 30, 1, 51, 50, 54, 55,
+ 21, 14, 1, 35, 34, 0, 3, 35, 55, 51, 52, 38, 53, 52, 54, 53, 35, 55, 51, 18, 0, 51, 50, 22, 4,143, 91,169,102,157,202, 32,
+ 2, 65, 55,253,230, 2, 1, 1, 2, 1,190, 56,254,138, 32,202,157,102,169, 91, 89,185, 96,237,254,203, 40,211, 55,139, 1, 1,
+194, 55,156, 40, 1, 54,236, 98,185, 5, 98,213,105, 90,200,187,123, 24, 46, 35, 32, 46, 24,123,187,202, 90,105,211, 72, 72, 1,
+ 34, 1, 3,123, 23, 47, 32, 35, 47, 23,123, 1, 1, 1, 34, 71, 0, 1, 0, 40, 0, 0, 5, 22, 5,213, 0, 17, 0, 0, 19, 17,
+ 51, 17, 1, 51, 1, 33, 21, 33, 1, 35, 1, 17, 35, 17, 35, 53,191,189, 2,117,243,253,128, 1,170,254, 88, 2,176,249,253, 95,
+189,151, 3, 84, 2,129,253,137, 2,119,253,127,115,253, 31, 2,207,253, 49, 2,225,115, 0, 0, 0, 1, 0, 20, 0, 0, 5, 3,
+ 5,213, 0, 23, 0, 0, 1, 17, 33, 53, 33, 21, 33, 17, 55, 23, 5, 21, 55, 23, 5, 17, 35, 17, 7, 39, 37, 53, 7, 39, 2, 38,
+253,238, 4,239,253,238,229, 80,254,203,230, 80,254,202,203,231, 77, 1, 52,232, 77, 3,141, 1,158,170,170,254,241,161,111,216,
+136,162,111,217,253,184, 1,186,161,110,217,136,162,110, 0, 0, 0, 4, 0, 27,254,117, 8, 90, 5,200, 0, 23, 0, 35, 0, 48,
+ 0, 59, 0, 0, 51, 55, 51, 54, 55, 19, 34, 6, 29, 1, 7, 16, 55, 54, 33, 51, 50, 0, 21, 16, 3, 6, 4, 33, 55, 51, 32, 0,
+ 17, 52, 38, 43, 1, 3, 2, 6, 1, 19, 26, 1, 51, 32, 17, 16, 0, 35, 34, 39, 3, 19, 22, 51, 50, 18, 53, 52, 35, 34, 3, 7,
+ 28,148, 56,116, 42,172,130,150,194,160,160, 1,138, 64,226, 1, 4,238,124,254,172,254,212, 48,118, 1, 24, 1, 68,150,128, 80,
+134, 52, 74, 2,140,160, 74,230,192, 1, 72,254,178,224, 52, 92, 86,124, 74, 74,132,176,150,156, 68, 26,160, 82,211, 3, 95,166,
+145, 24, 94, 1, 17,159,161,254,234,241,254,119,254,218,152,122,160, 1,168, 1,110,174,208,253, 88,254,255,161,253,139, 3, 44,
+ 1,115, 1, 66,254,165,254,206,254, 55, 35,254, 82, 2,109, 78, 1, 67,246,245,254,185,130, 0, 0, 4, 0, 68, 0, 0, 4,162,
+ 5,213, 0, 29, 0, 36, 0, 43, 0, 49, 0, 0, 19, 53, 35, 53, 51, 17, 33, 50, 23, 22, 23, 51, 21, 35, 22, 20, 7, 51, 21, 35,
+ 6, 7, 6, 43, 1, 17, 35, 17, 35, 53, 5, 33, 21, 51, 50, 55, 54, 1, 33, 38, 39, 38, 43, 1, 5, 33, 21, 33, 54, 52,151, 82,
+ 82, 1,200,251,129, 76, 31, 92, 72, 1, 1, 71, 90, 31, 77,129,251,254,202, 83, 3, 28,254, 1,254,141, 77, 23,254, 17, 1,255,
+ 16, 23, 77,141,254, 2, 35,253,221, 2, 35, 2, 3,236, 86,116, 1, 31,113, 68,106,116, 21, 44, 21,116,107, 68,113,253,168, 3,
+120,116,116,122, 73, 22, 1, 89, 27, 21, 73,237, 86, 21, 44, 0, 0, 1, 0,117,255,227, 5,188, 5,240, 0, 54, 0, 0, 1, 54,
+ 55, 54, 55, 33, 53, 33, 54, 55, 54, 53, 52, 38, 35, 34, 6, 7, 53, 62, 1, 51, 50, 4, 21, 20, 7, 51, 21, 33, 6, 15, 1, 33,
+ 21, 33, 6, 21, 20, 22, 51, 50, 54, 55, 21, 14, 1, 35, 32, 36, 53, 52, 55, 35, 53, 1, 92, 4, 22, 74,128,254, 53, 3,146, 12,
+ 13, 59,179,165, 95,204,115,114,218,105,245, 1, 23, 25,175,254,253,103,216, 67, 2,133,252, 83, 49,188,173,114,236,123,128,239,
+106,254,231,254,221, 18,168, 2,161, 7, 22, 74, 44,123, 8, 9, 43,107,118,128, 54, 55,197, 38, 38,228,198, 85, 66,123, 92, 42,
+ 13,123, 59, 94,126,136, 70, 69,208, 47, 48,224,217, 75, 63,123, 0, 2, 0,170,254,211, 4,119, 6, 20, 0, 33, 0, 44, 0, 0,
+ 1, 21, 38, 39, 38, 35, 17, 50, 55, 54, 55, 21, 6, 7, 6, 7, 17, 35, 17, 38, 39, 38, 17, 53, 16, 55, 54, 55, 53, 55, 21, 22,
+ 23, 22, 1, 3, 6, 7, 6, 7, 6, 23, 22, 23, 22, 4,119, 91, 84, 85,101,101, 85, 84, 91, 89, 92, 89, 91,100,185,115,212,212,
+121,178,101, 93, 89, 92,254,138, 1, 91, 67,118, 15, 14, 14, 25,108, 67, 4,164,213,105, 45, 45,251,241, 45, 45,105,211, 72, 36,
+ 34, 2,254,240, 1, 21, 23,117,214, 1, 57, 17, 1, 66,203,116, 23,230, 2,226, 2, 34, 35,251,163, 3,249, 23, 66,117,170,161,
+102,180,108, 67, 0, 1,252, 61, 4,122,255,203, 6, 20, 0, 8, 0, 0, 3, 33, 23, 35, 39, 55, 51, 7, 33, 53,253, 27,132,126,
+175,175,126,132, 2,229, 5, 21,155,205,205,155, 0, 1,252, 61, 4,122,255,203, 6, 20, 0, 8, 0, 0, 1, 53, 33, 39, 51, 23,
+ 7, 35, 55,252, 61, 2,229,132,126,175,175,126,132, 5, 21,100,155,205,205,155, 0, 4, 0, 67,255,207, 7,216, 6, 4, 0, 10,
+ 0, 36, 0, 40, 0, 66, 0, 0, 1, 34, 6, 21, 20, 22, 51, 50, 54, 61, 1, 55, 17, 35, 53, 14, 1, 35, 34, 38, 53, 52, 54, 51,
+ 23, 52, 38, 35, 34, 6, 7, 53, 62, 1, 51, 50, 22, 37, 51, 1, 35, 1, 21, 46, 1, 35, 34, 6, 21, 20, 22, 51, 50, 54, 55, 21,
+ 14, 1, 35, 34, 38, 53, 52, 54, 51, 50, 22, 2, 15,160,112, 83, 72,102,127,188,188, 3,153,109,141,166,205,198,169,111,103, 68,
+129, 99, 92,148, 71,194,193, 2,176,216,252, 68,216, 5,169, 94,111, 56,121,137,137,121, 56,111, 94, 73,130, 73,202,236,238,209,
+ 67,128, 3,246, 66, 82, 67, 73,148,130, 10, 77,254, 13, 62, 5, 79,158,129,150,155, 6, 87, 92, 32, 55,178, 36, 30,202,250,249,
+203, 3,132,178, 52, 30,156,148,147,157, 31, 52,177, 34, 27,250,209,212,249, 27,255,255, 0,195,255,240, 8,140, 5,240, 16, 38,
+ 0,114, 0, 0, 16, 71, 0, 38, 3, 70, 0, 12, 65,117, 62, 82, 0, 2,255,214, 0, 0, 5, 24, 5,213, 0, 8, 0, 43, 0,153,
+184, 0, 44, 47,184, 0, 45, 47,184, 0, 21,220,184, 0, 0,220,184, 0, 44, 16,184, 0, 40,208,184, 0, 40, 47,184, 0, 4,220,
+ 65, 27, 0, 22, 0, 4, 0, 38, 0, 4, 0, 54, 0, 4, 0, 70, 0, 4, 0, 86, 0, 4, 0,102, 0, 4, 0,118, 0, 4, 0,134,
+ 0, 4, 0,150, 0, 4, 0,166, 0, 4, 0,182, 0, 4, 0,198, 0, 4, 0,214, 0, 4, 0, 13, 93, 65, 5, 0,229, 0, 4, 0,
+245, 0, 4, 0, 2, 93,184, 0, 0, 16,184, 0, 9,208,184, 0, 21, 16,184, 0, 11,208,184, 0, 21, 16,184, 0, 31,208,184, 0,
+ 0, 16,184, 0, 35,208, 0,184, 0, 10, 47,186, 0, 33, 0, 34, 0, 3, 43,184, 0, 33, 16, 48, 49, 1, 6, 7, 6, 21, 20, 23,
+ 22, 23, 17, 53, 51, 21, 22, 23, 22, 23, 21, 38, 39, 38, 39, 17, 54, 55, 54, 55, 21, 6, 7, 6, 7, 21, 33, 21, 33, 53, 38, 39,
+ 38, 17, 16, 55, 54, 1,119, 73, 51, 99, 99, 51, 73,202, 56, 54, 81, 76, 78, 78, 55, 56, 56, 55, 78, 78, 77, 82, 52, 56, 2,215,
+252, 95,161,107,149,151,105, 4,179, 29, 58,114,205,205,113, 59, 29, 3,212,122,110, 4, 11, 18, 35,172, 43, 22, 15, 4,252,164,
+ 4, 16, 21, 43,170, 36, 18, 11, 4, 42,170,222, 32,114,159, 1, 14, 1, 18,157,110, 0, 0, 0, 0, 4, 0, 60,255,207, 7,229,
+ 6, 4, 0, 25, 0, 29, 0, 40, 0, 50, 0, 0, 1, 21, 46, 1, 35, 34, 6, 21, 20, 22, 51, 50, 54, 55, 21, 14, 1, 35, 34, 38,
+ 53, 52, 54, 51, 50, 22, 37, 51, 1, 35, 1, 34, 6, 21, 20, 22, 51, 50, 54, 16, 38, 36, 32, 22, 21, 20, 6, 32, 38, 53, 52, 3,
+ 6, 94,111, 56,121,137,137,121, 56,111, 94, 73,130, 73,202,236,238,209, 67,128, 2,221,216,252, 68,216, 4,107, 97,118,118, 97,
+ 96,119,119,254,223, 1,130,218,218,254,126,217, 5,151,178, 52, 30,156,148,147,157, 31, 52,177, 34, 29,252,209,212,249, 27, 75,
+249,203, 3, 4,158,146,145,159,160, 1, 32,160,157,248,213,212,248,248,212,213, 0, 3, 0, 60,255,207, 8, 77, 6, 4, 0, 19,
+ 0, 45, 0, 49, 0, 0, 1, 17, 51, 17, 20, 22, 51, 50, 54, 53, 17, 51, 17, 35, 53, 14, 1, 35, 34, 38, 1, 21, 46, 1, 35, 34,
+ 6, 21, 20, 22, 51, 50, 54, 55, 21, 14, 1, 35, 34, 38, 53, 52, 54, 51, 50, 22, 37, 51, 1, 35, 5, 92,188, 81, 80, 99,117,188,
+188, 6,144, 96,158,161,253,170, 94,111, 56,121,137,137,121, 56,111, 94, 73,130, 73,202,236,238,209, 67,128, 2,221,216,252, 68,
+216, 1, 76, 2, 16,253,245,114,105,129,117, 1,240,252,144, 68, 9, 80,193, 4,255,178, 52, 30,156,148,147,157, 31, 52,177, 34,
+ 29,252,209,212,249, 27, 75,249,203, 0, 0, 0,255,255, 0,195, 0, 0, 7, 38, 5,240, 16, 34, 0,114, 0, 0, 16, 3, 0, 41,
+ 3, 3, 0, 0, 0, 1, 0, 72, 0, 0, 4,135, 6, 20, 0, 25, 0, 0, 1, 3, 35, 19, 62, 1, 53, 52, 38, 35, 34, 6, 7, 3,
+ 35, 1, 51, 3, 62, 1, 51, 50, 22, 21, 20, 6, 4,117,131,185,131, 9, 10,106, 95,148,217, 32,121,184, 1, 47,184,119, 70,218,
+120,148,163, 9, 2,164,253, 92, 2,157, 47, 72, 21, 84, 94,200,166,253,147, 6, 20,253,156, 94,109,160,145, 36, 82, 0, 0, 0,
+ 0, 1, 0, 34, 0, 0, 4, 98, 6, 20, 0, 29, 0, 0, 1, 54, 55, 54, 51, 50, 23, 22, 7, 3, 35, 19, 54, 38, 35, 34, 6, 7,
+ 3, 35, 19, 35, 55, 51, 55, 51, 7, 33, 7, 33, 1,148, 85, 99,100,117,193, 76, 75, 45,131,184,130, 31, 93,124,149,209, 32,123,
+185,249,154, 25,154, 28,185, 28, 2, 64, 25,253,192, 3,178,101, 50, 50,119,120,232,253, 92, 2,158,159,158,190,164,253,135, 5,
+ 4,125,147,147,125, 0, 0, 0, 0, 2, 0,106,255,227, 5, 70, 5,240, 0, 33, 0, 50, 0, 0, 63, 1, 54, 51, 50, 23, 22, 51,
+ 50, 55, 54, 53, 52, 39, 38, 53, 52, 63, 1, 6, 21, 20, 23, 22, 21, 20, 7, 6, 35, 34, 39, 38, 35, 34, 19, 54, 51, 50, 23, 22,
+ 51, 50, 55, 7, 6, 35, 34, 38, 35, 34, 7,106,140,111,117, 57,132,144, 33,121,100, 71, 62, 80, 80,213, 80, 80, 53,202,186,242,
+ 54,129,133, 56, 94,110,109,141,123,127,122,128,125,125,200,139,111,143,214,143,122,128, 90,165, 39, 80, 86,137, 97, 75,126,112,
+146,109,100,160,140,139,121,107,148, 98,188, 94,242,222, 79, 80, 5, 54, 56, 49, 47, 58,170, 58, 98, 58, 0, 0, 0, 2,255,228,
+255,227, 2,210, 5,240, 0, 28, 0, 38, 0, 0, 1, 22, 51, 50, 55, 51, 6, 7, 6, 35, 34, 39, 7, 35, 54, 55, 38, 53, 52, 55,
+ 18, 55, 54, 51, 50, 21, 6, 7, 2, 1, 18, 19, 54, 53, 52, 35, 6, 3, 6, 1, 48, 41, 87, 58, 75,133, 60, 70, 76, 70,156, 63,
+ 75,156,108, 80, 10, 31,117,104, 72,123,125, 1, 18, 72,254,184,187, 57, 30, 25,109, 97, 27, 1, 12,200,115,102, 53, 57,139,110,
+147,137, 78, 85,152,152, 2, 59,117, 81,173, 78, 93,254,131,254,247, 1, 92, 1, 22,147, 38, 69, 87,253,250,145,255,255, 0,201,
+ 0, 0, 8,240, 5,240, 16, 39, 0,124, 5,140, 0, 0, 16, 6, 0, 49, 0, 0, 0, 4, 1, 27, 0, 0, 6,229, 5,202, 0, 12,
+ 0, 25, 0, 34, 0, 45, 0, 0, 1, 22, 17, 16, 0, 33, 32, 0, 3, 16, 0, 33, 32, 6, 33, 32, 0, 17, 18, 0, 33, 32, 0, 17,
+ 16, 39, 5, 17, 51, 50, 54, 53, 52, 38, 35, 37, 33, 50, 22, 21, 20, 6, 43, 1, 17, 35, 6, 11,218,254, 74,254,209,254,207,254,
+ 82, 6, 1,180, 1, 49, 1, 50, 41,254,247,254,250,254,134, 5, 1,117, 1, 6, 1, 7, 1,121,187,253,211,178, 99,107,107, 99,
+254,193, 1, 63,176,180,180,176,178,141, 4,241,219,254,206,254,208,254, 76, 1,180, 1, 48, 1, 48, 1,182,101,254,133,254,249,
+254,251,254,135, 1,121, 1, 5, 1, 9,187,119,254,175, 88, 81, 80, 88,100,137,131,133,135,254,152, 0, 0, 0, 0, 2, 0,110,
+254, 59, 5, 67, 3,246, 0, 48, 0, 60, 0, 0, 1, 6, 21, 20, 23, 54, 55, 54, 51, 50, 23, 22, 21, 20, 7, 6, 35, 34, 39, 54,
+ 55, 22, 51, 50, 55, 54, 53, 52, 39, 38, 35, 34, 1, 18, 21, 20, 7, 6, 35, 34, 39, 38, 53, 16, 55, 38, 53, 52, 55, 3, 6, 21,
+ 20, 23, 22, 23, 50, 55, 54, 53, 52, 2, 53,136, 31, 91,171,219,132,131, 70, 73,156,121,174,101, 76, 18, 9, 41,113,122, 93, 69,
+ 38, 32, 74,189,254,159,135, 69, 89,131,113, 58, 63,223, 46,232,148,129, 31, 48, 46, 65, 28, 32, 3,198,130,190, 77,107,101,148,
+189, 76, 80,171,218,215,167, 60, 43, 29, 40,140,104,195,124, 72, 61,254,121,254,222,124,157,110,142, 61, 66,134, 1, 11,252,158,
+127,238,164,252,239,198,123,117, 46, 70, 1, 47, 52, 95, 78, 0, 0, 2, 0, 83,255,227, 6,108, 5,241, 0, 73, 0, 88, 0, 0,
+ 5, 38, 53, 52, 39, 38, 35, 34, 15, 1, 21, 20, 7, 6, 35, 34, 39, 38, 53, 22, 23, 20, 23, 22, 50, 55, 54, 53, 17, 52, 39, 38,
+ 35, 34, 7, 6, 20, 23, 22, 51, 23, 34, 39, 38, 53, 52, 55, 54, 51, 50, 23, 22, 23, 55, 54, 51, 50, 23, 22, 21, 20, 7, 6, 7,
+ 50, 23, 22, 23, 22, 21, 20, 23, 55, 23, 1, 22, 21, 17, 55, 54, 55, 54, 53, 52, 39, 38, 35, 34, 7, 5, 2, 82, 22, 40, 79, 42,
+ 92,120,103,103,140,141,102,103, 45, 46, 64, 64,144, 63, 64, 64, 63, 92, 81, 65, 64, 64, 64, 83, 54,151,102,103,103,102,151,162,
+101, 30, 16,211,187,112, 47, 36,126, 65, 66,125, 58, 49, 36, 27, 32, 45,144, 42,252,164, 21,154,144, 77, 74, 74, 24, 31, 64,102,
+ 29,183,159,140, 91,166, 43, 56,199,206,118,117,117,118,176, 12, 12,122, 86, 87, 87, 87,150, 2,155,149, 88, 87, 87, 86,202, 86,
+ 87, 92,117,118,156,157,117,117,117, 35, 32, 98, 87, 14, 49,177, 87,123,124, 94, 49, 36,104,123,131,128,118, 67, 91, 4, 83, 75,
+ 92,254,149, 71, 67,104,102,121,151, 32, 10, 47, 0, 5, 0,118, 0, 0, 5,225, 5,213, 0, 7, 0, 27, 0, 31, 0, 39, 0, 48,
+ 0, 0, 1, 22, 23, 19, 51, 3, 38, 39, 32, 43, 1, 17, 33, 17, 33, 32, 22, 21, 20, 6, 7, 30, 1, 23, 19, 33, 3, 38, 1, 17,
+ 51, 17, 1, 17, 38, 35, 33, 17, 33, 50, 55, 54, 55, 54, 53, 52, 39, 38, 39, 3, 46, 78,102,142,200,142, 96, 90,254,164,120, 20,
+254,110, 2,168, 1, 0,252,132,124, 64,124, 62,204,254, 72,190, 74,253,186,198, 1,238, 34, 38,254,194, 1, 62, 38,138, 58, 40,
+ 94, 94, 38, 60, 2,119, 47,201,254,229, 1, 27,192, 56,253,137, 5,213,214,216,141,186, 36, 22,144,126,254,104, 1,127,150, 3,
+ 92,250,243, 5, 13,253,110, 2,142, 4,253,106, 27, 21, 37, 84,164,158, 88, 36, 20, 0, 0, 0, 0, 2, 0,169, 0, 0, 6,131,
+ 5,213, 0, 8, 0, 31, 0,167,184, 0, 32, 47,184, 0, 33, 47,184, 0, 32, 16,184, 0, 14,208,184, 0, 14, 47,184, 0, 13,220,
+184, 0, 0,208,184, 0, 33, 16,184, 0, 19,220,184, 0, 5,220, 65, 5, 0,234, 0, 5, 0,250, 0, 5, 0, 2, 93, 65, 27, 0,
+ 25, 0, 5, 0, 41, 0, 5, 0, 57, 0, 5, 0, 73, 0, 5, 0, 89, 0, 5, 0,105, 0, 5, 0,121, 0, 5, 0,137, 0, 5, 0,
+153, 0, 5, 0,169, 0, 5, 0,185, 0, 5, 0,201, 0, 5, 0,217, 0, 5, 0, 13, 93,184, 0, 9,208,184, 0, 9, 47,186, 0,
+ 30, 0, 14, 0, 19, 17, 18, 57, 0,184, 0, 13, 47,184, 0, 26, 47,184, 0, 29, 47,186, 0, 15, 0, 0, 0, 3, 43,184, 0, 15,
+ 16,186, 0, 2, 0, 11, 0, 3, 43,184, 0, 2, 16, 48, 49, 1, 17, 51, 50, 54, 53, 52, 38, 35, 1, 6, 43, 1, 17, 35, 17, 33,
+ 50, 4, 21, 20, 7, 23, 55, 51, 9, 1, 35, 11, 1, 35, 1, 1,115,254,141,154,154,141, 1, 32,115,173,254,202, 1,200,251, 1,
+ 1, 78,174,190,232,254,205, 1, 67,233,207,212,232, 1, 73, 5, 47,253,207,146,135,134,146,253, 95, 54,253,168, 5,213,227,219,
+172,107,219,234,254,134,254,107, 1, 4,254,252, 1,149, 0, 0, 0, 2, 1, 3, 3,139, 6, 40, 5,216, 0, 39, 0, 52, 0, 0,
+ 1, 21, 46, 1, 35, 34, 6, 21, 20, 22, 31, 1, 30, 1, 21, 20, 6, 35, 34, 38, 39, 53, 30, 1, 51, 50, 54, 53, 52, 38, 47, 1,
+ 46, 1, 53, 52, 54, 51, 50, 22, 55, 51, 27, 1, 51, 17, 35, 17, 3, 35, 3, 17, 35, 2,230, 85, 87, 39, 65, 71, 47, 69, 56,112,
+105,144,140, 52,115, 71, 91,100, 47, 69, 75, 55, 63, 56,112, 99,138,124, 51,105,208,184,161,162,184,138,140,135,141,137, 5,183,
+ 89, 34, 19, 42, 47, 40, 32, 11, 9, 18, 86, 65, 79, 91, 19, 21, 96, 42, 24, 44, 50, 44, 42, 10, 9, 18, 77, 61, 72, 92, 15, 5,
+254,172, 1, 84,253,200, 1,148,254,216, 1, 40,254,108, 0, 0, 0, 3,255,252, 0, 0, 8, 48, 4, 96, 0, 7, 0, 19, 0, 25,
+ 0, 0, 3, 33, 21, 33, 17, 35, 17, 33, 5, 33, 21, 33, 17, 33, 21, 33, 17, 33, 21, 33, 1, 51, 17, 33, 21, 33, 4, 3,179,254,
+114,152,254,115, 2,224, 2,111,254, 22, 1,213,254, 43, 1,246,253,133, 2,239,133, 1,224,253,155, 4, 96,128,252, 32, 3,224,
+ 96,102,254,247,102,254,187,102, 3,128,252,230,102, 0, 0, 0, 0, 2, 1, 39, 3,147, 6, 70, 5,213, 0, 12, 0, 20, 0, 62,
+ 64, 33, 1, 6, 7, 16, 10, 4, 18, 14, 9, 3, 6,201, 13, 2, 0,129, 21, 1, 9, 5, 98, 3, 9, 98, 11, 13, 99, 15, 98, 19,
+ 99, 17, 21, 16,212,228,252,228,212,236,212,236, 17, 57, 49, 0, 16,244, 60, 60,236, 23, 50,212, 60, 60,196, 17, 57, 48, 1, 27,
+ 1, 51, 17, 35, 17, 3, 35, 3, 17, 35, 17, 35, 21, 35, 17, 35, 17, 35, 53, 4, 74,174,164,170,113,195, 55,203,114,113,203,114,
+201, 5,213,255, 0, 1, 0,253,190, 1,228,254,209, 1, 47,254, 28, 2, 66, 94,254, 28, 1,228, 94, 0, 0, 0,255,255, 0, 78,
+ 0, 0, 5,207, 5,231, 16, 6, 2,199, 0, 0, 0, 1, 0, 78,255,227, 5,207, 5,202, 0, 30, 0, 0, 1, 53, 33, 21, 22, 18,
+ 21, 20, 0, 32, 0, 53, 52, 18, 55, 53, 33, 21, 33, 6, 2, 21, 16, 0, 33, 32, 0, 17, 52, 2, 39, 5,207,253,168,177,198,254,
+248,254, 80,254,247,199,178,253,168, 1, 63,158,145, 1,127, 1, 49, 1, 47, 1,129,142,161, 5, 24,178,178, 97,254,180,202,240,
+254,222, 1, 35,239,202, 1, 76, 97,178,178,139,254,214,184,254,194,254,118, 1,137, 1, 53,194, 1, 40,141, 0,255,255, 0,201,
+ 0, 0, 5,106, 5,213, 16, 6, 0, 46, 0, 0,255,255, 0, 16, 0, 0, 5,104, 7,109, 16, 6, 0,135, 0, 0, 0, 2, 0,125,
+255,231, 6, 89, 5, 45, 0, 26, 0, 41, 0, 0, 37, 22, 23, 22, 32, 55, 54, 55, 51, 6, 7, 6, 32, 36, 2, 53, 52, 18, 36, 51,
+ 50, 4, 18, 21, 33, 34, 21, 53, 20, 51, 33, 50, 53, 17, 38, 39, 38, 35, 34, 7, 6, 7, 1,144, 67, 93,150, 1, 74,152,106, 77,
+111, 95,142,179,254,122,254,155,198,201, 1,103,190,189, 1,103,202,251, 74, 19, 19, 3,144, 20, 70, 95,152,159,160,152, 95, 68,
+228, 77, 51, 84, 84, 60, 96,120, 71, 90,179, 1, 65,175,176, 1, 69,174,174,254,187,176, 19, 73, 19, 19, 1,112, 80, 51, 82, 81,
+ 52, 79, 0, 0, 0, 1, 0,201, 0, 0, 4, 35, 5,213, 0, 9, 0, 0, 41, 1, 53, 33, 17, 33, 53, 33, 17, 51, 4, 35,252,166,
+ 2,144,253,176, 2, 80,202,170, 1,184,170, 2,201, 0, 0, 0, 0, 2, 0,104,255,231, 3, 74, 3, 41, 0, 11, 0, 23, 0, 0,
+ 1, 52, 38, 35, 34, 2, 21, 20, 22, 51, 50, 18, 3, 50, 22, 21, 20, 2, 35, 34, 38, 53, 52, 18, 2,169, 87, 79,109,141, 86, 80,
+109,141,194,152,203,221,162,152,203,221, 1,247,116,125,254,254,207,116,123, 1, 4, 1,253,216,163,198,254,255,216,163,198, 1,
+ 1, 0, 0, 0, 0, 1, 0,103,255,227, 5,178, 5,240, 0, 54, 0, 0, 9, 1, 22, 21, 20, 7, 52, 39, 1, 7, 6, 31, 1, 22,
+ 21, 20, 7, 6, 43, 1, 53, 54, 53, 52, 47, 1, 38, 53, 52, 63, 1, 39, 38, 53, 52, 55, 20, 23, 9, 1, 39, 38, 53, 52, 55, 20,
+ 31, 1, 22, 21, 20, 7, 52, 47, 1, 3,196, 1,139, 99,144, 50,252,251,155, 62, 66,172,100, 61, 86, 69,245,196, 47, 98, 53,140,
+154,241, 99,144, 50, 2,108, 1, 25,116, 99,144, 50,182, 99,144, 50, 18, 2,208,254,117, 99, 49,130, 76, 83, 50, 3, 5,156, 63,
+ 66,172,100,106,108, 44, 62, 56, 63, 93, 29, 47, 99, 54,103, 85,141,155,241, 99, 49,130, 76, 83, 50,253,150, 1, 25,116, 99, 49,
+130, 76, 83, 50,182, 99, 49,130, 76, 83, 50, 18, 0, 4, 0,151, 0, 0, 9, 76, 4, 96, 0, 9, 0, 12, 0, 20, 0, 32, 0, 0,
+ 19, 33, 21, 33, 17, 33, 21, 33, 17, 35, 1, 3, 33, 1, 51, 1, 35, 39, 33, 7, 35, 1, 51, 27, 1, 51, 9, 1, 35, 9, 1, 35,
+ 1,151, 2,131,254, 20, 1,188,254, 68,151, 3,131,181, 1,106,255, 0,151, 1,119,138, 90,254, 68, 90,140, 3,214,143,245,246,
+144,254,195, 1, 82,144,254,235,254,233,144, 1, 96, 4, 96,128,254,182,127,253,233, 3, 8,254, 67, 2, 53,252,128,230,230, 3,
+128,254,179, 1, 77,254, 82,254, 46, 1,125,254,131, 1,222, 0, 0, 2, 0, 59,255,227, 5,184, 5,240, 0, 38, 0, 48, 0, 0,
+ 9, 1, 14, 1, 7, 35, 54, 18, 55, 1, 51, 23, 62, 1, 51, 50, 0, 21, 20, 6, 7, 30, 1, 21, 20, 6, 35, 34, 38, 39, 53, 30,
+ 1, 51, 50, 54, 53, 52, 38, 55, 62, 1, 53, 52, 38, 35, 34, 6, 7, 3,186,254, 4, 59, 66, 6,186, 12,104, 93,254,233,252,143,
+104,228,131,241, 1, 50,134,134, 48, 50,222,184, 83,165, 85, 87,158, 68,105,131, 59, 50, 91, 85,212,160, 95,166, 73, 2, 64, 2,
+ 8, 89,203,114,132, 1, 2,126, 1, 29,147, 89, 87,254,237,215,128,225, 99, 63,125, 60,162,197, 36, 36,182, 47, 49,111, 88, 51,
+103,206, 81,161, 88,146,194, 63, 64, 0, 0, 0,255,255, 0,137,255,227, 7, 88, 5,240, 16, 34, 0,123, 0, 0, 16, 39, 6, 90,
+ 3, 53, 0, 0, 16, 3, 0,117, 4,139,253,100,255,255, 0, 94,255,227, 7, 88, 5,240, 16, 34, 0,116, 0, 0, 16, 39, 6, 90,
+ 3, 53, 0, 0, 16, 3, 0,117, 4,139,253,100,255,255, 0,137,255,227, 7, 94, 5,240, 16, 34, 0,123, 0, 0, 16, 39, 6, 90,
+ 3, 53, 0, 0, 16, 3, 5,207, 4,139,253,100,255,255, 0, 94,255,227, 7, 94, 5,240, 16, 34, 0,116, 0, 0, 16, 39, 6, 90,
+ 3, 53, 0, 0, 16, 3, 5,207, 4,139,253,100,255,255, 0, 98,255,227, 7, 94, 5,240, 16, 34, 0,117, 0, 0, 16, 39, 6, 90,
+ 3, 53, 0, 0, 16, 3, 5,207, 4,139,253,100,255,255, 0, 63,255,227, 7, 94, 5,240, 16, 34, 5,206, 0, 0, 16, 39, 6, 90,
+ 3, 53, 0, 0, 16, 3, 5,207, 4,139,253,100,255,255, 0,137,255,227, 7,126, 5,240, 16, 34, 0,123, 0, 0, 16, 39, 6, 90,
+ 3, 53, 0, 0, 16, 3, 5,208, 4,139,253,100,255,255, 0,102,255,227, 7,126, 5,240, 16, 34, 5,207, 0, 0, 16, 39, 6, 90,
+ 3, 53, 0, 0, 16, 3, 5,208, 4,139,253,100,255,255, 0,137,255,227, 7,119, 5,240, 16, 34, 0,123, 0, 0, 16, 39, 6, 90,
+ 3, 53, 0, 0, 16, 3, 5,210, 4,139,253,100,255,255, 0, 98,255,227, 7,119, 5,240, 16, 34, 0,117, 0, 0, 16, 39, 6, 90,
+ 3, 53, 0, 0, 16, 3, 5,210, 4,139,253,100,255,255, 0,102,255,227, 7,119, 5,240, 16, 34, 5,207, 0, 0, 16, 39, 6, 90,
+ 3, 53, 0, 0, 16, 3, 5,210, 4,139,253,100,255,255, 0,108,255,227, 7,119, 5,240, 16, 34, 5,209, 0, 0, 16, 39, 6, 90,
+ 3, 53, 0, 0, 16, 3, 5,210, 4,139,253,100,255,255, 0,137,255,227, 6, 2, 5,240, 16, 34, 0,123, 0, 0, 16, 7, 6, 90,
+ 3, 53, 0, 0,255,255, 0,201, 0, 0, 1,147, 5,213, 16, 6, 0, 44, 0, 0,255,255, 0,201, 0, 0, 3, 39, 5,213, 16, 38,
+ 0, 44, 0, 0, 16, 7, 0, 44, 1,148, 0, 0,255,255, 0,201, 0, 0, 4,187, 5,213, 16, 38, 0, 44, 0, 0, 16, 39, 0, 44,
+ 1,148, 0, 0, 16, 7, 0, 44, 3, 40, 0, 0,255,255, 0,201, 0, 0, 7, 81, 5,213, 16, 38, 0, 44, 0, 0, 16, 7, 0, 57,
+ 1,233, 0, 0,255,255, 0, 16, 0, 0, 5,104, 5,213, 16, 6, 0, 57, 0, 0,255,255, 0, 16, 0, 0, 6,152, 5,213, 16, 38,
+ 0, 57, 0, 0, 16, 7, 0, 44, 5, 5, 0, 0,255,255, 0, 16, 0, 0, 8, 44, 5,213, 16, 38, 0, 57, 0, 0, 16, 39, 0, 44,
+ 5, 5, 0, 0, 16, 7, 0, 44, 6,153, 0, 0,255,255, 0, 16, 0, 0, 9,192, 5,213, 16, 38, 0, 57, 0, 0, 16, 39, 0, 44,
+ 5, 5, 0, 0, 16, 39, 0, 44, 6,153, 0, 0, 16, 7, 0, 44, 8, 45, 0, 0,255,255, 0,201, 0, 0, 7, 23, 5,213, 16, 38,
+ 0, 44, 0, 0, 16, 7, 0, 59, 1,220, 0, 0,255,255, 0, 61, 0, 0, 5, 59, 5,213, 16, 6, 0, 59, 0, 0,255,255, 0, 61,
+ 0, 0, 6,174, 5,213, 16, 38, 0, 59, 0, 0, 16, 7, 0, 44, 5, 27, 0, 0,255,255, 0, 61, 0, 0, 8, 66, 5,213, 16, 38,
+ 0, 59, 0, 0, 16, 39, 0, 44, 5, 27, 0, 0, 16, 7, 0, 44, 6,175, 0, 0,255,255, 0,201, 0, 0, 4,106, 5,213, 16, 6,
+ 0, 47, 0, 0,255,255, 0,115,255,227, 5, 39, 5,240, 16, 6, 0, 38, 0, 0,255,255, 0,201, 0, 0, 5,176, 5,213, 16, 6,
+ 0, 39, 0, 0,255,255, 0,201, 0, 0, 6, 31, 5,213, 16, 6, 0, 48, 0, 0,255,255, 0,193, 0, 0, 1,121, 6, 20, 16, 6,
+ 0, 76, 0, 0,255,255, 0,193, 0, 0, 2,233, 6, 20, 16, 38, 0, 76, 0, 0, 16, 7, 0, 76, 1,112, 0, 0,255,255, 0,193,
+ 0, 0, 4, 89, 6, 20, 16, 38, 0, 76, 0, 0, 16, 39, 0, 76, 1,112, 0, 0, 16, 7, 0, 76, 2,224, 0, 0,255,255, 0,193,
+ 0, 0, 6, 65, 6, 20, 16, 38, 0, 76, 0, 0, 16, 7, 0, 89, 1,194, 0, 0,255,255, 0, 61, 0, 0, 4,127, 4, 96, 16, 6,
+ 0, 89, 0, 0,255,255, 0, 61, 0, 0, 5,189, 6, 20, 16, 38, 0, 89, 0, 0, 16, 7, 0, 76, 4, 68, 0, 0,255,255, 0, 61,
+ 0, 0, 7, 45, 6, 20, 16, 38, 0, 89, 0, 0, 16, 39, 0, 76, 4, 68, 0, 0, 16, 7, 0, 76, 5,180, 0, 0,255,255, 0, 61,
+ 0, 0, 8,157, 6, 20, 16, 38, 0, 89, 0, 0, 16, 39, 0, 76, 4, 68, 0, 0, 16, 39, 0, 76, 5,180, 0, 0, 16, 7, 0, 76,
+ 7, 36, 0, 0,255,255, 0,193, 0, 0, 6, 74, 6, 20, 16, 38, 0, 76, 0, 0, 16, 7, 0, 91, 1,209, 0, 0,255,255, 0, 59,
+ 0, 0, 4,121, 4, 96, 16, 6, 0, 91, 0, 0,255,255, 0, 59, 0, 0, 5,212, 6, 20, 16, 38, 0, 91, 0, 0, 16, 7, 0, 76,
+ 4, 91, 0, 0,255,255, 0, 59, 0, 0, 7, 68, 6, 20, 16, 38, 0, 91, 0, 0, 16, 39, 0, 76, 4, 91, 0, 0, 16, 7, 0, 76,
+ 5,203, 0, 0,255,255, 0,193, 0, 0, 1,121, 6, 20, 16, 6, 0, 79, 0, 0,255,255, 0,113,255,227, 3,231, 4,123, 16, 6,
+ 0, 70, 0, 0,255,255, 0,113,255,227, 4, 90, 6, 20, 16, 6, 0, 71, 0, 0,255,255, 0,186, 0, 0, 7, 29, 4,123, 16, 6,
+ 0, 80, 0, 0, 0, 3, 0,121,255,255, 9,125, 5,213, 0, 13, 0, 22, 0, 31, 0, 0, 1, 32, 0, 17, 16, 0, 41, 1, 32, 0,
+ 17, 16, 0, 33, 1, 51, 32, 0, 17, 16, 0, 33, 35, 3, 17, 35, 32, 0, 17, 16, 0, 33, 6, 53, 1,178, 1,150,254,104,254, 80,
+253,140,254, 80,254,104, 1,150, 1,178, 1,159,244, 1, 53, 1, 31,254,225,254,203,244,202,244,254,203,254,225, 1, 31, 1, 53,
+ 5,213,254,151,254,128,254,126,254,150, 1,106, 1,130, 1,128, 1,105,250,209, 1, 24, 1, 46, 1, 44, 1, 23,251,119, 4,137,
+254,233,254,212,254,210,254,232, 0, 3, 0,201, 0, 0, 5,176, 5,213, 0, 17, 0, 26, 0, 35, 0,251,186, 0, 9, 0, 27, 0,
+ 3, 43,184, 0, 9, 16,186, 0, 14, 0, 23, 0, 3, 43,184, 0, 14, 16,186, 0, 31, 0, 5, 0, 3, 43,184, 0, 31, 16,184, 0,
+ 9, 16,184, 0, 0,208, 65, 5, 0,234, 0, 5, 0,250, 0, 5, 0, 2, 93, 65, 27, 0, 25, 0, 5, 0, 41, 0, 5, 0, 57, 0,
+ 5, 0, 73, 0, 5, 0, 89, 0, 5, 0,105, 0, 5, 0,121, 0, 5, 0,137, 0, 5, 0,153, 0, 5, 0,169, 0, 5, 0,185, 0,
+ 5, 0,201, 0, 5, 0,217, 0, 5, 0, 13, 93,184, 0, 9, 16,184, 0, 18,208, 65, 5, 0,234, 0, 23, 0,250, 0, 23, 0, 2,
+ 93, 65, 27, 0, 25, 0, 23, 0, 41, 0, 23, 0, 57, 0, 23, 0, 73, 0, 23, 0, 89, 0, 23, 0,105, 0, 23, 0,121, 0, 23, 0,
+137, 0, 23, 0,153, 0, 23, 0,169, 0, 23, 0,185, 0, 23, 0,201, 0, 23, 0,217, 0, 23, 0, 13, 93,184, 0, 31, 16,184, 0,
+ 37,220, 0,186, 0, 2, 0, 34, 0, 3, 43,184, 0, 2, 16,186, 0, 28, 0, 8, 0, 3, 43,184, 0, 28, 16,186, 0, 19, 0, 0,
+ 0, 3, 43,184, 0, 19, 16,186, 0, 10, 0, 18, 0, 3, 43,184, 0, 10, 16, 48, 49, 1, 21, 51, 32, 0, 17, 16, 0, 33, 35, 21,
+ 51, 32, 22, 21, 20, 6, 35, 3, 17, 51, 50, 54, 53, 52, 38, 35, 1, 33, 32, 0, 17, 16, 0, 41, 1, 1,147,244, 1, 53, 1, 31,
+254,225,254,203,244, 72, 1, 0,240,241,255, 72, 78,159,147,147,159,254,232, 1,159, 1,178, 1,150,254,104,254, 80,254, 97, 1,
+ 89,179, 1, 24, 1, 46, 1, 44, 1, 23,178,194,207,208,195, 2,158,253,232,129,140,138,129, 1,222,254,151,254,128,254,126,254,
+150, 0, 0, 0, 0, 5, 0,121,255,255, 9,125, 5,213, 0, 17, 0, 26, 0, 40, 0, 49, 0, 67, 0, 0, 1, 51, 32, 0, 17, 16,
+ 0, 33, 35, 53, 51, 32, 54, 53, 52, 38, 33, 35, 25, 1, 51, 50, 22, 21, 20, 6, 35, 19, 32, 0, 17, 16, 0, 41, 1, 32, 0, 17,
+ 16, 0, 33, 19, 35, 34, 38, 53, 52, 54, 59, 1, 53, 35, 32, 6, 21, 20, 22, 33, 51, 21, 35, 32, 0, 17, 16, 0, 33, 51, 5, 96,
+244, 1, 53, 1, 31,254,225,254,203,244, 72, 0,255,241,240,255, 0, 72, 78,159,147,147,159,135, 1,176, 1,152,254,106,254, 78,
+253,140,254, 78,254,106, 1,152, 1,176,213, 78,159,147,147,159, 78, 72,255, 0,240,241, 0,255, 72,244,254,203,254,225, 1, 31,
+ 1, 53,244, 5, 47,254,233,254,212,254,210,254,232,179,195,208,207,194,253, 98, 2, 24,129,138,140,129,254, 33, 1,106, 1,130,
+ 1,128, 1,105,254,151,254,128,254,126,254,150, 1,223,129,140,138,129,134,194,207,208,195,179, 1, 24, 1, 46, 1, 44, 1, 23,
+255,255, 0,115,255,227, 5, 39, 5,240, 16, 6, 1, 72, 0, 0, 0, 1, 0,100, 0,204, 6, 63, 4, 56, 0, 9, 0,129,180, 2,
+ 9, 6, 0, 10, 16,212,212,204, 50, 64, 9, 64, 2, 64, 9, 48, 2, 48, 9, 4, 93, 49, 64, 10, 2, 5, 9, 1, 0, 6, 5,156,
+ 6, 10, 0, 16,212,236, 17, 57, 57,204, 16,204, 48, 64, 12, 8, 9, 9, 0, 8, 7, 8, 7,156, 0, 9, 0, 7, 5, 16,252, 60,
+ 8, 6, 16, 60, 64, 12, 3, 2, 2, 1, 3, 4, 3, 4,156, 1, 2, 1, 7, 5, 16,252, 60, 8, 6, 16, 60,176, 16, 75, 83, 88,
+ 0,179, 3, 2, 8, 9, 16, 60, 16, 60,180, 8,156, 9, 9, 0, 7, 5, 16,236,180, 3,156, 2, 2, 1, 7, 5, 16,236, 89, 19,
+ 53, 1, 23, 7, 33, 21, 33, 23, 7,100, 1,137,120,233, 4,195,251, 61,233,120, 2, 85, 90, 1,137,120,233,170,233,120, 0, 0,
+ 0, 1, 1,163, 0, 0, 5, 15, 5,220, 0, 9, 0,129, 64, 10, 2, 5, 9, 1, 0, 6, 5,156, 6, 10, 16,212,236, 17, 57, 57,
+204, 16,204, 49, 0,180, 2, 9, 6, 0, 10, 16,212,212,204, 50, 64, 9, 79, 2, 79, 9, 63, 2, 63, 9, 4, 93, 48, 64, 12, 8,
+ 9, 9, 0, 8, 7, 8, 7,156, 0, 9, 0, 7, 4, 16,252, 60, 8, 6, 16, 60, 64, 12, 3, 2, 2, 1, 3, 4, 3, 4,156, 1,
+ 2, 1, 7, 4, 16,252, 60, 8, 6, 16, 60,176, 16, 75, 83, 88, 1,179, 3, 2, 8, 9, 16, 60, 16, 60,180, 8,156, 9, 9, 0,
+ 7, 4, 16,236,180, 3,156, 2, 2, 1, 7, 4, 16,236, 89, 1, 51, 1, 7, 39, 17, 35, 17, 7, 39, 3, 45, 90, 1,136,120,232,
+170,234,120, 5,220,254,118,120,234,251, 60, 4,196,234,120, 0, 0, 1, 0,117, 0,204, 6, 80, 4, 56, 0, 9, 0,129,180, 2,
+ 9, 0, 6, 10, 16,212,212,204, 50, 64, 9, 79, 2, 79, 9, 95, 2, 95, 9, 4, 93, 49, 64, 10, 9, 6, 2, 1, 0, 5, 6,156,
+ 5, 10, 0, 16,212,236, 17, 57, 57,204, 16,204, 48, 64, 12, 8, 9, 9, 0, 8, 7, 8, 7,156, 0, 9, 0, 7, 5, 16,252, 60,
+ 8, 6, 16, 60, 64, 12, 3, 2, 2, 1, 3, 4, 3, 4,156, 1, 2, 1, 7, 5, 16,252, 60, 8, 6, 16, 60,176, 16, 75, 83, 88,
+ 0,179, 3, 2, 8, 9, 16, 60, 16, 60,180, 8,156, 9, 9, 0, 7, 5, 16,236,180, 3,156, 2, 2, 1, 7, 5, 16,236, 89, 1,
+ 21, 1, 39, 55, 33, 53, 33, 39, 55, 6, 80,254,119,120,233,251, 61, 4,195,233,120, 2,175, 90,254,119,120,233,170,233,120, 0,
+ 0, 1, 1,163,255,249, 5, 15, 5,213, 0, 9, 0,129, 64, 10, 9, 6, 2, 1, 0, 5, 6,156, 5, 10, 16,212,236, 17, 57, 57,
+204, 16,204, 49, 0,180, 2, 9, 0, 6, 10, 16,212,212,204, 50, 64, 9, 64, 2, 64, 9, 80, 2, 80, 9, 4, 93, 48, 64, 12, 8,
+ 9, 9, 0, 8, 7, 8, 7,156, 0, 9, 0, 7, 4, 16,252, 60, 8, 6, 16, 60, 64, 12, 3, 2, 2, 1, 3, 4, 3, 4,156, 1,
+ 2, 1, 7, 4, 16,252, 60, 8, 6, 16, 60,176, 16, 75, 83, 88, 1,179, 3, 2, 8, 9, 16, 60, 16, 60,180, 8,156, 9, 9, 0,
+ 7, 4, 16,236,180, 3,156, 2, 2, 1, 7, 4, 16,236, 89, 5, 35, 1, 55, 23, 17, 51, 17, 55, 23, 3,135, 90,254,118,120,234,
+170,232,120, 7, 1,138,120,234, 4,196,251, 60,234,120, 0, 0, 0, 1, 0,100, 0,204, 6, 80, 4, 56, 0, 15, 0,218,182, 7,
+ 10, 9, 2, 15, 0, 16, 16,212,204, 50,212,204, 50, 64, 13, 80, 2, 80, 15, 95, 10, 95, 7, 79, 10, 79, 7, 6, 93, 49, 0, 64,
+ 15, 7, 2, 4, 10, 15, 0, 1, 8, 9, 4, 13, 4,156, 13, 16, 16,212,236, 17, 23, 57,204, 50, 16,204, 50, 48, 64, 12, 14, 15,
+ 15, 0, 14, 13, 14, 13,156, 0, 15, 0, 7, 5, 16,252, 60, 8, 6, 16, 60, 64, 12, 3, 2, 2, 1, 3, 4, 3, 4,156, 1, 2,
+ 1, 7, 5, 16,252, 60, 8, 6, 16, 60, 64, 12, 11, 10, 10, 9, 11, 12, 11, 12,156, 9, 9, 10, 7, 5, 16,252, 60, 8, 6, 16,
+ 60, 64, 12, 6, 7, 7, 8, 6, 5, 6, 5,156, 8, 7, 8, 7, 5, 16,252, 60, 8, 6, 16, 60,176, 16, 75, 83, 88, 0,183, 11,
+ 10, 6, 7, 3, 2, 14, 15, 16, 60, 16, 60, 16, 60, 16, 60,180, 14,156, 15, 15, 0, 7, 5, 16,236,180, 3,156, 2, 2, 1, 7,
+ 5, 16,236,180, 11,156, 10, 10, 9, 7, 5, 16,236,180, 6,156, 7, 7, 8, 7, 5, 16,236, 89, 19, 53, 1, 23, 7, 33, 39, 55,
+ 1, 21, 1, 39, 55, 33, 23, 7,100, 1,137,120,233, 3,188,233,120, 1,137,254,119,120,233,252, 68,233,120, 2, 85, 90, 1,137,
+120,233,233,120,254,119, 90,254,119,120,233,233,120, 0, 0, 0, 0, 1, 1,163,255,239, 5, 15, 5,220, 0, 15, 0,222, 64, 15,
+ 7, 2, 4, 10, 15, 0, 1, 8, 9, 4, 13, 4,156, 13, 16, 16,212,236, 17, 23, 57,204, 50, 16,204, 50, 49, 0,182, 7, 10, 9,
+ 2, 15, 0, 16, 16,212,204, 50,212,204, 50, 64, 17, 95, 2, 95, 15, 80, 10, 80, 7, 79, 2, 79, 15, 64, 10, 64, 7, 8, 93, 48,
+ 64, 12, 14, 15, 15, 0, 14, 13, 14, 13,156, 0, 15, 0, 7, 4, 16,252, 60, 8, 6, 16, 60, 64, 12, 3, 2, 2, 1, 3, 4, 3,
+ 4,156, 1, 2, 1, 7, 4, 16,252, 60, 8, 6, 16, 60, 64, 12, 11, 10, 10, 9, 11, 12, 11, 12,156, 9, 9, 10, 7, 4, 16,252,
+ 60, 8, 6, 16, 60, 64, 12, 6, 7, 7, 8, 6, 5, 6, 5,156, 8, 7, 8, 7, 4, 16,252, 60, 8, 6, 16, 60,176, 16, 75, 83,
+ 88, 1,183, 11, 10, 6, 7, 3, 2, 14, 15, 16, 60, 16, 60, 16, 60, 16, 60,180, 14,156, 15, 15, 0, 7, 4, 16,236,180, 3,156,
+ 2, 2, 1, 7, 4, 16,236,180, 11,156, 10, 10, 9, 7, 4, 16,236,180, 6,156, 7, 7, 8, 7, 4, 16,236, 89, 1, 51, 1, 7,
+ 39, 17, 55, 23, 1, 35, 1, 55, 23, 17, 7, 39, 3, 45, 90, 1,136,120,232,232,120,254,120, 90,254,118,120,234,234,120, 5,220,
+254,118,120,234,252, 67,234,120,254,118, 1,138,120,234, 3,189,234,120, 0, 0, 0, 1, 1, 32, 0, 52, 5,159, 4,179, 0, 9,
+ 0, 0, 1, 55, 33, 21, 33, 1, 7, 1, 17, 35, 1, 32, 63, 2, 44,254,182, 3, 94,120,252,162,169, 4,116, 63,169,252,162,120,
+ 3, 94,254,182, 0, 1, 1, 32, 0, 52, 5,159, 4,179, 0, 9, 0, 0, 1, 23, 17, 35, 17, 1, 39, 1, 33, 53, 5, 96, 63,169,
+252,162,120, 3, 94,254,182, 4,179, 63,253,212, 1, 74,252,162,120, 3, 94,169, 0, 1, 1, 32, 0, 52, 5,159, 4,179, 0, 9,
+ 0, 0, 37, 7, 33, 53, 33, 1, 55, 1, 17, 51, 5,159, 63,253,212, 1, 74,252,162,120, 3, 94,169,115, 63,169, 3, 94,120,252,
+162, 1, 74, 0, 0, 1, 1, 32, 0, 52, 5,159, 4,179, 0, 9, 0, 0, 37, 39, 17, 51, 17, 1, 23, 1, 33, 21, 1, 95, 63,169,
+ 3, 94,120,252,162, 1, 74, 52, 63, 2, 44,254,182, 3, 94,120,252,162,169, 0, 0, 1, 0,100, 0,204, 5, 63, 5, 3, 0, 11,
+ 0, 0, 1, 33, 23, 7, 1, 53, 1, 23, 7, 33, 17, 51, 5, 63,252, 61,233,120,254,119, 1,137,120,233, 3, 25,170, 2, 45,233,
+120, 1,137, 90, 1,137,120,233, 2, 44, 0, 0, 0, 1, 0,217, 2, 45, 5,219, 2,215, 0, 3, 0, 17,182, 0,156, 2, 4, 1,
+ 0, 4, 16,212,196, 49, 0, 16,212,236, 48, 19, 33, 21, 33,217, 5, 2,250,254, 2,215,170, 0, 0, 2, 0,217, 0, 0, 5,219,
+ 5, 4, 0, 11, 0, 15, 0, 0, 33, 35, 17, 33, 53, 33, 17, 51, 17, 33, 21, 33, 1, 53, 33, 21, 3,174,168,253,211, 2, 45,168,
+ 2, 45,253,211,253, 43, 5, 2, 1,131,170, 1,131,254,125,170, 2,215,170,170, 0, 2, 0,217, 0, 0, 5,219, 5,213, 0, 11,
+ 0, 15, 0, 87,186, 0, 5, 0, 6, 0, 3, 43,184, 0, 5, 16,184, 0, 0,208,184, 0, 6, 16,184, 0, 10,208,184, 0, 6, 16,
+184, 0, 12,208,184, 0, 5, 16,184, 0, 13,208, 0,184, 0, 5, 47,186, 0, 13, 0, 14, 0, 3, 43,184, 0, 13, 16,186, 0, 2,
+ 0, 3, 0, 3, 43,184, 0, 2, 16,184, 0, 3, 16,184, 0, 7,208,184, 0, 2, 16,184, 0, 9,208, 48, 49, 1, 17, 33, 21, 33,
+ 17, 35, 17, 33, 53, 33, 25, 1, 51, 21, 35, 3,174, 2, 45,253,211,168,253,211, 2, 45,168,168, 4,160,254, 5,170,254, 5, 1,
+251,170, 1,251, 1, 53,204, 0, 0, 1,254,137,255,227, 2,205, 5,240, 0, 3, 0, 43, 64, 19, 0, 15, 1, 2, 1, 2, 15, 3,
+ 0, 3, 66, 2,140, 0,145, 4, 1, 3, 4, 16,212,204, 49, 0, 16,228,228, 48, 75, 83, 88, 7, 16, 5,237, 7, 16, 5,237, 89,
+ 34, 1, 51, 1, 35, 2, 45,160,252, 92,160, 5,240,249,243, 0,255,255, 1,138,255,146, 4, 60, 6, 37, 16, 3, 0, 63, 1,138,
+ 0, 80, 0, 0,255,255, 0,190, 0,175, 4, 68, 4, 85, 16, 7, 0, 13, 0,129,254,101, 0, 0,255,255, 1, 68, 1, 71, 3,190,
+ 3,194, 16, 7, 0,114, 0,129,253,210, 0, 0, 0, 1, 0,219, 2, 72, 1,174, 3, 70, 0, 3, 0, 18,183, 2,131, 0, 4, 1,
+ 25, 0, 4, 16,212,236, 49, 0, 16,212,236, 48, 19, 51, 21, 35,219,211,211, 3, 70,254, 0, 0, 0, 1, 0, 61,255,215, 5, 25,
+ 6,125, 0, 10, 0, 42, 64, 24, 10, 9, 8, 7, 6, 5, 11, 2, 4, 2, 0, 11, 10, 9, 7, 6, 5, 4, 3, 0, 8, 1, 8, 11,
+ 16,212,204, 23, 57, 49, 0, 16,212,204,196, 17, 18, 23, 57, 48, 1, 51, 21, 35, 1, 35, 1, 7, 39, 37, 1, 4, 92,189,115,253,
+174, 66,254,193,125, 25, 1, 27, 1, 0, 6,125, 96,249,186, 3,115, 45, 80, 98,253, 59, 0, 0,255,255, 0, 61,255,215, 5, 25,
+ 7,208, 18, 34, 6, 95, 0, 0, 16, 3, 0,117, 0,115, 1,224,255,255, 0, 61,255,215, 5, 25, 7,191, 18, 34, 6, 95, 0, 0,
+ 16, 3, 5,206, 0,115, 1,224, 0, 2, 0,221, 0,221, 4,141, 3,238, 0, 11, 0, 37, 0, 0, 1, 46, 1, 35, 34, 6, 21, 20,
+ 22, 51, 50, 54, 1, 34, 38, 39, 14, 1, 35, 34, 38, 53, 52, 54, 51, 50, 22, 23, 62, 1, 51, 21, 34, 6, 7, 30, 1, 51, 3, 25,
+ 49,133, 85,102,127,118, 89, 82,134, 1,189, 73,149, 79, 70,157, 94,136,186,167,134, 95,153, 72, 68,158, 97, 43,133, 74, 49,134,
+ 67, 2,154, 88, 88,132,106,101,134,136,254,232,119,139,135,127,223,166,175,216,126,138,138,131,150,135,162, 88, 90, 0, 0, 0,
+ 0, 3, 0,221, 0,221, 5,207, 3,238, 0, 11, 0, 23, 0, 47, 0,255, 64, 29, 45, 27, 21, 9, 33, 3, 0, 36, 24, 4, 21, 15,
+ 39, 33, 21, 27, 15, 33, 48, 12, 0, 36, 24, 18, 6, 42, 18, 30, 48, 16,212,196,212,196, 17, 57, 57, 57, 57, 49, 0, 16,212,196,
+212,196, 16,192, 17, 18, 23, 57, 18, 57, 17, 18, 57, 48, 64,190, 5, 2, 5, 3, 5, 4, 0, 5, 0, 6, 0, 7, 5, 8, 5, 9,
+ 5, 10, 10, 16, 15, 17, 15, 18, 15, 19, 10, 20, 21, 2, 21, 3, 21, 4, 16, 5, 16, 6, 16, 7, 21, 8, 21, 9, 21, 10, 26, 14,
+ 26, 15, 26, 16, 31, 17, 31, 18, 31, 19, 26, 20, 26, 21, 26, 22, 36, 2, 36, 3, 36, 4, 32, 5, 32, 6, 32, 7, 36, 8, 36, 9,
+ 36, 10, 42, 14, 42, 15, 42, 16, 47, 17, 47, 18, 47, 19, 42, 20, 42, 21, 42, 22, 53, 2, 53, 3, 53, 4, 48, 5, 48, 6, 48, 7,
+ 53, 8, 53, 9, 53, 10, 58, 14, 58, 15, 58, 16, 63, 17, 63, 18, 63, 19, 58, 20, 58, 21, 58, 22, 69, 2, 69, 3, 69, 4, 64, 5,
+ 64, 6, 64, 7, 69, 8, 69, 9, 69, 10, 74, 14, 74, 15, 74, 16, 79, 17, 79, 18, 79, 19, 74, 20, 74, 21, 74, 22, 86,180, 31,176,
+ 32,176, 33,176, 34,176, 38,176, 39,176, 40,180, 41, 8, 93, 1, 93, 1, 30, 1, 51, 50, 54, 53, 52, 38, 35, 34, 6, 7, 46, 1,
+ 35, 34, 6, 21, 20, 22, 51, 50, 54, 23, 14, 1, 35, 34, 38, 53, 52, 54, 51, 50, 22, 23, 62, 1, 51, 50, 22, 21, 20, 6, 35, 34,
+ 38, 3,147, 49,134, 84,101,128,118, 89, 82,133,196, 49,133, 85,102,127,118, 89, 82,134,144, 70,157, 94,136,186,167,134, 95,153,
+ 72, 68,158, 97,134,188,167,134, 94,149, 2, 47, 88, 90,135,105,101,134,135, 55, 88, 88,132,106,101,134,136, 22,135,127,223,166,
+175,216,126,138,138,131,225,167,175,214,119, 0, 0, 6, 0,247, 0, 1, 7, 9, 6, 19, 0, 3, 0, 49, 0, 59, 0, 70, 0, 79,
+ 0, 89, 0, 0, 1, 33, 17, 33, 17, 21, 20, 6, 32, 38, 53, 52, 54, 59, 1, 17, 35, 34, 38, 53, 52, 54, 32, 22, 29, 1, 33, 53,
+ 52, 54, 51, 50, 22, 21, 20, 6, 43, 1, 17, 51, 50, 22, 21, 20, 6, 35, 34, 38, 61, 1, 1, 53, 52, 38, 35, 34, 6, 20, 22, 51,
+ 19, 35, 34, 6, 21, 20, 22, 51, 50, 54, 53, 1, 51, 50, 54, 52, 38, 34, 6, 21, 17, 21, 20, 22, 50, 54, 53, 52, 38, 35, 3,108,
+ 1, 40,254,216,185,254,252,184,184,127,170,170,127,184,184, 1, 4,185, 1, 40,185,130,131,183,183,128,170,170,128,183,183,131,
+130,185,254, 68, 98, 69, 68, 98, 98, 69,166,166, 69, 98, 98, 69, 68, 98, 2, 80,167, 68, 98, 97,138, 98, 98,138, 97, 98, 68, 2,
+118, 1, 40,254, 68,170,128,183,184,131,128,186, 1, 40,186,129,130,184,183,128,170,170,128,183,184,130,129,186,254,216,186,128,
+131,184,183,128,170, 2, 80,167, 69, 97, 97,138, 98,253,176, 98, 68, 69, 98, 98, 68, 2,247, 98,138, 97, 97, 69,253, 9,167, 68,
+ 98, 98, 69, 68, 98, 0, 0, 0, 0, 1, 0,217, 1, 31, 5,219, 3, 94, 0, 5, 0, 0, 1, 33, 17, 51, 17, 33, 5,219,250,254,
+168, 4, 90, 1, 31, 2, 63,254,107, 0, 0, 0, 0, 2, 0,172, 0, 0, 7, 84, 5,200, 0, 7, 0, 11, 0, 0, 19, 33, 1, 33,
+ 21, 33, 1, 33, 37, 33, 21, 33,172, 2, 66, 2,154, 1,204,253,188,253,102,254, 54, 3,244, 2,180,253, 76, 5,200,250,204,148,
+ 5, 52,148,148, 0, 1, 0,183,254,242, 2,123, 6, 18, 0, 5, 0, 0, 19, 1, 51, 9, 1, 35,183, 1, 26,170,254,230, 1, 26,
+170, 2,130,252,112, 3,144, 3,144, 0, 0, 0, 0, 1, 0,164,254,242, 2,104, 6, 18, 0, 5, 0, 0, 9, 1, 35, 9, 1, 51,
+ 2,104,254,230,170, 1, 26,254,230,170, 2,130,252,112, 3,144, 3,144, 0, 0, 0, 3, 0,152,255,236, 6,148, 5,232, 0, 13,
+ 0, 27, 0, 38, 0,219,186, 0, 14, 0, 6, 0, 3, 43,184, 0, 14, 16,186, 0, 35, 0, 29, 0, 3, 43,184, 0, 35, 16,186, 0,
+ 0, 0, 20, 0, 3, 43,184, 0, 0, 16, 65, 27, 0, 22, 0, 14, 0, 38, 0, 14, 0, 54, 0, 14, 0, 70, 0, 14, 0, 86, 0, 14,
+ 0,102, 0, 14, 0,118, 0, 14, 0,134, 0, 14, 0,150, 0, 14, 0,166, 0, 14, 0,182, 0, 14, 0,198, 0, 14, 0,214, 0, 14,
+ 0, 13, 93, 65, 5, 0,229, 0, 14, 0,245, 0, 14, 0, 2, 93, 65, 5, 0,234, 0, 20, 0,250, 0, 20, 0, 2, 93, 65, 27, 0,
+ 25, 0, 20, 0, 41, 0, 20, 0, 57, 0, 20, 0, 73, 0, 20, 0, 89, 0, 20, 0,105, 0, 20, 0,121, 0, 20, 0,137, 0, 20, 0,
+153, 0, 20, 0,169, 0, 20, 0,185, 0, 20, 0,201, 0, 20, 0,217, 0, 20, 0, 13, 93, 0,186, 0, 17, 0, 3, 0, 3, 43,184,
+ 0, 17, 16,186, 0, 10, 0, 24, 0, 3, 43,184, 0, 10, 16,186, 0, 36, 0, 37, 0, 3, 43,184, 0, 36, 16,184, 0, 28,208, 48,
+ 49, 1, 16, 0, 33, 32, 0, 17, 52, 18, 36, 51, 50, 4, 18, 5, 16, 0, 33, 32, 0, 17, 52, 2, 36, 35, 34, 4, 2, 1, 51, 17,
+ 7, 53, 37, 51, 17, 51, 21, 33, 6,148,254, 63,254,194,254,196,254, 63,206, 1,113,190,193, 1,113,205,250, 87, 1,143, 1, 28,
+ 1, 28, 1,143,182,254,184,173,173,254,184,182, 1,124,217,236, 1, 1,161,218,253,151, 2,234,254,193,254, 65, 1,191, 1, 63,
+198, 1,114,198,198,254,144,200,254,228,254,112, 1,144, 1, 28,179, 1, 71,177,177,254,185,253,255, 2,126, 43,152, 47,252,230,
+142, 0, 0, 0, 0, 3, 0,152,255,236, 6,148, 5,232, 0, 13, 0, 27, 0, 56, 1, 63,186, 0, 14, 0, 6, 0, 3, 43,184, 0,
+ 14, 16,186, 0, 51, 0, 38, 0, 3, 43,184, 0, 51, 16,186, 0, 0, 0, 20, 0, 3, 43,184, 0, 0, 16, 65, 27, 0, 22, 0, 14,
+ 0, 38, 0, 14, 0, 54, 0, 14, 0, 70, 0, 14, 0, 86, 0, 14, 0,102, 0, 14, 0,118, 0, 14, 0,134, 0, 14, 0,150, 0, 14,
+ 0,166, 0, 14, 0,182, 0, 14, 0,198, 0, 14, 0,214, 0, 14, 0, 13, 93, 65, 5, 0,229, 0, 14, 0,245, 0, 14, 0, 2, 93,
+ 65, 5, 0,234, 0, 20, 0,250, 0, 20, 0, 2, 93, 65, 27, 0, 25, 0, 20, 0, 41, 0, 20, 0, 57, 0, 20, 0, 73, 0, 20, 0,
+ 89, 0, 20, 0,105, 0, 20, 0,121, 0, 20, 0,137, 0, 20, 0,153, 0, 20, 0,169, 0, 20, 0,185, 0, 20, 0,201, 0, 20, 0,
+217, 0, 20, 0, 13, 93,184, 0, 51, 16,184, 0, 29,208,184, 0, 29, 47, 65, 5, 0,234, 0, 38, 0,250, 0, 38, 0, 2, 93, 65,
+ 27, 0, 25, 0, 38, 0, 41, 0, 38, 0, 57, 0, 38, 0, 73, 0, 38, 0, 89, 0, 38, 0,105, 0, 38, 0,121, 0, 38, 0,137, 0,
+ 38, 0,153, 0, 38, 0,169, 0, 38, 0,185, 0, 38, 0,201, 0, 38, 0,217, 0, 38, 0, 13, 93,186, 0, 44, 0, 6, 0, 0, 17,
+ 18, 57, 0,186, 0, 17, 0, 3, 0, 3, 43,184, 0, 17, 16,186, 0, 10, 0, 24, 0, 3, 43,184, 0, 10, 16,186, 0, 29, 0, 30,
+ 0, 3, 43,184, 0, 29, 16,186, 0, 48, 0, 41, 0, 3, 43,184, 0, 48, 16, 48, 49, 1, 16, 0, 33, 32, 0, 17, 52, 18, 36, 51,
+ 50, 4, 18, 5, 16, 0, 33, 32, 0, 17, 52, 2, 36, 35, 34, 4, 2, 1, 33, 21, 33, 53, 54, 36, 55, 62, 1, 53, 52, 38, 35, 34,
+ 6, 7, 53, 62, 1, 51, 50, 22, 21, 20, 6, 7, 14, 1, 6,148,254, 63,254,194,254,196,254, 63,206, 1,113,190,193, 1,113,205,
+250, 87, 1,143, 1, 28, 1, 28, 1,143,182,254,184,173,173,254,184,182, 2, 79, 1,180,253, 92, 82, 1, 6, 33, 62, 47, 95, 78,
+ 59,132,115, 97,145, 61,163,197, 48, 62, 17,178, 2,234,254,193,254, 65, 1,191, 1, 63,198, 1,114,198,198,254,144,200,254,228,
+254,112, 1,144, 1, 28,179, 1, 71,177,177,254,185,253,255,142,129, 77,241, 34, 63, 85, 40, 63, 78, 38, 58,171, 36, 31,151,125,
+ 58,105, 70, 18,167, 0, 0, 0, 0, 3, 0,152,255,236, 6,148, 5,232, 0, 13, 0, 27, 0, 68, 1,181,186, 0, 14, 0, 6, 0,
+ 3, 43,184, 0, 14, 16,186, 0, 66, 0, 53, 0, 3, 43,184, 0, 66, 16,186, 0, 0, 0, 20, 0, 3, 43,184, 0, 0, 16, 65, 27,
+ 0, 22, 0, 14, 0, 38, 0, 14, 0, 54, 0, 14, 0, 70, 0, 14, 0, 86, 0, 14, 0,102, 0, 14, 0,118, 0, 14, 0,134, 0, 14,
+ 0,150, 0, 14, 0,166, 0, 14, 0,182, 0, 14, 0,198, 0, 14, 0,214, 0, 14, 0, 13, 93, 65, 5, 0,229, 0, 14, 0,245, 0,
+ 14, 0, 2, 93, 65, 5, 0,234, 0, 20, 0,250, 0, 20, 0, 2, 93, 65, 27, 0, 25, 0, 20, 0, 41, 0, 20, 0, 57, 0, 20, 0,
+ 73, 0, 20, 0, 89, 0, 20, 0,105, 0, 20, 0,121, 0, 20, 0,137, 0, 20, 0,153, 0, 20, 0,169, 0, 20, 0,185, 0, 20, 0,
+201, 0, 20, 0,217, 0, 20, 0, 13, 93, 65, 5, 0,234, 0, 53, 0,250, 0, 53, 0, 2, 93, 65, 27, 0, 25, 0, 53, 0, 41, 0,
+ 53, 0, 57, 0, 53, 0, 73, 0, 53, 0, 89, 0, 53, 0,105, 0, 53, 0,121, 0, 53, 0,137, 0, 53, 0,153, 0, 53, 0,169, 0,
+ 53, 0,185, 0, 53, 0,201, 0, 53, 0,217, 0, 53, 0, 13, 93,186, 0, 28, 0, 53, 0, 66, 17, 18, 57,186, 0, 44, 0, 53, 0,
+ 66, 17, 18, 57,184, 0, 44, 47, 65, 5, 0,234, 0, 44, 0,250, 0, 44, 0, 2, 93, 65, 27, 0, 25, 0, 44, 0, 41, 0, 44, 0,
+ 57, 0, 44, 0, 73, 0, 44, 0, 89, 0, 44, 0,105, 0, 44, 0,121, 0, 44, 0,137, 0, 44, 0,153, 0, 44, 0,169, 0, 44, 0,
+185, 0, 44, 0,201, 0, 44, 0,217, 0, 44, 0, 13, 93,184, 0, 31,220,186, 0, 38, 0, 6, 0, 0, 17, 18, 57,186, 0, 59, 0,
+ 6, 0, 0, 17, 18, 57, 0,186, 0, 17, 0, 3, 0, 3, 43,184, 0, 17, 16,186, 0, 10, 0, 24, 0, 3, 43,184, 0, 10, 16,186,
+ 0, 41, 0, 34, 0, 3, 43,184, 0, 41, 16,186, 0, 63, 0, 56, 0, 3, 43,184, 0, 63, 16,186, 0, 50, 0, 47, 0, 3, 43,184,
+ 0, 50, 16,186, 0, 28, 0, 47, 0, 50, 17, 18, 57, 48, 49, 1, 16, 0, 33, 32, 0, 17, 52, 18, 36, 51, 50, 4, 18, 5, 16, 0,
+ 33, 32, 0, 17, 52, 2, 36, 35, 34, 4, 2, 5, 30, 1, 21, 20, 6, 35, 34, 38, 39, 53, 30, 1, 51, 50, 54, 53, 52, 38, 43, 1,
+ 53, 51, 50, 54, 53, 52, 38, 35, 34, 6, 7, 53, 62, 1, 51, 50, 22, 21, 20, 6, 6,148,254, 63,254,194,254,196,254, 63,206, 1,
+113,190,193, 1,113,205,250, 87, 1,143, 1, 28, 1, 28, 1,143,182,254,184,173,173,254,184,182, 3,185, 13,118,216,195, 64,136,
+ 88, 91,125, 68,117,115,107, 99,140,145, 90, 88, 92, 91, 52,121,107, 95,136, 61,161,193,104, 2,234,254,193,254, 65, 1,191, 1,
+ 63,198, 1,114,198,198,254,144,200,254,228,254,112, 1,144, 1, 28,179, 1, 71,177,177,254,185,150, 3,129, 93,141,156, 23, 27,
+168, 48, 28, 79, 76, 71, 78,140, 60, 58, 60, 63, 21, 32,151, 24, 20,137,115, 81,114, 0, 0, 0, 0, 4, 0,152,255,236, 6,148,
+ 5,232, 0, 13, 0, 27, 0, 30, 0, 41, 0,243,186, 0, 14, 0, 6, 0, 3, 43,184, 0, 14, 16,186, 0, 32, 0, 28, 0, 3, 43,
+184, 0, 32, 16,186, 0, 0, 0, 20, 0, 3, 43,184, 0, 0, 16, 65, 27, 0, 22, 0, 14, 0, 38, 0, 14, 0, 54, 0, 14, 0, 70,
+ 0, 14, 0, 86, 0, 14, 0,102, 0, 14, 0,118, 0, 14, 0,134, 0, 14, 0,150, 0, 14, 0,166, 0, 14, 0,182, 0, 14, 0,198,
+ 0, 14, 0,214, 0, 14, 0, 13, 93, 65, 5, 0,229, 0, 14, 0,245, 0, 14, 0, 2, 93, 65, 5, 0,234, 0, 20, 0,250, 0, 20,
+ 0, 2, 93, 65, 27, 0, 25, 0, 20, 0, 41, 0, 20, 0, 57, 0, 20, 0, 73, 0, 20, 0, 89, 0, 20, 0,105, 0, 20, 0,121, 0,
+ 20, 0,137, 0, 20, 0,153, 0, 20, 0,169, 0, 20, 0,185, 0, 20, 0,201, 0, 20, 0,217, 0, 20, 0, 13, 93,184, 0, 32, 16,
+184, 0, 36,208,184, 0, 28, 16,184, 0, 38,208, 0,186, 0, 17, 0, 3, 0, 3, 43,184, 0, 17, 16,186, 0, 10, 0, 24, 0, 3,
+ 43,184, 0, 10, 16,186, 0, 34, 0, 35, 0, 3, 43,184, 0, 34, 16,184, 0, 29,208,184, 0, 35, 16,184, 0, 39,208, 48, 49, 1,
+ 16, 0, 33, 32, 0, 17, 52, 18, 36, 51, 50, 4, 18, 5, 16, 0, 33, 32, 0, 17, 52, 2, 36, 35, 34, 4, 2, 37, 1, 33, 3, 51,
+ 17, 51, 21, 35, 21, 35, 53, 33, 53, 6,148,254, 63,254,194,254,196,254, 63,206, 1,113,190,193, 1,113,205,250, 87, 1,143, 1,
+ 28, 1, 28, 1,143,182,254,184,173,173,254,184,182, 2,191,254,243, 1, 13, 24,206,141,141,182,254, 67, 2,234,254,193,254, 65,
+ 1,191, 1, 63,198, 1,114,198,198,254,144,200,254,228,254,112, 1,144, 1, 28,179, 1, 71,177,177,254,185, 79,254,130, 2, 72,
+253,184,141,211,211,142, 0, 0, 0, 3, 0,152,255,236, 6,148, 5,232, 0, 13, 0, 27, 0, 57, 1, 75,186, 0, 14, 0, 6, 0,
+ 3, 43,184, 0, 14, 16,186, 0, 31, 0, 28, 0, 3, 43,184, 0, 31, 16,186, 0, 38, 0, 51, 0, 3, 43,184, 0, 38, 16,186, 0,
+ 0, 0, 20, 0, 3, 43,184, 0, 0, 16, 65, 27, 0, 22, 0, 14, 0, 38, 0, 14, 0, 54, 0, 14, 0, 70, 0, 14, 0, 86, 0, 14,
+ 0,102, 0, 14, 0,118, 0, 14, 0,134, 0, 14, 0,150, 0, 14, 0,166, 0, 14, 0,182, 0, 14, 0,198, 0, 14, 0,214, 0, 14,
+ 0, 13, 93, 65, 5, 0,229, 0, 14, 0,245, 0, 14, 0, 2, 93, 65, 5, 0,234, 0, 20, 0,250, 0, 20, 0, 2, 93, 65, 27, 0,
+ 25, 0, 20, 0, 41, 0, 20, 0, 57, 0, 20, 0, 73, 0, 20, 0, 89, 0, 20, 0,105, 0, 20, 0,121, 0, 20, 0,137, 0, 20, 0,
+153, 0, 20, 0,169, 0, 20, 0,185, 0, 20, 0,201, 0, 20, 0,217, 0, 20, 0, 13, 93,186, 0, 45, 0, 6, 0, 0, 17, 18, 57,
+ 65, 5, 0,234, 0, 51, 0,250, 0, 51, 0, 2, 93, 65, 27, 0, 25, 0, 51, 0, 41, 0, 51, 0, 57, 0, 51, 0, 73, 0, 51, 0,
+ 89, 0, 51, 0,105, 0, 51, 0,121, 0, 51, 0,137, 0, 51, 0,153, 0, 51, 0,169, 0, 51, 0,185, 0, 51, 0,201, 0, 51, 0,
+217, 0, 51, 0, 13, 93, 0,186, 0, 17, 0, 3, 0, 3, 43,184, 0, 17, 16,186, 0, 10, 0, 24, 0, 3, 43,184, 0, 10, 16,186,
+ 0, 48, 0, 41, 0, 3, 43,184, 0, 48, 16,186, 0, 29, 0, 30, 0, 3, 43,184, 0, 29, 16,186, 0, 35, 0, 54, 0, 3, 43,184,
+ 0, 35, 16, 48, 49, 1, 16, 0, 33, 32, 0, 17, 52, 18, 36, 51, 50, 4, 18, 5, 16, 0, 33, 32, 0, 17, 52, 2, 36, 35, 34, 4,
+ 2, 1, 33, 21, 33, 21, 6, 54, 51, 50, 22, 21, 20, 6, 35, 34, 38, 39, 53, 30, 1, 51, 50, 54, 53, 52, 38, 35, 34, 6, 7, 6,
+148,254, 63,254,194,254,196,254, 63,206, 1,113,190,193, 1,113,205,250, 87, 1,143, 1, 28, 1, 28, 1,143,182,254,184,173,173,
+254,184,182, 1,152, 2, 61,254,111, 3, 63, 31,176,207,213,190, 64,133, 88, 95,119, 68,104,118,118,104, 50,101, 89, 2,234,254,
+193,254, 65, 1,191, 1, 63,198, 1,114,198,198,254,144,200,254,228,254,112, 1,144, 1, 28,179, 1, 71,177,177,254,185, 1, 25,
+142,171, 1, 10,176,149,152,172, 20, 24,172, 47, 27, 97, 85, 86, 97, 20, 37, 0, 0, 4, 0,152,255,236, 6,148, 5,232, 0, 13,
+ 0, 27, 0, 39, 0, 64, 1,145,186, 0, 14, 0, 6, 0, 3, 43,184, 0, 14, 16,186, 0, 31, 0, 59, 0, 3, 43,184, 0, 31, 16,
+186, 0, 53, 0, 37, 0, 3, 43,184, 0, 53, 16,186, 0, 0, 0, 20, 0, 3, 43,184, 0, 0, 16, 65, 27, 0, 22, 0, 14, 0, 38,
+ 0, 14, 0, 54, 0, 14, 0, 70, 0, 14, 0, 86, 0, 14, 0,102, 0, 14, 0,118, 0, 14, 0,134, 0, 14, 0,150, 0, 14, 0,166,
+ 0, 14, 0,182, 0, 14, 0,198, 0, 14, 0,214, 0, 14, 0, 13, 93, 65, 5, 0,229, 0, 14, 0,245, 0, 14, 0, 2, 93, 65, 5,
+ 0,234, 0, 20, 0,250, 0, 20, 0, 2, 93, 65, 27, 0, 25, 0, 20, 0, 41, 0, 20, 0, 57, 0, 20, 0, 73, 0, 20, 0, 89, 0,
+ 20, 0,105, 0, 20, 0,121, 0, 20, 0,137, 0, 20, 0,153, 0, 20, 0,169, 0, 20, 0,185, 0, 20, 0,201, 0, 20, 0,217, 0,
+ 20, 0, 13, 93, 65, 27, 0, 22, 0, 31, 0, 38, 0, 31, 0, 54, 0, 31, 0, 70, 0, 31, 0, 86, 0, 31, 0,102, 0, 31, 0,118,
+ 0, 31, 0,134, 0, 31, 0,150, 0, 31, 0,166, 0, 31, 0,182, 0, 31, 0,198, 0, 31, 0,214, 0, 31, 0, 13, 93, 65, 5, 0,
+229, 0, 31, 0,245, 0, 31, 0, 2, 93, 65, 5, 0,234, 0, 37, 0,250, 0, 37, 0, 2, 93, 65, 27, 0, 25, 0, 37, 0, 41, 0,
+ 37, 0, 57, 0, 37, 0, 73, 0, 37, 0, 89, 0, 37, 0,105, 0, 37, 0,121, 0, 37, 0,137, 0, 37, 0,153, 0, 37, 0,169, 0,
+ 37, 0,185, 0, 37, 0,201, 0, 37, 0,217, 0, 37, 0, 13, 93,186, 0, 41, 0, 37, 0, 53, 17, 18, 57, 0,186, 0, 17, 0, 3,
+ 0, 3, 43,184, 0, 17, 16,186, 0, 10, 0, 24, 0, 3, 43,184, 0, 10, 16,186, 0, 34, 0, 56, 0, 3, 43,184, 0, 34, 16,186,
+ 0, 62, 0, 44, 0, 3, 43,184, 0, 62, 16,186, 0, 50, 0, 28, 0, 3, 43,184, 0, 50, 16, 48, 49, 1, 16, 0, 33, 32, 0, 17,
+ 52, 18, 36, 51, 50, 4, 18, 5, 16, 0, 33, 32, 0, 17, 52, 2, 36, 35, 34, 4, 2, 5, 34, 6, 21, 20, 22, 51, 50, 54, 53, 52,
+ 38, 19, 21, 46, 1, 35, 34, 6, 7, 6, 54, 51, 50, 22, 21, 20, 6, 35, 34, 38, 53, 52, 18, 51, 50, 22, 6,148,254, 63,254,194,
+254,196,254, 63,206, 1,113,190,193, 1,113,205,250, 87, 1,143, 1, 28, 1, 28, 1,143,182,254,184,173,173,254,184,182, 2,161,
+ 78, 92, 92, 78, 78, 92, 92,212, 84, 97, 47,119,127, 5, 9,128, 78,160,186,194,160,185,192,234,200, 53,106, 2,234,254,193,254,
+ 65, 1,191, 1, 63,198, 1,114,198,198,254,144,200,254,228,254,112, 1,144, 1, 28,179, 1, 71,177,177,254,185,159, 98, 91, 90,
+ 98, 98, 90, 91, 98, 1,157,156, 35, 22,148, 80, 11, 61,177,148,145,179,253,231,218, 1, 11, 19, 0, 3, 0,152,255,236, 6,148,
+ 5,232, 0, 13, 0, 27, 0, 34, 0,235,184, 0, 35, 47,184, 0, 36, 47,184, 0, 0,220,184, 0, 35, 16,184, 0, 6,208,184, 0,
+ 6, 47,184, 0, 14,220, 65, 27, 0, 22, 0, 14, 0, 38, 0, 14, 0, 54, 0, 14, 0, 70, 0, 14, 0, 86, 0, 14, 0,102, 0, 14,
+ 0,118, 0, 14, 0,134, 0, 14, 0,150, 0, 14, 0,166, 0, 14, 0,182, 0, 14, 0,198, 0, 14, 0,214, 0, 14, 0, 13, 93, 65,
+ 5, 0,229, 0, 14, 0,245, 0, 14, 0, 2, 93,184, 0, 0, 16,184, 0, 20,220, 65, 5, 0,234, 0, 20, 0,250, 0, 20, 0, 2,
+ 93, 65, 27, 0, 25, 0, 20, 0, 41, 0, 20, 0, 57, 0, 20, 0, 73, 0, 20, 0, 89, 0, 20, 0,105, 0, 20, 0,121, 0, 20, 0,
+137, 0, 20, 0,153, 0, 20, 0,169, 0, 20, 0,185, 0, 20, 0,201, 0, 20, 0,217, 0, 20, 0, 13, 93,186, 0, 32, 0, 6, 0,
+ 0, 17, 18, 57,186, 0, 33, 0, 6, 0, 0, 17, 18, 57, 0,186, 0, 17, 0, 3, 0, 3, 43,184, 0, 17, 16,186, 0, 10, 0, 24,
+ 0, 3, 43,184, 0, 10, 16,186, 0, 29, 0, 33, 0, 3, 43,184, 0, 29, 16, 48, 49, 1, 16, 0, 33, 32, 0, 17, 52, 18, 36, 51,
+ 50, 4, 18, 5, 16, 0, 33, 32, 0, 17, 52, 2, 36, 35, 34, 4, 2, 1, 33, 21, 1, 35, 1, 33, 6,148,254, 63,254,194,254,196,
+254, 63,206, 1,113,190,193, 1,113,205,250, 87, 1,143, 1, 28, 1, 28, 1,143,182,254,184,173,173,254,184,182, 1,107, 2,171,
+254,148,193, 1, 81,254, 49, 2,234,254,193,254, 65, 1,191, 1, 63,198, 1,114,198,198,254,144,200,254,228,254,112, 1,144, 1,
+ 28,179, 1, 71,177,177,254,185, 1, 25, 75,252,163, 3, 26, 0, 0, 5, 0,152,255,236, 6,148, 5,232, 0, 13, 0, 27, 0, 39,
+ 0, 63, 0, 75, 2, 13,186, 0, 14, 0, 6, 0, 3, 43,184, 0, 14, 16,186, 0, 31, 0, 61, 0, 3, 43,184, 0, 31, 16,186, 0,
+ 49, 0, 70, 0, 3, 43,184, 0, 49, 16,186, 0, 0, 0, 20, 0, 3, 43,184, 0, 0, 16, 65, 27, 0, 22, 0, 14, 0, 38, 0, 14,
+ 0, 54, 0, 14, 0, 70, 0, 14, 0, 86, 0, 14, 0,102, 0, 14, 0,118, 0, 14, 0,134, 0, 14, 0,150, 0, 14, 0,166, 0, 14,
+ 0,182, 0, 14, 0,198, 0, 14, 0,214, 0, 14, 0, 13, 93, 65, 5, 0,229, 0, 14, 0,245, 0, 14, 0, 2, 93, 65, 5, 0,234,
+ 0, 20, 0,250, 0, 20, 0, 2, 93, 65, 27, 0, 25, 0, 20, 0, 41, 0, 20, 0, 57, 0, 20, 0, 73, 0, 20, 0, 89, 0, 20, 0,
+105, 0, 20, 0,121, 0, 20, 0,137, 0, 20, 0,153, 0, 20, 0,169, 0, 20, 0,185, 0, 20, 0,201, 0, 20, 0,217, 0, 20, 0,
+ 13, 93, 65, 27, 0, 22, 0, 31, 0, 38, 0, 31, 0, 54, 0, 31, 0, 70, 0, 31, 0, 86, 0, 31, 0,102, 0, 31, 0,118, 0, 31,
+ 0,134, 0, 31, 0,150, 0, 31, 0,166, 0, 31, 0,182, 0, 31, 0,198, 0, 31, 0,214, 0, 31, 0, 13, 93, 65, 5, 0,229, 0,
+ 31, 0,245, 0, 31, 0, 2, 93, 65, 5, 0,234, 0, 70, 0,250, 0, 70, 0, 2, 93, 65, 27, 0, 25, 0, 70, 0, 41, 0, 70, 0,
+ 57, 0, 70, 0, 73, 0, 70, 0, 89, 0, 70, 0,105, 0, 70, 0,121, 0, 70, 0,137, 0, 70, 0,153, 0, 70, 0,169, 0, 70, 0,
+185, 0, 70, 0,201, 0, 70, 0,217, 0, 70, 0, 13, 93,186, 0, 37, 0, 70, 0, 49, 17, 18, 57,184, 0, 37, 47, 65, 5, 0,234,
+ 0, 37, 0,250, 0, 37, 0, 2, 93, 65, 27, 0, 25, 0, 37, 0, 41, 0, 37, 0, 57, 0, 37, 0, 73, 0, 37, 0, 89, 0, 37, 0,
+105, 0, 37, 0,121, 0, 37, 0,137, 0, 37, 0,153, 0, 37, 0,169, 0, 37, 0,185, 0, 37, 0,201, 0, 37, 0,217, 0, 37, 0,
+ 13, 93,186, 0, 43, 0, 61, 0, 31, 17, 18, 57,184, 0, 43, 47,186, 0, 52, 0, 70, 0, 49, 17, 18, 57,184, 0, 37, 16,184, 0,
+ 55,220,184, 0, 43, 16,184, 0, 64,220, 0,186, 0, 17, 0, 3, 0, 3, 43,184, 0, 17, 16,186, 0, 10, 0, 24, 0, 3, 43,184,
+ 0, 10, 16,186, 0, 34, 0, 58, 0, 3, 43,184, 0, 34, 16,186, 0, 46, 0, 73, 0, 3, 43,184, 0, 46, 16,186, 0, 67, 0, 28,
+ 0, 3, 43,184, 0, 67, 16,186, 0, 52, 0, 28, 0, 67, 17, 18, 57, 48, 49, 1, 16, 0, 33, 32, 0, 17, 52, 18, 36, 51, 50, 4,
+ 18, 5, 16, 0, 33, 32, 0, 17, 52, 2, 36, 35, 34, 4, 2, 5, 34, 6, 21, 20, 22, 51, 50, 54, 53, 52, 38, 37, 46, 1, 53, 52,
+ 54, 51, 50, 22, 21, 20, 6, 7, 30, 1, 21, 20, 6, 35, 34, 38, 53, 52, 54, 55, 20, 22, 51, 50, 54, 53, 52, 38, 35, 34, 6, 6,
+148,254, 63,254,194,254,196,254, 63,206, 1,113,190,193, 1,113,205,250, 87, 1,143, 1, 28, 1, 28, 1,143,182,254,184,173,173,
+254,184,182, 2,175, 84, 95, 95, 84, 84, 95, 95,254,198, 4,106,183,157,157,182,105, 4, 15,118,190,173,173,190,118, 87, 81, 77,
+ 75, 82, 82, 75, 77, 81, 2,234,254,193,254, 65, 1,191, 1, 63,198, 1,114,198,198,254,144,200,254,228,254,112, 1,144, 1, 28,
+179, 1, 71,177,177,254,185,230, 80, 73, 73, 80, 81, 72, 73, 80, 73, 1,118, 83,116,136,136,116, 83,118, 1, 3,131, 92,138,151,
+151,138, 92,131,193, 61, 66, 66, 61, 62, 66, 66, 0, 4, 0,152,255,236, 6,148, 5,232, 0, 13, 0, 27, 0, 52, 0, 64, 1,145,
+186, 0, 14, 0, 6, 0, 3, 43,184, 0, 14, 16,186, 0, 62, 0, 41, 0, 3, 43,184, 0, 62, 16,186, 0, 0, 0, 20, 0, 3, 43,
+184, 0, 0, 16,186, 0, 47, 0, 56, 0, 3, 43,184, 0, 47, 16, 65, 27, 0, 22, 0, 14, 0, 38, 0, 14, 0, 54, 0, 14, 0, 70,
+ 0, 14, 0, 86, 0, 14, 0,102, 0, 14, 0,118, 0, 14, 0,134, 0, 14, 0,150, 0, 14, 0,166, 0, 14, 0,182, 0, 14, 0,198,
+ 0, 14, 0,214, 0, 14, 0, 13, 93, 65, 5, 0,229, 0, 14, 0,245, 0, 14, 0, 2, 93, 65, 5, 0,234, 0, 20, 0,250, 0, 20,
+ 0, 2, 93, 65, 27, 0, 25, 0, 20, 0, 41, 0, 20, 0, 57, 0, 20, 0, 73, 0, 20, 0, 89, 0, 20, 0,105, 0, 20, 0,121, 0,
+ 20, 0,137, 0, 20, 0,153, 0, 20, 0,169, 0, 20, 0,185, 0, 20, 0,201, 0, 20, 0,217, 0, 20, 0, 13, 93, 65, 27, 0, 22,
+ 0, 62, 0, 38, 0, 62, 0, 54, 0, 62, 0, 70, 0, 62, 0, 86, 0, 62, 0,102, 0, 62, 0,118, 0, 62, 0,134, 0, 62, 0,150,
+ 0, 62, 0,166, 0, 62, 0,182, 0, 62, 0,198, 0, 62, 0,214, 0, 62, 0, 13, 93, 65, 5, 0,229, 0, 62, 0,245, 0, 62, 0,
+ 2, 93,186, 0, 29, 0, 41, 0, 62, 17, 18, 57, 65, 5, 0,234, 0, 56, 0,250, 0, 56, 0, 2, 93, 65, 27, 0, 25, 0, 56, 0,
+ 41, 0, 56, 0, 57, 0, 56, 0, 73, 0, 56, 0, 89, 0, 56, 0,105, 0, 56, 0,121, 0, 56, 0,137, 0, 56, 0,153, 0, 56, 0,
+169, 0, 56, 0,185, 0, 56, 0,201, 0, 56, 0,217, 0, 56, 0, 13, 93, 0,186, 0, 17, 0, 3, 0, 3, 43,184, 0, 17, 16,186,
+ 0, 10, 0, 24, 0, 3, 43,184, 0, 10, 16,186, 0, 32, 0, 50, 0, 3, 43,184, 0, 32, 16,186, 0, 44, 0, 59, 0, 3, 43,184,
+ 0, 44, 16,186, 0, 53, 0, 38, 0, 3, 43,184, 0, 53, 16, 48, 49, 1, 16, 0, 33, 32, 0, 17, 52, 18, 36, 51, 50, 4, 18, 5,
+ 16, 0, 33, 32, 0, 17, 52, 2, 36, 35, 34, 4, 2, 1, 53, 30, 1, 51, 50, 54, 55, 54, 6, 35, 34, 38, 53, 52, 54, 51, 50, 22,
+ 21, 20, 2, 35, 34, 38, 19, 50, 54, 53, 52, 38, 35, 34, 6, 21, 20, 22, 6,148,254, 63,254,194,254,196,254, 63,206, 1,113,190,
+193, 1,113,205,250, 87, 1,143, 1, 28, 1, 28, 1,143,182,254,184,173,173,254,184,182, 1,144, 85, 97, 46,119,127, 5, 10,128,
+ 79,159,186,194,160,185,191,233,200, 53,107,217, 78, 91, 91, 78, 78, 92, 92, 2,234,254,193,254, 65, 1,191, 1, 63,198, 1,114,
+198,198,254,144,200,254,228,254,112, 1,144, 1, 28,179, 1, 71,177,177,254,185,253,139,156, 36, 21,147, 79, 13, 60,175,148,145,
+180,253,232,218,254,246, 19, 1,180, 98, 91, 91, 98, 98, 91, 91, 98, 0, 0, 0, 0, 5, 0,152,255,236, 6,148, 5,232, 0, 13,
+ 0, 27, 0, 38, 0, 50, 0, 62, 1,155,186, 0, 14, 0, 6, 0, 3, 43,184, 0, 14, 16,186, 0, 35, 0, 29, 0, 3, 43,184, 0,
+ 35, 16,186, 0, 42, 0, 60, 0, 3, 43,184, 0, 42, 16,186, 0, 54, 0, 48, 0, 3, 43,184, 0, 54, 16,186, 0, 0, 0, 20, 0,
+ 3, 43,184, 0, 0, 16, 65, 27, 0, 22, 0, 14, 0, 38, 0, 14, 0, 54, 0, 14, 0, 70, 0, 14, 0, 86, 0, 14, 0,102, 0, 14,
+ 0,118, 0, 14, 0,134, 0, 14, 0,150, 0, 14, 0,166, 0, 14, 0,182, 0, 14, 0,198, 0, 14, 0,214, 0, 14, 0, 13, 93, 65,
+ 5, 0,229, 0, 14, 0,245, 0, 14, 0, 2, 93, 65, 5, 0,234, 0, 20, 0,250, 0, 20, 0, 2, 93, 65, 27, 0, 25, 0, 20, 0,
+ 41, 0, 20, 0, 57, 0, 20, 0, 73, 0, 20, 0, 89, 0, 20, 0,105, 0, 20, 0,121, 0, 20, 0,137, 0, 20, 0,153, 0, 20, 0,
+169, 0, 20, 0,185, 0, 20, 0,201, 0, 20, 0,217, 0, 20, 0, 13, 93, 65, 5, 0,234, 0, 48, 0,250, 0, 48, 0, 2, 93, 65,
+ 27, 0, 25, 0, 48, 0, 41, 0, 48, 0, 57, 0, 48, 0, 73, 0, 48, 0, 89, 0, 48, 0,105, 0, 48, 0,121, 0, 48, 0,137, 0,
+ 48, 0,153, 0, 48, 0,169, 0, 48, 0,185, 0, 48, 0,201, 0, 48, 0,217, 0, 48, 0, 13, 93, 65, 5, 0,234, 0, 60, 0,250,
+ 0, 60, 0, 2, 93, 65, 27, 0, 25, 0, 60, 0, 41, 0, 60, 0, 57, 0, 60, 0, 73, 0, 60, 0, 89, 0, 60, 0,105, 0, 60, 0,
+121, 0, 60, 0,137, 0, 60, 0,153, 0, 60, 0,169, 0, 60, 0,185, 0, 60, 0,201, 0, 60, 0,217, 0, 60, 0, 13, 93, 0,186,
+ 0, 17, 0, 3, 0, 3, 43,184, 0, 17, 16,186, 0, 10, 0, 24, 0, 3, 43,184, 0, 10, 16,186, 0, 45, 0, 57, 0, 3, 43,184,
+ 0, 45, 16,186, 0, 36, 0, 37, 0, 3, 43,184, 0, 36, 16,186, 0, 51, 0, 39, 0, 3, 43,184, 0, 51, 16,184, 0, 36, 16,184,
+ 0, 28,208, 48, 49, 1, 16, 0, 33, 32, 0, 17, 52, 18, 36, 51, 50, 4, 18, 5, 16, 0, 33, 32, 0, 17, 52, 2, 36, 35, 34, 4,
+ 2, 19, 51, 17, 7, 53, 55, 51, 17, 51, 21, 33, 1, 34, 6, 21, 20, 22, 51, 50, 54, 53, 52, 38, 39, 50, 22, 21, 20, 6, 35, 34,
+ 38, 53, 52, 54, 6,148,254, 63,254,194,254,196,254, 63,206, 1,113,190,193, 1,113,205,250, 87, 1,143, 1, 28, 1, 28, 1,143,
+182,254,184,173,173,254,184,182,205,158,172,188,117,159,254, 62, 3, 4, 64, 69, 69, 64, 63, 70, 70, 63,130,136,136,130,131,136,
+136, 2,234,254,193,254, 65, 1,191, 1, 63,198, 1,114,198,198,254,144,200,254,228,254,112, 1,144, 1, 28,179, 1, 71,177,177,
+254,185,254, 62, 2, 62, 39,137, 42,253, 54,128, 2,222,151,163,162,151,151,162,163,151,123,228,209,208,228,228,208,209,228, 0,
+ 0, 1, 0,170, 1,119, 6,130, 4, 99, 0, 5, 0, 11, 0,184, 0, 2, 47,184, 0, 5, 47, 48, 49, 19, 17, 37, 5, 17, 5,170,
+ 1,119, 4, 97,251,159, 2, 50, 1,117,188,188,254,139,187, 0, 0, 1, 0,170, 0, 0, 4,116, 5,217, 0, 19, 0, 31, 0,184,
+ 0, 5, 47,186, 0, 16, 0, 18, 0, 3, 43,184, 0, 16, 16,184, 0, 18, 16,184, 0, 13,208,184, 0, 13, 47, 48, 49, 1, 22, 21,
+ 20, 7, 3, 33, 3, 38, 53, 52, 55, 54, 39, 35, 53, 33, 23, 7, 22, 3,126,246, 8,238,254, 34,237, 9,246,127, 7,117, 1,218,
+ 1,119, 1, 4,224, 66,179, 32, 36,252, 89, 3,167, 38, 34,175, 66, 26,134, 89, 89, 1,135, 0, 0, 1, 0, 47, 0, 0, 5,170,
+ 6, 20, 0, 36, 0, 72, 64, 19, 38, 0, 7, 9, 5, 8, 12, 33, 24, 13, 30, 8, 17, 12, 33, 16, 20, 76, 37, 16,252, 60,196, 50,
+196,252, 60,196, 16, 60,252, 60,196,196,196, 49, 0, 64, 17, 9, 13, 17,169, 18, 2, 26,135, 0, 24,151, 6, 31, 18,188, 11, 15,
+ 47, 60,230, 50, 50,254, 60,238, 50, 16,238, 50, 50, 48, 1, 21, 35, 34, 6, 29, 1, 33, 21, 33, 17, 35, 17, 33, 17, 35, 17, 35,
+ 53, 51, 53, 52, 54, 59, 1, 21, 35, 34, 7, 6, 29, 1, 33, 53, 52, 54, 51, 5,170,176, 99, 77, 1, 47,254,209,185,254, 7,185,
+176,176,174,189,174,176, 99, 39, 38, 1,249,174,189, 6, 20,153, 80,104, 99,143,252, 47, 3,209,252, 47, 3,209,143, 78,187,171,
+153, 40, 40,104, 99, 78,187,171, 0, 2, 0, 47, 0, 0, 4, 74, 6, 20, 0, 21, 0, 25, 0, 67, 64, 17, 27, 70, 0, 23, 8, 22,
+ 15, 20, 4, 8, 8, 3, 22, 10, 6, 76, 26, 16,252, 60,196, 50,196,252, 60,196, 16,254, 60,236, 49, 0, 64, 18, 8, 3,169, 0,
+ 16,135, 14, 24,190, 22,177, 14,151, 9, 0,188, 5, 1, 47, 60,230, 50,238,254,238, 16,238, 16,238, 50, 48, 1, 17, 35, 17, 33,
+ 17, 35, 17, 35, 53, 51, 53, 52, 54, 59, 1, 21, 35, 34, 6, 29, 1, 1, 51, 21, 35, 4, 74,185,254, 7,185,176,176,173,179,185,
+176, 99, 77, 1,249,185,185, 4, 96,251,160, 3,209,252, 47, 3,209,143, 78,183,175,153, 80,104, 99, 1,178,233, 0, 1, 0, 47,
+ 0, 0, 4, 74, 6, 20, 0, 21, 0, 55, 64, 15, 23, 70, 1, 8, 4, 10, 12, 8, 8, 16, 4, 18, 14, 76, 22, 16,252, 60,196,196,
+252, 60,196, 16,254,236, 49, 0, 64, 13, 15, 11,169, 9, 4,135, 0,151, 17, 9,188, 13, 2, 47, 60,230, 50,254,238, 16,238, 50,
+ 48, 1, 33, 17, 35, 17, 33, 34, 6, 29, 1, 33, 21, 33, 17, 35, 17, 35, 53, 51, 53, 52, 54, 2, 74, 2, 0,185,254,183, 99, 77,
+ 1, 47,254,209,185,176,176,174, 6, 20,249,236, 5,123, 80,104, 99,143,252, 47, 3,209,143, 78,187,171, 0, 0, 0, 2, 0, 47,
+ 0, 0, 6,252, 6, 20, 0, 41, 0, 45, 0, 90, 64, 24, 47, 70, 23, 43, 8, 42, 16, 27, 21, 8, 26, 42, 9, 0, 31, 6, 8, 36,
+ 30, 9, 34, 38, 76, 46, 16,252, 60,196, 50,196,252, 60,196, 16,196, 50,252, 60,196, 16,252, 60,236, 49, 0, 64, 23, 27, 31, 35,
+169, 36, 17, 1,135, 0, 45,190, 42,177, 16, 0,151, 22, 7, 36,188, 25, 29, 33, 47, 60, 60,228, 50, 50,228, 50,244,236, 16,236,
+ 50, 16,236, 50, 50, 48, 1, 21, 35, 34, 7, 6, 29, 1, 33, 53, 52, 55, 54, 55, 54, 59, 1, 21, 35, 34, 6, 29, 1, 33, 17, 35,
+ 17, 33, 17, 35, 17, 33, 17, 35, 17, 35, 53, 51, 53, 52, 54, 51, 5, 51, 21, 35, 2,248,176, 99, 39, 38, 1,249, 87, 28, 39, 78,
+131,174,176, 99, 77, 2,178,185,254, 7,185,254, 7,185,176,176,174,189, 3,249,185,185, 6, 20,153, 40, 40,104, 99, 78,187, 85,
+ 28, 19, 39,153, 80,104, 99,251,160, 3,209,252, 47, 3,209,252, 47, 3,209,143, 78,187,171, 2,233, 0, 0, 0, 0, 1, 0, 47,
+ 0, 0, 6,252, 6, 20, 0, 38, 0, 78, 64, 22, 40, 70, 13, 8, 16, 22, 24, 20, 8, 16, 9, 0, 28, 6, 8, 33, 27, 9, 31, 35,
+ 76, 39, 16,252, 60,196, 50,196,252, 60,196, 16,196,252, 60,196, 16,252,236, 49, 0, 64, 18, 24, 28, 32,169, 33, 17, 2,135, 12,
+ 38,151, 21, 7, 33,188, 15, 26, 30, 47, 60, 60,228, 50, 50,244, 60,236, 50, 16,236, 50, 50, 48, 1, 21, 35, 34, 7, 6, 29, 1,
+ 33, 53, 52, 54, 51, 33, 17, 35, 17, 33, 34, 6, 29, 1, 33, 21, 33, 17, 35, 17, 33, 17, 35, 17, 35, 53, 51, 53, 52, 54, 51, 2,
+248,176, 99, 39, 38, 1,249,174,189, 2, 0,185,254,183, 99, 77, 1, 47,254,209,185,254, 7,185,176,176,174,189, 6, 20,153, 40,
+ 40,104, 99, 78,187,171,249,236, 5,123, 80,104, 99,143,252, 47, 3,209,252, 47, 3,209,143, 78,187,171, 0, 0, 0, 1, 0, 47,
+ 0, 0, 5, 76, 6, 20, 0, 45, 0, 0, 1, 53, 52, 39, 38, 43, 1, 34, 7, 6, 21, 17, 35, 17, 35, 53, 51, 53, 52, 55, 54, 59,
+ 1, 50, 23, 22, 29, 1, 33, 21, 33, 17, 20, 23, 22, 59, 1, 21, 35, 34, 39, 38, 53, 17, 35, 53, 3, 24, 36, 37,101, 34, 99, 39,
+ 38,185,176,176, 87, 87,189, 30,189, 87, 85, 1,123,254,133, 37, 38,115,189,189,213, 81, 81,135, 4, 96, 99,104, 40, 40, 40, 40,
+104,251, 61, 3,209,143, 78,187, 85, 86, 86, 83,189, 78,143,253,160,137, 39, 39,154, 80, 79,210, 2, 96,143, 0, 0, 1, 0,111,
+255,227, 6,178, 5,240, 0, 89, 0, 0, 1, 21, 38, 39, 38, 35, 34, 7, 6, 21, 20, 23, 22, 31, 1, 30, 1, 21, 20, 7, 6, 35,
+ 34, 39, 38, 39, 53, 22, 23, 22, 51, 50, 55, 54, 53, 52, 39, 38, 47, 1, 38, 39, 38, 53, 52, 55, 54, 51, 50, 23, 38, 53, 52, 55,
+ 54, 55, 50, 23, 22, 29, 1, 33, 21, 33, 17, 20, 23, 22, 59, 1, 21, 35, 34, 39, 38, 53, 17, 35, 53, 51, 53, 52, 39, 38, 7, 34,
+ 7, 6, 21, 20, 3, 81, 86, 73, 84, 70,117, 63, 59, 49, 49,148, 63,195,166,123,124,216, 96, 92, 97,108,102, 99, 99, 97,130, 70,
+ 70, 50, 45,177, 64,171, 76, 76,102,112,181, 72, 77, 5, 92, 91,162,140, 98, 94, 1,123,254,133, 37, 38,115,189,189,213, 81, 81,
+135,135, 48, 54, 68, 69, 54, 52, 4, 63,174, 43, 17, 20, 42, 39, 87, 64, 37, 36, 33, 14, 43,152,137,156, 91, 91, 17, 18, 35,190,
+ 53, 26, 27, 45, 44, 81, 75, 40, 35, 42, 15, 36, 74, 75,130,166, 78, 86, 11, 29, 31,135, 95, 93, 1, 96, 92,136, 76,143,253,160,
+137, 39, 39,154, 80, 79,210, 2, 96,143, 78, 65, 43, 50, 1, 49, 48, 64, 61, 0, 0, 1, 0,170,255,227, 8,227, 6, 20, 0, 74,
+ 0, 0, 1, 22, 21, 17, 35, 53, 14, 1, 35, 34, 38, 53, 17, 51, 17, 20, 22, 51, 50, 54, 53, 17, 52, 39, 33, 34, 39, 38, 55, 54,
+ 55, 54, 59, 1, 21, 35, 34, 21, 20, 51, 33, 39, 38, 55, 54, 59, 1, 21, 35, 38, 21, 20, 31, 1, 33, 3, 20, 23, 22, 51, 50, 54,
+ 53, 17, 51, 17, 35, 53, 14, 1, 35, 34, 38, 53, 17, 4, 79, 9,184, 67,177,117,193,200,184,124,124,149,173, 5,254, 83,149, 94,
+ 83, 3, 3, 87,115,118, 89, 89,131,131, 1,108, 23, 77, 32, 55,209,236,222, 96, 14, 59, 1,221, 1, 62, 62,124,149,173,184,184,
+ 67,177,117,193,200, 3,182, 37, 33,252,144,172,102, 99,240,231, 1,102,254,161,159,159,190,164, 1,145, 36, 28, 94, 83,145,131,
+ 66, 87,175,123,138, 56,186, 72,122,175, 1, 44, 39, 34,145,253, 97,160, 79, 79,190,164, 2,123,251,160,172,102, 99,240,231, 1,
+252, 0, 0, 0, 0, 1, 0,174,255,227, 8,227, 6, 20, 0, 58, 0, 0, 1, 33, 38, 21, 20, 31, 1, 22, 21, 17, 35, 53, 14, 1,
+ 35, 34, 38, 53, 17, 51, 17, 20, 22, 51, 50, 54, 53, 17, 52, 47, 1, 38, 55, 54, 51, 33, 17, 33, 21, 33, 17, 20, 22, 51, 50, 55,
+ 54, 53, 17, 51, 17, 35, 53, 14, 1, 35, 34, 38, 53, 5, 57,254,243, 96, 14, 77, 49,184, 67,177,117,193,200,184,124,124,149,173,
+ 16, 77, 77, 32, 55,209, 1,211, 2,242,253, 14,124,124,152, 83, 87,184,184, 67,177,117,193,200, 5,101, 1, 44, 39, 34,188,120,
+ 77,252,144,172,102, 99,240,231, 2,166,253, 97,159,159,190,164, 1,145, 63, 39,188,187, 71,122,254, 76,170,254, 11,159,159, 95,
+ 98,161, 1, 59,252,224,172,102, 99,240,231, 0, 0, 1, 0,174,254, 86, 8,227, 6, 20, 0, 53, 0, 0, 1, 33, 38, 21, 20, 31,
+ 1, 22, 21, 17, 35, 53, 14, 1, 35, 34, 38, 53, 17, 51, 17, 20, 22, 51, 50, 54, 53, 17, 52, 47, 1, 38, 55, 54, 51, 33, 17, 62,
+ 1, 51, 50, 22, 21, 17, 35, 17, 52, 38, 35, 34, 6, 21, 17, 35, 5, 57,254,243, 96, 14, 77, 49,184, 67,177,117,193,200,184,124,
+124,149,173, 16, 77, 77, 32, 55,209, 1,212, 66,179,117,193,198,184,124,124,149,172,185, 5,101, 1, 44, 39, 34,188,120, 77,252,
+144,172,102, 99,240,231, 2,166,253, 97,159,159,190,164, 1,145, 63, 39,188,187, 71,122,253,158,101,100,239,232,253, 92, 2,158,
+159,158,190,164,251,221, 0, 0, 0, 2, 0,174,254, 86, 8,227, 6, 20, 0, 53, 0, 60, 0, 0, 1, 33, 34, 39, 38, 55, 54, 55,
+ 54, 51, 33, 17, 33, 17, 20, 22, 51, 50, 54, 53, 17, 51, 17, 35, 53, 14, 1, 35, 34, 38, 53, 17, 35, 17, 51, 21, 33, 17, 14, 1,
+ 35, 34, 38, 53, 17, 51, 17, 20, 22, 51, 50, 55, 54, 53, 25, 1, 33, 34, 21, 20, 51, 3,160,254,219,149, 94, 83, 3, 3, 87,115,
+118, 1,221, 1,153,124,124,149,173,184,184, 67,177,117,193,200,225,213,254,115, 67,177,117,193,200,184,124,124,149, 87, 86,254,
+219,131,131, 3,182, 94, 83,145,131, 66, 87,254, 76,253, 97,159,159,190,164, 2,123,251,160,172,102, 99,240,231, 1,252,251, 66,
+162, 2, 86,102, 99,240,231, 1,102,254,161,159,159, 95, 95,164, 2,123, 1, 5,123,138, 0, 0, 0, 1, 0,174,254, 86, 11,155,
+ 6, 20, 0, 72, 0, 0, 1, 33, 38, 21, 20, 31, 1, 22, 21, 17, 35, 53, 14, 1, 35, 34, 38, 53, 17, 51, 17, 20, 22, 51, 50, 54,
+ 53, 17, 52, 47, 1, 38, 55, 54, 51, 33, 17, 54, 55, 54, 51, 50, 22, 29, 1, 20, 23, 22, 51, 50, 54, 53, 17, 51, 17, 35, 53, 14,
+ 1, 35, 34, 39, 38, 61, 1, 52, 38, 35, 34, 6, 21, 17, 35, 5, 57,254,243, 96, 14, 77, 49,184, 67,177,117,193,200,184,124,124,
+149,173, 16, 77, 77, 32, 55,209, 1,212, 99, 37, 90,107,193,198, 62, 56,110,140,173,184,184, 67,177,108,175, 98,100,124,124,120,
+172,185, 5,101, 1, 44, 39, 34,188,120, 77,252,144,172,102, 99,240,231, 2,166,253, 97,159,159,190,164, 1,145, 63, 39,188,187,
+ 71,122,253,158,129, 22, 50,239,232,227,151, 88, 79,190,164, 2,123,251,160,172,102, 99,120,123,228,228,159,158,190,164,251,221,
+ 0, 3, 0, 30,255, 84, 8, 22, 7, 76, 0, 3, 0, 7, 0, 42, 0, 0, 9, 4, 21, 51, 53, 39, 53, 52, 54, 55, 54, 55, 54, 63,
+ 1, 54, 55, 54, 53, 52, 38, 35, 34, 6, 7, 21, 62, 1, 51, 50, 22, 21, 20, 6, 15, 1, 14, 1, 29, 1, 4, 26, 3,252,252, 4,
+252, 4, 3,150,203, 6, 6, 6, 8, 19, 23, 44, 88, 92, 34, 36,223,184,103,193, 94, 97,179, 79,108,131, 51, 57, 90, 90, 56, 7,
+ 76,252, 4,252, 4, 3,252,253,174,254,254,147,123, 52, 60, 21, 25, 26, 31, 43, 86, 90, 64, 69, 76,159,194, 56, 57,188, 67, 70,
+110, 89, 49, 94, 53, 89, 86,130,101,154, 0, 0, 0, 0, 0, 1, 0, 0, 60, 2, 0, 1, 9,254, 48, 0, 0, 11, 11,244, 0, 16,
+ 0, 36,255,211, 0, 16, 0, 37,255,183, 0, 16, 0, 42, 0, 75, 0, 16, 0, 45, 0,114, 0, 16, 0, 50, 0, 57, 0, 16, 0, 52,
+ 0, 75, 0, 16, 0, 55,255, 68, 0, 16, 0, 57,255,136, 0, 16, 0, 58,255,173, 0, 16, 0, 59,255,154, 0, 16, 0, 60,255, 13,
+ 0, 16, 0, 82, 0, 38, 0, 16, 0, 89,255,201, 0, 16, 0, 92,255,220, 0, 16, 0,130,255,211, 0, 16, 0,131,255,211, 0, 16,
+ 0,132,255,211, 0, 16, 0,133,255,211, 0, 16, 0,134,255,211, 0, 16, 0,148, 0, 57, 0, 16, 0,149, 0, 57, 0, 16, 0,150,
+ 0, 57, 0, 16, 0,151, 0, 57, 0, 16, 0,152, 0, 57, 0, 16, 0,159,255, 13, 0, 16, 0,180, 0, 38, 0, 16, 0,181, 0, 38,
+ 0, 16, 0,182, 0, 38, 0, 16, 0,183, 0, 38, 0, 16, 0,184, 0, 38, 0, 16, 0,191,255,220, 0, 16, 0,193,255,220, 0, 16,
+ 0,194,255,211, 0, 16, 0,196,255,211, 0, 16, 0,198,255,211, 0, 16, 0,224, 0, 75, 0, 16, 1, 38,255, 68, 0, 16, 1, 58,
+255, 13, 0, 36, 0, 16,255,211, 0, 36, 0, 17,255,220, 0, 36, 0, 29,255,220, 0, 36, 0, 36, 0, 57, 0, 36, 0, 38,255,220,
+ 0, 36, 0, 42,255,220, 0, 36, 0, 50,255,220, 0, 36, 0, 52,255,220, 0, 36, 0, 55,255, 97, 0, 36, 0, 57,255,125, 0, 36,
+ 0, 58,255,144, 0, 36, 0, 60,255, 97, 0, 36, 0, 70,255,220, 0, 36, 0, 71,255,220, 0, 36, 0, 72,255,220, 0, 36, 0, 73,
+255,183, 0, 36, 0, 82,255,220, 0, 36, 0, 84,255,220, 0, 36, 0, 87,255,220, 0, 36, 0, 89,255,136, 0, 36, 0, 90,255,173,
+ 0, 36, 0, 92,255,117, 0, 36, 0,109,255,183, 0, 36, 0,130, 0, 57, 0, 36, 0,131, 0, 57, 0, 36, 0,132, 0, 57, 0, 36,
+ 0,133, 0, 57, 0, 36, 0,134, 0, 57, 0, 36, 0,137,255,220, 0, 36, 0,148,255,220, 0, 36, 0,149,255,220, 0, 36, 0,150,
+255,220, 0, 36, 0,151,255,220, 0, 36, 0,152,255,220, 0, 36, 0,159,255, 97, 0, 36, 0,169,255,220, 0, 36, 0,170,255,220,
+ 0, 36, 0,171,255,220, 0, 36, 0,172,255,220, 0, 36, 0,173,255,220, 0, 36, 0,180,255,220, 0, 36, 0,181,255,220, 0, 36,
+ 0,182,255,220, 0, 36, 0,183,255,220, 0, 36, 0,184,255,220, 0, 36, 0,191,255,117, 0, 36, 0,193,255,117, 0, 36, 0,194,
+ 0, 57, 0, 36, 0,196, 0, 57, 0, 36, 0,198, 0, 57, 0, 36, 0,200,255,220, 0, 36, 0,201,255,220, 0, 36, 0,202,255,220,
+ 0, 36, 0,203,255,220, 0, 36, 0,204,255,220, 0, 36, 0,205,255,220, 0, 36, 0,206,255,220, 0, 36, 0,207,255,220, 0, 36,
+ 0,209,255,220, 0, 36, 0,211,255,220, 0, 36, 0,213,255,220, 0, 36, 0,215,255,220, 0, 36, 0,217,255,220, 0, 36, 0,219,
+255,220, 0, 36, 0,221,255,220, 0, 36, 0,222,255,220, 0, 36, 0,224,255,220, 0, 36, 0,226,255,220, 0, 36, 1, 14,255,220,
+ 0, 36, 1, 15,255,220, 0, 36, 1, 16,255,220, 0, 36, 1, 17,255,220, 0, 36, 1, 18,255,220, 0, 36, 1, 19,255,220, 0, 36,
+ 1, 36,255, 97, 0, 36, 1, 37,255,220, 0, 36, 1, 38,255, 97, 0, 36, 1, 39,255,220, 0, 36, 1, 54,255,144, 0, 36, 1, 55,
+255,173, 0, 36, 1, 56,255, 97, 0, 36, 1, 57,255,117, 0, 36, 1, 58,255, 97, 0, 36, 1,136,255,220, 0, 36, 1,172,255,220,
+ 0, 36, 1,173,255,220, 0, 36, 1,174,255,220, 0, 36, 1,175,255,220, 0, 36, 1,220,255, 97, 0, 36, 1,221,255,220, 0, 36,
+ 1,240,255,220, 0, 36, 1,243,255,220, 0, 36, 1,244,255, 97, 0, 36, 1,245,255,117, 0, 36, 4,252,255,144, 0, 36, 4,253,
+255,173, 0, 36, 4,254,255,144, 0, 36, 4,255,255,173, 0, 36, 5, 0,255,144, 0, 36, 5, 1,255,173, 0, 36, 5,106,255, 97,
+ 0, 36, 5,107,255,117, 0, 36, 5,145,254,248, 0, 36, 5,146,255, 3, 0, 36, 5,147, 0, 47, 0, 37, 0, 38,255,220, 0, 37,
+ 0, 42,255,220, 0, 37, 0, 50,255,220, 0, 37, 0, 54,255,220, 0, 37, 0, 57,255,193, 0, 37, 0, 58,255,183, 0, 37, 0, 60,
+255,144, 0, 37, 0,109,255,193, 0, 37, 0,125,255,220, 0, 37, 0,137,255,220, 0, 37, 0,148,255,220, 0, 37, 0,149,255,220,
+ 0, 37, 0,150,255,220, 0, 37, 0,151,255,220, 0, 37, 0,152,255,220, 0, 37, 0,159,255,144, 0, 37, 0,200,255,220, 0, 37,
+ 0,202,255,220, 0, 37, 0,204,255,220, 0, 37, 0,206,255,220, 0, 37, 0,222,255,220, 0, 37, 0,224,255,220, 0, 37, 0,226,
+255,220, 0, 37, 0,228,255,220, 0, 37, 1, 14,255,220, 0, 37, 1, 16,255,220, 0, 37, 1, 18,255,220, 0, 37, 1, 28,255,220,
+ 0, 37, 1, 30,255,220, 0, 37, 1, 32,255,220, 0, 37, 1, 34,255,220, 0, 37, 1, 54,255,183, 0, 37, 1, 56,255,144, 0, 37,
+ 1, 58,255,144, 0, 37, 1,172,255,220, 0, 37, 1,174,255,220, 0, 37, 1,218,255,220, 0, 37, 1,240,255,220, 0, 37, 4,252,
+255,183, 0, 37, 4,254,255,183, 0, 37, 5, 0,255,183, 0, 37, 5,106,255,144, 0, 37, 5,145,255,144, 0, 37, 5,146,255,144,
+ 0, 37, 5,147,255,173, 0, 38, 0, 60,255,220, 0, 38, 0,109,255,220, 0, 38, 0,125,255,220, 0, 38, 0,159,255,220, 0, 38,
+ 1, 56,255,220, 0, 38, 1, 58,255,220, 0, 38, 1,244,255,220, 0, 38, 5,106,255,220, 0, 38, 5,146, 0, 38, 0, 39, 0, 36,
+255,220, 0, 39, 0, 57,255,220, 0, 39, 0, 60,255,144, 0, 39, 0,109,255,220, 0, 39, 0,125,255,220, 0, 39, 0,130,255,220,
+ 0, 39, 0,131,255,220, 0, 39, 0,132,255,220, 0, 39, 0,133,255,220, 0, 39, 0,134,255,220, 0, 39, 0,159,255,144, 0, 39,
+ 0,194,255,220, 0, 39, 0,196,255,220, 0, 39, 0,198,255,220, 0, 39, 1, 56,255,144, 0, 39, 1, 58,255,144, 0, 39, 1,244,
+255,144, 0, 39, 5,106,255,144, 0, 39, 5,145,255,211, 0, 39, 5,146,255,201, 0, 39, 5,147,255, 68, 0, 41, 0, 17,254,183,
+ 0, 41, 0, 29,255, 97, 0, 41, 0, 36,255, 68, 0, 41, 0, 54,255,220, 0, 41, 0, 55,255,220, 0, 41, 0, 68,255, 68, 0, 41,
+ 0, 72,255,144, 0, 41, 0, 76,255,107, 0, 41, 0, 82,255,183, 0, 41, 0, 85,255,107, 0, 41, 0, 88,255,144, 0, 41, 0, 92,
+255, 68, 0, 41, 0,130,255, 68, 0, 41, 0,131,255, 68, 0, 41, 0,132,255, 68, 0, 41, 0,133,255, 68, 0, 41, 0,134,255, 68,
+ 0, 41, 0,162,255, 68, 0, 41, 0,163,255, 68, 0, 41, 0,164,255, 68, 0, 41, 0,165,255, 68, 0, 41, 0,166,255, 68, 0, 41,
+ 0,167,255, 68, 0, 41, 0,170,255,144, 0, 41, 0,171,255,144, 0, 41, 0,172,255,144, 0, 41, 0,173,255,144, 0, 41, 0,180,
+255,183, 0, 41, 0,181,255,183, 0, 41, 0,182,255,183, 0, 41, 0,183,255,183, 0, 41, 0,184,255,183, 0, 41, 0,187,255,144,
+ 0, 41, 0,188,255,144, 0, 41, 0,189,255,144, 0, 41, 0,190,255,144, 0, 41, 0,191,255, 68, 0, 41, 0,193,255, 68, 0, 41,
+ 0,194,255, 68, 0, 41, 0,195,255, 68, 0, 41, 0,196,255, 68, 0, 41, 0,197,255, 68, 0, 41, 0,198,255, 68, 0, 41, 0,199,
+255, 68, 0, 41, 0,213,255,144, 0, 41, 0,215,255,144, 0, 41, 0,217,255,144, 0, 41, 0,219,255,144, 0, 41, 0,221,255,144,
+ 0, 41, 0,241,255,107, 0, 41, 0,245,255,107, 0, 41, 1, 15,255,183, 0, 41, 1, 17,255,183, 0, 41, 1, 19,255,183, 0, 41,
+ 1, 23,255,107, 0, 41, 1, 25,255,107, 0, 41, 1, 27,255,107, 0, 41, 1, 28,255,220, 0, 41, 1, 30,255,220, 0, 41, 1, 32,
+255,220, 0, 41, 1, 34,255,220, 0, 41, 1, 36,255,220, 0, 41, 1, 38,255,220, 0, 41, 1, 40,255,220, 0, 41, 1, 43,255,144,
+ 0, 41, 1, 45,255,144, 0, 41, 1, 47,255,144, 0, 41, 1, 49,255,144, 0, 41, 1, 51,255,144, 0, 41, 1, 53,255,144, 0, 41,
+ 1, 57,255, 68, 0, 41, 1,173,255,183, 0, 41, 1,175,255,183, 0, 41, 1,218,255,220, 0, 41, 1,220,255,220, 0, 41, 1,241,
+255,183, 0, 41, 1,245,255, 68, 0, 41, 5,107,255, 68, 0, 41, 5,145,255,211, 0, 41, 5,147,254,136, 0, 42, 0, 55,255,183,
+ 0, 42, 0, 60,255,154, 0, 42, 0,109,255,220, 0, 42, 0,125,255,220, 0, 42, 0,159,255,154, 0, 42, 1, 38,255,183, 0, 42,
+ 1, 58,255,154, 0, 42, 5,145,255,211, 0, 42, 5,146,255,211, 0, 42, 5,147,255,201, 0, 43, 0, 17,255,220, 0, 43, 5,145,
+255,183, 0, 43, 5,146,255,193, 0, 43, 5,147,255,183, 0, 45, 0, 16,255,183, 0, 45, 0, 36,255,220, 0, 45, 0,109,255,220,
+ 0, 45, 0,125,255,220, 0, 45, 0,130,255,220, 0, 45, 0,131,255,220, 0, 45, 0,132,255,220, 0, 45, 0,133,255,220, 0, 45,
+ 0,134,255,220, 0, 45, 5,145,255,183, 0, 45, 5,146,255,193, 0, 45, 5,147,255,144, 0, 46, 0, 16,255, 41, 0, 46, 0, 36,
+255,220, 0, 46, 0, 38,255,144, 0, 46, 0, 50,255,144, 0, 46, 0, 55,255, 97, 0, 46, 0, 56,255,201, 0, 46, 0, 58,255,183,
+ 0, 46, 0, 60,255,183, 0, 46, 0, 68,255,220, 0, 46, 0, 72,255,154, 0, 46, 0, 82,255,154, 0, 46, 0, 88,255,154, 0, 46,
+ 0, 92,255,107, 0, 46, 0,109,255,125, 0, 46, 0,130,255,220, 0, 46, 0,131,255,220, 0, 46, 0,132,255,220, 0, 46, 0,133,
+255,220, 0, 46, 0,134,255,220, 0, 46, 0,137,255,144, 0, 46, 0,148,255,144, 0, 46, 0,149,255,144, 0, 46, 0,150,255,144,
+ 0, 46, 0,151,255,144, 0, 46, 0,152,255,144, 0, 46, 0,155,255,201, 0, 46, 0,156,255,201, 0, 46, 0,157,255,201, 0, 46,
+ 0,158,255,201, 0, 46, 0,159,255,183, 0, 46, 0,162,255,220, 0, 46, 0,163,255,220, 0, 46, 0,164,255,220, 0, 46, 0,165,
+255,220, 0, 46, 0,166,255,220, 0, 46, 0,167,255,220, 0, 46, 0,170,255,154, 0, 46, 0,171,255,154, 0, 46, 0,172,255,154,
+ 0, 46, 0,173,255,154, 0, 46, 0,180,255,154, 0, 46, 0,181,255,154, 0, 46, 0,182,255,154, 0, 46, 0,183,255,154, 0, 46,
+ 0,184,255,154, 0, 46, 0,187,255,154, 0, 46, 0,188,255,154, 0, 46, 0,189,255,154, 0, 46, 0,190,255,154, 0, 46, 0,191,
+255,107, 0, 46, 0,193,255,107, 0, 46, 0,200,255,144, 0, 46, 0,206,255,144, 0, 46, 0,221,255,154, 0, 46, 1, 38,255, 97,
+ 0, 46, 1, 48,255,201, 0, 46, 1, 49,255,154, 0, 46, 1, 58,255,183, 0, 46, 5,145,255,193, 0, 46, 5,146,255,193, 0, 47,
+ 0, 16,255,220, 0, 47, 0, 36, 0, 47, 0, 47, 0, 50,255,183, 0, 47, 0, 55,254,230, 0, 47, 0, 56,255,154, 0, 47, 0, 57,
+255, 31, 0, 47, 0, 58,255, 68, 0, 47, 0, 60,254,240, 0, 47, 0, 72,255,220, 0, 47, 0, 82,255,220, 0, 47, 0, 88,255,220,
+ 0, 47, 0, 92,255, 68, 0, 47, 0,130, 0, 47, 0, 47, 0,131, 0, 47, 0, 47, 0,132, 0, 47, 0, 47, 0,133, 0, 47, 0, 47,
+ 0,134, 0, 47, 0, 47, 0,148,255,183, 0, 47, 0,149,255,183, 0, 47, 0,150,255,183, 0, 47, 0,151,255,183, 0, 47, 0,152,
+255,183, 0, 47, 0,155,255,154, 0, 47, 0,156,255,154, 0, 47, 0,157,255,154, 0, 47, 0,158,255,154, 0, 47, 0,159,254,240,
+ 0, 47, 0,170,255,220, 0, 47, 0,171,255,220, 0, 47, 0,172,255,220, 0, 47, 0,173,255,220, 0, 47, 0,180,255,220, 0, 47,
+ 0,181,255,220, 0, 47, 0,182,255,220, 0, 47, 0,183,255,220, 0, 47, 0,184,255,220, 0, 47, 0,187,255,220, 0, 47, 0,188,
+255,220, 0, 47, 0,189,255,220, 0, 47, 0,190,255,220, 0, 47, 0,191,255, 68, 0, 47, 0,193,255, 68, 0, 47, 0,221,255,220,
+ 0, 47, 1, 38,254,230, 0, 47, 1, 48,255,154, 0, 47, 1, 49,255,220, 0, 47, 1, 58,254,240, 0, 47, 5,145,254, 97, 0, 47,
+ 5,146,253,230, 0, 50, 0, 16, 0, 57, 0, 50, 0, 17,255,173, 0, 50, 0, 29,255,220, 0, 50, 0, 36,255,220, 0, 50, 0, 57,
+255,220, 0, 50, 0, 59,255,125, 0, 50, 0, 60,255,144, 0, 50, 0,109,255,220, 0, 50, 0,130,255,220, 0, 50, 0,131,255,220,
+ 0, 50, 0,132,255,220, 0, 50, 0,133,255,220, 0, 50, 0,134,255,220, 0, 50, 0,159,255,144, 0, 50, 1, 58,255,144, 0, 50,
+ 5,145,255,211, 0, 50, 5,146,255,220, 0, 50, 5,147,255, 68, 0, 51, 0, 16,255,211, 0, 51, 0, 17,254,193, 0, 51, 0, 36,
+255,125, 0, 51, 0, 60,255,211, 0, 51, 0, 68,255,164, 0, 51, 0, 72,255,183, 0, 51, 0, 76,255,211, 0, 51, 0, 81,255,220,
+ 0, 51, 0, 82,255,183, 0, 51, 0, 85,255,220, 0, 51, 0, 86,255,220, 0, 51, 0, 88,255,220, 0, 51, 0,109,255,220, 0, 51,
+ 0,130,255,125, 0, 51, 0,131,255,125, 0, 51, 0,132,255,125, 0, 51, 0,133,255,125, 0, 51, 0,134,255,125, 0, 51, 0,159,
+255,211, 0, 51, 0,162,255,164, 0, 51, 0,163,255,164, 0, 51, 0,164,255,164, 0, 51, 0,165,255,164, 0, 51, 0,166,255,164,
+ 0, 51, 0,167,255,164, 0, 51, 0,170,255,183, 0, 51, 0,171,255,183, 0, 51, 0,172,255,183, 0, 51, 0,173,255,183, 0, 51,
+ 0,179,255,220, 0, 51, 0,180,255,183, 0, 51, 0,181,255,183, 0, 51, 0,182,255,183, 0, 51, 0,183,255,183, 0, 51, 0,184,
+255,183, 0, 51, 0,187,255,220, 0, 51, 0,188,255,220, 0, 51, 0,189,255,220, 0, 51, 0,190,255,220, 0, 51, 0,221,255,183,
+ 0, 51, 1, 10,255,220, 0, 51, 1, 23,255,220, 0, 51, 1, 27,255,220, 0, 51, 1, 33,255,220, 0, 51, 1, 35,255,220, 0, 51,
+ 1, 49,255,220, 0, 51, 1, 58,255,211, 0, 51, 5,145, 0, 38, 0, 51, 5,146, 0, 38, 0, 51, 5,147,254,183, 0, 52, 0, 16,
+ 0, 57, 0, 52, 5,145,255,211, 0, 52, 5,146,255,220, 0, 52, 5,147,255,125, 0, 53, 0, 16,255,173, 0, 53, 0, 17,255,183,
+ 0, 53, 0, 29,255,193, 0, 53, 0, 36,255,173, 0, 53, 0, 38,255,154, 0, 53, 0, 55,255,107, 0, 53, 0, 57,255,144, 0, 53,
+ 0, 58,255,173, 0, 53, 0, 60,255,125, 0, 53, 0, 68,255,211, 0, 53, 0, 72,255,164, 0, 53, 0, 82,255,164, 0, 53, 0, 88,
+255,164, 0, 53, 0, 92,255,144, 0, 53, 0,109,255,144, 0, 53, 0,125,255,220, 0, 53, 0,130,255,173, 0, 53, 0,131,255,173,
+ 0, 53, 0,132,255,173, 0, 53, 0,133,255,173, 0, 53, 0,134,255,173, 0, 53, 0,137,255,154, 0, 53, 0,159,255,125, 0, 53,
+ 0,162,255,211, 0, 53, 0,163,255,211, 0, 53, 0,164,255,211, 0, 53, 0,165,255,211, 0, 53, 0,166,255,211, 0, 53, 0,167,
+255,211, 0, 53, 0,170,255,164, 0, 53, 0,171,255,164, 0, 53, 0,172,255,164, 0, 53, 0,173,255,164, 0, 53, 0,180,255,164,
+ 0, 53, 0,181,255,164, 0, 53, 0,182,255,164, 0, 53, 0,183,255,164, 0, 53, 0,184,255,164, 0, 53, 0,187,255,164, 0, 53,
+ 0,188,255,164, 0, 53, 0,189,255,164, 0, 53, 0,190,255,164, 0, 53, 0,191,255,144, 0, 53, 0,193,255,144, 0, 53, 0,200,
+255,154, 0, 53, 0,206,255,154, 0, 53, 0,221,255,164, 0, 53, 1, 38,255,107, 0, 53, 1, 49,255,164, 0, 53, 1, 58,255,125,
+ 0, 53, 5,145,255,107, 0, 53, 5,146,255,125, 0, 53, 5,147,255,220, 0, 54, 0, 36, 0, 38, 0, 54, 0,130, 0, 38, 0, 54,
+ 0,131, 0, 38, 0, 54, 0,132, 0, 38, 0, 54, 0,133, 0, 38, 0, 54, 0,134, 0, 38, 0, 55, 0, 16,255, 68, 0, 55, 0, 17,
+255, 13, 0, 55, 0, 29,255, 31, 0, 55, 0, 36,255, 97, 0, 55, 0, 38,255,136, 0, 55, 0, 55,255,220, 0, 55, 0, 68,254,173,
+ 0, 55, 0, 70,254,164, 0, 55, 0, 72,254,164, 0, 55, 0, 76,255,193, 0, 55, 0, 82,254,164, 0, 55, 0, 85,254,211, 0, 55,
+ 0, 86,254,173, 0, 55, 0, 88,254,201, 0, 55, 0, 90,254,173, 0, 55, 0, 92,254,193, 0, 55, 0,109,255, 68, 0, 55, 0,125,
+255,144, 0, 55, 0,130,255, 97, 0, 55, 0,131,255, 97, 0, 55, 0,132,255, 97, 0, 55, 0,133,255, 97, 0, 55, 0,134,255, 97,
+ 0, 55, 0,137,255,136, 0, 55, 0,162,254,173, 0, 55, 0,163,254,173, 0, 55, 0,164,254,173, 0, 55, 0,165,254,173, 0, 55,
+ 0,166,254,173, 0, 55, 0,167,254,173, 0, 55, 0,169,254,164, 0, 55, 0,170,254,164, 0, 55, 0,171,254,164, 0, 55, 0,172,
+254,164, 0, 55, 0,173,254,164, 0, 55, 0,180,254,164, 0, 55, 0,181,254,164, 0, 55, 0,182,254,164, 0, 55, 0,183,254,164,
+ 0, 55, 0,184,254,164, 0, 55, 0,187,254,201, 0, 55, 0,188,254,201, 0, 55, 0,189,254,201, 0, 55, 0,190,254,201, 0, 55,
+ 0,191,254,193, 0, 55, 0,193,254,193, 0, 55, 0,200,255,136, 0, 55, 0,201,254,164, 0, 55, 0,206,255,136, 0, 55, 0,207,
+254,164, 0, 55, 0,221,254,164, 0, 55, 1, 23,254,211, 0, 55, 1, 27,254,211, 0, 55, 1, 33,254,173, 0, 55, 1, 35,254,173,
+ 0, 55, 1, 38,255,220, 0, 55, 1, 49,254,201, 0, 55, 5,146,255,211, 0, 55, 5,147,254,248, 0, 56, 0, 61,255,220, 0, 56,
+ 1, 63,255,220, 0, 57, 0, 16,255,136, 0, 57, 0, 17,254,248, 0, 57, 0, 29,255, 89, 0, 57, 0, 36,255,125, 0, 57, 0, 50,
+255,220, 0, 57, 0, 68,255, 97, 0, 57, 0, 72,255, 97, 0, 57, 0, 76,255,211, 0, 57, 0, 82,255, 97, 0, 57, 0, 88,255,117,
+ 0, 57, 0, 92,255,201, 0, 57, 0,109,255, 78, 0, 57, 0,125,255,144, 0, 57, 0,130,255,125, 0, 57, 0,131,255,125, 0, 57,
+ 0,132,255,125, 0, 57, 0,133,255,125, 0, 57, 0,134,255,125, 0, 57, 0,148,255,220, 0, 57, 0,149,255,220, 0, 57, 0,150,
+255,220, 0, 57, 0,151,255,220, 0, 57, 0,152,255,220, 0, 57, 0,162,255, 97, 0, 57, 0,163,255, 97, 0, 57, 0,164,255, 97,
+ 0, 57, 0,165,255, 97, 0, 57, 0,166,255, 97, 0, 57, 0,167,255, 97, 0, 57, 0,170,255, 97, 0, 57, 0,171,255, 97, 0, 57,
+ 0,172,255, 97, 0, 57, 0,173,255, 97, 0, 57, 0,180,255, 97, 0, 57, 0,181,255, 97, 0, 57, 0,182,255, 97, 0, 57, 0,183,
+255, 97, 0, 57, 0,184,255, 97, 0, 57, 0,187,255,117, 0, 57, 0,188,255,117, 0, 57, 0,189,255,117, 0, 57, 0,190,255,117,
+ 0, 57, 0,191,255,201, 0, 57, 0,193,255,201, 0, 57, 0,221,255, 97, 0, 57, 1, 49,255,117, 0, 57, 5,147,254,230, 0, 58,
+ 0, 16,255,173, 0, 58, 0, 17,255, 21, 0, 58, 0, 29,255,136, 0, 58, 0, 36,255,144, 0, 58, 0, 68,255,125, 0, 58, 0, 72,
+255,136, 0, 58, 0, 76,255,211, 0, 58, 0, 82,255,136, 0, 58, 0, 85,255,164, 0, 58, 0, 88,255,183, 0, 58, 0, 92,255,220,
+ 0, 58, 0,109,255,144, 0, 58, 0,125,255,220, 0, 58, 0,130,255,144, 0, 58, 0,131,255,144, 0, 58, 0,132,255,144, 0, 58,
+ 0,133,255,144, 0, 58, 0,134,255,144, 0, 58, 0,162,255,125, 0, 58, 0,163,255,125, 0, 58, 0,164,255,125, 0, 58, 0,165,
+255,125, 0, 58, 0,166,255,125, 0, 58, 0,167,255,125, 0, 58, 0,170,255,136, 0, 58, 0,171,255,136, 0, 58, 0,172,255,136,
+ 0, 58, 0,173,255,136, 0, 58, 0,180,255,136, 0, 58, 0,181,255,136, 0, 58, 0,182,255,136, 0, 58, 0,183,255,136, 0, 58,
+ 0,184,255,136, 0, 58, 0,187,255,183, 0, 58, 0,188,255,183, 0, 58, 0,189,255,183, 0, 58, 0,190,255,183, 0, 58, 0,191,
+255,220, 0, 58, 0,193,255,220, 0, 58, 0,221,255,136, 0, 58, 1, 23,255,164, 0, 58, 1, 27,255,164, 0, 58, 1, 49,255,183,
+ 0, 58, 5,145,255,220, 0, 58, 5,147,254,248, 0, 59, 0, 16,255,154, 0, 59, 0, 38,255,107, 0, 59, 0, 50,255,125, 0, 59,
+ 0, 55,255,220, 0, 59, 0, 72,255,164, 0, 59, 0,109,255,144, 0, 59, 0,137,255,107, 0, 59, 0,148,255,125, 0, 59, 0,149,
+255,125, 0, 59, 0,150,255,125, 0, 59, 0,151,255,125, 0, 59, 0,152,255,125, 0, 59, 0,170,255,164, 0, 59, 0,171,255,164,
+ 0, 59, 0,172,255,164, 0, 59, 0,173,255,164, 0, 59, 0,200,255,107, 0, 59, 0,206,255,107, 0, 59, 0,221,255,164, 0, 59,
+ 1, 38,255,220, 0, 59, 5,145,255, 97, 0, 59, 5,146,255,173, 0, 59, 5,147,255,211, 0, 60, 0, 16,255, 13, 0, 60, 0, 17,
+254, 97, 0, 60, 0, 29,254,240, 0, 60, 0, 36,255, 97, 0, 60, 0, 38,255,144, 0, 60, 0, 50,255,144, 0, 60, 0, 68,254,230,
+ 0, 60, 0, 72,254,240, 0, 60, 0, 76,255,183, 0, 60, 0, 82,254,240, 0, 60, 0, 88,255, 21, 0, 60, 0,109,255, 31, 0, 60,
+ 0,125,255,107, 0, 60, 0,130,255, 97, 0, 60, 0,131,255, 97, 0, 60, 0,132,255, 97, 0, 60, 0,133,255, 97, 0, 60, 0,134,
+255, 97, 0, 60, 0,137,255,144, 0, 60, 0,148,255,144, 0, 60, 0,149,255,144, 0, 60, 0,150,255,144, 0, 60, 0,151,255,144,
+ 0, 60, 0,152,255,144, 0, 60, 0,162,254,230, 0, 60, 0,163,254,230, 0, 60, 0,164,254,230, 0, 60, 0,165,254,230, 0, 60,
+ 0,166,254,230, 0, 60, 0,167,254,230, 0, 60, 0,170,254,240, 0, 60, 0,171,254,240, 0, 60, 0,172,254,240, 0, 60, 0,173,
+254,240, 0, 60, 0,180,254,240, 0, 60, 0,181,254,240, 0, 60, 0,182,254,240, 0, 60, 0,183,254,240, 0, 60, 0,184,254,240,
+ 0, 60, 0,187,255, 21, 0, 60, 0,188,255, 21, 0, 60, 0,189,255, 21, 0, 60, 0,190,255, 21, 0, 60, 0,200,255,144, 0, 60,
+ 0,206,255,144, 0, 60, 0,221,254,240, 0, 60, 1, 49,255, 21, 0, 60, 5,145,255,144, 0, 60, 5,146,255,220, 0, 60, 5,147,
+254,248, 0, 61, 0, 16,255,220, 0, 61, 5,145,255,220, 0, 61, 5,146,255,220, 0, 61, 5,147,255,220, 0, 72, 0, 91,255,220,
+ 0, 73, 0, 16,255,144, 0, 73, 0, 17,255,107, 0, 73, 0, 29,255,183, 0, 73, 0, 87,255,220, 0, 73, 0, 90,255,220, 0, 73,
+ 0, 92,255,220, 0, 73, 0,109,255,183, 0, 73, 0,125,255,220, 0, 73, 0,191,255,220, 0, 73, 0,193,255,220, 0, 73, 1, 39,
+255,220, 0, 73, 5,145, 0, 65, 0, 73, 5,147,255, 21, 0, 78, 0, 68,255,220, 0, 78, 0, 72,255,183, 0, 78, 0, 82,255,183,
+ 0, 78, 0, 88,255,193, 0, 78, 0, 92,255,183, 0, 78, 0,162,255,220, 0, 78, 0,163,255,220, 0, 78, 0,164,255,220, 0, 78,
+ 0,165,255,220, 0, 78, 0,166,255,220, 0, 78, 0,167,255,220, 0, 78, 0,170,255,183, 0, 78, 0,171,255,183, 0, 78, 0,172,
+255,183, 0, 78, 0,173,255,183, 0, 78, 0,180,255,183, 0, 78, 0,181,255,183, 0, 78, 0,182,255,183, 0, 78, 0,183,255,183,
+ 0, 78, 0,184,255,183, 0, 78, 0,187,255,193, 0, 78, 0,188,255,193, 0, 78, 0,189,255,193, 0, 78, 0,190,255,193, 0, 78,
+ 0,191,255,183, 0, 78, 0,193,255,183, 0, 78, 0,221,255,183, 0, 78, 1, 49,255,193, 0, 81, 5,145,255,107, 0, 81, 5,146,
+255,144, 0, 81, 5,147,255,164, 0, 82, 0, 16, 0, 38, 0, 82, 0, 17,255,220, 0, 82, 0, 91,255,193, 0, 82, 5,145,255,107,
+ 0, 82, 5,146,255,183, 0, 82, 5,147,255,125, 0, 85, 0, 16,255,125, 0, 85, 0, 17,255, 68, 0, 85, 0, 29,255,220, 0, 85,
+ 0, 70,255,211, 0, 85, 0, 71,255,220, 0, 85, 0, 72,255,211, 0, 85, 0, 74,255,220, 0, 85, 0, 75,255,220, 0, 85, 0, 80,
+255,220, 0, 85, 0, 81,255,220, 0, 85, 0, 82,255,211, 0, 85, 0, 84,255,220, 0, 85, 0, 85,255,220, 0, 85, 0, 91,255,201,
+ 0, 85, 0,109,255,183, 0, 85, 0,169,255,211, 0, 85, 0,170,255,211, 0, 85, 0,171,255,211, 0, 85, 0,172,255,211, 0, 85,
+ 0,173,255,211, 0, 85, 0,179,255,220, 0, 85, 0,180,255,211, 0, 85, 0,181,255,211, 0, 85, 0,182,255,211, 0, 85, 0,183,
+255,211, 0, 85, 0,184,255,211, 0, 85, 0,201,255,211, 0, 85, 0,207,255,211, 0, 85, 0,209, 0, 72, 0, 85, 0,221,255,211,
+ 0, 85, 0,225,255,220, 0, 85, 1, 10,255,220, 0, 85, 1, 23,255,220, 0, 85, 1, 27,255,220, 0, 85, 5,146, 0, 86, 0, 85,
+ 5,147,254,201, 0, 89, 0, 16,255,201, 0, 89, 0, 17,255, 97, 0, 89, 0, 29,255,144, 0, 89, 0,109,255,220, 0, 89, 0,125,
+255,220, 0, 89, 5,146,255,220, 0, 89, 5,147,254,240, 0, 90, 0, 17,255, 68, 0, 90, 0, 29,255,144, 0, 90, 0,109,255,220,
+ 0, 90, 0,125,255,220, 0, 90, 5,147,255, 41, 0, 91, 0, 70,255,220, 0, 91, 0, 72,255,193, 0, 91, 0, 82,255,193, 0, 91,
+ 0,169,255,220, 0, 91, 0,170,255,193, 0, 91, 0,171,255,193, 0, 91, 0,172,255,193, 0, 91, 0,173,255,193, 0, 91, 0,180,
+255,193, 0, 91, 0,181,255,193, 0, 91, 0,182,255,193, 0, 91, 0,183,255,193, 0, 91, 0,184,255,193, 0, 91, 0,201,255,220,
+ 0, 91, 0,207,255,220, 0, 91, 0,221,255,193, 0, 92, 0, 16,255,220, 0, 92, 0, 17,254,220, 0, 92, 0, 29,255,107, 0, 92,
+ 0,109,255,220, 0, 92, 0,125,255,220, 0, 92, 5,147,254,211, 0,109, 0, 37,255,220, 0,109, 0, 38,255,220, 0,109, 0, 39,
+255,220, 0,109, 0, 42,255,220, 0,109, 0, 45,255,220, 0,109, 0, 55,255,144, 0,109, 0, 57,255,144, 0,109, 0, 58,255,220,
+ 0,109, 0, 60,255,107, 0,109, 0, 89,255,220, 0,109, 0, 90,255,220, 0,109, 0, 92,255,220, 0,109, 0,136, 0,151, 0,109,
+ 0,137,255,220, 0,109, 0,159,255,107, 0,109, 0,191,255,220, 0,109, 0,193,255,220, 0,109, 0,200,255,220, 0,109, 0,206,
+255,220, 0,109, 0,208,255,220, 0,109, 0,224,255,220, 0,109, 1, 38,255,144, 0,109, 1, 58,255,107, 0,125, 0, 36,255,183,
+ 0,125, 0, 37,255,183, 0,125, 0, 38,255,220, 0,125, 0, 39,255,220, 0,125, 0, 45,255,220, 0,125, 0, 50,255,220, 0,125,
+ 0, 55,255, 68, 0,125, 0, 57,255, 78, 0,125, 0, 58,255,144, 0,125, 0, 59,255,144, 0,125, 0, 60,255, 31, 0,125, 0, 89,
+255,220, 0,125, 0, 90,255,220, 0,125, 0, 92,255,220, 0,125, 0,130,255,183, 0,125, 0,131,255,183, 0,125, 0,132,255,183,
+ 0,125, 0,133,255,183, 0,125, 0,134,255,183, 0,125, 0,137,255,220, 0,125, 0,148,255,220, 0,125, 0,149,255,220, 0,125,
+ 0,150,255,220, 0,125, 0,151,255,220, 0,125, 0,152,255,220, 0,125, 0,159,255, 31, 0,125, 0,191,255,220, 0,125, 0,193,
+255,220, 0,125, 0,200,255,220, 0,125, 0,206,255,220, 0,125, 0,208,255,220, 0,125, 1, 38,255, 68, 0,125, 1, 58,255, 31,
+ 0,130, 0, 16,255,211, 0,130, 0, 17,255,220, 0,130, 0, 29,255,220, 0,130, 0, 36, 0, 57, 0,130, 0, 38,255,220, 0,130,
+ 0, 42,255,220, 0,130, 0, 50,255,220, 0,130, 0, 52,255,220, 0,130, 0, 55,255, 97, 0,130, 0, 57,255,125, 0,130, 0, 58,
+255,144, 0,130, 0, 60,255, 97, 0,130, 0, 70,255,220, 0,130, 0, 71,255,220, 0,130, 0, 72,255,220, 0,130, 0, 73,255,183,
+ 0,130, 0, 82,255,220, 0,130, 0, 84,255,220, 0,130, 0, 87,255,220, 0,130, 0, 89,255,136, 0,130, 0, 90,255,173, 0,130,
+ 0, 92,255,117, 0,130, 0,109,255,183, 0,130, 0,130, 0, 57, 0,130, 0,131, 0, 57, 0,130, 0,132, 0, 57, 0,130, 0,133,
+ 0, 57, 0,130, 0,134, 0, 57, 0,130, 0,137,255,220, 0,130, 0,148,255,220, 0,130, 0,149,255,220, 0,130, 0,150,255,220,
+ 0,130, 0,151,255,220, 0,130, 0,152,255,220, 0,130, 0,159,255, 97, 0,130, 0,169,255,220, 0,130, 0,170,255,220, 0,130,
+ 0,171,255,220, 0,130, 0,172,255,220, 0,130, 0,173,255,220, 0,130, 0,180,255,220, 0,130, 0,181,255,220, 0,130, 0,182,
+255,220, 0,130, 0,183,255,220, 0,130, 0,184,255,220, 0,130, 0,191,255,117, 0,130, 0,193,255,117, 0,130, 0,194, 0, 57,
+ 0,130, 0,196, 0, 57, 0,130, 0,198, 0, 57, 0,130, 0,200,255,220, 0,130, 0,201,255,220, 0,130, 0,202,255,220, 0,130,
+ 0,204,255,220, 0,130, 0,205,255,220, 0,130, 0,206,255,220, 0,130, 0,207,255,220, 0,130, 0,209,255,220, 0,130, 0,213,
+255,220, 0,130, 0,215,255,220, 0,130, 0,217,255,220, 0,130, 0,219,255,220, 0,130, 0,221,255,220, 0,130, 0,222,255,220,
+ 0,130, 0,224,255,220, 0,130, 0,226,255,220, 0,130, 1, 14,255,220, 0,130, 1, 15,255,220, 0,130, 1, 16,255,220, 0,130,
+ 1, 17,255,220, 0,130, 1, 18,255,220, 0,130, 1, 19,255,220, 0,130, 1, 36,255, 97, 0,130, 1, 37,255,220, 0,130, 1, 38,
+255, 97, 0,130, 1, 39,255,220, 0,130, 1, 54,255,144, 0,130, 1, 55,255,173, 0,130, 1, 56,255, 97, 0,130, 1, 57,255,117,
+ 0,130, 1, 58,255, 97, 0,130, 1,240,255,220, 0,130, 1,241,255,220, 0,130, 4,252,255,144, 0,130, 4,255,255,173, 0,130,
+ 5, 0,255,144, 0,130, 5, 1,255,173, 0,130, 5,106,255, 97, 0,130, 5,107,255,117, 0,130, 5,145,254,248, 0,130, 5,146,
+255, 3, 0,130, 5,147, 0, 47, 0,131, 0, 16,255,211, 0,131, 0, 17,255,220, 0,131, 0, 29,255,220, 0,131, 0, 36, 0, 57,
+ 0,131, 0, 38,255,220, 0,131, 0, 42,255,220, 0,131, 0, 50,255,220, 0,131, 0, 52,255,220, 0,131, 0, 55,255, 97, 0,131,
+ 0, 57,255,125, 0,131, 0, 58,255,144, 0,131, 0, 60,255, 97, 0,131, 0, 70,255,220, 0,131, 0, 71,255,220, 0,131, 0, 72,
+255,220, 0,131, 0, 73,255,183, 0,131, 0, 82,255,220, 0,131, 0, 84,255,220, 0,131, 0, 87,255,220, 0,131, 0, 89,255,136,
+ 0,131, 0, 90,255,173, 0,131, 0, 92,255,117, 0,131, 0,109,255,183, 0,131, 0,130, 0, 57, 0,131, 0,131, 0, 57, 0,131,
+ 0,132, 0, 57, 0,131, 0,133, 0, 57, 0,131, 0,134, 0, 57, 0,131, 0,137,255,220, 0,131, 0,148,255,220, 0,131, 0,149,
+255,220, 0,131, 0,150,255,220, 0,131, 0,151,255,220, 0,131, 0,152,255,220, 0,131, 0,159,255, 97, 0,131, 0,169,255,220,
+ 0,131, 0,170,255,220, 0,131, 0,171,255,220, 0,131, 0,172,255,220, 0,131, 0,173,255,220, 0,131, 0,180,255,220, 0,131,
+ 0,181,255,220, 0,131, 0,182,255,220, 0,131, 0,183,255,220, 0,131, 0,184,255,220, 0,131, 0,191,255,117, 0,131, 0,193,
+255,117, 0,131, 0,194, 0, 57, 0,131, 0,196, 0, 57, 0,131, 0,198, 0, 57, 0,131, 0,200,255,220, 0,131, 0,201,255,220,
+ 0,131, 0,202,255,220, 0,131, 0,204,255,220, 0,131, 0,205,255,220, 0,131, 0,206,255,220, 0,131, 0,207,255,220, 0,131,
+ 0,209,255,220, 0,131, 0,213,255,220, 0,131, 0,215,255,220, 0,131, 0,217,255,220, 0,131, 0,219,255,220, 0,131, 0,221,
+255,220, 0,131, 0,222,255,220, 0,131, 0,224,255,220, 0,131, 0,226,255,220, 0,131, 1, 14,255,220, 0,131, 1, 15,255,220,
+ 0,131, 1, 16,255,220, 0,131, 1, 17,255,220, 0,131, 1, 18,255,220, 0,131, 1, 19,255,220, 0,131, 1, 36,255, 97, 0,131,
+ 1, 37,255,220, 0,131, 1, 38,255, 97, 0,131, 1, 39,255,220, 0,131, 1, 54,255,144, 0,131, 1, 55,255,173, 0,131, 1, 56,
+255, 97, 0,131, 1, 57,255,117, 0,131, 1, 58,255, 97, 0,131, 1,240,255,220, 0,131, 1,241,255,220, 0,131, 4,252,255,144,
+ 0,131, 4,254,255,144, 0,131, 4,255,255,173, 0,131, 5, 0,255,144, 0,131, 5, 1,255,173, 0,131, 5,106,255, 97, 0,131,
+ 5,107,255,117, 0,131, 5,145,254,248, 0,131, 5,146,255, 3, 0,131, 5,147, 0, 47, 0,132, 0, 16,255,211, 0,132, 0, 17,
+255,220, 0,132, 0, 29,255,220, 0,132, 0, 36, 0, 57, 0,132, 0, 38,255,220, 0,132, 0, 42,255,220, 0,132, 0, 50,255,220,
+ 0,132, 0, 52,255,220, 0,132, 0, 55,255, 97, 0,132, 0, 57,255,125, 0,132, 0, 58,255,144, 0,132, 0, 60,255, 97, 0,132,
+ 0, 70,255,220, 0,132, 0, 71,255,220, 0,132, 0, 72,255,220, 0,132, 0, 73,255,183, 0,132, 0, 82,255,220, 0,132, 0, 84,
+255,220, 0,132, 0, 87,255,220, 0,132, 0, 89,255,136, 0,132, 0, 90,255,173, 0,132, 0, 92,255,117, 0,132, 0,109,255,183,
+ 0,132, 0,130, 0, 57, 0,132, 0,131, 0, 57, 0,132, 0,132, 0, 57, 0,132, 0,133, 0, 57, 0,132, 0,134, 0, 57, 0,132,
+ 0,137,255,220, 0,132, 0,148,255,220, 0,132, 0,149,255,220, 0,132, 0,150,255,220, 0,132, 0,151,255,220, 0,132, 0,152,
+255,220, 0,132, 0,159,255, 97, 0,132, 0,169,255,220, 0,132, 0,170,255,220, 0,132, 0,171,255,220, 0,132, 0,172,255,220,
+ 0,132, 0,173,255,220, 0,132, 0,180,255,220, 0,132, 0,181,255,220, 0,132, 0,182,255,220, 0,132, 0,183,255,220, 0,132,
+ 0,184,255,220, 0,132, 0,191,255,117, 0,132, 0,193,255,117, 0,132, 0,194, 0, 57, 0,132, 0,196, 0, 57, 0,132, 0,198,
+ 0, 57, 0,132, 0,200,255,220, 0,132, 0,201,255,220, 0,132, 0,202,255,220, 0,132, 0,204,255,220, 0,132, 0,205,255,220,
+ 0,132, 0,206,255,220, 0,132, 0,207,255,220, 0,132, 0,209,255,220, 0,132, 0,213,255,220, 0,132, 0,215,255,220, 0,132,
+ 0,217,255,220, 0,132, 0,219,255,220, 0,132, 0,221,255,220, 0,132, 0,222,255,220, 0,132, 0,224,255,220, 0,132, 0,226,
+255,220, 0,132, 1, 14,255,220, 0,132, 1, 15,255,220, 0,132, 1, 16,255,220, 0,132, 1, 17,255,220, 0,132, 1, 18,255,220,
+ 0,132, 1, 19,255,220, 0,132, 1, 36,255, 97, 0,132, 1, 37,255,220, 0,132, 1, 38,255, 97, 0,132, 1, 39,255,220, 0,132,
+ 1, 54,255,144, 0,132, 1, 55,255,173, 0,132, 1, 56,255, 97, 0,132, 1, 57,255,117, 0,132, 1, 58,255, 97, 0,132, 1,240,
+255,220, 0,132, 1,241,255,220, 0,132, 4,252,255,144, 0,132, 4,254,255,144, 0,132, 4,255,255,173, 0,132, 5, 0,255,144,
+ 0,132, 5, 1,255,173, 0,132, 5,106,255, 97, 0,132, 5,107,255,117, 0,132, 5,145,254,248, 0,132, 5,146,255, 3, 0,132,
+ 5,147, 0, 47, 0,133, 0, 16,255,211, 0,133, 0, 17,255,220, 0,133, 0, 29,255,220, 0,133, 0, 36, 0, 57, 0,133, 0, 38,
+255,220, 0,133, 0, 42,255,220, 0,133, 0, 50,255,220, 0,133, 0, 52,255,220, 0,133, 0, 55,255, 97, 0,133, 0, 57,255,125,
+ 0,133, 0, 58,255,144, 0,133, 0, 60,255, 97, 0,133, 0, 70,255,220, 0,133, 0, 71,255,220, 0,133, 0, 72,255,220, 0,133,
+ 0, 73,255,183, 0,133, 0, 82,255,220, 0,133, 0, 84,255,220, 0,133, 0, 87,255,220, 0,133, 0, 89,255,136, 0,133, 0, 90,
+255,173, 0,133, 0, 92,255,117, 0,133, 0,109,255,183, 0,133, 0,130, 0, 57, 0,133, 0,131, 0, 57, 0,133, 0,132, 0, 57,
+ 0,133, 0,133, 0, 57, 0,133, 0,134, 0, 57, 0,133, 0,137,255,220, 0,133, 0,148,255,220, 0,133, 0,149,255,220, 0,133,
+ 0,150,255,220, 0,133, 0,151,255,220, 0,133, 0,152,255,220, 0,133, 0,159,255, 97, 0,133, 0,169,255,220, 0,133, 0,170,
+255,220, 0,133, 0,171,255,220, 0,133, 0,172,255,220, 0,133, 0,173,255,220, 0,133, 0,180,255,220, 0,133, 0,181,255,220,
+ 0,133, 0,182,255,220, 0,133, 0,183,255,220, 0,133, 0,184,255,220, 0,133, 0,191,255,117, 0,133, 0,193,255,117, 0,133,
+ 0,194, 0, 57, 0,133, 0,196, 0, 57, 0,133, 0,198, 0, 57, 0,133, 0,200,255,220, 0,133, 0,201,255,220, 0,133, 0,202,
+255,220, 0,133, 0,204,255,220, 0,133, 0,205,255,220, 0,133, 0,206,255,220, 0,133, 0,207,255,220, 0,133, 0,209,255,220,
+ 0,133, 0,213,255,220, 0,133, 0,215,255,220, 0,133, 0,217,255,220, 0,133, 0,219,255,220, 0,133, 0,221,255,220, 0,133,
+ 0,222,255,220, 0,133, 0,224,255,220, 0,133, 0,226,255,220, 0,133, 1, 14,255,220, 0,133, 1, 15,255,220, 0,133, 1, 16,
+255,220, 0,133, 1, 17,255,220, 0,133, 1, 18,255,220, 0,133, 1, 19,255,220, 0,133, 1, 36,255, 97, 0,133, 1, 37,255,220,
+ 0,133, 1, 38,255, 97, 0,133, 1, 39,255,220, 0,133, 1, 54,255,144, 0,133, 1, 55,255,173, 0,133, 1, 56,255, 97, 0,133,
+ 1, 57,255,117, 0,133, 1, 58,255, 97, 0,133, 1,240,255,220, 0,133, 4,252,255,144, 0,133, 4,254,255,144, 0,133, 4,255,
+255,173, 0,133, 5, 0,255,144, 0,133, 5, 1,255,173, 0,133, 5,106,255, 97, 0,133, 5,107,255,117, 0,133, 5,145,254,248,
+ 0,133, 5,146,255, 3, 0,133, 5,147, 0, 47, 0,134, 0, 16,255,211, 0,134, 0, 17,255,220, 0,134, 0, 29,255,220, 0,134,
+ 0, 36, 0, 57, 0,134, 0, 38,255,220, 0,134, 0, 42,255,220, 0,134, 0, 50,255,220, 0,134, 0, 52,255,220, 0,134, 0, 55,
+255, 97, 0,134, 0, 57,255,125, 0,134, 0, 58,255,144, 0,134, 0, 60,255, 97, 0,134, 0, 70,255,220, 0,134, 0, 71,255,220,
+ 0,134, 0, 72,255,220, 0,134, 0, 73,255,183, 0,134, 0, 82,255,220, 0,134, 0, 84,255,220, 0,134, 0, 87,255,220, 0,134,
+ 0, 89,255,136, 0,134, 0, 90,255,173, 0,134, 0, 92,255,117, 0,134, 0,109,255,183, 0,134, 0,130, 0, 57, 0,134, 0,131,
+ 0, 57, 0,134, 0,132, 0, 57, 0,134, 0,133, 0, 57, 0,134, 0,134, 0, 57, 0,134, 0,137,255,220, 0,134, 0,148,255,220,
+ 0,134, 0,149,255,220, 0,134, 0,150,255,220, 0,134, 0,151,255,220, 0,134, 0,152,255,220, 0,134, 0,159,255, 97, 0,134,
+ 0,169,255,220, 0,134, 0,170,255,220, 0,134, 0,171,255,220, 0,134, 0,172,255,220, 0,134, 0,173,255,220, 0,134, 0,180,
+255,220, 0,134, 0,181,255,220, 0,134, 0,182,255,220, 0,134, 0,183,255,220, 0,134, 0,184,255,220, 0,134, 0,191,255,117,
+ 0,134, 0,193,255,117, 0,134, 0,194, 0, 57, 0,134, 0,196, 0, 57, 0,134, 0,198, 0, 57, 0,134, 0,200,255,220, 0,134,
+ 0,201,255,220, 0,134, 0,202,255,220, 0,134, 0,204,255,220, 0,134, 0,205,255,220, 0,134, 0,206,255,220, 0,134, 0,207,
+255,220, 0,134, 0,209,255,220, 0,134, 0,213,255,220, 0,134, 0,215,255,220, 0,134, 0,217,255,220, 0,134, 0,219,255,220,
+ 0,134, 0,221,255,220, 0,134, 0,222,255,220, 0,134, 0,224,255,220, 0,134, 0,226,255,220, 0,134, 1, 14,255,220, 0,134,
+ 1, 15,255,220, 0,134, 1, 16,255,220, 0,134, 1, 17,255,220, 0,134, 1, 18,255,220, 0,134, 1, 19,255,220, 0,134, 1, 36,
+255, 97, 0,134, 1, 37,255,220, 0,134, 1, 38,255, 97, 0,134, 1, 39,255,220, 0,134, 1, 54,255,144, 0,134, 1, 55,255,173,
+ 0,134, 1, 56,255, 97, 0,134, 1, 57,255,117, 0,134, 1, 58,255, 97, 0,134, 1,240,255,220, 0,134, 1,241,255,220, 0,134,
+ 4,252,255,144, 0,134, 4,254,255,144, 0,134, 4,255,255,173, 0,134, 5, 0,255,144, 0,134, 5, 1,255,173, 0,134, 5,106,
+255, 97, 0,134, 5,107,255,117, 0,134, 5,145,254,248, 0,134, 5,146,255, 3, 0,134, 5,147, 0, 47, 0,136, 5,145,255,173,
+ 0,136, 5,146,255,164, 0,136, 5,147,255,144, 0,137, 0, 60,255,220, 0,137, 0,109,255,220, 0,137, 0,125,255,220, 0,137,
+ 0,159,255,220, 0,137, 1, 58,255,220, 0,137, 5,146, 0, 38, 0,146, 0, 36,255,220, 0,146, 0, 57,255,220, 0,146, 0, 60,
+255,144, 0,146, 0,109,255,220, 0,146, 0,125,255,220, 0,146, 0,130,255,220, 0,146, 0,131,255,220, 0,146, 0,132,255,220,
+ 0,146, 0,133,255,220, 0,146, 0,134,255,220, 0,146, 0,159,255,144, 0,146, 0,194,255,220, 0,146, 0,196,255,220, 0,146,
+ 0,198,255,220, 0,146, 1, 56,255,144, 0,146, 1, 58,255,144, 0,146, 1,244,255,144, 0,146, 5,106,255,144, 0,146, 5,145,
+255,211, 0,146, 5,146,255,201, 0,146, 5,147,255, 68, 0,148, 0, 16, 0, 57, 0,148, 0, 17,255,173, 0,148, 0, 29,255,220,
+ 0,148, 0, 36,255,220, 0,148, 0, 57,255,220, 0,148, 0, 59,255,125, 0,148, 0, 60,255,144, 0,148, 0,109,255,220, 0,148,
+ 0,130,255,220, 0,148, 0,131,255,220, 0,148, 0,132,255,220, 0,148, 0,133,255,220, 0,148, 0,134,255,220, 0,148, 0,159,
+255,144, 0,148, 1, 58,255,144, 0,148, 5,145,255,211, 0,148, 5,146,255,220, 0,148, 5,147,255, 68, 0,149, 0, 16, 0, 57,
+ 0,149, 0, 17,255,173, 0,149, 0, 29,255,220, 0,149, 0, 36,255,220, 0,149, 0, 57,255,220, 0,149, 0, 59,255,125, 0,149,
+ 0, 60,255,144, 0,149, 0,109,255,220, 0,149, 0,130,255,220, 0,149, 0,131,255,220, 0,149, 0,132,255,220, 0,149, 0,133,
+255,220, 0,149, 0,134,255,220, 0,149, 0,159,255,144, 0,149, 1, 58,255,144, 0,149, 5,145,255,211, 0,149, 5,146,255,220,
+ 0,149, 5,147,255, 68, 0,150, 0, 16, 0, 57, 0,150, 0, 17,255,173, 0,150, 0, 29,255,220, 0,150, 0, 36,255,220, 0,150,
+ 0, 57,255,220, 0,150, 0, 59,255,125, 0,150, 0, 60,255,144, 0,150, 0,109,255,220, 0,150, 0,130,255,220, 0,150, 0,131,
+255,220, 0,150, 0,132,255,220, 0,150, 0,133,255,220, 0,150, 0,134,255,220, 0,150, 0,159,255,144, 0,150, 1, 58,255,144,
+ 0,150, 5,145,255,211, 0,150, 5,146,255,220, 0,150, 5,147,255, 68, 0,151, 0, 16, 0, 57, 0,151, 0, 17,255,173, 0,151,
+ 0, 29,255,220, 0,151, 0, 36,255,220, 0,151, 0, 57,255,220, 0,151, 0, 59,255,125, 0,151, 0, 60,255,144, 0,151, 0,109,
+255,220, 0,151, 0,130,255,220, 0,151, 0,131,255,220, 0,151, 0,132,255,220, 0,151, 0,133,255,220, 0,151, 0,134,255,220,
+ 0,151, 0,159,255,144, 0,151, 1, 58,255,144, 0,151, 5,145,255,211, 0,151, 5,146,255,220, 0,151, 5,147,255, 68, 0,152,
+ 0, 16, 0, 57, 0,152, 0, 17,255,173, 0,152, 0, 29,255,220, 0,152, 0, 36,255,220, 0,152, 0, 57,255,220, 0,152, 0, 59,
+255,125, 0,152, 0, 60,255,144, 0,152, 0,109,255,220, 0,152, 0,130,255,220, 0,152, 0,131,255,220, 0,152, 0,132,255,220,
+ 0,152, 0,133,255,220, 0,152, 0,134,255,220, 0,152, 0,159,255,144, 0,152, 1, 58,255,144, 0,152, 5,145,255,211, 0,152,
+ 5,146,255,220, 0,152, 5,147,255, 68, 0,155, 0, 61,255,220, 0,155, 1, 63,255,220, 0,156, 0, 61,255,220, 0,156, 1, 63,
+255,220, 0,157, 0, 61,255,220, 0,157, 1, 63,255,220, 0,158, 0, 61,255,220, 0,158, 1, 63,255,220, 0,159, 0, 16,255, 13,
+ 0,159, 0, 17,254, 97, 0,159, 0, 29,254,240, 0,159, 0, 36,255, 97, 0,159, 0, 38,255,144, 0,159, 0, 50,255,144, 0,159,
+ 0, 68,254,230, 0,159, 0, 72,254,240, 0,159, 0, 76,255,183, 0,159, 0, 82,254,240, 0,159, 0, 88,255, 21, 0,159, 0,109,
+255, 31, 0,159, 0,125,255,107, 0,159, 0,130,255, 97, 0,159, 0,131,255, 97, 0,159, 0,132,255, 97, 0,159, 0,133,255, 97,
+ 0,159, 0,134,255, 97, 0,159, 0,137,255,144, 0,159, 0,148,255,144, 0,159, 0,149,255,144, 0,159, 0,150,255,144, 0,159,
+ 0,151,255,144, 0,159, 0,152,255,144, 0,159, 0,162,254,230, 0,159, 0,163,254,230, 0,159, 0,164,254,230, 0,159, 0,165,
+254,230, 0,159, 0,166,254,230, 0,159, 0,167,254,230, 0,159, 0,170,254,240, 0,159, 0,171,254,240, 0,159, 0,172,254,240,
+ 0,159, 0,173,254,240, 0,159, 0,180,254,240, 0,159, 0,181,254,240, 0,159, 0,182,254,240, 0,159, 0,183,254,240, 0,159,
+ 0,184,254,240, 0,159, 0,187,255, 21, 0,159, 0,188,255, 21, 0,159, 0,189,255, 21, 0,159, 0,190,255, 21, 0,159, 0,200,
+255,144, 0,159, 0,206,255,144, 0,159, 0,221,254,240, 0,159, 1, 49,255, 21, 0,159, 5,145,255,144, 0,159, 5,146,255,220,
+ 0,159, 5,147,254,248, 0,160, 0, 17,255,107, 0,160, 0, 29,255,183, 0,160, 5,145,255,220, 0,160, 5,147,255, 68, 0,161,
+ 0, 16, 0, 38, 0,161, 5,145,255,144, 0,161, 5,146,255,144, 0,161, 5,147,255,173, 0,170, 0, 91,255,220, 0,171, 0, 91,
+255,220, 0,172, 0, 91,255,220, 0,173, 0, 91,255,220, 0,178, 5,145,255,164, 0,178, 5,146,255,144, 0,178, 5,147,255,183,
+ 0,179, 5,145,255,107, 0,179, 5,146,255,144, 0,179, 5,147,255,164, 0,180, 0, 16, 0, 38, 0,180, 0, 17,255,220, 0,180,
+ 0, 91,255,193, 0,180, 5,145,255,107, 0,180, 5,146,255,183, 0,180, 5,147,255,125, 0,181, 0, 16, 0, 38, 0,181, 0, 17,
+255,220, 0,181, 0, 91,255,193, 0,181, 5,145,255,107, 0,181, 5,146,255,183, 0,181, 5,147,255,125, 0,182, 0, 16, 0, 38,
+ 0,182, 0, 17,255,220, 0,182, 0, 91,255,193, 0,182, 5,145,255,107, 0,182, 5,146,255,183, 0,182, 5,147,255,125, 0,183,
+ 0, 16, 0, 38, 0,183, 0, 17,255,220, 0,183, 0, 91,255,193, 0,183, 5,145,255,107, 0,183, 5,146,255,183, 0,183, 5,147,
+255,125, 0,184, 0, 16, 0, 38, 0,184, 0, 17,255,220, 0,184, 0, 91,255,193, 0,184, 5,145,255,107, 0,184, 5,146,255,183,
+ 0,184, 5,147,255,125, 0,191, 0, 16,255,220, 0,191, 0, 17,254,220, 0,191, 0, 29,255,107, 0,191, 0,109,255,220, 0,191,
+ 0,125,255,220, 0,191, 5,147,254,211, 0,193, 0, 16,255,220, 0,193, 0, 17,254,220, 0,193, 0, 29,255,107, 0,193, 0,109,
+255,220, 0,193, 0,125,255,220, 0,193, 5,147,254,211, 0,194, 0, 16,255,211, 0,194, 0, 17,255,220, 0,194, 0, 29,255,220,
+ 0,194, 0, 36, 0, 57, 0,194, 0, 38,255,220, 0,194, 0, 42,255,220, 0,194, 0, 50,255,220, 0,194, 0, 52,255,220, 0,194,
+ 0, 55,255, 97, 0,194, 0, 57,255,125, 0,194, 0, 58,255,144, 0,194, 0, 60,255, 97, 0,194, 0, 70,255,220, 0,194, 0, 71,
+255,220, 0,194, 0, 72,255,220, 0,194, 0, 73,255,183, 0,194, 0, 82,255,220, 0,194, 0, 84,255,220, 0,194, 0, 87,255,220,
+ 0,194, 0, 89,255,136, 0,194, 0, 90,255,173, 0,194, 0, 92,255,117, 0,194, 0,109,255,183, 0,194, 0,130, 0, 57, 0,194,
+ 0,131, 0, 57, 0,194, 0,132, 0, 57, 0,194, 0,133, 0, 57, 0,194, 0,134, 0, 57, 0,194, 0,148,255,220, 0,194, 0,149,
+255,220, 0,194, 0,150,255,220, 0,194, 0,151,255,220, 0,194, 0,152,255,220, 0,194, 0,159,255, 97, 0,194, 0,169,255,220,
+ 0,194, 0,170,255,220, 0,194, 0,171,255,220, 0,194, 0,172,255,220, 0,194, 0,173,255,220, 0,194, 0,180,255,220, 0,194,
+ 0,181,255,220, 0,194, 0,182,255,220, 0,194, 0,183,255,220, 0,194, 0,184,255,220, 0,194, 0,191,255,117, 0,194, 0,193,
+255,117, 0,194, 0,194, 0, 57, 0,194, 0,196, 0, 57, 0,194, 0,198, 0, 57, 0,194, 0,200,255,220, 0,194, 0,202,255,220,
+ 0,194, 0,204,255,220, 0,194, 0,205,255,220, 0,194, 0,206,255,220, 0,194, 0,209,255,220, 0,194, 0,211,255,220, 0,194,
+ 0,213,255,220, 0,194, 0,215,255,220, 0,194, 0,217,255,220, 0,194, 0,219,255,220, 0,194, 0,221,255,220, 0,194, 0,222,
+255,220, 0,194, 0,226,255,220, 0,194, 1, 14,255,220, 0,194, 1, 15,255,220, 0,194, 1, 16,255,220, 0,194, 1, 17,255,220,
+ 0,194, 1, 18,255,220, 0,194, 1, 19,255,220, 0,194, 1, 36,255, 97, 0,194, 1, 37,255,220, 0,194, 1, 38,255, 97, 0,194,
+ 1, 39,255,220, 0,194, 1, 54,255,144, 0,194, 1, 55,255,173, 0,194, 1, 56,255, 97, 0,194, 1, 57,255,117, 0,194, 1, 58,
+255, 97, 0,194, 1,240,255,220, 0,194, 1,241,255,220, 0,194, 4,252,255,144, 0,194, 4,254,255,144, 0,194, 4,255,255,173,
+ 0,194, 5, 0,255,144, 0,194, 5, 1,255,173, 0,194, 5,106,255, 97, 0,194, 5,107,255,117, 0,194, 5,145,254,248, 0,194,
+ 5,146,255, 2, 0,194, 5,147, 0, 47, 0,196, 0, 16,255,211, 0,196, 0, 17,255,220, 0,196, 0, 29,255,220, 0,196, 0, 36,
+ 0, 57, 0,196, 0, 38,255,220, 0,196, 0, 42,255,220, 0,196, 0, 50,255,220, 0,196, 0, 52,255,220, 0,196, 0, 55,255, 97,
+ 0,196, 0, 57,255,125, 0,196, 0, 58,255,144, 0,196, 0, 60,255, 97, 0,196, 0, 70,255,220, 0,196, 0, 71,255,220, 0,196,
+ 0, 72,255,220, 0,196, 0, 73,255,183, 0,196, 0, 82,255,220, 0,196, 0, 84,255,220, 0,196, 0, 87,255,220, 0,196, 0, 89,
+255,136, 0,196, 0, 90,255,173, 0,196, 0, 92,255,117, 0,196, 0,109,255,183, 0,196, 0,130, 0, 57, 0,196, 0,131, 0, 57,
+ 0,196, 0,132, 0, 57, 0,196, 0,133, 0, 57, 0,196, 0,134, 0, 57, 0,196, 0,148,255,220, 0,196, 0,149,255,220, 0,196,
+ 0,150,255,220, 0,196, 0,151,255,220, 0,196, 0,152,255,220, 0,196, 0,159,255, 97, 0,196, 0,169,255,220, 0,196, 0,170,
+255,220, 0,196, 0,171,255,220, 0,196, 0,172,255,220, 0,196, 0,173,255,220, 0,196, 0,180,255,220, 0,196, 0,181,255,220,
+ 0,196, 0,182,255,220, 0,196, 0,183,255,220, 0,196, 0,184,255,220, 0,196, 0,191,255,117, 0,196, 0,193,255,117, 0,196,
+ 0,194, 0, 57, 0,196, 0,196, 0, 57, 0,196, 0,198, 0, 57, 0,196, 0,200,255,220, 0,196, 0,202,255,220, 0,196, 0,204,
+255,220, 0,196, 0,205,255,220, 0,196, 0,206,255,220, 0,196, 0,209,255,220, 0,196, 0,211,255,220, 0,196, 0,213,255,220,
+ 0,196, 0,215,255,220, 0,196, 0,217,255,220, 0,196, 0,219,255,220, 0,196, 0,221,255,220, 0,196, 0,222,255,220, 0,196,
+ 0,226,255,220, 0,196, 1, 14,255,220, 0,196, 1, 15,255,220, 0,196, 1, 16,255,220, 0,196, 1, 17,255,220, 0,196, 1, 18,
+255,220, 0,196, 1, 19,255,220, 0,196, 1, 36,255, 97, 0,196, 1, 37,255,220, 0,196, 1, 38,255, 97, 0,196, 1, 39,255,220,
+ 0,196, 1, 54,255,144, 0,196, 1, 55,255,173, 0,196, 1, 56,255, 97, 0,196, 1, 57,255,117, 0,196, 1, 58,255, 97, 0,196,
+ 1,240,255,220, 0,196, 1,241,255,220, 0,196, 4,252,255,144, 0,196, 4,254,255,144, 0,196, 4,255,255,173, 0,196, 5, 0,
+255,144, 0,196, 5, 1,255,173, 0,196, 5,106,255, 97, 0,196, 5,107,255,117, 0,196, 5,145,254,248, 0,196, 5,146,255, 2,
+ 0,196, 5,147, 0, 47, 0,198, 0, 16,255,211, 0,198, 0, 17,255,220, 0,198, 0, 29,255,220, 0,198, 0, 36, 0, 57, 0,198,
+ 0, 38,255,220, 0,198, 0, 42,255,220, 0,198, 0, 50,255,220, 0,198, 0, 52,255,220, 0,198, 0, 55,255, 97, 0,198, 0, 57,
+255,125, 0,198, 0, 58,255,144, 0,198, 0, 60,255, 97, 0,198, 0, 70,255,220, 0,198, 0, 71,255,220, 0,198, 0, 72,255,220,
+ 0,198, 0, 73,255,183, 0,198, 0, 82,255,220, 0,198, 0, 84,255,220, 0,198, 0, 87,255,220, 0,198, 0, 89,255,136, 0,198,
+ 0, 90,255,173, 0,198, 0,109,255,183, 0,198, 0,130, 0, 57, 0,198, 0,131, 0, 57, 0,198, 0,132, 0, 57, 0,198, 0,133,
+ 0, 57, 0,198, 0,134, 0, 57, 0,198, 0,148,255,220, 0,198, 0,149,255,220, 0,198, 0,150,255,220, 0,198, 0,151,255,220,
+ 0,198, 0,152,255,220, 0,198, 0,159,255, 97, 0,198, 0,169,255,220, 0,198, 0,170,255,220, 0,198, 0,171,255,220, 0,198,
+ 0,172,255,220, 0,198, 0,173,255,220, 0,198, 0,180,255,220, 0,198, 0,181,255,220, 0,198, 0,182,255,220, 0,198, 0,183,
+255,220, 0,198, 0,184,255,220, 0,198, 0,194, 0, 57, 0,198, 0,196, 0, 57, 0,198, 0,198, 0, 57, 0,198, 0,200,255,220,
+ 0,198, 0,202,255,220, 0,198, 0,204,255,220, 0,198, 0,205,255,220, 0,198, 0,206,255,220, 0,198, 0,209,255,220, 0,198,
+ 0,211,255,220, 0,198, 0,213,255,220, 0,198, 0,215,255,220, 0,198, 0,217,255,220, 0,198, 0,219,255,220, 0,198, 0,221,
+255,220, 0,198, 0,222,255,220, 0,198, 0,226,255,220, 0,198, 1, 14,255,220, 0,198, 1, 15,255,220, 0,198, 1, 16,255,220,
+ 0,198, 1, 17,255,220, 0,198, 1, 19,255,220, 0,198, 1, 36,255, 97, 0,198, 1, 37,255,220, 0,198, 1, 38,255, 97, 0,198,
+ 1, 39,255,220, 0,198, 1, 54,255,144, 0,198, 1, 55,255,173, 0,198, 1, 56,255, 97, 0,198, 1, 58,255, 97, 0,198, 1,240,
+255,220, 0,198, 1,241,255,220, 0,198, 4,252,255,144, 0,198, 4,254,255,144, 0,198, 4,255,255,173, 0,198, 5, 0,255,144,
+ 0,198, 5, 1,255,173, 0,198, 5,106,255, 97, 0,198, 5,145,254,248, 0,198, 5,146,255, 2, 0,198, 5,147, 0, 47, 0,200,
+ 0, 60,255,220, 0,200, 0,109,255,220, 0,200, 0,125,255,220, 0,200, 0,159,255,220, 0,200, 1, 58,255,220, 0,200, 5,146,
+ 0, 38, 0,206, 0, 60,255,220, 0,206, 0,109,255,220, 0,206, 0,125,255,220, 0,206, 0,159,255,220, 0,206, 1, 58,255,220,
+ 0,206, 5,146, 0, 38, 0,208, 0, 36,255,220, 0,208, 0, 57,255,220, 0,208, 0, 60,255,144, 0,208, 0,109,255,220, 0,208,
+ 0,125,255,220, 0,208, 0,130,255,220, 0,208, 0,131,255,220, 0,208, 0,132,255,220, 0,208, 0,133,255,220, 0,208, 0,134,
+255,220, 0,208, 0,159,255,144, 0,208, 0,194,255,220, 0,208, 0,196,255,220, 0,208, 0,198,255,220, 0,208, 1, 56,255,144,
+ 0,208, 1, 58,255,144, 0,208, 1,244,255,144, 0,208, 5,106,255,144, 0,208, 5,145,255,211, 0,208, 5,146,255,201, 0,208,
+ 5,147,255, 68, 0,210, 0, 36,255,220, 0,210, 0, 57,255,220, 0,210, 0, 60,255,144, 0,210, 0,109,255,220, 0,210, 0,125,
+255,220, 0,210, 0,130,255,220, 0,210, 0,131,255,220, 0,210, 0,132,255,220, 0,210, 0,133,255,220, 0,210, 0,134,255,220,
+ 0,210, 0,159,255,144, 0,210, 1, 58,255,144, 0,210, 5,145,255,211, 0,210, 5,146,255,201, 0,210, 5,147,255, 68, 0,221,
+ 0, 91,255,220, 0,224, 0, 55,255,183, 0,224, 0, 60,255,154, 0,224, 0,109,255,220, 0,224, 0,125,255,220, 0,224, 0,159,
+255,154, 0,224, 1, 38,255,183, 0,224, 1, 58,255,154, 0,224, 5,145,255,211, 0,224, 5,146,255,211, 0,224, 5,147,255,201,
+ 0,251, 0, 16,255,220, 0,251, 0, 36, 0, 47, 0,251, 0, 50,255,183, 0,251, 0, 55,254,230, 0,251, 0, 56,255,154, 0,251,
+ 0, 57,255, 31, 0,251, 0, 58,255, 68, 0,251, 0, 60,254,240, 0,251, 0, 72,255,220, 0,251, 0, 82,255,220, 0,251, 0, 88,
+255,220, 0,251, 0, 92,255, 68, 0,251, 0,130, 0, 47, 0,251, 0,131, 0, 47, 0,251, 0,132, 0, 47, 0,251, 0,133, 0, 47,
+ 0,251, 0,134, 0, 47, 0,251, 0,148,255,183, 0,251, 0,149,255,183, 0,251, 0,150,255,183, 0,251, 0,151,255,183, 0,251,
+ 0,152,255,183, 0,251, 0,155,255,154, 0,251, 0,156,255,154, 0,251, 0,157,255,154, 0,251, 0,158,255,154, 0,251, 0,159,
+254,240, 0,251, 0,170,255,220, 0,251, 0,171,255,220, 0,251, 0,172,255,220, 0,251, 0,173,255,220, 0,251, 0,180,255,220,
+ 0,251, 0,181,255,220, 0,251, 0,182,255,220, 0,251, 0,183,255,220, 0,251, 0,184,255,220, 0,251, 0,187,255,220, 0,251,
+ 0,188,255,220, 0,251, 0,189,255,220, 0,251, 0,190,255,220, 0,251, 0,191,255, 68, 0,251, 0,193,255, 68, 0,251, 0,221,
+255,220, 0,251, 1, 38,254,230, 0,251, 1, 48,255,154, 0,251, 1, 49,255,220, 0,251, 1, 58,254,240, 0,251, 5,145,254, 97,
+ 0,251, 5,146,253,230, 0,255, 0, 16,255,220, 0,255, 0, 36, 0, 47, 0,255, 0, 50,255,183, 0,255, 0, 55,254,230, 0,255,
+ 0, 56,255,154, 0,255, 0, 57,255, 31, 0,255, 0, 58,255, 68, 0,255, 0, 60,254,240, 0,255, 0, 72,255,220, 0,255, 0, 82,
+255,220, 0,255, 0, 88,255,220, 0,255, 0, 92,255, 68, 0,255, 0,130, 0, 47, 0,255, 0,131, 0, 47, 0,255, 0,132, 0, 47,
+ 0,255, 0,133, 0, 47, 0,255, 0,134, 0, 47, 0,255, 0,148,255,183, 0,255, 0,149,255,183, 0,255, 0,150,255,183, 0,255,
+ 0,151,255,183, 0,255, 0,152,255,183, 0,255, 0,155,255,154, 0,255, 0,156,255,154, 0,255, 0,157,255,154, 0,255, 0,158,
+255,154, 0,255, 0,159,254,240, 0,255, 0,170,255,220, 0,255, 0,171,255,220, 0,255, 0,172,255,220, 0,255, 0,173,255,220,
+ 0,255, 0,180,255,220, 0,255, 0,181,255,220, 0,255, 0,182,255,220, 0,255, 0,183,255,220, 0,255, 0,184,255,220, 0,255,
+ 0,187,255,220, 0,255, 0,188,255,220, 0,255, 0,189,255,220, 0,255, 0,190,255,220, 0,255, 0,191,255, 68, 0,255, 0,193,
+255, 68, 0,255, 0,221,255,220, 0,255, 1, 38,254,230, 0,255, 1, 48,255,154, 0,255, 1, 49,255,220, 0,255, 1, 58,254,240,
+ 0,255, 5,145,254, 97, 0,255, 5,146,253,230, 1, 2, 0, 79,255, 63, 1, 10, 5,145,255,107, 1, 10, 5,146,255,144, 1, 10,
+ 5,147,255,164, 1, 22, 0, 16,255,173, 1, 22, 0, 17,255,183, 1, 22, 0, 29,255,193, 1, 22, 0, 36,255,173, 1, 22, 0, 38,
+255,154, 1, 22, 0, 55,255,107, 1, 22, 0, 57,255,144, 1, 22, 0, 58,255,173, 1, 22, 0, 60,255,125, 1, 22, 0, 68,255,211,
+ 1, 22, 0, 72,255,164, 1, 22, 0, 82,255,164, 1, 22, 0, 88,255,164, 1, 22, 0, 92,255,144, 1, 22, 0,109,255,144, 1, 22,
+ 0,125,255,220, 1, 22, 0,130,255,173, 1, 22, 0,131,255,173, 1, 22, 0,132,255,173, 1, 22, 0,133,255,173, 1, 22, 0,134,
+255,173, 1, 22, 0,137,255,154, 1, 22, 0,159,255,125, 1, 22, 0,162,255,211, 1, 22, 0,163,255,211, 1, 22, 0,164,255,211,
+ 1, 22, 0,165,255,211, 1, 22, 0,166,255,211, 1, 22, 0,167,255,211, 1, 22, 0,170,255,164, 1, 22, 0,171,255,164, 1, 22,
+ 0,172,255,164, 1, 22, 0,173,255,164, 1, 22, 0,180,255,164, 1, 22, 0,181,255,164, 1, 22, 0,182,255,164, 1, 22, 0,183,
+255,164, 1, 22, 0,184,255,164, 1, 22, 0,187,255,164, 1, 22, 0,188,255,164, 1, 22, 0,189,255,164, 1, 22, 0,190,255,164,
+ 1, 22, 0,191,255,144, 1, 22, 0,193,255,144, 1, 22, 0,200,255,154, 1, 22, 0,206,255,154, 1, 22, 0,221,255,164, 1, 22,
+ 1, 38,255,107, 1, 22, 1, 49,255,164, 1, 22, 1, 58,255,125, 1, 22, 5,145,255,107, 1, 22, 5,146,255,125, 1, 22, 5,147,
+255,220, 1, 23, 0, 16,255,125, 1, 23, 0, 17,255, 68, 1, 23, 0, 29,255,220, 1, 23, 0, 70,255,211, 1, 23, 0, 71,255,220,
+ 1, 23, 0, 72,255,211, 1, 23, 0, 74,255,220, 1, 23, 0, 75,255,220, 1, 23, 0, 80,255,220, 1, 23, 0, 81,255,220, 1, 23,
+ 0, 82,255,211, 1, 23, 0, 84,255,220, 1, 23, 0, 85,255,220, 1, 23, 0, 91,255,201, 1, 23, 0,109,255,183, 1, 23, 0,169,
+255,211, 1, 23, 0,170,255,211, 1, 23, 0,171,255,211, 1, 23, 0,172,255,211, 1, 23, 0,173,255,211, 1, 23, 0,179,255,220,
+ 1, 23, 0,180,255,211, 1, 23, 0,181,255,211, 1, 23, 0,182,255,211, 1, 23, 0,183,255,211, 1, 23, 0,184,255,211, 1, 23,
+ 0,201,255,211, 1, 23, 0,207,255,211, 1, 23, 0,209, 0, 72, 1, 23, 0,221,255,211, 1, 23, 0,225,255,220, 1, 23, 1, 10,
+255,220, 1, 23, 1, 23,255,220, 1, 23, 1, 27,255,220, 1, 23, 5,146, 0, 86, 1, 23, 5,147,254,201, 1, 26, 0, 16,255,173,
+ 1, 26, 0, 17,255,183, 1, 26, 0, 29,255,193, 1, 26, 0, 36,255,173, 1, 26, 0, 38,255,154, 1, 26, 0, 55,255,107, 1, 26,
+ 0, 57,255,144, 1, 26, 0, 58,255,173, 1, 26, 0, 60,255,125, 1, 26, 0, 68,255,211, 1, 26, 0, 72,255,164, 1, 26, 0, 82,
+255,164, 1, 26, 0, 88,255,164, 1, 26, 0, 92,255,144, 1, 26, 0,109,255,144, 1, 26, 0,125,255,220, 1, 26, 0,130,255,173,
+ 1, 26, 0,131,255,173, 1, 26, 0,132,255,173, 1, 26, 0,133,255,173, 1, 26, 0,134,255,173, 1, 26, 0,137,255,154, 1, 26,
+ 0,159,255,125, 1, 26, 0,162,255,211, 1, 26, 0,163,255,211, 1, 26, 0,164,255,211, 1, 26, 0,165,255,211, 1, 26, 0,166,
+255,211, 1, 26, 0,167,255,211, 1, 26, 0,170,255,164, 1, 26, 0,171,255,164, 1, 26, 0,172,255,164, 1, 26, 0,173,255,164,
+ 1, 26, 0,180,255,164, 1, 26, 0,181,255,164, 1, 26, 0,182,255,164, 1, 26, 0,183,255,164, 1, 26, 0,184,255,164, 1, 26,
+ 0,187,255,164, 1, 26, 0,188,255,164, 1, 26, 0,189,255,164, 1, 26, 0,190,255,164, 1, 26, 0,191,255,144, 1, 26, 0,193,
+255,144, 1, 26, 0,200,255,154, 1, 26, 0,206,255,154, 1, 26, 0,221,255,164, 1, 26, 1, 38,255,107, 1, 26, 1, 49,255,164,
+ 1, 26, 1, 58,255,125, 1, 26, 5,145,255,107, 1, 26, 5,146,255,125, 1, 26, 5,147,255,220, 1, 27, 0, 16,255,125, 1, 27,
+ 0, 17,255, 68, 1, 27, 0, 29,255,220, 1, 27, 0, 70,255,211, 1, 27, 0, 71,255,220, 1, 27, 0, 72,255,211, 1, 27, 0, 74,
+255,220, 1, 27, 0, 75,255,220, 1, 27, 0, 80,255,220, 1, 27, 0, 81,255,220, 1, 27, 0, 82,255,211, 1, 27, 0, 84,255,220,
+ 1, 27, 0, 85,255,220, 1, 27, 0, 91,255,201, 1, 27, 0,109,255,183, 1, 27, 0,169,255,211, 1, 27, 0,170,255,211, 1, 27,
+ 0,171,255,211, 1, 27, 0,172,255,211, 1, 27, 0,173,255,211, 1, 27, 0,179,255,220, 1, 27, 0,180,255,211, 1, 27, 0,181,
+255,211, 1, 27, 0,182,255,211, 1, 27, 0,183,255,211, 1, 27, 0,184,255,211, 1, 27, 0,201,255,211, 1, 27, 0,207,255,211,
+ 1, 27, 0,209,255,220, 1, 27, 0,221,255,211, 1, 27, 0,225,255,220, 1, 27, 1, 10,255,220, 1, 27, 1, 23,255,220, 1, 27,
+ 1, 27,255,220, 1, 27, 5,146, 0, 86, 1, 27, 5,147,254,201, 1, 32, 0, 36, 0, 38, 1, 32, 0,130, 0, 38, 1, 32, 0,131,
+ 0, 38, 1, 32, 0,132, 0, 38, 1, 32, 0,133, 0, 38, 1, 32, 0,134, 0, 38, 1, 34, 0, 36, 0, 38, 1, 34, 0,130, 0, 38,
+ 1, 34, 0,131, 0, 38, 1, 34, 0,132, 0, 38, 1, 34, 0,133, 0, 38, 1, 34, 0,134, 0, 38, 1, 38, 0, 16,255, 68, 1, 38,
+ 0, 17,255, 13, 1, 38, 0, 29,255, 31, 1, 38, 0, 36,255, 97, 1, 38, 0, 38,255,136, 1, 38, 0, 55,255,220, 1, 38, 0, 68,
+254,173, 1, 38, 0, 70,254,164, 1, 38, 0, 72,254,164, 1, 38, 0, 76,255,193, 1, 38, 0, 82,254,164, 1, 38, 0, 85,254,211,
+ 1, 38, 0, 86,254,173, 1, 38, 0, 88,254,201, 1, 38, 0, 90,254,173, 1, 38, 0, 92,254,193, 1, 38, 0,109,255, 68, 1, 38,
+ 0,125,255,144, 1, 38, 0,130,255, 97, 1, 38, 0,131,255, 97, 1, 38, 0,132,255, 97, 1, 38, 0,133,255, 97, 1, 38, 0,134,
+255, 97, 1, 38, 0,137,255,136, 1, 38, 0,162,254,173, 1, 38, 0,163,254,173, 1, 38, 0,164,254,173, 1, 38, 0,165,254,173,
+ 1, 38, 0,166,254,173, 1, 38, 0,167,254,173, 1, 38, 0,169,254,164, 1, 38, 0,170,254,164, 1, 38, 0,171,254,164, 1, 38,
+ 0,172,254,164, 1, 38, 0,173,254,164, 1, 38, 0,180,254,164, 1, 38, 0,181,254,164, 1, 38, 0,182,254,164, 1, 38, 0,183,
+254,164, 1, 38, 0,184,254,164, 1, 38, 0,187,254,201, 1, 38, 0,188,254,201, 1, 38, 0,189,254,201, 1, 38, 0,190,254,201,
+ 1, 38, 0,191,254,193, 1, 38, 0,193,254,193, 1, 38, 0,200,255,136, 1, 38, 0,201,254,164, 1, 38, 0,206,255,136, 1, 38,
+ 0,207,254,164, 1, 38, 0,221,254,164, 1, 38, 1, 23,254,211, 1, 38, 1, 27,254,211, 1, 38, 1, 33,254,173, 1, 38, 1, 35,
+254,173, 1, 38, 1, 38,255,220, 1, 38, 1, 49,254,201, 1, 38, 5,146,255,211, 1, 38, 5,147,254,248, 1, 48, 0, 61,255,220,
+ 1, 48, 1, 63,255,220, 1, 58, 0, 16,255, 13, 1, 58, 0, 17,254, 97, 1, 58, 0, 29,254,240, 1, 58, 0, 36,255, 97, 1, 58,
+ 0, 38,255,144, 1, 58, 0, 50,255,144, 1, 58, 0, 68,254,230, 1, 58, 0, 72,254,240, 1, 58, 0, 76,255,183, 1, 58, 0, 82,
+254,240, 1, 58, 0, 88,255, 21, 1, 58, 0,109,255, 31, 1, 58, 0,125,255,107, 1, 58, 0,130,255, 97, 1, 58, 0,131,255, 97,
+ 1, 58, 0,132,255, 97, 1, 58, 0,133,255, 97, 1, 58, 0,134,255, 97, 1, 58, 0,137,255,144, 1, 58, 0,148,255,144, 1, 58,
+ 0,149,255,144, 1, 58, 0,150,255,144, 1, 58, 0,151,255,144, 1, 58, 0,152,255,144, 1, 58, 0,162,254,230, 1, 58, 0,163,
+254,230, 1, 58, 0,164,254,230, 1, 58, 0,165,254,230, 1, 58, 0,166,254,230, 1, 58, 0,167,254,230, 1, 58, 0,170,254,240,
+ 1, 58, 0,171,254,240, 1, 58, 0,172,254,240, 1, 58, 0,173,254,240, 1, 58, 0,180,254,240, 1, 58, 0,181,254,240, 1, 58,
+ 0,182,254,240, 1, 58, 0,183,254,240, 1, 58, 0,184,254,240, 1, 58, 0,187,255, 21, 1, 58, 0,188,255, 21, 1, 58, 0,189,
+255, 21, 1, 58, 0,190,255, 21, 1, 58, 0,200,255,144, 1, 58, 0,206,255,144, 1, 58, 0,221,254,240, 1, 58, 1, 49,255, 21,
+ 1, 58, 5,145,255,144, 1, 58, 5,146,255,220, 1, 58, 5,147,254,248, 1, 63, 0, 16,255,220, 1, 63, 5,145,255,220, 1, 63,
+ 5,146,255,220, 1, 63, 5,147,255,220, 5,133, 0, 36,255,211, 5,133, 0, 37,255,183, 5,133, 0, 42, 0, 75, 5,133, 0, 45,
+ 0,114, 5,133, 0, 50, 0, 57, 5,133, 0, 52, 0, 75, 5,133, 0, 55,255, 68, 5,133, 0, 57,255,136, 5,133, 0, 58,255,173,
+ 5,133, 0, 59,255,154, 5,133, 0, 60,255, 13, 5,133, 0, 82, 0, 38, 5,133, 0, 89,255,201, 5,133, 0, 92,255,220, 5,133,
+ 0,130,255,211, 5,133, 0,131,255,211, 5,133, 0,132,255,211, 5,133, 0,133,255,211, 5,133, 0,134,255,211, 5,133, 0,148,
+ 0, 57, 5,133, 0,149, 0, 57, 5,133, 0,150, 0, 57, 5,133, 0,151, 0, 57, 5,133, 0,152, 0, 57, 5,133, 0,159,255, 13,
+ 5,133, 0,180, 0, 38, 5,133, 0,181, 0, 38, 5,133, 0,182, 0, 38, 5,133, 0,183, 0, 38, 5,133, 0,184, 0, 38, 5,133,
+ 0,191,255,220, 5,133, 0,193,255,220, 5,133, 0,224, 0, 75, 5,133, 1, 38,255, 68, 5,133, 1, 58,255, 13, 5,145, 0, 36,
+254,248, 5,145, 0, 37,255,193, 5,145, 0, 38,255,183, 5,145, 0, 39,255,193, 5,145, 0, 41,255,193, 5,145, 0, 42,255,183,
+ 5,145, 0, 43,255,193, 5,145, 0, 45,255,193, 5,145, 0, 46,255,193, 5,145, 0, 47,255,193, 5,145, 0, 50,255,183, 5,145,
+ 0, 51,255,193, 5,145, 0, 52,255,183, 5,145, 0, 53,255,193, 5,145, 0, 59,255,136, 5,145, 0, 61,255,220, 5,145, 0, 73,
+255,183, 5,145, 0, 81,255,144, 5,145, 0, 82,255,107, 5,145, 0, 85,255,144, 5,145, 0, 89,255,183, 5,145, 0, 90,255,183,
+ 5,145, 0, 92,255,183, 5,145, 0,130,254,248, 5,145, 0,131,254,248, 5,145, 0,132,254,248, 5,145, 0,133,254,248, 5,145,
+ 0,134,254,248, 5,145, 0,136,254,125, 5,145, 0,137,255,183, 5,145, 0,148,255,183, 5,145, 0,149,255,183, 5,145, 0,150,
+255,183, 5,145, 0,151,255,183, 5,145, 0,152,255,183, 5,145, 0,160,255,193, 5,145, 0,161,255,193, 5,145, 0,178,255,183,
+ 5,145, 0,179,255,144, 5,145, 0,180,255,107, 5,145, 0,181,255,107, 5,145, 0,182,255,107, 5,145, 0,183,255,107, 5,145,
+ 0,184,255,107, 5,145, 0,191,255,183, 5,145, 0,193,255,183, 5,145, 0,200,255,183, 5,145, 0,206,255,183, 5,145, 0,208,
+255,193, 5,145, 0,224,255,183, 5,145, 0,251,255,193, 5,145, 0,255,255,193, 5,145, 1, 10,255,144, 5,145, 1, 22,255,193,
+ 5,145, 1, 23,255,144, 5,145, 1, 26,255,193, 5,145, 1, 27,255,144, 5,145, 1, 63,255,220, 5,147, 0, 36, 0, 38, 5,147,
+ 0, 37,255,183, 5,147, 0, 38,255,144, 5,147, 0, 39,255,183, 5,147, 0, 41,255,183, 5,147, 0, 42,255,183, 5,147, 0, 43,
+255,183, 5,147, 0, 45, 0, 47, 5,147, 0, 46,255,183, 5,147, 0, 47,255,183, 5,147, 0, 50,255,144, 5,147, 0, 51,255,183,
+ 5,147, 0, 52,255,144, 5,147, 0, 53,255,183, 5,147, 0, 55,254,230, 5,147, 0, 57,254,136, 5,147, 0, 58,255, 3, 5,147,
+ 0, 59,255,183, 5,147, 0, 60,254,136, 5,147, 0, 73,255,220, 5,147, 0, 81,255,183, 5,147, 0, 82,255,183, 5,147, 0, 85,
+255,183, 5,147, 0, 89,255, 21, 5,147, 0, 90,255, 60, 5,147, 0, 92,255,144, 5,147, 0,130, 0, 38, 5,147, 0,131, 0, 38,
+ 5,147, 0,132, 0, 38, 5,147, 0,133, 0, 38, 5,147, 0,134, 0, 38, 5,147, 0,136, 0, 38, 5,147, 0,137,255,144, 5,147,
+ 0,148,255,144, 5,147, 0,149,255,144, 5,147, 0,150,255,144, 5,147, 0,151,255,144, 5,147, 0,152,255,144, 5,147, 0,159,
+254,136, 5,147, 0,160,255,183, 5,147, 0,161,255,183, 5,147, 0,178,255,183, 5,147, 0,179,255,183, 5,147, 0,180,255,183,
+ 5,147, 0,181,255,183, 5,147, 0,182,255,183, 5,147, 0,183,255,183, 5,147, 0,184,255,183, 5,147, 0,191,255,144, 5,147,
+ 0,193,255,144, 5,147, 0,200,255,144, 5,147, 0,206,255,144, 5,147, 0,208,255,183, 5,147, 0,224,255,183, 5,147, 0,251,
+255,183, 5,147, 0,255,255,183, 5,147, 1, 10,255,183, 5,147, 1, 22,255,183, 5,147, 1, 23,255,183, 5,147, 1, 26,255,183,
+ 5,147, 1, 27,255,183, 5,147, 1, 38,254,230, 5,147, 1, 58,254,136, 0, 0, 0, 0, 0, 61, 2,226, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0,152, 1, 50, 0, 1, 0, 0, 0, 0, 0, 1, 0, 11, 1,227, 0, 1, 0, 0, 0, 0, 0, 2, 0, 4, 1,249, 0, 1,
+ 0, 0, 0, 0, 0, 3, 0, 11, 2, 22, 0, 1, 0, 0, 0, 0, 0, 4, 0, 11, 2, 58, 0, 1, 0, 0, 0, 0, 0, 5, 0, 11,
+ 2, 94, 0, 1, 0, 0, 0, 0, 0, 6, 0, 10, 2,128, 0, 1, 0, 0, 0, 0, 0, 8, 0, 17, 2,175, 0, 1, 0, 0, 0, 0,
+ 0, 11, 0, 29, 2,253, 0, 1, 0, 0, 0, 0, 0, 13, 18,157, 40, 87, 0, 1, 0, 0, 0, 0, 0, 14, 0, 52, 59, 95, 0, 1,
+ 0, 0, 0, 0, 1, 0, 0, 24, 59,148, 0, 1, 0, 0, 0, 0, 1, 1, 0, 9, 60, 27, 0, 1, 0, 0, 0, 0, 1, 2, 0, 18,
+ 60, 76, 0, 1, 0, 0, 0, 0, 1, 3, 0, 9, 60,139, 0, 1, 0, 0, 0, 0, 1, 4, 0, 17, 60,167, 0, 1, 0, 0, 0, 0,
+ 1, 5, 0, 16, 61, 22, 0, 1, 0, 0, 0, 0, 1, 6, 0, 14, 61,125, 0, 1, 0, 0, 0, 0, 1, 7, 0, 7, 61,207, 0, 1,
+ 0, 0, 0, 0, 1, 8, 0, 18, 61,245, 0, 1, 0, 0, 0, 1, 1, 0, 0, 24, 59,173, 0, 1, 0, 0, 0, 1, 1, 1, 0, 9,
+ 60, 37, 0, 1, 0, 0, 0, 1, 1, 2, 0, 23, 60, 95, 0, 1, 0, 0, 0, 1, 1, 3, 0, 9, 60,149, 0, 1, 0, 0, 0, 1,
+ 1, 4, 0, 31, 60,185, 0, 1, 0, 0, 0, 1, 1, 5, 0, 18, 61, 39, 0, 1, 0, 0, 0, 1, 1, 6, 0, 15, 61,140, 0, 1,
+ 0, 0, 0, 1, 1, 7, 0, 21, 61,215, 0, 1, 0, 0, 0, 1, 1, 8, 0, 22, 62, 8, 0, 1, 0, 0, 0, 2, 1, 0, 0, 33,
+ 59,198, 0, 1, 0, 0, 0, 2, 1, 1, 0, 9, 60, 47, 0, 1, 0, 0, 0, 2, 1, 4, 0, 23, 60,217, 0, 1, 0, 0, 0, 2,
+ 1, 5, 0, 17, 61, 58, 0, 1, 0, 0, 0, 2, 1, 6, 0, 17, 61,156, 0, 1, 0, 0, 0, 2, 1, 8, 0, 16, 62, 31, 0, 1,
+ 0, 0, 0, 3, 1, 0, 0, 21, 59,232, 0, 1, 0, 0, 0, 3, 1, 1, 0, 8, 60, 57, 0, 1, 0, 0, 0, 3, 1, 4, 0, 17,
+ 60,241, 0, 1, 0, 0, 0, 3, 1, 5, 0, 19, 61, 76, 0, 1, 0, 0, 0, 3, 1, 6, 0, 13, 61,174, 0, 1, 0, 0, 0, 3,
+ 1, 8, 0, 18, 62, 48, 0, 1, 0, 0, 0, 4, 1, 0, 0, 28, 59,254, 0, 1, 0, 0, 0, 4, 1, 1, 0, 9, 60, 66, 0, 1,
+ 0, 0, 0, 4, 1, 2, 0, 19, 60,119, 0, 1, 0, 0, 0, 4, 1, 3, 0, 7, 60,159, 0, 1, 0, 0, 0, 4, 1, 4, 0, 18,
+ 61, 3, 0, 1, 0, 0, 0, 4, 1, 5, 0, 28, 61, 96, 0, 1, 0, 0, 0, 4, 1, 6, 0, 18, 61,188, 0, 1, 0, 0, 0, 4,
+ 1, 7, 0, 7, 61,237, 0, 1, 0, 0, 0, 4, 1, 8, 0, 17, 62, 67, 0, 3, 0, 1, 4, 9, 0, 0, 1, 48, 0, 0, 0, 3,
+ 0, 1, 4, 9, 0, 1, 0, 22, 1,203, 0, 3, 0, 1, 4, 9, 0, 2, 0, 8, 1,239, 0, 3, 0, 1, 4, 9, 0, 3, 0, 22,
+ 1,254, 0, 3, 0, 1, 4, 9, 0, 4, 0, 22, 2, 34, 0, 3, 0, 1, 4, 9, 0, 5, 0, 22, 2, 70, 0, 3, 0, 1, 4, 9,
+ 0, 6, 0, 20, 2,106, 0, 3, 0, 1, 4, 9, 0, 8, 0, 34, 2,139, 0, 3, 0, 1, 4, 9, 0, 11, 0, 58, 2,193, 0, 3,
+ 0, 1, 4, 9, 0, 13, 37, 58, 3, 27, 0, 3, 0, 1, 4, 9, 0, 14, 0,104, 58,245, 0, 67, 0,111, 0,112, 0,121, 0,114,
+ 0,105, 0,103, 0,104, 0,116, 0, 32, 0, 40, 0, 99, 0, 41, 0, 32, 0, 50, 0, 48, 0, 48, 0, 51, 0, 32, 0, 98, 0,121,
+ 0, 32, 0, 66, 0,105, 0,116, 0,115, 0,116, 0,114, 0,101, 0, 97, 0,109, 0, 44, 0, 32, 0, 73, 0,110, 0, 99, 0, 46,
+ 0, 32, 0, 65, 0,108, 0,108, 0, 32, 0, 82, 0,105, 0,103, 0,104, 0,116, 0,115, 0, 32, 0, 82, 0,101, 0,115, 0,101,
+ 0,114, 0,118, 0,101, 0,100, 0, 46, 0, 10, 0, 67, 0,111, 0,112, 0,121, 0,114, 0,105, 0,103, 0,104, 0,116, 0, 32,
+ 0, 40, 0, 99, 0, 41, 0, 32, 0, 50, 0, 48, 0, 48, 0, 54, 0, 32, 0, 98, 0,121, 0, 32, 0, 84, 0, 97, 0,118, 0,109,
+ 0,106, 0,111, 0,110, 0,103, 0, 32, 0, 66, 0, 97, 0,104, 0, 46, 0, 32, 0, 65, 0,108, 0,108, 0, 32, 0, 82, 0,105,
+ 0,103, 0,104, 0,116, 0,115, 0, 32, 0, 82, 0,101, 0,115, 0,101, 0,114, 0,118, 0,101, 0,100, 0, 46, 0, 10, 0, 68,
+ 0,101, 0,106, 0, 97, 0, 86, 0,117, 0, 32, 0, 99, 0,104, 0, 97, 0,110, 0,103, 0,101, 0,115, 0, 32, 0, 97, 0,114,
+ 0,101, 0, 32, 0,105, 0,110, 0, 32, 0,112, 0,117, 0, 98, 0,108, 0,105, 0, 99, 0, 32, 0,100, 0,111, 0,109, 0, 97,
+ 0,105, 0,110, 0, 10, 0, 0, 67,111,112,121,114,105,103,104,116, 32, 40, 99, 41, 32, 50, 48, 48, 51, 32, 98,121, 32, 66,105,
+116,115,116,114,101, 97,109, 44, 32, 73,110, 99, 46, 32, 65,108,108, 32, 82,105,103,104,116,115, 32, 82,101,115,101,114,118,101,
+100, 46, 10, 67,111,112,121,114,105,103,104,116, 32, 40, 99, 41, 32, 50, 48, 48, 54, 32, 98,121, 32, 84, 97,118,109,106,111,110,
+103, 32, 66, 97,104, 46, 32, 65,108,108, 32, 82,105,103,104,116,115, 32, 82,101,115,101,114,118,101,100, 46, 10, 68,101,106, 97,
+ 86,117, 32, 99,104, 97,110,103,101,115, 32, 97,114,101, 32,105,110, 32,112,117, 98,108,105, 99, 32,100,111,109, 97,105,110, 10,
+ 0, 0, 68, 0,101, 0,106, 0, 97, 0, 86, 0,117, 0, 32, 0, 83, 0, 97, 0,110, 0,115, 0, 0, 68,101,106, 97, 86,117, 32,
+ 83, 97,110,115, 0, 0, 66, 0,111, 0,111, 0,107, 0, 0, 66,111,111,107, 0, 0, 68, 0,101, 0,106, 0, 97, 0, 86, 0,117,
+ 0, 32, 0, 83, 0, 97, 0,110, 0,115, 0, 0, 68,101,106, 97, 86,117, 32, 83, 97,110,115, 0, 0, 68, 0,101, 0,106, 0, 97,
+ 0, 86, 0,117, 0, 32, 0, 83, 0, 97, 0,110, 0,115, 0, 0, 68,101,106, 97, 86,117, 32, 83, 97,110,115, 0, 0, 86, 0,101,
+ 0,114, 0,115, 0,105, 0,111, 0,110, 0, 32, 0, 50, 0, 46, 0, 56, 0, 0, 86,101,114,115,105,111,110, 32, 50, 46, 56, 0,
+ 0, 68, 0,101, 0,106, 0, 97, 0, 86, 0,117, 0, 83, 0, 97, 0,110, 0,115, 0, 0, 68,101,106, 97, 86,117, 83, 97,110,115,
+ 0, 0, 68, 0,101, 0,106, 0, 97, 0, 86, 0,117, 0, 32, 0,102, 0,111, 0,110, 0,116, 0,115, 0, 32, 0,116, 0,101, 0,
+ 97, 0,109, 0, 0, 68,101,106, 97, 86,117, 32,102,111,110,116,115, 32,116,101, 97,109, 0, 0,104, 0,116, 0,116, 0,112, 0,
+ 58, 0, 47, 0, 47, 0,100, 0,101, 0,106, 0, 97, 0,118, 0,117, 0, 46, 0,115, 0,111, 0,117, 0,114, 0, 99, 0,101, 0,
+102, 0,111, 0,114, 0,103, 0,101, 0, 46, 0,110, 0,101, 0,116, 0, 0,104,116,116,112, 58, 47, 47,100,101,106, 97,118,117,
+ 46,115,111,117,114, 99,101,102,111,114,103,101, 46,110,101,116, 0, 0, 70, 0,111, 0,110, 0,116, 0,115, 0, 32, 0, 97, 0,
+114, 0,101, 0, 32, 0, 40, 0, 99, 0, 41, 0, 32, 0, 66, 0,105, 0,116, 0,115, 0,116, 0,114, 0,101, 0, 97, 0,109, 0,
+ 32, 0, 40, 0,115, 0,101, 0,101, 0, 32, 0, 98, 0,101, 0,108, 0,111, 0,119, 0, 41, 0, 46, 0, 32, 0, 68, 0,101, 0,
+106, 0, 97, 0, 86, 0,117, 0, 32, 0, 99, 0,104, 0, 97, 0,110, 0,103, 0,101, 0,115, 0, 32, 0, 97, 0,114, 0,101, 0,
+ 32, 0,105, 0,110, 0, 32, 0,112, 0,117, 0, 98, 0,108, 0,105, 0, 99, 0, 32, 0,100, 0,111, 0,109, 0, 97, 0,105, 0,
+110, 0, 46, 0, 32, 0, 71, 0,108, 0,121, 0,112, 0,104, 0,115, 0, 32, 0,105, 0,109, 0,112, 0,111, 0,114, 0,116, 0,
+101, 0,100, 0, 32, 0,102, 0,114, 0,111, 0,109, 0, 32, 0, 65, 0,114, 0,101, 0,118, 0, 32, 0,102, 0,111, 0,110, 0,
+116, 0,115, 0, 32, 0, 97, 0,114, 0,101, 0, 32, 0, 40, 0, 99, 0, 41, 0, 32, 0, 84, 0, 97, 0,118, 0,109, 0,106, 0,
+117, 0,110, 0,103, 0, 32, 0, 66, 0, 97, 0,104, 0, 32, 0, 40, 0,115, 0,101, 0,101, 0, 32, 0, 98, 0,101, 0,108, 0,
+111, 0,119, 0, 41, 0, 10, 0, 10, 0, 66, 0,105, 0,116, 0,115, 0,116, 0,114, 0,101, 0, 97, 0,109, 0, 32, 0, 86, 0,
+101, 0,114, 0, 97, 0, 32, 0, 70, 0,111, 0,110, 0,116, 0,115, 0, 32, 0, 67, 0,111, 0,112, 0,121, 0,114, 0,105, 0,
+103, 0,104, 0,116, 0, 10, 0, 45, 0, 45, 0, 45, 0, 45, 0, 45, 0, 45, 0, 45, 0, 45, 0, 45, 0, 45, 0, 45, 0, 45, 0,
+ 45, 0, 45, 0, 45, 0, 45, 0, 45, 0, 45, 0, 45, 0, 45, 0, 45, 0, 45, 0, 45, 0, 45, 0, 45, 0, 45, 0, 45, 0, 45, 0,
+ 45, 0, 45, 0, 10, 0, 10, 0, 67, 0,111, 0,112, 0,121, 0,114, 0,105, 0,103, 0,104, 0,116, 0, 32, 0, 40, 0, 99, 0,
+ 41, 0, 32, 0, 50, 0, 48, 0, 48, 0, 51, 0, 32, 0, 98, 0,121, 0, 32, 0, 66, 0,105, 0,116, 0,115, 0,116, 0,114, 0,
+101, 0, 97, 0,109, 0, 44, 0, 32, 0, 73, 0,110, 0, 99, 0, 46, 0, 32, 0, 65, 0,108, 0,108, 0, 32, 0, 82, 0,105, 0,
+103, 0,104, 0,116, 0,115, 0, 32, 0, 82, 0,101, 0,115, 0,101, 0,114, 0,118, 0,101, 0,100, 0, 46, 0, 32, 0, 66, 0,
+105, 0,116, 0,115, 0,116, 0,114, 0,101, 0, 97, 0,109, 0, 32, 0, 86, 0,101, 0,114, 0, 97, 0, 32, 0,105, 0,115, 0,
+ 10, 0, 97, 0, 32, 0,116, 0,114, 0, 97, 0,100, 0,101, 0,109, 0, 97, 0,114, 0,107, 0, 32, 0,111, 0,102, 0, 32, 0,
+ 66, 0,105, 0,116, 0,115, 0,116, 0,114, 0,101, 0, 97, 0,109, 0, 44, 0, 32, 0, 73, 0,110, 0, 99, 0, 46, 0, 10, 0,
+ 10, 0, 80, 0,101, 0,114, 0,109, 0,105, 0,115, 0,115, 0,105, 0,111, 0,110, 0, 32, 0,105, 0,115, 0, 32, 0,104, 0,
+101, 0,114, 0,101, 0, 98, 0,121, 0, 32, 0,103, 0,114, 0, 97, 0,110, 0,116, 0,101, 0,100, 0, 44, 0, 32, 0,102, 0,
+114, 0,101, 0,101, 0, 32, 0,111, 0,102, 0, 32, 0, 99, 0,104, 0, 97, 0,114, 0,103, 0,101, 0, 44, 0, 32, 0,116, 0,
+111, 0, 32, 0, 97, 0,110, 0,121, 0, 32, 0,112, 0,101, 0,114, 0,115, 0,111, 0,110, 0, 32, 0,111, 0, 98, 0,116, 0,
+ 97, 0,105, 0,110, 0,105, 0,110, 0,103, 0, 32, 0, 97, 0, 32, 0, 99, 0,111, 0,112, 0,121, 0, 10, 0,111, 0,102, 0,
+ 32, 0,116, 0,104, 0,101, 0, 32, 0,102, 0,111, 0,110, 0,116, 0,115, 0, 32, 0, 97, 0, 99, 0, 99, 0,111, 0,109, 0,
+112, 0, 97, 0,110, 0,121, 0,105, 0,110, 0,103, 0, 32, 0,116, 0,104, 0,105, 0,115, 0, 32, 0,108, 0,105, 0, 99, 0,
+101, 0,110, 0,115, 0,101, 0, 32, 0, 40, 0, 34, 0, 70, 0,111, 0,110, 0,116, 0,115, 0, 34, 0, 41, 0, 32, 0, 97, 0,
+110, 0,100, 0, 32, 0, 97, 0,115, 0,115, 0,111, 0, 99, 0,105, 0, 97, 0,116, 0,101, 0,100, 0, 10, 0,100, 0,111, 0,
+ 99, 0,117, 0,109, 0,101, 0,110, 0,116, 0, 97, 0,116, 0,105, 0,111, 0,110, 0, 32, 0,102, 0,105, 0,108, 0,101, 0,
+115, 0, 32, 0, 40, 0,116, 0,104, 0,101, 0, 32, 0, 34, 0, 70, 0,111, 0,110, 0,116, 0, 32, 0, 83, 0,111, 0,102, 0,
+116, 0,119, 0, 97, 0,114, 0,101, 0, 34, 0, 41, 0, 44, 0, 32, 0,116, 0,111, 0, 32, 0,114, 0,101, 0,112, 0,114, 0,
+111, 0,100, 0,117, 0, 99, 0,101, 0, 32, 0, 97, 0,110, 0,100, 0, 32, 0,100, 0,105, 0,115, 0,116, 0,114, 0,105, 0,
+ 98, 0,117, 0,116, 0,101, 0, 32, 0,116, 0,104, 0,101, 0, 10, 0, 70, 0,111, 0,110, 0,116, 0, 32, 0, 83, 0,111, 0,
+102, 0,116, 0,119, 0, 97, 0,114, 0,101, 0, 44, 0, 32, 0,105, 0,110, 0, 99, 0,108, 0,117, 0,100, 0,105, 0,110, 0,
+103, 0, 32, 0,119, 0,105, 0,116, 0,104, 0,111, 0,117, 0,116, 0, 32, 0,108, 0,105, 0,109, 0,105, 0,116, 0, 97, 0,
+116, 0,105, 0,111, 0,110, 0, 32, 0,116, 0,104, 0,101, 0, 32, 0,114, 0,105, 0,103, 0,104, 0,116, 0,115, 0, 32, 0,
+116, 0,111, 0, 32, 0,117, 0,115, 0,101, 0, 44, 0, 32, 0, 99, 0,111, 0,112, 0,121, 0, 44, 0, 32, 0,109, 0,101, 0,
+114, 0,103, 0,101, 0, 44, 0, 10, 0,112, 0,117, 0, 98, 0,108, 0,105, 0,115, 0,104, 0, 44, 0, 32, 0,100, 0,105, 0,
+115, 0,116, 0,114, 0,105, 0, 98, 0,117, 0,116, 0,101, 0, 44, 0, 32, 0, 97, 0,110, 0,100, 0, 47, 0,111, 0,114, 0,
+ 32, 0,115, 0,101, 0,108, 0,108, 0, 32, 0, 99, 0,111, 0,112, 0,105, 0,101, 0,115, 0, 32, 0,111, 0,102, 0, 32, 0,
+116, 0,104, 0,101, 0, 32, 0, 70, 0,111, 0,110, 0,116, 0, 32, 0, 83, 0,111, 0,102, 0,116, 0,119, 0, 97, 0,114, 0,
+101, 0, 44, 0, 32, 0, 97, 0,110, 0,100, 0, 32, 0,116, 0,111, 0, 32, 0,112, 0,101, 0,114, 0,109, 0,105, 0,116, 0,
+ 10, 0,112, 0,101, 0,114, 0,115, 0,111, 0,110, 0,115, 0, 32, 0,116, 0,111, 0, 32, 0,119, 0,104, 0,111, 0,109, 0,
+ 32, 0,116, 0,104, 0,101, 0, 32, 0, 70, 0,111, 0,110, 0,116, 0, 32, 0, 83, 0,111, 0,102, 0,116, 0,119, 0, 97, 0,
+114, 0,101, 0, 32, 0,105, 0,115, 0, 32, 0,102, 0,117, 0,114, 0,110, 0,105, 0,115, 0,104, 0,101, 0,100, 0, 32, 0,
+116, 0,111, 0, 32, 0,100, 0,111, 0, 32, 0,115, 0,111, 0, 44, 0, 32, 0,115, 0,117, 0, 98, 0,106, 0,101, 0, 99, 0,
+116, 0, 32, 0,116, 0,111, 0, 32, 0,116, 0,104, 0,101, 0, 10, 0,102, 0,111, 0,108, 0,108, 0,111, 0,119, 0,105, 0,
+110, 0,103, 0, 32, 0, 99, 0,111, 0,110, 0,100, 0,105, 0,116, 0,105, 0,111, 0,110, 0,115, 0, 58, 0, 10, 0, 10, 0,
+ 84, 0,104, 0,101, 0, 32, 0, 97, 0, 98, 0,111, 0,118, 0,101, 0, 32, 0, 99, 0,111, 0,112, 0,121, 0,114, 0,105, 0,
+103, 0,104, 0,116, 0, 32, 0, 97, 0,110, 0,100, 0, 32, 0,116, 0,114, 0, 97, 0,100, 0,101, 0,109, 0, 97, 0,114, 0,
+107, 0, 32, 0,110, 0,111, 0,116, 0,105, 0, 99, 0,101, 0,115, 0, 32, 0, 97, 0,110, 0,100, 0, 32, 0,116, 0,104, 0,
+105, 0,115, 0, 32, 0,112, 0,101, 0,114, 0,109, 0,105, 0,115, 0,115, 0,105, 0,111, 0,110, 0, 32, 0,110, 0,111, 0,
+116, 0,105, 0, 99, 0,101, 0, 32, 0,115, 0,104, 0, 97, 0,108, 0,108, 0, 10, 0, 98, 0,101, 0, 32, 0,105, 0,110, 0,
+ 99, 0,108, 0,117, 0,100, 0,101, 0,100, 0, 32, 0,105, 0,110, 0, 32, 0, 97, 0,108, 0,108, 0, 32, 0, 99, 0,111, 0,
+112, 0,105, 0,101, 0,115, 0, 32, 0,111, 0,102, 0, 32, 0,111, 0,110, 0,101, 0, 32, 0,111, 0,114, 0, 32, 0,109, 0,
+111, 0,114, 0,101, 0, 32, 0,111, 0,102, 0, 32, 0,116, 0,104, 0,101, 0, 32, 0, 70, 0,111, 0,110, 0,116, 0, 32, 0,
+ 83, 0,111, 0,102, 0,116, 0,119, 0, 97, 0,114, 0,101, 0, 32, 0,116, 0,121, 0,112, 0,101, 0,102, 0, 97, 0, 99, 0,
+101, 0,115, 0, 46, 0, 10, 0, 10, 0, 84, 0,104, 0,101, 0, 32, 0, 70, 0,111, 0,110, 0,116, 0, 32, 0, 83, 0,111, 0,
+102, 0,116, 0,119, 0, 97, 0,114, 0,101, 0, 32, 0,109, 0, 97, 0,121, 0, 32, 0, 98, 0,101, 0, 32, 0,109, 0,111, 0,
+100, 0,105, 0,102, 0,105, 0,101, 0,100, 0, 44, 0, 32, 0, 97, 0,108, 0,116, 0,101, 0,114, 0,101, 0,100, 0, 44, 0,
+ 32, 0,111, 0,114, 0, 32, 0, 97, 0,100, 0,100, 0,101, 0,100, 0, 32, 0,116, 0,111, 0, 44, 0, 32, 0, 97, 0,110, 0,
+100, 0, 32, 0,105, 0,110, 0, 32, 0,112, 0, 97, 0,114, 0,116, 0,105, 0, 99, 0,117, 0,108, 0, 97, 0,114, 0, 10, 0,
+116, 0,104, 0,101, 0, 32, 0,100, 0,101, 0,115, 0,105, 0,103, 0,110, 0,115, 0, 32, 0,111, 0,102, 0, 32, 0,103, 0,
+108, 0,121, 0,112, 0,104, 0,115, 0, 32, 0,111, 0,114, 0, 32, 0, 99, 0,104, 0, 97, 0,114, 0, 97, 0, 99, 0,116, 0,
+101, 0,114, 0,115, 0, 32, 0,105, 0,110, 0, 32, 0,116, 0,104, 0,101, 0, 32, 0, 70, 0,111, 0,110, 0,116, 0,115, 0,
+ 32, 0,109, 0, 97, 0,121, 0, 32, 0, 98, 0,101, 0, 32, 0,109, 0,111, 0,100, 0,105, 0,102, 0,105, 0,101, 0,100, 0,
+ 32, 0, 97, 0,110, 0,100, 0, 10, 0, 97, 0,100, 0,100, 0,105, 0,116, 0,105, 0,111, 0,110, 0, 97, 0,108, 0, 32, 0,
+103, 0,108, 0,121, 0,112, 0,104, 0,115, 0, 32, 0,111, 0,114, 0, 32, 0, 99, 0,104, 0, 97, 0,114, 0, 97, 0, 99, 0,
+116, 0,101, 0,114, 0,115, 0, 32, 0,109, 0, 97, 0,121, 0, 32, 0, 98, 0,101, 0, 32, 0, 97, 0,100, 0,100, 0,101, 0,
+100, 0, 32, 0,116, 0,111, 0, 32, 0,116, 0,104, 0,101, 0, 32, 0, 70, 0,111, 0,110, 0,116, 0,115, 0, 44, 0, 32, 0,
+111, 0,110, 0,108, 0,121, 0, 32, 0,105, 0,102, 0, 32, 0,116, 0,104, 0,101, 0, 32, 0,102, 0,111, 0,110, 0,116, 0,
+115, 0, 10, 0, 97, 0,114, 0,101, 0, 32, 0,114, 0,101, 0,110, 0, 97, 0,109, 0,101, 0,100, 0, 32, 0,116, 0,111, 0,
+ 32, 0,110, 0, 97, 0,109, 0,101, 0,115, 0, 32, 0,110, 0,111, 0,116, 0, 32, 0, 99, 0,111, 0,110, 0,116, 0, 97, 0,
+105, 0,110, 0,105, 0,110, 0,103, 0, 32, 0,101, 0,105, 0,116, 0,104, 0,101, 0,114, 0, 32, 0,116, 0,104, 0,101, 0,
+ 32, 0,119, 0,111, 0,114, 0,100, 0,115, 0, 32, 0, 34, 0, 66, 0,105, 0,116, 0,115, 0,116, 0,114, 0,101, 0, 97, 0,
+109, 0, 34, 0, 32, 0,111, 0,114, 0, 32, 0,116, 0,104, 0,101, 0, 32, 0,119, 0,111, 0,114, 0,100, 0, 10, 0, 34, 0,
+ 86, 0,101, 0,114, 0, 97, 0, 34, 0, 46, 0, 10, 0, 10, 0, 84, 0,104, 0,105, 0,115, 0, 32, 0, 76, 0,105, 0, 99, 0,
+101, 0,110, 0,115, 0,101, 0, 32, 0, 98, 0,101, 0, 99, 0,111, 0,109, 0,101, 0,115, 0, 32, 0,110, 0,117, 0,108, 0,
+108, 0, 32, 0, 97, 0,110, 0,100, 0, 32, 0,118, 0,111, 0,105, 0,100, 0, 32, 0,116, 0,111, 0, 32, 0,116, 0,104, 0,
+101, 0, 32, 0,101, 0,120, 0,116, 0,101, 0,110, 0,116, 0, 32, 0, 97, 0,112, 0,112, 0,108, 0,105, 0, 99, 0, 97, 0,
+ 98, 0,108, 0,101, 0, 32, 0,116, 0,111, 0, 32, 0, 70, 0,111, 0,110, 0,116, 0,115, 0, 32, 0,111, 0,114, 0, 32, 0,
+ 70, 0,111, 0,110, 0,116, 0, 10, 0, 83, 0,111, 0,102, 0,116, 0,119, 0, 97, 0,114, 0,101, 0, 32, 0,116, 0,104, 0,
+ 97, 0,116, 0, 32, 0,104, 0, 97, 0,115, 0, 32, 0, 98, 0,101, 0,101, 0,110, 0, 32, 0,109, 0,111, 0,100, 0,105, 0,
+102, 0,105, 0,101, 0,100, 0, 32, 0, 97, 0,110, 0,100, 0, 32, 0,105, 0,115, 0, 32, 0,100, 0,105, 0,115, 0,116, 0,
+114, 0,105, 0, 98, 0,117, 0,116, 0,101, 0,100, 0, 32, 0,117, 0,110, 0,100, 0,101, 0,114, 0, 32, 0,116, 0,104, 0,
+101, 0, 32, 0, 34, 0, 66, 0,105, 0,116, 0,115, 0,116, 0,114, 0,101, 0, 97, 0,109, 0, 10, 0, 86, 0,101, 0,114, 0,
+ 97, 0, 34, 0, 32, 0,110, 0, 97, 0,109, 0,101, 0,115, 0, 46, 0, 10, 0, 10, 0, 84, 0,104, 0,101, 0, 32, 0, 70, 0,
+111, 0,110, 0,116, 0, 32, 0, 83, 0,111, 0,102, 0,116, 0,119, 0, 97, 0,114, 0,101, 0, 32, 0,109, 0, 97, 0,121, 0,
+ 32, 0, 98, 0,101, 0, 32, 0,115, 0,111, 0,108, 0,100, 0, 32, 0, 97, 0,115, 0, 32, 0,112, 0, 97, 0,114, 0,116, 0,
+ 32, 0,111, 0,102, 0, 32, 0, 97, 0, 32, 0,108, 0, 97, 0,114, 0,103, 0,101, 0,114, 0, 32, 0,115, 0,111, 0,102, 0,
+116, 0,119, 0, 97, 0,114, 0,101, 0, 32, 0,112, 0, 97, 0, 99, 0,107, 0, 97, 0,103, 0,101, 0, 32, 0, 98, 0,117, 0,
+116, 0, 32, 0,110, 0,111, 0, 10, 0, 99, 0,111, 0,112, 0,121, 0, 32, 0,111, 0,102, 0, 32, 0,111, 0,110, 0,101, 0,
+ 32, 0,111, 0,114, 0, 32, 0,109, 0,111, 0,114, 0,101, 0, 32, 0,111, 0,102, 0, 32, 0,116, 0,104, 0,101, 0, 32, 0,
+ 70, 0,111, 0,110, 0,116, 0, 32, 0, 83, 0,111, 0,102, 0,116, 0,119, 0, 97, 0,114, 0,101, 0, 32, 0,116, 0,121, 0,
+112, 0,101, 0,102, 0, 97, 0, 99, 0,101, 0,115, 0, 32, 0,109, 0, 97, 0,121, 0, 32, 0, 98, 0,101, 0, 32, 0,115, 0,
+111, 0,108, 0,100, 0, 32, 0, 98, 0,121, 0, 32, 0,105, 0,116, 0,115, 0,101, 0,108, 0,102, 0, 46, 0, 10, 0, 10, 0,
+ 84, 0, 72, 0, 69, 0, 32, 0, 70, 0, 79, 0, 78, 0, 84, 0, 32, 0, 83, 0, 79, 0, 70, 0, 84, 0, 87, 0, 65, 0, 82, 0,
+ 69, 0, 32, 0, 73, 0, 83, 0, 32, 0, 80, 0, 82, 0, 79, 0, 86, 0, 73, 0, 68, 0, 69, 0, 68, 0, 32, 0, 34, 0, 65, 0,
+ 83, 0, 32, 0, 73, 0, 83, 0, 34, 0, 44, 0, 32, 0, 87, 0, 73, 0, 84, 0, 72, 0, 79, 0, 85, 0, 84, 0, 32, 0, 87, 0,
+ 65, 0, 82, 0, 82, 0, 65, 0, 78, 0, 84, 0, 89, 0, 32, 0, 79, 0, 70, 0, 32, 0, 65, 0, 78, 0, 89, 0, 32, 0, 75, 0,
+ 73, 0, 78, 0, 68, 0, 44, 0, 32, 0, 69, 0, 88, 0, 80, 0, 82, 0, 69, 0, 83, 0, 83, 0, 10, 0, 79, 0, 82, 0, 32, 0,
+ 73, 0, 77, 0, 80, 0, 76, 0, 73, 0, 69, 0, 68, 0, 44, 0, 32, 0, 73, 0, 78, 0, 67, 0, 76, 0, 85, 0, 68, 0, 73, 0,
+ 78, 0, 71, 0, 32, 0, 66, 0, 85, 0, 84, 0, 32, 0, 78, 0, 79, 0, 84, 0, 32, 0, 76, 0, 73, 0, 77, 0, 73, 0, 84, 0,
+ 69, 0, 68, 0, 32, 0, 84, 0, 79, 0, 32, 0, 65, 0, 78, 0, 89, 0, 32, 0, 87, 0, 65, 0, 82, 0, 82, 0, 65, 0, 78, 0,
+ 84, 0, 73, 0, 69, 0, 83, 0, 32, 0, 79, 0, 70, 0, 32, 0, 77, 0, 69, 0, 82, 0, 67, 0, 72, 0, 65, 0, 78, 0, 84, 0,
+ 65, 0, 66, 0, 73, 0, 76, 0, 73, 0, 84, 0, 89, 0, 44, 0, 10, 0, 70, 0, 73, 0, 84, 0, 78, 0, 69, 0, 83, 0, 83, 0,
+ 32, 0, 70, 0, 79, 0, 82, 0, 32, 0, 65, 0, 32, 0, 80, 0, 65, 0, 82, 0, 84, 0, 73, 0, 67, 0, 85, 0, 76, 0, 65, 0,
+ 82, 0, 32, 0, 80, 0, 85, 0, 82, 0, 80, 0, 79, 0, 83, 0, 69, 0, 32, 0, 65, 0, 78, 0, 68, 0, 32, 0, 78, 0, 79, 0,
+ 78, 0, 73, 0, 78, 0, 70, 0, 82, 0, 73, 0, 78, 0, 71, 0, 69, 0, 77, 0, 69, 0, 78, 0, 84, 0, 32, 0, 79, 0, 70, 0,
+ 32, 0, 67, 0, 79, 0, 80, 0, 89, 0, 82, 0, 73, 0, 71, 0, 72, 0, 84, 0, 44, 0, 32, 0, 80, 0, 65, 0, 84, 0, 69, 0,
+ 78, 0, 84, 0, 44, 0, 10, 0, 84, 0, 82, 0, 65, 0, 68, 0, 69, 0, 77, 0, 65, 0, 82, 0, 75, 0, 44, 0, 32, 0, 79, 0,
+ 82, 0, 32, 0, 79, 0, 84, 0, 72, 0, 69, 0, 82, 0, 32, 0, 82, 0, 73, 0, 71, 0, 72, 0, 84, 0, 46, 0, 32, 0, 73, 0,
+ 78, 0, 32, 0, 78, 0, 79, 0, 32, 0, 69, 0, 86, 0, 69, 0, 78, 0, 84, 0, 32, 0, 83, 0, 72, 0, 65, 0, 76, 0, 76, 0,
+ 32, 0, 66, 0, 73, 0, 84, 0, 83, 0, 84, 0, 82, 0, 69, 0, 65, 0, 77, 0, 32, 0, 79, 0, 82, 0, 32, 0, 84, 0, 72, 0,
+ 69, 0, 32, 0, 71, 0, 78, 0, 79, 0, 77, 0, 69, 0, 10, 0, 70, 0, 79, 0, 85, 0, 78, 0, 68, 0, 65, 0, 84, 0, 73, 0,
+ 79, 0, 78, 0, 32, 0, 66, 0, 69, 0, 32, 0, 76, 0, 73, 0, 65, 0, 66, 0, 76, 0, 69, 0, 32, 0, 70, 0, 79, 0, 82, 0,
+ 32, 0, 65, 0, 78, 0, 89, 0, 32, 0, 67, 0, 76, 0, 65, 0, 73, 0, 77, 0, 44, 0, 32, 0, 68, 0, 65, 0, 77, 0, 65, 0,
+ 71, 0, 69, 0, 83, 0, 32, 0, 79, 0, 82, 0, 32, 0, 79, 0, 84, 0, 72, 0, 69, 0, 82, 0, 32, 0, 76, 0, 73, 0, 65, 0,
+ 66, 0, 73, 0, 76, 0, 73, 0, 84, 0, 89, 0, 44, 0, 32, 0, 73, 0, 78, 0, 67, 0, 76, 0, 85, 0, 68, 0, 73, 0, 78, 0,
+ 71, 0, 10, 0, 65, 0, 78, 0, 89, 0, 32, 0, 71, 0, 69, 0, 78, 0, 69, 0, 82, 0, 65, 0, 76, 0, 44, 0, 32, 0, 83, 0,
+ 80, 0, 69, 0, 67, 0, 73, 0, 65, 0, 76, 0, 44, 0, 32, 0, 73, 0, 78, 0, 68, 0, 73, 0, 82, 0, 69, 0, 67, 0, 84, 0,
+ 44, 0, 32, 0, 73, 0, 78, 0, 67, 0, 73, 0, 68, 0, 69, 0, 78, 0, 84, 0, 65, 0, 76, 0, 44, 0, 32, 0, 79, 0, 82, 0,
+ 32, 0, 67, 0, 79, 0, 78, 0, 83, 0, 69, 0, 81, 0, 85, 0, 69, 0, 78, 0, 84, 0, 73, 0, 65, 0, 76, 0, 32, 0, 68, 0,
+ 65, 0, 77, 0, 65, 0, 71, 0, 69, 0, 83, 0, 44, 0, 10, 0, 87, 0, 72, 0, 69, 0, 84, 0, 72, 0, 69, 0, 82, 0, 32, 0,
+ 73, 0, 78, 0, 32, 0, 65, 0, 78, 0, 32, 0, 65, 0, 67, 0, 84, 0, 73, 0, 79, 0, 78, 0, 32, 0, 79, 0, 70, 0, 32, 0,
+ 67, 0, 79, 0, 78, 0, 84, 0, 82, 0, 65, 0, 67, 0, 84, 0, 44, 0, 32, 0, 84, 0, 79, 0, 82, 0, 84, 0, 32, 0, 79, 0,
+ 82, 0, 32, 0, 79, 0, 84, 0, 72, 0, 69, 0, 82, 0, 87, 0, 73, 0, 83, 0, 69, 0, 44, 0, 32, 0, 65, 0, 82, 0, 73, 0,
+ 83, 0, 73, 0, 78, 0, 71, 0, 32, 0, 70, 0, 82, 0, 79, 0, 77, 0, 44, 0, 32, 0, 79, 0, 85, 0, 84, 0, 32, 0, 79, 0,
+ 70, 0, 10, 0, 84, 0, 72, 0, 69, 0, 32, 0, 85, 0, 83, 0, 69, 0, 32, 0, 79, 0, 82, 0, 32, 0, 73, 0, 78, 0, 65, 0,
+ 66, 0, 73, 0, 76, 0, 73, 0, 84, 0, 89, 0, 32, 0, 84, 0, 79, 0, 32, 0, 85, 0, 83, 0, 69, 0, 32, 0, 84, 0, 72, 0,
+ 69, 0, 32, 0, 70, 0, 79, 0, 78, 0, 84, 0, 32, 0, 83, 0, 79, 0, 70, 0, 84, 0, 87, 0, 65, 0, 82, 0, 69, 0, 32, 0,
+ 79, 0, 82, 0, 32, 0, 70, 0, 82, 0, 79, 0, 77, 0, 32, 0, 79, 0, 84, 0, 72, 0, 69, 0, 82, 0, 32, 0, 68, 0, 69, 0,
+ 65, 0, 76, 0, 73, 0, 78, 0, 71, 0, 83, 0, 32, 0, 73, 0, 78, 0, 32, 0, 84, 0, 72, 0, 69, 0, 10, 0, 70, 0, 79, 0,
+ 78, 0, 84, 0, 32, 0, 83, 0, 79, 0, 70, 0, 84, 0, 87, 0, 65, 0, 82, 0, 69, 0, 46, 0, 10, 0, 10, 0, 69, 0,120, 0,
+ 99, 0,101, 0,112, 0,116, 0, 32, 0, 97, 0,115, 0, 32, 0, 99, 0,111, 0,110, 0,116, 0, 97, 0,105, 0,110, 0,101, 0,
+100, 0, 32, 0,105, 0,110, 0, 32, 0,116, 0,104, 0,105, 0,115, 0, 32, 0,110, 0,111, 0,116, 0,105, 0, 99, 0,101, 0,
+ 44, 0, 32, 0,116, 0,104, 0,101, 0, 32, 0,110, 0, 97, 0,109, 0,101, 0,115, 0, 32, 0,111, 0,102, 0, 32, 0, 71, 0,
+110, 0,111, 0,109, 0,101, 0, 44, 0, 32, 0,116, 0,104, 0,101, 0, 32, 0, 71, 0,110, 0,111, 0,109, 0,101, 0, 10, 0,
+ 70, 0,111, 0,117, 0,110, 0,100, 0, 97, 0,116, 0,105, 0,111, 0,110, 0, 44, 0, 32, 0, 97, 0,110, 0,100, 0, 32, 0,
+ 66, 0,105, 0,116, 0,115, 0,116, 0,114, 0,101, 0, 97, 0,109, 0, 32, 0, 73, 0,110, 0, 99, 0, 46, 0, 44, 0, 32, 0,
+115, 0,104, 0, 97, 0,108, 0,108, 0, 32, 0,110, 0,111, 0,116, 0, 32, 0, 98, 0,101, 0, 32, 0,117, 0,115, 0,101, 0,
+100, 0, 32, 0,105, 0,110, 0, 32, 0, 97, 0,100, 0,118, 0,101, 0,114, 0,116, 0,105, 0,115, 0,105, 0,110, 0,103, 0,
+ 32, 0,111, 0,114, 0, 10, 0,111, 0,116, 0,104, 0,101, 0,114, 0,119, 0,105, 0,115, 0,101, 0, 32, 0,116, 0,111, 0,
+ 32, 0,112, 0,114, 0,111, 0,109, 0,111, 0,116, 0,101, 0, 32, 0,116, 0,104, 0,101, 0, 32, 0,115, 0, 97, 0,108, 0,
+101, 0, 44, 0, 32, 0,117, 0,115, 0,101, 0, 32, 0,111, 0,114, 0, 32, 0,111, 0,116, 0,104, 0,101, 0,114, 0, 32, 0,
+100, 0,101, 0, 97, 0,108, 0,105, 0,110, 0,103, 0,115, 0, 32, 0,105, 0,110, 0, 32, 0,116, 0,104, 0,105, 0,115, 0,
+ 32, 0, 70, 0,111, 0,110, 0,116, 0, 32, 0, 83, 0,111, 0,102, 0,116, 0,119, 0, 97, 0,114, 0,101, 0, 10, 0,119, 0,
+105, 0,116, 0,104, 0,111, 0,117, 0,116, 0, 32, 0,112, 0,114, 0,105, 0,111, 0,114, 0, 32, 0,119, 0,114, 0,105, 0,
+116, 0,116, 0,101, 0,110, 0, 32, 0, 97, 0,117, 0,116, 0,104, 0,111, 0,114, 0,105, 0,122, 0, 97, 0,116, 0,105, 0,
+111, 0,110, 0, 32, 0,102, 0,114, 0,111, 0,109, 0, 32, 0,116, 0,104, 0,101, 0, 32, 0, 71, 0,110, 0,111, 0,109, 0,
+101, 0, 32, 0, 70, 0,111, 0,117, 0,110, 0,100, 0, 97, 0,116, 0,105, 0,111, 0,110, 0, 32, 0,111, 0,114, 0, 32, 0,
+ 66, 0,105, 0,116, 0,115, 0,116, 0,114, 0,101, 0, 97, 0,109, 0, 10, 0, 73, 0,110, 0, 99, 0, 46, 0, 44, 0, 32, 0,
+114, 0,101, 0,115, 0,112, 0,101, 0, 99, 0,116, 0,105, 0,118, 0,101, 0,108, 0,121, 0, 46, 0, 32, 0, 70, 0,111, 0,
+114, 0, 32, 0,102, 0,117, 0,114, 0,116, 0,104, 0,101, 0,114, 0, 32, 0,105, 0,110, 0,102, 0,111, 0,114, 0,109, 0,
+ 97, 0,116, 0,105, 0,111, 0,110, 0, 44, 0, 32, 0, 99, 0,111, 0,110, 0,116, 0, 97, 0, 99, 0,116, 0, 58, 0, 32, 0,
+102, 0,111, 0,110, 0,116, 0,115, 0, 32, 0, 97, 0,116, 0, 32, 0,103, 0,110, 0,111, 0,109, 0,101, 0, 32, 0,100, 0,
+111, 0,116, 0, 10, 0,111, 0,114, 0,103, 0, 46, 0, 32, 0, 10, 0, 10, 0, 65, 0,114, 0,101, 0,118, 0, 32, 0, 70, 0,
+111, 0,110, 0,116, 0,115, 0, 32, 0, 67, 0,111, 0,112, 0,121, 0,114, 0,105, 0,103, 0,104, 0,116, 0, 10, 0, 45, 0,
+ 45, 0, 45, 0, 45, 0, 45, 0, 45, 0, 45, 0, 45, 0, 45, 0, 45, 0, 45, 0, 45, 0, 45, 0, 45, 0, 45, 0, 45, 0, 45, 0,
+ 45, 0, 45, 0, 45, 0, 45, 0, 45, 0, 45, 0, 45, 0, 45, 0, 45, 0, 45, 0, 45, 0, 45, 0, 45, 0, 10, 0, 10, 0, 67, 0,
+111, 0,112, 0,121, 0,114, 0,105, 0,103, 0,104, 0,116, 0, 32, 0, 40, 0, 99, 0, 41, 0, 32, 0, 50, 0, 48, 0, 48, 0,
+ 54, 0, 32, 0, 98, 0,121, 0, 32, 0, 84, 0, 97, 0,118, 0,109, 0,106, 0,111, 0,110, 0,103, 0, 32, 0, 66, 0, 97, 0,
+104, 0, 46, 0, 32, 0, 65, 0,108, 0,108, 0, 32, 0, 82, 0,105, 0,103, 0,104, 0,116, 0,115, 0, 32, 0, 82, 0,101, 0,
+115, 0,101, 0,114, 0,118, 0,101, 0,100, 0, 46, 0, 10, 0, 10, 0, 80, 0,101, 0,114, 0,109, 0,105, 0,115, 0,115, 0,
+105, 0,111, 0,110, 0, 32, 0,105, 0,115, 0, 32, 0,104, 0,101, 0,114, 0,101, 0, 98, 0,121, 0, 32, 0,103, 0,114, 0,
+ 97, 0,110, 0,116, 0,101, 0,100, 0, 44, 0, 32, 0,102, 0,114, 0,101, 0,101, 0, 32, 0,111, 0,102, 0, 32, 0, 99, 0,
+104, 0, 97, 0,114, 0,103, 0,101, 0, 44, 0, 32, 0,116, 0,111, 0, 32, 0, 97, 0,110, 0,121, 0, 32, 0,112, 0,101, 0,
+114, 0,115, 0,111, 0,110, 0, 32, 0,111, 0, 98, 0,116, 0, 97, 0,105, 0,110, 0,105, 0,110, 0,103, 0, 10, 0, 97, 0,
+ 32, 0, 99, 0,111, 0,112, 0,121, 0, 32, 0,111, 0,102, 0, 32, 0,116, 0,104, 0,101, 0, 32, 0,102, 0,111, 0,110, 0,
+116, 0,115, 0, 32, 0, 97, 0, 99, 0, 99, 0,111, 0,109, 0,112, 0, 97, 0,110, 0,121, 0,105, 0,110, 0,103, 0, 32, 0,
+116, 0,104, 0,105, 0,115, 0, 32, 0,108, 0,105, 0, 99, 0,101, 0,110, 0,115, 0,101, 0, 32, 0, 40, 0, 34, 0, 70, 0,
+111, 0,110, 0,116, 0,115, 0, 34, 0, 41, 0, 32, 0, 97, 0,110, 0,100, 0, 10, 0, 97, 0,115, 0,115, 0,111, 0, 99, 0,
+105, 0, 97, 0,116, 0,101, 0,100, 0, 32, 0,100, 0,111, 0, 99, 0,117, 0,109, 0,101, 0,110, 0,116, 0, 97, 0,116, 0,
+105, 0,111, 0,110, 0, 32, 0,102, 0,105, 0,108, 0,101, 0,115, 0, 32, 0, 40, 0,116, 0,104, 0,101, 0, 32, 0, 34, 0,
+ 70, 0,111, 0,110, 0,116, 0, 32, 0, 83, 0,111, 0,102, 0,116, 0,119, 0, 97, 0,114, 0,101, 0, 34, 0, 41, 0, 44, 0,
+ 32, 0,116, 0,111, 0, 32, 0,114, 0,101, 0,112, 0,114, 0,111, 0,100, 0,117, 0, 99, 0,101, 0, 10, 0, 97, 0,110, 0,
+100, 0, 32, 0,100, 0,105, 0,115, 0,116, 0,114, 0,105, 0, 98, 0,117, 0,116, 0,101, 0, 32, 0,116, 0,104, 0,101, 0,
+ 32, 0,109, 0,111, 0,100, 0,105, 0,102, 0,105, 0, 99, 0, 97, 0,116, 0,105, 0,111, 0,110, 0,115, 0, 32, 0,116, 0,
+111, 0, 32, 0,116, 0,104, 0,101, 0, 32, 0, 66, 0,105, 0,116, 0,115, 0,116, 0,114, 0,101, 0, 97, 0,109, 0, 32, 0,
+ 86, 0,101, 0,114, 0, 97, 0, 32, 0, 70, 0,111, 0,110, 0,116, 0, 32, 0, 83, 0,111, 0,102, 0,116, 0,119, 0, 97, 0,
+114, 0,101, 0, 44, 0, 10, 0,105, 0,110, 0, 99, 0,108, 0,117, 0,100, 0,105, 0,110, 0,103, 0, 32, 0,119, 0,105, 0,
+116, 0,104, 0,111, 0,117, 0,116, 0, 32, 0,108, 0,105, 0,109, 0,105, 0,116, 0, 97, 0,116, 0,105, 0,111, 0,110, 0,
+ 32, 0,116, 0,104, 0,101, 0, 32, 0,114, 0,105, 0,103, 0,104, 0,116, 0,115, 0, 32, 0,116, 0,111, 0, 32, 0,117, 0,
+115, 0,101, 0, 44, 0, 32, 0, 99, 0,111, 0,112, 0,121, 0, 44, 0, 32, 0,109, 0,101, 0,114, 0,103, 0,101, 0, 44, 0,
+ 32, 0,112, 0,117, 0, 98, 0,108, 0,105, 0,115, 0,104, 0, 44, 0, 10, 0,100, 0,105, 0,115, 0,116, 0,114, 0,105, 0,
+ 98, 0,117, 0,116, 0,101, 0, 44, 0, 32, 0, 97, 0,110, 0,100, 0, 47, 0,111, 0,114, 0, 32, 0,115, 0,101, 0,108, 0,
+108, 0, 32, 0, 99, 0,111, 0,112, 0,105, 0,101, 0,115, 0, 32, 0,111, 0,102, 0, 32, 0,116, 0,104, 0,101, 0, 32, 0,
+ 70, 0,111, 0,110, 0,116, 0, 32, 0, 83, 0,111, 0,102, 0,116, 0,119, 0, 97, 0,114, 0,101, 0, 44, 0, 32, 0, 97, 0,
+110, 0,100, 0, 32, 0,116, 0,111, 0, 32, 0,112, 0,101, 0,114, 0,109, 0,105, 0,116, 0, 10, 0,112, 0,101, 0,114, 0,
+115, 0,111, 0,110, 0,115, 0, 32, 0,116, 0,111, 0, 32, 0,119, 0,104, 0,111, 0,109, 0, 32, 0,116, 0,104, 0,101, 0,
+ 32, 0, 70, 0,111, 0,110, 0,116, 0, 32, 0, 83, 0,111, 0,102, 0,116, 0,119, 0, 97, 0,114, 0,101, 0, 32, 0,105, 0,
+115, 0, 32, 0,102, 0,117, 0,114, 0,110, 0,105, 0,115, 0,104, 0,101, 0,100, 0, 32, 0,116, 0,111, 0, 32, 0,100, 0,
+111, 0, 32, 0,115, 0,111, 0, 44, 0, 32, 0,115, 0,117, 0, 98, 0,106, 0,101, 0, 99, 0,116, 0, 32, 0,116, 0,111, 0,
+ 10, 0,116, 0,104, 0,101, 0, 32, 0,102, 0,111, 0,108, 0,108, 0,111, 0,119, 0,105, 0,110, 0,103, 0, 32, 0, 99, 0,
+111, 0,110, 0,100, 0,105, 0,116, 0,105, 0,111, 0,110, 0,115, 0, 58, 0, 10, 0, 10, 0, 84, 0,104, 0,101, 0, 32, 0,
+ 97, 0, 98, 0,111, 0,118, 0,101, 0, 32, 0, 99, 0,111, 0,112, 0,121, 0,114, 0,105, 0,103, 0,104, 0,116, 0, 32, 0,
+ 97, 0,110, 0,100, 0, 32, 0,116, 0,114, 0, 97, 0,100, 0,101, 0,109, 0, 97, 0,114, 0,107, 0, 32, 0,110, 0,111, 0,
+116, 0,105, 0, 99, 0,101, 0,115, 0, 32, 0, 97, 0,110, 0,100, 0, 32, 0,116, 0,104, 0,105, 0,115, 0, 32, 0,112, 0,
+101, 0,114, 0,109, 0,105, 0,115, 0,115, 0,105, 0,111, 0,110, 0, 32, 0,110, 0,111, 0,116, 0,105, 0, 99, 0,101, 0,
+ 10, 0,115, 0,104, 0, 97, 0,108, 0,108, 0, 32, 0, 98, 0,101, 0, 32, 0,105, 0,110, 0, 99, 0,108, 0,117, 0,100, 0,
+101, 0,100, 0, 32, 0,105, 0,110, 0, 32, 0, 97, 0,108, 0,108, 0, 32, 0, 99, 0,111, 0,112, 0,105, 0,101, 0,115, 0,
+ 32, 0,111, 0,102, 0, 32, 0,111, 0,110, 0,101, 0, 32, 0,111, 0,114, 0, 32, 0,109, 0,111, 0,114, 0,101, 0, 32, 0,
+111, 0,102, 0, 32, 0,116, 0,104, 0,101, 0, 32, 0, 70, 0,111, 0,110, 0,116, 0, 32, 0, 83, 0,111, 0,102, 0,116, 0,
+119, 0, 97, 0,114, 0,101, 0, 10, 0,116, 0,121, 0,112, 0,101, 0,102, 0, 97, 0, 99, 0,101, 0,115, 0, 46, 0, 10, 0,
+ 10, 0, 84, 0,104, 0,101, 0, 32, 0, 70, 0,111, 0,110, 0,116, 0, 32, 0, 83, 0,111, 0,102, 0,116, 0,119, 0, 97, 0,
+114, 0,101, 0, 32, 0,109, 0, 97, 0,121, 0, 32, 0, 98, 0,101, 0, 32, 0,109, 0,111, 0,100, 0,105, 0,102, 0,105, 0,
+101, 0,100, 0, 44, 0, 32, 0, 97, 0,108, 0,116, 0,101, 0,114, 0,101, 0,100, 0, 44, 0, 32, 0,111, 0,114, 0, 32, 0,
+ 97, 0,100, 0,100, 0,101, 0,100, 0, 32, 0,116, 0,111, 0, 44, 0, 32, 0, 97, 0,110, 0,100, 0, 32, 0,105, 0,110, 0,
+ 10, 0,112, 0, 97, 0,114, 0,116, 0,105, 0, 99, 0,117, 0,108, 0, 97, 0,114, 0, 32, 0,116, 0,104, 0,101, 0, 32, 0,
+100, 0,101, 0,115, 0,105, 0,103, 0,110, 0,115, 0, 32, 0,111, 0,102, 0, 32, 0,103, 0,108, 0,121, 0,112, 0,104, 0,
+115, 0, 32, 0,111, 0,114, 0, 32, 0, 99, 0,104, 0, 97, 0,114, 0, 97, 0, 99, 0,116, 0,101, 0,114, 0,115, 0, 32, 0,
+105, 0,110, 0, 32, 0,116, 0,104, 0,101, 0, 32, 0, 70, 0,111, 0,110, 0,116, 0,115, 0, 32, 0,109, 0, 97, 0,121, 0,
+ 32, 0, 98, 0,101, 0, 10, 0,109, 0,111, 0,100, 0,105, 0,102, 0,105, 0,101, 0,100, 0, 32, 0, 97, 0,110, 0,100, 0,
+ 32, 0, 97, 0,100, 0,100, 0,105, 0,116, 0,105, 0,111, 0,110, 0, 97, 0,108, 0, 32, 0,103, 0,108, 0,121, 0,112, 0,
+104, 0,115, 0, 32, 0,111, 0,114, 0, 32, 0, 99, 0,104, 0, 97, 0,114, 0, 97, 0, 99, 0,116, 0,101, 0,114, 0,115, 0,
+ 32, 0,109, 0, 97, 0,121, 0, 32, 0, 98, 0,101, 0, 32, 0, 97, 0,100, 0,100, 0,101, 0,100, 0, 32, 0,116, 0,111, 0,
+ 32, 0,116, 0,104, 0,101, 0, 10, 0, 70, 0,111, 0,110, 0,116, 0,115, 0, 44, 0, 32, 0,111, 0,110, 0,108, 0,121, 0,
+ 32, 0,105, 0,102, 0, 32, 0,116, 0,104, 0,101, 0, 32, 0,102, 0,111, 0,110, 0,116, 0,115, 0, 32, 0, 97, 0,114, 0,
+101, 0, 32, 0,114, 0,101, 0,110, 0, 97, 0,109, 0,101, 0,100, 0, 32, 0,116, 0,111, 0, 32, 0,110, 0, 97, 0,109, 0,
+101, 0,115, 0, 32, 0,110, 0,111, 0,116, 0, 32, 0, 99, 0,111, 0,110, 0,116, 0, 97, 0,105, 0,110, 0,105, 0,110, 0,
+103, 0, 32, 0,101, 0,105, 0,116, 0,104, 0,101, 0,114, 0, 10, 0,116, 0,104, 0,101, 0, 32, 0,119, 0,111, 0,114, 0,
+100, 0,115, 0, 32, 0, 34, 0, 84, 0, 97, 0,118, 0,109, 0,106, 0,111, 0,110, 0,103, 0, 32, 0, 66, 0, 97, 0,104, 0,
+ 34, 0, 32, 0,111, 0,114, 0, 32, 0,116, 0,104, 0,101, 0, 32, 0,119, 0,111, 0,114, 0,100, 0, 32, 0, 34, 0, 65, 0,
+114, 0,101, 0,118, 0, 34, 0, 46, 0, 10, 0, 10, 0, 84, 0,104, 0,105, 0,115, 0, 32, 0, 76, 0,105, 0, 99, 0,101, 0,
+110, 0,115, 0,101, 0, 32, 0, 98, 0,101, 0, 99, 0,111, 0,109, 0,101, 0,115, 0, 32, 0,110, 0,117, 0,108, 0,108, 0,
+ 32, 0, 97, 0,110, 0,100, 0, 32, 0,118, 0,111, 0,105, 0,100, 0, 32, 0,116, 0,111, 0, 32, 0,116, 0,104, 0,101, 0,
+ 32, 0,101, 0,120, 0,116, 0,101, 0,110, 0,116, 0, 32, 0, 97, 0,112, 0,112, 0,108, 0,105, 0, 99, 0, 97, 0, 98, 0,
+108, 0,101, 0, 32, 0,116, 0,111, 0, 32, 0, 70, 0,111, 0,110, 0,116, 0,115, 0, 10, 0,111, 0,114, 0, 32, 0, 70, 0,
+111, 0,110, 0,116, 0, 32, 0, 83, 0,111, 0,102, 0,116, 0,119, 0, 97, 0,114, 0,101, 0, 32, 0,116, 0,104, 0, 97, 0,
+116, 0, 32, 0,104, 0, 97, 0,115, 0, 32, 0, 98, 0,101, 0,101, 0,110, 0, 32, 0,109, 0,111, 0,100, 0,105, 0,102, 0,
+105, 0,101, 0,100, 0, 32, 0, 97, 0,110, 0,100, 0, 32, 0,105, 0,115, 0, 32, 0,100, 0,105, 0,115, 0,116, 0,114, 0,
+105, 0, 98, 0,117, 0,116, 0,101, 0,100, 0, 32, 0,117, 0,110, 0,100, 0,101, 0,114, 0, 32, 0,116, 0,104, 0,101, 0,
+ 32, 0, 10, 0, 34, 0, 84, 0, 97, 0,118, 0,109, 0,106, 0,111, 0,110, 0,103, 0, 32, 0, 66, 0, 97, 0,104, 0, 32, 0,
+ 65, 0,114, 0,101, 0,118, 0, 34, 0, 32, 0,110, 0, 97, 0,109, 0,101, 0,115, 0, 46, 0, 10, 0, 10, 0, 84, 0,104, 0,
+101, 0, 32, 0, 70, 0,111, 0,110, 0,116, 0, 32, 0, 83, 0,111, 0,102, 0,116, 0,119, 0, 97, 0,114, 0,101, 0, 32, 0,
+109, 0, 97, 0,121, 0, 32, 0, 98, 0,101, 0, 32, 0,115, 0,111, 0,108, 0,100, 0, 32, 0, 97, 0,115, 0, 32, 0,112, 0,
+ 97, 0,114, 0,116, 0, 32, 0,111, 0,102, 0, 32, 0, 97, 0, 32, 0,108, 0, 97, 0,114, 0,103, 0,101, 0,114, 0, 32, 0,
+115, 0,111, 0,102, 0,116, 0,119, 0, 97, 0,114, 0,101, 0, 32, 0,112, 0, 97, 0, 99, 0,107, 0, 97, 0,103, 0,101, 0,
+ 32, 0, 98, 0,117, 0,116, 0, 10, 0,110, 0,111, 0, 32, 0, 99, 0,111, 0,112, 0,121, 0, 32, 0,111, 0,102, 0, 32, 0,
+111, 0,110, 0,101, 0, 32, 0,111, 0,114, 0, 32, 0,109, 0,111, 0,114, 0,101, 0, 32, 0,111, 0,102, 0, 32, 0,116, 0,
+104, 0,101, 0, 32, 0, 70, 0,111, 0,110, 0,116, 0, 32, 0, 83, 0,111, 0,102, 0,116, 0,119, 0, 97, 0,114, 0,101, 0,
+ 32, 0,116, 0,121, 0,112, 0,101, 0,102, 0, 97, 0, 99, 0,101, 0,115, 0, 32, 0,109, 0, 97, 0,121, 0, 32, 0, 98, 0,
+101, 0, 32, 0,115, 0,111, 0,108, 0,100, 0, 32, 0, 98, 0,121, 0, 10, 0,105, 0,116, 0,115, 0,101, 0,108, 0,102, 0,
+ 46, 0, 10, 0, 10, 0, 84, 0, 72, 0, 69, 0, 32, 0, 70, 0, 79, 0, 78, 0, 84, 0, 32, 0, 83, 0, 79, 0, 70, 0, 84, 0,
+ 87, 0, 65, 0, 82, 0, 69, 0, 32, 0, 73, 0, 83, 0, 32, 0, 80, 0, 82, 0, 79, 0, 86, 0, 73, 0, 68, 0, 69, 0, 68, 0,
+ 32, 0, 34, 0, 65, 0, 83, 0, 32, 0, 73, 0, 83, 0, 34, 0, 44, 0, 32, 0, 87, 0, 73, 0, 84, 0, 72, 0, 79, 0, 85, 0,
+ 84, 0, 32, 0, 87, 0, 65, 0, 82, 0, 82, 0, 65, 0, 78, 0, 84, 0, 89, 0, 32, 0, 79, 0, 70, 0, 32, 0, 65, 0, 78, 0,
+ 89, 0, 32, 0, 75, 0, 73, 0, 78, 0, 68, 0, 44, 0, 10, 0, 69, 0, 88, 0, 80, 0, 82, 0, 69, 0, 83, 0, 83, 0, 32, 0,
+ 79, 0, 82, 0, 32, 0, 73, 0, 77, 0, 80, 0, 76, 0, 73, 0, 69, 0, 68, 0, 44, 0, 32, 0, 73, 0, 78, 0, 67, 0, 76, 0,
+ 85, 0, 68, 0, 73, 0, 78, 0, 71, 0, 32, 0, 66, 0, 85, 0, 84, 0, 32, 0, 78, 0, 79, 0, 84, 0, 32, 0, 76, 0, 73, 0,
+ 77, 0, 73, 0, 84, 0, 69, 0, 68, 0, 32, 0, 84, 0, 79, 0, 32, 0, 65, 0, 78, 0, 89, 0, 32, 0, 87, 0, 65, 0, 82, 0,
+ 82, 0, 65, 0, 78, 0, 84, 0, 73, 0, 69, 0, 83, 0, 32, 0, 79, 0, 70, 0, 10, 0, 77, 0, 69, 0, 82, 0, 67, 0, 72, 0,
+ 65, 0, 78, 0, 84, 0, 65, 0, 66, 0, 73, 0, 76, 0, 73, 0, 84, 0, 89, 0, 44, 0, 32, 0, 70, 0, 73, 0, 84, 0, 78, 0,
+ 69, 0, 83, 0, 83, 0, 32, 0, 70, 0, 79, 0, 82, 0, 32, 0, 65, 0, 32, 0, 80, 0, 65, 0, 82, 0, 84, 0, 73, 0, 67, 0,
+ 85, 0, 76, 0, 65, 0, 82, 0, 32, 0, 80, 0, 85, 0, 82, 0, 80, 0, 79, 0, 83, 0, 69, 0, 32, 0, 65, 0, 78, 0, 68, 0,
+ 32, 0, 78, 0, 79, 0, 78, 0, 73, 0, 78, 0, 70, 0, 82, 0, 73, 0, 78, 0, 71, 0, 69, 0, 77, 0, 69, 0, 78, 0, 84, 0,
+ 10, 0, 79, 0, 70, 0, 32, 0, 67, 0, 79, 0, 80, 0, 89, 0, 82, 0, 73, 0, 71, 0, 72, 0, 84, 0, 44, 0, 32, 0, 80, 0,
+ 65, 0, 84, 0, 69, 0, 78, 0, 84, 0, 44, 0, 32, 0, 84, 0, 82, 0, 65, 0, 68, 0, 69, 0, 77, 0, 65, 0, 82, 0, 75, 0,
+ 44, 0, 32, 0, 79, 0, 82, 0, 32, 0, 79, 0, 84, 0, 72, 0, 69, 0, 82, 0, 32, 0, 82, 0, 73, 0, 71, 0, 72, 0, 84, 0,
+ 46, 0, 32, 0, 73, 0, 78, 0, 32, 0, 78, 0, 79, 0, 32, 0, 69, 0, 86, 0, 69, 0, 78, 0, 84, 0, 32, 0, 83, 0, 72, 0,
+ 65, 0, 76, 0, 76, 0, 10, 0, 84, 0, 65, 0, 86, 0, 77, 0, 74, 0, 79, 0, 78, 0, 71, 0, 32, 0, 66, 0, 65, 0, 72, 0,
+ 32, 0, 66, 0, 69, 0, 32, 0, 76, 0, 73, 0, 65, 0, 66, 0, 76, 0, 69, 0, 32, 0, 70, 0, 79, 0, 82, 0, 32, 0, 65, 0,
+ 78, 0, 89, 0, 32, 0, 67, 0, 76, 0, 65, 0, 73, 0, 77, 0, 44, 0, 32, 0, 68, 0, 65, 0, 77, 0, 65, 0, 71, 0, 69, 0,
+ 83, 0, 32, 0, 79, 0, 82, 0, 32, 0, 79, 0, 84, 0, 72, 0, 69, 0, 82, 0, 32, 0, 76, 0, 73, 0, 65, 0, 66, 0, 73, 0,
+ 76, 0, 73, 0, 84, 0, 89, 0, 44, 0, 10, 0, 73, 0, 78, 0, 67, 0, 76, 0, 85, 0, 68, 0, 73, 0, 78, 0, 71, 0, 32, 0,
+ 65, 0, 78, 0, 89, 0, 32, 0, 71, 0, 69, 0, 78, 0, 69, 0, 82, 0, 65, 0, 76, 0, 44, 0, 32, 0, 83, 0, 80, 0, 69, 0,
+ 67, 0, 73, 0, 65, 0, 76, 0, 44, 0, 32, 0, 73, 0, 78, 0, 68, 0, 73, 0, 82, 0, 69, 0, 67, 0, 84, 0, 44, 0, 32, 0,
+ 73, 0, 78, 0, 67, 0, 73, 0, 68, 0, 69, 0, 78, 0, 84, 0, 65, 0, 76, 0, 44, 0, 32, 0, 79, 0, 82, 0, 32, 0, 67, 0,
+ 79, 0, 78, 0, 83, 0, 69, 0, 81, 0, 85, 0, 69, 0, 78, 0, 84, 0, 73, 0, 65, 0, 76, 0, 10, 0, 68, 0, 65, 0, 77, 0,
+ 65, 0, 71, 0, 69, 0, 83, 0, 44, 0, 32, 0, 87, 0, 72, 0, 69, 0, 84, 0, 72, 0, 69, 0, 82, 0, 32, 0, 73, 0, 78, 0,
+ 32, 0, 65, 0, 78, 0, 32, 0, 65, 0, 67, 0, 84, 0, 73, 0, 79, 0, 78, 0, 32, 0, 79, 0, 70, 0, 32, 0, 67, 0, 79, 0,
+ 78, 0, 84, 0, 82, 0, 65, 0, 67, 0, 84, 0, 44, 0, 32, 0, 84, 0, 79, 0, 82, 0, 84, 0, 32, 0, 79, 0, 82, 0, 32, 0,
+ 79, 0, 84, 0, 72, 0, 69, 0, 82, 0, 87, 0, 73, 0, 83, 0, 69, 0, 44, 0, 32, 0, 65, 0, 82, 0, 73, 0, 83, 0, 73, 0,
+ 78, 0, 71, 0, 10, 0, 70, 0, 82, 0, 79, 0, 77, 0, 44, 0, 32, 0, 79, 0, 85, 0, 84, 0, 32, 0, 79, 0, 70, 0, 32, 0,
+ 84, 0, 72, 0, 69, 0, 32, 0, 85, 0, 83, 0, 69, 0, 32, 0, 79, 0, 82, 0, 32, 0, 73, 0, 78, 0, 65, 0, 66, 0, 73, 0,
+ 76, 0, 73, 0, 84, 0, 89, 0, 32, 0, 84, 0, 79, 0, 32, 0, 85, 0, 83, 0, 69, 0, 32, 0, 84, 0, 72, 0, 69, 0, 32, 0,
+ 70, 0, 79, 0, 78, 0, 84, 0, 32, 0, 83, 0, 79, 0, 70, 0, 84, 0, 87, 0, 65, 0, 82, 0, 69, 0, 32, 0, 79, 0, 82, 0,
+ 32, 0, 70, 0, 82, 0, 79, 0, 77, 0, 10, 0, 79, 0, 84, 0, 72, 0, 69, 0, 82, 0, 32, 0, 68, 0, 69, 0, 65, 0, 76, 0,
+ 73, 0, 78, 0, 71, 0, 83, 0, 32, 0, 73, 0, 78, 0, 32, 0, 84, 0, 72, 0, 69, 0, 32, 0, 70, 0, 79, 0, 78, 0, 84, 0,
+ 32, 0, 83, 0, 79, 0, 70, 0, 84, 0, 87, 0, 65, 0, 82, 0, 69, 0, 46, 0, 10, 0, 10, 0, 69, 0,120, 0, 99, 0,101, 0,
+112, 0,116, 0, 32, 0, 97, 0,115, 0, 32, 0, 99, 0,111, 0,110, 0,116, 0, 97, 0,105, 0,110, 0,101, 0,100, 0, 32, 0,
+105, 0,110, 0, 32, 0,116, 0,104, 0,105, 0,115, 0, 32, 0,110, 0,111, 0,116, 0,105, 0, 99, 0,101, 0, 44, 0, 32, 0,
+116, 0,104, 0,101, 0, 32, 0,110, 0, 97, 0,109, 0,101, 0, 32, 0,111, 0,102, 0, 32, 0, 84, 0, 97, 0,118, 0,109, 0,
+106, 0,111, 0,110, 0,103, 0, 32, 0, 66, 0, 97, 0,104, 0, 32, 0,115, 0,104, 0, 97, 0,108, 0,108, 0, 32, 0,110, 0,
+111, 0,116, 0, 10, 0, 98, 0,101, 0, 32, 0,117, 0,115, 0,101, 0,100, 0, 32, 0,105, 0,110, 0, 32, 0, 97, 0,100, 0,
+118, 0,101, 0,114, 0,116, 0,105, 0,115, 0,105, 0,110, 0,103, 0, 32, 0,111, 0,114, 0, 32, 0,111, 0,116, 0,104, 0,
+101, 0,114, 0,119, 0,105, 0,115, 0,101, 0, 32, 0,116, 0,111, 0, 32, 0,112, 0,114, 0,111, 0,109, 0,111, 0,116, 0,
+101, 0, 32, 0,116, 0,104, 0,101, 0, 32, 0,115, 0, 97, 0,108, 0,101, 0, 44, 0, 32, 0,117, 0,115, 0,101, 0, 32, 0,
+111, 0,114, 0, 32, 0,111, 0,116, 0,104, 0,101, 0,114, 0, 10, 0,100, 0,101, 0, 97, 0,108, 0,105, 0,110, 0,103, 0,
+115, 0, 32, 0,105, 0,110, 0, 32, 0,116, 0,104, 0,105, 0,115, 0, 32, 0, 70, 0,111, 0,110, 0,116, 0, 32, 0, 83, 0,
+111, 0,102, 0,116, 0,119, 0, 97, 0,114, 0,101, 0, 32, 0,119, 0,105, 0,116, 0,104, 0,111, 0,117, 0,116, 0, 32, 0,
+112, 0,114, 0,105, 0,111, 0,114, 0, 32, 0,119, 0,114, 0,105, 0,116, 0,116, 0,101, 0,110, 0, 32, 0, 97, 0,117, 0,
+116, 0,104, 0,111, 0,114, 0,105, 0,122, 0, 97, 0,116, 0,105, 0,111, 0,110, 0, 10, 0,102, 0,114, 0,111, 0,109, 0,
+ 32, 0, 84, 0, 97, 0,118, 0,109, 0,106, 0,111, 0,110, 0,103, 0, 32, 0, 66, 0, 97, 0,104, 0, 46, 0, 32, 0, 70, 0,
+111, 0,114, 0, 32, 0,102, 0,117, 0,114, 0,116, 0,104, 0,101, 0,114, 0, 32, 0,105, 0,110, 0,102, 0,111, 0,114, 0,
+109, 0, 97, 0,116, 0,105, 0,111, 0,110, 0, 44, 0, 32, 0, 99, 0,111, 0,110, 0,116, 0, 97, 0, 99, 0,116, 0, 58, 0,
+ 32, 0,116, 0, 97, 0,118, 0,109, 0,106, 0,111, 0,110, 0,103, 0, 32, 0, 64, 0, 32, 0,102, 0,114, 0,101, 0,101, 0,
+ 10, 0, 46, 0, 32, 0,102, 0,114, 0, 46, 0, 0, 70,111,110,116,115, 32, 97,114,101, 32, 40, 99, 41, 32, 66,105,116,115,116,
+114,101, 97,109, 32, 40,115,101,101, 32, 98,101,108,111,119, 41, 46, 32, 68,101,106, 97, 86,117, 32, 99,104, 97,110,103,101,115,
+ 32, 97,114,101, 32,105,110, 32,112,117, 98,108,105, 99, 32,100,111,109, 97,105,110, 46, 32, 71,108,121,112,104,115, 32,105,109,
+112,111,114,116,101,100, 32,102,114,111,109, 32, 65,114,101,118, 32,102,111,110,116,115, 32, 97,114,101, 32, 40, 99, 41, 32, 84,
+ 97,118,109,106,117,110,103, 32, 66, 97,104, 32, 40,115,101,101, 32, 98,101,108,111,119, 41, 10, 10, 66,105,116,115,116,114,101,
+ 97,109, 32, 86,101,114, 97, 32, 70,111,110,116,115, 32, 67,111,112,121,114,105,103,104,116, 10, 45, 45, 45, 45, 45, 45, 45, 45,
+ 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 10, 10, 67,111,112,121,114,105,103,104,
+116, 32, 40, 99, 41, 32, 50, 48, 48, 51, 32, 98,121, 32, 66,105,116,115,116,114,101, 97,109, 44, 32, 73,110, 99, 46, 32, 65,108,
+108, 32, 82,105,103,104,116,115, 32, 82,101,115,101,114,118,101,100, 46, 32, 66,105,116,115,116,114,101, 97,109, 32, 86,101,114,
+ 97, 32,105,115, 10, 97, 32,116,114, 97,100,101,109, 97,114,107, 32,111,102, 32, 66,105,116,115,116,114,101, 97,109, 44, 32, 73,
+110, 99, 46, 10, 10, 80,101,114,109,105,115,115,105,111,110, 32,105,115, 32,104,101,114,101, 98,121, 32,103,114, 97,110,116,101,
+100, 44, 32,102,114,101,101, 32,111,102, 32, 99,104, 97,114,103,101, 44, 32,116,111, 32, 97,110,121, 32,112,101,114,115,111,110,
+ 32,111, 98,116, 97,105,110,105,110,103, 32, 97, 32, 99,111,112,121, 10,111,102, 32,116,104,101, 32,102,111,110,116,115, 32, 97,
+ 99, 99,111,109,112, 97,110,121,105,110,103, 32,116,104,105,115, 32,108,105, 99,101,110,115,101, 32, 40, 34, 70,111,110,116,115,
+ 34, 41, 32, 97,110,100, 32, 97,115,115,111, 99,105, 97,116,101,100, 10,100,111, 99,117,109,101,110,116, 97,116,105,111,110, 32,
+102,105,108,101,115, 32, 40,116,104,101, 32, 34, 70,111,110,116, 32, 83,111,102,116,119, 97,114,101, 34, 41, 44, 32,116,111, 32,
+114,101,112,114,111,100,117, 99,101, 32, 97,110,100, 32,100,105,115,116,114,105, 98,117,116,101, 32,116,104,101, 10, 70,111,110,
+116, 32, 83,111,102,116,119, 97,114,101, 44, 32,105,110, 99,108,117,100,105,110,103, 32,119,105,116,104,111,117,116, 32,108,105,
+109,105,116, 97,116,105,111,110, 32,116,104,101, 32,114,105,103,104,116,115, 32,116,111, 32,117,115,101, 44, 32, 99,111,112,121,
+ 44, 32,109,101,114,103,101, 44, 10,112,117, 98,108,105,115,104, 44, 32,100,105,115,116,114,105, 98,117,116,101, 44, 32, 97,110,
+100, 47,111,114, 32,115,101,108,108, 32, 99,111,112,105,101,115, 32,111,102, 32,116,104,101, 32, 70,111,110,116, 32, 83,111,102,
+116,119, 97,114,101, 44, 32, 97,110,100, 32,116,111, 32,112,101,114,109,105,116, 10,112,101,114,115,111,110,115, 32,116,111, 32,
+119,104,111,109, 32,116,104,101, 32, 70,111,110,116, 32, 83,111,102,116,119, 97,114,101, 32,105,115, 32,102,117,114,110,105,115,
+104,101,100, 32,116,111, 32,100,111, 32,115,111, 44, 32,115,117, 98,106,101, 99,116, 32,116,111, 32,116,104,101, 10,102,111,108,
+108,111,119,105,110,103, 32, 99,111,110,100,105,116,105,111,110,115, 58, 10, 10, 84,104,101, 32, 97, 98,111,118,101, 32, 99,111,
+112,121,114,105,103,104,116, 32, 97,110,100, 32,116,114, 97,100,101,109, 97,114,107, 32,110,111,116,105, 99,101,115, 32, 97,110,
+100, 32,116,104,105,115, 32,112,101,114,109,105,115,115,105,111,110, 32,110,111,116,105, 99,101, 32,115,104, 97,108,108, 10, 98,
+101, 32,105,110, 99,108,117,100,101,100, 32,105,110, 32, 97,108,108, 32, 99,111,112,105,101,115, 32,111,102, 32,111,110,101, 32,
+111,114, 32,109,111,114,101, 32,111,102, 32,116,104,101, 32, 70,111,110,116, 32, 83,111,102,116,119, 97,114,101, 32,116,121,112,
+101,102, 97, 99,101,115, 46, 10, 10, 84,104,101, 32, 70,111,110,116, 32, 83,111,102,116,119, 97,114,101, 32,109, 97,121, 32, 98,
+101, 32,109,111,100,105,102,105,101,100, 44, 32, 97,108,116,101,114,101,100, 44, 32,111,114, 32, 97,100,100,101,100, 32,116,111,
+ 44, 32, 97,110,100, 32,105,110, 32,112, 97,114,116,105, 99,117,108, 97,114, 10,116,104,101, 32,100,101,115,105,103,110,115, 32,
+111,102, 32,103,108,121,112,104,115, 32,111,114, 32, 99,104, 97,114, 97, 99,116,101,114,115, 32,105,110, 32,116,104,101, 32, 70,
+111,110,116,115, 32,109, 97,121, 32, 98,101, 32,109,111,100,105,102,105,101,100, 32, 97,110,100, 10, 97,100,100,105,116,105,111,
+110, 97,108, 32,103,108,121,112,104,115, 32,111,114, 32, 99,104, 97,114, 97, 99,116,101,114,115, 32,109, 97,121, 32, 98,101, 32,
+ 97,100,100,101,100, 32,116,111, 32,116,104,101, 32, 70,111,110,116,115, 44, 32,111,110,108,121, 32,105,102, 32,116,104,101, 32,
+102,111,110,116,115, 10, 97,114,101, 32,114,101,110, 97,109,101,100, 32,116,111, 32,110, 97,109,101,115, 32,110,111,116, 32, 99,
+111,110,116, 97,105,110,105,110,103, 32,101,105,116,104,101,114, 32,116,104,101, 32,119,111,114,100,115, 32, 34, 66,105,116,115,
+116,114,101, 97,109, 34, 32,111,114, 32,116,104,101, 32,119,111,114,100, 10, 34, 86,101,114, 97, 34, 46, 10, 10, 84,104,105,115,
+ 32, 76,105, 99,101,110,115,101, 32, 98,101, 99,111,109,101,115, 32,110,117,108,108, 32, 97,110,100, 32,118,111,105,100, 32,116,
+111, 32,116,104,101, 32,101,120,116,101,110,116, 32, 97,112,112,108,105, 99, 97, 98,108,101, 32,116,111, 32, 70,111,110,116,115,
+ 32,111,114, 32, 70,111,110,116, 10, 83,111,102,116,119, 97,114,101, 32,116,104, 97,116, 32,104, 97,115, 32, 98,101,101,110, 32,
+109,111,100,105,102,105,101,100, 32, 97,110,100, 32,105,115, 32,100,105,115,116,114,105, 98,117,116,101,100, 32,117,110,100,101,
+114, 32,116,104,101, 32, 34, 66,105,116,115,116,114,101, 97,109, 10, 86,101,114, 97, 34, 32,110, 97,109,101,115, 46, 10, 10, 84,
+104,101, 32, 70,111,110,116, 32, 83,111,102,116,119, 97,114,101, 32,109, 97,121, 32, 98,101, 32,115,111,108,100, 32, 97,115, 32,
+112, 97,114,116, 32,111,102, 32, 97, 32,108, 97,114,103,101,114, 32,115,111,102,116,119, 97,114,101, 32,112, 97, 99,107, 97,103,
+101, 32, 98,117,116, 32,110,111, 10, 99,111,112,121, 32,111,102, 32,111,110,101, 32,111,114, 32,109,111,114,101, 32,111,102, 32,
+116,104,101, 32, 70,111,110,116, 32, 83,111,102,116,119, 97,114,101, 32,116,121,112,101,102, 97, 99,101,115, 32,109, 97,121, 32,
+ 98,101, 32,115,111,108,100, 32, 98,121, 32,105,116,115,101,108,102, 46, 10, 10, 84, 72, 69, 32, 70, 79, 78, 84, 32, 83, 79, 70,
+ 84, 87, 65, 82, 69, 32, 73, 83, 32, 80, 82, 79, 86, 73, 68, 69, 68, 32, 34, 65, 83, 32, 73, 83, 34, 44, 32, 87, 73, 84, 72, 79,
+ 85, 84, 32, 87, 65, 82, 82, 65, 78, 84, 89, 32, 79, 70, 32, 65, 78, 89, 32, 75, 73, 78, 68, 44, 32, 69, 88, 80, 82, 69, 83, 83,
+ 10, 79, 82, 32, 73, 77, 80, 76, 73, 69, 68, 44, 32, 73, 78, 67, 76, 85, 68, 73, 78, 71, 32, 66, 85, 84, 32, 78, 79, 84, 32, 76,
+ 73, 77, 73, 84, 69, 68, 32, 84, 79, 32, 65, 78, 89, 32, 87, 65, 82, 82, 65, 78, 84, 73, 69, 83, 32, 79, 70, 32, 77, 69, 82, 67,
+ 72, 65, 78, 84, 65, 66, 73, 76, 73, 84, 89, 44, 10, 70, 73, 84, 78, 69, 83, 83, 32, 70, 79, 82, 32, 65, 32, 80, 65, 82, 84, 73,
+ 67, 85, 76, 65, 82, 32, 80, 85, 82, 80, 79, 83, 69, 32, 65, 78, 68, 32, 78, 79, 78, 73, 78, 70, 82, 73, 78, 71, 69, 77, 69, 78,
+ 84, 32, 79, 70, 32, 67, 79, 80, 89, 82, 73, 71, 72, 84, 44, 32, 80, 65, 84, 69, 78, 84, 44, 10, 84, 82, 65, 68, 69, 77, 65, 82,
+ 75, 44, 32, 79, 82, 32, 79, 84, 72, 69, 82, 32, 82, 73, 71, 72, 84, 46, 32, 73, 78, 32, 78, 79, 32, 69, 86, 69, 78, 84, 32, 83,
+ 72, 65, 76, 76, 32, 66, 73, 84, 83, 84, 82, 69, 65, 77, 32, 79, 82, 32, 84, 72, 69, 32, 71, 78, 79, 77, 69, 10, 70, 79, 85, 78,
+ 68, 65, 84, 73, 79, 78, 32, 66, 69, 32, 76, 73, 65, 66, 76, 69, 32, 70, 79, 82, 32, 65, 78, 89, 32, 67, 76, 65, 73, 77, 44, 32,
+ 68, 65, 77, 65, 71, 69, 83, 32, 79, 82, 32, 79, 84, 72, 69, 82, 32, 76, 73, 65, 66, 73, 76, 73, 84, 89, 44, 32, 73, 78, 67, 76,
+ 85, 68, 73, 78, 71, 10, 65, 78, 89, 32, 71, 69, 78, 69, 82, 65, 76, 44, 32, 83, 80, 69, 67, 73, 65, 76, 44, 32, 73, 78, 68, 73,
+ 82, 69, 67, 84, 44, 32, 73, 78, 67, 73, 68, 69, 78, 84, 65, 76, 44, 32, 79, 82, 32, 67, 79, 78, 83, 69, 81, 85, 69, 78, 84, 73,
+ 65, 76, 32, 68, 65, 77, 65, 71, 69, 83, 44, 10, 87, 72, 69, 84, 72, 69, 82, 32, 73, 78, 32, 65, 78, 32, 65, 67, 84, 73, 79, 78,
+ 32, 79, 70, 32, 67, 79, 78, 84, 82, 65, 67, 84, 44, 32, 84, 79, 82, 84, 32, 79, 82, 32, 79, 84, 72, 69, 82, 87, 73, 83, 69, 44,
+ 32, 65, 82, 73, 83, 73, 78, 71, 32, 70, 82, 79, 77, 44, 32, 79, 85, 84, 32, 79, 70, 10, 84, 72, 69, 32, 85, 83, 69, 32, 79, 82,
+ 32, 73, 78, 65, 66, 73, 76, 73, 84, 89, 32, 84, 79, 32, 85, 83, 69, 32, 84, 72, 69, 32, 70, 79, 78, 84, 32, 83, 79, 70, 84, 87,
+ 65, 82, 69, 32, 79, 82, 32, 70, 82, 79, 77, 32, 79, 84, 72, 69, 82, 32, 68, 69, 65, 76, 73, 78, 71, 83, 32, 73, 78, 32, 84, 72,
+ 69, 10, 70, 79, 78, 84, 32, 83, 79, 70, 84, 87, 65, 82, 69, 46, 10, 10, 69,120, 99,101,112,116, 32, 97,115, 32, 99,111,110,116,
+ 97,105,110,101,100, 32,105,110, 32,116,104,105,115, 32,110,111,116,105, 99,101, 44, 32,116,104,101, 32,110, 97,109,101,115, 32,
+111,102, 32, 71,110,111,109,101, 44, 32,116,104,101, 32, 71,110,111,109,101, 10, 70,111,117,110,100, 97,116,105,111,110, 44, 32,
+ 97,110,100, 32, 66,105,116,115,116,114,101, 97,109, 32, 73,110, 99, 46, 44, 32,115,104, 97,108,108, 32,110,111,116, 32, 98,101,
+ 32,117,115,101,100, 32,105,110, 32, 97,100,118,101,114,116,105,115,105,110,103, 32,111,114, 10,111,116,104,101,114,119,105,115,
+101, 32,116,111, 32,112,114,111,109,111,116,101, 32,116,104,101, 32,115, 97,108,101, 44, 32,117,115,101, 32,111,114, 32,111,116,
+104,101,114, 32,100,101, 97,108,105,110,103,115, 32,105,110, 32,116,104,105,115, 32, 70,111,110,116, 32, 83,111,102,116,119, 97,
+114,101, 10,119,105,116,104,111,117,116, 32,112,114,105,111,114, 32,119,114,105,116,116,101,110, 32, 97,117,116,104,111,114,105,
+122, 97,116,105,111,110, 32,102,114,111,109, 32,116,104,101, 32, 71,110,111,109,101, 32, 70,111,117,110,100, 97,116,105,111,110,
+ 32,111,114, 32, 66,105,116,115,116,114,101, 97,109, 10, 73,110, 99, 46, 44, 32,114,101,115,112,101, 99,116,105,118,101,108,121,
+ 46, 32, 70,111,114, 32,102,117,114,116,104,101,114, 32,105,110,102,111,114,109, 97,116,105,111,110, 44, 32, 99,111,110,116, 97,
+ 99,116, 58, 32,102,111,110,116,115, 32, 97,116, 32,103,110,111,109,101, 32,100,111,116, 10,111,114,103, 46, 32, 10, 10, 65,114,
+101,118, 32, 70,111,110,116,115, 32, 67,111,112,121,114,105,103,104,116, 10, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+ 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 10, 10, 67,111,112,121,114,105,103,104,116, 32, 40, 99, 41,
+ 32, 50, 48, 48, 54, 32, 98,121, 32, 84, 97,118,109,106,111,110,103, 32, 66, 97,104, 46, 32, 65,108,108, 32, 82,105,103,104,116,
+115, 32, 82,101,115,101,114,118,101,100, 46, 10, 10, 80,101,114,109,105,115,115,105,111,110, 32,105,115, 32,104,101,114,101, 98,
+121, 32,103,114, 97,110,116,101,100, 44, 32,102,114,101,101, 32,111,102, 32, 99,104, 97,114,103,101, 44, 32,116,111, 32, 97,110,
+121, 32,112,101,114,115,111,110, 32,111, 98,116, 97,105,110,105,110,103, 10, 97, 32, 99,111,112,121, 32,111,102, 32,116,104,101,
+ 32,102,111,110,116,115, 32, 97, 99, 99,111,109,112, 97,110,121,105,110,103, 32,116,104,105,115, 32,108,105, 99,101,110,115,101,
+ 32, 40, 34, 70,111,110,116,115, 34, 41, 32, 97,110,100, 10, 97,115,115,111, 99,105, 97,116,101,100, 32,100,111, 99,117,109,101,
+110,116, 97,116,105,111,110, 32,102,105,108,101,115, 32, 40,116,104,101, 32, 34, 70,111,110,116, 32, 83,111,102,116,119, 97,114,
+101, 34, 41, 44, 32,116,111, 32,114,101,112,114,111,100,117, 99,101, 10, 97,110,100, 32,100,105,115,116,114,105, 98,117,116,101,
+ 32,116,104,101, 32,109,111,100,105,102,105, 99, 97,116,105,111,110,115, 32,116,111, 32,116,104,101, 32, 66,105,116,115,116,114,
+101, 97,109, 32, 86,101,114, 97, 32, 70,111,110,116, 32, 83,111,102,116,119, 97,114,101, 44, 10,105,110, 99,108,117,100,105,110,
+103, 32,119,105,116,104,111,117,116, 32,108,105,109,105,116, 97,116,105,111,110, 32,116,104,101, 32,114,105,103,104,116,115, 32,
+116,111, 32,117,115,101, 44, 32, 99,111,112,121, 44, 32,109,101,114,103,101, 44, 32,112,117, 98,108,105,115,104, 44, 10,100,105,
+115,116,114,105, 98,117,116,101, 44, 32, 97,110,100, 47,111,114, 32,115,101,108,108, 32, 99,111,112,105,101,115, 32,111,102, 32,
+116,104,101, 32, 70,111,110,116, 32, 83,111,102,116,119, 97,114,101, 44, 32, 97,110,100, 32,116,111, 32,112,101,114,109,105,116,
+ 10,112,101,114,115,111,110,115, 32,116,111, 32,119,104,111,109, 32,116,104,101, 32, 70,111,110,116, 32, 83,111,102,116,119, 97,
+114,101, 32,105,115, 32,102,117,114,110,105,115,104,101,100, 32,116,111, 32,100,111, 32,115,111, 44, 32,115,117, 98,106,101, 99,
+116, 32,116,111, 10,116,104,101, 32,102,111,108,108,111,119,105,110,103, 32, 99,111,110,100,105,116,105,111,110,115, 58, 10, 10,
+ 84,104,101, 32, 97, 98,111,118,101, 32, 99,111,112,121,114,105,103,104,116, 32, 97,110,100, 32,116,114, 97,100,101,109, 97,114,
+107, 32,110,111,116,105, 99,101,115, 32, 97,110,100, 32,116,104,105,115, 32,112,101,114,109,105,115,115,105,111,110, 32,110,111,
+116,105, 99,101, 10,115,104, 97,108,108, 32, 98,101, 32,105,110, 99,108,117,100,101,100, 32,105,110, 32, 97,108,108, 32, 99,111,
+112,105,101,115, 32,111,102, 32,111,110,101, 32,111,114, 32,109,111,114,101, 32,111,102, 32,116,104,101, 32, 70,111,110,116, 32,
+ 83,111,102,116,119, 97,114,101, 10,116,121,112,101,102, 97, 99,101,115, 46, 10, 10, 84,104,101, 32, 70,111,110,116, 32, 83,111,
+102,116,119, 97,114,101, 32,109, 97,121, 32, 98,101, 32,109,111,100,105,102,105,101,100, 44, 32, 97,108,116,101,114,101,100, 44,
+ 32,111,114, 32, 97,100,100,101,100, 32,116,111, 44, 32, 97,110,100, 32,105,110, 10,112, 97,114,116,105, 99,117,108, 97,114, 32,
+116,104,101, 32,100,101,115,105,103,110,115, 32,111,102, 32,103,108,121,112,104,115, 32,111,114, 32, 99,104, 97,114, 97, 99,116,
+101,114,115, 32,105,110, 32,116,104,101, 32, 70,111,110,116,115, 32,109, 97,121, 32, 98,101, 10,109,111,100,105,102,105,101,100,
+ 32, 97,110,100, 32, 97,100,100,105,116,105,111,110, 97,108, 32,103,108,121,112,104,115, 32,111,114, 32, 99,104, 97,114, 97, 99,
+116,101,114,115, 32,109, 97,121, 32, 98,101, 32, 97,100,100,101,100, 32,116,111, 32,116,104,101, 10, 70,111,110,116,115, 44, 32,
+111,110,108,121, 32,105,102, 32,116,104,101, 32,102,111,110,116,115, 32, 97,114,101, 32,114,101,110, 97,109,101,100, 32,116,111,
+ 32,110, 97,109,101,115, 32,110,111,116, 32, 99,111,110,116, 97,105,110,105,110,103, 32,101,105,116,104,101,114, 10,116,104,101,
+ 32,119,111,114,100,115, 32, 34, 84, 97,118,109,106,111,110,103, 32, 66, 97,104, 34, 32,111,114, 32,116,104,101, 32,119,111,114,
+100, 32, 34, 65,114,101,118, 34, 46, 10, 10, 84,104,105,115, 32, 76,105, 99,101,110,115,101, 32, 98,101, 99,111,109,101,115, 32,
+110,117,108,108, 32, 97,110,100, 32,118,111,105,100, 32,116,111, 32,116,104,101, 32,101,120,116,101,110,116, 32, 97,112,112,108,
+105, 99, 97, 98,108,101, 32,116,111, 32, 70,111,110,116,115, 10,111,114, 32, 70,111,110,116, 32, 83,111,102,116,119, 97,114,101,
+ 32,116,104, 97,116, 32,104, 97,115, 32, 98,101,101,110, 32,109,111,100,105,102,105,101,100, 32, 97,110,100, 32,105,115, 32,100,
+105,115,116,114,105, 98,117,116,101,100, 32,117,110,100,101,114, 32,116,104,101, 32, 10, 34, 84, 97,118,109,106,111,110,103, 32,
+ 66, 97,104, 32, 65,114,101,118, 34, 32,110, 97,109,101,115, 46, 10, 10, 84,104,101, 32, 70,111,110,116, 32, 83,111,102,116,119,
+ 97,114,101, 32,109, 97,121, 32, 98,101, 32,115,111,108,100, 32, 97,115, 32,112, 97,114,116, 32,111,102, 32, 97, 32,108, 97,114,
+103,101,114, 32,115,111,102,116,119, 97,114,101, 32,112, 97, 99,107, 97,103,101, 32, 98,117,116, 10,110,111, 32, 99,111,112,121,
+ 32,111,102, 32,111,110,101, 32,111,114, 32,109,111,114,101, 32,111,102, 32,116,104,101, 32, 70,111,110,116, 32, 83,111,102,116,
+119, 97,114,101, 32,116,121,112,101,102, 97, 99,101,115, 32,109, 97,121, 32, 98,101, 32,115,111,108,100, 32, 98,121, 10,105,116,
+115,101,108,102, 46, 10, 10, 84, 72, 69, 32, 70, 79, 78, 84, 32, 83, 79, 70, 84, 87, 65, 82, 69, 32, 73, 83, 32, 80, 82, 79, 86,
+ 73, 68, 69, 68, 32, 34, 65, 83, 32, 73, 83, 34, 44, 32, 87, 73, 84, 72, 79, 85, 84, 32, 87, 65, 82, 82, 65, 78, 84, 89, 32, 79,
+ 70, 32, 65, 78, 89, 32, 75, 73, 78, 68, 44, 10, 69, 88, 80, 82, 69, 83, 83, 32, 79, 82, 32, 73, 77, 80, 76, 73, 69, 68, 44, 32,
+ 73, 78, 67, 76, 85, 68, 73, 78, 71, 32, 66, 85, 84, 32, 78, 79, 84, 32, 76, 73, 77, 73, 84, 69, 68, 32, 84, 79, 32, 65, 78, 89,
+ 32, 87, 65, 82, 82, 65, 78, 84, 73, 69, 83, 32, 79, 70, 10, 77, 69, 82, 67, 72, 65, 78, 84, 65, 66, 73, 76, 73, 84, 89, 44, 32,
+ 70, 73, 84, 78, 69, 83, 83, 32, 70, 79, 82, 32, 65, 32, 80, 65, 82, 84, 73, 67, 85, 76, 65, 82, 32, 80, 85, 82, 80, 79, 83, 69,
+ 32, 65, 78, 68, 32, 78, 79, 78, 73, 78, 70, 82, 73, 78, 71, 69, 77, 69, 78, 84, 10, 79, 70, 32, 67, 79, 80, 89, 82, 73, 71, 72,
+ 84, 44, 32, 80, 65, 84, 69, 78, 84, 44, 32, 84, 82, 65, 68, 69, 77, 65, 82, 75, 44, 32, 79, 82, 32, 79, 84, 72, 69, 82, 32, 82,
+ 73, 71, 72, 84, 46, 32, 73, 78, 32, 78, 79, 32, 69, 86, 69, 78, 84, 32, 83, 72, 65, 76, 76, 10, 84, 65, 86, 77, 74, 79, 78, 71,
+ 32, 66, 65, 72, 32, 66, 69, 32, 76, 73, 65, 66, 76, 69, 32, 70, 79, 82, 32, 65, 78, 89, 32, 67, 76, 65, 73, 77, 44, 32, 68, 65,
+ 77, 65, 71, 69, 83, 32, 79, 82, 32, 79, 84, 72, 69, 82, 32, 76, 73, 65, 66, 73, 76, 73, 84, 89, 44, 10, 73, 78, 67, 76, 85, 68,
+ 73, 78, 71, 32, 65, 78, 89, 32, 71, 69, 78, 69, 82, 65, 76, 44, 32, 83, 80, 69, 67, 73, 65, 76, 44, 32, 73, 78, 68, 73, 82, 69,
+ 67, 84, 44, 32, 73, 78, 67, 73, 68, 69, 78, 84, 65, 76, 44, 32, 79, 82, 32, 67, 79, 78, 83, 69, 81, 85, 69, 78, 84, 73, 65, 76,
+ 10, 68, 65, 77, 65, 71, 69, 83, 44, 32, 87, 72, 69, 84, 72, 69, 82, 32, 73, 78, 32, 65, 78, 32, 65, 67, 84, 73, 79, 78, 32, 79,
+ 70, 32, 67, 79, 78, 84, 82, 65, 67, 84, 44, 32, 84, 79, 82, 84, 32, 79, 82, 32, 79, 84, 72, 69, 82, 87, 73, 83, 69, 44, 32, 65,
+ 82, 73, 83, 73, 78, 71, 10, 70, 82, 79, 77, 44, 32, 79, 85, 84, 32, 79, 70, 32, 84, 72, 69, 32, 85, 83, 69, 32, 79, 82, 32, 73,
+ 78, 65, 66, 73, 76, 73, 84, 89, 32, 84, 79, 32, 85, 83, 69, 32, 84, 72, 69, 32, 70, 79, 78, 84, 32, 83, 79, 70, 84, 87, 65, 82,
+ 69, 32, 79, 82, 32, 70, 82, 79, 77, 10, 79, 84, 72, 69, 82, 32, 68, 69, 65, 76, 73, 78, 71, 83, 32, 73, 78, 32, 84, 72, 69, 32,
+ 70, 79, 78, 84, 32, 83, 79, 70, 84, 87, 65, 82, 69, 46, 10, 10, 69,120, 99,101,112,116, 32, 97,115, 32, 99,111,110,116, 97,105,
+110,101,100, 32,105,110, 32,116,104,105,115, 32,110,111,116,105, 99,101, 44, 32,116,104,101, 32,110, 97,109,101, 32,111,102, 32,
+ 84, 97,118,109,106,111,110,103, 32, 66, 97,104, 32,115,104, 97,108,108, 32,110,111,116, 10, 98,101, 32,117,115,101,100, 32,105,
+110, 32, 97,100,118,101,114,116,105,115,105,110,103, 32,111,114, 32,111,116,104,101,114,119,105,115,101, 32,116,111, 32,112,114,
+111,109,111,116,101, 32,116,104,101, 32,115, 97,108,101, 44, 32,117,115,101, 32,111,114, 32,111,116,104,101,114, 10,100,101, 97,
+108,105,110,103,115, 32,105,110, 32,116,104,105,115, 32, 70,111,110,116, 32, 83,111,102,116,119, 97,114,101, 32,119,105,116,104,
+111,117,116, 32,112,114,105,111,114, 32,119,114,105,116,116,101,110, 32, 97,117,116,104,111,114,105,122, 97,116,105,111,110, 10,
+102,114,111,109, 32, 84, 97,118,109,106,111,110,103, 32, 66, 97,104, 46, 32, 70,111,114, 32,102,117,114,116,104,101,114, 32,105,
+110,102,111,114,109, 97,116,105,111,110, 44, 32, 99,111,110,116, 97, 99,116, 58, 32,116, 97,118,109,106,111,110,103, 32, 64, 32,
+102,114,101,101, 10, 46, 32,102,114, 46, 0, 0,104, 0,116, 0,116, 0,112, 0, 58, 0, 47, 0, 47, 0,100, 0,101, 0,106, 0,
+ 97, 0,118, 0,117, 0, 46, 0,115, 0,111, 0,117, 0,114, 0, 99, 0,101, 0,102, 0,111, 0,114, 0,103, 0,101, 0, 46, 0,
+110, 0,101, 0,116, 0, 47, 0,119, 0,105, 0,107, 0,105, 0, 47, 0,105, 0,110, 0,100, 0,101, 0,120, 0, 46, 0,112, 0,
+104, 0,112, 0, 47, 0, 76, 0,105, 0, 99, 0,101, 0,110, 0,115, 0,101, 0, 0,104,116,116,112, 58, 47, 47,100,101,106, 97,
+118,117, 46,115,111,117,114, 99,101,102,111,114,103,101, 46,110,101,116, 47,119,105,107,105, 47,105,110,100,101,120, 46,112,104,
+112, 47, 76,105, 99,101,110,115,101, 0, 65,108,108, 32, 84,121,112,111,103,114, 97,112,104,105, 99, 32, 70,101, 97,116,117,114,
+101,115, 0, 70,111,110, 99,116,105,111,110,115, 32,116,121,112,111,103,114, 97,112,104,105,113,117,101,115, 0, 65,108,108,101,
+ 32,116,121,112,111,103,114, 97,102,105,115, 99,104,101,110, 32, 77,154,103,108,105, 99,104,107,101,105,116,101,110, 0, 70,117,
+110,122,105,111,110,105, 32, 84,105,112,111,103,114, 97,102,105, 99,104,101, 0, 65,108,108,101, 32,116,121,112,111,103,114, 97,
+102,105,115, 99,104,101, 32,107,101,110,109,101,114,107,101,110, 0, 76,105,103, 97,116,117,114,101,115, 0, 76,105,103, 97,116,
+117,114,101,115, 0, 76,105,103, 97,116,117,114,101,110, 0, 76,101,103, 97,116,117,114,101, 0, 76,105,103, 97,116,117,114,101,
+110, 0, 67,117,114,115,105,118,101, 32, 99,111,110,110,101, 99,116,105,111,110, 0, 67,111,110,110,101, 99,116,105,111,110, 32,
+100,101,115, 32, 67,117,114,115,105,118,101,115, 0, 67,117,114,115,105,101,118,101, 32,118,101,114, 98,105,110,100,105,110,103,
+ 0, 70,114, 97, 99,116,105,111,110,115, 0, 70,114, 97, 99,116,105,111,110,115, 0, 66,114,101,117,107,101,110, 0, 65,108,108,
+ 32, 84,121,112,101, 32, 70,101, 97,116,117,114,101,115, 0, 84,111,117,116,101,115, 32,102,111,110, 99,116,105,111,110,115, 32,
+116,121,112,111,103,114, 97,112,104,105,113,117,101,115, 0, 65,108,108,101, 32, 65,117,115,122,101,105, 99,104,110,117,110,103,
+115, 97,114,116,101,110, 0, 84,117,116,116,101, 32,108,101, 32, 70,117,110,122,105,111,110,105, 0, 65,108,108,101, 32,116,121,
+112,101,107,101,110,109,101,114,107,101,110, 0, 67,111,109,109,111,110, 32, 76,105,103, 97,116,117,114,101,115, 0, 76,105,103,
+ 97,116,117,114,101,115, 32, 85,115,117,101,108,108,101,115, 0, 78,111,114,109, 97,108,101, 32, 76,105,103, 97,116,117,114,101,
+110, 0, 76,101,103, 97,116,117,114,101, 32,112,105,157, 32, 67,111,109,117,110,105, 0, 71,101,109,101,101,110,115, 99,104, 97,
+112,112,101,108,105,106,107,101, 32, 76,105,103, 97,116,117,114,101,110, 0, 82, 97,114,101, 32, 76,105,103, 97,116,117,114,101,
+115, 0, 76,105,103, 97,116,117,114,101,115, 32, 82, 97,114,101,115, 0, 83,101,108,116,101,110,101, 32, 76,105,103, 97,116,117,
+114,101,110, 0, 76,101,103, 97,116,117,114,101, 32, 82, 97,114,101, 0, 90,101,108,100,122, 97,109,101, 32,108,105,103, 97,116,
+117,114,101,110, 0, 67,117,114,115,105,118,101, 0, 80,108,101,105,110,101,109,101,110,116, 32, 99,111,110,110,101, 99,116,142,
+101,115, 0, 67,117,114,115,105,101,102, 0, 68,105, 97,103,111,110, 97,108, 32, 70,114, 97, 99,116,105,111,110,115, 0, 70,114,
+ 97, 99,116,105,111,110,115, 32,101,110, 32, 68,105, 97,103,111,110, 97,108,101, 0, 68,105, 97,103,111,110, 97,108,101,114, 32,
+ 66,114,117, 99,104, 0, 70,114, 97,122,105,111,110,105, 32, 68,105, 97,103,111,110, 97,108,105, 0, 68,105, 97,103,111,110, 97,
+108,101, 32, 98,114,101,117,107,101,110, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0,255,171, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6,163, 0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8,
+ 0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 16, 0, 17, 0, 18, 0, 19, 0, 20, 0, 21, 0, 22, 0, 23, 0, 24,
+ 0, 25, 0, 26, 0, 27, 0, 28, 0, 29, 0, 30, 0, 31, 0, 32, 0, 33, 0, 34, 0, 35, 0, 36, 0, 37, 0, 38, 0, 39, 0, 40,
+ 0, 41, 0, 42, 0, 43, 0, 44, 0, 45, 0, 46, 0, 47, 0, 48, 0, 49, 0, 50, 0, 51, 0, 52, 0, 53, 0, 54, 0, 55, 0, 56,
+ 0, 57, 0, 58, 0, 59, 0, 60, 0, 61, 0, 62, 0, 63, 0, 64, 0, 65, 0, 66, 0, 67, 0, 68, 0, 69, 0, 70, 0, 71, 0, 72,
+ 0, 73, 0, 74, 0, 75, 0, 76, 0, 77, 0, 78, 0, 79, 0, 80, 0, 81, 0, 82, 0, 83, 0, 84, 0, 85, 0, 86, 0, 87, 0, 88,
+ 0, 89, 0, 90, 0, 91, 0, 92, 0, 93, 0, 94, 0, 95, 0, 96, 0, 97, 0,172, 0,163, 0,132, 0,133, 0,189, 0,150, 0,232,
+ 0,134, 0,142, 0,139, 0,157, 0,169, 0,164, 1, 2, 0,138, 0,218, 0,131, 0,147, 0,242, 0,243, 0,141, 0,151, 0,136,
+ 0,195, 0,222, 0,241, 0,158, 0,170, 0,245, 0,244, 0,246, 0,162, 0,173, 0,201, 0,199, 0,174, 0, 98, 0, 99, 0,144,
+ 0,100, 0,203, 0,101, 0,200, 0,202, 0,207, 0,204, 0,205, 0,206, 0,233, 0,102, 0,211, 0,208, 0,209, 0,175, 0,103,
+ 0,240, 0,145, 0,214, 0,212, 0,213, 0,104, 0,235, 0,237, 0,137, 0,106, 0,105, 0,107, 0,109, 0,108, 0,110, 0,160,
+ 0,111, 0,113, 0,112, 0,114, 0,115, 0,117, 0,116, 0,118, 0,119, 0,234, 0,120, 0,122, 0,121, 0,123, 0,125, 0,124,
+ 0,184, 0,161, 0,127, 0,126, 0,128, 0,129, 0,236, 0,238, 0,186, 1, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 0,253,
+ 0,254, 1, 9, 1, 10, 1, 11, 1, 12, 0,255, 1, 0, 1, 13, 1, 14, 1, 15, 1, 1, 1, 16, 1, 17, 1, 18, 1, 19, 1, 20,
+ 1, 21, 1, 22, 1, 23, 1, 24, 1, 25, 1, 26, 1, 27, 0,248, 0,249, 1, 28, 1, 29, 1, 30, 1, 31, 1, 32, 1, 33, 1, 34,
+ 1, 35, 1, 36, 1, 37, 1, 38, 1, 39, 1, 40, 1, 41, 1, 42, 1, 43, 0,250, 0,215, 1, 44, 1, 45, 1, 46, 1, 47, 1, 48,
+ 1, 49, 1, 50, 1, 51, 1, 52, 1, 53, 1, 54, 1, 55, 1, 56, 1, 57, 1, 58, 0,226, 0,227, 1, 59, 1, 60, 1, 61, 1, 62,
+ 1, 63, 1, 64, 1, 65, 1, 66, 1, 67, 1, 68, 1, 69, 1, 70, 1, 71, 1, 72, 1, 73, 0,176, 0,177, 1, 74, 1, 75, 1, 76,
+ 1, 77, 1, 78, 1, 79, 1, 80, 1, 81, 1, 82, 1, 83, 0,251, 0,252, 0,228, 0,229, 1, 84, 1, 85, 1, 86, 1, 87, 1, 88,
+ 1, 89, 1, 90, 1, 91, 1, 92, 1, 93, 1, 94, 1, 95, 1, 96, 1, 97, 1, 98, 1, 99, 1,100, 1,101, 1,102, 1,103, 1,104,
+ 1,105, 0,187, 1,106, 1,107, 1,108, 1,109, 0,230, 0,231, 1,110, 1,111, 1,112, 1,113, 1,114, 1,115, 1,116, 1,117,
+ 1,118, 1,119, 1,120, 1,121, 1,122, 1,123, 1,124, 1,125, 1,126, 1,127, 1,128, 0,166, 1,129, 1,130, 1,131, 1,132,
+ 1,133, 1,134, 1,135, 1,136, 1,137, 1,138, 1,139, 1,140, 1,141, 1,142, 1,143, 1,144, 1,145, 1,146, 1,147, 1,148,
+ 1,149, 1,150, 1,151, 1,152, 1,153, 1,154, 1,155, 1,156, 1,157, 1,158, 1,159, 1,160, 1,161, 1,162, 1,163, 1,164,
+ 1,165, 1,166, 1,167, 1,168, 1,169, 1,170, 1,171, 1,172, 1,173, 1,174, 1,175, 1,176, 1,177, 1,178, 1,179, 1,180,
+ 1,181, 1,182, 1,183, 1,184, 1,185, 1,186, 1,187, 1,188, 1,189, 1,190, 1,191, 1,192, 1,193, 1,194, 1,195, 1,196,
+ 1,197, 1,198, 1,199, 1,200, 1,201, 1,202, 1,203, 1,204, 1,205, 1,206, 1,207, 1,208, 1,209, 1,210, 1,211, 1,212,
+ 1,213, 1,214, 1,215, 1,216, 1,217, 1,218, 1,219, 1,220, 1,221, 1,222, 1,223, 1,224, 1,225, 1,226, 1,227, 1,228,
+ 1,229, 1,230, 1,231, 1,232, 1,233, 1,234, 1,235, 1,236, 1,237, 1,238, 1,239, 1,240, 1,241, 1,242, 1,243, 1,244,
+ 1,245, 1,246, 1,247, 1,248, 1,249, 1,250, 1,251, 1,252, 1,253, 1,254, 1,255, 2, 0, 2, 1, 2, 2, 2, 3, 2, 4,
+ 2, 5, 2, 6, 2, 7, 2, 8, 2, 9, 2, 10, 2, 11, 2, 12, 2, 13, 2, 14, 2, 15, 2, 16, 2, 17, 2, 18, 2, 19, 2, 20,
+ 2, 21, 2, 22, 2, 23, 2, 24, 2, 25, 2, 26, 2, 27, 2, 28, 2, 29, 2, 30, 2, 31, 2, 32, 2, 33, 2, 34, 2, 35, 2, 36,
+ 2, 37, 2, 38, 2, 39, 2, 40, 2, 41, 2, 42, 2, 43, 2, 44, 2, 45, 2, 46, 2, 47, 2, 48, 2, 49, 2, 50, 2, 51, 2, 52,
+ 2, 53, 2, 54, 2, 55, 2, 56, 2, 57, 2, 58, 2, 59, 2, 60, 2, 61, 2, 62, 2, 63, 2, 64, 2, 65, 2, 66, 2, 67, 2, 68,
+ 2, 69, 2, 70, 2, 71, 2, 72, 2, 73, 2, 74, 0,216, 0,225, 2, 75, 2, 76, 2, 77, 2, 78, 2, 79, 2, 80, 2, 81, 2, 82,
+ 2, 83, 2, 84, 2, 85, 2, 86, 2, 87, 2, 88, 2, 89, 2, 90, 0,219, 0,220, 0,221, 0,224, 0,217, 0,223, 2, 91, 2, 92,
+ 2, 93, 2, 94, 2, 95, 2, 96, 2, 97, 2, 98, 2, 99, 2,100, 2,101, 2,102, 2,103, 2,104, 2,105, 2,106, 2,107, 2,108,
+ 2,109, 2,110, 2,111, 2,112, 2,113, 2,114, 2,115, 2,116, 2,117, 2,118, 2,119, 2,120, 2,121, 2,122, 2,123, 2,124,
+ 2,125, 2,126, 2,127, 2,128, 2,129, 2,130, 2,131, 2,132, 2,133, 2,134, 2,135, 2,136, 2,137, 2,138, 2,139, 2,140,
+ 2,141, 2,142, 2,143, 2,144, 2,145, 2,146, 2,147, 2,148, 2,149, 2,150, 2,151, 2,152, 2,153, 2,154, 2,155, 2,156,
+ 2,157, 2,158, 2,159, 2,160, 2,161, 2,162, 2,163, 2,164, 2,165, 2,166, 2,167, 2,168, 2,169, 2,170, 2,171, 2,172,
+ 2,173, 2,174, 2,175, 2,176, 2,177, 2,178, 2,179, 2,180, 2,181, 2,182, 2,183, 2,184, 2,185, 2,186, 2,187, 2,188,
+ 2,189, 2,190, 2,191, 2,192, 2,193, 2,194, 2,195, 2,196, 2,197, 2,198, 2,199, 2,200, 2,201, 2,202, 2,203, 2,204,
+ 2,205, 2,206, 2,207, 2,208, 2,209, 2,210, 2,211, 2,212, 2,213, 2,214, 2,215, 2,216, 2,217, 2,218, 2,219, 2,220,
+ 2,221, 2,222, 2,223, 2,224, 2,225, 2,226, 2,227, 2,228, 2,229, 2,230, 2,231, 2,232, 2,233, 2,234, 0,159, 2,235,
+ 2,236, 2,237, 2,238, 2,239, 2,240, 2,241, 2,242, 2,243, 2,244, 2,245, 2,246, 2,247, 2,248, 2,249, 2,250, 2,251,
+ 2,252, 2,253, 2,254, 2,255, 3, 0, 0,155, 3, 1, 3, 2, 3, 3, 3, 4, 3, 5, 3, 6, 3, 7, 3, 8, 3, 9, 3, 10,
+ 3, 11, 3, 12, 3, 13, 3, 14, 3, 15, 3, 16, 3, 17, 3, 18, 3, 19, 3, 20, 3, 21, 3, 22, 3, 23, 3, 24, 3, 25, 3, 26,
+ 3, 27, 3, 28, 3, 29, 3, 30, 3, 31, 3, 32, 3, 33, 3, 34, 3, 35, 3, 36, 3, 37, 3, 38, 3, 39, 3, 40, 3, 41, 3, 42,
+ 3, 43, 3, 44, 3, 45, 3, 46, 3, 47, 3, 48, 3, 49, 3, 50, 3, 51, 3, 52, 3, 53, 3, 54, 3, 55, 3, 56, 3, 57, 3, 58,
+ 3, 59, 3, 60, 3, 61, 3, 62, 3, 63, 3, 64, 3, 65, 3, 66, 3, 67, 3, 68, 3, 69, 3, 70, 3, 71, 3, 72, 3, 73, 3, 74,
+ 3, 75, 3, 76, 3, 77, 3, 78, 3, 79, 3, 80, 3, 81, 3, 82, 3, 83, 3, 84, 3, 85, 3, 86, 3, 87, 3, 88, 3, 89, 3, 90,
+ 3, 91, 3, 92, 3, 93, 3, 94, 3, 95, 3, 96, 3, 97, 3, 98, 3, 99, 3,100, 3,101, 3,102, 3,103, 3,104, 3,105, 3,106,
+ 3,107, 3,108, 3,109, 3,110, 3,111, 3,112, 3,113, 3,114, 3,115, 3,116, 3,117, 3,118, 3,119, 3,120, 3,121, 3,122,
+ 3,123, 3,124, 3,125, 3,126, 3,127, 3,128, 3,129, 3,130, 3,131, 3,132, 3,133, 3,134, 3,135, 3,136, 3,137, 3,138,
+ 3,139, 3,140, 3,141, 3,142, 3,143, 3,144, 3,145, 3,146, 3,147, 3,148, 3,149, 3,150, 3,151, 3,152, 3,153, 3,154,
+ 3,155, 3,156, 3,157, 3,158, 3,159, 3,160, 3,161, 3,162, 3,163, 3,164, 3,165, 3,166, 3,167, 3,168, 3,169, 3,170,
+ 3,171, 3,172, 3,173, 3,174, 3,175, 3,176, 3,177, 3,178, 3,179, 3,180, 3,181, 3,182, 3,183, 3,184, 3,185, 3,186,
+ 3,187, 3,188, 3,189, 3,190, 3,191, 3,192, 3,193, 3,194, 3,195, 3,196, 3,197, 3,198, 3,199, 3,200, 3,201, 3,202,
+ 3,203, 3,204, 3,205, 3,206, 3,207, 3,208, 3,209, 3,210, 3,211, 3,212, 3,213, 3,214, 3,215, 3,216, 3,217, 3,218,
+ 3,219, 3,220, 3,221, 3,222, 3,223, 3,224, 3,225, 3,226, 3,227, 3,228, 3,229, 3,230, 3,231, 3,232, 3,233, 3,234,
+ 3,235, 3,236, 3,237, 3,238, 3,239, 3,240, 3,241, 3,242, 3,243, 3,244, 3,245, 3,246, 3,247, 3,248, 3,249, 3,250,
+ 3,251, 3,252, 3,253, 3,254, 3,255, 4, 0, 4, 1, 4, 2, 4, 3, 4, 4, 4, 5, 4, 6, 4, 7, 4, 8, 4, 9, 4, 10,
+ 4, 11, 4, 12, 4, 13, 4, 14, 4, 15, 4, 16, 4, 17, 4, 18, 4, 19, 4, 20, 4, 21, 4, 22, 4, 23, 4, 24, 4, 25, 4, 26,
+ 4, 27, 4, 28, 4, 29, 4, 30, 4, 31, 4, 32, 4, 33, 4, 34, 4, 35, 4, 36, 4, 37, 4, 38, 4, 39, 4, 40, 4, 41, 4, 42,
+ 4, 43, 4, 44, 4, 45, 4, 46, 4, 47, 4, 48, 4, 49, 4, 50, 4, 51, 4, 52, 4, 53, 4, 54, 4, 55, 4, 56, 4, 57, 4, 58,
+ 4, 59, 4, 60, 4, 61, 4, 62, 4, 63, 4, 64, 4, 65, 4, 66, 4, 67, 4, 68, 4, 69, 4, 70, 4, 71, 4, 72, 4, 73, 4, 74,
+ 4, 75, 4, 76, 4, 77, 4, 78, 4, 79, 4, 80, 4, 81, 4, 82, 4, 83, 4, 84, 4, 85, 4, 86, 4, 87, 4, 88, 4, 89, 4, 90,
+ 4, 91, 4, 92, 4, 93, 4, 94, 4, 95, 4, 96, 4, 97, 4, 98, 4, 99, 4,100, 4,101, 4,102, 4,103, 4,104, 4,105, 4,106,
+ 4,107, 4,108, 4,109, 4,110, 4,111, 4,112, 4,113, 4,114, 4,115, 4,116, 4,117, 4,118, 4,119, 4,120, 4,121, 4,122,
+ 4,123, 4,124, 4,125, 4,126, 4,127, 4,128, 4,129, 4,130, 4,131, 4,132, 4,133, 4,134, 4,135, 4,136, 4,137, 4,138,
+ 4,139, 4,140, 4,141, 4,142, 4,143, 4,144, 4,145, 4,146, 4,147, 4,148, 4,149, 4,150, 4,151, 4,152, 4,153, 4,154,
+ 4,155, 4,156, 4,157, 4,158, 4,159, 4,160, 4,161, 4,162, 4,163, 4,164, 4,165, 4,166, 4,167, 4,168, 4,169, 4,170,
+ 4,171, 4,172, 4,173, 4,174, 4,175, 4,176, 4,177, 4,178, 4,179, 4,180, 4,181, 4,182, 4,183, 4,184, 4,185, 4,186,
+ 4,187, 4,188, 4,189, 4,190, 4,191, 4,192, 4,193, 4,194, 4,195, 4,196, 4,197, 4,198, 4,199, 4,200, 4,201, 4,202,
+ 4,203, 4,204, 4,205, 4,206, 4,207, 4,208, 4,209, 4,210, 4,211, 4,212, 4,213, 4,214, 4,215, 4,216, 4,217, 4,218,
+ 4,219, 4,220, 4,221, 4,222, 4,223, 4,224, 4,225, 4,226, 4,227, 4,228, 4,229, 4,230, 4,231, 4,232, 4,233, 4,234,
+ 4,235, 4,236, 4,237, 4,238, 4,239, 4,240, 4,241, 4,242, 4,243, 4,244, 4,245, 4,246, 4,247, 4,248, 4,249, 4,250,
+ 4,251, 4,252, 4,253, 4,254, 4,255, 5, 0, 5, 1, 5, 2, 5, 3, 5, 4, 5, 5, 5, 6, 5, 7, 5, 8, 5, 9, 5, 10,
+ 5, 11, 5, 12, 5, 13, 5, 14, 5, 15, 5, 16, 5, 17, 5, 18, 5, 19, 5, 20, 5, 21, 5, 22, 5, 23, 5, 24, 5, 25, 5, 26,
+ 5, 27, 5, 28, 5, 29, 5, 30, 5, 31, 5, 32, 5, 33, 5, 34, 5, 35, 5, 36, 5, 37, 5, 38, 5, 39, 5, 40, 5, 41, 5, 42,
+ 5, 43, 5, 44, 5, 45, 5, 46, 5, 47, 5, 48, 5, 49, 5, 50, 5, 51, 5, 52, 5, 53, 5, 54, 5, 55, 5, 56, 5, 57, 5, 58,
+ 5, 59, 5, 60, 5, 61, 5, 62, 5, 63, 5, 64, 5, 65, 5, 66, 5, 67, 5, 68, 5, 69, 5, 70, 5, 71, 5, 72, 5, 73, 5, 74,
+ 5, 75, 5, 76, 5, 77, 5, 78, 5, 79, 5, 80, 5, 81, 5, 82, 5, 83, 5, 84, 5, 85, 5, 86, 5, 87, 5, 88, 5, 89, 5, 90,
+ 5, 91, 5, 92, 5, 93, 5, 94, 5, 95, 5, 96, 5, 97, 5, 98, 5, 99, 5,100, 5,101, 5,102, 5,103, 5,104, 5,105, 5,106,
+ 5,107, 5,108, 5,109, 5,110, 5,111, 5,112, 5,113, 5,114, 5,115, 5,116, 5,117, 5,118, 5,119, 5,120, 5,121, 5,122,
+ 5,123, 5,124, 5,125, 5,126, 5,127, 5,128, 5,129, 5,130, 5,131, 5,132, 5,133, 5,134, 5,135, 5,136, 5,137, 5,138,
+ 5,139, 5,140, 5,141, 5,142, 5,143, 5,144, 5,145, 5,146, 5,147, 5,148, 5,149, 5,150, 5,151, 5,152, 5,153, 5,154,
+ 5,155, 5,156, 5,157, 5,158, 5,159, 5,160, 5,161, 5,162, 5,163, 5,164, 5,165, 5,166, 5,167, 5,168, 5,169, 0,178,
+ 0,179, 5,170, 5,171, 5,172, 0,182, 0,183, 0,196, 5,173, 0,180, 0,181, 0,197, 5,174, 0,130, 0,194, 0,135, 5,175,
+ 5,176, 5,177, 0,171, 5,178, 0,198, 5,179, 5,180, 5,181, 5,182, 5,183, 5,184, 5,185, 5,186, 0,190, 0,191, 5,187,
+ 5,188, 5,189, 5,190, 5,191, 5,192, 5,193, 5,194, 5,195, 0,188, 5,196, 5,197, 5,198, 5,199, 5,200, 5,201, 5,202,
+ 5,203, 5,204, 5,205, 5,206, 5,207, 5,208, 5,209, 5,210, 5,211, 5,212, 5,213, 5,214, 5,215, 5,216, 5,217, 5,218,
+ 5,219, 5,220, 5,221, 5,222, 5,223, 5,224, 5,225, 5,226, 5,227, 5,228, 5,229, 5,230, 5,231, 5,232, 5,233, 5,234,
+ 5,235, 5,236, 5,237, 5,238, 5,239, 5,240, 5,241, 5,242, 5,243, 5,244, 5,245, 5,246, 5,247, 5,248, 5,249, 5,250,
+ 5,251, 5,252, 5,253, 0,247, 5,254, 5,255, 6, 0, 6, 1, 6, 2, 6, 3, 6, 4, 6, 5, 6, 6, 6, 7, 6, 8, 6, 9,
+ 6, 10, 6, 11, 6, 12, 6, 13, 6, 14, 6, 15, 6, 16, 6, 17, 6, 18, 6, 19, 6, 20, 6, 21, 6, 22, 6, 23, 6, 24, 6, 25,
+ 6, 26, 6, 27, 6, 28, 6, 29, 6, 30, 6, 31, 6, 32, 0,140, 6, 33, 6, 34, 6, 35, 6, 36, 6, 37, 6, 38, 6, 39, 6, 40,
+ 6, 41, 6, 42, 6, 43, 6, 44, 6, 45, 6, 46, 6, 47, 6, 48, 6, 49, 6, 50, 6, 51, 6, 52, 6, 53, 6, 54, 6, 55, 6, 56,
+ 6, 57, 6, 58, 6, 59, 6, 60, 6, 61, 6, 62, 6, 63, 6, 64, 6, 65, 6, 66, 6, 67, 6, 68, 6, 69, 6, 70, 6, 71, 6, 72,
+ 6, 73, 6, 74, 6, 75, 6, 76, 6, 77, 6, 78, 6, 79, 6, 80, 6, 81, 6, 82, 6, 83, 6, 84, 6, 85, 6, 86, 6, 87, 6, 88,
+ 6, 89, 6, 90, 6, 91, 6, 92, 6, 93, 6, 94, 6, 95, 6, 96, 6, 97, 6, 98, 6, 99, 6,100, 6,101, 6,102, 0,239, 6,103,
+ 6,104, 0,188, 6,105, 6,106, 6,107, 0,195, 0,165, 6,108, 6,109, 6,110, 0,146, 6,111, 6,112, 6,113, 6,114, 6,115,
+ 6,116, 6,117, 6,118, 6,119, 6,120, 6,121, 6,122, 6,123, 6,124, 6,125, 6,126, 6,127, 6,128, 6,129, 0,192, 0,193,
+ 6,130, 6,131, 6,132, 6,133, 6,134, 6,135, 6,136, 6,137, 6,138, 6,139, 6,140, 6,141, 6,142, 6,143, 6,144, 6,145,
+ 6,146, 6,147, 6,148, 6,149, 6,150, 6,151, 6,152, 6,153, 6,154, 6,155, 6,156, 6,157, 6,158, 6,159, 6,160, 6,161,
+ 6,162, 6,163, 6,164, 6,165, 6,166, 6,167, 6,168, 6,169, 6,170, 6,171, 9,115,102,116,104,121,112,104,101,110, 7, 65,
+109, 97, 99,114,111,110, 7, 97,109, 97, 99,114,111,110, 6, 65, 98,114,101,118,101, 6, 97, 98,114,101,118,101, 7, 65,111,103,
+111,110,101,107, 7, 97,111,103,111,110,101,107, 11, 67, 99,105,114, 99,117,109,102,108,101,120, 11, 99, 99,105,114, 99,117,109,
+102,108,101,120, 10, 67,100,111,116, 97, 99, 99,101,110,116, 10, 99,100,111,116, 97, 99, 99,101,110,116, 6, 68, 99, 97,114,111,
+110, 6,100, 99, 97,114,111,110, 6, 68, 99,114,111, 97,116, 7, 69,109, 97, 99,114,111,110, 7,101,109, 97, 99,114,111,110, 6,
+ 69, 98,114,101,118,101, 6,101, 98,114,101,118,101, 10, 69,100,111,116, 97, 99, 99,101,110,116, 10,101,100,111,116, 97, 99, 99,
+101,110,116, 7, 69,111,103,111,110,101,107, 7,101,111,103,111,110,101,107, 6, 69, 99, 97,114,111,110, 6,101, 99, 97,114,111,
+110, 11, 71, 99,105,114, 99,117,109,102,108,101,120, 11,103, 99,105,114, 99,117,109,102,108,101,120, 10, 71,100,111,116, 97, 99,
+ 99,101,110,116, 10,103,100,111,116, 97, 99, 99,101,110,116, 12, 71, 99,111,109,109, 97, 97, 99, 99,101,110,116, 12,103, 99,111,
+109,109, 97, 97, 99, 99,101,110,116, 11, 72, 99,105,114, 99,117,109,102,108,101,120, 11,104, 99,105,114, 99,117,109,102,108,101,
+120, 4, 72, 98, 97,114, 4,104, 98, 97,114, 6, 73,116,105,108,100,101, 6,105,116,105,108,100,101, 7, 73,109, 97, 99,114,111,
+110, 7,105,109, 97, 99,114,111,110, 6, 73, 98,114,101,118,101, 6,105, 98,114,101,118,101, 7, 73,111,103,111,110,101,107, 7,
+105,111,103,111,110,101,107, 2, 73, 74, 2,105,106, 11, 74, 99,105,114, 99,117,109,102,108,101,120, 11,106, 99,105,114, 99,117,
+109,102,108,101,120, 12, 75, 99,111,109,109, 97, 97, 99, 99,101,110,116, 12,107, 99,111,109,109, 97, 97, 99, 99,101,110,116, 12,
+107,103,114,101,101,110,108, 97,110,100,105, 99, 6, 76, 97, 99,117,116,101, 6,108, 97, 99,117,116,101, 12, 76, 99,111,109,109,
+ 97, 97, 99, 99,101,110,116, 12,108, 99,111,109,109, 97, 97, 99, 99,101,110,116, 6, 76, 99, 97,114,111,110, 6,108, 99, 97,114,
+111,110, 4, 76,100,111,116, 4,108,100,111,116, 6, 78, 97, 99,117,116,101, 6,110, 97, 99,117,116,101, 12, 78, 99,111,109,109,
+ 97, 97, 99, 99,101,110,116, 12,110, 99,111,109,109, 97, 97, 99, 99,101,110,116, 6, 78, 99, 97,114,111,110, 6,110, 99, 97,114,
+111,110, 11,110, 97,112,111,115,116,114,111,112,104,101, 3, 69,110,103, 3,101,110,103, 7, 79,109, 97, 99,114,111,110, 7,111,
+109, 97, 99,114,111,110, 6, 79, 98,114,101,118,101, 6,111, 98,114,101,118,101, 13, 79,104,117,110,103, 97,114,117,109,108, 97,
+117,116, 13,111,104,117,110,103, 97,114,117,109,108, 97,117,116, 6, 82, 97, 99,117,116,101, 6,114, 97, 99,117,116,101, 12, 82,
+ 99,111,109,109, 97, 97, 99, 99,101,110,116, 12,114, 99,111,109,109, 97, 97, 99, 99,101,110,116, 6, 82, 99, 97,114,111,110, 6,
+114, 99, 97,114,111,110, 6, 83, 97, 99,117,116,101, 6,115, 97, 99,117,116,101, 11, 83, 99,105,114, 99,117,109,102,108,101,120,
+ 11,115, 99,105,114, 99,117,109,102,108,101,120, 12, 84, 99,111,109,109, 97, 97, 99, 99,101,110,116, 12,116, 99,111,109,109, 97,
+ 97, 99, 99,101,110,116, 6, 84, 99, 97,114,111,110, 6,116, 99, 97,114,111,110, 4, 84, 98, 97,114, 4,116, 98, 97,114, 6, 85,
+116,105,108,100,101, 6,117,116,105,108,100,101, 7, 85,109, 97, 99,114,111,110, 7,117,109, 97, 99,114,111,110, 6, 85, 98,114,
+101,118,101, 6,117, 98,114,101,118,101, 5, 85,114,105,110,103, 5,117,114,105,110,103, 13, 85,104,117,110,103, 97,114,117,109,
+108, 97,117,116, 13,117,104,117,110,103, 97,114,117,109,108, 97,117,116, 7, 85,111,103,111,110,101,107, 7,117,111,103,111,110,
+101,107, 11, 87, 99,105,114, 99,117,109,102,108,101,120, 11,119, 99,105,114, 99,117,109,102,108,101,120, 11, 89, 99,105,114, 99,
+117,109,102,108,101,120, 11,121, 99,105,114, 99,117,109,102,108,101,120, 6, 90, 97, 99,117,116,101, 6,122, 97, 99,117,116,101,
+ 10, 90,100,111,116, 97, 99, 99,101,110,116, 10,122,100,111,116, 97, 99, 99,101,110,116, 5,108,111,110,103,115, 7,117,110,105,
+ 48, 49, 56, 48, 7,117,110,105, 48, 49, 56, 49, 7,117,110,105, 48, 49, 56, 50, 7,117,110,105, 48, 49, 56, 51, 7,117,110,105,
+ 48, 49, 56, 52, 7,117,110,105, 48, 49, 56, 53, 7,117,110,105, 48, 49, 56, 54, 7,117,110,105, 48, 49, 56, 55, 7,117,110,105,
+ 48, 49, 56, 56, 7,117,110,105, 48, 49, 56, 57, 7,117,110,105, 48, 49, 56, 65, 7,117,110,105, 48, 49, 56, 66, 7,117,110,105,
+ 48, 49, 56, 67, 7,117,110,105, 48, 49, 56, 68, 7,117,110,105, 48, 49, 56, 69, 7,117,110,105, 48, 49, 56, 70, 7,117,110,105,
+ 48, 49, 57, 48, 7,117,110,105, 48, 49, 57, 49, 7,117,110,105, 48, 49, 57, 51, 7,117,110,105, 48, 49, 57, 52, 7,117,110,105,
+ 48, 49, 57, 53, 7,117,110,105, 48, 49, 57, 54, 7,117,110,105, 48, 49, 57, 55, 7,117,110,105, 48, 49, 57, 56, 7,117,110,105,
+ 48, 49, 57, 57, 7,117,110,105, 48, 49, 57, 65, 7,117,110,105, 48, 49, 57, 66, 7,117,110,105, 48, 49, 57, 67, 7,117,110,105,
+ 48, 49, 57, 68, 7,117,110,105, 48, 49, 57, 69, 7,117,110,105, 48, 49, 57, 70, 5, 79,104,111,114,110, 5,111,104,111,114,110,
+ 7,117,110,105, 48, 49, 65, 50, 7,117,110,105, 48, 49, 65, 51, 7,117,110,105, 48, 49, 65, 52, 7,117,110,105, 48, 49, 65, 53,
+ 7,117,110,105, 48, 49, 65, 54, 7,117,110,105, 48, 49, 65, 55, 7,117,110,105, 48, 49, 65, 56, 7,117,110,105, 48, 49, 65, 57,
+ 7,117,110,105, 48, 49, 65, 65, 7,117,110,105, 48, 49, 65, 66, 7,117,110,105, 48, 49, 65, 67, 7,117,110,105, 48, 49, 65, 68,
+ 7,117,110,105, 48, 49, 65, 69, 5, 85,104,111,114,110, 5,117,104,111,114,110, 7,117,110,105, 48, 49, 66, 49, 7,117,110,105,
+ 48, 49, 66, 50, 7,117,110,105, 48, 49, 66, 51, 7,117,110,105, 48, 49, 66, 52, 7,117,110,105, 48, 49, 66, 53, 7,117,110,105,
+ 48, 49, 66, 54, 7,117,110,105, 48, 49, 66, 55, 7,117,110,105, 48, 49, 66, 56, 7,117,110,105, 48, 49, 66, 57, 7,117,110,105,
+ 48, 49, 66, 65, 7,117,110,105, 48, 49, 66, 66, 7,117,110,105, 48, 49, 66, 67, 7,117,110,105, 48, 49, 66, 68, 7,117,110,105,
+ 48, 49, 66, 69, 7,117,110,105, 48, 49, 66, 70, 7,117,110,105, 48, 49, 67, 48, 7,117,110,105, 48, 49, 67, 49, 7,117,110,105,
+ 48, 49, 67, 50, 7,117,110,105, 48, 49, 67, 51, 7,117,110,105, 48, 49, 67, 52, 7,117,110,105, 48, 49, 67, 53, 7,117,110,105,
+ 48, 49, 67, 54, 7,117,110,105, 48, 49, 67, 55, 7,117,110,105, 48, 49, 67, 56, 7,117,110,105, 48, 49, 67, 57, 7,117,110,105,
+ 48, 49, 67, 65, 7,117,110,105, 48, 49, 67, 66, 7,117,110,105, 48, 49, 67, 67, 7,117,110,105, 48, 49, 67, 68, 7,117,110,105,
+ 48, 49, 67, 69, 7,117,110,105, 48, 49, 67, 70, 7,117,110,105, 48, 49, 68, 48, 7,117,110,105, 48, 49, 68, 49, 7,117,110,105,
+ 48, 49, 68, 50, 7,117,110,105, 48, 49, 68, 51, 7,117,110,105, 48, 49, 68, 52, 7,117,110,105, 48, 49, 68, 53, 7,117,110,105,
+ 48, 49, 68, 54, 7,117,110,105, 48, 49, 68, 55, 7,117,110,105, 48, 49, 68, 56, 7,117,110,105, 48, 49, 68, 57, 7,117,110,105,
+ 48, 49, 68, 65, 7,117,110,105, 48, 49, 68, 66, 7,117,110,105, 48, 49, 68, 67, 7,117,110,105, 48, 49, 68, 68, 7,117,110,105,
+ 48, 49, 68, 69, 7,117,110,105, 48, 49, 68, 70, 7,117,110,105, 48, 49, 69, 48, 7,117,110,105, 48, 49, 69, 49, 7,117,110,105,
+ 48, 49, 69, 50, 7,117,110,105, 48, 49, 69, 51, 7,117,110,105, 48, 49, 69, 52, 7,117,110,105, 48, 49, 69, 53, 6, 71, 99, 97,
+114,111,110, 6,103, 99, 97,114,111,110, 7,117,110,105, 48, 49, 69, 56, 7,117,110,105, 48, 49, 69, 57, 7,117,110,105, 48, 49,
+ 69, 65, 7,117,110,105, 48, 49, 69, 66, 7,117,110,105, 48, 49, 69, 67, 7,117,110,105, 48, 49, 69, 68, 7,117,110,105, 48, 49,
+ 69, 69, 7,117,110,105, 48, 49, 69, 70, 7,117,110,105, 48, 49, 70, 48, 7,117,110,105, 48, 49, 70, 49, 7,117,110,105, 48, 49,
+ 70, 50, 7,117,110,105, 48, 49, 70, 51, 7,117,110,105, 48, 49, 70, 52, 7,117,110,105, 48, 49, 70, 53, 7,117,110,105, 48, 49,
+ 70, 54, 7,117,110,105, 48, 49, 70, 55, 7,117,110,105, 48, 49, 70, 56, 7,117,110,105, 48, 49, 70, 57, 10, 65,114,105,110,103,
+ 97, 99,117,116,101, 10, 97,114,105,110,103, 97, 99,117,116,101, 7, 65, 69, 97, 99,117,116,101, 7, 97,101, 97, 99,117,116,101,
+ 11, 79,115,108, 97,115,104, 97, 99,117,116,101, 11,111,115,108, 97,115,104, 97, 99,117,116,101, 7,117,110,105, 48, 50, 48, 48,
+ 7,117,110,105, 48, 50, 48, 49, 7,117,110,105, 48, 50, 48, 50, 7,117,110,105, 48, 50, 48, 51, 7,117,110,105, 48, 50, 48, 52,
+ 7,117,110,105, 48, 50, 48, 53, 7,117,110,105, 48, 50, 48, 54, 7,117,110,105, 48, 50, 48, 55, 7,117,110,105, 48, 50, 48, 56,
+ 7,117,110,105, 48, 50, 48, 57, 7,117,110,105, 48, 50, 48, 65, 7,117,110,105, 48, 50, 48, 66, 7,117,110,105, 48, 50, 48, 67,
+ 7,117,110,105, 48, 50, 48, 68, 7,117,110,105, 48, 50, 48, 69, 7,117,110,105, 48, 50, 48, 70, 7,117,110,105, 48, 50, 49, 48,
+ 7,117,110,105, 48, 50, 49, 49, 7,117,110,105, 48, 50, 49, 50, 7,117,110,105, 48, 50, 49, 51, 7,117,110,105, 48, 50, 49, 52,
+ 7,117,110,105, 48, 50, 49, 53, 7,117,110,105, 48, 50, 49, 54, 7,117,110,105, 48, 50, 49, 55, 12, 83, 99,111,109,109, 97, 97,
+ 99, 99,101,110,116, 12,115, 99,111,109,109, 97, 97, 99, 99,101,110,116, 7,117,110,105, 48, 50, 49, 65, 7,117,110,105, 48, 50,
+ 49, 66, 7,117,110,105, 48, 50, 49, 67, 7,117,110,105, 48, 50, 49, 68, 7,117,110,105, 48, 50, 49, 69, 7,117,110,105, 48, 50,
+ 49, 70, 7,117,110,105, 48, 50, 50, 48, 7,117,110,105, 48, 50, 50, 49, 7,117,110,105, 48, 50, 50, 50, 7,117,110,105, 48, 50,
+ 50, 51, 7,117,110,105, 48, 50, 50, 52, 7,117,110,105, 48, 50, 50, 53, 7,117,110,105, 48, 50, 50, 54, 7,117,110,105, 48, 50,
+ 50, 55, 7,117,110,105, 48, 50, 50, 56, 7,117,110,105, 48, 50, 50, 57, 7,117,110,105, 48, 50, 50, 65, 7,117,110,105, 48, 50,
+ 50, 66, 7,117,110,105, 48, 50, 50, 67, 7,117,110,105, 48, 50, 50, 68, 7,117,110,105, 48, 50, 50, 69, 7,117,110,105, 48, 50,
+ 50, 70, 7,117,110,105, 48, 50, 51, 48, 7,117,110,105, 48, 50, 51, 49, 7,117,110,105, 48, 50, 51, 50, 7,117,110,105, 48, 50,
+ 51, 51, 7,117,110,105, 48, 50, 51, 52, 7,117,110,105, 48, 50, 51, 53, 7,117,110,105, 48, 50, 51, 54, 8,100,111,116,108,101,
+115,115,106, 7,117,110,105, 48, 50, 51, 56, 7,117,110,105, 48, 50, 51, 57, 7,117,110,105, 48, 50, 51, 65, 7,117,110,105, 48,
+ 50, 51, 66, 7,117,110,105, 48, 50, 51, 67, 7,117,110,105, 48, 50, 51, 68, 7,117,110,105, 48, 50, 51, 69, 7,117,110,105, 48,
+ 50, 51, 70, 7,117,110,105, 48, 50, 52, 48, 7,117,110,105, 48, 50, 52, 49, 7,117,110,105, 48, 50, 53, 57, 7,117,110,105, 48,
+ 50, 54, 50, 7,117,110,105, 48, 50, 55, 48, 7,117,110,105, 48, 50, 55, 53, 7,117,110,105, 48, 50, 57, 50, 7,117,110,105, 48,
+ 50, 66, 48, 7,117,110,105, 48, 50, 66, 49, 7,117,110,105, 48, 50, 66, 50, 7,117,110,105, 48, 50, 66, 51, 7,117,110,105, 48,
+ 50, 66, 52, 7,117,110,105, 48, 50, 66, 53, 7,117,110,105, 48, 50, 66, 54, 7,117,110,105, 48, 50, 66, 55, 7,117,110,105, 48,
+ 50, 66, 56, 7,117,110,105, 48, 50, 66, 57, 7,117,110,105, 48, 50, 66, 65, 7,117,110,105, 48, 50, 66, 66, 9, 97,102,105,105,
+ 53, 55, 57, 50, 57, 9, 97,102,105,105, 54, 52, 57, 51, 55, 7,117,110,105, 48, 50, 66, 69, 7,117,110,105, 48, 50, 66, 70, 7,
+117,110,105, 48, 50, 67, 48, 7,117,110,105, 48, 50, 67, 49, 7,117,110,105, 48, 50, 67, 50, 7,117,110,105, 48, 50, 67, 51, 7,
+117,110,105, 48, 50, 67, 52, 7,117,110,105, 48, 50, 67, 53, 7,117,110,105, 48, 50, 67, 56, 7,117,110,105, 48, 50, 67, 57, 7,
+117,110,105, 48, 50, 67, 65, 7,117,110,105, 48, 50, 67, 66, 7,117,110,105, 48, 50, 67, 67, 7,117,110,105, 48, 50, 67, 68, 7,
+117,110,105, 48, 50, 67, 69, 7,117,110,105, 48, 50, 67, 70, 7,117,110,105, 48, 50, 68, 48, 7,117,110,105, 48, 50, 68, 49, 7,
+117,110,105, 48, 50, 68, 50, 7,117,110,105, 48, 50, 68, 51, 7,117,110,105, 48, 50, 68, 52, 7,117,110,105, 48, 50, 68, 53, 7,
+117,110,105, 48, 50, 68, 54, 7,117,110,105, 48, 50, 68, 55, 7,117,110,105, 48, 50, 68, 69, 7,117,110,105, 48, 50, 68, 70, 7,
+117,110,105, 48, 50, 69, 48, 7,117,110,105, 48, 50, 69, 49, 7,117,110,105, 48, 50, 69, 50, 7,117,110,105, 48, 50, 69, 51, 7,
+117,110,105, 48, 50, 69, 52, 7,117,110,105, 48, 50, 69, 53, 7,117,110,105, 48, 50, 69, 54, 7,117,110,105, 48, 50, 69, 55, 7,
+117,110,105, 48, 50, 69, 56, 7,117,110,105, 48, 50, 69, 57, 7,117,110,105, 48, 50, 69, 67, 7,117,110,105, 48, 50, 69, 68, 7,
+117,110,105, 48, 50, 69, 69, 7,117,110,105, 48, 50, 70, 51, 7,117,110,105, 48, 50, 70, 55, 9,103,114, 97,118,101, 99,111,109,
+ 98, 9, 97, 99,117,116,101, 99,111,109, 98, 7,117,110,105, 48, 51, 48, 50, 9,116,105,108,100,101, 99,111,109, 98, 7,117,110,
+105, 48, 51, 48, 52, 7,117,110,105, 48, 51, 48, 53, 7,117,110,105, 48, 51, 48, 54, 7,117,110,105, 48, 51, 48, 55, 7,117,110,
+105, 48, 51, 48, 56, 13,104,111,111,107, 97, 98,111,118,101, 99,111,109, 98, 7,117,110,105, 48, 51, 48, 65, 7,117,110,105, 48,
+ 51, 48, 66, 7,117,110,105, 48, 51, 48, 67, 7,117,110,105, 48, 51, 48, 68, 7,117,110,105, 48, 51, 48, 69, 7,117,110,105, 48,
+ 51, 48, 70, 7,117,110,105, 48, 51, 49, 48, 7,117,110,105, 48, 51, 49, 49, 7,117,110,105, 48, 51, 49, 50, 7,117,110,105, 48,
+ 51, 49, 51, 7,117,110,105, 48, 51, 49, 52, 7,117,110,105, 48, 51, 49, 53, 7,117,110,105, 48, 51, 49, 54, 7,117,110,105, 48,
+ 51, 49, 55, 7,117,110,105, 48, 51, 49, 56, 7,117,110,105, 48, 51, 49, 57, 7,117,110,105, 48, 51, 49, 65, 7,117,110,105, 48,
+ 51, 49, 66, 7,117,110,105, 48, 51, 49, 67, 7,117,110,105, 48, 51, 49, 68, 7,117,110,105, 48, 51, 49, 69, 7,117,110,105, 48,
+ 51, 49, 70, 7,117,110,105, 48, 51, 50, 48, 7,117,110,105, 48, 51, 50, 49, 7,117,110,105, 48, 51, 50, 50, 12,100,111,116, 98,
+101,108,111,119, 99,111,109, 98, 7,117,110,105, 48, 51, 50, 52, 7,117,110,105, 48, 51, 50, 53, 7,117,110,105, 48, 51, 50, 54,
+ 7,117,110,105, 48, 51, 50, 55, 7,117,110,105, 48, 51, 50, 56, 7,117,110,105, 48, 51, 50, 57, 7,117,110,105, 48, 51, 50, 65,
+ 7,117,110,105, 48, 51, 50, 66, 7,117,110,105, 48, 51, 50, 67, 7,117,110,105, 48, 51, 50, 68, 7,117,110,105, 48, 51, 50, 69,
+ 7,117,110,105, 48, 51, 50, 70, 7,117,110,105, 48, 51, 51, 48, 7,117,110,105, 48, 51, 51, 49, 7,117,110,105, 48, 51, 51, 50,
+ 7,117,110,105, 48, 51, 51, 51, 7,117,110,105, 48, 51, 51, 52, 7,117,110,105, 48, 51, 51, 53, 7,117,110,105, 48, 51, 51, 54,
+ 7,117,110,105, 48, 51, 51, 55, 7,117,110,105, 48, 51, 51, 56, 7,117,110,105, 48, 51, 51, 57, 7,117,110,105, 48, 51, 51, 65,
+ 7,117,110,105, 48, 51, 51, 66, 7,117,110,105, 48, 51, 51, 67, 7,117,110,105, 48, 51, 51, 68, 7,117,110,105, 48, 51, 51, 69,
+ 7,117,110,105, 48, 51, 51, 70, 7,117,110,105, 48, 51, 52, 48, 7,117,110,105, 48, 51, 52, 49, 7,117,110,105, 48, 51, 52, 50,
+ 7,117,110,105, 48, 51, 52, 51, 7,117,110,105, 48, 51, 52, 52, 7,117,110,105, 48, 51, 52, 53, 7,117,110,105, 48, 51, 52, 54,
+ 7,117,110,105, 48, 51, 52, 55, 7,117,110,105, 48, 51, 52, 56, 7,117,110,105, 48, 51, 52, 57, 7,117,110,105, 48, 51, 52, 65,
+ 7,117,110,105, 48, 51, 52, 66, 7,117,110,105, 48, 51, 52, 67, 7,117,110,105, 48, 51, 52, 68, 7,117,110,105, 48, 51, 52, 69,
+ 7,117,110,105, 48, 51, 53, 49, 7,117,110,105, 48, 51, 53, 50, 7,117,110,105, 48, 51, 53, 51, 7,117,110,105, 48, 51, 53, 55,
+ 7,117,110,105, 48, 51, 53, 56, 7,117,110,105, 48, 51, 53, 67, 7,117,110,105, 48, 51, 53, 68, 7,117,110,105, 48, 51, 54, 48,
+ 7,117,110,105, 48, 51, 54, 49, 7,117,110,105, 48, 51, 54, 50, 7,117,110,105, 48, 51, 55, 52, 7,117,110,105, 48, 51, 55, 53,
+ 7,117,110,105, 48, 51, 55, 65, 7,117,110,105, 48, 51, 55, 69, 5,116,111,110,111,115, 13,100,105,101,114,101,115,105,115,116,
+111,110,111,115, 10, 65,108,112,104, 97,116,111,110,111,115, 9, 97,110,111,116,101,108,101,105, 97, 12, 69,112,115,105,108,111,
+110,116,111,110,111,115, 8, 69,116, 97,116,111,110,111,115, 9, 73,111,116, 97,116,111,110,111,115, 12, 79,109,105, 99,114,111,
+110,116,111,110,111,115, 12, 85,112,115,105,108,111,110,116,111,110,111,115, 10, 79,109,101,103, 97,116,111,110,111,115, 17,105,
+111,116, 97,100,105,101,114,101,115,105,115,116,111,110,111,115, 5, 65,108,112,104, 97, 4, 66,101,116, 97, 5, 71, 97,109,109,
+ 97, 7,117,110,105, 48, 51, 57, 52, 7, 69,112,115,105,108,111,110, 4, 90,101,116, 97, 3, 69,116, 97, 5, 84,104,101,116, 97,
+ 4, 73,111,116, 97, 5, 75, 97,112,112, 97, 6, 76, 97,109, 98,100, 97, 2, 77,117, 2, 78,117, 2, 88,105, 7, 79,109,105, 99,
+114,111,110, 2, 80,105, 3, 82,104,111, 5, 83,105,103,109, 97, 3, 84, 97,117, 7, 85,112,115,105,108,111,110, 3, 80,104,105,
+ 3, 67,104,105, 3, 80,115,105, 12, 73,111,116, 97,100,105,101,114,101,115,105,115, 15, 85,112,115,105,108,111,110,100,105,101,
+114,101,115,105,115, 10, 97,108,112,104, 97,116,111,110,111,115, 12,101,112,115,105,108,111,110,116,111,110,111,115, 8,101,116,
+ 97,116,111,110,111,115, 9,105,111,116, 97,116,111,110,111,115, 20,117,112,115,105,108,111,110,100,105,101,114,101,115,105,115,
+116,111,110,111,115, 5, 97,108,112,104, 97, 4, 98,101,116, 97, 5,103, 97,109,109, 97, 5,100,101,108,116, 97, 7,101,112,115,
+105,108,111,110, 4,122,101,116, 97, 3,101,116, 97, 5,116,104,101,116, 97, 4,105,111,116, 97, 5,107, 97,112,112, 97, 6,108,
+ 97,109, 98,100, 97, 7,117,110,105, 48, 51, 66, 67, 2,110,117, 2,120,105, 7,111,109,105, 99,114,111,110, 3,114,104,111, 6,
+115,105,103,109, 97, 49, 5,115,105,103,109, 97, 3,116, 97,117, 7,117,112,115,105,108,111,110, 3,112,104,105, 3, 99,104,105,
+ 3,112,115,105, 5,111,109,101,103, 97, 12,105,111,116, 97,100,105,101,114,101,115,105,115, 15,117,112,115,105,108,111,110,100,
+105,101,114,101,115,105,115, 12,111,109,105, 99,114,111,110,116,111,110,111,115, 12,117,112,115,105,108,111,110,116,111,110,111,
+115, 10,111,109,101,103, 97,116,111,110,111,115, 7,117,110,105, 48, 51, 68, 48, 6,116,104,101,116, 97, 49, 8, 85,112,115,105,
+108,111,110, 49, 7,117,110,105, 48, 51, 68, 51, 7,117,110,105, 48, 51, 68, 52, 4,112,104,105, 49, 6,111,109,101,103, 97, 49,
+ 7,117,110,105, 48, 51, 68, 55, 7,117,110,105, 48, 51, 68, 56, 7,117,110,105, 48, 51, 68, 57, 7,117,110,105, 48, 51, 68, 65,
+ 7,117,110,105, 48, 51, 68, 66, 7,117,110,105, 48, 51, 68, 67, 7,117,110,105, 48, 51, 68, 68, 7,117,110,105, 48, 51, 68, 69,
+ 7,117,110,105, 48, 51, 68, 70, 7,117,110,105, 48, 51, 69, 48, 7,117,110,105, 48, 51, 69, 49, 7,117,110,105, 48, 51, 69, 50,
+ 7,117,110,105, 48, 51, 69, 51, 7,117,110,105, 48, 51, 69, 52, 7,117,110,105, 48, 51, 69, 53, 7,117,110,105, 48, 51, 69, 54,
+ 7,117,110,105, 48, 51, 69, 55, 7,117,110,105, 48, 51, 69, 56, 7,117,110,105, 48, 51, 69, 57, 7,117,110,105, 48, 51, 69, 65,
+ 7,117,110,105, 48, 51, 69, 66, 7,117,110,105, 48, 51, 69, 67, 7,117,110,105, 48, 51, 69, 68, 7,117,110,105, 48, 51, 69, 69,
+ 7,117,110,105, 48, 51, 69, 70, 7,117,110,105, 48, 51, 70, 48, 7,117,110,105, 48, 51, 70, 49, 7,117,110,105, 48, 51, 70, 50,
+ 7,117,110,105, 48, 51, 70, 51, 7,117,110,105, 48, 51, 70, 52, 7,117,110,105, 48, 51, 70, 53, 7,117,110,105, 48, 51, 70, 54,
+ 7,117,110,105, 48, 51, 70, 55, 7,117,110,105, 48, 51, 70, 56, 7,117,110,105, 48, 51, 70, 57, 7,117,110,105, 48, 51, 70, 65,
+ 7,117,110,105, 48, 51, 70, 66, 7,117,110,105, 48, 51, 70, 67, 7,117,110,105, 48, 51, 70, 68, 7,117,110,105, 48, 51, 70, 69,
+ 7,117,110,105, 48, 51, 70, 70, 7,117,110,105, 48, 52, 48, 48, 9, 97,102,105,105, 49, 48, 48, 50, 51, 9, 97,102,105,105, 49,
+ 48, 48, 53, 49, 9, 97,102,105,105, 49, 48, 48, 53, 50, 9, 97,102,105,105, 49, 48, 48, 53, 51, 9, 97,102,105,105, 49, 48, 48,
+ 53, 52, 9, 97,102,105,105, 49, 48, 48, 53, 53, 9, 97,102,105,105, 49, 48, 48, 53, 54, 9, 97,102,105,105, 49, 48, 48, 53, 55,
+ 9, 97,102,105,105, 49, 48, 48, 53, 56, 9, 97,102,105,105, 49, 48, 48, 53, 57, 9, 97,102,105,105, 49, 48, 48, 54, 48, 9, 97,
+102,105,105, 49, 48, 48, 54, 49, 7,117,110,105, 48, 52, 48, 68, 9, 97,102,105,105, 49, 48, 48, 54, 50, 9, 97,102,105,105, 49,
+ 48, 49, 52, 53, 9, 97,102,105,105, 49, 48, 48, 49, 55, 9, 97,102,105,105, 49, 48, 48, 49, 56, 9, 97,102,105,105, 49, 48, 48,
+ 49, 57, 9, 97,102,105,105, 49, 48, 48, 50, 48, 9, 97,102,105,105, 49, 48, 48, 50, 49, 9, 97,102,105,105, 49, 48, 48, 50, 50,
+ 9, 97,102,105,105, 49, 48, 48, 50, 52, 9, 97,102,105,105, 49, 48, 48, 50, 53, 9, 97,102,105,105, 49, 48, 48, 50, 54, 9, 97,
+102,105,105, 49, 48, 48, 50, 55, 9, 97,102,105,105, 49, 48, 48, 50, 56, 9, 97,102,105,105, 49, 48, 48, 50, 57, 9, 97,102,105,
+105, 49, 48, 48, 51, 48, 9, 97,102,105,105, 49, 48, 48, 51, 49, 9, 97,102,105,105, 49, 48, 48, 51, 50, 9, 97,102,105,105, 49,
+ 48, 48, 51, 51, 9, 97,102,105,105, 49, 48, 48, 51, 52, 9, 97,102,105,105, 49, 48, 48, 51, 53, 9, 97,102,105,105, 49, 48, 48,
+ 51, 54, 9, 97,102,105,105, 49, 48, 48, 51, 55, 9, 97,102,105,105, 49, 48, 48, 51, 56, 9, 97,102,105,105, 49, 48, 48, 51, 57,
+ 9, 97,102,105,105, 49, 48, 48, 52, 48, 9, 97,102,105,105, 49, 48, 48, 52, 49, 9, 97,102,105,105, 49, 48, 48, 52, 50, 9, 97,
+102,105,105, 49, 48, 48, 52, 51, 9, 97,102,105,105, 49, 48, 48, 52, 52, 9, 97,102,105,105, 49, 48, 48, 52, 53, 9, 97,102,105,
+105, 49, 48, 48, 52, 54, 9, 97,102,105,105, 49, 48, 48, 52, 55, 9, 97,102,105,105, 49, 48, 48, 52, 56, 9, 97,102,105,105, 49,
+ 48, 48, 52, 57, 9, 97,102,105,105, 49, 48, 48, 54, 53, 9, 97,102,105,105, 49, 48, 48, 54, 54, 9, 97,102,105,105, 49, 48, 48,
+ 54, 55, 9, 97,102,105,105, 49, 48, 48, 54, 56, 9, 97,102,105,105, 49, 48, 48, 54, 57, 9, 97,102,105,105, 49, 48, 48, 55, 48,
+ 9, 97,102,105,105, 49, 48, 48, 55, 50, 9, 97,102,105,105, 49, 48, 48, 55, 51, 9, 97,102,105,105, 49, 48, 48, 55, 52, 9, 97,
+102,105,105, 49, 48, 48, 55, 53, 9, 97,102,105,105, 49, 48, 48, 55, 54, 9, 97,102,105,105, 49, 48, 48, 55, 55, 9, 97,102,105,
+105, 49, 48, 48, 55, 56, 9, 97,102,105,105, 49, 48, 48, 55, 57, 9, 97,102,105,105, 49, 48, 48, 56, 48, 9, 97,102,105,105, 49,
+ 48, 48, 56, 49, 9, 97,102,105,105, 49, 48, 48, 56, 50, 9, 97,102,105,105, 49, 48, 48, 56, 51, 9, 97,102,105,105, 49, 48, 48,
+ 56, 52, 9, 97,102,105,105, 49, 48, 48, 56, 53, 9, 97,102,105,105, 49, 48, 48, 56, 54, 9, 97,102,105,105, 49, 48, 48, 56, 55,
+ 9, 97,102,105,105, 49, 48, 48, 56, 56, 9, 97,102,105,105, 49, 48, 48, 56, 57, 9, 97,102,105,105, 49, 48, 48, 57, 48, 9, 97,
+102,105,105, 49, 48, 48, 57, 49, 9, 97,102,105,105, 49, 48, 48, 57, 50, 9, 97,102,105,105, 49, 48, 48, 57, 51, 9, 97,102,105,
+105, 49, 48, 48, 57, 52, 9, 97,102,105,105, 49, 48, 48, 57, 53, 9, 97,102,105,105, 49, 48, 48, 57, 54, 9, 97,102,105,105, 49,
+ 48, 48, 57, 55, 7,117,110,105, 48, 52, 53, 48, 9, 97,102,105,105, 49, 48, 48, 55, 49, 9, 97,102,105,105, 49, 48, 48, 57, 57,
+ 9, 97,102,105,105, 49, 48, 49, 48, 48, 9, 97,102,105,105, 49, 48, 49, 48, 49, 9, 97,102,105,105, 49, 48, 49, 48, 50, 9, 97,
+102,105,105, 49, 48, 49, 48, 51, 9, 97,102,105,105, 49, 48, 49, 48, 52, 9, 97,102,105,105, 49, 48, 49, 48, 53, 9, 97,102,105,
+105, 49, 48, 49, 48, 54, 9, 97,102,105,105, 49, 48, 49, 48, 55, 9, 97,102,105,105, 49, 48, 49, 48, 56, 9, 97,102,105,105, 49,
+ 48, 49, 48, 57, 7,117,110,105, 48, 52, 53, 68, 9, 97,102,105,105, 49, 48, 49, 49, 48, 9, 97,102,105,105, 49, 48, 49, 57, 51,
+ 7,117,110,105, 48, 52, 54, 48, 7,117,110,105, 48, 52, 54, 49, 9, 97,102,105,105, 49, 48, 49, 52, 54, 9, 97,102,105,105, 49,
+ 48, 49, 57, 52, 7,117,110,105, 48, 52, 54, 52, 7,117,110,105, 48, 52, 54, 53, 7,117,110,105, 48, 52, 54, 54, 7,117,110,105,
+ 48, 52, 54, 55, 7,117,110,105, 48, 52, 54, 56, 7,117,110,105, 48, 52, 54, 57, 7,117,110,105, 48, 52, 54, 65, 7,117,110,105,
+ 48, 52, 54, 66, 7,117,110,105, 48, 52, 54, 67, 7,117,110,105, 48, 52, 54, 68, 7,117,110,105, 48, 52, 54, 69, 7,117,110,105,
+ 48, 52, 54, 70, 7,117,110,105, 48, 52, 55, 48, 7,117,110,105, 48, 52, 55, 49, 9, 97,102,105,105, 49, 48, 49, 52, 55, 9, 97,
+102,105,105, 49, 48, 49, 57, 53, 9, 97,102,105,105, 49, 48, 49, 52, 56, 9, 97,102,105,105, 49, 48, 49, 57, 54, 7,117,110,105,
+ 48, 52, 55, 54, 7,117,110,105, 48, 52, 55, 55, 7,117,110,105, 48, 52, 55, 56, 7,117,110,105, 48, 52, 55, 57, 7,117,110,105,
+ 48, 52, 55, 65, 7,117,110,105, 48, 52, 55, 66, 7,117,110,105, 48, 52, 55, 67, 7,117,110,105, 48, 52, 55, 68, 7,117,110,105,
+ 48, 52, 55, 69, 7,117,110,105, 48, 52, 55, 70, 7,117,110,105, 48, 52, 56, 48, 7,117,110,105, 48, 52, 56, 49, 7,117,110,105,
+ 48, 52, 56, 50, 7,117,110,105, 48, 52, 56, 51, 7,117,110,105, 48, 52, 56, 52, 7,117,110,105, 48, 52, 56, 53, 7,117,110,105,
+ 48, 52, 56, 54, 7,117,110,105, 48, 52, 56, 56, 7,117,110,105, 48, 52, 56, 57, 7,117,110,105, 48, 52, 56, 65, 7,117,110,105,
+ 48, 52, 56, 66, 7,117,110,105, 48, 52, 56, 67, 7,117,110,105, 48, 52, 56, 68, 7,117,110,105, 48, 52, 56, 69, 7,117,110,105,
+ 48, 52, 56, 70, 9, 97,102,105,105, 49, 48, 48, 53, 48, 9, 97,102,105,105, 49, 48, 48, 57, 56, 7,117,110,105, 48, 52, 57, 50,
+ 7,117,110,105, 48, 52, 57, 51, 7,117,110,105, 48, 52, 57, 52, 7,117,110,105, 48, 52, 57, 53, 7,117,110,105, 48, 52, 57, 54,
+ 7,117,110,105, 48, 52, 57, 55, 7,117,110,105, 48, 52, 57, 56, 7,117,110,105, 48, 52, 57, 57, 7,117,110,105, 48, 52, 57, 65,
+ 7,117,110,105, 48, 52, 57, 66, 7,117,110,105, 48, 52, 57, 67, 7,117,110,105, 48, 52, 57, 68, 7,117,110,105, 48, 52, 57, 69,
+ 7,117,110,105, 48, 52, 57, 70, 7,117,110,105, 48, 52, 65, 48, 7,117,110,105, 48, 52, 65, 49, 7,117,110,105, 48, 52, 65, 50,
+ 7,117,110,105, 48, 52, 65, 51, 7,117,110,105, 48, 52, 65, 52, 7,117,110,105, 48, 52, 65, 53, 7,117,110,105, 48, 52, 65, 54,
+ 7,117,110,105, 48, 52, 65, 55, 7,117,110,105, 48, 52, 65, 56, 7,117,110,105, 48, 52, 65, 57, 7,117,110,105, 48, 52, 65, 65,
+ 7,117,110,105, 48, 52, 65, 66, 7,117,110,105, 48, 52, 65, 67, 7,117,110,105, 48, 52, 65, 68, 7,117,110,105, 48, 52, 65, 69,
+ 7,117,110,105, 48, 52, 65, 70, 7,117,110,105, 48, 52, 66, 48, 7,117,110,105, 48, 52, 66, 49, 7,117,110,105, 48, 52, 66, 50,
+ 7,117,110,105, 48, 52, 66, 51, 7,117,110,105, 48, 52, 66, 52, 7,117,110,105, 48, 52, 66, 53, 7,117,110,105, 48, 52, 66, 54,
+ 7,117,110,105, 48, 52, 66, 55, 7,117,110,105, 48, 52, 66, 56, 7,117,110,105, 48, 52, 66, 57, 7,117,110,105, 48, 52, 66, 65,
+ 7,117,110,105, 48, 52, 66, 66, 7,117,110,105, 48, 52, 66, 67, 7,117,110,105, 48, 52, 66, 68, 7,117,110,105, 48, 52, 66, 69,
+ 7,117,110,105, 48, 52, 66, 70, 7,117,110,105, 48, 52, 67, 48, 7,117,110,105, 48, 52, 67, 49, 7,117,110,105, 48, 52, 67, 50,
+ 7,117,110,105, 48, 52, 67, 51, 7,117,110,105, 48, 52, 67, 52, 7,117,110,105, 48, 52, 67, 53, 7,117,110,105, 48, 52, 67, 54,
+ 7,117,110,105, 48, 52, 67, 55, 7,117,110,105, 48, 52, 67, 56, 7,117,110,105, 48, 52, 67, 57, 7,117,110,105, 48, 52, 67, 65,
+ 7,117,110,105, 48, 52, 67, 66, 7,117,110,105, 48, 52, 67, 67, 7,117,110,105, 48, 52, 67, 68, 7,117,110,105, 48, 52, 67, 69,
+ 7,117,110,105, 48, 52, 68, 48, 7,117,110,105, 48, 52, 68, 49, 7,117,110,105, 48, 52, 68, 50, 7,117,110,105, 48, 52, 68, 51,
+ 7,117,110,105, 48, 52, 68, 52, 7,117,110,105, 48, 52, 68, 53, 7,117,110,105, 48, 52, 68, 54, 7,117,110,105, 48, 52, 68, 55,
+ 7,117,110,105, 48, 52, 68, 56, 9, 97,102,105,105, 49, 48, 56, 52, 54, 7,117,110,105, 48, 52, 68, 65, 7,117,110,105, 48, 52,
+ 68, 66, 7,117,110,105, 48, 52, 68, 67, 7,117,110,105, 48, 52, 68, 68, 7,117,110,105, 48, 52, 68, 69, 7,117,110,105, 48, 52,
+ 68, 70, 7,117,110,105, 48, 52, 69, 48, 7,117,110,105, 48, 52, 69, 49, 7,117,110,105, 48, 52, 69, 50, 7,117,110,105, 48, 52,
+ 69, 51, 7,117,110,105, 48, 52, 69, 52, 7,117,110,105, 48, 52, 69, 53, 7,117,110,105, 48, 52, 69, 54, 7,117,110,105, 48, 52,
+ 69, 55, 7,117,110,105, 48, 52, 69, 56, 7,117,110,105, 48, 52, 69, 57, 7,117,110,105, 48, 52, 69, 65, 7,117,110,105, 48, 52,
+ 69, 66, 7,117,110,105, 48, 52, 69, 67, 7,117,110,105, 48, 52, 69, 68, 7,117,110,105, 48, 52, 69, 69, 7,117,110,105, 48, 52,
+ 69, 70, 7,117,110,105, 48, 52, 70, 48, 7,117,110,105, 48, 52, 70, 49, 7,117,110,105, 48, 52, 70, 50, 7,117,110,105, 48, 52,
+ 70, 51, 7,117,110,105, 48, 52, 70, 52, 7,117,110,105, 48, 52, 70, 53, 7,117,110,105, 48, 52, 70, 54, 7,117,110,105, 48, 52,
+ 70, 55, 7,117,110,105, 48, 52, 70, 56, 7,117,110,105, 48, 52, 70, 57, 7,117,110,105, 48, 53, 48, 48, 7,117,110,105, 48, 53,
+ 48, 49, 7,117,110,105, 48, 53, 48, 50, 7,117,110,105, 48, 53, 48, 51, 7,117,110,105, 48, 53, 48, 52, 7,117,110,105, 48, 53,
+ 48, 53, 7,117,110,105, 48, 53, 48, 54, 7,117,110,105, 48, 53, 48, 55, 7,117,110,105, 48, 53, 48, 56, 7,117,110,105, 48, 53,
+ 48, 57, 7,117,110,105, 48, 53, 48, 65, 7,117,110,105, 48, 53, 48, 66, 7,117,110,105, 48, 53, 48, 67, 7,117,110,105, 48, 53,
+ 48, 68, 7,117,110,105, 48, 53, 48, 69, 7,117,110,105, 48, 53, 48, 70, 7,117,110,105, 48, 53, 51, 49, 7,117,110,105, 48, 53,
+ 51, 50, 7,117,110,105, 48, 53, 51, 51, 7,117,110,105, 48, 53, 51, 52, 7,117,110,105, 48, 53, 51, 53, 7,117,110,105, 48, 53,
+ 51, 54, 7,117,110,105, 48, 53, 51, 55, 7,117,110,105, 48, 53, 51, 56, 7,117,110,105, 48, 53, 51, 57, 7,117,110,105, 48, 53,
+ 51, 65, 7,117,110,105, 48, 53, 51, 66, 7,117,110,105, 48, 53, 51, 67, 7,117,110,105, 48, 53, 51, 68, 7,117,110,105, 48, 53,
+ 51, 69, 7,117,110,105, 48, 53, 51, 70, 7,117,110,105, 48, 53, 52, 48, 7,117,110,105, 48, 53, 52, 49, 7,117,110,105, 48, 53,
+ 52, 50, 7,117,110,105, 48, 53, 52, 51, 7,117,110,105, 48, 53, 52, 52, 7,117,110,105, 48, 53, 52, 53, 7,117,110,105, 48, 53,
+ 52, 54, 7,117,110,105, 48, 53, 52, 55, 7,117,110,105, 48, 53, 52, 56, 7,117,110,105, 48, 53, 52, 57, 7,117,110,105, 48, 53,
+ 52, 65, 7,117,110,105, 48, 53, 52, 66, 7,117,110,105, 48, 53, 52, 67, 7,117,110,105, 48, 53, 52, 68, 7,117,110,105, 48, 53,
+ 52, 69, 7,117,110,105, 48, 53, 52, 70, 7,117,110,105, 48, 53, 53, 48, 7,117,110,105, 48, 53, 53, 49, 7,117,110,105, 48, 53,
+ 53, 50, 7,117,110,105, 48, 53, 53, 51, 7,117,110,105, 48, 53, 53, 52, 7,117,110,105, 48, 53, 53, 53, 7,117,110,105, 48, 53,
+ 53, 54, 7,117,110,105, 48, 53, 53, 57, 7,117,110,105, 48, 53, 53, 65, 7,117,110,105, 48, 53, 53, 66, 7,117,110,105, 48, 53,
+ 53, 67, 7,117,110,105, 48, 53, 53, 68, 7,117,110,105, 48, 53, 53, 69, 7,117,110,105, 48, 53, 53, 70, 7,117,110,105, 48, 53,
+ 54, 49, 7,117,110,105, 48, 53, 54, 50, 7,117,110,105, 48, 53, 54, 51, 7,117,110,105, 48, 53, 54, 52, 7,117,110,105, 48, 53,
+ 54, 53, 7,117,110,105, 48, 53, 54, 54, 7,117,110,105, 48, 53, 54, 55, 7,117,110,105, 48, 53, 54, 56, 7,117,110,105, 48, 53,
+ 54, 57, 7,117,110,105, 48, 53, 54, 65, 7,117,110,105, 48, 53, 54, 66, 7,117,110,105, 48, 53, 54, 67, 7,117,110,105, 48, 53,
+ 54, 68, 7,117,110,105, 48, 53, 54, 69, 7,117,110,105, 48, 53, 54, 70, 7,117,110,105, 48, 53, 55, 48, 7,117,110,105, 48, 53,
+ 55, 49, 7,117,110,105, 48, 53, 55, 50, 7,117,110,105, 48, 53, 55, 51, 7,117,110,105, 48, 53, 55, 52, 7,117,110,105, 48, 53,
+ 55, 53, 7,117,110,105, 48, 53, 55, 54, 7,117,110,105, 48, 53, 55, 55, 7,117,110,105, 48, 53, 55, 56, 7,117,110,105, 48, 53,
+ 55, 57, 7,117,110,105, 48, 53, 55, 65, 7,117,110,105, 48, 53, 55, 66, 7,117,110,105, 48, 53, 55, 67, 7,117,110,105, 48, 53,
+ 55, 68, 7,117,110,105, 48, 53, 55, 69, 7,117,110,105, 48, 53, 55, 70, 7,117,110,105, 48, 53, 56, 48, 7,117,110,105, 48, 53,
+ 56, 49, 7,117,110,105, 48, 53, 56, 50, 7,117,110,105, 48, 53, 56, 51, 7,117,110,105, 48, 53, 56, 52, 7,117,110,105, 48, 53,
+ 56, 53, 7,117,110,105, 48, 53, 56, 54, 7,117,110,105, 48, 53, 56, 55, 7,117,110,105, 48, 53, 56, 57, 7,117,110,105, 48, 53,
+ 56, 65, 9, 97,102,105,105, 53, 55, 51, 56, 56, 7,117,110,105, 49, 69, 48, 48, 7,117,110,105, 49, 69, 48, 49, 7,117,110,105,
+ 49, 69, 48, 50, 7,117,110,105, 49, 69, 48, 51, 7,117,110,105, 49, 69, 48, 52, 7,117,110,105, 49, 69, 48, 53, 7,117,110,105,
+ 49, 69, 48, 54, 7,117,110,105, 49, 69, 48, 55, 7,117,110,105, 49, 69, 48, 56, 7,117,110,105, 49, 69, 48, 57, 7,117,110,105,
+ 49, 69, 48, 65, 7,117,110,105, 49, 69, 48, 66, 7,117,110,105, 49, 69, 48, 67, 7,117,110,105, 49, 69, 48, 68, 7,117,110,105,
+ 49, 69, 48, 69, 7,117,110,105, 49, 69, 48, 70, 7,117,110,105, 49, 69, 49, 48, 7,117,110,105, 49, 69, 49, 49, 7,117,110,105,
+ 49, 69, 49, 50, 7,117,110,105, 49, 69, 49, 51, 7,117,110,105, 49, 69, 49, 52, 7,117,110,105, 49, 69, 49, 53, 7,117,110,105,
+ 49, 69, 49, 54, 7,117,110,105, 49, 69, 49, 55, 7,117,110,105, 49, 69, 49, 56, 7,117,110,105, 49, 69, 49, 57, 7,117,110,105,
+ 49, 69, 49, 65, 7,117,110,105, 49, 69, 49, 66, 7,117,110,105, 49, 69, 49, 67, 7,117,110,105, 49, 69, 49, 68, 7,117,110,105,
+ 49, 69, 49, 69, 7,117,110,105, 49, 69, 49, 70, 7,117,110,105, 49, 69, 50, 48, 7,117,110,105, 49, 69, 50, 49, 7,117,110,105,
+ 49, 69, 50, 50, 7,117,110,105, 49, 69, 50, 51, 7,117,110,105, 49, 69, 50, 52, 7,117,110,105, 49, 69, 50, 53, 7,117,110,105,
+ 49, 69, 50, 54, 7,117,110,105, 49, 69, 50, 55, 7,117,110,105, 49, 69, 50, 56, 7,117,110,105, 49, 69, 50, 57, 7,117,110,105,
+ 49, 69, 50, 65, 7,117,110,105, 49, 69, 50, 66, 7,117,110,105, 49, 69, 50, 67, 7,117,110,105, 49, 69, 50, 68, 7,117,110,105,
+ 49, 69, 50, 69, 7,117,110,105, 49, 69, 50, 70, 7,117,110,105, 49, 69, 51, 48, 7,117,110,105, 49, 69, 51, 49, 7,117,110,105,
+ 49, 69, 51, 50, 7,117,110,105, 49, 69, 51, 51, 7,117,110,105, 49, 69, 51, 52, 7,117,110,105, 49, 69, 51, 53, 7,117,110,105,
+ 49, 69, 51, 54, 7,117,110,105, 49, 69, 51, 55, 7,117,110,105, 49, 69, 51, 56, 7,117,110,105, 49, 69, 51, 57, 7,117,110,105,
+ 49, 69, 51, 65, 7,117,110,105, 49, 69, 51, 66, 7,117,110,105, 49, 69, 51, 67, 7,117,110,105, 49, 69, 51, 68, 7,117,110,105,
+ 49, 69, 51, 69, 7,117,110,105, 49, 69, 51, 70, 7,117,110,105, 49, 69, 52, 48, 7,117,110,105, 49, 69, 52, 49, 7,117,110,105,
+ 49, 69, 52, 50, 7,117,110,105, 49, 69, 52, 51, 7,117,110,105, 49, 69, 52, 52, 7,117,110,105, 49, 69, 52, 53, 7,117,110,105,
+ 49, 69, 52, 54, 7,117,110,105, 49, 69, 52, 55, 7,117,110,105, 49, 69, 52, 56, 7,117,110,105, 49, 69, 52, 57, 7,117,110,105,
+ 49, 69, 52, 65, 7,117,110,105, 49, 69, 52, 66, 7,117,110,105, 49, 69, 52, 67, 7,117,110,105, 49, 69, 52, 68, 7,117,110,105,
+ 49, 69, 52, 69, 7,117,110,105, 49, 69, 52, 70, 7,117,110,105, 49, 69, 53, 48, 7,117,110,105, 49, 69, 53, 49, 7,117,110,105,
+ 49, 69, 53, 50, 7,117,110,105, 49, 69, 53, 51, 7,117,110,105, 49, 69, 53, 52, 7,117,110,105, 49, 69, 53, 53, 7,117,110,105,
+ 49, 69, 53, 54, 7,117,110,105, 49, 69, 53, 55, 7,117,110,105, 49, 69, 53, 56, 7,117,110,105, 49, 69, 53, 57, 7,117,110,105,
+ 49, 69, 53, 65, 7,117,110,105, 49, 69, 53, 66, 7,117,110,105, 49, 69, 53, 67, 7,117,110,105, 49, 69, 53, 68, 7,117,110,105,
+ 49, 69, 53, 69, 7,117,110,105, 49, 69, 53, 70, 7,117,110,105, 49, 69, 54, 48, 7,117,110,105, 49, 69, 54, 49, 7,117,110,105,
+ 49, 69, 54, 50, 7,117,110,105, 49, 69, 54, 51, 7,117,110,105, 49, 69, 54, 52, 7,117,110,105, 49, 69, 54, 53, 7,117,110,105,
+ 49, 69, 54, 54, 7,117,110,105, 49, 69, 54, 55, 7,117,110,105, 49, 69, 54, 56, 7,117,110,105, 49, 69, 54, 57, 7,117,110,105,
+ 49, 69, 54, 65, 7,117,110,105, 49, 69, 54, 66, 7,117,110,105, 49, 69, 54, 67, 7,117,110,105, 49, 69, 54, 68, 7,117,110,105,
+ 49, 69, 54, 69, 7,117,110,105, 49, 69, 54, 70, 7,117,110,105, 49, 69, 55, 48, 7,117,110,105, 49, 69, 55, 49, 7,117,110,105,
+ 49, 69, 55, 50, 7,117,110,105, 49, 69, 55, 51, 7,117,110,105, 49, 69, 55, 52, 7,117,110,105, 49, 69, 55, 53, 7,117,110,105,
+ 49, 69, 55, 54, 7,117,110,105, 49, 69, 55, 55, 7,117,110,105, 49, 69, 55, 56, 7,117,110,105, 49, 69, 55, 57, 7,117,110,105,
+ 49, 69, 55, 65, 7,117,110,105, 49, 69, 55, 66, 7,117,110,105, 49, 69, 55, 67, 7,117,110,105, 49, 69, 55, 68, 7,117,110,105,
+ 49, 69, 55, 69, 7,117,110,105, 49, 69, 55, 70, 6, 87,103,114, 97,118,101, 6,119,103,114, 97,118,101, 6, 87, 97, 99,117,116,
+101, 6,119, 97, 99,117,116,101, 9, 87,100,105,101,114,101,115,105,115, 9,119,100,105,101,114,101,115,105,115, 7,117,110,105,
+ 49, 69, 56, 54, 7,117,110,105, 49, 69, 56, 55, 7,117,110,105, 49, 69, 56, 56, 7,117,110,105, 49, 69, 56, 57, 7,117,110,105,
+ 49, 69, 56, 65, 7,117,110,105, 49, 69, 56, 66, 7,117,110,105, 49, 69, 56, 67, 7,117,110,105, 49, 69, 56, 68, 7,117,110,105,
+ 49, 69, 56, 69, 7,117,110,105, 49, 69, 56, 70, 7,117,110,105, 49, 69, 57, 48, 7,117,110,105, 49, 69, 57, 49, 7,117,110,105,
+ 49, 69, 57, 50, 7,117,110,105, 49, 69, 57, 51, 7,117,110,105, 49, 69, 57, 52, 7,117,110,105, 49, 69, 57, 53, 7,117,110,105,
+ 49, 69, 57, 54, 7,117,110,105, 49, 69, 57, 55, 7,117,110,105, 49, 69, 57, 56, 7,117,110,105, 49, 69, 57, 57, 7,117,110,105,
+ 49, 69, 57, 65, 7,117,110,105, 49, 69, 57, 66, 7,117,110,105, 49, 69, 65, 48, 7,117,110,105, 49, 69, 65, 49, 7,117,110,105,
+ 49, 69, 65, 50, 7,117,110,105, 49, 69, 65, 51, 7,117,110,105, 49, 69, 65, 52, 7,117,110,105, 49, 69, 65, 53, 7,117,110,105,
+ 49, 69, 65, 54, 7,117,110,105, 49, 69, 65, 55, 7,117,110,105, 49, 69, 65, 56, 7,117,110,105, 49, 69, 65, 57, 7,117,110,105,
+ 49, 69, 65, 65, 7,117,110,105, 49, 69, 65, 66, 7,117,110,105, 49, 69, 65, 67, 7,117,110,105, 49, 69, 65, 68, 7,117,110,105,
+ 49, 69, 65, 69, 7,117,110,105, 49, 69, 65, 70, 7,117,110,105, 49, 69, 66, 48, 7,117,110,105, 49, 69, 66, 49, 7,117,110,105,
+ 49, 69, 66, 50, 7,117,110,105, 49, 69, 66, 51, 7,117,110,105, 49, 69, 66, 52, 7,117,110,105, 49, 69, 66, 53, 7,117,110,105,
+ 49, 69, 66, 54, 7,117,110,105, 49, 69, 66, 55, 7,117,110,105, 49, 69, 66, 56, 7,117,110,105, 49, 69, 66, 57, 7,117,110,105,
+ 49, 69, 66, 65, 7,117,110,105, 49, 69, 66, 66, 7,117,110,105, 49, 69, 66, 67, 7,117,110,105, 49, 69, 66, 68, 7,117,110,105,
+ 49, 69, 66, 69, 7,117,110,105, 49, 69, 66, 70, 7,117,110,105, 49, 69, 67, 48, 7,117,110,105, 49, 69, 67, 49, 7,117,110,105,
+ 49, 69, 67, 50, 7,117,110,105, 49, 69, 67, 51, 7,117,110,105, 49, 69, 67, 52, 7,117,110,105, 49, 69, 67, 53, 7,117,110,105,
+ 49, 69, 67, 54, 7,117,110,105, 49, 69, 67, 55, 7,117,110,105, 49, 69, 67, 56, 7,117,110,105, 49, 69, 67, 57, 7,117,110,105,
+ 49, 69, 67, 65, 7,117,110,105, 49, 69, 67, 66, 7,117,110,105, 49, 69, 67, 67, 7,117,110,105, 49, 69, 67, 68, 7,117,110,105,
+ 49, 69, 67, 69, 7,117,110,105, 49, 69, 67, 70, 7,117,110,105, 49, 69, 68, 48, 7,117,110,105, 49, 69, 68, 49, 7,117,110,105,
+ 49, 69, 68, 50, 7,117,110,105, 49, 69, 68, 51, 7,117,110,105, 49, 69, 68, 52, 7,117,110,105, 49, 69, 68, 53, 7,117,110,105,
+ 49, 69, 68, 54, 7,117,110,105, 49, 69, 68, 55, 7,117,110,105, 49, 69, 68, 56, 7,117,110,105, 49, 69, 68, 57, 7,117,110,105,
+ 49, 69, 68, 65, 7,117,110,105, 49, 69, 68, 66, 7,117,110,105, 49, 69, 68, 67, 7,117,110,105, 49, 69, 68, 68, 7,117,110,105,
+ 49, 69, 68, 69, 7,117,110,105, 49, 69, 68, 70, 7,117,110,105, 49, 69, 69, 48, 7,117,110,105, 49, 69, 69, 49, 7,117,110,105,
+ 49, 69, 69, 50, 7,117,110,105, 49, 69, 69, 51, 7,117,110,105, 49, 69, 69, 52, 7,117,110,105, 49, 69, 69, 53, 7,117,110,105,
+ 49, 69, 69, 54, 7,117,110,105, 49, 69, 69, 55, 7,117,110,105, 49, 69, 69, 56, 7,117,110,105, 49, 69, 69, 57, 7,117,110,105,
+ 49, 69, 69, 65, 7,117,110,105, 49, 69, 69, 66, 7,117,110,105, 49, 69, 69, 67, 7,117,110,105, 49, 69, 69, 68, 7,117,110,105,
+ 49, 69, 69, 69, 7,117,110,105, 49, 69, 69, 70, 7,117,110,105, 49, 69, 70, 48, 7,117,110,105, 49, 69, 70, 49, 6, 89,103,114,
+ 97,118,101, 6,121,103,114, 97,118,101, 7,117,110,105, 49, 69, 70, 52, 7,117,110,105, 49, 69, 70, 53, 7,117,110,105, 49, 69,
+ 70, 54, 7,117,110,105, 49, 69, 70, 55, 7,117,110,105, 49, 69, 70, 56, 7,117,110,105, 49, 69, 70, 57, 7,117,110,105, 49, 70,
+ 66, 70, 7,117,110,105, 49, 70, 70, 68, 7,117,110,105, 49, 70, 70, 69, 7,117,110,105, 50, 48, 48, 48, 7,117,110,105, 50, 48,
+ 48, 49, 7,117,110,105, 50, 48, 48, 50, 7,117,110,105, 50, 48, 48, 51, 7,117,110,105, 50, 48, 48, 52, 7,117,110,105, 50, 48,
+ 48, 53, 7,117,110,105, 50, 48, 48, 54, 7,117,110,105, 50, 48, 48, 55, 7,117,110,105, 50, 48, 48, 56, 7,117,110,105, 50, 48,
+ 48, 57, 7,117,110,105, 50, 48, 48, 65, 7,117,110,105, 50, 48, 48, 66, 9, 97,102,105,105, 54, 49, 54, 54, 52, 7, 97,102,105,
+105, 51, 48, 49, 7, 97,102,105,105, 50, 57, 57, 7, 97,102,105,105, 51, 48, 48, 7,117,110,105, 50, 48, 49, 48, 7,117,110,105,
+ 50, 48, 49, 49, 10,102,105,103,117,114,101,100, 97,115,104, 9, 97,102,105,105, 48, 48, 50, 48, 56, 7,117,110,105, 50, 48, 49,
+ 54, 13,117,110,100,101,114,115, 99,111,114,101,100, 98,108, 13,113,117,111,116,101,114,101,118,101,114,115,101,100, 7,117,110,
+105, 50, 48, 49, 70, 7,117,110,105, 50, 48, 50, 51, 14,111,110,101,100,111,116,101,110,108,101, 97,100,101,114, 14,116,119,111,
+100,111,116,101,110,108,101, 97,100,101,114, 7,117,110,105, 50, 48, 50, 55, 7,117,110,105, 50, 48, 51, 49, 6,109,105,110,117,
+116,101, 6,115,101, 99,111,110,100, 7,117,110,105, 50, 48, 51, 52, 7,117,110,105, 50, 48, 51, 53, 7,117,110,105, 50, 48, 51,
+ 54, 7,117,110,105, 50, 48, 51, 55, 7,117,110,105, 50, 48, 51, 56, 7,117,110,105, 50, 48, 51, 66, 9,101,120, 99,108, 97,109,
+100, 98,108, 7,117,110,105, 50, 48, 51, 68, 7,117,110,105, 50, 48, 51, 69, 7,117,110,105, 50, 48, 51, 70, 7,117,110,105, 50,
+ 48, 52, 48, 7,117,110,105, 50, 48, 52, 49, 7,117,110,105, 50, 48, 52, 50, 7,117,110,105, 50, 48, 52, 51, 7,117,110,105, 50,
+ 48, 52, 53, 7,117,110,105, 50, 48, 52, 54, 7,117,110,105, 50, 48, 52, 55, 7,117,110,105, 50, 48, 52, 56, 7,117,110,105, 50,
+ 48, 52, 57, 7,117,110,105, 50, 48, 52, 65, 7,117,110,105, 50, 48, 52, 66, 7,117,110,105, 50, 48, 52, 67, 7,117,110,105, 50,
+ 48, 52, 68, 7,117,110,105, 50, 48, 52, 69, 7,117,110,105, 50, 48, 52, 70, 7,117,110,105, 50, 48, 53, 48, 7,117,110,105, 50,
+ 48, 53, 49, 7,117,110,105, 50, 48, 53, 50, 7,117,110,105, 50, 48, 53, 51, 7,117,110,105, 50, 48, 53, 52, 7,117,110,105, 50,
+ 48, 53, 53, 7,117,110,105, 50, 48, 53, 54, 7,117,110,105, 50, 48, 53, 55, 7,117,110,105, 50, 48, 53, 56, 7,117,110,105, 50,
+ 48, 53, 57, 7,117,110,105, 50, 48, 53, 65, 7,117,110,105, 50, 48, 53, 66, 7,117,110,105, 50, 48, 53, 67, 7,117,110,105, 50,
+ 48, 53, 68, 7,117,110,105, 50, 48, 53, 69, 7,117,110,105, 50, 48, 55, 48, 7,117,110,105, 50, 48, 55, 49, 7,117,110,105, 50,
+ 48, 55, 52, 7,117,110,105, 50, 48, 55, 53, 7,117,110,105, 50, 48, 55, 54, 7,117,110,105, 50, 48, 55, 55, 7,117,110,105, 50,
+ 48, 55, 56, 7,117,110,105, 50, 48, 55, 57, 7,117,110,105, 50, 48, 55, 65, 7,117,110,105, 50, 48, 55, 66, 7,117,110,105, 50,
+ 48, 55, 67, 7,117,110,105, 50, 48, 55, 68, 7,117,110,105, 50, 48, 55, 69, 7,117,110,105, 50, 48, 55, 70, 7,117,110,105, 50,
+ 48, 56, 48, 7,117,110,105, 50, 48, 56, 49, 7,117,110,105, 50, 48, 56, 50, 7,117,110,105, 50, 48, 56, 51, 7,117,110,105, 50,
+ 48, 56, 52, 7,117,110,105, 50, 48, 56, 53, 7,117,110,105, 50, 48, 56, 54, 7,117,110,105, 50, 48, 56, 55, 7,117,110,105, 50,
+ 48, 56, 56, 7,117,110,105, 50, 48, 56, 57, 7,117,110,105, 50, 48, 56, 65, 7,117,110,105, 50, 48, 56, 66, 7,117,110,105, 50,
+ 48, 56, 67, 7,117,110,105, 50, 48, 56, 68, 7,117,110,105, 50, 48, 56, 69, 7,117,110,105, 50, 48, 65, 48, 13, 99,111,108,111,
+110,109,111,110,101,116, 97,114,121, 7,117,110,105, 50, 48, 65, 50, 4,108,105,114, 97, 7,117,110,105, 50, 48, 65, 53, 7,117,
+110,105, 50, 48, 65, 54, 6,112,101,115,101,116, 97, 7,117,110,105, 50, 48, 65, 56, 7,117,110,105, 50, 48, 65, 57, 9, 97,102,
+105,105, 53, 55, 54, 51, 54, 4,100,111,110,103, 4, 69,117,114,111, 7,117,110,105, 50, 48, 65, 68, 7,117,110,105, 50, 48, 65,
+ 69, 7,117,110,105, 50, 48, 65, 70, 7,117,110,105, 50, 48, 66, 49, 7,117,110,105, 50, 48, 66, 52, 7,117,110,105, 50, 48, 66,
+ 53, 7,117,110,105, 50, 48, 68, 54, 7,117,110,105, 50, 48, 68, 55, 7,117,110,105, 50, 49, 48, 48, 7,117,110,105, 50, 49, 48,
+ 51, 7,117,110,105, 50, 49, 48, 52, 9, 97,102,105,105, 54, 49, 50, 52, 56, 7,117,110,105, 50, 49, 48, 54, 7,117,110,105, 50,
+ 49, 48, 57, 7,117,110,105, 50, 49, 48, 69, 7,117,110,105, 50, 49, 48, 70, 8, 73,102,114, 97,107,116,117,114, 9, 97,102,105,
+105, 54, 49, 50, 56, 57, 9, 97,102,105,105, 54, 49, 51, 53, 50, 7,117,110,105, 50, 49, 49, 55, 11,119,101,105,101,114,115,116,
+114, 97,115,115, 8, 82,102,114, 97,107,116,117,114, 7,117,110,105, 50, 49, 49, 68, 12,112,114,101,115, 99,114,105,112,116,105,
+111,110, 7,117,110,105, 50, 49, 50, 48, 7,117,110,105, 50, 49, 50, 49, 7,117,110,105, 50, 49, 50, 54, 7,117,110,105, 50, 49,
+ 50, 55, 7,117,110,105, 50, 49, 50, 65, 7,117,110,105, 50, 49, 50, 66, 9,101,115,116,105,109, 97,116,101,100, 7,117,110,105,
+ 50, 49, 51, 50, 7,117,110,105, 50, 49, 51, 52, 5, 97,108,101,112,104, 7,117,110,105, 50, 49, 51, 66, 7,117,110,105, 50, 49,
+ 52, 66, 8,111,110,101,116,104,105,114,100, 9,116,119,111,116,104,105,114,100,115, 7,117,110,105, 50, 49, 53, 53, 7,117,110,
+105, 50, 49, 53, 54, 7,117,110,105, 50, 49, 53, 55, 7,117,110,105, 50, 49, 53, 56, 7,117,110,105, 50, 49, 53, 57, 7,117,110,
+105, 50, 49, 53, 65, 9,111,110,101,101,105,103,104,116,104, 12,116,104,114,101,101,101,105,103,104,116,104,115, 11,102,105,118,
+101,101,105,103,104,116,104,115, 12,115,101,118,101,110,101,105,103,104,116,104,115, 7,117,110,105, 50, 49, 53, 70, 7,117,110,
+105, 50, 49, 54, 48, 7,117,110,105, 50, 49, 54, 49, 7,117,110,105, 50, 49, 54, 50, 7,117,110,105, 50, 49, 54, 51, 7,117,110,
+105, 50, 49, 54, 52, 7,117,110,105, 50, 49, 54, 53, 7,117,110,105, 50, 49, 54, 54, 7,117,110,105, 50, 49, 54, 55, 7,117,110,
+105, 50, 49, 54, 56, 7,117,110,105, 50, 49, 54, 57, 7,117,110,105, 50, 49, 54, 65, 7,117,110,105, 50, 49, 54, 66, 7,117,110,
+105, 50, 49, 54, 67, 7,117,110,105, 50, 49, 54, 68, 7,117,110,105, 50, 49, 54, 69, 7,117,110,105, 50, 49, 54, 70, 7,117,110,
+105, 50, 49, 55, 48, 7,117,110,105, 50, 49, 55, 49, 7,117,110,105, 50, 49, 55, 50, 7,117,110,105, 50, 49, 55, 51, 7,117,110,
+105, 50, 49, 55, 52, 7,117,110,105, 50, 49, 55, 53, 7,117,110,105, 50, 49, 55, 54, 7,117,110,105, 50, 49, 55, 55, 7,117,110,
+105, 50, 49, 55, 56, 7,117,110,105, 50, 49, 55, 57, 7,117,110,105, 50, 49, 55, 65, 7,117,110,105, 50, 49, 55, 66, 7,117,110,
+105, 50, 49, 55, 67, 7,117,110,105, 50, 49, 55, 68, 7,117,110,105, 50, 49, 55, 69, 7,117,110,105, 50, 49, 55, 70, 7,117,110,
+105, 50, 49, 56, 48, 7,117,110,105, 50, 49, 56, 49, 7,117,110,105, 50, 49, 56, 50, 7,117,110,105, 50, 49, 56, 51, 9, 97,114,
+114,111,119,108,101,102,116, 7, 97,114,114,111,119,117,112, 10, 97,114,114,111,119,114,105,103,104,116, 9, 97,114,114,111,119,
+100,111,119,110, 9, 97,114,114,111,119, 98,111,116,104, 9, 97,114,114,111,119,117,112,100,110, 7,117,110,105, 50, 49, 57, 54,
+ 7,117,110,105, 50, 49, 57, 55, 7,117,110,105, 50, 49, 57, 56, 7,117,110,105, 50, 49, 57, 57, 14, 99, 97,114,114,105, 97,103,
+101,114,101,116,117,114,110, 7,117,110,105, 50, 50, 49, 51, 7,117,110,105, 50, 50, 49, 52, 7,117,110,105, 50, 50, 49, 54, 12,
+ 97,115,116,101,114,105,115,107,109, 97,116,104, 7,117,110,105, 50, 50, 49, 56, 7,117,110,105, 50, 50, 49, 66, 7,117,110,105,
+ 50, 50, 49, 67, 12,112,114,111,112,111,114,116,105,111,110, 97,108, 7,117,110,105, 50, 51, 49, 56, 7,117,110,105, 50, 51, 49,
+ 57, 7,117,110,105, 50, 51, 50, 53, 9, 97,110,103,108,101,108,101,102,116, 10, 97,110,103,108,101,114,105,103,104,116, 7,117,
+110,105, 50, 52, 54, 48, 7,117,110,105, 50, 52, 54, 49, 7,117,110,105, 50, 52, 54, 50, 7,117,110,105, 50, 52, 54, 51, 7,117,
+110,105, 50, 52, 54, 52, 7,117,110,105, 50, 52, 54, 53, 7,117,110,105, 50, 52, 54, 54, 7,117,110,105, 50, 52, 54, 55, 7,117,
+110,105, 50, 52, 54, 56, 7,117,110,105, 50, 52, 54, 57, 7,117,110,105, 50, 54, 66, 48, 7,117,110,105, 50, 54, 66, 49, 7,117,
+110,105, 50, 56, 48, 48, 7,117,110,105, 70, 66, 48, 48, 7,117,110,105, 70, 66, 48, 51, 7,117,110,105, 70, 66, 48, 52, 7,117,
+110,105, 70, 66, 48, 53, 7,117,110,105, 70, 66, 48, 54, 7,117,110,105, 70, 66, 49, 51, 7,117,110,105, 70, 66, 49, 52, 7,117,
+110,105, 70, 66, 49, 53, 7,117,110,105, 70, 66, 49, 54, 7,117,110,105, 70, 66, 49, 55, 7,117,110,105, 70, 70, 70, 68, 9,100,
+108, 76,116, 99, 97,114,111,110, 8, 68,105,101,114,101,115,105,115, 5, 65, 99,117,116,101, 5, 84,105,108,100,101, 5, 71,114,
+ 97,118,101, 10, 67,105,114, 99,117,109,102,108,101,120, 5, 67, 97,114,111,110, 12,117,110,105, 48, 51, 49, 49, 46, 99, 97,115,
+101, 5, 66,114,101,118,101, 9, 68,111,116, 97, 99, 99,101,110,116, 12, 72,117,110,103, 97,114,117,109,108, 97,117,116, 11, 68,
+111,117, 98,108,101, 97, 99,117,116,101, 11,117,110,105, 48, 51, 48, 56, 48, 51, 48, 52, 11,117,110,105, 48, 51, 48, 52, 48, 51,
+ 48, 56, 11,117,110,105, 48, 51, 48, 55, 48, 51, 48, 52, 11,117,110,105, 48, 51, 48, 56, 48, 51, 48, 49, 11,117,110,105, 48, 51,
+ 48, 56, 48, 51, 48, 48, 11,117,110,105, 48, 51, 48, 52, 48, 51, 48, 49, 11,117,110,105, 48, 51, 48, 52, 48, 51, 48, 48, 11,117,
+110,105, 48, 51, 48, 51, 48, 51, 48, 52, 11,117,110,105, 48, 51, 48, 56, 48, 51, 48, 67, 11,117,110,105, 48, 51, 48, 51, 48, 51,
+ 48, 56, 11,117,110,105, 48, 51, 48, 67, 48, 51, 48, 55, 11,117,110,105, 48, 51, 48, 51, 48, 51, 48, 49, 11,117,110,105, 48, 51,
+ 48, 50, 48, 51, 48, 49, 11,117,110,105, 48, 51, 48, 50, 48, 51, 48, 48, 11,117,110,105, 48, 51, 48, 50, 48, 51, 48, 51, 11,117,
+110,105, 48, 51, 48, 54, 48, 51, 48, 51, 11,117,110,105, 48, 51, 48, 54, 48, 51, 48, 49, 11,117,110,105, 48, 51, 48, 54, 48, 51,
+ 48, 48, 11,117,110,105, 48, 51, 48, 54, 48, 51, 48, 57, 11,117,110,105, 48, 51, 48, 50, 48, 51, 48, 57, 0, 0, 0, 2, 0, 0,
+ 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 20,108, 0, 0, 0, 16, 0, 0, 0, 7, 0, 1, 0, 2, 0, 0, 0, 1,255,255,255,255,
+ 0, 1, 0, 3, 0, 0, 0, 0,255,255,255,254, 0, 1, 0, 2, 0, 0, 0, 1,255,255,255,255, 0, 1, 0, 3, 0, 0, 0, 0,
+255,255,255,254, 0, 1, 0, 4, 0, 0, 0, 2,255,255,255,255, 0, 1, 0, 5, 0, 0, 0, 0,255,255,255,253, 0, 1, 0, 4,
+ 0, 0, 0, 2,255,255,255,255, 0, 1, 0, 5, 0, 0, 0, 0,255,255,255,253, 0, 1, 0, 4, 0, 0, 0, 2,255,255,255,255,
+ 0, 1, 0, 5, 0, 0, 0, 0,255,255,255,253, 0, 2, 0, 2, 0, 0, 0, 4,255,255,255,255, 0, 2, 0, 0, 0, 0, 0, 0,
+255,255,255,251, 0, 11, 0, 2, 0, 0, 0, 8,255,255,255,255, 0, 11, 0, 0, 0, 0, 0, 0,255,255,255,247, 0, 0, 0, 0,
+255,255,255,255,255,255,255,255, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,176, 64, 0, 0, 1, 0, 0, 0, 4,
+ 0, 0, 0, 6, 0, 0, 0, 20, 0, 0, 0,242, 0, 0, 1, 34, 0, 0, 1, 98, 0, 4, 0, 6, 0, 10, 0, 48, 0, 3, 0, 12,
+ 2, 92, 2, 72, 0, 78, 2, 97, 2, 94, 0,120, 2,104, 2,100, 0,128, 2,110, 2,107, 0,138, 2,123, 2,113, 0,146, 2,138,
+ 2,129, 0,168, 2,140, 2,140, 0,188, 2,154, 2,142, 0,190, 4,123, 4,123, 0,216, 5,253, 5,252, 0,218,255,255,255,255,
+ 0, 0, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5,
+ 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5,
+ 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5,
+ 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5,
+ 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 5, 0, 4, 0, 5, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 2, 0, 0, 0, 1, 0, 2, 0, 3, 0, 3, 0, 4, 0, 3, 0, 5, 0, 4, 0, 6, 0, 6, 0, 7, 0, 6, 0, 5,
+ 0, 7, 0, 0, 0, 0,255,255,255,255, 0, 2,128, 0,255,255, 0, 0, 0, 1, 0, 0,255,255,255,255, 0, 0, 0, 0, 0, 1,
+255,255, 0, 2, 0, 0,255,255,255,255, 0, 3,128, 0,255,255, 0, 2, 0, 0, 0, 0, 0, 3,255,255, 0, 3, 0, 0,255,255,
+255,255, 0, 0, 0, 16, 0, 0, 0, 28, 0, 0, 0, 40, 0, 0, 0, 52, 0, 4, 0, 6, 0, 0, 0, 0,255,255, 0, 0, 0, 4,
+ 0, 6, 0, 0, 0, 0,255,255, 0, 0, 0, 4, 0, 6, 0, 0, 0, 0,255,255, 0, 0, 0, 4, 0, 6, 0, 0, 0, 0,255,255,
+ 0, 0, 0, 0, 0, 0, 4, 52, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 22, 0, 0, 0, 28, 0, 0, 0,160, 0, 0, 2,132,
+ 0, 0, 3, 38, 0, 0, 3,186, 0, 0, 4, 4, 0, 4, 0, 6, 0, 13, 0, 48, 0, 3, 0, 30, 0, 3, 0, 3, 0, 96, 0, 17,
+ 0, 17, 0, 98, 0, 41, 0, 41, 0,100, 0, 81, 0, 81, 0,102, 0,114, 0,114, 0,104, 2, 21, 2, 21, 0,106, 2, 73, 2, 73,
+ 0,108, 2, 76, 2, 75, 0,110, 2, 80, 2, 78, 0,114, 2, 83, 2, 82, 0,120, 2,112, 2,111, 0,124, 5,159, 5,159, 0,128,
+ 5,162, 5,162, 0,130,255,255,255,255, 0, 0, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0, 11, 0, 12, 0, 13,
+ 0, 14, 0, 15, 0, 16, 0, 17, 0, 18, 0, 19, 0, 20, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0,
+ 0, 3, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 6, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0, 3, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 5, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0, 3, 0, 4, 0, 7, 0, 8,
+ 0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 16, 0, 5, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 17,
+ 0, 0, 0, 0, 0, 3, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 6,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 18, 0, 0, 0, 0, 0, 3, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 19, 0, 0, 0, 3, 0, 4,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 2, 0, 0, 0, 20, 0, 3, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 5, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0, 3, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, 6, 0, 22, 0, 22, 0, 22, 0, 22, 0, 22, 0, 22, 0, 22, 0, 22,
+ 0, 22, 0, 22, 0, 22, 0, 22, 0, 22, 0, 22, 0, 22, 0, 22, 0, 22, 0, 22, 0, 22, 0, 22, 0, 23, 0, 22, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0, 3, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 5, 0, 24, 0, 25, 0, 25, 0, 25, 0, 25, 0, 25, 0, 25, 0, 25, 0, 25, 0, 25, 0, 25, 0, 25, 0, 25,
+ 0, 25, 0, 25, 0, 25, 0, 25, 0, 25, 0, 25, 0, 25, 0, 25, 0, 25, 0, 26, 0, 0, 0, 0, 0, 0, 0, 2,128, 0, 0, 0,
+ 0, 3,128, 0, 0, 0, 0, 5,128, 0, 0, 0, 0, 6,128, 0, 0, 0, 0, 7,128, 0, 0, 0, 0, 9,128, 0, 0, 0, 0, 0,
+160, 0, 0, 0, 0, 0,160, 0, 0, 2, 0, 0,160, 0, 0, 4, 0, 0,160, 0, 0, 6, 0, 0,160, 0, 0, 8, 0, 0,160, 0,
+ 0, 10, 0, 0,160, 0, 0, 12, 0, 0,160, 0, 0, 14, 0, 0,160, 0, 0, 16, 0, 0,160, 0, 0, 18, 0, 4,128, 0, 0, 0,
+ 0, 0,160, 0, 0, 20, 0, 0,160, 0, 0, 23, 0, 0,160, 0, 0, 25, 0, 8,128, 0, 0, 0, 0, 0, 96, 0, 0, 27, 0, 0,
+160, 0, 0, 29, 0, 10,128, 0, 0, 0, 0, 0, 96, 0, 0, 32, 0, 0,160, 0, 0, 34, 63,255,253,183,191,255,255,254, 63,255,
+253,183,128, 0, 0, 0, 63,255,253,184,128, 0, 0, 2, 63,255,253,184,128, 0, 0, 4, 63,255,253,185,128, 0, 0, 6, 63,255,
+253,186,128, 0, 0, 8, 63,255,253,186,128, 0, 0, 10, 63,255,253,187,128, 0, 0, 12, 63,255,253,161,128, 0, 0, 14, 63,255,
+253,162,128, 0, 0, 16, 0, 0, 0, 3, 0, 0, 0, 4,128, 0, 0, 5, 63,255,255,238,191,255,255,166, 63,255,255,200,191,255,
+254, 5, 63,255,250,124,191,255,250,125, 63,255,250,126, 63,255,250,127,191,255,250,128, 63,255,250,126,191,255,250,127, 63,255,
+250,128, 63,255,250,129,191,255,250,130, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0,
+ 0, 5, 0, 0, 0, 6, 0, 0, 0, 7, 0, 0, 0, 8, 0, 0, 0, 9, 0, 0, 0, 0, 0, 10, 0, 0, 0, 11, 0, 0, 0, 12,
+ 0, 0, 0, 13, 0, 0, 0, 0, 0, 14, 0, 0, 0, 15, 0, 0, 0, 0, 0, 16, 0,118, 2, 53, 0,113, 2, 49, 2, 50, 0,106,
+ 2, 51, 2, 54, 0,122, 2, 52, 5,155, 6, 3, 1, 11, 5,160, 5,161, 5,163, 5,164, 0, 0, 0, 0, 0,144, 0, 0, 0, 2,
+ 0, 0, 0, 1, 0, 0, 0, 6, 0, 0, 0, 28, 0, 0, 0, 62, 0, 0, 0, 98, 0, 0, 0,116, 0, 0, 0,124, 0, 0, 0,128,
+ 0, 4, 0, 6, 0, 2, 0, 12, 0, 1, 0, 0, 4, 86, 4, 86, 0, 30, 4,115, 4,115, 0, 32,255,255,255,255, 0, 0, 0, 4,
+ 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2,128, 0, 0, 0, 0, 0,160, 0, 0, 0, 63,255,251,141,191,255,251,171,
+ 0, 0, 0, 0, 4,120, 0, 0, 0, 0, 1, 48, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 10, 0, 0, 0, 28, 0, 0, 0, 94,
+ 0, 0, 0,174, 0, 0, 0,222, 0, 0, 1, 6, 0, 0, 1, 26, 0, 4, 0, 6, 0, 6, 0, 24, 0, 2, 0, 12, 4, 86, 4, 86,
+ 0, 54, 4, 92, 4, 92, 0, 56, 4, 94, 4, 94, 0, 58, 4,101, 4,101, 0, 60, 4,103, 4,103, 0, 62, 4,111, 4,111, 0, 64,
+255,255,255,255, 0, 0, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 4, 0, 5, 0, 1, 0, 6, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 7,
+ 0, 2, 0, 0, 0, 0, 0, 0, 0, 2,128, 0, 0, 0, 0, 3,128, 0, 0, 0, 0, 0,160, 0, 0, 0, 0, 0,160, 0, 0, 2,
+ 0, 0,160, 0, 0, 4, 0, 0,160, 0, 0, 6, 0, 0,160, 0, 0, 8, 63,255,251,170,191,255,251,156, 63,255,251,166,191,255,
+251,158, 63,255,251,166,191,255,251,160, 63,255,251,159,191,255,251,162, 63,255,251,161,191,255,251,154, 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 6,126, 6,127, 6,129, 6,125, 6,128, 0, 0, 4,228, 0, 0, 0, 2,
+ 0, 0, 0, 2, 0, 0, 0, 23, 0, 0, 0, 28, 0, 0, 0,162, 0, 0, 3, 84, 0, 0, 3,246, 0, 0, 4,122, 0, 0, 4,188,
+ 0, 4, 0, 6, 0, 13, 0, 48, 0, 3, 0, 30, 0, 18, 0, 18, 0, 96, 0, 36, 0, 36, 0, 98, 0, 41, 0, 40, 0,100, 0, 48,
+ 0, 47, 0,104, 0, 55, 0, 53, 0,108, 0, 59, 0, 59, 0,114, 0, 68, 0, 68, 0,116, 0, 70, 0, 70, 0,118, 0, 73, 0, 73,
+ 0,120, 0, 76, 0, 76, 0,122, 0, 79, 0, 79, 0,124, 0, 82, 0, 82, 0,126, 0, 88, 0, 86, 0,128,255,255,255,255, 0, 0,
+ 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 16, 0, 17, 0, 18, 0, 19,
+ 0, 20, 0, 21, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 0, 3, 0, 4,
+ 0, 0, 0, 5, 0, 6, 0, 7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 0, 3, 0, 4, 0, 0, 0, 5, 0, 6, 0, 7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 0, 3, 0, 4, 0, 0, 0, 5,
+ 0, 6, 0, 7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ 0, 0, 0, 0, 0, 2, 0, 3, 0, 4, 0, 10, 0, 5, 0, 6, 0, 7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 0, 3, 0, 4, 0, 0, 0, 5, 0, 6, 0, 7,
+ 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 12,
+ 0, 2, 0, 3, 0, 4, 0, 0, 0, 5, 0, 6, 0, 7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 13, 0, 1, 0, 0, 0, 0, 0, 2, 0, 3, 0, 4, 0, 0, 0, 5, 0, 6, 0, 7, 0, 0, 0, 0,
+ 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 14, 0, 0, 0, 2, 0, 3,
+ 0, 4, 0, 0, 0, 5, 0, 6, 0, 7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 0, 3, 0, 4, 0, 0, 0, 5, 0, 6, 0, 7, 0, 0, 0, 0, 0, 0, 0, 8,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 0, 3, 0, 4, 0, 0,
+ 0, 5, 0, 16, 0, 7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0, 0, 2, 0, 3, 0, 4, 0, 0, 0, 5, 0, 6, 0, 7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 0, 3, 0, 4, 0, 0, 0, 5, 0, 6,
+ 0, 7, 0, 0, 0, 0, 0, 18, 0, 8, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 2, 0, 3, 0, 4, 0, 0, 0, 5, 0, 6, 0, 20, 0, 21, 0, 22, 0, 0, 0, 8, 0, 0, 0, 0, 0, 23, 0, 23,
+ 0, 23, 0, 23, 0, 23, 0, 23, 0, 23, 0, 23, 0, 23, 0, 23, 0, 23, 0, 23, 0, 23, 0, 23, 0, 23, 0, 23, 0, 23, 0, 24,
+ 0, 25, 0, 23, 0, 23, 0, 23, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2,
+ 0, 3, 0, 4, 0, 0, 0, 5, 0, 6, 0, 7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
+128, 0, 0, 0, 0, 4,128, 0, 0, 0, 0, 5,128, 0, 0, 0, 0, 6,128, 0, 0, 0, 0, 8,128, 0, 0, 0, 0, 10,128, 0,
+ 0, 0, 0, 12,128, 0, 0, 0, 0, 14,128, 0, 0, 0, 0, 3,128, 0, 0, 0, 0, 0,160, 0, 0, 0, 0, 0,160, 0, 0, 3,
+ 0, 0,160, 0, 0, 5, 0, 7,128, 0, 0, 0, 0, 0,160, 0, 0, 7, 0, 9,128, 0, 0, 0, 0, 0,160, 0, 0, 10, 0, 11,
+128, 0, 0, 0, 0, 0,160, 0, 0, 13, 0, 0,160, 0, 0, 16, 0, 13,128, 0, 0, 0, 0, 0,160, 0, 0, 19, 0, 0,160, 0,
+ 0, 21, 0, 0, 96, 0, 0, 23, 0, 0,160, 0, 0, 25, 0, 0,160, 0, 0, 28, 0, 0,160, 0, 0, 31, 63,255,255,197, 63,255,
+255,221,191,255,255,217, 63,255,255,173,191,255,255,207, 63,255,255,213,191,255,255,208, 63,255,255,216, 63,255,255,224,191,255,
+255,210, 63,255,255,196, 63,255,255,249,191,255,255,200, 63,255,255,187, 63,255,255,252,191,255,255,201, 63,255,255,184, 63,255,
+255,255,191,255,255,204, 63,255,255,199,191,255,255,203, 63,255,255,198,191,255,255,205, 63,255,255,206,191,255,255,207, 63,255,
+255,205, 63,255,255,209,191,255,255,210, 63,255,255,205, 63,255,255,212,191,255,255,213, 63,255,255,200,191,255,255,202, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 5, 0, 0,
+ 0, 0, 0, 6, 0, 0, 0, 7, 0, 0, 0, 8, 0, 0, 0, 9, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 11, 0, 0, 0, 12,
+ 6, 25, 5,241, 6, 14, 6, 15, 5,254, 6, 1, 6, 2, 6,119, 6,120, 6,118, 6,121, 6,122, 6,124, 0, 0, 0, 0, 0,220,
+ 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 6, 0, 0, 0, 28, 0, 0, 0, 62, 0, 0, 0,110, 0, 0, 0,152, 0, 0, 0,184,
+ 0, 0, 0,200, 0, 4, 0, 6, 0, 2, 0, 12, 0, 1, 0, 0, 0, 4, 0, 4, 0, 30, 0, 34, 0, 34, 0, 32,255,255,255,255,
+ 0, 0, 0, 4, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 6, 0, 0, 0, 0, 0, 0, 0, 2,128, 0,
+ 0, 0, 0, 3,128, 0, 0, 0, 0, 0,160, 0, 0, 0, 0, 0,160, 0, 0, 2, 0, 0,160, 0, 0, 4, 0, 0,160, 0, 0, 6,
+ 63,255,255,252,191,255,255,253, 63,255,255,224,191,255,255,255, 0, 0, 0, 0,191,255,255,227, 63,255,255,228,191,255,255,229,
+ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 5,169, 5,182, 5,181, 5,180, 0, 0, 6, 56, 0, 0, 0, 2,
+ 0, 0, 0, 8, 0, 0, 0, 14, 0, 0, 0, 28, 0, 0, 0, 84, 0, 0, 2,132, 0, 0, 3,182, 0, 0, 5, 46, 0, 0, 5,234,
+ 0, 4, 0, 6, 0, 3, 0, 12, 0, 1, 0, 6, 0, 18, 0, 18, 0, 36, 0, 27, 0, 20, 0, 38, 5,177, 5,177, 0, 54,255,255,
+255,255, 0, 0, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ 0, 2, 0, 3, 0, 4, 0, 5, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 1, 0, 2, 0, 3,
+ 0, 4, 0, 5, 0, 0, 0, 6, 0, 0, 0, 8, 0, 9, 0, 9, 0, 9, 0, 9, 0, 9, 0, 9, 0, 10, 0, 11, 0, 12, 0, 13,
+ 0, 14, 0, 9, 0, 15, 0, 9, 0, 16, 0, 16, 0, 16, 0, 16, 0, 16, 0, 16, 0, 17, 0, 18, 0, 19, 0, 20, 0, 21, 0, 16,
+ 0, 22, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 0, 0, 6, 0, 0, 0, 24,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 25, 0, 4, 0, 26, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 27, 0, 4, 0, 28, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 29, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 0, 0, 6, 0, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ 0, 2, 0, 3, 0, 31, 0, 32, 0, 0, 0, 6, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 3,
+ 0, 34, 0, 35, 0, 0, 0, 6, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5,
+ 0, 0, 0, 6, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 39, 0, 0, 0, 6,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 40, 0, 0, 0, 6, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 0, 0, 6, 0, 0, 0, 42, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 43, 0, 6, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 45, 0, 6, 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 0, 1,
+ 0, 2, 0, 3, 0, 4, 0, 5, 0, 0, 0, 6, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 3,
+ 0, 4, 0, 5, 0, 0, 0, 6, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5,
+ 0, 0, 0, 6, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,128, 0, 0, 0, 0, 5,128, 0, 0, 0, 0, 8,128, 0, 0, 0,
+ 0, 11,128, 0, 0, 0, 0, 14,128, 0, 0, 0, 0, 17,128, 0, 0, 0, 0, 4,128, 0, 0, 0, 0, 3,128, 0, 0, 0, 0, 0,
+ 96, 0, 0, 0, 0, 0,160, 0, 0, 2, 0, 0,160, 0, 0, 5, 0, 0,160, 0, 0, 8, 0, 0,160, 0, 0, 11, 0, 0,160, 0,
+ 0, 14, 0, 0,160, 0, 0, 17, 0, 0, 96, 0, 0, 20, 0, 0,160, 0, 0, 22, 0, 0,160, 0, 0, 25, 0, 0,160, 0, 0, 28,
+ 0, 0,160, 0, 0, 31, 0, 0,160, 0, 0, 34, 0, 0,160, 0, 0, 37, 0, 7,128, 0, 0, 0, 0, 6,128, 0, 0, 0, 0, 0,
+160, 0, 0, 40, 0, 0,160, 0, 0, 43, 0, 0,160, 0, 0, 46, 0, 0,160, 0, 0, 49, 0, 10,128, 0, 0, 0, 0, 9,128, 0,
+ 0, 0, 0, 0,160, 0, 0, 52, 0, 0,160, 0, 0, 55, 0, 0,160, 0, 0, 58, 0, 0,160, 0, 0, 61, 0, 0,160, 0, 0, 64,
+ 0, 0,160, 0, 0, 67, 0, 13,128, 0, 0, 0, 0, 12,128, 0, 0, 0, 0, 0,160, 0, 0, 70, 0, 0,160, 0, 0, 73, 0, 16,
+128, 0, 0, 0, 0, 15,128, 0, 0, 0, 0, 0,160, 0, 0, 76, 0, 0,160, 0, 0, 79, 0, 0,160, 0, 0, 82, 0, 0,160, 0,
+ 0, 85, 0, 19,128, 0, 0, 0, 0, 18,128, 0, 0, 0, 0, 0,160, 0, 0, 88, 0, 0,160, 0, 0, 91, 63,255,250, 79,191,255,
+255,237, 63,255,255,237, 63,255,250, 82,191,255,255,240, 63,255,255,239, 63,255,250, 85,191,255,255,243, 63,255,255,241, 63,255,
+250, 88,191,255,255,246, 63,255,255,243, 63,255,250, 91,191,255,255,249, 63,255,255,245, 63,255,250, 94,191,255,255,252, 63,255,
+255,246, 63,255,250, 97,191,255,255,255, 0, 0, 0, 2,128, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 5,128, 0, 0, 4, 0, 0,
+ 0, 3, 0, 0, 0, 8,128, 0, 0, 7, 0, 0, 0, 5, 0, 0, 0, 11,128, 0, 0, 10, 0, 0, 0, 7, 0, 0, 0, 14,128, 0,
+ 0, 13, 0, 0, 0, 9, 0, 0, 0, 17,128, 0, 0, 16, 0, 0, 0, 10, 0, 0, 0, 20,128, 0, 0, 19, 0, 0, 0, 18, 63,255,
+250,120,128, 0, 0, 21, 0, 0, 0, 19, 63,255,250,123,128, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 29,128, 0, 0, 27, 0, 0,
+ 0, 25, 0, 0, 0, 32,128, 0, 0, 30, 0, 0, 0, 29, 63,255,250,132,128, 0, 0, 32, 0, 0, 0, 31, 63,255,250,135,128, 0,
+ 0, 35, 0, 0, 0, 31, 63,255,250,138,128, 0, 0, 38, 0, 0, 0, 38, 0, 0, 0, 44,128, 0, 0, 41, 0, 0, 0, 40, 0, 0,
+ 0, 47,128, 0, 0, 44, 0, 0, 0, 40, 0, 0, 0, 50,128, 0, 0, 47, 0, 0, 0, 46, 63,255,250,150,128, 0, 0, 49, 0, 0,
+ 0, 49, 0, 0, 0, 56,128, 0, 0, 52, 0, 0, 0, 51, 63,255,250,156,128, 0, 0, 54, 0, 0, 0, 52, 63,255,250,159,128, 0,
+ 0, 57, 0, 0, 0, 57, 0, 0, 0, 65,128, 0, 0, 60, 0, 0, 0, 58, 0, 0, 0, 68,128, 0, 0, 63, 0, 0, 0, 61, 63,255,
+250,168,128, 0, 0, 64, 0, 0, 0, 64, 0, 0, 0, 74,128, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+ 0, 2, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 6, 0, 0, 0, 7, 0, 0,
+ 0, 0, 0, 8, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0,
+ 0, 13, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 18,
+ 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0, 23, 0, 0,
+ 0, 0, 0, 24, 0, 0, 0, 0, 0, 25, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 27, 0, 0, 0, 0, 0, 28, 0, 0, 0, 0,
+ 0, 29, 0, 0, 0, 0, 0, 30, 0, 0, 0, 0, 0, 31, 6, 39, 0,127, 6, 27, 0,126, 6, 29, 6, 33, 6, 35, 6, 39, 0,127,
+ 6, 27, 0,126, 6, 29, 6, 33, 6, 35, 6, 28, 6, 30, 6, 28, 6, 30, 0,128, 6, 31, 6, 36, 0,128, 6, 31, 6, 36, 6, 32,
+ 6, 32, 6, 34, 6, 37, 6, 34, 6, 37, 6, 38, 6, 38, 0, 0, 0, 1, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ 0, 0, 0, 60, 0, 0, 1, 0, 0, 1, 0, 2, 0, 0, 0, 64, 0, 0, 1, 1, 0, 2, 0, 1, 0, 0, 0, 72,192, 0, 1, 2,
+ 0, 11, 0, 1, 0, 0, 0, 76,192, 0, 1, 3, 0, 0, 1, 4, 0, 2, 1, 5, 0, 4, 1, 6, 0, 2, 1, 7, 0, 2, 1, 8,
+ 0, 2, 0, 0, 0, 1, 0, 0, 0, 2, 0, 6, 0, 97, 1,128, 0, 6, 0,198, 0, 3, 0, 3, 0, 10, 0, 5, 0, 4, 0, 11,
+ 0, 8, 0, 6, 0, 5, 0, 10, 0, 9, 0, 11, 0, 11, 0, 11, 17, 11, 0, 12, 0, 12, 31, 11, 0, 13, 0, 13, 0, 11, 0, 14,
+ 0, 14, 0, 4, 0, 15, 0, 15, 0, 7, 0, 16, 0, 16, 0, 4, 0, 18, 0, 17, 0, 7, 0, 28, 0, 19, 0, 3, 0, 29, 0, 29,
+ 0, 7, 0, 30, 0, 30, 0, 11, 0, 31, 0, 31, 18, 11, 0, 32, 0, 32, 0, 11, 0, 33, 0, 33, 30, 11, 0, 35, 0, 34, 0, 11,
+ 0, 62, 0, 62, 18, 11, 0, 63, 0, 63, 0, 11, 0, 64, 0, 64, 30, 11, 0, 67, 0, 65, 0, 11, 0, 94, 0, 94, 18, 11, 0, 95,
+ 0, 95, 0, 11, 0, 96, 0, 96, 30, 11, 0, 97, 0, 97, 0, 11, 0, 98, 0, 98, 0, 7, 0, 99, 0, 99, 0, 11, 0,103, 0,100,
+ 0, 5, 0,107, 0,104, 0, 11, 0,113, 0,109, 0, 11, 0,115, 0,114, 0, 5, 0,117, 0,116, 0, 3, 0,118, 0,118, 0, 11,
+ 0,122, 0,120, 0, 11, 0,123, 0,123, 0, 3, 0,129, 0,125, 0, 11, 0,153, 0,153, 0, 11, 0,185, 0,185, 0, 11, 2, 19,
+ 2, 18, 0, 11, 2, 40, 2, 27, 0, 11, 2, 56, 2, 43, 0, 11, 2, 68, 2, 62, 0, 11, 2, 71, 2, 70, 0, 11, 2,154, 2, 72,
+128, 11, 2,156, 2,155, 0, 11, 2,160, 2,157,128, 11, 2,162, 2,161, 0, 11, 2,166, 2,164, 0, 11, 2,168, 2,168, 0, 11,
+ 3, 19, 3, 19, 0, 11, 3,163, 3,160,128, 11, 3,165, 3,164, 0, 11, 4,122, 4,122, 0, 11, 4,123, 4,123, 0, 7, 5,116,
+ 5,114, 0, 11, 5,127, 5,117, 0, 10, 5,130, 5,128, 0, 11, 5,132, 5,131, 0, 10, 5,156, 5,133, 0, 11, 5,161, 5,157,
+ 0, 5, 5,165, 5,162, 0, 11, 5,166, 5,166, 17, 11, 5,167, 5,167, 31, 11, 5,176, 5,168, 0, 11, 5,177, 5,177, 0, 7,
+ 5,178, 5,178, 17, 11, 5,179, 5,179, 31, 11, 5,203, 5,180, 0, 11, 5,204, 5,204, 0, 3, 5,211, 5,206, 0, 3, 5,213,
+ 5,212, 0, 4, 5,214, 5,214, 0, 11, 5,215, 5,215, 17, 11, 5,216, 5,216, 31, 11, 5,227, 5,218, 0, 3, 5,229, 5,228,
+ 0, 4, 5,230, 5,230, 0, 11, 5,231, 5,231, 17, 11, 5,232, 5,232, 31, 11, 5,251, 5,233, 0, 5, 5,253, 5,252,128, 11,
+ 6, 3, 5,254, 0, 11, 6, 10, 6, 8, 0, 11, 6, 16, 6, 13, 0, 11, 6, 18, 6, 18, 0, 11, 6, 21, 6, 21, 0, 5, 6, 22,
+ 6, 22, 0, 11, 6, 39, 6, 25, 0, 11, 6, 86, 6, 76, 0, 11, 6, 87, 6, 87, 0, 4, 6, 88, 6, 88, 0, 5, 6,102, 6, 89,
+ 0, 11, 6,103, 6,103, 17, 11, 6,104, 6,104, 31, 11, 6,116, 6,105, 0, 11, 6,130, 6,130, 0, 1,255,255,255,255, 0, 0,
+};
+
diff --git a/source/blender/src/blenderbuttons.c b/source/blender/src/blenderbuttons.c
new file mode 100644
index 00000000000..064bd1c65dd
--- /dev/null
+++ b/source/blender/src/blenderbuttons.c
@@ -0,0 +1,2078 @@
+/* DataToC output of file <blenderbuttons> */
+
+int datatoc_blenderbuttons_size= 66284;
+char datatoc_blenderbuttons[]= {
+137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13,
+ 73, 72, 68, 82, 0, 0, 2, 0, 0, 0, 1, 0, 8, 6, 0, 0, 0,197,144,206,103, 0, 0, 0, 1,115, 82, 71, 66, 0,174,206,
+ 28,233, 0, 0, 0, 6, 98, 75, 71, 68, 0,255, 0,255, 0,255,160,189,167,147, 0, 0, 0, 9,112, 72, 89,115, 0, 0, 11, 19,
+ 0, 0, 11, 19, 1, 0,154,156, 24, 0, 0, 0, 7,116, 73, 77, 69, 7,215, 9, 22, 2, 14, 23,165, 89,144, 34, 0, 0, 32, 0,
+ 73, 68, 65, 84,120,218,236, 93,121,124, 19,213,218,126,206,100,239,190, 80, 10,148,165, 44,101,149,165,101,151,197, 6, 91, 20,
+ 62, 5,129, 22, 68,148, 42, 92, 27, 17, 92,241,130,219,189,202, 21, 65, 54,149, 43, 10,225, 42,155, 2, 74, 11, 8,202, 34, 45,
+164,128, 80,217,177, 40, 75,161, 80, 74, 11,165, 37, 77,155, 52,219, 36,153,243,253,145,164,166,165,105,150, 6, 4,205,243, 35,
+191,102, 38, 51, 47,103,230,156,243, 62,239,114, 22,210,171, 87, 47, 10, 63,252,240,195, 15, 63,252,240,227,111, 5,198,255, 10,
+252,240,195, 15, 63,252,240,227,239,131,147,167,178, 1, 0,196, 31, 1,240,195, 15, 63,252,240,195, 15,127, 4,192, 15, 63,252,
+240,195, 15, 63,252,240, 27, 0,126,248,225,135, 31,126,248,225,135,223, 0,240,195, 15, 63,252,240,195, 15, 63,254, 18,224, 59,
+ 30, 76,155, 54,141,120, 43,104,249,242,229,183,141, 37,240,203,243,203,107, 0,116,249,242,229,127, 90,249,114,114,114,104, 98,
+ 98, 34,241,215,199,253, 43,239,244,233,211, 94, 55,190, 94,189,122,193, 95, 31,247,182,188, 83,167, 78,121, 45, 47, 62, 62,254,
+111, 47,207, 99, 3,224,239, 12,153, 76, 86,235, 5,202,229,114,114, 47,151,115,197,138, 21, 32,132, 16,127,205,121, 87,199, 19,
+ 39, 78, 68,102,102,102,205,113, 74, 74,202, 95,226, 93,238,220,117,178, 65, 69, 48,114, 68,194, 95,186,205, 72,194,183, 66,108,
+232,128,182, 96, 81,141, 93,200,215,191,123,207,182,197,123, 85,199,248,241, 55,141, 0,220,141,198,186,115,231,206,196,109,219,
+182, 41,236,199,163, 71,143,150,142, 28, 57, 50,231, 94,120, 25,148, 90,117,231,189,202,171, 50,153,140, 22, 22, 22, 2, 0, 98,
+ 99, 99, 1,224,190, 80, 34,117,141, 43,155,129,229,212, 51,119, 87,238,198,141, 27,221, 54,212,100, 50, 25,221,180,105, 83,205,
+241,214,173, 91,145,156,156, 92,115,156,153,153, 73,255, 44, 35,160,119,239,222, 20, 0, 78,156, 56, 65,124,113,221,182,239,229,
+ 13, 24, 0,242, 70,215, 95, 76,219, 86, 0,128,155, 6, 3,204,122,163,245,100,165, 26, 0,144,154,154,138,164,164, 36,167,229,
+ 91,153,180,146,198,221,136,243,232,255,151,254, 46,117,163, 94, 36, 8,127,241, 12, 12,219,182, 66,165, 26, 3, 21,128, 4,201,
+ 34,188, 43, 57,129, 86, 98,160,220, 80,128,119,245,227, 61,250,127,179,179,179, 19, 51, 50, 50, 20,142,231, 82, 83, 83,165, 73,
+ 73, 73, 57,247, 82,223,242,149, 14,184, 31,158,247, 78,160, 69, 19, 49, 9, 18,132, 18,163, 88, 72,141,149,122,166, 90,175,230,
+170, 13,236,223, 98,118,156, 75, 3, 96,231,206,157,137,246,191,141, 37,106,187, 34,153,179,105, 46,130, 90,133,162,250, 90, 21,
+222, 27,255,174, 98,219,182,109,240, 91,195,174, 33,151,203, 73,108,108, 44, 45, 44, 44, 68, 97, 97, 33,118,239,222,125,207,122,
+ 18,246,186,150,203,229, 68, 46,151, 11,100, 50,153,105,225,194,133,199, 0, 96,214,172, 89,125, 27,186,119,204,152, 49, 53,223,
+205,102, 11, 88,147, 17,172,145, 5,203, 90, 63,102,179, 25,179,102,205,242,168, 44,142,228, 95, 31,146,147,147,255, 84, 35,192,
+ 29,227,167,119,239,222, 46,101,140, 28,145, 64,188, 33,121,183, 17, 22,130,188,203,223, 66,130,150,176,224, 16,202,190, 60,137,
+ 95, 11,148, 24,251,209,106,183,110,143,187, 17,231, 38,161, 91,161,232,166,112,169,136, 37, 35,223, 69,196,232,169, 40,121, 53,
+ 1,208,171,106,206,159,212,255, 19, 39, 1, 64, 15, 12,149,164, 98,111,248, 9,132, 1,232,173,234,237,118,251,173,139,140,140,
+ 12, 69, 70, 70,198, 61,161,175,236,101,244,133, 14,184, 31,158,215,215, 24,220, 51,158, 60, 29,211,150,255,114,202,100, 94,211,
+ 46, 49, 12,159, 52, 37,186,170, 42, 78,140,104,203,186, 31,179, 44,147, 31, 75,182,184, 35,135, 16,114,221, 3, 39,179,133, 27,
+242,102,122, 32,111,201, 29, 53, 0,182,109,219,166,216,244,175,183, 49,254,131,121,138,145, 35, 71,146,198, 52, 48, 59,241, 3,
+192, 45,157, 18,136, 4,222,218,251, 62,212,151, 85,144, 61,127,111, 17,153,179, 14,241,103,151,209,209, 8,120,244,209, 71, 81,
+ 88, 88,136,216,216,216,123,238,221, 41, 20, 86, 71, 66, 42,149, 82,185, 92,206,200,229,242, 24,153, 76, 86,178,112,225,194, 19,
+238,202, 49,155,205, 96, 89, 83, 13,241, 59,146,255,241,227,199,209,167, 79, 31,143,202, 53,126,252, 31, 30,224,196,137, 19,145,
+149,149, 85,203, 0,240, 69, 91,241,166, 30, 78,156, 56, 65,114,114,114,232,240,225,195,111,251,109,207,158, 61,216,184,113, 99,
+205,113, 67,227, 22,110, 51,222,125,152, 14,136,105,219, 10, 37,170, 42,108,121, 97, 28, 34,201, 32, 20,252,239, 13,180, 27,211,
+ 14, 89, 30,144,191, 29,233,233,233, 20, 0, 86,174, 92,217,232, 54, 27,179,233, 16,116, 87,171, 81, 34,107,219,224,117,103,196,
+217,152,211,253, 38,230,159,121,167, 81,245,233, 11,210,245,165, 12, 95, 68, 2,238,244,243,250, 10,105,105,105, 1, 0, 30, 4,
+ 16,228,112,186, 18, 64,222,218,181,107, 43,220,149,179,116,197, 82,134,189,101, 20,140, 24, 53, 70,172,130, 73, 44, 16,240,249,
+106,131,152, 17, 10,245, 28, 47, 36,208,204, 74, 76, 38,126,233,117,227,186,175,214, 26, 38, 79, 77,179, 16, 66, 72,125, 99, 70,
+ 28, 81, 89, 89,249,161,253,123,126,126,254,173,192,192, 64, 70,171,213,114,142,215,244,235,215,239, 19, 95, 18,187, 39,134,130,
+ 87, 6,192,206,157, 59, 19, 59,118,236,136,184,160, 16, 52, 38, 10,224, 72,254,183,116, 74,204,127,248,253,154,223,158,219,246,
+ 34,208, 20, 24,179,112,188, 71,141,204, 25, 65,251,138,164,175, 93,187, 6, 0,104,213,170, 85,173,239,246,255,215, 85,131,184,
+147, 33, 62, 71, 35,192,100, 50, 99,197,138, 21,119,204, 11,240, 84,102, 29,242,119,188,255,186, 92, 46, 15,151,201,100, 42,183,
+201,223,100, 2,203, 26, 97,100, 89,152,234,144, 63,229, 60,139,208,141, 31, 63, 30,199,143, 31,175, 57, 94,178,100, 9, 82, 82,
+ 82,106,142, 51, 51, 51, 27,109,236, 56, 24, 60,141,110,127,142,196, 63,113,226, 68,196,199,199,123, 37,199, 87,233,128,226,203,
+ 69,208,110,253, 55,130,166, 44, 69, 76,219, 86,136,142,148,224,242,214,203, 86,242, 15, 11,177,166, 0, 4, 60,183,100,249,130,
+248, 1,160,227,217, 75,184,246,222, 92,232, 51,214, 52, 28, 33,144, 72, 96, 48, 24, 80, 80, 80,128, 50,195, 5,116, 68,140,211,
+107,179,179,179, 19, 27,106,251,114,185,156,216,251, 73,118,118,118,162, 39,225,113,199,168,152,189,191, 58,158,243,212, 17,112,
+ 70,220,158,232,130,250,158, 55, 43, 43,139, 18, 66,144,148,148, 68, 26,243,188,118, 76,157, 58,149,126,245,213, 87,141,170,243,
+180,180,180, 80, 0, 99,246,238,221,251,111,142,227,140, 14, 36,200,231,241,120,129,105,105,105,255, 88,187,118,237, 78, 87,114,
+222,120,243, 13,190, 68, 40, 22, 11, 4,162, 64,134, 79, 66, 40, 79, 20,192,241,120,124,142, 48,224, 8,223, 66,121, 60, 35,143,
+ 35, 6, 45,207,162, 11, 20, 10,200, 87,135,119, 25,196,163,154,114, 40,114, 93, 70,149, 74,165,214,233,116,102, 0,208,106,181,
+220,219,111,191, 93, 67,248,243,230,205,123,173,177,237, 61, 57, 57,249, 5,251,247,172,172,172, 21,190,232, 67,140, 43,239,127,
+238,132, 20, 24,202,203,241, 70,183,206,112,204,221,187,237,133,216, 82, 8,142,228, 63,122,244,104,169, 92, 46, 39,163, 71,143,
+150,174, 30,253,133, 53,178,216,169, 73,173,235,221,193,172,207,243, 49,235,243,124, 76, 95,124, 14,105, 31,252,134,177,111,157,
+110,244, 11, 41, 46, 46,118,203, 48,184, 91,228, 95, 88, 88,232,148,152, 99, 99, 99, 97, 98, 89,244,239,215,175,209,255,143, 61,
+ 76,190,105,211, 38, 40, 20,138,154, 79, 67,134,150, 51, 50,148, 74,165,117,201,191,198, 80,118, 71, 49,153,205, 22,171,231,111,
+180,134,254,235,146,191,197, 98,129, 86,175,245,232, 25,237, 17,131,186, 81,131,204,204, 76,100,102,102,214, 50, 6, 60,122,222,
+156,218,250, 80,145,147,227,209, 59,107,136,252, 39, 78,156,136,133, 11, 23,214,144,191,128, 47,240, 72,206,200, 17, 9,196,150,
+130,169,247,227,137, 44, 61,138, 80, 61,166, 63,104,198, 27, 40,190, 92, 4, 58,166,203, 31,222, 74,198, 27,224, 55,143, 2,194,
+194,238,170, 71,168,189, 85, 0,125,198, 26, 80, 74,113,230,204, 25, 12, 29, 58, 20, 18,137,164, 22,241,135,135,135, 67,175,215,
+ 67,175,215,163,164,164, 4, 79,233, 95,198,151,225,175, 58,149,105,207,129, 55,244,126,236,191,213,205,151,187, 75,220,190,114,
+ 86,236,247,214, 37,127, 87, 14, 82, 67,207,155,149,149, 69, 51, 51, 51,145,145,145,129,236,236,108,218,216,231,157, 58,117, 42,
+229,243,249,152, 58,117,170,215,125, 34, 45, 45, 77, 12,224,249,236,236,236,183, 63,248,224,131, 35,132,144, 88,251, 7, 64,203,
+200,200,200,128,125,251,246, 45, 79, 75, 75, 27,218,144,156,229,242, 21, 60, 30, 17,136, 88, 51, 13, 49, 26, 77, 77, 45, 28,215,
+210,194,113,109, 45,132,180, 6,143, 23, 73, 8, 9, 3,225,133,112, 20, 17,148,229,194,212,122, 83, 96,211, 16, 51,143,233,167,
+113,171,142,116, 58,157,185,174,215,127,175,131,113,199,251,215,149,222,192,136,248, 4,143, 9,218,110, 68,204,217, 52, 23, 0,
+106,200,223, 30, 69, 24, 57,114,100,142,221, 8, 40, 86, 95, 71,194,172, 1, 30, 25, 25, 90,189, 5, 90,189, 5, 55,148, 70,148,
+148, 27,112,237,166,193, 43,226,179,119, 22, 87,228,255,103,193,153, 17, 0, 0, 6,214, 8,131,193,224,181,108, 59,105,219,115,
+228, 81, 81, 81,142,222, 44,220, 85, 38,117, 61, 97,103,161, 68,119,148, 30,107, 50, 90, 61,127, 35, 11,214, 84,155,252, 77, 38,
+ 19,180, 90, 45, 52,106,205,159, 90, 39, 86,131, 41,195, 49, 32,103,255,135, 77,155, 50,188, 54, 2, 28,201,223, 78,252, 12,195,
+ 64, 44, 22, 35, 48, 40,160, 81,101,222,185,235, 36,117,246,113,117,239,238,183,222, 71, 36, 6,193,156,244, 18, 0, 32, 40,247,
+ 18,126, 45, 80, 90, 13,182,164,151, 96, 58, 51, 7,184,165,244,168, 60,233,233,233,212,158, 14,240, 6,129,184, 5, 0, 88,179,
+102, 13,182,109,219,134, 69,139, 22,225,232,209,163, 48, 26,141, 40, 43, 43,179,123,101, 53,215,199,196,196, 64, 15,128,135, 43,
+127, 74,123,113,214,238,235,122,243,222, 26, 20,245,165, 5, 60,149,231, 24, 9,203,200,200,104,212, 51,219,201, 31, 0,188, 53,
+ 2,210,210,210,154,217,200, 63,125,237,218,181,103,223,125,247,221, 39, 54,108,216,128,142, 29, 59, 2, 0,218,180,105,131,170,
+170, 42,209,156, 57,115, 78,236,219,183,239,155,180,180,180,216,250,227,229, 0, 56, 74,192,153,197, 22,139, 57,194, 98,182,180,
+ 52, 89, 76, 29,120, 12,105, 33,228, 51, 2,177,128,167,231, 7, 8, 43, 3,131,121,106,158,152,154,197, 60, 94, 32,223,204,134,
+ 92, 57,121, 74,244, 76,212,167, 46,203,157,159,159,127, 75,171,213,114,245,133,249,123,246,236,121,129,101, 89,159,181,165,158,
+ 61,123,250, 76, 22,191, 33,226,254, 95,250,212, 63,200,182,248, 26,222,232,214, 25,139,183,109,243,120, 44,128,221,251,183,147,
+126, 45, 47,101,228,200,156,109,219,182, 1, 0, 34,187, 55,243,168,240,213,122, 11, 52, 58, 51,212, 90, 51,170,170,205,168,212,
+152, 61,126, 1,245,141,252,119,244,242, 29,191, 95,190,124, 25,149,149,149,119, 77,105,172, 88,177, 2,177,177,177,176, 15,250,
+115,204,245,203,100, 50,186, 98,197, 10, 24,244,122,175, 13, 0,153, 76, 70, 87,175, 94,141,226,146, 18, 8,120, 60, 68, 55,107,
+ 86,139,252, 31,126,248, 97,140, 31, 63,222, 45,229, 36,151,203,137, 84, 42,173,101, 4,212,141,100,184, 59, 86,129, 53,178, 96,
+141, 70,152, 76, 44,204,102, 75, 13,249, 27,141, 70,232,116, 58, 84, 87, 87, 67,163,241,220, 0,112, 76, 1,216,225,173,231,191,
+ 41, 99, 19, 64,129, 91, 54,162,161,214, 70, 4, 66,169,213, 8,200,200,192,248,212, 84,143,211, 1,117,201, 95, 32, 16, 64, 36,
+ 18, 65, 44, 22, 67, 44, 22,123,245,220,181,250,181,147,148,128,171,148,214,216, 21,155, 65, 71,181,197,205,129, 9,136,196, 32,
+ 72,198,125, 6,243,141,114, 32, 44, 4,124,229, 70,252,248,233, 9,128,199,243,168, 44,141, 77, 5,104,121, 86,157, 50,127,254,
+124,148,151,151, 99,249,242,229,232,217,179, 39, 62,248,224, 3, 36, 36, 36, 64,175,215,215,245,208,236, 38,245, 93, 37,126,119,
+ 9,218,219,116,128, 51, 67,194, 27, 57,169,169,169, 53,196,239, 77,223,168,143,252,107,200,134,207,135,217,108,246, 52, 29, 16,
+156,151,151,247,223,105,211,166, 29,232,222,189,123, 8, 0,188,255,254,251,200,207,207, 7, 0, 12, 24, 48, 0, 91,182,108,193,
+224,193,131, 3,159,122,234,169,130,156,156,156,236, 41, 83,166, 60,117,187,162, 7, 34, 34, 35,184,203,151, 11,204, 57,138,189,
+187, 58,116,136,203,105,219, 38,246, 44, 47, 88, 82,198, 35, 66, 45, 35, 18,232, 24,113,128,134,229,243, 88, 80, 19,143, 19,155,
+130, 53, 37,202,160,163,251, 78,247,107, 18, 30,189,197,165, 49,234,144,243,223,186,117,107,218,152, 49, 99,214,218,195,254,106,
+181,154, 17, 10,133,141,110, 75,190, 10,251,187,140, 0,216,189,252, 62,237,227, 96, 40, 47,135,182,216, 74,130, 67,109,222,161,
+167, 81,128,203,191, 93,186, 77,118,125,199,202, 51,165, 30, 21,190,177,228,239, 72,252,148, 82,180,106,213,170,214,111, 38,147,
+169,230, 83, 89, 89, 9,173, 86,139,138,138,138,187,166, 60,236,243,252,119,239,222, 93, 43, 18, 96, 39,255, 30, 61,122,192, 96,
+208,215, 40, 58,106,183,102,220, 84, 76,159,127,241, 57, 76, 38, 19, 90,198,196,192,100,177,212, 75,254,158, 40, 18,155, 17,112,
+155, 87, 98,159,186,216, 80, 36,227, 54, 3,128, 53,213,144,255,177,163,199,160,211,235,161,209,104, 80, 85, 85,133,202,202,202,
+ 90,158,157,167,176,167, 1,188,205,251, 3,128,242,150, 18, 74,229, 45,220, 82, 86,224,150, 82, 9,165, 82, 9,229, 45,171, 71,
+218,185, 75, 23, 84,216,190,123,234,253, 3, 64,124,124,252, 31, 94,127, 96, 32,130,130,130, 17, 28, 20, 12,141, 70, 35,109, 76,
+123,106, 40, 37,224,234,222,130, 69,233, 16,140,251, 12,145, 24, 4,126,238,103, 48,109,126, 9, 8, 11,193,246, 23, 83,112,117,
+251, 21, 60,190,112, 29,192,191,203,203,138, 24,174, 66, 18, 35,129, 86,171,133,193, 96,128, 78,167, 67,110,110, 46, 62,250,232,
+163,122, 47, 15, 8,176, 71, 80, 46,121, 76,222,222,122,213,142,239,183,238,251,118,118,220, 24, 35,163,190,180,128, 39,114,146,
+146,146, 72,106,106, 42, 82, 82, 82,144,156,156,236,117,100,226,171,175,190, 34,102,115,109,157,108, 54,155,225,233, 88,128,181,
+107,215, 94, 76, 77, 77,237,185, 97,195,134,161, 7, 15, 30, 12, 78, 74, 74, 58,106, 39,127,155,163, 10,145, 72, 68,175, 94,189,
+ 42,216,181,107, 87,167,240,240,240, 99,131, 6, 13, 42,168, 79,214,132,241, 19,184,184,182, 29, 53, 3, 6, 12, 72, 57,123,246,
+247, 97,106,173,166, 25, 53,155,204, 96, 96, 50, 27, 25,163,209,104,212,171, 81,170,230,140, 6, 77, 73, 81,169,249,199, 29, 59,
+ 23, 52,137,140, 42, 99, 89,157, 75,247,189, 62,239, 95,165, 82,241, 1, 32, 36, 36,228,158, 77, 11, 48,206,188,255, 77,255,122,
+219,106, 53,151,222,168,245,155,167, 99, 1, 70,143, 30, 45,253,252,249,165, 0,172, 3,254,182,109,219,166,112,156, 90,184,109,
+219, 54, 69,242,215, 79, 0, 0, 78, 46,252, 5,163, 71,143,150,222,173,135,119,236, 36,197,197,197, 53,222,190,157,244, 29, 42,
+ 23, 26,141, 6, 6,131,193, 65,137,220,189, 50,190,240,130,117,236,135,201,108,198,217,179,103,113,234,228, 73,244,236,209, 19,
+ 6,131, 1,122,189, 1, 6,189, 30,223,124,253, 53,236,215,185,211,209,151, 44, 89,130,174, 93,186,194,100, 50,225,226,197,139,
+ 48,155, 88,148, 20,151,248,244,157,218,143,109,107, 22, 32, 54, 54,214, 45,197,196,154,140, 48, 91,172, 97,255, 35, 71,126,129,
+ 86,175, 69,181, 70,141,170,170, 42,168, 42, 43,161, 82, 85, 52,202, 16,179, 71, 2, 26,227,225, 28, 56,112, 0, 26,141, 6, 26,
+141,218,246, 87,131, 38,145,145,232,220,165, 11,206,159, 59,135,253, 7, 14,120, 44,211,238,253,243,249, 2, 4, 4, 4, 32, 40,
+ 40, 8,193, 65, 65, 8, 10, 10, 64,133,170, 66, 10, 32,231, 78,135,250,157,225,215, 2, 37, 76,103,230, 64,137, 67, 32, 35, 23,
+131, 12,250, 55, 10, 22,165, 99,212,194,181, 16, 11, 24, 64,192,183,126,188,128,183,169,128,146,199,190, 64,196,198,199,160,211,
+233, 16, 17, 17, 1,149, 74, 5,149, 74,133,195,135, 15,227,198,141, 27, 53, 97,226,154,235, 75, 74,240, 98,184, 4, 77, 2,202,
+ 27,242,128,165,142,164,234, 56, 72,206,254,221,254,155,253, 90,111,188,115,119,211, 3,238,146,191,183,158,127,125,207,155,148,
+148, 68,146,147,147, 73, 99,158,183,174, 17,224, 13,249,219,241,246,219,111,231, 61,241,196, 19, 79,205,159, 63,191,211,175,191,
+254, 58, 72, 34,145,240, 70,141, 26, 69, 68, 34, 17, 56,142, 35, 35, 71,142,204,123,229,149, 87,122, 60,240,192, 3,219,255,241,
+143,127,164, 77,157, 58,213,105, 46, 42,253,197,116,238,247,115, 23,143, 61,208,189,199,211,199,142, 30, 29,187,125,199, 15,243,
+142, 31, 61,218,236,108,254,121,241,197,146, 2,250,205,210,239, 36,243,151, 44,234,154,189, 99,199,146, 14,237, 59,252, 24, 20,
+ 29,120, 96,237,218,181, 22,184, 89,242,164,164, 36, 28, 59,118,172,215,138, 21, 43,230, 24, 12, 6,193, 7, 31,124,240,241,246,
+237,219, 39,150,148,148,220, 93,226,104,108, 10, 32,242, 74, 33, 42,108,161,127, 71, 12,141,138,194, 98,156,119,223,235,176,133,
+248,207,159, 56,139,176, 78, 77,144,252,245, 19,216,246,204,247, 10,123,216,223, 78,254,118,239,223,147, 89, 6, 91,230,251,102,
+ 36, 62, 33, 4,231,206,157,131,189,177,214, 13,179, 10, 4, 2, 8, 4, 2,148,151,151, 99,228,200,145,119,189,146,236,163,254,
+ 87,172, 88,129,126,253,250,193, 96, 52, 66,111,208,195, 96, 27,220,164, 55, 88,211, 0,203,150, 45,115,169, 76,100, 50, 25, 93,
+184,112, 33, 44, 22, 11, 78,156, 56, 9, 1,223, 26,182,141,139,139,195,149,194, 66,148,148,148, 96,227,198,111, 49,113,226,147,
+216,187,119, 47,117,140, 4, 52,164,128,228,114,185, 16,128, 89, 38,147,113,245,121, 64,158, 76, 85,180,123,254,185,185,185,208,
+ 86,235,106, 12, 48,181, 70, 13,181,186, 10,106,117,181,215,161,112,187,247,111, 91, 9,208, 43, 67, 96,226,196,137,181,142,219,
+198,198,162,115, 23,235,160,184,243,231,206,225,138, 45,226, 81,247, 58,119, 48,240,193,129, 16, 9, 69,144, 72, 36, 16,139,197,
+ 16,137, 68, 40, 45, 45,117,155,252, 93,133,250,189, 93, 35, 96,236, 71,171,177, 5,192,163,243,255, 15, 52,227, 13,144,241, 75,
+240,107,129, 18, 36, 34, 28,151,138,213, 86,239,223,195, 20, 64,221, 84,128,199,211, 3,245,122,128, 87, 80, 39,188,111, 37,122,
+147,201,132, 47,191,252, 18, 67,135,254, 49, 46,108,239,179, 49, 64,153, 14,157,118,170,208, 43,170,141, 51, 5,158, 83, 39,247,
+173, 0,106,212,191,162,238,181,222, 16,118, 67,121,123,111, 61,127,111, 13,137, 59,253,188, 54, 35,160,209,179, 0,230,205,155,
+183, 81,171,213, 70,157,206,203, 27,175,215,235,123, 40, 20,251, 36, 34,177,136,207, 16, 6,251,246,237, 11,238,218,181,235,186,
+212,212,212,127,143, 25, 51,198,165,183,174,216,251, 19, 55,106,204,168,253, 61,123,198,207, 98,205,198, 71, 47,229, 95,156,199,
+ 21, 22,152, 1, 80, 49, 24, 83,247, 14,157, 50,154, 54,141,218,201,227, 11,191,249,240,221, 5,172, 61,133,208, 16,250,245,235,
+247, 73, 82, 82, 18, 0,160,188,188, 28,217,217,217, 33,171, 86,173,154, 7, 0,199,142, 29,235,215,173, 91,183,221,247,133, 1,
+ 96,247,206, 31,254,102, 67,195, 94,134, 7, 83, 2,237,214,111,194,172, 1,136,236,222,172,134,244, 29, 67,255, 39, 23,254,226,
+145,229,234,171, 57,169,246,178,117,233,210, 5,103,206,156,169, 69, 44,149,149,149, 5, 0,218,215,119, 79,125,107, 87,223,105,
+ 35,160, 62,101,241,205,215,223,192, 96, 48,192,200, 26,193,178, 44, 22, 46, 92, 8, 87,228,111, 7,199, 89, 32,150, 4, 65,175,
+ 55,224,220,217,179,224, 11, 4, 48,177, 44, 2, 2, 3,176,113,227, 70,240,120, 60,251,220,249, 6,159,117,225,194,133,187,101,
+ 50, 25, 43,151,203,155,218,203, 89,103, 29, 0,143, 66,155,179,102,205,194,161, 67,135, 80, 93, 93,141,106,173, 22, 26,181,218,
+ 70,254,106,104,212, 26, 84,107,170,161,117, 80,248,238,188,187, 62,125,250,208,227,199,143,215,120,255,245, 77, 3,116,119, 17,
+160,196,196,196,219,234,194, 78,250,167, 78,157,170,241,230,221,125,230,222,189,123, 83,251, 34, 63, 65, 1, 65, 16, 75,196,208,
+104, 52, 82,135, 28,182, 71,138,247, 78, 45, 6,100, 55, 2,198,204, 95, 5,186, 25,104,242,172, 28, 57,175,166, 96,240,130,245,
+128, 64,128, 64,113,227,242,156,117, 13, 1, 0, 80, 28,114, 21,108,188,137,238,187, 3, 80,250,131, 14,170,185,127,156, 53,153,
+ 76, 24, 50,100, 8, 0, 32, 38, 92,130,159,229,173,176,232,163,107,248,226,164,190, 65,105,142, 30, 63, 96, 29, 8,103, 87,236,
+117, 7,197,121, 58, 45,206,113,252, 78, 99, 61,255,250,116,130, 55,178,238,228,243, 58, 26, 1,190,104,127, 75,151, 46,253,239,
+148,231,166,236,234,219,187, 79, 63,141, 90, 29, 97,182,152,141,209,209,209,229, 49, 49, 49,165,106,181,250,215, 49, 99,198,184,
+173, 20,182,111,221,206, 1,216,248,204,211,255,200, 29, 52,120,240,247, 18,137, 36,148,128,114,132, 16,112, 28,173,210,107, 85,
+138, 11,121, 69,154, 0,161,192, 45, 61,111,127,103,128,117, 32,117,221,129,122, 31,125,244,209,191,239, 11, 3, 96,228,200,145,
+ 57,141, 89,240,199,157,198,106, 55, 4,236,196,239, 75, 66,111, 76,217,186,119,239,142, 99,199,142,161,188,188, 38, 68,216, 30,
+ 0,148, 74,107, 68,233,153,103,158,249, 83, 43,171,238, 59,162,148,210,167,159,121, 26,203,150,125,110,203,153,155, 17, 26, 26,
+ 74,220,189,223, 14,137, 68,108,151,103,245,166,180, 58,199,123, 0,212,191, 89,135, 3,186, 44, 92,184,240,162, 76, 38, 43,147,
+203,229, 60,199, 1,129,182,105,129,110, 43, 58,251,220,247, 65,131, 6,249,252,221,245,233,211,167,238, 94, 0, 53,191,123,186,
+ 2,160, 92, 46, 39, 57, 57, 57,116,227,198,141,181, 22,234,177,203,246,166, 61, 39, 38, 38, 18,147,217, 4,147,198,228,211,103,
+111, 40,244,239,233,222, 0, 99, 63, 90, 13, 56, 44,252,243,208,219,127,140, 75,210,250,168,188,181, 34, 0,221, 26, 54, 62, 75,
+ 6,149,160, 4, 64,194,162,112,204, 61,209, 17, 81, 0,202, 11,180,232,208,161, 3, 0,224,191,115,195,241, 72,223, 40,180,125,
+ 36,223,173,255,219,147,169,110, 25, 25, 25,138,134,150, 61,118,165,111,124,161,243, 26, 43,235,110, 60,175, 47,177,106,245,170,
+139, 0, 46,250, 74,222,215,223,124, 89, 8, 31,140, 10,205,206,206,246,233,115,250, 98,145, 31,175, 12,128, 59, 77, 96, 59,119,
+238, 76,220,182,240,222,219, 11,192,222,145,250,246,237,139,157, 59,119, 26,108,164,207, 1, 8,184, 19,145, 7, 31, 53, 18, 34,
+151,203,107, 60,251,134,200,255, 78, 98,214,172, 89,142,241,212, 26,133,109,159, 70,232,137,183,115, 39,223,175,163,236,156,156,
+156, 70, 47,251,155,152,152, 72, 18, 19, 19, 27, 93, 46, 87,107,251,251, 2,141, 73, 9,204,158, 61, 27,151, 47, 95,246, 89, 89,
+220, 89,222,215, 83,156,252,167, 10, 39, 97, 29, 24, 58, 52, 85,130,159,142,116, 68,116, 64, 16,126, 63,126, 19,157,220, 36,127,
+ 87,237,239, 94, 93, 14,215, 23,107, 9,220, 79,207,123,175,193,157,229,125, 61,148,183,228,110,149,253,174,239, 6,120,167, 34,
+ 12,190, 52, 2, 70,142, 28, 41,190,159, 26,224,159, 29, 61, 1, 96, 95,161,198,108, 55, 0,252,202,227,222, 65, 99, 83, 2,237,
+218,181, 35,237,218,181,243,137,190,241,100, 31, 0,111,113, 32, 67,143, 3, 25,249,254, 62,235,135, 31,174,156,200, 94,189,122,
+ 81,255,107,240,195, 15, 63,252,240,195,143,191, 23, 24,255, 43,240,195, 15, 63,252,240,195, 15,191, 1,224,135, 31,126,248,225,
+135, 31,126,248, 13, 0, 63,252,240,195, 15, 63,252,240,195,111, 0,248,225,135, 31,126,248,225,135, 31, 0,112, 20, 64,185,237,
+239,125,137, 90,179, 0,166, 77,155,230,245,200,212,250,230,137,251,229,221,123,242,210,211,211,189,146, 23, 31, 31,127,155,188,
+ 83,167, 78,121, 93,190,250,228,221, 47,245,225,233, 59, 92,185,114,229, 93, 41,159,175,235,227,110,214,175,171,105,162,158,190,
+ 63, 95,203,243,235,151,187, 47,239, 30,111,207, 71, 79,157, 58,149, 12,216, 54,152, 4, 12,247, 90,127,243,216, 0,240,227,175,
+143,149, 43, 87,250, 95,194,223, 12, 97, 97, 97, 12,172,211, 51,249, 85, 85, 85, 28,165,212,114, 47,149,207,190,239,124,118,118,
+ 54,245,197, 66, 51,190, 90,105,207,143, 59,135,237,219,183, 39,142, 26, 53, 42,231, 62,126,132,126, 0,236,203, 14, 11, 60, 53,
+ 0,238,201, 8,128, 31,127, 61, 80, 74,107,109,117,236,109, 4, 96,249,242,229, 46,175, 25, 62,124,120, 98, 86, 86, 86,173,149,
+197,146,147,147,165,123,246,236,241,170,163,103,102,102,214, 43, 47, 37, 37,229,158,144,119, 47,131, 16, 66,218, 68, 71,163,176,
+180,148, 86, 86, 86,218,247,103,240,104,137, 65, 71, 99,241,248,150,101,197,132, 96,186,124, 87,222, 54,217,136, 30, 95, 83, 10,
+245,202,221,121,211,103,143,237, 71,192, 80,190, 74, 99,160,125,198,189,228,241,150,156,217,217,217,137,246, 37,103,109,127,189,
+ 90,110,182, 46,249,219,219,125, 99, 55,218,169,239, 94,111,101,250, 66,158, 76, 38, 3,240,199, 10,157,190,128, 76, 38,243,169,
+ 60,119,200,127,231,206,157,138, 81,163, 70,221,239,198,153,189,189,223,209,231,104,209, 68, 76,130, 4,161,196, 40, 22, 82, 99,
+165,158,169,214,171,185,106, 3,235,147,233,251,183, 25, 0,190, 36, 8,111,101,121, 42,143, 16,194, 0,144, 0,208, 83, 74,185,
+123,173,124,190, 34, 88, 95, 24, 0,118,165,238, 88, 86, 66,136,145, 82, 42,106, 76,164,128, 16, 66, 1, 96,201,146, 37,181,118,
+ 12,155, 57,115,166,130, 16, 2, 74, 41,241, 80, 41, 81, 0,224,190, 11,175,117,158,153,144,165,200,202,202,242,120, 33, 21, 95,
+202,187, 31,162, 40,148, 82, 42,109,223,150, 74,219,183, 5, 0,148,178,230, 73,205,132,252,245,246,223,207,171,171, 69, 55,202,
+203, 89,119,100, 29,219,252, 89, 62,199, 33,230,193,129, 77, 66, 62,126,117,240,158, 30, 61,194,174, 78, 95,208,239, 67, 0,184,
+ 89,165,251, 63, 1,159,252, 0,144,179,233,233,233,221, 60,125, 55,117,151,162,109,204,114,179,142,228,239, 11, 35,192,217, 61,
+222, 26, 20,190,144,151,154,154,138,140,140, 12,183, 72, 59, 59, 59,187,214, 26,245,222, 26, 1,158,200,113,151,252, 57,142,195,
+202,149, 43,177,126,253,122, 58,105,210, 36,226,161,158, 17, 82, 74,125,178, 94,118,100,100,100,186, 82,169,244,182, 67,139,108,
+158, 63,123, 39,250,240,224,158,241,228,233,152,182,252,151, 83, 38,243,154,118,137, 97,248,164, 41,209, 85, 85,113, 98, 68, 91,
+214,253,152,101,153,252, 88,114,163, 35,121,124,119,148,155, 76, 38,139, 2,208, 7,192,113,185, 92, 94,126,143,121, 58, 33, 0,
+146, 0,140, 1,176,149, 16,146, 77, 41, 85,251, 64,238,183,148,210, 39,189, 37,216,123, 5, 12,195, 52,104,164, 16, 66,250, 1,
+ 16, 18, 66,154, 82, 74,203,156, 93,215,144,129, 66, 8,161,175,188,242, 10, 90,183,110,125,219,118,161, 75,150, 44,145, 22, 21,
+ 21, 41, 8, 33,212, 93, 35, 64, 38,147,209, 53, 47, 5, 98,242,224,219, 55,151,225,190, 11,199,186,159, 89, 60,235,153,215,228,
+ 83,121, 85, 85, 85,137,111,190,249,166, 98,252,248,241,144, 74,173, 43,219,157, 62,125, 58,113,249,242,229,138,214,173, 91,131,
+227, 56,232,245,122, 36, 38, 38, 98,248,240,225, 46,101, 10,171,180,137,157,222,220,164,200, 74,104, 41,109,246,124,114, 14, 0,
+152, 75,205,137, 23,222, 51, 43, 44,173, 67,160,230, 2,161,210,135,160, 44,244,152,116,234,236,166, 46,189,227,246,173,154, 53,
+107, 45,148,220,120,105,250, 51,198,104,137, 80,168,174,208,147,133,171, 54,172,127,251,133,167, 17, 46,145, 80,131,201, 66,255,
+181,108,149, 17, 0,105,222,188, 9,191,180, 84,201,244,234, 85,255,206,154,125,155,238,137,187, 30, 19, 16, 54,232,193,168, 37,
+241,189, 35, 4,107,214, 92,138,141,106, 34,185,245,201,171, 71,150, 20, 94,141,183,140,120,164,121,110,254, 69, 77,209,179,147,
+219,143,180,183, 27, 79,250,128,227, 6, 57,141, 9,215,215, 37,255,186,253,211, 27,249,247, 98, 4,192,113,163, 30,153, 76,134,
+212,212,212, 90,231, 29, 73,219,113, 99, 31,111,141, 10,187,156,140,140,140, 70, 71, 9, 28,201,127,230,204,153, 56,126,252, 56,
+253,249,231,159, 49,105,210, 36, 79, 69,177,132, 16, 1,165,212,236, 3, 21, 89, 26, 25, 25, 57, 70,169, 84,110,245,226,222, 80,
+ 88,199, 0,132, 3,184,145,150,150, 22, 6, 32,221,118,108,199, 77, 0, 63, 0, 40, 88,187,118,173, 91, 66,151,174, 88,202,176,
+183,140,130, 17,163,198,136, 85, 48,137, 5, 2, 62, 95,109, 16, 51, 66,161,158,227,133, 4,154, 89,137,201,196, 47,189,110, 92,
+247,213, 90,195,228,169,105, 22, 66, 8,113,214,127, 27, 29, 1, 32,132,180, 2,240, 63, 0, 37, 0, 94,145,201,100,207, 83, 74,
+175,221, 45, 15,214, 5, 73, 71, 2, 88, 7,224, 58,128,195, 0, 30, 5, 48,149, 16, 50,153, 82,170,108,164,248, 9,132,144, 73,
+174,242,165,119, 51,196,126,135, 48, 0,192, 5, 0,109, 1,148, 17, 27, 83,187,107,208, 12, 31, 62, 60, 17, 64, 45,242,159, 57,
+115,166,194, 49, 26, 96,251, 77, 49,124,248,240, 68, 87,233,128,204,204,204, 68, 0,181,200,154,153,160,130,163,247, 62,121,176,
+ 16,207,126,166, 69,102,102,102,162,171,240,189,175,229, 1,192,145, 35, 71, 20, 98,177, 24,185,185,185,181,246, 59, 96, 24, 6,
+239,188,243, 14,177, 43,187, 29, 59,118, 40,134, 15, 31,238,178, 2,154, 29, 57,171,160, 98, 1,122,148, 11, 21,101, 14,225, 68,
+194, 80,244,120,135, 37, 0,139, 51, 7,174, 38, 94,223,252,152, 2, 56,218, 32, 81, 72,219,183,165,173,133, 18,188,254,226, 36,
+ 99,116,144, 80,120,235,204, 33, 18,200,240,241,242,144, 56,180, 8,147,224,106,238, 65,162,103, 41,153,153,254, 12, 43,109,223,
+150,118, 14, 8,198, 13,122,139,196,199,199,215, 43,175, 73, 19,225, 67, 66, 33, 35, 62,124,248,198, 43,102,139,225,211,232,150,
+237, 76, 97, 77, 4, 68,173,190, 20,208,174,109, 64,147,136, 8, 81, 57, 71,213,198, 31,143,150,105,167, 13,249,115, 26,112,221,
+176,191, 99,223,244,212, 8,176, 95,227, 56,142,192,213,117,174,182,223,246,165, 60, 71,178,151,203, 85, 0, 84,144,201,194,235,
+ 37,109,119,225,204,168,176,159,179, 25,106,141, 38,255, 29, 59,118, 40, 24,134, 1,195, 48, 24, 50,100, 8, 14, 30, 60, 88,171,
+190,220,133,197, 98,201,227,241,120, 38, 66, 8,223, 7,227, 89, 36, 74,165,242,187,200,200,200,113, 74,165,114,179,135,247,154,
+ 96, 29, 91, 99, 76, 75, 75,139, 6,240,225,222,189,123,211, 56,142,227, 28, 56,138,240,120,188, 37, 82,169,244, 63,105,105,105,
+115, 92, 25, 1,111,188,249, 6, 95, 34, 20,139, 5, 2, 81, 32,195, 39, 33,148, 39, 10,224,120, 60, 62, 71, 24,112,132,111,161,
+ 60,158,145,199, 17,131,150,103,209, 5, 10, 5,228,171,195,187, 12,226, 81, 77, 57, 20,221,185, 8,192,167, 0,246, 2,248, 2,
+192,139, 0, 62, 93,185,114,229, 56, 47, 9, 59, 28,192, 43, 0,250, 2, 24, 9, 96, 39,128, 99, 0,150, 82, 74, 85, 94,136, 60,
+ 96, 43,215,114, 74, 41, 71, 8, 9, 4,144,102, 59,223,173, 17,134, 69,168,237,107, 32, 0,181, 39, 30,182,147, 8,138, 16,192,
+219, 0,230,201,229,114, 22,247, 22,250, 2, 56, 4,160, 25, 33,100,163,173, 78,190,174,107,208, 56, 51, 80,178,178,178, 20,142,
+ 97,255,153, 51,103,214, 28, 59,126, 95,178,100,137,212,102, 24, 52,216,227,179,178,178, 20,142, 97,122,102,130, 10, 23,119, 90,
+119, 97,100, 70,126, 93, 67,218,220,119,225, 96, 38,100, 41, 92,109,232, 83,159, 60,187,130,101, 38,200,168,167,242, 40,165,137,
+135, 15, 31,198,164, 73,147,240,229,151, 95,226,228,201,147,137, 9, 9, 9, 57,117,175, 17,139,197,138,230,205,155,187, 19,171,
+ 79,108,126,248, 55, 92,152,148,136,160, 47,207,128,220,208, 37,210,230, 1, 54,121,196,118, 9, 18, 5,134,214,138,136,230, 13,
+111,101, 43,109,223,150,166,255, 99, 2, 27, 29, 40, 20,152, 46, 29, 23,134, 71, 5, 19,197, 13, 53,198,245,106,133,206, 49, 97,
+ 16, 86, 94,128, 66,163, 71, 43,129, 8, 97,132, 39,120,107,234, 36, 90, 45, 20,229, 75,219,183,165, 8, 9,171, 87,166,170, 82,
+ 19,209,175, 95,208, 18,181,185,255,236,224,240,114,145,129, 9,228, 36, 65,172, 49,162, 73, 36, 19, 16, 38,230,171, 42,110,136,
+212, 85,102, 8,170,140,196,177,205, 52,100,208,218,242,254, 10, 87,196,153,154,154, 42,117, 53, 30,160, 62,207,191,174, 33,224,
+137, 17, 96,255,173, 33, 50,118, 60,239,138,172,235,202,163,155,194,111,215, 55,227, 85,112, 87, 94, 67,225,254,198,144,118, 93,
+163, 2, 0, 34, 34,178,125, 66,254,211,166, 77,179,166,223, 56, 14,111,188,241, 6, 62,253,244,211, 26,242, 95,190,124,185,199,
+207,203, 48, 12, 88,150, 61, 37, 20, 10,205, 62,136, 4, 84, 0,128, 82,169,220, 28, 25, 25, 41, 85, 42,149, 10, 79,138, 2, 0,
+ 44,203,242, 1,172,204,206,206, 30, 49,119,238,220,235,239,190,251,110,235, 58,105, 6,186,111,223,190,119,135, 13, 27, 86,145,
+150,150,246, 89, 67, 70, 0,143, 8, 68,172,153,134,112,156, 41, 82,200,227, 53,161,132,132, 18, 62,159,240,121, 60, 45, 33,132,
+ 5,225,233, 57,138, 0,202,114, 66,181,197,132,246, 33,102, 19,211, 79, 67,125,102, 0,212,201, 13,199, 0,104, 69, 41,181, 19,
+254, 34, 66,200, 81,153, 76, 22, 67, 41, 45,241,196,131, 37,132, 60, 99, 35,235,143, 1,204, 6,240, 52,128, 24, 0,169, 0,138,
+ 8, 33, 47, 82, 74,191,246,128,164,255, 13,224, 18,165,244,115, 66,136,200,214,225,205,148,210, 47, 8, 33,143, 16, 66,254, 77,
+ 41,253,143,151,141, 98, 40,172,243, 59, 31,178,133,111,220, 70,125, 17, 0,153, 76, 54, 5,192,123, 0, 74,211,211,211, 87,220,
+ 99, 17,128,110,182,178, 37, 3, 24, 1,224,170, 43,131,198, 25, 28, 9,223,145,244,235,142, 11,112,187,119, 57,144, 63, 0, 92,
+220,249, 76, 45, 35,192, 27,121,142, 10, 86, 46,151, 19, 71, 35,192, 29,236,223,191, 31, 44,203,162,119,239,222,210,159,127,254,
+ 89, 81, 88, 88,168, 72, 72,176,110,169,203,113, 28,230,207,159, 79,171,171,171, 33, 16, 8, 48,118,236, 88,151,207,109,200, 61,
+ 6,134, 53,163,178,119,172, 84,240,243,117,197,165,213,251,209,254,237, 17, 86,210,226, 40,242,230, 11,105, 69,117, 48,244,130,
+ 32, 36, 79,187,232,250, 61, 50,188,234,242, 51,185,161, 6,163,133, 9,149,136,104, 74,175,214, 8,145, 8, 72,177,178, 26,129,
+ 12, 31,227,227, 91,211, 35,191,151,225,151, 31,118,163, 77, 96, 16,253, 85,163,190, 10,160,147, 51,113,185,167, 90, 76, 31, 16,
+127,107,127, 16,191,173, 89,104,190,217,126,232,192,241, 65, 6, 54,240, 49, 94,208, 49, 70, 93, 89, 17, 80,120,238, 88, 91, 19,
+123,174,252,114,129, 54,196,214,103, 92, 17, 21,117,215, 59,181,143, 15,112, 54, 38,192,153, 55,237,202,171,148,201,100,212,219,
+144,233,189,132,186,158,191,149,188,129,140, 12,223, 13, 18,244,133,231, 79, 41,133,217,252, 7, 71, 15, 30, 60, 24, 7, 15, 30,
+244,138,252,237,158,183, 64, 32,176,112, 28,119,152, 97, 24, 83, 35,141,128,166,246, 47, 74,165, 82, 17, 25, 25, 41, 83, 42,149,
+238, 62,180,170,178,178, 82,116,236,216,177,167,179,179,179, 71,172, 93,187, 86,153,150,150,214,122,195,134, 13,120,255,253,247,
+145,159,159,143, 54,109,218,160,180,180,148,204,153, 51,167,236,189,247,222,251,100,216,176, 97,167,210,210,210,126,118, 42,145,
+ 51,139, 45, 96, 34, 8,135,150, 38,112, 45, 3, 4, 34,129,144,207,220, 18, 11,120,122,158, 68,168, 17,137,120, 70,163,133, 19,
+242, 77,252, 64,214,108,228,174,156, 60,165,127, 38,234, 83,211, 17,120,199, 31,174, 34, 0,143, 0, 56, 84,103,224,216, 33, 0,
+143,172, 92,185,155, 6, 91, 96, 0, 0, 32, 0, 73, 68, 65, 84,114,149, 7,100,253, 20,128, 87, 1,196,214, 9,205,171, 0,252,
+ 70, 8,249, 47,128, 61,132, 16, 11,165,116,131, 27,242, 2,108,185,150,110, 54,235,222, 88,231,146,201, 0,126, 39,132, 44,166,
+148,234,188, 9,255, 3, 88,101,251,235,145, 1, 80,151, 48,101, 50,217,115, 0,166,219,222,229, 18, 66,136, 81, 46,151,175,190,
+ 23, 20, 8, 33,164, 3,172, 91, 30,255, 8, 96, 27, 0,123, 61,193,221, 8,192,223, 13, 37, 37, 37,138,254,253,251,131, 16,146,
+211,191,127,127,124,255,253,247,120,226,137, 39, 18,155, 53,107,166, 96, 24, 6,111,189,245, 22,177, 41,147,196,141, 27, 55, 42,
+140, 70, 35,250,246,237,235, 84,209, 13,188,114, 93, 81,218,191, 11, 64, 72,206,239,209, 22,105,183,211, 17, 10, 3, 7,169, 53,
+ 5, 0,244,120,139, 37,128, 18, 90,101, 85,226,190,141, 29, 20,218,224,163,210, 39,211, 66,234,245,138,139, 89,243,226,149, 43,
+ 55,188, 17,213, 68, 82, 88,165,101, 67, 99,195, 3, 5,169, 61,219, 5,196,199,138,136, 65,103,129, 78,207,225, 18,209, 91,182,
+ 21,150,232, 10, 74,171, 45,205,132,226, 27,165,172, 97,248, 53,163,233,227, 96,224,245,250,100,134,132,199,180,212, 87, 95,108,
+209, 53,105, 24,115,246,200,141,161, 37,231,191,191,214,161, 79,122, 83, 94,151, 94,197,167, 14,126, 87, 69,120, 33,125, 57,142,
+171,184,121, 83,239,210,138,170, 75,216,174,142,237,222,108, 70, 70,134, 83,194,118, 12,175,215,141, 4,184,115,253,253,138,164,
+164, 36,167,123,208, 59,134,240, 27, 3, 95,200,169,174,174, 86, 0, 0,159,207,199,107,175,189,134,227,199,143,227,231,159,127,
+110,172, 88, 35, 0,139,209,104, 52,151,148,148,100,197,196,196,152,224,253, 72,124,141,227,129, 82,169,148, 71, 70, 70, 62,174,
+ 84, 42,221,209,251, 98,131,193, 16, 53,107,214,172, 37,211,166, 77,171,234,222,189,187, 8, 64, 13,249, 3,192,128, 1, 3,176,
+101,203, 22, 12, 30, 60, 88,244,212, 83, 79,105,114,114,114,246,117,235,214,109,112, 64, 64, 0,116,186,219,169,137,227,168, 57,
+ 71,177,119, 87,135, 14,113, 57,109,219,196,158,229, 5, 75,202,120, 68,168,101, 68, 2, 29, 35, 14,208,176,124, 30, 11,106,226,
+113, 98, 83,176,166, 68, 25,116,116,223,233,126, 77,194,163,183,120,251, 34, 27,140, 0,200,100,178,225, 0,214,215,241,106,247,
+ 1,152,148,158,158,190,202, 29, 15,150, 16,194,179,133,191, 71, 59,203,203, 83, 74,149,132,144,241, 0,182, 17, 66,190,115, 35,
+175,243, 20,128, 61,148,210, 42, 39,242,170, 8, 33,123,108,215,125,233, 33, 41, 14, 3, 16, 9, 96, 6,128,141,132,144, 97,148,
+210,125,222, 68, 0, 8, 33, 41, 0, 22, 1,104, 67, 41,213, 18, 66, 6, 0,184, 42,147,201, 52,148,210, 76,119, 35, 0, 50,171,
+169,239,142,210, 34,114,187, 27,224, 30, 6, 2, 56, 74, 41,165,196,234, 54, 93, 5,160, 37,132,180,178,143,243,240, 36, 2, 80,
+215,227,111,140,247, 95, 19,150, 31,249,117, 77, 20, 32,174, 17,222,255, 31, 97,254, 63,194,183, 50,153,103,222,191,201,100,162,
+199,143, 31, 71,112,112, 48,242,242,242,168,197, 98,129, 90,173,198,185,115,231, 20,145,145,145,168, 19,246,203,233,218,181,171,
+116,211,166, 77,138,190,125,251,214, 31,238, 51,153,104,171,227,103, 32, 12,142,129, 32, 79, 73,163, 45,193,208,168, 25, 88,206,
+ 85, 3,145,181,119,164, 14,140, 52,231,180,238,115, 66,186,123,243, 4, 5,176,171, 94,101,119,241,218,181,127,198,181,106, 5,
+220,210,191, 1, 0,249,122, 53,118,136, 74,202,187, 62, 52, 52,170, 43,155,135,223,174,170,176,227,244, 77,126, 65,121,117, 8,
+ 0,148,178,134,240,107, 70, 83,106, 65, 73,201,150, 94, 81, 81,245, 26, 0, 15, 61, 54,158, 9, 16, 14,239,110,214,254, 86,212,
+186, 75, 82,199,170,107,155,217, 75,191,101, 85,154,184,160,155,101, 69,191,148,169, 43, 2,251,130, 97, 72,133,198, 16, 42,155,
+144,208, 74,254,221,201,107,206,218,140, 92, 46, 39,142, 17, 0,199,104, 76,221,112,187,157,164, 83, 83, 83,145,148,148, 68,234,
+ 91, 40,166, 49,163,241,235,147,119, 63,194,222,221,101,178,240,219, 34, 2,222, 70, 21, 50, 50, 50,124, 66,254,235,215,175,167,
+ 7, 14, 28, 0,221, 20, 14, 50, 94,133, 79, 62,249, 4,148, 82, 48, 12,131, 21, 43, 86,120, 61,224, 83,165, 82, 25, 35, 34, 34,
+164, 7, 14, 28,216, 53,116,232,208, 17, 54, 93, 75, 61,157,105,100, 67,152,173,191,166, 43,149,202,149,145,145,145,207, 0,168,
+136,140,140,124, 78,169, 84,186,114,212, 12,205,154, 53,171,218,189,123,247, 20,169, 84,186,170,115,231,206,218,164,164,164,170,
+236,236,108,123, 10, 25,219,182,109,131, 72, 36,194,213,171, 87,153, 93,187,118,133,180,104,209,162,120,208,160, 65, 5,231,206,
+157,171, 87, 96, 92,219,142, 26,189,222,144,114,224,192,129, 45,145, 77, 34, 43, 66, 67, 66,174, 67, 40, 52,153,141,140,209,204,
+ 51,234, 13,124,181, 54,208, 24,200,191, 94, 86, 46,217,183,123,215,146,174,221, 30, 88,196, 26,116, 94,167,149,249,117,136,134,
+200,100, 50,251, 75,108,102,251,236,183, 77,179,171,137,130, 2,152, 73, 8,105, 1,160,212,206,185,245, 89,232, 54, 82,121, 25,
+214, 1,122, 87,234,200,169,139, 43,182,235, 94, 38,132,124,218,128, 60, 2, 96, 44,128, 5, 46,228,173, 5, 48,155, 16,178,202,
+ 69,249, 28, 27, 77, 44,172,227, 29,122,195,154,251,127, 7,192, 9, 66, 72,123, 0,133,142, 54,134, 27,242,158, 4, 48,213, 70,
+178,122, 91, 89,245,182,227, 21,132, 16, 33,128,111, 27,146,103,171,139,103, 0, 76,115,215, 0,144,201,100,203, 1,124,237, 76,
+158, 77,230, 98, 0,193,176,142, 98,221,110, 43,155, 24,214, 65, 45,191, 1,232, 79, 8,153, 1,224,103, 0, 59,156,149, 15,176,
+206,163,119,146,235, 71,221,177, 1,201,201,201, 46,141,129,228,228,100, 41, 51,225,143,188,189,221, 8,176,127,119, 12,231,123,
+ 45,111,194,237, 83, 2,221,145,119,250,244,105,180,110,221, 26,175,189,246, 90, 77,155, 89,183,110, 29,205,205,205,197, 99,143,
+ 61,118,219,245, 1, 1, 1, 10,177, 88,236, 84, 94,236,233,211,168,108,221, 28, 71, 94,155, 82, 35,239,194, 63,183, 36,182,205,
+173, 82, 48,143,137,111, 43, 75, 81, 62, 11,145,184,225,217, 79,151,138,139,103,161,101,203, 95, 0, 12,160,160, 60, 92, 41,127,
+ 77,103, 54,195,108,176, 6,201,206,150,151,227,138,129, 93,199, 39, 68, 3, 66, 76,151,138,139, 51, 1,192,217, 32,192, 22,177,
+157,103, 1, 88,152,127,240,149, 66,113,244, 88, 85, 73,169,184,101,105,241, 49, 49, 4, 17, 29, 10,175, 90, 98,148,165,215, 32,
+ 20, 10,154,118,139, 14,124,170, 82, 99,250, 6,192, 53, 23,158, 43, 1,144, 88,119,250,159, 19, 15, 84,234,205,154, 0,245,229,
+255,255, 14,104,236, 84, 61,199,193,128,141,149,183, 97,195,122,154,147,147, 3,146,105, 53,140,247,188, 27,140,225,115, 53, 24,
+ 58,116, 40, 60,153,246, 87, 31, 34, 34, 34,164, 0,240,224,131, 15,234,108,245,219, 24,121,170,200,200,200, 73, 0,236,206,169,
+ 81,169, 84,238,112,113,143,210,230, 36,114, 0,170,163,163,163,243,158,120,226,137,101,243,231,207,159,110,177, 88,136, 68, 34,
+ 65,114,114, 50,126,250,233, 39,112, 28,135,145, 35, 71, 86,191,242,202, 43, 97,189,122,245, 58, 55,118,236,216,254, 0,170, 13,
+134,250,215, 13, 74,127, 49,157,147, 62,252,200,177, 7,186,247,120,250,216,209,163,235, 78,241,249, 41,237,218,180,123, 43, 36,
+ 50,170, 66, 16, 37,166,251,119,237,147, 84,168,148,113, 49, 17, 81,111,117,236,216,241,199,160,232,192, 3,159,252, 71,110,113,
+214,127, 61,141, 0,240, 96,157,238, 55, 8,192, 7, 0, 94,178, 17, 79,160, 99,127,130,117,144,216, 37, 0,255,178,165, 4,142,
+ 59,145,207,192, 58,200,108, 15,128, 0, 55,202,115, 24,192,112, 56,223,163,128, 1, 16, 5,160, 13,128, 19, 46,100,158,176, 93,
+215, 20,206,115,147, 12, 0, 33,172,211, 54, 38, 3,120,194, 70,220,249, 54,217,249,182,227, 13, 0,190,135,117,198,129, 10,206,
+231,125,218,229, 77,176, 69, 30, 58,219,140, 36,199,114,222, 0, 32, 3,112,222,118,237,119, 46,228,189, 10,235,236, 6,119, 82,
+ 25, 1, 0,118, 3, 88,239,162, 62,198, 1,248,208,246,247,148, 67,249, 4,182,186,204, 0,240, 25,128,185,182,223,111, 56,251,
+ 15,247,236,217,147, 67, 8, 65, 81, 81,145,194, 62, 19,160,174,215, 95, 84, 84,164,176, 95,235,234, 1, 82, 82, 82,114,178,178,
+178,176,238,103,182,102,228,126, 93, 47,125,221,207,108,205,181,119, 83, 94,110,110, 46,134, 12,169, 61,212, 61, 54, 54, 86,186,
+105,211, 38, 69,187,118,237,164, 28,199, 41,230,205,155, 71,237,211, 0, 9, 33,232,211,167,143, 83,163,162, 83,110, 46,190,141,
+108, 42, 13,113, 56,215,101,198,112,104, 23, 93, 3, 30,110, 10,202, 1,121,243, 4,180,154, 11, 66,133, 62, 4, 42, 18,143,158,
+ 67,182, 75, 27,106,246,182, 25, 28,155, 1,108,238,208, 38,166, 19,128,215,140, 22, 14,153,121,133, 24, 18,109, 77,119, 18, 74,
+ 53, 26,179,249,131,155, 55,111,222,116,163, 77, 45, 2, 16,152,127,190,226,233,202, 19,155,154,148,221,168, 64,217, 77, 13,248,
+124,101, 96,181,138,162, 82,109,161, 77,163,132, 97,124, 14, 99,244, 70,203,183,115, 95, 27, 20,214,180, 75, 90,165, 11,162,201,
+113, 53,215,191,209, 43,248, 37,109,178,254,205, 30,239,161, 7,124,103,103, 1,144,241, 42, 52, 70,158, 51,143,189,119,239,222,
+247,140, 33, 82, 51,216,209, 78,254,121,102,172, 86, 88,251, 88, 99,201,223, 78,248,124, 62, 63,138,207,231,151, 29, 62,124,248,
+171, 70,120,255, 0,208, 90,169, 84,126,110,139, 2, 76,176,205, 8,152,160, 84, 42,191,107,224,158,141,182, 8, 49,181,233,238,
+234,121,243,230,189,164,213,106, 91,156,206,203, 75,210,235,245,193, 10,197, 62, 34, 18,139,192, 16, 6,251,246,237, 19,116,237,
+218,245, 84,106,106,234, 72, 0,213, 99,198,140,193,135, 31,126,232, 84,184, 98,239, 79,220,168, 49,163,246,247,236, 25, 63,139,
+ 53, 27, 31,189,148,127,113, 30, 87, 88, 96, 6, 64,197, 96, 76,221, 59,116,202,104,218, 52,106, 39,143, 47,252,230,195,119, 23,
+ 52,106, 80,121,125, 6,192,107, 54, 11,231, 49, 0,231, 0, 4,213,115,223, 78,155,199,158, 2,235,146,136,147,157,200,231, 1,
+136,179,189, 48,119, 12, 0,165,237,122, 94, 3,242, 18, 1, 92,116, 83,222, 69,219,245, 91, 26,144,151, 14,224, 89, 0,103, 96,
+157,161,112,165,142,108,133,205,251,159,110,243,134,215, 0, 78, 71, 92,240,108, 30,251,100, 0,189,108, 81,132,250,202,169,182,
+253,190,194,102, 4,172,105, 64,222, 90, 91, 67,115,231,121,169,237,250,134,222,223,199,182,200,198, 30,155, 81,131, 58,178,127,
+ 2,208,213, 86, 23,249, 54, 67,170,149,171, 14,105, 91,160, 67, 81,223, 66, 64,158, 90,233,114,185,156, 60, 43,147,209,103, 63,
+211,214,179,112,143,202, 99,130,240,149,188,151, 95,126,249,182,107,134, 14, 29,154, 51,116,232, 80, 2, 0,195,134, 13,243, 72,
+ 9,237,124,249,101, 18, 82, 55, 77,209, 38, 40, 71,178,172, 11, 1,128,110,114, 1,177, 6,101,236, 35,179,175,186,217, 12,108,
+245, 98,161,133,224, 3,188,106,212,144,191,205, 69,190, 41, 22,139,221, 85, 28, 4,192,251, 7,179, 79, 5, 68,183,108,243, 56,
+135,128,184,226,162, 82,158,201, 80, 73,155, 53, 13, 34, 65,129, 2, 98, 54,113, 80, 85,178,102, 34, 33,146, 42,141,185, 67, 83,
+231, 14, 65,189,100, 81,247,251,159,185,124,239,157,158, 5,208, 88,121,206, 60,246,118,237,218,221, 51,228,207,125, 23,142, 61,
+121,214, 49,121,107, 20, 44,190, 61,204,130, 82,234,147,122,181,235, 17,139,197,162, 4,128,132,132,132, 70, 45, 8,100, 39,127,
+ 27,110,217,254,186,234, 27, 51, 28,244,169, 9, 64, 49, 0, 44, 93,186,116,220,148,231,166, 36,247,237,221,103,140, 70,173,142,
+ 50, 91,204,134,232,232,232,146,152,152,152, 2,181, 90,189,245,252,249,243,183,222,122,235, 45,183,202,181,125,235,118, 14,192,
+198,103,158,254, 71,238,160,193,131,191,151, 72, 36,161, 4,148, 35,132,128,227,104,149, 94,171, 82, 92,200, 43,210, 4, 8, 5,
+141, 10,111,213, 53, 0, 44, 0,158,107,128, 64, 28,113,204,246,177,216, 62,245,193, 2,235,136,122,158,155,229, 81, 0,200,118,
+ 33,111, 27,172,131,214,220,193,211,110,148,111, 37,128,175, 92,200,249, 29,214, 41,144,112, 67,222,215,182,136,129, 43, 20,218,
+ 60,123,119,202,199,243,160, 78, 87,186,144,247,176, 27,242,236,209,134, 53,182,119, 99,113,167, 99, 14, 31, 62, 60,209, 78,248,
+142, 33,120,111,150, 2,150,203,229, 36, 51, 51, 51,145,153,224,155,165,123,125, 45,239,126, 64, 65,241,117, 99, 92,171, 86,107,
+166, 45, 90,241,172,253, 28, 43, 96,214, 27,116,220,238,210,162, 34,141, 91,141,105,229, 74,122,235,196,106,178,224,187,223,102,
+237, 88, 54,108,235,145,163, 55, 94,136, 10,229, 70, 49, 17, 33, 97,148, 2,132, 80,163,209,204,149,114,192, 45,214,200,133,149,
+220,208,179,113, 30,148, 49, 53, 53, 85,234,152, 14, 72, 77, 77,149,222, 43,239,239, 94, 92, 9,240,126,193, 35,115, 53,119,244,
+ 25,109,211,190,155,139,197,226, 27, 9, 9, 9, 15,251, 66,166, 82,169,220, 27, 25, 25,249,172, 82,169, 92,227,230, 45, 60, 88,
+211, 0, 53,250,116,213,234, 85, 89, 0,178,124,245,156, 95,127,243,101, 33,106,167,159,125,138,250, 12, 0,111, 54, 53,112,102,
+133,112,176,142,216,244,203,251,107,202,171, 5, 27,209,251,172,163,167,164,164,228,184,154,151,255,103,202,187, 31, 80,161,211,
+ 77, 1, 2, 76, 0,162, 56,208, 18,131,129,221, 80, 90, 90,254,171, 39,211,166,154,244,126,142,110,251,100, 4,185, 25,248,100,
+110,203,193,200,205, 94,245,241,107, 17, 17,162,217,124, 30,161, 55,148,134, 11, 55, 88,243, 58,137,128, 17, 75,248, 60,158,201,
+204,137, 61, 41,159, 61,199,111, 31,120,230,237, 62, 0,183, 77,253,115, 8,253,123,179,216, 76, 93,207,220,157,243,119, 91,222,
+ 29, 52,124, 26,117, 63, 51, 65, 5, 66, 8, 70,141,254, 99, 64,244,206, 93, 39,107,116,200,200, 17, 9, 62,121, 86, 74,105, 41,
+124,188, 14,191, 7,228, 15, 88,151,159,231,112,135,150, 2,190, 27,224,215,169,120,234,174,178,175,139,250, 70,177,251,229,253,
+181,229,249,113,239, 67,169, 84, 82, 88,211, 92,141,194,205,192, 49, 20, 0, 14,174, 95, 74,146,166,188,254,201,228,244,188,207,
+ 94,154,120,184, 43,171, 37,109, 35, 4,252, 38, 32, 68, 23, 36,225,151, 63,208, 57, 36,223, 83,217, 73, 73, 73, 36, 35, 35,195,
+235,157, 0,239, 20,121,222, 47, 17,128,187,185,145,143,123,207,104,141, 13,253, 13,186, 87, 40,172, 27, 2,137,112,159,238, 6,
+ 72,122,245,234,245,247, 24, 34,235,135, 31,126,128,207, 3, 2, 68, 4, 28,103,213,209,213,122,127,247,247,195,143,191,173, 62,
+240,191, 2, 63,252,248,251,192,108, 1,212, 58, 59,233,251,201,223, 15, 63,254,206, 96,252,175,192, 15, 63,252,240,195, 15, 63,
+252, 6,128, 31,126,248,225,135, 31,126,248,225, 55, 0,252,240,195, 15, 63,252,240,195,143,191, 34,106,141, 1,152, 54,109,154,
+215, 35, 55,235, 91, 91,187, 62,121, 63,124,247,191,196, 7,122,116, 80, 52,111, 25, 35,213,232,181,138,253,138, 92,105,202,132,
+ 23,115,188,149,183,108,213,230,196, 94, 61,250, 43,110,150,148, 32, 80, 18,136,107,197, 5,210,231,167,140,246, 90,158,175,159,
+247,204,254,105,137, 3,250,183, 83, 72, 2,121,224,243, 24, 16, 49,193, 13,245, 43,196, 91,121, 39,111,246, 72,236,219,191,175,
+ 34, 52,136, 7,240,129,138,211, 43,137,187,229,139,123, 36,206,235,231,189,248,211,197,219,228,245,235,215,207,107,121, 71,143,
+ 30,189, 93, 94,156,247,229, 59,122,241,246,242,245,239,216,209,107,121, 71,242,243,239, 59,121,143, 52, 80,191, 11, 22,100,208,
+217,179, 83,157,254,254, 83, 61,245, 27,247,232, 35,222,183,151,221, 63,221,222,158, 31,241,190,189, 44,200, 82,210, 16,174,160,
+214,185, 38,113, 79,122, 45,239,214,197,111,111, 43,223,169,183,175,122,173, 72,227,231,181,185,237,220, 39, 77, 74,188,150,247,
+218,173, 24,252, 25,250,234, 94,146,119,234,212, 41,175,229,197,199,199,123, 37,143, 16,194,175,111,138,172,183,242,124, 93, 62,
+ 79,228,121,108, 0, 56,131, 97,163, 44, 14, 64, 59, 88,215, 9, 40, 16, 79,148, 95,113,247, 63,216,252,245,130, 68, 2, 14, 81,
+ 97, 17,200,221,127, 82,177,118,237, 82, 12, 74, 26, 4,179, 86,167,232,218,121, 40, 56, 14,138,223,219,174,149,198,199,247,192,
+165, 75, 87, 81, 85,169, 69,247,129,147,114,156,201, 91,249,141, 34,145,130,160, 77,135,118, 10,217,235,115,161,252,239,102,124,
+253,191, 47, 0,136,177,243,215, 98, 48, 12, 20, 75,223,127, 23,249,249, 23, 16, 27,219, 6, 34, 9, 31,215,139,243,157, 46, 46,
+114,121,203, 23, 84, 40, 20, 66, 34,145,160,160,160, 0, 45,154,134,160, 9, 63, 8, 45, 90,135, 33, 92, 18,138, 64, 98, 1,195,
+ 48,160,156, 5, 58, 17, 31, 85, 55,171, 80,214,199,245, 92,242,170,130,207,105,176,164, 10, 3,251,182, 71, 80, 32, 31, 66, 9,
+ 3, 62, 15, 96,132,124,116,138,249, 31, 53, 81, 30, 46, 95,159,226,118,133, 47,219,101, 72,140,137,137,193,160, 7, 91, 42,244,
+ 6, 35, 24,145, 4, 48, 1,121,213, 9,137,122,157, 22,253,155, 94,200,249,179,172,200,149, 43, 87,210,244,244,244,191,213,252,
+250,123, 21,174,136,190,145,215, 7, 2,232,219, 76, 18,240, 97, 73, 73, 73,103,129, 88, 4, 46, 32,224, 35, 88, 87,198,172,190,
+ 87,222, 65,193,239,187, 18,175,156,221,127,219, 94, 3, 73,169, 31,253, 85,218, 40,249,122,221,186,243, 34,161, 80,194,113, 92,
+104, 96, 80, 80,208,227,163, 70, 5,192, 58, 31,253, 94, 29,217,105,143, 54,115,141,126,120, 66, 66, 66, 67, 67,103,118,234,212,
+105,172, 72, 36,106, 89, 92, 92, 92, 92, 82, 82,114,148,101,217,121,148,210, 2, 47,228,133,133,135,135,207, 29, 54,108,216,136,
+ 23, 95,124, 49,182, 95,191,126, 55,207,156, 57,115,216, 96, 48,204,161,148,158,249,219, 68, 0,156,144, 63, 47, 80,196,239,251,
+204,224,246,139, 57, 74, 13, 7, 47,220,252,239,185,141,178, 61,226,137,242,179,174,238, 77, 29,213,129,142, 26,182, 0,166,234,
+ 74,240, 45, 12,126, 59,123, 1,105,105,175,252,209, 34, 24,224,151,220, 53,104,210, 58, 70,193, 85,171,193,114, 4,251,246,229,
+ 74,139,245,245,203,147,201,230, 81, 8, 67, 65, 2, 66,112,242,108, 17,126, 61,251, 28, 86,125,251, 83,205,239, 28, 7, 60, 58,
+112, 32, 80, 93, 10, 32, 24, 5,103,206, 65,208, 36, 12,131, 6, 60,160,168,212, 53, 96,179, 16, 6, 32, 12,122,245, 72, 64,179,
+ 64, 33, 90, 52, 17, 35, 36, 50, 2,225,162, 96,132,139,121, 16,240,120, 48, 89, 44,168, 52,115, 56,118,235,132,203,151, 90,250,
+235, 92, 26, 17, 10,132, 4, 4, 32,170, 73, 36, 66, 66, 2, 64, 25, 11,204, 92, 53, 44,176, 32, 40, 40, 0, 77,154,181, 68,187,
+184,159,105,246,254,193, 13, 42,165, 21, 89, 44, 13, 13, 14, 68,187,182, 77, 17,213, 36, 18, 90,173, 22, 66,145, 24, 2,131,117,
+113,190,182,177,109, 20, 21,170, 74,124,151, 91, 40, 45, 42,190, 14, 85,233, 85,204,123, 49,161, 65, 99, 32, 99, 65,134,219, 74,
+ 34,233,217, 36,105,120,116,120, 78, 67,228,127, 55,140,128,183, 23, 45,162, 0, 48,239,159,255,244,201,255,241,214,194,133, 20,
+ 0,230,207,154,229,181,188, 31, 15, 29, 74, 99, 89,118, 13, 0,140,149, 74, 25,111,148,175,124,211, 38,106, 83, 66, 53,231, 40,
+165, 32,132,212,252,181,159,179, 95,151,158,234,156,176,103,207, 78, 37,238,146,186,135,228,223, 53,208,100,222, 28, 28, 22,218,
+ 25, 0,132, 18, 49, 88,189, 1,156, 86,183,240,240,129,253,239, 63, 52,110, 92, 23, 0, 69,174,132, 24,121, 66, 10,235,220,105,
+179,141, 20, 56,155, 30,170, 87, 23,245,124,104, 4,206,239,219,230, 81, 29, 93, 57,187, 95,209,225,129, 68,105,108,151, 71, 61,
+ 55,138, 83, 43, 60,186,124,252,248,241,216,148,154,221,224, 53,210,236,218, 91,145,116, 13,179, 62,106,153,129,131,222,108,173,
+ 87,173,237,175,188,127, 24, 58, 6, 11, 26,148,183,120,241,226,156,183, 95,125,163,233,232,177, 99,130, 12, 6, 61,150,126,242,
+ 49,179,108,217, 50,195,140, 25, 51, 98, 0, 92,247,117,223,219,189,123,119,210,214,173, 91,179, 0,207,214, 44,200,205,205,165,
+133,133,133, 80, 42,149,208,104, 52, 8, 14, 14, 70,100,100, 36, 98, 99, 99, 49,112,224, 64,175,250, 29, 33,100,104, 66, 66,194,
+186,215, 95,127,253, 82,167, 78,157,214,196,199,199,159,187,121,243,102,203,220,220,220,132, 41, 83,166,236, 32,132, 44,164,148,
+122,178, 85,189,116,236,216,177, 25, 11, 22, 44,136, 52,153, 76,144, 72, 36, 8, 12, 12,108,174,213,106,199,141, 30, 61,250,113,
+ 66,200, 12, 74,233,255,238, 71,114, 63,125,250,116,173,227,250, 54,116,227, 59, 33,253, 86, 0,218,195,186,196,161, 69,107, 52,
+ 95,203,189, 88,246,233,192,184,166,175, 12,235,218,252,253,102,161,146, 22,138,141,178,141, 0, 46,136, 39,202,157,110, 82, 99,
+172,174, 64,179, 14, 15, 99,238, 63,199, 98,141,252,143,190,184,255,240, 10,104,117, 70,140, 76,122, 5, 15, 14,122, 22, 79,142,
+ 31, 6,137, 68, 4,214, 98,134, 70,199, 42, 58, 14,232,224,164,113, 92, 5, 88, 96,236,164,229,120,254,245, 23,106,206, 62,250,
+ 96, 34,196, 98, 17,190,223,247, 19,118, 30,202,197,186,213, 95,192,160, 55, 66,200,227, 35, 40, 64, 8,173,178, 88, 90, 89,140,
+122,119, 31,163,148, 2,148,179,126, 24, 14,148, 82, 24, 89, 81,205,242, 14,148,181,192,194, 3, 44,176,192,194,114, 48, 91, 26,
+ 54, 96, 11,142,206,167, 45,163, 40, 66,130, 3, 17,211,178, 45, 58,119,239,128,224, 32, 9,170,170,203, 81, 90, 94, 10, 85,213,
+ 77,152, 12, 4, 1, 1, 1,136,138, 26,132,113, 99,206,208,205, 91, 59,213, 31,198, 95,127,141, 90,130,131,161,231, 3, 66,177,
+ 16,122,157, 16,172, 78, 8,131, 88, 4, 62, 49,131,130, 7,131,190, 26,122,157, 6, 45, 91,182, 80, 8,121,124, 84, 64,141, 79,
+ 63, 61, 0,145,168,225,198,177,104,221, 34,151, 13,232,159,147,255,217,224,239, 42,149,138,214, 57,238, 29, 17, 17,145, 79, 8,
+ 49, 80, 74,249,225,225,225, 1, 5, 5, 5,145, 25, 25, 25, 57,233,233,233, 45,188,109,200,194,232,232,137, 53,255, 7,144, 24,
+ 14,248, 44,218,177, 50, 35,131, 78,159, 62, 93,106, 42, 43,243, 72,230,143,135, 14,201,250,245,235, 55,111,112,175, 94, 48,137,
+ 68, 88,178,100, 9, 55,110,216,176,100, 74,105,182,135, 10, 13,139,223,127,191,230,120,230,123,239, 97,201,156, 57, 13, 30,187,
+ 66, 93, 35, 96,193,130, 12,218,187,119,111,100,103, 95,166, 73, 73,237,186, 1,184,188, 96, 65,134,222, 67,242,207,237,222,173,
+ 91,136,189,207, 4,138, 37,184, 81, 94, 6,181,170, 18, 9,253,250, 7,252,184,106,117,246, 99, 83,158,235, 6,235,218,232, 13,
+193,252,242,188,101,252,167,199, 61,206,143,139,141,229,236,158,225,123, 75, 62,171,117,209,156,153, 47, 89, 13,191, 87,103, 72,
+ 39,143, 74,246,184, 94,189, 34,255, 26, 11, 57,194,131,139, 61,219, 49, 47,144, 79,240,235,156,169, 32, 33, 77, 96,185,252, 43,
+140,151,127, 71,126,133, 22,125,118,149,185,117,255, 10,185,252,224,235,178,233,109, 38,255, 99, 74, 88,198,250,111,185,216,216,
+ 88,102,238,130,133, 8,126,127, 46,190,255,254,251,146, 39,158,120,194, 43, 67,212, 9,241, 39,111,221,186,117,143,253,120,204,
+152, 49,195,221,185, 79,163,209, 36,238,217,179, 71, 97, 50,153,208,190,125,123, 12, 25, 50, 4,161,161,161,168,172,172,196,245,
+235,215,113,229,202, 21, 92,191,126,157, 14, 31, 62, 92, 26, 28, 28,156,227, 65, 95, 25, 51,108,216,176,165,139, 23, 47,222, 24,
+ 31, 31,191,212,110,236,180,104,209, 2,227,198,141, 35, 41, 41, 41, 65, 0,114, 9, 33,185,206,118, 47,173, 43,111,198,140, 25,
+153,211,167, 79,103, 78,156, 56, 1, 66, 8, 34, 35, 35,107, 62,187,118,237, 18, 14, 24, 48,224, 11, 66,200, 17,119,228,221,203,
+228,111, 63, 87,247, 57,248,245,144,127,100,159,182,145,147,123,181,137,152, 68, 8, 17, 80, 74, 77,156,245,195, 90, 76, 6,189,
+144,225, 90,116,111, 38,254,103,147,144,246, 29,182, 30,187,242,173, 97,163,236,160,120,162,252, 70, 3,234, 27, 93,187,116, 2,
+195,228, 32,191, 82, 9,224, 28,170, 74, 46, 66, 32, 22, 97,219,142,255, 66,119,203,130, 73,207,189, 6,142, 3, 70, 61, 62, 16,
+ 22,126,144,203,135,203,207, 63, 7,142, 3, 70,246, 36, 0, 90, 0,104, 3,131,145, 69,202,163,195, 33, 14, 99,176,110,195,110,
+ 48, 12,144,249,237, 26,148, 92,254, 93,250, 68, 98, 92,206,133, 83,245,203,226, 40,192,113, 28, 56,142,131,197, 98,129, 81, 64,
+ 97, 34, 38,176, 44, 11, 93,128, 1,224,196, 96,168, 5, 22, 33, 69, 53,107,128, 86, 93,213, 96,217,162,130,140,224,243, 37,136,
+140,140, 68,135, 14, 29, 16,221,172, 63,192, 99, 96,177,156, 0, 67, 43, 97,208,154, 97,225,180, 40,189, 94,129,168,200, 91,136,
+ 12, 27, 4,149,230,173,196,250, 54,121,145, 24,204,160,198, 91,128, 65, 4,150, 49, 65, 43,228,163, 90, 34, 0, 95, 32, 4,184,
+ 64, 16, 30, 65,181, 86, 7, 85,233, 85, 20,156, 56,132,138,162, 34,112, 28, 7,134,242,188,106, 52,171,150,255, 97, 56, 79,153,
+ 54,197,181,158,180,109, 27,106,111, 58, 25, 25, 25,179, 95,127,253,245, 23,138,138,138, 24, 66, 72,148, 92, 46,255, 22,214,205,
+157, 2, 26,209,150, 5,159,127,254,249,134,155, 55,111, 34, 51, 51, 19,125, 58,117,226,133,119,239,222,232, 14, 50,127,214, 44,
+162, 2, 18, 41,165,138,101,203,150, 41, 0, 64, 54,126,188,219, 94, 9,203,178, 43, 6,219, 58,147, 80, 40, 68,199,142, 29,177,
+121,223,190, 44, 91, 52,192,109, 57,119,106,171,218,217,179, 83, 73,118,246,101,122,226,132, 53, 98,229,240,247,247,135, 30,122,
+168,100,246,236,212, 80,119, 57, 43,208,100,222,220,189, 91,183, 16, 30,195,224,197,167, 39, 65,111, 48, 98,201, 87, 95, 33, 64,
+ 34,129,193, 96,128, 65,175, 71,207,248, 94,113, 63,173, 95, 63,253,145, 73,147, 62,117, 21,117,156, 51,243, 37, 14, 0,115,177,
+176,144,169, 75,248,117,187,167, 55,207,222,170,243, 80,105,118,198,155, 52,121,212, 84, 41, 21,197,121,101, 8, 56,238,218, 71,
+ 55,133,187, 60,239,210,130, 10,227,227,106,181, 5,251,147,163, 32,120, 69, 14,245,164,182,224,135, 55,245,136,252,247,238,221,
+ 91, 26,219,188,197,245,127,188,248, 66,171, 55, 95,155,133,101,171, 87,156,237,151,144,208,110,197,103, 43, 2, 94,157,245, 6,
+214, 15,236,143, 13, 27, 54, 60,243,212, 83, 79,173,107, 36,241, 39,110,221,186,181,198, 97,146,203,229, 5,176,110,235,190,215,
+157,251,247,236,217,163,136,138,138, 66,124,124,188,153, 97, 24,190, 53, 58,203, 65, 32, 16, 32, 34, 34, 2,205,154, 53,195,149,
+ 43, 87,176,103,207, 30,197,184,113,227,220,234, 43,132,144,212,199, 30,123,236,227,197,139, 23,127,214,169, 83,167,229,132, 16,
+ 14,192, 23, 0, 30, 1,112, 0,192, 28, 74,105, 33, 33,228, 13, 0,115,220,145,183,120,198,140,239, 6,167,166,146,237,219,183,
+131,207,231, 67,161, 80,224,215, 95,127, 69,135, 14, 29,240,193, 7, 31,224,129, 7, 30,192, 11, 47,188,192,127,231,157,119, 22,
+223,143,228,159, 62,251,163, 63, 28,157, 5,111,214,107, 4,212, 55, 11,128,225,243, 24,190,153,163, 26,189,201,124,157, 16, 34,
+ 10, 18,241,122,132, 8,209, 71,210,237,161,246,144, 62, 15,116, 30,130,230,129,116,204, 51,131,218,190, 25, 17, 18,144,108,216,
+ 40,107, 64,153,112,224,241,236,132, 20, 2,160, 37, 66, 99, 30,131,222, 98,192,114,249,106,124,189, 33, 19,195,165,131, 0, 0,
+ 58, 29,192,227, 59, 23, 37, 9,232, 4, 0,176, 88, 28,247,166, 41, 5,144, 11,134, 39,194,228,180,169, 72, 25, 63, 30, 63,238,
+176, 18, 89, 64, 32,160,173,190,209,224,203, 50,129, 87, 67,254, 38,179, 5, 70,181, 9,186, 74, 29, 42, 77, 44, 42,116, 44, 84,
+ 70, 13, 42, 53,213, 80,149,105, 80, 81,105, 64, 69,181,243, 37,212,127, 85, 44,160,132, 16,240,120, 4,132, 17,193, 98,161, 48,
+235,138,160,173,188,136,146,210, 42, 84,168,170, 81,165,177,160, 66,101, 64,113,113, 41,206,158, 63,141,202,170,211,232,159,208,
+219,233,222,232, 60, 0,140,198, 0,253,165,235, 80,254,118, 14,202,162,171, 80, 87, 85, 64, 93, 85,129,171,103, 79,224,112,198,
+ 42,228,110, 90,135,242, 75,151, 96, 97, 57,235,194,216,188,187,147, 6, 76, 79, 79, 39,182,176, 63,155,146,146,210,101,238,220,
+185,175, 55,111,222, 92,155,153,153,217, 35, 35, 35,227, 7, 0,241,182, 74,247,122,193, 41, 97,116,244, 76, 0, 24,240,192, 3,
+152, 62,125,122,217,177,243,231,179, 79,157, 57,147,232,139,242,135, 3, 57,178,241,227,201,140, 25, 51,164, 0, 32,104,218,212,
+ 35,185, 38, 91,152,101,243,230,205,104,218,180, 41,222,156, 49, 3, 51,103,206,196, 22,133,226,158,200,195,218, 73, 95, 46,151,
+215,124, 0, 96,255,254,253, 49, 0, 30,119, 83, 76,223,176,240,240,206, 60,134,193,115, 41, 41,168,172, 82,163,248,198,117, 8,
+ 4,124,240,249,214,143, 64, 32,128, 72, 18,128,246,177,177,159, 92, 58,126,194,173,205,124, 46, 22, 22,226,155,205, 63,212,124,
+236,120,111,201,103,120,111,201,103,216,169,216,239,197, 19,107, 18, 1,160, 83,247,145, 57, 73,163,166, 74,179,182,127,165,200,
+206,120,243,158,168,139,188,181,159,162,236,249, 4, 60,148, 85,142,174, 97,124,240, 66, 34, 96, 86,149,161,207,174, 50, 4,242,
+173, 28,200,115, 49, 39,235,202,165, 75,202,149,242,255,117, 90,251,191,181,248,239, 87, 95, 92,253, 98,241,199,239,189,254,210,
+203,143,207,157, 55, 23,146,224, 64, 12, 25, 48, 8,199,142, 30, 91,123,240,208, 65,175,159,185, 46,249,111,223,190, 29,125,251,
+246,109, 15, 96,146,187, 97,127,147,201,132,132,132, 4,206, 98,177,240,171,170,170, 96, 52, 26, 97, 52, 26,113,254,252,121, 40,
+ 20, 10, 28, 58,116, 8,205,155, 55,135,201,100, 66,110,110,174,203,178, 18, 66, 38,142, 31, 63,254,211,177, 99,199,134, 44, 95,
+190, 60,132, 16, 34, 4,176, 31, 64, 21,128, 4, 0, 63, 0,176, 27,158,123, 1, 60,224, 74,222,214,215, 95,255,238,241,158, 61,
+201,250,148, 20,148,156, 58,133,143, 63,254,152,251,241,199, 31,255,115,237,218,181,166, 10,133,226,249,217,179,103,195,100, 50,
+ 97,208,160, 65, 8, 12, 12, 28,136,251, 28,142,198, 64, 45,178,175,123, 66, 60, 81, 94,254,203,165,242, 21,107, 14, 92,122,237,
+124, 73,213, 30, 6,148, 15, 80,224,177, 15,240, 75,239,143,241,161, 42, 5,251,186, 45, 4, 30,121, 11,193, 2, 46,254,209, 94,
+177,147,108,233,130,219,176,125, 95, 5, 1,212, 24,157,246, 10, 56, 14, 0, 42, 0, 4, 3, 48,161, 77,167, 4,136, 69,124, 88,
+204, 70, 80,214, 74,170,193,193,193, 80, 86,168,156, 62,196,167,159,188, 78, 0,224,236, 47, 95,129, 97,106, 59, 9,156,254,119,
+ 24,140, 38,240, 4, 98, 16,161, 53,135,166, 81,171, 49,112, 96,195,117,199,231, 88,112, 28, 7,179,217, 12,163,209,136,106,206,
+140, 42,214, 4,245, 13, 53,170,174, 87, 65, 93, 90,129, 10,117, 37, 74, 13, 58,168,181,149,168, 52, 58, 31,235, 20, 28,164,133,
+217,204,193,200, 90, 80, 89,165, 70,254,165, 34, 28, 61,145,135, 95,142,230,225,220,249, 2, 20, 95,187,133,106, 45, 11, 77,181,
+ 17, 55, 74,170,112,230,247, 43,200,205, 61,133,226, 27,165, 78,101, 58,154, 58,230, 42, 45,138, 79,159,195,111,187,246, 33,107,
+245, 39,216,183,113, 53,138, 11, 46,129,163, 38,112,132,212, 16,191, 39,201, 53, 87, 97,126, 87,224,243,249, 0,112, 19,192,205,
+240,240,240,226,224,224, 96,227,236,217,179,143,193, 58, 96,140,129,117,141,236,124,111,229,127,254,249,231,243, 83, 82, 82, 0,
+ 0,109,163,162,154,218,114,226, 60, 95,118, 14,123,248,223, 30, 9,112, 35,252,159, 4, 0, 75,150, 44,193,197, 27, 55, 48,118,
+248,112,216,163, 1,121,121,121, 0, 96, 55, 2,220,170,138,153,239,189,135, 55,222,127,191, 38,188,111,255,110, 63,182,127,119,
+ 39,252,111, 71,118,246,101,251,214,186,181,206,219,143,179,179, 47,127,227,142,156, 48, 62,255, 67, 3,107, 4,143,199,195,249,
+203, 5,184, 92,124, 13, 71, 78,255, 10,150, 53,129, 1, 1,159,207, 7, 33, 4,156,197, 2,189, 86,135,188,253, 57,251,220, 16,
+203, 56,146,254,211,227, 30,191,205,227, 63,114, 50, 15,142, 17, 2,247,224, 16, 78, 22,197,229,216, 7,253,101,103,188, 73, 5,
+230,139,137,127,170, 6,174,184, 1, 97,235,142, 40,155,254, 32,242,214,126, 10,126,147,230, 53, 63,149, 77,127, 16, 77,196, 12,
+ 66,248, 13, 55,151, 78,113,157, 90, 4, 4, 4, 6,252,247,203,207, 13,210,135, 30, 18,246, 31, 56, 96,253,149, 75, 87,184,243,
+151,242, 1,142, 66, 44, 18, 97, 80,239, 65,216,177,125, 7,182,110,221,234,145, 17,176,123,247,238, 68,153, 76, 70,237,228,191,
+103,207, 30,172, 88,177,130, 5,128,163, 71,143,178, 50,153,236, 41,119, 82, 11,133,133,133,246,173,137,153,194,194, 66,100,101,
+101, 33, 47, 47, 15, 90,173, 22, 42,149, 10,199,143, 31, 71, 81, 81, 17,174, 93,187,134, 54,109,218,160,176,176,176, 65,121, 60,
+ 30,111,242,147, 79, 62,185, 40, 49, 49, 49,232,216,177, 99, 33, 58,157,238, 31, 18,137, 36, 7,192,103,148,210,183, 40,165, 85,
+ 54, 3,160, 47, 33, 68, 72, 41, 53,161,129,233,237, 66,161,112,242,247, 51,103,174, 31,212,180, 41, 49,207,154,133,129, 44,139,
+ 99,219,183,211,146,146,146,169,148,210,247, 40,165,229, 0,214,156, 61,123,214,108, 54,155, 17, 20, 20,132,152,152,152, 32,147,
+201,132,191, 34,234, 75, 1, 68, 3,104, 63,166, 79,235, 23, 91, 69, 6, 78,130, 73, 15,116, 74,198,201,168, 49, 24, 54, 99, 21,
+244,183, 42,193, 11, 9,134, 98,233,100, 12,233,250, 11, 34,242,178,134, 2,104,237,236, 63,232, 16,210, 18,191,229,109,113,176,
+ 55,180,176,166, 9, 77,128,201, 8, 62,199, 3, 99,235,247, 91,191,183,166,155, 6,141, 24,239,188,161,158,161,120, 52,222,209,
+192, 35,182,199, 16, 0, 2, 49,204,196, 2,155, 31,140, 9,147, 94, 6, 0,197,213,195, 43,157,246, 44, 11, 71, 97,230, 24, 48,
+102, 51, 24,214, 8,157,205,178,208,243,120, 8, 52,235,161,214, 83, 16, 1,129,197, 98,129,206, 2,148,105, 89, 56, 75,102,155,
+ 89, 14, 6, 1, 15,156,206, 12, 51, 87, 5, 77,181, 9, 60, 34,128,209,108, 2, 75, 89,152, 77, 44, 32,228,192, 16,128,136, 56,
+ 84,233, 45, 40, 45,215, 65,107, 52,215,235, 36, 51,196, 82, 99, 0, 16,242, 7,159,152, 12,122, 84, 85, 84,128, 33, 60,240,249,
+ 20,160,124,240,136,247,137,191, 11, 87, 47,176,157,218,116, 18,186, 19,246,175, 99, 73, 67, 34,145, 0,128, 30, 0,203,231,243,
+113,249,242,101, 44, 88,176,224,113, 0,215,102,207,158, 29, 31, 26, 26, 26, 86, 85, 85,117,181,178,178,210,227,112,183, 48, 58,
+122, 10, 0, 52,107,214,172,230,220,140, 25, 51, 42, 63,251,236,179,108, 0, 73,241,221,187,239,245, 85, 71,152, 49, 99,134,212,
+ 29, 3,224,199, 67,135, 18,251,245,235, 23, 51,184, 87, 47,144,224, 96, 44, 88,176, 0,179,102,205,130, 64, 32,128, 73,165, 66,
+104,104, 40,222,156, 49,163,102, 92,128, 59,131, 3,235,230,248, 93,141, 9,112,134, 5, 30, 12,238, 60,113,226, 4, 78,156, 56,
+ 81,115,189,179, 28,167,170,162,162,115, 80,112, 48,110,169, 84, 80, 28, 57, 2, 62,195,131,209,100,130, 78,175, 7,199,113, 53,
+131, 21,205, 38, 22,172,209,232, 78, 29,115, 0, 24, 91, 26,128,115,104,248, 6,219,121,188,183,228, 51, 33, 0,196,197,198,150,
+ 93, 57,251, 91,163,234, 53, 41,245, 35,114,254,100,102,226,174,173, 95, 41,124, 49, 11,192,147,176,127,173,176,236,166,255,161,
+ 87,218,107, 16,181,237, 97,213, 21,183,110, 32,191, 66,107,181, 85, 6, 62,134, 34,139, 25, 1,203,142, 52, 40, 67,173, 86,135,
+137, 36, 98,116,104,219, 86,124,165,248, 90,115,101,185, 18, 19,158,158,164,216,185, 55, 11, 75, 63, 90,146,185,117,231,246,148,
+184,182,113,152, 60,238, 25,228,158, 60,132,173,155, 55,211, 49,110,132,216, 29,189,254, 61,123,246, 32, 57, 57,217,110, 44, 10,
+175, 95,191,142, 23, 94,120, 65,104,127,124, 87,178,148, 74, 37,167,125, 17,183, 0, 0, 32, 0, 73, 68, 65, 84,134, 12, 25, 2,
+139,197,130,194,194, 66, 28, 58,116, 8, 93,187,118, 69,104,104, 40, 90,181,106,133, 94,189,122,129, 97, 24, 48, 12,131,230,205,
+155,215, 68,169,156,232,151,174, 61,122,244,248,116,224,192,129,188,188,188,188, 16,139,197, 82,186,121,243,102,181, 94,175, 95,
+ 64, 41,117, 52, 96, 95, 28, 49, 98, 68,209,206,157, 59,219, 18, 66,110,192,201,198, 60,132,144,248, 25, 82,233,154,254,124, 62,
+ 41,159, 55, 15,212,100,130,130,199,227,114,117,186,103, 41,165, 95, 59, 92, 58,237,221,119,223,229, 51, 12,131,138,138, 10, 92,
+190,124,185,236,129, 7, 30,104,250,151, 55, 0, 12, 27,101,113,209,161,146,193, 35,122,198,188, 16, 34, 17,244, 51, 91, 56, 21,
+159, 90, 66, 16,214,156,119,163,210, 0,253,173, 42, 64,200,135,165, 82,131, 98, 21, 11, 68,182, 6,195,177,226,134, 66,188,151,
+212,106,116, 12, 11,129,217, 8, 92,202,249, 6, 29, 18, 31,169,113,224, 76,172, 9, 2, 48,168, 54, 88,119,168,125, 52, 49, 1,
+146,200,152, 6, 11,252,104,119,130,157,191, 82, 8,196,128,176,245, 35, 96,139, 14,214, 56, 14, 2,161, 8, 38, 24, 16, 36,177,
+238, 72,186,125,231, 70,252,118, 52, 71, 58,105,120,111,231,218,136,227, 32,100,245, 48, 65, 8,134, 49, 3, 6,171, 98, 51,153,
+ 76, 48, 26, 4,224,241, 5,128, 1,160,156, 53, 69,208, 38,182,173, 83, 89, 58, 3, 7, 30,143,192,100, 54,193, 96,228,160,214,
+ 88,219,161,137,163, 96,141, 28,192, 7,120, 2, 30,248, 98,128,232, 45,224,136, 25, 28,244,208,232,109, 1,105, 23,176, 0, 96,
+ 56,128, 18,128, 97, 56, 16,194, 3, 71, 9, 24,198, 54,150,138, 99,192, 49, 12, 8,231,158,131,236,224,253, 11,189,109, 64, 1,
+ 1, 1,176,121,251, 81,151, 47, 95, 46, 91,176, 96,129, 20,192, 19,179,103,207, 30,222,174, 93, 59,173, 70,163, 81,154,205,230,
+ 26,162,240,132,255, 63,255,252,243,175, 82, 82, 82, 16,219,164, 73,205,201,216, 38, 77,194,108, 81,128,168, 63,163,195,176, 44,
+171,176,123,251, 84,163,193,191,254,245, 47, 24,149,202,154,145,111, 29,108,198,138,192,104,196,227,143, 63, 94, 86, 82, 86,246,
+ 84, 76, 64,192,250,187, 81, 54,199, 65,125,142,249,255,250,208,187,119,111, 36, 37,181,171,185,190,190,117, 0, 0,192,108,100,
+ 81,201, 86,192, 96, 48, 32, 44, 52, 20, 98,161, 8, 38,139, 25,148, 82, 88, 44, 22,176, 44, 11,147,201, 4,206,108,113,183,126,
+185,139,133,133, 76, 92,108,172,221, 35,224, 46, 22, 22, 50,223,108,254, 65,236, 24, 17,136,139,141,173,132,143, 6,179,117, 78,
+ 72,201, 41, 46, 56,238,147,119,236,237, 24,128,135,178,202, 81, 22,155, 9, 97,235,142, 32,109,123,160,205,234, 83,184,101,224,
+ 16,200, 39, 96,127,254, 30, 23, 46, 95,113,185,127,158,222,204,226, 68,238, 81,124,186,248, 19, 60,152, 56, 24,239,254,231,125,
+252,180,235, 39,172, 95,247, 53, 6, 14, 29,156,210, 42,182, 53,248, 1, 2,236, 61,184, 23, 27,214,126,141, 45,223,111,198,142,
+ 29, 59,232,255,253,223,255, 57,149, 44,147,201,104, 93,226,183,163,178,178,210,243, 36,140, 70,131,208,208,208, 35, 0,250,199,
+198,198,162,119,239,222,224,241,172,105,214, 54,109,218, 64, 36, 18,161,170,170, 10,177,177,177, 8, 14, 14,190,170,209,104,218,
+ 56, 53,182, 40, 61, 75, 8,153,191,101,203,150,145,113,113,113,157, 55,111,222, 92,173, 82,169,230, 80, 74, 55, 56,144,250,152,
+135, 30,122,232,245,213,171, 87,111, 2, 80, 6, 32, 21,192, 47, 0,122,214, 35,239, 20, 33,100,126,216,241,227,111, 63,105, 54,
+227, 19,128,251,170,186,250,153, 58,242,158,120,249,229,151, 63, 73, 79, 79,199,149, 43, 87,176, 99,199, 14,152,205,230,125, 0,
+158,188, 95, 72,189, 87,175, 94, 56,125,250,116, 77,222,191,193, 80, 92,157,227,118, 99,250,180,158, 27, 34, 17,244, 43, 87, 27,
+126, 58,124,177,124, 1,120, 34,224,194, 65, 60, 28, 75,241,214, 75,143,163,119,183, 88,188, 44, 27,129, 81,237, 89,224,204, 30,
+ 80,129,196,140, 6, 7,235, 84, 34,191,178, 8,124, 17,240,232,168,215,176,225,191, 31, 1, 96, 1,157, 17, 22, 61,240,189,226,
+ 52,178,143, 89,103, 20,182,108,221, 22, 12,223, 53,121,141,236, 73, 96, 50, 0,219,119,236, 70,159,225, 47, 89,189,127, 8,192,
+147, 0,227, 31, 75,197,200,161,163, 1, 0,197, 87, 11, 96, 54, 52,188, 85, 51,165, 20,102, 98, 37,120, 35,107, 29,252,103, 52,
+232,161,211,233, 80, 93, 93, 13,141,186, 10, 26,141, 6,106, 77, 53, 12,213,213,208,235,245,206, 27,127, 53,129,222, 96,129,222,
+ 96,129, 86,103,130,166,218, 8,149,198,136, 74, 53,139, 42,141, 9,149,149,214,191, 21, 74, 51, 42, 84,102, 84, 84,153,113,171,
+130,197,205, 91,206,203,200, 80, 10, 11, 0, 98, 33, 32, 12, 7, 74, 40, 64, 41, 40,229,193,194,253, 81,125,156, 77,123,120, 26,
+ 27,239, 50,176, 11, 14,237, 60,132,159,246,253, 84, 99, 20, 92,184,122,193,173,123,121, 60, 30,248,214,250,138, 1,208,126,225,
+194,133,191, 2, 88,246,230,155,111,190,218,174, 93, 59,179,181, 63, 89, 11,230, 33,249, 19, 97,116,244, 86, 0,136,142,142,190,
+237,199,233,211,167,155,143, 95,184,176,209, 87, 99, 1,236,225,127,119,247,141, 55, 57, 76,177,248,238,187,239,112,169,212,154,
+194,249, 49, 39,167,214,111, 23, 46, 92,104, 26, 21, 21,165,250, 51,148, 64, 82, 82, 59,198,166,224,235, 42,252, 90,191,187, 52,
+240, 66,130,207,115, 22, 11,212, 21, 42,220,186,117, 11,202, 74, 21,180, 58, 29,180, 58, 29, 52,213,213,208, 86,169,161,169,172,
+132, 65,175, 3,107, 48,128, 51, 91, 92,234,156,184,216, 88,187,206,224, 0,176,142,233, 0, 0,248,102,243, 15,120,111,201,103,
+ 97, 0,162, 61,125,238,115, 39, 51, 19,235,230,253, 11,126,223,149,248,103, 43,229, 27, 19, 98,209,102,245, 41,144,182, 61, 96,
+220,159,137,171,207,197, 35,144, 79,112, 48, 57, 10,230,170,114,244,217, 93, 6, 23, 25, 0,164,164,164,144,231, 95,153,134, 75,
+ 23, 46, 32, 55,231, 32, 66,131, 67, 49,113,194, 68,132, 69, 70,224,228,209,227, 8, 18,138, 17, 24, 24,136,230,177, 45,176,241,
+219,141,120,243,157,183, 81,237, 5,137,219,145,144,144,224,241, 61,193,193,193,168,170,170,234,207, 48, 12,219,170, 85, 43,244,
+235,215, 15,221,186,117, 67,147, 38, 77, 32, 22,139, 17, 27, 27,139,158, 61,123, 34, 44, 44, 12, 26,141,166, 77,112,112,176, 43,
+253,188,104,255,254,253, 89,235,214,173, 19,168, 84,170,119,235,144,117,234,144, 33, 67, 62, 93,189,122,245,170,232,232,232,121,
+132,144, 32, 0,111, 2,120,175, 1,121,239,204,213,104, 22, 77, 53,155, 45, 95,233,245, 79,213,145,151,242,164,236,223, 91, 94,
+122,117, 38,239,194,133, 11, 56,114,228, 8, 86,175, 94, 93, 13,224,173,251,205,179,175, 27,209,115, 22,225,171,235,185,139,120,
+ 12, 9, 46, 82,106,215,127,127,188,104, 9,128,176,190,237, 34, 47, 73,110, 93,233, 36,222,242, 34,230, 13,123, 25,243,146,251,
+ 1,213,215,128,239,231, 0, 21,197,168, 70,192, 25,155,229,229, 4, 65,248,127,246,174, 60,174,169, 43,251,127,239,203, 66, 0,
+149,197,125, 87,172,184, 87, 17,171,160, 85, 18,141, 74,181,180,181, 21,181, 50,181, 12, 90,130,157,182, 90,107,199,182,182,181,
+155,109,157, 41,106,167,139,128,173, 63,237,140,142, 10,118,113,171, 75, 48,161, 46, 32, 69,187,169, 85, 81, 84, 20, 23,148,132,
+ 45, 9,217,222,253,253,145,188, 24, 48, 36, 47, 1,171,118,242,253,124,162,121, 11, 39,247,189,119,223,253,158,115,238,185,231,
+112, 57, 66,126,249,117, 27, 6, 15, 73,192,155,175,127,133,239,190, 94,142, 61,170,223, 33,139, 29, 0,161, 48, 0,123,247, 31,
+ 5, 21, 8, 97,178, 90,121, 95,100,124, 84, 95,236, 58,114, 18, 72,255, 16, 83, 19, 38,225,225,135, 19,176,123,223, 55,176,152,
+235, 48,121,226,147, 96,172,102, 4,136,220,143,115,148,181,194,106, 91,237, 8,161,197, 10, 51, 21, 58, 98, 2, 24,198,150, 31,
+128, 33, 54, 79, 1,231, 49,104,212,253,101,104, 9, 70,160,133, 56,128,177, 89,188, 86, 10, 43, 75,192, 82, 22,102, 51,133,201,
+ 8, 48, 18, 10, 34, 32, 32, 2, 2, 43, 67, 96,180, 82, 84,234,168, 7, 87,123,253,233,100,238,108,161,128,130, 33, 12, 88, 42,
+168,103, 61, 80,226,153,108, 95,158,245, 50,250,197,246,115,108, 43,215, 42,161, 92,107, 91,193,118,112,231, 65, 96, 18,206, 1,
+232,233,209,156, 99,109,191,149,147,147,115,192, 62, 72, 13,239,217,179,103, 91, 0,181, 44,203, 6,152,205,230, 32,139,197, 98,
+161,148, 86,187,114, 5, 55,226,250, 95,242,217,103,159, 77,154, 58,117, 42,122,182,109,203,107,234,170, 41,224,130,255,134,245,
+237,235, 49,128,173,119,135, 14,178,244,244,116, 85, 66, 66, 66,245,169, 83,167, 90,157, 62,125, 26,143,201,109, 75,193,250,244,
+233,131,244,244,116, 36, 36, 36,152, 78,157, 58, 37,190,112,225, 2,104,117,181, 97, 80,191,126,110,101,190,180,100, 73, 61, 15,
+201,194,183,222,170,167, 48,121, 51,247,239,220,181,227,226,226,158,205,203,203,251, 92,161, 80, 32, 51, 51,211, 65,254,209,209,
+209,188,220,185, 0, 80,124,242,108, 81,219, 54,161, 35, 77, 38, 35,234,174,233, 33,150, 72, 32, 20, 10, 29, 30, 0, 67,109, 45,
+140, 58,157, 45,126,166,178, 18, 81,114,185,167,123,104,225, 92,252,111,191,244,188, 6,128,100,196,208,251,113,248,232,175,245,
+ 78,114,138, 11,224,141, 19, 71,115,164,151,207, 22,169, 6, 15,191,217,134,115,103, 14, 73, 43,175,151,168,154,210, 63, 56,171,
+223, 87,247, 63, 0,156,214,232, 80, 58,231, 1,208,115,191,162,221,234,163,208, 89, 40,170,147,122, 34,100,195, 57, 84,255,181,
+ 53,132, 4, 96,120, 40,160,127,123,238, 57,242,198,135,239,209,118,173,219,192,204, 90, 81,124,177, 4, 73, 79,206,196, 87,255,
+249, 15,190,251,118, 43,102, 38,205,132,177,206,136,253, 69,135, 96, 48,212, 34, 53, 57, 57, 47,215, 77,160, 93,102,102, 38,217,
+181,107,151,116,194,132, 9, 42, 87,158,128,138,138, 10,188,252,242,203,248,231, 63,255,201,235, 58, 91,183,110,141,203,151, 47,
+ 35, 44, 44, 76,152,145,145,129, 7, 30,120, 0, 81, 81, 81, 16,139,197, 96, 24, 6, 5, 5, 5,136,137,137, 1, 0, 92,190,124,
+ 25,173, 91,183,246,220,145, 41,125,159, 16,242, 45,165,244,132, 19, 89, 63, 57,122,244,232,101,115,230,204, 9,205,200,200,144,
+252,227, 31,255, 96, 0,124, 3, 96, 33,165,244, 90, 84, 84,148, 59,121,127, 39,132,108,160,148,254,236, 44,111,198,162,175,215,
+ 63, 49,105, 20,153, 52,119, 37, 20,143,244,195, 23,159,164,179,213,213,213, 41,148,210,243,238,228,221, 43, 74, 0,159,129,244,
+236,127, 15,157,123, 78,163, 51, 30,129, 45,112,171, 99,126,241,245,172, 49,125,219, 47, 22,158, 59, 28,142,255,123, 10, 8, 8,
+ 6,140, 58,128, 82,152, 5,146,107,251,143, 95,249, 18, 64,163,217,151, 54,172,255, 92, 54, 51,105,150, 10, 0,116,172, 25,103,
+ 42, 75, 1, 88,113, 95,171,158,144,201,238, 71,251, 54, 29, 80, 81,101,227,134, 74,147, 5, 87, 42,117,112, 55, 92,118,233, 22,
+139, 75,165,249,246,167, 38, 68,252, 96, 91, 12,192,174,223,204,216,189, 61, 7,215,110, 92, 70,235, 80,219, 74,130, 80,177, 8,
+247, 15,115,127, 19, 76, 16, 66,204, 90, 96,133, 0, 44, 33, 96,172, 44, 96,182,192, 42, 18, 58,200, 31,176, 45, 23, 4,117,191,
+ 42,233,177, 25,175,144,111,255,189,144, 6,137, 41,132, 34, 39, 15,131, 25,176, 80,160,206, 4, 88,141, 86, 16, 66, 64,196, 4,
+ 22, 43,160, 51, 2,179,147,255, 65, 92,165,194,180, 58, 49, 36,203,176, 32,118,247,191,189,195,194,202, 50, 96, 4,246,149, 2,
+ 0,168,128, 2,148,159, 23,192,153,252, 93,109, 31,220,121,208, 35,249, 91,173, 86, 24,141, 70, 76,157, 58,117, 64, 78, 78,206,
+ 10, 0, 67,114,114,114,118,229,228,228,236,159, 58,117,234,115,189,122,245, 50, 19, 66, 90,127,252,241,199,123, 94,121,229,149,
+ 36,141, 70,147,231,198,251,228,232,147, 11, 23, 46, 92,178,112,225, 66,236,218,181, 11,186,107,215,110, 57,161,103,219,182, 56,
+119,238, 28, 0,168,248, 36, 6,106, 44,233,143,168, 93, 59,233,103,159,125,166,162,148, 98, 88,159, 62,178,161,131, 6,169, 61,
+201, 26,212,175,159,154, 48,204,196,147, 63,254,216, 3, 64, 0,128,127,153, 3, 2, 32, 50, 26,209,187, 99, 71, 44, 88,176, 0,
+ 7, 15, 30, 92, 22, 25, 25,153, 55,176,115,103,143, 49, 10,174,242, 0,248, 26, 3,224, 12, 46, 15, 64, 76, 76,226,143, 5, 5,
+229, 7, 21, 10,133,216, 62, 77, 48, 18, 64, 62,223, 36, 64, 61, 6,247,127,205,112,229,234, 4,214, 98,237,171,171,170, 66,213,
+141,235, 32,132, 1,165, 44,234,234,234, 64, 41, 5,165, 20,231, 78,252, 14,179,201,136,251,134, 69,171,189, 24,115, 66, 1, 48,
+147,100,113,236, 36, 89, 92,189,160, 63,251, 20, 1,111,156,252,249,107,233,229,179, 69, 42, 0,232,209,189, 59,190,107,224, 5,
+104,219,109,168,236, 78, 14,198,195,190, 47, 71,209, 67,192,144,104, 57,202,255, 54, 18, 29, 62, 63,132,211, 26, 29,194,196, 4,
+ 21, 26, 45,132,132,120,244, 0,112,152, 53,107, 86,189, 51,183,109,219, 70, 39, 77,126, 8,219,183,110,199,230,205,155,241,214,
+226, 55,176, 71,157, 11,129, 80,128,206, 93, 58,199, 85, 85,185, 95,186, 28, 31, 31,175,142,143,143,119,169, 8,236,221,187, 23,
+103,206,156,169,203,204,204,236,200,167,109, 61,122,244, 64, 73, 73, 9,250,247,239,111,153, 63,127,190,120,227,198,141, 8, 9,
+ 9,193,201,147, 39,111,241,188,150,148,148,160, 7,207,231,220,128,252,159,122,224,129, 7,222,121,242,201, 39, 67,138,138,138,
+ 90,214,213,213,253, 53, 48, 48,240, 97,131,193,240, 17,165,244, 59,158,242,156,201,255,169,135,159,223,184,238,193,113, 83,200,
+ 63,148, 0,233,244, 8,222, 95,249, 26,213, 20,159, 76,161,148,102,227, 79,140,122, 10,128,228,201,204,227,154,255, 42, 78, 75,
+158,204,228,166, 52, 75,143,253, 87,241,125, 77,157, 69, 55,226,190, 54,147,194,131, 4, 15, 8,140,117,193, 22,202,212, 84,212,
+152, 10,242,207, 92,221, 93,166,209,231, 73,158,204,188,130, 85,171, 92,254, 64,173,174,173, 58,237,111,115,101, 0, 84,172,128,
+155,230, 19,224, 76,245, 21,188,249, 92, 10,244,122, 35,170, 13,182, 24, 0, 19, 19,128,177,241,238,211,236,190,177, 56,153,236,
+218, 49,204,246,114, 91, 57,215,185, 5,241,131, 8,102, 60,187, 28, 65, 65, 1,104, 21, 40,145, 1, 80, 21, 31, 59, 42,139, 29,
+232, 62, 33,136,144, 90, 96, 34, 54, 37, 0,132,192, 74,169, 77, 17,176,216,151,251, 17, 6, 66,150,133,133, 91,118,224, 65, 9,
+168, 52,132,194, 96,172,128, 88,200, 56,210,156, 89, 88,192,108,166, 48, 91, 40,106, 13,172,205,250, 7,129,153,189,233,186,119,
+ 73,176, 44, 3,134, 88, 65,172, 4,148,161, 14,247, 63,105,100,198,133,147,244,194,139, 50,178,106,213, 73,183, 22,222,239,249,
+191, 55,181,239,152, 40,165, 48, 24, 12, 24, 52,104,208,149,136,136,136, 41,231,207,159,239,189,121,243,230, 66, 0,143,230,228,
+228, 60,234,124,242,135, 31,126,168,126,229,149, 87,100, 26,141,198, 19, 65, 56,110, 72, 90, 90, 90,163, 39, 61,241,244,211, 0,
+188, 75, 12,196,101,221,107,136,225,253,250,201,162,120,144, 63,135,129,125,250,236,113,246,100,164,167,167,127,154,144,144, 96,
+ 57,117,234,148,240,194,133, 11,232,209,186,117,126,231,160,160, 92,158, 3, 81,179,191,212, 13,200,253, 90, 94, 94,158,115,140,
+199,111,118, 69,128,111,198, 64, 93, 96,199, 14, 79,156,204,221,151, 31, 26, 28,220,170, 90, 91, 9,139,197, 2,106,127, 15,180,
+215,202, 81,173,213,130, 82,202,199,250,183,189,172, 55, 99, 78, 24,251,114, 64,102,196,208,251, 49, 73, 22,231,240, 10, 21,159,
+ 63,207, 95, 9,208,255, 34,189, 84, 92,232,176,242,191,203,254, 82, 5, 0,109, 35, 70,201, 6, 71, 39,168,239,220,240, 74,111,
+ 85, 2,176, 26, 67,210,222,196, 85,150,197,224,181,133, 40,140,111,143, 1,219,175, 65, 72,128,150, 34,223,106,179, 37, 36, 36,
+144,125,234,125,116,236,248,113,216,186,229, 91,188,187,236, 67, 44,170,170, 2,101, 89,108,218,180, 5,101,101,101, 15, 3,216,
+238,209,163,234, 66, 17, 0,128, 41, 83,166,252, 12,160,134, 79, 91, 98, 99, 99,201,229,203,151,233,209,163, 71,197, 67,135, 14,
+197,184,113,227,160, 82,169,208,173, 91, 55, 24,141, 70,196,197,197,129, 82,202, 30, 61,122,148, 17,137, 68, 94,103, 4, 36,132,
+244, 15, 9, 9, 89, 49,125,250,116,209,137, 19, 39, 90, 25,141,198,198, 2, 3,249,202,139,234, 60,100,218,186, 33, 99,166,147,
+ 47,243,128,106, 3, 96, 58,183,139,213, 20,171, 26, 6, 6,222, 51,224,242, 0, 56,123, 0, 92,237,115,233, 74,117, 34,127,110,
+251,247, 11,255, 85,148, 94,184, 81,155, 15,160,163,253,229, 53, 2, 40, 3, 80, 34,121, 50,211,224,113, 46,105,240, 35,234,227,
+191,150,202,172,180,133,202,249,229,168,213, 85,219,214,253, 51, 65,248,251, 71,252, 83, 76,198, 79, 30, 72,222,155,251,176, 20,
+140, 94,229,204,133, 45, 90,132,192,106,214, 2, 84,135, 11,135,178,200,172, 25,241, 30,101,153, 33, 0, 40,181, 17, 53, 4, 16,
+ 83,187, 34, 96, 39,127, 91, 14, 64, 0, 60,167, 38,146, 83, 95, 39, 89,159,188, 69, 45,102, 13,132,246,133,189,148, 82, 88, 45,
+ 20,117,102,160,186,198, 2, 51, 40, 44,148,129, 80, 68,176,244,157, 79, 27,189,238, 57,115,108, 65, 90,235,214,158,161,196,108,
+179,254, 41, 0, 74, 9, 64,237, 22, 3, 21,128, 8, 88,176,172, 16, 47, 45,156,192,235, 30,206,121,119,142,236,252,217,243,238,
+ 8, 88, 4,219, 82, 13,119,236,196, 2,128,209,104,132, 86,171,213,134,132,132, 32, 58, 58,250,151,225,195,135, 7, 92,191,126,
+ 29,103,207,158,181, 45, 15, 99, 89,233,150, 45, 91, 84,118, 37, 64,197, 67, 9, 48, 39,198,199, 39,246, 24, 52,200,250, 64,223,
+190, 58,123, 31, 53,162,254,138, 72, 36,198,219,158,109, 15, 30, 73,129, 94,126,249,101, 25, 0, 12,235,211,231,150, 99,209,131,
+ 7, 55,137, 32, 6,245,235,247, 57,195, 48,214,147, 63,254, 24,220,190,125,251, 27, 3, 71,142, 92,119, 39, 95,126, 23,164,174,
+139,142,142,118,142,182,118,172, 99,245, 66, 9, 56, 17, 53,110,236,136,173, 95,124,185, 37,162,103,143,254, 70, 99, 29,172,102,
+ 11, 88,150, 69,203,176, 48, 84,105, 52,136,146,203,101, 60,172,127, 0,168,124,251,165,231,219, 1, 48, 21,159, 63, 47,230,230,
+255, 15, 31,253, 21,147,100,113,236,146,244, 79, 60, 37, 7,114, 32,178,163,150,158, 60,117, 82,182,111,247,119,245, 92,252, 99,
+ 39, 62, 42, 99, 90,197, 54,233,185, 54,230,238,119,189,159, 63,135, 13,251,190, 28,248,254, 57,199,246,125,223,221, 92, 2, 92,
+101,182,250,220,222,177,210,177,228,171,210,175, 30,154, 48, 57,126,231, 51, 79,205, 62,112,255,224, 65, 15,110,253,110, 27,242,
+127, 62,130,212,212,212, 29,171, 26, 49,208, 60, 40, 2,179,191,249,230,155, 47,190,249,230,155,152,248,248,120,222,141,155, 48,
+ 97,194,216, 61,123,246,236,219,190,125, 59, 34, 34, 34, 48,126,252,120,132,132,132,156,174,170,170,138, 60,126,252, 56, 74, 74,
+ 74, 24,145, 72,132, 9, 19, 38,200,189,126, 46,182,192,192,101,219,182,109,107, 52, 48,208, 75,121, 63, 17, 66, 62,248, 54,231,
+145,215, 12,157,147, 96,248,241,117,246,242,254,165, 79,249, 42,239,110, 84, 4,188,153, 2,112, 9,201,147,153, 58, 0,191,218,
+ 63, 62,225,169,167,158, 83,167,165,189, 34,203,200,124, 87,213,185,123,111, 0, 70,136, 2, 36,184,116,165, 26,113, 9,179,136,
+247,242, 30, 81,223,215, 55, 18,107,215,124, 13,176, 23, 0, 8, 97,169, 51,160,115,199, 16, 89,183, 86, 22,254, 47,191,149,133,
+144, 97, 97, 38, 66,136,168,229,166, 34, 0, 11, 64,173,224, 27, 24,230,140,212,231,223, 34, 0,176,228,213,185, 84, 36,180, 89,
+251, 22,214,230, 50,175,172,161,176, 90, 0,129,144,197,231,159,241, 83,122,158, 78,182,165, 70, 94,243,229, 41, 10, 46, 39, 60,
+ 3,176,196,230,238, 95,176,240, 97,175, 26, 89, 85, 91,165, 14,107, 31,214,212,254,197, 0,182,152, 8,131,193, 0,171,213,138,
+234,234,106, 8, 4, 2, 88,173, 86,116,232,208, 1,102,179, 25,153,153,153,170, 6,158, 0,149,167,154, 1, 81,131, 6,229, 0,
+ 64,115,100,252, 3,128,112, 66,212, 0, 16, 62,120,240,109, 49,243, 6,244,233,147,209, 20, 1,205, 25, 3,224,130,204,117,238,
+ 86, 3,120,145, 14,248,228, 35,115,102, 15, 4, 32, 56,153,151,103,174,211, 27,192, 90,173,232, 23, 29, 45,235, 24,217, 31, 61,
+ 6,247,231,247,206, 81, 50,125,247,247, 59, 28,155, 35,251, 71, 56,190,239,254,126,199, 45,219,238, 66,227, 79, 95, 9, 35, 76,
+171, 88,140,155, 72,100, 39, 78,158,197,149, 11,191,169, 0, 96,223,238,239, 84,237,187,157,149, 13, 26,241, 23,175,149,128,105,
+211,166,193,219,244,190, 86,226, 62,239,118,233,148, 14,248,254,114,221,109, 31,240,103,205,154,245, 61, 0,166,168,168,136,205,
+ 45,200, 67,235, 54,173,209,148,250, 28,241,241,241, 95,198,199,199,127, 5,207,233,157,235,161,101,203,150,170, 39,158,120,130,
+228,231,231,211,179,103,207,162,176,176, 16, 53, 53, 53,145,205, 81, 11,192, 78,218,255, 36,132,136,242,243,243, 7,153, 76,166,
+215, 41,165,155,154,244, 2, 83,186,152, 16, 34, 10,233,245,213,130,170,179,123,146,154, 42,239, 78,131, 91, 5,224,106,191, 79,
+ 10,128,183, 83, 9,141,186,170, 30,127, 90,189, 99,247, 25,242,216,228, 32,218,174,115, 87,104,106, 44,136,155,252,148,207, 29,
+ 33,246,129,190, 36,246,129,215,160, 80,188, 73,129,107, 8,107, 41, 68,183,112,214,171,151,126,216, 95, 23,222,182, 2, 54,111,
+127,176,138, 0,192,188,249,207, 81,147,193, 12, 22,182,101,115, 43, 62, 91,225,211,111,166,204,182,213, 12, 88,243,197, 73,202,
+ 82, 1, 94,125,229,209, 59, 89,221, 76,236,236,198, 54, 26,141, 48,153, 76, 14, 34,227, 8,204, 95, 37,208, 61,188, 73, 63,236,
+ 35, 76,139, 22, 37, 6,216, 61, 40,214, 38,202,162, 0, 44,125,227,226,234,181,185, 71,199, 14,188, 5, 4,176, 70,245,211, 9,
+ 94, 27,126,104, 88, 10,184,158,253,221, 42, 70, 61, 96,120, 12, 6, 12, 71,147,239,165,167,194, 62, 13,117, 96, 11, 9,128,129,
+113,191, 34,245,108,141, 5,145, 45,249, 12,145,205,210, 21,232,176, 97,195,154,179, 79,249,156, 1, 39, 54, 54,150,120, 74,196,
+214, 4,210,190, 37, 48,176,137,242,110, 9, 12,188,215,149, 0, 62, 32, 67,134, 12,161,240,195,143, 38,162,119,239,222, 40, 46,
+ 46,246,223, 8, 63,252,240,195,143,123, 4,140,255, 22,248,209, 28,240,147,191, 31,126,248,225,135, 95, 1,240,195, 15, 63,252,
+240,195, 15, 63,252, 10,128, 31,126,248,225,135, 31,126,248,225, 87, 0,252,240,195, 15, 63,252,240,195,143, 59,142,122,161,169,
+115,231,206,245, 57,122,212, 85, 38, 59,191, 60,191, 60,191,188,187, 67,158, 66,161,160,153,153,141, 47, 59,245,223, 63,191,188,
+187, 77,222, 79, 63,253,228,179,188,168,168,168,255,121,121, 94, 43, 0,220, 64,225,173, 16,119, 3, 75,115,203,243,227,238,132,
+ 39,130,241,227,238,124, 14, 94,158, 31, 12,224,129, 3, 7, 14, 44, 21, 8, 4, 35, 3, 2, 2,160,215,235, 15, 61,248,224,131,
+139, 1, 20, 2,208,223, 13,247, 64,169, 84, 74,179,179,179, 85,127,198,113,229,216,177, 99, 40, 44, 44,244,120, 94, 65, 65, 1,
+ 61,118,236, 24,178,178,178,200,192,129, 3,155, 44,143,195,240,225,195,225, 78,158, 31,247,176, 7,128,131, 55,233, 73,249, 36,
+202,113, 37,175,177,242,176,190, 36,222,249,179, 15,232,124,207,157, 56,113,162,236,241,199, 31, 87,243,149,217,185,243,173,165,
+151,203,202,202,234,109, 39, 38, 38, 66, 46,151, 19, 62,242,110,167, 18, 48,113,226, 68, 10, 0,187,119,239, 38,119,131, 60,157,
+ 78, 55,110,203,150, 45,202,211,167, 79, 3, 0, 34, 34, 34, 30, 73, 73, 73,217,230,235,243,117,238,247,148, 82,199,251,193,237,
+231,222, 21, 66, 8, 50, 50, 50,136, 59,229,153,239,115,240,242,121,245, 63,118,236,216,150,234,234,234,190,221,187,119,199,141,
+ 27, 55, 80, 87, 87, 7, 0, 35,183,108,217,162, 10, 14, 14, 62, 25, 31, 31,255, 24, 0,183,165, 36, 71,141, 26,229,149, 65,112,
+240,224, 65, 25,120,166,122,230,144,157,157,173, 74, 76, 76,148,201,229,114,181,183,207, 35, 53, 53,213,171,246, 77,155, 54,141,
+247,251,193,161,123,119, 91, 5,220,154,154, 26, 24,141, 70,174, 63,241,122,223, 10, 11, 11,241,239,127,187,207, 80,107, 52, 26,
+233,200,145, 35,209,175, 95, 63,172, 95,191,190,220,104, 52,118,107,108, 93,120, 97, 97, 33,146,146,146,120, 93,235,181,107,215,
+176,116,233, 82,100,102,102,250, 7,230,123, 0, 13,147, 1,221,206, 68, 64,126, 43,246, 54,226,187, 12,207, 41,141, 31,155,187,
+203, 43,153, 42,213, 77, 3,233,244,233,211, 8, 14, 14,118, 12, 66, 78,247,131,143,181, 69, 27,110, 55, 28,192,148, 74, 37,205,
+206,206,246,217, 2,219,176, 97,131,116,226,196,137,141,202,111, 10,210,210,210,232,152, 49, 99,100, 51,103,206,244,138, 44,182,
+108,217,162,108,215,174, 29,102,205,154, 5,173, 86,203,166,167,167,111,213,106,181, 51,194,194,194,188,202, 34, 70, 8,193,247,
+223,127,239,216,142,143,143,199,174, 93,187,220,110,123, 66, 67, 37, 64,161, 80,208,232,232,104,100,101,101, 81, 46, 49,147,183,
+228, 95, 85, 85,149,223,171, 87,175, 86, 0, 32,145, 72, 16, 24, 24,136,242,242,114, 84, 86, 86, 34, 36, 36, 4,229,229,229,125,
+119,237,218, 85, 24, 31, 31,223, 7,192, 85,119,194, 6, 14, 28,136,196,196, 68, 68, 68,220,204,250,183,108,217,178,122,231, 44,
+ 90,180,136,179,100, 85, 51,103,206,244,250,121,251, 66,254, 28, 86,174, 92,217,216,161, 70, 43, 88,242, 69,112,112, 48, 78,156,
+ 56, 1,145, 72, 4,147,201,132, 93,187,118,161,184,184, 24,175,190,234, 93,197,217,107, 13,138,100, 61,242,200, 35, 2, 0,242,
+ 31,126,248, 97, 87, 92, 92,220,181,199, 30,123,172,189, 82,169,132, 64, 32,104, 27, 26, 26, 42,240, 70, 86, 99, 56,127,254,188,
+159, 36,238, 81,242,231,246,121,172, 5,112,175, 98,205,154, 53,210,148,148, 20,117, 83,229,220, 43,174,236,206,195,222,187,105,
+181, 23,189,238,147, 12,173, 86, 11,189, 94,239,176, 64,178,178,178,156, 45, 33,190,214,214, 45,219,114,185, 28,123,247,238,165,
+132,144, 91,142,251,130, 31,126,248, 65,245,242,203, 47, 35, 39, 39, 7, 83,167, 78,109,150,251,183,123,247,110,146,155,155, 75,
+ 41,165,200,203,203, 83,229,229,229,121,165,160,156, 62,125, 26,179,102,205, 98, 1, 48, 98,177,152,137,140,140, 68,122,122,250,
+ 70, 0, 27, 35, 34, 34, 38,167,164,164,236,228, 35,231,118, 20, 3,226,148,128,172,172, 44,202,165, 1,230,254, 87, 40, 20, 52,
+ 49, 49,209,155,107, 13,214,106,181, 91, 36, 18, 73, 43, 0,248,219,223,254,134,186,186, 58,100,100,100, 32, 48, 48, 16,117,117,
+117, 48, 24, 12, 16, 8, 4,168,170,170,106, 5, 32, 29,192, 95,220, 9,228,200,189,164,164,228,150,125,205,129,196,196, 68,153,
+253, 58,101,190, 42, 2, 47,190,248,162,227,251,138, 21, 43,184,175, 76,131,253,188, 21, 2,206,107,242,250,235,175, 35, 56, 56,
+ 24, 57, 57, 57,136,139,139,243,137,252, 27, 98,244,232,209,128, 45, 75,227, 95,159,122,234, 41,244,238,221,187,253,174, 93,187,
+ 80, 81, 81,193,149,220, 53,121,120, 23,154,187,251, 73, 39, 79,158,172,218,177, 99,135, 43,239,141,116,236,216,177, 42, 66, 8,
+114,115,115,253,238,222,219, 76,254,169,139, 62, 4, 0,100, 45,123,197,165, 18,240,135, 40, 0, 89, 89, 89,174, 30, 52,109,108,
+191, 47,191,113,248,240, 97, 21, 0, 89, 83,149,128,164,164,164,255,153,249,108,189, 94,127,139,213,239, 11,209,112,196, 50,117,
+234, 84,140, 31, 63,158, 0, 64, 78, 78, 78,179,180,113,195,134, 13, 82,187, 69, 71,202,203,203,165,217,217,217,170,242,242,114,
+169,183, 22,187, 43,140, 27, 55,142,140, 27, 55, 14, 27, 54,108,144,230,229,229,169, 54,108,216,224,149, 92,173, 86,107, 9, 11,
+ 11, 19,111,217,178, 5,118,111, 64,157, 86,171,101,210,211,211,119,104,181,218, 9, 97, 97, 97,123,239,228,243,229, 72,223,185,
+ 47, 43, 20, 10,202, 41,105, 60,241, 64,113,113,113,223, 65,131, 6, 97,246,236,217,168,170,170, 66, 69, 69, 5, 68, 34, 17,132,
+ 66, 33,132, 66, 33, 68, 34, 17, 2, 3, 3,161,209,104,160, 84, 42,103,202,229,242,231, 61, 9, 45, 41, 41,169,167, 28,114, 10,
+ 0,231, 9,136,142,142,246,166,141,174,172,127, 89,118,118,182,170, 41,158, 39, 39, 88, 26, 25, 43,121,123, 3,206,159, 63,143,
+188,188, 60, 76,158, 60, 25,221,187,119, 71,155, 54,109,144,151,151,135, 87, 95,125,213,225,125, 19, 8, 4, 94, 55,108,244,232,
+209, 88,188,120, 49,150, 46, 93,218, 49, 37, 37,101,250,147, 79, 62,137,241,227,199, 3, 0, 4, 2,193,172,214,173, 91,111,203,
+204,204, 52,187, 43, 6,180, 97,195, 6, 94, 94,128,178,178, 50,204,152, 49,131,159,129,210,185, 51, 82, 83, 83, 85, 37, 37, 37,
+ 80, 42,149,220,253,151,166,166,166,170, 56, 5,218,143,219, 11,142,252,185,239,156, 18,240,135,123, 0, 26,155,199,246, 37, 64,
+240,118, 43, 1,147, 38, 77,106,178, 39,192,155,235,242,230, 55,158,120,110, 55,182,124, 58,177, 89,238, 21,247, 2, 42, 20, 10,
+151,115,122,135, 14, 29,106,178, 98,208, 28,207,247,135, 31,126, 80,113, 86,255,204,153, 51,213, 63,252,240, 3,218,181,107,167,
+ 66, 51, 37, 78,231,228,230,229,229, 33, 47, 47,207,163,187, 89,167,211, 77,218,178,101,203, 14, 0, 72, 79, 79, 23, 71, 68, 68,
+ 32, 37, 37,133, 59, 44,249,245, 87, 91,189,172,244,244,244, 61, 17, 17, 17,143,165,164,164,120,172, 79, 30, 31, 31, 95, 47, 38,
+230,161,135, 30,170,231, 25,224,227,246,119,161,116, 83, 87,253,139,123, 46,206,211, 1,238,176,107,215,174,165,145,145,145, 0,
+128, 51,103,206,128, 82,138, 83,167, 78, 57,234, 62, 8,133, 66, 16, 66, 96,181, 90,161,215,235,241,205, 55,223, 64, 46,151,123,
+172,186,228, 76,254,137,137,137, 46,149, 23,231, 41, 2, 95,148, 0,185, 92, 78, 20, 10, 5,109,170, 55,160, 57,198, 73,179,217,
+140,161, 67,135, 66,173, 86, 99,216,176, 97,208,233,116,142,169, 29,181, 90,141,137, 19, 39,194,194,149, 32,247,206,242,199,210,
+165, 75, 59,165,164,164, 92,250,242,203, 47, 29,199, 58,117,234,132,229,203,151,255,155, 47, 97, 55, 51,212, 71,142, 28, 65,116,
+116, 52, 34, 34, 34, 48,116,232, 80,122,244,232, 81, 25, 71,254, 37, 37, 37, 80,171,213,126,235,255, 46,192, 31,162, 0,252,145,
+ 65,128,205,161, 4,244,232,209,163, 73,158, 0,110,144, 93,191,126,189,203,227, 59,119,238,196,250,245,235,125,178, 76, 10,206,
+245, 71, 76,207, 19, 62,187,253, 57, 56,207,249, 43,149, 74,200,229,114,135,219,255,208,161, 67,232,218,181,107,179, 40,125, 77,
+177,190, 56,235,255,198,141, 27,142, 58,243, 82,169, 84,214,156, 94, 0, 14,113,113,113,178,188,188, 60,149,167,243,182,108,217,
+178,131,155,251,215,233,116, 88,182,108, 25,106,107,107, 33, 18,137, 16, 16, 16,128,115,231,206,225,189,247,222,131, 86,171, 69,
+122,122,250,183, 90,173,118,108, 88, 88,152,202, 3,201,214, 35,123, 79, 49, 1,205,161,120, 30, 57,114,164,222,249,141, 5,137,
+133,135,135,143, 52, 26,141,176, 88, 44, 56,116,232, 16, 4, 2, 1, 76, 38, 19, 12, 6, 3, 88,150,117,188,199,102,179, 25, 70,
+163,145,123,167, 61,134,137, 55,230,242, 95,180,104,145,195, 11, 16, 17, 17,129,242,242,242, 38, 43,162,220,170, 0, 47, 98, 71,
+ 52, 0,194, 93, 29,112,154, 14,240, 10,233,233,233,120,249,229,151, 17, 21, 21,229,240,128,112,233,179,163,162,162,112,234,212,
+ 41,180,107,215,206, 43,153,251,247,239,199,232,209,163,187,167,164,164,156,231,200,223, 62,126,118,222,180,105,211,229,134, 1,
+189,124, 21,138,198,126,203, 75,239, 19, 57,114,228,136, 52, 53, 53, 85, 53,108,216, 48, 12, 27, 54, 76, 5, 0,167, 78,157, 66,
+ 94, 94,158,159,252,111, 35,184,106,128, 89,203, 94,185,101, 10,224, 79, 27, 3,112, 55, 42, 1, 73, 73, 73,116,241,226,197,183,
+184, 2,125, 33,255, 39,158,107,222,121, 58,157, 78,119, 75,144, 31,103,245,139, 68, 34, 92,189,122,245,142,146,191,179,245,239,
+108,185,205,152, 49, 67,173, 86,171,155,221, 11,224,141,231,100,214,172, 89,122, 0, 65,193,193,193,120,227,141, 55, 32, 18,137,
+ 28,199,147,147,147, 1, 0, 97, 97, 97, 72, 72, 72,192,129, 3, 7,246, 37, 36, 36,252, 33,237,116,190,223,206,243,255,174, 16,
+ 29, 29, 93,175, 82,163,171,117,216, 0, 96, 50,153,160,209,104, 80, 87, 87,135,144,144, 16, 4, 4, 4,192, 98,177,128, 82, 10,
+171,213, 10,147,201, 4,179,217, 12,171,213,234,172,208,223,112,215,206,146,146,146,122,214,125,195,233,128,134, 1,130, 77,133,
+ 92, 46, 87,123, 25,139, 34,105,236, 64, 35,177, 1, 30,241,222,123,239, 97,242,228,201,232,209,163, 7,130,130,130, 32,149, 74,
+161,209,104, 16, 28, 28, 12,173, 86,139,181,107,215,130, 97,188,139, 47, 28, 61,122,116,151,148,148,148,243,243,231,207,199,214,
+173, 91,241,232,163,143, 2, 64,135,253,251,247, 95,243,229, 62,217, 21, 10,112, 99, 22, 55, 86,121, 75,254,206,158,128, 77,155,
+ 54,201,166, 79,159,174, 2,128, 77,155, 54,201,170,170,170,212,240,227, 15,131, 43,183,191, 51,254,148,153, 0, 71,140, 24, 33,
+107,142,128, 64, 95,173,116,231, 1,121,233,210,165, 77, 38,127, 14, 67,163,134, 32,119,159, 10, 27,246, 5, 57,148,130,130,115,
+253,155,116,141,209,209,209, 40, 41, 41, 65, 78, 78, 14,186,118,237,138,117,235,214,249, 96,117, 81, 41,247, 45, 45, 45,173, 89,
+200,159,179,254,203,203,203,101, 13,143,141, 25, 51, 70,150,147,147,227, 56,167, 57,144,151,151,167,226,235,125,210,106,181,191,
+195, 54, 47,204,110,218,180, 9,107,215,174, 5, 0,108,220,184, 17, 90,173,150, 59,205,114,234,212, 41,180,109,219,246,142,188,
+ 3,206,209,254,174,148, 51,190,101,154, 75, 74, 74, 14, 89,173, 86,104,181, 90,220,184,113,195, 17, 56,170,215,235, 81, 91, 91,
+139,234,234,106, 84, 85, 85,193, 96, 48,192,104, 52,194,106,181, 2, 64,190, 59,153, 13,201,221, 85, 32,105,195, 85, 1,124,161,
+ 84, 42,165, 13,175, 89,169, 84,122,219, 79,130,154,251,121,172, 91,183, 14, 82,169, 20, 65, 65, 65, 56,113,226, 4,212,106, 53,
+130,131,131,241,230,155,111,226,192,129, 3,120,245,213, 87,189, 82, 0, 70,143, 30,221, 33, 37, 37,229,226,140, 25, 51,240,245,
+215, 95,115,228,223, 9,192, 53,119,150, 60, 31, 37, 96,233,210,165,205, 65,254, 0, 32,229,200, 31, 0,166, 79,159,174,138,139,
+139,243, 87,159,253, 35,199,129, 69, 31,214,139, 5,104,136, 63, 77, 16, 96,115,147,191,125,189,107,147, 45, 55,110, 58, 32, 41,
+ 41,201,103,242,127,226,185,221, 24, 26,117,211,117,179,229,235,111,176,229,107,219,247,220,125, 42, 96,172, 12,128,119,203, 0,
+ 21, 10, 5,162,163,163, 1,216,130, 1,143, 28, 57,130,189,123,109, 49,107,191,253,246, 27,226,226,226,188,144, 70,212,192,205,
+192,191,166, 70,234,111,216,176, 65,234,202,250,111,136,230,242, 2,112,138,132, 84, 42,149,121, 58, 55, 34, 34, 98, 66,122,122,
+250,158,132,132, 4,156, 58,117, 10,167, 79,159,198,123,239,189,103, 1, 32,212,235,245, 72, 79, 79,135,253,152,240,194,133, 11,
+120,234,169,167, 60,202,188, 29, 49, 0,156, 37,157,157,157,237,240, 98,113,196,200, 61,119, 62,136,140,140, 44,210,235,245, 35,
+ 77, 38, 19,174, 95,191,142,128,128, 0, 8,133, 66,135, 7, 64,167,211, 65,175,215,195,104, 52,162,170,170,138,155,207,191,228,
+ 78, 38, 71,238,220, 52, 64,116,116, 52, 26,122, 43, 92,197, 5,240, 33,127, 46, 7, 64,195,125, 77,233, 31,156,213,239,194,226,
+183,240, 29, 67,139,139,139,113,234,212, 41,232,245,122,196,198,198, 66,175,215, 35, 59, 59, 27,211,167, 79,199,214,173, 91, 33,
+ 16, 8,120, 43, 0,145,145,145, 93, 56,242, 47, 44, 44,196, 91,111,189, 5, 0,221,146,146,146,174,172, 95,191,158,236,223,191,
+191, 73, 99, 40,231, 9,104, 10,249, 71, 71, 71, 83,174,159, 29, 61,122, 20, 69, 69, 69,178,212,212, 84, 85,159,220, 12, 96, 18,
+ 0, 0, 32, 0, 73, 68, 65, 84, 62,125, 32, 18,137,168, 83, 96,160, 31,205, 12,110, 21,128,171, 32,192, 59,178, 10,224,143, 10,
+ 2,188,219,200,191,161, 18,208, 20,203,223,221,118,238, 62,149, 47, 47,232, 77,115, 39, 40, 8,253,250,245,171,119,252,240,225,
+195, 94,201,155, 58,117,170, 67, 1,200,201,201, 65, 78, 78, 78,189, 85, 1,222, 92,255,186,117,235, 84, 0,176,107,215, 46,151,
+228, 57,115,230, 76,245,186,117,235, 0,240, 91,194,212, 88,210, 31, 78,209,160,148, 34, 46, 46, 78, 54, 99,198, 12,143,125, 39,
+ 37, 37,101,175, 70,163, 25,119,240,224,193,220,200,200, 72,156, 62,125, 26, 90,173, 86, 24, 22, 22,134,148,148, 20,104, 52,154,
+ 11, 7, 15, 30,236, 30, 25, 25,137, 89,179,102,121,188, 94, 87,121, 0,124,141, 1,104,248,110,101,102,102, 18,185, 92, 14,165,
+ 82, 73, 27, 78,203,240,125, 30, 49, 49, 49,175,169,213,234, 23,172, 86, 43,170,171,171, 97, 54,155, 29,202, 74, 93, 93, 29, 40,
+165,245, 2, 3,229,114,249,147,118, 98,228, 13,185, 92, 14,185, 92, 94,111, 89,160,183, 83, 0,206, 68, 47,151,203,213, 13,199,
+ 22,103,165,160, 25,193,123,252,228,150,250,189,244,210, 75, 80,171,213,144,201,100, 40, 46, 46, 70,139, 22, 45, 80, 90, 90,202,
+ 91, 1, 56,124,248, 48, 73, 73, 73,185,248,212, 83, 79, 97,255,254,253,120,243,205, 55, 1,160,115, 82, 82,210,229,230, 32,127,
+103, 37,160, 41,150, 63, 55,190,148,148,148,160,168,168,136,216, 13, 65, 89,106,106,170, 42, 34, 34, 2, 82,169,148,250, 3, 1,
+239, 60,132,141, 13, 74,205, 9, 87, 1, 63,203,150, 45,107,116,255,157, 36,255,164,164,164,219,146, 50,180, 41, 50, 47, 94,242,
+ 60, 31, 31, 24,232,157,215,210,221,252,176, 47,144,203,229,178,241,227,199,171,115,115,115,233,230,205,155,235, 41, 2, 13, 73,
+137,175,204,180,180,180, 70, 53, 27, 46, 41,137, 55,137,129, 26, 83, 56,101, 50, 25, 47,242,231, 16, 30, 30,238,152,215, 63,113,
+226,196, 95,210,211,211,255,205,121, 4, 46, 92,184,208,253,245,215, 95,151, 17, 66,120,201,187, 29,121, 0, 26,222,103, 87,243,
+223, 94, 40,165,186,184,184,184, 37, 59,119,238,124,219, 98,177,160,178,178,210, 17, 3, 0, 0,215,175, 95, 71,101,101, 37, 40,
+165,156,213,238,213,100, 59, 55,255,223,112,217, 95,195, 56, 1,190,228,239,252,156,239,182,165,188,156, 18,240,202, 43,175, 32,
+ 47, 47, 15, 9, 9, 9,248,224,131, 15,176,112,225, 66, 8,133, 66, 72, 36, 18, 79,207,149, 80, 74,217,217,179,103,227,223,255,
+254, 55,214,172, 89, 3, 0, 93,247,239,223,127,217,110,177,251,212,153,156,166,173,154, 13,101,101,101,112,145, 7, 64,157,149,
+149, 37, 27, 59,118,172,202,151, 37,143,126,120, 7, 87, 65,128,188, 20, 0,111,146,114,248, 74,216,205,141,230, 32,255,187,113,
+208,152, 55,111,158,236,228,201,147,205, 42,211,110, 13,169,154, 83, 38, 71,120,220,218,122, 0,142,100, 64, 44,203, 98,203,150,
+ 45,188,149,128,151, 95,126,153,107,231, 45, 49, 0, 12,195,128,101, 89,252,253,239,127, 87,241, 37, 79,119,242,154,186,146, 32,
+ 37, 37,229, 63, 26,141,230,250,193,131, 7,119,241,181,250,111,183,183,173,225,253,117,229, 98,247, 70, 9, 32,132,188, 51,121,
+242,228,156,245,235,215, 31, 23,139,197,224, 86, 5,176, 44,139,208,208, 80,104,181, 90, 46,133,109, 16, 0, 43, 95,131,192, 57,
+248,239,200,145, 35,144,203,229,245,198, 19, 79,227, 80, 73, 73, 9, 45, 41, 41,145, 53,116,241, 55,113,201, 31,128, 70,221,253,
+150, 21, 43, 86, 72, 0,152, 96,139,159,226, 62, 94, 41, 1,206,137,127,158,125,246, 89,199,247,234,234,106,143,175, 89, 76, 76,
+ 12, 25, 48, 96, 0,253,234,171,175, 30,219,184,113,227,119, 28,217,110,220,184, 17,222, 70,253,115,184,124,249,178, 35, 37,113,
+ 51, 65,189, 99,199,142,198,250,148,122,223,190,125,126,203,255, 54,130, 91, 5,224,138,248,121,173, 2,104,110, 82,111, 76,222,
+221,162, 60,220,173,228, 15, 0,253,251,247, 87,247,239,223,191, 89,101,218, 7,199,219,126,173,206,238,255,134, 36,213,216,178,
+ 51,123,251,248,180,141,120,113,189,183,245, 90,195,195,195,119, 55, 37,210,191, 57, 99, 0, 92,245, 97,119,222, 30, 47,250,252,
+137,164,164,164, 22,123,246,236,121,191,180,180,244, 5,131,193, 0,171,213,138, 33, 67,134, 96,216,176, 97,233,114,185,124, 17,
+ 31,242, 7,128,130,130, 2,199,119,231, 88,147,130,130,130, 91,182,221, 33, 34, 34,130,216,189, 4, 50, 0, 42, 78,153,112,154,
+ 10,240,250,153, 76,155, 54,173,177, 67, 66,167,241, 82,124, 39,198,149,204,204, 76,246,216,177, 99,248,228,147, 79, 8, 0, 94,
+ 73,121,158,127,222,125, 78,166,225,195,135, 99,202,148, 41,188,219,224, 73,158, 31,119,159, 18,208, 24,249,187, 84, 0,154,155,
+ 4,253, 21,226,252,112,213, 7, 26, 91,118,230,191, 55,119,245,111,232, 38, 76,152, 48, 15,192, 60, 95, 5, 28, 60,120,144,204,
+156, 57,243,182, 40,180,190,102, 14,252, 35,149,197,166, 98,224,192,129,205, 90,140,167,185,229,249,113,119, 41, 1, 30,173,168,
+ 33, 67,134,248, 7, 98, 63,252,240,195, 15, 63,252,248, 31, 3,227,191, 5,126,248,225,135, 31,126,248,225, 87, 0,252,240,195,
+ 15, 63,252,240,195, 15,191, 2,224,135, 31,126,248,225,199, 61, 8, 11, 0,214,127, 27,252,112, 7,161,255, 22,248,225,135, 31,
+126,248,199,118, 63,254,199, 59,201,220,185,115,125,142,128,117, 21,213,237, 78,158,167,245,199,222,202,107,238,246,249,229,249,
+229,253,175,203,251,233,181, 11, 62, 15, 44, 81,239,119,199,237,150,119,228, 85,223,229, 69,127,112,171,188,180,180, 52, 2, 0,
+132, 16,169,217,108,198,185,115,231, 84, 38,147, 9, 66,161, 16,151, 46, 93,194,147, 33, 61,176,187,168, 8,134,251,187, 34, 38,
+ 38, 70, 38, 16, 8, 64, 41, 85, 3, 64, 70, 70,198,109,127, 30, 92,251,156, 65, 8,233, 15,160,221,241,227,199,119,116,234,212,
+137,209,104, 52,146, 78,157, 58,189, 23, 24, 24,184, 10,192,101,251,114, 82, 38, 35, 35,195,234, 70, 94, 75,187,183, 64, 79, 8,
+161, 0,112,241,216,127, 86, 43, 70,151,166,108, 40,138, 60, 39,108, 55, 33,166, 69,203, 86,181, 0, 40,165, 84, 8, 32, 44, 35,
+ 35,227,226,109,239,127, 63,253,228,179,188,168,168,168,255,121,121,183, 85, 75,228,155,109,203,219,236,111,190,164,204,173, 92,
+251,181, 84, 24, 30,162, 58,123,250,140,236,190,128, 22, 8,126, 62, 73,125, 55,105, 89,141,229, 35,247, 47,145,188,243,216,186,
+117,171,116,231,206,157,170,244,215,108,219,223,238, 31,141,164,164, 36, 94,207,101,127,254, 33, 41, 67,136,234,212,201,147,208,
+106,181,232,222,189, 59, 90,180,108,137,248,241, 19,120, 63,215,189,123,247,214,123,113,115,114,114,220,214, 82,200,201,201,241,
+185,223,112,133,154, 50, 50, 50,154,214,239, 18, 53,246, 47, 20, 0, 1,178,195,125,151, 21,189, 2,136,120,218,246,189,100, 45,
+112,100, 65,211, 31,234,212, 27,245,219,151,211,134,215,159, 17, 66,168, 78,167,147,237,217,179, 71, 85, 82, 82,130, 68, 81,107,
+116,232,218, 22,117, 58, 3, 2,245, 22,140, 90,248, 12,198, 36, 76,199,246, 47, 51,176, 45, 55, 87, 53, 97,194, 4,217, 93,208,
+133, 79, 91,173,214,142, 37, 37, 37,236,224,193,131,197,145,145,145, 56,122,244,232,107,117,117,117,147,123,247,238, 45, 39,132,
+104, 40,165,158,166, 2,106,156, 55, 44, 22, 11,243, 75,209, 79,189,187,204,142,194,223,135, 15,104, 91,176,231,163,205, 91,126,
+147,254,220,123,224,216, 15,236,242, 46,217, 21, 6,214,239,105,248, 31,115, 19,121,155,191,223,155, 60,248,222,146,191,117,195,
+ 14,105,108,219, 46, 42,210, 57, 2,197,181,149,232,216,169,135,202,204, 90,113,242,211,117, 40,239,222, 86, 54, 60, 97, 18, 47,
+ 69,224,136, 74, 65,251,246,226,182, 4,248,102, 15,139,253, 63, 82,164,206, 0,250,246, 2, 22, 44,109, 26,113,115, 5, 74,154,
+154,157,204,149, 50,209, 92,114,155,130,212,212, 84,138, 37, 4,228,157,198,207,161,148, 2, 75, 8,166,253,158,120,215,172,181,
+190, 73,254,212, 78,254, 99,112,224,192, 1, 36, 37, 37,121,252,219,251, 7,239,161,253,251, 15, 67,118,246, 21, 28,206,183, 37,
+172, 57,125,242, 20, 0, 96,206, 95,191,166,167,206, 76,149, 5, 75,248, 61,151,241,227,199,179,123,247,238,101,114,114,114,176,
+111,223, 62,183,133,152,124, 77,161,218,216,123,155,166, 80,208, 12, 31, 20, 10, 46, 93,120,147, 83, 25, 71, 60, 93,191,216, 78,
+115, 40, 0, 78,247,201, 94,157,144, 23,206,158, 61, 11,245,230,205,170,119,228,211, 48, 36,233, 89,136,219,135, 1, 66,123,178,
+ 63,150, 2,172, 8,172,145, 98,210,211,169, 40,253,215,135, 56,116,232,144,106,228,200,145, 50,206, 11,112,135, 96,101, 24,166,
+ 93,155, 54,109,160, 86,171,133,131, 7, 15,198,240,225,195,153,171, 87,175, 70,253,242,203, 47,199,238,191,255,254,161,132,144,
+171,118,178,102,120,222,187, 22,227,198,142,143,248, 96,249, 86,102, 81,242,111,173, 98,226,231,202, 98, 70, 40, 71, 47,252,228,
+210,195,145, 15,204,138, 38,132,212,192, 22, 99,192, 52,214,207,156, 19, 91,121,234, 71, 77, 86, 72,253,168,135,134, 9,128, 26,
+194,167, 98, 64,206, 3,200,144, 89,131, 48,119,212,115, 12,120, 86,238,107,168, 4, 40, 20, 10, 26, 29, 29,141,172,172, 44,234,
+ 92,182,212, 43, 98,205, 59, 34,157, 25, 21,171, 18, 91, 89, 88, 65, 17, 88, 25,132,171,215,175,227,106, 77, 21,122, 6,180,128,
+177,248,178,234,240,182,157,178, 17, 60,148,128,190,189,128,147,103, 25, 80, 42,129,149, 4,224,177,241,102, 76,153, 96,192,205,
+ 24,154,166,167, 74,104, 42, 73,115,196,191,104,209, 34, 20, 21, 21, 1, 0,118,156, 20,161,206,108, 86, 41,254, 58,204, 43, 69,
+192, 27, 37,206,158,226,213,253,115, 89, 98, 59, 28, 29, 29,221,120,254,246, 37,190,189,227,219, 63,191, 34,221,246,203, 91, 14,
+133,103,242,160, 37,178, 71,158,235,212,228, 1,119,235,214,173,210, 29, 59,118,168, 24,134,193, 75,239,195, 81,253,140, 79, 29,
+140,176,176, 31,164, 49, 35,210, 0,108,195,232,209,255,170,119,108,230, 76, 96,210, 36, 96, 18,114, 84, 43,254, 5, 94, 74, 0,
+ 71,254,106,181,237,212,233,211,167, 59, 10, 43,121, 67, 96,238, 44,127, 46, 37,179,243,245,165,165,249, 70,254,205,134,232,229,
+ 0,128,149, 43, 87,222, 84, 0,134,166, 3, 71, 95,186, 35,205,217,183,111, 31, 86, 77, 73, 69,207,177,227, 1,129, 17, 68,196,
+128, 8, 25, 16,129, 8,148, 18,176, 58, 11,168,213, 10,106,178,226,153,167,159,197,179,111,206,195,217,246,237, 85,189,122,245,
+186,147,158, 0, 82, 84, 84, 20,219,181,107, 87,113, 73, 73, 9,242,242,242,112,242,228, 73,140, 31, 63, 30,177,177,177, 29,215,
+172, 89,243,238,180,105,211,158,241, 66, 1, 16, 28,200,253,239,255, 61, 62, 68,223,254, 72,141, 0, 51,151,212,226,193,168,143,
+241,220,252,233,194,143, 22, 85,246, 92,244,209,250,153, 17, 81, 51, 51,209, 72, 26,100,103, 66,119, 30,211,211,210,210,168,171,
+253,205, 93, 16,206,143,219,224, 1,112,126, 72, 27,118,173,175,236,117, 95,175, 80,197, 59,207,176,115, 71, 61,199,123,240,200,
+204,204, 36, 89, 89, 89,148, 75, 75,202,253,175, 80, 40,104, 98, 98,162,119, 86,245,174, 67,210,137,145, 3, 84,226, 58, 11, 2,
+ 63,122, 25, 22,189, 9,146,151,150, 34, 68, 44, 65,157,200, 0, 93,157, 1,129, 32, 48, 94, 44, 87, 85, 85, 85,201, 66, 66, 66,
+220, 14,194, 39,207, 2, 89, 27, 89, 0,122,251, 7, 24,253, 0,131, 41, 19, 8,156, 3,105, 83,103, 0, 89, 27,125,240,152, 38,
+ 38,202,236,215,233,147,181,206,145, 63, 71,252, 0,144,121,192, 12,131, 73, 7, 0, 24,183,104, 47,178,151,141, 87, 1,224, 45,
+255,236,135,103, 33, 34,197, 55, 59, 2, 41, 3,105,211,215,105,187, 28,109,255,202, 47, 69, 40,121,199, 70,254,238,106,204, 19,
+ 69, 54,181,157,195,207,250, 63,186,195, 44,205,218,250,188,138,130,226,131,249,223, 98,132, 52, 18, 27, 62,223,143, 47,246,164,
+169,118, 40, 40,230,254,229, 45,217,144,209, 29,125, 82, 4,106, 47, 40,232,216,193, 64,246, 87,199, 65, 41, 69,203,118,247, 59,
+200,127,213,170, 85,110,219,167,171, 83, 74, 83, 19, 59,170,128,207, 0,124,139,195,135,129, 17, 35,110, 30,127,247,221,155,223,
+ 95,124, 33, 71,149,241, 69, 31, 25,195,118,117,219, 78,142,252,227,226,226,192,178, 44, 62,253,244,211,102,123,193, 21, 10,133,
+131,252,235, 43, 5, 10,154,145,225,254,157, 99,166,105,235,169,191,196,254, 15,155,232,226, 60, 98, 63,145,216,190, 12, 30,124,
+235, 28, 59, 51, 93,235,240,202, 3, 0,203, 38, 99,254,252,249,142,227,243,231,207,199,202,149, 43,193,244,158,125,243, 87,237,
+231,187,146, 39,156,238,186,125, 22,139,139,243,120,180,175,174,174, 14, 29,186,247, 0, 88, 19,152, 0,128, 8, 5,176,212, 84,
+161,174,228, 28,174, 95, 42, 67,151,145, 82, 16,113, 40,136,217, 4, 8, 24, 44,155,187, 16,227,179,222,194,130, 5, 11,154,117,
+ 80,246,148, 42,219,137,108, 9,165, 52,212, 96, 48,140, 12, 15, 15,199,169, 83,167,192,178, 44,206,157, 59,135,181,107,215,162,
+ 95,191,126,232,220,185,243, 44, 0,207, 52, 32,107,182, 49,242,166,148,182,233,206, 28,150,118,236, 22, 47,174,204,251, 13, 85,
+218, 0,252,123,187, 5, 59, 11,254,131, 23, 18, 3,133, 66, 61, 27, 13,204,108,180, 14,194,237, 40,110,229,135,119,104,172,239,
+184,242, 12, 8,249, 18, 63,165, 20,178,215,226,144,149,151, 25,154, 10, 5,126,254,234, 55, 96,148,227,181,226, 5,142,244,245,
+250,245, 0, 8,234,234,214, 32, 60, 92,137,236,236,108,120,147,198,115,120, 64, 43, 85,187, 58, 43, 36, 75,158,133,245,134, 6,
+150,203, 55, 32, 20,139, 16, 68, 4, 8, 38, 2, 4, 11,132, 8, 23, 73,160,173,169,196,149,125,135, 84, 33, 83, 30,114, 59,208,
+185, 34,245,253, 63,178,118, 5, 0, 88,190,152,128, 18,192, 22, 30,227,125, 7,183,147,178, 44, 59, 59, 91,149,157,157,237,211,
+ 20,130, 51,249, 67, 40, 64,201, 21,219,224, 87,122,173, 14,221,218, 75,208, 59,121, 27,178,215, 38,168,248,186,215, 69,164, 24,
+ 66, 82, 6, 1,185, 1, 43,109,131,128,118, 4,193, 51, 46,131,101, 53,168,171,203,134,181,232,239,222,121,114,121, 84,110,243,
+166,196,107,230,214,231, 84,177,225,175,227,211,111,103,163, 5,211, 13, 0,240,236,243,125, 48,120,120, 4,214,127,150,135, 85,
+255,121, 91,149, 57,218, 55,215, 33, 33,128,226,197, 99,142, 65,239,193, 7, 31,196,254,253,251, 61,146, 63, 0, 36,205, 16,169,
+128,125, 0,142,161,242, 90, 11,244,238, 6,172, 94, 93, 11,149, 10,232,221, 27,136,136,176,137,168,188,214,194,246, 50, 14,250,
+ 93,245,235, 47, 93,137, 59,242,223,183,111, 31, 88,150,117,144,244,166, 77,155,154, 76, 32,206,219, 13,201, 31, 0, 60,145, 63,
+ 0,100,100,102, 18, 10, 72, 9,160, 78, 77, 77,109,180,227,179, 78,131,126,102, 86,150,140, 16, 96,213,231,171,110,137,121, 89,
+149,145,233,236, 95,145, 82, 74, 85, 31,127,252,177, 99,199,199, 31,127,140,149, 43, 87, 34, 35, 35,163,126, 21, 57, 2,169, 43,
+121, 25,182, 20,182, 50, 74,169,250,153,103,158,105,180,125, 22, 39, 47, 74,214,234,213, 50, 66,128,140, 85, 25, 42, 87,228, 37,
+108,217, 18, 16, 9, 96,213, 87,226,247,157,185, 88,191, 57, 7,159, 95, 62, 7, 0, 40,124,187, 21,122,143,153, 4, 99,233, 69,
+ 28,255,229, 8,126, 59,119, 26, 85, 87,175,226,216,177, 99,205, 86, 88,107,237,218,181, 82,126,125,152,132, 80, 74,251, 22, 21,
+ 21,125,244,198, 27,111, 12,248,232,163,143,196, 38,147, 9, 2,129, 0, 45, 91,182,132, 78,167, 67, 97, 97, 33, 34, 34, 34,184,
+186, 5,238,172,255, 96, 66, 8, 75, 41, 13,175,188,116,240,199,183,255,175, 52,252,203,249,157,160,209,137, 33, 22, 50,232, 18,
+ 38,193,213, 27, 38, 40,254, 97,193,224, 97,209,193,221, 60,120, 18,210,210,210, 40,167, 8, 56,247,197,198,190,251,113,251,193,
+145,127, 67,229,128,241, 52,136,112,245,190,235,185, 57,227,147,188,110, 64, 86, 86, 22,181,145,255, 6, 7,249, 75,126, 60, 15,
+253,238,251,234, 29,247,104,185,102,110,144,134,104,106,192,138,133, 48, 29, 57, 14,227,239, 37,168,219,179, 31, 48, 24, 33,166,
+ 20, 65, 16, 64, 8, 2, 35,107,129,198, 88,135,207,247,110,247, 40,115,249, 98,155,117,239, 12,219, 54,103,174, 80,156, 58, 67,
+177, 96,169,239,125, 86, 46,151,171,157,221, 94, 74,165,146,215,139,174, 84, 42, 29,181,181, 57, 60,185,242, 18,114,143,104, 81,
+122,173,206,161, 4, 20, 95, 50, 0,242,205, 80, 42,149,188,220,145, 66, 98,171, 28, 38,170,249, 13,193,193,103, 16, 32,169, 1,
+203,106, 96, 54, 31,129, 64, 16, 1,147,174,226,142,117,214,220,111,142, 73, 1, 82,143,252,175,156,162, 24,154, 32,192,243,239,
+141,199,131,227, 7, 0,160,246,243,188,195,134, 13, 27,232, 75,239, 19,180,104, 59, 8, 20, 64,252,148,185, 56,112,224, 0,175,
+191,101,153,139,180, 93,187, 95, 29,228, 95, 83, 97, 43,193, 60,120,176,141,252,185, 66,128,182, 99,129,168,169, 8, 68,120,208,
+ 21,183, 50,167, 78,157, 10,153, 76,134,177, 99,199, 98,250,244,233, 16, 8, 4,183,124,156,247,243,133,171,247,214, 39,101,201,
+137,136, 9, 33,142, 79, 99,251, 8,160, 6,133,186, 17, 89, 55,223,175,212, 84,149, 43,203,121,254,252,249, 72, 77, 77,173, 79,
+168,141,200,251, 54, 51, 19,199,142, 29, 83, 17, 66,164, 0,234,221, 51,135, 63,187,193, 62,119,237, 19, 83, 10, 38, 40, 0,230,
+171, 23,144,249,250,235, 88,171,171,132, 54, 46,198,113,252,203,255,172,197, 91, 11,231, 32,114,193,147,120,231,183,125,216,172,
+ 61,135,241,143, 60,130,136,136, 8,175,167, 0,214,174, 93, 43, 85, 40, 20,116,205,154, 53,245,250,112, 65, 65,129,202,221, 52,
+ 20, 33, 68, 68, 8, 25,246,219,111,191,149,230,229,229,169, 95,122,233,165,152, 79, 63,253, 84, 82, 91, 91,235, 40,211, 92, 87,
+ 87,135, 22, 45, 90, 20, 79,155, 54,173,207,168, 81,163,186,121, 80, 36, 24, 66, 72,247,223,242,183,148,159,222,189,224,252,130,
+ 87,211, 59,110, 91,210, 9,191,151, 9, 81, 85, 43, 0, 75,128,138, 90, 19,104,235, 94,117, 47,190,182,116,192,195,143,253,197,
+227,116, 66, 70, 70, 6,225,198,186,204,204, 76,143,223,253,184, 51,228,239,210, 3,224, 76,252,124,198, 25,111, 44,145,155,174,
+182, 53, 46,189, 3,245,226, 12, 26,113, 99, 12,104,211, 94,165,161,102,136, 43, 52,144,124,187, 15, 68,200, 0,117, 38,208, 26,
+ 29,136,197, 2, 17, 0, 43,101, 81,103,181,160,198, 98, 2, 88,207,115,168, 92,144,223,242,197,141, 15,131,182, 32,193,166, 15,
+168,153,153,153,132,115,233,243,177,214,111,177,254, 1,252,247,185,142,245,182,135,189, 82, 2, 17,189, 1, 51,105,131,236,236,
+236,125,124,189, 0,146, 90, 21,194,223,249, 15,174,191,148,134, 27,154, 64,116, 50, 31,135,213, 90, 2, 0,184,240,115,135, 59,
+214, 97, 55,239,250, 68, 53,103, 66,102, 61,242,231, 16, 19,246, 58, 70, 14,152,138,216,240,227,216,188,235, 61,213,184, 41,252,
+ 7,145,245,235,215,211, 31,126,248, 1, 21, 21,227,208,186,117, 46, 90,180, 25, 8, 74, 41, 24,134,225, 21,136, 84, 90, 10,148,
+148, 28,227, 38, 18, 0, 73, 45, 52, 58, 96,248,112,219,158,226, 98,224,179,207,128,154,106, 64, 87, 11,212,234,128,224,176,106,
+ 94,109,107,108,174,255,236,217,179, 0,128,247,223,127, 31, 0, 16, 25, 25,217,108,110,102,231, 62,201,231,111,230,205,155, 7,
+103,139,189, 33,113,123, 1, 41,112,115,238,223, 25,156, 23,192,126,142,218,157,144,217,157, 35,113,250,248, 9,148,133,133,169,
+ 24,134,193, 11, 47,188,128,127,253,235, 95, 62,183,111,180, 49, 20,148,173,197,156,247, 23, 99,208,212,169,200,124,255,125, 48,
+204, 77,158,203, 44, 62,118,211, 67,184,127, 63,246,238,221,139,115,231,206,121, 29, 4,184,118,237, 90,105,126,126,190, 10, 0,
+ 10, 11, 11, 85, 12,195,200,146,147,147,213,107,214,172,145, 82, 74, 17, 27, 27, 43, 51, 24, 12,170, 70, 20, 59,115, 65, 65,193,
+160,164,164,164, 86, 61,123,246,196,206,157, 59,245, 85, 85, 85, 66,131,193, 96,243,118,216,231, 63, 38, 78,156, 24, 73, 8, 9,
+164,148, 26, 92,136, 97,156,228, 49, 37,167,126, 94,249,214,223, 83, 90,180,238,157,141,159,178,159,198,175, 23, 9, 74,175, 9,
+ 1,202,192,104, 50, 67, 67, 91,151,253,109,246,179, 49,132,144, 50,218, 12, 90, 37,159, 56, 27, 63,254, 24, 52, 58, 5,144,151,
+151,119,203,190,202, 50,173,215,100,231,236, 1,176, 77, 1,216,250,143,228,199,243, 8, 56, 86, 6,107,168,205,138,106, 56,135,
+220, 88,181,184, 19,151, 74,161, 15, 8, 68,132,197,130, 46,129, 45, 16, 36, 18,131,152,205, 0, 75, 97,177, 90, 81, 99, 53, 65,
+111,181,192, 72,173,176,130,130,122,209,217, 22, 44,189,169, 4,216,226, 2,110,146,254,242,197, 2,164, 47, 38,120,105,169,165,
+201, 55, 93, 46,151,171,185,210,165,124,176, 40,219,118,223,151, 37,134, 57, 8,223,225,202,167, 55, 32, 2, 32,164, 90,124, 53,
+ 39,204,242,164,146, 95, 92,135,232,218,143,176,194,230,166,254, 72, 24,130, 39,175, 93, 64,209, 63,186, 32,184, 67, 63, 84,149,
+149,225,234,249,203,119,180, 99, 14, 30, 30, 1,157,189,187,233, 3, 79, 32,200,208, 31, 95,191,109,118, 28, 31, 37, 31,128,252,
+205,222, 89,254, 83,198,252,128,111,191,149, 35, 52, 95,137, 21,139,129, 23,151, 82,140, 25, 51,134,247,178,191, 30, 93,186,146,
+ 94,189,234,107,129,219,183,219, 2,255, 54,108, 0,122,247,166, 88,185,146,224,157,119,106,109, 10, 2,128,222,125,194,240,210,
+139,252,218,200, 89,169, 83,167, 78,197,166, 77,155,234, 89,178,241,241,241,141,146,155,175,138,168,151, 30, 60,217,202,149, 43,
+ 85,141, 41, 0,203,151, 47, 71, 86, 86, 22, 47, 75,248,153,103,158, 81,113,145,255,174,240,226,139, 47, 98,197,138, 21,170,172,
+172, 44,183,109,252,225, 68, 41, 94,123,103, 33,102, 47,249, 59, 94, 53,153,240,241,199, 31, 55,122,143,150, 47, 95, 14,165, 82,
+ 9, 66,136,180, 49,194, 30,211,191, 27,214,124,249, 25,162,103,206,196,219,111,191,237, 86,105,152, 63,127, 62,150, 47, 95,142,
+213,171, 87,171,189,189,247,249,249,249, 42, 46, 88, 78,161, 80,208,130,130, 2, 85,114,114, 50, 57,124,248,176,138, 16,130,228,
+228,100,245,170, 85,171, 26,253,123,189, 94, 31,186,125,251,118,140, 27, 55, 14,197,197,197, 65, 58,157, 14,102,179, 25, 12,195,
+192,100, 50, 33, 49, 49,145,216,201,221,192,199,177,101, 52, 26,197, 71,182,204,196,152,199,223,193,238,188,179, 56,119, 69,128,
+106, 29, 3,129, 16, 40,211, 5,226,133, 87, 22,199, 2,184,196,151,251,185,184, 19,128,223,116,128, 31,119,198,250,135, 43, 55,
+ 14,231,154,145, 74,165,144, 74,165,248,229,151, 95, 28,159,146, 31, 47,160,202, 80,133,214,195,189, 95,247,203,145,123, 80, 80,
+ 18, 36, 63,158,135,232, 66, 5, 40, 33, 16,207,174,168,119,220, 35,113,137, 5,176, 82,224,146,174, 18,165, 85, 26, 92,175,214,
+162,170,174, 14, 90,147, 1,215,141, 6, 92,169,211,163,172,174, 22, 26,179, 17, 90,214, 12, 19,235, 57, 27,230,232, 7, 92, 12,
+120, 78,113, 1,115,166,183, 0,133, 24,212,187, 50,224, 14, 23,126,195,206,206,215,253,239,176, 60,175,213, 33,247,136,182, 30,
+241,115,228, 31,192, 94, 64, 0,123, 1,111, 77, 20,162,180,180,212,196, 87,230,150,115, 44,218,166,103, 56,182,207,233,172,184,
+116,182, 12,167, 14, 30,199,213,243,149,119,188,227,110,248,220,166,128, 86,151, 83, 4, 25,250, 67, 58, 91,136,199,151,136, 28,
+159,244,205, 51, 65, 64,120, 15, 72,143, 62,152,135,167, 23,200, 17, 86,144, 11, 66, 8,190, 59,104,123, 4,124,201,159, 67,100,
+223, 62, 13, 20, 11,224,211, 79,129, 51,103,108,158,128,183,223,166, 14,247, 59,165, 20, 97, 97, 97,158, 71, 96,123, 31,181, 90,
+173,176, 90,173,120,255,253,247,113,246,236, 89,156, 62,125, 26,167, 79,159,134, 82,169,196,194,133, 11, 81, 90, 90,122, 39, 31,
+137,186, 49, 75,122,222,188,121,156, 85,199,139, 12, 9, 33, 46,173,127, 14,238,142, 57, 99,127, 64, 37, 8,211, 2, 95,188,182,
+ 20, 45,182, 43,145,154,154, 10,231, 82,195,138,222, 3, 49, 47,122, 36,130,130,130, 48,102,204, 24,188,241,198, 27, 80, 42,149,
+ 42,173, 86,235,242,253,251,178,236, 52,174, 12,232,143,206,157, 59,203, 88,150,109,212,219,193,121, 42,124,245,188, 56, 71,202,
+199,198,198,202, 56,162, 4,128,152,152, 24,153,135,123, 55,118,204,152, 49,173, 74, 75, 75,177,127,255,126,220,119,223,125, 16,
+ 10,133, 14,101,177,115,231,206,124,167, 35, 88,187, 60,210,171,111,212,162,172, 61,161,248,117,231, 18,140,142,237,135, 96, 9,
+131,224, 32, 43, 2, 3,140,120,232,209,105, 44, 0, 77, 67, 93,213,147,114,201, 93, 31,159,233, 0, 63,238, 28, 24,119, 15, 49,
+ 51, 51,179,229,188,121,243, 48,111,222, 60, 0, 48,189,155,246, 46,204,229, 22, 4, 6, 74,124, 74, 70,146,152,104, 11, 31, 14,
+154,120, 6, 84,192,224,141,175,245, 14,235,159, 47,130, 58,119,150, 89, 90, 4, 65, 75,173, 56,161,211,226, 88, 85, 5,142, 87,
+223,192,241,106, 13, 78,232, 52, 56,163,215,162,194, 88,135, 90,139, 5,151,245, 58,199,111,186,195,148, 9, 4,203, 23, 11,176,
+124,177, 0, 20, 2, 80,194, 32,117, 6,193, 51, 51,196,152, 61,189, 45,122,245,106, 15, 22, 34, 0,222, 93, 50,231,234, 79, 76,
+ 76,148, 53,220,231,197, 61,147, 21, 95,178, 41,242, 69, 31,218,130,232,118,191, 28, 98,115,223, 80, 45, 4, 84, 7, 35, 99,139,
+104,214,104, 52, 65,137,137,137, 94, 21, 69,143,142,142,134, 82,169,196,134, 90, 29, 12, 38, 6, 79,111,252, 2,229,146, 64, 24,
+ 76,119,174, 76, 68,194,224,183,100,249,154,165,216,240,239,155, 38,254,215,111,155, 17, 19,246,250, 77,133,242,225,207,100, 25,
+153, 25,188,114, 75,172,120, 29, 72, 94, 48, 14,161, 5, 74,200,254, 17, 7,102, 50,160, 86,171,125,234,195,221,187,215,143, 30,
+ 31, 59, 22, 8, 13, 5, 34, 34,128, 17,131, 91, 66, 34, 22, 64,192,220, 20, 43, 9, 12,244, 56, 32, 51, 12,227,152,235, 63,123,
+246, 44, 34, 35, 35,235,125,222,121,231, 29,188,243,206, 59,184,124,153,191, 87,198,213,124,189, 51,210,210,188,183,192,178,178,
+178,100, 43, 86,172,112, 73,216,124,173,127, 39,215,243, 45,113, 10,220, 54,203,242, 75, 97,111, 34, 4,172,222, 8, 81,135,238,
+ 80,188,247, 30,146,131, 67, 17,170,206,119, 28,159,253,151,100,188,245,209, 23, 40, 94,254, 95,188, 57,104, 44,166,133,245,196,
+222,173, 91, 81, 82, 82,226,242,253,123, 44, 77,129, 1, 3, 7,202,184,160, 70, 78, 33,115,158,158,113,181,207,141,245, 69,211,
+210,210, 40, 23,216,199,205,247, 59,147,124,114,114,178, 58, 38, 38, 70,198,185,254,147,147,147,213, 30,238, 91,158, 72, 36,186,
+239,177,199, 30, 59, 91, 85, 85, 5,173, 86,139,192,192, 64,180,109,219, 22,161,161,161, 8, 13, 13,245,116,243,216, 6,242,172,
+ 1, 1, 1,250, 39,210,254, 37, 91,251,227, 48,156,191, 88,141,246, 33, 2,196,246, 33,184,191, 39, 69,112,171, 86,149, 0,172,
+110,120,195, 95,111,224, 30,181,254, 1,207,203, 0,107, 51, 51, 51, 3, 0, 4, 43, 20, 10,135, 22,216, 37,174,147, 79,154,111,
+102,102, 38,145,203,229, 80, 42,149, 84, 60, 59,187,158, 43,146,111, 30,128,214,143,140, 83, 87,100,239,132,222, 98, 68,181, 78,
+143,179,102, 51, 68,172,205, 81, 95,101,174, 3, 75, 41, 40,128,157,215,206, 65,103, 49, 3, 0,143,129,137, 96,193,210,250,125,
+220, 54, 21,192,194, 10, 35,126, 63, 83,131, 53,155,170,189,186, 94,103,162,151,203,229,234,134, 94, 0,103,165,192, 29,228,114,
+185, 58, 91, 49, 13,162,113,159, 3,136, 64, 69,197,205,224, 60, 49,123, 5, 38,166, 35,254, 54,232, 52,174, 92,177, 13,196,153,
+153,153,185,124,228,166,125,157, 85, 79,241,202,206,206, 6, 55, 41,177,241,183, 67, 94,173,202,104,110, 60,252,108, 71,245, 54,
+ 5,197, 65,229,113, 0,192,200, 1,182,204,120,127,159,191, 4,135,142, 15,192, 71,155,103, 34,115,251,179,170,204, 4,126, 4,
+254,244, 2, 57,194,195,149,206,134, 44, 52, 26, 57, 40,205,182,187, 42, 41,178,179, 19,121,201,154,250,248, 19,100,239,238, 61,
+ 20,176,185,254,101, 50,130, 27, 23, 67,160,211, 74, 96,168, 22, 99,227, 58,130,121,243, 40, 46,148,215, 96, 68,108, 12,102, 78,
+159,193,203, 42,182, 90,173,142,249,126,165,210,214, 86,103,194, 47, 47, 47, 71,121,121,185,215,238,125,133, 66, 65, 25,134,185,
+133, 84, 51, 50, 50,137, 15, 73,128,212,148,210,122,177, 0, 78, 30, 1,222,174,112,103,215,126,195,232,125, 79,110,255,134, 74,
+142,165,166, 6,162, 54,225, 16, 4,181,192,128, 39,166,226,157, 9,227,241, 26,183,108, 47,106, 40,172,134, 58,136, 90,183,199,
+160, 24, 41,122,116,233,137,127,253,158,143,129, 3, 7,202,126,252,241,199, 91,148,128, 52,133, 2, 0, 81, 1,192,179,105,105,
+142,165,131,150, 6,100, 47, 20, 10, 0,122,115,161, 34, 1, 48,216,197, 32, 59,100,200, 16, 66, 41,117,184,248, 11, 11, 11, 29,
+ 46,126,231,243,236,219, 30,201,223,110,176,191, 30, 26, 26, 58, 32, 38, 38,166,215,201,147, 39,113,244,232, 81, 88,173, 86, 4,
+ 7, 7, 67,175,215,151,135,135,135,159,247,198,232, 35,132, 48,237,219,183,223,251,232,163,143,182, 47, 56, 80,136,149,217,123,
+209,138,136,209,167,189, 17,103,110, 4,227,193, 62,230,115, 0,204,156,130,102, 87, 40,173,238,158,137,243, 88,231,159, 2,184,
+187,193,103,190,216, 4,192,228, 76,212,151,242, 46, 3, 51,189, 39,127,103,178,113, 53,104,241, 85, 2,170, 53, 90,153, 57, 72,
+162,170, 98, 88, 92,173,171, 5,204,102, 88, 41, 5, 1,240,123,109, 37,202,244,213,160,148,114, 73,108,120, 12, 76, 20,169, 51,
+ 8,178, 54,222,236,147, 39,207, 2,125,123, 89, 32,128,174, 73,228,239,220,217,125,117,121, 37, 38, 38,202,178,179,159, 85, 1,
+ 69,208,104, 52,166,210,210, 82,225,178,241, 96, 22,237, 29,131,249, 3, 15, 57,172, 48,190, 74,133, 43,175, 75,195,109,142,132,
+248, 90,115, 88, 66, 48, 44,171,132, 2,174,151,251, 57, 50, 1, 42, 65,249, 4, 41,166, 37,124, 46,203,220,246, 55, 85,254,102,
+138,216,240,227, 24, 37, 31,128, 3,123,143,163, 64,251, 30, 8, 8, 20, 9,159,241,190,214,240,112, 37, 8, 33,152, 50,101, 10,
+ 86,175,174, 6,103, 20,219,254,167,246,123,156, 93,111, 64,114, 51, 5,139,184,177, 50, 89,222, 62,149,106,236, 88,192,116,181,
+ 43, 46, 86, 6,128,181,207,182,118,212,181,199,203,169, 53,216, 91,208, 7, 45,187,244,225,213, 70,142,248, 47, 93,186, 4, 0,
+184,122,245,170,195, 51,112,237,218, 53,199,192,234, 11, 50, 51, 51, 9,151, 8,168,225, 28,110, 70,102, 38,225,147, 15,192, 25,
+171, 87,175,174, 23, 11,176, 98,197, 10,175,173,255,134,132,225, 43, 36, 18, 9,174, 94, 56,143,158,189,122,131,181, 24, 65, 44,
+ 86, 8, 91,182, 66,203,161,195,208, 34,234, 1,176, 58, 11,172,122, 35,168,197, 10, 88, 89, 44, 90,245, 17,166,207,156, 14,137,
+ 68,226, 82,158,101, 99, 24,175,223,117,117, 94,244, 7,174,207,141,141,141,149, 21, 20, 20,168,184, 49, 96,212,168, 81, 46,239,
+ 21, 15,242, 7, 33,132, 5,176,171, 79,159, 62, 81,159,124,242,137,233,250,245,235,117,227,199,143,127,180,168,168,232, 77,189,
+ 94, 95,209,166, 77, 27, 69,255,254,253, 53, 94,220,123, 17,128,110, 49, 35, 70,180, 77,155,157,134,115,151,206,105,158,154,157,
+ 54,250,240,222,117,233, 87,106, 52, 35,135,197,141,103,219,119,137,124,220,133,215,128,117, 55, 22, 56,115, 69, 99,201,127,252,
+137,128,238, 29, 5,160, 81,235,194, 23,242,231,200,134,203, 9,224,139, 18,208, 83,145,164, 6, 64,202, 50,215, 82, 4, 74,160,
+165, 22,152, 44, 22,176,148, 69,235,144, 16, 92,210, 85,241,203, 96,103,135,171,229,125, 55, 99, 0,188,203,196,230,202,197,223,
+212,116,189,246,191, 77, 24, 54,108,216,182, 69,139, 22,137,195,195,195,217, 43, 87,174, 96,254,192, 43,245,200,223,155,223,112,
+117,255,125,134, 61,203, 95,195, 36, 79,174,206,225,139,168,135, 5,234,140,135, 51,200,214, 79, 47, 75,119,252,246,182, 42,127,
+ 51, 64, 64,144, 48,248, 45,217,195,207,242, 79, 0,196,245, 37, 27,193, 87,219, 7, 41,192, 21,239,172, 77,183, 57, 79,130,187,
+101, 16, 96, 85,163, 3,211,204,233, 51,212, 51,167,207, 32, 21,218, 79,164,214,154, 26, 21, 17, 0,250,186, 64,144, 26, 11,132,
+140, 16,122, 70, 34,155, 48,109, 14,132,148,120,108,231,248,241,227,201,125,247,221, 71,111,215,251,103,179,246, 51, 72, 90, 90,
+ 26,117,142,104,119,246, 4,120, 41, 78,205, 89,254, 78, 10,133,250, 78, 12, 94, 99,199,142,197,223, 54,103,225,157,154, 74, 12,
+137,123, 16, 76,251, 48, 91,155,204,212,150,186, 23, 34, 16,129, 16, 68, 44,192,234,140,229,104, 53,110, 24,122,245,234,245,135,
+166,238,229,172,251,252,252,124,213,136, 17, 35,100,179,102,205,106,210,111,159, 61,123, 86,158,155,155,123, 65, 32, 16,108, 29,
+ 61,122,244,187, 12,195, 92,143,137,137,201,115, 88, 50, 78, 30, 37, 66, 8, 92, 61,115, 39, 79,128,242,232,209,163,195,191, 90,
+187,142, 17, 11, 2, 46, 78,125,114,234, 96,134, 97,180, 15, 78,154, 51, 25, 64,136,157,248,107, 0, 80,139,197,226,144,215, 64,
+105,243,151,148,191, 11,193,199,253,239,147, 2,208, 28, 10,131, 59,242,241,102,128,147, 41,146,137,114,175, 82,202,158, 42, 86,
+233,140, 38, 88,172, 86,244, 26, 62, 20,145,150, 17, 94,145, 97,115, 6,163,112, 73,127, 0,168, 56, 79,135,211, 84, 0,105,130,
+220,237,114,185, 92,168, 84, 42, 23, 44, 91,182,236, 31, 78,202,197,216,204,204, 76,175, 18,145,216, 61, 5,205,150,188,100,218,
+239,137,246,251,216,248,245, 77, 83, 42,125,210,244, 31,121,174,147,250, 17, 52,253,249,216,200,157,224,233, 5, 99, 29,121,202,
+185,113,108,109,122, 46,130,187,101,144,224,110,137, 94,201, 12,109,245,188,250,224, 5, 16,150,185, 40, 53,232,109,117, 0,130,
+ 37,114,117, 72,103,120,181, 98,212,169,255,137,236, 26,103,179,207,171,114, 74, 64,115,200,178,199, 2,168,184,239, 77,149,231,
+235,202,178, 94,189,122,161,195, 11, 47,200, 86,238,217,163, 42,121,247, 91, 36,138, 90, 35,212, 94,188,199,160,183, 96,222,194,
+ 87, 33, 8, 10,199,206,117,153,248,165, 13,193,132, 38,228,237,183, 90, 45,240, 54, 6,168,161, 18,192,199,202,247,112,159,200,
+233,211,167,175, 83, 74,211,251,246,237,251,127, 21, 21, 21, 58,161, 80, 8,139,197, 66, 91,183,110,237,240,168,232,116, 58,136,
+197, 98,135, 23,201,141,188, 49,133,133,133, 96, 45, 4, 35, 71, 13,126,235,210,165, 75, 90,141, 70,131,240,240,112,182, 75,151,
+ 46, 90,238,217, 84, 85, 85, 65, 34,145,128, 16,130,128,128, 0, 94, 70, 31,167, 36, 52,252,222,208, 43,234,199, 61,230, 1,184,
+ 93, 74,129,207,196, 56, 94,174,198,120,249, 93, 21, 77,106, 87, 2,200,109,152, 71,183,202,229,242,127,202,229,242,127, 54, 71,
+251,154,241,122, 73,115,156,115, 59, 97,179,234, 1,123,138,253, 6,199, 18,155, 36,155, 97,187,170,131, 37, 93,155,163,153,230,
+219,121, 15,154,177,232,138,218,155,185,122, 15,202,132,207,114, 40,165, 36, 40, 40, 8, 83,166, 76,129,189,124, 47, 74,157,202,
+247, 30,204,221,235, 40,223, 59, 46,102, 28,236, 74,111,163,191,183, 90,251, 1,121, 38,236,213, 91,137,137,103, 53, 65, 30, 74,
+ 64,147,241,192, 3, 15, 24, 45, 22, 75, 30, 0, 29,203,178,212,100,178, 45,252,185,126,253, 58, 0,160, 69, 11,219,210, 94,110,
+191, 72, 36,114,123,255, 30,126,248, 97, 78,198, 30,150,101, 17, 26, 26, 10,150,101, 29, 43, 78,236,171, 88, 72, 93, 93, 29, 5,
+ 0,177, 88, 12, 66, 8,243, 71,140,237,126,248, 14, 62,169,164, 1,128, 12, 25, 50,196,175,137,249,225,135, 31,126,220, 59,176,
+ 0,168, 3, 32,105,102, 35,206, 83,193, 32,222, 21, 5,253,184, 55,224,127,152,126,248,225,135, 31,247, 22,132, 0, 90,240, 32,
+127, 61,108, 65,220,205,197, 7, 44,252,203,254,254,116, 29,201, 15, 63,252,240,195,143, 63, 31,130,252,124,225,135,223, 3,224,
+135, 31,126,248,225,135, 31,126,109,242,131,254, 0, 0, 32, 0, 73, 68, 65, 84,248, 21, 0, 63,252,240,195, 15, 63,252,248, 95,
+ 71, 61,151,206,220,185,115,125,142,224,116, 85,188,231,110,151, 23, 49, 52, 0,129, 1, 87, 33, 18, 87,130,101,109,203,194, 4,
+ 2, 6, 12, 17,216,254,103, 8, 8, 97, 64,137,208,182, 6, 22, 22,108,219, 33, 2,165, 20,225, 76,107,120,217,190, 0, 0,109,
+ 96, 11,224,169,129,109,185,151, 25,246, 57,181,123,241,254,249,229,249,229,249,229,249,229,221, 46,121, 63,253,244,147,207,242,
+162,162,162,254,231,229,121,173, 0,252,175,225,135, 3,103, 48,124,152, 25, 97,161,128, 70, 75,240,211, 47, 18, 8, 25, 33, 38,
+ 77,180, 98,175,170, 45, 8, 97, 64, 24, 6,146,150,192,216,225,149, 0,132,120, 48,150,162,176, 72,104,163,113, 30, 80, 29, 58,
+ 64, 1, 64, 68,205, 24, 49,122,236,133,211,191,254,104, 44,175,174,139,180,234,235, 32,151,203, 67, 1, 84,249,245,208,123, 27,
+ 57, 95,255, 91,218,187, 87, 79,213,245,235,117, 77, 74,248,116, 15, 65,154,154,154,234,156, 7,160, 73,215,156,154,154,234,115,
+ 58, 96, 63,252,240,163,153, 60, 0, 28,214,125,245, 37,111,109,226,233, 89,179, 61,190,172,205, 45,175, 57, 81, 88, 36, 66,252,
+120, 43,126,249, 53, 16, 98,145, 16, 66,129, 16, 34, 17, 69,128,192, 12, 8, 91, 66, 8, 3,134, 15,176, 64, 34, 14, 0, 5,208,
+177, 61,240,200, 36, 22,185, 91,249,145,255,153,223, 79,227,190,254,189,208,169,115, 40, 46, 93, 56,217, 61,164, 67, 79,180,233,
+100,197,247,223,125, 7,165, 82, 89,121,167,215,199, 43,149,202, 73,217,217,217, 59,184,237,196,196,196,135,229,114,249, 14,255,
+171,225, 25,191,254,162,164,150,186,227,178, 25,143,244, 82,177,108, 5,170, 58, 25, 84, 39,143,109, 70,173,177, 35,134, 69,143,
+254,211,146, 88,106,106,170,106,254,252,249, 32,132,240, 42,219,203, 7, 92,178,152,102, 40, 55,239, 71, 19, 21, 48,183,160, 20,
+ 89,171, 87, 55,250,188,185, 4, 63,206,217, 2,185, 26, 2, 78,181, 4, 28,207,217,185, 50,162, 31,205, 11, 46, 27, 32, 7, 87,
+185, 1,238, 42, 15, 0,131, 63,182, 31, 76,154, 96, 6,133, 0, 66,129, 8, 35, 71, 16,180,107,203, 64, 40,100, 16, 32, 18,160,
+111, 36,131, 11, 23, 45, 24, 30,205,160,117,184, 4,223,239,107, 5, 0, 16, 80, 3,108,169,176,173, 30,201,255,215,162, 34,244,
+232,212, 5,191,230, 23,224,176,201, 12,237, 13, 45,196, 1, 45,209, 47,106, 20, 6,143,154, 0,213,182,108, 0,252,114,227,223,
+ 6,226, 31,155,157,157,157,187,104,209, 34, 20, 21, 21,113, 29,166, 18,192, 11,115,230,204,217,158,152,152, 40,151,203,229,185,
+127,186,151,226, 39, 37, 13, 16,106, 32,100, 76,168,171,179,162, 74, 23,136, 7,199, 76,243,234,254,111,206,249, 74,218, 42, 80,
+131,191, 76, 31,138, 30,221, 31, 81,181,106, 21, 2,179,197,130,235,215,111,160,125,233, 69, 20,159, 45,193,161,131, 26, 58,114,
+212,163, 62, 61,215,172,172, 44,234, 52, 56,223,109,131,163, 20,184, 89, 14,215, 94, 29, 80,138, 59,148, 14,248, 15,124, 95,232,
+150, 45, 91,110,173,167,112,199,200,139, 74, 9, 8,104, 51,220,119, 90,250, 53,200,225, 57,206, 28,111,207,146,105,175,134,228,
+132, 57, 25, 58, 12,159,254,137, 91, 69,238,251,239,191,119,108,199,199,199, 99,215,174, 93,110,183,253,184,253,228,239,188,207,
+ 89, 17,112,171, 0, 28, 60,112, 24,163, 30, 28,241,135, 53,154,245, 34,127,170,115, 42, 73, 95,179, 79, 49, 66, 1,180, 26, 33,
+ 58,180, 19,161, 67, 59, 49,106,107, 69,144,136,132,176, 10, 3, 48,116, 16,193,144,251, 5, 96,136,200,150, 2, 83, 36,134,136,
+ 49,130, 72,196,176,232, 1, 11,116,110,201,255,192,190, 92,244,236,216, 22,199,126, 57,134,197,239,190, 85,175,125, 75,223,126,
+159, 50, 2,130,161,209, 67,241,253,174, 92,175, 42,239,177, 44, 43, 45, 42, 42, 82,157, 57,115, 6,129,129,129, 8, 12, 12,148,
+197,199,199,171,189, 28,204,100,217,217,217,185, 28,241, 59,117,142, 80, 0, 19,190,248,226,139, 27,115,230,204, 81, 2, 24, 47,
+151,203,149,119, 99, 7, 95,179,102,141, 52, 37, 37,133,247,117,255,119,211, 58,233,192,200,150,170,238, 29,235, 16,210, 42, 0,
+ 12, 19, 4,131,193,130, 10,141, 1,121,202,149, 84,210,106, 40, 70, 12, 31,195,171, 31,137,112, 21, 83, 30,190, 95, 53, 96, 64,
+ 63, 92,185,170,197,145,159,142,162,182, 86,135,144,144,150,136,136,232, 14, 70, 32,130,213, 90,138,159,126, 62, 64,163,134, 60,
+248,167,178,110, 82, 83, 83, 85, 47,190,248,162, 99,123,254,252,249, 88,177, 98,133,106,181, 27,171,208, 43, 50,186, 75, 61, 0,
+118, 37,157,230,228,228,192, 85, 97,165, 63, 18,206, 86,118,102,102,134,140,210,166, 41, 1, 76,247, 39, 28,228, 93,248, 65, 11,
+151,102, 88,135, 80, 6,157,195,153,123,246,249,253,175,194,153,236, 93, 41, 5, 30, 61, 0, 7, 15, 28, 6,128, 38, 43, 2, 7,
+ 94, 40,118,123,252,193,127,245,246,121,176, 32,132,248, 84,109, 79,169,110, 7,145, 80,132,174,157,106, 81, 83, 35,194,145, 99,
+ 93, 33, 16, 8, 32, 32, 2,136, 69, 22, 12,232,173, 71,159,222, 2, 16, 48, 16,139, 2, 32, 22, 16, 68,223,111, 66,120, 24,139,
+ 13,255,231, 94,118,191,158,237,113,225,108,249, 45,228, 15, 0,139,151,188, 70,222,127,247, 31,180, 99,236,253, 8, 11,109,201,
+187,189, 6,131, 65,186, 98,197, 10,213,133, 11, 23,234,233, 27, 70,163, 17,143, 62,202,223,218,204,206,206,222,231, 76,254, 46,
+208, 38, 61, 61,189,242,165,151, 94,218,123,167,167, 40, 26, 35,255,195,135, 15,171, 82, 82, 82,120,183, 45, 50, 34, 92,213,185,
+125, 53,218,180, 14, 70,151,206, 29, 16, 20, 28,132, 11, 23,202, 96,181,178,232,220,169, 37,142,255,158,143,181,167,138,165,201,
+ 79,205,118, 59,152,254,246,219, 1,250,120, 66, 63,116,235,214, 5, 39,126,191,128, 35, 71,126,199,245, 27, 53,160, 20, 8, 11,
+ 11,132, 94, 95,139,168,168, 1,168,172,172, 66,217,145,159,240,213,127, 78, 75,103,253,133,191,162,114,151, 67, 10,216,138, 79,
+113,248,248,227,143,185,109,175,188, 0,169,169,169,212,217, 37,236,108, 65, 58,187,164,155, 99,122,225,221,119,223,165, 93,187,
+118,109,114, 46,126,185, 92, 78, 8, 33,116,243,230,205,110,115,236,115, 72, 75, 75,163,174, 60, 4,107,215,174,149,114,197,129,
+ 92, 41,177, 10,133,130, 54,150,202,213,185,158, 3,165, 20, 10, 69,154,170, 41, 94,136,134,242,134,191, 90,139, 31, 63,104, 81,
+143,248,253,184, 55,173,255,134,125,168, 73, 83, 0, 77, 85, 4, 30,252, 87,239, 70,149, 0, 95,200,159, 67, 94, 94, 30,202,202,
+202, 0, 0,157, 59,119,166,222, 40, 1, 2,106,128,144, 88, 33, 22,137,240,211,177,182, 16, 8,133,104, 41,210,217,226, 0, 90,
+ 48, 40, 43,107,137,251, 7,176, 32,132, 32,241, 17, 11, 40,203, 0, 36,192,230,120, 67, 77,163,114,245,149, 23,113, 85, 83,139,
+151,222,124,179,209,182, 84, 86,105,160,189,126,213, 46,139, 55,113, 55, 36,127, 0,192,206,157, 59, 97,181, 90,165,143, 63,254,
+184,199, 1, 78,169, 84,142,109, 88,250,151,235, 48, 85, 85,245,226, 17, 67,151, 44, 89, 2,165, 82, 57,238,110,154, 10,224,200,
+223,155,191,249,239,166,117,210,251, 35,141, 8, 12, 12,133, 36, 64,140,158, 61,123,160,107,143, 30,168,174, 86, 67,163,169,133,
+ 88, 44, 64,120,152, 4,194,192, 80,183,185,226, 1, 64, 72,203,208,178, 69,107,232, 13, 22, 28, 59, 86,140,203, 87,171,112,229,
+106, 45, 12, 70, 9,186,117,182, 64, 18, 32, 64,241,233, 18,220,215,171, 23, 46, 95,169,134,193,210,202,163, 76, 59,209, 81, 79,
+251,189,157, 14,104, 76,166, 47,178, 56,235,127,254,252,249,183,236,127,241,197, 23,125,138, 5,112, 69,162, 13,231,142,155,203,
+171,144,159,159,175, 66, 19, 11,242,228,230,230,210,236,236,108, 36, 38, 38,194,213,116, 0, 31, 79, 21, 71,254, 0, 80, 88, 88,
+168, 98, 24,166, 94,155,214,174, 93, 43,229, 99,244,196,198,198,202, 56, 57,205,225,113,217,252, 98, 48,166,173,208,185, 36,254,
+206,225,140,125,148,226,247,120,227,227,227,235,121, 73, 30,122,232,161,122,247,202,239,246,191,123,224,117, 12, 64,115,121, 4,
+154, 19,197,197, 54,197,162,172,172,204, 43, 37, 64, 40, 20, 66, 36, 16, 65, 36, 34, 24, 51, 10,208,235,140, 56,119, 86, 12,145,
+ 80, 4,161, 85,136,152, 17, 20, 98,145, 8, 2, 1, 3, 80, 2,141, 22,248,241,168, 16, 44,203, 2,184,222,168,220,163, 63,157,
+ 69,109,109,227, 25, 56, 63, 92,178,132, 6, 4, 72, 96, 48, 84,193,202, 90,120, 95,231,209,163, 71, 27, 87, 58,244,122, 94, 68,
+211,208,245,239, 74, 51,220,182,109,155,243,249,202, 59,225, 5,112,229,226,119, 38,255,216,216, 88,222, 85,232,186,116,110,175,
+ 98,152,139,176, 88, 89,152,204, 22, 92,191,161,129, 72, 44,129,209,104,134,217, 98,133,197,194,194, 98,165,168,212,222,240, 40,
+ 75, 44,210, 65, 18,216, 5, 21, 21, 85,168,174,209, 67,163, 53,160, 85,235,193, 24,121,255,253, 40, 60,184, 11,157, 76, 22, 84,
+ 85, 87,161, 79,159, 94, 8, 16, 11,161,171,209,252, 89,198, 10, 41,165,212, 49,247,239,140,149, 43, 87,250, 20, 11, 48,127,254,
+252,122,222,132,134,199,248, 42, 0,182, 82,207,156, 69, 27,142,113,227,198,213,235,175,156,129, 80, 90, 90,170, 82, 42,149, 62,
+ 21,166, 82, 42,149, 14,242,231,166, 3,182,108,217,226,145, 92, 27,122,170,242,243,243, 85, 92,224,155, 66,161,160, 5, 5, 5,
+170,228,228,100,199,241,130,130, 2, 21, 33,238,155, 23, 27, 27, 43,115, 46, 51,156,150,150, 70,221,221, 43, 79,227, 97, 98, 98,
+ 34,166,198, 42,177, 9,192,244, 21, 58, 60,240,106,173,219,123, 63,124,186,251,123,213,112,142,223, 83, 76,128, 31,183,223, 27,
+208,152, 7,224, 15,245,239,184,178,244,155, 98,253, 55,176, 88, 81, 92, 92,140,149, 43, 87,242, 46, 53, 41, 16, 8, 17, 51,156,
+133,128, 17,226,199, 34, 9, 78, 21, 75, 48,121, 34,240,240, 67, 64, 66, 60, 65,199,246, 98, 72,196, 1,144,136, 3, 16, 40, 9,
+ 64,231,142, 1,144,136, 37,144,136,221,151,196,124, 99,241,235,100,217, 7,239,144,198, 6,146, 94, 61,187, 35, 36, 52, 24, 18,
+214,132, 90,189,249, 15,239, 20, 7, 14, 28,200, 61,112,224, 64, 61,194,119,254, 0, 64, 69, 69, 5, 18, 18, 18,238,152,149, 95,
+ 88, 88,168,114,182,134,184,125, 0, 48, 98,196, 8,175, 44, 57,171, 21,208,233,205,208,233, 76,168,174, 54,226,218, 53, 45, 46,
+ 95,190,129,154, 26, 35,106,107,205,168,173, 53, 65,167, 51,163,170,210,243,138, 76,163,209,130,186, 58, 43,204,102, 19, 90,182,
+ 20,163,107,231, 86, 8, 10, 14, 6, 0, 68,244,234,129, 46,157, 90, 33,164,149, 4,148, 90, 97,182,176, 48, 26,117,127,138,129,
+ 36, 53, 53, 85,181, 96,193, 2,183,100,206, 45, 13,228,233,157,144,217,149, 6,151, 88,177, 98, 5, 86,175, 94,237,117,169, 97,
+155, 91, 92, 65,157, 63, 28,161,150,149,149, 33, 59, 59,219,235, 82,180,185,185,185, 52, 39, 39,199,153,252, 33,151,203,201,212,
+169, 83,221,254,221,220,185,115, 65, 8,113, 88,245,107,214,172,145, 2, 64, 76, 76,140,204, 89,137,117, 62, 78, 41,117, 28,231,
+113,181,245,172,120, 87,138,131, 39,101, 2, 0,218,180,105, 3,226,100, 61, 52, 85,158, 31,119, 31,249,187,218,246,201, 3,112,
+ 55, 89,254, 55, 7,120, 43, 4, 2,129,215,127, 55,106, 56,139,118,109, 3, 80, 93, 45, 68,128,208,130, 0,177, 0,234,195, 98,
+ 76,150,137, 32, 22,137, 80, 93, 45,194,193,162, 96,180,146, 16, 48, 12,131,120,185, 9,143, 78,166, 96, 24,138,247,126,246,190,
+157, 74,165,146, 10,130, 36,208,136,218, 32,200,124, 9,103,202, 40,198, 74,199,240,254,251,168,168, 40, 28, 58,116,200,229,177,
+160,160, 32,222,131,165, 86,171, 29,103, 31,120,144,156,156,236,216, 95, 81, 81,225,248,158,156,156,140,242,242,242, 59,242, 60,
+ 83, 82, 82,212,133,133,133,200,207,207, 87,177, 44, 43, 99, 24, 6,156,229,223,216,188,169, 59,148, 94,188, 44,107,219, 74,175,
+ 10, 16, 11, 96, 50,179,168, 51, 94,194,197, 75, 21,208,104,171,161,209,232, 81,161, 49,160, 66, 99, 64,104,120, 15,143,178,174,
+221,160,184,122,237, 6,250,245,235,133, 74,173, 22, 34, 33,131,234,154, 75,208, 85,178,232,127,159, 14,237,219,182, 69, 80, 80,
+ 16, 2, 2, 2,113,229,106, 13,136, 32,140, 47,193, 18, 39,114,108,150, 85, 0,205,189,130,160, 49,107, 29,168, 23, 11,192, 23,
+106, 0,152, 55,111,222, 45, 94, 5,167,105, 6,181, 47,237,156, 54,109, 90, 61, 11, 54, 59, 59,219, 65, 94, 79, 60,241, 4,198,
+143, 31, 79, 92, 37,158,225,105,249, 59,208,208,211,208, 16, 67,134, 12, 33,148, 82,135,149, 95, 88, 88,168, 34,132, 56, 74, 3,
+ 39, 39, 39,171,243,243,243,145,159,159,175, 74, 78, 78, 38,135, 15, 31,118, 28, 95,181,106, 85,163,114,243,243,243, 85, 12, 67,
+100, 5, 5,182,119, 98,238,220,185,248,249,231,159,100, 28,133, 23, 20, 20,168,184,235,231,163, 76,172, 90,181, 10,159,201,194,
+ 48,125,165, 30,128,109, 58,192, 25,211, 87,234, 29,247, 51, 69, 38,242, 51,235,189,162,180, 47,250,176,190,210,189,236, 21,252,
+252,243,207,252, 87, 1,220, 14,226,119,142, 5,104,138,245, 95,223,146,175, 79,254,241,241,241, 80, 40, 20, 30,167, 2,218,180,
+ 17,128, 33, 2,180,109, 35, 64,239, 94, 20,151, 47, 11,193, 8, 8, 68, 66, 33, 68, 66, 17,126,253, 45, 24,225,193, 34, 8, 4,
+ 2,140, 26, 97, 69, 96, 96, 0, 88,150, 2,212,234, 19,249,183,104,223, 21,215,106, 41,116,103,212, 16, 18, 1, 94, 94,178,152,
+120, 57,176,201, 46, 94,188,168,186,120,241,226, 45,215, 59,101,202, 20, 94,131,101, 98, 98,226,248,138,138,138,189, 28,201, 3,
+ 64, 66, 66, 2,214,174, 93,235, 56,167,186,186, 26,229,229,229,216,190,125, 59, 18, 19, 19,199,222,137,206, 27, 19, 19, 35,203,
+207,207, 87, 21, 22, 22,170,184, 96,177,152,152, 24,159,230,112,103,253, 37, 69,189,241,191, 89,160,101,213,208, 27,204,208, 6,
+212,129, 66,139,186, 58, 11,170,171,141, 40,191,161,199,229, 43,181, 24, 45,235,238, 81,150,193,212, 6, 37,231,174, 35,162,103,
+ 55,244,236,217, 5, 21, 21, 55, 16, 22,106, 69,239,222, 33,104,215, 54, 2,146,192, 64, 84, 86,214,226,200,209,147,184, 84, 86,
+141, 14, 93, 6,220,179, 3, 8, 5, 40, 33,144,113, 92,234, 76,170,238,214,237, 83,123,176,224,173,230, 35,234,173, 42,203,202,
+202,146,173, 92,185, 82,213, 80, 1, 88,190,124, 57,151, 96,200,173, 60, 74, 41, 37,132, 16,133, 34,204,169, 77,244, 22, 98,206,
+206,182, 77, 17, 76,157, 58,149,151,251,191,254,148, 66,174, 75,242,231,139,216,216, 88, 89, 65, 65,129,138,243, 58,140, 26, 53,
+ 74,230,234, 56, 23,140,231,137,176,185,185,245,131, 7, 15,169, 8, 33, 32,132, 96,200,144,193,178, 33, 67,134,168,157, 20, 4,
+251,185,128,167,247,133,147,199, 76,211,130,147,151, 56,182, 71,189, 7, 53,109,197, 9,135, 60, 62,240,199, 0,220, 59,240,168,
+ 0,220,141, 22, 63,135, 25, 51,102, 52,233,239, 25,134,129, 64, 96,251,244,139,100, 16, 53,200,138, 0,177,196,166, 0,136, 68,
+ 24, 57, 2, 8, 8, 0, 68,130, 0,180,105, 35,129, 64,160,131,213,202,130,101,189,119,219,235, 53, 87, 33,233,210, 23,231,148,
+255, 65, 91, 33,131,167, 22,191,230,245,128, 18, 24, 24,168,126,237,181,215,100, 77, 89, 6, 40,151,203,149, 10,133, 2,207, 61,
+247,156, 99, 31,103,233, 87, 87, 87, 67,175,215, 35, 37, 37, 5, 0,240,249,231,159, 35, 51, 51, 83,117, 39,158,109,114,114,178,
+154,101, 89, 25,103,249, 15, 31, 62,188, 73, 1, 92, 93,186,247, 65, 81,193,110,180,107, 19,132,160, 32, 91,183, 55, 26,173,168,
+174, 49, 65,163, 53,160,107,207, 1,120,112,100,156,199,103, 50,105,210, 19,100,207,247,255, 71, 11, 10,143, 99,244,168,193,232,
+222,189, 59,204,166, 58, 68, 13,185, 31,193, 33, 33,184, 80, 82,138,178,203,149, 56,152,255, 59,180, 53, 33,152, 18, 27,119,207,
+250, 76,231,166, 41, 0, 64, 5, 16,204, 85, 40, 28, 4,206, 54, 32,125,134, 33, 54,109,193,206,203, 4,192, 96, 23,243,141,105,
+ 10, 5, 5,133, 83,164, 10, 65,106,106,106, 61, 47,192,188,121,243, 64, 8, 65, 90,154, 66,197,177, 63, 8, 48,120,240, 16, 87,
+228,229,112,199,123, 34, 57,190,228,223, 16, 83,167, 78,197,184,113,227,100, 77,233,199,176,207,213,143, 24, 49, 66, 54,107,214,
+ 44,117, 99,199,157,230,246, 27, 5, 23, 59,192, 41, 95,182,105, 4,162,110,168, 84,240,109, 95, 67,121,155, 95,108, 97,187,233,
+146,246,142,115, 54,191, 88,234, 80, 8,118,255,226,126,236,115,149, 7,192, 31, 3,112,143, 42, 0, 35, 71, 13,191, 45,115, 62,
+205,101,249, 59,119, 36, 95,160,209, 18,116,108,207, 56, 82,254,238,201,181,205,239, 7, 4, 72, 16, 32, 14, 64,194, 67, 4,146,
+ 0, 49, 2, 37, 4,154, 10, 1, 10,143,180,132,149,181,162,107, 23,239,230,117,149, 74, 37,173,212, 27,160, 45,218,137,222, 93,
+ 69, 56,246,255,236,125,121,124, 19,213,250,254, 51,147,189, 43,109, 41, 45,123,161, 80, 65,182, 2, 5, 17, 89, 18, 40,160, 44,
+149,173,200,166, 95,228,122, 27,112,187, 44, 42,138,222,159,222,235, 5,197,171,130, 87,174, 80,184, 42, 42, 84,108, 43, 75,193,
+ 66,161,144,176,136, 90, 40,149, 85, 40, 80,150,210, 2, 45,109,154, 54,205,158, 57,191, 63,210, 9,105, 72,155, 73, 26, 86,231,
+249,124,242, 73,114,102,242,102,230,204, 57,231,121,223,247,188,231, 61, 37,190,207, 11,211, 52,173,238,223,191, 63,213,191,127,
+127,159,101, 36, 39, 39, 43, 86,174, 92,169, 98,221,252, 21, 21, 21,207, 60,246,216, 99,186,221,187,119,255,244,244,211, 79,143,
+172,168,168,160,158,125,246,217,156,228,228,100,197,189,108,156,117,174,126,133,211,103,223,219,156,157,220, 73,225,153,211, 40,
+ 45,186, 12,154,166, 96,179, 17, 72,101,225,136,235,218, 29, 19,198, 39,115,110,232,165,229,140,162,178,162, 84,101, 52, 90,209,
+163,123, 71,180,110,213, 28, 87,138,111, 64,115,226, 2,206, 22, 94,193,158,189,199,113,185,132,224,133,191,190,226, 83,231,185,
+ 95,146,255, 48, 63,132,249,124, 94,239,165, 28,229, 93,248, 26, 43, 86,172,112, 40, 0, 43, 86,172, 0,138,214,221,118,174, 59,
+121, 13,120, 5,110, 27,179,154,154,172,135,162,168, 38,181, 61,150,228, 27, 34,119, 79,199,221,121, 21, 92,126,235, 78, 30,247,
+231,124,249, 71,100,174,120,206, 62, 54, 12,107, 87,143,252, 1, 32,121,116, 63,251, 7,205,239, 30, 21, 0, 62, 15,192,253,131,
+ 53,203,222,188,109, 26,192, 43, 5,224,126, 14,248,240, 53,249,143, 51,142, 28,149, 64, 42, 22, 99,220,104, 10, 52, 69,161,127,
+130, 21, 39, 78,202, 64, 83,246, 57,255,170, 42, 26,173,162, 5,160, 41, 49,142,157, 16, 67, 42, 1,204, 22, 51, 46, 95,145,121,
+ 69,254, 23, 10, 11,240,216,240,177, 16, 54,127, 12, 23, 10,243, 32,188,158,137, 55, 94,127,139,124,244,239, 15,238, 73, 5,215,
+229,171, 87, 36, 36, 36,168, 22, 45, 90,132,238,221,187,151,105, 52, 26, 36, 36, 36, 40, 52, 26, 13, 94,125,245, 85, 85,114,114,
+242,125,145,215,190,169,196,239,170, 4, 12, 26, 56, 20,235,190,251, 82,222, 50,186,165, 42, 48, 48,144,147,213,127,219, 0,251,
+220, 95,212, 0,168, 13,235, 83,201,233,179,191,161,101, 84, 16,164, 82, 17,116, 58, 51, 74,174, 85,131, 18,182,197, 11,127,125,
+142,143,150,226,130,163, 11,129,216,231, 81,111,121, 97,254,130,166,144,117,147, 47,105,206,156,112, 39, 69,194, 63,132,230,137,
+148,189, 33,237,166,230, 51,112, 87,103,201,143, 75,236,247,106,184,102,127,241,120, 96, 17, 31, 31,239, 8,248, 91,179,236,205,
+219,142,121, 84, 0,252,157,143,255,110,231,247,247,170,241,131,130, 70, 67, 33, 32,154, 66, 68, 56,133,132, 62, 22, 72,197, 2,
+ 72,196, 22, 68,132, 75,235, 6, 1, 10, 3, 18,108,200, 59, 42,178,123, 11, 56, 14, 50,185,185,185,164,219, 35, 33, 88,248,183,
+127,194, 32,110,131, 77,185, 37,136,141,179, 91,238, 65,135,183, 99,225,107,111,145, 79, 62,190,119, 74, 64, 98, 98, 34,149,155,
+155, 43, 95,182,108,153,202,217, 59,224, 15,229,234,126, 70, 93,178,159, 38,223,227,140,153, 74,234,224,161,125,164,188,162, 28,
+134,235,122, 72,165, 17,104,211,161,167, 79, 74,197,131, 6,123, 58,108, 63,221,102,209, 58, 56, 86, 4, 20,125,115,207,239,205,
+ 83,112,223,195,134,145, 99,159,241,202,114,247,228,123,228, 99, 0,238, 47, 37,160, 33,242,247,232, 1,248, 51,128,192, 30,213,
+ 79,209, 4, 4, 4,225,205, 8,246, 29, 20, 66, 42, 22, 65, 34, 22, 34,105, 52, 1, 33, 12,194, 34,172,176,218, 40, 48,140,173,
+110,240,243,140,158, 49, 58,140,153,148, 12,157,176, 51, 90, 4, 5, 98,250,132,112,164,109, 62,225, 80, 2, 44,182, 77,247,252,
+254, 89, 69,128,239, 50,190,123, 21, 30,214,123, 91,163,249,144, 74, 9,123,243,118,102,200, 8,247, 85, 30, 82,194,222,188,253,
+ 64,254,130, 38, 89,253, 60,154,134,201, 47,173,244, 91, 27,126,216,141,135, 7, 77, 9,240,104, 0,199,199,199,243,147, 54, 60,
+120,240,224,193,131,199,159, 12,124,162,103, 30, 60,120,240,224,193,131, 87, 0,120,240,224,193,131, 7, 15, 30,188, 2,192,131,
+ 7, 15, 30, 60,120,240,224, 21, 0, 30, 60,120,240,224,193,131,199,195,129,122,171, 0,230,206,157,235,115, 4,167,187,220,218,
+254,150, 55, 99,246, 28,143,191,171,173,188,238,248, 28, 24, 30,237,248,188,225,171,213,183,157, 27,169,120,193,163,188,221,203,
+111,101,204, 27, 49,127,165,227,115,185,234,127,240,229,250, 26,130,175,215,215, 16,220, 93,223,248,103,149, 30,127,119, 68,245,
+ 19, 98, 98, 98,112,233,210, 37, 36, 40,198, 56,202,183,124,151,122,199,235,239,133,107,215, 26,109, 47, 38,161, 80,190,176,164,
+196,177,100,113,101, 84,148,227,252,255,181,108,121,199,219,159,171,188,172,172, 44,121,118,118,118,189, 76,137,163, 71,143, 86,
+ 36, 37, 37,169,239, 69,255, 40, 40, 40,240, 89, 94,239,222,189,239,244,245, 81,115,231,206,197,253, 60,190,220, 11,121,105,105,
+105,211,122,244,232,145,118,226,196,137, 73,211,167, 79,223,212, 84,121,206, 27, 29, 57, 71,228, 63,136,245,231,239,246,252,103,
+147,231,181, 2,224, 10,171,213, 42, 55, 26,141,160, 4, 34, 80, 20, 5,155,213, 2,177, 72, 8,137, 68,162,110,170,230, 97,181,
+ 90,229, 0, 32, 20, 10,155, 36,171,182,242, 58, 2,195,163, 29,196, 31,221, 54, 6, 0,112,189,248,146, 79,242,118, 47,127, 25,
+ 35,230,175,116, 16,215,127,179,242, 0, 0, 47, 37,245,199,195,136, 35,170,159,144,160, 24,131, 35,170,159, 0, 0, 99, 38,207,
+ 0, 0, 92,186,116,239,235,239, 63, 55,110,200, 11, 1, 85, 28,160, 40, 4,236,123,168, 47,122, 3, 0,208,127,217, 71,247,180,
+222,212,106, 53,201,206,206,134,209,104,172, 87, 46,149, 74, 85, 33, 33, 33,144,203,229,247,229,114, 40,138,162, 6, 61,210,161,
+245, 55,196,102,211, 23, 94,185,254, 22, 33,100, 59,111, 7, 53,162,116,154, 76,195, 10, 10, 10, 66, 74, 75, 75,163,195,195,195,
+155,245,237,219,183, 36, 56, 56,248, 59, 95,229,165,165,165, 13,159, 62,125,250,190,180,180,180, 23, 0,132, 78,125,126,206,108,
+ 0,204,137, 19, 39,158, 3,176, 5, 0,227,141, 60,118,207, 19,150,248,155,210,223, 92,119, 73,244,215,146,190,134,148, 18, 30,
+247,153, 7,192, 25,213, 53, 58,121,203,184,126,170,161, 61,186, 32, 64, 34, 2, 33, 4, 54, 27,193,201,115,151,113,241,248, 1,
+133, 76, 34,130, 64, 32,240,137,188,131,164,151,228,221, 58, 23,169, 78, 22,118, 84,212,154, 98,124, 38,126, 0,144,133, 70,160,
+182,242,186,131,248, 27,243, 8,112,177, 84,251,207,120, 19,187,151,191,236,232, 72, 13,157,215,216, 26, 75,215,255, 20,139,197,
+ 0,236,105, 50, 25,198,222,191,109, 54,155,227,250,105,129,136,179, 21, 13, 0, 45, 91,216, 83,117,154,171,171, 96,178, 90, 1,
+ 0, 58,171, 93, 94,135,145,127, 65,167,110,189, 57, 17, 63, 0,244, 26, 56, 28, 71, 84, 63, 57,136,191,161,243,238,102,253, 1,
+192,203, 55,110, 16, 0, 24, 21, 24,136,156,218, 90, 21, 75,252, 0,112,118,215,238,219,206,139,111,217,146,211,117,106, 3,111,
+202,243,111, 30, 70,201,149, 99,232,220,126, 0, 6, 72,229, 94,183,225,172,172,172,167,119,236,216,193,146,191, 21,128, 17, 64,
+ 0, 0,198,104, 52, 10,101, 50, 25,170,171,171,229,238, 60, 1,247,152,252,163,250,197,247,216,145,243,253,234,160,218,146, 63,
+ 48, 40,121,110, 26, 69, 81,207, 17, 66,182,220,111, 3, 83,110,110, 46,105, 74,126, 10, 46,155,129, 53, 6,139,197, 34,207,203,
+203, 83,157, 58,117,202, 81,118,243,230, 77, 20, 22, 22,162,101,203,150,223,202,229,114, 69,112,112, 48,215,231, 75,167,165,165,
+253, 3,192,227,131, 70,141,151,165,165,165, 69, 77,125,126, 78, 48, 0, 27, 0,182,225, 62, 82,119,222, 16,174,247,199,246, 55,
+165, 82, 73, 26,234,111,236,121,158,250,155, 82,169, 36,251,127,201,131, 64, 32,132,205,102,133,182, 70,135,233,147,158, 38, 31,
+127,252,113,147, 8,219, 85,169,104,234,115,225,225, 25,238,182,253,101,193, 41, 19, 96,173,193, 44, 31,158, 52, 93,213,182, 69,
+ 40, 2,164, 66, 48, 12, 3, 27, 3, 8, 5, 20,194, 67,187,160, 91,231,118,170,220,156,159, 20, 54, 75,173,220, 91, 37,192,108,
+ 54,203,187,118,187,168,234,213,229, 34, 4,180, 77,165, 62,210, 90, 33, 22,137,188,146, 81, 91,121, 29,178,208, 8,132,134, 4,
+ 3,128,227,221,221,121,209,109, 99, 60,122, 3,118, 47,127, 25,253,103,188,137,255,123,102, 34, 0, 56,222,221,157,247,223,172,
+ 60,175,180,107,129, 64,128, 54,109,218, 64, 32, 16,192,108, 54,163,182,182, 22, 54,155, 13, 26,141,198,167,135, 27, 36, 20,224,
+171, 21,155, 33, 9, 5,110, 92, 2, 14,235, 74, 80,126,253, 60,190, 91,254,150, 87, 86,127,175,129,195,209,166,149,125,138,164,
+141, 27,242,143,137,137,113, 76, 7, 0,192,213,171, 87,253, 82,127, 92,146,171,190,124,227, 6, 25, 21, 24,136,247, 95,126, 9,
+ 0,240,190, 19,241,175, 47, 44,172, 79,254, 94,100,107,221,119,105,189,188,253,243, 66,213,155,237,102,194,196, 36, 66,194, 16,
+252,113,115, 15,190,254,119,186, 98,114,207, 84,174,109, 80,152,157,157,189,197, 96, 48, 96,221,186,117,198, 89,179,102, 73, 1,
+ 4, 1, 96,214,173, 91,103,158, 53,107,150,208, 96, 48, 64, 42,149,170,146,146,146,154, 52,208,109,218,180, 73,190,107,215, 46,
+ 85, 83,115,217, 59,218,142,152,254,127,159,191,255,134,172,217,233,239, 33, 59,187, 23,239, 13, 11, 11,126,117, 91,249, 63,235,
+ 44,207,251,138,252,211,211,211,161,209,140, 32, 25, 25,201, 94,223,251, 87, 95,125, 37,111, 10,217,212,214,214,202,179,178,178,
+ 84, 53, 53, 53,110,143, 95,187,118, 13,153,153,153,170,174, 93,187, 42, 6, 12, 24,224,169,221, 80,105,105,105,223, 13, 26, 53,
+126, 74, 97,193, 33, 97,155, 86,209,214,169,207,207,169, 55,238,238,253,105, 19,122,244,232,209, 37, 45, 45,237,169, 30, 61,122,
+100, 1,192,193,131, 7, 27, 37, 85, 46,253, 77,169, 84, 18, 80, 20,224, 33,203,223,234,213,171,201,245,178,155, 40, 56,121,218,
+ 81,102, 52,154,240,209,231,107,116,202, 89,211,120,194,126,136,113, 91, 16, 96, 77, 77,141,124,208,200, 9,170, 46,237, 34, 32,
+ 17,209, 96, 24, 6,215,175, 95,199,137, 99, 5, 48, 91, 25, 48, 12, 65, 68,104, 0, 70, 62, 53, 86,101, 48, 89,189,254, 67,137,
+168, 12,177,237,174, 3, 2, 10,143,118, 46,134, 68,120,195,107,203,223,153,252,111,179,240,170,107,112,189,248, 18,100,161, 17,
+ 13,122, 5, 26, 35, 47, 87,124,243,195, 38,188,148,212, 31,253,103,188,217,160, 85,235, 14, 98,177, 24, 2,129, 0, 33, 33, 33,
+ 40, 42, 42,130, 70,163,177, 43, 82, 62,146,127,203, 22, 81, 8, 18, 10, 48,225,149,127,225,169,233, 3,177,253,100, 9,174, 27,
+208,100,242,119,197,213,210,235, 56,117,228,103, 68,134,133,216,201, 95, 40,240, 75,253, 61, 57,233,255, 0, 0, 97, 66,145, 87,
+228, 15, 0,127, 95,249, 95,252,125,229,127, 29,228,159, 83, 91,139,215, 71,142,181, 31,140, 20,115,186,239,111, 46,127, 40,255,
+235,194,199, 85,207,183,127, 17, 34, 58, 8,129, 8, 0, 13, 1, 90, 71, 61,129,151,223, 95,160, 42,106,181,156,147, 26,161, 86,
+171, 45, 0,240,205, 55,223,232, 1, 72,217,109,148,215,173, 91,199, 0, 8,112,222, 86, 89,173, 86,251, 52, 47,167,215,235,229,
+222,148,115,176,252, 7,245,235, 19,175,207,216,180, 89,217,187,123,156,160,246,244, 30, 92, 42,171,193,181, 42, 61, 24, 66,124,
+ 10, 4, 78, 73, 73, 33,201,201, 25,100,195,134, 13,126, 77, 36,230, 68,254, 8, 15,207,245, 73, 70, 94, 94,158, 42, 53, 53,149,
+162, 40,202,161, 12,120,121, 13,183,145,255,145, 35, 71, 48,125,250,116,103, 15, 1,206,156, 57,163,210,235,245,141,110,152,149,
+150,150,246,242,160, 81,227,199, 46, 89, 60, 95,152,145,145,129,255,125,254,177,176,206, 99,228, 32,255,140,140, 12,172, 92,185,
+ 18, 61,122,244,200,242,212,223, 92,201,191,161,254,246,212, 19,117, 94,192,224, 64,143,242, 62,249,124,149,131,252,203,110, 86,
+160,236,102, 5,180, 53, 58,136, 68,194,160, 85,235,190, 55,186, 90,241, 60, 30, 12,196,199,199,223,246,106, 84, 1,176,217,108,
+ 36, 34,166, 39, 98,162,155,193,104,177,129,162,128,156,156,157,248,246,155,117, 56,126,236, 24, 94, 95, 48, 15, 2, 1, 13,198,
+198, 32, 36, 64,130,152,158,131, 84, 6,131,129,115, 7,179, 88, 44,242,110,157, 47,171, 66,130,244,248,234,155, 50,208, 20, 65,
+255, 30,103, 85, 22,139,197,171, 78,234,142,252, 89,226, 55,104, 43,234, 41, 8,218,234, 26,143,242,220,117, 38,182, 35,229,109,
+248,176, 30,193,125,243, 3,183,244,189,177,177,177,136,136,136, 64,117,117, 53,196, 98, 49,104,154,134,193, 96,128, 70,163,129,
+ 64, 32, 96, 7,102,206,247,252,227,150,205,152,183, 98, 23, 54,127,254, 14, 90,182,136, 66, 64, 96, 56,138,109, 37,248,110,249,
+ 91, 8,170, 27, 52, 4, 28,229,185, 35,127,150,248,181,165, 23,208,165, 77, 11,212,232,141,144, 4, 72, 0,155,205, 99, 60,128,
+167,250,123,107,237,118,156, 58,250, 11,186,119,124, 20, 90,155,103,165,145, 37,255,179,187,118,227,239, 43,255,235, 40,207,169,
+173, 69, 78,109, 45,138,148,255,192,174,211,199,209,173,127, 71,160,194,243,214,204,105,231,150,201,231,190, 58, 92, 21, 25,216,
+ 21, 6, 82, 3,152,202, 32, 54, 85,194,100,171,129,145, 49,128, 17, 7,161,245,224, 4,100,254,190,212,211, 64, 71,109,220,184,
+ 17, 70,163, 17, 74,165, 50, 64,169, 84, 2,246, 41, 0, 40,149, 74,212,125,175,179,160,140,216,184,113,163,215,157,246,204,153,
+ 51,242, 5, 11, 22,168, 62,251,236, 51, 66, 81,148, 10, 0, 14, 28, 56, 64,150, 46, 93, 74,222,121,231, 29,159,182,102, 14,150,
+208,235,254,251,230,243,178, 81,173, 77,130, 67,103,174, 99,251, 37, 26,111,238,184, 97,250,135, 90,167,173,181,224,255,124,145,
+169,209,140,184,147,150, 63,194,195,115, 49, 99,198, 12,175,119,163,116, 38,252,213,171, 87, 83,236,118,210, 92,113,232,208, 33,
+249,141, 27,220,140, 18,179,217,140, 19, 39, 78,236,109,172,189, 0,144,183,105, 21, 45, 78, 78, 78, 6, 0,228,231,231, 99,239,
+ 79,155,164, 87, 75,175, 51, 44,249, 3, 64,114,114,178,163,191,157, 56,113, 98,121, 83,250,219, 71,179,198,226,228,133, 98, 68,
+119,108, 9,212,234, 57,223,123,217,205, 10, 88, 44,214,186,177,218, 10,139,197,138,226,203,151,164, 77,121,166,174,222, 3,222,
+155,112,127,161,158, 43,202,100, 50,161,119,151, 46,170, 0,153, 8, 12, 67, 96, 99,128,159, 15, 28,196, 63,222,255, 23, 24, 2,
+156, 59,127, 30,199,143,253,142,238,221,123, 65, 32,160,240, 72,199, 54, 40, 58,106,133,140,227,230,120, 98, 97, 25,226, 98, 74,
+ 1, 33,133,226,107, 22, 64, 72,161,103,151,203,200, 59, 81, 6,130,214, 62,221,128,179,123,223,157,103,192,160,173,168,183, 26,
+192, 19,156,221,251,238, 52,237,188, 13, 31, 98,196,252,149,110,163,216,157, 97,181, 90, 17, 16, 16, 0,154,166, 17, 22, 22, 6,
+189, 94,143,218, 90,251, 54,192,145,145,145,168,168,168,240,106, 3, 14,163, 6,232, 47,147,225,245,207, 15, 96, 68, 47,224,114,
+ 1,112,184,238,216,235,159, 31,192,127,230, 43, 96, 99,108, 94,215,223,169, 35, 63, 59, 62, 15,239,219, 5,194, 96, 26, 57,234,
+211,232,221,165, 45, 66,130, 36,248, 38, 51, 23, 9,138, 49,184,234,102, 21,128,167,250,203, 58, 77,128,107, 64,210,112, 10,107,
+183, 23, 33, 34,172, 3, 38, 62, 65,113,170, 63,214,221,159, 83,123,107,235,100,242,222,114,160,181, 22,212, 95,223, 5,249,199,
+251, 0,109, 0,149,183, 20, 43,163,162,168,255, 53, 50, 17, 16, 59, 41, 72,213,190, 89, 95, 84,219,116, 48,105,206,227,187, 43,
+105, 56,152,164,193,163, 47, 40, 48,242,149, 32,200,194, 30,129, 84, 24, 6, 97,146, 22,135, 55, 29, 38,253, 18,250, 53, 52, 72,
+ 57,254,131,166,105, 16, 66,204,117, 74,180,145,166,105, 61, 33, 36, 28,246, 32, 46,159,151,215,118,233,210, 69, 61,114,228, 72,
+ 69, 69, 69,133, 42, 39, 39,199,174,248,228,228,160,107,215,174,232,210,165,139, 79,219, 51,215,152,152, 87,103,255,253, 63,219,
+254, 61, 38,154, 38, 70, 45,254,186,161,208, 98,181, 88, 86,154,108, 88, 74, 8,169,244, 69,230,248,241,230, 59, 78,254, 67,134,
+ 12, 81,123, 43, 39, 47, 47,175,222,148, 9,235, 5,224,186,171,164,205,102,243, 74, 97,184,120,241, 34, 30,123,236,177,134,218,
+139, 20,192,163, 0,132,195,198, 76,172, 42, 42, 42,106,150,159,159,143,140,140, 12,244, 45, 42,162,243,243,243, 1, 0,125,251,
+246,197,147, 67, 19, 16, 18, 36,193,202,175, 55,151, 77,159, 62,125,241,170, 85,171,230,123,219,223,174,109,249, 16,193,221,164,
+ 8,234, 60, 15,233, 31,190,128, 94,221,163,241,200,216,127, 33, 53, 53,149,114, 23,101,239,108, 60, 73,165, 18, 0,128, 72, 36,
+132, 94,111,244,235,179,229, 73,255,222,192,235,205,128, 24,134, 65,128, 68, 12,179,149,128,166, 0,154, 2,222,253,231,191, 96,
+ 99,128,218, 90, 29,174, 95,191,134,168,168,104, 16,194,192,106, 5,164, 34, 33, 4, 34,110, 46, 88,171,213, 42,127, 52,246,170,
+170,121, 88, 53, 64, 81,118,221,152, 2, 40,138,160, 79,183,115,170,223,142, 71, 41,188, 93, 17,192, 90,247, 13, 77, 9,112,177,
+254, 93,181,232,134,136,223, 27,235, 31,176, 7, 12,181,104,209, 2, 18,137,196,225, 50,100, 3,255, 66, 67, 67, 33, 18,137, 80,
+ 92, 92, 12, 17, 71,121, 95,231,238,195, 11, 99,135,130, 53,111, 10,173,118,247, 63, 0,200,227,128,144,127,169, 48,255,181,129,
+ 8,243,226,126,175,150,218,131, 21,219,181, 8,135,198,100,130, 48, 68, 0, 99,185, 30,160,105,180,108,223, 6,187,246, 30,246,
+169,254,254,111,225, 18, 92,252,121, 15,132,215,129,170, 40, 32,128,166, 49, 32,166, 3,134, 13,141,226, 36,199,117,174,127,253,
+ 51, 47,224, 71,211, 89,160,147, 17,248, 77, 8, 4, 9,129,113,125,209,102, 28, 55,227, 53,182,117, 56,204,230, 74,136,172, 22,
+124,119, 37, 13,191,204, 10,197,144, 9, 79,163, 75,139,174,138,147,187,212,170,222,201,181, 16,153,107, 97,237,194,160,252, 6,
+183,160,209, 58,229,205, 56,107,214,172, 32, 0, 26, 66,136, 8, 0,102,205,154,213,228,220, 26, 19, 39, 78, 84, 31, 60,120, 80,
+241,199, 31,127,168, 2, 2, 2, 16, 16, 16,128, 25, 51,102,248, 52,136, 82, 20, 21, 61,118,236,216,181,175,189,246, 26,253,250,
+252, 87,153,238,204,121,218,100,182,212,154,109,228, 53,111,228,164,164,164, 16,141,102, 4,198,143, 55, 99,198,140, 25,148,175,
+215,115, 39,201,223,157,187,127,245,234,213,148, 82,169, 36,179,103,207,230,116,189, 58,157,174,158,219,223, 25, 11, 22, 44,192,
+130, 5,246, 77,139, 18, 18, 18,156,207,151, 52, 32,174, 21,128,152, 58,165, 48,224,201, 73, 51,141, 29, 59,118,148,102,100,100,
+128, 37,255,228,228,100, 68,181,108,233,220,223,182,195,105,138,128, 75,127, 75, 25, 55, 4,191,150,150, 33,184, 87, 48, 74,114,
+ 46, 0, 82, 9, 38,189,242, 28,194,219,140,229, 56, 54,219, 80,114,237,134, 85, 36, 18, 10, 89, 15, 0, 0, 20, 95,190,212,164,
+231,218,208,212, 1,175, 16,220, 59,133,192, 85, 9,160,221,153, 56,132, 16, 48, 60,100, 20,197, 0, 0, 32, 0, 73, 68, 65, 84,
+ 4,176, 49,118, 37,128,162,128, 77, 63,102, 98,194,196,201,104, 30,217,194, 49, 0, 18, 47,246,202, 22,208,101,232,214,169,216,
+241,189,103,247, 0,135,147,172,207,163, 69, 16,208,101, 94,223,144,171,187,223,221,113,111,172,127, 87,119,191,187,227,206,107,
+217, 27, 67,117,117, 53,106,106,106, 96, 50,153,192, 48, 12,202,203,203, 29,238,127,189, 94, 15,157, 78,231,213, 20,192,230,207,
+223,129,250, 36,160,189, 4, 88, 12,192,127, 22, 41, 28,238,255,163, 5,192,239,215,126,134,192,203,250,211,150, 94, 64,120,104,
+ 32, 34,194, 3,241, 72, 92, 87, 20, 93, 44, 71, 97, 73, 5,218, 69,132,194,116,163, 12,231,207,157,175,151, 11,128, 75,253, 13,
+148, 63,141, 65,138,105,216,188, 45, 29,170,253,233, 72,251,116, 33, 38, 45, 92,138,227, 22,160,188,162,140, 83,253, 57,207,245,
+ 63, 63,240, 49,204,120,180, 61,210, 55,239,197,241,227,151,240,233,137,124,108, 28,241, 28,240,229, 33,148,148,148,215,203, 5,
+208, 16,218, 24, 37,176,153,111,194,108,214, 2, 0,162, 90,183, 69,151,174, 93, 21,213, 50,123, 44,134,129,209,131, 54,213, 66,
+ 86, 43,192,141,107,215, 61, 17,170,221, 35, 99, 52,194,104, 52, 74, 1,152, 1, 4, 27,141,198, 16,215, 37,129,190, 66,175,215,
+203,247,239,223,175,234,218,181, 43,102,206,156,169,184,121,243, 38,114,114,114, 56,119, 54,138,162, 6, 73, 36, 18, 93,112,112,
+176,117,196,136, 17,215, 22, 45, 90,212,106,241,226,197, 69,135, 11,142,143,222,120,202,116,198,194,192,235,253, 88,239,132,203,
+223,159,228,239,106,253,179, 49, 10,206, 94, 0, 46, 50, 68,162, 91, 42,249,167,159,126,234,120,185,251, 14, 56, 86,248, 52,244,
+108,196,117, 47, 26,128, 80, 91,122,193,173, 59,157,237,111, 5, 71, 11, 46, 78,159, 62, 61,197,155,254, 54,184,223, 35, 72,124,
+ 34, 14, 75,254,249, 49, 62, 89,145,141,255,183,126, 47,230, 12, 75,192,245,173,217,208,106,170, 61,146,109,106,106, 42,149,156,
+244, 36, 44, 22,107,129,197, 98,181, 58, 43, 0, 0,176,244,221,183,124, 38,108,158,232,239, 45,220,205,253,187,122, 5,234, 41,
+ 0, 52, 77, 67,171,211, 67, 64, 83,176, 90,109, 96, 8,129,149,177, 7,145, 30,251,189, 0,195,134,143,178,187,201, 8,129,128,
+ 22,160, 70,111,134,213,108,242,172, 97,218,108,242, 14,173,175,169, 34,195,181, 14, 45, 99, 96,255, 32,123,183,161, 40, 80, 20,
+ 65,239,174,231, 85, 86,155, 77,206,245,230, 88,235,190,177, 96, 64,159,172,215, 70,130,107,188, 65, 88, 88, 24,202,203,203, 33,
+145, 72, 80, 83, 83,131,200,200, 72, 71, 80,160,209,104, 68, 85, 85,149, 87, 10, 64,202,146,141,248,207, 34, 5, 66, 99, 0,245,
+ 73,224,213,101, 42, 4, 9, 5,152,248,183, 15,112,149,185,142, 13,159,190, 1, 1,205, 93, 30,107,253,247,237, 27,135,200,142,
+ 49,104, 17,217, 28, 98,154,130,149, 34, 40,175, 53, 64, 83, 99,244,169,254, 62,249,112, 11,198,119,237,128,144,144, 8, 4, 68,
+182,130,165, 82,131,130,237,223,163,170,242,138, 79,141,248,171, 15, 95, 6,230, 39, 66,104, 53, 35,166, 22, 40, 19, 84,227, 63,
+215, 14, 3,226, 16,206, 50,142,110,251, 85,113,147, 54,224,138, 88,143,132, 78, 10, 60,250, 92, 16,138,194,212,170,200,200, 2,
+ 85,219, 1, 69,208,210, 53, 48, 17, 3,244,235, 25, 72,131,130,185, 88,254,206, 3, 60,187, 10, 64,236,175,142,187,115,231, 78,
+ 0,192,140, 25, 51, 20, 93,186,116, 81, 79,152, 48,193, 97, 49,114, 33,255,200,200,200, 29,107,215,174, 13, 76, 77, 77, 21,204,
+159, 63, 31,243,230,205, 35,135, 14, 29, 26, 64, 8,201,209, 91, 72, 87, 66,200,111,222, 91,115, 97, 13,186,253,125, 13, 8,244,
+ 39,249,187, 18,188,179,194,178,122,245,106, 42, 47, 47,143,147,107,255,234,213,171,135,216,207,105,105,105,142,151,107, 25,139,
+240,240,112, 0,104,104, 16,188, 10,160, 10, 0,125,181,244, 58,126,249,229, 23,199,156,127,223,190,125, 1, 0, 25, 25, 25,248,
+ 33, 43, 27,154, 26,163, 30,192, 82,216,151, 6,114,238,111, 91, 55,191,135, 81,139, 94,193,232,209,195,209, 92, 34, 64, 13, 69,
+144, 83, 88,140, 95, 78,150,120, 69,212,115,103, 77,235, 87,116,254,188,176,248,242, 37,176,175,165,239,190,213,168, 37,207,227,
+254, 38,126,215, 50,119,168, 55, 5, 32,145, 72,112,238,244,113, 69, 76,171,112,149, 76, 36,132,205,198,128,162, 40, 80, 20,144,
+162,124, 9,132, 48,176,213,229, 3,208, 27,141,248,163,176, 8, 98,177,103, 39,182,213, 82,137,222,143, 94,116, 30, 69,241,226,
+252,139,248,113,125,103,135,238,156,208,253, 2,126, 61,214, 21, 66, 65,164, 87,214,191, 59,226, 55,104, 43, 0,192, 39,235,223,
+ 93, 71,203,219,240, 33, 0,112,182,254, 1,251, 58,255,232,232,104,152, 76, 38,220,184,113, 3, 54,155, 13,205,155, 55, 71, 69,
+ 69, 5,154, 55,111, 94, 87,175,220, 9,187,252,250,121,188,243, 47, 21,180,151,128,127, 47, 28, 12,157,213,134, 5,203, 50,240,
+217,162,100, 44,252,116, 59,132, 20, 5, 47,248, 31,218,210, 11,104,217,188, 25, 68, 16,193, 6, 10,215, 46,158,194,229, 50, 45,
+ 98, 35,195,177,245,232, 33,252,113, 26, 94, 91,255,147,102, 47,128, 40, 28,160, 5,192,186,236,139,248,241,139,215, 49,251,195,
+ 84, 44, 24,215, 11, 47, 13,111,239, 85,253,229,212,214,226,147,164, 41, 64,149, 20,160, 68,192, 39, 31, 99,242,225, 3,216, 53,
+124, 46,168, 15, 94, 1,245,235, 27,156,172,127, 0,248,253, 90, 4, 30, 51,104,161,147, 9,160,151, 74, 17, 59, 73, 4, 19, 49,
+ 64, 75,139, 96, 69, 28,136, 77, 15,203,205,107,248,249,115, 45,102, 76,143,189, 39,157, 54, 63, 63,159,212, 17, 3, 53,113,226,
+ 68,181,221, 55,102,199,224,193,131,169,193,131, 7,115, 33,255, 39, 90,181,106,181,243,131, 15, 62, 8, 60,119,238, 28, 68, 34,
+ 17, 66, 66, 66,112,252,248,113, 11, 33,164,188, 41,215,215,216,154,124, 95,188, 3,254, 36,127, 87,235,223, 78,172,183, 47, 31,
+228, 18, 11,144,156,156,124,238,135, 31,126, 24,104,181,114, 91,225, 36,149, 74,103, 55,114,184, 6,192, 69, 0,125, 11, 11, 14,
+193,121,206,255,197,217, 83,176,179, 99, 71,176,211, 1, 59, 58,118, 12,152, 62,125,250,215,222,244,183,103, 18, 31, 67, 40, 19,
+ 6, 61, 68,248,113,249, 43,248, 98,251,239,120,253,201, 65,152,245,105, 26, 38, 47,253,206, 43, 11,220, 57,153,144,187, 50,126,
+253,254,195,137,122, 30, 0,129, 64, 64, 85, 93, 59,143, 11,197, 21, 16,138, 4,176,218, 24, 88,172, 54, 28, 61,154,143,111,191,
+253, 26,102, 27,129,197,198, 64, 44,164, 81,166,209,161,228,143, 95, 20, 50,153, 76,237,129, 8,229, 93, 99, 47,223,178,254,237,
+ 67, 21,126, 92, 31,103, 31,227,104, 2,208, 4, 52,205, 96, 64,175, 63, 84, 54, 14, 94, 0,119,214,191,243, 42,128,192,240,104,
+175,200,223,157,245,239, 28, 85, 59, 98,254, 74,175,200,203, 62, 40,106,160,211,233, 32, 18,137, 28,214, 63,195, 48,142,119,111,
+ 21,128,239,150,191,133,163, 37,251, 16, 20,109, 15,250, 11, 22, 10, 80,126,253, 60, 66, 36, 34, 84, 85, 94,133,128,166, 32,164,
+185, 77, 63,179,214,127,219,240, 96,156, 46,186, 8,171,217, 12,137, 80, 12,157,206,136,173,170, 67, 72, 80,140,241,138,252,217,
+250,123,250,229,247,177,225, 63,159, 65,207, 0,109, 99,219,224,228,169, 95,177, 96, 92, 47,159,234, 15, 0, 22,196, 38, 96,219,
+185,189,128,214, 10, 72,155, 99,119,222,105, 80, 31,188,130,149, 81, 81, 20, 87,242, 7,128,233,157, 23,169,127,222,157, 7,152,
+107,160,163,106,160,161,117,208, 10, 45,176,216,170, 33, 49,234, 33, 45,189,136,141,139,207, 33, 38, 62, 14,141, 4, 0,214,131,
+204, 41,242, 85, 42,149, 66, 42,149,186, 61,198, 21,107,215,174,197,218,181,107,155,212,153,131,131,131, 95, 61,127,254,124, 96,
+ 72, 72, 8,100, 50, 25,194,195,195, 81, 94, 94, 14,138,162,244,254, 28, 52, 88,139, 63, 55, 55,151, 0,246,128, 64,111,130, 2,
+253, 77,254, 95,125,245,149,156,120, 94,235,206,105, 69, 64, 96, 96, 96,138, 80, 40,188,224, 90,254,233,167,159,214,179,252, 1,
+160,125,251,246, 72, 76, 76, 92,231,201,254,185, 90,122,189, 94,180,255, 59,127,159, 15,137, 80,140,168,168, 40,176,171, 3,234,
+142, 7,122,211,223, 94,144,247,196,188,143, 63, 67,205,141, 50, 68,134,180,192,169,211, 87, 48,235,211, 52,164,166,166, 82,190,
+144, 53,251, 59,231,223, 59,203,225, 61, 1, 15, 6,126,255,253,247, 70,147, 1, 53,232, 1,168, 27, 68,212,249,234, 45, 10, 66,
+146, 84, 49,173, 34, 16, 28, 32,193,163,221,227,241,104,183, 94, 16,210,128,206, 96,195,149,107,149,200, 83,255,164, 8, 10, 12,
+240,248, 7,181,122, 61,226,218, 95,131,209, 36, 5, 97,141, 26, 2,200,164, 70, 16, 2, 84, 86, 73, 0, 10, 8, 14,180,162, 71,
+220, 37, 28, 56,210, 27,193,193,193,156,173,127,103,139, 95, 22, 26, 1, 17,177, 0,214, 91,227,157, 77,232,249, 26,157,173,127,
+103,139,159, 45, 59,127,170,192,113, 46,151, 44,123,206, 74, 0, 0, 68, 71,219,149,145,202,202, 74,132,132,132, 56,220,255,222,
+ 40, 0,172, 18, 0,124,128,185,201, 67,129,255, 28,192, 23,111,143,193,228,133,159, 33,237,195,151, 32,164, 40,136, 37,220, 86,
+236,176,214,255,233, 43,101,232,212,182, 57,190,252,223, 70,196,196,196, 32,180, 85, 44,122,181,138,133,197,116,203,253, 47,226,
+ 32,147,181,254,255, 53,123, 56, 94,125,119, 29,218,118,164,154, 84,127,172,245, 63,114,243, 87,216, 53, 99, 26,168, 54, 3, 0,
+216,179, 2, 2,246, 20,193,236,185,175, 70, 69,113, 34,142,158,166, 55,168,180,143,151,201, 99, 39,214,168, 98, 58,119, 71,181,
+ 12,184,136,203,168,185, 84,142,242,165, 54,232, 52,109, 48,255,185,133,156, 31,200,170, 85,171, 40,153, 76, 70, 12, 6, 3,156,
+ 44, 79, 34,147,201,176,106,213, 42, 47,210, 19,249, 15, 53, 53, 53,255,126,233,165,151,146,214,174, 93, 43, 13, 13, 13,133, 74,
+165,194,138, 21, 43,170,205,102,243,147,254,252, 31,214,226,103,151,203,121, 27, 16,152,152,152, 72,105, 52, 35,136, 63,200, 31,
+ 0, 88, 98,231, 66, 80, 28, 50, 12,154,159,123,238,185, 1,233,233,233,199,107,107,107, 91, 90, 44,246,101,166,174,228,255,232,
+163,143, 98,192,128, 1, 99, 57, 60,103,161,182,244, 2,150,188,247, 14, 54,109,219,129, 81,131,250, 96, 79,238,175,118, 3,166,
+ 85, 44, 66, 91,197,162,111, 81, 17,158,156, 52,243,230,149, 10,253,200,118, 17, 1,153, 92,173,255,121,107,182, 97,241, 95, 70,
+162, 85,180,220,161, 92,176,247,200,197,115,227,139,119,128,247, 4, 60,184, 74, 1, 39, 5, 0, 0, 66,130,131,212, 71,213, 91,
+ 20, 23,219, 60,130,142,157,187,170, 66, 2,101, 96, 8, 96, 48,153, 81, 84, 84,132,242,162,223, 21,193, 65,129,160,105,218, 99,
+199,149, 73,165, 72,223, 57, 84,193, 70,192, 55,234,142,160,105, 4, 6,114,183,158,216, 37,128,129,225,209, 96,108, 22, 59,249,
+215,193, 66,137, 60,166,216,117, 5,187,164,102,196,252,149,245, 72,203, 23,242,119, 86, 2,156, 19,255, 84, 86, 86,122,126, 0,
+ 30,148,128,239,156, 86, 9,175, 93,250,226,173, 47, 22, 29,130, 56,202,105, 27, 30,140,244, 35,191,227,228,153,179, 72, 80,140,
+169, 71,250,222,144, 63,139,167, 95,126, 31, 63,246, 9,196,203, 19,186,248,165,254, 22,196, 38, 96, 97, 86, 58,168, 37,239, 98,
+ 71,212, 99, 88,161, 59, 89,239,248,196,208,102,104, 35,245,110, 79,138,233,157, 23,169,119,100,101,226,170,230, 2,202, 43,174,
+225, 70, 97, 16, 4,182, 16, 60,209,115, 48, 20,207, 41,238,233,160,230,143,108,127,132,144, 35, 20, 69,141,160, 40,106,247,103,
+159,125, 38, 29, 63,126,124,181, 94,175, 31,233,203,156,127, 99,240,199, 18, 64,165, 50,204, 47,228,239,106,165,250, 9, 55,167,
+ 76,153, 18, 91, 83, 83,179, 36, 63, 63,127,126, 73, 73, 9,106,107,107, 33, 22,139,209,178,101, 75, 68, 70, 70,142,239,211,167,
+207, 86,142,178,254, 0,208,183,109,120, 48, 30,127,252,113,252,126,174, 4,205, 59,116,171,215,223,158,156, 52, 83, 15,224,115,
+ 46,228,207,226, 5,121, 79,140,200,253, 13, 51,222,253, 22, 67,134, 12, 65, 84, 84,148, 91, 69,203, 95, 21,194, 42, 1,222,212,
+117, 67, 10, 25,175, 68,220, 59,210,231,148, 10, 24, 0, 66, 66, 66,212,166,202, 98,249, 81,117,161, 2,176, 71,210, 18, 66, 32,
+145, 72, 16, 26,194, 57, 7, 54, 68, 34,145, 58, 84, 36,242,251,205,177,174,126,129, 85, 15, 88,245,142, 8,120,150,248,189, 93,
+139,197,186,250,207,159, 42,192,249, 83, 5,136,140,140, 68,121,121,185, 79,196, 31, 26,217, 10,102, 14,193,145, 92, 49,227,253,
+239,112,232,128,218,111,242, 46, 93,186,228,216,237,207, 98, 50,222, 70,254,222, 16, 63,139,231,250, 4,250,173,254, 0,128, 90,
+254,134,131,248, 89,242,191, 88, 91,171,152, 24,218, 12,227, 56, 90,253,238,240, 84,135,201, 20, 58,212,125,241, 33,176,125,245,
+234,213, 20,155,237,111,213,170, 85,148,115,230,191,117,235,214, 81,171, 86,173,114,124, 94,189,122,245, 93,239,244,132,144,131,
+ 20, 69, 13,201,204,204, 92, 80, 93, 93,189,156, 16,146,231,239,255,240,199, 18, 64,127,146,211, 29,130, 33, 56, 56,120,129, 92,
+ 46, 95,208, 68, 57, 7, 79,156, 56,241, 4,128, 14,205, 59,116,211, 91, 76,198,128,186,254, 86, 13, 64, 11,224,143,118, 17, 1,
+207,192, 30, 44,200, 25, 35,222, 89,123, 87,136,191, 41,138, 22, 79,242,247, 6,241,241,241,156,200,223,163, 1, 42, 20, 10,213,
+158,220,241,119, 27,236,220, 62, 75,252,104, 34,241,179,115,211,218,178,171,208,150, 93, 69,100,100,100,147, 44,126, 0,176,218,
+ 24,175,189, 15,141,161,172, 82,235,243,181,184,130,157,219,247, 23,241,251,187,254,216,185,253,109, 58, 29,113,182,250,123, 11,
+ 69, 77, 34,254, 63, 19, 8, 33,135, 1, 76,227,107,226,222, 99,250,244,233,169, 0,190,189, 82,161,215, 91, 76, 70,231,249,200,
+144,118, 17, 1, 97,240,114,247, 63,150, 84,157,221,252, 15,144, 82,197,227, 46, 42, 1,156, 12,173,248,248,120, 62,176,131, 7,
+ 15, 30, 60,120,240,248,147,129,230,171,128, 7, 15, 30, 60,120,240,224, 21, 0, 30, 60,120,240,224,193,131, 7,175, 0,240,224,
+193,131, 7, 15, 30, 60,120, 5,128, 7, 15, 30, 60,120,240,224,241, 80,160,222, 42,128,185,115,231,250, 28, 69,234,110,187,201,
+251, 93, 94, 65, 65,129,207,242,122,247,238,125,199,229,249,251,126,155, 55,143,247, 89,222,205,155,191,223,235,231, 75,213, 41,
+172, 12,220, 36, 95,121, 16,219,223,221,146, 87,151,152,136,174,171, 67, 2,128,204,157, 59,151,225,235,143,151,199,143,207, 15,
+175, 60,175, 21,128,135, 1, 77, 77, 50, 49,101,202, 20, 57, 0,231,148,161,138,244,244,116, 53,175, 43,222, 27,104,181,218,103,
+ 79,156, 56,209, 75, 32, 16, 44,148, 72, 36,208,235,245,111, 12, 26, 52,232, 99,248, 33,211, 30, 33,196,235,108,140, 15, 34,230,
+206,157, 75,192,113,147, 25, 30,247, 14, 89, 89, 89,242,164,164, 36,181,143,191, 85,100,103,103,239,245, 71, 66,169, 58,121,207,
+100,103,103,111, 92,189,122,117, 56,236,123, 26,216,112, 15,178, 91,242,184,139, 30,128, 7, 29,185,185,185,242,166,252,126,202,
+148, 41,242,244,244,116,213,148, 41, 83,156,139, 85, 83,166, 76,241, 89, 9, 96, 21,138,140,140, 12, 54, 85,167, 87,178, 82, 82,
+ 82,136,151,255,215,232,122,224,221,187,191,246, 86,158, 66,163, 9,188, 23, 10, 16,117,242,228,201,127, 87, 87, 87,255,165,125,
+251,246,205,110,222,188,137,186,237,118, 63,250,241,199, 31, 63, 10, 12, 12, 28,246,228,147, 79,170,154,244, 7, 62,144,191, 82,
+ 57,215,235, 65, 48, 53,117, 21,117,247,228, 53,158, 14,183,161, 77, 95,184,246,175,244,244,116, 21,222,165, 64,253,211,189, 66,
+133,119, 41, 76,249, 35,217,235,122, 29, 53,106, 20, 1,128,156,156, 28,191, 16, 24,187, 21,176, 82, 25,230,247,245,241, 89, 89,
+ 89,242,236,236,108,149, 55,100,251,215,191,166, 16, 66,236, 91,171,187,195,184,113, 99, 21,217,217,217,170,164,164, 36,202,135,
+118, 60,108,199,142, 29,123,134, 14, 29,138, 57,115,230,144,180,180,180, 17,213,213,213,185,222, 92,155, 27,165, 17, 83, 7,138,
+161,156,163,172,124, 99,253,162,173, 31, 78,251,240,105,246,216,218,181,107, 26,189,198,153, 51,103, 18, 0, 8, 12,108,120,107,
+131,218,218, 90, 0,192,172, 89,179,248,252, 5,119, 9,108,114, 32,231, 28, 1, 66, 15, 29,222,109,222,108, 14,249,180,239, 21,
+154, 68, 8,206,228,159,158,158, 78, 77,153, 50,133, 56,201,245,250,126, 89,133,130, 37,154,186, 13, 63,188, 87, 40, 50,194,189,
+248,215, 68,143,103,212,142,123,145,187, 56, 47,247,181,105,136,128,188,244,202, 80, 90,173,246,135,238,221,187, 79, 2, 64, 19,
+ 66, 32,147,201, 80, 86, 86,134,170,170, 42,132,134,134,162,172,172,108,239,206,157, 59, 21, 79, 62,249,164, 87,202, 73,110,110,
+ 46, 97, 55,102,161, 40, 10,147, 38, 77, 66, 98, 98,162,130,162, 40,206,114,178,178,182, 56, 62, 39, 37,141,247,248,221, 19, 12,
+135, 94,190, 85,221, 3, 87,214,251,238, 90, 38, 27,232,121, 83, 37,118, 59, 97,103,236,223,191, 31, 75,151, 46,189,237, 89,172,
+ 95,191,158,112,172, 55,121, 70, 70,134, 10,239, 82,117, 4,155,124,251,192,253, 46,213,100, 11,241, 62, 30, 91,234, 89,218,169,
+169,169, 10, 66, 8, 54,108,216, 64, 14, 30, 60,136,158, 61,123,122,252,237,161, 6,114, 50,110,206, 88,136,236,236,108, 21,195,
+ 48, 88,179,102, 13, 60,109,171, 76, 81,148,156, 16,226,104,175, 91,183,110, 13,160, 40, 10,211,166, 77,187, 1, 32,106,250,244,
+233,187, 87,175, 94, 77,123, 99,177,127,188,251, 99,199,231,235, 57,215, 64, 81, 20,210,254, 22, 0,128,194,191,103,126,244,116,
+243,230,205, 1, 0,223,127,147,134, 57, 67,231,112,146,217,183,111, 95,116,236,216,145,103,222,251,136,252, 93, 65, 55, 54,144,
+103,100,100, 96,205,154, 53,196,221, 0,234,203,206, 80, 77,181,208, 61,201,115,178,178,125, 54, 10,211,211,211,169,244,244,116,
+138, 85, 2, 0, 40,154,162, 80, 80, 20,133,228,228,100, 16, 66, 40,167,107,243, 90, 81,161,166,104, 28, 47, 46,229,158, 16,180,
+125,149,227,197,165,220, 27,242, 39,132,128,221,157,205,211, 46,109,238,218,164, 70,163,249, 54, 52, 52,116, 18, 0,122,246,236,
+217,152, 49, 99, 6,196, 98, 49,100, 50, 25,164, 82, 41, 40,138,130, 64, 32,128, 86,171,229, 92,143,153,153,153,114,165, 82, 73,
+ 50, 51, 51,225,244, 76,240,227,143, 63, 98,206,156, 57,170,204,204, 76,249,253,216,113,221, 41, 4,247,194,179,150,145,145,161,
+ 74, 77, 77,165,158, 57, 51,197,173,133,175, 84, 42,201,148, 63,146, 21,238, 60, 3,158, 48,103,206, 28,242,250,235,175,163, 67,
+135, 14,126,185,222, 57,115,230, 16,165, 50, 12, 17, 17,123,252, 90, 15, 91,182,108, 25,158,155,155,187,183, 87,175, 94,212, 23,
+ 95,124,161,102,201,191, 41,216,156,177, 16,203,151, 47, 7,195, 48, 88,184,112, 33,184,200,116, 38,127, 0,216,177, 99,199,182,
+ 33, 67,134, 0, 64,216,180,105,211,172, 67,135, 14,133, 82,169,100,184, 26, 45,174,125,116,197,138, 21,120,230,113,187,109,152,
+246, 55, 25,166, 14, 20,227,141, 81,175,115,190,167,192,192, 64, 12, 25, 50, 4, 41, 41, 41, 84, 98, 98,162,219, 23,123, 14,111,
+253,223, 59,242,111, 84, 1, 96,201, 42, 63, 63,223,145,118,210,217,122,242,150,104, 29, 22,132,159, 7, 37, 55,202,128,194,159,
+149,151,158,158,174,242,131, 12,135, 66,145,156,156,172, 96,235,240, 97,130, 51,249, 3, 64, 73, 73,137,227,216,213,171, 87, 57,
+ 43,140, 90,173,246, 3,189, 94, 63,147,166,105,122,250,244,233,208,106,181, 40, 45, 45,133, 72, 36,130, 80, 40,132, 80, 40,132,
+ 72, 36,130, 76, 38,131,193, 96,112,155, 18,213,205, 0, 39,223,189,123,183,138,162, 40, 76,158, 60, 25,171, 87,175,166, 18, 19,
+ 19,169,212,212, 84,106,242,228,201,108,251, 81,241, 67, 69,227,228, 95, 87,151, 10,118, 16,119,126,246,201,201,201,138,196,196,
+ 68, 53,224, 91, 74,218,196,196, 68,106,245,234,213, 84, 70, 70, 6, 8, 33,126, 81,198,222,122,235, 45,100,100,100,112,106, 35,
+158,176,105,211,166, 17, 71,142, 28,201,141,137,137,129, 78,167, 35,129,129,129,228,192,129, 3, 0, 28, 65,150, 62,145,255,167,
+159,126, 10,138,162, 64,211, 52,142, 28, 57, 2, 86,166, 23, 30,137,167, 41,138,194,212,169, 83,173,117, 69,230,105,211,166, 85,
+203,229,114,204,153, 51,135,217,186,117,171,199,123,119,158, 10,187,158,115, 13,160,128, 13,175,222,202, 90,156,246,183, 0, 76,
+123, 66,130, 69, 79,190,193,249,186,184, 88,254,188,119,224,238,145,127,202,162, 15,221, 30, 23, 54,214, 33,139,138,138, 72,126,
+126, 62, 50, 50, 50,192,126,102, 93, 59,222,116,242, 59, 77,254,206, 86, 53, 59, 8,221,175,112,158, 18,120,216, 64, 8, 65, 73,
+ 73, 9,174, 95,191,238, 40,115,253,238, 1,130, 95,126,249,101,116, 92, 92, 28, 4, 2, 1,206,159, 63, 15, 66, 8,206,158, 61,
+ 11,179,217, 12,138,162, 32, 20, 10, 65, 81, 20,108, 54, 27,244,122, 61, 54,111,222,140,196,196,198,167, 61,246,236,217,163, 2,
+128,201,147, 39,223,214,110,235,190, 19,150, 40,184,180,107, 87,183,190,167,239, 92,172,124, 22, 13, 77, 7,112,113,253,187, 98,
+255,254,253,168,179, 12,155,166, 0,191, 75,129,114, 82,224, 88, 5,150,157,243,207,117, 34,127, 95,172,117, 86, 9, 99,201,104,
+207,158, 61, 42, 95, 45, 67, 86, 94,231,206,157,111, 35, 55, 95,176,106,213, 42,252,241,199, 31, 36, 50, 50, 18,173, 91,183,118,
+108,251,124,233,210, 37, 8, 4, 2,252,247,191,255,245,233, 15,134, 62, 97,223,190,140, 97, 24,188,246,218,107, 88,177, 98, 5,
+ 14, 28, 56, 0,138,162, 48, 46,233,175,184,124,137,219, 6,142, 59,118,236,216, 82,247,140,141,176,175,144, 97, 0, 96,218,180,
+105, 85, 0,154,101,103,103,131,162, 40,206, 10,149,221,250,191,125, 31, 19,251,116, 0,240,125, 90, 1,178,180, 89,114,240,120,
+224,201,191, 81, 5, 0, 0, 82, 82, 82, 40,214,234,103,201,223,237,220,159, 23,100,221,152, 37,200,101,158,216,147, 60,215,227,
+247,106, 71,170, 41, 83,166, 56,207, 53, 19,119,199, 89,207, 64,147, 72, 55, 61,204,175,215,173, 27, 59,215, 39,203,191,161,193,
+182, 77,155, 54,183,157,219,200, 51,105, 22, 30, 30,222,221,100, 50,161,178,178, 18,135, 14, 29,130, 64, 32,128,217,108,134,193,
+ 96, 0,195, 48,142, 93, 41, 45, 22, 11, 76, 38, 19,167, 41, 6,246, 57, 52,212,110, 19, 19, 19,169,204,204, 76,146,145,145,225,
+ 81,153,176, 91, 93,119, 38, 6, 64, 54,112,229,109, 68,207,126,247, 69, 17, 24, 50,100, 72,211,149, 0,151, 57,255,220,220, 92,
+185,131,236,111,205,249,251, 20, 35,227,162,132, 1,176,239,182,168, 84, 42, 9,151,231,192,213, 11, 80, 23,251,224,117,108, 1,
+187,179, 99,235,214,173, 17, 18, 18, 66,185, 42,187,221,187,119,247,217,242, 39,132,192,106,181, 58,202, 6, 13, 26,132, 3, 7,
+ 14, 96,223,207, 54,124,188,140,219, 28,123, 86, 86,214,168,186,185,255,211, 0,154, 3,112,222,108,168, 20, 64, 51, 0,200,206,
+206, 86,245,234,213,203,163,188,250,115,255,110, 60, 5,117,239, 92,229,241,184,255, 33,228,210, 57, 89,235,223, 91,203,191,168,
+168,136,248,211,221,237, 73, 94,221,180,132,223, 60, 13,107,214,172,161, 82, 82, 82,124,250,173,235,117,166,166,166,234,148, 74,
+101, 80, 67,199,125,133,243,220,191, 63,148, 1,231,185,127,174,202,192,140, 25, 51, 16, 24, 24,136,160,160, 32, 4, 7, 7, 35,
+ 52, 52,148, 9, 11, 11,163,179,179,179,241,236,179,207, 58,206,147, 74,165, 24, 57,114, 36,148, 74, 37,105, 96,183,170, 8,179,
+217,140,202,202, 74, 24,141, 70,132,134,134, 66, 34,145,192,106,181,130, 16, 2,155,205, 6,179,217, 12,139,197, 2,155,205,230,
+ 85,124,129,167, 41,171,201,147, 39,227,126,152,154,241, 20, 16,232, 45, 88, 37,192,231,246,245,207,134,235,110,202, 31,201,117,
+113, 55,190,201,118,181,254,157, 21, 73, 95,130, 1, 93,173,255,198, 20, 83,174,228, 47, 16, 8, 72, 72, 72, 8, 96, 15,168,163,
+ 0, 16,139,197, 2,173, 86,139, 22, 45, 90,248,116,223,172, 49, 37, 20, 10, 49,127,254,124, 28, 57,114, 4,183,230,253,185,183,
+233,157, 59,119,238, 28, 60,120, 48, 0, 4,195, 62,157,171, 7,128,141, 27, 55,182,216,183,111, 95, 8, 33,196,161,108,187, 91,
+103,127,155,245,255,217, 10, 76, 29,112,187,245, 63,227, 63,122,108, 60,100, 1, 33, 4,189,167,247,198,156,161,115, 40, 46,242,
+120,220,223,214, 63,192, 33, 19, 96,110,110,174,195,245,239, 28, 15,192, 5, 29, 59,118,164,146,147,147,253, 54, 39,207, 65,158,
+207,243,235, 83,166, 76, 33,174,175,220,220, 92,134, 93, 21,224,180, 34,192, 39,164,164,164, 4, 61,204, 13,110,205,154, 53,248,
+244,211, 79,235,181, 43,150,252,147,146,146,144,148,148, 4, 0,216,183,111, 95, 99, 98,194,139,138,138,140, 54,155, 13, 26,141,
+ 6, 55,111,222,132, 70,163,129, 94,175,135, 94,175,135, 78,167, 67,117,117, 53,180, 90, 45, 12, 6, 3, 76, 38, 19,108, 54,207,
+203,219, 41,138, 66,102,102,166, 87, 10,219,131,140,253,251,247,215,123, 57,227,204,153, 51,114,231,239, 92,230,156, 93,231,252,
+ 93, 45,247,166, 4,114,185,251,237,234,213,171,169,204,204, 76,191,198, 2,100,102,102,114, 30,187, 88,242,167,105,154,212,181,
+ 47,135,235,159, 97, 24,220,184,113, 3,157, 59,119,166,230,206,157,235,245,181,188,189,104, 40,246,237,219, 7,230,135,102, 32,
+132, 96,249,242,229,142,103,180,255, 16,231,184, 61,100,101,101,141, 7,128,105,211,166,149,212, 41, 0,166,239,191,223,208, 98,
+238,220,185, 45,246,237,219,135,167,158,122,106,132, 55,203, 20,175,231, 92, 3, 5, 10, 27,156,172,255,233,159,233, 33,152,170,
+197,247,135,204,152, 55,111, 30,150,237,252,136,103,214,135,136,252, 61,122, 0,214,172, 89, 83,111,222,223, 57, 30, 32, 37, 37,
+133,226,216,193,213,117,196,172,170,179,132,155,228,246,118, 39,143,117,251, 39, 38, 38,170,253, 21, 85,154,152,152,120, 50, 55,
+ 55,183,251,253,248,128, 89,171,223, 95,238,127,214,234,247,214,253,207, 98,195,134, 13,142,207,255,248,199, 63,240,245,215, 95,
+ 3,128, 25,128,152, 37,126, 0, 24, 57,114,164, 39, 5,192, 16, 23, 23, 7,189, 94, 15,179,217,140,242,242,114, 72, 36, 18, 8,
+133, 66,135, 7,160,182,182, 22,122,189, 30, 38,147, 9, 90,173, 22,147, 38, 77,242,168, 96,178,214,125, 99,203, 90,217,243,184,
+224, 78,198, 0,248,114,220, 21,236,114, 63,119, 88,190,124,185,106,254,252,249,138, 46, 93,186,168,239,101, 27,110,200,250,119,
+134, 55,177, 0, 13, 89,255,190, 90,254, 52, 77, 19,134, 97, 40, 0,239,177, 77,219,102,179,189, 27, 24, 24,136, 54,109,218,248,
+ 52,198,188,243,230, 80,168,213,106, 80,153, 17, 0,128, 93,239, 4, 99,228,191,106, 48,100,200, 16, 44, 89,182,207,171,196, 84,
+ 59,118,236,216, 60,116,232, 80, 0, 40,223,184, 49,173,245,190,125, 7,154, 17,138, 96,244, 83,163,147,146,146,146,182,121, 51,
+156, 0,246,185,255,169, 3, 69,245, 45,126, 16,204,159, 55, 31, 81, 35,163,255, 20, 9,179, 30, 58,163,108,217,155, 13, 42, 8,
+172, 7, 86,200,197,242,239,219,183,239,109,241, 0,222,184,232, 92, 73,219, 15,228,236, 42,207,239, 17,220, 41, 41, 41,221,115,
+115,115,253, 38,239, 97,237, 64,108, 98, 25,214, 77,156,145,145,129,231,159,127, 30, 0,196,236, 57,206,199,234, 6,173,134,112,
+106,192,128, 1,207,170,213,234, 12,155,205,134,234,234,106, 88, 44, 22,199,188,191,209,104,116, 44, 49,100, 3, 3, 71,142, 28,
+169,230,208, 94,168,140,140, 12, 82,231, 5,168,215,110,115,115,115,217,114, 36, 38, 38,114,242, 86,221,237, 24, 0,215,105, 1,
+ 79,207,163,177,227, 74,165,146, 44, 95,190, 92,245,204, 51,207,224,135, 31,126,240,233,153,187, 46,191,101,191,167,167,167,171,
+ 82, 74,148,152,226,193,210, 30, 53,106, 20,185,120,241, 34,118,238,220,217, 96,125, 95,188,120, 17, 0,144,147,147,227,241,122,
+146,147, 51, 72,114,242,112,140, 24, 81,132,162,162, 34,183,209,229, 21, 21,195, 1,104,160, 84, 54, 60,110,177,228,111, 54,155,
+137, 88, 44,102,207,121,175, 78, 33,120,247,242,229,203,104,223,190,189, 79,150, 63, 77, 83,118,133,157, 37,255,227, 86,124,173,
+ 50, 3, 0,150, 44,219,231,245, 24,193,246,137,185,115,231,198, 19, 66, 48,102,236,152, 73,227,198,142,219,228,203,208, 52,126,
+194,211,167, 41,138,122,148, 16, 64, 48, 85, 11, 66, 8,230, 47,152,143,232,145, 45,111, 77,124,248, 14,214,203, 76,192,103, 18,
+188,239,208,160, 2,224,188,220,207,197,213, 71, 50, 50, 50,192, 53, 96,202,149,180,253,117,225,206,242,252,176,254,159, 71, 19,
+225,236, 66,119, 38, 33, 54,159,132,235,177, 6,230, 16,173, 0,126, 28, 58,116,232, 43,217,217,217,159, 91,173, 86, 84, 85, 85,
+ 57, 98, 0, 0,160,188,188, 28, 85, 85, 85, 32,132,192,155,233,165, 17, 35, 70, 40,118,239,222,173,202,200,200, 64,102,102, 38,
+113,157,243, 31, 49, 98,132, 87,201,128,238, 4, 12,135, 94,246,154,240,221, 17,124, 99, 74, 64,106,106, 42, 53,103,206, 28,226,
+ 11,249,215, 11, 0,116,122,238, 78, 65,129,222,122, 1, 26, 84,220, 47, 93,186,228, 80,208,184, 26, 26,206, 83,149,183,223, 55,
+183,177, 74,171,213,146,208,208, 80,103,242,127,215,100, 50,161,180,180, 20, 29, 58,116,240,137,252,149, 74, 37, 97,126, 8,195,
+174,227,246,160,191,117, 42, 51, 54, 30, 50,131, 16,130, 3,191,248,206,137,251,247,239,199, 83, 79, 61,165,240, 53,125, 48, 75,
+208, 12,195,136, 0,224,135, 95, 44,152, 55,111, 30,162, 71,181,116,241, 15,120, 7, 54,203,223,144, 33, 67, 8,224,126,185,159,
+ 83, 38, 64,194,231, 2,240, 47, 26,136,175,242, 46, 19, 96,106,106, 42,181,102,205, 26,226,110,217,148, 55, 83, 0,110, 72,219,
+111,112,145,231,215,245,255, 46,233,128,189, 70,114,114, 50, 56, 4, 44,114, 70, 67,238,126, 95,167, 1, 26,114,247,251, 50, 13,
+224,156, 94,214,149,124, 26, 59,214,208,173, 82, 20,181,114,204,152, 49,171, 55,108,216, 96, 17,139,197, 48,153, 76,176, 90,173,
+ 96, 24, 6,205,154, 53,131, 70,163, 65,178,151, 75,207, 38, 79,158,172,158, 60,121, 50,181,123,247,110,146,153,153,137,140,140,
+ 12,176,121, 1,254, 76, 3,208,222,189,123,201,152, 49, 99,176,125,251,246, 38,147,191, 43,201,229,218, 21, 50,143,222,184,215,
+ 95,127,253, 54,227,194, 21,111,188,241, 6,225, 26,228,169, 84,134,121,148,167, 84,114,155,255,151,201, 28,169, 47, 9, 33, 4,
+122,189, 30,165,165,165, 62,207,249,215,243,124,252,171,166,222,247,166,144,255, 23, 95,124,225,175, 54,203,100,109,221,214,217,
+ 57, 19,160,191,208,152, 66,182,110,221, 58,158,169,239,103, 15, 0, 96, 95, 6,232, 77,249,189,196,253,182,254,223, 31, 75,252,
+110, 41, 34,137,126,187,174, 41, 83,166, 40,188, 77,239,235,129, 24,136,179, 66,227, 46,208,202,245, 24, 71,194,181,206,152, 49,
+131,218,181,107,151,252,202,149, 43, 42,131,193, 0,155,205,134, 71, 31,125, 84,145,144,144,224,243,243, 30, 49, 98, 4, 53, 98,
+196, 8,118,132,247,105,106,230, 78,199, 0,120,250,206,197,226,172,139, 14,175, 79, 56, 94, 38,153, 97,235, 8,239, 82, 36, 23,
+201,183,217,131, 41, 41, 41, 36,165, 68, 9,170,126, 34, 32, 10, 0,206,157, 59, 71, 26,233,171, 30, 43,125,248,240,225,148, 23,
+125,159,242,199, 57, 0, 80, 89, 89, 9,153, 76, 70, 40,138, 66,251,246,237, 65, 81, 20,213,185,115,103, 52,149,252,233,103, 52,
+160, 40, 10, 73, 79,219, 87, 21, 81, 20,229, 88,238,199,186,243,239, 17,152,190, 51,251,248, 85,224,172, 89,179, 88,229, 63, 8,
+118,175,158, 21,118,247, 63,227,116, 14, 63, 29,112,191, 43, 0, 15, 10,252,177,214,223, 95,132,125, 7, 20, 27,191, 94,151,191,
+ 55,246,185,211,214,115,221, 28,191,219,255, 48,155,205, 16, 8, 4, 16, 8, 4,119,177,173,173,162,238,111,121, 13,247,133,153,
+ 51,103,122, 47,240,221, 91,251, 88,100,100,100,212, 27,180, 83, 74,148,206,150,183,250, 97, 24, 75,162,163,163,169, 91,125,197,
+ 30,108,219, 84,242,183, 63,147,198,182, 2,186, 29,171, 86,253,118,215, 8,114,206,208, 57,212,221, 30, 19,120,183,255,221,135,
+187,169, 1, 42, 62, 62,158,215,196,120,240,224,193,131, 7,143, 63, 25,104,190, 10,120,240,224,193,131, 7, 15, 94, 1,224,193,
+131, 7, 15, 30, 60,120,240, 10, 0, 15, 30, 60,120,240,224,193,131, 87, 0,120,240,224,193,131, 7, 15, 30, 15, 5,234,173, 2,
+152, 59,119,174,207,145,153,238, 18,187,240,242,120,121,188,188,187, 39,111,241,226,197,245,181,123,154,118, 44,115,116, 94,106,
+198,102, 83,116, 94,122,230, 46,125,112, 80, 80, 16,164, 82,169,227,247, 52, 77, 59, 86, 92, 56,203, 99, 55,102, 98, 24,251, 42,
+ 47,118,179, 28,254,249,122, 35,143,146, 11,132, 18, 16,198, 10,134,177,170,125,145, 71, 8, 81, 28, 59,118, 76, 24, 31, 31,159,
+ 11,151,172,123, 62,202,147, 31, 59,118, 12,241,241,241,234,123, 81,127, 5, 5, 5, 62,203,235,221,187,247,159, 94,158,215, 10,
+192,159, 17,111,191,157, 87,175,226,150, 44,233, 79,221, 87,242,242,222, 38, 0,176,164,255, 18,202,249,179,175,242,216, 76,113,
+ 74,165, 18,169,169,169,141,157,215,232,113,103,121,112, 90,166,199,254,198,249,247, 74,165,210,113,140,171,220, 63, 35,104,115,
+173,188,252,228, 33, 12, 9, 43, 87,181,182, 22,163,144,116,192,145,218,112, 69, 72,220, 99, 16, 7, 6,171, 61,253,254,224,193,
+131, 24, 52,104,144,131,248, 89,194,166, 40,234, 54,194,102, 24,198,241,186,124,249,178, 91,121, 71,143, 30, 69,223,190,125, 33,
+147,201, 32, 20, 10, 33, 16, 8,234,201,100, 73,223,102,179, 57, 94, 38,147, 9,249,249,249,232,212,169,211,195,248,136, 40, 59,
+ 47, 18,249,217,179,103,113,238,220, 57, 85,179,102,205, 48,120,240,224, 38,245,113,138,162,229, 18,105, 56,154,133, 61,162,170,
+213,149, 40,116, 53,197,114,111,101, 48, 12, 35,207,204,204,220, 91, 88, 88,136,237,219,183, 67, 38,147, 97,225,194,133, 2, 56,
+173,189,247, 65,158,170,232,194,121,236,222,149, 3,177, 68,130,121,243,230, 15, 35,132,168,248,158,250,144,122, 0, 30, 36,100,
+102,102,122,212,120, 38, 79,158,236,177, 99,178, 4,237, 74,220,190,194,223,242,252, 13,167,204,124,156, 6, 45, 46,169,101,185,
+202,171, 83, 4,154,148, 93,156,205, 42,232,252,255, 15,124, 47, 36, 68,126,250,224, 46,132, 92,252, 69,165,215,155, 96,121,140,
+134,172, 13,133,206, 87,142,163, 95, 48, 81,105,202, 15,227,247,128,231, 20, 55,169,214,141, 42, 1,167, 79,159,134, 64, 32,192,
+224,193,131, 33, 20, 10, 29, 47, 86, 33, 96,173,126,171,213, 10,155,205, 6,139,197,130,203,151, 47, 99,239,222,189,110,229,233,
+245,122, 20, 20, 20, 96,192,128, 1, 16,139,197, 16,137, 68,245,100, 50, 12, 3,171,213, 10,171,213, 10,139,197, 2,131,193,128,
+130,130, 2,232,116,186,251, 66,159,170,107,103, 52,110, 37,162,241,153,163, 23, 47, 94,204,184,140, 45,168,169,169, 65, 68, 68,
+132, 79, 25, 72, 23, 47, 94, 92,239,122,190, 75,203,135, 76,214, 2, 2,129, 88,165,171, 41,246, 90,102, 94, 94, 30,116, 58, 29,
+ 6, 12, 24,112, 57, 49, 49,177,101, 69, 69, 5,118,237,218,101, 11, 15, 15, 71, 66, 66, 66,163,125,100,214,168,225,183,213,205,
+137, 51,103,160, 14, 14,192,130,229,255, 44,238,221,167,123,219,107, 87,203,176, 43, 91,189, 55,166,123,239,196,234,106,237, 30,
+158, 58,239,127,176,169,127,157,225,154, 11, 64,216,216, 32,203, 14,174,158,190,223, 11,242,127,241,197, 23, 27, 61, 71,163,209,
+224,251,239,191, 39, 92,148, 0,150,172,155,106,173,223, 9,121,206,150,127, 83,173,127, 39, 18,166, 0, 16,165, 82,233,113,227,
+ 24,142,100, 77,177,196,206, 90,251,206,150,191, 51,213,113,109, 51, 78,158, 10,226,156, 78, 24, 0, 42, 43,237,153, 17,195,195,
+115, 31,138,142,122,233,183, 92,116, 42, 86,169,138,245, 12, 38,118, 18,224,145, 72, 43,152,112, 2, 81,184, 0, 53, 21, 98,200,
+106, 12,232,122,108,165, 42, 63,110,142, 66, 31,208, 94,221,176, 37, 73,225,143, 63,254,128, 88, 44,198,176, 97,195, 28,164, 45,
+219,142, 30,155, 0, 0, 32, 0, 73, 68, 65, 84, 18,137, 64,211, 52, 8, 33,176, 88, 44,176, 90,173, 48,153, 76, 40, 46, 46,134,
+ 74,165,106,112, 75,101,154,166, 97,177, 88,112,236,216, 49, 12, 30, 60, 24, 50,153, 12, 18,137,196, 33,143, 85, 0, 76, 38, 19,
+116, 58, 29, 78,156, 56, 1,163,209,232, 85, 98, 38,181, 90, 45, 23, 8, 4,170,154,154, 26,136,197, 98,148,149,149,189, 60,113,
+226,196, 26,169, 84,250,157, 47,164,173, 86,171,167, 8, 4,130, 31,156,228, 21, 78,156, 56,241,172, 84, 42,157, 12,251, 14,149,
+ 94, 91,194,239,188,243,142,106,233,210,165,101, 0, 90,212,145, 55, 78,159, 62,141, 22, 45, 90, 52,152,119,221, 19,249,127, 53,
+123, 54, 70,247,238, 13, 0,136,126,229, 21,200, 2,162,160,171,190,130,106,237, 5, 5, 33, 54,181,183, 50,123,246,236,137,178,
+178, 50, 28, 60,120,176, 61, 77,211, 56,113,226, 4,194,195,195,177,127,255,126,152,205,102,143,245, 88,241,193,130,122,223,131,
+204, 22,180,178, 26, 49,239,245,119,219, 46,255,248, 31,248,247,199, 95,160, 53,109,195, 23, 31,127,154, 59,108,234,116,158, 93,
+ 31, 64,242,103,203, 57,237, 5, 0,220,158,255,219,211,247,187, 9,127,238,212,247, 32,192, 89, 9,104,162, 7,128, 37, 88, 10,
+ 0,249,122,194,183,110, 9,249,249,205,207,113, 38,235, 58,215, 62,229,102,192,118,254,189, 67, 65,224, 50, 5,192,254,183,235,
+187,171, 7,224, 65,135,177,234,166,124,136,169, 64, 85, 38,176,161, 83, 40,208,190, 29,129,160,167, 24,194,142, 29, 33, 54, 25,
+ 97,250,185, 24, 38,173, 16, 2, 70, 4, 99,238,119, 42,122,244,223, 20,140,208,253,116, 0,235,158, 63,127,254, 60,194,194,194,
+160, 80, 40, 32,149, 74, 33, 22,139, 33, 20, 10, 29, 86,191,209,104, 68,105,105, 41,246,237,219, 7,154,166, 65,211, 52, 26,147,
+103,179,217,112,234,212, 41, 12, 26, 52, 8, 33, 33, 33,144, 74,165, 16, 8, 4,176, 90,173, 48,155,205,168,174,174,198,225,195,
+135, 97, 50,153, 32, 20, 10, 29,177, 0,158,176,126,253,122,185, 78,167, 83, 93,188,120, 17,213,213,213, 16,139,197,136,142,142,
+ 94,121,224,192, 1, 12, 28, 56, 80, 24, 24, 24,248,181, 55, 74,192,250,245,235, 39,232,116,186, 31, 92,228,197, 29, 56,112, 32,
+110,224,192,129,223, 7, 6, 6, 78,230, 42,143, 97, 24,185,217,108, 70,101,101,165,202,201,163, 0, 0, 88,186,116,105,201,226,
+197,139, 91, 79,158, 60,121,152, 84, 42,245,106,252,163, 5, 98,185,107,217,245,207, 63, 71,244,248, 54,248,247,191, 63, 83, 88,
+ 44,181, 62,141,167, 7, 15, 30, 84,253,246,219,111,120,243,205, 55,171, 5, 2, 65,136, 84, 42,197,192,129, 3,161, 82,169,144,
+157,157,141,214,173, 91,123,225,239,160,176,254,252, 53,252,120,174, 4, 89, 91,191,129, 64, 64, 97,193, 43,207, 50,189,162,155,
+211,107,230,189,139,181,222,202,227,113, 79,200,223, 85, 57,117,167, 20,248,188, 10,224, 94,111,111,219,177, 99, 71,133,167,215,
+221,182,214,239,132, 60,127, 88,253, 13,225,235, 9,223, 82,207,111,126,142,184, 35,127,112,159, 34,168,103,233, 87, 86, 38, 58,
+ 44,116,220,218, 2,212,107,183,127, 99, 68, 31, 30,158,235,147,245,111,181, 90,229,135, 15, 31, 38, 13,149,185, 30,107, 8,206,
+231, 91,173, 86,185,235, 49,215,178,198, 80,121,234,168,170,180,164, 26, 45,130,133,232, 24, 76, 32,108,206, 64,248,248,147, 8,
+236,245, 29,100,125, 62,129, 36, 84, 6,177,206, 0,189,222,134,118, 2, 61,246,111,104, 88,121,162,105, 26, 66,161, 16, 34,145,
+ 8,231,206,157,195,137, 19, 39, 16, 18, 18,130,136,136, 8, 68, 68, 68,160,121,243,230,104,214,172, 25,180, 90, 45,246,239,223,
+ 15,129, 64,224,152,219,119, 7,246,184, 88, 44,134,205,102, 67, 97, 97, 33, 2, 2, 2,208,188,121,115,180,104,209, 2,145,145,
+145, 8, 10, 10, 66, 97, 97, 33, 44, 22,139, 99,138,160, 33,133,194,213,242,191,113,227,134,234,194,133, 11,232,208,161, 3, 70,
+141, 26,133,254,253,251, 67,175,215, 99,239,222,189, 56,118,236,216,151, 70,163,145,115,238, 98,181, 90,173,184, 81, 86,190,169,
+232,154, 22,193,157, 6, 32,110,212, 95,208,186,127, 18, 52, 38, 26,187,115,247,224,216,177, 99, 19,141, 70,227, 95,185,146,127,
+117,117, 53,142, 31, 63,174, 58,120,240, 32,122,246,236,137,197,139, 23, 55, 71,221,124,250,226,197,139, 91, 3,128, 55,228, 79,
+ 11,196,242,192,160, 86,242,240,136,238,170, 13, 27,143, 99,246, 87, 95, 33,187,160, 0,217, 5, 5,136,126,229, 21, 0,128,197,
+ 82,187,207,151,126,156,157,157, 77,178,178,178, 48,105,210,164,203,193,193,193,116, 64, 64, 64,126, 94, 94, 30, 14, 30, 60,136,
+155, 55,111, 34, 46, 46,206, 43,121,159, 21,156,195,199,191,158,196,218,143,223, 58, 46, 20, 24, 64,219,106,240,209,138,175,232,
+ 31,246,231,163,148, 22,226,145, 71, 30,225, 89,246, 33, 1,237, 43,193,223,195,205, 43,238,140,133,253,118, 30,241,231,188,189,
+191,229,221, 73, 69,224,249,205,207, 17,231, 87, 67, 94, 1, 79, 94,133,219,200,173,190, 50,224,173,167,130,106,168,220,213, 43,
+192, 5, 53, 53, 53,242, 61,123,246,168,242,242,242, 26, 44,115, 62,214, 24,156,207,223,179,103,143,170,166,166, 70,238,124,204,
+181,172, 49,132, 24, 43,144,125,197,136, 29, 23, 25, 20,107, 40,220, 40, 7,104, 97, 40,104, 42, 2,148, 81,130,218, 27, 20,142,
+ 95, 97,112,226,138, 17, 21, 53, 22,244, 8,151,168,184, 40, 0, 18,137, 4, 23, 46, 92,192,153, 51,103, 16, 30, 30,142,176,176,
+ 48,132,133,133, 65,175,215,227,224,193,131, 16,137, 68, 16,139,197,141,238,165,192,122, 7, 88, 37,128, 16,130,162,162, 34,132,
+135,135,163, 77,155, 54,136,140,140, 68, 81, 81, 17,108, 54, 27, 36, 18, 9,196, 98,113,189,149, 7,238,134, 21,246, 67,121,121,
+185,234,234,213,171,232,214,173, 27,158,124,242, 73,140, 29, 59, 86, 49,118,236, 88,197,224,193,131, 97,179,217,240,203, 47,191,
+160,168,168,104, 0, 0, 78,243, 9,229,229,229,123,111, 84,106, 17, 30,219, 11,113,137,179,208,109,204, 92,116, 29, 51, 7,237,
+ 31,159, 0, 51, 17,176,242, 56, 61,223,186,216, 7,213,185,115,231,216,123, 85,212, 17, 63,189,120,241, 98, 44, 93,186, 20, 75,
+151, 46, 61,227, 26, 23,208, 16, 4, 66,169, 60, 44,188,171, 42,186,245, 32, 85, 88, 68, 87, 80,180, 16, 95,126,173,194,236,175,
+190,194,236,175,190,194,210,165, 75, 81, 94, 94, 14,174,242, 92, 44,127,178,109,219, 54, 12, 28, 56, 16,125,250,244,105, 15, 64,
+186,103,207,158,190,151, 46, 93,194,169, 83,167, 96, 48, 24, 48,102,204,152, 97, 92,229,165,157, 45,198, 39,135,207, 96,245,146,
+215, 43,219, 60,210,190,167, 94,167, 65,218,166, 61, 56,126,226, 44,246,255,180, 27,218,235, 55, 48,102,204,232, 68,240,184,111,
+ 17, 31, 31,223,160,245,207, 41, 6, 32, 53, 53,149,202,205,205,149,115,253,254, 32,195,159,150,250,157,144, 7,248,207,253,223,
+160, 21,234, 52,167,238, 45,249,179, 94, 0,103,235,220, 31,240, 20,124,232, 13,212,106,181,188,180,180, 84,197,110,238,210, 80,
+153, 47, 56,127,254, 60, 42, 42, 42, 84,173, 90,181, 82,200,229,114,117, 67,101, 13, 18,215,205, 98, 28,186,102,192,152,128, 0,
+ 28, 40,102,208,170,143, 4, 29, 76,249,208,156,126, 17,155, 63, 58, 14,230,146, 22, 58, 51, 65, 73,141, 13, 50, 33, 13,171,246,
+ 58, 66, 27, 81,218,157,149, 0,169, 84,138,203,151, 47,227,204,153, 51,232,214,173, 27, 52, 26, 13,126,253,245, 87,199, 92,190,
+167,249,122,138,162, 28, 94, 0, 86, 30, 33, 4,197,197,197,232,209,163, 7,114,115,115,193, 48, 12,164, 82, 41, 68, 34,145, 99,
+149, 0, 23, 15,192,149, 43, 87, 96, 52, 26,209,183,111, 95,180,105,211, 70, 33, 16, 8, 16, 18, 18,130,199, 30,123, 76,241,235,
+175,191,170,174, 92,185,130,234,234,234, 19,224,232,178,191,114,229, 10, 24, 90,140,214,241,137,104,214, 38, 14,180, 64, 4, 89,
+ 72, 36,218, 61, 54, 6,151,127,205, 66,157,188, 75,158,228, 16, 66,228, 85, 85, 85,170,146,146, 18,180,107,215, 14, 79, 60,241,
+132, 66, 32, 16,168, 7, 13, 26, 68, 45, 94,188,152, 12, 24, 48,192, 90, 55,110,198,133,134,134,162, 78, 65,177, 53, 38, 83, 42,
+141, 64, 68,100, 47,152, 77, 90,220,172, 40,128,201,164, 25,110,177,232,250, 3,248, 96,192,128, 1, 0,128, 27,215,175,163, 78,
+158, 8,128,133,203, 61, 31, 61,122,116,242,134, 13, 27, 48, 99,198, 12, 12, 26, 52, 8, 0,152, 93,187,118, 9,179,179,179, 49,
+123,246,236,145, 61,123,246,220,237, 77, 91, 46,172,214, 99,209,190,223,241,225,107, 74, 12, 30,155, 24, 94,171,187,137,244, 77,
+251,144,250,229,143,216,177, 96, 22, 58,150, 93,197,178,234,235, 8, 15,143,224,131, 0, 31, 16, 56,187,253,221,197,171, 52, 24,
+ 3,224, 58,183,239,233,251,195, 8,127, 47,193,243, 21,255,234,247, 47, 5, 69, 81,247,101,125,187, 44,245,171, 23, 7,224,170,
+ 12,248,115,249, 31, 87,229, 32, 43, 43, 75,126,227,198, 13,149,217,108,110,180,172, 41,208,104, 52,168,173,173, 85, 85, 87, 87,
+ 43,220,149, 37, 37, 37, 53,248,236,142, 85, 26,160, 53, 51, 56, 86,110, 69,105,149, 21, 81,191, 10,209, 51,253, 60, 46, 95, 58,
+133,179,191,153, 97, 21, 10, 96,102, 0,163,153, 64, 67, 24, 68,134,145, 70, 9,219,121,249, 31, 27,177,127,227,198, 13,180,111,
+223, 30,151, 46, 93,114,184,252,133, 66,161,227,124,111,167,243,156,115, 8,176,239,119,104, 74,176, 10, 77,139,222,191,205, 24,
+247,116, 2,195, 48,168,173,173,181, 15,142, 66,161, 66, 32, 16,168, 93, 60, 73,194,172,172, 44, 36, 37, 37,209,139, 22, 45,186,
+177,108,217, 50,235,162, 69,139, 26,189,121,138,178, 43, 68, 6,253, 13,232,106,138, 21, 54,155, 81, 13, 96, 63,128, 15,106,106,
+106,144,149,149,229, 80, 38, 59,117,234,100,246, 36,175,174,125, 37,101,102,102,102,140, 25, 51,198, 65,254, 63,255,252, 51,189,
+101,203, 22,200,229,242,177,222,146,255, 53,189, 9,207,102,255,138,121, 83,198, 96,242,179,147,160, 55, 86, 99,115,150, 26, 43,
+190, 72,195,183, 35,251,161, 99,217, 85,158, 77, 31, 2,101,192, 85, 9,184, 43,153, 0,149, 74, 37,113,158,211,245,244,157,199,
+109, 3,251, 29, 37,127, 95,231,212, 89,226,119,141,246,119,113,253, 83,117, 47,183,231, 54,212, 94, 60,181, 11,174,237, 37, 41,
+ 41, 73,221,185,115,103, 69, 88, 88, 88,163,101, 77, 65, 88, 88, 24, 58,119,238, 92,143,232,221,149,185,131,193, 22, 2, 11, 5,
+ 28,185,105, 66,153,205,134, 61, 69, 70,164,103, 24,177,247,106, 36,206,139, 67,113, 85,107, 65,113, 13,131, 90, 43,160,183, 18,
+ 72, 34,162, 61, 18, 51,187,190,223,102,179,193,106,181, 34, 34, 34, 2, 65, 65, 65,104,223,190, 61, 44, 22,139,163,220, 93, 66,
+ 32, 87,121,236,250,126,171,213, 10,131,193, 0, 66, 8,218,182,109,139,146,146, 18,180,108,217, 18, 66,161, 16, 38,147, 9,102,
+179,217,241,191, 92,166, 7,219,181,107, 7,169, 84,138,252,252,124, 92,189,122, 85,101,179,217, 80, 93, 93, 77,253,246,219,111,
+ 42,157, 78,135,118,237,218, 33, 36, 36,228, 73,174, 99, 84,187,118,237, 64, 51,102,148, 20,228,162,234,106, 33, 24,155, 5,134,
+234,114, 92,249,237, 39,152,107, 53,172,188, 24, 46,202, 13,139,136,136, 8, 21,195, 48, 14, 79,231,210,165, 75,169, 83,167, 78,
+161,142,180, 25, 0, 81,238, 18, 30,185,194,106, 53,192,106,209, 65, 22, 24, 13,169, 44, 28, 0, 37, 7, 96, 93,186,116,105,132,
+147, 60,172, 93,187,150, 77,160,228,246,158, 43, 42, 42,200,183,223,126, 75, 82, 83, 83,201, 63,255,249,207,173, 73, 73, 73, 24,
+ 59,118, 44,235, 13,168,222,182,109, 27, 38, 79,158,156, 52,101,202,148,159,184,212, 89, 69, 69, 5,249,238,187,239,200,212, 23,
+ 95,198,176,204,125,120,237,185,137,120,245,141,185, 48,154,117,184,120,161, 24,169,169,233,216, 50,110, 32,228,109, 91,248,220,
+ 55,182,108,217,194,143,235,247, 16,174,211, 1,174,129,128,119, 53, 21,176,235,180,129,167,239,119,205,210,111, 96,174,222,213,
+218,231,106,253, 55, 36, 47,239,237,183, 73,222,219,183,220,249,174,223, 61,121, 34,252, 37,207, 25,172,203,255,235, 9,223, 82,
+190,184,255, 83, 83, 83, 29,150,125, 67,243,253,108,185,243,185,158,224, 41,126,192,155,233, 1,185, 92,174, 30, 55,110,156,194,
+ 57, 57,141,187, 50, 95,208,169, 83, 39,140, 27, 55,174,158,171,223, 93, 89,131,191,239,220, 9,157, 3, 5, 8,166, 0, 11, 33,
+248, 67, 99,198,134,243, 38,124,127,168, 20,135, 47, 84,162,212, 0, 84, 24,109,184,160, 35,184,102, 34,208,153, 45,138,198,200,
+139, 93,154,103, 54,155, 97, 48, 24,208,178,101, 75,116,239,222,189, 78,209, 11, 71,255,254,253, 29,132,205,146,118, 67,132,205,
+ 18,186,197, 98,129,217,108, 6, 69, 81,136,141,141, 69, 85, 85, 21,138,139,139, 81, 89, 89,137,152,152, 24,208, 52, 13,179,217,
+ 12,147,201,228,248,141, 39, 68, 70, 70, 42,218,180,105,131, 83,167, 78, 97,231,206,157,216,190,125,187,106,251,246,237,123, 15,
+ 28, 56, 0,129, 64,128,199, 31,127, 28, 29, 59,118, 52,128, 99, 34,155,200,200,200,164,168,240, 80, 84, 20,253,142,179,187,191,
+198,169,159, 86,225,143,159, 82,113,249,151, 45,144,208, 12, 43,175,196,147, 28,161, 80,168,142,138,138, 82,132,132,132,224,216,
+177, 99,184,122,245,170, 74,175,215,203,157, 21,129, 58, 79, 0,189, 97,195, 6,116,235,214,205,227,181,153, 77, 90,104,171,206,
+ 67, 36, 10, 68,179,240, 46,170,192,160,214, 16,137, 2,229, 20, 69, 15, 96,207, 9,174,202,133,234,219, 87, 49,162,139,142, 85,
+154,111,195, 79, 63,253, 4,153, 76,134,110,221,186, 33, 38, 38, 6,117,211, 7, 86,141, 70,163,203,204,204,108, 22, 31, 31,159,
+ 52,108,216,176,109, 92,219,110,118,246, 79, 8, 9, 9,194,144,161,143,233,227,251,244,196,132, 23,103, 67, 79, 89, 81, 94, 86,
+137, 57,175,188,143,101, 9,157,208,167,133,239, 74,242,150, 45, 91,200, 71, 31,125,196, 43, 1,247,137, 34,224, 14,247,205, 94,
+ 0,247,122, 85,129, 47, 4,236, 45,250, 47,177, 43, 16,206, 68,205,150,221, 45,121,206, 86,248,243,155,159,195,243,155,159,171,
+247,217,185,140,171,197,238,236, 73,112,231, 81,104,106, 92,128,179, 39,192,245,157, 43,130,131,131,213,195,135, 15, 87,244,239,
+223,191,193, 50,231, 99,141,214,187,211,249,195,135, 15, 87, 4, 7,223, 90,150,231,174,172, 81,235, 80, 18,168,232,209,178, 57,
+158,136,144,160, 95,152, 24,173,164, 52, 36,132, 64,106,178,162, 93,144, 16, 26, 66,112, 82,103, 69, 97,173, 21,173, 91, 68, 32,
+166,223,208, 6,101,177, 86, 63,187,212,175, 93,187,118,232,213,171, 23, 52, 26, 13,170,170,170, 80, 85, 85,133,224,224, 96, 12,
+ 24, 48, 0,102,179,217,145, 19,160, 33,194,102,149, 9,139,197, 2,138,162, 16, 23, 23, 7,131,193,128,242,242,114,148,149,149,
+161,188,188, 28,181,181,181,136,139,139,131, 80, 40,116,200,107, 40,175,128,171, 82, 22, 21, 21,165,136,141,141,197,197,139, 23,
+145,147,147,131,188,188, 60, 4, 4, 4, 96,216,176, 97,232,213,171,215, 79, 82,169,116, 1, 56, 78, 1,200,229,242,109, 81, 45,
+ 34,103,198,182,108, 6,221,133,223, 80,152,243, 37, 74,242,182, 34, 76, 98, 67,226,240, 97,232,213,171,215, 44,169, 84,154,197,
+ 69, 86, 72, 72, 8,250,244,233, 3, 66, 8, 14, 29, 58,132,252,252,124, 85, 73, 73,137,170,178,178, 82,190,120,241, 98, 5,155,
+ 57, 49, 33, 33, 1,251,247,239,247, 40,143, 97, 44,106,173,230,188,162,178,252, 4, 36,210,112, 68,183,122, 92, 21, 25,221, 95,
+ 21, 28, 18,243,211,191, 63,254,207, 56, 86,222,247,127, 11,192,198,159, 77,104, 72,233, 41, 44, 44, 68,243,230,205, 49,104,208,
+ 32,166, 95,191,126,208,235,245,168,173,173,197,202,149, 43,131,186,116,233, 50,126,234,212,169,219,188,233, 19,103,207, 22,162,
+125,187, 54,152, 58, 53, 41,224,157,183,231,161,162, 70,139,155, 21, 55,145,242,234,251,120,127,194,112, 12,111, 23,213, 36,242,
+ 95,177, 98, 5,186,119,239,142,207, 63,255,156, 87, 2,238, 34,126,255,253,247, 6,243, 0,220,166,240,222, 47, 4,239,205,170,
+130,201,147, 39, 83,254,202, 4,232, 9,174,137,120,252,161, 4,248,131,252,125,149,215, 80,170, 94, 87,203,220,155,148,189, 46,
+ 74,130, 35, 41, 80, 83,238,203, 89,105,112,182,246,125, 89, 1,224,108,221,245,235,215,143,106,168,204,245, 88, 67,104,236,124,
+174, 50, 88, 60, 46, 31,166, 46, 18, 18, 88,243,178,113, 73, 11, 4, 81, 34,180, 15,162, 81, 98,163, 32,144, 8,177,191,204, 6,
+ 35, 3, 68, 74, 4,136, 77, 24, 2,105,231, 4,117, 99, 10,128,197, 98,129, 64, 32, 64,135, 14, 29,208,167, 79, 31, 84, 87, 87,
+195,104, 52, 58,214,231,155,205,102,132,135,135, 99,208,160, 65,216,182,109,155, 99, 74,192, 29,108, 54,155, 35,170,191,107,215,
+174,168,115,211,195,104, 52, 58,250, 51,235, 73,232,218,181, 43, 42, 43, 43,161,211,233, 26,235,203,245, 14,204,156, 57, 83,173,
+ 86,171,135,117,235,214,109,175, 83,226,158,170,193,131, 7,239,149, 74,165, 51, 0, 24,189,169,203,153, 51,103,110, 80,171,213,
+213,221,186,117,203,114,146,119,115,240,224,193, 43,165, 82,233, 55, 92,229,208, 52,173,110,213,170,149, 98,212,168, 81,184,120,
+241,162,234,204,153, 51,184,114,229, 10,130,131,131, 85,205,154, 53,195,136, 17, 35,240,191,255,253, 15, 9, 9, 9,156,175,205,
+106,213,171,171, 52,103, 21, 70, 99, 37,154,133,197,169,130,130,219, 34, 56,164, 29,106,107, 74,182,125,184,236, 75, 76,155,154,
+136,239,255, 22,224,182,158, 88,140, 30, 61, 26,217,217,217,184,122,245, 42, 93, 89, 89, 9,163,209,136,253,251,247, 11,235,148,
+206,106,111,251,195,152, 49,163,177,121,243, 54, 84, 87, 85,224,106,233, 53,252,237,165,231,204,175,191,185, 84, 60, 97,216, 64,
+ 12, 50, 85, 3, 34,223,232, 97,203,150, 45,228,189,247,222,115,164,131,142,141,141,197, 71, 31,125,132, 55,222,120,131,140, 31,
+ 63,254,193,207,220,249,128, 42, 5,247, 76, 1,184, 19,171, 10,252, 65,238, 44,110,222,252, 18,111,231,109,109, 52,219,158, 55,
+193,127, 55,111,126,137,188,183,111,201,115, 38,102, 87,151, 61, 23,210,190,249,229, 77,228,109,125,219,111,242,252, 9, 46, 30,
+ 2,118, 15, 0,111,218,203,159,169,115,198, 12, 84, 40,142,155,172,170,242,189,123, 32,178, 26,112,188,134, 32,183,198, 10, 49,
+ 69, 33,130, 16, 40, 90, 54, 67, 88,116,164,162,205, 99,114, 15,150,166,221, 3, 16, 19, 19,131,254,253,251,195, 96, 48,192, 98,
+177, 64, 44, 22, 59, 8,155,181,210, 35, 35, 35,241,196, 19, 79, 32, 39, 39,167, 81, 15,128, 80, 40, 68,175, 94,189, 64, 81, 20,
+244,122,189,195,187,192, 42,237,108,118, 65,134, 97,208,163, 71, 15,252,250,235,175,240, 38,184, 82, 46,151,171,112, 43, 78, 36,
+ 8,246,108,123, 87,192, 49, 18,222,157, 39,192, 73, 86, 56,128, 74, 0, 94,231, 38,166,105, 90,221,172, 89, 51,244,232,209, 67,
+ 33, 18,137,216,229,143, 42, 0, 40, 41, 41,193, 83, 79, 61,133, 79, 63,253,212, 43,153, 54,155, 73, 93,171, 43,145,155,205, 90,
+133,172,250,146, 42,164, 89, 44, 2,130, 90, 33, 32,168, 21,118,237,185, 1,106,120,227, 22,247,192,129, 3, 41,177, 88, 76, 42,
+ 43, 43, 49,122,244,104,115, 68, 68,132,152, 97, 24, 92,185,114, 5,240, 33, 88,242,241,199, 7, 82, 18,137,132,132,156,206,199,
+ 75, 47,253, 5,109,226, 58,139, 63,154,247, 23,102,221, 23,223,208, 43, 5, 70,159,218,242,150, 45, 91,200,162, 69,139,208,172,
+ 89, 51,148,150,150, 66, 38,147,129, 97, 24, 4, 6, 6, 98,201,146, 37,120,251,237,183,121, 37,224, 14, 35, 62, 62,190, 65, 47,
+ 0,167,101,128,119, 2,247,243,170,130,198, 8,199, 23,235,191, 33,121,174,150, 58,235,186,247, 68,218,254,150,231,236, 9,240,
+245,120, 99, 94, 5,215,205,127,188,149,247,103, 3, 77,211,234,248,225,163,168,202, 90,131, 60,212,106, 82, 9, 46, 23,161,147,
+229, 26,130, 35,162, 48,176, 71, 23, 68,180,110,174, 8,141, 31,234,177,127, 16, 66,208,161, 67, 7, 12, 26, 52,200, 49, 31, 47,
+ 16, 8, 96, 50,153, 28,169,123,157,167, 9,218,182,109,139, 39,158,120, 2,106,181,123,209, 50,153, 12,241,241,241, 16, 10,133,
+ 48,155,205,142,223, 57, 47, 29,116,222, 8,136,166,105,244,238,221, 27,249,249,249,190, 84, 3, 1, 80, 83,247,242, 7,116,190,
+ 16,191, 59,175, 81,247,238,221,217, 56, 10,138, 97, 24,185, 94,175,135,201,100, 66,151, 46, 93,176,124,249,114, 47, 55,199, 33,
+106,139,185, 6, 22,179, 78, 97, 48,148, 67, 34, 9,131, 72, 28,172,162,105, 33,214,111,248, 73, 49,115,198,152, 70,229,213,229,
+245,167, 62,249,228, 19,198, 96, 48, 0, 0,226,226,226,188, 74,191,236,140, 62,125,250, 82,130,126,253,158,154,253,222, 39,217,
+118,121,132,142,139,123, 4,113,227,199,207, 20, 10,133, 27,124,145,185,108,217, 50,190, 83,223, 39, 74, 64, 99,228,127, 87, 21,
+128, 7, 21,254, 92,246,231, 74,204, 77,181,214,253, 37,175, 41, 22,183, 51,177,179,159, 93, 92,246,124, 35,226,136, 97, 73,227,
+213,117,214, 43,134,248,240,251,228,228,100,132,133,133, 57, 34,252, 25,134,113,184,240, 89, 15, 0, 27,244,199,238, 8, 24, 27,
+ 27, 11,138,162,176,113,227,198,219,228,173, 88,177, 2, 25, 25, 25,142,115,109, 54,155,199,237,128,197, 98, 49, 18, 18, 18,192,
+ 37, 58,254, 65, 85,214,130,130,130, 16, 20, 20,132,136,136,136, 38,244, 29, 86, 17,168, 1, 77, 11, 97, 15,199, 98, 84, 28,229,
+145,133, 11, 23, 82,117,207,147,208, 52,221,164,113,196,102, 99,118,204,159, 63,159, 2, 64, 51, 12, 99,163,105, 90, 6, 47,167,
+ 95, 88,240,214,253,253,165, 4,120, 2, 21, 31, 31,207, 7,103,240,224,193,131, 7, 15, 30,127, 50,208,124, 21,240,224,193,131,
+ 7, 15, 30,188, 2,192,131, 7, 15, 30, 60,120,240,224, 21, 0, 30, 60,120,240,224,193,131, 7,175, 0,240,224,193,131, 7, 15,
+ 30, 60, 30, 10,212, 91, 5, 48,119,238, 92,159, 35, 56, 87,173, 90,117, 91, 48, 33, 47,143,151,199,203,123,248,228, 41,149, 74,
+242,244,120, 37,182,110, 73, 69,106,106, 42, 13, 55,107,208,249,250,227,229, 45, 89,178,196,113,206,219,111,191, 77,121, 43,175,
+160,160,192,231,235,235,221,187,247,159, 94,158,215, 10, 0,219,185, 27, 58,217,151, 37, 47, 15,178, 60, 95,100,222,239,247,235,
+ 6, 98, 0, 33, 0, 2,234,218, 3, 3,224, 38,252,176,134,218,159, 96,235,193, 31,247,236,174, 78,239, 85,242,161,154,154, 26,
+249,161, 67,135, 84,251,246,237, 3, 0, 12, 29, 58, 20, 3, 7, 14,228,156, 74,248, 94, 60,135,167,199, 43, 49,250,169, 62, 86,
+ 64, 41, 84, 42,149,204,159, 45,113, 19, 15,207, 88,178,100, 9, 25, 55, 46,182,222,119, 79, 74, 0,143,123,236, 1, 96, 65,210,
+111,223, 0,130,154,226,251,190,233,238, 6,136,166,236,254,231,111,121,238,238,183, 41,247,124,191,223, 47, 75,252,167,142, 31,
+248,250,212,169, 99,195,163, 91,199, 70,105,181, 22,132,134,138,112,189,228, 2,211,173, 91,175,202,110, 61, 7,247, 7,112,209,
+ 27,129, 71,127,249,130, 20, 93, 40,196,133, 75, 70, 20, 95, 35,104,219,146, 66,108,140, 20, 29, 99,227,208,231,241, 23,239,139,
+206,239, 78,145, 96,247, 26,184, 23, 68,118,226,196, 9, 85,124,252, 78,172, 94,173,135, 90, 13,188,251,238, 46, 20, 23, 23,171,
+162,163,163, 33,149, 74, 81, 90, 90,170,152, 48, 97, 2,252,161, 16, 28, 56,112,128,104,181, 90,197,136, 17, 35, 32,145, 72,124,
+145, 71, 3,192,232,167,250, 48, 41, 41, 41, 66, 96, 13,182,110,177,119, 21,248,119,219, 94, 30, 15, 1,204,230, 69,200,201, 73,
+193,168, 81,107, 48,110,220, 50,135, 71,128, 87, 4,238, 14,248, 68, 64, 94,192,153,236, 41, 10, 96,126, 8,123,104,239,213, 98,
+174,125, 54,103,231, 15,139, 59,117,234,220,101,226,248,161,104,219, 58, 4,205, 66, 37,208, 84, 25, 81,114,173, 45,125,174, 72,
+211,124,123,214, 87,170, 81, 79, 62,243,137, 72, 28,248,185, 39,121,167, 79,236,147, 95, 44,220,174, 18,160, 26,207,140, 1,158,
+232, 11,196,182, 7,206, 95, 34, 56,120,196,128,108,213, 49,252,244,227,235,164, 67,220, 88,197,163, 61, 60,103,180,187, 83,222,
+142,134,188, 8,169,169,169,212,189, 82, 2, 42, 43, 43,241,234,171,122, 68, 70, 2,201,201,192,135, 31,234, 80, 80, 80, 0,171,
+213, 10,169, 84,138, 22, 45, 90,168,182,111,223,142,206,157, 59, 43, 18, 18, 18,212, 94, 14, 0,242,147, 39, 79, 34, 42, 42, 74,
+ 53, 98,196, 8,106,253,250,245, 0,160,202,205,205,197,244,233,211,209,191,127,127,111,239, 85, 12, 0,217, 59,142,210,192, 26,
+198,254,110,215,161,249, 17,132,135,179,181, 15, 0,147, 38,253,136,156, 28,251,123, 74,202, 5,176, 30, 1,222, 27,112,119,137,
+223,185,252,158,165, 2,190,223, 65,210,195, 28, 74,192,195, 76,254, 0,132,187,115,210,223, 81, 12,233, 19,215,175,119, 75, 80,
+148, 61,171, 27,195, 16,132, 4, 73, 16, 24, 43, 70, 76,219, 80,180,142, 14,106,191, 59, 39,253,157,209,227,158,207, 0,112,189,
+ 49,129, 23, 11,183,171, 6,247,173,198,188,231, 1,129,192,174, 64, 89,172, 64, 96, 0,208,181, 19, 48, 32, 30,216,174,170,198,
+175,199,182,171, 30,237, 49,212,167,142,239,175, 41,128,134,126,207, 42, 1,119,251, 97,132,135,135, 99,251,118, 25,218,182, 53,
+ 64,173, 6, 52, 26, 33, 58,117,234,132, 78,157, 58, 65,167,211,161,168,168, 8,106,181, 26,213,213,213,170, 71, 30,121,132,243,
+212,192,166, 77,155,228, 6,131, 65, 37, 22,139,161,209,212,247,100, 25, 12, 6,124,249,229,151, 40, 42, 42, 34, 83,167, 78,245,
+166, 62, 25, 0,216,186, 37, 21,128,146,182,191,251,142,195,135, 15, 59,234,155,221, 68,201, 93, 25,151,118,225,252,108,185,150,
+121, 52, 10, 8,145,227,236, 89,244,215,233, 84, 17, 37, 37,184,218,162, 5,142,134,132, 40, 68,143, 62, 10, 66, 81,106, 95,239,
+217,219, 13,163,184,200,224, 90,118,167,229, 57,187,254, 83, 82,114, 48,110, 92,172,227,157,197,184,113,177,188, 18,112, 23,224,
+ 74,246,236,254, 0,206,229,252, 42, 0,215, 78,255,144,223,223,169,227, 7, 62,236,212,169, 83, 92,255, 62, 45,235,149,211, 52,
+ 5,177, 88, 0,153, 84, 8,145,136, 70,108,135, 48,196,198,118,106,113,234,248,129,237,141, 41,138, 71,127,249,130, 8, 80,141,
+249,179, 1,163, 9,184, 88, 12,104,180, 64, 85, 53,144,150, 5,188,242, 30,176,248, 99, 96, 96, 31,128, 38,213, 56,250,203, 23,
+188,181,232,132, 30, 61,122, 40,182,110,237,138, 22, 45,128,233,211,133,136,142,238,135,161, 67,135, 42,198,141, 27, 71,141, 29,
+ 59, 86, 49,106,212, 40, 68, 69, 69,225,232,209,163,248,225,135, 31, 84,187,118,237,146,155, 76, 38,121, 99, 50,215,175, 95, 47,
+ 55,153, 76, 42,145, 72,212,232,127,171, 84, 42,164,167,167,203,185,144,236,254,253,251, 9, 0,115,106,106,170,248,150, 18,112,
+139, 76,247,239,223, 79,188, 85,160,242,242,242, 28,175,198,202,124, 81,234,184,150, 53, 70,254, 29,207,156, 81, 77,248,253,119,
+ 85,219,194,243, 16, 87, 87,163,101,225, 25,200,127,253, 69, 21,121,236,152, 10,132,200,125,121,222,121,121,121, 56,124,248, 48,
+ 57,121,242,164,220,215, 54,195,202,224, 82,198, 85,158, 43,209,115, 41,243, 4,150,244,217,119,243,184, 78,124,135,191, 75,196,
+207, 37, 13,240, 3,235, 1,184,147,150, 26,185,131,215,231, 47, 23, 51, 43,191,161,255,105,236, 63, 78,157, 62,246,212,148,137,
+ 10, 7,233,187,131, 84, 34, 68,149,214,132,255,223,222,181,199, 53,113,166,235,103,146, 16, 2,130, 32,226, 13, 47, 85, 64, 91,
+196, 42,104, 85,212, 21,137, 69,173, 8,106,181,209,158,109,247,172,181, 93, 98,183,199, 95,247, 20, 43,110,217,238,177, 61,181,
+ 21, 79,109,187,235,233,110, 73,247,168,237, 46,187,219, 70, 43,138, 90,217,166, 6,109,171,182,138,183,122,169,114,241, 86, 65,
+169,200,157,132,100, 50,223,249, 35, 12, 14, 33,151,153,201, 32,216,206,243,251,241, 35,249, 50,121, 51,215,239,121,222,247,251,
+222,247, 27, 21, 19, 1,227, 14,115, 76,252,216,233, 97,158,236, 85,148, 95,196,210,121,206,215,251, 14, 2,239,254, 21,152, 61,
+ 29, 72, 75, 1,190, 43, 3, 78,156, 37, 8,210, 80, 72,140, 7,230,204, 0, 62, 41,186,136,241, 83,164,243,220,197,156,187, 46,
+154, 83, 33, 10,161,161,161,197, 77, 77,206,249,150, 63,255,249,207, 49,109,218, 52,138,251,217,237,219,183,181,113,113, 42,243,
+252,249, 0, 69, 29, 67,117,117,139,249,251,239, 99,188,133,255, 82, 40,138, 50,243, 93, 28,166,186,186,218,236, 75,247, 62,241,
+196, 19,200,207,207, 71,126,126, 62,121,226,137, 39, 58, 92,139,131, 7, 15,146,252,252,252,246,237,122, 74,127,192,183,205, 19,
+ 90,207,156,193,136,146, 18,216, 20, 10, 4, 80, 0,205, 16, 48,118, 7, 24,154, 70,191, 47, 14,162,140, 16,244, 78, 76, 20, 77,
+224,193,193,193,230, 99,199,142,105,151, 45, 91, 86, 44,214, 6,128, 14, 30,185,187, 54, 49,209, 5,127,201,223, 19,209, 23,185,
+ 68, 2,100,116, 63,220, 10, 0, 79,147,223,196, 16,142, 47, 66, 20,106,239,110,143,209,138,153, 49,238,109, 82,161, 24,123,238,
+190, 35,114,226,162,106, 96, 84,204,232,168,129, 33, 32, 4,248,226,240, 53,180, 88,156,171,174,142, 31, 55, 16,253,250, 6,225,
+218,245, 70,166,236, 82,173, 66,165, 82, 96,100,116, 31, 68, 69,197,134,195,185, 68,171, 91,148, 95,182, 98,218, 4,160,213, 14,
+124,122, 0, 48, 31, 38,136, 26, 64, 33,122, 24,240,240,207,128, 7, 98, 40,168,148,206,165,197,147, 18,128,255,201,179,242, 58,
+223,220,144, 60,159,215,124, 20, 47,119,172,159,123,222,165,204, 48, 16,131,182,229, 92, 49,118,236, 88,173,235,103, 74,165,210,
+ 60,122,116, 53, 94,122,201, 41, 79, 95,127,253, 34, 46, 95,142,247,104,203,106,181,250,244,252,185,184,124,249,178,207,109,146,
+147,147,169,228,228,228,118,178,207,207,207, 39,174, 2, 33, 57, 57,185, 91,206, 93, 87,120,255, 0, 48,242, 86,141,217,102,183,
+ 67,161, 80,128, 40,149, 96, 24, 6,118,134, 1,227,112,192,225, 96, 48,164,170,202,220,144,152, 40,250,152, 91, 90, 90, 0,192,
+124,244,232, 81, 80, 20, 37,120,126, 71, 87,136, 0,169, 60,255,162,204, 34,204, 49,204,193,226,237, 64,102,145,243,117, 81,102,
+ 81,187, 56, 80, 23,150,201,204,123, 23,193,157, 19,192,107, 14,128,167, 44, 0,177,217, 1,158, 60, 46, 49,158,152, 55,209, 32,
+ 86,160,120, 59,110,215,239,242,245, 34, 60, 77, 42, 20, 99,207,219,119,216,223,161, 0, 48, 31,251,156,187,192, 56,103,251, 7,
+ 2, 0,174, 85, 54,192, 98,161, 1, 0,177,209,125,208,175,111, 16, 78,157,173, 86, 92, 40,189, 13,141, 70,137,152, 17,225,168,
+173,183, 1,128, 71,195,215,170, 8, 98,238,115,254,254, 35,201, 64,194,104, 10,129,106,128,166,157,145,128,240, 80,160,226, 42,
+ 48, 39, 25,184,111,136,115,251,238, 4,151,244,197,140, 11,247,116, 84, 87, 87,119, 89, 20,165,141,228,219, 61,254,238, 38,127,
+ 46,114,115,115, 73,118,118, 54, 37,246,115, 87, 4,148,151,161,213,110, 3,165, 84,193, 65, 8, 40, 0,180,131,129,157,102, 64,
+ 28, 14, 80,165, 23, 0,164,249,189,223,103,206,156, 65,100,100,164,185,190,190, 94, 27, 22, 22, 38, 90, 4,248,106,187, 91,228,
+159,147,147, 67,173, 91,183,142, 44,222,222, 81, 16, 0,192, 28,195, 28,168, 11,203, 80, 88, 88,222,158, 9,192, 78, 24,140,136,
+136,144,153,250, 46,147,191, 71, 1,208,211,225,141, 16,197, 16,172, 63, 41,142, 94,237,118,113, 54, 1,181,164, 86,232,111, 80,
+ 97, 97, 1,168,173,179, 34, 50, 34, 24,186,249, 15,128,118, 48, 8, 12, 84, 66,169, 80,128, 16,130,244,217, 49,152, 55, 43, 6,
+ 20, 5,212,212, 90, 16, 22, 22, 0, 0,183, 61, 25, 28, 58,136, 66,249, 21,130, 7, 98,128,153, 83,156,189,206,119,101,192,216,
+ 7,128, 62,189,129,185, 41, 0,195, 0, 42, 37,112,241,146,115,123,190,215, 86,200,107,119,133, 68,132, 70,122,186, 67, 4, 48,
+ 12,147, 50,120,240, 96,148,151,151,227,224,193,131,230,233,211,167,107, 67, 66, 66,160, 80, 40,138, 1,192,225,112,104,207,157,
+235,111,126,229,149,235,160, 40, 10,213,213,163, 48,106,212,112, 92,188,120,209,147, 61,183,237, 31,127,252,113,231, 40, 18, 33,
+ 88,186,116,169,160, 99,230,138,128,158, 68,254, 82,136, 4, 46,110, 15, 25, 12,245,119, 23, 64, 2, 0, 53, 67,156, 19, 91, 29,
+ 52,108,196,129, 22,154,134, 37,246, 1, 73,246,125,204,152, 49,160, 40, 74, 20,249, 3,192,164, 73,147, 48,113,226, 68,234,155,
+111,190, 33,222,218,124,161, 45, 98,208,129,240,221,181, 9, 65,102,209, 29,226, 7,208,201,243,103, 39, 12, 22, 22,150,203, 76,
+221, 13,228,127,207, 10,128,174, 22, 20, 82, 17, 2, 33,128, 98,105,109,151,137, 0, 54,115, 65,177,164,150,143,247, 15, 0,170,
+ 27,215,203,111, 93,187, 62, 36, 50, 50, 34, 24,111,253,249, 40,146,167, 14,197,248,177, 3, 64, 5, 80,237, 25, 1,109, 75,199,
+227,218,245, 70,220,184, 94,126, 9,128, 71,183, 50,102,184, 6, 95,149, 88,240, 64, 12, 16, 57, 1, 88,243, 44,240,252, 50, 32,
+ 44,212, 25,246,127,229,143,192,218,231,157,219,126, 85,226,220, 94, 44, 65, 75,229,169,247,164, 90, 0,231,206,157,131, 70,227,
+ 60, 39,123,246,236,193,213,171, 87,205,247,223,127,191,118,230,204,153,104,108,108, 76,137,136,136, 48,127,249, 37,141,226, 98,
+ 96,226,196,135, 48,108,216, 48,237,144, 33, 67, 0,192,236,206, 94,175, 94,189, 96,179,217,120,253, 54, 77,211,247,252,179,203,
+ 37,127, 62, 66,128,175, 8, 40,239,215, 95, 27,120,250,180,153, 33, 4,189, 20, 42, 40,149, 20,104,226, 64,139,221,142, 70,155,
+ 13,149, 81, 81,218, 72, 63,246, 59, 56, 56, 24, 20, 69,105, 39, 78,156, 88, 44,214, 6, 75,244,190,218,238,182, 8,200,201,201,
+161, 50,219, 60,123, 87,242,231,122,255, 50,186,151,252,101, 1,112, 55, 60,188, 46, 78, 41,108, 23, 1,252,132, 6, 29, 31, 63,
+174,178,236, 82,109,228,184,248,254, 88,243,124, 18,182,254,227, 91, 4,105, 84, 72, 24,211, 31, 20, 69,113, 60, 73,130,178, 75,
+181,136,143, 31,119, 6, 64,163, 39,131,209, 49,163,176,103,255, 41, 44, 91, 12,144, 10, 32,105, 17, 16, 61, 20,200,223,201,217,
+232,121,192,225, 0,246,236,119,110,223, 93,240, 22, 41,234,174, 52,192,219,183,111,155,227,226, 46, 97,203, 22, 0,112,224,213,
+ 87, 79,227,196,137, 22,115, 75, 75, 11, 26, 27, 27, 81, 81, 81,129,155, 55,111, 98,252,248,241, 88,186,116,169,207, 52, 64, 66,
+136,150, 97, 24,179, 66,225, 59,193,135, 21, 30, 66,193, 14, 1,228,231,231, 35, 57, 57,185, 91,159,175,236,236,108,138, 37,126,
+ 95, 67, 0,190,182,225,162, 79, 98, 34,106,108, 54, 56,204,197,176,169, 3, 16, 66, 84,176, 50, 12,234,109, 54, 52,206,124, 24,
+145, 19, 38,136,140, 10, 82,152, 56,113,162,232,113,127,174, 13, 46,209,187,107,243, 71, 4, 28, 61,122,212,107, 27, 31,184, 35,
+127,214,243, 7, 32, 79, 8,236,102,242,151, 5,192, 61,142,246,241,127,254,195, 0,142,248,177,211,103,238,222,181,249,203,175,
+ 75, 66, 31,152, 60, 33, 10,115, 83,163,177,239,243, 10,236,249,151,243,225,252, 93,214, 84, 48, 12,193,215, 37,149, 40, 47, 47,
+187,146, 62,127,249,127, 0,176,123, 50, 56,126,202,175,169, 61,219, 95, 36,111,111,118,166, 2,190,247,154, 51,245, 47,117,154,
+ 51, 21,240,237,151,157,228,255,246,102,192,129,222,162, 43, 2,250,235,153,251,138, 32,116, 87, 22, 64,115,115, 51, 18, 19,173,
+152, 56,209,249,254,161,135, 8,246,237,171,192,197,139, 23,217, 66, 64, 72, 73, 73,193,200,145, 35,121,213, 0,152, 61,123,118,
+113, 65, 65,129,207, 40, 0, 77,211, 8, 15, 15,215, 10,221,223,182,116,192,246,204,128,131, 7, 15, 18,177,195, 0,147, 38, 77,
+226,213, 38, 68, 4,248,218,142,183, 81,133,162,216, 54,121,178,246,124, 64, 0,134, 86, 85,153, 67,174, 94,133,117,196, 8, 92,
+238,223, 95, 27, 49,126, 60,208, 54, 68, 35,130, 96,165, 32,233, 78, 54,220,181,241, 61,151,174,219,177,132,239,171, 77, 12, 92,
+ 73,159,141, 8,248, 59,132, 39,163, 51,248, 76,140,150, 5, 64, 23,122,230, 61,244, 55,106,230, 60,178,244,157,162,125, 31,189,
+248,125, 85, 99, 76,236,136, 62,152, 55, 59, 6,237, 98,190, 3, 0, 0, 32, 0, 73, 68, 65, 84,125,194, 53,168,173,179,226,196,
+183, 55, 81,118,169, 22,229,229,101,135,230, 60,178,244, 19, 0,215,124, 25, 28, 49, 42, 93,251, 69,201,110,243,161,146, 6,204,
+155, 9,188,255,134,179, 18, 96,249, 21,224,255, 62,118,122,254, 14,244,198,136, 81,233, 90,177,199,234,207, 16, 0, 95,242,239,
+142, 57, 0, 85, 85, 85,218, 62,125, 34,205,199,142,253, 0, 0,184,120,177, 55, 38, 78, 28,141,190,125,251, 66,163,209,160,170,
+170, 74,155,158,158, 46,168, 20,240,240,225,195,181, 23, 46, 92, 48,115, 35, 58,174,228, 31, 27, 27,139, 73,147, 38, 9, 34, 49,
+ 54, 11,128, 51,246,207, 78, 8, 20, 37, 2,220, 17,161, 88,114,244, 69,238,130,200,159, 35, 2,250, 62,244, 16, 90, 0,170,165,
+173,201,223,169,106,254,146,191,144,243,198,247,183,164,182,199,151,252,109, 25,177,128, 60,254,127, 87, 34, 1,158,132,129,160,
+ 52, 64,177,147,229,132,166, 1,138,181, 39,214,166,212,251,231,237, 60, 73,181,127,254, 76, 92, 12, 80,247,202, 75,159,191,252,
+159,103, 79,127,241,167, 29, 59, 15, 68, 15, 28, 28,147,196, 89, 11,224, 72,124,252,184,111,210,231, 47,127, 9, 64, 51, 31,123,
+163, 31,156, 81, 60,250,193, 25,212,241,195,127, 34, 31,237,185,136,215,223,237,121,107, 1,244, 68,242, 7,128,199, 31,127, 28,
+167, 78,157,194, 83, 79, 29,107,139, 0, 60,132, 37, 75,198,105,131,131,131,139,197,218, 76, 72, 72, 40, 78, 72, 72,160,118,237,
+218,149,210,216,216,104, 86, 42,149, 80, 40, 20,160,105, 26,106,181, 26, 33, 33, 33, 90, 9,200, 95, 18, 17, 32,227,199,137,156,
+156, 28,106, 93,230, 58, 18,181, 50, 74,139,225,238,183,169,204, 44, 50,203,243, 1,186, 23, 42,190, 29,165,212, 29,111, 87,216,
+ 19,243, 91,247,242,241,250,137,250,248,177,211,159,140, 31, 59,157,173, 24, 19, 2, 32, 18, 64, 21, 0, 11,218,202,190, 10,193,
+248, 41,191,166,196, 20,249,233,234,243,208,147,234, 74,184, 34, 56, 56,184,120,202,148, 41,212,148, 41,210,159,184,249,243,231,
+ 23, 67,162,226,150,236,184,191, 43,201, 39, 39, 39, 83,249,249,249,164, 39,204, 7,144,209,243, 68,128,247, 13, 32,147,127, 23,
+128,111, 21, 64, 0,160, 18, 18, 18,228,177, 23, 25, 50,100,200,144, 33,227, 39, 6,121, 45, 0, 25, 50,100,200,144, 33, 67, 22,
+ 0, 50,100,200,144, 33, 67,134, 12, 89, 0,200,144, 33, 67,134, 12, 25, 50,100, 1, 32, 67,134, 12, 25, 50,100,200,248,113,160,
+ 67, 22,192,179,207, 62, 43,122, 86,166,187, 66, 14,178,189,174,177,199,103, 17,155,238,180,103, 50,153, 82, 0,152,141, 70,163,
+ 36,246,246,239,223,159,194, 48,140,100,246,228,251,175,219,236, 45, 5,240,113, 23,239, 95, 0, 0, 13,156, 69,107,172,112,102,
+179, 16,184, 20,177,145,175, 71,207,183,119,226,196, 9,209,246, 18, 19, 19,127,242,246, 4, 11, 0, 95,228,224, 9, 66, 82,169,
+164,182,119, 55,145,169,171, 39, 80,171, 97,200, 15,226,181,127, 38,147, 41,197,104, 52,154,165, 58, 94,174,189,141, 27, 55,106,
+179,178,178,204, 98,150, 23,118,103,239,204,187,189, 49,230,185, 6,248, 99,143,197,194,137,123,205,167, 46, 56, 0, 0, 6,131,
+129,100,102,102,250,117, 61, 71, 13,248, 8, 22, 58, 2, 65, 65, 65, 48, 26,141, 68,167,211,117,219,253, 33,166,142,131,183,243,
+215,211,237,249,250, 29,129,223, 61,220, 85,215,133,162,168, 52,133, 66, 49, 90,161, 80,164, 80, 20, 53, 10, 64,176,205,102, 43,
+ 82, 42,149,225, 12,195, 84, 19, 66, 94, 6, 80, 3, 9,170,217,201,144,241,163,140, 0,184,123,200, 9, 33,222, 30, 58,193, 29,
+134, 84,246,132,122,176, 82,226,179,207, 62,243,217,137,176,228,154,157,157,141,254,253,251,187,173,128,151,149,149,101,230,251,
+155,172, 61,150,248,143, 28, 57,210, 46, 4,252,177,199,156,251, 61, 20,163, 95,197,135,251,157,165, 99,153,115,191,111,223, 70,
+ 49,250, 85, 65,231,165,119,195, 11,132, 33,192, 63,247, 57,109,205,157, 17,128,248,216,179, 48, 24, 12, 4, 0,132, 10,129,122,
+250,159, 41,117,151,107, 96,161,102,152,155, 91,123, 97,238,156, 58, 12, 30, 72,225,216,177, 67,164,161,193,138,153, 51,103,246,
+152, 53,232,123,146,128,246,246,140, 73,245,204,137,132,141,123,255,109,219,182,205,188,104,209, 34,237,236,217,179,139,253, 49,
+170, 84, 42,231,170, 84,170,100,149, 74,245,184, 82,169,236,163, 80, 40, 66,114,115,115, 21, 47,190,248,226,114,135,195, 1,218,
+137,199, 29, 14, 71, 6,128,175,218, 68,128,173,173,255,235,242, 97,208, 61,123,246, 16,190,231, 62, 45, 45, 77,208, 5,217,187,
+119, 47,241,231,251, 50,126,252, 96, 43, 2, 10, 90, 14,152, 15,249, 79,152, 48, 1, 37, 37, 37,130, 58, 44,111, 29, 14, 31,123,
+238,236,103,103,103,163,162,162, 2, 70,163, 81,210,101, 93, 51, 51, 12, 4, 65,163, 96,248, 56,133, 2, 0,131, 49,140, 18, 66,
+254, 27, 55,110,212, 86, 87, 87,155, 61,145,127,118,118, 54,114,115,115, 5,145, 63, 0,232,116, 58, 36, 37, 37,105,147,146,146,
+252,178,199,146, 61,251,127,253,127,163, 3,249,175, 94,172,193,134,237, 86, 94,231, 42,204,146, 69,198,140, 82,162,217, 66,240,
+194, 47, 52, 56,114,150,134,165,153,160,197, 6,104, 19,206,226,236, 69,135,160,104, 64,197,181,183, 73,221,141, 94, 8,237,173,
+198,192, 65, 33,232, 55, 32, 22, 87,202,109, 24, 62,218,142, 0, 77, 53, 76, 59,110, 97,199,142, 29,228,209, 71, 31,149, 59,188,
+123, 7,237,203, 15, 26,141, 70,115, 70, 70, 6,182,111,223,110,158, 61,123,118,167,107, 56,126,252,120,242,202, 43,175, 32, 35,
+ 35,195,235,245, 85,169, 84, 51,213,106,245, 24,181, 90,189, 82,173, 86, 7, 95,187,118, 13, 35, 71,142,132, 82,169, 68,104,104,
+ 40,202,202,202, 16, 18, 18,162, 58,122,244,104,248,225,195,135,191,120,238,185,231,134, 3,184, 2, 64, 13, 15,197,174, 50, 51,
+ 51, 59, 57, 43,220,126,139,109,167, 40, 10, 6,131,193,231,253,183,107,215, 46,143, 54,184,237,132, 16,164,165,165, 9, 58,161,
+ 59,119,238,244,235,251, 93, 76, 60, 41, 9, 9, 9,197,242,109,223,125,164, 47, 42, 2,192,151,252,249, 34, 59, 59,219,231, 54,
+124,136,203, 19,249,175, 95,191, 30,107,214,172,233,208, 46, 86, 4,100, 78, 48, 16,244, 29, 5,195,191, 82, 40,174,199, 63,107,
+214, 44, 10, 0,216,255,101,101,101,132, 15, 89,123, 35,255,182,200,128, 79,175,157, 13,211,115, 61,124,215,161, 5, 49,246,188,
+121,248,171, 23,243, 95, 41, 46,210,242, 2, 25,121,159, 18, 65,129, 20,238,139, 82,226, 86, 45, 3, 59,173, 68, 77, 29, 65,125,
+ 19, 65,217,247, 12,160, 0, 34,131, 79,195,100, 50,165,164,166,166,122,237, 20,174, 92,125, 43, 37, 46, 54, 6,135,111,220,196,
+136, 97,253, 48,102,108, 52,148,129, 17,184,111, 68, 45,106, 45, 86, 84,223,112,224,251,155, 86, 4,171, 42, 96, 50,133,250,180,
+215,213,240,228,149,139,189, 7,165,178,231, 73,108, 11,137, 16, 72, 12,134,125, 70, 40,138,130, 70,163,209, 2, 48,187,222, 19,
+ 19, 38, 76,224, 69,254, 0, 16, 16, 16, 16,174,209,104,150,221,186,117, 43,120,212,168, 81, 72, 76, 76,132, 74,165,194, 31,255,
+248, 71, 56, 28, 14, 60,248,224,131,248,228,147, 79,112,244,232, 81,156, 62,125, 26, 74,165,242, 79, 14,135, 99,129, 55,155, 11,
+ 22, 44,104, 63,127,190,250, 65, 62,132,155,151,151,167, 29, 56,112,160,153, 16,226,213, 1,186,113,227,134,224,181, 50, 88,219,
+ 98,191,207, 18,245,249,243,231,189,246, 27,113,113,113, 90,161,100,126,254,252,121,115,125,125, 61,194,194,194,180,178, 16,232,
+153, 80,121,234,124,124,121,234, 61, 5, 21, 21, 21, 88,179,102,141, 40, 1,225, 13, 78, 79, 63,147,250,236,179,207,136,209, 48,
+ 9, 80, 91, 8,159,177,127,119,100,237, 74,202,222,134, 5, 60,129, 43, 40,142, 28, 57, 98, 78, 74, 74,234, 16,250, 23,106,239,
+239, 47,134,120,236,220,158,120,179,153,183, 29,134, 97, 82, 2,131, 41, 40, 20, 64,112, 16, 80,215,192,160,149, 16,244, 10,162,
+ 96,101, 0, 75, 43,193,144,126, 10, 48, 52, 80,122,205,129,138,138, 10, 51,188,148,167, 61,119,118, 91,202,152, 49, 15,152,213,
+106,130, 95, 45,155, 12,135,131,224, 70,181, 13, 87,175,215, 1, 1,215, 16,212,167, 21, 85,213,151,161, 80,215,227,220,185, 58,
+132,245,241,110,239,110,193,149,156,245,122, 61,241,103,133, 65,215,133,158,168, 37,181,162,198,247,111,223, 78,237,240, 62, 34,
+194,228,147,216,132,136, 18,215,118, 31, 34,197,193, 62, 35,233,233,233, 72, 77, 77, 45, 54, 26,141,176, 88, 44,237,215,144,245,
+252,211,211,211,121, 93,211,192,192,192,169,205,205,205, 15,196,197,197, 65,171,213, 34, 43, 43, 11, 79, 63,253, 52, 0,192,110,
+183, 99,235,214,173, 40, 41, 41,193,241,227,199,241,209, 71, 31,193, 98,177,196, 50, 12, 51,215,155,205,121,243,230, 73,122, 63,
+237,217,179,135,215,208, 28, 69, 81,102,161, 33,124,174,109, 49,223, 7,156,107, 71,212,215,215,163,178,178,210,237,231, 81, 81,
+ 81, 16, 75,224,149,149,149,168,172,172,148,133,192, 93, 6, 55,220,239, 45, 26,160, 18,234,177, 75, 77,180,254,194,104, 52,250,
+245,253, 76,131,158, 96, 16, 96,200,112,118, 92,134,146,204, 14, 97,126,167,199, 95, 79, 92, 35, 1,124,201,186,186,186,186, 3,
+ 57,139, 33,107,190, 96, 69,135, 94,175, 39,190,234, 65,243, 33, 0, 54,252,239,201, 30, 33,132,220, 58,247, 2, 6,181,133,254,
+ 89, 88, 28, 4, 86, 27, 96,111,107,179,211, 4, 68,225,124,253,237,233, 18, 54, 75,192, 45, 66, 67,235,205,205, 22, 5, 34, 35,
+194, 81,119,187, 5,117,245,117, 56,114,236, 6,174,223, 36, 80,247,106,193,224,216, 38, 88, 90,110, 97,228, 88, 59,134,199,181,
+226,163,247, 75,176,111,223,190, 20,249,145,191, 55,192,122,255, 20, 69,161,176,176,144,164,167,167, 99,247,238,221, 8, 10, 10,
+ 74,201,206,206, 54, 11, 33,127, 0,129,117,117,117,191,180,219,237,138,224,224, 96, 36, 39, 39,227,205, 55,223, 68, 64, 64, 0,
+244,122, 61, 62,248,224, 3,148,148,148,224,200,145, 35,248,252,243,207,241,237,183,223, 34, 50, 50, 50,146,166,233,251,224, 99,
+173,139,204,204, 76,226,107, 8,224,253,247,223,231,181,159, 93, 57, 4,176,107,215, 46, 73,134, 0,194,194,194,180,149,149,149,
+102, 79,159,249,123,221,101, 33,112,143, 68, 0,238, 37,228,229,229, 81, 82,204, 90,103,201,221,184,230, 18,160, 84, 35,115,246,
+112, 32,124, 56, 12,109, 9, 75,124,199,254,165, 6,247,216,216, 73,127, 92,207,223, 21,236,220, 0, 79,147, 1,197,120,144,249,
+171,122,121,140, 8,132, 54,100,225,178,141,224,198, 45, 6,128, 2, 33,193,206, 16,167,157, 38,176,182, 2, 86, 27, 96,109, 5,
+108,118,192,106, 1,108,173,119,162, 36,238, 4, 69, 8,253, 2,185,126,117, 24,134,142, 8, 1, 9, 80,225,150,197, 2,243,129,
+107, 56, 87,118, 29,183,111, 55, 33,126,130, 3,205, 86, 26,214, 86, 7, 44, 45, 12,110, 92, 5, 44,205,192,142, 29, 59,204, 66,
+ 22,192,144, 33, 77,132, 67,196,179, 70, 88,239, 95,163,209,104, 83, 83, 83,139,217,148, 81,139,197, 98, 46, 41, 41,161,210,211,
+211,249,218,162, 1,196, 2, 96, 18, 18, 18, 24,141, 70,163,248,224,131, 15,176,124,249,114,188,241,198, 27, 32,132,224,235,175,
+191,198,129, 3, 7,112,250,244,105,212,215,215, 99,228,200,145,104,104,104, 8, 86, 40, 20,253,125, 25, 95,184,112,161, 71,145,
+204, 70, 80,230,205,155,199,247,220,245,232, 33, 0,111, 81, 0,127,188,127, 89, 8,200, 2,160, 75, 72, 81,167,211,105,217, 49,
+ 67, 87, 17,192,237,144,216,241,120,177, 99,177, 44,233,207,154, 53,139,114, 14, 3,168, 97,200,191,187,199,203,206,250, 79, 77,
+ 77,165, 76, 38, 19,241, 21, 13,241,149,118,232,141,208,221,193,219,182,191,252,109, 51,162, 6, 40,240,243, 12, 53,172,173, 64,
+ 88, 40, 5, 5,213,230,245,131,192,218, 2, 52,219, 8,154, 45, 4,205, 86, 2,134, 0, 10, 47,115,174,127,249,124, 51, 30, 28,
+ 87,129,129, 15,220,198,103,159, 86,227,246,109, 43, 18,166, 52, 96,108, 68, 19, 16,208, 10,107, 11,131,234,235, 4,205,205, 20,
+104,154, 66, 68, 36, 5, 80,140,252, 20,223, 59,104,191,127,217,231,151, 29, 6, 96,177,123,247,238, 78,243,143,220,204, 5, 96,
+ 47,122, 44,128,147,171, 87,175,158,170, 82,169, 66, 62,252,240, 67,108,217,178, 5, 79, 61,245, 20,214,175, 95, 15,138,162,112,
+249,242,101, 88, 44, 22,100,103,103,131,166,105,172, 88,177,130,161, 40,202,231, 3, 32,229,108,250,158, 62, 4,224, 45, 10, 32,
+133,247, 47, 67, 22, 0,146,194,117, 28,217, 19,193,183,109,199, 27,134, 18,231, 12,117, 39,241,151,194,248,199, 75,112,102, 1,
+116, 20, 5,124,134, 1,164, 2,235,205,155, 76, 38,194,245,254,217,136, 0,247,189, 78,167, 3, 91, 44,199, 93, 97, 13, 95,132,
+238, 10, 54, 11,192,147, 61,218, 1, 52,183, 16,180,218,156,147,253, 90,109, 4,170,192, 59,159, 89, 91, 0,139,157,160,230, 54,
+193, 15,181, 4,199,207,209, 96, 24, 64,167,211,105, 75, 75, 75, 59, 93, 27,154, 6, 42,175,217,112,173,188, 22, 95, 30,174, 5,
+ 33, 20,206,125,199, 32,253,231, 52,212, 42,130, 31,110, 2, 95,254, 11,104,104, 32, 32, 12,240,179,153, 20, 52, 26, 96,238,220,
+ 5,184,114,229, 10,175, 99, 42,216,170, 39, 11,151, 73,159, 42,234,207,120,191, 91, 50, 88, 82, 43,137,157,136, 8, 83,143,142,
+ 36,176,109,227,199,143, 39,199,143, 31, 71, 97, 97, 97,167,239,100,100,100,184, 51,165, 0,112, 6,192,201,141, 27, 55,142, 11,
+ 15, 15, 15, 1,156, 97,240,205,155, 55, 99,249,242,229,216,178,101, 75,187, 23,191,113,227, 70,212,213,213,161,161,161,161,169,
+165,165,165,162, 45,130,160,246,182,175,191,250,213,175, 58,204,135, 98, 61,120, 66, 8,239,240, 63,112,111, 12, 1,184,139, 2,
+ 72,237,253,179, 54,101,207, 95, 22, 0,126,161,164,164,196,231,108,114,147,201,148,194, 59,165, 48,176, 23,140,195, 15, 2,116,
+ 9,193,136, 94,200, 92, 55, 2,134,226,116, 10, 48,144, 59,130, 96,150,232, 97, 0,215, 84, 64, 79,169,129,158, 58, 75,189, 94,
+223, 78,254,174, 19, 0,219, 60,255,246, 54,111, 17, 0,174, 61,169, 58,243,189,123,247,166, 92,175,250,212,204,244, 99,160, 80,
+ 1, 1, 10,103,103,100,103, 8,104, 26,104,108, 36,176,217, 1,218,238, 20, 5, 11, 22, 58,163, 55,165,165,165, 30,237,181,222,
+218,107,142,143,103,240,197, 1, 7, 40, 5,240,195, 13, 10,154, 32,224,192, 62,192,102,161, 64, 17, 96,236,248, 0, 84, 94,101,
+ 48, 99,198, 60,164,165,165,121, 20, 60,174,228,191,225, 57, 96,245,187,210,138, 0, 79, 67, 81,221,109,207, 87,200,185, 27,224,
+118,103,216, 89,255,233,233,233,237,247, 40, 27,189, 91,188,120,177, 55, 15,180, 9,192,165, 19, 39, 78, 52, 77,159, 62,189, 31,
+ 56, 57,253,155, 55,111,110, 39, 89,187,221, 14,135,195,129,210,210, 82,244,235,215,239, 22,195, 48,188,212,226,194,133, 11, 61,
+121,234,130,136,246, 94, 24, 2,112, 23, 5,144,210,251,151,137,255, 71, 40, 0, 74, 74, 74,238,122,213, 62,214,203,101,137, 46,
+ 53, 53,149,114, 67,254,132, 13, 43,234,116, 58, 81,191,195,205, 2, 96,219,132,122,254,174, 19, 0,219,208,222,150,149,149,101,
+214,233,116,188, 31, 50, 46,249,187,155, 19, 32,212,158, 47,108,216,110,133, 47,123,105,105,105,197, 47,101,239,194,195, 73, 1,
+ 96, 0,216,109, 12, 2,213,206,211,212,216, 76,208,106, 39,160, 29, 64,201, 25, 7, 28, 12,129,175,148,189,180,180,180,226,223,
+255,110, 23,102,164, 40,241,232, 19, 74, 52, 53, 18, 52,214, 3,205,141, 20, 70,140, 36,112,216, 41,168, 20, 26,212,221,102, 80,
+249,189, 13,171,254,147,223,132,177,130,173,122,242,206,243,192,168, 97,192,166, 23,128,149,111, 73, 47, 2,164,140, 12, 72,101,
+175,171, 82,254, 68, 62,247,140, 59,242, 95,187,118,109,167, 48,255,182,109,219,204, 25, 25, 25,240, 80, 36,136, 37,122, 27,128,
+147,247,223,127,127,185,213,106, 29,172, 84, 42, 53,193,193,193, 0,128,237,219,183, 99,241,226,197,176, 88, 44,176, 90,173,104,
+109,109, 69, 72, 72,136,213,225,112,236, 36,132,220,224,179,179, 82,101, 3,220, 43, 67, 0,220, 40, 0,251, 90, 38,126, 89, 0,
+220, 53,242,231, 99, 51, 53, 53,149, 50, 26,141,164,205,219,133,209,104, 36,220,180, 68, 87,175,223,157, 64,232, 4, 37, 5,168,
+ 21, 64,144, 18, 8, 81, 1,173,141, 48,190, 17, 0, 4,125, 67, 50, 31, 27, 1, 4, 69,192,240, 87,225, 94,191,183,217,254, 44,
+ 89,243,205, 97,119, 37,127,215, 57, 1, 66,237,241, 37,127, 62,246, 94,207,125,143,122,225,249, 21, 68,163, 1, 24, 6,120,240,
+126,229,157,235,241,173, 3,118, 7,129,131, 81, 98,209,162, 69,188,196,201,171,175,189, 71,173, 90,181,130,208, 52, 96,179, 19,
+ 56,104, 64, 65, 1, 41,243,128,198, 58, 10,223,157,178,192, 98, 85, 96,126,198, 34, 94,199, 82,176, 85, 79,214, 62, 13,196, 14,
+113,190,143, 25, 12,116, 69, 36, 64,134, 48,120, 42,246,163,215,235, 73,122,122, 58,159,108, 0,101,120,120,248, 73,139,197,242,
+183,138,138,138,225,227,198,141,139,166,105, 90, 21, 16, 16,128,157, 59,119, 98,214,172, 89,176, 90,173,104,105,105, 65,105,105,
+105, 67,159, 62,125,246, 91, 44,150, 15, 25,134,105, 6,207, 10,128,108, 81, 32, 86, 76, 9, 9,253,179,184, 87,134, 0,184, 81,
+ 0, 41,174,175,152,218, 1, 50,238, 1, 1,208, 29,158,191,171,247,193,245,132, 60,133,250,165,220, 71, 33, 99,255, 82,147, 63,
+ 71,236,112, 11, 1,177, 34,200,220, 22,233, 16,100,207,215, 92, 0,161,246,222,250,195,123,148, 94,175, 39, 10, 5,240,101,137,
+115,172,159,157,240,231, 28,247, 95, 36,200,222,155,111,190, 71,173,120,182,173, 38,133,194,105,227,155,131, 64,115, 19, 3,194,
+ 0,243,231,207,195,156, 57,115,124, 94,143,130,173,122,146,253, 36, 16, 30, 2, 84,222, 2,130, 2, 1,134, 0,189, 52,192, 58,
+ 61,144,147, 39,139, 0,190,240, 21,125, 16,250,188,185, 35,255, 21, 43, 86, 16, 54, 19,160,176,176,144, 80, 20,229, 77, 8,132,
+216,108,182, 38,133, 66, 97,138,138,138, 26,210,216,216,248,220,177, 99,199, 6, 37, 38, 38, 50, 52, 77,183,212,215,215,223, 60,
+117,234,212,229, 17, 35, 70,148,247,237,219,183,194, 98,177,108,167,105,250, 38, 33,132,183, 0, 96,139, 2,113,162, 2, 98,250,
+ 43,109, 23,246,133,146,219,150,138,180,101,242,191, 71, 5,128,175, 92,127,161, 15, 58,223,218, 1, 66,236,230,229,229, 81,158,
+ 22,219, 17, 66, 94,134,204, 60,103,152,255, 34,128,139,174,159,214,183,253, 93,130,136,227, 53, 75, 69,174,220,243,162,215,235,
+ 9, 91,103, 32, 43, 43, 75, 84,134,131,171,189,252, 85,189,218, 69,129, 63,162,201,245,154,176, 19,254,196, 70, 37,222,251,115,
+ 71,123, 77, 13,206, 14,120,254,252,249,194,238,191,191,221, 93, 34,236,110,123, 61,108,220,191,131,199,206,125,227, 74,254, 38,
+147, 41,133, 16,130,221,187,119,115,183,241,102,239,170,205,102, 11, 36,132, 52, 50, 12,147,103,179,217,190, 30, 54,108, 88,100,
+ 93, 93, 29,245,242,203, 47, 55,212,215,215,215, 12, 30, 60,184,177,169,169,169,217,102,179, 53,216,237,246, 86,135,195, 97, 17,
+178,195, 18, 13, 3,116, 37, 17,202, 36, 43, 67, 58, 1, 32,181,103,223,149,145,130,212,212,212, 98, 94, 33,126, 31,144,114, 86,
+255,221,136,140, 8, 89,244, 71,138,104,128,208,107,194, 77,235,242,119, 72,194,213,158, 80,242,151,218,187,239,233,207, 71, 87,
+222,127, 18,216,166,218, 4, 10, 81, 40, 20, 96,255, 88,193, 50,111,222, 60,204,157, 59, 23, 12,195,128, 97, 24, 16, 66,124,253,
+ 30, 69,211,116, 48, 33,196,193, 48, 76,171,221,110, 63,168, 84, 42, 41,133, 66, 17, 8, 32,144, 97, 24, 56, 28, 14, 37, 77,211,
+106,154,166, 7, 57, 28,142,243,156,239,118,249, 34, 64, 50,100,244, 4,120,171,145, 66, 37, 36, 36,200,203, 99,202,144, 33,227,
+ 94, 69, 11,135,208, 25,142, 99,163,226,180, 87, 1, 8, 3,160,145,137, 95,134, 12, 47, 17, 0, 25, 50,100,200,184,135,160,105,
+ 19, 1, 12,135,248, 21,184,179,242,160, 10,192,160,182,215,114,213, 40, 25, 50,100, 1, 32, 67,134,140, 31, 9, 20, 0, 66, 56,
+239, 89,226, 87,115, 72,159,105,219, 78,246,254,101,200,144, 5,128, 12, 25, 50,126, 34,125,154, 76,250, 50,100,120, 81,207, 50,
+100,200,144, 33, 67,134,140,159,178, 90,126,246,217,103,185, 11,233, 16,238, 12,123,189, 94, 79, 92, 22,218,185,154,154,154, 58,
+140,125,239,174, 20, 43,215,158, 80,252, 24,237,185,166, 45,114,207,167,124,254,228,235,209,211,237,173, 91,183,174,125,155,156,
+156, 28, 74,132, 61,192, 67, 57, 96,249,126,246,109,243,167,118,255,157, 56,113, 66,180,189,196,196,196,159,188, 61,193, 2, 64,
+ 32,250,241,217,136, 93,189, 79, 42,197,226,154, 51,237,110, 53, 64,119,219,116,135,186, 98, 9, 70,167,211,105, 89,162, 97, 43,
+128,245,148, 92,237,221,187,119,167, 20, 22, 22,182,147,224,188,121,243,180,243,231,207, 47,254, 49,170, 93,119,215,227,252,121,
+103,102, 88, 92, 92, 92,183,238,155, 94,175, 39, 11, 22,234,177,179, 32,207,237, 61,187,247,211,227,100,103, 65,158,215,123,121,
+239,167,199,189,118, 2,105,115,199,139,190,233,214,173, 91, 71, 50, 50, 98, 58,188,247, 37, 2,124,161,177,169, 49,101,215,191,
+118, 33, 58, 62,218, 12, 10, 56,127,226,156,118, 74,194, 84,196,221, 31, 39,232,254, 59,116,232, 80,167,227,158, 58,117,170, 92,
+220, 73,134,140, 46, 20, 0,106,190, 27, 38, 37, 37, 9, 54,238,110,177, 24, 22,238, 72,212,117,161, 13,190, 68, 43,166, 8, 11,
+ 31, 65,193,218,205,206,206, 70,110,110,174,217, 83, 77,118,118, 59,111,185,154,174,251, 56,120,196, 80, 0,192, 77,171, 21,180,
+165,213,217, 88,215, 0,192,185,246,129,144,218, 8, 92,242, 7,156,181,197,133,228,218,235,245,122,162,160,156,213,245,216,255,
+128,247,215,127,126,239,238, 11, 50,215,235,193, 18,191,216,235, 33,165,168,100,201, 63,109,238,120, 43,160,215,236, 44,200, 19,
+253, 27,172,128,112, 47, 0,242,252,218, 79,155, 45, 27, 69, 69,153,152, 51,199,128,140,140,220,246,136,128, 24, 33,240,229,217,
+ 47,201,125,137, 67,241,118,222,155,232, 19,220, 7, 12,237,128,149,180,154,247,125,253,175, 57,251, 15,124, 78,166, 70, 79,211,
+106, 52, 26,159, 66,224,208,161, 67,164, 45,178,208,201,163,148, 69,128,140,159, 50, 78,158, 60,217,225,189,187, 62,205, 31, 1,
+ 32,104,254,128,187, 85,236,164, 0, 1, 82,252,182, 33, 96,193, 20, 62,158,187, 94,175, 39,217,217,217, 88,191,126, 61, 0,180,
+255,119,183,157,224, 21,219,194,123,227,116,197, 63, 17,132, 33,112,224, 43, 84,255,229, 56, 78,149,215, 96,209,250, 45,221,118,
+163,157,254,246, 12,198, 62, 56, 6, 12, 1,206,156,113,190, 6,238,188,230,182, 51, 60, 79, 53,183, 6,187, 55, 24, 12, 6,138,
+239,245, 88,182,108, 25, 0,180,255,119, 75,254, 20, 5,120,185, 31,244,122, 61,121,248,225, 79,161,215,207,149, 84, 4,164,205,
+ 29,223,146,153,153, 25, 12, 24,176,179, 64, 24,177,115, 61,124,127, 73,222,147,247, 15, 0,139, 23,111, 71, 81,145,243,127,102,
+102, 57,216,136,128,144,104, 0, 33, 36,197,124, 97,191,249,185,255,120, 22, 15,245, 75, 68, 80, 88, 24,136,141, 6, 67, 28, 80,
+170,212,136, 77,141, 45,250,110,194, 5,172, 55,228,154, 39, 71, 38,105,131,131,131,125,138,128, 91,183,110,117,120, 63,111,122,
+ 47, 76,126,254, 43, 60,158,107,237,112, 33,103,206,156, 41,250,122, 21, 20, 20,144,133, 11, 23, 74,118,189,165,182,215,197, 68,
+146,226,111, 89,223,147, 39, 79,166,180,145,144,104, 59, 20, 69,245, 5, 48, 28,192,108, 0, 3, 0,196, 1, 56, 9,231,162, 80,
+ 0,144, 79, 8,249, 78,166,254,206,228,207,182,185,138,128, 14, 2,160,162,162,130, 84, 84, 84, 0, 0,162,163,163,193, 93,108,
+ 6, 64,135,247,238, 62,247,132,234,234,106,179,209,104,228, 29, 9,112, 93,235,222, 27, 9, 83,109,165, 48, 93, 73, 84,104,136,
+221, 96, 48,248,220,198,100,242,189,182,122,219,144,135, 71,210, 95,179,102, 13,114,115,115,193, 21, 8,124, 48,120,196, 80, 92,
+175,173,199, 39, 43, 22,163, 47, 53, 13,229,239,175, 66,244,163,209,248,172,155,201, 31, 64, 59,225, 3,192,152, 49, 99, 58,180,
+179,145, 1,110,187,212,158,189, 55, 34,102,175,135, 39,210,223,186,117, 43,114,115,115, 49,119, 90, 34, 62,253,234, 4, 16,218,
+ 11,104,104,186,235,231,112,239,167,199,131, 1, 3,246,126,122, 92, 18,123, 11, 27, 94,242,250,108, 22,244,126,157,215, 3,194,
+ 13,253,103,102, 22, 33, 35, 35,166,253, 63,139,140,140, 24,222, 34,224,253,127,188,143, 55,222,125, 13,211, 71,166,192,209,218,
+ 10,218, 65,131, 82, 81, 0,148, 32, 96,112,243,135, 74,196,245,123, 0, 47,173,120, 9,175,109,120,205,252,240, 24,223,209, 44,
+215,206,110, 94,212, 86,183,132,191,127,255,126, 34, 70, 4, 20, 20, 20,144,189, 47,127,138,180,255,134, 36,164, 93, 80, 80, 64,
+ 54,108,216,128,213,171, 87,247,104, 17,112,242,228,201,148,250,250,122,115,101,101, 37, 18, 18, 18,252,218,207,250,250,122,243,
+157, 46, 91, 20,249,135, 0,248, 55, 0, 39, 0,124, 8, 96, 22,128, 71, 0,252,154, 35, 0,110,201,212,239,226, 72,101, 59, 57,
+198,144,187,198,237,231, 29, 4, 64,116,116, 52, 21, 29, 29,221, 78,246,220, 80,178,209,104,236,240,222,245,243,210,210, 82,143,
+ 29, 14, 43, 42,178,178,178,204,217,217,217,112, 93, 40,199,117,241, 28,163,209,232, 49, 4,235,174,179,119,109,235,206,133,138,
+ 0,224,227,143, 63,246, 72,252, 0, 58,144,255,154, 53,107,120,217,252,190,226, 42,154,119,252, 30, 33,203,255,128,193, 35,134,
+ 98, 64,223, 32, 84,236,168,112,146,127,120,111,231, 16, 64,128, 82,240,190,102,100,100,104,185,195, 0, 25, 25, 25,130,163, 52,
+ 12, 1,134,245, 2,254,247, 73,224,153,173, 64,191, 96,224,124,157,251,246,179,181,130, 31,124,191,163, 54,175,190,250,170, 71,
+226, 7,128, 13,203,210,177,105,223, 17, 12,140, 30,132, 27, 87,110,250,244,254, 1,128, 79, 20, 64, 72, 24,223,233,225,235,221,
+122,250,236,216,190,208,251,122,195,223, 61,159,163, 81, 43, 32,226, 94,137,233,240,223,150, 17, 11,117, 97, 25,239,239,183, 88,
+ 90, 48,109,233, 84,115,210,160,201,104,109,110,134, 42, 48, 16, 42,213,157, 46,168,162,172, 12,187,118,238,188,190,252,169,101,
+131,135, 7, 14, 67,226,140,132,212,175,139,190, 78,153,252,208,100, 65, 94,227,186,189,203,112,224,192, 1, 60,246, 88,199,246,
+153, 51,103, 82, 66, 69, 0, 75,254, 24,254, 54,246,190,252,159,126,139,128,130,130, 2,242,206, 59,239, 96,212,168, 81,216,180,
+105, 19, 86,174, 92,217,227, 68, 0,151,248,165,178,199,218,242, 35,154,160, 5, 48, 3,192, 86, 66, 72, 19, 69, 81, 3, 1, 92,
+ 0,112,133, 16, 66,203, 84,223, 89, 16,179,228,207,190, 54,228,174,233, 20, 5,184, 43,117, 0,140, 70, 35, 59,246,138,138,138,
+ 10,244,239,223,191,147, 64, 96,219,170,171,171,121,213,185,247, 53, 25, 80, 72,135,185,100,201,146, 46, 59,118, 46,129,185,243,
+250,115,115,115,145,151,151, 71,185,155, 5,203,133, 5, 87,209,244,232,100,144,208, 85, 64,234,203,104,194, 63,128,191, 56,189,
+ 69, 98, 92,133,128,127,223, 4,154, 22, 94,232, 44, 61, 61,189,152,199,178,171,222, 35, 60,155,129, 87,222, 3,134, 14, 1,110,
+238, 86,227,131,255,179, 97,217, 63, 61,183, 11,129,212,235,217,115, 39,251, 85, 21,172, 71,104,188, 6, 33, 35,127,131,143,215,
+ 63,131,113, 99, 6,226,254,244,215,120, 93, 15, 62,247, 39,223,161, 2,246,222,229,146,127, 94, 94, 30,197, 78,252, 19, 69, 52,
+189, 95,167,196,144,188, 59,216, 50, 98,221,182, 23,185, 68, 2,124,161,170,186, 10,179,117,179, 17,218,187, 15, 28, 20,141, 47,
+ 14, 28, 68, 99, 83, 19, 50,230,207,199, 15,213,213,216,182,253, 19, 60,253,212,178,193,129,154, 64, 40, 72, 0,230,140,159, 99,
+186, 96,222, 36,202,107,172,173,173,245,251,184,185,228, 15,192,111, 17, 80, 80, 80, 64,214,174, 93,139,216, 88,231,249,140,137,
+137, 65, 79,138, 4, 72, 77,252,110,188,127,246,181,152, 99, 29, 13,128, 0, 8,160, 40, 42, 24, 64, 60,128,115, 0, 6, 83, 20,
+213, 0,160,142, 72,221, 89,252, 4,112,215, 10, 1,245,239,223, 95,171,211,233, 58, 13, 5, 28, 57,114,196,220,182,216,139,224,
+ 57, 2,158, 38, 3,122,243, 28, 61, 9,148,174, 0,235,221,123, 10,247,243,245,254, 1, 96,223,111,215, 34,227,141,183, 64,167,
+ 78,131, 10, 64,200,225, 50,124, 86, 94, 3, 0,160, 83, 87,194,254,109, 36,168,126,191, 22, 76, 82,124,163, 44,222, 80,179,240,
+ 31, 88,249,212, 53, 92, 92,177, 26,205,159,219, 48, 48,210,123,187, 20, 17, 0, 49,226, 96,235,214,173, 78, 53,156,145,140, 35,
+149,213, 8, 29, 23,138,235, 69,229,128, 38, 16,139, 87,254, 59, 34,134,164,119,219,131,232,105,214,191, 84, 81, 45,111, 25, 2,
+190,178, 3,138, 50,139, 48,199, 48, 7,139,183, 3,153, 69,206,215, 69,153, 69,130,163, 0, 77,214, 70, 68, 6,245, 5,109,109,
+ 1, 81, 16, 76,156, 52, 9, 59,118,236,176,190,243,214, 91, 26,134, 16, 60,241,228, 19,136,232, 27,129,150,166, 38,208, 14, 26,
+161, 1,189, 97, 87,216, 69, 29,111, 93, 93, 93,135,236, 0,161, 19, 2, 59,145, 63, 11,145, 34,160,160,160,128,100,103,103, 99,
+210,164, 73, 29,218,199,140, 25,131,117,235,214, 33, 39, 39,167,219, 68, 64, 87, 17,191,171,247, 15, 0,149,149,149, 98,163, 0,
+ 95,195, 57,222,223, 0,103,232,127, 54,128, 82, 0, 99, 1,236, 4,176, 5,128, 29, 50,196, 11, 0, 87, 66, 96,215,156,231,243,
+185,183, 89,211, 44,216,225, 5,118, 66, 32, 59, 55,128,141, 14, 68, 71, 71,155,217,225,130,238,234,120,165,132,175,177,126,214,
+251,231, 99,107,209,123,219, 65,230,143,192,205, 41,227,209, 23,211, 16,180,120, 19,232,170, 31,128,240,222, 80,213,252, 3,187,
+223, 41, 1,148, 74,193,199, 46,197, 82,180,167, 94,248, 55, 60,148, 0, 68,175, 60,131,248,144,167,112,225, 62, 29,240,191,171,
+ 61,182,119, 87, 4, 32, 55, 55, 23,211, 39,222,143,212,105,163,144,241,224,106,108,124,231,207, 56, 87,114, 29, 43,102, 62,132,
+ 27, 59,247,162,190,182, 65,146,251,193,221, 80,129,175,231,195,155,183, 47,213, 61,234,201,190,183,137,131, 57, 57, 57,212,186,
+117,235,200,226,237, 29, 5, 1, 0,204, 49,204,129,186,176, 12,133,133,229,237,153, 0,236,132,193,136,136, 8,119,114, 14, 12,
+195,192,193, 0,132,161, 17, 24,164,193,147,191,248,133,230,149,255,250, 47, 12, 24, 48,128, 25, 60,112,160,194,218,220, 4, 7,
+ 1, 8,227, 0,195,248,142,104, 77,157, 58,149,218,182,109, 27,169,169,169, 65, 67, 67, 67, 7,225,200,205, 14, 16,146, 21, 80,
+ 80, 80, 64, 54, 62,115, 22,208,196, 2, 55,222,237,188,129, 38, 22, 27,159, 57,139,172,191,240, 19, 1, 5, 5, 5,100,193,130,
+ 5,218, 49, 99,198,152,107,106,106, 58,125, 62,108,216, 48, 44, 88,176, 64,123, 47, 77, 12, 20,227,253,251, 19, 5, 32,132, 20,
+115,174,237, 32, 0,167, 0, 60, 74, 8,105,134, 12,105, 4,128, 75,161, 31, 95,133,128, 58,124,238, 45,100,170,211,233,220, 70,
+ 1, 88,178,239,223,191,191, 54, 59, 59,219,204,142,201,234,116, 58,175,105,128,222,188, 67,161,147,255,186, 42, 13,144,245,238,
+189, 77, 6, 20,130,242,255,201, 68,192,226, 77,176, 84, 94,132,234,240, 38,216,183,175, 4,149,246, 38,118,253,250, 49, 92,217,
+117, 9, 25, 27, 62, 4, 84,221, 83,217,121,181, 17, 40,218,176, 3,241, 87,230, 0,183,154,241,226,172,213, 94,219,165,136, 0,
+136,245,254,119,238, 88, 11,229,224,209, 8,193, 40, 92, 61, 96, 64, 35, 69,240,205,197,107, 72, 61,115,157,231,117,191,218,254,
+126,201,146,188, 14,100, 15, 0,159,127, 62,215,237,118,222,158, 15, 95,161,126, 41,210, 14,165,200, 16,200, 44,186, 67,252, 0,
+ 58,121,254,236,132,193,194,194,114,183,223, 15, 13, 10, 69,101,125, 37, 38, 13,159, 12, 75,171, 21,176, 88, 65,219,236,120, 41,
+ 59, 27,148, 2,138,150,230, 38, 48,140, 3,180,131, 32, 80, 21,128, 31,154,126, 64,128,195,119,182,241, 99,143, 61,214,126,110,
+ 14, 29, 58, 68,216,254,134,155, 29, 80, 85, 85,197,251, 56, 23, 46, 92, 72,101,253, 5,100,227, 51,103, 17, 55,162,243,239,159,
+191,100, 67,214, 95,226,193,151,172, 23, 46, 92, 72, 21, 20, 20,144, 73,147, 38, 97,216,176, 97,157, 62, 63,115,230, 12,118,238,
+220,105,238, 46,242,111,243,198,169,174, 28,251,231,194,143, 40, 0,139,217,112, 78,254,110,149, 41, 92, 66, 1,208, 85, 96, 61,
+127, 0, 72, 74, 74,210, 26,141, 70, 51, 27,250,247, 32, 14,180,165,165,165,102,161, 36, 44,182,147,148, 58, 13,144,235,253,187,
+ 35,126, 86,232, 8,217,223, 83,229, 53,176,127,251, 10,110,226, 43, 12, 76,123, 19,168,111, 64,185, 97, 21, 98,158,125, 27, 55,
+182,172, 2, 2, 84,128,162,123, 42, 59, 95,109, 6,226,250, 63,202,187,189, 59, 34, 0,185,185,185, 77, 75, 83, 39, 87,133, 49,
+125,134,182, 32, 64,179,253,237,149,248,211,238,147,120,241,145,159, 97,217, 91,127,199, 99,175,255,181, 91, 38,143,178, 2,180,
+173, 14, 0,229,175, 56,245, 39,212,239, 45, 10,144,217,230,217,187,146, 63,215,251,247,133,168,254, 81,216,247, 69, 17,166, 14,
+157,138,224, 94, 33, 96, 24, 2, 5,161,193, 80, 20, 8, 33,112, 16,128,102, 8,104,154,134,165,190, 25,123,142,238,129,218,161,
+ 22, 60, 41,213, 53, 43, 32,103,229, 52,204,139,170,128,225, 40,127, 27,158, 68,128, 80,242,231,218,203,201,201, 33, 27, 54,108,
+192,160, 65,131,238, 8,251,242,114,228,230,230,162, 39,120,254, 82, 11, 1,119,222,191, 63, 81,128,182,254, 55, 5,192,125, 0,
+126, 39, 79,254,187, 71, 4,128,235,172,127,157, 78,215, 62,238,206, 21, 7,220,215,254,120,240, 98, 58,114,169,210, 0, 61,121,
+255, 98,137,159,197,162,245, 91,240, 9,128, 71,222,152, 7, 98, 92, 5,106,201, 70,156, 42,175, 1, 21,209, 7,101,223, 55, 56,
+189,127,165,178, 91,110, 34, 79,249,254,254,212, 1,224, 35,184,248,138,131,173, 91,183,218, 0, 52, 62,147, 50,182,225, 55,111,
+254,193,246,219,151,178,173,253,122,247,175, 57,123,238,234,128,101,231,254, 30,210,221, 89, 35,158,200,153, 59, 68, 35, 60,163,
+192,221,111,248, 23, 1,112, 71,254,172,231, 15,192,231,132, 64,141, 70, 67,157,219,117,126,190,121, 90,241, 78,221,131,143,161,
+193,218, 0, 74, 1, 56, 75,138, 48,112, 56, 8, 24,154, 70,175,192, 80, 28,170, 63,129,210,195,101,152, 53,126, 86,177,223, 39,
+183,252, 87, 0,132,167, 1,118, 16, 1,131,174,226,124,213, 48, 81,228,207,181,183,122,245,106,178,105,211, 38,132,135,135,163,
+166,166, 6,107,215,174, 69, 79, 11,251, 75, 33, 4, 60,121,255, 98,162, 0, 20, 69, 13, 0, 48,176,237, 70, 73, 4,144, 5,160,
+ 92,166,111,137, 5, 64, 87,213, 1,240, 20, 17,216,184,113,163,214, 85, 40,232,116, 58,179, 80,123, 92, 34,232, 9, 37,118,185,
+222,191,107,250, 95, 69, 69, 69,135,243, 38,164,106, 31, 43, 2, 30,125, 99, 51,200,118, 32,114, 89, 30,138,127,243, 24,126,150,
+155, 15, 4, 4,160,151, 70,221, 45,199,203,205,241,119,247, 90,100, 29, 0, 26,128,162,237,218, 42,252,188, 30, 55,151,166, 78,
+174,252,141,161,112,196, 75, 79,207,238, 29, 53, 48,197, 6,224,180, 78,167, 11, 3, 16, 34,246,122,220, 33,233,185,228,225,135,
+ 63,229,132,255,133,125,223,155, 7,207, 45, 15,204, 87, 72,116, 69, 49, 32, 79,112, 37,125, 54, 34,224,105,200,227,151, 75,126,
+185,171,240,239,133,112, 44,165, 79,207, 24, 58, 99,108,223,208,190,176,218,173, 32,132, 64,173, 82,163,206,210,130, 35,223,127,
+142,173,127,251, 0,218,209, 90, 73, 10,135,173,219,187, 12, 31,124,240, 1, 86,173, 18, 94, 3,224,142, 8,128, 95,228,207,181,
+183,114,229, 74,182, 14, 0,122,242,152, 63, 87, 8,136,249,174,191,181, 3,184,143, 1,156,249,254, 86, 0, 47, 0, 56, 74, 8,
+113,200,244,237,241,220,227,228,201,147, 48,228,174,233, 84, 7,192,107, 33,160,174,170, 3,224, 46, 34,224,137,232,197, 68, 1,
+252, 69, 87,165, 1,178, 98, 36, 47, 47, 15, 38,147,137,169,168,168,224, 18,153, 54, 53, 53, 85,204,219, 75, 87, 0, 0, 2, 12,
+ 73, 68, 65, 84,176,119,179,104,253, 22,128, 83,248,103,198, 75,239,181,191,238,142,217, 48, 93,229, 61, 83, 20,245, 14,128,219,
+112,166,255, 60,233,167,185, 27,207,164,140,109,157,101,250,186,247, 19,255,245, 33,242,242,242,212, 38,147,105, 16, 58,150,179,
+ 22,117, 61,186, 58, 18,224,171,190,191, 47,116,197,144,128, 39,242,183,101,196, 2,133,190, 29, 51,237,216,153,212,129,109, 95,
+144,195,195,142, 96,218,228,105, 24, 28, 58, 24, 96, 8,126,176,214,224,208,241, 67,184,113,246, 6,102,198,205,212, 6, 6, 6,
+118,251,245,224,138, 0,169,200,154,141, 4,220, 43, 19,254,252,173, 2,232, 47, 8, 33, 6, 0, 6,200, 16, 12, 79, 5,128,220,
+ 10,128,174, 66, 86, 86,150, 91,178,231,174,196,230, 2, 51,159,172, 2,169,188,254,174, 72, 3,108,155,225, 79,155, 76, 38, 85,
+219,208, 1, 75,254, 51, 83, 83, 83, 5, 69, 57,218, 22, 83, 50, 75,189,143,158,198,152,165,174,117, 47, 16,129, 0, 84,121,121,
+121, 47,183,189,119, 0,248,133,191, 54,103,253,238,253,146,188,188,188,100,147,201, 4,147,201,100, 5,160,105,251,243,155,248,
+217, 40,128,216,115,230,139,228, 23, 44,212,119,216, 78, 40,113, 75, 49, 36,144,147,147, 67,173,203, 92, 71,162, 86, 70,105, 49,
+220,253, 54,149,153, 69,102,190,243, 1, 38,197, 79,162, 90, 90, 90, 82,182,188,177, 5,195, 98,239, 51, 3,192,133, 51,223,105,
+211,103,101, 32, 46, 33, 78,244,245,152, 58,117, 42,181,125,251,246, 78, 89, 1,118,187,127, 25, 98, 82,147,245,143,109,182,191,
+140,158, 25, 5,112,109,227, 45, 0,124,121,226,124, 61,117,177,157, 34,223, 66, 44,254, 18,149,212, 68,199,218, 51,153, 76,196,
+100, 50,169,184,231, 43, 58, 58, 90,212,111,181, 17,148,228, 29, 70, 79, 24,251,118,131, 80, 0, 77,206,130,252, 20, 5, 32, 8,
+126,228,247,114,174,199,101,147,201,196,230,149, 53, 68, 71, 71,247,139,142,142, 14,236, 9,231,210, 95, 79,220,151,109,169,134,
+ 4,124,146,123,142,176,123, 52, 56, 56,184,120,201,130,165, 96,239,237,164,248, 36, 73,246,115,241,226,197, 50,185,202,144, 69,
+ 0, 15, 39,154, 74, 72, 72,144,171, 39,201,144, 33, 67,134, 12, 25, 63, 49, 40,228, 83, 32, 67,134, 12, 25, 50,100,200, 2, 64,
+134, 12, 25, 50,100,200,144,241, 19,192,255, 3,117,205,212, 3,120, 27, 16, 76, 0, 0, 0, 0, 73, 69, 78, 68,174, 66, 96,130,
+};
+
diff --git a/source/blender/src/booleanops.c b/source/blender/src/booleanops.c
new file mode 100644
index 00000000000..04214beeb90
--- /dev/null
+++ b/source/blender/src/booleanops.c
@@ -0,0 +1,566 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * CSG operations.
+ */
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
+
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "CSG_BooleanOps.h"
+
+#include "BKE_booleanops.h"
+#include "BKE_cdderivedmesh.h"
+#include "BKE_customdata.h"
+#include "BKE_depsgraph.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_material.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_toolbox.h"
+
+#include "BDR_editface.h"
+
+#include <math.h>
+
+/**
+ * Here's the vertex iterator structure used to walk through
+ * the blender vertex structure.
+ */
+
+typedef struct {
+ Mesh *mesh;
+ Object *ob;
+ int pos;
+} VertexIt;
+
+/**
+ * Implementations of local vertex iterator functions.
+ * These describe a blender mesh to the CSG module.
+ */
+
+static void VertexIt_Destruct(CSG_VertexIteratorDescriptor * iterator)
+{
+ if (iterator->it) {
+ // deallocate memory for iterator
+ MEM_freeN(iterator->it);
+ iterator->it = 0;
+ }
+ iterator->Done = NULL;
+ iterator->Fill = NULL;
+ iterator->Reset = NULL;
+ iterator->Step = NULL;
+ iterator->num_elements = 0;
+
+}
+
+static int VertexIt_Done(CSG_IteratorPtr it)
+{
+ VertexIt * iterator = (VertexIt *)it;
+ return(iterator->pos >= iterator->mesh->totvert);
+}
+
+static void VertexIt_Fill(CSG_IteratorPtr it, CSG_IVertex *vert)
+{
+ VertexIt * iterator = (VertexIt *)it;
+ MVert *verts = iterator->mesh->mvert;
+
+ float global_pos[3];
+
+ /* boolean happens in global space, transform both with obmat */
+ VecMat4MulVecfl(
+ global_pos,
+ iterator->ob->obmat,
+ verts[iterator->pos].co
+ );
+
+ vert->position[0] = global_pos[0];
+ vert->position[1] = global_pos[1];
+ vert->position[2] = global_pos[2];
+}
+
+static void VertexIt_Step(CSG_IteratorPtr it)
+{
+ VertexIt * iterator = (VertexIt *)it;
+ iterator->pos ++;
+}
+
+static void VertexIt_Reset(CSG_IteratorPtr it)
+{
+ VertexIt * iterator = (VertexIt *)it;
+ iterator->pos = 0;
+}
+
+static void VertexIt_Construct(CSG_VertexIteratorDescriptor *output, Object *ob)
+{
+
+ VertexIt *it;
+ if (output == 0) return;
+
+ // allocate some memory for blender iterator
+ it = (VertexIt *)(MEM_mallocN(sizeof(VertexIt),"Boolean_VIt"));
+ if (it == 0) {
+ return;
+ }
+ // assign blender specific variables
+ it->ob = ob;
+ it->mesh = ob->data;
+
+ it->pos = 0;
+
+ // assign iterator function pointers.
+ output->Step = VertexIt_Step;
+ output->Fill = VertexIt_Fill;
+ output->Done = VertexIt_Done;
+ output->Reset = VertexIt_Reset;
+ output->num_elements = it->mesh->totvert;
+ output->it = it;
+}
+
+/**
+ * Blender Face iterator
+ */
+
+typedef struct {
+ Mesh *mesh;
+ int pos;
+ int offset;
+} FaceIt;
+
+static void FaceIt_Destruct(CSG_FaceIteratorDescriptor * iterator)
+{
+ MEM_freeN(iterator->it);
+ iterator->Done = NULL;
+ iterator->Fill = NULL;
+ iterator->Reset = NULL;
+ iterator->Step = NULL;
+ iterator->num_elements = 0;
+}
+
+static int FaceIt_Done(CSG_IteratorPtr it)
+{
+ // assume CSG_IteratorPtr is of the correct type.
+ FaceIt * iterator = (FaceIt *)it;
+ return(iterator->pos >= iterator->mesh->totface);
+}
+
+static void FaceIt_Fill(CSG_IteratorPtr it, CSG_IFace *face)
+{
+ // assume CSG_IteratorPtr is of the correct type.
+ FaceIt *face_it = (FaceIt *)it;
+ MFace *mfaces = face_it->mesh->mface;
+ MFace *mface = &mfaces[face_it->pos];
+
+ face->vertex_index[0] = mface->v1;
+ face->vertex_index[1] = mface->v2;
+ face->vertex_index[2] = mface->v3;
+ if (mface->v4) {
+ face->vertex_index[3] = mface->v4;
+ face->vertex_number = 4;
+ } else {
+ face->vertex_number = 3;
+ }
+
+ face->orig_face = face_it->offset + face_it->pos;
+}
+
+static void FaceIt_Step(CSG_IteratorPtr it)
+{
+ FaceIt * face_it = (FaceIt *)it;
+ face_it->pos ++;
+}
+
+static void FaceIt_Reset(CSG_IteratorPtr it)
+{
+ FaceIt * face_it = (FaceIt *)it;
+ face_it->pos = 0;
+}
+
+static void FaceIt_Construct(
+ CSG_FaceIteratorDescriptor *output, Object *ob, int offset)
+{
+ FaceIt *it;
+ if (output == 0) return;
+
+ // allocate some memory for blender iterator
+ it = (FaceIt *)(MEM_mallocN(sizeof(FaceIt),"Boolean_FIt"));
+ if (it == 0) {
+ return ;
+ }
+ // assign blender specific variables
+ it->mesh = ob->data;
+ it->offset = offset;
+ it->pos = 0;
+
+ // assign iterator function pointers.
+ output->Step = FaceIt_Step;
+ output->Fill = FaceIt_Fill;
+ output->Done = FaceIt_Done;
+ output->Reset = FaceIt_Reset;
+ output->num_elements = it->mesh->totface;
+ output->it = it;
+}
+
+static Object *AddNewBlenderMesh(Base *base)
+{
+ // This little function adds a new mesh object to the blender object list
+ // It uses ob to duplicate data as this seems to be easier than creating
+ // a new one. This new oject contains no faces nor vertices.
+ Mesh *old_me;
+ Base *basen;
+ Object *ob_new;
+
+ // now create a new blender object.
+ // duplicating all the settings from the previous object
+ // to the new one.
+ ob_new= copy_object(base->object);
+
+ // Ok we don't want to use the actual data from the
+ // last object, the above function incremented the
+ // number of users, so decrement it here.
+ old_me= ob_new->data;
+ old_me->id.us--;
+
+ // Now create a new base to add into the linked list of
+ // vase objects.
+
+ basen= MEM_mallocN(sizeof(Base), "duplibase");
+ *basen= *base;
+ BLI_addhead(&G.scene->base, basen); /* addhead: anders oneindige lus */
+ basen->object= ob_new;
+ basen->flag &= ~SELECT;
+
+ // Initialize the mesh data associated with this object.
+ ob_new->data= add_mesh("Mesh");
+ G.totmesh++;
+
+ // Finally assign the object type.
+ ob_new->type= OB_MESH;
+
+ return ob_new;
+}
+
+static void InterpCSGFace(
+ DerivedMesh *dm, Mesh *orig_me, int index, int orig_index, int nr,
+ float mapmat[][4])
+{
+ float obco[3], *co[4], *orig_co[4], w[4][4];
+ MFace *mface, *orig_mface;
+ int j;
+
+ mface = CDDM_get_face(dm, index);
+ orig_mface = orig_me->mface + orig_index;
+
+ // get the vertex coordinates from the original mesh
+ orig_co[0] = (orig_me->mvert + orig_mface->v1)->co;
+ orig_co[1] = (orig_me->mvert + orig_mface->v2)->co;
+ orig_co[2] = (orig_me->mvert + orig_mface->v3)->co;
+ orig_co[3] = (orig_mface->v4)? (orig_me->mvert + orig_mface->v4)->co: NULL;
+
+ // get the vertex coordinates from the new derivedmesh
+ co[0] = CDDM_get_vert(dm, mface->v1)->co;
+ co[1] = CDDM_get_vert(dm, mface->v2)->co;
+ co[2] = CDDM_get_vert(dm, mface->v3)->co;
+ co[3] = (nr == 4)? CDDM_get_vert(dm, mface->v4)->co: NULL;
+
+ for (j = 0; j < nr; j++) {
+ // get coordinate into the space of the original mesh
+ if (mapmat)
+ VecMat4MulVecfl(obco, mapmat, co[j]);
+ else
+ VecCopyf(obco, co[j]);
+
+ InterpWeightsQ3Dfl(orig_co[0], orig_co[1], orig_co[2], orig_co[3], obco, w[j]);
+ }
+
+ CustomData_interp(&orig_me->fdata, &dm->faceData, &orig_index, NULL, (float*)w, 1, index);
+}
+
+/* Iterate over the CSG Output Descriptors and create a new DerivedMesh
+ from them */
+static DerivedMesh *ConvertCSGDescriptorsToDerivedMesh(
+ CSG_FaceIteratorDescriptor *face_it,
+ CSG_VertexIteratorDescriptor *vertex_it,
+ float parinv[][4],
+ float mapmat[][4],
+ Material **mat,
+ int *totmat,
+ Object *ob1,
+ Object *ob2)
+{
+ DerivedMesh *dm;
+ GHash *material_hash = NULL;
+ Mesh *me1= (Mesh*)ob1->data;
+ Mesh *me2= (Mesh*)ob2->data;
+ int i;
+
+ // create a new DerivedMesh
+ dm = CDDM_new(vertex_it->num_elements, 0, face_it->num_elements);
+
+ CustomData_merge(&me1->fdata, &dm->faceData, CD_MASK_DERIVEDMESH,
+ CD_DEFAULT, face_it->num_elements);
+ CustomData_merge(&me2->fdata, &dm->faceData, CD_MASK_DERIVEDMESH,
+ CD_DEFAULT, face_it->num_elements);
+
+ // step through the vertex iterators:
+ for (i = 0; !vertex_it->Done(vertex_it->it); i++) {
+ CSG_IVertex csgvert;
+ MVert *mvert = CDDM_get_vert(dm, i);
+
+ // retrieve a csg vertex from the boolean module
+ vertex_it->Fill(vertex_it->it, &csgvert);
+ vertex_it->Step(vertex_it->it);
+
+ // we have to map the vertex coordinates back in the coordinate frame
+ // of the resulting object, since it was computed in world space
+ VecMat4MulVecfl(mvert->co, parinv, csgvert.position);
+ }
+
+ // a hash table to remap materials to indices
+ if (mat) {
+ material_hash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
+ *totmat = 0;
+ }
+
+ // step through the face iterators
+ for(i = 0; !face_it->Done(face_it->it); i++) {
+ Mesh *orig_me;
+ Object *orig_ob;
+ Material *orig_mat;
+ CSG_IFace csgface;
+ MFace *mface;
+ int orig_index, mat_nr;
+
+ // retrieve a csg face from the boolean module
+ face_it->Fill(face_it->it, &csgface);
+ face_it->Step(face_it->it);
+
+ // find the original mesh and data
+ orig_ob = (csgface.orig_face < me1->totface)? ob1: ob2;
+ orig_me = (orig_ob == ob1)? me1: me2;
+ orig_index = (orig_ob == ob1)? csgface.orig_face: csgface.orig_face - me1->totface;
+
+ // copy all face layers, including mface
+ CustomData_copy_data(&orig_me->fdata, &dm->faceData, orig_index, i, 1);
+
+ // set mface
+ mface = CDDM_get_face(dm, i);
+ mface->v1 = csgface.vertex_index[0];
+ mface->v2 = csgface.vertex_index[1];
+ mface->v3 = csgface.vertex_index[2];
+ mface->v4 = (csgface.vertex_number == 4)? csgface.vertex_index[3]: 0;
+
+ // set material, based on lookup in hash table
+ orig_mat= give_current_material(orig_ob, mface->mat_nr+1);
+
+ if (mat && orig_mat) {
+ if (!BLI_ghash_haskey(material_hash, orig_mat)) {
+ mat[*totmat] = orig_mat;
+ mat_nr = mface->mat_nr = (*totmat)++;
+ BLI_ghash_insert(material_hash, orig_mat, (void*)mat_nr);
+ }
+ else
+ mface->mat_nr = (int)BLI_ghash_lookup(material_hash, orig_mat);
+ }
+ else
+ mface->mat_nr = 0;
+
+ InterpCSGFace(dm, orig_me, i, orig_index, csgface.vertex_number,
+ (orig_me == me2)? mapmat: NULL);
+
+ test_index_face(mface, &dm->faceData, i, csgface.vertex_number);
+ }
+
+ if (material_hash)
+ BLI_ghash_free(material_hash, NULL, NULL);
+
+ CDDM_calc_edges(dm);
+ CDDM_calc_normals(dm);
+
+ return dm;
+}
+
+static void BuildMeshDescriptors(
+ struct Object *ob,
+ int face_offset,
+ struct CSG_FaceIteratorDescriptor * face_it,
+ struct CSG_VertexIteratorDescriptor * vertex_it)
+{
+ VertexIt_Construct(vertex_it,ob);
+ FaceIt_Construct(face_it,ob,face_offset);
+}
+
+static void FreeMeshDescriptors(
+ struct CSG_FaceIteratorDescriptor *face_it,
+ struct CSG_VertexIteratorDescriptor *vertex_it)
+{
+ VertexIt_Destruct(vertex_it);
+ FaceIt_Destruct(face_it);
+}
+
+DerivedMesh *NewBooleanDerivedMesh_intern(
+ struct Object *ob, struct Object *ob_select,
+ int int_op_type, Material **mat, int *totmat)
+{
+
+ float inv_mat[4][4];
+ float map_mat[4][4];
+
+ DerivedMesh *dm = NULL;
+ Mesh *me1 = get_mesh(ob_select);
+ Mesh *me2 = get_mesh(ob);
+
+ if (me1 == NULL || me2 == NULL) return 0;
+ if (!me1->totface || !me2->totface) return 0;
+
+ // we map the final object back into ob's local coordinate space. For this
+ // we need to compute the inverse transform from global to ob (inv_mat),
+ // and the transform from ob to ob_select for use in interpolation (map_mat)
+ Mat4Invert(inv_mat, ob->obmat);
+ Mat4MulMat4(map_mat, ob_select->obmat, inv_mat);
+ Mat4Invert(inv_mat, ob_select->obmat);
+
+ {
+ // interface with the boolean module:
+ //
+ // the idea is, we pass the boolean module verts and faces using the
+ // provided descriptors. once the boolean operation is performed, we
+ // get back output descriptors, from which we then build a DerivedMesh
+
+ CSG_VertexIteratorDescriptor vd_1, vd_2;
+ CSG_FaceIteratorDescriptor fd_1, fd_2;
+ CSG_OperationType op_type;
+ CSG_BooleanOperation *bool_op;
+
+ // work out the operation they chose and pick the appropriate
+ // enum from the csg module.
+ switch (int_op_type) {
+ case 1 : op_type = e_csg_intersection; break;
+ case 2 : op_type = e_csg_union; break;
+ case 3 : op_type = e_csg_difference; break;
+ case 4 : op_type = e_csg_classify; break;
+ default : op_type = e_csg_intersection;
+ }
+
+ BuildMeshDescriptors(ob_select, 0, &fd_1, &vd_1);
+ BuildMeshDescriptors(ob, me1->totface, &fd_2, &vd_2);
+
+ bool_op = CSG_NewBooleanFunction();
+
+ // perform the operation
+ if (CSG_PerformBooleanOperation(bool_op, op_type, fd_1, vd_1, fd_2, vd_2)) {
+ CSG_VertexIteratorDescriptor vd_o;
+ CSG_FaceIteratorDescriptor fd_o;
+
+ CSG_OutputFaceDescriptor(bool_op, &fd_o);
+ CSG_OutputVertexDescriptor(bool_op, &vd_o);
+
+ // iterate through results of operation and insert
+ // into new object
+ dm = ConvertCSGDescriptorsToDerivedMesh(
+ &fd_o, &vd_o, inv_mat, map_mat, mat, totmat, ob_select, ob);
+
+ // free up the memory
+ CSG_FreeVertexDescriptor(&vd_o);
+ CSG_FreeFaceDescriptor(&fd_o);
+ }
+ else
+ error("Unknown internal error in boolean");
+
+ CSG_FreeBooleanOperation(bool_op);
+
+ FreeMeshDescriptors(&fd_1, &vd_1);
+ FreeMeshDescriptors(&fd_2, &vd_2);
+ }
+
+ return dm;
+}
+
+int NewBooleanMesh(Base *base, Base *base_select, int int_op_type)
+{
+ Mesh *me_new;
+ int a, maxmat, totmat= 0;
+ Object *ob_new, *ob, *ob_select;
+ Material **mat;
+ DerivedMesh *dm;
+
+ ob= base->object;
+ ob_select= base_select->object;
+
+ maxmat= ob->totcol + ob_select->totcol;
+ mat= (Material**)MEM_mallocN(sizeof(Material*)*maxmat, "NewBooleanMeshMat");
+
+ dm= NewBooleanDerivedMesh_intern(ob, ob_select, int_op_type, mat, &totmat);
+
+ if (dm == NULL) {
+ MEM_freeN(mat);
+ return 0;
+ }
+
+ /* create a new blender mesh object - using 'base' as a template */
+ ob_new= AddNewBlenderMesh(base_select);
+ me_new= ob_new->data;
+
+ DM_to_mesh(dm, me_new);
+ dm->release(dm);
+
+ /* add materials to object */
+ for (a = 0; a < totmat; a++)
+ assign_material(ob_new, mat[a], a+1);
+
+ MEM_freeN(mat);
+
+ /* update dag */
+ DAG_object_flush_update(G.scene, ob_new, OB_RECALC_DATA);
+
+ return 1;
+}
+
+DerivedMesh *NewBooleanDerivedMesh(struct Object *ob, struct Object *ob_select,
+ int int_op_type)
+{
+ return NewBooleanDerivedMesh_intern(ob, ob_select, int_op_type, NULL, NULL);
+}
+
diff --git a/source/blender/src/booleanops_mesh.c b/source/blender/src/booleanops_mesh.c
new file mode 100644
index 00000000000..d0b40b6eb7e
--- /dev/null
+++ b/source/blender/src/booleanops_mesh.c
@@ -0,0 +1,296 @@
+#if 0
+
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#include "CSG_BooleanOps.h"
+
+#include "BKE_booleanops.h"
+#include "BKE_booleanops_mesh.h"
+#include "MEM_guardedalloc.h"
+
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_global.h"
+#include "BKE_mesh.h"
+#include "BKE_displist.h"
+#include "BKE_object.h"
+#include "BKE_utildefines.h"
+#include "BKE_library.h"
+#include "BKE_material.h"
+
+#include "BLI_arithb.h"
+
+/**
+ * Implementation of boolean ops mesh interface.
+ */
+
+ void
+CSG_DestroyMeshDescriptor(
+ CSG_MeshDescriptor *mesh
+){
+ // Call mesh descriptors destroy function....
+ mesh->m_destroy_func(mesh);
+}
+
+// Destroy function for blender mesh internals.
+
+static
+ void
+CSG_DestroyBlenderMeshInternals(
+ CSG_MeshDescriptor *mesh
+) {
+ // Free face and vertex iterators.
+ FreeMeshDescriptors(&(mesh->m_face_iterator),&(mesh->m_vertex_iterator));
+}
+
+
+static
+ void
+CSG_DestroyCSGMeshInternals(
+ CSG_MeshDescriptor *mesh
+){
+ CSG_FreeVertexDescriptor(&(mesh->m_vertex_iterator));
+ CSG_FreeFaceDescriptor(&(mesh->m_face_iterator));
+}
+
+static
+ int
+MakeCSGMeshFromBlenderBase(
+ Base * base,
+ CSG_MeshDescriptor * output
+) {
+ Mesh *me;
+ if (output == NULL || base == NULL) return 0;
+
+ me = get_mesh(base->object);
+
+ output->m_descriptor.user_face_vertex_data_size = 0;
+ output->m_descriptor.user_data_size = sizeof(FaceData);
+
+ output->base = base;
+
+ BuildMeshDescriptors(
+ base->object,
+ &(output->m_face_iterator),
+ &(output->m_vertex_iterator)
+ );
+
+ output->m_destroy_func = CSG_DestroyBlenderMeshInternals;
+
+ return 1;
+}
+
+ int
+CSG_LoadBlenderMesh(
+ Object * obj,
+ CSG_MeshDescriptor *output
+){
+
+ Mesh *me;
+ if (output == NULL || obj == NULL) return 0;
+
+ me = get_mesh(obj);
+
+ output->m_descriptor.user_face_vertex_data_size = 0;
+ output->m_descriptor.user_data_size = sizeof(FaceData);
+
+ output->base = NULL;
+
+ BuildMeshDescriptors(
+ obj,
+ &(output->m_face_iterator),
+ &(output->m_vertex_iterator)
+ );
+
+ output->m_destroy_func = CSG_DestroyBlenderMeshInternals;
+ output->base = NULL;
+
+ return 1;
+}
+
+
+
+
+ int
+CSG_AddMeshToBlender(
+ CSG_MeshDescriptor *mesh
+){
+ Mesh *me_new = NULL;
+ Object *ob_new = NULL;
+ float inv_mat[4][4];
+
+ if (mesh == NULL) return 0;
+ if (mesh->base == NULL) return 0;
+
+ Mat4Invert(inv_mat,mesh->base->object->obmat);
+
+ // Create a new blender mesh object - using 'base' as
+ // a template for the new object.
+ ob_new= AddNewBlenderMesh(mesh->base);
+
+ me_new = ob_new->data;
+
+ // make sure the iterators are reset.
+ mesh->m_face_iterator.Reset(mesh->m_face_iterator.it);
+ mesh->m_vertex_iterator.Reset(mesh->m_vertex_iterator.it);
+
+ // iterate through results of operation and insert into new object
+ // see subsurf.c
+
+ ConvertCSGDescriptorsToMeshObject(
+ ob_new,
+ &(mesh->m_descriptor),
+ &(mesh->m_face_iterator),
+ &(mesh->m_vertex_iterator),
+ inv_mat
+ );
+
+ return 1;
+}
+
+ int
+CSG_PerformOp(
+ CSG_MeshDescriptor *mesh1,
+ CSG_MeshDescriptor *mesh2,
+ int int_op_type,
+ CSG_MeshDescriptor *output
+){
+
+ CSG_OperationType op_type;
+ CSG_BooleanOperation * bool_op = CSG_NewBooleanFunction();
+ int success = 0;
+
+ if (bool_op == NULL) return 0;
+
+ if ((mesh1 == NULL) || (mesh2 == NULL) || (output == NULL)) {
+ return 0;
+ }
+ if ((int_op_type < 1) || (int_op_type > 3)) return 0;
+
+ switch (int_op_type) {
+ case 1 : op_type = e_csg_intersection; break;
+ case 2 : op_type = e_csg_union; break;
+ case 3 : op_type = e_csg_difference; break;
+ case 4 : op_type = e_csg_classify; break;
+ default : op_type = e_csg_intersection;
+ }
+
+ output->m_descriptor = CSG_DescibeOperands(bool_op,mesh1->m_descriptor,mesh2->m_descriptor);
+ output->base = mesh1->base;
+
+ if (output->m_descriptor.user_face_vertex_data_size) {
+ // Then use the only interp function supported
+ success =
+ CSG_PerformBooleanOperation(
+ bool_op,
+ op_type,
+ mesh1->m_face_iterator,
+ mesh1->m_vertex_iterator,
+ mesh2->m_face_iterator,
+ mesh2->m_vertex_iterator,
+ InterpFaceVertexData
+ );
+ } else {
+ success =
+ CSG_PerformBooleanOperation(
+ bool_op,
+ op_type,
+ mesh1->m_face_iterator,
+ mesh1->m_vertex_iterator,
+ mesh2->m_face_iterator,
+ mesh2->m_vertex_iterator,
+ InterpNoUserData
+ );
+ }
+
+ if (!success) {
+ CSG_FreeBooleanOperation(bool_op);
+ bool_op = NULL;
+ return 0;
+ }
+
+ // get the ouput mesh descriptors.
+
+ CSG_OutputFaceDescriptor(bool_op,&(output->m_face_iterator));
+ CSG_OutputVertexDescriptor(bool_op,&(output->m_vertex_iterator));
+ output->m_destroy_func = CSG_DestroyCSGMeshInternals;
+
+ return 1;
+}
+
+ int
+NewBooleanMeshTest(
+ struct Base * base,
+ struct Base * base_select,
+ int op_type
+){
+
+ CSG_MeshDescriptor m1,m2,output;
+ CSG_MeshDescriptor output2,output3;
+
+ if (!MakeCSGMeshFromBlenderBase(base,&m1)) {
+ return 0;
+ }
+
+ if (!MakeCSGMeshFromBlenderBase(base_select,&m2)) {
+ return 0;
+ }
+
+ CSG_PerformOp(&m1,&m2,1,&output);
+ CSG_PerformOp(&m1,&m2,2,&output2);
+ CSG_PerformOp(&m1,&m2,3,&output3);
+
+ if (!CSG_AddMeshToBlender(&output)) {
+ return 0;
+ }
+ if (!CSG_AddMeshToBlender(&output2)) {
+ return 0;
+ }
+ if (!CSG_AddMeshToBlender(&output3)) {
+ return 0;
+ }
+
+
+ CSG_DestroyMeshDescriptor(&m1);
+ CSG_DestroyMeshDescriptor(&m2);
+ CSG_DestroyMeshDescriptor(&output);
+ CSG_DestroyMeshDescriptor(&output2);
+ CSG_DestroyMeshDescriptor(&output3);
+
+ return 1;
+}
+
+#endif
+
diff --git a/source/blender/src/butspace.c b/source/blender/src/butspace.c
new file mode 100644
index 00000000000..f694c9aa862
--- /dev/null
+++ b/source/blender/src/butspace.c
@@ -0,0 +1,799 @@
+/**
+ * $Id:
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <time.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "blendef.h"
+#include "MEM_guardedalloc.h"
+
+#include "DNA_color_types.h"
+#include "DNA_image_types.h"
+#include "DNA_material_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_space_types.h"
+#include "DNA_texture_types.h"
+
+#include "BKE_colortools.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_library.h"
+#include "BKE_utildefines.h"
+
+#include "BLI_blenlib.h"
+
+#include "BSE_drawview.h" // for do_viewbuttons.c .... hurms
+#include "BSE_node.h"
+
+#include "BIF_gl.h"
+#include "BIF_graphics.h"
+#include "BIF_keyval.h"
+#include "BIF_interface.h"
+#include "BIF_toolbox.h"
+#include "BIF_space.h"
+#include "BIF_screen.h"
+#include "BIF_butspace.h"
+#include "BSE_headerbuttons.h"
+#include "BIF_previewrender.h"
+#include "BIF_mywindow.h"
+#include "BIF_glutil.h"
+#include "BIF_resources.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "mydevice.h"
+#include "butspace.h" // own module
+
+/************************ function prototypes ***************************/
+void drawbutspace(ScrArea *, void *);
+
+
+/* Local vars ---------------------------------------------------------- */
+short bgpicmode=0, near=1000, far=1000;
+MTex emptytex;
+MTex mtexcopybuf;
+
+char texstr[20][12]= {"None" , "Clouds" , "Wood", "Marble", "Magic" , "Blend",
+ "Stucci", "Noise" , "Image", "Plugin", "EnvMap" , "Musgrave",
+ "Voronoi", "DistNoise", "", "", "", "", "", ""};
+/* ---------------------------------------------------------------------- */
+
+void test_idbutton_cb(void *namev, void *arg2)
+{
+ char *name= namev;
+
+ test_idbutton(name+2);
+}
+
+
+void test_scriptpoin_but(char *name, ID **idpp)
+{
+ ID *id;
+
+ id= G.main->text.first;
+ while(id) {
+ if( strcmp(name, id->name+2)==0 ) {
+ *idpp= id;
+ return;
+ }
+ id= id->next;
+ }
+ *idpp= NULL;
+}
+
+void test_actionpoin_but(char *name, ID **idpp)
+{
+ ID *id;
+
+ id= G.main->action.first;
+ while(id) {
+ if( strcmp(name, id->name+2)==0 ) {
+ id_us_plus(id);
+ *idpp= id;
+ return;
+ }
+ id= id->next;
+ }
+ *idpp= NULL;
+}
+
+
+void test_obpoin_but(char *name, ID **idpp)
+{
+ ID *id;
+
+ if(idpp == (ID **)&(emptytex.object)) {
+ error("You must add a texture first");
+ *idpp= 0;
+ return;
+ }
+
+ id= G.main->object.first;
+ while(id) {
+ if( strcmp(name, id->name+2)==0 ) {
+ *idpp= id;
+ id_lib_extern(id); /* checks lib data, sets correct flag for saving then */
+ return;
+ }
+ id= id->next;
+ }
+ *idpp= NULL;
+}
+
+/* tests for an object of type OB_MESH */
+void test_meshobpoin_but(char *name, ID **idpp)
+{
+ ID *id;
+
+ id = G.main->object.first;
+ while(id) {
+ Object *ob = (Object *)id;
+ if(ob->type == OB_MESH && strcmp(name, id->name + 2) == 0) {
+ *idpp = id;
+ /* checks lib data, sets correct flag for saving then */
+ id_lib_extern(id);
+ return;
+ }
+ id = id->next;
+ }
+ *idpp = NULL;
+}
+
+void test_meshpoin_but(char *name, ID **idpp)
+{
+ ID *id;
+
+ if( *idpp ) (*idpp)->us--;
+
+ id= G.main->mesh.first;
+ while(id) {
+ if( strcmp(name, id->name+2)==0 ) {
+ *idpp= id;
+ id_us_plus(id);
+ return;
+ }
+ id= id->next;
+ }
+ *idpp= NULL;
+}
+
+void test_matpoin_but(char *name, ID **idpp)
+{
+ ID *id;
+
+ if( *idpp ) (*idpp)->us--;
+
+ id= G.main->mat.first;
+ while(id) {
+ if( strcmp(name, id->name+2)==0 ) {
+ *idpp= id;
+ id_us_plus(id);
+ return;
+ }
+ id= id->next;
+ }
+ *idpp= NULL;
+}
+
+void test_scenepoin_but(char *name, ID **idpp)
+{
+ ID *id;
+
+ if( *idpp ) (*idpp)->us--;
+
+ id= G.main->scene.first;
+ while(id) {
+ if( strcmp(name, id->name+2)==0 ) {
+ *idpp= id;
+ id_us_plus(id);
+ return;
+ }
+ id= id->next;
+ }
+ *idpp= NULL;
+}
+
+void test_grouppoin_but(char *name, ID **idpp)
+{
+ ID *id;
+
+ if( *idpp ) (*idpp)->us--;
+
+ id= G.main->group.first;
+ while(id) {
+ if( strcmp(name, id->name+2)==0 ) {
+ *idpp= id;
+ id_us_plus(id);
+ return;
+ }
+ id= id->next;
+ }
+ *idpp= NULL;
+}
+
+void test_texpoin_but(char *name, ID **idpp)
+{
+ ID *id;
+
+ if( *idpp ) (*idpp)->us--;
+
+ id= G.main->tex.first;
+ while(id) {
+ if( strcmp(name, id->name+2)==0 ) {
+ *idpp= id;
+ id_us_plus(id);
+ return;
+ }
+ id= id->next;
+ }
+ *idpp= NULL;
+}
+
+void test_imapoin_but(char *name, ID **idpp)
+{
+ ID *id;
+
+ if( *idpp ) (*idpp)->us--;
+
+ id= G.main->image.first;
+ while(id) {
+ if( strcmp(name, id->name+2)==0 ) {
+ *idpp= id;
+ id_us_plus(id);
+ return;
+ }
+ id= id->next;
+ }
+ *idpp= NULL;
+}
+
+/* ----------- custom button group ---------------------- */
+
+static void curvemap_buttons_zoom_in(void *cumap_v, void *unused)
+{
+ CurveMapping *cumap = cumap_v;
+ float d;
+
+ /* we allow 20 times zoom */
+ if( (cumap->curr.xmax - cumap->curr.xmin) > 0.04f*(cumap->clipr.xmax - cumap->clipr.xmin) ) {
+ d= 0.1154f*(cumap->curr.xmax - cumap->curr.xmin);
+ cumap->curr.xmin+= d;
+ cumap->curr.xmax-= d;
+ d= 0.1154f*(cumap->curr.ymax - cumap->curr.ymin);
+ cumap->curr.ymin+= d;
+ cumap->curr.ymax-= d;
+ }
+}
+
+static void curvemap_buttons_zoom_out(void *cumap_v, void *unused)
+{
+ CurveMapping *cumap = cumap_v;
+ float d, d1;
+
+ /* we allow 20 times zoom, but dont view outside clip */
+ if( (cumap->curr.xmax - cumap->curr.xmin) < 20.0f*(cumap->clipr.xmax - cumap->clipr.xmin) ) {
+ d= d1= 0.15f*(cumap->curr.xmax - cumap->curr.xmin);
+
+ if(cumap->flag & CUMA_DO_CLIP)
+ if(cumap->curr.xmin-d < cumap->clipr.xmin)
+ d1= cumap->curr.xmin - cumap->clipr.xmin;
+ cumap->curr.xmin-= d1;
+
+ if(cumap->flag & CUMA_DO_CLIP)
+ if(cumap->curr.xmax+d > cumap->clipr.xmax)
+ d1= -cumap->curr.xmax + cumap->clipr.xmax;
+ cumap->curr.xmax+= d1;
+
+ d= d1= 0.15f*(cumap->curr.ymax - cumap->curr.ymin);
+
+ if(cumap->flag & CUMA_DO_CLIP)
+ if(cumap->curr.ymin-d < cumap->clipr.ymin)
+ d1= cumap->curr.ymin - cumap->clipr.ymin;
+ cumap->curr.ymin-= d1;
+
+ if(cumap->flag & CUMA_DO_CLIP)
+ if(cumap->curr.ymax+d > cumap->clipr.ymax)
+ d1= -cumap->curr.ymax + cumap->clipr.ymax;
+ cumap->curr.ymax+= d1;
+ }
+}
+
+static void curvemap_buttons_setclip(void *cumap_v, void *unused)
+{
+ CurveMapping *cumap = cumap_v;
+
+ curvemapping_changed(cumap, 0);
+}
+
+static void curvemap_buttons_delete(void *cumap_v, void *unused)
+{
+ CurveMapping *cumap = cumap_v;
+
+ curvemap_remove(cumap->cm+cumap->cur, SELECT);
+ curvemapping_changed(cumap, 0);
+}
+
+/* NOTE: this is a block-menu, needs 0 events, otherwise the menu closes */
+static uiBlock *curvemap_clipping_func(void *cumap_v)
+{
+ CurveMapping *cumap = cumap_v;
+ uiBlock *block;
+ uiBut *bt;
+
+ block= uiNewBlock(&curarea->uiblocks, "curvemap_clipping_func", UI_EMBOSS, UI_HELV, curarea->win);
+
+ /* use this for a fake extra empy space around the buttons */
+ uiDefBut(block, LABEL, 0, "", -4, 16, 128, 106, NULL, 0, 0, 0, 0, "");
+
+ bt= uiDefButBitI(block, TOG, CUMA_DO_CLIP, 1, "Use Clipping",
+ 0,100,120,18, &cumap->flag, 0.0, 0.0, 10, 0, "");
+ uiButSetFunc(bt, curvemap_buttons_setclip, cumap, NULL);
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, 0, "Min X ", 0,74,120,18, &cumap->clipr.xmin, -100.0, cumap->clipr.xmax, 10, 0, "");
+ uiDefButF(block, NUM, 0, "Min Y ", 0,56,120,18, &cumap->clipr.ymin, -100.0, cumap->clipr.ymax, 10, 0, "");
+ uiDefButF(block, NUM, 0, "Max X ", 0,38,120,18, &cumap->clipr.xmax, cumap->clipr.xmin, 100.0, 10, 0, "");
+ uiDefButF(block, NUM, 0, "Max Y ", 0,20,120,18, &cumap->clipr.ymax, cumap->clipr.ymin, 100.0, 10, 0, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+
+ return block;
+}
+
+
+static void curvemap_tools_dofunc(void *cumap_v, int event)
+{
+ CurveMapping *cumap = cumap_v;
+ CurveMap *cuma= cumap->cm+cumap->cur;
+
+ switch(event) {
+ case 0:
+ curvemap_reset(cuma, &cumap->clipr);
+ curvemapping_changed(cumap, 0);
+ break;
+ case 1:
+ cumap->curr= cumap->clipr;
+ break;
+ case 2: /* set vector */
+ curvemap_sethandle(cuma, 1);
+ curvemapping_changed(cumap, 0);
+ break;
+ case 3: /* set auto */
+ curvemap_sethandle(cuma, 0);
+ curvemapping_changed(cumap, 0);
+ break;
+ case 4: /* extend horiz */
+ cuma->flag &= ~CUMA_EXTEND_EXTRAPOLATE;
+ curvemapping_changed(cumap, 0);
+ break;
+ case 5: /* extend extrapolate */
+ cuma->flag |= CUMA_EXTEND_EXTRAPOLATE;
+ curvemapping_changed(cumap, 0);
+ break;
+ }
+ addqueue(curarea->win, REDRAW, 1);
+}
+
+static uiBlock *curvemap_tools_func(void *cumap_v)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "curvemap_tools_func", UI_EMBOSSP, UI_HELV, curarea->win);
+ uiBlockSetButmFunc(block, curvemap_tools_dofunc, cumap_v);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Reset View", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Vector Handle", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Auto Handle", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Extend Horizontal", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Extend Extrapolated", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 5, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Reset Curve", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 50);
+ return block;
+}
+
+/* still unsure how this call evolves... we use labeltype for defining what curve-channels to show */
+void curvemap_buttons(uiBlock *block, CurveMapping *cumap, char labeltype, short event, short redraw, rctf *rect)
+{
+ uiBut *bt;
+ float dx, fy= rect->ymax-18.0f;
+ int icon;
+ short xco, yco;
+
+ yco= (short)(rect->ymax-18.0f);
+
+ /* curve choice options + tools/settings, 8 icons + spacer */
+ dx= (rect->xmax-rect->xmin)/(9.0f);
+
+ uiBlockBeginAlign(block);
+ if(labeltype=='v') { /* vector */
+ xco= (short)rect->xmin;
+ if(cumap->cm[0].curve)
+ uiDefButI(block, ROW, redraw, "X", xco, yco+2, dx, 16, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
+ xco= (short)(rect->xmin+1.0f*dx);
+ if(cumap->cm[1].curve)
+ uiDefButI(block, ROW, redraw, "Y", xco, yco+2, dx, 16, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
+ xco= (short)(rect->xmin+2.0f*dx);
+ if(cumap->cm[2].curve)
+ uiDefButI(block, ROW, redraw, "Z", xco, yco+2, dx, 16, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
+ }
+ else if(labeltype=='c') { /* color */
+ xco= (short)rect->xmin;
+ if(cumap->cm[3].curve)
+ uiDefButI(block, ROW, redraw, "C", xco, yco+2, dx, 16, &cumap->cur, 0.0, 3.0, 0.0, 0.0, "");
+ xco= (short)(rect->xmin+1.0f*dx);
+ if(cumap->cm[0].curve)
+ uiDefButI(block, ROW, redraw, "R", xco, yco+2, dx, 16, &cumap->cur, 0.0, 0.0, 0.0, 0.0, "");
+ xco= (short)(rect->xmin+2.0f*dx);
+ if(cumap->cm[1].curve)
+ uiDefButI(block, ROW, redraw, "G", xco, yco+2, dx, 16, &cumap->cur, 0.0, 1.0, 0.0, 0.0, "");
+ xco= (short)(rect->xmin+3.0f*dx);
+ if(cumap->cm[2].curve)
+ uiDefButI(block, ROW, redraw, "B", xco, yco+2, dx, 16, &cumap->cur, 0.0, 2.0, 0.0, 0.0, "");
+ }
+ /* else no channels ! */
+ uiBlockEndAlign(block);
+
+ xco= (short)(rect->xmin+4.5f*dx);
+ uiBlockSetEmboss(block, UI_EMBOSSN);
+ bt= uiDefIconBut(block, BUT, redraw, ICON_ZOOMIN, xco, yco, dx, 14, NULL, 0.0, 0.0, 0.0, 0.0, "Zoom in");
+ uiButSetFunc(bt, curvemap_buttons_zoom_in, cumap, NULL);
+
+ xco= (short)(rect->xmin+5.25f*dx);
+ bt= uiDefIconBut(block, BUT, redraw, ICON_ZOOMOUT, xco, yco, dx, 14, NULL, 0.0, 0.0, 0.0, 0.0, "Zoom out");
+ uiButSetFunc(bt, curvemap_buttons_zoom_out, cumap, NULL);
+
+ xco= (short)(rect->xmin+6.0f*dx);
+ bt= uiDefIconBlockBut(block, curvemap_tools_func, cumap, event, ICON_MODIFIER, xco, yco, dx, 18, "Tools");
+
+ xco= (short)(rect->xmin+7.0f*dx);
+ if(cumap->flag & CUMA_DO_CLIP) icon= ICON_CLIPUV_HLT; else icon= ICON_CLIPUV_DEHLT;
+ bt= uiDefIconBlockBut(block, curvemap_clipping_func, cumap, event, icon, xco, yco, dx, 18, "Clipping Options");
+
+ xco= (short)(rect->xmin+8.0f*dx);
+ bt= uiDefIconBut(block, BUT, event, ICON_X, xco, yco, dx, 18, NULL, 0.0, 0.0, 0.0, 0.0, "Delete points");
+ uiButSetFunc(bt, curvemap_buttons_delete, cumap, NULL);
+
+ uiBlockSetEmboss(block, UI_EMBOSS);
+
+ uiDefBut(block, BUT_CURVE, event, "",
+ rect->xmin, rect->ymin, rect->xmax-rect->xmin, fy-rect->ymin,
+ cumap, 0.0f, 1.0f, 0, 0, "");
+
+
+}
+
+
+/* --------------------------------- */
+
+/* nodes have button callbacks, that can draw in butspace too. need separate handling */
+static void do_node_buts(unsigned short event)
+{
+ Material *ma;
+
+ /* all operations default on active material layer here */
+ /* but this also gets called for lamp and world... */
+ ma= G.buts->lockpoin;
+ if(ma && GS(ma->id.name)==ID_MA)
+ ma = editnode_get_active_material(ma);
+ else
+ ma= NULL;
+
+ if(event>=B_NODE_EXEC) {
+ if(ma) end_render_material(ma); /// temporal... 3d preview
+ BIF_preview_changed(ID_MA);
+ allqueue(REDRAWNODE, 0);
+ allqueue(REDRAWBUTSSHADING, 0);
+ }
+}
+
+void do_butspace(unsigned short event)
+{
+ SpaceButs *buts;
+
+ /* redraw windows of the same type? */
+ buts= curarea->spacedata.first;
+ if(buts->mainb==CONTEXT_SCENE) allqueue(REDRAWBUTSSCENE, curarea->win);
+ if(buts->mainb==CONTEXT_OBJECT) allqueue(REDRAWBUTSOBJECT, curarea->win);
+ if(buts->mainb==CONTEXT_SHADING) allqueue(REDRAWBUTSSHADING, curarea->win);
+ if(buts->mainb==CONTEXT_EDITING) allqueue(REDRAWBUTSEDIT, curarea->win);
+ if(buts->mainb==CONTEXT_SCRIPT) allqueue(REDRAWBUTSSCRIPT, curarea->win);
+ if(buts->mainb==CONTEXT_LOGIC) allqueue(REDRAWBUTSLOGIC, curarea->win);
+
+ if (event <=50){
+ do_global_buttons2(event);
+ }
+ else if(event<=100) {
+ do_global_buttons(event);
+ }
+ else if(event < 1000) {
+ do_headerbuttons(event);
+ }
+ else if(event<=B_VIEWBUTS) {
+ do_viewbuts(event);
+ }
+ else if(event<=B_LAMPBUTS) {
+ do_lampbuts(event);
+ }
+ else if(event<=B_MATBUTS) {
+ do_matbuts(event);
+ }
+ else if(event<=B_TEXBUTS) {
+ do_texbuts(event);
+ }
+ else if(event<=B_ANIMBUTS) {
+ do_object_panels(event);
+ }
+ else if(event<=B_WORLDBUTS) {
+ do_worldbuts(event);
+ }
+ else if(event<=B_RENDERBUTS) {
+ do_render_panels(event); // buttons_scene.c
+ }
+ else if(event<=B_COMMONEDITBUTS) {
+ do_common_editbuts(event);
+ }
+ else if(event<=B_MESHBUTS) {
+ do_meshbuts(event);
+ }
+ else if(event<=B_VGROUPBUTS) {
+ do_vgroupbuts(event);
+ }
+ else if(event<=B_CURVEBUTS) {
+ do_curvebuts(event);
+ }
+ else if(event<=B_FONTBUTS) {
+ do_fontbuts(event);
+ }
+ else if(event<=B_ARMBUTS) {
+ do_armbuts(event);
+ }
+ else if(event<=B_CAMBUTS) {
+ do_cambuts(event);
+ }
+ else if(event<=B_MBALLBUTS) {
+ do_mballbuts(event);
+ }
+ else if(event<=B_LATTBUTS) {
+ do_latticebuts(event);
+ }
+ else if(event<=B_GAMEBUTS) {
+ do_logic_buts(event); // buttons_logic.c
+ }
+ else if(event<=B_FPAINTBUTS) {
+ do_fpaintbuts(event);
+ }
+ else if(event<=B_RADIOBUTS) {
+ do_radiobuts(event);
+ }
+ else if(event<=B_SCRIPTBUTS) {
+ do_scriptbuts(event);
+ }
+ else if(event<=B_SOUNDBUTS) {
+ do_soundbuts(event);
+ }
+ else if(event<=B_CONSTRAINTBUTS) {
+ do_constraintbuts(event);
+ }
+ else if(event<=B_UVAUTOCALCBUTS) {
+ do_uvcalculationbuts(event);
+ }
+ else if(event<=B_EFFECTSBUTS) {
+ do_effects_panels(event);
+ }
+ else if(event<=B_MODIFIER_BUTS) {
+ extern void do_modifier_panels(unsigned short event);
+ do_modifier_panels(event);
+ }
+ else if(event<=B_NODE_BUTS) {
+ do_node_buts(event);
+ }
+ else if(event==REDRAWVIEW3D) allqueue(event, 1); // 1=do header too
+ else if(event>REDRAWVIEW3D) allqueue(event, 0);
+}
+
+static void butspace_context_switch(SpaceButs *buts, Object *new)
+{
+ // change type automatically
+ if(new) {
+ int tab= buts->tab[CONTEXT_SHADING];
+
+ if(tab == TAB_SHADING_WORLD) {
+ if(new->type==OB_CAMERA);
+ else if(new->type==OB_LAMP) {
+ buts->tab[CONTEXT_SHADING]= TAB_SHADING_LAMP;
+ }
+ else buts->tab[CONTEXT_SHADING]= TAB_SHADING_MAT;
+
+ }
+ else if(tab == TAB_SHADING_TEX) {
+ if(new->type==OB_LAMP) buts->texfrom= 2;
+ else if(new->type==OB_CAMERA) buts->texfrom= 1;
+ else buts->texfrom= 0;
+ }
+ else if(tab == TAB_SHADING_RAD) {
+ }
+ else if(new->type==OB_CAMERA) {
+ buts->tab[CONTEXT_SHADING]= TAB_SHADING_WORLD;
+ }
+ else if(new->type==OB_LAMP) {
+ buts->tab[CONTEXT_SHADING]= TAB_SHADING_LAMP;
+ }
+ else {
+ buts->tab[CONTEXT_SHADING]= TAB_SHADING_MAT;
+ }
+ }
+}
+
+/* new active object */
+void redraw_test_buttons(Object *new)
+{
+ ScrArea *sa;
+ SpaceButs *buts;
+
+ sa= G.curscreen->areabase.first;
+ while(sa) {
+ if(sa->spacetype==SPACE_BUTS) {
+ buts= sa->spacedata.first;
+
+ if(ELEM5(buts->mainb, CONTEXT_OBJECT, CONTEXT_EDITING, CONTEXT_SHADING, CONTEXT_LOGIC, CONTEXT_SCRIPT)) {
+ addqueue(sa->win, REDRAW, 1);
+ buts->re_align= 1;
+
+ if(new && buts->mainb==CONTEXT_SHADING) {
+ /* does node previews too... */
+ BIF_preview_changed(ID_TE);
+ }
+ }
+ // always do context switch
+ if(new) butspace_context_switch(buts, new);
+
+ }
+ sa= sa->next;
+ }
+}
+
+
+/* callback */
+void drawbutspace(ScrArea *sa, void *spacedata)
+{
+ ID *id, *idfrom;
+ SpaceButs *sbuts= sa->spacedata.first;
+ View2D *v2d= &sbuts->v2d;
+ float col[3];
+ int tab, align=0;
+
+ /* context */
+ buttons_active_id(&id, &idfrom);
+ G.buts->lockpoin= id;
+
+ myortho2(v2d->cur.xmin, v2d->cur.xmax, v2d->cur.ymin, v2d->cur.ymax);
+
+ BIF_GetThemeColor3fv(TH_BACK, col);
+ glClearColor(col[0], col[1], col[2], 0.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ uiSetButLock(G.scene->id.lib!=0, ERROR_LIBDATA_MESSAGE);
+ uiFreeBlocksWin(&sa->uiblocks, sa->win);
+
+ /* select the context to be drawn, per contex/tab the actual context is tested */
+ switch(sbuts->mainb) {
+ case CONTEXT_SCENE:
+ tab= sbuts->tab[CONTEXT_SCENE];
+
+ if(tab== TAB_SCENE_RENDER)
+ render_panels();
+ else if(tab == TAB_SCENE_ANIM)
+ anim_panels();
+ else if(tab == TAB_SCENE_SOUND)
+ sound_panels();
+
+ break;
+ case CONTEXT_OBJECT:
+ tab= sbuts->tab[CONTEXT_OBJECT];
+
+ if(tab==TAB_OBJECT_OBJECT)
+ object_panels();
+ else if(tab==TAB_OBJECT_PHYSICS)
+ physics_panels();
+
+ break;
+ case CONTEXT_SHADING:
+ tab= sbuts->tab[CONTEXT_SHADING];
+
+ if(tab==TAB_SHADING_MAT)
+ material_panels();
+ else if(tab==TAB_SHADING_LAMP)
+ lamp_panels();
+ else if(tab==TAB_SHADING_WORLD)
+ world_panels();
+ else if(tab==TAB_SHADING_RAD)
+ radio_panels();
+ else if(tab==TAB_SHADING_TEX)
+ texture_panels();
+
+ break;
+ case CONTEXT_EDITING:
+ /* no tabs */
+ editing_panels();
+
+ break;
+ case CONTEXT_SCRIPT:
+ script_panels();
+
+ break;
+ case CONTEXT_LOGIC:
+ /* no tabs */
+ logic_buts();
+ break;
+ }
+
+ uiClearButLock();
+
+ /* when align changes, also do this for new panels */
+ /* don't always align, this function is called during AnmatePanels too */
+ if(sbuts->align)
+ if(sbuts->re_align || sbuts->mainbo!=sbuts->mainb || sbuts->tabo!=sbuts->tab[sbuts->mainb])
+ align= 1;
+
+ uiDrawBlocksPanels(sa, align);
+
+ /* since panels give different layouts, we have to make sure v2d.tot matches */
+ uiMatchPanel_view2d(sa);
+
+ sbuts->re_align= 0;
+ // also for memory for finding which texture you'd like to see
+ sbuts->mainbo= sbuts->mainb;
+ sbuts->tabo= sbuts->tab[sbuts->mainb];
+
+ myortho2(-0.375, (float)(sa->winx)-0.375, -0.375, (float)(sa->winy)-0.375);
+ draw_area_emboss(sa);
+ myortho2(v2d->cur.xmin, v2d->cur.xmax, v2d->cur.ymin, v2d->cur.ymax);
+
+ /* always in end */
+ sa->win_swap= WIN_BACK_OK;
+}
+
+
diff --git a/source/blender/src/buttons_editing.c b/source/blender/src/buttons_editing.c
new file mode 100644
index 00000000000..faa4ae4c445
--- /dev/null
+++ b/source/blender/src/buttons_editing.c
@@ -0,0 +1,5624 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <time.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef WIN32
+#ifndef snprintf
+#define snprintf _snprintf
+#endif
+#endif
+
+#include "MEM_guardedalloc.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_scene_types.h"
+
+#include "DNA_action_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_brush_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_color_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_effect_types.h"
+#include "DNA_group_types.h"
+#include "DNA_key_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_material_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_nla_types.h"
+#include "DNA_object_types.h"
+#include "DNA_object_force.h"
+#include "DNA_radio_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_vfont_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_world_types.h"
+#include "DNA_packedFile_types.h"
+
+#include "BKE_blender.h"
+#include "BKE_brush.h"
+#include "BKE_curve.h"
+#include "BKE_customdata.h"
+#include "BKE_colortools.h"
+#include "BKE_deform.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_key.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_modifier.h"
+#include "BKE_packedFile.h"
+#include "BKE_scene.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_vfontdata.h"
+#include "BLI_editVert.h"
+#include "BLI_dynstr.h"
+
+#include "BSE_filesel.h"
+
+#include "BIF_gl.h"
+#include "BIF_editarmature.h"
+#include "BIF_editconstraint.h"
+#include "BIF_editdeform.h"
+#include "BIF_editfont.h"
+#include "BIF_editkey.h"
+#include "BIF_editmesh.h"
+#include "BIF_imasel.h"
+#include "BIF_interface.h"
+#include "BIF_meshtools.h"
+#include "BIF_mywindow.h"
+#include "BIF_poseobject.h"
+#include "BIF_renderwin.h"
+#include "BIF_resources.h"
+#include "BIF_retopo.h"
+#include "BIF_screen.h"
+#include "BIF_scrarea.h"
+#include "BIF_space.h"
+#include "BIF_toets.h"
+#include "BIF_toolbox.h"
+#include "BIF_previewrender.h"
+#include "BIF_butspace.h"
+
+#ifdef WITH_VERSE
+#include "BIF_verse.h"
+#endif
+
+#include "mydevice.h"
+#include "blendef.h"
+
+#include "BKE_action.h"
+#include "BKE_anim.h"
+#include "BKE_armature.h"
+#include "BKE_constraint.h"
+#include "BKE_curve.h"
+#include "BKE_displist.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_effect.h"
+#include "BKE_font.h"
+#include "BKE_image.h"
+#include "BKE_ipo.h"
+#include "BKE_lattice.h"
+#include "BKE_material.h"
+#include "BKE_mball.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_poseobject.h"
+
+#include "BDR_drawobject.h"
+#include "BDR_editcurve.h"
+#include "BDR_editface.h"
+#include "BDR_editobject.h"
+#include "BDR_sculptmode.h"
+#include "BDR_vpaint.h"
+#include "BDR_unwrapper.h"
+
+#include "BSE_drawview.h"
+#include "BSE_editipo.h"
+#include "BSE_edit.h"
+#include "BSE_filesel.h"
+#include "BSE_headerbuttons.h"
+#include "BSE_trans_types.h"
+#include "BSE_view.h"
+#include "BSE_seqaudio.h"
+
+#include "RE_render_ext.h" // make_sticky
+
+#include "butspace.h" // own module
+#include "multires.h"
+
+static float editbutweight= 1.0;
+float editbutvweight= 1;
+static int actmcol= 0, acttface= 0, acttface_rnd = 0, actmcol_rnd = 0;
+
+extern ListBase editNurb;
+
+/* *************************** Unicode Character Groups ****************** */
+unicodect uctabname[125] = {
+ {"All", "All", 0x0000, 0xffff},
+ {"Basic Latin", "Basic Latin", 0x0000, 0x007f},
+ {"Latin 1 Supp", "Latin-1 Supplement", 0x0080, 0x00ff},
+
+ {"Latin Ext. A.", "Latin Extended-A", 0x0100, 0x017F},
+ {"Latin Ext. B.", "Latin Extended-B", 0x0180,0x024F},
+ {"Latin Ext. Add.", "Latin Extended Additional", 0x1e00, 0x1eff},
+
+ {"IPA Ext", "IPA Extensions", 0x0250, 0x02AF},
+ {"Spacing Mod.", "Spacing Modifier Letters", 0x02b0, 0x02ff},
+
+ {"Comb. Dia.", "Combining Diacritical Marks", 0x0300, 0x036F},
+ {"Greek, Coptic", "Greek and Coptic", 0x0370, 0x03ff},
+ {"Greek Ext.", "Greek Extended", 0x1f00, 0x1fff},
+
+ {"Cyrillic", "Cyrillic", 0x0400, 0x04ff},
+ {"Cyrillic Supp.", "Cyrillic Supplementary", 0x0500, 0x052f},
+
+ {"Armenian", "Armenian", 0x0530, 0x058f},
+ {"Hebrew", "Hebrew", 0x0590, 0x05ff},
+
+
+ {"Arabic", "Arabic", 0x0600, 0x06ff},
+ {"Syriac", "Syriac", 0x0700, 0x074f},
+
+ {"Thaana", "Thaana", 0x0780, 0x07bf},
+ {"Devanagari", "Devanagari", 0x0900, 0x097f},
+
+ {"Bengali", "Bengali", 0x0980, 0x09ff},
+ {"Gurmukhi", "Gurmukhi", 0x0a00, 0x0a7f},
+
+ {"Gujarati", "Gujarati", 0x0a80, 0x0aff},
+ {"Oriya", "Oriya", 0x0b00, 0x0b7f},
+
+ {"Tamil", "Tamil", 0x0b80, 0x0bff},
+ {"Tegulu", "Tegulu", 0x0c00, 0x0c7f},
+
+ {"Kannada", "Kannada", 0x0c80, 0x0cff},
+ {"Malayalam", "Malayalam", 0x0d00, 0x0d7f},
+
+ {"Sinhala", "Sinhala", 0x0d80, 0x0dff},
+ {"Thai", "Thai", 0x0e00, 0x0e7f},
+
+ {"Lao", "Lao", 0x0e80, 0x0eff},
+ {"Tibetan", "Tibetan", 0x0f00, 0x0fff},
+
+ {"Myanmar", "Myanmar", 0x1000, 0x109f},
+ {"Georgian", "Georgian", 0x10a0, 0x10ff},
+
+ {"Ethiopic", "Ethiopic", 0x1200, 0x137f},
+
+ {"Cherokee", "Cherokee", 0x13a0, 0x13ff},
+ {"Unif. Canadian", "Unified Canadian Aboriginal Syllabics", 0x1400, 0x167f},
+
+ {"Ogham", "Ogham", 0x1680, 0x169f},
+ {"Runic", "Runic", 0x16a0, 0x16ff},
+
+ {"Tagalog", "Tagalog", 0x1700, 0x171f},
+ {"Hanunoo", "Hanunoo", 0x1720, 0x173f},
+
+ {"Buhid", "Buhid", 0x1740, 0x175f},
+ {"Tagbanwa", "Tagbanwa", 0x1760, 0x177f},
+
+ {"Khmer", "Khmer", 0x1780, 0x17ff},
+ {"Khmer Symb", "Khmer Symbols", 0x19e0, 0x19ff},
+
+ {"Mongolian", "Mongolian", 0x1800, 0x18af},
+
+ {"Limbu", "Limbu", 0x1900, 0x194f},
+ {"Tai Le", "Tai Le", 0x1950, 0x197f},
+
+ {"Phon. Ext.", "Phonetic Extensions", 0x1d00, 0x1d7f},
+
+
+ {"Gen. Punct.", "General Punctutation", 0x2000, 0x206f},
+ {"Super, Sub", "Superscripts and Subscripts", 0x2070, 0x209f},
+
+ {"Curr. Symb.", "Currency Symbols", 0x20a0, 0x20cf},
+ {"Comb. Diacrit.", "Combining Diacritical Marks for Symbols", 0x20d0, 0x20ff},
+
+ {"Letter Symb", "Letterlike Symbols", 0x2100, 0x214f},
+ {"Numb. Forms", "Number Forms", 0x2150, 0x218f},
+
+ {"Arrows", "Arrows", 0x2190, 0x21ff},
+ {"Math Oper.", "Mathematical Operators", 0x2200, 0x22ff},
+
+ {"Misc. Tech.", "Miscellaneous Technical", 0x2300, 0x23ff},
+ {"Ctrl. Pict.", "Control Pictures", 0x2400, 0x243f},
+
+ {"OCR", "Optical Character Recognition", 0x2440, 0x245f},
+ {"Enc. Alpha", "Enclosed Alphanumerics", 0x2460, 0x24ff},
+
+ {"Bow Drawing", "Box Drawing", 0x2500, 0x257f},
+ {"BLock Elem.", "Block Elements", 0x2580, 0x259f},
+
+ {"Geom. Shapes", "Geometric Shapes", 0x25a0, 0x25ff},
+ {"Misc. Symb.", "Miscellaneous Symbols", 0x2600, 0x26ff},
+
+ {"Dingbats", "Dingbats", 0x2700, 0x27bf},
+ {"Misc. Math A", "Miscellaneous Mathematical Symbols-A", 0x27c0, 0x27ef},
+
+ {"Supp. Arrows-A", "Supplemental Arrows-A", 0x27f0, 0x27ff},
+ {"Braille Pat.", "Braille Patterns", 0x2800, 0x28ff},
+
+ {"Supp. Arrows-B", "Supplemental Arrows-B", 0x2900, 0x297f},
+ {"Misc. Math B", "Miscellaneous Mathematical Symbols-B", 0x2980, 0x29ff},
+
+ {"Supp. Math Op.", "Supplemental Mathematical Operators", 0x2a00, 0x2aff},
+ {"Misc. Symb.", "Miscellaneous Symbols and Arrows", 0x2b00, 0x2bff},
+
+ {"Kangxi Rad.", "Kangxi Radicals", 0x2f00, 0x2fdf},
+
+ {"Ideographic", "Ideographic Description Characters", 0x2ff0, 0x2fff},
+
+ {"Hiragana", "Hiragana", 0x3040, 0x309f},
+ {"Katakana", "Katakana", 0x30a0, 0x30ff},
+ {"Katakana Ext.", "Katakana Phonetic Extensions", 0x31f0, 0x31ff},
+
+ {"Bopomofo", "Bopomofo", 0x3100, 0x312f},
+ {"Bopomofo Ext.", "Bopomofo Extended", 0x31a0, 0x31bf},
+
+ {"Hangul", "Hangul Jamo", 0x1100, 0x11ff},
+ {"Hangul Comp.", "Hangul Compatibility Jamo", 0x3130, 0x318f},
+ {"Hangul Syll.", "Hangul Syllables", 0xac00, 0xd7af},
+
+ {"Kanbun", "Kanbun", 0x3190, 0x319f},
+
+
+
+ {"Yijing Hex.", "Yijing Hexagram Symbols", 0x4dc0, 0x4dff},
+
+ {"Yi Syllables", "Yi Syllables", 0xa000, 0xa48f},
+ {"Yi Radicals", "Yi Radicals", 0xa490, 0xa4cf},
+
+ {"High Surr.", "High Surrogate Area", 0xd800, 0xdbff},
+
+ {"Low Surr.", "Low Surrogates", 0xdc00, 0xdfff},
+ {"Priv. Use Area", "Private Use Area", 0xe000, 0xf8ff},
+
+ {"CJK Rad. Supp.", "CJK Radicals Supplement", 0x2e80, 0x2eff},
+ {"CJK Ideographs", "CJK Unified Ideographs", 0x4e00, 0x9faf},
+ {"CJK Ideog. Ext. A", "CJK Unified Ideographs Extension A", 0x3400, 0x4dbf},
+ {"CJK Ideog. Ext. B", "CJK Unified Ideographs Extension B", 0x20000, 0x2a6df},
+ {"CJK Symbols.", "CJK Symbols and Punctuation", 0x3000, 0x303f},
+ {"Enclosed CJK", "Enclosed CJK Letters and Months", 0x3200, 0x32ff},
+ {"CJK Comp.", "CJK Compatibility", 0x3300, 0x33ff},
+ {"CJK Comp. Ideog.", "CJK Compatibility Ideographs", 0xf900, 0xfaff},
+ {"CJK Comp. Forms", "CJK Compatibility Forms", 0xfe30, 0xfe4f},
+ {"CJK Comp. Supp.", "CJK Compatibility Ideographs Supplement", 0x2f800, 0x2fa1f},
+
+ {"Alpha. Pres. Forms", "Alphabetic Presentation Forms", 0xfb00, 0xfb4f},
+
+ {"Arabic Pres. A", "Arabic Presentation Forms-A", 0xfb50, 0xfdff},
+ {"Arabic Pres. B", "Arabic Presentation Forms-B", 0xfe70, 0xfeff},
+
+ {"Var. Sel.", "Variation Selectors", 0xfe00, 0xfe0f},
+
+ {"Comb. Half", "Combining Half Marks", 0xfe20, 0xfe2f},
+
+ {"Sml. From Var.", "Small Form Variants", 0xfe50, 0xfe6f},
+
+ {"Half, Full Forms", "Halfwidth and Fullwidth Forms", 0xff00, 0xffef},
+ {"Specials", "Specials", 0xfff0, 0xffff},
+
+ {"Lin. B Syllab.", "Linear B Syllabary", 0x10000, 0x1007f},
+ {"Lin. B Idog.", "Linear B Ideograms", 0x10080, 0x100ff},
+
+ {"Aegean Num.", "Aegean Numbers", 0x10100, 0x1013f},
+ {"Old Italic", "Old Italic", 0x10300, 0x1032f},
+
+ {"Gothic", "Gothic", 0x10330, 0x1034f},
+ {"Ugaritic", "Ugaritic", 0x10380, 0x1039f},
+
+ {"Deseret", "Deseret", 0x10400, 0x1044f},
+ {"Shavian", "Shavian", 0x10450, 0x1047f},
+
+ {"Osmanya", "Osmanya", 0x10480, 0x104af},
+ {"Cypriot Syll", "Cypriot Syllabary", 0x10800, 0x1083f},
+
+ {"Bysantine Mus.", "Bysantine Musical Symbols", 0x1d000, 0x1d0ff},
+ {"Music Symb.", "Musical Symbols", 0x1d100, 0x1d1ff},
+
+ {"Tai Xuan Symb", "Tai Xuan Jing Symbols", 0x1d300, 0x1d35f},
+ {"Math. Alpha Symb.", "Mathematical Alpanumeric Symbols", 0x1d400, 0x1d7ff},
+
+
+ {"Tags", "Tags", 0xe0000, 0xe007f},
+ {"Var. Supp", "Variation Selectors Supplement", 0xe0100, 0xe01ef},
+
+ {"Supp. Priv. A", "Supplementary Private Use Area-A", 0xf0000, 0xffffd},
+ {"Supp. Priv. B", "Supplementary Private Use Area-B", 0x100000, 0x10fffd}
+};
+
+
+/* *************************** static functions prototypes ****************** */
+VFont *exist_vfont(char *str);
+
+/* *************** */
+
+void do_common_editbuts(unsigned short event) // old name, is a mix of object and editing events....
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+ Base *base;
+ Object *ob= OBACT;
+ Nurb *nu;
+ Curve *cu;
+ BezTriple *bezt;
+ BPoint *bp;
+ unsigned int local;
+ int a, bit, index= -1;
+
+ switch(event) {
+
+ case B_MATWICH:
+ if(G.obedit && G.obedit->actcol>0) {
+ if(G.obedit->type == OB_MESH) {
+ efa= em->faces.first;
+ while(efa) {
+ if(efa->f & SELECT) {
+ if(index== -1) index= efa->mat_nr;
+ else if(index!=efa->mat_nr) {
+ error("Mixed colors");
+ return;
+ }
+ }
+ efa= efa->next;
+ }
+ }
+ else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) {
+ nu= editNurb.first;
+ while(nu) {
+ if( isNurbsel(nu) ) {
+ if(index== -1) index= nu->mat_nr;
+ else if(index!=nu->mat_nr) {
+ error("Mixed colors");
+ return;
+ }
+ }
+ nu= nu->next;
+ }
+ }
+ if(index>=0) {
+ G.obedit->actcol= index+1;
+ scrarea_queue_winredraw(curarea);
+ }
+ }
+ break;
+ case B_MATNEW:
+ new_material_to_objectdata(ob);
+ scrarea_queue_winredraw(curarea);
+ BIF_undo_push("New material");
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWVIEW3D_Z, 0);
+ allqueue(REDRAWOOPS, 0);
+ break;
+ case B_MATDEL:
+ delete_material_index();
+ scrarea_queue_winredraw(curarea);
+ BIF_undo_push("Delete material index");
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWVIEW3D_Z, 0);
+ allqueue(REDRAWOOPS, 0);
+ break;
+ case B_MATASS:
+ if(G.obedit && G.obedit->actcol>0) {
+ if(G.obedit->type == OB_MESH) {
+ efa= em->faces.first;
+ while(efa) {
+ if(efa->f & SELECT)
+ efa->mat_nr= G.obedit->actcol-1;
+ efa= efa->next;
+ }
+ }
+ else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) {
+ nu= editNurb.first;
+ while(nu) {
+ if( isNurbsel(nu) )
+ nu->mat_nr= nu->charidx= G.obedit->actcol-1;
+ nu= nu->next;
+ }
+ }
+ else if (G.obedit->type == OB_FONT) {
+ if (mat_to_sel()) {
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ }
+ allqueue(REDRAWVIEW3D_Z, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ shade_buttons_change_3d();
+ BIF_undo_push("Assign material index");
+ }
+ break;
+ case B_MATSEL:
+ case B_MATDESEL:
+ if(G.obedit) {
+ if(G.obedit->type == OB_MESH) {
+ if (event==B_MATSEL) {
+ editmesh_select_by_material(G.obedit->actcol-1);
+ } else {
+ editmesh_deselect_by_material(G.obedit->actcol-1);
+ }
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) {
+ nu= editNurb.first;
+ while(nu) {
+ if(nu->mat_nr==G.obedit->actcol-1) {
+ if(nu->bezt) {
+ a= nu->pntsu;
+ bezt= nu->bezt;
+ while(a--) {
+ if(bezt->hide==0) {
+ if(event==B_MATSEL) {
+ bezt->f1 |= 1;
+ bezt->f2 |= 1;
+ bezt->f3 |= 1;
+ }
+ else {
+ bezt->f1 &= ~1;
+ bezt->f2 &= ~1;
+ bezt->f3 &= ~1;
+ }
+ }
+ bezt++;
+ }
+ }
+ else if(nu->bp) {
+ a= nu->pntsu*nu->pntsv;
+ bp= nu->bp;
+ while(a--) {
+ if(bp->hide==0) {
+ if(event==B_MATSEL) bp->f1 |= 1;
+ else bp->f1 &= ~1;
+ }
+ bp++;
+ }
+ }
+ }
+ nu= nu->next;
+ }
+ BIF_undo_push("Select material index");
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ }
+ countall();
+ break;
+ case B_HIDE:
+ if(G.obedit) {
+ if(G.obedit->type == OB_MESH) hide_mesh(0);
+ else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) hideNurb(0);
+ }
+ break;
+ case B_REVEAL:
+ if(G.obedit) {
+ if(G.obedit->type == OB_MESH) reveal_mesh();
+ else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) revealNurb();
+ }
+ else if(FACESEL_PAINT_TEST) reveal_tface();
+
+ break;
+ case B_SELSWAP:
+ if(G.obedit) {
+ if(G.obedit->type == OB_MESH) selectswap_mesh();
+ else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) selectswapNurb();
+ }
+ break;
+ case B_AUTOTEX:
+ if(ob && G.obedit==0) {
+ if(ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) tex_space_curve(ob->data);
+ }
+ break;
+ case B_DOCENTER:
+ docenter(0);
+ break;
+ case B_DOCENTERNEW:
+ docenter_new();
+ break;
+ case B_DOCENTERCURSOR:
+ docenter_cursor();
+ break;
+ case B_SETSMOOTH:
+ case B_SETSOLID:
+ if(G.obedit) {
+ if(G.obedit->type == OB_MESH) {
+ mesh_set_smooth_faces((event==B_SETSMOOTH));
+ }
+ else {
+ nurb_set_smooth((event==B_SETSMOOTH));
+ }
+ }
+ else if(G.vd) {
+ base= FIRSTBASE;
+ while(base) {
+ if(TESTBASELIB(base)) {
+ if(base->object->type==OB_MESH) {
+ mesh_set_smooth_flag(base->object, (event==B_SETSMOOTH));
+ }
+ else if ELEM(base->object->type, OB_SURF, OB_CURVE) {
+ cu= base->object->data;
+ nu= cu->nurb.first;
+ while(nu) {
+ if(event==B_SETSMOOTH) nu->flag |= ME_SMOOTH;
+ else nu->flag &= ~ME_SMOOTH;
+ nu= nu->next;
+ }
+ makeDispListCurveTypes(base->object, 0);
+ }
+ }
+ base= base->next;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+
+ if(event == B_SETSMOOTH) BIF_undo_push("Set Smooth");
+ else BIF_undo_push("Set Solid");
+ }
+ break;
+ case B_CHANGEDEP:
+ DAG_scene_sort(G.scene); // makes new dag
+ if(ob) ob->recalc |= OB_RECALC;
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+
+ case B_ADDKEY:
+ insert_shapekey(ob);
+ break;
+ case B_SETKEY:
+ ob->shapeflag |= OB_SHAPE_TEMPLOCK;
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ break;
+ case B_LOCKKEY:
+ ob->shapeflag &= ~OB_SHAPE_TEMPLOCK;
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ break;
+ case B_NEXTKEY:
+ {
+ Key *key= ob_get_key(ob);
+ if(ob->shapenr == BLI_countlist(&key->block))
+ ob->shapenr= 1;
+ else ob->shapenr++;
+ do_common_editbuts(B_SETKEY);
+ break;
+ }
+ case B_PREVKEY:
+ {
+ Key *key= ob_get_key(ob);
+ if(ob->shapenr <= 1)
+ ob->shapenr= BLI_countlist(&key->block);
+ else ob->shapenr--;
+ do_common_editbuts(B_SETKEY);
+ break;
+ }
+ case B_NAMEKEY:
+ allspace(REMAKEIPO, 0);
+ allqueue (REDRAWIPO, 0);
+ break;
+ case B_DELKEY:
+ delete_key(OBACT);
+ allqueue(REDRAWACTION, 0);
+ break;
+
+
+ default:
+ if (G.vd==NULL)
+ break;
+
+ if(event>=B_OBLAY && event<=B_OBLAY+31) {
+ local= BASACT->lay & 0xFF000000;
+ BASACT->lay -= local;
+ if(BASACT->lay==0 || (G.qual & LR_SHIFTKEY)==0) {
+ bit= event-B_OBLAY;
+ BASACT->lay= 1<<bit;
+ scrarea_queue_winredraw(curarea);
+ }
+ BASACT->lay += local;
+ /* optimal redraw */
+ if( (ob->lay & G.vd->lay) && (BASACT->lay & G.vd->lay) );
+ else if( (ob->lay & G.vd->lay)==0 && (BASACT->lay & G.vd->lay)==0 );
+ else {
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_scene_sort(G.scene);
+ }
+ ob->lay= BASACT->lay;
+ }
+ }
+
+}
+
+/* *************************** MESH ******************************** */
+
+static void verify_customdata_name_func(void *data1, void *data2)
+{
+ CustomData *data= (CustomData*)data1;
+ CustomDataLayer *layer= (CustomDataLayer*)data2;
+
+ CustomData_set_layer_unique_name(data, layer - data->layers);
+}
+
+static void delete_customdata_layer(void *data1, void *data2)
+{
+ Mesh *me= (Mesh*)data1;
+ CustomData *data= (G.obedit)? &G.editMesh->fdata: &me->fdata;
+ CustomDataLayer *layer= (CustomDataLayer*)data2;
+ void *actlayerdata, *rndlayerdata, *layerdata=layer->data;
+ int type= layer->type;
+ int index= CustomData_get_layer_index(data, type);
+ int i, actindex, rndindex;
+
+ /*ok, deleting a non-active layer needs to preserve the active layer indices.
+ to do this, we store a pointer to the .data member of both layer and the active layer,
+ (to detect if we're deleting the active layer or not), then use the active
+ layer data pointer to find where the active layer has ended up.
+
+ this is necassary because the deletion functions only support deleting the active
+ layer. */
+ actlayerdata = data->layers[CustomData_get_active_layer_index(data, type)].data;
+ rndlayerdata = data->layers[CustomData_get_render_layer_index(data, type)].data;
+ CustomData_set_layer_active(data, type, layer - &data->layers[index]);
+
+ /* Multires is handled seperately because the display data is separate
+ from the data stored in multires */
+ if(me && me->mr) {
+ multires_delete_layer(me, &me->mr->fdata, type, layer - &data->layers[index]);
+ }
+ else if(G.obedit) {
+ EM_free_data_layer(data, type);
+ }
+ else if(me) {
+ CustomData_free_layer_active(data, type, me->totface);
+ mesh_update_customdata_pointers(me);
+ }
+
+ if(!CustomData_has_layer(data, type)) {
+ if(type == CD_MCOL && (G.f & G_VERTEXPAINT))
+ G.f &= ~G_VERTEXPAINT; /* get out of vertexpaint mode */
+ }
+
+ /*reconstruct active layer*/
+ if (actlayerdata != layerdata) {
+ /*find index. . .*/
+ actindex = CustomData_get_layer_index(data, type);
+ for (i=actindex; i<data->totlayer; i++) {
+ if (data->layers[i].data == actlayerdata) {
+ actindex = i - actindex;
+ break;
+ }
+ }
+
+ /*set index. . .*/
+ CustomData_set_layer_active(data, type, actindex);
+ }
+
+ if (rndlayerdata != layerdata) {
+ /*find index. . .*/
+ rndindex = CustomData_get_layer_index(data, type);
+ for (i=rndindex; i<data->totlayer; i++) {
+ if (data->layers[i].data == rndlayerdata) {
+ rndindex = i - rndindex;
+ break;
+ }
+ }
+
+ /*set index. . .*/
+ CustomData_set_layer_render(data, type, rndindex);
+ }
+
+
+ DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA);
+
+ if(type == CD_MTFACE)
+ BIF_undo_push("Delete UV Texture");
+ else if(type == CD_MCOL)
+ BIF_undo_push("Delete Vertex Color");
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWIMAGE, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+}
+
+static int customdata_buttons(
+ uiBlock *block, Mesh *me, CustomData *data,
+ int type, int *activep, int *renderp,
+ int setevt, int setevt_rnd, int newevt,
+ char *label, char *shortlabel, char *browsetip, char *browsetip_rnd,
+ char *newtip, char *deltip, int x, int y)
+{
+ CustomDataLayer *layer;
+ uiBut *but;
+ int i, count= CustomData_number_of_layers(data, type);
+
+ if(count >= MAX_MTFACE) {
+ uiDefBut(block, LABEL, 0, label, x,y,220,19, 0, 0.0, 0, 0, 0, "");
+ }
+ else {
+ uiDefBut(block, LABEL, 0, label, x,y,140,19, 0, 0.0, 0, 0, 0, "");
+ uiBlockBeginAlign(block);
+ uiDefBut(block, BUT, newevt, "New", x+140,y,80,19, 0,0,0,0,0, newtip);
+ uiBlockEndAlign(block);
+ }
+
+ y -= (count)? 24: 19;
+
+ uiBlockBeginAlign(block);
+ for (count=1, i=0; i<data->totlayer; i++) {
+ layer= &data->layers[i];
+
+ if(layer->type == type) {
+ *activep= layer->active + 1;
+ *renderp= layer->active_rnd + 1;
+
+ uiDefIconButI(block, ROW, setevt, ICON_VIEW3D, x,y,25,19, activep, 1.0, count, 0, 0, browsetip);
+ uiDefIconButI(block, ROW, setevt_rnd, ICON_SCENE, x+25,y,25,19, renderp, 1.0, count, 0, 0, browsetip_rnd);
+ but=uiDefBut(block, TEX, setevt, "", x+50,y,145,19, layer->name, 0.0, 31.0, 0, 0, label);
+ uiButSetFunc(but, verify_customdata_name_func, data, layer);
+ but= uiDefIconBut(block, BUT, B_NOP, VICON_X, x+195,y,25,19, NULL, 0.0, 0.0, 0.0, 0.0, deltip);
+ uiButSetFunc(but, delete_customdata_layer, me, layer);
+
+
+ count++;
+ y -= 19;
+ }
+ }
+ uiBlockEndAlign(block);
+
+ return y;
+}
+
+static void editing_panel_mesh_type(Object *ob, Mesh *me)
+{
+ uiBlock *block;
+ uiBut *but;
+ float val;
+ CustomData *fdata;
+ int yco;
+
+ block= uiNewBlock(&curarea->uiblocks, "editing_panel_mesh_type", UI_EMBOSS, UI_HELV, curarea->win);
+ if( uiNewPanel(curarea, block, "Mesh", "Editing", 320, 0, 318, 204)==0) return;
+ uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, ME_AUTOSMOOTH, REDRAWVIEW3D, "Auto Smooth",10,180,170,19, &me->flag, 0, 0, 0, 0, "Treats all set-smoothed faces with angles less than Degr: as 'smooth' during render");
+ uiDefButS(block, NUM, B_DIFF, "Degr:", 10,160,170,19, &me->smoothresh, 1, 80, 0, 0, "Defines maximum angle between face normals that 'Auto Smooth' will operate on");
+ uiBlockEndAlign(block);
+
+ /* Retopo */
+ if(G.obedit) {
+ uiBlockBeginAlign(block);
+ but= uiDefButBitC(block,TOG,RETOPO,B_NOP, "Retopo", 10,130,170,19, &G.scene->toolsettings->retopo_mode, 0,0,0,0, "Turn on the re-topology tool");
+ uiButSetFunc(but,retopo_toggle,ob,me);
+ if(G.scene->toolsettings->retopo_mode) {
+ but= uiDefButBitC(block,TOG,RETOPO_PAINT,B_NOP,"Paint", 10,110,55,19, &G.scene->toolsettings->retopo_mode,0,0,0,0, "Draw intersecting lines in the 3d view, ENTER creates quad or tri faces, wrapped onto other objects in the 3d view.");
+ uiButSetFunc(but,retopo_paint_toggle,ob,me);
+ but= uiDefBut(block,BUT,B_NOP,"Retopo All", 65,110,115,19, 0,0,0,0,0, "Apply the re-topology tool to all selected vertices");
+ uiButSetFunc(but,retopo_do_all_cb,ob,me);
+ }
+ uiBlockEndAlign(block);
+ }
+
+ uiBlockBeginAlign(block);
+ uiDefBut(block, BUT,B_DOCENTER, "Center", 10, 80, 65, 19, 0, 0, 0, 0, 0, "Shifts object data to be centered about object's origin");
+ uiDefBut(block, BUT,B_DOCENTERNEW, "Center New", 75, 80, 105, 19, 0, 0, 0, 0, 0, "Shifts object's origin to center of object data");
+ uiDefBut(block, BUT,B_DOCENTERCURSOR, "Center Cursor", 10, 60, 170, 19, 0, 0, 0, 0, 0, "Shifts object's origin to cursor location");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, ME_TWOSIDED, REDRAWVIEW3D, "Double Sided", 10,30,170,19, &me->flag, 0, 0, 0, 0, "Render/display the mesh as double or single sided");
+ uiDefButBitS(block, TOG, ME_NOPUNOFLIP, REDRAWVIEW3D, "No V.Normal Flip", 10,10,170,19, &me->flag, 0, 0, 0, 0, "Disables flipping of vertexnormals during render");
+ uiBlockEndAlign(block);
+
+ uiDefIDPoinBut(block, test_meshpoin_but, ID_ME, B_REDR, "TexMesh: ", 190,180,220,19, &me->texcomesh, "Derive texture coordinates from another mesh.");
+
+ if(me->msticky) val= 1.0; else val= 0.0;
+ uiDefBut(block, LABEL, 0, "Sticky", 190,155,140,19, 0, val, 0, 0, 0, "");
+ uiBlockBeginAlign(block);
+ if(me->msticky==NULL) {
+ uiDefBut(block, BUT, B_MAKESTICKY, "Make", 330,155, 80,19, 0, 0, 0, 0, 0, "Creates Sticky coordinates from the current camera view background picture");
+ }
+ else uiDefBut(block, BUT, B_DELSTICKY, "Delete", 330,155, 80,19, 0, 0, 0, 0, 0, "Deletes Sticky texture coordinates");
+ uiBlockEndAlign(block);
+
+ fdata= (G.obedit)? &G.editMesh->fdata: &me->fdata;
+ yco= customdata_buttons(block, me, fdata, CD_MTFACE, &acttface, &acttface_rnd,
+ B_SETTFACE, B_SETTFACE_RND, B_NEWTFACE, "UV Texture", "UV Texture:",
+ "Set active UV texture", "Set rendering UV texture", "Creates a new UV texture layer",
+ "Removes the current UV texture layer", 190, 130);
+
+ yco= customdata_buttons(block, me, fdata, CD_MCOL, &actmcol, &actmcol_rnd,
+ B_SETMCOL, B_SETMCOL_RND, B_NEWMCOL, "Vertex Color", "Vertex Color:",
+ "Sets active vertex color layer", "Sets rendering vertex color layer", "Creates a new vertex color layer",
+ "Removes the current vertex color layer", 190, yco-5);
+
+ if(yco < 0)
+ uiNewPanelHeight(block, 204 - yco);
+}
+
+/* *************************** MODIFIERS ******************************** */
+
+void do_modifier_panels(unsigned short event)
+{
+ Object *ob = OBACT;
+
+ switch(event) {
+ case B_MODIFIER_REDRAW:
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWOOPS, 0);
+ break;
+
+ case B_MODIFIER_RECALC:
+ ob->softflag |= OB_SB_RESET;
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWIMAGE, 0);
+ allqueue(REDRAWOOPS, 0);
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ object_handle_update(ob);
+ countall();
+ break;
+ }
+}
+
+static void modifiers_add(void *ob_v, int type)
+{
+ Object *ob = ob_v;
+ ModifierTypeInfo *mti = modifierType_getInfo(type);
+
+ if (mti->flags&eModifierTypeFlag_RequiresOriginalData) {
+ ModifierData *md = ob->modifiers.first;
+
+ while (md && modifierType_getInfo(md->type)->type==eModifierTypeType_OnlyDeform) {
+ md = md->next;
+ }
+
+ BLI_insertlinkbefore(&ob->modifiers, md, modifier_new(type));
+ } else {
+ BLI_addtail(&ob->modifiers, modifier_new(type));
+ }
+ BIF_undo_push("Add modifier");
+}
+
+typedef struct MenuEntry {
+ char *name;
+ int ID;
+} MenuEntry;
+
+static int menuEntry_compare_names(const void *entry1, const void *entry2)
+{
+ return strcmp(((MenuEntry *)entry1)->name, ((MenuEntry *)entry2)->name);
+}
+
+static uiBlock *modifiers_add_menu(void *ob_v)
+{
+ Object *ob = ob_v;
+ uiBlock *block;
+ int i, yco=0;
+ int numEntries = 0;
+ MenuEntry entries[NUM_MODIFIER_TYPES];
+
+ block= uiNewBlock(&curarea->uiblocks, "modifier_add_menu",
+ UI_EMBOSSP, UI_HELV, curarea->win);
+ uiBlockSetButmFunc(block, modifiers_add, ob);
+
+ for (i=eModifierType_None+1; i<NUM_MODIFIER_TYPES; i++) {
+ ModifierTypeInfo *mti = modifierType_getInfo(i);
+
+ /* Only allow adding through appropriate other interfaces */
+ if(ELEM(i, eModifierType_Softbody, eModifierType_Hook)) continue;
+
+ if((mti->flags&eModifierTypeFlag_AcceptsCVs) ||
+ (ob->type==OB_MESH && (mti->flags&eModifierTypeFlag_AcceptsMesh))) {
+ entries[numEntries].name = mti->name;
+ entries[numEntries].ID = i;
+
+ ++numEntries;
+ }
+ }
+
+ qsort(entries, numEntries, sizeof(*entries), menuEntry_compare_names);
+
+
+ for(i = 0; i < numEntries; ++i)
+ uiDefBut(block, BUTM, B_MODIFIER_RECALC, entries[i].name,
+ 0, yco -= 20, 160, 19, NULL, 0, 0, 1, entries[i].ID, "");
+
+ uiTextBoundsBlock(block, 50);
+ uiBlockSetDirection(block, UI_DOWN);
+
+ return block;
+}
+
+static void modifiers_del(void *ob_v, void *md_v)
+{
+ Object *ob = ob_v;
+ ModifierData *md;
+
+ /* It seems on rapid delete it is possible to
+ * get called twice on same modifier, so make
+ * sure it is in list.
+ */
+ for (md=ob->modifiers.first; md; md=md->next)
+ if (md==md_v)
+ break;
+
+ if (!md)
+ return;
+
+ BLI_remlink(&ob->modifiers, md_v);
+
+ modifier_free(md_v);
+
+ BIF_undo_push("Del modifier");
+}
+
+int mod_moveUp(void *ob_v, void *md_v)
+{
+ Object *ob = ob_v;
+ ModifierData *md = md_v;
+
+ if (md->prev) {
+ ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ if (mti->type!=eModifierTypeType_OnlyDeform) {
+ ModifierTypeInfo *nmti = modifierType_getInfo(md->prev->type);
+
+ if (nmti->flags&eModifierTypeFlag_RequiresOriginalData)
+ return -1;
+ }
+
+ BLI_remlink(&ob->modifiers, md);
+ BLI_insertlink(&ob->modifiers, md->prev->prev, md);
+ }
+
+ return 0;
+}
+
+static void modifiers_moveUp(void *ob_v, void *md_v)
+{
+ if( mod_moveUp( ob_v, md_v ) )
+ error("Cannot move above a modifier requiring original data.");
+ else
+ BIF_undo_push("Move modifier");
+}
+
+int mod_moveDown(void *ob_v, void *md_v)
+{
+ Object *ob = ob_v;
+ ModifierData *md = md_v;
+
+ if (md->next) {
+ ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ if (mti->flags&eModifierTypeFlag_RequiresOriginalData) {
+ ModifierTypeInfo *nmti = modifierType_getInfo(md->next->type);
+
+ if (nmti->type!=eModifierTypeType_OnlyDeform)
+ return -1;
+ }
+
+ BLI_remlink(&ob->modifiers, md);
+ BLI_insertlink(&ob->modifiers, md->next, md);
+ }
+
+ return 0;
+}
+
+static void modifiers_moveDown(void *ob_v, void *md_v)
+{
+ if( mod_moveDown( ob_v, md_v ) )
+ error("Cannot move beyond a non-deforming modifier.");
+ else
+ BIF_undo_push("Move modifier");
+}
+
+static void modifier_testLatticeObj(char *name, ID **idpp)
+{
+ ID *id;
+
+ for (id= G.main->object.first; id; id= id->next) {
+ if( strcmp(name, id->name+2)==0 ) {
+ if (((Object *)id)->type != OB_LATTICE) {
+ error ("Lattice deform object must be a lattice");
+ break;
+ }
+ *idpp= id;
+ return;
+ }
+ }
+ *idpp= 0;
+}
+
+static void modifier_testCurveObj(char *name, ID **idpp)
+{
+ ID *id;
+
+ for (id= G.main->object.first; id; id= id->next) {
+ if( strcmp(name, id->name+2)==0 ) {
+ if (((Object *)id)->type != OB_CURVE) {
+ error ("Curve deform object must be a curve");
+ break;
+ }
+ *idpp= id;
+ return;
+ }
+ }
+ *idpp= 0;
+}
+
+static void modifier_testMeshObj(char *name, ID **idpp)
+{
+ ID *id;
+
+ for (id= G.main->object.first; id; id= id->next) {
+ /* no boolean on its own object */
+ if(id != (ID *)OBACT) {
+ if( strcmp(name, id->name+2)==0 ) {
+ if (((Object *)id)->type != OB_MESH) {
+ error ("Boolean modifier object must be a mesh");
+ break;
+ }
+ *idpp= id;
+ return;
+ }
+ }
+ }
+ *idpp= NULL;
+}
+
+static void modifier_testArmatureObj(char *name, ID **idpp)
+{
+ ID *id;
+
+ for (id= G.main->object.first; id; id= id->next) {
+ if( strcmp(name, id->name+2)==0 ) {
+ if (((Object *)id)->type != OB_ARMATURE) {
+ error ("Armature deform object must be an armature");
+ break;
+ }
+ *idpp= id;
+ return;
+ }
+ }
+ *idpp= 0;
+}
+
+static void modifier_testTexture(char *name, ID **idpp)
+{
+ ID *id;
+
+ for(id = G.main->tex.first; id; id = id->next) {
+ if(strcmp(name, id->name + 2) == 0) {
+ *idpp = id;
+ /* texture gets user, objects not: delete object = clear modifier */
+ id_us_plus(id);
+ return;
+ }
+ }
+ *idpp = 0;
+}
+
+#if 0 /* this is currently unused, but could be useful in the future */
+static void modifier_testMaterial(char *name, ID **idpp)
+{
+ ID *id;
+
+ for(id = G.main->mat.first; id; id = id->next) {
+ if(strcmp(name, id->name + 2) == 0) {
+ *idpp = id;
+ return;
+ }
+ }
+ *idpp = 0;
+}
+#endif
+
+static void modifier_testImage(char *name, ID **idpp)
+{
+ ID *id;
+
+ for(id = G.main->image.first; id; id = id->next) {
+ if(strcmp(name, id->name + 2) == 0) {
+ *idpp = id;
+ return;
+ }
+ }
+ *idpp = 0;
+}
+
+/* autocomplete callback for ID buttons */
+void autocomplete_image(char *str, void *arg_v)
+{
+ /* search if str matches the beginning of an ID struct */
+ if(str[0]) {
+ AutoComplete *autocpl = autocomplete_begin(str, 22);
+ ID *id;
+
+ for(id = G.main->image.first; id; id = id->next)
+ autocomplete_do_name(autocpl, id->name+2);
+
+ autocomplete_end(autocpl, str);
+ }
+}
+
+/* autocomplete callback for ID buttons */
+void autocomplete_meshob(char *str, void *arg_v)
+{
+ /* search if str matches the beginning of an ID struct */
+ if(str[0]) {
+ AutoComplete *autocpl = autocomplete_begin(str, 22);
+ ID *id;
+
+ for(id = G.main->object.first; id; id = id->next)
+ if(((Object *)id)->type == OB_MESH)
+ autocomplete_do_name(autocpl, id->name+2);
+
+ autocomplete_end(autocpl, str);
+ }
+}
+
+static void modifiers_applyModifier(void *obv, void *mdv)
+{
+ Object *ob = obv;
+ ModifierData *md = mdv;
+ DerivedMesh *dm;
+ Mesh *me = ob->data;
+ int converted = 0;
+
+ if (G.obedit) {
+ error("Modifiers cannot be applied in editmode");
+ return;
+ } else if (((ID*) ob->data)->us>1) {
+ error("Modifiers cannot be applied to multi-user data");
+ return;
+ }
+
+ if (md!=ob->modifiers.first) {
+ if (!okee("Modifier is not first"))
+ return;
+ }
+
+ if (ob->type==OB_MESH) {
+ if(me->mr && multires_modifier_warning()) {
+ error("Modifier changes topology; cannot apply with multires active");
+ return;
+ }
+ if(me->key) {
+ error("Modifier cannot be applied to Mesh with Shape Keys");
+ return;
+ }
+
+ sculptmode_pmv_off(me);
+
+ dm = mesh_create_derived_for_modifier(ob, md);
+ if (!dm) {
+ error("Modifier is disabled or returned error, skipping apply");
+ return;
+ }
+
+ DM_to_mesh(dm, me);
+ converted = 1;
+
+ dm->release(dm);
+ }
+ else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
+ ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ Curve *cu = ob->data;
+ int numVerts;
+ float (*vertexCos)[3];
+
+ if (!okee("Apply will only change CV points, not tesselated/bevel vertices"))
+ return;
+
+ if (!(md->mode&eModifierMode_Realtime) || (mti->isDisabled && mti->isDisabled(md))) {
+ error("Modifier is disabled, skipping apply");
+ return;
+ }
+
+ vertexCos = curve_getVertexCos(cu, &cu->nurb, &numVerts);
+ mti->deformVerts(md, ob, NULL, vertexCos, numVerts);
+ curve_applyVertexCos(cu, &cu->nurb, vertexCos);
+
+ converted = 1;
+
+ MEM_freeN(vertexCos);
+
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ }
+ else {
+ error("Cannot apply modifier for this object type");
+ return;
+ }
+
+ if (converted) {
+ BLI_remlink(&ob->modifiers, md);
+ modifier_free(md);
+
+ BIF_undo_push("Apply modifier");
+ }
+}
+
+static void modifiers_copyModifier(void *ob_v, void *md_v)
+{
+ Object *ob = ob_v;
+ ModifierData *md = md_v;
+ ModifierData *nmd = modifier_new(md->type);
+
+ modifier_copyData(md, nmd);
+
+ BLI_insertlink(&ob->modifiers, md, nmd);
+
+ BIF_undo_push("Copy modifier");
+}
+
+static void modifiers_setOnCage(void *ob_v, void *md_v)
+{
+ Object *ob = ob_v;
+ ModifierData *md;
+
+ int i, cageIndex = modifiers_getCageIndex(ob, NULL );
+
+ for( i = 0, md=ob->modifiers.first; md; ++i, md=md->next )
+ if( md == md_v ) {
+ if( i >= cageIndex )
+ md->mode ^= eModifierMode_OnCage;
+ break;
+ }
+}
+
+static void modifiers_clearHookOffset(void *ob_v, void *md_v)
+{
+ Object *ob = ob_v;
+ ModifierData *md = md_v;
+ HookModifierData *hmd = (HookModifierData*) md;
+
+ if (hmd->object) {
+ Mat4Invert(hmd->object->imat, hmd->object->obmat);
+ Mat4MulSerie(hmd->parentinv, hmd->object->imat, ob->obmat, NULL, NULL, NULL, NULL, NULL, NULL);
+ BIF_undo_push("Clear hook offset");
+ }
+}
+
+static void modifiers_cursorHookCenter(void *ob_v, void *md_v)
+{
+ Object *ob = ob_v;
+ ModifierData *md = md_v;
+ HookModifierData *hmd = (HookModifierData*) md;
+
+ if (G.vd) {
+ float *curs = give_cursor();
+ float bmat[3][3], imat[3][3];
+
+ where_is_object(ob);
+
+ Mat3CpyMat4(bmat, ob->obmat);
+ Mat3Inv(imat, bmat);
+
+ curs= give_cursor();
+ hmd->cent[0]= curs[0]-ob->obmat[3][0];
+ hmd->cent[1]= curs[1]-ob->obmat[3][1];
+ hmd->cent[2]= curs[2]-ob->obmat[3][2];
+ Mat3MulVecfl(imat, hmd->cent);
+
+ BIF_undo_push("Hook cursor center");
+ }
+}
+
+static void modifiers_selectHook(void *ob_v, void *md_v)
+{
+ ModifierData *md = md_v;
+ HookModifierData *hmd = (HookModifierData*) md;
+
+ hook_select(hmd);
+}
+
+static void modifiers_reassignHook(void *ob_v, void *md_v)
+{
+ ModifierData *md = md_v;
+ HookModifierData *hmd = (HookModifierData*) md;
+ float cent[3];
+ int *indexar, tot, ok;
+ char name[32];
+
+ ok= hook_getIndexArray(&tot, &indexar, name, cent);
+
+ if (!ok) {
+ error("Requires selected vertices or active Vertex Group");
+ } else {
+ if (hmd->indexar) {
+ MEM_freeN(hmd->indexar);
+ }
+
+ VECCOPY(hmd->cent, cent);
+ hmd->indexar = indexar;
+ hmd->totindex = tot;
+ }
+}
+
+static void modifiers_convertToReal(void *ob_v, void *md_v)
+{
+ Object *ob = ob_v;
+ ModifierData *md = md_v;
+ ModifierData *nmd = modifier_new(md->type);
+
+ modifier_copyData(md, nmd);
+ nmd->mode &= ~eModifierMode_Virtual;
+
+ BLI_addhead(&ob->modifiers, nmd);
+
+ ob->partype = PAROBJECT;
+
+ BIF_undo_push("Modifier convert to real");
+}
+
+static void build_uvlayer_menu_vars(CustomData *data, char **menu_string,
+ int *uvlayer_tmp, char *uvlayer_name)
+{
+ char strtmp[38];
+ int totuv, i;
+ CustomDataLayer *layer
+ = &data->layers[CustomData_get_layer_index(data, CD_MTFACE)];
+
+ *uvlayer_tmp = -1;
+
+ totuv = CustomData_number_of_layers(data, CD_MTFACE);
+
+ *menu_string = MEM_callocN(sizeof(**menu_string) * (totuv * 38 + 10),
+ "menu_string");
+ sprintf(*menu_string, "UV Layer%%t");
+ for(i = 0; i < totuv; i++) {
+ /* assign first layer as uvlayer_name if uvlayer_name is null. */
+ if(strcmp(layer->name, uvlayer_name) == 0) *uvlayer_tmp = i + 1;
+ sprintf(strtmp, "|%s%%x%d", layer->name, i + 1);
+ strcat(*menu_string, strtmp);
+ layer++;
+ }
+
+ /* there is no uvlayer defined, or else it was deleted. Assign active
+ * layer, then recalc modifiers.
+ */
+ if(*uvlayer_tmp == -1) {
+ if(CustomData_get_active_layer_index(data, CD_MTFACE) != -1) {
+ *uvlayer_tmp = 1;
+ layer = data->layers;
+ for(i = 0; i < CustomData_get_active_layer_index(data, CD_MTFACE);
+ i++, layer++) {
+ if(layer->type == CD_MTFACE) (*uvlayer_tmp)++;
+ }
+ strcpy(uvlayer_name, layer->name);
+
+ /* update the modifiers */
+ do_modifier_panels(B_MODIFIER_RECALC);
+ } else {
+ /* ok we have no uv layers, so make sure menu button knows that.*/
+ *uvlayer_tmp = 0;
+ }
+ }
+}
+
+void set_displace_uvlayer(void *arg1, void *arg2)
+{
+ DisplaceModifierData *dmd=arg1;
+ CustomDataLayer *layer = arg2;
+
+ /*check we have UV layers*/
+ if (dmd->uvlayer_tmp < 1) return;
+ layer = layer + (dmd->uvlayer_tmp-1);
+
+ strcpy(dmd->uvlayer_name, layer->name);
+}
+
+void set_uvproject_uvlayer(void *arg1, void *arg2)
+{
+ UVProjectModifierData *umd=arg1;
+ CustomDataLayer *layer = arg2;
+
+ /*check we have UV layers*/
+ if (umd->uvlayer_tmp < 1) return;
+ layer = layer + (umd->uvlayer_tmp-1);
+
+ strcpy(umd->uvlayer_name, layer->name);
+}
+
+static void modifiers_bindMeshDeform(void *ob_v, void *md_v)
+{
+ MeshDeformModifierData *mmd = (MeshDeformModifierData*) md_v;
+ Object *ob = (Object*)ob_v;
+
+ if(mmd->bindweights) {
+ MEM_freeN(mmd->bindweights);
+ MEM_freeN(mmd->bindcos);
+ mmd->bindweights= NULL;
+ mmd->bindcos= NULL;
+ mmd->totvert= 0;
+ mmd->totcagevert= 0;
+ }
+ else {
+ DerivedMesh *dm;
+ int mode= mmd->modifier.mode;
+
+ /* force modifier to run, it will call binding routine */
+ mmd->needbind= 1;
+ mmd->modifier.mode |= eModifierMode_Realtime;
+
+ if(ob->type == OB_MESH) {
+ dm= mesh_create_derived_view(ob, 0);
+ dm->release(dm);
+ }
+ else if(ob->type == OB_LATTICE) {
+ lattice_calc_modifiers(ob);
+ }
+
+ mmd->needbind= 0;
+ mmd->modifier.mode= mode;
+ }
+}
+
+static void draw_modifier(uiBlock *block, Object *ob, ModifierData *md, int *xco, int *yco, int index, int cageIndex, int lastCageIndex)
+{
+ ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ uiBut *but;
+ int isVirtual = md->mode&eModifierMode_Virtual;
+ int x = *xco, y = *yco, color = md->error?TH_REDALERT:TH_BUT_NEUTRAL;
+ int editing = (G.obedit==ob);
+ short height=26, width = 295, buttonWidth = width-120-10;
+ char str[128];
+
+ /* rounded header */
+ uiBlockSetCol(block, color);
+ /* roundbox 4 free variables: corner-rounding, nop, roundbox type, shade */
+ uiDefBut(block, ROUNDBOX, 0, "", x-10, y-4, width, 25, NULL, 7.0, 0.0,
+ (!isVirtual && (md->mode&eModifierMode_Expanded))?3:15, 20, "");
+ uiBlockSetCol(block, TH_AUTO);
+
+ /* open/close icon */
+ if (!isVirtual) {
+ uiBlockSetEmboss(block, UI_EMBOSSN);
+ uiDefIconButBitI(block, ICONTOG, eModifierMode_Expanded, B_MODIFIER_REDRAW, VICON_DISCLOSURE_TRI_RIGHT, x-10, y-2, 20, 20, &md->mode, 0.0, 0.0, 0.0, 0.0, "Collapse/Expand Modifier");
+ }
+
+ uiBlockSetEmboss(block, UI_EMBOSS);
+
+ if (isVirtual) {
+ sprintf(str, "%s parent deform", md->name);
+ uiDefBut(block, LABEL, 0, str, x+10, y-1, width-110, 19, NULL, 0.0, 0.0, 0.0, 0.0, "Modifier name");
+
+ but = uiDefBut(block, BUT, B_MODIFIER_RECALC, "Make Real", x+width-100, y, 80, 16, NULL, 0.0, 0.0, 0.0, 0.0, "Convert virtual modifier to a real modifier");
+ uiButSetFunc(but, modifiers_convertToReal, ob, md);
+ } else {
+ uiBlockBeginAlign(block);
+ uiDefBut(block, TEX, B_MODIFIER_REDRAW, "", x+10, y-1, buttonWidth-60, 19, md->name, 0.0, sizeof(md->name)-1, 0.0, 0.0, "Modifier name");
+
+ /* Softbody not allowed in this situation, enforce! */
+ if (md->type!=eModifierType_Softbody || !(ob->pd && ob->pd->deflect)) {
+ uiDefIconButBitI(block, TOG, eModifierMode_Render, B_MODIFIER_RECALC, ICON_SCENE, x+10+buttonWidth-60, y-1, 19, 19,&md->mode, 0, 0, 1, 0, "Enable modifier during rendering");
+ uiDefIconButBitI(block, TOG, eModifierMode_Realtime, B_MODIFIER_RECALC, VICON_VIEW3D, x+10+buttonWidth-40, y-1, 19, 19,&md->mode, 0, 0, 1, 0, "Enable modifier during interactive display");
+ if (mti->flags&eModifierTypeFlag_SupportsEditmode) {
+ uiDefIconButBitI(block, TOG, eModifierMode_Editmode, B_MODIFIER_RECALC, VICON_EDIT, x+10+buttonWidth-20, y-1, 19, 19,&md->mode, 0, 0, 1, 0, "Enable modifier during Editmode (only if enabled for display)");
+ }
+ }
+ uiBlockEndAlign(block);
+
+ uiBlockSetEmboss(block, UI_EMBOSSR);
+
+ if (ob->type==OB_MESH && modifier_couldBeCage(md) && index<=lastCageIndex) {
+ int icon, color;
+
+ if (index==cageIndex) {
+ color = TH_BUT_SETTING;
+ icon = VICON_EDITMODE_HLT;
+ } else if (index<cageIndex) {
+ color = TH_BUT_NEUTRAL;
+ icon = VICON_EDITMODE_DEHLT;
+ } else {
+ color = TH_BUT_NEUTRAL;
+ icon = ICON_BLANK1;
+ }
+ uiBlockSetCol(block, color);
+ but = uiDefIconBut(block, BUT, B_MODIFIER_RECALC, icon, x+width-105, y, 16, 16, NULL, 0.0, 0.0, 0.0, 0.0, "Apply modifier to editing cage during Editmode");
+ uiButSetFunc(but, modifiers_setOnCage, ob, md);
+ uiBlockSetCol(block, TH_AUTO);
+ }
+
+ uiBlockSetCol(block, TH_BUT_ACTION);
+
+ but = uiDefIconBut(block, BUT, B_MODIFIER_RECALC, VICON_MOVE_UP, x+width-75, y, 16, 16, NULL, 0.0, 0.0, 0.0, 0.0, "Move modifier up in stack");
+ uiButSetFunc(but, modifiers_moveUp, ob, md);
+
+ but = uiDefIconBut(block, BUT, B_MODIFIER_RECALC, VICON_MOVE_DOWN, x+width-75+20, y, 16, 16, NULL, 0.0, 0.0, 0.0, 0.0, "Move modifier down in stack");
+ uiButSetFunc(but, modifiers_moveDown, ob, md);
+
+ uiBlockSetEmboss(block, UI_EMBOSSN);
+
+ but = uiDefIconBut(block, BUT, B_MODIFIER_RECALC, VICON_X, x+width-70+40, y, 16, 16, NULL, 0.0, 0.0, 0.0, 0.0, "Delete modifier");
+ uiButSetFunc(but, modifiers_del, ob, md);
+ uiBlockSetCol(block, TH_AUTO);
+ }
+
+ uiBlockSetEmboss(block, UI_EMBOSS);
+
+ if (isVirtual || !(md->mode&eModifierMode_Expanded)) {
+ y -= 18;
+ } else {
+ int cy = y - 8;
+ int lx = x + width - 60 - 15;
+
+ if (md->type==eModifierType_Subsurf) {
+ height = 105;
+ } else if (md->type==eModifierType_Lattice) {
+ height = 48;
+ } else if (md->type==eModifierType_Curve) {
+ height = 72;
+ } else if (md->type==eModifierType_Build) {
+ height = 86;
+ } else if (md->type==eModifierType_Mirror) {
+ height = 67;
+ } else if (md->type==eModifierType_EdgeSplit) {
+ EdgeSplitModifierData *emd = (EdgeSplitModifierData*) md;
+ height = 48;
+ if(emd->flags & MOD_EDGESPLIT_FROMANGLE) height += 19;
+ } else if (md->type==eModifierType_Displace) {
+ DisplaceModifierData *dmd = (DisplaceModifierData *)md;
+ height = 124;
+ if(dmd->texmapping == MOD_DISP_MAP_OBJECT ||
+ dmd->texmapping == MOD_DISP_MAP_UV)
+ height += 19;
+ } else if (md->type==eModifierType_UVProject) {
+ height = 114 + ((UVProjectModifierData *)md)->num_projectors * 19;
+ } else if (md->type==eModifierType_Decimate) {
+ height = 48;
+ } else if (md->type==eModifierType_Smooth) {
+ height = 86;
+ } else if (md->type==eModifierType_Cast) {
+ height = 143;
+ } else if (md->type==eModifierType_Wave) {
+ WaveModifierData *wmd = (WaveModifierData *)md;
+ height = 294;
+ if(wmd->texmapping == MOD_WAV_MAP_OBJECT ||
+ wmd->texmapping == MOD_WAV_MAP_UV)
+ height += 19;
+ if(wmd->flag & MOD_WAVE_NORM)
+ height += 19;
+ } else if (md->type==eModifierType_Armature) {
+ height = 86;
+ } else if (md->type==eModifierType_Hook) {
+ HookModifierData *hmd = (HookModifierData*) md;
+ height = 86;
+ if (editing)
+ height += 20;
+ if(hmd->indexar==NULL)
+ height += 20;
+ } else if (md->type==eModifierType_Softbody) {
+ height = 26;
+ } else if (md->type==eModifierType_Boolean) {
+ height = 48;
+ } else if (md->type==eModifierType_Array) {
+ height = 211;
+ } else if (md->type==eModifierType_MeshDeform) {
+ height = 73;
+ }
+
+ /* roundbox 4 free variables: corner-rounding, nop, roundbox type, shade */
+ uiDefBut(block, ROUNDBOX, 0, "", x-10, y-height-2, width, height-2, NULL, 5.0, 0.0, 12, 40, "");
+
+ y -= 18;
+
+ if (!isVirtual) {
+ uiBlockBeginAlign(block);
+ but = uiDefBut(block, BUT, B_MODIFIER_RECALC, "Apply", lx,(cy-=19),60,19, 0, 0, 0, 0, 0, "Apply the current modifier and remove from the stack");
+ uiButSetFunc(but, modifiers_applyModifier, ob, md);
+ if (md->type!=eModifierType_Softbody) {
+ but = uiDefBut(block, BUT, B_MODIFIER_RECALC, "Copy", lx,(cy-=19),60,19, 0, 0, 0, 0, 0, "Duplicate the current modifier at the same position in the stack");
+ uiButSetFunc(but, modifiers_copyModifier, ob, md);
+ }
+ uiBlockEndAlign(block);
+ }
+
+ lx = x + 10;
+ cy = y + 10 - 1;
+ uiBlockBeginAlign(block);
+ if (md->type==eModifierType_Subsurf) {
+ SubsurfModifierData *smd = (SubsurfModifierData*) md;
+ char subsurfmenu[]="Subsurf Type%t|Catmull-Clark%x0|Simple Subdiv.%x1";
+ uiDefButS(block, MENU, B_MODIFIER_RECALC, subsurfmenu, lx,(cy-=19),buttonWidth,19, &smd->subdivType, 0, 0, 0, 0, "Selects type of subdivision algorithm.");
+ uiDefButS(block, NUM, B_MODIFIER_RECALC, "Levels:", lx, (cy-=19), buttonWidth,19, &smd->levels, 1, 6, 0, 0, "Number subdivisions to perform");
+ uiDefButS(block, NUM, B_MODIFIER_REDRAW, "Render Levels:", lx, (cy-=19), buttonWidth,19, &smd->renderLevels, 1, 6, 0, 0, "Number subdivisions to perform when rendering");
+
+ /* Disabled until non-EM DerivedMesh implementation is complete */
+
+ /*
+ uiDefButBitS(block, TOG, eSubsurfModifierFlag_Incremental, B_MODIFIER_RECALC, "Incremental", lx, (cy-=19),90,19,&smd->flags, 0, 0, 0, 0, "Use incremental calculation, even outside of mesh mode");
+ uiDefButBitS(block, TOG, eSubsurfModifierFlag_DebugIncr, B_MODIFIER_RECALC, "Debug", lx+90, cy,buttonWidth-90,19,&smd->flags, 0, 0, 0, 0, "Visualize the subsurf incremental calculation, for debugging effect of other modifiers");
+ */
+
+ uiDefButBitS(block, TOG, eSubsurfModifierFlag_ControlEdges, B_MODIFIER_RECALC, "Optimal Draw", lx, (cy-=19), buttonWidth,19,&smd->flags, 0, 0, 0, 0, "Skip drawing/rendering of interior subdivided edges");
+ uiDefButBitS(block, TOG, eSubsurfModifierFlag_SubsurfUv, B_MODIFIER_RECALC, "Subsurf UV", lx, (cy-=19),buttonWidth,19,&smd->flags, 0, 0, 0, 0, "Use subsurf to subdivide UVs");
+ } else if (md->type==eModifierType_Lattice) {
+ LatticeModifierData *lmd = (LatticeModifierData*) md;
+ uiDefIDPoinBut(block, modifier_testLatticeObj, ID_OB, B_CHANGEDEP, "Ob: ", lx, (cy-=19), buttonWidth,19, &lmd->object, "Lattice object to deform with");
+ but=uiDefBut(block, TEX, B_MODIFIER_RECALC, "VGroup: ", lx, (cy-=19), buttonWidth,19, &lmd->name, 0.0, 31.0, 0, 0, "Vertex Group name");
+ uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)ob);
+ } else if (md->type==eModifierType_Curve) {
+ CurveModifierData *cmd = (CurveModifierData*) md;
+ uiDefIDPoinBut(block, modifier_testCurveObj, ID_OB, B_CHANGEDEP, "Ob: ", lx, (cy-=19), buttonWidth,19, &cmd->object, "Curve object to deform with");
+ but=uiDefBut(block, TEX, B_MODIFIER_RECALC, "VGroup: ", lx, (cy-=19), buttonWidth,19, &cmd->name, 0.0, 31.0, 0, 0, "Vertex Group name");
+ uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)ob);
+
+ uiDefButS(block, ROW,B_MODIFIER_RECALC,"X", lx, (cy-=19), 19,19, &cmd->defaxis, 12.0, MOD_CURVE_POSX, 0, 0, "The axis that the curve deforms along");
+ uiDefButS(block, ROW,B_MODIFIER_RECALC,"Y", (lx+buttonWidth/6), cy, 19,19, &cmd->defaxis, 12.0, MOD_CURVE_POSY, 0, 0, "The axis that the curve deforms along");
+ uiDefButS(block, ROW,B_MODIFIER_RECALC,"Z", (lx+2*buttonWidth/6), cy, 19,19, &cmd->defaxis, 12.0, MOD_CURVE_POSZ, 0, 0, "The axis that the curve deforms along");
+ uiDefButS(block, ROW,B_MODIFIER_RECALC,"-X", (lx+3*buttonWidth/6), cy, 24,19, &cmd->defaxis, 12.0, MOD_CURVE_NEGX, 0, 0, "The axis that the curve deforms along");
+ uiDefButS(block, ROW,B_MODIFIER_RECALC,"-Y", (lx+4*buttonWidth/6), cy, 24,19, &cmd->defaxis, 12.0, MOD_CURVE_NEGY, 0, 0, "The axis that the curve deforms along");
+ uiDefButS(block, ROW,B_MODIFIER_RECALC,"-Z", (lx+buttonWidth-buttonWidth/6), cy, 24,19, &cmd->defaxis, 12.0, MOD_CURVE_NEGZ, 0, 0, "The axis that the curve deforms along");
+ } else if (md->type==eModifierType_Build) {
+ BuildModifierData *bmd = (BuildModifierData*) md;
+ uiDefButF(block, NUM, B_MODIFIER_RECALC, "Start:", lx, (cy-=19), buttonWidth,19, &bmd->start, 1.0, MAXFRAMEF, 100, 0, "Specify the start frame of the effect");
+ uiDefButF(block, NUM, B_MODIFIER_RECALC, "Length:", lx, (cy-=19), buttonWidth,19, &bmd->length, 1.0, MAXFRAMEF, 100, 0, "Specify the total time the build effect requires");
+ uiDefButI(block, TOG, B_MODIFIER_RECALC, "Randomize", lx, (cy-=19), buttonWidth,19, &bmd->randomize, 0, 0, 1, 0, "Randomize the faces or edges during build.");
+ uiDefButI(block, NUM, B_MODIFIER_RECALC, "Seed:", lx, (cy-=19), buttonWidth,19, &bmd->seed, 1.0, MAXFRAMEF, 100, 0, "Specify the seed for random if used.");
+ } else if (md->type==eModifierType_Mirror) {
+ MirrorModifierData *mmd = (MirrorModifierData*) md;
+ uiDefButF(block, NUM, B_MODIFIER_RECALC, "Merge Limit:", lx, (cy-=19), buttonWidth,19, &mmd->tolerance, 0.0, 1.0, 10, 10, "Distance from axis within which mirrored vertices are merged");
+ uiDefButBitS(block, TOG, MOD_MIR_AXIS_X, B_MODIFIER_RECALC, "X", lx,(cy-=19),20,19, &mmd->flag, 0, 0, 0, 0, "Enable X axis mirror");
+ uiDefButBitS(block, TOG, MOD_MIR_AXIS_Y, B_MODIFIER_RECALC, "Y", lx+20,cy,20,19, &mmd->flag, 0, 0, 0, 0, "Enable Y axis mirror");
+ uiDefButBitS(block, TOG, MOD_MIR_AXIS_Z, B_MODIFIER_RECALC, "Z", lx+40,cy,20,19, &mmd->flag, 0, 0, 0, 0, "Enable Z axis mirror");
+ uiDefButBitS(block, TOG, MOD_MIR_CLIPPING, B_MODIFIER_RECALC, "Do Clipping", lx+60, cy, buttonWidth-60,19, &mmd->flag, 1, 2, 0, 0, "Prevents during Transform vertices to go through Mirror");
+ uiDefButBitS(block, TOG, MOD_MIR_MIRROR_U, B_MODIFIER_RECALC,
+ "Mirror U",
+ lx, (cy-=19), buttonWidth/2, 19,
+ &mmd->flag, 0, 0, 0, 0,
+ "Mirror the U texture coordinate around "
+ "the 0.5 point");
+ uiDefButBitS(block, TOG, MOD_MIR_MIRROR_V, B_MODIFIER_RECALC,
+ "Mirror V",
+ lx + buttonWidth/2 + 1, cy, buttonWidth/2, 19,
+ &mmd->flag, 0, 0, 0, 0,
+ "Mirror the V texture coordinate around "
+ "the 0.5 point");
+ } else if (md->type==eModifierType_EdgeSplit) {
+ EdgeSplitModifierData *emd = (EdgeSplitModifierData*) md;
+ uiDefButBitI(block, TOG, MOD_EDGESPLIT_FROMANGLE,
+ B_MODIFIER_RECALC, "From Edge Angle",
+ lx, (cy -= 19), buttonWidth, 19,
+ &emd->flags, 0, 0, 0, 0,
+ "Split edges with high angle between faces");
+ if(emd->flags & MOD_EDGESPLIT_FROMANGLE) {
+ uiDefButF(block, NUM, B_MODIFIER_RECALC, "Split Angle:",
+ lx, (cy -= 19), buttonWidth, 19, &emd->split_angle,
+ 0.0, 180.0, 100, 2,
+ "Angle above which to split edges");
+ }
+ uiDefButBitI(block, TOG, MOD_EDGESPLIT_FROMFLAG,
+ B_MODIFIER_RECALC, "From Marked As Sharp",
+ lx, (cy -= 19), buttonWidth, 19,
+ &emd->flags, 0, 0, 0, 0,
+ "Split edges that are marked as sharp");
+ } else if (md->type==eModifierType_Displace) {
+ DisplaceModifierData *dmd = (DisplaceModifierData*) md;
+ but = uiDefBut(block, TEX, B_MODIFIER_RECALC, "VGroup: ",
+ lx, (cy -= 19), buttonWidth, 19,
+ &dmd->defgrp_name, 0.0, 31.0, 0, 0,
+ "Name of vertex group to displace"
+ " (displace whole mesh if blank)");
+ uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)ob);
+ uiDefIDPoinBut(block, modifier_testTexture, ID_TE, B_CHANGEDEP,
+ "Texture: ", lx, (cy -= 19), buttonWidth, 19,
+ &dmd->texture,
+ "Texture to use as displacement input");
+ uiDefButF(block, NUM, B_MODIFIER_RECALC, "Midlevel:",
+ lx, (cy -= 19), buttonWidth, 19, &dmd->midlevel,
+ 0, 1, 10, 3,
+ "Material value that gives no displacement");
+ uiDefButF(block, NUM, B_MODIFIER_RECALC, "Strength:",
+ lx, (cy -= 19), buttonWidth, 19, &dmd->strength,
+ -1000, 1000, 10, 10,
+ "Strength of displacement");
+ sprintf(str, "Direction%%t|Normal%%x%d|RGB -> XYZ%%x%d|"
+ "Z%%x%d|Y%%x%d|X%%x%d",
+ MOD_DISP_DIR_NOR, MOD_DISP_DIR_RGB_XYZ,
+ MOD_DISP_DIR_Z, MOD_DISP_DIR_Y, MOD_DISP_DIR_X);
+ uiDefButI(block, MENU, B_MODIFIER_RECALC, str,
+ lx, (cy -= 19), buttonWidth, 19, &dmd->direction,
+ 0.0, 1.0, 0, 0, "Displace direction");
+ sprintf(str, "Texture Coordinates%%t"
+ "|Local%%x%d|Global%%x%d|Object%%x%d|UV%%x%d",
+ MOD_DISP_MAP_LOCAL, MOD_DISP_MAP_GLOBAL,
+ MOD_DISP_MAP_OBJECT, MOD_DISP_MAP_UV);
+ uiDefButI(block, MENU, B_MODIFIER_RECALC, str,
+ lx, (cy -= 19), buttonWidth, 19, &dmd->texmapping,
+ 0.0, 1.0, 0, 0,
+ "Texture coordinates used for displacement input");
+ if (dmd->texmapping == MOD_DISP_MAP_UV) {
+ char *strtmp;
+ int i;
+ CustomData *fdata = G.obedit ? &G.editMesh->fdata
+ : &((Mesh*)ob->data)->fdata;
+ build_uvlayer_menu_vars(fdata, &strtmp, &dmd->uvlayer_tmp,
+ dmd->uvlayer_name);
+ but = uiDefButI(block, MENU, B_MODIFIER_RECALC, strtmp,
+ lx, (cy -= 19), buttonWidth, 19, &dmd->uvlayer_tmp,
+ 0.0, 1.0, 0, 0, "Set the UV layer to use");
+ MEM_freeN(strtmp);
+ i = CustomData_get_layer_index(fdata, CD_MTFACE);
+ uiButSetFunc(but, set_displace_uvlayer, dmd,
+ &fdata->layers[i]);
+ }
+ if(dmd->texmapping == MOD_DISP_MAP_OBJECT) {
+ uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CHANGEDEP,
+ "Ob: ", lx, (cy -= 19), buttonWidth, 19,
+ &dmd->map_object,
+ "Object to get texture coordinates from");
+ }
+ } else if (md->type==eModifierType_UVProject) {
+ UVProjectModifierData *umd = (UVProjectModifierData *) md;
+ int i;
+ char *strtmp;
+ CustomData *fdata = G.obedit ? &G.editMesh->fdata
+ : &((Mesh*)ob->data)->fdata;
+ build_uvlayer_menu_vars(fdata, &strtmp, &umd->uvlayer_tmp,
+ umd->uvlayer_name);
+ but = uiDefButI(block, MENU, B_MODIFIER_RECALC, strtmp,
+ lx, (cy -= 19), buttonWidth, 19, &umd->uvlayer_tmp,
+ 0.0, 1.0, 0, 0, "Set the UV layer to use");
+ i = CustomData_get_layer_index(fdata, CD_MTFACE);
+ uiButSetFunc(but, set_uvproject_uvlayer, umd, &fdata->layers[i]);
+ MEM_freeN(strtmp);
+ uiDefButF(block, NUM, B_MODIFIER_RECALC, "AspX:",
+ lx, (cy -= 19), buttonWidth / 2, 19, &umd->aspectx,
+ 1, 1000, 100, 2,
+ "Horizontal Aspect Ratio");
+ uiDefButF(block, NUM, B_MODIFIER_RECALC, "AspY:",
+ lx + (buttonWidth / 2) + 1, cy, buttonWidth / 2, 19,
+ &umd->aspecty,
+ 1, 1000, 100, 2,
+ "Vertical Aspect Ratio");
+ uiDefButI(block, NUM, B_MODIFIER_RECALC, "Projectors:",
+ lx, (cy -= 19), buttonWidth, 19, &umd->num_projectors,
+ 1, MOD_UVPROJECT_MAXPROJECTORS, 0, 0,
+ "Number of objects to use as projectors");
+ for(i = 0; i < umd->num_projectors; ++i) {
+ uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CHANGEDEP,
+ "Ob: ", lx, (cy -= 19), buttonWidth, 19,
+ &umd->projectors[i],
+ "Object to use as projector");
+ }
+ uiDefIDPoinBut(block, modifier_testImage, ID_IM, B_CHANGEDEP,
+ "Image: ", lx, (cy -= 19), buttonWidth, 19,
+ &umd->image,
+ "Image to project (only faces with this image "
+ "will be altered");
+ uiButSetCompleteFunc(but, autocomplete_image, (void *)ob);
+ uiDefButBitI(block, TOG, MOD_UVPROJECT_OVERRIDEIMAGE,
+ B_MODIFIER_RECALC, "Override Image",
+ lx, (cy -= 19), buttonWidth, 19,
+ &umd->flags, 0, 0, 0, 0,
+ "Override faces' current images with the "
+ "given image");
+ } else if (md->type==eModifierType_Decimate) {
+ DecimateModifierData *dmd = (DecimateModifierData*) md;
+ uiDefButF(block, NUM, B_MODIFIER_RECALC, "Ratio:", lx,(cy-=19),buttonWidth,19, &dmd->percent, 0.0, 1.0, 10, 0, "Defines the percentage of triangles to reduce to");
+ sprintf(str, "Face Count: %d", dmd->faceCount);
+ uiDefBut(block, LABEL, 1, str, lx, (cy-=19), 160,19, NULL, 0.0, 0.0, 0, 0, "Displays the current number of faces in the decimated mesh");
+ } else if (md->type==eModifierType_Smooth) {
+ SmoothModifierData *smd = (SmoothModifierData*) md;
+
+ uiDefButBitS(block, TOG, MOD_SMOOTH_X, B_MODIFIER_RECALC, "X", lx,(cy-=19),45,19, &smd->flag, 0, 0, 0, 0, "Enable X axis smoothing");
+ uiDefButBitS(block, TOG, MOD_SMOOTH_Y, B_MODIFIER_RECALC, "Y", lx+45,cy,45,19, &smd->flag, 0, 0, 0, 0, "Enable Y axis smoothing");
+ uiDefButBitS(block, TOG, MOD_SMOOTH_Z, B_MODIFIER_RECALC, "Z", lx+90,cy,45,19, &smd->flag, 0, 0, 0, 0, "Enable Z axis smoothing");
+
+ uiDefButF(block, NUM, B_MODIFIER_RECALC, "Factor:", lx,(cy-=19),buttonWidth, 19, &smd->fac, -10.0, 10.0, 0.5, 0, "Define the amount of smoothing, from 0.0 to 1.0 (lower / higher values can deform the mesh)");
+ uiDefButS(block, NUM, B_MODIFIER_RECALC, "Repeat:", lx,(cy-=19),buttonWidth, 19, &smd->repeat, 0.0, 30.0, 1, 0, "Number of smoothing iterations");
+ but=uiDefBut(block, TEX, B_MODIFIER_RECALC, "VGroup: ", lx, (cy-=19), buttonWidth,19, &smd->defgrp_name, 0.0, 31.0, 0, 0, "Vertex Group name to define which vertices are affected");
+ } else if (md->type==eModifierType_Cast) {
+ CastModifierData *cmd = (CastModifierData*) md;
+
+ char casttypemenu[]="Projection Type%t|Sphere%x0|Cylinder%x1|Cuboid%x2";
+ uiDefButS(block, MENU, B_MODIFIER_RECALC, casttypemenu, lx,(cy-=19),buttonWidth - 30,19, &cmd->type, 0, 0, 0, 0, "Projection type to apply");
+ uiDefButBitS(block, TOG, MOD_CAST_X, B_MODIFIER_RECALC, "X", lx,(cy-=19),45,19, &cmd->flag, 0, 0, 0, 0, "Enable (local) X axis deformation");
+ uiDefButBitS(block, TOG, MOD_CAST_Y, B_MODIFIER_RECALC, "Y", lx+45,cy,45,19, &cmd->flag, 0, 0, 0, 0, "Enable (local) Y axis deformation");
+ if (cmd->type != MOD_CAST_TYPE_CYLINDER) {
+ uiDefButBitS(block, TOG, MOD_CAST_Z, B_MODIFIER_RECALC, "Z", lx+90,cy,45,19, &cmd->flag, 0, 0, 0, 0, "Enable (local) Z axis deformation");
+ }
+ uiDefButF(block, NUM, B_MODIFIER_RECALC, "Factor:", lx,(cy-=19),buttonWidth, 19, &cmd->fac, -10.0, 10.0, 5, 0, "Define the amount of deformation");
+ uiDefButF(block, NUM, B_MODIFIER_RECALC, "Radius:", lx,(cy-=19),buttonWidth, 19, &cmd->radius, 0.0, 100.0, 10.0, 0, "Only deform vertices within this distance from the center of the effect (leave as 0 for infinite)");
+ uiDefButF(block, NUM, B_MODIFIER_RECALC, "Size:", lx,(cy-=19),buttonWidth, 19, &cmd->size, 0.0, 100.0, 10.0, 0, "Size of projection shape (leave as 0 for auto)");
+ uiDefButBitS(block, TOG, MOD_CAST_SIZE_FROM_RADIUS, B_MODIFIER_RECALC, "From radius", lx+buttonWidth,cy,80,19, &cmd->flag, 0, 0, 0, 0, "Use radius as size of projection shape (0 = auto)");
+ if (ob->type == OB_MESH) {
+ but=uiDefBut(block, TEX, B_MODIFIER_RECALC, "VGroup: ", lx, (cy-=19), buttonWidth,19, &cmd->defgrp_name, 0.0, 31.0, 0, 0, "Vertex Group name to define which vertices are affected");
+ }
+ uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CHANGEDEP, "Ob: ", lx,(cy-=19), buttonWidth,19, &cmd->object, "Control object: if available, its location determines the center of the effect");
+ if(cmd->object) {
+ uiDefButBitS(block, TOG, MOD_CAST_USE_OB_TRANSFORM, B_MODIFIER_RECALC, "Use transform", lx+buttonWidth,cy,80,19, &cmd->flag, 0, 0, 0, 0, "Use object transform to control projection shape");
+ }
+ } else if (md->type==eModifierType_Wave) {
+ WaveModifierData *wmd = (WaveModifierData*) md;
+ uiDefButBitS(block, TOG, MOD_WAVE_X, B_MODIFIER_RECALC, "X", lx,(cy-=19),45,19, &wmd->flag, 0, 0, 0, 0, "Enable X axis motion");
+ uiDefButBitS(block, TOG, MOD_WAVE_Y, B_MODIFIER_RECALC, "Y", lx+45,cy,45,19, &wmd->flag, 0, 0, 0, 0, "Enable Y axis motion");
+ uiDefButBitS(block, TOG, MOD_WAVE_CYCL, B_MODIFIER_RECALC, "Cycl", lx+90,cy,buttonWidth-90,19, &wmd->flag, 0, 0, 0, 0, "Enable cyclic wave effect");
+ uiDefButBitS(block, TOG, MOD_WAVE_NORM, B_MODIFIER_RECALC, "Normals", lx,(cy-=19),buttonWidth,19, &wmd->flag, 0, 0, 0, 0, "Displace along normals");
+ if (wmd->flag & MOD_WAVE_NORM){
+ if (ob->type==OB_MESH) {
+ uiDefButBitS(block, TOG, MOD_WAVE_NORM_X, B_MODIFIER_RECALC, "X", lx,(cy-=19),buttonWidth/3,19, &wmd->flag, 0, 0, 0, 0, "Enable displacement along the X normal");
+ uiDefButBitS(block, TOG, MOD_WAVE_NORM_Y, B_MODIFIER_RECALC, "Y", lx+(buttonWidth/3),cy,buttonWidth/3,19, &wmd->flag, 0, 0, 0, 0, "Enable displacement along the Y normal");
+ uiDefButBitS(block, TOG, MOD_WAVE_NORM_Z, B_MODIFIER_RECALC, "Z", lx+(buttonWidth/3)*2,cy,buttonWidth/3,19, &wmd->flag, 0, 0, 0, 0, "Enable displacement along the Z normal");
+ }
+ else
+ uiDefBut(block, LABEL, 1, "Meshes Only", lx, (cy-=19), buttonWidth,19, NULL, 0.0, 0.0, 0, 0, "");
+ }
+
+ uiBlockBeginAlign(block);
+ if(wmd->speed >= 0)
+ uiDefButF(block, NUM, B_MODIFIER_RECALC, "Time sta:", lx,(cy-=19),buttonWidth,19, &wmd->timeoffs, -MAXFRAMEF, MAXFRAMEF, 100, 0, "Specify starting frame of the wave");
+ else
+ uiDefButF(block, NUM, B_MODIFIER_RECALC, "Time end:", lx,(cy-=19),buttonWidth,19, &wmd->timeoffs, -MAXFRAMEF, MAXFRAMEF, 100, 0, "Specify ending frame of the wave");
+ uiDefButF(block, NUM, B_MODIFIER_RECALC, "Lifetime:", lx,(cy-=19),buttonWidth,19, &wmd->lifetime, -MAXFRAMEF, MAXFRAMEF, 100, 0, "Specify the lifespan of the wave");
+ uiDefButF(block, NUM, B_MODIFIER_RECALC, "Damptime:", lx,(cy-=19),buttonWidth,19, &wmd->damp, -MAXFRAMEF, MAXFRAMEF, 100, 0, "Specify the dampingtime of the wave");
+ cy -= 9;
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_MODIFIER_RECALC, "Sta x:", lx,(cy-=19),113,19, &wmd->startx, -100.0, 100.0, 100, 0, "Starting position for the X axis");
+ uiDefButF(block, NUM, B_MODIFIER_RECALC, "Sta y:", lx+115,cy,105,19, &wmd->starty, -100.0, 100.0, 100, 0, "Starting position for the Y axis");
+ uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_MODIFIER_RECALC, "Ob: ", lx, (cy-=19), 220,19, &wmd->objectcenter, "Object to use as Starting Position (leave blank to disable)");
+ uiDefBut(block, TEX, B_MODIFIER_RECALC, "VGroup: ",lx, (cy -= 19), 220, 19,&wmd->defgrp_name, 0.0, 31.0, 0, 0, "Name of vertex group with which to modulate displacement");
+ uiDefIDPoinBut(block, modifier_testTexture, ID_TE, B_CHANGEDEP,"Texture: ", lx, (cy -= 19), 220, 19, &wmd->texture,"Texture with which to modulate wave");
+ sprintf(str, "Texture Coordinates%%t"
+ "|Local%%x%d|Global%%x%d|Object%%x%d|UV%%x%d",
+ MOD_WAV_MAP_LOCAL, MOD_WAV_MAP_GLOBAL,
+ MOD_WAV_MAP_OBJECT, MOD_WAV_MAP_UV);
+ uiDefButI(block, MENU, B_MODIFIER_RECALC, str,
+ lx, (cy -= 19), 220, 19, &wmd->texmapping,
+ 0.0, 1.0, 0, 0,
+ "Texture coordinates used for modulation input");
+ if (wmd->texmapping == MOD_WAV_MAP_UV) {
+ char *strtmp;
+ int i;
+ CustomData *fdata = G.obedit ? &G.editMesh->fdata
+ : &((Mesh*)ob->data)->fdata;
+ build_uvlayer_menu_vars(fdata, &strtmp, &wmd->uvlayer_tmp,
+ wmd->uvlayer_name);
+ but = uiDefButI(block, MENU, B_MODIFIER_RECALC, strtmp,
+ lx, (cy -= 19), 220, 19, &wmd->uvlayer_tmp,
+ 0.0, 1.0, 0, 0, "Set the UV layer to use");
+ MEM_freeN(strtmp);
+ i = CustomData_get_layer_index(fdata, CD_MTFACE);
+ uiButSetFunc(but, set_displace_uvlayer, wmd,
+ &fdata->layers[i]);
+ }
+ if(wmd->texmapping == MOD_DISP_MAP_OBJECT) {
+ uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CHANGEDEP,
+ "Ob: ", lx, (cy -= 19), 220, 19,
+ &wmd->map_object,
+ "Object to get texture coordinates from");
+ }
+ cy -= 9;
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUMSLI, B_MODIFIER_RECALC, "Speed:", lx,(cy-=19),220,19, &wmd->speed, -2.0, 2.0, 0, 0, "Specify the wave speed");
+ uiDefButF(block, NUMSLI, B_MODIFIER_RECALC, "Height:", lx,(cy-=19),220,19, &wmd->height, -2.0, 2.0, 0, 0, "Specify the amplitude of the wave");
+ uiDefButF(block, NUMSLI, B_MODIFIER_RECALC, "Width:", lx,(cy-=19),220,19, &wmd->width, 0.0, 5.0, 0, 0, "Specify the width of the wave");
+ uiDefButF(block, NUMSLI, B_MODIFIER_RECALC, "Narrow:", lx,(cy-=19),220,19, &wmd->narrow, 0.0, 10.0, 0, 0, "Specify how narrow the wave follows");
+ } else if (md->type==eModifierType_Armature) {
+ ArmatureModifierData *amd = (ArmatureModifierData*) md;
+ uiDefIDPoinBut(block, modifier_testArmatureObj, ID_OB, B_CHANGEDEP, "Ob: ", lx, (cy-=19), buttonWidth,19, &amd->object, "Armature object to deform with");
+
+ but=uiDefBut(block, TEX, B_MODIFIER_RECALC, "VGroup: ", lx, (cy-=19), buttonWidth,19, &amd->defgrp_name, 0.0, 31.0, 0, 0, "Vertex Group name to control overall armature influence");
+ uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)ob);
+ uiDefButBitS(block, TOG, ARM_DEF_VGROUP, B_ARM_RECALCDATA, "Vert.Groups", lx,cy-=19,buttonWidth/2,20, &amd->deformflag, 0, 0, 0, 0, "Enable VertexGroups defining deform");
+ uiDefButBitS(block, TOG, ARM_DEF_ENVELOPE, B_ARM_RECALCDATA, "Envelopes", lx+buttonWidth/2,cy,(buttonWidth + 1)/2,20, &amd->deformflag, 0, 0, 0, 0, "Enable Bone Envelopes defining deform");
+ uiDefButBitS(block, TOG, ARM_DEF_QUATERNION, B_ARM_RECALCDATA, "Quaternion", lx,(cy-=19),buttonWidth/2,20, &amd->deformflag, 0, 0, 0, 0, "Enable deform rotation interpolation with Quaternions");
+ uiDefButBitS(block, TOG, ARM_DEF_B_BONE_REST, B_ARM_RECALCDATA, "B-Bone Rest", lx+buttonWidth/2,cy,(buttonWidth + 1)/2,20, &amd->deformflag, 0, 0, 0, 0, "Make B-Bones deform already in rest position");
+ } else if (md->type==eModifierType_Hook) {
+ HookModifierData *hmd = (HookModifierData*) md;
+ uiDefButF(block, NUM, B_MODIFIER_RECALC, "Falloff: ", lx, (cy-=19), buttonWidth,19, &hmd->falloff, 0.0, 100.0, 100, 0, "If not zero, the distance from hook where influence ends");
+ uiDefButF(block, NUMSLI, B_MODIFIER_RECALC, "Force: ", lx, (cy-=19), buttonWidth,19, &hmd->force, 0.0, 1.0, 100, 0, "Set relative force of hook");
+ uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CHANGEDEP, "Ob: ", lx, (cy-=19), buttonWidth,19, &hmd->object, "Parent Object for hook, also recalculates and clears offset");
+ if(hmd->indexar==NULL) {
+ but=uiDefBut(block, TEX, B_MODIFIER_RECALC, "VGroup: ", lx, (cy-=19), buttonWidth,19, &hmd->name, 0.0, 31.0, 0, 0, "Vertex Group name");
+ uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)ob);
+ }
+ uiBlockBeginAlign(block);
+ but = uiDefBut(block, BUT, B_MODIFIER_RECALC, "Reset", lx, (cy-=19), 80,19, NULL, 0.0, 0.0, 0, 0, "Recalculate and clear offset (transform) of hook");
+ uiButSetFunc(but, modifiers_clearHookOffset, ob, md);
+ but = uiDefBut(block, BUT, B_MODIFIER_RECALC, "Recenter", lx+80, cy, buttonWidth-80,19, NULL, 0.0, 0.0, 0, 0, "Sets hook center to cursor position");
+ uiButSetFunc(but, modifiers_cursorHookCenter, ob, md);
+
+ if (editing) {
+ but = uiDefBut(block, BUT, B_MODIFIER_RECALC, "Select", lx, (cy-=19), 80,19, NULL, 0.0, 0.0, 0, 0, "Selects effected vertices on mesh");
+ uiButSetFunc(but, modifiers_selectHook, ob, md);
+ but = uiDefBut(block, BUT, B_MODIFIER_RECALC, "Reassign", lx+80, cy, buttonWidth-80,19, NULL, 0.0, 0.0, 0, 0, "Reassigns selected vertices to hook");
+ uiButSetFunc(but, modifiers_reassignHook, ob, md);
+ }
+ } else if (md->type==eModifierType_Softbody) {
+ uiDefBut(block, LABEL, 1, "See Softbody panel.", lx, (cy-=19), buttonWidth,19, NULL, 0.0, 0.0, 0, 0, "");
+ } else if (md->type==eModifierType_Boolean) {
+ BooleanModifierData *bmd = (BooleanModifierData*) md;
+ uiDefButI(block, MENU, B_MODIFIER_RECALC, "Operation%t|Intersect%x0|Union%x1|Difference%x2", lx,(cy-=19),buttonWidth,19, &bmd->operation, 0.0, 1.0, 0, 0, "Boolean operation to perform");
+ uiDefIDPoinBut(block, modifier_testMeshObj, ID_OB, B_CHANGEDEP, "Ob: ", lx, (cy-=19), buttonWidth,19, &bmd->object, "Mesh object to use for boolean operation");
+ } else if (md->type==eModifierType_Array) {
+ ArrayModifierData *amd = (ArrayModifierData*) md;
+ float range = 10000;
+ int cytop, halfwidth = (width - 5)/2 - 15;
+ int halflx = lx + halfwidth + 10;
+
+ uiBlockSetEmboss(block, UI_EMBOSSX);
+ uiBlockEndAlign(block);
+
+ /* length parameters */
+ uiBlockBeginAlign(block);
+ sprintf(str, "Length Fit%%t|Fixed Count%%x%d|Fixed Length%%x%d"
+ "|Fit To Curve Length%%x%d",
+ MOD_ARR_FIXEDCOUNT, MOD_ARR_FITLENGTH, MOD_ARR_FITCURVE);
+ uiDefButI(block, MENU, B_MODIFIER_RECALC, str,
+ lx, (cy-=19), buttonWidth, 19, &amd->fit_type,
+ 0.0, 1.0, 0, 0, "Array length calculation method");
+ switch(amd->fit_type)
+ {
+ case MOD_ARR_FIXEDCOUNT:
+ uiDefButI(block, NUM, B_MODIFIER_RECALC, "Count:",
+ lx, (cy -= 19), buttonWidth, 19, &amd->count,
+ 1, 1000, 0, 0, "Number of duplicates to make");
+ break;
+ case MOD_ARR_FITLENGTH:
+ uiDefButF(block, NUM, B_MODIFIER_RECALC, "Length:",
+ lx, (cy -= 19), buttonWidth, 19, &amd->length,
+ 0, range, 10, 2,
+ "Length to fit array within");
+ break;
+ case MOD_ARR_FITCURVE:
+ uiDefIDPoinBut(block, modifier_testCurveObj, ID_OB,
+ B_CHANGEDEP, "Ob: ",
+ lx, (cy -= 19), buttonWidth, 19, &amd->curve_ob,
+ "Curve object to fit array length to");
+ break;
+ }
+ uiBlockEndAlign(block);
+
+ /* offset parameters */
+ cy -= 10;
+ cytop= cy;
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOG, MOD_ARR_OFF_CONST, B_MODIFIER_RECALC,
+ "Constant Offset", lx, (cy-=19), halfwidth, 19,
+ &amd->offset_type, 0, 0, 0, 0,
+ "Constant offset between duplicates "
+ "(local coordinates)");
+ uiDefButF(block, NUM, B_MODIFIER_RECALC, "X:",
+ lx, (cy-=19), halfwidth, 19,
+ &amd->offset[0],
+ -range, range, 10, 3,
+ "Constant component for duplicate offsets "
+ "(local coordinates)");
+ uiDefButF(block, NUM, B_MODIFIER_RECALC, "Y:",
+ lx, (cy-=19), halfwidth, 19,
+ &amd->offset[1],
+ -range, range, 10, 3,
+ "Constant component for duplicate offsets "
+ "(local coordinates)");
+ uiDefButF(block, NUM, B_MODIFIER_RECALC, "Z:",
+ lx, (cy-=19), halfwidth, 19,
+ &amd->offset[2],
+ -range, range, 10, 3,
+ "Constant component for duplicate offsets "
+ "(local coordinates)");
+ uiBlockEndAlign(block);
+
+ cy= cytop;
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOG, MOD_ARR_OFF_RELATIVE, B_MODIFIER_RECALC,
+ "Relative Offset", halflx, (cy-=19), halfwidth, 19,
+ &amd->offset_type, 0, 0, 0, 0,
+ "Offset between duplicates relative to object width "
+ "(local coordinates)");
+ uiDefButF(block, NUM, B_MODIFIER_RECALC, "X:",
+ halflx, (cy-=19), halfwidth, 19,
+ &amd->scale[0],
+ -range, range, 10, 3,
+ "Component for duplicate offsets relative to object "
+ "width (local coordinates)");
+ uiDefButF(block, NUM, B_MODIFIER_RECALC, "Y:",
+ halflx, (cy-=19), halfwidth, 19,
+ &amd->scale[1],
+ -range, range, 10, 3,
+ "Component for duplicate offsets relative to object "
+ "width (local coordinates)");
+ uiDefButF(block, NUM, B_MODIFIER_RECALC, "Z:",
+ halflx, (cy-=19), halfwidth, 19,
+ &amd->scale[2],
+ -range, range, 10, 3,
+ "Component for duplicate offsets relative to object "
+ "width (local coordinates)");
+ uiBlockEndAlign(block);
+
+ /* vertex merging parameters */
+ cy -= 10;
+ cytop= cy;
+
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOG, MOD_ARR_MERGE, B_MODIFIER_RECALC,
+ "Merge",
+ lx, (cy-=19), halfwidth/2, 19, &amd->flags,
+ 0, 0, 0, 0,
+ "Merge vertices in adjacent duplicates");
+ uiDefButBitI(block, TOG, MOD_ARR_MERGEFINAL, B_MODIFIER_RECALC,
+ "First Last",
+ lx + halfwidth/2, cy, (halfwidth+1)/2, 19,
+ &amd->flags,
+ 0, 0, 0, 0,
+ "Merge vertices in first duplicate with vertices"
+ " in last duplicate");
+ uiDefButF(block, NUM, B_MODIFIER_RECALC, "Limit:",
+ lx, (cy-=19), halfwidth, 19, &amd->merge_dist,
+ 0, 1.0f, 1, 4,
+ "Limit below which to merge vertices");
+
+ /* offset ob */
+ cy = cytop;
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOG, MOD_ARR_OFF_OBJ, B_MODIFIER_RECALC,
+ "Object Offset", halflx, (cy -= 19), halfwidth, 19,
+ &amd->offset_type, 0, 0, 0, 0,
+ "Add an object transformation to the total offset");
+ uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CHANGEDEP,
+ "Ob: ", halflx, (cy -= 19), halfwidth, 19,
+ &amd->offset_ob,
+ "Object from which to take offset transformation");
+ uiBlockEndAlign(block);
+
+ cy -= 10;
+ but = uiDefIDPoinBut(block, test_meshobpoin_but, ID_OB,
+ B_CHANGEDEP, "Start cap: ",
+ lx, (cy -= 19), halfwidth, 19,
+ &amd->start_cap,
+ "Mesh object to use as start cap");
+ uiButSetCompleteFunc(but, autocomplete_meshob, (void *)ob);
+ but = uiDefIDPoinBut(block, test_meshobpoin_but, ID_OB,
+ B_CHANGEDEP, "End cap: ",
+ halflx, cy, halfwidth, 19,
+ &amd->end_cap,
+ "Mesh object to use as end cap");
+ uiButSetCompleteFunc(but, autocomplete_meshob, (void *)ob);
+ } else if (md->type==eModifierType_MeshDeform) {
+ MeshDeformModifierData *mmd = (MeshDeformModifierData*) md;
+
+ uiBlockBeginAlign(block);
+ uiDefIDPoinBut(block, test_meshobpoin_but, ID_OB, B_CHANGEDEP, "Ob: ", lx, (cy-=19), buttonWidth,19, &mmd->object, "Mesh object to be use as cage");
+ but=uiDefBut(block, TEX, B_MODIFIER_RECALC, "VGroup: ", lx, (cy-19), buttonWidth-40,19, &mmd->defgrp_name, 0.0, 31.0, 0, 0, "Vertex Group name to control overall meshdeform influence");
+ uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)ob);
+ uiDefButBitS(block, TOG, MOD_MDEF_INVERT_VGROUP, B_MODIFIER_RECALC, "Inv", lx+buttonWidth-40, (cy-=19), 40,19, &mmd->flag, 0.0, 31.0, 0, 0, "Invert vertex group influence");
+
+ uiBlockBeginAlign(block);
+ if(mmd->bindweights) {
+ but= uiDefBut(block, BUT, B_MODIFIER_RECALC, "Unbind", lx,(cy-24), buttonWidth,19, 0, 0, 0, 0, 0, "Unbind mesh from cage");
+ uiButSetFunc(but,modifiers_bindMeshDeform,ob,md);
+ }
+ else {
+ but= uiDefBut(block, BUT, B_MODIFIER_RECALC, "Bind", lx,(cy-24), buttonWidth/2,19, 0, 0, 0, 0, 0, "Bind mesh to cage");
+ uiButSetFunc(but,modifiers_bindMeshDeform,ob,md);
+ uiDefButS(block, NUM, B_NOP, "Precision:", lx+(buttonWidth+1)/2,(cy-=24), buttonWidth/2,19, &mmd->gridsize, 2, 10, 0.5, 0, "The grid size for binding");
+ }
+ uiBlockEndAlign(block);
+ }
+
+ uiBlockEndAlign(block);
+
+ y-=height;
+ }
+
+ if (md->error) {
+ char str[512];
+
+ y -= 20;
+
+ uiBlockSetCol(block, color);
+ /* roundbox 4 free variables: corner-rounding, nop, roundbox type, shade */
+ uiDefBut(block, ROUNDBOX, 0, "", x-10, y, width, 20, NULL, 5.0, 0.0, 15, 40, "");
+ uiBlockSetCol(block, TH_AUTO);
+
+ sprintf(str, "Modifier Error: %s", md->error);
+ uiDefBut(block, LABEL, B_NOP, str, x+15, y+15, width-35, 19, NULL, 0.0, 0.0, 0.0, 0.0, "");
+ }
+
+ y -= 3+6;
+
+ *xco = x;
+ *yco = y;
+}
+
+static void editing_panel_modifiers(Object *ob)
+{
+ ModifierData *md;
+ uiBlock *block;
+ char str[64];
+ int xco, yco, i, lastCageIndex, cageIndex = modifiers_getCageIndex(ob, &lastCageIndex);
+
+ block= uiNewBlock(&curarea->uiblocks, "editing_panel_modifiers", UI_EMBOSS, UI_HELV, curarea->win);
+ if( uiNewPanel(curarea, block, "Modifiers", "Editing", 640, 0, 318, 204)==0) return;
+
+ uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
+ uiNewPanelHeight(block, 204);
+
+ uiDefBlockBut(block, modifiers_add_menu, ob, "Add Modifier", 0, 190, 130, 20, "Add a new modifier");
+
+ sprintf(str, "To: %s", ob->id.name+2);
+ uiDefBut(block, LABEL, 1, str, 140, 190, 150, 20, NULL, 0.0, 0.0, 0, 0, "Object whose modifier stack is being edited");
+
+ xco = 0;
+ yco = 160;
+
+ md = modifiers_getVirtualModifierList(ob);
+
+ for (i=0; md; i++, md=md->next) {
+ draw_modifier(block, ob, md, &xco, &yco, i, cageIndex, lastCageIndex);
+ if (md->mode&eModifierMode_Virtual) i--;
+ }
+
+ if(yco < 0) uiNewPanelHeight(block, 204-yco);
+}
+
+static char *make_key_menu(Key *key)
+{
+ KeyBlock *kb;
+ int index= 1;
+ char *str, item[64];
+
+ for (kb = key->block.first; kb; kb=kb->next, index++);
+ str= MEM_mallocN(index*40, "key string");
+ str[0]= 0;
+
+ index= 1;
+ for (kb = key->block.first; kb; kb=kb->next, index++) {
+ sprintf (item, "|%s%%x%d", kb->name, index);
+ strcat(str, item);
+ }
+
+ return str;
+}
+
+static void editing_panel_shapes(Object *ob)
+{
+ uiBlock *block;
+ Key *key= NULL;
+ KeyBlock *kb;
+ int icon;
+ char *strp;
+
+ block= uiNewBlock(&curarea->uiblocks, "editing_panel_shapes", UI_EMBOSS, UI_HELV, curarea->win);
+ uiNewPanelTabbed("Modifiers", "Editing");
+ if( uiNewPanel(curarea, block, "Shapes", "Editing", 640, 0, 318, 204)==0) return;
+
+ /* Todo check data is library here */
+ uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
+
+ uiDefBut(block, BUT, B_ADDKEY, "Add Shape Key" , 10, 180, 150, 20, NULL, 0.0, 0.0, 0, 0, "Add new Shape Key");
+
+ key= ob_get_key(ob);
+ if(key==NULL) {
+ /* label aligns add button */
+ uiDefBut(block, LABEL, 0, "", 170, 180,140,20, NULL, 0, 0, 0, 0, "");
+ return;
+ }
+
+ uiDefButS(block, TOG, B_RELKEY, "Relative", 170, 180,140,20, &key->type, 0, 0, 0, 0, "Makes Shape Keys relative");
+
+ kb= BLI_findlink(&key->block, ob->shapenr-1);
+ if(kb==NULL) {
+ ob->shapenr= 1;
+ kb= key->block.first;
+ }
+
+ uiBlockBeginAlign(block);
+ if(ob->shapeflag & OB_SHAPE_LOCK) icon= ICON_PIN_HLT; else icon= ICON_PIN_DEHLT;
+ uiDefIconButBitS(block, TOG, OB_SHAPE_LOCK, B_LOCKKEY, icon, 10,150,25,20, &ob->shapeflag, 0, 0, 0, 0, "Always show the current Shape for this Object");
+ uiSetButLock(G.obedit==ob, "Unable to perform in EditMode");
+ uiDefIconBut(block, BUT, B_PREVKEY, ICON_TRIA_LEFT, 35,150,20,20, NULL, 0, 0, 0, 0, "Previous Shape Key");
+ strp= make_key_menu(key);
+ uiDefButS(block, MENU, B_SETKEY, strp, 55,150,20,20, &ob->shapenr, 0, 0, 0, 0, "Browses existing choices or adds NEW");
+ MEM_freeN(strp);
+ uiDefIconBut(block, BUT, B_NEXTKEY, ICON_TRIA_RIGHT, 75,150,20,20, NULL, 0, 0, 0, 0, "Next Shape Key");
+ uiClearButLock();
+ uiDefBut(block, TEX, B_NAMEKEY, "", 95, 150, 190, 20, kb->name, 0.0, 31.0, 0, 0, "Current Shape Key name");
+ uiDefIconBut(block, BUT, B_DELKEY, ICON_X, 285,150,25,20, 0, 0, 0, 0, 0, "Deletes current Shape Key");
+ uiBlockEndAlign(block);
+
+ if(key->type && (ob->shapeflag & OB_SHAPE_LOCK)==0 && ob->shapenr!=1) {
+ uiBlockBeginAlign(block);
+ make_rvk_slider(block, ob, ob->shapenr-1, 10, 120, 150, 20, "Key value, when used it inserts an animation curve point");
+ uiDefButF(block, NUM, B_REDR, "Min ", 160,120, 75, 20, &kb->slidermin, -10.0, 10.0, 100, 1, "Minumum for slider");
+ uiDefButF(block, NUM, B_REDR, "Max ", 235,120, 75, 20, &kb->slidermax, -10.0, 10.0, 100, 1, "Maximum for slider");
+ uiBlockEndAlign(block);
+ }
+ if(key->type && ob->shapenr!=1)
+ uiDefBut(block, TEX, B_MODIFIER_RECALC, "VGroup: ", 10, 90, 150,19, &kb->vgroup, 0.0, 31.0, 0, 0, "Vertex Weight Group name, to blend with Basis Shape");
+
+ if(key->type==0)
+ uiDefButS(block, NUM, B_DIFF, "Slurph:", 10, 60, 150, 19, &(key->slurph), -500.0, 500.0, 0, 0, "Creates a delay in amount of frames in applying keypositions, first vertex goes first");
+
+}
+
+/* *************************** FONT ******************************** */
+
+static short give_vfontnr(VFont *vfont)
+{
+ VFont *vf;
+ short nr= 1;
+
+ vf= G.main->vfont.first;
+ while(vf) {
+ if(vf==vfont) return nr;
+ nr++;
+ vf= vf->id.next;
+ }
+ return -1;
+}
+
+static VFont *give_vfontpointer(int nr) /* nr= button */
+{
+ VFont *vf;
+ short tel= 1;
+
+ vf= G.main->vfont.first;
+ while(vf) {
+ if(tel==nr) return vf;
+ tel++;
+ vf= vf->id.next;
+ }
+ return G.main->vfont.first;
+}
+
+VFont *exist_vfont(char *str)
+{
+ VFont *vf;
+
+ vf= G.main->vfont.first;
+ while(vf) {
+ if(strcmp(vf->name, str)==0) return vf;
+ vf= vf->id.next;
+ }
+ return 0;
+}
+
+static char *give_vfontbutstr(void)
+{
+ VFont *vf;
+ int len= 0;
+ char *str, di[FILE_MAXDIR], fi[FILE_MAXFILE];
+
+ vf= G.main->vfont.first;
+ while(vf) {
+ strcpy(di, vf->name);
+ BLI_splitdirstring(di, fi);
+ len+= strlen(fi)+4;
+ vf= vf->id.next;
+ }
+
+ str= MEM_callocN(len+21, "vfontbutstr");
+ strcpy(str, "FONTS %t");
+ vf= G.main->vfont.first;
+ while(vf) {
+
+ if(vf->id.us==0) strcat(str, "|0 ");
+ else strcat(str, "| ");
+
+ strcpy(di, vf->name);
+ BLI_splitdirstring(di, fi);
+
+ strcat(str, fi);
+ vf= vf->id.next;
+ }
+ return str;
+}
+
+static void load_buts_vfont(char *name)
+{
+ VFont *vf;
+ Curve *cu;
+
+ if(OBACT && OBACT->type==OB_FONT) cu= OBACT->data;
+ else return;
+
+ vf= exist_vfont(name);
+ if(vf==0) {
+ vf= load_vfont(name);
+ if(vf==0) return;
+ }
+ else id_us_plus((ID *)vf);
+
+ switch(cu->curinfo.flag & CU_STYLE) {
+ case CU_BOLD:
+ if(cu->vfontb) cu->vfontb->id.us--;
+ cu->vfontb= vf;
+ break;
+ case CU_ITALIC:
+ if(cu->vfonti) cu->vfonti->id.us--;
+ cu->vfonti= vf;
+ break;
+ case (CU_BOLD|CU_ITALIC):
+ if(cu->vfontbi) cu->vfontbi->id.us--;
+ cu->vfontbi= vf;
+ break;
+ default:
+ if(cu->vfont) cu->vfont->id.us--;
+ cu->vfont= vf;
+ break;
+ }
+
+ DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA);
+ BIF_undo_push("Load vector font");
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+}
+
+static void set_unicode_text_fs(char *file)
+{
+ if (file > 0) paste_unicodeText(file);
+}
+
+void do_fontbuts(unsigned short event)
+{
+ Curve *cu;
+ VFont *vf;
+ Object *ob;
+ ScrArea *sa;
+ char str[80];
+ int ctevt;
+ char *ctmenu;
+ DynStr *ds;
+ int i, style=0;
+
+ ob= OBACT;
+
+ switch(event) {
+ case B_MAKEFONT:
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+
+ case B_STYLETOSELU:
+ case B_STYLETOSELB:
+ case B_STYLETOSELI:
+ switch (event) {
+ case B_STYLETOSELU: style = CU_UNDERLINE; break;
+ case B_STYLETOSELB: style = CU_BOLD; break;
+ case B_STYLETOSELI: style = CU_ITALIC; break;
+ }
+ if (style_to_sel(style, ((Curve*)ob->data)->curinfo.flag & style)) {
+ text_to_curve(ob, 0);
+ makeDispListCurveTypes(ob, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ allqueue(REDRAWBUTSEDIT, 0);
+ break;
+
+ case B_FASTFONT:
+ if (G.obedit) {
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ break;
+ case B_INSTB:
+ cu= ob->data;
+ if (cu->totbox < 256) {
+ for (i = cu->totbox; i>cu->actbox; i--) cu->tb[i]= cu->tb[i-1];
+ cu->tb[cu->actbox]= cu->tb[cu->actbox-1];
+ cu->actbox++;
+ cu->totbox++;
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ text_to_curve(ob, 0);
+ makeDispListCurveTypes(ob, 0);
+ }
+ else {
+ error("Do you really need that many text frames?");
+ }
+ break;
+ case B_DELTB:
+ cu= ob->data;
+ if (cu->totbox > 1) {
+ for (i = cu->actbox-1; i < cu->totbox; i++) cu->tb[i]= cu->tb[i+1];
+ cu->totbox--;
+ cu->actbox--;
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ text_to_curve(ob, 0);
+ makeDispListCurveTypes(ob, 0);
+ }
+ break;
+ case B_TOUPPER:
+ to_upper();
+ break;
+ case B_LOADFONT:
+ vf= give_vfontpointer(G.buts->texnr);
+ if(vf && vf->id.prev!=vf->id.next) strcpy(str, vf->name);
+ else strcpy(str, U.fontdir);
+
+ sa= closest_bigger_area();
+ areawinset(sa->win);
+
+ activate_fileselect(FILE_LOADFONT, "SELECT FONT", str, load_buts_vfont);
+
+ break;
+ case B_PACKFONT:
+ if (ob) {
+ cu= ob->data;
+ if(cu && cu->vfont) {
+ if (cu->vfont->packedfile) {
+ if (G.fileflags & G_AUTOPACK) {
+ if (okee("Disable AutoPack ?")) {
+ G.fileflags &= ~G_AUTOPACK;
+ }
+ }
+
+ if ((G.fileflags & G_AUTOPACK) == 0) {
+ if (unpackVFont(cu->vfont, PF_ASK) == RET_OK) {
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ }
+ } else {
+ cu->vfont->packedfile = newPackedFile(cu->vfont->name);
+ }
+ }
+ }
+ allqueue(REDRAWHEADERS, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ break;
+
+ case B_LOAD3DTEXT:
+ if (!G.obedit) { error("Only in editmode!"); return; }
+ if (G.obedit->type != OB_FONT) return;
+ activate_fileselect(FILE_SPECIAL, "Open Text File", G.sce, load_3dtext_fs);
+ break;
+
+ case B_LOREM:
+ if (!G.obedit) { error("Only in editmode!"); return; }
+ if (G.obedit->type != OB_FONT) return;
+ add_lorem();
+
+ break;
+
+ case B_SETFONT:
+ if(ob) {
+ cu= ob->data;
+
+ vf= give_vfontpointer(G.buts->texnr);
+ if(vf) {
+ id_us_plus((ID *)vf);
+
+ switch(cu->curinfo.flag & CU_STYLE) {
+ case CU_BOLD:
+ cu->vfontb->id.us--;
+ cu->vfontb= vf;
+ break;
+ case CU_ITALIC:
+ cu->vfonti->id.us--;
+ cu->vfonti= vf;
+ break;
+ case (CU_BOLD|CU_ITALIC):
+ cu->vfontbi->id.us--;
+ cu->vfontbi= vf;
+ break;
+ default:
+ cu->vfont->id.us--;
+ cu->vfont= vf;
+ break;
+ }
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+
+ BIF_undo_push("Set vector font");
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ }
+ }
+ break;
+
+ case B_SETCHAR:
+ G.charmin = 0x0000;
+ G.charmax = 0xffff;
+ if(G.charstart < 0)
+ G.charstart = 0;
+ if(G.charstart > (0xffff - 12*6))
+ G.charstart = 0xffff - (12*6);
+ allqueue(REDRAWBUTSEDIT, 0);
+ break;
+
+ case B_SETUPCHAR:
+ G.charstart = G.charstart - (12*6);
+ if(G.charstart < 0)
+ G.charstart = 0;
+ if(G.charstart < G.charmin)
+ G.charstart = G.charmin;
+ allqueue(REDRAWBUTSEDIT, 0);
+ break;
+
+ case B_SETCAT:
+ // Create new dynamic string
+ ds = BLI_dynstr_new();
+
+ // Fill the dynamic string with entries
+ for(i=0;i<104;i++)
+ {
+ BLI_dynstr_append(ds, "|");
+ BLI_dynstr_append(ds, uctabname[i].name);
+ }
+
+ // Create the menu string from dyn string
+ ctmenu = BLI_dynstr_get_cstring(ds);
+
+ // Call the popup menu
+ ctevt = pupmenu_col(ctmenu, 40);
+ G.charstart = uctabname[ctevt-1].start;
+ G.charmin = uctabname[ctevt-1].start;
+ G.charmax = uctabname[ctevt-1].end;
+
+ // Free all data
+ BLI_dynstr_free(ds);
+ MEM_freeN(ctmenu);
+
+ // And refresh
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+
+ break;
+
+ case B_SETDOWNCHAR:
+ G.charstart = G.charstart + (12*6);
+ if(G.charstart > (0xffff - 12*6))
+ G.charstart = 0xffff - (12*6);
+ if(G.charstart > G.charmax - 12*6)
+ G.charstart = G.charmax - 12*6;
+ allqueue(REDRAWBUTSEDIT, 0);
+ break;
+
+ case B_SETUNITEXT:
+ sa= closest_bigger_area();
+ areawinset(sa->win);
+
+ if(ob==G.obedit) {
+ activate_fileselect(FILE_SPECIAL, "Open Text File", G.sce, set_unicode_text_fs);
+ }
+ break;
+
+ case B_TEXTONCURVE:
+ if(ob) {
+ cu= ob->data;
+ if(cu->textoncurve && cu->textoncurve->type!=OB_CURVE) {
+ error("Only Curve Objects");
+ cu->textoncurve= 0;
+ allqueue(REDRAWBUTSEDIT, 0);
+ }
+ DAG_scene_sort(G.scene); // makes new dag
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ }
+}
+
+#ifdef INTERNATIONAL
+static void editing_panel_char_type(Object *ob, Curve *cu)
+{
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "editing_panel_char_type", UI_EMBOSS, UI_HELV, curarea->win);
+ uiNewPanelTabbed("Font", "Editing");
+ if(uiNewPanel(curarea, block, "Char", "Editing", 640, 0, 318, 204)==0)
+ return;
+
+ // Set the selected font
+ G.selfont = cu->vfont;
+
+ uiDefIconBut(block, BUT, B_SETUNITEXT, ICON_TEXT, 0,210,20,20, 0, 0, 0, 0, 0, "Load Unicode Text file");
+
+ // Unicode categorization selection button
+ uiDefBut(block, BUT, B_SETCAT, "Unicode Table", 22,210,226,20, 0, 0, 0, 0, 0, "Select Unicode Table");
+ uiDefButI(block, NUM, /*B_SETUPCHAR*/ 0, "", 250,210,50,20, &G.charstart, 0, 0xffff, 0, 0, "UT");
+
+ // Character selection button
+ uiDefBut(block, CHARTAB, B_SETCHAR, "", 0, 0, 264, 200, 0, 0, 0, 0, 0, "Select character");
+
+ // Buttons to change the max, min
+ uiDefButI(block, BUT, B_SETUPCHAR, "U", 280, 185, 15, 15, &G.charstart, 0, 0xffff, 0, 0, "Scroll character table up");
+ uiDefButI(block, BUT, B_SETDOWNCHAR, "D", 280, 0, 15, 15, &G.charstart, 0, 0xffff, 0, 0, "Scroll character table down");
+}
+#endif
+
+static void editing_panel_font_type(Object *ob, Curve *cu)
+{
+ uiBlock *block;
+ char *strp;
+ static int packdummy = 0;
+ char str[32];
+
+ block= uiNewBlock(&curarea->uiblocks, "editing_panel_font_type", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Font", "Editing", 640, 0, 470, 204)==0) return;
+
+ switch(cu->curinfo.flag & CU_STYLE) {
+ case CU_BOLD:
+ G.buts->texnr= give_vfontnr(cu->vfontb);
+ break;
+ case CU_ITALIC:
+ G.buts->texnr= give_vfontnr(cu->vfonti);
+ break;
+ case (CU_BOLD|CU_ITALIC):
+ G.buts->texnr= give_vfontnr(cu->vfontbi);
+ break;
+ default:
+ G.buts->texnr= give_vfontnr(cu->vfont);
+ break;
+ }
+
+ strp= give_vfontbutstr();
+// vfd= cu->vfont->data;
+
+ uiDefBut(block, BUT,B_LOADFONT, "Load", 480,188,68,20, 0, 0, 0, 0, 0, "Load a new font");
+ uiDefButS(block, MENU, B_SETFONT, strp, 550,188,220,20, &G.buts->texnr, 0, 0, 0, 0, "Change font for object");
+
+ if (cu->vfont->packedfile) {
+ packdummy = 1;
+ } else {
+ packdummy = 0;
+ }
+ uiDefIconButI(block, TOG|BIT|0, B_PACKFONT, ICON_PACKAGE, 772,188,20,20, &packdummy, 0, 0, 0, 0, "Pack/Unpack this font");
+
+ /* This doesn't work anyway */
+// uiDefBut(block, LABEL, 0, vfd->name, 480, 165,314,20, 0, 0, 0, 0, 0, "Postscript name of the font");
+
+ uiDefBut(block, BUT, B_LOAD3DTEXT, "Insert Text", 480, 165, 90, 20, 0, 0, 0, 0, 0, "Insert text file at cursor");
+ uiDefBut(block, BUT, B_LOREM, "Lorem", 575, 165, 70, 20, 0, 0, 0, 0, 0, "Insert a paragraph of Lorem Ipsum at cursor");
+ uiDefButC(block, TOG|BIT|2,B_STYLETOSELU, "U", 727,165,20,20, &(cu->curinfo.flag), 0,0, 0, 0, "");
+ uiBlockBeginAlign(block);
+ uiDefButBitC(block, TOG, CU_BOLD, B_STYLETOSELB, "B", 752,165,20,20, &(cu->curinfo.flag), 0,0, 0, 0, "");
+ uiDefButBitC(block, TOG, CU_ITALIC, B_STYLETOSELI, "i", 772,165,20,20, &(cu->curinfo.flag), 0, 0, 0, 0, "");
+ uiBlockEndAlign(block);
+
+ MEM_freeN(strp);
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, ROW,B_MAKEFONT, "Left", 480,135,47,20, &cu->spacemode, 0.0,0.0, 0, 0, "Left align the text from the object center");
+ uiDefButS(block, ROW,B_MAKEFONT, "Center", 527,135,47,20, &cu->spacemode, 0.0,1.0, 0, 0, "Middle align the text from the object center");
+ uiDefButS(block, ROW,B_MAKEFONT, "Right", 574,135,47,20, &cu->spacemode, 0.0,2.0, 0, 0, "Right align the text from the object center");
+ uiDefButS(block, ROW,B_MAKEFONT, "Justify", 621,135,47,20, &cu->spacemode, 0.0,3.0, 0, 0, "Fill completed lines to maximum textframe width by expanding whitespace");
+ uiDefButS(block, ROW,B_MAKEFONT, "Flush", 668,135,47,20, &cu->spacemode, 0.0,4.0, 0, 0, "Fill every line to maximum textframe width, distributing space among all characters");
+ uiDefBut(block, BUT, B_TOUPPER, "ToUpper", 715,135,78,20, 0, 0, 0, 0, 0, "Toggle between upper and lower case in editmode");
+ uiBlockEndAlign(block);
+ uiDefButBitS(block, TOG, CU_FAST, B_FASTFONT, "Fast Edit", 715,105,78,20, &cu->flag, 0, 0, 0, 0, "Don't fill polygons while editing");
+
+ uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_TEXTONCURVE, "TextOnCurve:", 480,105,220,19, &cu->textoncurve, "Apply a deforming curve to the text");
+ uiDefBut(block, TEX,REDRAWVIEW3D, "Ob Family:", 480,84,220,19, cu->family, 0.0, 20.0, 0, 0, "Blender uses font from selfmade objects");
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM,B_MAKEFONT, "Size:", 480,56,155,20, &cu->fsize, 0.1,10.0, 10, 0, "Size of the text");
+ uiDefButF(block, NUM,B_MAKEFONT, "Linedist:", 640,56,155,20, &cu->linedist, 0.0,10.0, 10, 0, "Distance between text lines");
+ uiDefButF(block, NUM,B_MAKEFONT, "Word spacing:", 795,56,155,20, &cu->wordspace, 0.0,10.0, 10, 0, "Distance factor between words");
+ uiDefButF(block, NUM,B_MAKEFONT, "Spacing:", 480,34,155,20, &cu->spacing, 0.0,10.0, 10, 0, "Spacing of individual characters");
+ uiDefButF(block, NUM,B_MAKEFONT, "X offset:", 640,34,155,20, &cu->xof, -50.0,50.0, 10, 0, "Horizontal position from object center");
+ uiDefButF(block, NUM,B_MAKEFONT, "UL position:", 795,34,155,20, &cu->ulpos, -0.2,0.8, 10, 0, "Vertical position of underline");
+ uiDefButF(block, NUM,B_MAKEFONT, "Shear:", 480,12,155,20, &cu->shear, -1.0,1.0, 10, 0, "Italic angle of the characters");
+ uiDefButF(block, NUM,B_MAKEFONT, "Y offset:", 640,12,155,20, &cu->yof, -50.0,50.0, 10, 0, "Vertical position from object center");
+ uiDefButF(block, NUM,B_MAKEFONT, "UL height:", 795,12,155,20, &cu->ulheight, 0.01,0.5, 10, 0, "Thickness of underline");
+ uiBlockEndAlign(block);
+
+ sprintf(str, "%d TextFrame: ", cu->totbox);
+ uiBlockBeginAlign(block);
+ uiDefButI(block, NUM, REDRAWVIEW3D, str, 805, 188, 145, 20, &cu->actbox, 1.0, cu->totbox, 0, 10, "Textbox to show settings for");
+ uiDefBut(block, BUT,B_INSTB, "Insert", 805, 168, 72, 20, 0, 0, 0, 0, 0, "Insert a new text frame after the current one");
+ uiDefBut(block, BUT,B_DELTB, "Delete", 877, 168, 73, 20, 0, 0, 0, 0, 0, "Delete current text frame and shift the others up");
+ uiDefButF(block, NUM,B_MAKEFONT, "X:", 805, 148, 72, 20, &(cu->tb[cu->actbox-1].x), -50.0, 50.0, 10, 0, "Horizontal offset of text frame");
+ uiDefButF(block, NUM,B_MAKEFONT, "Y:", 877, 148, 73, 20, &(cu->tb[cu->actbox-1].y), -50.0, 50.0, 10, 0, "Horizontal offset of text frame");
+ uiDefButF(block, NUM,B_MAKEFONT, "Width:", 805, 128, 145, 20, &(cu->tb[cu->actbox-1].w), 0.0, 50.0, 10, 0, "Horizontal offset of text frame");
+ uiDefButF(block, NUM,B_MAKEFONT, "Height:", 805, 108, 145, 20, &(cu->tb[cu->actbox-1].h), 0.0, 50.0, 10, 0, "Horizontal offset of text frame");
+ uiBlockEndAlign(block);
+}
+
+
+/* *************************** CURVE ******************************** */
+
+
+void do_curvebuts(unsigned short event)
+{
+ extern Nurb *lastnu;
+ extern ListBase editNurb; /* from editcurve */
+ Object *ob;
+ Curve *cu;
+ Nurb *nu;
+
+ ob= OBACT;
+ if(ob==0) return;
+
+ switch(event) {
+
+ case B_CONVERTPOLY:
+ case B_CONVERTBEZ:
+ case B_CONVERTBSPL:
+ case B_CONVERTCARD:
+ case B_CONVERTNURB:
+ if(G.obedit) {
+ setsplinetype(event-B_CONVERTPOLY);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ break;
+ case B_UNIFU:
+ case B_ENDPU:
+ case B_BEZU:
+ case B_UNIFV:
+ case B_ENDPV:
+ case B_BEZV:
+ if(G.obedit) {
+ nu= editNurb.first;
+ while(nu) {
+ if(isNurbsel(nu)) {
+ if((nu->type & 7)==CU_NURBS) {
+ if(event<B_UNIFV) {
+ nu->flagu &= 1;
+ nu->flagu += ((event-B_UNIFU)<<1);
+ makeknots(nu, 1, nu->flagu>>1);
+ }
+ else if(nu->pntsv>1) {
+ nu->flagv &= 1;
+ nu->flagv += ((event-B_UNIFV)<<1);
+ makeknots(nu, 2, nu->flagv>>1);
+ }
+ }
+ }
+ nu= nu->next;
+ }
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ break;
+ case B_SETWEIGHT:
+ if(G.obedit) {
+ weightflagNurb(1, editbutweight, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ break;
+ case B_SETW1:
+ editbutweight= 1.0;
+ scrarea_queue_winredraw(curarea);
+ break;
+ case B_SETW2:
+ editbutweight= sqrt(2.0)/4.0;
+ scrarea_queue_winredraw(curarea);
+ break;
+ case B_SETW3:
+ editbutweight= 0.25;
+ scrarea_queue_winredraw(curarea);
+ break;
+ case B_SETW4:
+ editbutweight= sqrt(0.5);
+ scrarea_queue_winredraw(curarea);
+ break;
+ case B_SETORDER:
+ if(G.obedit) {
+ nu= lastnu;
+ if(nu && (nu->type & 7)==CU_NURBS ) {
+ if(nu->orderu>nu->pntsu) {
+ nu->orderu= nu->pntsu;
+ scrarea_queue_winredraw(curarea);
+ }
+ makeknots(nu, 1, nu->flagu>>1);
+ if(nu->orderv>nu->pntsv) {
+ nu->orderv= nu->pntsv;
+ scrarea_queue_winredraw(curarea);
+ }
+ makeknots(nu, 2, nu->flagv>>1);
+ }
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ break;
+ case B_TILTINTERP:
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+ case B_SUBSURFTYPE:
+ /* fallthrough */
+ case B_MAKEDISP:
+ if(G.vd) {
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSALL, 0);
+ allqueue(REDRAWINFO, 1); /* 1, because header->win==0! */
+ }
+ break;
+
+ case B_SUBDIVCURVE:
+ subdivideNurb();
+ break;
+ case B_SPINNURB:
+ if( (G.obedit==NULL) || (G.obedit->type!=OB_SURF) || (G.vd==NULL) ||
+ ((G.obedit->lay & G.vd->lay) == 0) ) return;
+ spinNurb(0, 0);
+ countall();
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+ case B_CU3D: /* allow 3D curve */
+ if(G.obedit) {
+ cu= G.obedit->data;
+ nu= editNurb.first;
+ while(nu) {
+ nu->type &= ~CU_2D;
+ if((cu->flag & CU_3D)==0) nu->type |= CU_2D;
+ test2DNurb(nu);
+ nu= nu->next;
+ }
+ }
+ if(ob->type==OB_CURVE) {
+ cu= ob->data;
+ nu= cu->nurb.first;
+ while(nu) {
+ nu->type &= ~CU_2D;
+ if((cu->flag & CU_3D)==0) nu->type |= CU_2D;
+ test2DNurb(nu);
+ nu= nu->next;
+ }
+ }
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+ case B_SETRESOLU:
+ if(ob->type==OB_CURVE) {
+ cu= ob->data;
+ if(ob==G.obedit) nu= editNurb.first;
+ else nu= cu->nurb.first;
+
+ while(nu) {
+ nu->resolu= cu->resolu;
+ nu= nu->next;
+ }
+ }
+
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSALL, 0);
+ allqueue(REDRAWINFO, 1); /* 1, because header->win==0! */
+
+ break;
+ }
+}
+
+static void editing_panel_curve_tools(Object *ob, Curve *cu)
+{
+ Nurb *nu;
+ extern ListBase editNurb; /* from editcurve */
+ extern Nurb *lastnu;
+ uiBlock *block;
+ short *sp;
+
+ block= uiNewBlock(&curarea->uiblocks, "editing_panel_curve_tools", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Curve Tools", "Editing", 640, 0, 318, 204)==0) return;
+
+ uiDefBut(block, LABEL, 0, "Make Knots",562,173,102, 18, 0, 0, 0, 0, 0, "");
+
+ if(ob->type==OB_CURVE) {
+ uiDefBut(block, LABEL, 0, "Convert", 463,173,72, 18, 0, 0, 0, 0, 0, "");
+ uiBlockBeginAlign(block);
+ uiDefBut(block, BUT,B_CONVERTPOLY,"Poly", 467,152,72, 18, 0, 0, 0, 0, 0, "Converts selected into regular Polygon vertices");
+ uiDefBut(block, BUT,B_CONVERTBEZ,"Bezier", 467,132,72, 18, 0, 0, 0, 0, 0, "Converts selected to Bezier triples");
+ uiDefBut(block, BUT,B_CONVERTNURB,"Nurb", 467,112,72, 18, 0, 0, 0, 0, 0, "Converts selected to Nurbs Points");
+ }
+ uiBlockBeginAlign(block);
+ uiDefBut(block, BUT,B_UNIFU,"Uniform U", 565,152,102, 18, 0, 0, 0, 0, 0, "Nurbs only; interpolated result doesn't go to end points in U");
+ uiDefBut(block, BUT,B_UNIFV,"V", 670,152,50, 18, 0, 0, 0, 0, 0, "Nurbs only; interpolated result doesn't go to end points in V");
+ uiDefBut(block, BUT,B_ENDPU,"Endpoint U", 565,132,102, 18, 0, 0, 0, 0, 0, "Nurbs only; interpolated result is forced to end points in U");
+ uiDefBut(block, BUT,B_ENDPV,"V", 670,132,50, 18, 0, 0, 0, 0, 0, "Nurbs only; interpolated result is forced to end points in V");
+ uiDefBut(block, BUT,B_BEZU,"Bezier U", 565,112,102, 18, 0, 0, 0, 0, 0, "Nurbs only; make knots array mimic a Bezier in U");
+ uiDefBut(block, BUT,B_BEZV,"V", 670,112,50, 18, 0, 0, 0, 0, 0, "Nurbs only; make knots array mimic a Bezier in V");
+ uiBlockEndAlign(block);
+
+ uiDefBut(block, BUT,B_SETWEIGHT,"Set Weight", 465,11,95,49, 0, 0, 0, 0, 0, "Nurbs only; set weight for select points");
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM,0,"Weight:", 565,36,102,22, &editbutweight, 0.01, 100.0, 10, 0, "The weight you can assign");
+ uiDefBut(block, BUT,B_SETW1,"1.0", 670,36,50,22, 0, 0, 0, 0, 0, "");
+ uiDefBut(block, BUT,B_SETW2,"sqrt(2)/4",565,11,55,20, 0, 0, 0, 0, 0, "");
+ uiDefBut(block, BUT,B_SETW3,"0.25", 620,11,45,20, 0, 0, 0, 0, 0, "");
+ uiDefBut(block, BUT,B_SETW4,"sqrt(0.5)",665,11,55,20, 0, 0, 0, 0, 0, "");
+ uiBlockEndAlign(block);
+
+ if(ob==G.obedit) {
+ nu= lastnu;
+ if(nu==NULL) nu= editNurb.first;
+ if(nu) {
+ if (ob->type==OB_CURVE) {
+ uiDefBut(block, LABEL, 0, "Tilt",
+ 467,87,72, 18, 0, 0, 0, 0, 0, "");
+ /* KEY_LINEAR, KEY_CARDINAL, KEY_BSPLINE */
+ uiDefButS(block, MENU, B_TILTINTERP, "Tilt Interpolation %t|Linear %x0|Cardinal %x1|BSpline %x2",
+ 467,67,72, 18, &(nu->tilt_interp), 0, 0, 0, 0, "Tilt interpolation");
+ }
+
+ uiBlockBeginAlign(block);
+ sp= &(nu->orderu);
+ uiDefButS(block, NUM, B_SETORDER, "Order U:", 565,90,102, 19, sp, 2.0, 6.0, 0, 0, "Nurbs only; the amount of control points involved");
+ sp= &(nu->orderv);
+ uiDefButS(block, NUM, B_SETORDER, "V:", 670,90,50, 19, sp, 2.0, 6.0, 0, 0, "Nurbs only; the amount of control points involved");
+ sp= &(nu->resolu);
+ uiDefButS(block, NUM, B_MAKEDISP, "Resol U:", 565,70,102, 19, sp, 1.0, 1024.0, 0, 0, "The amount of new points interpolated per control vertex pair");
+ sp= &(nu->resolv);
+ uiDefButS(block, NUM, B_MAKEDISP, "V:", 670,70,50, 19, sp, 1.0, 1024.0, 0, 0, "The amount of new points interpolated per control vertex pair");
+ }
+ }
+
+
+}
+
+static void editing_panel_curve_tools1(Object *ob, Curve *cu)
+{
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "editing_panel_curve_tools1", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Curve Tools1", "Editing", 960, 0, 318, 204)==0) return;
+
+ uiDefBut(block, BUT, B_SUBDIVCURVE, "Subdivide", 400,180,150,20, 0, 0, 0, 0, 0, "Subdivide selected");
+ if(ob->type==OB_SURF) {
+ uiDefBut(block, BUT, B_SPINNURB, "Spin", 400,160,150,20, 0, 0, 0, 0, 0, "Spin selected 360 degrees");
+ }
+ uiBlockBeginAlign(block);
+ uiDefBut(block, BUT,B_HIDE, "Hide", 400,140,150,18, 0, 0, 0, 0, 0, "Hides selected faces");
+ uiDefBut(block, BUT,B_REVEAL, "Reveal", 400,120,150,18, 0, 0, 0, 0, 0, "Reveals selected faces");
+ uiDefBut(block, BUT,B_SELSWAP, "Select Swap", 400,100,150,18, 0, 0, 0, 0, 0, "Selects unselected faces, and deselects selected faces");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, REDRAWVIEW3D, "NSize:", 400, 60, 150, 19, &G.scene->editbutsize, 0.001, 1.0, 10, 0, "Normal size for drawing");
+ uiDefButBitI(block, TOGN, G_HIDDENHANDLES, REDRAWVIEW3D, "Draw Handles", 400, 40, 150, 19, &G.f, 0, 0, 0, 0, "Draw curve handles in 3D view");
+ uiBlockEndAlign(block);
+
+ if(G.obedit) {
+ uiBut *but;
+ uiBlockBeginAlign(block);
+ but= uiDefButBitS(block,TOG,CU_RETOPO,B_NOP, "Retopo", 560,180,100,19, &cu->flag, 0,0,0,0, "Turn on the re-topology tool");
+ uiButSetFunc(but,retopo_toggle,0,0);
+ if(cu->flag & CU_RETOPO) {
+ but= uiDefBut(block,BUT,B_NOP,"Retopo All", 560,160,100,19, 0,0,0,0,0, "Apply the re-topology tool to all selected vertices");
+ uiButSetFunc(but,retopo_do_all_cb,0,0);
+ }
+ }
+}
+
+/* only for bevel or taper */
+static void test_obcurpoin_but(char *name, ID **idpp)
+{
+ ID *id;
+
+ for(id= G.main->object.first; id; id= id->next) {
+ if( strcmp(name, id->name+2)==0 ) {
+ if (((Object *)id)->type != OB_CURVE) {
+ error ("Bevel/Taper Object must be a Curve");
+ break;
+ }
+ if(id == (ID *)OBACT) {
+ error ("Cannot Bevel/Taper own Object");
+ break;
+ }
+
+ *idpp= id;
+ return;
+ }
+ }
+ *idpp= NULL;
+}
+
+
+
+/* for curve, surf and font! */
+static void editing_panel_curve_type(Object *ob, Curve *cu)
+{
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "editing_panel_curve_type", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Curve and Surface", "Editing", 320, 0, 318, 204)==0) return;
+
+ uiDefButBitS(block, TOG, CU_UV_ORCO, 0, "UV Orco", 600,160,150,19, &cu->flag, 0, 0, 0, 0, "Forces to use UV coordinates for texture mapping 'orco'");
+ if(ob->type==OB_SURF)
+ uiDefButBitS(block, TOG, CU_NOPUNOFLIP, REDRAWVIEW3D, "No Puno Flip", 600,140,150,19, &cu->flag, 0, 0, 0, 0, "Don't flip vertex normals while render");
+
+ uiBlockBeginAlign(block);
+ uiDefBut(block, BUT,B_DOCENTER, "Center", 600, 115, 55, 19, 0, 0, 0, 0, 0, "Shifts object data to be centered about object's origin");
+ uiDefBut(block, BUT,B_DOCENTERNEW, "Center New", 655, 115, 95, 19, 0, 0, 0, 0, 0, "Shifts object's origin to center of object data");
+ uiDefBut(block, BUT,B_DOCENTERCURSOR, "Center Cursor", 600, 95, 150, 19, 0, 0, 0, 0, 0, "Shifts object's origin to cursor location");
+ uiBlockEndAlign(block);
+
+ if(cu->key) {
+ /* uiDefButS(block, NUM, B_DIFF, "Slurph:", 600,25,140,19, &(cu->key->slurph), -500.0, 500.0,0,0); ,""*/
+ uiDefButS(block, TOG, B_RELKEY, "Relative Keys", 600, 72,150,19, &cu->key->type, 0, 0, 0, 0, "");
+ }
+
+
+ if(ob->type!=OB_SURF) {
+
+ if(ob->type==OB_CURVE) {
+ extern float prlen; // buttons_object.c, should be moved....
+ char str[32];
+
+ sprintf(str, "%.4f", prlen);
+ uiDefBut(block, BUT, B_PRINTLEN, "PrintLen", 600,135,75,19, 0, 0, 0, 0, 0, "");
+ uiDefBut(block, LABEL, 0, str, 675,135,75,19, 0, 1.0, 0, 0, 0, "");
+
+ uiBlockBeginAlign(block);
+ /*note, PathLen's max was MAXFRAMEF but this is a short, perhaps the pathlen should be increased later on */
+ uiDefButS(block, NUM, B_RECALCPATH, "PathLen:", 600,50,150,19, &cu->pathlen, 1.0, 32767.0f, 0, 0, "If no speed Ipo was set, the amount of frames of the path");
+ uiDefButBitS(block, TOG, CU_PATH, B_RECALCPATH, "CurvePath", 600,30,75,19 , &cu->flag, 0, 0, 0, 0, "Enables curve to become translation path");
+ uiDefButBitS(block, TOG, CU_FOLLOW, REDRAWVIEW3D, "CurveFollow",675,30,75,19, &cu->flag, 0, 0, 0, 0, "Makes curve path children to rotate along path");
+ uiDefButBitS(block, TOG, CU_STRETCH, B_CURVECHECK, "CurveStretch", 600,10,150,19, &cu->flag, 0, 0, 0, 0, "Option for curve-deform: makes deformed child to stretch along entire path");
+ uiDefButBitS(block, TOG, CU_OFFS_PATHDIST, REDRAWVIEW3D, "PathDist Offs", 600,-10,150,19, &cu->flag, 0, 0, 0, 0, "Children will use TimeOffs value as path distance offset");
+
+ uiBlockEndAlign(block);
+ }
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, NUM, B_SETRESOLU, "DefResolU:", 760,160,150,19, &cu->resolu, 1.0, 1024.0, 0, 0, "Default resolution");
+ uiDefButS(block, NUM, B_NOP, "RenResolU", 760,140,150,19, &cu->resolu_ren, 0.0f, 1024, 0, 0, "Set resolution for rendering. A value of zero skips this operation.");
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_MAKEDISP, "Width:", 760,90,150,19, &cu->width, 0.0, 2.0, 1, 0, "Make interpolated result thinner or fatter");
+ uiDefButF(block, NUM, B_MAKEDISP, "Extrude:", 760,70,150,19, &cu->ext1, 0.0, 100.0, 10, 0, "Curve extrusion size when not using a bevel object");
+ uiDefButF(block, NUM, B_MAKEDISP, "Bevel Depth:", 760,50,150,19, &cu->ext2, 0.0, 2.0, 1, 0, "Bevel depth when not using a bevel object");
+ uiDefButS(block, NUM, B_MAKEDISP, "BevResol:", 760,30,150,19, &cu->bevresol, 0.0, 32.0, 0, 0, "Bevel resolution when depth is non-zero and not using a bevel object");
+ uiDefIDPoinBut(block, test_obcurpoin_but, ID_OB, B_CHANGEDEP, "BevOb:", 760,10,150,19, &cu->bevobj, "Curve object name that defines the bevel shape");
+ uiDefIDPoinBut(block, test_obcurpoin_but, ID_OB, B_CHANGEDEP, "TaperOb:", 760,-10,150,19, &cu->taperobj, "Curve object name that defines the taper (width)");
+
+ uiBlockBeginAlign(block);
+ uiBlockSetCol(block, TH_BUT_SETTING1);
+ uiDefButBitS(block, TOG, CU_BACK, B_MAKEDISP, "Back", 760,115,50,19, &cu->flag, 0, 0, 0, 0, "Draw filled back for extruded/beveled curves");
+ uiDefButBitS(block, TOG, CU_FRONT, B_MAKEDISP, "Front",810,115,50,19, &cu->flag, 0, 0, 0, 0, "Draw filled front for extruded/beveled curves");
+ uiDefButBitS(block, TOG, CU_3D, B_CU3D, "3D", 860,115,50,19, &cu->flag, 0, 0, 0, 0, "Allow Curve to be 3d, it doesn't fill then");
+ }
+}
+
+
+/* *************************** CAMERA ******************************** */
+
+/* callback to handle angle to lens conversion */
+static void do_angletolensconversion_cb(void *lens1, void *angle1)
+{
+ float *lens= (float *)lens1;
+ float *angle= (float *)angle1;
+ float anglevalue= *angle;
+
+ if(lens) {
+ *lens= 16.0f / tan(M_PI*anglevalue/360.0f);
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+/* callback to handle lens to angle conversion */
+static void do_lenstoangleconversion_cb(void *lens1, void *angle1)
+{
+ float *lens= (float *)lens1;
+ float *angle= (float *)angle1;
+ float lensvalue= *lens;
+
+ if(lens) {
+ *angle= 360.0f * atan(16.0f/lensvalue) / M_PI;
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static void editing_panel_camera_type(Object *ob, Camera *cam)
+{
+ uiBlock *block;
+ uiBut *but;
+ float grid=0.0;
+
+ if(G.vd) grid= G.vd->grid;
+ if(grid<1.0) grid= 1.0;
+
+ block= uiNewBlock(&curarea->uiblocks, "editing_panel_camera_type", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Camera", "Editing", 320, 0, 318, 204)==0) return;
+
+ uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
+
+ uiDefBut(block, LABEL, 10, "Lens:", 10, 180, 150, 20, 0, 0.0, 0.0, 0, 0, "");
+
+ uiBlockBeginAlign(block);
+ if(cam->type==CAM_ORTHO) {
+ uiDefButF(block, NUM,REDRAWVIEW3D, "Scale:",
+ 10, 160, 150, 20, &cam->ortho_scale, 0.01, 1000.0, 50, 0, "Specify the ortho scaling of the used camera");
+ } else {
+ if(cam->flag & CAM_ANGLETOGGLE) {
+ but= uiDefButF(block, NUM,REDRAWVIEW3D, "Lens:",
+ 10, 160, 130, 20, &cam->angle, 7.323871, 172.847331, 100, 0, "Specify the lens of the camera in degrees");
+ uiButSetFunc(but,do_angletolensconversion_cb, &cam->lens, &cam->angle);
+ }
+ else {
+ but= uiDefButF(block, NUM,REDRAWVIEW3D, "Lens:",
+ 10, 160, 130, 20, &cam->lens, 1.0, 250.0, 100, 0, "Specify the lens of the camera");
+ uiButSetFunc(but,do_lenstoangleconversion_cb, &cam->lens, &cam->angle);
+ }
+
+ uiDefButS(block, TOG|BIT|5, B_REDR, "D",
+ 140, 160, 20, 20, &cam->flag, 0, 0, 0, 0, "Use degree as the unit of the camera lens");
+ }
+ uiDefButS(block, TOG, REDRAWVIEW3D, "Orthographic",
+ 10, 140, 150, 20, &cam->type, 0, 0, 0, 0, "Render with orthographic projection (no prespective)");
+ uiBlockEndAlign(block);
+
+/* qdn: focal dist. param. from yafray now enabled for Blender as well, to use with defocus composit node */
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, REDRAWVIEW3D, "Dof Dist:", 10, 110, 150, 20 /*0, 125, 150, 20*/, &cam->YF_dofdist, 0.0, 5000.0, 50, 0, "Sets distance to point of focus (enable 'Limits' to make visible in 3Dview)");
+ uiDefIDPoinBut(block, test_obpoin_but, ID_OB, REDRAWVIEW3D, "Dof Ob:", 10, 90, 150, 20, &cam->dof_ob, "Focus on this object (overrides the 'Dof Dist')");
+ uiBlockEndAlign(block);
+
+ uiDefBut(block, LABEL, 0, "Clipping Start/End:", 10, 45, 150, 20, 0, 0.0, 0.0, 0, 0, "");
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM,REDRAWVIEW3D, "Start:",
+ 10, 25, 150, 20, &cam->clipsta, 0.001*grid, 100.0*grid, 10, 0, "Clip out geometry closer then this distance to the camera");
+ uiDefButF(block, NUM,REDRAWVIEW3D, "End:",
+ 10, 5, 150, 20, &cam->clipend, 1.0, 5000.0*grid, 100, 0, "Clip out geometry further then this distance to the camera");
+ uiBlockEndAlign(block);
+
+ uiDefBut(block, LABEL, 0, "Show:", 170, 180, 150, 20, 0, 0.0, 0.0, 0, 0, "");
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, TOG|BIT|0, REDRAWVIEW3D, "Limits",
+ 170, 160, 75, 20, &cam->flag, 0, 0, 0, 0, "Draw the clipping range and the focal point");
+ uiDefButS(block, TOG|BIT|1, REDRAWVIEW3D, "Mist",
+ 245, 160, 75, 20, &cam->flag, 0, 0, 0, 0, "Draw a line that indicates the mist area");
+
+ uiDefButS(block, TOG|BIT|4, REDRAWVIEW3D, "Name",
+ 170, 140, 75, 20, &cam->flag, 0, 0, 0, 0, "Draw the active camera's name in camera view");
+ uiDefButS(block, TOG|BIT|3, REDRAWVIEW3D, "Title Safe",
+ 245, 140, 75, 20, &cam->flag, 0, 0, 0, 0, "Draw a the title safe zone in camera view");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, TOG|BIT|2, REDRAWVIEW3D, "Passepartout",
+ 170, 110, 150, 20, &cam->flag, 0, 0, 0, 0, "Draw a darkened passepartout over the off-screen area in camera view");
+ uiDefButF(block, NUMSLI, REDRAWVIEW3D, "Alpha: ",
+ 170, 90, 150, 20, &cam->passepartalpha, 0.0, 1.0, 0, 0, "The opacity (darkness) of the passepartout");
+ uiBlockEndAlign(block);
+
+ uiDefButF(block, NUM,REDRAWVIEW3D, "Size:",
+ 170, 50, 150, 20, &cam->drawsize, 0.1*grid, 10.0, 10, 0, "The size that the camera is displayed in the 3D View (different from the object's scale)");
+
+ uiDefBut(block, LABEL, 0, "Shift:", 170, 25, 150, 20, 0, 0.0, 0.0, 0, 0, "");
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM,REDRAWVIEW3D, "X:",
+ 170, 5, 75, 20, &cam->shiftx, -2.0, 2.0, 1, 2, "Horizontally shift the camera view, without changing the perspective");
+ uiDefButF(block, NUM,REDRAWVIEW3D, "Y:",
+ 245, 5, 75, 20, &cam->shifty, -2.0, 2.0, 1, 2, "Vertically shift the camera view, without changing the perspective");
+ uiBlockEndAlign(block);
+}
+
+/* yafray: extra camera panel to set Depth-of-Field parameters */
+static void editing_panel_camera_yafraydof(Object *ob, Camera *cam)
+{
+ uiBlock *block;
+ char *mst1, *mst2;
+
+ block= uiNewBlock(&curarea->uiblocks, "editing_panel_camera_yafraydof", UI_EMBOSS, UI_HELV, curarea->win);
+ uiNewPanelTabbed("Camera", "Editing");
+ if(uiNewPanel(curarea, block, "Yafray DoF", "Editing", 320, 0, 318, 204)==0) return;
+
+ uiDefButF(block, NUM, REDRAWVIEW3D, "DoFDist:", 10, 147, 180, 20, &cam->YF_dofdist, 0.0, 5000.0, 50, 0, "Sets distance to point of focus (use camera 'ShowLimits' to make visible in 3Dview)");
+ uiDefButF(block, NUM, B_DIFF, "Aperture:", 10, 125, 180, 20, &cam->YF_aperture, 0.0, 2.0, 1, 0, "Sets lens aperture, the larger, the more blur (use small values, 0 is no DoF)");
+
+ uiDefButBitS(block, TOG, CAM_YF_NO_QMC, B_DIFF, "Random sampling", 10, 90, 180, 20, &cam->flag, 0, 0, 0, 0, "Use noisy random Lens sampling instead of QMC");
+
+ uiDefBut(block, LABEL, 0, "Bokeh", 10, 60, 180, 19, 0, 0.0, 0.0, 0, 0, "");
+ mst1 = "Bokeh Type%t|Disk1%x0|Disk2%x1|Triangle%x2|Square%x3|Pentagon%x4|Hexagon%x5|Ring%x6";
+ uiDefButS(block, MENU, B_REDR, mst1, 10, 40, 89, 20, &cam->YF_bkhtype, 0.0, 0.0, 0, 0, "Sets Bokeh type");
+
+ if ((cam->YF_bkhtype!=0) && (cam->YF_bkhtype!=6)) {
+ mst2 = "Bokeh Bias%t|Uniform%x0|Center%x1|Edge%x2";
+ uiDefButS(block, MENU, B_REDR, mst2, 100, 40, 90, 20, &cam->YF_bkhbias, 0.0, 0.0, 0, 0, "Sets Bokeh bias");
+ if (cam->YF_bkhtype>1)
+ uiDefButF(block, NUM, B_DIFF, "Rotation:", 10, 15, 180, 20, &cam->YF_bkhrot, 0.0, 360.0, 100, 0, "Shape rotation amount in degrees");
+ }
+
+}
+
+/* **************************** CAMERA *************************** */
+
+void do_cambuts(unsigned short event)
+{
+ Object *ob;
+ Camera *cam;
+
+ ob= OBACT;
+ if (ob==0) return;
+ cam= ob->data;
+
+ switch(event) {
+ case 0:
+ ;
+ break;
+ }
+}
+
+/* *************************** MBALL ******************************** */
+
+void do_mballbuts(unsigned short event)
+{
+ switch(event) {
+ case B_RECALCMBALL:
+ DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+ }
+}
+
+static void editing_panel_mball_type(Object *ob, MetaBall *mb)
+{
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "editing_panel_mball_type", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "MetaBall", "Editing", 320, 0, 318, 204)==0) return;
+
+ ob= find_basis_mball(ob);
+ mb= ob->data;
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_RECALCMBALL, "Wiresize:", 470,178,250,19, &mb->wiresize, 0.05, 1.0, 1, 0, "Polygonization resolution in 3d window");
+ uiDefButF(block, NUM, B_NOP, "Rendersize:", 470,158,250,19, &mb->rendersize, 0.05, 1.0, 1, 0, "Polygonization resolution in rendering");
+ uiDefButF(block, NUM, B_RECALCMBALL, "Threshold:", 470,138,250,19, &mb->thresh, 0.0001, 5.0, 1, 0, "Defines influence of meta elements");
+
+ uiBlockBeginAlign(block);
+ uiBlockSetCol(block, TH_BUT_SETTING1);
+ uiDefBut(block, LABEL, 0, "Update:", 471,108,120,19, 0, 0, 0, 0, 0, "");
+ uiDefButS(block, ROW, B_DIFF, "Always", 471, 85, 120, 19, &mb->flag, 0.0, 0.0, 0, 0, "While editing, always updates");
+ uiDefButS(block, ROW, B_DIFF, "Half Res", 471, 65, 120, 19, &mb->flag, 0.0, 1.0, 0, 0, "While editing, updates in half resolution");
+ uiDefButS(block, ROW, B_DIFF, "Fast", 471, 45, 120, 19, &mb->flag, 0.0, 2.0, 0, 0, "While editing, updates without polygonization");
+ uiDefButS(block, ROW, B_DIFF, "Never", 471, 25, 120, 19, &mb->flag, 0.0, 3.0, 0, 0, "While editing, doesn't update");
+
+}
+
+static void editing_panel_mball_tools(Object *ob, MetaBall *mb)
+{
+ extern MetaElem *lastelem;
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "editing_panel_mball_tools", UI_EMBOSS, UI_HELV, curarea->win);
+ if( uiNewPanel(curarea, block, "MetaBall tools", "Editing", 640, 0, 318, 204)==0) return;
+
+ if(ob==G.obedit && lastelem) {
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_RECALCMBALL, "Stiffness:", 750,178,250,19, &lastelem->s, 0.0, 10.0, 1, 0, "Stiffness for active meta");
+ if(lastelem->type!=MB_BALL)
+ uiDefButF(block, NUM, B_RECALCMBALL, "dx:", 750,158,250,19, &lastelem->expx, 0.0, 20.0, 1, 0, "X size for active meta");
+ if((lastelem->type!=MB_BALL)&&(lastelem->type!=MB_TUBE))
+ uiDefButF(block, NUM, B_RECALCMBALL, "dy:", 750,138,250,19, &lastelem->expy, 0.0, 20.0, 1, 0, "Y size for active meta");
+
+ if((lastelem->type==MB_CUBE)||(lastelem->type==MB_ELIPSOID))
+ uiDefButF(block, NUM, B_RECALCMBALL, "dz:", 750,118,250,19, &lastelem->expz, 0.0, 20.0, 1, 0, "Z size for active meta");
+ uiBlockEndAlign(block);
+
+ uiDefButS(block, ROW, B_RECALCMBALL, "Ball", 753,83,60,19, &lastelem->type, 1.0, MB_BALL, 0, 0, "Draw active meta as Ball");
+ uiBlockBeginAlign(block);
+ uiDefButS(block, ROW, B_RECALCMBALL, "Tube", 753,62,60,19, &lastelem->type, 1.0, MB_TUBE, 0, 0, "Draw active meta as Ball");
+ uiDefButS(block, ROW, B_RECALCMBALL, "Plane", 814,62,60,19, &lastelem->type, 1.0, MB_PLANE, 0, 0, "Draw active meta as Plane");
+ uiDefButS(block, ROW, B_RECALCMBALL, "Elipsoid", 876,62,60,19, &lastelem->type, 1.0, MB_ELIPSOID, 0, 0, "Draw active meta as Ellipsoid");
+ uiDefButS(block, ROW, B_RECALCMBALL, "Cube", 938,62,60,19, &lastelem->type, 1.0, MB_CUBE, 0, 0, "Draw active meta as Cube");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, MB_NEGATIVE, B_RECALCMBALL, "Negative",753,16,125,19, &lastelem->flag, 0, 0, 0, 0, "Make active meta creating holes");
+ uiDefButBitS(block, TOG, MB_HIDE, B_RECALCMBALL, "Hide",878,16,125,19, &lastelem->flag, 0, 0, 0, 0, "Make active meta invisible");
+ uiBlockEndAlign(block);
+
+ }
+
+}
+
+
+/* *************************** LATTICE ******************************** */
+
+void do_latticebuts(unsigned short event)
+{
+ Object *ob;
+ Lattice *lt;
+
+ ob= OBACT;
+ if(ob->type!=OB_LATTICE) return;
+
+ switch(event) {
+ case B_REGULARLAT:
+ if(ob) {
+ lt = ob->data;
+ if(ob==G.obedit) resizelattice(editLatt, lt->opntsu, lt->opntsv, lt->opntsw, NULL);
+ else resizelattice(ob->data, lt->opntsu, lt->opntsv, lt->opntsw, NULL);
+ ob->softflag |= OB_SB_REDO;
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ case B_RESIZELAT:
+ if(ob) {
+ lt = ob->data;
+ resizelattice(ob->data, lt->opntsu, lt->opntsv, lt->opntsw, ob);
+ ob->softflag |= OB_SB_REDO;
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ break;
+ case B_DRAWLAT:
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+ case B_LATTCHANGED:
+
+ lt= ob->data;
+ if(lt->flag & LT_OUTSIDE) outside_lattice(lt);
+
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+
+ allqueue(REDRAWVIEW3D, 0);
+
+ break;
+ }
+}
+
+static void editing_panel_lattice_type(Object *ob, Lattice *lt)
+{
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "editing_panel_lattice_type", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Lattice", "Editing", 320, 0, 318, 204)==0) return;
+
+
+ uiSetButLock(lt->key!=0, "Not with VertexKeys");
+ uiSetButLock(ob==G.obedit, "Unable to perform function in EditMode");
+
+ uiBlockBeginAlign(block);
+
+ lt->opntsu = lt->pntsu;
+ lt->opntsv = lt->pntsv;
+ lt->opntsw = lt->pntsw;
+
+ uiDefButS(block, NUM, B_RESIZELAT, "U:", 469, 178,100,19, &lt->opntsu, 1.0, 64.0, 0, 0, "Points in U direction");
+ uiDefButC(block, ROW, B_LATTCHANGED, "Lin", 572, 178, 40, 19, &lt->typeu, 1.0, (float)KEY_LINEAR, 0, 0, "Set Linear interpolation");
+ uiDefButC(block, ROW, B_LATTCHANGED, "Card", 613, 178, 40, 19, &lt->typeu, 1.0, (float)KEY_CARDINAL, 0, 0, "Set Cardinal interpolation");
+ uiDefButC(block, ROW, B_LATTCHANGED, "B", 652, 178, 40, 19, &lt->typeu, 1.0, (float)KEY_BSPLINE, 0, 0, "Set B-spline interpolation");
+
+ uiDefButS(block, NUM, B_RESIZELAT, "V:", 469, 156,100,19, &lt->opntsv, 1.0, 64.0, 0, 0, "Points in V direction");
+ uiDefButC(block, ROW, B_LATTCHANGED, "Lin", 572, 156, 40, 19, &lt->typev, 2.0, (float)KEY_LINEAR, 0, 0, "Set Linear interpolation");
+ uiDefButC(block, ROW, B_LATTCHANGED, "Card", 613, 156, 40, 19, &lt->typev, 2.0, (float)KEY_CARDINAL, 0, 0, "Set Cardinal interpolation");
+ uiDefButC(block, ROW, B_LATTCHANGED, "B", 652, 156, 40, 19, &lt->typev, 2.0, (float)KEY_BSPLINE, 0, 0, "Set B-spline interpolation");
+
+ uiDefButS(block, NUM, B_RESIZELAT, "W:", 469, 134,100,19, &lt->opntsw, 1.0, 64.0, 0, 0, "Points in W direction");
+ uiDefButC(block, ROW, B_LATTCHANGED, "Lin", 572, 134, 40, 19, &lt->typew, 3.0, (float)KEY_LINEAR, 0, 0, "Set Linear interpolation");
+ uiDefButC(block, ROW, B_LATTCHANGED, "Card", 613, 134, 40, 19, &lt->typew, 3.0, (float)KEY_CARDINAL, 0, 0, "Set Cardinal interpolation");
+ uiDefButC(block, ROW, B_LATTCHANGED, "B", 652, 134, 40, 19, &lt->typew, 3.0, (float)KEY_BSPLINE, 0, 0, "Set B-spline interpolation");
+
+ uiBlockEndAlign(block);
+
+ uiDefBut(block, BUT, B_REGULARLAT, "Make Regular", 469,98,102,31, 0, 0, 0, 0, 0, "Make Lattice regular");
+
+ uiClearButLock();
+ uiDefButBitS(block, TOG, LT_OUTSIDE, B_LATTCHANGED, "Outside", 571,98,122,31, &lt->flag, 0, 0, 0, 0, "Only draw, and take into account, the outer vertices");
+
+ if(lt->key) {
+ uiDefButS(block, NUM, B_DIFF, "Slurph:", 469,60,120,19, &(lt->key->slurph), -500.0, 500.0, 0, 0, "Set time value to denote 'slurph' (sequential delay) vertices with key framing");
+ uiDefButS(block, TOG, B_RELKEY, "Relative Keys", 469,40,120,19, &lt->key->type, 0, 0, 0, 0, "Use relative keys (instead of absolute)");
+ }
+
+}
+
+/* *************************** ARMATURE ******************************** */
+
+void do_armbuts(unsigned short event)
+{
+ Object *ob= OBACT;
+
+ switch(event) {
+ case B_ARM_RECALCDATA:
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 1);
+ allqueue(REDRAWBUTSEDIT, 0);
+ break;
+ case B_ARM_STRIDE:
+ if(ob && ob->pose) {
+ bPoseChannel *pchan;
+ bActionStrip *strip;
+
+ for (pchan=ob->pose->chanbase.first; pchan; pchan=pchan->next)
+ if(pchan->flag & POSE_STRIDE)
+ break;
+
+ /* we put the stride bone name in the strips, for lookup of action channel */
+ for (strip=ob->nlastrips.first; strip; strip=strip->next){
+ if(strip->flag & ACTSTRIP_USESTRIDE) {
+ if(pchan) BLI_strncpy(strip->stridechannel, pchan->name, 32);
+ else strip->stridechannel[0]= 0;
+ }
+ }
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 1);
+ allqueue(REDRAWNLA, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ }
+ break;
+ case B_ARM_CALCPATHS:
+ if (ob && ob->pose)
+ pose_calculate_path(ob);
+ break;
+ case B_ARM_CLEARPATHS:
+ if (ob && ob->pose)
+ pose_clear_paths(ob);
+ break;
+ }
+}
+
+static void validate_stridebutton_cb(void *pchanv, void *poin)
+{
+ Object *ob= OBACT;
+ bPoseChannel *pchan;
+
+ if(ob && ob->pose) {
+ for (pchan=ob->pose->chanbase.first; pchan; pchan=pchan->next){
+ if(pchan!=pchanv)
+ pchan->flag &= ~POSE_STRIDE;
+ }
+ }
+}
+
+static int editbone_to_parnr (EditBone *bone)
+{
+ EditBone *ebone;
+ int index;
+
+ for (ebone=G.edbo.first, index=0; ebone; ebone=ebone->next, index++){
+ if (ebone==bone)
+ return index;
+ }
+
+ return -1;
+}
+
+
+/* the "IK" button in editbuttons */
+static void attach_bone_to_parent_cb(void *bonev, void *arg2_unused)
+{
+ EditBone *ebone= bonev;
+
+ if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
+ /* Attach this bone to its parent */
+ VECCOPY(ebone->head, ebone->parent->tail);
+ }
+}
+
+static void parnr_to_editbone(EditBone *bone)
+{
+ if (bone->parNr == -1){
+ bone->parent = NULL;
+ bone->flag &= ~BONE_CONNECTED;
+ }
+ else{
+ bone->parent = BLI_findlink(&G.edbo, bone->parNr);
+ attach_bone_to_parent_cb(bone, NULL);
+ }
+}
+
+static void parnr_to_editbone_cb(void *bonev, void *arg2_unused)
+{
+ EditBone *curBone= bonev;
+ parnr_to_editbone(curBone);
+}
+
+/* only used for showing parent of editbones */
+static void build_bonestring (char *string, EditBone *bone)
+{
+ bArmature *arm= G.obedit->data;
+ EditBone *curBone;
+ EditBone *pBone;
+ int skip=0;
+ int index, numbones, i;
+ char (*qsort_ptr)[32] = NULL;
+
+ /* That space is there for a reason - for no parent */
+ sprintf (string, "Parent%%t| %%x%d", -1);
+
+ numbones = BLI_countlist(&G.edbo);
+
+ /*
+ * This will hold the bone names temporarily so we can sort them
+ */
+ if (numbones > 0)
+ qsort_ptr = MEM_callocN (numbones * sizeof (qsort_ptr[0]),
+ "qsort_ptr");
+
+ numbones = 0;
+ for (curBone = G.edbo.first, index=0; curBone;
+ curBone=curBone->next, index++){
+ /* Make sure this is a valid child */
+ if (curBone != bone){
+ skip=0;
+ for (pBone=curBone->parent; pBone; pBone=pBone->parent){
+ if (pBone==bone){
+ skip=1;
+ break;
+ }
+ }
+ /* no browsing for bones in invisible layers */
+ if ((arm->layer & curBone->layer) == 0) {
+ /* but ensure the current parent at least shows */
+ if(bone->parent!=curBone)
+ skip= 1;
+ }
+
+ if (skip)
+ continue;
+
+ sprintf (qsort_ptr[numbones], "|%s%%x%d", curBone->name, index);
+ numbones++;
+ }
+ }
+ qsort (qsort_ptr, numbones, sizeof (qsort_ptr[0]),
+ ( int (*)(const void *, const void *) ) strcmp);
+
+ for (i=0; i < numbones; ++i) {
+ sprintf (string, "%s%s", string, qsort_ptr[i]);
+ }
+
+ if (qsort_ptr)
+ MEM_freeN(qsort_ptr);
+}
+
+/* assumes armature editmode */
+/* exported to drawview.c via BIF_butspace.h */
+void validate_editbonebutton_cb(void *bonev, void *namev)
+{
+ EditBone *eBone= bonev;
+ char oldname[32], newname[32];
+
+ /* need to be on the stack */
+ BLI_strncpy(newname, eBone->name, 32);
+ BLI_strncpy(oldname, (char *)namev, 32);
+ /* restore */
+ BLI_strncpy(eBone->name, oldname, 32);
+
+ armature_bone_rename(G.obedit->data, oldname, newname); // editarmature.c
+ allqueue(REDRAWALL, 0);
+}
+
+/* assumes armature posemode */
+static void validate_posebonebutton_cb(void *bonev, void *namev)
+{
+ Bone *bone= bonev;
+ Object *ob= OBACT;
+ char oldname[32], newname[32];
+
+ /* need to be on the stack */
+ BLI_strncpy(newname, bone->name, 32);
+ BLI_strncpy(oldname, (char *)namev, 32);
+ /* restore */
+ BLI_strncpy(bone->name, oldname, 32);
+
+ armature_bone_rename(ob->data, oldname, newname); // editarmature.c
+ allqueue(REDRAWALL, 0);
+}
+
+static void armature_layer_cb(void *lay_v, void *value_v)
+{
+ short *layer= lay_v;
+ int value= (long)value_v;
+
+ if(*layer==0 || G.qual==0) *layer= value;
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWNLA, 0);
+}
+
+static void editing_panel_armature_type(Object *ob, bArmature *arm)
+{
+ uiBlock *block;
+ uiBut *but;
+ int a;
+
+ block= uiNewBlock(&curarea->uiblocks, "editing_panel_armature_type", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Armature", "Editing", 320, 0, 318, 204)==0) return;
+
+ uiDefBut(block, LABEL, 0, "Editing Options", 10,180,150,20, 0, 0, 0, 0, 0, "");
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOG, ARM_MIRROR_EDIT, B_DIFF, "X-Axis Mirror", 10, 160,100,20, &arm->flag, 0, 0, 0, 0, "Enable X-axis mirrored editing");
+ uiDefButBitC(block, TOG, OB_DRAWXRAY,REDRAWVIEW3D, "X-Ray", 110,160,100,20, &ob->dtx, 0, 0, 0, 0, "Draw armature in front of solid objects");
+ uiDefButBitI(block, TOG, ARM_AUTO_IK, B_DIFF, "Auto IK", 210,160,100,20, &arm->flag, 0, 0, 0, 0, "Adds temporal IK chains while grabbing Bones");
+ uiBlockEndAlign(block);
+
+ uiDefBut(block, LABEL, 0, "Display Options", 10,133,150,19, 0, 0, 0, 0, 0, "");
+
+ /* layers */
+ uiBlockBeginAlign(block);
+ for(a=0; a<8; a++) {
+ short dx= 18;
+ but= uiDefButBitS(block, BUT_TOGDUAL, 1<<a, REDRAWVIEW3D, "", 10+a*dx, 115, dx, 15, &arm->layer, 0, 0, 0, 0, "");
+ uiButSetFunc(but, armature_layer_cb, &arm->layer, (void *)(1<<a));
+ }
+ uiBlockBeginAlign(block);
+ for(a=8; a<16; a++) {
+ short dx= 18;
+ but= uiDefButBitS(block, BUT_TOGDUAL, 1<<a, REDRAWVIEW3D, "", 18+a*dx, 115, dx, 15, &arm->layer, 0, 0, 0, 0, "");
+ uiButSetFunc(but, armature_layer_cb, &arm->layer, (void *)(1<<a));
+ }
+ /* quite bad here, but I don't know a better place for copy... */
+ if(ob->pose)
+ ob->pose->proxy_layer= arm->layer;
+
+ uiBlockBeginAlign(block);
+ uiDefButI(block, ROW, REDRAWVIEW3D, "Octahedron", 10, 87,90,20, &arm->drawtype, 0, ARM_OCTA, 0, 0, "Draw bones as octahedra");
+ uiDefButI(block, ROW, REDRAWVIEW3D, "Stick", 100, 87,55,20, &arm->drawtype, 0, ARM_LINE, 0, 0, "Draw bones as simple 2d lines with dots");
+ uiDefButI(block, ROW, REDRAWVIEW3D, "B-Bone", 155, 87,70,20, &arm->drawtype, 0, ARM_B_BONE, 0, 0, "Draw bones as boxes, showing subdivision and b-splines");
+ uiDefButI(block, ROW, REDRAWVIEW3D, "Envelope", 225, 87,85,20, &arm->drawtype, 0, ARM_ENVELOPE, 0, 0, "Draw bones as extruded spheres, showing deformation influence volume");
+
+ uiDefButBitI(block, TOG, ARM_DRAWAXES, REDRAWVIEW3D, "Draw Axes", 10, 67,100,20, &arm->flag, 0, 0, 0, 0, "Draw bone axes");
+ uiDefButBitI(block, TOG, ARM_DRAWNAMES, REDRAWVIEW3D, "Draw Names", 110,67,100,20, &arm->flag, 0, 0, 0, 0, "Draw bone names");
+ uiDefButBitI(block, TOGN, ARM_NO_CUSTOM, REDRAWVIEW3D, "Draw Shapes", 210,67,100,20, &arm->flag, 0, 0, 0, 0, "Draw custom bone shapes");
+
+ uiBlockEndAlign(block);
+
+ uiDefBut(block, LABEL, 0, "Deform Options", 10,40,150,20, 0, 0, 0, 0, 0, "");
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, ARM_DEF_VGROUP, B_ARM_RECALCDATA, "Vertex Groups", 10, 20,100,20, &arm->deformflag, 0, 0, 0, 0, "Enable VertexGroups defining deform (not for Modifiers)");
+ uiDefButBitS(block, TOG, ARM_DEF_ENVELOPE, B_ARM_RECALCDATA, "Envelopes", 110,20,100,20, &arm->deformflag, 0, 0, 0, 0, "Enable Bone Envelopes defining deform (not for Modifiers)");
+ uiDefButBitS(block, TOG, ARM_DEF_QUATERNION, B_ARM_RECALCDATA, "Quaternion", 210,20,100,20, &arm->deformflag, 0, 0, 0, 0, "Enable deform rotation interpolation with Quaternions (not for Modifiers)");
+ uiDefButBitI(block, TOG, ARM_RESTPOS, B_ARM_RECALCDATA,"Rest Position", 10,0,100,20, &arm->flag, 0, 0, 0, 0, "Show armature rest position, no posing possible");
+ uiDefButBitI(block, TOG, ARM_DELAYDEFORM, REDRAWVIEW3D, "Delay Deform", 110,0,100,20, &arm->flag, 0, 0, 0, 0, "Don't deform children when manipulating bones in pose mode");
+ uiDefButBitS(block, TOG, ARM_DEF_B_BONE_REST, B_ARM_RECALCDATA,"B-Bone Rest", 210,0,100,20, &arm->deformflag, 0, 0, 0, 0, "Make B-Bones deform already in rest position");
+ uiBlockEndAlign(block);
+}
+
+static void editing_panel_armature_visuals(Object *ob, bArmature *arm)
+{
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "editing_panel_armature_visuals", UI_EMBOSS, UI_HELV, curarea->win);
+ uiNewPanelTabbed("Armature", "Editing");
+ if(uiNewPanel(curarea, block, "Armature Visualisations", "Editing", 320, 0, 318, 204)==0) return;
+
+ /* version patch for older files here (do_versions patch too complicated) */
+ if ((arm->ghostsf == 0) || (arm->ghostef == 0)) {
+ arm->ghostsf = CFRA - (arm->ghostep * arm->ghostsize);
+ arm->ghostef = CFRA + (arm->ghostep * arm->ghostsize);
+ }
+ if ((arm->pathsf == 0) || (arm->pathef == 0)) {
+ arm->pathsf = SFRA;
+ arm->pathef = EFRA;
+ }
+
+ /* Ghost Drawing Options */
+ uiDefBut(block, LABEL, 0, "Ghost Options", 10,180,150,20, 0, 0, 0, 0, 0, "");
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, MENU, REDRAWVIEW3D, "Ghosts %t|Around Current Frame %x0|In Range %x1",
+ 10, 160, 150, 20, &arm->ghosttype, 0, 0, 0, 0, "Choose range of Ghosts to draw for current Action");
+
+ uiDefButS(block, NUM, REDRAWVIEW3D, "GStep: ", 10,140,150,20, &arm->ghostsize, 1.0f, 20.0f, 0, 0, "How many frames between Ghost instances");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ if (arm->ghosttype == ARM_GHOST_CUR) {
+ /* range is around current frame */
+ uiDefButS(block, NUM, REDRAWVIEW3D, "Ghost: ", 10,110,150,20, &arm->ghostep, 0.0f, 30.0f, 0, 0, "Draw Ghosts around current frame, for current Action");
+ }
+ else if (arm->ghosttype == ARM_GHOST_RANGE) {
+ /* range is defined by start+end frame below */
+ uiDefButI(block, NUM,REDRAWVIEW3D,"GSta:",10,110,150,20, &arm->ghostsf,1.0,MAXFRAMEF, 0, 0, "The start frame for Ghost display range");
+ uiDefButI(block, NUM,REDRAWVIEW3D,"GEnd:",10,90,150,20, &arm->ghostef,arm->ghostsf,MAXFRAMEF, 0, 0, "The end frame for Ghost display range");
+ }
+ uiBlockEndAlign(block);
+
+ /* Bone Path Drawing Options */
+ uiDefBut(block, LABEL, 0, "Bone Paths", 165,180,150,20, 0, 0, 0, 0, 0, "");
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, ARM_PATH_FNUMS, REDRAWVIEW3D, "Frame Nums", 170, 160, 80, 20, &arm->pathflag, 0, 0, 0, 0, "Show frame numbers on path");
+ uiDefButS(block, NUM, REDRAWVIEW3D, "PStep:",250,160,80,20, &arm->pathsize,1,100, 10, 50, "Frames between highlighted points on bone path");
+ uiDefButBitS(block, TOG, ARM_PATH_KFRAS, REDRAWVIEW3D, "Show Keys", 170, 140, 160, 20, &arm->pathflag, 0, 0, 0, 0, "Show key frames on path");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButI(block, NUM,REDRAWVIEW3D,"PSta:",170,100,80,20, &arm->pathsf, 1.0, MAXFRAMEF, 0, 0, "The start frame for Bone Path display range");
+ uiDefButI(block, NUM,REDRAWVIEW3D,"PEnd:",250,100,80,20, &arm->pathef, arm->pathsf, MAXFRAMEF, 0, 0, "The end frame for Bone Path display range");
+ uiDefButBitS(block, TOG, ARM_PATH_HEADS, REDRAWVIEW3D, "Bone-Head Path", 170, 80, 160, 20, &arm->pathflag, 0, 0, 0, 0, "Calculate the Path travelled by the Bone's Head instead of Tail");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefBut(block, BUT, B_ARM_CALCPATHS, "Calculate Paths", 170,40,160,20, 0, 0, 0, 0, 0, "(Re)calculates the paths of the selected bones");
+ uiDefBut(block, BUT, B_ARM_CLEARPATHS, "Clear All Paths", 170,20,160,20, 0, 0, 0, 0, 0, "Clears all bone paths");
+ uiBlockEndAlign(block);
+}
+
+/* autocomplete callback for editbones */
+static void autocomplete_editbone(char *str, void *arg_v)
+{
+ if(G.obedit==NULL) return;
+
+ /* search if str matches the beginning of an ID struct */
+ if(str[0]) {
+ AutoComplete *autocpl= autocomplete_begin(str, 32);
+ EditBone *ebone;
+
+ for (ebone=G.edbo.first; ebone; ebone=ebone->next)
+ if(ebone->name!=str)
+ autocomplete_do_name(autocpl, ebone->name);
+
+ autocomplete_end(autocpl, str);
+ }
+}
+
+static void editing_panel_armature_bones(Object *ob, bArmature *arm)
+{
+ uiBlock *block;
+ uiBut *but;
+ EditBone *curBone;
+ char *boneString=NULL;
+ int by=180;
+ int index, a;
+
+ /* Draw the bone name block */
+
+ block= uiNewBlock(&curarea->uiblocks, "editing_panel_armature_bones", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Armature Bones", "Editing", 640, 0, 318, 204)==0) return;
+
+ /* this is a variable height panel, newpanel doesnt force new size on existing panels */
+ /* so first we make it default height */
+ uiNewPanelHeight(block, 204);
+
+
+ uiDefBut(block, LABEL, 0, "Selected Bones", 0,by,158,18, 0, 0, 0, 0, 0, "Only show in Armature Editmode");
+ by-=20;
+ for (curBone=G.edbo.first, index=0; curBone; curBone=curBone->next, index++){
+ if ((curBone->flag & BONE_SELECTED) && (curBone->layer & arm->layer)) {
+
+ /* Bone naming button */
+ but=uiDefBut(block, TEX, REDRAWVIEW3D, "BO:", -10,by,117,18, curBone->name, 0, 31, 0, 0, "Change the bone name");
+ uiButSetFunc(but, validate_editbonebutton_cb, curBone, NULL);
+ uiButSetCompleteFunc(but, autocomplete_editbone, (void *)OBACT);
+
+ uiDefBut(block, LABEL, 0, "child of", 107,by,73,18, NULL, 0.0, 0.0, 0.0, 0.0, "");
+
+ boneString = MEM_mallocN((BLI_countlist(&G.edbo) * 64)+64, "Bone str");
+ build_bonestring (boneString, curBone);
+
+ curBone->parNr = editbone_to_parnr(curBone->parent);
+ but = uiDefButI(block, MENU,REDRAWVIEW3D, boneString, 180,by,120,18, &curBone->parNr, 0.0, 0.0, 0.0, 0.0, "Parent");
+ /* last arg NULL means button will put old string there */
+ uiButSetFunc(but, parnr_to_editbone_cb, curBone, NULL);
+
+ MEM_freeN(boneString);
+
+ /* Connect to parent flag */
+ if (curBone->parent){
+ but=uiDefButBitI(block, TOG, BONE_CONNECTED, B_ARM_RECALCDATA, "Con", 300,by,32,18, &curBone->flag, 0.0, 0.0, 0.0, 0.0, "Connect this Bone to Parent");
+ uiButSetFunc(but, attach_bone_to_parent_cb, curBone, NULL);
+ }
+
+ /* Segment, dist and weight buttons */
+ uiBlockBeginAlign(block);
+ uiDefButS(block, NUM, B_ARM_RECALCDATA, "Segm: ", -10,by-19,117,18, &curBone->segments, 1.0, 32.0, 0.0, 0.0, "Subdivisions for B-bones");
+ uiDefButF(block, NUM,B_ARM_RECALCDATA, "Dist:", 110, by-19, 105, 18, &curBone->dist, 0.0, 1000.0, 10.0, 0.0, "Bone deformation distance");
+ uiDefButF(block, NUM,B_ARM_RECALCDATA, "Weight:", 225, by-19,105, 18, &curBone->weight, 0.0F, 1000.0F, 10.0F, 0.0F, "Bone deformation weight");
+
+ /* bone types */
+ uiDefButBitI(block, TOG, BONE_HINGE, B_ARM_RECALCDATA, "Hinge", -10,by-38,85,18, &curBone->flag, 1.0, 32.0, 0.0, 0.0, "Don't inherit rotation or scale from parent Bone");
+ uiDefButBitI(block, TOGN, BONE_NO_DEFORM, B_ARM_RECALCDATA, "Deform", 75, by-38, 85, 18, &curBone->flag, 0.0, 0.0, 0.0, 0.0, "Indicate if Bone deforms geometry");
+ uiDefButBitI(block, TOG, BONE_MULT_VG_ENV, B_ARM_RECALCDATA, "Mult", 160,by-38,85,18, &curBone->flag, 1.0, 32.0, 0.0, 0.0, "Multiply Bone Envelope with VertexGroup");
+ uiDefButBitI(block, TOG, BONE_HIDDEN_A, REDRAWVIEW3D, "Hide", 245,by-38,85,18, &curBone->flag, 0, 0, 0, 0, "Toggles display of this bone in Edit Mode");
+
+ /* layers */
+ uiBlockBeginAlign(block);
+ for(a=0; a<8; a++) {
+ short dx= 21;
+ but= uiDefButBitS(block, TOG, 1<<a, REDRAWVIEW3D, "", -10+a*dx, by-57, dx, 15, &curBone->layer, 0, 0, 0, 0, "Armature layer that bone exists on");
+ uiButSetFunc(but, armature_layer_cb, &curBone->layer, (void *)(1<<a));
+ }
+ uiBlockBeginAlign(block);
+ for(a=8; a<16; a++) {
+ short dx= 21;
+ but= uiDefButBitS(block, TOG, 1<<a, REDRAWVIEW3D, "", -6+a*dx, by-57, dx, 15, &curBone->layer, 0, 0, 0, 0, "Armature layer that bone exists on");
+ uiButSetFunc(but, armature_layer_cb, &curBone->layer, (void *)(1<<a));
+ }
+
+ uiBlockEndAlign(block);
+ by-=80;
+
+ if(by < -200) break; // for time being... extreme long panels are very slow
+ }
+ }
+
+ if(by<0) {
+ uiNewPanelHeight(block, 204 - by);
+ }
+
+}
+
+/* sets warning popup for buttons, and returns 1 for protected proxy posechannels */
+static int ob_arm_bone_pchan_lock(Object *ob, bArmature *arm, Bone *bone, bPoseChannel *pchan)
+{
+ /* ob lib case is already set globally */
+ if(ob->id.lib)
+ return 0;
+ if(arm->id.lib) {
+ if(pchan==NULL)
+ uiSetButLock(1, ERROR_LIBDATA_MESSAGE);
+ else if(ob->proxy && bone->layer & arm->layer_protected) {
+ uiSetButLock(1, "Can't edit protected proxy channel");
+ return 1;
+ }
+ else
+ uiClearButLock();
+ }
+ return 0;
+}
+
+static void editing_panel_pose_bones(Object *ob, bArmature *arm)
+{
+ uiBlock *block;
+ uiBut *but;
+ bPoseChannel *pchan;
+ Bone *curBone;
+ int by, a;
+ int index, zerodof, zerolimit;
+
+ /* Draw the bone name block */
+ block= uiNewBlock(&curarea->uiblocks, "editing_panel_pose_bones", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Armature Bones", "Editing", 640, 0, 318, 204)==0) return;
+
+ /* this is a variable height panel, newpanel doesnt force new size on existing panels */
+ /* so first we make it default height */
+ uiNewPanelHeight(block, 204);
+
+ uiDefBut(block, LABEL, 0, "Selected Bones", 0,180,158,18, 0, 0, 0, 0, 0, "Only show in Armature Editmode/Posemode");
+ by= 160;
+
+ for (pchan=ob->pose->chanbase.first, index=0; pchan; pchan=pchan->next, index++){
+ curBone= pchan->bone;
+ if ((curBone->flag & BONE_SELECTED) && (curBone->layer & arm->layer)) {
+
+ if(ob_arm_bone_pchan_lock(ob, arm, curBone, pchan))
+ uiDefBut(block, LABEL, 0, "Proxy Locked", 160, 180,150,18, NULL, 1, 0, 0, 0, "");
+
+ /* Bone naming button */
+ uiBlockBeginAlign(block);
+ but=uiDefBut(block, TEX, REDRAWVIEW3D, "BO:", -10,by,117,19, curBone->name, 0, 24, 0, 0, "Change the bone name");
+ uiButSetFunc(but, validate_posebonebutton_cb, curBone, NULL);
+ uiButSetCompleteFunc(but, autocomplete_bone, (void *)ob);
+
+ /* Dist and weight buttons */
+ uiDefButF(block, NUM,B_ARM_RECALCDATA, "Dist:", 107, by, 105, 19, &curBone->dist, 0.0, 1000.0, 10.0, 0.0, "Bone deformation distance");
+ uiDefButF(block, NUM,B_ARM_RECALCDATA, "Weight:", 220, by, 110, 19, &curBone->weight, 0.0F, 1000.0F, 10.0F, 0.0F, "Bone deformation weight");
+
+ /* Segment, ease in/out buttons */
+ uiBlockBeginAlign(block);
+ uiDefButS(block, NUM, B_ARM_RECALCDATA, "Segm: ", -10,by-19,117,19, &curBone->segments, 1.0, 32.0, 0.0, 0.0, "Subdivisions for B-bones");
+ uiDefButF(block, NUM,B_ARM_RECALCDATA, "In:", 107, by-19,105, 19, &curBone->ease1, 0.0, 2.0, 10.0, 0.0, "First length of Bezier handle");
+ uiDefButF(block, NUM,B_ARM_RECALCDATA, "Out:", 220, by-19, 110, 19, &curBone->ease2, 0.0, 2.0, 10.0, 0.0, "Second length of Bezier handle");
+
+ /* bone types */
+ uiDefButBitI(block, TOG, BONE_HINGE, B_ARM_RECALCDATA, "Hinge", -10,by-38,80,19, &curBone->flag, 1.0, 32.0, 0.0, 0.0, "Don't inherit rotation or scale from parent Bone");
+ uiDefButBitI(block, TOGN, BONE_NO_DEFORM, B_ARM_RECALCDATA, "Deform", 70, by-38, 80, 19, &curBone->flag, 0.0, 0.0, 0.0, 0.0, "Indicate if Bone deforms geometry");
+ uiDefButBitI(block, TOG, BONE_MULT_VG_ENV, B_ARM_RECALCDATA, "Mult", 150,by-38,80,19, &curBone->flag, 1.0, 32.0, 0.0, 0.0, "Multiply Bone Envelope with VertexGroup");
+ ob_arm_bone_pchan_lock(ob, arm, curBone, pchan);
+ uiDefIDPoinBut(block, test_obpoin_but, ID_OB, REDRAWVIEW3D, "OB:", 230,by-38,100,19, &pchan->custom, "Object that defines custom draw type for this Bone");
+ ob_arm_bone_pchan_lock(ob, arm, curBone, NULL);
+
+ /* layers */
+ uiBlockBeginAlign(block);
+ for(a=0; a<8; a++) {
+ short dx= 21;
+ but= uiDefButBitS(block, TOG, 1<<a, REDRAWVIEW3D, "", -10+a*dx, by-57, dx, 15, &curBone->layer, 0, 0, 0, 0, "Armature layer that bone exists on");
+ uiButSetFunc(but, armature_layer_cb, &curBone->layer, (void *)(1<<a));
+ }
+ uiBlockBeginAlign(block);
+ for(a=8; a<16; a++) {
+ short dx= 21;
+ but= uiDefButBitS(block, TOG, 1<<a, REDRAWVIEW3D, "", -6+a*dx, by-57, dx, 15, &curBone->layer, 0, 0, 0, 0, "Armature layer that bone exists on");
+ uiButSetFunc(but, armature_layer_cb, &curBone->layer, (void *)(1<<a));
+ }
+ uiBlockEndAlign(block);
+
+ by-= 20;
+
+ ob_arm_bone_pchan_lock(ob, arm, curBone, pchan);
+
+ /* DOFs only for IK chains */
+ zerodof = 1;
+ zerolimit = 1;
+ if(pose_channel_in_IK_chain(ob, pchan)) {
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, BONE_IK_NO_XDOF, B_ARM_RECALCDATA, "Lock X Rot", -10,by-60,114,19, &pchan->ikflag, 0.0, 0.0, 0.0, 0.0, "Disable X DoF for IK");
+ if ((pchan->ikflag & BONE_IK_NO_XDOF)==0) {
+ uiDefButF(block, NUM, B_ARM_RECALCDATA, "Stiff X:", -10, by-80, 114, 19, &pchan->stiffness[0], 0.0, 0.99, 1.0, 0.0, "Resistance to bending for X axis");
+ uiDefButBitS(block, TOG, BONE_IK_XLIMIT, B_ARM_RECALCDATA, "Limit X", -10,by-100,114,19, &pchan->ikflag, 0.0, 0.0, 0.0, 0.0, "Limit rotation over X axis");
+ if ((pchan->ikflag & BONE_IK_XLIMIT)) {
+ uiDefButF(block, NUM, B_ARM_RECALCDATA, "Min X:", -10, by-120, 114, 19, &pchan->limitmin[0], -180.0, 0.0, 1000, 1, "Minimum X limit");
+ uiDefButF(block, NUM, B_ARM_RECALCDATA, "Max X:", -10, by-140, 114, 19, &pchan->limitmax[0], 0.0, 180.0f, 1000, 1, "Maximum X limit");
+ zerolimit = 0;
+ }
+ zerodof = 0;
+ }
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, BONE_IK_NO_YDOF, B_ARM_RECALCDATA, "Lock Y Rot", 104,by-60,113,19, &pchan->ikflag, 0.0, 0.0, 0.0, 0.0, "Disable Y DoF for IK");
+ if ((pchan->ikflag & BONE_IK_NO_YDOF)==0) {
+ uiDefButF(block, NUM, B_ARM_RECALCDATA, "Stiff Y:", 104, by-80, 114, 19, &pchan->stiffness[1], 0.0, 0.99, 1.0, 0.0, "Resistance to twisting over Y axis");
+ uiDefButBitS(block, TOG, BONE_IK_YLIMIT, B_ARM_RECALCDATA, "Limit Y", 104,by-100,113,19, &pchan->ikflag, 0.0, 0.0, 0.0, 0.0, "Limit rotation over Y axis");
+ if ((pchan->ikflag & BONE_IK_YLIMIT)) {
+ uiDefButF(block, NUM, B_ARM_RECALCDATA, "Min Y:", 104, by-120, 113, 19, &pchan->limitmin[1], -180.0, 0.0, 1000, 1, "Minimum Y limit");
+ uiDefButF(block, NUM, B_ARM_RECALCDATA, "Max Y:", 104, by-140, 113, 19, &pchan->limitmax[1], 0.0, 180.0, 1000, 1, "Maximum Y limit");
+ zerolimit = 0;
+ }
+ zerodof = 0;
+ }
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, BONE_IK_NO_ZDOF, B_ARM_RECALCDATA, "Lock Z Rot", 217,by-60,113,19, &pchan->ikflag, 0.0, 0.0, 0.0, 0.0, "Disable Z DoF for IK");
+ if ((pchan->ikflag & BONE_IK_NO_ZDOF)==0) {
+ uiDefButF(block, NUM, B_ARM_RECALCDATA, "Stiff Z:", 217, by-80, 114, 19, &pchan->stiffness[2], 0.0, 0.99, 1.0, 0.0, "Resistance to bending for Z axis");
+ uiDefButBitS(block, TOG, BONE_IK_ZLIMIT, B_ARM_RECALCDATA, "Limit Z", 217,by-100,113,19, &pchan->ikflag, 0.0, 0.0, 0.0, 0.0, "Limit rotation over Z axis");
+ if ((pchan->ikflag & BONE_IK_ZLIMIT)) {
+ uiDefButF(block, NUM, B_ARM_RECALCDATA, "Min Z:", 217, by-120, 113, 19, &pchan->limitmin[2], -180.0, 0.0, 1000, 1, "Minimum Z limit");
+ uiDefButF(block, NUM, B_ARM_RECALCDATA, "Max Z:", 217, by-140, 113, 19, &pchan->limitmax[2], 0.0, 180.0, 1000, 1, "Maximum Z limit");
+ zerolimit = 0;
+ }
+ zerodof = 0;
+ }
+ uiBlockEndAlign(block);
+
+ by -= (zerodof)? 82: (zerolimit)? 122: 162;
+
+ uiDefButF(block, NUM, B_ARM_RECALCDATA, "Stretch:", -10, by, 113, 19, &pchan->ikstretch, 0.0, 1.0, 1.0, 0.0, "Allow scaling of the bone for IK");
+
+ by -= 20;
+ }
+ else {
+ but= uiDefButBitS(block, TOG, POSE_STRIDE, B_ARM_STRIDE, "Stride Root", -10, by-60, 113, 19, &pchan->flag, 0.0, 0.0, 0, 0, "Set this PoseChannel to define the Stride distance");
+ uiButSetFunc(but, validate_stridebutton_cb, pchan, NULL);
+
+ uiDefBut(block, LABEL, 0, "(DoF only for IK chains)", 110,by-60, 190, 19, 0, 0, 0, 0, 0, "");
+ by -= 82;
+ }
+
+
+ if(by < -200) break; // for time being... extreme long panels are very slow
+ }
+ }
+
+ if(by<0) {
+ uiNewPanelHeight(block, 204 - by);
+ }
+
+}
+
+
+/* *************************** MESH ******************************** */
+
+/* from this object to all objects with same ob->data */
+static void copy_linked_vgroup_channels(Object *ob)
+{
+ Base *base;
+
+ for(base=FIRSTBASE; base; base= base->next) {
+ if(base->object->type==ob->type) {
+ if(base->object!=ob && base->object->data==ob->data) {
+ BLI_freelistN(&base->object->defbase);
+ duplicatelist(&base->object->defbase, &ob->defbase);
+ base->object->actdef= ob->actdef;
+ DAG_object_flush_update(G.scene, base->object, OB_RECALC_DATA);
+ }
+ }
+ }
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+}
+
+void do_vgroupbuts(unsigned short event)
+{
+ Object *ob= OBACT;
+
+ switch(event) {
+ case B_NEWVGROUP:
+ add_defgroup (ob);
+ scrarea_queue_winredraw(curarea);
+ allqueue(REDRAWOOPS, 0);
+ break;
+ case B_DELVGROUP:
+ if ((G.obedit) && (G.obedit == ob))
+ del_defgroup (ob);
+ else
+ del_defgroup_in_object_mode (ob);
+ allqueue (REDRAWVIEW3D, 1);
+ allqueue(REDRAWOOPS, 0);
+ BIF_undo_push("Delete vertex group");
+ break;
+ case B_ASSIGNVGROUP:
+ assign_verts_defgroup ();
+ allqueue (REDRAWVIEW3D, 1);
+ BIF_undo_push("Assign to vertex group");
+ break;
+ case B_REMOVEVGROUP:
+ remove_verts_defgroup (0);
+ allqueue (REDRAWVIEW3D, 1);
+ allqueue(REDRAWOOPS, 0);
+ BIF_undo_push("Remove from vertex group");
+ break;
+ case B_SELVGROUP:
+ sel_verts_defgroup(1);
+ allqueue (REDRAWVIEW3D, 1);
+ allqueue(REDRAWOOPS, 0);
+ countall();
+ break;
+ case B_DESELVGROUP:
+ sel_verts_defgroup(0);
+ allqueue (REDRAWVIEW3D, 1);
+ allqueue(REDRAWOOPS, 0);
+ countall();
+ break;
+ case B_LINKEDVGROUP:
+ copy_linked_vgroup_channels(ob);
+ break;
+ case B_COPYVGROUP:
+ duplicate_defgroup (ob);
+ scrarea_queue_winredraw (curarea);
+ allqueue (REDRAWOOPS, 0);
+ break;
+ }
+}
+
+void do_meshbuts(unsigned short event)
+{
+ Object *ob;
+ Mesh *me;
+ MCol *mcol;
+ EditMesh *em= G.editMesh;
+ float fac;
+ int count; /* store num of changes made to see if redraw & undo are needed*/
+ int layernum;
+ short randfac;
+
+ ob= OBACT;
+ if(ob && ob->type==OB_MESH) {
+
+ me= get_mesh(ob);
+ if(me==NULL) return;
+
+ switch(event) {
+ case B_DELSTICKY:
+ if(me->msticky) {
+ CustomData_free_layer_active(&me->vdata, CD_MSTICKY, me->totvert);
+ me->msticky= NULL;
+ BIF_undo_push("Delete Sticky");
+ }
+ allqueue(REDRAWBUTSEDIT, 0);
+ break;
+ case B_MAKESTICKY:
+ RE_make_sticky();
+ BIF_undo_push("Make Sticky");
+ allqueue(REDRAWBUTSEDIT, 0);
+ break;
+
+ case B_NEWMCOL:
+ if(G.obedit) {
+ layernum= CustomData_number_of_layers(&em->fdata, CD_MCOL);
+ EM_add_data_layer(&em->fdata, CD_MCOL);
+ CustomData_set_layer_active(&em->fdata, CD_MCOL, layernum);
+ }
+ else if(me) {
+ mcol= me->mcol;
+ layernum= CustomData_number_of_layers(&me->fdata, CD_MCOL);
+
+ if(mcol)
+ CustomData_add_layer(&me->fdata, CD_MCOL, CD_DUPLICATE,
+ mcol, me->totface);
+ else
+ CustomData_add_layer(&me->fdata, CD_MCOL, CD_CALLOC,
+ NULL, me->totface);
+
+ CustomData_set_layer_active(&me->fdata, CD_MCOL, layernum);
+ mesh_update_customdata_pointers(me);
+
+ if(!mcol)
+ shadeMeshMCol(ob, me);
+ }
+
+ if (me->mr) multires_load_cols(me);
+
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ BIF_undo_push("New Vertex Color");
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ break;
+ case B_SETMCOL:
+ if (G.obedit || me) {
+ CustomData *fdata= (G.obedit)? &em->fdata: &me->fdata;
+ CustomData_set_layer_active(fdata, CD_MCOL, actmcol-1);
+ mesh_update_customdata_pointers(me);
+
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ BIF_undo_push("Set Active Vertex Color");
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ }
+ break;
+ case B_SETMCOL_RND:
+ if (G.obedit || me) {
+ CustomData *fdata= (G.obedit)? &em->fdata: &me->fdata;
+ CustomData_set_layer_render(fdata, CD_MCOL, actmcol_rnd-1);
+
+ BIF_undo_push("Set Render Vertex Color");
+ allqueue(REDRAWBUTSEDIT, 0);
+ }
+ break;
+
+ case B_NEWTFACE:
+ if(me)
+ layernum= CustomData_number_of_layers(&me->fdata, CD_MTFACE);
+ else
+ layernum= CustomData_number_of_layers(&em->fdata, CD_MTFACE);
+
+ if(me && me->mr) {
+ multires_add_layer(me, &me->mr->fdata, CD_MTFACE, layernum);
+ }
+ else if(G.obedit) {
+ EM_add_data_layer(&em->fdata, CD_MTFACE);
+ CustomData_set_layer_active(&em->fdata, CD_MTFACE, layernum);
+ }
+ else if(me) {
+ if(me->mtface)
+ CustomData_add_layer(&me->fdata, CD_MTFACE, CD_DUPLICATE,
+ me->mtface, me->totface);
+ else
+ CustomData_add_layer(&me->fdata, CD_MTFACE, CD_DEFAULT,
+ NULL, me->totface);
+
+ CustomData_set_layer_active(&me->fdata, CD_MTFACE, layernum);
+ mesh_update_customdata_pointers(me);
+ }
+
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ BIF_undo_push("New UV Texture");
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWIMAGE, 0);
+ break;
+ case B_SETTFACE:
+ if (G.obedit || me) {
+ CustomData *fdata= (G.obedit)? &em->fdata: &me->fdata;
+
+ CustomData_set_layer_active(fdata, CD_MTFACE, acttface-1);
+ mesh_update_customdata_pointers(me);
+
+ /* Update first-level face data in multires */
+ if(me && me->mr && me->mr->current != 1)
+ CustomData_set_layer_active(&me->mr->fdata, CD_MTFACE, acttface-1);
+
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ BIF_undo_push("Set Active UV Texture");
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWIMAGE, 0);
+ }
+ break;
+ case B_SETTFACE_RND:
+ if (G.obedit || me) {
+ CustomData *fdata= (G.obedit)? &em->fdata: &me->fdata;
+ CustomData_set_layer_render(fdata, CD_MTFACE, acttface_rnd-1);
+ BIF_undo_push("Set Render UV Texture");
+ allqueue(REDRAWBUTSEDIT, 0);
+ }
+ break;
+
+ case B_FLIPNORM:
+ if(G.obedit) {
+ flip_editnormals();
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ BIF_undo_push("Flip Normals");
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ break;
+ }
+ }
+ if(G.obedit==NULL || (G.obedit->type!=OB_MESH)) return;
+
+ switch(event) {
+ case B_SPIN:
+ if( select_area(SPACE_VIEW3D)) spin_mesh(G.scene->toolsettings->step, G.scene->toolsettings->degr, 0, 0);
+ break;
+ case B_SPINDUP:
+ if( select_area(SPACE_VIEW3D)) spin_mesh(G.scene->toolsettings->step, G.scene->toolsettings->degr, 0, 1);
+ break;
+ case B_EXTR:
+ G.f |= G_DISABLE_OK;
+ if( select_area(SPACE_VIEW3D)) extrude_mesh();
+ G.f -= G_DISABLE_OK;
+ break;
+ case B_SCREW:
+ if( select_area(SPACE_VIEW3D)) screw_mesh(G.scene->toolsettings->step, G.scene->toolsettings->turn);
+ break;
+ case B_EXTREP:
+ if( select_area(SPACE_VIEW3D)) extrude_repeat_mesh(G.scene->toolsettings->step, G.scene->toolsettings->extr_offs);
+ break;
+ case B_SPLIT:
+ G.f |= G_DISABLE_OK;
+ split_mesh();
+ G.f -= G_DISABLE_OK;
+ break;
+ case B_REMDOUB:
+ count= removedoublesflag(1, 1, G.scene->toolsettings->doublimit);
+ notice("Removed: %d", count);
+ if (count) { /* only undo and redraw if an action is taken */
+ countall ();
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ BIF_undo_push("Rem Doubles");
+ }
+ break;
+ case B_SUBDIV:
+ waitcursor(1);
+ esubdivideflag(1, 0.0, G.scene->toolsettings->editbutflag,1,0);
+ countall();
+ waitcursor(0);
+ allqueue(REDRAWVIEW3D, 0);
+ BIF_undo_push("Subdivide");
+ break;
+ case B_FRACSUBDIV:
+ randfac= 10;
+ if(button(&randfac, 1, 100, "Rand fac:")==0) return;
+ waitcursor(1);
+ fac= -( (float)randfac )/100;
+ esubdivideflag(1, fac, G.scene->toolsettings->editbutflag,1,0);
+ countall();
+ waitcursor(0);
+ allqueue(REDRAWVIEW3D, 0);
+ BIF_undo_push("Fractal Subdivide");
+ break;
+ case B_XSORT:
+ if( select_area(SPACE_VIEW3D)) xsortvert_flag(1);
+ break;
+ case B_HASH:
+ hashvert_flag(1);
+ break;
+ case B_TOSPHERE:
+ vertices_to_sphere();
+ break;
+ case B_VERTEXNOISE:
+ vertexnoise();
+ break;
+ case B_VERTEXSMOOTH:
+ vertexsmooth();
+ break;
+ case B_DRAWEDGES:
+ G.f &= ~G_DRAWCREASES;
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+ case B_DRAWCREASES:
+ G.f &= ~G_DRAWEDGES;
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+ case B_JOINTRIA:
+ join_triangles();
+ break;
+ }
+
+ /* WATCH IT: previous events only in editmode! */
+}
+
+static void editing_panel_mesh_tools(Object *ob, Mesh *me)
+{
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "editing_panel_mesh_tools", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Mesh Tools", "Editing", 640, 0, 318, 254)==0) return;
+
+ uiBlockBeginAlign(block);
+ //uiDefButBitS(block, TOG, B_AUTOFGON, 0, "FGon", 10,195,30,19, &G.scene->toolsettings->editbutflag, 0, 0, 0, 0, "Causes 'Subdivide' To create FGon on inner edges where possible");
+ uiDefButBitS(block, TOG, B_BEAUTY, 0, "Beauty", 10,195,53,19, &G.scene->toolsettings->editbutflag, 0, 0, 0, 0, "Causes 'Subdivide' to split faces in halves instead of quarters using long edges unless 'Short' is selected");
+ uiDefButBitS(block, TOG, B_BEAUTY_SHORT, 0, "Short", 63,195,52,19, &G.scene->toolsettings->editbutflag, 0, 0, 0, 0, "If Beauty is set, 'Subdivide' splits faces in halves using short edges");
+
+ uiDefBut(block, BUT,B_SUBDIV,"Subdivide", 115,195,105,19, 0, 0, 0, 0, 0, "Splits selected faces into halves or quarters");
+
+ uiDefButS(block, MENU, B_DIFF, "Corner Cut Type %t|Path %x0|Innervert %x1|Fan %x2",
+ 220, 195, 105, 19, &G.scene->toolsettings->cornertype , 0, 0, 0, 0, "Choose Quad Corner Cut Type");
+
+ uiDefBut(block, BUT,B_VERTEXNOISE,"Noise", 10,175,78,19, 0, 0, 0, 0, 0, "Use vertex coordinate as texture coordinate");
+ uiDefBut(block, BUT,B_HASH,"Hash", 88,175,78,19, 0, 0, 0, 0, 0, "Randomizes selected vertex sequence data");
+ uiDefBut(block, BUT,B_XSORT,"Xsort", 166,175,78,19, 0, 0, 0, 0, 0, "Sorts selected vertex data in the X direction");
+ uiDefBut(block, BUT,B_FRACSUBDIV, "Fractal", 244,175,81,19, 0, 0, 0, 0, 0, "Subdivides selected faces with a random factor");
+
+
+ uiDefBut(block, BUT,B_TOSPHERE,"To Sphere", 10,155,78,19, 0, 0, 0, 0, 0, "Moves selected vertices outwards into a spherical shape");
+ uiDefBut(block, BUT,B_VERTEXSMOOTH,"Smooth", 88,155,78,19, 0, 0, 0, 0, 0, "Flattens angles of selected faces");
+ uiDefBut(block, BUT,B_SPLIT,"Split", 166,155,78,19, 0, 0, 0, 0, 0, "Splits selected vertices to separate sub-mesh");
+ uiDefBut(block, BUT,B_FLIPNORM,"Flip Normals", 244,155,81,19, 0, 0, 0, 0, 0, "Toggles the direction of the selected face's normals");
+
+ uiDefBut(block, BUT,B_REMDOUB,"Rem Doubles", 10,135,78,19, 0, 0, 0, 0, 0, "Removes duplicates from selected vertices");
+ uiDefButF(block, NUM, B_DIFF, "Limit:", 88,135,117,19, &G.scene->toolsettings->doublimit, 0.0001, 1.0, 10, 0, "Specifies the max distance 'Rem Doubles' will consider vertices as 'doubled'");
+ uiDefButF(block, NUM, B_DIFF, "Threshold:", 205,135,120,19, &G.scene->toolsettings->select_thresh, 0.0001, 1.0, 10, 0, "Tolerence for the 'Select Group' tool (Shift+G) and 'Knife Exact' (vertex snap).");
+ uiBlockEndAlign(block);
+
+ uiDefBut(block, BUT,B_EXTR,"Extrude", 10,105,315,24, 0, 0, 0, 0, 0, "Converts selected edges to faces and selects the new vertices");
+
+ uiBlockBeginAlign(block);
+ uiDefBut(block, BUT,B_SPIN, "Spin", 10,75,100,24, 0, 0, 0, 0, 0, "Extrudes the selected vertices in a circle around the cursor in the indicated viewport");
+ uiDefBut(block, BUT,B_SPINDUP,"Spin Dup", 110,75,100,24, 0, 0, 0, 0, 0, "Creates copies of the selected vertices in a circle around the cursor in the indicated viewport");
+ uiDefBut(block, BUT,B_SCREW,"Screw", 210,75,115,24, 0, 0, 0, 0, 0, "Activates the screw tool"); // Bish - This could use some more definition
+
+ uiDefButF(block, NUM, B_DIFF, "Degr:", 10,55,100,19, &G.scene->toolsettings->degr,-360.0,360.0, 1000, 0, "Specifies the number of degrees 'Spin' revolves");
+ uiDefButS(block, NUM, B_DIFF, "Steps:", 110,55,100,19, &G.scene->toolsettings->step,1.0,180.0, 0, 0, "Specifies the total number of 'Spin' slices");
+ uiDefButS(block, NUM, B_DIFF, "Turns:", 210,55,115,19, &G.scene->toolsettings->turn,1.0,360.0, 0, 0, "Specifies the number of revolutions the screw turns");
+ uiDefButBitS(block, TOG, B_KEEPORIG, B_DIFF, "Keep Original",10,35,200,19, &G.scene->toolsettings->editbutflag, 0, 0, 0, 0, "Keeps a copy of the original vertices and faces after executing tools");
+ uiDefButBitS(block, TOG, B_CLOCKWISE, B_DIFF, "Clockwise", 210,35,115,19, &G.scene->toolsettings->editbutflag, 0, 0, 0, 0, "Specifies the direction for 'Screw' and 'Spin'");
+
+ uiBlockBeginAlign(block);
+ uiDefBut(block, BUT,B_EXTREP, "Extrude Dup", 10,10,150,19, 0, 0, 0, 0, 0, "Creates copies of the selected vertices in a straight line away from the current viewport");
+ uiDefButF(block, NUM, B_DIFF, "Offset:", 160,10,165,19, &G.scene->toolsettings->extr_offs, 0.01, 100.0, 100, 0, "Sets the distance between each copy for 'Extrude Dup'");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefBut(block, BUT, B_JOINTRIA, "Join Triangles", 10, -20, 120, 19, 0, 0, 0, 0, 0, "Convert selected triangles to Quads");
+ uiDefButF(block, NUM, B_DIFF, "Threshold", 130, -20, 195, 19, &G.scene->toolsettings->jointrilimit, 0.0, 1.0, 5, 0, "Conversion threshold for complex islands");
+ uiDefButBitS(block, TOG, B_JOINTRIA_UV, 0, "Delimit UVs", 10, -40, 78, 19, &G.scene->toolsettings->editbutflag, 0,0,0,0, "Join pairs only where UVs match");
+ uiDefButBitS(block, TOG, B_JOINTRIA_VCOL, 0, "Delimit Vcol", 90, -40, 78, 19, &G.scene->toolsettings->editbutflag, 0,0,0,0, "Join pairs only where Vcols match");
+ uiDefButBitS(block, TOG, B_JOINTRIA_SHARP, 0, "Delimit Sharp", 170, -40, 78, 19, &G.scene->toolsettings->editbutflag, 0,0,0,0, "Join pairs only where edge is not sharp");
+ uiDefButBitS(block, TOG, B_JOINTRIA_MAT, 0, "Delimit Mat", 250, -40, 74, 19, &G.scene->toolsettings->editbutflag, 0,0,0,0, "Join pairs only where material matches");
+ uiBlockEndAlign(block);
+
+
+}
+
+static void verify_vertexgroup_name_func(void *datav, void *data2_unused)
+{
+ unique_vertexgroup_name((bDeformGroup*)datav, OBACT);
+}
+
+
+
+static void editing_panel_mesh_tools1(Object *ob, Mesh *me)
+{
+ uiBlock *block;
+
+
+ block= uiNewBlock(&curarea->uiblocks, "editing_panel_mesh_tools1", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Mesh Tools 1", "Editing", 960, 0, 318, 204)==0) return;
+
+ uiBlockBeginAlign(block);
+ uiDefBut(block, BUT,B_SELSWAP, "Select Swap", 955, 200, 106, 19, 0, 0, 0, 0, 0, "Selects unselected faces, and deselects selected faces (Ctrl+I)");
+ uiDefBut(block, BUT,B_HIDE, "Hide", 1061, 200, 106, 19, 0, 0, 0, 0, 0, "Hides selected faces (H)");
+ uiDefBut(block, BUT,B_REVEAL, "Reveal", 1167, 200, 107, 19, 0, 0, 0, 0, 0, "Reveals selected faces (Alt H)");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, REDRAWVIEW3D, "NSize:", 955, 170, 150, 19, &G.scene->editbutsize, 0.001, 2.0, 10, 0, "Sets the length to use when displaying face normals");
+ uiDefButBitI(block, TOG, G_DRAWNORMALS, REDRAWVIEW3D, "Draw Normals", 955,148,150,19, &G.f, 0, 0, 0, 0, "Displays face normals as lines");
+ uiDefButBitI(block, TOG, G_DRAW_VNORMALS, REDRAWVIEW3D, "Draw VNormals",955,126,150,19, &G.f, 0, 0, 0, 0, "Displays vertex normals as lines");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOG, G_DRAWFACES, REDRAWVIEW3D_IMAGE, "Draw Faces", 955,88,150,19, &G.f, 0, 0, 0, 0, "Displays all faces as shades in the 3d view and UV editor");
+ uiDefButBitI(block, TOG, G_DRAWEDGES, REDRAWVIEW3D, "Draw Edges", 955,66,150,19, &G.f, 0, 0, 0, 0, "Displays selected edges using hilights");
+ uiDefButBitI(block, TOG, G_DRAWCREASES, REDRAWVIEW3D, "Draw Creases", 955,44,150,19, &G.f, 0, 0, 0, 0, "Displays creases created for subsurf weighting");
+ uiDefButBitI(block, TOG, G_DRAWSEAMS, REDRAWVIEW3D, "Draw Seams", 955,22,150,19, &G.f, 0, 0, 0, 0, "Displays UV unwrapping seams");
+ uiDefButBitI(block, TOG, G_DRAWSHARP, REDRAWVIEW3D, "Draw Sharp", 955,0,150,19, &G.f, 0, 0, 0, 0, "Displays sharp edges, used with the EdgeSplit modifier");
+ uiBlockEndAlign(block);
+
+ /* Measurement drawing options */
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOG, G_DRAW_EDGELEN, REDRAWVIEW3D, "Edge Length", 1125,170,150,19, &G.f, 0, 0, 0, 0, "Displays selected edge lengths");
+ uiDefButBitI(block, TOG, G_DRAW_EDGEANG, REDRAWVIEW3D, "Edge Angles", 1125,148,150,19, &G.f, 0, 0, 0, 0, "Displays the angles in the selected edges in degrees");
+ uiDefButBitI(block, TOG, G_DRAW_FACEAREA, REDRAWVIEW3D, "Face Area", 1125,126,150,19, &G.f, 0, 0, 0, 0, "Displays the area of selected faces");
+#ifdef WITH_VERSE
+ if(G.editMesh->vnode)
+ uiDefButBitI(block, TOG, G_DRAW_VERSE_DEBUG, REDRAWVIEW3D, "Draw VDebug",1125,104,150,19, &G.f, 0, 0, 0, 0, "Displays verse debug information");
+#endif
+
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOG, G_ALLEDGES, 0, "All Edges", 1125, 22,150,19, &G.f, 0, 0, 0, 0, "Displays all edges in object mode without optimization");
+ uiDefButBitS(block, TOG, B_MESH_X_MIRROR, B_DIFF, "X-axis mirror",1125,0,150,19, &G.scene->toolsettings->editbutflag, 0, 0, 0, 0, "While using transforms, mirrors the transformation");
+ uiBlockEndAlign(block);
+}
+
+char *get_vertexgroup_menustr(Object *ob)
+{
+ bDeformGroup *dg;
+ int defCount, min, index;
+ char (*qsort_ptr)[sizeof(dg->name)+5] = NULL; // +5 for "%x99|"
+ char *s, *menustr;
+ int printed;
+
+ defCount=BLI_countlist(&ob->defbase);
+
+ if (!defCount) min=0;
+ else min=1;
+
+ if (defCount > 0) {
+ /*
+ * This will hold the group names temporarily
+ * so we can sort them
+ */
+ qsort_ptr = MEM_callocN (defCount * sizeof (qsort_ptr[0]),
+ "qsort_ptr");
+ for (index = 1, dg = ob->defbase.first; dg; index++, dg=dg->next) {
+ printed = snprintf (qsort_ptr[index - 1], sizeof (dg->name), dg->name);
+ snprintf (qsort_ptr[index - 1]+printed, 5+1, "%%x%d|", index); // +1 to move the \0
+ }
+
+ qsort (qsort_ptr, defCount, sizeof (qsort_ptr[0]),
+ ( int (*)(const void *, const void *) ) strcmp);
+ }
+
+ s= menustr = MEM_callocN((sizeof(qsort_ptr[0]) * defCount)+30, "menustr"); // plus 30 for when defCount==0
+ if(defCount) {
+ for (index = 0; index < defCount; index++) {
+ int cnt= sprintf (s, "%s", qsort_ptr[index]);
+ if (cnt>0) s+= cnt;
+ }
+ }
+ else strcpy(menustr, "No Vertex Groups in Object");
+
+ if (qsort_ptr)
+ MEM_freeN (qsort_ptr);
+
+ return menustr;
+}
+
+static void editing_panel_links(Object *ob)
+{
+ uiBlock *block;
+ ID *id, *idfrom;
+ int *poin, xco=143;
+ float min;
+ Material *ma;
+ char str[64];
+ uiBut *but;
+
+ block= uiNewBlock(&curarea->uiblocks, "editing_panel_links", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Link and Materials", "Editing", 0, 0, 318, 204)==0) return;
+
+ uiSetButLock((ob && ob->id.lib), ERROR_LIBDATA_MESSAGE);
+
+ buttons_active_id(&id, &idfrom);
+
+ if(id) {
+ int alone= 0;
+ int local= 0;
+ int browse= B_EDITBROWSE;
+
+ if(ob->type==OB_MESH) {
+ browse= B_MESHBROWSE;
+ alone= B_MESHALONE;
+ local= B_MESHLOCAL;
+ uiSetButLock(G.obedit!=0, "Unable to perform function in EditMode");
+ }
+ else if(ob->type==OB_MBALL) {
+ alone= B_MBALLALONE;
+ local= B_MBALLLOCAL;
+ }
+ else if ELEM3(ob->type, OB_CURVE, OB_FONT, OB_SURF) {
+ alone= B_CURVEALONE;
+ local= B_CURVELOCAL;
+ }
+ else if(ob->type==OB_CAMERA) {
+ alone= B_CAMERAALONE;
+ local= B_CAMERALOCAL;
+ }
+ else if(ob->type==OB_LAMP) {
+ alone= B_LAMPALONE;
+ local= B_LAMPLOCAL;
+ }
+ else if (ob->type==OB_ARMATURE){
+ alone = B_ARMALONE;
+ local = B_ARMLOCAL;
+ }
+ else if(ob->type==OB_LATTICE) {
+ alone= B_LATTALONE;
+ local= B_LATTLOCAL;
+ }
+ uiBlockSetCol(block, TH_BUT_SETTING2);
+ xco= std_libbuttons(block, 143, 180, 0, NULL, browse, GS(id->name), 0, id, idfrom, &(G.buts->menunr), alone, local, 0, 0, B_KEEPDATA);
+ uiBlockSetCol(block, TH_AUTO);
+ }
+ if(ob) {
+ uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
+ but = uiDefBut(block, TEX, B_IDNAME, "OB:", xco, 180, 454-xco, YIC, ob->id.name+2, 0.0, 21.0, 0, 0, "Active Object name.");
+#ifdef WITH_VERSE
+ if(ob->vnode) uiButSetFunc(but, test_and_send_idbutton_cb, ob, ob->id.name);
+ else uiButSetFunc(but, test_idbutton_cb, ob->id.name, NULL);
+#else
+ uiButSetFunc(but, test_idbutton_cb, ob->id.name, NULL);
+#endif
+
+ }
+
+ /* empty display handling, note it returns! */
+ if (ob->type==OB_EMPTY) {
+ uiDefBut(block, LABEL,0,"Empty Display:",
+ xco, 154, 130,20, 0, 0, 0, 0, 0, "");
+
+ uiBlockBeginAlign(block);
+ uiDefButC(block, MENU, REDRAWVIEW3D, "Empty Drawtype%t|Arrows%x1|Single Arrow%x4|Plain Axes%x2|Circle%x3|Cube%x5",
+ xco, 128, 140, 20, &ob->empty_drawtype, 0, 0, 0, 0, "The Empty 3D View display style");
+ uiDefButF(block, NUM, REDRAWVIEW3D, "Size:",
+ xco, 108, 140, 21, &ob->empty_drawsize, 0.01, 10.0, 1, 0, "The size to display the Empty");
+ uiBlockEndAlign(block);
+ return;
+ }
+
+ /* vertex group... partially editmode... */
+ if(ob->type==OB_MESH || ob->type==OB_LATTICE) {
+ bDeformGroup *defGroup;
+ uiBut *but;
+ int defCount;
+
+ uiDefBut(block, LABEL,0,"Vertex Groups",
+ 143,153,130,20, 0, 0, 0, 0, 0, "");
+
+ defCount=BLI_countlist(&ob->defbase);
+
+ if (defCount) {
+ char *menustr= get_vertexgroup_menustr(ob);
+
+ uiBlockBeginAlign(block);
+
+ uiDefButS(block, MENU, B_MAKEDISP, menustr, 143, 132,18,21, (short *)&ob->actdef, 1, defCount, 0, 0, "Browses available vertex groups");
+ MEM_freeN (menustr);
+
+ if (ob->actdef){
+ defGroup = BLI_findlink(&ob->defbase, ob->actdef-1);
+ but= uiDefBut(block, TEX, REDRAWBUTSEDIT,"", 161,132,140-18,21, defGroup->name, 0, 31, 0, 0, "Displays current vertex group name. Click to change. (Match bone name for deformation.)");
+ uiButSetFunc(but, verify_vertexgroup_name_func, defGroup, NULL);
+ uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)ob);
+
+ uiDefButF(block, NUM, REDRAWVIEW3D, "Weight:", 143, 111, 140, 21, &editbutvweight, 0, 1, 10, 0, "Sets the current vertex group's bone deformation strength");
+ }
+ uiBlockEndAlign(block);
+ }
+
+ if (G.obedit && G.obedit==ob){
+ uiBlockBeginAlign(block);
+ uiDefBut(block, BUT,B_NEWVGROUP,"New", 143,90,70,21, 0, 0, 0, 0, 0, "Creates a new vertex group");
+ uiDefBut(block, BUT,B_DELVGROUP,"Delete", 213,90,70,21, 0, 0, 0, 0, 0, "Removes the current vertex group");
+
+ uiDefBut(block, BUT,B_ASSIGNVGROUP,"Assign", 143,69,70,21, 0, 0, 0, 0, 0, "Assigns selected vertices to the current vertex group");
+ uiDefBut(block, BUT,B_REMOVEVGROUP,"Remove", 213,69,70,21, 0, 0, 0, 0, 0, "Removes selected vertices from the current vertex group");
+
+ uiDefBut(block, BUT,B_SELVGROUP,"Select", 143,48,70,21, 0, 0, 0, 0, 0, "Selects vertices belonging to the current vertex group");
+ uiDefBut(block, BUT,B_DESELVGROUP,"Desel.", 213,48,70,21, 0, 0, 0, 0, 0, "Deselects vertices belonging to the current vertex group");
+ uiBlockEndAlign(block);
+ }
+ else {
+ ID *id= ob->data;
+
+ uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
+
+ uiBlockBeginAlign (block);
+ uiDefBut (block, BUT, B_NEWVGROUP, "New", 143, 90, 70, 21, 0, 0, 0, 0, 0, "Creates a new vertex group");
+ uiDefBut (block, BUT, B_DELVGROUP, "Delete", 213, 90, 70, 21, 0, 0, 0, 0, 0, "Removes the current vertex group");
+ uiDefBut (block, BUT, B_COPYVGROUP, "Copy Group", 143, 70, 140, 19, 0, 0, 0, 0, 0, "Copy Group of Vertex");
+ uiBlockEndAlign (block);
+
+ if(id->us > 1)
+ uiDefBut(block, BUT,B_LINKEDVGROUP, "Copy To Linked", 143,50,140,20, 0, 0, 0, 0, 0, "Creates identical vertex group names in other Objects using this Object-data");
+ }
+ }
+
+ /* now only objects that can be visible rendered */
+ if ELEM5(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL);
+ else return;
+
+ id= ob->data;
+ uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
+
+ if(ob->type==OB_MESH) poin= &( ((Mesh *)ob->data)->texflag );
+ else if(ob->type==OB_MBALL) poin= &( ((MetaBall *)ob->data)->texflag );
+ else poin= &( ((Curve *)ob->data)->texflag );
+ uiDefButBitI(block, TOG, AUTOSPACE, B_AUTOTEX, "AutoTexSpace", 143,15,140,19, poin, 0, 0, 0, 0, "Adjusts active object's texture space automatically when transforming object");
+
+ sprintf(str,"%d Mat ", ob->totcol);
+ if(ob->totcol) min= 1.0; else min= 0.0;
+ ma= give_current_material(ob, ob->actcol);
+
+ if(ma) uiDefBut(block, LABEL, 0, ma->id.name+2, 318,153, 103, 20, 0, 0, 0, 0, 0, "");
+
+ uiBlockBeginAlign(block);
+ if(ma) uiDefButF(block, COL, B_REDR, "", 292,123,31,30, &(ma->r), 0, 0, 0, 0, "");
+ uiDefButC(block, NUM, B_ACTCOL, str, 324,123,100,30, &ob->actcol, min, (float)(ob->totcol), 0, 0, "Displays total number of material indices and the current index");
+ uiDefBut(block, BUT,B_MATWICH, "?", 424,123,30,30, 0, 0, 0, 0, 0, "In EditMode, sets the active material index from selected faces");
+
+ uiBlockBeginAlign(block);
+ uiDefBut(block, BUT,B_MATNEW, "New", 292,98,80,20, 0, 0, 0, 0, 0, "Adds a new Material index");
+ uiDefBut(block, BUT,B_MATDEL, "Delete", 374,98,80,20, 0, 0, 0, 0, 0, "Deletes this Material index");
+ uiDefBut(block, BUT,B_MATSEL, "Select", 292,76,80,20, 0, 0, 0, 0, 0, "In EditMode, selects faces that have the active index");
+ uiDefBut(block, BUT,B_MATDESEL, "Deselect", 374,76,80,20, 0, 0, 0, 0, 0, "Deselects everything with current indexnumber");
+ uiDefBut(block, BUT,B_MATASS, "Assign", 292,47,162,26, 0, 0, 0, 0, 0, "In EditMode, assigns the active index to selected faces");
+
+ uiBlockBeginAlign(block);
+ uiDefBut(block, BUT,B_SETSMOOTH,"Set Smooth", 291,15,80,20, 0, 0, 0, 0, 0, "In EditMode, sets 'smooth' rendering of selected faces");
+ uiDefBut(block, BUT,B_SETSOLID, "Set Solid", 373,15,80,20, 0, 0, 0, 0, 0, "In EditMode, sets 'solid' rendering of selected faces");
+
+ uiBlockEndAlign(block);
+
+
+}
+
+void editing_panel_sculpting_tools()
+{
+ uiBlock *block= uiNewBlock(&curarea->uiblocks, "editing_panel_sculpting_tools", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Sculpt", "Editing", 300, 0, 318, 204)==0) return;
+
+ sculptmode_draw_interface_tools(block,0,200);
+}
+
+void editing_panel_sculpting_textures()
+{
+ uiBlock *block= uiNewBlock(&curarea->uiblocks, "editing_panel_sculpting_textures", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Brush", "Editing", 300, 0, 318, 204)==0) return;
+
+ sculptmode_draw_interface_textures(block,0,200);
+}
+
+void sculptmode_draw_interface_tools(uiBlock *block, unsigned short cx, unsigned short cy)
+{
+ SculptData *sd;
+ uiBut *but;
+
+ if(!G.scene) return;
+ sd= &G.scene->sculptdata;
+
+ uiBlockBeginAlign(block);
+
+ uiDefBut(block,LABEL,B_NOP,"Brush",cx,cy,90,19,NULL,0,0,0,0,"");
+ cy-= 20;
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block,ROW,REDRAWBUTSEDIT,"Draw",cx,cy,67,19,&sd->brush_type,14.0,DRAW_BRUSH,0,0,"Draw lines on the model");
+ uiDefButS(block,ROW,REDRAWBUTSEDIT,"Smooth",cx+67,cy,67,19,&sd->brush_type,14.0,SMOOTH_BRUSH,0,0,"Interactively smooth areas of the model");
+ uiDefButS(block,ROW,REDRAWBUTSEDIT,"Pinch",cx+134,cy,67,19,&sd->brush_type,14.0,PINCH_BRUSH,0,0,"Interactively pinch areas of the model");
+ uiDefButS(block,ROW,REDRAWBUTSEDIT,"Inflate",cx+201,cy,67,19,&sd->brush_type,14,INFLATE_BRUSH,0,0,"Push vertices along the direction of their normals");
+ cy-= 20;
+ uiDefButS(block,ROW,REDRAWBUTSEDIT,"Grab", cx,cy,89,19,&sd->brush_type,14,GRAB_BRUSH,0,0,"Grabs a group of vertices and moves them with the mouse");
+ uiDefButS(block,ROW,REDRAWBUTSEDIT,"Layer", cx+89,cy,89,19,&sd->brush_type,14, LAYER_BRUSH,0,0,"Adds a layer of depth");
+ uiDefButS(block,ROW,REDRAWBUTSEDIT,"Flatten", cx+178,cy,90,19,&sd->brush_type,14, FLATTEN_BRUSH,0,0,"Interactively flatten areas of the model");
+ cy-= 25;
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefBut(block,LABEL,B_NOP,"Shape",cx,cy,90,19,NULL,0,0,0,0,"");
+ cy-= 20;
+ uiBlockBeginAlign(block);
+ if(sd->brush_type != SMOOTH_BRUSH && sd->brush_type != GRAB_BRUSH && sd->brush_type != FLATTEN_BRUSH) {
+ uiDefButC(block,ROW,B_NOP,"Add",cx,cy,89,19,&sculptmode_brush()->dir,15.0,1.0,0, 0,"Add depth to model [Shift]");
+ uiDefButC(block,ROW,B_NOP,"Sub",cx+89,cy,89,19,&sculptmode_brush()->dir,15.0,2.0,0, 0,"Subtract depth from model [Shift]");
+ }
+ if(sd->brush_type!=GRAB_BRUSH)
+ uiDefButC(block,TOG,B_NOP,"Airbrush",cx+178,cy,89,19,&sculptmode_brush()->airbrush,0,0,0,0,"Brush makes changes without waiting for the mouse to move");
+ cy-= 20;
+ but= uiDefButS(block,NUMSLI,B_NOP,"Size: ",cx,cy,268,19,&sculptmode_brush()->size,1.0,200.0,0,0,"Set brush radius in pixels");
+ cy-= 20;
+ if(sd->brush_type!=GRAB_BRUSH)
+ uiDefButC(block,NUMSLI,B_NOP,"Strength: ",cx,cy,268,19,&sculptmode_brush()->strength,1.0,100.0,0,0,"Set brush strength");
+ cy-= 25;
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefBut( block,LABEL,B_NOP,"Symmetry",cx,cy,90,19,NULL,0,0,0,0,"");
+ cy-= 20;
+ uiBlockBeginAlign(block);
+ uiDefButBitC(block, TOG, SYMM_X, 0, "X", cx,cy,89,19, &sd->symm, 0,0,0,0, "Mirror brush across X axis");
+ uiDefButBitC(block, TOG, SYMM_Y, 0, "Y", cx+89,cy,89,19, &sd->symm, 0,0,0,0, "Mirror brush across Y axis");
+ uiDefButBitC(block, TOG, SYMM_Z, 0, "Z", cx+178,cy,90,19, &sd->symm, 0,0,0,0, "Mirror brush across Z axis");
+ uiBlockEndAlign(block);
+
+ cx+= 210;
+}
+
+void sculptmode_draw_interface_textures(uiBlock *block, unsigned short cx, unsigned short cy)
+{
+ SculptData *sd= sculpt_data();
+ MTex *mtex;
+ int i;
+ int orig_y= cy;
+ char *strp;
+ uiBut *but;
+
+ uiBlockBeginAlign(block);
+ uiDefBut(block,LABEL,B_NOP,"Common",cx,cy,80,20,0,0,0,0,0,"");
+ cy-= 20;
+
+ uiBlockBeginAlign(block);
+ uiDefButC(block,TOG,B_NOP, "Fade", cx,cy,80,19, &sd->texfade, 0,0,0,0,"Smooth the edges of the texture");
+ cy-= 20;
+ uiDefButS(block,NUM,B_NOP, "Space", cx,cy,80,19, &sd->spacing, 0,500,20,0,"Non-zero inserts N pixels between dots");
+ cy-= 20;
+ if(sd->brush_type == DRAW_BRUSH)
+ uiDefButC(block,NUM,B_NOP, "View", cx,cy,80,19, &sculptmode_brush()->view, 0,10,20,0,"Pulls brush direction towards view");
+ uiBlockEndAlign(block);
+
+ cy= orig_y;
+ cx+= 85;
+ uiBlockBeginAlign(block);
+ uiDefBut(block,LABEL,B_NOP,"Texture",cx,cy,80,20,0,0,0,0,0,"");
+ cy-= 20;
+
+ /* TEX CHANNELS */
+ uiBlockBeginAlign(block);
+ uiBlockSetCol(block, TH_BUT_NEUTRAL);
+ for(i=-1; i<8; i++) {
+ char str[64];
+ int loos;
+ mtex= sd->mtex[i];
+
+ if(i==-1)
+ strcpy(str, "Default");
+ else {
+ if(mtex && mtex->tex) splitIDname(mtex->tex->id.name+2, str, &loos);
+ else strcpy(str, "");
+ }
+ str[10]= 0;
+ uiDefButS(block, ROW, REDRAWBUTSEDIT, str,cx, cy, 80, 20, &sd->texact, 3.0, (float)i, 0, 0, "Texture channel");
+ cy-= 18;
+ }
+
+ cy= orig_y-20;
+ cx+= 85;
+ mtex= sd->mtex[sd->texact];
+
+ if(sd->texact == -1) {
+ uiBlockBeginAlign(block);
+ uiDefBut(block,LABEL,B_NOP,"",cx,cy,115,20,0,0,0,0,0,""); /* Padding */
+ } else {
+ ID *id= NULL;
+ uiBlockBeginAlign(block);
+
+ if(mtex && mtex->tex) id= &mtex->tex->id;
+ IDnames_to_pupstring(&strp, NULL, "ADD NEW %x 32767", &G.main->tex, id, &G.buts->texnr);
+
+ if(mtex && mtex->tex) {
+ uiDefBut(block, TEX, B_IDNAME, "TE:",cx,cy,115,19, mtex->tex->id.name+2, 0.0, 21.0, 0, 0, "Texture name");
+ cy-= 20;
+
+ uiDefButS(block,MENU,B_SCULPT_TEXBROWSE, strp, cx,cy,20,19, &G.buts->texnr, 0,0,0,0, "Selects an existing texture or creates new");
+ uiDefIconBut(block, BUT, B_AUTOTEXNAME, ICON_AUTO, cx+21,cy,21,20, 0, 0, 0, 0, 0, "Auto-assigns name to texture");
+
+ but= uiDefBut(block, BUT, B_NOP, "Clear",cx+43, cy, 72, 20, 0, 0, 0, 0, 0, "Erases link to texture");
+ uiButSetFunc(but,sculptmode_rem_tex,0,0);
+ cy-= 25;
+
+ uiBlockBeginAlign(block);
+ uiDefButC(block,ROW, REDRAWBUTSEDIT, "Drag", cx, cy,39,19, &sd->texrept, 18,SCULPTREPT_DRAG,0,0,"Move the texture with the brush");
+ uiDefButC(block,ROW, REDRAWBUTSEDIT, "Tile", cx+39,cy,39,19, &sd->texrept, 18,SCULPTREPT_TILE,0,0,"Treat the texture as a tiled image extending across the screen");
+ uiDefButC(block,ROW, REDRAWBUTSEDIT, "3D", cx+78,cy,37,19, &sd->texrept, 18,SCULPTREPT_3D, 0,0,"Use vertex coords as texture coordinates");
+ cy-= 20;
+
+ if(sd->texrept != SCULPTREPT_3D) {
+ uiBlockBeginAlign(block);
+ uiDefButF(block,NUM,0, "Angle", cx,cy,115,19, &mtex->warpfac, 0,360,100,0, "Rotate texture counterclockwise");
+ }
+ cy-= 20;
+
+ if(sd->texrept != SCULPTREPT_DRAG) {
+ uiBlockBeginAlign(block);
+ but= uiDefIconButC(block, TOG, REDRAWBUTSEDIT, sd->texsep ? ICON_UNLOCKED : ICON_LOCKED, cx,cy,20,19, &sd->texsep,0,0,0,0, "Locks the texture sizes together");
+ uiBlockBeginAlign(block);
+ uiDefButF(block,NUM,B_NOP, sd->texsep ? "SizeX" : "Size", cx+20,cy,95,19, &mtex->size[0],1,1000,100,0,"Scaling factor for texture");
+ cy-= 20;
+ if(sd->texsep) {
+ uiDefButF(block,NUM,B_NOP, "SizeY", cx+20,cy,95,19, &mtex->size[1],1,1000,100,0,"Scaling factor for texture");
+ cy-= 20;
+ if(sd->texrept == SCULPTREPT_3D)
+ uiDefButF(block,NUM,B_NOP, "SizeZ", cx+20,cy,95,19, &mtex->size[2],1,1000,100,0,"Scaling factor for texture");
+ cy-= 20;
+ }
+ }
+ }
+ else {
+ uiDefButS(block,TOG,B_SCULPT_TEXBROWSE, "Add New" ,cx, cy, 115, 19, &G.buts->texnr,-1,32767,0,0, "Adds a new texture");
+ uiDefButS(block,MENU,B_SCULPT_TEXBROWSE, strp, cx,cy-20,20,19, &G.buts->texnr, 0,0,0,0, "Selects an existing texture or creates new");
+ }
+
+ MEM_freeN(strp);
+ }
+
+ uiBlockEndAlign(block);
+}
+
+/* *************************** FACE/PAINT *************************** */
+
+void do_fpaintbuts(unsigned short event)
+{
+ Mesh *me;
+ Object *ob;
+ bDeformGroup *defGroup;
+ MTFace *activetf, *tf;
+ MFace *mf;
+ MCol *activemcol;
+ int a;
+ SculptData *sd= &G.scene->sculptdata;
+ ID *id, *idtest;
+ extern VPaint Gwp; /* from vpaint */
+ ToolSettings *settings= G.scene->toolsettings;
+ int nr= 1;
+ MTex *mtex;
+
+ ob= OBACT;
+ if(ob==NULL) return;
+
+ switch(event) {
+
+ case B_VPGAMMA:
+ vpaint_dogamma();
+ break;
+ case B_COPY_TF_MODE:
+ case B_COPY_TF_UV:
+ case B_COPY_TF_COL:
+ case B_COPY_TF_TEX:
+ me= get_mesh(OBACT);
+ activetf= get_active_mtface(NULL, &activemcol, 0);
+
+ if(me && activetf) {
+ for (a=0, tf=me->mtface, mf=me->mface; a < me->totface; a++, tf++, mf++) {
+ if(tf!=activetf && (mf->flag & ME_FACE_SEL)) {
+ if(event==B_COPY_TF_MODE) {
+ tf->mode= activetf->mode;
+ tf->transp= activetf->transp;
+ }
+ else if(event==B_COPY_TF_UV) {
+ memcpy(tf->uv, activetf->uv, sizeof(tf->uv));
+ tf->tpage= activetf->tpage;
+ tf->tile= activetf->tile;
+
+ if(activetf->mode & TF_TILES) tf->mode |= TF_TILES;
+ else tf->mode &= ~TF_TILES;
+
+ }
+ else if(event==B_COPY_TF_TEX) {
+ tf->tpage= activetf->tpage;
+ tf->tile= activetf->tile;
+
+ if(activetf->mode & TF_TILES) tf->mode |= TF_TILES;
+ else tf->mode &= ~TF_TILES;
+ }
+ else if(event==B_COPY_TF_COL && activemcol)
+ memcpy(&me->mcol[a*4], activemcol, sizeof(MCol)*4);
+ }
+ }
+
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ do_shared_vertexcol(me);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWIMAGE, 0);
+ }
+ break;
+ case B_SET_VCOL:
+ if(FACESEL_PAINT_TEST)
+ clear_vpaint_selectedfaces();
+ else
+ clear_vpaint();
+ break;
+ case B_REDR_3D_IMA:
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWIMAGE, 0);
+ break;
+ case B_ASSIGNMESH:
+
+ test_object_materials(ob->data);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ break;
+
+ case B_TFACE_HALO:
+ activetf = get_active_mtface(NULL, NULL, 0);
+ if(activetf) {
+ activetf->mode &= ~TF_BILLBOARD2;
+ allqueue(REDRAWBUTSEDIT, 0);
+ }
+ break;
+
+ case B_TFACE_BILLB:
+ activetf = get_active_mtface(NULL, NULL, 0);
+ if(activetf) {
+ activetf->mode &= ~TF_BILLBOARD;
+ allqueue(REDRAWBUTSEDIT, 0);
+ }
+ break;
+ case B_WEIGHT0_0:
+ editbutvweight = 0.0f;
+ allqueue(REDRAWBUTSEDIT, 0);
+ break;
+
+ case B_WEIGHT1_4:
+ editbutvweight = 0.25f;
+ allqueue(REDRAWBUTSEDIT, 0);
+ break;
+ case B_WEIGHT1_2:
+ editbutvweight = 0.5f;
+ allqueue(REDRAWBUTSEDIT, 0);
+ break;
+ case B_WEIGHT3_4:
+ editbutvweight = 0.75f;
+ allqueue(REDRAWBUTSEDIT, 0);
+ break;
+ case B_WEIGHT1_0:
+ editbutvweight = 1.0f;
+ allqueue(REDRAWBUTSEDIT, 0);
+ break;
+
+ case B_OPA1_8:
+ Gwp.a = 0.125f;
+ allqueue(REDRAWBUTSEDIT, 0);
+ break;
+ case B_OPA1_4:
+ Gwp.a = 0.25f;
+ allqueue(REDRAWBUTSEDIT, 0);
+ break;
+ case B_OPA1_2:
+ Gwp.a = 0.5f;
+ allqueue(REDRAWBUTSEDIT, 0);
+ break;
+ case B_OPA3_4:
+ Gwp.a = 0.75f;
+ allqueue(REDRAWBUTSEDIT, 0);
+ break;
+ case B_OPA1_0:
+ Gwp.a = 1.0f;
+ allqueue(REDRAWBUTSEDIT, 0);
+ break;
+ case B_CLR_WPAINT:
+ if(!multires_level1_test()) {
+ defGroup = BLI_findlink(&ob->defbase, ob->actdef-1);
+ if(defGroup) {
+ Mesh *me= ob->data;
+ int a;
+ for(a=0; a<me->totvert; a++)
+ remove_vert_defgroup (ob, defGroup, a);
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ }
+ }
+ break;
+ case B_SCULPT_TEXBROWSE:
+ sd= &G.scene->sculptdata;
+
+ if(G.buts->texnr== -2) {
+ id= NULL;
+ if(sd) {
+ mtex= sd->mtex[sd->texact];
+ if(mtex) id= &mtex->tex->id;
+ }
+
+ activate_databrowse((ID *)id, ID_TE, 0, B_SCULPT_TEXBROWSE, &G.buts->texnr, do_global_buttons);
+ return;
+ }
+ if(G.buts->texnr < 0) break;
+
+ if(G.buts->pin) {
+
+ }
+ else if(sd && sd->texact == -1) {
+ error("No texture channel selected");
+ allqueue(REDRAWBUTSSHADING, 0);
+ }
+ else if(sd && sd->texact != -1) {
+ id= NULL;
+
+ mtex= sd->mtex[sd->texact];
+ if(mtex) id= &mtex->tex->id;
+
+ idtest= G.main->tex.first;
+ while(idtest) {
+ if(nr==G.buts->texnr) {
+ break;
+ }
+ nr++;
+ idtest= idtest->next;
+ }
+ if(idtest==0) { /* new tex */
+ if(id) idtest= (ID *)copy_texture((Tex *)id);
+ else idtest= (ID *)add_texture("Tex");
+ idtest->us--;
+ }
+ if(idtest!=id && sd) {
+
+ if(sd->mtex[sd->texact]==0) {
+ sd->mtex[sd->texact]= add_mtex();
+ sd->mtex[sd->texact]->texco= TEXCO_VIEW;
+ sd->mtex[sd->texact]->size[0]=
+ sd->mtex[sd->texact]->size[1]=
+ sd->mtex[sd->texact]->size[2]= 100;
+ sd->mtex[sd->texact]->warpfac= 0;
+ }
+ sd->mtex[sd->texact]->tex= (Tex *)idtest;
+ id_us_plus(idtest);
+ if(id) id->us--;
+
+ BIF_undo_push("Texture browse");
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWOOPS, 0);
+ BIF_preview_changed(ID_TE);
+ }
+ }
+ break;
+
+ case B_BRUSHBROWSE:
+ if(G.buts->menunr==-2) {
+ activate_databrowse((ID*)settings->imapaint.brush, ID_BR, 0, B_BRUSHBROWSE, &G.buts->menunr, do_global_buttons);
+ break;
+ }
+ else if(G.buts->menunr < 0) break;
+
+ if(brush_set_nr(&settings->imapaint.brush, G.buts->menunr)) {
+ BIF_undo_push("Browse Brush");
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWIMAGE, 0);
+ }
+ break;
+ case B_BRUSHDELETE:
+ if(brush_delete(&settings->imapaint.brush)) {
+ BIF_undo_push("Unlink Brush");
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWIMAGE, 0);
+ }
+ break;
+ case B_BRUSHKEEPDATA:
+ brush_toggle_fake_user(settings->imapaint.brush);
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWIMAGE, 0);
+ break;
+ case B_BRUSHLOCAL:
+ if(settings->imapaint.brush && settings->imapaint.brush->id.lib) {
+ if(okee("Make local")) {
+ make_local_brush(settings->imapaint.brush);
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWIMAGE, 0);
+ }
+ }
+ break;
+ case B_BTEXBROWSE:
+ if(settings->imapaint.brush) {
+ Brush *brush= settings->imapaint.brush;
+
+ if(G.buts->menunr==-2) {
+ MTex *mtex= brush->mtex[brush->texact];
+ ID *id= (ID*)((mtex)? mtex->tex: NULL);
+ if(G.qual & LR_CTRLKEY) {
+ activate_databrowse_imasel(id, ID_TE, 0, B_BTEXBROWSE, &G.buts->menunr, do_fpaintbuts);
+ } else {
+ activate_databrowse(id, ID_TE, 0, B_BTEXBROWSE, &G.buts->menunr, do_fpaintbuts);
+ }
+ break;
+ }
+ else if(G.buts->menunr < 0) break;
+
+ if(brush_texture_set_nr(brush, G.buts->menunr)) {
+ BIF_undo_push("Browse Brush Texture");
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWIMAGE, 0);
+ }
+ }
+ break;
+ case B_BTEXDELETE:
+ if(settings->imapaint.brush) {
+ if (brush_texture_delete(settings->imapaint.brush)) {
+ BIF_undo_push("Unlink Brush Texture");
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWIMAGE, 0);
+ }
+ }
+ break;
+ case B_BRUSHCHANGE:
+ allqueue(REDRAWIMAGE, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ break;
+ }
+}
+
+/* -------------------- MODE: vpaint ------------------- */
+
+void weight_paint_buttons(uiBlock *block)
+{
+ extern VPaint Gwp; /* from vpaint */
+ Object *ob;
+ ob= OBACT;
+
+ if(ob==NULL) return;
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUMSLI, REDRAWVIEW3D, "Weight:",10,170,225,19, &editbutvweight, 0, 1, 10, 0, "Sets the current vertex group's bone deformation strength");
+
+ uiDefBut(block, BUT, B_WEIGHT0_0 , "0", 10,150,45,19, 0, 0, 0, 0, 0, "");
+ uiDefBut(block, BUT, B_WEIGHT1_4 , "1/4", 55,150,45,19, 0, 0, 0, 0, 0, "");
+ uiDefBut(block, BUT, B_WEIGHT1_2 , "1/2", 100,150,45,19, 0, 0, 0, 0, 0, "");
+ uiDefBut(block, BUT, B_WEIGHT3_4 , "3/4", 145,150,45,19, 0, 0, 0, 0, 0, "");
+ uiDefBut(block, BUT, B_WEIGHT1_0 , "1", 190,150,45,19, 0, 0, 0, 0, 0, "");
+
+ uiDefButF(block, NUMSLI, B_NOP, "Opacity ", 10,130,225,19, &Gwp.a, 0.0, 1.0, 0, 0, "The amount of pressure on the brush");
+
+ uiDefBut(block, BUT, B_OPA1_8 , "1/8", 10,110,45,19, 0, 0, 0, 0, 0, "");
+ uiDefBut(block, BUT, B_OPA1_4 , "1/4", 55,110,45,19, 0, 0, 0, 0, 0, "");
+ uiDefBut(block, BUT, B_OPA1_2 , "1/2", 100,110,45,19, 0, 0, 0, 0, 0, "");
+ uiDefBut(block, BUT, B_OPA3_4 , "3/4", 145,110,45,19, 0, 0, 0, 0, 0, "");
+ uiDefBut(block, BUT, B_OPA1_0 , "1", 190,110,45,19, 0, 0, 0, 0, 0, "");
+
+ uiDefButF(block, NUMSLI, B_NOP, "Size ", 10,90,225,19, &Gwp.size, 2.0, 64.0, 0, 0, "The size of the brush");
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, ROW, B_DIFF, "Mix", 250,170,60,17, &Gwp.mode, 1.0, 0.0, 0, 0, "Mix the vertex colors");
+ uiDefButS(block, ROW, B_DIFF, "Add", 250,152,60,17, &Gwp.mode, 1.0, 1.0, 0, 0, "Add the vertex colors");
+ uiDefButS(block, ROW, B_DIFF, "Sub", 250,134,60,17, &Gwp.mode, 1.0, 2.0, 0, 0, "Subtract from the vertex color");
+ uiDefButS(block, ROW, B_DIFF, "Mul", 250,116,60,17, &Gwp.mode, 1.0, 3.0, 0, 0, "Multiply the vertex color");
+ uiDefButS(block, ROW, B_DIFF, "Filter", 250, 98,60,17, &Gwp.mode, 1.0, 4.0, 0, 0, "Mix the colors with an alpha factor");
+ uiDefButS(block, ROW, B_DIFF, "Lighter", 250, 80,60,17, &Gwp.mode, 1.0, 5.0, 0, 0, "Paint over darker areas only");
+ uiDefButS(block, ROW, B_DIFF, "Darker", 250, 62,60,17, &Gwp.mode, 1.0, 6.0, 0, 0, "Paint over lighter areas only");
+ uiBlockEndAlign(block);
+
+ /* draw options same as below */
+ uiBlockBeginAlign(block);
+ if (FACESEL_PAINT_TEST) {
+ uiDefButBitI(block, TOG, G_DRAWFACES, B_UVAUTO_DRAWFACES, "Faces", 10,45,60,19, &G.f, 0, 0, 0, 0, "Displays all faces as shades");
+ uiDefButBitI(block,TOG, G_DRAWEDGES, REDRAWVIEW3D,"Edges",70,45,60,19, &G.f, 2.0, 0, 0, 0, "Displays edges of visible faces");
+ uiDefButBitI(block,TOG, G_HIDDENEDGES, REDRAWVIEW3D,"Hidden Edges",130,45,100,19, &G.f, 2.0, 1.0, 0, 0, "Displays edges of hidden faces");
+ } else{
+ uiDefButBitC(block, TOG, OB_DRAWWIRE, REDRAWVIEW3D, "Wire", 10,45,75,19, &ob->dtx, 0, 0, 0, 0, "Displays the active object's wireframe in shaded drawing modes");
+ }
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, VP_AREA, 0, "All Faces", 10,20,60,19, &Gwp.flag, 0, 0, 0, 0, "Paint on all faces inside brush (otherwise only on face under mouse cursor)");
+ uiDefButBitS(block, TOG, VP_SOFT, 0, "Vert Dist", 70,20,60,19, &Gwp.flag, 0, 0, 0, 0, "Use distances to vertices (instead of all vertices of face)");
+ uiDefButBitS(block, TOGN, VP_HARD, 0, "Soft", 130,20,60,19, &Gwp.flag, 0, 0, 0, 0, "Use a soft brush");
+ uiDefButBitS(block, TOG, VP_NORMALS, 0, "Normals", 190,20,60,19, &Gwp.flag, 0, 0, 0, 0, "Applies the vertex normal before painting");
+ uiDefButBitS(block, TOG, VP_SPRAY, 0, "Spray", 250,20,55,19, &Gwp.flag, 0, 0, 0, 0, "Keep applying paint effect while holding mouse");
+ uiBlockEndAlign(block);
+
+ if(ob) {
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, VP_ONLYVGROUP, REDRAWVIEW3D, "Vgroup", 10,0,100,19, &Gwp.flag, 0, 0, 0, 0, "Only paint on vertices in the selected vertex group.");
+ uiDefButBitS(block, TOG, VP_MIRROR_X, REDRAWVIEW3D, "X-Mirror", 110,0,100,19, &Gwp.flag, 0, 0, 0, 0, "Mirrored Paint, applying on mirrored Weight Group name");
+ uiDefBut(block, BUT, B_CLR_WPAINT, "Clear", 210,0,100,19, NULL, 0, 0, 0, 0, "Removes reference to this deform group from all vertices");
+ uiBlockEndAlign(block);
+ }
+}
+
+static void editing_panel_mesh_paint(void)
+{
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "editing_panel_mesh_paint", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Paint", "Editing", 640, 0, 318, 204)==0) return;
+
+
+ if(G.f & G_WEIGHTPAINT) {
+ weight_paint_buttons(block);
+ }
+ else if(G.f & G_VERTEXPAINT) {
+ extern VPaint Gvp; /* from vpaint */
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUMSLI, B_NOP, "R ", 979,170,150,19, &Gvp.r, 0.0, 1.0, B_VPCOLSLI, 0, "The amount of red used for painting");
+ uiDefButF(block, NUMSLI, B_NOP, "G ", 979,150,150,19, &Gvp.g, 0.0, 1.0, B_VPCOLSLI, 0, "The amount of green used for painting");
+ uiDefButF(block, NUMSLI, B_NOP, "B ", 979,130,150,19, &Gvp.b, 0.0, 1.0, B_VPCOLSLI, 0, "The amount of blue used for painting");
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUMSLI, B_NOP, "Opacity ", 979,105,222,19, &Gvp.a, 0.0, 1.0, 0, 0, "The amount of pressure on the brush");
+ uiDefButF(block, NUMSLI, B_NOP, "Size ", 979,85,222,19, &Gvp.size, 2.0, 64.0, 0, 0, "The size of the brush");
+ uiBlockEndAlign(block);
+
+ uiDefButF(block, COL, B_REDR, "", 1140,150,60,40, &(Gvp.r), 0, 0, 0, B_VPCOLSLI, "");
+ uiDefBut(block, BUT, B_SET_VCOL, "SetVCol", 1140,130,60,20, 0, 0, 0, 0, 0, "Set Vertex color of selection to current (Shift+K)");
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, ROW, B_DIFF, "Mix", 1212,170,63,17, &Gvp.mode, 1.0, 0.0, 0, 0, "Mix the vertex colors");
+ uiDefButS(block, ROW, B_DIFF, "Add", 1212,152,63,17, &Gvp.mode, 1.0, 1.0, 0, 0, "Add the vertex color");
+ uiDefButS(block, ROW, B_DIFF, "Sub", 1212, 134,63,17, &Gvp.mode, 1.0, 2.0, 0, 0, "Subtract from the vertex color");
+ uiDefButS(block, ROW, B_DIFF, "Mul", 1212, 116,63,17, &Gvp.mode, 1.0, 3.0, 0, 0, "Multiply the vertex color");
+ uiDefButS(block, ROW, B_DIFF, "Filter", 1212, 98,63,17, &Gvp.mode, 1.0, 4.0, 0, 0, "Mix the colors with an alpha factor");
+ uiDefButS(block, ROW, B_DIFF, "Lighter", 1212, 80,63,17, &Gvp.mode, 1.0, 5.0, 0, 0, "Paint over darker areas only");
+ uiDefButS(block, ROW, B_DIFF, "Darker", 1212, 62,63,17, &Gvp.mode, 1.0, 6.0, 0, 0, "Paint over lighter areas only");
+ uiBlockEndAlign(block);
+
+ /* draw options */
+ uiBlockBeginAlign(block);
+ if (FACESEL_PAINT_TEST) {
+ uiDefButBitI(block, TOG, G_DRAWFACES, B_UVAUTO_DRAWFACES, "Faces", 979,50,60,19, &G.f, 0, 0, 0, 0, "Displays all faces as shades");
+ uiDefButBitI(block,TOG, G_DRAWEDGES, REDRAWVIEW3D,"Edges",1039,50,60,19, &G.f, 2.0, 0, 0, 0, "Displays edges of visible faces");
+ uiDefButBitI(block,TOG, G_HIDDENEDGES, REDRAWVIEW3D,"Hidden Edges",1099,50,100,19, &G.f, 2.0, 1.0, 0, 0, "Displays edges of hidden faces");
+ }
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, VP_AREA, 0, "All Faces", 979,25,75,19, &Gvp.flag, 0, 0, 0, 0, "Paint on all faces inside brush");
+ uiDefButBitS(block, TOG, VP_SOFT, 0, "Vertex Dist", 1054,25,75,19, &Gvp.flag, 0, 0, 0, 0, "Use distances to vertices (instead of paint entire faces)");
+ uiDefButBitS(block, TOG, VP_NORMALS, 0, "Normals", 1129,25,75,19, &Gvp.flag, 0, 0, 0, 0, "Applies the vertex normal before painting");
+ uiDefButBitS(block, TOG, VP_SPRAY, 0, "Spray", 1204,25,72,19, &Gvp.flag, 0, 0, 0, 0, "Keep applying paint effect while holding mouse");
+
+ uiBlockBeginAlign(block);
+ uiDefBut(block, BUT, B_VPGAMMA, "Set", 979,0,81,19, 0, 0, 0, 0, 0, "Apply Mul and Gamma to vertex colors");
+ uiDefButF(block, NUM, B_DIFF, "Mul:", 1061,0,112,19, &Gvp.mul, 0.1, 50.0, 10, 0, "Set the number to multiply vertex colors with");
+ uiDefButF(block, NUM, B_DIFF, "Gamma:", 1174,0,102,19, &Gvp.gamma, 0.1, 5.0, 10, 0, "Change the clarity of the vertex colors");
+ uiBlockEndAlign(block);
+ }
+ else { /* texture paint */
+ ToolSettings *settings= G.scene->toolsettings;
+ Brush *brush= settings->imapaint.brush;
+ ID *id;
+ int yco, xco, butw;
+
+ yco= 160;
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, ROW, B_BRUSHCHANGE, "Draw", 0 ,yco,108,19, &settings->imapaint.tool, 7.0, PAINT_TOOL_DRAW, 0, 0, "Draw brush");
+ uiDefButS(block, ROW, B_BRUSHCHANGE, "Soften", 108 ,yco,106,19, &settings->imapaint.tool, 7.0, PAINT_TOOL_SOFTEN, 0, 0, "Soften brush");
+ uiDefButS(block, ROW, B_BRUSHCHANGE, "Smear", 214,yco,106,19, &settings->imapaint.tool, 7.0, PAINT_TOOL_SMEAR, 0, 0, "Smear brush");
+ uiBlockEndAlign(block);
+ yco -= 30;
+
+ uiBlockSetCol(block, TH_BUT_SETTING2);
+ id= (ID*)settings->imapaint.brush;
+ xco= std_libbuttons(block, 0, yco, 0, NULL, B_BRUSHBROWSE, ID_BR, 0, id, NULL, &(G.buts->menunr), 0, B_BRUSHLOCAL, B_BRUSHDELETE, 0, B_BRUSHKEEPDATA);
+ uiBlockSetCol(block, TH_AUTO);
+
+ if(brush && !brush->id.lib) {
+ MTex *mtex= brush->mtex[brush->texact];
+
+ butw= 320-(xco+10);
+
+ uiDefButS(block, MENU, B_NOP, "Mix %x0|Add %x1|Subtract %x2|Multiply %x3|Lighten %x4|Darken %x5|Erase Alpha %x6|Add Alpha %x7", xco+10,yco,butw,19, &brush->blend, 0, 0, 0, 0, "Blending method for applying brushes");
+
+ uiDefButBitS(block, TOG|BIT, BRUSH_TORUS, B_BRUSHCHANGE, "Wrap", xco+10,yco-25,butw,19, &brush->flag, 0, 0, 0, 0, "Enables torus wrapping");
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG|BIT, BRUSH_AIRBRUSH, B_BRUSHCHANGE, "Airbrush", xco+10,yco-50,butw,19, &brush->flag, 0, 0, 0, 0, "Keep applying paint effect while holding mouse (spray)");
+ uiDefButF(block, NUM, B_NOP, "Rate ", xco+10,yco-70,butw,19, &brush->rate, 0.01, 1.0, 0, 0, "Number of paints per second for Airbrush");
+ uiBlockEndAlign(block);
+
+ yco -= 25;
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, COL, B_VPCOLSLI, "", 0,yco,200,19, brush->rgb, 0, 0, 0, 0, "");
+ uiDefButF(block, NUMSLI, B_NOP, "Opacity ", 0,yco-20,180,19, &brush->alpha, 0.0, 1.0, 0, 0, "The amount of pressure on the brush");
+ uiDefButBitS(block, TOG|BIT, BRUSH_ALPHA_PRESSURE, B_NOP, "P", 180,yco-20,20,19, &brush->flag, 0, 0, 0, 0, "Enables pressure sensitivity for tablets");
+ uiDefButI(block, NUMSLI, B_NOP, "Size ", 0,yco-40,180,19, &brush->size, 1, 200, 0, 0, "The size of the brush");
+ uiDefButBitS(block, TOG|BIT, BRUSH_SIZE_PRESSURE, B_NOP, "P", 180,yco-40,20,19, &brush->flag, 0, 0, 0, 0, "Enables pressure sensitivity for tablets");
+ uiDefButF(block, NUMSLI, B_NOP, "Falloff ", 0,yco-60,180,19, &brush->innerradius, 0.0, 1.0, 0, 0, "The fall off radius of the brush");
+ uiDefButBitS(block, TOG|BIT, BRUSH_RAD_PRESSURE, B_NOP, "P", 180,yco-60,20,19, &brush->flag, 0, 0, 0, 0, "Enables pressure sensitivity for tablets");
+ uiDefButF(block, NUMSLI, B_NOP, "Spacing ",0,yco-80,180,19, &brush->spacing, 1.0, 100.0, 0, 0, "Repeating paint on %% of brush diameter");
+ uiDefButBitS(block, TOG|BIT, BRUSH_SPACING_PRESSURE, B_NOP, "P", 180,yco-80,20,19, &brush->flag, 0, 0, 0, 0, "Enables pressure sensitivity for tablets");
+ uiBlockEndAlign(block);
+
+ yco -= 110;
+
+ uiBlockSetCol(block, TH_BUT_SETTING2);
+ id= (mtex)? (ID*)mtex->tex: NULL;
+ xco= std_libbuttons(block, 0, yco, 0, NULL, B_BTEXBROWSE, ID_TE, 0, id, NULL, &(G.buts->menunr), 0, 0, B_BTEXDELETE, 0, 0);
+ /*uiDefButBitS(block, TOG|BIT, BRUSH_FIXED_TEX, B_BRUSHCHANGE, "Fixed", xco+5,yco,butw,19, &brush->flag, 0, 0, 0, 0, "Keep texture origin in fixed position");*/
+ uiBlockSetCol(block, TH_AUTO);
+ }
+ }
+}
+
+static void editing_panel_mesh_texface(void)
+{
+ uiBlock *block;
+ MTFace *tf;
+
+ block= uiNewBlock(&curarea->uiblocks, "editing_panel_mesh_texface", UI_EMBOSS, UI_HELV, curarea->win);
+ uiNewPanelTabbed("Multires", "Editing");
+ if(uiNewPanel(curarea, block, "Texture Face", "Editing", 960, 0, 318, 204)==0) return;
+
+ tf = get_active_mtface(NULL, NULL, 0);
+ if(tf) {
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, TF_TEX, B_REDR_3D_IMA, "Tex", 600,160,60,19, &tf->mode, 0, 0, 0, 0, "Render face with texture");
+ uiDefButBitS(block, TOG, TF_TILES, B_REDR_3D_IMA, "Tiles", 660,160,60,19, &tf->mode, 0, 0, 0, 0, "Use tilemode for face");
+ uiDefButBitS(block, TOG, TF_LIGHT, REDRAWVIEW3D, "Light", 720,160,60,19, &tf->mode, 0, 0, 0, 0, "Use light for face");
+ uiDefButBitS(block, TOG, TF_INVISIBLE, REDRAWVIEW3D, "Invisible",780,160,60,19, &tf->mode, 0, 0, 0, 0, "Make face invisible");
+ uiDefButBitS(block, TOG, TF_DYNAMIC, REDRAWVIEW3D, "Collision", 840,160,60,19, &tf->mode, 0, 0, 0, 0, "Use face for collision detection");
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, TF_SHAREDCOL, REDRAWVIEW3D, "Shared", 600,135,60,19, &tf->mode, 0, 0, 0, 0, "Blend vertex colors across face when vertices are shared");
+ uiDefButBitS(block, TOG, TF_TWOSIDE, REDRAWVIEW3D, "Twoside",660,135,60,19, &tf->mode, 0, 0, 0, 0, "Render face twosided");
+ uiDefButBitS(block, TOG, TF_OBCOL, REDRAWVIEW3D, "ObColor",720,135,60,19, &tf->mode, 0, 0, 0, 0, "Use ObColor instead of vertex colors");
+
+ uiBlockBeginAlign(block);
+
+ uiDefButBitS(block, TOG, TF_BILLBOARD, B_TFACE_HALO, "Halo", 600,110,60,19, &tf->mode, 0, 0, 0, 0, "Screen aligned billboard");
+ uiDefButBitS(block, TOG, TF_BILLBOARD2, B_TFACE_BILLB, "Billboard",660,110,60,19, &tf->mode, 0, 0, 0, 0, "Billboard with Z-axis constraint");
+ uiDefButBitS(block, TOG, TF_SHADOW, REDRAWVIEW3D, "Shadow", 720,110,60,19, &tf->mode, 0, 0, 0, 0, "Face is used for shadow");
+ uiDefButBitS(block, TOG, TF_BMFONT, REDRAWVIEW3D, "Text", 780,110,60,19, &tf->mode, 0, 0, 0, 0, "Enable bitmap text on face");
+
+ uiBlockBeginAlign(block);
+ uiBlockSetCol(block, TH_BUT_SETTING1);
+ uiDefButC(block, ROW, REDRAWVIEW3D, "Opaque", 600,80,60,19, &tf->transp, 2.0, (float)TF_SOLID,0, 0, "Render color of textured face as color");
+ uiDefButC(block, ROW, REDRAWVIEW3D, "Add", 660,80,60,19, &tf->transp, 2.0, (float)TF_ADD, 0, 0, "Render face transparent and add color of face");
+ uiDefButC(block, ROW, REDRAWVIEW3D, "Alpha", 720,80,60,19, &tf->transp, 2.0, (float)TF_ALPHA,0, 0, "Render polygon transparent, depending on alpha channel of the texture");
+ }
+}
+
+void do_uvcalculationbuts(unsigned short event)
+{
+ switch(event) {
+ case B_UVAUTO_DRAWFACES:
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWIMAGE, 0);
+ break;
+ }
+}
+
+static void editing_panel_mesh_uvautocalculation(void)
+{
+ uiBlock *block;
+ int butH= 19, butHB= 20, row= 180, butS= 10;
+
+ block= uiNewBlock(&curarea->uiblocks, "editing_panel_mesh_uvautocalculation", UI_EMBOSS, UI_HELV, curarea->win);
+ /* make this a tab of "Texture face" to save screen space*/
+ uiNewPanelTabbed("Multires", "Editing");
+ if(uiNewPanel(curarea, block, "UV Calculation", "Editing", 960, 0, 318, 204)==0)
+ return;
+ row-= 4*butHB+butS;
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, MENU, REDRAWBUTSEDIT, "Unwrapper%t|Conformal%x0|Angle Based%x1",100,row,200,butH, &G.scene->toolsettings->unwrapper, 0, 0, 0, 0, "Unwrap method");
+ uiDefButBitS(block, TOG, 1, B_NOP, "Fill Holes",100,row-butHB,200,butH,&G.scene->toolsettings->uvcalc_flag, 0, 0, 0, 0, "Fill holes to prevent internal overlaps");
+ uiBlockEndAlign(block);
+ row-= 2*butHB+butS;
+
+ row= 180;
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM,B_UVAUTO_CUBESIZE ,"Cube Size:",315,row,200,butH, &G.scene->toolsettings->uvcalc_cubesize, 0.0001, 100.0, 10, 3, "Defines the cubemap size for cube mapping");
+ uiBlockEndAlign(block);
+ row-= butHB+butS;
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM,B_UVAUTO_CYLRADIUS ,"Cyl Radius:",315,row,200,butH, &G.scene->toolsettings->uvcalc_radius, 0.1, 100.0, 10, 3, "Defines the radius of the UV mapping cylinder");
+ uiBlockEndAlign(block);
+ row-= butHB+butS;
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, ROW,B_UVAUTO_FACE,"View Aligns Face",315,row,200,butH, &G.scene->toolsettings->uvcalc_mapdir,2.0, 1.0, 0.0,0.0, "View is on equator for cylindrical and spherical UV mapping");
+ uiDefButS(block, ROW,B_UVAUTO_TOP,"VA Top",315,row-butHB,100,butH, &G.scene->toolsettings->uvcalc_mapdir,2.0, 0.0, 0.0,0.0, "View is on poles for cylindrical and spherical UV mapping");
+ uiDefButS(block, ROW,B_UVAUTO_TOP,"Al Obj",415,row-butHB,100,butH, &G.scene->toolsettings->uvcalc_mapdir,2.0, 2.0, 0.0,0.0, "Align to object for cylindrical and spherical UV mapping");
+ uiBlockEndAlign(block);
+ row-= 2*butHB+butS;
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, ROW,B_UVAUTO_ALIGNX,"Polar ZX",315,row,100,butH, &G.scene->toolsettings->uvcalc_mapalign,2.0, 0.0, 0.0,0.0, "Polar 0 is X for cylindrical and spherical UV mapping");
+ uiDefButS(block, ROW,B_UVAUTO_ALIGNY,"Polar ZY",415,row,100,butH, &G.scene->toolsettings->uvcalc_mapalign,2.0, 1.0, 0.0,0.0, "Polar 0 is Y for cylindrical and spherical UV mapping");
+ uiBlockEndAlign(block);
+}
+
+void editing_panel_mesh_multires()
+{
+ uiBlock *block;
+ uiBut *but;
+ Object *ob= OBACT;
+ Mesh *me= get_mesh(ob);
+ int cx= 100, cy= 0;
+
+ block= uiNewBlock(&curarea->uiblocks, "editing_panel_mesh_multires", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Multires", "Editing", 500, 0, 318, 204)==0) return;
+
+ uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
+
+ if(!me->mr) {
+ but= uiDefBut(block,BUT,B_NOP,"Add Multires", cx,cy,268,19,0,0,0,0,0,"");
+ uiButSetFunc(but,multires_make,ob,me);
+ } else {
+ char subsurfmenu[]= "Subsurf Type%t|Catmull-Clark%x0|Simple Subdiv.%x1";
+
+ but= uiDefBut(block,BUT,B_NOP,"Apply Multires", cx,cy,268,19,0,0,0,0,0,"Apply current multires level to mesh and the delete other levels");
+ uiButSetFunc(but,multires_delete,ob,me);
+ cy-= 24;
+
+ uiBlockBeginAlign(block);
+ but= uiDefBut(block,BUT,B_NOP,"Add Level", cx,cy,134,19,0,0,0,0,0,"Add a new level of subdivision at the end of the chain");
+ uiButSetFunc(but,multires_add_level,ob,me);
+ uiDefButC(block, MENU, B_NOP, subsurfmenu, cx + 134, cy, 134, 19, &G.scene->toolsettings->multires_subdiv_type, 0, 0, 0, 0, "Selects type of subdivision algorithm.");
+ cy-= 20;
+
+ if(me->mr->level_count>1) {
+ but= uiDefBut(block,BUT,B_NOP,"Del Lower", cx,cy,134,19,0,0,0,0,0,"Remove all levels of subdivision below the current one");
+ uiButSetFunc(but,multires_del_lower,ob,me);
+ but= uiDefBut(block,BUT,B_NOP,"Del Higher", cx+134,cy,134,19,0,0,0,0,0,"Remove all levels of subdivision above the current one");
+ uiButSetFunc(but,multires_del_higher,ob,me);
+ cy-= 20;
+
+ but= uiDefButC(block,NUM,B_NOP,"Level: ",cx,cy,268,19,(char *)&me->mr->newlvl,1.0,me->mr->level_count,0,0,"");
+ uiButSetFunc(but,multires_set_level_cb, ob, me);
+ cy-= 20;
+
+ but= uiDefButC(block,NUM,B_NOP,"Edges: ",cx,cy,268,19,(char *)&me->mr->edgelvl,1.0,me->mr->level_count,0,0,"Set level of edges to display");
+ uiButSetFunc(but,multires_edge_level_update,ob,me);
+ cy-= 20;
+ uiBlockEndAlign(block);
+
+ cy-= 5;
+ uiDefBut(block,LABEL,B_NOP,"Rendering",cx,cy,100,19,0,0,0,0,0,"");
+ cy-= 20;
+
+ uiBlockBeginAlign(block);
+ uiDefButC(block,NUM,B_NOP,"Pin: ",cx,cy,268,19,(char *)&me->mr->pinlvl,1.0,me->mr->level_count,0,0,"Set level to apply modifiers to during render");
+ cy-= 20;
+
+ uiDefButC(block,NUM,B_NOP,"Render: ",cx,cy,268,19,(char *)&me->mr->renderlvl,1.0,me->mr->level_count,0,0,"Set level to render");
+ cy-= 20;
+
+ if(multires_modifier_warning()) {
+ char *tip= "One or more modifiers are enabled that modify mesh topology";
+ uiDefIconBut(block,LABEL,B_NOP,ICON_ERROR, cx,cy,20,20, 0,0,0,0,0, tip);
+ uiDefBut(block,LABEL,B_NOP, "Cannot use render level", cx+20,cy,180,19, 0,0,0,0,0, tip);
+ }
+ }
+ }
+
+ uiBlockEndAlign(block);
+}
+
+/* this is a mode context sensitive system */
+
+void editing_panels()
+{
+ Object *ob;
+ Curve *cu;
+ MetaBall *mb;
+ Lattice *lt;
+ bArmature *arm;
+ Camera *cam;
+
+ ob= OBACT;
+ if(ob==NULL) return;
+ uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
+
+ switch(ob->type) {
+ case OB_MESH:
+ editing_panel_links(ob);
+ editing_panel_mesh_type(ob, ob->data);
+ editing_panel_modifiers(ob);
+ editing_panel_shapes(ob);
+ editing_panel_mesh_multires();
+ /* modes */
+ if(G.obedit) {
+ editing_panel_mesh_tools(ob, ob->data);
+ editing_panel_mesh_tools1(ob, ob->data);
+ editing_panel_mesh_uvautocalculation();
+ if (EM_texFaceCheck())
+ editing_panel_mesh_texface();
+ }
+ else if(G.f & G_SCULPTMODE) {
+ uiNewPanelTabbed("Multires", "Editing");
+ editing_panel_sculpting_tools();
+ uiNewPanelTabbed("Multires", "Editing");
+ editing_panel_sculpting_textures();
+ } else {
+ if(G.f & (G_VERTEXPAINT | G_TEXTUREPAINT | G_WEIGHTPAINT) ) {
+ editing_panel_mesh_paint();
+ }
+ }
+ break;
+
+ case OB_CURVE:
+ case OB_SURF:
+ cu= ob->data;
+ editing_panel_links(ob);
+ editing_panel_curve_type(ob, cu);
+ editing_panel_modifiers(ob);
+// editing_panel_shapes(ob);
+ if(G.obedit) {
+ editing_panel_curve_tools(ob, cu);
+ editing_panel_curve_tools1(ob, cu);
+ }
+ break;
+
+ case OB_MBALL:
+ mb= ob->data;
+ editing_panel_links(ob);
+ editing_panel_mball_type(ob, mb);
+ if(G.obedit) {
+ editing_panel_mball_tools(ob, mb);
+ }
+ break;
+
+ case OB_FONT:
+ cu= ob->data;
+ editing_panel_links(ob);
+ editing_panel_curve_type(ob, cu);
+ editing_panel_font_type(ob, cu);
+
+#ifdef INTERNATIONAL
+ if(G.obedit)
+ {
+ editing_panel_char_type(ob, cu);
+ }
+#endif
+ editing_panel_modifiers(ob);
+ break;
+
+ case OB_LATTICE:
+ lt= ob->data;
+ editing_panel_links(ob);
+ editing_panel_lattice_type(ob, lt);
+ editing_panel_modifiers(ob);
+ editing_panel_shapes(ob);
+ break;
+
+ case OB_LAMP:
+ editing_panel_links(ob);
+ break;
+
+ case OB_EMPTY:
+ editing_panel_links(ob);
+ break;
+
+ case OB_CAMERA:
+ cam= ob->data;
+ editing_panel_links(ob); // no editmode!
+ editing_panel_camera_type(ob, cam);
+ /* yafray: extra panel for dof parameters */
+ if (G.scene->r.renderer==R_YAFRAY) editing_panel_camera_yafraydof(ob, cam);
+ break;
+
+ case OB_ARMATURE:
+ arm= ob->data;
+ editing_panel_links(ob); // no editmode!
+ editing_panel_armature_type(ob, arm);
+ if(G.obedit) {
+ editing_panel_armature_bones(ob, arm);
+ }
+ else if(ob->flag & OB_POSEMODE) {
+ editing_panel_armature_visuals(ob, arm);
+ editing_panel_pose_bones(ob, arm);
+ object_panel_constraint("Editing");
+ }
+ break;
+ }
+ uiClearButLock();
+}
diff --git a/source/blender/src/buttons_logic.c b/source/blender/src/buttons_logic.c
new file mode 100644
index 00000000000..77922f041d8
--- /dev/null
+++ b/source/blender/src/buttons_logic.c
@@ -0,0 +1,2814 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+
+#ifndef WIN32
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "DNA_action_types.h"
+#include "DNA_material_types.h"
+#include "DNA_sensor_types.h"
+#include "DNA_actuator_types.h"
+#include "DNA_controller_types.h"
+#include "DNA_property_types.h"
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_sound_types.h"
+#include "DNA_text_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_world_types.h"
+
+#include "BKE_library.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_sca.h"
+#include "BKE_property.h"
+
+#include "BIF_gl.h"
+#include "BIF_resources.h"
+#include "BIF_space.h"
+#include "BIF_interface.h"
+#include "BIF_butspace.h"
+#include "BIF_screen.h"
+#include "BIF_keyval.h"
+#include "BIF_editsound.h"
+
+#include "BIF_editsca.h"
+
+
+#include "BDR_editcurve.h"
+#include "BDR_editobject.h"
+#include "BSE_headerbuttons.h"
+#include "BSE_filesel.h"
+
+#include "blendef.h"
+#include "mydevice.h"
+#include "nla.h" /* For __NLA : Important, do not remove */
+#include "butspace.h" // own module
+
+/* internals */
+void buttons_enji(uiBlock *, Object *);
+void buttons_ketsji(uiBlock *, Object *);
+void buttons_bullet(uiBlock *, Object *);
+
+/****/
+
+static ID **get_selected_and_linked_obs(short *count, short scavisflag);
+static char *actuator_pup(Object *owner);
+
+/****/
+
+
+static void del_property(void *selpropv, void *data2_unused)
+{
+ bProperty *prop, *selprop= selpropv;
+ Object *ob;
+ int a=0;
+
+ ob= OBACT;
+ if(ob==NULL) return;
+
+ prop= ob->prop.first;
+ while(prop) {
+ if(prop==selprop) {
+ if (strcmp(prop->name,"Text") == 0) {
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ BLI_remlink(&ob->prop, prop);
+ free_property(prop);
+ break;
+ }
+ a++;
+ prop= prop->next;
+ }
+ BIF_undo_push("Delete property");
+ allqueue(REDRAWBUTSLOGIC, 0);
+
+}
+
+static int vergname(const void *v1, const void *v2)
+{
+ char **x1, **x2;
+
+ x1= (char **)v1;
+ x2= (char **)v2;
+
+ return strcmp(*x1, *x2);
+}
+
+void make_unique_prop_names(char *str)
+{
+ Object *ob;
+ bProperty *prop;
+ bSensor *sens;
+ bController *cont;
+ bActuator *act;
+ ID **idar;
+ short a, obcount, propcount=0, nr;
+ char **names;
+
+ /* this function is called by a Button, and gives the current
+ * stringpointer as an argument, this is the one that can change
+ */
+
+ idar= get_selected_and_linked_obs(&obcount, BUTS_SENS_SEL|BUTS_SENS_ACT|BUTS_ACT_SEL|BUTS_ACT_ACT|BUTS_CONT_SEL|BUTS_CONT_ACT);
+
+ /* for each object, make properties and sca names unique */
+
+ /* count total names */
+ for(a=0; a<obcount; a++) {
+ ob= (Object *)idar[a];
+ propcount+= BLI_countlist(&ob->prop);
+ propcount+= BLI_countlist(&ob->sensors);
+ propcount+= BLI_countlist(&ob->controllers);
+ propcount+= BLI_countlist(&ob->actuators);
+ }
+ if(propcount==0) {
+ if(idar) MEM_freeN(idar);
+ return;
+ }
+
+ /* make names array for sorting */
+ names= MEM_callocN(propcount*sizeof(void *), "names");
+
+ /* count total names */
+ nr= 0;
+ for(a=0; a<obcount; a++) {
+ ob= (Object *)idar[a];
+ prop= ob->prop.first;
+ while(prop) {
+ names[nr++]= prop->name;
+ prop= prop->next;
+ }
+ sens= ob->sensors.first;
+ while(sens) {
+ names[nr++]= sens->name;
+ sens= sens->next;
+ }
+ cont= ob->controllers.first;
+ while(cont) {
+ names[nr++]= cont->name;
+ cont= cont->next;
+ }
+ act= ob->actuators.first;
+ while(act) {
+ names[nr++]= act->name;
+ act= act->next;
+ }
+ }
+
+ qsort(names, propcount, sizeof(void *), vergname);
+
+ /* now we check for double names, and change them */
+
+ for(nr=0; nr<propcount; nr++) {
+ if(names[nr]!=str && strcmp( names[nr], str )==0 ) {
+ BLI_newname(str, +1);
+ }
+ }
+
+ MEM_freeN(idar);
+ MEM_freeN(names);
+}
+
+static void make_unique_prop_names_cb(void *strv, void *redraw_view3d_flagv)
+{
+ char *str= strv;
+ int redraw_view3d_flag= (int) redraw_view3d_flagv;
+
+ make_unique_prop_names(str);
+ if (redraw_view3d_flag) allqueue(REDRAWVIEW3D, 0);
+}
+
+static void sca_move_sensor(void *datav, void *data2_unused)
+{
+ bSensor *sens_to_delete= datav;
+ int val;
+ Base *base;
+ bSensor *sens;
+
+ val= pupmenu("Move up%x1|Move down %x2");
+
+ if(val>0) {
+ /* now find out which object has this ... */
+ base= FIRSTBASE;
+ while(base) {
+
+ sens= base->object->sensors.first;
+ while(sens) {
+ if(sens == sens_to_delete) break;
+ sens= sens->next;
+ }
+
+ if(sens) {
+ if( val==1 && sens->prev) {
+ BLI_remlink(&base->object->sensors, sens);
+ BLI_insertlinkbefore(&base->object->sensors, sens->prev, sens);
+ }
+ else if( val==2 && sens->next) {
+ BLI_remlink(&base->object->sensors, sens);
+ BLI_insertlink(&base->object->sensors, sens->next, sens);
+ }
+ BIF_undo_push("Move sensor");
+ allqueue(REDRAWBUTSLOGIC, 0);
+ break;
+ }
+
+ base= base->next;
+ }
+ }
+}
+
+static void sca_move_controller(void *datav, void *data2_unused)
+{
+ bController *controller_to_del= datav;
+ int val;
+ Base *base;
+ bController *cont;
+
+ val= pupmenu("Move up%x1|Move down %x2");
+
+ if(val>0) {
+ /* now find out which object has this ... */
+ base= FIRSTBASE;
+ while(base) {
+
+ cont= base->object->controllers.first;
+ while(cont) {
+ if(cont == controller_to_del) break;
+ cont= cont->next;
+ }
+
+ if(cont) {
+ if( val==1 && cont->prev) {
+ BLI_remlink(&base->object->controllers, cont);
+ BLI_insertlinkbefore(&base->object->controllers, cont->prev, cont);
+ }
+ else if( val==2 && cont->next) {
+ BLI_remlink(&base->object->controllers, cont);
+ BLI_insertlink(&base->object->controllers, cont->next, cont);
+ }
+ BIF_undo_push("Move controller");
+ allqueue(REDRAWBUTSLOGIC, 0);
+ break;
+ }
+
+ base= base->next;
+ }
+ }
+}
+
+static void sca_move_actuator(void *datav, void *data2_unused)
+{
+ bActuator *actuator_to_move= datav;
+ int val;
+ Base *base;
+ bActuator *act;
+
+ val= pupmenu("Move up%x1|Move down %x2");
+
+ if(val>0) {
+ /* now find out which object has this ... */
+ base= FIRSTBASE;
+ while(base) {
+
+ act= base->object->actuators.first;
+ while(act) {
+ if(act == actuator_to_move) break;
+ act= act->next;
+ }
+
+ if(act) {
+ if( val==1 && act->prev) {
+ BLI_remlink(&base->object->actuators, act);
+ BLI_insertlinkbefore(&base->object->actuators, act->prev, act);
+ }
+ else if( val==2 && act->next) {
+ BLI_remlink(&base->object->actuators, act);
+ BLI_insertlink(&base->object->actuators, act->next, act);
+ }
+ BIF_undo_push("Move actuator");
+ allqueue(REDRAWBUTSLOGIC, 0);
+ break;
+ }
+
+ base= base->next;
+ }
+ }
+}
+
+void do_logic_buts(unsigned short event)
+{
+ bProperty *prop;
+ bSensor *sens;
+ bController *cont;
+ bActuator *act;
+ Base *base;
+ Object *ob;
+ int didit;
+
+ ob= OBACT;
+ if(ob==0) return;
+
+ switch(event) {
+
+ case B_SETSECTOR:
+ /* check for inconsistant types */
+ ob->gameflag &= ~(OB_PROP|OB_MAINACTOR|OB_DYNAMIC|OB_ACTOR);
+ ob->dtx |= OB_BOUNDBOX;
+ allqueue(REDRAWBUTSGAME, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+
+ case B_SETPROP:
+ /* check for inconsistant types */
+ ob->gameflag &= ~(OB_SECTOR|OB_MAINACTOR|OB_DYNAMIC|OB_ACTOR);
+ allqueue(REDRAWBUTSGAME, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+
+ case B_SETACTOR:
+ case B_SETDYNA:
+ case B_SETMAINACTOR:
+ ob->gameflag &= ~(OB_SECTOR|OB_PROP);
+ allqueue(REDRAWBUTSGAME, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+
+
+ case B_ADD_PROP:
+ prop= new_property(PROP_FLOAT);
+ make_unique_prop_names(prop->name);
+ BLI_addtail(&ob->prop, prop);
+ BIF_undo_push("Add property");
+ allqueue(REDRAWBUTSLOGIC, 0);
+ break;
+
+ case B_CHANGE_PROP:
+ prop= ob->prop.first;
+ while(prop) {
+ if(prop->type!=prop->otype) {
+ init_property(prop);
+ if (strcmp(prop->name, "Text") == 0) {
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ }
+ prop= prop->next;
+ }
+ allqueue(REDRAWBUTSLOGIC, 0);
+ break;
+
+ case B_ADD_SENS:
+ base= FIRSTBASE;
+ while(base) {
+ if(base->object->scaflag & OB_ADDSENS) {
+ base->object->scaflag &= ~OB_ADDSENS;
+ sens= new_sensor(SENS_ALWAYS);
+ BLI_addtail(&(base->object->sensors), sens);
+ make_unique_prop_names(sens->name);
+ base->object->scaflag |= OB_SHOWSENS;
+ }
+ base= base->next;
+ }
+
+ BIF_undo_push("Add sensor");
+ allqueue(REDRAWBUTSLOGIC, 0);
+ break;
+
+ case B_CHANGE_SENS:
+ base= FIRSTBASE;
+ while(base) {
+ sens= base->object->sensors.first;
+ while(sens) {
+ if(sens->type != sens->otype) {
+ init_sensor(sens);
+ sens->otype= sens->type;
+ break;
+ }
+ sens= sens->next;
+ }
+ base= base->next;
+ }
+ allqueue(REDRAWBUTSLOGIC, 0);
+ break;
+
+ case B_DEL_SENS:
+ base= FIRSTBASE;
+ while(base) {
+ sens= base->object->sensors.first;
+ while(sens) {
+ if(sens->flag & SENS_DEL) {
+ BLI_remlink(&(base->object->sensors), sens);
+ free_sensor(sens);
+ break;
+ }
+ sens= sens->next;
+ }
+ base= base->next;
+ }
+ BIF_undo_push("Delete sensor");
+ allqueue(REDRAWBUTSLOGIC, 0);
+ break;
+
+ case B_ADD_CONT:
+ base= FIRSTBASE;
+ while(base) {
+ if(base->object->scaflag & OB_ADDCONT) {
+ base->object->scaflag &= ~OB_ADDCONT;
+ cont= new_controller(CONT_LOGIC_AND);
+ make_unique_prop_names(cont->name);
+ base->object->scaflag |= OB_SHOWCONT;
+ BLI_addtail(&(base->object->controllers), cont);
+ }
+ base= base->next;
+ }
+ BIF_undo_push("Add controller");
+ allqueue(REDRAWBUTSLOGIC, 0);
+ break;
+
+ case B_CHANGE_CONT:
+ base= FIRSTBASE;
+ while(base) {
+ cont= base->object->controllers.first;
+ while(cont) {
+ if(cont->type != cont->otype) {
+ init_controller(cont);
+ cont->otype= cont->type;
+ break;
+ }
+ cont= cont->next;
+ }
+ base= base->next;
+ }
+ allqueue(REDRAWBUTSLOGIC, 0);
+ break;
+
+
+ case B_DEL_CONT:
+ base= FIRSTBASE;
+ while(base) {
+ cont= base->object->controllers.first;
+ while(cont) {
+ if(cont->flag & CONT_DEL) {
+ BLI_remlink(&(base->object->controllers), cont);
+ unlink_controller(cont);
+ free_controller(cont);
+ break;
+ }
+ cont= cont->next;
+ }
+ base= base->next;
+ }
+ BIF_undo_push("Delete controller");
+ allqueue(REDRAWBUTSLOGIC, 0);
+ break;
+
+ case B_ADD_ACT:
+ base= FIRSTBASE;
+ while(base) {
+ if(base->object->scaflag & OB_ADDACT) {
+ base->object->scaflag &= ~OB_ADDACT;
+ act= new_actuator(ACT_OBJECT);
+ make_unique_prop_names(act->name);
+ BLI_addtail(&(base->object->actuators), act);
+ base->object->scaflag |= OB_SHOWACT;
+ }
+ base= base->next;
+ }
+ BIF_undo_push("Add actuator");
+ allqueue(REDRAWBUTSLOGIC, 0);
+ break;
+
+ case B_CHANGE_ACT:
+ base= FIRSTBASE;
+ while(base) {
+ act= base->object->actuators.first;
+ while(act) {
+ if(act->type != act->otype) {
+ init_actuator(act);
+ act->otype= act->type;
+ break;
+ }
+ act= act->next;
+ }
+ base= base->next;
+ }
+ allqueue(REDRAWBUTSLOGIC, 0);
+ break;
+
+ case B_DEL_ACT:
+ base= FIRSTBASE;
+ while(base) {
+ act= base->object->actuators.first;
+ while(act) {
+ if(act->flag & ACT_DEL) {
+ BLI_remlink(&(base->object->actuators), act);
+ unlink_actuator(act);
+ free_actuator(act);
+ break;
+ }
+ act= act->next;
+ }
+ base= base->next;
+ }
+ BIF_undo_push("Delete actuator");
+ allqueue(REDRAWBUTSLOGIC, 0);
+ break;
+
+ case B_SOUNDACT_BROWSE:
+ /* since we don't know which... */
+ didit= 0;
+ base= FIRSTBASE;
+ while(base)
+ {
+ act= base->object->actuators.first;
+ while(act)
+ {
+ if(act->type==ACT_SOUND)
+ {
+ bSoundActuator *sa= act->data;
+ if(sa->sndnr)
+ {
+ bSound *sound= G.main->sound.first;
+ int nr= 1;
+
+ if(sa->sndnr == -2) {
+ activate_databrowse((ID *)G.main->sound.first, ID_SO, 0, B_SOUNDACT_BROWSE,
+ &sa->sndnr, do_logic_buts);
+ break;
+ }
+
+ while(sound)
+ {
+ if(nr==sa->sndnr)
+ break;
+ nr++;
+ sound= sound->id.next;
+ }
+
+ if(sa->sound)
+ sa->sound->id.us--;
+
+ sa->sound= sound;
+
+ if(sound)
+ sound->id.us++;
+
+ sa->sndnr= 0;
+ didit= 1;
+ }
+ }
+ act= act->next;
+ }
+ if(didit)
+ break;
+ base= base->next;
+ }
+ allqueue(REDRAWBUTSLOGIC, 0);
+ allqueue(REDRAWSOUND, 0);
+
+ break;
+ }
+}
+
+
+static char *sensor_name(int type)
+{
+ switch (type) {
+ case SENS_ALWAYS:
+ return "Always";
+ case SENS_TOUCH:
+ return "Touch";
+ case SENS_NEAR:
+ return "Near";
+ case SENS_KEYBOARD:
+ return "Keyboard";
+ case SENS_PROPERTY:
+ return "Property";
+ case SENS_MOUSE:
+ return "Mouse";
+ case SENS_COLLISION:
+ return "Collision";
+ case SENS_RADAR:
+ return "Radar";
+ case SENS_RANDOM:
+ return "Random";
+ case SENS_RAY:
+ return "Ray";
+ case SENS_MESSAGE:
+ return "Message";
+ case SENS_JOYSTICK:
+ return "Joystick";
+ }
+ return "unknown";
+}
+
+static char *sensor_pup(void)
+{
+ /* the number needs to match defines in game.h */
+ return "Sensors %t|Always %x0|Keyboard %x3|Mouse %x5|"
+ "Touch %x1|Collision %x6|Near %x2|Radar %x7|"
+ "Property %x4|Random %x8|Ray %x9|Message %x10|Joystick %x11";
+}
+
+static char *controller_name(int type)
+{
+ switch (type) {
+ case CONT_LOGIC_AND:
+ return "AND";
+ case CONT_LOGIC_OR:
+ return "OR";
+ case CONT_EXPRESSION:
+ return "Expression";
+ case CONT_PYTHON:
+ return "Python";
+ }
+ return "unknown";
+}
+
+static char *controller_pup(void)
+{
+ return "Controllers %t|AND %x0|OR %x1|Expression %x2|Python %x3";
+}
+
+static char *actuator_name(int type)
+{
+ switch (type) {
+ case ACT_ACTION:
+ return "Action";
+ case ACT_OBJECT:
+ return "Motion";
+ case ACT_IPO:
+ return "Ipo";
+ case ACT_LAMP:
+ return "Lamp";
+ case ACT_CAMERA:
+ return "Camera";
+ case ACT_MATERIAL:
+ return "Material";
+ case ACT_SOUND:
+ return "Sound";
+ case ACT_CD:
+ return "CD";
+ case ACT_PROPERTY:
+ return "Property";
+ case ACT_EDIT_OBJECT:
+ return "Edit Object";
+ case ACT_CONSTRAINT:
+ return "Constraint";
+ case ACT_SCENE:
+ return "Scene";
+ case ACT_GROUP:
+ return "Group";
+ case ACT_RANDOM:
+ return "Random";
+ case ACT_MESSAGE:
+ return "Message";
+ case ACT_GAME:
+ return "Game";
+ case ACT_VISIBILITY:
+ return "Visibility";
+ }
+ return "unknown";
+}
+
+
+
+
+static char *actuator_pup(Object *owner)
+{
+ switch (owner->type)
+ {
+ case OB_ARMATURE:
+ return "Actuators %t|Action %x15|Motion %x0|Constraint %x9|Ipo %x1"
+ "|Camera %x3|Sound %x5|Property %x6|Edit Object %x10"
+ "|Scene %x11|Random %x13|Message %x14|CD %x16|Game %x17"
+ "|Visibility %x18";
+ break;
+ default:
+ return "Actuators %t|Motion %x0|Constraint %x9|Ipo %x1"
+ "|Camera %x3|Sound %x5|Property %x6|Edit Object %x10"
+ "|Scene %x11|Random %x13|Message %x14|CD %x16|Game %x17"
+ "|Visibility %x18";
+ }
+}
+
+
+
+static void set_sca_ob(Object *ob)
+{
+ bController *cont;
+ bActuator *act;
+
+ cont= ob->controllers.first;
+ while(cont) {
+ cont->mynew= (bController *)ob;
+ cont= cont->next;
+ }
+ act= ob->actuators.first;
+ while(act) {
+ act->mynew= (bActuator *)ob;
+ act= act->next;
+ }
+}
+
+static ID **get_selected_and_linked_obs(short *count, short scavisflag)
+{
+ Base *base;
+ Object *ob, *obt;
+ ID **idar;
+ bSensor *sens;
+ bController *cont;
+ unsigned int lay;
+ int a, nr, doit;
+
+ /* we need a sorted object list */
+ /* set scavisflags flags in Objects to indicate these should be evaluated */
+ /* also hide ob pointers in ->new entries of controllerss/actuators */
+
+ *count= 0;
+
+ if(G.scene==NULL) return NULL;
+
+ ob= G.main->object.first;
+ while(ob) {
+ ob->scavisflag= 0;
+ set_sca_ob(ob);
+ ob= ob->id.next;
+ }
+
+ if(G.vd) lay= G.vd->lay;
+ else lay= G.scene->lay;
+
+ base= FIRSTBASE;
+ while(base) {
+ if(base->lay & lay) {
+ if(base->flag & SELECT) {
+ if(scavisflag & BUTS_SENS_SEL) base->object->scavisflag |= OB_VIS_SENS;
+ if(scavisflag & BUTS_CONT_SEL) base->object->scavisflag |= OB_VIS_CONT;
+ if(scavisflag & BUTS_ACT_SEL) base->object->scavisflag |= OB_VIS_ACT;
+ }
+ }
+ base= base->next;
+ }
+
+ if(OBACT) {
+ if(scavisflag & BUTS_SENS_ACT) OBACT->scavisflag |= OB_VIS_SENS;
+ if(scavisflag & BUTS_CONT_ACT) OBACT->scavisflag |= OB_VIS_CONT;
+ if(scavisflag & BUTS_ACT_ACT) OBACT->scavisflag |= OB_VIS_ACT;
+ }
+
+ if(scavisflag & (BUTS_SENS_LINK|BUTS_CONT_LINK|BUTS_ACT_LINK)) {
+ doit= 1;
+ while(doit) {
+ doit= 0;
+
+ ob= G.main->object.first;
+ while(ob) {
+
+ /* 1st case: select sensor when controller selected */
+ if((scavisflag & BUTS_SENS_LINK) && (ob->scavisflag & OB_VIS_SENS)==0) {
+ sens= ob->sensors.first;
+ while(sens) {
+ for(a=0; a<sens->totlinks; a++) {
+ if(sens->links[a]) {
+ obt= (Object *)sens->links[a]->mynew;
+ if(obt && (obt->scavisflag & OB_VIS_CONT)) {
+ doit= 1;
+ ob->scavisflag |= OB_VIS_SENS;
+ break;
+ }
+ }
+ }
+ if(doit) break;
+ sens= sens->next;
+ }
+ }
+
+ /* 2nd case: select cont when act selected */
+ if((scavisflag & BUTS_CONT_LINK) && (ob->scavisflag & OB_VIS_CONT)==0) {
+ cont= ob->controllers.first;
+ while(cont) {
+ for(a=0; a<cont->totlinks; a++) {
+ if(cont->links[a]) {
+ obt= (Object *)cont->links[a]->mynew;
+ if(obt && (obt->scavisflag & OB_VIS_ACT)) {
+ doit= 1;
+ ob->scavisflag |= OB_VIS_CONT;
+ break;
+ }
+ }
+ }
+ if(doit) break;
+ cont= cont->next;
+ }
+ }
+
+ /* 3rd case: select controller when sensor selected */
+ if((scavisflag & BUTS_CONT_LINK) && (ob->scavisflag & OB_VIS_SENS)) {
+ sens= ob->sensors.first;
+ while(sens) {
+ for(a=0; a<sens->totlinks; a++) {
+ if(sens->links[a]) {
+ obt= (Object *)sens->links[a]->mynew;
+ if(obt && (obt->scavisflag & OB_VIS_CONT)==0) {
+ doit= 1;
+ obt->scavisflag |= OB_VIS_CONT;
+ }
+ }
+ }
+ sens= sens->next;
+ }
+ }
+
+ /* 4th case: select actuator when controller selected */
+ if( (scavisflag & BUTS_ACT_LINK) && (ob->scavisflag & OB_VIS_CONT)) {
+ cont= ob->controllers.first;
+ while(cont) {
+ for(a=0; a<cont->totlinks; a++) {
+ if(cont->links[a]) {
+ obt= (Object *)cont->links[a]->mynew;
+ if(obt && (obt->scavisflag & OB_VIS_ACT)==0) {
+ doit= 1;
+ obt->scavisflag |= OB_VIS_ACT;
+ }
+ }
+ }
+ cont= cont->next;
+ }
+
+ }
+ ob= ob->id.next;
+ }
+ }
+ }
+
+ /* now we count */
+ ob= G.main->object.first;
+ while(ob) {
+ if( ob->scavisflag ) (*count)++;
+ ob= ob->id.next;
+ }
+
+ if(*count==0) return NULL;
+ if(*count>24) *count= 24; /* temporal */
+
+ idar= MEM_callocN( (*count)*sizeof(void *), "idar");
+
+ ob= G.main->object.first;
+ nr= 0;
+ while(ob) {
+ if( ob->scavisflag ) {
+ idar[nr]= (ID *)ob;
+ nr++;
+ }
+ if(nr>=24) break;
+ ob= ob->id.next;
+ }
+
+ /* just to be sure... these were set in set_sca_done_ob() */
+ clear_sca_new_poins();
+
+ return idar;
+}
+
+
+static int get_col_sensor(int type)
+{
+ switch(type) {
+ case SENS_ALWAYS: return TH_BUT_ACTION;
+ case SENS_TOUCH: return TH_BUT_NEUTRAL;
+ case SENS_COLLISION: return TH_BUT_SETTING;
+ case SENS_NEAR: return TH_BUT_SETTING1;
+ case SENS_KEYBOARD: return TH_BUT_SETTING2;
+ case SENS_PROPERTY: return TH_BUT_NUM;
+ case SENS_MOUSE: return TH_BUT_TEXTFIELD;
+ case SENS_RADAR: return TH_BUT_POPUP;
+ case SENS_RANDOM: return TH_BUT_NEUTRAL;
+ case SENS_RAY: return TH_BUT_SETTING1;
+ case SENS_MESSAGE: return TH_BUT_SETTING2;
+ case SENS_JOYSTICK: return TH_BUT_NEUTRAL;
+ default: return TH_BUT_NEUTRAL;
+ }
+}
+static void set_col_sensor(int type, int medium)
+{
+ int col= get_col_sensor(type);
+ BIF_ThemeColorShade(col, medium?30:0);
+}
+
+/**
+ * Draws a toggle for pulse mode, a frequency field and a toggle to invert
+ * the value of this sensor. Operates on the shared data block of sensors.
+ */
+static void draw_default_sensor_header(bSensor *sens,
+ uiBlock *block,
+ short x,
+ short y,
+ short w)
+{
+ /* Pulsing and frequency */
+ uiDefIconButBitS(block, TOG, SENS_PULSE_REPEAT, 1, ICON_DOTSUP,
+ (short)(x + 10 + 0. * (w-20)), (short)(y - 19), (short)(0.15 * (w-20)), 19,
+ &sens->pulse, 0.0, 0.0, 0, 0,
+ "Activate TRUE level triggering (pulse mode)");
+
+ uiDefIconButBitS(block, TOG, SENS_NEG_PULSE_MODE, 1, ICON_DOTSDOWN,
+ (short)(x + 10 + 0.15 * (w-20)), (short)(y - 19), (short)(0.15 * (w-20)), 19,
+ &sens->pulse, 0.0, 0.0, 0, 0,
+ "Activate FALSE level triggering (pulse mode)");
+ uiDefButS(block, NUM, 1, "f:",
+ (short)(x + 10 + 0.3 * (w-20)), (short)(y - 19), (short)(0.275 * (w-20)), 19,
+ &sens->freq, 0.0, 10000.0, 0, 0,
+ "Delay between repeated pulses (in logic tics, 0 = no delay)");
+
+ /* value or shift? */
+ uiDefButS(block, TOG, 1, "Inv",
+ (short)(x + 10 + 0.85 * (w-20)), (short)(y - 19), (short)(0.15 * (w-20)), 19,
+ &sens->invert, 0.0, 0.0, 0, 0,
+ "Invert the level (output) of this sensor");
+}
+
+static short draw_sensorbuttons(bSensor *sens, uiBlock *block, short xco, short yco, short width,char* objectname)
+{
+ bNearSensor *ns = NULL;
+ bTouchSensor *ts = NULL;
+ bKeyboardSensor *ks = NULL;
+ bPropertySensor *ps = NULL;
+ bMouseSensor *ms = NULL;
+ bCollisionSensor *cs = NULL;
+ bRadarSensor *rs = NULL;
+ bRandomSensor *randomSensor = NULL;
+ bRaySensor *raySens = NULL;
+ bMessageSensor *mes = NULL;
+ bJoystickSensor *joy = NULL;
+
+ short ysize;
+ char *str;
+
+ /* yco is at the top of the rect, draw downwards */
+
+ uiBlockSetEmboss(block, UI_EMBOSSM);
+
+ set_col_sensor(sens->type, 0);
+
+ switch (sens->type)
+ {
+ case SENS_ALWAYS:
+ {
+ ysize= 24;
+
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+
+ draw_default_sensor_header(sens, block, xco, yco, width);
+
+ yco-= ysize;
+
+ break;
+ }
+ case SENS_TOUCH:
+ {
+ ysize= 48;
+
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+
+ draw_default_sensor_header(sens, block, xco, yco, width);
+
+ ts= sens->data;
+
+ /* uiDefBut(block, TEX, 1, "Property:", xco,yco-22,width, 19, &ts->name, 0, 31, 0, 0, "Only look for Objects with this property"); */
+ uiDefIDPoinBut(block, test_matpoin_but, ID_MA, 1, "MA:",(short)(xco + 10),(short)(yco-44), (short)(width - 20), 19, &ts->ma, "Only look for floors with this Material");
+ ///* uiDefButF(block, NUM, 1, "Margin:", xco+width/2,yco-44,width/2, 19, &ts->dist, 0.0, 10.0, 100, 0, "Extra margin (distance) for larger sensitivity");
+ yco-= ysize;
+ break;
+ }
+ case SENS_COLLISION:
+ {
+ ysize= 48;
+
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+
+ draw_default_sensor_header(sens, block, xco, yco, width);
+ cs= sens->data;
+
+ /* The collision sensor will become a generic collision (i.e. it */
+ /* absorb the old touch sensor). */
+
+ uiDefButBitS(block, TOG, SENS_COLLISION_MATERIAL, B_REDR, "M/P",(short)(xco + 10),(short)(yco - 44),
+ (short)(0.20 * (width-20)), 19, &cs->mode, 0.0, 0.0, 0, 0,
+ "Toggle collision on material or property.");
+
+ if (cs->mode & SENS_COLLISION_MATERIAL) {
+ uiDefBut(block, TEX, 1, "Material:", (short)(xco + 10 + 0.20 * (width-20)),
+ (short)(yco-44), (short)(0.8*(width-20)), 19, &cs->materialName, 0, 31, 0, 0,
+ "Only look for Objects with this material");
+ } else {
+ uiDefBut(block, TEX, 1, "Property:", (short)(xco + 10 + 0.20 * (width-20)), (short)(yco-44),
+ (short)(0.8*(width-20)), 19, &cs->name, 0, 31, 0, 0,
+ "Only look for Objects with this property");
+ }
+
+ /* uiDefButS(block, NUM, 1, "Damp:", xco+10+width-90,yco-24, 70, 19, &cs->damp, 0, 250, 0, 0, "For 'damp' time don't detect another collision"); */
+
+ yco-= ysize;
+ break;
+ }
+ case SENS_NEAR:
+ {
+ ysize= 72;
+
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+
+ draw_default_sensor_header(sens, block, xco, yco, width);
+ ns= sens->data;
+
+ uiDefBut(block, TEX, 1, "Property:",(short)(10+xco),(short)(yco-44), (short)(width-20), 19,
+ &ns->name, 0, 31, 0, 0, "Only look for Objects with this property");
+ uiDefButF(block, NUM, 1, "Dist",(short)(10+xco),(short)(yco-68),(short)((width-22)/2), 19,
+ &ns->dist, 0.0, 1000.0, 1000, 0, "Trigger distance");
+ uiDefButF(block, NUM, 1, "Reset",(short)(10+xco+(width-22)/2), (short)(yco-68), (short)((width-22)/2), 19,
+ &ns->resetdist, 0.0, 1000.0, 1000, 0, "Reset distance");
+ yco-= ysize;
+ break;
+ }
+ case SENS_RADAR:
+ {
+ ysize= 72;
+
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+
+ draw_default_sensor_header(sens, block, xco, yco, width);
+
+ rs= sens->data;
+
+ uiDefBut(block, TEX, 1, "Prop:",
+ (short)(10+xco),(short)(yco-44), (short)(0.7 * (width-20)), 19,
+ &rs->name, 0, 31, 0, 0,
+ "Only look for Objects with this property");
+ uiDefButS(block, ROW, 1, "X",
+ (short)(10+xco+0.7 * (width-20)),(short)(yco-44), (short)(0.1 * (width-22)),19,
+ &rs->axis, 2.0, 0, 0, 0,
+ "Cast the cone along the object's positive x-axis");
+ uiDefButS(block, ROW, 1, "Y",
+ (short)(10+xco+0.8 * (width-20)),(short)(yco-44),(short)(0.1 * (width-22)), 19,
+ &rs->axis, 2.0, 1, 0, 0,
+ "Cast the cone along the object's positive y-axis");
+ uiDefButS(block, ROW, 1, "Z",
+ (short)(10+xco+0.9 * (width-20)), (short)(yco-44), (short)(0.1 * (width-22)), 19,
+ &rs->axis, 2.0, 2, 0, 0,
+ "Cast the cone along the object's positive z-axis");
+ uiDefButF(block, NUM, 1, "Ang:",
+ (short)(10+xco), (short)(yco-68), (short)((width-20)/2), 19,
+ &rs->angle, 0.0, 179.9, 10, 0,
+ "Opening angle of the radar cone.");
+ uiDefButF(block, NUM, 1, "Dist:",
+ (short)(xco+10 + (width-20)/2), (short)(yco-68), (short)((width-20)/2), 19,
+ &rs->range, 0.01, 10000.0, 100, 0,
+ "Depth of the radar cone");
+ yco-= ysize;
+ break;
+ }
+ case SENS_KEYBOARD:
+ {
+ /* 5 lines: 120 height */
+ ysize= 120;
+
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+
+ /* header line */
+ draw_default_sensor_header(sens, block, xco, yco, width);
+ ks= sens->data;
+
+ /* line 2: hotkey and allkeys toggle */
+ uiDefKeyevtButS(block, B_DIFF, "", xco+40, yco-44, (width)/2, 19, &ks->key, "Key code");
+
+ /* line 3: two key modifyers (qual1, qual2) */
+ uiDefKeyevtButS(block, B_DIFF, "", xco+40, yco-68, (width-50)/2, 19, &ks->qual, "Modifier key code");
+ uiDefKeyevtButS(block, B_DIFF, "", xco+40+(width-50)/2, yco-68, (width-50)/2, 19, &ks->qual2, "Second Modifier key code");
+
+ /* labels for line 1 and 2 */
+ uiDefBut(block, LABEL, 0, "Key", xco, yco-44, 40, 19, NULL, 0, 0, 0, 0, "");
+ uiDefBut(block, LABEL, 0, "Hold", xco, yco-68, 40, 19, NULL, 0, 0, 0, 0, "");
+
+ /* part of line 1 */
+ uiBlockSetCol(block, TH_BUT_SETTING2);
+ uiDefButBitS(block, TOG, 1, 0, "All keys", xco+40+(width/2), yco-44, (width/2)-50, 19,
+ &ks->type, 0, 0, 0, 0, "");
+
+ /* line 4: toggle property for string logging mode */
+ uiDefBut(block, TEX, 1, "LogToggle: ",
+ xco+10, yco-92, (width-20), 19,
+ ks->toggleName, 0, 31, 0, 0,
+ "Property that indicates whether to log "
+ "keystrokes as a string.");
+
+ /* line 5: target property for string logging mode */
+ uiDefBut(block, TEX, 1, "Target: ",
+ xco+10, yco-116, (width-20), 19,
+ ks->targetName, 0, 31, 0, 0,
+ "Property that receives the keystrokes in case "
+ "a string is logged.");
+
+ yco-= ysize;
+ break;
+ }
+ case SENS_PROPERTY:
+ {
+ ysize= 96;
+
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize,
+ (float)xco+width, (float)yco, 1);
+
+ draw_default_sensor_header(sens, block, xco, yco, width);
+ ps= sens->data;
+
+ str= "Type %t|Equal %x0|Not Equal %x1|Interval %x2|Changed %x3";
+ /* str= "Type %t|Equal %x0|Not Equal %x1"; */
+ uiDefButI(block, MENU, B_REDR, str, xco+30,yco-44,width-60, 19,
+ &ps->type, 0, 31, 0, 0, "Type");
+
+ if (ps->type != SENS_PROP_EXPRESSION)
+ {
+ uiDefBut(block, TEX, 1, "Prop: ", xco+30,yco-68,width-60, 19,
+ ps->name, 0, 31, 0, 0, "Property name");
+ }
+
+ if(ps->type == SENS_PROP_INTERVAL)
+ {
+ uiDefBut(block, TEX, 1, "Min: ", xco,yco-92,width/2, 19,
+ ps->value, 0, 31, 0, 0, "test for min value");
+ uiDefBut(block, TEX, 1, "Max: ", xco+width/2,yco-92,width/2, 19,
+ ps->maxvalue, 0, 31, 0, 0, "test for max value");
+ }
+ else if(ps->type == SENS_PROP_CHANGED);
+ else
+ {
+ uiDefBut(block, TEX, 1, "Value: ", xco+30,yco-92,width-60, 19,
+ ps->value, 0, 31, 0, 0, "test for value");
+ }
+
+ yco-= ysize;
+ break;
+ }
+ case SENS_MOUSE:
+ {
+ ms= sens->data;
+ /* Two lines: 48 pixels high. */
+ ysize = 48;
+
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+
+ /* line 1: header */
+ draw_default_sensor_header(sens, block, xco, yco, width);
+
+ /* Line 2: type selection. The number are a bit mangled to get
+ * proper compatibility with older .blend files. */
+ str= "Type %t|Left button %x1|Middle button %x2|"
+ "Right button %x4|Wheel Up %x5|Wheel Down %x6|Movement %x8|Mouse over %x16|Mouse over any%x32";
+ uiDefButS(block, MENU, B_REDR, str, xco+10, yco-44, width-20, 19,
+ &ms->type, 0, 31, 0, 0,
+ "Specify the type of event this mouse sensor should trigger on.");
+
+ yco-= ysize;
+ break;
+ }
+ case SENS_RANDOM:
+ {
+ ysize = 48;
+
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+
+ draw_default_sensor_header(sens, block, xco, yco, width);
+ randomSensor = sens->data;
+ /* some files were wrongly written, avoid crash now */
+ if (randomSensor)
+ {
+ uiDefButI(block, NUM, 1, "Seed: ", xco+10,yco-44,(width-20), 19,
+ &randomSensor->seed, 0, 1000, 0, 0,
+ "Initial seed of the generator. (Choose 0 for not random)");
+ }
+ yco-= ysize;
+ break;
+ }
+ case SENS_RAY:
+ {
+ ysize = 72;
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+
+ draw_default_sensor_header(sens, block, xco, yco, width);
+ raySens = sens->data;
+
+ /* 1. property or material */
+ uiDefButBitS(block, TOG, SENS_COLLISION_MATERIAL, B_REDR, "M/P",
+ xco + 10,yco - 44, 0.20 * (width-20), 19,
+ &raySens->mode, 0.0, 0.0, 0, 0,
+ "Toggle collision on material or property.");
+
+ if (raySens->mode & SENS_COLLISION_MATERIAL)
+ {
+ uiDefBut(block, TEX, 1, "Material:", xco + 10 + 0.20 * (width-20), yco-44, 0.8*(width-20), 19,
+ &raySens->matname, 0, 31, 0, 0,
+ "Only look for Objects with this material");
+ }
+ else
+ {
+ uiDefBut(block, TEX, 1, "Property:", xco + 10 + 0.20 * (width-20), yco-44, 0.8*(width-20), 19,
+ &raySens->propname, 0, 31, 0, 0,
+ "Only look for Objects with this property");
+ }
+
+ /* 2. sensing range */
+ uiDefButF(block, NUM, 1, "Range", xco+10, yco-68, 0.6 * (width-20), 19,
+ &raySens->range, 0.01, 10000.0, 100, 0,
+ "Sense objects no farther than this distance");
+
+ /* 3. axis choice */
+ str = "Type %t|+ X axis %x1|+ Y axis %x0|+ Z axis %x2|- X axis %x3|- Y axis %x4|- Z axis %x5";
+ uiDefButI(block, MENU, B_REDR, str, xco+10 + 0.6 * (width-20), yco-68, 0.4 * (width-20), 19,
+ &raySens->axisflag, 2.0, 31, 0, 0,
+ "Specify along which axis the ray is cast.");
+
+ yco-= ysize;
+ break;
+ }
+ case SENS_MESSAGE:
+ {
+ mes = sens->data;
+ ysize = 2 * 24; /* total number of lines * 24 pixels/line */
+
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize,
+ (float)xco+width, (float)yco, 1);
+
+ /* line 1: header line */
+ draw_default_sensor_header(sens, block, xco, yco, width);
+
+ /* line 2: Subject filter */
+ uiDefBut(block, TEX, 1, "Subject: ",
+ (xco+10), (yco-44), (width-20), 19,
+ mes->subject, 0, 31, 0, 0,
+ "Optional subject filter: only accept messages with this subject"
+ ", or empty for all");
+
+ yco -= ysize;
+ break;
+ }
+ case SENS_JOYSTICK:
+ {
+
+ ysize = 72;
+
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+
+ /* line 1: header */
+ draw_default_sensor_header(sens, block, xco, yco, width);
+
+ joy= sens->data;
+
+
+ str= "Type %t|Button %x0|Axis %x1|Hat%x2";
+ uiDefButS(block, MENU, B_REDR, str, xco+10, yco-44, 0.6 * (width-20), 19,
+ &joy->type, 0, 31, 0, 0,
+ "The type of event this joystick sensor is triggered on.");
+
+ if(joy->type == SENS_JOY_BUTTON)
+ {
+ uiDefButI(block, NUM, 1, "Number:", xco+10, yco-68, 0.6 * (width-20), 19,
+ &joy->button, 0, 18, 100, 0,
+ "Specify which button to use");
+
+ str = "Type %t|Pressed %x0|Released %x1";
+ uiDefButI(block, MENU, B_REDR, str, xco+10 + 0.6 * (width-20), yco-68, 0.4 * (width-20), 19,
+ &joy->buttonf, 2.0, 31, 0, 0,
+ "Button pressed or released.");
+ }
+ else if(joy->type == SENS_JOY_AXIS)
+ {
+ uiDefButI(block, NUM, 1, "Number:", xco+10, yco-68, 0.6 * (width-20), 19,
+ &joy->axis, 1, 2.0, 100, 0,
+ "Specify which axis to use");
+
+ uiDefButI(block, NUM, 1, "Threshold:", xco+10 + 0.6 * (width-20),yco-44, 0.4 * (width-20), 19,
+ &joy->precision, 0, 32768.0, 100, 0,
+ "Specify the precision of the axis");
+
+ str = "Type %t|Up Axis %x1 |Down Axis %x3|Left Axis %x2|Right Axis %x0";
+ uiDefButI(block, MENU, B_REDR, str, xco+10 + 0.6 * (width-20), yco-68, 0.4 * (width-20), 19,
+ &joy->axisf, 2.0, 31, 0, 0,
+ "The direction of the axis");
+ }
+ else
+ {
+ uiDefButI(block, NUM, 1, "Number:", xco+10, yco-68, 0.6 * (width-20), 19,
+ &joy->hat, 1, 2.0, 100, 0,
+ "Specify which hat to use");
+
+ uiDefButI(block, NUM, 1, "Direction:", xco+10 + 0.6 * (width-20), yco-68, 0.4 * (width-20), 19,
+ &joy->hatf, 0, 12, 100, 0,
+ "Specify hat direction");
+ }
+ yco-= ysize;
+ break;
+ }
+ }
+
+ uiBlockSetEmboss(block, UI_EMBOSSM);
+ uiBlockSetCol(block, TH_AUTO);
+
+ return yco-4;
+}
+
+
+
+static short draw_controllerbuttons(bController *cont, uiBlock *block, short xco, short yco, short width)
+{
+ bExpressionCont *ec;
+ bPythonCont *pc;
+ short ysize;
+
+ uiBlockSetEmboss(block, UI_EMBOSSM);
+
+ switch (cont->type) {
+ case CONT_EXPRESSION:
+ ysize= 28;
+
+ BIF_ThemeColor(TH_BUT_SETTING);
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+
+ /* uiDefBut(block, LABEL, 1, "Not yet...", xco,yco-24,80, 19, NULL, 0, 0, 0, 0, ""); */
+ ec= cont->data;
+ /* uiDefBut(block, BUT, 1, "Variables", xco,yco-24,80, 19, NULL, 0, 0, 0, 0, "Available variables for expression"); */
+ uiDefBut(block, TEX, 1, "Exp:", xco + 10 , yco-21, width-20, 19,
+ ec->str, 0, 127, 0, 0,
+ "Expression");
+
+ yco-= ysize;
+ break;
+ case CONT_PYTHON:
+ ysize= 28;
+
+ if(cont->data==NULL) init_controller(cont);
+ pc= cont->data;
+
+ BIF_ThemeColor(TH_BUT_SETTING1);
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+
+ uiDefIDPoinBut(block, test_scriptpoin_but, ID_SCRIPT, 1, "Script: ", xco+45,yco-24,width-90, 19, &pc->text, "");
+
+ yco-= ysize;
+ break;
+
+ default:
+ ysize= 4;
+
+ BIF_ThemeColor(TH_BUT_NEUTRAL);
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+
+ yco-= ysize;
+ }
+
+ uiBlockSetEmboss(block, UI_EMBOSSM);
+ uiBlockSetCol(block, TH_AUTO);
+
+ return yco;
+}
+
+static int get_col_actuator(int type)
+{
+ switch(type) {
+ case ACT_ACTION: return TH_BUT_ACTION;
+ case ACT_OBJECT: return TH_BUT_NEUTRAL;
+ case ACT_IPO: return TH_BUT_SETTING;
+ case ACT_PROPERTY: return TH_BUT_SETTING1;
+ case ACT_SOUND: return TH_BUT_SETTING2;
+ case ACT_CD: return TH_BUT_NUM;
+ case ACT_CAMERA: return TH_BUT_TEXTFIELD;
+ case ACT_EDIT_OBJECT: return TH_BUT_POPUP;
+ case ACT_GROUP: return TH_BUT_ACTION;
+ case ACT_RANDOM: return TH_BUT_NEUTRAL;
+ case ACT_SCENE: return TH_BUT_SETTING;
+ case ACT_MESSAGE: return TH_BUT_SETTING1;
+ case ACT_GAME: return TH_BUT_SETTING2;
+ case ACT_VISIBILITY: return TH_BUT_NUM;
+ case ACT_CONSTRAINT: return TH_BUT_ACTION;
+ default: return TH_BUT_NEUTRAL;
+ }
+}
+static void set_col_actuator(int item, int medium)
+{
+ int col= get_col_actuator(item);
+ BIF_ThemeColorShade(col, medium?30:10);
+
+}
+
+static short draw_actuatorbuttons(bActuator *act, uiBlock *block, short xco, short yco, short width)
+{
+ bSoundActuator *sa = NULL;
+ bCDActuator *cda = NULL;
+ bObjectActuator *oa = NULL;
+ bIpoActuator *ia = NULL;
+ bPropertyActuator *pa = NULL;
+ bCameraActuator *ca = NULL;
+ bEditObjectActuator *eoa = NULL;
+ bConstraintActuator *coa = NULL;
+ bSceneActuator *sca = NULL;
+ bGroupActuator *ga = NULL;
+ bRandomActuator *randAct = NULL;
+ bMessageActuator *ma = NULL;
+ bActionActuator *aa = NULL;
+ bGameActuator *gma = NULL;
+ bVisibilityActuator *visAct = NULL;
+
+ float *fp;
+ short ysize = 0, wval;
+ char *str;
+ int myline;
+
+ /* yco is at the top of the rect, draw downwards */
+ uiBlockSetEmboss(block, UI_EMBOSSM);
+ set_col_actuator(act->type, 0);
+
+ switch (act->type)
+ {
+ case ACT_OBJECT:
+ {
+ ysize= 129;
+
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+
+ oa = act->data;
+ wval = (width-100)/3;
+
+ uiDefBut(block, LABEL, 0, "Force", xco, yco-22, 55, 19, NULL, 0, 0, 0, 0, "Sets the force");
+ uiDefButF(block, NUM, 0, "", xco+45, yco-22, wval, 19, oa->forceloc, -10000.0, 10000.0, 10, 0, "");
+ uiDefButF(block, NUM, 0, "", xco+45+wval, yco-22, wval, 19, oa->forceloc+1, -10000.0, 10000.0, 10, 0, "");
+ uiDefButF(block, NUM, 0, "", xco+45+2*wval, yco-22, wval, 19, oa->forceloc+2, -10000.0, 10000.0, 10, 0, "");
+
+ uiDefBut(block, LABEL, 0, "Torque", xco, yco-41, 55, 19, NULL, 0, 0, 0, 0, "Sets the torque");
+ uiDefButF(block, NUM, 0, "", xco+45, yco-41, wval, 19, oa->forcerot, -10000.0, 10000.0, 10, 0, "");
+ uiDefButF(block, NUM, 0, "", xco+45+wval, yco-41, wval, 19, oa->forcerot+1, -10000.0, 10000.0, 10, 0, "");
+ uiDefButF(block, NUM, 0, "", xco+45+2*wval, yco-41, wval, 19, oa->forcerot+2, -10000.0, 10000.0, 10, 0, "");
+
+ uiDefBut(block, LABEL, 0, "dLoc", xco, yco-64, 45, 19, NULL, 0, 0, 0, 0, "Sets the dLoc");
+ uiDefButF(block, NUM, 0, "", xco+45, yco-64, wval, 19, oa->dloc, -10000.0, 10000.0, 10, 0, "");
+ uiDefButF(block, NUM, 0, "", xco+45+wval, yco-64, wval, 19, oa->dloc+1, -10000.0, 10000.0, 10, 0, "");
+ uiDefButF(block, NUM, 0, "", xco+45+2*wval, yco-64, wval, 19, oa->dloc+2, -10000.0, 10000.0, 10, 0, "");
+
+ uiDefBut(block, LABEL, 0, "dRot", xco, yco-83, 45, 19, NULL, 0, 0, 0, 0, "Sets the dRot");
+ uiDefButF(block, NUM, 0, "", xco+45, yco-83, wval, 19, oa->drot, -10000.0, 10000.0, 10, 0, "");
+ uiDefButF(block, NUM, 0, "", xco+45+wval, yco-83, wval, 19, oa->drot+1, -10000.0, 10000.0, 10, 0, "");
+ uiDefButF(block, NUM, 0, "", xco+45+2*wval, yco-83, wval, 19, oa->drot+2, -10000.0, 10000.0, 10, 0, "");
+
+ uiDefBut(block, LABEL, 0, "linV", xco, yco-106, 45, 19, NULL, 0, 0, 0, 0, "Sets the linear velocity");
+ uiDefButF(block, NUM, 0, "", xco+45, yco-106, wval, 19, oa->linearvelocity, -10000.0, 10000.0, 10, 0, "");
+ uiDefButF(block, NUM, 0, "", xco+45+wval, yco-106, wval, 19, oa->linearvelocity+1, -10000.0, 10000.0, 10, 0, "");
+ uiDefButF(block, NUM, 0, "", xco+45+2*wval, yco-106, wval, 19, oa->linearvelocity+2, -10000.0, 10000.0, 10, 0, "");
+
+ uiDefBut(block, LABEL, 0, "angV", xco, yco-125, 45, 19, NULL, 0, 0, 0, 0, "Sets the angular velocity");
+ uiDefButF(block, NUM, 0, "", xco+45, yco-125, wval, 19, oa->angularvelocity, -10000.0, 10000.0, 10, 0, "");
+ uiDefButF(block, NUM, 0, "", xco+45+wval, yco-125, wval, 19, oa->angularvelocity+1, -10000.0, 10000.0, 10, 0, "");
+ uiDefButF(block, NUM, 0, "", xco+45+2*wval, yco-125, wval, 19, oa->angularvelocity+2, -10000.0, 10000.0, 10, 0, "");
+
+ uiDefButBitI(block, TOG, ACT_FORCE_LOCAL, 0, "L", xco+45+3*wval, yco-22, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation");
+ uiDefButBitI(block, TOG, ACT_TORQUE_LOCAL, 0, "L", xco+45+3*wval, yco-41, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation");
+ uiDefButBitI(block, TOG, ACT_DLOC_LOCAL, 0, "L", xco+45+3*wval, yco-64, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation");
+ uiDefButBitI(block, TOG, ACT_DROT_LOCAL, 0, "L", xco+45+3*wval, yco-83, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation");
+ uiDefButBitI(block, TOG, ACT_LIN_VEL_LOCAL, 0, "L", xco+45+3*wval, yco-106, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation");
+ uiDefButBitI(block, TOG, ACT_ANG_VEL_LOCAL, 0, "L", xco+45+3*wval, yco-125, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation");
+
+ uiDefButBitI(block, TOG, ACT_ADD_LIN_VEL, 0, "add",xco+45+3*wval+15, yco-106, 35, 19, &oa->flag, 0.0, 0.0, 0, 0, "Toggles between ADD and SET linV");
+
+ yco-= ysize;
+ break;
+ }
+ case ACT_ACTION:
+ {
+ /* DrawAct */
+#ifdef __NLA_ACTION_BY_MOTION_ACTUATOR
+ ysize = 112;
+#else
+ ysize= 92;
+#endif
+
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+
+ aa = act->data;
+ wval = (width-60)/3;
+
+ // str= "Action types %t|Play %x0|Ping Pong %x1|Flipper %x2|Loop Stop %x3|Loop End %x4|Property %x6";
+#ifdef __NLA_ACTION_BY_MOTION_ACTUATOR
+ str= "Action types %t|Play %x0|Flipper %x2|Loop Stop %x3|Loop End %x4|Property %x6|Displacement %x7";
+#else
+ str= "Action types %t|Play %x0|Flipper %x2|Loop Stop %x3|Loop End %x4|Property %x6";
+#endif
+ uiDefButS(block, MENU, B_REDR, str, xco+30, yco-24, width-60, 19, &aa->type, 0.0, 0.0, 0.0, 0.0, "Action playback type");
+ uiDefIDPoinBut(block, test_actionpoin_but, ID_AC, 1, "AC: ", xco+30, yco-44, width-60, 19, &aa->act, "Action name");
+
+ if(aa->type == ACT_ACTION_FROM_PROP)
+ {
+ uiDefBut(block, TEX, 0, "Prop: ",xco+30, yco-64, width-60, 19, aa->name, 0.0, 31.0, 0, 0, "Use this property to define the Action position");
+ }
+ else
+ {
+ uiDefButI(block, NUM, 0, "Sta: ",xco+30, yco-64, (width-60)/2, 19, &aa->sta, 0.0, MAXFRAMEF, 0, 0, "Start frame");
+ uiDefButI(block, NUM, 0, "End: ",xco+30+(width-60)/2, yco-64, (width-60)/2, 19, &aa->end, 0.0, MAXFRAMEF, 0, 0, "End frame");
+ }
+
+
+
+ uiDefButI(block, NUM, 0, "Blendin: ", xco+30, yco-84, (width-60)/2, 19, &aa->blendin, 0.0, MAXFRAMEF, 0.0, 0.0, "Number of frames of motion blending");
+ uiDefButS(block, NUM, 0, "Priority: ", xco+30+(width-60)/2, yco-84, (width-60)/2, 19, &aa->priority, 0.0, 100.0, 0.0, 0.0, "Execution priority - lower numbers will override actions with higher numbers");
+
+#ifdef __NLA_ACTION_BY_MOTION_ACTUATOR
+ if(aa->type == ACT_ACTION_MOTION)
+ {
+ uiDefButF(block, NUM, 0, "Cycle: ",xco+30, yco-104, (width-60)/2, 19, &aa->stridelength, 0.0, 2500.0, 0, 0, "Distance covered by a single cycle of the action");
+ }
+#endif
+
+ yco-=ysize;
+ break;
+ }
+ case ACT_IPO:
+ {
+ ia= act->data;
+
+ ysize= 52;
+
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+
+ str = "Ipo types %t|Play %x0|Ping Pong %x1|Flipper %x2|Loop Stop %x3|Loop End %x4|Property %x6";
+
+ uiDefButS(block, MENU, B_REDR, str, xco+20, yco-24, width-40 - (width-40)/3, 19, &ia->type, 0, 0, 0, 0, "");
+ uiDefButBitS(block, TOG, ACT_IPOCHILD, B_REDR,
+ "Child", xco+20+0.666*(width-40), yco-24, (width-40)/3, 19,
+ &ia->flag, 0, 0, 0, 0,
+ "Add all children Objects as well");
+
+ if(ia->type==ACT_IPO_FROM_PROP) {
+ uiDefBut(block, TEX, 0,
+ "Prop: ", xco+20, yco-44, width-40, 19,
+ ia->name, 0.0, 31.0, 0, 0,
+ "Use this property to define the Ipo position");
+ }
+ else {
+ uiDefButI(block, NUM, 0,
+ "Sta", xco+20, yco-44, (width-100)/2, 19,
+ &ia->sta, 0.0, MAXFRAMEF, 0, 0,
+ "Start frame");
+ uiDefButI(block, NUM, 0,
+ "End", xco+18+(width-90)/2, yco-44, (width-100)/2, 19,
+ &ia->end, 0.0, MAXFRAMEF, 0, 0,
+ "End frame");
+
+ uiDefButBitS(block, TOG, ACT_IPOFORCE, B_REDR,
+ "Force", xco+width-78, yco-44, 43, 19,
+ &ia->flag, 0, 0, 0, 0,
+ "Convert Ipo to force");
+
+ /* Only show the do-force-local toggle if force is requested */
+ if (ia->flag & ACT_IPOFORCE) {
+ uiDefButBitS(block, TOG, ACT_IPOFORCE_LOCAL, 0,
+ "L", xco+width-35, yco-44, 15, 19,
+ &ia->flag, 0, 0, 0, 0,
+ "Let the force-ipo act in local coordinates.");
+ }
+
+ }
+ yco-= ysize;
+ break;
+ }
+ case ACT_PROPERTY:
+ {
+ ysize= 68;
+
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+
+ pa= act->data;
+
+ str= "Type %t|Assign %x0|Add %x1|Copy %x2";
+ uiDefButI(block, MENU, B_REDR, str, xco+30,yco-24,width-60, 19, &pa->type, 0, 31, 0, 0, "Type");
+
+ uiDefBut(block, TEX, 1, "Prop: ", xco+30,yco-44,width-60, 19, pa->name, 0, 31, 0, 0, "Property name");
+
+ if(pa->type==ACT_PROP_COPY) {
+ uiDefIDPoinBut(block, test_obpoin_but, ID_OB, 1, "OB:", xco+10, yco-64, (width-20)/2, 19, &(pa->ob), "Copy from this Object");
+ uiDefBut(block, TEX, 1, "Prop: ", xco+10+(width-20)/2, yco-64, (width-20)/2, 19, pa->value, 0, 31, 0, 0, "Copy this property");
+ }
+ else {
+ uiDefBut(block, TEX, 1, "Value: ", xco+30,yco-64,width-60, 19, pa->value, 0, 31, 0, 0, "change with this value");
+ }
+ yco-= ysize;
+
+ break;
+ }
+ case ACT_SOUND:
+ {
+ ysize = 70;
+
+ sa = act->data;
+ sa->sndnr = 0;
+
+ wval = (width-20)/2;
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+
+ if(G.main->sound.first) {
+ IDnames_to_pupstring(&str, "Sound files", NULL, &(G.main->sound), (ID *)sa->sound, &(sa->sndnr));
+ /* reset this value, it is for handling the event */
+ sa->sndnr = 0;
+ uiDefButS(block, MENU, B_SOUNDACT_BROWSE, str, xco+10,yco-22,20,19, &(sa->sndnr), 0, 0, 0, 0, "");
+
+ if(sa->sound) {
+ char dummy_str[] = "Sound mode %t|Play Stop %x0|Play End %x1|Loop Stop %x2|Loop End %x3|Loop Ping Pong Stop %x5|Loop Ping Pong %x4";
+ uiDefBut(block, TEX, B_IDNAME, "SO:",xco+30,yco-22,width-40,19, sa->sound->id.name+2, 0.0, 21.0, 0, 0, "");
+ uiDefButS(block, MENU, 1, dummy_str,xco+10,yco-44,width-20, 19, &sa->type, 0.0, 0.0, 0, 0, "");
+ uiDefButF(block, NUM, 0, "Volume:", xco+10,yco-66,wval, 19, &sa->sound->volume, 0.0, 1.0, 0, 0, "Sets the volume of this sound");
+ uiDefButF(block, NUM, 0, "Pitch:",xco+wval+10,yco-66,wval, 19, &sa->sound->pitch,-12.0, 12.0, 0, 0, "Sets the pitch of this sound");
+ }
+ MEM_freeN(str);
+ }
+ else {
+ uiDefBut(block, LABEL, 0, "Use Sound window (F10) to load samples", xco, yco-24, width, 19, NULL, 0, 0, 0, 0, "");
+ }
+
+ yco-= ysize;
+
+ break;
+ }
+ case ACT_CD:
+ {
+ char cd_type_str[] = "Sound mode %t|Play all tracks %x0|Play one track %x1|"
+ "Volume %x3|Stop %x4|Pause %x5|Resume %x6";
+ cda = act->data;
+
+ if (cda) {
+ if (cda->track == 0) {
+ cda->track = 1;
+ cda->volume = 1;
+ cda->type = ACT_CD_PLAY_ALL;
+ }
+
+ if (cda->type == ACT_CD_PLAY_TRACK || cda->type == ACT_CD_LOOP_TRACK) {
+ ysize = 48;
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+ uiDefButS(block, NUM, 0, "Track:", xco+10,yco-44,width-20, 19, &cda->track, 1, 99, 0, 0, "Select the track to be played");
+ }
+ else if (cda->type == ACT_CD_VOLUME) {
+ ysize = 48;
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+ uiDefButF(block, NUM, 0, "Volume:", xco+10,yco-44,width-20, 19, &cda->volume, 0, 1, 0, 0, "Set the volume for CD playback");
+ }
+ else {
+ ysize = 28;
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+ }
+ uiDefButS(block, MENU, B_REDR, cd_type_str,xco+10,yco-22,width-20, 19, &cda->type, 0.0, 0.0, 0, 0, "");
+ }
+ yco-= ysize;
+ break;
+ }
+ case ACT_CAMERA:
+
+ ysize= 48;
+
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+
+ ca= act->data;
+
+ uiDefIDPoinBut(block, test_obpoin_but, ID_OB, 1, "OB:", xco+10, yco-24, (width-20)/2, 19, &(ca->ob), "Look at this Object");
+ uiDefButF(block, NUM, 0, "Height:", xco+10+(width-20)/2, yco-24, (width-20)/2, 19, &ca->height, 0.0, 20.0, 0, 0, "");
+
+ uiDefButF(block, NUM, 0, "Min:", xco+10, yco-44, (width-60)/2, 19, &ca->min, 0.0, 20.0, 0, 0, "");
+
+ if(ca->axis==0) ca->axis= 'x';
+ uiDefButS(block, ROW, 0, "X", xco+10+(width-60)/2, yco-44, 20, 19, &ca->axis, 4.0, (float)'x', 0, 0, "Camera tries to get behind the X axis");
+ uiDefButS(block, ROW, 0, "Y", xco+30+(width-60)/2, yco-44, 20, 19, &ca->axis, 4.0, (float)'y', 0, 0, "Camera tries to get behind the Y axis");
+
+ uiDefButF(block, NUM, 0, "Max:", xco+20+(width)/2, yco-44, (width-60)/2, 19, &ca->max, 0.0, 20.0, 0, 0, "");
+
+ yco-= ysize;
+
+ break;
+
+ case ACT_EDIT_OBJECT:
+
+ eoa= act->data;
+
+ if(eoa->type==ACT_EDOB_ADD_OBJECT) {
+ int wval; /* just a temp width */
+ ysize = 72;
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+
+ uiDefIDPoinBut(block, test_obpoin_but, ID_OB, 1, "OB:", xco+10, yco-44, (width-20)/2, 19, &(eoa->ob), "Add this Object (cant be on an visible layer)");
+ uiDefButI(block, NUM, 0, "Time:", xco+10+(width-20)/2, yco-44, (width-20)/2, 19, &eoa->time, 0.0, 2000.0, 0, 0, "Duration the new Object lives");
+
+ wval= (width-60)/3;
+ uiDefBut(block, LABEL, 0, "linV", xco, yco-68, 45, 19,
+ NULL, 0, 0, 0, 0,
+ "Velocity upon creation.");
+ uiDefButF(block, NUM, 0, "", xco+45, yco-68, wval, 19,
+ eoa->linVelocity, -100.0, 100.0, 10, 0,
+ "Velocity upon creation, x component.");
+ uiDefButF(block, NUM, 0, "", xco+45+wval, yco-68, wval, 19,
+ eoa->linVelocity+1, -100.0, 100.0, 10, 0,
+ "Velocity upon creation, y component.");
+ uiDefButF(block, NUM, 0, "", xco+45+2*wval, yco-68, wval, 19,
+ eoa->linVelocity+2, -100.0, 100.0, 10, 0,
+ "Velocity upon creation, z component.");
+ uiDefButBitS(block, TOG, 2, 0, "L", xco+45+3*wval, yco-68, 15, 19,
+ &eoa->localflag, 0.0, 0.0, 0, 0,
+ "Apply the transformation locally");
+
+ }
+ else if(eoa->type==ACT_EDOB_END_OBJECT) {
+ ysize= 28;
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+ }
+ else if(eoa->type==ACT_EDOB_REPLACE_MESH) {
+ ysize= 48;
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+
+ uiDefIDPoinBut(block, test_meshpoin_but, ID_ME, 1, "ME:", xco+40, yco-44, (width-80), 19, &(eoa->me), "replace the existing mesh with this one");
+ }
+ else if(eoa->type==ACT_EDOB_TRACK_TO) {
+ ysize= 48;
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+
+ uiDefIDPoinBut(block, test_obpoin_but, ID_OB, 1, "OB:", xco+10, yco-44, (width-20)/2, 19, &(eoa->ob), "Track to this Object");
+ uiDefButI(block, NUM, 0, "Time:", xco+10+(width-20)/2, yco-44, (width-20)/2-40, 19, &eoa->time, 0.0, 2000.0, 0, 0, "Duration the tracking takes");
+ uiDefButS(block, TOG, 0, "3D", xco+width-50, yco-44, 40, 19, &eoa->flag, 0.0, 0.0, 0, 0, "Enable 3D tracking");
+ }
+
+ str= "Edit Object %t|Add Object %x0|End Object %x1|Replace Mesh %x2|Track to %x3";
+ uiDefButS(block, MENU, B_REDR, str, xco+40, yco-24, (width-80), 19, &eoa->type, 0.0, 0.0, 0, 0, "");
+
+ yco-= ysize;
+
+ break;
+
+ case ACT_CONSTRAINT:
+
+ ysize= 44;
+
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+
+ coa= act->data;
+
+/* str= "Limit %t|None %x0|Loc X %x1|Loc Y %x2|Loc Z %x4|Rot X %x8|Rot Y %x16|Rot Z %x32"; */
+ str= "Limit %t|None %x0|Loc X %x1|Loc Y %x2|Loc Z %x4";
+ uiDefButS(block, MENU, 1, str, xco+10, yco-40, 70, 19, &coa->flag, 0.0, 0.0, 0, 0, "");
+
+ uiDefButS(block, NUM, 0, "Damp:", xco+10, yco-20, 70, 19, &coa->damp, 0.0, 100.0, 0, 0, "");
+ uiDefBut(block, LABEL, 0, "Min", xco+80, yco-20, (width-90)/2, 19, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefBut(block, LABEL, 0, "Max", xco+80+(width-90)/2, yco-20, (width-90)/2, 19, NULL, 0.0, 0.0, 0, 0, "");
+
+ if(coa->flag & ACT_CONST_LOCX) fp= coa->minloc;
+ else if(coa->flag & ACT_CONST_LOCY) fp= coa->minloc+1;
+ else if(coa->flag & ACT_CONST_LOCZ) fp= coa->minloc+2;
+ else if(coa->flag & ACT_CONST_ROTX) fp= coa->minrot;
+ else if(coa->flag & ACT_CONST_ROTY) fp= coa->minrot+1;
+ else fp= coa->minrot+2;
+
+ uiDefButF(block, NUM, 0, "", xco+80, yco-40, (width-90)/2, 19, fp, -2000.0, 2000.0, 10, 0, "");
+ uiDefButF(block, NUM, 0, "", xco+80+(width-90)/2, yco-40, (width-90)/2, 19, fp+3, -2000.0, 2000.0, 10, 0, "");
+
+ yco-= ysize;
+
+ break;
+
+ case ACT_SCENE:
+ sca= act->data;
+
+ if(sca->type==ACT_SCENE_RESTART) {
+ ysize= 28;
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+ }
+ else if(sca->type==ACT_SCENE_CAMERA) {
+
+ ysize= 48;
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+
+ uiDefIDPoinBut(block, test_obpoin_but, ID_OB, 1, "OB:", xco+40, yco-44, (width-80), 19, &(sca->camera), "Set this Camera");
+ }
+ else if(sca->type==ACT_SCENE_SET) {
+
+ ysize= 48;
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+
+ uiDefIDPoinBut(block, test_scenepoin_but, ID_SCE, 1, "SCE:", xco+40, yco-44, (width-80), 19, &(sca->scene), "Set this Scene");
+ }
+ else if(sca->type==ACT_SCENE_ADD_FRONT) {
+
+ ysize= 48;
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+
+ uiDefIDPoinBut(block, test_scenepoin_but, ID_SCE, 1, "SCE:", xco+40, yco-44, (width-80), 19, &(sca->scene), "Add an Overlay Scene");
+ }
+ else if(sca->type==ACT_SCENE_ADD_BACK) {
+
+ ysize= 48;
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+
+ uiDefIDPoinBut(block, test_scenepoin_but, ID_SCE, 1, "SCE:", xco+40, yco-44, (width-80), 19, &(sca->scene), "Add a Background Scene");
+ }
+ else if(sca->type==ACT_SCENE_REMOVE) {
+
+ ysize= 48;
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+
+ uiDefIDPoinBut(block, test_scenepoin_but, ID_SCE, 1, "SCE:", xco+40, yco-44, (width-80), 19, &(sca->scene), "Remove a Scene");
+ }
+ else if(sca->type==ACT_SCENE_SUSPEND) {
+
+ ysize= 48;
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+
+ uiDefIDPoinBut(block, test_scenepoin_but, ID_SCE, 1, "SCE:", xco+40, yco-44, (width-80), 19, &(sca->scene), "Pause a Scene");
+ }
+ else if(sca->type==ACT_SCENE_RESUME) {
+
+ ysize= 48;
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+
+ uiDefIDPoinBut(block, test_scenepoin_but, ID_SCE, 1, "SCE:", xco+40, yco-44, (width-80), 19, &(sca->scene), "Unpause a Scene");
+ }
+
+ str= "Scene %t|Restart %x0|Set Scene %x1|Set Camera %x2|Add OverlayScene %x3|Add BackgroundScene %x4|Remove Scene %x5|Suspend Scene %x6|Resume Scene %x7";
+ uiDefButS(block, MENU, B_REDR, str, xco+40, yco-24, (width-80), 19, &sca->type, 0.0, 0.0, 0, 0, "");
+
+ yco-= ysize;
+ break;
+ case ACT_GAME:
+ {
+ gma = act->data;
+ if (gma->type == ACT_GAME_LOAD)
+ {
+ //ysize = 68;
+ ysize = 48;
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+ uiDefBut(block, TEX, 1, "File: ", xco+10, yco-44,width-20,19, &(gma->filename), 0, 63, 0, 0, "Load this file");
+// uiDefBut(block, TEX, 1, "Anim: ", xco+10, yco-64,width-20,19, &(gma->loadaniname), 0, 63, 0, 0, "Use this loadinganimation");
+ }
+/* else if (gma->type == ACT_GAME_START)
+ {
+ ysize = 68;
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+
+ uiDefBut(block, TEX, 1, "File: ", xco+10, yco-44,width-20,19, &(gma->filename), 0, 63, 0, 0, "Load this file");
+ uiDefBut(block, TEX, 1, "Anim: ", xco+10, yco-64,width-20,19, &(gma->loadaniname), 0, 63, 0, 0, "Use this loadinganimation");
+ }
+*/ else if (gma->type == ACT_GAME_RESTART)
+ {
+ ysize = 28;
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+ }
+ else if (gma->type == ACT_GAME_QUIT)
+ {
+ ysize = 28;
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+ }
+
+ //str = "Scene %t|Load game%x0|Start loaded game%x1|Restart this game%x2|Quit this game %x3";
+ str = "Scene %t|Start new game%x0|Restart this game%x2|Quit this game %x3";
+ uiDefButS(block, MENU, B_REDR, str, xco+40, yco-24, (width-80), 19, &gma->type, 0.0, 0.0, 0, 0, "");
+
+ yco -= ysize;
+ break;
+ }
+ case ACT_GROUP:
+ ga= act->data;
+
+ ysize= 52;
+
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+
+ str= "GroupKey types %t|Set Key %x6|Play %x0|Ping Pong %x1|Flipper %x2|Loop Stop %x3|Loop End %x4|Property %x5";
+
+ uiDefButS(block, MENU, 1, str, xco+20, yco-24, width-40, 19, &ga->type, 0, 0, 0, 0, "");
+ if(ga->type==ACT_GROUP_SET) {
+ uiDefBut(block, TEX, 0, "Key: ", xco+20, yco-44, (width-10)/2, 19, ga->name, 0.0, 31.0, 0, 0, "This name defines groupkey to be set");
+ uiDefButI(block, NUM, 0, "Frame:", xco+20+(width-10)/2, yco-44, (width-70)/2, 19, &ga->sta, 0.0, 2500.0, 0, 0, "Set this frame");
+ }
+ else if(ga->type==ACT_GROUP_FROM_PROP) {
+ uiDefBut(block, TEX, 0, "Prop: ", xco+20, yco-44, width-40, 19, ga->name, 0.0, 31.0, 0, 0, "Use this property to define the Group position");
+ }
+ else {
+ uiDefButI(block, NUM, 0, "Sta", xco+20, yco-44, (width-40)/2, 19, &ga->sta, 0.0, 2500.0, 0, 0, "Start frame");
+ uiDefButI(block, NUM, 0, "End", xco+20+(width-40)/2, yco-44, (width-40)/2, 19, &ga->end, 0.0, 2500.0, 0, 0, "End frame");
+ }
+ yco-= ysize;
+ break;
+
+ case ACT_VISIBILITY:
+ ysize = 24;
+
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco,
+ (float)yco-ysize, (float)xco+width, (float)yco, 1);
+
+ visAct = act->data;
+
+ str= "Visibility %t|Visible %x0|Invisible %x1";
+
+ uiDefButI(block, MENU, B_REDR, str,
+ xco + 10, yco - 24, width - 20, 19, &visAct->flag,
+ 0.0, 0.0, 0, 0,
+ "Make the object invisible or visible.");
+/*
+ uiDefButBitI(block, TOG, ACT_VISIBILITY_INVISIBLE, 0,
+ "Invisible",
+ xco + 10, yco - 24, width - 20, 19, &visAct->flag,
+ 0.0, 0.0, 0, 0,
+ "Make the object invisible or visible.");
+*/
+ yco-= ysize;
+
+ break;
+
+ case ACT_RANDOM:
+ ysize = 69;
+
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco,
+ (float)yco-ysize, (float)xco+width, (float)yco, 1);
+
+ randAct = act->data;
+
+ /* 1. seed */
+ uiDefButI(block, NUM, 1, "Seed: ", (xco+10),yco-24, 0.4 *(width-20), 19,
+ &randAct->seed, 0, 1000, 0, 0,
+ "Initial seed of the random generator. Use Python for more freedom. "
+ " (Choose 0 for not random)");
+
+ /* 2. distribution type */
+ /* One pick per distribution. These numbers MUST match the #defines */
+ /* in game.h !!! */
+ str= "Distribution %t|Bool Constant %x0|Bool Uniform %x1"
+ "|Bool Bernoulli %x2|Int Constant %x3|Int Uniform %x4"
+ "|Int Poisson %x5|Float Constant %x6|Float Uniform %x7"
+ "|Float Normal %x8|Float Neg. Exp. %x9";
+ uiDefButI(block, MENU, B_REDR, str, (xco+10) + 0.4 * (width-20), yco-24, 0.6 * (width-20), 19,
+ &randAct->distribution, 0.0, 0.0, 0, 0,
+ "Choose the type of distribution");
+
+ /* 3. property */
+ uiDefBut(block, TEX, 1, "Property:", (xco+10), yco-44, (width-20), 19,
+ &randAct->propname, 0, 31, 0, 0,
+ "Assign the random value to this property");
+
+ /*4. and 5. arguments for the distribution*/
+ switch (randAct->distribution) {
+ case ACT_RANDOM_BOOL_CONST:
+ uiDefButBitI(block, TOG, 1, 1, "Always true", (xco+10), yco-64, (width-20), 19,
+ &randAct->int_arg_1, 2.0, 1, 0, 0,
+ "Always false or always true");
+ break;
+ case ACT_RANDOM_BOOL_UNIFORM:
+ uiDefBut(block, LABEL, 0, " Do a 50-50 pick.", (xco+10), yco-64, (width-20), 19,
+ NULL, 0, 0, 0, 0,
+ "Choose between true and false, 50% chance each.");
+ break;
+ case ACT_RANDOM_BOOL_BERNOUILLI:
+ uiDefButF(block, NUM, 1, "Chance", (xco+10), yco-64, (width-20), 19,
+ &randAct->float_arg_1, 0.0, 1.0, 0, 0,
+ "Pick a number between 0 and 1. Success if you stay "
+ "below this value");
+ break;
+ case ACT_RANDOM_INT_CONST:
+ uiDefButI(block, NUM, 1, "Value: ", (xco+10), yco-64, (width-20), 19,
+ &randAct->int_arg_1, -1000, 1000, 0, 0,
+ "Always return this number");
+ break;
+ case ACT_RANDOM_INT_UNIFORM:
+ uiDefButI(block, NUM, 1, "Min: ", (xco+10), yco-64, (width-20)/2, 19,
+ &randAct->int_arg_1, -1000, 1000, 0, 0,
+ "Choose a number from a range. "
+ "Lower boundary of the range.");
+ uiDefButI(block, NUM, 1, "Max: ", (xco+10) + (width-20)/2, yco-64, (width-20)/2, 19,
+ &randAct->int_arg_2, -1000, 1000, 0, 0,
+ "Choose a number from a range. "
+ "Upper boundary of the range.");
+ break;
+ case ACT_RANDOM_INT_POISSON:
+ uiDefButF(block, NUM, 1, "Mean: ", (xco+10), yco-64, (width-20), 19,
+ &randAct->float_arg_1, 0.01, 100.0, 0, 0,
+ "Expected mean value of the distribution.");
+ break;
+ case ACT_RANDOM_FLOAT_CONST:
+ uiDefButF(block, NUM, 1, "Value: ", (xco+10), yco-64, (width-20), 19,
+ &randAct->float_arg_1, 0.0, 1.0, 0, 0,
+ "Always return this number");
+ break;
+ case ACT_RANDOM_FLOAT_UNIFORM:
+ uiDefButF(block, NUM, 1, "Min: ", (xco+10), yco-64, (width-20)/2, 19,
+ &randAct->float_arg_1, -10000.0, 10000.0, 0, 0,
+ "Choose a number from a range. "
+ "Lower boundary of the range.");
+ uiDefButF(block, NUM, 1, "Max: ", (xco+10) + (width-20)/2, yco-64, (width-20)/2, 19,
+ &randAct->float_arg_2, -10000.0, 10000.0, 0, 0,
+ "Choose a number from a range. "
+ "Upper boundary of the range.");
+ break;
+ case ACT_RANDOM_FLOAT_NORMAL:
+ uiDefButF(block, NUM, 1, "Mean: ", (xco+10), yco-64, (width-20)/2, 19,
+ &randAct->float_arg_1, -10000.0, 10000.0, 0, 0,
+ "A normal distribution. Mean of the distribution.");
+ uiDefButF(block, NUM, 1, "SD: ", (xco+10) + (width-20)/2, yco-64, (width-20)/2, 19,
+ &randAct->float_arg_2, 0.0, 10000.0, 0, 0,
+ "A normal distribution. Standard deviation of the "
+ "distribution.");
+ break;
+ case ACT_RANDOM_FLOAT_NEGATIVE_EXPONENTIAL:
+ uiDefButF(block, NUM, 1, "Half-life time: ", (xco+10), yco-64, (width-20), 19,
+ &randAct->float_arg_1, 0.001, 10000.0, 0, 0,
+ "Negative exponential dropoff.");
+ break;
+ default:
+ ; /* don't know what this distro is... can be useful for testing */
+ /* though :) */
+ }
+
+ yco-= ysize;
+ break;
+ case ACT_MESSAGE:
+ ma = act->data;
+
+#define MESSAGE_SENSOR_TO_FIELD_WORKS /* Really? Not really. Don't remove this ifdef yet */
+
+#ifdef MESSAGE_SENSOR_TO_FIELD_WORKS
+ ysize = 4 + (3 * 24); /* footer + number of lines * 24 pixels/line */
+#else
+ ysize = 4 + (2 * 24); /* footer + number of lines * 24 pixels/line */
+#endif
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize,
+ (float)xco+width, (float)yco, 1);
+
+ myline=1;
+
+
+#ifdef MESSAGE_SENSOR_TO_FIELD_WORKS
+ /* line 1: To */
+ uiDefBut(block, TEX, 1, "To: ",
+ (xco+10), (yco-(myline++*24)), (width-20), 19,
+ &ma->toPropName, 0, 31, 0, 0,
+ "Optional send message to objects with this name only"
+ ", or empty to broadcast");
+
+#endif
+
+ /* line 2: Message Subject */
+ uiDefBut(block, TEX, 1, "Subject: ",
+ (xco+10), (yco-(myline++*24)), (width-20), 19,
+ &ma->subject, 0, 31, 0, 0,
+ "Optional message subject. This is what can be filtered on.");
+
+ /* line 3: Text/Property */
+ uiDefButBitS(block, TOG, 1, B_REDR, "T/P",
+ (xco+10),(yco-(myline*24)), (0.20 * (width-20)), 19,
+ &ma->bodyType, 0.0, 0.0, 0, 0,
+ "Toggle message type: either Text or a PropertyName.");
+
+ if (ma->bodyType == ACT_MESG_MESG)
+ {
+ /* line 3: Message Body */
+ uiDefBut(block, TEX, 1, "Body: ",
+ (xco+10+(0.20*(width-20))),(yco-(myline++*24)),(0.8*(width-20)),19,
+ &ma->body, 0, 31, 0, 0,
+ "Optional message body Text");
+ } else
+ {
+ /* line 3: Property body (set by property) */
+ uiDefBut(block, TEX, 1, "Propname: ",
+ (xco+10+(0.20*(width-20))),(yco-(myline++*24)),(0.8*(width-20)),19,
+ &ma->body, 0, 31, 0, 0,
+ "The message body will be set by the Property Value");
+ }
+
+ yco -= ysize;
+ break;
+ default:
+ ysize= 4;
+
+ glRects(xco, yco-ysize, xco+width, yco);
+ uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
+
+ yco-= ysize;
+ break;
+ }
+
+ uiBlockSetEmboss(block, UI_EMBOSSM);
+
+ return yco-4;
+}
+
+static void do_sensor_menu(void *arg, int event)
+{
+ ID **idar;
+ Object *ob;
+ bSensor *sens;
+ short count, a;
+
+ idar= get_selected_and_linked_obs(&count, G.buts->scaflag);
+
+ for(a=0; a<count; a++) {
+ ob= (Object *)idar[a];
+ if(event==0 || event==2) ob->scaflag |= OB_SHOWSENS;
+ else if(event==1) ob->scaflag &= ~OB_SHOWSENS;
+ }
+
+ for(a=0; a<count; a++) {
+ ob= (Object *)idar[a];
+ sens= ob->sensors.first;
+ while(sens) {
+ if(event==2) sens->flag |= SENS_SHOW;
+ else if(event==3) sens->flag &= ~SENS_SHOW;
+ sens= sens->next;
+ }
+ }
+
+ if(idar) MEM_freeN(idar);
+ allqueue(REDRAWBUTSLOGIC, 0);
+}
+
+static uiBlock *sensor_menu(void *arg_unused)
+{
+ uiBlock *block;
+ int yco=0;
+
+ block= uiNewBlock(&curarea->uiblocks, "filemenu", UI_EMBOSSP, UI_HELV, curarea->win);
+ uiBlockSetButmFunc(block, do_sensor_menu, NULL);
+
+ uiDefBut(block, BUTM, 1, "Show Objects", 0, (short)(yco-=20), 160, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefBut(block, BUTM, 1, "Hide Objects", 0, (short)(yco-=20), 160, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefBut(block, SEPR, 0, "", 0, (short)(yco-=6), 160, 6, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefBut(block, BUTM, 1, "Show Sensors", 0, (short)(yco-=20), 160, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefBut(block, BUTM, 1, "Hide Sensors", 0, (short)(yco-=20), 160, 19, NULL, 0.0, 0.0, 1, 3, "");
+
+ uiBlockSetDirection(block, UI_TOP);
+
+ return block;
+}
+
+static void do_controller_menu(void *arg, int event)
+{
+ ID **idar;
+ Object *ob;
+ bController *cont;
+ short count, a;
+
+ idar= get_selected_and_linked_obs(&count, G.buts->scaflag);
+
+ for(a=0; a<count; a++) {
+ ob= (Object *)idar[a];
+ if(event==0 || event==2) ob->scaflag |= OB_SHOWCONT;
+ else if(event==1) ob->scaflag &= ~OB_SHOWCONT;
+ }
+
+ for(a=0; a<count; a++) {
+ ob= (Object *)idar[a];
+ cont= ob->controllers.first;
+ while(cont) {
+ if(event==2) cont->flag |= CONT_SHOW;
+ else if(event==3) cont->flag &= ~CONT_SHOW;
+ cont= cont->next;
+ }
+ }
+
+ if(idar) MEM_freeN(idar);
+ allqueue(REDRAWBUTSLOGIC, 0);
+}
+
+static uiBlock *controller_menu(void *arg_unused)
+{
+ uiBlock *block;
+ int yco=0;
+
+ block= uiNewBlock(&curarea->uiblocks, "filemenu", UI_EMBOSSP, UI_HELV, curarea->win);
+ uiBlockSetButmFunc(block, do_controller_menu, NULL);
+
+ uiDefBut(block, BUTM, 1, "Show Objects", 0, (short)(yco-=20), 160, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefBut(block, BUTM, 1, "Hide Objects", 0,(short)(yco-=20), 160, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefBut(block, SEPR, 0, "", 0, (short)(yco-=6), 160, 6, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefBut(block, BUTM, 1, "Show Controllers", 0, (short)(yco-=20), 160, 19, NULL, 0.0, 0.0, 2, 2, "");
+ uiDefBut(block, BUTM, 1, "Hide Controllers", 0, (short)(yco-=20), 160, 19, NULL, 0.0, 0.0, 3, 3, "");
+
+ uiBlockSetDirection(block, UI_TOP);
+
+ return block;
+}
+
+static void do_actuator_menu(void *arg, int event)
+{
+ ID **idar;
+ Object *ob;
+ bActuator *act;
+ short count, a;
+
+ idar= get_selected_and_linked_obs(&count, G.buts->scaflag);
+
+ for(a=0; a<count; a++) {
+ ob= (Object *)idar[a];
+ if(event==0 || event==2) ob->scaflag |= OB_SHOWACT;
+ else if(event==1) ob->scaflag &= ~OB_SHOWACT;
+ }
+
+ for(a=0; a<count; a++) {
+ ob= (Object *)idar[a];
+ act= ob->actuators.first;
+ while(act) {
+ if(event==2) act->flag |= ACT_SHOW;
+ else if(event==3) act->flag &= ~ACT_SHOW;
+ act= act->next;
+ }
+ }
+
+ if(idar) MEM_freeN(idar);
+ allqueue(REDRAWBUTSLOGIC, 0);
+}
+
+static uiBlock *actuator_menu(void *arg_unused)
+{
+ uiBlock *block;
+ int xco=0;
+
+ block= uiNewBlock(&curarea->uiblocks, "filemenu", UI_EMBOSSP, UI_HELV, curarea->win);
+ uiBlockSetButmFunc(block, do_actuator_menu, NULL);
+
+ uiDefBut(block, BUTM, 1, "Show Objects", 0, (short)(xco-=20), 160, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefBut(block, BUTM, 1, "Hide Objects", 0, (short)(xco-=20), 160, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefBut(block, SEPR, 0, "", 0, (short)(xco-=6), 160, 6, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefBut(block, BUTM, 1, "Show Actuators", 0, (short)(xco-=20), 160, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefBut(block, BUTM, 1, "Hide Actuators", 0, (short)(xco-=20), 160, 19, NULL, 0.0, 0.0, 1, 3, "");
+
+ uiBlockSetDirection(block, UI_TOP);
+
+ return block;
+}
+
+
+void buttons_enji(uiBlock *block, Object *ob)
+{
+ uiDefButBitI(block, TOG, OB_SECTOR, B_SETSECTOR, "Sector",
+ 10,205,65,19, &ob->gameflag, 0, 0, 0, 0,
+ "All game elements should be in the Sector boundbox");
+ uiDefButBitI(block, TOG, OB_PROP, B_SETPROP, "Prop",
+ 75,205,65,19, &ob->gameflag, 0, 0, 0, 0,
+ "An Object fixed within a sector");
+ uiBlockSetCol(block, BUTPURPLE);
+ uiDefButBitI(block, TOG, OB_ACTOR, B_SETACTOR, "Actor",
+ 140,205,65,19, &ob->gameflag, 0, 0, 0, 0,
+ "Objects that are evaluated by the engine ");
+ if(ob->gameflag & OB_ACTOR) {
+ uiDefButBitI(block, TOG, OB_DYNAMIC, B_SETDYNA, "Dynamic",
+ 205,205,75,19, &ob->gameflag, 0, 0, 0, 0,
+ "Motion defined by laws of physics");
+ uiDefButBitI(block, TOG, OB_MAINACTOR, B_SETMAINACTOR, "MainActor",
+ 280,205,70,19, &ob->gameflag, 0, 0, 0, 0, "");
+
+ if(ob->gameflag & OB_DYNAMIC) {
+ uiDefButBitI(block, TOG, OB_DO_FH, B_DIFF, "Do Fh",
+ 10,185,50,19, &ob->gameflag, 0, 0, 0, 0,
+ "Use Fh settings in Materials");
+ uiDefButBitI(block, TOG, OB_ROT_FH, B_DIFF, "Rot Fh",
+ 60,185,50,19, &ob->gameflag, 0, 0, 0, 0,
+ "Use face normal to rotate Object");
+
+ uiBlockSetCol(block, BUTGREY);
+ uiDefButF(block, NUM, B_DIFF, "Mass:",
+ 110, 185, 120, 19, &ob->mass, 0.01, 100.0, 10, 0,
+ "The mass of the Object");
+ uiDefButF(block, NUM, REDRAWVIEW3D, "Size:",
+ 230, 185, 120, 19, &ob->inertia, 0.01, 10.0, 10, 0,
+ "Bounding sphere size");
+ uiDefButF(block, NUM, B_DIFF, "Damp:",
+ 10, 165, 100, 19, &ob->damping, 0.0, 1.0, 10, 0,
+ "General movement damping");
+ uiDefButF(block, NUM, B_DIFF, "RotDamp:",
+ 110, 165, 120, 19, &ob->rdamping, 0.0, 1.0, 10, 0,
+ "General rotation damping");
+ }
+ }
+
+}
+
+void buttons_ketsji(uiBlock *block, Object *ob)
+{
+ uiDefButBitI(block, TOG, OB_ACTOR, B_REDR, "Actor",
+ 10,205,55,19, &ob->gameflag, 0, 0, 0, 0,
+ "Objects that are evaluated by the engine ");
+ if(ob->gameflag & OB_ACTOR) {
+ uiDefButBitI(block, TOG, OB_GHOST, B_REDR, "Ghost", 65,205,55,19,
+ &ob->gameflag, 0, 0, 0, 0,
+ "Objects that don't restitute collisions (like a ghost)");
+ uiDefButBitI(block, TOG, OB_DYNAMIC, B_REDR, "Dynamic", 120,205,70,19,
+ &ob->gameflag, 0, 0, 0, 0,
+ "Motion defined by laws of physics");
+
+ if(ob->gameflag & OB_DYNAMIC) {
+ uiDefButBitI(block, TOG, OB_RIGID_BODY, B_REDR, "Rigid Body", 190,205,80,19,
+ &ob->gameflag, 0, 0, 0, 0,
+ "Enable rolling physics");
+ uiDefButBitI(block, TOG, OB_COLLISION_RESPONSE, B_REDR, "No sleeping", 270,205,80,19,
+ &ob->gameflag, 0, 0, 0, 0,
+ "Disable auto (de)activation");
+
+ uiDefButBitI(block, TOG, OB_DO_FH, B_DIFF, "Do Fh", 10,185,50,19,
+ &ob->gameflag, 0, 0, 0, 0,
+ "Use Fh settings in Materials");
+ uiDefButBitI(block, TOG, OB_ROT_FH, B_DIFF, "Rot Fh", 60,185,50,19,
+ &ob->gameflag, 0, 0, 0, 0,
+ "Use face normal to rotate Object");
+ uiDefButF(block, NUM, B_DIFF, "Mass:", 110, 185, 80, 19,
+ &ob->mass, 0.01, 10000.0, 10, 0,
+ "The mass of the Object");
+ uiDefButF(block, NUM, REDRAWVIEW3D, "Radius:", 190, 185, 80, 19,
+ &ob->inertia, 0.01, 10.0, 10, 0,
+ "Bounding sphere radius");
+ uiDefButF(block, NUM, B_DIFF, "Form:", 270, 185, 80, 19,
+ &ob->formfactor, 0.01, 100.0, 10, 0,
+ "Form factor");
+
+ uiDefButF(block, NUM, B_DIFF, "Damp:", 10, 165, 100, 19,
+ &ob->damping, 0.0, 1.0, 10, 0,
+ "General movement damping");
+ uiDefButF(block, NUM, B_DIFF, "RotDamp:", 110, 165, 120, 19,
+ &ob->rdamping, 0.0, 1.0, 10, 0,
+ "General rotation damping");
+ uiDefButBitI(block, TOG, OB_ANISOTROPIC_FRICTION, B_REDR, "Anisotropic",
+ 230, 165, 120, 19,
+ &ob->gameflag, 0.0, 1.0, 10, 0,
+ "Enable anisotropic friction");
+ }
+
+ if (ob->gameflag & OB_ANISOTROPIC_FRICTION) {
+ uiDefButF(block, NUM, B_DIFF, "x friction:", 10, 145, 114, 19,
+ &ob->anisotropicFriction[0], 0.0, 1.0, 10, 0,
+ "Relative friction coefficient in the x-direction.");
+ uiDefButF(block, NUM, B_DIFF, "y friction:", 124, 145, 113, 19,
+ &ob->anisotropicFriction[1], 0.0, 1.0, 10, 0,
+ "Relative friction coefficient in the y-direction.");
+ uiDefButF(block, NUM, B_DIFF, "z friction:", 237, 145, 113, 19,
+ &ob->anisotropicFriction[2], 0.0, 1.0, 10, 0,
+ "Relative friction coefficient in the z-direction.");
+ }
+ }
+
+ if (!(ob->gameflag & OB_GHOST)) {
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOG, OB_BOUNDS, B_REDR, "Bounds", 10, 125, 75, 19,
+ &ob->gameflag, 0, 0,0, 0,
+ "Specify a bounds object for physics");
+ if (ob->gameflag & OB_BOUNDS) {
+ uiDefButS(block, MENU, REDRAWVIEW3D, "Boundary Display%t|Box%x0|Sphere%x1|Cylinder%x2|Cone%x3|Convex Hull Polytope%x5|Static TriangleMesh %x4",
+ 85, 125, 160, 19, &ob->boundtype, 0, 0, 0, 0, "Selects the collision type");
+ uiDefButBitI(block, TOG, OB_CHILD, B_REDR, "Compound", 250,125,100,19,
+ &ob->gameflag, 0, 0, 0, 0,
+ "Add Children");
+ }
+ uiBlockEndAlign(block);
+ }
+}
+
+void buttons_bullet(uiBlock *block, Object *ob)
+{
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOG, OB_ACTOR, B_REDR, "Actor",
+ 10,205,55,19, &ob->gameflag, 0, 0, 0, 0,
+ "Objects that are evaluated by the engine ");
+ if(ob->gameflag & OB_ACTOR) {
+ uiDefButBitI(block, TOG, OB_GHOST, B_REDR, "Ghost", 65,205,55,19,
+ &ob->gameflag, 0, 0, 0, 0,
+ "Objects that don't restitute collisions (like a ghost)");
+ uiDefButBitI(block, TOG, OB_DYNAMIC, B_REDR, "Dynamic", 120,205,70,19,
+ &ob->gameflag, 0, 0, 0, 0,
+ "Motion defined by laws of physics");
+
+ if(ob->gameflag & OB_DYNAMIC) {
+ uiDefButBitI(block, TOG, OB_RIGID_BODY, B_REDR, "Rigid Body", 190,205,80,19,
+ &ob->gameflag, 0, 0, 0, 0,
+ "Enable rolling physics");
+ uiDefButBitI(block, TOG, OB_COLLISION_RESPONSE, B_REDR, "No sleeping", 270,205,80,19,
+ &ob->gameflag, 0, 0, 0, 0,
+ "Disable auto (de)activation");
+
+ uiDefButF(block, NUM, B_DIFF, "Mass:", 10, 185, 170, 19,
+ &ob->mass, 0.01, 10000.0, 10, 2,
+ "The mass of the Object");
+ uiDefButF(block, NUM, REDRAWVIEW3D, "Radius:", 180, 185, 170, 19,
+ &ob->inertia, 0.01, 10.0, 10, 2,
+ "Bounding sphere radius");
+
+ uiDefButF(block, NUMSLI, B_DIFF, "Damp ", 10, 165, 150, 19,
+ &ob->damping, 0.0, 1.0, 10, 0,
+ "General movement damping");
+ uiDefButF(block, NUMSLI, B_DIFF, "RotDamp ", 160, 165, 190, 19,
+ &ob->rdamping, 0.0, 1.0, 10, 0,
+ "General rotation damping");
+ }
+ }
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOG, OB_BOUNDS, B_REDR, "Bounds", 10, 125, 75, 19,
+ &ob->gameflag, 0, 0,0, 0,
+ "Specify a bounds object for physics");
+ if (ob->gameflag & OB_BOUNDS) {
+ uiDefButS(block, MENU, REDRAWVIEW3D, "Boundary Display%t|Box%x0|Sphere%x1|Cylinder%x2|Cone%x3|Convex Hull Polytope%x5|Static TriangleMesh %x4",
+ //almost ready to enable this one: uiDefButS(block, MENU, REDRAWVIEW3D, "Boundary Display%t|Box%x0|Sphere%x1|Cylinder%x2|Cone%x3|Convex Hull Polytope%x5|Static TriangleMesh %x4|Dynamic Mesh %x5|",
+ 85, 125, 160, 19, &ob->boundtype, 0, 0, 0, 0, "Selects the collision type");
+ uiDefButBitI(block, TOG, OB_CHILD, B_REDR, "Compound", 250,125,100,19,
+ &ob->gameflag, 0, 0, 0, 0,
+ "Add Children");
+ }
+ uiBlockEndAlign(block);
+}
+
+/* never used, see CVS 1.134 for the code */
+/* static FreeCamera *new_freecamera(void) */
+
+/* never used, see CVS 1.120 for the code */
+/* static uiBlock *freecamera_menu(void) */
+
+
+void logic_buts(void)
+{
+ ID **idar;
+ Object *ob;
+ bProperty *prop;
+ bSensor *sens;
+ bController *cont;
+ bActuator *act;
+ uiBlock *block;
+ uiBut *but;
+ World *wrld;
+ int a;
+ short xco, yco, count, width, ycoo;
+ char *pupstr, name[32];
+
+ wrld= G.scene->world;
+
+ ob= OBACT;
+
+ if(ob==0) return;
+ uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
+
+ sprintf(name, "buttonswin %d", curarea->win);
+ block= uiNewBlock(&curarea->uiblocks, name, UI_EMBOSS, UI_HELV, curarea->win);
+
+ uiBlockSetCol(block, TH_BUT_SETTING2);
+
+ if(wrld) {
+ switch(wrld->physicsEngine) {
+ case WOPHY_ENJI:
+ buttons_enji(block, ob);
+ break;
+ case WOPHY_BULLET:
+ buttons_bullet(block, ob);
+ break;
+ default:
+ buttons_ketsji(block, ob);
+ break;
+ }
+ }
+ else buttons_ketsji(block, ob);
+
+ uiBlockSetCol(block, TH_AUTO);
+ uiBlockBeginAlign(block);
+ uiDefBut(block, BUT, B_ADD_PROP, "Add Property", 10, 90, 340, 24,
+ NULL, 0.0, 100.0, 100, 0,
+ "");
+
+ pupstr= "Types %t|Bool %x0|Int %x1|Float %x2|String %x3|Timer %x5";
+
+ a= 0;
+ prop= ob->prop.first;
+ while(prop) {
+ but= uiDefBut(block, BUT, 1, "Del", 10, (short)(70-20*a), 40, 20, NULL, 0.0, 0.0, 1, (float)a, "");
+ uiButSetFunc(but, del_property, prop, NULL);
+ uiDefButS(block, MENU, B_CHANGE_PROP, pupstr, 50, (short)(70-20*a), 60, 20, &prop->type, 0, 0, 0, 0, "");
+ but= uiDefBut(block, TEX, 1, "Name:", 110, (short)(70-20*a), 110, 20, prop->name, 0, 31, 0, 0, "");
+ uiButSetFunc(but, make_unique_prop_names_cb, prop->name, (void*) 1);
+
+ if(prop->type==PROP_BOOL) {
+ uiDefButBitI(block, TOG, 1, B_REDR, "True", 220, (short)(70-20*a), 55, 20, &prop->data, 0, 0, 0, 0, "");
+ uiDefButBitI(block, TOGN, 1, B_REDR, "False", 270, (short)(70-20*a), 55, 20, &prop->data, 0, 0, 0, 0, "");
+ }
+ else if(prop->type==PROP_INT)
+ uiDefButI(block, NUM, B_REDR, "", 220, (short)(70-20*a), 110, 20, &prop->data, -10000, 10000, 0, 0, "");
+ else if(prop->type==PROP_FLOAT)
+ uiDefButF(block, NUM, B_REDR, "", 220, (short)(70-20*a), 110, 20, (float*) &prop->data, -10000, 10000, 100, 3, "");
+ else if(prop->type==PROP_STRING)
+ uiDefBut(block, TEX, B_REDR, "", 220, (short)(70-20*a), 110, 20, prop->poin, 0, 127, 0, 0, "");
+ else if(prop->type==PROP_TIME)
+ uiDefButF(block, NUM, B_REDR, "", 220, (short)(70-20*a), 110, 20, (float*) &prop->data, -10000, 10000, 100, 3, "");
+
+ uiDefButBitS(block, TOG, PROP_DEBUG, B_REDR, "D", 330, (short)(70-20*a), 20, 20, &prop->flag, 0, 0, 0, 0, "Print Debug info");
+
+ a++;
+ prop= prop->next;
+
+ }
+ uiBlockEndAlign(block);
+
+ uiClearButLock();
+
+ idar= get_selected_and_linked_obs(&count, G.buts->scaflag);
+
+ /* ******************************* */
+ xco= 375; yco= 170; width= 230;
+
+ uiBlockSetEmboss(block, UI_EMBOSSP);
+ uiDefBlockBut(block, sensor_menu, NULL, "Sensors", xco-10, yco+35, 80, 19, "");
+ uiBlockSetEmboss(block, UI_EMBOSS);
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, BUTS_SENS_SEL, B_REDR, "Sel", xco+110, yco+35, (width-100)/3, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show all selected Objects");
+ uiDefButBitS(block, TOG, BUTS_SENS_ACT, B_REDR, "Act", xco+110+(width-100)/3, yco+35, (width-100)/3, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show active Object");
+ uiDefButBitS(block, TOG, BUTS_SENS_LINK, B_REDR, "Link", xco+110+2*(width-100)/3, yco+35, (width-100)/3, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show linked Objects to Controller");
+ uiBlockEndAlign(block);
+
+ for(a=0; a<count; a++) {
+ ob= (Object *)idar[a];
+ uiClearButLock();
+ uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
+
+ if( (ob->scavisflag & OB_VIS_SENS) == 0) continue;
+
+ /* presume it is only objects for now */
+ uiBlockSetEmboss(block, UI_EMBOSS);
+ uiBlockBeginAlign(block);
+ if(ob->sensors.first) uiSetCurFont(block, UI_HELVB);
+ uiDefButBitS(block, TOG, OB_SHOWSENS, B_REDR, ob->id.name+2,(short)(xco-10), yco, (short)(width-30), 19, &ob->scaflag, 0, 31, 0, 0, "Object name, click to show/hide sensors");
+ if(ob->sensors.first) uiSetCurFont(block, UI_HELV);
+ uiDefButBitS(block, TOG, OB_ADDSENS, B_ADD_SENS, "Add",(short)(xco+width-40), yco, 50, 19, &ob->scaflag, 0, 0, 0, 0, "Add a new Sensor");
+ uiBlockEndAlign(block);
+ yco-=20;
+
+ if(ob->scaflag & OB_SHOWSENS) {
+
+ sens= ob->sensors.first;
+ while(sens) {
+ uiBlockSetEmboss(block, UI_EMBOSSM);
+ uiDefIconButBitS(block, TOG, SENS_DEL, B_DEL_SENS, ICON_X, xco, yco, 22, 19, &sens->flag, 0, 0, 0, 0, "Delete Sensor");
+ uiDefIconButBitS(block, ICONTOG, SENS_SHOW, B_REDR, ICON_RIGHTARROW, (short)(xco+width-22), yco, 22, 19, &sens->flag, 0, 0, 0, 0, "Sensor settings");
+
+ ycoo= yco;
+ if(sens->flag & SENS_SHOW)
+ {
+ uiDefButS(block, MENU, B_CHANGE_SENS, sensor_pup(), (short)(xco+22), yco, 100, 19, &sens->type, 0, 0, 0, 0, "Sensor type");
+ but= uiDefBut(block, TEX, 1, "", (short)(xco+122), yco, (short)(width-144), 19, sens->name, 0, 31, 0, 0, "Sensor name");
+ uiButSetFunc(but, make_unique_prop_names_cb, sens->name, (void*) 0);
+
+ sens->otype= sens->type;
+ yco= draw_sensorbuttons(sens, block, xco, yco, width,ob->id.name);
+ if(yco-6 < ycoo) ycoo= (yco+ycoo-20)/2;
+ }
+ else {
+ set_col_sensor(sens->type, 1);
+ glRecti(xco+22, yco, xco+width-22,yco+19);
+ but= uiDefBut(block, LABEL, 0, sensor_name(sens->type), (short)(xco+22), yco, 100, 19, sens, 0, 0, 0, 0, "");
+ uiButSetFunc(but, sca_move_sensor, sens, NULL);
+ but= uiDefBut(block, LABEL, 0, sens->name, (short)(xco+122), yco, (short)(width-144), 19, sens, 0, 31, 0, 0, "");
+ uiButSetFunc(but, sca_move_sensor, sens, NULL);
+ }
+
+ but= uiDefIconBut(block, LINK, 0, ICON_LINK, (short)(xco+width), ycoo, 19, 19, NULL, 0, 0, 0, 0, "");
+ uiSetButLink(but, NULL, (void ***)&(sens->links), &sens->totlinks, LINK_SENSOR, LINK_CONTROLLER);
+
+ yco-=20;
+
+ sens= sens->next;
+ }
+ yco-= 6;
+ }
+ }
+
+ /* ******************************* */
+ xco= 675; yco= 170; width= 230;
+
+ uiBlockSetEmboss(block, UI_EMBOSSP);
+ uiDefBlockBut(block, controller_menu, NULL, "Controllers", xco-10, yco+35, 100, 19, "");
+ uiBlockSetEmboss(block, UI_EMBOSS);
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, BUTS_CONT_SEL, B_REDR, "Sel", xco+110, yco+35, (width-100)/3, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show all selected Objects");
+ uiDefButBitS(block, TOG, BUTS_CONT_ACT, B_REDR, "Act", xco+110+(width-100)/3, yco+35, (width-100)/3, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show active Object");
+ uiDefButBitS(block, TOG, BUTS_CONT_LINK, B_REDR, "Link", xco+110+2*(width-100)/3, yco+35, (width-100)/3, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show linked Objects to Sensor/Actuator");
+ uiBlockEndAlign(block);
+
+ ob= OBACT;
+
+ for(a=0; a<count; a++) {
+ ob= (Object *)idar[a];
+ uiClearButLock();
+ uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
+ if( (ob->scavisflag & OB_VIS_CONT) == 0) continue;
+
+ /* presume it is only objects for now */
+ uiBlockSetEmboss(block, UI_EMBOSS);
+ uiBlockBeginAlign(block);
+ if(ob->controllers.first) uiSetCurFont(block, UI_HELVB);
+ uiDefButBitS(block, TOG, OB_SHOWCONT, B_REDR, ob->id.name+2,(short)(xco-10), yco, (short)(width-30), 19, &ob->scaflag, 0, 0, 0, 0, "Active Object name");
+ if(ob->controllers.first) uiSetCurFont(block, UI_HELV);
+ uiDefButBitS(block, TOG, OB_ADDCONT, B_ADD_CONT, "Add",(short)(xco+width-40), yco, 50, 19, &ob->scaflag, 0, 0, 0, 0, "Add a new Controller");
+ uiBlockEndAlign(block);
+ yco-=20;
+
+ if(ob->scaflag & OB_SHOWCONT) {
+
+ cont= ob->controllers.first;
+ while(cont) {
+ uiBlockSetEmboss(block, UI_EMBOSSM);
+ uiDefIconButBitS(block, TOG, CONT_DEL, B_DEL_CONT, ICON_X, xco, yco, 22, 19, &cont->flag, 0, 0, 0, 0, "Delete Controller");
+ uiDefIconButBitS(block, ICONTOG, CONT_SHOW, B_REDR, ICON_RIGHTARROW, (short)(xco+width-22), yco, 22, 19, &cont->flag, 0, 0, 0, 0, "Controller settings");
+
+ if(cont->flag & CONT_SHOW) {
+ cont->otype= cont->type;
+ uiDefButS(block, MENU, B_CHANGE_CONT, controller_pup(),(short)(xco+22), yco, 100, 19, &cont->type, 0, 0, 0, 0, "Controller type");
+ but= uiDefBut(block, TEX, 1, "", (short)(xco+122), yco, (short)(width-144), 19, cont->name, 0, 31, 0, 0, "Controller name");
+ uiButSetFunc(but, make_unique_prop_names_cb, cont->name, (void*) 0);
+
+ ycoo= yco;
+ yco= draw_controllerbuttons(cont, block, xco, yco, width);
+ if(yco-6 < ycoo) ycoo= (yco+ycoo-20)/2;
+ }
+ else {
+ cpack(0x999999);
+ glRecti(xco+22, yco, xco+width-22,yco+19);
+ but= uiDefBut(block, LABEL, 0, controller_name(cont->type), (short)(xco+22), yco, 100, 19, cont, 0, 0, 0, 0, "Controller type");
+ uiButSetFunc(but, sca_move_controller, cont, NULL);
+ but= uiDefBut(block, LABEL, 0, cont->name,(short)(xco+122), yco,(short)(width-144), 19, cont, 0, 0, 0, 0, "Controller name");
+ uiButSetFunc(but, sca_move_controller, cont, NULL);
+ ycoo= yco;
+ }
+
+ but= uiDefIconBut(block, LINK, 0, ICON_LINK, (short)(xco+width), ycoo, 19, 19, NULL, 0, 0, 0, 0, "");
+ uiSetButLink(but, NULL, (void ***)&(cont->links), &cont->totlinks, LINK_CONTROLLER, LINK_ACTUATOR);
+
+ uiDefIconBut(block, INLINK, 0, ICON_INLINK,(short)(xco-19), ycoo, 19, 19, cont, LINK_CONTROLLER, 0, 0, 0, "");
+
+ yco-=20;
+
+ cont= cont->next;
+ }
+ yco-= 6;
+ }
+ }
+
+ /* ******************************* */
+ xco= 985; yco= 170; width= 280;
+
+ uiBlockSetEmboss(block, UI_EMBOSSP);
+ uiDefBlockBut(block, actuator_menu, NULL, "Actuators", xco-10, yco+35, 100, 19, "");
+ uiBlockSetEmboss(block, UI_EMBOSS);
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, BUTS_ACT_SEL, B_REDR, "Sel", xco+110, yco+35, (width-110)/3, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show all selected Objects");
+ uiDefButBitS(block, TOG, BUTS_ACT_ACT, B_REDR, "Act", xco+110+(width-110)/3, yco+35, (width-110)/3, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show active Object");
+ uiDefButBitS(block, TOG, BUTS_ACT_LINK, B_REDR, "Link", xco+110+2*(width-110)/3, yco+35, (width-110)/3, 19, &G.buts->scaflag, 0, 0, 0, 0, "Show linked Objects to Controller");
+ uiBlockEndAlign(block);
+ for(a=0; a<count; a++) {
+ ob= (Object *)idar[a];
+ uiClearButLock();
+ uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
+ if( (ob->scavisflag & OB_VIS_ACT) == 0) continue;
+
+ /* presume it is only objects for now */
+ uiBlockSetEmboss(block, UI_EMBOSS);
+ uiBlockBeginAlign(block);
+ if(ob->actuators.first) uiSetCurFont(block, UI_HELVB);
+ uiDefButBitS(block, TOG, OB_SHOWACT, B_REDR, ob->id.name+2,(short)(xco-10), yco,(short)(width-30), 19, &ob->scaflag, 0, 31, 0, 0, "Object name, click to show/hide actuators");
+ if(ob->actuators.first) uiSetCurFont(block, UI_HELV);
+ uiDefButBitS(block, TOG, OB_ADDACT, B_ADD_ACT, "Add",(short)(xco+width-40), yco, 50, 19, &ob->scaflag, 0, 0, 0, 0, "Add a new Actuator");
+ uiBlockEndAlign(block);
+ yco-=20;
+
+ if(ob->scaflag & OB_SHOWACT) {
+
+ act= ob->actuators.first;
+ while(act) {
+ uiBlockSetEmboss(block, UI_EMBOSSM);
+ uiDefIconButBitS(block, TOG, ACT_DEL, B_DEL_ACT, ICON_X, xco, yco, 22, 19, &act->flag, 0, 0, 0, 0, "Delete Actuator");
+ uiDefIconButBitS(block, ICONTOG, ACT_SHOW, B_REDR, ICON_RIGHTARROW, (short)(xco+width-22), yco, 22, 19, &act->flag, 0, 0, 0, 0, "Actuator settings");
+
+ if(act->flag & ACT_SHOW) {
+ act->otype= act->type;
+ uiDefButS(block, MENU, B_CHANGE_ACT, actuator_pup(ob), (short)(xco+22), yco, 100, 19, &act->type, 0, 0, 0, 0, "Actuator type");
+ but= uiDefBut(block, TEX, 1, "", (short)(xco+122), yco, (short)(width-144), 19, act->name, 0, 31, 0, 0, "Actuator name");
+ uiButSetFunc(but, make_unique_prop_names_cb, act->name, (void*) 0);
+
+ ycoo= yco;
+ yco= draw_actuatorbuttons(act, block, xco, yco, width);
+ if(yco-6 < ycoo) ycoo= (yco+ycoo-20)/2;
+ }
+ else {
+ set_col_actuator(act->type, 1);
+ glRecti((short)(xco+22), yco, (short)(xco+width-22),(short)(yco+19));
+ but= uiDefBut(block, LABEL, 0, actuator_name(act->type), (short)(xco+22), yco, 100, 19, act, 0, 0, 0, 0, "Actuator type");
+ uiButSetFunc(but, sca_move_actuator, act, NULL);
+ but= uiDefBut(block, LABEL, 0, act->name, (short)(xco+122), yco, (short)(width-144), 19, act, 0, 0, 0, 0, "Actuator name");
+ uiButSetFunc(but, sca_move_actuator, act, NULL);
+ ycoo= yco;
+ }
+
+ uiDefIconBut(block, INLINK, 0, ICON_INLINK,(short)(xco-19), ycoo, 19, 19, act, LINK_ACTUATOR, 0, 0, 0, "");
+
+ yco-=20;
+
+ act= act->next;
+ }
+ yco-= 6;
+ }
+ }
+
+ uiComposeLinks(block);
+ uiDrawBlock(block);
+
+ if(idar) MEM_freeN(idar);
+}
+
diff --git a/source/blender/src/buttons_object.c b/source/blender/src/buttons_object.c
new file mode 100644
index 00000000000..98c2914cee4
--- /dev/null
+++ b/source/blender/src/buttons_object.c
@@ -0,0 +1,3546 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <time.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_ID.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_action.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_library.h"
+#include "BKE_softbody.h"
+#include "BKE_utildefines.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "BSE_filesel.h"
+#include "BSE_headerbuttons.h"
+
+#include "BIF_butspace.h"
+#include "BIF_editaction.h"
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+#include "BIF_graphics.h"
+#include "BIF_interface.h"
+#include "BIF_keyval.h"
+#include "BIF_mainqueue.h"
+#include "BIF_mywindow.h"
+#include "BIF_poseobject.h"
+#include "BIF_resources.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_toolbox.h"
+
+#include "BDR_drawobject.h"
+#include "BDR_editcurve.h"
+
+#include "mydevice.h"
+#include "blendef.h"
+
+/* -----includes for this file specific----- */
+
+
+#include "DNA_action_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_effect_types.h"
+#include "DNA_group_types.h"
+#include "DNA_image_types.h"
+#include "DNA_key_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_material_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_object_force.h"
+#include "DNA_object_fluidsim.h"
+#include "DNA_radio_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_sound_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_vfont_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_world_types.h"
+#include "DNA_text_types.h"
+
+#include "BKE_anim.h"
+#include "BKE_armature.h"
+#include "BKE_constraint.h"
+#include "BKE_curve.h"
+#include "BKE_deform.h"
+#include "BKE_depsgraph.h"
+#include "BKE_displist.h"
+#include "BKE_effect.h"
+#include "BKE_font.h"
+#include "BKE_group.h"
+#include "BKE_image.h"
+#include "BKE_ipo.h"
+#include "BKE_lattice.h"
+#include "BKE_material.h"
+#include "BKE_mball.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+#include "BKE_sound.h"
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
+#include "BKE_DerivedMesh.h"
+
+#include "LBM_fluidsim.h"
+#include "elbeem.h"
+
+#include "BIF_editconstraint.h"
+#include "BIF_editdeform.h"
+
+#include "BSE_editipo.h"
+#include "BSE_edit.h"
+
+#include "BDR_editobject.h"
+#include "BPY_extern.h"
+
+#include "butspace.h" // own module
+
+static float prspeed=0.0;
+float prlen=0.0;
+
+
+/* ********************* CONSTRAINT ***************************** */
+
+static void constraint_active_func(void *ob_v, void *con_v)
+{
+ Object *ob= ob_v;
+ bConstraint *con;
+ ListBase *lb;
+
+ /* lets be nice and escape if its active already */
+ if(con_v) {
+ con= con_v;
+ if(con->flag & CONSTRAINT_ACTIVE) return;
+ }
+
+ lb= get_active_constraints(ob);
+
+ for(con= lb->first; con; con= con->next) {
+ if(con==con_v) con->flag |= CONSTRAINT_ACTIVE;
+ else con->flag &= ~CONSTRAINT_ACTIVE;
+ }
+
+ /* make sure ipowin and buttons shows it */
+ if(ob->ipowin==ID_CO) {
+ allqueue(REDRAWIPO, ID_CO);
+ allspace(REMAKEIPO, 0);
+ allqueue(REDRAWNLA, 0);
+ }
+ allqueue(REDRAWBUTSOBJECT, 0);
+}
+
+static void add_constraint_to_active(Object *ob, bConstraint *con)
+{
+ ListBase *list;
+
+ list = get_active_constraints(ob);
+ if (list) {
+ unique_constraint_name(con, list);
+ BLI_addtail(list, con);
+
+ con->flag |= CONSTRAINT_ACTIVE;
+ for(con= con->prev; con; con= con->prev)
+ con->flag &= ~CONSTRAINT_ACTIVE;
+ }
+}
+
+/* returns base ID for Ipo, sets actname to channel if appropriate */
+/* should not make action... */
+void get_constraint_ipo_context(void *ob_v, char *actname)
+{
+ Object *ob= ob_v;
+
+ /* todo; check object if it has ob-level action ipo */
+
+ if (ob->flag & OB_POSEMODE) {
+ bPoseChannel *pchan;
+
+ pchan = get_active_posechannel(ob);
+ if (pchan) {
+ BLI_strncpy(actname, pchan->name, 32);
+ }
+ }
+ else if(ob->ipoflag & OB_ACTION_OB)
+ strcpy(actname, "Object");
+}
+
+/* initialize UI to show Ipo window and make sure channels etc exist */
+static void enable_constraint_ipo_func (void *ob_v, void *con_v)
+{
+ Object *ob= ob_v;
+ bConstraint *con = con_v;
+ char actname[32]="";
+
+ /* verifies if active constraint is set and shown in UI */
+ constraint_active_func(ob_v, con_v);
+
+ /* the context */
+ get_constraint_ipo_context(ob, actname);
+
+ /* adds ipo & channels & curve if needed */
+ verify_ipo((ID *)ob, ID_CO, actname, con->name);
+
+ /* make sure ipowin shows it */
+ ob->ipowin= ID_CO;
+ allqueue(REDRAWIPO, ID_CO);
+ allspace(REMAKEIPO, 0);
+ allqueue(REDRAWNLA, 0);
+}
+
+
+static void add_influence_key_to_constraint_func (void *ob_v, void *con_v)
+{
+ Object *ob= ob_v;
+ bConstraint *con = con_v;
+ IpoCurve *icu;
+ char actname[32]="";
+
+ /* verifies if active constraint is set and shown in UI */
+ constraint_active_func(ob_v, con_v);
+
+ /* the context */
+ get_constraint_ipo_context(ob, actname);
+
+ /* adds ipo & channels & curve if needed */
+ icu= verify_ipocurve((ID *)ob, ID_CO, actname, con->name, CO_ENFORCE);
+
+ if (!icu) {
+ error("Cannot get a curve from this IPO, may be dealing with linked data");
+ return;
+ }
+
+ if(ob->action)
+ insert_vert_icu(icu, get_action_frame(ob, (float)CFRA), con->enforce, 0);
+ else
+ insert_vert_icu(icu, CFRA, con->enforce, 0);
+
+ /* make sure ipowin shows it */
+ ob->ipowin= ID_CO;
+ allqueue(REDRAWIPO, ID_CO);
+ allspace(REMAKEIPO, 0);
+ allqueue(REDRAWNLA, 0);
+
+ BIF_undo_push("Insert Influence Key");
+}
+
+void del_constr_func (void *ob_v, void *con_v)
+{
+ bConstraint *con= con_v;
+ bConstraintChannel *chan;
+ ListBase *lb;
+
+ /* remove ipo channel */
+ lb= get_active_constraint_channels(ob_v, 0);
+ if(lb) {
+ chan = get_constraint_channel(lb, con->name);
+ if(chan) {
+ if(chan->ipo) chan->ipo->id.us--;
+ BLI_freelinkN(lb, chan);
+ }
+ }
+ /* remove constraint itself */
+ lb= get_active_constraints(ob_v);
+ free_constraint_data (con);
+ BLI_freelinkN(lb, con);
+
+ constraint_active_func(ob_v, NULL);
+}
+
+static void del_constraint_func (void *ob_v, void *con_v)
+{
+ del_constr_func (ob_v, con_v);
+ BIF_undo_push("Delete constraint");
+ allqueue(REDRAWBUTSOBJECT, 0);
+ allqueue(REDRAWIPO, 0);
+}
+
+static void verify_constraint_name_func (void *con_v, void *name_v)
+{
+ Object *ob= OBACT;
+ bConstraint *con= con_v;
+ char oldname[32];
+
+ if (!con)
+ return;
+
+ /* put on the stack */
+ BLI_strncpy(oldname, (char *)name_v, 32);
+
+ rename_constraint(ob, con, oldname);
+
+ constraint_active_func(ob, con);
+ allqueue(REDRAWACTION, 0);
+}
+
+void const_moveUp(void *ob_v, void *con_v)
+{
+ bConstraint *con, *constr= con_v;
+ ListBase *conlist;
+
+ if(constr->prev) {
+ conlist = get_active_constraints(ob_v);
+ for(con= conlist->first; con; con= con->next) {
+ if(con==constr) {
+ BLI_remlink(conlist, con);
+ BLI_insertlink(conlist, con->prev->prev, con);
+ break;
+ }
+ }
+ }
+}
+
+static void constraint_moveUp(void *ob_v, void *con_v)
+{
+ const_moveUp(ob_v, con_v);
+ BIF_undo_push("Move constraint");
+}
+
+void const_moveDown(void *ob_v, void *con_v)
+{
+ bConstraint *con, *constr= con_v;
+ ListBase *conlist;
+
+ if(constr->next) {
+ conlist = get_active_constraints(ob_v);
+ for(con= conlist->first; con; con= con->next) {
+ if(con==constr) {
+ BLI_remlink(conlist, con);
+ BLI_insertlink(conlist, con->next, con);
+ break;
+ }
+ }
+ }
+}
+
+static void constraint_moveDown(void *ob_v, void *con_v)
+{
+ const_moveDown(ob_v, con_v);
+ BIF_undo_push("Move constraint");
+}
+
+/* autocomplete callback for buttons */
+void autocomplete_bone(char *str, void *arg_v)
+{
+ Object *ob= (Object *)arg_v;
+
+ if(ob==NULL || ob->pose==NULL) return;
+
+ /* search if str matches the beginning of name */
+ if(str[0]) {
+ AutoComplete *autocpl= autocomplete_begin(str, 32);
+ bPoseChannel *pchan;
+
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next)
+ autocomplete_do_name(autocpl, pchan->name);
+
+ autocomplete_end(autocpl, str);
+ }
+}
+
+/* autocomplete callback for buttons */
+void autocomplete_vgroup(char *str, void *arg_v)
+{
+ Object *ob= (Object *)arg_v;
+
+ if(ob==NULL) return;
+
+ /* search if str matches the beginning of a name */
+ if(str[0]) {
+ AutoComplete *autocpl= autocomplete_begin(str, 32);
+ bDeformGroup *dg;
+
+ for(dg= ob->defbase.first; dg; dg= dg->next)
+ if(dg->name!=str)
+ autocomplete_do_name(autocpl, dg->name);
+
+ autocomplete_end(autocpl, str);
+ }
+}
+
+/* pole angle callback */
+void con_kinematic_set_pole_angle(void *ob_v, void *con_v)
+{
+ bConstraint *con= con_v;
+ bKinematicConstraint *data = con->data;
+
+ if(data->poletar) {
+ if(data->flag & CONSTRAINT_IK_SETANGLE) {
+ data->flag |= CONSTRAINT_IK_GETANGLE;
+ data->flag &= ~CONSTRAINT_IK_SETANGLE;
+ }
+ else {
+ data->flag &= ~CONSTRAINT_IK_GETANGLE;
+ data->flag |= CONSTRAINT_IK_SETANGLE;
+ }
+ }
+}
+
+/* some commonly used macros in the constraints drawing code */
+#define is_armature_target(target) (target && target->type==OB_ARMATURE)
+#define is_armature_owner(ob) ((ob->type == OB_ARMATURE) && (ob->flag & OB_POSEMODE))
+#define is_geom_target(target) (target && (ELEM(target->type, OB_MESH, OB_LATTICE)) )
+
+/* Helper function for draw constraint - draws constraint space stuff
+ * This function should not be called if no menus are required
+ * owner/target: -1 = don't draw menu; 0= not posemode, 1 = posemode
+ */
+static void draw_constraint_spaceselect (uiBlock *block, bConstraint *con, short xco, short yco, short owner, short target)
+{
+ short tarx, ownx;
+ short bwidth;
+
+ /* calculate sizes and placement of menus */
+ if (owner == -1) {
+ bwidth = 125;
+ tarx = 120;
+ ownx = 0;
+
+ }
+ else if (target == -1) {
+ bwidth = 125;
+ tarx = 0;
+ ownx = 120;
+ }
+ else {
+ bwidth = 100;
+ tarx = 95;
+ ownx = tarx + bwidth;
+ }
+
+
+ uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "CSpace:", xco, yco, 80,18, NULL, 0.0, 0.0, 0.0, 0.0, "");
+
+ uiBlockBeginAlign(block);
+
+ /* Target-Space */
+ if (target == 1) {
+ uiDefButC(block, MENU, B_CONSTRAINT_TEST, "Target Space %t|World Space %x0|Pose Space %x3|Local with Parent %x4|Local Space %x1",
+ tarx, yco, bwidth, 18, &con->tarspace, 0, 0, 0, 0, "Choose space that target is evaluated in");
+ }
+ else if (target == 0) {
+ uiDefButC(block, MENU, B_CONSTRAINT_TEST, "Target Space %t|World Space %x0|Local (Without Parent) Space %x1",
+ tarx, yco, bwidth, 18, &con->tarspace, 0, 0, 0, 0, "Choose space that target is evaluated in");
+ }
+
+ /* Owner-Space */
+ if (owner == 1) {
+ uiDefButC(block, MENU, B_CONSTRAINT_TEST, "Owner Space %t|World Space %x0|Pose Space %x3|Local with Parent %x4|Local Space %x1",
+ ownx, yco, bwidth, 18, &con->ownspace, 0, 0, 0, 0, "Choose space that owner is evaluated in");
+ }
+ else if (owner == 0) {
+ uiDefButC(block, MENU, B_CONSTRAINT_TEST, "Owner Space %t|World Space %x0|Local (Without Parent) Space %x1",
+ ownx, yco, bwidth, 18, &con->ownspace, 0, 0, 0, 0, "Choose space that owner is evaluated in");
+ }
+
+ uiBlockEndAlign(block);
+}
+
+/* draw panel showing settings for a constraint */
+static void draw_constraint (uiBlock *block, ListBase *list, bConstraint *con, short *xco, short *yco)
+{
+ Object *ob= OBACT;
+ bConstraintTypeInfo *cti;
+ uiBut *but;
+ char typestr[64];
+ short height, width = 265;
+ int rb_col;
+
+ cti= constraint_get_typeinfo(con);
+ if (cti == NULL) {
+ /* exception for 'Null' constraint - it doesn't have constraint typeinfo! */
+ if (con->type == CONSTRAINT_TYPE_NULL)
+ strcpy(typestr, "Null");
+ else
+ strcpy(typestr, "Unknown");
+ }
+ else
+ strcpy(typestr, cti->name);
+
+ /* unless button has own callback, it adds this callback to button */
+ uiBlockSetFunc(block, constraint_active_func, ob, con);
+
+ /* Draw constraint header */
+ uiBlockSetEmboss(block, UI_EMBOSSN);
+
+ /* rounded header */
+ rb_col= (con->flag & CONSTRAINT_ACTIVE)?40:20;
+ uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-10, *yco-1, width+40, 22, NULL, 5.0, 0.0,
+ (con->flag & CONSTRAINT_EXPAND)?3:15 , rb_col-20, "");
+
+ /* open/close */
+ uiDefIconButBitS(block, ICONTOG, CONSTRAINT_EXPAND, B_CONSTRAINT_TEST, ICON_DISCLOSURE_TRI_RIGHT, *xco-10, *yco, 20, 20, &con->flag, 0.0, 0.0, 0.0, 0.0, "Collapse/Expand Constraint");
+
+ /* up/down */
+ uiBlockBeginAlign(block);
+ uiBlockSetEmboss(block, UI_EMBOSS);
+ but = uiDefIconBut(block, BUT, B_CONSTRAINT_TEST, VICON_MOVE_UP, *xco+width-50, *yco, 16, 18, NULL, 0.0, 0.0, 0.0, 0.0, "Move constraint up in constraint stack");
+ uiButSetFunc(but, constraint_moveUp, ob, con);
+
+ but = uiDefIconBut(block, BUT, B_CONSTRAINT_TEST, VICON_MOVE_DOWN, *xco+width-50+18, *yco, 16, 18, NULL, 0.0, 0.0, 0.0, 0.0, "Move constraint down in constraint stack");
+ uiButSetFunc(but, constraint_moveDown, ob, con);
+ uiBlockEndAlign(block);
+
+ if (con->flag & CONSTRAINT_EXPAND) {
+ if (con->flag & CONSTRAINT_DISABLE)
+ uiBlockSetCol(block, TH_REDALERT);
+
+ uiBlockSetEmboss(block, UI_EMBOSS);
+
+ uiDefBut(block, LABEL, B_CONSTRAINT_TEST, typestr, *xco+10, *yco, 100, 18, NULL, 0.0, 0.0, 0.0, 0.0, "");
+
+ but = uiDefBut(block, TEX, B_CONSTRAINT_TEST, "", *xco+120, *yco, 85, 18, con->name, 0.0, 29.0, 0.0, 0.0, "Constraint name");
+ uiButSetFunc(but, verify_constraint_name_func, con, NULL);
+ }
+ else {
+ uiBlockSetEmboss(block, UI_EMBOSSN);
+
+ if (con->flag & CONSTRAINT_DISABLE)
+ uiBlockSetCol(block, TH_REDALERT);
+
+ uiDefBut(block, LABEL, B_CONSTRAINT_TEST, typestr, *xco+10, *yco, 100, 18, NULL, 0.0, 0.0, 0.0, 0.0, "");
+
+ uiDefBut(block, LABEL, B_CONSTRAINT_TEST, con->name, *xco+120, *yco-1, 135, 19, NULL, 0.0, 0.0, 0.0, 0.0, "");
+ }
+
+ uiBlockSetCol(block, TH_AUTO);
+
+ uiBlockSetEmboss(block, UI_EMBOSSN);
+
+ but = uiDefIconBut(block, BUT, B_CONSTRAINT_CHANGETARGET, ICON_X, *xco+262, *yco, 19, 19, list, 0.0, 0.0, 0.0, 0.0, "Delete constraint");
+ uiButSetFunc(but, del_constraint_func, ob, con);
+
+ uiBlockSetEmboss(block, UI_EMBOSS);
+
+
+ /* Draw constraint data */
+ if ((con->flag & CONSTRAINT_EXPAND) == 0) {
+ (*yco) -= 21;
+ }
+ else {
+ switch (con->type) {
+ case CONSTRAINT_TYPE_PYTHON:
+ {
+ bPythonConstraint *data = con->data;
+ bConstraintTarget *ct;
+ uiBut *but2;
+ int tarnum, theight;
+ static int pyconindex=0;
+ char *menustr;
+
+ theight = (data->tarnum)? (data->tarnum * 38) : (38);
+ height = theight + 78;
+ uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-10, *yco-height, width+40, height-1, NULL, 5.0, 0.0, 12, rb_col, "");
+
+ uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Script:", *xco+60, *yco-24, 55, 18, NULL, 0.0, 0.0, 0.0, 0.0, "");
+
+ /* do the scripts menu */
+ menustr = buildmenu_pyconstraints(data->text, &pyconindex);
+ but2 = uiDefButI(block, MENU, B_CONSTRAINT_TEST, menustr,
+ *xco+120, *yco-24, 150, 20, &pyconindex,
+ 0.0, 1.0, 0, 0, "Set the Script Constraint to use");
+ uiButSetFunc(but2, validate_pyconstraint_cb, data, &pyconindex);
+ MEM_freeN(menustr);
+
+ /* draw target(s) */
+ if (data->flag & PYCON_USETARGETS) {
+ /* Draw target parameters */
+ for (ct=data->targets.first, tarnum=1; ct; ct=ct->next, tarnum++) {
+ char tarstr[32];
+ short yoffset= ((tarnum-1) * 38);
+
+ /* target label */
+ sprintf(tarstr, "Target %02d:", tarnum);
+ uiDefBut(block, LABEL, B_CONSTRAINT_TEST, tarstr, *xco+45, *yco-(48+yoffset), 60, 18, NULL, 0.0, 0.0, 0.0, 0.0, "");
+
+ /* target space-selector - per target */
+ if (is_armature_target(ct->tar)) {
+ uiDefButS(block, MENU, B_CONSTRAINT_TEST, "Target Space %t|World Space %x0|Pose Space %x3|Local with Parent %x4|Local Space %x1",
+ *xco+10, *yco-(66+yoffset), 100, 18, &ct->space, 0, 0, 0, 0, "Choose space that target is evaluated in");
+ }
+ else {
+ uiDefButS(block, MENU, B_CONSTRAINT_TEST, "Target Space %t|World Space %x0|Local (Without Parent) Space %x1",
+ *xco+10, *yco-(66+yoffset), 100, 18, &ct->space, 0, 0, 0, 0, "Choose space that target is evaluated in");
+ }
+
+ uiBlockBeginAlign(block);
+ /* target object */
+ uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-(48+yoffset), 150, 18, &ct->tar, "Target Object");
+
+ /* subtarget */
+ if (is_armature_target(ct->tar)) {
+ but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-(66+yoffset),150,18, &ct->subtarget, 0, 24, 0, 0, "Subtarget Bone");
+ uiButSetCompleteFunc(but, autocomplete_bone, (void *)ct->tar);
+ }
+ else if (is_geom_target(ct->tar)) {
+ but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-(66+yoffset),150,18, &ct->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points");
+ uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)ct->tar);
+ }
+ else {
+ strcpy(ct->subtarget, "");
+ }
+ uiBlockEndAlign(block);
+ }
+ }
+ else {
+ /* Draw indication that no target needed */
+ uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Target:", *xco+60, *yco-48, 55, 18, NULL, 0.0, 0.0, 0.0, 0.0, "");
+ uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Not Applicable", *xco+120, *yco-48, 150, 18, NULL, 0.0, 0.0, 0.0, 0.0, "");
+ }
+
+ /* settings */
+ uiBlockBeginAlign(block);
+ but=uiDefBut(block, BUT, B_CONSTRAINT_TEST, "Options", *xco, *yco-(52+theight), (width/2),18, NULL, 0, 24, 0, 0, "Change some of the constraint's settings.");
+ uiButSetFunc(but, BPY_pyconstraint_settings, data, NULL);
+
+ but=uiDefBut(block, BUT, B_CONSTRAINT_TEST, "Refresh", *xco+((width/2)+10), *yco-(52+theight), (width/2),18, NULL, 0, 24, 0, 0, "Force constraint to refresh it's settings");
+ uiBlockEndAlign(block);
+
+ /* constraint space settings */
+ draw_constraint_spaceselect(block, con, *xco, *yco-(73+theight), is_armature_owner(ob), -1);
+ }
+ break;
+ case CONSTRAINT_TYPE_ACTION:
+ {
+ bActionConstraint *data = con->data;
+ float minval, maxval;
+
+ height = 108;
+ uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-10, *yco-height, width+40,height-1, NULL, 5.0, 0.0, 12, rb_col, "");
+
+ uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Target:", *xco+65, *yco-24, 50, 18, NULL, 0.0, 0.0, 0.0, 0.0, "");
+
+ /* Draw target parameters */
+ uiBlockBeginAlign(block);
+ uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-24, 135, 18, &data->tar, "Target Object");
+
+ if (is_armature_target(data->tar)) {
+ but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone");
+ uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar);
+ }
+ else {
+ strcpy(data->subtarget, "");
+ }
+
+ uiBlockEndAlign(block);
+
+ /* Draw action/type buttons */
+ uiBlockBeginAlign(block);
+ uiDefIDPoinBut(block, test_actionpoin_but, ID_AC, B_CONSTRAINT_TEST, "AC:", *xco+((width/2)-117), *yco-64, 78, 18, &data->act, "Action containing the keyed motion for this bone");
+ uiDefButS(block, MENU, B_CONSTRAINT_TEST, "Key on%t|Loc X%x20|Loc Y%x21|Loc Z%x22|Rot X%x0|Rot Y%x1|Rot Z%x2|Size X%x10|Size Y%x11|Size Z%x12", *xco+((width/2)-117), *yco-84, 78, 18, &data->type, 0, 24, 0, 0, "Specify which transformation channel from the target is used to key the action");
+ uiBlockEndAlign(block);
+
+ /* Draw start/end frame buttons */
+ uiBlockBeginAlign(block);
+ uiDefButI(block, NUM, B_CONSTRAINT_TEST, "Start:", *xco+((width/2)-36), *yco-64, 78, 18, &data->start, 1, MAXFRAME, 0.0, 0.0, "Starting frame of the keyed motion");
+ uiDefButI(block, NUM, B_CONSTRAINT_TEST, "End:", *xco+((width/2)-36), *yco-84, 78, 18, &data->end, 1, MAXFRAME, 0.0, 0.0, "Ending frame of the keyed motion");
+ uiBlockEndAlign(block);
+
+ /* Draw minimum/maximum transform range buttons */
+ uiBlockBeginAlign(block);
+ if (data->type < 10) { /* rotation */
+ minval = -180.0f;
+ maxval = 180.0f;
+ }
+ else if (data->type < 20) { /* scaling */
+ minval = 0.0001f;
+ maxval = 1000.0f;
+ }
+ else { /* location */
+ minval = -1000.0f;
+ maxval = 1000.0f;
+ }
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Min:", *xco+((width/2)+45), *yco-64, 78, 18, &data->min, minval, maxval, 0, 0, "Minimum value for target channel range");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Max:", *xco+((width/2)+45), *yco-84, 78, 18, &data->max, minval, maxval, 0, 0, "Maximum value for target channel range");
+ uiBlockEndAlign(block);
+
+ /* constraint space settings */
+ draw_constraint_spaceselect(block, con, *xco, *yco-104, -1, is_armature_target(data->tar));
+ }
+ break;
+ case CONSTRAINT_TYPE_CHILDOF:
+ {
+ bChildOfConstraint *data = con->data;
+ short normButWidth = (width/3);
+
+ height = 165;
+ uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-10, *yco-height, width+40,height-1, NULL, 5.0, 0.0, 12, rb_col, "");
+
+ uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Parent:", *xco+65, *yco-24, 50, 18, NULL, 0.0, 0.0, 0.0, 0.0, "");
+
+ /* Draw target parameters */
+ uiBlockBeginAlign(block);
+ uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-24, 135, 18, &data->tar, "Target Object to use as Parent");
+
+ if (is_armature_target(data->tar)) {
+ but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone to use as Parent");
+ uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar);
+ }
+ else if (is_geom_target(data->tar)) {
+ but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points");
+ uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar);
+ }
+ else {
+ strcpy(data->subtarget, "");
+ }
+ uiBlockEndAlign(block);
+
+ /* Draw triples of channel toggles */
+ uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Use Channel(s):", *xco+65, *yco-64, 150, 18, NULL, 0.0, 0.0, 0.0, 0.0, "");
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOG, CHILDOF_LOCX, B_CONSTRAINT_TEST, "Loc X", *xco, *yco-84, normButWidth, 18, &data->flag, 0, 24, 0, 0, "Parent affects x-location");
+ uiDefButBitI(block, TOG, CHILDOF_LOCY, B_CONSTRAINT_TEST, "Loc Y", *xco+normButWidth, *yco-84, normButWidth, 18, &data->flag, 0, 24, 0, 0, "Parent affects y-location");
+ uiDefButBitI(block, TOG, CHILDOF_LOCZ, B_CONSTRAINT_TEST, "Loc Z", *xco+(normButWidth * 2), *yco-84, normButWidth, 18, &data->flag, 0, 24, 0, 0, "Parent affects z-location");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOG, CHILDOF_ROTX, B_CONSTRAINT_TEST, "Rot X", *xco, *yco-105, normButWidth, 18, &data->flag, 0, 24, 0, 0, "Parent affects x-rotation");
+ uiDefButBitI(block, TOG, CHILDOF_ROTY, B_CONSTRAINT_TEST, "Rot Y", *xco+normButWidth, *yco-105, normButWidth, 18, &data->flag, 0, 24, 0, 0, "Parent affects y-rotation");
+ uiDefButBitI(block, TOG, CHILDOF_ROTZ, B_CONSTRAINT_TEST, "Rot Z", *xco+(normButWidth * 2), *yco-105, normButWidth, 18, &data->flag, 0, 24, 0, 0, "Parent affects z-rotation");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOG, CHILDOF_SIZEX, B_CONSTRAINT_TEST, "Scale X", *xco, *yco-126, normButWidth, 18, &data->flag, 0, 24, 0, 0, "Parent affects x-scaling");
+ uiDefButBitI(block, TOG, CHILDOF_SIZEY, B_CONSTRAINT_TEST, "Scale Y", *xco+normButWidth, *yco-126, normButWidth, 18, &data->flag, 0, 24, 0, 0, "Parent affects y-scaling");
+ uiDefButBitI(block, TOG, CHILDOF_SIZEZ, B_CONSTRAINT_TEST, "Scale Z", *xco+(normButWidth * 2), *yco-126, normButWidth, 18, &data->flag, 0, 24, 0, 0, "Parent affects z-scaling");
+ uiBlockEndAlign(block);
+
+
+ /* Inverse options */
+ uiBlockBeginAlign(block);
+ but=uiDefBut(block, BUT, B_CONSTRAINT_TEST, "Set Offset", *xco, *yco-151, (width/2),18, NULL, 0, 24, 0, 0, "Calculate current Parent-Inverse Matrix (i.e. restore offset from parent)");
+ uiButSetFunc(but, childof_const_setinv, data, NULL);
+
+ but=uiDefBut(block, BUT, B_CONSTRAINT_TEST, "Clear Offset", *xco+((width/2)+10), *yco-151, (width/2),18, NULL, 0, 24, 0, 0, "Clear Parent-Inverse Matrix (i.e. clear offset from parent)");
+ uiButSetFunc(but, childof_const_clearinv, data, NULL);
+ uiBlockEndAlign(block);
+ }
+ break;
+ case CONSTRAINT_TYPE_LOCLIKE:
+ {
+ bLocateLikeConstraint *data = con->data;
+
+ height = 111;
+ uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-10, *yco-height, width+40,height-1, NULL, 5.0, 0.0, 12, rb_col, "");
+
+ uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Target:", *xco+65, *yco-24, 50, 18, NULL, 0.0, 0.0, 0.0, 0.0, "");
+
+ /* Draw target parameters */
+ uiBlockBeginAlign(block);
+ uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-24, 135, 18, &data->tar, "Target Object");
+
+ if (is_armature_target(data->tar)) {
+ but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone");
+ uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar);
+ }
+ else if (is_geom_target(data->tar)) {
+ but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points");
+ uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar);
+ }
+ else {
+ strcpy(data->subtarget, "");
+ }
+ uiBlockEndAlign(block);
+
+ /* Draw XYZ toggles */
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOG, LOCLIKE_X, B_CONSTRAINT_TEST, "X", *xco+((width/2)-48), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Copy X component");
+ uiDefButBitI(block, TOG, LOCLIKE_X_INVERT, B_CONSTRAINT_TEST, "-", *xco+((width/2)-16), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Invert X component");
+ uiDefButBitI(block, TOG, LOCLIKE_Y, B_CONSTRAINT_TEST, "Y", *xco+((width/2)+16), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Copy Y component");
+ uiDefButBitI(block, TOG, LOCLIKE_Y_INVERT, B_CONSTRAINT_TEST, "-", *xco+((width/2)+48), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Invert Y component");
+ uiDefButBitI(block, TOG, LOCLIKE_Z, B_CONSTRAINT_TEST, "Z", *xco+((width/2)+96), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Copy Z component");
+ uiDefButBitI(block, TOG, LOCLIKE_Z_INVERT, B_CONSTRAINT_TEST, "-", *xco+((width/2)+128), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Invert Z component");
+ uiBlockEndAlign(block);
+
+ /* Draw options */
+ uiDefButBitI(block, TOG, LOCLIKE_OFFSET, B_CONSTRAINT_TEST, "Offset", *xco, *yco-89, (width/2), 18, &data->flag, 0, 24, 0, 0, "Add original location onto copied location");
+ if (is_armature_target(data->tar)) {
+ uiDefButBitI(block, TOG, LOCLIKE_TIP, B_CONSTRAINT_TEST, "Target Bone Tail", *xco+(width/2), *yco-89, (width/2), 18, &data->flag, 0, 24, 0, 0, "Copy Location of Target Bone's Tail");
+ }
+
+ /* constraint space settings */
+ draw_constraint_spaceselect(block, con, *xco, *yco-109, is_armature_owner(ob), is_armature_target(data->tar));
+ }
+ break;
+ case CONSTRAINT_TYPE_ROTLIKE:
+ {
+ bRotateLikeConstraint *data = con->data;
+
+ height = 101;
+ uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-10, *yco-height, width+40,height-1, NULL, 5.0, 0.0, 12, rb_col, "");
+
+ uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Target:", *xco+65, *yco-24, 50, 18, NULL, 0.0, 0.0, 0.0, 0.0, "");
+
+ /* Draw target parameters */
+ uiBlockBeginAlign(block);
+ uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-24, 135, 18, &data->tar, "Target Object");
+
+ if (is_armature_target(data->tar)) {
+ but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone");
+ uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar);
+ }
+ else if (is_geom_target(data->tar)) {
+ but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points");
+ uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar);
+ }
+ else {
+ strcpy(data->subtarget, "");
+ }
+ uiBlockEndAlign(block);
+
+ /* Draw XYZ toggles */
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOG, ROTLIKE_X, B_CONSTRAINT_TEST, "X", *xco+((width/2)-48), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Copy X component");
+ uiDefButBitI(block, TOG, ROTLIKE_X_INVERT, B_CONSTRAINT_TEST, "-", *xco+((width/2)-16), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Invert X component");
+ uiDefButBitI(block, TOG, ROTLIKE_Y, B_CONSTRAINT_TEST, "Y", *xco+((width/2)+16), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Copy Y component");
+ uiDefButBitI(block, TOG, ROTLIKE_Y_INVERT, B_CONSTRAINT_TEST, "-", *xco+((width/2)+48), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Invert Y component");
+ uiDefButBitI(block, TOG, ROTLIKE_Z, B_CONSTRAINT_TEST, "Z", *xco+((width/2)+96), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Copy Z component");
+ uiDefButBitI(block, TOG, ROTLIKE_Z_INVERT, B_CONSTRAINT_TEST, "-", *xco+((width/2)+128), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Invert Z component");
+ uiBlockEndAlign(block);
+
+ /* draw offset toggle */
+ uiDefButBitI(block, TOG, ROTLIKE_OFFSET, B_CONSTRAINT_TEST, "Offset", *xco, *yco-64, 80, 18, &data->flag, 0, 24, 0, 0, "Add original rotation onto copied rotation");
+
+ /* constraint space settings */
+ draw_constraint_spaceselect(block, con, *xco, *yco-94, is_armature_owner(ob), is_armature_target(data->tar));
+ }
+ break;
+ case CONSTRAINT_TYPE_SIZELIKE:
+ {
+ bSizeLikeConstraint *data = con->data;
+
+ height = 101;
+
+ uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-10, *yco-height, width+40,height-1, NULL, 5.0, 0.0, 12, rb_col, "");
+
+ uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Target:", *xco+65, *yco-24, 50, 18, NULL, 0.0, 0.0, 0.0, 0.0, "");
+
+ /* Draw target parameters */
+ uiBlockBeginAlign(block);
+ uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-24, 135, 18, &data->tar, "Target Object");
+
+ if (is_armature_target(data->tar)) {
+ but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone");
+ uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar);
+ }
+ else if (is_geom_target(data->tar)) {
+ but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points");
+ uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar);
+ }
+ else {
+ strcpy(data->subtarget, "");
+ }
+ uiBlockEndAlign(block);
+
+ /* Draw XYZ toggles */
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOG, SIZELIKE_X, B_CONSTRAINT_TEST, "X", *xco+((width/2)-48), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Copy X component");
+ uiDefButBitI(block, TOG, SIZELIKE_Y, B_CONSTRAINT_TEST, "Y", *xco+((width/2)-16), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Copy Y component");
+ uiDefButBitI(block, TOG, SIZELIKE_Z, B_CONSTRAINT_TEST, "Z", *xco+((width/2)+16), *yco-64, 32, 18, &data->flag, 0, 24, 0, 0, "Copy Z component");
+ uiBlockEndAlign(block);
+
+ /* draw offset toggle */
+ uiDefButBitI(block, TOG, SIZELIKE_OFFSET, B_CONSTRAINT_TEST, "Offset", *xco, *yco-64, 80, 18, &data->flag, 0, 24, 0, 0, "Add original scaling onto copied scaling");
+
+ /* constraint space settings */
+ draw_constraint_spaceselect(block, con, *xco, *yco-94, is_armature_owner(ob), is_armature_target(data->tar));
+ }
+ break;
+ case CONSTRAINT_TYPE_KINEMATIC:
+ {
+ bKinematicConstraint *data = con->data;
+
+ height = 146;
+ if(data->poletar)
+ height += 30;
+
+ uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-10, *yco-height, width+40,height-1, NULL, 5.0, 0.0, 12, rb_col, "");
+
+ /* IK Target */
+ uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Target:", *xco, *yco-24, 50, 18, NULL, 0.0, 0.0, 0.0, 0.0, "");
+
+ /* Draw target parameters */
+ uiBlockBeginAlign(block);
+ uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco, *yco-44, 137, 19, &data->tar, "Target Object");
+
+ if (is_armature_target(data->tar)) {
+ but=uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco, *yco-62,137,19, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone");
+ uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar);
+ }
+ else if (is_geom_target(data->tar)) {
+ but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco, *yco-62,137,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points");
+ uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar);
+ }
+ else {
+ strcpy (data->subtarget, "");
+ }
+
+ uiBlockEndAlign(block);
+
+ /* Settings */
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, CONSTRAINT_IK_TIP, B_CONSTRAINT_TEST, "Use Tail", *xco, *yco-92, 137, 19, &data->flag, 0, 0, 0, 0, "Include Bone's tail als last element in Chain");
+ uiDefButI(block, NUM, B_CONSTRAINT_TEST, "ChainLen:", *xco, *yco-112,137,19, &data->rootbone, 0, 255, 0, 0, "If not zero, the amount of bones in this chain");
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUMSLI, B_CONSTRAINT_TEST, "PosW ", *xco+147, *yco-92, 137, 19, &data->weight, 0.01, 1.0, 2, 2, "For Tree-IK: weight of position control for this target");
+ uiDefButBitS(block, TOG, CONSTRAINT_IK_ROT, B_CONSTRAINT_TEST, "Rot", *xco+147, *yco-112, 40,19, &data->flag, 0, 0, 0, 0, "Chain follows rotation of target");
+ uiDefButF(block, NUMSLI, B_CONSTRAINT_TEST, "W ", *xco+187, *yco-112, 97, 19, &data->orientweight, 0.01, 1.0, 2, 2, "For Tree-IK: Weight of orientation control for this target");
+
+ uiBlockBeginAlign(block);
+
+ uiDefButBitS(block, TOG, CONSTRAINT_IK_STRETCH, B_CONSTRAINT_TEST, "Stretch", *xco, *yco-137,137,19, &data->flag, 0, 0, 0, 0, "Enable IK stretching");
+ uiBlockBeginAlign(block);
+ uiDefButS(block, NUM, B_CONSTRAINT_TEST, "Iterations:", *xco+147, *yco-137, 137, 19, &data->iterations, 1, 10000, 0, 0, "Maximum number of solving iterations");
+ uiBlockEndAlign(block);
+
+ /* Pole Vector */
+ uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Pole Target:", *xco+147, *yco-24, 100, 18, NULL, 0.0, 0.0, 0.0, 0.0, "");
+
+ uiBlockBeginAlign(block);
+ uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+147, *yco-44, 137, 19, &data->poletar, "Pole Target Object");
+ if (is_armature_target(data->poletar)) {
+ but=uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+147, *yco-62,137,19, &data->polesubtarget, 0, 24, 0, 0, "Pole Subtarget Bone");
+ uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->poletar);
+ }
+ else if (is_geom_target(data->poletar)) {
+ but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+147, *yco-62,137,18, &data->polesubtarget, 0, 24, 0, 0, "Name of Vertex Group defining pole 'target' points");
+ uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->poletar);
+ }
+ else {
+ strcpy (data->polesubtarget, "");
+ }
+
+ if(data->poletar) {
+ uiBlockBeginAlign(block);
+#if 0
+ but = uiDefBut(block, BUT, B_CONSTRAINT_TEST, (data->flag & CONSTRAINT_IK_SETANGLE)? "Set Pole Offset": "Clear Pole Offset", *xco, *yco-167, 137, 19, 0, 0.0, 1.0, 0.0, 0.0, "Set the pole rotation offset from the current pose");
+ uiButSetFunc(but, con_kinematic_set_pole_angle, ob, con);
+ if(!(data->flag & CONSTRAINT_IK_SETANGLE))
+#endif
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Pole Offset ", *xco, *yco-167, 137, 19, &data->poleangle, -180.0, 180.0, 0, 0, "Pole rotation offset");
+ }
+ }
+ break;
+ case CONSTRAINT_TYPE_TRACKTO:
+ {
+ bTrackToConstraint *data = con->data;
+
+ height = 96;
+ uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-10, *yco-height, width+40,height-1, NULL, 5.0, 0.0, 12, rb_col, "");
+
+ uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Target:", *xco+65, *yco-24, 50, 18, NULL, 0.0, 0.0, 0.0, 0.0, "");
+
+ /* Draw target parameters */
+ uiBlockBeginAlign(block);
+ uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-24, 135, 18, &data->tar, "Target Object");
+
+ if (is_armature_target(data->tar)) {
+ but=uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone");
+ uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar);
+ }
+ else if (is_geom_target(data->tar)) {
+ but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points");
+ uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar);
+ }
+ else {
+ strcpy(data->subtarget, "");
+ }
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Align:", *xco+5, *yco-42, 50, 18, NULL, 0.0, 0.0, 0.0, 0.0, "");
+
+ uiDefButBitI(block, TOG, 1, B_CONSTRAINT_TEST, "TargetZ", *xco+60, *yco-42, 50, 18, &data->flags, 0, 1, 0, 0, "Target Z axis, not world Z axis, will constrain up direction");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "To:", *xco+12, *yco-64, 25, 18, NULL, 0.0, 0.0, 0.0, 0.0, "");
+
+ uiDefButI(block, ROW,B_CONSTRAINT_TEST,"X", *xco+39, *yco-64,17,18, &data->reserved1, 12.0, 0.0, 0, 0, "X axis points to the target object");
+ uiDefButI(block, ROW,B_CONSTRAINT_TEST,"Y", *xco+56, *yco-64,17,18, &data->reserved1, 12.0, 1.0, 0, 0, "Y axis points to the target object");
+ uiDefButI(block, ROW,B_CONSTRAINT_TEST,"Z", *xco+73, *yco-64,17,18, &data->reserved1, 12.0, 2.0, 0, 0, "Z axis points to the target object");
+ uiDefButI(block, ROW,B_CONSTRAINT_TEST,"-X", *xco+90, *yco-64,24,18, &data->reserved1, 12.0, 3.0, 0, 0, "-X axis points to the target object");
+ uiDefButI(block, ROW,B_CONSTRAINT_TEST,"-Y", *xco+114, *yco-64,24,18, &data->reserved1, 12.0, 4.0, 0, 0, "-Y axis points to the target object");
+ uiDefButI(block, ROW,B_CONSTRAINT_TEST,"-Z", *xco+138, *yco-64,24,18, &data->reserved1, 12.0, 5.0, 0, 0, "-Z axis points to the target object");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Up:", *xco+174, *yco-64, 30, 18, NULL, 0.0, 0.0, 0.0, 0.0, "");
+
+ uiDefButI(block, ROW,B_CONSTRAINT_TEST,"X", *xco+204, *yco-64,17,18, &data->reserved2, 13.0, 0.0, 0, 0, "X axis points upward");
+ uiDefButI(block, ROW,B_CONSTRAINT_TEST,"Y", *xco+221, *yco-64,17,18, &data->reserved2, 13.0, 1.0, 0, 0, "Y axis points upward");
+ uiDefButI(block, ROW,B_CONSTRAINT_TEST,"Z", *xco+238, *yco-64,17,18, &data->reserved2, 13.0, 2.0, 0, 0, "Z axis points upward");
+ uiBlockEndAlign(block);
+
+ /* constraint space settings */
+ draw_constraint_spaceselect(block, con, *xco, *yco-94, is_armature_owner(ob), is_armature_target(data->tar));
+ }
+ break;
+ case CONSTRAINT_TYPE_MINMAX:
+ {
+ bMinMaxConstraint *data = con->data;
+
+ height = 66;
+ uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-10, *yco-height, width+40,height-1, NULL, 5.0, 0.0, 12, rb_col, "");
+
+ uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Target:", *xco+65, *yco-24, 50, 18, NULL, 0.0, 0.0, 0.0, 0.0, "");
+
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Offset:", *xco, *yco-44, 100, 18, &data->offset, -100, 100, 100.0, 0.0, "Offset from the position of the object center");
+
+ /* Draw target parameters */
+ uiBlockBeginAlign(block);
+ uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-24, 135, 18, &data->tar, "Target Object");
+
+ if (is_armature_target(data->tar)) {
+ but=uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone");
+ uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar);
+ }
+ else if (is_geom_target(data->tar)) {
+ but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points");
+ uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar);
+ }
+ else {
+ strcpy(data->subtarget, "");
+ }
+ uiBlockEndAlign(block);
+
+ uiDefButBitI(block, TOG, 0, B_CONSTRAINT_TEST, "Sticky", *xco, *yco-24, 44, 18, &data->flag, 0, 24, 0, 0, "Immobilize object while constrained");
+ uiDefButBitI(block, TOG, 2, B_CONSTRAINT_TEST, "Use Rot", *xco+44, *yco-24, 64, 18, &data->flag, 0, 24, 0, 0, "Use target object rotation");
+
+ uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Max/Min:", *xco-8, *yco-64, 54, 18, NULL, 0.0, 0.0, 0.0, 0.0, "");
+
+ uiBlockBeginAlign(block);
+ uiDefButI(block, ROW, B_CONSTRAINT_TEST,"X", *xco+51, *yco-64,17,18, &data->minmaxflag, 12.0, 0.0, 0, 0, "Will not pass below X of target");
+ uiDefButI(block, ROW, B_CONSTRAINT_TEST,"Y", *xco+67, *yco-64,17,18, &data->minmaxflag, 12.0, 1.0, 0, 0, "Will not pass below Y of target");
+ uiDefButI(block, ROW, B_CONSTRAINT_TEST,"Z", *xco+85, *yco-64,17,18, &data->minmaxflag, 12.0, 2.0, 0, 0, "Will not pass below Z of target");
+ uiDefButI(block, ROW, B_CONSTRAINT_TEST,"-X", *xco+102, *yco-64,24,18, &data->minmaxflag, 12.0, 3.0, 0, 0, "Will not pass above X of target");
+ uiDefButI(block, ROW, B_CONSTRAINT_TEST,"-Y", *xco+126, *yco-64,24,18, &data->minmaxflag, 12.0, 4.0, 0, 0, "Will not pass above Y of target");
+ uiDefButI(block, ROW, B_CONSTRAINT_TEST,"-Z", *xco+150, *yco-64,24,18, &data->minmaxflag, 12.0, 5.0, 0, 0, "Will not pass above Z of target");
+ uiBlockEndAlign(block);
+ }
+ break;
+ case CONSTRAINT_TYPE_LOCKTRACK:
+ {
+ bLockTrackConstraint *data = con->data;
+ height = 66;
+ uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-10, *yco-height, width+40,height-1, NULL, 5.0, 0.0, 12, rb_col, "");
+
+ uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Target:", *xco+65, *yco-24, 50, 18, NULL, 0.0, 0.0, 0.0, 0.0, "");
+
+ /* Draw target parameters */
+ uiBlockBeginAlign(block);
+ uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-24, 135, 18, &data->tar, "Target Object");
+
+ if (is_armature_target(data->tar)) {
+ but=uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone");
+ uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar);
+ }
+ else if (is_geom_target(data->tar)) {
+ but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points");
+ uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar);
+ }
+ else {
+ strcpy(data->subtarget, "");
+ }
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "To:", *xco+12, *yco-64, 25, 18, NULL, 0.0, 0.0, 0.0, 0.0, "");
+
+ uiDefButI(block, ROW, B_CONSTRAINT_TEST,"X", *xco+39, *yco-64,17,18, &data->trackflag, 12.0, 0.0, 0, 0, "X axis points to the target object");
+ uiDefButI(block, ROW, B_CONSTRAINT_TEST,"Y", *xco+56, *yco-64,17,18, &data->trackflag, 12.0, 1.0, 0, 0, "Y axis points to the target object");
+ uiDefButI(block, ROW, B_CONSTRAINT_TEST,"Z", *xco+73, *yco-64,17,18, &data->trackflag, 12.0, 2.0, 0, 0, "Z axis points to the target object");
+ uiDefButI(block, ROW, B_CONSTRAINT_TEST,"-X", *xco+90, *yco-64,24,18, &data->trackflag, 12.0, 3.0, 0, 0, "-X axis points to the target object");
+ uiDefButI(block, ROW, B_CONSTRAINT_TEST,"-Y", *xco+114, *yco-64,24,18, &data->trackflag, 12.0, 4.0, 0, 0, "-Y axis points to the target object");
+ uiDefButI(block, ROW, B_CONSTRAINT_TEST,"-Z", *xco+138, *yco-64,24,18, &data->trackflag, 12.0, 5.0, 0, 0, "-Z axis points to the target object");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Lock:", *xco+166, *yco-64, 38, 18, NULL, 0.0, 0.0, 0.0, 0.0, "");
+
+ uiDefButI(block, ROW, B_CONSTRAINT_TEST,"X", *xco+204, *yco-64,17,18, &data->lockflag, 13.0, 0.0, 0, 0, "X axis is locked");
+ uiDefButI(block, ROW, B_CONSTRAINT_TEST,"Y", *xco+221, *yco-64,17,18, &data->lockflag, 13.0, 1.0, 0, 0, "Y axis is locked");
+ uiDefButI(block, ROW, B_CONSTRAINT_TEST,"Z", *xco+238, *yco-64,17,18, &data->lockflag, 13.0, 2.0, 0, 0, "Z axis is locked");
+ uiBlockEndAlign(block);
+ }
+ break;
+ case CONSTRAINT_TYPE_FOLLOWPATH:
+ {
+ bFollowPathConstraint *data = con->data;
+
+ height = 66;
+ uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-10, *yco-height, width+40,height-1, NULL, 5.0, 0.0, 12, rb_col, "");
+
+ uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Target:", *xco+65, *yco-24, 50, 18, NULL, 0.0, 0.0, 0.0, 0.0, "");
+
+ /* Draw target parameters */
+ uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-24, 135, 18, &data->tar, "Target Object");
+
+ /* Draw Curve Follow toggle */
+ uiDefButBitI(block, TOG, 1, B_CONSTRAINT_TEST, "CurveFollow", *xco+39, *yco-44, 100, 18, &data->followflag, 0, 24, 0, 0, "Object will follow the heading and banking of the curve");
+
+ /* Draw Offset number button */
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Offset:", *xco+155, *yco-44, 100, 18, &data->offset, -MAXFRAMEF, MAXFRAMEF, 100.0, 0.0, "Offset from the position corresponding to the time frame");
+
+ uiBlockBeginAlign(block);
+ uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Fw:", *xco+12, *yco-64, 27, 18, NULL, 0.0, 0.0, 0.0, 0.0, "");
+
+ uiDefButI(block, ROW, B_CONSTRAINT_TEST,"X", *xco+39, *yco-64,17,18, &data->trackflag, 12.0, 0.0, 0, 0, "The axis that points forward along the path");
+ uiDefButI(block, ROW, B_CONSTRAINT_TEST,"Y", *xco+56, *yco-64,17,18, &data->trackflag, 12.0, 1.0, 0, 0, "The axis that points forward along the path");
+ uiDefButI(block, ROW, B_CONSTRAINT_TEST,"Z", *xco+73, *yco-64,17,18, &data->trackflag, 12.0, 2.0, 0, 0, "The axis that points forward along the path");
+ uiDefButI(block, ROW, B_CONSTRAINT_TEST,"-X", *xco+90, *yco-64,24,18, &data->trackflag, 12.0, 3.0, 0, 0, "The axis that points forward along the path");
+ uiDefButI(block, ROW, B_CONSTRAINT_TEST,"-Y", *xco+114, *yco-64,24,18, &data->trackflag, 12.0, 4.0, 0, 0, "The axis that points forward along the path");
+ uiDefButI(block, ROW, B_CONSTRAINT_TEST,"-Z", *xco+138, *yco-64,24,18, &data->trackflag, 12.0, 5.0, 0, 0, "The axis that points forward along the path");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Up:", *xco+174, *yco-64, 30, 18, NULL, 0.0, 0.0, 0.0, 0.0, "");
+
+ uiDefButI(block, ROW, B_CONSTRAINT_TEST,"X", *xco+204, *yco-64,17,18, &data->upflag, 13.0, 0.0, 0, 0, "The axis that points upward");
+ uiDefButI(block, ROW, B_CONSTRAINT_TEST,"Y", *xco+221, *yco-64,17,18, &data->upflag, 13.0, 1.0, 0, 0, "The axis that points upward");
+ uiDefButI(block, ROW, B_CONSTRAINT_TEST,"Z", *xco+238, *yco-64,17,18, &data->upflag, 13.0, 2.0, 0, 0, "The axis that points upward");
+ uiBlockEndAlign(block);
+ }
+ break;
+ case CONSTRAINT_TYPE_STRETCHTO:
+ {
+ bStretchToConstraint *data = con->data;
+
+ height = 105;
+ uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-10, *yco-height, width+40,height-1, NULL, 5.0, 0.0, 12, rb_col, "");
+
+ uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Target:", *xco+65, *yco-24, 50, 18, NULL, 0.0, 0.0, 0.0, 0.0, "");
+
+ /* Draw target parameters */
+ uiBlockBeginAlign(block);
+ uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-24, 135, 18, &data->tar, "Target Object");
+
+ if (is_armature_target(data->tar)) {
+ but=uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone");
+ uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar);
+ }
+ else if (is_geom_target(data->tar)) {
+ but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points");
+ uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar);
+ }
+ else {
+ strcpy(data->subtarget, "");
+ }
+ uiBlockEndAlign(block);
+
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block,BUTM,B_CONSTRAINT_TEST,"R",*xco, *yco-60,20,18,&(data->orglength),0.0,0,0,0,"Recalculate RLength");
+ uiDefButF(block,NUM,B_CONSTRAINT_TEST,"Rest Length:",*xco+18, *yco-60,237,18,&(data->orglength),0.0,100,0.5,0.5,"Length at Rest Position");
+ uiBlockEndAlign(block);
+
+ uiDefButF(block,NUM,B_CONSTRAINT_TEST,"Volume Variation:",*xco+18, *yco-82,237,18,&(data->bulge),0.0,100,0.5,0.5,"Factor between volume variation and stretching");
+
+ uiBlockBeginAlign(block);
+ uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Vol:",*xco+14, *yco-104,30,18, NULL, 0.0, 0.0, 0.0, 0.0, "");
+ uiDefButI(block, ROW,B_CONSTRAINT_TEST,"XZ", *xco+44, *yco-104,30,18, &data->volmode, 12.0, 0.0, 0, 0, "Keep Volume: Scaling X & Z");
+ uiDefButI(block, ROW,B_CONSTRAINT_TEST,"X", *xco+74, *yco-104,20,18, &data->volmode, 12.0, 1.0, 0, 0, "Keep Volume: Scaling X");
+ uiDefButI(block, ROW,B_CONSTRAINT_TEST,"Z", *xco+94, *yco-104,20,18, &data->volmode, 12.0, 2.0, 0, 0, "Keep Volume: Scaling Z");
+ uiDefButI(block, ROW,B_CONSTRAINT_TEST,"NONE", *xco+114, *yco-104,50,18, &data->volmode, 12.0, 3.0, 0, 0, "Ignore Volume");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefBut(block, LABEL, B_CONSTRAINT_TEST,"Plane:",*xco+175, *yco-104,40,18, NULL, 0.0, 0.0, 0.0, 0.0, "");
+ uiDefButI(block, ROW,B_CONSTRAINT_TEST,"X", *xco+215, *yco-104,20,18, &data->plane, 12.0, 0.0, 0, 0, "Keep X axis");
+ uiDefButI(block, ROW,B_CONSTRAINT_TEST,"Z", *xco+235, *yco-104,20,18, &data->plane, 12.0, 2.0, 0, 0, "Keep Z axis");
+ uiBlockEndAlign(block);
+ }
+ break;
+ case CONSTRAINT_TYPE_LOCLIMIT:
+ {
+ bLocLimitConstraint *data = con->data;
+
+ int togButWidth = 50;
+ int textButWidth = ((width/2)-togButWidth);
+
+ height = 106;
+ uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-10, *yco-height, width+40,height-1, NULL, 5.0, 0.0, 12, rb_col, "");
+
+ /* Draw Pairs of LimitToggle+LimitValue */
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, LIMIT_XMIN, B_CONSTRAINT_TEST, "minX", *xco, *yco-28, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum x value");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+togButWidth, *yco-28, (textButWidth-5), 18, &(data->xmin), -1000, 1000, 0.1,0.5,"Lowest x value to allow");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, LIMIT_XMAX, B_CONSTRAINT_TEST, "maxX", *xco+(width-(textButWidth-5)-togButWidth), *yco-28, 50, 18, &data->flag, 0, 24, 0, 0, "Use maximum x value");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+(width-textButWidth-5), *yco-28, (textButWidth-5), 18, &(data->xmax), -1000, 1000, 0.1,0.5,"Highest x value to allow");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, LIMIT_YMIN, B_CONSTRAINT_TEST, "minY", *xco, *yco-50, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum y value");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+togButWidth, *yco-50, (textButWidth-5), 18, &(data->ymin), -1000, 1000, 0.1,0.5,"Lowest y value to allow");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, LIMIT_YMAX, B_CONSTRAINT_TEST, "maxY", *xco+(width-(textButWidth-5)-togButWidth), *yco-50, 50, 18, &data->flag, 0, 24, 0, 0, "Use maximum y value");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+(width-textButWidth-5), *yco-50, (textButWidth-5), 18, &(data->ymax), -1000, 1000, 0.1,0.5,"Highest y value to allow");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, LIMIT_ZMIN, B_CONSTRAINT_TEST, "minZ", *xco, *yco-72, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum z value");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+togButWidth, *yco-72, (textButWidth-5), 18, &(data->zmin), -1000, 1000, 0.1,0.5,"Lowest z value to allow");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, LIMIT_ZMAX, B_CONSTRAINT_TEST, "maxZ", *xco+(width-(textButWidth-5)-togButWidth), *yco-72, 50, 18, &data->flag, 0, 24, 0, 0, "Use maximum z value");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+(width-textButWidth-5), *yco-72, (textButWidth-5), 18, &(data->zmax), -1000, 1000, 0.1,0.5,"Highest z value to allow");
+ uiBlockEndAlign(block);
+
+ /* constraint space settings */
+ draw_constraint_spaceselect(block, con, *xco, *yco-100, is_armature_owner(ob), -1);
+ }
+ break;
+ case CONSTRAINT_TYPE_ROTLIMIT:
+ {
+ bRotLimitConstraint *data = con->data;
+ int normButWidth = (width/3);
+
+ height = 106;
+
+ uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-10, *yco-height, width+40,height-1, NULL, 5.0, 0.0, 12, rb_col, "");
+
+ /* Draw Pairs of LimitToggle+LimitValue */
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, LIMIT_XROT, B_CONSTRAINT_TEST, "LimitX", *xco, *yco-28, normButWidth, 18, &data->flag, 0, 24, 0, 0, "Limit rotation on x-axis");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "min:", *xco+normButWidth, *yco-28, normButWidth, 18, &(data->xmin), -360, 360, 0.1,0.5,"Lowest x value to allow");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "max:", *xco+(normButWidth * 2), *yco-28, normButWidth, 18, &(data->xmax), -360, 360, 0.1,0.5,"Highest x value to allow");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, LIMIT_YROT, B_CONSTRAINT_TEST, "LimitY", *xco, *yco-50, normButWidth, 18, &data->flag, 0, 24, 0, 0, "Limit rotation on y-axis");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "min:", *xco+normButWidth, *yco-50, normButWidth, 18, &(data->ymin), -360, 360, 0.1,0.5,"Lowest y value to allow");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "max:", *xco+(normButWidth * 2), *yco-50, normButWidth, 18, &(data->ymax), -360, 360, 0.1,0.5,"Highest y value to allow");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, LIMIT_ZROT, B_CONSTRAINT_TEST, "LimitZ", *xco, *yco-72, normButWidth, 18, &data->flag, 0, 24, 0, 0, "Limit rotation on z-axis");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "min:", *xco+normButWidth, *yco-72, normButWidth, 18, &(data->zmin), -360, 360, 0.1,0.5,"Lowest z value to allow");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "max:", *xco+(normButWidth * 2), *yco-72, normButWidth, 18, &(data->zmax), -360, 360, 0.1,0.5,"Highest z value to allow");
+ uiBlockEndAlign(block);
+
+ /* constraint space settings */
+ draw_constraint_spaceselect(block, con, *xco, *yco-100, is_armature_owner(ob), -1);
+ }
+ break;
+ case CONSTRAINT_TYPE_SIZELIMIT:
+ {
+ bSizeLimitConstraint *data = con->data;
+
+ int togButWidth = 50;
+ int textButWidth = ((width/2)-togButWidth);
+
+ height = 106;
+
+ uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-10, *yco-height, width+40,height-1, NULL, 5.0, 0.0, 12, rb_col, "");
+
+ /* Draw Pairs of LimitToggle+LimitValue */
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, LIMIT_XMIN, B_CONSTRAINT_TEST, "minX", *xco, *yco-28, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum x value");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+togButWidth, *yco-28, (textButWidth-5), 18, &(data->xmin), 0.0001, 1000, 0.1,0.5,"Lowest x value to allow");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, LIMIT_XMAX, B_CONSTRAINT_TEST, "maxX", *xco+(width-(textButWidth-5)-togButWidth), *yco-28, 50, 18, &data->flag, 0, 24, 0, 0, "Use maximum x value");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+(width-textButWidth-5), *yco-28, (textButWidth-5), 18, &(data->xmax), 0.0001, 1000, 0.1,0.5,"Highest x value to allow");
+ uiBlockEndAlign(block);
+
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, LIMIT_YMIN, B_CONSTRAINT_TEST, "minY", *xco, *yco-50, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum y value");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+togButWidth, *yco-50, (textButWidth-5), 18, &(data->ymin), 0.0001, 1000, 0.1,0.5,"Lowest y value to allow");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, LIMIT_YMAX, B_CONSTRAINT_TEST, "maxY", *xco+(width-(textButWidth-5)-togButWidth), *yco-50, 50, 18, &data->flag, 0, 24, 0, 0, "Use maximum y value");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+(width-textButWidth-5), *yco-50, (textButWidth-5), 18, &(data->ymax), 0.0001, 1000, 0.1,0.5,"Highest y value to allow");
+ uiBlockEndAlign(block);
+
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, LIMIT_ZMIN, B_CONSTRAINT_TEST, "minZ", *xco, *yco-72, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum z value");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+togButWidth, *yco-72, (textButWidth-5), 18, &(data->zmin), 0.0001, 1000, 0.1,0.5,"Lowest z value to allow");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, LIMIT_ZMAX, B_CONSTRAINT_TEST, "maxZ", *xco+(width-(textButWidth-5)-togButWidth), *yco-72, 50, 18, &data->flag, 0, 24, 0, 0, "Use maximum z value");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+(width-textButWidth-5), *yco-72, (textButWidth-5), 18, &(data->zmax), 0.0001, 1000, 0.1,0.5,"Highest z value to allow");
+ uiBlockEndAlign(block);
+
+ /* constraint space settings */
+ draw_constraint_spaceselect(block, con, *xco, *yco-100, is_armature_owner(ob), -1);
+ }
+ break;
+ case CONSTRAINT_TYPE_RIGIDBODYJOINT:
+ {
+ bRigidBodyJointConstraint *data = con->data;
+ float extremeLin = 999.f;
+ float extremeAngX = 180.f;
+ float extremeAngY = 45.f;
+ float extremeAngZ = 45.f;
+ int togButWidth = 70;
+ int offsetY = 150;
+ int textButWidth = ((width/2)-togButWidth);
+
+ uiDefButI(block, MENU, B_CONSTRAINT_TEST, "Joint Types%t|Ball%x1|Hinge%x2|Cone Twist%x4|Generic (experimental)%x12",//|Extra Force%x6",
+ *xco, *yco-25, 150, 18, &data->type, 0, 0, 0, 0, "Choose the joint type");
+ height = 140;
+ if (data->type==CONSTRAINT_RB_GENERIC6DOF)
+ height = 270;
+ if (data->type==CONSTRAINT_RB_CONETWIST)
+ height = 200;
+
+ uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-10, *yco-height, width+40,height-1, NULL, 5.0, 0.0, 12, rb_col, "");
+
+ uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "toObject:", *xco, *yco-50, 130, 18, &data->tar, "Child Object");
+ uiDefButBitS(block, TOG, CONSTRAINT_DRAW_PIVOT, B_CONSTRAINT_TEST, "ShowPivot", *xco+135, *yco-50, 130, 18, &data->flag, 0, 24, 0, 0, "Show pivot position and rotation");
+
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Pivot X:", *xco, *yco-75, 130, 18, &data->pivX, -1000, 1000, 100, 0.0, "Offset pivot on X");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Pivot Y:", *xco, *yco-100, 130, 18, &data->pivY, -1000, 1000, 100, 0.0, "Offset pivot on Y");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Pivot Z:", *xco, *yco-125, 130, 18, &data->pivZ, -1000, 1000, 100, 0.0, "Offset pivot on z");
+
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Ax X:", *xco+135, *yco-75, 130, 18, &data->axX, -360, 360, 1500, 0.0, "Rotate pivot on X Axis (in degrees)");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Ax Y:", *xco+135, *yco-100, 130, 18, &data->axY, -360, 360, 1500, 0.0, "Rotate pivot on Y Axis (in degrees)");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "Ax Z:", *xco+135, *yco-125, 130, 18, &data->axZ, -360, 360, 1500, 0.0, "Rotate pivot on Z Axis (in degrees)");
+
+ if (data->type==CONSTRAINT_RB_GENERIC6DOF) {
+ /* Draw Pairs of LimitToggle+LimitValue */
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, 1, B_CONSTRAINT_TEST, "LinMinX", *xco, *yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum x limit");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+togButWidth, *yco-offsetY, (textButWidth-5), 18, &(data->minLimit[0]), -extremeLin, extremeLin, 0.1,0.5,"min x limit");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, 1, B_CONSTRAINT_TEST, "LinMaxX", *xco+(width-(textButWidth-5)-togButWidth), *yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use maximum x limit");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+(width-textButWidth-5), *yco-offsetY, (textButWidth), 18, &(data->maxLimit[0]), -extremeLin, extremeLin, 0.1,0.5,"max x limit");
+ uiBlockEndAlign(block);
+
+ offsetY += 20;
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, 2, B_CONSTRAINT_TEST, "LinMinY", *xco, *yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum y limit");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+togButWidth, *yco-offsetY, (textButWidth-5), 18, &(data->minLimit[1]), -extremeLin, extremeLin, 0.1,0.5,"min y limit");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, 2, B_CONSTRAINT_TEST, "LinMaxY", *xco+(width-(textButWidth-5)-togButWidth), *yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use maximum y limit");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+(width-textButWidth-5), *yco-offsetY, (textButWidth), 18, &(data->maxLimit[1]), -extremeLin, extremeLin, 0.1,0.5,"max y limit");
+ uiBlockEndAlign(block);
+
+ offsetY += 20;
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, 4, B_CONSTRAINT_TEST, "LinMinZ", *xco, *yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum z limit");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+togButWidth, *yco-offsetY, (textButWidth-5), 18, &(data->minLimit[2]), -extremeLin, extremeLin, 0.1,0.5,"min z limit");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, 4, B_CONSTRAINT_TEST, "LinMaxZ", *xco+(width-(textButWidth-5)-togButWidth), *yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use maximum z limit");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+(width-textButWidth-5), *yco-offsetY, (textButWidth), 18, &(data->maxLimit[2]), -extremeLin, extremeLin, 0.1,0.5,"max z limit");
+ uiBlockEndAlign(block);
+ offsetY += 20;
+ }
+ if ((data->type==CONSTRAINT_RB_GENERIC6DOF) || (data->type==CONSTRAINT_RB_CONETWIST)) {
+ /* Draw Pairs of LimitToggle+LimitValue */
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, 8, B_CONSTRAINT_TEST, "AngMinX", *xco, *yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum x limit");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+togButWidth, *yco-offsetY, (textButWidth-5), 18, &(data->minLimit[3]), -extremeAngX, extremeAngX, 0.1,0.5,"min x limit");
+ uiBlockEndAlign(block);
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, 8, B_CONSTRAINT_TEST, "AngMaxX", *xco+(width-(textButWidth-5)-togButWidth), *yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use maximum x limit");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+(width-textButWidth-5), *yco-offsetY, (textButWidth), 18, &(data->maxLimit[3]), -extremeAngX, extremeAngX, 0.1,0.5,"max x limit");
+ uiBlockEndAlign(block);
+
+ offsetY += 20;
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, 16, B_CONSTRAINT_TEST, "AngMinY", *xco, *yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum y limit");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+togButWidth, *yco-offsetY, (textButWidth-5), 18, &(data->minLimit[4]), -extremeAngY, extremeAngY, 0.1,0.5,"min y limit");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, 16, B_CONSTRAINT_TEST, "AngMaxY", *xco+(width-(textButWidth-5)-togButWidth), *yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use maximum y limit");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+(width-textButWidth-5), *yco-offsetY, (textButWidth), 18, &(data->maxLimit[4]), -extremeAngY, extremeAngY, 0.1,0.5,"max y limit");
+ uiBlockEndAlign(block);
+
+ offsetY += 20;
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, 32, B_CONSTRAINT_TEST, "AngMinZ", *xco, *yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum z limit");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+togButWidth, *yco-offsetY, (textButWidth-5), 18, &(data->minLimit[5]), -extremeAngZ, extremeAngZ, 0.1,0.5,"min z limit");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, 32, B_CONSTRAINT_TEST, "AngMaxZ", *xco+(width-(textButWidth-5)-togButWidth), *yco-offsetY, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use maximum z limit");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "", *xco+(width-textButWidth-5), *yco-offsetY, (textButWidth), 18, &(data->maxLimit[5]), -extremeAngZ, extremeAngZ, 0.1,0.5,"max z limit");
+ uiBlockEndAlign(block);
+ }
+ }
+ break;
+ case CONSTRAINT_TYPE_CLAMPTO:
+ {
+ bClampToConstraint *data = con->data;
+
+ height = 90;
+ uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-10, *yco-height, width+40,height-1, NULL, 5.0, 0.0, 12, rb_col, "");
+
+ uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Target:", *xco+65, *yco-24, 50, 18, NULL, 0.0, 0.0, 0.0, 0.0, "");
+
+ /* Draw target parameters */
+ uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-24, 135, 18, &data->tar, "Target Object");
+
+ /* Draw XYZ toggles */
+ uiBlockBeginAlign(block);
+ uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Main Axis:", *xco, *yco-64, 90, 18, NULL, 0.0, 0.0, 0.0, 0.0, "");
+ uiDefButI(block, ROW, B_CONSTRAINT_TEST, "Auto", *xco+100, *yco-64, 50, 18, &data->flag, 12.0, CLAMPTO_AUTO, 0, 0, "Automatically determine main-axis of movement");
+ uiDefButI(block, ROW, B_CONSTRAINT_TEST, "X", *xco+150, *yco-64, 32, 18, &data->flag, 12.0, CLAMPTO_X, 0, 0, "Main axis of movement is x-axis");
+ uiDefButI(block, ROW, B_CONSTRAINT_TEST, "Y", *xco+182, *yco-64, 32, 18, &data->flag, 12.0, CLAMPTO_Y, 0, 0, "Main axis of movement is y-axis");
+ uiDefButI(block, ROW, B_CONSTRAINT_TEST, "Z", *xco+214, *yco-64, 32, 18, &data->flag, 12.0, CLAMPTO_Z, 0, 0, "Main axis of movement is z-axis");
+ uiBlockEndAlign(block);
+
+ /* Extra Options Controlling Behaviour */
+ //uiBlockBeginAlign(block);
+ uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Options:", *xco, *yco-88, 90, 18, NULL, 0.0, 0.0, 0.0, 0.0, "");
+ uiDefButBitI(block, TOG, CLAMPTO_CYCLIC, B_CONSTRAINT_TEST, "Cyclic", *xco+((width/2)), *yco-88,60,19, &data->flag2, 0, 0, 0, 0, "Treat curve as cyclic curve (no clamping to curve bounding box)");
+ //uiBlockEndAlign(block);
+ }
+ break;
+ case CONSTRAINT_TYPE_TRANSFORM:
+ {
+ bTransformConstraint *data = con->data;
+ float fmin, fmax, tmin, tmax;
+
+ height = 178;
+ uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-10, *yco-height, width+40,height-1, NULL, 5.0, 0.0, 12, rb_col, "");
+
+ /* Draw target parameters */
+ uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Target:", *xco+65, *yco-24, 50, 18, NULL, 0.0, 0.0, 0.0, 0.0, "");
+
+ /* Draw target parameters */
+ uiBlockBeginAlign(block);
+ uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_CONSTRAINT_CHANGETARGET, "OB:", *xco+120, *yco-24, 135, 18, &data->tar, "Target Object to use as Parent");
+
+ if (is_armature_target(data->tar)) {
+ but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "BO:", *xco+120, *yco-42,135,18, &data->subtarget, 0, 24, 0, 0, "Subtarget Bone to use as Parent");
+ uiButSetCompleteFunc(but, autocomplete_bone, (void *)data->tar);
+ }
+ else if (is_geom_target(data->tar)) {
+ but= uiDefBut(block, TEX, B_CONSTRAINT_CHANGETARGET, "VG:", *xco+120, *yco-66,150,18, &data->subtarget, 0, 24, 0, 0, "Name of Vertex Group defining 'target' points");
+ uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)data->tar);
+ }
+ else {
+ strcpy(data->subtarget, "");
+ }
+ uiBlockEndAlign(block);
+
+ /* Extrapolate Ranges? */
+ uiDefButBitC(block, TOG, 1, B_CONSTRAINT_TEST, "Extrapolate", *xco, *yco-42,80,19, &data->expo, 0, 0, 0, 0, "Extrapolate ranges");
+
+ /* Draw options for source motion */
+ uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Source:", *xco-10, *yco-62, 50, 18, NULL, 0.0, 0.0, 0.0, 0.0, "");
+
+ /* draw Loc/Rot/Size toggles */
+ uiBlockBeginAlign(block);
+ uiDefButS(block, ROW, B_CONSTRAINT_TEST, "Loc", *xco-5, *yco-82, 45, 18, &data->from, 12.0, 0, 0, 0, "Use Location transform channels from Target");
+ uiDefButS(block, ROW, B_CONSTRAINT_TEST, "Rot", *xco+40, *yco-82, 45, 18, &data->from, 12.0, 1, 0, 0, "Use Rotation transform channels from Target");
+ uiDefButS(block, ROW, B_CONSTRAINT_TEST, "Scale", *xco+85, *yco-82, 45, 18, &data->from, 12.0, 2, 0, 0, "Use Scale transform channels from Target");
+ uiBlockEndAlign(block);
+
+ /* Draw Pairs of Axis: Min/Max Value*/
+ if (data->from == 2) {
+ fmin= 0.0001;
+ fmax= 1000.0;
+ }
+ else if (data->from == 1) {
+ fmin= -360.0;
+ fmax= 360.0;
+ }
+ else {
+ fmin = -1000.0;
+ fmax= 1000.0;
+ }
+
+ uiBlockBeginAlign(block);
+ uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "X:", *xco-10, *yco-107, 30, 18, NULL, 0.0, 0.0, 0.0, 0.0, "");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "min", *xco+20, *yco-107, 55, 18, &data->from_min[0], fmin, fmax, 0, 0, "Bottom of range of x-axis source motion for source->target mapping");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "max", *xco+75, *yco-107, 55, 18, &data->from_max[0], fmin, fmax, 0, 0, "Top of range of x-axis source motion for source->target mapping");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Y:", *xco-10, *yco-127, 30, 18, NULL, 0.0, 0.0, 0.0, 0.0, "");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "min", *xco+20, *yco-127, 55, 18, &data->from_min[1], fmin, fmax, 0, 0, "Bottom of range of y-axis source motion for source->target mapping");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "max", *xco+75, *yco-127, 55, 18, &data->from_max[1], fmin, fmax, 0, 0, "Top of range of y-axis source motion for source->target mapping");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Z:", *xco-10, *yco-147, 30, 18, NULL, 0.0, 0.0, 0.0, 0.0, "");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "min", *xco+20, *yco-147, 55, 18, &data->from_min[2], fmin, fmax, 0, 0, "Bottom of range of z-axis source motion for source->target mapping");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "max", *xco+75, *yco-147, 55, 18, &data->from_max[2], fmin, fmax, 0, 0, "Top of range of z-axis source motion for source->target mapping");
+ uiBlockEndAlign(block);
+
+
+ /* Draw options for target motion */
+ uiDefBut(block, LABEL, B_CONSTRAINT_TEST, "Destination:", *xco+150, *yco-62, 150, 18, NULL, 0.0, 0.0, 0.0, 0.0, "");
+
+ /* draw Loc/Rot/Size toggles */
+ uiBlockBeginAlign(block);
+ uiDefButS(block, ROW, B_CONSTRAINT_TEST, "Loc", *xco+150, *yco-82, 45, 18, &data->to, 12.0, 0, 0, 0, "Use as Location transform");
+ uiDefButS(block, ROW, B_CONSTRAINT_TEST, "Rot", *xco+195, *yco-82, 45, 18, &data->to, 12.0, 1, 0, 0, "Use as Rotation transform");
+ uiDefButS(block, ROW, B_CONSTRAINT_TEST, "Scale", *xco+245, *yco-82, 45, 18, &data->to, 12.0, 2, 0, 0, "Use as Scale transform");
+ uiBlockEndAlign(block);
+
+ /* Draw Pairs of Source-Axis: Min/Max Value*/
+ if (data->to == 2) {
+ tmin= 0.0001;
+ tmax= 1000.0;
+ }
+ else if (data->to == 1) {
+ tmin= -360.0;
+ tmax= 360.0;
+ }
+ else {
+ tmin = -1000.0;
+ tmax= 1000.0;
+ }
+
+ uiBlockBeginAlign(block);
+ uiDefButC(block, MENU, B_CONSTRAINT_TEST, "Axis Mapping%t|X->X%x0|Y->X%x1|Z->X%x2", *xco+150, *yco-107, 40, 18, &data->map[0], 0, 24, 0, 0, "Specify which source axis the x-axis destination uses");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "min", *xco+175, *yco-107, 50, 18, &data->to_min[0], tmin, tmax, 0, 0, "Bottom of range of x-axis destination motion for source->target mapping");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "max", *xco+240, *yco-107, 50, 18, &data->to_max[0], tmin, tmax, 0, 0, "Top of range of x-axis destination motion for source->target mapping");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButC(block, MENU, B_CONSTRAINT_TEST, "Axis Mapping%t|X->Y%x0|Y->Y%x1|Z->Y%x2", *xco+150, *yco-127, 40, 18, &data->map[1], 0, 24, 0, 0, "Specify which source axis the y-axis destination uses");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "min", *xco+175, *yco-127, 50, 18, &data->to_min[1], tmin, tmax, 0, 0, "Bottom of range of y-axis destination motion for source->target mapping");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "max", *xco+240, *yco-127, 50, 18, &data->to_max[1], tmin, tmax, 0, 0, "Top of range of y-axis destination motion for source->target mapping");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButC(block, MENU, B_CONSTRAINT_TEST, "Axis Mapping%t|X->Z%x0|Y->Z%x1|Z->Z%x2", *xco+150, *yco-147, 40, 18, &data->map[2], 0, 24, 0, 0, "Specify which source axis the z-axis destination uses");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "min", *xco+175, *yco-147, 50, 18, &data->to_min[2], tmin, tmax, 0, 0, "Bottom of range of z-axis destination motion for source->target mapping");
+ uiDefButF(block, NUM, B_CONSTRAINT_TEST, "max", *xco+240, *yco-147, 50, 18, &data->to_max[2], tmin, tmax, 0, 0, "Top of range of z-axis destination motion for source->target mapping");
+ uiBlockEndAlign(block);
+
+ /* constraint space settings */
+ draw_constraint_spaceselect(block, con, *xco, *yco-170, is_armature_owner(ob), is_armature_target(data->tar));
+ }
+ break;
+ case CONSTRAINT_TYPE_NULL:
+ {
+ height = 17;
+ uiDefBut(block, ROUNDBOX, B_DIFF, "", *xco-10, *yco-height, width+40,height-1, NULL, 5.0, 0.0, 12, rb_col, "");
+ }
+ break;
+ default:
+ height = 0;
+ break;
+ }
+
+ (*yco)-=(24+height);
+ }
+
+ if (ELEM(con->type, CONSTRAINT_TYPE_NULL, CONSTRAINT_TYPE_RIGIDBODYJOINT)==0) {
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUMSLI, B_CONSTRAINT_INF, "Influence ", *xco, *yco, 197, 20, &(con->enforce), 0.0, 1.0, 0.0, 0.0, "Amount of influence this constraint will have on the final solution");
+ but = uiDefBut(block, BUT, B_CONSTRAINT_TEST, "Show", *xco+200, *yco, 45, 20, 0, 0.0, 1.0, 0.0, 0.0, "Show constraint's ipo in the Ipo window, adds a channel if not there");
+ /* If this is on an object or bone, add ipo channel the constraint */
+ uiButSetFunc (but, enable_constraint_ipo_func, ob, con);
+ but = uiDefBut(block, BUT, B_CONSTRAINT_TEST, "Key", *xco+245, *yco, 40, 20, 0, 0.0, 1.0, 0.0, 0.0, "Add an influence keyframe to the constraint");
+ /* Add a keyframe to the influence IPO */
+ uiButSetFunc (but, add_influence_key_to_constraint_func, ob, con);
+ uiBlockEndAlign(block);
+ (*yco)-=24;
+ }
+ else {
+ (*yco)-=3;
+ }
+}
+
+static uiBlock *add_constraintmenu(void *arg_unused)
+{
+ Object *ob= OBACT;
+ uiBlock *block;
+ ListBase *conlist;
+ short yco= 0;
+
+ conlist = get_active_constraints(ob);
+
+ block= uiNewBlock(&curarea->uiblocks, "add_constraintmenu", UI_EMBOSSP, UI_HELV, curarea->win);
+
+ uiDefBut(block, BUTM, B_CONSTRAINT_ADD_CHILDOF, "Child Of", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefBut(block, BUTM, B_CONSTRAINT_ADD_TRANSFORM, "Transformation", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, 120, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefBut(block, BUTM, B_CONSTRAINT_ADD_LOCLIKE, "Copy Location", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefBut(block, BUTM, B_CONSTRAINT_ADD_ROTLIKE, "Copy Rotation", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefBut(block, BUTM, B_CONSTRAINT_ADD_SIZELIKE, "Copy Scale", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, 120, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefBut(block, BUTM, B_CONSTRAINT_ADD_LOCLIMIT, "Limit Location", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefBut(block, BUTM, B_CONSTRAINT_ADD_ROTLIMIT, "Limit Rotation", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefBut(block, BUTM, B_CONSTRAINT_ADD_SIZELIMIT, "Limit Scale", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, 120, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefBut(block, BUTM, B_CONSTRAINT_ADD_TRACKTO, "Track To", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefBut(block, BUTM, B_CONSTRAINT_ADD_MINMAX, "Floor", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefBut(block, BUTM, B_CONSTRAINT_ADD_LOCKTRACK, "Locked Track", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefBut(block, BUTM, B_CONSTRAINT_ADD_FOLLOWPATH, "Follow Path", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, 120, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefBut(block, BUTM, B_CONSTRAINT_ADD_CLAMPTO, "Clamp To", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefBut(block, BUTM, B_CONSTRAINT_ADD_STRETCHTO, "Stretch To", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, "");
+
+ uiDefBut(block, BUTM, B_CONSTRAINT_ADD_RIGIDBODYJOINT, "Rigid Body Joint", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, "");//rcruiz
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, 120, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ if (ob->flag & OB_POSEMODE) {
+ uiDefBut(block, BUTM, B_CONSTRAINT_ADD_KINEMATIC, "IK Solver", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, "");
+ }
+ uiDefBut(block, BUTM, B_CONSTRAINT_ADD_ACTION, "Action", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, 120, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefBut(block, BUTM, B_CONSTRAINT_ADD_PYTHON, "Script", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, 120, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefBut(block, BUTM, B_CONSTRAINT_ADD_NULL, "Null", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, "");
+
+
+ uiTextBoundsBlock(block, 50);
+ uiBlockSetDirection(block, UI_DOWN);
+
+ return block;
+}
+
+void do_constraintbuts(unsigned short event)
+{
+ Object *ob= OBACT;
+ bConstraint *con;
+
+ switch(event) {
+ case B_CONSTRAINT_TEST:
+ break; // no handling
+ case B_CONSTRAINT_INF:
+ /* influence; do not execute actions for 1 dag_flush */
+ if (ob->pose)
+ ob->pose->flag |= (POSE_LOCKED|POSE_DO_UNLOCK);
+
+ case B_CONSTRAINT_CHANGETARGET:
+ if (ob->pose) ob->pose->flag |= POSE_RECALC; // checks & sorts pose channels
+ DAG_scene_sort(G.scene);
+ break;
+
+ case B_CONSTRAINT_ADD_NULL:
+ {
+ con = add_new_constraint(CONSTRAINT_TYPE_NULL);
+ add_constraint_to_active(ob, con);
+
+ BIF_undo_push("Add constraint");
+ }
+ break;
+ case B_CONSTRAINT_ADD_PYTHON:
+ {
+ con = add_new_constraint(CONSTRAINT_TYPE_PYTHON);
+ add_constraint_to_active(ob, con);
+
+ BIF_undo_push("Add constraint");
+ }
+ break;
+ case B_CONSTRAINT_ADD_KINEMATIC:
+ {
+ con = add_new_constraint(CONSTRAINT_TYPE_KINEMATIC);
+ add_constraint_to_active(ob, con);
+
+ BIF_undo_push("Add constraint");
+ }
+ break;
+ case B_CONSTRAINT_ADD_CHILDOF:
+ {
+ con= add_new_constraint(CONSTRAINT_TYPE_CHILDOF);
+ add_constraint_to_active(ob, con);
+
+ /* if this constraint is being added to a posechannel, make sure
+ * the constraint gets evaluated in pose-space
+ */
+ if (ob->flag & OB_POSEMODE) {
+ con->ownspace = CONSTRAINT_SPACE_POSE;
+ con->flag |= CONSTRAINT_SPACEONCE;
+ }
+
+ BIF_undo_push("Add constraint");
+ }
+ break;
+ case B_CONSTRAINT_ADD_TRACKTO:
+ {
+ con = add_new_constraint(CONSTRAINT_TYPE_TRACKTO);
+ add_constraint_to_active(ob, con);
+
+ BIF_undo_push("Add constraint");
+ }
+ break;
+ case B_CONSTRAINT_ADD_MINMAX:
+ {
+ con = add_new_constraint(CONSTRAINT_TYPE_MINMAX);
+ add_constraint_to_active(ob, con);
+
+ BIF_undo_push("Add constraint");
+ }
+ break;
+ case B_CONSTRAINT_ADD_ROTLIKE:
+ {
+ con = add_new_constraint(CONSTRAINT_TYPE_ROTLIKE);
+ add_constraint_to_active(ob, con);
+
+ BIF_undo_push("Add constraint");
+ }
+ break;
+ case B_CONSTRAINT_ADD_LOCLIKE:
+ {
+ con = add_new_constraint(CONSTRAINT_TYPE_LOCLIKE);
+ add_constraint_to_active(ob, con);
+
+ BIF_undo_push("Add constraint");
+ }
+ break;
+ case B_CONSTRAINT_ADD_SIZELIKE:
+ {
+ con = add_new_constraint(CONSTRAINT_TYPE_SIZELIKE);
+ add_constraint_to_active(ob, con);
+
+ BIF_undo_push("Add constraint");
+ }
+ break;
+ case B_CONSTRAINT_ADD_ACTION:
+ {
+ con = add_new_constraint(CONSTRAINT_TYPE_ACTION);
+ add_constraint_to_active(ob, con);
+
+ BIF_undo_push("Add constraint");
+ }
+ break;
+ case B_CONSTRAINT_ADD_LOCKTRACK:
+ {
+ con = add_new_constraint(CONSTRAINT_TYPE_LOCKTRACK);
+ add_constraint_to_active(ob, con);
+
+ BIF_undo_push("Add constraint");
+ }
+ break;
+ case B_CONSTRAINT_ADD_FOLLOWPATH:
+ {
+ con = add_new_constraint(CONSTRAINT_TYPE_FOLLOWPATH);
+ add_constraint_to_active(ob, con);
+
+ BIF_undo_push("Add constraint");
+ }
+ break;
+ case B_CONSTRAINT_ADD_STRETCHTO:
+ {
+ con = add_new_constraint(CONSTRAINT_TYPE_STRETCHTO);
+ add_constraint_to_active(ob, con);
+
+ BIF_undo_push("Add constraint");
+ }
+ break;
+ case B_CONSTRAINT_ADD_LOCLIMIT:
+ {
+ con = add_new_constraint(CONSTRAINT_TYPE_LOCLIMIT);
+ add_constraint_to_active(ob, con);
+
+ BIF_undo_push("Add constraint");
+ }
+ break;
+ case B_CONSTRAINT_ADD_ROTLIMIT:
+ {
+ con = add_new_constraint(CONSTRAINT_TYPE_ROTLIMIT);
+ add_constraint_to_active(ob, con);
+
+ BIF_undo_push("Add constraint");
+ }
+ break;
+ case B_CONSTRAINT_ADD_SIZELIMIT:
+ {
+ con = add_new_constraint(CONSTRAINT_TYPE_SIZELIMIT);
+ add_constraint_to_active(ob, con);
+
+ BIF_undo_push("Add constraint");
+ }
+ break;
+ case B_CONSTRAINT_ADD_RIGIDBODYJOINT:
+ {
+ bRigidBodyJointConstraint *data;
+ Base *base_iter;
+
+ con = add_new_constraint(CONSTRAINT_TYPE_RIGIDBODYJOINT);
+ add_constraint_to_active(ob, con);
+
+ /* set selected first object as target - moved from new_constraint_data */
+ data = (bRigidBodyJointConstraint*)con->data;
+ base_iter = G.scene->base.first;
+ while ( base_iter && !data->tar ) {
+ if( ( ( base_iter->flag & SELECT ) &&
+// ( base_iter->lay & G.vd->lay ) ) &&
+ ( base_iter != G.scene->basact ) ))
+ {
+ data->tar=base_iter->object;
+ break;
+ }
+ base_iter = base_iter->next;
+ }
+
+ BIF_undo_push("Add constraint");
+ }
+ break;
+ case B_CONSTRAINT_ADD_CLAMPTO:
+ {
+ con = add_new_constraint(CONSTRAINT_TYPE_CLAMPTO);
+ add_constraint_to_active(ob, con);
+
+ BIF_undo_push("Add constraint");
+ }
+ break;
+ case B_CONSTRAINT_ADD_TRANSFORM:
+ {
+ con = add_new_constraint(CONSTRAINT_TYPE_TRANSFORM);
+ add_constraint_to_active(ob, con);
+
+ BIF_undo_push("Add constraint");
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ object_test_constraints(ob);
+
+ if(ob->pose) update_pose_constraint_flags(ob->pose);
+
+ if(ob->type==OB_ARMATURE) DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA|OB_RECALC_OB);
+ else DAG_object_flush_update(G.scene, ob, OB_RECALC_OB);
+
+ allqueue (REDRAWVIEW3D, 0);
+ allqueue (REDRAWBUTSOBJECT, 0);
+}
+
+void softbody_bake(Object *ob)
+{
+ Base *base;
+ SoftBody *sb;
+ ScrArea *sa;
+ float frameleno= G.scene->r.framelen;
+ int cfrao= CFRA, sfra=100000, efra=0, didbreak =0;
+
+
+ G.scene->r.framelen= 1.0; // baking has to be in uncorrected time
+ sbSetInterruptCallBack(blender_test_break); // make softbody module ESC aware
+ G.afbreek=0; // init global break system
+
+ if(ob) {
+ sb= ob->soft;
+ sfra= MIN2(sfra, sb->sfra);
+ efra= MAX2(efra, sb->efra);
+ sbObjectToSoftbody(ob); // put softbody in restposition, free bake
+ ob->softflag |= OB_SB_BAKEDO;
+ }
+ else {
+ for(base=G.scene->base.first; base; base= base->next) {
+ if(TESTBASELIB(base)) {
+ if(base->object->soft) {
+ sb= base->object->soft;
+ sfra= MIN2(sfra, sb->sfra);
+ efra= MAX2(efra, sb->efra);
+ sbObjectToSoftbody(base->object); // put softbody in restposition, free bake
+ base->object->softflag |= OB_SB_BAKEDO;
+ }
+ }
+ }
+ }
+
+ CFRA= sfra;
+ update_for_newframe_muted(); // put everything on this frame
+
+ curarea->win_swap= 0; // clean swapbuffers
+
+ for(; CFRA <= efra; CFRA++) {
+ set_timecursor(CFRA);
+
+ update_for_newframe_muted();
+
+ for(sa= G.curscreen->areabase.first; sa; sa= sa->next) {
+ if(sa->spacetype == SPACE_VIEW3D) {
+ scrarea_do_windraw(sa);
+ }
+ }
+ screen_swapbuffers();
+ //blender_test_break() has a granularity of 10 ms, who cares .. baking the unit cube is kinda boring
+ if (blender_test_break()){
+ didbreak = 1;
+ break;
+ }
+
+ }
+ if((didbreak)&&(G.qual!=LR_SHIFTKEY)) {
+ if(ob)
+ sbObjectToSoftbody(ob); // free bake
+ else {
+ for(base=G.scene->base.first; base; base= base->next) {
+ if(TESTBASELIB(base)) {
+ if(base->object->soft) {
+ sbObjectToSoftbody(base->object); // free bake
+ }
+ }
+ }
+ }
+ }
+
+ /* restore */
+ waitcursor(0);
+ sbSetInterruptCallBack(NULL); // softbody module won't ESC
+ G.afbreek=0; // reset global break system
+
+ if(ob)
+ ob->softflag &= ~OB_SB_BAKEDO;
+ else {
+ for(base=G.scene->base.first; base; base= base->next)
+ if(TESTBASELIB(base))
+ if(base->object->soft)
+ base->object->softflag &= ~OB_SB_BAKEDO;
+ }
+
+ CFRA= cfrao;
+ G.scene->r.framelen= frameleno;
+ update_for_newframe_muted();
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSOBJECT, 0);
+}
+
+// store processed path & file prefix for fluidsim bake directory
+void fluidsimFilesel(char *selection)
+{
+ Object *ob = OBACT;
+ char srcDir[FILE_MAXDIR+FILE_MAXFILE], srcFile[FILE_MAXFILE];
+ char prefix[FILE_MAXFILE];
+ char *srch, *srchSub, *srchExt, *lastFound;
+ int isElbeemSurf = 0;
+
+ // make prefix
+ strcpy(srcDir, selection);
+ BLI_splitdirstring(srcDir, srcFile);
+ strcpy(prefix, srcFile);
+ // check if this is a previously generated surface mesh file
+ srch = strstr(prefix, "fluidsurface_");
+ // TODO search from back...
+ if(srch) {
+ srchSub = strstr(prefix,"_preview_");
+ if(!srchSub) srchSub = strstr(prefix,"_final_");
+ srchExt = strstr(prefix,".gz.bobj");
+ if(!srchExt) srchExt = strstr(prefix,".bobj");
+ if(srchSub && srchExt) {
+ *srch = '\0';
+ isElbeemSurf = 1;
+ }
+ }
+ if(!isElbeemSurf) {
+ // try to remove suffix
+ lastFound = NULL;
+ srch = strchr(prefix, '.'); // search last . from extension
+ while(srch) {
+ lastFound = srch;
+ if(srch) {
+ srch++;
+ srch = strchr(srch, '.');
+ }
+ }
+ if(lastFound) {
+ *lastFound = '\0';
+ }
+ }
+
+ if(ob->fluidsimSettings) {
+ strcpy(ob->fluidsimSettings->surfdataPath, srcDir);
+ //not necessary? strcat(ob->fluidsimSettings->surfdataPath, "/");
+ strcat(ob->fluidsimSettings->surfdataPath, prefix);
+
+ // redraw view & buttons...
+ allqueue(REDRAWBUTSOBJECT, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ }
+}
+
+void do_object_panels(unsigned short event)
+{
+ Object *ob;
+ Effect *eff;
+
+ ob= OBACT;
+ if(ob==NULL)
+ return;
+
+ switch(event) {
+ case B_TRACKBUTS:
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_OB);
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+ case B_RECALCPATH:
+ DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+ case B_DUPLI_FRAME:
+ ob->transflag &= ~(OB_DUPLIVERTS|OB_DUPLIFACES|OB_DUPLIGROUP);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSOBJECT, 0);
+ break;
+ case B_DUPLI_VERTS:
+ ob->transflag &= ~(OB_DUPLIFRAMES|OB_DUPLIFACES|OB_DUPLIGROUP);
+ DAG_scene_sort(G.scene);
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSOBJECT, 0);
+ break;
+ case B_DUPLI_FACES:
+ ob->transflag &= ~(OB_DUPLIVERTS|OB_DUPLIFRAMES|OB_DUPLIGROUP);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSOBJECT, 0);
+ break;
+ case B_DUPLI_GROUP:
+ ob->transflag &= ~(OB_DUPLIVERTS|OB_DUPLIFRAMES|OB_DUPLIFACES);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSOBJECT, 0);
+ break;
+
+ case B_PRINTSPEED:
+ {
+ float vec[3];
+ CFRA++;
+ do_ob_ipo(ob);
+ where_is_object(ob);
+ VECCOPY(vec, ob->obmat[3]);
+ CFRA--;
+ do_ob_ipo(ob);
+ where_is_object(ob);
+ VecSubf(vec, vec, ob->obmat[3]);
+ prspeed= Normalize(vec);
+ scrarea_queue_winredraw(curarea);
+ }
+ break;
+ case B_PRINTLEN:
+ if(ob->type==OB_CURVE) {
+ Curve *cu=ob->data;
+
+ if(cu->path) prlen= cu->path->totdist; else prlen= -1.0;
+ scrarea_queue_winredraw(curarea);
+ }
+ break;
+ case B_RELKEY:
+ allspace(REMAKEIPO, 0);
+ allqueue(REDRAWBUTSOBJECT, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWIPO, 0);
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ break;
+ case B_CURVECHECK:
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+
+ case B_SOFTBODY_CHANGE:
+ ob->softflag |= OB_SB_REDO;
+ allqueue(REDRAWBUTSOBJECT, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+ case B_SOFTBODY_DEL_VG:
+ if(ob->soft) {
+ ob->soft->vertgroup= 0;
+ ob->softflag |= OB_SB_REDO;
+ allqueue(REDRAWBUTSOBJECT, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ break;
+ case B_SOFTBODY_BAKE:
+ if(ob->soft) softbody_bake(ob);
+ break;
+ case B_SOFTBODY_BAKE_FREE:
+ if(ob->soft) sbObjectToSoftbody(ob);
+ allqueue(REDRAWBUTSOBJECT, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+ case B_FLUIDSIM_BAKE:
+ /* write config files (currently no simulation) */
+ fluidsimBake(ob);
+ break;
+ case B_FLUIDSIM_MAKEPART:
+ {
+ PartEff *paf= NULL;
+ /* prepare fluidsim particle display */
+ // simplified delete effect, create new - recalc some particles...
+ if(ob==NULL || ob->type!=OB_MESH) break;
+ ob->fluidsimSettings->type = 0;
+ // reset type, and init particle system once normally
+ paf= give_parteff(ob);
+ if( (BLI_countlist(&ob->effect)<MAX_EFFECT) &&
+ (!paf)) {
+ // create new entry
+ copy_act_effect(ob); DAG_scene_sort(G.scene); }
+ paf = give_parteff(ob);
+ if(paf) {
+ paf->totpart = 1000; paf->sta = paf->end = 1.0; // generate some particles...
+ build_particle_system(ob);
+ ob->fluidsimSettings->type = OB_FLUIDSIM_PARTICLE;
+ }
+ }
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSOBJECT, 0);
+ break;
+ case B_FLUIDSIM_SELDIR:
+ {
+ ScrArea *sa = closest_bigger_area();
+ /* choose dir for surface files */
+ areawinset(sa->win);
+ activate_fileselect(FILE_SPECIAL, "Select Directory", ob->fluidsimSettings->surfdataPath, fluidsimFilesel);
+ }
+ break;
+ case B_FLUIDSIM_FORCEREDRAW:
+ /* force redraw */
+ allqueue(REDRAWBUTSOBJECT, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ break;
+ case B_GROUP_RELINK:
+ group_relink_nla_objects(ob);
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+
+ case B_OBJECT_IPOFLAG:
+ if(ob->ipo) ob->ipo->showkey= (ob->ipoflag & OB_DRAWKEY)?1:0;
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+
+ default:
+ if(event>=B_SELEFFECT && event<B_SELEFFECT+MAX_EFFECT) {
+ int a=B_SELEFFECT;
+
+ eff= ob->effect.first;
+ while(eff) {
+ if(event==a) eff->flag |= SELECT;
+ else eff->flag &= ~SELECT;
+
+ a++;
+ eff= eff->next;
+ }
+ allqueue(REDRAWBUTSOBJECT, 0);
+ }
+ }
+
+}
+
+static void do_add_groupmenu(void *arg, int event)
+{
+ Object *ob= OBACT;
+
+ if(ob) {
+
+ if(event== -1) {
+ Group *group= add_group( "Group" );
+ add_to_group(group, ob);
+ }
+ else
+ add_to_group(BLI_findlink(&G.main->group, event), ob);
+
+ ob->flag |= OB_FROMGROUP;
+ BASACT->flag |= OB_FROMGROUP;
+ allqueue(REDRAWBUTSOBJECT, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+}
+
+static uiBlock *add_groupmenu(void *arg_unused)
+{
+ uiBlock *block;
+ Group *group;
+ short yco= 0;
+ char str[32];
+
+ block= uiNewBlock(&curarea->uiblocks, "add_constraintmenu", UI_EMBOSSP, UI_HELV, curarea->win);
+ uiBlockSetButmFunc(block, do_add_groupmenu, NULL);
+
+ uiDefBut(block, BUTM, B_NOP, "ADD NEW", 0, 20, 160, 19, NULL, 0.0, 0.0, 1, -1, "");
+ for(group= G.main->group.first; group; group= group->id.next, yco++) {
+ if(group->id.lib) strcpy(str, "L ");
+ else strcpy(str, " ");
+ strcat(str, group->id.name+2);
+ uiDefBut(block, BUTM, B_NOP, str, 0, -20*yco, 160, 19, NULL, 0.0, 0.0, 1, yco, "");
+ }
+
+ uiTextBoundsBlock(block, 50);
+ uiBlockSetDirection(block, UI_DOWN);
+
+ return block;
+}
+
+static void group_ob_rem(void *gr_v, void *ob_v)
+{
+ Object *ob= OBACT;
+
+ rem_from_group(gr_v, ob);
+ if(find_group(ob)==NULL) {
+ ob->flag &= ~OB_FROMGROUP;
+ BASACT->flag &= ~OB_FROMGROUP;
+ }
+ allqueue(REDRAWBUTSOBJECT, 0);
+ allqueue(REDRAWVIEW3D, 0);
+
+}
+
+static void group_local(void *gr_v, void *unused)
+{
+ Group *group= gr_v;
+
+ group->id.lib= NULL;
+
+ allqueue(REDRAWBUTSOBJECT, 0);
+ allqueue(REDRAWVIEW3D, 0);
+
+}
+
+static void object_panel_object(Object *ob)
+{
+ uiBlock *block;
+ uiBut *but;
+ Group *group;
+ int a, xco, yco=0;
+ short dx= 33, dy= 30;
+
+ block= uiNewBlock(&curarea->uiblocks, "object_panel_object", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Object and Links", "Object", 0, 0, 318, 204)==0) return;
+
+ uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
+
+ /* object name */
+ uiBlockSetCol(block, TH_BUT_SETTING2);
+ xco= std_libbuttons(block, 10, 180, 0, NULL, 0, ID_OB, 0, &ob->id, NULL, &(G.buts->menunr), B_OBALONE, B_OBLOCAL, 0, 0, B_KEEPDATA);
+ uiBlockSetCol(block, TH_AUTO);
+
+ /* parent */
+ uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_OBJECTPANELPARENT, "Par:", xco+5, 180, 305-xco, 20, &ob->parent, "Parent Object");
+
+ /* TODO, check for ob->id.lib */
+ but = uiDefButS(block, NUM, B_NOP, "PassIndex:", xco+5, 150, 305-xco, 20, &ob->index, 0.0, 1000.0, 0, 0, "Index # for the IndexOB render pass.");
+
+ uiDefBlockBut(block, add_groupmenu, NULL, "Add to Group", 10,150,150,20, "Add Object to a new Group");
+
+ /* all groups */
+ for(group= G.main->group.first; group; group= group->id.next) {
+ if(object_in_group(ob, group)) {
+ xco= 160;
+
+ uiBlockBeginAlign(block);
+ but = uiDefBut(block, TEX, B_IDNAME, "GR:", 10, 120-yco, 150, 20, group->id.name+2, 0.0, 21.0, 0, 0, "Displays Group name. Click to change.");
+ uiButSetFunc(but, test_idbutton_cb, group->id.name, NULL);
+
+ if(group->id.lib) {
+ but= uiDefIconBut(block, BUT, B_NOP, ICON_PARLIB, 160, 120-yco, 20, 20, NULL, 0.0, 0.0, 0.0, 0.0, "Make Group local");
+ uiButSetFunc(but, group_local, group, NULL);
+ xco= 180;
+ }
+ but = uiDefIconBut(block, BUT, B_NOP, VICON_X, xco, 120-yco, 20, 20, NULL, 0.0, 0.0, 0.0, 0.0, "Remove Group membership");
+ uiButSetFunc(but, group_ob_rem, group, ob);
+
+ yco+= 20;
+ xco= 10;
+
+ /* layers */
+ uiBlockBeginAlign(block);
+ for(a=0; a<5; a++)
+ uiDefButBitI(block, TOG, 1<<a, REDRAWVIEW3D, "", (short)(xco+a*(dx/2)), 120-yco, (short)(dx/2), (short)(dy/2), (int *)&(group->layer), 0, 0, 0, 0, "");
+ for(a=0; a<5; a++)
+ uiDefButBitI(block, TOG, 1<<(a+10), REDRAWVIEW3D, "", (short)(xco+a*(dx/2)), 105-yco, (short)(dx/2), (short)(dy/2), (int *)&(group->layer), 0, 0, 0, 0, "");
+
+ xco+= 7;
+ uiBlockBeginAlign(block);
+ for(a=5; a<10; a++)
+ uiDefButBitI(block, TOG, 1<<a, REDRAWVIEW3D, "", (short)(xco+a*(dx/2)), 120-yco, (short)(dx/2), (short)(dy/2), (int *)&(group->layer), 0, 0, 0, 0, "");
+ for(a=5; a<10; a++)
+ uiDefButBitI(block, TOG, 1<<(a+10), REDRAWVIEW3D, "", (short)(xco+a*(dx/2)), 105-yco, (short)(dx/2), (short)(dy/2), (int *)&(group->layer), 0, 0, 0, 0, "");
+
+ uiBlockEndAlign(block);
+
+ yco+= 40;
+ }
+ }
+
+ if(120-yco < -10)
+ uiNewPanelHeight(block, 204 - (120-yco));
+}
+
+static void object_panel_anim(Object *ob)
+{
+ uiBlock *block;
+ char str[32];
+
+ block= uiNewBlock(&curarea->uiblocks, "object_panel_anim", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Anim settings", "Object", 320, 0, 318, 204)==0) return;
+
+ uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, ROW,B_TRACKBUTS,"TrackX", 24,180,59,19, &ob->trackflag, 12.0, 0.0, 0, 0, "Specify the axis that points to another object");
+ uiDefButS(block, ROW,B_TRACKBUTS,"Y", 85,180,19,19, &ob->trackflag, 12.0, 1.0, 0, 0, "Specify the axis that points to another object");
+ uiDefButS(block, ROW,B_TRACKBUTS,"Z", 104,180,19,19, &ob->trackflag, 12.0, 2.0, 0, 0, "Specify the axis that points to another object");
+ uiDefButS(block, ROW,B_TRACKBUTS,"-X", 124,180,24,19, &ob->trackflag, 12.0, 3.0, 0, 0, "Specify the axis that points to another object");
+ uiDefButS(block, ROW,B_TRACKBUTS,"-Y", 150,180,24,19, &ob->trackflag, 12.0, 4.0, 0, 0, "Specify the axis that points to another object");
+ uiDefButS(block, ROW,B_TRACKBUTS,"-Z", 178,180,24,19, &ob->trackflag, 12.0, 5.0, 0, 0, "Specify the axis that points to another object");
+ uiBlockBeginAlign(block);
+ uiDefButS(block, ROW,REDRAWVIEW3D,"UpX", 226,180,45,19, &ob->upflag, 13.0, 0.0, 0, 0, "Specify the axis that points up");
+ uiDefButS(block, ROW,REDRAWVIEW3D,"Y", 274,180,20,19, &ob->upflag, 13.0, 1.0, 0, 0, "Specify the axis that points up");
+ uiDefButS(block, ROW,REDRAWVIEW3D,"Z", 298,180,19,19, &ob->upflag, 13.0, 2.0, 0, 0, "Specify the axis that points up");
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, OB_DRAWKEY, B_OBJECT_IPOFLAG, "Draw Key", 24,155,71,19, &ob->ipoflag, 0, 0, 0, 0, "Draw object as key position");
+ uiDefButBitS(block, TOG, OB_DRAWKEYSEL, REDRAWVIEW3D, "Draw Key Sel", 97,155,81,19, &ob->ipoflag, 0, 0, 0, 0, "Limit the drawing of object keys");
+ uiDefButBitS(block, TOG, OB_POWERTRACK, REDRAWVIEW3D, "Powertrack", 180,155,78,19, &ob->transflag, 0, 0, 0, 0, "Switch objects rotation off");
+ uiDefButBitS(block, TOG, PARSLOW, 0, "SlowPar", 260,155,56,19, &ob->partype, 0, 0, 0, 0, "Create a delay in the parent relationship");
+ uiBlockBeginAlign(block);
+
+ uiDefButBitS(block, TOG, OB_DUPLIFRAMES, B_DUPLI_FRAME, "DupliFrames", 24,130,95,20, &ob->transflag, 0, 0, 0, 0, "Make copy of object for every frame");
+ uiDefButBitS(block, TOG, OB_DUPLIVERTS, B_DUPLI_VERTS, "DupliVerts", 119,130,95,20, &ob->transflag, 0, 0, 0, 0, "Duplicate child objects on all vertices");
+ uiDefButBitS(block, TOG, OB_DUPLIFACES, B_DUPLI_FACES, "DupliFaces", 214,130,102,20, &ob->transflag, 0, 0, 0, 0, "Duplicate child objects on all faces");
+ uiDefButBitS(block, TOG, OB_DUPLIGROUP, B_DUPLI_GROUP, "DupliGroup", 24,110,150,20, &ob->transflag, 0, 0, 0, 0, "Enable group instancing");
+ if(ob->transflag & OB_DUPLIFRAMES)
+ uiDefButBitS(block, TOG, OB_DUPLINOSPEED, REDRAWVIEW3D, "No Speed", 174,110,142,20, &ob->transflag, 0, 0, 0, 0, "Set dupliframes to still, regardless of frame");
+ else if(ob->transflag & OB_DUPLIVERTS)
+ uiDefButBitS(block, TOG, OB_DUPLIROT, REDRAWVIEW3D, "Rot", 174,110,142,20, &ob->transflag, 0, 0, 0, 0, "Rotate dupli according to vertex normal");
+ else if(ob->transflag & OB_DUPLIFACES)
+ uiDefButBitS(block, TOG, OB_DUPLIFACES_SCALE, REDRAWVIEW3D, "Scale", 174,110,142,20, &ob->transflag, 0, 0, 0, 0, "Scale dupli based on face size");
+ else
+ uiDefIDPoinBut(block, test_grouppoin_but, ID_GR, B_GROUP_RELINK, "GR:", 174,110,142,20, &ob->dup_group, "Instance an existing group");
+
+ uiBlockBeginAlign(block);
+ /* DupSta and DupEnd are both shorts, so the maxframe is greater then their range
+ just limit the buttons to the max short */
+ uiDefButI(block, NUM, REDRAWVIEW3D, "DupSta:", 24,85,141,19, &ob->dupsta, 1.0, 32767, 0, 0, "Specify startframe for Dupliframes");
+ uiDefButI(block, NUM, REDRAWVIEW3D, "DupOn:", 170,85,146,19, &ob->dupon, 1.0, 1500.0, 0, 0, "Specify the number of frames to use between DupOff frames");
+ uiDefButI(block, NUM, REDRAWVIEW3D, "DupEnd", 24,65,140,19, &ob->dupend, 1.0, 32767, 0, 0, "Specify endframe for Dupliframes");
+ uiDefButI(block, NUM, REDRAWVIEW3D, "DupOff", 171,65,145,19, &ob->dupoff, 0.0, 1500.0, 0, 0, "Specify recurring frames to exclude from the Dupliframes");
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, OB_OFFS_OB, REDRAWALL, "Offs Ob", 24,35,56,20, &ob->ipoflag, 0, 0, 0, 0, "Not functional at the moment!");
+ uiDefButBitS(block, TOG, OB_OFFS_PARENT, REDRAWALL, "Offs Par", 82,35,56,20 , &ob->ipoflag, 0, 0, 0, 0, "Let the timeoffset work on the parent");
+ uiDefButBitS(block, TOG, OB_OFFS_PARTICLE, REDRAWALL, "Offs Particle", 140,35,103,20, &ob->ipoflag, 0, 0, 0, 0, "Let the timeoffset work on the particle effect");
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, REDRAWALL, "TimeOffset:", 24,10,115,20, &ob->sf, -MAXFRAMEF, MAXFRAMEF, 100, 0, "Specify an offset in frames");
+ uiDefBut(block, BUT, B_AUTOTIMEOFS, "Automatic Time", 139,10,104,20, 0, 0, 0, 0, 0, "Generate automatic timeoffset values for all selected frames");
+ uiDefBut(block, BUT, B_PRINTSPEED, "PrSpeed", 248,10,67,20, 0, 0, 0, 0, 0, "Print objectspeed");
+ uiBlockEndAlign(block);
+
+ sprintf(str, "%.4f", prspeed);
+ uiDefBut(block, LABEL, 0, str, 247,35,63,31, NULL, 1.0, 0, 0, 0, "");
+
+}
+
+static void object_panel_draw(Object *ob)
+{
+ uiBlock *block;
+ int xco, a, dx, dy;
+
+ block= uiNewBlock(&curarea->uiblocks, "object_panel_draw", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Draw", "Object", 640, 0, 318, 204)==0) return;
+
+ uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
+
+ /* LAYERS */
+ xco= 120;
+ dx= 35;
+ dy= 30;
+
+ uiDefBut(block, LABEL, 0, "Layers", 10,170,100,20, NULL, 0, 0, 0, 0, "");
+
+ uiBlockBeginAlign(block);
+ for(a=0; a<5; a++)
+ uiDefButBitI(block, TOG, 1<<a, B_OBLAY+a, "", (short)(xco+a*(dx/2)), 180, (short)(dx/2), (short)(dy/2), (int *)&(BASACT->lay), 0, 0, 0, 0, "");
+ for(a=0; a<5; a++)
+ uiDefButBitI(block, TOG, 1<<(a+10), B_OBLAY+a+10, "", (short)(xco+a*(dx/2)), 165, (short)(dx/2), (short)(dy/2), (int *)&(BASACT->lay), 0, 0, 0, 0, "");
+
+ xco+= 7;
+ uiBlockBeginAlign(block);
+ for(a=5; a<10; a++)
+ uiDefButBitI(block, TOG, 1<<a, B_OBLAY+a, "", (short)(xco+a*(dx/2)), 180, (short)(dx/2), (short)(dy/2), (int *)&(BASACT->lay), 0, 0, 0, 0, "");
+ for(a=5; a<10; a++)
+ uiDefButBitI(block, TOG, 1<<(a+10), B_OBLAY+a+10, "", (short)(xco+a*(dx/2)), 165, (short)(dx/2), (short)(dy/2), (int *)&(BASACT->lay), 0, 0, 0, 0, "");
+
+ uiBlockEndAlign(block);
+
+ uiDefBut(block, LABEL, 0, "Drawtype", 10,120,100,20, NULL, 0, 0, 0, 0, "");
+
+ uiBlockBeginAlign(block);
+ uiDefButC(block, ROW, REDRAWVIEW3D, "Shaded", 10,100,100, 20, &ob->dt, 0, OB_SHADED, 0, 0, "Draw active object shaded or textured");
+ uiDefButC(block, ROW, REDRAWVIEW3D, "Solid", 10,80,100, 20, &ob->dt, 0, OB_SOLID, 0, 0, "Draw active object in solid");
+ uiDefButC(block, ROW, REDRAWVIEW3D, "Wire", 10,60, 100, 20, &ob->dt, 0, OB_WIRE, 0, 0, "Draw active object in wireframe");
+ uiDefButC(block, ROW, REDRAWVIEW3D, "Bounds", 10,40, 100, 20, &ob->dt, 0, OB_BOUNDBOX, 0, 0, "Only draw object with bounding box");
+ uiBlockEndAlign(block);
+
+ uiDefBut(block, LABEL, 0, "Draw Extra", 120,120,90,20, NULL, 0, 0, 0, 0, "");
+
+ uiBlockBeginAlign(block);
+ uiDefButBitC(block, TOG, OB_BOUNDBOX, REDRAWVIEW3D, "Bounds", 120, 100, 90, 20, &ob->dtx, 0, 0, 0, 0, "Displays the active object's bounds");
+ uiDefButBitC(block, TOG, OB_DRAWNAME, REDRAWVIEW3D, "Name", 210, 100, 90, 20, &ob->dtx, 0, 0, 0, 0, "Displays the active object's name");
+
+ uiDefButS(block, MENU, REDRAWVIEW3D, "Boundary Display%t|Box%x0|Sphere%x1|Cylinder%x2|Cone%x3|Polyheder%x4",
+ 120, 80, 90, 20, &ob->boundtype, 0, 0, 0, 0, "Selects the boundary display type");
+ uiDefButBitC(block, TOG, OB_AXIS, REDRAWVIEW3D, "Axis", 210, 80, 90, 20, &ob->dtx, 0, 0, 0, 0, "Displays the active object's center and axis");
+
+ uiDefButBitC(block, TOG, OB_TEXSPACE, REDRAWVIEW3D, "TexSpace", 120, 60, 90, 20, &ob->dtx, 0, 0, 0, 0, "Displays the active object's texture space");
+ uiDefButBitC(block, TOG, OB_DRAWWIRE, REDRAWVIEW3D, "Wire", 210, 60, 90, 20, &ob->dtx, 0, 0, 0, 0, "Adds the active object's wireframe over solid drawing");
+
+ uiDefButBitC(block, TOG, OB_DRAWTRANSP, REDRAWVIEW3D, "Transp", 120, 40, 90, 20, &ob->dtx, 0, 0, 0, 0, "Enables transparent materials for the active object (Mesh only)");
+ uiDefButBitC(block, TOG, OB_DRAWXRAY, REDRAWVIEW3D, "X-ray", 210, 40, 90, 20, &ob->dtx, 0, 0, 0, 0, "Makes the active object draw in front of others");
+}
+
+void object_panel_constraint(char *context)
+{
+ uiBlock *block;
+ Object *ob= OBACT;
+ ListBase *conlist;
+ bConstraint *curcon;
+ short xco, yco;
+ char str[64];
+
+ block= uiNewBlock(&curarea->uiblocks, "object_panel_constraint", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Constraints", context, 960, 0, 318, 204)==0) return;
+
+ uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
+
+ /* this is a variable height panel, newpanel doesnt force new size on existing panels */
+ /* so first we make it default height */
+ uiNewPanelHeight(block, 204);
+
+ /* do not allow this panel to draw in editmode - why?*/
+ if(G.obedit==OBACT) return; // ??
+
+ conlist = get_active_constraints(OBACT);
+
+ if (conlist) {
+ uiDefBlockBut(block, add_constraintmenu, NULL, "Add Constraint", 0, 190, 130, 20, "Add a new constraint");
+
+ /* print active object or bone */
+ str[0]= 0;
+ if (ob->flag & OB_POSEMODE) {
+ bPoseChannel *pchan= get_active_posechannel(ob);
+ if(pchan) sprintf(str, "To Bone: %s", pchan->name);
+ }
+ else {
+ sprintf(str, "To Object: %s", ob->id.name+2);
+ }
+ uiDefBut(block, LABEL, 1, str, 150, 190, 150, 20, NULL, 0.0, 0.0, 0, 0, "Displays Active Object or Bone name");
+
+ /* Go through the list of constraints and draw them */
+ xco = 10;
+ yco = 160;
+
+ for (curcon = conlist->first; curcon; curcon=curcon->next) {
+ /* hrms, the temporal constraint should not draw! */
+ if(curcon->type==CONSTRAINT_TYPE_KINEMATIC) {
+ bKinematicConstraint *data= curcon->data;
+ if(data->flag & CONSTRAINT_IK_TEMP)
+ continue;
+ }
+ /* Draw default constraint header */
+ draw_constraint(block, conlist, curcon, &xco, &yco);
+ }
+
+ if(yco < 0) uiNewPanelHeight(block, 204-yco);
+
+ }
+}
+
+void do_effects_panels(unsigned short event)
+{
+ Object *ob;
+ Base *base;
+ Effect *eff, *effn;
+ PartEff *paf;
+
+ ob= OBACT;
+
+ switch(event) {
+
+ case B_AUTOTIMEOFS:
+ auto_timeoffs();
+ break;
+ case B_FRAMEMAP:
+ G.scene->r.framelen= G.scene->r.framapto;
+ G.scene->r.framelen/= G.scene->r.images;
+ allqueue(REDRAWALL, 0);
+ break;
+ case B_NEWEFFECT:
+ if(ob) {
+ if(ob->fluidsimFlag & OB_FLUIDSIM_ENABLE) {
+ // NT particles and fluid meshes currently dont work together -> switch off beforehand
+ if(ob->fluidsimSettings->type == OB_FLUIDSIM_DOMAIN) {
+ pupmenu("Fluidsim Particle Error%t|Please disable the fluidsim domain before activating particles.%x0");
+ break;
+ //ob->fluidsimFlag = 0; ob->fluidsimSettings->type = 0; allqueue(REDRAWVIEW3D, 0);
+ }
+ }
+ if (BLI_countlist(&ob->effect)==MAX_EFFECT)
+ error("Unable to add: effect limit reached");
+ else
+ copy_act_effect(ob);
+ }
+ DAG_scene_sort(G.scene);
+ BIF_undo_push("New effect");
+ allqueue(REDRAWBUTSOBJECT, 0);
+ break;
+ case B_DELEFFECT:
+ if(ob==NULL || ob->type!=OB_MESH) break;
+ eff= ob->effect.first;
+ while(eff) {
+ effn= eff->next;
+ if(eff->flag & SELECT) {
+ BLI_remlink(&ob->effect, eff);
+ free_effect(eff);
+ break;
+ }
+ eff= effn;
+ }
+ BIF_undo_push("Delete effect");
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSOBJECT, 0);
+ break;
+ case B_NEXTEFFECT:
+ if(ob==0 || ob->type!=OB_MESH) break;
+ eff= ob->effect.first;
+ while(eff) {
+ if(eff->flag & SELECT) {
+ if(eff->next) {
+ eff->flag &= ~SELECT;
+ eff->next->flag |= SELECT;
+ }
+ break;
+ }
+ eff= eff->next;
+ }
+ allqueue(REDRAWBUTSOBJECT, 0);
+ break;
+ case B_PREVEFFECT:
+ if(ob==0 || ob->type!=OB_MESH) break;
+ eff= ob->effect.first;
+ while(eff) {
+ if(eff->flag & SELECT) {
+ if(eff->prev) {
+ eff->flag &= ~SELECT;
+ eff->prev->flag |= SELECT;
+ }
+ break;
+ }
+ eff= eff->next;
+ }
+ allqueue(REDRAWBUTSOBJECT, 0);
+ break;
+ case B_EFFECT_DEP:
+ DAG_scene_sort(G.scene);
+ /* no break, pass on */
+ case B_CALCEFFECT:
+ if(ob==NULL || ob->type!=OB_MESH) break;
+ eff= ob->effect.first;
+ while(eff) {
+ if(eff->flag & SELECT) {
+ if(eff->type==EFF_PARTICLE) build_particle_system(ob);
+ }
+ eff= eff->next;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSOBJECT, 0);
+ break;
+ case B_PAF_SET_VG:
+
+ paf= give_parteff(ob);
+ if(paf) {
+ bDeformGroup *dg= get_named_vertexgroup(ob, paf->vgroupname);
+ if(dg)
+ paf->vertgroup= get_defgroup_num(ob, dg)+1;
+ else
+ paf->vertgroup= 0;
+
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ break;
+ case B_PAF_SET_VG1:
+
+ paf= give_parteff(ob);
+ if(paf) {
+ bDeformGroup *dg= get_named_vertexgroup(ob, paf->vgroupname_v);
+ if(dg)
+ paf->vertgroup_v= get_defgroup_num(ob, dg)+1;
+ else
+ paf->vertgroup_v= 0;
+
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ break;
+ case B_FIELD_DEP:
+ /* do this before scene sort, that one checks for CU_PATH */
+ if(ob->type==OB_CURVE && ob->pd->forcefield==PFIELD_GUIDE) {
+ Curve *cu= ob->data;
+
+ cu->flag |= (CU_PATH|CU_3D);
+ do_curvebuts(B_CU3D); /* all curves too */
+ }
+ DAG_scene_sort(G.scene);
+
+ if(ob->type==OB_CURVE && ob->pd->forcefield==PFIELD_GUIDE)
+ DAG_object_flush_update(G.scene, ob, OB_RECALC);
+ else
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_OB);
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSOBJECT, 0);
+ break;
+ case B_FIELD_CHANGE:
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_OB);
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+ case B_RECALCAL:
+ if (G.vd==NULL)
+ break;
+
+ base= FIRSTBASE;
+ while(base) {
+ if(base->lay & G.vd->lay) {
+ ob= base->object;
+ eff= ob->effect.first;
+ while(eff) {
+ if(eff->flag & SELECT) {
+ if(eff->type==EFF_PARTICLE) build_particle_system(ob);
+ }
+ eff= eff->next;
+ }
+ }
+ base= base->next;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+ default:
+ if(event>=B_SELEFFECT && event<B_SELEFFECT+MAX_EFFECT) {
+ ob= OBACT;
+ if(ob) {
+ int a=B_SELEFFECT;
+
+ eff= ob->effect.first;
+ while(eff) {
+ if(event==a) eff->flag |= SELECT;
+ else eff->flag &= ~SELECT;
+
+ a++;
+ eff= eff->next;
+ }
+ allqueue(REDRAWBUTSOBJECT, 0);
+ }
+ }
+ }
+
+}
+
+/* Panel for particle interaction settings */
+static void object_panel_fields(Object *ob)
+{
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "object_panel_fields", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Fields and Deflection", "Physics", 0, 0, 318, 204)==0) return;
+
+ uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
+
+ /* should become button, option? */
+ if(ob->pd==NULL) {
+ ob->pd= MEM_callocN(sizeof(PartDeflect), "PartDeflect");
+ /* and if needed, init here */
+ ob->pd->pdef_sbdamp = 0.1f;
+ ob->pd->pdef_sbift = 0.2f;
+ ob->pd->pdef_sboft = 0.02f;
+ }
+
+ if(ob->pd) {
+ PartDeflect *pd= ob->pd;
+ char *menustr= MEM_mallocN(256, "temp string");
+ char *tipstr="Choose field type";
+
+ uiDefBut(block, LABEL, 0, "Fields", 10,180,140,20, NULL, 0.0, 0, 0, 0, "");
+
+ /* setup menu button */
+ sprintf(menustr, "Field Type%%t|None %%x0|Spherical %%x%d|Wind %%x%d|Vortex %%x%d|Curve Guide %%x%d",
+ PFIELD_FORCE, PFIELD_WIND, PFIELD_VORTEX, PFIELD_GUIDE);
+
+ if(pd->forcefield==PFIELD_FORCE) tipstr= "Object center attracts or repels particles";
+ else if(pd->forcefield==PFIELD_WIND) tipstr= "Constant force applied in direction of Object Z axis";
+ else if(pd->forcefield==PFIELD_VORTEX) tipstr= "Particles swirl around Z-axis of the Object";
+ else if(pd->forcefield==PFIELD_GUIDE) tipstr= "Use a Curve Path to guide particles";
+
+ uiDefButS(block, MENU, B_FIELD_DEP, menustr, 10,160,140,20, &pd->forcefield, 0.0, 0.0, 0, 0, tipstr);
+ MEM_freeN(menustr);
+
+ if(pd->forcefield) {
+ uiBlockBeginAlign(block);
+ if(pd->forcefield == PFIELD_GUIDE) {
+ uiDefButF(block, NUM, B_FIELD_CHANGE, "MinDist: ", 10,120,140,20, &pd->f_strength, 0.0, 1000.0, 10, 0, "The distance from which particles are affected fully.");
+ uiDefButF(block, NUM, B_FIELD_CHANGE, "Fall-off: ", 10,100,140,20, &pd->f_power, 0.0, 10.0, 10, 0, "Falloff factor, between mindist and maxdist");
+ }
+ else {
+ uiDefButF(block, NUM, B_FIELD_CHANGE, "Strength: ", 10,110,140,20, &pd->f_strength, -1000, 1000, 10, 0, "Strength of force field");
+ uiDefButF(block, NUM, B_FIELD_CHANGE, "Fall-off: ", 10,90,140,20, &pd->f_power, 0, 10, 10, 0, "Falloff power (real gravitational fallof = 2)");
+ }
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, PFIELD_USEMAX, B_FIELD_CHANGE, "Use MaxDist", 10,60,140,20, &pd->flag, 0.0, 0, 0, 0, "Use a maximum distance for the field to work");
+ uiDefButF(block, NUM, B_FIELD_CHANGE, "MaxDist: ", 10,40,140,20, &pd->maxdist, 0, 1000.0, 10, 0, "Maximum distance for the field to work");
+ uiBlockEndAlign(block);
+
+ if(pd->forcefield == PFIELD_GUIDE)
+ uiDefButBitS(block, TOG, PFIELD_GUIDE_PATH_ADD, B_FIELD_CHANGE, "Additive", 10,10,140,20, &pd->flag, 0.0, 0, 0, 0, "Based on distance/falloff it adds a portion of the entire path");
+
+ }
+
+ uiDefBut(block, LABEL, 0, "Deflection", 160,180,140,20, NULL, 0.0, 0, 0, 0, "");
+
+ /* only meshes collide now */
+ if(ob->type==OB_MESH) {
+ uiDefButBitS(block, TOG, 1, B_REDR, "Deflection",160,160,150,20, &pd->deflect, 0, 0, 0, 0, "Deflects particles based on collision");
+ if(pd->deflect) {
+ uiDefBut(block, LABEL, 0, "Particles", 160,140,150,20, NULL, 0.0, 0, 0, 0, "");
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_DIFF, "Damping: ", 160,120,150,20, &pd->pdef_damp, 0.0, 1.0, 10, 0, "Amount of damping during particle collision");
+ uiDefButF(block, NUM, B_DIFF, "Rnd Damping: ", 160,100,150,20, &pd->pdef_rdamp, 0.0, 1.0, 10, 0, "Random variation of damping");
+ uiDefButF(block, NUM, B_DIFF, "Permeability: ", 160,80,150,20, &pd->pdef_perm, 0.0, 1.0, 10, 0, "Chance that the particle will pass through the mesh");
+ uiBlockEndAlign(block);
+
+ uiDefBut(block, LABEL, 0, "Soft Body", 160,60,150,20, NULL, 0.0, 0, 0, 0, "");
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_FIELD_CHANGE, "Damping:", 160,40,150,20, &pd->pdef_sbdamp, 0.0, 1.0, 10, 0, "Amount of damping during soft body collision");
+ uiDefButF(block, NUM, B_FIELD_CHANGE, "Inner:", 160,20,150,20, &pd->pdef_sbift, 0.001, 1.0, 10, 0, "Inner face thickness");
+ uiDefButF(block, NUM, B_FIELD_CHANGE, "Outer:", 160, 0,150,20, &pd->pdef_sboft, 0.001, 1.0, 10, 0, "Outer face thickness");
+ }
+ }
+ }
+}
+
+
+/* Panel for softbodies */
+static void object_softbodies__enable(void *ob_v, void *arg2)
+{
+ Object *ob = ob_v;
+ ModifierData *md = modifiers_findByType(ob, eModifierType_Softbody);
+
+ if (modifiers_isSoftbodyEnabled(ob)) {
+ if (md) {
+ md->mode &= ~(eModifierMode_Render|eModifierMode_Realtime);
+ }
+ } else {
+ if (!md) {
+ md = modifier_new(eModifierType_Softbody);
+ BLI_addhead(&ob->modifiers, md);
+ }
+
+ md->mode |= eModifierMode_Render|eModifierMode_Realtime;
+
+ if (!ob->soft) {
+ ob->soft= sbNew();
+ ob->softflag |= OB_SB_GOAL|OB_SB_EDGES;
+ }
+ }
+
+ allqueue(REDRAWBUTSEDIT, 0);
+}
+
+static int _can_softbodies_at_all(Object *ob)
+{
+ // list of Yes
+ if ((ob->type==OB_MESH)
+ || (ob->type==OB_CURVE)
+ || (ob->type==OB_LATTICE)
+ || (ob->type==OB_SURF)
+ ) return 1;
+ // else deny
+ return 0;
+}
+static void object_softbodies_II(Object *ob)
+{
+ uiBlock *block;
+ static int val;
+ if(!_can_softbodies_at_all(ob)) return;
+ /*bah that is ugly! creating missing data members in UI code*/
+ if(ob->pd == NULL){
+ ob->pd= MEM_callocN(sizeof(PartDeflect), "PartDeflect");
+ ob->pd->pdef_sbdamp = 0.1f;
+ ob->pd->pdef_sbift = 0.2f;
+ ob->pd->pdef_sboft = 0.02f;
+ }
+ block= uiNewBlock(&curarea->uiblocks, "object_softbodies_II", UI_EMBOSS, UI_HELV, curarea->win);
+ uiNewPanelTabbed("Soft Body", "Physics");
+ if(uiNewPanel(curarea, block, "Soft Body Collision", "Physics", 651, 0, 318, 204)==0) return;
+
+ uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
+
+ val = modifiers_isSoftbodyEnabled(ob);
+ if(!val) {
+ uiDefBut(block, LABEL, 0, "",10,10,1,2, NULL, 0.0, 0, 0, 0, ""); /* tell UI we go to 10,10*/
+ uiBlockBeginAlign(block);
+ uiDefBut(block, LABEL, 0, "Object is not a softbody",10,190,300,20, NULL, 0.0, 0, 0, 0, "");
+ uiDefBut(block, LABEL, 0, "However it can deflect a softbody",10,170,300,20, NULL, 0.0, 0, 0, 0, "");
+ /* OTHER OBJECTS COLLISION STUFF */
+ if (ob->type==OB_MESH){
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, 1, B_REDR, "Deflection",10,50,150,20, &ob->pd->deflect, 0, 0, 0, 0, "Makes this object visible to softbody objects");
+ if(ob->pd->deflect) {
+ uiDefButF(block, NUM, B_FIELD_CHANGE, "Damping:", 160,50,150,20, &ob->pd->pdef_sbdamp, 0.0, 1.0, 10, 0, "Amount of damping during soft body collision");
+ uiDefButBitS(block, TOG,OB_SB_COLLFINAL , B_DIFF, "Ev.M.Stack",10,30,150,20, &ob->softflag, 0, 0, 0, 0, "Pick collision object from modifier stack");
+ uiDefButF(block, NUM, B_FIELD_CHANGE, "Inner:", 160,30,150,20, &ob->pd->pdef_sbift, 0.001, 1.0, 10, 0, "Inner face thickness");
+ uiDefButF(block, NUM, B_FIELD_CHANGE, "Outer:", 160,10,150,20, &ob->pd->pdef_sboft, 0.001, 1.0, 10, 0, "Outer face thickness");
+ }
+ }
+ uiBlockEndAlign(block);
+ }
+ else{
+ SoftBody *sb= ob->soft;
+ /* SELF COLLISION STUFF */
+ if ((ob->type==OB_MESH)||(ob->type==OB_CURVE) ) {
+ uiBlockBeginAlign(block);
+ if (ob->softflag & OB_SB_EDGES){
+ uiDefButBitS(block, TOG, OB_SB_SELF, B_SOFTBODY_CHANGE, "Self Collision", 10,170,150,20, &ob->softflag, 0, 0, 0, 0, "enable naive vertex ball self collision");
+ if(ob->softflag & OB_SB_SELF){
+ uiDefButF(block, NUM, B_SOFTBODY_CHANGE, "Ball Size:", 160,170,150,20, &sb->colball, -10.0, 10.0, 10, 0, "Absolute ball size or factor if not manual adjusted");
+ uiDefButS(block, ROW, B_DIFF, "Man",10,150,60,20, &sb->sbc_mode, 4.0,(float)0, 0, 0, "Manual adjust");
+ uiDefButS(block, ROW, B_DIFF, "Av",70,150,60,20, &sb->sbc_mode, 4.0,(float)1, 0, 0, "Average Spring lenght * Ball Size");
+ uiDefButS(block, ROW, B_DIFF, "Min",130,150,60,20, &sb->sbc_mode, 4.0,(float)2, 0, 0, "Minimal Spring lenght * Ball Size");
+ uiDefButS(block, ROW, B_DIFF, "Max",190,150,60,20, &sb->sbc_mode, 4.0,(float)3, 0, 0, "Maximal Spring lenght * Ball Size");
+ uiDefButS(block, ROW, B_DIFF, "AvMiMa",250,150,60,20, &sb->sbc_mode, 4.0,(float)4, 0, 0, "(Min+Max)/2 * Ball Size");
+ uiDefButF(block, NUM, B_DIFF, "B Stiff:", 10,130,150,20, &sb->ballstiff, 0.001, 100.0, 10, 0, "Ball inflating presure");
+ uiDefButF(block, NUM, B_DIFF, "B Damp:", 160,130,150,20, &sb->balldamp, 0.001, 1.0, 10, 0, "Blending to inelastic collision");
+ }
+ }
+ else{
+ uiDefBut(block, LABEL, 0, "<Self Collision> not available because there",10,170,300,20, NULL, 0.0, 0, 0, 0, "");
+ uiDefBut(block, LABEL, 0, "are no edges, enable <Use Edges>",10,150,300,20, NULL, 0.0, 0, 0, 0, "");
+ }
+
+ uiBlockEndAlign(block);
+ /*SOLVER SETTINGS*/
+ uiDefButF(block, NUM, B_DIFF, "Error Lim:", 10,100,130,20, &sb->rklimit , 0.001, 10.0, 10, 0, "The Runge-Kutta ODE solver error limit, low value gives more precision, high values speed");
+ uiDefButBitS(block, TOG, SBSO_OLDERR, B_DIFF,"O", 140,100,20,20, &sb->solverflags, 0, 0, 0, 0, "Old Error Calculation");
+ uiDefButS(block, NUM, B_DIFF, "Fuzzy:", 160,100,130,20, &sb->fuzzyness, 1.00, 100.0, 10, 0, "Fuzzyness while on collision, high values make collsion handling faster but less stable");
+ uiDefButBitS(block, TOG, SBSO_MONITOR, B_DIFF,"M", 290,100,20,20, &sb->solverflags, 0, 0, 0, 0, "Turn on SB diagnose console prints");
+ uiDefButS(block, NUM, B_DIFF, "MinS:", 10,80,100,20, &sb->minloops, 0.00, 30000.0, 10, 0, "Minimal # solver steps/frame ");
+ uiDefButS(block, NUM, B_DIFF, "MaxS:", 110,80,100,20, &sb->maxloops, 0.00, 30000.0, 10, 0, "Maximal # solver steps/frame ");
+ uiDefButS(block, NUM, B_DIFF, "Choke:", 210,80,100,20, &sb->choke, 0.00, 100.0, 10, 0, "'Viscosity' inside collision target ");
+ }
+ /* OTHER OBJECTS COLLISION STUFF */
+ if (ob->type==OB_MESH){
+ uiDefButBitS(block, TOG, 1, B_REDR, "Deflection",10,50,150,20, &ob->pd->deflect, 0, 0, 0, 0, "Makes this object visible to other softbody objects");
+ if(ob->pd->deflect) {
+ uiDefButF(block, NUM, B_DIFF, "Damping:", 160,50,150,20, &ob->pd->pdef_sbdamp, 0.0, 1.0, 10, 0, "Amount of damping during soft body collision");
+ uiDefButBitS(block, TOG,OB_SB_COLLFINAL , B_DIFF, "Ev.M.Stack",10,30,150,20, &ob->softflag, 0, 0, 0, 0, "Pick collision object from modifier stack");
+ uiDefButF(block, NUM, B_DIFF, "Inner:", 160,30,150,20, &ob->pd->pdef_sbift, 0.001, 1.0, 10, 0, "Inner face thickness");
+ uiDefButF(block, NUM, B_DIFF, "Outer:", 160,10,150,20, &ob->pd->pdef_sboft, 0.001, 1.0, 10, 0, "Outer face thickness");
+ }
+ }
+ uiDefBut(block, LABEL, 0, "",10,10,1,2, NULL, 0.0, 0, 0, 0, ""); /* tell UI we go to 10,10*/
+ }
+ uiBlockEndAlign(block);
+}
+
+static void object_softbodies(Object *ob)
+{
+ uiBlock *block;
+ static int val;
+ uiBut *but;
+ if(!_can_softbodies_at_all(ob)) return;
+ block= uiNewBlock(&curarea->uiblocks, "object_softbodies", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Soft Body", "Physics", 640, 0, 318, 204)==0) return;
+ uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
+
+ val = modifiers_isSoftbodyEnabled(ob);
+ but = uiDefButI(block, TOG, REDRAWBUTSOBJECT, "Soft Body", 10,200,130,20, &val, 0, 0, 0, 0, "Sets object to become soft body");
+ uiButSetFunc(but, object_softbodies__enable, ob, NULL);
+ uiDefBut(block, LABEL, 0, "",10,10,300,0, NULL, 0.0, 0, 0, 0, ""); /* tell UI we go to 10,10*/
+
+ if(modifiers_isSoftbodyEnabled(ob)){
+ SoftBody *sb= ob->soft;
+ int defCount;
+ char *menustr;
+
+ if(sb==NULL) {
+ sb= ob->soft= sbNew();
+ ob->softflag |= OB_SB_GOAL|OB_SB_EDGES;
+ }
+
+ uiDefButBitS(block, TOG, OB_SB_BAKESET, REDRAWBUTSOBJECT, "Bake settings", 180,200,130,20, &ob->softflag, 0, 0, 0, 0, "To convert simulation into baked (cached) result");
+
+ if(sb->keys) uiSetButLock(1, "Soft Body is baked, free it first");
+
+ if(ob->softflag & OB_SB_BAKESET) {
+ uiBlockBeginAlign(block);
+ uiDefButI(block, NUM, B_DIFF, "Start:", 10, 170,100,20, &sb->sfra, 1.0, 10000.0, 10, 0, "Start frame for baking");
+ uiDefButI(block, NUM, B_DIFF, "End:", 110, 170,100,20, &sb->efra, 1.0, 10000.0, 10, 0, "End frame for baking");
+ uiDefButI(block, NUM, B_DIFF, "Interval:", 210, 170,100,20, &sb->interval, 1.0, 10.0, 10, 0, "Interval in frames between baked keys");
+ uiBlockEndAlign(block);
+
+ uiDefButS(block, TOG, B_DIFF, "Local", 10, 145,100,20, &sb->local, 0.0, 0.0, 0, 0, "Use local coordinates for baking");
+
+
+ uiClearButLock();
+ uiBlockBeginAlign(block);
+
+ if(sb->keys) {
+ char str[128];
+ uiDefIconTextBut(block, BUT, B_SOFTBODY_BAKE_FREE, ICON_X, "FREE BAKE", 10, 120,300,20, NULL, 0.0, 0.0, 0, 0, "Free baked result");
+ sprintf(str, "Stored %d vertices %d keys %.3f MB", sb->totpoint, sb->totkey, ((float)16*sb->totpoint*sb->totkey)/(1024.0*1024.0));
+ uiDefBut(block, LABEL, 0, str, 10, 100,300,20, NULL, 0.0, 0.0, 00, 0, "");
+ }
+ else
+ uiDefBut(block, BUT, B_SOFTBODY_BAKE, "BAKE", 10, 120,300,20, NULL, 0.0, 0.0, 10, 0, "Start baking. Press ESC to exit without baking");
+
+ }
+ else {
+ /* GENERAL STUFF */
+ static char str[128];
+ if (sb->totpoint){
+ sprintf(str, "Vertex Mass; Object mass %f [k]",sb->nodemass*sb->totpoint/1000.0f);
+ }
+ else{
+ sprintf(str, "Vertex Mass");
+ }
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_DIFF, "Friction:", 10, 170,150,20, &sb->mediafrict, 0.0, 50.0, 10, 0, "General media friction for point movements");
+ uiDefButF(block, NUM, B_DIFF, "Mass:", 160, 170,150,20, &sb->nodemass , 0.001, 50000.0, 10, 0, str);
+ uiDefButF(block, NUM, B_DIFF, "Grav:", 10,150,150,20, &sb->grav , 0.0, 10.0, 10, 0, "Apply gravitation to point movement");
+ uiDefButF(block, NUM, B_DIFF, "Speed:", 160,150,150,20, &sb->physics_speed , 0.01, 100.0, 10, 0, "Tweak timing for physics to control frequency and speed");
+ uiBlockEndAlign(block);
+
+ /* GOAL STUFF */
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, OB_SB_GOAL, B_SOFTBODY_CHANGE, "Use Goal", 10,120,130,20, &ob->softflag, 0, 0, 0, 0, "Define forces for vertices to stick to animated position");
+ if (ob->softflag & OB_SB_GOAL){
+ if(ob->type==OB_MESH) {
+ menustr= get_vertexgroup_menustr(ob);
+ defCount=BLI_countlist(&ob->defbase);
+ if(defCount==0) sb->vertgroup= 0;
+ uiDefButS(block, MENU, B_SOFTBODY_CHANGE, menustr, 140,120,20,20, &sb->vertgroup, 0, defCount, 0, 0, "Browses available vertex groups");
+ MEM_freeN (menustr);
+
+ if(sb->vertgroup) {
+ bDeformGroup *defGroup = BLI_findlink(&ob->defbase, sb->vertgroup-1);
+ if(defGroup)
+ uiDefBut(block, BUT, B_DIFF, defGroup->name, 160,120,130,20, NULL, 0.0, 0.0, 0, 0, "Name of current vertex group");
+ else
+ uiDefBut(block, BUT, B_DIFF, "(no group)", 160,120,130,20, NULL, 0.0, 0.0, 0, 0, "Vertex Group doesn't exist anymore");
+ uiDefIconBut(block, BUT, B_SOFTBODY_DEL_VG, ICON_X, 290,120,20,20, 0, 0, 0, 0, 0, "Disable use of vertex group");
+ }
+ else
+ uiDefButF(block, NUM, B_SOFTBODY_CHANGE, "Goal:", 160,120,150,20, &sb->defgoal, 0.0, 1.0, 10, 0, "Default Goal (vertex target position) value, when no Vertex Group used");
+ }
+ else {
+ uiDefButS(block, TOG, B_SOFTBODY_CHANGE, "W", 140,120,20,20, &sb->vertgroup, 0, 1, 0, 0, "Use control point weight values");
+ uiDefButF(block, NUM, B_SOFTBODY_CHANGE, "Goal:", 160,120,150,20, &sb->defgoal, 0.0, 1.0, 10, 0, "Default Goal (vertex target position) value, when no Vertex Group used");
+ }
+
+ uiDefButF(block, NUM, B_DIFF, "G Stiff:", 10,100,150,20, &sb->goalspring, 0.0, 0.999, 10, 0, "Goal (vertex target position) spring stiffness");
+ uiDefButF(block, NUM, B_DIFF, "G Damp:", 160,100,150,20, &sb->goalfrict , 0.0, 50.0, 10, 0, "Goal (vertex target position) friction");
+ uiDefButF(block, NUM, B_SOFTBODY_CHANGE, "G Min:", 10,80,150,20, &sb->mingoal, 0.0, 1.0, 10, 0, "Goal minimum, vertex group weights are scaled to match this range");
+ uiDefButF(block, NUM, B_SOFTBODY_CHANGE, "G Max:", 160,80,150,20, &sb->maxgoal, 0.0, 1.0, 10, 0, "Goal maximum, vertex group weights are scaled to match this range");
+ }
+ uiBlockEndAlign(block);
+
+ /* EDGE SPRING STUFF */
+ if(ob->type!=OB_SURF) {
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, OB_SB_EDGES, B_SOFTBODY_CHANGE, "Use Edges", 10,50,90,20, &ob->softflag, 0, 0, 0, 0, "Use Edges as springs");
+ if (ob->softflag & OB_SB_EDGES){
+ uiDefButBitS(block, TOG, OB_SB_QUADS, B_SOFTBODY_CHANGE, "Stiff Quads", 110,50,90,20, &ob->softflag, 0, 0, 0, 0, "Adds diagonal springs on 4-gons");
+ uiDefButBitS(block, TOG, OB_SB_EDGECOLL, B_DIFF, "CEdge", 220,50,45,20, &ob->softflag, 0, 0, 0, 0, "Edge collide too");
+ uiDefButBitS(block, TOG, OB_SB_FACECOLL, B_DIFF, "CFace", 265,50,45,20, &ob->softflag, 0, 0, 0, 0, "Faces collide too SLOOOOOW warning ");
+ uiDefButF(block, NUM, B_DIFF, "E Stiff:", 10,30,150,20, &sb->inspring, 0.0, 0.999, 10, 0, "Edge spring stiffness");
+ uiDefButF(block, NUM, B_DIFF, "E Damp:", 160,30,150,20, &sb->infrict, 0.0, 50.0, 10, 0, "Edge spring friction");
+ uiDefButS(block, NUM, B_DIFF, "Aero:", 10,10,150,20, &sb->aeroedge, 0.00, 30000.0, 10, 0, "Make edges 'sail'");
+ if(ob->type==OB_MESH) {
+ uiDefButF(block, NUM, B_SOFTBODY_CHANGE, "Rigidity:", 160,10,150,20, &sb->secondspring, 0.0, 10.0, 10, 0, "Strenght of Springs over 2 Edges");
+ }
+ else sb->secondspring = 0;
+ uiDefBut(block, LABEL, 0, "",10,10,1,0, NULL, 0.0, 0, 0, 0, ""); /* tell UI we go to 10,10*/
+ }
+ uiBlockEndAlign(block);
+ }
+ }
+ }
+ uiBlockEndAlign(block);
+}
+
+static void object_panel_particles_motion(Object *ob)
+{
+ uiBlock *block;
+ uiBut *but;
+ PartEff *paf= give_parteff(ob);
+
+ if (paf==NULL) return;
+
+ block= uiNewBlock(&curarea->uiblocks, "object_panel_particles_motion", UI_EMBOSS, UI_HELV, curarea->win);
+ uiNewPanelTabbed("Particles ", "Physics");
+ if(uiNewPanel(curarea, block, "Particle Motion", "Physics", 320, 0, 318, 204)==0) return;
+
+ uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
+
+ /* top row */
+ uiBlockBeginAlign(block);
+ uiDefButI(block, NUM, B_CALCEFFECT, "Keys:", 0,180,75,20, &paf->totkey, 1.0, 100.0, 0, 0, "Specify the number of key positions");
+ uiDefButBitS(block, TOG, PAF_BSPLINE, B_CALCEFFECT, "Bspline", 75,180,75,20, &paf->flag, 0, 0, 0, 0, "Use B spline formula for particle interpolation");
+ uiDefButI(block, NUM, B_CALCEFFECT, "Seed:", 150,180,75,20, &paf->seed, 0.0, 255.0, 0, 0, "Set an offset in the random table");
+ uiDefButF(block, NUM, B_CALCEFFECT, "RLife:", 225,180,85,20, &paf->randlife, 0.0, 2.0, 10, 1, "Give the particlelife a random variation");
+ uiBlockEndAlign(block);
+
+ /* left collumn */
+ uiDefBut(block, LABEL, 0, "Velocity:", 0,160,150,20, NULL, 0.0, 0, 0, 0, "");
+ uiBlockBeginAlign(block);
+ uiBlockSetCol(block, TH_BUT_SETTING2);
+ uiDefButF(block, NUM, B_CALCEFFECT, "Normal:", 0,140,150,18, &paf->normfac, -2.0, 2.0, 1, 3, "Let the mesh give the particle a starting speed");
+ uiDefButF(block, NUM, B_CALCEFFECT, "Object:", 0,122,150,18, &paf->obfac, -1.0, 1.0, 1, 3, "Let the object give the particle a starting speed");
+ uiDefButF(block, NUM, B_CALCEFFECT, "Random:", 0,104,150,18, &paf->randfac, 0.0, 2.0, 1, 3, "Give the starting speed a random variation");
+ uiDefButF(block, NUM, B_CALCEFFECT, "Texture:", 0,86,150,18, &paf->texfac, 0.0, 2.0, 1, 3, "Let the texture give the particle a starting speed");
+ uiDefButF(block, NUM, B_CALCEFFECT, "Damping:", 0,68,150,18, &paf->damp, 0.0, 1.0, 1, 3, "Specify the damping factor");
+ uiBlockSetCol(block, TH_AUTO);
+ but=uiDefBut(block, TEX, B_PAF_SET_VG1, "VGroup:", 0,50,150,18, paf->vgroupname_v, 0, 31, 0, 0, "Name of vertex group to use for speed control");
+ uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)OBACT);
+ uiBlockEndAlign(block);
+
+ uiDefBut(block, LABEL, 0, "Texture Emission", 0,30,150,20, NULL, 0.0, 0, 0, 0, "");
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG3, PAF_TEXTIME, B_CALCEFFECT, "TexEmit", 0,10,75,20, &(paf->flag2), 0, 0, 0, 0, "Use a texture to define emission of particles");
+ uiDefButS(block, NUM, B_CALCEFFECT, "Tex:", 75,10,75,20, &paf->timetex, 1.0, 10.0, 0, 0, "Specify texture used for the texture emission");
+
+ /* right collumn */
+ uiDefIDPoinBut(block, test_grouppoin_but, ID_GR, B_CALCEFFECT, "GR:", 160, 155, 150, 20, &paf->group, "Limit Force Fields to this Group");
+
+ uiBlockBeginAlign(block);
+ uiDefBut(block, LABEL, 0, "Force:", 160,130,75,20, NULL, 0.0, 0, 0, 0, "");
+ uiDefButF(block, NUM, B_CALCEFFECT, "X:", 235,130,75,20, paf->force, -1.0, 1.0, 1, 2, "Specify the X axis of a continues force");
+ uiDefButF(block, NUM, B_CALCEFFECT, "Y:", 160,110,75,20, paf->force+1,-1.0, 1.0, 1, 2, "Specify the Y axis of a continues force");
+ uiDefButF(block, NUM, B_CALCEFFECT, "Z:", 235,110,75,20, paf->force+2, -1.0, 1.0, 1, 2, "Specify the Z axis of a continues force");
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, NUM, B_CALCEFFECT, "Tex:", 160,80,75,20, &paf->speedtex, 1.0, 10.0, 0, 2, "Specify the texture used for force");
+ uiDefButF(block, NUM, B_CALCEFFECT, "X:", 235,80,75,20, paf->defvec, -1.0, 1.0, 1, 2, "Specify the X axis of a force, determined by the texture");
+ uiDefButF(block, NUM, B_CALCEFFECT, "Y:", 160,60,75,20, paf->defvec+1,-1.0, 1.0, 1, 2, "Specify the Y axis of a force, determined by the texture");
+ uiDefButF(block, NUM, B_CALCEFFECT, "Z:", 235,60,75,20, paf->defvec+2, -1.0, 1.0, 1, 2, "Specify the Z axis of a force, determined by the texture");
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, ROW, B_CALCEFFECT, "Int", 160,30,50,20, &paf->texmap, 14.0, 0.0, 0, 0, "Use texture intensity as a factor for texture force");
+ uiDefButS(block, ROW, B_CALCEFFECT, "RGB", 210,30,50,20, &paf->texmap, 14.0, 1.0, 0, 0, "Use RGB values as a factor for particle speed vector");
+ uiDefButS(block, ROW, B_CALCEFFECT, "Grad", 260,30,50,20, &paf->texmap, 14.0, 2.0, 0, 0, "Use texture gradient as a factor for particle speed vector");
+
+ uiDefButF(block, NUM, B_CALCEFFECT, "Nabla:", 160,10,150,20, &paf->nabla, 0.0001f, 1.0, 1, 0, "Specify the dimension of the area for gradient calculation");
+
+}
+
+
+static void object_panel_particles(Object *ob)
+{
+ uiBlock *block;
+ uiBut *but;
+ PartEff *paf= give_parteff(ob);
+
+ /* the panelname "Particles " has a space to exclude previous saved panel "Particles" */
+ block= uiNewBlock(&curarea->uiblocks, "object_panel_particles", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Particles ", "Physics", 320, 0, 318, 204)==0) return;
+
+ uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
+
+ if (ob->type == OB_MESH) {
+ uiBlockBeginAlign(block);
+ if(paf==NULL)
+ uiDefBut(block, BUT, B_NEWEFFECT, "NEW", 0,180,75,20, 0, 0, 0, 0, 0, "Create a new Particle effect");
+ else
+ uiDefBut(block, BUT, B_DELEFFECT, "Delete", 0,180,75,20, 0, 0, 0, 0, 0, "Delete the effect");
+ }
+ else uiDefBut(block, LABEL, 0, "Only Mesh Objects can generate particles", 10,180,300,20, NULL, 0.0, 0, 0, 0, "");
+
+
+ if(paf==NULL) return;
+
+ uiDefBut(block, BUT, B_RECALCAL, "RecalcAll", 75,180,75,20, 0, 0, 0, 0, 0, "Update all particle systems");
+ uiBlockEndAlign(block);
+
+ uiDefBut(block, LABEL, 0, "Emit:", 0,150,75,20, NULL, 0.0, 0, 0, 0, "");
+ uiBlockBeginAlign(block);
+ uiDefButI(block, NUM, B_CALCEFFECT, "Amount:", 0,130,150,20, &paf->totpart, 1.0, 1000000.0, 0, 0, "The total number of particles");
+ if(paf->flag & PAF_STATIC) {
+ uiDefButS(block, NUM, REDRAWVIEW3D, "Step:", 0,110,150,20, &paf->staticstep, 1.0, 100.0, 10, 0, "For static duplicators, the Step value skips particles");
+ }
+ else {
+ uiDefButF(block, NUM, B_CALCEFFECT, "Sta:", 0,110,75,20, &paf->sta, -250.0, MAXFRAMEF, 100, 1, "Frame # to start emitting particles");
+ uiDefButF(block, NUM, B_CALCEFFECT, "End:", 75,110,75,20, &paf->end, 1.0, MAXFRAMEF, 100, 1, "Frame # to stop emitting particles");
+ }
+ uiDefButF(block, NUM, B_CALCEFFECT, "Life:", 0,90,75,20, &paf->lifetime, 1.0, MAXFRAMEF, 100, 1, "Specify the life span of the particles");
+ uiDefButS(block, NUM, B_CALCEFFECT, "Disp:", 75,90,75,20, &paf->disp, 0.0, 100.0, 10, 0, "Percentage of particles to calculate for 3d view");
+ uiBlockEndAlign(block);
+
+ uiDefBut(block, LABEL, 0, "From:", 0,70,75,20, NULL, 0.0, 0, 0, 0, "");
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOGN, PAF_OFACE, B_CALCEFFECT, "Verts", 0,50,75,20, &paf->flag, 0, 0, 0, 0, "Emit particles from vertices");
+ uiDefButBitS(block, TOG, PAF_FACE, B_CALCEFFECT, "Faces", 75,50,75,20, &paf->flag, 0, 0, 0, 0, "Emit particles from faces");
+ if(paf->flag & PAF_FACE) {
+ uiDefButBitS(block, TOG, PAF_TRAND, B_CALCEFFECT, "Rand", 0,30,50,20, &paf->flag, 0, 0, 0, 0, "Use true random distribution from faces");
+ uiDefButBitS(block, TOG, PAF_EDISTR, B_CALCEFFECT, "Even", 50,30,50,20, &paf->flag, 0, 0, 0, 0, "Use even distribution from faces based on face areas");
+ uiDefButS(block, NUM, B_CALCEFFECT, "P/F:", 100,30,50,20, &paf->userjit, 0.0, 200.0, 1, 0, "Jitter table distribution: maximum particles per face (0=uses default)");
+ }
+ else uiBlockEndAlign(block); /* vgroup button no align */
+
+ but=uiDefBut(block, TEX, B_PAF_SET_VG, "VGroup:", 0,10,150,20, paf->vgroupname, 0, 31, 0, 0, "Name of vertex group to use");
+ uiButSetCompleteFunc(but, autocomplete_vgroup, (void *)OBACT);
+ uiBlockEndAlign(block);
+
+ /* right collumn */
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, PAF_STATIC, B_EFFECT_DEP, "Static", 160,180,75,20, &paf->flag, 0, 0, 0, 0, "Make static particles (deform only works with SubSurf)");
+ if(paf->flag & PAF_STATIC) {
+ uiDefButBitS(block, TOG, PAF_ANIMATED, B_DIFF, "Animated", 235,180,75,20, &paf->flag, 0, 0, 0, 0, "Static particles are recalculated each rendered frame");
+ }
+ uiBlockEndAlign(block);
+
+ uiDefBut(block, LABEL, 0, "Display:", 160,150,75,20, NULL, 0.0, 0, 0, 0, "");
+ uiBlockBeginAlign(block);
+ uiDefButS(block, NUM, B_CALCEFFECT, "Material:", 160,130,150,20, &paf->omat, 1.0, 16.0, 0, 0, "Specify material used for the particles");
+ uiDefButS(block, TOG|BIT|7, B_REDR, "Mesh", 160,110,50,20, &paf->flag, 0, 0, 0, 0, "Render emitter Mesh also");
+ uiDefButBitS(block, TOG, PAF_UNBORN, B_DIFF, "Unborn",210,110,50,20, &paf->flag, 0, 0, 0, 0, "Make particles appear before they are emitted");
+ uiDefButBitS(block, TOG, PAF_DIED, B_DIFF, "Died", 260,110,50,20, &paf->flag, 0, 0, 0, 0, "Make particles appear after they have died");
+ uiDefButS(block, TOG, REDRAWVIEW3D, "Vect", 160,90,75,20, &paf->stype, 0, 0, 0, 0, "Give the particles a direction and rotation");
+ if(paf->flag & PAF_STATIC)
+ uiDefButF(block, NUM, B_CALCEFFECT, "Max:", 235,90,75,20, &paf->maxlen, 0.0, 100.0, 10, 1, "The maximum length of a particle strand (zero is no limit)");
+ else
+ uiDefButF(block, NUM, B_CALCEFFECT, "Size:", 235,90,75,20, &paf->vectsize, 0.0, 1.0, 10, 1, "The amount the Vect option influences halo size");
+ uiBlockEndAlign(block);
+
+ uiDefBut(block, LABEL, 0, "Children:", 160,70,75,20, NULL, 0.0, 0, 0, 0, "");
+ uiBlockBeginAlign(block);
+ uiDefButS(block, NUM, B_REDR, "Generation:", 160,50,150,20, &paf->curmult, 0.0, 3.0, 0, 0, "Current generation of particles");
+ uiDefButS(block, NUM, B_CALCEFFECT, "Num:", 160,30,75,20, paf->child+paf->curmult, 1.0, 600.0, 100, 0, "Specify the number of generations of particles that can multiply itself");
+ uiDefButF(block, NUM, B_CALCEFFECT, "Prob:", 235,30,75,20, paf->mult+paf->curmult, 0.0, 1.0, 10, 1, "Probability \"dying\" particle spawns a new one.");
+ uiDefButF(block, NUM, B_CALCEFFECT, "Life:", 160,10,75,20, paf->life+paf->curmult, 1.0, 600.0, 100, 1, "Specify the lifespan of the next generation particles");
+ uiDefButS(block, NUM, B_CALCEFFECT, "Mat:", 235,10,75,20, paf->mat+paf->curmult, 1.0, 8.0, 0, 0, "Specify the material used for the particles");
+ uiBlockEndAlign(block);
+
+}
+
+/* NT - Panel for fluidsim settings */
+static void object_panel_fluidsim(Object *ob)
+{
+#ifndef DISABLE_ELBEEM
+ uiBlock *block;
+ int yline = 160;
+ const int lineHeight = 20;
+ const int separateHeight = 3;
+ const int objHeight = 20;
+ char *msg = NULL;
+
+ block= uiNewBlock(&curarea->uiblocks, "object_fluidsim", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Fluid Simulation", "Physics", 1060, 0, 318, 204)==0) return;
+
+ uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
+
+ if(ob->type==OB_MESH) {
+ if(((Mesh *)ob->data)->totvert == 0) {
+ msg = "Mesh has no vertices.";
+ goto errMessage;
+ }
+ uiDefButBitS(block, TOG, OB_FLUIDSIM_ENABLE, REDRAWBUTSOBJECT, "Enable", 0,yline, 75,objHeight,
+ &ob->fluidsimFlag, 0, 0, 0, 0, "Sets object to participate in fluid simulation");
+
+ if(ob->fluidsimFlag & OB_FLUIDSIM_ENABLE) {
+ FluidsimSettings *fss= ob->fluidsimSettings;
+
+ if(fss==NULL) {
+ fss = ob->fluidsimSettings = fluidsimSettingsNew(ob);
+ }
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, ROW, REDRAWBUTSOBJECT ,"Domain", 90, yline, 70,objHeight, &fss->type, 15.0, OB_FLUIDSIM_DOMAIN, 20.0, 1.0, "Bounding box of this object represents the computational domain of the fluid simulation.");
+ uiDefButS(block, ROW, REDRAWBUTSOBJECT ,"Fluid", 160, yline, 70,objHeight, &fss->type, 15.0, OB_FLUIDSIM_FLUID, 20.0, 2.0, "Object represents a volume of fluid in the simulation.");
+ uiDefButS(block, ROW, REDRAWBUTSOBJECT ,"Obstacle", 230, yline, 70,objHeight, &fss->type, 15.0, OB_FLUIDSIM_OBSTACLE,20.0, 3.0, "Object is a fixed obstacle.");
+ yline -= lineHeight;
+
+ uiDefButS(block, ROW, REDRAWBUTSOBJECT ,"Inflow", 90, yline, 70,objHeight, &fss->type, 15.0, OB_FLUIDSIM_INFLOW, 20.0, 4.0, "Object adds fluid to the simulation.");
+ uiDefButS(block, ROW, REDRAWBUTSOBJECT ,"Outflow", 160, yline, 70,objHeight, &fss->type, 15.0, OB_FLUIDSIM_OUTFLOW, 20.0, 5.0, "Object removes fluid from the simulation.");
+ uiDefButS(block, ROW, B_FLUIDSIM_MAKEPART ,"Particle", 230, yline, 70,objHeight, &fss->type, 15.0, OB_FLUIDSIM_PARTICLE,20.0, 3.0, "Object is made a particle system to display particles generated by a fluidsim domain object.");
+ uiBlockEndAlign(block);
+ yline -= lineHeight;
+ yline -= 2*separateHeight;
+
+ /* display specific settings for each type */
+ if(fss->type == OB_FLUIDSIM_DOMAIN) {
+ const int maxRes = 512;
+ char memString[32];
+
+ // use mesh bounding box and object scaling
+ // TODO fix redraw issue
+ elbeemEstimateMemreq(fss->resolutionxyz,
+ ob->fluidsimSettings->bbSize[0],ob->fluidsimSettings->bbSize[1],ob->fluidsimSettings->bbSize[2], fss->maxRefine, memString);
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, ROW, REDRAWBUTSOBJECT, "Std", 0,yline, 25,objHeight, &fss->show_advancedoptions, 16.0, 0, 20.0, 0, "Show standard domain options.");
+ uiDefButS(block, ROW, REDRAWBUTSOBJECT, "Adv", 25,yline, 25,objHeight, &fss->show_advancedoptions, 16.0, 1, 20.0, 1, "Show advanced domain options.");
+ uiDefButS(block, ROW, REDRAWBUTSOBJECT, "Bnd", 50,yline, 25,objHeight, &fss->show_advancedoptions, 16.0, 2, 20.0, 2, "Show domain boundary options.");
+ uiBlockEndAlign(block);
+
+ uiDefBut(block, BUT, B_FLUIDSIM_BAKE, "BAKE",90, yline,210,objHeight, NULL, 0.0, 0.0, 10, 0, "Perform simulation and output and surface&preview meshes for each frame.");
+ yline -= lineHeight;
+ yline -= 2*separateHeight;
+
+ if(fss->show_advancedoptions == 0) {
+ uiDefBut(block, LABEL, 0, "Req. BAKE Memory:", 0,yline,150,objHeight, NULL, 0.0, 0, 0, 0, "");
+ uiDefBut(block, LABEL, 0, memString, 200,yline,100,objHeight, NULL, 0.0, 0, 0, 0, "");
+ yline -= lineHeight;
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, NUM, REDRAWBUTSOBJECT, "Resolution:", 0, yline,150,objHeight, &fss->resolutionxyz, 1, maxRes, 10, 0, "Domain resolution in X, Y and Z direction");
+ uiDefButS(block, NUM, B_DIFF, "Preview-Res.:", 150, yline,150,objHeight, &fss->previewresxyz, 1, 100, 10, 0, "Resolution of the preview meshes to generate, also in X, Y and Z direction");
+ uiBlockEndAlign(block);
+ yline -= lineHeight;
+ yline -= 1*separateHeight;
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_DIFF, "Start time:", 0, yline,150,objHeight, &fss->animStart, 0.0, 100.0, 10, 0, "Simulation time of the first blender frame.");
+ uiDefButF(block, NUM, B_DIFF, "End time:", 150, yline,150,objHeight, &fss->animEnd , 0.0, 100.0, 10, 0, "Simulation time of the last blender frame.");
+ uiBlockEndAlign(block);
+ yline -= lineHeight;
+ yline -= 2*separateHeight;
+
+ if((fss->guiDisplayMode<1) || (fss->guiDisplayMode>3)){ fss->guiDisplayMode=2; } // can be changed by particle setting
+ uiDefBut(block, LABEL, 0, "Disp.-Qual.:", 0,yline, 90,objHeight, NULL, 0.0, 0, 0, 0, "");
+ uiBlockBeginAlign(block);
+ uiDefButS(block, MENU, B_FLUIDSIM_FORCEREDRAW, "GuiDisplayMode%t|Geometry %x1|Preview %x2|Final %x3",
+ 90,yline,105,objHeight, &fss->guiDisplayMode, 0, 0, 0, 0, "How to display the fluid mesh in the Blender GUI.");
+ uiDefButS(block, MENU, B_DIFF, "RenderDisplayMode%t|Geometry %x1|Preview %x2|Final %x3",
+ 195,yline,105,objHeight, &fss->renderDisplayMode, 0, 0, 0, 0, "How to display the fluid mesh for rendering.");
+ uiBlockEndAlign(block);
+ yline -= lineHeight;
+ yline -= 1*separateHeight;
+
+ uiBlockBeginAlign(block);
+ uiDefIconBut(block, BUT, B_FLUIDSIM_SELDIR, ICON_FILESEL, 0, yline, 20, objHeight, 0, 0, 0, 0, 0, "Select Directory (and/or filename prefix) to store baked fluid simulation files in");
+ uiDefBut(block, TEX, B_FLUIDSIM_FORCEREDRAW,"", 20, yline, 280, objHeight, fss->surfdataPath, 0.0,79.0, 0, 0, "Enter Directory (and/or filename prefix) to store baked fluid simulation files in");
+ uiBlockEndAlign(block);
+ // FIXME what is the 79.0 above?
+ } else if(fss->show_advancedoptions == 1) {
+ // advanced options
+ uiDefBut(block, LABEL, 0, "Gravity:", 0, yline, 90,objHeight, NULL, 0.0, 0, 0, 0, "");
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_DIFF, "X:", 90, yline, 70,objHeight, &fss->gravx, -1000.1, 1000.1, 10, 0, "Gravity in X direction");
+ uiDefButF(block, NUM, B_DIFF, "Y:", 160, yline, 70,objHeight, &fss->gravy, -1000.1, 1000.1, 10, 0, "Gravity in Y direction");
+ uiDefButF(block, NUM, B_DIFF, "Z:", 230, yline, 70,objHeight, &fss->gravz, -1000.1, 1000.1, 10, 0, "Gravity in Z direction");
+ uiBlockEndAlign(block);
+ yline -= lineHeight;
+ yline -= 1*separateHeight;
+
+ /* viscosity */
+ if (fss->viscosityMode==1) /*manual*/
+ uiBlockBeginAlign(block);
+ uiDefButS(block, MENU, REDRAWVIEW3D, "Viscosity%t|Manual %x1|Water %x2|Oil %x3|Honey %x4",
+ 0,yline, 90,objHeight, &fss->viscosityMode, 0, 0, 0, 0, "Set viscosity of the fluid to a preset value, or use manual input.");
+ if(fss->viscosityMode==1) {
+ uiDefButF(block, NUM, B_DIFF, "Value:", 90, yline, 105,objHeight, &fss->viscosityValue, 0.0, 10.0, 10, 0, "Viscosity setting: value that is multiplied by 10 to the power of (exponent*-1).");
+ uiDefButS(block, NUM, B_DIFF, "Neg-Exp.:", 195, yline, 105,objHeight, &fss->viscosityExponent, 0, 10, 10, 0, "Negative exponent for the viscosity value (to simplify entering small values e.g. 5*10^-6.");
+ uiBlockEndAlign(block);
+ } else {
+ // display preset values
+ uiDefBut(block, LABEL, 0, fluidsimViscosityPresetString[fss->viscosityMode], 90,yline,200,objHeight, NULL, 0.0, 0, 0, 0, "");
+ }
+ yline -= lineHeight;
+ yline -= 1*separateHeight;
+
+ uiDefBut(block, LABEL, 0, "Realworld-size:", 0,yline,150,objHeight, NULL, 0.0, 0, 0, 0, "");
+ uiDefButF(block, NUM, B_DIFF, "", 150, yline,150,objHeight, &fss->realsize, 0.001, 10.0, 10, 0, "Size of the simulation domain in meters.");
+ yline -= lineHeight;
+ yline -= 2*separateHeight;
+
+ uiDefBut(block, LABEL, 0, "Gridlevels:", 0,yline,150,objHeight, NULL, 0.0, 0, 0, 0, "");
+ uiDefButI(block, NUM, B_DIFF, "", 150, yline,150,objHeight, &fss->maxRefine, -1, 4, 10, 0, "Number of coarsened Grids to use (set to -1 for automatic selection).");
+ yline -= lineHeight;
+
+ uiDefBut(block, LABEL, 0, "Compressibility:", 0,yline,150,objHeight, NULL, 0.0, 0, 0, 0, "");
+ uiDefButF(block, NUM, B_DIFF, "", 150, yline,150,objHeight, &fss->gstar, 0.001, 0.10, 10,0, "Allowed compressibility due to gravitational force for standing fluid (directly affects simulation step size).");
+ yline -= lineHeight;
+
+ } else if(fss->show_advancedoptions == 2) {
+ // copied from obstacle...
+ //yline -= lineHeight + 5;
+ //uiDefBut(block, LABEL, 0, "Domain boundary type settings:", 0,yline,300,objHeight, NULL, 0.0, 0, 0, 0, "");
+ //yline -= lineHeight;
+
+ uiBlockBeginAlign(block); // domain
+ uiDefButS(block, ROW, REDRAWBUTSOBJECT ,"Noslip", 0, yline,100,objHeight, &fss->typeFlags, 15.0, OB_FSBND_NOSLIP, 20.0, 1.0, "Obstacle causes zero normal and tangential velocity (=sticky). Default for all. Only option for moving objects.");
+ uiDefButS(block, ROW, REDRAWBUTSOBJECT ,"Part", 100, yline,100,objHeight, &fss->typeFlags, 15.0, OB_FSBND_PARTSLIP, 20.0, 2.0, "Mix between no-slip and free-slip. Non moving objects only!");
+ uiDefButS(block, ROW, REDRAWBUTSOBJECT ,"Free", 200, yline,100,objHeight, &fss->typeFlags, 15.0, OB_FSBND_FREESLIP, 20.0, 3.0, "Obstacle only causes zero normal velocity (=not sticky). Non moving objects only!");
+ uiBlockEndAlign(block);
+ yline -= lineHeight;
+
+ if(fss->typeFlags&OB_FSBND_PARTSLIP) {
+ uiDefBut(block, LABEL, 0, "PartSlipValue:", 0,yline,200,objHeight, NULL, 0.0, 0, 0, 0, "");
+ uiDefButF(block, NUM, B_DIFF, "", 200, yline,100,objHeight, &fss->partSlipValue, 0.0, 1.0, 10,0, ".");
+ yline -= lineHeight;
+ } else {
+ //uiDefBut(block, LABEL, 0, "-", 200,yline,100,objHeight, NULL, 0.0, 0, 0, 0, "");
+ }
+ // copied from obstacle...
+
+ uiDefBut(block, LABEL, 0, "Tracer Particles:", 0,yline,200,objHeight, NULL, 0.0, 0, 0, 0, "");
+ uiDefButI(block, NUM, B_DIFF, "", 200, yline,100,objHeight, &fss->generateTracers, 0.0, 10000.0, 10,0, "Number of tracer particles to generate.");
+ yline -= lineHeight;
+ uiDefBut(block, LABEL, 0, "Generate Particles:", 0,yline,200,objHeight, NULL, 0.0, 0, 0, 0, "");
+ uiDefButF(block, NUM, B_DIFF, "", 200, yline,100,objHeight, &fss->generateParticles, 0.0, 10.0, 10,0, "Amount of particles to generate (0=off, 1=normal, >1=more).");
+ yline -= lineHeight;
+ uiDefBut(block, LABEL, 0, "Surface Subdiv:", 0,yline,200,objHeight, NULL, 0.0, 0, 0, 0, "");
+ uiDefButI(block, NUM, B_DIFF, "", 200, yline,100,objHeight, &fss->surfaceSubdivs, 0.0, 5.0, 10,0, "Number of isosurface subdivisions. This is necessary for the inclusion of particles into the surface generation. Warning - can lead to longer computation times!");
+ yline -= lineHeight;
+
+ uiDefBut(block, LABEL, 0, "Surface Smoothing:", 0,yline,200,objHeight, NULL, 0.0, 0, 0, 0, "");
+ uiDefButF(block, NUM, B_DIFF, "", 200, yline,100,objHeight, &fss->surfaceSmoothing, 0.0, 5.0, 10,0, "Amount of surface smoothing (0=off, 1=normal, >1=stronger smoothing).");
+ yline -= lineHeight;
+
+ // use new variable...
+ uiDefBut(block, LABEL, 0, "Generate&Use SpeedVecs:", 0,yline,200,objHeight, NULL, 0.0, 0, 0, 0, "");
+ uiDefButBitC(block, TOG, 1, REDRAWBUTSOBJECT, "Disable", 200, yline,100,objHeight, &fss->domainNovecgen, 0, 0, 0, 0, "Default is to generate and use fluidsim vertex speed vectors, this option switches calculation off during bake, and disables loading.");
+ yline -= lineHeight;
+ } // domain 3
+ }
+ else if(
+ (fss->type == OB_FLUIDSIM_FLUID)
+ || (fss->type == OB_FLUIDSIM_INFLOW)
+ ) {
+ uiBlockBeginAlign(block); // fluid
+ uiDefButC(block, ROW, REDRAWBUTSOBJECT ,"Init Volume", 0, yline,100,objHeight, &fss->volumeInitType, 15.0, 1, 20.0, 1.0, "Type of volume init: use only inner region of mesh.");
+ uiDefButC(block, ROW, REDRAWBUTSOBJECT ,"Init Shell", 100, yline,100,objHeight, &fss->volumeInitType, 15.0, 2, 20.0, 2.0, "Type of volume init: use only the hollow shell defined by the faces of the mesh.");
+ uiDefButC(block, ROW, REDRAWBUTSOBJECT ,"Init Both", 200, yline,100,objHeight, &fss->volumeInitType, 15.0, 3, 20.0, 3.0, "Type of volume init: use both the inner volume and the outer shell.");
+ uiBlockEndAlign(block);
+ yline -= lineHeight;
+
+ yline -= lineHeight + 5; // fluid + inflow
+ if(fss->type == OB_FLUIDSIM_FLUID) uiDefBut(block, LABEL, 0, "Initial velocity:", 0,yline,200,objHeight, NULL, 0.0, 0, 0, 0, "");
+ if(fss->type == OB_FLUIDSIM_INFLOW) uiDefBut(block, LABEL, 0, "Inflow velocity:", 0,yline,200,objHeight, NULL, 0.0, 0, 0, 0, "");
+ yline -= lineHeight;
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_DIFF, "X:", 0, yline, 100,objHeight, &fss->iniVelx, -1000.1, 1000.1, 10, 0, "Fluid velocity in X direction");
+ uiDefButF(block, NUM, B_DIFF, "Y:", 100, yline, 100,objHeight, &fss->iniVely, -1000.1, 1000.1, 10, 0, "Fluid velocity in Y direction");
+ uiDefButF(block, NUM, B_DIFF, "Z:", 200, yline, 100,objHeight, &fss->iniVelz, -1000.1, 1000.1, 10, 0, "Fluid velocity in Z direction");
+ uiBlockEndAlign(block);
+ yline -= lineHeight;
+
+ if(fss->type == OB_FLUIDSIM_INFLOW) { // inflow
+ uiDefBut(block, LABEL, 0, "Local Inflow Coords", 0,yline,200,objHeight, NULL, 0.0, 0, 0, 0, "");
+ uiDefButBitS(block, TOG, OB_FSINFLOW_LOCALCOORD, REDRAWBUTSOBJECT, "Enable", 200, yline,100,objHeight, &fss->typeFlags, 0, 0, 0, 0, "Use local coordinates for inflow (e.g. for rotating objects).");
+ yline -= lineHeight;
+ } else {
+ }
+
+ // domainNovecgen "misused" here
+ uiDefBut(block, LABEL, 0, "Animated Mesh:", 0,yline,200,objHeight, NULL, 0.0, 0, 0, 0, "");
+ uiDefButBitC(block, TOG, 1, REDRAWBUTSOBJECT, "Export", 200, yline,100,objHeight, &fss->domainNovecgen, 0, 0, 0, 0, "Export this mesh as an animated one. Slower, only use if really necessary (e.g. armatures or parented objects), animated pos/rot/scale IPOs do not require it.");
+ yline -= lineHeight;
+
+ } // fluid inflow
+ else if( (fss->type == OB_FLUIDSIM_OUTFLOW) ) {
+ yline -= lineHeight + 5;
+
+ uiBlockBeginAlign(block); // outflow
+ uiDefButC(block, ROW, REDRAWBUTSOBJECT ,"Init Volume", 0, yline,100,objHeight, &fss->volumeInitType, 15.0, 1, 20.0, 1.0, "Type of volume init: use only inner region of mesh.");
+ uiDefButC(block, ROW, REDRAWBUTSOBJECT ,"Init Shell", 100, yline,100,objHeight, &fss->volumeInitType, 15.0, 2, 20.0, 2.0, "Type of volume init: use only the hollow shell defined by the faces of the mesh.");
+ uiDefButC(block, ROW, REDRAWBUTSOBJECT ,"Init Both", 200, yline,100,objHeight, &fss->volumeInitType, 15.0, 3, 20.0, 3.0, "Type of volume init: use both the inner volume and the outer shell.");
+ uiBlockEndAlign(block);
+ yline -= lineHeight;
+
+ // domainNovecgen "misused" here
+ uiDefBut(block, LABEL, 0, "Animated Mesh:", 0,yline,200,objHeight, NULL, 0.0, 0, 0, 0, "");
+ uiDefButBitC(block, TOG, 1, REDRAWBUTSOBJECT, "Export", 200, yline,100,objHeight, &fss->domainNovecgen, 0, 0, 0, 0, "Export this mesh as an animated one. Slower, only use if really necessary (e.g. armatures or parented objects), animated pos/rot/scale IPOs do not require it.");
+ yline -= lineHeight;
+
+ //uiDefBut(block, LABEL, 0, "No additional settings as of now...", 0,yline,300,objHeight, NULL, 0.0, 0, 0, 0, "");
+ }
+ else if( (fss->type == OB_FLUIDSIM_OBSTACLE) ) {
+ yline -= lineHeight + 5; // obstacle
+
+ uiBlockBeginAlign(block); // obstacle
+ uiDefButC(block, ROW, REDRAWBUTSOBJECT ,"Init Volume", 0, yline,100,objHeight, &fss->volumeInitType, 15.0, 1, 20.0, 1.0, "Type of volume init: use only inner region of mesh.");
+ uiDefButC(block, ROW, REDRAWBUTSOBJECT ,"Init Shell", 100, yline,100,objHeight, &fss->volumeInitType, 15.0, 2, 20.0, 2.0, "Type of volume init: use only the hollow shell defined by the faces of the mesh.");
+ uiDefButC(block, ROW, REDRAWBUTSOBJECT ,"Init Both", 200, yline,100,objHeight, &fss->volumeInitType, 15.0, 3, 20.0, 3.0, "Type of volume init: use both the inner volume and the outer shell.");
+ uiBlockEndAlign(block);
+ yline -= lineHeight;
+
+ uiBlockBeginAlign(block); // obstacle
+ uiDefButS(block, ROW, REDRAWBUTSOBJECT ,"Noslip", 0, yline,100,objHeight, &fss->typeFlags, 15.0, OB_FSBND_NOSLIP, 20.0, 1.0, "Obstacle causes zero normal and tangential velocity (=sticky). Default for all. Only option for moving objects.");
+ uiDefButS(block, ROW, REDRAWBUTSOBJECT ,"Part", 100, yline,100,objHeight, &fss->typeFlags, 15.0, OB_FSBND_PARTSLIP, 20.0, 2.0, "Mix between no-slip and free-slip. Non moving objects only!");
+ uiDefButS(block, ROW, REDRAWBUTSOBJECT ,"Free", 200, yline,100,objHeight, &fss->typeFlags, 15.0, OB_FSBND_FREESLIP, 20.0, 3.0, "Obstacle only causes zero normal velocity (=not sticky). Non moving objects only!");
+ uiBlockEndAlign(block);
+ yline -= lineHeight;
+
+ // domainNovecgen "misused" here
+ uiDefBut(block, LABEL, 0, "Animated Mesh:", 0,yline,200,objHeight, NULL, 0.0, 0, 0, 0, "");
+ uiDefButBitC(block, TOG, 1, REDRAWBUTSOBJECT, "Export", 200, yline,100,objHeight, &fss->domainNovecgen, 0, 0, 0, 0, "Export this mesh as an animated one. Slower, only use if really necessary (e.g. armatures or parented objects), animated loc/rot/scale IPOs do not require it.");
+ yline -= lineHeight;
+
+ uiDefBut(block, LABEL, 0, "PartSlip Amount:", 0,yline,200,objHeight, NULL, 0.0, 0, 0, 0, "");
+ if(fss->typeFlags&OB_FSBND_PARTSLIP) {
+ uiDefButF(block, NUM, B_DIFF, "", 200, yline,100,objHeight, &fss->partSlipValue, 0.0, 1.0, 10,0, "Amount of mixing between no- and free-slip, 0=stickier, 1=same as free slip.");
+ } else { uiDefBut(block, LABEL, 0, "-", 200,yline,100,objHeight, NULL, 0.0, 0, 0, 0, ""); }
+ yline -= lineHeight;
+
+ // generateParticles "misused" here
+ uiDefBut(block, LABEL, 0, "Impact Factor:", 0,yline,200,objHeight, NULL, 0.0, 0, 0, 0, "");
+ uiDefButF(block, NUM, B_DIFF, "", 200, yline,100,objHeight, &fss->surfaceSmoothing, -2.0, 10.0, 10,0, "This is an unphysical value for moving objects - it controls the impact an obstacle has on the fluid, =0 behaves a bit like outflow (deleting fluid), =1 is default, while >1 results in high forces. Can be used to tweak total mass.");
+ yline -= lineHeight;
+
+ yline -= lineHeight; // obstacle
+ }
+ else if(fss->type == OB_FLUIDSIM_PARTICLE) {
+
+ //fss->type == 0; // off, broken...
+ if(1) {
+ // limited selection, old fixed: fss->typeFlags = (1<<5)|(1<<1);
+# define PARTBUT_WIDTH (300/3)
+ uiDefButBitS(block, TOG, (1<<2) , REDRAWBUTSOBJECT, "Drops", 0*PARTBUT_WIDTH, yline, PARTBUT_WIDTH,objHeight, &fss->typeFlags, 0, 0, 0, 0, "Show drop particles.");
+ uiDefButBitS(block, TOG, (1<<4) , REDRAWBUTSOBJECT, "Floats", 1*PARTBUT_WIDTH, yline, PARTBUT_WIDTH,objHeight, &fss->typeFlags, 0, 0, 0, 0, "Show floating foam particles.");
+ uiDefButBitS(block, TOG, (1<<5) , REDRAWBUTSOBJECT, "Tracer", 2*PARTBUT_WIDTH, yline, PARTBUT_WIDTH,objHeight, &fss->typeFlags, 0, 0, 0, 0, "Show tracer particles.");
+ yline -= lineHeight;
+# undef PARTBUT_WIDTH
+
+
+ uiDefBut(block, LABEL, 0, "Size Influence:", 0,yline,150,objHeight, NULL, 0.0, 0, 0, 0, "");
+ uiDefButF(block, NUM, B_DIFF, "", 150, yline,150,objHeight, &fss->particleInfSize, 0.0, 2.0, 10,0, "Amount of particle size scaling: 0=off (all same size), 1=full (range 0.2-2.0), >1=stronger.");
+ yline -= lineHeight;
+ uiDefBut(block, LABEL, 0, "Alpha Influence:", 0,yline,150,objHeight, NULL, 0.0, 0, 0, 0, "");
+ uiDefButF(block, NUM, B_DIFF, "", 150, yline,150,objHeight, &fss->particleInfAlpha, 0.0, 2.0, 10,0, "Amount of particle alpha change, inverse of size influence: 0=off (all same alpha), 1=full (large particles get lower alphas, smaller ones higher values).");
+ yline -= lineHeight;
+
+ yline -= 1*separateHeight;
+
+ // FSPARTICLE also select input files
+ uiBlockBeginAlign(block);
+ uiDefIconBut(block, BUT, B_FLUIDSIM_SELDIR, ICON_FILESEL, 0, yline, 20, objHeight, 0, 0, 0, 0, 0, "Select fluid simulation bake directory/prefix to load particles from, same as for domain object.");
+ uiDefBut(block, TEX, B_FLUIDSIM_FORCEREDRAW,"", 20, yline, 280, objHeight, fss->surfdataPath, 0.0,79.0, 0, 0, "Enter fluid simulation bake directory/prefix to load particles from, same as for domain object.");
+ uiBlockEndAlign(block);
+ yline -= lineHeight;
+ } // disabled for now...
+
+ }
+ else {
+ yline -= lineHeight + 5;
+ /* not yet set */
+ uiDefBut(block, LABEL, 0, "Select object type for simulation", 0,yline,300,objHeight, NULL, 0.0, 0, 0, 0, "");
+ yline -= lineHeight;
+ }
+ return;
+
+ } else {
+ msg = "Object not enabled for fluid simulation...";
+ }
+ } else {
+ msg = "Only Mesh Objects can participate.";
+ }
+errMessage:
+ yline -= lineHeight + 5;
+ uiDefBut(block, LABEL, 0, msg, 0,yline,300,objHeight, NULL, 0.0, 0, 0, 0, "");
+ yline -= lineHeight;
+
+#endif // DISABLE_ELBEEM
+}
+
+void object_panels()
+{
+ Object *ob;
+
+ /* check context here */
+ ob= OBACT;
+ if(ob) {
+ object_panel_object(ob);
+ object_panel_anim(ob);
+ object_panel_draw(ob);
+ object_panel_constraint("Object");
+
+ uiClearButLock();
+ }
+}
+
+void physics_panels()
+{
+ Object *ob;
+
+ /* check context here */
+ ob= OBACT;
+ if(ob) {
+ object_panel_fields(ob);
+ object_panel_particles(ob);
+ object_panel_particles_motion(ob);
+ object_softbodies(ob);
+ object_softbodies_II(ob);
+ object_panel_fluidsim(ob);
+ }
+}
diff --git a/source/blender/src/buttons_scene.c b/source/blender/src/buttons_scene.c
new file mode 100644
index 00000000000..c734eac0735
--- /dev/null
+++ b/source/blender/src/buttons_scene.c
@@ -0,0 +1,2070 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <time.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+#include "DNA_node_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_sound_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_packedFile_types.h"
+
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_node.h"
+#include "BKE_library.h"
+#include "BKE_scene.h"
+#include "BKE_sound.h"
+#include "BKE_packedFile.h"
+#include "BKE_utildefines.h"
+
+#include "BLI_blenlib.h"
+
+#include "BSE_filesel.h"
+
+#include "BIF_gl.h"
+#include "BIF_graphics.h"
+#include "BIF_glutil.h"
+#include "BIF_interface.h"
+#include "BIF_imasel.h"
+#include "BIF_keyval.h"
+#include "BIF_mainqueue.h"
+#include "BIF_mywindow.h"
+#include "BIF_meshtools.h"
+#include "BIF_resources.h"
+#include "BIF_renderwin.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_toolbox.h"
+
+#include "BIF_butspace.h"
+
+#include "mydevice.h"
+#include "blendef.h"
+
+/* -----includes for this file specific----- */
+
+#include "DNA_image_types.h"
+
+#include "BKE_writeavi.h"
+#include "BKE_writeffmpeg.h"
+#include "BKE_image.h"
+
+#include "BLI_threads.h"
+
+#include "BIF_editsound.h"
+#include "BIF_writeimage.h"
+#include "BIF_writeavicodec.h"
+
+#include "BSE_seqaudio.h"
+#include "BSE_headerbuttons.h"
+
+#include "RE_pipeline.h"
+
+#include "butspace.h" // own module
+
+#ifdef WITH_QUICKTIME
+#include "quicktime_export.h"
+#endif
+
+#ifdef WITH_FFMPEG
+
+#include <ffmpeg/avcodec.h> /* for PIX_FMT_* and CODEC_ID_* */
+#include <ffmpeg/avformat.h>
+
+static int ffmpeg_preset_sel = 0;
+
+extern int is_container(int);
+
+extern void makeffmpegstring(char* string);
+
+#endif
+
+/* here the calls for scene buttons
+ - render
+ - world
+ - anim settings, audio
+*/
+
+/* prototypes */
+void playback_anim(void);
+
+/* ************************ SOUND *************************** */
+static void load_new_sample(char *str) /* called from fileselect */
+{
+ char name[FILE_MAX];
+ bSound *sound;
+ bSample *sample, *newsample;
+
+ sound = G.buts->lockpoin;
+
+ if (sound) {
+ // save values
+ sample = sound->sample;
+ strcpy(name, sound->sample->name);
+
+ strcpy(sound->name, str);
+ sound_set_sample(sound, NULL);
+ sound_initialize_sample(sound);
+
+ if (sound->sample->type == SAMPLE_INVALID) {
+ error("Not a valid sample: %s", str);
+
+ newsample = sound->sample;
+
+ // restore values
+ strcpy(sound->name, name);
+ sound_set_sample(sound, sample);
+
+ // remove invalid sample
+
+ sound_free_sample(newsample);
+ BLI_remlink(samples, newsample);
+ MEM_freeN(newsample);
+ }
+ }
+
+ BIF_undo_push("Load new audio file");
+ allqueue(REDRAWBUTSSCENE, 0);
+
+}
+
+
+void do_soundbuts(unsigned short event)
+{
+ char name[FILE_MAX];
+ bSound *sound;
+ bSample *sample;
+ bSound* tempsound;
+ ID *id;
+
+ sound = G.buts->lockpoin;
+
+ switch(event) {
+ case B_SOUND_REDRAW:
+ allqueue(REDRAWBUTSSCENE, 0);
+ break;
+
+ case B_SOUND_LOAD_SAMPLE:
+ if (sound) strcpy(name, sound->name);
+ else strcpy(name, U.sounddir);
+
+ activate_fileselect(FILE_SPECIAL, "SELECT WAV FILE", name, load_new_sample);
+ break;
+
+ case B_SOUND_PLAY_SAMPLE:
+ if (sound) {
+ if (sound->sample->type != SAMPLE_INVALID) {
+ sound_play_sound(sound);
+ allqueue(REDRAWBUTSSCENE, 0);
+ }
+ }
+ break;
+
+ case B_SOUND_MENU_SAMPLE:
+ if (G.buts->menunr > 0) {
+ sample = BLI_findlink(samples, G.buts->menunr - 1);
+ if (sample && sound) {
+ BLI_strncpy(sound->name, sample->name, sizeof(sound->name));
+ sound_set_sample(sound, sample);
+ do_soundbuts(B_SOUND_REDRAW);
+ }
+ }
+
+ break;
+ case B_SOUND_NAME_SAMPLE:
+ load_new_sample(sound->name);
+ break;
+
+ case B_SOUND_UNPACK_SAMPLE:
+ if(sound && sound->sample) {
+ sample = sound->sample;
+
+ if (sample->packedfile) {
+ if (G.fileflags & G_AUTOPACK) {
+ if (okee("Disable AutoPack ?")) {
+ G.fileflags &= ~G_AUTOPACK;
+ }
+ }
+
+ if ((G.fileflags & G_AUTOPACK) == 0) {
+ unpackSample(sample, PF_ASK);
+ }
+ } else {
+ sound_set_packedfile(sample, newPackedFile(sample->name));
+ }
+ allqueue(REDRAWHEADERS, 0);
+ do_soundbuts(B_SOUND_REDRAW);
+ }
+ break;
+
+ case B_SOUND_COPY_SOUND:
+ if (sound) {
+ tempsound = sound_make_copy(sound);
+ sound = tempsound;
+ id = &sound->id;
+ G.buts->lockpoin = (bSound*)id;
+ BIF_undo_push("Copy sound");
+ do_soundbuts(B_SOUND_REDRAW);
+ }
+ break;
+
+ case B_SOUND_RECALC:
+ waitcursor(1);
+ sound = G.main->sound.first;
+ while (sound) {
+ free(sound->stream);
+ sound->stream = 0;
+ audio_makestream(sound);
+ sound = (bSound *) sound->id.next;
+ }
+ waitcursor(0);
+ allqueue(REDRAWSEQ, 0);
+ break;
+
+ case B_SOUND_RATECHANGED:
+
+ allqueue(REDRAWBUTSSCENE, 0);
+ allqueue(REDRAWSEQ, 0);
+ break;
+
+ case B_SOUND_MIXDOWN:
+ audio_mixdown();
+ break;
+
+ default:
+ if (G.f & G_DEBUG) {
+ printf("do_soundbuts: unhandled event %d\n", event);
+ }
+ }
+}
+
+
+static void sound_panel_listener(void)
+{
+ uiBlock *block;
+ int xco= 100, yco=100, mixrate;
+ char mixrateinfo[256];
+
+ block= uiNewBlock(&curarea->uiblocks, "sound_panel_listener", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Listener", "Sound", 320, 0, 318, 204)==0) return;
+
+ mixrate = sound_get_mixrate();
+ sprintf(mixrateinfo, "Game Mixrate: %d Hz", mixrate);
+ uiDefBut(block, LABEL, 0, mixrateinfo, xco,yco,295,20, 0, 0, 0, 0, 0, "");
+
+ yco -= 30;
+ uiDefBut(block, LABEL, 0, "Game listener settings:",xco,yco,195,20, 0, 0, 0, 0, 0, "");
+
+ yco -= 30;
+ uiDefButF(block, NUMSLI, B_SOUND_CHANGED, "Volume: ",
+ xco,yco,195,24,&G.listener->gain, 0.0, 1.0, 1.0, 0, "Sets the maximum volume for the overall sound");
+
+ yco -= 30;
+ uiDefBut(block, LABEL, 0, "Game Doppler effect settings:",xco,yco,195,20, 0, 0, 0, 0, 0, "");
+
+ yco -= 30;
+ uiDefButF(block, NUMSLI, B_SOUND_CHANGED, "Doppler: ",
+ xco,yco,195,24,&G.listener->dopplerfactor, 0.0, 10.0, 1.0, 0, "Use this for scaling the doppler effect");
+
+ yco -=30;
+ uiDefButF(block, NUMSLI, B_SOUND_CHANGED, "Velocity: ",
+ xco,yco,195,24,&G.listener->dopplervelocity,0.0,10000.0, 1.0,0, "Sets the propagation speed of sound");
+
+
+}
+
+static void sound_panel_sequencer(void)
+{
+ uiBlock *block;
+ short xco, yco;
+ char mixrateinfo[256];
+
+ block= uiNewBlock(&curarea->uiblocks, "sound_panel_sequencer", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Sequencer", "Sound", 640, 0, 318, 204)==0) return;
+
+ /* audio sequence engine settings ------------------------------------------------------------------ */
+
+ xco = 1010;
+ yco = 195;
+
+ uiDefBut(block, LABEL, 0, "Audio sequencer settings", xco,yco,295,20, 0, 0, 0, 0, 0, "");
+
+ yco -= 25;
+ sprintf(mixrateinfo, "Mixing/Sync (latency: %d ms)", (int)( (((float)U.mixbufsize)/(float)G.scene->audio.mixrate)*1000.0 ) );
+ uiDefBut(block, LABEL, 0, mixrateinfo, xco,yco,295,20, 0, 0, 0, 0, 0, "");
+
+ yco -= 25;
+ uiDefButI(block, ROW, B_SOUND_RATECHANGED, "44.1 kHz", xco,yco,75,20, &G.scene->audio.mixrate, 2.0, 44100.0, 0, 0, "Mix at 44.1 kHz");
+ uiDefButI(block, ROW, B_SOUND_RATECHANGED, "48.0 kHz", xco+80,yco,75,20, &G.scene->audio.mixrate, 2.0, 48000.0, 0, 0, "Mix at 48 kHz");
+ uiDefBut(block, BUT, B_SOUND_RECALC, "Recalc", xco+160,yco,75,20, 0, 0, 0, 0, 0, "Recalculate samples");
+
+ yco -= 25;
+ uiDefButBitS(block, TOG, AUDIO_SYNC, B_SOUND_CHANGED, "Sync", xco,yco,115,20, &G.scene->audio.flag, 0, 0, 0, 0, "Use sample clock for syncing animation to audio");
+ uiDefButBitS(block, TOG, AUDIO_SCRUB, B_SOUND_CHANGED, "Scrub", xco+120,yco,115,20, &G.scene->audio.flag, 0, 0, 0, 0, "Scrub when changing frames");
+
+ yco -= 25;
+ uiDefBut(block, LABEL, 0, "Main mix", xco,yco,295,20, 0, 0, 0, 0, 0, "");
+
+ yco -= 25;
+ uiDefButF(block, NUMSLI, B_SOUND_CHANGED, "Main (dB): ",
+ xco,yco,235,24,&G.scene->audio.main, -24.0, 6.0, 0, 0, "Set the audio master gain/attenuation in dB");
+
+ yco -= 25;
+ uiDefButBitS(block, TOG, AUDIO_MUTE, 0, "Mute", xco,yco,235,24, &G.scene->audio.flag, 0, 0, 0, 0, "Mute audio from sequencer");
+
+ yco -= 35;
+ uiDefBut(block, BUT, B_SOUND_MIXDOWN, "MIXDOWN", xco,yco,235,24, 0, 0, 0, 0, 0, "Create WAV file from sequenced audio (output goes to render output dir)");
+
+}
+
+static char *make_sample_menu(void)
+{
+ int len= BLI_countlist(samples); /* BKE_sound.h */
+
+ if(len) {
+ bSample *sample;
+ char *str;
+ int nr, a=0;
+
+ str= MEM_callocN(32*len, "menu");
+
+ for(nr=1, sample= samples->first; sample; sample= sample->id.next, nr++) {
+ a+= sprintf(str+a, "|%s %%x%d", sample->id.name+2, nr);
+ }
+ return str;
+ }
+ return NULL;
+}
+
+static void sound_panel_sound(bSound *sound)
+{
+ static int packdummy=0;
+ ID *id, *idfrom;
+ uiBlock *block;
+ bSample *sample;
+ char *strp, ch[256];
+
+ block= uiNewBlock(&curarea->uiblocks, "sound_panel_sound", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Sound", "Sound", 0, 0, 318, 204)==0) return;
+
+ uiDefBut(block, LABEL, 0, "Blender Sound block",10,180,195,20, 0, 0, 0, 0, 0, "");
+
+ // warning: abuse of texnr here! (ton didnt code!)
+ buttons_active_id(&id, &idfrom);
+ std_libbuttons(block, 10, 160, 0, NULL, B_SOUNDBROWSE2, ID_SO, 0, id, idfrom, &(G.buts->texnr), 1, 0, 0, 0, 0);
+
+ if (sound) {
+
+ uiDefBut(block, BUT, B_SOUND_COPY_SOUND, "Copy sound", 220,160,90,20, 0, 0, 0, 0, 0, "Make another copy (duplicate) of the current sound");
+
+ uiSetButLock(sound->id.lib!=0, ERROR_LIBDATA_MESSAGE);
+ sound_initialize_sample(sound);
+ sample = sound->sample;
+
+ /* info string */
+ if (sound->sample && sound->sample->len) {
+ char *tmp;
+ if (sound->sample->channels == 1) tmp= "Mono";
+ else if (sound->sample->channels == 2) tmp= "Stereo";
+ else tmp= "Unknown";
+
+ sprintf(ch, "Sample: %s, %d bit, %d Hz, %d samples", tmp, sound->sample->bits, sound->sample->rate, (sound->sample->len/(sound->sample->bits/8)/sound->sample->channels));
+ uiDefBut(block, LABEL, 0, ch, 35,140,225,20, 0, 0, 0, 0, 0, "");
+ }
+ else {
+ uiDefBut(block, LABEL, 0, "Sample: No sample info available.",35,140,225,20, 0, 0, 0, 0, 0, "");
+ }
+
+ /* sample browse buttons */
+ uiBlockBeginAlign(block);
+ strp= make_sample_menu();
+ if (strp) {
+ uiDefButS(block, MENU, B_SOUND_MENU_SAMPLE, strp, 10,120,23,20, &(G.buts->menunr), 0, 0, 0, 0, "Select another loaded sample");
+ MEM_freeN(strp);
+ }
+ uiDefBut(block, TEX, B_SOUND_NAME_SAMPLE, "", 35,120,250,20, sound->name, 0.0, 79.0, 0, 0, "The sample file used by this Sound");
+
+ if (sound->sample->packedfile) packdummy = 1;
+ else packdummy = 0;
+
+ uiDefIconButBitI(block, TOG, 1, B_SOUND_UNPACK_SAMPLE, ICON_PACKAGE,
+ 285, 120,25,20, &packdummy, 0, 0, 0, 0,"Pack/Unpack this sample");
+
+ uiBlockBeginAlign(block);
+ uiDefBut(block, BUT, B_SOUND_LOAD_SAMPLE, "Load sample", 10, 95,150,24, 0, 0, 0, 0, 0, "Load a different sample file");
+
+ uiDefBut(block, BUT, B_SOUND_PLAY_SAMPLE, "Play", 160, 95, 150, 24, 0, 0.0, 0, 0, 0, "Playback sample using settings below");
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUMSLI, B_SOUND_CHANGED, "Volume: ",
+ 10,70,150,20, &sound->volume, 0.0, 1.0, 0, 0, "Game engine only: Set the volume of this sound");
+
+ uiDefButF(block, NUMSLI, B_SOUND_CHANGED, "Pitch: ",
+ 160,70,150,20, &sound->pitch, -12.0, 12.0, 0, 0, "Game engine only: Set the pitch of this sound");
+
+ /* looping */
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOG, SOUND_FLAGS_LOOP, B_SOUND_REDRAW, "Loop",
+ 10, 50, 95, 20, &sound->flags, 0.0, 0.0, 0, 0, "Game engine only: Toggle between looping on/off");
+
+ if (sound->flags & SOUND_FLAGS_LOOP) {
+ uiDefButBitI(block, TOG, SOUND_FLAGS_BIDIRECTIONAL_LOOP, B_SOUND_REDRAW, "Ping Pong",
+ 105, 50, 95, 20, &sound->flags, 0.0, 0.0, 0, 0, "Game engine only: Toggle between A->B and A->B->A looping");
+
+ }
+
+
+ /* 3D settings ------------------------------------------------------------------ */
+ uiBlockBeginAlign(block);
+
+ if (sound->sample->channels == 1) {
+ uiDefButBitI(block, TOG, SOUND_FLAGS_3D, B_SOUND_REDRAW, "3D Sound",
+ 10, 10, 90, 20, &sound->flags, 0, 0, 0, 0, "Game engine only: Turns 3D sound on");
+
+ if (sound->flags & SOUND_FLAGS_3D) {
+ uiDefButF(block, NUMSLI, B_SOUND_CHANGED, "Scale: ",
+ 100,10,210,20, &sound->attenuation, 0.0, 5.0, 1.0, 0, "Game engine only: Sets the surround scaling factor for this sound");
+
+ }
+ }
+ }
+}
+
+
+/* ************************* SCENE *********************** */
+
+
+static void output_pic(char *name)
+{
+ strcpy(G.scene->r.pic, name);
+ allqueue(REDRAWBUTSSCENE, 0);
+ BIF_undo_push("Change output picture directory");
+}
+
+static void backbuf_pic(char *name)
+{
+ Image *ima;
+
+ strcpy(G.scene->r.backbuf, name);
+ allqueue(REDRAWBUTSSCENE, 0);
+
+ ima= BKE_add_image_file(name);
+ if(ima)
+ BKE_image_signal(ima, NULL, IMA_SIGNAL_RELOAD);
+
+ BIF_undo_push("Change background picture");
+}
+
+static void ftype_pic(char *name)
+{
+ strcpy(G.scene->r.ftype, name);
+ allqueue(REDRAWBUTSSCENE, 0);
+}
+
+static void run_playanim(char *file)
+{
+ extern char bprogname[]; /* usiblender.c */
+ char str[FILE_MAX];
+ int pos[2], size[2];
+
+ /* use current settings for defining position of window. it actually should test image size */
+ calc_renderwin_rectangle((G.scene->r.xsch*G.scene->r.size)/100,
+ (G.scene->r.ysch*G.scene->r.size)/100, G.winpos, pos, size);
+#ifdef WIN32
+ sprintf(str, "%s -a -p %d %d \"%s\"", bprogname, pos[0], pos[1], file);
+#else
+ sprintf(str, "\"%s\" -a -p %d %d \"%s\"", bprogname, pos[0], pos[1], file);
+#endif
+ system(str);
+}
+
+void playback_anim(void)
+{
+ char file[FILE_MAX];
+
+ if(BKE_imtype_is_movie(G.scene->r.imtype)) {
+ switch (G.scene->r.imtype) {
+#ifdef WITH_QUICKTIME
+ case R_QUICKTIME:
+ makeqtstring(file);
+ break;
+#endif
+#ifdef WITH_FFMPEG
+ case R_FFMPEG:
+ makeffmpegstring(file);
+ break;
+#endif
+ default:
+ makeavistring(&G.scene->r, file);
+ break;
+ }
+ if(BLI_exist(file)) {
+ run_playanim(file);
+ }
+ else error("Can't find movie: %s", file);
+ }
+ else {
+ BKE_makepicstring(file, G.scene->r.pic, G.scene->r.sfra, G.scene->r.imtype);
+ if(BLI_exist(file)) {
+ run_playanim(file);
+ }
+ else error("Can't find image: %s", file);
+ }
+}
+
+#ifdef WITH_FFMPEG
+static void set_ffmpeg_preset(int preset);
+#endif
+
+void do_render_panels(unsigned short event)
+{
+ ScrArea *sa;
+ ID *id;
+
+ switch(event) {
+
+ case B_DORENDER:
+ BIF_do_render(0);
+ break;
+ case B_RTCHANGED:
+ allqueue(REDRAWALL, 0);
+ break;
+ case B_SWITCHRENDER:
+ /* new panels added, so... */
+ G.buts->re_align= 1;
+ allqueue(REDRAWBUTSSCENE, 0);
+ break;
+ case B_PLAYANIM:
+ playback_anim();
+ break;
+
+ case B_DOANIM:
+ BIF_do_render(1);
+ break;
+
+ case B_FS_PIC:
+ sa= closest_bigger_area();
+ areawinset(sa->win);
+ if(G.qual == LR_CTRLKEY)
+ activate_imageselect(FILE_SPECIAL, "SELECT OUTPUT PICTURES", G.scene->r.pic, output_pic);
+ else
+ activate_fileselect(FILE_SPECIAL, "SELECT OUTPUT PICTURES", G.scene->r.pic, output_pic);
+ break;
+
+ case B_FS_BACKBUF:
+ sa= closest_bigger_area();
+ areawinset(sa->win);
+ if(G.qual == LR_CTRLKEY)
+ activate_imageselect(FILE_SPECIAL, "SELECT BACKBUF PICTURE", G.scene->r.backbuf, backbuf_pic);
+ else
+ activate_fileselect(FILE_SPECIAL, "SELECT BACKBUF PICTURE", G.scene->r.backbuf, backbuf_pic);
+ break;
+
+ case B_FS_FTYPE:
+ sa= closest_bigger_area();
+ areawinset(sa->win);
+ if(G.qual == LR_CTRLKEY)
+ activate_imageselect(FILE_SPECIAL, "SELECT FTYPE", G.scene->r.ftype, ftype_pic);
+ else
+ activate_fileselect(FILE_SPECIAL, "SELECT FTYPE", G.scene->r.ftype, ftype_pic);
+ break;
+
+ case B_PR_PAL:
+ G.scene->r.xsch= 720;
+ G.scene->r.ysch= 576;
+ G.scene->r.xasp= 54;
+ G.scene->r.yasp= 51;
+ G.scene->r.size= 100;
+ G.scene->r.frs_sec= 25;
+ G.scene->r.frs_sec_base= 1;
+ G.scene->r.mode &= ~R_PANORAMA;
+ G.scene->r.xparts= G.scene->r.yparts= 4;
+#ifdef WITH_FFMPEG
+ G.scene->r.ffcodecdata.gop_size = 15;
+#endif
+ BLI_init_rctf(&G.scene->r.safety, 0.1, 0.9, 0.1, 0.9);
+ BIF_undo_push("Set PAL");
+ allqueue(REDRAWBUTSSCENE, 0);
+ allqueue(REDRAWVIEWCAM, 0);
+ break;
+
+ case B_FILETYPEMENU:
+ allqueue(REDRAWBUTSSCENE, 0);
+#ifdef WITH_FFMPEG
+ if (G.scene->r.imtype == R_FFMPEG) {
+ if (G.scene->r.ffcodecdata.type <= 0 ||
+ G.scene->r.ffcodecdata.codec <= 0 ||
+ G.scene->r.ffcodecdata.audio_codec <= 0 ||
+ G.scene->r.ffcodecdata.video_bitrate <= 1) {
+ G.scene->r.ffcodecdata.codec
+ = CODEC_ID_MPEG2VIDEO;
+ set_ffmpeg_preset(FFMPEG_PRESET_DVD);
+ }
+
+ if (G.scene->r.ffcodecdata.audio_codec <= 0) {
+ G.scene->r.ffcodecdata.audio_codec
+ = CODEC_ID_MP2;
+ G.scene->r.ffcodecdata.audio_bitrate = 128;
+ }
+ break;
+ }
+#endif
+#if defined (_WIN32) || defined (__APPLE__)
+ // fall through to codec settings if this is the first
+ // time R_AVICODEC is selected for this scene.
+ if (((G.scene->r.imtype == R_AVICODEC)
+ && (G.scene->r.avicodecdata == NULL)) ||
+ ((G.scene->r.imtype == R_QUICKTIME)
+ && (G.scene->r.qtcodecdata == NULL))) {
+ } else {
+ break;
+ }
+#endif /*_WIN32 || __APPLE__ */
+
+ case B_SELECTCODEC:
+#if defined (_WIN32) || defined (__APPLE__)
+ if ((G.scene->r.imtype == R_QUICKTIME)) { /* || (G.scene->r.qtcodecdata)) */
+#ifdef WITH_QUICKTIME
+ get_qtcodec_settings();
+#endif /* WITH_QUICKTIME */
+ }
+#if defined (_WIN32) && !defined(FREE_WINDOWS)
+ else
+ get_avicodec_settings();
+#endif /* _WIN32 && !FREE_WINDOWS */
+#endif /* _WIN32 || __APPLE__ */
+ break;
+
+ case B_PR_HD:
+ G.scene->r.xsch= 1920;
+ G.scene->r.ysch= 1080;
+ G.scene->r.xasp= 1;
+ G.scene->r.yasp= 1;
+ G.scene->r.size= 100;
+ G.scene->r.mode &= ~R_PANORAMA;
+ G.scene->r.xparts= G.scene->r.yparts= 4;
+
+ BLI_init_rctf(&G.scene->r.safety, 0.1, 0.9, 0.1, 0.9);
+ BIF_undo_push("Set FULL");
+ allqueue(REDRAWBUTSSCENE, 0);
+ allqueue(REDRAWVIEWCAM, 0);
+ break;
+ case B_PR_FULL:
+ G.scene->r.xsch= 1280;
+ G.scene->r.ysch= 1024;
+ G.scene->r.xasp= 1;
+ G.scene->r.yasp= 1;
+ G.scene->r.size= 100;
+ G.scene->r.mode &= ~R_PANORAMA;
+ G.scene->r.xparts= G.scene->r.yparts= 4;
+
+ BLI_init_rctf(&G.scene->r.safety, 0.1, 0.9, 0.1, 0.9);
+ BIF_undo_push("Set FULL");
+ allqueue(REDRAWBUTSSCENE, 0);
+ allqueue(REDRAWVIEWCAM, 0);
+ break;
+ case B_PR_PRV:
+ G.scene->r.xsch= 640;
+ G.scene->r.ysch= 512;
+ G.scene->r.xasp= 1;
+ G.scene->r.yasp= 1;
+ G.scene->r.size= 50;
+ G.scene->r.mode &= ~R_PANORAMA;
+ G.scene->r.xparts= G.scene->r.yparts= 2;
+
+ BLI_init_rctf(&G.scene->r.safety, 0.1, 0.9, 0.1, 0.9);
+ allqueue(REDRAWVIEWCAM, 0);
+ allqueue(REDRAWBUTSSCENE, 0);
+ break;
+ case B_PR_PAL169:
+ G.scene->r.xsch= 720;
+ G.scene->r.ysch= 576;
+ G.scene->r.xasp= 64;
+ G.scene->r.yasp= 45;
+ G.scene->r.size= 100;
+ G.scene->r.frs_sec= 25;
+ G.scene->r.frs_sec_base= 1;
+ G.scene->r.mode &= ~R_PANORAMA;
+ G.scene->r.xparts= G.scene->r.yparts= 4;
+#ifdef WITH_FFMPEG
+ G.scene->r.ffcodecdata.gop_size = 15;
+#endif
+
+ BLI_init_rctf(&G.scene->r.safety, 0.1, 0.9, 0.1, 0.9);
+ BIF_undo_push("Set PAL 16/9");
+ allqueue(REDRAWVIEWCAM, 0);
+ allqueue(REDRAWBUTSSCENE, 0);
+ break;
+ case B_PR_PC:
+ G.scene->r.xsch= 640;
+ G.scene->r.ysch= 480;
+ G.scene->r.xasp= 100;
+ G.scene->r.yasp= 100;
+ G.scene->r.size= 100;
+ G.scene->r.mode &= ~R_PANORAMA;
+ G.scene->r.xparts= G.scene->r.yparts= 4;
+
+ BLI_init_rctf(&G.scene->r.safety, 0.0, 1.0, 0.0, 1.0);
+ BIF_undo_push("Set PC");
+ allqueue(REDRAWVIEWCAM, 0);
+ allqueue(REDRAWBUTSSCENE, 0);
+ break;
+ case B_PR_PRESET:
+ G.scene->r.xsch= 720;
+ G.scene->r.ysch= 576;
+ G.scene->r.xasp= 54;
+ G.scene->r.yasp= 51;
+ G.scene->r.size= 100;
+ G.scene->r.mode= R_OSA+R_SHADOW+R_FIELDS;
+ G.scene->r.imtype= R_TARGA;
+ G.scene->r.xparts= G.scene->r.yparts= 4;
+
+ BLI_init_rctf(&G.scene->r.safety, 0.1, 0.9, 0.1, 0.9);
+ BIF_undo_push("Set Default");
+ allqueue(REDRAWVIEWCAM, 0);
+ allqueue(REDRAWBUTSSCENE, 0);
+ break;
+ case B_PR_PANO:
+ G.scene->r.xsch= 576;
+ G.scene->r.ysch= 176;
+ G.scene->r.xasp= 115;
+ G.scene->r.yasp= 100;
+ G.scene->r.size= 100;
+ G.scene->r.mode |= R_PANORAMA;
+ G.scene->r.xparts= 16;
+ G.scene->r.yparts= 1;
+
+ BLI_init_rctf(&G.scene->r.safety, 0.1, 0.9, 0.1, 0.9);
+ BIF_undo_push("Set Panorama");
+ allqueue(REDRAWVIEWCAM, 0);
+ allqueue(REDRAWBUTSSCENE, 0);
+ break;
+ case B_PR_NTSC:
+ G.scene->r.xsch= 720;
+ G.scene->r.ysch= 480;
+ G.scene->r.xasp= 10;
+ G.scene->r.yasp= 11;
+ G.scene->r.size= 100;
+ G.scene->r.frs_sec= 30;
+ G.scene->r.frs_sec_base = 1.001;
+ G.scene->r.mode &= ~R_PANORAMA;
+ G.scene->r.xparts= G.scene->r.yparts= 2;
+#ifdef WITH_FFMPEG
+ G.scene->r.ffcodecdata.gop_size = 18;
+#endif
+
+ BLI_init_rctf(&G.scene->r.safety, 0.1, 0.9, 0.1, 0.9);
+ BIF_undo_push("Set NTSC");
+ allqueue(REDRAWBUTSSCENE, 0);
+ allqueue(REDRAWVIEWCAM, 0);
+ break;
+
+ case B_SETBROWSE:
+ id= (ID*) G.scene->set;
+
+ if (G.buts->menunr==-2) {
+ activate_databrowse(id, ID_SCE, 0, B_SETBROWSE, &G.buts->menunr, do_render_panels);
+ }
+ else if (G.buts->menunr>0) {
+ Scene *newset= (Scene*) BLI_findlink(&G.main->scene, G.buts->menunr-1);
+
+ if (newset==G.scene)
+ error("Can't use the same scene as its own set");
+ else if (newset) {
+ G.scene->set= newset;
+ if (scene_check_setscene(G.scene)==0)
+ error("This would create a cycle");
+
+ allqueue(REDRAWBUTSSCENE, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ BIF_undo_push("Change Set Scene");
+ }
+ }
+ break;
+ case B_CLEARSET:
+ G.scene->set= NULL;
+ allqueue(REDRAWBUTSSCENE, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ BIF_undo_push("Clear Set Scene");
+
+ break;
+ case B_SET_EDGE:
+ allqueue(REDRAWBUTSSCENE, 0);
+ break;
+ case B_SET_ZBLUR:
+ G.scene->r.mode &= ~R_EDGE;
+ allqueue(REDRAWBUTSSCENE, 0);
+ break;
+ case B_ADD_RENDERLAYER:
+ if(G.scene->r.actlay==32767) {
+ scene_add_render_layer(G.scene);
+ G.scene->r.actlay= BLI_countlist(&G.scene->r.layers) - 1;
+ }
+ allqueue(REDRAWBUTSSCENE, 0);
+ allqueue(REDRAWNODE, 0);
+ break;
+ case B_SET_PASS:
+ if(G.scene->nodetree) {
+ ntreeCompositForceHidden(G.scene->nodetree);
+ allqueue(REDRAWNODE, 0);
+ }
+ allqueue(REDRAWBUTSSCENE, 0);
+ allqueue(REDRAWOOPS, 0);
+ }
+}
+
+/* NOTE: this is a block-menu, needs 0 events, otherwise the menu closes */
+static uiBlock *edge_render_menu(void *arg_unused)
+{
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "edge render", UI_EMBOSS, UI_HELV, curarea->win);
+
+ /* use this for a fake extra empy space around the buttons */
+ uiDefBut(block, LABEL, 0, "", 0, 0, 220, 115, NULL, 0, 0, 0, 0, "");
+
+ uiDefButS(block, NUM, 0,"Eint:", 45,75,175,19, &G.scene->r.edgeint, 0.0, 255.0, 0, 0,
+ "Sets edge intensity for Toon shading");
+
+ /* color settings for the toon shading */
+ uiDefButF(block, COL, 0, "", 10, 10,30,60, &(G.scene->r.edgeR), 0, 0, 0, B_EDGECOLSLI, "");
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUMSLI, 0, "R ", 45, 50, 175,19, &G.scene->r.edgeR, 0.0, 1.0, B_EDGECOLSLI, 0,
+ "Color for edges in toon shading mode.");
+ uiDefButF(block, NUMSLI, 0, "G ", 45, 30, 175,19, &G.scene->r.edgeG, 0.0, 1.0, B_EDGECOLSLI, 0,
+ "Color for edges in toon shading mode.");
+ uiDefButF(block, NUMSLI, 0, "B ", 45, 10, 175,19, &G.scene->r.edgeB, 0.0, 1.0, B_EDGECOLSLI, 0,
+ "Color for edges in toon shading mode.");
+
+
+ uiBlockSetDirection(block, UI_TOP);
+
+ return block;
+}
+
+
+/* NOTE: this is a block-menu, needs 0 events, otherwise the menu closes */
+static uiBlock *framing_render_menu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 190, xco = 0;
+ int randomcolorindex = 1234;
+
+ block= uiNewBlock(&curarea->uiblocks, "framing_options", UI_EMBOSS, UI_HELV, curarea->win);
+
+ /* use this for a fake extra empy space around the buttons */
+ uiDefBut(block, LABEL, 0, "", -5, -10, 295, 224, NULL, 0, 0, 0, 0, "");
+
+ uiDefBut(block, LABEL, 0, "Framing:", xco, yco, 68,19, 0, 0, 0, 0, 0, "");
+ uiBlockBeginAlign(block);
+ uiDefButC(block, ROW, 0, "Stretch", xco += 70, yco, 68, 19, &G.scene->framing.type, 1.0, SCE_GAMEFRAMING_SCALE , 0, 0, "Stretch or squeeze the viewport to fill the display window");
+ uiDefButC(block, ROW, 0, "Expose", xco += 70, yco, 68, 19, &G.scene->framing.type, 1.0, SCE_GAMEFRAMING_EXTEND, 0, 0, "Show the entire viewport in the display window, viewing more horizontally or vertically");
+ uiDefButC(block, ROW, 0, "Letterbox", xco += 70, yco, 68, 19, &G.scene->framing.type, 1.0, SCE_GAMEFRAMING_BARS , 0, 0, "Show the entire viewport in the display window, using bar horizontally or vertically");
+ uiBlockEndAlign(block);
+
+ yco -= 25;
+ xco = 40;
+
+ uiDefButF(block, COL, 0, "", 0, yco - 58 + 18, 33, 58, &G.scene->framing.col[0], 0, 0, 0, randomcolorindex, "");
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUMSLI, 0, "R ", xco,yco,243,18, &G.scene->framing.col[0], 0.0, 1.0, randomcolorindex, 0, "Set the red component of the bars");
+ yco -= 20;
+ uiDefButF(block, NUMSLI, 0, "G ", xco,yco,243,18, &G.scene->framing.col[1], 0.0, 1.0, randomcolorindex, 0, "Set the green component of the bars");
+ yco -= 20;
+ uiDefButF(block, NUMSLI, 0, "B ", xco,yco,243,18, &G.scene->framing.col[2], 0.0, 1.0, randomcolorindex, 0, "Set the blue component of the bars");
+ uiBlockEndAlign(block);
+
+ xco = 0;
+ uiDefBut(block, LABEL, 0, "Fullscreen:", xco, yco-=30, 100, 19, 0, 0.0, 0.0, 0, 0, "");
+ uiDefButS(block, TOG, 0, "Fullscreen", xco+70, yco, 68, 19, &G.scene->r.fullscreen, 0.0, 0.0, 0, 0, "Starts player in a new fullscreen display");
+ uiBlockBeginAlign(block);
+ uiDefButS(block, NUM, 0, "X:", xco+40, yco-=27, 100, 19, &G.scene->r.xplay, 10.0, 2000.0, 0, 0, "Displays current X screen/window resolution. Click to change.");
+ uiDefButS(block, NUM, 0, "Y:", xco+140, yco, 100, 19, &G.scene->r.yplay, 10.0, 2000.0, 0, 0, "Displays current Y screen/window resolution. Click to change.");
+ uiDefButS(block, NUM, 0, "Freq:", xco+40, yco-=21, 100, 19, &G.scene->r.freqplay, 10.0, 2000.0, 0, 0, "Displays clock frequency of fullscreen display. Click to change.");
+ uiDefButS(block, NUM, 0, "Bits:", xco+140, yco, 100, 19, &G.scene->r.depth, 8.0, 32.0, 800.0, 0, "Displays bit depth of full screen display. Click to change.");
+ uiBlockEndAlign(block);
+
+ /* stereo settings */
+ /* can't use any definition from the game engine here so hardcode it. Change it here when it changes there!
+ * RAS_IRasterizer has definitions:
+ * RAS_STEREO_NOSTEREO 1
+ * RAS_STEREO_QUADBUFFERED 2
+ * RAS_STEREO_ABOVEBELOW 3
+ * RAS_STEREO_INTERLACED 4 future
+ * RAS_STEREO_ANAGLYPH 5
+ * RAS_STEREO_SIDEBYSIDE 6
+ * RAS_STEREO_VINTERLACE 7
+ */
+ uiBlockBeginAlign(block);
+ uiDefButS(block, ROW, 0, "No Stereo", xco, yco-=30, 88, 19, &(G.scene->r.stereomode), 7.0, 1.0, 0, 0, "Disables stereo");
+ uiDefButS(block, ROW, 0, "Pageflip", xco+=90, yco, 88, 19, &(G.scene->r.stereomode), 7.0, 2.0, 0, 0, "Enables hardware pageflip stereo method");
+ uiDefButS(block, ROW, 0, "Syncdouble", xco+=90, yco, 88, 19, &(G.scene->r.stereomode), 7.0, 3.0, 0, 0, "Enables syncdoubling stereo method");
+ uiDefButS(block, ROW, 0, "Anaglyph", xco-=180, yco-=21, 88, 19, &(G.scene->r.stereomode), 7.0, 5.0, 0, 0, "Enables anaglyph (Red-Blue) stereo method");
+ uiDefButS(block, ROW, 0, "Side by Side", xco+=90, yco, 88, 19, &(G.scene->r.stereomode), 7.0, 6.0, 0, 0, "Enables side by side left and right images");
+ uiDefButS(block, ROW, 0, "V Interlace", xco+=90, yco, 88, 19, &(G.scene->r.stereomode), 7.0, 7.0, 0, 0, "Enables interlaced vertical strips for autostereo display");
+
+ uiBlockEndAlign(block);
+
+ uiBlockSetDirection(block, UI_TOP);
+
+ return block;
+}
+
+#ifdef WITH_FFMPEG
+
+static char* ffmpeg_format_pup(void)
+{
+ static char string[2048];
+ char formatstring[2048];
+#if 0
+ int i = 0;
+ int stroffs = 0;
+ AVOutputFormat* next = first_oformat;
+ formatstring = "FFMpeg format: %%t";
+ sprintf(string, formatstring);
+ formatstring = "|%s %%x%d";
+ /* FIXME: This should only be generated once */
+ while (next != NULL) {
+ if (next->video_codec != CODEC_ID_NONE && !(next->flags & AVFMT_NOFILE)) {
+ sprintf(string+stroffs, formatstring, next->name, i++);
+ stroffs += strlen(string+stroffs);
+ }
+ next = next->next;
+ }
+ return string;
+#endif
+ strcpy(formatstring, "FFMpeg format: %%t|%s %%x%d|%s %%x%d|%s %%x%d|%s %%x%d|%s %%x%d|%s %%x%d|%s %%x%d|%s %%x%d");
+ sprintf(string, formatstring,
+ "MPEG-1", FFMPEG_MPEG1,
+ "MPEG-2", FFMPEG_MPEG2,
+ "MPEG-4", FFMPEG_MPEG4,
+ "AVI", FFMPEG_AVI,
+ "Quicktime", FFMPEG_MOV,
+ "DV", FFMPEG_DV,
+ "H264", FFMPEG_H264,
+ "XVid", FFMPEG_XVID);
+ return string;
+}
+
+static char* ffmpeg_preset_pup(void)
+{
+ static char string[2048];
+ char formatstring[2048];
+
+ strcpy(formatstring, "FFMpeg preset: %%t|%s %%x%d|%s %%x%d|%s %%x%d|%s %%x%d|%s %%x%d");
+ sprintf(string, formatstring,
+ "", FFMPEG_PRESET_NONE,
+ "DVD", FFMPEG_PRESET_DVD,
+ "SVCD", FFMPEG_PRESET_SVCD,
+ "VCD", FFMPEG_PRESET_VCD,
+ "DV", FFMPEG_PRESET_DV);
+ return string;
+}
+
+
+static char* ffmpeg_codec_pup(void) {
+ static char string[2048];
+ char formatstring[2048];
+ strcpy(formatstring, "FFMpeg format: %%t|%s %%x%d|%s %%x%d|%s %%x%d|%s %%x%d|%s %%x%d|%s %%x%d|%s %%x%d");
+ sprintf(string, formatstring,
+ "MPEG1", CODEC_ID_MPEG1VIDEO,
+ "MPEG2", CODEC_ID_MPEG2VIDEO,
+ "MPEG4(divx)", CODEC_ID_MPEG4,
+ "HuffYUV", CODEC_ID_HUFFYUV,
+ "DV", CODEC_ID_DVVIDEO,
+ "H264", CODEC_ID_H264,
+ "XVid", CODEC_ID_XVID);
+ return string;
+
+}
+
+static char* ffmpeg_audio_codec_pup(void) {
+ static char string[2048];
+ char formatstring[2048];
+ strcpy(formatstring, "FFMpeg format: %%t|%s %%x%d|%s %%x%d|%s %%x%d|%s %%x%d|%s %%x%d");
+ sprintf(string, formatstring,
+ "MP2", CODEC_ID_MP2,
+ "MP3", CODEC_ID_MP3,
+ "AC3", CODEC_ID_AC3,
+ "AAC", CODEC_ID_AAC,
+ "PCM", CODEC_ID_PCM_S16LE);
+ return string;
+
+}
+
+#endif
+
+static char *imagetype_pup(void)
+{
+ static char string[1024];
+ char formatstring[1024];
+ char appendstring[1024];
+
+ strcpy(formatstring, "Save image as: %%t|%s %%x%d|%s %%x%d|%s %%x%d|%s %%x%d|%s %%x%d|%s %%x%d|%s %%x%d");
+
+#ifdef __sgi
+ strcat(formatstring, "|%s %%x%d"); // add space for Movie
+#endif
+
+ strcat(formatstring, "|%s %%x%d"); // add space for PNG
+/* Commented out until implemented
+#ifdef WITH_DDS
+ strcat(formatstring, "|%s %%x%d"); // add space for DDS
+#endif
+*/
+ strcat(formatstring, "|%s %%x%d"); // add space for BMP
+ strcat(formatstring, "|%s %%x%d"); // add space for Radiance HDR
+ strcat(formatstring, "|%s %%x%d"); // add space for Cineon
+ strcat(formatstring, "|%s %%x%d"); // add space for DPX
+
+#ifdef _WIN32
+ strcat(formatstring, "|%s %%x%d"); // add space for AVI Codec
+#endif
+
+#ifdef WITH_FFMPEG
+ strcat(formatstring, "|%s %%x%d"); // Add space for ffmpeg
+#endif
+ strcat(formatstring, "|%s %%x%d"); // Add space for frameserver
+
+#ifdef WITH_QUICKTIME
+ if(G.have_quicktime)
+ strcat(formatstring, "|%s %%x%d"); // add space for Quicktime
+#endif
+
+ if(G.have_quicktime) {
+ sprintf(string, formatstring,
+ "Frameserver", R_FRAMESERVER,
+#ifdef WITH_FFMPEG
+ "FFMpeg", R_FFMPEG,
+#endif
+ "AVI Raw", R_AVIRAW,
+ "AVI Jpeg", R_AVIJPEG,
+#ifdef _WIN32
+ "AVI Codec", R_AVICODEC,
+#endif
+#ifdef WITH_QUICKTIME
+ "QuickTime", R_QUICKTIME,
+#endif
+ "Targa", R_TARGA,
+ "Targa Raw", R_RAWTGA,
+ "PNG", R_PNG,
+/* commented out until implemented
+#ifdef WITH_DDS
+ "DDS", R_DDS,
+#endif
+*/
+ "BMP", R_BMP,
+ "Jpeg", R_JPEG90,
+ "HamX", R_HAMX,
+ "Iris", R_IRIS,
+ "Radiance HDR", R_RADHDR,
+ "Cineon", R_CINEON,
+ "DPX", R_DPX
+#ifdef __sgi
+ ,"Movie", R_MOVIE
+#endif
+ );
+ } else {
+ sprintf(string, formatstring,
+ "Frameserver", R_FRAMESERVER,
+#ifdef WITH_FFMPEG
+ "FFMpeg", R_FFMPEG,
+#endif
+ "AVI Raw", R_AVIRAW,
+ "AVI Jpeg", R_AVIJPEG,
+#ifdef _WIN32
+ "AVI Codec", R_AVICODEC,
+#endif
+ "Targa", R_TARGA,
+ "Targa Raw", R_RAWTGA,
+ "PNG", R_PNG,
+#ifdef WITH_DDS
+ "DDS", R_DDS,
+#endif
+ "BMP", R_BMP,
+ "Jpeg", R_JPEG90,
+ "HamX", R_HAMX,
+ "Iris", R_IRIS,
+ "Radiance HDR", R_RADHDR,
+ "Cineon", R_CINEON,
+ "DPX", R_DPX
+#ifdef __sgi
+ ,"Movie", R_MOVIE
+#endif
+ );
+ }
+
+#ifdef WITH_OPENEXR
+ strcpy(formatstring, "|%s %%x%d");
+ sprintf(appendstring, formatstring, "OpenEXR", R_OPENEXR);
+ strcat(string, appendstring);
+ sprintf(appendstring, formatstring, "MultiLayer", R_MULTILAYER);
+ strcat(string, appendstring);
+#endif
+
+ if (G.have_libtiff) {
+ strcpy(formatstring, "|%s %%x%d");
+ sprintf(appendstring, formatstring, "TIFF", R_TIFF);
+ strcat(string, appendstring);
+ }
+
+ return (string);
+}
+
+#ifdef _WIN32
+static char *avicodec_str(void)
+{
+ static char string[1024];
+
+ sprintf(string, "Codec: %s", G.scene->r.avicodecdata->avicodecname);
+
+ return string;
+}
+#endif
+
+static void render_panel_output(void)
+{
+ ID *id;
+ int a,b;
+ uiBlock *block;
+ char *strp;
+
+
+ block= uiNewBlock(&curarea->uiblocks, "render_panel_output", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Output", "Render", 0, 0, 318, 204)==0) return;
+
+ uiBlockBeginAlign(block);
+ uiDefIconBut(block, BUT, B_FS_PIC, ICON_FILESEL, 10, 190, 20, 20, 0, 0, 0, 0, 0, "Open Fileselect to get Pics dir/name");
+ uiDefBut(block, TEX,0,"", 31, 190, 279, 20,G.scene->r.pic, 0.0,79.0, 0, 0, "Directory/name to save rendered Pics to");
+ uiDefIconBut(block, BUT,B_FS_BACKBUF, ICON_FILESEL, 10, 168, 20, 20, 0, 0, 0, 0, 0, "Open Fileselect to get Backbuf image");
+ uiDefBut(block, TEX,0,"", 31, 168, 279, 20,G.scene->r.backbuf, 0.0,79.0, 0, 0, "Image to use as background for rendering");
+ uiDefIconBut(block, BUT,B_FS_FTYPE, ICON_FILESEL, 10, 146, 20, 20, 0, 0, 0, 0, 0, "Open Fileselect to get Ftype image");
+ uiDefBut(block, TEX,0,"", 31, 146, 279, 20,G.scene->r.ftype,0.0,79.0, 0, 0, "Image to use with FTYPE Image type");
+ uiBlockEndAlign(block);
+
+
+ /* SET BUTTON */
+ uiBlockBeginAlign(block);
+ id= (ID *)G.scene->set;
+ IDnames_to_pupstring(&strp, NULL, NULL, &(G.main->scene), id, &(G.buts->menunr));
+ if(strp[0])
+ uiDefButS(block, MENU, B_SETBROWSE, strp, 10, 120, 20, 20, &(G.buts->menunr), 0, 0, 0, 0, "Scene to link as a Set");
+ MEM_freeN(strp);
+
+ if(G.scene->set) {
+ uiSetButLock(1, NULL);
+ uiDefIDPoinBut(block, test_scenepoin_but, ID_SCE, B_NOP, "", 31, 120, 100, 20, &(G.scene->set), "Name of the Set");
+ uiClearButLock();
+ uiDefIconBut(block, BUT, B_CLEARSET, ICON_X, 132, 120, 20, 20, 0, 0, 0, 0, 0, "Remove Set link");
+ }
+ uiBlockEndAlign(block);
+
+ uiBlockSetCol(block, TH_BUT_SETTING1);
+ uiDefButBitS(block, TOG, R_BACKBUF, B_NOP,"Backbuf", 10, 94, 80, 20, &G.scene->r.bufflag, 0, 0, 0, 0, "Enable/Disable use of Backbuf image");
+ uiDefButS(block, NUM, B_NOP, "Threads:", 10, 68, 100, 20, &G.scene->r.threads, 1, BLENDER_MAX_THREADS, 0, 0, "Amount of threads for render");
+ uiBlockSetCol(block, TH_AUTO);
+
+ uiBlockBeginAlign(block);
+ for(b=2; b>=0; b--)
+ for(a=0; a<3; a++)
+ uiDefButBitS(block, TOG, 1<<(3*b+a), 800,"", (short)(10+18*a),(short)(10+14*b),16,12, &G.winpos, 0, 0, 0, 0, "Render window placement on screen");
+ uiBlockEndAlign(block);
+
+ uiDefButBitS(block, TOG, R_EXR_TILE_FILE, B_NOP, "Save Buffers", 72, 31, 120, 19, &G.scene->r.scemode, 0.0, 0.0, 0, 0, "Save the tiles for all RenderLayers and used SceneNodes to files, to save memory");
+
+ uiDefButS(block, MENU, B_REDR, "Render Display %t|Render Window %x1|Image Editor %x0|Full Screen %x2",
+ 72, 10, 120, 19, &G.displaymode, 0.0, (float)R_DISPLAYWIN, 0, 0, "Sets render output display");
+
+ uiDefButBitS(block, TOG, R_EXTENSION, B_NOP, "Extensions", 205, 10, 105, 19, &G.scene->r.scemode, 0.0, 0.0, 0, 0, "Adds extensions to the output when rendering animations");
+
+ /* Dither control */
+ uiDefButF(block, NUM,B_DIFF, "Dither:", 205,31,105,19, &G.scene->r.dither_intensity, 0.0, 2.0, 0, 0, "The amount of dithering noise present in the output image (0.0 = no dithering)");
+
+ /* Toon shading buttons */
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOG, R_EDGE, B_NOP,"Edge", 100, 94, 70, 20, &G.scene->r.mode, 0, 0, 0, 0, "Enable Toon Edge-enhance");
+ uiDefBlockBut(block, edge_render_menu, NULL, "Edge Settings", 170, 94, 140, 20, "Display Edge settings");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, R_NO_TEX, B_NOP, "Disable Tex", 115, 68, 70, 20, &G.scene->r.scemode, 0.0, 0.0, 0, 0, "Disables Textures for render");
+ uiDefButBitS(block, TOG, R_FREE_IMAGE, B_NOP, "Free Tex Images", 205, 68, 100, 20, &G.scene->r.scemode, 0.0, 0.0, 0, 0, "Frees all Images used by Textures after each render");
+ uiBlockEndAlign(block);
+}
+
+static void do_bake_func(void *unused_v, void *unused_p)
+{
+ objects_bake_render(0);
+}
+
+static void render_panel_bake(void)
+{
+ uiBlock *block;
+ uiBut *but;
+
+ block= uiNewBlock(&curarea->uiblocks, "render_panel_bake", UI_EMBOSS, UI_HELV, curarea->win);
+ uiNewPanelTabbed("Anim", "Render");
+ if(uiNewPanel(curarea, block, "Bake", "Render", 320, 0, 318, 204)==0) return;
+
+ but= uiDefBut(block, BUT, B_NOP, "BAKE", 10, 150, 190,40, 0, 0, 0, 0, 0, "Start the bake render for selected Objects");
+ uiButSetFunc(but, do_bake_func, NULL, NULL);
+#if 0
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, R_BAKE_OSA, B_DIFF, "OSA", 10,120,190,20, &G.scene->r.bake_flag, 0, 0, 0, 0, "Enables Oversampling (Anti-aliasing)");
+ uiDefButS(block, ROW,B_DIFF,"5", 10,100,50,20,&G.scene->r.bake_osa,2.0,5.0, 0, 0, "Sets oversample level to 5");
+ uiDefButS(block, ROW,B_DIFF,"8", 60,100,45,20,&G.scene->r.bake_osa,2.0,8.0, 0, 0, "Sets oversample level to 8");
+ uiDefButS(block, ROW,B_DIFF,"11", 105,100,45,20,&G.scene->r.bake_osa,2.0,11.0, 0, 0, "Sets oversample level to 11");
+ uiDefButS(block, ROW,B_DIFF,"16", 150,100,50,20,&G.scene->r.bake_osa,2.0,16.0, 0, 0, "Sets oversample level to 16");
+#endif
+ uiBlockBeginAlign(block);
+ uiDefButS(block, ROW,B_DIFF,"Full Render", 210,170,120,20,&G.scene->r.bake_mode, 1.0, RE_BAKE_ALL, 0, 0, "");
+ uiDefButS(block, ROW,B_DIFF,"Ambient Occlusion",210,150,120,20,&G.scene->r.bake_mode, 1.0, RE_BAKE_AO, 0, 0, "");
+ uiDefButS(block, ROW,B_DIFF,"Normals", 210,130,120,20,&G.scene->r.bake_mode, 1.0, RE_BAKE_NORMALS, 0, 0, "");
+ uiDefButS(block, ROW,B_DIFF,"Textures", 210,110,120,20,&G.scene->r.bake_mode, 1.0, RE_BAKE_TEXTURE, 0, 0, "");
+ uiBlockEndAlign(block);
+
+ uiDefButBitS(block, TOG, R_BAKE_CLEAR, B_DIFF, "Clear", 210,80,120,20,&G.scene->r.bake_flag, 0.0, 0, 0, 0, "Clear Images before baking");
+
+ uiDefButS(block, NUM, B_DIFF,"Margin:", 210,50,120,20,&G.scene->r.bake_filter, 0.0, 32.0, 0, 0, "Amount of pixels to extend the baked result with, as post process filter");
+}
+
+static void render_panel_render(void)
+{
+ uiBlock *block;
+ char str[256];
+
+ block= uiNewBlock(&curarea->uiblocks, "render_panel_render", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Render", "Render", 320, 0, 318, 204)==0) return;
+
+ uiBlockBeginAlign(block);
+ uiDefBut(block, BUT,B_DORENDER,"RENDER", 369, 164, 191,37, 0, 0, 0, 0, 0, "Start the rendering");
+#ifndef DISABLE_YAFRAY
+ /* yafray: on request, render engine menu is back again, and moved to Render panel */
+ uiDefButS(block, MENU, B_SWITCHRENDER, "Rendering Engine %t|Blender Internal %x0|YafRay %x1",
+ 369, 142, 191, 20, &G.scene->r.renderer, 0, 0, 0, 0, "Choose rendering engine");
+#else
+ uiDefButS(block, MENU, B_SWITCHRENDER, "Rendering Engine %t|Blender Internal %x0",
+ 369, 142, 191, 20, &G.scene->r.renderer, 0, 0, 0, 0, "Choose rendering engine");
+#endif /* disable yafray */
+
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOG, R_OSA, B_DIFF, "OSA", 369,109,122,20,&G.scene->r.mode, 0, 0, 0, 0, "Enables Oversampling (Anti-aliasing)");
+ uiDefButS(block, ROW,B_DIFF,"5", 369,88,29,20,&G.scene->r.osa,2.0,5.0, 0, 0, "Sets oversample level to 5");
+ uiDefButS(block, ROW,B_DIFF,"8", 400,88,29,20,&G.scene->r.osa,2.0,8.0, 0, 0, "Sets oversample level to 8 (Recommended)");
+ uiDefButS(block, ROW,B_DIFF,"11", 431,88,29,20,&G.scene->r.osa,2.0,11.0, 0, 0, "Sets oversample level to 11");
+ uiDefButS(block, ROW,B_DIFF,"16", 462,88,29,20,&G.scene->r.osa,2.0,16.0, 0, 0, "Sets oversample level to 16");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOG, R_MBLUR, B_REDR, "MBLUR", 496,109,64,20,&G.scene->r.mode, 0, 0, 0, 0, "Enables Motion Blur calculation");
+ uiDefButF(block, NUM,B_DIFF,"Bf:", 496,88,64,20,&G.scene->r.blurfac, 0.01, 5.0, 10, 2, "Sets motion blur factor");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, NUM,B_DIFF,"Xparts:", 369,46,95,29,&G.scene->r.xparts,1.0, 512.0, 0, 0, "Sets the number of horizontal parts to render image in (For panorama sets number of camera slices)");
+ uiDefButS(block, NUM,B_DIFF,"Yparts:", 465,46,95,29,&G.scene->r.yparts,1.0, 64.0, 0, 0, "Sets the number of vertical parts to render image in");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, ROW,800,"Sky", 369,13,35,20,&G.scene->r.alphamode,3.0,0.0, 0, 0, "Fill background with sky");
+ uiDefButS(block, ROW,800,"Premul", 405,13,50,20,&G.scene->r.alphamode,3.0,1.0, 0, 0, "Multiply alpha in advance");
+ uiDefButS(block, ROW,800,"Key", 456,13,35,20,&G.scene->r.alphamode,3.0,2.0, 0, 0, "Alpha and color values remain unchanged");
+ uiBlockEndAlign(block);
+
+ if(G.scene->r.mode & R_RAYTRACE)
+ uiDefButS(block, MENU, B_DIFF,"Octree resolution %t|64 %x64|128 %x128|256 %x256|512 %x512", 496,13,64,20,&G.scene->r.ocres,0.0,0.0, 0, 0, "Octree resolution for ray tracing");
+
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOG, R_SHADOW, B_REDR,"Shadow", 565,172,60,29, &G.scene->r.mode, 0, 0, 0, 0, "Enable shadow calculation");
+ uiDefButBitI(block, TOG, R_ENVMAP, B_REDR,"EnvMap", 627,172,60,29, &G.scene->r.mode, 0, 0, 0, 0, "Enable environment map rendering");
+ uiDefButBitI(block, TOG, R_PANORAMA, B_REDR,"Pano", 565,142,40,29, &G.scene->r.mode, 0, 0, 0, 0, "Enable panorama rendering (output width is multiplied by Xparts)");
+ uiDefButBitI(block, TOG, R_RAYTRACE, B_REDR,"Ray",606,142,40,29, &G.scene->r.mode, 0, 0, 0, 0, "Enable ray tracing");
+ uiDefButBitI(block, TOG, R_RADIO, B_REDR,"Radio", 647,142,40,29, &G.scene->r.mode, 0, 0, 0, 0, "Enable radiosity rendering");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, ROW,B_DIFF,"100%", 565,109,122,20,&G.scene->r.size,1.0,100.0, 0, 0, "Set render size to defined size");
+ uiDefButS(block, ROW,B_DIFF,"75%", 565,88,40,20,&G.scene->r.size,1.0,75.0, 0, 0, "Set render size to 3/4 of defined size");
+ uiDefButS(block, ROW,B_DIFF,"50%", 606,88,40,20,&G.scene->r.size,1.0,50.0, 0, 0, "Set render size to 1/2 of defined size");
+ uiDefButS(block, ROW,B_DIFF,"25%", 647,88,40,20,&G.scene->r.size,1.0,25.0, 0, 0, "Set render size to 1/4 of defined size");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOG, R_FIELDS, B_REDR,"Fields", 565,55,60,20,&G.scene->r.mode, 0, 0, 0, 0, "Enables field rendering");
+ uiDefButBitI(block, TOG, R_ODDFIELD, B_REDR,"Odd", 627,55,39,20,&G.scene->r.mode, 0, 0, 0, 0, "Enables Odd field first rendering (Default: Even field)");
+ uiDefButBitI(block, TOG, R_FIELDSTILL, B_REDR,"X", 668,55,19,20,&G.scene->r.mode, 0, 0, 0, 0, "Disables time difference in field calculations");
+
+ sprintf(str, "Filter%%t|Box %%x%d|Tent %%x%d|Quad %%x%d|Cubic %%x%d|Gauss %%x%d|CatRom %%x%d|Mitch %%x%d", R_FILTER_BOX, R_FILTER_TENT, R_FILTER_QUAD, R_FILTER_CUBIC, R_FILTER_GAUSS, R_FILTER_CATROM, R_FILTER_MITCH);
+ uiDefButS(block, MENU, B_DIFF,str, 565,34,60,20, &G.scene->r.filtertype, 0, 0, 0, 0, "Set sampling filter for antialiasing");
+ uiDefButF(block, NUM,B_DIFF,"", 627,34,60,20,&G.scene->r.gauss,0.5, 1.5, 10, 2, "Sets the filter size");
+
+ uiDefButBitI(block, TOG, R_BORDER, REDRAWVIEWCAM, "Border", 565,13,122,20, &G.scene->r.mode, 0, 0, 0, 0, "Render a small cut-out of the image");
+ uiBlockEndAlign(block);
+
+}
+
+static void render_panel_anim(void)
+{
+ uiBlock *block;
+
+
+ block= uiNewBlock(&curarea->uiblocks, "render_panel_anim", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Anim", "Render", 640, 0, 318, 204)==0) return;
+
+
+ uiDefBut(block, BUT,B_DOANIM,"ANIM", 692,142,192,47, 0, 0, 0, 0, 0, "Start rendering a sequence");
+
+ uiBlockSetCol(block, TH_BUT_SETTING1);
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, R_DOSEQ, B_NOP, "Do Sequence",692,114,192,20, &G.scene->r.scemode, 0, 0, 0, 0, "Enables sequence output rendering (Default: 3D rendering)");
+ uiDefButBitS(block, TOG, R_DOCOMP, B_NOP, "Do Composite",692,90,192,20, &G.scene->r.scemode, 0, 0, 0, 0, "Uses compositing nodes for output rendering");
+ uiBlockEndAlign(block);
+
+ uiBlockSetCol(block, TH_AUTO);
+ uiDefBut(block, BUT,B_PLAYANIM, "PLAY",692,40,94,33, 0, 0, 0, 0, 0, "Play animation of rendered images/avi (searches Pics: field)");
+ uiDefButS(block, NUM, B_RTCHANGED, "rt:",789,40,95,33, &G.rt, -1000.0, 1000.0, 0, 0, "General testing/debug button");
+
+ uiBlockBeginAlign(block);
+ uiDefButI(block, NUM,REDRAWSEQ,"Sta:",692,10,94,24, &G.scene->r.sfra,1.0,MAXFRAMEF, 0, 0, "The start frame of the animation");
+ uiDefButI(block, NUM,REDRAWSEQ,"End:",789,10,95,24, &G.scene->r.efra,SFRA,MAXFRAMEF, 0, 0, "The end frame of the animation");
+ uiBlockEndAlign(block);
+}
+
+#ifdef WITH_FFMPEG
+static void set_ffmpeg_preset(int preset)
+{
+ int isntsc = (G.scene->r.frs_sec != 25);
+ switch (preset) {
+ case FFMPEG_PRESET_VCD:
+ G.scene->r.ffcodecdata.type = FFMPEG_MPEG1;
+ G.scene->r.ffcodecdata.video_bitrate = 1150;
+ G.scene->r.xsch = 352;
+ G.scene->r.ysch = isntsc ? 240 : 288;
+ G.scene->r.ffcodecdata.gop_size = isntsc ? 18 : 15;
+ G.scene->r.ffcodecdata.rc_max_rate = 1150;
+ G.scene->r.ffcodecdata.rc_min_rate = 1150;
+ G.scene->r.ffcodecdata.rc_buffer_size = 40*8;
+ G.scene->r.ffcodecdata.mux_packet_size = 2324;
+ G.scene->r.ffcodecdata.mux_rate = 2352 * 75 * 8;
+ break;
+ case FFMPEG_PRESET_SVCD:
+ G.scene->r.ffcodecdata.type = FFMPEG_MPEG2;
+ G.scene->r.ffcodecdata.video_bitrate = 2040;
+ G.scene->r.xsch = 480;
+ G.scene->r.ysch = isntsc ? 480 : 576;
+ G.scene->r.ffcodecdata.gop_size = isntsc ? 18 : 15;
+ G.scene->r.ffcodecdata.rc_max_rate = 2516;
+ G.scene->r.ffcodecdata.rc_min_rate = 0;
+ G.scene->r.ffcodecdata.rc_buffer_size = 224*8;
+ G.scene->r.ffcodecdata.mux_packet_size = 2324;
+ G.scene->r.ffcodecdata.mux_rate = 0;
+
+ break;
+ case FFMPEG_PRESET_DVD:
+ G.scene->r.ffcodecdata.type = FFMPEG_MPEG2;
+ G.scene->r.ffcodecdata.video_bitrate = 6000;
+ G.scene->r.xsch = 720;
+ G.scene->r.ysch = isntsc ? 480 : 576;
+ G.scene->r.ffcodecdata.gop_size = isntsc ? 18 : 15;
+ G.scene->r.ffcodecdata.rc_max_rate = 9000;
+ G.scene->r.ffcodecdata.rc_min_rate = 0;
+ G.scene->r.ffcodecdata.rc_buffer_size = 224*8;
+ G.scene->r.ffcodecdata.mux_packet_size = 2048;
+ G.scene->r.ffcodecdata.mux_rate = 10080000;
+
+ break;
+ case FFMPEG_PRESET_DV:
+ G.scene->r.ffcodecdata.type = FFMPEG_DV;
+ G.scene->r.xsch = 720;
+ G.scene->r.ysch = isntsc ? 480 : 576;
+ break;
+ }
+}
+
+static void render_panel_ffmpeg_video(void)
+{
+ uiBlock *block;
+ int yofs;
+ int xcol1;
+ int xcol2;
+
+ block = uiNewBlock(&curarea->uiblocks, "render_panel_ffmpeg_video",
+ UI_EMBOSS, UI_HELV, curarea->win);
+
+ uiNewPanelTabbed("Format", "Render");
+ if (uiNewPanel(curarea, block, "Video", "Render", 960, 0, 318, 204)== 0)
+ return;
+
+ if (ffmpeg_preset_sel != 0) {
+ set_ffmpeg_preset(ffmpeg_preset_sel);
+ ffmpeg_preset_sel = 0;
+ allqueue(REDRAWBUTSSCENE, 0);
+ }
+
+ xcol1 = 872;
+ xcol2 = 1002;
+
+ yofs = 54;
+ uiDefBut(block, LABEL, B_DIFF, "Format", xcol1, yofs+88,
+ 110, 20, 0, 0, 0, 0, 0, "");
+ uiDefBut(block, LABEL, B_DIFF, "Preset", xcol2, yofs+88,
+ 110, 20, 0, 0, 0, 0, 0, "");
+ uiDefButI(block, MENU, B_DIFF, ffmpeg_format_pup(),
+ xcol1, yofs+66, 110, 20, &G.scene->r.ffcodecdata.type,
+ 0,0,0,0, "output file format");
+ uiDefButI(block, NUM, B_DIFF, "Bitrate",
+ xcol1, yofs+44, 110, 20,
+ &G.scene->r.ffcodecdata.video_bitrate,
+ 1, 14000, 0, 0, "Video bitrate(kb/s)");
+ uiDefButI(block, NUM, B_DIFF, "Min Rate",
+ xcol1, yofs+22, 110, 20, &G.scene->r.ffcodecdata.rc_min_rate,
+ 0, 14000, 0, 0, "Rate control: min rate(kb/s)");
+ uiDefButI(block, NUM, B_DIFF, "Max Rate",
+ xcol1, yofs, 110, 20, &G.scene->r.ffcodecdata.rc_max_rate,
+ 1, 14000, 0, 0, "Rate control: max rate(kb/s)");
+
+ uiDefButI(block, NUM, B_DIFF, "Mux Rate",
+ xcol1, yofs-22, 110, 20,
+ &G.scene->r.ffcodecdata.mux_rate,
+ 0, 100000000, 0, 0, "Mux rate (bits/s(!))");
+
+
+ uiDefButI(block, MENU, B_REDR, ffmpeg_preset_pup(),
+ xcol2, yofs+66, 110, 20, &ffmpeg_preset_sel,
+ 0,0,0,0, "Output file format preset selection");
+ uiDefButI(block, NUM, B_DIFF, "GOP Size",
+ xcol2, yofs+44, 110, 20, &G.scene->r.ffcodecdata.gop_size,
+ 0, 100, 0, 0, "Distance between key frames");
+ uiDefButI(block, NUM, B_DIFF, "Buffersize",
+ xcol2, yofs+22, 110, 20,
+ &G.scene->r.ffcodecdata.rc_buffer_size,
+ 0, 2000, 0, 0, "Rate control: buffer size (kb)");
+ uiDefButI(block, NUM, B_DIFF, "Mux PSize",
+ xcol2, yofs, 110, 20,
+ &G.scene->r.ffcodecdata.mux_packet_size,
+ 0, 16384, 0, 0, "Mux packet size (byte)");
+
+ uiDefButBitI(block, TOG, FFMPEG_AUTOSPLIT_OUTPUT, B_NOP,
+ "Autosplit Output",
+ xcol2, yofs-22, 110, 20,
+ &G.scene->r.ffcodecdata.flags,
+ 0, 1, 0,0, "Autosplit output at 2GB boundary.");
+
+
+ if (ELEM(G.scene->r.ffcodecdata.type, FFMPEG_AVI, FFMPEG_MOV)) {
+ uiDefBut(block, LABEL, 0, "Codec",
+ xcol1, yofs-44, 110, 20, 0, 0, 0, 0, 0, "");
+ uiDefButI(block, MENU,B_REDR, ffmpeg_codec_pup(),
+ xcol1, yofs-66, 110, 20,
+ &G.scene->r.ffcodecdata.codec,
+ 0,0,0,0, "FFMpeg codec to use");
+ }
+}
+
+static void render_panel_ffmpeg_audio(void)
+{
+ uiBlock *block;
+ int yofs;
+ int xcol;
+
+ block = uiNewBlock(&curarea->uiblocks, "render_panel_ffmpeg_audio", UI_EMBOSS, UI_HELV, curarea->win);
+ uiNewPanelTabbed("Format", "Render");
+ if (uiNewPanel(curarea, block, "Audio", "Render", 960, 0, 318, 204) == 0) return;
+
+ yofs = 54;
+ xcol = 892;
+
+ uiDefButBitI(block, TOG, FFMPEG_MULTIPLEX_AUDIO, B_NOP,
+ "Multiplex audio", xcol, yofs, 225, 20,
+ &G.scene->r.ffcodecdata.flags,
+ 0, 1, 0,0, "Interleave audio with the output video");
+ uiDefBut(block, LABEL, 0, "Codec",
+ xcol, yofs-22, 225, 20, 0, 0, 0, 0, 0, "");
+ uiDefButI(block, MENU,B_NOP, ffmpeg_audio_codec_pup(),
+ xcol, yofs-44, 225, 20,
+ &G.scene->r.ffcodecdata.audio_codec,
+ 0,0,0,0, "FFMpeg codec to use");
+ uiDefButI(block, NUM, B_DIFF, "Bitrate",
+ xcol, yofs-66, 110, 20,
+ &G.scene->r.ffcodecdata.audio_bitrate,
+ 32, 384, 0, 0, "Audio bitrate(kb/s)");
+}
+#endif
+
+static void render_panel_stamp(void)
+{
+ uiBlock *block;
+ int yofs=0, xofs=550;
+
+ block= uiNewBlock (&curarea->uiblocks, "render_panel_stamp", UI_EMBOSS, UI_HELV, curarea->win);
+ uiNewPanelTabbed ("Format", "Render");
+ if(uiNewPanel (curarea, block, "Stamp", "Render", 960, 0, 318, 204)==0) return;
+
+ if (G.scene->r.scemode & R_STAMP_INFO) {
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOG, R_STAMP_NOTE, B_REDR, "Note", xofs, yofs, 100, 19, &G.scene->r.stamp, 0, 0, 0, 0, "Stamp user data");
+ uiDefBut(block, TEX, B_NOP, "", xofs+100, yofs, 200, 19, &G.scene->r.stamp_udata, 0.0, 128.0, 100, 0, "User Note");
+ uiBlockEndAlign(block);
+ yofs += 30; /* gap */
+
+
+ yofs += 100;
+ // Order is important for alligning ... grr
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOG, R_STAMP_SCENE, B_REDR, "Scene", xofs, yofs, 100, 19, &G.scene->r.stamp, 0, 0, 0, 0, "Stamp scene name");
+ yofs -= 20;
+ uiDefButBitI(block, TOG, R_STAMP_CAMERA, B_REDR, "Camera", xofs, yofs, 100, 19, &G.scene->r.stamp, 0, 0, 0, 0, "Stamp camera name");
+ yofs -= 20;
+ uiDefButBitI(block, TOG, R_STAMP_DATE, B_REDR, "Date", xofs, yofs, 100, 19, &G.scene->r.stamp, 0, 0, 0, 0, "Stamp date");
+ yofs -= 20;
+ uiDefButBitI(block, TOG, R_STAMP_TIME, B_REDR, "Time", xofs, yofs, 100, 19, &G.scene->r.stamp, 0, 0, 0, 0, "Stamp time (HH:MM:SS)");
+ yofs -= 20;
+ uiDefButBitI(block, TOG, R_STAMP_FRAME, B_REDR, "Frame", xofs, yofs, 100, 19, &G.scene->r.stamp, 0, 0, 0, 0, "Stamp frame number");
+ yofs -= 20;
+ uiDefButBitI(block, TOG, R_STAMP_MARKER, B_REDR, "Marker", xofs, yofs, 100, 19, &G.scene->r.stamp, 0, 0, 0, 0, "Stamp the last marker");
+ uiBlockEndAlign(block);
+ yofs += 100;
+
+ /* draw font selector */
+ if (G.scene->r.stamp & R_STAMP_DRAW) {
+ uiDefButS(block, MENU, B_REDR, "Stamp Font Size%t|Tiny Text%x1|Small Text%x2|Medium Text%x3|Large Text%x0|Extra Large Text%x4|",
+ xofs+110, yofs, 190, 19, &G.scene->r.stamp_font_id, 0, 0, 0, 0, "Choose stamp text size");
+
+ /* draw fg/bg next to the scene */
+ yofs -= 25;
+ uiDefBut(block, LABEL, B_NOP, "Text Color", xofs+110, yofs, 80, 19, 0, 0, 0, 0, 0, "");
+ uiDefBut(block, LABEL, B_NOP, "Background", xofs+205, yofs, 80, 19, 0, 0, 0, 0, 0, "");
+ yofs -= 20;
+ uiDefButF(block, COL, B_NOP, "", xofs+110, yofs, 90, 19, G.scene->r.fg_stamp, 0, 0, 0, 0, "Foreground text color");
+ uiDefButF(block, COL, B_NOP, "", xofs+210, yofs, 90, 19, G.scene->r.bg_stamp, 0, 0, 0, 0, "Background color");
+ yofs -= 30;
+ uiDefButF(block, NUMSLI, B_NOP, "A ", xofs+110, yofs, 190, 19, &G.scene->r.bg_stamp[3], 0, 1.0, 0, 0, "Alpha for text background");
+ yofs += 105;
+ } else {
+ yofs += 30;
+ }
+
+ uiDefButBitS(block, TOG, R_STAMP_INFO, B_REDR, "Enable Stamp", xofs, yofs, 100, 20, &G.scene->r.scemode, 0, 0, 0, 0, "Disable stamp info in images metadata");
+ uiDefButBitI(block, TOG, R_STAMP_DRAW, B_REDR, "Draw Stamp", xofs+110, yofs, 190, 20, &G.scene->r.stamp, 0, 0, 0, 0, "Draw the stamp info into each frame");
+ yofs += 20;
+ }
+ else {
+ uiDefButBitS(block, TOG, R_STAMP_INFO, B_REDR, "Enable Stamp", xofs, 142, 100, 20, &G.scene->r.scemode, 0, 0, 0, 0, "Enable stamp info to image metadata");
+ yofs += 20;
+ uiDefBut(block, LABEL, 0, "", xofs, yofs, 300, 19, 0, 0, 0, 0, 0, "");
+ }
+}
+
+static void render_panel_format(void)
+{
+ uiBlock *block;
+ int yofs;
+
+
+ block= uiNewBlock(&curarea->uiblocks, "render_panel_format", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Format", "Render", 960, 0, 318, 204)==0) return;
+ uiDefBlockBut(block, framing_render_menu, NULL,
+ "Game framing settings",
+ 892, 169, 227, 20, "Display game framing settings");
+ /* uiDefIconTextBlockBut(block, framing_render_menu, NULL,
+ ICON_BLOCKBUT_CORNER,
+ "Game framing settings",
+ 892, 169, 227, 20,
+ "Display game framing settings"); */
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, NUM,REDRAWVIEWCAM,"SizeX:", 892 ,136,112,27, &G.scene->r.xsch, 4.0, 10000.0, 0, 0, "The image width in pixels");
+ uiDefButS(block, NUM,REDRAWVIEWCAM,"SizeY:", 1007,136,112,27, &G.scene->r.ysch, 4.0,10000.0, 0, 0, "The image height in scanlines");
+ uiDefButS(block, NUM,REDRAWVIEWCAM,"AspX:", 892 ,114,112,20, &G.scene->r.xasp, 1.0,200.0, 0, 0, "The horizontal aspect ratio");
+ uiDefButS(block, NUM,REDRAWVIEWCAM,"AspY:", 1007,114,112,20, &G.scene->r.yasp, 1.0,200.0, 0, 0, "The vertical aspect ratio");
+ uiBlockEndAlign(block);
+
+ yofs = 54;
+
+#ifdef __sgi
+ yofs = 76;
+ uiDefButS(block, NUM,B_DIFF,"MaxSize:", 892,32,165,20, &G.scene->r.maximsize, 0.0, 500.0, 0, 0, "Maximum size per frame to save in an SGI movie");
+ uiDefButBitI(block, TOG, R_COSMO, 0,"Cosmo", 1059,32,60,20, &G.scene->r.mode, 0, 0, 0, 0, "Attempt to save SGI movies using Cosmo hardware");
+#endif
+
+ uiDefButS(block, MENU,B_FILETYPEMENU,imagetype_pup(), 892,yofs,174,20, &G.scene->r.imtype, 0, 0, 0, 0, "Images are saved in this file format");
+ uiDefButBitI(block, TOG, R_CROP, B_DIFF, "Crop", 1068,yofs,51,20, &G.scene->r.mode, 0, 0, 0, 0, "When Border render, the resulting image gets cropped");
+
+ yofs -= 22;
+
+ if(G.scene->r.quality==0) G.scene->r.quality= 90;
+
+#ifdef WITH_QUICKTIME
+ if (G.scene->r.imtype == R_AVICODEC || G.scene->r.imtype == R_QUICKTIME) {
+#else /* WITH_QUICKTIME */
+ if (0) {
+#endif
+ if(G.scene->r.imtype == R_QUICKTIME) {
+#ifdef WITH_QUICKTIME
+#if defined (_WIN32) || defined (__APPLE__)
+ //glColor3f(0.65, 0.65, 0.7);
+ //glRecti(892,yofs+46,892+225,yofs+45+20);
+ if(G.scene->r.qtcodecdata == NULL)
+ uiDefBut(block, LABEL, 0, "Codec: not set", 892,yofs+44,225,20, 0, 0, 0, 0, 0, "");
+ else
+ uiDefBut(block, LABEL, 0, G.scene->r.qtcodecdata->qtcodecname, 892,yofs+44,225,20, 0, 0, 0, 0, 0, "");
+ uiDefBut(block, BUT,B_SELECTCODEC, "Set codec", 892,yofs,74,20, 0, 0, 0, 0, 0, "Set codec settings for Quicktime");
+#endif
+#endif /* WITH_QUICKTIME */
+ } else {
+#ifdef _WIN32
+ //glColor3f(0.65, 0.65, 0.7);
+ //glRecti(892,yofs+46,892+225,yofs+45+20);
+ if(G.scene->r.avicodecdata == NULL)
+ uiDefBut(block, LABEL, 0, "Codec: not set.", 892,yofs+43,225,20, 0, 0, 0, 0, 0, "");
+ else
+ uiDefBut(block, LABEL, 0, avicodec_str(), 892,yofs+43,225,20, 0, 0, 0, 0, 0, "");
+#endif
+ uiDefBut(block, BUT,B_SELECTCODEC, "Set codec", 892,yofs,74,20, 0, 0, 0, 0, 0, "Set codec settings for AVI");
+ }
+#ifdef WITH_OPENEXR
+ }
+ else if (ELEM(G.scene->r.imtype, R_OPENEXR, R_MULTILAYER)) {
+ if (G.scene->r.quality > 5) G.scene->r.quality = 2;
+
+ if(G.scene->r.imtype==R_OPENEXR) {
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, R_OPENEXR_HALF, B_NOP,"Half", 892,yofs+44,60,20, &G.scene->r.subimtype, 0, 0, 0, 0, "Use 16 bit floats instead of 32 bit floats per channel");
+ uiDefButBitS(block, TOG, R_OPENEXR_ZBUF, B_NOP,"Zbuf", 952,yofs+44,60,20, &G.scene->r.subimtype, 0, 0, 0, 0, "Save the z-depth per pixel (32 bit unsigned int zbuffer)");
+ uiBlockEndAlign(block);
+ uiDefButBitS(block, TOG, R_PREVIEW_JPG, B_NOP,"Preview",1027,yofs+44,90,20, &G.scene->r.subimtype, 0, 0, 0, 0, "When animation render, save JPG preview images in same directory");
+ }
+ uiDefButS(block, MENU,B_NOP, "Codec %t|None %x0|Pxr24 (lossy) %x1|ZIP (lossless) %x2|PIZ (lossless) %x3|RLE (lossless) %x4",
+ 892,yofs,74,20, &G.scene->r.quality, 0, 0, 0, 0, "Set codec settings for OpenEXR");
+
+#endif
+ } else {
+ if(G.scene->r.quality < 5) G.scene->r.quality = 90; /* restore from openexr */
+
+ uiDefButS(block, NUM,B_DIFF, "Q:", 892,yofs,74,20, &G.scene->r.quality, 10.0, 100.0, 0, 0, "Quality setting for JPEG images, AVI Jpeg and SGI movies");
+ }
+ uiDefButS(block, NUM,B_FRAMEMAP,"FPS:", 968,yofs,75,20, &G.scene->r.frs_sec, 1.0, 120.0, 100.0, 0, "Frames per second");
+ uiDefButF(block, NUM,B_FRAMEMAP,"/", 1043,yofs,75,20, &G.scene->r.frs_sec_base, 1.0, 120.0, 0.1, 3, "Frames per second base");
+
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, ROW,B_DIFF,"BW", 892, 10,74,19, &G.scene->r.planes, 5.0,(float)R_PLANESBW, 0, 0, "Images are saved with BW (grayscale) data");
+ uiDefButS(block, ROW,B_DIFF,"RGB", 968, 10,74,19, &G.scene->r.planes, 5.0,(float)R_PLANES24, 0, 0, "Images are saved with RGB (color) data");
+ uiDefButS(block, ROW,B_DIFF,"RGBA", 1044, 10,75,19, &G.scene->r.planes, 5.0,(float)R_PLANES32, 0, 0, "Images are saved with RGB and Alpha data (if supported)");
+
+ uiBlockBeginAlign(block);
+ uiDefBut(block, BUT,B_PR_PAL, "PAL", 1146,170,100,18, 0, 0, 0, 0, 0, "Size preset: Image size - 720x576, Aspect ratio - 54x51, 25 fps");
+ uiDefBut(block, BUT,B_PR_NTSC, "NTSC", 1146,150,100,18, 0, 0, 0, 0, 0, "Size preset: Image size - 720x480, Aspect ratio - 10x11, 30 fps");
+ uiDefBut(block, BUT,B_PR_PRESET, "Default", 1146,130,100,18, 0, 0, 0, 0, 0, "Same as PAL, with render settings (OSA, Shadows, Fields)");
+ uiDefBut(block, BUT,B_PR_PRV, "Preview", 1146,110,100,18, 0, 0, 0, 0, 0, "Size preset: Image size - 640x512, Render size 50%");
+ uiDefBut(block, BUT,B_PR_PC, "PC", 1146,90,100,18, 0, 0, 0, 0, 0, "Size preset: Image size - 640x480, Aspect ratio - 100x100");
+ uiDefBut(block, BUT,B_PR_PAL169, "PAL 16:9",1146,70,100,18, 0, 0, 0, 0, 0, "Size preset: Image size - 720x576, Aspect ratio - 64x45");
+ uiDefBut(block, BUT,B_PR_PANO, "PANO", 1146,50,100,18, 0, 0, 0, 0, 0, "Standard panorama settings");
+ uiDefBut(block, BUT,B_PR_FULL, "FULL", 1146,30,100,18, 0, 0, 0, 0, 0, "Size preset: Image size - 1280x1024, Aspect ratio - 1x1");
+ uiDefBut(block, BUT,B_PR_HD, "HD", 1146,10,100,18, 0, 0, 0, 0, 0, "Size preset: Image size - 1920x1080, Aspect ratio - 1x1");
+ uiBlockEndAlign(block);
+}
+
+#ifndef DISABLE_YAFRAY /* disable yafray stuff */
+/* yafray: global illumination options panel */
+static void render_panel_yafrayGI()
+{
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "render_panel_yafrayGI", UI_EMBOSS, UI_HELV, curarea->win);
+ uiNewPanelTabbed("Render", "Render");
+ if(uiNewPanel(curarea, block, "YafRay GI", "Render", 320, 0, 318, 204)==0) return;
+
+ // label to force a boundbox for buttons not to be centered
+ uiDefBut(block, LABEL, 0, " ", 305,180,10,10, 0, 0, 0, 0, 0, "");
+
+ uiDefBut(block, LABEL, 0, "Method", 5,175,70,20, 0, 1.0, 0, 0, 0, "");
+ uiDefButS(block, MENU, B_REDR, "GiMethod %t|None %x0|SkyDome %x1|Full %x2", 70,175,89,20, &G.scene->r.GImethod, 0, 0, 0, 0, "Global Illumination Method");
+
+ uiDefBut(block, LABEL, 0, "Quality", 5,150,70,20, 0, 1.0, 0, 0, 0, "");
+ uiDefButS(block, MENU, B_REDR, "GiQuality %t|None %x0|Low %x1|Medium %x2 |High %x3|Higher %x4|Best %x5|Use Blender AO settings %x6", 70,150,89,20, &G.scene->r.GIquality, 0, 0, 0, 0, "Global Illumination Quality");
+
+ if (G.scene->r.GImethod>0) {
+ uiDefButF(block, NUM, B_DIFF, "EmitPwr:", 5,35,154,20, &G.scene->r.GIpower, 0.01, 100.0, 10, 0, "arealight, material emit and background intensity scaling, 1 is normal");
+ if (G.scene->r.GImethod==2) uiDefButF(block, NUM, B_DIFF, "GI Pwr:", 5,10,154,20, &G.scene->r.GIindirpower, 0.01, 100.0, 10, 0, "GI indirect lighting intensity scaling, 1 is normal");
+ }
+
+ if (G.scene->r.GImethod>0)
+ {
+ if (G.scene->r.GIdepth==0) G.scene->r.GIdepth=2;
+
+ if (G.scene->r.GImethod==2) {
+ uiDefButI(block, NUM, B_DIFF, "Depth:", 180,175,110,20, &G.scene->r.GIdepth, 1.0, 100.0, 10, 10, "Number of bounces of the indirect light");
+ uiDefButI(block, NUM, B_DIFF, "CDepth:", 180,150,110,20, &G.scene->r.GIcausdepth, 1.0, 100.0, 10, 10, "Number of bounces inside objects (for caustics)");
+ uiDefButBitS(block, TOG, 1, B_REDR, "Photons",210,125,100,20, &G.scene->r.GIphotons, 0, 0, 0, 0, "Use global photons to help in GI");
+ }
+
+ uiDefButBitS(block, TOG, 1, B_REDR, "Cache",6,125,95,20, &G.scene->r.GIcache, 0, 0, 0, 0, "Cache occlusion/irradiance samples (faster)");
+ if (G.scene->r.GIcache)
+ {
+ uiDefButBitS(block,TOG, 1, B_REDR, "NoBump",108,125,95,20, &G.scene->r.YF_nobump, 0, 0, 0, 0, "Don't use bumpnormals for cache (faster, but no bumpmapping in total indirectly lit areas)");
+ uiDefBut(block, LABEL, 0, "Cache parameters:", 5,105,130,20, 0, 1.0, 0, 0, 0, "");
+ if (G.scene->r.GIshadowquality==0.0) G.scene->r.GIshadowquality=0.9;
+ uiDefButF(block, NUM, B_DIFF,"ShadQu:", 5,85,154,20, &(G.scene->r.GIshadowquality), 0.01, 1.0 ,1,0, "Sets the shadow quality, keep it under 0.95 :-) ");
+ if (G.scene->r.GIpixelspersample==0) G.scene->r.GIpixelspersample=10;
+ uiDefButI(block, NUM, B_DIFF, "Prec:", 5,60,75,20, &G.scene->r.GIpixelspersample, 1, 50, 10, 10, "Maximum number of pixels without samples, the lower the better and slower");
+ if (G.scene->r.GIrefinement==0) G.scene->r.GIrefinement=1.0;
+ uiDefButF(block, NUM, B_DIFF, "Ref:", 84,60,75,20, &G.scene->r.GIrefinement, 0.001, 1.0, 1, 0, "Threshold to refine shadows EXPERIMENTAL. 1 = no refinement");
+ }
+
+ if (G.scene->r.GImethod==2) {
+ if (G.scene->r.GIphotons)
+ {
+ uiDefBut(block, LABEL, 0, "Photon parameters:", 170,105,130,20, 0, 1.0, 0, 0, 0, "");
+ if(G.scene->r.GIphotoncount==0) G.scene->r.GIphotoncount=100000;
+ uiDefButI(block, NUM, B_DIFF, "Count:", 170,85,140,20, &G.scene->r.GIphotoncount,
+ 0, 10000000, 10, 10, "Number of photons to shoot");
+ if(G.scene->r.GIphotonradius==0.0) G.scene->r.GIphotonradius=1.0;
+ uiDefButF(block, NUMSLI, B_DIFF,"Radius:", 170,60,140,20, &(G.scene->r.GIphotonradius),
+ 0.00001, 100.0 ,0,0, "Radius to search for photons to mix (blur)");
+ if(G.scene->r.GImixphotons==0) G.scene->r.GImixphotons=100;
+ uiDefButI(block, NUM, B_DIFF, "MixCount:", 170,35,140,20, &G.scene->r.GImixphotons,
+ 0, 1000, 10, 10, "Number of photons to mix");
+ uiDefButBitS(block, TOG, 1, B_REDR, "Tune Photons",170,10,140,20, &G.scene->r.GIdirect,
+ 0, 0, 0, 0, "Show the photonmap directly in the render for tuning");
+ }
+ }
+
+ }
+}
+
+/* yafray: global options panel */
+static void render_panel_yafrayGlobal()
+{
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "render_panel_yafrayGlobal", UI_EMBOSS, UI_HELV, curarea->win);
+ uiNewPanelTabbed("Render", "Render");
+ if(uiNewPanel(curarea, block, "YafRay", "Render", 320, 0, 318, 204)==0) return;
+
+ // label to force a boundbox for buttons not to be centered
+ uiDefBut(block, LABEL, 0, " ", 305,180,10,10, 0, 0, 0, 0, 0, "");
+
+ uiDefButBitS(block, TOGN, 1, B_REDR, "xml", 5,180,75,20, &G.scene->r.YFexportxml,
+ 0, 0, 0, 0, "Export to an xml file and call yafray instead of plugin");
+
+ uiDefButF(block, NUMSLI, B_DIFF,"Bi ", 5,35,150,20, &(G.scene->r.YF_raybias),
+ 0.0, 10.0 ,0,0, "Shadow ray bias to avoid self shadowing");
+ uiDefButI(block, NUM, B_DIFF, "Raydepth ", 5,60,150,20,
+ &G.scene->r.YF_raydepth, 1.0, 80.0, 10, 10, "Maximum render ray depth from the camera");
+ uiDefButF(block, NUMSLI, B_DIFF, "Gam ", 5,10,150,20, &G.scene->r.YF_gamma, 0.001, 5.0, 0, 0, "Gamma correction, 1 is off");
+ uiDefButF(block, NUMSLI, B_DIFF, "Exp ", 160,10,150,20,&G.scene->r.YF_exposure, 0.0, 10.0, 0, 0, "Exposure adjustment, 0 is off");
+
+ uiDefButI(block, NUM, B_DIFF, "Processors:", 160,60,150,20, &G.scene->r.YF_numprocs, 1.0, 8.0, 10, 10, "Number of processors to use");
+
+ /*AA Settings*/
+ uiDefButBitS(block, TOGN, 1, B_REDR, "Auto AA", 5,140,150,20, &G.scene->r.YF_AA,
+ 0, 0, 0, 0, "Set AA using OSA and GI quality, disable for manual control");
+ uiDefButBitS(block, TOGN, 1, B_DIFF, "Clamp RGB", 160,140,150,20, &G.scene->r.YF_clamprgb, 1.0, 8.0, 10, 10, "For AA on fast high contrast changes. Not advisable for Bokeh! Dulls lens shape detail.");
+ if(G.scene->r.YF_AA){
+ uiDefButI(block, NUM, B_DIFF, "AA Passes ", 5,115,150,20, &G.scene->r.YF_AApasses, 0, 64, 10, 10, "Number of AA passes (0 is no AA)");
+ uiDefButI(block, NUM, B_DIFF, "AA Samples ", 160,115,150,20, &G.scene->r.YF_AAsamples, 0, 2048, 10, 10, "Number of samples per pass");
+ uiDefButF(block, NUMSLI, B_DIFF, "Psz ", 5,90,150,20, &G.scene->r.YF_AApixelsize, 1.0, 2.0, 0, 0, "AA pixel filter size");
+ uiDefButF(block, NUMSLI, B_DIFF, "Thr ", 160,90,150,20, &G.scene->r.YF_AAthreshold, 0.000001, 1.0, 0, 0, "AA threshold");
+ }
+}
+#endif /* disable yafray stuff */
+
+static void layer_copy_func(void *lay_v, void *lay_p)
+{
+ unsigned int *lay= lay_p;
+ int laybit= (int)lay_v;
+
+ if(G.qual & LR_SHIFTKEY) {
+ if(*lay==0) *lay= 1<<laybit;
+ }
+ else
+ *lay= 1<<laybit;
+
+ copy_view3d_lock(REDRAW);
+ allqueue(REDRAWBUTSSCENE, 0);
+}
+
+static void delete_scene_layer_func(void *srl_v, void *act_i)
+{
+ if(BLI_countlist(&G.scene->r.layers)>1) {
+ long act= (long)act_i;
+
+ BLI_remlink(&G.scene->r.layers, srl_v);
+ MEM_freeN(srl_v);
+ G.scene->r.actlay= 0;
+
+ if(G.scene->nodetree) {
+ bNode *node;
+ for(node= G.scene->nodetree->nodes.first; node; node= node->next) {
+ if(node->type==CMP_NODE_R_LAYERS && node->id==NULL) {
+ if(node->custom1==act)
+ node->custom1= 0;
+ else if(node->custom1>act)
+ node->custom1--;
+ }
+ }
+ }
+ allqueue(REDRAWBUTSSCENE, 0);
+ allqueue(REDRAWNODE, 0);
+ }
+}
+
+static void rename_scene_layer_func(void *srl_v, void *unused_v)
+{
+ if(G.scene->nodetree) {
+ SceneRenderLayer *srl= srl_v;
+ bNode *node;
+ for(node= G.scene->nodetree->nodes.first; node; node= node->next) {
+ if(node->type==CMP_NODE_R_LAYERS && node->id==NULL) {
+ if(node->custom1==G.scene->r.actlay)
+ BLI_strncpy(node->name, srl->name, NODE_MAXSTR);
+ }
+ }
+ }
+ allqueue(REDRAWBUTSSCENE, 0);
+ allqueue(REDRAWOOPS, 0);
+ allqueue(REDRAWNODE, 0);
+}
+
+static char *scene_layer_menu(void)
+{
+ SceneRenderLayer *srl;
+ int len= 32 + 32*BLI_countlist(&G.scene->r.layers);
+ short a, nr;
+ char *str= MEM_callocN(len, "menu layers");
+
+ strcpy(str, "ADD NEW %x32767");
+ a= strlen(str);
+ for(nr=0, srl= G.scene->r.layers.first; srl; srl= srl->next, nr++) {
+ if(srl->layflag & SCE_LAY_DISABLE)
+ a+= sprintf(str+a, "|%s %%i%d %%x%d", srl->name, ICON_BLANK1, nr);
+ else
+ a+= sprintf(str+a, "|%s %%i%d %%x%d", srl->name, ICON_CHECKBOX_HLT, nr);
+ }
+
+ return str;
+}
+
+static void draw_3d_layer_buttons(uiBlock *block, unsigned int *poin, short xco, short yco, short dx, short dy)
+{
+ uiBut *bt;
+ long a;
+
+ uiBlockBeginAlign(block);
+ for(a=0; a<5; a++) {
+ bt= uiDefButBitI(block, TOG, 1<<a, B_NOP, "", (short)(xco+a*(dx/2)), yco+dy/2, (short)(dx/2), (short)(dy/2), (int *)poin, 0, 0, 0, 0, "");
+ uiButSetFunc(bt, layer_copy_func, (void *)a, poin);
+ }
+ for(a=0; a<5; a++) {
+ bt=uiDefButBitI(block, TOG, 1<<(a+10), B_NOP, "", (short)(xco+a*(dx/2)), yco, (short)(dx/2), (short)(dy/2), (int *)poin, 0, 0, 0, 0, "");
+ uiButSetFunc(bt, layer_copy_func, (void *)(a+10), poin);
+ }
+
+ xco+= 7;
+ uiBlockBeginAlign(block);
+ for(a=5; a<10; a++) {
+ bt=uiDefButBitI(block, TOG, 1<<a, B_NOP, "", (short)(xco+a*(dx/2)), yco+dy/2, (short)(dx/2), (short)(dy/2), (int *)poin, 0, 0, 0, 0, "");
+ uiButSetFunc(bt, layer_copy_func, (void *)a, poin);
+ }
+ for(a=5; a<10; a++) {
+ bt=uiDefButBitI(block, TOG, 1<<(a+10), B_NOP, "", (short)(xco+a*(dx/2)), yco, (short)(dx/2), (short)(dy/2), (int *)poin, 0, 0, 0, 0, "");
+ uiButSetFunc(bt, layer_copy_func, (void *)(a+10), poin);
+ }
+
+ uiBlockEndAlign(block);
+}
+
+static void render_panel_layers(void)
+{
+ uiBlock *block;
+ uiBut *bt;
+ SceneRenderLayer *srl= BLI_findlink(&G.scene->r.layers, G.scene->r.actlay);
+ char *strp;
+
+ if(srl==NULL) {
+ G.scene->r.actlay= 0;
+ srl= G.scene->r.layers.first;
+ }
+
+ block= uiNewBlock(&curarea->uiblocks, "render_panel_layers", UI_EMBOSS, UI_HELV, curarea->win);
+ uiNewPanelTabbed("Output", "Render");
+ if(uiNewPanel(curarea, block, "Render Layers", "Render", 320, 0, 318, 204)==0) return;
+
+ /* first, as reminder, the scene layers */
+ uiDefBut(block, LABEL, 0, "Scene:", 10,170,100,20, NULL, 0, 0, 0, 0, "");
+ draw_3d_layer_buttons(block, &G.scene->lay, 130, 170, 35, 30);
+
+ /* layer disable, menu, name, delete button */
+ uiBlockBeginAlign(block);
+ uiDefIconButBitI(block, ICONTOGN, SCE_LAY_DISABLE, B_REDR, ICON_CHECKBOX_HLT-1, 10, 145, 20, 20, &srl->layflag, 0.0, 0.0, 0, 0, "Disable or enable this RenderLayer");
+ strp= scene_layer_menu();
+ uiDefButS(block, MENU, B_ADD_RENDERLAYER, strp, 30,145,23,20, &(G.scene->r.actlay), 0, 0, 0, 0, "Choose Active Render Layer");
+ MEM_freeN(strp);
+
+ /* name max 20, exr format limit... */
+ bt= uiDefBut(block, TEX, REDRAWNODE, "", 53,145,172,20, srl->name, 0.0, 20.0, 0, 0, "");
+ uiButSetFunc(bt, rename_scene_layer_func, srl, NULL);
+
+ uiDefButBitS(block, TOG, R_SINGLE_LAYER, B_NOP, "Single", 230,145,60,20, &G.scene->r.scemode, 0, 0, 0, 0, "Only render this layer");
+ bt=uiDefIconBut(block, BUT, B_NOP, ICON_X, 285, 145, 25, 20, 0, 0, 0, 0, 0, "Deletes current Render Layer");
+ uiButSetFunc(bt, delete_scene_layer_func, srl, (void *)(long)G.scene->r.actlay);
+ uiBlockEndAlign(block);
+
+ /* RenderLayer visible-layers */
+ uiDefBut(block, LABEL, 0, "Layer:", 10,110,100,20, NULL, 0, 0, 0, 0, "");
+ draw_3d_layer_buttons(block, &srl->lay, 130,110, 35, 30);
+
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOG, SCE_LAY_ALL_Z, B_NOP,"AllZ", 10, 85, 40, 20, &srl->layflag, 0, 0, 0, 0, "Fill in Z values for all not-rendered faces, for masking");
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOG, SCE_LAY_SOLID, B_NOP,"Solid", 50, 85, 60, 20, &srl->layflag, 0, 0, 0, 0, "Render Solid faces in this Layer");
+ uiDefButBitI(block, TOG, SCE_LAY_HALO, B_NOP,"Halo", 110, 85, 55, 20, &srl->layflag, 0, 0, 0, 0, "Render Halos in this Layer (on top of Solid)");
+ uiDefButBitI(block, TOG, SCE_LAY_ZTRA, B_NOP,"Ztra", 165, 85, 55, 20, &srl->layflag, 0, 0, 0, 0, "Render Z-Transparent faces in this Layer (On top of Solid and Halos)");
+ uiDefButBitI(block, TOG, SCE_LAY_SKY, B_NOP,"Sky", 220, 85, 40, 20, &srl->layflag, 0, 0, 0, 0, "Render Sky or backbuffer in this Layer");
+ uiDefButBitI(block, TOG, SCE_LAY_EDGE, B_NOP,"Edge", 260, 85, 50, 20, &srl->layflag, 0, 0, 0, 0, "Render Edge-enhance in this Layer (only works for Solid faces)");
+
+ uiDefIDPoinBut(block, test_grouppoin_but, ID_GR, B_SET_PASS, "Light:", 10, 65, 150, 20, &(srl->light_override), "Name of Group to use as Lamps instead");
+ uiDefIDPoinBut(block, test_matpoin_but, ID_MA, B_SET_PASS, "Mat:", 160, 65, 150, 20, &(srl->mat_override), "Name of Material to use as Materials instead");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOG, SCE_PASS_COMBINED, B_SET_PASS,"Combined", 10, 30, 80, 20, &srl->passflag, 0, 0, 0, 0, "Deliver full combined RGBA buffer");
+ uiDefButBitI(block, TOG, SCE_PASS_Z, B_SET_PASS,"Z", 90, 30, 30, 20, &srl->passflag, 0, 0, 0, 0, "Deliver Z values pass");
+ uiDefButBitI(block, TOG, SCE_PASS_VECTOR, B_SET_PASS,"Vec", 120, 30, 40, 20, &srl->passflag, 0, 0, 0, 0, "Deliver Speed Vector pass");
+ uiDefButBitI(block, TOG, SCE_PASS_NORMAL, B_SET_PASS,"Nor", 160, 30, 40, 20, &srl->passflag, 0, 0, 0, 0, "Deliver Normal pass");
+ uiDefButBitI(block, TOG, SCE_PASS_UV, B_SET_PASS,"UV", 200, 30, 40, 20, &srl->passflag, 0, 0, 0, 0, "Deliver Texture UV pass");
+ uiDefButBitI(block, TOG, SCE_PASS_INDEXOB, B_SET_PASS,"IndexOb",240, 30, 70, 20, &srl->passflag, 0, 0, 0, 0, "Deliver Object Index pass");
+
+ uiDefButBitI(block, TOG, SCE_PASS_RGBA, B_SET_PASS,"Col", 10, 10, 35, 20, &srl->passflag, 0, 0, 0, 0, "Deliver shade-less Color pass");
+ uiDefButBitI(block, TOG, SCE_PASS_DIFFUSE, B_SET_PASS,"Diff", 45, 10, 35, 20, &srl->passflag, 0, 0, 0, 0, "Deliver Diffuse pass");
+ uiDefButBitI(block, BUT_TOGDUAL, SCE_PASS_SPEC, B_SET_PASS,"Spec", 80, 10, 40, 20, &srl->passflag, 0, 0, 0, 0, "Deliver Specular pass");
+ uiDefButBitI(block, BUT_TOGDUAL, SCE_PASS_SHADOW, B_SET_PASS,"Shad", 120, 10, 40, 20, &srl->passflag, 0, 0, 0, 0, "Deliver Shadow pass");
+ uiDefButBitI(block, BUT_TOGDUAL, SCE_PASS_AO, B_SET_PASS,"AO", 160, 10, 30, 20, &srl->passflag, 0, 0, 0, 0, "Deliver AO pass");
+ uiDefButBitI(block, BUT_TOGDUAL, SCE_PASS_REFLECT, B_SET_PASS,"Refl", 190, 10, 40, 20, &srl->passflag, 0, 0, 0, 0, "Deliver Raytraced Reflection pass");
+ uiDefButBitI(block, BUT_TOGDUAL, SCE_PASS_REFRACT, B_SET_PASS,"Refr", 230, 10, 40, 20, &srl->passflag, 0, 0, 0, 0, "Deliver Raytraced Refraction pass");
+ uiDefButBitI(block, BUT_TOGDUAL, SCE_PASS_RADIO, B_SET_PASS,"Rad", 270, 10, 40, 20, &srl->passflag, 0, 0, 0, 0, "Deliver Radiosity pass");
+}
+
+void render_panels()
+{
+
+ render_panel_output();
+ render_panel_layers();
+ render_panel_render();
+ render_panel_anim();
+ render_panel_bake();
+
+ render_panel_format();
+ render_panel_stamp();
+#ifdef WITH_FFMPEG
+ if (G.scene->r.imtype == R_FFMPEG) {
+ render_panel_ffmpeg_video();
+ render_panel_ffmpeg_audio();
+ }
+#endif
+
+#ifndef DISABLE_YAFRAY
+ /* yafray: GI & Global panel, only available when yafray enabled for rendering */
+ if (G.scene->r.renderer==R_YAFRAY) {
+ if (G.scene->r.YF_gamma==0.0) G.scene->r.YF_gamma=1.0;
+ if (G.scene->r.YF_raybias==0.0) G.scene->r.YF_raybias=0.001;
+ if (G.scene->r.YF_raydepth==0) G.scene->r.YF_raydepth=5;
+ if (G.scene->r.YF_AApixelsize==0.0) G.scene->r.YF_AApixelsize=1.5;
+ if (G.scene->r.YF_AAthreshold==0.0) G.scene->r.YF_AAthreshold=0.05;
+ if (G.scene->r.GIpower==0.0) G.scene->r.GIpower=1.0;
+ if (G.scene->r.GIindirpower==0.0) G.scene->r.GIindirpower=1.0;
+ render_panel_yafrayGlobal();
+ render_panel_yafrayGI();
+ }
+#endif
+
+}
+
+/* --------------------------------------------- */
+
+void anim_panels()
+{
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "anim_panel", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Anim", "Anim", 0, 0, 318, 204)==0) return;
+
+ uiBlockBeginAlign(block);
+ uiDefButI(block, NUM,B_FRAMEMAP,"Map Old:", 10,160,150,20,&G.scene->r.framapto,1.0,900.0, 0, 0, "Specify old mapping value in frames");
+ uiDefButI(block, NUM,B_FRAMEMAP,"Map New:", 160,160,150,20,&G.scene->r.images,1.0,900.0, 0, 0, "Specify how many frames the Map Old will last");
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, NUM,B_FRAMEMAP,"FPS:", 10,130,75,20, &G.scene->r.frs_sec, 1.0, 120.0, 100.0, 0, "Frames per second");
+ uiDefButF(block, NUM,B_FRAMEMAP,"/", 85,130,75,20, &G.scene->r.frs_sec_base, 1.0, 120.0, 0.1, 3, "Frames per second base");
+
+ uiDefButBitS(block, TOG, AUDIO_SYNC, B_SOUND_CHANGED, "Sync",160,130,150,20, &G.scene->audio.flag, 0, 0, 0, 0, "Use sample clock for syncing animation to audio");
+
+ uiBlockBeginAlign(block);
+ uiDefButI(block, NUM,REDRAWALL,"Sta:", 10,100,150,20,&G.scene->r.sfra,1.0,MAXFRAMEF, 0, 0, "Specify the start frame of the animation");
+ uiDefButI(block, NUM,REDRAWALL,"End:", 160,100,150,20,&G.scene->r.efra,1.0,MAXFRAMEF, 0, 0, "Specify the end frame of the animation");
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, NUM, REDRAWTIME, "Steps:",10, 70, 150, 20,&(G.scene->jumpframe), 1, 100, 1, 100, "Set spacing between frames changes with up and down arrow keys");
+
+
+}
+
+/* --------------------------------------------- */
+
+void sound_panels()
+{
+ bSound *sound;
+
+ /* paranoia check */
+ sound = G.buts->lockpoin;
+ if(sound && GS(sound->id.name)!=ID_SO) {
+ sound= NULL;
+ G.buts->lockpoin= NULL;
+ }
+
+ sound_panel_sound(sound);
+ sound_panel_listener();
+ sound_panel_sequencer();
+}
+
+
+
diff --git a/source/blender/src/buttons_script.c b/source/blender/src/buttons_script.c
new file mode 100644
index 00000000000..52e7be7c93e
--- /dev/null
+++ b/source/blender/src/buttons_script.c
@@ -0,0 +1,384 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <time.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+#include "DNA_action_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_effect_types.h"
+#include "DNA_group_types.h"
+#include "DNA_ID.h"
+#include "DNA_image_types.h"
+#include "DNA_key_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_material_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_object_types.h"
+#include "DNA_radio_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_sound_types.h"
+#include "DNA_text_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_vfont_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_world_types.h"
+#include "DNA_space_types.h"
+
+#include "BKE_anim.h"
+#include "BKE_armature.h"
+#include "BKE_constraint.h"
+#include "BKE_curve.h"
+#include "BKE_displist.h"
+#include "BKE_effect.h"
+#include "BKE_font.h"
+#include "BKE_image.h"
+#include "BKE_ipo.h"
+#include "BKE_lattice.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_mball.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_sound.h"
+#include "BKE_texture.h"
+#include "BKE_global.h"
+#include "BKE_utildefines.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_dynstr.h"
+
+#include "BSE_filesel.h"
+
+#include "BIF_gl.h"
+#include "BIF_graphics.h"
+#include "BIF_keyval.h"
+#include "BIF_mainqueue.h"
+#include "BIF_resources.h"
+#include "BIF_screen.h"
+#include "BIF_mywindow.h"
+#include "BIF_space.h"
+#include "BIF_glutil.h"
+#include "BIF_interface.h"
+#include "BIF_toolbox.h"
+
+#include "BIF_butspace.h"
+
+#include "mydevice.h"
+#include "blendef.h"
+#include "butspace.h"
+
+/* ************************ function prototypes ********************** */
+void draw_scriptlink(uiBlock *, ScriptLink *, int , int , int ) ;
+
+/* *************************** SCRIPT ******************************** */
+
+static void extend_scriptlink(ScriptLink *slink)
+{
+ void *stmp, *ftmp;
+
+ if (!slink) return;
+
+ stmp= slink->scripts;
+ slink->scripts= MEM_mallocN(sizeof(ID*)*(slink->totscript+1), "scriptlistL");
+
+ ftmp= slink->flag;
+ slink->flag= MEM_mallocN(sizeof(short*)*(slink->totscript+1), "scriptlistF");
+
+ if (slink->totscript) {
+ memcpy(slink->scripts, stmp, sizeof(ID*)*(slink->totscript));
+ MEM_freeN(stmp);
+
+ memcpy(slink->flag, ftmp, sizeof(short)*(slink->totscript));
+ MEM_freeN(ftmp);
+ }
+
+ slink->scripts[slink->totscript]= NULL;
+ slink->flag[slink->totscript]= SCRIPT_FRAMECHANGED;
+
+ slink->totscript++;
+ slink->actscript = slink->totscript;
+}
+
+static void delete_scriptlink(ScriptLink *slink)
+{
+ int i;
+
+ if (!slink) return;
+
+ if (slink->totscript>0) {
+ for (i=slink->actscript-1; i<slink->totscript-1; i++) {
+ slink->flag[i]= slink->flag[i+1];
+ slink->scripts[i]= slink->scripts[i+1];
+ }
+
+ slink->totscript--;
+ }
+
+ CLAMP(slink->actscript, 1, slink->totscript);
+
+ if (slink->totscript==0) {
+ if (slink->scripts) MEM_freeN(slink->scripts);
+ if (slink->flag) MEM_freeN(slink->flag);
+
+ slink->scripts= NULL;
+ slink->flag= NULL;
+ slink->totscript= slink->actscript= 0;
+ }
+}
+
+static char *scriptlinks_menu_string(void)
+{
+ char *menu = NULL;
+ DynStr *ds = BLI_dynstr_new();
+ Text *text = G.main->text.first;
+ int txtcounter = 0;
+
+ if (text) {
+ BLI_dynstr_append(ds, "Select Script Link%t");
+ while (text) {
+ BLI_dynstr_append(ds, "|");
+ BLI_dynstr_append(ds, text->id.name+2);
+ txtcounter += 1;
+ text = text->id.next;
+ }
+ if (txtcounter) menu = BLI_dynstr_get_cstring(ds);
+ }
+ BLI_dynstr_free(ds);
+ return menu;
+}
+
+static void scriptlinks_pupmenu(ScriptLink *slink)
+{
+ short menuitem;
+ char *menustr = scriptlinks_menu_string();
+
+ if (!slink) return;
+
+ if (menustr) {
+ menuitem = pupmenu_col(menustr, 20);
+ MEM_freeN(menustr);
+ if (menuitem > 0) {
+ Text *text = G.main->text.first;
+ while (--menuitem) text = text->id.next;
+ if (text) slink->scripts[slink->totscript - 1]= (ID *)text;
+ }
+ }
+}
+
+void do_scriptbuts(unsigned short event)
+{
+ Object *ob=NULL;
+ ScriptLink *slink=NULL;
+ Material *ma;
+
+ switch (event) {
+ case B_SSCRIPT_ADD:
+ slink = &G.scene->scriptlink;
+ extend_scriptlink(slink);
+ BIF_undo_push("Add scriptlink");
+ scriptlinks_pupmenu(slink);
+ break;
+ case B_SSCRIPT_DEL:
+ BIF_undo_push("Delete scriptlink");
+ delete_scriptlink(&G.scene->scriptlink);
+ break;
+
+ case B_SCRIPT_ADD:
+ case B_SCRIPT_DEL:
+ ob= OBACT;
+
+ if (ob && G.buts->scriptblock==ID_OB) {
+ slink= &ob->scriptlink;
+
+ } else if (ob && G.buts->scriptblock==ID_MA) {
+ ma= give_current_material(ob, ob->actcol);
+ if (ma) slink= &ma->scriptlink;
+
+ } else if (ob && G.buts->scriptblock==ID_CA) {
+ if (ob->type==OB_CAMERA)
+ slink= &((Camera *)ob->data)->scriptlink;
+
+ } else if (ob && G.buts->scriptblock==ID_LA) {
+ if (ob->type==OB_LAMP)
+ slink= &((Lamp *)ob->data)->scriptlink;
+
+ } else if (G.buts->scriptblock==ID_WO) {
+ if (G.scene->world)
+ slink= &(G.scene->world->scriptlink);
+ }
+
+ if (event==B_SCRIPT_ADD) {
+ extend_scriptlink(slink);
+ BIF_undo_push("Add scriptlink");
+ scriptlinks_pupmenu(slink);
+ }
+ else {
+ delete_scriptlink(slink);
+ BIF_undo_push("Delete scriptlink");
+ }
+ break;
+ default:
+ break;
+ }
+
+ allqueue(REDRAWBUTSSCRIPT, 0);
+ allqueue(REDRAWOOPS, 0);
+}
+
+void draw_scriptlink(uiBlock *block, ScriptLink *script, int sx, int sy, int scene)
+{
+ char str[256];
+
+ if (script->totscript) {
+ strcpy(str, "FrameChanged%x 1|");
+ strcat(str, "Redraw%x 4|");
+ strcat(str, "Render%x 16|");
+ if (scene) {
+ strcat(str, "OnLoad%x 2|");
+ strcat(str, "OnSave%x 8");
+ }
+ uiBlockBeginAlign(block);
+ uiDefButS(block, MENU, 1, str, (short)sx, (short)sy, 140, 19, &script->flag[script->actscript-1], 0, 0, 0, 0, "Script links for this event");
+
+ uiDefIDPoinBut(block, test_scriptpoin_but, ID_SCRIPT, 1, "", (short)(sx+140),(short)sy, 140, 19, &script->scripts[script->actscript-1], "Name of Script to link");
+ uiBlockEndAlign(block);
+ }
+
+ sprintf(str,"%d Scr:", script->totscript);
+
+ uiDefButS(block, NUM, REDRAWBUTSSCRIPT, str, (short)(sx+140), (short)sy-20,60,19, &script->actscript, 1, script->totscript, 0, 0, "Total / Active Script link (LeftMouse + Drag to change)");
+
+ if (scene) {
+
+ if (script->totscript<32767)
+ uiDefBut(block, BUT, B_SSCRIPT_ADD, "New", (short)(sx+240), (short)sy-20, 40, 19, 0, 0, 0, 0, 0, "Add a new Script link");
+ if (script->totscript)
+ uiDefBut(block, BUT, B_SSCRIPT_DEL, "Del", (short)(sx+200), (short)sy-20, 40, 19, 0, 0, 0, 0, 0, "Delete the current Script link");
+ uiDefBut(block, LABEL, 0, "Scene Script link", sx,sy-20,140,20, 0, 0, 0, 0, 0, "");
+ }
+ else {
+ if (script->totscript<32767)
+ uiDefBut(block, BUT, B_SCRIPT_ADD, "New", (short)(sx+240), (short)sy-20, 40, 19, 0, 0, 0, 0, 0, "Add a new Script link");
+ if (script->totscript)
+ uiDefBut(block, BUT, B_SCRIPT_DEL, "Del", (short)(sx+200), (short)sy-20, 40, 19, 0, 0, 0, 0, 0, "Delete the current Script link");
+ uiDefBut(block, LABEL, 0, "Selected Script link", sx,sy-20,140,20, 0, 0, 0, 0, 0, "");
+
+ }
+
+}
+
+/* ************************************* */
+
+static void script_panel_scriptlink(void)
+{
+ uiBlock *block;
+ Object *ob=NULL;
+ ScriptLink *script=NULL;
+ Material *ma;
+ int xco = 10;
+
+ block= uiNewBlock(&curarea->uiblocks, "script_panel_scriptlink", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Scriptlinks", "Script", 0, 0, 318, 204)==0) return;
+
+ uiDefButBitI(block, TOG, G_DOSCRIPTLINKS, REDRAWBUTSSCRIPT,
+ "Enable Script Links", xco, 200, 150, 20, &G.f, 0, 0, 0, 0,
+ "Enable execution of all assigned Script links and Space Handelers");
+ /* for proper alignment: */
+ uiDefBut(block, LABEL, 0, "", 160, 200,150,20, NULL, 0.0, 0.0, 0, 0, "");
+
+ if (G.f & G_DOSCRIPTLINKS) {
+ //uiBlockBeginAlign(block);
+ ob= OBACT;
+ if(ob)
+ uiDefIconButS(block, ROW, B_REDR, ICON_OBJECT, xco,175,25,20, &G.buts->scriptblock, 2.0, (float)ID_OB, 0, 0, "Displays Object script links");
+
+ if(ob && give_current_material(ob, ob->actcol))
+ uiDefIconButS(block, ROW, B_REDR, ICON_MATERIAL, xco+=25,175,25,20, &G.buts->scriptblock, 2.0, (float)ID_MA, 0, 0, "Displays Material script links ");
+
+ if(G.scene->world)
+ uiDefIconButS(block, ROW, B_REDR, ICON_WORLD, xco+=25,175,25,20, &G.buts->scriptblock, 2.0, (float)ID_WO, 0, 0, "Displays World script links");
+
+ if(ob && ob->type==OB_CAMERA)
+ uiDefIconButS(block, ROW, B_REDR, ICON_CAMERA, xco+=25,175,25,20, &G.buts->scriptblock, 2.0, (float)ID_CA, 0, 0, "Displays Camera script links");
+
+ if(ob && ob->type==OB_LAMP)
+ uiDefIconButS(block, ROW, B_REDR, ICON_LAMP, xco+=25,175,25,20, &G.buts->scriptblock, 2.0, (float)ID_LA, 0, 0, "Displays Lamp script links");
+ //uiBlockEndAlign(block);
+
+ if (ob && G.buts->scriptblock==ID_OB) {
+ script= &ob->scriptlink;
+
+ } else if (ob && G.buts->scriptblock==ID_MA) {
+ ma= give_current_material(ob, ob->actcol);
+ if (ma) script= &ma->scriptlink;
+
+ } else if (ob && G.buts->scriptblock==ID_CA) {
+ if (ob->type==OB_CAMERA)
+ script= &((Camera *)ob->data)->scriptlink;
+
+ } else if (ob && G.buts->scriptblock==ID_LA) {
+ if (ob->type==OB_LAMP)
+ script= &((Lamp *)ob->data)->scriptlink;
+
+ } else if (G.buts->scriptblock==ID_WO) {
+ if (G.scene->world)
+ script= &(G.scene->world->scriptlink);
+ }
+
+ if (script) draw_scriptlink(block, script, 10, 140, 0);
+
+ draw_scriptlink(block, &G.scene->scriptlink, 10, 80, 1);
+ }
+}
+
+
+
+
+void script_panels()
+{
+ script_panel_scriptlink();
+
+}
diff --git a/source/blender/src/buttons_shading.c b/source/blender/src/buttons_shading.c
new file mode 100644
index 00000000000..67ccf78c5f6
--- /dev/null
+++ b/source/blender/src/buttons_shading.c
@@ -0,0 +1,4235 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: not all of this file anymore. :)
+ *
+ * Contributor(s):
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <time.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_customdata_types.h"
+#include "DNA_image_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_node_types.h"
+#include "DNA_packedFile_types.h"
+#include "DNA_radio_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_world_types.h"
+
+#include "BKE_colortools.h"
+#include "BKE_displist.h"
+#include "BKE_effect.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_node.h"
+#include "BKE_material.h"
+#include "BKE_utildefines.h"
+#include "BKE_texture.h"
+
+#include "BKE_packedFile.h"
+#include "BKE_plugin_types.h"
+#include "BKE_image.h"
+
+#include "BLI_blenlib.h"
+#include "BMF_Api.h"
+
+#include "BSE_filesel.h"
+#include "BSE_headerbuttons.h"
+#include "BSE_node.h"
+
+#include "BDR_drawmesh.h"
+
+#include "BIF_drawimage.h"
+#include "BIF_gl.h"
+#include "BIF_graphics.h"
+#include "BIF_keyval.h"
+#include "BIF_mainqueue.h"
+#include "BIF_resources.h"
+#include "BIF_screen.h"
+#include "BIF_mywindow.h"
+#include "BIF_space.h"
+#include "BIF_glutil.h"
+#include "BIF_imasel.h"
+#include "BIF_interface.h"
+#include "BIF_toolbox.h"
+#include "BIF_space.h"
+#include "BIF_previewrender.h"
+#include "BIF_butspace.h"
+#include "BIF_writeimage.h"
+#include "BIF_toets.h"
+
+#include "mydevice.h"
+#include "blendef.h"
+#include "radio.h"
+
+#include "RE_pipeline.h"
+
+/* -----includes for this file specific----- */
+
+#include "butspace.h" // own module
+
+
+static MTex emptytex;
+static int packdummy = 0;
+
+static char *mapto_blendtype_pup(void)
+{
+ static char formatstr[] = "|%s %%x%d";
+ static char string[1024];
+ char *str = string;
+
+ str += sprintf(str, formatstr, "Mix", MTEX_BLEND);
+
+ str += sprintf(str, formatstr, "Add", MTEX_ADD);
+ str += sprintf(str, formatstr, "Subtract", MTEX_SUB);
+
+ str += sprintf(str, formatstr, "Multiply", MTEX_MUL);
+ str += sprintf(str, formatstr, "Screen", MTEX_SCREEN);
+ str += sprintf(str, formatstr, "Overlay", MTEX_OVERLAY);
+
+ str += sprintf(str, formatstr, "Difference", MTEX_DIFF);
+ str += sprintf(str, formatstr, "Divide", MTEX_DIV);
+
+ str += sprintf(str, formatstr, "Darken", MTEX_DARK);
+ str += sprintf(str, formatstr, "Lighten", MTEX_LIGHT);
+
+ return string;
+}
+
+void shade_buttons_change_3d(void)
+{
+ Object *ob= OBACT;
+ ScrArea *sa;
+
+ if(ob==NULL) return;
+
+ for(sa= G.curscreen->areabase.first; sa; sa= sa->next) {
+ if(sa->spacetype==SPACE_VIEW3D) {
+ View3D *v3d= sa->spacedata.first;
+
+ if(v3d->drawtype >= OB_SOLID) addqueue(sa->win, REDRAW, 0);
+ if(v3d->drawtype == OB_SHADED) {
+ if(ob->type==OB_LAMP) reshadeall_displist();
+ else {
+ /* all objects using material */
+ Base *base= FIRSTBASE;
+ Material *ma= give_current_material(ob, ob->actcol);
+ int a;
+
+ while(base) {
+ if(base->lay & G.vd->lay) {
+ for(a=1; a<=ob->totcol; a++) {
+ if(ma == give_current_material(base->object, a)) {
+ freedisplist(&(base->object->disp));
+ break;
+ }
+ }
+ }
+ base= base->next;
+ }
+ }
+ }
+ }
+ }
+}
+
+/* *************************** TEXTURE ******************************** */
+
+static void load_image_cb(char *str, void *ima_pp_v, void *iuser_v) /* called from fileselect or button */
+{
+ Image **ima_pp= (Image **)ima_pp_v;
+ Image *ima= NULL;
+
+ ima= BKE_add_image_file(str);
+ if(ima) {
+ if(*ima_pp) {
+ (*ima_pp)->id.us--;
+ }
+ *ima_pp= ima;
+
+ BKE_image_signal(ima, iuser_v, IMA_SIGNAL_RELOAD);
+
+ /* button event gets lost when it goes via filewindow */
+ if(G.buts && G.buts->lockpoin) {
+ Tex *tex= G.buts->lockpoin;
+ if(GS(tex->id.name)==ID_TE) {
+ BIF_preview_changed(ID_TE);
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWOOPS, 0);
+ }
+ }
+ }
+
+ BIF_undo_push("Load image");
+}
+
+static void load_plugin_tex(char *str, void *tex_v, void *unused) /* called from fileselect */
+{
+ Tex *tex= tex_v;
+
+ if(tex->type!=TEX_PLUGIN) return;
+
+ if(tex->plugin) free_plugin_tex(tex->plugin);
+
+ tex->stype= 0;
+ tex->plugin= add_plugin_tex(str);
+
+ allqueue(REDRAWBUTSSHADING, 0);
+ BIF_preview_changed(ID_TE);
+}
+
+static void save_env(char *name)
+{
+ Tex *tex;
+ char str[FILE_MAX];
+
+ strcpy(str, name);
+ BLI_convertstringcode(str, G.sce, G.scene->r.cfra);
+ tex= G.buts->lockpoin;
+
+ if(tex && GS(tex->id.name)==ID_TE) {
+ if(tex->env && tex->env->ok && saveover(str)) {
+ waitcursor(1);
+ BIF_save_envmap(tex->env, str);
+ strcpy(G.ima, name);
+ waitcursor(0);
+ }
+ }
+
+}
+
+static int vergcband(const void *a1, const void *a2)
+{
+ const CBData *x1=a1, *x2=a2;
+
+ if( x1->pos > x2->pos ) return 1;
+ else if( x1->pos < x2->pos) return -1;
+ return 0;
+}
+
+void do_texbuts(unsigned short event)
+{
+ Tex *tex;
+ ScrArea *sa;
+ char str[FILE_MAX];
+
+ tex= G.buts->lockpoin;
+
+ switch(event) {
+ case B_TEXPRV:
+ BIF_preview_changed(ID_TE);
+ allqueue(REDRAWBUTSSHADING, 0);
+
+ if(tex && G.scene->nodetree) {
+ NodeTagIDChanged(G.scene->nodetree, &tex->id);
+ allqueue(RECALC_COMPOSITE, 0);
+ }
+ break;
+ case B_TEXCHANNEL:
+ scrarea_queue_headredraw(curarea);
+ BIF_preview_changed(ID_TE);
+ allqueue(REDRAWBUTSSHADING, 0);
+ if(G.buts->texfrom == 3) /* brush texture */
+ allqueue(REDRAWIMAGE, 0);
+ break;
+ case B_TEXTYPE:
+ if(tex==NULL) return;
+ tex->stype= 0;
+ allqueue(REDRAWBUTSSHADING, 0);
+ BIF_preview_changed(ID_TE);
+
+ if(tex && G.scene->nodetree) {
+ NodeTagIDChanged(G.scene->nodetree, &tex->id);
+ allqueue(RECALC_COMPOSITE, 0);
+ }
+ break;
+ case B_DEFTEXVAR:
+ if(tex==NULL) return;
+ default_tex(tex);
+ BIF_undo_push("Default texture vars");
+ allqueue(REDRAWBUTSSHADING, 0);
+ BIF_preview_changed(ID_TE);
+ break;
+
+ case B_IMAGECHANGED:
+ BIF_preview_changed(ID_TE);
+ allqueue(REDRAWBUTSSHADING, 0);
+
+ if(tex) {
+ if(G.scene->nodetree) {
+ NodeTagIDChanged(G.scene->nodetree, &tex->id);
+ allqueue(RECALC_COMPOSITE, 0);
+ }
+ if(tex->ima && (tex->imaflag & TEX_MIPMAP) && (tex->ima->flag & IMA_FIELDS)) {
+ error("Cannot combine fields and mipmap");
+ tex->imaflag -= TEX_MIPMAP;
+ }
+ if(tex->env)
+ BKE_free_envmapdata(tex->env);
+ }
+
+ break;
+
+ case B_TEXREDR_PRV:
+ allqueue(REDRAWBUTSSHADING, 0);
+ BIF_preview_changed(ID_TE);
+ shade_buttons_change_3d();
+ break;
+
+
+ case B_LOADPLUGIN:
+ if(tex==NULL) return;
+
+ sa= closest_bigger_area();
+ areawinset(sa->win);
+ if(tex->plugin) strcpy(str, tex->plugin->name);
+ else {
+ strcpy(str, U.plugtexdir);
+ }
+ activate_fileselect_args(FILE_SPECIAL, "SELECT PLUGIN", str, load_plugin_tex, tex, NULL);
+
+ break;
+
+ case B_NAMEPLUGIN:
+ if(tex==NULL || tex->plugin==NULL) return;
+ strcpy(str, tex->plugin->name);
+ free_plugin_tex(tex->plugin);
+ tex->stype= 0;
+ tex->plugin= add_plugin_tex(str);
+ allqueue(REDRAWBUTSSHADING, 0);
+ BIF_preview_changed(ID_TE);
+ break;
+
+ case B_COLORBAND:
+ if(tex==NULL) return;
+ if(tex->coba==NULL) tex->coba= add_colorband(0);
+ allqueue(REDRAWBUTSSHADING, 0);
+ BIF_preview_changed(ID_TE); // also ramps, so we do this
+ break;
+
+ case B_ENV_DELETE:
+ if(tex->env) {
+ BKE_free_envmap(tex->env);
+ tex->env= 0;
+ allqueue(REDRAWBUTSSHADING, 0);
+ BIF_preview_changed(ID_TE);
+ }
+ break;
+ case B_ENV_FREE:
+ if(tex->env) {
+ BKE_free_envmapdata(tex->env);
+ allqueue(REDRAWBUTSSHADING, 0);
+ BIF_preview_changed(ID_TE);
+ }
+ break;
+ case B_ENV_FREE_ALL:
+ tex= G.main->tex.first;
+ while(tex) {
+ if(tex->id.us && tex->type==TEX_ENVMAP) {
+ if(tex->env) {
+ if(tex->env->stype!=ENV_LOAD) BKE_free_envmapdata(tex->env);
+ }
+ }
+ tex= tex->id.next;
+ }
+ allqueue(REDRAWBUTSSHADING, 0);
+ BIF_preview_changed(ID_TE);
+ break;
+ case B_ENV_SAVE:
+ if(tex->env && tex->env->ok) {
+ if(tex->env->type==ENV_PLANE) {
+ notice("Sorry, not implemented yet");
+ }
+ else {
+ sa= closest_bigger_area();
+ areawinset(sa->win);
+ save_image_filesel_str(str);
+ activate_fileselect(FILE_SPECIAL, str, G.ima, save_env);
+ }
+ }
+ break;
+ case B_ENV_OB:
+ if(tex->env && tex->env->object) {
+ BIF_preview_changed(ID_TE);
+ if ELEM(tex->env->object->type, OB_CAMERA, OB_LAMP) {
+ error("Camera or Lamp not allowed");
+ tex->env->object= NULL;
+ }
+ }
+ break;
+
+ default:
+ if(event>=B_PLUGBUT && event<=B_PLUGBUT+23) {
+ PluginTex *pit= tex->plugin;
+ if(pit && pit->callback) {
+ pit->callback(event - B_PLUGBUT);
+ BIF_preview_changed(ID_TE);
+ allqueue(REDRAWBUTSSHADING, 0);
+ }
+ }
+ }
+}
+
+static void texture_panel_plugin(Tex *tex)
+{
+ uiBlock *block;
+ VarStruct *varstr;
+ PluginTex *pit;
+ short xco, yco, a;
+
+ block= uiNewBlock(&curarea->uiblocks, "texture_panel_plugin", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Plugin", "Texture", 640, 0, 318, 204)==0) return;
+ uiSetButLock(tex->id.lib!=0, ERROR_LIBDATA_MESSAGE);
+
+ if(tex->plugin && tex->plugin->doit) {
+
+ pit= tex->plugin;
+
+ for(a=0; a<pit->stypes; a++) {
+ uiDefButS(block, ROW, B_TEXREDR_PRV, pit->stnames+16*a, (76*a), 152, 75, 20, &tex->stype, 2.0, (float)a, 0, 0, "");
+ }
+
+ varstr= pit->varstr;
+ if(varstr) {
+ for(a=0; a<pit->vars; a++, varstr++) {
+ xco= 140*(a/6)+1;
+ yco= 125 - 20*(a % 6)+1;
+ uiDefBut(block, varstr->type, B_PLUGBUT+a, varstr->name, xco,yco,137,19, &(pit->data[a]), varstr->min, varstr->max, 100, 0, varstr->tip);
+ }
+ }
+ uiDefBut(block, TEX, B_NAMEPLUGIN, "", 0,180,318,24, pit->name, 0.0, 159.0, 0, 0, "");
+ }
+
+ uiDefBut(block, BUT, B_LOADPLUGIN, "Load Plugin", 0,204,137,24, 0, 0, 0, 0, 0, "");
+
+}
+
+
+static void texture_panel_magic(Tex *tex)
+{
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "texture_panel_magic", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Magic", "Texture", 640, 0, 318, 204)==0) return;
+ uiSetButLock(tex->id.lib!=0, ERROR_LIBDATA_MESSAGE);
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, NUM, B_TEXPRV, "Depth:", 10, 90, 150, 19, &tex->noisedepth, 0.0, 10.0, 0, 0, "Sets the depth of the pattern");
+ uiDefButF(block, NUM, B_TEXPRV, "Turbulence:", 10, 70, 150, 19, &tex->turbul, 0.0, 200.0, 10, 0, "Sets the strength of the pattern");
+}
+
+static void texture_panel_blend(Tex *tex)
+{
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "texture_panel_blend", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Blend", "Texture", 640, 0, 318, 204)==0) return;
+ uiSetButLock(tex->id.lib!=0, ERROR_LIBDATA_MESSAGE);
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, ROW, B_TEXPRV, "Lin", 10, 180, 75, 19, &tex->stype, 2.0, (float)TEX_LIN, 0, 0, "Creates a linear progresion");
+ uiDefButS(block, ROW, B_TEXPRV, "Quad", 85, 180, 75, 19, &tex->stype, 2.0, (float)TEX_QUAD, 0, 0, "Creates a quadratic progression");
+ uiDefButS(block, ROW, B_TEXPRV, "Ease", 160, 180, 75, 19, &tex->stype, 2.0, (float)TEX_EASE, 0, 0, "Creates a progression easing from one step to the next");
+ uiDefButBitS(block, TOG, TEX_FLIPBLEND, B_TEXPRV, "Flip XY", 235, 180, 75, 19, &tex->flag, 0, 0, 0, 0, "Flips the direction of the progression 90 degrees");
+
+ uiDefButS(block, ROW, B_TEXPRV, "Diag", 10, 160, 75, 19, &tex->stype, 2.0, (float)TEX_DIAG, 0, 0, "Use a diagonal progression");
+ uiDefButS(block, ROW, B_TEXPRV, "Sphere", 85, 160, 75, 19, &tex->stype, 2.0, (float)TEX_SPHERE, 0, 0, "Use progression with the shape of a sphere");
+ uiDefButS(block, ROW, B_TEXPRV, "Halo", 160, 160, 75, 19, &tex->stype, 2.0, (float)TEX_HALO, 0, 0, "Use a quadratic progression with the shape of a sphere");
+ uiDefButS(block, ROW, B_TEXPRV, "Radial", 235, 160, 75, 19, &tex->stype, 2.0, (float)TEX_RAD, 0, 0, "Use a polar progression");
+
+}
+
+/* newnoise: noisebasis menu string */
+static char* noisebasis_menu()
+{
+ static char nbmenu[256];
+ sprintf(nbmenu, "Noise Basis %%t|Blender Original %%x%d|Original Perlin %%x%d|Improved Perlin %%x%d|Voronoi F1 %%x%d|Voronoi F2 %%x%d|Voronoi F3 %%x%d|Voronoi F4 %%x%d|Voronoi F2-F1 %%x%d|Voronoi Crackle %%x%d|CellNoise %%x%d", TEX_BLENDER, TEX_STDPERLIN, TEX_NEWPERLIN, TEX_VORONOI_F1, TEX_VORONOI_F2, TEX_VORONOI_F3, TEX_VORONOI_F4, TEX_VORONOI_F2F1, TEX_VORONOI_CRACKLE, TEX_CELLNOISE);
+ return nbmenu;
+}
+
+static void texture_panel_wood(Tex *tex)
+{
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "texture_panel_wood", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Wood", "Texture", 640, 0, 318, 204)==0) return;
+ uiSetButLock(tex->id.lib!=0, ERROR_LIBDATA_MESSAGE);
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, ROW, B_TEXPRV, "Bands", 10, 180, 75, 18, &tex->stype, 2.0, (float)TEX_BAND, 0, 0, "Uses standard wood texture in bands");
+ uiDefButS(block, ROW, B_TEXPRV, "Rings", 85, 180, 75, 18, &tex->stype, 2.0, (float)TEX_RING, 0, 0, "Uses wood texture in rings");
+ uiDefButS(block, ROW, B_TEXPRV, "BandNoise", 160, 180, 75, 18, &tex->stype, 2.0, (float)TEX_BANDNOISE, 0, 0, "Adds noise to standard wood");
+ uiDefButS(block, ROW, B_TEXPRV, "RingNoise", 235, 180, 75, 18, &tex->stype, 2.0, (float)TEX_RINGNOISE, 0, 0, "Adds noise to rings");
+
+ uiDefButS(block, ROW, B_TEXPRV, "Sin", 10, 160, 50, 19, &tex->noisebasis2, 8.0, (float)TEX_SIN, 0, 0, "Uses a sine wave to produce bands");
+ uiDefButS(block, ROW, B_TEXPRV, "Saw", 60, 160, 50, 19, &tex->noisebasis2, 8.0, (float)TEX_SAW, 0, 0, "Uses a saw wave to produce bands");
+ uiDefButS(block, ROW, B_TEXPRV, "Tri", 110, 160, 50, 19, &tex->noisebasis2, 8.0, (float)TEX_TRI, 0, 0, "Uses a triangle wave to produce bands");
+ uiDefButS(block, ROW, B_TEXPRV, "Soft noise", 160, 160, 75, 19, &tex->noisetype, 12.0, (float)TEX_NOISESOFT, 0, 0, "Generates soft noise");
+ uiDefButS(block, ROW, B_TEXPRV, "Hard noise", 235, 160, 75, 19, &tex->noisetype, 12.0, (float)TEX_NOISEPERL, 0, 0, "Generates hard noise");
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_TEXPRV, "NoiseSize :", 10, 130, 150, 19, &tex->noisesize, 0.0001, 2.0, 10, 0, "Sets scaling for noise input");
+ uiDefButF(block, NUM, B_TEXPRV, "Turbulence:", 160, 130, 150, 19, &tex->turbul, 0.0, 200.0, 10, 0, "Sets the turbulence of the bandnoise and ringnoise types");
+ uiBlockEndAlign(block);
+
+ /* newnoise: noisebasis menu */
+ uiDefBut(block, LABEL, 0, "Noise Basis", 10, 30, 150, 19, 0, 0.0, 0.0, 0, 0, "");
+ uiDefButS(block, MENU, B_TEXPRV, noisebasis_menu(), 10, 10, 150, 19, &tex->noisebasis, 0,0,0,0, "Sets the noise basis used for turbulence");
+ uiDefButF(block, NUM, B_NOP, "Nabla: ", 160, 10, 150, 19, &tex->nabla, 0.001, 0.1, 1, 0, "Defines size of derivative offset used for calculating normal");
+
+}
+
+static void texture_panel_stucci(Tex *tex)
+{
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "texture_panel_stucci", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Stucci", "Texture", 640, 0, 318, 204)==0) return;
+ uiSetButLock(tex->id.lib!=0, ERROR_LIBDATA_MESSAGE);
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, ROW, B_TEXPRV, "Plastic", 10, 180, 100, 19, &tex->stype, 2.0, (float)TEX_PLASTIC, 0, 0, "Uses standard stucci");
+ uiDefButS(block, ROW, B_TEXPRV, "Wall In", 110, 180, 100, 19, &tex->stype, 2.0, (float)TEX_WALLIN, 0, 0, "Creates Dimples");
+ uiDefButS(block, ROW, B_TEXPRV, "Wall Out", 210, 180, 100, 19, &tex->stype, 2.0, (float)TEX_WALLOUT, 0, 0, "Creates Ridges");
+
+ uiDefButS(block, ROW, B_TEXPRV, "Soft noise", 10, 160, 150, 19, &tex->noisetype, 12.0, (float)TEX_NOISESOFT, 0, 0, "Generates soft noise");
+ uiDefButS(block, ROW, B_TEXPRV, "Hard noise", 160, 160, 150, 19, &tex->noisetype, 12.0, (float)TEX_NOISEPERL, 0, 0, "Generates hard noise");
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_TEXPRV, "NoiseSize :", 10, 110, 150, 19, &tex->noisesize, 0.0001, 2.0, 10, 0, "Sets scaling for noise input");
+ uiDefButF(block, NUM, B_TEXPRV, "Turbulence:", 10, 90, 150, 19, &tex->turbul, 0.0, 200.0, 10, 0, "Sets the depth of the stucci");
+ uiBlockEndAlign(block);
+
+ /* newnoise: noisebasis menu */
+ uiDefBut(block, LABEL, 0, "Noise Basis", 10, 30, 150, 19, 0, 0.0, 0.0, 0, 0, "");
+ uiDefButS(block, MENU, B_TEXPRV, noisebasis_menu(), 10, 10, 150, 19, &tex->noisebasis, 0,0,0,0, "Sets the noise basis used for turbulence");
+ // note, nabla not supported here!
+// uiDefButF(block, NUM, B_NOP, "Nabla: ", 160, 10, 150, 19, &tex->nabla, 0.001, 0.1, 1, 0, "Defines size of derivative offset used for calculating normal");
+
+}
+
+static void texture_panel_marble(Tex *tex)
+{
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "texture_panel_marble", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Marble", "Texture", 640, 0, 318, 204)==0) return;
+ uiSetButLock(tex->id.lib!=0, ERROR_LIBDATA_MESSAGE);
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, ROW, B_TEXPRV, "Soft", 10, 180, 100, 18, &tex->stype, 2.0, (float)TEX_SOFT, 0, 0, "Uses soft marble");
+ uiDefButS(block, ROW, B_TEXPRV, "Sharp", 110, 180, 100, 18, &tex->stype, 2.0, (float)TEX_SHARP, 0, 0, "Uses more clearly defined marble");
+ uiDefButS(block, ROW, B_TEXPRV, "Sharper", 210, 180, 100, 18, &tex->stype, 2.0, (float)TEX_SHARPER, 0, 0, "Uses very clearly defined marble");
+
+ uiDefButS(block, ROW, B_TEXPRV, "Soft noise", 10, 160, 150, 19, &tex->noisetype, 12.0, (float)TEX_NOISESOFT, 0, 0, "Generates soft noise");
+ uiDefButS(block, ROW, B_TEXPRV, "Hard noise", 160, 160, 150, 19, &tex->noisetype, 12.0, (float)TEX_NOISEPERL, 0, 0, "Generates hard noise");
+
+ uiDefButS(block, ROW, B_TEXPRV, "Sin", 10, 140, 100, 18, &tex->noisebasis2, 8.0, 0.0, 0, 0, "Uses a sine wave to produce bands.");
+ uiDefButS(block, ROW, B_TEXPRV, "Saw", 110, 140, 100, 18, &tex->noisebasis2, 8.0, 1.0, 0, 0, "Uses a saw wave to produce bands");
+ uiDefButS(block, ROW, B_TEXPRV, "Tri", 210, 140, 100, 18, &tex->noisebasis2, 8.0, 2.0, 0, 0, "Uses a triangle wave to produce bands");
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_TEXPRV, "NoiseSize :", 10, 110, 150, 19, &tex->noisesize, 0.0001, 2.0, 10, 0, "Sets scaling for noise input");
+ uiDefButS(block, NUM, B_TEXPRV, "NoiseDepth:", 10, 90, 150, 19, &tex->noisedepth, 0.0, 6.0, 0, 0, "Sets the depth of the marble calculation");
+ uiDefButF(block, NUM, B_TEXPRV, "Turbulence:", 10, 70, 150, 19, &tex->turbul, 0.0, 200.0, 10, 0, "Sets the turbulence of the sine bands");
+ uiBlockEndAlign(block);
+
+ /* newnoise: noisebasis menu */
+ uiDefBut(block, LABEL, 0, "Noise Basis", 10, 30, 150, 19, 0, 0.0, 0.0, 0, 0, "");
+ uiDefButS(block, MENU, B_TEXPRV, noisebasis_menu(), 10, 10, 150, 19, &tex->noisebasis, 0,0,0,0, "Sets the noise basis used for turbulence");
+ uiDefButF(block, NUM, B_NOP, "Nabla: ", 160, 10, 150, 19, &tex->nabla, 0.001, 0.1, 1, 0, "Defines size of derivative offset used for calculating normal");
+
+}
+
+static void texture_panel_clouds(Tex *tex)
+{
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "texture_panel_clouds", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Clouds", "Texture", 640, 0, 318, 204)==0) return;
+ uiSetButLock(tex->id.lib!=0, ERROR_LIBDATA_MESSAGE);
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, ROW, B_TEXPRV, "Default", 10, 180, 70, 18, &tex->stype, 2.0, (float)TEX_DEFAULT, 0, 0, "Uses standard noise");
+ uiDefButS(block, ROW, B_TEXPRV, "Color", 80, 180, 70, 18, &tex->stype, 2.0, (float)TEX_COLOR, 0, 0, "Lets Noise return RGB value");
+ uiDefButS(block, ROW, B_TEXPRV, "Soft noise", 155, 180, 75, 18, &tex->noisetype, 12.0, (float)TEX_NOISESOFT, 0, 0, "Generates soft noise");
+ uiDefButS(block, ROW, B_TEXPRV, "Hard noise", 230, 180, 80, 18, &tex->noisetype, 12.0, (float)TEX_NOISEPERL, 0, 0, "Generates hard noise");
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_TEXPRV, "NoiseSize :", 10, 130, 150, 19, &tex->noisesize, 0.0001, 2.0, 10, 0, "Sets scaling for noise input");
+ uiDefButS(block, NUM, B_TEXPRV, "NoiseDepth:", 160, 130, 150, 19, &tex->noisedepth, 0.0, 6.0, 0, 0, "Sets the depth of the cloud calculation");
+ uiBlockEndAlign(block);
+
+ /* newnoise: noisebasis menu */
+ uiDefBut(block, LABEL, 0, "Noise Basis", 10, 30, 150, 19, 0, 0.0, 0.0, 0, 0, "");
+ uiDefButS(block, MENU, B_TEXPRV, noisebasis_menu(), 10, 10, 150, 19, &tex->noisebasis, 0,0,0,0, "Sets the noise basis used for turbulence");
+ uiDefButF(block, NUM, B_NOP, "Nabla: ", 160, 10, 150, 19, &tex->nabla, 0.001, 0.1, 1, 0, "Defines size of derivative offset used for calculating normal");
+
+}
+
+/*****************************************/
+/* newnoise: panel(s) for musgrave types */
+/*****************************************/
+
+static void texture_panel_musgrave(Tex *tex)
+{
+ uiBlock *block;
+ char *str;
+
+ block= uiNewBlock(&curarea->uiblocks, "texture_panel_musgrave", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Musgrave", "Texture", 640, 0, 318, 204)==0) return;
+ uiSetButLock(tex->id.lib!=0, ERROR_LIBDATA_MESSAGE);
+
+ /* TEX_MFRACTAL, TEX_RIDGEDMF, TEX_HYBRIDMF, TEX_FBM, TEX_HTERRAIN */
+ str= "Multifractal %x0|Ridged Multifractal %x1|Hybrid Multifractal %x2|Hetero Terrain %x4|fBm %x3";
+ uiDefButS(block, MENU, B_TEXREDR_PRV, str, 10, 160, 150, 19, &tex->stype, 0.0, 0.0, 0, 0, "Sets Musgrave type");
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUMSLI, B_TEXPRV, "H: ", 10, 130, 150, 19, &tex->mg_H, 0.0001, 2.0, 10, 0, "Sets the highest fractal dimension");
+ uiDefButF(block, NUMSLI, B_TEXPRV, "Lacu: ", 160, 130, 150, 19, &tex->mg_lacunarity, 0.0, 6.0, 10, 0, "Sets the gap between succesive frequencies");
+ uiDefButF(block, NUMSLI, B_TEXPRV, "Octs: ", 10, 110, 150, 19, &tex->mg_octaves, 0.0, 8.0, 10, 0, "Sets the number of frequencies used");
+ if ((tex->stype==TEX_RIDGEDMF) || (tex->stype==TEX_HYBRIDMF) || (tex->stype==TEX_HTERRAIN)) {
+ uiDefButF(block, NUMSLI, B_TEXPRV, "Ofst: ", 160, 110, 150, 19, &tex->mg_offset, 0.0, 6.0, 10, 0, "Sets the fractal offset");
+ if ((tex->stype==TEX_RIDGEDMF) || (tex->stype==TEX_HYBRIDMF))
+ uiDefButF(block, NUMSLI, B_TEXPRV, "Gain: ", 10, 90, 150, 19, &tex->mg_gain, 0.0, 6.0, 10, 0, "Sets the gain multiplier");
+ }
+
+ uiBlockBeginAlign(block);
+ /* noise output scale */
+ uiDefButF(block, NUM, B_TEXPRV, "iScale: ", 10, 60, 150, 19, &tex->ns_outscale, 0.0, 10.0, 10, 0, "Scales intensity output");
+ /* frequency scale */
+ uiDefButF(block, NUM, B_TEXPRV, "NoiseSize: ", 160, 60, 150, 19, &tex->noisesize, 0.0001, 2.0, 10, 0, "Sets scaling for noise input");
+ uiBlockEndAlign(block);
+
+ /* noisebasis menu */
+ uiDefBut(block, LABEL, 0, "Noise Basis", 10, 30, 150, 19, 0, 0.0, 0.0, 0, 0, "");
+ uiDefButS(block, MENU, B_TEXPRV, noisebasis_menu(), 10, 10, 150, 19, &tex->noisebasis, 0,0,0,0, "Sets the noise basis used for turbulence");
+ uiDefButF(block, NUM, B_NOP, "Nabla: ", 160, 10, 150, 19, &tex->nabla, 0.001, 0.1, 1, 0, "Defines size of derivative offset used for calculating normal");
+
+}
+
+
+static void texture_panel_distnoise(Tex *tex)
+{
+ uiBlock *block;
+ block= uiNewBlock(&curarea->uiblocks, "texture_panel_distnoise", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Distorted Noise", "Texture", 640, 0, 318, 204)==0) return;
+ uiSetButLock(tex->id.lib!=0, ERROR_LIBDATA_MESSAGE);
+
+ uiBlockBeginAlign(block);
+ /* distortion amount */
+ uiDefButF(block, NUM, B_TEXPRV, "DistAmnt: ", 10, 130, 150, 19, &tex->dist_amount, 0.0, 10.0, 10, 0, "Sets amount of distortion");
+ /* frequency scale */
+ uiDefButF(block, NUM, B_TEXPRV, "NoiseSize: ", 160, 130, 150, 19, &tex->noisesize, 0.0001, 2.0, 10, 0, "Sets scaling for noise input");
+ uiBlockEndAlign(block);
+
+ uiDefBut(block, LABEL, 0, "Distortion Noise", 10, 100, 150, 19, 0, 0.0, 0.0, 0, 0, "");
+ uiDefBut(block, LABEL, 0, "Noise Basis", 160, 100, 150, 19, 0, 0.0, 0.0, 0, 0, "");
+
+ uiBlockBeginAlign(block);
+ /* noisebasis used for the distortion */
+ uiDefButS(block, MENU, B_TEXPRV, noisebasis_menu(), 10, 80, 150, 19, &tex->noisebasis, 0,0,0,0, "Sets the noise basis which does the distortion");
+ /* noisebasis to distort */
+ uiDefButS(block, MENU, B_TEXPRV, noisebasis_menu(), 160, 80, 150, 19, &tex->noisebasis2, 0,0,0,0, "Sets the noise basis to distort");
+ uiBlockEndAlign(block);
+
+ uiDefButF(block, NUM, B_NOP, "Nabla: ", 10, 50, 150, 19, &tex->nabla, 0.001, 0.1, 1, 0, "Defines size of derivative offset used for calculating normal");
+}
+
+
+static void texture_panel_voronoi(Tex *tex)
+{
+ char dm_menu[256];
+ uiBlock *block;
+ block= uiNewBlock(&curarea->uiblocks, "texture_panel_voronoi", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Voronoi", "Texture", 640, 0, 318, 204)==0) return;
+ uiSetButLock(tex->id.lib!=0, ERROR_LIBDATA_MESSAGE);
+
+ /* color types */
+ uiBlockBeginAlign(block);
+ uiDefButS(block, ROW, B_TEXPRV, "Int", 10, 180, 75, 18, &tex->vn_coltype, 1.0, 0.0, 0, 0, "Only calculate intensity");
+ uiDefButS(block, ROW, B_TEXPRV, "Col1", 85, 180, 75, 18, &tex->vn_coltype, 1.0, 1.0, 0, 0, "Color cells by position");
+ uiDefButS(block, ROW, B_TEXPRV, "Col2", 160, 180, 75, 18, &tex->vn_coltype, 1.0, 2.0, 0, 0, "Same as Col1 + outline based on F2-F1");
+ uiDefButS(block, ROW, B_TEXPRV, "Col3", 235, 180, 75, 18, &tex->vn_coltype, 1.0, 3.0, 0, 0, "Same as Col2 * intensity");
+ uiBlockEndAlign(block);
+
+ /* distance metric */
+ sprintf(dm_menu, "Distance Metric %%t|Actual Distance %%x%d|Distance Squared %%x%d|Manhattan %%x%d|Chebychev %%x%d|Minkovsky 1/2 %%x%d|Minkovsky 4 %%x%d|Minkovsky %%x%d", TEX_DISTANCE, TEX_DISTANCE_SQUARED, TEX_MANHATTAN, TEX_CHEBYCHEV, TEX_MINKOVSKY_HALF, TEX_MINKOVSKY_FOUR, TEX_MINKOVSKY);
+ uiDefBut(block, LABEL, B_TEXPRV, "Distance Metric", 10, 160, 150, 19, 0, 0, 0, 0, 0, "");
+ uiDefButS(block, MENU, B_TEXPRV, dm_menu, 10, 140, 150, 19, &tex->vn_distm, 0,0,0,0, "Sets the distance metric to be used");
+
+ if (tex->vn_distm==TEX_MINKOVSKY)
+ uiDefButF(block, NUMSLI, B_TEXPRV, "Exp: ", 10, 120, 150, 19, &tex->vn_mexp, 0.01, 10.0, 10, 0, "Sets minkovsky exponent");
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_TEXPRV, "iScale: ", 160, 140, 150, 19, &tex->ns_outscale, 0.01, 10.0, 10, 0, "Scales intensity output");
+ uiDefButF(block, NUM, B_TEXPRV, "Size: ", 160, 120, 150, 19, &tex->noisesize, 0.0001, 2.0, 10, 0, "Sets scaling for noise input");
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_NOP, "Nabla: ", 160, 70, 150, 19, &tex->nabla, 0.001, 0.1, 1, 0, "Defines size of derivative offset used for calculating normal");
+
+ /* weights */
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUMSLI, B_TEXPRV, "W1: ", 10, 70, 150, 19, &tex->vn_w1, -2.0, 2.0, 10, 0, "Sets feature weight 1");
+ uiDefButF(block, NUMSLI, B_TEXPRV, "W2: ", 10, 50, 150, 19, &tex->vn_w2, -2.0, 2.0, 10, 0, "Sets feature weight 2");
+ uiDefButF(block, NUMSLI, B_TEXPRV, "W3: ", 10, 30, 150, 19, &tex->vn_w3, -2.0, 2.0, 10, 0, "Sets feature weight 3");
+ uiDefButF(block, NUMSLI, B_TEXPRV, "W4: ", 10, 10, 150, 19, &tex->vn_w4, -2.0, 2.0, 10, 0, "Sets feature weight 4");
+}
+
+
+static char *layer_menu(RenderResult *rr, short *curlay)
+{
+ RenderLayer *rl;
+ int len= 64 + 32*BLI_countlist(&rr->layers);
+ short a, nr= 0;
+ char *str= MEM_callocN(len, "menu layers");
+
+ strcpy(str, "Layer %t");
+ a= strlen(str);
+
+ /* compo result */
+ if(rr->rectf) {
+ a+= sprintf(str+a, "|Composite %%x0");
+ nr= 1;
+ }
+ for(rl= rr->layers.first; rl; rl= rl->next, nr++) {
+ a+= sprintf(str+a, "|%s %%x%d", rl->name, nr);
+ }
+
+ if(*curlay >= nr)
+ *curlay= 0;
+
+ return str;
+}
+
+/* rl==NULL means composite result */
+static char *pass_menu(RenderLayer *rl, short *curpass)
+{
+ RenderPass *rpass;
+ int len= 64 + 32*(rl?BLI_countlist(&rl->passes):1);
+ short a, nr= 0;
+ char *str= MEM_callocN(len, "menu layers");
+
+ strcpy(str, "Pass %t");
+ a= strlen(str);
+
+ /* rendered results don't have a Combined pass */
+ if(rl==NULL || rl->rectf) {
+ a+= sprintf(str+a, "|Combined %%x0");
+ nr= 1;
+ }
+
+ if(rl)
+ for(rpass= rl->passes.first; rpass; rpass= rpass->next, nr++)
+ a+= sprintf(str+a, "|%s %%x%d", rpass->name, nr);
+
+ if(*curpass >= nr)
+ *curpass= 0;
+
+ return str;
+}
+
+static void set_frames_cb(void *ima_v, void *iuser_v)
+{
+ Image *ima= ima_v;
+ ImageUser *iuser= iuser_v;
+
+ if(ima->anim) {
+ iuser->frames = IMB_anim_get_duration(ima->anim);
+ BKE_image_user_calc_imanr(iuser, G.scene->r.cfra, 0);
+ }
+}
+
+static void image_src_change_cb(void *ima_v, void *iuser_v)
+{
+ BKE_image_signal(ima_v, iuser_v, IMA_SIGNAL_SRC_CHANGE);
+}
+
+/* buttons have 2 arg callbacks, filewindow has 3 args... so thats why the wrapper below */
+static void image_browse_cb1(char *unused, void *ima_pp_v, void *iuser_v)
+{
+ Image **ima_pp= (Image **)ima_pp_v;
+ ImageUser *iuser= iuser_v;
+
+ if(ima_pp) {
+ Image *ima= *ima_pp;
+
+ if(iuser->menunr== -2) {
+ activate_databrowse_args(&ima->id, ID_IM, 0, &iuser->menunr, image_browse_cb1, ima_pp, iuser);
+ }
+ else if (iuser->menunr>0) {
+ Image *newima= (Image*) BLI_findlink(&G.main->image, iuser->menunr-1);
+
+ if (newima && newima!=ima) {
+ *ima_pp= newima;
+ id_us_plus(&newima->id);
+ if(ima) ima->id.us--;
+
+ BKE_image_signal(newima, iuser, IMA_SIGNAL_USER_NEW_IMAGE);
+
+ BIF_undo_push("Browse image");
+ }
+ }
+ }
+}
+
+static void image_browse_cb(void *ima_pp_v, void *iuser_v)
+{
+ image_browse_cb1(NULL, ima_pp_v, iuser_v);
+}
+
+static void image_reload_cb(void *ima_v, void *iuser_v)
+{
+ if(ima_v) {
+ BKE_image_signal(ima_v, iuser_v, IMA_SIGNAL_RELOAD);
+ }
+}
+
+static void image_field_test(void *ima_v, void *iuser_v)
+{
+ Image *ima= ima_v;
+
+ if(ima) {
+ ImBuf *ibuf= BKE_image_get_ibuf(ima, iuser_v);
+ if(ibuf) {
+ short nr= 0;
+ if( !(ima->flag & IMA_FIELDS) && (ibuf->flags & IB_fields) ) nr= 1;
+ if( (ima->flag & IMA_FIELDS) && !(ibuf->flags & IB_fields) ) nr= 1;
+ if(nr) {
+ BKE_image_signal(ima, iuser_v, IMA_SIGNAL_FREE);
+ }
+ }
+ }
+}
+
+static void image_unlink_cb(void *ima_pp_v, void *unused)
+{
+ Image **ima_pp= (Image **)ima_pp_v;
+
+ if(ima_pp && *ima_pp) {
+ Image *ima= *ima_pp;
+ ima->id.us--;
+ *ima_pp= NULL;
+ }
+}
+
+static void image_load_fs_cb(void *ima_pp_v, void *iuser_v)
+{
+ Image **ima_pp= (Image **)ima_pp_v;
+ ScrArea *sa;
+ char *name;
+
+ if(ima_pp==NULL) return;
+
+ sa= closest_bigger_area();
+ areawinset(sa->win);
+ if(*ima_pp) name= (*ima_pp)->name;
+#ifdef _WIN32
+ else {
+ if (strcmp (U.textudir, "/") == 0)
+ name= G.sce;
+ else
+ name= U.textudir;
+ }
+#else
+ else name = U.textudir;
+#endif
+ if (G.qual & LR_CTRLKEY) {
+ activate_imageselect_args(FILE_SPECIAL, "SELECT IMAGE", name, load_image_cb, ima_pp_v, iuser_v);
+ }
+ else {
+ activate_fileselect_args(FILE_SPECIAL, "SELECT IMAGE", name, load_image_cb, ima_pp_v, iuser_v);
+ }
+}
+
+/* 5 layer button callbacks... */
+static void image_multi_cb(void *rr_v, void *iuser_v)
+{
+ BKE_image_multilayer_index(rr_v, iuser_v);
+}
+static void image_multi_inclay_cb(void *rr_v, void *iuser_v)
+{
+ RenderResult *rr= rr_v;
+ ImageUser *iuser= iuser_v;
+ int tot= BLI_countlist(&rr->layers) + (rr->rectf?1:0); /* fake compo result layer */
+ if(iuser->layer<tot-1)
+ iuser->layer++;
+ BKE_image_multilayer_index(rr, iuser);
+}
+static void image_multi_declay_cb(void *rr_v, void *iuser_v)
+{
+ ImageUser *iuser= iuser_v;
+ if(iuser->layer>0)
+ iuser->layer--;
+ BKE_image_multilayer_index(rr_v, iuser);
+}
+static void image_multi_incpass_cb(void *rr_v, void *iuser_v)
+{
+ RenderResult *rr= rr_v;
+ ImageUser *iuser= iuser_v;
+ RenderLayer *rl= BLI_findlink(&rr->layers, iuser->layer);
+ if(rl) {
+ int tot= BLI_countlist(&rl->passes) + (rl->rectf?1:0); /* builtin render result has no combined pass in list */
+ if(iuser->pass<tot-1) {
+ iuser->pass++;
+ BKE_image_multilayer_index(rr, iuser);
+ }
+ }
+}
+static void image_multi_decpass_cb(void *rr_v, void *iuser_v)
+{
+ ImageUser *iuser= iuser_v;
+ if(iuser->pass>0) {
+ iuser->pass--;
+ BKE_image_multilayer_index(rr_v, iuser);
+ }
+}
+
+static void image_pack_cb(void *ima_v, void *iuser_v)
+{
+ if(ima_v) {
+ Image *ima= ima_v;
+ if(ima->source!=IMA_SRC_SEQUENCE && ima->source!=IMA_SRC_MOVIE) {
+ if (ima->packedfile) {
+ if (G.fileflags & G_AUTOPACK) {
+ if (okee("Disable AutoPack ?")) {
+ G.fileflags &= ~G_AUTOPACK;
+ }
+ }
+
+ if ((G.fileflags & G_AUTOPACK) == 0) {
+ unpackImage(ima, PF_ASK);
+ BIF_undo_push("Unpack image");
+ }
+ }
+ else {
+ ImBuf *ibuf= BKE_image_get_ibuf(ima, iuser_v);
+ if (ibuf && (ibuf->userflags & IB_BITMAPDIRTY)) {
+ error("Can't pack painted image. Save image or use Repack as PNG.");
+ } else {
+ ima->packedfile = newPackedFile(ima->name);
+ BIF_undo_push("Pack image");
+ }
+ }
+ }
+ }
+}
+
+static void image_load_cb(void *ima_pp_v, void *iuser_v)
+{
+ if(ima_pp_v) {
+ Image *ima= *((Image **)ima_pp_v);
+ ImBuf *ibuf= BKE_image_get_ibuf(ima, iuser_v);
+ char str[FILE_MAX];
+
+ /* name in ima has been changed by button! */
+ BLI_strncpy(str, ima->name, FILE_MAX);
+ if(ibuf) BLI_strncpy(ima->name, ibuf->name, FILE_MAX);
+
+ load_image_cb(str, ima_pp_v, iuser_v);
+ }
+}
+
+static void image_freecache_cb(void *ima_v, void *unused)
+{
+ BKE_image_free_anim_ibufs(ima_v, G.scene->r.cfra);
+ allqueue(REDRAWIMAGE, 0);
+}
+
+static void image_generated_change_cb(void *ima_v, void *iuser_v)
+{
+ BKE_image_signal(ima_v, iuser_v, IMA_SIGNAL_FREE);
+}
+
+static void image_user_change(void *iuser_v, void *unused)
+{
+ BKE_image_user_calc_imanr(iuser_v, G.scene->r.cfra, 0);
+}
+
+void uiblock_layer_pass_buttons(uiBlock *block, RenderResult *rr, ImageUser *iuser, int event, int x, int y, int w)
+{
+ uiBut *but;
+ RenderLayer *rl= NULL;
+ int wmenu1, wmenu2;
+ char *strp;
+
+ /* layer menu is 1/3 larger than pass */
+ wmenu1= (3*w)/5;
+ wmenu2= (2*w)/5;
+
+ /* menu buts */
+ strp= layer_menu(rr, &iuser->layer);
+ but= uiDefButS(block, MENU, event, strp, x, y, wmenu1, 20, &iuser->layer, 0,0,0,0, "Select Layer");
+ uiButSetFunc(but, image_multi_cb, rr, iuser);
+ MEM_freeN(strp);
+
+ rl= BLI_findlink(&rr->layers, iuser->layer - (rr->rectf?1:0)); /* fake compo layer, return NULL is meant to be */
+ strp= pass_menu(rl, &iuser->pass);
+ but= uiDefButS(block, MENU, event, strp, x+wmenu1, y, wmenu2, 20, &iuser->pass, 0,0,0,0, "Select Pass");
+ uiButSetFunc(but, image_multi_cb, rr, iuser);
+ MEM_freeN(strp);
+}
+
+static void uiblock_layer_pass_arrow_buttons(uiBlock *block, RenderResult *rr, ImageUser *iuser, int imagechanged)
+{
+ uiBut *but;
+
+ if(rr==NULL || iuser==NULL)
+ return;
+ if(rr->layers.first==NULL) {
+ uiDefBut(block, LABEL, 0, "No Layers in Render Result,", 10, 107, 300, 20, NULL, 1, 0, 0, 0, "");
+ return;
+ }
+
+ uiBlockBeginAlign(block);
+
+ /* decrease, increase arrows */
+ but= uiDefIconBut(block, BUT, imagechanged, ICON_TRIA_LEFT, 10,107,17,20, NULL, 0, 0, 0, 0, "Previous Layer");
+ uiButSetFunc(but, image_multi_declay_cb, rr, iuser);
+ but= uiDefIconBut(block, BUT, imagechanged, ICON_TRIA_RIGHT, 27,107,18,20, NULL, 0, 0, 0, 0, "Next Layer");
+ uiButSetFunc(but, image_multi_inclay_cb, rr, iuser);
+
+ uiblock_layer_pass_buttons(block, rr, iuser, imagechanged, 45, 107, 230);
+
+ /* decrease, increase arrows */
+ but= uiDefIconBut(block, BUT, imagechanged, ICON_TRIA_LEFT, 275,107,17,20, NULL, 0, 0, 0, 0, "Previous Pass");
+ uiButSetFunc(but, image_multi_decpass_cb, rr, iuser);
+ but= uiDefIconBut(block, BUT, imagechanged, ICON_TRIA_RIGHT, 292,107,18,20, NULL, 0, 0, 0, 0, "Next Pass");
+ uiButSetFunc(but, image_multi_incpass_cb, rr, iuser);
+
+ uiBlockEndAlign(block);
+
+}
+
+/* The general Image panel with the loadsa callbacks! */
+void uiblock_image_panel(uiBlock *block, Image **ima_pp, ImageUser *iuser,
+ short redraw, short imagechanged)
+{
+ Image *ima= *ima_pp;
+ uiBut *but;
+ char str[128], *strp;
+
+ /* different stuff when we show viewer */
+ if(ima && ima->source==IMA_SRC_VIEWER) {
+ ImBuf *ibuf= BKE_image_get_ibuf(ima, iuser);
+
+ image_info(ima, ibuf, str);
+ uiDefBut(block, LABEL, 0, ima->id.name+2, 10, 180, 300, 20, NULL, 1, 0, 0, 0, "");
+ uiDefBut(block, LABEL, 0, str, 10, 160, 300, 20, NULL, 1, 0, 0, 0, "");
+
+ if(ima->type==IMA_TYPE_COMPOSITE) {
+ iuser= ntree_get_active_iuser(G.scene->nodetree);
+ if(iuser) {
+ uiBlockBeginAlign(block);
+ uiDefIconTextBut(block, BUT, B_SIMA_RECORD, ICON_REC, "Record", 10,120,100,20, 0, 0, 0, 0, 0, "");
+ uiDefIconTextBut(block, BUT, B_SIMA_PLAY, ICON_PLAY, "Play", 110,120,100,20, 0, 0, 0, 0, 0, "");
+ but= uiDefBut(block, BUT, B_NOP, "Free Cache", 210,120,100,20, 0, 0, 0, 0, 0, "");
+ uiButSetFunc(but, image_freecache_cb, ima, NULL);
+
+ if(iuser->frames)
+ sprintf(str, "(%d) Frames:", iuser->framenr);
+ else strcpy(str, "Frames:");
+ uiBlockBeginAlign(block);
+ uiDefButI(block, NUM, imagechanged, str, 10, 90,150, 20, &iuser->frames, 0.0, MAXFRAMEF, 0, 0, "Sets the number of images of a movie to use");
+ uiDefButI(block, NUM, imagechanged, "StartFr:", 160,90,150,20, &iuser->sfra, 1.0, MAXFRAMEF, 0, 0, "Sets the global starting frame of the movie");
+ }
+ }
+ else if(ima->type==IMA_TYPE_R_RESULT) {
+ /* browse layer/passes */
+ uiblock_layer_pass_arrow_buttons(block, RE_GetResult(RE_GetRender(G.scene->id.name)), iuser, imagechanged);
+ }
+ return;
+ }
+
+ /* the main ima source types */
+ if(ima) {
+ uiSetButLock(ima->id.lib!=NULL, ERROR_LIBDATA_MESSAGE);
+ uiBlockBeginAlign(block);
+ uiBlockSetFunc(block, image_src_change_cb, ima, iuser);
+ uiDefButS(block, ROW, imagechanged, "Still", 10, 180, 60, 20, &ima->source, 0.0, IMA_SRC_FILE, 0, 0, "Single Image file");
+ uiDefButS(block, ROW, imagechanged, "Movie", 70, 180, 60, 20, &ima->source, 0.0, IMA_SRC_MOVIE, 0, 0, "Movie file");
+ uiDefButS(block, ROW, imagechanged, "Sequence", 130, 180, 90, 20, &ima->source, 0.0, IMA_SRC_SEQUENCE, 0, 0, "Multiple Image files, as a sequence");
+ uiDefButS(block, ROW, imagechanged, "Generated", 220, 180, 90, 20, &ima->source, 0.0, IMA_SRC_GENERATED, 0, 0, "Generated Image");
+ uiBlockSetFunc(block, NULL, NULL, NULL);
+ }
+ else
+ uiDefBut(block, LABEL, 0, " ", 10, 180, 300, 20, 0, 0, 0, 0, 0, ""); /* for align in panel */
+
+ /* Browse */
+ IMAnames_to_pupstring(&strp, NULL, NULL, &(G.main->image), NULL, &iuser->menunr);
+
+ uiBlockBeginAlign(block);
+ but= uiDefButS(block, MENU, imagechanged, strp, 10,155,23,20, &iuser->menunr, 0, 0, 0, 0, "Selects an existing Image or Movie");
+ uiButSetFunc(but, image_browse_cb, ima_pp, iuser);
+
+ MEM_freeN(strp);
+
+ /* name + options, or only load */
+ if(ima) {
+ int drawpack= (ima->source!=IMA_SRC_SEQUENCE && ima->source!=IMA_SRC_MOVIE && ima->ok);
+
+ but= uiDefBut(block, TEX, B_IDNAME, "IM:", 33, 155, 177, 20, ima->id.name+2, 0.0, 21.0, 0, 0, "Current Image Datablock name.");
+ uiButSetFunc(but, test_idbutton_cb, ima->id.name, NULL);
+ but= uiDefBut(block, BUT, imagechanged, "Reload", 210, 155, 60, 20, NULL, 0, 0, 0, 0, "Reloads Image or Movie");
+ uiButSetFunc(but, image_reload_cb, ima, iuser);
+
+ but= uiDefIconBut(block, BUT, imagechanged, ICON_X, 270,155,20,20, 0, 0, 0, 0, 0, "Unlink Image block");
+ uiButSetFunc(but, image_unlink_cb, ima_pp, NULL);
+ sprintf(str, "%d", ima->id.us);
+ uiDefBut(block, BUT, B_NOP, str, 290,155,20,20, 0, 0, 0, 0, 0, "Only displays number of users of Image block");
+
+ but= uiDefIconBut(block, BUT, imagechanged, ICON_FILESEL, 10, 135, 23, 20, 0, 0, 0, 0, 0, "Open Fileselect to load new Image");
+ uiButSetFunc(but, image_load_fs_cb, ima_pp, iuser);
+ but= uiDefBut(block, TEX, imagechanged, "", 33,135,257+(drawpack?0:20),20, ima->name, 0.0, 239.0, 0, 0, "Image/Movie file name, change to load new");
+ uiButSetFunc(but, image_load_cb, ima_pp, iuser);
+
+ if(drawpack) {
+ if (ima->packedfile) packdummy = 1;
+ else packdummy = 0;
+ but= uiDefIconButBitI(block, TOG, 1, redraw, ICON_PACKAGE, 290,135,20,20, &packdummy, 0, 0, 0, 0, "Toggles Packed status of this Image");
+ uiButSetFunc(but, image_pack_cb, ima, iuser);
+ }
+
+ }
+ else {
+ but= uiDefBut(block, BUT, imagechanged, "Load", 33, 155, 100,20, NULL, 0, 0, 0, 0, "Load new Image of Movie");
+ uiButSetFunc(but, image_load_fs_cb, ima_pp, iuser);
+ }
+ uiBlockEndAlign(block);
+
+ if(ima) {
+ ImBuf *ibuf= BKE_image_get_ibuf(ima, iuser);
+
+ /* check for re-render, only buttons */
+ if(imagechanged==B_IMAGECHANGED) {
+ if(iuser->flag & IMA_ANIM_REFRESHED) {
+ iuser->flag &= ~IMA_ANIM_REFRESHED;
+ BIF_preview_changed(ID_TE);
+ }
+ }
+
+ /* multilayer? */
+ if(ima->type==IMA_TYPE_MULTILAYER && ima->rr) {
+ uiblock_layer_pass_arrow_buttons(block, ima->rr, iuser, imagechanged);
+ }
+ else {
+ image_info(ima, ibuf, str);
+ uiDefBut(block, LABEL, 0, str, 10, 112, 300, 20, NULL, 1, 0, 0, 0, "");
+ }
+
+ /* exception, let's do because we only use this panel 3 times in blender... but not real good code! */
+ if( (FACESEL_PAINT_TEST) && G.sima && &G.sima->iuser==iuser)
+ return;
+ /* left side default per-image options, right half the additional options */
+
+ /* fields */
+ uiBlockBeginAlign(block);
+ but= uiDefButBitS(block, TOG, IMA_FIELDS, imagechanged, "Fields", 10, 90, 100, 20, &ima->flag, 0, 0, 0, 0, "Click to enable use of fields in Image");
+ uiButSetFunc(but, image_field_test, ima, iuser);
+ uiDefButBitS(block, TOG, IMA_STD_FIELD, B_NOP, "Odd", 10, 70, 100, 20, &ima->flag, 0, 0, 0, 0, "Standard Field Toggle");
+ uiBlockEndAlign(block);
+
+ uiDefButBitS(block, TOG, IMA_ANTIALI, B_NOP, "Anti", 10, 35, 100, 20, &ima->flag, 0, 0, 0, 0, "Toggles Image anti-aliasing, only works with solid colors");
+
+ if( ELEM(ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) {
+ sprintf(str, "(%d) Frames:", iuser->framenr);
+
+ uiBlockBeginAlign(block);
+ uiBlockSetFunc(block, image_user_change, iuser, NULL);
+ uiDefButBitS(block, TOG, IMA_ANIM_ALWAYS, B_NOP, "Auto Refresh", 120, 90, 190, 20, &iuser->flag, 0, 0, 0, 0, "Always refresh Image on frame changes");
+
+ if(ima->anim) {
+ uiDefButI(block, NUM, imagechanged, str, 120, 70,170, 20, &iuser->frames, 0.0, MAXFRAMEF, 0, 0, "Sets the number of images of a movie to use");
+ but= uiDefBut(block, BUT, redraw, "<", 290, 70, 20, 20, 0, 0, 0, 0, 0, "Copies number of frames in movie file to Frames: button");
+ uiButSetFunc(but, set_frames_cb, ima, iuser);
+ }
+ else
+ uiDefButI(block, NUM, imagechanged, str, 120, 70,190, 20, &iuser->frames, 0.0, MAXFRAMEF, 0, 0, "Sets the number of images of a movie to use");
+
+ uiDefButI(block, NUM, imagechanged, "Offs:", 120,50,100,20, &iuser->offset, -MAXFRAMEF, MAXFRAMEF, 0, 0, "Offsets the number of the frame to use in the animation");
+ uiDefButS(block, NUM, imagechanged, "Fie/Ima:", 220,50,90,20, &iuser->fie_ima, 1.0, 200.0, 0, 0, "The number of fields per rendered frame (2 fields is 1 image)");
+
+ uiDefButI(block, NUM, imagechanged, "StartFr:", 120,30,100,20, &iuser->sfra, 1.0, MAXFRAMEF, 0, 0, "Sets the global starting frame of the movie");
+ uiDefButS(block, TOG, imagechanged, "Cyclic", 220,30,90,20, &iuser->cycl, 0.0, 1.0, 0, 0, "Cycle the images in the movie");
+
+ uiBlockSetFunc(block, NULL, iuser, NULL);
+ }
+ else if(ima->source==IMA_SRC_GENERATED) {
+
+ uiBlockBeginAlign(block);
+ uiBlockSetFunc(block, image_generated_change_cb, ima, iuser);
+ uiDefButS(block, NUM, imagechanged, "SizeX:", 120,90,100,20, &ima->gen_x, 1.0, 5000.0, 0, 0, "Image size x");
+ uiDefButS(block, NUM, imagechanged, "SizeY:", 220,90,90,20, &ima->gen_y, 1.0, 5000.0, 0, 0, "Image size y");
+ uiDefButS(block, TOG, imagechanged, "UV Test grid",120,70,190,20, &ima->gen_type, 0.0, 1.0, 0, 0, "");
+ uiBlockSetFunc(block, NULL, NULL, NULL);
+ }
+ }
+ uiBlockEndAlign(block);
+}
+
+static void texture_panel_image(Image **ima, ImageUser *iuser)
+{
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "texture_panel_image", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Image", "Texture", 960, 0, 318, 204)==0) return;
+
+ uiblock_image_panel(block, ima, iuser, B_REDR, B_IMAGECHANGED);
+}
+
+static void texture_panel_image_map(Tex *tex)
+{
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "texture_panel_image_map", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Map Image", "Texture", 640, 0, 318, 204)==0) return;
+ uiSetButLock(tex->id.lib!=0, ERROR_LIBDATA_MESSAGE);
+
+ /* types */
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, TEX_MIPMAP, B_IMAGECHANGED, "MipMap", 10, 180, 75, 20, &tex->imaflag, 0, 0, 0, 0, "Generates and uses mipmaps");
+ uiDefButBitS(block, TOG, TEX_GAUSS_MIP, 0, "Gauss", 85, 180, 75, 20, &tex->imaflag, 0, 0, 0, 0, "Enable Gauss filter to sample down mipmaps");
+ uiDefButBitS(block, TOG, TEX_INTERPOL, 0, "Interpol", 160, 180, 75, 20, &tex->imaflag, 0, 0, 0, 0, "Interpolates pixels using Area filter");
+ uiDefButBitS(block, TOG, TEX_IMAROT, B_TEXPRV, "Rot90", 235, 180, 75, 20, &tex->imaflag, 0, 0, 0, 0, "Actually flips X and Y for rendering, rotates and mirrors");
+
+ uiDefButBitS(block, TOG, TEX_USEALPHA, B_TEXPRV, "UseAlpha", 10, 160, 100, 20, &tex->imaflag, 0, 0, 0, 0, "Click to use Image's alpha channel");
+ uiDefButBitS(block, TOG, TEX_CALCALPHA, B_TEXPRV, "CalcAlpha", 110, 160, 100, 20, &tex->imaflag, 0, 0, 0, 0, "Click to calculate an alpha channel based on Image RGB values");
+ uiDefButBitS(block, TOG, TEX_NEGALPHA, B_TEXPRV, "NegAlpha", 210, 160, 100, 20, &tex->flag, 0, 0, 0, 0, "Click to invert the alpha values");
+ uiBlockEndAlign(block);
+
+ uiDefButF(block, NUM, B_TEXPRV, "Filter :", 10,120,150,20, &tex->filtersize, 0.1, 25.0, 10, 3, "Sets the filter size used by mipmap and interpol");
+
+ uiDefButBitS(block, TOG, TEX_NORMALMAP, B_NOP, "Normal Map", 160,120,150,20, &tex->imaflag,
+ 0, 0, 0, 0, "Use image RGB values for normal mapping");
+
+ /* crop extend clip */
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, ROW, B_TEXREDR_PRV, "Extend", 10,90,63,19, &tex->extend, 4.0, 1.0, 0, 0, "Extends the color of the edge pixels");
+ uiDefButS(block, ROW, B_TEXREDR_PRV, "Clip", 73,90,48,19, &tex->extend, 4.0, 2.0, 0, 0, "Sets alpha 0.0 outside Image edges");
+ uiDefButS(block, ROW, B_TEXREDR_PRV, "ClipCube", 121,90,63,19, &tex->extend, 4.0, 4.0, 0, 0, "Sets alpha to 0.0 outside cubeshaped area around Image");
+ uiDefButS(block, ROW, B_TEXREDR_PRV, "Repeat", 184,90,63,19, &tex->extend, 4.0, 3.0, 0, 0, "Causes Image to repeat horizontally and vertically");
+ uiDefButS(block, ROW, B_TEXREDR_PRV, "Checker", 247,90,63,19, &tex->extend, 4.0, 5.0, 0, 0, "Causes Image to repeat in checker pattern");
+
+ if(tex->extend==TEX_REPEAT) {
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, TEX_REPEAT_XMIR, B_TEXPRV, "Mirr", 10,60,30,19, &tex->flag, 0.0, 0.0, 0, 0, "Mirrors X direction repeat");
+ uiDefButS(block, NUM, B_TEXPRV, "Xrepeat:", 40,60,120,19, &tex->xrepeat, 1.0, 512.0, 0, 0, "Sets a repetition multiplier in the X direction");
+ uiDefButBitS(block, TOG, TEX_REPEAT_YMIR, B_TEXPRV, "Mirr", 160,60,30,19, &tex->flag, 0.0, 0.0, 0, 0, "Mirrors Y direction repeat");
+ uiDefButS(block, NUM, B_TEXPRV, "Yrepeat:", 190,60,120,19, &tex->yrepeat, 1.0, 512.0, 0, 0, "Sets a repetition multiplier in the Y direction");
+ }
+ else if(tex->extend==TEX_CHECKER) {
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, TEX_CHECKER_ODD, B_TEXPRV, "Odd", 10,60,100,19, &tex->flag, 0.0, 0.0, 0, 0, "Sets odd checker tiles");
+ uiDefButBitS(block, TOG, TEX_CHECKER_EVEN, B_TEXPRV, "Even", 110,60,100,19, &tex->flag, 0.0, 0.0, 0, 0, "Sets even checker tiles");
+ uiDefButF(block, NUM, B_TEXPRV, "Mortar:", 210,60,100,19, &tex->checkerdist, 0.0, 0.99, 0, 0, "Set checkers distance (like mortar)");
+ }
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_TEXPRV, "MinX ", 10,30,150,19, &tex->cropxmin, -10.0, 10.0, 10, 0, "Sets minimum X value to crop Image");
+ uiDefButF(block, NUM, B_TEXPRV, "MinY ", 10,10,150,19, &tex->cropymin, -10.0, 10.0, 10, 0, "Sets minimum Y value to crop Image");
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_TEXPRV, "MaxX ", 160,30,150,19, &tex->cropxmax, -10.0, 10.0, 10, 0, "Sets maximum X value to crop Image");
+ uiDefButF(block, NUM, B_TEXPRV, "MaxY ", 160,10,150,19, &tex->cropymax, -10.0, 10.0, 10, 0, "Sets maximum Y value to crop Image");
+ uiBlockEndAlign(block);
+
+}
+
+/***************************************/
+
+static void texture_panel_envmap(Tex *tex)
+{
+ uiBlock *block;
+ uiBut *but;
+ EnvMap *env;
+ ID *id;
+ short a, xco, yco, dx, dy;
+ char *strp, str[32];
+
+ block= uiNewBlock(&curarea->uiblocks, "texture_panel_envmap", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Envmap", "Texture", 640, 0, 318, 204)==0) return;
+ uiSetButLock(tex->id.lib!=0, ERROR_LIBDATA_MESSAGE);
+
+ if(tex->env==NULL) {
+ tex->env= BKE_add_envmap();
+ tex->env->object= OBACT;
+ }
+ if(tex->env) {
+ env= tex->env;
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, ROW, B_REDR, "Static", 10, 180, 100, 19, &env->stype, 2.0, (float)ENV_STATIC, 0, 0, "Calculates environment map only once");
+ uiDefButS(block, ROW, B_REDR, "Anim", 110, 180, 100, 19, &env->stype, 2.0, (float)ENV_ANIM, 0, 0, "Calculates environment map at each rendering");
+ uiDefButS(block, ROW, B_ENV_FREE, "Load", 210, 180, 100, 19, &env->stype, 2.0, (float)ENV_LOAD, 0, 0, "Loads saved environment map from disk");
+ uiBlockEndAlign(block);
+
+ if(env->stype==ENV_LOAD) {
+ /* file input */
+ id= (ID *)tex->ima;
+ IMAnames_to_pupstring(&strp, NULL, NULL, &(G.main->image), id, &(G.buts->menunr));
+ if(strp[0]) {
+ uiBlockBeginAlign(block);
+
+ but= uiDefButS(block, MENU, B_TEXPRV, strp, 10,145,23,20, &tex->iuser.menunr, 0, 0, 0, 0, "Selects an existing environment map");
+ uiButSetFunc(but, image_browse_cb, &tex->ima, &tex->iuser);
+
+ if(tex->ima) {
+ but= uiDefBut(block, TEX, B_NAMEIMA, "", 35,145,255,20, tex->ima->name, 0.0, 79.0, 0, 0, "Displays environment map name: click to change");
+ uiButSetFunc(but, image_load_cb, &tex->ima, &tex->iuser);
+
+ sprintf(str, "%d", tex->ima->id.us);
+ uiDefBut(block, BUT, 0, str, 290,145,20,20, 0, 0, 0, 0, 0, "Displays number of users of environment map: click to make single user");
+ uiBlockEndAlign(block);
+
+ but= uiDefBut(block, BUT, B_IMAGECHANGED, "Reload", 230,125,80,20, 0, 0, 0, 0, 0, "Reloads saved environment map");
+ uiButSetFunc(but, image_reload_cb, tex->ima, NULL);
+
+ if (tex->ima->packedfile) packdummy = 1;
+ else packdummy = 0;
+ but= uiDefIconButBitI(block, TOG, 1, B_REDR, ICON_PACKAGE, 205,125,24,20, &packdummy, 0, 0, 0, 0, "Toggles Packed status of this environment map");
+ uiButSetFunc(but, image_pack_cb, tex->ima, &tex->iuser);
+ }
+ else uiBlockEndAlign(block);
+ }
+ MEM_freeN(strp);
+
+ but= uiDefBut(block, BUT, B_IMAGECHANGED, "Load Image", 10,125,150,20, 0, 0, 0, 0, 0, "Loads saved environment map - file select");
+ uiButSetFunc(but, image_load_fs_cb, &tex->ima, &tex->iuser);
+ }
+ else {
+ uiBlockBeginAlign(block);
+ uiDefBut(block, BUT, B_ENV_FREE, "Free Data", 10,145,100,20, 0, 0, 0, 0, 0, "Releases all images associated with this environment map");
+ uiDefBut(block, BUT, B_ENV_SAVE, "Save EnvMap", 110,145,100,20, 0, 0, 0, 0, 0, "Saves current environment map");
+ uiDefBut(block, BUT, B_ENV_FREE_ALL, "Free all EnvMaps", 210,145,100,20, 0, 0, 0, 0, 0, "Frees all rendered environment maps for all materials");
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, ROW, B_NOP, "Cube", 10,120,100,20, &env->type, 3.0f, (float)ENV_CUBE, 0, 0, "Use environment map with six cube sides");
+ uiDefButS(block, ROW, B_NOP, "Plane", 110,120,100,20, &env->type, 3.0f, (float)ENV_PLANE, 0, 0, "Only one side is rendered, with Z axis pointing in direction of image");
+ uiDefButF(block, NUM, B_NOP, "Zoom: ", 210,120,100,20, &env->viewscale, 0.5f, 5.0f, 100, 2, "Zoom factor for planar environment map");
+ uiBlockEndAlign(block);
+ }
+
+ uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_ENV_OB, "Ob:", 10,90,150,20, &(env->object), "Displays object to use as viewpoint for environment map: click to change");
+ if(env->stype!=ENV_LOAD)
+ uiDefButS(block, NUM, B_ENV_FREE, "CubeRes", 160,90,150,20, &env->cuberes, 50, 4096.0, 0, 0, "Sets the pixel resolution of the rendered environment map");
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_TEXPRV, "Filter :", 10,65,150,20, &tex->filtersize, 0.1, 25.0, 0, 3, "Adjusts sharpness or blurriness of the reflection"),
+ uiDefButS(block, NUM, B_ENV_FREE, "Depth:", 160,65,150,20, &env->depth, 0, 5.0, 0, 0, "Sets the number of times a map will be rendered recursively mirror effects"),
+ uiDefButF(block, NUM, REDRAWVIEW3D, "ClipSta", 10,40,150,20, &env->clipsta, 0.01, 50.0, 100, 0, "Sets start value for clipping: objects nearer than this are not visible to map");
+ uiDefButF(block, NUM, B_NOP, "ClipEnd", 160,40,150,20, &env->clipend, 0.1, 20000.0, 1000, 0, "Sets end value for clipping beyond which objects are not visible to map");
+ uiBlockEndAlign(block);
+
+ uiDefBut(block, LABEL, 0, "Don't render layer:", 10,10,140,22, 0, 0.0, 0.0, 0, 0, "");
+ xco= 160;
+ yco= 10;
+ dx= 28;
+ dy= 26;
+
+ uiBlockBeginAlign(block);
+ for(a=0; a<5; a++)
+ uiDefButBitI(block, TOG, 1<<a, 0, "", (xco+a*(dx/2)), (yco+dy/2), (dx/2), (1+dy/2), (int *)&env->notlay, 0, 0, 0, 0, "Toggles layer visibility to environment map");
+ for(a=0; a<5; a++)
+ uiDefButBitI(block, TOG, 1<<(a+10), 0, "",(xco+a*(dx/2)), yco, (dx/2), (dy/2), (int *)&env->notlay, 0, 0, 0, 0, "Toggles layer visibility to environment map");
+
+ uiBlockBeginAlign(block);
+ xco+= 5;
+ for(a=5; a<10; a++)
+ uiDefButBitI(block, TOG, 1<<a, 0, "", (xco+a*(dx/2)), (yco+dy/2), (dx/2), (1+dy/2), (int *)&env->notlay, 0, 0, 0, 0, "Toggles layer visibility to environment map");
+ for(a=5; a<10; a++)
+ uiDefButBitI(block, TOG, 1<<(a+10), 0, "",(xco+a*(dx/2)), yco, (dx/2), (dy/2), (int *)&env->notlay, 0, 0, 0, 0, "Toggles layer visibility to environment map");
+
+ }
+}
+
+static void colorband_pos_cb(void *coba_v, void *unused_v)
+{
+ ColorBand *coba= coba_v;
+ int a;
+
+ if(coba->tot<2) return;
+
+ for(a=0; a<coba->tot; a++) coba->data[a].cur= a;
+ qsort(coba->data, coba->tot, sizeof(CBData), vergcband);
+ for(a=0; a<coba->tot; a++) {
+ if(coba->data[a].cur==coba->cur) {
+ if(coba->cur!=a) addqueue(curarea->win, REDRAW, 0); /* button cur */
+ coba->cur= a;
+ break;
+ }
+ }
+}
+
+static void colorband_add_cb(void *coba_v, void *unused_v)
+{
+ ColorBand *coba= coba_v;
+
+ if(coba->tot < MAXCOLORBAND-1) coba->tot++;
+ coba->cur= coba->tot-1;
+
+ colorband_pos_cb(coba, NULL);
+ BIF_undo_push("Add colorband");
+
+}
+
+static void colorband_del_cb(void *coba_v, void *unused_v)
+{
+ ColorBand *coba= coba_v;
+ int a;
+
+ if(coba->tot<2) return;
+
+ for(a=coba->cur; a<coba->tot; a++) {
+ coba->data[a]= coba->data[a+1];
+ }
+ if(coba->cur) coba->cur--;
+ coba->tot--;
+
+ BIF_undo_push("Delete colorband");
+ BIF_preview_changed(ID_TE);
+}
+
+
+/* offset aligns from bottom, standard width 300, height 115 */
+static void draw_colorband_buts(uiBlock *block, ColorBand *coba, int xoffs, int yoffs, int redraw)
+{
+ CBData *cbd;
+ uiBut *bt;
+
+ if(coba==NULL) return;
+
+ bt= uiDefBut(block, BUT, redraw, "Add", 80+xoffs,95+yoffs,37,20, 0, 0, 0, 0, 0, "Adds a new color position to the colorband");
+ uiButSetFunc(bt, colorband_add_cb, coba, NULL);
+ uiDefButS(block, NUM, redraw, "Cur:", 117+xoffs,95+yoffs,81,20, &coba->cur, 0.0, (float)(coba->tot-1), 0, 0, "Displays the active color from the colorband");
+ bt= uiDefBut(block, BUT, redraw, "Del", 199+xoffs,95+yoffs,37,20, 0, 0, 0, 0, 0, "Deletes the active position");
+ uiButSetFunc(bt, colorband_del_cb, coba, NULL);
+ uiDefButS(block, ROW, redraw, "E", 236+xoffs,95+yoffs,16,20, &coba->ipotype, 5.0, 1.0, 0, 0, "Sets interpolation type 'Ease' (quadratic) ");
+ uiDefButS(block, ROW, redraw, "C", 252+xoffs,95+yoffs,16,20, &coba->ipotype, 5.0, 3.0, 0, 0, "Sets interpolation type Cardinal");
+ uiDefButS(block, ROW, redraw, "L", 268+xoffs,95+yoffs,16,20, &coba->ipotype, 5.0, 0.0, 0, 0, "Sets interpolation type Linear");
+ uiDefButS(block, ROW, redraw, "S", 284+xoffs,95+yoffs,16,20, &coba->ipotype, 5.0, 2.0, 0, 0, "Sets interpolation type B-Spline");
+
+ uiDefBut(block, BUT_COLORBAND, redraw, "", xoffs,65+yoffs,300,30, coba, 0, 0, 0, 0, "");
+
+ cbd= coba->data + coba->cur;
+
+ uiBlockBeginAlign(block);
+ bt= uiDefButF(block, NUM, redraw, "Pos", xoffs,40+yoffs,110,20, &cbd->pos, 0.0, 1.0, 10, 0, "Sets the position of the active color");
+ uiButSetFunc(bt, colorband_pos_cb, coba, NULL);
+ uiDefButF(block, COL, redraw, "", xoffs,20+yoffs,110,20, &(cbd->r), 0, 0, 0, B_BANDCOL, "");
+ uiDefButF(block, NUMSLI, redraw, "A ", xoffs,yoffs,110,20, &cbd->a, 0.0, 1.0, 10, 0, "Sets the alpha value for this position");
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUMSLI, redraw, "R ", 115+xoffs,40+yoffs,185,20, &cbd->r, 0.0, 1.0, B_BANDCOL, 0, "Sets the red value for the active color");
+ uiDefButF(block, NUMSLI, redraw, "G ", 115+xoffs,20+yoffs,185,20, &cbd->g, 0.0, 1.0, B_BANDCOL, 0, "Sets the green value for the active color");
+ uiDefButF(block, NUMSLI, redraw, "B ", 115+xoffs,yoffs,185,20, &cbd->b, 0.0, 1.0, B_BANDCOL, 0, "Sets the blue value for the active color");
+ uiBlockEndAlign(block);
+}
+
+void draw_colorband_buts_small(uiBlock *block, ColorBand *coba, rctf *butr, int event)
+{
+ CBData *cbd;
+ uiBut *bt;
+ float unit= (butr->xmax-butr->xmin)/14.0f;
+ float xs= butr->xmin;
+
+ cbd= coba->data + coba->cur;
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, COL, event, "", xs,butr->ymin+20.0f,2.0f*unit,20, &(cbd->r), 0, 0, 0, B_BANDCOL, "");
+ uiDefButF(block, NUM, event, "A:", xs+2.0f*unit,butr->ymin+20.0f,4.0f*unit,20, &(cbd->a), 0.0f, 1.0f, 10, 2, "");
+ bt= uiDefBut(block, BUT, event, "Add", xs+6.0f*unit,butr->ymin+20.0f,2.0f*unit,20, NULL, 0, 0, 0, 0, "Adds a new color position to the colorband");
+ uiButSetFunc(bt, colorband_add_cb, coba, NULL);
+ bt= uiDefBut(block, BUT, event, "Del", xs+8.0f*unit,butr->ymin+20.0f,2.0f*unit,20, NULL, 0, 0, 0, 0, "Deletes the active position");
+ uiButSetFunc(bt, colorband_del_cb, coba, NULL);
+ uiDefButS(block, ROW, event, "E", xs+10.0f*unit,butr->ymin+20.0f,unit,20, &coba->ipotype, 5.0, 1.0, 0, 0, "Sets interpolation type 'Ease' (quadratic) ");
+ uiDefButS(block, ROW, event, "C", xs+11.0f*unit,butr->ymin+20.0f,unit,20, &coba->ipotype, 5.0, 3.0, 0, 0, "Sets interpolation type Cardinal");
+ uiDefButS(block, ROW, event, "L", xs+12.0f*unit,butr->ymin+20.0f,unit,20, &coba->ipotype, 5.0, 0.0, 0, 0, "Sets interpolation type Linear");
+ uiDefButS(block, ROW, event, "S", xs+13.0f*unit,butr->ymin+20.0f,unit,20, &coba->ipotype, 5.0, 2.0, 0, 0, "Sets interpolation type B-Spline");
+
+ uiDefBut(block, BUT_COLORBAND, event, "", xs,butr->ymin,butr->xmax-butr->xmin,20.0f, coba, 0, 0, 0, 0, "");
+ uiBlockEndAlign(block);
+
+}
+
+static void texture_panel_colors(Tex *tex)
+{
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "texture_panel_colors", UI_EMBOSS, UI_HELV, curarea->win);
+ uiNewPanelTabbed("Texture", "Texture");
+ if(uiNewPanel(curarea, block, "Colors", "Texture", 1280, 0, 318, 204)==0) return;
+
+
+ /* COLORBAND */
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, TEX_COLORBAND, B_COLORBAND, "Colorband",10,180,80,20, &tex->flag, 0, 0, 0, 0, "Toggles colorband operations");
+
+ if(tex->flag & TEX_COLORBAND) {
+ draw_colorband_buts(block, tex->coba, 10, 85, B_TEXREDR_PRV);
+ }
+
+ /* RGB-BRICON */
+ if((tex->flag & TEX_COLORBAND)==0) {
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUMSLI, B_TEXPRV, "R ", 60,80,200,20, &tex->rfac, 0.0, 2.0, 0, 0, "Changes the red value of the texture");
+ uiDefButF(block, NUMSLI, B_TEXPRV, "G ", 60,60,200,20, &tex->gfac, 0.0, 2.0, 0, 0, "Changes the green value of the texture");
+ uiDefButF(block, NUMSLI, B_TEXPRV, "B ", 60,40,200,20, &tex->bfac, 0.0, 2.0, 0, 0, "Changes the blue value of the texture");
+ }
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUMSLI, B_TEXPRV, "Bright", 10,10,150,20, &tex->bright, 0.0, 2.0, 0, 0, "Changes the brightness of the color or intensity of a texture");
+ uiDefButF(block, NUMSLI, B_TEXPRV, "Contr", 160,10,150,20, &tex->contrast, 0.01, 5.0, 0, 0, "Changes the contrast of the color or intensity of a texture");
+}
+
+
+static void texture_panel_texture(MTex *mtex, Material *ma, World *wrld, Lamp *la, bNode *node, Brush *br, SculptData *sd)
+{
+ MTex *mt=NULL;
+ uiBlock *block;
+ ID *id=NULL, *idfrom;
+ int a, yco, loos;
+ char str[32];
+
+
+ block= uiNewBlock(&curarea->uiblocks, "texture_panel_texture", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Texture", "Texture", 320, 0, 318, 204)==0) return;
+
+ /* first do the browse but */
+ if(mtex)
+ id= (ID *)mtex->tex;
+ else if(node)
+ id= node->id;
+
+ if(ma) idfrom= &ma->id;
+ else if(wrld) idfrom= &wrld->id;
+ else if(la) idfrom= &la->id;
+ else if(br) idfrom= &br->id;
+ else if(sd) idfrom= NULL; /* Not sure what this does */
+ else idfrom= NULL;
+
+ uiBlockSetCol(block, TH_BUT_SETTING2);
+ if(ma) {
+ std_libbuttons(block, 10, 180, 0, NULL, B_TEXBROWSE, ID_TE, 0, id, idfrom, &(G.buts->texnr), B_TEXALONE, B_TEXLOCAL, B_TEXDELETE, B_AUTOTEXNAME, B_KEEPDATA);
+ }
+ else if(wrld) {
+ std_libbuttons(block, 10, 180, 0, NULL, B_WTEXBROWSE, ID_TE, 0, id, idfrom, &(G.buts->texnr), B_TEXALONE, B_TEXLOCAL, B_TEXDELETE, B_AUTOTEXNAME, B_KEEPDATA);
+ }
+ else if(la) {
+ std_libbuttons(block, 10, 180, 0, NULL, B_LTEXBROWSE, ID_TE, 0, id, idfrom, &(G.buts->texnr), B_TEXALONE, B_TEXLOCAL, B_TEXDELETE, B_AUTOTEXNAME, B_KEEPDATA);
+ }
+ else if(br) {
+ std_libbuttons(block, 10, 180, 0, NULL, B_BTEXBROWSE, ID_TE, 0, id, idfrom, &(G.buts->menunr), B_TEXALONE, B_TEXLOCAL, B_TEXDELETE, B_AUTOTEXNAME, B_KEEPDATA);
+ }
+ else if(sd) {
+ std_libbuttons(block, 10, 180, 0, NULL, B_SCULPT_TEXBROWSE, ID_TE, 0, id, idfrom, &(G.buts->texnr), B_TEXALONE, B_TEXLOCAL, B_TEXDELETE, B_AUTOTEXNAME, B_KEEPDATA);
+ }
+ else if(node) {
+
+ }
+ uiBlockSetCol(block, TH_BUT_NEUTRAL);
+
+ /* From button: removed */
+
+ /* CHANNELS */
+ if(node==NULL) {
+ uiBlockBeginAlign(block);
+ yco= 150;
+ for(a= 0; a<MAX_MTEX; a++) {
+
+ if(ma) mt= ma->mtex[a];
+ else if(wrld) mt= wrld->mtex[a];
+ else if(la) mt= la->mtex[a];
+ else if(br) mt= br->mtex[a];
+ else if(sd) mt= sd->mtex[a];
+
+ if(mt && mt->tex) splitIDname(mt->tex->id.name+2, str, &loos);
+ else strcpy(str, "");
+ str[14]= 0;
+
+ if(ma) {
+ uiDefButC(block, ROW, B_TEXCHANNEL, str, 10,yco,140,19, &(ma->texact), 0.0, (float)a, 0, 0, "Click to select texture channel");
+ yco-= 20;
+ }
+ else if(wrld) {
+ uiDefButS(block, ROW, B_TEXCHANNEL, str, 10,yco,140,19, &(wrld->texact), 0.0, (float)a, 0, 0, "");
+ yco-= 20;
+ }
+ else if(la) {
+ uiDefButS(block, ROW, B_TEXCHANNEL, str, 10,yco,140,19, &(la->texact), 0.0, (float)a, 0, 0, "");
+ yco-= 20;
+ }
+ else if(br) {
+ uiDefButS(block, ROW, B_TEXCHANNEL, str, 10,yco,140,19, &(br->texact), 0.0, (float)a, 0, 0, "");
+ yco-= 20;
+ }
+ else if(sd) {
+ uiDefButS(block, ROW, B_TEXCHANNEL, str, 10,yco,140,19, &(sd->texact), 0.0, (float)a, 0, 0, "");
+ yco-= 20;
+ }
+ }
+ uiBlockEndAlign(block);
+ }
+ uiBlockSetCol(block, TH_AUTO);
+
+ /* TYPES */
+ if(id) {
+ char textypes[512];
+ Tex *tex= (Tex *)id;
+
+ uiSetButLock(tex->id.lib!=0, ERROR_LIBDATA_MESSAGE);
+
+ /* newnoise: all texture types as menu, not enough room for more buttons.
+ * Can widen panel, but looks ugly when other panels overlap it */
+
+ sprintf(textypes, "Texture Type %%t|None %%x%d|Image %%x%d|EnvMap %%x%d|Clouds %%x%d|Marble %%x%d|Stucci %%x%d|Wood %%x%d|Magic %%x%d|Blend %%x%d|Noise %%x%d|Plugin %%x%d|Musgrave %%x%d|Voronoi %%x%d|DistortedNoise %%x%d", 0, TEX_IMAGE, TEX_ENVMAP, TEX_CLOUDS, TEX_MARBLE, TEX_STUCCI, TEX_WOOD, TEX_MAGIC, TEX_BLEND, TEX_NOISE, TEX_PLUGIN, TEX_MUSGRAVE, TEX_VORONOI, TEX_DISTNOISE);
+ uiDefBut(block, LABEL, 0, "Texture Type", 160, 150, 140, 20, 0, 0.0, 0.0, 0, 0, "");
+ uiDefButS(block, MENU, B_TEXTYPE, textypes, 160, 125, 140, 25, &tex->type, 0,0,0,0, "Select texture type");
+
+ }
+ else {
+ // label to avoid centering
+ uiDefBut(block, LABEL, 0, " ", 160, 10, 140, 20, 0, 0, 0, 0, 0, "");
+ }
+}
+
+static void texture_panel_preview(MTex *mtex, int preview)
+{
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "texture_panel_preview", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Preview", "Texture", 0, 0, 318, 204)==0) return;
+
+ if(preview) uiBlockSetDrawExtraFunc(block, BIF_previewdraw);
+
+ // label to force a boundbox for buttons not to be centered
+ uiDefBut(block, LABEL, 0, " ", 20,20,10,10, 0, 0, 0, 0, 0, "");
+
+ uiBlockBeginAlign(block);
+ uiDefButC(block, ROW, B_TEXREDR_PRV, "Mat", 200,175,80,25, &G.buts->texfrom, 3.0, 0.0, 0, 0, "Displays the textures of the active material");
+ uiDefButC(block, ROW, B_TEXREDR_PRV, "World", 200,150,80,25, &G.buts->texfrom, 3.0, 1.0, 0, 0, "Displays the textures of the world block");
+ uiDefButC(block, ROW, B_TEXREDR_PRV, "Lamp", 200,125,80,25, &G.buts->texfrom, 3.0, 2.0, 0, 0, "Displays the textures of the selected lamp");
+ uiDefButC(block, ROW, B_TEXREDR_PRV, "Brush", 200,100,80,25, &G.buts->texfrom, 3.0, 3.0, 0, 0, "Displays the textures of the selected brush");
+ uiBlockEndAlign(block);
+
+ if(mtex && mtex->tex)
+ uiDefButBitS(block, TOG, TEX_PRV_ALPHA, B_TEXREDR_PRV, "Alpha", 200,60,80,20, &mtex->tex->flag, 0, 0, 0, 0, "Show alpha in preview");
+
+ uiDefBut(block, BUT, B_DEFTEXVAR, "Default Vars",200,10,80,20, 0, 0, 0, 0, 0, "Sets all values to defaults");
+
+}
+
+
+
+/* *************************** RADIO ******************************** */
+
+void do_radiobuts(unsigned short event)
+{
+ Radio *rad;
+ int phase;
+
+ phase= rad_phase();
+ rad= G.scene->radio;
+
+ switch(event) {
+ case B_RAD_ADD:
+ add_radio();
+ BIF_undo_push("Add radiosity");
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+ case B_RAD_DELETE:
+ delete_radio();
+ BIF_undo_push("Delete radiosity");
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+ case B_RAD_FREE:
+ freeAllRad();
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+ case B_RAD_COLLECT:
+ rad_collect_meshes();
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+ case B_RAD_INIT:
+ if(phase==RAD_PHASE_PATCHES) {
+ rad_limit_subdivide();
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ break;
+ case B_RAD_SHOOTP:
+ if(phase==RAD_PHASE_PATCHES) {
+ waitcursor(1);
+ rad_subdivshootpatch();
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ waitcursor(0);
+ }
+ break;
+ case B_RAD_SHOOTE:
+ if(phase==RAD_PHASE_PATCHES) {
+ waitcursor(1);
+ rad_subdivshootelem();
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ waitcursor(0);
+ }
+ break;
+ case B_RAD_GO:
+ if(phase==RAD_PHASE_PATCHES) {
+ waitcursor(1);
+ rad_go();
+ waitcursor(0);
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ break;
+ case B_RAD_LIMITS:
+ rad_setlimits();
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSSHADING, 0);
+ break;
+ case B_RAD_FAC:
+ set_radglobal();
+ if(phase & RAD_PHASE_FACES) make_face_tab();
+ else make_node_display(); /* radio solver also uses nodes, different ones :) */
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+ case B_RAD_NODELIM:
+ if(phase & RAD_PHASE_FACES) {
+ set_radglobal();
+ removeEqualNodes(rad->nodelim);
+ make_face_tab();
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSSHADING, 0);
+ }
+ break;
+ case B_RAD_NODEFILT:
+ if(phase & RAD_PHASE_FACES) {
+ set_radglobal();
+ filterNodes();
+ make_face_tab();
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ break;
+ case B_RAD_FACEFILT:
+ if(phase & RAD_PHASE_FACES) {
+ filterFaces();
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ break;
+ case B_RAD_DRAW:
+ set_radglobal();
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+ case B_RAD_ADDMESH:
+ if(phase & RAD_PHASE_FACES) rad_addmesh();
+ BIF_undo_push("Radiosity add mesh");
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+ case B_RAD_REPLACE:
+ if(phase & RAD_PHASE_FACES) rad_replacemesh();
+ BIF_undo_push("Radiosity replace mesh");
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+ }
+
+}
+
+
+static void radio_panel_calculation(Radio *rad, int flag)
+{
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "radio_panel_calculation", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Calculation", "Radio", 640, 0, 318, 204)==0) return;
+ uiAutoBlock(block, 10, 10, 300, 200, UI_BLOCK_ROWS);
+
+ if(flag != RAD_PHASE_PATCHES) uiBlockSetCol(block, TH_BUT_NEUTRAL);
+ uiDefBut(block, BUT, B_RAD_GO, "GO", 0, 0, 10, 15, NULL, 0, 0, 0, 0, "Starts the radiosity simulation");
+
+ uiBlockSetCol(block, TH_AUTO);
+ uiDefButS(block, NUM, B_NOP, "SubSh Patch:", 1, 0, 10, 10, &rad->subshootp, 0.0, 10.0, 0, 0, "Sets the number of times the environment is tested to detect pathes");
+ uiDefButS(block, NUM, B_NOP, "SubSh Element:", 1, 0, 10, 10, &rad->subshoote, 0.0, 10.0, 0, 0, "Sets the number of times the environment is tested to detect elements");
+
+ if(flag != RAD_PHASE_PATCHES) uiBlockSetCol(block, TH_BUT_NEUTRAL);
+ uiDefBut(block, BUT, B_RAD_SHOOTE, "Subdiv Shoot Element", 2, 0, 10, 10, NULL, 0, 0, 0, 0, "For pre-subdivision, Detects high energy changes and subdivide Elements");
+ uiDefBut(block, BUT, B_RAD_SHOOTP, "Subdiv Shoot Patch", 2, 0, 10, 10, NULL, 0, 0, 0, 0, "For pre-subdivision, Detects high energy changes and subdivide Patches");
+
+ uiBlockSetCol(block, TH_AUTO);
+ uiDefButI(block, NUM, B_NOP, "MaxEl:", 3, 0, 10, 10, &rad->maxnode, 1.0, 250000.0, 0, 0, "Sets the maximum allowed number of elements");
+ uiDefButS(block, NUM, B_NOP, "Max Subdiv Shoot:", 3, 0, 10, 10, &rad->maxsublamp, 1.0, 250.0, 0, 0, "Sets the maximum number of initial shoot patches that are evaluated");
+
+ if(flag & RAD_PHASE_FACES);
+ else uiBlockSetCol(block, TH_BUT_NEUTRAL);
+ uiDefBut(block, BUT, B_RAD_FACEFILT, "FaceFilter", 4, 0, 10, 10, NULL, 0, 0, 0, 0, "Forces an extra smoothing");
+ uiDefBut(block, BUT, B_RAD_NODEFILT, "Element Filter", 4, 0, 10, 10, NULL, 0, 0, 0, 0, "Filters elements to remove aliasing artefacts");
+
+ uiDefBut(block, BUT, B_RAD_NODELIM, "RemoveDoubles", 5, 0, 30, 10, NULL, 0.0, 50.0, 0, 0, "Joins elements which differ less than 'Lim'");
+ uiBlockSetCol(block, TH_AUTO);
+ uiDefButS(block, NUM, B_NOP, "Lim:", 5, 0, 10, 10, &rad->nodelim, 0.0, 50.0, 0, 0, "Sets the range for removing doubles");
+
+
+}
+
+static void radio_panel_tool(Radio *rad, int flag)
+{
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "radio_panel_tool", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Radio Tool", "Radio", 320, 0, 318, 204)==0) return;
+ uiAutoBlock(block, 10, 10, 300, 200, UI_BLOCK_ROWS);
+
+ if(flag & RAD_PHASE_PATCHES) uiBlockSetCol(block, TH_BUT_SETTING1);
+ uiDefBut(block, BUT, B_RAD_COLLECT, "Collect Meshes", 0, 0, 10, 15, NULL, 0, 0, 0, 0, "Converts selected visible meshes to patches");
+
+ if(flag & RAD_PHASE_PATCHES)uiBlockSetCol(block, TH_AUTO);
+ else uiBlockSetCol(block, TH_BUT_NEUTRAL);
+ uiDefBut(block, BUT, B_RAD_FREE, "Free Radio Data", 0, 0, 10, 15, NULL, 0, 0, 0, 0, "Releases all memory used by Radiosity");
+
+ if(flag & RAD_PHASE_FACES) uiBlockSetCol(block, TH_AUTO);
+ else uiBlockSetCol(block, TH_BUT_NEUTRAL);
+ uiDefBut(block, BUT, B_RAD_REPLACE, "Replace Meshes", 1, 0, 10, 12, NULL, 0, 0, 0, 0, "Converts meshes to Mesh objects with vertex colors, changing input-meshes");
+ uiDefBut(block, BUT, B_RAD_ADDMESH, "Add new Meshes", 1, 0, 10, 12, NULL, 0, 0, 0, 0, "Converts meshes to Mesh objects with vertex colors, unchanging input-meshes");
+
+ uiBlockSetCol(block, TH_AUTO);
+ uiDefButS(block, ROW, B_RAD_DRAW, "Wire", 2, 0, 10, 10, &rad->drawtype, 0.0, 0.0, 0, 0, "Enables wireframe drawmode");
+ uiDefButS(block, ROW, B_RAD_DRAW, "Solid", 2, 0, 10, 10, &rad->drawtype, 0.0, 1.0, 0, 0, "Enables solid drawmode");
+ uiDefButS(block, ROW, B_RAD_DRAW, "Gour", 2, 0, 10, 10, &rad->drawtype, 0.0, 2.0, 0, 0, "Enables Gourad drawmode");
+ uiDefButBitS(block, TOG, 1, B_RAD_DRAW, "ShowLim", 2, 0, 10, 10, &rad->flag, 0, 0, 0, 0, "Draws patch and element limits");
+ uiDefButBitS(block, TOG, 2, B_RAD_DRAW, "Z", 2, 0, 3, 10, &rad->flag, 0, 0, 0, 0, "Draws limits differently");
+
+ uiDefButS(block, NUM, B_RAD_LIMITS, "ElMax:", 3, 0, 10, 10, &rad->elma, 1.0, 500.0, 0, 0, "Sets maximum size of an element");
+ uiDefButS(block, NUM, B_RAD_LIMITS, "ElMin:", 3, 0, 10, 10, &rad->elmi, 1.0, 100.0, 0, 0, "Sets minimum size of an element");
+ uiDefButS(block, NUM, B_RAD_LIMITS, "PaMax:", 3, 0, 10, 10, &rad->pama, 10.0, 1000.0, 0, 0, "Sets maximum size of a patch");
+ uiDefButS(block, NUM, B_RAD_LIMITS, "PaMin:", 3, 0, 10, 10, &rad->pami, 10.0, 1000.0, 0, 0, "Sets minimum size of a patch");
+
+ uiDefBut(block, BUT, B_RAD_INIT, "Limit Subdivide", 5, 0, 10, 10, NULL, 0, 0, 0, 0, "Subdivides patches");
+}
+
+
+static void radio_panel_render(Radio *rad)
+{
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "radio_panel_render", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Radio Render", "Radio", 0, 0, 318, 204)==0) return;
+ uiAutoBlock(block, 210, 30, 230, 150, UI_BLOCK_ROWS);
+
+ uiDefButS(block, NUMSLI, B_RAD_LIMITS, "Hemires:", 0, 0, 10, 10, &rad->hemires, 100.0, 1000.0, 100, 0, "Sets the size of a hemicube");
+ uiDefButS(block, NUM, B_NOP, "Max Iterations:", 2, 0, 10, 15, &rad->maxiter, 0.0, 10000.0, 0, 0, "Limits the maximum number of radiosity rounds");
+ uiDefButF(block, NUM, B_RAD_FAC, "Mult:", 3, 0, 10, 15, &rad->radfac, 0.001, 250.0, 100, 0, "Mulitplies the energy values");
+ uiDefButF(block, NUM, B_RAD_FAC, "Gamma:", 3, 0, 10, 15, &rad->gamma, 0.2, 10.0, 10, 0, "Changes the contrast of the energy values");
+ uiDefButF(block, NUMSLI, B_NOP, "Convergence:", 5, 0, 10, 10, &rad->convergence, 0.0, 1.0, 10, 0, "Sets the lower threshold of unshot energy");
+}
+
+
+/* ***************************** WORLD ************************** */
+
+void do_worldbuts(unsigned short event)
+{
+ static short mtexcopied=0;
+ static MTex mtexcopybuf;
+ World *wrld;
+ MTex *mtex;
+
+ switch(event) {
+ case B_TEXCLEARWORLD:
+ wrld= G.buts->lockpoin;
+ mtex= wrld->mtex[ wrld->texact ];
+ if(mtex) {
+ if(mtex->tex) mtex->tex->id.us--;
+ MEM_freeN(mtex);
+ wrld->mtex[ wrld->texact ]= 0;
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWOOPS, 0);
+ BIF_undo_push("Unlink world texture");
+ BIF_preview_changed(ID_WO);
+ }
+ break;
+ case B_WMTEXCOPY:
+ wrld= G.buts->lockpoin;
+ if(wrld && wrld->mtex[(int)wrld->texact] ) {
+ mtex= wrld->mtex[(int)wrld->texact];
+ if(mtex->tex==NULL) {
+ error("No texture available");
+ }
+ else {
+ memcpy(&mtexcopybuf, wrld->mtex[(int)wrld->texact], sizeof(MTex));
+ mtexcopied= 1;
+ }
+ }
+ break;
+ case B_WMTEXPASTE:
+ wrld= G.buts->lockpoin;
+ if(wrld && mtexcopied && mtexcopybuf.tex) {
+ if(wrld->mtex[(int)wrld->texact]==NULL )
+ wrld->mtex[(int)wrld->texact]= MEM_mallocN(sizeof(MTex), "mtex");
+ else if(wrld->mtex[(int)wrld->texact]->tex)
+ wrld->mtex[(int)wrld->texact]->tex->id.us--;
+
+ memcpy(wrld->mtex[(int)wrld->texact], &mtexcopybuf, sizeof(MTex));
+
+ id_us_plus((ID *)mtexcopybuf.tex);
+ BIF_undo_push("Paste mapping settings");
+ BIF_preview_changed(ID_WO);
+ scrarea_queue_winredraw(curarea);
+ }
+ break;
+ case B_AO_FALLOFF:
+ /* falloff distances option only supports plain */
+ wrld= G.buts->lockpoin;
+ if(wrld)
+ wrld->aocolor= WO_AOPLAIN;
+ scrarea_queue_winredraw(curarea);
+ break;
+ }
+}
+
+static void world_panel_mapto(World *wrld)
+{
+ uiBlock *block;
+ MTex *mtex;
+
+ block= uiNewBlock(&curarea->uiblocks, "world_panel_mapto", UI_EMBOSS, UI_HELV, curarea->win);
+ uiNewPanelTabbed("Texture and Input", "World");
+ if(uiNewPanel(curarea, block, "Map To", "World", 1280, 0, 318, 204)==0) return;
+
+ uiSetButLock(wrld->id.lib!=0, ERROR_LIBDATA_MESSAGE);
+
+ mtex= wrld->mtex[ wrld->texact ];
+ if(mtex==NULL) {
+ mtex= &emptytex;
+ default_mtex(mtex);
+ mtex->texco= TEXCO_VIEW;
+ }
+
+ /* TEXTURE OUTPUT */
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, MTEX_STENCIL, B_WORLDPRV, "Stencil", 10,125,45,19, &(mtex->texflag), 0, 0, 0, 0, "Sets the texture mapping to stencil mode");
+ uiDefButBitS(block, TOG, MTEX_NEGATIVE, B_WORLDPRV, "Neg", 55,125,30,19, &(mtex->texflag), 0, 0, 0, 0, "Inverts the values of the texture to reverse its effect");
+ uiDefButBitS(block, TOG, MTEX_RGBTOINT, B_WORLDPRV, "No RGB", 85,125,60,19, &(mtex->texflag), 0, 0, 0, 0, "Converts texture RGB values to intensity (gray) values");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, COL, B_WORLDPRV, "", 10,100,135,19, &(mtex->r), 0, 0, 0, B_MTEXCOL, "");
+ uiDefButF(block, NUMSLI, B_WORLDPRV, "R ", 10,80,135,19, &(mtex->r), 0.0, 1.0, B_MTEXCOL, 0, "The default color for textures that don't return RGB");
+ uiDefButF(block, NUMSLI, B_WORLDPRV, "G ", 10,60,135,19, &(mtex->g), 0.0, 1.0, B_MTEXCOL, 0, "The default color for textures that don't return RGB");
+ uiDefButF(block, NUMSLI, B_WORLDPRV, "B ", 10,40,135,19, &(mtex->b), 0.0, 1.0, B_MTEXCOL, 0, "The default color for textures that don't return RGB");
+ uiBlockEndAlign(block);
+ uiDefButF(block, NUMSLI, B_WORLDPRV, "DVar ", 10,10,135,19, &(mtex->def_var), 0.0, 1.0, 0, 0, "The default value for textures to mix with values (not RGB)");
+
+ /* MAP TO */
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, WOMAP_BLEND, B_WORLDPRV, "Blend", 10,180,75,19, &(mtex->mapto), 0, 0, 0, 0, "Causes the texture to affect the color progression of the background");
+ uiDefButBitS(block, TOG, WOMAP_HORIZ, B_WORLDPRV, "Hori", 85,180,75,19, &(mtex->mapto), 0, 0, 0, 0, "Causes the texture to affect the color of the horizon");
+ uiDefButBitS(block, TOG, WOMAP_ZENUP, B_WORLDPRV, "ZenUp", 160,180,75,19, &(mtex->mapto), 0, 0, 0, 0, "Causes the texture to affect the color of the zenith above");
+ uiDefButBitS(block, TOG, WOMAP_ZENDOWN, B_WORLDPRV, "ZenDo", 235,180,75,19, &(mtex->mapto), 0, 0, 0, 0, "Causes the texture to affect the color of the zenith below");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, MENU, B_WORLDPRV, mapto_blendtype_pup(),155,125,155,19, &(mtex->blendtype), 0, 0, 0, 0, "Texture blending mode");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUMSLI, B_WORLDPRV, "Col ", 155,100,155,19, &(mtex->colfac), 0.0, 1.0, 0, 0, "Sets the amount the texture affects color values");
+ uiDefButF(block, NUMSLI, B_WORLDPRV, "Nor ", 155,80,155,19, &(mtex->norfac), 0.0, 1.0, 0, 0, "Sets the amount the texture affects normal values");
+ uiDefButF(block, NUMSLI, B_WORLDPRV, "Var ", 155,60,155,19, &(mtex->varfac), 0.0, 1.0, 0, 0, "Sets the amount the texture affects other values");
+
+}
+
+static void world_panel_texture(World *wrld)
+{
+ uiBlock *block;
+ MTex *mtex;
+ ID *id;
+ int a, loos;
+ char str[64], *strp;
+
+ block= uiNewBlock(&curarea->uiblocks, "world_panel_texture", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Texture and Input", "World", 960, 0, 318, 204)==0) return;
+
+ uiSetButLock(wrld->id.lib!=0, ERROR_LIBDATA_MESSAGE);
+
+ /* TEX CHANNELS */
+ uiBlockSetCol(block, TH_BUT_NEUTRAL);
+ uiBlockBeginAlign(block);
+ for(a= 0; a<MAX_MTEX; a++) {
+ mtex= wrld->mtex[a];
+ if(mtex && mtex->tex) splitIDname(mtex->tex->id.name+2, str, &loos);
+ else strcpy(str, "");
+ str[10]= 0;
+ uiDefButS(block, ROW, REDRAWBUTSSHADING, str,10, 160-18*a, 80, 20, &(wrld->texact), 3.0, (float)a, 0, 0, "Texture channel");
+ }
+ uiBlockEndAlign(block);
+
+ mtex= wrld->mtex[ wrld->texact ];
+ if(mtex==NULL) {
+ mtex= &emptytex;
+ default_mtex(mtex);
+ mtex->texco= TEXCO_VIEW;
+ }
+
+ /* TEXTUREBLOCK SELECT */
+ uiBlockSetCol(block, TH_BUT_SETTING2);
+ id= (ID *)mtex->tex;
+ IDnames_to_pupstring(&strp, NULL, "ADD NEW %x 32767", &(G.main->tex), id, &(G.buts->texnr));
+ uiDefButS(block, MENU, B_WTEXBROWSE, strp, 100,140,20,19, &(G.buts->texnr), 0, 0, 0, 0, "Selects an existing texture or creates new");
+ MEM_freeN(strp);
+
+ if(id) {
+ uiDefBut(block, TEX, B_IDNAME, "TE:", 100,160,200,19, id->name+2, 0.0, 21.0, 0, 0, "Displays name of the texture block: click to change");
+ sprintf(str, "%d", id->us);
+ uiDefBut(block, BUT, 0, str, 196,140,21,19, 0, 0, 0, 0, 0, "Displays number of users of texture: click to make single user");
+ uiDefIconBut(block, BUT, B_AUTOTEXNAME, ICON_AUTO, 220,140,21,19, 0, 0, 0, 0, 0, "Auto-assigns name to texture");
+ if(id->lib) {
+ if(wrld->id.lib) uiDefIconBut(block, BUT, 0, ICON_DATALIB, 219,140,21,19, 0, 0, 0, 0, 0, "");
+ else uiDefIconBut(block, BUT, 0, ICON_PARLIB, 219,140,21,19, 0, 0, 0, 0, 0, "");
+ }
+ uiBlockSetCol(block, TH_AUTO);
+ uiDefBut(block, BUT, B_TEXCLEARWORLD, "Clear", 122, 140, 72, 19, 0, 0, 0, 0, 0, "Erases link to texture");
+ }
+ else
+ uiDefButS(block, TOG, B_WTEXBROWSE, "Add New" ,100, 160, 200, 19, &(G.buts->texnr), -1.0, 32767.0, 0, 0, "Adds a new texture datablock");
+
+ uiBlockSetCol(block, TH_AUTO);
+
+ /* copy/paste */
+ uiBlockBeginAlign(block);
+ uiDefIconBut(block, BUT, B_WMTEXCOPY, ICON_COPYUP, 250,140,25,19, 0, 0, 0, 0, 0, "Copies the mapping settings to the buffer");
+ uiDefIconBut(block, BUT, B_WMTEXPASTE, ICON_PASTEUP,275,140,25,19, 0, 0, 0, 0, 0, "Pastes the mapping settings from the buffer");
+
+ /* TEXCO */
+ uiBlockBeginAlign(block);
+ uiDefButS(block, ROW, B_WORLDPRV, "View", 100,110,100,20, &(mtex->texco), 4.0, (float)TEXCO_VIEW, 0, 0, "Uses view vector for the texture coordinates");
+ uiDefButS(block, ROW, B_WORLDPRV, "Global", 200,110,100,20, &(mtex->texco), 4.0, (float)TEXCO_GLOB, 0, 0, "Uses global coordinates for the texture coordinates (interior mist)");
+
+ uiDefButS(block, ROW, B_WORLDPRV, "AngMap", 100,90,70,20, &(mtex->texco), 4.0, (float)TEXCO_ANGMAP, 0, 0, "Uses 360 degree angular coordinates, e.g. for spherical light probes");
+ uiDefButS(block, ROW, B_WORLDPRV, "Sphere", 170,90,65,20, &(mtex->texco), 4.0, (float)TEXCO_H_SPHEREMAP, 0, 0, "For 360 degree panorama sky, spherical mapped, only top half");
+ uiDefButS(block, ROW, B_WORLDPRV, "Tube", 235,90,65,20, &(mtex->texco), 4.0, (float)TEXCO_H_TUBEMAP, 0, 0, "For 360 degree panorama sky, cylindrical mapped, only top half");
+
+ uiDefButS(block, ROW, B_WORLDPRV, "Object", 100,70,70,20, &(mtex->texco), 4.0, (float)TEXCO_OBJECT, 0, 0, "Uses linked object's coordinates for texture coordinates");
+ uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_WORLDPRV, "OB:", 170,70,130,20, &(mtex->object), "Object name to use for mapping");
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_WORLDPRV, "dX", 100,40,100,19, mtex->ofs, -20.0, 20.0, 10, 0, "Fine tunes texture mapping X coordinate");
+ uiDefButF(block, NUM, B_WORLDPRV, "dY", 100,20,100,19, mtex->ofs+1, -20.0, 20.0, 10, 0, "Fine tunes texture mapping Y coordinate");
+ uiDefButF(block, NUM, B_WORLDPRV, "dZ", 100, 0,100,19, mtex->ofs+2, -20.0, 20.0, 10, 0, "Fine tunes texture mapping Z coordinate");
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_WORLDPRV, "sizeX", 200,40,100,19, mtex->size, -10.0, 10.0, 10, 0, "Sets scaling for the texture's X size");
+ uiDefButF(block, NUM, B_WORLDPRV, "sizeY", 200,20,100,19, mtex->size+1, -10.0, 10.0, 10, 0, "Sets scaling for the texture's Y size");
+ uiDefButF(block, NUM, B_WORLDPRV, "sizeZ", 200, 0,100,19, mtex->size+2, -10.0, 10.0, 10, 0, "Sets scaling for the texture's Z size");
+
+}
+
+static void world_panel_mistaph(World *wrld)
+{
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "world_panel_mistaph", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Mist / Stars / Physics", "World", 640, 0, 318, 204)==0) return;
+
+ uiSetButLock(wrld->id.lib!=0, ERROR_LIBDATA_MESSAGE);
+
+#if GAMEBLENDER == 1
+ uiDefButI(block, MENU, 1,
+#ifdef USE_ODE
+ "Physics %t|None %x0|Sumo %x2|Ode %x4 |Bullet %x5",
+#else
+ //"Physics %t|None %x0|Sumo %x2|Bullet %x5", //disable Sumo, until too many people complain ;-)
+ "Physics %t|None %x0|Sumo (deprecated) %x2|Bullet %x5",
+#endif
+ 10,180,140,19, &wrld->physicsEngine, 0, 0, 0, 0,
+ "Physics Engine");
+
+ /* Gravitation for the game worlds */
+ uiDefButF(block, NUMSLI,0, "Grav ", 150,180,150,19, &(wrld->gravity), 0.0, 25.0, 0, 0, "Sets the gravitation constant of the game world");
+#endif
+
+ uiBlockSetCol(block, TH_BUT_SETTING1);
+ uiDefButBitS(block, TOG, WO_MIST, B_WORLDPRV2,"Mist", 10,120,140,19, &wrld->mode, 0, 0, 0, 0, "Toggles mist simulation");
+ uiBlockSetCol(block, TH_AUTO);
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, ROW, B_WORLDPRV2, "Qua", 10, 90, 40, 19, &wrld->mistype, 1.0, 0.0, 0, 0, "Mist uses quadratic progression");
+ uiDefButS(block, ROW, B_WORLDPRV2, "Lin", 50, 90, 50, 19, &wrld->mistype, 1.0, 1.0, 0, 0, "Mist uses linear progression");
+ uiDefButS(block, ROW, B_WORLDPRV2, "Sqr", 100, 90, 50, 19, &wrld->mistype, 1.0, 2.0, 0, 0, "Mist uses inverse quadratic progression");
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM,B_WORLDPRV2, "Sta:",10,70,140,19, &wrld->miststa, 0.0, 10000.0, 10, 0, "Specifies the starting distance of the mist");
+ uiDefButF(block, NUM,B_WORLDPRV2, "Di:",10,50,140,19, &wrld->mistdist, 0.0,10000.0, 10, 00, "Specifies the depth of the mist");
+ uiDefButF(block, NUM,B_WORLDPRV2,"Hi:", 10,30,140,19, &wrld->misthi,0.0,100.0, 10, 0, "Specifies the factor for a less dense mist with increasing height");
+ uiDefButF(block, NUMSLI, B_WORLDPRV2, "Misi ", 10,10,140,19, &(wrld->misi), 0., 1.0, 0, 0, "Sets the mist intensity");
+ uiBlockEndAlign(block);
+
+ uiBlockSetCol(block, TH_BUT_SETTING1);
+ uiDefButBitS(block, TOG, WO_STARS, B_WORLDPRV2, "Stars",160,120,140,19, &wrld->mode, 0, 0, 0, 0, "Toggles starfield generation");
+ uiBlockSetCol(block, TH_AUTO);
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM,B_WORLDPRV2,"StarDist:", 160,70,140,19, &(wrld->stardist), 2.0, 1000.0, 100, 0, "Specifies the average distance between any two stars");
+ uiDefButF(block, NUM,B_WORLDPRV2,"MinDist:", 160,50,140,19, &(wrld->starmindist), 0.0, 1000.0, 100, 0, "Specifies the minimum distance to the camera for stars");
+ uiDefButF(block, NUMSLI,B_WORLDPRV2,"Size:", 160,30,140,19, &(wrld->starsize), 0.0, 10.0, 10, 0, "Specifies the average screen dimension of stars");
+ uiDefButF(block, NUMSLI,B_WORLDPRV2,"Colnoise:", 160,10,140,19, &(wrld->starcolnoise), 0.0, 1.0, 100, 0, "Randomizes star color");
+ uiBlockEndAlign(block);
+
+}
+
+static void world_panel_amb_occ(World *wrld)
+{
+ uiBlock *block;
+ short yco=PANEL_YMAX;
+
+ block= uiNewBlock(&curarea->uiblocks, "world_panel_amb_oc", UI_EMBOSS, UI_HELV, curarea->win);
+ uiNewPanelTabbed("Mist / Stars / Physics", "World");
+ if(uiNewPanel(curarea, block, "Amb Occ", "World", PANELX, PANELY, PANELW, PANELH)==0) return;
+
+ uiBlockSetCol(block, TH_BUT_SETTING1);
+ uiDefButBitS(block, TOG, WO_AMB_OCC, B_REDR, "Ambient Occlusion",
+ X2CLM1, yco-=BUTH, BUTW1, BUTH, &wrld->mode, 0, 0, 0, 0, "Toggles ambient occlusion (soft shadows)");
+ uiBlockSetCol(block, TH_AUTO);
+
+ if(!(wrld->mode & WO_AMB_OCC)) return;
+
+ yco -= YSPACE;
+
+ uiDefButS(block, NUM, B_REDR, "Samples:",
+ X2CLM1, yco-=BUTH, BUTW2, BUTH, &wrld->aosamp, 1.0, 32.0, 100, 0, "Sets the number of samples used for AO (actual number: squared)");
+
+ yco -= YSPACE;
+
+ uiDefButF(block, NUM, B_REDR, "Max Dist:",
+ X2CLM1, yco-=BUTH, BUTW2, BUTH, &wrld->aodist, 0.001, 5000.0, 100, 0, "Sets length of AO rays, defines how far away other faces give occlusion effect");
+
+ yco -= YSPACE;
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, WO_AODIST, B_AO_FALLOFF, "Use Falloff",
+ X2CLM1, yco-=BUTH, BUTW2, BUTH, &wrld->aomode, 0, 0, 0, 0, "When enabled, distances to objects will be used to attenuate shadows. Only for Plain AO.");
+ if (wrld->aomode & WO_AODIST)
+ uiDefButF(block, NUM, B_REDR, "Strength:",
+ X2CLM1, yco-=BUTH, BUTW2, BUTH, &wrld->aodistfac, 0.00001, 10.0, 100, 0, "Distance attenuation factor, the higher, the 'shorter' the shadows");
+ uiBlockEndAlign(block);
+
+ /* column 2 */
+ yco = PANEL_YMAX - BUTH - YSPACE;
+
+ uiDefButS(block, MENU, B_REDR, "Constant QMC %x2|Adaptive QMC %x1|Constant Jittered %x0",
+ X2CLM2, yco-=BUTH, BUTW2, BUTH, &wrld->ao_samp_method, 0, 0, 0, 0, "Method for generating shadow samples: Constant QMC: best quality, Adaptive QMC: fast in high contrast areas");
+
+ yco -= YSPACE;
+
+ if (wrld->ao_samp_method == WO_AOSAMP_HALTON) {
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_REDR, "Threshold:",
+ X2CLM2, yco-=BUTH, BUTW2, BUTH, &wrld->ao_adapt_thresh, 0.0, 1.0, 100, 0, "Samples below this threshold will be considered fully shadowed/unshadowed and skipped");
+ uiDefButF(block, NUMSLI, B_REDR, "Adapt Vec:",
+ X2CLM2, yco-=BUTH, BUTW2, BUTH, &wrld->ao_adapt_speed_fac, 0.0, 1.0, 100, 0, "Use the speed vector pass to reduce AO samples in fast moving pixels. The higher the value, the more aggressive the sample reduction. Requires Vec pass enabled.");
+ uiBlockEndAlign(block);
+ } else if (wrld->ao_samp_method == WO_AOSAMP_CONSTANT) {
+ uiDefButF(block, NUMSLI, B_REDR, "Bias:",
+ X2CLM2, yco-=BUTH, BUTW2, BUTH, &wrld->aobias, 0.0, 0.5, 10, 0, "Sets bias to prevent smoothed faces to show banding (in radians)");
+ }
+
+
+ yco = PANEL_YMAX - (5*BUTH+4*YSPACE);
+
+ /* result mix modes */
+ uiBlockBeginAlign(block);
+ uiDefButS(block, ROW, B_REDR, "Add",
+ X3CLM1, yco-=BUTH, BUTW3, BUTH, &wrld->aomix, 1.0, (float)WO_AOADD, 0, 0, "adds light/shadows");
+ uiDefButS(block, ROW, B_REDR, "Sub",
+ X3CLM2, yco, BUTW3, BUTH, &wrld->aomix, 1.0, (float)WO_AOSUB, 0, 0, "subtracts light/shadows (needs at least one normal light to make anything visible)");
+ uiDefButS(block, ROW, B_REDR, "Both",
+ X3CLM3, yco, BUTW3, BUTH, &wrld->aomix, 1.0, (float)WO_AOADDSUB, 0, 0, "both lightens & darkens");
+
+ yco -= YSPACE;
+
+ /* color treatment */
+ uiBlockBeginAlign(block);
+ uiDefButS(block, ROW, B_REDR, "Plain",
+ X3CLM1, yco-=BUTH, BUTW3, BUTH, &wrld->aocolor, 2.0, (float)WO_AOPLAIN, 0, 0, "Plain diffuse energy (white)");
+ uiDefButS(block, ROW, B_REDR, "Sky Color",
+ X3CLM2, yco, BUTW3, BUTH, &wrld->aocolor, 2.0, (float)WO_AOSKYCOL, 0, 0, "Use horizon and zenith color for diffuse energy");
+ uiDefButS(block, ROW, B_REDR, "Sky Texture",
+ X3CLM3, yco, BUTW3, BUTH, &wrld->aocolor, 2.0, (float)WO_AOSKYTEX, 0, 0, "Does full Sky texture render for diffuse energy");
+ uiBlockEndAlign(block);
+
+ yco -= YSPACE;
+
+ uiDefButF(block, NUMSLI, B_REDR, "Energy:",
+ X2CLM1, yco-=BUTH, BUTW2, BUTH, &wrld->aoenergy, 0.01, 3.0, 100, 0, "Sets global energy scale for AO");
+
+}
+
+static void world_panel_world(World *wrld)
+{
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "world_panel_world", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "World", "World", 320, 0, 318, 204)==0) return;
+
+ uiBlockSetCol(block, TH_BUT_SETTING2);
+ std_libbuttons(block, 10, 180, 0, NULL, B_WORLDBROWSE, ID_WO, 0, (ID *)wrld, (ID *)G.scene, &(G.buts->menunr), B_WORLDALONE, B_WORLDLOCAL, B_WORLDDELETE, 0, B_KEEPDATA);
+
+ if(wrld==NULL) return;
+
+ uiSetButLock(wrld->id.lib!=0, ERROR_LIBDATA_MESSAGE);
+ uiBlockSetCol(block, TH_AUTO);
+
+ uiDefButF(block, COL, B_WORLDPRV, "", 10,150,145,19, &wrld->horr, 0, 0, 0, B_COLHOR, "");
+ uiDefButF(block, COL, B_WORLDPRV, "", 160,150,145,19, &wrld->zenr, 0, 0, 0, B_COLZEN, "");
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUMSLI,B_WORLDPRV,"HoR ", 10,130,145,19, &(wrld->horr), 0.0, 1.0, B_COLHOR,0, "Sets the amount of red color at the horizon");
+ uiDefButF(block, NUMSLI,B_WORLDPRV,"HoG ", 10,110,145,19, &(wrld->horg), 0.0, 1.0, B_COLHOR,0, "Sets the amount of green color at the horizon");
+ uiDefButF(block, NUMSLI,B_WORLDPRV,"HoB ", 10,90,145,19, &(wrld->horb), 0.0, 1.0, B_COLHOR,0, "Sets the amount of blue color at the horizon");
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUMSLI,B_WORLDPRV,"ZeR ", 160,130,145,19, &(wrld->zenr), 0.0, 1.0, B_COLZEN,0, "Sets the amount of red color at the zenith");
+ uiDefButF(block, NUMSLI,B_WORLDPRV,"ZeG ", 160,110,145,19, &(wrld->zeng), 0.0, 1.0, B_COLZEN,0, "Sets the amount of green color at the zenith");
+ uiDefButF(block, NUMSLI,B_WORLDPRV,"ZeB ", 160,90,145,19, &(wrld->zenb), 0.0, 1.0, B_COLZEN,0, "Sets the amount of blue color at the zenith");
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUMSLI,B_WORLDPRV,"AmbR ", 10,50,145,19, &(wrld->ambr), 0.0, 1.0 ,0,0, "Sets the amount of red ambient color");
+ uiDefButF(block, NUMSLI,B_WORLDPRV,"AmbG ", 10,30,145,19, &(wrld->ambg), 0.0, 1.0 ,0,0, "Sets the amount of green ambient color");
+ uiDefButF(block, NUMSLI,B_WORLDPRV,"AmbB ", 10,10,145,19, &(wrld->ambb), 0.0, 1.0 ,0,0, "Sets the amount of blue ambient color");
+
+ uiBlockBeginAlign(block);
+ uiBlockSetCol(block, TH_BUT_SETTING1);
+ uiDefButF(block, NUMSLI,B_WORLDPRV, "Exp ", 160,30,145,19, &(wrld->exp), 0.0, 1.0, 0, 2, "Sets amount of exponential color correction for light");
+ uiDefButF(block, NUMSLI,B_WORLDPRV, "Range ", 160,10,145,19, &(wrld->range), 0.2, 5.0, 0, 2, "Sets the color amount that will be mapped on color 1.0");
+
+
+}
+
+static void world_panel_preview(World *wrld)
+{
+ uiBlock *block;
+
+ /* name "Preview" is abused to detect previewrender offset panel */
+ block= uiNewBlock(&curarea->uiblocks, "world_panel_preview", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Preview", "World", 0, 0, 318, 204)==0) return;
+
+ if(wrld==NULL) return;
+
+ uiSetButLock(wrld->id.lib!=0, ERROR_LIBDATA_MESSAGE);
+
+ uiBlockSetDrawExtraFunc(block, BIF_previewdraw);
+
+ // label to force a boundbox for buttons not to be centered
+ uiDefBut(block, LABEL, 0, " ", 20,20,10,10, 0, 0, 0, 0, 0, "");
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, WO_SKYREAL, B_WORLDPRV,"Real", 200,175,80,25, &wrld->skytype, 0, 0, 0, 0, "Renders background with a real horizon");
+ uiDefButBitS(block, TOG, WO_SKYBLEND, B_WORLDPRV,"Blend",200,150,80,25, &wrld->skytype, 0, 0, 0, 0, "Renders background with natural progression from horizon to zenith");
+ uiDefButBitS(block, TOG,WO_SKYPAPER, B_WORLDPRV,"Paper",200,125,80,25, &wrld->skytype, 0, 0, 0, 0, "Flattens blend or texture coordinates");
+ uiBlockEndAlign(block);
+
+}
+
+/* ************************ LAMP *************************** */
+
+void do_lampbuts(unsigned short event)
+{
+ static short mtexcopied=0;
+ static MTex mtexcopybuf;
+ Lamp *la;
+ MTex *mtex;
+
+ switch(event) {
+ case B_LAMPREDRAW:
+ BIF_preview_changed(ID_LA);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSSHADING, 0);
+ break;
+ case B_TEXCLEARLAMP:
+ la= G.buts->lockpoin;
+ mtex= la->mtex[ la->texact ];
+ if(mtex) {
+ if(mtex->tex) mtex->tex->id.us--;
+ MEM_freeN(mtex);
+ la->mtex[ la->texact ]= 0;
+ BIF_undo_push("Unlink world texture");
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWOOPS, 0);
+ BIF_preview_changed(ID_LA);
+ }
+ break;
+ case B_SBUFF:
+ la= G.buts->lockpoin;
+ la->bufsize = la->bufsize&=(~15);
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWOOPS, 0);
+ break;
+ case B_SHADBUF:
+ la= G.buts->lockpoin;
+ la->mode &= ~LA_SHAD_RAY;
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+ case B_SHADRAY:
+ la= G.buts->lockpoin;
+ la->mode &= ~LA_SHAD_BUF;
+ /* yafray: 'softlight' uses it's own shadbuf. flag.
+ Must be cleared here too when switching from ray shadow */
+ la->mode &= ~LA_YF_SOFT;
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+ case B_LMTEXCOPY:
+ la= G.buts->lockpoin;
+ if(la && la->mtex[(int)la->texact] ) {
+ mtex= la->mtex[(int)la->texact];
+ if(mtex->tex==NULL) {
+ error("No texture available");
+ }
+ else {
+ memcpy(&mtexcopybuf, la->mtex[(int)la->texact], sizeof(MTex));
+ mtexcopied= 1;
+ }
+ }
+ break;
+ case B_LMTEXPASTE:
+ la= G.buts->lockpoin;
+ if(la && mtexcopied && mtexcopybuf.tex) {
+ if(la->mtex[(int)la->texact]==NULL )
+ la->mtex[(int)la->texact]= MEM_mallocN(sizeof(MTex), "mtex");
+ else if(la->mtex[(int)la->texact]->tex)
+ la->mtex[(int)la->texact]->tex->id.us--;
+
+ memcpy(la->mtex[(int)la->texact], &mtexcopybuf, sizeof(MTex));
+
+ id_us_plus((ID *)mtexcopybuf.tex);
+ BIF_undo_push("Paste mapping settings");
+ BIF_preview_changed(ID_LA);
+ scrarea_queue_winredraw(curarea);
+ }
+ break;
+ case B_LFALLOFFCHANGED:
+ la= G.buts->lockpoin;
+ curvemapping_changed(la->curfalloff, 1);
+ BIF_undo_push("Edit Lamp falloff curve");
+ BIF_preview_changed(ID_LA);
+ scrarea_queue_winredraw(curarea);
+ break;
+
+ }
+}
+
+
+static void lamp_panel_mapto(Object *ob, Lamp *la)
+{
+ uiBlock *block;
+ MTex *mtex;
+
+ block= uiNewBlock(&curarea->uiblocks, "lamp_panel_mapto", UI_EMBOSS, UI_HELV, curarea->win);
+ uiNewPanelTabbed("Texture and Input", "Lamp");
+ if(uiNewPanel(curarea, block, "Map To", "Lamp", 1280, 0, 318, 204)==0) return;
+
+ uiSetButLock(la->id.lib!=0, ERROR_LIBDATA_MESSAGE);
+
+ mtex= la->mtex[ la->texact ];
+ if(mtex==NULL) {
+ mtex= &emptytex;
+ default_mtex(mtex);
+ mtex->texco= TEXCO_VIEW;
+ }
+
+ /* TEXTURE OUTPUT */
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, MTEX_STENCIL, B_LAMPPRV, "Stencil", 10,125,45,19, &(mtex->texflag), 0, 0, 0, 0, "Sets the texture mapping to stencil mode");
+ uiDefButBitS(block, TOG, MTEX_NEGATIVE, B_LAMPPRV, "Neg", 55,125,30,19, &(mtex->texflag), 0, 0, 0, 0, "Inverts the values of the texture to reverse its effect");
+ uiDefButBitS(block, TOG, MTEX_RGBTOINT, B_LAMPPRV, "No RGB", 85,125,60,19, &(mtex->texflag), 0, 0, 0, 0, "Converts texture RGB values to intensity (gray) values");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, COL, B_LAMPPRV, "", 10,100,135,19, &(mtex->r), 0, 0, 0, B_MTEXCOL, "");
+ uiDefButF(block, NUMSLI, B_LAMPPRV, "R ", 10,80,135,19, &(mtex->r), 0.0, 1.0, B_MTEXCOL, 0, "The default color for textures that don't return RGB");
+ uiDefButF(block, NUMSLI, B_LAMPPRV, "G ", 10,60,135,19, &(mtex->g), 0.0, 1.0, B_MTEXCOL, 0, "The default color for textures that don't return RGB");
+ uiDefButF(block, NUMSLI, B_LAMPPRV, "B ", 10,40,135,19, &(mtex->b), 0.0, 1.0, B_MTEXCOL, 0, "The default color for textures that don't return RGB");
+ uiBlockEndAlign(block);
+ uiDefButF(block, NUMSLI, B_LAMPPRV, "DVar ", 10,10,135,19, &(mtex->def_var), 0.0, 1.0, 0, 0, "The default value the textures uses to mix with");
+
+ /* MAP TO */
+ uiDefButBitS(block, TOG, MAP_COL, B_LAMPPRV, "Col", 10,180,135,19, &(mtex->mapto), 0, 0, 0, 0, "Lets the texture affect the basic color of the lamp");
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, MENU, B_LAMPPRV, mapto_blendtype_pup(),155,125,155,19, &(mtex->blendtype), 0, 0, 0, 0, "Texture blending mode");
+ uiBlockEndAlign(block);
+
+ uiDefButF(block, NUMSLI, B_LAMPPRV, "Col ", 155,100,155,19, &(mtex->colfac), 0.0, 1.0, 0, 0, "Sets the amount the texture affects color values");
+
+}
+
+
+static void lamp_panel_texture(Object *ob, Lamp *la)
+{
+ uiBlock *block;
+ MTex *mtex;
+ ID *id;
+ int a, loos;
+ char *strp, str[64];
+
+ block= uiNewBlock(&curarea->uiblocks, "lamp_panel_texture", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Texture and Input", "Lamp", 960, 0, 318, 204)==0) return;
+
+ uiSetButLock(la->id.lib!=0, ERROR_LIBDATA_MESSAGE);
+
+ /* TEX CHANNELS */
+ uiBlockSetCol(block, TH_BUT_NEUTRAL);
+ uiBlockBeginAlign(block);
+ for(a= 0; a<MAX_MTEX; a++) {
+ mtex= la->mtex[a];
+ if(mtex && mtex->tex) splitIDname(mtex->tex->id.name+2, str, &loos);
+ else strcpy(str, "");
+ str[10]= 0;
+ uiDefButS(block, ROW, B_REDR, str, 10, 160-18*a, 80, 20, &(la->texact), 3.0, (float)a, 0, 0, "");
+ }
+ uiBlockEndAlign(block);
+
+ mtex= la->mtex[ la->texact ];
+ if(mtex==NULL) {
+ mtex= &emptytex;
+ default_mtex(mtex);
+ mtex->texco= TEXCO_VIEW;
+ }
+
+ /* TEXTUREBLOK SELECT */
+ uiBlockSetCol(block, TH_BUT_SETTING2);
+ id= (ID *)mtex->tex;
+ IDnames_to_pupstring(&strp, NULL, "ADD NEW %x 32767", &(G.main->tex), id, &(G.buts->texnr));
+
+ /* doesnt work, because lockpoin points to lamp, not to texture */
+ uiDefButS(block, MENU, B_LTEXBROWSE, strp, 100,140,20,19, &(G.buts->texnr), 0, 0, 0, 0, "Selects an existing texture or creates new");
+ MEM_freeN(strp);
+
+ if(id) {
+ uiDefBut(block, TEX, B_IDNAME, "TE:", 100,160,200,19, id->name+2, 0.0, 21.0, 0, 0, "Displays name of the texture block: click to change");
+ sprintf(str, "%d", id->us);
+ uiDefBut(block, BUT, 0, str, 196,140,21,19, 0, 0, 0, 0, 0, "Displays number of users of texture: click to make single user");
+ uiDefIconBut(block, BUT, B_AUTOTEXNAME, ICON_AUTO, 221,140,21,19, 0, 0, 0, 0, 0, "Auto-assigns name to texture");
+ if(id->lib) {
+ if(la->id.lib) uiDefIconBut(block, BUT, 0, ICON_DATALIB, 219,140,21,19, 0, 0, 0, 0, 0, "");
+ else uiDefIconBut(block, BUT, 0, ICON_PARLIB, 219,140,21,19, 0, 0, 0, 0, 0, "");
+ }
+ uiBlockSetCol(block, TH_AUTO);
+ uiDefBut(block, BUT, B_TEXCLEARLAMP, "Clear", 122, 140, 72, 19, 0, 0, 0, 0, 0, "Erases link to texture");
+ }
+ else
+ uiDefButS(block, TOG, B_LTEXBROWSE, "Add New" ,100, 160, 200, 19, &(G.buts->texnr), -1.0, 32767.0, 0, 0, "Adds a new texture datablock");
+
+ /* copy/paste */
+ uiBlockBeginAlign(block);
+ uiDefIconBut(block, BUT, B_LMTEXCOPY, ICON_COPYUP, 250,140,25,19, 0, 0, 0, 0, 0, "Copies the mapping settings to the buffer");
+ uiDefIconBut(block, BUT, B_LMTEXPASTE, ICON_PASTEUP, 275,140,25,19, 0, 0, 0, 0, 0, "Pastes the mapping settings from the buffer");
+
+ /* TEXCO */
+ uiBlockSetCol(block, TH_AUTO);
+ uiBlockBeginAlign(block);
+ uiDefButS(block, ROW, B_LAMPPRV, "Glob", 100,110,60,20, &(mtex->texco), 4.0, (float)TEXCO_GLOB, 0, 0, "Uses global coordinates for the texture coordinates");
+ uiDefButS(block, ROW, B_LAMPPRV, "View", 160,110,70,20, &(mtex->texco), 4.0, (float)TEXCO_VIEW, 0, 0, "Uses view coordinates for the texture coordinates");
+ uiDefButS(block, ROW, B_LAMPPRV, "Object", 230,110,70,20, &(mtex->texco), 4.0, (float)TEXCO_OBJECT, 0, 0, "Uses linked object's coordinates for texture coordinates");
+ uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_LAMPPRV, "", 100,90,200,20, &(mtex->object), "");
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_LAMPPRV, "dX", 100,50,100,18, mtex->ofs, -20.0, 20.0, 10, 0, "Fine tunes texture mapping X coordinate");
+ uiDefButF(block, NUM, B_LAMPPRV, "dY", 100,30,100,18, mtex->ofs+1, -20.0, 20.0, 10, 0, "Fine tunes texture mapping Y coordinate");
+ uiDefButF(block, NUM, B_LAMPPRV, "dZ", 100,10,100,18, mtex->ofs+2, -20.0, 20.0, 10, 0, "Fine tunes texture mapping Z coordinate");
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_LAMPPRV, "sizeX", 200,50,100,18, mtex->size, -10.0, 10.0, 10, 0, "Sets scaling for the texture's X size");
+ uiDefButF(block, NUM, B_LAMPPRV, "sizeY", 200,30,100,18, mtex->size+1, -10.0, 10.0, 10, 0, "Sets scaling for the texture's Y size");
+ uiDefButF(block, NUM, B_LAMPPRV, "sizeZ", 200,10,100,18, mtex->size+2, -10.0, 10.0, 10, 0, "Sets scaling for the texture's Z size");
+ uiBlockEndAlign(block);
+}
+
+static void lamp_panel_spot(Object *ob, Lamp *la)
+{
+ uiBlock *block;
+ float grid=0.0;
+
+ block= uiNewBlock(&curarea->uiblocks, "lamp_panel_spot", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Shadow and Spot", "Lamp", 640, 0, 318, 204)==0) return;
+
+ /* hemis and ray shadow dont work at all... */
+ /* yafray: ignore photonlight as well */
+ if ((la->type==LA_HEMI) || (la->type==LA_YF_PHOTON)) return;
+
+ if(G.vd) grid= G.vd->grid;
+ if(grid<1.0) grid= 1.0;
+
+ uiSetButLock(la->id.lib!=0, ERROR_LIBDATA_MESSAGE);
+
+ uiBlockSetCol(block, TH_BUT_SETTING1);
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, LA_SHAD_RAY, B_SHADRAY,"Ray Shadow",10,180,80,19,&la->mode, 0, 0, 0, 0, "Use ray tracing for shadow");
+ if(la->type==LA_SPOT) {
+ uiDefButBitS(block, TOG, LA_SHAD_BUF, B_SHADBUF, "Buf.Shadow",10,160,80,19,&la->mode, 0, 0, 0, 0, "Lets spotlight produce shadows using shadow buffer");
+ if(la->mode & LA_SHAD_BUF) {
+ char *tip= "Regular buffer type";
+ if(la->buftype==LA_SHADBUF_IRREGULAR)
+ tip= "Irregular buffer produces sharp shadow always, but it doesn't show up for raytracing";
+ else if(la->buftype==LA_SHADBUF_HALFWAY)
+ tip= "Regular buffer, averaging the closest and 2nd closest Z value for reducing biasing";
+
+ uiDefButC(block, MENU, B_REDR, "Classical %x0|Classic-Halfway %x2|Irregular %x1", 10,140,80,19,&la->buftype, 0, 0, 0, 0, tip);
+ }
+ }
+ uiBlockEndAlign(block);
+
+ uiDefButBitS(block, TOG, LA_ONLYSHADOW, B_LAMPPRV,"OnlyShadow", 10,110,80,19,&la->mode, 0, 0, 0, 0, "Causes light to cast shadows only without illuminating objects");
+
+ if(la->type==LA_SPOT) {
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, LA_SQUARE, B_LAMPREDRAW,"Square", 10,60,80,19,&la->mode, 0, 0, 0, 0, "Sets square spotbundles");
+ uiDefButBitS(block, TOG, LA_HALO, B_LAMPREDRAW,"Halo", 10,40,80,19,&la->mode, 0, 0, 0, 0, "Renders spotlight with a volumetric halo");
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUMSLI,B_LAMPREDRAW,"SpotSi ", 100,180,200,19,&la->spotsize, 1.0, 180.0, 0, 0, "Sets the angle of the spotlight beam in degrees");
+ uiDefButF(block, NUMSLI,B_LAMPREDRAW,"SpotBl ", 100,160,200,19,&la->spotblend, 0.0, 1.0, 0, 0, "Sets the softness of the spotlight edge");
+ uiBlockEndAlign(block);
+
+ uiDefButF(block, NUMSLI,B_LAMPREDRAW,"HaloInt ", 100,135,200,19,&la->haint, 0.0, 5.0, 0, 0, "Sets the intensity of the spotlight halo");
+
+ if(la->mode & LA_SHAD_BUF) {
+ if(ELEM(la->buftype, LA_SHADBUF_REGULAR, LA_SHADBUF_HALFWAY)) {
+ uiBlockBeginAlign(block);
+ uiDefButS(block, NUM,B_SBUFF,"ShadowBufferSize:", 100,110,200,19, &la->bufsize,512,10240, 0, 0, "Sets the size of the shadow buffer to nearest multiple of 16");
+ uiDefButS(block, ROW,B_NOP, "Box", 100,90,65,19, &la->filtertype, 0.0, LA_SHADBUF_BOX, 0, 0, "Apply Box filter for shadowbuffer samples");
+ uiDefButS(block, ROW,B_NOP, "Tent", 165,90,65,19, &la->filtertype, 0.0, LA_SHADBUF_TENT, 0, 0, "Apply Tent filter for shadowbuffer samples");
+ uiDefButS(block, ROW,B_NOP, "Gauss", 230,90,70,19, &la->filtertype, 0.0, LA_SHADBUF_GAUSS, 0, 0, "Apply Gauss filter for shadowbuffer samples");
+
+ // uiDefButS(block, ROW,B_NOP,"SubSamples: 1", 100,90,140,19, &la->buffers, 1.0, 1.0, 0, 0, "Amount of lampbuffer subsamples, a value of larger than 1 halves the shadowbuffer size");
+ // uiDefButS(block, ROW,B_NOP,"4", 240,90,30,19, &la->buffers, 1.0, 4.0, 0, 0, "Amount of lampbuffer subsamples, this halves the actual shadowbuffer size");
+ // uiDefButS(block, ROW,B_NOP,"9", 270,90,30,19, &la->buffers, 1.0, 9.0, 0, 0, "Amount of lampbuffer subsamples, this halves the shadowbuffer size");
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, NUM,B_LAMPREDRAW,"Samples:", 100,60,100,19, &la->samp,1.0,16.0, 0, 0, "Sets the number of shadow map samples");
+ uiDefButS(block, NUM,B_NOP,"Halo step:", 200,60,100,19, &la->shadhalostep, 0.0, 12.0, 0, 0, "Sets the volumetric halo sampling frequency");
+ uiDefButF(block, NUM,B_LAMPREDRAW,"Bias:", 100,40,100,19, &la->bias, 0.001, 5.0, 1, 0, "Sets the shadow map sampling bias");
+ uiDefButF(block, NUM,B_LAMPREDRAW,"Soft:", 200,40,100,19, &la->soft,1.0,100.0, 100, 0, "Sets the size of the shadow sample area");
+ }
+ else { /* LA_SHADBUF_IRREGULAR */
+ uiDefButF(block, NUM,B_LAMPREDRAW,"Bias:", 100,40,100,19, &la->bias, 0.01, 5.0, 1, 0, "Sets the shadow map sampling bias");
+ }
+
+ uiBlockBeginAlign(block);
+ uiDefIconButBitC(block, TOG, LA_SHADBUF_AUTO_START, B_REDR, ICON_AUTO, 10, 10, 25, 19, &la->bufflag, 0.0, 0.0, 0, 0, "Automatic calculation of clipping-start, based on visible vertices");
+ if(la->bufflag & LA_SHADBUF_AUTO_START)
+ uiDefBut(block, LABEL, B_NOP, "ClipSta: Auto", 35,10,115,19, NULL, 0, 0, 0, 0, "");
+ else
+ uiDefButF(block, NUM,REDRAWVIEW3D,"ClipSta:", 35,10,115,19, &la->clipsta, 0.1*grid,1000.0*grid, 10, 0, "Sets the shadow map clip start: objects closer will not generate shadows");
+ uiDefIconButBitC(block, TOG, LA_SHADBUF_AUTO_END, B_REDR, ICON_AUTO, 160, 10, 25, 19, &la->bufflag, 0.0, 0.0, 0, 0, "Automatic calculation of clipping-end, based on visible vertices");
+ if(la->bufflag & LA_SHADBUF_AUTO_END)
+ uiDefBut(block, LABEL,B_NOP, "ClipEnd: Auto", 185,10,115,19, NULL, 0, 0, 0, 0, "");
+ else
+ uiDefButF(block, NUM,REDRAWVIEW3D,"ClipEnd:", 185,10,115,19,&la->clipend, 1.0, 5000.0*grid, 100, 0, "Sets the shadow map clip end beyond which objects will not generate shadows");
+ uiBlockEndAlign(block);
+
+ }
+ }
+ if(ELEM4(la->type, LA_AREA, LA_SPOT, LA_SUN, LA_LOCAL) && (la->mode & LA_SHAD_RAY)) {
+
+ if (ELEM3(la->type, LA_SPOT, LA_SUN, LA_LOCAL)) {
+ if (la->ray_samp_method == LA_SAMP_CONSTANT) la->ray_samp_method = LA_SAMP_HALTON;
+
+ uiDefButS(block, MENU, B_REDR, "Adaptive QMC %x1|Constant QMC %x2",
+ 100,110,200,19, &la->ray_samp_method, 0, 0, 0, 0, "Method for generating shadow samples: Adaptive QMC is fastest, Constant QMC is less noisy but slower");
+
+ uiDefButF(block, NUM,B_LAMPREDRAW,"Soft Size", 100,80,200,19, &la->area_size, 0.01, 100.0, 10, 0, "Area light size, doesn't affect energy amount");
+
+ uiDefButS(block, NUM,0,"Samples:", 100,60,200,19, &la->ray_samp, 1.0, 16.0, 100, 0, "Sets the amount of samples taken extra (samp x samp)");
+ uiDefButF(block, NUM,0,"Threshold:", 100,40,200,19, &la->adapt_thresh, 0.0, 1.0, 100, 0, "Threshold for adaptive sampling, to control what level is considered already in shadow");
+ }
+ else if (la->type == LA_AREA) {
+ uiDefButS(block, MENU, B_REDR, "Adaptive QMC %x1|Constant QMC %x2|Constant Jittered %x0",
+ 100,180,200,19, &la->ray_samp_method, 0, 0, 0, 0, "Method for generating shadow samples: Adaptive QMC is fastest");
+
+ if(la->area_shape==LA_AREA_SQUARE)
+ uiDefButS(block, NUM,0,"Samples:", 100,150,200,19, &la->ray_samp, 1.0, 16.0, 100, 0, "Sets the amount of samples taken extra (samp x samp)");
+ else if(la->area_shape==LA_AREA_CUBE)
+ uiDefButS(block, NUM,0,"Samples:", 100,130,200,19, &la->ray_samp, 1.0, 16.0, 100, 0, "Sets the amount of samples taken extra (samp x samp x samp)");
+
+ if (ELEM(la->area_shape, LA_AREA_RECT, LA_AREA_BOX)) {
+ uiDefButS(block, NUM,0,"SamplesX:", 100,150,200,19, &la->ray_samp, 1.0, 16.0, 100, 0, "Sets the amount of X samples taken extra");
+ uiDefButS(block, NUM,0,"SamplesY:", 100,130,200,19, &la->ray_sampy, 1.0, 16.0, 100, 0, "Sets the amount of Y samples taken extra");
+ if(la->area_shape==LA_AREA_BOX)
+ uiDefButS(block, NUM,0,"SamplesZ:", 100,110,200,19, &la->ray_sampz, 1.0, 8.0, 100, 0, "Sets the amount of Z samples taken extra");
+ }
+
+ if (la->ray_samp_method == LA_SAMP_CONSTANT) {
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, LA_SAMP_UMBRA, 0,"Umbra", 100,90,200,19,&la->ray_samp_type, 0, 0, 0, 0, "Emphasis parts that are fully shadowed");
+ uiDefButBitS(block, TOG, LA_SAMP_DITHER, 0,"Dither", 100,70,100,19,&la->ray_samp_type, 0, 0, 0, 0, "Use 2x2 dithering for sampling");
+ uiDefButBitS(block, TOG, LA_SAMP_JITTER, 0,"Noise", 200,70,100,19,&la->ray_samp_type, 0, 0, 0, 0, "Use noise for sampling");
+ } else if (la->ray_samp_method == LA_SAMP_HALTON) {
+ uiDefButF(block, NUM,0,"Threshold:", 100,90,200,19, &la->adapt_thresh, 0.0, 1.0, 100, 0, "Threshold for adaptive sampling, to control what level is considered already in shadow");
+ }
+ }
+
+
+ }
+ else uiDefBut(block, LABEL,0," ", 100,180,200,19,NULL, 0, 0, 0, 0, "");
+
+}
+
+/* yafray: adaptation of lamp_panel_spot above with yafray specific parameters */
+static void lamp_panel_yafray(Object *ob, Lamp *la)
+{
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "lamp_panel_yafray", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Yafray: Shadow and Photons", "Lamp", 640, 0, 318, 204)==0) return;
+
+ /* hemis not used in yafray */
+ if(la->type==LA_HEMI) return;
+
+ uiSetButLock(la->id.lib!=0, ERROR_LIBDATA_MESSAGE);
+
+ /* photonlight params */
+ if (la->type==LA_YF_PHOTON) {
+ uiBlockSetCol(block, TH_BUT_SETTING1);
+ uiDefButBitS(block, TOG, 1, B_DIFF,"Use QMC",10,180,80,19,&la->YF_useqmc, 0, 0, 0, 0, "Use QMC sampling (sometimes visible patterns)");
+ uiBlockSetCol(block, TH_AUTO);
+ uiDefButF(block, NUMSLI,B_LAMPREDRAW,"Angle ", 100,180,200,19,&la->spotsize, 1.0, 180.0, 0, 0, "Sets the angle of the photonlight beam in degrees");
+ uiDefButI(block, NUM,B_DIFF,"photons:", 10,150,290,19, &la->YF_numphotons, 10000, 100000000, 0, 0, "Maximum number of photons to shoot");
+ uiDefButI(block, NUM,B_DIFF,"search:", 10,130,290,19, &la->YF_numsearch, 100, 1000, 0, 0, "Number of photons to mix (blur)");
+ uiDefButS(block, NUM,B_DIFF,"depth:", 10,100,290,19, &la->YF_phdepth, 1, 100, 0, 0, "Maximum caustic bounce depth");
+ uiDefButF(block, NUM,B_DIFF,"Blur:", 10,70,290,19, &la->YF_causticblur, 0.01, 1.0, 1, 0, "Amount of caustics blurring (also depends on search)");
+ return;
+ }
+
+ uiBlockSetCol(block, TH_BUT_SETTING1);
+
+ /* in yafray arealights always cast shadows, so ray shadow flag not needed */
+ /* ray shadow also not used when halo for spot enabled */
+ if ((la->type!=LA_AREA) && (!((la->type==LA_SPOT) && (la->mode & LA_HALO))))
+ uiDefButBitS(block, TOG, LA_SHAD_RAY, B_SHADRAY,"Ray Shadow",10,180,80,19,&la->mode, 0, 0, 0, 0, "Use ray tracing for shadow");
+
+ /* in yafray the regular lamp can use shadowbuffers (softlight), used by spot with halo as well */
+ /* to prevent clash with blender shadowbuf flag, a special flag is used for yafray */
+ if (la->type==LA_LOCAL) {
+ uiDefButBitS(block, TOG, LA_YF_SOFT, B_SHADBUF, "Buf.Shadow",10,160,80,19,&la->mode, 0, 0, 0, 0, "Lets light produce shadows using shadow buffer");
+ uiDefButF(block, NUM, B_DIFF, "GloInt:", 100,155,200,19, &la->YF_glowint, 0.0, 1.0, 1, 0, "Sets light glow intensity, 0 is off");
+ uiDefButF(block, NUM, B_DIFF, "GloOfs:", 100,135,100,19, &la->YF_glowofs, 0.0, 2.0, 1, 0, "Sets light glow offset, the higher, the less 'peaked' the glow");
+ uiDefButS(block, NUM, B_DIFF, "GlowType:", 200,135,100,19, &la->YF_glowtype, 0, 1, 1, 0, "Sets light glow type");
+ }
+
+ /* shadowbuffers used only for 'softlight' & spotlight with halo */
+ if (((la->type==LA_LOCAL) && (la->mode & LA_YF_SOFT)) || ((la->type==LA_SPOT) && (la->mode & LA_HALO))) {
+ /* Shadow buffer size can be anything in yafray, but reasonable minimum is 128 */
+ /* Maximum is 1024, since zbuf in yafray is float, no multiple of 16 restriction */
+ uiDefButS(block, NUM,B_DIFF,"ShadowBufferSize:", 100,110,200,19, &la->YF_bufsize, 128, 1024, 0, 0, "Sets the size of the shadow buffer");
+
+ /* samples & halostep params only used for spotlight with halo */
+ if ((la->type==LA_SPOT) && (la->mode & LA_HALO)) {
+ uiDefButS(block, NUM,B_DIFF,"Samples:", 100,30,100,19, &la->samp,1.0,16.0, 0, 0, "Sets the number of shadow map samples");
+ uiDefButS(block, NUM,B_DIFF,"Halo step:", 200,30,100,19, &la->shadhalostep, 0.0, 12.0, 0, 0, "Sets the volumetric halo sampling frequency");
+ }
+ uiDefButF(block, NUM,B_DIFF,"Bias:", 100,10,100,19, &la->bias, 0.01, 5.0, 1, 0, "Sets the shadow map sampling bias");
+ /* here can use the Blender soft param, since for yafray it has the same function as in Blender */
+ uiDefButF(block, NUM,B_DIFF,"Soft:", 200,10,100,19, &la->soft,1.0,100.0, 100, 0, "Sets the size of the shadow sample area");
+ }
+ else if ((la->type==LA_LOCAL) && (la->mode & LA_SHAD_RAY)) {
+ /* for spherelight, light radius */
+ uiDefButF(block, NUM,B_DIFF,"Radius:", 200,10,100,19, &la->YF_ltradius, 0.0,100.0, 100, 0, "Sets the radius of the lightsource, 0 is same as pointlight");
+ }
+
+ if (la->type==LA_SPOT) {
+
+ uiDefButBitS(block, TOG, LA_HALO, B_LAMPREDRAW,"Halo", 10,50,80,19,&la->mode, 0, 0, 0, 0, "Renders spotlight with a volumetric halo");
+
+ uiBlockSetCol(block, TH_AUTO);
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUMSLI,B_LAMPREDRAW,"SpotSi ", 100,180,200,19,&la->spotsize, 1.0, 180.0, 0, 0, "Sets the angle of the spotlight beam in degrees");
+ uiDefButF(block, NUMSLI,B_LAMPREDRAW,"SpotBl ", 100,160,200,19,&la->spotblend, 0.0, 1.0, 0, 0, "Sets the softness of the spotlight edge");
+ uiBlockEndAlign(block);
+
+ if (la->mode & LA_HALO) uiDefButF(block, NUMSLI,0,"HaloInt ", 100,135,200,19,&la->haint, 0.0, 5.0, 0, 0, "Sets the intensity of the spotlight halo");
+ }
+ else if ((la->type==LA_AREA) || ((la->type==LA_LOCAL) && (la->mode & LA_SHAD_RAY))) {
+ /* area samples param also used for 'spherelight' */
+ uiBlockBeginAlign(block);
+ uiBlockSetCol(block, TH_AUTO);
+
+ uiDefButS(block, NUM,B_DIFF,"Samples:", 100,180,200,19, &la->ray_samp, 1.0, 16.0, 100, 0, "Sets the amount of samples taken extra (samp x samp)");
+
+ /* shadow sampling types not used in yafray, removed */
+ }
+ else uiDefBut(block, LABEL,0," ", 100,180,200,19,NULL, 0, 0, 0, 0, "");
+
+}
+
+static void lamp_panel_falloff(Object *ob, Lamp *la)
+{
+ uiBlock *block;
+ rctf butr;
+ short yco=PANEL_YMAX;
+ float grid= 0.0;
+
+ /* name "Preview" is abused to detect previewrender offset panel */
+ block= uiNewBlock(&curarea->uiblocks, "lamp_panel_falloff", UI_EMBOSS, UI_HELV, curarea->win);
+ uiNewPanelTabbed("Lamp", "Lamp");
+ if(uiNewPanel(curarea, block, "Falloff Curve", "Lamp", PANELX, PANELY, PANELW, PANELH)==0) return;
+
+ if(G.vd) grid= G.vd->grid;
+ if(grid<1.0) grid= 1.0;
+
+ uiSetButLock(la->id.lib!=0, ERROR_LIBDATA_MESSAGE);
+
+ BLI_init_rctf(&butr, 10.0, 310.0, 10.0, (float)yco);
+ curvemap_buttons(block, la->curfalloff, 's', B_LFALLOFFCHANGED, B_LAMPREDRAW, &butr);
+
+}
+
+static void lamp_panel_lamp(Object *ob, Lamp *la)
+{
+ uiBlock *block;
+ float grid= 0.0;
+ short xco;
+
+ block= uiNewBlock(&curarea->uiblocks, "lamp_panel_lamp", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Lamp", "Lamp", 320, 0, 318, 204)==0) return;
+
+ if(G.vd) grid= G.vd->grid;
+ if(grid<1.0) grid= 1.0;
+
+ uiSetButLock(la->id.lib!=0, ERROR_LIBDATA_MESSAGE);
+
+ uiBlockSetCol(block, TH_BUT_SETTING2);
+ xco= std_libbuttons(block, 8, 180, 0, NULL, B_LAMPBROWSE, ID_LA, 0, (ID *)la, (ID *)ob, &(G.buts->menunr), B_LAMPALONE, B_LAMPLOCAL, 0, 0, 0);
+
+ uiBlockSetCol(block, TH_AUTO);
+ uiDefButF(block, NUM,B_LAMPREDRAW,"Dist:", xco,180,300-xco,20,&la->dist, 0.01, 5000.0*grid, 100, 0, "Sets the distance value at which light intensity is half");
+
+ uiBlockBeginAlign(block);
+ uiSetButLock(la->id.lib!=0, ERROR_LIBDATA_MESSAGE);
+ if(la->type==LA_AREA) {
+ //uiDefButS(block, MENU, B_LAMPREDRAW, "Shape %t|Square %x0|Rect %x1|Cube %x2|Box %x3",
+ uiDefButS(block, MENU, B_LAMPREDRAW, "Shape %t|Square %x0|Rect %x1",
+ 10, 150, 100, 19, &la->area_shape, 0,0,0,0, "Sets area light shape");
+ if (ELEM(la->area_shape, LA_AREA_RECT, LA_AREA_BOX)){
+ uiDefButF(block, NUM,B_LAMPREDRAW,"SizeX ", 10,130,100,19, &la->area_size, 0.01, 100.0, 10, 0, "Area light size X, doesn't affect energy amount");
+ uiDefButF(block, NUM,B_LAMPREDRAW,"SizeY ", 10,110,100,19, &la->area_sizey, 0.01, 100.0, 10, 0, "Area light size Y, doesn't affect energy amount");
+ }
+ if(la->area_shape==LA_AREA_BOX)
+ uiDefButF(block, NUM,B_LAMPREDRAW,"SizeZ ", 10,90,100,19, &la->area_sizez, 0.01, 100.0, 10, 0, "Area light size Z, doesn't affect energy amount");
+ if (ELEM(la->area_shape, LA_AREA_SQUARE, LA_AREA_CUBE))
+ uiDefButF(block, NUM,B_LAMPREDRAW,"Size ", 10,130,100,19, &la->area_size, 0.01, 100.0, 10, 0, "Area light size, doesn't affect energy amount");
+ }
+ else if( ELEM(la->type, LA_LOCAL, LA_SPOT)) {
+ uiBlockSetCol(block, TH_BUT_SETTING1);
+ uiDefButS(block, MENU, B_LAMPREDRAW, "Falloff %t|Constant %x0|Inverse Linear %x1|Inverse Square %x2|Custom Curve %x3|Lin/Quad Weighted %x4|",
+ 10,150,100,19, &la->falloff_type, 0,0,0,0, "Lamp falloff - intensity decay with distance");
+ uiDefButBitS(block, TOG, LA_SPHERE, REDRAWVIEW3D,"Sphere", 10,130,100,19,&la->mode, 0, 0, 0, 0, "Sets light intensity to zero for objects beyond the distance value");
+ }
+
+ uiBlockBeginAlign(block);
+ uiBlockSetCol(block, TH_BUT_SETTING1);
+ uiDefButBitS(block, TOG, LA_LAYER, 0,"Layer", 10,70,100,19,&la->mode, 0, 0, 0, 0, "Illuminates objects in the same layer as the lamp only");
+ uiDefButBitS(block, TOG, LA_NEG, B_LAMPPRV,"Negative", 10,50,100,19,&la->mode, 0, 0, 0, 0, "Sets lamp to cast negative light");
+ uiDefButBitS(block, TOG, LA_NO_DIFF, 0,"No Diffuse", 10,30,100,19,&la->mode, 0, 0, 0, 0, "Disables diffuse shading of material illuminated by this lamp");
+ uiDefButBitS(block, TOG, LA_NO_SPEC, 0,"No Specular", 10,10,100,19,&la->mode, 0, 0, 0, 0, "Disables specular shading of material illuminated by this lamp");
+ uiBlockEndAlign(block);
+
+ uiBlockSetCol(block, TH_AUTO);
+ uiDefButF(block, NUMSLI,B_LAMPPRV,"Energy ", 120,150,180,20, &(la->energy), 0.0, 10.0, 0, 0, "Sets the intensity of the light");
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUMSLI,B_LAMPPRV,"R ", 120,120,180,20,&la->r, 0.0, 1.0, B_COLLAMP, 0, "Sets the red component of the light");
+ uiDefButF(block, NUMSLI,B_LAMPPRV,"G ", 120,100,180,20,&la->g, 0.0, 1.0, B_COLLAMP, 0, "Sets the green component of the light");
+ uiDefButF(block, NUMSLI,B_LAMPPRV,"B ", 120,80,180,20,&la->b, 0.0, 1.0, B_COLLAMP, 0, "Sets the blue component of the light");
+ uiBlockEndAlign(block);
+
+ uiDefButF(block, COL, B_LAMPPRV, "", 120,52,180,24, &la->r, 0, 0, 0, B_COLLAMP, "");
+
+ uiBlockBeginAlign(block);
+ if (ELEM(la->type, LA_LOCAL, LA_SPOT) && (la->falloff_type == LA_FALLOFF_SLIDERS)) {
+ uiDefButF(block, NUMSLI,B_LAMPPRV,"Linear ", 120,30,180,19,&la->att1, 0.0, 1.0, 0, 0, "Set the linear distance attenuatation for a quad lamp");
+ uiDefButF(block, NUMSLI,B_LAMPPRV,"Quad ", 120,10,180,19,&la->att2, 0.0, 1.0, 0, 0, "Set the quadratic distance attenuatation for a quad lamp");
+ }
+ else if(la->type==LA_AREA) {
+ if(la->k==0.0) la->k= 1.0;
+ uiDefButF(block, NUMSLI,0,"Gamma ", 120,10,180,19,&la->k, 0.001, 2.0, 100, 0, "Set the light gamma correction value");
+ }
+}
+
+
+static void lamp_panel_preview(Object *ob, Lamp *la)
+{
+ uiBlock *block;
+
+ /* name "Preview" is abused to detect previewrender offset panel */
+ block= uiNewBlock(&curarea->uiblocks, "lamp_panel_preview", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Preview", "Lamp", 0, 0, 318, 204)==0) return;
+
+ uiSetButLock(la->id.lib!=0, ERROR_LIBDATA_MESSAGE);
+
+ uiBlockSetDrawExtraFunc(block, BIF_previewdraw);
+
+ // label to force a boundbox for buttons not to be centered
+ uiDefBut(block, LABEL, 0, " ", 20,20,10,10, 0, 0, 0, 0, 0, "");
+ uiBlockBeginAlign(block);
+ uiDefButS(block, ROW,B_LAMPREDRAW,"Lamp", 200,175,80,25,&la->type,1.0,(float)LA_LOCAL, 0, 0, "Creates an omnidirectional point light source");
+ uiDefButS(block, ROW,B_LAMPREDRAW,"Area", 200,150,80,25,&la->type,1.0,(float)LA_AREA, 0, 0, "Creates a directional area light source");
+ uiDefButS(block, ROW,B_LAMPREDRAW,"Spot", 200,125,80,25,&la->type,1.0,(float)LA_SPOT, 0, 0, "Creates a directional cone light source");
+ uiDefButS(block, ROW,B_LAMPREDRAW,"Sun", 200,100,80,25,&la->type,1.0,(float)LA_SUN, 0, 0, "Creates a constant direction parallel ray light source");
+ uiDefButS(block, ROW,B_LAMPREDRAW,"Hemi", 200,75,80,25,&la->type,1.0,(float)LA_HEMI, 0, 0, "Creates a 180 degree constant light source");
+ /* yafray: extra type, photonlight */
+ if (G.scene->r.renderer==R_YAFRAY)
+ uiDefButS(block, ROW,B_LAMPREDRAW,"Photon", 200,50,80,25,&la->type,1.0,(float)LA_YF_PHOTON, 0, 0, "Creates a special caustics photon 'light', not a real lightsource, use with other lights");
+}
+
+
+/* ****************** MATERIAL ***************** */
+
+
+void do_matbuts(unsigned short event)
+{
+ static short mtexcopied=0;
+ static MTex mtexcopybuf;
+ Material *ma;
+ MTex *mtex;
+
+ /* all operations default on active material layer here */
+ /* but this also gets called for lamp and world... */
+ ma= G.buts->lockpoin;
+ if(ma && GS(ma->id.name)==ID_MA)
+ ma = editnode_get_active_material(ma);
+ else
+ ma= NULL;
+
+ switch(event) {
+ case B_MAT_YF_PRESET: {
+ switch (ma->YF_preset) {
+ case 0:
+ /* normal mode, no reflection/refraction */
+ ma->alpha = 1;
+ ma->mode &= ~(MA_RAYMIRROR+MA_RAYTRANSP+MA_ZTRA);
+ break;
+ case 1: {
+ /* clear glass */
+ ma->alpha = 0.001;
+ ma->ray_mirror = 1;
+ ma->fresnel_mir_i = 5;
+ ma->mode |= (MA_RAYMIRROR+MA_RAYTRANSP);
+ ma->mode &= ~MA_ZTRA;
+ ma->filter = 0;
+ ma->ang = 1.5;
+ break;
+ }
+ case 2: {
+ /* color glass */
+ ma->alpha = 0.001;
+ ma->ray_mirror = 1;
+ ma->fresnel_mir_i = 5;
+ ma->mode |= (MA_RAYMIRROR+MA_RAYTRANSP);
+ ma->mode &= ~MA_ZTRA;
+ ma->filter = 1;
+ ma->ang = 1.5;
+ break;
+ }
+ case 3: {
+ /* uniform reflect */
+ ma->alpha = 1;
+ ma->ray_mirror = 1;
+ ma->fresnel_mir_i = 1;
+ ma->mode |= MA_RAYMIRROR;
+ ma->mode &= ~(MA_RAYTRANSP+MA_ZTRA);
+ break;
+ }
+ case 4: {
+ /* fresnel reflect */
+ ma->alpha = 1;
+ ma->ray_mirror = 1;
+ ma->fresnel_mir_i = 5;
+ ma->mode |= MA_RAYMIRROR;
+ ma->mode &= ~(MA_RAYTRANSP+MA_ZTRA);
+ ma->ang = 3;
+ break;
+ }
+ }
+ BIF_preview_changed(ID_MA);
+ allqueue(REDRAWBUTSSHADING, 0);
+ shade_buttons_change_3d();
+ break;
+ }
+ case B_ACTCOL:
+ scrarea_queue_headredraw(curarea);
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWOOPS, 0);
+ BIF_preview_changed(ID_MA);
+ break;
+ case B_MATFROM:
+ scrarea_queue_headredraw(curarea);
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWOOPS, 0);
+ // BIF_previewdraw(); push/pop!
+ break;
+ case B_MATPRV:
+ if(ma) end_render_material(ma); /// temporal... 3d preview
+ BIF_preview_changed(ID_MA);
+ allqueue(REDRAWBUTSSHADING, 0);
+ shade_buttons_change_3d();
+ break;
+ case B_LAMPPRV:
+ BIF_preview_changed(ID_LA);
+ allqueue(REDRAWBUTSSHADING, 0);
+ break;
+ case B_WORLDPRV:
+ BIF_preview_changed(ID_WO);
+ allqueue(REDRAWBUTSSHADING, 0);
+ break;
+ case B_WORLDPRV2:
+ BIF_preview_changed(ID_WO);
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+ case B_MATHALO:
+ /* when halo is disabled, clear star flag, this is the same as MA_FACETEXTURE <blush> */
+ /* same for 'xtreme alpha' which is 'only shadow' */
+ if(ma) {
+ if((ma->mode & MA_HALO)==0) {
+ ma->mode &= ~(MA_STAR|MA_HALO_XALPHA|MA_ZINV|MA_ENV);
+ }
+ BIF_preview_changed(ID_MA);
+ allqueue(REDRAWBUTSSHADING, 0);
+ shade_buttons_change_3d();
+ }
+ break;
+ case B_TEXCLEAR:
+ mtex= ma->mtex[(int) ma->texact ];
+ if(mtex) {
+ if(mtex->tex) mtex->tex->id.us--;
+ MEM_freeN(mtex);
+ ma->mtex[ (int) ma->texact ]= 0;
+ BIF_undo_push("Unlink material texture");
+ if(ma) end_render_material(ma); /// temporal... 3d preview
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWOOPS, 0);
+ BIF_preview_changed(ID_MA);
+ }
+ break;
+ case B_MTEXCOPY:
+ if(ma && ma->mtex[(int)ma->texact] ) {
+ mtex= ma->mtex[(int)ma->texact];
+ if(mtex->tex==NULL) {
+ error("No texture available");
+ }
+ else {
+ memcpy(&mtexcopybuf, ma->mtex[(int)ma->texact], sizeof(MTex));
+ mtexcopied= 1;
+ }
+ }
+ break;
+ case B_MTEXPASTE:
+ if(ma && mtexcopied && mtexcopybuf.tex) {
+ if(ma->mtex[(int)ma->texact]==NULL )
+ ma->mtex[(int)ma->texact]= MEM_mallocN(sizeof(MTex), "mtex");
+ else if(ma->mtex[(int)ma->texact]->tex)
+ ma->mtex[(int)ma->texact]->tex->id.us--;
+
+ memcpy(ma->mtex[(int)ma->texact], &mtexcopybuf, sizeof(MTex));
+
+ id_us_plus((ID *)mtexcopybuf.tex);
+ BIF_undo_push("Paste mapping settings");
+ BIF_preview_changed(ID_MA);
+ scrarea_queue_winredraw(curarea);
+ }
+ break;
+ case B_MATZTRANSP:
+ if(ma) {
+ ma->mode &= ~MA_RAYTRANSP;
+ //BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT); /// temporal... 3d preview
+ allqueue(REDRAWBUTSSHADING, 0);
+ BIF_preview_changed(ID_MA);
+ }
+ break;
+ case B_MATRAYTRANSP:
+ if(ma) {
+ ma->mode &= ~MA_ZTRA;
+ if(ma) end_render_material(ma); /// temporal... 3d preview
+ allqueue(REDRAWBUTSSHADING, 0);
+ BIF_preview_changed(ID_MA);
+ }
+ break;
+ case B_MATCOLORBAND:
+ if(ma) {
+ if(ma->mode & MA_RAMP_COL)
+ if(ma->ramp_col==NULL) ma->ramp_col= add_colorband(0);
+ if(ma->mode & MA_RAMP_SPEC)
+ if(ma->ramp_spec==NULL) ma->ramp_spec= add_colorband(0);
+
+ if(ma) end_render_material(ma); /// temporal... 3d preview
+ allqueue(REDRAWBUTSSHADING, 0);
+ BIF_preview_changed(ID_MA);
+ shade_buttons_change_3d();
+ }
+ break;
+ case B_MAT_USENODES:
+ ma= G.buts->lockpoin; /* use base material instead */
+ if(ma) {
+ if(ma->use_nodes && ma->nodetree==NULL) {
+ node_shader_default(ma);
+ }
+ if(ma) end_render_material(ma); /// temporal... 3d preview
+ BIF_preview_changed(ID_MA);
+ allqueue(REDRAWNODE, 0);
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWIPO, 0);
+ }
+ break;
+ case B_MAT_VCOL_PAINT:
+ if(ma) {
+ ma->mode &= ~MA_VERTEXCOL;
+ BIF_preview_changed(ID_MA);
+ allqueue(REDRAWBUTSSHADING, 0);
+ }
+ break;
+ case B_MAT_VCOL_LIGHT:
+ if(ma) {
+ ma->mode &= ~MA_VERTEXCOLP;
+ BIF_preview_changed(ID_MA);
+ allqueue(REDRAWBUTSSHADING, 0);
+ }
+ break;
+
+ }
+}
+
+
+/* if from nodes, hide options that are not available */
+static void material_panel_map_to(Material *ma, int from_nodes)
+{
+ uiBlock *block;
+ MTex *mtex;
+
+ block= uiNewBlock(&curarea->uiblocks, "material_panel_map_to", UI_EMBOSS, UI_HELV, curarea->win);
+ uiNewPanelTabbed("Texture", "Material");
+ if(uiNewPanel(curarea, block, "Map To", "Material", 1600, 0, 318, 204)==0) return;
+
+ uiSetButLock(ma->id.lib!=NULL, ERROR_LIBDATA_MESSAGE);
+
+ mtex= ma->mtex[ ma->texact ];
+ if(mtex==NULL) {
+ mtex= &emptytex;
+ default_mtex(mtex);
+ }
+
+ /* TEXTURE OUTPUT */
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, MTEX_STENCIL, B_MATPRV, "Stencil", 10,125,45,19, &(mtex->texflag), 0, 0, 0, 0, "Sets the texture mapping to stencil mode");
+ uiDefButBitS(block, TOG, MTEX_NEGATIVE, B_MATPRV, "Neg", 55,125,30,19, &(mtex->texflag), 0, 0, 0, 0, "Inverts the values of the texture to reverse its effect");
+ uiDefButBitS(block, TOG,MTEX_RGBTOINT, B_MATPRV, "No RGB", 85,125,60,19, &(mtex->texflag), 0, 0, 0, 0, "Converts texture RGB values to intensity (gray) values");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, COL, B_MATPRV, "", 10,100,135,19, &(mtex->r), 0, 0, 0, B_MTEXCOL, "");
+
+ if(ma->colormodel==MA_HSV) {
+ uiBlockSetCol(block, TH_BUT_SETTING1);
+ uiDefButF(block, HSVSLI, B_MATPRV, "H ", 10,80,135,19, &(mtex->r), 0.0, 0.9999, B_MTEXCOL, 0, "");
+ uiDefButF(block, HSVSLI, B_MATPRV, "S ", 10,60,135,19, &(mtex->r), 0.0001, 1.0, B_MTEXCOL, 0, "");
+ uiDefButF(block, HSVSLI, B_MATPRV, "V ", 10,40,135,19, &(mtex->r), 0.0001, 1.0, B_MTEXCOL, 0, "");
+ uiBlockSetCol(block, TH_AUTO);
+ }
+ else {
+ uiDefButF(block, NUMSLI, B_MATPRV, "R ", 10,80,135,19, &(mtex->r), 0.0, 1.0, B_MTEXCOL, 0, "The default color for textures that don't return RGB");
+ uiDefButF(block, NUMSLI, B_MATPRV, "G ", 10,60,135,19, &(mtex->g), 0.0, 1.0, B_MTEXCOL, 0, "The default color for textures that don't return RGB");
+ uiDefButF(block, NUMSLI, B_MATPRV, "B ", 10,40,135,19, &(mtex->b), 0.0, 1.0, B_MTEXCOL, 0, "The default color for textures that don't return RGB");
+ }
+ uiBlockEndAlign(block);
+
+ uiDefButF(block, NUMSLI, B_MATPRV, "DVar ", 10,10,135,19, &(mtex->def_var), 0.0, 1.0, 0, 0, "The default value the texture uses to mix with (not RGB)");
+
+ /* MAP TO */
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, MAP_COL, B_MATPRV, "Col", 10,180,40,19, &(mtex->mapto), 0, 0, 0, 0, "Causes the texture to affect basic color of the material");
+ uiDefButBitS(block, TOG3, MAP_NORM, B_MATPRV, "Nor", 50,180,40,19, &(mtex->mapto), 0, 0, 0, 0, "Causes the texture to affect the rendered normal");
+ uiDefButBitS(block, TOG, MAP_COLSPEC, B_MATPRV, "Csp", 90,180,40,19, &(mtex->mapto), 0, 0, 0, 0, "Causes the texture to affect the specularity color");
+ uiDefButBitS(block, TOG, MAP_COLMIR, B_MATPRV, "Cmir", 130,180,50,19, &(mtex->mapto), 0, 0, 0, 0, "Causes the texture to affect the mirror color");
+ uiDefButBitS(block, TOG3, MAP_REF, B_MATPRV, "Ref", 180,180,40,19, &(mtex->mapto), 0, 0, 0, 0, "Causes the texture to affect the value of the materials reflectivity");
+ uiDefButBitS(block, TOG3, MAP_SPEC, B_MATPRV, "Spec", 220,180,50,19, &(mtex->mapto), 0, 0, 0, 0, "Causes the texture to affect the value of specularity");
+ uiDefButBitS(block, TOG3, MAP_AMB, B_MATPRV, "Amb", 270,180,40,19, &(mtex->mapto), 0, 0, 0, 0, "Causes the texture to affect the value of ambient");
+
+ uiDefButBitS(block, TOG3, MAP_HAR, B_MATPRV, "Hard", 10,160,50,19, &(mtex->mapto), 0, 0, 0, 0, "Causes the texture to affect the hardness value");
+ uiDefButBitS(block, TOG3, MAP_RAYMIRR, B_MATPRV, "RayMir", 60,160,50,19, &(mtex->mapto), 0, 0, 0, 0, "Causes the texture to affect the ray-mirror value");
+ uiDefButBitS(block, TOG3, MAP_ALPHA, B_MATPRV, "Alpha", 110,160,50,19, &(mtex->mapto), 0, 0, 0, 0, "Causes the texture to affect the alpha value");
+ uiDefButBitS(block, TOG3, MAP_EMIT, B_MATPRV, "Emit", 160,160,45,19, &(mtex->mapto), 0, 0, 0, 0, "Causes the texture to affect the emit value");
+ uiDefButBitS(block, TOG3, MAP_TRANSLU, B_MATPRV, "TransLu", 205,160,60,19, &(mtex->mapto), 0, 0, 0, 0, "Causes the texture to affect the layer blending value");
+ if(from_nodes==0)
+ uiDefButBitS(block, TOG3, MAP_DISPLACE, B_MATPRV, "Disp", 265,160,45,19, &(mtex->mapto), 0, 0, 0, 0, "Let the texture displace the surface");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, MENU, B_MATPRV, mapto_blendtype_pup(),155,125,155,19, &(mtex->blendtype), 0, 0, 0, 0, "Texture blending mode");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUMSLI, B_MATPRV, "Col ", 155,100,155,19, &(mtex->colfac), 0.0, 1.0, 0, 0, "Sets the amount the texture affects color values");
+ /* newnoise: increased range to 25, the constant offset for bumpmapping quite often needs a higher nor setting */
+ uiDefButF(block, NUMSLI, B_MATPRV, "Nor ", 155,80,155,19, &(mtex->norfac), 0.0, 25.0, 0, 0, "Sets the amount the texture affects normal values");
+ uiDefButF(block, NUMSLI, B_MATPRV, "Var ", 155,60,155,19, &(mtex->varfac), 0.0, 1.0, 0, 0, "Sets the amount the texture affects other values");
+ uiDefButF(block, NUMSLI, B_MATPRV, "Disp ", 155,40,155,19, &(mtex->dispfac), 0.0, 1.0, 0, 0, "Sets the amount the texture displaces the surface");
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, MAP_WARP, B_MATPRV, "Warp", 155,10,40,19, &(mtex->mapto), 0, 0, 0, 0, "Let the texture warp texture coordinates of next channels");
+ uiDefButF(block, NUMSLI, B_MATPRV, "fac ", 195,10,115,19, &(mtex->warpfac), 0.0, 1.0, 0, 0, "Sets the amount the texture affects texture coordinates of next channels");
+}
+
+/* autocomplete callback for buttons */
+void autocomplete_uv(char *str, void *arg_v)
+{
+ Mesh *me;
+ CustomDataLayer *layer;
+ AutoComplete *autocpl;
+ int a;
+
+ if(str[0]==0)
+ return;
+
+ autocpl= autocomplete_begin(str, 32);
+
+ /* search if str matches the beginning of name */
+ for(me= G.main->mesh.first; me; me=me->id.next)
+ for(a=0, layer= me->fdata.layers; a<me->fdata.totlayer; a++, layer++)
+ if(layer->type == CD_MTFACE)
+ autocomplete_do_name(autocpl, layer->name);
+
+ autocomplete_end(autocpl, str);
+}
+
+int verify_valid_uv_name(char *str)
+{
+ Mesh *me;
+ CustomDataLayer *layer;
+ int a;
+
+ if(str[0]==0)
+ return 1;
+
+ /* search if str matches the name */
+ for(me= G.main->mesh.first; me; me=me->id.next)
+ for(a=0, layer= me->fdata.layers; a<me->fdata.totlayer; a++, layer++)
+ if(layer->type == CD_MTFACE)
+ if(strcmp(layer->name, str)==0)
+ return 1;
+
+ return 0;
+}
+
+static void material_panel_map_input(Object *ob, Material *ma)
+{
+ uiBlock *block;
+ uiBut *but;
+ MTex *mtex;
+ int b;
+
+ block= uiNewBlock(&curarea->uiblocks, "material_panel_map_input", UI_EMBOSS, UI_HELV, curarea->win);
+ uiNewPanelTabbed("Texture", "Material");
+ if(uiNewPanel(curarea, block, "Map Input", "Material", 1280, 0, 318, 204)==0) return;
+
+ uiSetButLock(ma->id.lib!=NULL, ERROR_LIBDATA_MESSAGE);
+
+ mtex= ma->mtex[ ma->texact ];
+ if(mtex==NULL) {
+ mtex= &emptytex;
+ default_mtex(mtex);
+ }
+
+ /* TEXCO */
+ uiBlockBeginAlign(block);
+ uiDefButS(block, ROW, B_MATPRV, "Glob", 630,180,45,18, &(mtex->texco), 4.0, (float)TEXCO_GLOB, 0, 0, "Uses global coordinates for the texture coordinates");
+ uiDefButS(block, ROW, B_MATPRV, "Object", 675,180,75,18, &(mtex->texco), 4.0, (float)TEXCO_OBJECT, 0, 0, "Uses linked object's coordinates for texture coordinates");
+ if(mtex->texco == TEXCO_UV) {
+ if(!verify_valid_uv_name(mtex->uvname))
+ uiBlockSetCol(block, TH_REDALERT);
+ but=uiDefBut(block, TEX, B_MATPRV, "UV:", 750,180,158,18, mtex->uvname, 0, 31, 0, 0, "Set name of UV layer to use, default is active UV layer");
+ uiButSetCompleteFunc(but, autocomplete_uv, NULL);
+ uiBlockSetCol(block, TH_AUTO);
+ }
+ else
+ uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_MATPRV, "Ob:",750,180,158,18, &(mtex->object), "");
+
+ uiDefButS(block, ROW, B_MATPRV, "UV", 630,160,40,18, &(mtex->texco), 4.0, (float)TEXCO_UV, 0, 0, "Uses UV coordinates for texture coordinates");
+ uiDefButS(block, ROW, B_MATPRV, "Orco", 670,160,55,18, &(mtex->texco), 4.0, (float)TEXCO_ORCO, 0, 0, "Uses the original undeformed coordinates of the object");
+ if( give_parteff(ob) )
+ uiDefButS(block, ROW, B_MATPRV, "Strand", 725,160,50,18, &(mtex->texco), 4.0, (float)TEXCO_STRAND, 0, 0, "Uses normalized strand texture coordinate (1D)");
+ else
+ uiDefButS(block, ROW, B_MATPRV, "Stick", 725,160,50,18, &(mtex->texco), 4.0, (float)TEXCO_STICKY, 0, 0, "Uses mesh's sticky coordinates for the texture coordinates");
+ uiDefButS(block, ROW, B_MATPRV, "Win", 775,160,45,18, &(mtex->texco), 4.0, (float)TEXCO_WINDOW, 0, 0, "Uses screen coordinates as texture coordinates");
+ uiDefButS(block, ROW, B_MATPRV, "Nor", 820,160,44,18, &(mtex->texco), 4.0, (float)TEXCO_NORM, 0, 0, "Uses normal vector as texture coordinates");
+ uiDefButS(block, ROW, B_MATPRV, "Refl", 864,160,44,18, &(mtex->texco), 4.0, (float)TEXCO_REFL, 0, 0, "Uses reflection vector as texture coordinates");
+
+ uiDefButS(block, ROW, B_MATPRV, "Stress", 630,140,70,18, &(mtex->texco), 4.0, (float)TEXCO_STRESS, 0, 0, "Uses the difference of edge lengths compared to original coordinates of the mesh");
+ uiDefButS(block, ROW, B_MATPRV, "Tangent", 700,140,70,18, &(mtex->texco), 4.0, (float)TEXCO_TANGENT, 0, 0, "Uses the optional tangent vector as texture coordinates");
+
+ /* COORDS */
+ uiBlockBeginAlign(block);
+ uiDefButC(block, ROW, B_MATPRV, "Flat", 630,115,48,19, &(mtex->mapping), 5.0, (float)MTEX_FLAT, 0, 0, "Maps X and Y coordinates directly");
+ uiDefButC(block, ROW, B_MATPRV, "Cube", 681,115,50,19, &(mtex->mapping), 5.0, (float)MTEX_CUBE, 0, 0, "Maps using the normal vector");
+ uiDefButC(block, ROW, B_MATPRV, "Tube", 630,95,48,19, &(mtex->mapping), 5.0, (float)MTEX_TUBE, 0, 0, "Maps with Z as central axis (tube-like)");
+ uiDefButC(block, ROW, B_MATPRV, "Sphe", 681,95,50,19, &(mtex->mapping), 5.0, (float)MTEX_SPHERE, 0, 0, "Maps with Z as central axis (sphere-like)");
+
+ uiBlockBeginAlign(block);
+ for(b=0; b<3; b++) {
+ char *cp;
+ if(b==0) cp= &(mtex->projx);
+ else if(b==1) cp= &(mtex->projy);
+ else cp= &(mtex->projz);
+
+ uiDefButC(block, ROW, B_MATPRV, "", 630, 50-20*b, 24, 18, cp, 6.0+b, 0.0, 0, 0, "");
+ uiDefButC(block, ROW, B_MATPRV, "X", 656, 50-20*b, 24, 18, cp, 6.0+b, 1.0, 0, 0, "");
+ uiDefButC(block, ROW, B_MATPRV, "Y", 682, 50-20*b, 24, 18, cp, 6.0+b, 2.0, 0, 0, "");
+ uiDefButC(block, ROW, B_MATPRV, "Z", 708, 50-20*b, 24, 18, cp, 6.0+b, 3.0, 0, 0, "");
+ }
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_MATPRV, "ofsX", 778,115,130,19, mtex->ofs, -10.0, 10.0, 10, 0, "Fine tunes texture mapping X coordinate");
+ uiDefButF(block, NUM, B_MATPRV, "ofsY", 778,95,130,19, mtex->ofs+1, -10.0, 10.0, 10, 0, "Fine tunes texture mapping Y coordinate");
+ uiDefButF(block, NUM, B_MATPRV, "ofsZ", 778,75,130,19, mtex->ofs+2, -10.0, 10.0, 10, 0, "Fine tunes texture mapping Z coordinate");
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_MATPRV, "sizeX", 778,50,130,19, mtex->size, -100.0, 100.0, 10, 0, "Sets scaling for the texture's X size");
+ uiDefButF(block, NUM, B_MATPRV, "sizeY", 778,30,130,19, mtex->size+1, -100.0, 100.0, 10, 0, "Sets scaling for the texture's Y size");
+ uiDefButF(block, NUM, B_MATPRV, "sizeZ", 778,10,130,19, mtex->size+2, -100.0, 100.0, 10, 0, "Sets scaling for the texture's Z size");
+ uiBlockEndAlign(block);
+
+}
+
+
+static void material_panel_texture(Material *ma)
+{
+ uiBlock *block;
+ MTex *mtex;
+ ID *id;
+ int loos;
+ int a;
+ char str[64], *strp;
+
+ block= uiNewBlock(&curarea->uiblocks, "material_panel_texture", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Texture", "Material", 960, 0, 318, 204)==0) return;
+ uiClearButLock();
+
+ /* TEX CHANNELS */
+ uiBlockSetCol(block, TH_BUT_NEUTRAL);
+
+ uiBlockBeginAlign(block);
+ for(a= 0; a<MAX_MTEX; a++) {
+ mtex= ma->mtex[a];
+ if(mtex && mtex->tex) splitIDname(mtex->tex->id.name+2, str, &loos);
+ else strcpy(str, "");
+ str[10]= 0;
+ uiDefButC(block, ROW, B_TEXCHANNEL, str, 10, 180-18*a, 70, 20, &(ma->texact), 3.0, (float)a, 0, 0, "");
+ }
+ uiBlockEndAlign(block);
+
+ uiSetButLock(ma->id.lib!=NULL, ERROR_LIBDATA_MESSAGE);
+
+ /* SEPTEX */
+ uiBlockSetCol(block, TH_AUTO);
+
+ for(a= 0; a<MAX_MTEX; a++) {
+ mtex= ma->mtex[a];
+ if(mtex && mtex->tex) {
+ uiDefIconButBitS(block, ICONTOGN, 1<<a, B_MATPRV, ICON_CHECKBOX_HLT-1, -20, 180-18*a, 28, 20, &ma->septex, 0.0, 0.0, 0, 0, "Click to disable or enable this texture channel");
+ }
+ }
+ uiBlockBeginAlign(block);
+ uiDefIconBut(block, BUT, B_MTEXCOPY, ICON_COPYUP, 100,180,23,21, 0, 0, 0, 0, 0, "Copies the mapping settings to the buffer");
+ uiDefIconBut(block, BUT, B_MTEXPASTE, ICON_PASTEUP, 125,180,23,21, 0, 0, 0, 0, 0, "Pastes the mapping settings from the buffer");
+ uiBlockEndAlign(block);
+ uiBlockSetCol(block, TH_AUTO);
+
+ mtex= ma->mtex[ ma->texact ];
+ if(mtex==NULL) {
+ mtex= &emptytex;
+ default_mtex(mtex);
+ }
+
+ /* TEXTUREBLOK SELECT */
+ uiBlockSetCol(block, TH_BUT_SETTING2);
+ if(G.main->tex.first==NULL)
+ id= NULL;
+ else
+ id= (ID*) mtex->tex;
+ IDnames_to_pupstring(&strp, NULL, "ADD NEW %x32767", &(G.main->tex), id, &(G.buts->texnr));
+ uiDefButS(block, MENU, B_EXTEXBROWSE, strp, 100,130,20,20, &(G.buts->texnr), 0, 0, 0, 0, "Selects an existing texture or creates new");
+ MEM_freeN(strp);
+
+ if(id) {
+ uiDefBut(block, TEX, B_IDNAME, "TE:", 100,150,163,20, id->name+2, 0.0, 21.0, 0, 0, "Displays name of the texture block: click to change");
+ sprintf(str, "%d", id->us);
+ uiDefBut(block, BUT, 0, str, 196,130,21,20, 0, 0, 0, 0, 0, "Displays number of users of texture");
+ uiDefIconBut(block, BUT, B_AUTOTEXNAME, ICON_AUTO, 241,130,21,20, 0, 0, 0, 0, 0, "Auto-assigns name to texture");
+ if(id->lib) {
+ if(ma->id.lib) uiDefIconBut(block, BUT, 0, ICON_DATALIB, 219,130,21,20, 0, 0, 0, 0, 0, "");
+ else uiDefIconBut(block, BUT, 0, ICON_PARLIB, 219,130,21,20, 0, 0, 0, 0, 0, "");
+ }
+ uiBlockSetCol(block, TH_AUTO);
+ uiDefBut(block, BUT, B_TEXCLEAR, "Clear", 122, 130, 72, 20, 0, 0, 0, 0, 0, "Erases link to texture");
+
+ }
+ else
+ uiDefButS(block, TOG, B_EXTEXBROWSE, "Add New" ,100, 150, 163, 20, &(G.buts->texnr), -1.0, 32767.0, 0, 0, "Adds a new texture datablock");
+
+ // force no centering
+ uiDefBut(block, LABEL, 0, " ", 250, 10, 25, 20, 0, 0, 0, 0, 0, "");
+
+ uiBlockSetCol(block, TH_AUTO);
+}
+
+static void material_panel_tramir(Material *ma)
+{
+ uiBlock *block;
+ short yco=PANEL_YMAX;
+
+ block= uiNewBlock(&curarea->uiblocks, "material_panel_tramir", UI_EMBOSS, UI_HELV, curarea->win);
+ uiNewPanelTabbed("Shaders", "Material");
+ if(uiNewPanel(curarea, block, "Mirror Transp", "Material", PANELX, PANELY, PANELW, PANELH+80)==0) return;
+
+ uiSetButLock(ma->id.lib!=NULL, ERROR_LIBDATA_MESSAGE);
+
+ uiDefButBitI(block, TOG, MA_RAYMIRROR, B_MATPRV, "Ray Mirror",
+ X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->mode), 0, 0, 0, 0, "Enables raytracing for mirror reflection rendering");
+
+ yco -= YSPACE;
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUMSLI, B_MATPRV, "RayMir: ",
+ X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->ray_mirror), 0.0, 1.0, 100, 2, "Sets the amount mirror reflection for raytrace");
+ uiDefButF(block, NUMSLI, B_MATPRV, "Fresnel: ",
+ X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->fresnel_mir), 0.0, 5.0, 10, 2, "Power of Fresnel for mirror reflection");
+ uiDefButF(block, NUMSLI, B_MATPRV, "Fac: ",
+ X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->fresnel_mir_i), 1.0, 5.0, 10, 2, "Blending factor for Fresnel");
+ uiBlockEndAlign(block);
+
+ yco -= YSPACE;
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUMSLI, B_MATPRV, "Gloss: ",
+ X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->gloss_mir), 0.0, 1.0, 100, 0, "The shininess of the reflection. Values < 1.0 give diffuse, blurry reflections ");
+ uiDefButF(block, NUMSLI, B_MATPRV, "Aniso: ",
+ X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->aniso_gloss_mir), 0.0, 1.0, 100, 0, "The shape of the reflection, from 0. (circular) to 1.0 (fully stretched along the tangent)");
+ uiDefButS(block, NUM, B_MATPRV, "Samples:",
+ X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->samp_gloss_mir), 1.0, 1024.0, 100, 0, "Number of cone samples averaged for blurry reflections");
+ uiDefButF(block, NUM, B_MATPRV, "Thresh: ",
+ X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->adapt_thresh_mir), 0.0, 1.0, 100, 0, "Threshold for adaptive sampling. If a sample contributes less than this amount (as a percentage), sampling is stopped");
+ uiBlockEndAlign(block);
+
+ yco -= YSPACE;
+ uiDefButS(block, NUM, B_MATPRV, "Depth:",
+ X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->ray_depth), 0.0, 10.0, 100, 0, "Maximum allowed number of light inter-reflections");
+
+ yco -= YSPACE;
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_MATPRV, "Max Dist:",
+ X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->dist_mir), 0.0, 100.0, 100, 0, "Maximum distance of reflected rays. Reflections further than this range fade to sky color");
+ uiDefButS(block, MENU, B_MATPRV, "Ray end fade-out: %t|Fade to Sky Color %x0|Fade to Material Color %x1",
+ X2CLM1, yco-=BUTH, BUTW2, BUTH, &(ma->fadeto_mir), 0, 0, 0, 0, "The color that rays with no intersection within the Max Distance take. Material color can be best for indoor scenes, sky color for outdoor.");
+ uiBlockEndAlign(block);
+
+ yco=PANEL_YMAX;
+
+ uiDefButBitI(block, TOG, MA_RAYTRANSP, B_MATRAYTRANSP,"Ray Transp",
+ X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->mode), 0, 0, 0, 0, "Enables raytracing for transparent refraction rendering");
+
+ yco -= YSPACE;
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUMSLI, B_MATPRV, "IOR: ",
+ X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->ang), 1.0, 3.0, 100, 2, "Sets angular index of refraction for raytraced refraction");
+ uiDefButF(block, NUMSLI, B_MATPRV, "Fresnel: ",
+ X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->fresnel_tra), 0.0, 5.0, 10, 2, "Power of Fresnel for mirror reflection");
+ uiDefButF(block, NUMSLI, B_MATPRV, "Fac: ",
+ X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->fresnel_tra_i), 1.0, 5.0, 10, 2, "Blending factor for Fresnel");
+ uiBlockEndAlign(block);
+
+ yco -= YSPACE;
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUMSLI, B_MATPRV, "Gloss: ",
+ X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->gloss_tra), 0.0, 1.0, 100, 0, "The clarity of the refraction. Values < 1.0 give diffuse, blurry reflections ");
+ uiDefButS(block, NUM, B_MATPRV, "Samples:",
+ X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->samp_gloss_tra), 0.0, 1024.0, 100, 0, "Number of cone samples averaged for blurry refractions");
+ uiDefButF(block, NUM, B_MATPRV, "Thresh: ",
+ X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->adapt_thresh_tra), 0.0, 1.0, 100, 0, "Threshold for adaptive sampling. If a sample contributes less than this amount (as a percentage), sampling is stopped");
+ uiBlockEndAlign(block);
+
+ yco -= YSPACE;
+
+ uiDefButS(block, NUM, B_MATPRV, "Depth:",
+ X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->ray_depth_tra), 0.0, 10.0, 100, 0, "Maximum allowed number of light inter-refractions");
+
+ yco -= YSPACE;
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_MATPRV, "Filter:",
+ X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->filter), 0.0, 1.0, 10, 0, "Amount to blend in the material's diffuse color in raytraced transparency (simulating absorption)");
+ uiDefButF(block, NUMSLI, B_MATPRV, "Limit: ",
+ X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->tx_limit), 0.0, 100.0, 10, 2, "Maximum depth for light to travel through the transparent material before becoming fully filtered (0.0 is disabled)");
+ uiDefButF(block, NUMSLI, B_MATPRV, "Falloff: ",
+ X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->tx_falloff), 0.1, 10.0, 10, 2, "Falloff power for transmissivity filter effect (1.0 is linear)");
+ uiBlockEndAlign(block);
+
+ yco -= YSPACE;
+
+ uiDefButF(block, NUMSLI, B_MATPRV, "SpecTra: ",
+ X2CLM2, yco-=BUTH, BUTW2, BUTH, &(ma->spectra), 0.0, 1.0, 0, 0, "Makes specular areas opaque on transparent materials");
+}
+
+/* yafray: adapted version of Blender's tramir panel.
+ * Only removed the buttons not needed, so only the ones that are important for yafray are left.
+ * Also re-arranged buttons for more room for extra parameters.
+ * With the exception of the material preset menu and the new parameters,
+ * most of blender's parameters are re-used without interfering with them.
+ */
+static void material_panel_tramir_yafray(Material *ma)
+{
+ uiBlock *block;
+ char *mstr = "Material presets %t|No Reflect/Transmit %x0|Clear Glass %x1|Color Glass %x2|Uniform Reflect %x3|Fresnel Reflect %x4";
+
+ /* better to use same name as original panel */
+ block= uiNewBlock(&curarea->uiblocks, "material_panel_tramir", UI_EMBOSS, UI_HELV, curarea->win);
+ uiNewPanelTabbed("Shaders", "Material");
+ if(uiNewPanel(curarea, block, "Mirror Transp", "Material", 640, 0, 318, 204)==0) return;
+
+ uiSetButLock(ma->id.lib!=NULL, ERROR_LIBDATA_MESSAGE);
+
+ /* material preset menu */
+ uiDefBut(block, LABEL, 0, "Mat.Preset", 20, 182, 100, 20, 0, 0.0, 0.0, 0, 0, "");
+ uiDefButI(block, MENU, B_MAT_YF_PRESET, mstr, 110, 182, 200, 20, &ma->YF_preset, 0.0, 0.0, 0, 0, "Basic material presets to start with");
+
+ uiDefButBitI(block, TOG, MA_RAYMIRROR, B_MATPRV,"Ray Mirror", 10,160,100,20, &(ma->mode), 0, 0, 0, 0, "Enables raytracing for mirror reflection rendering");
+ uiDefButBitI(block, TOG, MA_RAYTRANSP, B_MATRAYTRANSP,"Ray Transp", 110,160,100,20, &(ma->mode), 0, 0, 0, 0, "Enables raytracing for transparency rendering");
+ uiDefButBitI(block, TOG, MA_ZTRA, B_MATZTRANSP,"ZTransp", 210,160,100,20, &(ma->mode), 0, 0, 0, 0, "Use for objects with alphamap textures");
+
+ uiDefButF(block, NUMSLI, B_MATPRV, "rayMir ", 10,140,150,20, &(ma->ray_mirror), 0.0, 1.0, 100, 2, "Sets the amount mirror reflection for raytrace");
+ uiDefButF(block, NUMSLI, B_MATPRV, "frsOfs ", 160,140,150,20, &(ma->fresnel_mir_i), 1.0, 5.0, 10, 2, "Fresnel offset, 1 is uniform mirror, 5 is fresnel mirror (IOR>1)");
+
+ /* ior has extended range up to 30, for use with total fresnel reflection */
+ uiDefButF(block, NUMSLI, B_MATPRV, "IOR ", 10,115,150,20, &(ma->ang), 1.0, 30.0, 100, 2, "Sets the angular index of refraction for raytrace");
+
+ // parameters only used in ray_transp mode
+ if(ma->mode & MA_RAYTRANSP) {
+ // Filter
+ uiDefButF(block, NUM, B_MATPRV, "Filt:", 160,115,150,20, &(ma->filter), 0.0, 1.0, 10, 0, "Amount of filtering for transparent raytrace");
+
+ /* absorption color */
+ uiDefBut(block, LABEL, 0, "Absorption Color", 10, 98, 150, 18, 0, 0.0, 0.0, 0, 0, "");
+ uiDefButF(block, COL, B_MATPRV, "", 10, 38, 30, 58, &ma->YF_ar, 0, 0, 0, B_MATCOL, "transmit absorption color, white is no absorption");
+ uiDefButF(block, NUMSLI, B_MATPRV, "aR ", 40, 78, 120, 18, &ma->YF_ar, 1e-7f, 1.0, B_MATCOL, 0, "");
+ uiDefButF(block, NUMSLI, B_MATPRV, "aG ", 40, 58, 120, 18, &ma->YF_ag, 1e-7f, 1.0, B_MATCOL, 0, "");
+ uiDefButF(block, NUMSLI, B_MATPRV, "aB ", 40, 38, 120, 18, &ma->YF_ab, 1e-7f, 1.0, B_MATCOL, 0, "");
+ uiDefButF(block, NUM, B_MATPRV, "Ds", 10, 18, 150, 18, &ma->YF_dscale, 1e-7f, 100.0, 10.0, 0, "absorption distance scale, 1 is one blender (world) unit of distance");
+
+ /* disperions parameters */
+ uiDefBut(block, LABEL, 0, "Dispersion", 160, 98, 150, 18, 0, 0.0, 0.0, 0, 0, "");
+ uiDefButF(block, NUM, B_MATPRV, "Pwr ", 160, 78, 150, 18, &ma->YF_dpwr, 0.0, 1.0, 0.25, 0, "Dispersion power, the higher, the more dispersion, 0 is no dispersion");
+ uiDefButI(block, NUM, B_MATPRV, "Samples ", 160, 58, 150, 18, &ma->YF_dsmp, 1.0, 100.0, 0, 0, "Dispersion samples, minimum at least 10, unless using jitter ");
+ uiDefButBitI(block, TOG, 1, B_MATPRV, "Jitter", 160, 38, 150, 18, &ma->YF_djit, 0.0, 1.0, 0, 0, "Enable jittering of wavelenghts, adds noise");
+ }
+
+}
+
+static void material_sss_preset_cb(void *material_v, void *unused_v)
+{
+ static const float presets[11][7] = {
+ {0.909578, 0.905931, 0.665691, 6.961082, 6.400181, 1.895899, 1.300000},
+ {0.429632, 0.210025, 0.167767, 11.605177, 3.883766, 1.754386, 1.300000},
+ {0.439300, 0.216000, 0.141027, 9.435642, 3.347647, 1.790287, 1.300000},
+ {0.986552, 0.942637, 0.827285, 15.027623, 4.663968, 2.541380, 1.300000},
+ {0.221636, 0.007505, 0.002154, 4.761743, 0.574827, 0.394116, 1.300000},
+ {0.925008, 0.905025, 0.884275, 8.509412, 5.566180, 3.951266, 1.500000},
+ {0.855344, 0.740311, 0.291994, 14.266395, 7.227615, 2.036157, 1.300000},
+ {0.889319, 0.888034, 0.795811, 18.424364, 10.443473, 3.501882, 1.300000},
+ {0.573652, 0.312750, 0.174289, 3.673294, 1.366534, 0.682693, 1.300000},
+ {0.748679, 0.570766, 0.467133, 4.821475, 1.693699, 1.089971, 1.300000},
+ {0.947235, 0.931028, 0.851872, 10.898815, 6.575351, 2.508417, 1.300000}};
+
+ Material *ma= (Material*)material_v;
+
+ if(ma->sss_preset==0) return;
+
+ ma->sss_col[0]= presets[ma->sss_preset][0];
+ ma->sss_col[1]= presets[ma->sss_preset][1];
+ ma->sss_col[2]= presets[ma->sss_preset][2];
+ ma->sss_radius[0]= presets[ma->sss_preset][3];
+ ma->sss_radius[1]= presets[ma->sss_preset][4];
+ ma->sss_radius[2]= presets[ma->sss_preset][5];
+ ma->sss_ior= presets[ma->sss_preset][6];
+}
+
+static void material_sss_custom_set_cb(void *material_v, void *unused_v)
+{
+ Material *ma= (Material*)material_v;
+
+ ma->sss_preset= 0;
+ allqueue(REDRAWNODE, 0);
+}
+
+static void material_panel_sss(Material *ma)
+{
+ uiBlock *block;
+ uiBut *bt;
+
+ block= uiNewBlock(&curarea->uiblocks, "material_panel_sss", UI_EMBOSS, UI_HELV, curarea->win);
+ uiNewPanelTabbed("Mirror Transp", "Material");
+ if(uiNewPanel(curarea, block, "SSS", "Material", 640, 0, 318, 204)==0) return;
+
+ uiSetButLock(ma->id.lib!=NULL, ERROR_LIBDATA_MESSAGE);
+
+ uiDefButBitS(block, TOG, MA_DIFF_SSS, B_MATPRV,"Subsurface Scattering",10,180,180,20, &(ma->sss_flag), 0, 0, 0, 0, "Enables diffuse subsurface scattering");
+
+ bt=uiDefButS(block, MENU, B_MATPRV, "Apple %x1|Chicken %x2|Cream %x3|Ketchup %x4|Marble %x5|Potato %x6|Skim Milk %x7|Skin 1 %x8|Skin 2 %x9|Whole Milk %x10|Custom %x0",
+ 200,180,110,20, &ma->sss_preset, 0, 0, 0, 0, "");
+ uiButSetFunc(bt, material_sss_preset_cb, ma, NULL);
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_MATPRV, "Scale:", 10,150,145,20,
+ &ma->sss_scale, 0.001, 1000, 1, 3, "Object scale");
+ bt=uiDefButF(block, NUM, B_MATPRV, "Radius R", 10,130,145,20,
+ &ma->sss_radius[0], 0.0001, 10000, 1, 3,
+ "Mean red scattering path length");
+ uiButSetFunc(bt, material_sss_custom_set_cb, ma, NULL);
+ bt=uiDefButF(block, NUM, B_MATPRV, "Radius G", 10,110,145,20,
+ &ma->sss_radius[1], 0.0001, 10000, 1, 3,
+ "Mean green scattering path length");
+ uiButSetFunc(bt, material_sss_custom_set_cb, ma, NULL);
+ bt=uiDefButF(block, NUM, B_MATPRV, "Radius B", 10,90,145,20,
+ &ma->sss_radius[2], 0.0001, 10000, 1, 3,
+ "Mean blue scattering path length");
+ uiButSetFunc(bt, material_sss_custom_set_cb, ma, NULL);
+ uiBlockEndAlign(block);
+
+ bt=uiDefButF(block, NUM, B_MATPRV, "IOR:", 10,60,145,20,
+ &ma->sss_ior, 0.1, 2, 1, 3, "Index of refraction (higher values are denser)");
+ uiButSetFunc(bt, material_sss_custom_set_cb, ma, NULL);
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_MATPRV, "Error:", 10,30,145,20,
+ &ma->sss_error, 0.0001, 10, 1, 3, "Error tolerance (low values are slower and higher quality)");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ bt=uiDefButF(block, COL, B_MATPRV, "", 165,150,145,20,
+ &ma->sss_col[0], 0.0, 1.0, 0, 0,
+ "Scattering color");
+ uiButSetFunc(bt, material_sss_custom_set_cb, ma, NULL);
+ uiDefButF(block, NUMSLI, B_MATPRV, "Col ", 165,130,145,20,
+ &ma->sss_colfac, 0.0, 1.0, 0, 0,
+ "Blend factor for SSS colors");
+ uiDefButF(block, NUMSLI, B_MATPRV, "Tex ", 165,110,145,20,
+ &ma->sss_texfac, 0.0, 1.0, 0, 0,
+ "Texture scattering factor");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUMSLI, B_MATPRV, "Front ", 165,80,145,20,
+ &ma->sss_front, 0.0, 2.0, 0, 0,
+ "Front scattering weight");
+ uiDefButF(block, NUMSLI, B_MATPRV, "Back ", 165,60,145,20,
+ &ma->sss_back, 0.0, 10.0, 0, 0,
+ "Back scattering weight");
+ uiBlockEndAlign(block);
+}
+
+static void material_panel_shading(Material *ma)
+{
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "material_panel_shading", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Shaders", "Material", 640, 0, 318, 204)==0) return;
+
+ uiSetButLock(ma->id.lib!=NULL, ERROR_LIBDATA_MESSAGE);
+
+ if(ma->mode & MA_HALO) {
+ uiDefButF(block, NUM, B_MATPRV, "HaloSize: ", 10,155,190,18, &(ma->hasize), 0.0, 100.0, 10, 3, "Sets the dimension of the halo");
+ uiDefButS(block, NUMSLI, B_MATPRV, "Hard ", 10,135,190,18, &(ma->har), 1.0, 127.0, 0, 0, "Sets the hardness of the halo");
+ uiDefButF(block, NUMSLI, B_MATPRV, "Add ", 10,115,190,18, &(ma->add), 0.0, 1.0, 0, 0, "Sets the strength of the add effect");
+
+ uiDefButS(block, NUM, B_MATPRV, "Rings: ", 10,90,90,18, &(ma->ringc), 0.0, 24.0, 0, 0, "Sets the number of rings rendered over the halo");
+ uiDefButS(block, NUM, B_MATPRV, "Lines: ", 100,90,100,18, &(ma->linec), 0.0, 250.0, 0, 0, "Sets the number of star shaped lines rendered over the halo");
+ uiDefButS(block, NUM, B_MATPRV, "Star: ", 10,70,90,18, &(ma->starc), 3.0, 50.0, 0, 0, "Sets the number of points on the star shaped halo");
+ uiDefButC(block, NUM, B_MATPRV, "Seed: ", 100,70,100,18, &(ma->seed1), 0.0, 255.0, 0, 0, "Randomizes ring dimension and line location");
+ if(ma->mode & MA_HALO_FLARE) {
+ uiDefButF(block, NUM, B_MATPRV, "FlareSize: ", 10,50,95,18, &(ma->flaresize), 0.1, 25.0, 10, 3, "Sets the factor by which the flare is larger than the halo");
+ uiDefButF(block, NUM, B_MATPRV, "Sub Size: ", 100,50,100,18, &(ma->subsize), 0.1, 25.0, 10, 3, "Sets the dimension of the subflares, dots and circles");
+ uiDefButF(block, NUMSLI, B_MATPRV, "Boost: ", 10,30,190,18, &(ma->flareboost), 0.1, 10.0, 10, 3, "Gives the flare extra strength");
+ uiDefButC(block, NUM, B_MATPRV, "Fl.seed: ", 10,10,90,18, &(ma->seed2), 0.0, 255.0, 0, 0, "Specifies an offset in the flare seed table");
+ uiDefButS(block, NUM, B_MATPRV, "Flares: ", 100,10,100,18, &(ma->flarec), 1.0, 32.0, 0, 0, "Sets the number of subflares");
+ }
+ uiBlockSetCol(block, TH_BUT_SETTING1);
+
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOG, MA_HALO_FLARE, B_MATPRV, "Flare",245,142,65,28, &(ma->mode), 0, 0, 0, 0, "Renders halo as a lensflare");
+ uiDefButBitI(block, TOG, MA_HALO_RINGS, B_MATPRV, "Rings", 245,123,65, 18, &(ma->mode), 0, 0, 0, 0, "Renders rings over halo");
+ uiDefButBitI(block, TOG, MA_HALO_LINES, B_MATPRV, "Lines", 245,104,65, 18, &(ma->mode), 0, 0, 0, 0, "Renders star shaped lines over halo");
+ uiDefButBitI(block, TOG, MA_STAR, B_MATPRV, "Star", 245,85,65, 18, &(ma->mode), 0, 0, 0, 0, "Renders halo as a star");
+ uiDefButBitI(block, TOG, MA_HALOTEX, B_MATPRV, "HaloTex", 245,66,65, 18, &(ma->mode), 0, 0, 0, 0, "Gives halo a texture");
+ uiDefButBitI(block, TOG, MA_HALOPUNO, B_MATPRV, "HaloPuno", 245,47,65, 18, &(ma->mode), 0, 0, 0, 0, "Uses the vertex normal to specify the dimension of the halo");
+ uiDefButBitI(block, TOG, MA_HALO_XALPHA, B_MATPRV, "X Alpha", 245,28,65, 18, &(ma->mode), 0, 0, 0, 0, "Uses extreme alpha");
+ uiDefButBitI(block, TOG, MA_HALO_SHADE, B_MATPRV, "Shaded", 245,9,65, 18, &(ma->mode), 0, 0, 0, 0, "Lets halo receive light and shadows");
+ uiBlockEndAlign(block);
+ }
+ else {
+ char *str1= "Diffuse Shader%t|Lambert %x0|Oren-Nayar %x1|Toon %x2|Minnaert %x3|Fresnel %x4";
+ char *str2= "Specular Shader%t|CookTorr %x0|Phong %x1|Blinn %x2|Toon %x3|WardIso %x4";
+
+ /* diff shader buttons */
+ uiDefButS(block, MENU, B_MATPRV, str1, 9, 180,78,19, &(ma->diff_shader), 0.0, 0.0, 0, 0, "Creates a diffuse shader");
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUMSLI, B_MATPRV, "Ref ", 90,180,150,19, &(ma->ref), 0.0, 1.0, 0, 0, "Sets the amount of reflection");
+ if(ma->diff_shader==MA_DIFF_ORENNAYAR)
+ uiDefButF(block, NUMSLI, B_MATPRV, "Rough:",90,160, 150,19, &(ma->roughness), 0.0, 3.14, 0, 0, "Sets Oren Nayar Roughness");
+ else if(ma->diff_shader==MA_DIFF_TOON) {
+ uiDefButF(block, NUMSLI, B_MATPRV, "Size:", 90, 160,150,19, &(ma->param[0]), 0.0, 3.14, 0, 0, "Sets size of diffuse toon area");
+ uiDefButF(block, NUMSLI, B_MATPRV, "Smooth:",90,140,150,19, &(ma->param[1]), 0.0, 1.0, 0, 0, "Sets smoothness of diffuse toon area");
+ }
+ else if(ma->diff_shader==MA_DIFF_MINNAERT)
+ uiDefButF(block, NUMSLI, B_MATPRV, "Dark:",90,160, 150,19, &(ma->darkness), 0.0, 2.0, 0, 0, "Sets Minnaert darkness");
+ else if(ma->diff_shader==MA_DIFF_FRESNEL) {
+ uiDefButF(block, NUMSLI, B_MATPRV, "Fresnel:", 90, 160,150,19, &(ma->param[1]), 0.0, 5.0, 0, 0, "Power of Fresnel");
+ uiDefButF(block, NUMSLI, B_MATPRV, "Fac:",90,140,150,19, &(ma->param[0]), 1.0, 5.0, 0, 0, "Blending factor");
+ }
+ uiBlockEndAlign(block);
+
+ /* spec shader buttons */
+ uiDefButS(block, MENU, B_MATPRV, str2, 9,120,77,19, &(ma->spec_shader), 0.0, 0.0, 0, 0, "Creates a specular shader");
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUMSLI, B_MATPRV, "Spec ", 90,120,150,19, &(ma->spec), 0.0, 2.0, 0, 0, "Sets the degree of specularity");
+ if ELEM3(ma->spec_shader, MA_SPEC_COOKTORR, MA_SPEC_PHONG, MA_SPEC_BLINN) {
+ uiDefButS(block, NUMSLI, B_MATPRV, "Hard:", 90, 100, 150,19, &(ma->har), 1.0, 511, 0, 0, "Sets the hardness of the specularity");
+ }
+ if(ma->spec_shader==MA_SPEC_BLINN)
+ uiDefButF(block, NUMSLI, B_MATPRV, "Refr:", 90, 80,150,19, &(ma->refrac), 1.0, 10.0, 0, 0, "Sets the material's Index of Refraction");
+ if(ma->spec_shader==MA_SPEC_TOON) {
+ uiDefButF(block, NUMSLI, B_MATPRV, "Size:", 90, 100,150,19, &(ma->param[2]), 0.0, 1.53, 0, 0, "Sets the size of specular toon area");
+ uiDefButF(block, NUMSLI, B_MATPRV, "Smooth:",90, 80,150,19, &(ma->param[3]), 0.0, 1.0, 0, 0, "Sets the smoothness of specular toon area");
+ }
+ if(ma->spec_shader==MA_SPEC_WARDISO)
+ uiDefButF(block, NUMSLI, B_MATPRV, "rms:", 90, 100,150,19, &(ma->rms), 0.0, 0.4, 0, 0, "Sets the standard deviation of surface slope");
+ /* default shading variables */
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUMSLI, B_MATPRV, "Tralu ", 9,30,150,19, &(ma->translucency), 0.0, 1.0, 100, 2, "Translucency, amount of diffuse shading of the back side");
+ uiDefButF(block, NUMSLI, B_MATPRV, "SBias ", 159,30,151,19, &(ma->sbias), 0.0, 0.25, 10, 2, "Shadow bias, to prevent terminator problems on shadow boundary");
+ uiDefButF(block, NUMSLI, B_MATPRV, "Amb ", 9,10,150,19, &(ma->amb), 0.0, 1.0, 0, 0, "Sets the amount of global ambient color the material receives");
+ uiDefButF(block, NUMSLI, B_MATPRV, "Emit ", 159,10,151,19, &(ma->emit), 0.0, 2.0, 0, 0, "Sets the amount of light the material emits");
+ uiBlockEndAlign(block);
+
+ uiBlockSetCol(block, TH_BUT_SETTING1);
+ uiDefButBitI(block, TOG, MA_TANGENT_V, B_MATPRV, "Tangent V", 245,180,65,19, &(ma->mode), 0, 0, 0, 0, "Use the tangent vector in V direction for shading");
+
+ /* qdn: normalmap tangents separated from shading */
+ uiDefButBitI(block, TOG, MA_NORMAP_TANG, B_MATPRV, "NMap TS", 245,160,65,19, &(ma->mode), 0, 0, 0, 0, "Enable Tangent Space normal mapping");
+
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOG, MA_SHADOW, B_MATPRV, "Shadow", 245,140,65,19, &(ma->mode), 0, 0, 0, 0, "Makes material receive shadows");
+ uiDefButBitI(block, TOG, MA_SHADOW_TRA, B_MATPRV, "TraShadow", 245,120,65,19, &(ma->mode), 0, 0, 0, 0, "Receives transparent shadows based at material color and alpha");
+ uiDefButBitI(block, TOG, MA_ONLYSHADOW, B_MATPRV, "OnlyShad", 245,100,65,20, &(ma->mode), 0, 0, 0, 0, "Renders shadows on material as Alpha value");
+ uiDefButBitI(block, TOG, MA_RAYBIAS, B_MATPRV, "Bias", 245,80,65,19, &(ma->mode), 0, 0, 0, 0, "Prevents ray traced shadow errors with phong interpolated normals (terminator problem)");
+
+ uiBlockBeginAlign(block);
+ uiDefIDPoinBut(block, test_grouppoin_but, ID_GR, B_MATPRV, "GR:", 9, 55, 150, 19, &ma->group, "Limit Lighting to Lamps in this Group");
+ uiDefButBitI(block, TOG, MA_GROUP_NOLAY, B_MATPRV, "Exclusive", 159,55, 85,20, &(ma->mode), 0, 0, 0, 0, "The material exclusively uses Lamps in this Group");
+ }
+}
+
+static void material_panel_ramps(Material *ma)
+{
+ uiBlock *block;
+ ColorBand *coba;
+ float *facp;
+ char *inputc, *methodc;
+
+ block= uiNewBlock(&curarea->uiblocks, "material_panel_ramps", UI_EMBOSS, UI_HELV, curarea->win);
+ uiNewPanelTabbed("Material", "Material");
+ if(uiNewPanel(curarea, block, "Ramps", "Material", 640, 0, 318, 204)==0) return;
+
+ uiSetButLock(ma->id.lib!=NULL, ERROR_LIBDATA_MESSAGE);
+
+ uiBlockBeginAlign(block);
+ uiBlockSetCol(block, TH_BUT_SETTING1);
+ uiDefButS(block, ROW, B_REDR, "Show Col Ramp",10,180,150,20, &ma->ramp_show, 0, 0, 0, 0, "Show ramp buttons for material diffuse color");
+ uiDefButS(block, ROW, B_REDR, "Show Spec Ramp",160,180,150,20, &ma->ramp_show, 0, 1, 0, 0, "Show ramp buttons for material specular color");
+ uiBlockSetCol(block, TH_AUTO);
+
+ /* COLORBAND */
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOG, ma->ramp_show?MA_RAMP_SPEC:MA_RAMP_COL, B_MATCOLORBAND, "Colorband",10,145,80,20, &ma->mode, 0, 0, 0, 0, "Toggles colorband ramp operations");
+
+ if(ma->mode & (ma->ramp_show?MA_RAMP_SPEC:MA_RAMP_COL)) {
+ if(ma->ramp_show==0) {
+ coba= ma->ramp_col;
+ inputc= &ma->rampin_col;
+ methodc= &ma->rampblend_col;
+ facp= &ma->rampfac_col;
+ }
+ else {
+ coba= ma->ramp_spec;
+ inputc= &ma->rampin_spec;
+ methodc= &ma->rampblend_spec;
+ facp= &ma->rampfac_spec;
+ }
+ draw_colorband_buts(block, coba, 10, 50, B_MATPRV); // aligns with previous button
+
+ uiDefBut(block, LABEL, 0, "Input",10,30,90,20, NULL, 0, 0, 0, 0, "");
+ uiDefBut(block, LABEL, 0, "Method",100,30,90,20, NULL, 0, 0, 0, 0, "");
+ uiDefBut(block, LABEL, 0, "Factor",190,30,120,20, NULL, 0, 0, 0, 0, "");
+ uiBlockBeginAlign(block);
+ uiDefButC(block, MENU, B_MATPRV, "Shader %x0|Energy %x1|Normal %x2|Result %x3",10,10,90,20, inputc, 0, 0, 0, 0, "Input for Ramp");
+ uiDefButC(block, MENU, B_MATPRV, "Mix %x0|Add %x1|Subtract %x3|Multiply %x2|Screen %x4|Overlay %x9|Divide %x5|Difference %x6|Darken %x7|Lighten %x8|Dodge %x10|Burn %x11|Color %x15|Value %x14|Saturation %x13|Hue %x12",110,10,90,20, methodc, 0, 0, 0, 0, "Blending method for Ramp (uses alpha in Colorband)");
+ uiDefButF(block, NUMSLI, B_MATPRV, "", 190,10,120,20, facp, 0.0, 1.0, 100, 0, "Blending factor (also uses alpha in Colorband)");
+ }
+}
+
+/* NOTE: this is a block-menu, needs 0 events, otherwise the menu closes */
+static uiBlock *strand_menu(void *mat_v)
+{
+ Material *ma= mat_v;
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "strand menu", UI_EMBOSS, UI_HELV, curarea->win);
+
+ /* use this for a fake extra empy space around the buttons */
+ uiDefBut(block, LABEL, 0, "", 0, 0, 250, 100, NULL, 0, 0, 0, 0, "");
+
+ uiBlockBeginAlign(block);
+ /* event return 0, to prevent menu to close */
+ uiDefButBitI(block, TOG, MA_TANGENT_STR, 0, "Use Tangent Shading", 10,70,230,20, &(ma->mode), 0, 0, 0, 0, "Uses direction of strands as normal for tangent-shading");
+ uiDefButF(block, NUMSLI, 0, "Start ", 10, 50, 230,20, &ma->strand_sta, 0.25, 20.0, 2, 0, "Start size of strands in pixels");
+ uiDefButF(block, NUMSLI, 0, "End ", 10, 30, 230,20, &ma->strand_end, 0.25, 10.0, 2, 0, "End size of strands in pixels");
+ uiDefButF(block, NUMSLI, 0, "Shape ", 10, 10, 230,20, &ma->strand_ease, -0.9, 0.9, 2, 0, "Shape of strands, positive value makes it rounder, negative makes it spiky");
+
+ uiBlockSetDirection(block, UI_TOP);
+ BIF_preview_changed(ID_MA);
+ return block;
+}
+
+
+static void material_panel_material(Material *ma)
+{
+ uiBlock *block;
+ float *colpoin = NULL;
+ int rgbsel = 0;
+
+ block= uiNewBlock(&curarea->uiblocks, "material_panel_material", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Material", "Material", 320, 0, 318, 204)==0) return;
+
+ uiSetButLock(ma->id.lib!=NULL, ERROR_LIBDATA_MESSAGE);
+ uiBlockBeginAlign(block);
+ uiDefIconBut(block, BUT, B_MATCOPY, ICON_COPYUP, 262,200,XIC,YIC, 0, 0, 0, 0, 0, "Copies Material to the buffer");
+ uiDefIconBut(block, BUT, B_MATPASTE, ICON_PASTEUP, 283,200,XIC,YIC, 0, 0, 0, 0, 0, "Pastes Material from the buffer");
+ uiBlockEndAlign(block);
+ if(ma->dynamode & MA_DRAW_DYNABUTS) {
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUMSLI, B_DIFF, "Restitut ", 128,120,175,20, &ma->reflect, 0.0, 1.0, 0, 0, "Elasticity of collisions");
+ uiDefButF(block, NUMSLI, B_DIFF, "Friction ", 128,100 ,175,20, &ma->friction, 0.0, 100.0, 0, 0, "Coulomb friction coefficient");
+ uiDefButF(block, NUMSLI, B_DIFF, "Fh Force ", 128,80 ,175,20, &ma->fh, 0.0, 1.0, 0, 0, "Upward spring force within the Fh area");
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_NOP, "Fh Damp ", 8,120,100,20, &ma->xyfrict, 0.0, 1.0, 10, 0, "Damping of the Fh spring force");
+ uiDefButF(block, NUM, B_NOP, "Fh Dist ", 8,100 ,100,20, &ma->fhdist, 0.0, 20.0, 10, 0, "Height of the Fh area");
+ uiDefButBitS(block, TOG, MA_FH_NOR, 0, "Fh Norm", 8,80 ,100,20, &ma->dynamode, 0.0, 0.0, 0, 0, "Add a horizontal spring force on slopes");
+ }
+ else {
+ if(!(ma->mode & MA_HALO)) {
+ uiBlockBeginAlign(block);
+ uiBlockSetCol(block, TH_BUT_SETTING1);
+ uiDefButBitI(block, TOG, MA_VERTEXCOL, B_MAT_VCOL_LIGHT, "VCol Light", 8,166,74,20, &(ma->mode), 0, 0, 0, 0, "Adds vertex colors as extra light");
+ uiDefButBitI(block, TOG, MA_VERTEXCOLP, B_MAT_VCOL_PAINT, "VCol Paint", 82,166,74,20, &(ma->mode), 0, 0, 0, 0, "Replaces material's colors with vertex colors");
+ uiDefButBitI(block, TOG, MA_FACETEXTURE, B_REDR, "TexFace", 156,166,74,20, &(ma->mode), 0, 0, 0, 0, "Sets UV-Editor assigned texture as color and texture info for faces");
+ uiDefButBitI(block, TOG, MA_SHLESS, B_MATPRV, "Shadeless", 230,166,73,20, &(ma->mode), 0, 0, 0, 0, "Makes material insensitive to light or shadow");
+
+ uiDefButBitI(block, TOG, MA_NOMIST, B_NOP, "No Mist", 8,146,74,20, &(ma->mode), 0, 0, 0, 0, "Sets the material to ignore mist values");
+ uiDefButBitI(block, TOG, MA_ENV, B_MATPRV, "Env", 82,146,74,20, &(ma->mode), 0, 0, 0, 0, "Causes faces to render with alpha zero: allows sky/backdrop to show through (only for solid faces)");
+ uiDefButF(block, NUM, B_NOP, "Shad A ", 156,146,147,19, &ma->shad_alpha, 0.001, 1.0f, 100, 0, "Shadow casting alpha, only in use for Irregular Shadowbuffer");
+ }
+ uiBlockSetCol(block, TH_AUTO);
+ uiBlockBeginAlign(block);
+ uiDefButF(block, COL, B_MATPRV, "", 8,97,72,20, &(ma->r), 0, 0, 0, B_MATCOL, "");
+ uiDefButF(block, COL, B_MATPRV, "", 8,77,72,20, &(ma->specr), 0, 0, 0, B_SPECCOL, "");
+ uiDefButF(block, COL, B_MATPRV, "", 8,57,72,20, &(ma->mirr), 0, 0, 0, B_MIRCOL, "");
+
+ uiBlockBeginAlign(block);
+ if(ma->mode & MA_HALO) {
+ uiDefButC(block, ROW, REDRAWBUTSSHADING, "Halo", 83,97,40,20, &(ma->rgbsel), 2.0, 0.0, 0, 0, "Sets the color of the halo with the RGB sliders");
+ uiDefButC(block, ROW, REDRAWBUTSSHADING, "Line", 83,77,40,20, &(ma->rgbsel), 2.0, 1.0, 0, 0, "Sets the color of the lines with the RGB sliders");
+ uiDefButC(block, ROW, REDRAWBUTSSHADING, "Ring", 83,57,40,20, &(ma->rgbsel), 2.0, 2.0, 0, 0, "Sets the color of the rings with the RGB sliders");
+ }
+ else {
+ uiDefButC(block, ROW, REDRAWBUTSSHADING, "Col", 83,97,40,20, &(ma->rgbsel), 2.0, 0.0, 0, 0, "Sets the diffuse color of the material");
+ uiDefButC(block, ROW, REDRAWBUTSSHADING, "Spe", 83,77,40,20, &(ma->rgbsel), 2.0, 1.0, 0, 0, "Sets the specular color of the material");
+ uiDefButC(block, ROW, REDRAWBUTSSHADING, "Mir", 83,57,40,20, &(ma->rgbsel), 2.0, 2.0, 0, 0, "Sets the mirror color of the material");
+ }
+
+ if(ma->rgbsel==0) {colpoin= &(ma->r); rgbsel= B_MATCOL;}
+ else if(ma->rgbsel==1) {colpoin= &(ma->specr); rgbsel= B_SPECCOL;}
+ else if(ma->rgbsel==2) {colpoin= &(ma->mirr); rgbsel= B_MIRCOL;}
+
+ if(ma->rgbsel==0 && (ma->mode & (MA_VERTEXCOLP|MA_FACETEXTURE) && !(ma->mode & MA_HALO)));
+ else if(ma->colormodel==MA_HSV) {
+ uiBlockSetCol(block, TH_BUT_SETTING1);
+ uiBlockBeginAlign(block);
+ uiDefButF(block, HSVSLI, B_MATPRV, "H ", 128,97,175,19, colpoin, 0.0, 0.9999, rgbsel, 0, "");
+ uiDefButF(block, HSVSLI, B_MATPRV, "S ", 128,77,175,19, colpoin, 0.0001, 1.0, rgbsel, 0, "");
+ uiDefButF(block, HSVSLI, B_MATPRV, "V ", 128,57,175,19, colpoin, 0.0001, 1.0, rgbsel, 0, "");
+ uiBlockSetCol(block, TH_AUTO);
+ }
+ else {
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUMSLI, B_MATPRV, "R ", 128,97,175,19, colpoin, 0.0, 1.0, rgbsel, 0, "");
+ uiDefButF(block, NUMSLI, B_MATPRV, "G ", 128,77,175,19, colpoin+1, 0.0, 1.0, rgbsel, 0, "");
+ uiDefButF(block, NUMSLI, B_MATPRV, "B ", 128,57,175,19, colpoin+2, 0.0, 1.0, rgbsel, 0, "");
+ }
+ uiBlockEndAlign(block);
+ uiDefButF(block, NUMSLI, B_MATPRV, "A ", 128,30,175,19, &ma->alpha, 0.0, 1.0, 0, 0, "Alpha");
+
+ }
+ uiBlockBeginAlign(block);
+ uiDefButS(block, ROW, REDRAWBUTSSHADING, "RGB", 8,30,38,19, &(ma->colormodel), 1.0, (float)MA_RGB, 0, 0, "Creates color using red, green and blue");
+ uiDefButS(block, ROW, REDRAWBUTSSHADING, "HSV", 46,30,38,19, &(ma->colormodel), 1.0, (float)MA_HSV, 0, 0, "Creates color using hue, saturation and value");
+ uiDefButBitS(block, TOG, MA_DRAW_DYNABUTS, REDRAWBUTSSHADING, "DYN", 84,30,39,19, &(ma->dynamode), 0.0, 0.0, 0, 0, "Adjusts parameters for dynamics options");
+
+}
+
+static void material_panel_nodes(Material *ma)
+{
+ bNode *node;
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "material_panel_nodes", UI_EMBOSS, UI_HELV, curarea->win);
+ uiNewPanelTabbed("Links and Pipeline", "Material");
+ if(uiNewPanel(curarea, block, "Nodes", "Material", 640, 0, 318, 204)==0) return;
+
+ node= editnode_get_active(ma->nodetree);
+ if(node==NULL) return;
+ /* we dont display the buttons here for the active material, is in links panel */
+ if(node==editnode_get_active_idnode(ma->nodetree, ID_MA)) return;
+
+ if(node->typeinfo->butfunc) {
+ /* we use butfunc to retrieve height for the butrect, but node->width is
+ used to calculate that too. Could be done smarter once */
+ rctf rct;
+ rct.xmin= 10.0f;
+ rct.xmax= rct.xmin+node->width-NODE_DY;
+ rct.ymax= 155.0;
+ rct.ymin= rct.ymax - (float)node->typeinfo->butfunc(NULL, NULL, node, NULL);
+ node->typeinfo->butfunc(block, ma->nodetree, node, &rct);
+ }
+}
+
+static void material_panel_links(Object *ob, Material *ma)
+{
+ uiBlock *block;
+ uiBut *but;
+ ID *id, *idn, *idfrom;
+ bNode *node=NULL;
+ float min;
+ short xco;
+ char str[30];
+
+ block= uiNewBlock(&curarea->uiblocks, "material_panel_links", UI_EMBOSS, UI_HELV, curarea->win);
+ /* 310 makes sorting code to put it right after preview panel */
+ if(uiNewPanel(curarea, block, "Links and Pipeline", "Material", 310, 0, 318, 204)==0) return;
+
+ /* Links from object to material/nodes */
+ uiDefBut(block, ROUNDBOX, 0, "", 5, 90, 310, 110, NULL, 7.0, 0.0, 15 , 20, "");
+ uiDefBut(block, LABEL, B_DIFF, "Link to Object", 10, 180, 300, 20, 0, 0, 0, 0, 0, "");
+
+ /* the main material browse but */
+ buttons_active_id(&id, &idfrom); /* base material! */
+
+ uiBlockSetCol(block, TH_BUT_SETTING2);
+ xco= std_libbuttons(block, 10, 160, 0, NULL, B_MATBROWSE, ID_MA, 0, id, idfrom, &(G.buts->menunr), B_MATALONE, B_MATLOCAL, B_MATDELETE, B_AUTOMATNAME, B_KEEPDATA);
+
+ if(ma) uiSetButLock(ma->id.lib!=NULL, ERROR_LIBDATA_MESSAGE);
+
+ if(ma)
+ uiDefButC(block, TOG, B_MAT_USENODES, "Nodes", xco+5,160,300-xco-5,20, &ma->use_nodes, 0.0f, 0.0f, 0, 0, "");
+
+ if(ob->actcol==0) ob->actcol= 1; /* because of TOG|BIT button */
+
+ uiBlockBeginAlign(block);
+
+ /* id is the block from which the material is used */
+ if( BTST(ob->colbits, ob->actcol-1) ) id= (ID *)ob;
+ else id= ob->data;
+
+ /* indicate which one is linking a material */
+ if(id) {
+ if(id->lib)
+ uiSetButLock(1, ERROR_LIBDATA_MESSAGE);
+ else
+ uiClearButLock();
+
+ strncpy(str, id->name, 2);
+ str[2]= ':'; str[3]= 0;
+ but= uiDefBut(block, TEX, B_IDNAME, str, 10,135,115,20, id->name+2, 0.0, 21.0, 0, 0, "Shows the block the material is linked to");
+ uiButSetFunc(but, test_idbutton_cb, id->name, NULL);
+ }
+
+ uiBlockSetCol(block, TH_BUT_ACTION);
+ uiDefButBitS(block, TOG, 1<<(ob->actcol-1), B_MATFROM, "OB", 125,135,32,20, &ob->colbits, 0, 0, 0, 0, "Links material to object");
+ idn= ob->data;
+ strncpy(str, idn->name, 2);
+ str[2]= 0;
+ uiBlockSetCol(block, TH_BUT_SETTING);
+ uiDefButBitS(block, TOGN, 1<<(ob->actcol-1), B_MATFROM, str, 158,135,32,20, &ob->colbits, 0, 0, 0, 0, "Shows the block the material is linked to");
+ uiBlockSetCol(block, TH_AUTO);
+
+ sprintf(str, "%d Mat", ob->totcol);
+ if(ob->totcol) min= 1.0; else min= 0.0;
+ uiDefButC(block, NUM, B_ACTCOL, str, 190,135,110,20, &(ob->actcol), min, (float)ob->totcol, 0, 0, "Shows the number of materials on object and the active material");
+ uiBlockEndAlign(block);
+
+ if(ma==NULL) return;
+ uiSetButLock(ma->id.lib!=NULL, ERROR_LIBDATA_MESSAGE);
+
+ /* Active material node */
+ if(ma->use_nodes) {
+ uiDefBut(block, LABEL, B_DIFF, "Active Material Node", 10, 115, 300, 20, 0, 0, 0, 0, 0, "");
+
+ if(ma) node= editnode_get_active_idnode(ma->nodetree, ID_MA);
+ if(node==NULL) {
+ node= editnode_get_active(ma->nodetree);
+ if(node && node->type!=SH_NODE_MATERIAL)
+ node= NULL;
+ }
+ if(node) {
+ rctf rct;
+ rct.xmin= 10.0f;
+ rct.xmax= 300.0f;
+ rct.ymax= 114.0f;
+ rct.ymin= 95.0f;
+ node->typeinfo->butfunc(block, ma->nodetree, node, &rct);
+ }
+ }
+
+ /* main render pipeline settings */
+ uiDefBut(block, LABEL, B_DIFF, "Render Pipeline", 10, 70, 300, 20, 0, 0, 0, 0, 0, "");
+
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOG, MA_HALO, B_MATHALO, "Halo", 10,50,100,19, &(ma->mode), 0, 0, 0, 0, "Renders material as a halo");
+ uiDefButBitI(block, TOG, MA_ZTRA, B_MATZTRANSP,"ZTransp", 110,50,100,19, &(ma->mode), 0, 0, 0, 0, "Enables Z-Buffering of transparent faces");
+ uiDefButF(block, NUM, B_DIFF, "Zoffs:", 210,50,100,19, &(ma->zoffs), 0.0, 100.0, 100, 0, "Gives faces an artificial offset in the Z buffer for Ztransp option");
+
+ uiDefButBitI(block, TOG, MA_FULL_OSA, 0, "Full Osa", 10,30,75,19, &(ma->mode), 0.0, 10.0, 0, 0, "Forces to render all OSA samples, for shading and texture antialiasing");
+ uiDefButBitI(block, TOG, MA_WIRE, B_MATPRV, "Wire", 85,30,75,19, &(ma->mode), 0, 0, 0, 0, "Renders only the edges of faces as a wireframe");
+ uiDefBlockBut(block, strand_menu, ma, "Strands", 160,30,75, 19, "Display strand settings for static particles");
+ uiDefButBitI(block, TOG, MA_ZINV, B_MATPRV, "ZInvert", 236,30,75,19, &(ma->mode), 0, 0, 0, 0, "Renders material's faces with inverted Z Buffer");
+
+ uiDefButBitI(block, TOG, MA_RADIO, B_NOP, "Radio", 10,10,75,19, &(ma->mode), 0, 0, 0, 0, "Enables radiosity rendering for material");
+ uiDefButBitI(block, TOG, MA_ONLYCAST, B_MATPRV,"OnlyCast", 85,10,75,19, &(ma->mode), 0, 0, 0, 0, "Makes faces cast shadows only, not rendered");
+ uiDefButBitI(block, TOG, MA_TRACEBLE, B_NOP,"Traceable", 160,10,75,19, &(ma->mode), 0, 0, 0, 0, "Makes material detectable by ray tracing");
+ uiDefButBitI(block, TOG, MA_SHADBUF, B_MATPRV, "Shadbuf", 235,10,75,19, &(ma->mode), 0, 0, 0, 0, "Makes material cast shadows from shadow buffer lamps");
+
+
+}
+
+static void material_panel_preview(Material *ma)
+{
+ uiBlock *block;
+
+ /* name "Preview" is abused to detect previewrender offset panel */
+ block= uiNewBlock(&curarea->uiblocks, "material_panel_preview", UI_EMBOSS, UI_HELV, curarea->win);
+ if(uiNewPanel(curarea, block, "Preview", "Material", 0, 0, 318, 204)==0) return;
+
+ if(ma) {
+ G.buts->lockpoin= ma; /* BIF_previewdraw callback will read it */
+
+ uiBlockSetDrawExtraFunc(block, BIF_previewdraw);
+
+ // label to force a boundbox for buttons not to be centered
+ uiDefBut(block, LABEL, 0, " ", 20,20,10,10, 0, 0, 0, 0, 0, "");
+ uiBlockSetCol(block, TH_BUT_NEUTRAL);
+ uiBlockBeginAlign(block);
+ uiDefIconButC(block, ROW, B_MATPRV, ICON_MATPLANE, 210,180,25,22, &(ma->pr_type), 10, MA_FLAT, 0, 0, "Preview type: Flat XY plane");
+ uiDefIconButC(block, ROW, B_MATPRV, ICON_MATSPHERE, 210,158,25,22, &(ma->pr_type), 10, MA_SPHERE, 0, 0, "Preview type: Sphere");
+ uiDefIconButC(block, ROW, B_MATPRV, ICON_MATCUBE, 210,136,25,22, &(ma->pr_type), 10, MA_CUBE, 0, 0, "Preview type: Cube");
+ uiDefIconButC(block, ROW, B_MATPRV, ICON_MONKEY, 210,114,25,22, &(ma->pr_type), 10, MA_MONKEY, 0, 0, "Preview type: Monkey");
+ uiDefIconButC(block, ROW, B_MATPRV, ICON_HAIR, 210, 92,25,22, &(ma->pr_type), 10, MA_HAIR, 0, 0, "Preview type: Hair strands");
+ uiDefIconButC(block, ROW, B_MATPRV, ICON_MATSPHERE, 210, 70,25,22, &(ma->pr_type), 10, MA_SPHERE_A, 0, 0, "Preview type: Large sphere with sky");
+ uiBlockEndAlign(block);
+
+ uiDefIconButBitC(block, TOG, SB_PRV_OSA, B_MATPRV, ICON_RING, 210, 10,25,22, &(G.buts->flag), 0, 0, 0, 0, "Preview uses OSA (oversampling)");
+ }
+}
+
+void material_panels()
+{
+ Material *ma;
+ MTex *mtex;
+ Object *ob= OBACT;
+
+ if(ob==NULL) return;
+
+ // type numbers are ordered
+ if((ob->type<OB_LAMP) && ob->type) {
+ int from_nodes= 0;
+
+ ma= give_current_material(ob, ob->actcol);
+
+ // always draw first 2 panels
+ material_panel_preview(ma);
+ material_panel_links(ob, ma);
+
+ if(ma && ma->use_nodes) {
+ material_panel_nodes(ma);
+ from_nodes= 1;
+ }
+
+ ma= editnode_get_active_material(ma);
+ if(ma) {
+ material_panel_material(ma);
+ material_panel_ramps(ma);
+ material_panel_shading(ma);
+
+ if (G.scene->r.renderer==R_INTERN)
+ material_panel_tramir(ma);
+ else {
+ if(ma->YF_ar==0.f) {
+ ma->YF_ar = ma->YF_ag = ma->YF_ab = 1;
+ ma->YF_dscale = 1;
+ }
+ material_panel_tramir_yafray(ma);
+ }
+
+ material_panel_sss(ma);
+ material_panel_texture(ma);
+
+ mtex= ma->mtex[ ma->texact ];
+ if(mtex && mtex->tex) {
+ material_panel_map_input(ob, ma);
+ material_panel_map_to(ma, from_nodes);
+ }
+ }
+ }
+}
+
+void lamp_panels()
+{
+ Object *ob= OBACT;
+ Lamp *la;
+
+ if(ob==NULL || ob->type!= OB_LAMP) return;
+ la= ob->data;
+
+ lamp_panel_preview(ob, ob->data);
+ lamp_panel_lamp(ob, ob->data);
+
+ if (ELEM(la->type, LA_SPOT, LA_LOCAL) && (la->falloff_type == LA_FALLOFF_CURVE))
+ lamp_panel_falloff(ob, ob->data);
+
+ /* switch to yafray lamp panel if yafray enabled */
+ if (G.scene->r.renderer==R_INTERN)
+ lamp_panel_spot(ob, ob->data);
+ else {
+ /* init vars */
+ if (la->YF_numphotons==0) la->YF_numphotons=1000;
+ if (la->YF_numsearch==0) la->YF_numsearch=10;
+ if (la->YF_phdepth==0) la->YF_phdepth=1;
+ if (la->YF_causticblur==0.0) la->YF_causticblur=0.001;
+ if (la->YF_bufsize==0) la->YF_bufsize=128;
+ /* spherelight radius default is zero, so nothing to do */
+ lamp_panel_yafray(ob, la);
+ }
+ lamp_panel_texture(ob, ob->data);
+ lamp_panel_mapto(ob, ob->data);
+
+}
+
+void world_panels()
+{
+ World *wrld;
+
+ wrld= G.scene->world;
+
+ world_panel_preview(wrld);
+ world_panel_world(wrld);
+
+ if(wrld) {
+ world_panel_mistaph(wrld);
+ world_panel_amb_occ(wrld);
+ world_panel_texture(wrld);
+ world_panel_mapto(wrld);
+ }
+}
+
+void texture_panels()
+{
+ Material *ma=NULL;
+ Brush *br=NULL;
+ SculptData *sd=NULL;
+ Lamp *la=NULL;
+ World *wrld=NULL;
+ bNode *node=NULL;
+ Object *ob= OBACT;
+ MTex *mtex= NULL;
+
+ if(G.buts->texfrom==0) {
+ if(ob) {
+ ma= give_current_material(ob, ob->actcol);
+
+ if(ma && ma->use_nodes) {
+ node= editnode_get_active_idnode(ma->nodetree, ID_TE);
+
+ if(node)
+ ma= NULL;
+ else {
+ ma= editnode_get_active_material(ma);
+ }
+ }
+ if(ma) mtex= ma->mtex[ ma->texact ];
+ }
+ }
+ else if(G.buts->texfrom==1) {
+ wrld= G.scene->world;
+ if(wrld) mtex= wrld->mtex[ wrld->texact ];
+ }
+ else if(G.buts->texfrom==2) {
+ if(ob && ob->type==OB_LAMP) {
+ la= ob->data;
+ mtex= la->mtex[ la->texact ];
+ }
+ }
+ else if(G.buts->texfrom==3) {
+ if(G.f & G_SCULPTMODE) {
+ sd= &G.scene->sculptdata;
+ if(sd->texact != -1)
+ mtex= sd->mtex[sd->texact];
+ }
+ else {
+ br= G.scene->toolsettings->imapaint.brush;
+ if(br) mtex= br->mtex[br->texact];
+ }
+ }
+
+ texture_panel_preview(mtex, ma || wrld || la || br || node || sd); // for 'from' buttons
+
+ if(ma || wrld || la || br || node || sd) {
+ Tex *tex= NULL;
+
+ texture_panel_texture(mtex, ma, wrld, la, node, br, sd);
+
+ if(mtex) tex= mtex->tex;
+ else if(node) tex= (Tex *)node->id;
+
+ if(tex) {
+ texture_panel_colors(tex);
+
+ switch(tex->type) {
+ case TEX_IMAGE:
+ texture_panel_image(&tex->ima, &tex->iuser);
+ texture_panel_image_map(tex);
+ break;
+ case TEX_ENVMAP:
+ texture_panel_envmap(tex);
+ break;
+ case TEX_CLOUDS:
+ texture_panel_clouds(tex);
+ break;
+ case TEX_MARBLE:
+ texture_panel_marble(tex);
+ break;
+ case TEX_STUCCI:
+ texture_panel_stucci(tex);
+ break;
+ case TEX_WOOD:
+ texture_panel_wood(tex);
+ break;
+ case TEX_BLEND:
+ texture_panel_blend(tex);
+ break;
+ case TEX_MAGIC:
+ texture_panel_magic(tex);
+ break;
+ case TEX_PLUGIN:
+ texture_panel_plugin(tex);
+ break;
+ case TEX_NOISE:
+ // no panel! (e: not really true, is affected by noisedepth param)
+ break;
+ /* newnoise: musgrave panels */
+ case TEX_MUSGRAVE:
+ texture_panel_musgrave(tex);
+ break;
+ case TEX_DISTNOISE:
+ texture_panel_distnoise(tex);
+ break;
+ /* newnoise: voronoi */
+ case TEX_VORONOI:
+ texture_panel_voronoi(tex);
+ break;
+ }
+ }
+ }
+}
+
+void radio_panels()
+{
+ Radio *rad;
+ int flag;
+
+ rad= G.scene->radio;
+ if(rad==NULL) {
+ add_radio();
+ rad= G.scene->radio;
+ }
+
+ radio_panel_render(rad);
+
+ flag= rad_phase();
+
+ radio_panel_tool(rad, flag);
+ if(flag) radio_panel_calculation(rad, flag);
+
+
+}
diff --git a/source/blender/src/cmap.tga.c b/source/blender/src/cmap.tga.c
new file mode 100644
index 00000000000..da515b6b106
--- /dev/null
+++ b/source/blender/src/cmap.tga.c
@@ -0,0 +1,92 @@
+/* DataToC output of file <cmap_tga> */
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+int datatoc_cmap_tga_size= 13400;
+char datatoc_cmap_tga[]= {"\x00\x01\x01\x00\x00\x00\x01\x18\x00\x00\x00\x00\x9a\x00\x50\x00\x08\x08\xf3\xf3\xf3\xdb\xdb\xdb\xc4\xc4\xc4\xad\xad\xad\x96\x96\x96\x7f\x7f\x7f\x67\x67\x67\x50\x50\x50\x39\x39\x39\x22\x22\x22\x0b\x0b\x0b\xf4\xf4\xf4\xe6\xc8\xec\xe6\xa4\xec\xe6\x7f\xec\xe6\x5b\xec\xe6\x36\xec\xe6\x12\xec\xb3\xec\xec\xb3\xc8\xec\xb3\xa4\xec\xb3\x7f\xec\xb3\x5b\xec" \
+"\xb3\x36\xec\xb3\x12\xec\x80\xec\xec\x80\xc8\xec\x80\xa4\xec\x80\x7f\xec\x80\x5b\xec\x80\x36\xec\x80\x12\xec\x4d\xec\xec\x4d\xc8\xec\x4d\xa4\xec\x4d\x7f\xec\x4d\x5b\xec\x4d\x36\xec\x4d\x12\xec\x1a\xec\xec\x1a\xc8\xec\x1a\xa4\xec\x1a\x7f\xec\x1a\x5b\xec\x1a\x36\xec\x1a\x12\xec\xe6\xec\xc8\xe6\xc8\xc8\xe6\xa4\xc8\xe6\x7f\xc8\xe6\x5b\xc8\xe6\x36\xc8\xe6\x12\xc8\xb3\xec\xc8\xb3\xc8\xc8\xb3\xa4\xc8\xb3\x7f\xc8\xb3\x5b\xc8\xb3\x36\xc8\xb3\x12\xc8\x80\xec\xc8\x80\xc8\xc8\x80\xa4\xc8\x80\x7f\xc8\x80\x5b\xc8\x80\x36\xc8\x80\x12\xc8\x4d\xec\xc8\x4d\xc8\xc8\x4d\xa4\xc8\x4d\x7f\xc8\x4d\x5b\xc8\x4d\x36\xc8\x4d\x12\xc8\x1a\xec\xc8\x1a\xc8\xc8\x1a\xa4\xc8\x1a\x7f\xc8\x1a\x5b\xc8\x1a\x36\xc8\x1a\x12\xc8\xe6\xec\xa4\xe6\xc8\xa4\xe6\xa4\xa4\xe6\x7f\xa4\xe6\x5b\xa4\xe6\x36\xa4\xe6\x12\xa4\xb3\xec\xa4\xb3\xc8\xa4\xb3\xa4\xa4\xb3\x7f\xa4\xb3\x5b\xa4\xb3\x36\xa4\xb3\x12\xa4\x80\xec\xa4\x80\xc8\xa4\x80\xa4\xa4\x80\x7f\xa4\x80\x5b\xa4\x80\x36\xa4\x80\x12\xa4\x4d\xec\xa4\x4d\xc8\xa4\x4d\xa4\xa4\x4d\x7f\xa4\x4d\x5b\xa4\x4d\x36\xa4\x4d" \
+"\x12\xa4\x1a\xec\xa4\x1a\xc8\xa4\x1a\xa4\xa4\x1a\x7f\xa4\x1a\x5b\xa4\x1a\x36\xa4\x1a\x12\xa4\xe6\xec\x7f\xe6\xc8\x7f\xe6\xa4\x7f\xe6\x7f\x7f\xe6\x5b\x7f\xe6\x36\x7f\xe6\x12\x7f\xb3\xec\x7f\xb3\xc8\x7f\xb3\xa4\x7f\xb3\x7f\x7f\xb3\x5b\x7f\xb3\x36\x7f\xb3\x12\x7f\x80\xec\x7f\x80\xc8\x7f\x80\xa4\x7f\x80\x7f\x7f\x80\x5b\x7f\x80\x36\x7f\x80\x12\x7f\x4d\xec\x7f\x4d\xc8\x7f\x4d\xa4\x7f\x4d\x7f\x7f\x4d\x5b\x7f\x4d\x36\x7f\x4d\x12\x7f\x1a\xec\x7f\x1a\xc8\x7f\x1a\xa4\x7f\x1a\x7f\x7f\x1a\x5b\x7f\x1a\x36\x7f\x1a\x12\x7f\xe6\xec\x5b\xe6\xc8\x5b\xe6\xa4\x5b\xe6\x7f\x5b\xe6\x5b\x5b\xe6\x36\x5b\xe6\x12\x5b\xb3\xec\x5b\xb3\xc8\x5b\xb3\xa4\x5b\xb3\x7f\x5b\xb3\x5b\x5b\xb3\x36\x5b\xb3\x12\x5b\x80\xec\x5b\x80\xc8\x5b\x80\xa4\x5b\x80\x7f\x5b\x80\x5b\x5b\x80\x36\x5b\x80\x12\x5b\x4d\xec\x5b\x4d\xc8\x5b\x4d\xa4\x5b\x4d\x7f\x5b\x4d\x5b\x5b\x4d\x36\x5b\x4d\x12\x5b\x1a\xec\x5b\x1a\xc8\x5b\x1a\xa4\x5b\x1a\x7f\x5b\x1a\x5b\x5b\x1a\x36\x5b\x1a\x12\x5b\xe6\xec\x36\xe6\xc8\x36\xe6\xa4\x36\xe6\x7f\x36\xe6\x5b\x36\xe6\x36\x36\xe6\x12\x36\xb3\xec" \
+"\x36\xb3\xc8\x36\xb3\xa4\x36\xb3\x7f\x36\xb3\x5b\x36\xb3\x36\x36\xb3\x12\x36\x80\xec\x36\x80\xc8\x36\x80\xa4\x36\x80\x7f\x36\x80\x5b\x36\x80\x36\x36\x80\x12\x36\x4d\xec\x36\x4d\xc8\x36\x4d\xa4\x36\x4d\x7f\x36\x4d\x5b\x36\x4d\x36\x36\x4d\x12\x36\x1a\xec\x36\x1a\xc8\x36\x1a\xa4\x36\x1a\x7f\x36\x1a\x5b\x36\x1a\x36\x36\x1a\x12\x36\xe6\xec\x12\xe6\xc8\x12\xe6\xa4\x12\xe6\x7f\x12\xe6\x5b\x12\xe6\x36\x12\xe6\x12\x12\xb3\xec\x12\xb3\xc8\x12\xb3\xa4\x12\xb3\x7f\x12\xb3\x5b\x12\xb3\x36\x12\xb3\x12\x12\x80\xec\x12\x80\xc8\x12\x80\xa4\x12\x80\x7f\x12\x80\x5b\x12\x80\x36\x12\x80\x12\x12\x4d\xec\x12\x4d\xc8\x12\x4d\xa4\x12\x4d\x7f\x12\x4d\x5b\x12\x4d\x36\x12\x4d\x12\x12\x1a\xec\x12\x1a\xc8\x12\x1a\xa4\x12\x1a\x7f\x12\x1a\x5b\x12\x1a\x36\x12\x1a\x12\x12\x03\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02" \
+"\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x04\x07\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x07\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x02\x04\x07\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x02\x07\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a" \
+"\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x02\x04\x07\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x02\x07\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a" \
+"\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x02\x04\x07\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x02\x07\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x02\x04\x07\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x02\x07\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a" \
+"\x0a\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x02\x04\x07\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x02\x07\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\xff\xff\xff\xff\xff\x09\x09\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x09\x09\x09\xff\xff\xff\xff\xff\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x02\x04\x07\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x02\x07\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\xdc\xdc\xdc\xdc\xdc" \
+"\xdc\xdc\xdc\xdc\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\x09\x09\x09\x09\x09\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x09\x09\x09\x09\x09\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x02\x04\x07\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x02\x07\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\x09\x09\x09\x09\xdb\xdb\xdb\xdb\xdb\xdb\x09\x09\x09\x09\x09\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x0a\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\x09\x09\x09\x09\x09\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x09\x09\x09\x09\xdc\xdc\xdc\xdc" \
+"\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\x0a\x0a\x0a\x0a\x0a\x0a\x0a\x02\x04\x07\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x02\x07\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\x09\x09\x09\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x09\x09\x09\x09\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\x02\x04\x07\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x02\x07\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe" \
+"\xfe\xfe\xfe\xfe\xf7\xf7\xf7\xf7\xf7\xf7\xf7\xf7\xf7\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\x02\x04\x07\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09\x02\x07\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xf7\xf7\xf7\xf7\xf7\xf7\xf7\xf7\xf7\xf7\xf7\xf7\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\xdc\x02\x04\x07\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09\x02\x07\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9" \
+"\xb9\xb8\xb8\xb8\xb8\xb8\xb8\xb8\xb8\xb8\xb7\xb7\xda\xda\xda\xda\xda\xda\xda\xda\xda\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xf6\xf6\xf6\xf6\xf6\xf7\xf7\xf7\xf7\xf7\xf7\xf7\xf7\xf7\xf7\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xb2\xb2\xb2\xb2\xb2\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\x02\x04\x07\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09\x02\x07\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb8\xb8\xb8\xb8\xb8\xb8\xb8\xb8\xb8\xb7\xb7\xb7\xb7\xda\xda\xda\xda\xda\xda\xda\xda\xda\xda\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xf6\xf6\xf6\xf6\xf6\xf6\xf6\xf6\xf7\xf7\xf7\xf7\xf7\xf7\xf7\xf7\xf7\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xb2" \
+"\xb2\xb2\xb2\xb2\xb2\xb2\xb2\xb2\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\x02\x04\x07\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09\x02\x07\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb8\xb8\xb8\xb8\xb8\xb8\xb8\xb8\xb8\xb7\xb7\xb7\xb7\xb7\xb7\xb7\xda\xda\xda\xda\xda\xda\xda\xda\xda\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xf6\xf6\xf6\xf6\xf6\xf6\xf6\xf6\xf6\xf6\xf7\xf7\xf7\xf7\xf7\xf7\xf7\xf7\xf7\xf7\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xb2\xb2\xb2\xb2\xb2\xb2\xb2\xb2\xb2\xb2\xb2\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\x02\x04\x07\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09\x09\x02\x07\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb8\xb8\xb8\xb8\xb8\xb8\xb8\xb8\xb7\xb7\xb7\xb7\xb7\xb7\xb7\xb7\xb7\xb7\xda\xda\xda\xda\xda\xda\xda\xda\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xf6" \
+"\xf6\xf6\xf6\xf6\xf6\xf6\xf6\xf6\xf6\xf6\xf6\xf6\xf7\xf7\xf7\xf7\xf7\xf7\xf7\xf7\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xb2\xb2\xb2\xb2\xb2\xb2\xb2\xb2\xb2\xb2\xb2\xb2\xb2\xb2\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\x02\x04\x07\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\x02\x07\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb8\xb8\xb8\xb8\xb8\xb8\xb8\xb8\xb7\xb7\xb7\xb7\xb7\xb7\xb7\xb7\xb7\xb7\xb7\xb7\xda\xda\xda\xda\xda\xda\xda\xda\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xf6\xf6\xf6\xf6\xf6\xf6\xf6\xf6\xf6\xf6\xf6\xf6\xf6\xf6\xf6\xf7\xf7\xf7\xf7\xf7\xf7\xf7\xf7\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xf8\xd5\xd5\xd5\xd5\xd5\xd5\xd5\xb2\xb2\xb2\xb2\xb2\xb2\xb2\xb2\xb2\xb2\xb2\xb2\xb2\xb2\xb2\xb2\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\x02\x04\x07\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\x02\x07\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb8" \
+"\xb8\xb8\xb8\xb8\xb8\xb8\xb7\xb7\xb7\xb7\xb7\xb7\xb7\xb7\xb7\xb7\xb7\xb7\xb7\xb7\xda\xda\xda\xda\xda\xda\xda\xda\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xfd\xf6\xf6\xf6\xf6\xf6\xf6\xf6\xf6\xf6\xf6\xef\xef\xef\xef\xef\xef\xef\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xce\xce\xce\xce\xce\xce\xce\xab\xab\xab\xab\xab\xab\xab\xab\xb2\xb2\xb2\xb2\xb2\xb2\xb2\xb2\xb2\xb2\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\xb9\x02\x04\x07\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\xdb\x02\x07\x96\x96\x96\x96\x96\x96\x96\x96\x95\x95\x95\x95\x95\x95\x95\x94\x94\x94\x94\x94\x94\x94\x94\xb6\xb6\xb6\xb6\xb6\xb6\xb6\xb6\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xee\xef\xef\xef\xef\xef\xef\xef\xef\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xce\xce\xce\xce\xce\xce\xce\xab\xab\xab\xab\xab" \
+"\xab\xab\xab\x88\x88\x8f\x8f\x8f\x8f\x8f\x8f\x8f\x8f\x8f\x8f\x96\x96\x96\x96\x96\x96\x96\x96\x96\x96\x96\x02\x04\x07\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x02\x07\x96\x96\x96\x96\x96\x96\x96\x96\x95\x95\x95\x95\x95\x95\x94\x94\x94\x94\x94\x94\x94\x94\x93\x93\xb6\xb6\xb6\xb6\xb6\xb6\xb6\xb6\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xee\xee\xee\xef\xef\xef\xef\xef\xef\xef\xef\xf0\xf0\xf0\xf0\xf0\xf0\xf0\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xce\xce\xce\xce\xce\xce\xab\xab\xab\xab\xab\xab\xab\xab\x88\x88\x88\x88\x8f\x8f\x8f\x8f\x8f\x8f\x8f\x8f\x8f\x8f\x96\x96\x96\x96\x96\x96\x96\x96\x96\x96\x02\x04\x07\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x02\x07\x96\x96\x96\x96\x96\x96\x96\x95\x95\x95\x95\x95\x95\x95\x94\x94\x94\x94\x94\x94\x94\x93\x93\x93\x93\x93\xb6\xb6\xb6\xb6\xb6\xb6\xb6\xd9\xd9\xd9\xd9\xd9\xd9\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xf5\xf5\xf5" \
+"\xf5\xf5\xf5\xf5\xf5\xf5\xee\xee\xee\xee\xee\xef\xef\xef\xef\xef\xef\xef\xef\xf0\xf0\xf0\xf0\xf0\xf0\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xce\xce\xce\xce\xce\xce\xce\xab\xab\xab\xab\xab\xab\xab\x88\x88\x88\x88\x88\x88\x8f\x8f\x8f\x8f\x8f\x8f\x8f\x8f\x8f\x96\x96\x96\x96\x96\x96\x96\x96\x96\x96\x02\x04\x07\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x02\x07\x96\x96\x96\x96\x96\x96\x96\x95\x95\x95\x95\x95\x95\x94\x94\x94\x94\x94\x94\x94\x93\x93\x93\x93\x93\x93\xb6\xb6\xb6\xb6\xb6\xb6\xb6\xd9\xd9\xd9\xd9\xd9\xd9\xd9\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xee\xee\xee\xee\xee\xee\xee\xef\xef\xef\xef\xef\xef\xef\xef\xf0\xf0\xf0\xf0\xf0\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xce\xce\xce\xce\xce\xce\xab\xab\xab\xab\xab\xab\xab\x88\x88\x88\x88\x88\x88\x88\x88\x8f\x8f\x8f\x8f\x8f\x8f\x8f\x8f\x8f\x96\x96\x96\x96\x96\x96\x96\x96\x96\x02\x04\x07\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x08\x02\x07\x96\x96\x96\x96\x96\x96\x95\x95" \
+"\x95\x95\x95\x95\x94\x94\x94\x94\x94\x94\x94\x93\x93\x93\x93\x93\x93\x93\x93\xb6\xb6\xb6\xb6\xb6\xb6\xb6\xd9\xd9\xd9\xd9\xd9\xd9\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xfc\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xf5\xee\xee\xee\xee\xee\xee\xee\xee\xee\xef\xef\xef\xef\xef\xef\xef\xf0\xf0\xf0\xf0\xf0\xf0\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xce\xce\xce\xce\xce\xce\xab\xab\xab\xab\xab\xab\xab\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x8f\x8f\x8f\x8f\x8f\x8f\x8f\x8f\x96\x96\x96\x96\x96\x96\x96\x96\x96\x02\x04\x07\x08\x08\x08\x08\x08\x08\x08\x08\x08\x07\x07\x02\x07\x73\x73\x73\x73\x73\x73\x72\x72\x72\x72\x72\x71\x71\x71\x71\x71\x71\x71\x70\x70\x70\x70\x70\x92\x92\x92\x92\x92\xb5\xb5\xb5\xb5\xb5\xb5\xb5\xd8\xd8\xd8\xd8\xd8\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xed\xed\xed\xed\xed\xed\xed\xee\xee\xee\xee\xef\xef\xef\xef\xef\xef\xef\xf0\xf0\xf0\xf0\xf0\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xce\xce\xce\xce\xce\xce\xab\xab\xab\xab\xab\xab" \
+"\x88\x88\x88\x88\x88\x65\x65\x65\x65\x65\x65\x65\x6c\x6c\x6c\x6c\x6c\x6c\x6c\x6c\x73\x73\x73\x73\x73\x73\x73\x73\x02\x04\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x02\x07\x73\x73\x73\x73\x73\x73\x72\x72\x72\x72\x72\x71\x71\x71\x71\x71\x71\x71\x70\x70\x70\x70\x6f\x6f\x92\x92\x92\x92\x92\xb5\xb5\xb5\xb5\xb5\xb5\xb5\xd8\xd8\xd8\xd8\xd8\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xed\xed\xed\xed\xed\xed\xed\xee\xee\xee\xee\xee\xef\xef\xef\xef\xef\xef\xf0\xf0\xf0\xf0\xf0\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xce\xce\xce\xce\xce\xab\xab\xab\xab\xab\xab\xab\x88\x88\x88\x88\x65\x65\x65\x65\x65\x65\x65\x65\x6c\x6c\x6c\x6c\x6c\x6c\x6c\x6c\x73\x73\x73\x73\x73\x73\x73\x73\x02\x04\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x02\x07\x73\x73\x73\x73\x73\x73\x72\x72\x72\x72\x72\x71\x71\x71\x71\x71\x71\x70\x70\x70\x70\x6f\x6f\x6f\x6f\x92\x92\x92\x92\x92\xb5\xb5\xb5\xb5\xb5\xb5\xd8\xd8\xd8\xd8\xd8\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xf4\xf4\xf4\xf4" \
+"\xf4\xf4\xf4\xf4\xed\xed\xed\xed\xed\xed\xed\xed\xed\xee\xee\xee\xee\xef\xef\xef\xef\xef\xef\xef\xf0\xf0\xf0\xf0\xf0\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xf1\xce\xce\xce\xce\xab\xab\xab\xab\xab\xab\xab\x88\x88\x88\x88\x65\x65\x65\x65\x65\x65\x65\x65\x65\x65\x6c\x6c\x6c\x6c\x6c\x6c\x6c\x6c\x73\x73\x73\x73\x73\x73\x73\x02\x04\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x02\x07\x73\x73\x73\x73\x73\x72\x72\x72\x72\x72\x71\x71\x71\x71\x71\x71\x70\x70\x70\x70\x70\x6f\x6f\x6f\x6f\x6f\x92\x92\x92\x92\xb5\xb5\xb5\xb5\xb5\xb5\xd8\xd8\xd8\xd8\xd8\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xed\xed\xed\xed\xed\xed\xed\xed\xe6\xe6\xe6\xe7\xe7\xe7\xe7\xe8\xe8\xe8\xe8\xe8\xe8\xe9\xe9\xe9\xe9\xe9\xea\xea\xea\xea\xea\xea\xea\xea\xea\xea\xc7\xc7\xc7\xc7\xc7\xa4\xa4\xa4\xa4\xa4\xa4\x81\x81\x81\x81\x5e\x5e\x5e\x5e\x65\x65\x65\x65\x65\x65\x65\x65\x6c\x6c\x6c\x6c\x6c\x6c\x6c\x73\x73\x73\x73\x73\x73\x73\x02\x04\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x02\x07\x73\x73\x73\x73\x73\x72" \
+"\x72\x72\x72\x71\x71\x71\x71\x71\x71\x70\x70\x70\x70\x70\x6f\x6f\x6f\x6f\x6f\x6f\x6f\x92\x92\x92\x92\xb5\xb5\xb5\xb5\xb5\xb5\xd8\xd8\xd8\xd8\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xed\xed\xed\xed\xed\xed\xed\xe6\xe6\xe6\xe6\xe7\xe7\xe7\xe7\xe7\xe8\xe8\xe8\xe8\xe8\xe8\xe9\xe9\xe9\xe9\xea\xea\xea\xea\xea\xea\xea\xea\xea\xea\xc7\xc7\xc7\xc7\xc7\xa4\xa4\xa4\xa4\xa4\x81\x81\x81\x81\x81\x5e\x5e\x5e\x5e\x5e\x65\x65\x65\x65\x65\x65\x65\x6c\x6c\x6c\x6c\x6c\x6c\x6c\x73\x73\x73\x73\x73\x73\x73\x02\x04\x07\xb0\xb0\xb0\xb0\xb0\xb0\xb0\xb0\xb0\xb0\xb0\x02\x07\x73\x73\x73\x73\x73\x72\x72\x72\x72\x71\x71\x71\x71\x71\x71\x70\x70\x70\x70\x6f\x6f\x6f\x6f\x6f\x6f\x6f\x6f\x92\x92\x92\x92\xb5\xb5\xb5\xb5\xb5\xb5\xd8\xd8\xd8\xd8\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xfb\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xed\xed\xed\xed\xed\xed\xed\xe6\xe6\xe6\xe6\xe6\xe6\xe7\xe7\xe7\xe7\xe8\xe8\xe8\xe8\xe8\xe8\xe9\xe9\xe9\xe9\xea\xea\xea\xea\xea\xea\xea\xea\xea\xea\xc7\xc7\xc7\xc7\xa4\xa4\xa4\xa4\xa4\xa4\x81" \
+"\x81\x81\x81\x5e\x5e\x5e\x5e\x5e\x5e\x65\x65\x65\x65\x65\x65\x65\x65\x6c\x6c\x6c\x6c\x6c\x6c\x6c\x73\x73\x73\x73\x73\x73\x02\x04\x07\xb0\xb0\xb0\xb0\xb0\xb0\xb0\xb0\xb0\xb0\xb0\x02\x07\x50\x50\x50\x50\x50\x4f\x4f\x4f\x4f\x4e\x4e\x4e\x4e\x4e\x4d\x4d\x4d\x4d\x4d\x4c\x4c\x4c\x4c\x6e\x6e\x6e\x6e\x6e\x91\x91\x91\x91\xb4\xb4\xb4\xb4\xb4\xb4\xd7\xd7\xd7\xd7\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xf3\xf3\xf3\xf3\xf3\xf3\xf3\xec\xec\xec\xec\xec\xec\xec\xe5\xe5\xe5\xe6\xe6\xe6\xe6\xe7\xe7\xe7\xe7\xe8\xe8\xe8\xe8\xe8\xe9\xe9\xe9\xe9\xe9\xea\xea\xea\xea\xea\xea\xea\xea\xea\xc7\xc7\xc7\xc7\xa4\xa4\xa4\xa4\xa4\xa4\x81\x81\x81\x81\x5e\x5e\x5e\x5e\x3b\x3b\x3b\x42\x42\x42\x42\x42\x42\x42\x49\x49\x49\x49\x49\x49\x49\x50\x50\x50\x50\x50\x50\x02\x04\x07\xb0\xb0\xb0\xb0\xb0\xb0\xb0\xb0\xb0\xb0\xb0\x02\x07\x50\x50\x50\x50\x4f\x4f\x4f\x4f\x4f\x4e\x4e\x4e\x4e\x4e\x4d\x4d\x4d\x4d\x4c\x4c\x4c\x4c\x4b\x4b\x6e\x6e\x6e\x6e\x6e\x91\x91\x91\x91\xb4\xb4\xb4\xb4\xb4\xd7\xd7\xd7\xd7\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xf3\xf3\xf3" \
+"\xf3\xf3\xf3\xec\xec\xec\xec\xec\xec\xec\xe5\xe5\xe5\xe5\xe6\xe6\xe6\xe6\xe6\xe7\xe7\xe7\xe8\xe8\xe8\xe8\xe8\xe8\xe9\xe9\xe9\xe9\xea\xea\xea\xea\xea\xea\xea\xea\xea\xc7\xc7\xc7\xc7\xa4\xa4\xa4\xa4\xa4\x81\x81\x81\x81\x5e\x5e\x5e\x5e\x3b\x3b\x3b\x3b\x3b\x42\x42\x42\x42\x42\x42\x42\x49\x49\x49\x49\x49\x49\x50\x50\x50\x50\x50\x50\x02\x04\x07\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x02\x07\x50\x50\x50\x50\x4f\x4f\x4f\x4f\x4e\x4e\x4e\x4e\x4e\x4d\x4d\x4d\x4d\x4c\x4c\x4c\x4c\x4c\x4b\x4b\x4b\x6e\x6e\x6e\x6e\x91\x91\x91\x91\xb4\xb4\xb4\xb4\xb4\xd7\xd7\xd7\xd7\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xf3\xf3\xf3\xf3\xf3\xec\xec\xec\xec\xec\xec\xec\xec\xe5\xe5\xe5\xe5\xe5\xe6\xe6\xe6\xe6\xe7\xe7\xe7\xe7\xe8\xe8\xe8\xe8\xe8\xe9\xe9\xe9\xe9\xea\xea\xea\xea\xea\xea\xea\xea\xea\xc7\xc7\xc7\xa4\xa4\xa4\xa4\xa4\x81\x81\x81\x81\x5e\x5e\x5e\x5e\x5e\x3b\x3b\x3b\x3b\x3b\x42\x42\x42\x42\x42\x42\x42\x42\x49\x49\x49\x49\x49\x50\x50\x50\x50\x50\x50\x02\x04\x07\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x02\x07\x50\x50\x50\x50" \
+"\x4f\x4f\x4f\x4f\x4e\x4e\x4e\x4e\x4e\x4d\x4d\x4d\x4d\x4c\x4c\x4c\x4c\x4b\x4b\x4b\x4b\x4b\x6e\x6e\x6e\x6e\x91\x91\x91\xb4\xb4\xb4\xb4\xb4\xb4\xd7\xd7\xd7\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xf3\xf3\xf3\xf3\xf3\xf3\xec\xec\xec\xec\xec\xec\xec\xe5\xe5\xe5\xe5\xe5\xe5\xe6\xe6\xe6\xe6\xe7\xe7\xe7\xe7\xe8\xe8\xe8\xe8\xe8\xe9\xe9\xe9\xe9\xea\xea\xea\xea\xea\xea\xea\xea\xc7\xc7\xc7\xc7\xa4\xa4\xa4\xa4\xa4\x81\x81\x81\x81\x5e\x5e\x5e\x5e\x3b\x3b\x3b\x3b\x3b\x3b\x3b\x42\x42\x42\x42\x42\x42\x42\x49\x49\x49\x49\x49\x50\x50\x50\x50\x50\x50\x02\x04\x07\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x02\x07\x50\x50\x50\x50\x4f\x4f\x4f\x4f\x4e\x4e\x4e\x4e\x4d\x4d\x4d\x4d\x4c\x4c\x4c\x4c\x4c\x4b\x4b\x4b\x4b\x4b\x6e\x6e\x6e\x6e\x91\x91\x91\x91\xb4\xb4\xb4\xb4\xb4\xd7\xd7\xd7\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xf3\xf3\xf3\xf3\xf3\xf3\xec\xec\xec\xec\xec\xec\xe5\xe5\xe5\xe5\xe5\xde\xde\xde\xdf\xdf\xdf\xdf\xe0\xe0\xe0\xe0\xe1\xe1\xe1\xe1\xe1\xe2\xe2\xe2\xe3\xe3\xe3\xe3\xe3\xe3\xe3\xe3\xc0\xc0\xc0\xc0\x9d\x9d\x9d\x9d\x9d\x7a" \
+"\x7a\x7a\x57\x57\x57\x57\x34\x34\x34\x34\x3b\x3b\x3b\x3b\x42\x42\x42\x42\x42\x42\x42\x49\x49\x49\x49\x49\x49\x50\x50\x50\x50\x50\x02\x04\x07\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x02\x07\x50\x50\x50\x50\x4f\x4f\x4f\x4e\x4e\x4e\x4e\x4e\x4d\x4d\x4d\x4d\x4c\x4c\x4c\x4c\x4b\x4b\x4b\x4b\x4b\x4b\x6e\x6e\x6e\x6e\x6e\x91\x91\x91\xb4\xb4\xb4\xb4\xb4\xd7\xd7\xd7\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xfa\xf3\xf3\xf3\xf3\xf3\xf3\xec\xec\xec\xec\xec\xec\xe5\xe5\xe5\xe5\xe5\xde\xde\xde\xdf\xdf\xdf\xdf\xdf\xe0\xe0\xe0\xe1\xe1\xe1\xe1\xe1\xe2\xe2\xe2\xe3\xe3\xe3\xe3\xe3\xe3\xe3\xe3\xc0\xc0\xc0\xc0\x9d\x9d\x9d\x9d\x7a\x7a\x7a\x7a\x57\x57\x57\x57\x34\x34\x34\x34\x3b\x3b\x3b\x3b\x3b\x42\x42\x42\x42\x42\x42\x49\x49\x49\x49\x49\x49\x50\x50\x50\x50\x50\x02\x04\x07\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x06\x02\x07\x2d\x2d\x2d\x2d\x2c\x2c\x2c\x2b\x2b\x2b\x2b\x2a\x2a\x2a\x2a\x29\x29\x29\x29\x28\x28\x28\x28\x4a\x4a\x4a\x4a\x6d\x6d\x6d\x6d\x90\x90\x90\x90\xb3\xb3\xb3\xb3\xd6\xd6\xd6\xd6\xf9\xf9\xf9\xf9\xf9\xf9\xf9\xf9\xf9\xf2\xf2" \
+"\xf2\xf2\xf2\xeb\xeb\xeb\xeb\xeb\xeb\xe4\xe4\xe4\xe4\xe4\xdd\xde\xde\xde\xde\xdf\xdf\xdf\xdf\xe0\xe0\xe0\xe1\xe1\xe1\xe1\xe1\xe2\xe2\xe2\xe3\xe3\xe3\xe3\xe3\xe3\xe3\xe3\xc0\xc0\xc0\x9d\x9d\x9d\x9d\x9d\x7a\x7a\x7a\x57\x57\x57\x57\x57\x34\x34\x34\x11\x11\x18\x18\x18\x18\x18\x1f\x1f\x1f\x1f\x1f\x1f\x26\x26\x26\x26\x26\x2d\x2d\x2d\x2d\x2d\x02\x04\x07\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x02\x07\x2d\x2d\x2d\x2d\x2c\x2c\x2c\x2b\x2b\x2b\x2b\x2a\x2a\x2a\x2a\x29\x29\x29\x29\x28\x28\x28\x28\x27\x4a\x4a\x4a\x4a\x6d\x6d\x6d\x6d\x90\x90\x90\xb3\xb3\xb3\xb3\xd6\xd6\xd6\xd6\xf9\xf9\xf9\xf9\xf9\xf9\xf9\xf9\xf9\xf2\xf2\xf2\xf2\xf2\xeb\xeb\xeb\xeb\xeb\xeb\xe4\xe4\xe4\xe4\xdd\xdd\xdd\xde\xde\xde\xdf\xdf\xdf\xdf\xe0\xe0\xe0\xe0\xe1\xe1\xe1\xe1\xe2\xe2\xe2\xe3\xe3\xe3\xe3\xe3\xe3\xe3\xe3\xc0\xc0\xc0\x9d\x9d\x9d\x9d\x7a\x7a\x7a\x7a\x57\x57\x57\x57\x34\x34\x34\x34\x11\x11\x18\x18\x18\x18\x18\x1f\x1f\x1f\x1f\x1f\x1f\x26\x26\x26\x26\x26\x2d\x2d\x2d\x2d\x2d\x02\x04\x07\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x02\x07\x2d\x2d" \
+"\x2d\x2d\x2c\x2c\x2c\x2b\x2b\x2b\x2b\x2a\x2a\x2a\x29\x29\x29\x29\x28\x28\x28\x28\x27\x27\x4a\x4a\x4a\x4a\x6d\x6d\x6d\x6d\x90\x90\x90\x90\xb3\xb3\xb3\xb3\xd6\xd6\xd6\xf9\xf9\xf9\xf9\xf9\xf9\xf9\xf9\xf2\xf2\xf2\xf2\xf2\xeb\xeb\xeb\xeb\xeb\xeb\xe4\xe4\xe4\xe4\xe4\xdd\xdd\xdd\xde\xde\xde\xde\xdf\xdf\xdf\xdf\xe0\xe0\xe0\xe1\xe1\xe1\xe1\xe2\xe2\xe2\xe3\xe3\xe3\xe3\xe3\xe3\xe3\xe3\xc0\xc0\xc0\x9d\x9d\x9d\x9d\x7a\x7a\x7a\x7a\x57\x57\x57\x34\x34\x34\x34\x11\x11\x11\x11\x18\x18\x18\x18\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x26\x26\x26\x26\x2d\x2d\x2d\x2d\x2d\x02\x04\x07\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x02\x07\x2d\x2d\x2d\x2d\x2c\x2c\x2c\x2b\x2b\x2b\x2b\x2a\x2a\x2a\x29\x29\x29\x29\x28\x28\x28\x28\x27\x27\x27\x4a\x4a\x4a\x6d\x6d\x6d\x6d\x6d\x90\x90\x90\xb3\xb3\xb3\xb3\xd6\xd6\xd6\xf9\xf9\xf9\xf9\xf9\xf9\xf9\xf9\xf2\xf2\xf2\xf2\xf2\xeb\xeb\xeb\xeb\xeb\xeb\xe4\xe4\xe4\xe4\xdd\xdd\xdd\xdd\xdd\xde\xde\xde\xdf\xdf\xdf\xdf\xe0\xe0\xe0\xe0\xe1\xe1\xe1\xe2\xe2\xe2\xe2\xe3\xe3\xe3\xe3\xe3\xe3\xe3\xc0\xc0\xc0\x9d\x9d\x9d\x9d\x7a" \
+"\x7a\x7a\x57\x57\x57\x57\x34\x34\x34\x34\x11\x11\x11\x11\x11\x18\x18\x18\x18\x1f\x1f\x1f\x1f\x1f\x1f\x26\x26\x26\x26\x26\x2d\x2d\x2d\x2d\x02\x04\x07\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x05\x02\x07\x2d\x2d\x2d\x2d\x2c\x2c\x2b\x2b\x2b\x2b\x2b\x2a\x2a\x2a\x29\x29\x29\x28\x28\x28\x28\x27\x27\x27\x27\x27\x4a\x4a\x4a\x6d\x6d\x6d\x6d\x90\x90\x90\xb3\xb3\xb3\xb3\xd6\xd6\xd6\xf9\xf9\xf9\xf9\xf9\xf9\xf9\xf9\xf2\xf2\xf2\xf2\xf2\xeb\xeb\xeb\xeb\xeb\xe4\xe4\xe4\xe4\xe4\xdd\xdd\xdd\xdd\xdd\xde\xde\xde\xde\xdf\xdf\xdf\xdf\xe0\xe0\xe0\xe1\xe1\xe1\xe1\xe2\xe2\xe2\xe3\xe3\xe3\xe3\xe3\xe3\xe3\xc0\xc0\x9d\x9d\x9d\x9d\x7a\x7a\x7a\x7a\x57\x57\x57\x57\x34\x34\x34\x11\x11\x11\x11\x11\x11\x18\x18\x18\x18\x18\x1f\x1f\x1f\x1f\x1f\x26\x26\x26\x26\x26\x2d\x2d\x2d\x2d\x02\x04\x07\x05\x05\x05\x05\x85\x85\x85\x85\x85\x85\x85\x02\x07\x2d\x2d\x2d\x2c\x2c\x2c\x2b\x2b\x2b\x2b\x2a\x2a\x2a\x29\x29\x29\x29\x28\x28\x28\x28\x27\x27\x27\x27\x27\x4a\x4a\x4a\x6d\x6d\x6d\x6d\x90\x90\x90\xb3\xb3\xb3\xb3\xd6\xd6\xd6\xf9\xf9\xf9\xf9\xf9\xf9\xf9\xf9\xf2" \
+"\xf2\xf2\xf2\xeb\xeb\xeb\xeb\xeb\xeb\xe4\xe4\xe4\xe4\xe4\xdd\xdd\xdd\xdd\xdd\xdd\xde\xde\xde\xdf\xdf\xdf\xdf\xe0\xe0\xe0\xe1\xe1\xe1\xe1\xe2\xe2\xe2\xe3\xe3\xe3\xe3\xe3\xe3\xc0\xc0\xc0\x9d\x9d\x9d\x9d\x7a\x7a\x7a\x57\x57\x57\x57\x34\x34\x34\x34\x11\x11\x11\x11\x11\x11\x18\x18\x18\x18\x18\x1f\x1f\x1f\x1f\x1f\x26\x26\x26\x26\x26\x2d\x2d\x2d\x2d\x02\x04\x07\x85\x85\x85\x85\x85\x85\x85\x85\x85\x85\x85\x02\x07\x2d\x2d\x2d\x2c\x2c\x2c\x2b\x2b\x2b\x2a\x2a\x2a\x2a\x29\x29\x29\x29\x28\x28\x28\x28\x27\x27\x27\x27\x27\x4a\x4a\x4a\x6d\x6d\x6d\x6d\x90\x90\x90\x90\xb3\xb3\xb3\xb3\xd6\xd6\xd6\xf9\xf9\xf9\xf9\xf9\xf9\xf2\xf2\xf2\xf2\xf2\xeb\xeb\xeb\xeb\xeb\xeb\xe4\xe4\xe4\xe4\xe4\xdd\xdd\xdd\xdd\xdd\xdd\xde\xde\xde\xdf\xdf\xdf\xdf\xe0\xe0\xe0\xe0\xe1\xe1\xe1\xe1\xe2\xe2\xe3\xe3\xe3\xe3\xe3\xe3\xc0\xc0\xc0\x9d\x9d\x9d\x9d\x7a\x7a\x7a\x57\x57\x57\x57\x34\x34\x34\x34\x11\x11\x11\x11\x11\x11\x18\x18\x18\x18\x18\x1f\x1f\x1f\x1f\x1f\x1f\x26\x26\x26\x26\x2d\x2d\x2d\x2d\x02\x04\x07\x85\x85\x85\x85\x85\x85\x85\x85\x85\x85\x85\x02\x07" \
+"\x2d\x2d\x2c\x2c\x2c\x2b\x2b\x2b\x2b\x2a\x2a\x2a\x2a\x29\x29\x29\x29\x28\x28\x28\x28\x27\x27\x27\x27\x27\x4a\x4a\x4a\x4a\x6d\x6d\x6d\x6d\x90\x90\x90\xb3\xb3\xb3\xb3\xd6\xd6\xd6\xf9\xf9\xf9\xf9\xf9\xf9\xf2\xf2\xf2\xf2\xf2\xeb\xeb\xeb\xeb\xeb\xeb\xe4\xe4\xe4\xe4\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xde\xde\xde\xdf\xdf\xdf\xdf\xdf\xe0\xe0\xe0\xe1\xe1\xe1\xe1\xe2\xe2\xe2\xe3\xe3\xe3\xe3\xc0\xc0\xc0\x9d\x9d\x9d\x9d\x7a\x7a\x7a\x7a\x57\x57\x57\x57\x34\x34\x34\x34\x11\x11\x11\x11\x11\x11\x18\x18\x18\x18\x18\x1f\x1f\x1f\x1f\x1f\x1f\x26\x26\x26\x26\x26\x2d\x2d\x2d\x02\x04\x07\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x02\x07\x2d\x2d\x2c\x2c\x2c\x2b\x2b\x2b\x2b\x2a\x2a\x2a\x29\x29\x29\x29\x29\x28\x28\x28\x28\x27\x27\x27\x27\x27\x4a\x4a\x4a\x4a\x6d\x6d\x6d\x6d\x90\x90\x90\x90\xb3\xb3\xb3\xb3\xd6\xd6\xd6\xf9\xf9\xf9\xf9\xf2\xf2\xf2\xf2\xf2\xeb\xeb\xeb\xeb\xeb\xeb\xe4\xe4\xe4\xe4\xe4\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xde\xde\xde\xde\xdf\xdf\xdf\xdf\xe0\xe0\xe0\xe1\xe1\xe1\xe1\xe1\xe2\xe2\xe3\xe3\xe3\xe3\xc0\xc0\xc0\x9d\x9d\x9d\x9d\x7a" \
+"\x7a\x7a\x7a\x57\x57\x57\x57\x34\x34\x34\x11\x11\x11\x11\x11\x11\x11\x11\x18\x18\x18\x18\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x26\x26\x26\x26\x2d\x2d\x2d\x02\x04\x07\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x02\x07\x2d\x2c\x2c\x2c\x2b\x2b\x2b\x2b\x2b\x2a\x2a\x2a\x29\x29\x29\x29\x28\x28\x28\x28\x27\x27\x27\x27\x27\x27\x4a\x4a\x4a\x4a\x6d\x6d\x6d\x6d\x6d\x90\x90\x90\xb3\xb3\xb3\xb3\xd6\xd6\xd6\xf9\xf9\xf9\xf9\xf2\xf2\xf2\xf2\xf2\xeb\xeb\xeb\xeb\xeb\xeb\xe4\xe4\xe4\xe4\xe4\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xde\xde\xde\xde\xdf\xdf\xdf\xdf\xe0\xe0\xe0\xe0\xe1\xe1\xe1\xe1\xe2\xe2\xe2\xe3\xe3\xc0\xc0\xc0\x9d\x9d\x9d\x9d\x7a\x7a\x7a\x7a\x57\x57\x57\x57\x34\x34\x34\x34\x11\x11\x11\x11\x11\x11\x11\x11\x18\x18\x18\x18\x18\x1f\x1f\x1f\x1f\x1f\x1f\x26\x26\x26\x26\x26\x2d\x2d\x02\x04\x07\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x02\x07\x2d\x2c\x2c\x2c\x2b\x2b\x2b\x2b\x2a\x2a\x2a\x29\x29\x29\x29\x29\x28\x28\x28\x28\x27\x27\x27\x27\x27\x27\x4a\x4a\x4a\x4a\x4a\x6d\x6d\x6d\x6d\x90\x90\x90\x90\xb3\xb3\xb3\xb3\xd6\xd6\xd6\xf9\xf9\xf2\xf2" \
+"\xf2\xf2\xf2\xeb\xeb\xeb\xeb\xeb\xeb\xeb\xe4\xe4\xe4\xe4\xe4\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xde\xde\xde\xde\xdf\xdf\xdf\xdf\xdf\xe0\xe0\xe0\xe1\xe1\xe1\xe1\xe1\xe2\xe2\xe2\xc0\xc0\xc0\xc0\x9d\x9d\x9d\x9d\x7a\x7a\x7a\x7a\x57\x57\x57\x57\x34\x34\x34\x34\x11\x11\x11\x11\x11\x11\x11\x11\x18\x18\x18\x18\x18\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x26\x26\x26\x26\x26\x2d\x02\x04\x07\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x02\x07\x2c\x2c\x2c\x2b\x2b\x2b\x2b\x2a\x2a\x2a\x2a\x29\x29\x29\x29\x29\x28\x28\x28\x28\x27\x27\x27\x27\x27\x27\x4a\x4a\x4a\x4a\x4a\x6d\x6d\x6d\x6d\x6d\x90\x90\x90\xb3\xb3\xb3\xb3\xd6\xd6\xd6\xd6\xd6\xcf\xcf\xcf\xcf\xcf\xc8\xc8\xc8\xc8\xc8\xc8\xc1\xc1\xc1\xc1\xc1\xc1\xba\xba\xba\xba\xba\xba\xba\xbb\xbb\xbb\xbb\xbc\xbc\xbc\xbc\xbc\xbd\xbd\xbd\xbd\xbe\xbe\xbe\xbe\xbf\xbf\xbf\xbf\xbf\xbf\x9c\x9c\x9c\x9c\x79\x79\x79\x79\x56\x56\x56\x56\x56\x33\x33\x33\x33\x10\x10\x10\x10\x10\x10\x10\x10\x17\x17\x17\x17\x17\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x25\x25\x25\x25\x25\x2c\x02\x04\x07\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04" \
+"\x02\x07\x2c\x2c\x2b\x2b\x2b\x2b\x2b\x2a\x2a\x2a\x2a\x29\x29\x29\x29\x29\x28\x28\x28\x28\x27\x27\x27\x27\x27\x27\x4a\x4a\x4a\x4a\x4a\x6d\x6d\x6d\x6d\x6d\x90\x90\x90\x90\xb3\xb3\xb3\xb3\xd6\xd6\xd6\xcf\xcf\xcf\xcf\xcf\xc8\xc8\xc8\xc8\xc8\xc8\xc8\xc1\xc1\xc1\xc1\xc1\xc1\xba\xba\xba\xba\xba\xba\xba\xbb\xbb\xbb\xbb\xbb\xbc\xbc\xbc\xbc\xbc\xbd\xbd\xbd\xbe\xbe\xbe\xbe\xbe\xbf\xbf\xbf\xbf\xbf\x9c\x9c\x9c\x9c\x79\x79\x79\x79\x56\x56\x56\x56\x56\x33\x33\x33\x33\x10\x10\x10\x10\x10\x10\x10\x10\x17\x17\x17\x17\x17\x17\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x25\x25\x25\x25\x25\x02\x04\x07\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x02\x07\x25\x25\x24\x24\x24\x24\x23\x23\x23\x23\x22\x22\x22\x22\x22\x21\x21\x21\x21\x21\x20\x20\x20\x20\x20\x20\x43\x43\x43\x43\x43\x66\x66\x66\x66\x66\x89\x89\x89\x89\xac\xac\xac\xac\xac\xcf\xcf\xcf\xcf\xcf\xcf\xcf\xc8\xc8\xc8\xc8\xc8\xc8\xc1\xc1\xc1\xc1\xc1\xc1\xc1\xba\xba\xba\xba\xba\xba\xba\xbb\xbb\xbb\xbb\xbb\xbc\xbc\xbc\xbc\xbc\xbd\xbd\xbd\xbd\xbe\xbe\xbe\xbe\xbf\xbf\xbf\xbf\x9c\x9c\x9c\x9c\x79\x79" \
+"\x79\x79\x56\x56\x56\x56\x56\x33\x33\x33\x33\x33\x10\x10\x10\x10\x10\x10\x10\x10\x17\x17\x17\x17\x17\x17\x17\x1e\x1e\x1e\x1e\x1e\x1e\x25\x25\x25\x25\x25\x02\x04\x07\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x04\x02\x07\x25\x24\x24\x24\x24\x24\x23\x23\x23\x23\x22\x22\x22\x22\x22\x21\x21\x21\x21\x21\x20\x20\x20\x20\x20\x20\x20\x43\x43\x43\x43\x66\x66\x66\x66\x66\x66\x89\x89\x89\x89\xac\xac\xac\xac\xcf\xcf\xcf\xcf\xcf\xcf\xc8\xc8\xc8\xc8\xc8\xc8\xc8\xc1\xc1\xc1\xc1\xc1\xc1\xba\xba\xba\xba\xba\xba\xba\xba\xbb\xbb\xbb\xbb\xbb\xbc\xbc\xbc\xbc\xbc\xbc\xbd\xbd\xbd\xbd\xbe\xbe\xbe\xbe\xbf\xbf\x9c\x9c\x9c\x9c\x9c\x79\x79\x79\x79\x56\x56\x56\x56\x56\x33\x33\x33\x33\x33\x10\x10\x10\x10\x10\x10\x10\x10\x10\x17\x17\x17\x17\x17\x17\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x25\x25\x25\x25\x02\x04\x07\x5a\x5a\x5a\x5a\x5a\x5a\x5a\x5a\x5a\x5a\x5a\x02\x07\x25\x24\x24\x24\x24\x23\x23\x23\x23\x22\x22\x22\x22\x22\x22\x21\x21\x21\x21\x21\x20\x20\x20\x20\x20\x20\x20\x43\x43\x43\x43\x43\x66\x66\x66\x66\x66\x89\x89\x89\x89\xac\xac\xac\xac\xac\xcf\xcf" \
+"\xcf\xcf\xc8\xc8\xc8\xc8\xc8\xc8\xc8\xc8\xc1\xc1\xc1\xc1\xc1\xc1\xba\xba\xba\xba\xba\xba\xba\xba\xbb\xbb\xbb\xbb\xbb\xbc\xbc\xbc\xbc\xbc\xbc\xbd\xbd\xbd\xbd\xbe\xbe\xbe\xbe\xbe\x9c\x9c\x9c\x9c\x9c\x79\x79\x79\x79\x56\x56\x56\x56\x56\x56\x33\x33\x33\x33\x33\x10\x10\x10\x10\x10\x10\x10\x10\x10\x17\x17\x17\x17\x17\x17\x1e\x1e\x1e\x1e\x1e\x1e\x1e\x25\x25\x25\x25\x02\x04\x07\x5a\x5a\x5a\x5a\x5a\x5a\x5a\x5a\x5a\x5a\x5a\x02\x07\x24\x24\x24\x24\x23\x23\x23\x23\x23\x22\x22\x22\x22\x22\x21\x21\x21\x21\x21\x21\x20\x20\x20\x20\x20\x20\x20\x43\x43\x43\x43\x43\x66\x66\x66\x66\x66\x66\x89\x89\x89\x89\xac\xac\xac\xac\xac\xac\xac\xac\xa5\xa5\xa5\xa5\xa5\xa5\xa5\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x97\x97\x97\x97\x97\x97\x97\x97\x97\x98\x98\x98\x98\x98\x99\x99\x99\x99\x99\x9a\x9a\x9a\x9a\x9a\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x78\x78\x78\x78\x55\x55\x55\x55\x55\x55\x32\x32\x32\x32\x32\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x16\x16\x16\x16\x16\x16\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x24\x24\x24\x02\x04\x07\x5a\x5a\x5a\x5a\x5a\x5a\x5a\x5a\x5a" \
+"\x5a\x5a\x02\x07\x24\x24\x24\x24\x23\x23\x23\x23\x22\x22\x22\x22\x22\x22\x21\x21\x21\x21\x21\x20\x20\x20\x20\x20\x20\x20\x20\x43\x43\x43\x43\x43\x43\x66\x66\x66\x66\x66\x89\x89\x89\x89\x89\xac\xac\xac\xac\xac\xac\xa5\xa5\xa5\xa5\xa5\xa5\xa5\xa5\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x97\x97\x97\x97\x97\x97\x97\x97\x97\x98\x98\x98\x98\x98\x99\x99\x99\x99\x99\x99\x9a\x9a\x9a\x9a\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x78\x78\x78\x78\x55\x55\x55\x55\x55\x55\x32\x32\x32\x32\x32\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x16\x16\x16\x16\x16\x16\x16\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x24\x24\x02\x04\x07\x03\x03\x03\x03\x03\x03\x03\x03\x03\x03\x03\x02\x07\x24\x24\x24\x23\x23\x23\x23\x22\x22\x22\x22\x22\x22\x22\x21\x21\x21\x21\x21\x20\x20\x20\x20\x20\x20\x20\x20\x43\x43\x43\x43\x43\x43\x66\x66\x66\x66\x66\x66\x89\x89\x89\x89\xac\xac\xac\xac\xac\xa5\xa5\xa5\xa5\xa5\xa5\xa5\xa5\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x97\x97\x97\x97\x97\x97\x97\x97\x97\x97\x98\x98\x98\x98\x98\x98\x99\x99\x99\x99\x99\x99\x9a\x9a\x9a\x9a\x9b\x9b\x9b\x9b\x9b\x9b\x78\x78\x78" \
+"\x78\x55\x55\x55\x55\x55\x55\x55\x32\x32\x32\x32\x32\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x16\x16\x16\x16\x16\x16\x16\x16\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x24\x02\x04\x07\x03\x03\x03\x03\x03\x03\x03\x03\x03\x03\x03\x02\x07\x24\x24\x23\x23\x23\x23\x23\x22\x22\x22\x22\x22\x22\x21\x21\x21\x21\x21\x21\x20\x20\x20\x20\x20\x20\x20\x20\x43\x43\x43\x43\x43\x43\x66\x66\x66\x66\x66\x66\x66\x89\x89\x89\x89\xac\xac\xac\xac\xa5\xa5\xa5\xa5\xa5\xa5\xa5\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x97\x97\x97\x97\x97\x97\x97\x97\x97\x97\x98\x98\x98\x98\x98\x98\x99\x99\x99\x99\x99\x99\x9a\x9a\x9a\x9a\x9a\x9b\x9b\x9b\x9b\x78\x78\x78\x78\x78\x55\x55\x55\x55\x55\x55\x32\x32\x32\x32\x32\x32\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x16\x16\x16\x16\x16\x16\x16\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x24\x02\x04\x07\x03\x03\x03\x03\x03\x03\x03\x03\x03\x03\x03\x02\x07\x24\x23\x23\x23\x23\x23\x22\x22\x22\x22\x22\x22\x22\x21\x21\x21\x21\x21\x21\x20\x20\x20\x20\x20\x20\x20\x20\x20\x43\x43\x43\x43\x43\x43\x66\x66\x66\x66\x66\x66\x89\x89\x89\x89\x89\xac" \
+"\xac\xa5\xa5\xa5\xa5\xa5\xa5\xa5\xa5\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x97\x97\x97\x97\x97\x97\x97\x97\x97\x97\x98\x98\x98\x98\x98\x98\x98\x99\x99\x99\x99\x99\x99\x9a\x9a\x9a\x9a\x9a\x9b\x9b\x9b\x78\x78\x78\x78\x55\x55\x55\x55\x55\x55\x55\x32\x32\x32\x32\x32\x32\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x16\x16\x16\x16\x16\x16\x16\x16\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x02\x04\x07\x03\x03\x03\x03\x03\x03\x03\x03\x03\x03\x03\x02\x07\x1d\x1c\x1c\x1c\x1c\x1b\x1b\x1b\x1b\x1b\x1b\x1b\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x19\x19\x19\x19\x19\x19\x19\x19\x19\x3c\x3c\x3c\x3c\x3c\x3c\x5f\x5f\x5f\x5f\x5f\x5f\x5f\x82\x82\x82\x82\x82\xa5\xa5\xa5\xa5\xa5\xa5\xa5\xa5\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x97\x97\x97\x97\x97\x97\x97\x97\x97\x97\x97\x98\x98\x98\x98\x98\x98\x98\x99\x99\x99\x99\x99\x99\x99\x9a\x9a\x9a\x9a\x9a\x9b\x78\x78\x78\x78\x55\x55\x55\x55\x55\x55\x55\x32\x32\x32\x32\x32\x32\x32\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x16\x16\x16\x16\x16\x16\x16\x16\x16\x1d\x1d\x1d\x1d\x1d\x1d\x1d\x02\x04\x07\x03\x03\x03\x03\x03\x03\x03" \
+"\x03\x03\x03\x03\x02\x07\x1c\x1c\x1c\x1c\x1b\x1b\x1b\x1b\x1b\x1b\x1b\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x19\x19\x19\x19\x19\x19\x19\x19\x19\x19\x3c\x3c\x3c\x3c\x3c\x3c\x3c\x5f\x5f\x5f\x5f\x5f\x5f\x5f\x82\x82\x82\x82\x82\x82\x82\x82\x82\x82\x82\x7b\x7b\x7b\x7b\x7b\x7b\x7b\x7b\x7b\x74\x74\x74\x74\x74\x74\x74\x74\x74\x74\x74\x74\x75\x75\x75\x75\x75\x75\x75\x76\x76\x76\x76\x76\x76\x76\x77\x77\x77\x77\x77\x77\x77\x77\x77\x54\x54\x54\x54\x54\x54\x54\x31\x31\x31\x31\x31\x31\x31\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x15\x15\x15\x15\x15\x15\x15\x15\x1c\x1c\x1c\x1c\x1c\x1c\x1c\x02\x04\x07\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x07\x1c\x1c\x1c\x1c\x1b\x1b\x1b\x1b\x1b\x1b\x1b\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x19\x19\x19\x19\x19\x19\x19\x19\x19\x19\x3c\x3c\x3c\x3c\x3c\x3c\x3c\x3c\x5f\x5f\x5f\x5f\x5f\x5f\x5f\x82\x82\x82\x82\x82\x82\x82\x82\x82\x82\x7b\x7b\x7b\x7b\x7b\x7b\x7b\x7b\x7b\x74\x74\x74\x74\x74\x74\x74\x74\x74\x74\x74\x74\x75\x75\x75\x75\x75\x75\x75\x75\x76\x76\x76\x76\x76\x76\x76\x77\x77\x77\x77\x77\x77\x54" \
+"\x54\x54\x54\x54\x54\x54\x54\x31\x31\x31\x31\x31\x31\x31\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x15\x15\x15\x15\x15\x15\x15\x15\x15\x1c\x1c\x1c\x1c\x1c\x1c\x02\x04\x07\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x07\x1c\x1c\x1c\x1b\x1b\x1b\x1b\x1b\x1b\x1b\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x19\x19\x19\x19\x19\x19\x19\x19\x19\x19\x3c\x3c\x3c\x3c\x3c\x3c\x3c\x3c\x5f\x5f\x5f\x5f\x5f\x5f\x5f\x5f\x82\x82\x82\x82\x82\x82\x82\x82\x7b\x7b\x7b\x7b\x7b\x7b\x7b\x7b\x7b\x74\x74\x74\x74\x74\x74\x74\x74\x74\x74\x74\x74\x74\x75\x75\x75\x75\x75\x75\x75\x75\x76\x76\x76\x76\x76\x76\x76\x77\x77\x77\x77\x77\x77\x54\x54\x54\x54\x54\x54\x54\x31\x31\x31\x31\x31\x31\x31\x31\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x15\x15\x15\x15\x15\x15\x15\x15\x15\x1c\x1c\x1c\x1c\x1c\x02\x04\x07\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x07\x1c\x1c\x1b\x1b\x1b\x1b\x1b\x1b\x1b\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x19\x19\x19\x19\x19\x19\x19\x19\x19\x19\x19\x3c\x3c\x3c\x3c\x3c\x3c\x3c\x3c\x5f\x5f\x5f\x5f\x5f\x5f\x5f" \
+"\x5f\x82\x82\x82\x82\x82\x82\x7b\x7b\x7b\x7b\x7b\x7b\x7b\x7b\x7b\x7b\x74\x74\x74\x74\x74\x74\x74\x74\x74\x74\x74\x74\x74\x74\x75\x75\x75\x75\x75\x75\x75\x75\x76\x76\x76\x76\x76\x76\x76\x76\x77\x77\x77\x54\x54\x54\x54\x54\x54\x54\x54\x31\x31\x31\x31\x31\x31\x31\x31\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x1c\x1c\x1c\x1c\x02\x04\x07\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x07\x1b\x1b\x1b\x1b\x1b\x1b\x1b\x1b\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x19\x19\x19\x19\x19\x19\x19\x19\x19\x19\x19\x19\x3c\x3c\x3c\x3c\x3c\x3c\x3c\x3c\x3c\x5f\x5f\x5f\x5f\x5f\x5f\x5f\x5f\x82\x82\x82\x82\x7b\x7b\x7b\x7b\x7b\x7b\x7b\x7b\x7b\x7b\x74\x74\x74\x74\x74\x74\x74\x74\x74\x74\x74\x74\x74\x74\x74\x75\x75\x75\x75\x75\x75\x75\x75\x75\x76\x76\x76\x76\x76\x76\x76\x76\x54\x54\x54\x54\x54\x54\x54\x54\x31\x31\x31\x31\x31\x31\x31\x31\x31\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x0e\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x1c\x1c\x1c\x02\x04\x07\x02\x02\x02\x02\x02" \
+"\x02\x02\x02\x02\x02\x02\x02\x07\x1b\x1b\x1b\x1b\x1b\x1b\x1b\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x19\x19\x19\x19\x19\x19\x19\x19\x19\x19\x19\x19\x19\x3c\x3c\x3c\x3c\x3c\x3c\x3c\x3c\x3c\x5f\x5f\x5f\x5f\x5f\x5f\x5f\x5f\x5f\x5f\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x52\x52\x52\x52\x52\x52\x52\x52\x52\x52\x53\x53\x53\x53\x53\x53\x53\x53\x53\x53\x53\x53\x53\x53\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x1b\x1b\x02\x04\x07\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x07\x1b\x1b\x1b\x1b\x1b\x1b\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x1a\x19\x19\x19\x19\x19\x19\x19\x19\x19\x19\x19\x19\x19\x3c\x3c\x3c\x3c\x3c\x3c\x3c\x3c\x3c\x3c\x5f\x5f\x5f\x5f\x5f\x5f\x5f\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x52\x52\x52\x52\x52\x52\x52\x52\x52\x52\x53\x53\x53\x53\x53\x53\x53\x53" \
+"\x53\x53\x53\x53\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x02\x04\x07\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x02\x07\x14\x14\x14\x14\x14\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x35\x35\x35\x35\x35\x35\x35\x35\x35\x35\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x52\x52\x52\x52\x52\x52\x52\x52\x52\x52\x52\x53\x53\x53\x53\x53\x53\x53\x53\x53\x53\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x02\x04\x07\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x02\x07\x14\x14\x14\x14\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x35\x35\x35\x35\x35\x35\x35\x35\x35\x35\x35" \
+"\x35\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x52\x52\x52\x52\x52\x52\x52\x52\x52\x52\x52\x52\x53\x53\x53\x53\x53\x53\x53\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x14\x14\x14\x14\x14\x14\x14\x14\x14\x14\x02\x04\x07\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x02\x07\x14\x14\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x35\x35\x35\x35\x35\x35\x35\x35\x35\x35\x35\x35\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x52\x52\x52\x52\x52\x52\x52\x52\x52\x52\x52\x52\x53\x53\x53\x53\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x14\x14\x14\x14\x14\x14\x14\x14\x14\x02\x04\x07\x01\x01\x01" \
+"\x01\x01\x01\x01\x01\x01\x01\x01\x02\x07\x14\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x35\x35\x35\x35\x35\x35\x35\x35\x35\x35\x35\x35\x58\x58\x58\x58\x58\x58\x58\x58\x58\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x51\x52\x52\x52\x52\x52\x52\x52\x52\x52\x52\x52\x52\x53\x53\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x30\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x0d\x14\x14\x14\x14\x14\x14\x14\x02\x04\x07\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x02\x07\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x35\x35\x35\x35\x35\x35\x35\x35\x35\x35\x35\x35\x35\x35\x35\x35\x35\x35\x35\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f" \
+"\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x13\x13\x13\x13\x13\x13\x02\x04\x07\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x02\x07\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x35\x35\x35\x35\x35\x35\x35\x35\x35\x35\x35\x35\x35\x35\x35\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x13\x13\x13\x13\x02\x04\x07\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x02\x07\x13\x13\x13\x13\x13\x13\x01\x01\x01\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x12\x01\x01\x01" \
+"\x35\x35\x35\x35\x35\x35\x35\x35\x35\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x13\x13\x02\x04\x07\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x02\x07\x0c\x0c\x0c\x0c\x01\x01\x01\x01\x01\x01\x01\x12\x12\x12\x12\x12\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x12\x12\x12\x12\x01\x01\x01\x01\x01\x01\x01\x01\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x01\x01\x01\x01\x2f\x2f\x2f\x2f\x2f\x2f\x2f\x01\x01\x01\x01\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x02\x04\x07\x0b" \
+"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x02\x07\x0c\x01\x01\x01\x01\x01\x01\x01\x01\x01\x12\x12\x12\x12\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x12\x12\x12\x12\x12\x01\x01\x01\x01\x01\x01\x01\x01\x01\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x02\x04\x07\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x02\x07\x01\x01\x01\x01\x01\x01\x01\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x01\x01\x01\x01\x01\x01\x01\x01\x01\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x2e\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x01\x01\x01\x01\x01" \
+"\x01\x01\x01\x01\x01\x01\x01\x01\x01\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x0c\x01\x02\x04\x07\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x02\x07\x0c\x0c\x0c\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x2e\x2e\x2e\x2e\x2e\x2e\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0c\x0c\x02\x04\x07\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x02\x07\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b" \
+"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x02\x04\x07\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x02\x07\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x02\x04" \
+"\x07\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x02\x07\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x02\x04\x07\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x02\x07\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b" \
+"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x02\x04\x07\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x02\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x04\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x03\x01\x00\x14\x00\x3e\x33\x00\x00\x00\x01\x00\x00\x38\x42\x49\x4d\x03\xed\x00\x00\x00\x00\x00\x10\x00\x48\x00\x00\x00\x01\x00\x01\x00\x48\x00\x00\x00" \
+"\x01\x00\x01\x38\x42\x49\x4d\x03\xf3\x00\x00\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x38\x42\x49\x4d\x03\xf5\x00\x00\x00\x00\x00\x48\x00\x2f\x66\x66\x00\x01\x00\x6c\x66\x66\x00\x06\x00\x00\x00\x00\x00\x00\x00\x2f\x66\x66\x00\x01\x00\xa1\x99\x9a\x00\x06\x00\x00\x00\x00\x00\x00\x00\x32\x00\x00\x00\x01\x00\x5a\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x35\x00\x00\x00\x01\x00\x2d\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x38\x42\x49\x4d\x03\xf8\x00\x00\x00\x00\x00\x70\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x03\xe8\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x03\xe8\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x03\xe8\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x03\xe8\x00\x00\x00\x00\x00\x00\x32\x33\x00\x00\x54\x52\x55\x45\x56\x49\x53\x49\x4f\x4e\x2d\x58\x46\x49\x4c\x45\x2e" \
+"\x00"};
diff --git a/source/blender/src/cmovie.tga.c b/source/blender/src/cmovie.tga.c
new file mode 100644
index 00000000000..391c032168d
--- /dev/null
+++ b/source/blender/src/cmovie.tga.c
@@ -0,0 +1,205 @@
+/* DataToC output of file <cmovie_tga> */
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+int datatoc_cmovie_tga_size= 6247;
+char datatoc_cmovie_tga[]= {"\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x40\x00\x34\x00\x20\x00\x01\x0c\x0c\x0c\xff\x0d\x0d\x0d\xff\x82\xe0\xe0\xe0\xff\x01\xdf\xdf\xdf\xff\x0d\x0d\x0d\xff\x83\x0c\x0c\x0c\xff\x17\xfe\xfe\xfe\xff\xfd\xfd\xfd\xff\xfd\xfd\xfd\xff\xfe\xfe\xfe\xff\x50\x50\x50\xff\x9c\x9c\x9c\xff\x9c\x9c\x9c\xff\x9d\x9d\x9d\xff\xac\xac\xac\xff\xb8\xb8\xb8\xff\xb6\xb6\xb6\xff\xa9\xa9\xa9\xff\x9c\x9c\x9c\xff\xa4\xa4\xa4" \
+"\xff\xb2\xb2\xb2\xff\x3b\x35\x35\xff\x58\x51\x51\xff\xa3\x9c\x9c\xff\x9a\x97\x97\xff\xb8\xb8\xb8\xff\xaf\xae\xae\xff\x47\x42\x42\xff\x86\x80\x80\xff\xb4\xb4\xb4\xff\x8c\xb7\xb7\xb7\xff\x84\xb8\xb8\xb8\xff\x83\x0c\x0c\x0c\xff\x00\x0d\x0d\x0d\xff\x82\xe0\xe0\xe0\xff\x01\xdf\xdf\xdf\xff\x0d\x0d\x0d\xff\x8b\x0c\x0c\x0c\xff\x83\xfe\xfe\xfe\xff\x13\x52\x52\x52\xff\x9f\x9f\x9f\xff\xa0\xa0\xa0\xff\xa9\xa9\xa9\xff\xb6\xb6\xb6\xff\xb7\xb7\xb7\xff\xac\xac\xac\xff\x9d\x9d\x9d\xff\x9c\x9c\x9c\xff\xa6\xa6\xa6\xff\xa6\xa6\xa6\xff\x38\x32\x32\xff\x72\x6a\x6a\xff\x86\x80\x80\xff\xaf\xaf\xaf\xff\xb7\xb7\xb7\xff\x5d\x5a\x5a\xff\x4d\x46\x46\xff\x9a\x93\x93\xff\xb4\xb4\xb4\xff\x8b\xb7\xb7\xb7\xff\x85\xb8\xb8\xb8\xff\x95\x0c\x0c\x0c\xff\x83\xfe\xfe\xfe\xff\x13\x5a\x5a\x5a\xff\xb3\xb3\xb3\xff\xb4\xb4\xb4\xff\xb7\xb7\xb7\xff\xb8\xb8\xb8\xff\xb5\xb5\xb5\xff\xa2\xa2\xa2\xff\x9c\x9c\x9c\xff\x9d\x9d\x9d\xff\xad\xad\xad\xff\xb8\xb8\xb8\xff\x91\x8f\x8f\xff\x8e\x8b\x8b\xff\xad\xac\xac\xff\xb8\xb8\xb8\xff\x9a\x99\x99\xff\x33\x2c\x2c\xff\x84" \
+"\x7d\x7d\xff\x9e\x99\x99\xff\xb6\xb6\xb6\xff\x8b\xb7\xb7\xb7\xff\x85\xb8\xb8\xb8\xff\x8b\x0c\x0c\x0c\xff\x00\x0d\x0d\x0d\xff\x82\xe0\xe0\xe0\xff\x01\xdf\xdf\xdf\xff\x0d\x0d\x0d\xff\x83\x0c\x0c\x0c\xff\x83\xc3\x73\x00\xff\x00\x5c\x5c\x5c\xff\x83\xb8\xb8\xb8\xff\x04\xb5\xb5\xb5\xff\xa3\xa3\xa3\xff\x9e\x9e\x9e\xff\xa7\xa7\xa7\xff\xb6\xb6\xb6\xff\x83\xb8\xb8\xb8\xff\x04\xb7\xb7\xb7\xff\x92\x90\x90\xff\x43\x3b\x3b\xff\x7b\x74\x74\xff\xa0\x9d\x9d\xff\x89\xb7\xb7\xb7\xff\x01\xb6\xb6\xb6\xff\xb7\xb7\xb7\xff\x86\xb8\xb8\xb8\xff\x83\x0c\x0c\x0c\xff\x00\x0d\x0d\x0d\xff\x82\xe0\xe0\xe0\xff\x03\xdf\xdf\xdf\xff\x0d\x0d\x0d\xff\x0c\x0c\x0c\xff\x0c\x0c\x0c\xff\x83\xe0\xe0\xe0\xff\x01\xdf\xdf\xdf\xff\xdf\xdf\xdf\xff\x83\x0c\x0c\x0c\xff\x83\xc3\x73\x00\xff\x00\x5c\x5c\x5c\xff\x83\xb8\xb8\xb8\xff\x03\xb7\xb7\xb7\xff\xb3\xb3\xb3\xff\xb2\xb2\xb2\xff\xb7\xb7\xb7\xff\x83\xb8\xb8\xb8\xff\x04\xb7\xb7\xb7\xff\xb7\xb7\xb7\xff\xb6\xb6\xb6\xff\x91\x8f\x8f\xff\xa2\xa0\xa0\xff\x8b\xb7\xb7\xb7\xff\x87\xb8\xb8\xb8\xff\x83\x0c\x0c\x0c\xff\x83" \
+"\xe0\xe0\xe0\xff\x03\xdf\xdf\xdf\xff\xdf\xdf\xdf\xff\x0c\x0c\x0c\xff\x0c\x0c\x0c\xff\x83\xe0\xe0\xe0\xff\x01\xdf\xdf\xdf\xff\xdf\xdf\xdf\xff\x83\x0c\x0c\x0c\xff\x83\xc3\x73\x00\xff\x00\x5c\x5c\x5c\xff\x89\xb8\xb8\xb8\xff\x01\xb7\xb7\xb7\xff\xb8\xb8\xb8\xff\x8f\xb7\xb7\xb7\xff\x88\xb8\xb8\xb8\xff\x83\x0c\x0c\x0c\xff\x83\xe0\xe0\xe0\xff\x04\xdf\xdf\xdf\xff\xdf\xdf\xdf\xff\x0c\x0c\x0c\xff\x0c\x0c\x0c\xff\x0d\x0d\x0d\xff\x82\xe0\xe0\xe0\xff\x01\xdf\xdf\xdf\xff\x0d\x0d\x0d\xff\xb1\x0c\x0c\x0c\xff\x00\x0d\x0d\x0d\xff\x82\xe0\xe0\xe0\xff\x01\xdf\xdf\xdf\xff\x0d\x0d\x0d\xff\xff\x0c\x0c\x0c\xff\x81\x0c\x0c\x0c\xff\x00\x0d\x0d\x0d\xff\x82\xe0\xe0\xe0\xff\x01\xdf\xdf\xdf\xff\x0d\x0d\x0d\xff\x83\x0c\x0c\x0c\xff\x83\xfe\xfe\xfe\xff\x00\x5c\x5c\x5c\xff\x85\xb8\xb8\xb8\xff\x00\xb7\xb7\xb7\xff\x83\xb6\xb6\xb6\xff\x8d\xb8\xb8\xb8\xff\x02\xb7\xb7\xb7\xff\xb7\xb7\xb7\xff\xb8\xb8\xb8\xff\x82\xb7\xb7\xb7\xff\x85\xb8\xb8\xb8\xff\x83\x0c\x0c\x0c\xff\x00\x0d\x0d\x0d\xff\x82\xe0\xe0\xe0\xff\x03\xdf\xdf\xdf\xff\x0d\x0d\x0d\xff\x0c\x0c" \
+"\x0c\xff\x0c\x0c\x0c\xff\x83\xe0\xe0\xe0\xff\x01\xdf\xdf\xdf\xff\xdf\xdf\xdf\xff\x83\x0c\x0c\x0c\xff\x83\xfe\xfe\xfe\xff\x00\x5c\x5c\x5c\xff\x83\xb8\xb8\xb8\xff\x09\xb6\xb6\xb6\xff\xb2\xb2\xb2\xff\xae\xae\xae\xff\xa9\xa9\xa9\xff\xa6\xa6\xa6\xff\xa6\xa6\xa6\xff\xa8\xa8\xa8\xff\xab\xab\xab\xff\xb2\xb2\xb2\xff\xb6\xb6\xb6\xff\x89\xb8\xb8\xb8\xff\x86\xb7\xb7\xb7\xff\x85\xb8\xb8\xb8\xff\x83\x0c\x0c\x0c\xff\x83\xe0\xe0\xe0\xff\x03\xdf\xdf\xdf\xff\xdf\xdf\xdf\xff\x0c\x0c\x0c\xff\x0c\x0c\x0c\xff\x83\xe0\xe0\xe0\xff\x01\xdf\xdf\xdf\xff\xdf\xdf\xdf\xff\x83\x0c\x0c\x0c\xff\x83\xe0\xb8\x7f\xff\x06\x5c\x5c\x5c\xff\xb8\xb8\xb8\xff\xb8\xb8\xb8\xff\xb7\xb7\xb7\xff\xb1\xb1\xb1\xff\xa8\xa8\xa8\xff\xa0\xa0\xa0\xff\x85\x9c\x9c\x9c\xff\x05\x9e\x9e\x9e\xff\xa4\xa4\xa4\xff\xb0\xb0\xb0\xff\xb9\xb9\xb9\xff\xba\xba\xba\xff\xb9\xb9\xb9\xff\x86\xb8\xb8\xb8\xff\x85\xb7\xb7\xb7\xff\x85\xb8\xb8\xb8\xff\x83\x0c\x0c\x0c\xff\x83\xe0\xe0\xe0\xff\x04\xdf\xdf\xdf\xff\xdf\xdf\xdf\xff\x0c\x0c\x0c\xff\x0c\x0c\x0c\xff\x0d\x0d\x0d\xff\x82\xe0\xe0\xe0" \
+"\xff\x01\xdf\xdf\xdf\xff\x0d\x0d\x0d\xff\x83\x0c\x0c\x0c\xff\x83\xc3\x73\x00\xff\x04\x5c\x5c\x5c\xff\xb8\xb8\xb8\xff\xb6\xb6\xb6\xff\xae\xae\xae\xff\xa1\xa1\xa1\xff\x87\x9c\x9c\x9c\xff\x09\x9d\x9d\x9d\xff\xa0\xa0\xa0\xff\xa3\xa3\xa3\xff\xa9\xa9\xa9\xff\x9c\x9b\x9c\xff\x8c\x8a\x8b\xff\x7f\x7e\x7e\xff\x8c\x8a\x8b\xff\xa1\xa1\xa1\xff\xb5\xb5\xb5\xff\x83\xb8\xb8\xb8\xff\x84\xb7\xb7\xb7\xff\x85\xb8\xb8\xb8\xff\x83\x0c\x0c\x0c\xff\x00\x0d\x0d\x0d\xff\x82\xe0\xe0\xe0\xff\x01\xdf\xdf\xdf\xff\x0d\x0d\x0d\xff\x8b\x0c\x0c\x0c\xff\x83\xc3\x73\x00\xff\x03\x5c\x5c\x5c\xff\xb7\xb7\xb7\xff\xac\xac\xac\xff\x9f\x9f\x9f\xff\x87\x9c\x9c\x9c\xff\x0e\x9d\x9d\x9d\xff\xa0\xa0\xa0\xff\x9f\x9f\x9f\xff\x6e\x6c\x6c\xff\x36\x31\x32\xff\x21\x1b\x1c\xff\x20\x1a\x1b\xff\x1f\x19\x1a\xff\x1e\x19\x1a\xff\x24\x1f\x20\xff\x42\x3e\x3f\xff\x84\x83\x83\xff\xb2\xb2\xb2\xff\xb8\xb8\xb8\xff\xb8\xb8\xb8\xff\x84\xb7\xb7\xb7\xff\x85\xb8\xb8\xb8\xff\x95\x0c\x0c\x0c\xff\x83\xe0\xb8\x7f\xff\x02\x5c\x5c\x5c\xff\xb1\xb1\xb1\xff\xa0\xa0\xa0\xff\x88\x9c\x9c\x9c" \
+"\xff\x0d\x9d\x9d\x9d\xff\x96\x96\x96\xff\x42\x3e\x3f\xff\x21\x1b\x1c\xff\x1e\x22\x20\xff\x16\x3e\x34\xff\x10\x4f\x41\xff\x0e\x53\x44\xff\x10\x41\x35\xff\x14\x1f\x1c\xff\x19\x14\x15\xff\x1e\x19\x1a\xff\x45\x41\x42\xff\xa2\xa1\xa1\xff\x85\xb7\xb7\xb7\xff\x85\xb8\xb8\xb8\xff\x8b\x0c\x0c\x0c\xff\x00\x0d\x0d\x0d\xff\x82\xe0\xe0\xe0\xff\x01\xdf\xdf\xdf\xff\x0d\x0d\x0d\xff\x83\x0c\x0c\x0c\xff\x83\xfe\xfe\xfe\xff\x01\x5a\x5a\x5a\xff\xa5\xa5\xa5\xff\x89\x9c\x9c\x9c\xff\x0e\x96\x96\x96\xff\x41\x3d\x3e\xff\x20\x1d\x1e\xff\x14\x4d\x3f\xff\x07\x98\x78\xff\x05\xaf\x8a\xff\x05\xbc\x94\xff\x05\xbb\x92\xff\x05\xba\x92\xff\x05\xa0\x7d\xff\x09\x62\x4d\xff\x10\x21\x1c\xff\x19\x14\x15\xff\x2f\x2a\x2b\xff\x99\x98\x99\xff\x84\xb7\xb7\xb7\xff\x85\xb8\xb8\xb8\xff\x83\x0c\x0c\x0c\xff\x00\x0d\x0d\x0d\xff\x82\xe0\xe0\xe0\xff\x03\xdf\xdf\xdf\xff\x0d\x0d\x0d\xff\x0c\x0c\x0c\xff\x0c\x0c\x0c\xff\x83\xe0\xe0\xe0\xff\x01\xdf\xdf\xdf\xff\xdf\xdf\xdf\xff\x83\x0c\x0c\x0c\xff\x05\xfe\xfe\xfe\xff\xfd\xfd\xfd\xff\xfd\xfd\xfd\xff\xfe\xfe\xfe\xff\x55" \
+"\x55\x55\xff\x9d\x9d\x9d\xff\x88\x9c\x9c\x9c\xff\x10\x9b\x9b\x9b\xff\x48\x45\x46\xff\x20\x1b\x1c\xff\x11\x6a\x55\xff\x06\x9d\x79\xff\x06\xa8\x82\xff\x06\xb2\x8a\xff\x06\xc3\x96\xff\x06\xd1\xa4\xff\x06\xd0\xa3\xff\x06\xbd\x94\xff\x04\xad\x88\xff\x05\x88\x6a\xff\x0b\x37\x2c\xff\x16\x12\x12\xff\x31\x2d\x2e\xff\xa2\xa2\xa2\xff\x84\xb7\xb7\xb7\xff\x84\xb8\xb8\xb8\xff\x83\x0c\x0c\x0c\xff\x83\xe0\xe0\xe0\xff\x03\xdf\xdf\xdf\xff\xdf\xdf\xdf\xff\x0c\x0c\x0c\xff\x0c\x0c\x0c\xff\x83\xe0\xe0\xe0\xff\x01\xdf\xdf\xdf\xff\xdf\xdf\xdf\xff\x83\x0c\x0c\x0c\xff\x83\xfe\xfe\xfe\xff\x01\x55\x55\x55\xff\x9e\x9e\x9e\xff\x88\x9c\x9c\x9c\xff\x11\x75\x74\x75\xff\x22\x1d\x1e\xff\x1a\x48\x3d\xff\x06\x9f\x7b\xff\x06\xaf\x8a\xff\x06\xb4\x8c\xff\x06\xc0\x95\xff\x08\xc9\x9c\xff\x09\xcd\xa3\xff\x08\xc5\x9b\xff\x07\xca\x9f\xff\x05\xba\x92\xff\x04\xa5\x81\xff\x04\x90\x71\xff\x0b\x33\x28\xff\x17\x12\x12\xff\x4d\x49\x4a\xff\xb3\xb3\xb3\xff\x83\xb7\xb7\xb7\xff\x84\xb8\xb8\xb8\xff\x83\x0c\x0c\x0c\xff\x83\xe0\xe0\xe0\xff\x04\xdf\xdf\xdf\xff\xdf\xdf" \
+"\xdf\xff\x0c\x0c\x0c\xff\x0c\x0c\x0c\xff\x0d\x0d\x0d\xff\x82\xe0\xe0\xe0\xff\x01\xdf\xdf\xdf\xff\x0d\x0d\x0d\xff\x83\x0c\x0c\x0c\xff\x83\xc3\x73\x00\xff\x02\x5b\x5b\x5b\xff\xb0\xb0\xb0\xff\xa2\xa2\xa2\xff\x86\x9c\x9c\x9c\xff\x12\x9b\x9b\x9b\xff\x3c\x39\x39\xff\x24\x1f\x20\xff\x0e\x92\x75\xff\x07\xab\x85\xff\x07\xaf\x88\xff\x07\xbd\x94\xff\x06\x97\x76\xff\x0b\x66\x4f\xff\x13\x3c\x33\xff\x19\x2d\x33\xff\x1d\x39\x46\xff\x17\x61\x5e\xff\x0b\x91\x77\xff\x04\x9d\x7b\xff\x05\x86\x69\xff\x0d\x20\x1b\xff\x1d\x18\x18\xff\x86\x84\x84\xff\x83\xb7\xb7\xb7\xff\x84\xb8\xb8\xb8\xff\x83\x0c\x0c\x0c\xff\x00\x0d\x0d\x0d\xff\x82\xe0\xe0\xe0\xff\x01\xdf\xdf\xdf\xff\x0d\x0d\x0d\xff\x8b\x0c\x0c\x0c\xff\x83\xc3\x73\x00\xff\x02\x5c\x5c\x5c\xff\xb7\xb7\xb7\xff\xa7\xa7\xa7\xff\x86\x9c\x9c\x9c\xff\x13\x8e\x8e\x8e\xff\x27\x23\x23\xff\x1d\x4c\x42\xff\x09\xb3\x8d\xff\x08\xaf\x87\xff\x09\xbf\x95\xff\x08\x9e\x7d\xff\x0b\x48\x39\xff\x1a\x10\x14\xff\x23\x12\x2a\xff\x2c\x19\x47\xff\x2d\x1b\x56\xff\x2b\x1a\x59\xff\x26\x24\x58\xff\x12\x76\x6e\xff" \
+"\x04\xa3\x80\xff\x07\x63\x4d\xff\x13\x0f\x0f\xff\x42\x3e\x3f\xff\xb4\xb4\xb4\xff\x82\xb7\xb7\xb7\xff\x84\xb8\xb8\xb8\xff\x95\x0c\x0c\x0c\xff\x83\xc3\x73\x00\xff\x02\x5c\x5c\x5c\xff\xb6\xb6\xb6\xff\xa3\xa3\xa3\xff\x86\x9c\x9c\x9c\xff\x13\x9b\x9b\x9b\xff\x88\x92\x8f\xff\x0f\xa5\x83\xff\x0a\xba\x93\xff\x0b\xb5\x8d\xff\x0a\xc4\x9b\xff\x08\x6c\x57\xff\x14\x0f\x0e\xff\x1d\x10\x20\xff\x28\x18\x42\xff\x30\x1d\x5d\xff\x36\x21\x72\xff\x39\x23\x82\xff\x37\x23\x85\xff\x2e\x27\x72\xff\x0b\x9a\x82\xff\x04\x97\x74\xff\x0c\x20\x1a\xff\x20\x1a\x1c\xff\x9f\x9e\x9e\xff\x82\xb7\xb7\xb7\xff\x84\xb8\xb8\xb8\xff\x8b\x0c\x0c\x0c\xff\x00\x0d\x0d\x0d\xff\x82\xe0\xe0\xe0\xff\x01\xdf\xdf\xdf\xff\x0d\x0d\x0d\xff\x83\x0c\x0c\x0c\xff\x83\xe0\xb8\x7f\xff\x02\x5b\x5b\x5b\xff\xb3\xb3\xb3\xff\xa4\xa4\xa4\xff\x86\x9c\x9c\x9c\xff\x13\x9d\x9d\x9d\xff\x8b\xa2\x9b\xff\x11\xb9\x96\xff\x0e\xc7\xa0\xff\x0e\xc8\xa0\xff\x0b\xb4\x8e\xff\x0d\x3b\x30\xff\x16\x0b\x10\xff\x21\x14\x2f\xff\x2d\x1c\x52\xff\x36\x22\x70\xff\x4a\x33\x9c\xff\x5d\x45\xc1\xff\x59\x42" \
+"\xc9\xff\x43\x2d\xaa\xff\x1e\x65\x7c\xff\x04\xb5\x8e\xff\x08\x50\x40\xff\x20\x22\x22\xff\x86\x85\x85\xff\x82\xb7\xb7\xb7\xff\x84\xb8\xb8\xb8\xff\x83\x0c\x0c\x0c\xff\x00\x0d\x0d\x0d\xff\x82\xe0\xe0\xe0\xff\x03\xdf\xdf\xdf\xff\x0d\x0d\x0d\xff\x0c\x0c\x0c\xff\x0c\x0c\x0c\xff\x83\xe0\xe0\xe0\xff\x01\xdf\xdf\xdf\xff\xdf\xdf\xdf\xff\x83\x0c\x0c\x0c\xff\x83\xfe\xfe\xfe\xff\x02\x52\x52\x52\xff\xa1\xa1\xa1\xff\x9e\x9e\x9e\xff\x87\x9c\x9c\x9c\xff\x12\x88\xa4\x9d\xff\x14\xb6\x92\xff\x12\xbb\x95\xff\x12\xca\xa1\xff\x0f\xb0\x8a\xff\x0f\x2c\x24\xff\x18\x0c\x17\xff\x26\x15\x3c\xff\x33\x20\x67\xff\x47\x30\x94\xff\x71\x57\xd5\xff\xa3\x87\xfc\xff\x92\x76\xfc\xff\x5b\x41\xda\xff\x2d\x4d\x90\xff\x06\xbc\x92\xff\x05\xaa\x84\xff\x55\xaf\x98\xff\xbc\xbc\xbc\xff\x82\xb7\xb7\xb7\xff\x84\xb8\xb8\xb8\xff\x83\x0c\x0c\x0c\xff\x83\xe0\xe0\xe0\xff\x03\xdf\xdf\xdf\xff\xdf\xdf\xdf\xff\x0c\x0c\x0c\xff\x0c\x0c\x0c\xff\x83\xe0\xe0\xe0\xff\x01\xdf\xdf\xdf\xff\xdf\xdf\xdf\xff\x83\x0c\x0c\x0c\xff\x83\xfe\xfe\xfe\xff\x00\x51\x51\x51\xff\x88\x9c\x9c" \
+"\x9c\xff\x13\x98\x97\x97\xff\x93\x9d\x9a\xff\x45\xb3\x99\xff\x17\xc9\xa1\xff\x17\xca\xa1\xff\x15\xca\xa3\xff\x11\x3c\x31\xff\x17\x0b\x19\xff\x26\x15\x44\xff\x34\x21\x6f\xff\x4f\x37\xa4\xff\x85\x6b\xf0\xff\xc1\xa3\xff\xff\xad\x8f\xff\xff\x66\x4a\xec\xff\x30\x49\x91\xff\x07\xca\x9f\xff\x06\xb7\x8e\xff\x49\xb8\x9e\xff\xbe\xbe\xbe\xff\x82\xb7\xb7\xb7\xff\x84\xb8\xb8\xb8\xff\x83\x0c\x0c\x0c\xff\x83\xe0\xe0\xe0\xff\x04\xdf\xdf\xdf\xff\xdf\xdf\xdf\xff\x0c\x0c\x0c\xff\x0c\x0c\x0c\xff\x0d\x0d\x0d\xff\x82\xe0\xe0\xe0\xff\x01\xdf\xdf\xdf\xff\x0d\x0d\x0d\xff\x83\x0c\x0c\x0c\xff\x83\xfe\xfe\xfe\xff\x00\x55\x55\x55\xff\x88\x9c\x9c\x9c\xff\x16\x7a\x79\x79\xff\x86\x7f\x7f\xff\xa6\xb6\xaf\xff\x23\xd0\xaa\xff\x1e\xdc\xb1\xff\x1d\xe3\xb8\xff\x15\x7e\x65\xff\x18\x0d\x17\xff\x24\x15\x3e\xff\x33\x1f\x6a\xff\x49\x32\x9e\xff\x6f\x54\xdf\xff\x95\x78\xfe\xff\x88\x69\xfe\xff\x5b\x3e\xdf\xff\x26\x76\x91\xff\x07\xcf\xa2\xff\x07\xb8\x90\xff\x4b\xb6\x9c\xff\xbf\xbf\xbf\xff\xb8\xb8\xb8\xff\xb7\xb7\xb7\xff\xb7\xb7\xb7\xff\x84\xb8\xb8\xb8\xff" \
+"\x83\x0c\x0c\x0c\xff\x00\x0d\x0d\x0d\xff\x82\xe0\xe0\xe0\xff\x01\xdf\xdf\xdf\xff\x0d\x0d\x0d\xff\x8b\x0c\x0c\x0c\xff\x83\xc3\x73\x00\xff\x05\x59\x59\x59\xff\xa2\xa2\xa2\xff\x9c\x9c\x9c\xff\x9c\x9c\x9c\xff\x9b\x9b\x9b\xff\x99\x99\x99\xff\x83\x9c\x9c\x9c\xff\x16\x93\x93\x93\xff\x6c\x65\x65\xff\xc1\xba\xb9\xff\x4d\xd8\xb7\xff\x25\xe2\xb8\xff\x24\xe1\xb6\xff\x1f\xd1\xa8\xff\x17\x2a\x28\xff\x21\x14\x32\xff\x2f\x1c\x5b\xff\x3e\x28\x88\xff\x50\x37\xb6\xff\x5f\x42\xdc\xff\x60\x40\xe8\xff\x46\x43\xb6\xff\x12\xd5\xb8\xff\x07\xd3\xa6\xff\x09\x85\x69\xff\x57\x5e\x5a\xff\xab\xa8\xa8\xff\xb8\xb8\xb8\xff\xb7\xb7\xb7\xff\xb7\xb7\xb7\xff\x84\xb8\xb8\xb8\xff\x95\x0c\x0c\x0c\xff\x83\xc3\x73\x00\xff\x20\x5c\x5c\x5c\xff\xac\xac\xac\xff\x9d\x9d\x9d\xff\x8f\x8f\x8f\xff\x4d\x48\x48\xff\x56\x50\x50\xff\x66\x62\x62\xff\x74\x71\x71\xff\x7f\x7c\x7c\xff\x8d\x8a\x8a\xff\x99\x99\x99\xff\x5d\x59\x59\xff\xc2\xba\xba\xff\xa2\xd7\xc9\xff\x2d\xdd\xb5\xff\x2b\xe9\xbf\xff\x29\xef\xc8\xff\x21\xb9\x99\xff\x1a\x28\x2e\xff\x24\x16\x3f\xff\x33\x20\x66" \
+"\xff\x3c\x24\x85\xff\x43\x2b\x9d\xff\x43\x40\xa8\xff\x1e\xbe\xb2\xff\x0a\xea\xba\xff\x07\xd6\xaa\xff\x0c\x53\x42\xff\x79\x72\x72\xff\xa9\xa6\xa6\xff\xb7\xb7\xb7\xff\xb8\xb8\xb8\xff\xb7\xb7\xb7\xff\x84\xb8\xb8\xb8\xff\x8b\x0c\x0c\x0c\xff\x00\x0d\x0d\x0d\xff\x82\xe0\xe0\xe0\xff\x01\xdf\xdf\xdf\xff\x0d\x0d\x0d\xff\x83\x0c\x0c\x0c\xff\x83\xc3\x73\x00\xff\x1d\x5c\x5c\x5c\xff\xb6\xb6\xb6\xff\xa5\xa5\xa5\xff\x65\x62\x62\xff\x43\x3b\x3b\xff\x77\x6f\x6f\xff\xa0\x99\x99\xff\x9f\x98\x98\xff\x91\x8a\x8a\xff\x91\x8f\x8f\xff\x9b\x9b\x9b\xff\x7e\x7d\x7d\xff\x92\x8b\x8b\xff\xd7\xd4\xd2\xff\x5f\xda\xbd\xff\x30\xe0\xb9\xff\x2e\xd7\xb0\xff\x2b\xde\xb7\xff\x25\xbe\x9c\xff\x1f\x71\x63\xff\x21\x48\x55\xff\x26\x4d\x63\xff\x26\x88\x90\xff\x19\xe4\xc7\xff\x10\xeb\xbc\xff\x0b\xdd\xae\xff\x08\xb5\x8f\xff\x25\x34\x2f\xff\x96\x8f\x8f\xff\xb2\xb1\xb1\xff\x82\xb7\xb7\xb7\xff\x84\xb8\xb8\xb8\xff\x83\x0c\x0c\x0c\xff\x00\x0d\x0d\x0d\xff\x82\xe0\xe0\xe0\xff\x03\xdf\xdf\xdf\xff\x0d\x0d\x0d\xff\x0c\x0c\x0c\xff\x0c\x0c\x0c\xff\x83\xe0\xe0\xe0\xff" \
+"\x01\xdf\xdf\xdf\xff\xdf\xdf\xdf\xff\x83\x0c\x0c\x0c\xff\x83\xe0\xb8\x7f\xff\x1d\x5c\x5c\x5c\xff\xb7\xb7\xb7\xff\xb3\xb3\xb3\xff\x98\x98\x98\xff\x4d\x49\x49\xff\x5e\x57\x57\xff\x77\x70\x70\xff\x80\x7c\x7c\xff\x93\x92\x92\xff\x9c\x9c\x9c\xff\x9c\x9c\x9c\xff\x9b\x9b\x9b\xff\x61\x5d\x5d\xff\xcb\xc4\xc4\xff\xca\xda\xd4\xff\x45\xd5\xb2\xff\x31\xd3\xae\xff\x2e\xd0\xab\xff\x2b\xdc\xb8\xff\x29\xe0\xb7\xff\x24\xd8\xae\xff\x20\xe0\xb7\xff\x1b\xea\xbe\xff\x15\xe5\xb7\xff\x10\xe3\xb5\xff\x0c\xd0\xa5\xff\x0d\x69\x55\xff\x70\x6a\x6a\xff\xa3\x9d\x9d\xff\xb8\xb7\xb7\xff\x82\xb7\xb7\xb7\xff\x84\xb8\xb8\xb8\xff\x83\x0c\x0c\x0c\xff\x83\xe0\xe0\xe0\xff\x03\xdf\xdf\xdf\xff\xdf\xdf\xdf\xff\x0c\x0c\x0c\xff\x0c\x0c\x0c\xff\x83\xe0\xe0\xe0\xff\x01\xdf\xdf\xdf\xff\xdf\xdf\xdf\xff\x83\x0c\x0c\x0c\xff\x0a\xfe\xfe\xfe\xff\xfd\xfd\xfd\xff\xfd\xfd\xfd\xff\xfe\xfe\xfe\xff\x59\x59\x59\xff\xae\xae\xae\xff\xb3\xb3\xb3\xff\xb2\xb2\xb2\xff\xa2\xa2\xa2\xff\x90\x90\x90\xff\x97\x97\x97\xff\x84\x9c\x9c\x9c\xff\x10\x92\x92\x92\xff\x77\x73\x73\xff\xe0" \
+"\xd9\xd9\xff\xc7\xdd\xd6\xff\x4e\xce\xaf\xff\x33\xd8\xb4\xff\x2f\xd4\xb0\xff\x2a\xd4\xad\xff\x25\xda\xb1\xff\x21\xd0\xa8\xff\x1b\xda\xb2\xff\x15\xd7\xaf\xff\x0f\xc3\x9c\xff\x0d\x84\x6a\xff\x4f\x55\x52\xff\x9d\x96\x96\xff\xb1\xae\xae\xff\x83\xb7\xb7\xb7\xff\x84\xb8\xb8\xb8\xff\x83\x0c\x0c\x0c\xff\x83\xe0\xe0\xe0\xff\x04\xdf\xdf\xdf\xff\xdf\xdf\xdf\xff\x0c\x0c\x0c\xff\x0c\x0c\x0c\xff\x0d\x0d\x0d\xff\x82\xe0\xe0\xe0\xff\x01\xdf\xdf\xdf\xff\x0d\x0d\x0d\xff\x83\x0c\x0c\x0c\xff\x1f\xfe\xfe\xfe\xff\xfd\xfd\xfd\xff\xfd\xfd\xfd\xff\xfe\xfe\xfe\xff\x4f\x4f\x4f\xff\xa3\xa3\xa3\xff\xb4\xb4\xb4\xff\xb8\xb8\xb8\xff\xb4\xb4\xb4\xff\xa7\xa7\xa7\xff\x9e\x9e\x9e\xff\x9c\x9c\x9c\xff\x9c\x9c\x9c\xff\x9b\x9b\x9b\xff\x96\x96\x96\xff\x85\x83\x83\xff\x95\x94\x94\xff\x89\x89\x89\xff\x85\x80\x80\xff\xe8\xe0\xe0\xff\xd8\xe4\xdf\xff\x76\xdd\xc6\xff\x37\xcd\xab\xff\x2d\xcc\xa8\xff\x27\xd3\xae\xff\x21\xc7\xa1\xff\x1a\xbe\x97\xff\x13\xa6\x84\xff\x18\x73\x5f\xff\x5d\x61\x5f\xff\x9c\x95\x95\xff\xac\xa8\xa8\xff\x84\xb7\xb7\xb7\xff\x84\xb8\xb8" \
+"\xb8\xff\x83\x0c\x0c\x0c\xff\x00\x0d\x0d\x0d\xff\x82\xe0\xe0\xe0\xff\x01\xdf\xdf\xdf\xff\x0d\x0d\x0d\xff\x8b\x0c\x0c\x0c\xff\x83\xfe\xfe\xfe\xff\x01\x51\x51\x51\xff\xb0\xb0\xb0\xff\x82\xb8\xb8\xb8\xff\x16\xb6\xb6\xb6\xff\xaf\xaf\xaf\xff\x90\x90\x90\xff\x68\x65\x65\xff\x5a\x55\x55\xff\x63\x5d\x5d\xff\x88\x81\x81\xff\x9a\x9a\x9a\xff\x9c\x9c\x9c\xff\x8e\x8d\x8d\xff\x90\x8d\x8d\xff\xdf\xd8\xd8\xff\xee\xe7\xe7\xff\xcc\xda\xd4\xff\x8a\xcb\xbc\xff\x5b\xb5\x9f\xff\x48\xa0\x8b\xff\x4b\x8e\x7e\xff\x6b\x84\x7d\xff\x98\x92\x91\xff\xa5\x9e\x9e\xff\xae\xab\xab\xff\xb6\xb6\xb6\xff\x84\xb7\xb7\xb7\xff\x84\xb8\xb8\xb8\xff\x95\x0c\x0c\x0c\xff\x83\xc3\x73\x00\xff\x19\x59\x59\x59\xff\xb7\xb7\xb7\xff\xb8\xb8\xb8\xff\xb8\xb8\xb8\xff\xb5\xb5\xb5\xff\xae\xae\xae\xff\x8f\x8e\x8e\xff\x39\x32\x32\xff\x5f\x58\x58\xff\x91\x8a\x8a\xff\x98\x92\x92\xff\x9d\x9c\x9c\xff\xa7\xa7\xa7\xff\xa7\xa7\xa7\xff\xaa\xaa\xaa\xff\xad\xac\xac\xff\x9a\x9a\x9a\xff\xbf\xbb\xbb\xff\xd9\xd3\xd3\xff\xe2\xda\xda\xff\xd7\xcf\xcf\xff\xca\xc3\xc3\xff\xbf\xb8\xb8\xff" \
+"\xb8\xb1\xb1\xff\xb4\xaf\xaf\xff\xb5\xb3\xb3\xff\x86\xb7\xb7\xb7\xff\x84\xb8\xb8\xb8\xff\x8b\x0c\x0c\x0c\xff\x00\x0d\x0d\x0d\xff\x82\xe0\xe0\xe0\xff\x01\xdf\xdf\xdf\xff\x0d\x0d\x0d\xff\x83\x0c\x0c\x0c\xff\x83\xc3\x73\x00\xff\x17\x5c\x5c\x5c\xff\xb8\xb8\xb8\xff\xb7\xb7\xb7\xff\xb1\xb1\xb1\xff\xa4\xa4\xa4\xff\xa8\xa8\xa8\xff\x71\x6e\x6e\xff\x4a\x42\x42\xff\x7f\x78\x78\xff\x91\x8a\x8a\xff\xa3\xa1\xa1\xff\xb8\xb8\xb8\xff\xb8\xb8\xb8\xff\xb7\xb7\xb7\xff\x8b\x89\x89\xff\xa1\x9e\x9e\xff\xb8\xb8\xb8\xff\xb8\xb8\xb8\xff\xab\xab\xab\xff\xb8\xb7\xb7\xff\xc1\xbe\xbe\xff\xc3\xc1\xc1\xff\xbd\xbb\xbb\xff\xb9\xb8\xb8\xff\x89\xb7\xb7\xb7\xff\x83\xb8\xb8\xb8\xff\x83\x0c\x0c\x0c\xff\x00\x0d\x0d\x0d\xff\x82\xe0\xe0\xe0\xff\x03\xdf\xdf\xdf\xff\x0d\x0d\x0d\xff\x0c\x0c\x0c\xff\x0c\x0c\x0c\xff\x83\xe0\xe0\xe0\xff\x01\xdf\xdf\xdf\xff\xdf\xdf\xdf\xff\x83\x0c\x0c\x0c\xff\x83\xc3\x73\x00\xff\x12\x5c\x5c\x5c\xff\xb4\xb4\xb4\xff\xac\xac\xac\xff\x9f\x9f\x9f\xff\x9c\x9c\x9c\xff\xae\xae\xae\xff\xb3\xb3\xb3\xff\x84\x82\x82\xff\x7d\x7a\x7a\xff" \
+"\x98\x97\x97\xff\xb6\xb6\xb6\xff\xb8\xb8\xb8\xff\xb3\xb3\xb3\xff\x73\x71\x71\xff\x6a\x63\x63\xff\xaf\xae\xae\xff\xb8\xb8\xb8\xff\xb7\xb7\xb7\xff\x97\x95\x95\xff\x8e\xb7\xb7\xb7\xff\x83\xb6\xb6\xb6\xff\x83\x0c\x0c\x0c\xff\x83\xe0\xe0\xe0\xff\x03\xdf\xdf\xdf\xff\xdf\xdf\xdf\xff\x0c\x0c\x0c\xff\x0c\x0c\x0c\xff\x83\xe0\xe0\xe0\xff\x01\xdf\xdf\xdf\xff\xdf\xdf\xdf\xff\x83\x0c\x0c\x0c\xff\x83\xe0\xb8\x7f\xff\x13\x58\x58\x58\xff\xa3\xa3\xa3\xff\x9c\x9c\x9c\xff\x9c\x9c\x9c\xff\xa2\xa2\xa2\xff\xb4\xb4\xb4\xff\xb8\xb8\xb8\xff\xb5\xb5\xb5\xff\xa4\xa4\xa4\xff\xa3\xa3\xa3\xff\xb6\xb6\xb6\xff\xa0\x9f\x9f\xff\x4f\x4a\x4a\xff\x56\x4e\x4e\xff\x95\x8f\x8f\xff\xb5\xb5\xb5\xff\xb8\xb8\xb8\xff\x8e\x8d\x8d\xff\x78\x72\x72\xff\xb6\xb5\xb5\xff\x8c\xb7\xb7\xb7\xff\x84\xb8\xb8\xb8\xff\x83\x0c\x0c\x0c\xff\x83\xe0\xe0\xe0\xff\x04\xdf\xdf\xdf\xff\xdf\xdf\xdf\xff\x0c\x0c\x0c\xff\x0c\x0c\x0c\xff\x0d\x0d\x0d\xff\x82\xe0\xe0\xe0\xff\x01\xdf\xdf\xdf\xff\x0d\x0d\x0d\xff\x83\x0c\x0c\x0c\xff\x17\xfe\xfe\xfe\xff\xfd\xfd\xfd\xff\xfd\xfd\xfd\xff\xfe" \
+"\xfe\xfe\xff\x50\x50\x50\xff\x9c\x9c\x9c\xff\x9c\x9c\x9c\xff\x9d\x9d\x9d\xff\xac\xac\xac\xff\xb8\xb8\xb8\xff\xb6\xb6\xb6\xff\xa9\xa9\xa9\xff\x9c\x9c\x9c\xff\xa4\xa4\xa4\xff\xb2\xb2\xb2\xff\x3b\x35\x35\xff\x58\x51\x51\xff\xa3\x9c\x9c\xff\x9a\x97\x97\xff\xb8\xb8\xb8\xff\xaf\xae\xae\xff\x47\x42\x42\xff\x86\x80\x80\xff\xb4\xb4\xb4\xff\x8c\xb7\xb7\xb7\xff\x84\xb8\xb8\xb8\xff\x83\x0c\x0c\x0c\xff\x00\x0d\x0d\x0d\xff\x82\xe0\xe0\xe0\xff\x01\xdf\xdf\xdf\xff\x0d\x0d\x0d\xff\x8b\x0c\x0c\x0c\xff\x83\xfe\xfe\xfe\xff\x13\x52\x52\x52\xff\x9f\x9f\x9f\xff\xa0\xa0\xa0\xff\xa9\xa9\xa9\xff\xb6\xb6\xb6\xff\xb7\xb7\xb7\xff\xac\xac\xac\xff\x9d\x9d\x9d\xff\x9c\x9c\x9c\xff\xa6\xa6\xa6\xff\xa6\xa6\xa6\xff\x38\x32\x32\xff\x72\x6a\x6a\xff\x86\x80\x80\xff\xaf\xaf\xaf\xff\xb7\xb7\xb7\xff\x5d\x5a\x5a\xff\x4d\x46\x46\xff\x9a\x93\x93\xff\xb4\xb4\xb4\xff\x8b\xb7\xb7\xb7\xff\x85\xb8\xb8\xb8\xff\x95\x0c\x0c\x0c\xff\x83\xfe\xfe\xfe\xff\x13\x5a\x5a\x5a\xff\xb3\xb3\xb3\xff\xb4\xb4\xb4\xff\xb7\xb7\xb7\xff\xb8\xb8\xb8\xff\xb5\xb5\xb5\xff\xa2\xa2\xa2" \
+"\xff\x9c\x9c\x9c\xff\x9d\x9d\x9d\xff\xad\xad\xad\xff\xb8\xb8\xb8\xff\x91\x8f\x8f\xff\x8e\x8b\x8b\xff\xad\xac\xac\xff\xb8\xb8\xb8\xff\x9a\x99\x99\xff\x33\x2c\x2c\xff\x84\x7d\x7d\xff\x9e\x99\x99\xff\xb6\xb6\xb6\xff\x8b\xb7\xb7\xb7\xff\x85\xb8\xb8\xb8\xff\x8b\x0c\x0c\x0c\xff\x00\x0d\x0d\x0d\xff\x82\xe0\xe0\xe0\xff\x01\xdf\xdf\xdf\xff\x0d\x0d\x0d\xff\x83\x0c\x0c\x0c\xff\x83\xc3\x73\x00\xff\x00\x5c\x5c\x5c\xff\x83\xb8\xb8\xb8\xff\x04\xb5\xb5\xb5\xff\xa3\xa3\xa3\xff\x9e\x9e\x9e\xff\xa7\xa7\xa7\xff\xb6\xb6\xb6\xff\x83\xb8\xb8\xb8\xff\x04\xb7\xb7\xb7\xff\x92\x90\x90\xff\x43\x3b\x3b\xff\x7b\x74\x74\xff\xa0\x9d\x9d\xff\x89\xb7\xb7\xb7\xff\x01\xb6\xb6\xb6\xff\xb7\xb7\xb7\xff\x86\xb8\xb8\xb8\xff\x83\x0c\x0c\x0c\xff\x00\x0d\x0d\x0d\xff\x82\xe0\xe0\xe0\xff\x03\xdf\xdf\xdf\xff\x0d\x0d\x0d\xff\x0c\x0c\x0c\xff\x0c\x0c\x0c\xff\x83\xe0\xe0\xe0\xff\x01\xdf\xdf\xdf\xff\xdf\xdf\xdf\xff\x83\x0c\x0c\x0c\xff\x83\xc3\x73\x00\xff\x00\x5c\x5c\x5c\xff\x83\xb8\xb8\xb8\xff\x03\xb7\xb7\xb7\xff\xb3\xb3\xb3\xff\xb2\xb2\xb2\xff\xb7\xb7\xb7\xff" \
+"\x83\xb8\xb8\xb8\xff\x04\xb7\xb7\xb7\xff\xb7\xb7\xb7\xff\xb6\xb6\xb6\xff\x91\x8f\x8f\xff\xa2\xa0\xa0\xff\x8b\xb7\xb7\xb7\xff\x87\xb8\xb8\xb8\xff\x83\x0c\x0c\x0c\xff\x83\xe0\xe0\xe0\xff\x03\xdf\xdf\xdf\xff\xdf\xdf\xdf\xff\x0c\x0c\x0c\xff\x0c\x0c\x0c\xff\x83\xe0\xe0\xe0\xff\x01\xdf\xdf\xdf\xff\xdf\xdf\xdf\xff\x83\x0c\x0c\x0c\xff\x83\xc3\x73\x00\xff\x00\x5c\x5c\x5c\xff\x89\xb8\xb8\xb8\xff\x01\xb7\xb7\xb7\xff\xb8\xb8\xb8\xff\x8f\xb7\xb7\xb7\xff\x88\xb8\xb8\xb8\xff\x83\x0c\x0c\x0c\xff\x83\xe0\xe0\xe0\xff\x04\xdf\xdf\xdf\xff\xdf\xdf\xdf\xff\x0c\x0c\x0c\xff\x0c\x0c\x0c\xff\x0d\x0d\x0d\xff\x82\xe0\xe0\xe0\xff\x01\xdf\xdf\xdf\xff\x0d\x0d\x0d\xff\xb1\x0c\x0c\x0c\xff\x00\x0d\x0d\x0d\xff\x82\xe0\xe0\xe0\xff\x01\xdf\xdf\xdf\xff\x0d\x0d\x0d\xff\xff\x0c\x0c\x0c\xff\x81\x0c\x0c\x0c\xff\x00\x0d\x0d\x0d\xff\x82\xe0\xe0\xe0\xff\x01\xdf\xdf\xdf\xff\x0d\x0d\x0d\xff\x83\x0c\x0c\x0c\xff\x83\xfe\xfe\xfe\xff\x00\x5c\x5c\x5c\xff\x85\xb8\xb8\xb8\xff\x00\xb7\xb7\xb7\xff\x83\xb6\xb6\xb6\xff\x8d\xb8\xb8\xb8\xff\x02\xb7\xb7\xb7\xff\xb7\xb7" \
+"\xb7\xff\xb8\xb8\xb8\xff\x82\xb7\xb7\xb7\xff\x85\xb8\xb8\xb8\xff\x83\x0c\x0c\x0c\xff\x00\x0d\x0d\x0d\xff\x82\xe0\xe0\xe0\xff\x03\xdf\xdf\xdf\xff\x0d\x0d\x0d\xff\x0c\x0c\x0c\xff\x0c\x0c\x0c\xff\x83\xe0\xe0\xe0\xff\x01\xdf\xdf\xdf\xff\xdf\xdf\xdf\xff\x83\x0c\x0c\x0c\xff\x83\xfe\xfe\xfe\xff\x00\x5c\x5c\x5c\xff\x83\xb8\xb8\xb8\xff\x09\xb6\xb6\xb6\xff\xb2\xb2\xb2\xff\xae\xae\xae\xff\xa9\xa9\xa9\xff\xa6\xa6\xa6\xff\xa6\xa6\xa6\xff\xa8\xa8\xa8\xff\xab\xab\xab\xff\xb2\xb2\xb2\xff\xb6\xb6\xb6\xff\x89\xb8\xb8\xb8\xff\x86\xb7\xb7\xb7\xff\x85\xb8\xb8\xb8\xff\x83\x0c\x0c\x0c\xff\x83\xe0\xe0\xe0\xff\x03\xdf\xdf\xdf\xff\xdf\xdf\xdf\xff\x0c\x0c\x0c\xff\x0c\x0c\x0c\xff\x83\xe0\xe0\xe0\xff\x01\xdf\xdf\xdf\xff\xdf\xdf\xdf\xff\x83\x0c\x0c\x0c\xff\x83\xe0\xb8\x7f\xff\x06\x5c\x5c\x5c\xff\xb8\xb8\xb8\xff\xb8\xb8\xb8\xff\xb7\xb7\xb7\xff\xb1\xb1\xb1\xff\xa8\xa8\xa8\xff\xa0\xa0\xa0\xff\x85\x9c\x9c\x9c\xff\x05\x9e\x9e\x9e\xff\xa4\xa4\xa4\xff\xb0\xb0\xb0\xff\xb9\xb9\xb9\xff\xba\xba\xba\xff\xb9\xb9\xb9\xff\x86\xb8\xb8\xb8\xff\x85\xb7\xb7" \
+"\xb7\xff\x85\xb8\xb8\xb8\xff\x83\x0c\x0c\x0c\xff\x83\xe0\xe0\xe0\xff\x04\xdf\xdf\xdf\xff\xdf\xdf\xdf\xff\x0c\x0c\x0c\xff\x0c\x0c\x0c\xff\x0d\x0d\x0d\xff\x82\xe0\xe0\xe0\xff\x01\xdf\xdf\xdf\xff\x0d\x0d\x0d\xff\x83\x0c\x0c\x0c\xff\x83\xc3\x73\x00\xff\x04\x5c\x5c\x5c\xff\xb8\xb8\xb8\xff\xb6\xb6\xb6\xff\xae\xae\xae\xff\xa1\xa1\xa1\xff\x87\x9c\x9c\x9c\xff\x09\x9d\x9d\x9d\xff\xa0\xa0\xa0\xff\xa3\xa3\xa3\xff\xa9\xa9\xa9\xff\x9c\x9b\x9c\xff\x8c\x8a\x8b\xff\x7f\x7e\x7e\xff\x8c\x8a\x8b\xff\xa1\xa1\xa1\xff\xb5\xb5\xb5\xff\x83\xb8\xb8\xb8\xff\x84\xb7\xb7\xb7\xff\x85\xb8\xb8\xb8\xff\x83\x0c\x0c\x0c\xff\x00\x0d\x0d\x0d\xff\x82\xe0\xe0\xe0\xff\x01\xdf\xdf\xdf\xff\x0d\x0d\x0d\xff\x8b\x0c\x0c\x0c\xff\x83\xc3\x73\x00\xff\x03\x5c\x5c\x5c\xff\xb7\xb7\xb7\xff\xac\xac\xac\xff\x9f\x9f\x9f\xff\x87\x9c\x9c\x9c\xff\x0e\x9d\x9d\x9d\xff\xa0\xa0\xa0\xff\x9f\x9f\x9f\xff\x6e\x6c\x6c\xff\x36\x31\x32\xff\x21\x1b\x1c\xff\x20\x1a\x1b\xff\x1f\x19\x1a\xff\x1e\x19\x1a\xff\x24\x1f\x20\xff\x42\x3e\x3f\xff\x84\x83\x83\xff\xb2\xb2\xb2\xff\xb8\xb8\xb8" \
+"\xff\xb8\xb8\xb8\xff\x84\xb7\xb7\xb7\xff\x85\xb8\xb8\xb8\xff\x95\x0c\x0c\x0c\xff\x83\xe0\xb8\x7f\xff\x02\x5c\x5c\x5c\xff\xb1\xb1\xb1\xff\xa0\xa0\xa0\xff\x88\x9c\x9c\x9c\xff\x0d\x9d\x9d\x9d\xff\x96\x96\x96\xff\x42\x3e\x3f\xff\x21\x1b\x1c\xff\x1e\x22\x20\xff\x16\x3e\x34\xff\x10\x4f\x41\xff\x0e\x53\x44\xff\x10\x41\x35\xff\x14\x1f\x1c\xff\x19\x14\x15\xff\x1e\x19\x1a\xff\x45\x41\x42\xff\xa2\xa1\xa1\xff\x85\xb7\xb7\xb7\xff\x85\xb8\xb8\xb8\xff\x8b\x0c\x0c\x0c\xff\x00\x0d\x0d\x0d\xff\x82\xe0\xe0\xe0\xff\x01\xdf\xdf\xdf\xff\x0d\x0d\x0d\xff\x83\x0c\x0c\x0c\xff\x83\xfe\xfe\xfe\xff\x01\x5a\x5a\x5a\xff\xa5\xa5\xa5\xff\x89\x9c\x9c\x9c\xff\x0e\x96\x96\x96\xff\x41\x3d\x3e\xff\x20\x1d\x1e\xff\x14\x4d\x3f\xff\x07\x98\x78\xff\x05\xaf\x8a\xff\x05\xbc\x94\xff\x05\xbb\x92\xff\x05\xba\x92\xff\x05\xa0\x7d\xff\x09\x62\x4d\xff\x10\x21\x1c\xff\x19\x14\x15\xff\x2f\x2a\x2b\xff\x99\x98\x99\xff\x84\xb7\xb7\xb7\xff\x85\xb8\xb8\xb8\xff\x83\x0c\x0c\x0c\xff\x00\x0d\x0d\x0d\xff\x82\xe0\xe0\xe0\xff\x02\xdf\xdf\xdf\xff\x0d\x0d\x0d\xff\x0c\x0c\x0c" \
+"\xff"};
+
+/* these are not the monkeys you are looking for */
+int monkeyo= 4;
+int monkeynv= 271;
+int monkeynf= 250;
+signed char monkeyv[271][3]= {
+{-71,21,98},{-63,12,88},{-57,7,74},{-82,-3,79},{-82,4,92},
+{-82,17,100},{-92,21,102},{-101,12,95},{-107,7,83},
+{-117,31,84},{-109,31,95},{-96,31,102},{-92,42,102},
+{-101,50,95},{-107,56,83},{-82,66,79},{-82,58,92},
+{-82,46,100},{-71,42,98},{-63,50,88},{-57,56,74},
+{-47,31,72},{-55,31,86},{-67,31,97},{-66,31,99},
+{-70,43,100},{-82,48,103},{-93,43,105},{-98,31,105},
+{-93,20,105},{-82,31,106},{-82,15,103},{-70,20,100},
+{-127,55,95},{-127,45,105},{-127,-87,94},{-127,-41,100},
+{-127,-24,102},{-127,-99,92},{-127,52,77},{-127,73,73},
+{-127,115,-70},{-127,72,-109},{-127,9,-106},{-127,-49,-45},
+{-101,-24,72},{-87,-56,73},{-82,-89,73},{-80,-114,68},
+{-85,-121,67},{-104,-124,71},{-127,-126,74},{-71,-18,68},
+{-46,-5,69},{-21,19,57},{-17,55,76},{-36,62,80},
+{-64,77,88},{-86,97,94},{-107,92,97},{-119,63,96},
+{-106,53,99},{-111,39,98},{-101,12,95},{-79,2,90},
+{-64,8,86},{-47,24,83},{-45,38,83},{-50,48,85},
+{-72,56,92},{-95,60,97},{-127,-98,94},{-113,-92,94},
+{-112,-107,91},{-119,-113,89},{-127,-114,88},{-127,-25,96},
+{-127,-18,95},{-114,-19,95},{-111,-29,96},{-116,-37,95},
+{-76,-6,86},{-48,7,80},{-34,26,77},{-32,48,84},
+{-39,53,93},{-71,70,102},{-87,82,107},{-101,79,109},
+{-114,55,108},{-111,-13,104},{-100,-57,91},{-95,-90,88},
+{-93,-105,85},{-97,-117,81},{-106,-119,81},{-127,-121,82},
+{-127,6,93},{-127,27,98},{-85,61,95},{-106,18,96},
+{-110,27,97},{-112,-88,94},{-117,-57,96},{-127,-57,96},
+{-127,-42,95},{-115,-35,100},{-110,-29,102},{-113,-17,100},
+{-122,-16,100},{-127,-26,106},{-121,-19,104},{-115,-20,104},
+{-113,-29,106},{-117,-32,103},{-127,-37,103},{-94,-40,71},
+{-106,-31,91},{-104,-40,91},{-97,-32,71},{-127,-112,88},
+{-121,-111,88},{-115,-105,91},{-115,-95,93},{-127,-100,84},
+{-115,-96,85},{-115,-104,82},{-121,-109,81},{-127,-110,81},
+{-105,28,100},{-103,20,99},{-84,55,97},{-92,54,99},
+{-73,51,99},{-55,45,89},{-52,37,88},{-53,25,87},
+{-66,13,92},{-79,8,95},{-98,14,100},{-104,38,100},
+{-100,48,100},{-97,46,97},{-102,38,97},{-96,16,97},
+{-79,11,93},{-68,15,90},{-57,27,86},{-56,36,86},
+{-59,43,87},{-74,50,96},{-91,51,98},{-84,52,96},
+{-101,22,96},{-102,29,96},{-113,59,78},{-102,85,79},
+{-84,88,76},{-65,71,71},{-40,58,63},{-25,52,59},
+{-28,21,48},{-50,0,53},{-71,-12,60},{-127,115,37},
+{-127,126,-10},{-127,-25,-86},{-127,-59,24},{-127,-125,59},
+{-127,-103,44},{-127,-73,41},{-127,-62,36},{-18,30,7},
+{-17,41,-6},{-28,34,-56},{-68,56,-90},{-33,-6,9},
+{-51,-16,-21},{-45,-1,-55},{-84,7,-85},{-97,-45,52},
+{-104,-53,33},{-90,-91,49},{-95,-64,50},{-85,-117,51},
+{-109,-97,47},{-111,-69,46},{-106,-121,56},{-99,-36,55},
+{-100,-29,60},{-101,-22,64},{-100,-50,21},{-89,-40,-34},
+{-83,-19,-69},{-69,111,-49},{-69,119,-9},{-69,109,30},
+{-68,67,55},{-34,52,43},{-46,58,36},{-45,90,7},
+{-25,72,16},{-25,79,-15},{-45,96,-25},{-45,87,-57},
+{-25,69,-46},{-48,42,-75},{-65,3,-70},{-22,42,-26},
+{-75,-22,19},{-72,-25,-27},{-13,52,-30},{-28,-18,-16},
+{6,-13,-42},{37,7,-55},{46,41,-54},{31,65,-54},
+{4,61,-40},{3,53,-37},{25,56,-50},{35,37,-52},
+{28,10,-52},{5,-5,-39},{-21,-9,-17},{-9,46,-28},
+{-6,39,-37},{-14,-3,-27},{6,0,-47},{25,12,-57},
+{31,32,-57},{23,46,-56},{4,44,-46},{-19,37,-27},
+{-20,22,-35},{-30,12,-35},{-22,11,-35},{-19,2,-35},
+{-23,-2,-35},{-34,0,-9},{-35,-3,-22},{-35,5,-24},
+{-25,26,-27},{-13,31,-34},{-13,30,-41},{-23,-2,-41},
+{-18,2,-41},{-21,10,-41},{-29,12,-41},{-19,22,-41},
+{6,42,-53},{25,44,-62},{34,31,-63},{28,11,-62},
+{7,0,-54},{-14,-2,-34},{-5,37,-44},{-13,14,-42},
+{-7,8,-43},{1,16,-47},{-4,22,-45},{3,30,-48},
+{8,24,-49},{15,27,-50},{12,35,-50},{4,56,-62},
+{33,60,-70},{48,38,-64},{41,7,-68},{6,-11,-63},
+{-26,-16,-42},{-17,49,-49},
+};
+
+signed char monkeyf[250][4]= {
+{27,4,5,26}, {25,4,5,24}, {3,6,5,4}, {1,6,5,2}, {5,6,7,4},
+{3,6,7,2}, {5,8,7,6}, {3,8,7,4}, {7,8,9,6},
+{5,8,9,4}, {7,10,9,8}, {5,10,9,6}, {9,10,11,8},
+{7,10,11,6}, {9,12,11,10}, {7,12,11,8}, {11,6,13,12},
+{5,4,13,12}, {3,-2,13,12}, {-3,-4,13,12}, {-5,-10,13,12},
+{-11,-12,14,12}, {-13,-18,14,13}, {-19,4,5,13}, {10,12,4,4},
+{10,11,9,9}, {8,7,9,9}, {7,5,6,6}, {6,3,4,4},
+{5,1,2,2}, {4,-1,0,0}, {3,-3,-2,-2}, {22,67,68,23},
+{20,65,66,21}, {18,63,64,19}, {16,61,62,17}, {14,59,60,15},
+{12,19,48,57}, {18,19,48,47}, {18,19,48,47}, {18,19,48,47},
+{18,19,48,47}, {18,19,48,47}, {18,19,48,47}, {18,19,48,47},
+{18,19,48,47}, {18,-9,-8,47}, {18,27,45,46}, {26,55,43,44},
+{24,41,42,54}, {22,39,40,23}, {20,37,38,21}, {18,35,36,19},
+{16,33,34,17}, {14,31,32,15}, {12,39,30,13}, {11,48,45,38},
+{8,36,-19,9}, {8,-20,44,47}, {42,45,46,43}, {18,19,40,39},
+{16,17,38,37}, {14,15,36,35}, {32,44,43,33}, {12,33,32,42},
+{19,44,43,42}, {40,41,42,-27}, {8,9,39,-28}, {15,43,42,16},
+{13,43,42,14}, {11,43,42,12}, {9,-30,42,10}, {37,12,38,-32},
+{-33,37,45,46}, {-33,40,41,39}, {38,40,41,37}, {36,40,41,35},
+{34,40,41,33}, {36,39,38,37}, {35,40,39,38}, {1,2,14,21},
+{1,2,40,13}, {1,2,40,39}, {1,24,12,39}, {-34,36,38,11},
+{35,38,36,37}, {-37,8,35,37}, {-11,-12,-45,40}, {-11,-12,39,38},
+{-11,-12,37,36}, {-11,-12,35,34}, {33,34,40,41}, {33,34,38,39},
+{33,34,36,37}, {33,-52,34,35}, {33,37,36,34}, {33,35,34,34},
+{8,7,37,36}, {-32,7,35,46}, {-34,-33,45,46}, {4,-33,43,34},
+{-34,-33,41,42}, {-34,-33,39,40}, {-34,-33,37,38}, {-34,-33,35,36},
+{-34,-33,33,34}, {-34,-33,31,32}, {-34,-4,28,30}, {-5,-34,28,27},
+{-35,-44,36,27}, {26,35,36,45}, {24,25,44,45}, {25,23,44,42},
+{25,24,41,40}, {25,24,39,38}, {25,24,37,36}, {25,24,35,34},
+{25,24,33,32}, {25,24,31,30}, {15,24,29,38}, {25,24,27,26},
+{23,12,37,26}, {11,12,35,36}, {-86,-59,36,-80}, {-60,-61,36,35},
+{-62,-63,36,35}, {-64,-65,36,35}, {-66,-67,36,35}, {-68,-69,36,35},
+{-70,-71,36,35}, {-72,-73,36,35}, {-74,-75,36,35}, {42,43,53,58},
+{40,41,57,56}, {38,39,55,57}, {-81,-80,37,56}, {-83,-82,55,52},
+{-85,-84,51,49}, {-87,-86,48,49}, {47,50,51,48}, {46,48,51,49},
+{43,46,49,44}, {-92,-91,45,42}, {-23,49,50,-20}, {-94,40,48,-24},
+{-96,-22,48,49}, {-97,48,21,-90}, {-100,36,50,23}, {22,49,48,-100},
+{-101,47,46,22}, {21,45,35,25}, {33,34,44,41}, {13,14,28,24},
+{-107,26,30,-106}, {14,46,45,15}, {14,44,43,-110}, {-111,42,23,-110},
+{6,7,45,46}, {45,44,47,46}, {45,46,47,48}, {47,46,49,48},
+{17,49,47,48}, {17,36,46,48}, {35,36,44,45}, {35,36,40,43},
+{35,36,38,39}, {-4,-3,37,35}, {-123,34,33,1}, {-9,-8,-7,-6},
+{-10,-7,32,-125}, {-127,-11,-126,-126}, {-7,-6,5,31}, {4,5,33,30},
+{4,39,33,32}, {4,35,32,38}, {20,21,39,38}, {4,37,38,5},
+{-11,-10,36,3}, {-11,15,14,35}, {13,16,34,34}, {-13,14,13,13},
+{-3,1,30,29}, {-3,28,29,1}, {-2,31,28,-1}, {12,13,27,30},
+{-2,26,12,12}, {35,29,42,36}, {34,35,36,33}, {32,35,36,31},
+{30,35,36,29}, {28,35,36,27}, {26,35,36,25}, {34,39,38,35},
+{32,39,38,33}, {30,39,38,31}, {28,39,38,29}, {26,39,38,27},
+{25,31,32,38}, {-18,-17,45,44}, {-18,17,28,44}, {-24,-20,42,-23},
+{11,35,27,14}, {25,28,39,41}, {37,41,40,38}, {34,40,36,35},
+{32,40,39,33}, {30,39,31,40}, {21,29,39,22}, {-31,37,28,4},
+{-32,33,35,36}, {32,33,34,34}, {18,35,36,48}, {34,25,40,35},
+{24,25,38,39}, {24,25,36,37}, {24,25,34,35}, {24,25,32,33},
+{24,13,41,31}, {17,11,41,35}, {15,16,34,35}, {13,14,34,35},
+{11,12,34,35}, {9,10,34,35}, {7,8,34,35}, {26,25,37,36},
+{35,36,37,38}, {37,36,39,38}, {37,38,39,40}, {25,31,36,39},
+{18,34,35,30}, {17,22,30,33}, {19,29,21,20}, {16,26,29,17},
+{24,29,28,25}, {22,31,28,23}, {20,31,30,21}, {18,31,30,19},
+{16,30,17,17}, {-21,-22,35,34}, {-21,-22,33,32}, {-21,-22,31,30},
+{-21,-22,29,28}, {-21,-22,27,26}, {-28,-22,25,31}, {24,28,29,30},
+{23,24,26,27}, {23,24,25,25}, {-69,-35,-32,27}, {-70,26,25,-66},
+{-68,-67,24,-33},
+};
diff --git a/source/blender/src/cre/license.jpeg.c b/source/blender/src/cre/license.jpeg.c
new file mode 100644
index 00000000000..880d3dbde2e
--- /dev/null
+++ b/source/blender/src/cre/license.jpeg.c
@@ -0,0 +1,38 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+int datatoc_tonize= 0;
+char datatoc_ton[]= {0};
diff --git a/source/blender/src/cre/license_key.c b/source/blender/src/cre/license_key.c
new file mode 100644
index 00000000000..4daa7628f53
--- /dev/null
+++ b/source/blender/src/cre/license_key.c
@@ -0,0 +1,197 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "license_key.h"
+#include "keyed_functions.h"
+#include "BKE_utildefines.h"
+#include "BIF_screen.h" // splash
+#include "BIF_toolbox.h"
+#include <stdio.h>
+#include <string.h>
+#include "BLO_readfile.h"
+//#include "BLO_keyStore.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+int LICENSE_KEY_VALID = TRUE;
+int I_AM_PUBLISHER = TRUE;
+
+// Python stuff
+
+#include "Python.h"
+#include "marshal.h"
+#include "compile.h" /* to give us PyCodeObject */
+#include "eval.h" /* prototype for PyEval_EvalCode */
+
+#include "BPY_extern.h"
+#include "IMB_imbuf.h"
+
+Fptr g_functab[PYKEY_TABLEN];
+Fptr g_ptrtab[PYKEY_TABLEN];
+
+static int g_seed[3] = PYKEY_SEED;
+static PyObject *g_module_self;
+static PyObject *g_main;
+
+
+// end Python stuff
+
+// **************** PYTHON STUFF **************************
+/* ----------------------------------------------------- */
+/* this is the dummy functions to demonstrate */
+
+int sticky_shoes(void *vp)
+{
+#ifndef NDEBUG
+ printf("feature not enabled: Buy our Key NOW!\n");
+#endif
+ return 0;
+}
+
+/*
+int key_func1(void *vp) {
+ printf("function 1 called\n");
+}
+
+*/
+int key_return_true(void *vp) {
+#ifndef NDEBUG
+ printf("function 2 called (return true)\n");
+#endif
+ return 1;
+}
+
+/* ----------------------------------------------------- */
+
+/* Declarations for objects of type Fplist */
+
+
+#ifndef NDEBUG
+void feature1(void)
+{
+ Fptr f;
+
+ printf("feature 2 called\n");
+ f = g_ptrtab[KEY_FUNC2];
+ if (f) f(0);
+}
+
+void feature2(void)
+{
+ Fptr f;
+
+ printf("feature 3 called\n");
+ f = g_ptrtab[KEY_FUNC3];
+ if (f) f(0);
+}
+
+#endif
+
+
+/* Initialization function for the module (*must* be called initprot) */
+
+static void init_ftable(void) // initializes functiontable
+{
+ int i;
+
+ g_functab[0] = &key_func1;
+
+ for (i = 1; i < PYKEY_TABLEN; i++)
+ {
+ g_functab[i] = &sticky_shoes;
+ }
+
+ // for debugging perposes
+ /*
+ for (i = 0; i < PYKEY_TABLEN; i++)
+ {
+ g_functab[i] = (Fptr *) (i + 100);
+ }
+ */
+}
+
+
+static void init_ptable(void) // initializes functiontable
+{
+ int i;
+
+ for (i = 0; i < PYKEY_TABLEN; i++)
+ {
+ g_ptrtab[i] = &sticky_shoes;
+ }
+}
+
+
+#ifdef NDEBUG
+static void print_ptable(void)
+{
+ int i;
+
+ for (i = 0; i < PYKEY_TABLEN; i++)
+ {
+ printf ("index[%02d] = %08x\n", i, g_ptrtab[i]);
+ }
+}
+#endif
+
+static void insertname(PyObject *m,PyObject *p, char *name)
+{
+}
+
+/* initialisation */
+static void initprot()
+{
+ init_ftable(); // malloc
+ init_ptable(); // malloc
+}
+
+// ******************************* KEY STUFF *********************
+
+void create_key_name(char * keyname)
+{
+}
+
+void checkhome()
+{
+ initprot(); // initialize module and function tables
+
+}
+
+void SHOW_LICENSE_KEY(void)
+{
+}
+
+void loadKeyboard(char * name)
+{
+}
diff --git a/source/blender/src/cursors.c b/source/blender/src/cursors.c
new file mode 100644
index 00000000000..ea10d2e9b3e
--- /dev/null
+++ b/source/blender/src/cursors.c
@@ -0,0 +1,840 @@
+/**
+* $Id$
+*
+* ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version. The Blender
+* Foundation also sells licenses for use in proprietary software under
+* the Blender License. See http://www.blender.org/BL/ for information
+* about this.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software Foundation,
+* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*
+* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+* All rights reserved.
+*
+* The Original Code is: all of this file.
+*
+* Contributor(s): none yet.
+*
+* ***** END GPL/BL DUAL LICENSE BLOCK *****
+*/
+
+#include <stdio.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "DNA_listBase.h"
+#include "DNA_userdef_types.h"
+
+#include "BIF_cursors.h"
+#include "BIF_resources.h"
+#include "BIF_graphics.h"
+#include "BIF_screen.h"
+
+#include "winlay.h"
+
+
+/* ******************************************************************
+Cursor Description:
+
+Each bit represents a pixel, so 1 byte = 8 pixels,
+the bytes go Left to Right. Top to bottom
+the bits in a byte go right to left
+(ie; 0x01, 0x80 represents a line of 16 pix with the first and last pix set.)
+
+A 0 in the bitmap = bg_color, a 1 fg_color
+a 0 in the mask = transparent pix.
+
+Until 32x32 cursors are supported on all platforms, the size of the
+small cursors MUST be 16x16.
+
+Large cursors have a MAXSIZE of 32x32.
+
+Other than that, the specified size of the cursors is just a guideline,
+However, the char array that defines the BM and MASK must be byte aligned.
+ie a 17x17 cursor needs 3 bytes (cols) * 17 bytes (rows)
+(3 bytes = 17 bits rounded up to nearest whole byte). Pad extra bits
+in mask with 0's.
+
+Setting big_bm=NULL disables the large version of the cursor.
+
+*******************************************************************
+
+There is a nice Python GUI utility that can be used for drawing cursors in
+this format in the Blender source distribution, in
+blender/source/tools/MakeCursor.py . Start it with $ python MakeCursor.py
+It will copy its output to the console when you press 'Do it'.
+
+*/
+
+/* Because defining a cursor mixes declarations and executable code
+ each cursor needs it's own scoping block or it would be split up
+ over several hundred lines of code. To enforce/document this better
+ I define 2 pretty braindead macros so it's obvious what the extra "[]"
+ are for */
+
+#define BEGIN_CURSOR_BLOCK {
+#define END_CURSOR_BLOCK }
+
+/* Cursor Globals */
+static BCursor *BlenderCursor[BC_NUMCURSORS]; /*Points to static BCursor Structs */
+static short CurrentCursor=-1, LastCursor=-1;
+
+short GetBlenderCursor(void) {
+ return CurrentCursor;
+}
+
+void SetBlenderCursor(short curs){
+ Window *win;
+
+ if ((curs<LASTCURSOR)||(curs>=BC_NUMCURSORS)) return;
+
+ win=winlay_get_active_window();
+
+ if (win==NULL) return; /* Can't set custom cursor before Window init */
+
+ LastCursor=CurrentCursor;
+ CurrentCursor=curs;
+
+ if (curs==LASTCURSOR) curs=LastCursor;
+
+ if (curs==SYSCURSOR) { /* System default Cursor */
+ window_set_cursor(win, CURSOR_STD);
+ //set_cursor(CURSOR_STD);
+ }
+ else if ( (U.curssize==0) || (BlenderCursor[curs]->big_bm == NULL) ) {
+ window_set_custom_cursor_ex(win, BlenderCursor[curs], 0);
+ }
+ else {
+ window_set_custom_cursor_ex(win, BlenderCursor[curs], 1);
+ }
+}
+
+/* unused no prototypes
+short GetCurrentCursor(void){
+ return(CurrentCursor);
+}
+*/
+
+void InitCursorData(void){
+
+ /********************** NW_ARROW Cursor **************************/
+BEGIN_CURSOR_BLOCK
+ static char nw_sbm[]={
+ 0x03, 0x00, 0x05, 0x00, 0x09, 0x00, 0x11, 0x00,
+ 0x21, 0x00, 0x41, 0x00, 0x81, 0x00, 0x01, 0x01,
+ 0x01, 0x02, 0xc1, 0x03, 0x49, 0x00, 0x8d, 0x00,
+ 0x8b, 0x00, 0x10, 0x01, 0x90, 0x01, 0x60, 0x00,
+ };
+
+ static char nw_smsk[]={
+ 0x03, 0x00, 0x07, 0x00, 0x0f, 0x00, 0x1f, 0x00,
+ 0x3f, 0x00, 0x7f, 0x00, 0xff, 0x00, 0xff, 0x01,
+ 0xff, 0x03, 0xff, 0x03, 0x7f, 0x00, 0xff, 0x00,
+ 0xfb, 0x00, 0xf0, 0x01, 0xf0, 0x01, 0x60, 0x00,
+ };
+
+ static BCursor NWArrowCursor = {
+ /*small*/
+ nw_sbm, nw_smsk,
+ 16, 16,
+ 6, 7,
+ /*big*/
+ NULL, NULL,
+ 32,32,
+ 15, 15,
+ /*color*/
+ BC_BLACK, BC_WHITE
+ };
+
+ BlenderCursor[BC_NW_ARROWCURSOR]=&NWArrowCursor;
+END_CURSOR_BLOCK
+
+ ///********************** NS_ARROW Cursor *************************/
+BEGIN_CURSOR_BLOCK
+ static char ns_sbm[]={
+ 0x40, 0x01, 0x20, 0x02, 0x10, 0x04, 0x08, 0x08,
+ 0x04, 0x10, 0x3c, 0x1e, 0x20, 0x02, 0x20, 0x02,
+ 0x20, 0x02, 0x20, 0x02, 0x3c, 0x1e, 0x04, 0x10,
+ 0x08, 0x08, 0x10, 0x04, 0x20, 0x02, 0x40, 0x01
+ };
+
+ static char ns_smsk[]={
+ 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0xf8, 0x0f,
+ 0xfc, 0x1f, 0xfc, 0x1f, 0xe0, 0x03, 0xe0, 0x03,
+ 0xe0, 0x03, 0xe0, 0x03, 0xfc, 0x1f, 0xfc, 0x1f,
+ 0xf8, 0x0f, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01
+ };
+
+ static BCursor NSArrowCursor = {
+ /*small*/
+ ns_sbm, ns_smsk,
+ 16, 16,
+ 6, 7,
+ /*big*/
+ NULL, NULL,
+ 32,32,
+ 15, 15,
+ /*color*/
+ BC_BLACK, BC_WHITE
+ };
+
+ BlenderCursor[BC_NS_ARROWCURSOR]=&NSArrowCursor;
+
+END_CURSOR_BLOCK
+ /********************** EW_ARROW Cursor *************************/
+BEGIN_CURSOR_BLOCK
+ static char ew_sbm[]={
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x38, 0x1c,
+ 0x2c, 0x34, 0xe6, 0x67, 0x03, 0xc0, 0x01, 0x80,
+ 0x03, 0xc0, 0xe6, 0x67, 0x2c, 0x34, 0x38, 0x1c,
+ 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char ew_smsk[]={
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x38, 0x1c,
+ 0x3c, 0x3c, 0xfe, 0x7f, 0xff, 0xff, 0x3f, 0xfc,
+ 0xff, 0xff, 0xfe, 0x7f, 0x3c, 0x3c, 0x38, 0x1c,
+ 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static BCursor EWArrowCursor = {
+ /*small*/
+ ew_sbm, ew_smsk,
+ 16, 16,
+ 7, 6,
+ /*big*/
+ NULL, NULL,
+ 32,32,
+ 15, 15,
+ /*color*/
+ BC_BLACK, BC_WHITE
+ };
+
+ BlenderCursor[BC_EW_ARROWCURSOR]=&EWArrowCursor;
+END_CURSOR_BLOCK
+
+ /********************** Wait Cursor *****************************/
+BEGIN_CURSOR_BLOCK
+ static char wait_sbm[]={
+ 0xfe, 0x7f, 0x02, 0x40, 0x02, 0x40, 0x84, 0x21,
+ 0xc8, 0x13, 0xd0, 0x0b, 0xa0, 0x04, 0x20, 0x05,
+ 0xa0, 0x04, 0x10, 0x09, 0x88, 0x11, 0xc4, 0x23,
+ 0xe2, 0x47, 0xfa, 0x5f, 0x02, 0x40, 0xfe, 0x7f,
+ };
+
+ static char wait_smsk[]={
+ 0xfe, 0x7f, 0xfe, 0x7f, 0x06, 0x60, 0x8c, 0x31,
+ 0xd8, 0x1b, 0xf0, 0x0f, 0xe0, 0x06, 0x60, 0x07,
+ 0xe0, 0x06, 0x30, 0x0d, 0x98, 0x19, 0xcc, 0x33,
+ 0xe6, 0x67, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f,
+ };
+
+ static char wait_lbm[]={
+ 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f,
+ 0x0c, 0x00, 0x00, 0x30, 0x0c, 0x00, 0x00, 0x30,
+ 0x0c, 0x00, 0x00, 0x30, 0x0c, 0x00, 0x00, 0x18,
+ 0x18, 0xc0, 0x03, 0x0c, 0x30, 0x20, 0x07, 0x06,
+ 0x60, 0xf0, 0x0f, 0x03, 0xc0, 0xd0, 0x8d, 0x01,
+ 0x80, 0x79, 0xcf, 0x00, 0x00, 0xf3, 0x67, 0x00,
+ 0x00, 0x66, 0x37, 0x00, 0x00, 0x8c, 0x33, 0x00,
+ 0x00, 0x0c, 0x32, 0x00, 0x00, 0xcc, 0x33, 0x00,
+ 0x00, 0x8c, 0x30, 0x00, 0x00, 0x46, 0x61, 0x00,
+ 0x00, 0x03, 0xc3, 0x00, 0x80, 0x01, 0x83, 0x01,
+ 0xc0, 0xc0, 0x03, 0x03, 0x60, 0xa0, 0x05, 0x06,
+ 0x30, 0xf0, 0x0f, 0x0c, 0x18, 0xf8, 0x1d, 0x18,
+ 0x0c, 0x5c, 0x3f, 0x30, 0x0c, 0xff, 0x5f, 0x30,
+ 0x0c, 0xf7, 0xfe, 0x31, 0xcc, 0xfb, 0x9f, 0x33,
+ 0x0c, 0x00, 0x00, 0x30, 0x0c, 0x00, 0x00, 0x30,
+ 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f,
+ };
+
+ static char wait_lmsk[]={
+ 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f,
+ 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f,
+ 0x3c, 0x00, 0x00, 0x3c, 0x3c, 0x00, 0x00, 0x1e,
+ 0x78, 0xc0, 0x03, 0x0f, 0xf0, 0xa0, 0x87, 0x07,
+ 0xe0, 0xf1, 0xcf, 0x03, 0xc0, 0xf3, 0xef, 0x01,
+ 0x80, 0xff, 0xff, 0x00, 0x00, 0xff, 0x7f, 0x00,
+ 0x00, 0xfe, 0x3f, 0x00, 0x00, 0xfc, 0x3f, 0x00,
+ 0x00, 0x3c, 0x3f, 0x00, 0x00, 0xfc, 0x3f, 0x00,
+ 0x00, 0xbc, 0x3c, 0x00, 0x00, 0xde, 0x79, 0x00,
+ 0x00, 0x0f, 0xf3, 0x00, 0x80, 0x07, 0xe3, 0x01,
+ 0xc0, 0xc3, 0xc3, 0x03, 0xe0, 0xe1, 0x87, 0x07,
+ 0xf0, 0xf0, 0x0f, 0x0f, 0x78, 0xf8, 0x1f, 0x1e,
+ 0x3c, 0x7c, 0x3f, 0x3c, 0x3c, 0xff, 0x7f, 0x3c,
+ 0xbc, 0xff, 0xff, 0x3d, 0xfc, 0xfb, 0xbf, 0x3f,
+ 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f,
+ 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f,
+ };
+
+ static BCursor WaitCursor = {
+ /*small*/
+ wait_sbm, wait_smsk,
+ 16, 16,
+ 7, 7,
+ /*big*/
+ wait_lbm, wait_lmsk,
+ 32,32,
+ 15, 15,
+ /*color*/
+ BC_BLACK, BC_WHITE
+ };
+
+ BlenderCursor[BC_WAITCURSOR]=&WaitCursor;
+END_CURSOR_BLOCK
+
+ /********************** Cross Cursor ***************************/
+BEGIN_CURSOR_BLOCK
+ static char cross_sbm[]={
+ 0x00, 0x00, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01,
+ 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x7e, 0x7e,
+ 0x7e, 0x7e, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01,
+ 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x00, 0x00,
+ };
+
+ static char cross_smsk[]={
+ 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01,
+ 0x80, 0x01, 0x80, 0x01, 0xc0, 0x03, 0x7f, 0xfe,
+ 0x7f, 0xfe, 0xc0, 0x03, 0x80, 0x01, 0x80, 0x01,
+ 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01,
+ };
+ static char cross_lbm[]={
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x00,
+ 0x00, 0xc0, 0x03, 0x00, 0x00, 0x40, 0x02, 0x00,
+ 0x00, 0x78, 0x1e, 0x00, 0xfc, 0x1f, 0xf8, 0x3f,
+ 0xfc, 0x1f, 0xf8, 0x3f, 0x00, 0x78, 0x1e, 0x00,
+ 0x00, 0x40, 0x02, 0x00, 0x00, 0xc0, 0x03, 0x00,
+ 0x00, 0xc0, 0x03, 0x00, 0x00, 0x80, 0x01, 0x00,
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ static char cross_lmsk[]={
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0xc0, 0x03, 0x00,
+ 0x00, 0xe0, 0x07, 0x00, 0x00, 0x70, 0x0e, 0x00,
+ 0x00, 0x78, 0x1e, 0x00, 0xff, 0x1f, 0xf8, 0xff,
+ 0xff, 0x1f, 0xf8, 0xff, 0x00, 0x78, 0x1e, 0x00,
+ 0x00, 0x70, 0x0e, 0x00, 0x00, 0xe0, 0x07, 0x00,
+ 0x00, 0xc0, 0x03, 0x00, 0x00, 0x80, 0x01, 0x00,
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
+ 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00,
+ };
+
+ static BCursor CrossCursor = {
+ /*small*/
+ cross_sbm, cross_smsk,
+ 16, 16,
+ 7, 7,
+ /*big*/
+ cross_lbm, cross_lmsk,
+ 32,32,
+ 15, 15,
+ /*color*/
+ BC_BLACK, BC_WHITE
+ };
+
+ BlenderCursor[BC_CROSSCURSOR]=&CrossCursor;
+END_CURSOR_BLOCK
+
+ /********************** EditCross Cursor ***********************/
+BEGIN_CURSOR_BLOCK
+ static char editcross_sbm[]={
+ 0x0e, 0x00, 0x11, 0x00, 0x1d, 0x00, 0x19, 0x03,
+ 0x1d, 0x03, 0x11, 0x03, 0x0e, 0x03, 0x00, 0x03,
+ 0xf8, 0x7c, 0xf8, 0x7c, 0x00, 0x03, 0x00, 0x03,
+ 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00,
+ };
+
+ static char editcross_smsk[]={
+ 0x0e, 0x00, 0x1f, 0x00, 0x1f, 0x03, 0x1f, 0x03,
+ 0x1f, 0x03, 0x1f, 0x03, 0x0e, 0x03, 0x80, 0x07,
+ 0xfc, 0xfc, 0xfc, 0xfc, 0x80, 0x07, 0x00, 0x03,
+ 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03,
+ };
+
+ static BCursor EditCrossCursor = {
+ /*small*/
+ editcross_sbm, editcross_smsk,
+ 16, 16,
+ 9, 8,
+ /*big*/
+ NULL, NULL,
+ 32,32,
+ 15, 15,
+ /*color*/
+ BC_BLACK, BC_WHITE
+ };
+
+ BlenderCursor[BC_EDITCROSSCURSOR]=&EditCrossCursor;
+END_CURSOR_BLOCK
+
+ /********************** Box Select *************************/
+BEGIN_CURSOR_BLOCK
+ static char box_sbm[32]={
+ 0x7f, 0x00, 0x41, 0x00, 0x41, 0x00, 0x41, 0x06,
+ 0x41, 0x06, 0x41, 0x06, 0x7f, 0x06, 0x00, 0x06,
+ 0xe0, 0x79, 0xe0, 0x79, 0x00, 0x06, 0x00, 0x06,
+ 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00,
+ };
+
+ static char box_smsk[32]={
+ 0x7f, 0x00, 0x7f, 0x00, 0x63, 0x06, 0x63, 0x06,
+ 0x63, 0x06, 0x7f, 0x06, 0x7f, 0x06, 0x00, 0x0f,
+ 0xf0, 0xf9, 0xf0, 0xf9, 0x00, 0x0f, 0x00, 0x06,
+ 0x00, 0x06, 0x00, 0x06, 0x00, 0x06, 0x00, 0x06,
+
+ };
+
+ static BCursor BoxSelCursor = {
+ /*small*/
+ box_sbm, box_smsk,
+ 16, 16,
+ 9, 8,
+ /*big*/
+ NULL, NULL,
+ 32,32,
+ 15, 15,
+ /*color*/
+ BC_BLACK, BC_WHITE
+ };
+
+ BlenderCursor[BC_BOXSELCURSOR]=&BoxSelCursor;
+
+END_CURSOR_BLOCK
+ /********************** Knife Cursor ***********************/
+BEGIN_CURSOR_BLOCK
+ static char knife_sbm[]={
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x2c,
+ 0x00, 0x5a, 0x00, 0x34, 0x00, 0x2a, 0x00, 0x17,
+ 0x80, 0x06, 0x40, 0x03, 0xa0, 0x03, 0xd0, 0x01,
+ 0x68, 0x00, 0x1c, 0x00, 0x06, 0x00, 0x00, 0x00
+ };
+
+ static char knife_smsk[]={
+ 0x00, 0x60, 0x00, 0xf0, 0x00, 0xfc, 0x00, 0xfe,
+ 0x00, 0xfe, 0x00, 0x7e, 0x00, 0x7f, 0x80, 0x3f,
+ 0xc0, 0x0e, 0x60, 0x07, 0xb0, 0x07, 0xd8, 0x03,
+ 0xec, 0x01, 0x7e, 0x00, 0x1f, 0x00, 0x07, 0x00
+ };
+
+ static char knife_lbm[]={
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x1c,
+ 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x7f,
+ 0x00, 0x00, 0x80, 0xbf, 0x00, 0x00, 0xc0, 0x5f,
+ 0x00, 0x00, 0xc0, 0x6f, 0x00, 0x00, 0xc0, 0x37,
+ 0x00, 0x00, 0xa8, 0x1b, 0x00, 0x00, 0x54, 0x0d,
+ 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0x54, 0x00,
+ 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0x53, 0x00,
+ 0x00, 0xc0, 0x07, 0x00, 0x00, 0xe0, 0x0f, 0x00,
+ 0x00, 0xd0, 0x0f, 0x00, 0x00, 0xe8, 0x07, 0x00,
+ 0x00, 0xf4, 0x07, 0x00, 0x00, 0xfa, 0x00, 0x00,
+ 0x00, 0x3d, 0x00, 0x00, 0x80, 0x0e, 0x00, 0x00,
+ 0xc0, 0x03, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00,
+ 0x30, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ };
+
+ static char knife_lmsk[]={
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
+ 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x7e,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x80, 0xff,
+ 0x00, 0x00, 0xc0, 0xbf, 0x00, 0x00, 0xe0, 0xdf,
+ 0x00, 0x00, 0xe0, 0xef, 0x00, 0x00, 0xf8, 0x77,
+ 0x00, 0x00, 0xfc, 0x3b, 0x00, 0x00, 0xfe, 0x1d,
+ 0x00, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0xfe, 0x01,
+ 0x00, 0x00, 0xff, 0x01, 0x00, 0xc0, 0xff, 0x00,
+ 0x00, 0xe0, 0x7f, 0x00, 0x00, 0xf0, 0x1f, 0x00,
+ 0x00, 0xd8, 0x1f, 0x00, 0x00, 0xec, 0x0f, 0x00,
+ 0x00, 0xf6, 0x0f, 0x00, 0x00, 0xfb, 0x06, 0x00,
+ 0x80, 0xbd, 0x01, 0x00, 0xc0, 0x6e, 0x00, 0x00,
+ 0xe0, 0x1b, 0x00, 0x00, 0xf0, 0x06, 0x00, 0x00,
+ 0xb8, 0x01, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00,
+ 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ };
+
+ static BCursor KnifeCursor = {
+ /*small*/
+ knife_sbm, knife_smsk,
+ 16, 16,
+ 0, 15,
+ /*big*/
+ knife_lbm, knife_lmsk,
+ 32,32,
+ 0, 31,
+ /*color*/
+ BC_BLACK, BC_WHITE
+ };
+
+ BlenderCursor[BC_KNIFECURSOR]=&KnifeCursor;
+
+END_CURSOR_BLOCK
+
+ /********************** Loop Select Cursor ***********************/
+BEGIN_CURSOR_BLOCK
+
+static char vloop_sbm[]={
+ 0x00, 0x00, 0x7e, 0x00, 0x3e, 0x00, 0x1e, 0x00,
+ 0x0e, 0x00, 0x66, 0x60, 0x62, 0x6f, 0x00, 0x00,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x00, 0x00, 0x60, 0x60, 0x60, 0x6f, 0x00, 0x00,
+};
+
+static char vloop_smsk[]={
+ 0xff, 0x01, 0xff, 0x00, 0x7f, 0x00, 0x3f, 0x00,
+ 0xff, 0xf0, 0xff, 0xff, 0xf7, 0xff, 0xf3, 0xf0,
+ 0x61, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60,
+ 0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0xff, 0xf0, 0xf0,
+};
+
+
+
+static char vloop_lbm[]={
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xfc, 0x3f, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00,
+ 0xfc, 0x0f, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00,
+ 0xfc, 0x03, 0x00, 0x00, 0xfc, 0x03, 0x00, 0x00,
+ 0xfc, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00,
+ 0x3c, 0x3c, 0x00, 0x3c, 0x3c, 0x3c, 0x00, 0x3c,
+ 0x0c, 0x3c, 0xff, 0x3c, 0x0c, 0x3c, 0xff, 0x3c,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c,
+ 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c,
+ 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c,
+ 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c,
+ 0x00, 0x3c, 0xff, 0x3c, 0x00, 0x3c, 0xff, 0x3c,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static char vloop_lmsk[]={
+ 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x03, 0x00,
+ 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0xff, 0x3f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00,
+ 0xff, 0x0f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00,
+ 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x3f, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff,
+ 0x0f, 0xff, 0x00, 0xff, 0x0f, 0xff, 0x00, 0xff,
+ 0x03, 0x3c, 0x00, 0x3c, 0x03, 0x3c, 0x00, 0x3c,
+ 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c,
+ 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c,
+ 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
+ 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff,
+ 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
+};
+
+
+
+ static BCursor VLoopCursor = {
+ /*small*/
+ vloop_sbm, vloop_smsk,
+ 16, 16,
+ 0, 0,
+ /*big*/
+ vloop_lbm, vloop_lmsk,
+ 32,32,
+ 0, 0,
+ /*color*/
+ BC_BLACK, BC_WHITE
+ };
+
+ BlenderCursor[BC_VLOOPCURSOR]=&VLoopCursor;
+
+END_CURSOR_BLOCK
+
+
+ /********************** TextEdit Cursor ***********************/
+BEGIN_CURSOR_BLOCK
+ static char textedit_sbm[]={
+ 0xe0, 0x03, 0x10, 0x04, 0x60, 0x03, 0x40, 0x01,
+ 0x40, 0x01, 0x40, 0x01, 0x40, 0x01, 0x40, 0x01,
+ 0x40, 0x01, 0x40, 0x01, 0x40, 0x01, 0x40, 0x01,
+ 0x40, 0x01, 0x60, 0x03, 0x10, 0x04, 0xe0, 0x03,
+ };
+
+ static char textedit_smsk[]={
+ 0xe0, 0x03, 0xf0, 0x07, 0xe0, 0x03, 0xc0, 0x01,
+ 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01,
+ 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x01,
+ 0xc0, 0x01, 0xe0, 0x03, 0xf0, 0x07, 0xe0, 0x03,
+ };
+
+ static BCursor TextEditCursor = {
+ /*small*/
+ textedit_sbm, textedit_smsk,
+ 16, 16,
+ 9, 8,
+ /*big*/
+ NULL, NULL,
+ 32,32,
+ 15, 15,
+ /*color*/
+ BC_BLACK, BC_WHITE
+ };
+
+ BlenderCursor[BC_TEXTEDITCURSOR]=&TextEditCursor;
+END_CURSOR_BLOCK
+
+
+ /********************** Paintbrush Cursor ***********************/
+BEGIN_CURSOR_BLOCK
+ static char paintbrush_sbm[]={
+
+ 0x00, 0xe0, 0x00, 0x98, 0x00, 0x44, 0x00, 0x42,
+ 0x00, 0x21, 0x80, 0x20, 0x40, 0x13, 0x40, 0x17,
+ 0xa0, 0x0b, 0x98, 0x05, 0x04, 0x02, 0x02, 0x01,
+ 0x02, 0x01, 0x02, 0x01, 0x81, 0x00, 0x7f, 0x00,
+
+
+
+ };
+
+ static char paintbrush_smsk[]={
+ 0x00, 0xe0, 0x00, 0xf8, 0x00, 0x7c, 0x00, 0x7e,
+ 0x00, 0x3f, 0x80, 0x3f, 0xc0, 0x1f, 0xc0, 0x1f,
+ 0xe0, 0x0f, 0xf8, 0x07, 0xfc, 0x03, 0xfe, 0x01,
+ 0xfe, 0x01, 0xfe, 0x01, 0xff, 0x00, 0x7f, 0x00,
+
+
+ };
+
+ static BCursor PaintBrushCursor = {
+ /*small*/
+ paintbrush_sbm, paintbrush_smsk,
+ 16, 16,
+ 0, 15,
+ /*big*/
+ NULL, NULL,
+ 32,32,
+ 15, 15,
+ /*color*/
+ BC_BLACK, BC_WHITE
+ };
+
+ BlenderCursor[BC_PAINTBRUSHCURSOR]=&PaintBrushCursor;
+END_CURSOR_BLOCK
+
+
+/********************** Hand Cursor ***********************/
+BEGIN_CURSOR_BLOCK
+
+static char hand_sbm[]={
+ 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x80, 0x0d,
+ 0x98, 0x6d, 0x98, 0x6d, 0xb0, 0x6d, 0xb0, 0x6d,
+ 0xe0, 0x6f, 0xe6, 0x7f, 0xee, 0x7f, 0xfc, 0x3f,
+ 0xf8, 0x3f, 0xf0, 0x1f, 0xc0, 0x1f, 0xc0, 0x1f,
+};
+
+static char hand_smsk[]={
+ 0x00, 0x00, 0x80, 0x01, 0xc0, 0x0f, 0xd8, 0x7f,
+ 0xfc, 0xff, 0xfc, 0xff, 0xf8, 0xff, 0xf8, 0xff,
+ 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f,
+ 0xfc, 0x7f, 0xf8, 0x3f, 0xf0, 0x3f, 0xe0, 0x3f,
+};
+
+
+static BCursor HandCursor = {
+ /*small*/
+ hand_sbm, hand_smsk,
+ 16, 16,
+ 8, 8,
+ /*big*/
+ NULL, NULL,
+ 32,32,
+ 15, 15,
+ /*color*/
+ BC_BLACK, BC_WHITE
+};
+
+BlenderCursor[BC_HANDCURSOR]=&HandCursor;
+
+END_CURSOR_BLOCK
+
+/********************** NSEW Scroll Cursor ***********************/
+BEGIN_CURSOR_BLOCK
+
+static char nsewscroll_sbm[]={
+ 0x00, 0x00, 0x80, 0x01, 0xc0, 0x03, 0xc0, 0x03,
+ 0x00, 0x00, 0x00, 0x00, 0x0c, 0x30, 0x0e, 0x70,
+ 0x0e, 0x70, 0x0c, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0xc0, 0x03, 0xc0, 0x03, 0x80, 0x01, 0x00, 0x00,
+};
+
+static char nsewscroll_smsk[]={
+ 0x80, 0x01, 0xc0, 0x03, 0xe0, 0x07, 0xe0, 0x07,
+ 0xc0, 0x03, 0x0c, 0x30, 0x1e, 0x78, 0x1f, 0xf8,
+ 0x1f, 0xf8, 0x1e, 0x78, 0x0c, 0x30, 0xc0, 0x03,
+ 0xe0, 0x07, 0xe0, 0x07, 0xc0, 0x03, 0x80, 0x01,
+};
+
+
+static BCursor NSEWScrollCursor = {
+ /*small*/
+ nsewscroll_sbm, nsewscroll_smsk,
+ 16, 16,
+ 8, 8,
+ /*big*/
+ NULL, NULL,
+ 32,32,
+ 15, 15,
+ /*color*/
+ BC_BLACK, BC_WHITE
+};
+
+BlenderCursor[BC_NSEW_SCROLLCURSOR]=&NSEWScrollCursor;
+
+END_CURSOR_BLOCK
+
+
+/********************** NS Scroll Cursor ***********************/
+BEGIN_CURSOR_BLOCK
+
+static char nsscroll_sbm[]={
+ 0x00, 0x00, 0x80, 0x01, 0xc0, 0x03, 0xc0, 0x03,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xc0, 0x03, 0xc0, 0x03, 0x80, 0x01, 0x00, 0x00,
+};
+
+static char nsscroll_smsk[]={
+ 0x80, 0x01, 0xc0, 0x03, 0xe0, 0x07, 0xe0, 0x07,
+ 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03,
+ 0xe0, 0x07, 0xe0, 0x07, 0xc0, 0x03, 0x80, 0x01,
+};
+
+
+static BCursor NSScrollCursor = {
+ /*small*/
+ nsscroll_sbm, nsscroll_smsk,
+ 16, 16,
+ 8, 8,
+ /*big*/
+ NULL, NULL,
+ 32,32,
+ 15, 15,
+ /*color*/
+ BC_BLACK, BC_WHITE
+};
+
+BlenderCursor[BC_NS_SCROLLCURSOR]=&NSScrollCursor;
+
+END_CURSOR_BLOCK
+
+
+/********************** EW Scroll Cursor ***********************/
+BEGIN_CURSOR_BLOCK
+
+static char ewscroll_sbm[]={
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0c, 0x30, 0x0e, 0x70,
+ 0x0e, 0x70, 0x0c, 0x30, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static char ewscroll_smsk[]={
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0c, 0x30, 0x1e, 0x78, 0x1f, 0xf8,
+ 0x1f, 0xf8, 0x1e, 0x78, 0x0c, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+
+static BCursor EWScrollCursor = {
+ /*small*/
+ ewscroll_sbm, ewscroll_smsk,
+ 16, 16,
+ 8, 8,
+ /*big*/
+ NULL, NULL,
+ 32,32,
+ 15, 15,
+ /*color*/
+ BC_BLACK, BC_WHITE
+};
+
+BlenderCursor[BC_EW_SCROLLCURSOR]=&EWScrollCursor;
+
+END_CURSOR_BLOCK
+
+/********************** Eyedropper Cursor ***********************/
+BEGIN_CURSOR_BLOCK
+
+static char eyedropper_sbm[]={
+ 0x00, 0x30, 0x00, 0x48, 0x00, 0x85, 0x80, 0x82,
+ 0x40, 0x40, 0x80, 0x20, 0x40, 0x11, 0xa0, 0x23,
+ 0xd0, 0x15, 0xe8, 0x0a, 0x74, 0x01, 0xb4, 0x00,
+ 0x4a, 0x00, 0x35, 0x00, 0x08, 0x00, 0x04, 0x00,
+};
+
+static char eyedropper_smsk[]={
+ 0x00, 0x30, 0x00, 0x78, 0x00, 0xfd, 0x80, 0xff,
+ 0xc0, 0x7f, 0x80, 0x3f, 0xc0, 0x1f, 0xe0, 0x3f,
+ 0xf0, 0x1f, 0xf8, 0x0b, 0xfc, 0x01, 0xfc, 0x00,
+ 0x7e, 0x00, 0x3f, 0x00, 0x0c, 0x00, 0x04, 0x00,
+};
+
+
+static BCursor EyedropperCursor = {
+ /*small*/
+ eyedropper_sbm, eyedropper_smsk,
+ 16, 16,
+ 1, 15,
+ /*big*/
+ NULL, NULL,
+ 32,32,
+ 15, 15,
+ /*color*/
+ BC_BLACK, BC_WHITE
+};
+
+BlenderCursor[BC_EYEDROPPER_CURSOR]=&EyedropperCursor;
+
+END_CURSOR_BLOCK
+
+/********************** Put the cursors in the array ***********************/
+
+
+
+}
+
+
+
diff --git a/source/blender/src/drawaction.c b/source/blender/src/drawaction.c
new file mode 100644
index 00000000000..183558b65bc
--- /dev/null
+++ b/source/blender/src/drawaction.c
@@ -0,0 +1,1291 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Joshua Leung
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * Drawing routines for the Action window type
+ */
+
+/* System includes ----------------------------------------------------- */
+
+#include <math.h>
+#include <stdlib.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "BMF_Api.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+/* Types --------------------------------------------------------------- */
+#include "DNA_listBase.h"
+#include "DNA_action_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_key_types.h"
+
+#include "BKE_action.h"
+#include "BKE_depsgraph.h"
+#include "BKE_ipo.h"
+#include "BKE_key.h"
+#include "BKE_global.h"
+#include "BKE_utildefines.h"
+
+/* Everything from source (BIF, BDR, BSE) ------------------------------ */
+
+#include "BIF_editaction.h"
+#include "BIF_editkey.h"
+#include "BIF_editnla.h"
+#include "BIF_interface.h"
+#include "BIF_interface_icons.h"
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+#include "BIF_resources.h"
+#include "BIF_screen.h"
+#include "BIF_mywindow.h"
+#include "BIF_space.h"
+
+#include "BDR_drawaction.h"
+#include "BDR_editcurve.h"
+
+#include "BSE_drawnla.h"
+#include "BSE_drawipo.h"
+#include "BSE_editaction_types.h"
+#include "BSE_editipo.h"
+#include "BSE_time.h"
+#include "BSE_view.h"
+
+/* 'old' stuff": defines and types, and own include -------------------- */
+
+#include "blendef.h"
+#include "mydevice.h"
+
+/********************************** Slider Stuff **************************** */
+
+/* sliders for shapekeys */
+static void meshactionbuts(SpaceAction *saction, Object *ob, Key *key)
+{
+ int i;
+ char str[64];
+ float x, y;
+ uiBlock *block;
+ uiBut *but;
+
+#define XIC 20
+#define YIC 20
+
+ /* lets make the rvk sliders */
+
+ /* reset the damn myortho2 or the sliders won't draw/redraw
+ * correctly *grumble*
+ */
+ mywinset(curarea->win);
+ myortho2(-0.375, curarea->winx-0.375, G.v2d->cur.ymin, G.v2d->cur.ymax);
+
+ sprintf(str, "actionbuttonswin %d", curarea->win);
+ block= uiNewBlock (&curarea->uiblocks, str, UI_EMBOSS, UI_HELV, curarea->win);
+
+ x = NAMEWIDTH + 1;
+ y = 0.0f;
+
+ /* make the little 'open the sliders' widget */
+ // should eventually be removed
+ BIF_ThemeColor(TH_FACE); // this slot was open... (???... Aligorith)
+ glRects(2, y + 2*CHANNELHEIGHT - 2, ACTWIDTH - 2, y + CHANNELHEIGHT + 2);
+ glColor3ub(0, 0, 0);
+ glRasterPos2f(4, y + CHANNELHEIGHT + 6);
+ BMF_DrawString(G.font, "Sliders");
+
+ uiBlockSetEmboss(block, UI_EMBOSSN);
+
+ if (!(G.saction->flag & SACTION_SLIDERS)) {
+ ACTWIDTH = NAMEWIDTH;
+ but=uiDefIconButBitS(block, TOG, SACTION_SLIDERS, B_REDR,
+ ICON_DISCLOSURE_TRI_RIGHT,
+ NAMEWIDTH - XIC - 5, y + CHANNELHEIGHT,
+ XIC,YIC-2,
+ &(G.saction->flag), 0, 0, 0, 0,
+ "Show action window sliders");
+ /* no hilite, the winmatrix is not correct later on... */
+ uiButSetFlag(but, UI_NO_HILITE);
+
+ }
+ else {
+ but= uiDefIconButBitS(block, TOG, SACTION_SLIDERS, B_REDR,
+ ICON_DISCLOSURE_TRI_DOWN,
+ NAMEWIDTH - XIC - 5, y + CHANNELHEIGHT,
+ XIC,YIC-2,
+ &(G.saction->flag), 0, 0, 0, 0,
+ "Hide action window sliders");
+ /* no hilite, the winmatrix is not correct later on... */
+ uiButSetFlag(but, UI_NO_HILITE);
+
+ ACTWIDTH = NAMEWIDTH + SLIDERWIDTH;
+
+ /* sliders are open so draw them */
+ BIF_ThemeColor(TH_FACE);
+
+ glRects(NAMEWIDTH, 0, NAMEWIDTH+SLIDERWIDTH, curarea->winy);
+ uiBlockSetEmboss(block, UI_EMBOSS);
+ for (i=1; i < key->totkey; i++) {
+ make_rvk_slider(block, ob, i,
+ x, y, SLIDERWIDTH-2, CHANNELHEIGHT-1, "Slider to control Shape Keys");
+
+ y-=CHANNELHEIGHT+CHANNELSKIP;
+
+ /* see sliderval array in editkey.c */
+ if(i >= 255) break;
+ }
+ }
+ uiDrawBlock(block);
+
+}
+
+static void icu_slider_func(void *voidicu, void *voidignore)
+{
+ /* the callback for the icu sliders ... copies the
+ * value from the icu->curval into a bezier at the
+ * right frame on the right ipo curve (creating both the
+ * ipo curve and the bezier if needed).
+ */
+ IpoCurve *icu= voidicu;
+ BezTriple *bezt=NULL;
+ float cfra, icuval;
+
+ cfra = frame_to_float(CFRA);
+ if (G.saction->pin==0 && OBACT)
+ cfra= get_action_frame(OBACT, cfra);
+
+ /* if the ipocurve exists, try to get a bezier
+ * for this frame
+ */
+ bezt = get_bezt_icu_time(icu, &cfra, &icuval);
+
+ /* create the bezier triple if one doesn't exist,
+ * otherwise modify it's value
+ */
+ if (bezt == NULL) {
+ insert_vert_icu(icu, cfra, icu->curval, 0);
+ }
+ else {
+ bezt->vec[1][1] = icu->curval;
+ }
+
+ /* make sure the Ipo's are properly processed and
+ * redraw as necessary
+ */
+ sort_time_ipocurve(icu);
+ testhandles_ipocurve(icu);
+
+ /* nla-update (in case this affects anything) */
+ synchronize_action_strips();
+
+ /* do redraw pushes, and also the depsgraph flushes */
+ if (OBACT->pose || ob_get_key(OBACT))
+ DAG_object_flush_update(G.scene, OBACT, OB_RECALC);
+ else
+ DAG_object_flush_update(G.scene, OBACT, OB_RECALC_OB);
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWNLA, 0);
+ allqueue(REDRAWIPO, 0);
+ allspace(REMAKEIPO, 0);
+ allqueue(REDRAWBUTSALL, 0);
+}
+
+static void make_icu_slider(uiBlock *block, IpoCurve *icu,
+ int x, int y, int w, int h, char *tip)
+{
+ /* create a slider for the ipo-curve*/
+ uiBut *but;
+
+ if(icu==NULL) return;
+
+ if (IS_EQ(icu->slide_max, icu->slide_min)) {
+ if (IS_EQ(icu->ymax, icu->ymin)) {
+ if (ELEM(icu->blocktype, ID_CO, ID_KE)) {
+ /* hack for constraints and shapekeys (and maybe a few others) */
+ icu->slide_min= 0.0;
+ icu->slide_max= 1.0;
+ }
+ else {
+ icu->slide_min= -100;
+ icu->slide_max= 100;
+ }
+ }
+ else {
+ icu->slide_min= icu->ymin;
+ icu->slide_max= icu->ymax;
+ }
+ }
+ if (icu->slide_min >= icu->slide_max) {
+ SWAP(float, icu->slide_min, icu->slide_max);
+ }
+
+ but=uiDefButF(block, NUMSLI, REDRAWVIEW3D, "",
+ x, y , w, h,
+ &(icu->curval), icu->slide_min, icu->slide_max,
+ 10, 2, tip);
+
+ uiButSetFunc(but, icu_slider_func, icu, NULL);
+
+ // no hilite, the winmatrix is not correct later on...
+ uiButSetFlag(but, UI_NO_HILITE);
+}
+
+/* sliders for ipo-curves of active action-channel */
+static void action_icu_buts(SpaceAction *saction)
+{
+ bAction *act= saction->action;
+ bActionChannel *achan;
+ bConstraintChannel *conchan;
+ IpoCurve *icu;
+ char str[64];
+ float x, y;
+ uiBlock *block;
+
+ /* lets make the action sliders */
+
+ /* reset the damn myortho2 or the sliders won't draw/redraw
+ * correctly *grumble*
+ */
+ mywinset(curarea->win);
+ myortho2(-0.375, curarea->winx-0.375, G.v2d->cur.ymin, G.v2d->cur.ymax);
+
+ sprintf(str, "actionbuttonswin %d", curarea->win);
+ block= uiNewBlock (&curarea->uiblocks, str,
+ UI_EMBOSS, UI_HELV, curarea->win);
+
+ x = NAMEWIDTH + 1;
+ y = 0.0f;
+
+ uiBlockSetEmboss(block, UI_EMBOSSN);
+
+ if (G.saction->flag & SACTION_SLIDERS) {
+ /* sliders are open so draw them */
+
+ /* draw backdrop first */
+ BIF_ThemeColor(TH_FACE); // change this color... it's ugly
+ glRects(NAMEWIDTH, G.v2d->cur.ymin, NAMEWIDTH+SLIDERWIDTH, G.v2d->cur.ymax);
+
+ uiBlockSetEmboss(block, UI_EMBOSS);
+ for (achan=act->chanbase.first; achan; achan= achan->next) {
+ if(VISIBLE_ACHAN(achan)) {
+ y-=CHANNELHEIGHT+CHANNELSKIP;
+
+ if (EXPANDED_ACHAN(achan)) {
+ if (achan->ipo) {
+ y-=CHANNELHEIGHT+CHANNELSKIP;
+
+ if (FILTER_IPO_ACHAN(achan)) {
+ for (icu= achan->ipo->curve.first; icu; icu=icu->next) {
+ if (achan->flag & ACHAN_HILIGHTED) {
+ make_icu_slider(block, icu,
+ x, y, SLIDERWIDTH-2, CHANNELHEIGHT-2,
+ "Slider to control current value of IPO-Curve");
+ }
+
+ y-=CHANNELHEIGHT+CHANNELSKIP;
+ }
+ }
+ }
+
+ if (achan->constraintChannels.first) {
+ y-=CHANNELHEIGHT+CHANNELSKIP;
+
+ if (FILTER_CON_ACHAN(achan)) {
+ for (conchan= achan->constraintChannels.first; conchan; conchan=conchan->next) {
+ if ((achan->flag & ACHAN_HILIGHTED) && EDITABLE_CONCHAN(conchan)) {
+ icu= (IpoCurve *)conchan->ipo->curve.first;
+ make_icu_slider(block, icu,
+ x, y, SLIDERWIDTH-2, CHANNELHEIGHT-2,
+ "Slider to control current value of Constraint Channel");
+ }
+
+ y-=CHANNELHEIGHT+CHANNELSKIP;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ uiDrawBlock(block);
+}
+
+/********************************** Current Frame **************************** */
+
+void draw_cfra_action (void)
+{
+ Object *ob;
+ float vec[2];
+
+ /* Draw a light green line to indicate current frame */
+ vec[0]= (G.scene->r.cfra);
+ vec[0]*= G.scene->r.framelen;
+
+ vec[1]= G.v2d->cur.ymin;
+ glColor3ub(0x60, 0xc0, 0x40);
+ glLineWidth(2.0);
+
+ glBegin(GL_LINE_STRIP);
+ glVertex2fv(vec);
+ vec[1]= G.v2d->cur.ymax;
+ glVertex2fv(vec);
+ glEnd();
+
+ /* Draw dark green line if slow-parenting/time-offset is enabled */
+ ob= (G.scene->basact) ? (G.scene->basact->object) : 0;
+ if(ob && ob->sf!=0.0 && (ob->ipoflag & OB_OFFS_OB) ) {
+ vec[0]-= ob->sf;
+
+ glColor3ub(0x10, 0x60, 0);
+
+ glBegin(GL_LINE_STRIP);
+ glVertex2fv(vec);
+ vec[1]= G.v2d->cur.ymin;
+ glVertex2fv(vec);
+ glEnd();
+ }
+
+ glLineWidth(1.0);
+}
+
+/********************************** Left-Hand Panel + Generics **************************** */
+
+/* left hand part */
+static void draw_channel_names(void)
+{
+ ListBase act_data = {NULL, NULL};
+ bActListElem *ale;
+ int filter;
+ void *data;
+ short datatype;
+ short ofsx = 0, ofsy = 0;
+ float x= 0.0f, y= 0.0f;
+
+ /* determine what type of data we are operating on */
+ data = get_action_context(&datatype);
+ if (data == NULL) return;
+
+ /* Clip to the scrollable area */
+ if(curarea->winx>SCROLLB+10 && curarea->winy>SCROLLH+10) {
+ if(G.v2d->scroll) {
+ ofsx= curarea->winrct.xmin;
+ ofsy= curarea->winrct.ymin;
+ glViewport(ofsx, ofsy+G.v2d->mask.ymin, NAMEWIDTH,
+ (ofsy+G.v2d->mask.ymax) -
+ (ofsy+G.v2d->mask.ymin));
+ glScissor(ofsx, ofsy+G.v2d->mask.ymin, NAMEWIDTH,
+ (ofsy+G.v2d->mask.ymax) -
+ (ofsy+G.v2d->mask.ymin));
+ }
+ }
+
+ /* prepare scaling for LHS panel */
+ myortho2(0, NAMEWIDTH, G.v2d->cur.ymin, G.v2d->cur.ymax);
+
+ /* set default color back to black */
+ glColor3ub(0x00, 0x00, 0x00);
+
+ /* build list of channels to draw */
+ filter= (ACTFILTER_FORDRAWING|ACTFILTER_VISIBLE|ACTFILTER_CHANNELS);
+ actdata_filter(&act_data, filter, data, datatype);
+
+ /* loop through channels, and set up drawing depending on their type */
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ for (ale= act_data.first; ale; ale= ale->next) {
+ short indent= 0, offset= 0, sel= 0;
+ int expand= -1, protect = -1, special= -1, mute = -1;
+ char name[32];
+
+ /* determine what needs to be drawn */
+ switch (ale->type) {
+ case ACTTYPE_ACHAN: /* action channel */
+ {
+ bActionChannel *achan= (bActionChannel *)ale->data;
+
+ indent = 0;
+ special = -1;
+
+ if (EXPANDED_ACHAN(achan))
+ expand = ICON_TRIA_DOWN;
+ else
+ expand = ICON_TRIA_RIGHT;
+
+ if (EDITABLE_ACHAN(achan))
+ protect = ICON_UNLOCKED;
+ else
+ protect = ICON_LOCKED;
+
+ if (achan->ipo) {
+ if (achan->ipo->muteipo)
+ mute = ICON_MUTE_IPO_ON;
+ else
+ mute = ICON_MUTE_IPO_OFF;
+ }
+
+ sel = SEL_ACHAN(achan);
+ sprintf(name, achan->name);
+ }
+ break;
+ case ACTTYPE_CONCHAN: /* constraint channel */
+ {
+ bConstraintChannel *conchan = (bConstraintChannel *)ale->data;
+
+ indent = 2;
+
+ if (EDITABLE_CONCHAN(conchan))
+ protect = ICON_UNLOCKED;
+ else
+ protect = ICON_LOCKED;
+
+ if (conchan->ipo) {
+ if (conchan->ipo->muteipo)
+ mute = ICON_MUTE_IPO_ON;
+ else
+ mute = ICON_MUTE_IPO_OFF;
+ }
+
+ sel = SEL_CONCHAN(conchan);
+ sprintf(name, conchan->name);
+ }
+ break;
+ case ACTTYPE_ICU: /* ipo-curve channel */
+ {
+ IpoCurve *icu = (IpoCurve *)ale->data;
+
+ indent = 2;
+ protect = -1; // for now, until this can be supported by others
+
+ if (icu->flag & IPO_MUTE)
+ mute = ICON_MUTE_IPO_ON;
+ else
+ mute = ICON_MUTE_IPO_OFF;
+
+ sel = SEL_ICU(icu);
+ if (G.saction->pin)
+ sprintf(name, getname_ipocurve(icu, NULL));
+ else
+ sprintf(name, getname_ipocurve(icu, OBACT));
+ }
+ break;
+ case ACTTYPE_SHAPEKEY: /* shapekey channel */
+ {
+ KeyBlock *kb = (KeyBlock *)ale->data;
+
+ indent = 0;
+ special = -1;
+
+ if (kb->name[0] == '\0')
+ sprintf(name, "Key %d", ale->index);
+ else
+ sprintf(name, kb->name);
+ }
+ break;
+ case ACTTYPE_FILLIPO: /* ipo expand widget */
+ {
+ bActionChannel *achan = (bActionChannel *)ale->data;
+
+ indent = 1;
+ special = geticon_ipo_blocktype(achan->ipo->blocktype);
+
+ if (FILTER_IPO_ACHAN(achan))
+ expand = ICON_TRIA_DOWN;
+ else
+ expand = ICON_TRIA_RIGHT;
+
+ sel = SEL_ACHAN(achan);
+ sprintf(name, "IPO Curves");
+ }
+ break;
+ case ACTTYPE_FILLCON: /* constraint expand widget */
+ {
+ bActionChannel *achan = (bActionChannel *)ale->data;
+
+ indent = 1;
+ special = ICON_CONSTRAINT;
+
+ if (FILTER_CON_ACHAN(achan))
+ expand = ICON_TRIA_DOWN;
+ else
+ expand = ICON_TRIA_RIGHT;
+
+ sel = SEL_ACHAN(achan);
+ sprintf(name, "Constraint");
+ }
+ break;
+ }
+
+ /* now, start drawing based on this information */
+ /* draw backing strip behind channel name */
+ BIF_ThemeColorShade(TH_HEADER, ((indent==0)?20: (indent==1)?-20: -40));
+ offset = 7 * indent;
+ glRectf(x+offset, y-CHANNELHEIGHT/2, (float)NAMEWIDTH, y+CHANNELHEIGHT/2);
+
+ /* draw expand/collapse triangle */
+ if (expand > 0) {
+ BIF_icon_draw(x+offset, y-CHANNELHEIGHT/2, expand);
+ offset += 17;
+ }
+
+ /* draw special icon indicating type of ipo-blocktype?
+ * only for expand widgets for Ipo and Constraint Channels
+ */
+ if (special > 0) {
+ offset = 24;
+ BIF_icon_draw(x+offset, y-CHANNELHEIGHT/2, special);
+ offset += 17;
+ }
+
+ /* draw name */
+ if (sel)
+ BIF_ThemeColor(TH_TEXT_HI);
+ else
+ BIF_ThemeColor(TH_TEXT);
+ offset += 3;
+ glRasterPos2f(x+offset, y-4);
+ BMF_DrawString(G.font, name);
+
+ /* reset offset - for RHS of panel */
+ offset = 0;
+
+ /* draw protect 'lock' */
+ if (protect > 0) {
+ offset = 16;
+ BIF_icon_draw(NAMEWIDTH-offset, y-CHANNELHEIGHT/2, protect);
+ }
+
+ /* draw mute 'eye' */
+ if (mute > 0) {
+ offset += 16;
+ BIF_icon_draw(NAMEWIDTH-offset, y-CHANNELHEIGHT/2, mute);
+ }
+
+ /* adjust y-position for next one */
+ y-=CHANNELHEIGHT+CHANNELSKIP;
+ }
+
+ /* free tempolary channels */
+ BLI_freelistN(&act_data);
+
+ /* re-adjust view matrices for correct scaling */
+ myortho2(0, NAMEWIDTH, 0, (ofsy+G.v2d->mask.ymax) - (ofsy+G.v2d->mask.ymin)); // Scaling
+}
+
+/* sets or clears hidden flags */
+void check_action_context(SpaceAction *saction)
+{
+ bActionChannel *achan;
+
+ if(saction->action==NULL) return;
+
+ for (achan=saction->action->chanbase.first; achan; achan=achan->next)
+ achan->flag &= ~ACHAN_HIDDEN;
+
+ if (G.saction->pin==0 && OBACT) {
+ Object *ob= OBACT;
+ bPoseChannel *pchan;
+ bArmature *arm= ob->data;
+
+ for (achan=saction->action->chanbase.first; achan; achan=achan->next) {
+ pchan= get_pose_channel(ob->pose, achan->name);
+ if (pchan) {
+ if ((pchan->bone->layer & arm->layer)==0)
+ achan->flag |= ACHAN_HIDDEN;
+ else if (pchan->bone->flag & BONE_HIDDEN_P)
+ achan->flag |= ACHAN_HIDDEN;
+ }
+ }
+ }
+}
+
+static void draw_channel_strips(void)
+{
+ ListBase act_data = {NULL, NULL};
+ bActListElem *ale;
+ int filter;
+ void *data;
+ short datatype;
+
+ rcti scr_rct;
+ gla2DDrawInfo *di;
+ float y, sta, end;
+ int act_start, act_end, dummy;
+ char col1[3], col2[3];
+
+ BIF_GetThemeColor3ubv(TH_SHADE2, col2);
+ BIF_GetThemeColor3ubv(TH_HILITE, col1);
+
+ /* get editor data */
+ data= get_action_context(&datatype);
+ if (data == NULL) return;
+
+ scr_rct.xmin= G.saction->area->winrct.xmin + G.saction->v2d.mask.xmin;
+ scr_rct.ymin= G.saction->area->winrct.ymin + G.saction->v2d.mask.ymin;
+ scr_rct.xmax= G.saction->area->winrct.xmin + G.saction->v2d.hor.xmax;
+ scr_rct.ymax= G.saction->area->winrct.ymin + G.saction->v2d.mask.ymax;
+ di= glaBegin2DDraw(&scr_rct, &G.v2d->cur);
+
+ /* if in NLA there's a strip active, map the view */
+ if (datatype == ACTCONT_ACTION) {
+ if (NLA_ACTION_SCALED)
+ map_active_strip(di, OBACT, 0);
+
+ /* start and end of action itself */
+ calc_action_range(data, &sta, &end, 0);
+ gla2DDrawTranslatePt(di, sta, 0.0f, &act_start, &dummy);
+ gla2DDrawTranslatePt(di, end, 0.0f, &act_end, &dummy);
+
+ if (NLA_ACTION_SCALED)
+ map_active_strip(di, OBACT, 1);
+ }
+
+ /* build list of channels to draw */
+ filter= (ACTFILTER_FORDRAWING|ACTFILTER_VISIBLE|ACTFILTER_CHANNELS);
+ actdata_filter(&act_data, filter, data, datatype);
+
+ /* first backdrop strips */
+ y = 0.0;
+ glEnable(GL_BLEND);
+ for (ale= act_data.first; ale; ale= ale->next) {
+ int frame1_x, channel_y, sel=0;
+
+ /* determine if any need to draw channel */
+ if (ale->datatype != ALE_NONE) {
+ /* determine if channel is selected */
+ switch (ale->type) {
+ case ACTTYPE_ACHAN:
+ {
+ bActionChannel *achan = (bActionChannel *)ale->data;
+ sel = SEL_ACHAN(achan);
+ }
+ break;
+ case ACTTYPE_CONCHAN:
+ {
+ bConstraintChannel *conchan = (bConstraintChannel *)ale->data;
+ sel = SEL_CONCHAN(conchan);
+ }
+ break;
+ case ACTTYPE_ICU:
+ {
+ IpoCurve *icu = (IpoCurve *)ale->data;
+ sel = SEL_ICU(icu);
+ }
+ break;
+ }
+
+ if (datatype == ACTCONT_ACTION) {
+ gla2DDrawTranslatePt(di, G.v2d->cur.xmin, y, &frame1_x, &channel_y);
+
+ if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x22);
+ else glColor4ub(col2[0], col2[1], col2[2], 0x22);
+ glRectf(frame1_x, channel_y-CHANNELHEIGHT/2, G.v2d->hor.xmax, channel_y+CHANNELHEIGHT/2);
+
+ if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x22);
+ else glColor4ub(col2[0], col2[1], col2[2], 0x22);
+ glRectf(act_start, channel_y-CHANNELHEIGHT/2, act_end, channel_y+CHANNELHEIGHT/2);
+ }
+ else if (datatype == ACTCONT_SHAPEKEY) {
+ gla2DDrawTranslatePt(di, 1, y, &frame1_x, &channel_y);
+
+ /* all frames that have a frame number less than one
+ * get a desaturated orange background
+ */
+ glColor4ub(col2[0], col2[1], col2[2], 0x22);
+ glRectf(0, channel_y-CHANNELHEIGHT/2, frame1_x, channel_y+CHANNELHEIGHT/2);
+
+ /* frames one and higher get a saturated orange background */
+ glColor4ub(col2[0], col2[1], col2[2], 0x44);
+ glRectf(frame1_x, channel_y-CHANNELHEIGHT/2, G.v2d->hor.xmax, channel_y+CHANNELHEIGHT/2);
+ }
+ }
+
+ /* Increment the step */
+ y-=CHANNELHEIGHT+CHANNELSKIP;
+ }
+ glDisable(GL_BLEND);
+
+ if (NLA_ACTION_SCALED)
+ map_active_strip(di, OBACT, 0);
+
+ /* draw keyframes */
+ y = 0.0;
+ for (ale= act_data.first; ale; ale= ale->next) {
+ switch (ale->datatype) {
+ case ALE_IPO:
+ draw_ipo_channel(di, ale->key_data, y);
+ break;
+ case ALE_ICU:
+ draw_icu_channel(di, ale->key_data, y);
+ break;
+ }
+
+ y-=CHANNELHEIGHT+CHANNELSKIP;
+ }
+
+ /* free tempolary channels used for drawing */
+ BLI_freelistN(&act_data);
+
+ /* black line marking 'current frame' for Time-Slide transform mode */
+ if (G.saction->flag & SACTION_MOVING) {
+ int frame1_x, channel_y;
+
+ gla2DDrawTranslatePt(di, G.saction->timeslide, 0, &frame1_x, &channel_y);
+ cpack(0x0);
+
+ glBegin(GL_LINES);
+ glVertex2f(frame1_x, G.v2d->mask.ymin - 100);
+ glVertex2f(frame1_x, G.v2d->mask.ymax);
+ glEnd();
+ }
+
+ glaEnd2DDraw(di);
+}
+
+/* ********* action panel *********** */
+
+
+void do_actionbuts(unsigned short event)
+{
+ switch(event) {
+ case REDRAWVIEW3D:
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+ case B_REDR:
+ allqueue(REDRAWACTION, 0);
+ break;
+ }
+}
+
+
+static void action_panel_properties(short cntrl) // ACTION_HANDLER_PROPERTIES
+{
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "action_panel_properties", UI_EMBOSS, UI_HELV, curarea->win);
+ uiPanelControl(UI_PNL_SOLID | UI_PNL_CLOSE | cntrl);
+ uiSetPanelHandler(ACTION_HANDLER_PROPERTIES); // for close and esc
+ if(uiNewPanel(curarea, block, "Transform Properties", "Action", 10, 230, 318, 204)==0) return;
+
+ uiDefBut(block, LABEL, 0, "test text", 10,180,300,19, 0, 0, 0, 0, 0, "");
+
+}
+
+static void action_blockhandlers(ScrArea *sa)
+{
+ SpaceAction *sact= sa->spacedata.first;
+ short a;
+
+ for(a=0; a<SPACE_MAXHANDLER; a+=2) {
+ switch(sact->blockhandler[a]) {
+
+ case ACTION_HANDLER_PROPERTIES:
+ action_panel_properties(sact->blockhandler[a+1]);
+ break;
+
+ }
+ /* clear action value for event */
+ sact->blockhandler[a+1]= 0;
+ }
+ uiDrawBlocksPanels(sa, 0);
+}
+
+/* ************************* Action Editor Space ***************************** */
+
+void drawactionspace(ScrArea *sa, void *spacedata)
+{
+ bAction *act = NULL;
+ Key *key = NULL;
+ void *data;
+ short datatype;
+
+ short ofsx = 0, ofsy = 0;
+ float col[3];
+
+ /* this is unlikely to occur, but it may */
+ if (G.saction == NULL)
+ return;
+
+ /* warning: blocks need to be freed each time, handlers dont remove */
+ uiFreeBlocksWin(&sa->uiblocks, sa->win);
+
+ /* only try to refresh action that's displayed if not pinned */
+ if (G.saction->pin==0) {
+ /* TODO: allow more than one active action sometime? */
+ if (OBACT)
+ G.saction->action = OBACT->action;
+ else
+ G.saction->action= NULL;
+ }
+
+ /* get data */
+ data = get_action_context(&datatype);
+ if (datatype == ACTCONT_ACTION)
+ act = data;
+ else if (datatype == ACTCONT_SHAPEKEY)
+ key = data;
+
+ /* Lets make sure the width of the left hand of the screen
+ * is set to an appropriate value based on whether sliders
+ * are showing of not
+ */
+ if ((data) && (G.saction->flag & SACTION_SLIDERS))
+ ACTWIDTH = NAMEWIDTH + SLIDERWIDTH;
+ else
+ ACTWIDTH = NAMEWIDTH;
+
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ calc_scrollrcts(sa, G.v2d, curarea->winx, curarea->winy);
+
+ /* background color for entire window (used in lefthand part though) */
+ BIF_GetThemeColor3fv(TH_HEADER, col);
+ glClearColor(col[0], col[1], col[2], 0.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ if(curarea->winx>SCROLLB+10 && curarea->winy>SCROLLH+10) {
+ if(G.v2d->scroll) {
+ ofsx= curarea->winrct.xmin;
+ ofsy= curarea->winrct.ymin;
+ glViewport(ofsx+G.v2d->mask.xmin, ofsy+G.v2d->mask.ymin,
+ ( ofsx+G.v2d->mask.xmax-1)-(ofsx+G.v2d->mask.xmin)+1,
+ ( ofsy+G.v2d->mask.ymax-1)-( ofsy+G.v2d->mask.ymin)+1);
+ glScissor(ofsx+G.v2d->mask.xmin, ofsy+G.v2d->mask.ymin,
+ ( ofsx+G.v2d->mask.xmax-1)-(ofsx+G.v2d->mask.xmin)+1,
+ ( ofsy+G.v2d->mask.ymax-1)-( ofsy+G.v2d->mask.ymin)+1);
+ }
+ }
+
+ BIF_GetThemeColor3fv(TH_BACK, col);
+ glClearColor(col[0], col[1], col[2], 0.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ myortho2(G.v2d->cur.xmin, G.v2d->cur.xmax, G.v2d->cur.ymin, G.v2d->cur.ymax);
+ bwin_clear_viewmat(sa->win); /* clear buttons view */
+ glLoadIdentity();
+
+ /* Draw backdrop */
+ calc_ipogrid();
+ draw_ipogrid();
+
+ check_action_context(G.saction);
+
+ /* Draw channel strips */
+ draw_channel_strips();
+
+ /* reset matrices for stuff to be drawn on top of keys*/
+ glViewport(ofsx+G.v2d->mask.xmin,
+ ofsy+G.v2d->mask.ymin,
+ ( ofsx+G.v2d->mask.xmax-1)-(ofsx+G.v2d->mask.xmin)+1,
+ ( ofsy+G.v2d->mask.ymax-1)-( ofsy+G.v2d->mask.ymin)+1);
+ glScissor(ofsx+G.v2d->mask.xmin,
+ ofsy+G.v2d->mask.ymin,
+ ( ofsx+G.v2d->mask.xmax-1)-(ofsx+G.v2d->mask.xmin)+1,
+ ( ofsy+G.v2d->mask.ymax-1)-( ofsy+G.v2d->mask.ymin)+1);
+ myortho2(G.v2d->cur.xmin, G.v2d->cur.xmax, G.v2d->cur.ymin, G.v2d->cur.ymax);
+
+ /* Draw current frame */
+ draw_cfra_action();
+
+ /* Draw markers */
+ draw_markers_timespace(0);
+
+ /* Draw 'curtains' for preview */
+ draw_anim_preview_timespace();
+
+ /* Draw scroll */
+ mywinset(curarea->win); // reset scissor too
+ if (curarea->winx>SCROLLB+10 && curarea->winy>SCROLLH+10) {
+ myortho2(-0.375, curarea->winx-0.375, -0.375, curarea->winy-0.375);
+ if (G.v2d->scroll) drawscroll(0);
+ }
+
+ /* Draw Left-Hand Panel if enough space in window */
+ if (G.v2d->mask.xmin!=0) {
+ /* Draw channel names */
+ draw_channel_names();
+
+ if(sa->winx > 50 + NAMEWIDTH + SLIDERWIDTH) {
+ if (act) {
+ /* if there is an action, draw sliders for its
+ * ipo-curve channels in the action window
+ */
+ action_icu_buts(G.saction);
+ }
+ else if (key) {
+ /* if there is a mesh with rvk's selected,
+ * then draw the key frames in the action window
+ */
+ meshactionbuts(G.saction, OBACT, key);
+ }
+ }
+ }
+
+ mywinset(curarea->win); // reset scissor too
+ myortho2(-0.375, curarea->winx-0.375, -0.375, curarea->winy-0.375);
+ draw_area_emboss(sa);
+
+ /* it is important to end a view in a transform compatible with buttons */
+ bwin_scalematrix(sa->win, G.saction->blockscale, G.saction->blockscale, G.saction->blockscale);
+ action_blockhandlers(sa);
+
+ curarea->win_swap= WIN_BACK_OK;
+}
+
+/* *************************** Keyframe Drawing *************************** */
+
+static void add_bezt_to_keycolumnslist(ListBase *keys, BezTriple *bezt)
+{
+ /* The equivilant of add_to_cfra_elem except this version
+ * makes ActKeyColumns - one of the two datatypes required
+ * for action editor drawing.
+ */
+ ActKeyColumn *ak, *akn;
+
+ if (!(keys) || !(bezt)) return;
+
+ /* try to find a keyblock that starts on the previous beztriple */
+ for (ak= keys->first; ak; ak= ak->next) {
+ /* do because of double keys */
+ if (ak->cfra == bezt->vec[1][0]) {
+ /* set selection status and 'touched' status */
+ if (BEZSELECTED(bezt)) ak->sel = SELECT;
+ ak->modified += 1;
+
+ return;
+ }
+ else if (ak->cfra > bezt->vec[1][0]) break;
+ }
+
+ /* add new block */
+ akn= MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumn");
+ if (ak) BLI_insertlinkbefore(keys, ak, akn);
+ else BLI_addtail(keys, akn);
+
+ akn->cfra= bezt->vec[1][0];
+ akn->modified += 1;
+
+ // TODO: handle type = bezt->h1 or bezt->h2
+ akn->handle_type= 0;
+
+ if (BEZSELECTED(bezt))
+ akn->sel = SELECT;
+ else
+ akn->sel = 0;
+}
+
+static void add_bezt_to_keyblockslist(ListBase *blocks, IpoCurve *icu, int index)
+{
+ /* The equivilant of add_to_cfra_elem except this version
+ * makes ActKeyBlocks - one of the two datatypes required
+ * for action editor drawing.
+ */
+ ActKeyBlock *ab, *abn;
+ BezTriple *beztn=NULL, *prev=NULL;
+ BezTriple *bezt;
+ int v;
+
+ /* get beztriples */
+ beztn= (icu->bezt + index);
+
+ for (v=0, bezt=icu->bezt; v<icu->totvert; v++, bezt++) {
+ /* skip if beztriple is current */
+ if (v != index) {
+ /* check if beztriple is immediately before */
+ if (beztn->vec[1][0] > bezt->vec[1][0]) {
+ /* check if closer than previous was */
+ if (prev) {
+ if (prev->vec[1][0] < bezt->vec[1][0])
+ prev= bezt;
+ }
+ else {
+ prev= bezt;
+ }
+ }
+ }
+ }
+
+ /* check if block needed - same value? */
+ if ((!prev) || (!beztn))
+ return;
+ if (beztn->vec[1][1] != prev->vec[1][1])
+ return;
+
+ /* try to find a keyblock that starts on the previous beztriple */
+ for (ab= blocks->first; ab; ab= ab->next) {
+ /* check if alter existing block or add new block */
+ if (ab->start == prev->vec[1][0]) {
+ /* set selection status and 'touched' status */
+ if (BEZSELECTED(beztn)) ab->sel = SELECT;
+ ab->modified += 1;
+
+ return;
+ }
+ else if (ab->start > prev->vec[1][0]) break;
+ }
+
+ /* add new block */
+ abn= MEM_callocN(sizeof(ActKeyBlock), "ActKeyBlock");
+ if (ab) BLI_insertlinkbefore(blocks, ab, abn);
+ else BLI_addtail(blocks, abn);
+
+ abn->start= prev->vec[1][0];
+ abn->end= beztn->vec[1][0];
+ abn->val= beztn->vec[1][1];
+
+ if (BEZSELECTED(prev) || BEZSELECTED(beztn))
+ abn->sel = SELECT;
+ else
+ abn->sel = 0;
+ abn->modified = 1;
+}
+
+/* helper function - find actkeycolumn that occurs on cframe */
+static ActKeyColumn *cfra_find_actkeycolumn (ListBase *keys, float cframe)
+{
+ ActKeyColumn *ak;
+
+ if (keys==NULL)
+ return NULL;
+
+ for (ak= keys->first; ak; ak= ak->next) {
+ if (ak->cfra == cframe)
+ return ak;
+ }
+
+ return NULL;
+}
+
+static void draw_keylist(gla2DDrawInfo *di, ListBase *keys, ListBase *blocks, float ypos)
+{
+ ActKeyColumn *ak;
+ ActKeyBlock *ab;
+
+ glEnable(GL_BLEND);
+
+ /* draw keyblocks */
+ if (blocks) {
+ for (ab= blocks->first; ab; ab= ab->next) {
+ short startCurves, endCurves, totCurves;
+
+ /* find out how many curves occur at each keyframe */
+ ak= cfra_find_actkeycolumn(keys, ab->start);
+ startCurves = (ak)? ak->totcurve: 0;
+
+ ak= cfra_find_actkeycolumn(keys, ab->end);
+ endCurves = (ak)? ak->totcurve: 0;
+
+ /* only draw keyblock if it appears in at all of the keyframes at lowest end */
+ if (!startCurves && !endCurves)
+ continue;
+ else
+ totCurves = (startCurves>endCurves)? endCurves: startCurves;
+
+ if (ab->totcurve >= totCurves) {
+ int sc_xa, sc_ya;
+ int sc_xb, sc_yb;
+
+ /* get co-ordinates of block */
+ gla2DDrawTranslatePt(di, ab->start, ypos, &sc_xa, &sc_ya);
+ gla2DDrawTranslatePt(di, ab->end, ypos, &sc_xb, &sc_yb);
+
+ /* draw block */
+ if (ab->sel)
+ BIF_ThemeColor4(TH_STRIP_SELECT);
+ else
+ BIF_ThemeColor4(TH_STRIP);
+ glRectf(sc_xa, sc_ya-3, sc_xb, sc_yb+5);
+ }
+ }
+ }
+
+ /* draw keys */
+ if (keys) {
+ for (ak= keys->first; ak; ak= ak->next) {
+ int sc_x, sc_y;
+
+ /* get co-ordinate to draw at */
+ gla2DDrawTranslatePt(di, ak->cfra, ypos, &sc_x, &sc_y);
+
+ if(ak->sel & 1) BIF_icon_draw_aspect(sc_x-7, sc_y-6, ICON_SPACE2, 1.0f);
+ else BIF_icon_draw_aspect(sc_x-7, sc_y-6, ICON_SPACE3, 1.0f);
+ }
+ }
+
+ glDisable(GL_BLEND);
+}
+
+void draw_object_channel(gla2DDrawInfo *di, Object *ob, float ypos)
+{
+ ListBase keys = {0, 0};
+ ListBase blocks = {0, 0};
+
+ ob_to_keylist(ob, &keys, &blocks);
+ draw_keylist(di, &keys, &blocks, ypos);
+
+ BLI_freelistN(&keys);
+ BLI_freelistN(&blocks);
+}
+
+void draw_ipo_channel(gla2DDrawInfo *di, Ipo *ipo, float ypos)
+{
+ ListBase keys = {0, 0};
+ ListBase blocks = {0, 0};
+
+ ipo_to_keylist(ipo, &keys, &blocks);
+ draw_keylist(di, &keys, &blocks, ypos);
+
+ BLI_freelistN(&keys);
+ BLI_freelistN(&blocks);
+}
+
+void draw_icu_channel(gla2DDrawInfo *di, IpoCurve *icu, float ypos)
+{
+ ListBase keys = {0, 0};
+ ListBase blocks = {0, 0};
+
+ icu_to_keylist(icu, &keys, &blocks);
+ draw_keylist(di, &keys, &blocks, ypos);
+
+ BLI_freelistN(&keys);
+ BLI_freelistN(&blocks);
+}
+
+void draw_action_channel(gla2DDrawInfo *di, bAction *act, float ypos)
+{
+ ListBase keys = {0, 0};
+
+ action_to_keylist(act, &keys, NULL);
+ draw_keylist(di, &keys, NULL, ypos);
+ BLI_freelistN(&keys);
+}
+
+/* --------------- Conversion: data -> keyframe list ------------------ */
+
+void ob_to_keylist(Object *ob, ListBase *keys, ListBase *blocks)
+{
+ bConstraintChannel *conchan;
+
+ if (ob) {
+ /* Add object keyframes */
+ if (ob->ipo)
+ ipo_to_keylist(ob->ipo, keys, blocks);
+
+ /* Add constraint keyframes */
+ for (conchan=ob->constraintChannels.first; conchan; conchan=conchan->next){
+ if(conchan->ipo)
+ ipo_to_keylist(conchan->ipo, keys, blocks);
+ }
+
+ /* Add object data keyframes */
+ // TODO??
+ }
+}
+
+void icu_to_keylist(IpoCurve *icu, ListBase *keys, ListBase *blocks)
+{
+ BezTriple *bezt;
+ ActKeyColumn *ak;
+ ActKeyBlock *ab;
+ int v;
+
+ if (icu && icu->totvert) {
+ /* loop through beztriples, making ActKeys and ActKeyBlocks */
+ bezt= icu->bezt;
+
+ for (v=0; v<icu->totvert; v++, bezt++) {
+ add_bezt_to_keycolumnslist(keys, bezt);
+ if (blocks) add_bezt_to_keyblockslist(blocks, icu, v);
+ }
+
+ /* update the number of curves that elements have appeared in */
+ if (keys) {
+ for (ak= keys->first; ak; ak= ak->next) {
+ if (ak->modified) {
+ ak->modified = 0;
+ ak->totcurve += 1;
+ }
+ }
+ }
+ if (blocks) {
+ for (ab= blocks->first; ab; ab= ab->next) {
+ if (ab->modified) {
+ ab->modified = 0;
+ ab->totcurve += 1;
+ }
+ }
+ }
+ }
+}
+
+void ipo_to_keylist(Ipo *ipo, ListBase *keys, ListBase *blocks)
+{
+ IpoCurve *icu;
+
+ if (ipo) {
+ for (icu= ipo->curve.first; icu; icu= icu->next)
+ icu_to_keylist(icu, keys, blocks);
+ }
+}
+
+void action_to_keylist(bAction *act, ListBase *keys, ListBase *blocks)
+{
+ bActionChannel *achan;
+ bConstraintChannel *conchan;
+
+ if (act) {
+ /* loop through action channels */
+ for (achan= act->chanbase.first; achan; achan= achan->next) {
+ /* firstly, add keys from action channel's ipo block */
+ if (achan->ipo)
+ ipo_to_keylist(achan->ipo, keys, blocks);
+
+ /* then, add keys from constraint channels */
+ for (conchan= achan->constraintChannels.first; conchan; conchan= conchan->next) {
+ if (conchan->ipo)
+ ipo_to_keylist(achan->ipo, keys, blocks);
+ }
+ }
+ }
+}
+
diff --git a/source/blender/src/drawarmature.c b/source/blender/src/drawarmature.c
new file mode 100644
index 00000000000..601a3fdf589
--- /dev/null
+++ b/source/blender/src/drawarmature.c
@@ -0,0 +1,2080 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 by the Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "BMF_Api.h"
+
+#include "DNA_action_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_ID.h"
+#include "DNA_nla_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_constraint.h"
+#include "BKE_depsgraph.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_object.h"
+#include "BKE_ipo.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_editaction.h"
+#include "BIF_editarmature.h"
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+#include "BIF_graphics.h"
+#include "BIF_interface.h"
+#include "BIF_poseobject.h"
+#include "BIF_mywindow.h"
+#include "BIF_resources.h"
+#include "BIF_screen.h"
+
+#include "BDR_editobject.h"
+#include "BDR_drawobject.h"
+#include "BDR_drawaction.h"
+
+#include "BSE_edit.h"
+#include "BSE_view.h"
+
+#include "mydevice.h"
+#include "blendef.h"
+#include "nla.h"
+
+/* half the cube, in Y */
+static float cube[8][3] = {
+{-1.0, 0.0, -1.0},
+{-1.0, 0.0, 1.0},
+{-1.0, 1.0, 1.0},
+{-1.0, 1.0, -1.0},
+{ 1.0, 0.0, -1.0},
+{ 1.0, 0.0, 1.0},
+{ 1.0, 1.0, 1.0},
+{ 1.0, 1.0, -1.0},
+};
+
+
+/* *************** Armature drawing, helper calls for parts ******************* */
+
+static void drawsolidcube_size(float xsize, float ysize, float zsize)
+{
+ static GLuint displist=0;
+ float n[3];
+
+ glScalef(xsize, ysize, zsize);
+
+ n[0]=0; n[1]=0; n[2]=0;
+
+ if(displist==0) {
+ displist= glGenLists(1);
+ glNewList(displist, GL_COMPILE_AND_EXECUTE);
+
+ glBegin(GL_QUADS);
+ n[0]= -1.0;
+ glNormal3fv(n);
+ glVertex3fv(cube[0]); glVertex3fv(cube[1]); glVertex3fv(cube[2]); glVertex3fv(cube[3]);
+ n[0]=0;
+ n[1]= -1.0;
+ glNormal3fv(n);
+ glVertex3fv(cube[0]); glVertex3fv(cube[4]); glVertex3fv(cube[5]); glVertex3fv(cube[1]);
+ n[1]=0;
+ n[0]= 1.0;
+ glNormal3fv(n);
+ glVertex3fv(cube[4]); glVertex3fv(cube[7]); glVertex3fv(cube[6]); glVertex3fv(cube[5]);
+ n[0]=0;
+ n[1]= 1.0;
+ glNormal3fv(n);
+ glVertex3fv(cube[7]); glVertex3fv(cube[3]); glVertex3fv(cube[2]); glVertex3fv(cube[6]);
+ n[1]=0;
+ n[2]= 1.0;
+ glNormal3fv(n);
+ glVertex3fv(cube[1]); glVertex3fv(cube[5]); glVertex3fv(cube[6]); glVertex3fv(cube[2]);
+ n[2]=0;
+ n[2]= -1.0;
+ glNormal3fv(n);
+ glVertex3fv(cube[7]); glVertex3fv(cube[4]); glVertex3fv(cube[0]); glVertex3fv(cube[3]);
+ glEnd();
+
+ glEndList();
+ }
+ else glCallList(displist);
+
+}
+
+static void drawcube_size(float xsize, float ysize, float zsize)
+{
+ static GLuint displist=0;
+
+ glScalef(xsize, ysize, zsize);
+
+ if(displist==0) {
+ displist= glGenLists(1);
+ glNewList(displist, GL_COMPILE_AND_EXECUTE);
+
+ glBegin(GL_LINE_STRIP);
+ glVertex3fv(cube[0]); glVertex3fv(cube[1]);glVertex3fv(cube[2]); glVertex3fv(cube[3]);
+ glVertex3fv(cube[0]); glVertex3fv(cube[4]);glVertex3fv(cube[5]); glVertex3fv(cube[6]);
+ glVertex3fv(cube[7]); glVertex3fv(cube[4]);
+ glEnd();
+
+ glBegin(GL_LINES);
+ glVertex3fv(cube[1]); glVertex3fv(cube[5]);
+ glVertex3fv(cube[2]); glVertex3fv(cube[6]);
+ glVertex3fv(cube[3]); glVertex3fv(cube[7]);
+ glEnd();
+
+ glEndList();
+ }
+ else glCallList(displist);
+
+}
+
+
+static void draw_bonevert(void)
+{
+ static GLuint displist=0;
+
+ if(displist==0) {
+ GLUquadricObj *qobj;
+
+ displist= glGenLists(1);
+ glNewList(displist, GL_COMPILE_AND_EXECUTE);
+
+ glPushMatrix();
+
+ qobj = gluNewQuadric();
+ gluQuadricDrawStyle(qobj, GLU_SILHOUETTE);
+ gluDisk( qobj, 0.0, 0.05, 16, 1);
+
+ glRotatef (90, 0, 1, 0);
+ gluDisk( qobj, 0.0, 0.05, 16, 1);
+
+ glRotatef (90, 1, 0, 0);
+ gluDisk( qobj, 0.0, 0.05, 16, 1);
+
+ gluDeleteQuadric(qobj);
+
+ glPopMatrix();
+ glEndList();
+ }
+ else glCallList(displist);
+}
+
+static void draw_bonevert_solid(void)
+{
+ static GLuint displist=0;
+
+ if(displist==0) {
+ GLUquadricObj *qobj;
+
+ displist= glGenLists(1);
+ glNewList(displist, GL_COMPILE_AND_EXECUTE);
+
+ qobj = gluNewQuadric();
+ gluQuadricDrawStyle(qobj, GLU_FILL);
+ glShadeModel(GL_SMOOTH);
+ gluSphere( qobj, 0.05, 8, 5);
+ glShadeModel(GL_FLAT);
+ gluDeleteQuadric(qobj);
+
+ glEndList();
+ }
+ else glCallList(displist);
+}
+
+static void draw_bone_octahedral()
+{
+ static GLuint displist=0;
+
+ if(displist==0) {
+ float vec[6][3];
+
+ displist= glGenLists(1);
+ glNewList(displist, GL_COMPILE_AND_EXECUTE);
+
+ vec[0][0]= vec[0][1]= vec[0][2]= 0.0;
+ vec[5][0]= vec[5][2]= 0.0; vec[5][1]= 1.0;
+
+ vec[1][0]= 0.1; vec[1][2]= 0.1; vec[1][1]= 0.1;
+ vec[2][0]= 0.1; vec[2][2]= -0.1; vec[2][1]= 0.1;
+ vec[3][0]= -0.1; vec[3][2]= -0.1; vec[3][1]= 0.1;
+ vec[4][0]= -0.1; vec[4][2]= 0.1; vec[4][1]= 0.1;
+
+ /* Section 1, sides */
+ glBegin(GL_LINE_LOOP);
+ glVertex3fv(vec[0]);
+ glVertex3fv(vec[1]);
+ glVertex3fv(vec[5]);
+ glVertex3fv(vec[3]);
+ glVertex3fv(vec[0]);
+ glVertex3fv(vec[4]);
+ glVertex3fv(vec[5]);
+ glVertex3fv(vec[2]);
+ glEnd();
+
+ /* Section 1, square */
+ glBegin(GL_LINE_LOOP);
+ glVertex3fv(vec[1]);
+ glVertex3fv(vec[2]);
+ glVertex3fv(vec[3]);
+ glVertex3fv(vec[4]);
+ glEnd();
+
+ glEndList();
+ }
+ else glCallList(displist);
+}
+
+static void draw_bone_solid_octahedral(void)
+{
+ static GLuint displist=0;
+
+ if(displist==0) {
+ float vec[6][3], nor[3];
+
+ displist= glGenLists(1);
+ glNewList(displist, GL_COMPILE_AND_EXECUTE);
+
+ vec[0][0]= vec[0][1]= vec[0][2]= 0.0;
+ vec[5][0]= vec[5][2]= 0.0; vec[5][1]= 1.0;
+
+ vec[1][0]= 0.1; vec[1][2]= 0.1; vec[1][1]= 0.1;
+ vec[2][0]= 0.1; vec[2][2]= -0.1; vec[2][1]= 0.1;
+ vec[3][0]= -0.1; vec[3][2]= -0.1; vec[3][1]= 0.1;
+ vec[4][0]= -0.1; vec[4][2]= 0.1; vec[4][1]= 0.1;
+
+
+ glBegin(GL_TRIANGLES);
+ /* bottom */
+ CalcNormFloat(vec[2], vec[1], vec[0], nor);
+ glNormal3fv(nor);
+ glVertex3fv(vec[2]);glVertex3fv(vec[1]);glVertex3fv(vec[0]);
+
+ CalcNormFloat(vec[3], vec[2], vec[0], nor);
+ glNormal3fv(nor);
+ glVertex3fv(vec[3]);glVertex3fv(vec[2]);glVertex3fv(vec[0]);
+
+ CalcNormFloat(vec[4], vec[3], vec[0], nor);
+ glNormal3fv(nor);
+ glVertex3fv(vec[4]);glVertex3fv(vec[3]);glVertex3fv(vec[0]);
+
+ CalcNormFloat(vec[1], vec[4], vec[0], nor);
+ glNormal3fv(nor);
+ glVertex3fv(vec[1]);glVertex3fv(vec[4]);glVertex3fv(vec[0]);
+
+ /* top */
+ CalcNormFloat(vec[5], vec[1], vec[2], nor);
+ glNormal3fv(nor);
+ glVertex3fv(vec[5]);glVertex3fv(vec[1]);glVertex3fv(vec[2]);
+
+ CalcNormFloat(vec[5], vec[2], vec[3], nor);
+ glNormal3fv(nor);
+ glVertex3fv(vec[5]);glVertex3fv(vec[2]);glVertex3fv(vec[3]);
+
+ CalcNormFloat(vec[5], vec[3], vec[4], nor);
+ glNormal3fv(nor);
+ glVertex3fv(vec[5]);glVertex3fv(vec[3]);glVertex3fv(vec[4]);
+
+ CalcNormFloat(vec[5], vec[4], vec[1], nor);
+ glNormal3fv(nor);
+ glVertex3fv(vec[5]);glVertex3fv(vec[4]);glVertex3fv(vec[1]);
+
+ glEnd();
+
+ glEndList();
+ }
+ else glCallList(displist);
+}
+
+/* *************** Armature drawing, bones ******************* */
+
+
+static void draw_bone_points(int dt, int armflag, unsigned int boneflag, int id)
+{
+ /* Draw root point if we are not connected */
+ if (!(boneflag & BONE_CONNECTED)){
+ if (id != -1)
+ glLoadName (id | BONESEL_ROOT);
+
+ if(dt<=OB_WIRE) {
+ if(armflag & ARM_EDITMODE) {
+ if (boneflag & BONE_ROOTSEL) BIF_ThemeColor(TH_VERTEX_SELECT);
+ else BIF_ThemeColor(TH_VERTEX);
+ }
+ }
+ else
+ BIF_ThemeColor(TH_BONE_SOLID);
+
+ if(dt>OB_WIRE) draw_bonevert_solid();
+ else draw_bonevert();
+ }
+
+ /* Draw tip point */
+ if (id != -1)
+ glLoadName (id | BONESEL_TIP);
+
+ if(dt<=OB_WIRE) {
+ if(armflag & ARM_EDITMODE) {
+ if (boneflag & BONE_TIPSEL) BIF_ThemeColor(TH_VERTEX_SELECT);
+ else BIF_ThemeColor(TH_VERTEX);
+ }
+ }
+ else {
+ BIF_ThemeColor(TH_BONE_SOLID);
+ }
+
+ glTranslatef(0.0, 1.0, 0.0);
+ if(dt>OB_WIRE) draw_bonevert_solid();
+ else draw_bonevert();
+ glTranslatef(0.0, -1.0, 0.0);
+
+}
+
+/* 16 values of sin function (still same result!) */
+static float si[16] = {
+ 0.00000000,
+ 0.20129852, 0.39435585,
+ 0.57126821, 0.72479278,
+ 0.84864425, 0.93775213,
+ 0.98846832, 0.99871650,
+ 0.96807711, 0.89780453,
+ 0.79077573, 0.65137248,
+ 0.48530196, 0.29936312,
+ 0.10116832
+};
+/* 16 values of cos function (still same result!) */
+static float co[16] ={
+ 1.00000000,
+ 0.97952994, 0.91895781,
+ 0.82076344, 0.68896691,
+ 0.52896401, 0.34730525,
+ 0.15142777, -0.05064916,
+ -0.25065253, -0.44039415,
+ -0.61210598, -0.75875812,
+ -0.87434661, -0.95413925,
+ -0.99486932
+};
+
+
+
+/* smat, imat = mat & imat to draw screenaligned */
+static void draw_sphere_bone_dist(float smat[][4], float imat[][4], int boneflag, bPoseChannel *pchan, EditBone *ebone)
+{
+ float head, tail, length, dist;
+ float *headvec, *tailvec, dirvec[3];
+
+ /* figure out the sizes of spheres */
+ if(ebone) {
+ /* this routine doesn't call set_matrix_editbone() that calculates it */
+ ebone->length = VecLenf(ebone->head, ebone->tail);
+
+ length= ebone->length;
+ tail= ebone->rad_tail;
+ dist= ebone->dist;
+ if (ebone->parent && (ebone->flag & BONE_CONNECTED))
+ head= ebone->parent->rad_tail;
+ else
+ head= ebone->rad_head;
+ headvec= ebone->head;
+ tailvec= ebone->tail;
+ }
+ else {
+ length= pchan->bone->length;
+ tail= pchan->bone->rad_tail;
+ dist= pchan->bone->dist;
+ if (pchan->parent && (pchan->bone->flag & BONE_CONNECTED))
+ head= pchan->parent->bone->rad_tail;
+ else
+ head= pchan->bone->rad_head;
+ headvec= pchan->pose_head;
+ tailvec= pchan->pose_tail;
+ }
+
+ /* ***** draw it ***** */
+
+ /* move vector to viewspace */
+ VecSubf(dirvec, tailvec, headvec);
+ Mat4Mul3Vecfl(smat, dirvec);
+ /* clear zcomp */
+ dirvec[2]= 0.0;
+ /* move vector back */
+ Mat4Mul3Vecfl(imat, dirvec);
+
+ if(0.0f != Normalize(dirvec)) {
+ float norvec[3], vec1[3], vec2[3], vec[3];
+ int a;
+
+ //VecMulf(dirvec, head);
+ Crossf(norvec, dirvec, imat[2]);
+
+ glBegin(GL_QUAD_STRIP);
+
+ for(a=0; a<16; a++) {
+ vec[0]= - *(si+a) * dirvec[0] + *(co+a) * norvec[0];
+ vec[1]= - *(si+a) * dirvec[1] + *(co+a) * norvec[1];
+ vec[2]= - *(si+a) * dirvec[2] + *(co+a) * norvec[2];
+
+ vec1[0]= headvec[0] + head*vec[0];
+ vec1[1]= headvec[1] + head*vec[1];
+ vec1[2]= headvec[2] + head*vec[2];
+ vec2[0]= headvec[0] + (head+dist)*vec[0];
+ vec2[1]= headvec[1] + (head+dist)*vec[1];
+ vec2[2]= headvec[2] + (head+dist)*vec[2];
+
+ glColor4ub(255, 255, 255, 50);
+ glVertex3fv(vec1);
+ //glColor4ub(255, 255, 255, 0);
+ glVertex3fv(vec2);
+ }
+
+ for(a=15; a>=0; a--) {
+ vec[0]= *(si+a) * dirvec[0] + *(co+a) * norvec[0];
+ vec[1]= *(si+a) * dirvec[1] + *(co+a) * norvec[1];
+ vec[2]= *(si+a) * dirvec[2] + *(co+a) * norvec[2];
+
+ vec1[0]= tailvec[0] + tail*vec[0];
+ vec1[1]= tailvec[1] + tail*vec[1];
+ vec1[2]= tailvec[2] + tail*vec[2];
+ vec2[0]= tailvec[0] + (tail+dist)*vec[0];
+ vec2[1]= tailvec[1] + (tail+dist)*vec[1];
+ vec2[2]= tailvec[2] + (tail+dist)*vec[2];
+
+ //glColor4ub(255, 255, 255, 50);
+ glVertex3fv(vec1);
+ //glColor4ub(255, 255, 255, 0);
+ glVertex3fv(vec2);
+ }
+ /* make it cyclic... */
+
+ vec[0]= - *(si) * dirvec[0] + *(co) * norvec[0];
+ vec[1]= - *(si) * dirvec[1] + *(co) * norvec[1];
+ vec[2]= - *(si) * dirvec[2] + *(co) * norvec[2];
+
+ vec1[0]= headvec[0] + head*vec[0];
+ vec1[1]= headvec[1] + head*vec[1];
+ vec1[2]= headvec[2] + head*vec[2];
+ vec2[0]= headvec[0] + (head+dist)*vec[0];
+ vec2[1]= headvec[1] + (head+dist)*vec[1];
+ vec2[2]= headvec[2] + (head+dist)*vec[2];
+
+ //glColor4ub(255, 255, 255, 50);
+ glVertex3fv(vec1);
+ //glColor4ub(255, 255, 255, 0);
+ glVertex3fv(vec2);
+
+ glEnd();
+ }
+}
+
+
+/* smat, imat = mat & imat to draw screenaligned */
+static void draw_sphere_bone_wire(float smat[][4], float imat[][4], int armflag, int boneflag, int constflag, unsigned int id, bPoseChannel *pchan, EditBone *ebone)
+{
+ float head, tail, length;
+ float *headvec, *tailvec, dirvec[3];
+
+ /* figure out the sizes of spheres */
+ if(ebone) {
+ /* this routine doesn't call set_matrix_editbone() that calculates it */
+ ebone->length = VecLenf(ebone->head, ebone->tail);
+
+ length= ebone->length;
+ tail= ebone->rad_tail;
+ if (ebone->parent && (boneflag & BONE_CONNECTED))
+ head= ebone->parent->rad_tail;
+ else
+ head= ebone->rad_head;
+ headvec= ebone->head;
+ tailvec= ebone->tail;
+ }
+ else {
+ length= pchan->bone->length;
+ tail= pchan->bone->rad_tail;
+ if (pchan->parent && (boneflag & BONE_CONNECTED))
+ head= pchan->parent->bone->rad_tail;
+ else
+ head= pchan->bone->rad_head;
+ headvec= pchan->pose_head;
+ tailvec= pchan->pose_tail;
+ }
+
+ /* sphere root color */
+ if(armflag & ARM_EDITMODE) {
+ if (boneflag & BONE_ROOTSEL) BIF_ThemeColor(TH_VERTEX_SELECT);
+ else BIF_ThemeColor(TH_VERTEX);
+ }
+ else if(armflag & ARM_POSEMODE) {
+ /* in black or selection color */
+ if (boneflag & BONE_ACTIVE) BIF_ThemeColorShade(TH_BONE_POSE, 40);
+ else if (boneflag & BONE_SELECTED) BIF_ThemeColor(TH_BONE_POSE);
+ else BIF_ThemeColor(TH_WIRE);
+ }
+
+ /* Draw root point if we are not connected */
+ if (!(boneflag & BONE_CONNECTED)){
+ if (id != -1)
+ glLoadName (id | BONESEL_ROOT);
+
+ drawcircball(GL_LINE_LOOP, headvec, head, imat);
+ }
+
+ /* Draw tip point */
+ if(armflag & ARM_EDITMODE) {
+ if (boneflag & BONE_TIPSEL) BIF_ThemeColor(TH_VERTEX_SELECT);
+ else BIF_ThemeColor(TH_VERTEX);
+ }
+
+ if (id != -1)
+ glLoadName (id | BONESEL_TIP);
+
+ drawcircball(GL_LINE_LOOP, tailvec, tail, imat);
+
+ /* base */
+ if(armflag & ARM_EDITMODE) {
+ if (boneflag & BONE_SELECTED) BIF_ThemeColor(TH_SELECT);
+ else BIF_ThemeColor(TH_WIRE);
+ }
+
+ VecSubf(dirvec, tailvec, headvec);
+
+ /* move vector to viewspace */
+ Mat4Mul3Vecfl(smat, dirvec);
+ /* clear zcomp */
+ dirvec[2]= 0.0;
+ /* move vector back */
+ Mat4Mul3Vecfl(imat, dirvec);
+
+ if(0.0f != Normalize(dirvec)) {
+ float norvech[3], norvect[3], vec[3];
+
+ VECCOPY(vec, dirvec);
+
+ VecMulf(dirvec, head);
+ Crossf(norvech, dirvec, imat[2]);
+
+ VecMulf(vec, tail);
+ Crossf(norvect, vec, imat[2]);
+
+ if (id != -1)
+ glLoadName (id | BONESEL_BONE);
+
+ glBegin(GL_LINES);
+ vec[0]= headvec[0] + norvech[0];
+ vec[1]= headvec[1] + norvech[1];
+ vec[2]= headvec[2] + norvech[2];
+ glVertex3fv(vec);
+ vec[0]= tailvec[0] + norvect[0];
+ vec[1]= tailvec[1] + norvect[1];
+ vec[2]= tailvec[2] + norvect[2];
+ glVertex3fv(vec);
+ vec[0]= headvec[0] - norvech[0];
+ vec[1]= headvec[1] - norvech[1];
+ vec[2]= headvec[2] - norvech[2];
+ glVertex3fv(vec);
+ vec[0]= tailvec[0] - norvect[0];
+ vec[1]= tailvec[1] - norvect[1];
+ vec[2]= tailvec[2] - norvect[2];
+ glVertex3fv(vec);
+
+ glEnd();
+ }
+}
+
+/* does wire only for outline selecting */
+static void draw_sphere_bone(int dt, int armflag, int boneflag, int constflag, unsigned int id, bPoseChannel *pchan, EditBone *ebone)
+{
+ GLUquadricObj *qobj;
+ float head, tail, length;
+ float fac1, fac2;
+
+ glPushMatrix();
+ qobj = gluNewQuadric();
+
+ /* figure out the sizes of spheres */
+ if(ebone) {
+ length= ebone->length;
+ tail= ebone->rad_tail;
+ if (ebone->parent && (boneflag & BONE_CONNECTED))
+ head= ebone->parent->rad_tail;
+ else
+ head= ebone->rad_head;
+ }
+ else {
+ length= pchan->bone->length;
+ tail= pchan->bone->rad_tail;
+ if (pchan->parent && (boneflag & BONE_CONNECTED))
+ head= pchan->parent->bone->rad_tail;
+ else
+ head= pchan->bone->rad_head;
+ }
+
+ /* move to z-axis space */
+ glRotatef (-90.0f, 1.0f, 0.0f, 0.0f);
+
+ if(dt==OB_SOLID) {
+ /* set up solid drawing */
+ glEnable(GL_COLOR_MATERIAL);
+ glEnable(GL_LIGHTING);
+
+ gluQuadricDrawStyle(qobj, GLU_FILL);
+ glShadeModel(GL_SMOOTH);
+ }
+ else {
+ gluQuadricDrawStyle(qobj, GLU_SILHOUETTE);
+ }
+
+ /* sphere root color */
+ if(armflag & ARM_EDITMODE) {
+ if (boneflag & BONE_ROOTSEL) BIF_ThemeColor(TH_VERTEX_SELECT);
+ else BIF_ThemeColorShade(TH_BONE_SOLID, -30);
+ }
+ else if(armflag & ARM_POSEMODE) {
+ if (boneflag & BONE_ACTIVE) BIF_ThemeColorShade(TH_BONE_POSE, 10);
+ else if (boneflag & BONE_SELECTED) BIF_ThemeColorShade(TH_BONE_POSE, -30);
+ else BIF_ThemeColorShade(TH_BONE_SOLID, -30);
+
+ }
+ else if(dt==OB_SOLID)
+ BIF_ThemeColorShade(TH_BONE_SOLID, -30);
+
+ /* Draw root point if we are not connected */
+ if (!(boneflag & BONE_CONNECTED)){
+ if (id != -1)
+ glLoadName (id | BONESEL_ROOT);
+ gluSphere( qobj, head, 16, 10);
+ }
+
+ /* Draw tip point */
+ if(armflag & ARM_EDITMODE) {
+ if (boneflag & BONE_TIPSEL) BIF_ThemeColor(TH_VERTEX_SELECT);
+ else BIF_ThemeColorShade(TH_BONE_SOLID, -30);
+ }
+
+ if (id != -1)
+ glLoadName (id | BONESEL_TIP);
+
+ glTranslatef(0.0, 0.0, length);
+ gluSphere( qobj, tail, 16, 10);
+ glTranslatef(0.0, 0.0, -length);
+
+ /* base */
+ if(armflag & ARM_EDITMODE) {
+ if (boneflag & BONE_SELECTED) BIF_ThemeColor(TH_SELECT);
+ else BIF_ThemeColor(TH_BONE_SOLID);
+ }
+ else if(armflag & ARM_POSEMODE) {
+ if (boneflag & BONE_ACTIVE) BIF_ThemeColorShade(TH_BONE_POSE, 40);
+ else if (boneflag & BONE_SELECTED) BIF_ThemeColor(TH_BONE_POSE);
+ else BIF_ThemeColor(TH_BONE_SOLID);
+
+ }
+ else if(dt==OB_SOLID)
+ BIF_ThemeColor(TH_BONE_SOLID);
+
+ fac1= (length-head)/length;
+ fac2= (length-tail)/length;
+
+ if(length > head+tail) {
+ if (id != -1)
+ glLoadName (id | BONESEL_BONE);
+
+ glEnable(GL_POLYGON_OFFSET_FILL);
+ glPolygonOffset(-1.0, -1.0);
+
+ glTranslatef(0.0f, 0.0f, head);
+ gluCylinder(qobj, fac1*head + (1.0f-fac1)*tail, fac2*tail + (1.0f-fac2)*head, length-head-tail, 16, 1);
+ glTranslatef(0.0f, 0.0f, -head);
+
+ glDisable(GL_POLYGON_OFFSET_FILL);
+
+ /* draw sphere on extrema */
+ glTranslatef(0.0f, 0.0f, length-tail);
+ gluSphere( qobj, fac2*tail + (1.0f-fac2)*head, 16, 10);
+ glTranslatef(0.0f, 0.0f, -length+tail);
+
+ glTranslatef(0.0f, 0.0f, head);
+ gluSphere( qobj, fac1*head + (1.0f-fac1)*tail, 16, 10);
+ }
+ else {
+ /* 1 sphere in center */
+ glTranslatef(0.0f, 0.0f, (head + length-tail)/2.0);
+ gluSphere( qobj, fac1*head + (1.0f-fac1)*tail, 16, 10);
+ }
+
+ /* restore */
+ if(dt==OB_SOLID) {
+ glShadeModel(GL_FLAT);
+ glDisable(GL_LIGHTING);
+ glDisable(GL_COLOR_MATERIAL);
+ }
+
+ glPopMatrix();
+ gluDeleteQuadric(qobj);
+}
+
+static GLubyte bm_dot6[]= {0x0, 0x18, 0x3C, 0x7E, 0x7E, 0x3C, 0x18, 0x0};
+static GLubyte bm_dot8[]= {0x3C, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x3C};
+
+static GLubyte bm_dot5[]= {0x0, 0x0, 0x10, 0x38, 0x7c, 0x38, 0x10, 0x0};
+static GLubyte bm_dot7[]= {0x0, 0x38, 0x7C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38};
+
+
+static void draw_line_bone(int armflag, int boneflag, int constflag, unsigned int id, bPoseChannel *pchan, EditBone *ebone)
+{
+ float length;
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+ if(pchan)
+ length= pchan->bone->length;
+ else
+ length= ebone->length;
+
+ glPushMatrix();
+ glScalef(length, length, length);
+
+ /* this chunk not in object mode */
+ if(armflag & (ARM_EDITMODE|ARM_POSEMODE)) {
+ glLineWidth(4.0);
+ if(armflag & ARM_POSEMODE) {
+ /* outline in black or selection color */
+ if (boneflag & BONE_ACTIVE) BIF_ThemeColorShade(TH_BONE_POSE, 40);
+ else if (boneflag & BONE_SELECTED) BIF_ThemeColor(TH_BONE_POSE);
+ else BIF_ThemeColor(TH_WIRE);
+ }
+ else if (armflag & ARM_EDITMODE) {
+ BIF_ThemeColor(TH_WIRE);
+ }
+
+ /* Draw root point if we are not connected */
+ if (!(boneflag & BONE_CONNECTED)){
+ if (G.f & G_PICKSEL) { // no bitmap in selection mode, crashes 3d cards...
+ glLoadName (id | BONESEL_ROOT);
+ glBegin(GL_POINTS);
+ glVertex3f(0.0f, 0.0f, 0.0f);
+ glEnd();
+ }
+ else {
+ glRasterPos3f(0.0f, 0.0f, 0.0f);
+ glBitmap(8, 8, 4, 4, 0, 0, bm_dot8);
+ }
+ }
+
+ if (id != -1)
+ glLoadName ((GLuint) id|BONESEL_BONE);
+
+ glBegin(GL_LINES);
+ glVertex3f(0.0f, 0.0f, 0.0f);
+ glVertex3f(0.0f, 1.0f, 0.0f);
+ glEnd();
+
+ /* tip */
+ if (G.f & G_PICKSEL) { // no bitmap in selection mode, crashes 3d cards...
+ glLoadName (id | BONESEL_TIP);
+ glBegin(GL_POINTS);
+ glVertex3f(0.0f, 1.0f, 0.0f);
+ glEnd();
+ }
+ else {
+ glRasterPos3f(0.0f, 1.0f, 0.0f);
+ glBitmap(8, 8, 4, 4, 0, 0, bm_dot7);
+ }
+
+ /* further we send no names */
+ if (id != -1)
+ glLoadName (id & 0xFFFF); // object tag, for bordersel optim
+
+ if(armflag & ARM_POSEMODE) {
+ /* inner part in background color or constraint */
+ if(constflag) {
+ if(constflag & PCHAN_HAS_STRIDE) glColor3ub(0, 0, 200);
+ else if(constflag & PCHAN_HAS_TARGET) glColor3ub(255, 150, 0);
+ else if(constflag & PCHAN_HAS_IK) glColor3ub(255, 255, 0);
+ else if(constflag & PCHAN_HAS_CONST) glColor3ub(0, 255, 120);
+ else BIF_ThemeColor(TH_BONE_POSE); // PCHAN_HAS_ACTION
+ }
+ else BIF_ThemeColorShade(TH_BACK, -30);
+ }
+ }
+
+ glLineWidth(2.0);
+
+ /* Draw root point if we are not connected */
+ if (!(boneflag & BONE_CONNECTED)){
+ if ((G.f & G_PICKSEL)==0) { // no bitmap in selection mode, crashes 3d cards...
+ if(armflag & ARM_EDITMODE) {
+ if (boneflag & BONE_ROOTSEL) BIF_ThemeColor(TH_VERTEX_SELECT);
+ else BIF_ThemeColor(TH_VERTEX);
+ }
+ glRasterPos3f(0.0f, 0.0f, 0.0f);
+ glBitmap(8, 8, 4, 4, 0, 0, bm_dot6);
+ }
+ }
+
+ if(armflag & ARM_EDITMODE) {
+ if (boneflag & BONE_SELECTED) BIF_ThemeColor(TH_EDGE_SELECT);
+ else BIF_ThemeColorShade(TH_BACK, -30);
+ }
+ glBegin(GL_LINES);
+ glVertex3f(0.0f, 0.0f, 0.0f);
+ glVertex3f(0.0f, 1.0f, 0.0f);
+ glEnd();
+
+ /* tip */
+ if ((G.f & G_PICKSEL)==0) { // no bitmap in selection mode, crashes 3d cards...
+ if(armflag & ARM_EDITMODE) {
+ if (boneflag & BONE_TIPSEL) BIF_ThemeColor(TH_VERTEX_SELECT);
+ else BIF_ThemeColor(TH_VERTEX);
+ }
+ glRasterPos3f(0.0f, 1.0f, 0.0f);
+ glBitmap(8, 8, 4, 4, 0, 0, bm_dot5);
+ }
+
+ glLineWidth(1.0);
+
+ glPopMatrix();
+}
+
+static void draw_b_bone_boxes(int dt, bPoseChannel *pchan, float xwidth, float length, float zwidth)
+{
+ int segments= 0;
+
+ if(pchan) segments= pchan->bone->segments;
+
+ if(segments>1 && pchan) {
+ float dlen= length/(float)segments;
+ Mat4 *bbone= b_bone_spline_setup(pchan, 0);
+ int a;
+
+ for(a=0; a<segments; a++, bbone++) {
+ glPushMatrix();
+ glMultMatrixf(bbone->mat);
+ if(dt==OB_SOLID) drawsolidcube_size(xwidth, dlen, zwidth);
+ else drawcube_size(xwidth, dlen, zwidth);
+ glPopMatrix();
+ }
+ }
+ else {
+ glPushMatrix();
+ if(dt==OB_SOLID) drawsolidcube_size(xwidth, length, zwidth);
+ else drawcube_size(xwidth, length, zwidth);
+ glPopMatrix();
+ }
+}
+
+static void draw_b_bone(int dt, int armflag, int boneflag, int constflag, unsigned int id, bPoseChannel *pchan, EditBone *ebone)
+{
+ float xwidth, length, zwidth;
+
+ if(pchan) {
+ xwidth= pchan->bone->xwidth;
+ length= pchan->bone->length;
+ zwidth= pchan->bone->zwidth;
+ }
+ else {
+ xwidth= ebone->xwidth;
+ length= ebone->length;
+ zwidth= ebone->zwidth;
+ }
+
+ /* draw points only if... */
+ if(armflag & ARM_EDITMODE) {
+ /* move to unitspace */
+ glPushMatrix();
+ glScalef(length, length, length);
+ draw_bone_points(dt, armflag, boneflag, id);
+ glPopMatrix();
+ length*= 0.95f; // make vertices visible
+ }
+
+ /* colors for modes */
+ if (armflag & ARM_POSEMODE) {
+ if(dt==OB_WIRE) {
+ if (boneflag & BONE_ACTIVE) BIF_ThemeColorShade(TH_BONE_POSE, 40);
+ else if (boneflag & BONE_SELECTED) BIF_ThemeColor(TH_BONE_POSE);
+ else BIF_ThemeColor(TH_WIRE);
+ }
+ else
+ BIF_ThemeColor(TH_BONE_SOLID);
+ }
+ else if (armflag & ARM_EDITMODE) {
+ if(dt==OB_WIRE) {
+ if (boneflag & BONE_ACTIVE) BIF_ThemeColor(TH_EDGE_SELECT);
+ else if (boneflag & BONE_SELECTED) BIF_ThemeColorShade(TH_EDGE_SELECT, -20);
+ else BIF_ThemeColor(TH_WIRE);
+ }
+ else
+ BIF_ThemeColor(TH_BONE_SOLID);
+ }
+
+ if (id != -1) {
+ glLoadName ((GLuint) id|BONESEL_BONE);
+ }
+
+ /* set up solid drawing */
+ if(dt > OB_WIRE) {
+ glEnable(GL_COLOR_MATERIAL);
+ glEnable(GL_LIGHTING);
+ BIF_ThemeColor(TH_BONE_SOLID);
+
+ draw_b_bone_boxes(OB_SOLID, pchan, xwidth, length, zwidth);
+
+ /* disable solid drawing */
+ glDisable(GL_COLOR_MATERIAL);
+ glDisable(GL_LIGHTING);
+ }
+ else { // wire
+ if (armflag & ARM_POSEMODE){
+ if(constflag) {
+ glEnable(GL_BLEND);
+
+ if(constflag & PCHAN_HAS_STRIDE) glColor4ub(0, 0, 200, 80);
+ else if(constflag & PCHAN_HAS_TARGET) glColor4ub(255, 150, 0, 80);
+ else if(constflag & PCHAN_HAS_IK) glColor4ub(255, 255, 0, 80);
+ else if(constflag & PCHAN_HAS_CONST) glColor4ub(0, 255, 120, 80);
+ else BIF_ThemeColor4(TH_BONE_POSE); // PCHAN_HAS_ACTION
+
+ draw_b_bone_boxes(OB_SOLID, pchan, xwidth, length, zwidth);
+
+ glDisable(GL_BLEND);
+
+ /* restore colors */
+ if (boneflag & BONE_ACTIVE) BIF_ThemeColorShade(TH_BONE_POSE, 40);
+ else if (boneflag & BONE_SELECTED) BIF_ThemeColor(TH_BONE_POSE);
+ else BIF_ThemeColor(TH_WIRE);
+ }
+ }
+
+ draw_b_bone_boxes(OB_WIRE, pchan, xwidth, length, zwidth);
+ }
+}
+
+static void draw_bone(int dt, int armflag, int boneflag, int constflag, unsigned int id, float length)
+{
+
+ /* Draw a 3d octahedral bone, we use normalized space based on length,
+ for glDisplayLists */
+
+ glScalef(length, length, length);
+
+ /* set up solid drawing */
+ if(dt > OB_WIRE) {
+ glEnable(GL_COLOR_MATERIAL);
+ glEnable(GL_LIGHTING);
+ BIF_ThemeColor(TH_BONE_SOLID);
+ }
+
+ /* colors for posemode */
+ if (armflag & ARM_POSEMODE) {
+ if(dt==OB_WIRE) {
+ if (boneflag & BONE_ACTIVE) BIF_ThemeColorShade(TH_BONE_POSE, 40);
+ else if (boneflag & BONE_SELECTED) BIF_ThemeColor(TH_BONE_POSE);
+ else BIF_ThemeColor(TH_WIRE);
+ }
+ else
+ BIF_ThemeColor(TH_BONE_SOLID);
+ }
+
+
+ draw_bone_points(dt, armflag, boneflag, id);
+
+ /* now draw the bone itself */
+
+ if (id != -1) {
+ glLoadName ((GLuint) id|BONESEL_BONE);
+ }
+
+ /* wire? */
+ if(dt <= OB_WIRE) {
+ /* colors */
+ if (armflag & ARM_EDITMODE) {
+ if (boneflag & BONE_ACTIVE) BIF_ThemeColor(TH_EDGE_SELECT);
+ else if (boneflag & BONE_SELECTED) BIF_ThemeColorShade(TH_EDGE_SELECT, -20);
+ else BIF_ThemeColor(TH_WIRE);
+ }
+ else if (armflag & ARM_POSEMODE){
+ if(constflag) {
+ glEnable(GL_BLEND);
+
+ if(constflag & PCHAN_HAS_STRIDE) glColor4ub(0, 0, 200, 80);
+ else if(constflag & PCHAN_HAS_TARGET) glColor4ub(255, 150, 0, 80);
+ else if(constflag & PCHAN_HAS_IK) glColor4ub(255, 255, 0, 80);
+ else if(constflag & PCHAN_HAS_CONST) glColor4ub(0, 255, 120, 80);
+ else BIF_ThemeColor4(TH_BONE_POSE); // PCHAN_HAS_ACTION
+
+ draw_bone_solid_octahedral();
+ glDisable(GL_BLEND);
+
+ /* restore colors */
+ if (boneflag & BONE_ACTIVE) BIF_ThemeColorShade(TH_BONE_POSE, 40);
+ else if (boneflag & BONE_SELECTED) BIF_ThemeColor(TH_BONE_POSE);
+ else BIF_ThemeColor(TH_WIRE);
+ }
+ }
+ draw_bone_octahedral();
+ }
+ else { /* solid */
+
+ BIF_ThemeColor(TH_BONE_SOLID);
+ draw_bone_solid_octahedral();
+ }
+
+ /* disable solid drawing */
+ if(dt>OB_WIRE) {
+ glDisable(GL_COLOR_MATERIAL);
+ glDisable(GL_LIGHTING);
+ }
+}
+
+static void draw_custom_bone(Object *ob, int dt, int armflag, int boneflag, unsigned int id, float length)
+{
+
+ if(ob==NULL) return;
+
+ glScalef(length, length, length);
+
+ /* colors for posemode */
+ if (armflag & ARM_POSEMODE) {
+ if (boneflag & BONE_ACTIVE) BIF_ThemeColorShade(TH_BONE_POSE, 40);
+ else if (boneflag & BONE_SELECTED) BIF_ThemeColor(TH_BONE_POSE);
+ else BIF_ThemeColor(TH_WIRE);
+ }
+
+ if (id != -1) {
+ glLoadName ((GLuint) id|BONESEL_BONE);
+ }
+
+ draw_object_instance(ob, dt, armflag & ARM_POSEMODE);
+}
+
+
+static void pchan_draw_IK_root_lines(bPoseChannel *pchan)
+{
+ bConstraint *con;
+ bPoseChannel *parchan;
+
+ for(con= pchan->constraints.first; con; con= con->next) {
+ if(con->type == CONSTRAINT_TYPE_KINEMATIC) {
+ bKinematicConstraint *data = (bKinematicConstraint*)con->data;
+ int segcount= 0;
+
+ setlinestyle(3);
+ glBegin(GL_LINES);
+
+ /* exclude tip from chain? */
+ if(!(data->flag & CONSTRAINT_IK_TIP))
+ parchan= pchan->parent;
+ else
+ parchan= pchan;
+
+ glVertex3fv(parchan->pose_tail);
+
+ /* Find the chain's root */
+ while (parchan->parent){
+ segcount++;
+ if(segcount==data->rootbone || segcount>255) break; // 255 is weak
+ parchan= parchan->parent;
+ }
+ if(parchan)
+ glVertex3fv(parchan->pose_head);
+
+ glEnd();
+ setlinestyle(0);
+ }
+ }
+}
+
+static void bgl_sphere_project(float ax, float az)
+{
+ float dir[3], sine, q3;
+
+ sine= 1.0f-ax*ax-az*az;
+ q3= (sine < 0.0f)? 0.0f: 2.0f*sqrt(sine);
+
+ dir[0]= -az*q3;
+ dir[1]= 1.0f-2.0f*sine;
+ dir[2]= ax*q3;
+
+ glVertex3fv(dir);
+}
+
+static void draw_dof_ellipse(float ax, float az)
+{
+ static float staticSine[16] = {
+ 0.0, 0.104528463268, 0.207911690818, 0.309016994375,
+ 0.406736643076, 0.5, 0.587785252292, 0.669130606359,
+ 0.743144825477, 0.809016994375, 0.866025403784,
+ 0.913545457643, 0.951056516295, 0.978147600734,
+ 0.994521895368, 1.0
+ };
+
+ int i, j, n=16;
+ float x, z, px, pz;
+
+ glEnable(GL_BLEND);
+ glDepthMask(0);
+
+ glColor4ub(70, 70, 70, 50);
+
+ glBegin(GL_QUADS);
+ pz= 0.0f;
+ for(i=1; i<n; i++) {
+ z= staticSine[i];
+
+ px= 0.0f;
+ for(j=1; j<n-i+1; j++) {
+ x = staticSine[j];
+
+ if(j == n-i) {
+ glEnd();
+ glBegin(GL_TRIANGLES);
+ bgl_sphere_project(ax*px, az*z);
+ bgl_sphere_project(ax*px, az*pz);
+ bgl_sphere_project(ax*x, az*pz);
+ glEnd();
+ glBegin(GL_QUADS);
+ }
+ else {
+ bgl_sphere_project(ax*x, az*z);
+ bgl_sphere_project(ax*x, az*pz);
+ bgl_sphere_project(ax*px, az*pz);
+ bgl_sphere_project(ax*px, az*z);
+ }
+
+ px= x;
+ }
+ pz= z;
+ }
+ glEnd();
+
+ glDisable(GL_BLEND);
+ glDepthMask(1);
+
+ glColor3ub(0, 0, 0);
+
+ glBegin(GL_LINE_STRIP);
+ for(i=0; i<n; i++)
+ bgl_sphere_project(staticSine[n-i-1]*ax, staticSine[i]*az);
+ glEnd();
+}
+
+static void draw_pose_dofs(Object *ob)
+{
+ bArmature *arm= ob->data;
+ bPoseChannel *pchan;
+ Bone *bone;
+
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ bone= pchan->bone;
+ if(bone && !(bone->flag & BONE_HIDDEN_P)) {
+ if(bone->flag & BONE_SELECTED) {
+ if(bone->layer & arm->layer) {
+ if(pchan->ikflag & (BONE_IK_XLIMIT|BONE_IK_ZLIMIT)) {
+ if(pose_channel_in_IK_chain(ob, pchan)) {
+ float corner[4][3], posetrans[3], mat[4][4];
+ float phi=0.0f, theta=0.0f, scale;
+ int a, i;
+
+ /* in parent-bone pose, but own restspace */
+ glPushMatrix();
+
+ VECCOPY(posetrans, pchan->pose_mat[3]);
+ glTranslatef(posetrans[0], posetrans[1], posetrans[2]);
+
+ if(pchan->parent) {
+ Mat4CpyMat4(mat, pchan->parent->pose_mat);
+ mat[3][0]= mat[3][1]= mat[3][2]= 0.0f;
+ glMultMatrixf(mat);
+ }
+
+ Mat4CpyMat3(mat, pchan->bone->bone_mat);
+ glMultMatrixf(mat);
+
+ scale= bone->length*pchan->size[1];
+ glScalef(scale, scale, scale);
+
+ if(pchan->ikflag & BONE_IK_XLIMIT) {
+ if(pchan->ikflag & BONE_IK_ZLIMIT) {
+ float amin[3], amax[3];
+
+ for(i=0; i<3; i++) {
+ amin[i]= sin(pchan->limitmin[i]*M_PI/360.0);
+ amax[i]= sin(pchan->limitmax[i]*M_PI/360.0);
+ }
+
+ glScalef(1.0, -1.0, 1.0);
+ if (amin[0] != 0.0 && amin[2] != 0.0)
+ draw_dof_ellipse(amin[0], amin[2]);
+ if (amin[0] != 0.0 && amax[2] != 0.0)
+ draw_dof_ellipse(amin[0], amax[2]);
+ if (amax[0] != 0.0 && amin[2] != 0.0)
+ draw_dof_ellipse(amax[0], amin[2]);
+ if (amax[0] != 0.0 && amax[2] != 0.0)
+ draw_dof_ellipse(amax[0], amax[2]);
+ glScalef(1.0, -1.0, 1.0);
+ }
+ }
+
+ /* arcs */
+ if(pchan->ikflag & BONE_IK_ZLIMIT) {
+ theta= 0.5*(pchan->limitmin[2]+pchan->limitmax[2]);
+ glRotatef(theta, 0.0f, 0.0f, 1.0f);
+
+ glColor3ub(50, 50, 255); // blue, Z axis limit
+ glBegin(GL_LINE_STRIP);
+ for(a=-16; a<=16; a++) {
+ float fac= ((float)a)/16.0f;
+ phi= fac*(M_PI/360.0f)*(pchan->limitmax[2]-pchan->limitmin[2]);
+
+ if(a==-16) i= 0; else i= 1;
+ corner[i][0]= sin(phi);
+ corner[i][1]= cos(phi);
+ corner[i][2]= 0.0f;
+ glVertex3fv(corner[i]);
+ }
+ glEnd();
+
+ glRotatef(-theta, 0.0f, 0.0f, 1.0f);
+ }
+
+ if(pchan->ikflag & BONE_IK_XLIMIT) {
+ theta= 0.5*( pchan->limitmin[0]+pchan->limitmax[0]);
+ glRotatef(theta, 1.0f, 0.0f, 0.0f);
+
+ glColor3ub(255, 50, 50); // Red, X axis limit
+ glBegin(GL_LINE_STRIP);
+ for(a=-16; a<=16; a++) {
+ float fac= ((float)a)/16.0f;
+ phi= 0.5f*M_PI + fac*(M_PI/360.0f)*(pchan->limitmax[0]-pchan->limitmin[0]);
+
+ if(a==-16) i= 2; else i= 3;
+ corner[i][0]= 0.0f;
+ corner[i][1]= sin(phi);
+ corner[i][2]= cos(phi);
+ glVertex3fv(corner[i]);
+ }
+ glEnd();
+
+ glRotatef(-theta, 1.0f, 0.0f, 0.0f);
+ }
+
+ glPopMatrix(); // out of cone, out of bone
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+/* assumes object is Armature with pose */
+static void draw_pose_channels(Base *base, int dt)
+{
+ Object *ob= base->object;
+ bArmature *arm= ob->data;
+ bPoseChannel *pchan;
+ Bone *bone;
+ GLfloat tmp;
+ float smat[4][4], imat[4][4];
+ int index= -1;
+ int do_dashed= 1;
+ short flag, constflag;
+
+ /* hacky... prevent outline select from drawing dashed helplines */
+ glGetFloatv(GL_LINE_WIDTH, &tmp);
+ if(tmp > 1.1) do_dashed= 0;
+ if (G.vd->flag & V3D_HIDE_HELPLINES) do_dashed= 0;
+
+ /* precalc inverse matrix for drawing screen aligned */
+ if(arm->drawtype==ARM_ENVELOPE) {
+ /* precalc inverse matrix for drawing screen aligned */
+ mygetmatrix(smat);
+ Mat4MulFloat3(smat[0], 1.0f/VecLength(ob->obmat[0]));
+ Mat4Invert(imat, smat);
+
+ /* and draw blended distances */
+ if(arm->flag & ARM_POSEMODE) {
+ glEnable(GL_BLEND);
+ //glShadeModel(GL_SMOOTH);
+
+ if(G.vd->zbuf) glDisable(GL_DEPTH_TEST);
+
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ bone= pchan->bone;
+ if(bone && !(bone->flag & (BONE_HIDDEN_P|BONE_NO_DEFORM))) {
+ if(bone->flag & (BONE_SELECTED))
+ if(bone->layer & arm->layer)
+ draw_sphere_bone_dist(smat, imat, bone->flag, pchan, NULL);
+ }
+ }
+
+ if(G.vd->zbuf) glEnable(GL_DEPTH_TEST);
+ glDisable(GL_BLEND);
+ //glShadeModel(GL_FLAT);
+ }
+ }
+
+ /* little speedup, also make sure transparent only draws once */
+ glCullFace(GL_BACK);
+ glEnable(GL_CULL_FACE);
+
+ /* if solid we draw that first, with selection codes, but without names, axes etc */
+ if(dt>OB_WIRE) {
+ if(arm->flag & ARM_POSEMODE) index= base->selcol;
+
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ bone= pchan->bone;
+ if(bone && !(bone->flag & BONE_HIDDEN_P)) {
+ if(bone->layer & arm->layer) {
+ glPushMatrix();
+ glMultMatrixf(pchan->pose_mat);
+
+ /* catch exception for bone with hidden parent */
+ flag= bone->flag;
+ if(bone->parent && (bone->parent->flag & BONE_HIDDEN_P))
+ flag &= ~BONE_CONNECTED;
+
+ if(pchan->custom && !(arm->flag & ARM_NO_CUSTOM))
+ draw_custom_bone(pchan->custom, OB_SOLID, arm->flag, flag, index, bone->length);
+ else if(arm->drawtype==ARM_LINE)
+ ; /* nothing in solid */
+ else if(arm->drawtype==ARM_ENVELOPE)
+ draw_sphere_bone(OB_SOLID, arm->flag, flag, 0, index, pchan, NULL);
+ else if(arm->drawtype==ARM_B_BONE)
+ draw_b_bone(OB_SOLID, arm->flag, flag, 0, index, pchan, NULL);
+ else {
+ draw_bone(OB_SOLID, arm->flag, flag, 0, index, bone->length);
+ }
+ glPopMatrix();
+ }
+ }
+ if (index!= -1) index+= 0x10000; // pose bones count in higher 2 bytes only
+ }
+ /* very very confusing... but in object mode, solid draw, we cannot do glLoadName yet, stick bones are dawn in next loop */
+ if(arm->drawtype!=ARM_LINE) {
+ glLoadName (index & 0xFFFF); // object tag, for bordersel optim
+ index= -1;
+ }
+ }
+
+ /* wire draw over solid only in posemode */
+ if( dt<=OB_WIRE || (arm->flag & ARM_POSEMODE) || arm->drawtype==ARM_LINE) {
+
+ /* draw line check first. we do selection indices */
+ if (arm->drawtype==ARM_LINE) {
+ if (arm->flag & ARM_POSEMODE) index= base->selcol;
+ }
+ /* if solid && posemode, we draw again with polygonoffset */
+ else if (dt>OB_WIRE && (arm->flag & ARM_POSEMODE))
+ bglPolygonOffset(1.0);
+ else
+ /* and we use selection indices if not done yet */
+ if (arm->flag & ARM_POSEMODE) index= base->selcol;
+
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ bone= pchan->bone;
+ if(bone && !(bone->flag & BONE_HIDDEN_P)) {
+ if(bone->layer & arm->layer) {
+ if (do_dashed && bone->parent) {
+ /* Draw a line from our root to the parent's tip */
+ if(!(bone->flag & BONE_CONNECTED) ){
+ if (arm->flag & ARM_POSEMODE) {
+ glLoadName (index & 0xFFFF); // object tag, for bordersel optim
+ BIF_ThemeColor(TH_WIRE);
+ }
+ setlinestyle(3);
+ glBegin(GL_LINES);
+ glVertex3fv(pchan->pose_head);
+ glVertex3fv(pchan->parent->pose_tail);
+ glEnd();
+ setlinestyle(0);
+ }
+ // Draw a line to IK root bone
+ if(arm->flag & ARM_POSEMODE) {
+ if(pchan->constflag & PCHAN_HAS_IK) {
+ if(bone->flag & BONE_SELECTED) {
+
+ if(pchan->constflag & PCHAN_HAS_TARGET) glColor3ub(200, 120, 0);
+ else glColor3ub(200, 200, 50); // add theme!
+
+ glLoadName (index & 0xFFFF);
+ pchan_draw_IK_root_lines(pchan);
+ }
+ }
+ }
+ }
+
+ if(arm->drawtype!=ARM_ENVELOPE) {
+ glPushMatrix();
+ glMultMatrixf(pchan->pose_mat);
+ }
+
+ /* catch exception for bone with hidden parent */
+ flag= bone->flag;
+ if(bone->parent && (bone->parent->flag & BONE_HIDDEN_P))
+ flag &= ~BONE_CONNECTED;
+
+ /* extra draw service for pose mode */
+ constflag= pchan->constflag;
+ if(pchan->flag & (POSE_ROT|POSE_LOC|POSE_SIZE))
+ constflag |= PCHAN_HAS_ACTION;
+ if(pchan->flag & POSE_STRIDE)
+ constflag |= PCHAN_HAS_STRIDE;
+
+ if(pchan->custom && !(arm->flag & ARM_NO_CUSTOM)) {
+ if(dt<OB_SOLID)
+ draw_custom_bone(pchan->custom, OB_WIRE, arm->flag, flag, index, bone->length);
+ }
+ else if(arm->drawtype==ARM_ENVELOPE) {
+ if(dt<OB_SOLID)
+ draw_sphere_bone_wire(smat, imat, arm->flag, flag, constflag, index, pchan, NULL);
+ }
+ else if(arm->drawtype==ARM_LINE)
+ draw_line_bone(arm->flag, flag, constflag, index, pchan, NULL);
+ else if(arm->drawtype==ARM_B_BONE)
+ draw_b_bone(OB_WIRE, arm->flag, flag, constflag, index, pchan, NULL);
+ else {
+ draw_bone(OB_WIRE, arm->flag, flag, constflag, index, bone->length);
+ }
+
+ if(arm->drawtype!=ARM_ENVELOPE)
+ glPopMatrix();
+ }
+ }
+ if (index!= -1) index+= 0x10000; // pose bones count in higher 2 bytes only
+ }
+ /* restore things */
+ if (arm->drawtype!=ARM_LINE && dt>OB_WIRE && (arm->flag & ARM_POSEMODE))
+ bglPolygonOffset(0.0);
+
+ }
+
+ /* restore */
+ glDisable(GL_CULL_FACE);
+
+ /* draw DoFs */
+ if (arm->flag & ARM_POSEMODE)
+ draw_pose_dofs(ob);
+
+ /* finally names and axes */
+ if(arm->flag & (ARM_DRAWNAMES|ARM_DRAWAXES)) {
+ // patch for several 3d cards (IBM mostly) that crash on glSelect with text drawing
+ if((G.f & G_PICKSEL) == 0) {
+ float vec[3];
+
+ if(G.vd->zbuf) glDisable(GL_DEPTH_TEST);
+
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ if((pchan->bone->flag & BONE_HIDDEN_P)==0) {
+ if(pchan->bone->layer & arm->layer) {
+ if (arm->flag & (ARM_EDITMODE|ARM_POSEMODE)) {
+ bone= pchan->bone;
+ if(bone->flag & BONE_SELECTED) BIF_ThemeColor(TH_TEXT_HI);
+ else BIF_ThemeColor(TH_TEXT);
+ }
+ else if(dt > OB_WIRE) BIF_ThemeColor(TH_TEXT);
+
+ if (arm->flag & ARM_DRAWNAMES){
+ VecMidf(vec, pchan->pose_head, pchan->pose_tail);
+ glRasterPos3fv(vec);
+ BMF_DrawString(G.font, " ");
+ BMF_DrawString(G.font, pchan->name);
+ }
+ /* Draw additional axes */
+ if( (arm->flag & ARM_DRAWAXES) && (arm->flag & ARM_POSEMODE) ){
+ glPushMatrix();
+ glMultMatrixf(pchan->pose_mat);
+ glTranslatef(0.0f, pchan->bone->length, 0.0f);
+ drawaxes(0.25f*pchan->bone->length, 0, OB_ARROWS);
+ glPopMatrix();
+ }
+ }
+ }
+ }
+
+ if(G.vd->zbuf) glEnable(GL_DEPTH_TEST);
+ }
+ }
+
+}
+
+/* in editmode, we don't store the bone matrix... */
+static void set_matrix_editbone(EditBone *eBone)
+{
+ float delta[3],offset[3];
+ float mat[3][3], bmat[4][4];
+
+ /* Compose the parent transforms (i.e. their translations) */
+ VECCOPY (offset, eBone->head);
+
+ glTranslatef (offset[0],offset[1],offset[2]);
+
+ VecSubf(delta, eBone->tail, eBone->head);
+
+ eBone->length = sqrt (delta[0]*delta[0] + delta[1]*delta[1] +delta[2]*delta[2]);
+
+ vec_roll_to_mat3(delta, eBone->roll, mat);
+ Mat4CpyMat3(bmat, mat);
+
+ glMultMatrixf (bmat);
+
+}
+
+static void draw_ebones(Object *ob, int dt)
+{
+ EditBone *eBone;
+ bArmature *arm= ob->data;
+ float smat[4][4], imat[4][4];
+ unsigned int index;
+ int flag;
+
+ /* envelope (deform distance) */
+ if(arm->drawtype==ARM_ENVELOPE) {
+ /* precalc inverse matrix for drawing screen aligned */
+ mygetmatrix(smat);
+ Mat4MulFloat3(smat[0], 1.0f/VecLength(ob->obmat[0]));
+ Mat4Invert(imat, smat);
+
+ /* and draw blended distances */
+ glEnable(GL_BLEND);
+ //glShadeModel(GL_SMOOTH);
+
+ if(G.vd->zbuf) glDisable(GL_DEPTH_TEST);
+
+ for (eBone=G.edbo.first, index=0; eBone; eBone=eBone->next, index++){
+ if(eBone->layer & arm->layer)
+ if(!(eBone->flag & (BONE_HIDDEN_A|BONE_NO_DEFORM)))
+ if(eBone->flag & (BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL))
+ draw_sphere_bone_dist(smat, imat, eBone->flag, NULL, eBone);
+ }
+
+ if(G.vd->zbuf) glEnable(GL_DEPTH_TEST);
+ glDisable(GL_BLEND);
+ //glShadeModel(GL_FLAT);
+ }
+
+ /* if solid we draw it first */
+ if(dt>OB_WIRE && arm->drawtype!=ARM_LINE) {
+ index= 0;
+ for (eBone=G.edbo.first, index=0; eBone; eBone=eBone->next, index++){
+ if(eBone->layer & arm->layer) {
+ if(!(eBone->flag & BONE_HIDDEN_A)) {
+ glPushMatrix();
+ set_matrix_editbone(eBone);
+
+ /* catch exception for bone with hidden parent */
+ flag= eBone->flag;
+ if(eBone->parent && ((eBone->parent->flag & BONE_HIDDEN_A) || (eBone->parent->layer & arm->layer)==0) )
+ flag &= ~BONE_CONNECTED;
+
+ if(arm->drawtype==ARM_ENVELOPE)
+ draw_sphere_bone(OB_SOLID, arm->flag, flag, 0, index, NULL, eBone);
+ else if(arm->drawtype==ARM_B_BONE)
+ draw_b_bone(OB_SOLID, arm->flag, flag, 0, index, NULL, eBone);
+ else {
+ draw_bone(OB_SOLID, arm->flag, flag, 0, index, eBone->length);
+ }
+
+ glPopMatrix();
+ }
+ }
+ }
+ }
+
+ /* if wire over solid, set offset */
+ index= -1;
+ glLoadName(-1);
+ if(arm->drawtype==ARM_LINE) {
+ if(G.f & G_PICKSEL)
+ index= 0;
+ }
+ else if (dt>OB_WIRE)
+ bglPolygonOffset(1.0);
+ else if(arm->flag & ARM_EDITMODE)
+ index= 0; // do selection codes
+
+ for (eBone=G.edbo.first; eBone; eBone=eBone->next){
+ if(eBone->layer & arm->layer) {
+ if(!(eBone->flag & BONE_HIDDEN_A)) {
+
+ /* catch exception for bone with hidden parent */
+ flag= eBone->flag;
+ if(eBone->parent && ((eBone->parent->flag & BONE_HIDDEN_A) || (eBone->parent->layer & arm->layer)==0) )
+ flag &= ~BONE_CONNECTED;
+
+ if(arm->drawtype==ARM_ENVELOPE) {
+ if(dt<OB_SOLID)
+ draw_sphere_bone_wire(smat, imat, arm->flag, flag, 0, index, NULL, eBone);
+ }
+ else {
+ glPushMatrix();
+ set_matrix_editbone(eBone);
+
+ if(arm->drawtype==ARM_LINE)
+ draw_line_bone(arm->flag, flag, 0, index, NULL, eBone);
+ else if(arm->drawtype==ARM_B_BONE)
+ draw_b_bone(OB_WIRE, arm->flag, flag, 0, index, NULL, eBone);
+ else
+ draw_bone(OB_WIRE, arm->flag, flag, 0, index, eBone->length);
+
+ glPopMatrix();
+ }
+
+ /* offset to parent */
+ if (eBone->parent) {
+ BIF_ThemeColor(TH_WIRE);
+ glLoadName (-1); // -1 here is OK!
+ setlinestyle(3);
+
+ glBegin(GL_LINES);
+ glVertex3fv(eBone->parent->tail);
+ glVertex3fv(eBone->head);
+ glEnd();
+
+ setlinestyle(0);
+ }
+ }
+ }
+ if(index!=-1) index++;
+ }
+
+ /* restore */
+ if(arm->drawtype==ARM_LINE);
+ else if (dt>OB_WIRE) bglPolygonOffset(0.0);
+
+ /* finally names and axes */
+ if(arm->flag & (ARM_DRAWNAMES|ARM_DRAWAXES)) {
+ // patch for several 3d cards (IBM mostly) that crash on glSelect with text drawing
+ if((G.f & G_PICKSEL) == 0) {
+ float vec[3];
+
+ if(G.vd->zbuf) glDisable(GL_DEPTH_TEST);
+
+ for (eBone=G.edbo.first, index=0; eBone; eBone=eBone->next, index++){
+ if(eBone->layer & arm->layer) {
+ if(!(eBone->flag & BONE_HIDDEN_A)) {
+
+ if(eBone->flag & BONE_SELECTED) BIF_ThemeColor(TH_TEXT_HI);
+ else BIF_ThemeColor(TH_TEXT);
+
+ /* Draw name */
+ if(arm->flag & ARM_DRAWNAMES){
+ VecMidf(vec, eBone->head, eBone->tail);
+ glRasterPos3fv(vec);
+ BMF_DrawString(G.font, " ");
+ BMF_DrawString(G.font, eBone->name);
+ }
+ /* Draw additional axes */
+ if(arm->flag & ARM_DRAWAXES){
+ glPushMatrix();
+ set_matrix_editbone(eBone);
+ glTranslatef(0.0f, eBone->length, 0.0f);
+ drawaxes(eBone->length*0.25f, 0, OB_ARROWS);
+ glPopMatrix();
+ }
+
+ }
+ }
+ }
+
+ if(G.vd->zbuf) glEnable(GL_DEPTH_TEST);
+ }
+ }
+}
+
+/* in view space */
+static void draw_pose_paths(Object *ob)
+{
+ bArmature *arm= ob->data;
+ bPoseChannel *pchan;
+ bAction *act;
+ bActionChannel *achan;
+ CfraElem *ce;
+ ListBase ak;
+ float *fp;
+ int a;
+ int stepsize, sfra;
+
+ if(G.vd->zbuf) glDisable(GL_DEPTH_TEST);
+
+ glPushMatrix();
+ glLoadMatrixf(G.vd->viewmat);
+
+ /* version patch here - cannot access frame info from file reading */
+ if (arm->pathsize == 0) arm->pathsize= 1;
+ stepsize = arm->pathsize;
+
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ if(pchan->bone->layer & arm->layer) {
+ if(pchan->path) {
+ /* version patch here - cannot access frame info from file reading */
+ if ((pchan->pathsf == 0) || (pchan->pathef == 0)) {
+ pchan->pathsf= SFRA;
+ pchan->pathef= EFRA;
+ }
+ sfra= pchan->pathsf;
+
+ /* draw curve-line of path */
+ BIF_ThemeColorBlend(TH_WIRE, TH_BACK, 0.7);
+ glBegin(GL_LINE_STRIP);
+ for(a=0, fp= pchan->path; a<pchan->pathlen; a++, fp+=3)
+ glVertex3fv(fp);
+ glEnd();
+
+ glPointSize(1.0);
+
+ /* draw little black point at each frame
+ * NOTE: this is not really visible/noticable
+ */
+ glBegin(GL_POINTS);
+ for(a=0, fp= pchan->path; a<pchan->pathlen; a++, fp+=3)
+ glVertex3fv(fp);
+ glEnd();
+
+ /* Draw little white dots at each framestep value */
+ BIF_ThemeColor(TH_TEXT_HI);
+ glBegin(GL_POINTS);
+ for(a=0, fp= pchan->path; a<pchan->pathlen; a+=stepsize, fp+=(stepsize*3))
+ glVertex3fv(fp);
+ glEnd();
+
+ /* Draw frame numbers at each framestep value */
+ if (arm->pathflag & ARM_PATH_FNUMS) {
+ for(a=0, fp= pchan->path; a<pchan->pathlen; a+=stepsize, fp+=(stepsize*3)) {
+ char str[32];
+
+ /* only draw framenum if several consecutive highlighted points occur on same point */
+ if (a == 0) {
+ glRasterPos3fv(fp);
+ sprintf(str, " %d\n", (a+sfra));
+ BMF_DrawString(G.font, str);
+ }
+ else if ((a > stepsize) && (a < pchan->pathlen-stepsize)) {
+ if ((VecEqual(fp, fp-(stepsize*3))==0) || (VecEqual(fp, fp+(stepsize*3))==0)) {
+ glRasterPos3fv(fp);
+ sprintf(str, " %d\n", (a+sfra));
+ BMF_DrawString(G.font, str);
+ }
+ }
+ }
+ }
+
+ /* Keyframes - dots and numbers */
+ if (arm->pathflag & ARM_PATH_KFRAS) {
+ /* build list of all keyframes in active action for pchan */
+ ak.first = ak.last = NULL;
+ act= ob_get_action(ob);
+ if (act) {
+ achan= get_action_channel(act, pchan->name);
+ if (achan)
+ ipo_to_keylist(achan->ipo, &ak, NULL);
+ }
+
+ /* Draw little yellow dots at each keyframe */
+ BIF_ThemeColor(TH_VERTEX_SELECT);
+ glBegin(GL_POINTS);
+ for(a=0, fp= pchan->path; a<pchan->pathlen; a++, fp+=3) {
+ for (ce= ak.first; ce; ce= ce->next) {
+ if (ce->cfra == (a+sfra))
+ glVertex3fv(fp);
+ }
+ }
+ glEnd();
+
+ /* Draw frame numbers of keyframes */
+ if (arm->pathflag & ARM_PATH_FNUMS) {
+ for(a=0, fp= pchan->path; a<pchan->pathlen; a++, fp+=3) {
+ for (ce= ak.first; ce; ce= ce->next) {
+ if (ce->cfra == (a+sfra)) {
+ char str[32];
+
+ glRasterPos3fv(fp);
+ sprintf(str, " %d\n", (a+sfra));
+ BMF_DrawString(G.font, str);
+ }
+ }
+ }
+ }
+
+ BLI_freelistN(&ak);
+ }
+ }
+ }
+ }
+
+ if(G.vd->zbuf) glEnable(GL_DEPTH_TEST);
+ glPopMatrix();
+}
+
+/* draw ghosts that occur within a frame range
+ * note: object should be in posemode */
+static void draw_ghost_poses_range(Base *base)
+{
+ Object *ob= base->object;
+ bArmature *arm= ob->data;
+ bPose *posen, *poseo;
+ float start, end, stepsize, range, colfac;
+ int cfrao, flago, ipoflago;
+
+ start = arm->ghostsf;
+ end = arm->ghostef;
+ if (end<=start)
+ return;
+
+ stepsize= (float)(arm->ghostsize);
+ range= (float)(end - start);
+
+ /* store values */
+ ob->flag &= ~OB_POSEMODE;
+ cfrao= CFRA;
+ flago= arm->flag;
+ arm->flag &= ~(ARM_DRAWNAMES|ARM_DRAWAXES);
+ ipoflago= ob->ipoflag;
+ ob->ipoflag |= OB_DISABLE_PATH;
+
+ /* copy the pose */
+ poseo= ob->pose;
+ copy_pose(&posen, ob->pose, 1);
+ ob->pose= posen;
+ armature_rebuild_pose(ob, ob->data); /* child pointers for IK */
+
+ glEnable(GL_BLEND);
+ if(G.vd->zbuf) glDisable(GL_DEPTH_TEST);
+
+ /* draw from first frame of range to last */
+ for(CFRA= start; CFRA<end; CFRA+=stepsize) {
+ colfac = (end-CFRA)/range;
+ BIF_ThemeColorShadeAlpha(TH_WIRE, 0, -128-(int)(120.0f*sqrt(colfac)));
+
+ do_all_pose_actions(ob);
+ where_is_pose(ob);
+ draw_pose_channels(base, OB_WIRE);
+ }
+ glDisable(GL_BLEND);
+ if(G.vd->zbuf) glEnable(GL_DEPTH_TEST);
+
+ free_pose_channels(posen);
+ MEM_freeN(posen);
+
+ /* restore */
+ CFRA= cfrao;
+ ob->pose= poseo;
+ arm->flag= flago;
+ armature_rebuild_pose(ob, ob->data);
+ ob->flag |= OB_POSEMODE;
+ ob->ipoflag= ipoflago;
+
+}
+
+/* object is supposed to be armature in posemode */
+static void draw_ghost_poses(Base *base)
+{
+ Object *ob= base->object;
+ bArmature *arm= ob->data;
+ bPose *posen, *poseo;
+ bActionStrip *strip;
+ float cur, start, end, stepsize, range, colfac, actframe, ctime;
+ int cfrao, maptime, flago, ipoflago;
+
+ /* pre conditions, get an action with sufficient frames */
+ if(ob->action==NULL)
+ return;
+
+ calc_action_range(ob->action, &start, &end, 0);
+ if(start==end)
+ return;
+
+ stepsize= (float)(arm->ghostsize);
+ range= (float)(arm->ghostep)*stepsize + 0.5f; /* plus half to make the for loop end correct */
+
+ /* we only map time for armature when an active strip exists */
+ for (strip=ob->nlastrips.first; strip; strip=strip->next)
+ if(strip->flag & ACTSTRIP_ACTIVE)
+ break;
+
+ maptime= (strip!=NULL);
+
+ /* store values */
+ ob->flag &= ~OB_POSEMODE;
+ cfrao= CFRA;
+ if(maptime) actframe= get_action_frame(ob, (float)CFRA);
+ else actframe= CFRA;
+ flago= arm->flag;
+ arm->flag &= ~(ARM_DRAWNAMES|ARM_DRAWAXES);
+ ipoflago= ob->ipoflag;
+ ob->ipoflag |= OB_DISABLE_PATH;
+
+ /* copy the pose */
+ poseo= ob->pose;
+ copy_pose(&posen, ob->pose, 1);
+ ob->pose= posen;
+ armature_rebuild_pose(ob, ob->data); /* child pointers for IK */
+
+ glEnable(GL_BLEND);
+ if(G.vd->zbuf) glDisable(GL_DEPTH_TEST);
+
+ /* draw from darkest blend to lowest */
+ for(cur= stepsize; cur<range; cur+=stepsize) {
+
+ ctime= cur - fmod((float)cfrao, stepsize); /* ensures consistant stepping */
+ colfac= ctime/range;
+ BIF_ThemeColorShadeAlpha(TH_WIRE, 0, -128-(int)(120.0f*sqrt(colfac)));
+
+ /* only within action range */
+ if(actframe+ctime >= start && actframe+ctime <= end) {
+
+ if(maptime) CFRA= (int)get_action_frame_inv(ob, actframe+ctime);
+ else CFRA= (int)floor(actframe+ctime);
+
+ if(CFRA!=cfrao) {
+ do_all_pose_actions(ob);
+ where_is_pose(ob);
+ draw_pose_channels(base, OB_WIRE);
+ }
+ }
+
+ ctime= cur + fmod((float)cfrao, stepsize) - stepsize+1.0f; /* ensures consistant stepping */
+ colfac= ctime/range;
+ BIF_ThemeColorShadeAlpha(TH_WIRE, 0, -128-(int)(120.0f*sqrt(colfac)));
+
+ /* only within action range */
+ if(actframe-ctime >= start && actframe-ctime <= end) {
+
+ if(maptime) CFRA= (int)get_action_frame_inv(ob, actframe-ctime);
+ else CFRA= (int)floor(actframe-ctime);
+
+ if(CFRA!=cfrao) {
+ do_all_pose_actions(ob);
+ where_is_pose(ob);
+ draw_pose_channels(base, OB_WIRE);
+ }
+ }
+ }
+ glDisable(GL_BLEND);
+ if(G.vd->zbuf) glEnable(GL_DEPTH_TEST);
+
+ free_pose_channels(posen);
+ MEM_freeN(posen);
+
+ /* restore */
+ CFRA= cfrao;
+ ob->pose= poseo;
+ arm->flag= flago;
+ armature_rebuild_pose(ob, ob->data);
+ ob->flag |= OB_POSEMODE;
+ ob->ipoflag= ipoflago;
+
+}
+
+/* called from drawobject.c, return 1 if nothing was drawn */
+int draw_armature(Base *base, int dt)
+{
+ Object *ob= base->object;
+ bArmature *arm= ob->data;
+ int retval= 0;
+
+ if(dt>OB_WIRE && arm->drawtype!=ARM_LINE) {
+ /* we use color for solid lighting */
+ glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR);
+ glEnable(GL_COLOR_MATERIAL);
+ glColor3ub(0,0,0); // clear spec
+ glDisable(GL_COLOR_MATERIAL);
+
+ glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
+ glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW); // only for lighting...
+ }
+
+ /* arm->flag is being used to detect mode... */
+ /* editmode? */
+ if(ob==G.obedit || (G.obedit && ob->data==G.obedit->data)) {
+ if(ob==G.obedit) arm->flag |= ARM_EDITMODE;
+ draw_ebones(ob, dt);
+ arm->flag &= ~ARM_EDITMODE;
+ }
+ else{
+ /* Draw Pose */
+ if(ob->pose && ob->pose->chanbase.first) {
+ /* drawing posemode selection indices or colors only in these cases */
+ if(!(base->flag & OB_FROMDUPLI)) {
+ if(G.f & G_PICKSEL) {
+ if(ob->flag & OB_POSEMODE)
+ arm->flag |= ARM_POSEMODE;
+ }
+ else if(ob->flag & OB_POSEMODE) {
+ if (arm->ghosttype == ARM_GHOST_RANGE){
+ draw_ghost_poses_range(base);
+ }
+ else {
+ if (arm->ghostep)
+ draw_ghost_poses(base);
+ }
+
+ if(ob==OBACT)
+ arm->flag |= ARM_POSEMODE;
+ else if(G.f & G_WEIGHTPAINT)
+ arm->flag |= ARM_POSEMODE;
+
+ draw_pose_paths(ob);
+ }
+ }
+ draw_pose_channels(base, dt);
+ arm->flag &= ~ARM_POSEMODE;
+
+ if(ob->flag & OB_POSEMODE)
+ BIF_ThemeColor(TH_WIRE); /* restore, for extra draw stuff */
+ }
+ else retval= 1;
+ }
+ /* restore */
+ glFrontFace(GL_CCW);
+
+ return retval;
+}
+
+/* *************** END Armature drawing ******************* */
+
diff --git a/source/blender/src/drawdeps.c b/source/blender/src/drawdeps.c
new file mode 100644
index 00000000000..d948f31009b
--- /dev/null
+++ b/source/blender/src/drawdeps.c
@@ -0,0 +1,316 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+#ifdef _WIN32
+#include "BLI_winstuff.h"
+#endif
+
+#include "BMF_Api.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "DNA_ID.h"
+#include "DNA_object_types.h"
+#include "DNA_oops_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_view2d_types.h"
+#include "DNA_action_types.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_global.h"
+
+#include "BIF_interface.h"
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+#include "BIF_mywindow.h"
+#include "BIF_resources.h"
+#include "BIF_screen.h"
+
+#include "BIF_oops.h"
+
+#include "BSE_drawipo.h"
+#include "BSE_drawoops.h"
+#include "MEM_guardedalloc.h"
+#include "blendef.h"
+
+
+#include "depsgraph_private.h"
+
+#ifdef WIN32
+#else
+#include <sys/time.h>
+#endif
+
+
+
+void boundbox_deps()
+{
+ DagNode *node;
+ float min[2], max[2];
+
+ if(G.soops==0) return;
+
+ min[0]= 1000.0;
+ max[0]= -10000.0;
+ min[1]= 1000.0;
+ max[1]= -1000.0;
+
+ node = getMainDag()->DagNode.first;
+ while(node) {
+ min[0]= MIN2(min[0], node->x);
+ max[0]= MAX2(max[0], node->x+OOPSX);
+ min[1]= MIN2(min[1], node->y);
+ max[1]= MAX2(max[1], node->y+OOPSY);
+
+ node= node->next;
+ }
+
+ G.v2d->tot.xmin= min[0];
+ G.v2d->tot.xmax= max[0];
+ G.v2d->tot.ymin= min[1];
+ G.v2d->tot.ymax= max[1];
+}
+
+static unsigned int get_line_color(DagAdjList *child)
+{
+ switch (child->type) {
+ case DAG_RL_SCENE :
+ return 0x00000;
+ case DAG_RL_DATA :
+ return 0xFF0000;
+ case DAG_RL_OB_OB :
+ return 0x00FF00;
+ case DAG_RL_OB_DATA :
+ return 0xFFFF00;
+ case DAG_RL_DATA_OB :
+ return 0x000000;
+ case DAG_RL_DATA_DATA :
+ return 0x0000FF;
+ default :
+ return 0xFF00FF;
+ }
+ //return 0x00000;
+}
+
+
+static void draw_deps(DagNode *node)
+{
+ float v1[2], x1, y1, x2, y2;
+ unsigned int body, border;
+ short line= 0;
+ char str[32];
+ DagAdjList *itA = node->child;
+
+ x1= node->x;
+ x2= node->x+DEPSX;
+ y1= node->y;
+ y2= node->y+DEPSY;
+
+ if(x2 < G.v2d->cur.xmin || x1 > G.v2d->cur.xmax) return;
+ if(y2 < G.v2d->cur.ymin || y1 > G.v2d->cur.ymax) return;
+
+ body = give_oops_color(node->type, 0, &border);
+
+ line= 0;
+// border= 00;
+ cpack(body);
+
+ glRectf(x1, y1, x2, y2);
+
+ v1[0]= x1;
+ v1[1]= (y1+y2)/2 -0.3f;
+ sprintf(str, " %s", ((ID *) node->ob)->name+2);
+
+ calc_oopstext(str, v1);
+
+ /* ICON */
+// if(str[1] && oopscalex>1.1) {
+ draw_icon_oops(v1, node->type);
+// }
+
+
+ cpack(0x0);
+ glRasterPos3f(v1[0], v1[1], 0.0);
+ BMF_DrawString(G.fonts, str);
+
+
+ if(line) setlinestyle(2);
+ cpack(border);
+
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ glRectf(x1, y1, x2, y2);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ if(line) setlinestyle(0);
+
+ while (itA) { /* draw connection lines */
+ cpack(get_line_color(itA));
+ glBegin(GL_LINE_STRIP);
+ glVertex2f(node->x+DEPSX, node->y+ 0.5*DEPSY);
+ glVertex2f(itA->node->x, itA->node->y+ 0.5*DEPSY);
+ glEnd();
+ itA = itA->next;
+ }
+ /* Draw the little rounded connection point */
+ glColor3ub(0, 0, 0);
+ glPushMatrix();
+
+ glTranslatef(node->x , node->y+ 0.5*DEPSY, 0.0);
+ glutil_draw_filled_arc(-M_PI/2, M_PI, 0.07*DEPSX, 7);
+
+ glPopMatrix();
+
+}
+
+void draw_all_deps(void)
+{
+ DagNode *node;
+ DagForest *dag;
+
+ dag = getMainDag();
+ node = dag->DagNode.first;
+ //node = node->next;
+ while(node) {
+ draw_deps(node);
+ node = node->next;
+ }
+ free_forest(dag);
+ MEM_freeN(dag);
+ setMainDag(NULL);
+}
+
+
+
+
+int build_deps(short mask)
+{
+ Base *base;
+ Object *ob = NULL;
+ DagNode * node = NULL;
+ DagNode * node2 = NULL ;
+DagNode * scenenode;
+ DagForest *dag;
+
+#ifdef DEPS_DEBUG
+ //timers
+ struct timeval tp1, tp2, tp3, tp4;
+
+ gettimeofday(&tp1,NULL);
+#endif
+
+ DagNodeQueue *retqueue;
+
+// float y = 0;
+// int maxlev = 0;
+
+ if(G.soops==0) return -1;
+
+
+ // rebuilt each time for now
+ dag = getMainDag();
+ if ( dag)
+ free_forest( dag );
+ else {
+ dag = dag_init();
+ setMainDag(dag);
+ }
+
+ // add base node for scene. scene is always the first node in DAG
+ scenenode = dag_add_node(dag, G.scene);
+ set_node_xy(scenenode,0.0, 0.0);
+ /* blocks from this scene */
+
+
+ /* targets in object struct yet to be added. should even they ?
+ struct Ipo *ipo;
+ ListBase nlastrips;
+ ListBase hooks;
+ */
+
+
+ base= FIRSTBASE;
+ while(base) { // add all objects in any case
+ int addtoroot = 1;
+
+ // graph_print_adj_list();
+ ob= (Object *) base->object;
+
+ node = dag_get_node(dag,ob);
+
+ if ((ob->data) && (mask&DAG_RL_DATA)) {
+ node2 = dag_get_node(dag,ob->data);
+ dag_add_relation(dag,node,node2,DAG_RL_DATA);
+ node2->first_ancestor = ob;
+ node2->ancestor_count += 1;
+
+ }
+
+ if (addtoroot == 1 )
+ dag_add_relation(dag,scenenode,node,DAG_RL_SCENE);
+
+ base= base->next;
+ }
+
+//graph_print_adj_list();
+//fprintf(stderr,"building deps\n");
+#ifdef DEPS_DEBUG
+ gettimeofday(&tp2,NULL);
+#endif
+
+//graph_bfs(); //set levels
+
+#ifdef DEPS_DEBUG
+gettimeofday(&tp3,NULL);
+#endif
+
+
+retqueue = graph_dfs(); //set levels
+#ifdef DEPS_DEBUG
+gettimeofday(&tp4,NULL);
+fprintf(stderr,"************************************\n");
+graph_print_queue_dist(retqueue);
+//graph_print_queue(retqueue);
+
+fprintf(stderr,"TIME BUILD %d %d BFS %d %d DFS %d %d\n",tp2.tv_sec-tp1.tv_sec ,tp2.tv_usec-tp1.tv_usec
+ , tp3.tv_sec-tp2.tv_sec ,tp3.tv_usec-tp2.tv_usec
+ , tp4.tv_sec-tp3.tv_sec ,tp4.tv_usec-tp3.tv_usec);
+#endif
+
+queue_delete(retqueue);
+
+//graph_print_adj_list();
+return 0;
+}
diff --git a/source/blender/src/drawimage.c b/source/blender/src/drawimage.c
new file mode 100644
index 00000000000..f75de0bb331
--- /dev/null
+++ b/source/blender/src/drawimage.c
@@ -0,0 +1,2703 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Blender Foundation, 2002-2006
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <math.h>
+#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WIN32
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+#include "MEM_guardedalloc.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+#include "BLI_editVert.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_color_types.h"
+#include "DNA_image_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_packedFile_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BKE_brush.h"
+#include "BKE_colortools.h"
+#include "BKE_utildefines.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_mesh.h"
+#include "BKE_node.h"
+#include "BKE_image.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_displist.h"
+#include "BKE_object.h"
+
+#include "BDR_editface.h"
+#include "BDR_drawobject.h"
+#include "BDR_drawmesh.h"
+#include "BDR_imagepaint.h"
+
+#include "BIF_cursors.h"
+#include "BIF_gl.h"
+#include "BIF_graphics.h"
+#include "BIF_mywindow.h"
+#include "BIF_drawimage.h"
+#include "BIF_resources.h"
+#include "BIF_interface.h"
+#include "BIF_interface_icons.h"
+#include "BIF_editsima.h"
+#include "BIF_glutil.h"
+#include "BIF_renderwin.h"
+#include "BIF_space.h"
+#include "BIF_screen.h"
+#include "BIF_toolbox.h"
+#include "BIF_transform.h"
+#include "BIF_editmesh.h"
+
+#include "BSE_drawipo.h"
+#include "BSE_drawview.h"
+#include "BSE_filesel.h"
+#include "BSE_headerbuttons.h"
+#include "BSE_node.h"
+#include "BSE_trans_types.h"
+#include "BSE_view.h"
+
+#include "RE_pipeline.h"
+#include "BMF_Api.h"
+
+#include "PIL_time.h"
+
+/* Modules used */
+#include "mydevice.h"
+#include "blendef.h"
+#include "butspace.h" // event codes
+#include "winlay.h"
+
+#include "interface.h" /* bad.... but preview code needs UI info. Will solve... (ton) */
+
+static unsigned char *alloc_alpha_clone_image(int *width, int *height)
+{
+ Brush *brush = G.scene->toolsettings->imapaint.brush;
+ ImBuf *ibuf;
+ unsigned int size, alpha;
+ unsigned char *rect, *cp;
+
+ if(!brush || !brush->clone.image)
+ return NULL;
+
+ ibuf= BKE_image_get_ibuf(brush->clone.image, NULL);
+
+ if(!ibuf || !ibuf->rect)
+ return NULL;
+
+ rect= MEM_dupallocN(ibuf->rect);
+ if(!rect)
+ return NULL;
+
+ *width= ibuf->x;
+ *height= ibuf->y;
+
+ size= (*width)*(*height);
+ alpha= (unsigned char)255*brush->clone.alpha;
+ cp= rect;
+
+ while(size-- > 0) {
+ cp[3]= alpha;
+ cp += 4;
+ }
+
+ return rect;
+}
+
+static int image_preview_active(ScrArea *sa, float *xim, float *yim)
+{
+ SpaceImage *sima= sa->spacedata.first;
+
+ /* only when compositor shows, and image handler set */
+ if(sima->image && sima->image->type==IMA_TYPE_COMPOSITE) {
+ short a;
+
+ for(a=0; a<SPACE_MAXHANDLER; a+=2) {
+ if(sima->blockhandler[a] == IMAGE_HANDLER_PREVIEW) {
+ if(xim) *xim= (G.scene->r.size*G.scene->r.xsch)/100;
+ if(yim) *yim= (G.scene->r.size*G.scene->r.ysch)/100;
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+
+/**
+ * Sets up the fields of the View2D member of the SpaceImage struct
+ * This routine can be called in two modes:
+ * mode == 'f': float mode (0.0 - 1.0)
+ * mode == 'p': pixel mode (0 - size)
+ *
+ * @param sima the image space to update
+ * @param mode the mode to use for the update
+ * @return void
+ *
+ */
+void calc_image_view(SpaceImage *sima, char mode)
+{
+ float xim=256, yim=256;
+ float x1, y1;
+
+ if(image_preview_active(curarea, &xim, &yim));
+ else if(sima->image) {
+ ImBuf *ibuf= BKE_image_get_ibuf(sima->image, &sima->iuser);
+ float xuser_asp, yuser_asp;
+
+ aspect_sima(sima, &xuser_asp, &yuser_asp);
+ if(ibuf) {
+ xim= ibuf->x * xuser_asp;
+ yim= ibuf->y * yuser_asp;
+ }
+ else if( sima->image->type==IMA_TYPE_R_RESULT ) {
+ /* not very important, just nice */
+ xim= (G.scene->r.xsch*G.scene->r.size)/100;
+ yim= (G.scene->r.ysch*G.scene->r.size)/100;
+ }
+ }
+
+ sima->v2d.tot.xmin= 0;
+ sima->v2d.tot.ymin= 0;
+ sima->v2d.tot.xmax= xim;
+ sima->v2d.tot.ymax= yim;
+
+ sima->v2d.mask.xmin= sima->v2d.mask.ymin= 0;
+ sima->v2d.mask.xmax= curarea->winx;
+ sima->v2d.mask.ymax= curarea->winy;
+
+
+ /* Which part of the image space do we see? */
+ /* Same calculation as in lrectwrite: area left and down*/
+ x1= curarea->winrct.xmin+(curarea->winx-sima->zoom*xim)/2;
+ y1= curarea->winrct.ymin+(curarea->winy-sima->zoom*yim)/2;
+
+ x1-= sima->zoom*sima->xof;
+ y1-= sima->zoom*sima->yof;
+
+ /* relative display right */
+ sima->v2d.cur.xmin= ((curarea->winrct.xmin - (float)x1)/sima->zoom);
+ sima->v2d.cur.xmax= sima->v2d.cur.xmin + ((float)curarea->winx/sima->zoom);
+
+ /* relative display left */
+ sima->v2d.cur.ymin= ((curarea->winrct.ymin-(float)y1)/sima->zoom);
+ sima->v2d.cur.ymax= sima->v2d.cur.ymin + ((float)curarea->winy/sima->zoom);
+
+ if(mode=='f') {
+ sima->v2d.cur.xmin/= xim;
+ sima->v2d.cur.xmax/= xim;
+ sima->v2d.cur.ymin/= yim;
+ sima->v2d.cur.ymax/= yim;
+ }
+}
+
+/* check for facelesect, and set active image */
+void what_image(SpaceImage *sima)
+{
+ MTFace *activetf;
+
+ if( (sima->mode!=SI_TEXTURE) ||
+ (sima->image && sima->image->source==IMA_SRC_VIEWER) ||
+ (G.obedit != OBACT) ||
+ (sima->pin)
+ ) {
+ return;
+ }
+
+ /* viewer overrides uv editmode */
+ if (EM_texFaceCheck()) {
+ sima->image= NULL;
+
+ activetf = get_active_mtface(NULL, NULL, 1); /* partially selected face is ok */
+
+ if(activetf && activetf->mode & TF_TEX) {
+ if (!sima->pin)
+ sima->image= activetf->tpage;
+
+ if(sima->flag & SI_EDITTILE);
+ else sima->curtile= activetf->tile;
+
+ if(sima->image) {
+ if(activetf->mode & TF_TILES)
+ sima->image->tpageflag |= IMA_TILES;
+ else sima->image->tpageflag &= ~IMA_TILES;
+ }
+ }
+ }
+}
+
+/* after a what_image(), this call will give ibufs, includes the spare image */
+ImBuf *imagewindow_get_ibuf(SpaceImage *sima)
+{
+
+ if(G.sima->image) {
+ /* check for spare */
+ if(sima->image->type==IMA_TYPE_R_RESULT && sima->showspare)
+ return sima->spare;
+ else
+ return BKE_image_get_ibuf(sima->image, &sima->iuser);
+ }
+ return NULL;
+}
+
+extern int EM_texFaceCheck(void); /* from editmesh.c */
+/* called to assign images to UV faces */
+void image_changed(SpaceImage *sima, Image *image)
+{
+ MTFace *tface;
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+ ImBuf *ibuf = NULL;
+ short change = 0;
+
+ if(image==NULL) {
+ sima->flag &= ~SI_DRAWTOOL;
+ } else {
+ ibuf = BKE_image_get_ibuf(image, NULL);
+ }
+
+ if(sima->mode!=SI_TEXTURE)
+ return;
+
+ /* skip assigning these procedural images... */
+ if(image && (image->type==IMA_TYPE_R_RESULT || image->type==IMA_TYPE_COMPOSITE)) {;
+ return;
+ } else if (EM_texFaceCheck()) {
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ if (efa->h==0 && efa->f & SELECT) {
+ if (image) {
+ tface->tpage= image;
+ tface->mode |= TF_TEX;
+
+ if(image->tpageflag & IMA_TILES) tface->mode |= TF_TILES;
+ else tface->mode &= ~TF_TILES;
+
+ if(image->id.us==0) id_us_plus(&image->id);
+ else id_lib_extern(&image->id);
+
+ if (tface->transp==TF_ADD) {} /* they obviously know what they are doing! - leave as is */
+ else if (ibuf && ibuf->depth == 32) tface->transp = TF_ALPHA;
+ else tface->transp = TF_SOLID;
+
+ } else {
+ tface->tpage= NULL;
+ tface->mode &= ~TF_TEX;
+ tface->transp = TF_SOLID;
+ }
+ change = 1;
+ }
+ }
+ }
+ /* change the space image after because SIMA_FACEDRAW_CHECK uses the space image
+ * to check if the face is displayed in UV-localview */
+ sima->image = image;
+
+ if (change)
+ object_uvs_changed(OBACT);
+
+ allqueue(REDRAWBUTSEDIT, 0);
+}
+/*
+ * dotile - 1, set the tile flag (from the space image)
+ * 2, set the tile index for the faces.
+ * */
+void image_set_tile(SpaceImage *sima, int dotile)
+{
+ MTFace *tface;
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+
+ if(!sima->image || sima->mode!=SI_TEXTURE || !EM_texFaceCheck())
+ return;
+
+ /* skip assigning these procedural images... */
+ if(sima->image && (sima->image->type==IMA_TYPE_R_RESULT || sima->image->type==IMA_TYPE_COMPOSITE))
+ return;
+
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ if (efa->h==0 && efa->f & SELECT) {
+ if (dotile==1) {
+ /* set tile flag */
+ if (sima->image->tpageflag & IMA_TILES) {
+ tface->mode |= TF_TILES;
+ } else {
+ tface->mode &= ~TF_TILES;
+ }
+ } else if (dotile==2) {
+ /* set tile index */
+ tface->tile= sima->curtile;
+ }
+ }
+ }
+ object_uvs_changed(OBACT);
+ allqueue(REDRAWBUTSEDIT, 0);
+}
+
+
+
+void uvco_to_areaco(float *vec, short *mval)
+{
+ float x, y;
+
+ mval[0]= IS_CLIPPED;
+
+ x= (vec[0] - G.v2d->cur.xmin)/(G.v2d->cur.xmax-G.v2d->cur.xmin);
+ y= (vec[1] - G.v2d->cur.ymin)/(G.v2d->cur.ymax-G.v2d->cur.ymin);
+
+ if(x>=0.0 && x<=1.0) {
+ if(y>=0.0 && y<=1.0) {
+ mval[0]= G.v2d->mask.xmin + x*(G.v2d->mask.xmax-G.v2d->mask.xmin);
+ mval[1]= G.v2d->mask.ymin + y*(G.v2d->mask.ymax-G.v2d->mask.ymin);
+ }
+ }
+}
+
+void uvco_to_areaco_noclip(float *vec, int *mval)
+{
+ float x, y;
+
+ mval[0]= IS_CLIPPED;
+
+ x= (vec[0] - G.v2d->cur.xmin)/(G.v2d->cur.xmax-G.v2d->cur.xmin);
+ y= (vec[1] - G.v2d->cur.ymin)/(G.v2d->cur.ymax-G.v2d->cur.ymin);
+
+ x= G.v2d->mask.xmin + x*(G.v2d->mask.xmax-G.v2d->mask.xmin);
+ y= G.v2d->mask.ymin + y*(G.v2d->mask.ymax-G.v2d->mask.ymin);
+
+ mval[0]= x;
+ mval[1]= y;
+}
+
+static void drawcursor_sima(float xuser_asp, float yuser_asp)
+{
+ int wi, hi;
+ float w, h;
+
+ if (!G.obedit || !CustomData_has_layer(&G.editMesh->fdata, CD_MTFACE)) return;
+
+ transform_width_height_tface_uv(&wi, &hi);
+ w = (((float)wi)/256.0f)*G.sima->zoom * xuser_asp;
+ h = (((float)hi)/256.0f)*G.sima->zoom * yuser_asp;
+
+ cpack(0xFFFFFF);
+ glTranslatef(G.v2d->cursor[0], G.v2d->cursor[1], 0.0f);
+ fdrawline(-0.05/w, 0, 0, 0.05/h);
+ fdrawline(0, 0.05/h, 0.05/w, 0);
+ fdrawline(0.05/w, 0, 0, -0.05/h);
+ fdrawline(0, -0.05/h, -0.05/w, 0);
+
+ setlinestyle(4);
+ cpack(0xFF);
+ fdrawline(-0.05/w, 0, 0, 0.05/h);
+ fdrawline(0, 0.05/h, 0.05/w, 0);
+ fdrawline(0.05/w, 0, 0, -0.05/h);
+ fdrawline(0, -0.05/h, -0.05/w, 0);
+
+
+ setlinestyle(0);
+ cpack(0x0);
+ fdrawline(-0.020/w, 0, -0.1/w, 0);
+ fdrawline(0.1/w, 0, .020/w, 0);
+ fdrawline(0, -0.020/h, 0, -0.1/h);
+ fdrawline(0, 0.1/h, 0, 0.020/h);
+
+ setlinestyle(1);
+ cpack(0xFFFFFF);
+ fdrawline(-0.020/w, 0, -0.1/w, 0);
+ fdrawline(0.1/w, 0, .020/w, 0);
+ fdrawline(0, -0.020/h, 0, -0.1/h);
+ fdrawline(0, 0.1/h, 0, 0.020/h);
+
+ glTranslatef(-G.v2d->cursor[0], -G.v2d->cursor[1], 0.0f);
+ setlinestyle(0);
+}
+
+// checks if we are selecting only faces
+int draw_uvs_face_check(void)
+{
+ if (G.sima==NULL)
+ return 0;
+ if (G.sima->flag & SI_SYNC_UVSEL && G.scene->selectmode == SCE_SELECT_FACE)
+ return 2;
+ if (G.sima->flag & SI_SELACTFACE)
+ return 1;
+ return 0;
+}
+
+void tface_center(MTFace *tf, float cent[2], void * isquad)
+{
+
+ if (isquad) {
+ cent[0] = (tf->uv[0][0] + tf->uv[1][0] + tf->uv[2][0] + tf->uv[3][0]) / 4.0;
+ cent[1] = (tf->uv[0][1] + tf->uv[1][1] + tf->uv[2][1] + tf->uv[3][1]) / 4.0;
+ } else {
+ cent[0] = (tf->uv[0][0] + tf->uv[1][0] + tf->uv[2][0]) / 3.0;
+ cent[1] = (tf->uv[0][1] + tf->uv[1][1] + tf->uv[2][1]) / 3.0;
+ }
+}
+
+/* draws uv's in the image space */
+void draw_uvs_sima(void)
+{
+ MTFace *tface,*activetface = NULL;
+ EditMesh *em = G.editMesh;
+ EditFace *efa, *efa_act;
+
+ char col1[4], col2[4];
+ float pointsize;
+ int drawface;
+
+ if (!G.obedit || !CustomData_has_layer(&em->fdata, CD_MTFACE))
+ return;
+
+ drawface = draw_uvs_face_check();
+
+ calc_image_view(G.sima, 'f'); /* float */
+ myortho2(G.v2d->cur.xmin, G.v2d->cur.xmax, G.v2d->cur.ymin, G.v2d->cur.ymax);
+ glLoadIdentity();
+
+
+ if(G.sima->flag & SI_DRAWTOOL) {
+ /* draws the grey mesh when painting */
+ glColor3ub(112, 112, 112);
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ glBegin(GL_LINE_LOOP);
+ glVertex2fv(tface->uv[0]);
+ glVertex2fv(tface->uv[1]);
+ glVertex2fv(tface->uv[2]);
+ if(efa->v4) glVertex2fv(tface->uv[3]);
+ glEnd();
+ }
+ return; /* only draw shadow mesh */
+ } else if (G.sima->flag & SI_DRAWSHADOW) {
+ /* draw shadow mesh - this is the mesh with the modifier applied */
+ glColor3ub(112, 112, 112);
+ if ( em->derivedFinal &&
+ em->derivedFinal->drawUVEdges &&
+ CustomData_has_layer(&em->derivedFinal->faceData, CD_MTFACE)
+ ) {
+ /* we can use the existing final mesh */
+ glColor3ub(112, 112, 112);
+ G.editMesh->derivedFinal->drawUVEdges(G.editMesh->derivedFinal);
+ } else {
+ DerivedMesh *finalDM, *cageDM;
+
+ /* draw final mesh with modifiers applied */
+ cageDM = editmesh_get_derived_cage_and_final(&finalDM, CD_MASK_BAREMESH | CD_MASK_MTFACE);
+
+ if (finalDM->drawUVEdges &&
+ DM_get_face_data_layer(finalDM, CD_MTFACE) &&
+ /* When sync selection is enabled, all faces are drawn (except for hidden)
+ * so if cage is the same as the final, theres no point in drawing the shadowmesh. */
+ !((G.sima->flag & SI_SYNC_UVSEL && cageDM==finalDM))
+ ) {
+ glColor3ub(112, 112, 112);
+ finalDM->drawUVEdges(finalDM);
+ }
+
+ if (cageDM != finalDM)
+ cageDM->release(cageDM);
+ finalDM->release(finalDM);
+ }
+ }
+
+ activetface = get_active_mtface(&efa_act, NULL, 0); /* will be set to NULL if hidden */
+
+ /* draw transparent faces */
+ if(G.f & G_DRAWFACES) {
+ BIF_GetThemeColor4ubv(TH_FACE, col1);
+ BIF_GetThemeColor4ubv(TH_FACE_SELECT, col2);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_BLEND);
+
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+
+ if (SIMA_FACEDRAW_CHECK(efa, tface)) {
+ efa->tmp.p = tface;
+ if (tface==activetface) continue; /* important the temp pointer is set above */
+ if( SIMA_FACESEL_CHECK(efa, tface) )
+ glColor4ubv((GLubyte *)col2);
+ else
+ glColor4ubv((GLubyte *)col1);
+
+ glBegin(efa->v4?GL_QUADS:GL_TRIANGLES);
+ glVertex2fv(tface->uv[0]);
+ glVertex2fv(tface->uv[1]);
+ glVertex2fv(tface->uv[2]);
+ if(efa->v4) glVertex2fv(tface->uv[3]);
+ glEnd();
+
+ } else {
+ if (tface == activetface)
+ activetface= NULL;
+ efa->tmp.p = NULL;
+ }
+ }
+ } else {
+ /* would be nice to do this within a draw loop but most below are optional, so it would involve too many checks */
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ if (SIMA_FACEDRAW_CHECK(efa, tface)) {
+ efa->tmp.p = tface;
+ } else {
+ if (tface == activetface)
+ activetface= NULL;
+ efa->tmp.p = NULL;
+ }
+ }
+ glDisable(GL_BLEND);
+ }
+
+ if (activetface) {
+ GLubyte act_face_stipple[32*32/8] = DM_FACE_STIPPLE;
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ BIF_ThemeColor4(TH_EDITMESH_ACTIVE);
+ glEnable(GL_POLYGON_STIPPLE);
+ glPolygonStipple(act_face_stipple);
+ glBegin(efa_act->v4?GL_QUADS:GL_TRIANGLES);
+ glVertex2fv(activetface->uv[0]);
+ glVertex2fv(activetface->uv[1]);
+ glVertex2fv(activetface->uv[2]);
+ if(efa_act->v4) glVertex2fv(activetface->uv[3]);
+ glEnd();
+ glDisable(GL_POLYGON_STIPPLE);
+ glDisable(GL_BLEND);
+ }
+
+ if (G.sima->flag & SI_SMOOTH_UV) {
+ glEnable( GL_LINE_SMOOTH );
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+
+ switch (G.sima->dt_uv) {
+ case SI_UVDT_DASH:
+ for (efa= em->faces.first; efa; efa= efa->next) {
+// tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+// if (SIMA_FACEDRAW_CHECK(efa, tface)) {
+
+ /*this is a shortcut to do the same as above but a faster for drawing */
+ if ((tface=(MTFace *)efa->tmp.p)) {
+
+ cpack(0x111111);
+ glBegin(GL_LINE_LOOP);
+ glVertex2fv(tface->uv[0]);
+ glVertex2fv(tface->uv[1]);
+ glVertex2fv(tface->uv[2]);
+ if(efa->v4) glVertex2fv(tface->uv[3]);
+ glEnd();
+
+ setlinestyle(2);
+ cpack(0x909090);
+ glBegin(GL_LINE_STRIP);
+ glVertex2fv(tface->uv[0]);
+ glVertex2fv(tface->uv[1]);
+ glEnd();
+
+ glBegin(GL_LINE_STRIP);
+ glVertex2fv(tface->uv[0]);
+ if(efa->v4) glVertex2fv(tface->uv[3]);
+ else glVertex2fv(tface->uv[2]);
+ glEnd();
+
+ glBegin(GL_LINE_STRIP);
+ glVertex2fv(tface->uv[1]);
+ glVertex2fv(tface->uv[2]);
+ if(efa->v4) glVertex2fv(tface->uv[3]);
+ glEnd();
+ setlinestyle(0);
+ }
+ }
+ break;
+ case SI_UVDT_BLACK: /* black/white */
+ case SI_UVDT_WHITE:
+ cpack((G.sima->dt_uv==SI_UVDT_WHITE) ? 0xFFFFFF : 0x0);
+ for (efa= em->faces.first; efa; efa= efa->next) {
+// tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+// if (SIMA_FACEDRAW_CHECK(efa, tface)) {
+
+ /*this is a shortcut to do the same as above but a faster for drawing */
+ if ((tface=(MTFace *)efa->tmp.p)) {
+
+ glBegin(GL_LINE_LOOP);
+ glVertex2fv(tface->uv[0]);
+ glVertex2fv(tface->uv[1]);
+ glVertex2fv(tface->uv[2]);
+ if(efa->v4) glVertex2fv(tface->uv[3]);
+ glEnd();
+ }
+ }
+ break;
+ case SI_UVDT_OUTLINE:
+ glLineWidth(3);
+ cpack(0x0);
+
+ for (efa= em->faces.first; efa; efa= efa->next) {
+// tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+// if (SIMA_FACEDRAW_CHECK(efa, tface)) {
+
+ /*this is a shortcut to do the same as above but a faster for drawing */
+ if ((tface=(MTFace *)efa->tmp.p)) {
+
+ glBegin(GL_LINE_LOOP);
+ glVertex2fv(tface->uv[0]);
+ glVertex2fv(tface->uv[1]);
+ glVertex2fv(tface->uv[2]);
+ if(efa->v4) glVertex2fv(tface->uv[3]);
+ glEnd();
+ }
+ }
+
+ glLineWidth(1);
+ cpack(0xFFFFFF);
+ for (efa= em->faces.first; efa; efa= efa->next) {
+// tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+// if (SIMA_FACEDRAW_CHECK(efa, tface)) {
+
+ /*this is a shortcut to do the same as above but a faster for drawing */
+ if ((tface=(MTFace *)efa->tmp.p)) {
+
+ glBegin(GL_LINE_LOOP);
+ glVertex2fv(tface->uv[0]);
+ glVertex2fv(tface->uv[1]);
+ glVertex2fv(tface->uv[2]);
+ if(efa->v4) glVertex2fv(tface->uv[3]);
+ glEnd();
+ }
+ }
+ break;
+ }
+
+ if (G.sima->flag & SI_SMOOTH_UV) {
+ glDisable( GL_LINE_SMOOTH);
+ glDisable(GL_BLEND);
+ }
+
+ if (drawface) {
+ // draw UV face points
+ float cent[2];
+
+
+ /* unselected faces's */
+ pointsize = BIF_GetThemeValuef(TH_FACEDOT_SIZE);
+ // TODO - drawobject.c changes this value after - Investiagate!
+ glPointSize(pointsize);
+
+ BIF_ThemeColor(TH_WIRE);
+ bglBegin(GL_POINTS);
+ for (efa= em->faces.first; efa; efa= efa->next) {
+
+// tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+// if (SIMA_FACEDRAW_CHECK(efa, tface)) {
+
+ /*this is a shortcut to do the same as above but a faster for drawing */
+ if ((tface=(MTFace *)efa->tmp.p)) {
+ if( ! SIMA_FACESEL_CHECK(efa, tface) ) {
+ tface_center(tface, cent, (void *)efa->v4);
+ bglVertex2fv(cent);
+ }
+ }
+ }
+ bglEnd();
+ /* selected faces's */
+ BIF_ThemeColor(TH_FACE_DOT);
+ bglBegin(GL_POINTS);
+ for (efa= em->faces.first; efa; efa= efa->next) {
+
+// tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+// if (SIMA_FACEDRAW_CHECK(efa, tface)) {
+
+ /*this is a shortcut to do the same as above but a faster for drawing */
+ if ((tface=(MTFace *)efa->tmp.p)) {
+ if( SIMA_FACESEL_CHECK(efa, tface) ) {
+ tface_center(tface, cent, (void *)efa->v4);
+ bglVertex2fv(cent);
+ }
+ }
+ }
+ bglEnd();
+ }
+
+ if (drawface != 2) { /* 2 means Mesh Face Mode */
+ /* unselected uv's */
+ BIF_ThemeColor(TH_VERTEX);
+ pointsize = BIF_GetThemeValuef(TH_VERTEX_SIZE);
+ glPointSize(pointsize);
+
+ bglBegin(GL_POINTS);
+ for (efa= em->faces.first; efa; efa= efa->next) {
+
+// tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+// if (SIMA_FACEDRAW_CHECK(efa, tface)) {
+
+ /*this is a shortcut to do the same as above but a faster for drawing */
+ if ((tface=(MTFace *)efa->tmp.p)) {
+
+ if(SIMA_UVSEL_CHECK(efa, tface, 0)); else bglVertex2fv(tface->uv[0]);
+ if(SIMA_UVSEL_CHECK(efa, tface, 1)); else bglVertex2fv(tface->uv[1]);
+ if(SIMA_UVSEL_CHECK(efa, tface, 2)); else bglVertex2fv(tface->uv[2]);
+ if(efa->v4) {
+ if(SIMA_UVSEL_CHECK(efa, tface, 3)); else bglVertex2fv(tface->uv[3]);
+ }
+ }
+ }
+ bglEnd();
+
+ /* pinned uv's */
+ /* give odd pointsizes odd pin pointsizes */
+ glPointSize(pointsize*2 + (((int)pointsize % 2)? (-1): 0));
+ cpack(0xFF);
+
+ bglBegin(GL_POINTS);
+ for (efa= em->faces.first; efa; efa= efa->next) {
+// tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+// if (SIMA_FACEDRAW_CHECK(efa, tface)) {
+
+ /*this is a shortcut to do the same as above but a faster for drawing */
+ if ((tface=(MTFace *)efa->tmp.p)) {
+
+ if(tface->unwrap & TF_PIN1) bglVertex2fv(tface->uv[0]);
+ if(tface->unwrap & TF_PIN2) bglVertex2fv(tface->uv[1]);
+ if(tface->unwrap & TF_PIN3) bglVertex2fv(tface->uv[2]);
+ if(efa->v4) {
+ if(tface->unwrap & TF_PIN4) bglVertex2fv(tface->uv[3]);
+ }
+ }
+ }
+ bglEnd();
+
+ /* selected uv's */
+ BIF_ThemeColor(TH_VERTEX_SELECT);
+ glPointSize(pointsize);
+
+ bglBegin(GL_POINTS);
+ for (efa= em->faces.first; efa; efa= efa->next) {
+// tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+// if (SIMA_FACEDRAW_CHECK(efa, tface)) {
+
+ /*this is a shortcut to do the same as above but a faster for drawing */
+ if ((tface=(MTFace *)efa->tmp.p)) {
+
+ if(!SIMA_UVSEL_CHECK(efa, tface, 0)); else bglVertex2fv(tface->uv[0]);
+ if(!SIMA_UVSEL_CHECK(efa, tface, 1)); else bglVertex2fv(tface->uv[1]);
+ if(!SIMA_UVSEL_CHECK(efa, tface, 2)); else bglVertex2fv(tface->uv[2]);
+ if(efa->v4) {
+ if(!SIMA_UVSEL_CHECK(efa, tface, 3)); else bglVertex2fv(tface->uv[3]);
+ }
+ }
+ }
+ bglEnd();
+ }
+ glPointSize(1.0);
+}
+
+static unsigned int *get_part_from_ibuf(ImBuf *ibuf, short startx, short starty, short endx, short endy)
+{
+ unsigned int *rt, *rp, *rectmain;
+ short y, heigth, len;
+
+ /* the right offset in rectot */
+
+ rt= ibuf->rect+ (starty*ibuf->x+ startx);
+
+ len= (endx-startx);
+ heigth= (endy-starty);
+
+ rp=rectmain= MEM_mallocN(heigth*len*sizeof(int), "rect");
+
+ for(y=0; y<heigth; y++) {
+ memcpy(rp, rt, len*4);
+ rt+= ibuf->x;
+ rp+= len;
+ }
+ return rectmain;
+}
+
+static void draw_image_transform(ImBuf *ibuf, float xuser_asp, float yuser_asp)
+{
+ if(G.moving) {
+ float aspx, aspy, center[3];
+
+ BIF_drawConstraint();
+
+ if(ibuf==0 || ibuf->rect==0 || ibuf->x==0 || ibuf->y==0) {
+ aspx= aspy= 1.0;
+ }
+ else {
+ aspx= (256.0/ibuf->x) * xuser_asp;
+ aspy= (256.0/ibuf->y) * yuser_asp;
+ }
+ BIF_getPropCenter(center);
+
+ /* scale and translate the circle into place and draw it */
+ glPushMatrix();
+ glScalef(aspx, aspy, 1.0);
+ glTranslatef((1/aspx)*center[0] - center[0],
+ (1/aspy)*center[1] - center[1], 0.0);
+
+ BIF_drawPropCircle();
+
+ glPopMatrix();
+ }
+}
+
+static void draw_image_view_icon(void)
+{
+ float xPos = 5.0;
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+
+ if (G.sima->flag & SI_SYNC_UVSEL) {
+ /* take settings from the editmesh */
+ if (G.scene->selectmode == SCE_SELECT_FACE || G.sima->flag & SI_SELACTFACE) {
+ BIF_icon_draw_aspect(xPos, 5.0, ICON_FACESEL_HLT, 1.0f);
+ }
+
+ } else {
+ /* use the flags for UV mode - normal operation */
+ if(G.sima->flag & SI_SELACTFACE) {
+ BIF_icon_draw_aspect(xPos, 5.0, ICON_FACESEL_HLT, 1.0f);
+ }
+ }
+
+ glBlendFunc(GL_ONE, GL_ZERO);
+ glDisable(GL_BLEND);
+}
+
+static void draw_image_view_tool(void)
+{
+ ToolSettings *settings= G.scene->toolsettings;
+ Brush *brush= settings->imapaint.brush;
+ short mval[2];
+ float radius;
+ int draw= 0;
+
+ if(brush) {
+ if(settings->imapaint.flag & IMAGEPAINT_DRAWING) {
+ if(settings->imapaint.flag & IMAGEPAINT_DRAW_TOOL_DRAWING)
+ draw= 1;
+ }
+ else if(settings->imapaint.flag & IMAGEPAINT_DRAW_TOOL)
+ draw= 1;
+
+ if(draw) {
+ getmouseco_areawin(mval);
+
+ radius= brush->size*G.sima->zoom/2;
+ fdrawXORcirc(mval[0], mval[1], radius);
+
+ if (brush->innerradius != 1.0) {
+ radius *= brush->innerradius;
+ fdrawXORcirc(mval[0], mval[1], radius);
+ }
+ }
+ }
+}
+
+/* ************ panel stuff ************* */
+
+/* this function gets the values for cursor and vertex number buttons */
+static void image_transform_but_attr(int *imx, int *imy, int *step, int *digits) /*, float *xcoord, float *ycoord)*/
+{
+ ImBuf *ibuf= imagewindow_get_ibuf(G.sima);
+ if(ibuf) {
+ *imx= ibuf->x;
+ *imy= ibuf->y;
+ }
+
+ if (G.sima->flag & SI_COORDFLOATS) {
+ *step= 1;
+ *digits= 3;
+ }
+ else {
+ *step= 100;
+ *digits= 2;
+ }
+}
+
+
+/* is used for both read and write... */
+void image_editvertex_buts(uiBlock *block)
+{
+ static float ocent[2];
+ float cent[2]= {0.0, 0.0};
+ int imx= 256, imy= 256;
+ int nactive= 0, step, digits;
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+ MTFace *tf;
+
+ if( is_uv_tface_editing_allowed_silent()==0 ) return;
+
+ image_transform_but_attr(&imx, &imy, &step, &digits);
+
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ if (SIMA_FACEDRAW_CHECK(efa, tf)) {
+
+ if (SIMA_UVSEL_CHECK(efa, tf, 0)) {
+ cent[0]+= tf->uv[0][0];
+ cent[1]+= tf->uv[0][1];
+ nactive++;
+ }
+ if (SIMA_UVSEL_CHECK(efa, tf, 1)) {
+ cent[0]+= tf->uv[1][0];
+ cent[1]+= tf->uv[1][1];
+ nactive++;
+ }
+ if (SIMA_UVSEL_CHECK(efa, tf, 2)) {
+ cent[0]+= tf->uv[2][0];
+ cent[1]+= tf->uv[2][1];
+ nactive++;
+ }
+ if (efa->v4 && SIMA_UVSEL_CHECK(efa, tf, 3)) {
+ cent[0]+= tf->uv[3][0];
+ cent[1]+= tf->uv[3][1];
+ nactive++;
+ }
+ }
+ }
+
+ if(block) { // do the buttons
+ if (nactive) {
+ ocent[0]= cent[0]/nactive;
+ ocent[1]= cent[1]/nactive;
+ if (G.sima->flag & SI_COORDFLOATS) {
+ } else {
+ ocent[0] *= imx;
+ ocent[1] *= imy;
+ }
+
+ //uiBlockBeginAlign(block);
+ if(nactive==1) {
+ uiDefButF(block, NUM, B_TRANS_IMAGE, "Vertex X:", 10, 10, 145, 19, &ocent[0], -10*imx, 10.0*imx, step, digits, "");
+ uiDefButF(block, NUM, B_TRANS_IMAGE, "Vertex Y:", 165, 10, 145, 19, &ocent[1], -10*imy, 10.0*imy, step, digits, "");
+ }
+ else {
+ uiDefButF(block, NUM, B_TRANS_IMAGE, "Median X:", 10, 10, 145, 19, &ocent[0], -10*imx, 10.0*imx, step, digits, "");
+ uiDefButF(block, NUM, B_TRANS_IMAGE, "Median Y:", 165, 10, 145, 19, &ocent[1], -10*imy, 10.0*imy, step, digits, "");
+ }
+ //uiBlockEndAlign(block);
+ }
+ }
+ else { // apply event
+ float delta[2];
+
+ cent[0]= cent[0]/nactive;
+ cent[1]= cent[1]/nactive;
+
+ if (G.sima->flag & SI_COORDFLOATS) {
+ delta[0]= ocent[0]-cent[0];
+ delta[1]= ocent[1]-cent[1];
+ }
+ else {
+ delta[0]= ocent[0]/imx - cent[0];
+ delta[1]= ocent[1]/imy - cent[1];
+ }
+
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ if (SIMA_FACEDRAW_CHECK(efa, tf)) {
+ if (SIMA_UVSEL_CHECK(efa, tf, 0)) {
+ tf->uv[0][0]+= delta[0];
+ tf->uv[0][1]+= delta[1];
+ }
+ if (SIMA_UVSEL_CHECK(efa, tf, 1)) {
+ tf->uv[1][0]+= delta[0];
+ tf->uv[1][1]+= delta[1];
+ }
+ if (SIMA_UVSEL_CHECK(efa, tf, 2)) {
+ tf->uv[2][0]+= delta[0];
+ tf->uv[2][1]+= delta[1];
+ }
+ if (efa->v4 && SIMA_UVSEL_CHECK(efa, tf, 3)) {
+ tf->uv[3][0]+= delta[0];
+ tf->uv[3][1]+= delta[1];
+ }
+ }
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWIMAGE, 0);
+ }
+}
+
+
+/* is used for both read and write... */
+void image_editcursor_buts(uiBlock *block)
+{
+ static float ocent[2];
+ int imx= 256, imy= 256;
+ int step, digits;
+
+ if( is_uv_tface_editing_allowed_silent()==0 ) return;
+
+ image_transform_but_attr(&imx, &imy, &step, &digits);
+
+ if(block) { // do the buttons
+ ocent[0]= G.v2d->cursor[0];
+ ocent[1]= G.v2d->cursor[1];
+ if (G.sima->flag & SI_COORDFLOATS) {
+ } else {
+ ocent[0] *= imx;
+ ocent[1] *= imy;
+ }
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_CURSOR_IMAGE, "Cursor X:", 165, 120, 145, 19, &ocent[0], -10*imx, 10.0*imx, step, digits, "");
+ uiDefButF(block, NUM, B_CURSOR_IMAGE, "Cursor Y:", 165, 100, 145, 19, &ocent[1], -10*imy, 10.0*imy, step, digits, "");
+ uiBlockEndAlign(block);
+ }
+ else { // apply event
+ if (G.sima->flag & SI_COORDFLOATS) {
+ G.v2d->cursor[0]= ocent[0];
+ G.v2d->cursor[1]= ocent[1];
+ }
+ else {
+ G.v2d->cursor[0]= ocent[0]/imx;
+ G.v2d->cursor[1]= ocent[1]/imy;
+ }
+ allqueue(REDRAWIMAGE, 0);
+ }
+}
+
+
+void image_info(Image *ima, ImBuf *ibuf, char *str)
+{
+ int ofs= 0;
+
+ str[0]= 0;
+
+ if(ima==NULL) return;
+ if(ibuf==NULL) {
+ sprintf(str, "Can not get an image");
+ return;
+ }
+
+ if(ima->source==IMA_SRC_MOVIE) {
+ ofs= sprintf(str, "Movie ");
+ if(ima->anim)
+ ofs+= sprintf(str+ofs, "%d frs", IMB_anim_get_duration(ima->anim));
+ }
+ else
+ ofs= sprintf(str, "Image ");
+
+ ofs+= sprintf(str+ofs, ": size %d x %d,", ibuf->x, ibuf->y);
+
+ if(ibuf->rect_float) {
+ if(ibuf->channels!=4) {
+ sprintf(str+ofs, "%d float channel(s)", ibuf->channels);
+ }
+ else if(ibuf->depth==32)
+ strcat(str, " RGBA float");
+ else
+ strcat(str, " RGB float");
+ }
+ else {
+ if(ibuf->depth==32)
+ strcat(str, " RGBA byte");
+ else
+ strcat(str, " RGB byte");
+ }
+ if(ibuf->zbuf || ibuf->zbuf_float)
+ strcat(str, " + Z");
+
+}
+
+static void image_panel_properties(short cntrl) // IMAGE_HANDLER_PROPERTIES
+{
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "image_panel_properties", UI_EMBOSS, UI_HELV, curarea->win);
+ uiPanelControl(UI_PNL_SOLID | UI_PNL_CLOSE | cntrl);
+ uiSetPanelHandler(IMAGE_HANDLER_PROPERTIES); // for close and esc
+ if(uiNewPanel(curarea, block, "Image Properties", "Image", 10, 10, 318, 204)==0)
+ return;
+
+ /* note, it draws no bottom half in facemode, for vertex buttons */
+ uiblock_image_panel(block, &G.sima->image, &G.sima->iuser, B_REDR, B_REDR);
+ image_editvertex_buts(block);
+}
+
+static void image_panel_game_properties(short cntrl) // IMAGE_HANDLER_GAME_PROPERTIES
+{
+ ImBuf *ibuf= BKE_image_get_ibuf(G.sima->image, &G.sima->iuser);
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "image_panel_game_properties", UI_EMBOSS, UI_HELV, curarea->win);
+ uiPanelControl(UI_PNL_SOLID | UI_PNL_CLOSE | cntrl);
+ uiSetPanelHandler(IMAGE_HANDLER_GAME_PROPERTIES); // for close and esc
+ if(uiNewPanel(curarea, block, "Real-time Properties", "Image", 10, 10, 318, 204)==0)
+ return;
+
+ if (ibuf) {
+ char str[128];
+
+ image_info(G.sima->image, ibuf, str);
+ uiDefBut(block, LABEL, B_NOP, str, 10,180,300,19, 0, 0, 0, 0, 0, "");
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, IMA_TWINANIM, B_TWINANIM, "Anim", 10,150,140,19, &G.sima->image->tpageflag, 0, 0, 0, 0, "Toggles use of animated texture");
+ uiDefButS(block, NUM, B_TWINANIM, "Start:", 10,130,140,19, &G.sima->image->twsta, 0.0, 128.0, 0, 0, "Displays the start frame of an animated texture");
+ uiDefButS(block, NUM, B_TWINANIM, "End:", 10,110,140,19, &G.sima->image->twend, 0.0, 128.0, 0, 0, "Displays the end frame of an animated texture");
+ uiDefButS(block, NUM, B_NOP, "Speed", 10,90,140,19, &G.sima->image->animspeed, 1.0, 100.0, 0, 0, "Displays Speed of the animation in frames per second");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, IMA_TILES, B_SIMAGETILE, "Tiles", 160,150,140,19, &G.sima->image->tpageflag, 0, 0, 0, 0, "Toggles use of tilemode for faces (Shift LMB to pick the tile for selected faces)");
+ uiDefButS(block, NUM, B_SIMA_REDR_IMA_3D, "X:", 160,130,70,19, &G.sima->image->xrep, 1.0, 16.0, 0, 0, "Sets the degree of repetition in the X direction");
+ uiDefButS(block, NUM, B_SIMA_REDR_IMA_3D, "Y:", 230,130,70,19, &G.sima->image->yrep, 1.0, 16.0, 0, 0, "Sets the degree of repetition in the Y direction");
+ uiBlockBeginAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, IMA_CLAMP_U, B_SIMA3DVIEWDRAW, "ClampX", 160,100,70,19, &G.sima->image->tpageflag, 0, 0, 0, 0, "Disable texture repeating horizontaly");
+ uiDefButBitS(block, TOG, IMA_CLAMP_V, B_SIMA3DVIEWDRAW, "ClampY", 230,100,70,19, &G.sima->image->tpageflag, 0, 0, 0, 0, "Disable texture repeating vertically");
+ uiBlockEndAlign(block);
+ }
+}
+
+//static void image_panel_transform_properties(short cntrl) // IMAGE_HANDLER_TRANSFORM_PROPERTIES
+//{
+// uiBlock *block;
+//
+// block= uiNewBlock(&curarea->uiblocks, "image_transform_properties", UI_EMBOSS, UI_HELV, curarea->win);
+// uiPanelControl(UI_PNL_SOLID | UI_PNL_CLOSE | cntrl);
+// uiSetPanelHandler(IMAGE_HANDLER_TRANSFORM_PROPERTIES); // for close and esc
+// if(uiNewPanel(curarea, block, "Transform Properties", "Image", 10, 10, 318, 204)==0)
+// return;
+//
+// image_editvertex_buts(block);
+//}
+
+static void image_panel_view_properties(short cntrl) // IMAGE_HANDLER_VIEW_PROPERTIES
+{
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "image_view_properties", UI_EMBOSS, UI_HELV, curarea->win);
+ uiPanelControl(UI_PNL_SOLID | UI_PNL_CLOSE | cntrl);
+ uiSetPanelHandler(IMAGE_HANDLER_VIEW_PROPERTIES); // for close and esc
+ if(uiNewPanel(curarea, block, "View Properties", "Image", 10, 10, 318, 204)==0)
+ return;
+
+
+ uiDefButBitI(block, TOG, SI_DRAW_TILE, B_REDR, "Repeat Image", 10,160,140,19, &G.sima->flag, 0, 0, 0, 0, "Repeat/Tile the image display");
+ uiDefButBitI(block, TOG, SI_COORDFLOATS, B_REDR, "Normalized Coords", 165,160,145,19, &G.sima->flag, 0, 0, 0, 0, "Display coords from 0.0 to 1.0 rather then in pixels");
+
+
+ if (G.sima->image) {
+ uiDefBut(block, LABEL, B_NOP, "Image Display:", 10,140,140,19, 0, 0, 0, 0, 0, "");
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_REDR, "AspX:", 10,120,140,19, &G.sima->image->aspx, 0.1, 5000.0, 100, 0, "X Display Aspect for this image, does not affect renderingm 0 disables.");
+ uiDefButF(block, NUM, B_REDR, "AspY:", 10,100,140,19, &G.sima->image->aspy, 0.1, 5000.0, 100, 0, "X Display Aspect for this image, does not affect rendering 0 disables.");
+ uiBlockEndAlign(block);
+ }
+
+
+ if (EM_texFaceCheck()) {
+ uiDefBut(block, LABEL, B_NOP, "Draw Type:", 10, 20,120,19, 0, 0, 0, 0, 0, "");
+ uiBlockBeginAlign(block);
+ uiDefButC(block, ROW, B_REDR, "Dash", 10, 0,58,19, &G.sima->dt_uv, 0.0, SI_UVDT_DASH, 0, 0, "Dashed Wire UV drawtype");
+ uiDefButC(block, ROW, B_REDR, "Black", 68, 0,58,19, &G.sima->dt_uv, 0.0, SI_UVDT_BLACK, 0, 0, "Black Wire UV drawtype");
+ uiDefButC(block, ROW, B_REDR, "White", 126,0,58,19, &G.sima->dt_uv, 0.0, SI_UVDT_WHITE, 0, 0, "White Wire UV drawtype");
+ uiDefButC(block, ROW, B_REDR, "Outline", 184,0,58,19, &G.sima->dt_uv, 0.0, SI_UVDT_OUTLINE, 0, 0, "Outline Wire UV drawtype");
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOG, SI_SMOOTH_UV, B_REDR, "Smooth", 250,0,60,19, &G.sima->flag, 0, 0, 0, 0, "Display smooth lines in the UV view");
+ }
+ image_editcursor_buts(block);
+}
+
+static void image_panel_paint(short cntrl) // IMAGE_HANDLER_PAINT
+{
+ /* B_SIMABRUSHCHANGE only redraws and eats the mouse messages */
+ /* so that LEFTMOUSE does not 'punch' through the floating panel */
+ /* B_SIMANOTHING */
+ ToolSettings *settings= G.scene->toolsettings;
+ Brush *brush= settings->imapaint.brush;
+ uiBlock *block;
+ ID *id;
+ int yco, xco, butw;
+
+ block= uiNewBlock(&curarea->uiblocks, "image_panel_paint", UI_EMBOSS, UI_HELV, curarea->win);
+ uiPanelControl(UI_PNL_SOLID | UI_PNL_CLOSE | cntrl);
+ uiSetPanelHandler(IMAGE_HANDLER_PAINT); // for close and esc
+ if(uiNewPanel(curarea, block, "Image Paint", "Image", 10, 230, 318, 204)==0)
+ return;
+
+ yco= 160;
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, ROW, B_SIMABRUSHCHANGE, "Draw", 0 ,yco,80,19, &settings->imapaint.tool, 7.0, PAINT_TOOL_DRAW, 0, 0, "Draw brush");
+ uiDefButS(block, ROW, B_SIMABRUSHCHANGE, "Soften", 80 ,yco,80,19, &settings->imapaint.tool, 7.0, PAINT_TOOL_SOFTEN, 0, 0, "Soften brush");
+ uiDefButS(block, ROW, B_SIMABRUSHCHANGE, "Smear", 160,yco,80,19, &settings->imapaint.tool, 7.0, PAINT_TOOL_SMEAR, 0, 0, "Smear brush");
+ uiDefButS(block, ROW, B_SIMABRUSHCHANGE, "Clone", 240,yco,80,19, &settings->imapaint.tool, 7.0, PAINT_TOOL_CLONE, 0, 0, "Clone brush, use RMB to drag source image");
+ uiBlockEndAlign(block);
+ yco -= 30;
+
+ uiBlockSetCol(block, TH_BUT_SETTING2);
+ id= (ID*)settings->imapaint.brush;
+ xco= std_libbuttons(block, 0, yco, 0, NULL, B_SIMABRUSHBROWSE, ID_BR, 0, id, NULL, &(G.sima->menunr), 0, B_SIMABRUSHLOCAL, B_SIMABRUSHDELETE, 0, B_KEEPDATA);
+ uiBlockSetCol(block, TH_AUTO);
+
+ if(brush && !brush->id.lib) {
+ butw= 320-(xco+10);
+
+ uiDefButS(block, MENU, B_SIMANOTHING, "Mix %x0|Add %x1|Subtract %x2|Multiply %x3|Lighten %x4|Darken %x5|Erase Alpha %x6|Add Alpha %x7", xco+10,yco,butw,19, &brush->blend, 0, 0, 0, 0, "Blending method for applying brushes");
+
+ uiDefButBitS(block, TOG|BIT, BRUSH_TORUS, B_SIMABRUSHCHANGE, "Wrap", xco+10,yco-25,butw,19, &brush->flag, 0, 0, 0, 0, "Enables torus wrapping");
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG|BIT, BRUSH_AIRBRUSH, B_SIMABRUSHCHANGE, "Airbrush", xco+10,yco-50,butw,19, &brush->flag, 0, 0, 0, 0, "Keep applying paint effect while holding mouse (spray)");
+ uiDefButF(block, NUM, B_SIMANOTHING, "Rate ", xco+10,yco-70,butw,19, &brush->rate, 0.01, 1.0, 0, 0, "Number of paints per second for Airbrush");
+ uiBlockEndAlign(block);
+
+ yco -= 25;
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, COL, B_VPCOLSLI, "", 0,yco,200,19, brush->rgb, 0, 0, 0, 0, "");
+ uiDefButF(block, NUMSLI, B_SIMANOTHING, "Opacity ", 0,yco-20,180,19, &brush->alpha, 0.0, 1.0, 0, 0, "The amount of pressure on the brush");
+ uiDefButBitS(block, TOG|BIT, BRUSH_ALPHA_PRESSURE, B_SIMANOTHING, "P", 180,yco-20,20,19, &brush->flag, 0, 0, 0, 0, "Enables pressure sensitivity for tablets");
+ uiDefButI(block, NUMSLI, B_SIMANOTHING, "Size ", 0,yco-40,180,19, &brush->size, 1, 200, 0, 0, "The size of the brush");
+ uiDefButBitS(block, TOG|BIT, BRUSH_SIZE_PRESSURE, B_SIMANOTHING, "P", 180,yco-40,20,19, &brush->flag, 0, 0, 0, 0, "Enables pressure sensitivity for tablets");
+ uiDefButF(block, NUMSLI, B_SIMANOTHING, "Falloff ", 0,yco-60,180,19, &brush->innerradius, 0.0, 1.0, 0, 0, "The fall off radius of the brush");
+ uiDefButBitS(block, TOG|BIT, BRUSH_RAD_PRESSURE, B_SIMANOTHING, "P", 180,yco-60,20,19, &brush->flag, 0, 0, 0, 0, "Enables pressure sensitivity for tablets");
+ uiDefButF(block, NUMSLI, B_SIMANOTHING, "Spacing ",0,yco-80,180,19, &brush->spacing, 1.0, 100.0, 0, 0, "Repeating paint on %% of brush diameter");
+ uiDefButBitS(block, TOG|BIT, BRUSH_SPACING_PRESSURE, B_SIMANOTHING, "P", 180,yco-80,20,19, &brush->flag, 0, 0, 0, 0, "Enables pressure sensitivity for tablets");
+ uiBlockEndAlign(block);
+
+ yco -= 110;
+
+ if(settings->imapaint.tool == PAINT_TOOL_CLONE) {
+ id= (ID*)brush->clone.image;
+ uiBlockSetCol(block, TH_BUT_SETTING2);
+ xco= std_libbuttons(block, 0, yco, 0, NULL, B_SIMACLONEBROWSE, ID_IM, 0, id, 0, &G.sima->menunr, 0, 0, B_SIMACLONEDELETE, 0, 0);
+ uiBlockSetCol(block, TH_AUTO);
+ if(id) {
+ butw= 320-(xco+5);
+ uiDefButF(block, NUMSLI, B_SIMABRUSHCHANGE, "B ",xco+5,yco,butw,19, &brush->clone.alpha , 0.0, 1.0, 0, 0, "Opacity of clone image display");
+ }
+ }
+ else {
+ MTex *mtex= brush->mtex[brush->texact];
+
+ uiBlockSetCol(block, TH_BUT_SETTING2);
+ id= (mtex)? (ID*)mtex->tex: NULL;
+ xco= std_libbuttons(block, 0, yco, 0, NULL, B_SIMABTEXBROWSE, ID_TE, 0, id, NULL, &(G.sima->menunr), 0, 0, B_SIMABTEXDELETE, 0, 0);
+ /*uiDefButBitS(block, TOG|BIT, BRUSH_FIXED_TEX, B_SIMABRUSHCHANGE, "Fixed", xco+5,yco,butw,19, &brush->flag, 0, 0, 0, 0, "Keep texture origin in fixed position");*/
+ uiBlockSetCol(block, TH_AUTO);
+ }
+ }
+
+#if 0
+ uiDefButBitS(block, TOG|BIT, IMAGEPAINT_DRAW_TOOL_DRAWING, B_SIMABRUSHCHANGE, "TD", 0,1,50,19, &settings->imapaint.flag.flag, 0, 0, 0, 0, "Enables brush shape while drawing");
+ uiDefButBitS(block, TOG|BIT, IMAGEPAINT_DRAW_TOOL, B_SIMABRUSHCHANGE, "TP", 50,1,50,19, &settings->imapaint.flag.flag, 0, 0, 0, 0, "Enables brush shape while not drawing");
+#endif
+}
+
+static void image_panel_curves_reset(void *cumap_v, void *ibuf_v)
+{
+ CurveMapping *cumap = cumap_v;
+ int a;
+
+ for(a=0; a<CM_TOT; a++)
+ curvemap_reset(cumap->cm+a, &cumap->clipr);
+
+ cumap->black[0]=cumap->black[1]=cumap->black[2]= 0.0f;
+ cumap->white[0]=cumap->white[1]=cumap->white[2]= 1.0f;
+ curvemapping_set_black_white(cumap, NULL, NULL);
+
+ curvemapping_changed(cumap, 0);
+ curvemapping_do_ibuf(cumap, ibuf_v);
+
+ allqueue(REDRAWIMAGE, 0);
+}
+
+
+static void image_panel_curves(short cntrl) // IMAGE_HANDLER_CURVES
+{
+ ImBuf *ibuf;
+ uiBlock *block;
+ uiBut *bt;
+
+ /* and we check for spare */
+ ibuf= imagewindow_get_ibuf(G.sima);
+
+ block= uiNewBlock(&curarea->uiblocks, "image_panel_curves", UI_EMBOSS, UI_HELV, curarea->win);
+ uiPanelControl(UI_PNL_SOLID | UI_PNL_CLOSE | cntrl);
+ uiSetPanelHandler(IMAGE_HANDLER_CURVES); // for close and esc
+ if(uiNewPanel(curarea, block, "Curves", "Image", 10, 450, 318, 204)==0)
+ return;
+
+ if (ibuf) {
+ rctf rect;
+
+ if(G.sima->cumap==NULL)
+ G.sima->cumap= curvemapping_add(4, 0.0f, 0.0f, 1.0f, 1.0f);
+
+ rect.xmin= 110; rect.xmax= 310;
+ rect.ymin= 10; rect.ymax= 200;
+ curvemap_buttons(block, G.sima->cumap, 'c', B_SIMACURVES, B_REDR, &rect);
+
+ bt=uiDefBut(block, BUT, B_SIMARANGE, "Reset", 10, 160, 90, 19, NULL, 0.0f, 0.0f, 0, 0, "Reset Black/White point and curves");
+ uiButSetFunc(bt, image_panel_curves_reset, G.sima->cumap, ibuf);
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_SIMARANGE, "Min R:", 10, 120, 90, 19, G.sima->cumap->black, -1000.0f, 1000.0f, 10, 2, "Black level");
+ uiDefButF(block, NUM, B_SIMARANGE, "Min G:", 10, 100, 90, 19, G.sima->cumap->black+1, -1000.0f, 1000.0f, 10, 2, "Black level");
+ uiDefButF(block, NUM, B_SIMARANGE, "Min B:", 10, 80, 90, 19, G.sima->cumap->black+2, -1000.0f, 1000.0f, 10, 2, "Black level");
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_SIMARANGE, "Max R:", 10, 50, 90, 19, G.sima->cumap->white, -1000.0f, 1000.0f, 10, 2, "White level");
+ uiDefButF(block, NUM, B_SIMARANGE, "Max G:", 10, 30, 90, 19, G.sima->cumap->white+1, -1000.0f, 1000.0f, 10, 2, "White level");
+ uiDefButF(block, NUM, B_SIMARANGE, "Max B:", 10, 10, 90, 19, G.sima->cumap->white+2, -1000.0f, 1000.0f, 10, 2, "White level");
+
+ }
+}
+
+/* are there curves? curves visible? and curves do something? */
+static int image_curves_active(ScrArea *sa)
+{
+ SpaceImage *sima= sa->spacedata.first;
+
+ if(sima->cumap) {
+ if(curvemapping_RGBA_does_something(sima->cumap)) {
+ short a;
+ for(a=0; a<SPACE_MAXHANDLER; a+=2) {
+ if(sima->blockhandler[a] == IMAGE_HANDLER_CURVES)
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+/* 0: disable preview
+ otherwise refresh preview
+*/
+void image_preview_event(int event)
+{
+ int exec= 0;
+
+
+ if(event==0) {
+ G.scene->r.scemode &= ~R_COMP_CROP;
+ exec= 1;
+ }
+ else {
+ if(image_preview_active(curarea, NULL, NULL)) {
+ G.scene->r.scemode |= R_COMP_CROP;
+ exec= 1;
+ }
+ else
+ G.scene->r.scemode &= ~R_COMP_CROP;
+ }
+
+ if(exec && G.scene->nodetree) {
+ /* should work when no node editor in screen..., so we execute right away */
+
+ ntreeCompositTagGenerators(G.scene->nodetree);
+
+ G.afbreek= 0;
+ G.scene->nodetree->timecursor= set_timecursor;
+ G.scene->nodetree->test_break= blender_test_break;
+
+ BIF_store_spare();
+
+ ntreeCompositExecTree(G.scene->nodetree, &G.scene->r, 1); /* 1 is do_previews */
+
+ G.scene->nodetree->timecursor= NULL;
+ G.scene->nodetree->test_break= NULL;
+
+ scrarea_do_windraw(curarea);
+ waitcursor(0);
+
+ allqueue(REDRAWNODE, 1);
+ }
+}
+
+
+/* nothing drawn here, we use it to store values */
+static void preview_cb(struct ScrArea *sa, struct uiBlock *block)
+{
+ rctf dispf;
+ rcti *disprect= &G.scene->r.disprect;
+ int winx= (G.scene->r.size*G.scene->r.xsch)/100;
+ int winy= (G.scene->r.size*G.scene->r.ysch)/100;
+ short mval[2];
+
+ if(G.scene->r.mode & R_BORDER) {
+ winx*= (G.scene->r.border.xmax - G.scene->r.border.xmin);
+ winy*= (G.scene->r.border.ymax - G.scene->r.border.ymin);
+ }
+
+ /* while dragging we need to update the rects, otherwise it doesn't end with correct one */
+
+ BLI_init_rctf(&dispf, 15.0f, (block->maxx - block->minx)-15.0f, 15.0f, (block->maxy - block->miny)-15.0f);
+ ui_graphics_to_window_rct(sa->win, &dispf, disprect);
+
+ /* correction for gla draw */
+ BLI_translate_rcti(disprect, -curarea->winrct.xmin, -curarea->winrct.ymin);
+
+ calc_image_view(G.sima, 'p');
+// printf("winrct %d %d %d %d\n", disprect->xmin, disprect->ymin,disprect->xmax, disprect->ymax);
+ /* map to image space coordinates */
+ mval[0]= disprect->xmin; mval[1]= disprect->ymin;
+ areamouseco_to_ipoco(G.v2d, mval, &dispf.xmin, &dispf.ymin);
+ mval[0]= disprect->xmax; mval[1]= disprect->ymax;
+ areamouseco_to_ipoco(G.v2d, mval, &dispf.xmax, &dispf.ymax);
+
+ /* map to render coordinates */
+ disprect->xmin= dispf.xmin;
+ disprect->xmax= dispf.xmax;
+ disprect->ymin= dispf.ymin;
+ disprect->ymax= dispf.ymax;
+
+ CLAMP(disprect->xmin, 0, winx);
+ CLAMP(disprect->xmax, 0, winx);
+ CLAMP(disprect->ymin, 0, winy);
+ CLAMP(disprect->ymax, 0, winy);
+// printf("drawrct %d %d %d %d\n", disprect->xmin, disprect->ymin,disprect->xmax, disprect->ymax);
+
+}
+
+static int is_preview_allowed(ScrArea *cur)
+{
+ SpaceImage *sima= cur->spacedata.first;
+ ScrArea *sa;
+
+ /* check if another areawindow has preview set */
+ for(sa=G.curscreen->areabase.first; sa; sa= sa->next) {
+ if(sa!=cur && sa->spacetype==SPACE_IMAGE) {
+ if(image_preview_active(sa, NULL, NULL))
+ return 0;
+ }
+ }
+ /* check image type */
+ if(sima->image==NULL || sima->image->type!=IMA_TYPE_COMPOSITE)
+ return 0;
+
+ return 1;
+}
+
+static void image_panel_preview(ScrArea *sa, short cntrl) // IMAGE_HANDLER_PREVIEW
+{
+ uiBlock *block;
+ SpaceImage *sima= sa->spacedata.first;
+ int ofsx, ofsy;
+
+ if(is_preview_allowed(sa)==0) {
+ rem_blockhandler(sa, IMAGE_HANDLER_PREVIEW);
+ G.scene->r.scemode &= ~R_COMP_CROP; /* quite weak */
+ return;
+ }
+
+ block= uiNewBlock(&sa->uiblocks, "image_panel_preview", UI_EMBOSS, UI_HELV, sa->win);
+ uiPanelControl(UI_PNL_SOLID | UI_PNL_CLOSE | UI_PNL_SCALE | cntrl);
+ uiSetPanelHandler(IMAGE_HANDLER_PREVIEW); // for close and esc
+
+ ofsx= -150+(sa->winx/2)/sima->blockscale;
+ ofsy= -100+(sa->winy/2)/sima->blockscale;
+ if(uiNewPanel(sa, block, "Preview", "Image", ofsx, ofsy, 300, 200)==0) return;
+
+ uiBlockSetDrawExtraFunc(block, preview_cb);
+
+}
+
+static void image_blockhandlers(ScrArea *sa)
+{
+ SpaceImage *sima= sa->spacedata.first;
+ short a;
+
+ /* warning; blocks need to be freed each time, handlers dont remove */
+ uiFreeBlocksWin(&sa->uiblocks, sa->win);
+
+ for(a=0; a<SPACE_MAXHANDLER; a+=2) {
+ switch(sima->blockhandler[a]) {
+
+ case IMAGE_HANDLER_PROPERTIES:
+ image_panel_properties(sima->blockhandler[a+1]);
+ break;
+ case IMAGE_HANDLER_GAME_PROPERTIES:
+ image_panel_game_properties(sima->blockhandler[a+1]);
+ break;
+// case IMAGE_HANDLER_TRANSFORM_PROPERTIES:
+// if (EM_texFaceCheck())
+// image_panel_transform_properties(sima->blockhandler[a+1]);
+// break;
+ case IMAGE_HANDLER_VIEW_PROPERTIES:
+ image_panel_view_properties(sima->blockhandler[a+1]);
+ break;
+ case IMAGE_HANDLER_PAINT:
+ image_panel_paint(sima->blockhandler[a+1]);
+ break;
+ case IMAGE_HANDLER_CURVES:
+ image_panel_curves(sima->blockhandler[a+1]);
+ break;
+ case IMAGE_HANDLER_PREVIEW:
+ image_panel_preview(sa, sima->blockhandler[a+1]);
+ break;
+ }
+ /* clear action value for event */
+ sima->blockhandler[a+1]= 0;
+ }
+ uiDrawBlocksPanels(sa, 0);
+}
+
+void imagespace_composite_flipbook(ScrArea *sa)
+{
+ SpaceImage *sima= sa->spacedata.first;
+ ImBuf *ibuf;
+ int cfrao= G.scene->r.cfra;
+ int sfra, efra;
+
+ if(sa->spacetype!=SPACE_IMAGE)
+ return;
+ if(sima->iuser.frames<2)
+ return;
+ if(G.scene->nodetree==NULL)
+ return;
+
+ sfra= sima->iuser.sfra;
+ efra= sima->iuser.sfra + sima->iuser.frames-1;
+ G.scene->nodetree->test_break= blender_test_break;
+
+ for(G.scene->r.cfra=sfra; G.scene->r.cfra<=efra; G.scene->r.cfra++) {
+
+ set_timecursor(CFRA);
+
+ BKE_image_all_free_anim_ibufs(CFRA);
+ ntreeCompositTagAnimated(G.scene->nodetree);
+ ntreeCompositExecTree(G.scene->nodetree, &G.scene->r, G.scene->r.cfra!=cfrao); /* 1 is no previews */
+
+ force_draw(0);
+
+ ibuf= BKE_image_get_ibuf(sima->image, &sima->iuser);
+ /* save memory in flipbooks */
+ if(ibuf)
+ imb_freerectfloatImBuf(ibuf);
+
+ if(blender_test_break())
+ break;
+ }
+ G.scene->nodetree->test_break= NULL;
+ waitcursor(0);
+
+ play_anim(0);
+
+ allqueue(REDRAWNODE, 1);
+ allqueue(REDRAWIMAGE, 1);
+
+ G.scene->r.cfra= cfrao;
+}
+
+static void imagespace_grid(SpaceImage *sima)
+{
+ float gridsize, gridstep= 1.0f/32.0f;
+ float fac, blendfac;
+
+ gridsize= sima->zoom;
+
+ calc_image_view(sima, 'f');
+ myortho2(sima->v2d.cur.xmin, sima->v2d.cur.xmax, sima->v2d.cur.ymin, sima->v2d.cur.ymax);
+
+ BIF_ThemeColorShade(TH_BACK, 20);
+ glRectf(0.0, 0.0, 1.0, 1.0);
+
+ if(gridsize<=0.0f) return;
+
+ if(gridsize<1.0f) {
+ while(gridsize<1.0f) {
+ gridsize*= 4.0;
+ gridstep*= 4.0;
+ }
+ }
+ else {
+ while(gridsize>=4.0f) {
+ gridsize/= 4.0;
+ gridstep/= 4.0;
+ }
+ }
+
+ /* the fine resolution level */
+ blendfac= 0.25*gridsize - floor(0.25*gridsize);
+ CLAMP(blendfac, 0.0, 1.0);
+ BIF_ThemeColorShade(TH_BACK, (int)(20.0*(1.0-blendfac)));
+
+ fac= 0.0f;
+ glBegin(GL_LINES);
+ while(fac<1.0) {
+ glVertex2f(0.0f, fac);
+ glVertex2f(1.0f, fac);
+ glVertex2f(fac, 0.0f);
+ glVertex2f(fac, 1.0f);
+ fac+= gridstep;
+ }
+
+ /* the large resolution level */
+ BIF_ThemeColor(TH_BACK);
+
+ fac= 0.0f;
+ while(fac<1.0) {
+ glVertex2f(0.0f, fac);
+ glVertex2f(1.0f, fac);
+ glVertex2f(fac, 0.0f);
+ glVertex2f(fac, 1.0f);
+ fac+= 4.0*gridstep;
+ }
+ glEnd();
+
+}
+
+static void sima_draw_alpha_backdrop(SpaceImage *sima, float x1, float y1, float xsize, float ysize)
+{
+ GLubyte checker_stipple[32*32/8] =
+ {
+ 255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0, \
+ 255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0, \
+ 255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0, \
+ 255,255,0,0,255,255,0,0,255,255,0,0,255,255,0,0, \
+ 0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255, \
+ 0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255, \
+ 0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255, \
+ 0,0,255,255,0,0,255,255,0,0,255,255,0,0,255,255, \
+ };
+
+ glColor3ub(100, 100, 100);
+ glRectf(x1, y1, x1 + sima->zoom*xsize, y1 + sima->zoom*ysize);
+ glColor3ub(160, 160, 160);
+
+ glEnable(GL_POLYGON_STIPPLE);
+ glPolygonStipple(checker_stipple);
+ glRectf(x1, y1, x1 + sima->zoom*xsize, y1 + sima->zoom*ysize);
+ glEnd();
+ glDisable(GL_POLYGON_STIPPLE);
+ return;
+}
+
+static void sima_draw_alpha_pixels(float x1, float y1, int rectx, int recty, unsigned int *recti)
+{
+
+ /* swap bytes, so alpha is most significant one, then just draw it as luminance int */
+ if(G.order==B_ENDIAN)
+ glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
+ glaDrawPixelsSafe(x1, y1, rectx, recty, rectx, GL_LUMINANCE, GL_UNSIGNED_INT, recti);
+ glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
+}
+
+static void sima_draw_alpha_pixelsf(float x1, float y1, int rectx, int recty, float *rectf)
+{
+ float *trectf= MEM_mallocN(rectx*recty*4, "temp");
+ int a, b;
+
+ for(a= rectx*recty -1, b= 4*a+3; a>=0; a--, b-=4)
+ trectf[a]= rectf[b];
+
+ glaDrawPixelsSafe(x1, y1, rectx, recty, rectx, GL_LUMINANCE, GL_FLOAT, trectf);
+ MEM_freeN(trectf);
+ /* ogl trick below is slower... (on ATI 9600) */
+// glColorMask(1, 0, 0, 0);
+// glaDrawPixelsSafe(x1, y1, rectx, recty, rectx, GL_RGBA, GL_FLOAT, rectf+3);
+// glColorMask(0, 1, 0, 0);
+// glaDrawPixelsSafe(x1, y1, rectx, recty, rectx, GL_RGBA, GL_FLOAT, rectf+2);
+// glColorMask(0, 0, 1, 0);
+// glaDrawPixelsSafe(x1, y1, rectx, recty, rectx, GL_RGBA, GL_FLOAT, rectf+1);
+// glColorMask(1, 1, 1, 1);
+}
+
+static void sima_draw_zbuf_pixels(float x1, float y1, int rectx, int recty, int *recti)
+{
+ if(recti==NULL)
+ return;
+
+ /* zbuffer values are signed, so we need to shift color range */
+ glPixelTransferf(GL_RED_SCALE, 0.5f);
+ glPixelTransferf(GL_GREEN_SCALE, 0.5f);
+ glPixelTransferf(GL_BLUE_SCALE, 0.5f);
+ glPixelTransferf(GL_RED_BIAS, 0.5f);
+ glPixelTransferf(GL_GREEN_BIAS, 0.5f);
+ glPixelTransferf(GL_BLUE_BIAS, 0.5f);
+
+ glaDrawPixelsSafe(x1, y1, rectx, recty, rectx, GL_LUMINANCE, GL_INT, recti);
+
+ glPixelTransferf(GL_RED_SCALE, 1.0f);
+ glPixelTransferf(GL_GREEN_SCALE, 1.0f);
+ glPixelTransferf(GL_BLUE_SCALE, 1.0f);
+ glPixelTransferf(GL_RED_BIAS, 0.0f);
+ glPixelTransferf(GL_GREEN_BIAS, 0.0f);
+ glPixelTransferf(GL_BLUE_BIAS, 0.0f);
+}
+
+static void sima_draw_zbuffloat_pixels(float x1, float y1, int rectx, int recty, float *rect_float)
+{
+ float bias, scale, *rectf, clipend;
+ int a;
+
+ if(rect_float==NULL)
+ return;
+
+ if(G.scene->camera && G.scene->camera->type==OB_CAMERA) {
+ bias= ((Camera *)G.scene->camera->data)->clipsta;
+ clipend= ((Camera *)G.scene->camera->data)->clipend;
+ scale= 1.0f/(clipend-bias);
+ }
+ else {
+ bias= 0.1f;
+ scale= 0.01f;
+ clipend= 100.0f;
+ }
+
+ rectf= MEM_mallocN(rectx*recty*4, "temp");
+ for(a= rectx*recty -1; a>=0; a--) {
+ if(rect_float[a]>clipend)
+ rectf[a]= 0.0f;
+ else if(rect_float[a]<bias)
+ rectf[a]= 1.0f;
+ else {
+ rectf[a]= 1.0f - (rect_float[a]-bias)*scale;
+ rectf[a]*= rectf[a];
+ }
+ }
+ glaDrawPixelsSafe(x1, y1, rectx, recty, rectx, GL_LUMINANCE, GL_FLOAT, rectf);
+
+ MEM_freeN(rectf);
+}
+
+static void imagewindow_draw_renderinfo(ScrArea *sa)
+{
+ SpaceImage *sima= sa->spacedata.first;
+ rcti rect;
+ float colf[3];
+ char *str= sima->showspare?sima->info_spare:sima->info_str;
+
+ if(str==NULL)
+ return;
+
+ rect= sa->winrct;
+ rect.ymin= rect.ymax-RW_HEADERY;
+
+ glaDefine2DArea(&rect);
+
+ /* clear header rect */
+ BIF_GetThemeColor3fv(TH_BACK, colf);
+ glClearColor(colf[0]+0.1f, colf[1]+0.1f, colf[2]+0.1f, 1.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ BIF_ThemeColor(TH_TEXT_HI);
+ glRasterPos2i(12, 5);
+ if(sima->showspare) {
+ BMF_DrawString(G.fonts, "(Previous)");
+ glRasterPos2i(72, 5);
+ }
+ BMF_DrawString(G.fonts, str);
+}
+
+void drawimagespace(ScrArea *sa, void *spacedata)
+{
+ SpaceImage *sima= spacedata;
+ ImBuf *ibuf= NULL;
+ Brush *brush;
+ float col[3];
+ unsigned int *rect;
+ float x1, y1;
+ short sx, sy, dx, dy, show_render= 0, show_viewer= 0;
+ float xuser_asp, yuser_asp;
+ /* If derived data is used then make sure that object
+ * is up-to-date... might not be the case because updates
+ * are normally done in drawview and could get here before
+ * drawing a View3D.
+ */
+ if (G.obedit && OBACT && (sima->flag & SI_DRAWSHADOW)) {
+ object_handle_update(OBACT);
+ }
+
+ BIF_GetThemeColor3fv(TH_BACK, col);
+ glClearColor(col[0], col[1], col[2], 0.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ bwin_clear_viewmat(sa->win); /* clear buttons view */
+ glLoadIdentity();
+
+ if(sima->image && sima->image->source==IMA_SRC_VIEWER) {
+ show_viewer= 1;
+ if(sima->image->type==IMA_TYPE_R_RESULT)
+ show_render= 1;
+ }
+ what_image(sima);
+
+ aspect_sima(sima, &xuser_asp, &yuser_asp);
+
+ if(sima->image) {
+
+ /* UGLY hack? until now iusers worked fine... but for flipbook viewer we need this */
+ if(sima->image->type==IMA_TYPE_COMPOSITE) {
+ ImageUser *iuser= ntree_get_active_iuser(G.scene->nodetree);
+ if(iuser) {
+ BKE_image_user_calc_imanr(iuser, G.scene->r.cfra, 0);
+ G.sima->iuser= *iuser;
+ }
+ }
+ /* and we check for spare */
+ ibuf= imagewindow_get_ibuf(sima);
+ }
+
+ if(ibuf==NULL || (ibuf->rect==NULL && ibuf->rect_float==NULL)) {
+ imagespace_grid(sima);
+ if(show_viewer==0) {
+ draw_uvs_sima();
+ drawcursor_sima(xuser_asp, yuser_asp);
+ }
+ }
+ else {
+ float xim, yim, xoffs=0.0f, yoffs= 0.0f;
+
+ if(image_preview_active(sa, &xim, &yim)) {
+ xoffs= G.scene->r.disprect.xmin;
+ yoffs= G.scene->r.disprect.ymin;
+ glColor3ub(0,0,0);
+ calc_image_view(sima, 'f');
+ myortho2(G.v2d->cur.xmin, G.v2d->cur.xmax, G.v2d->cur.ymin, G.v2d->cur.ymax);
+ glRectf(0.0f, 0.0f, 1.0f, 1.0f);
+ glLoadIdentity();
+ }
+ else {
+ xim= ibuf->x * xuser_asp; yim= ibuf->y * yuser_asp;
+ }
+
+ /* calc location */
+ x1= sima->zoom*xoffs + ((float)sa->winx - sima->zoom*(float)xim)/2.0f;
+ y1= sima->zoom*yoffs + ((float)sa->winy - sima->zoom*(float)yim)/2.0f;
+
+ x1-= sima->zoom*sima->xof;
+ y1-= sima->zoom*sima->yof;
+
+ /* needed for gla draw */
+ if(show_render) {
+ rcti rct= sa->winrct;
+
+ imagewindow_draw_renderinfo(sa); /* calls glaDefine2DArea too */
+
+ rct.ymax-=RW_HEADERY;
+ glaDefine2DArea(&rct);
+ }
+ else glaDefine2DArea(&sa->winrct);
+
+ glPixelZoom(sima->zoom * xuser_asp, sima->zoom * yuser_asp);
+
+ if(sima->flag & SI_EDITTILE) {
+ /* create char buffer from float if needed */
+ if(ibuf->rect_float && ibuf->rect==NULL)
+ IMB_rect_from_float(ibuf);
+
+ glaDrawPixelsSafe(x1, y1, ibuf->x, ibuf->y, ibuf->x, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
+
+ glPixelZoom(1.0, 1.0);
+
+ dx= ibuf->x/sima->image->xrep;
+ dy= ibuf->y/sima->image->yrep;
+ sy= (sima->curtile / sima->image->xrep);
+ sx= sima->curtile - sy*sima->image->xrep;
+
+ sx*= dx;
+ sy*= dy;
+
+ calc_image_view(sima, 'p'); /* pixel */
+ myortho2(G.v2d->cur.xmin, G.v2d->cur.xmax, G.v2d->cur.ymin, G.v2d->cur.ymax);
+
+ cpack(0x0);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glRects(sx, sy, sx+dx-1, sy+dy-1); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ cpack(0xFFFFFF);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glRects(sx+1, sy+1, sx+dx, sy+dy); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ }
+ else if(sima->mode==SI_TEXTURE) {
+
+ if(sima->image->tpageflag & IMA_TILES) {
+
+ /* just leave this a while */
+ if(sima->image->xrep<1) return;
+ if(sima->image->yrep<1) return;
+
+ if(sima->curtile >= sima->image->xrep*sima->image->yrep)
+ sima->curtile = sima->image->xrep*sima->image->yrep - 1;
+
+ dx= ibuf->x/sima->image->xrep;
+ dy= ibuf->y/sima->image->yrep;
+
+ sy= (sima->curtile / sima->image->xrep);
+ sx= sima->curtile - sy*sima->image->xrep;
+
+ sx*= dx;
+ sy*= dy;
+
+ /* create char buffer from float if needed */
+ if(ibuf->rect_float && ibuf->rect==NULL)
+ IMB_rect_from_float(ibuf);
+
+ rect= get_part_from_ibuf(ibuf, sx, sy, sx+dx, sy+dy);
+
+ /* rect= ibuf->rect; */
+ for(sy= 0; sy+dy<=ibuf->y; sy+= dy) {
+ for(sx= 0; sx+dx<=ibuf->x; sx+= dx) {
+ glaDrawPixelsSafe(x1+sx*sima->zoom, y1+sy*sima->zoom, dx, dy, dx, GL_RGBA, GL_UNSIGNED_BYTE, rect);
+ }
+ }
+
+ MEM_freeN(rect);
+ }
+ else {
+ float x1_rep, y1_rep;
+ int x_rep, y_rep;
+ double time_current;
+ short loop_draw_ok = 0;
+
+ if (sima->flag & SI_DRAW_TILE) {
+ loop_draw_ok= 1;
+ }
+
+ time_current = PIL_check_seconds_timer();
+
+ for (x_rep= ((int)G.v2d->cur.xmin)-1; x_rep < G.v2d->cur.xmax; x_rep++) {
+ x1_rep=x1+ ((x_rep* ibuf->x * sima->zoom) *xuser_asp);
+ for (y_rep= ((int)G.v2d->cur.ymin)-1; y_rep < G.v2d->cur.ymax; y_rep++) {
+ y1_rep=y1+ ((y_rep * ibuf->y *sima->zoom) *yuser_asp);
+
+ /* end repeating image loop */
+
+ if(!loop_draw_ok) {
+ y1_rep = y1;
+ x1_rep = x1;
+ }
+
+ /*printf("Drawing %d %d zoom:%.6f (%.6f %.6f), (%.6f %.6f)\n", x_rep, y_rep, sima->zoom, G.v2d->cur.xmin, G.v2d->cur.ymin, G.v2d->cur.xmax, G.v2d->cur.ymax);*/
+
+ /* this part is generic image display */
+ if(sima->flag & SI_SHOW_ALPHA) {
+ if(ibuf->rect)
+ sima_draw_alpha_pixels(x1_rep, y1_rep, ibuf->x, ibuf->y, ibuf->rect);
+ else if(ibuf->rect_float && ibuf->channels==4)
+ sima_draw_alpha_pixelsf(x1_rep, y1_rep, ibuf->x, ibuf->y, ibuf->rect_float);
+ }
+ else if(sima->flag & SI_SHOW_ZBUF && ((ibuf->zbuf || ibuf->zbuf_float || (ibuf->channels==1)) == 0)) {
+ if(ibuf->zbuf)
+ sima_draw_zbuf_pixels(x1_rep, y1_rep, ibuf->x, ibuf->y, ibuf->zbuf);
+ else if(ibuf->zbuf_float)
+ sima_draw_zbuffloat_pixels(x1_rep, y1_rep, ibuf->x, ibuf->y, ibuf->zbuf_float);
+ else if(ibuf->channels==1)
+ sima_draw_zbuffloat_pixels(x1_rep, y1_rep, ibuf->x, ibuf->y, ibuf->rect_float);
+ }
+ else {
+ if(sima->flag & SI_USE_ALPHA) {
+ sima_draw_alpha_backdrop(sima, x1_rep, y1_rep, (float)ibuf->x, (float)ibuf->y);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ }
+
+ /* detect if we need to redo the curve map.
+ ibuf->rect is zero for compositor and render results after change
+ convert to 32 bits always... drawing float rects isnt supported well (atis)
+
+ NOTE: if float buffer changes, we have to manually remove the rect
+ */
+
+ if(ibuf->rect_float) {
+ if(ibuf->rect==NULL) {
+ if(image_curves_active(sa))
+ curvemapping_do_ibuf(G.sima->cumap, ibuf);
+ else
+ IMB_rect_from_float(ibuf);
+ }
+ }
+
+ if(ibuf->rect)
+ glaDrawPixelsSafe(x1_rep, y1_rep, ibuf->x, ibuf->y, ibuf->x, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
+ // else
+ // glaDrawPixelsSafe(x1_rep, y1_rep, ibuf->x, ibuf->y, ibuf->x, GL_RGBA, GL_FLOAT, ibuf->rect_float);
+
+ if(sima->flag & SI_USE_ALPHA)
+ glDisable(GL_BLEND);
+ }
+
+ /* only draw once */
+ if(!loop_draw_ok) {
+ break; /* only draw once */
+ } else if ((PIL_check_seconds_timer() - time_current) > 0.25) {
+ loop_draw_ok = 0;
+ break;
+ }
+
+ /* tile draw loop */
+ }
+ /* only draw once */
+ if(!loop_draw_ok) break;
+ }
+ /* tile draw loop */
+
+ }
+
+ brush= G.scene->toolsettings->imapaint.brush;
+ if(brush && (G.scene->toolsettings->imapaint.tool == PAINT_TOOL_CLONE)) {
+ int w, h;
+ unsigned char *clonerect;
+
+ /* this is not very efficient, but glDrawPixels doesn't allow
+ drawing with alpha */
+ clonerect= alloc_alpha_clone_image(&w, &h);
+
+ if(clonerect) {
+ int offx, offy;
+ offx = sima->zoom*ibuf->x * + brush->clone.offset[0];
+ offy = sima->zoom*ibuf->y * + brush->clone.offset[1];
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glaDrawPixelsSafe(x1 + offx, y1 + offy, w, h, w, GL_RGBA, GL_UNSIGNED_BYTE, clonerect);
+ glDisable(GL_BLEND);
+
+ MEM_freeN(clonerect);
+ }
+ }
+
+ glPixelZoom(1.0, 1.0);
+
+ if(show_viewer==0) {
+ draw_uvs_sima();
+ drawcursor_sima(xuser_asp, yuser_asp);
+ }
+ }
+
+ glPixelZoom(1.0, 1.0);
+
+ calc_image_view(sima, 'f'); /* float */
+ }
+
+ draw_image_transform(ibuf, xuser_asp, yuser_asp);
+
+ mywinset(sa->win); /* restore scissor after gla call... */
+ myortho2(-0.375, sa->winx-0.375, -0.375, sa->winy-0.375);
+
+ if(G.rendering==0) {
+ draw_image_view_tool();
+ draw_image_view_icon();
+ }
+ draw_area_emboss(sa);
+
+ /* it is important to end a view in a transform compatible with buttons */
+ bwin_scalematrix(sa->win, sima->blockscale, sima->blockscale, sima->blockscale);
+ if(!(G.rendering && show_render))
+ image_blockhandlers(sa);
+
+ sa->win_swap= WIN_BACK_OK;
+}
+
+static void image_zoom_power_of_two(void)
+{
+ /* Make zoom a power of 2 */
+
+ G.sima->zoom = 1 / G.sima->zoom;
+ G.sima->zoom = log(G.sima->zoom) / log(2);
+ G.sima->zoom = ceil(G.sima->zoom);
+ G.sima->zoom = pow(2, G.sima->zoom);
+ G.sima->zoom = 1 / G.sima->zoom;
+}
+
+static void image_zoom_set_factor(float zoomfac)
+{
+ SpaceImage *sima= curarea->spacedata.first;
+ int width, height;
+
+ if (zoomfac <= 0.0f)
+ return;
+
+ sima->zoom *= zoomfac;
+
+ if (sima->zoom > 0.1f && sima->zoom < 4.0f)
+ return;
+
+ /* check zoom limits */
+
+ calc_image_view(G.sima, 'f'); /* was 'p' are there any cases where this should be 'p'?*/
+ width= 256;
+ height= 256;
+ if (sima->image) {
+ ImBuf *ibuf= imagewindow_get_ibuf(sima);
+
+ if (ibuf) {
+ float xim, yim;
+ /* I know a bit weak... but preview uses not actual image size */
+ if(image_preview_active(curarea, &xim, &yim)) {
+ width= (int) xim;
+ height= (int) yim;
+ }
+ else {
+ width= ibuf->x;
+ height= ibuf->y;
+ }
+ }
+ }
+ width *= sima->zoom;
+ height *= sima->zoom;
+
+ if ((width < 4) && (height < 4))
+ sima->zoom /= zoomfac;
+ else if((curarea->winrct.xmax - curarea->winrct.xmin) <= sima->zoom)
+ sima->zoom /= zoomfac;
+ else if((curarea->winrct.ymax - curarea->winrct.ymin) <= sima->zoom)
+ sima->zoom /= zoomfac;
+}
+
+void image_viewmove(int mode)
+{
+ short mval[2], mvalo[2], zoom0;
+ int oldcursor;
+ Window *win;
+
+ getmouseco_sc(mvalo);
+ zoom0= G.sima->zoom;
+
+ oldcursor=get_cursor();
+ win=winlay_get_active_window();
+
+ SetBlenderCursor(BC_NSEW_SCROLLCURSOR);
+
+ while(get_mbut()&(L_MOUSE|M_MOUSE)) {
+
+ getmouseco_sc(mval);
+
+ if(mvalo[0]!=mval[0] || mvalo[1]!=mval[1]) {
+
+ if(mode==0) {
+ G.sima->xof += (mvalo[0]-mval[0])/G.sima->zoom;
+ G.sima->yof += (mvalo[1]-mval[1])/G.sima->zoom;
+ }
+ else if (mode==1) {
+ float factor;
+
+ factor= 1.0+(float)(mvalo[0]-mval[0]+mvalo[1]-mval[1])/300.0;
+ image_zoom_set_factor(factor);
+ }
+
+ mvalo[0]= mval[0];
+ mvalo[1]= mval[1];
+
+ scrarea_do_windraw(curarea);
+ screen_swapbuffers();
+ }
+ else BIF_wait_for_statechange();
+ }
+ window_set_cursor(win, oldcursor);
+
+ if(image_preview_active(curarea, NULL, NULL)) {
+ /* recalculates new preview rect */
+ scrarea_do_windraw(curarea);
+ image_preview_event(2);
+ }
+}
+
+void image_viewzoom(unsigned short event, int invert)
+{
+ SpaceImage *sima= curarea->spacedata.first;
+
+ if(event==WHEELDOWNMOUSE || event==PADMINUS)
+ image_zoom_set_factor((U.uiflag & USER_WHEELZOOMDIR)? 1.25: 0.8);
+ else if(event==WHEELUPMOUSE || event==PADPLUSKEY)
+ image_zoom_set_factor((U.uiflag & USER_WHEELZOOMDIR)? 0.8: 1.25);
+ else if(event==PAD1)
+ sima->zoom= 1.0;
+ else if(event==PAD2)
+ sima->zoom= (invert)? 2.0: 0.5;
+ else if(event==PAD4)
+ sima->zoom= (invert)? 4.0: 0.25;
+ else if(event==PAD8)
+ sima->zoom= (invert)? 8.0: 0.125;
+
+ /* ensure pixel exact locations for draw */
+ sima->xof= (int)sima->xof;
+ sima->yof= (int)sima->yof;
+
+ if(image_preview_active(curarea, NULL, NULL)) {
+ /* recalculates new preview rect */
+ scrarea_do_windraw(curarea);
+ image_preview_event(2);
+ }
+}
+
+/**
+ * Updates the fields of the View2D member of the SpaceImage struct.
+ * Default behavior is to reset the position of the image and set the zoom to 1
+ * If the image will not fit within the window rectangle, the zoom is adjusted
+ *
+ * @return void
+ *
+ */
+void image_home(void)
+{
+ ImBuf *ibuf;
+ int width, height, imgwidth, imgheight;
+ float zoomX, zoomY;
+
+ if (curarea->spacetype != SPACE_IMAGE) return;
+ ibuf= imagewindow_get_ibuf(G.sima);
+
+ if (ibuf == NULL) {
+ imgwidth = 256;
+ imgheight = 256;
+ }
+ else {
+ imgwidth = ibuf->x;
+ imgheight = ibuf->y;
+ }
+
+ /* Check if the image will fit in the image with zoom==1 */
+ width = curarea->winx;
+ height = curarea->winy;
+ if (((imgwidth >= width) || (imgheight >= height)) &&
+ ((width > 0) && (height > 0))) {
+ /* Find the zoom value that will fit the image in the image space */
+ zoomX = ((float)width) / ((float)imgwidth);
+ zoomY = ((float)height) / ((float)imgheight);
+ G.sima->zoom= MIN2(zoomX, zoomY);
+
+ image_zoom_power_of_two();
+ }
+ else {
+ G.sima->zoom= 1.0f;
+ }
+
+ G.sima->xof= G.sima->yof= 0.0f;
+
+ calc_image_view(G.sima, 'f'); /* was 'p' are there any cases where this should be 'p'?*/
+ /*calc_arearcts(curarea);*/
+ scrarea_queue_winredraw(curarea);
+ scrarea_queue_winredraw(curarea);
+}
+
+void image_viewcenter(void)
+{
+ ImBuf *ibuf= BKE_image_get_ibuf(G.sima->image, &G.sima->iuser);
+ float size, min[2], max[2], d[2], xim=256.0f, yim=256.0f;
+
+ if( is_uv_tface_editing_allowed()==0 ) return;
+
+ if (!minmax_tface_uv(min, max)) return;
+
+ if(ibuf) {
+ xim= ibuf->x;
+ yim= ibuf->y;
+ }
+
+ G.sima->xof= (int) (((min[0] + max[0])*0.5f - 0.5f)*xim);
+ G.sima->yof= (int) (((min[1] + max[1])*0.5f - 0.5f)*yim);
+
+ d[0] = max[0] - min[0];
+ d[1] = max[1] - min[1];
+ size= 0.5*MAX2(d[0], d[1])*MAX2(xim, yim)/256.0f;
+
+ if(size<=0.01) size= 0.01;
+
+ G.sima->zoom= 0.7/size;
+
+ calc_image_view(G.sima, 'f'); /* was 'p' are there any cases where 'p' is still needed? */
+
+ scrarea_queue_winredraw(curarea);
+}
+
+
+/* *********************** render callbacks ***************** */
+
+/* set on initialize render, only one render output to imagewindow can exist, so the global isnt dangerous yet :) */
+static ScrArea *image_area= NULL;
+
+/* can get as well the full picture, as the parts while rendering */
+static void imagewindow_progress(ScrArea *sa, RenderResult *rr, volatile rcti *renrect)
+{
+ SpaceImage *sima= sa->spacedata.first;
+ float x1, y1, *rectf= NULL;
+ unsigned int *rect32= NULL;
+ int ymin, ymax, xmin, xmax;
+
+ /* if renrect argument, we only display scanlines */
+ if(renrect) {
+ /* if ymax==recty, rendering of layer is ready, we should not draw, other things happen... */
+ if(rr->renlay==NULL || renrect->ymax>=rr->recty)
+ return;
+
+ /* xmin here is first subrect x coord, xmax defines subrect width */
+ xmin = renrect->xmin;
+ xmax = renrect->xmax - xmin;
+ if (xmax<2) return;
+
+ ymin= renrect->ymin;
+ ymax= renrect->ymax - ymin;
+ if(ymax<2)
+ return;
+ renrect->ymin= renrect->ymax;
+ }
+ else {
+ xmin = ymin = 0;
+ xmax = rr->rectx - 2*rr->crop;
+ ymax = rr->recty - 2*rr->crop;
+ }
+
+ /* image window cruft */
+
+ /* find current float rect for display, first case is after composit... still weak */
+ if(rr->rectf)
+ rectf= rr->rectf;
+ else {
+ if(rr->rect32)
+ rect32= (unsigned int *)rr->rect32;
+ else {
+ if(rr->renlay==NULL || rr->renlay->rectf==NULL) return;
+ rectf= rr->renlay->rectf;
+ }
+ }
+ if(rectf) {
+ /* if scanline updates... */
+ rectf+= 4*(rr->rectx*ymin + xmin);
+
+ /* when rendering more pixels than needed, we crop away cruft */
+ if(rr->crop)
+ rectf+= 4*(rr->crop*rr->rectx + rr->crop);
+ }
+
+ /* tilerect defines drawing offset from (0,0) */
+ /* however, tilerect (xmin, ymin) is first pixel */
+ x1 = sima->centx + (rr->tilerect.xmin + rr->crop + xmin)*sima->zoom;
+ y1 = sima->centy + (rr->tilerect.ymin + rr->crop + ymin)*sima->zoom;
+
+ /* needed for gla draw */
+ { rcti rct= sa->winrct; rct.ymax-= RW_HEADERY; glaDefine2DArea(&rct);}
+
+ glPixelZoom(sima->zoom, sima->zoom);
+
+ if(rect32)
+ glaDrawPixelsSafe(x1, y1, xmax, ymax, rr->rectx, GL_RGBA, GL_UNSIGNED_BYTE, rect32);
+ else
+ glaDrawPixelsSafe_to32(x1, y1, xmax, ymax, rr->rectx, rectf);
+
+ glPixelZoom(1.0, 1.0);
+
+}
+
+
+/* in render window; display a couple of scanlines of rendered image */
+/* NOTE: called while render, so no malloc allowed! */
+static void imagewindow_progress_display_cb(RenderResult *rr, volatile rcti *rect)
+{
+
+ if (image_area) {
+
+ imagewindow_progress(image_area, rr, rect);
+
+ /* no screen_swapbuffers, prevent any other window to draw */
+ myswapbuffers();
+ }
+}
+
+/* unused, init_display_cb is called on each render */
+static void imagewindow_clear_display_cb(RenderResult *rr)
+{
+ if (image_area) {
+ }
+}
+
+/* returns biggest area that is not uv/image editor. Note that it uses buttons */
+/* window as the last possible alternative. */
+static ScrArea *biggest_non_image_area(void)
+{
+ ScrArea *sa, *big= NULL;
+ int size, maxsize= 0, bwmaxsize= 0;
+ short foundwin= 0;
+
+ for(sa= G.curscreen->areabase.first; sa; sa= sa->next) {
+ if(sa->winx > 10 && sa->winy > 10) {
+ size= sa->winx*sa->winy;
+ if(sa->spacetype == SPACE_BUTS) {
+ if(foundwin == 0 && size > bwmaxsize) {
+ bwmaxsize= size;
+ big= sa;
+ }
+ }
+ else if(sa->spacetype != SPACE_IMAGE && size > maxsize) {
+ maxsize= size;
+ big= sa;
+ foundwin= 1;
+ }
+ }
+ }
+
+ return big;
+}
+
+static ScrArea *biggest_area(void)
+{
+ ScrArea *sa, *big= NULL;
+ int size, maxsize= 0;
+
+ for(sa= G.curscreen->areabase.first; sa; sa= sa->next) {
+ size= sa->winx*sa->winy;
+ if(size > maxsize) {
+ maxsize= size;
+ big= sa;
+ }
+ }
+ return big;
+}
+
+
+/* if R_DISPLAYIMAGE
+ use Image Window showing Render Result
+ else: turn largest non-image area into Image Window (not to frustrate texture or composite usage)
+ else: then we use Image Window anyway...
+ if R_DISPSCREEN
+ make a new temp fullscreen area with Image Window
+*/
+
+static ScrArea *find_area_showing_r_result(void)
+{
+ ScrArea *sa;
+ SpaceImage *sima;
+
+ /* find an imagewindow showing render result */
+ for(sa=G.curscreen->areabase.first; sa; sa= sa->next) {
+ if(sa->spacetype==SPACE_IMAGE) {
+ sima= sa->spacedata.first;
+ if(sima->image && sima->image->type==IMA_TYPE_R_RESULT)
+ break;
+ }
+ }
+ return sa;
+}
+
+static ScrArea *imagewindow_set_render_display(void)
+{
+ ScrArea *sa;
+ SpaceImage *sima;
+
+ sa= find_area_showing_r_result();
+
+ if(sa==NULL) {
+ /* find largest open non-image area */
+ sa= biggest_non_image_area();
+ if(sa) {
+ newspace(sa, SPACE_IMAGE);
+ sima= sa->spacedata.first;
+
+ /* makes ESC go back to prev space */
+ sima->flag |= SI_PREVSPACE;
+ }
+ else {
+ /* use any area of decent size */
+ sa= biggest_area();
+ if(sa->spacetype!=SPACE_IMAGE) {
+ newspace(sa, SPACE_IMAGE);
+ sima= sa->spacedata.first;
+
+ /* makes ESC go back to prev space */
+ sima->flag |= SI_PREVSPACE;
+ }
+ }
+ }
+
+ sima= sa->spacedata.first;
+
+ /* get the correct image, and scale it */
+ sima->image= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
+
+ if(G.displaymode==R_DISPLAYSCREEN) {
+ if(sa->full==0) {
+ sima->flag |= SI_FULLWINDOW;
+ /* fullscreen works with lousy curarea */
+ curarea= sa;
+ area_fullscreen();
+ sa= curarea;
+ }
+ }
+
+ return sa;
+}
+
+static void imagewindow_init_display_cb(RenderResult *rr)
+{
+
+ image_area= imagewindow_set_render_display();
+
+ if(image_area) {
+ SpaceImage *sima= image_area->spacedata.first;
+
+ areawinset(image_area->win);
+
+ if(sima->info_str==NULL)
+ sima->info_str= MEM_callocN(RW_MAXTEXT, "info str imagewin");
+
+ /* calc location using original size (tiles don't tell) */
+ sima->centx= (image_area->winx - sima->zoom*(float)rr->rectx)/2.0f;
+ sima->centy= (image_area->winy - sima->zoom*(float)rr->recty)/2.0f;
+
+ sima->centx-= sima->zoom*sima->xof;
+ sima->centy-= sima->zoom*sima->yof;
+
+ drawimagespace(image_area, sima);
+ if(image_area->headertype) scrarea_do_headdraw(image_area);
+ screen_swapbuffers();
+
+ allqueue(REDRAWIMAGE, 0); /* redraw in end */
+ }
+}
+
+/* coming from BIF_toggle_render_display() */
+void imagewindow_toggle_render(void)
+{
+ ScrArea *sa;
+
+ /* check if any imagewindow is showing temporal render output */
+ for(sa=G.curscreen->areabase.first; sa; sa= sa->next) {
+ if(sa->spacetype==SPACE_IMAGE) {
+ SpaceImage *sima= sa->spacedata.first;
+
+ if(sima->image && sima->image->type==IMA_TYPE_R_RESULT)
+ if(sima->flag & (SI_PREVSPACE|SI_FULLWINDOW))
+ break;
+ }
+ }
+ if(sa) {
+ addqueue(sa->win, ESCKEY, 1); /* also returns from fullscreen */
+ }
+ else {
+ sa= imagewindow_set_render_display();
+ scrarea_queue_headredraw(sa);
+ scrarea_queue_winredraw(sa);
+ }
+}
+
+/* NOTE: called while render, so no malloc allowed! */
+static void imagewindow_renderinfo_cb(RenderStats *rs)
+{
+
+ if(image_area) {
+ SpaceImage *sima= image_area->spacedata.first;
+
+ if(rs)
+ make_renderinfo_string(rs, sima->info_str);
+
+ imagewindow_draw_renderinfo(image_area);
+
+ /* no screen_swapbuffers, prevent any other window to draw */
+ myswapbuffers();
+ }
+}
+
+void imagewindow_render_callbacks(Render *re)
+{
+ RE_display_init_cb(re, imagewindow_init_display_cb);
+ RE_display_draw_cb(re, imagewindow_progress_display_cb);
+ RE_display_clear_cb(re, imagewindow_clear_display_cb);
+ RE_stats_draw_cb(re, imagewindow_renderinfo_cb);
+}
+
+void imagewin_store_spare(void)
+{
+ ScrArea *sa= find_area_showing_r_result();
+
+ if(sa) {
+ ImBuf *ibuf;
+ SpaceImage *sima= sa->spacedata.first;
+
+ if(sima->spare==NULL)
+ return;
+
+ /* only store when it does not show spare */
+ if(sima->showspare==0)
+ return;
+ sima->showspare= 0;
+
+ /* free spare */
+ IMB_freeImBuf(sima->spare);
+
+ /* make a copy of render result */
+ ibuf= BKE_image_get_ibuf(sima->image, &sima->iuser);
+ sima->spare= IMB_dupImBuf(ibuf);
+
+ if(sima->info_str)
+ BLI_strncpy(sima->info_spare, sima->info_str, RW_MAXTEXT);
+
+ }
+}
+
+/* context: in current image window? */
+void imagewindow_swap_render_rects(void)
+{
+ ScrArea *sa= find_area_showing_r_result();
+
+ if(sa) {
+ SpaceImage *sima= sa->spacedata.first;
+ ImBuf *ibuf= BKE_image_get_ibuf(sima->image, &sima->iuser);
+ if(ibuf) {
+
+ sima->showspare ^= 1;
+
+ if(sima->spare==NULL)
+ sima->spare= IMB_allocImBuf(ibuf->x, ibuf->y, 32, 0, 0);
+ if(sima->info_spare==NULL)
+ sima->info_spare= MEM_callocN(RW_MAXTEXT, "info str imagewin");
+
+ allqueue(REDRAWIMAGE, 0);
+ }
+ }
+}
+
diff --git a/source/blender/src/drawimasel.c b/source/blender/src/drawimasel.c
new file mode 100644
index 00000000000..257c5831813
--- /dev/null
+++ b/source/blender/src/drawimasel.c
@@ -0,0 +1,734 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef _WIN32
+#pragma warning (once : 4761)
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_ID.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_object_types.h"
+#include "DNA_material_types.h"
+
+#include "BLI_blenlib.h"
+#ifdef WIN32
+#include "BLI_winstuff.h"
+#endif
+#include "BLI_storage_types.h"
+
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_icons.h"
+#include "BKE_utildefines.h"
+#include "BIF_filelist.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+#include "BIF_mywindow.h"
+#include "BIF_screen.h"
+#include "BIF_resources.h"
+#include "BIF_language.h"
+
+#include "BIF_interface.h"
+#include "BIF_interface_icons.h"
+#include "BIF_previewrender.h"
+#include "BIF_fsmenu.h"
+#include "BIF_space.h"
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+#include "BSE_drawimasel.h"
+#include "BSE_drawipo.h" /* for v2d functions */
+#include "BSE_view.h"
+
+#include "BLO_readfile.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "PIL_time.h"
+
+#include "blendef.h"
+#include "mydevice.h"
+
+#include "interface.h" /* urm... for rasterpos_safe, roundbox */
+
+#define BUTTONWIDTH 20
+#define BOOKMARKWIDTH_MAX 240
+
+void calc_imasel_rcts(SpaceImaSel *simasel, int winx, int winy)
+{
+ int width = (int)16.0f*simasel->aspect;
+ int numtiles;
+ int numfiles = 0;
+ int tilewidth = simasel->prv_w + TILE_BORDER_X*4;
+ int tileheight = simasel->prv_h + TILE_BORDER_Y*4 + U.fontsize;
+
+ // complete area of the space
+ simasel->v2d.mask.xmin= simasel->v2d.mask.ymin = 0;
+ simasel->v2d.mask.xmax= winx;
+ simasel->v2d.mask.ymax= winy;
+
+ // vertical scroll bar
+ simasel->v2d.vert= simasel->v2d.mask;
+ simasel->v2d.vert.xmax -= TILE_BORDER_X + 2;
+ simasel->v2d.vert.xmin= simasel->v2d.vert.xmax- width - TILE_BORDER_X - 2;
+ simasel->v2d.vert.ymax -= IMASEL_BUTTONS_HEIGHT + TILE_BORDER_Y + 2;
+ simasel->v2d.vert.ymin += TILE_BORDER_Y + 2;
+ // simasel->v2d.mask.xmax= simasel->v2d.vert.xmin;
+
+ if (simasel->flag & FILE_BOOKMARKS) {
+ int bmwidth = (simasel->v2d.vert.xmin - simasel->v2d.mask.xmin)/4.0f;
+ if (bmwidth > BOOKMARKWIDTH_MAX) bmwidth = BOOKMARKWIDTH_MAX;
+
+ simasel->bookmarkrect.xmin = simasel->v2d.mask.xmin + TILE_BORDER_X;
+ simasel->bookmarkrect.xmax = simasel->v2d.mask.xmin + bmwidth - TILE_BORDER_X;
+ simasel->bookmarkrect.ymax = simasel->v2d.mask.ymax - IMASEL_BUTTONS_HEIGHT - TILE_BORDER_Y;
+ simasel->bookmarkrect.ymin = simasel->v2d.mask.ymin + TILE_BORDER_Y;
+
+ simasel->viewrect.xmin = simasel->bookmarkrect.xmax + TILE_BORDER_X;
+ simasel->viewrect.xmax = simasel->v2d.vert.xmin - TILE_BORDER_X;
+ simasel->viewrect.ymax = simasel->v2d.mask.ymax - IMASEL_BUTTONS_HEIGHT - TILE_BORDER_Y;
+ simasel->viewrect.ymin = simasel->v2d.mask.ymin + TILE_BORDER_Y;
+ } else {
+ simasel->viewrect.xmin = simasel->v2d.mask.xmin + TILE_BORDER_X;
+ simasel->viewrect.xmax = simasel->v2d.vert.xmin - TILE_BORDER_X;
+ simasel->viewrect.ymax = simasel->v2d.mask.ymax - IMASEL_BUTTONS_HEIGHT - TILE_BORDER_Y;
+ simasel->viewrect.ymin = simasel->v2d.mask.ymin + TILE_BORDER_Y;
+ }
+
+ simasel->numtilesx = (simasel->viewrect.xmax - simasel->viewrect.xmin) / tilewidth;
+ simasel->numtilesy = (simasel->viewrect.ymax - simasel->viewrect.ymin) / tileheight;
+ numtiles = simasel->numtilesx*simasel->numtilesy;
+
+ if (simasel->files) {
+ numfiles = BIF_filelist_numfiles(simasel->files);
+ }
+ if (numtiles > numfiles) numtiles = numfiles;
+
+ simasel->scrollarea = ((float)simasel->v2d.vert.ymax - (float)simasel->v2d.vert.ymin);
+ if (numtiles < numfiles) {
+ simasel->scrollheight = ((float)numtiles / (float)numfiles)*simasel->scrollarea;
+ simasel->scrollarea -= simasel->scrollheight;
+ } else {
+ simasel->scrollheight = simasel->scrollarea;
+ }
+ if (simasel->scrollarea < 0) simasel->scrollarea = 0;
+}
+
+void draw_imasel_scroll(SpaceImaSel *simasel)
+{
+ rcti scrollbar;
+ rcti scrollhandle;
+
+ scrollbar.xmin= simasel->v2d.cur.xmin + simasel->v2d.vert.xmin;
+ scrollbar.ymin = simasel->v2d.cur.ymin + simasel->v2d.vert.ymin;
+ scrollbar.xmax= simasel->v2d.cur.xmin + simasel->v2d.vert.xmax;
+ scrollbar.ymax = simasel->v2d.cur.ymin + simasel->v2d.vert.ymax;
+
+ scrollhandle.xmin= scrollbar.xmin;
+ scrollhandle.ymin = scrollbar.ymax - simasel->scrollpos -1;
+ scrollhandle.xmax= scrollbar.xmax-1;
+ scrollhandle.ymax = scrollbar.ymax - simasel->scrollpos - simasel->scrollheight;
+
+ BIF_ThemeColor(TH_SHADE1);
+ glRecti(scrollbar.xmin, scrollbar.ymin, scrollbar.xmax, scrollbar.ymax);
+ uiEmboss(scrollbar.xmin-2, scrollbar.ymin-2, scrollbar.xmax+2, scrollbar.ymax+2, 1);
+
+ BIF_ThemeColor(TH_SHADE2);
+ glRecti(scrollhandle.xmin, scrollhandle.ymin, scrollhandle.xmax, scrollhandle.ymax);
+
+ uiEmboss(scrollhandle.xmin, scrollhandle.ymin, scrollhandle.xmax, scrollhandle.ymax, 1);
+}
+
+static void draw_tile(SpaceImaSel *simasel, short sx, short sy, int colorid)
+{
+ /* TODO: BIF_ThemeColor seems to need this to show the color, not sure why? - elubie */
+ glEnable(GL_BLEND);
+ glColor4ub(0, 0, 0, 100);
+ glDisable(GL_BLEND);
+
+ BIF_ThemeColor4(colorid);
+ uiSetRoundBox(15);
+ uiRoundBox(sx+TILE_BORDER_X, sy - simasel->prv_h - TILE_BORDER_Y*3 - U.fontsize, sx + simasel->prv_w + TILE_BORDER_X*3, sy, 6);
+}
+
+static float shorten_string(SpaceImaSel *simasel, char* string, float w)
+{
+ short shortened = 0;
+ float sw = 0;
+
+ sw = BIF_GetStringWidth(simasel->curfont, string, 0);
+ while (sw>w) {
+ int slen = strlen(string);
+ string[slen-1] = '\0';
+ sw = BIF_GetStringWidth(simasel->curfont, string, 0);
+ shortened = 1;
+ }
+ if (shortened) {
+ int slen = strlen(string);
+ if (slen > 3) {
+ BLI_strncpy(string+slen-3, "...", 4);
+ }
+ }
+ return sw;
+}
+
+static void draw_file(SpaceImaSel *simasel, short sx, short sy, struct direntry *file)
+{
+ short soffs;
+ char fname[FILE_MAXFILE];
+ float sw;
+
+ BLI_strncpy(fname,file->relname, FILE_MAXFILE);
+ sw = shorten_string(simasel, fname, simasel->prv_w );
+ soffs = (simasel->prv_w + TILE_BORDER_X*4 - sw) / 2;
+
+ ui_rasterpos_safe(sx+soffs, sy - simasel->prv_h - TILE_BORDER_Y*2 - U.fontsize, simasel->aspect);
+#ifdef WIN32
+ BIF_DrawString(simasel->curfont, fname, ((U.transopts & USER_TR_MENUS) | CONVERT_TO_UTF8));
+#else
+ BIF_DrawString(simasel->curfont, fname, (U.transopts & USER_TR_MENUS));
+#endif
+}
+
+static void draw_imasel_bookmarks(ScrArea *sa, SpaceImaSel *simasel)
+{
+ char bookmark[FILE_MAX];
+ float sw;
+
+ if (simasel->flag & FILE_BOOKMARKS) {
+ int nentries = fsmenu_get_nentries();
+ int i;
+ short sx, sy;
+ int bmwidth;
+ int linestep = U.fontsize*3/2;
+
+ sx = simasel->bookmarkrect.xmin + TILE_BORDER_X;
+ sy = simasel->bookmarkrect.ymax - TILE_BORDER_Y - linestep;
+ bmwidth = simasel->bookmarkrect.xmax - simasel->bookmarkrect.xmin - 2*TILE_BORDER_X;
+
+ if (bmwidth < 0) return;
+
+ for (i=0; i< nentries && sy > linestep ;++i) {
+ char *fname = fsmenu_get_entry(i);
+ char *sname = NULL;
+
+ if (fname) {
+ int sl;
+ BLI_strncpy(bookmark, fname, FILE_MAX);
+
+ sl = strlen(bookmark)-1;
+ if (bookmark[sl] == '\\' || bookmark[sl] == '/') {
+ bookmark[sl] = '\0';
+ sl--;
+ }
+ while (sl) {
+ if (bookmark[sl] == '\\' || bookmark[sl] == '/'){
+ sl++;
+ break;
+ };
+ sl--;
+ }
+ sname = &bookmark[sl];
+ sw = shorten_string(simasel, sname, bmwidth);
+
+
+ if (simasel->active_bookmark == i ) {
+ glEnable(GL_BLEND);
+ glColor4ub(0, 0, 0, 100);
+ glDisable(GL_BLEND);
+ BIF_ThemeColor(TH_HILITE);
+ uiSetRoundBox(15);
+ uiRoundBox(simasel->bookmarkrect.xmin + TILE_BORDER_X - 1, sy - linestep*0.25, simasel->bookmarkrect.xmax - TILE_BORDER_X + 1, sy + linestep*0.75, 6);
+ BIF_ThemeColor(TH_TEXT_HI);
+ } else {
+ BIF_ThemeColor(TH_TEXT);
+ }
+ ui_rasterpos_safe(sx, sy, simasel->aspect);
+#ifdef WIN32
+ BIF_DrawString(simasel->curfont, sname, ((U.transopts & USER_TR_MENUS) | CONVERT_TO_UTF8));
+#else
+ BIF_DrawString(simasel->curfont, sname, (U.transopts & USER_TR_MENUS));
+#endif
+ sy -= linestep;
+ } else {
+ cpack(0xB0B0B0);
+ sdrawline(sx, sy + U.fontsize/2 , sx + bmwidth, sy + U.fontsize/2);
+ cpack(0x303030);
+ sdrawline(sx, sy + 1 + U.fontsize/2 , sx + bmwidth, sy + 1 + U.fontsize/2);
+ sy -= linestep;
+ }
+ }
+
+ uiEmboss(simasel->bookmarkrect.xmin, simasel->bookmarkrect.ymin, simasel->bookmarkrect.xmax-1, simasel->bookmarkrect.ymax-1, 1);
+ }
+}
+
+static void draw_imasel_previews(ScrArea *sa, SpaceImaSel *simasel)
+{
+ static double lasttime= 0;
+ struct FileList* files = simasel->files;
+ int numfiles;
+ struct direntry *file;
+ int numtiles;
+
+ int tilewidth = simasel->prv_w + TILE_BORDER_X*4;
+ int tileheight = simasel->prv_h + TILE_BORDER_Y*4 + U.fontsize;
+ short sx, sy;
+ int do_load = 1;
+
+ ImBuf* imb=0;
+ int i,j;
+ short type;
+ int colorid = 0;
+ int todo;
+ int fileoffset, rowoffset, columnoffset;
+ float scrollofs;
+
+
+ rcti viewrect = simasel->viewrect;
+
+ if (!files) return;
+ /* Reload directory */
+ BLI_strncpy(simasel->dir, BIF_filelist_dir(files), FILE_MAXDIR);
+
+ type = BIF_filelist_gettype(simasel->files);
+
+ if (BIF_filelist_empty(files))
+ {
+ unsigned int filter = 0;
+ BIF_filelist_hidedot(simasel->files, simasel->flag & FILE_HIDE_DOT);
+ if (simasel->flag & FILE_FILTER) {
+ filter = simasel->filter ;
+ } else {
+ filter = 0;
+ }
+
+ BIF_filelist_setfilter(simasel->files, filter);
+ BIF_filelist_readdir(files);
+
+ if(simasel->sort!=FILE_SORTALPHA) BIF_filelist_sort(simasel->files, simasel->sort);
+ }
+
+ BIF_filelist_imgsize(simasel->files,simasel->prv_w,simasel->prv_h);
+
+ numfiles = BIF_filelist_numfiles(files);
+ numtiles = simasel->numtilesx*simasel->numtilesy;
+
+ if (numtiles > numfiles) numtiles = numfiles;
+
+ todo = 0;
+ if (lasttime < 0.001) lasttime = PIL_check_seconds_timer();
+
+
+ if (simasel->numtilesx > 0) {
+ /* calculate the offset to start drawing */
+ if ((numtiles < numfiles) && (simasel->scrollarea > 0)) {
+ fileoffset = numfiles*( (simasel->scrollpos) / simasel->scrollarea) + 0.5;
+ } else {
+ fileoffset = 0;
+ }
+ rowoffset = (fileoffset / simasel->numtilesx)*simasel->numtilesx;
+ columnoffset = fileoffset % simasel->numtilesx;
+ scrollofs = (float)tileheight*(float)columnoffset/(float)simasel->numtilesx;
+ } else {
+ rowoffset = 0;
+ scrollofs = 0;
+ }
+ /* add partially visible row */
+ numtiles += simasel->numtilesx;
+ for (i=rowoffset, j=0 ; (i < numfiles) && (j < numtiles); ++i, ++j)
+ {
+ sx = simasel->v2d.cur.xmin + viewrect.xmin + (j % simasel->numtilesx)*tilewidth;
+ sy = simasel->v2d.cur.ymin + viewrect.ymax + (short)scrollofs - (viewrect.ymin + (j / simasel->numtilesx)*tileheight);
+
+ file = BIF_filelist_file(files, i);
+
+ if (simasel->active_file == i) {
+ colorid = TH_ACTIVE;
+ draw_tile(simasel, sx, sy, colorid);
+ } else if (file->flags & ACTIVE) {
+ colorid = TH_HILITE;
+ draw_tile(simasel, sx, sy, colorid);
+ } else {
+ /*
+ colorid = TH_PANEL;
+ draw_tile(simasel, sx, sy, colorid);
+ */
+ }
+
+ if ( type == FILE_MAIN) {
+ ID *id;
+ int icon_id = 0;
+ int idcode;
+ idcode= BIF_groupname_to_code(simasel->dir);
+ if (idcode == ID_MA || idcode == ID_TE || idcode == ID_LA || idcode == ID_WO || idcode == ID_IM) {
+ id = (ID *)file->poin;
+ icon_id = BKE_icon_getid(id);
+ }
+ if (icon_id) {
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ if (do_load) {
+ BIF_icon_draw_preview(sx+2*TILE_BORDER_X, sy-simasel->prv_w-TILE_BORDER_X, icon_id, 0);
+ } else {
+ BIF_icon_draw_preview(sx+2*TILE_BORDER_X, sy-simasel->prv_w-TILE_BORDER_X, icon_id, 1);
+ todo++;
+ }
+
+ glDisable(GL_BLEND);
+ }
+ }
+ else {
+ if ( (file->flags & IMAGEFILE) || (file->flags & MOVIEFILE))
+ {
+ if (do_load) {
+ BIF_filelist_loadimage(simasel->files, i);
+ } else {
+ todo++;
+ }
+ imb = BIF_filelist_getimage(simasel->files, i);
+ } else {
+ imb = BIF_filelist_getimage(simasel->files, i);
+ }
+
+ if (imb) {
+ float fx = ((float)simasel->prv_w - (float)imb->x)/2.0f;
+ float fy = ((float)simasel->prv_h - (float)imb->y)/2.0f;
+ short dx = (short)(fx + 0.5f);
+ short dy = (short)(fy + 0.5f);
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ // glaDrawPixelsSafe((float)sx+8 + dx, (float)sy - imgwidth + dy - 8, imb->x, imb->y, imb->x, GL_RGBA, GL_UNSIGNED_BYTE, imb->rect);
+ glColor4f(1.0, 1.0, 1.0, 1.0);
+ glaDrawPixelsTex((float)sx+2*TILE_BORDER_X + dx, (float)sy - simasel->prv_h + dy - 2*TILE_BORDER_Y, imb->x, imb->y,GL_UNSIGNED_BYTE, imb->rect);
+ // glDisable(GL_BLEND);
+ imb = 0;
+ }
+ }
+
+ if (type == FILE_MAIN) {
+ glColor3f(1.0f, 1.0f, 1.0f);
+ }
+ else {
+ if (S_ISDIR(file->type)) {
+ glColor3f(1.0f, 1.0f, 0.9f);
+ }
+ else if (file->flags & IMAGEFILE) {
+ BIF_ThemeColor(TH_SEQ_IMAGE);
+ }
+ else if (file->flags & MOVIEFILE) {
+ BIF_ThemeColor(TH_SEQ_MOVIE);
+ }
+ else if (file->flags & BLENDERFILE) {
+ BIF_ThemeColor(TH_SEQ_SCENE);
+ }
+ else {
+ if (simasel->active_file == i) {
+ BIF_ThemeColor(TH_GRID); /* grid used for active text */
+ } else if (file->flags & ACTIVE) {
+ BIF_ThemeColor(TH_TEXT_HI);
+ } else {
+ BIF_ThemeColor(TH_TEXT);
+ }
+ }
+ }
+
+ draw_file(simasel, sx, sy, file);
+
+ if(do_load && (PIL_check_seconds_timer() - lasttime > 0.3)) {
+ lasttime= PIL_check_seconds_timer();
+ do_load = 0;
+ }
+ }
+
+ if (!do_load && todo > 0) /* we broke off loading */
+ addafterqueue(sa->win, RENDERPREVIEW, 1);
+}
+
+
+/* in panel space! */
+static void imasel_imgdraw(ScrArea *sa, uiBlock *block)
+{
+ SpaceImaSel *simasel= sa->spacedata.first;
+ rctf dispf;
+ rcti winrect;
+ struct direntry *file;
+ char path[FILE_MAX];
+ float tsize;
+ short ofsx=0;
+ short ofsy=0;
+ short ex, ey;
+ float scaledx, scaledy;
+ int index;
+
+ BLI_init_rctf(&dispf, 0.0f, (block->maxx - block->minx)-0.0f, 0.0f, (block->maxy - block->miny)-0.0f);
+ ui_graphics_to_window_rct(sa->win, &dispf, &winrect);
+
+ if (!simasel->img) {
+ BLI_join_dirfile(path, simasel->dir, simasel->file);
+ if (!BLI_exists(path))
+ return;
+
+ index = BIF_filelist_find(simasel->files, simasel->file);
+ if (index >= 0) {
+ file = BIF_filelist_file(simasel->files,index);
+ if (file->flags & IMAGEFILE || file->flags & MOVIEFILE) {
+ simasel->img = IMB_loadiffname(path, IB_rect);
+
+ if (simasel->img) {
+ tsize = MIN2(winrect.xmax - winrect.xmin,winrect.ymax - winrect.ymin);
+
+ if (simasel->img->x > simasel->img->y) {
+ scaledx = (float)tsize;
+ scaledy = ( (float)simasel->img->y/(float)simasel->img->x )*tsize;
+ ofsy = (scaledx - scaledy) / 2.0;
+ ofsx = 0;
+ }
+ else {
+ scaledy = (float)tsize;
+ scaledx = ( (float)simasel->img->x/(float)simasel->img->y )*tsize;
+ ofsx = (scaledy - scaledx) / 2.0;
+ ofsy = 0;
+ }
+ ex = (short)scaledx;
+ ey = (short)scaledy;
+
+ IMB_scaleImBuf(simasel->img, ex, ey);
+ }
+ }
+ }
+ }
+ if (simasel->img == NULL)
+ return;
+ if(simasel->img->rect==NULL)
+ return;
+
+ /* correction for gla draw */
+ BLI_translate_rcti(&winrect, -curarea->winrct.xmin, -curarea->winrct.ymin);
+
+ glaDefine2DArea(&sa->winrct);
+ glaDrawPixelsSafe(winrect.xmin+ofsx, winrect.ymin+ofsy, simasel->img->x, simasel->img->y, simasel->img->x, GL_RGBA, GL_UNSIGNED_BYTE, simasel->img->rect);
+}
+
+static void imasel_panel_image(ScrArea *sa, short cntrl)
+{
+ uiBlock *block;
+ SpaceImaSel *simasel= sa->spacedata.first;
+ short w = 300;
+ short h = 300;
+ short offsx, offsy;
+
+ if (simasel->img) {
+ w = simasel->img->x;
+ h = simasel->img->y;
+ }
+
+ offsx = -150 + (simasel->v2d.mask.xmax - simasel->v2d.mask.xmin)/2;
+ offsy = -150 + (simasel->v2d.mask.ymax - simasel->v2d.mask.ymin)/2;
+
+ block= uiNewBlock(&curarea->uiblocks, "imasel_panel_image", UI_EMBOSS, UI_HELV, curarea->win);
+ uiPanelControl(UI_PNL_SOLID | UI_PNL_CLOSE | cntrl);
+ uiSetPanelHandler(IMASEL_HANDLER_IMAGE); // for close and esc
+ if(uiNewPanel(curarea, block, "Image Preview", "Image Browser", offsx, offsy, w, h)==0)
+ return;
+ uiBlockSetDrawExtraFunc(block, imasel_imgdraw);
+}
+
+static void imasel_blockhandlers(ScrArea *sa)
+{
+ SpaceImaSel *simasel= sa->spacedata.first;
+ short a;
+
+ for(a=0; a<SPACE_MAXHANDLER; a+=2) {
+ switch(simasel->blockhandler[a]) {
+
+ case IMASEL_HANDLER_IMAGE:
+ imasel_panel_image(sa, simasel->blockhandler[a+1]);
+ break;
+
+ }
+ /* clear action value for event */
+ simasel->blockhandler[a+1]= 0;
+ }
+ uiDrawBlocksPanels(sa, 0);
+}
+
+
+static void draw_imasel_buttons(ScrArea *sa, SpaceImaSel* simasel)
+{
+ uiBlock *block;
+ int loadbutton;
+ char name[20];
+ char *menu;
+ float slen;
+ float parentbut_width = 20;
+ float bookmarkbut_width = 0.0f;
+ int filebuty1, filebuty2;
+
+ float xmin = simasel->v2d.mask.xmin + 10;
+ float xmax = simasel->v2d.mask.xmax - 10;
+
+ filebuty1= simasel->v2d.mask.ymax - IMASEL_BUTTONS_HEIGHT;
+ filebuty2= filebuty1+IMASEL_BUTTONS_HEIGHT/2 -6;
+
+ /* HEADER */
+ sprintf(name, "win %d", sa->win);
+ block = uiNewBlock(&sa->uiblocks, name, UI_EMBOSS, UI_HELV, sa->win);
+
+ uiSetButLock( BIF_filelist_gettype(simasel->files)==FILE_MAIN && simasel->returnfunc, NULL);
+
+ /* space available for load/save buttons? */
+ slen = BIF_GetStringWidth(G.font, simasel->title, simasel->aspect);
+ loadbutton= slen > 60 ? slen + 20 : 80; /* MAX2(80, 20+BIF_GetStringWidth(G.font, simasel->title)); */
+ if(simasel->v2d.mask.xmax-simasel->v2d.mask.xmin > loadbutton+20) {
+ if(simasel->title[0]==0) {
+ loadbutton= 0;
+ }
+ }
+ else {
+ loadbutton= 0;
+ }
+
+ menu= fsmenu_build_menu();
+
+ if (menu[0]) {
+ bookmarkbut_width = parentbut_width;
+ }
+
+ uiDefBut(block, TEX, B_FS_FILENAME,"", xmin+parentbut_width+bookmarkbut_width+2, filebuty1, xmax-xmin-loadbutton-parentbut_width-bookmarkbut_width, 21, simasel->file, 0.0, (float)FILE_MAXFILE-1, 0, 0, "");
+ uiDefBut(block, TEX, B_FS_DIRNAME,"", xmin+parentbut_width, filebuty2, xmax-xmin-loadbutton-parentbut_width, 21, simasel->dir, 0.0, (float)FILE_MAXFILE-1, 0, 0, "");
+
+ if(loadbutton) {
+ uiSetCurFont(block, UI_HELV);
+ uiDefBut(block, BUT,B_FS_LOAD, simasel->title, xmax-loadbutton, filebuty2, loadbutton, 21, simasel->dir, 0.0, (float)FILE_MAXFILE-1, 0, 0, "");
+ uiDefBut(block, BUT,B_FS_CANCEL, "Cancel", xmax-loadbutton, filebuty1, loadbutton, 21, simasel->file, 0.0, (float)FILE_MAXFILE-1, 0, 0, "");
+ }
+
+ if(menu[0]) { // happens when no .Bfs is there, and first time browse
+ uiDefButS(block, MENU,B_FS_DIR_MENU, menu, xmin, filebuty1, parentbut_width, 21, &simasel->menu, 0, 0, 0, 0, "");
+ uiDefBut(block, BUT, B_FS_BOOKMARK, "B", xmin+22, filebuty1, bookmarkbut_width, 21, 0, 0, 0, 0, 0, "Bookmark current directory");
+ }
+ MEM_freeN(menu);
+
+ uiDefBut(block, BUT, B_FS_PARDIR, "P", xmin, filebuty2, parentbut_width, 21, 0, 0, 0, 0, 0, "Move to the parent directory (PKEY)");
+
+ uiDrawBlock(block);
+}
+
+
+
+/* ************** main drawing function ************** */
+
+void drawimaselspace(ScrArea *sa, void *spacedata)
+{
+ float col[3];
+ SpaceImaSel *simasel= curarea->spacedata.first;
+
+ BIF_GetThemeColor3fv(TH_BACK, col);
+ glClearColor(col[0], col[1], col[2], 0.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ /* HACK: somehow when going fullscreen, v2d isn't set correctly */
+ simasel->v2d.cur.xmin= simasel->v2d.cur.ymin= 0.0f;
+ simasel->v2d.cur.xmax= sa->winx;
+ simasel->v2d.cur.ymax= sa->winy;
+ simasel->v2d.tot= simasel->v2d.cur;
+ test_view2d(G.v2d, sa->winx, sa->winy);
+
+ calc_imasel_rcts(simasel, sa->winx, sa->winy);
+
+ myortho2(simasel->v2d.cur.xmin, simasel->v2d.cur.xmax, simasel->v2d.cur.ymin, simasel->v2d.cur.ymax);
+ bwin_clear_viewmat(sa->win); /* clear buttons view */
+ glLoadIdentity();
+
+ /* warning; blocks need to be freed each time, handlers dont remove */
+ uiFreeBlocksWin(&sa->uiblocks, sa->win);
+
+ /* aspect+font, set each time */
+ simasel->aspect= (simasel->v2d.cur.xmax - simasel->v2d.cur.xmin)/((float)sa->winx);
+ simasel->curfont= uiSetCurFont_ext(simasel->aspect);
+
+ if (!simasel->files) {
+ simasel->files = BIF_filelist_new();
+ BIF_filelist_setdir(simasel->files, simasel->dir);
+ BIF_filelist_settype(simasel->files, simasel->type);
+ }
+
+ /* Buttons */
+ draw_imasel_buttons(sa, simasel);
+
+ /* scrollbar */
+ draw_imasel_scroll(simasel);
+
+ /* bookmarks */
+ draw_imasel_bookmarks(sa, simasel);
+
+ uiEmboss(simasel->viewrect.xmin, simasel->viewrect.ymin, simasel->v2d.mask.xmax-TILE_BORDER_X, simasel->viewrect.ymax, 1);
+
+
+ glScissor(sa->winrct.xmin + simasel->viewrect.xmin ,
+ sa->winrct.ymin + simasel->viewrect.ymin,
+ simasel->viewrect.xmax - simasel->viewrect.xmin ,
+ simasel->viewrect.ymax - simasel->viewrect.ymin);
+
+ /* previews */
+ draw_imasel_previews(sa, simasel);
+
+ /* BIF_ThemeColor(TH_HEADER);*/
+ /* glRecti(simasel->viewrect.xmin, simasel->viewrect.ymin, simasel->viewrect.xmax, simasel->viewrect.ymax);*/
+
+ /* restore viewport (not needed yet) */
+ mywinset(sa->win);
+
+ /* ortho at pixel level curarea */
+ myortho2(-0.375, curarea->winx-0.375, -0.375, curarea->winy-0.375);
+
+ draw_area_emboss(sa);
+
+ imasel_blockhandlers(sa);
+
+ curarea->win_swap= WIN_BACK_OK;
+}
diff --git a/source/blender/src/drawipo.c b/source/blender/src/drawipo.c
new file mode 100644
index 00000000000..d9ef3349ec1
--- /dev/null
+++ b/source/blender/src/drawipo.c
@@ -0,0 +1,2728 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef _WIN32
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "DNA_action_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_key_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_sequence_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BKE_curve.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_ipo.h"
+#include "BKE_key.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_cursors.h"
+#include "BIF_gl.h"
+#include "BIF_graphics.h"
+#include "BIF_resources.h"
+#include "BIF_screen.h"
+#include "BIF_interface.h"
+#include "BIF_mywindow.h"
+#include "BIF_space.h"
+#include "BIF_toolbox.h"
+#include "BIF_glutil.h"
+#include "BIF_editseq.h"
+#include "BIF_editaction.h"
+#include "BIF_language.h"
+
+#include "BSE_drawipo.h"
+#include "BSE_view.h"
+#include "BSE_editipo.h"
+#include "BSE_editipo_types.h"
+#include "BSE_editnla_types.h"
+#include "BSE_time.h"
+
+#include "BPY_extern.h"
+
+#include "mydevice.h"
+#include "blendef.h"
+#include "butspace.h" // shouldnt be...
+#include "interface.h" /* for ui_rasterpos_safe */
+#include "winlay.h"
+
+/* local define... also used in editipo ... */
+#define ISPOIN(a, b, c) ( (a->b) && (a->c) )
+#define ISPOIN3(a, b, c, d) ( (a->b) && (a->c) && (a->d) )
+#define ISPOIN4(a, b, c, d, e) ( (a->b) && (a->c) && (a->d) && (a->e) )
+
+ /* minimum pixels per gridstep */
+#define IPOSTEP 35
+
+static float ipogrid_dx, ipogrid_dy, ipogrid_startx, ipogrid_starty;
+static int ipomachtx, ipomachty;
+
+static int vertymin, vertymax, horxmin, horxmax; /* globals to test LEFTMOUSE for scrollbar */
+
+static void scroll_prstr(float x, float y, float val, char dir, int disptype)
+{
+ int len, macht;
+ char str[32];
+
+ if(dir=='v') {
+ macht= ipomachty;
+ if ELEM(disptype, IPO_DISPDEGR, IPO_DISPTIME) {
+ macht+=1;
+ val *= 10;
+ }
+ }
+ else macht= ipomachtx;
+
+ if (macht<=0) sprintf(str, "%.*f", 1-macht, val);
+ else sprintf(str, "%d", (int)floor(val + 0.375));
+
+ len= strlen(str);
+ if(dir=='h') x-= 4*len;
+
+ if(dir=='v' && disptype==IPO_DISPDEGR) {
+ str[len]= 186; /* Degree symbol */
+ str[len+1]= 0;
+ }
+
+ ui_rasterpos_safe(x, y, 1.0);
+ BIF_DrawString(G.fonts, str, 0);
+}
+
+static void step_to_grid(float *step, int *macht)
+{
+ float loga, rem;
+
+ /* try to write step as a power of 10 */
+
+ loga= log10(*step);
+ *macht= (int)(loga);
+
+ rem= loga- *macht;
+ rem= pow(10.0, rem);
+
+ if(loga<0.0) {
+ if(rem < 0.2) rem= 0.2;
+ else if(rem < 0.5) rem= 0.5;
+ else rem= 1.0;
+
+ *step= rem*pow(10.0, (float)*macht);
+
+ // partial of a frame have no meaning
+ switch(curarea->spacetype) {
+ case SPACE_TIME: {
+ SpaceTime *stime= curarea->spacedata.first;
+ if(stime->flag & TIME_DRAWFRAMES) {
+ rem = 1.0;
+ *step = 1.0;
+ }
+ break;
+ }
+ case SPACE_SEQ: {
+ SpaceTime * sseq= curarea->spacedata.first;
+ if (sseq->flag & SEQ_DRAWFRAMES) {
+ rem = 1.0;
+ *step = 1.0;
+ }
+ }
+ default:
+ break;
+ }
+
+
+
+ if(rem==1.0) (*macht)++; // prevents printing 1.0 2.0 3.0 etc
+ }
+ else {
+ if(rem < 2.0) rem= 2.0;
+ else if(rem < 5.0) rem= 5.0;
+ else rem= 10.0;
+
+ *step= rem*pow(10.0, (float)*macht);
+
+ (*macht)++;
+ if(rem==10.0) (*macht)++; // prevents printing 1.0 2.0 3.0 etc
+ }
+}
+
+void calc_ipogrid()
+{
+ float space, pixels, secondiv=1.0;
+ int secondgrid= 0;
+ /* rule: gridstep is minimal IPOSTEP pixels */
+ /* how large is IPOSTEP pixels? */
+
+ if(G.v2d==0) return;
+
+ /* detect of we have seconds or frames, should become argument */
+
+ switch(curarea->spacetype) {
+ case SPACE_TIME: {
+ SpaceTime *stime= curarea->spacedata.first;
+ if(!(stime->flag & TIME_DRAWFRAMES)) {
+ secondgrid= 1;
+ secondiv= 0.01 * FPS;
+ }
+ break;
+ }
+ case SPACE_SEQ: {
+ SpaceSeq * sseq = curarea->spacedata.first;
+ if (!(sseq->flag & SEQ_DRAWFRAMES)) {
+ secondgrid = 1;
+ secondiv = 0.01 * FPS;
+ }
+ break;
+ }
+ case SPACE_ACTION: {
+ SpaceAction *saction = curarea->spacedata.first;
+ if (saction->flag & SACTION_DRAWTIME) {
+ secondgrid = 1;
+ secondiv = 0.01 * FPS;
+ }
+ break;
+ }
+ case SPACE_NLA: {
+ SpaceNla *snla = curarea->spacedata.first;
+ if (snla->flag & SNLA_DRAWTIME) {
+ secondgrid = 1;
+ secondiv = 0.01 * FPS;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ space= G.v2d->cur.xmax - G.v2d->cur.xmin;
+ pixels= G.v2d->mask.xmax-G.v2d->mask.xmin;
+
+ ipogrid_dx= IPOSTEP*space/(secondiv*pixels);
+ step_to_grid(&ipogrid_dx, &ipomachtx);
+ ipogrid_dx*= secondiv;
+
+ if ELEM5(curarea->spacetype, SPACE_SEQ, SPACE_SOUND, SPACE_TIME, SPACE_ACTION, SPACE_NLA) {
+ if(ipogrid_dx < 0.1) ipogrid_dx= 0.1;
+ ipomachtx-= 2;
+ if(ipomachtx<-2) ipomachtx= -2;
+ }
+
+ space= (G.v2d->cur.ymax - G.v2d->cur.ymin);
+ pixels= curarea->winy;
+ ipogrid_dy= IPOSTEP*space/pixels;
+ step_to_grid(&ipogrid_dy, &ipomachty);
+
+ if ELEM5(curarea->spacetype, SPACE_SEQ, SPACE_SOUND, SPACE_TIME, SPACE_ACTION, SPACE_NLA) {
+ if(ipogrid_dy < 1.0) ipogrid_dy= 1.0;
+ if(ipomachty<1) ipomachty= 1;
+ }
+
+ ipogrid_startx= secondiv*(G.v2d->cur.xmin/secondiv - fmod(G.v2d->cur.xmin/secondiv, ipogrid_dx/secondiv));
+ if(G.v2d->cur.xmin<0.0) ipogrid_startx-= ipogrid_dx;
+
+ ipogrid_starty= (G.v2d->cur.ymin-fmod(G.v2d->cur.ymin, ipogrid_dy));
+ if(G.v2d->cur.ymin<0.0) ipogrid_starty-= ipogrid_dy;
+
+}
+
+void draw_ipogrid(void)
+{
+ float vec1[2], vec2[2];
+ int a, step;
+
+ vec1[0]= vec2[0]= ipogrid_startx;
+ vec1[1]= ipogrid_starty;
+ vec2[1]= G.v2d->cur.ymax;
+
+ step= (G.v2d->mask.xmax-G.v2d->mask.xmin+1)/IPOSTEP;
+
+ BIF_ThemeColor(TH_GRID);
+
+ for(a=0; a<step; a++) {
+ glBegin(GL_LINE_STRIP);
+ glVertex2fv(vec1); glVertex2fv(vec2);
+ glEnd();
+ vec2[0]= vec1[0]+= ipogrid_dx;
+ }
+
+ vec2[0]= vec1[0]-= 0.5*ipogrid_dx;
+
+ BIF_ThemeColorShade(TH_GRID, 16);
+
+ step++;
+ for(a=0; a<=step; a++) {
+ glBegin(GL_LINE_STRIP);
+ glVertex2fv(vec1); glVertex2fv(vec2);
+ glEnd();
+ vec2[0]= vec1[0]-= ipogrid_dx;
+ }
+
+ if ELEM4(curarea->spacetype, SPACE_SOUND, SPACE_ACTION, SPACE_NLA, SPACE_TIME);
+ else {
+ vec1[0]= ipogrid_startx;
+ vec1[1]= vec2[1]= ipogrid_starty;
+ vec2[0]= G.v2d->cur.xmax;
+
+ step= (curarea->winy+1)/IPOSTEP;
+
+ BIF_ThemeColor(TH_GRID);
+ for(a=0; a<=step; a++) {
+ glBegin(GL_LINE_STRIP);
+ glVertex2fv(vec1); glVertex2fv(vec2);
+ glEnd();
+ vec2[1]= vec1[1]+= ipogrid_dy;
+ }
+ vec2[1]= vec1[1]-= 0.5*ipogrid_dy;
+ step++;
+
+ if(curarea->spacetype==SPACE_IPO) {
+ BIF_ThemeColorShade(TH_GRID, 16);
+ for(a=0; a<step; a++) {
+ glBegin(GL_LINE_STRIP);
+ glVertex2fv(vec1); glVertex2fv(vec2);
+ glEnd();
+ vec2[1]= vec1[1]-= ipogrid_dy;
+ }
+ }
+ }
+
+ BIF_ThemeColorShade(TH_GRID, -50);
+
+ if (curarea->spacetype!=SPACE_ACTION && curarea->spacetype!=SPACE_NLA)
+ { /* Horizontal axis */
+ vec1[0]= G.v2d->cur.xmin;
+ vec2[0]= G.v2d->cur.xmax;
+ vec1[1]= vec2[1]= 0.0;
+ glBegin(GL_LINE_STRIP);
+
+ glVertex2fv(vec1);
+ glVertex2fv(vec2);
+
+ glEnd();
+ }
+
+ /* Vertical axis */
+
+ vec1[1]= G.v2d->cur.ymin;
+ vec2[1]= G.v2d->cur.ymax;
+ vec1[0]= vec2[0]= 0.0;
+ glBegin(GL_LINE_STRIP);
+ glVertex2fv(vec1); glVertex2fv(vec2);
+ glEnd();
+
+ /* Limits box */
+ if(curarea->spacetype==SPACE_IPO) {
+ if(G.sipo->blocktype==ID_SEQ) {
+ Sequence * last_seq = get_last_seq();
+ float start = 0.0;
+ float end = 100.0;
+
+ if (last_seq &&
+ ((last_seq->flag & SEQ_IPO_FRAME_LOCKED) != 0)) {
+ start = last_seq->startdisp;
+ end = last_seq->enddisp;
+ }
+
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ glRectf(start, 0.0, end, 1.0);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ }
+ else if(ELEM(G.sipo->blocktype, ID_CU, ID_CO)) {
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ glRectf(0.0, 1.0, G.v2d->cur.xmax, 1.0);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ }
+ }
+}
+
+void areamouseco_to_ipoco(View2D *v2d, short *mval, float *x, float *y)
+{
+ float div, ofs;
+
+ div= v2d->mask.xmax-v2d->mask.xmin;
+ ofs= v2d->mask.xmin;
+
+ *x= v2d->cur.xmin+ (v2d->cur.xmax-v2d->cur.xmin)*(mval[0]-ofs)/div;
+
+ div= v2d->mask.ymax-v2d->mask.ymin;
+ ofs= v2d->mask.ymin;
+
+ *y= v2d->cur.ymin+ (v2d->cur.ymax-v2d->cur.ymin)*(mval[1]-ofs)/div;
+}
+
+void ipoco_to_areaco(View2D *v2d, float *vec, short *mval)
+{
+ float x, y;
+
+ mval[0]= IS_CLIPPED;
+
+ x= (vec[0] - v2d->cur.xmin)/(v2d->cur.xmax-v2d->cur.xmin);
+ y= (vec[1] - v2d->cur.ymin)/(v2d->cur.ymax-v2d->cur.ymin);
+
+ if(x>=0.0 && x<=1.0) {
+ if(y>=0.0 && y<=1.0) {
+ mval[0]= v2d->mask.xmin + x*(v2d->mask.xmax-v2d->mask.xmin);
+ mval[1]= v2d->mask.ymin + y*(v2d->mask.ymax-v2d->mask.ymin);
+ }
+ }
+}
+
+void ipoco_to_areaco_noclip(View2D *v2d, float *vec, short *mval)
+{
+ float x, y;
+
+ x= (vec[0] - v2d->cur.xmin)/(v2d->cur.xmax-v2d->cur.xmin);
+ y= (vec[1] - v2d->cur.ymin)/(v2d->cur.ymax-v2d->cur.ymin);
+
+ x= v2d->mask.xmin + x*(v2d->mask.xmax-v2d->mask.xmin);
+ y= v2d->mask.ymin + y*(v2d->mask.ymax-v2d->mask.ymin);
+
+ if(x<-32760) mval[0]= -32760;
+ else if(x>32760) mval[0]= 32760;
+ else mval[0]= x;
+
+ if(y<-32760) mval[1]= -32760;
+ else if(y>32760) mval[1]= 32760;
+ else mval[1]= y;
+}
+
+int in_ipo_buttons(void)
+{
+ short mval[2];
+
+ getmouseco_areawin(mval);
+
+ if(mval[0]< G.v2d->mask.xmax) return 0;
+ else return 1;
+}
+
+static View2D *spacelink_get_view2d(SpaceLink *sl)
+{
+ if(sl->spacetype==SPACE_IPO)
+ return &((SpaceIpo *)sl)->v2d;
+ else if(sl->spacetype==SPACE_SOUND)
+ return &((SpaceSound *)sl)->v2d;
+ if(sl->spacetype==SPACE_ACTION)
+ return &((SpaceAction *)sl)->v2d;
+ if(sl->spacetype==SPACE_NLA)
+ return &((SpaceNla *)sl)->v2d;
+ if(sl->spacetype==SPACE_TIME)
+ return &((SpaceTime *)sl)->v2d;
+ if(sl->spacetype==SPACE_SEQ)
+ return &((SpaceSeq *)sl)->v2d;
+ return NULL;
+}
+
+/* copies changes in this view from or to all 2d views with lock option open */
+/* do not call this inside of drawing routines, to prevent eternal loops */
+void view2d_do_locks(ScrArea *cursa, int flag)
+{
+ ScrArea *sa;
+ View2D *v2d, *curv2d;
+ SpaceLink *sl;
+
+ curv2d= spacelink_get_view2d(cursa->spacedata.first);
+ if(curv2d==NULL) return;
+ if((curv2d->flag & V2D_VIEWLOCK)==0) return;
+
+ for(sa= G.curscreen->areabase.first; sa; sa= sa->next) {
+ if(sa!=cursa) {
+ for(sl= sa->spacedata.first; sl; sl= sl->next) {
+
+ v2d= spacelink_get_view2d(sl);
+ if(v2d) {
+ if(v2d->flag & V2D_VIEWLOCK) {
+ if(flag & V2D_LOCK_COPY) {
+ v2d->cur.xmin= curv2d->cur.xmin;
+ v2d->cur.xmax= curv2d->cur.xmax;
+ }
+ else {
+ curv2d->cur.xmin= v2d->cur.xmin;
+ curv2d->cur.xmax= v2d->cur.xmax;
+ scrarea_queue_winredraw(sa);
+ }
+
+ if(flag & V2D_LOCK_REDRAW) {
+ if(sl == sa->spacedata.first)
+ scrarea_do_windraw(sa);
+ }
+ else
+ scrarea_queue_winredraw(sa);
+ }
+ }
+ }
+ }
+ }
+}
+
+/* event based, note: curarea is in here... */
+void view2d_zoom(View2D *v2d, float factor, int winx, int winy)
+{
+ float dx= factor*(v2d->cur.xmax-v2d->cur.xmin);
+ float dy= factor*(v2d->cur.ymax-v2d->cur.ymin);
+ if ((v2d->keepzoom & V2D_LOCKZOOM_X)==0) {
+ v2d->cur.xmin+= dx;
+ v2d->cur.xmax-= dx;
+ }
+ if ((v2d->keepzoom & V2D_LOCKZOOM_Y)==0) {
+ v2d->cur.ymin+= dy;
+ v2d->cur.ymax-= dy;
+ }
+ test_view2d(v2d, winx, winy);
+ view2d_do_locks(curarea, V2D_LOCK_COPY);
+}
+
+
+void test_view2d(View2D *v2d, int winx, int winy)
+{
+ /* cur is not allowed to be larger than max, smaller than min, or outside of tot */
+ rctf *cur, *tot;
+ float dx, dy, temp, fac, zoom;
+
+ /* correct winx for scroll */
+ if(v2d->scroll & L_SCROLL) winx-= SCROLLB;
+ if(v2d->scroll & B_SCROLL) winy-= SCROLLH;
+ if(v2d->scroll & B_SCROLLO) winy-= SCROLLH; /* B_SCROLL and B_SCROLLO are basically same thing */
+
+ /* header completely closed window */
+ if(winy<=0) return;
+
+ cur= &v2d->cur;
+ tot= &v2d->tot;
+
+ dx= cur->xmax-cur->xmin;
+ dy= cur->ymax-cur->ymin;
+
+ /* Reevan's test */
+ if (v2d->keepzoom & V2D_LOCKZOOM_Y)
+ v2d->cur.ymax=v2d->cur.ymin+((float)winy);
+
+ if (v2d->keepzoom & V2D_LOCKZOOM_X)
+ v2d->cur.xmax=v2d->cur.xmin+((float)winx);
+
+ if(v2d->keepzoom) {
+
+ zoom= ((float)winx)/dx;
+
+ if(zoom<v2d->minzoom || zoom>v2d->maxzoom) {
+ if(zoom<v2d->minzoom) fac= zoom/v2d->minzoom;
+ else fac= zoom/v2d->maxzoom;
+
+ dx*= fac;
+ temp= 0.5*(cur->xmax+cur->xmin);
+
+ cur->xmin= temp-0.5*dx;
+ cur->xmax= temp+0.5*dx;
+ }
+
+ zoom= ((float)winy)/dy;
+
+ if(zoom<v2d->minzoom || zoom>v2d->maxzoom) {
+ if(zoom<v2d->minzoom) fac= zoom/v2d->minzoom;
+ else fac= zoom/v2d->maxzoom;
+
+ dy*= fac;
+ temp= 0.5*(cur->ymax+cur->ymin);
+ cur->ymin= temp-0.5*dy;
+ cur->ymax= temp+0.5*dy;
+ }
+ }
+ else {
+ if(dx<G.v2d->min[0]) {
+ dx= G.v2d->min[0];
+ temp= 0.5*(cur->xmax+cur->xmin);
+ cur->xmin= temp-0.5*dx;
+ cur->xmax= temp+0.5*dx;
+ }
+ else if(dx>G.v2d->max[0]) {
+ dx= G.v2d->max[0];
+ temp= 0.5*(cur->xmax+cur->xmin);
+ cur->xmin= temp-0.5*dx;
+ cur->xmax= temp+0.5*dx;
+ }
+
+ if(dy<G.v2d->min[1]) {
+ dy= G.v2d->min[1];
+ temp= 0.5*(cur->ymax+cur->ymin);
+ cur->ymin= temp-0.5*dy;
+ cur->ymax= temp+0.5*dy;
+ }
+ else if(dy>G.v2d->max[1]) {
+ dy= G.v2d->max[1];
+ temp= 0.5*(cur->ymax+cur->ymin);
+ cur->ymin= temp-0.5*dy;
+ cur->ymax= temp+0.5*dy;
+ }
+ }
+
+ if(v2d->keepaspect) {
+ short do_x=0, do_y=0;
+
+ /* when a window edge changes, the aspect ratio can't be used to
+ find which is the best new 'cur' rect. thats why it stores 'old' */
+ if(winx!=v2d->oldwinx) do_x= 1;
+ if(winy!=v2d->oldwiny) do_y= 1;
+
+ dx= (cur->ymax-cur->ymin)/(cur->xmax-cur->xmin);
+ dy= ((float)winy)/((float)winx);
+
+ if(do_x==do_y) { // both sizes change, ctrl+uparrow
+ if(do_x==1 && do_y==1) {
+ if( ABS(winx-v2d->oldwinx)>ABS(winy-v2d->oldwiny)) do_y= 0;
+ else do_x= 0;
+ }
+ else if( dy > 1.0) do_x= 0; else do_x= 1;
+ }
+
+ if( do_x ) {
+ if (v2d->keeptot == 2 && winx < v2d->oldwinx) {
+ /* This is a special hack for the outliner, to ensure that the
+ * outliner contents will not eventually get pushed out of view
+ * when shrinking the view.
+ */
+ cur->xmax -= cur->xmin;
+ cur->xmin= 0.0f;
+ }
+ else {
+ /* portrait window: correct for x */
+ dx= cur->ymax-cur->ymin;
+ temp= (cur->xmax+cur->xmin);
+
+ cur->xmin= temp/2.0 - 0.5*dx/dy;
+ cur->xmax= temp/2.0 + 0.5*dx/dy;
+ }
+ }
+ else {
+ dx= cur->xmax-cur->xmin;
+ temp= (cur->ymax+cur->ymin);
+
+ cur->ymin= temp/2.0 - 0.5*dy*dx;
+ cur->ymax= temp/2.0 + 0.5*dy*dx;
+ }
+
+ v2d->oldwinx= winx;
+ v2d->oldwiny= winy;
+ }
+
+ if(v2d->keeptot) {
+ dx= cur->xmax-cur->xmin;
+ dy= cur->ymax-cur->ymin;
+
+ if(dx > tot->xmax-tot->xmin) {
+ if(v2d->keepzoom==0) {
+ if(cur->xmin<tot->xmin) cur->xmin= tot->xmin;
+ if(cur->xmax>tot->xmax) cur->xmax= tot->xmax;
+ }
+ else {
+ if(cur->xmax < tot->xmax) {
+ dx= tot->xmax-cur->xmax;
+ cur->xmin+= dx;
+ cur->xmax+= dx;
+ }
+ else if(cur->xmin > tot->xmin) {
+ dx= cur->xmin-tot->xmin;
+ cur->xmin-= dx;
+ cur->xmax-= dx;
+ }
+ }
+ }
+ else {
+ if(cur->xmin < tot->xmin) {
+ dx= tot->xmin-cur->xmin;
+ cur->xmin+= dx;
+ cur->xmax+= dx;
+ }
+ else if((v2d->keeptot!=2) && (cur->xmax > tot->xmax)) {
+ /* keeptot==2 is a special case for the outliner. see space.c, init_v2d_oops for details */
+ dx= cur->xmax-tot->xmax;
+ cur->xmin-= dx;
+ cur->xmax-= dx;
+ }
+ }
+
+ if(dy > tot->ymax-tot->ymin) {
+ if(v2d->keepzoom==0) {
+ if(cur->ymin<tot->ymin) cur->ymin= tot->ymin;
+ if(cur->ymax>tot->ymax) cur->ymax= tot->ymax;
+ }
+ else {
+ if(cur->ymax < tot->ymax) {
+ dy= tot->ymax-cur->ymax;
+ cur->ymin+= dy;
+ cur->ymax+= dy;
+ }
+ else if(cur->ymin > tot->ymin) {
+ dy= cur->ymin-tot->ymin;
+ cur->ymin-= dy;
+ cur->ymax-= dy;
+ }
+ }
+ }
+ else {
+ if(cur->ymin < tot->ymin) {
+ dy= tot->ymin-cur->ymin;
+ cur->ymin+= dy;
+ cur->ymax+= dy;
+ }
+ else if(cur->ymax > tot->ymax) {
+ dy= cur->ymax-tot->ymax;
+ cur->ymin-= dy;
+ cur->ymax-= dy;
+ }
+ }
+ }
+}
+
+#define IPOBUTX 70
+static int calc_ipobuttonswidth(ScrArea *sa)
+{
+ SpaceIpo *sipo= sa->spacedata.first;
+ EditIpo *ei;
+ int ipowidth = IPOBUTX;
+ int a;
+ float textwidth = 0;
+
+ /* default width when no space ipo or no channels */
+ if (sipo == NULL) return IPOBUTX;
+ if ((sipo->totipo==0) || (sipo->editipo==NULL)) return IPOBUTX;
+
+ ei= sipo->editipo;
+
+ for(a=0; a<sipo->totipo; a++, ei++) {
+ textwidth = BIF_GetStringWidth(G.font, ei->name, 0);
+ if (textwidth + 18 > ipowidth)
+ ipowidth = textwidth + 18;
+ }
+ return ipowidth;
+
+}
+
+void calc_scrollrcts(ScrArea *sa, View2D *v2d, int winx, int winy)
+{
+ v2d->mask.xmin= v2d->mask.ymin= 0;
+ v2d->mask.xmax= winx;
+ v2d->mask.ymax= winy;
+
+ if(sa->spacetype==SPACE_ACTION) {
+ if(sa->winx > ACTWIDTH+50) {
+ v2d->mask.xmin+= ACTWIDTH;
+ v2d->hor.xmin+=ACTWIDTH;
+ }
+ }
+ else if(sa->spacetype==SPACE_NLA){
+ if(sa->winx > NLAWIDTH+50) {
+ v2d->mask.xmin+= NLAWIDTH;
+ v2d->hor.xmin+=NLAWIDTH;
+ }
+ }
+ else if(sa->spacetype==SPACE_IPO) {
+ int ipobutx = calc_ipobuttonswidth(sa);
+
+ v2d->mask.xmax-= ipobutx;
+
+ if(v2d->mask.xmax<ipobutx)
+ v2d->mask.xmax= winx;
+ }
+
+ if(v2d->scroll) {
+ if(v2d->scroll & L_SCROLL) {
+ v2d->vert= v2d->mask;
+ v2d->vert.xmax= SCROLLB;
+ v2d->mask.xmin= SCROLLB;
+ }
+ else if(v2d->scroll & R_SCROLL) {
+ v2d->vert= v2d->mask;
+ v2d->vert.xmin= v2d->vert.xmax-SCROLLB;
+ v2d->mask.xmax= v2d->vert.xmin;
+ }
+
+ if((v2d->scroll & B_SCROLL) || (v2d->scroll & B_SCROLLO)) {
+ v2d->hor= v2d->mask;
+ v2d->hor.ymax= SCROLLH;
+ v2d->mask.ymin= SCROLLH;
+ }
+ else if(v2d->scroll & T_SCROLL) {
+ v2d->hor= v2d->mask;
+ v2d->hor.ymin= v2d->hor.ymax-SCROLLH;
+ v2d->mask.ymax= v2d->hor.ymin;
+ }
+ }
+}
+
+ /* draws a line in left vertical scrollbar at the given height */
+static void draw_solution_line(View2D *v2d, float h)
+{
+ float vec[2];
+ short mval[2];
+
+ vec[0]= v2d->cur.xmin;
+ vec[1]= h;
+ ipoco_to_areaco(v2d, vec, mval);
+ if(mval[0]!=IS_CLIPPED) {
+ glBegin(GL_LINES);
+ glVertex2f(v2d->vert.xmin, mval[1]);
+ glVertex2f(v2d->vert.xmax, mval[1]);
+ glEnd();
+ }
+}
+
+static void draw_solution(SpaceIpo *sipo)
+{
+ View2D *v2d= &sipo->v2d;
+ EditIpo *ei;
+ int a;
+
+ if (!(v2d->scroll & VERT_SCROLL)) return;
+
+ ei= sipo->editipo;
+ for(a=0; a<sipo->totipo; a++, ei++) {
+ if ISPOIN(ei, flag & IPO_VISIBLE, icu) {
+ cpack(ei->col);
+
+ /* DISPBITS ipos have 'multiple' values. */
+ if(ei->disptype==IPO_DISPBITS) {
+ int b, val= ei->icu->curval;
+
+ for (b=0; b<31; b++)
+ if (val & (1<<b))
+ draw_solution_line(v2d, b+1);
+ } else {
+ draw_solution_line(v2d, ei->icu->curval);
+ }
+ }
+ }
+}
+
+/* used for drawing timeline */
+void draw_view2d_numbers_horiz(int drawframes)
+{
+ float fac, fac2, dfac, val;
+
+ /* the numbers: convert ipogrid_startx and -dx to scroll coordinates */
+
+ fac= (ipogrid_startx- G.v2d->cur.xmin)/(G.v2d->cur.xmax-G.v2d->cur.xmin);
+ fac= G.v2d->mask.xmin+fac*(G.v2d->mask.xmax-G.v2d->mask.xmin);
+
+ dfac= (ipogrid_dx)/(G.v2d->cur.xmax-G.v2d->cur.xmin);
+ dfac= dfac*(G.v2d->mask.xmax-G.v2d->mask.xmin);
+
+ BIF_ThemeColor(TH_TEXT);
+ val= ipogrid_startx;
+ while(fac < G.v2d->mask.xmax) {
+
+ if(drawframes) {
+ ipomachtx= 1;
+ scroll_prstr(fac, 2.0+(float)(G.v2d->mask.ymin), val, 'h', 0);
+ }
+ else {
+ fac2= val/FPS;
+ scroll_prstr(fac, 2.0+(float)(G.v2d->mask.ymin), fac2, 'h', 0);
+ }
+
+ fac+= dfac;
+ val+= ipogrid_dx;
+ }
+}
+
+
+void drawscroll(int disptype)
+{
+ rcti vert, hor;
+ float fac, dfac, val, fac2, tim;
+ int darker, dark, light, lighter;
+
+ vert= (G.v2d->vert);
+ hor= (G.v2d->hor);
+
+ darker= -40;
+ dark= 0;
+ light= 20;
+ lighter= 50;
+
+ if((G.v2d->scroll & HOR_SCROLL) || (G.v2d->scroll & HOR_SCROLLO)) {
+
+ BIF_ThemeColorShade(TH_SHADE1, light);
+ glRecti(hor.xmin, hor.ymin, hor.xmax, hor.ymax);
+
+ /* slider */
+ fac= (G.v2d->cur.xmin- G.v2d->tot.xmin)/(G.v2d->tot.xmax-G.v2d->tot.xmin);
+ if(fac<0.0) fac= 0.0;
+ horxmin= hor.xmin+fac*(hor.xmax-hor.xmin);
+
+ fac= (G.v2d->cur.xmax- G.v2d->tot.xmin)/(G.v2d->tot.xmax-G.v2d->tot.xmin);
+ if(fac>1.0) fac= 1.0;
+ horxmax= hor.xmin+fac*(hor.xmax-hor.xmin);
+
+ if(horxmin > horxmax) horxmin= horxmax;
+
+ BIF_ThemeColorShade(TH_SHADE1, dark);
+ glRecti(horxmin, hor.ymin, horxmax, hor.ymax);
+
+ /* decoration bright line */
+ BIF_ThemeColorShade(TH_SHADE1, lighter);
+ sdrawline(hor.xmin, hor.ymax, hor.xmax, hor.ymax);
+
+ /* the numbers: convert ipogrid_startx and -dx to scroll coordinates */
+ fac= (ipogrid_startx- G.v2d->cur.xmin)/(G.v2d->cur.xmax-G.v2d->cur.xmin);
+ fac= hor.xmin+fac*(hor.xmax-hor.xmin);
+
+ dfac= (ipogrid_dx)/(G.v2d->cur.xmax-G.v2d->cur.xmin);
+ dfac= dfac*(hor.xmax-hor.xmin);
+
+ BIF_ThemeColor(TH_TEXT);
+ val= ipogrid_startx;
+ while(fac < hor.xmax) {
+
+ if(curarea->spacetype==SPACE_OOPS) {
+ /* Under no circumstances may the outliner/oops display numbers on its scrollbar
+ * Unfortunately, versions of Blender without this patch will hang on loading files with
+ * horizontally scrollable Outliners.
+ */
+ break;
+ }
+ else if(curarea->spacetype==SPACE_SEQ) {
+ SpaceSeq * sseq = curarea->spacedata.first;
+ if (sseq->flag & SEQ_DRAWFRAMES) {
+ ipomachtx = 1;
+ scroll_prstr(fac, 3.0+(float)(hor.ymin), val, 'h', disptype);
+ } else {
+ fac2= val/FPS;
+ tim= floor(fac2);
+ fac2= fac2-tim;
+ scroll_prstr(fac, 3.0+(float)(hor.ymin), tim+FPS*fac2/100.0, 'h', disptype);
+ }
+ }
+ else if (curarea->spacetype==SPACE_SOUND) {
+ SpaceSound *ssound= curarea->spacedata.first;
+
+ if(ssound->flag & SND_DRAWFRAMES) {
+ ipomachtx= 1;
+ scroll_prstr(fac, 3.0+(float)(hor.ymin), val, 'h', disptype);
+ }
+ else {
+ fac2= val/FPS;
+ scroll_prstr(fac, 3.0+(float)(hor.ymin), fac2, 'h', disptype);
+ }
+ }
+ else if (curarea->spacetype==SPACE_TIME) {
+ SpaceTime *stime= curarea->spacedata.first;
+
+ if(stime->flag & TIME_DRAWFRAMES) {
+ ipomachtx= 1;
+ scroll_prstr(fac, 3.0+(float)(hor.ymin), val, 'h', disptype);
+ }
+ else {
+ fac2= val/FPS;
+ scroll_prstr(fac, 3.0+(float)(hor.ymin), fac2, 'h', disptype);
+ }
+ }
+ else if (curarea->spacetype==SPACE_IPO) {
+ EditIpo *ei= get_active_editipo();
+
+ if(ei && ei->icu && ei->icu->driver) {
+ int adrcode= ei->icu->driver->adrcode;
+
+ if(adrcode==OB_ROT_X || adrcode==OB_ROT_Y || adrcode==OB_ROT_Z) {
+ scroll_prstr(fac, 3.0+(float)(hor.ymin), val, 'v', IPO_DISPDEGR);
+ }
+ else
+ scroll_prstr(fac, 3.0+(float)(hor.ymin), val, 'h', disptype);
+ }
+ else
+ scroll_prstr(fac, 3.0+(float)(hor.ymin), val, 'h', disptype);
+ }
+ else if (curarea->spacetype==SPACE_ACTION) {
+ SpaceAction *saction= curarea->spacedata.first;
+
+ if (saction->flag & SACTION_DRAWTIME) {
+ fac2= val/FPS;
+ scroll_prstr(fac, 3.0+(float)(hor.ymin), fac2, 'h', disptype);
+ }
+ else {
+ ipomachtx= 1;
+ scroll_prstr(fac, 3.0+(float)(hor.ymin), val, 'h', disptype);
+ }
+ }
+ else if (curarea->spacetype==SPACE_NLA) {
+ SpaceNla *snla= curarea->spacedata.first;
+
+ if (snla->flag & SNLA_DRAWTIME) {
+ fac2= val/FPS;
+ scroll_prstr(fac, 3.0+(float)(hor.ymin), fac2, 'h', disptype);
+ }
+ else {
+ ipomachtx= 1;
+ scroll_prstr(fac, 3.0+(float)(hor.ymin), val, 'h', disptype);
+ }
+ }
+ else {
+ scroll_prstr(fac, 3.0+(float)(hor.ymin), val, 'h', disptype);
+ }
+
+ fac+= dfac;
+ val+= ipogrid_dx;
+ }
+ }
+
+ if(G.v2d->scroll & VERT_SCROLL) {
+ BIF_ThemeColorShade(TH_SHADE1, light);
+ glRecti(vert.xmin, vert.ymin, vert.xmax, vert.ymax);
+
+ /* slider */
+ fac= (G.v2d->cur.ymin- G.v2d->tot.ymin)/(G.v2d->tot.ymax-G.v2d->tot.ymin);
+ if(fac<0.0) fac= 0.0;
+ vertymin= vert.ymin+fac*(vert.ymax-vert.ymin);
+
+ fac= (G.v2d->cur.ymax- G.v2d->tot.ymin)/(G.v2d->tot.ymax-G.v2d->tot.ymin);
+ if(fac>1.0) fac= 1.0;
+ vertymax= vert.ymin+fac*(vert.ymax-vert.ymin);
+
+ if(vertymin > vertymax) vertymin= vertymax;
+
+ BIF_ThemeColorShade(TH_SHADE1, dark);
+ glRecti(vert.xmin, vertymin, vert.xmax, vertymax);
+
+ /* decoration black line */
+ BIF_ThemeColorShade(TH_SHADE1, darker);
+ if(G.v2d->scroll & HOR_SCROLL)
+ sdrawline(vert.xmax, vert.ymin+SCROLLH, vert.xmax, vert.ymax);
+ else
+ sdrawline(vert.xmax, vert.ymin, vert.xmax, vert.ymax);
+
+ /* the numbers: convert ipogrid_starty and -dy to scroll coordinates */
+ fac= (ipogrid_starty- G.v2d->cur.ymin)/(G.v2d->cur.ymax-G.v2d->cur.ymin);
+ fac= vert.ymin+SCROLLH+fac*(vert.ymax-vert.ymin-SCROLLH);
+
+ dfac= (ipogrid_dy)/(G.v2d->cur.ymax-G.v2d->cur.ymin);
+ dfac= dfac*(vert.ymax-vert.ymin-SCROLLH);
+
+ if(curarea->spacetype==SPACE_OOPS);
+ else if(curarea->spacetype==SPACE_SEQ) {
+ BIF_ThemeColor(TH_TEXT);
+ val= ipogrid_starty;
+ fac+= 0.5*dfac;
+ while(fac < vert.ymax) {
+ scroll_prstr((float)(vert.xmax)-14.0, fac, val, 'v', disptype);
+ fac+= dfac;
+ val+= ipogrid_dy;
+ }
+ }
+ else if (curarea->spacetype==SPACE_NLA){
+ }
+ else if (curarea->spacetype==SPACE_ACTION){
+ /* No digits on vertical axis in action mode! */
+ }
+ else {
+ BIF_ThemeColor(TH_TEXT);
+ val= ipogrid_starty;
+ while(fac < vert.ymax) {
+ scroll_prstr((float)(vert.xmax)-14.0, fac, val, 'v', disptype);
+ fac+= dfac;
+ val+= ipogrid_dy;
+ }
+ }
+ }
+}
+
+static void draw_ipobuts(SpaceIpo *sipo)
+{
+ ScrArea *area= sipo->area;
+ View2D *v2d= &sipo->v2d;
+ Object *ob= OBACT;
+ uiBlock *block;
+ uiBut *but;
+ EditIpo *ei;
+ int a, y, sel, tot, ipobutx;
+ char naam[20];
+
+ if(area->winx< calc_ipobuttonswidth(area)) return;
+
+ if(sipo->butofs) {
+ tot= 30+IPOBUTY*sipo->totipo;
+ if(tot<area->winy) sipo->butofs= 0;
+ }
+
+ ipobutx = calc_ipobuttonswidth(area);
+
+ BIF_ThemeColor(TH_SHADE2);
+ glRects(v2d->mask.xmax, 0, area->winx, area->winy);
+
+ cpack(0x0);
+ sdrawline(v2d->mask.xmax, 0, v2d->mask.xmax, area->winy);
+
+ if(sipo->totipo==0) return;
+ if(sipo->editipo==0) return;
+
+ sprintf(naam, "ipowin %d", area->win);
+ block= uiNewBlock(&area->uiblocks, naam, UI_EMBOSSN, UI_HELV, area->win);
+
+ ei= sipo->editipo;
+ y= area->winy-30+sipo->butofs;
+
+ if(ob && sipo->blocktype==ID_KE) {
+ int icon;
+ if(ob->shapeflag & OB_SHAPE_LOCK) icon= ICON_PIN_HLT; else icon= ICON_PIN_DEHLT;
+ uiDefIconButBitS(block, TOG, OB_SHAPE_LOCK, B_SETKEY, icon,
+ v2d->mask.xmax+18,y,25,20, &ob->shapeflag, 0, 0, 0, 0, "Always show the current Shape for this Object");
+ y-= IPOBUTY;
+ }
+
+ for(a=0; a<sipo->totipo; a++, ei++, y-=IPOBUTY) {
+ // this button defines visiblity, bit zero of flag (IPO_VISIBLE)
+ but= uiDefButBitS(block, TOG, IPO_VISIBLE, a+1, ei->name, v2d->mask.xmax+18, y, ipobutx-15, IPOBUTY-1, &(ei->flag), 0, 0, 0, 0, "");
+ // no hilite, its not visible, but most of all the winmatrix is not correct later on...
+ uiButSetFlag(but, UI_TEXT_LEFT|UI_NO_HILITE);
+
+ // this fake button defines selection of curves
+ if(ei->icu) {
+ cpack(ei->col);
+
+ glRects(v2d->mask.xmax+8, y+2, v2d->mask.xmax+15, y+IPOBUTY-2);
+ sel= ei->flag & (IPO_SELECT + IPO_EDIT);
+
+ uiEmboss((float)(v2d->mask.xmax+8), (float)(y+2), (float)(v2d->mask.xmax+15), (float)(y+IPOBUTY-2), sel);
+
+ if(ei->icu->driver) {
+ cpack(0x0);
+ fdrawbox((float)v2d->mask.xmax+11, (float)y+8, (float)v2d->mask.xmax+12.5, (float)y+9.5);
+ }
+ }
+
+ if(ei->flag & IPO_ACTIVE) {
+ cpack(0x0);
+ fdrawbox(v2d->mask.xmax+7, y+1, v2d->mask.xmax+16, y+IPOBUTY-1);
+ }
+ }
+ uiDrawBlock(block);
+}
+
+static void draw_ipovertices(int sel)
+{
+ EditIpo *ei;
+ BezTriple *bezt;
+ float v1[2];
+ int val, ok, nr, a, b;
+
+ if(G.f & G_PICKSEL) return;
+
+ glPointSize(BIF_GetThemeValuef(TH_VERTEX_SIZE));
+
+ ei= G.sipo->editipo;
+ for(nr=0; nr<G.sipo->totipo; nr++, ei++) {
+ if ISPOIN(ei, flag & IPO_VISIBLE, icu) {
+
+ if(G.sipo->showkey) {
+ if(sel) BIF_ThemeColor(TH_TEXT_HI);
+ else BIF_ThemeColor(TH_TEXT);
+ } else if(ei->flag & IPO_EDIT) {
+ if(sel) BIF_ThemeColor(TH_VERTEX_SELECT);
+ else BIF_ThemeColor(TH_VERTEX);
+ } else {
+ if(sel) BIF_ThemeColor(TH_TEXT_HI);
+ else BIF_ThemeColor(TH_TEXT);
+
+ val= (ei->icu->flag & IPO_SELECT)!=0;
+ if(sel != val) continue;
+ }
+
+ /* We can't change the color in the middle of
+ * GL_POINTS because then Blender will segfault
+ * on TNT2 / Linux with NVidia's drivers
+ * (at least up to ver. 4349) */
+
+ a= ei->icu->totvert;
+ bezt= ei->icu->bezt;
+ bglBegin(GL_POINTS);
+
+ while(a--) {
+
+ /* IPO_DISPBITS is used for displaying layer ipo types as well as modes */
+ if(ei->disptype==IPO_DISPBITS) {
+ /*if (G.v2d->cur.xmin < bezt->vec[1][0] < G.v2d->cur.xmax) {*/
+ ok= 0;
+
+ if(ei->flag & IPO_EDIT) {
+ if( (bezt->f2 & 1) == sel ) ok= 1;
+ }
+ else ok= 1;
+
+ if(ok) {
+ val= bezt->vec[1][1];
+ b= 0;
+ v1[0]= bezt->vec[1][0];
+
+ while(b<31) {
+ if(val & (1<<b)) {
+ v1[1]= b+1;
+ bglVertex3fv(v1);
+ }
+ b++;
+ }
+ }
+ /*}*/
+ } else { /* normal non bit curves */
+ if(ei->flag & IPO_EDIT) {
+ if(ei->icu->ipo==IPO_BEZ) {
+ /* Draw the editmode hendels for a bezier curve */
+ if( (bezt->f1 & 1) == sel)/* && G.v2d->cur.xmin < bezt->vec[0][0] < G.v2d->cur.xmax)*/
+ bglVertex3fv(bezt->vec[0]);
+
+ if( (bezt->f3 & 1) == sel)/* && G.v2d->cur.xmin < bezt->vec[2][0] < G.v2d->cur.xmax)*/
+ bglVertex3fv(bezt->vec[2]);
+
+ }
+
+ if( (bezt->f2 & 1) == sel) /* && G.v2d->cur.xmin < bezt->vec[1][0] < G.v2d->cur.xmax)*/
+ bglVertex3fv(bezt->vec[1]);
+
+ }
+ else {
+ /* draw only if in bounds */
+ /*if (G.v2d->cur.xmin < bezt->vec[1][0] < G.v2d->cur.xmax)*/
+ bglVertex3fv(bezt->vec[1]);
+
+ }
+ }
+
+ bezt++;
+ }
+ bglEnd();
+ }
+ }
+
+ glPointSize(1.0);
+}
+
+static void draw_ipohandles(int sel)
+{
+ extern unsigned int nurbcol[];
+ EditIpo *ei;
+ BezTriple *bezt;
+ float *fp;
+ unsigned int *col;
+ int a, b;
+
+ if(sel) col= nurbcol+4;
+ else col= nurbcol;
+
+ ei= G.sipo->editipo;
+ for(a=0; a<G.sipo->totipo; a++, ei++) {
+ if ISPOIN4(ei, flag & IPO_VISIBLE, flag & IPO_EDIT, icu, disptype!=IPO_DISPBITS) {
+ if(ei->icu->ipo==IPO_BEZ) {
+ bezt= ei->icu->bezt;
+ b= ei->icu->totvert;
+ while(b--) {
+
+ if( (bezt->f2 & 1)==sel) {
+ fp= bezt->vec[0];
+ cpack(col[bezt->h1]);
+
+ glBegin(GL_LINE_STRIP);
+ glVertex2fv(fp); glVertex2fv(fp+3);
+ glEnd();
+ cpack(col[bezt->h2]);
+
+ glBegin(GL_LINE_STRIP);
+ glVertex2fv(fp+3); glVertex2fv(fp+6);
+ glEnd();
+ }
+ else if( (bezt->f1 & 1)==sel) {
+ fp= bezt->vec[0];
+ cpack(col[bezt->h1]);
+
+ glBegin(GL_LINE_STRIP);
+ glVertex2fv(fp); glVertex2fv(fp+3);
+ glEnd();
+ }
+ else if( (bezt->f3 & 1)==sel) {
+ fp= bezt->vec[1];
+ cpack(col[bezt->h2]);
+
+ glBegin(GL_LINE_STRIP);
+ glVertex2fv(fp); glVertex2fv(fp+3);
+ glEnd();
+ }
+
+ bezt++;
+ }
+ }
+ }
+ }
+}
+
+int pickselcode;
+
+static void init_pickselcode(void)
+{
+ pickselcode= 1;
+}
+
+static void draw_ipocurves(int sel)
+{
+ EditIpo *ei;
+ IpoCurve *icu;
+ BezTriple *bezt, *prevbezt;
+ float *fp, fac, data[120], v1[2], v2[2], v3[2], v4[2];
+ float cycdx=0, cycdy=0, cycxofs, cycyofs;
+ int a, b, resol, cycount, val, nr;
+
+
+ ei= G.sipo->editipo;
+ for(nr=0; nr<G.sipo->totipo; nr++, ei++) {
+ if ISPOIN3(ei, flag & IPO_VISIBLE, icu, icu->bezt) {
+
+ if(G.f & G_PICKSEL) {
+ glLoadName(pickselcode++);
+ val= 1;
+ }
+ else {
+ val= (ei->flag & (IPO_SELECT+IPO_EDIT))!=0;
+ val= (val==sel);
+ }
+
+ if(val) {
+
+ cycyofs= cycxofs= 0.0;
+ cycount= 1;
+
+ icu= ei->icu;
+
+ /* curve */
+ if(G.sipo->showkey) BIF_ThemeColor(TH_TEXT);
+ else cpack(ei->col);
+
+ /* cyclic */
+ if(icu->extrap & IPO_CYCL) {
+ cycdx= (icu->bezt+icu->totvert-1)->vec[1][0] - icu->bezt->vec[1][0];
+ cycdy= (icu->bezt+icu->totvert-1)->vec[1][1] - icu->bezt->vec[1][1];
+ if(cycdx>0.01) {
+
+ while(icu->bezt->vec[1][0]+cycxofs > G.v2d->cur.xmin) {
+ cycxofs-= cycdx;
+ if(icu->extrap & IPO_DIR) cycyofs-= cycdy;
+ cycount++;
+ }
+ bezt= icu->bezt+(icu->totvert-1);
+ fac= 0.0;
+ while(bezt->vec[1][0]+fac < G.v2d->cur.xmax) {
+ cycount++;
+ fac+= cycdx;
+ }
+ }
+ }
+
+ while(cycount--) {
+
+ if(ei->disptype==IPO_DISPBITS) {
+
+ /* lines */
+ cpack(ei->col);
+ bezt= icu->bezt;
+ a= icu->totvert;
+
+ while(a--) {
+ val= bezt->vec[1][1];
+ b= 0;
+
+ while(b<31) {
+ if(val & (1<<b)) {
+ v1[1]= b+1;
+
+ glBegin(GL_LINE_STRIP);
+ if(icu->extrap & IPO_CYCL) ;
+ else if(a==icu->totvert-1) {
+ v1[0]= G.v2d->cur.xmin+cycxofs;
+ glVertex2fv(v1);
+ }
+ v1[0]= bezt->vec[1][0]+cycxofs;
+ glVertex2fv(v1);
+
+ if(a) v1[0]= (bezt+1)->vec[1][0]+cycxofs;
+ else if(icu->extrap & IPO_CYCL) ;
+ else v1[0]= G.v2d->cur.xmax+cycxofs;
+
+ glVertex2fv(v1);
+ glEnd();
+ }
+ b++;
+ }
+ bezt++;
+ }
+
+ }
+ else {
+
+ b= icu->totvert-1;
+ prevbezt= icu->bezt;
+ bezt= prevbezt+1;
+
+ glBegin(GL_LINE_STRIP);
+
+ /* extrapolate to left? */
+ if( (icu->extrap & IPO_CYCL)==0) {
+ if(prevbezt->vec[1][0] > G.v2d->cur.xmin) {
+ v1[0]= G.v2d->cur.xmin;
+ if(icu->extrap==IPO_HORIZ || icu->ipo==IPO_CONST) v1[1]= prevbezt->vec[1][1];
+ else {
+ fac= (prevbezt->vec[0][0]-prevbezt->vec[1][0])/(prevbezt->vec[1][0]-v1[0]);
+ if(fac!=0.0) fac= 1.0/fac;
+ v1[1]= prevbezt->vec[1][1]-fac*(prevbezt->vec[0][1]-prevbezt->vec[1][1]);
+ }
+ glVertex2fv(v1);
+ }
+ }
+
+ if(b==0) {
+ v1[0]= prevbezt->vec[1][0]+cycxofs;
+ v1[1]= prevbezt->vec[1][1]+cycyofs;
+ glVertex2fv(v1);
+ }
+
+ while(b--) {
+ if(icu->ipo==IPO_CONST) {
+ v1[0]= prevbezt->vec[1][0]+cycxofs;
+ v1[1]= prevbezt->vec[1][1]+cycyofs;
+ glVertex2fv(v1);
+ v1[0]= bezt->vec[1][0]+cycxofs;
+ v1[1]= prevbezt->vec[1][1]+cycyofs;
+ glVertex2fv(v1);
+ }
+ else if(icu->ipo==IPO_LIN) {
+ v1[0]= prevbezt->vec[1][0]+cycxofs;
+ v1[1]= prevbezt->vec[1][1]+cycyofs;
+ glVertex2fv(v1);
+ }
+ else {
+ /* resol not depending on horizontal resolution anymore, drivers for example... */
+ if(icu->driver) resol= 32;
+ else resol= 3.0*sqrt(bezt->vec[1][0] - prevbezt->vec[1][0]);
+
+ if(resol<2) {
+ v1[0]= prevbezt->vec[1][0]+cycxofs;
+ v1[1]= prevbezt->vec[1][1]+cycyofs;
+ glVertex2fv(v1);
+ }
+ else {
+ if(resol>32) resol= 32;
+
+ v1[0]= prevbezt->vec[1][0]+cycxofs;
+ v1[1]= prevbezt->vec[1][1]+cycyofs;
+ v2[0]= prevbezt->vec[2][0]+cycxofs;
+ v2[1]= prevbezt->vec[2][1]+cycyofs;
+
+ v3[0]= bezt->vec[0][0]+cycxofs;
+ v3[1]= bezt->vec[0][1]+cycyofs;
+ v4[0]= bezt->vec[1][0]+cycxofs;
+ v4[1]= bezt->vec[1][1]+cycyofs;
+
+ correct_bezpart(v1, v2, v3, v4);
+
+ forward_diff_bezier(v1[0], v2[0], v3[0], v4[0], data, resol, 3);
+ forward_diff_bezier(v1[1], v2[1], v3[1], v4[1], data+1, resol, 3);
+
+ fp= data;
+ while(resol--) {
+ glVertex2fv(fp);
+ fp+= 3;
+ }
+ }
+ }
+ prevbezt= bezt;
+ bezt++;
+
+ /* last point? */
+ if(b==0) {
+ v1[0]= prevbezt->vec[1][0]+cycxofs;
+ v1[1]= prevbezt->vec[1][1]+cycyofs;
+ glVertex2fv(v1);
+ }
+ }
+
+ /* extrapolate to right? */
+ if( (icu->extrap & IPO_CYCL)==0) {
+ if(prevbezt->vec[1][0] < G.v2d->cur.xmax) {
+ v1[0]= G.v2d->cur.xmax;
+ if(icu->extrap==IPO_HORIZ || icu->ipo==IPO_CONST) v1[1]= prevbezt->vec[1][1];
+ else {
+ fac= (prevbezt->vec[2][0]-prevbezt->vec[1][0])/(prevbezt->vec[1][0]-v1[0]);
+ if(fac!=0.0) fac= 1.0/fac;
+ v1[1]= prevbezt->vec[1][1]-fac*(prevbezt->vec[2][1]-prevbezt->vec[1][1]);
+ }
+ glVertex2fv(v1);
+ }
+ }
+
+ glEnd();
+
+ }
+ cycxofs+= cycdx;
+ if(icu->extrap & IPO_DIR) cycyofs+= cycdy;
+ }
+
+ /* line that indicates the end of a speed curve */
+ if(G.sipo->blocktype==ID_CU && icu->adrcode==CU_SPEED) {
+ b= icu->totvert-1;
+ if(b) {
+ glColor3ub(0, 0, 0);
+ bezt= icu->bezt+b;
+ glBegin(GL_LINES);
+ glVertex2f(bezt->vec[1][0], 0.0);
+ glVertex2f(bezt->vec[1][0], bezt->vec[1][1]);
+ glEnd();
+ }
+ }
+ }
+ }
+ }
+}
+
+static int get_ipo_cfra_from_cfra(SpaceIpo * sipo, int cfra)
+{
+ if (sipo->blocktype==ID_SEQ) {
+ Sequence * seq = (Sequence*) sipo->from;
+
+ if (!seq) {
+ return cfra;
+ }
+
+ if ((seq->flag & SEQ_IPO_FRAME_LOCKED) != 0) {
+ return cfra;
+ } else {
+ float ctime= frame_to_float(cfra - seq->startdisp);
+ float div= (seq->enddisp - seq->startdisp)/100.0f;
+
+ if(div == 0.0) {
+ return 0;
+ } else {
+ return ctime / div;
+ }
+ }
+ } else {
+ return cfra;
+ }
+}
+
+static void draw_cfra(SpaceIpo *sipo)
+{
+ View2D *v2d= &sipo->v2d;
+ Object *ob;
+ float vec[2];
+
+ vec[0] = get_ipo_cfra_from_cfra(sipo, G.scene->r.cfra);
+ vec[0]*= G.scene->r.framelen;
+
+ vec[1]= v2d->cur.ymin;
+ glColor3ub(0x60, 0xc0, 0x40); // no theme, should be global color once...
+ glLineWidth(2.0);
+
+ glBegin(GL_LINE_STRIP);
+ glVertex2fv(vec);
+ vec[1]= v2d->cur.ymax;
+ glVertex2fv(vec);
+ glEnd();
+
+ if(sipo->blocktype==ID_OB) {
+ ob= (G.scene->basact) ? (G.scene->basact->object) : 0;
+ if(ob && ob->sf!=0.0 && (ob->ipoflag & OB_OFFS_OB) ) {
+ vec[0]-= ob->sf;
+
+ BIF_ThemeColorShade(TH_HILITE, -30);
+
+ glBegin(GL_LINE_STRIP);
+ glVertex2fv(vec);
+ vec[1]= G.v2d->cur.ymin;
+ glVertex2fv(vec);
+ glEnd();
+ }
+ }
+
+ glLineWidth(1.0);
+}
+
+static void draw_ipokey(SpaceIpo *sipo)
+{
+ IpoKey *ik;
+
+ glBegin(GL_LINES);
+ for (ik= sipo->ipokey.first; ik; ik= ik->next) {
+ if(ik->flag & 1) glColor3ub(0xFF, 0xFF, 0x99);
+ else glColor3ub(0xAA, 0xAA, 0x55);
+
+ glVertex2f(ik->val, G.v2d->cur.ymin);
+ glVertex2f(ik->val, G.v2d->cur.ymax);
+ }
+ glEnd();
+}
+
+static void draw_key(SpaceIpo *sipo, int visible)
+{
+ View2D *v2d= &sipo->v2d;
+ Key *key;
+ KeyBlock *kb, *act=NULL;
+ Object *ob= OBACT;
+ unsigned int col;
+ int index;
+
+ key= ob_get_key((Object *)sipo->from);
+ if(key==NULL)
+ return;
+
+ if(key->type== KEY_RELATIVE) if(visible==0) return;
+
+ for(index=1, kb= key->block.first; kb; kb= kb->next, index++) {
+ if(kb->type==KEY_LINEAR) setlinestyle(2);
+ else if(kb->type==KEY_BSPLINE) setlinestyle(4);
+ else setlinestyle(0);
+
+ if(kb==key->refkey) col= 0x22FFFF;
+ else col= 0xFFFF00;
+
+ if(ob->shapenr!=index) col-= 0x225500;
+ else act= kb;
+
+ cpack(col);
+
+ glBegin(GL_LINE_STRIP);
+ glVertex2f(v2d->cur.xmin, kb->pos);
+ glVertex2f(v2d->cur.xmax, kb->pos);
+ glEnd();
+
+ }
+
+ if(act) {
+ if(act->type==KEY_LINEAR) setlinestyle(2);
+ else if(act->type==KEY_BSPLINE) setlinestyle(4);
+ else setlinestyle(0);
+
+ if(act==key->refkey) cpack(0x22FFFF);
+ else cpack(0xFFFF00);
+
+ glBegin(GL_LINE_STRIP);
+ glVertex2f(v2d->cur.xmin, act->pos);
+ glVertex2f(v2d->cur.xmax, act->pos);
+ glEnd();
+ }
+
+ setlinestyle(0);
+}
+
+/* ************************** buttons *********************** */
+
+
+#define B_SETSPEED 3401
+#define B_MUL_IPO 3402
+#define B_TRANS_IPO 3403
+#define B_IPO_NONE 3404
+#define B_IPO_DRIVER 3405
+#define B_IPO_REDR 3406
+#define B_IPO_DEPCHANGE 3407
+#define B_IPO_DRIVERTYPE 3408
+
+static float hspeed= 0;
+
+static void boundbox_ipo_curves(SpaceIpo *si)
+{
+ EditIpo *ei;
+ Key *key;
+ KeyBlock *kb;
+ int a, first= 1;
+
+ ei= si->editipo;
+ if(ei==0)
+ return;
+
+ for(a=0; a<si->totipo; a++, ei++) {
+
+ if(ei->icu) {
+ if(ei->flag & IPO_VISIBLE) {
+
+ boundbox_ipocurve(ei->icu, 0);
+ if(first) {
+ si->v2d.tot= ei->icu->totrct;
+ first= 0;
+ }
+ else BLI_union_rctf(&(si->v2d.tot), &(ei->icu->totrct));
+ }
+ }
+ }
+ /* keylines? */
+ if(si->blocktype==ID_KE) {
+ key= ob_get_key((Object *)si->from);
+ if(key && key->block.first) {
+ kb= key->block.first;
+ if(kb->pos < si->v2d.tot.ymin) si->v2d.tot.ymin= kb->pos;
+ kb= key->block.last;
+ if(kb->pos > si->v2d.tot.ymax) si->v2d.tot.ymax= kb->pos;
+ }
+ }
+ si->tot= si->v2d.tot;
+}
+
+
+/* is used for both read and write... */
+static void ipo_editvertex_buts(uiBlock *block, SpaceIpo *si, float min, float max)
+{
+ Object *ob= OBACT;
+ EditIpo *ei;
+ BezTriple *bezt;
+ float median[3];
+ int a, b, tot, iskey=0;
+
+ median[0]= median[1]= median[2]= 0.0;
+ tot= 0;
+
+ ei= G.sipo->editipo;
+ for(a=0; a<G.sipo->totipo; a++, ei++) {
+
+ if ISPOIN(ei, flag & IPO_VISIBLE, icu) {
+ if( (ei->flag & IPO_EDIT) || G.sipo->showkey) {
+
+ if(ei->icu->bezt) {
+ bezt= ei->icu->bezt;
+ b= ei->icu->totvert;
+ while(b--) {
+ // all three selected
+ if(bezt->f2 & 1) {
+ VecAddf(median, median, bezt->vec[1]);
+ tot++;
+ }
+ else {
+ if(bezt->f1 & 1) {
+ VecAddf(median, median, bezt->vec[0]);
+ tot++;
+ }
+ if(bezt->f3 & 1) {
+ VecAddf(median, median, bezt->vec[2]);
+ tot++;
+ }
+ }
+ bezt++;
+ }
+
+ }
+ }
+ }
+ }
+ /* check for keys */
+ if(tot==0) {
+ if(G.sipo->blocktype==ID_KE) {
+ Key *key= ob_get_key((Object *)G.sipo->from);
+ KeyBlock *kb;
+
+ if(key==NULL || ob->shapenr==0) return;
+ iskey= 1;
+
+ kb= BLI_findlink(&key->block, ob->shapenr-1);
+ median[1]+= kb->pos;
+ tot++;
+ }
+ }
+ if(tot==0) return;
+
+ median[0] /= (float)tot;
+ median[1] /= (float)tot;
+ median[2] /= (float)tot;
+
+ if(block) { // buttons
+
+ VECCOPY(si->median, median);
+
+ uiBlockBeginAlign(block);
+ if(tot==1) {
+ if(iskey)
+ uiDefButF(block, NUM, B_TRANS_IPO, "Key Y:", 10, 80, 300, 19, &(si->median[1]), min, max, 10, 0, "");
+ else {
+ uiDefButF(block, NUM, B_TRANS_IPO, "Vertex X:", 10, 100, 150, 19, &(si->median[0]), min, max, 100, 0, "");
+ uiDefButF(block, NUM, B_TRANS_IPO, "Vertex Y:", 160, 100, 150, 19, &(si->median[1]), min, max, 100, 0, "");
+ }
+ }
+ else {
+ if(iskey)
+ uiDefButF(block, NUM, B_TRANS_IPO, "Median Key Y:", 10, 80, 300, 19, &(si->median[1]), min, max, 10, 0, "");
+ else {
+ uiDefButF(block, NUM, B_TRANS_IPO, "Median X:", 10, 100, 150, 19, &(si->median[0]), min, max, 100, 0, "");
+ uiDefButF(block, NUM, B_TRANS_IPO, "Median Y:", 160, 100, 150, 19, &(si->median[1]), min, max, 100, 0, "");
+ }
+ }
+ }
+ else if(iskey) { // apply
+ VecSubf(median, si->median, median);
+
+ if(G.sipo->blocktype==ID_KE) {
+ Key *key= ob_get_key((Object *)G.sipo->from);
+ KeyBlock *kb;
+
+ if(key==NULL || ob->shapenr==0) return;
+
+ kb= BLI_findlink(&key->block, ob->shapenr-1);
+ kb->pos+= median[1];
+ tot++;
+
+ sort_keys(key);
+ }
+ }
+ else {
+
+ VecSubf(median, si->median, median);
+
+ ei= G.sipo->editipo;
+ for(a=0; a<G.sipo->totipo; a++, ei++) {
+
+ if ISPOIN(ei, flag & IPO_VISIBLE, icu) {
+ if( (ei->flag & IPO_EDIT) || G.sipo->showkey) {
+
+ if(ei->icu->bezt) {
+ bezt= ei->icu->bezt;
+ b= ei->icu->totvert;
+ while(b--) {
+ // all three selected
+ if(bezt->f2 & 1) {
+ VecAddf(bezt->vec[0], bezt->vec[0], median);
+ VecAddf(bezt->vec[1], bezt->vec[1], median);
+ VecAddf(bezt->vec[2], bezt->vec[2], median);
+ }
+ else {
+ if(bezt->f1 & 1) {
+ VecAddf(bezt->vec[0], bezt->vec[0], median);
+ }
+ if(bezt->f3 & 1) {
+ VecAddf(bezt->vec[2], bezt->vec[2], median);
+ }
+ }
+ bezt++;
+ }
+
+ }
+ }
+ }
+ }
+ }
+}
+
+void do_ipobuts(unsigned short event)
+{
+ Object *ob= OBACT;
+ EditIpo *ei;
+
+ if(G.sipo->from==NULL) return;
+
+ switch(event) {
+ case B_IPO_REDR:
+ ei= get_active_editipo();
+ if(ei) {
+ if(ei->icu->driver) {
+ if (ei->icu->driver->type == IPO_DRIVER_TYPE_PYTHON) {
+ /* first del pydriver's global dict, just in case
+ * an available pydrivers.py module needs to be reloaded */
+ BPY_pydriver_update();
+ /* eval user's expression once for validity; update DAG */
+ BPY_pydriver_eval(ei->icu->driver);
+ DAG_scene_sort(G.scene);
+ }
+ else if(G.sipo->blocktype==ID_KE || G.sipo->blocktype==ID_AC)
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ else
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_OB);
+ }
+ }
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+ case B_SETSPEED:
+ set_speed_editipo(hspeed);
+ break;
+ case B_MUL_IPO:
+ scale_editipo();
+ allqueue(REDRAWIPO, 0);
+ break;
+ case B_TRANS_IPO:
+ ipo_editvertex_buts(NULL, G.sipo, 0.0, 0.0);
+ editipo_changed(G.sipo, 1);
+ allqueue(REDRAWIPO, 0);
+ break;
+ case B_SETKEY:
+ ob->shapeflag &= ~OB_SHAPE_TEMPLOCK;
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ break;
+ case B_IPO_DRIVER:
+ ei= get_active_editipo();
+ if(ei) {
+ if(ei->icu==NULL) {
+ ei->icu= verify_ipocurve(G.sipo->from, G.sipo->blocktype, G.sipo->actname, G.sipo->constname, ei->adrcode);
+ if (!ei->icu) {
+ error("Could not add a driver to this curve, may be linked data!");
+ break;
+ }
+ ei->flag |= IPO_SELECT;
+ ei->icu->flag= ei->flag;
+ }
+ if(ei->icu->driver) {
+ MEM_freeN(ei->icu->driver);
+ ei->icu->driver= NULL;
+ if(ei->icu->bezt==NULL) {
+ BLI_remlink( &(G.sipo->ipo->curve), ei->icu);
+ free_ipo_curve(ei->icu);
+ ei->icu= NULL;
+ }
+ }
+ else {
+ ei->icu->driver= MEM_callocN(sizeof(IpoDriver), "ipo driver");
+ ei->icu->driver->blocktype= ID_OB;
+ ei->icu->driver->adrcode= OB_LOC_X;
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ DAG_scene_sort(G.scene);
+
+ BIF_undo_push("Add/Remove Ipo driver");
+ }
+ break;
+ case B_IPO_DRIVERTYPE:
+ ei= get_active_editipo();
+ if(ei) {
+ if(ei->icu->driver) {
+ IpoDriver *driver= ei->icu->driver;
+
+ if(driver->type == IPO_DRIVER_TYPE_PYTHON) {
+ /* pydriver expression shouldn't reference own ob,
+ * so we need to store ob ptr to check against it */
+ driver->ob= ob;
+ }
+ else {
+ driver->ob= NULL;
+ driver->blocktype= ID_OB;
+ driver->adrcode= OB_LOC_X;
+ driver->flag &= ~IPO_DRIVER_FLAG_INVALID;
+ }
+ }
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ DAG_scene_sort(G.scene);
+
+ BIF_undo_push("Change Ipo driver type");
+ }
+ break;
+ case B_IPO_DEPCHANGE:
+ ei= get_active_editipo();
+ if(ei) {
+ if(ei->icu->driver) {
+ IpoDriver *driver= ei->icu->driver;
+
+ if(driver->type == IPO_DRIVER_TYPE_PYTHON) {
+ }
+ else {
+ if(driver->ob) {
+ if(ob==driver->ob) {
+ error("Cannot assign a Driver to own Object");
+ driver->ob= NULL;
+ }
+ else {
+ /* check if type is still OK */
+ if(driver->ob->type==OB_ARMATURE && driver->blocktype==ID_AR);
+ else driver->blocktype= ID_OB;
+ }
+ }
+ }
+ DAG_scene_sort(G.scene);
+
+ if(G.sipo->blocktype==ID_KE || G.sipo->blocktype==ID_AC)
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ else
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_OB);
+ }
+ }
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ break;
+ }
+}
+
+static char *ipodriver_modeselect_pup(Object *ob)
+{
+ static char string[265];
+ char tmpstr[64];
+ char formatstring[64];
+
+ strcpy(string, "Driver type: %t");
+
+ strcpy(formatstring, "|%s %%x%d %%i%d");
+
+ if(ob) {
+ sprintf(tmpstr,formatstring,"Object",ID_OB, ICON_OBJECT);
+ strcat(string,tmpstr);
+ }
+ if(ob && ob->type==OB_ARMATURE) {
+ sprintf(tmpstr,formatstring,"Pose",ID_AR, ICON_POSE_DEHLT);
+ strcat(string,tmpstr);
+ }
+
+ return (string);
+}
+
+static char *ipodriver_channelselect_pup(void)
+{
+ static char string[1024];
+ char *tmp;
+
+ strcpy(string, "Driver channel: %t");
+ tmp= string+strlen(string);
+
+ tmp+= sprintf(tmp, "|Loc X %%x%d", OB_LOC_X);
+ tmp+= sprintf(tmp, "|Loc Y %%x%d", OB_LOC_Y);
+ tmp+= sprintf(tmp, "|Loc Z %%x%d", OB_LOC_Z);
+ tmp+= sprintf(tmp, "|Rot X %%x%d", OB_ROT_X);
+ tmp+= sprintf(tmp, "|Rot Y %%x%d", OB_ROT_Y);
+ tmp+= sprintf(tmp, "|Rot Z %%x%d", OB_ROT_Z);
+ tmp+= sprintf(tmp, "|Scale X %%x%d", OB_SIZE_X);
+ tmp+= sprintf(tmp, "|Scale Y %%x%d", OB_SIZE_Y);
+ tmp+= sprintf(tmp, "|Scale Z %%x%d", OB_SIZE_Z);
+ tmp+= sprintf(tmp, "|Rotation Differance %%x%d", OB_ROT_DIFF);
+
+ return (string);
+}
+
+static void ipo_panel_properties(short cntrl) // IPO_HANDLER_PROPERTIES
+{
+ extern int totipo_curve; // editipo.c
+ uiBlock *block;
+ EditIpo *ei;
+ char name[48];
+
+ block= uiNewBlock(&curarea->uiblocks, "ipo_panel_properties", UI_EMBOSS, UI_HELV, curarea->win);
+ uiPanelControl(UI_PNL_SOLID | UI_PNL_CLOSE | cntrl);
+ uiSetPanelHandler(IPO_HANDLER_PROPERTIES); // for close and esc
+ if(uiNewPanel(curarea, block, "Transform Properties", "Ipo", 10, 230, 318, 204)==0) return;
+
+ /* this is new panel height, newpanel doesnt force new size on existing panels */
+ uiNewPanelHeight(block, 204);
+
+ /* driver buttons first */
+ ei= get_active_editipo();
+ if(ei) {
+
+ sprintf(name, "Driven Channel: %s", ei->name);
+ uiDefBut(block, LABEL, 0, name, 10, 265, 200, 19, NULL, 1.0, 0.0, 0, 0, "");
+
+ if(ei->icu && ei->icu->driver) {
+ IpoDriver *driver= ei->icu->driver;
+
+ uiDefBut(block, BUT, B_IPO_DRIVER, "Remove", 210,265,100,20, NULL, 0.0f, 0.0f, 0, 0, "Remove Driver for this Ipo Channel");
+
+ uiBlockBeginAlign(block);
+ uiDefIconButS(block, TOG, B_IPO_DRIVERTYPE, ICON_PYTHON, 10,240,25,20, &driver->type, (float)IPO_DRIVER_TYPE_NORMAL, (float)IPO_DRIVER_TYPE_PYTHON, 0, 0, "Use a one-line Python Expression as Driver");
+
+ if(driver->type == IPO_DRIVER_TYPE_PYTHON) {
+ uiDefBut(block, TEX, B_IPO_REDR, "", 35,240,275,20, driver->name, 0, 127, 0, 0, "Python Expression");
+ uiBlockEndAlign(block);
+ if(driver->flag & IPO_DRIVER_FLAG_INVALID) {
+ uiDefBut(block, LABEL, 0, "Error: invalid Python expression",
+ 5,215,230,19, NULL, 0, 0, 0, 0, "");
+ }
+ }
+ else {
+ uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_IPO_DEPCHANGE, "OB:", 35, 240, 125, 20, &(driver->ob), "Driver Object");
+ if(driver->ob) {
+ int icon=ICON_OBJECT;
+
+ if(driver->ob->type==OB_ARMATURE && driver->blocktype==ID_AR) {
+ icon = ICON_POSE_DEHLT;
+ uiDefBut(block, TEX, B_IPO_REDR, "BO:", 10,220,150,20, driver->name, 0, 31, 0, 0, "Bone name");
+
+ if(driver->adrcode==OB_ROT_DIFF)
+ uiDefBut(block, TEX, B_IPO_REDR, "BO:", 10,200,150,20, driver->name+DRIVER_NAME_OFFS, 0, 31, 0, 0, "Bone name for angular reference");
+
+ }
+ else driver->blocktype= ID_OB; /* safety when switching object button */
+
+ uiBlockBeginAlign(block);
+ uiDefIconTextButS(block, MENU, B_IPO_DEPCHANGE, icon,
+ ipodriver_modeselect_pup(driver->ob), 165,240,145,20, &(driver->blocktype), 0, 0, 0, 0, "Driver type");
+
+ uiDefButS(block, MENU, B_IPO_REDR,
+ ipodriver_channelselect_pup(), 165,220,145,20, &(driver->adrcode), 0, 0, 0, 0, "Driver channel");
+ }
+ uiBlockEndAlign(block);
+ }
+ }
+ else {
+ uiDefBut(block, BUT, B_IPO_DRIVER, "Add Driver", 210,265,100,19, NULL, 0.0f, 0.0f, 0, 0, "Create a Driver for this Ipo Channel");
+ }
+ }
+ else
+ uiDefBut(block, LABEL, 0, " ", 10, 265, 150, 19, NULL, 1.0, 0.0, 0, 0, "");
+
+ boundbox_ipo_curves(G.sipo); // should not be needed... transform/draw calls should update
+
+ /* note ranges for buttons below are idiot... we need 2 ranges, one for sliding scale, one for real clip */
+ if(G.sipo->ipo && G.sipo->ipo->curve.first && totipo_curve) {
+ extern int totipo_vertsel; // editipo.c
+ uiDefBut(block, LABEL, 0, "Visible curves", 160, 200, 150, 19, NULL, 1.0, 0.0, 0, 0, "");
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_MUL_IPO, "Xmin:", 10, 180, 150, 19, &G.sipo->tot.xmin, G.sipo->tot.xmin-1000.0, MAXFRAMEF, 100, 0, "");
+ uiDefButF(block, NUM, B_MUL_IPO, "Xmax:", 160, 180, 150, 19, &G.sipo->tot.xmax, G.sipo->tot.ymin-1000.0, MAXFRAMEF, 100, 0, "");
+
+ uiDefButF(block, NUM, B_MUL_IPO, "Ymin:", 10, 160, 150, 19, &G.sipo->tot.ymin, G.sipo->tot.ymin-1000.0, 5000.0, 100, 0, "");
+ uiDefButF(block, NUM, B_MUL_IPO, "Ymax:", 160, 160, 150, 19, &G.sipo->tot.ymax, G.sipo->tot.ymin-1000.0, 5000.0, 100, 0, "");
+
+ /* SPEED BUTTON */
+ if(totipo_vertsel) {
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_IPO_NONE, "Speed:", 10,130,150,19, &hspeed, 0.0, 180.0, 1, 0, "");
+ uiDefBut(block, BUT, B_SETSPEED,"SET", 160,130,50,19, 0, 0, 0, 0, 0, "");
+ }
+ }
+
+ /* this one also does keypositions */
+ if(G.sipo->ipo) ipo_editvertex_buts(block, G.sipo, -10000, MAXFRAMEF);
+}
+
+static void ipo_blockhandlers(ScrArea *sa)
+{
+ SpaceIpo *sipo= sa->spacedata.first;
+ short a;
+
+ /* warning; blocks need to be freed each time, handlers dont remove (for ipo moved to drawipospace) */
+
+ for(a=0; a<SPACE_MAXHANDLER; a+=2) {
+ switch(sipo->blockhandler[a]) {
+
+ case IPO_HANDLER_PROPERTIES:
+ ipo_panel_properties(sipo->blockhandler[a+1]);
+ break;
+
+ }
+ /* clear action value for event */
+ sipo->blockhandler[a+1]= 0;
+ }
+ uiDrawBlocksPanels(sa, 0);
+
+}
+
+
+void drawipospace(ScrArea *sa, void *spacedata)
+{
+ SpaceIpo *sipo= sa->spacedata.first;
+ View2D *v2d= &sipo->v2d;
+ EditIpo *ei;
+ float col[3];
+ int ofsx, ofsy, a, disptype;
+
+ bwin_clear_viewmat(sa->win); /* clear buttons view */
+ glLoadIdentity();
+
+ uiFreeBlocksWin(&sa->uiblocks, sa->win); /* for panel handler to work */
+
+ test_editipo(0); /* test if current editipo is correct, make_editipo sets v2d->cur, call here because of calc_ipobuttonswidth() */
+
+ v2d->hor.xmax+=calc_ipobuttonswidth(sa);
+ calc_scrollrcts(sa, G.v2d, sa->winx, sa->winy);
+
+ BIF_GetThemeColor3fv(TH_BACK, col);
+ glClearColor(col[0], col[1], col[2], 0.0);
+
+ if (sipo->pin)
+ glClearColor(col[0]+0.05,col[1],col[2], 0.0); // litepink
+ else
+ glClearColor(col[0],col[1],col[2], 0.0);
+
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ if(sa->winx>SCROLLB+10 && sa->winy>SCROLLH+10) {
+ if(v2d->scroll) {
+ ofsx= sa->winrct.xmin; // ivm mywin
+ ofsy= sa->winrct.ymin;
+ glViewport(ofsx+v2d->mask.xmin, ofsy+v2d->mask.ymin, ( ofsx+v2d->mask.xmax-1)-(ofsx+v2d->mask.xmin)+1, ( ofsy+v2d->mask.ymax-1)-( ofsy+v2d->mask.ymin)+1);
+ glScissor(ofsx+v2d->mask.xmin, ofsy+v2d->mask.ymin, ( ofsx+v2d->mask.xmax-1)-(ofsx+v2d->mask.xmin)+1, ( ofsy+v2d->mask.ymax-1)-( ofsy+v2d->mask.ymin)+1);
+ }
+ }
+
+ myortho2(v2d->cur.xmin, v2d->cur.xmax, v2d->cur.ymin, v2d->cur.ymax);
+
+ if(sipo->editipo) {
+
+ /* correct scale for degrees? */
+ disptype= -1;
+ ei= sipo->editipo;
+ for(a=0; a<sipo->totipo; a++, ei++) {
+ if(ei->flag & IPO_VISIBLE) {
+ if(disptype== -1) disptype= ei->disptype;
+ else if(disptype!=ei->disptype) disptype= 0;
+ }
+ }
+
+ calc_ipogrid();
+ draw_ipogrid();
+
+ draw_cfra(sipo);
+
+ /* ipokeys */
+ if(sipo->showkey) {
+ if(sipo->ipokey.first==0) make_ipokey();
+ else update_ipokey_val();
+ draw_ipokey(sipo);
+ }
+
+ if(sipo->blocktype==ID_KE) {
+ ei= sipo->editipo;
+ draw_key(sipo, ei->flag & IPO_VISIBLE);
+ }
+
+ /* map ipo-points for drawing if scaled ipo */
+ if (NLA_IPO_SCALED)
+ actstrip_map_ipo_keys(OBACT, sipo->ipo, 0, 0);
+
+ /* draw deselect */
+ draw_ipocurves(0);
+ draw_ipohandles(0);
+ draw_ipovertices(0);
+
+ /* draw select */
+ draw_ipocurves(1);
+ draw_ipohandles(1);
+ draw_ipovertices(1);
+
+ /* undo mapping of ipo-points for drawing if scaled ipo */
+ if (NLA_IPO_SCALED)
+ actstrip_map_ipo_keys(OBACT, sipo->ipo, 1, 0);
+
+ /* Draw 'curtains' for preview */
+ draw_anim_preview_timespace();
+
+ /* draw markers */
+ draw_markers_timespace(0);
+
+ /* restore viewport */
+ mywinset(sa->win);
+
+ if(sa->winx>SCROLLB+10 && sa->winy>SCROLLH+10) {
+
+ /* ortho at pixel level sa */
+ myortho2(-0.375, sa->winx-0.375, -0.375, sa->winy-0.375);
+
+ if(v2d->scroll) {
+ drawscroll(disptype);
+ draw_solution(sipo);
+ }
+
+ draw_ipobuts(sipo);
+ }
+ }
+ else {
+ calc_ipogrid();
+ draw_ipogrid();
+ }
+
+ myortho2(-0.375, sa->winx-0.375, -0.375, sa->winy-0.375);
+ draw_area_emboss(sa);
+
+ /* it is important to end a view in a transform compatible with buttons */
+ bwin_scalematrix(sa->win, sipo->blockscale, sipo->blockscale, sipo->blockscale);
+ /* only draw panels when relevant */
+ if(sipo->editipo) ipo_blockhandlers(sa);
+
+ sa->win_swap= WIN_BACK_OK;
+}
+
+void scroll_ipobuts()
+{
+ int tot;
+ short yo, mval[2];
+
+ tot= 30+IPOBUTY*G.sipo->totipo;
+ if(tot<curarea->winy) return;
+
+ getmouseco_areawin(mval);
+ yo= mval[1];
+
+ while(get_mbut()&M_MOUSE) {
+ getmouseco_areawin(mval);
+ if(mval[1]!=yo) {
+ G.sipo->butofs+= (mval[1]-yo);
+ if(G.sipo->butofs<0) G.sipo->butofs= 0;
+ else if(G.sipo->butofs+curarea->winy>tot) G.sipo->butofs= tot-curarea->winy;
+
+ scrarea_do_windraw(curarea);
+ screen_swapbuffers();
+
+ yo= mval[1];
+ }
+ else BIF_wait_for_statechange();
+ }
+}
+
+/* total mess function, especially with mousewheel, needs cleanup badly (ton) */
+int view2dzoom(unsigned short event)
+{
+ ScrArea *sa;
+ float fac, dx, dy, wtemp;
+ short mval[2], mvalo[2];
+ short is_wheel= (event==WHEELUPMOUSE) || (event==WHEELDOWNMOUSE);
+
+ getmouseco_areawin(mvalo);
+ mval[0]= mvalo[0];
+ mval[1]= mvalo[1];
+
+ while( (get_mbut()&(L_MOUSE|M_MOUSE)) || is_wheel ) {
+
+ /* regular mousewheel: zoom regular
+ * alt-shift mousewheel: zoom y only
+ * alt-ctrl mousewheel: zoom x only
+ */
+ if (event==WHEELUPMOUSE) {
+ if(U.uiflag & USER_WHEELZOOMDIR)
+ wtemp = -0.0375;
+ else
+ wtemp = 0.03;
+ if(curarea->spacetype!=SPACE_BUTS) wtemp*= 3;
+
+ dx= (float)(wtemp*(G.v2d->cur.xmax-G.v2d->cur.xmin));
+ dy= (float)(wtemp*(G.v2d->cur.ymax-G.v2d->cur.ymin));
+
+ switch (G.qual & (LR_CTRLKEY|LR_SHIFTKEY|LR_ALTKEY)) {
+ case 0:
+ break;
+ case (LR_SHIFTKEY|LR_ALTKEY):
+ dx = 0;
+ break;
+ case (LR_CTRLKEY|LR_ALTKEY):
+ dy = 0;
+ break;
+ default:
+ if(curarea->spacetype==SPACE_BUTS); // exception
+ else return 0;
+ break;
+ }
+ }
+ else if (event==WHEELDOWNMOUSE) {
+ if(U.uiflag & USER_WHEELZOOMDIR)
+ wtemp = 0.03;
+ else
+ wtemp = -0.0375;
+ if(curarea->spacetype!=SPACE_BUTS) wtemp*= 3;
+
+ dx= (float)(wtemp*(G.v2d->cur.xmax-G.v2d->cur.xmin));
+ dy= (float)(wtemp*(G.v2d->cur.ymax-G.v2d->cur.ymin));
+
+ switch (G.qual & (LR_CTRLKEY|LR_SHIFTKEY|LR_ALTKEY)) {
+ case 0:
+ break;
+ case (LR_SHIFTKEY|LR_ALTKEY):
+ dx = 0;
+ break;
+ case (LR_CTRLKEY|LR_ALTKEY):
+ dy = 0;
+ break;
+ default:
+ if(curarea->spacetype==SPACE_BUTS);
+ else return 0;
+ break;
+ }
+ }
+ else {
+ getmouseco_areawin(mval);
+ if(U.viewzoom==USER_ZOOM_SCALE) {
+ float dist;
+
+ dist = (G.v2d->mask.xmax - G.v2d->mask.xmin)/2.0;
+ dx= 1.0-(fabs(mvalo[0]-dist)+2.0)/(fabs(mval[0]-dist)+2.0);
+ dx*= 0.5*(G.v2d->cur.xmax-G.v2d->cur.xmin);
+
+ dist = (G.v2d->mask.ymax - G.v2d->mask.ymin)/2.0;
+ dy= 1.0-(fabs(mvalo[1]-dist)+2.0)/(fabs(mval[1]-dist)+2.0);
+ dy*= 0.5*(G.v2d->cur.ymax-G.v2d->cur.ymin);
+
+ }
+ else {
+ fac= 0.01*(mval[0]-mvalo[0]);
+ dx= fac*(G.v2d->cur.xmax-G.v2d->cur.xmin);
+ fac= 0.01*(mval[1]-mvalo[1]);
+ dy= fac*(G.v2d->cur.ymax-G.v2d->cur.ymin);
+
+ if(U.viewzoom==USER_ZOOM_CONT) {
+ dx/= 20.0;
+ dy/= 20.0;
+ }
+ }
+ }
+
+ if (ELEM(event, WHEELUPMOUSE, WHEELDOWNMOUSE) || mval[0]!=mvalo[0] || mval[1]!=mvalo[1]) {
+
+ if(U.viewzoom!=USER_ZOOM_CONT) {
+ mvalo[0]= mval[0];
+ mvalo[1]= mval[1];
+ }
+
+ if( ELEM(curarea->spacetype, SPACE_NLA, SPACE_ACTION) ) {
+ if(mvalo[0] < G.v2d->mask.xmin) {
+ G.v2d->cur.ymin+= dy;
+ G.v2d->cur.ymax-= dy;
+ }
+ else {
+ G.v2d->cur.xmin+= dx;
+ G.v2d->cur.xmax-= dx;
+ }
+ }
+ else if (ELEM(curarea->spacetype, SPACE_SOUND, SPACE_TIME)) {
+ G.v2d->cur.xmin+= dx;
+ G.v2d->cur.xmax-= dx;
+ }
+ else if (curarea->spacetype == SPACE_SEQ) {
+ /* less sensitivity on y scale */
+ G.v2d->cur.xmin+= dx;
+ G.v2d->cur.xmax-= dx;
+ if (!(ELEM(event, WHEELUPMOUSE, WHEELDOWNMOUSE))) {
+ G.v2d->cur.ymin+= dy/2;
+ G.v2d->cur.ymax-= dy/2;
+ }
+ }
+ else {
+ G.v2d->cur.xmin+= dx;
+ G.v2d->cur.xmax-= dx;
+ G.v2d->cur.ymin+= dy;
+ G.v2d->cur.ymax-= dy;
+ }
+
+ test_view2d(G.v2d, curarea->winx, curarea->winy); /* cur min max rects */
+
+ sa= curarea; /* now when are you going to kill this one! */
+ view2d_do_locks(curarea, V2D_LOCK_COPY|V2D_LOCK_REDRAW);
+ areawinset(sa->win);
+
+ scrarea_do_windraw(curarea);
+ screen_swapbuffers();
+ }
+ else BIF_wait_for_statechange();
+ /* return if we were using the mousewheel
+ */
+ if ( is_wheel ) return 1;
+ }
+ return 1;
+}
+
+void center_currframe(void)
+{
+ /* place the current frame in the
+ * center of the 2D window.
+ */
+ float width;
+
+ width = G.v2d->cur.xmax - G.v2d->cur.xmin;
+ G.v2d->cur.xmin = CFRA - 0.5*(width);
+ G.v2d->cur.xmax = CFRA + 0.5*(width);
+
+ test_view2d(G.v2d, curarea->winx, curarea->winy);
+ view2d_do_locks(curarea, V2D_LOCK_COPY);
+
+ scrarea_queue_winredraw(curarea);
+}
+
+/* total mess function, especially with mousewheel, needs cleanup badly (ton) */
+int view2dmove(unsigned short event)
+{
+ /* return 1 when something was done */
+ float facx=0.0, facy=0.0, dx, dy, left=1.0, right=1.0;
+ short mval[2], mvalo[2], leftret=1, mousebut;
+ short is_wheel= (event==WHEELUPMOUSE) || (event==WHEELDOWNMOUSE);
+ int oldcursor, cursor;
+ Window *win;
+
+ /* when wheel is used, we only draw it once */
+
+ /* try to do some zooming if the
+ * middlemouse and ctrl are pressed
+ * or if the mousewheel is being used.
+ * Return if zooming was done.
+ */
+
+ /* check for left mouse / right mouse button select */
+ if (U.flag & USER_LMOUSESELECT) mousebut = R_MOUSE;
+ else mousebut = L_MOUSE;
+
+ if ( (G.qual & LR_CTRLKEY) || is_wheel ) {
+ /* patch for oops & buttonswin, standard scroll no zoom */
+ if(curarea->spacetype==SPACE_OOPS) {
+ SpaceOops *soops= curarea->spacedata.first;
+ if(soops->type==SO_OUTLINER);
+ else if (view2dzoom(event)) {
+ return 0;
+ }
+ }
+ else if(curarea->spacetype==SPACE_BUTS && (G.qual & LR_CTRLKEY)==0);
+ else if (view2dzoom(event)) {
+ return 0;
+ }
+ }
+
+ /* test where mouse is */
+ getmouseco_areawin(mvalo);
+ /* initialize this too */
+ mval[0]= mvalo[0];
+ mval[1]= mvalo[1];
+
+ if ELEM7(curarea->spacetype, SPACE_IPO, SPACE_SEQ, SPACE_OOPS, SPACE_SOUND, SPACE_ACTION, SPACE_NLA, SPACE_TIME) {
+
+ if( BLI_in_rcti(&G.v2d->mask, (int)mvalo[0], (int)mvalo[1]) ) {
+ facx= (G.v2d->cur.xmax-G.v2d->cur.xmin)/(float)(G.v2d->mask.xmax-G.v2d->mask.xmin);
+ facy= (G.v2d->cur.ymax-G.v2d->cur.ymin)/(float)(G.v2d->mask.ymax-G.v2d->mask.ymin);
+ }
+ /* stoopid exception to allow scroll in lefthand side */
+ else if(curarea->spacetype==SPACE_ACTION && BLI_in_rcti(&G.v2d->mask, ACTWIDTH+(int)mvalo[0], (int)mvalo[1]) ) {
+ facx= 0.0f;
+ facy= (G.v2d->cur.ymax-G.v2d->cur.ymin)/(float)(G.v2d->mask.ymax-G.v2d->mask.ymin);
+ }
+ else if(curarea->spacetype==SPACE_NLA && BLI_in_rcti(&G.v2d->mask, NLAWIDTH+(int)mvalo[0], (int)mvalo[1]) ) {
+ facx= 0.0f;
+ facy= (G.v2d->cur.ymax-G.v2d->cur.ymin)/(float)(G.v2d->mask.ymax-G.v2d->mask.ymin);
+ }
+ else if(IN_2D_VERT_SCROLL((int)mvalo)) {
+ facy= -(G.v2d->tot.ymax-G.v2d->tot.ymin)/(float)(G.v2d->mask.ymax-G.v2d->mask.ymin);
+ if(get_mbut() & mousebut) {
+ /* which part of scrollbar should move? */
+ if(mvalo[1]< (vertymin+vertymax)/2 ) right= 0.0;
+ else left= 0.0;
+ leftret= 0;
+ }
+ if(is_wheel)
+ facy= -facy;
+ }
+ else if(IN_2D_HORIZ_SCROLL((int)mvalo)) {
+ facx= -(G.v2d->tot.xmax-G.v2d->tot.xmin)/(float)(G.v2d->mask.xmax-G.v2d->mask.xmin);
+ if(get_mbut() & mousebut) {
+ /* which part of scrollbar should move? */
+ if(mvalo[0]< (horxmin+horxmax)/2 ) right= 0.0;
+ else left= 0.0;
+ leftret= 0;
+ }
+ }
+ }
+ else {
+ facx= (G.v2d->cur.xmax-G.v2d->cur.xmin)/(float)(curarea->winx);
+ facy= (G.v2d->cur.ymax-G.v2d->cur.ymin)/(float)(curarea->winy);
+ }
+
+ cursor = BC_NSEW_SCROLLCURSOR;
+
+ /* no y move in audio & time */
+ if ELEM(curarea->spacetype, SPACE_SOUND, SPACE_TIME) {
+ facy= 0.0;
+ cursor = BC_EW_SCROLLCURSOR;
+ }
+
+ /* store the old cursor to temporarily change it */
+ oldcursor=get_cursor();
+ win=winlay_get_active_window();
+
+
+ if(get_mbut() & mousebut && leftret) return 0;
+ if(facx==0.0 && facy==0.0) return 1;
+
+ if (!is_wheel) SetBlenderCursor(cursor);
+
+ while( (get_mbut()&(L_MOUSE|M_MOUSE)) || is_wheel) {
+
+ /* If the mousewheel is used with shift key
+ * the scroll up and down. If the mousewheel
+ * is used with the ctrl key then scroll left
+ * and right.
+ */
+ if (is_wheel) {
+
+ if(event==WHEELDOWNMOUSE) {
+ facx= -facx; facy= -facy;
+ }
+ switch (G.qual & (LR_CTRLKEY|LR_SHIFTKEY|LR_ALTKEY)) {
+ case (LR_SHIFTKEY):
+ dx = 0.0;
+ dy= facy*20.0;
+ break;
+ case (LR_CTRLKEY):
+ dx= facx*20.0;
+ dy = 0.0;
+ break;
+ default:
+ if(curarea->spacetype==SPACE_OOPS) {
+ dx= 0.0;
+ dy= facy*20;
+ }
+ else if(curarea->spacetype==SPACE_BUTS) {
+ if(G.buts->align==BUT_HORIZONTAL) {
+ dx= facx*30; dy= 0.0;
+ } else {
+ dx= 0.0; dy= facy*30;
+ }
+ }
+ else return 0;
+ break;
+ }
+ }
+ else {
+
+
+ getmouseco_areawin(mval);
+ dx= facx*(mvalo[0]-mval[0]);
+ dy= facy*(mvalo[1]-mval[1]);
+ }
+
+ if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || is_wheel) {
+ ScrArea *sa;
+
+ G.v2d->cur.xmin+= left*dx;
+ G.v2d->cur.xmax+= right*dx;
+ G.v2d->cur.ymin+= left*dy;
+ G.v2d->cur.ymax+= right*dy;
+
+ test_view2d(G.v2d, curarea->winx, curarea->winy);
+
+ sa= curarea; /* bad global */
+ view2d_do_locks(curarea, V2D_LOCK_COPY|V2D_LOCK_REDRAW);
+ areawinset(sa->win);
+
+ if(curarea->spacetype==SPACE_OOPS)
+ ((SpaceOops *)curarea->spacedata.first)->storeflag |= SO_TREESTORE_REDRAW;
+
+ scrarea_do_windraw(curarea);
+ screen_swapbuffers();
+
+ mvalo[0]= mval[0];
+ mvalo[1]= mval[1];
+ }
+ else BIF_wait_for_statechange();
+ /* return if we were using the mousewheel
+ */
+ if ( is_wheel ) return 1;
+ }
+
+ window_set_cursor(win, oldcursor);
+ return 1;
+}
+
+void view2dborder(void)
+{
+
+}
+
+EditIpo *select_proj_ipo(rctf *rectf, int event)
+{
+ EditIpo *ei;
+ float xmin, ymin, xmax, ymax;
+ /* this was IGLuint, but it's a useless typedef... */
+ GLuint buffer[MAXPICKBUF];
+ int a, b;
+ int hits;
+ unsigned int code;
+ short mval[2];
+
+ G.f |= G_PICKSEL;
+
+ if(rectf==0) {
+ getmouseco_areawin(mval);
+
+ mval[0]-= 6; mval[1]-= 6;
+ areamouseco_to_ipoco(G.v2d, mval, &xmin, &ymin);
+ mval[0]+= 12; mval[1]+= 12;
+ areamouseco_to_ipoco(G.v2d, mval, &xmax, &ymax);
+
+ myortho2(xmin, xmax, ymin, ymax);
+ }
+ else myortho2(rectf->xmin, rectf->xmax, rectf->ymin, rectf->ymax);
+
+ glSelectBuffer( MAXPICKBUF, buffer);
+ glRenderMode(GL_SELECT);
+ glInitNames(); /* whatfor? but otherwise it does not work */
+ glPushName(-1);
+
+ /* get rid of buttons view */
+ glPushMatrix();
+ glLoadIdentity();
+
+ init_pickselcode(); /* drawipo.c */
+ draw_ipocurves(0);
+
+ /* restore buttons view */
+ glPopMatrix();
+
+ G.f -= G_PICKSEL;
+
+ hits= glRenderMode(GL_RENDER);
+ glPopName(); /* see above (pushname) */
+ if(hits<1) return 0;
+
+ code= 1;
+ ei= G.sipo->editipo;
+ for(a=0; a<G.sipo->totipo; a++, ei++) {
+ if ISPOIN(ei, icu, flag & IPO_VISIBLE) {
+ if(rectf) {
+ for(b=0; b<hits; b++) {
+ /* conversion for glSelect */
+ if(code == buffer[ (4 * b) + 3] ) {
+ if(event==LEFTMOUSE) ei->flag |= IPO_SELECT;
+ else ei->flag &= ~IPO_SELECT;
+ ei->icu->flag= ei->flag;
+ }
+ }
+ }
+ else {
+ /* also conversion for glSelect */
+ if(code==buffer[ 3 ]) return ei;
+ }
+ code++;
+ }
+ }
+ return 0;
+}
diff --git a/source/blender/src/drawmesh.c b/source/blender/src/drawmesh.c
new file mode 100644
index 00000000000..ba20771b179
--- /dev/null
+++ b/source/blender/src/drawmesh.c
@@ -0,0 +1,1220 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <string.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_edgehash.h"
+#include "BLI_editVert.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "DNA_image_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_property_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BKE_bmfont.h"
+#include "BKE_displist.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_effect.h"
+#include "BKE_global.h"
+#include "BKE_image.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_property.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_editmesh.h"
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+#include "BIF_mywindow.h"
+#include "BIF_resources.h"
+
+#include "BDR_editface.h"
+#include "BDR_vpaint.h"
+#include "BDR_drawmesh.h"
+
+#include "BSE_drawview.h"
+
+#include "blendef.h"
+#include "nla.h"
+
+#ifndef GL_CLAMP_TO_EDGE
+#define GL_CLAMP_TO_EDGE 0x812F
+#endif
+
+//#include "glext.h"
+/* some local functions */
+#if defined(GL_EXT_texture_object) && (!defined(__sun__) || (!defined(__sun))) && !defined(__APPLE__) && !defined(__linux__) && !defined(WIN32)
+ #define glBindTexture(A,B) glBindTextureEXT(A,B)
+ #define glGenTextures(A,B) glGenTexturesEXT(A,B)
+ #define glDeleteTextures(A,B) glDeleteTexturesEXT(A,B)
+ #define glPolygonOffset(A,B) glPolygonOffsetEXT(A,B)
+
+#else
+
+/* #define GL_FUNC_ADD_EXT GL_FUNC_ADD */
+/* #define GL_FUNC_REVERSE_SUBTRACT_EXT GL_FUNC_REVERSE_SUBTRACT */
+/* #define GL_POLYGON_OFFSET_EXT GL_POLYGON_OFFSET */
+
+#endif
+
+ /* (n&(n-1)) zeros the least significant bit of n */
+static int is_pow2(int num) {
+ return ((num)&(num-1))==0;
+}
+static int smaller_pow2(int num) {
+ while (!is_pow2(num))
+ num= num&(num-1);
+ return num;
+}
+
+/* These are used to enable texture clamping */
+static int is_pow2_limit(int num) {
+ if (U.glreslimit != 0 && num > U.glreslimit) return 0;
+ return ((num)&(num-1))==0;
+}
+
+static int smaller_pow2_limit(int num) {
+ if (U.glreslimit != 0 && num > U.glreslimit)
+ return U.glreslimit;
+ return smaller_pow2(num);
+}
+
+static int fCurtile=0, fCurmode=0,fCurtileXRep=0,fCurtileYRep=0;
+static Image *fCurpage=0;
+static short fTexwindx, fTexwindy, fTexwinsx, fTexwinsy;
+static int fDoMipMap = 1;
+static int fLinearMipMap = 0;
+
+/* local prototypes --------------- */
+void update_realtime_textures(void);
+
+
+/* static int source, dest; also not used */
+
+/**
+ * Enables or disable mipmapping for realtime images.
+ * @param mipmap Turn mipmapping on (mipmap!=0) or off (mipmap==0).
+ */
+void set_mipmap(int mipmap)
+{
+ if (fDoMipMap != (mipmap != 0)) {
+ free_all_realtime_images();
+ fDoMipMap = mipmap != 0;
+ }
+}
+
+/**
+ * Returns the current setting for mipmapping.
+ */
+static int get_mipmap(void)
+{
+ return fDoMipMap && (!(G.f & G_TEXTUREPAINT));
+}
+
+/**
+ * Enables or disable linear mipmap setting for realtime images (textures).
+ * Note that this will will destroy all texture bindings in OpenGL.
+ * @see free_realtime_image()
+ * @param mipmap Turn linear mipmapping on (linear!=0) or off (linear==0).
+ */
+void set_linear_mipmap(int linear)
+{
+ if (fLinearMipMap != (linear != 0)) {
+ free_all_realtime_images();
+ fLinearMipMap = linear != 0;
+ }
+}
+
+/**
+ * Returns the current setting for linear mipmapping.
+ */
+int get_linear_mipmap(void)
+{
+ return fLinearMipMap;
+}
+
+
+/**
+ * Resets the realtime image cache variables.
+ */
+void clear_realtime_image_cache()
+{
+ fCurpage = NULL;
+ fCurtile = 0;
+ fCurmode = 0;
+ fCurtileXRep = 0;
+ fCurtileYRep = 0;
+}
+
+/* REMEMBER! Changes here must go into my_set_tpage() as well */
+int set_tpage(MTFace *tface)
+{
+ static int alphamode= -1;
+ static MTFace *lasttface= 0;
+ Image *ima;
+ ImBuf *ibuf;
+ unsigned int *rect=NULL, *bind;
+ int tpx=0, tpy=0, tilemode, tileXRep,tileYRep;
+
+ /* disable */
+ if(tface==0) {
+ if(lasttface==0) return 0;
+
+ lasttface= 0;
+ fCurtile= 0;
+ fCurpage= 0;
+ if(fCurmode!=0) {
+ glMatrixMode(GL_TEXTURE);
+ glLoadIdentity();
+ glMatrixMode(GL_MODELVIEW);
+ }
+ fCurmode= 0;
+ fCurtileXRep=0;
+ fCurtileYRep=0;
+ alphamode= -1;
+
+ glDisable(GL_BLEND);
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_TEXTURE_GEN_S);
+ glDisable(GL_TEXTURE_GEN_T);
+ glDisable ( GL_ALPHA_TEST );
+ return 0;
+ }
+ lasttface= tface;
+
+ if( alphamode != tface->transp) {
+ alphamode= tface->transp;
+
+ if(alphamode) {
+ glEnable(GL_BLEND);
+
+ if(alphamode==TF_ADD) {
+ glBlendFunc(GL_ONE, GL_ONE);
+ /* glBlendEquationEXT(GL_FUNC_ADD_EXT); */
+ }
+ else if(alphamode==TF_ALPHA) {
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ /* added after 2.45 to clip alpha */
+ glEnable ( GL_ALPHA_TEST );
+ glAlphaFunc ( GL_GREATER, U.glalphaclip );
+
+
+ /* glBlendEquationEXT(GL_FUNC_ADD_EXT); */
+ }
+ /* else { */
+ /* glBlendFunc(GL_ONE, GL_ONE); */
+ /* glBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT); */
+ /* } */
+ } else {
+ glDisable(GL_BLEND);
+ glDisable ( GL_ALPHA_TEST );
+ }
+ }
+
+ ima= tface->tpage;
+
+ /* Enable or disable reflection mapping */
+ if (ima && (ima->flag & IMA_REFLECT)){
+
+// glActiveTextureARB(GL_TEXTURE0_ARB);
+ glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
+ glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
+
+ glEnable(GL_TEXTURE_GEN_S);
+ glEnable(GL_TEXTURE_GEN_T);
+
+ /* Handle multitexturing here */
+ }
+ else{
+ glDisable(GL_TEXTURE_GEN_S);
+ glDisable(GL_TEXTURE_GEN_T);
+ }
+
+ tilemode= tface->mode & TF_TILES;
+ tileXRep = 0;
+ tileYRep = 0;
+ if (ima) {
+ tileXRep = ima->xrep;
+ tileYRep = ima->yrep;
+ }
+
+
+ if(ima==fCurpage && fCurtile==tface->tile && tilemode==fCurmode && fCurtileXRep==tileXRep && fCurtileYRep == tileYRep) return ima!=0;
+
+ if(tilemode!=fCurmode || fCurtileXRep!=tileXRep || fCurtileYRep != tileYRep) {
+ glMatrixMode(GL_TEXTURE);
+ glLoadIdentity();
+
+ if(tilemode && ima!=NULL)
+ glScalef(ima->xrep, ima->yrep, 1.0);
+
+ glMatrixMode(GL_MODELVIEW);
+ }
+
+ if(ima==NULL || ima->ok==0) {
+ glDisable(GL_TEXTURE_2D);
+
+ fCurtile= tface->tile;
+ fCurpage= 0;
+ fCurmode= tilemode;
+ fCurtileXRep = tileXRep;
+ fCurtileYRep = tileYRep;
+
+ return 0;
+ }
+
+ ibuf= BKE_image_get_ibuf(ima, NULL);
+ if(ibuf==NULL) {
+
+ fCurtile= tface->tile;
+ fCurpage= 0;
+ fCurmode= tilemode;
+ fCurtileXRep = tileXRep;
+ fCurtileYRep = tileYRep;
+
+ glDisable(GL_TEXTURE_2D);
+ return 0;
+ }
+
+ if ((ibuf->rect==NULL) && ibuf->rect_float)
+ IMB_rect_from_float(ibuf);
+
+ if(ima->tpageflag & IMA_TWINANIM) fCurtile= ima->lastframe;
+ else fCurtile= tface->tile;
+
+ if(tilemode) {
+ if(ima->repbind==0) make_repbind(ima);
+
+ if(fCurtile>=ima->totbind) fCurtile= 0;
+
+ /* this happens when you change repeat buttons */
+ if(ima->repbind) bind= ima->repbind+fCurtile;
+ else bind= &ima->bindcode;
+
+ if(*bind==0) {
+
+ fTexwindx= ibuf->x/ima->xrep;
+ fTexwindy= ibuf->y/ima->yrep;
+
+ if(fCurtile>=ima->xrep*ima->yrep) fCurtile= ima->xrep*ima->yrep-1;
+
+ fTexwinsy= fCurtile / ima->xrep;
+ fTexwinsx= fCurtile - fTexwinsy*ima->xrep;
+
+ fTexwinsx*= fTexwindx;
+ fTexwinsy*= fTexwindy;
+
+ tpx= fTexwindx;
+ tpy= fTexwindy;
+
+ rect= ibuf->rect + fTexwinsy*ibuf->x + fTexwinsx;
+ }
+ }
+ else {
+ bind= &ima->bindcode;
+
+ if(*bind==0) {
+ tpx= ibuf->x;
+ tpy= ibuf->y;
+ rect= ibuf->rect;
+ }
+ }
+
+ if(*bind==0) {
+ int rectw= tpx, recth= tpy;
+ unsigned int *tilerect= NULL, *scalerect= NULL;
+
+ /*
+ * Maarten:
+ * According to Ton this code is not needed anymore. It was used only
+ * in really old Blenders.
+ * Reevan:
+ * Actually it is needed for backwards compatibility. Simpledemo 6 does not display correctly without it.
+ */
+#if 1
+ if (tilemode) {
+ int y;
+
+ tilerect= MEM_mallocN(rectw*recth*sizeof(*tilerect), "tilerect");
+ for (y=0; y<recth; y++) {
+ unsigned int *rectrow= &rect[y*ibuf->x];
+ unsigned int *tilerectrow= &tilerect[y*rectw];
+
+ memcpy(tilerectrow, rectrow, tpx*sizeof(*rectrow));
+ }
+
+ rect= tilerect;
+ }
+#endif
+ if (!is_pow2_limit(rectw) || !is_pow2_limit(recth)) {
+ rectw= smaller_pow2_limit(rectw);
+ recth= smaller_pow2_limit(recth);
+
+ scalerect= MEM_mallocN(rectw*recth*sizeof(*scalerect), "scalerect");
+ gluScaleImage(GL_RGBA, tpx, tpy, GL_UNSIGNED_BYTE, rect, rectw, recth, GL_UNSIGNED_BYTE, scalerect);
+ rect= scalerect;
+ }
+
+ glGenTextures(1, (GLuint *)bind);
+
+ if((G.f & G_DEBUG) || !*bind) {
+ GLenum error = glGetError();
+ printf("Texture: %s\n", ima->id.name+2);
+ printf("name: %d, tpx: %d\n", *bind, tpx);
+ printf("tile: %d, mode: %d\n", fCurtile, tilemode);
+ if (error)
+ printf("error: %s\n", gluErrorString(error));
+ }
+ glBindTexture( GL_TEXTURE_2D, *bind);
+
+ if (!get_mipmap())
+ {
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rectw, recth, 0, GL_RGBA, GL_UNSIGNED_BYTE, rect);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ } else
+ {
+ int minfilter= fLinearMipMap?GL_LINEAR_MIPMAP_LINEAR:GL_LINEAR_MIPMAP_NEAREST;
+
+ gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, rectw, recth, GL_RGBA, GL_UNSIGNED_BYTE, rect);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minfilter);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ ima->tpageflag |= IMA_MIPMAP_COMPLETE;
+ }
+
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+
+ if (tilerect)
+ MEM_freeN(tilerect);
+ if (scalerect)
+ MEM_freeN(scalerect);
+ }
+ else glBindTexture( GL_TEXTURE_2D, *bind);
+
+ /* dont tile x/y as set the the game properties */
+ if (ima->tpageflag & IMA_CLAMP_U)
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ else
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ if (ima->tpageflag & IMA_CLAMP_V)
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ else
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
+ /* tag_image_time(ima);*/ /* Did this get lost in the image recode? */
+
+ glEnable(GL_TEXTURE_2D);
+
+ fCurpage= ima;
+ fCurmode= tilemode;
+ fCurtileXRep = tileXRep;
+ fCurtileYRep = tileYRep;
+
+ return 1;
+}
+
+void update_realtime_image(Image *ima, int x, int y, int w, int h)
+{
+ ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL);
+
+ if (ima->repbind || get_mipmap() || !ima->bindcode || !ibuf ||
+ (!is_pow2(ibuf->x) || !is_pow2(ibuf->y)) ||
+ (w == 0) || (h == 0)) {
+ /* these special cases require full reload still */
+ free_realtime_image(ima);
+ }
+ else {
+ int row_length = glaGetOneInteger(GL_UNPACK_ROW_LENGTH);
+ int skip_pixels = glaGetOneInteger(GL_UNPACK_SKIP_PIXELS);
+ int skip_rows = glaGetOneInteger(GL_UNPACK_SKIP_ROWS);
+
+ if ((ibuf->rect==NULL) && ibuf->rect_float)
+ IMB_rect_from_float(ibuf);
+
+ glBindTexture(GL_TEXTURE_2D, ima->bindcode);
+
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, ibuf->x);
+ glPixelStorei(GL_UNPACK_SKIP_PIXELS, x);
+ glPixelStorei(GL_UNPACK_SKIP_ROWS, y);
+
+ glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA,
+ GL_UNSIGNED_BYTE, ibuf->rect);
+
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, row_length);
+ glPixelStorei(GL_UNPACK_SKIP_PIXELS, skip_pixels);
+ glPixelStorei(GL_UNPACK_SKIP_ROWS, skip_rows);
+
+ if(ima->tpageflag & IMA_MIPMAP_COMPLETE)
+ ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
+ }
+}
+
+void free_realtime_image(Image *ima)
+{
+ if(ima->bindcode) {
+ glDeleteTextures(1, (GLuint *)&ima->bindcode);
+ ima->bindcode= 0;
+ ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
+ }
+ if(ima->repbind) {
+ glDeleteTextures(ima->totbind, (GLuint *)ima->repbind);
+
+ MEM_freeN(ima->repbind);
+ ima->repbind= NULL;
+ ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
+ }
+}
+
+void free_all_realtime_images(void)
+{
+ Image* ima;
+
+ for(ima=G.main->image.first; ima; ima=ima->id.next)
+ free_realtime_image(ima);
+}
+
+/* these two functions are called on entering and exiting texture paint mode,
+ temporary disabling/enabling mipmapping on all images for quick texture
+ updates with glTexSubImage2D. images that didn't change don't have to be
+ re-uploaded to OpenGL */
+void texpaint_disable_mipmap(void)
+{
+ Image* ima;
+
+ if(!fDoMipMap)
+ return;
+
+ for(ima=G.main->image.first; ima; ima=ima->id.next) {
+ if(ima->bindcode) {
+ glBindTexture(GL_TEXTURE_2D, ima->bindcode);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ }
+ }
+}
+
+void texpaint_enable_mipmap(void)
+{
+ Image* ima;
+
+ if(!fDoMipMap)
+ return;
+
+ for(ima=G.main->image.first; ima; ima=ima->id.next) {
+ if(ima->bindcode) {
+ if(ima->tpageflag & IMA_MIPMAP_COMPLETE) {
+ int minfilter= fLinearMipMap?GL_LINEAR_MIPMAP_LINEAR:GL_LINEAR_MIPMAP_NEAREST;
+
+ glBindTexture(GL_TEXTURE_2D, ima->bindcode);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minfilter);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ }
+ else
+ free_realtime_image(ima);
+ }
+ }
+}
+
+void make_repbind(Image *ima)
+{
+ ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL);
+
+ if(ibuf==NULL) return;
+
+ if(ima->repbind) {
+ glDeleteTextures(ima->totbind, (GLuint *)ima->repbind);
+ MEM_freeN(ima->repbind);
+ ima->repbind= 0;
+ ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
+ }
+ ima->totbind= ima->xrep*ima->yrep;
+ if(ima->totbind>1) {
+ ima->repbind= MEM_callocN(sizeof(int)*ima->totbind, "repbind");
+ }
+}
+
+void update_realtime_textures()
+{
+ Image *ima;
+
+ ima= G.main->image.first;
+ while(ima) {
+ if(ima->tpageflag & IMA_TWINANIM) {
+ if(ima->twend >= ima->xrep*ima->yrep) ima->twend= ima->xrep*ima->yrep-1;
+
+ /* check: is bindcode not in the array? Free. (to do) */
+
+ ima->lastframe++;
+ if(ima->lastframe > ima->twend) ima->lastframe= ima->twsta;
+
+ }
+ ima= ima->id.next;
+ }
+}
+
+/***/
+
+ /* Flags for marked edges */
+enum {
+ eEdge_Visible = (1<<0),
+ eEdge_Select = (1<<1),
+};
+
+ /* Creates a hash of edges to flags indicating
+ * adjacent tface select/active/etc flags.
+ */
+static void get_marked_edge_info__orFlags(EdgeHash *eh, int v0, int v1, int flags)
+{
+ int *flags_p;
+
+ if (!BLI_edgehash_haskey(eh, v0, v1)) {
+ BLI_edgehash_insert(eh, v0, v1, 0);
+ }
+
+ flags_p = (int*) BLI_edgehash_lookup_p(eh, v0, v1);
+ *flags_p |= flags;
+}
+
+EdgeHash *get_tface_mesh_marked_edge_info(Mesh *me)
+{
+ EdgeHash *eh = BLI_edgehash_new();
+ int i;
+ MFace *mf;
+ MTFace *tf = NULL;
+
+ for (i=0; i<me->totface; i++) {
+ mf = &me->mface[i];
+ if (me->mtface)
+ tf = &me->mtface[i];
+
+ if (mf->v3) {
+ if (!(mf->flag&ME_HIDE)) {
+ unsigned int flags = eEdge_Visible;
+ if (mf->flag&ME_FACE_SEL) flags |= eEdge_Select;
+
+ get_marked_edge_info__orFlags(eh, mf->v1, mf->v2, flags);
+ get_marked_edge_info__orFlags(eh, mf->v2, mf->v3, flags);
+ if (mf->v4) {
+ get_marked_edge_info__orFlags(eh, mf->v3, mf->v4, flags);
+ get_marked_edge_info__orFlags(eh, mf->v4, mf->v1, flags);
+ } else {
+ get_marked_edge_info__orFlags(eh, mf->v3, mf->v1, flags);
+ }
+ }
+ }
+ }
+
+ return eh;
+}
+
+
+static int draw_tfaces3D__setHiddenOpts(void *userData, int index)
+{
+ struct { Mesh *me; EdgeHash *eh; } *data = userData;
+ MEdge *med = &data->me->medge[index];
+ unsigned long flags = (long) BLI_edgehash_lookup(data->eh, med->v1, med->v2);
+
+ if((G.f & G_DRAWSEAMS) && (med->flag&ME_SEAM)) {
+ return 0;
+ } else if(G.f & G_DRAWEDGES){
+ if (G.f&G_HIDDENEDGES) {
+ return 1;
+ } else {
+ return (flags & eEdge_Visible);
+ }
+ } else {
+ return (flags & eEdge_Select);
+ }
+}
+static int draw_tfaces3D__setSeamOpts(void *userData, int index)
+{
+ struct { Mesh *me; EdgeHash *eh; } *data = userData;
+ MEdge *med = &data->me->medge[index];
+ unsigned long flags = (long) BLI_edgehash_lookup(data->eh, med->v1, med->v2);
+
+ if (med->flag&ME_SEAM) {
+ if (G.f&G_HIDDENEDGES) {
+ return 1;
+ } else {
+ return (flags & eEdge_Visible);
+ }
+ } else {
+ return 0;
+ }
+}
+static int draw_tfaces3D__setSelectOpts(void *userData, int index)
+{
+ struct { Mesh *me; EdgeHash *eh; } *data = userData;
+ MEdge *med = &data->me->medge[index];
+ unsigned long flags = (long) BLI_edgehash_lookup(data->eh, med->v1, med->v2);
+
+ return flags & eEdge_Select;
+}
+static int draw_tfaces3D__setActiveOpts(void *userData, int index)
+{
+ struct { Mesh *me; EdgeHash *eh; } *data = userData;
+ MEdge *med = &data->me->medge[index];
+ unsigned long flags = (long) BLI_edgehash_lookup(data->eh, med->v1, med->v2);
+
+ if (flags & eEdge_Select) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+static int draw_tfaces3D__drawFaceOpts(void *userData, int index)
+{
+ Mesh *me = (Mesh*)userData;
+
+ MFace *mface = &me->mface[index];
+ if (!(mface->flag&ME_HIDE) && (mface->flag&ME_FACE_SEL))
+ return 2; /* Don't set color */
+ else
+ return 0;
+}
+static void draw_tfaces3D(Object *ob, Mesh *me, DerivedMesh *dm)
+{
+ struct { Mesh *me; EdgeHash *eh; } data;
+
+ data.me = me;
+ data.eh = get_tface_mesh_marked_edge_info(me);
+
+ glEnable(GL_DEPTH_TEST);
+ glDisable(GL_LIGHTING);
+ bglPolygonOffset(1.0);
+
+ /* Draw (Hidden) Edges */
+ BIF_ThemeColor(TH_EDGE_FACESEL);
+ dm->drawMappedEdges(dm, draw_tfaces3D__setHiddenOpts, &data);
+
+ /* Draw Seams */
+ if(G.f & G_DRAWSEAMS) {
+ BIF_ThemeColor(TH_EDGE_SEAM);
+ glLineWidth(2);
+
+ dm->drawMappedEdges(dm, draw_tfaces3D__setSeamOpts, &data);
+
+ glLineWidth(1);
+ }
+
+ /* Draw Selected Faces */
+ if(G.f & G_DRAWFACES) {
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ BIF_ThemeColor4(TH_FACE_SELECT);
+
+ dm->drawMappedFacesTex(dm, draw_tfaces3D__drawFaceOpts, (void*)me);
+
+ glDisable(GL_BLEND);
+ }
+
+ bglPolygonOffset(1.0);
+
+ /* Draw Stippled Outline for selected faces */
+ glColor3ub(255, 255, 255);
+ setlinestyle(1);
+ dm->drawMappedEdges(dm, draw_tfaces3D__setSelectOpts, &data);
+ setlinestyle(0);
+
+ dm->drawMappedEdges(dm, draw_tfaces3D__setActiveOpts, &data);
+
+ bglPolygonOffset(0.0); // resets correctly now, even after calling accumulated offsets
+
+ BLI_edgehash_free(data.eh, NULL);
+}
+
+static int set_gl_light(Object *ob)
+{
+ Base *base;
+ Lamp *la;
+ int count;
+ /* float zero[4]= {0.0, 0.0, 0.0, 0.0}; */
+ float vec[4];
+
+ vec[3]= 1.0;
+
+ for(count=0; count<8; count++) glDisable(GL_LIGHT0+count);
+
+ count= 0;
+
+ base= FIRSTBASE;
+ while(base) {
+ if(base->object->type==OB_LAMP ) {
+ if(base->lay & G.vd->lay) {
+ if(base->lay & ob->lay)
+ {
+ la= base->object->data;
+
+ glPushMatrix();
+ glLoadMatrixf((float *)G.vd->viewmat);
+
+ where_is_object_simul(base->object);
+ VECCOPY(vec, base->object->obmat[3]);
+
+ if(la->type==LA_SUN) {
+ vec[0]= base->object->obmat[2][0];
+ vec[1]= base->object->obmat[2][1];
+ vec[2]= base->object->obmat[2][2];
+ vec[3]= 0.0;
+ glLightfv(GL_LIGHT0+count, GL_POSITION, vec);
+ }
+ else {
+ vec[3]= 1.0;
+ glLightfv(GL_LIGHT0+count, GL_POSITION, vec);
+ glLightf(GL_LIGHT0+count, GL_CONSTANT_ATTENUATION, 1.0);
+ glLightf(GL_LIGHT0+count, GL_LINEAR_ATTENUATION, la->att1/la->dist);
+ /* post 2.25 engine supports quad lights */
+ glLightf(GL_LIGHT0+count, GL_QUADRATIC_ATTENUATION, la->att2/(la->dist*la->dist));
+
+ if(la->type==LA_SPOT) {
+ vec[0]= -base->object->obmat[2][0];
+ vec[1]= -base->object->obmat[2][1];
+ vec[2]= -base->object->obmat[2][2];
+ glLightfv(GL_LIGHT0+count, GL_SPOT_DIRECTION, vec);
+ glLightf(GL_LIGHT0+count, GL_SPOT_CUTOFF, la->spotsize/2.0);
+ glLightf(GL_LIGHT0+count, GL_SPOT_EXPONENT, 128.0*la->spotblend);
+ }
+ else glLightf(GL_LIGHT0+count, GL_SPOT_CUTOFF, 180.0);
+ }
+
+ vec[0]= la->energy*la->r;
+ vec[1]= la->energy*la->g;
+ vec[2]= la->energy*la->b;
+ vec[3]= 1.0;
+ glLightfv(GL_LIGHT0+count, GL_DIFFUSE, vec);
+ glLightfv(GL_LIGHT0+count, GL_SPECULAR, vec);//zero);
+ glEnable(GL_LIGHT0+count);
+
+ glPopMatrix();
+
+ count++;
+ if(count>7) break;
+ }
+ }
+ }
+ base= base->next;
+ }
+
+ return count;
+}
+
+static Material *give_current_material_or_def(Object *ob, int matnr)
+{
+ extern Material defmaterial; // render module abuse...
+ Material *ma= give_current_material(ob, matnr);
+
+ return ma?ma:&defmaterial;
+}
+
+static int set_draw_settings_cached(int clearcache, int textured, MTFace *texface, int lit, Object *litob, int litmatnr, int doublesided)
+{
+ static int c_textured;
+ static int c_lit;
+ static int c_doublesided;
+ static MTFace *c_texface;
+ static Object *c_litob;
+ static int c_litmatnr;
+ static int c_badtex;
+
+ if (clearcache) {
+ c_textured= c_lit= c_doublesided= -1;
+ c_texface= (MTFace*) -1;
+ c_litob= (Object*) -1;
+ c_litmatnr= -1;
+ c_badtex= 0;
+ }
+
+ if (texface) {
+ lit = lit && (lit==-1 || texface->mode&TF_LIGHT);
+ textured = textured && (texface->mode&TF_TEX);
+ doublesided = texface->mode&TF_TWOSIDE;
+ } else {
+ textured = 0;
+ }
+
+ if (doublesided!=c_doublesided) {
+ if (doublesided) glDisable(GL_CULL_FACE);
+ else glEnable(GL_CULL_FACE);
+
+ c_doublesided= doublesided;
+ }
+
+ if (textured!=c_textured || texface!=c_texface) {
+ if (textured ) {
+ c_badtex= !set_tpage(texface);
+ } else {
+ set_tpage(0);
+ c_badtex= 0;
+ }
+ c_textured= textured;
+ c_texface= texface;
+ }
+
+ if (c_badtex) lit= 0;
+ if (lit!=c_lit || litob!=c_litob || litmatnr!=c_litmatnr) {
+ if (lit) {
+ Material *ma= give_current_material_or_def(litob, litmatnr+1);
+ float spec[4];
+
+ spec[0]= ma->spec*ma->specr;
+ spec[1]= ma->spec*ma->specg;
+ spec[2]= ma->spec*ma->specb;
+ spec[3]= 1.0;
+
+ glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
+ glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
+ glEnable(GL_LIGHTING);
+ glEnable(GL_COLOR_MATERIAL);
+ }
+ else {
+ glDisable(GL_LIGHTING);
+ glDisable(GL_COLOR_MATERIAL);
+ }
+ c_lit= lit;
+ c_litob= litob;
+ c_litmatnr= litmatnr;
+ }
+
+ return c_badtex;
+}
+
+/* Icky globals, fix with userdata parameter */
+
+struct TextureDrawState {
+ Object *ob;
+ int islit, istex;
+ unsigned char obcol[4];
+} Gtexdraw = {NULL, 0, 0, {0, 0, 0, 0}};
+
+static void draw_textured_begin(Object *ob)
+{
+ unsigned char obcol[4];
+ int istex, solidtex= 0;
+
+ if(G.vd->drawtype==OB_SOLID || (ob==G.obedit && G.vd->drawtype!=OB_TEXTURE)) {
+ /* draw with default lights in solid draw mode and edit mode */
+ solidtex= 1;
+ Gtexdraw.islit= -1;
+ }
+ else
+ /* draw with lights in the scene otherwise */
+ Gtexdraw.islit= set_gl_light(ob);
+
+ obcol[0]= CLAMPIS(ob->col[0]*255, 0, 255);
+ obcol[1]= CLAMPIS(ob->col[1]*255, 0, 255);
+ obcol[2]= CLAMPIS(ob->col[2]*255, 0, 255);
+ obcol[3]= CLAMPIS(ob->col[3]*255, 0, 255);
+
+ glCullFace(GL_BACK); glEnable(GL_CULL_FACE);
+ if(solidtex || G.vd->drawtype==OB_TEXTURE) istex= 1;
+ else istex= 0;
+
+ Gtexdraw.ob = ob;
+ Gtexdraw.istex = istex;
+ memcpy(Gtexdraw.obcol, obcol, sizeof(obcol));
+ set_draw_settings_cached(1, 0, 0, Gtexdraw.islit, 0, 0, 0);
+ glShadeModel(GL_SMOOTH);
+}
+
+static void draw_textured_end()
+{
+ /* switch off textures */
+ set_tpage(0);
+
+ glShadeModel(GL_FLAT);
+ glDisable(GL_CULL_FACE);
+
+ /* XXX, bad patch - default_gl_light() calls
+ * glLightfv(GL_LIGHT_POSITION, ...) which
+ * is transformed by the current matrix... we
+ * need to make sure that matrix is identity.
+ *
+ * It would be better if drawmesh.c kept track
+ * of and restored the light settings it changed.
+ * - zr
+ */
+ glPushMatrix();
+ glLoadIdentity();
+ default_gl_light();
+ glPopMatrix();
+}
+
+
+static int draw_tface__set_draw(MTFace *tface, MCol *mcol, int matnr)
+{
+ if (tface && (tface->mode&TF_INVISIBLE)) return 0;
+
+ if (tface && set_draw_settings_cached(0, Gtexdraw.istex, tface, Gtexdraw.islit, Gtexdraw.ob, matnr, TF_TWOSIDE)) {
+ glColor3ub(0xFF, 0x00, 0xFF);
+ return 2; /* Don't set color */
+ } else if (tface && tface->mode&TF_OBCOL) {
+ glColor3ubv(Gtexdraw.obcol);
+ return 2; /* Don't set color */
+ } else if (!mcol) {
+ if (tface) glColor3f(1.0, 1.0, 1.0);
+ else {
+ Material *ma= give_current_material(Gtexdraw.ob, matnr+1);
+ if(ma) glColor3f(ma->r, ma->g, ma->b);
+ else glColor3f(1.0, 1.0, 1.0);
+ }
+ return 2; /* Don't set color */
+ } else {
+ return 1; /* Set color from mcol */
+ }
+}
+
+static int draw_tface_mapped__set_draw(void *userData, int index)
+{
+ Mesh *me = (Mesh*)userData;
+ MTFace *tface = (me->mtface)? &me->mtface[index]: NULL;
+ MFace *mface = (me->mface)? &me->mface[index]: NULL;
+ MCol *mcol = (me->mcol)? &me->mcol[index]: NULL;
+ int matnr = me->mface[index].mat_nr;
+ if (mface && mface->flag&ME_HIDE) return 0;
+ return draw_tface__set_draw(tface, mcol, matnr);
+}
+
+static int draw_em_tf_mapped__set_draw(void *userData, int index)
+{
+ EditMesh *em = userData;
+ EditFace *efa = EM_get_face_for_index(index);
+ MTFace *tface;
+ MCol *mcol;
+ int matnr;
+
+ if (efa==NULL || efa->h)
+ return 0;
+
+ tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
+ matnr = efa->mat_nr;
+
+ return draw_tface__set_draw(tface, mcol, matnr);
+}
+
+static int wpaint__setSolidDrawOptions(void *userData, int index, int *drawSmooth_r)
+{
+ Mesh *me = (Mesh*)userData;
+ MTFace *tface = (me->mtface)? &me->mtface[index]: NULL;
+ MFace *mface = (me->mface)? &me->mface[index]: NULL;
+
+ if ((mface->flag&ME_HIDE) || (tface && (tface->mode&TF_INVISIBLE)))
+ return 0;
+
+ *drawSmooth_r = 1;
+ return 1;
+}
+
+static void draw_game_text_mesh(Object *ob, Mesh *me)
+{
+ DerivedMesh *ddm = mesh_get_derived_deform(ob, CD_MASK_BAREMESH);
+ MFace *mface= me->mface;
+ MTFace *tface= me->mtface;
+ MCol *mcol= me->mcol; /* why does mcol exist? */
+ bProperty *prop = get_property(ob, "Text");
+ int a, start= 0, totface= me->totface;
+
+ tface+= start;
+ mcol+= start*4;
+ for (a=start; a<totface; a++, tface++, mcol+=4) {
+ MFace *mf= &mface[a];
+ int mode= tface->mode;
+ int matnr= mf->mat_nr;
+ int mf_smooth= mf->flag & ME_SMOOTH;
+
+ if (!(mf->flag&ME_HIDE) && !(mode&TF_INVISIBLE) && (mode&TF_BMFONT)) {
+ int badtex= set_draw_settings_cached(0, Gtexdraw.istex, tface, Gtexdraw.islit, Gtexdraw.ob, matnr, TF_TWOSIDE);
+ float v1[3], v2[3], v3[3], v4[3];
+ char string[MAX_PROPSTRING];
+ int characters, index;
+ ImBuf *ibuf;
+ float curpos;
+
+ if (badtex)
+ continue;
+
+ ddm->getVertCo(ddm, mf->v1, v1);
+ ddm->getVertCo(ddm, mf->v2, v2);
+ ddm->getVertCo(ddm, mf->v3, v3);
+ if (mf->v4) ddm->getVertCo(ddm, mf->v4, v4);
+
+ // The BM_FONT handling code is duplicated in the gameengine
+ // Search for 'Frank van Beek' ;-)
+ // string = "Frank van Beek";
+
+ set_property_valstr(prop, string);
+ characters = strlen(string);
+
+ ibuf= BKE_image_get_ibuf(tface->tpage, NULL);
+ if (ibuf == NULL) {
+ characters = 0;
+ }
+
+ if (!mf_smooth) {
+ float nor[3];
+
+ CalcNormFloat(v1, v2, v3, nor);
+
+ glNormal3fv(nor);
+ }
+
+ curpos= 0.0;
+ glBegin(mf->v4?GL_QUADS:GL_TRIANGLES);
+ for (index = 0; index < characters; index++) {
+ float centerx, centery, sizex, sizey, transx, transy, movex, movey, advance;
+ int character = string[index];
+ char *cp= NULL;
+
+ // lets calculate offset stuff
+ // space starts at offset 1
+ // character = character - ' ' + 1;
+
+ matrixGlyph(ibuf, character, & centerx, &centery, &sizex, &sizey, &transx, &transy, &movex, &movey, &advance);
+ movex+= curpos;
+
+ if (tface->mode & TF_OBCOL)
+ glColor3ubv(Gtexdraw.obcol);
+ else if (me->mcol) cp= (char *)mcol;
+ else glColor3ub(255, 255, 255);
+
+ glTexCoord2f((tface->uv[0][0] - centerx) * sizex + transx, (tface->uv[0][1] - centery) * sizey + transy);
+ if (cp) glColor3ub(cp[3], cp[2], cp[1]);
+ glVertex3f(sizex * v1[0] + movex, sizey * v1[1] + movey, v1[2]);
+
+ glTexCoord2f((tface->uv[1][0] - centerx) * sizex + transx, (tface->uv[1][1] - centery) * sizey + transy);
+ if (cp) glColor3ub(cp[7], cp[6], cp[5]);
+ glVertex3f(sizex * v2[0] + movex, sizey * v2[1] + movey, v2[2]);
+
+ glTexCoord2f((tface->uv[2][0] - centerx) * sizex + transx, (tface->uv[2][1] - centery) * sizey + transy);
+ if (cp) glColor3ub(cp[11], cp[10], cp[9]);
+ glVertex3f(sizex * v3[0] + movex, sizey * v3[1] + movey, v3[2]);
+
+ if(mf->v4) {
+ glTexCoord2f((tface->uv[3][0] - centerx) * sizex + transx, (tface->uv[3][1] - centery) * sizey + transy);
+ if (cp) glColor3ub(cp[15], cp[14], cp[13]);
+ glVertex3f(sizex * v4[0] + movex, sizey * v4[1] + movey, v4[2]);
+ }
+
+ curpos+= advance;
+ }
+ glEnd();
+ }
+ }
+
+ ddm->release(ddm);
+}
+
+void draw_mesh_textured(Object *ob, DerivedMesh *dm, int faceselect)
+{
+ Mesh *me= ob->data;
+ int editing= 0;
+
+ /* correct for negative scale */
+ if(ob->transflag & OB_NEG_SCALE) glFrontFace(GL_CW);
+ else glFrontFace(GL_CCW);
+
+ /* draw the textured mesh */
+ draw_textured_begin(ob);
+
+#ifdef WITH_VERSE
+ if(me->vnode) {
+ /* verse-blender doesn't support uv mapping of textures yet */
+ dm->drawFacesTex(dm, NULL);
+ }
+ else {
+#endif
+ if(ob==G.obedit) {
+ dm->drawMappedFacesTex(dm, draw_em_tf_mapped__set_draw, G.editMesh);
+ } else if(faceselect) {
+ if(G.f & G_WEIGHTPAINT)
+ dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, me, 1);
+ else
+ dm->drawMappedFacesTex(dm, draw_tface_mapped__set_draw, me);
+ }
+ else
+ dm->drawFacesTex(dm, draw_tface__set_draw);
+#ifdef WITH_VERSE
+ }
+#endif
+
+ /* draw game engine text hack - but not if we are editing the mesh */
+ if (me->mtface && get_property(ob, "Text")) {
+ if(ob==G.obedit)
+ editing= 1;
+ else if(ob==OBACT)
+ if(FACESEL_PAINT_TEST)
+ editing= 1;
+
+ if(!editing)
+ draw_game_text_mesh(ob, me);
+ }
+
+ draw_textured_end();
+
+ /* draw edges and selected faces over textured mesh */
+ if(!G.obedit && faceselect)
+ draw_tfaces3D(ob, me, dm);
+
+ /* reset from negative scale correction */
+ glFrontFace(GL_CCW);
+
+ /* in editmode, the blend mode needs to be set incase it was ADD */
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ dm->release(dm);
+}
+
+void init_realtime_GL(void)
+{
+ glMatrixMode(GL_TEXTURE);
+ glLoadIdentity();
+ glMatrixMode(GL_MODELVIEW);
+}
+
diff --git a/source/blender/src/drawnla.c b/source/blender/src/drawnla.c
new file mode 100644
index 00000000000..0394fcce80b
--- /dev/null
+++ b/source/blender/src/drawnla.c
@@ -0,0 +1,824 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef _WIN32
+#pragma warning (once : 4761)
+#endif
+
+#include "BMF_Api.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "DNA_view3d_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_action_types.h"
+#include "DNA_nla_types.h"
+#include "DNA_constraint_types.h"
+
+#include "BLI_blenlib.h"
+#include "MEM_guardedalloc.h"
+
+#include "BKE_action.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+
+#include "BSE_drawnla.h"
+#include "BSE_drawipo.h"
+#include "BSE_editnla_types.h"
+#include "BSE_headerbuttons.h"
+#include "BSE_time.h"
+
+#include "BIF_editnla.h"
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+#include "BIF_interface.h"
+#include "BIF_interface_icons.h"
+#include "BIF_mywindow.h"
+#include "BIF_resources.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+
+#include "BDR_drawaction.h"
+#include "BDR_editcurve.h"
+
+#include "blendef.h"
+#include "butspace.h"
+#include "mydevice.h"
+
+#define TESTBASE_SAFE(base) ((base)->flag & SELECT && ((base)->object->restrictflag & OB_RESTRICT_VIEW)==0)
+
+
+/* the left hand side with channels only */
+static void draw_nla_channels(void)
+{
+ bActionStrip *strip;
+ Base *base;
+ Object *ob;
+ float x, y;
+ short ofsx, ofsy = 0;
+
+ myortho2(0, NLAWIDTH, G.v2d->cur.ymin, G.v2d->cur.ymax); // Scaling
+
+ /* Clip to the scrollable area */
+ if(curarea->winx>SCROLLB+10 && curarea->winy>SCROLLH+10) {
+ if(G.v2d->scroll) {
+ ofsx= curarea->winrct.xmin;
+ ofsy= curarea->winrct.ymin;
+ glViewport(ofsx, ofsy+G.v2d->mask.ymin, NLAWIDTH, ( ofsy+G.v2d->mask.ymax)-( ofsy+G.v2d->mask.ymin));
+ glScissor(ofsx, ofsy+G.v2d->mask.ymin, NLAWIDTH, ( ofsy+G.v2d->mask.ymax)-( ofsy+G.v2d->mask.ymin));
+ }
+ }
+
+ glColor3ub(0x00, 0x00, 0x00);
+
+ x = 0.0;
+ y = count_nla_levels();
+ y*= (NLACHANNELHEIGHT+NLACHANNELSKIP);
+
+ for (base=G.scene->base.first; base; base=base->next){
+ if (nla_filter(base)) {
+ ob= base->object;
+
+ BIF_ThemeColorShade(TH_HEADER, 20);
+ glRectf(x, y-NLACHANNELHEIGHT/2, (float)NLAWIDTH, y+NLACHANNELHEIGHT/2);
+
+ /* Draw the name / ipo timeline*/
+ if (TESTBASE_SAFE(base))
+ BIF_ThemeColor(TH_TEXT_HI);
+ else
+ BIF_ThemeColor(TH_TEXT);
+ glRasterPos2f(x+34, y-4);
+ BMF_DrawString(G.font, ob->id.name+2);
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) ;
+
+ /* icon to indicate expanded or collapsed */
+ if ((ob->nlastrips.first) || (ob->action)) {
+ if (ob->nlaflag & OB_NLA_COLLAPSED)
+ BIF_icon_draw(x+1, y-8, ICON_TRIA_RIGHT);
+ else
+ BIF_icon_draw(x+1, y-8, ICON_TRIA_DOWN);
+ }
+
+ /* icon to indicate nla or action */
+ if(ob->nlastrips.first && ob->action) {
+ if(ob->nlaflag & OB_NLA_OVERRIDE)
+ BIF_icon_draw(x+17, y-8, ICON_NLA);
+ else
+ BIF_icon_draw(x+17, y-8, ICON_ACTION);
+ }
+
+ /* icon to indicate if ipo-channel muted */
+ if (ob->ipo) {
+ if (ob->ipo->muteipo)
+ BIF_icon_draw(NLAWIDTH-16, y-NLACHANNELHEIGHT/2, ICON_MUTE_IPO_ON);
+ else
+ BIF_icon_draw(NLAWIDTH-16, y-NLACHANNELHEIGHT/2, ICON_MUTE_IPO_OFF);
+ }
+
+ glDisable(GL_BLEND);
+ y-=NLACHANNELHEIGHT+NLACHANNELSKIP;
+
+ /* check if object's nla strips are collapsed or not */
+ if ((ob->nlaflag & OB_NLA_COLLAPSED)==0) {
+ /* Draw the action timeline */
+ if (ob->action){
+ BIF_ThemeColorShade(TH_HEADER, -20);
+ glRectf(x+19, y-NLACHANNELHEIGHT/2, (float)NLAWIDTH, y+NLACHANNELHEIGHT/2);
+
+ if (TESTBASE_SAFE(base))
+ BIF_ThemeColor(TH_TEXT_HI);
+ else
+ BIF_ThemeColor(TH_TEXT);
+ glRasterPos2f(x+38, y-4);
+ BMF_DrawString(G.font, ob->action->id.name+2);
+
+ /* icon for active action (no strip mapping) */
+ for (strip = ob->nlastrips.first; strip; strip=strip->next)
+ if(strip->flag & ACTSTRIP_ACTIVE) break;
+ if(strip==NULL) {
+ glEnable(GL_BLEND);
+ BIF_icon_draw(x+5, y-8, ICON_DOT);
+ glDisable(GL_BLEND);
+ }
+
+ y-=NLACHANNELHEIGHT+NLACHANNELSKIP;
+ }
+
+ /* Draw the nla strips */
+ for (strip = ob->nlastrips.first; strip; strip=strip->next){
+ BIF_ThemeColorShade(TH_HEADER, -40);
+ glRectf(x+32, y-NLACHANNELHEIGHT/2, (float)NLAWIDTH, y+NLACHANNELHEIGHT/2);
+
+ if (TESTBASE_SAFE(base))
+ BIF_ThemeColor(TH_TEXT_HI);
+ else
+ BIF_ThemeColor(TH_TEXT);
+
+ // why this test? check freeing mem when deleting strips? (ton)
+ if(strip->act) {
+ glRasterPos2f(x+48, y-4);
+ BMF_DrawString(G.font, strip->act->id.name+2);
+
+ glEnable(GL_BLEND);
+
+ if(strip->flag & ACTSTRIP_ACTIVE)
+ BIF_icon_draw(x+16, y-8, ICON_DOT);
+
+ if(strip->modifiers.first)
+ BIF_icon_draw(x+34, y-8, ICON_MODIFIER);
+
+ if(strip->flag & ACTSTRIP_MUTE)
+ BIF_icon_draw(NLAWIDTH-16, y-NLACHANNELHEIGHT/2, ICON_MUTE_IPO_ON);
+ else
+ BIF_icon_draw(NLAWIDTH-16, y-NLACHANNELHEIGHT/2, ICON_MUTE_IPO_OFF);
+
+ glDisable(GL_BLEND);
+ }
+
+ y-=(NLACHANNELHEIGHT+NLACHANNELSKIP);
+ }
+ }
+ }
+ }
+
+ myortho2(0, NLAWIDTH, 0, ( ofsy+G.v2d->mask.ymax)-( ofsy+G.v2d->mask.ymin)); // Scaling
+}
+
+void map_active_strip(gla2DDrawInfo *di, Object *ob, int restore)
+{
+ static rctf stored;
+
+ if(restore)
+ gla2DSetMap(di, &stored);
+ else {
+ rctf map;
+
+ gla2DGetMap(di, &stored);
+ map= stored;
+ map.xmin= get_action_frame(ob, map.xmin);
+ map.xmax= get_action_frame(ob, map.xmax);
+ if(map.xmin==map.xmax) map.xmax+= 1.0;
+ gla2DSetMap(di, &map);
+ }
+}
+
+/* the right hand side, with strips and keys */
+static void draw_nla_strips_keys(SpaceNla *snla)
+{
+ Base *base;
+ rcti scr_rct;
+ gla2DDrawInfo *di;
+ float y;
+ char col1[3], col2[3];
+
+ BIF_GetThemeColor3ubv(TH_SHADE2, col2);
+ BIF_GetThemeColor3ubv(TH_HILITE, col1);
+
+ /* Draw strips */
+
+ scr_rct.xmin= snla->area->winrct.xmin + snla->v2d.mask.xmin;
+ scr_rct.ymin= snla->area->winrct.ymin + snla->v2d.mask.ymin;
+ scr_rct.xmax= snla->area->winrct.xmin + snla->v2d.hor.xmax;
+ scr_rct.ymax= snla->area->winrct.ymin + snla->v2d.mask.ymax;
+ di= glaBegin2DDraw(&scr_rct, &G.v2d->cur);
+
+ y=count_nla_levels();
+ y*= (NLACHANNELHEIGHT+NLACHANNELSKIP);
+
+ for (base=G.scene->base.first; base; base=base->next){
+ Object *ob= base->object;
+ bActionStrip *strip;
+ int frame1_x, channel_y;
+
+ if (nla_filter(base)==0)
+ continue;
+
+ /* Draw the field */
+ glEnable (GL_BLEND);
+ if (TESTBASE_SAFE(base))
+ glColor4ub (col1[0], col1[1], col1[2], 0x22);
+ else
+ glColor4ub (col2[0], col2[1], col2[2], 0x22);
+
+ gla2DDrawTranslatePt(di, 1, y, &frame1_x, &channel_y);
+ glRectf(0, channel_y-NLACHANNELHEIGHT/2, frame1_x, channel_y+NLACHANNELHEIGHT/2);
+
+
+ if (TESTBASE_SAFE(base))
+ glColor4ub (col1[0], col1[1], col1[2], 0x44);
+ else
+ glColor4ub (col2[0], col2[1], col2[2], 0x44);
+ glRectf(frame1_x, channel_y-NLACHANNELHEIGHT/2, G.v2d->hor.xmax, channel_y+NLACHANNELHEIGHT/2);
+
+ glDisable (GL_BLEND);
+
+ /* Draw the ipo keys */
+ draw_object_channel(di, ob, y);
+
+ y-=NLACHANNELHEIGHT+NLACHANNELSKIP;
+
+ /* check if object nla-strips expanded or not */
+ if (ob->nlaflag & OB_NLA_COLLAPSED)
+ continue;
+
+
+ /* Draw the action strip */
+ if (ob->action) {
+
+ /* Draw the field */
+ glEnable (GL_BLEND);
+ if (TESTBASE_SAFE(base))
+ glColor4ub (col1[0], col1[1], col1[2], 0x22);
+ else
+ glColor4ub (col2[0], col2[1], col2[2], 0x22);
+
+ gla2DDrawTranslatePt(di, 1, y, &frame1_x, &channel_y);
+ glRectf(0, channel_y-NLACHANNELHEIGHT/2+4, frame1_x, channel_y+NLACHANNELHEIGHT/2-4);
+
+ if (TESTBASE_SAFE(base))
+ glColor4ub (col1[0], col1[1], col1[2], 0x44);
+ else
+ glColor4ub (col2[0], col2[1], col2[2], 0x44);
+ glRectf(frame1_x, channel_y-NLACHANNELHEIGHT/2+4, G.v2d->hor.xmax, channel_y+NLACHANNELHEIGHT/2-4);
+
+ glDisable (GL_BLEND);
+
+ /* Draw the action keys, optionally corrected for active strip */
+ map_active_strip(di, ob, 0);
+ draw_action_channel(di, ob->action, y);
+ map_active_strip(di, ob, 1);
+
+ y-=NLACHANNELHEIGHT+NLACHANNELSKIP;
+
+ }
+
+ /* Draw the nla strips */
+ for (strip=ob->nlastrips.first; strip; strip=strip->next){
+ int stripstart, stripend;
+ int blendstart, blendend;
+
+ /* Draw rect */
+ if (strip->flag & ACTSTRIP_SELECT)
+ BIF_ThemeColor(TH_STRIP_SELECT);
+ else
+ BIF_ThemeColor(TH_STRIP);
+
+ gla2DDrawTranslatePt(di, strip->start+strip->blendin, y, &stripstart, &channel_y);
+ gla2DDrawTranslatePt(di, strip->end-strip->blendout, y, &stripend, &channel_y);
+ glRectf(stripstart, channel_y-NLACHANNELHEIGHT/2+3, stripend, channel_y+NLACHANNELHEIGHT/2-3);
+
+ if (strip->flag & ACTSTRIP_SELECT)
+ BIF_ThemeColorShade(TH_STRIP_SELECT, -60);
+ else
+ BIF_ThemeColorShade(TH_STRIP, -60);
+
+ /* Draw blendin */
+ if (strip->blendin>0){
+ glBegin(GL_TRIANGLES);
+
+ gla2DDrawTranslatePt(di, strip->start, y, &blendstart, &channel_y);
+
+ glVertex2f(blendstart, channel_y-NLACHANNELHEIGHT/2+3);
+ glVertex2f(stripstart, channel_y+NLACHANNELHEIGHT/2-3);
+ glVertex2f(stripstart, channel_y-NLACHANNELHEIGHT/2+3);
+
+
+ glEnd();
+ }
+ if (strip->blendout>0){
+ glBegin(GL_TRIANGLES);
+
+ gla2DDrawTranslatePt(di, strip->end, y, &blendend, &channel_y);
+
+ glVertex2f(blendend, channel_y-NLACHANNELHEIGHT/2+3);
+ glVertex2f(stripend, channel_y+NLACHANNELHEIGHT/2-3);
+ glVertex2f(stripend, channel_y-NLACHANNELHEIGHT/2+3);
+ glEnd();
+ }
+
+ gla2DDrawTranslatePt(di, strip->start, y, &stripstart, &channel_y);
+ gla2DDrawTranslatePt(di, strip->end, y, &stripend, &channel_y);
+
+ /* muted strip */
+ if(strip->flag & ACTSTRIP_MUTE) {
+ glColor3f(1, 0, 0);
+ glBegin(GL_LINES);
+ glVertex2f(stripstart, channel_y-NLACHANNELHEIGHT/2+3);
+ glVertex2f(stripend, channel_y+NLACHANNELHEIGHT/2-3);
+ glEnd();
+ }
+
+ /* Draw border */
+ glEnable (GL_BLEND);
+ glBegin(GL_LINE_STRIP);
+ glColor4f(1, 1, 1, 0.7);
+
+ glVertex2f(stripstart, channel_y-NLACHANNELHEIGHT/2+3);
+ glVertex2f(stripstart, channel_y+NLACHANNELHEIGHT/2-3);
+ glVertex2f(stripend, channel_y+NLACHANNELHEIGHT/2-3);
+ glColor4f(0, 0, 0, 0.7);
+ glVertex2f(stripend, channel_y-NLACHANNELHEIGHT/2+3);
+ glVertex2f(stripstart, channel_y-NLACHANNELHEIGHT/2+3);
+ glEnd();
+
+ /* Show strip extension */
+ if (strip->flag & ACTSTRIP_HOLDLASTFRAME){
+ if (strip->flag & ACTSTRIP_SELECT)
+ BIF_ThemeColorShadeAlpha(TH_STRIP_SELECT, 0, -180);
+ else
+ BIF_ThemeColorShadeAlpha(TH_STRIP, 0, -180);
+
+ glRectf(stripend, channel_y-NLACHANNELHEIGHT/2+4, G.v2d->hor.xmax, channel_y+NLACHANNELHEIGHT/2-2);
+ }
+
+ /* Show repeat */
+ if (strip->repeat > 1.0 && !(strip->flag & ACTSTRIP_USESTRIDE)){
+ float rep = 1;
+ glBegin(GL_LINES);
+ while (rep<strip->repeat){
+ /* Draw line */
+ glColor4f(0, 0, 0, 0.5);
+ gla2DDrawTranslatePt(di, strip->start+(rep*((strip->end-strip->start)/strip->repeat)), y, &frame1_x, &channel_y);
+ glVertex2f(frame1_x, channel_y-NLACHANNELHEIGHT/2+4);
+ glVertex2f(frame1_x, channel_y+NLACHANNELHEIGHT/2-2);
+
+ glColor4f(1.0, 1.0, 1.0, 0.5);
+ gla2DDrawTranslatePt(di, strip->start+(rep*((strip->end-strip->start)/strip->repeat)), y, &frame1_x, &channel_y);
+ glVertex2f(frame1_x+1, channel_y-NLACHANNELHEIGHT/2+4);
+ glVertex2f(frame1_x+1, channel_y+NLACHANNELHEIGHT/2-2);
+ rep+=1.0;
+ }
+ glEnd();
+
+ }
+ glDisable (GL_BLEND);
+
+ y-=(NLACHANNELHEIGHT+NLACHANNELSKIP);
+ }
+ }
+ glaEnd2DDraw(di);
+
+}
+
+/* ******* panel *********** */
+
+#define B_NLA_PANEL 121
+#define B_NLA_LOCK 122
+#define B_NLA_MOD_ADD 123
+#define B_NLA_MOD_NEXT 124
+#define B_NLA_MOD_PREV 125
+#define B_NLA_MOD_DEL 126
+#define B_NLA_MOD_DEPS 127
+
+/* For now just returns the first selected strip */
+bActionStrip *get_active_nlastrip(Object **obpp)
+{
+ Base *base;
+ bActionStrip *strip;
+
+ for (base=G.scene->base.first; base; base=base->next){
+ if ((base->object->nlaflag & OB_NLA_COLLAPSED)==0) {
+ for (strip=base->object->nlastrips.first; strip; strip=strip->next){
+ if (strip->flag & ACTSTRIP_SELECT) {
+ *obpp= base->object;
+ return strip;
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+void do_nlabuts(unsigned short event)
+{
+ Object *ob;
+ bActionStrip *strip;
+
+ /* Determine if an nla strip has been selected */
+ strip = get_active_nlastrip(&ob);
+ if (!strip) return;
+
+ switch(event) {
+ case B_REDR:
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWNLA, 0);
+ break;
+ case B_NLA_PANEL:
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_OB|OB_RECALC_DATA);
+ allqueue (REDRAWNLA, 0);
+ allqueue (REDRAWVIEW3D, 0);
+ break;
+ case B_NLA_LOCK:
+ synchronize_action_strips();
+ allqueue (REDRAWNLA, 0);
+ allqueue (REDRAWACTION, 0);
+ allqueue (REDRAWVIEW3D, 0);
+ break;
+
+ case B_NLA_MOD_ADD:
+ {
+ bActionModifier *amod= MEM_callocN(sizeof(bActionModifier), "bActionModifier");
+
+ BLI_addtail(&strip->modifiers, amod);
+ strip->curmod= BLI_countlist(&strip->modifiers)-1;
+ allqueue (REDRAWNLA, 0);
+ }
+ break;
+ case B_NLA_MOD_DEL:
+ if(strip->modifiers.first) {
+ bActionModifier *amod= BLI_findlink(&strip->modifiers, strip->curmod);
+ BLI_remlink(&strip->modifiers, amod);
+ MEM_freeN(amod);
+ if(strip->curmod) strip->curmod--;
+ allqueue (REDRAWNLA, 0);
+ }
+ break;
+ case B_NLA_MOD_NEXT:
+ if(strip->curmod < BLI_countlist(&strip->modifiers)-1)
+ strip->curmod++;
+ allqueue (REDRAWNLA, 0);
+ break;
+ case B_NLA_MOD_PREV:
+ if(strip->curmod > 0)
+ strip->curmod--;
+ allqueue (REDRAWNLA, 0);
+ break;
+ case B_NLA_MOD_DEPS:
+ DAG_scene_sort(G.scene);
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_OB|OB_RECALC_DATA);
+ break;
+ }
+}
+
+static char *make_modifier_menu(ListBase *lb)
+{
+ bActionModifier *amod;
+ int index= 1;
+ char *str, item[64], *types[3]={"Deform", "Noise", "Oomph"};
+
+ for (amod = lb->first; amod; amod=amod->next, index++);
+ str= MEM_mallocN(index*64, "key string");
+ str[0]= 0;
+
+ index= 0;
+ for (amod = lb->first; amod; amod=amod->next, index++) {
+ sprintf (item, "|%s %s%%x%d", types[amod->type], amod->channel, index);
+ strcat(str, item);
+ }
+
+ return str;
+}
+
+
+static void nla_panel_properties(short cntrl) // NLA_HANDLER_PROPERTIES
+{
+ Object *ob;
+ bActionStrip *strip;
+ uiBlock *block;
+ uiBut *but;
+
+ block= uiNewBlock(&curarea->uiblocks, "nla_panel_properties", UI_EMBOSS, UI_HELV, curarea->win);
+ uiPanelControl(UI_PNL_SOLID | UI_PNL_CLOSE | cntrl);
+ uiSetPanelHandler(NLA_HANDLER_PROPERTIES); // for close and esc
+ if(uiNewPanel(curarea, block, "Transform Properties", "NLA", 10, 230, 318, 224)==0) return;
+
+ /* Determine if an nla strip has been selected */
+ strip = get_active_nlastrip(&ob);
+ if (!strip) return;
+
+ /* first labels, for simpler align code :) */
+ uiDefBut(block, LABEL, 0, "Timeline Range:", 10,180,300,19, 0, 0, 0, 0, 0, "");
+ uiDefBut(block, LABEL, 0, "Blending:", 10,120,150,19, 0, 0, 0, 0, 0, "");
+ uiDefBut(block, LABEL, 0, "Options:", 160,120,150,19, 0, 0, 0, 0, 0, "");
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_NLA_PANEL, "Strip Start:", 10,160,150,19, &strip->start, -1000.0, strip->end-1, 100, 0, "First frame in the timeline");
+ uiDefButF(block, NUM, B_NLA_PANEL, "Strip End:", 160,160,150,19, &strip->end, strip->start+1, MAXFRAMEF, 100, 0, "Last frame in the timeline");
+
+ uiDefIconButBitS(block, ICONTOG, ACTSTRIP_LOCK_ACTION, B_NLA_LOCK, ICON_UNLOCKED, 10,140,20,19, &(strip->flag), 0, 0, 0, 0, "Toggles Action end/start to be automatic mapped to strip duration");
+ if(strip->flag & ACTSTRIP_LOCK_ACTION) {
+ char str[40];
+ sprintf(str, "Action Start: %.2f", strip->actstart);
+ uiDefBut(block, LABEL, B_NOP, str, 30,140,140,19, NULL, 0.0, 0.0, 0, 0, "First frame of the action to map to the playrange");
+ sprintf(str, "Action End: %.2f", strip->actend);
+ uiDefBut(block, LABEL, B_NOP, str, 170,140,140,19, NULL, 0.0, 0.0, 0, 0, "Last frame of the action to map to the playrange");
+ }
+ else {
+ uiDefButF(block, NUM, B_NLA_PANEL, "Action Start:", 30,140,140,19, &strip->actstart, -1000.0, strip->actend-1, 100, 0, "First frame of the action to map to the playrange");
+ uiDefButF(block, NUM, B_NLA_PANEL, "Action End:", 170,140,140,19, &strip->actend, strip->actstart+1, MAXFRAMEF, 100, 0, "Last frame of the action to map to the playrange");
+ }
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, ACTSTRIP_AUTO_BLENDS, B_NLA_LOCK, "Auto-Blending", 10,100,145,19, &(strip->flag), 0, 0, 0, 0, "Toggles automatic calculation of blendin/out values");
+ if (strip->flag & ACTSTRIP_AUTO_BLENDS) {
+ char str[32];
+ sprintf(str, "In: %.2f", strip->blendin);
+ uiDefBut(block, LABEL, B_NOP, str, 10,80,77,19, NULL, 0.0, 0.0, 0, 0, "Number of frames of ease-in");
+ sprintf(str, "Out: %.2f", strip->blendout);
+ uiDefBut(block, LABEL, B_NOP, str, 77,80,78,19, NULL, 0.0, 0.0, 0, 0, "Number of frames of ease-out");
+ }
+ else {
+ uiDefButF(block, NUM, B_NLA_PANEL, "In:", 10,80,77,19, &strip->blendin, 0.0, strip->end-strip->start, 100, 0, "Number of frames of ease-in");
+ uiDefButF(block, NUM, B_NLA_PANEL, "Out:", 77,80,78,19, &strip->blendout, 0.0, strip->end-strip->start, 100, 0, "Number of frames of ease-out");
+ }
+ uiDefButBitS(block, TOG, ACTSTRIP_MUTE, B_NLA_PANEL, "Mute", 10,60,145,19, &strip->flag, 0, 0, 0, 0, "Toggles whether the strip contributes to the NLA solution");
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_NLA_PANEL, "Repeat:", 160,100,150,19, &strip->repeat, 0.001, 1000.0f, 100, 0, "Number of times the action should repeat");
+ but= uiDefButC(block, TEX, B_NLA_PANEL, "OffsBone:", 160,80,150,19, strip->offs_bone, 0, 31.0f, 0, 0, "Name of Bone that defines offset for repeat");
+ uiButSetCompleteFunc(but, autocomplete_bone, (void *)ob);
+ uiDefButBitS(block, TOG, ACTSTRIP_HOLDLASTFRAME, B_NLA_PANEL, "Hold", 160,60,75,19, &strip->flag, 0, 0, 0, 0, "Toggles whether to continue displaying the last frame past the end of the strip");
+ uiDefButS(block, TOG, B_NLA_PANEL, "Add", 235,60,75,19, &strip->mode, 0, 0, 0, 0, "Toggles additive blending mode");
+
+ uiBlockEndAlign(block);
+
+ uiDefButBitS(block, TOG, ACTSTRIP_USESTRIDE, B_NLA_PANEL, "Stride Path", 10, 30,140,19, &strip->flag, 0, 0, 0, 0, "Plays action based on path position & stride");
+
+ if (strip->offs_bone[0]) {
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, ACTSTRIP_CYCLIC_USEX, B_NLA_PANEL, "Use X", 160,30,50,19, &strip->flag, 0, 0, 0, 0, "Turn off automatic single-axis cycling and use X as an offset axis. Note that you can use multiple axes at once.");
+ uiDefButBitS(block, TOG, ACTSTRIP_CYCLIC_USEY, B_NLA_PANEL, "Use Y", 210,30,50,19, &strip->flag, 0, 0, 0, 0, "Turn off automatic single-axis cycling and use Y as an offset axis. Note that you can use multiple axes at once.");
+ uiDefButBitS(block, TOG, ACTSTRIP_CYCLIC_USEZ, B_NLA_PANEL, "Use Z", 260,30,50,19, &strip->flag, 0, 0, 0, 0, "Turn off automatic single-axis cycling and use Z as an offset axis. Note that you can use multiple axes at once.");
+ uiBlockEndAlign(block);
+ }
+
+ if(ob->dup_group)
+ uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_NLA_PANEL, "Target:", 160,30, 150, 19, &strip->object, "Target Object in this group");
+
+ if(strip->flag & ACTSTRIP_USESTRIDE) {
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, OB_DISABLE_PATH, B_NLA_PANEL, "Disable", 10,0,60,19, &ob->ipoflag, 0, 0, 0, 0, "Disable path temporally, for editing cycles");
+
+ uiDefButF(block, NUM, B_NLA_PANEL, "Offs:", 70,0,120,19, &strip->actoffs, -500, 500.0, 100, 0, "Action offset in frames to tweak cycle of the action within the stride");
+ uiDefButF(block, NUM, B_NLA_PANEL, "Stri:", 190,0,120,19, &strip->stridelen, 0.0001, 1000.0, 100, 0, "Distance covered by one complete cycle of the action specified in the Action Range");
+
+ uiDefButS(block, ROW, B_NLA_PANEL, "X", 10, -20, 33, 19, &strip->stride_axis, 1, 0, 0, 0, "Dominant axis for Stride Bone");
+ uiDefButS(block, ROW, B_NLA_PANEL, "Y", 43, -20, 33, 19, &strip->stride_axis, 1, 1, 0, 0, "Dominant axis for Stride Bone");
+ uiDefButS(block, ROW, B_NLA_PANEL, "Z", 76, -20, 34, 19, &strip->stride_axis, 1, 2, 0, 0, "Dominant axis for Stride Bone");
+
+ but= uiDefBut(block, TEX, B_NLA_PANEL, "Stride Bone:", 110, -20, 200, 19, strip->stridechannel, 1, 31, 0, 0, "Name of Bone used for stride");
+ uiButSetCompleteFunc(but, autocomplete_bone, (void *)ob);
+ }
+ else { /* modifiers */
+ bActionModifier *amod= BLI_findlink(&strip->modifiers, strip->curmod);
+
+ uiBlockBeginAlign(block);
+ uiDefBut(block, BUT, B_NLA_MOD_ADD, "Add Modifier", 10,0,140,19, NULL, 0, 0, 0, 0, "");
+ if(amod) {
+ char *strp= make_modifier_menu(&strip->modifiers);
+
+ uiDefIconBut(block, BUT, B_NLA_MOD_NEXT, ICON_TRIA_LEFT, 150,0,20,19, NULL, 0, 0, 0, 0, "Previous Modifier");
+ uiDefButS(block, MENU, B_NLA_PANEL, strp, 170,0,20,19, &strip->curmod, 0, 0, 0, 0, "Browse modifier");
+ MEM_freeN(strp);
+ uiDefIconBut(block, BUT, B_NLA_MOD_PREV, ICON_TRIA_RIGHT, 190,0,20,19, NULL, 0, 0, 0, 0, "Next Modifier");
+ uiDefButS(block, MENU, B_REDR, "Deform %x0|Noise %x1|Oomph %x2", 210,0,80,19, &amod->type, 0, 0, 0, 0, "Modifier type");
+ uiDefIconBut(block, BUT, B_NLA_MOD_DEL, ICON_X, 290,0,20,19, NULL, 0, 0, 0, 0, "Delete Modifier");
+
+ if(amod->type==ACTSTRIP_MOD_DEFORM) {
+ but= uiDefBut(block, TEX, B_NLA_PANEL, "Chan:", 10, -20, 130, 19, amod->channel, 1, 31, 0, 0, "Name of channel used for modifier");
+ uiButSetCompleteFunc(but, autocomplete_bone, (void *)ob);
+ uiDefButS(block, MENU, B_REDR, "All%x0|XY%x3|XZ%x2|YZ%x1", 140,-20,40,19, &amod->no_rot_axis, 0, 0, 0, 0, "Enable rotation axes (local for curve)");
+ uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_NLA_MOD_DEPS, "Ob:", 180,-20, 130, 19, &amod->ob, "Curve Object");
+ }
+#if 0 /* this is not really ready for the primetime yet, but is here for testing */
+ else if(amod->type==ACTSTRIP_MOD_NOISE) {
+ but= uiDefBut(block, TEX, B_NLA_PANEL, "Chan:", 10, -20, 130, 19, amod->channel, 1, 31, 0, 0, "Name of channel used for modifier");
+ uiButSetCompleteFunc(but, autocomplete_bone, (void *)ob);
+ uiDefButBitS(block, TOG, 1, B_NLA_PANEL, "L", 140, -20, 20, 19, &amod->channels, 0, 24, 0, 0, "Apply noise to Location of channel");
+ uiDefButBitS(block, TOG, 2, B_NLA_PANEL, "R", 160, -20, 20, 19, &amod->channels, 0, 24, 0, 0, "Apply noise to Rotation of channel");
+ uiDefButBitS(block, TOG, 4, B_NLA_PANEL, "S", 180, -20, 20, 19, &amod->channels, 0, 24, 0, 0, "Apply noise to Scaling of channel");
+ uiDefButF(block, NUM, B_NLA_PANEL, "NSize:", 200,-20,55,19, &amod->noisesize, 0.0001, 2.0, 10, 0, "Sets scaling for noise input");
+ uiDefButF(block, NUM, B_NLA_PANEL, "Turb:", 255,-20,55,19, &amod->turbul, 0.0, 200.0, 10, 0, "Sets the depth of the noise");
+ }
+#endif
+ else
+ uiDefBut(block, LABEL, B_NOP, "Ack! Not implemented.", 10, -20, 150, 19, NULL, 0, 0, 0, 0, "");
+
+ }
+ else { /* for panel aligning */
+ uiBlockEndAlign(block);
+ uiDefBut(block, LABEL, B_NOP, " ", 10, -20, 150, 19, NULL, 0, 0, 0, 0, "");
+ }
+ }
+}
+
+static void nla_blockhandlers(ScrArea *sa)
+{
+ SpaceNla *snla= sa->spacedata.first;
+ short a;
+
+ for(a=0; a<SPACE_MAXHANDLER; a+=2) {
+ switch(snla->blockhandler[a]) {
+
+ case NLA_HANDLER_PROPERTIES:
+ nla_panel_properties(snla->blockhandler[a+1]);
+ break;
+
+ }
+ /* clear action value for event */
+ snla->blockhandler[a+1]= 0;
+ }
+ uiDrawBlocksPanels(sa, 0);
+}
+
+
+void drawnlaspace(ScrArea *sa, void *spacedata)
+{
+ float col[3];
+ short ofsx = 0, ofsy = 0;
+
+ uiFreeBlocksWin(&sa->uiblocks, sa->win); /* for panel handler to work */
+
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) ;
+
+ calc_scrollrcts(sa, G.v2d, curarea->winx, curarea->winy);
+
+ /* clear all, becomes the color for left part */
+ BIF_GetThemeColor3fv(TH_HEADER, col);
+ glClearColor(col[0], col[1], col[2], 0.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ if(curarea->winx>SCROLLB+10 && curarea->winy>SCROLLH+10) {
+ if(G.v2d->scroll) {
+ ofsx= curarea->winrct.xmin;
+ ofsy= curarea->winrct.ymin;
+ glViewport(ofsx+G.v2d->mask.xmin, ofsy+G.v2d->mask.ymin, ( ofsx+G.v2d->mask.xmax-1)-(ofsx+G.v2d->mask.xmin)+1, ( ofsy+G.v2d->mask.ymax-1)-( ofsy+G.v2d->mask.ymin)+1);
+ glScissor(ofsx+G.v2d->mask.xmin, ofsy+G.v2d->mask.ymin, ( ofsx+G.v2d->mask.xmax-1)-(ofsx+G.v2d->mask.xmin)+1, ( ofsy+G.v2d->mask.ymax-1)-( ofsy+G.v2d->mask.ymin)+1);
+ }
+ }
+
+ BIF_GetThemeColor3fv(TH_BACK, col);
+ glClearColor(col[0], col[1], col[2], 0.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ myortho2(G.v2d->cur.xmin, G.v2d->cur.xmax, G.v2d->cur.ymin, G.v2d->cur.ymax);
+ bwin_clear_viewmat(sa->win); /* clear buttons view */
+ glLoadIdentity();
+
+ /* Draw backdrop */
+ calc_ipogrid();
+ draw_ipogrid();
+
+ /* the right hand side, with strips and keys */
+ draw_nla_strips_keys(G.snla);
+
+
+ glViewport(ofsx+G.v2d->mask.xmin, ofsy+G.v2d->mask.ymin, ( ofsx+G.v2d->mask.xmax-1)-(ofsx+G.v2d->mask.xmin)+1, ( ofsy+G.v2d->mask.ymax-1)-( ofsy+G.v2d->mask.ymin)+1);
+ glScissor(ofsx+G.v2d->mask.xmin, ofsy+G.v2d->mask.ymin, ( ofsx+G.v2d->mask.xmax-1)-(ofsx+G.v2d->mask.xmin)+1, ( ofsy+G.v2d->mask.ymax-1)-( ofsy+G.v2d->mask.ymin)+1);
+ myortho2 (G.v2d->cur.xmin, G.v2d->cur.xmax, G.v2d->cur.ymin, G.v2d->cur.ymax);
+
+ /* Draw current frame */
+ draw_cfra_action();
+
+ /* draw markers */
+ draw_markers_timespace(0);
+
+ /* Draw preview 'curtains' */
+ draw_anim_preview_timespace();
+
+ /* Draw scroll */
+ mywinset(curarea->win); // reset scissor too
+ if(curarea->winx>SCROLLB+10 && curarea->winy>SCROLLH+10) {
+ myortho2(-0.375, curarea->winx-0.375, -0.375, curarea->winy-0.375);
+ if(G.v2d->scroll) drawscroll(0);
+ }
+ if(G.v2d->mask.xmin!=0) {
+ /* Draw channel names */
+ draw_nla_channels();
+ }
+ mywinset(curarea->win); // reset scissor too
+ myortho2(-0.375, sa->winx-0.375, -0.375, sa->winy-0.375);
+ draw_area_emboss(sa);
+
+ /* it is important to end a view in a transform compatible with buttons */
+ bwin_scalematrix(sa->win, G.snla->blockscale, G.snla->blockscale, G.snla->blockscale);
+ nla_blockhandlers(sa);
+
+ curarea->win_swap= WIN_BACK_OK;
+}
+
+int count_nla_levels(void)
+{
+ Base *base;
+ int y= 0;
+
+ for (base=G.scene->base.first; base; base=base->next) {
+ if (nla_filter(base)) {
+ /* object level */
+ y++;
+
+ /* nla strips for object collapsed? */
+ if ((base->object->nlaflag & OB_NLA_COLLAPSED)==0) {
+ if(base->object->action)
+ y++;
+
+ /* Nla strips */
+ y+= BLI_countlist(&base->object->nlastrips);
+ }
+ }
+ }
+
+ return y;
+}
+
+int nla_filter (Base *base)
+{
+ Object *ob = base->object;
+
+ if ((G.snla->flag & SNLA_ALLKEYED) || (base->lay & G.scene->lay)) {
+ if(ob->action || ob->nlastrips.first)
+ return 1;
+
+ /* should become option */
+ if (ob->ipo)
+ return 1;
+
+ if (ob->constraintChannels.first)
+ return 1;
+ }
+ return 0;
+}
+
diff --git a/source/blender/src/drawnode.c b/source/blender/src/drawnode.c
new file mode 100644
index 00000000000..256633524e4
--- /dev/null
+++ b/source/blender/src/drawnode.c
@@ -0,0 +1,2871 @@
+/**
+ * $Id:
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "DNA_action_types.h"
+#include "DNA_color_types.h"
+#include "DNA_customdata_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_ID.h"
+#include "DNA_image_types.h"
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BKE_global.h"
+#include "BKE_image.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_node.h"
+#include "BKE_object.h"
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
+
+#include "CMP_node.h"
+#include "SHD_node.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+#include "BIF_interface.h"
+#include "BIF_interface_icons.h"
+#include "BIF_language.h"
+#include "BIF_mywindow.h"
+#include "BIF_previewrender.h"
+#include "BIF_resources.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+
+#include "BSE_drawipo.h"
+#include "BSE_node.h"
+#include "BSE_view.h"
+
+#include "BMF_Api.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "RE_pipeline.h"
+#include "IMB_imbuf_types.h"
+
+#include "blendef.h"
+#include "butspace.h"
+#include "interface.h" /* urm... for rasterpos_safe, roundbox */
+#include "mydevice.h"
+
+extern void autocomplete_uv(char *str, void *arg_v);
+extern int verify_valid_uv_name(char *str);
+
+/* autocomplete callback for buttons */
+static void autocomplete_vcol(char *str, void *arg_v)
+{
+ Mesh *me;
+ CustomDataLayer *layer;
+ AutoComplete *autocpl;
+ int a;
+
+ if(str[0]==0)
+ return;
+
+ autocpl= autocomplete_begin(str, 32);
+
+ /* search if str matches the beginning of name */
+ for(me= G.main->mesh.first; me; me=me->id.next)
+ for(a=0, layer= me->fdata.layers; a<me->fdata.totlayer; a++, layer++)
+ if(layer->type == CD_MCOL)
+ autocomplete_do_name(autocpl, layer->name);
+
+ autocomplete_end(autocpl, str);
+}
+
+static int verify_valid_vcol_name(char *str)
+{
+ Mesh *me;
+ CustomDataLayer *layer;
+ int a;
+
+ if(str[0]==0)
+ return 1;
+
+ /* search if str matches the name */
+ for(me= G.main->mesh.first; me; me=me->id.next)
+ for(a=0, layer= me->fdata.layers; a<me->fdata.totlayer; a++, layer++)
+ if(layer->type == CD_MCOL)
+ if(strcmp(layer->name, str)==0)
+ return 1;
+
+ return 0;
+}
+
+static void snode_drawstring(SpaceNode *snode, char *str, int okwidth)
+{
+ char drawstr[NODE_MAXSTR];
+ int width;
+
+ if(str[0]==0 || okwidth<4) return;
+
+ BLI_strncpy(drawstr, str, NODE_MAXSTR);
+ width= snode->aspect*BIF_GetStringWidth(snode->curfont, drawstr, 0);
+
+ if(width > okwidth) {
+ int len= strlen(drawstr)-1;
+
+ while(width > okwidth && len>=0) {
+ drawstr[len]= 0;
+
+ width= snode->aspect*BIF_GetStringWidth(snode->curfont, drawstr, 0);
+ len--;
+ }
+ if(len==0) return;
+ }
+ BIF_DrawString(snode->curfont, drawstr, 0);
+
+}
+
+/* ************** Socket callbacks *********** */
+
+static void socket_vector_menu_cb(void *node_v, void *ntree_v)
+{
+ if(node_v && ntree_v) {
+ NodeTagChanged(ntree_v, node_v);
+ addqueue(curarea->win, UI_BUT_EVENT, B_NODE_EXEC+((bNode *)node_v)->nr);
+ }
+}
+
+/* NOTE: this is a block-menu, needs 0 events, otherwise the menu closes */
+static uiBlock *socket_vector_menu(void *socket_v)
+{
+ SpaceNode *snode= curarea->spacedata.first;
+ bNode *node;
+ bNodeSocket *sock= socket_v;
+ bNodeStack *ns= &sock->ns;
+ uiBlock *block;
+ uiBut *bt;
+
+ /* a bit ugly... retrieve the node the socket comes from */
+ for(node= snode->nodetree->nodes.first; node; node= node->next) {
+ bNodeSocket *sockt;
+ for(sockt= node->inputs.first; sockt; sockt= sockt->next)
+ if(sockt==sock)
+ break;
+ if(sockt)
+ break;
+ }
+
+ block= uiNewBlock(&curarea->uiblocks, "socket menu", UI_EMBOSS, UI_HELV, curarea->win);
+
+ /* use this for a fake extra empy space around the buttons */
+ uiDefBut(block, LABEL, 0, "", -4, -4, 188, 68, NULL, 0, 0, 0, 0, "");
+
+ uiBlockBeginAlign(block);
+ bt= uiDefButF(block, NUMSLI, 0, "X ", 0,40,180,20, ns->vec, ns->min, ns->max, 10, 0, "");
+ uiButSetFunc(bt, socket_vector_menu_cb, node, snode->nodetree);
+ bt= uiDefButF(block, NUMSLI, 0, "Y ", 0,20,180,20, ns->vec+1, ns->min, ns->max, 10, 0, "");
+ uiButSetFunc(bt, socket_vector_menu_cb, node, snode->nodetree);
+ bt= uiDefButF(block, NUMSLI, 0, "Z ", 0,0,180,20, ns->vec+2, ns->min, ns->max, 10, 0, "");
+ uiButSetFunc(bt, socket_vector_menu_cb, node, snode->nodetree);
+
+ uiBlockSetDirection(block, UI_TOP);
+
+ allqueue(REDRAWNODE, 0);
+
+ return block;
+}
+
+static void node_sync_cb(void *snode_v, void *node_v)
+{
+ SpaceNode *snode= snode_v;
+
+ if(snode->treetype==NTREE_SHADER) {
+ nodeShaderSynchronizeID(node_v, 1);
+ allqueue(REDRAWBUTSSHADING, 0);
+ }
+}
+
+/* ****************** GENERAL CALLBACKS FOR NODES ***************** */
+
+static void node_ID_title_cb(void *node_v, void *unused_v)
+{
+ bNode *node= node_v;
+
+ if(node->id) {
+ test_idbutton(node->id->name+2); /* library.c, verifies unique name */
+ BLI_strncpy(node->name, node->id->name+2, 21);
+
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWNODE, 0);
+ allqueue(REDRAWOOPS, 0);
+ }
+}
+
+
+static void node_but_title_cb(void *node_v, void *but_v)
+{
+ bNode *node= node_v;
+ uiBut *bt= but_v;
+ BLI_strncpy(node->name, bt->drawstr, NODE_MAXSTR);
+
+ allqueue(REDRAWNODE, 0);
+}
+
+
+/* ****************** BUTTON CALLBACKS FOR ALL TREES ***************** */
+
+static int node_buts_group(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
+{
+ if(block && node->id) {
+ uiBut *bt;
+ short width;
+
+ uiBlockBeginAlign(block);
+
+ /* name button */
+ width= (short)(butr->xmax-butr->xmin - (node->id->us>1?19.0f:0.0f));
+ bt= uiDefBut(block, TEX, B_NOP, "NT:",
+ butr->xmin, butr->ymin, width, 19,
+ node->id->name+2, 0.0, 19.0, 0, 0, "NodeTree name");
+ uiButSetFunc(bt, node_ID_title_cb, node, NULL);
+
+ /* user amount */
+ if(node->id->us>1) {
+ char str1[32];
+ sprintf(str1, "%d", node->id->us);
+ bt= uiDefBut(block, BUT, B_NOP, str1,
+ butr->xmax-19, butr->ymin, 19, 19,
+ NULL, 0, 0, 0, 0, "Displays number of users. Click to make a single-user copy.");
+ //uiButSetFunc(bt, node_mat_alone_cb, node, NULL);
+ }
+
+ uiBlockEndAlign(block);
+ }
+ return 19;
+}
+
+static int node_buts_value(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
+{
+ if(block) {
+ bNodeSocket *sock= node->outputs.first; /* first socket stores value */
+
+ uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "",
+ butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20,
+ sock->ns.vec, sock->ns.min, sock->ns.max, 10, 2, "");
+
+ }
+ return 20;
+}
+
+static int node_buts_rgb(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
+{
+ if(block) {
+ bNodeSocket *sock= node->outputs.first; /* first socket stores value */
+ if(sock) {
+ /* enforce square box drawing */
+ uiBlockSetEmboss(block, UI_EMBOSSP);
+
+ uiDefButF(block, HSVCUBE, B_NODE_EXEC+node->nr, "",
+ butr->xmin, butr->ymin, butr->xmax-butr->xmin, 12,
+ sock->ns.vec, 0.0f, 1.0f, 3, 0, "");
+ uiDefButF(block, HSVCUBE, B_NODE_EXEC+node->nr, "",
+ butr->xmin, butr->ymin+15, butr->xmax-butr->xmin, butr->ymax-butr->ymin -15 -15,
+ sock->ns.vec, 0.0f, 1.0f, 2, 0, "");
+ uiDefButF(block, COL, B_NOP, "",
+ butr->xmin, butr->ymax-12, butr->xmax-butr->xmin, 12,
+ sock->ns.vec, 0.0, 0.0, -1, 0, "");
+ /* the -1 above prevents col button to popup a color picker */
+
+ uiBlockSetEmboss(block, UI_EMBOSS);
+ }
+ }
+ return 30 + (int)(node->width-NODE_DY);
+}
+
+static int node_buts_mix_rgb(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
+{
+ if(block) {
+ uiBut *bt;
+ int a_but= (ntree->type==NTREE_COMPOSIT);
+
+ /* blend type */
+ uiBlockBeginAlign(block);
+ bt=uiDefButS(block, MENU, B_NODE_EXEC+node->nr, "Mix %x0|Add %x1|Subtract %x3|Multiply %x2|Screen %x4|Overlay %x9|Divide %x5|Difference %x6|Darken %x7|Lighten %x8|Dodge %x10|Burn %x11|Color %x15|Value %x14|Saturation %x13|Hue %x12",
+ butr->xmin, butr->ymin, butr->xmax-butr->xmin -(a_but?20:0), 20,
+ &node->custom1, 0, 0, 0, 0, "");
+ uiButSetFunc(bt, node_but_title_cb, node, bt);
+ /* Alpha option, composite */
+ if(a_but)
+ uiDefButS(block, TOG, B_NODE_EXEC+node->nr, "A",
+ butr->xmax-20, butr->ymin, 20, 20,
+ &node->custom2, 0, 0, 0, 0, "Include Alpha of 2nd input in this operation");
+ }
+ return 20;
+}
+
+static int node_buts_time(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
+{
+ if(block) {
+ CurveMapping *cumap= node->storage;
+ short dx= (short)((butr->xmax-butr->xmin)/2);
+ butr->ymin += 26;
+
+ curvemap_buttons(block, node->storage, 's', B_NODE_EXEC+node->nr, B_REDR, butr);
+
+ if(cumap) cumap->flag |= CUMA_DRAW_CFRA;
+ if(node->custom1<node->custom2)
+ cumap->black[0]= (float)(CFRA - node->custom1)/(float)(node->custom2-node->custom1);
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, NUM, B_NODE_EXEC+node->nr, "Sta:",
+ butr->xmin, butr->ymin-22, dx, 19,
+ &node->custom1, 1.0, 20000.0, 0, 0, "Start frame");
+ uiDefButS(block, NUM, B_NODE_EXEC+node->nr, "End:",
+ butr->xmin+dx, butr->ymin-22, dx, 19,
+ &node->custom2, 1.0, 20000.0, 0, 0, "End frame");
+ }
+
+ return node->width-NODE_DY;
+}
+
+static int node_buts_valtorgb(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
+{
+ if(block) {
+ if(node->storage) {
+ draw_colorband_buts_small(block, node->storage, butr, B_NODE_EXEC+node->nr);
+ }
+ }
+ return 40;
+}
+
+static int node_buts_curvevec(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
+{
+ if(block) {
+ curvemap_buttons(block, node->storage, 'v', B_NODE_EXEC+node->nr, B_REDR, butr);
+ }
+ return (int)(node->width-NODE_DY);
+}
+
+static int node_buts_curvecol(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
+{
+ if(block) {
+ curvemap_buttons(block, node->storage, 'c', B_NODE_EXEC+node->nr, B_REDR, butr);
+ }
+ return (int)(node->width-NODE_DY);
+}
+
+static int node_buts_normal(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
+{
+ if(block) {
+ bNodeSocket *sock= node->outputs.first; /* first socket stores normal */
+
+ uiDefButF(block, BUT_NORMAL, B_NODE_EXEC+node->nr, "",
+ butr->xmin, butr->ymin, butr->xmax-butr->xmin, butr->ymax-butr->ymin,
+ sock->ns.vec, 0.0f, 1.0f, 0, 0, "");
+
+ }
+ return (int)(node->width-NODE_DY);
+}
+
+static void node_browse_tex_cb(void *ntree_v, void *node_v)
+{
+ bNodeTree *ntree= ntree_v;
+ bNode *node= node_v;
+ Tex *tex;
+
+ if(node->menunr<1) return;
+
+ if(node->id) {
+ node->id->us--;
+ node->id= NULL;
+ }
+ tex= BLI_findlink(&G.main->tex, node->menunr-1);
+
+ node->id= &tex->id;
+ id_us_plus(node->id);
+ BLI_strncpy(node->name, node->id->name+2, 21);
+
+ nodeSetActive(ntree, node);
+
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWNODE, 0);
+ NodeTagChanged(ntree, node);
+
+ node->menunr= 0;
+}
+
+static int node_buts_texture(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
+{
+ if(block) {
+ uiBut *bt;
+ char *strp;
+
+ /* browse button texture */
+ uiBlockBeginAlign(block);
+ IDnames_to_pupstring(&strp, NULL, "", &(G.main->tex), NULL, NULL);
+ node->menunr= 0;
+ bt= uiDefButS(block, MENU, B_NODE_EXEC+node->nr, strp,
+ butr->xmin, butr->ymin, 20, 19,
+ &node->menunr, 0, 0, 0, 0, "Browse texture");
+ uiButSetFunc(bt, node_browse_tex_cb, ntree, node);
+ if(strp) MEM_freeN(strp);
+
+ if(node->id) {
+ bt= uiDefBut(block, TEX, B_NOP, "TE:",
+ butr->xmin+19, butr->ymin, butr->xmax-butr->xmin-19, 19,
+ node->id->name+2, 0.0, 19.0, 0, 0, "Texture name");
+ uiButSetFunc(bt, node_ID_title_cb, node, NULL);
+ }
+
+ }
+ return 19;
+}
+
+static int node_buts_math(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
+{
+ if(block) {
+ uiBut *bt;
+
+ bt=uiDefButS(block, MENU, B_NODE_EXEC, "Add %x0|Subtract %x1|Multiply %x2|Divide %x3|Sine %x4|Cosine %x5|Tangent %x6|Arcsine %x7|Arccosine %x8|Arctangent %x9|Power %x10|Logarithm %x11|Minimum %x12|Maximum %x13|Round %x14", butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, &node->custom1, 0, 0, 0, 0, "");
+ uiButSetFunc(bt, node_but_title_cb, node, bt);
+ }
+ return 20;
+}
+
+
+/* ****************** BUTTON CALLBACKS FOR SHADER NODES ***************** */
+
+
+static void node_mat_alone_cb(void *node_v, void *unused)
+{
+ bNode *node= node_v;
+
+ node->id= (ID *)copy_material((Material *)node->id);
+
+ BIF_undo_push("Single user material");
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWNODE, 0);
+ allqueue(REDRAWOOPS, 0);
+}
+
+static void node_browse_mat_cb(void *ntree_v, void *node_v)
+{
+ bNodeTree *ntree= ntree_v;
+ bNode *node= node_v;
+
+ if(node->menunr<1) return;
+
+ if(node->menunr==32767) { /* code for Add New */
+ if(node->id) {
+ /* make copy, but make sure it doesnt have the node tag nor nodes */
+ Material *ma= (Material *)node->id;
+ ma->id.us--;
+ ma= copy_material(ma);
+ ma->use_nodes= 0;
+ if(ma->nodetree) {
+ ntreeFreeTree(ma->nodetree);
+ MEM_freeN(ma->nodetree);
+ }
+ ma->nodetree= NULL;
+ node->id= (ID *)ma;
+ }
+ else node->id= (ID *)add_material("MatNode");
+ }
+ else {
+ if(node->id) node->id->us--;
+ node->id= BLI_findlink(&G.main->mat, node->menunr-1);
+ id_us_plus(node->id);
+ }
+ BLI_strncpy(node->name, node->id->name+2, 21);
+
+ nodeSetActive(ntree, node);
+
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWNODE, 0);
+ BIF_preview_changed(ID_MA);
+
+ node->menunr= 0;
+}
+
+static void node_new_mat_cb(void *ntree_v, void *node_v)
+{
+ bNodeTree *ntree= ntree_v;
+ bNode *node= node_v;
+
+ node->id= (ID *)add_material("MatNode");
+ BLI_strncpy(node->name, node->id->name+2, 21);
+
+ nodeSetActive(ntree, node);
+
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWNODE, 0);
+ BIF_preview_changed(ID_MA);
+
+}
+
+static void node_texmap_cb(void *texmap_v, void *unused_v)
+{
+ init_mapping(texmap_v);
+}
+
+static int node_shader_buts_material(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
+{
+ if(block) {
+ uiBut *bt;
+ short dx= (short)((butr->xmax-butr->xmin)/3.0f), has_us= (node->id && node->id->us>1);
+ short dy= (short)butr->ymin;
+ char *strp;
+
+ /* WATCH IT: we use this callback in material buttons, but then only want first row */
+ if(butr->ymax-butr->ymin > 21.0f) dy+= 19;
+
+ uiBlockBeginAlign(block);
+ if(node->id==NULL) uiBlockSetCol(block, TH_REDALERT);
+ else if(has_us) uiBlockSetCol(block, TH_BUT_SETTING1);
+ else uiBlockSetCol(block, TH_BUT_SETTING2);
+
+ /* browse button */
+ IDnames_to_pupstring(&strp, NULL, "ADD NEW %x32767", &(G.main->mat), NULL, NULL);
+ node->menunr= 0;
+ bt= uiDefButS(block, MENU, B_NOP, strp,
+ butr->xmin, dy, 19, 19,
+ &node->menunr, 0, 0, 0, 0, "Browses existing choices or adds NEW");
+ uiButSetFunc(bt, node_browse_mat_cb, ntree, node);
+ if(strp) MEM_freeN(strp);
+
+ /* Add New button */
+ if(node->id==NULL) {
+ bt= uiDefBut(block, BUT, B_NOP, "Add New",
+ butr->xmin+19, dy, (short)(butr->xmax-butr->xmin-19.0f), 19,
+ NULL, 0.0, 0.0, 0, 0, "Add new Material");
+ uiButSetFunc(bt, node_new_mat_cb, ntree, node);
+ uiBlockSetCol(block, TH_AUTO);
+ }
+ else {
+ /* name button */
+ short width= (short)(butr->xmax-butr->xmin-19.0f - (has_us?19.0f:0.0f));
+ bt= uiDefBut(block, TEX, B_NOP, "MA:",
+ butr->xmin+19, dy, width, 19,
+ node->id->name+2, 0.0, 19.0, 0, 0, "Material name");
+ uiButSetFunc(bt, node_ID_title_cb, node, NULL);
+
+ /* user amount */
+ if(has_us) {
+ char str1[32];
+ sprintf(str1, "%d", node->id->us);
+ bt= uiDefBut(block, BUT, B_NOP, str1,
+ butr->xmax-19, dy, 19, 19,
+ NULL, 0, 0, 0, 0, "Displays number of users. Click to make a single-user copy.");
+ uiButSetFunc(bt, node_mat_alone_cb, node, NULL);
+ }
+
+ /* WATCH IT: we use this callback in material buttons, but then only want first row */
+ if(butr->ymax-butr->ymin > 21.0f) {
+ /* node options */
+ uiBlockSetCol(block, TH_AUTO);
+ uiDefButBitS(block, TOG, SH_NODE_MAT_DIFF, B_NODE_EXEC+node->nr, "Diff",
+ butr->xmin, butr->ymin, dx, 19,
+ &node->custom1, 0, 0, 0, 0, "Material Node outputs Diffuse");
+ uiDefButBitS(block, TOG, SH_NODE_MAT_SPEC, B_NODE_EXEC+node->nr, "Spec",
+ butr->xmin+dx, butr->ymin, dx, 19,
+ &node->custom1, 0, 0, 0, 0, "Material Node outputs Specular");
+ uiDefButBitS(block, TOG, SH_NODE_MAT_NEG, B_NODE_EXEC+node->nr, "Neg Normal",
+ butr->xmax-dx, butr->ymin, dx, 19,
+ &node->custom1, 0, 0, 0, 0, "Material Node uses inverted Normal");
+ }
+ }
+ uiBlockEndAlign(block);
+ }
+ return 38;
+}
+
+static int node_shader_buts_mapping(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
+{
+ if(block) {
+ TexMapping *texmap= node->storage;
+ short dx= (short)((butr->xmax-butr->xmin)/7.0f);
+ short dy= (short)(butr->ymax-19);
+
+ uiBlockSetFunc(block, node_texmap_cb, texmap, NULL); /* all buttons get this */
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "", butr->xmin+dx, dy, 2*dx, 19, texmap->loc, -1000.0f, 1000.0f, 10, 2, "");
+ uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "", butr->xmin+3*dx, dy, 2*dx, 19, texmap->loc+1, -1000.0f, 1000.0f, 10, 2, "");
+ uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "", butr->xmin+5*dx, dy, 2*dx, 19, texmap->loc+2, -1000.0f, 1000.0f, 10, 2, "");
+ dy-= 19;
+ uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "", butr->xmin+dx, dy, 2*dx, 19, texmap->rot, -1000.0f, 1000.0f, 1000, 1, "");
+ uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "", butr->xmin+3*dx, dy, 2*dx, 19, texmap->rot+1, -1000.0f, 1000.0f, 1000, 1, "");
+ uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "", butr->xmin+5*dx, dy, 2*dx, 19, texmap->rot+2, -1000.0f, 1000.0f, 1000, 1, "");
+ dy-= 19;
+ uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "", butr->xmin+dx, dy, 2*dx, 19, texmap->size, -1000.0f, 1000.0f, 10, 2, "");
+ uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "", butr->xmin+3*dx, dy, 2*dx, 19, texmap->size+1, -1000.0f, 1000.0f, 10, 2, "");
+ uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "", butr->xmin+5*dx, dy, 2*dx, 19, texmap->size+2, -1000.0f, 1000.0f, 10, 2, "");
+ dy-= 25;
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "", butr->xmin+dx, dy, 2*dx, 19, texmap->min, -10.0f, 10.0f, 100, 2, "");
+ uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "", butr->xmin+3*dx, dy, 2*dx, 19, texmap->min+1, -10.0f, 10.0f, 100, 2, "");
+ uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "", butr->xmin+5*dx, dy, 2*dx, 19, texmap->min+2, -10.0f, 10.0f, 100, 2, "");
+ dy-= 19;
+ uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "", butr->xmin+dx, dy, 2*dx, 19, texmap->max, -10.0f, 10.0f, 10, 2, "");
+ uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "", butr->xmin+3*dx, dy, 2*dx, 19, texmap->max+1, -10.0f, 10.0f, 10, 2, "");
+ uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "", butr->xmin+5*dx, dy, 2*dx, 19, texmap->max+2, -10.0f, 10.0f, 10, 2, "");
+ uiBlockEndAlign(block);
+
+ /* labels/options */
+
+ dy= (short)(butr->ymax-19);
+ uiDefBut(block, LABEL, B_NOP, "Loc", butr->xmin, dy, dx, 19, NULL, 0.0f, 0.0f, 0, 0, "");
+ dy-= 19;
+ uiDefBut(block, LABEL, B_NOP, "Rot", butr->xmin, dy, dx, 19, NULL, 0.0f, 0.0f, 0, 0, "");
+ dy-= 19;
+ uiDefBut(block, LABEL, B_NOP, "Size", butr->xmin, dy, dx, 19, NULL, 0.0f, 0.0f, 0, 0, "");
+ dy-= 25;
+ uiDefButBitI(block, TOG, TEXMAP_CLIP_MIN, B_NODE_EXEC+node->nr, "Min", butr->xmin, dy, dx-4, 19, &texmap->flag, 0.0f, 0.0f, 0, 0, "");
+ dy-= 19;
+ uiDefButBitI(block, TOG, TEXMAP_CLIP_MAX, B_NODE_EXEC+node->nr, "Max", butr->xmin, dy, dx-4, 19, &texmap->flag, 0.0f, 0.0f, 0, 0, "");
+
+ }
+ return 5*19 + 6;
+}
+
+static int node_shader_buts_vect_math(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
+{
+ if(block) {
+ uiBut *bt;
+
+ bt=uiDefButS(block, MENU, B_NODE_EXEC, "Add %x0|Subtract %x1|Average %x2|Dot Product %x3 |Cross Product %x4|Normalize %x5", butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, &node->custom1, 0, 0, 0, 0, "");
+ uiButSetFunc(bt, node_but_title_cb, node, bt);
+ }
+ return 20;
+}
+
+static int node_shader_buts_geometry(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
+{
+ if(block) {
+ uiBut *but;
+ NodeGeometry *ngeo= (NodeGeometry*)node->storage;
+
+ if(!verify_valid_uv_name(ngeo->uvname))
+ uiBlockSetCol(block, TH_REDALERT);
+ but= uiDefBut(block, TEX, B_NODE_EXEC+node->nr, "UV:", butr->xmin, butr->ymin+20, butr->xmax-butr->xmin, 20, ngeo->uvname, 0, 31, 0, 0, "Set name of UV layer to use, default is active UV layer");
+ uiButSetCompleteFunc(but, autocomplete_uv, NULL);
+ uiBlockSetCol(block, TH_AUTO);
+
+ if(!verify_valid_vcol_name(ngeo->colname))
+ uiBlockSetCol(block, TH_REDALERT);
+ but= uiDefBut(block, TEX, B_NODE_EXEC+node->nr, "Col:", butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, ngeo->colname, 0, 31, 0, 0, "Set name of vertex color layer to use, default is active vertex color layer");
+ uiButSetCompleteFunc(but, autocomplete_vcol, NULL);
+ uiBlockSetCol(block, TH_AUTO);
+ }
+
+ return 40;
+}
+
+/* only once called */
+static void node_shader_set_butfunc(bNodeType *ntype)
+{
+ switch(ntype->type) {
+ /* case NODE_GROUP: note, typeinfo for group is generated... see "XXX ugly hack" */
+
+ case SH_NODE_MATERIAL:
+ case SH_NODE_MATERIAL_EXT:
+ ntype->butfunc= node_shader_buts_material;
+ break;
+ case SH_NODE_TEXTURE:
+ ntype->butfunc= node_buts_texture;
+ break;
+ case SH_NODE_NORMAL:
+ ntype->butfunc= node_buts_normal;
+ break;
+ case SH_NODE_CURVE_VEC:
+ ntype->butfunc= node_buts_curvevec;
+ break;
+ case SH_NODE_CURVE_RGB:
+ ntype->butfunc= node_buts_curvecol;
+ break;
+ case SH_NODE_MAPPING:
+ ntype->butfunc= node_shader_buts_mapping;
+ break;
+ case SH_NODE_VALUE:
+ ntype->butfunc= node_buts_value;
+ break;
+ case SH_NODE_RGB:
+ ntype->butfunc= node_buts_rgb;
+ break;
+ case SH_NODE_MIX_RGB:
+ ntype->butfunc= node_buts_mix_rgb;
+ break;
+ case SH_NODE_VALTORGB:
+ ntype->butfunc= node_buts_valtorgb;
+ break;
+ case SH_NODE_MATH:
+ ntype->butfunc= node_buts_math;
+ break;
+ case SH_NODE_VECT_MATH:
+ ntype->butfunc= node_shader_buts_vect_math;
+ break;
+ case SH_NODE_GEOMETRY:
+ ntype->butfunc= node_shader_buts_geometry;
+ break;
+ default:
+ ntype->butfunc= NULL;
+ }
+}
+
+/* ****************** BUTTON CALLBACKS FOR COMPOSITE NODES ***************** */
+
+
+
+static void node_browse_image_cb(void *ntree_v, void *node_v)
+{
+ bNodeTree *ntree= ntree_v;
+ bNode *node= node_v;
+
+ nodeSetActive(ntree, node);
+
+ if(node->menunr<1) return;
+ if(node->menunr==32767) { /* code for Load New */
+ addqueue(curarea->win, UI_BUT_EVENT, B_NODE_LOADIMAGE);
+ }
+ else {
+ if(node->id) node->id->us--;
+ node->id= BLI_findlink(&G.main->image, node->menunr-1);
+ id_us_plus(node->id);
+
+ BLI_strncpy(node->name, node->id->name+2, 21);
+
+ NodeTagChanged(ntree, node);
+ BKE_image_signal((Image *)node->id, node->storage, IMA_SIGNAL_USER_NEW_IMAGE);
+ addqueue(curarea->win, UI_BUT_EVENT, B_NODE_EXEC+node->nr);
+ }
+ node->menunr= 0;
+}
+
+static void node_active_cb(void *ntree_v, void *node_v)
+{
+ nodeSetActive(ntree_v, node_v);
+}
+static void node_image_type_cb(void *node_v, void *unused)
+{
+
+ allqueue(REDRAWNODE, 1);
+}
+
+static char *node_image_type_pup(void)
+{
+ char *str= MEM_mallocN(256, "image type pup");
+ int a;
+
+ str[0]= 0;
+
+ a= sprintf(str, "Image Type %%t|");
+ a+= sprintf(str+a, " Image %%x%d %%i%d|", IMA_SRC_FILE, ICON_IMAGE_DEHLT);
+ a+= sprintf(str+a, " Movie %%x%d %%i%d|", IMA_SRC_MOVIE, ICON_SEQUENCE);
+ a+= sprintf(str+a, " Sequence %%x%d %%i%d|", IMA_SRC_SEQUENCE, ICON_IMAGE_COL);
+ a+= sprintf(str+a, " Generated %%x%d %%i%d", IMA_SRC_GENERATED, ICON_BLANK1);
+
+ return str;
+}
+
+/* copy from buttons_shading.c */
+static char *layer_menu(RenderResult *rr)
+{
+ RenderLayer *rl;
+ int len= 40 + 40*BLI_countlist(&rr->layers);
+ short a, nr;
+ char *str= MEM_callocN(len, "menu layers");
+
+ strcpy(str, "Layer %t");
+ a= strlen(str);
+ for(nr=0, rl= rr->layers.first; rl; rl= rl->next, nr++) {
+ a+= sprintf(str+a, "|%s %%x%d", rl->name, nr);
+ }
+
+ return str;
+}
+
+static void image_layer_cb(void *ima_v, void *iuser_v)
+{
+
+ ntreeCompositForceHidden(G.scene->nodetree);
+ BKE_image_multilayer_index(ima_v, iuser_v);
+ allqueue(REDRAWNODE, 0);
+}
+
+static int node_composit_buts_image(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
+{
+ ImageUser *iuser= node->storage;
+
+ if(block) {
+ uiBut *bt;
+ short dy= (short)butr->ymax-19;
+ char *strp;
+
+ uiBlockBeginAlign(block);
+ uiBlockSetCol(block, TH_BUT_SETTING2);
+
+ /* browse button */
+ IMAnames_to_pupstring(&strp, NULL, "LOAD NEW %x32767", &(G.main->image), NULL, NULL);
+ node->menunr= 0;
+ bt= uiDefButS(block, MENU, B_NOP, strp,
+ butr->xmin, dy, 19, 19,
+ &node->menunr, 0, 0, 0, 0, "Browses existing choices");
+ uiButSetFunc(bt, node_browse_image_cb, ntree, node);
+ if(strp) MEM_freeN(strp);
+
+ /* Add New button */
+ if(node->id==NULL) {
+ bt= uiDefBut(block, BUT, B_NODE_LOADIMAGE, "Load New",
+ butr->xmin+19, dy, (short)(butr->xmax-butr->xmin-19.0f), 19,
+ NULL, 0.0, 0.0, 0, 0, "Add new Image");
+ uiButSetFunc(bt, node_active_cb, ntree, node);
+ uiBlockSetCol(block, TH_AUTO);
+ }
+ else {
+ /* name button + type */
+ Image *ima= (Image *)node->id;
+ short xmin= (short)butr->xmin, xmax= (short)butr->xmax;
+ short width= xmax - xmin - 45;
+ short icon= ICON_IMAGE_DEHLT;
+
+ if(ima->source==IMA_SRC_MOVIE) icon= ICON_SEQUENCE;
+ else if(ima->source==IMA_SRC_SEQUENCE) icon= ICON_IMAGE_COL;
+ else if(ima->source==IMA_SRC_GENERATED) icon= ICON_BLANK1;
+
+ bt= uiDefBut(block, TEX, B_NOP, "IM:",
+ xmin+19, dy, width, 19,
+ node->id->name+2, 0.0, 19.0, 0, 0, "Image name");
+ uiButSetFunc(bt, node_ID_title_cb, node, NULL);
+
+ /* buffer type option */
+ strp= node_image_type_pup();
+ bt= uiDefIconTextButS(block, MENU, B_NOP, icon, strp,
+ xmax-26, dy, 26, 19,
+ &ima->source, 0.0, 19.0, 0, 0, "Image type");
+ uiButSetFunc(bt, node_image_type_cb, node, ima);
+ MEM_freeN(strp);
+
+ if( ELEM(ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE) ) {
+ width= (xmax-xmin)/2;
+
+ dy-= 19;
+ uiDefButI(block, NUM, B_NODE_EXEC+node->nr, "Frs:",
+ xmin, dy, width, 19,
+ &iuser->frames, 0.0, MAXFRAMEF, 0, 0, "Amount of images used in animation");
+ uiDefButI(block, NUM, B_NODE_EXEC+node->nr, "SFra:",
+ xmin+width, dy, width, 19,
+ &iuser->sfra, 1.0, MAXFRAMEF, 0, 0, "Start frame of animation");
+ dy-= 19;
+ uiDefButI(block, NUM, B_NODE_EXEC+node->nr, "Offs:",
+ xmin, dy, width, 19,
+ &iuser->offset, -MAXFRAMEF, MAXFRAMEF, 0, 0, "Offsets the number of the frame to use in the animation");
+ uiDefButS(block, TOG, B_NODE_EXEC+node->nr, "Cycl",
+ xmin+width, dy, width-20, 19,
+ &iuser->cycl, 0.0, 0.0, 0, 0, "Make animation go cyclic");
+ uiDefIconButBitS(block, TOG, IMA_ANIM_ALWAYS, B_NODE_EXEC+node->nr, ICON_AUTO,
+ xmax-20, dy, 20, 19,
+ &iuser->flag, 0.0, 0.0, 0, 0, "Always refresh Image on frame changes");
+ }
+ if( ima->type==IMA_TYPE_MULTILAYER && ima->rr) {
+ RenderLayer *rl= BLI_findlink(&ima->rr->layers, iuser->layer);
+ if(rl) {
+ width= (xmax-xmin);
+ dy-= 19;
+ strp= layer_menu(ima->rr);
+ bt= uiDefButS(block, MENU, B_NODE_EXEC+node->nr, strp,
+ xmin, dy, width, 19,
+ &iuser->layer, 0.0, 10000.0, 0, 0, "Layer");
+ uiButSetFunc(bt, image_layer_cb, ima, node->storage);
+ MEM_freeN(strp);
+ }
+ }
+ }
+
+ }
+ if(node->id) {
+ Image *ima= (Image *)node->id;
+ int retval= 19;
+
+ /* for each draw we test for anim refresh event */
+ if(iuser->flag & IMA_ANIM_REFRESHED) {
+ iuser->flag &= ~IMA_ANIM_REFRESHED;
+ addqueue(curarea->win, UI_BUT_EVENT, B_NODE_EXEC+node->nr);
+ }
+
+ if( ELEM(ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE) )
+ retval+= 38;
+ if( ima->type==IMA_TYPE_MULTILAYER)
+ retval+= 19;
+ return retval;
+ }
+ else
+ return 19;
+}
+
+/* if we use render layers from other scene, we make a nice title */
+static void set_render_layers_title(void *node_v, void *unused)
+{
+ bNode *node= node_v;
+ Scene *sce;
+ SceneRenderLayer *srl;
+ char str[64];
+
+ if(node->id) {
+ BLI_strncpy(str, node->id->name+2, 21);
+ strcat(str, "|");
+ sce= (Scene *)node->id;
+ }
+ else {
+ str[0]= 0;
+ sce= G.scene;
+ }
+ srl= BLI_findlink(&sce->r.layers, node->custom1);
+ if(srl==NULL) {
+ node->custom1= 0;
+ srl= sce->r.layers.first;
+ }
+
+ strcat(str, srl->name);
+ BLI_strncpy(node->name, str, 32);
+}
+
+static char *scene_layer_menu(Scene *sce)
+{
+ SceneRenderLayer *srl;
+ int len= 40 + 40*BLI_countlist(&sce->r.layers);
+ short a, nr;
+ char *str= MEM_callocN(len, "menu layers");
+
+ strcpy(str, "Active Layer %t");
+ a= strlen(str);
+ for(nr=0, srl= sce->r.layers.first; srl; srl= srl->next, nr++) {
+ a+= sprintf(str+a, "|%s %%x%d", srl->name, nr);
+ }
+
+ return str;
+}
+
+static void node_browse_scene_cb(void *ntree_v, void *node_v)
+{
+ bNodeTree *ntree= ntree_v;
+ bNode *node= node_v;
+ Scene *sce;
+
+ if(node->menunr<1) return;
+
+ if(node->id) {
+ node->id->us--;
+ node->id= NULL;
+ }
+ sce= BLI_findlink(&G.main->scene, node->menunr-1);
+ if(sce!=G.scene) {
+ node->id= &sce->id;
+ id_us_plus(node->id);
+ }
+
+ set_render_layers_title(node, NULL);
+ nodeSetActive(ntree, node);
+
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWNODE, 0);
+ NodeTagChanged(ntree, node);
+
+ node->menunr= 0;
+}
+
+
+static int node_composit_buts_renderlayers(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
+{
+ if(block) {
+ uiBut *bt;
+ char *strp;
+
+ /* browse button scene */
+ uiBlockBeginAlign(block);
+ IDnames_to_pupstring(&strp, NULL, "", &(G.main->scene), NULL, NULL);
+ node->menunr= 0;
+ bt= uiDefButS(block, MENU, B_NOP, strp,
+ butr->xmin, butr->ymin, 20, 19,
+ &node->menunr, 0, 0, 0, 0, "Browse Scene to use RenderLayer from");
+ uiButSetFunc(bt, node_browse_scene_cb, ntree, node);
+ if(strp) MEM_freeN(strp);
+
+ /* browse button layer */
+ strp= scene_layer_menu(node->id?(Scene *)node->id:G.scene);
+ if(node->id)
+ bt= uiDefIconTextButS(block, MENU, B_NODE_EXEC+node->nr, ICON_SCENE_DEHLT, strp,
+ butr->xmin+20, butr->ymin, (butr->xmax-butr->xmin)-40, 19,
+ &node->custom1, 0, 0, 0, 0, "Choose Render Layer");
+ else
+ bt= uiDefButS(block, MENU, B_NODE_EXEC+node->nr, strp,
+ butr->xmin+20, butr->ymin, (butr->xmax-butr->xmin)-40, 19,
+ &node->custom1, 0, 0, 0, 0, "Choose Render Layer");
+ uiButSetFunc(bt, set_render_layers_title, node, NULL);
+ MEM_freeN(strp);
+
+ /* re-render */
+ /* uses custom2, not the best implementation of the world... but we need it to work now :) */
+ bt= uiDefIconButS(block, TOG, B_NODE_EXEC+node->nr, ICON_SCENE,
+ butr->xmax-20, butr->ymin, 20, 19,
+ &node->custom2, 0, 0, 0, 0, "Re-render this Layer");
+
+ }
+ return 19;
+}
+
+static int node_composit_buts_blur(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
+{
+ if(block) {
+ NodeBlurData *nbd= node->storage;
+ uiBut *bt;
+ short dy= butr->ymin+38;
+ short dx= (butr->xmax-butr->xmin)/2;
+ char str[256];
+
+ uiBlockBeginAlign(block);
+ sprintf(str, "Filter Type%%t|Flat %%x%d|Tent %%x%d|Quad %%x%d|Cubic %%x%d|Gauss %%x%d|Fast Gauss%%x%d|CatRom %%x%d|Mitch %%x%d", R_FILTER_BOX, R_FILTER_TENT, R_FILTER_QUAD, R_FILTER_CUBIC, R_FILTER_GAUSS, R_FILTER_FAST_GAUSS, R_FILTER_CATROM, R_FILTER_MITCH);
+ uiDefButS(block, MENU, B_NODE_EXEC+node->nr,str,
+ butr->xmin, dy, dx*2, 19,
+ &nbd->filtertype, 0, 0, 0, 0, "Set sampling filter for blur");
+ dy-=19;
+ if (nbd->filtertype != R_FILTER_FAST_GAUSS) {
+ uiDefButC(block, TOG, B_NODE_EXEC+node->nr, "Bokeh",
+ butr->xmin, dy, dx, 19,
+ &nbd->bokeh, 0, 0, 0, 0, "Uses circular filter, warning it's slow!");
+ uiDefButC(block, TOG, B_NODE_EXEC+node->nr, "Gamma",
+ butr->xmin+dx, dy, dx, 19,
+ &nbd->gamma, 0, 0, 0, 0, "Applies filter on gamma corrected values");
+ } else {
+ uiBlockEndAlign(block);
+ uiBlockBeginAlign(block);
+ }
+ dy-=19;
+ bt=uiDefButS(block, NUM, B_NODE_EXEC+node->nr, "X:",
+ butr->xmin, dy, dx, 19,
+ &nbd->sizex, 0, 256, 0, 0, "");
+ bt=uiDefButS(block, NUM, B_NODE_EXEC+node->nr, "Y:",
+ butr->xmin+dx, dy, dx, 19,
+ &nbd->sizey, 0, 256, 0, 0, "");
+ uiBlockEndAlign(block);
+ }
+ return 57;
+}
+
+/* qdn: defocus node */
+static int node_composit_buts_defocus(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
+{
+ if(block) {
+ NodeDefocus *nqd = node->storage;
+ short dy = butr->ymin + 209;
+ short dx = butr->xmax - butr->xmin;
+ char* mstr1 = "Bokeh Type%t|Octagon %x8|Heptagon %x7|Hexagon %x6|Pentagon %x5|Square %x4|Triangle %x3|Disk %x0";
+
+ uiDefBut(block, LABEL, B_NOP, "Bokeh Type", butr->xmin, dy, dx, 19, NULL, 0, 0, 0, 0, "");
+ uiDefButC(block, MENU, B_NODE_EXEC+node->nr, mstr1,
+ butr->xmin, dy-19, dx, 19,
+ &nqd->bktype, 0, 0, 0, 0, "Bokeh type");
+ if (nqd->bktype) { /* for some reason rotating a disk doesn't seem to work... ;) */
+ uiDefButC(block, NUM, B_NODE_EXEC+node->nr, "Rotate:",
+ butr->xmin, dy-38, dx, 19,
+ &nqd->rotation, 0, 90, 0, 0, "Bokeh shape rotation offset in degrees");
+ }
+ uiDefButC(block, TOG, B_NODE_EXEC+node->nr, "Gamma Correct",
+ butr->xmin, dy-57, dx, 19,
+ &nqd->gamco, 0, 0, 0, 0, "Enable gamma correction before and after main process");
+ if (nqd->no_zbuf==0) {
+ // only needed for zbuffer input
+ uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "fStop:",
+ butr->xmin, dy-76, dx, 19,
+ &nqd->fstop, 0.5, 128, 10, 0, "Amount of focal blur, 128=infinity=perfect focus, half the value doubles the blur radius");
+ }
+ uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "Maxblur:",
+ butr->xmin, dy-95, dx, 19,
+ &nqd->maxblur, 0, 10000, 1000, 0, "blur limit, maximum CoC radius, 0=no limit");
+ uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "BThreshold:",
+ butr->xmin, dy-114, dx, 19,
+ &nqd->bthresh, 0, 100, 100, 0, "CoC radius threshold, prevents background bleed on in-focus midground, 0=off");
+ uiDefButC(block, TOG, B_NODE_EXEC+node->nr, "Preview",
+ butr->xmin, dy-142, dx, 19,
+ &nqd->preview, 0, 0, 0, 0, "Enable sampling mode, useful for preview when using low samplecounts");
+ if (nqd->preview) {
+ /* only visible when sampling mode enabled */
+ uiDefButS(block, NUM, B_NODE_EXEC+node->nr, "Samples:",
+ butr->xmin, dy-161, dx, 19,
+ &nqd->samples, 16, 256, 0, 0, "Number of samples (16=grainy, higher=less noise)");
+ }
+ uiDefButS(block, TOG, B_NODE_EXEC+node->nr, "No zbuffer",
+ butr->xmin, dy-190, dx, 19,
+ &nqd->no_zbuf, 0, 0, 0, 0, "Enable when using an image as input instead of actual zbuffer (auto enabled if node not image based, eg. time node)");
+ if (nqd->no_zbuf) {
+ uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "Zscale:",
+ butr->xmin, dy-209, dx, 19,
+ &nqd->scale, 0, 1000, 100, 0, "Scales the Z input when not using a zbuffer, controls maximum blur designated by the color white or input value 1");
+ }
+ }
+ return 228;
+}
+
+
+/* qdn: glare node */
+static int node_composit_buts_glare(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
+{
+ if(block) {
+ NodeGlare *ndg = node->storage;
+ short dy = butr->ymin + 152, dx = butr->xmax - butr->xmin;
+ char* mn1 = "Type%t|Ghosts%x3|Streaks%x2|Fog Glow%x1|Simple Star%x0";
+ char* mn2 = "Quality/Speed%t|High/Slow%x0|Medium/Medium%x1|Low/Fast%x2";
+ uiDefButC(block, MENU, B_NODE_EXEC+node->nr, mn1,
+ butr->xmin, dy, dx, 19,
+ &ndg->type, 0, 0, 0, 0, "Glow/Flare/Bloom type");
+ uiDefButC(block, MENU, B_NODE_EXEC+node->nr, mn2,
+ butr->xmin, dy-19, dx, 19,
+ &ndg->quality, 0, 0, 0, 0,
+ "Quality speed trade off, if not set to high quality, effect will be applied to low-res copy of source image");
+ if (ndg->type != 1) {
+ uiDefButC(block, NUM, B_NODE_EXEC+node->nr, "Iterations:",
+ butr->xmin, dy-38, dx, 19,
+ &ndg->iter, 2, 5, 1, 0,
+ "higher values will generate longer/more streaks/ghosts");
+ if (ndg->type != 0)
+ uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "ColMod:",
+ butr->xmin, dy-57, dx, 19,
+ &ndg->colmod, 0, 1, 10, 0,
+ "Amount of Color Modulation, modulates colors of streaks and ghosts for a spectral dispersion effect");
+ }
+ uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "Mix:",
+ butr->xmin, dy-76, dx, 19,
+ &ndg->mix, -1, 1, 10, 0,
+ "Mix balance, -1 is original image only, 0 is exact 50/50 mix, 1 is processed image only");
+ uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "Threshold:",
+ butr->xmin, dy-95, dx, 19,
+ &ndg->threshold, 0, 1000, 10, 0,
+ "Brightness threshold, the glarefilter will be applied only to pixels brighter than this value");
+ if ((ndg->type == 2) || (ndg->type == 0))
+ {
+ if (ndg->type == 2) {
+ uiDefButC(block, NUM, B_NODE_EXEC+node->nr, "streaks:",
+ butr->xmin, dy-114, dx, 19,
+ &ndg->angle, 2, 16, 1000, 0,
+ "Total number of streaks");
+ uiDefButC(block, NUM, B_NODE_EXEC+node->nr, "AngOfs:",
+ butr->xmin, dy-133, dx, 19,
+ &ndg->angle_ofs, 0, 180, 1000, 0,
+ "Streak angle rotation offset in degrees");
+ }
+ uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "Fade:",
+ butr->xmin, dy-152, dx, 19,
+ &ndg->fade, 0.75, 1, 5, 0,
+ "Streak fade out factor");
+ }
+ if (ndg->type == 0)
+ uiDefButC(block, TOG, B_NODE_EXEC+node->nr, "Rot45",
+ butr->xmin, dy-114, dx, 19,
+ &ndg->angle, 0, 0, 0, 0,
+ "simple star filter, add 45 degree rotation offset");
+ if ((ndg->type == 1) || (ndg->type > 3)) // PBGH and fog glow
+ uiDefButC(block, NUM, B_NODE_EXEC+node->nr, "Size:",
+ butr->xmin, dy-114, dx, 19,
+ &ndg->size, 6, 9, 1000, 0,
+ "glow/glare size (not actual size, relative to initial size of bright area of pixels)");
+ }
+ return 171;
+}
+
+/* qdn: tonemap node */
+static int node_composit_buts_tonemap(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
+{
+ if(block) {
+ NodeTonemap *ntm = node->storage;
+ short dy = butr->ymin + 76, dx = butr->xmax - butr->xmin;
+ char* mn = "Type%t|R/D Photoreceptor%x1|Rh Simple%x0";
+
+ uiBlockBeginAlign(block);
+ uiDefButI(block, MENU, B_NODE_EXEC+node->nr, mn,
+ butr->xmin, dy, dx, 19,
+ &ntm->type, 0, 0, 0, 0,
+ "Tone mapping type");
+ if (ntm->type == 0) {
+ uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "Key:",
+ butr->xmin, dy-19, dx, 19,
+ &ntm->key, 0, 1, 5, 0,
+ "The value the average luminance is mapped to");
+ uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "Offset:",
+ butr->xmin, dy-38, dx, 19,
+ &ntm->offset, 0.001, 10, 5, 0,
+ "Tonemap offset, normally always 1, but can be used as an extra control to alter the brightness curve");
+ uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "Gamma:",
+ butr->xmin, dy-57, dx, 19,
+ &ntm->gamma, 0.001, 3, 5, 0,
+ "Gamma factor, if not used, set to 1");
+ }
+ else {
+ uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "Intensity:",
+ butr->xmin, dy-19, dx, 19,
+ &ntm->f, -8, 8, 10, 0, "if less than zero, darkens image, otherwise makes it brighter");
+ uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "Contrast:",
+ butr->xmin, dy-38, dx, 19,
+ &ntm->m, 0, 1, 5, 0, "Set to 0 to use estimate from input image");
+ uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "Adaptation:",
+ butr->xmin, dy-57, dx, 19,
+ &ntm->a, 0, 1, 5, 0, "if 0, global, if 1, based on pixel intensity");
+ uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "ColCorrect:",
+ butr->xmin, dy-76, dx, 19,
+ &ntm->c, 0, 1, 5, 0, "color correction, if 0, same for all channels, if 1, each independent");
+ }
+ uiBlockEndAlign(block);
+ }
+ return 95;
+}
+
+/* qdn: lens distortion node */
+static int node_composit_buts_lensdist(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
+{
+ if(block) {
+ NodeLensDist *nld = node->storage;
+ short dy = butr->ymin + 19, dx = butr->xmax - butr->xmin;
+ uiBlockBeginAlign(block);
+ uiDefButS(block, TOG, B_NODE_EXEC+node->nr, "Projector",
+ butr->xmin, dy, dx, 19,
+ &nld->proj, 0, 0, 0, 0,
+ "Enable/disable projector mode, effect is applied in horizontal direction only");
+ if (!nld->proj) {
+ uiDefButS(block, TOG, B_NODE_EXEC+node->nr, "Jitter",
+ butr->xmin, dy-19, dx/2, 19,
+ &nld->jit, 0, 0, 0, 0,
+ "Enable/disable jittering, faster, but also noisier");
+ uiDefButS(block, TOG, B_NODE_EXEC+node->nr, "Fit",
+ butr->xmin+dx/2, dy-19, dx/2, 19,
+ &nld->fit, 0, 0, 0, 0,
+ "For positive distortion factor only, scale image such that black areas are not visible");
+ }
+ uiBlockEndAlign(block);
+ }
+ return 38;
+}
+
+
+static int node_composit_buts_vecblur(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
+{
+ if(block) {
+ NodeBlurData *nbd= node->storage;
+ short dy= butr->ymin;
+ short dx= (butr->xmax-butr->xmin);
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, NUM, B_NODE_EXEC+node->nr, "Samples:",
+ butr->xmin, dy+57, dx, 19,
+ &nbd->samples, 1, 256, 0, 0, "Amount of samples");
+ uiDefButS(block, NUM, B_NODE_EXEC+node->nr, "MinSpeed:",
+ butr->xmin, dy+38, dx, 19,
+ &nbd->minspeed, 0, 1024, 0, 0, "Minimum speed for a pixel to be blurred, used to separate background from foreground");
+ uiDefButS(block, NUM, B_NODE_EXEC+node->nr, "MaxSpeed:",
+ butr->xmin, dy+19, dx, 19,
+ &nbd->maxspeed, 0, 1024, 0, 0, "If not zero, maximum speed in pixels");
+ uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "BlurFac:",
+ butr->xmin, dy, dx, 19,
+ &nbd->fac, 0.0f, 2.0f, 10, 2, "Scaling factor for motion vectors, actually 'shutter speed' in frames");
+ }
+ return 76;
+}
+
+static int node_composit_buts_filter(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
+{
+ if(block) {
+ uiBut *bt;
+
+ /* blend type */
+ bt=uiDefButS(block, MENU, B_NODE_EXEC+node->nr, "Soften %x0|Sharpen %x1|Laplace %x2|Sobel %x3|Prewitt %x4|Kirsch %x5|Shadow %x6",
+ butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20,
+ &node->custom1, 0, 0, 0, 0, "");
+ uiButSetFunc(bt, node_but_title_cb, node, bt);
+ }
+ return 20;
+}
+
+static int node_composit_buts_flip(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
+{
+ if(block) {
+ uiBut *bt;
+
+ /* flip x\y */
+ bt=uiDefButS(block, MENU, B_NODE_EXEC+node->nr, "Flip X %x0|Flip Y %x1|Flip X & Y %x2",
+ butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20,
+ &node->custom1, 0, 0, 0, 0, "");
+ uiButSetFunc(bt, node_but_title_cb, node, bt);
+ }
+ return 20;
+}
+
+static int node_composit_buts_crop(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
+{
+ if(block) {
+ NodeTwoXYs *ntxy= node->storage;
+ uiBut *bt;
+ char elementheight = 19;
+ short dx= (butr->xmax-butr->xmin)/2;
+ short dy= butr->ymax - elementheight;
+ short xymin= 0, xymax= 10000;
+
+ uiBlockBeginAlign(block);
+
+ /* crop image size toggle */
+ uiDefButS(block, TOG, B_NODE_EXEC+node->nr, "Crop Image Size",
+ butr->xmin, dy, dx*2, elementheight,
+ &node->custom1, 0, 0, 0, 0, "Crop the size of the input image.");
+
+ dy-=elementheight;
+
+ /* x1 */
+ bt=uiDefButS(block, NUM, B_NODE_EXEC+node->nr, "X1:",
+ butr->xmin, dy, dx, elementheight,
+ &ntxy->x1, xymin, xymax, 0, 0, "");
+ /* y1 */
+ bt=uiDefButS(block, NUM, B_NODE_EXEC+node->nr, "Y1:",
+ butr->xmin+dx, dy, dx, elementheight,
+ &ntxy->y1, xymin, xymax, 0, 0, "");
+
+ dy-=elementheight;
+
+ /* x2 */
+ bt=uiDefButS(block, NUM, B_NODE_EXEC+node->nr, "X2:",
+ butr->xmin, dy, dx, elementheight,
+ &ntxy->x2, xymin, xymax, 0, 0, "");
+ /* y2 */
+ bt=uiDefButS(block, NUM, B_NODE_EXEC+node->nr, "Y2:",
+ butr->xmin+dx, dy, dx, elementheight,
+ &ntxy->y2, xymin, xymax, 0, 0, "");
+
+ uiBlockEndAlign(block);
+ }
+ return 60;
+}
+
+static int node_composit_buts_splitviewer(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
+{
+ if(block) {
+ uiBlockBeginAlign(block);
+
+ uiDefButS(block, ROW, B_NODE_EXEC+node->nr, "X",
+ butr->xmin, butr->ymin+19, (butr->xmax-butr->xmin)/2, 20,
+ &node->custom2, 0.0, 0.0, 0, 0, "");
+ uiDefButS(block, ROW, B_NODE_EXEC+node->nr, "Y",
+ butr->xmin+(butr->xmax-butr->xmin)/2, butr->ymin+19, (butr->xmax-butr->xmin)/2, 20,
+ &node->custom2, 0.0, 1.0, 0, 0, "");
+
+ uiDefButS(block, NUMSLI, B_NODE_EXEC+node->nr, "Split %: ",
+ butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20, &node->custom1, 0, 100, 10, 0, "");
+ }
+ return 40;
+}
+
+static int node_composit_buts_map_value(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
+{
+ if(block) {
+ TexMapping *texmap= node->storage;
+ short xstart= (short)butr->xmin;
+ short dy= (short)(butr->ymax-19.0f);
+ short dx= (short)(butr->xmax-butr->xmin)/2;
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "Offs:", xstart, dy, 2*dx, 19, texmap->loc, -1000.0f, 1000.0f, 10, 2, "");
+ dy-= 19;
+ uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "Size:", xstart, dy, 2*dx, 19, texmap->size, -1000.0f, 1000.0f, 10, 3, "");
+ dy-= 23;
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOG, TEXMAP_CLIP_MIN, B_NODE_EXEC+node->nr, "Min", xstart, dy, dx, 19, &texmap->flag, 0.0f, 0.0f, 0, 0, "");
+ uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "", xstart+dx, dy, dx, 19, texmap->min, -1000.0f, 1000.0f, 10, 2, "");
+ dy-= 19;
+ uiDefButBitI(block, TOG, TEXMAP_CLIP_MAX, B_NODE_EXEC+node->nr, "Max", xstart, dy, dx, 19, &texmap->flag, 0.0f, 0.0f, 0, 0, "");
+ uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "", xstart+dx, dy, dx, 19, texmap->max, -1000.0f, 1000.0f, 10, 2, "");
+ }
+ return 80;
+}
+
+static int node_composit_buts_alphaover(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
+{
+ if(block) {
+
+ /* alpha type */
+ uiDefButS(block, TOG, B_NODE_EXEC+node->nr, "ConvertPremul",
+ butr->xmin, butr->ymin, butr->xmax-butr->xmin, 19,
+ &node->custom1, 0, 0, 0, 0, "");
+ }
+ return 19;
+}
+
+static int node_composit_buts_hue_sat(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
+{
+ if(block) {
+ NodeHueSat *nhs= node->storage;
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUMSLI, B_NODE_EXEC+node->nr, "Hue: ",
+ butr->xmin, butr->ymin+40.0f, butr->xmax-butr->xmin, 20,
+ &nhs->hue, 0.0f, 1.0f, 100, 0, "");
+ uiDefButF(block, NUMSLI, B_NODE_EXEC+node->nr, "Sat: ",
+ butr->xmin, butr->ymin+20.0f, butr->xmax-butr->xmin, 20,
+ &nhs->sat, 0.0f, 2.0f, 100, 0, "");
+ uiDefButF(block, NUMSLI, B_NODE_EXEC+node->nr, "Val: ",
+ butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20,
+ &nhs->val, 0.0f, 2.0f, 100, 0, "");
+ }
+ return 60;
+}
+
+static int node_composit_buts_dilateerode(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
+{
+ if(block) {
+ uiDefButS(block, NUM, B_NODE_EXEC+node->nr, "Distance:",
+ butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20,
+ &node->custom2, -100, 100, 0, 0, "Distance to grow/shrink (number of iterations)");
+ }
+ return 20;
+}
+
+static int node_composit_buts_diff_matte(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
+{
+ if(block) {
+ short sx= (butr->xmax-butr->xmin)/4;
+ short dx= (butr->xmax-butr->xmin)/3;
+ NodeChroma *c= node->storage;
+
+ uiBlockBeginAlign(block);
+ /*color space selectors*/
+ uiDefButS(block, ROW,B_NODE_EXEC+node->nr,"RGB",
+ butr->xmin,butr->ymin+60,sx,20,
+ &node->custom1,1,1, 0, 0, "RGB Color Space");
+ uiDefButS(block, ROW,B_NODE_EXEC+node->nr,"HSV",
+ butr->xmin+sx,butr->ymin+60,sx,20,
+ &node->custom1,1,2, 0, 0, "HSV Color Space");
+ uiDefButS(block, ROW,B_NODE_EXEC+node->nr,"YUV",
+ butr->xmin+2*sx,butr->ymin+60,sx,20,
+ &node->custom1,1,3, 0, 0, "YUV Color Space");
+ uiDefButS(block, ROW,B_NODE_EXEC+node->nr,"YCC",
+ butr->xmin+3*sx,butr->ymin+60,sx,20,
+ &node->custom1,1,4, 0, 0, "YCbCr Color Space");
+ /*channel tolorences*/
+ uiDefButF(block, NUM, B_NODE_EXEC+node->nr, " ",
+ butr->xmin, butr->ymin+40, dx, 20,
+ &c->t1, 0.0f, 1.0f, 100, 0, "Channel 1 Tolerance");
+ uiDefButF(block, NUM, B_NODE_EXEC+node->nr, " ",
+ butr->xmin+dx, butr->ymin+40, dx, 20,
+ &c->t2, 0.0f, 1.0f, 100, 0, "Channel 2 Tolorence");
+ uiDefButF(block, NUM, B_NODE_EXEC+node->nr, " ",
+ butr->xmin+2*dx, butr->ymin+40, dx, 20,
+ &c->t3, 0.0f, 1.0f, 100, 0, "Channel 3 Tolorence");
+ /*falloff parameters*/
+ /*
+ uiDefButF(block, NUMSLI, B_NODE_EXEC+node->nr, "Falloff Size ",
+ butr->xmin, butr->ymin+20, butr->xmax-butr->xmin, 20,
+ &c->fsize, 0.0f, 1.0f, 100, 0, "");
+ */
+ uiDefButF(block, NUMSLI, B_NODE_EXEC+node->nr, "Falloff: ",
+ butr->xmin, butr->ymin+20, butr->xmax-butr->xmin, 20,
+ &c->fstrength, 0.0f, 1.0f, 100, 0, "");
+ }
+ return 80;
+}
+
+static int node_composit_buts_color_spill(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
+{
+ if(block) {
+ short dx= (butr->xmax-butr->xmin)/3;
+
+ NodeChroma *c=node->storage;
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_NODE_EXEC+node->nr, "Enhance: ",
+ butr->xmin, butr->ymin+20.0, butr->xmax-butr->xmin, 20,
+ &c->t1, 0.0f, 0.5f, 100, 2, "Adjusts how much selected channel is affected by color spill algorithm");
+ uiDefButS(block, ROW, B_NODE_EXEC+node->nr, "R",
+ butr->xmin,butr->ymin,dx,20,
+ &node->custom1,1,1, 0, 0, "Red Spill Suppression");
+ uiDefButS(block, ROW, B_NODE_EXEC+node->nr, "G",
+ butr->xmin+dx,butr->ymin,dx,20,
+ &node->custom1,1,2, 0, 0, "Green Spill Suppression");
+ uiDefButS(block, ROW, B_NODE_EXEC+node->nr, "B",
+ butr->xmin+2*dx,butr->ymin,dx,20,
+ &node->custom1, 1, 3, 0, 0, "Blue Spill Suppression");
+ uiBlockEndAlign(block);
+ }
+ return 60;
+ }
+
+static int node_composit_buts_chroma_matte(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
+{
+ if(block) {
+ short dx=(butr->xmax-butr->xmin)/2;
+ NodeChroma *c= node->storage;
+ uiBlockBeginAlign(block);
+
+ uiDefButF(block, NUMSLI, B_NODE_EXEC+node->nr, "Acceptance ",
+ butr->xmin, butr->ymin+60, butr->xmax-butr->xmin, 20,
+ &c->t1, 1.0f, 80.0f, 100, 0, "Tolerance for colors to be considered a keying color");
+ uiDefButF(block, NUMSLI, B_NODE_EXEC+node->nr, "Cutoff ",
+ butr->xmin, butr->ymin+40, butr->xmax-butr->xmin, 20,
+ &c->t2, 0.0f, 30.0f, 100, 0, "Colors below this will be considered as exact matches for keying color");
+
+ uiDefButF(block, NUMSLI, B_NODE_EXEC+node->nr, "Lift ",
+ butr->xmin, butr->ymin+20, dx, 20,
+ &c->fsize, 0.0f, 1.0f, 100, 0, "Alpha Lift");
+ uiDefButF(block, NUMSLI, B_NODE_EXEC+node->nr, "Gain ",
+ butr->xmin+dx, butr->ymin+20, dx, 20,
+ &c->fstrength, 0.0f, 1.0f, 100, 0, "Alpha Gain");
+
+ uiDefButF(block, NUMSLI, B_NODE_EXEC+node->nr, "Shadow Adjust ",
+ butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20,
+ &c->t3, 0.0f, 1.0f, 100, 0, "Adjusts the brightness of any shadows captured");
+
+ if(c->t2 > c->t1)
+ c->t2=c->t1;
+ }
+ return 80;
+}
+
+static int node_composit_buts_channel_matte(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
+{
+ if(block) {
+ short sx= (butr->xmax-butr->xmin)/4;
+ short cx= (butr->xmax-butr->xmin)/3;
+ NodeChroma *c=node->storage;
+ char *c1, *c2, *c3;
+
+ /*color space selectors*/
+ uiBlockBeginAlign(block);
+ uiDefButS(block, ROW,B_NODE_EXEC+node->nr,"RGB",
+ butr->xmin,butr->ymin+60,sx,20,&node->custom1,1,1, 0, 0, "RGB Color Space");
+ uiDefButS(block, ROW,B_NODE_EXEC+node->nr,"HSV",
+ butr->xmin+sx,butr->ymin+60,sx,20,&node->custom1,1,2, 0, 0, "HSV Color Space");
+ uiDefButS(block, ROW,B_NODE_EXEC+node->nr,"YUV",
+ butr->xmin+2*sx,butr->ymin+60,sx,20,&node->custom1,1,3, 0, 0, "YUV Color Space");
+ uiDefButS(block, ROW,B_NODE_EXEC+node->nr,"YCC",
+ butr->xmin+3*sx,butr->ymin+60,sx,20,&node->custom1,1,4, 0, 0, "YCbCr Color Space");
+
+ if (node->custom1==1) {
+ c1="R"; c2="G"; c3="B";
+ }
+ else if(node->custom1==2){
+ c1="H"; c2="S"; c3="V";
+ }
+ else if(node->custom1==3){
+ c1="Y"; c2="U"; c3="V";
+ }
+ else { // if(node->custom1==4){
+ c1="Y"; c2="Cb"; c3="Cr";
+ }
+
+ /*channel selector */
+ uiDefButS(block, ROW, B_NODE_EXEC+node->nr, c1,
+ butr->xmin,butr->ymin+40,cx,20,&node->custom2,1, 1, 0, 0, "Channel 1");
+ uiDefButS(block, ROW, B_NODE_EXEC+node->nr, c2,
+ butr->xmin+cx,butr->ymin+40,cx,20,&node->custom2,1, 2, 0, 0, "Channel 2");
+ uiDefButS(block, ROW, B_NODE_EXEC+node->nr, c3,
+ butr->xmin+cx+cx,butr->ymin+40,cx,20,&node->custom2, 1, 3, 0, 0, "Channel 3");
+
+ /*tolerance sliders */
+ uiDefButF(block, NUMSLI, B_NODE_EXEC+node->nr, "High ",
+ butr->xmin, butr->ymin+20.0, butr->xmax-butr->xmin, 20,
+ &c->t1, 0.0f, 1.0f, 100, 0, "Values higher than this setting are 100% opaque");
+ uiDefButF(block, NUMSLI, B_NODE_EXEC+node->nr, "Low ",
+ butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20,
+ &c->t2, 0.0f, 1.0f, 100, 0, "Values lower than this setting are 100% keyed");
+ uiBlockEndAlign(block);
+
+ /*keep t2 (low) less than t1 (high) */
+ if(c->t2 > c->t1) {
+ c->t2=c->t1;
+ }
+ }
+ return 80;
+}
+
+static int node_composit_buts_luma_matte(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
+{
+ if(block) {
+ NodeChroma *c=node->storage;
+
+ /*tolerance sliders */
+ uiDefButF(block, NUMSLI, B_NODE_EXEC+node->nr, "High ",
+ butr->xmin, butr->ymin+20.0, butr->xmax-butr->xmin, 20,
+ &c->t1, 0.0f, 1.0f, 100, 0, "Values higher than this setting are 100% opaque");
+ uiDefButF(block, NUMSLI, B_NODE_EXEC+node->nr, "Low ",
+ butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20,
+ &c->t2, 0.0f, 1.0f, 100, 0, "Values lower than this setting are 100% keyed");
+ uiBlockEndAlign(block);
+
+ /*keep t2 (low) less than t1 (high) */
+ if(c->t2 > c->t1) {
+ c->t2=c->t1;
+ }
+ }
+ return 40;
+}
+
+static int node_composit_buts_map_uv(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
+{
+ if(block) {
+ uiDefButS(block, NUM, B_NODE_EXEC+node->nr, "Alpha:",
+ butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20,
+ &node->custom1, 0, 100, 0, 0, "Conversion percentage of UV differences to Alpha");
+ }
+ return 20;
+}
+
+static int node_composit_buts_id_mask(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
+{
+ if(block) {
+ uiDefButS(block, NUM, B_NODE_EXEC+node->nr, "ID:",
+ butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20,
+ &node->custom1, 0, 10000, 0, 0, "Pass Index number to convert to Alpha");
+ }
+ return 20;
+}
+
+
+/* allocate sufficient! */
+static void node_imagetype_string(char *str)
+{
+ str += sprintf(str, "Save Image as: %%t|");
+ str += sprintf(str, "Targa %%x%d|", R_TARGA);
+ str += sprintf(str, "Targa Raw %%x%d|", R_RAWTGA);
+ str += sprintf(str, "PNG %%x%d|", R_PNG);
+ str += sprintf(str, "BMP %%x%d|", R_BMP);
+ str += sprintf(str, "Jpeg %%x%d|", R_JPEG90);
+ str += sprintf(str, "Iris %%x%d|", R_IRIS);
+ str += sprintf(str, "Radiance HDR %%x%d|", R_RADHDR);
+ str += sprintf(str, "Cineon %%x%d|", R_CINEON);
+ str += sprintf(str, "DPX %%x%d|", R_DPX);
+ str += sprintf(str, "OpenEXR %%x%d", R_OPENEXR);
+}
+
+static int node_composit_buts_file_output(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
+{
+ if(block) {
+ NodeImageFile *nif= node->storage;
+ short x= (short)butr->xmin;
+ short y= (short)butr->ymin;
+ short w= (short)butr->xmax-butr->xmin;
+ char str[320];
+
+ node_imagetype_string(str);
+
+ uiBlockBeginAlign(block);
+
+ uiDefBut(block, TEX, B_NOP, "",
+ x, y+60, w, 20,
+ nif->name, 0.0f, 240.0f, 0, 0, "");
+
+ uiDefButS(block, MENU, B_NOP, str,
+ x, y+40, w, 20,
+ &nif->imtype, 0.0f, 1.0f, 0, 0, "");
+
+ if(nif->imtype==R_OPENEXR) {
+ uiDefButBitS(block, TOG, R_OPENEXR_HALF, B_REDR, "Half",
+ x, y+20, w/2, 20,
+ &nif->subimtype, 0, 0, 0, 0, "");
+
+ uiDefButS(block, MENU,B_NOP, "Codec %t|None %x0|Pxr24 (lossy) %x1|ZIP (lossless) %x2|PIZ (lossless) %x3|RLE (lossless) %x4",
+ x+w/2, y+20, w/2, 20,
+ &nif->codec, 0, 0, 0, 0, "");
+ }
+ else {
+ uiDefButS(block, NUM, B_NOP, "Quality: ",
+ x, y+20, w, 20,
+ &nif->quality, 10.0f, 100.0f, 10, 0, "");
+ }
+
+ /* start frame, end frame */
+ uiDefButI(block, NUM, B_NODE_EXEC+node->nr, "SFra: ",
+ x, y, w/2, 20,
+ &nif->sfra, 1, MAXFRAMEF, 10, 0, "");
+ uiDefButI(block, NUM, B_NODE_EXEC+node->nr, "EFra: ",
+ x+w/2, y, w/2, 20,
+ &nif->efra, 1, MAXFRAMEF, 10, 0, "");
+
+ }
+ return 80;
+}
+
+static void node_scale_cb(void *node_v, void *unused_v)
+{
+ bNode *node= node_v;
+ bNodeSocket *nsock;
+
+ /* check the 2 inputs, and set them to reasonable values */
+ for(nsock= node->inputs.first; nsock; nsock= nsock->next) {
+ if(node->custom1==CMP_SCALE_RELATIVE)
+ nsock->ns.vec[0]= 1.0;
+ else {
+ if(nsock->next==NULL)
+ nsock->ns.vec[0]= (float)G.scene->r.ysch;
+ else
+ nsock->ns.vec[0]= (float)G.scene->r.xsch;
+ }
+ }
+}
+
+static int node_composit_buts_scale(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
+{
+ if(block) {
+ uiBut *bt= uiDefButS(block, TOG, B_NODE_EXEC+node->nr, "Absolute",
+ butr->xmin, butr->ymin, butr->xmax-butr->xmin, 20,
+ &node->custom1, 0, 0, 0, 0, "");
+ uiButSetFunc(bt, node_scale_cb, node, NULL);
+ }
+ return 20;
+}
+
+static int node_composit_buts_invert(uiBlock *block, bNodeTree *ntree, bNode *node, rctf *butr)
+{
+ if(block) {
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, CMP_CHAN_RGB, B_NODE_EXEC+node->nr, "RGB",
+ butr->xmin, butr->ymin, (butr->xmax-butr->xmin)/2, 20,
+ &node->custom1, 0, 0, 0, 0, "");
+ uiDefButBitS(block, TOG, CMP_CHAN_A, B_NODE_EXEC+node->nr, "A",
+ butr->xmin+(butr->xmax-butr->xmin)/2, butr->ymin, (butr->xmax-butr->xmin)/2, 20,
+ &node->custom1, 0, 0, 0, 0, "");
+ uiBlockEndAlign(block);
+ }
+ return 20;
+}
+
+/* only once called */
+static void node_composit_set_butfunc(bNodeType *ntype)
+{
+ switch(ntype->type) {
+ /* case NODE_GROUP: note, typeinfo for group is generated... see "XXX ugly hack" */
+
+ case CMP_NODE_IMAGE:
+ ntype->butfunc= node_composit_buts_image;
+ break;
+ case CMP_NODE_R_LAYERS:
+ ntype->butfunc= node_composit_buts_renderlayers;
+ break;
+ case CMP_NODE_NORMAL:
+ ntype->butfunc= node_buts_normal;
+ break;
+ case CMP_NODE_CURVE_VEC:
+ ntype->butfunc= node_buts_curvevec;
+ break;
+ case CMP_NODE_CURVE_RGB:
+ ntype->butfunc= node_buts_curvecol;
+ break;
+ case CMP_NODE_VALUE:
+ ntype->butfunc= node_buts_value;
+ break;
+ case CMP_NODE_RGB:
+ ntype->butfunc= node_buts_rgb;
+ break;
+ case CMP_NODE_FLIP:
+ ntype->butfunc= node_composit_buts_flip;
+ break;
+ case CMP_NODE_SPLITVIEWER:
+ ntype->butfunc= node_composit_buts_splitviewer;
+ break;
+ case CMP_NODE_MIX_RGB:
+ ntype->butfunc= node_buts_mix_rgb;
+ break;
+ case CMP_NODE_VALTORGB:
+ ntype->butfunc= node_buts_valtorgb;
+ break;
+ case CMP_NODE_CROP:
+ ntype->butfunc= node_composit_buts_crop;
+ break;
+ case CMP_NODE_BLUR:
+ ntype->butfunc= node_composit_buts_blur;
+ break;
+ /* qdn: defocus node */
+ case CMP_NODE_DEFOCUS:
+ ntype->butfunc = node_composit_buts_defocus;
+ break;
+ /* qdn: glare node */
+ case CMP_NODE_GLARE:
+ ntype->butfunc = node_composit_buts_glare;
+ break;
+ /* qdn: tonemap node */
+ case CMP_NODE_TONEMAP:
+ ntype->butfunc = node_composit_buts_tonemap;
+ break;
+ /* qdn: lens distortion node */
+ case CMP_NODE_LENSDIST:
+ ntype->butfunc = node_composit_buts_lensdist;
+ break;
+ case CMP_NODE_VECBLUR:
+ ntype->butfunc= node_composit_buts_vecblur;
+ break;
+ case CMP_NODE_FILTER:
+ ntype->butfunc= node_composit_buts_filter;
+ break;
+ case CMP_NODE_MAP_VALUE:
+ ntype->butfunc= node_composit_buts_map_value;
+ break;
+ case CMP_NODE_TIME:
+ ntype->butfunc= node_buts_time;
+ break;
+ case CMP_NODE_ALPHAOVER:
+ ntype->butfunc= node_composit_buts_alphaover;
+ break;
+ case CMP_NODE_HUE_SAT:
+ ntype->butfunc= node_composit_buts_hue_sat;
+ break;
+ case CMP_NODE_TEXTURE:
+ ntype->butfunc= node_buts_texture;
+ break;
+ case CMP_NODE_DILATEERODE:
+ ntype->butfunc= node_composit_buts_dilateerode;
+ break;
+ case CMP_NODE_OUTPUT_FILE:
+ ntype->butfunc= node_composit_buts_file_output;
+ break;
+
+ case CMP_NODE_DIFF_MATTE:
+ ntype->butfunc=node_composit_buts_diff_matte;
+ break;
+ case CMP_NODE_COLOR_SPILL:
+ ntype->butfunc=node_composit_buts_color_spill;
+ break;
+ case CMP_NODE_CHROMA:
+ ntype->butfunc=node_composit_buts_chroma_matte;
+ break;
+ case CMP_NODE_SCALE:
+ ntype->butfunc= node_composit_buts_scale;
+ break;
+ case CMP_NODE_CHANNEL_MATTE:
+ ntype->butfunc= node_composit_buts_channel_matte;
+ break;
+ case CMP_NODE_LUMA_MATTE:
+ ntype->butfunc= node_composit_buts_luma_matte;
+ break;
+ case CMP_NODE_MAP_UV:
+ ntype->butfunc= node_composit_buts_map_uv;
+ break;
+ case CMP_NODE_ID_MASK:
+ ntype->butfunc= node_composit_buts_id_mask;
+ break;
+ case CMP_NODE_MATH:
+ ntype->butfunc= node_buts_math;
+ break;
+ case CMP_NODE_INVERT:
+ ntype->butfunc= node_composit_buts_invert;
+ break;
+ default:
+ ntype->butfunc= NULL;
+ }
+}
+
+
+/* ******* init draw callbacks for all tree types, only called in usiblender.c, once ************* */
+
+void init_node_butfuncs(void)
+{
+ bNodeType *ntype;
+
+ /* shader nodes */
+ ntype= node_all_shaders.first;
+ while(ntype) {
+ node_shader_set_butfunc(ntype);
+ ntype= ntype->next;
+ }
+ /* composit nodes */
+ ntype= node_all_composit.first;
+ while(ntype) {
+ node_composit_set_butfunc(ntype);
+ ntype= ntype->next;
+ }
+}
+
+/* ************** Generic drawing ************** */
+
+static void draw_nodespace_grid(SpaceNode *snode)
+{
+ float start, step= 25.0f;
+
+ BIF_ThemeColorShade(TH_BACK, -10);
+
+ start= snode->v2d.cur.xmin -fmod(snode->v2d.cur.xmin, step);
+
+ glBegin(GL_LINES);
+ for(; start<snode->v2d.cur.xmax; start+=step) {
+ glVertex2f(start, snode->v2d.cur.ymin);
+ glVertex2f(start, snode->v2d.cur.ymax);
+ }
+
+ start= snode->v2d.cur.ymin -fmod(snode->v2d.cur.ymin, step);
+ for(; start<snode->v2d.cur.ymax; start+=step) {
+ glVertex2f(snode->v2d.cur.xmin, start);
+ glVertex2f(snode->v2d.cur.xmax, start);
+ }
+
+ /* X and Y axis */
+ BIF_ThemeColorShade(TH_BACK, -18);
+ glVertex2f(0.0f, snode->v2d.cur.ymin);
+ glVertex2f(0.0f, snode->v2d.cur.ymax);
+ glVertex2f(snode->v2d.cur.xmin, 0.0f);
+ glVertex2f(snode->v2d.cur.xmax, 0.0f);
+
+ glEnd();
+}
+
+static void draw_nodespace_back(ScrArea *sa, SpaceNode *snode)
+{
+
+ draw_nodespace_grid(snode);
+
+ if(snode->flag & SNODE_BACKDRAW) {
+ Image *ima= BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
+ ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL);
+ if(ibuf) {
+ int x, y;
+ /* somehow the offset has to be calculated inverse */
+
+ glaDefine2DArea(&sa->winrct);
+ /* ortho at pixel level curarea */
+ myortho2(-0.375, sa->winx-0.375, -0.375, sa->winy-0.375);
+
+ x = (sa->winx-ibuf->x)/2 + snode->xof;
+ y = (sa->winx-ibuf->y)/2 + snode->yof;
+
+ if(ibuf->rect)
+ glaDrawPixelsSafe(x, y, ibuf->x, ibuf->y, ibuf->x, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
+ else if(ibuf->channels==4)
+ glaDrawPixelsSafe(x, y, ibuf->x, ibuf->y, ibuf->x, GL_RGBA, GL_FLOAT, ibuf->rect_float);
+
+ /* sort this out, this should not be needed */
+ myortho2(snode->v2d.cur.xmin, snode->v2d.cur.xmax, snode->v2d.cur.ymin, snode->v2d.cur.ymax);
+ bwin_clear_viewmat(sa->win); /* clear buttons view */
+ glLoadIdentity();
+ }
+ }
+}
+
+/* nice AA filled circle */
+static void socket_circle_draw(float x, float y, float size, int type, int select)
+{
+ /* 16 values of sin function */
+ static float si[16] = {
+ 0.00000000, 0.39435585,0.72479278,0.93775213,
+ 0.99871650,0.89780453,0.65137248,0.29936312,
+ -0.10116832,-0.48530196,-0.79077573,-0.96807711,
+ -0.98846832,-0.84864425,-0.57126821,-0.20129852
+ };
+ /* 16 values of cos function */
+ static float co[16] ={
+ 1.00000000,0.91895781,0.68896691,0.34730525,
+ -0.05064916,-0.44039415,-0.75875812,-0.95413925,
+ -0.99486932,-0.87434661,-0.61210598,-0.25065253,
+ 0.15142777,0.52896401,0.82076344,0.97952994,
+ };
+ int a;
+
+ if(select==0) {
+ if(type==-1)
+ glColor3ub(0, 0, 0);
+ else if(type==SOCK_VALUE)
+ glColor3ub(160, 160, 160);
+ else if(type==SOCK_VECTOR)
+ glColor3ub(100, 100, 200);
+ else if(type==SOCK_RGBA)
+ glColor3ub(200, 200, 40);
+ else
+ glColor3ub(100, 200, 100);
+ }
+ else {
+ if(type==SOCK_VALUE)
+ glColor3ub(200, 200, 200);
+ else if(type==SOCK_VECTOR)
+ glColor3ub(140, 140, 240);
+ else if(type==SOCK_RGBA)
+ glColor3ub(240, 240, 100);
+ else
+ glColor3ub(140, 240, 140);
+ }
+
+ glBegin(GL_POLYGON);
+ for(a=0; a<16; a++)
+ glVertex2f(x+size*si[a], y+size*co[a]);
+ glEnd();
+
+ glColor4ub(0, 0, 0, 150);
+ glEnable(GL_BLEND);
+ glEnable( GL_LINE_SMOOTH );
+ glBegin(GL_LINE_LOOP);
+ for(a=0; a<16; a++)
+ glVertex2f(x+size*si[a], y+size*co[a]);
+ glEnd();
+ glDisable( GL_LINE_SMOOTH );
+ glDisable(GL_BLEND);
+}
+
+/* not a callback */
+static void node_draw_preview(bNodePreview *preview, rctf *prv)
+{
+ float xscale= (prv->xmax-prv->xmin)/((float)preview->xsize);
+ float yscale= (prv->ymax-prv->ymin)/((float)preview->ysize);
+ float tile= (prv->xmax - prv->xmin) / 10.0;
+ float x, y;
+
+ /* draw checkerboard backdrop to show alpha */
+ glColor3ub(120, 120, 120);
+ glRectf(prv->xmin, prv->ymin, prv->xmax, prv->ymax);
+ glColor3ub(160, 160, 160);
+
+ for(y=prv->ymin; y<prv->ymax; y+=tile*2) {
+ for(x=prv->xmin; x<prv->xmax; x+=tile*2) {
+ float tilex= tile, tiley= tile;
+
+ if(x+tile > prv->xmax)
+ tilex= prv->xmax-x;
+ if(y+tile > prv->ymax)
+ tiley= prv->ymax-y;
+
+ glRectf(x, y, x + tilex, y + tiley);
+ }
+ }
+ for(y=prv->ymin+tile; y<prv->ymax; y+=tile*2) {
+ for(x=prv->xmin+tile; x<prv->xmax; x+=tile*2) {
+ float tilex= tile, tiley= tile;
+
+ if(x+tile > prv->xmax)
+ tilex= prv->xmax-x;
+ if(y+tile > prv->ymax)
+ tiley= prv->ymax-y;
+
+ glRectf(x, y, x + tilex, y + tiley);
+ }
+ }
+
+ glPixelZoom(xscale, yscale);
+ glEnable(GL_BLEND);
+ glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_ALPHA ); /* premul graphics */
+
+ glColor4f(1.0, 1.0, 1.0, 1.0);
+ glaDrawPixelsTex(prv->xmin, prv->ymin, preview->xsize, preview->ysize, GL_FLOAT, preview->rect);
+
+ glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
+ glDisable(GL_BLEND);
+ glPixelZoom(1.0f, 1.0f);
+
+ BIF_ThemeColorShadeAlpha(TH_BACK, -15, +100);
+ fdrawbox(prv->xmin, prv->ymin, prv->xmax, prv->ymax);
+
+}
+
+/* based on settings in node, sets drawing rect info. each redraw! */
+static void node_update_hidden(bNode *node)
+{
+ bNodeSocket *nsock;
+ float rad, drad, hiddenrad= HIDDEN_RAD;
+ int totin=0, totout=0, tot;
+
+ /* calculate minimal radius */
+ for(nsock= node->inputs.first; nsock; nsock= nsock->next)
+ if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL)))
+ totin++;
+ for(nsock= node->outputs.first; nsock; nsock= nsock->next)
+ if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL)))
+ totout++;
+
+ tot= MAX2(totin, totout);
+ if(tot>4) {
+ hiddenrad += 5.0*(float)(tot-4);
+ }
+
+ node->totr.xmin= node->locx;
+ node->totr.xmax= node->locx + 3*hiddenrad + node->miniwidth;
+ node->totr.ymax= node->locy + (hiddenrad - 0.5f*NODE_DY);
+ node->totr.ymin= node->totr.ymax - 2*hiddenrad;
+
+ /* output sockets */
+ rad=drad= M_PI/(1.0f + (float)totout);
+
+ for(nsock= node->outputs.first; nsock; nsock= nsock->next) {
+ if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
+ nsock->locx= node->totr.xmax - hiddenrad + sin(rad)*hiddenrad;
+ nsock->locy= node->totr.ymin + hiddenrad + cos(rad)*hiddenrad;
+ rad+= drad;
+ }
+ }
+
+ /* input sockets */
+ rad=drad= - M_PI/(1.0f + (float)totin);
+
+ for(nsock= node->inputs.first; nsock; nsock= nsock->next) {
+ if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
+ nsock->locx= node->totr.xmin + hiddenrad + sin(rad)*hiddenrad;
+ nsock->locy= node->totr.ymin + hiddenrad + cos(rad)*hiddenrad;
+ rad+= drad;
+ }
+ }
+}
+
+/* based on settings in node, sets drawing rect info. each redraw! */
+static void node_update(bNode *node)
+{
+ bNodeSocket *nsock;
+ float dy= node->locy;
+
+ /* header */
+ dy-= NODE_DY;
+
+ /* little bit space in top */
+ if(node->outputs.first)
+ dy-= NODE_DYS/2;
+
+ /* output sockets */
+ for(nsock= node->outputs.first; nsock; nsock= nsock->next) {
+ if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
+ nsock->locx= node->locx + node->width;
+ nsock->locy= dy - NODE_DYS;
+ dy-= NODE_DY;
+ }
+ }
+
+ node->prvr.xmin= node->butr.xmin= node->locx + NODE_DYS;
+ node->prvr.xmax= node->butr.xmax= node->locx + node->width- NODE_DYS;
+
+ /* preview rect? */
+ if(node->flag & NODE_PREVIEW) {
+ /* only recalculate size when there's a preview actually, otherwise we use stored result */
+ if(node->preview && node->preview->rect) {
+ float aspect= 1.0f;
+
+ if(node->preview && node->preview->xsize && node->preview->ysize)
+ aspect= (float)node->preview->ysize/(float)node->preview->xsize;
+
+ dy-= NODE_DYS/2;
+ node->prvr.ymax= dy;
+
+ if(aspect <= 1.0f)
+ node->prvr.ymin= dy - aspect*(node->width-NODE_DY);
+ else {
+ float dx= (node->width - NODE_DYS) - (node->width- NODE_DYS)/aspect; /* width correction of image */
+
+ node->prvr.ymin= dy - (node->width-NODE_DY);
+
+ node->prvr.xmin+= 0.5*dx;
+ node->prvr.xmax-= 0.5*dx;
+ }
+
+ dy= node->prvr.ymin - NODE_DYS/2;
+
+ /* make sure that maximums are bigger or equal to minimums */
+ if(node->prvr.xmax < node->prvr.xmin) SWAP(float, node->prvr.xmax, node->prvr.xmin);
+ if(node->prvr.ymax < node->prvr.ymin) SWAP(float, node->prvr.ymax, node->prvr.ymin);
+ }
+ else {
+ float oldh= node->prvr.ymax - node->prvr.ymin;
+ if(oldh==0.0f)
+ oldh= 0.6f*node->width-NODE_DY;
+ dy-= NODE_DYS/2;
+ node->prvr.ymax= dy;
+ node->prvr.ymin= dy - oldh;
+ dy= node->prvr.ymin - NODE_DYS/2;
+ }
+ }
+
+ /* XXX ugly hack, typeinfo for group is generated */
+ if(node->type == NODE_GROUP)
+ node->typeinfo->butfunc= node_buts_group;
+
+ /* buttons rect? */
+ if((node->flag & NODE_OPTIONS) && node->typeinfo->butfunc) {
+ dy-= NODE_DYS/2;
+ node->butr.ymax= dy;
+ node->butr.ymin= dy - (float)node->typeinfo->butfunc(NULL, NULL, node, NULL);
+ dy= node->butr.ymin - NODE_DYS/2;
+ }
+
+ /* input sockets */
+ for(nsock= node->inputs.first; nsock; nsock= nsock->next) {
+ if(!(nsock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
+ nsock->locx= node->locx;
+ nsock->locy= dy - NODE_DYS;
+ dy-= NODE_DY;
+ }
+ }
+
+ /* little bit space in end */
+ if(node->inputs.first || (node->flag & (NODE_OPTIONS|NODE_PREVIEW))==0 )
+ dy-= NODE_DYS/2;
+
+ node->totr.xmin= node->locx;
+ node->totr.xmax= node->locx + node->width;
+ node->totr.ymax= node->locy;
+ node->totr.ymin= dy;
+}
+
+/* based on settings in node, sets drawing rect info. each redraw! */
+/* note: this assumes only 1 group at a time is drawn (linked data) */
+/* in node->totr the entire boundbox for the group is stored */
+static void node_update_group(bNode *gnode)
+{
+ bNodeTree *ngroup= (bNodeTree *)gnode->id;
+ bNode *node;
+ bNodeSocket *nsock;
+ rctf *rect= &gnode->totr;
+ int counter;
+
+ /* center them, is a bit of abuse of locx and locy though */
+ for(node= ngroup->nodes.first; node; node= node->next) {
+ node->locx+= gnode->locx;
+ node->locy+= gnode->locy;
+ if(node->flag & NODE_HIDDEN)
+ node_update_hidden(node);
+ else
+ node_update(node);
+ node->locx-= gnode->locx;
+ node->locy-= gnode->locy;
+ }
+ counter= 1;
+ for(node= ngroup->nodes.first; node; node= node->next) {
+ if(counter) {
+ *rect= node->totr;
+ counter= 0;
+ }
+ else
+ BLI_union_rctf(rect, &node->totr);
+ }
+ if(counter==1) return; /* should be prevented? */
+
+ rect->xmin-= NODE_DY;
+ rect->ymin-= NODE_DY;
+ rect->xmax+= NODE_DY;
+ rect->ymax+= NODE_DY;
+
+ /* output sockets */
+ for(nsock= gnode->outputs.first; nsock; nsock= nsock->next) {
+ nsock->locx= rect->xmax;
+ nsock->locy= nsock->tosock->locy;
+ }
+
+ /* input sockets */
+ for(nsock= gnode->inputs.first; nsock; nsock= nsock->next) {
+ nsock->locx= rect->xmin;
+ nsock->locy= nsock->tosock->locy;
+ }
+}
+
+static void node_scaling_widget(int color_id, float aspect, float xmin, float ymin, float xmax, float ymax)
+{
+ float dx;
+ float dy;
+
+ dx= 0.5f*(xmax-xmin);
+ dy= 0.5f*(ymax-ymin);
+
+ BIF_ThemeColorShade(color_id, +30);
+ fdrawline(xmin, ymin, xmax, ymax);
+ fdrawline(xmin+dx, ymin, xmax, ymax-dy);
+
+ BIF_ThemeColorShade(color_id, -10);
+ fdrawline(xmin, ymin+aspect, xmax, ymax+aspect);
+ fdrawline(xmin+dx, ymin+aspect, xmax, ymax-dy+aspect);
+}
+
+static int node_get_colorid(bNode *node)
+{
+ if(node->typeinfo->nclass==NODE_CLASS_INPUT)
+ return TH_NODE_IN_OUT;
+ if(node->typeinfo->nclass==NODE_CLASS_OUTPUT) {
+ if(node->flag & NODE_DO_OUTPUT)
+ return TH_NODE_IN_OUT;
+ else
+ return TH_NODE;
+ }
+ if(node->typeinfo->nclass==NODE_CLASS_CONVERTOR)
+ return TH_NODE_CONVERTOR;
+ if(ELEM3(node->typeinfo->nclass, NODE_CLASS_OP_COLOR, NODE_CLASS_OP_VECTOR, NODE_CLASS_OP_FILTER))
+ return TH_NODE_OPERATOR;
+ if(node->typeinfo->nclass==NODE_CLASS_GROUP)
+ return TH_NODE_GROUP;
+ return TH_NODE;
+}
+
+static void node_draw_basis(ScrArea *sa, SpaceNode *snode, bNode *node)
+{
+ bNodeSocket *sock;
+ uiBlock *block= NULL;
+ uiBut *bt;
+ rctf *rct= &node->totr;
+ float slen, iconofs;
+ int ofs, color_id= node_get_colorid(node);
+
+ uiSetRoundBox(15-4);
+ ui_dropshadow(rct, BASIS_RAD, snode->aspect, node->flag & SELECT);
+
+ /* header */
+ if(color_id==TH_NODE)
+ BIF_ThemeColorShade(color_id, -20);
+ else
+ BIF_ThemeColor(color_id);
+
+ uiSetRoundBox(3);
+ uiRoundBox(rct->xmin, rct->ymax-NODE_DY, rct->xmax, rct->ymax, BASIS_RAD);
+
+ /* show/hide icons, note this sequence is copied in editnode.c */
+ iconofs= rct->xmax;
+
+ if(node->typeinfo->flag & NODE_PREVIEW) {
+ int icon_id;
+
+ if(node->flag & (NODE_ACTIVE_ID|NODE_DO_OUTPUT))
+ icon_id= ICON_MATERIAL;
+ else
+ icon_id= ICON_MATERIAL_DEHLT;
+ iconofs-= 18.0f;
+ glEnable(GL_BLEND);
+ BIF_icon_draw_aspect_blended(iconofs, rct->ymax-NODE_DY+2, icon_id, snode->aspect, -60);
+ glDisable(GL_BLEND);
+ }
+ if(node->type == NODE_GROUP) {
+
+ iconofs-= 18.0f;
+ glEnable(GL_BLEND);
+ if(node->id->lib) {
+ glPixelTransferf(GL_GREEN_SCALE, 0.7f);
+ glPixelTransferf(GL_BLUE_SCALE, 0.3f);
+ BIF_icon_draw_aspect(iconofs, rct->ymax-NODE_DY+2, ICON_NODE, snode->aspect);
+ glPixelTransferf(GL_GREEN_SCALE, 1.0f);
+ glPixelTransferf(GL_BLUE_SCALE, 1.0f);
+ }
+ else {
+ BIF_icon_draw_aspect_blended(iconofs, rct->ymax-NODE_DY+2, ICON_NODE, snode->aspect, -60);
+ }
+ glDisable(GL_BLEND);
+ }
+ if(node->typeinfo->flag & NODE_OPTIONS) {
+ iconofs-= 18.0f;
+ glEnable(GL_BLEND);
+ BIF_icon_draw_aspect_blended(iconofs, rct->ymax-NODE_DY+2, ICON_BUTS, snode->aspect, -60);
+ glDisable(GL_BLEND);
+ }
+ { /* always hide/reveil unused sockets */
+ int shade;
+
+ iconofs-= 18.0f;
+ if(node_has_hidden_sockets(node))
+ shade= -40;
+ else
+ shade= -90;
+ glEnable(GL_BLEND);
+ BIF_icon_draw_aspect_blended(iconofs, rct->ymax-NODE_DY+2, ICON_PLUS, snode->aspect, shade);
+ glDisable(GL_BLEND);
+ }
+
+ /* title */
+ if(node->flag & SELECT)
+ BIF_ThemeColor(TH_TEXT_HI);
+ else
+ BIF_ThemeColorBlendShade(TH_TEXT, color_id, 0.4, 10);
+
+ /* open/close entirely? */
+ ui_draw_tria_icon(rct->xmin+8.0f, rct->ymax-NODE_DY+4.0f, snode->aspect, 'v');
+
+ if(node->flag & SELECT)
+ BIF_ThemeColor(TH_TEXT_HI);
+ else
+ BIF_ThemeColor(TH_TEXT);
+
+ ui_rasterpos_safe(rct->xmin+19.0f, rct->ymax-NODE_DY+5.0f, snode->aspect);
+ snode_drawstring(snode, node->name, (int)(iconofs - rct->xmin-18.0f));
+
+ /* body */
+ BIF_ThemeColor4(TH_NODE);
+ glEnable(GL_BLEND);
+ uiSetRoundBox(8);
+ uiRoundBox(rct->xmin, rct->ymin, rct->xmax, rct->ymax-NODE_DY, BASIS_RAD);
+ glDisable(GL_BLEND);
+
+ /* scaling indicator */
+ node_scaling_widget(TH_NODE, snode->aspect, rct->xmax-BASIS_RAD*snode->aspect, rct->ymin, rct->xmax, rct->ymin+BASIS_RAD*snode->aspect);
+
+ /* outline active emphasis */
+ if(node->flag & NODE_ACTIVE) {
+ glEnable(GL_BLEND);
+ glColor4ub(200, 200, 200, 140);
+ uiSetRoundBox(15-4);
+ gl_round_box(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, BASIS_RAD);
+ glDisable(GL_BLEND);
+ }
+
+ /* we make buttons for input sockets, if... */
+ if(node->flag & NODE_OPTIONS) {
+ if(node->inputs.first || node->typeinfo->butfunc) {
+ char str[32];
+
+ /* make unique block name, also used for handling blocks in editnode.c */
+ sprintf(str, "node buttons %p", node);
+
+ block= uiNewBlock(&sa->uiblocks, str, UI_EMBOSS, UI_HELV, sa->win);
+ uiBlockSetFlag(block, UI_BLOCK_NO_HILITE);
+ if(snode->id)
+ uiSetButLock(snode->id->lib!=NULL, ERROR_LIBDATA_MESSAGE);
+ }
+ }
+
+ /* hurmf... another candidate for callback, have to see how this works first */
+ if(node->id && block && snode->treetype==NTREE_SHADER)
+ nodeShaderSynchronizeID(node, 0);
+
+ /* socket inputs, buttons */
+ for(sock= node->inputs.first; sock; sock= sock->next) {
+ if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
+ socket_circle_draw(sock->locx, sock->locy, NODE_SOCKSIZE, sock->type, sock->flag & SELECT);
+
+ if(block && sock->link==NULL) {
+ float *butpoin= sock->ns.vec;
+
+ if(sock->type==SOCK_VALUE) {
+ bt= uiDefButF(block, NUM, B_NODE_EXEC+node->nr, sock->name,
+ (short)sock->locx+NODE_DYS, (short)(sock->locy)-9, (short)node->width-NODE_DY, 17,
+ butpoin, sock->ns.min, sock->ns.max, 10, 2, "");
+ uiButSetFunc(bt, node_sync_cb, snode, node);
+ }
+ else if(sock->type==SOCK_VECTOR) {
+ uiDefBlockBut(block, socket_vector_menu, sock, sock->name,
+ (short)sock->locx+NODE_DYS, (short)sock->locy-9, (short)node->width-NODE_DY, 17,
+ "");
+ }
+ else if(block && sock->type==SOCK_RGBA) {
+ short labelw= node->width-NODE_DY-40, width;
+
+ if(labelw>0) width= 40; else width= node->width-NODE_DY;
+
+ bt= uiDefButF(block, COL, B_NODE_EXEC+node->nr, "",
+ (short)(sock->locx+NODE_DYS), (short)sock->locy-8, width, 15,
+ butpoin, 0, 0, 0, 0, "");
+ uiButSetFunc(bt, node_sync_cb, snode, node);
+
+ if(labelw>0) uiDefBut(block, LABEL, 0, sock->name,
+ (short)(sock->locx+NODE_DYS) + 40, (short)sock->locy-8, labelw, 15,
+ NULL, 0, 0, 0, 0, "");
+ }
+ }
+ else {
+ BIF_ThemeColor(TH_TEXT);
+ ui_rasterpos_safe(sock->locx+8.0f, sock->locy-5.0f, snode->aspect);
+ BIF_DrawString(snode->curfont, sock->name, 0);
+ }
+ }
+ }
+
+ /* socket outputs */
+ for(sock= node->outputs.first; sock; sock= sock->next) {
+ if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
+ socket_circle_draw(sock->locx, sock->locy, NODE_SOCKSIZE, sock->type, sock->flag & SELECT);
+
+ BIF_ThemeColor(TH_TEXT);
+ ofs= 0;
+ slen= snode->aspect*BIF_GetStringWidth(snode->curfont, sock->name, 0);
+ while(slen > node->width) {
+ ofs++;
+ slen= snode->aspect*BIF_GetStringWidth(snode->curfont, sock->name+ofs, 0);
+ }
+ ui_rasterpos_safe(sock->locx-8.0f-slen, sock->locy-5.0f, snode->aspect);
+ BIF_DrawString(snode->curfont, sock->name+ofs, 0);
+ }
+ }
+
+ /* preview */
+ if(node->flag & NODE_PREVIEW)
+ if(node->preview && node->preview->rect)
+ node_draw_preview(node->preview, &node->prvr);
+
+ /* buttons */
+ if(node->flag & NODE_OPTIONS) {
+ if(block) {
+ if(node->typeinfo->butfunc) {
+ node->typeinfo->butfunc(block, snode->nodetree, node, &node->butr);
+ }
+ uiDrawBlock(block);
+ }
+ }
+
+}
+
+void node_draw_hidden(SpaceNode *snode, bNode *node)
+{
+ bNodeSocket *sock;
+ rctf *rct= &node->totr;
+ float dx, centy= 0.5f*(rct->ymax+rct->ymin);
+ float hiddenrad= 0.5f*(rct->ymax-rct->ymin);
+ int color_id= node_get_colorid(node);
+
+ /* shadow */
+ uiSetRoundBox(15);
+ ui_dropshadow(rct, hiddenrad, snode->aspect, node->flag & SELECT);
+
+ /* body */
+ BIF_ThemeColor(color_id);
+ uiRoundBox(rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad);
+
+ /* outline active emphasis */
+ if(node->flag & NODE_ACTIVE) {
+ glEnable(GL_BLEND);
+ glColor4ub(200, 200, 200, 140);
+ gl_round_box(GL_LINE_LOOP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, hiddenrad);
+ glDisable(GL_BLEND);
+ }
+
+ /* title */
+ if(node->flag & SELECT)
+ BIF_ThemeColor(TH_TEXT_HI);
+ else
+ BIF_ThemeColorBlendShade(TH_TEXT, color_id, 0.4, 10);
+
+ /* open entirely icon */
+ ui_draw_tria_icon(rct->xmin+9.0f, centy-6.0f, snode->aspect, 'h');
+
+ if(node->flag & SELECT)
+ BIF_ThemeColor(TH_TEXT_HI);
+ else
+ BIF_ThemeColor(TH_TEXT);
+
+ if(node->miniwidth>0.0f) {
+ ui_rasterpos_safe(rct->xmin+21.0f, centy-4.0f, snode->aspect);
+ snode_drawstring(snode, node->name, (int)(rct->xmax - rct->xmin-18.0f -12.0f));
+ }
+
+ /* scale widget thing */
+ BIF_ThemeColorShade(color_id, -10);
+ dx= 10.0f;
+ fdrawline(rct->xmax-dx, centy-4.0f, rct->xmax-dx, centy+4.0f);
+ fdrawline(rct->xmax-dx-3.0f*snode->aspect, centy-4.0f, rct->xmax-dx-3.0f*snode->aspect, centy+4.0f);
+
+ BIF_ThemeColorShade(color_id, +30);
+ dx-= snode->aspect;
+ fdrawline(rct->xmax-dx, centy-4.0f, rct->xmax-dx, centy+4.0f);
+ fdrawline(rct->xmax-dx-3.0f*snode->aspect, centy-4.0f, rct->xmax-dx-3.0f*snode->aspect, centy+4.0f);
+
+ /* sockets */
+ for(sock= node->inputs.first; sock; sock= sock->next) {
+ if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL)))
+ socket_circle_draw(sock->locx, sock->locy, NODE_SOCKSIZE, sock->type, sock->flag & SELECT);
+ }
+
+ for(sock= node->outputs.first; sock; sock= sock->next) {
+ if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL)))
+ socket_circle_draw(sock->locx, sock->locy, NODE_SOCKSIZE, sock->type, sock->flag & SELECT);
+ }
+}
+
+/* note; this is used for fake links in groups too */
+void node_draw_link(SpaceNode *snode, bNodeLink *link)
+{
+ float vec[4][3];
+ float dist, spline_step, mx=0.0f, my=0.0f;
+ int curve_res, do_shaded= 1, th_col1= TH_WIRE, th_col2= TH_WIRE;
+
+ if(link->fromnode==NULL && link->tonode==NULL)
+ return;
+
+ /* this is dragging link */
+ if(link->fromnode==NULL || link->tonode==NULL) {
+ short mval[2];
+ getmouseco_areawin(mval);
+ areamouseco_to_ipoco(G.v2d, mval, &mx, &my);
+ BIF_ThemeColor(TH_WIRE);
+ do_shaded= 0;
+ }
+ else {
+ /* going to give issues once... */
+ if(link->tosock->flag & SOCK_UNAVAIL)
+ return;
+ if(link->fromsock->flag & SOCK_UNAVAIL)
+ return;
+
+ /* a bit ugly... but thats how we detect the internal group links */
+ if(link->fromnode==link->tonode) {
+ BIF_ThemeColorBlend(TH_BACK, TH_WIRE, 0.25f);
+ do_shaded= 0;
+ }
+ else {
+ /* check cyclic */
+ if(link->fromnode->level >= link->tonode->level && link->tonode->level!=0xFFF) {
+ if(link->fromnode->flag & SELECT)
+ th_col1= TH_EDGE_SELECT;
+ if(link->tonode->flag & SELECT)
+ th_col2= TH_EDGE_SELECT;
+ }
+ else {
+ BIF_ThemeColor(TH_REDALERT);
+ do_shaded= 0;
+ }
+ }
+ }
+
+ vec[0][2]= vec[1][2]= vec[2][2]= vec[3][2]= 0.0; /* only 2d spline, set the Z to 0*/
+
+ /* in v0 and v3 we put begin/end points */
+ if(link->fromnode) {
+ vec[0][0]= link->fromsock->locx;
+ vec[0][1]= link->fromsock->locy;
+ }
+ else {
+ vec[0][0]= mx;
+ vec[0][1]= my;
+ }
+ if(link->tonode) {
+ vec[3][0]= link->tosock->locx;
+ vec[3][1]= link->tosock->locy;
+ }
+ else {
+ vec[3][0]= mx;
+ vec[3][1]= my;
+ }
+
+ dist= 0.5f*ABS(vec[0][0] - vec[3][0]);
+
+ /* check direction later, for top sockets */
+ vec[1][0]= vec[0][0]+dist;
+ vec[1][1]= vec[0][1];
+
+ vec[2][0]= vec[3][0]-dist;
+ vec[2][1]= vec[3][1];
+
+ if( MIN4(vec[0][0], vec[1][0], vec[2][0], vec[3][0]) > G.v2d->cur.xmax); /* clipped */
+ else if ( MAX4(vec[0][0], vec[1][0], vec[2][0], vec[3][0]) < G.v2d->cur.xmin); /* clipped */
+ else {
+ curve_res = 24;
+
+ /* we can reuse the dist variable here to increment the GL curve eval amount*/
+ dist = 1.0f/curve_res;
+ spline_step = 0.0f;
+
+ glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, vec[0]);
+ glBegin(GL_LINE_STRIP);
+ while (spline_step < 1.000001f) {
+ if(do_shaded)
+ BIF_ThemeColorBlend(th_col1, th_col2, spline_step);
+ glEvalCoord1f(spline_step);
+ spline_step += dist;
+ }
+ glEnd();
+ }
+}
+
+static void node_draw_nodetree(ScrArea *sa, SpaceNode *snode, bNodeTree *ntree)
+{
+ bNode *node;
+ bNodeLink *link;
+ int a;
+
+ if(ntree==NULL) return; /* groups... */
+
+ /* node lines */
+ glEnable(GL_BLEND);
+ glEnable( GL_LINE_SMOOTH );
+ for(link= ntree->links.first; link; link= link->next)
+ node_draw_link(snode, link);
+ glDisable(GL_BLEND);
+ glDisable( GL_LINE_SMOOTH );
+
+ /* not selected first */
+ for(a=0, node= ntree->nodes.first; node; node= node->next, a++) {
+ node->nr= a; /* index of node in list, used for exec event code */
+ if(!(node->flag & SELECT)) {
+ if(node->flag & NODE_GROUP_EDIT);
+ else if(node->flag & NODE_HIDDEN)
+ node_draw_hidden(snode, node);
+ else
+ node_draw_basis(sa, snode, node);
+ }
+ }
+
+ /* selected */
+ for(node= ntree->nodes.first; node; node= node->next) {
+ if(node->flag & SELECT) {
+ if(node->flag & NODE_GROUP_EDIT);
+ else if(node->flag & NODE_HIDDEN)
+ node_draw_hidden(snode, node);
+ else
+ node_draw_basis(sa, snode, node);
+ }
+ }
+}
+
+/* fake links from groupnode to internal nodes */
+static void node_draw_group_links(SpaceNode *snode, bNode *gnode)
+{
+ bNodeLink fakelink;
+ bNodeSocket *sock;
+
+ glEnable(GL_BLEND);
+ glEnable( GL_LINE_SMOOTH );
+
+ fakelink.tonode= fakelink.fromnode= gnode;
+
+ for(sock= gnode->inputs.first; sock; sock= sock->next) {
+ if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
+ if(sock->tosock) {
+ fakelink.fromsock= sock;
+ fakelink.tosock= sock->tosock;
+ node_draw_link(snode, &fakelink);
+ }
+ }
+ }
+
+ for(sock= gnode->outputs.first; sock; sock= sock->next) {
+ if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
+ if(sock->tosock) {
+ fakelink.tosock= sock;
+ fakelink.fromsock= sock->tosock;
+ node_draw_link(snode, &fakelink);
+ }
+ }
+ }
+
+ glDisable(GL_BLEND);
+ glDisable( GL_LINE_SMOOTH );
+}
+
+/* groups are, on creation, centered around 0,0 */
+static void node_draw_group(ScrArea *sa, SpaceNode *snode, bNode *gnode)
+{
+ bNodeTree *ngroup= (bNodeTree *)gnode->id;
+ bNodeSocket *sock;
+ rctf rect= gnode->totr;
+
+ /* backdrop header */
+ glEnable(GL_BLEND);
+ uiSetRoundBox(3);
+ BIF_ThemeColorShadeAlpha(TH_NODE_GROUP, 0, -70);
+ gl_round_box(GL_POLYGON, rect.xmin, rect.ymax, rect.xmax, rect.ymax+NODE_DY, BASIS_RAD);
+
+ /* backdrop body */
+ BIF_ThemeColorShadeAlpha(TH_BACK, -8, -70);
+ uiSetRoundBox(12);
+ gl_round_box(GL_POLYGON, rect.xmin, rect.ymin, rect.xmax, rect.ymax, BASIS_RAD);
+
+ /* selection outline */
+ uiSetRoundBox(15);
+ glColor4ub(200, 200, 200, 140);
+ glEnable( GL_LINE_SMOOTH );
+ gl_round_box(GL_LINE_LOOP, rect.xmin, rect.ymin, rect.xmax, rect.ymax+NODE_DY, BASIS_RAD);
+ glDisable( GL_LINE_SMOOTH );
+ glDisable(GL_BLEND);
+
+ /* backdrop title */
+ BIF_ThemeColor(TH_TEXT_HI);
+ ui_rasterpos_safe(rect.xmin+8.0f, rect.ymax+5.0f, snode->aspect);
+ BIF_DrawString(snode->curfont, ngroup->id.name+2, 0);
+
+ /* links from groupsockets to the internal nodes */
+ node_draw_group_links(snode, gnode);
+
+ /* group sockets */
+ for(sock= gnode->inputs.first; sock; sock= sock->next)
+ if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL)))
+ socket_circle_draw(sock->locx, sock->locy, NODE_SOCKSIZE, sock->type, sock->flag & SELECT);
+ for(sock= gnode->outputs.first; sock; sock= sock->next)
+ if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL)))
+ socket_circle_draw(sock->locx, sock->locy, NODE_SOCKSIZE, sock->type, sock->flag & SELECT);
+
+ /* and finally the whole tree */
+ node_draw_nodetree(sa, snode, ngroup);
+}
+
+
+void drawnodespace(ScrArea *sa, void *spacedata)
+{
+ SpaceNode *snode= sa->spacedata.first;
+ float col[3];
+
+ BIF_GetThemeColor3fv(TH_BACK, col);
+ glClearColor(col[0], col[1], col[2], 0.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ calc_scrollrcts(sa, &(snode->v2d), sa->winx, sa->winy);
+
+ myortho2(snode->v2d.cur.xmin, snode->v2d.cur.xmax, snode->v2d.cur.ymin, snode->v2d.cur.ymax);
+ bwin_clear_viewmat(sa->win); /* clear buttons view */
+ glLoadIdentity();
+
+ /* always free, blocks here have no unique identifier (1 block per node) */
+ uiFreeBlocksWin(&sa->uiblocks, sa->win);
+
+ /* only set once */
+ glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
+ glEnable(GL_MAP1_VERTEX_3);
+
+ /* aspect+font, set each time */
+ snode->aspect= (snode->v2d.cur.xmax - snode->v2d.cur.xmin)/((float)sa->winx);
+ snode->curfont= uiSetCurFont_ext(snode->aspect);
+
+ /* backdrop */
+ draw_nodespace_back(sa, snode);
+
+ /* nodes */
+ snode_set_context(snode);
+
+ if(snode->nodetree) {
+ bNode *node;
+
+ /* for now, we set drawing coordinates on each redraw */
+ for(node= snode->nodetree->nodes.first; node; node= node->next) {
+ if(node->flag & NODE_GROUP_EDIT)
+ node_update_group(node);
+ else if(node->flag & NODE_HIDDEN)
+ node_update_hidden(node);
+ else
+ node_update(node);
+ }
+
+ node_draw_nodetree(sa, snode, snode->nodetree);
+
+ /* active group */
+ for(node= snode->nodetree->nodes.first; node; node= node->next) {
+ if(node->flag & NODE_GROUP_EDIT)
+ node_draw_group(sa, snode, node);
+ }
+ }
+
+ /* restore viewport (not needed yet) */
+ mywinset(sa->win);
+
+ /* ortho at pixel level curarea */
+ myortho2(-0.375, sa->winx-0.375, -0.375, sa->winy-0.375);
+
+ draw_area_emboss(sa);
+ curarea->win_swap= WIN_BACK_OK;
+
+ /* in the end, this is a delayed previewrender test, to allow buttons to be first */
+ if(snode->flag & SNODE_DO_PREVIEW) {
+ addafterqueue(sa->win, RENDERPREVIEW, 1);
+ snode->flag &= ~SNODE_DO_PREVIEW;
+ }
+}
diff --git a/source/blender/src/drawobject.c b/source/blender/src/drawobject.c
new file mode 100644
index 00000000000..f7fcb54297b
--- /dev/null
+++ b/source/blender/src/drawobject.c
@@ -0,0 +1,4645 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <string.h>
+#include <math.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "BMF_Api.h"
+
+#include "IMB_imbuf.h"
+
+
+#include "MTC_matrixops.h"
+
+#include "DNA_armature_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_constraint_types.h" // for drawing constraint
+#include "DNA_effect_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_object_force.h"
+#include "DNA_space_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_world_types.h"
+// FSPARTICLE
+#include "DNA_object_fluidsim.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_editVert.h"
+#include "BLI_edgehash.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_curve.h"
+#include "BKE_constraint.h" // for the get_constraint_target function
+#include "BKE_DerivedMesh.h"
+#include "BKE_displist.h"
+#include "BKE_effect.h"
+#include "BKE_font.h"
+#include "BKE_global.h"
+#include "BKE_image.h"
+#include "BKE_ipo.h"
+#include "BKE_key.h"
+#include "BKE_lattice.h"
+#include "BKE_mesh.h"
+#include "BKE_material.h"
+#include "BKE_mball.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+#include "BKE_anim.h" //for the where_on_path function
+#ifdef WITH_VERSE
+#include "BKE_verse.h"
+#endif
+
+#include "BIF_editarmature.h"
+#include "BIF_editdeform.h"
+#include "BIF_editmesh.h"
+#include "BIF_glutil.h"
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+#include "BIF_mywindow.h"
+#include "BIF_resources.h"
+#include "BIF_retopo.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+
+#include "BDR_drawmesh.h"
+#include "BDR_drawobject.h"
+#include "BDR_editobject.h"
+#include "BDR_sculptmode.h"
+#include "BDR_vpaint.h"
+
+#include "BSE_drawview.h"
+#include "BSE_node.h"
+#include "BSE_trans_types.h"
+#include "BSE_view.h"
+
+#include "blendef.h"
+#include "mydevice.h"
+#include "nla.h"
+
+#include "BKE_deform.h"
+
+/* pretty stupid */
+/* extern Lattice *editLatt; already in BKE_lattice.h */
+/* editcurve.c */
+extern ListBase editNurb;
+/* editmball.c */
+extern ListBase editelems;
+
+static void draw_bounding_volume(Object *ob);
+
+static void drawcube_size(float size);
+static void drawcircle_size(float size);
+
+/* ************* Setting OpenGL Material ************ */
+
+// Materials start counting at # one....
+#define MAXMATBUF (MAXMAT + 1)
+static float matbuf[MAXMATBUF][2][4];
+static int totmat_gl= 0;
+
+int set_gl_material(int nr)
+{
+ static int last_gl_matnr= -1;
+ static int last_ret_val= 1;
+
+ /* prevent index to use un-initialized array items */
+ if(nr>totmat_gl) nr= totmat_gl;
+
+ if(nr<0) {
+ last_gl_matnr= -1;
+ last_ret_val= 1;
+ }
+ else if(nr<MAXMATBUF && nr!=last_gl_matnr) {
+ glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, matbuf[nr][0]);
+ glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, matbuf[nr][1]);
+ last_gl_matnr = nr;
+ last_ret_val= matbuf[nr][0][3]!=0.0;
+
+ /* matbuf alpha: 0.0 = skip draw, 1.0 = no blending, else blend */
+ if(matbuf[nr][0][3]!= 0.0 && matbuf[nr][0][3]!= 1.0) {
+ glEnable(GL_BLEND);
+ }
+ else
+ glDisable(GL_BLEND);
+
+ }
+
+ return last_ret_val;
+}
+
+/* returns 1: when there's alpha needed to be drawn in a 2nd pass */
+int init_gl_materials(Object *ob, int check_alpha)
+{
+ extern Material defmaterial; // render module abuse...
+ Material *ma;
+ int a, has_alpha= 0;
+
+ if(ob->totcol==0) {
+ matbuf[0][0][0]= defmaterial.r;
+ matbuf[0][0][1]= defmaterial.g;
+ matbuf[0][0][2]= defmaterial.b;
+ matbuf[0][0][3]= 1.0;
+
+ matbuf[0][1][0]= defmaterial.specr;
+ matbuf[0][1][1]= defmaterial.specg;
+ matbuf[0][1][2]= defmaterial.specb;
+ matbuf[0][1][3]= 1.0;
+
+ /* do material 1 too, for displists! */
+ QUATCOPY(matbuf[1][0], matbuf[0][0]);
+ QUATCOPY(matbuf[1][1], matbuf[0][1]);
+ }
+
+ for(a=1; a<=ob->totcol; a++) {
+ ma= give_current_material(ob, a);
+ ma= editnode_get_active_material(ma);
+ if(ma==NULL) ma= &defmaterial;
+
+ if(a<MAXMATBUF) {
+ if (ma->mode & MA_SHLESS) {
+ matbuf[a][0][0]= 2*ma->r;
+ matbuf[a][0][1]= 2*ma->g;
+ matbuf[a][0][2]= 2*ma->b;
+ } else {
+ matbuf[a][0][0]= (ma->ref+ma->emit)*ma->r;
+ matbuf[a][0][1]= (ma->ref+ma->emit)*ma->g;
+ matbuf[a][0][2]= (ma->ref+ma->emit)*ma->b;
+ }
+
+ /* draw transparent, not in pick-select, nor editmode */
+ if(check_alpha && !(G.f & G_PICKSEL) && (ob->dtx & OB_DRAWTRANSP) && !(G.obedit && G.obedit->data==ob->data)) {
+ if(G.vd->transp) { // drawing the transparent pass
+ if(ma->alpha==1.0) matbuf[a][0][3]= 0.0; // means skip solid
+ else matbuf[a][0][3]= ma->alpha;
+ }
+ else { // normal pass
+ if(ma->alpha==1.0) matbuf[a][0][3]= 1.0;
+ else {
+ matbuf[a][0][3]= 0.0; // means skip transparent
+ has_alpha= 1; // return value, to indicate adding to after-draw queue
+ }
+ }
+ }
+ else
+ matbuf[a][0][3]= 1.0;
+
+ if (!(ma->mode & MA_SHLESS)) {
+ matbuf[a][1][0]= ma->spec*ma->specr;
+ matbuf[a][1][1]= ma->spec*ma->specg;
+ matbuf[a][1][2]= ma->spec*ma->specb;
+ matbuf[a][1][3]= 1.0;
+ }
+ }
+ }
+
+ totmat_gl= ob->totcol;
+ set_gl_material(-1); // signal for static variable
+ return has_alpha;
+}
+
+
+ /***/
+static unsigned int colortab[24]=
+ {0x0, 0xFF88FF, 0xFFBBFF,
+ 0x403000, 0xFFFF88, 0xFFFFBB,
+ 0x104040, 0x66CCCC, 0x77CCCC,
+ 0x104010, 0x55BB55, 0x66FF66,
+ 0xFFFFFF
+};
+
+
+static float cube[8][3] = {
+ {-1.0, -1.0, -1.0},
+ {-1.0, -1.0, 1.0},
+ {-1.0, 1.0, 1.0},
+ {-1.0, 1.0, -1.0},
+ { 1.0, -1.0, -1.0},
+ { 1.0, -1.0, 1.0},
+ { 1.0, 1.0, 1.0},
+ { 1.0, 1.0, -1.0},
+};
+
+/* ----------------- OpenGL Circle Drawing - Tables for Optimised Drawing Speed ------------------ */
+/* 32 values of sin function (still same result!) */
+static float sinval[32] = {
+ 0.00000000,
+ 0.20129852,
+ 0.39435585,
+ 0.57126821,
+ 0.72479278,
+ 0.84864425,
+ 0.93775213,
+ 0.98846832,
+ 0.99871650,
+ 0.96807711,
+ 0.89780453,
+ 0.79077573,
+ 0.65137248,
+ 0.48530196,
+ 0.29936312,
+ 0.10116832,
+ -0.10116832,
+ -0.29936312,
+ -0.48530196,
+ -0.65137248,
+ -0.79077573,
+ -0.89780453,
+ -0.96807711,
+ -0.99871650,
+ -0.98846832,
+ -0.93775213,
+ -0.84864425,
+ -0.72479278,
+ -0.57126821,
+ -0.39435585,
+ -0.20129852,
+ 0.00000000
+};
+
+/* 32 values of cos function (still same result!) */
+static float cosval[32] ={
+ 1.00000000,
+ 0.97952994,
+ 0.91895781,
+ 0.82076344,
+ 0.68896691,
+ 0.52896401,
+ 0.34730525,
+ 0.15142777,
+ -0.05064916,
+ -0.25065253,
+ -0.44039415,
+ -0.61210598,
+ -0.75875812,
+ -0.87434661,
+ -0.95413925,
+ -0.99486932,
+ -0.99486932,
+ -0.95413925,
+ -0.87434661,
+ -0.75875812,
+ -0.61210598,
+ -0.44039415,
+ -0.25065253,
+ -0.05064916,
+ 0.15142777,
+ 0.34730525,
+ 0.52896401,
+ 0.68896691,
+ 0.82076344,
+ 0.91895781,
+ 0.97952994,
+ 1.00000000
+};
+
+/* flag is same as for draw_object */
+void drawaxes(float size, int flag, char drawtype)
+{
+ int axis;
+ float v1[3]= {0.0, 0.0, 0.0};
+ float v2[3]= {0.0, 0.0, 0.0};
+ float v3[3]= {0.0, 0.0, 0.0};
+
+ switch(drawtype) {
+
+ case OB_PLAINAXES:
+ for (axis=0; axis<3; axis++) {
+ float v1[3]= {0.0, 0.0, 0.0};
+ float v2[3]= {0.0, 0.0, 0.0};
+
+ glBegin(GL_LINES);
+
+ v1[axis]= size;
+ v2[axis]= -size;
+ glVertex3fv(v1);
+ glVertex3fv(v2);
+
+ glEnd();
+ }
+ break;
+ case OB_SINGLE_ARROW:
+
+ glBegin(GL_LINES);
+ /* in positive z direction only */
+ v1[2]= size;
+ glVertex3fv(v1);
+ glVertex3fv(v2);
+ glEnd();
+
+ /* square pyramid */
+ glBegin(GL_TRIANGLES);
+
+ v2[0]= size*0.035; v2[1] = size*0.035;
+ v3[0]= size*-0.035; v3[1] = size*0.035;
+ v2[2]= v3[2]= size*0.75;
+
+ for (axis=0; axis<4; axis++) {
+ if (axis % 2 == 1) {
+ v2[0] *= -1;
+ v3[1] *= -1;
+ } else {
+ v2[1] *= -1;
+ v3[0] *= -1;
+ }
+
+ glVertex3fv(v1);
+ glVertex3fv(v2);
+ glVertex3fv(v3);
+
+ }
+ glEnd();
+
+ break;
+ case OB_CUBE:
+ drawcube_size(size);
+ break;
+
+ case OB_CIRCLE:
+ drawcircle_size(size);
+ break;
+
+ case OB_ARROWS:
+ default:
+ for (axis=0; axis<3; axis++) {
+ float v1[3]= {0.0, 0.0, 0.0};
+ float v2[3]= {0.0, 0.0, 0.0};
+ int arrow_axis= (axis==0)?1:0;
+
+ glBegin(GL_LINES);
+
+ v2[axis]= size;
+ glVertex3fv(v1);
+ glVertex3fv(v2);
+
+ v1[axis]= size*0.8;
+ v1[arrow_axis]= -size*0.125;
+ glVertex3fv(v1);
+ glVertex3fv(v2);
+
+ v1[arrow_axis]= size*0.125;
+ glVertex3fv(v1);
+ glVertex3fv(v2);
+
+ glEnd();
+
+ v2[axis]+= size*0.125;
+ glRasterPos3fv(v2);
+
+ // patch for 3d cards crashing on glSelect for text drawing (IBM)
+ if((flag & DRAW_PICKING) == 0) {
+ if (axis==0)
+ BMF_DrawString(G.font, "x");
+ else if (axis==1)
+ BMF_DrawString(G.font, "y");
+ else
+ BMF_DrawString(G.font, "z");
+ }
+ }
+ break;
+ }
+}
+
+/* circle for object centers, special_color is for library or ob users */
+static void drawcentercircle(float *vec, int selstate, int special_color)
+{
+ View3D *v3d= G.vd;
+ float size;
+
+ size= v3d->persmat[0][3]*vec[0]+ v3d->persmat[1][3]*vec[1]+ v3d->persmat[2][3]*vec[2]+ v3d->persmat[3][3];
+ size*= v3d->pixsize*((float)U.obcenter_dia*0.5f);
+
+ /* using gldepthfunc guarantees that it does write z values, but not checks for it, so centers remain visible independt order of drawing */
+ if(v3d->zbuf) glDepthFunc(GL_ALWAYS);
+ glEnable(GL_BLEND);
+
+ if(special_color) {
+#ifdef WITH_VERSE
+ if (selstate==VERSE) glColor4ub(0x00, 0xFF, 0x00, 155);
+ else if (selstate==ACTIVE || selstate==SELECT) glColor4ub(0x88, 0xFF, 0xFF, 155);
+#else
+ if (selstate==ACTIVE || selstate==SELECT) glColor4ub(0x88, 0xFF, 0xFF, 155);
+#endif
+
+ else glColor4ub(0x55, 0xCC, 0xCC, 155);
+ }
+ else {
+ if (selstate == ACTIVE) BIF_ThemeColorShadeAlpha(TH_ACTIVE, 0, -80);
+ else if (selstate == SELECT) BIF_ThemeColorShadeAlpha(TH_SELECT, 0, -80);
+ else if (selstate == DESELECT) BIF_ThemeColorShadeAlpha(TH_TRANSFORM, 0, -80);
+ }
+ drawcircball(GL_POLYGON, vec, size, v3d->viewinv);
+
+ BIF_ThemeColorShadeAlpha(TH_WIRE, 0, -30);
+ drawcircball(GL_LINE_LOOP, vec, size, v3d->viewinv);
+
+ glDisable(GL_BLEND);
+ if(v3d->zbuf) glDepthFunc(GL_LEQUAL);
+}
+
+
+void drawsolidcube(float size)
+{
+ float n[3];
+
+ glPushMatrix();
+ glScalef(size, size, size);
+
+ n[0]=0; n[1]=0; n[2]=0;
+ glBegin(GL_QUADS);
+ n[0]= -1.0;
+ glNormal3fv(n);
+ glVertex3fv(cube[0]); glVertex3fv(cube[1]); glVertex3fv(cube[2]); glVertex3fv(cube[3]);
+ n[0]=0;
+ glEnd();
+
+ glBegin(GL_QUADS);
+ n[1]= -1.0;
+ glNormal3fv(n);
+ glVertex3fv(cube[0]); glVertex3fv(cube[4]); glVertex3fv(cube[5]); glVertex3fv(cube[1]);
+ n[1]=0;
+ glEnd();
+
+ glBegin(GL_QUADS);
+ n[0]= 1.0;
+ glNormal3fv(n);
+ glVertex3fv(cube[4]); glVertex3fv(cube[7]); glVertex3fv(cube[6]); glVertex3fv(cube[5]);
+ n[0]=0;
+ glEnd();
+
+ glBegin(GL_QUADS);
+ n[1]= 1.0;
+ glNormal3fv(n);
+ glVertex3fv(cube[7]); glVertex3fv(cube[3]); glVertex3fv(cube[2]); glVertex3fv(cube[6]);
+ n[1]=0;
+ glEnd();
+
+ glBegin(GL_QUADS);
+ n[2]= 1.0;
+ glNormal3fv(n);
+ glVertex3fv(cube[1]); glVertex3fv(cube[5]); glVertex3fv(cube[6]); glVertex3fv(cube[2]);
+ n[2]=0;
+ glEnd();
+
+ glBegin(GL_QUADS);
+ n[2]= -1.0;
+ glNormal3fv(n);
+ glVertex3fv(cube[7]); glVertex3fv(cube[4]); glVertex3fv(cube[0]); glVertex3fv(cube[3]);
+ glEnd();
+
+ glPopMatrix();
+}
+
+static void drawcube(void)
+{
+
+ glBegin(GL_LINE_STRIP);
+ glVertex3fv(cube[0]); glVertex3fv(cube[1]);glVertex3fv(cube[2]); glVertex3fv(cube[3]);
+ glVertex3fv(cube[0]); glVertex3fv(cube[4]);glVertex3fv(cube[5]); glVertex3fv(cube[6]);
+ glVertex3fv(cube[7]); glVertex3fv(cube[4]);
+ glEnd();
+
+ glBegin(GL_LINE_STRIP);
+ glVertex3fv(cube[1]); glVertex3fv(cube[5]);
+ glEnd();
+
+ glBegin(GL_LINE_STRIP);
+ glVertex3fv(cube[2]); glVertex3fv(cube[6]);
+ glEnd();
+
+ glBegin(GL_LINE_STRIP);
+ glVertex3fv(cube[3]); glVertex3fv(cube[7]);
+ glEnd();
+}
+
+/* draws a cube on given the scaling of the cube, assuming that
+ * all required matrices have been set (used for drawing empties)
+ */
+static void drawcube_size(float size)
+{
+ glBegin(GL_LINE_STRIP);
+ glVertex3f(-size,-size,-size); glVertex3f(-size,-size,size);glVertex3f(-size,size,size); glVertex3f(-size,size,-size);
+ glVertex3f(-size,-size,-size); glVertex3f(size,-size,-size);glVertex3f(size,-size,size); glVertex3f(size,size,size);
+ glVertex3f(size,size,-size); glVertex3f(size,-size,-size);
+ glEnd();
+
+ glBegin(GL_LINE_STRIP);
+ glVertex3f(-size,-size,size); glVertex3f(size,-size,size);
+ glEnd();
+
+ glBegin(GL_LINE_STRIP);
+ glVertex3f(-size,size,size); glVertex3f(size,size,size);
+ glEnd();
+
+ glBegin(GL_LINE_STRIP);
+ glVertex3f(-size,size,-size); glVertex3f(size,size,-size);
+ glEnd();
+}
+
+/* this is an unused (old) cube-drawing function based on a given size */
+#if 0
+static void drawcube_size(float *size)
+{
+
+ glPushMatrix();
+ glScalef(size[0], size[1], size[2]);
+
+
+ glBegin(GL_LINE_STRIP);
+ glVertex3fv(cube[0]); glVertex3fv(cube[1]);glVertex3fv(cube[2]); glVertex3fv(cube[3]);
+ glVertex3fv(cube[0]); glVertex3fv(cube[4]);glVertex3fv(cube[5]); glVertex3fv(cube[6]);
+ glVertex3fv(cube[7]); glVertex3fv(cube[4]);
+ glEnd();
+
+ glBegin(GL_LINE_STRIP);
+ glVertex3fv(cube[1]); glVertex3fv(cube[5]);
+ glEnd();
+
+ glBegin(GL_LINE_STRIP);
+ glVertex3fv(cube[2]); glVertex3fv(cube[6]);
+ glEnd();
+
+ glBegin(GL_LINE_STRIP);
+ glVertex3fv(cube[3]); glVertex3fv(cube[7]);
+ glEnd();
+
+ glPopMatrix();
+}
+#endif
+
+static void drawshadbuflimits(Lamp *la, float mat[][4])
+{
+ float sta[3], end[3], lavec[3];
+
+ lavec[0]= -mat[2][0];
+ lavec[1]= -mat[2][1];
+ lavec[2]= -mat[2][2];
+ Normalize(lavec);
+
+ sta[0]= mat[3][0]+ la->clipsta*lavec[0];
+ sta[1]= mat[3][1]+ la->clipsta*lavec[1];
+ sta[2]= mat[3][2]+ la->clipsta*lavec[2];
+
+ end[0]= mat[3][0]+ la->clipend*lavec[0];
+ end[1]= mat[3][1]+ la->clipend*lavec[1];
+ end[2]= mat[3][2]+ la->clipend*lavec[2];
+
+
+ glBegin(GL_LINE_STRIP);
+ glVertex3fv(sta);
+ glVertex3fv(end);
+ glEnd();
+
+ glPointSize(3.0);
+ bglBegin(GL_POINTS);
+ bglVertex3fv(sta);
+ bglVertex3fv(end);
+ bglEnd();
+ glPointSize(1.0);
+}
+
+
+
+static void spotvolume(float *lvec, float *vvec, float inp)
+{
+ /* camera is at 0,0,0 */
+ float temp[3],plane[3],mat1[3][3],mat2[3][3],mat3[3][3],mat4[3][3],q[4],co,si,angle;
+
+ Normalize(lvec);
+ Normalize(vvec); /* is this the correct vector ? */
+
+ Crossf(temp,vvec,lvec); /* equation for a plane through vvec en lvec */
+ Crossf(plane,lvec,temp); /* a plane perpendicular to this, parrallel with lvec */
+
+ Normalize(plane);
+
+ /* now we've got two equations: one of a cone and one of a plane, but we have
+ three unknowns. We remove one unkown by rotating the plane to z=0 (the plane normal) */
+
+ /* rotate around cross product vector of (0,0,1) and plane normal, dot product degrees */
+ /* according definition, we derive cross product is (plane[1],-plane[0],0), en cos = plane[2]);*/
+
+ /* translating this comment to english didnt really help me understanding the math! :-) (ton) */
+
+ q[1] = plane[1] ;
+ q[2] = -plane[0] ;
+ q[3] = 0 ;
+ Normalize(&q[1]);
+
+ angle = saacos(plane[2])/2.0;
+ co = cos(angle);
+ si = sqrt(1-co*co);
+
+ q[0] = co;
+ q[1] *= si;
+ q[2] *= si;
+ q[3] = 0;
+
+ QuatToMat3(q,mat1);
+
+ /* rotate lamp vector now over acos(inp) degrees */
+
+ vvec[0] = lvec[0] ;
+ vvec[1] = lvec[1] ;
+ vvec[2] = lvec[2] ;
+
+ Mat3One(mat2);
+ co = inp;
+ si = sqrt(1-inp*inp);
+
+ mat2[0][0] = co;
+ mat2[1][0] = -si;
+ mat2[0][1] = si;
+ mat2[1][1] = co;
+ Mat3MulMat3(mat3,mat2,mat1);
+
+ mat2[1][0] = si;
+ mat2[0][1] = -si;
+ Mat3MulMat3(mat4,mat2,mat1);
+ Mat3Transp(mat1);
+
+ Mat3MulMat3(mat2,mat1,mat3);
+ Mat3MulVecfl(mat2,lvec);
+ Mat3MulMat3(mat2,mat1,mat4);
+ Mat3MulVecfl(mat2,vvec);
+
+ return;
+}
+
+static void drawlamp(Object *ob)
+{
+ Lamp *la;
+ View3D *v3d= G.vd;
+ float vec[3], lvec[3], vvec[3], circrad, x,y,z;
+ float pixsize, lampsize;
+ float imat[4][4], curcol[4];
+ char col[4];
+
+ la= ob->data;
+
+ /* we first draw only the screen aligned & fixed scale stuff */
+ glPushMatrix();
+ myloadmatrix(G.vd->viewmat);
+
+ /* lets calculate the scale: */
+ pixsize= v3d->persmat[0][3]*ob->obmat[3][0]+ v3d->persmat[1][3]*ob->obmat[3][1]+ v3d->persmat[2][3]*ob->obmat[3][2]+ v3d->persmat[3][3];
+ pixsize*= v3d->pixsize;
+ lampsize= pixsize*((float)U.obcenter_dia*0.5f);
+
+ /* and view aligned matrix: */
+ Mat4CpyMat4(imat, G.vd->viewinv);
+ Normalize(imat[0]);
+ Normalize(imat[1]);
+
+ /* for AA effects */
+ glGetFloatv(GL_CURRENT_COLOR, curcol);
+ curcol[3]= 0.6;
+ glColor4fv(curcol);
+
+ if(ob->id.us>1) {
+ if (ob==OBACT || (ob->flag & SELECT)) glColor4ub(0x88, 0xFF, 0xFF, 155);
+ else glColor4ub(0x77, 0xCC, 0xCC, 155);
+ }
+
+ /* Inner Circle */
+ VECCOPY(vec, ob->obmat[3]);
+ glEnable(GL_BLEND);
+ drawcircball(GL_LINE_LOOP, vec, lampsize, imat);
+ glDisable(GL_BLEND);
+ drawcircball(GL_POLYGON, vec, lampsize, imat);
+
+ /* restore */
+ if(ob->id.us>1)
+ glColor4fv(curcol);
+
+ /* Outer circle */
+ circrad = 3.0f*lampsize;
+ drawcircball(GL_LINE_LOOP, vec, circrad, imat);
+
+ setlinestyle(3);
+
+ /* draw dashed outer circle if shadow is on. remember some lamps can't have certain shadows! */
+ if (la->type!=LA_HEMI) {
+ if ((la->mode & LA_SHAD_RAY) ||
+ ((la->mode & LA_SHAD_BUF) && (la->type==LA_SPOT)) )
+ {
+ drawcircball(GL_LINE_LOOP, vec, circrad + 3.0f*pixsize, imat);
+ }
+ }
+
+ /* draw the pretty sun rays */
+ if(la->type==LA_SUN) {
+ float v1[3], v2[3], mat[3][3];
+ short axis;
+
+ /* setup a 45 degree rotation matrix */
+ VecRotToMat3(imat[2], M_PI/4.0f, mat);
+
+ /* vectors */
+ VECCOPY(v1, imat[0]);
+ VecMulf(v1, circrad*1.2f);
+ VECCOPY(v2, imat[0]);
+ VecMulf(v2, circrad*2.5f);
+
+ /* center */
+ glTranslatef(vec[0], vec[1], vec[2]);
+
+ setlinestyle(3);
+
+ glBegin(GL_LINES);
+ for (axis=0; axis<8; axis++) {
+ glVertex3fv(v1);
+ glVertex3fv(v2);
+ Mat3MulVecfl(mat, v1);
+ Mat3MulVecfl(mat, v2);
+ }
+ glEnd();
+
+ glTranslatef(-vec[0], -vec[1], -vec[2]);
+
+ }
+
+ if (la->type==LA_LOCAL) {
+ if(la->mode & LA_SPHERE) {
+ drawcircball(GL_LINE_LOOP, vec, la->dist, imat);
+ }
+ /* yafray: for photonlight also draw lightcone as for spot */
+ }
+
+ glPopMatrix(); /* back in object space */
+ vec[0]= vec[1]= vec[2]= 0.0f;
+
+ if ((la->type==LA_SPOT) || (la->type==LA_YF_PHOTON)) {
+ lvec[0]=lvec[1]= 0.0;
+ lvec[2] = 1.0;
+ x = G.vd->persmat[0][2];
+ y = G.vd->persmat[1][2];
+ z = G.vd->persmat[2][2];
+ vvec[0]= x*ob->obmat[0][0] + y*ob->obmat[0][1] + z*ob->obmat[0][2];
+ vvec[1]= x*ob->obmat[1][0] + y*ob->obmat[1][1] + z*ob->obmat[1][2];
+ vvec[2]= x*ob->obmat[2][0] + y*ob->obmat[2][1] + z*ob->obmat[2][2];
+
+ y = cos( M_PI*la->spotsize/360.0 );
+ spotvolume(lvec, vvec, y);
+ x = -la->dist;
+ lvec[0] *= x ;
+ lvec[1] *= x ;
+ lvec[2] *= x;
+ vvec[0] *= x ;
+ vvec[1] *= x ;
+ vvec[2] *= x;
+
+ /* draw the angled sides of the cone */
+ glBegin(GL_LINE_STRIP);
+ glVertex3fv(vvec);
+ glVertex3fv(vec);
+ glVertex3fv(lvec);
+ glEnd();
+
+ z = x*sqrt(1.0 - y*y);
+ x *= y;
+
+ /* draw the circle/square at the end of the cone */
+ glTranslatef(0.0, 0.0 , x);
+ if(la->mode & LA_SQUARE) {
+ vvec[0]= fabs(z);
+ vvec[1]= fabs(z);
+ vvec[2]= 0.0;
+ glBegin(GL_LINE_LOOP);
+ glVertex3fv(vvec);
+ vvec[1]= -fabs(z);
+ glVertex3fv(vvec);
+ vvec[0]= -fabs(z);
+ glVertex3fv(vvec);
+ vvec[1]= fabs(z);
+ glVertex3fv(vvec);
+ glEnd();
+ }
+ else circ(0.0, 0.0, fabs(z));
+
+ /* draw the circle/square representing spotbl */
+ if(la->type==LA_SPOT) {
+ float spotblcirc = fabs(z)*(1 - pow(la->spotblend, 2));
+ /* make sure the line is always visible - prevent it from reaching the outer border (or 0)
+ * values are kinda arbitrary - just what seemed to work well */
+ if (spotblcirc == 0) spotblcirc = 0.15;
+ else if (spotblcirc == fabs(z)) spotblcirc = fabs(z) - 0.07;
+ circ(0.0, 0.0, spotblcirc);
+ }
+
+ }
+ else if ELEM(la->type, LA_HEMI, LA_SUN) {
+
+ /* draw the line from the circle along the dist */
+ glBegin(GL_LINE_STRIP);
+ vec[2] = -circrad;
+ glVertex3fv(vec);
+ vec[2]= -la->dist;
+ glVertex3fv(vec);
+ glEnd();
+
+ if(la->type==LA_HEMI) {
+ /* draw the hemisphere curves */
+ short axis, steps, dir;
+ float outdist, zdist, mul;
+ vec[0]=vec[1]=vec[2]= 0.0;
+ outdist = 0.14; mul = 1.4; dir = 1;
+
+ setlinestyle(4);
+ /* loop over the 4 compass points, and draw each arc as a LINE_STRIP */
+ for (axis=0; axis<4; axis++) {
+ float v[3]= {0.0, 0.0, 0.0};
+ zdist = 0.02;
+
+ glBegin(GL_LINE_STRIP);
+
+ for (steps=0; steps<6; steps++) {
+ if (axis == 0 || axis == 1) { /* x axis up, x axis down */
+ /* make the arcs start at the edge of the energy circle */
+ if (steps == 0) v[0] = dir*circrad;
+ else v[0] = v[0] + dir*(steps*outdist);
+ } else if (axis == 2 || axis == 3) { /* y axis up, y axis down */
+ /* make the arcs start at the edge of the energy circle */
+ if (steps == 0) v[1] = dir*circrad;
+ else v[1] = v[1] + dir*(steps*outdist);
+ }
+
+ v[2] = v[2] - steps*zdist;
+
+ glVertex3fv(v);
+
+ zdist = zdist * mul;
+ }
+
+ glEnd();
+ /* flip the direction */
+ dir = -dir;
+ }
+ }
+ } else if(la->type==LA_AREA) {
+ setlinestyle(3);
+ if(la->area_shape==LA_AREA_SQUARE)
+ fdrawbox(-la->area_size*0.5, -la->area_size*0.5, la->area_size*0.5, la->area_size*0.5);
+ else if(la->area_shape==LA_AREA_RECT)
+ fdrawbox(-la->area_size*0.5, -la->area_sizey*0.5, la->area_size*0.5, la->area_sizey*0.5);
+
+ glBegin(GL_LINE_STRIP);
+ glVertex3f(0.0,0.0,-circrad);
+ glVertex3f(0.0,0.0,-la->dist);
+ glEnd();
+ }
+
+ /* and back to viewspace */
+ myloadmatrix(G.vd->viewmat);
+ VECCOPY(vec, ob->obmat[3]);
+
+ setlinestyle(0);
+
+ if(la->type==LA_SPOT && (la->mode & LA_SHAD_BUF) ) {
+ drawshadbuflimits(la, ob->obmat);
+ }
+
+ BIF_GetThemeColor4ubv(TH_LAMP, col);
+ glColor4ub(col[0], col[1], col[2], col[3]);
+
+ glEnable(GL_BLEND);
+
+ if (vec[2]>0) vec[2] -= circrad;
+ else vec[2] += circrad;
+
+ glBegin(GL_LINE_STRIP);
+ glVertex3fv(vec);
+ vec[2]= 0;
+ glVertex3fv(vec);
+ glEnd();
+
+ glPointSize(2.0);
+ glBegin(GL_POINTS);
+ glVertex3fv(vec);
+ glEnd();
+ glPointSize(1.0);
+
+ glDisable(GL_BLEND);
+
+ /* restore for drawing extra stuff */
+ glColor3fv(curcol);
+
+}
+
+static void draw_limit_line(float sta, float end, unsigned int col)
+{
+ glBegin(GL_LINES);
+ glVertex3f(0.0, 0.0, -sta);
+ glVertex3f(0.0, 0.0, -end);
+ glEnd();
+
+ glPointSize(3.0);
+ glBegin(GL_POINTS);
+ cpack(col);
+ glVertex3f(0.0, 0.0, -sta);
+ glVertex3f(0.0, 0.0, -end);
+ glEnd();
+ glPointSize(1.0);
+}
+
+
+/* yafray: draw camera focus point (cross, similar to aqsis code in tuhopuu) */
+/* qdn: now also enabled for Blender to set focus point for defocus composit node */
+static void draw_focus_cross(float dist, float size)
+{
+ glBegin(GL_LINES);
+ glVertex3f(-size, 0.f, -dist);
+ glVertex3f(size, 0.f, -dist);
+ glVertex3f(0.f, -size, -dist);
+ glVertex3f(0.f, size, -dist);
+ glEnd();
+}
+
+/* flag similar to draw_object() */
+static void drawcamera(Object *ob, int flag)
+{
+ /* a standing up pyramid with (0,0,0) as top */
+ Camera *cam;
+ World *wrld;
+ float vec[8][4], tmat[4][4], fac, facx, facy, depth;
+ int i;
+
+ cam= ob->data;
+
+ glDisable(GL_LIGHTING);
+ glDisable(GL_CULL_FACE);
+
+ if(G.vd->persp>=2 && cam->type==CAM_ORTHO && ob==G.vd->camera) {
+ facx= 0.5*cam->ortho_scale*1.28;
+ facy= 0.5*cam->ortho_scale*1.024;
+ depth= -cam->clipsta-0.1;
+ }
+ else {
+ fac= cam->drawsize;
+ if(G.vd->persp>=2 && ob==G.vd->camera) fac= cam->clipsta+0.1; /* that way it's always visible */
+
+ depth= - fac*cam->lens/16.0;
+ facx= fac*1.28;
+ facy= fac*1.024;
+ }
+
+ vec[0][0]= 0.0; vec[0][1]= 0.0; vec[0][2]= 0.001; /* GLBUG: for picking at iris Entry (well thats old!) */
+ vec[1][0]= facx; vec[1][1]= facy; vec[1][2]= depth;
+ vec[2][0]= facx; vec[2][1]= -facy; vec[2][2]= depth;
+ vec[3][0]= -facx; vec[3][1]= -facy; vec[3][2]= depth;
+ vec[4][0]= -facx; vec[4][1]= facy; vec[4][2]= depth;
+
+ glBegin(GL_LINE_LOOP);
+ glVertex3fv(vec[1]);
+ glVertex3fv(vec[2]);
+ glVertex3fv(vec[3]);
+ glVertex3fv(vec[4]);
+ glEnd();
+
+
+ if(G.vd->persp>=2 && ob==G.vd->camera) return;
+
+ glBegin(GL_LINE_STRIP);
+ glVertex3fv(vec[2]);
+ glVertex3fv(vec[0]);
+ glVertex3fv(vec[1]);
+ glVertex3fv(vec[4]);
+ glVertex3fv(vec[0]);
+ glVertex3fv(vec[3]);
+ glEnd();
+
+
+ /* arrow on top */
+ vec[0][2]= depth;
+
+
+ /* draw an outline arrow for inactive cameras and filled
+ * for active cameras. We actually draw both outline+filled
+ * for active cameras so the wire can be seen side-on */
+ for (i=0;i<2;i++) {
+ if (i==0) glBegin(GL_LINE_LOOP);
+ else if (i==1 && (ob == G.vd->camera)) glBegin(GL_TRIANGLES);
+ else break;
+
+ vec[0][0]= -0.7*cam->drawsize;
+ vec[0][1]= 1.1*cam->drawsize;
+ glVertex3fv(vec[0]);
+
+ vec[0][0]= 0.0;
+ vec[0][1]= 1.8*cam->drawsize;
+ glVertex3fv(vec[0]);
+
+ vec[0][0]= 0.7*cam->drawsize;
+ vec[0][1]= 1.1*cam->drawsize;
+ glVertex3fv(vec[0]);
+
+ glEnd();
+ }
+
+ if(flag==0) {
+ if(cam->flag & (CAM_SHOWLIMITS+CAM_SHOWMIST)) {
+ myloadmatrix(G.vd->viewmat);
+ Mat4CpyMat4(vec, ob->obmat);
+ Mat4Ortho(vec);
+ mymultmatrix(vec);
+
+ MTC_Mat4SwapMat4(G.vd->persmat, tmat);
+ mygetsingmatrix(G.vd->persmat);
+
+ if(cam->flag & CAM_SHOWLIMITS) {
+ draw_limit_line(cam->clipsta, cam->clipend, 0x77FFFF);
+ /* qdn: was yafray only, now also enabled for Blender to be used with defocus composit node */
+ draw_focus_cross(dof_camera(ob), cam->drawsize);
+ }
+
+ wrld= G.scene->world;
+ if(cam->flag & CAM_SHOWMIST)
+ if(wrld) draw_limit_line(wrld->miststa, wrld->miststa+wrld->mistdist, 0xFFFFFF);
+
+ MTC_Mat4SwapMat4(G.vd->persmat, tmat);
+ }
+ }
+}
+
+static void lattice_draw_verts(Lattice *lt, DispList *dl, short sel)
+{
+ BPoint *bp = lt->def;
+ float *co = dl?dl->verts:NULL;
+ int u, v, w;
+
+ BIF_ThemeColor(sel?TH_VERTEX_SELECT:TH_VERTEX);
+ glPointSize(BIF_GetThemeValuef(TH_VERTEX_SIZE));
+ bglBegin(GL_POINTS);
+
+ for(w=0; w<lt->pntsw; w++) {
+ int wxt = (w==0 || w==lt->pntsw-1);
+ for(v=0; v<lt->pntsv; v++) {
+ int vxt = (v==0 || v==lt->pntsv-1);
+ for(u=0; u<lt->pntsu; u++, bp++, co+=3) {
+ int uxt = (u==0 || u==lt->pntsu-1);
+ if(!(lt->flag & LT_OUTSIDE) || uxt || vxt || wxt) {
+ if(bp->hide==0) {
+ if((bp->f1 & 1)==sel) {
+ bglVertex3fv(dl?co:bp->vec);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ glPointSize(1.0);
+ bglEnd();
+}
+
+void lattice_foreachScreenVert(void (*func)(void *userData, BPoint *bp, int x, int y), void *userData)
+{
+ int i, N = editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
+ DispList *dl = find_displist(&G.obedit->disp, DL_VERTS);
+ float *co = dl?dl->verts:NULL;
+ BPoint *bp = editLatt->def;
+ float pmat[4][4], vmat[4][4];
+ short s[2];
+
+ view3d_get_object_project_mat(curarea, G.obedit, pmat, vmat);
+
+ for (i=0; i<N; i++, bp++, co+=3) {
+ if (bp->hide==0) {
+ view3d_project_short_clip(curarea, dl?co:bp->vec, s, pmat, vmat);
+ func(userData, bp, s[0], s[1]);
+ }
+ }
+}
+
+static void drawlattice__point(Lattice *lt, DispList *dl, int u, int v, int w, int use_wcol)
+{
+ int index = ((w*lt->pntsv + v)*lt->pntsu) + u;
+
+ if(use_wcol) {
+ float col[3];
+ MDeformWeight *mdw= get_defweight (lt->dvert+index, use_wcol-1);
+
+ weight_to_rgb(mdw?mdw->weight:0.0f, col, col+1, col+2);
+ glColor3fv(col);
+ }
+
+ if (dl) {
+ glVertex3fv(&dl->verts[index*3]);
+ } else {
+ glVertex3fv(lt->def[index].vec);
+ }
+}
+
+/* lattice color is hardcoded, now also shows weightgroup values in edit mode */
+static void drawlattice(Object *ob)
+{
+ Lattice *lt;
+ DispList *dl;
+ int u, v, w;
+ int use_wcol= 0;
+
+ lt= (ob==G.obedit)?editLatt:ob->data;
+ dl= find_displist(&ob->disp, DL_VERTS);
+ if(ob==G.obedit) {
+ cpack(0x004000);
+
+ if(ob->defbase.first && lt->dvert) {
+ use_wcol= ob->actdef;
+ glShadeModel(GL_SMOOTH);
+ }
+ }
+
+ glBegin(GL_LINES);
+ for(w=0; w<lt->pntsw; w++) {
+ int wxt = (w==0 || w==lt->pntsw-1);
+ for(v=0; v<lt->pntsv; v++) {
+ int vxt = (v==0 || v==lt->pntsv-1);
+ for(u=0; u<lt->pntsu; u++) {
+ int uxt = (u==0 || u==lt->pntsu-1);
+
+ if(w && ((uxt || vxt) || !(lt->flag & LT_OUTSIDE))) {
+ drawlattice__point(lt, dl, u, v, w-1, use_wcol);
+ drawlattice__point(lt, dl, u, v, w, use_wcol);
+ }
+ if(v && ((uxt || wxt) || !(lt->flag & LT_OUTSIDE))) {
+ drawlattice__point(lt, dl, u, v-1, w, use_wcol);
+ drawlattice__point(lt, dl, u, v, w, use_wcol);
+ }
+ if(u && ((vxt || wxt) || !(lt->flag & LT_OUTSIDE))) {
+ drawlattice__point(lt, dl, u-1, v, w, use_wcol);
+ drawlattice__point(lt, dl, u, v, w, use_wcol);
+ }
+ }
+ }
+ }
+ glEnd();
+
+ /* restoration for weight colors */
+ if(use_wcol)
+ glShadeModel(GL_FLAT);
+
+ if(ob==G.obedit) {
+ if(G.vd->zbuf) glDisable(GL_DEPTH_TEST);
+
+ lattice_draw_verts(lt, dl, 0);
+ lattice_draw_verts(lt, dl, 1);
+
+ if(G.vd->zbuf) glEnable(GL_DEPTH_TEST);
+ }
+}
+
+/* ***************** ******************** */
+
+static void mesh_foreachScreenVert__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s)
+{
+ struct { void (*func)(void *userData, EditVert *eve, int x, int y, int index); void *userData; int clipVerts; float pmat[4][4], vmat[4][4]; } *data = userData;
+ EditVert *eve = EM_get_vert_for_index(index);
+ short s[2];
+
+ if (eve->h==0) {
+ if (data->clipVerts) {
+ view3d_project_short_clip(curarea, co, s, data->pmat, data->vmat);
+ } else {
+ view3d_project_short_noclip(curarea, co, s, data->pmat);
+ }
+
+ data->func(data->userData, eve, s[0], s[1], index);
+ }
+}
+void mesh_foreachScreenVert(void (*func)(void *userData, EditVert *eve, int x, int y, int index), void *userData, int clipVerts)
+{
+ struct { void (*func)(void *userData, EditVert *eve, int x, int y, int index); void *userData; int clipVerts; float pmat[4][4], vmat[4][4]; } data;
+ DerivedMesh *dm = editmesh_get_derived_cage(CD_MASK_BAREMESH);
+
+ data.func = func;
+ data.userData = userData;
+ data.clipVerts = clipVerts;
+
+ view3d_get_object_project_mat(curarea, G.obedit, data.pmat, data.vmat);
+
+ EM_init_index_arrays(1, 0, 0);
+ dm->foreachMappedVert(dm, mesh_foreachScreenVert__mapFunc, &data);
+ EM_free_index_arrays();
+
+ dm->release(dm);
+}
+
+static void mesh_foreachScreenEdge__mapFunc(void *userData, int index, float *v0co, float *v1co)
+{
+ struct { void (*func)(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index); void *userData; int clipVerts; float pmat[4][4], vmat[4][4]; } *data = userData;
+ EditEdge *eed = EM_get_edge_for_index(index);
+ short s[2][2];
+
+ if (eed->h==0) {
+ if (data->clipVerts==1) {
+ view3d_project_short_clip(curarea, v0co, s[0], data->pmat, data->vmat);
+ view3d_project_short_clip(curarea, v1co, s[1], data->pmat, data->vmat);
+ } else {
+ view3d_project_short_noclip(curarea, v0co, s[0], data->pmat);
+ view3d_project_short_noclip(curarea, v1co, s[1], data->pmat);
+
+ if (data->clipVerts==2) {
+ if (!(s[0][0]>=0 && s[0][1]>= 0 && s[0][0]<curarea->winx && s[0][1]<curarea->winy))
+ if (!(s[1][0]>=0 && s[1][1]>= 0 && s[1][0]<curarea->winx && s[1][1]<curarea->winy))
+ return;
+ }
+ }
+
+ data->func(data->userData, eed, s[0][0], s[0][1], s[1][0], s[1][1], index);
+ }
+}
+void mesh_foreachScreenEdge(void (*func)(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index), void *userData, int clipVerts)
+{
+ struct { void (*func)(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index); void *userData; int clipVerts; float pmat[4][4], vmat[4][4]; } data;
+ DerivedMesh *dm = editmesh_get_derived_cage(CD_MASK_BAREMESH);
+
+ data.func = func;
+ data.userData = userData;
+ data.clipVerts = clipVerts;
+
+ view3d_get_object_project_mat(curarea, G.obedit, data.pmat, data.vmat);
+
+ EM_init_index_arrays(0, 1, 0);
+ dm->foreachMappedEdge(dm, mesh_foreachScreenEdge__mapFunc, &data);
+ EM_free_index_arrays();
+
+ dm->release(dm);
+}
+
+static void mesh_foreachScreenFace__mapFunc(void *userData, int index, float *cent, float *no)
+{
+ struct { void (*func)(void *userData, EditFace *efa, int x, int y, int index); void *userData; float pmat[4][4], vmat[4][4]; } *data = userData;
+ EditFace *efa = EM_get_face_for_index(index);
+ short s[2];
+
+ if (efa && efa->h==0 && efa->fgonf!=EM_FGON) {
+ view3d_project_short_clip(curarea, cent, s, data->pmat, data->vmat);
+
+ data->func(data->userData, efa, s[0], s[1], index);
+ }
+}
+void mesh_foreachScreenFace(void (*func)(void *userData, EditFace *efa, int x, int y, int index), void *userData)
+{
+ struct { void (*func)(void *userData, EditFace *efa, int x, int y, int index); void *userData; float pmat[4][4], vmat[4][4]; } data;
+ DerivedMesh *dm = editmesh_get_derived_cage(CD_MASK_BAREMESH);
+
+ data.func = func;
+ data.userData = userData;
+
+ view3d_get_object_project_mat(curarea, G.obedit, data.pmat, data.vmat);
+
+ EM_init_index_arrays(0, 0, 1);
+ dm->foreachMappedFaceCenter(dm, mesh_foreachScreenFace__mapFunc, &data);
+ EM_free_index_arrays();
+
+ dm->release(dm);
+}
+
+void nurbs_foreachScreenVert(void (*func)(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y), void *userData)
+{
+ float pmat[4][4], vmat[4][4];
+ short s[2];
+ Nurb *nu;
+ int i;
+
+ view3d_get_object_project_mat(curarea, G.obedit, pmat, vmat);
+
+ for (nu= editNurb.first; nu; nu=nu->next) {
+ if((nu->type & 7)==CU_BEZIER) {
+ for (i=0; i<nu->pntsu; i++) {
+ BezTriple *bezt = &nu->bezt[i];
+
+ if(bezt->hide==0) {
+ if (G.f & G_HIDDENHANDLES) {
+ view3d_project_short_clip(curarea, bezt->vec[1], s, pmat, vmat);
+ if (s[0] != IS_CLIPPED)
+ func(userData, nu, NULL, bezt, 1, s[0], s[1]);
+ } else {
+ view3d_project_short_clip(curarea, bezt->vec[0], s, pmat, vmat);
+ if (s[0] != IS_CLIPPED)
+ func(userData, nu, NULL, bezt, 0, s[0], s[1]);
+ view3d_project_short_clip(curarea, bezt->vec[1], s, pmat, vmat);
+ if (s[0] != IS_CLIPPED)
+ func(userData, nu, NULL, bezt, 1, s[0], s[1]);
+ view3d_project_short_clip(curarea, bezt->vec[2], s, pmat, vmat);
+ if (s[0] != IS_CLIPPED)
+ func(userData, nu, NULL, bezt, 2, s[0], s[1]);
+ }
+ }
+ }
+ }
+ else {
+ for (i=0; i<nu->pntsu*nu->pntsv; i++) {
+ BPoint *bp = &nu->bp[i];
+
+ if(bp->hide==0) {
+ view3d_project_short_clip(curarea, bp->vec, s, pmat, vmat);
+ func(userData, nu, bp, NULL, -1, s[0], s[1]);
+ }
+ }
+ }
+ }
+}
+
+/* ************** DRAW MESH ****************** */
+
+/* First section is all the "simple" draw routines,
+ * ones that just pass some sort of primitive to GL,
+ * with perhaps various options to control lighting,
+ * color, etc.
+ *
+ * These routines should not have user interface related
+ * logic!!!
+ */
+
+static void draw_dm_face_normals__mapFunc(void *userData, int index, float *cent, float *no)
+{
+ EditFace *efa = EM_get_face_for_index(index);
+
+ if (efa->h==0 && efa->fgonf!=EM_FGON) {
+ glVertex3fv(cent);
+ glVertex3f( cent[0] + no[0]*G.scene->editbutsize,
+ cent[1] + no[1]*G.scene->editbutsize,
+ cent[2] + no[2]*G.scene->editbutsize);
+ }
+}
+static void draw_dm_face_normals(DerivedMesh *dm) {
+ glBegin(GL_LINES);
+ dm->foreachMappedFaceCenter(dm, draw_dm_face_normals__mapFunc, 0);
+ glEnd();
+}
+
+static void draw_dm_face_centers__mapFunc(void *userData, int index, float *cent, float *no)
+{
+ EditFace *efa = EM_get_face_for_index(index);
+ int sel = *((int*) userData);
+
+ if (efa->h==0 && efa->fgonf!=EM_FGON && (efa->f&SELECT)==sel) {
+ bglVertex3fv(cent);
+ }
+}
+static void draw_dm_face_centers(DerivedMesh *dm, int sel)
+{
+ bglBegin(GL_POINTS);
+ dm->foreachMappedFaceCenter(dm, draw_dm_face_centers__mapFunc, &sel);
+ bglEnd();
+}
+
+static void draw_dm_vert_normals__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s)
+{
+ EditVert *eve = EM_get_vert_for_index(index);
+
+ if (eve->h==0) {
+ glVertex3fv(co);
+
+ if (no_f) {
+ glVertex3f( co[0] + no_f[0]*G.scene->editbutsize,
+ co[1] + no_f[1]*G.scene->editbutsize,
+ co[2] + no_f[2]*G.scene->editbutsize);
+ } else {
+ glVertex3f( co[0] + no_s[0]*G.scene->editbutsize/32767.0f,
+ co[1] + no_s[1]*G.scene->editbutsize/32767.0f,
+ co[2] + no_s[2]*G.scene->editbutsize/32767.0f);
+ }
+ }
+}
+static void draw_dm_vert_normals(DerivedMesh *dm) {
+ glBegin(GL_LINES);
+ dm->foreachMappedVert(dm, draw_dm_vert_normals__mapFunc, NULL);
+ glEnd();
+}
+
+ /* Draw verts with color set based on selection */
+static void draw_dm_verts__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s)
+{
+ struct { int sel; EditVert *eve_act; } * data = userData;
+ EditVert *eve = EM_get_vert_for_index(index);
+
+ if (eve->h==0 && (eve->f&SELECT)==data->sel) {
+ /* draw active larger - need to stop/start point drawing for this :/ */
+ if (eve==data->eve_act) {
+ float size = BIF_GetThemeValuef(TH_VERTEX_SIZE);
+ BIF_ThemeColor4(TH_EDITMESH_ACTIVE);
+
+ bglEnd();
+
+ glPointSize(size);
+ bglBegin(GL_POINTS);
+ bglVertex3fv(co);
+ bglEnd();
+
+ BIF_ThemeColor4(TH_VERTEX_SELECT);
+ glPointSize(size);
+ bglBegin(GL_POINTS);
+ } else {
+ bglVertex3fv(co);
+ }
+ }
+}
+static void draw_dm_verts(DerivedMesh *dm, int sel, EditVert *eve_act)
+{
+ struct { int sel; EditVert *eve_act; } data;
+ data.sel = sel;
+ data.eve_act = eve_act;
+
+ bglBegin(GL_POINTS);
+ dm->foreachMappedVert(dm, draw_dm_verts__mapFunc, &data);
+ bglEnd();
+}
+
+ /* Draw edges with color set based on selection */
+static int draw_dm_edges_sel__setDrawOptions(void *userData, int index)
+{
+ EditEdge *eed = EM_get_edge_for_index(index);
+ //unsigned char **cols = userData, *col;
+ struct { unsigned char *baseCol, *selCol, *actCol; EditEdge *eed_act; } * data = userData;
+ unsigned char *col;
+
+ if (eed->h==0) {
+ if (eed==data->eed_act) {
+ glColor4ubv(data->actCol);
+ } else {
+ if (eed->f&SELECT) {
+ col = data->selCol;
+ } else {
+ col = data->baseCol;
+ }
+ /* no alpha, this is used so a transparent color can disable drawing unselected edges in editmode */
+ if (col[3]==0) return 0;
+
+ glColor4ubv(col);
+ }
+ return 1;
+ } else {
+ return 0;
+ }
+}
+static void draw_dm_edges_sel(DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol, unsigned char *actCol, EditEdge *eed_act)
+{
+ struct { unsigned char *baseCol, *selCol, *actCol; EditEdge *eed_act; } data;
+
+ data.baseCol = baseCol;
+ data.selCol = selCol;
+ data.actCol = actCol;
+ data.eed_act = eed_act;
+ dm->drawMappedEdges(dm, draw_dm_edges_sel__setDrawOptions, &data);
+}
+
+ /* Draw edges */
+static int draw_dm_edges__setDrawOptions(void *userData, int index)
+{
+ return EM_get_edge_for_index(index)->h==0;
+}
+static void draw_dm_edges(DerivedMesh *dm)
+{
+ dm->drawMappedEdges(dm, draw_dm_edges__setDrawOptions, NULL);
+}
+
+ /* Draw edges with color interpolated based on selection */
+static int draw_dm_edges_sel_interp__setDrawOptions(void *userData, int index)
+{
+ return EM_get_edge_for_index(index)->h==0;
+}
+static void draw_dm_edges_sel_interp__setDrawInterpOptions(void *userData, int index, float t)
+{
+ EditEdge *eed = EM_get_edge_for_index(index);
+ unsigned char **cols = userData;
+ unsigned char *col0 = cols[(eed->v1->f&SELECT)?1:0];
+ unsigned char *col1 = cols[(eed->v2->f&SELECT)?1:0];
+
+ glColor4ub( col0[0] + (col1[0]-col0[0])*t,
+ col0[1] + (col1[1]-col0[1])*t,
+ col0[2] + (col1[2]-col0[2])*t,
+ col0[3] + (col1[3]-col0[3])*t);
+}
+static void draw_dm_edges_sel_interp(DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol)
+{
+ unsigned char *cols[2];
+ cols[0] = baseCol;
+ cols[1] = selCol;
+ dm->drawMappedEdgesInterp(dm, draw_dm_edges_sel_interp__setDrawOptions, draw_dm_edges_sel_interp__setDrawInterpOptions, cols);
+}
+
+ /* Draw only seam edges */
+static int draw_dm_edges_seams__setDrawOptions(void *userData, int index)
+{
+ EditEdge *eed = EM_get_edge_for_index(index);
+
+ return (eed->h==0 && eed->seam);
+}
+static void draw_dm_edges_seams(DerivedMesh *dm)
+{
+ dm->drawMappedEdges(dm, draw_dm_edges_seams__setDrawOptions, NULL);
+}
+
+ /* Draw only sharp edges */
+static int draw_dm_edges_sharp__setDrawOptions(void *userData, int index)
+{
+ EditEdge *eed = EM_get_edge_for_index(index);
+
+ return (eed->h==0 && eed->sharp);
+}
+static void draw_dm_edges_sharp(DerivedMesh *dm)
+{
+ dm->drawMappedEdges(dm, draw_dm_edges_sharp__setDrawOptions, NULL);
+}
+
+
+ /* Draw faces with color set based on selection
+ * return 2 for the active face so it renders with stipple enabled */
+static int draw_dm_faces_sel__setDrawOptions(void *userData, int index, int *drawSmooth_r)
+{
+ struct { unsigned char *cols[3]; EditFace *efa_act; } * data = userData;
+ EditFace *efa = EM_get_face_for_index(index);
+ unsigned char *col;
+
+ if (efa->h==0) {
+ if (efa == data->efa_act) {
+ glColor4ubv(data->cols[2]);
+ return 2; /* stipple */
+ } else {
+ col = data->cols[(efa->f&SELECT)?1:0];
+ if (col[3]==0) return 0;
+ glColor4ubv(col);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* also draws the active face */
+static void draw_dm_faces_sel(DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol, unsigned char *actCol, EditFace *efa_act)
+{
+ struct { unsigned char *cols[3]; EditFace *efa_act; } data;
+ data.cols[0] = baseCol;
+ data.cols[1] = selCol;
+ data.cols[2] = actCol;
+ data.efa_act = efa_act;
+
+ dm->drawMappedFaces(dm, draw_dm_faces_sel__setDrawOptions, &data, 0);
+}
+
+static int draw_dm_creases__setDrawOptions(void *userData, int index)
+{
+ EditEdge *eed = EM_get_edge_for_index(index);
+
+ if (eed->h==0 && eed->crease!=0.0) {
+ BIF_ThemeColorBlend(TH_WIRE, TH_EDGE_SELECT, eed->crease);
+ return 1;
+ } else {
+ return 0;
+ }
+}
+static void draw_dm_creases(DerivedMesh *dm)
+{
+ glLineWidth(3.0);
+ dm->drawMappedEdges(dm, draw_dm_creases__setDrawOptions, NULL);
+ glLineWidth(1.0);
+}
+
+/* Second section of routines: Combine first sets to form fancy
+ * drawing routines (for example rendering twice to get overlays).
+ *
+ * Also includes routines that are basic drawing but are too
+ * specialized to be split out (like drawing creases or measurements).
+ */
+
+/* EditMesh drawing routines*/
+
+static void draw_em_fancy_verts(EditMesh *em, DerivedMesh *cageDM, EditVert *eve_act)
+{
+ int sel;
+
+ if(G.vd->zbuf) glDepthMask(0); // disable write in zbuffer, zbuf select
+
+ for (sel=0; sel<2; sel++) {
+ char col[4], fcol[4];
+ int pass;
+
+ BIF_GetThemeColor3ubv(sel?TH_VERTEX_SELECT:TH_VERTEX, col);
+ BIF_GetThemeColor3ubv(sel?TH_FACE_DOT:TH_WIRE, fcol);
+
+ for (pass=0; pass<2; pass++) {
+ float size = BIF_GetThemeValuef(TH_VERTEX_SIZE);
+ float fsize = BIF_GetThemeValuef(TH_FACEDOT_SIZE);
+
+ if (pass==0) {
+ if(G.vd->zbuf && !(G.vd->flag&V3D_ZBUF_SELECT)) {
+ glDisable(GL_DEPTH_TEST);
+
+ glEnable(GL_BLEND);
+ } else {
+ continue;
+ }
+
+ size = (size>2.1?size/2.0:size);
+ fsize = (fsize>2.1?fsize/2.0:fsize);
+ col[3] = fcol[3] = 100;
+ } else {
+ col[3] = fcol[3] = 255;
+ }
+
+ if(G.scene->selectmode & SCE_SELECT_VERTEX) {
+ glPointSize(size);
+ glColor4ubv((GLubyte *)col);
+ draw_dm_verts(cageDM, sel, eve_act);
+ }
+
+ if( (G.scene->selectmode & SCE_SELECT_FACE) &&
+ (G.vd->drawtype<=OB_SOLID)
+ ) {
+ glPointSize(fsize);
+ glColor4ubv((GLubyte *)fcol);
+ draw_dm_face_centers(cageDM, sel);
+ }
+
+ if (pass==0) {
+ glDisable(GL_BLEND);
+ glEnable(GL_DEPTH_TEST);
+ }
+ }
+ }
+
+ if(G.vd->zbuf) glDepthMask(1);
+ glPointSize(1.0);
+}
+
+static void draw_em_fancy_edges(DerivedMesh *cageDM, short sel_only, EditEdge *eed_act)
+{
+ int pass;
+ unsigned char wireCol[4], selCol[4], actCol[4];
+
+ /* since this function does transparant... */
+ BIF_GetThemeColor3ubv(TH_EDGE_SELECT, (char *)selCol);
+ BIF_GetThemeColor3ubv(TH_WIRE, (char *)wireCol);
+ BIF_GetThemeColor3ubv(TH_EDITMESH_ACTIVE, (char *)actCol);
+
+ /* when sel only is used, dont render wire, only selected, this is used for
+ * textured draw mode when the 'edges' option is disabled */
+ if (sel_only)
+ wireCol[3] = 0;
+
+ for (pass=0; pass<2; pass++) {
+ /* show wires in transparant when no zbuf clipping for select */
+ if (pass==0) {
+ if (G.vd->zbuf && (G.vd->flag & V3D_ZBUF_SELECT)==0) {
+ glEnable(GL_BLEND);
+ glDisable(GL_DEPTH_TEST);
+ selCol[3] = 85;
+ if (!sel_only) wireCol[3] = 85;
+ } else {
+ continue;
+ }
+ } else {
+ selCol[3] = 255;
+ if (!sel_only) wireCol[3] = 255;
+ }
+
+ if(G.scene->selectmode == SCE_SELECT_FACE) {
+ draw_dm_edges_sel(cageDM, wireCol, selCol, actCol, eed_act);
+ }
+ else if( (G.f & G_DRAWEDGES) || (G.scene->selectmode & SCE_SELECT_EDGE) ) {
+ if(cageDM->drawMappedEdgesInterp && (G.scene->selectmode & SCE_SELECT_VERTEX)) {
+ glShadeModel(GL_SMOOTH);
+ draw_dm_edges_sel_interp(cageDM, wireCol, selCol);
+ glShadeModel(GL_FLAT);
+ } else {
+ draw_dm_edges_sel(cageDM, wireCol, selCol, actCol, eed_act);
+ }
+ }
+ else {
+ if (!sel_only) {
+ glColor4ubv(wireCol);
+ draw_dm_edges(cageDM);
+ }
+ }
+
+ if (pass==0) {
+ glDisable(GL_BLEND);
+ glEnable(GL_DEPTH_TEST);
+ }
+ }
+}
+
+#ifdef WITH_VERSE
+/*
+ * draw some debug info about verse mesh (vertex indexes,
+ * face indexes, status of )
+ */
+static void draw_verse_debug(Object *ob, EditMesh *em)
+{
+ struct EditVert *eve=NULL;
+ struct EditFace *efa=NULL;
+ float v1[3], v2[3], v3[3], v4[3], fvec[3], col[3];
+ char val[32];
+
+ if(G.vd->zbuf && (G.vd->flag & V3D_ZBUF_SELECT)==0)
+ glDisable(GL_DEPTH_TEST);
+
+ if(G.vd->zbuf) bglPolygonOffset(5.0);
+
+ BIF_GetThemeColor3fv(TH_TEXT, col);
+ /* make color a bit more red */
+ if(col[0]> 0.5) {col[1]*=0.7; col[2]*= 0.7;}
+ else col[0]= col[0]*0.7 + 0.3;
+ glColor3fv(col);
+
+ /* draw IDs of verse vertexes */
+ for(eve = em->verts.first; eve; eve = eve->next) {
+ if(eve->vvert) {
+ VecLerpf(fvec, ob->loc, eve->co, 1.1);
+ glRasterPos3f(fvec[0], fvec[1], fvec[2]);
+
+ sprintf(val, "%d", ((VerseVert*)eve->vvert)->id);
+ BMF_DrawString(G.fonts, val);
+ }
+ }
+
+ /* draw IDs of verse faces */
+ for(efa = em->faces.first; efa; efa = efa->next) {
+ if(efa->vface) {
+ VECCOPY(v1, efa->v1->co);
+ VECCOPY(v2, efa->v2->co);
+ VECCOPY(v3, efa->v3->co);
+ if(efa->v4) {
+ VECCOPY(v4, efa->v4->co);
+ glRasterPos3f(0.25*(v1[0]+v2[0]+v3[0]+v4[0]),
+ 0.25*(v1[1]+v2[1]+v3[1]+v4[1]),
+ 0.25*(v1[2]+v2[2]+v3[2]+v4[2]));
+ }
+ else {
+ glRasterPos3f((v1[0]+v2[0]+v3[0])/3,
+ (v1[1]+v2[1]+v3[1])/3,
+ (v1[2]+v2[2]+v3[2])/3);
+ }
+
+ sprintf(val, "%d", ((VerseFace*)efa->vface)->id);
+ BMF_DrawString(G.fonts, val);
+
+ }
+ }
+
+ if(G.vd->zbuf) {
+ glEnable(GL_DEPTH_TEST);
+ bglPolygonOffset(0.0);
+ }
+}
+#endif
+
+static void draw_em_measure_stats(Object *ob, EditMesh *em)
+{
+ EditEdge *eed;
+ EditFace *efa;
+ float v1[3], v2[3], v3[3], v4[3];
+ float fvec[3];
+ char val[32]; /* Stores the measurement display text here */
+ char conv_float[5]; /* Use a float conversion matching the grid size */
+ float area, col[3]; /* area of the face, color of the text to draw */
+
+ /* make the precission of the pronted value proportionate to the gridsize */
+ if ((G.vd->grid) < 0.01)
+ strcpy(conv_float, "%.6f");
+ else if ((G.vd->grid) < 0.1)
+ strcpy(conv_float, "%.5f");
+ else if ((G.vd->grid) < 1.0)
+ strcpy(conv_float, "%.4f");
+ else if ((G.vd->grid) < 10.0)
+ strcpy(conv_float, "%.3f");
+ else
+ strcpy(conv_float, "%.2f");
+
+
+ if(G.vd->zbuf && (G.vd->flag & V3D_ZBUF_SELECT)==0)
+ glDisable(GL_DEPTH_TEST);
+
+ if(G.vd->zbuf) bglPolygonOffset(5.0);
+
+ if(G.f & G_DRAW_EDGELEN) {
+ BIF_GetThemeColor3fv(TH_TEXT, col);
+ /* make color a bit more red */
+ if(col[0]> 0.5) {col[1]*=0.7; col[2]*= 0.7;}
+ else col[0]= col[0]*0.7 + 0.3;
+ glColor3fv(col);
+
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ /* draw non fgon edges, or selected edges, or edges next to selected verts while draging */
+ if((eed->h != EM_FGON) && ((eed->f & SELECT) || (G.moving && ((eed->v1->f & SELECT) || (eed->v2->f & SELECT)) ))) {
+ VECCOPY(v1, eed->v1->co);
+ VECCOPY(v2, eed->v2->co);
+
+ glRasterPos3f( 0.5*(v1[0]+v2[0]), 0.5*(v1[1]+v2[1]), 0.5*(v1[2]+v2[2]));
+
+ if(G.vd->flag & V3D_GLOBAL_STATS) {
+ Mat4MulVecfl(ob->obmat, v1);
+ Mat4MulVecfl(ob->obmat, v2);
+ }
+
+ sprintf(val, conv_float, VecLenf(v1, v2));
+ BMF_DrawString( G.fonts, val);
+ }
+ }
+ }
+
+ if(G.f & G_DRAW_FACEAREA) {
+ extern int faceselectedOR(EditFace *efa, int flag); // editmesh.h shouldn't be in this file... ok for now?
+
+ BIF_GetThemeColor3fv(TH_TEXT, col);
+ /* make color a bit more green */
+ if(col[1]> 0.5) {col[0]*=0.7; col[2]*= 0.7;}
+ else col[1]= col[1]*0.7 + 0.3;
+ glColor3fv(col);
+
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if((efa->f & SELECT) || (G.moving && faceselectedOR(efa, SELECT)) ) {
+ VECCOPY(v1, efa->v1->co);
+ VECCOPY(v2, efa->v2->co);
+ VECCOPY(v3, efa->v3->co);
+ if (efa->v4) {
+ VECCOPY(v4, efa->v4->co);
+ }
+ if(G.vd->flag & V3D_GLOBAL_STATS) {
+ Mat4MulVecfl(ob->obmat, v1);
+ Mat4MulVecfl(ob->obmat, v2);
+ Mat4MulVecfl(ob->obmat, v3);
+ if (efa->v4) Mat4MulVecfl(ob->obmat, v4);
+ }
+
+ if (efa->v4)
+ area= AreaQ3Dfl(v1, v2, v3, v4);
+ else
+ area = AreaT3Dfl(v1, v2, v3);
+
+ sprintf(val, conv_float, area);
+ glRasterPos3fv(efa->cent);
+ BMF_DrawString( G.fonts, val);
+ }
+ }
+ }
+
+ if(G.f & G_DRAW_EDGEANG) {
+ EditEdge *e1, *e2, *e3, *e4;
+
+ BIF_GetThemeColor3fv(TH_TEXT, col);
+ /* make color a bit more blue */
+ if(col[2]> 0.5) {col[0]*=0.7; col[1]*= 0.7;}
+ else col[2]= col[2]*0.7 + 0.3;
+ glColor3fv(col);
+
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ VECCOPY(v1, efa->v1->co);
+ VECCOPY(v2, efa->v2->co);
+ VECCOPY(v3, efa->v3->co);
+ if(efa->v4) {
+ VECCOPY(v4, efa->v4->co);
+ }
+ else {
+ VECCOPY(v4, v3);
+ }
+ if(G.vd->flag & V3D_GLOBAL_STATS) {
+ Mat4MulVecfl(ob->obmat, v1);
+ Mat4MulVecfl(ob->obmat, v2);
+ Mat4MulVecfl(ob->obmat, v3);
+ if (efa->v4) Mat4MulVecfl(ob->obmat, v4);
+ }
+
+ e1= efa->e1;
+ e2= efa->e2;
+ e3= efa->e3;
+ if(efa->e4) e4= efa->e4; else e4= e3;
+
+ /* Calculate the angles */
+
+ if( (e4->f & e1->f & SELECT) || (G.moving && (efa->v1->f & SELECT)) ) {
+ /* Vec 1 */
+ sprintf(val,"%.3f", VecAngle3(v4, v1, v2));
+ VecLerpf(fvec, efa->cent, efa->v1->co, 0.8);
+ glRasterPos3fv(fvec);
+ BMF_DrawString( G.fonts, val);
+ }
+ if( (e1->f & e2->f & SELECT) || (G.moving && (efa->v2->f & SELECT)) ) {
+ /* Vec 2 */
+ sprintf(val,"%.3f", VecAngle3(v1, v2, v3));
+ VecLerpf(fvec, efa->cent, efa->v2->co, 0.8);
+ glRasterPos3fv(fvec);
+ BMF_DrawString( G.fonts, val);
+ }
+ if( (e2->f & e3->f & SELECT) || (G.moving && (efa->v3->f & SELECT)) ) {
+ /* Vec 3 */
+ if(efa->v4)
+ sprintf(val,"%.3f", VecAngle3(v2, v3, v4));
+ else
+ sprintf(val,"%.3f", VecAngle3(v2, v3, v1));
+ VecLerpf(fvec, efa->cent, efa->v3->co, 0.8);
+ glRasterPos3fv(fvec);
+ BMF_DrawString( G.fonts, val);
+ }
+ /* Vec 4 */
+ if(efa->v4) {
+ if( (e3->f & e4->f & SELECT) || (G.moving && (efa->v4->f & SELECT)) ) {
+ sprintf(val,"%.3f", VecAngle3(v3, v4, v1));
+ VecLerpf(fvec, efa->cent, efa->v4->co, 0.8);
+ glRasterPos3fv(fvec);
+ BMF_DrawString( G.fonts, val);
+ }
+ }
+ }
+ }
+
+ if(G.vd->zbuf) {
+ glEnable(GL_DEPTH_TEST);
+ bglPolygonOffset(0.0);
+ }
+}
+
+static int draw_em_fancy__setFaceOpts(void *userData, int index, int *drawSmooth_r)
+{
+ EditFace *efa = EM_get_face_for_index(index);
+
+ if (efa->h==0) {
+ set_gl_material(efa->mat_nr+1);
+ return 1;
+ } else {
+ return 0;
+ }
+}
+static void draw_em_fancy(Object *ob, EditMesh *em, DerivedMesh *cageDM, DerivedMesh *finalDM, int dt)
+{
+ Mesh *me = ob->data;
+ EditFace *efa_act = NULL;
+ EditEdge *eed_act = NULL;
+ EditVert *eve_act = NULL;
+
+ if (G.editMesh->selected.last) {
+ EditSelection *ese = G.editMesh->selected.last;
+ if ( ese->type == EDITFACE ) {
+ efa_act = (EditFace *)ese->data;
+ } else if ( ese->type == EDITEDGE ) {
+ eed_act = (EditEdge *)ese->data;
+ } else if ( ese->type == EDITVERT ) {
+ eve_act = (EditVert *)ese->data;
+ }
+ }
+
+ EM_init_index_arrays(1, 1, 1);
+
+ if(dt>OB_WIRE) {
+ if( CHECK_OB_DRAWTEXTURE(G.vd, dt) ) {
+ draw_mesh_textured(ob, finalDM, 0);
+ } else {
+ glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, me->flag & ME_TWOSIDED);
+
+ glEnable(GL_LIGHTING);
+ glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW);
+
+ finalDM->drawMappedFaces(finalDM, draw_em_fancy__setFaceOpts, 0, 0);
+
+ glFrontFace(GL_CCW);
+ glDisable(GL_LIGHTING);
+ }
+
+ // Setup for drawing wire over, disable zbuffer
+ // write to show selected edge wires better
+ BIF_ThemeColor(TH_WIRE);
+
+ bglPolygonOffset(1.0);
+ glDepthMask(0);
+ }
+ else {
+ if (cageDM!=finalDM) {
+ BIF_ThemeColorBlend(TH_WIRE, TH_BACK, 0.7);
+ finalDM->drawEdges(finalDM, 1);
+ }
+ }
+
+ if((G.f & (G_DRAWFACES)) || FACESEL_PAINT_TEST) { /* transp faces */
+ unsigned char col1[4], col2[4], col3[4];
+
+ BIF_GetThemeColor4ubv(TH_FACE, (char *)col1);
+ BIF_GetThemeColor4ubv(TH_FACE_SELECT, (char *)col2);
+ BIF_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, (char *)col3);
+
+ glEnable(GL_BLEND);
+ glDepthMask(0); // disable write in zbuffer, needed for nice transp
+
+ /* dont draw unselected faces, only selected, this is MUCH nicer when texturing */
+ if CHECK_OB_DRAWTEXTURE(G.vd, dt)
+ col1[3] = 0;
+
+ draw_dm_faces_sel(cageDM, col1, col2, col3, efa_act);
+
+ glDisable(GL_BLEND);
+ glDepthMask(1); // restore write in zbuffer
+ } else if (efa_act) {
+ /* even if draw faces is off it would be nice to draw the stipple face
+ * Make all other faces zero alpha except for the active
+ * */
+ unsigned char col1[4], col2[4], col3[4];
+ col1[3] = col2[3] = 0; /* dont draw */
+ BIF_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, (char *)col3);
+
+ glEnable(GL_BLEND);
+ glDepthMask(0); // disable write in zbuffer, needed for nice transp
+
+ draw_dm_faces_sel(cageDM, col1, col2, col3, efa_act);
+
+ glDisable(GL_BLEND);
+ glDepthMask(1); // restore write in zbuffer
+
+ }
+
+ /* here starts all fancy draw-extra over */
+ if((G.f & G_DRAWEDGES)==0 && CHECK_OB_DRAWTEXTURE(G.vd, dt)) {
+ /* we are drawing textures and 'G_DRAWEDGES' is disabled, dont draw any edges */
+
+ /* only draw selected edges otherwise there is no way of telling if a face is selected */
+ draw_em_fancy_edges(cageDM, 1, eed_act);
+
+ } else {
+ if(G.f & G_DRAWSEAMS) {
+ BIF_ThemeColor(TH_EDGE_SEAM);
+ glLineWidth(2);
+
+ draw_dm_edges_seams(cageDM);
+
+ glColor3ub(0,0,0);
+ glLineWidth(1);
+ }
+
+ if(G.f & G_DRAWSHARP) {
+ BIF_ThemeColor(TH_EDGE_SHARP);
+ glLineWidth(2);
+
+ draw_dm_edges_sharp(cageDM);
+
+ glColor3ub(0,0,0);
+ glLineWidth(1);
+ }
+
+ if(G.f & G_DRAWCREASES) {
+ draw_dm_creases(cageDM);
+ }
+
+ draw_em_fancy_edges(cageDM, 0, eed_act);
+ }
+ if(ob==G.obedit) {
+ retopo_matrix_update(G.vd);
+
+ draw_em_fancy_verts(em, cageDM, eve_act);
+
+ if(G.f & G_DRAWNORMALS) {
+ BIF_ThemeColor(TH_NORMAL);
+ draw_dm_face_normals(cageDM);
+ }
+ if(G.f & G_DRAW_VNORMALS) {
+ BIF_ThemeColor(TH_NORMAL);
+ draw_dm_vert_normals(cageDM);
+ }
+
+ if(G.f & (G_DRAW_EDGELEN|G_DRAW_FACEAREA|G_DRAW_EDGEANG))
+ draw_em_measure_stats(ob, em);
+#ifdef WITH_VERSE
+ if(em->vnode && (G.f & G_DRAW_VERSE_DEBUG))
+ draw_verse_debug(ob, em);
+#endif
+ }
+
+ if(dt>OB_WIRE) {
+ glDepthMask(1);
+ bglPolygonOffset(0.0);
+ }
+
+ EM_free_index_arrays();
+}
+
+/* Mesh drawing routines */
+
+static void draw_mesh_object_outline(Object *ob, DerivedMesh *dm)
+{
+
+ if(G.vd->transp==0) { // not when we draw the transparent pass
+ glLineWidth(2.0);
+ glDepthMask(0);
+
+ /* if transparent, we cannot draw the edges for solid select... edges have no material info.
+ drawFacesSolid() doesn't draw the transparent faces */
+ if(ob->dtx & OB_DRAWTRANSP) {
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ dm->drawFacesSolid(dm, set_gl_material);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ }
+ else {
+ dm->drawEdges(dm, 0);
+ }
+
+ glLineWidth(1.0);
+ glDepthMask(1);
+ }
+}
+
+static int wpaint__setSolidDrawOptions(void *userData, int index, int *drawSmooth_r)
+{
+ *drawSmooth_r = 1;
+ return 1;
+}
+
+static void draw_mesh_fancy(Base *base, int dt, int flag)
+{
+ Object *ob= base->object;
+ Mesh *me = ob->data;
+ Material *ma= give_current_material(ob, 1);
+ int hasHaloMat = (ma && (ma->mode&MA_HALO));
+ int draw_wire = ob->dtx&OB_DRAWWIRE;
+ int totvert, totedge, totface;
+ DispList *dl;
+ DerivedMesh *dm= mesh_get_derived_final(ob, get_viewedit_datamask());
+
+ if(!dm)
+ return;
+
+#ifdef WITH_VERSE
+ if(me->vnode) {
+ struct VNode *vnode = (VNode*)me->vnode;
+ struct VLayer *vert_vlayer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER);
+ struct VLayer *face_vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER);
+
+ if(vert_vlayer) totvert = vert_vlayer->dl.da.count;
+ else totvert = 0;
+ totedge = 0; /* total count of edge needn't to be zero, but verse doesn't know edges */
+ if(face_vlayer) totface = face_vlayer->dl.da.count;
+ else totface = 0;
+ }
+ else {
+ totvert = dm->getNumVerts(dm);
+ totedge = dm->getNumEdges(dm);
+ totface = dm->getNumFaces(dm);
+ }
+#else
+ totvert = dm->getNumVerts(dm);
+ totedge = dm->getNumEdges(dm);
+ totface = dm->getNumFaces(dm);
+#endif
+
+ /* vertexpaint, faceselect wants this, but it doesnt work for shaded? */
+ if(dt!=OB_SHADED)
+ glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW);
+
+ // Unwanted combination.
+ if (ob==OBACT && FACESEL_PAINT_TEST) draw_wire = 0;
+
+ if(dt==OB_BOUNDBOX) {
+ draw_bounding_volume(ob);
+ }
+ else if(hasHaloMat || (totface==0 && totedge==0)) {
+ glPointSize(1.5);
+ dm->drawVerts(dm);
+ glPointSize(1.0);
+ }
+ else if(dt==OB_WIRE || totface==0) {
+ draw_wire = 1;
+ }
+ else if( (ob==OBACT && (G.f & G_TEXTUREPAINT || FACESEL_PAINT_TEST)) ||
+ CHECK_OB_DRAWTEXTURE(G.vd, dt))
+ {
+ int faceselect= (ob==OBACT && FACESEL_PAINT_TEST);
+
+ if ((G.vd->flag&V3D_SELECT_OUTLINE) && (base->flag&SELECT) && !(G.f&G_PICKSEL || FACESEL_PAINT_TEST) && !draw_wire) {
+ draw_mesh_object_outline(ob, dm);
+ }
+
+ draw_mesh_textured(ob, dm, faceselect);
+
+ if(!faceselect) {
+ if(base->flag & SELECT)
+ BIF_ThemeColor((ob==OBACT)?TH_ACTIVE:TH_SELECT);
+ else
+ BIF_ThemeColor(TH_WIRE);
+
+ dm->drawLooseEdges(dm);
+ }
+ }
+ else if(dt==OB_SOLID ) {
+
+ if ((G.vd->flag&V3D_SELECT_OUTLINE) && (base->flag&SELECT) && !draw_wire) {
+ draw_mesh_object_outline(ob, dm);
+ }
+
+ glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, me->flag & ME_TWOSIDED );
+
+ glEnable(GL_LIGHTING);
+ glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW);
+
+ dm->drawFacesSolid(dm, set_gl_material);
+
+ glFrontFace(GL_CCW);
+ glDisable(GL_LIGHTING);
+
+ if(base->flag & SELECT) {
+ BIF_ThemeColor((ob==OBACT)?TH_ACTIVE:TH_SELECT);
+ } else {
+ BIF_ThemeColor(TH_WIRE);
+ }
+ dm->drawLooseEdges(dm);
+ }
+ else if(dt==OB_SHADED) {
+ int do_draw= 1; /* to resolve all G.f settings below... */
+
+ if(ob==OBACT) {
+ do_draw= 0;
+ if( (G.f & G_WEIGHTPAINT)) {
+ set_gl_material(0); /* enforce defmaterial settings */
+
+ /* but set default spec */
+ glColorMaterial(GL_FRONT_AND_BACK, GL_SPECULAR);
+ glEnable(GL_COLOR_MATERIAL); /* according manpages needed */
+ glColor3ub(120, 120, 120);
+ glDisable(GL_COLOR_MATERIAL);
+ /* diffuse */
+ glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
+ glEnable(GL_LIGHTING);
+ glEnable(GL_COLOR_MATERIAL);
+
+ dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, me->mface, 1);
+ glDisable(GL_COLOR_MATERIAL);
+ glDisable(GL_LIGHTING);
+ }
+ else if((G.f & (G_VERTEXPAINT+G_TEXTUREPAINT)) && me->mcol) {
+ dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, NULL, 1);
+ }
+ else if(G.f & (G_VERTEXPAINT+G_TEXTUREPAINT)) {
+ glColor3f(1.0f, 1.0f, 1.0f);
+ dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, NULL, 0);
+ }
+ else do_draw= 1;
+ }
+ if(do_draw) {
+ dl = ob->disp.first;
+ if (!dl || !dl->col1) {
+ /* release and reload derivedmesh because it might be freed in
+ shadeDispList due to a different datamask */
+ dm->release(dm);
+ shadeDispList(base);
+ dl = find_displist(&ob->disp, DL_VERTCOL);
+ dm= mesh_get_derived_final(ob, get_viewedit_datamask());
+ }
+
+ if ((G.vd->flag&V3D_SELECT_OUTLINE) && (base->flag&SELECT) && !draw_wire) {
+ draw_mesh_object_outline(ob, dm);
+ }
+
+ /* False for dupliframe objects */
+ if (dl) {
+ unsigned int *obCol1 = dl->col1;
+ unsigned int *obCol2 = dl->col2;
+
+ dm->drawFacesColored(dm, me->flag&ME_TWOSIDED, (unsigned char*) obCol1, (unsigned char*) obCol2);
+ }
+
+ if(base->flag & SELECT) {
+ BIF_ThemeColor((ob==OBACT)?TH_ACTIVE:TH_SELECT);
+ } else {
+ BIF_ThemeColor(TH_WIRE);
+ }
+ dm->drawLooseEdges(dm);
+ }
+ }
+
+ /* set default draw color back for wire or for draw-extra later on */
+ if (dt!=OB_WIRE) {
+ if(base->flag & SELECT) {
+ if(ob==OBACT && ob->flag & OB_FROMGROUP)
+ BIF_ThemeColor(TH_GROUP_ACTIVE);
+ else if(ob->flag & OB_FROMGROUP)
+ BIF_ThemeColorShade(TH_GROUP_ACTIVE, -16);
+ else if(flag!=DRAW_CONSTCOLOR)
+ BIF_ThemeColor((ob==OBACT)?TH_ACTIVE:TH_SELECT);
+ else
+ glColor3ub(80,80,80);
+ } else {
+ if (ob->flag & OB_FROMGROUP)
+ BIF_ThemeColor(TH_GROUP);
+ else {
+ if(ob->dtx & OB_DRAWWIRE && flag==DRAW_CONSTCOLOR)
+ glColor3ub(80,80,80);
+ else
+ BIF_ThemeColor(TH_WIRE);
+ }
+ }
+ }
+ if (draw_wire) {
+ /* If drawing wire and drawtype is not OB_WIRE then we are
+ * overlaying the wires.
+ */
+
+ if (dt!=OB_WIRE) {
+ bglPolygonOffset(1.0);
+ glDepthMask(0); // disable write in zbuffer, selected edge wires show better
+ }
+
+ dm->drawEdges(dm, (dt==OB_WIRE || totface==0));
+
+ if (dt!=OB_WIRE) {
+ glDepthMask(1);
+ bglPolygonOffset(0.0);
+ }
+ }
+
+ dm->release(dm);
+}
+
+/* returns 1 if nothing was drawn, for detecting to draw an object center */
+static int draw_mesh_object(Base *base, int dt, int flag)
+{
+ Object *ob= base->object;
+ Mesh *me= ob->data;
+ int has_alpha= 0, drawlinked= 0, retval= 0;
+
+ if(G.obedit && ob!=G.obedit && ob->data==G.obedit->data) {
+ if(ob_get_key(ob));
+ else drawlinked= 1;
+ }
+
+ if(ob==G.obedit || drawlinked) {
+ DerivedMesh *finalDM, *cageDM;
+
+ if (G.obedit!=ob)
+ finalDM = cageDM = editmesh_get_derived_base();
+ else
+ cageDM = editmesh_get_derived_cage_and_final(&finalDM,
+ get_viewedit_datamask());
+
+ if(dt>OB_WIRE) init_gl_materials(ob, 0); // no transp in editmode, the fancy draw over goes bad then
+ draw_em_fancy(ob, G.editMesh, cageDM, finalDM, dt);
+
+ /* TODO, not 100% sure this is correct,
+ * however I could not make it crash or leak ram with different
+ * linked-dup/modifier configurtions,
+ * should double check whats going on before release - Campbell */
+ if (cageDM != finalDM) {
+ cageDM->release(cageDM);
+ finalDM->release(finalDM);
+ }
+ }
+ else if(!G.obedit && (G.f & G_SCULPTMODE) &&(G.scene->sculptdata.flags & SCULPT_DRAW_FAST) &&
+ OBACT==ob && !sculpt_modifiers_active(ob)) {
+ sculptmode_draw_mesh(0);
+ }
+ else {
+ /* don't create boundbox here with mesh_get_bb(), the derived system will make it, puts deformed bb's OK */
+
+ if(me->totface<=4 || boundbox_clip(ob->obmat, me->bb)) {
+ if(dt==OB_SOLID) has_alpha= init_gl_materials(ob, (base->flag & OB_FROMDUPLI)==0);
+ draw_mesh_fancy(base, dt, flag);
+
+ if(me->totvert==0) retval= 1;
+ }
+ }
+
+ /* init_gl_materials did the proper checking if this is needed */
+ if(has_alpha) add_view3d_after(G.vd, base, V3D_TRANSP);
+
+ return retval;
+}
+
+/* ************** DRAW DISPLIST ****************** */
+
+static int draw_index_wire= 1;
+static int index3_nors_incr= 1;
+
+/* returns 1 when nothing was drawn */
+static int drawDispListwire(ListBase *dlbase)
+{
+ DispList *dl;
+ int parts, nr;
+ float *data;
+
+ if(dlbase==NULL) return 1;
+
+ glDisableClientState(GL_NORMAL_ARRAY);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+
+ for(dl= dlbase->first; dl; dl= dl->next) {
+ if(dl->parts==0 || dl->nr==0)
+ continue;
+
+ data= dl->verts;
+
+ switch(dl->type) {
+ case DL_SEGM:
+
+ glVertexPointer(3, GL_FLOAT, 0, data);
+
+ for(parts=0; parts<dl->parts; parts++)
+ glDrawArrays(GL_LINE_STRIP, parts*dl->nr, dl->nr);
+
+ break;
+ case DL_POLY:
+
+ glVertexPointer(3, GL_FLOAT, 0, data);
+
+ for(parts=0; parts<dl->parts; parts++)
+ glDrawArrays(GL_LINE_LOOP, parts*dl->nr, dl->nr);
+
+ break;
+ case DL_SURF:
+
+ glVertexPointer(3, GL_FLOAT, 0, data);
+
+ for(parts=0; parts<dl->parts; parts++) {
+ if(dl->flag & DL_CYCL_U)
+ glDrawArrays(GL_LINE_LOOP, parts*dl->nr, dl->nr);
+ else
+ glDrawArrays(GL_LINE_STRIP, parts*dl->nr, dl->nr);
+ }
+
+ for(nr=0; nr<dl->nr; nr++) {
+ int ofs= 3*dl->nr;
+
+ data= ( dl->verts )+3*nr;
+ parts= dl->parts;
+
+ if(dl->flag & DL_CYCL_V) glBegin(GL_LINE_LOOP);
+ else glBegin(GL_LINE_STRIP);
+
+ while(parts--) {
+ glVertex3fv(data);
+ data+=ofs;
+ }
+ glEnd();
+
+ /* (ton) this code crashes for me when resolv is 86 or higher... no clue */
+// glVertexPointer(3, GL_FLOAT, sizeof(float)*3*dl->nr, data + 3*nr);
+// if(dl->flag & DL_CYCL_V)
+// glDrawArrays(GL_LINE_LOOP, 0, dl->parts);
+// else
+// glDrawArrays(GL_LINE_STRIP, 0, dl->parts);
+ }
+ break;
+
+ case DL_INDEX3:
+ if(draw_index_wire) {
+ glVertexPointer(3, GL_FLOAT, 0, dl->verts);
+ glDrawElements(GL_TRIANGLES, 3*dl->parts, GL_UNSIGNED_INT, dl->index);
+ }
+ break;
+
+ case DL_INDEX4:
+ if(draw_index_wire) {
+ glVertexPointer(3, GL_FLOAT, 0, dl->verts);
+ glDrawElements(GL_QUADS, 4*dl->parts, GL_UNSIGNED_INT, dl->index);
+ }
+ break;
+ }
+ }
+
+ glEnableClientState(GL_NORMAL_ARRAY);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+
+ return 0;
+}
+
+static void drawDispListsolid(ListBase *lb, Object *ob)
+{
+ DispList *dl;
+ float *data, curcol[4];
+ float *ndata;
+
+ if(lb==NULL) return;
+
+ /* for drawing wire */
+ glGetFloatv(GL_CURRENT_COLOR, curcol);
+
+ glEnable(GL_LIGHTING);
+
+ if(ob->transflag & OB_NEG_SCALE) glFrontFace(GL_CW);
+ else glFrontFace(GL_CCW);
+
+ if(ob->type==OB_MBALL) { // mball always smooth shaded
+ glShadeModel(GL_SMOOTH);
+ }
+
+ dl= lb->first;
+ while(dl) {
+ data= dl->verts;
+ ndata= dl->nors;
+
+ switch(dl->type) {
+ case DL_SEGM:
+ if(ob->type==OB_SURF) {
+ int nr;
+
+ glDisable(GL_LIGHTING);
+ glColor3fv(curcol);
+
+ // glVertexPointer(3, GL_FLOAT, 0, dl->verts);
+ // glDrawArrays(GL_LINE_STRIP, 0, dl->nr);
+
+ glBegin(GL_LINE_STRIP);
+ for(nr= dl->nr; nr; nr--, data+=3)
+ glVertex3fv(data);
+ glEnd();
+
+ glEnable(GL_LIGHTING);
+ }
+ break;
+ case DL_POLY:
+ if(ob->type==OB_SURF) {
+ int nr;
+
+ BIF_ThemeColor(TH_WIRE);
+ glDisable(GL_LIGHTING);
+
+ /* for some reason glDrawArrays crashes here in half of the platforms (not osx) */
+ //glVertexPointer(3, GL_FLOAT, 0, dl->verts);
+ //glDrawArrays(GL_LINE_LOOP, 0, dl->nr);
+
+ glBegin(GL_LINE_LOOP);
+ for(nr= dl->nr; nr; nr--, data+=3)
+ glVertex3fv(data);
+ glEnd();
+
+ glEnable(GL_LIGHTING);
+ break;
+ }
+ case DL_SURF:
+
+ if(dl->index) {
+ set_gl_material(dl->col+1);
+
+ if(dl->rt & CU_SMOOTH) glShadeModel(GL_SMOOTH);
+ else glShadeModel(GL_FLAT);
+
+ glVertexPointer(3, GL_FLOAT, 0, dl->verts);
+ glNormalPointer(GL_FLOAT, 0, dl->nors);
+ glDrawElements(GL_QUADS, 4*dl->totindex, GL_UNSIGNED_INT, dl->index);
+ }
+ break;
+
+ case DL_INDEX3:
+
+ set_gl_material(dl->col+1);
+
+ glVertexPointer(3, GL_FLOAT, 0, dl->verts);
+
+ /* voor polys only one normal needed */
+ if(index3_nors_incr==0) {
+ glDisableClientState(GL_NORMAL_ARRAY);
+ glNormal3fv(ndata);
+ }
+ else
+ glNormalPointer(GL_FLOAT, 0, dl->nors);
+
+ glDrawElements(GL_TRIANGLES, 3*dl->parts, GL_UNSIGNED_INT, dl->index);
+
+ if(index3_nors_incr==0)
+ glEnableClientState(GL_NORMAL_ARRAY);
+
+ break;
+
+ case DL_INDEX4:
+
+ set_gl_material(dl->col+1);
+
+ glVertexPointer(3, GL_FLOAT, 0, dl->verts);
+ glNormalPointer(GL_FLOAT, 0, dl->nors);
+ glDrawElements(GL_QUADS, 4*dl->parts, GL_UNSIGNED_INT, dl->index);
+
+ break;
+ }
+ dl= dl->next;
+ }
+
+ glShadeModel(GL_FLAT);
+ glDisable(GL_LIGHTING);
+ glFrontFace(GL_CCW);
+}
+
+static void drawDispListshaded(ListBase *lb, Object *ob)
+{
+ DispList *dl, *dlob;
+ unsigned int *cdata;
+
+ if(lb==NULL) return;
+
+ glShadeModel(GL_SMOOTH);
+ glDisableClientState(GL_NORMAL_ARRAY);
+ glEnableClientState(GL_COLOR_ARRAY);
+
+ dl= lb->first;
+ dlob= ob->disp.first;
+ while(dl && dlob) {
+
+ cdata= dlob->col1;
+ if(cdata==NULL) break;
+
+ switch(dl->type) {
+ case DL_SURF:
+ if(dl->index) {
+ glVertexPointer(3, GL_FLOAT, 0, dl->verts);
+ glColorPointer(4, GL_UNSIGNED_BYTE, 0, cdata);
+ glDrawElements(GL_QUADS, 4*dl->totindex, GL_UNSIGNED_INT, dl->index);
+ }
+ break;
+
+ case DL_INDEX3:
+
+ glVertexPointer(3, GL_FLOAT, 0, dl->verts);
+ glColorPointer(4, GL_UNSIGNED_BYTE, 0, cdata);
+ glDrawElements(GL_TRIANGLES, 3*dl->parts, GL_UNSIGNED_INT, dl->index);
+ break;
+
+ case DL_INDEX4:
+
+ glVertexPointer(3, GL_FLOAT, 0, dl->verts);
+ glColorPointer(4, GL_UNSIGNED_BYTE, 0, cdata);
+ glDrawElements(GL_QUADS, 4*dl->parts, GL_UNSIGNED_INT, dl->index);
+ break;
+ }
+
+ dl= dl->next;
+ dlob= dlob->next;
+ }
+
+ glShadeModel(GL_FLAT);
+ glEnableClientState(GL_NORMAL_ARRAY);
+ glDisableClientState(GL_COLOR_ARRAY);
+}
+
+/* returns 1 when nothing was drawn */
+static int drawDispList(Base *base, int dt)
+{
+ Object *ob= base->object;
+ ListBase *lb=0;
+ DispList *dl;
+ Curve *cu;
+ int solid, retval= 0;
+
+ solid= (dt > OB_WIRE);
+
+ switch(ob->type) {
+ case OB_FONT:
+ case OB_CURVE:
+ cu= ob->data;
+
+ lb= &cu->disp;
+
+ if(solid) {
+ dl= lb->first;
+ if(dl==NULL) return 1;
+
+ if(dl->nors==0) addnormalsDispList(ob, lb);
+ index3_nors_incr= 0;
+
+ if( displist_has_faces(lb)==0) {
+ draw_index_wire= 0;
+ drawDispListwire(lb);
+ draw_index_wire= 1;
+ }
+ else {
+ if(dt==OB_SHADED) {
+ if(ob->disp.first==0) shadeDispList(base);
+ drawDispListshaded(lb, ob);
+ }
+ else {
+ init_gl_materials(ob, 0);
+ glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0);
+ drawDispListsolid(lb, ob);
+ }
+ if(ob==G.obedit && cu->bevobj==NULL && cu->taperobj==NULL) {
+ cpack(0);
+ draw_index_wire= 0;
+ drawDispListwire(lb);
+ draw_index_wire= 1;
+ }
+ }
+ index3_nors_incr= 1;
+ }
+ else {
+ draw_index_wire= 0;
+ retval= drawDispListwire(lb);
+ draw_index_wire= 1;
+ }
+ break;
+ case OB_SURF:
+
+ lb= &((Curve *)ob->data)->disp;
+
+ if(solid) {
+ dl= lb->first;
+ if(dl==NULL) return 1;
+
+ if(dl->nors==NULL) addnormalsDispList(ob, lb);
+
+ if(dt==OB_SHADED) {
+ if(ob->disp.first==NULL) shadeDispList(base);
+ drawDispListshaded(lb, ob);
+ }
+ else {
+ init_gl_materials(ob, 0);
+ glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0);
+
+ drawDispListsolid(lb, ob);
+ }
+ }
+ else {
+ retval= drawDispListwire(lb);
+ }
+ break;
+ case OB_MBALL:
+
+ if( is_basis_mball(ob)) {
+ lb= &ob->disp;
+ if(lb->first==NULL) makeDispListMBall(ob);
+ if(lb->first==NULL) return 1;
+
+ if(solid) {
+
+ if(dt==OB_SHADED) {
+ dl= lb->first;
+ if(dl && dl->col1==0) shadeDispList(base);
+ drawDispListshaded(lb, ob);
+ }
+ else {
+ init_gl_materials(ob, 0);
+ glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0);
+
+ drawDispListsolid(lb, ob);
+ }
+ }
+ else{
+ /* MetaBalls use DL_INDEX4 type of DispList */
+ retval= drawDispListwire(lb);
+ }
+ }
+ break;
+ }
+
+ return retval;
+}
+
+/* ******************************** */
+
+
+static void draw_particle_system(Base *base, PartEff *paf)
+{
+ Object *ob= base->object;
+ Particle *pa;
+ float ptime, ctime, vec[3], vec1[3], mat[4][4];
+ int a, totpart;
+
+ pa= paf->keys;
+ // FSPARTICLE always rebuild fluid particle system upon change...
+ if( (pa==NULL)
+ || ( (ob->fluidsimFlag & OB_FLUIDSIM_ENABLE) && (ob->fluidsimSettings) && (ob->fluidsimSettings->type == OB_FLUIDSIM_PARTICLE))
+ ) {
+ build_particle_system(ob);
+ pa= paf->keys;
+ if(pa==NULL) return;
+ }
+
+ myloadmatrix(G.vd->viewmat);
+ /* flag abuse... but I need working code too now. This feature doesnt work for per frame animated objects */
+ if( (base->flag & OB_FROMDUPLI) && (ob->flag & OB_FROMGROUP) ) {
+ Mat4MulMat4(mat, paf->imat, ob->obmat);
+ mymultmatrix(mat);
+ }
+
+ if(ob->ipoflag & OB_OFFS_PARTICLE) ptime= ob->sf;
+ else ptime= 0.0;
+ ctime= bsystem_time(ob, (float)(G.scene->r.cfra), ptime);
+
+ glPointSize(1.0);
+
+ if(paf->stype==PAF_VECT) glBegin(GL_LINES);
+ else glBegin(GL_POINTS);
+
+ totpart= (paf->disp*paf->totpart)/100;
+ for(a=0; a<totpart; a++, pa+=paf->totkey) {
+
+ if(ctime > pa->time) {
+ if(ctime < pa->time+pa->lifetime) {
+
+ if(paf->stype==PAF_VECT) {
+ where_is_particle(paf, pa, ctime, vec);
+ where_is_particle(paf, pa, ctime+1.0, vec1);
+
+ glVertex3fv(vec);
+ glVertex3fv(vec1);
+ }
+ else {
+ where_is_particle(paf, pa, ctime, vec);
+
+ glVertex3fv(vec);
+ }
+ }
+ }
+ }
+ glEnd();
+
+ myloadmatrix(G.vd->viewmat);
+ mymultmatrix(ob->obmat); // bring back local matrix for dtx
+}
+
+static void draw_static_particle_system(Object *ob, PartEff *paf, int dt)
+{
+ Particle *pa;
+ float ctime, mtime, vec[3], veco[3];
+ int a, use_norm=0, totpart;
+
+ pa= paf->keys;
+ // FSPARTICLE always rebuild upon change...
+ if( (pa==NULL)
+ || ( (ob->fluidsimFlag & OB_FLUIDSIM_ENABLE) && (ob->fluidsimSettings) && (ob->fluidsimSettings->type == OB_FLUIDSIM_PARTICLE))
+ ) {
+ build_particle_system(ob);
+ pa= paf->keys;
+ if(pa==NULL) return;
+ }
+
+ if(paf->stype==PAF_VECT) {
+ if(dt>OB_WIRE) {
+
+ /* shaded/texture mode: we still draw solid, so have to set materials */
+ if(dt>OB_SOLID) init_gl_materials(ob, 0);
+
+ glEnable(GL_LIGHTING);
+ set_gl_material(paf->omat);
+ use_norm= 1;
+ }
+ }
+ else {
+ glPointSize(1.0);
+ glBegin(GL_POINTS);
+ }
+
+ totpart= (paf->disp*paf->totpart)/100;
+ for(a=0; a<totpart; a++, pa+=paf->totkey) {
+
+ if(paf->stype==PAF_VECT) {
+
+ glBegin(GL_LINE_STRIP);
+ where_is_particle(paf, pa, pa->time, veco);
+
+ mtime= pa->time+pa->lifetime+paf->staticstep;
+ for(ctime= pa->time+paf->staticstep; ctime<mtime; ctime+=paf->staticstep) {
+
+ where_is_particle(paf, pa, ctime, vec);
+
+ if(use_norm) {
+ float no[3];
+ VECSUB(no, vec, veco);
+ glNormal3fv(no);
+ }
+ glVertex3fv(veco);
+ VECCOPY(veco, vec);
+ }
+
+ glVertex3fv(veco);
+ glEnd();
+ }
+ else {
+ mtime= pa->time+pa->lifetime+paf->staticstep-1;
+ for(ctime= pa->time; ctime<mtime; ctime+=paf->staticstep) {
+ where_is_particle(paf, pa, ctime, vec);
+ glVertex3fv(vec);
+ }
+ }
+ }
+ if(paf->stype==PAF_VECT) {
+ glDisable(GL_LIGHTING);
+ }
+ else {
+ glEnd();
+ }
+
+}
+
+unsigned int nurbcol[8]= {
+ 0, 0x9090, 0x409030, 0x603080, 0, 0x40fff0, 0x40c033, 0xA090F0 };
+
+static void tekenhandlesN(Nurb *nu, short sel)
+{
+ BezTriple *bezt;
+ float *fp;
+ unsigned int *col;
+ int a;
+
+ if(nu->hide || (G.f & G_HIDDENHANDLES)) return;
+
+ glBegin(GL_LINES);
+
+ if( (nu->type & 7)==1) {
+ if(sel) col= nurbcol+4;
+ else col= nurbcol;
+
+ bezt= nu->bezt;
+ a= nu->pntsu;
+ while(a--) {
+ if(bezt->hide==0) {
+ if( (bezt->f2 & 1)==sel) {
+ fp= bezt->vec[0];
+
+ cpack(col[bezt->h1]);
+ glVertex3fv(fp);
+ glVertex3fv(fp+3);
+
+ cpack(col[bezt->h2]);
+ glVertex3fv(fp+3);
+ glVertex3fv(fp+6);
+ }
+ else if( (bezt->f1 & 1)==sel) {
+ fp= bezt->vec[0];
+
+ cpack(col[bezt->h1]);
+ glVertex3fv(fp);
+ glVertex3fv(fp+3);
+ }
+ else if( (bezt->f3 & 1)==sel) {
+ fp= bezt->vec[1];
+
+ cpack(col[bezt->h2]);
+ glVertex3fv(fp);
+ glVertex3fv(fp+3);
+ }
+ }
+ bezt++;
+ }
+ }
+ glEnd();
+}
+
+static void tekenvertsN(Nurb *nu, short sel)
+{
+ BezTriple *bezt;
+ BPoint *bp;
+ float size;
+ int a;
+
+ if(nu->hide) return;
+
+ if(sel) BIF_ThemeColor(TH_VERTEX_SELECT);
+ else BIF_ThemeColor(TH_VERTEX);
+
+ size= BIF_GetThemeValuef(TH_VERTEX_SIZE);
+ glPointSize(size);
+
+ bglBegin(GL_POINTS);
+
+ if((nu->type & 7)==1) {
+
+ bezt= nu->bezt;
+ a= nu->pntsu;
+ while(a--) {
+ if(bezt->hide==0) {
+ if (G.f & G_HIDDENHANDLES) {
+ if((bezt->f2 & 1)==sel) bglVertex3fv(bezt->vec[1]);
+ } else {
+ if((bezt->f1 & 1)==sel) bglVertex3fv(bezt->vec[0]);
+ if((bezt->f2 & 1)==sel) bglVertex3fv(bezt->vec[1]);
+ if((bezt->f3 & 1)==sel) bglVertex3fv(bezt->vec[2]);
+ }
+ }
+ bezt++;
+ }
+ }
+ else {
+ bp= nu->bp;
+ a= nu->pntsu*nu->pntsv;
+ while(a--) {
+ if(bp->hide==0) {
+ if((bp->f1 & 1)==sel) bglVertex3fv(bp->vec);
+ }
+ bp++;
+ }
+ }
+
+ bglEnd();
+ glPointSize(1.0);
+}
+
+static void draw_editnurb(Object *ob, Nurb *nurb, int sel)
+{
+ Nurb *nu;
+ BPoint *bp, *bp1;
+ int a, b, ofs;
+
+ nu= nurb;
+ while(nu) {
+ if(nu->hide==0) {
+ switch(nu->type & 7) {
+ case CU_POLY:
+ cpack(nurbcol[3]);
+ bp= nu->bp;
+ for(b=0; b<nu->pntsv; b++) {
+ if(nu->flagu & 1) glBegin(GL_LINE_LOOP);
+ else glBegin(GL_LINE_STRIP);
+
+ for(a=0; a<nu->pntsu; a++, bp++) {
+ glVertex3fv(bp->vec);
+ }
+
+ glEnd();
+ }
+ break;
+ case CU_NURBS:
+
+ bp= nu->bp;
+ for(b=0; b<nu->pntsv; b++) {
+ bp1= bp;
+ bp++;
+ for(a=nu->pntsu-1; a>0; a--, bp++) {
+ if(bp->hide==0 && bp1->hide==0) {
+ if(sel) {
+ if( (bp->f1 & 1) && ( bp1->f1 & 1) ) {
+ cpack(nurbcol[5]);
+
+ glBegin(GL_LINE_STRIP);
+ glVertex3fv(bp->vec);
+ glVertex3fv(bp1->vec);
+ glEnd();
+ }
+ }
+ else {
+ if( (bp->f1 & 1) && ( bp1->f1 & 1) );
+ else {
+ cpack(nurbcol[1]);
+
+ glBegin(GL_LINE_STRIP);
+ glVertex3fv(bp->vec);
+ glVertex3fv(bp1->vec);
+ glEnd();
+ }
+ }
+ }
+ bp1= bp;
+ }
+ }
+ if(nu->pntsv > 1) { /* surface */
+
+ ofs= nu->pntsu;
+ for(b=0; b<nu->pntsu; b++) {
+ bp1= nu->bp+b;
+ bp= bp1+ofs;
+ for(a=nu->pntsv-1; a>0; a--, bp+=ofs) {
+ if(bp->hide==0 && bp1->hide==0) {
+ if(sel) {
+ if( (bp->f1 & 1) && ( bp1->f1 & 1) ) {
+ cpack(nurbcol[7]);
+
+ glBegin(GL_LINE_STRIP);
+ glVertex3fv(bp->vec);
+ glVertex3fv(bp1->vec);
+ glEnd();
+ }
+ }
+ else {
+ if( (bp->f1 & 1) && ( bp1->f1 & 1) );
+ else {
+ cpack(nurbcol[3]);
+
+ glBegin(GL_LINE_STRIP);
+ glVertex3fv(bp->vec);
+ glVertex3fv(bp1->vec);
+ glEnd();
+ }
+ }
+ }
+ bp1= bp;
+ }
+ }
+
+ }
+ break;
+ }
+ }
+ nu= nu->next;
+ }
+}
+
+static void drawnurb(Base *base, Nurb *nurb, int dt)
+{
+ Object *ob= base->object;
+ Curve *cu = ob->data;
+ Nurb *nu;
+ BevList *bl;
+
+ retopo_matrix_update(G.vd);
+
+ /* DispList */
+ BIF_ThemeColor(TH_WIRE);
+ drawDispList(base, dt);
+
+ if(G.vd->zbuf) glDisable(GL_DEPTH_TEST);
+
+ /* first non-selected handles */
+ for(nu=nurb; nu; nu=nu->next) {
+ if((nu->type & 7)==CU_BEZIER) {
+ tekenhandlesN(nu, 0);
+ }
+ }
+ draw_editnurb(ob, nurb, 0);
+ draw_editnurb(ob, nurb, 1);
+ /* selected handles */
+ for(nu=nurb; nu; nu=nu->next) {
+ if((nu->type & 7)==1) tekenhandlesN(nu, 1);
+ tekenvertsN(nu, 0);
+ }
+
+ if(G.vd->zbuf) glEnable(GL_DEPTH_TEST);
+
+ /* direction vectors for 3d curve paths */
+ if(cu->flag & CU_3D) {
+ BIF_ThemeColor(TH_WIRE);
+ for (bl=cu->bev.first,nu=nurb; nu && bl; bl=bl->next,nu=nu->next) {
+ BevPoint *bevp= (BevPoint *)(bl+1);
+ int nr= bl->nr;
+ int skip= nu->resolu/16;
+ float fac;
+
+ while (nr-->0) {
+ float ox,oy,oz; // Offset perpendicular to the curve
+ float dx,dy,dz; // Delta along the curve
+
+ fac = calc_curve_subdiv_radius(cu, nu, (bl->nr - nr)) * G.scene->editbutsize;
+
+ ox = fac*bevp->mat[0][0];
+ oy = fac*bevp->mat[0][1];
+ oz = fac*bevp->mat[0][2];
+
+ dx = fac*bevp->mat[2][0];
+ dy = fac*bevp->mat[2][1];
+ dz = fac*bevp->mat[2][2];
+
+ glBegin(GL_LINE_STRIP);
+ glVertex3f(bevp->x - ox - dx, bevp->y - oy - dy, bevp->z - oz - dz);
+ glVertex3f(bevp->x, bevp->y, bevp->z);
+ glVertex3f(bevp->x + ox - dx, bevp->y + oy - dy, bevp->z + oz - dz);
+ glEnd();
+
+ bevp += skip+1;
+ nr -= skip;
+ }
+ }
+ }
+
+ if(G.vd->zbuf) glDisable(GL_DEPTH_TEST);
+
+ for(nu=nurb; nu; nu=nu->next) {
+ tekenvertsN(nu, 1);
+ }
+
+ if(G.vd->zbuf) glEnable(GL_DEPTH_TEST);
+}
+
+/* draw points on curve speed handles */
+static void curve_draw_speed(Object *ob)
+{
+ Curve *cu= ob->data;
+ IpoCurve *icu;
+ BezTriple *bezt;
+ float loc[4], dir[3];
+ int a;
+
+ if(cu->ipo==NULL)
+ return;
+
+ icu= cu->ipo->curve.first;
+ if(icu==NULL || icu->totvert<2)
+ return;
+
+ glPointSize( BIF_GetThemeValuef(TH_VERTEX_SIZE) );
+ bglBegin(GL_POINTS);
+
+ for(a=0, bezt= icu->bezt; a<icu->totvert; a++, bezt++) {
+ if( where_on_path(ob, bezt->vec[1][1], loc, dir)) {
+ BIF_ThemeColor((bezt->f2 & SELECT) && ob==OBACT?TH_VERTEX_SELECT:TH_VERTEX);
+ bglVertex3fv(loc);
+ }
+ }
+
+ glPointSize(1.0);
+ bglEnd();
+}
+
+
+static void tekentextcurs(void)
+{
+ cpack(0);
+
+ set_inverted_drawing(1);
+ glBegin(GL_QUADS);
+ glVertex2fv(G.textcurs[0]);
+ glVertex2fv(G.textcurs[1]);
+ glVertex2fv(G.textcurs[2]);
+ glVertex2fv(G.textcurs[3]);
+ glEnd();
+ set_inverted_drawing(0);
+}
+
+static void drawspiral(float *cent, float rad, float tmat[][4], int start)
+{
+ float vec[3], vx[3], vy[3];
+ int a, tot=32;
+ char inverse=0;
+
+ if (start < 0) {
+ inverse = 1;
+ start *= -1;
+ }
+
+ VECCOPY(vx, tmat[0]);
+ VECCOPY(vy, tmat[1]);
+ VecMulf(vx, rad);
+ VecMulf(vy, rad);
+
+ VECCOPY(vec, cent);
+
+ if (inverse==0) {
+ for(a=0; a<tot; a++) {
+ if (a+start>31)
+ start=-a + 1;
+ glBegin(GL_LINES);
+ glVertex3fv(vec);
+ vec[0]= cent[0] + *(sinval+a+start) * (vx[0] * (float)a/(float)tot) + *(cosval+a+start) * (vy[0] * (float)a/(float)tot);
+ vec[1]= cent[1] + *(sinval+a+start) * (vx[1] * (float)a/(float)tot) + *(cosval+a+start) * (vy[1] * (float)a/(float)tot);
+ vec[2]= cent[2] + *(sinval+a+start) * (vx[2] * (float)a/(float)tot) + *(cosval+a+start) * (vy[2] * (float)a/(float)tot);
+ glVertex3fv(vec);
+ glEnd();
+ }
+ }
+ else {
+ a=0;
+ vec[0]= cent[0] + *(sinval+a+start) * (vx[0] * (float)(-a+31)/(float)tot) + *(cosval+a+start) * (vy[0] * (float)(-a+31)/(float)tot);
+ vec[1]= cent[1] + *(sinval+a+start) * (vx[1] * (float)(-a+31)/(float)tot) + *(cosval+a+start) * (vy[1] * (float)(-a+31)/(float)tot);
+ vec[2]= cent[2] + *(sinval+a+start) * (vx[2] * (float)(-a+31)/(float)tot) + *(cosval+a+start) * (vy[2] * (float)(-a+31)/(float)tot);
+ for(a=0; a<tot; a++) {
+ if (a+start>31)
+ start=-a + 1;
+ glBegin(GL_LINES);
+ glVertex3fv(vec);
+ vec[0]= cent[0] + *(sinval+a+start) * (vx[0] * (float)(-a+31)/(float)tot) + *(cosval+a+start) * (vy[0] * (float)(-a+31)/(float)tot);
+ vec[1]= cent[1] + *(sinval+a+start) * (vx[1] * (float)(-a+31)/(float)tot) + *(cosval+a+start) * (vy[1] * (float)(-a+31)/(float)tot);
+ vec[2]= cent[2] + *(sinval+a+start) * (vx[2] * (float)(-a+31)/(float)tot) + *(cosval+a+start) * (vy[2] * (float)(-a+31)/(float)tot);
+ glVertex3fv(vec);
+ glEnd();
+ }
+ }
+}
+
+/* draws a circle on x-z plane given the scaling of the circle, assuming that
+ * all required matrices have been set (used for drawing empties)
+ */
+static void drawcircle_size(float size)
+{
+ float x, y;
+ short degrees;
+
+ glBegin(GL_LINE_LOOP);
+
+ /* coordinates are: cos(degrees*11.25)=x, sin(degrees*11.25)=y, 0.0f=z */
+ for (degrees=0; degrees<32; degrees++) {
+ x= *(cosval + degrees);
+ y= *(sinval + degrees);
+
+ glVertex3f(x*size, 0.0f, y*size);
+ }
+
+ glEnd();
+
+}
+
+void drawcircball(int mode, float *cent, float rad, float tmat[][4])
+{
+ float vec[3], vx[3], vy[3];
+ int a, tot=32;
+
+ VECCOPY(vx, tmat[0]);
+ VECCOPY(vy, tmat[1]);
+ VecMulf(vx, rad);
+ VecMulf(vy, rad);
+
+ glBegin(mode);
+ for(a=0; a<tot; a++) {
+ vec[0]= cent[0] + *(sinval+a) * vx[0] + *(cosval+a) * vy[0];
+ vec[1]= cent[1] + *(sinval+a) * vx[1] + *(cosval+a) * vy[1];
+ vec[2]= cent[2] + *(sinval+a) * vx[2] + *(cosval+a) * vy[2];
+ glVertex3fv(vec);
+ }
+ glEnd();
+}
+
+/* return 1 if nothing was drawn */
+static int drawmball(Base *base, int dt)
+{
+ Object *ob= base->object;
+ MetaBall *mb;
+ MetaElem *ml;
+ float imat[4][4], tmat[4][4];
+ int code= 1;
+
+ mb= ob->data;
+
+ if(ob==G.obedit) {
+ BIF_ThemeColor(TH_WIRE);
+ if((G.f & G_PICKSEL)==0 ) drawDispList(base, dt);
+ ml= editelems.first;
+ }
+ else {
+ if((base->flag & OB_FROMDUPLI)==0)
+ drawDispList(base, dt);
+ ml= mb->elems.first;
+ }
+
+ if(ml==NULL) return 1;
+
+ /* in case solid draw, reset wire colors */
+ if(ob!=G.obedit && (ob->flag & SELECT)) {
+ if(ob==OBACT) BIF_ThemeColor(TH_ACTIVE);
+ else BIF_ThemeColor(TH_SELECT);
+ }
+ else BIF_ThemeColor(TH_WIRE);
+
+ mygetmatrix(tmat);
+ Mat4Invert(imat, tmat);
+ Normalize(imat[0]);
+ Normalize(imat[1]);
+
+ while(ml) {
+
+ /* draw radius */
+ if(ob==G.obedit) {
+ if((ml->flag & SELECT) && (ml->flag & MB_SCALE_RAD)) cpack(0xA0A0F0);
+ else cpack(0x3030A0);
+
+ if(G.f & G_PICKSEL) {
+ ml->selcol1= code;
+ glLoadName(code++);
+ }
+ }
+ drawcircball(GL_LINE_LOOP, &(ml->x), ml->rad, imat);
+
+ /* draw stiffness */
+ if(ob==G.obedit) {
+ if((ml->flag & SELECT) && !(ml->flag & MB_SCALE_RAD)) cpack(0xA0F0A0);
+ else cpack(0x30A030);
+
+ if(G.f & G_PICKSEL) {
+ ml->selcol2= code;
+ glLoadName(code++);
+ }
+ drawcircball(GL_LINE_LOOP, &(ml->x), ml->rad*atan(ml->s)/M_PI_2, imat);
+ }
+
+ ml= ml->next;
+ }
+ return 0;
+}
+
+static void draw_forcefield(Object *ob)
+{
+ PartDeflect *pd= ob->pd;
+ float imat[4][4], tmat[4][4];
+ float vec[3]= {0.0, 0.0, 0.0};
+ int curcol;
+ float size;
+
+ if(ob!=G.obedit && (ob->flag & SELECT)) {
+ if(ob==OBACT) curcol= TH_ACTIVE;
+ else curcol= TH_SELECT;
+ }
+ else curcol= TH_WIRE;
+
+ /* scale size of circle etc with the empty drawsize */
+ if (ob->type == OB_EMPTY) size = ob->empty_drawsize;
+ else size = 1.0;
+
+ /* calculus here, is reused in PFIELD_FORCE */
+ mygetmatrix(tmat);
+ Mat4Invert(imat, tmat);
+// Normalize(imat[0]); // we don't do this because field doesnt scale either... apart from wind!
+// Normalize(imat[1]);
+
+ if (pd->forcefield == PFIELD_WIND) {
+ float force_val;
+
+ Mat4One(tmat);
+ BIF_ThemeColorBlend(curcol, TH_BACK, 0.5);
+
+ if (has_ipo_code(ob->ipo, OB_PD_FSTR))
+ force_val = IPO_GetFloatValue(ob->ipo, OB_PD_FSTR, G.scene->r.cfra);
+ else
+ force_val = pd->f_strength;
+ force_val*= 0.1;
+ drawcircball(GL_LINE_LOOP, vec, size, tmat);
+ vec[2]= 0.5*force_val;
+ drawcircball(GL_LINE_LOOP, vec, size, tmat);
+ vec[2]= 1.0*force_val;
+ drawcircball(GL_LINE_LOOP, vec, size, tmat);
+ vec[2]= 1.5*force_val;
+ drawcircball(GL_LINE_LOOP, vec, size, tmat);
+
+ }
+ else if (pd->forcefield == PFIELD_FORCE) {
+ float ffall_val;
+
+ if (has_ipo_code(ob->ipo, OB_PD_FFALL))
+ ffall_val = IPO_GetFloatValue(ob->ipo, OB_PD_FFALL, G.scene->r.cfra);
+ else
+ ffall_val = pd->f_power;
+
+ BIF_ThemeColorBlend(curcol, TH_BACK, 0.5);
+ drawcircball(GL_LINE_LOOP, vec, size, imat);
+ BIF_ThemeColorBlend(curcol, TH_BACK, 0.9 - 0.4 / pow(1.5, (double)ffall_val));
+ drawcircball(GL_LINE_LOOP, vec, size*1.5, imat);
+ BIF_ThemeColorBlend(curcol, TH_BACK, 0.9 - 0.4 / pow(2.0, (double)ffall_val));
+ drawcircball(GL_LINE_LOOP, vec, size*2.0, imat);
+ }
+ else if (pd->forcefield == PFIELD_VORTEX) {
+ float ffall_val, force_val;
+
+ Mat4One(imat);
+ if (has_ipo_code(ob->ipo, OB_PD_FFALL))
+ ffall_val = IPO_GetFloatValue(ob->ipo, OB_PD_FFALL, G.scene->r.cfra);
+ else
+ ffall_val = pd->f_power;
+
+ if (has_ipo_code(ob->ipo, OB_PD_FSTR))
+ force_val = IPO_GetFloatValue(ob->ipo, OB_PD_FSTR, G.scene->r.cfra);
+ else
+ force_val = pd->f_strength;
+
+ BIF_ThemeColorBlend(curcol, TH_BACK, 0.7);
+ if (force_val < 0) {
+ drawspiral(vec, size*1.0, imat, 1);
+ drawspiral(vec, size*1.0, imat, 16);
+ }
+ else {
+ drawspiral(vec, size*1.0, imat, -1);
+ drawspiral(vec, size*1.0, imat, -16);
+ }
+ }
+ else if (pd->forcefield == PFIELD_GUIDE && ob->type==OB_CURVE) {
+ Curve *cu= ob->data;
+ if((cu->flag & CU_PATH) && cu->path && cu->path->data) {
+ float mindist, guidevec1[4], guidevec2[3];
+
+ if (has_ipo_code(ob->ipo, OB_PD_FSTR))
+ mindist = IPO_GetFloatValue(ob->ipo, OB_PD_FSTR, G.scene->r.cfra);
+ else
+ mindist = pd->f_strength;
+
+ /*path end*/
+ setlinestyle(3);
+ where_on_path(ob, 1.0f, guidevec1, guidevec2);
+ BIF_ThemeColorBlend(curcol, TH_BACK, 0.5);
+ drawcircball(GL_LINE_LOOP, guidevec1, mindist, imat);
+
+ /*path beginning*/
+ setlinestyle(0);
+ where_on_path(ob, 0.0f, guidevec1, guidevec2);
+ BIF_ThemeColorBlend(curcol, TH_BACK, 0.5);
+ drawcircball(GL_LINE_LOOP, guidevec1, mindist, imat);
+
+ VECCOPY(vec, guidevec1); /* max center */
+ }
+ }
+
+ /* as last, guide curve alters it */
+ if(pd->flag & PFIELD_USEMAX) {
+ setlinestyle(3);
+ BIF_ThemeColorBlend(curcol, TH_BACK, 0.5);
+ drawcircball(GL_LINE_LOOP, vec, pd->maxdist, imat);
+ setlinestyle(0);
+ }
+}
+
+static void draw_box(float vec[8][3])
+{
+ glBegin(GL_LINE_STRIP);
+ glVertex3fv(vec[0]); glVertex3fv(vec[1]);glVertex3fv(vec[2]); glVertex3fv(vec[3]);
+ glVertex3fv(vec[0]); glVertex3fv(vec[4]);glVertex3fv(vec[5]); glVertex3fv(vec[6]);
+ glVertex3fv(vec[7]); glVertex3fv(vec[4]);
+ glEnd();
+
+ glBegin(GL_LINES);
+ glVertex3fv(vec[1]); glVertex3fv(vec[5]);
+ glVertex3fv(vec[2]); glVertex3fv(vec[6]);
+ glVertex3fv(vec[3]); glVertex3fv(vec[7]);
+ glEnd();
+}
+
+/* uses boundbox, function used by Ketsji */
+void get_local_bounds(Object *ob, float *center, float *size)
+{
+ BoundBox *bb= object_get_boundbox(ob);
+
+ if(bb==NULL) {
+ center[0]= center[1]= center[2]= 0.0;
+ VECCOPY(size, ob->size);
+ }
+ else {
+ size[0]= 0.5*fabs(bb->vec[0][0] - bb->vec[4][0]);
+ size[1]= 0.5*fabs(bb->vec[0][1] - bb->vec[2][1]);
+ size[2]= 0.5*fabs(bb->vec[0][2] - bb->vec[1][2]);
+
+ center[0]= (bb->vec[0][0] + bb->vec[4][0])/2.0;
+ center[1]= (bb->vec[0][1] + bb->vec[2][1])/2.0;
+ center[2]= (bb->vec[0][2] + bb->vec[1][2])/2.0;
+ }
+}
+
+
+
+static void draw_bb_quadric(BoundBox *bb, short type)
+{
+ float size[3], cent[3];
+ GLUquadricObj *qobj = gluNewQuadric();
+
+ gluQuadricDrawStyle(qobj, GLU_SILHOUETTE);
+
+ size[0]= 0.5*fabs(bb->vec[0][0] - bb->vec[4][0]);
+ size[1]= 0.5*fabs(bb->vec[0][1] - bb->vec[2][1]);
+ size[2]= 0.5*fabs(bb->vec[0][2] - bb->vec[1][2]);
+
+ cent[0]= (bb->vec[0][0] + bb->vec[4][0])/2.0;
+ cent[1]= (bb->vec[0][1] + bb->vec[2][1])/2.0;
+ cent[2]= (bb->vec[0][2] + bb->vec[1][2])/2.0;
+
+ glPushMatrix();
+ if(type==OB_BOUND_SPHERE) {
+ glTranslatef(cent[0], cent[1], cent[2]);
+ glScalef(size[0], size[1], size[2]);
+ gluSphere(qobj, 1.0, 8, 5);
+ }
+ else if(type==OB_BOUND_CYLINDER) {
+ float radius = size[0] > size[1] ? size[0] : size[1];
+ glTranslatef(cent[0], cent[1], cent[2]-size[2]);
+ glScalef(radius, radius, 2.0*size[2]);
+ gluCylinder(qobj, 1.0, 1.0, 1.0, 8, 1);
+ }
+ else if(type==OB_BOUND_CONE) {
+ float radius = size[0] > size[1] ? size[0] : size[1];
+ glTranslatef(cent[0], cent[2]-size[2], cent[1]);
+ glScalef(radius, 2.0*size[2], radius);
+ glRotatef(-90., 1.0, 0.0, 0.0);
+ gluCylinder(qobj, 1.0, 0.0, 1.0, 8, 1);
+ }
+ glPopMatrix();
+
+ gluDeleteQuadric(qobj);
+}
+
+static void draw_bounding_volume(Object *ob)
+{
+ BoundBox *bb=0;
+
+ if(ob->type==OB_MESH) {
+ bb= mesh_get_bb(ob->data);
+ }
+ else if ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT) {
+ bb= ( (Curve *)ob->data )->bb;
+ }
+ else if(ob->type==OB_MBALL) {
+ bb= ob->bb;
+ if(bb==0) {
+ makeDispListMBall(ob);
+ bb= ob->bb;
+ }
+ }
+ else {
+ drawcube();
+ return;
+ }
+
+ if(bb==0) return;
+
+ if(ob->boundtype==OB_BOUND_BOX) draw_box(bb->vec);
+ else draw_bb_quadric(bb, ob->boundtype);
+
+}
+
+static void drawtexspace(Object *ob)
+{
+ float vec[8][3], loc[3], size[3];
+
+ if(ob->type==OB_MESH) {
+ mesh_get_texspace(ob->data, loc, NULL, size);
+ }
+ else if ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT) {
+ Curve *cu= ob->data;
+ VECCOPY(size, cu->size);
+ VECCOPY(loc, cu->loc);
+ }
+ else if(ob->type==OB_MBALL) {
+ MetaBall *mb= ob->data;
+ VECCOPY(size, mb->size);
+ VECCOPY(loc, mb->loc);
+ }
+ else return;
+
+ vec[0][0]=vec[1][0]=vec[2][0]=vec[3][0]= loc[0]-size[0];
+ vec[4][0]=vec[5][0]=vec[6][0]=vec[7][0]= loc[0]+size[0];
+
+ vec[0][1]=vec[1][1]=vec[4][1]=vec[5][1]= loc[1]-size[1];
+ vec[2][1]=vec[3][1]=vec[6][1]=vec[7][1]= loc[1]+size[1];
+
+ vec[0][2]=vec[3][2]=vec[4][2]=vec[7][2]= loc[2]-size[2];
+ vec[1][2]=vec[2][2]=vec[5][2]=vec[6][2]= loc[2]+size[2];
+
+ setlinestyle(2);
+
+ draw_box(vec);
+
+ setlinestyle(0);
+}
+
+/* draws wire outline */
+static void drawSolidSelect(Base *base)
+{
+ Object *ob= base->object;
+
+ glLineWidth(2.0);
+ glDepthMask(0);
+
+ if(ELEM3(ob->type, OB_FONT,OB_CURVE, OB_SURF)) {
+ Curve *cu = ob->data;
+ if (displist_has_faces(&cu->disp) && boundbox_clip(ob->obmat, cu->bb)) {
+ draw_index_wire= 0;
+ drawDispListwire(&cu->disp);
+ draw_index_wire= 1;
+ }
+ } else if (ob->type==OB_MBALL) {
+ if((base->flag & OB_FROMDUPLI)==0)
+ drawDispListwire(&ob->disp);
+ }
+ else if(ob->type==OB_ARMATURE) {
+ if(!(ob->flag & OB_POSEMODE)) {
+ draw_armature(base, OB_WIRE);
+ }
+ }
+
+ glLineWidth(1.0);
+ glDepthMask(1);
+}
+
+static void drawWireExtra(Object *ob)
+{
+ if(ob!=G.obedit && (ob->flag & SELECT)) {
+ if(ob==OBACT) {
+ if(ob->flag & OB_FROMGROUP) BIF_ThemeColor(TH_GROUP_ACTIVE);
+ else BIF_ThemeColor(TH_ACTIVE);
+ }
+ else if(ob->flag & OB_FROMGROUP)
+ BIF_ThemeColorShade(TH_GROUP_ACTIVE, -16);
+ else
+ BIF_ThemeColor(TH_SELECT);
+ }
+ else {
+ if(ob->flag & OB_FROMGROUP)
+ BIF_ThemeColor(TH_GROUP);
+ else {
+ if(ob->dtx & OB_DRAWWIRE) {
+ glColor3ub(80,80,80);
+ } else {
+ BIF_ThemeColor(TH_WIRE);
+ }
+ }
+ }
+
+ bglPolygonOffset(1.0);
+ glDepthMask(0); // disable write in zbuffer, selected edge wires show better
+
+ if (ELEM3(ob->type, OB_FONT, OB_CURVE, OB_SURF)) {
+ Curve *cu = ob->data;
+ if (boundbox_clip(ob->obmat, cu->bb)) {
+ if (ob->type==OB_CURVE)
+ draw_index_wire= 0;
+ drawDispListwire(&cu->disp);
+ if (ob->type==OB_CURVE)
+ draw_index_wire= 1;
+ }
+ } else if (ob->type==OB_MBALL) {
+ drawDispListwire(&ob->disp);
+ }
+
+ glDepthMask(1);
+ bglPolygonOffset(0.0);
+}
+
+/* should be called in view space */
+static void draw_hooks(Object *ob)
+{
+ ModifierData *md;
+ float vec[3];
+
+ for (md=ob->modifiers.first; md; md=md->next) {
+ if (md->type==eModifierType_Hook) {
+ HookModifierData *hmd = (HookModifierData*) md;
+
+ VecMat4MulVecfl(vec, ob->obmat, hmd->cent);
+
+ if(hmd->object) {
+ setlinestyle(3);
+ glBegin(GL_LINES);
+ glVertex3fv(hmd->object->obmat[3]);
+ glVertex3fv(vec);
+ glEnd();
+ setlinestyle(0);
+ }
+
+ glPointSize(3.0);
+ bglBegin(GL_POINTS);
+ bglVertex3fv(vec);
+ bglEnd();
+ glPointSize(1.0);
+ }
+ }
+}
+
+
+//<rcruiz>
+void drawRBpivot(bRigidBodyJointConstraint *data){
+ float radsPerDeg = 6.283185307179586232f / 360.f;
+ int axis;
+ float v1[3]= {data->pivX, data->pivY, data->pivZ};
+ float eu[3]= {radsPerDeg*data->axX, radsPerDeg*data->axY, radsPerDeg*data->axZ};
+
+
+
+ float mat[4][4];
+ EulToMat4(eu,mat);
+ glLineWidth (4.0f);
+ setlinestyle(2);
+ for (axis=0; axis<3; axis++) {
+ float dir[3] = {0,0,0};
+ float v[3]= {data->pivX, data->pivY, data->pivZ};
+
+ dir[axis] = 1.f;
+ glBegin(GL_LINES);
+ Mat4MulVecfl(mat,dir);
+ v[0] += dir[0];
+ v[1] += dir[1];
+ v[2] += dir[2];
+ glVertex3fv(v1);
+ glVertex3fv(v);
+ glEnd();
+ glRasterPos3fv(v);
+ if (axis==0)
+ BMF_DrawString(G.font, "px");
+ else if (axis==1)
+ BMF_DrawString(G.font, "py");
+ else
+ BMF_DrawString(G.font, "pz");
+ }
+ glLineWidth (1.0f);
+ setlinestyle(0);
+}
+
+/* flag can be DRAW_PICKING and/or DRAW_CONSTCOLOR */
+void draw_object(Base *base, int flag)
+{
+ static int warning_recursive= 0;
+ Object *ob;
+ Curve *cu;
+ float cfraont;
+ float vec1[3], vec2[3];
+ unsigned int col=0;
+ int sel, drawtype, colindex= 0, ipoflag;
+ int i, selstart, selend, empty_object=0;
+ short dt, dtx, zbufoff= 0;
+
+ /* only once set now, will be removed too, should become a global standard */
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ ob= base->object;
+
+ if (ob!=G.obedit) {
+ if (ob->restrictflag & OB_RESTRICT_VIEW)
+ return;
+ }
+
+ /* xray delay? */
+ if((flag & DRAW_PICKING)==0 && (base->flag & OB_FROMDUPLI)==0) {
+ /* xray and transp are set when it is drawing the 2nd/3rd pass */
+ if(!G.vd->xray && !G.vd->transp && (ob->dtx & OB_DRAWXRAY)) {
+ add_view3d_after(G.vd, base, V3D_XRAY);
+ return;
+ }
+ }
+
+ /* draw keys? */
+ if(base==(G.scene->basact) || (base->flag & (SELECT+BA_WAS_SEL))) {
+ if(flag==0 && warning_recursive==0 && ob!=G.obedit) {
+ if(ob->ipo && ob->ipo->showkey && (ob->ipoflag & OB_DRAWKEY)) {
+ ListBase elems;
+ CfraElem *ce;
+ float temp[7][3];
+
+ warning_recursive= 1;
+
+ elems.first= elems.last= 0;
+ make_cfra_list(ob->ipo, &elems);
+
+ cfraont= (G.scene->r.cfra);
+ drawtype= G.vd->drawtype;
+ if(drawtype>OB_WIRE) G.vd->drawtype= OB_WIRE;
+ sel= base->flag;
+ memcpy(temp, &ob->loc, 7*3*sizeof(float));
+
+ ipoflag= ob->ipoflag;
+ ob->ipoflag &= ~OB_OFFS_OB;
+
+ set_no_parent_ipo(1);
+ disable_speed_curve(1);
+
+ if ((ob->ipoflag & OB_DRAWKEYSEL)==0) {
+ ce= elems.first;
+ while(ce) {
+ if(!ce->sel) {
+ (G.scene->r.cfra)= ce->cfra/G.scene->r.framelen;
+
+ base->flag= 0;
+
+ where_is_object_time(ob, (G.scene->r.cfra));
+ draw_object(base, 0);
+ }
+ ce= ce->next;
+ }
+ }
+
+ ce= elems.first;
+ while(ce) {
+ if(ce->sel) {
+ (G.scene->r.cfra)= ce->cfra/G.scene->r.framelen;
+
+ base->flag= SELECT;
+
+ where_is_object_time(ob, (G.scene->r.cfra));
+ draw_object(base, 0);
+ }
+ ce= ce->next;
+ }
+
+ set_no_parent_ipo(0);
+ disable_speed_curve(0);
+
+ base->flag= sel;
+ ob->ipoflag= ipoflag;
+
+ /* restore icu->curval */
+ (G.scene->r.cfra)= cfraont;
+
+ memcpy(&ob->loc, temp, 7*3*sizeof(float));
+ where_is_object(ob);
+ G.vd->drawtype= drawtype;
+
+ BLI_freelistN(&elems);
+
+ warning_recursive= 0;
+ }
+ }
+ }
+
+ /* patch? children objects with a timeoffs change the parents. How to solve! */
+ /* if( ((int)ob->ctime) != F_(G.scene->r.cfra)) where_is_object(ob); */
+
+ mymultmatrix(ob->obmat);
+
+ /* which wire color */
+ if((flag & DRAW_CONSTCOLOR) == 0) {
+ project_short(ob->obmat[3], &base->sx);
+
+ if((G.moving & G_TRANSFORM_OBJ) && (base->flag & (SELECT+BA_WAS_SEL))) BIF_ThemeColor(TH_TRANSFORM);
+ else {
+
+ if(ob->type==OB_LAMP) BIF_ThemeColor(TH_LAMP);
+ else BIF_ThemeColor(TH_WIRE);
+
+ if((G.scene->basact)==base) {
+ if(base->flag & (SELECT+BA_WAS_SEL)) BIF_ThemeColor(TH_ACTIVE);
+ }
+ else {
+ if(base->flag & (SELECT+BA_WAS_SEL)) BIF_ThemeColor(TH_SELECT);
+ }
+
+ // no theme yet
+ if(ob->id.lib) {
+ if(base->flag & (SELECT+BA_WAS_SEL)) colindex = 4;
+ else colindex = 3;
+ }
+ else if(warning_recursive==1) {
+ if(base->flag & (SELECT+BA_WAS_SEL)) {
+ if(G.scene->basact==base) colindex = 8;
+ else colindex= 7;
+ }
+ else colindex = 6;
+ }
+ else if(ob->flag & OB_FROMGROUP) {
+ if(base->flag & (SELECT+BA_WAS_SEL)) {
+ if(G.scene->basact==base) BIF_ThemeColor(TH_GROUP_ACTIVE);
+ else BIF_ThemeColorShade(TH_GROUP_ACTIVE, -16);
+ }
+ else BIF_ThemeColor(TH_GROUP);
+ colindex= 0;
+ }
+
+ }
+
+ if(colindex) {
+ col= colortab[colindex];
+ cpack(col);
+ }
+ }
+
+ /* maximum drawtype */
+ dt= MIN2(G.vd->drawtype, ob->dt);
+ if(G.vd->zbuf==0 && dt>OB_WIRE) dt= OB_WIRE;
+ dtx= 0;
+
+ /* faceselect exception: also draw solid when dt==wire, except in editmode */
+ if(ob==OBACT && (G.f & (G_VERTEXPAINT+G_TEXTUREPAINT+G_WEIGHTPAINT))) {
+ if(ob->type==OB_MESH) {
+
+ if(ob==G.obedit);
+ else {
+ dt= OB_SHADED;
+
+ glClearDepth(1.0); glClear(GL_DEPTH_BUFFER_BIT);
+ glEnable(GL_DEPTH_TEST);
+ if(dt<OB_SOLID) zbufoff= 1;
+ }
+ }
+ else {
+ if(dt<OB_SOLID) {
+ dt= OB_SOLID;
+ glClearDepth(1.); glClear(GL_DEPTH_BUFFER_BIT);
+ glEnable(GL_DEPTH_TEST);
+ zbufoff= 1;
+ }
+ }
+ }
+
+ /* draw-extra supported for boundbox drawmode too */
+ if(dt>=OB_BOUNDBOX ) {
+
+ dtx= ob->dtx;
+ if(G.obedit==ob) {
+ // the only 2 extra drawtypes alowed in editmode
+ dtx= dtx & (OB_DRAWWIRE|OB_TEXSPACE);
+ }
+
+ if(G.f & G_DRAW_EXT) {
+ if(ob->type==OB_EMPTY || ob->type==OB_CAMERA || ob->type==OB_LAMP) dt= OB_WIRE;
+ }
+ }
+
+ /* draw outline for selected solid objects, mesh does itself */
+ if((G.vd->flag & V3D_SELECT_OUTLINE) && ob->type!=OB_MESH) {
+ if(dt>OB_WIRE && dt<OB_TEXTURE && ob!=G.obedit) {
+ if (!(ob->dtx&OB_DRAWWIRE) && (ob->flag&SELECT) && !(flag&DRAW_PICKING)) {
+ drawSolidSelect(base);
+ }
+ }
+ }
+
+ switch( ob->type) {
+ case OB_MESH:
+ if (!(base->flag&OB_RADIO)) {
+ empty_object= draw_mesh_object(base, dt, flag);
+ if(flag!=DRAW_CONSTCOLOR) dtx &= ~OB_DRAWWIRE; // mesh draws wire itself
+
+ if(G.obedit!=ob && warning_recursive==0) {
+ PartEff *paf = give_parteff(ob);
+
+ if(paf) {
+ if(col || (ob->flag & SELECT)) cpack(0xFFFFFF); /* for visibility, also while wpaint */
+ if(paf->flag & PAF_STATIC) draw_static_particle_system(ob, paf, dt);
+ else if((flag & DRAW_PICKING) == 0) draw_particle_system(base, paf); // selection errors happen to easy
+ if(col) cpack(col);
+ }
+ }
+ }
+
+ break;
+ case OB_FONT:
+ cu= ob->data;
+ if (cu->disp.first==NULL) makeDispListCurveTypes(ob, 0);
+ if(ob==G.obedit) {
+ tekentextcurs();
+
+ if (cu->flag & CU_FAST) {
+ cpack(0xFFFFFF);
+ set_inverted_drawing(1);
+ drawDispList(base, OB_WIRE);
+ set_inverted_drawing(0);
+ } else {
+ drawDispList(base, dt);
+ }
+
+ if (cu->linewidth != 0.0) {
+ cpack(0xff44ff);
+ BIF_ThemeColor(TH_WIRE);
+ VECCOPY(vec1, ob->orig);
+ VECCOPY(vec2, ob->orig);
+ vec1[0] += cu->linewidth;
+ vec2[0] += cu->linewidth;
+ vec1[1] += cu->linedist * cu->fsize;
+ vec2[1] -= cu->lines * cu->linedist * cu->fsize;
+ setlinestyle(3);
+ glBegin(GL_LINE_STRIP);
+ glVertex2fv(vec1);
+ glVertex2fv(vec2);
+ glEnd();
+ setlinestyle(0);
+ }
+
+ setlinestyle(3);
+ for (i=0; i<cu->totbox; i++) {
+ if (cu->tb[i].w != 0.0) {
+ if (i == (cu->actbox-1))
+ BIF_ThemeColor(TH_ACTIVE);
+ else
+ BIF_ThemeColor(TH_WIRE);
+ vec1[0] = cu->tb[i].x;
+ vec1[1] = cu->tb[i].y + cu->fsize;
+ vec1[2] = 0.001;
+ glBegin(GL_LINE_STRIP);
+ glVertex3fv(vec1);
+ vec1[0] += cu->tb[i].w;
+ glVertex3fv(vec1);
+ vec1[1] -= cu->tb[i].h;
+ glVertex3fv(vec1);
+ vec1[0] -= cu->tb[i].w;
+ glVertex3fv(vec1);
+ vec1[1] += cu->tb[i].h;
+ glVertex3fv(vec1);
+ glEnd();
+ }
+ }
+ setlinestyle(0);
+
+
+ if (getselection(&selstart, &selend) && selboxes) {
+ float selboxw;
+
+ cpack(0xffffff);
+ set_inverted_drawing(1);
+ for (i=0; i<(selend-selstart+1); i++) {
+ SelBox *sb = &(selboxes[i]);
+
+ if (i<(selend-selstart)) {
+ if (selboxes[i+1].y == sb->y)
+ selboxw= selboxes[i+1].x - sb->x;
+ else
+ selboxw= sb->w;
+ }
+ else {
+ selboxw= sb->w;
+ }
+ glBegin(GL_QUADS);
+ glVertex3f(sb->x, sb->y, 0.001);
+ glVertex3f(sb->x+selboxw, sb->y, 0.001);
+ glVertex3f(sb->x+selboxw, sb->y+sb->h, 0.001);
+ glVertex3f(sb->x, sb->y+sb->h, 0.001);
+ glEnd();
+ }
+ set_inverted_drawing(0);
+ }
+ }
+ else if(dt==OB_BOUNDBOX)
+ draw_bounding_volume(ob);
+ else if(boundbox_clip(ob->obmat, cu->bb))
+ empty_object= drawDispList(base, dt);
+
+ break;
+ case OB_CURVE:
+ case OB_SURF:
+ cu= ob->data;
+ /* still needed for curves hidden in other layers. depgraph doesnt handle that yet */
+ if (cu->disp.first==NULL) makeDispListCurveTypes(ob, 0);
+
+ if(ob==G.obedit) {
+ drawnurb(base, editNurb.first, dt);
+ }
+ else if(dt==OB_BOUNDBOX)
+ draw_bounding_volume(ob);
+ else if(boundbox_clip(ob->obmat, cu->bb)) {
+ empty_object= drawDispList(base, dt);
+
+ if(cu->path)
+ curve_draw_speed(ob);
+ }
+ break;
+ case OB_MBALL:
+ if(ob==G.obedit)
+ drawmball(base, dt);
+ else if(dt==OB_BOUNDBOX)
+ draw_bounding_volume(ob);
+ else
+ empty_object= drawmball(base, dt);
+ break;
+ case OB_EMPTY:
+ drawaxes(ob->empty_drawsize, flag, ob->empty_drawtype);
+ break;
+ case OB_LAMP:
+ drawlamp(ob);
+ if(dtx || (base->flag & SELECT)) mymultmatrix(ob->obmat);
+ break;
+ case OB_CAMERA:
+ drawcamera(ob, flag);
+ break;
+ case OB_LATTICE:
+ drawlattice(ob);
+ break;
+ case OB_ARMATURE:
+ if(dt>OB_WIRE) set_gl_material(0); // we use defmaterial
+ empty_object= draw_armature(base, dt);
+ break;
+ default:
+ drawaxes(1.0, flag, OB_ARROWS);
+ }
+ if(ob->pd && ob->pd->forcefield) draw_forcefield(ob);
+
+ {
+ bConstraint *con;
+ for(con=ob->constraints.first; con; con= con->next)
+ {
+ if(con->type==CONSTRAINT_TYPE_RIGIDBODYJOINT)
+ {
+ bRigidBodyJointConstraint *data = (bRigidBodyJointConstraint*)con->data;
+ if(data->flag&CONSTRAINT_DRAW_PIVOT)
+ drawRBpivot(data);
+ }
+ }
+ }
+
+ /* draw extra: after normal draw because of makeDispList */
+ if(dtx) {
+ if(G.f & G_SIMULATION);
+ else if(dtx & OB_AXIS) {
+ drawaxes(1.0f, flag, OB_ARROWS);
+ }
+ if(dtx & OB_BOUNDBOX) draw_bounding_volume(ob);
+ if(dtx & OB_TEXSPACE) drawtexspace(ob);
+ if(dtx & OB_DRAWNAME) {
+ /* patch for several 3d cards (IBM mostly) that crash on glSelect with text drawing */
+ /* but, we also dont draw names for sets or duplicators */
+ if(flag == 0) {
+ glRasterPos3f(0.0, 0.0, 0.0);
+
+ BMF_DrawString(G.font, " ");
+ BMF_DrawString(G.font, ob->id.name+2);
+ }
+ }
+ /*if(dtx & OB_DRAWIMAGE) drawDispListwire(&ob->disp);*/
+ if((dtx & OB_DRAWWIRE) && dt>=OB_SOLID) drawWireExtra(ob);
+ }
+
+ if(dt<OB_SHADED) {
+ if((ob->gameflag & OB_ACTOR) && (ob->gameflag & OB_DYNAMIC)) {
+ float tmat[4][4], imat[4][4], vec[3];
+
+ vec[0]= vec[1]= vec[2]= 0.0;
+ mygetmatrix(tmat);
+ Mat4Invert(imat, tmat);
+
+ setlinestyle(2);
+ drawcircball(GL_LINE_LOOP, vec, ob->inertia, imat);
+ setlinestyle(0);
+ }
+ }
+
+ myloadmatrix(G.vd->viewmat);
+
+ if(zbufoff) glDisable(GL_DEPTH_TEST);
+
+ if(warning_recursive) return;
+ if(base->flag & (OB_FROMDUPLI|OB_RADIO)) return;
+ if(G.f & G_SIMULATION) return;
+
+ /* object centers, need to be drawn in viewmat space for speed, but OK for picking select */
+ if(ob!=OBACT || (G.f & (G_VERTEXPAINT|G_TEXTUREPAINT|G_WEIGHTPAINT))==0) {
+ int do_draw_center= -1; /* defines below are zero or positive... */
+
+ if((G.scene->basact)==base)
+ do_draw_center= ACTIVE;
+ else if(base->flag & SELECT)
+ do_draw_center= SELECT;
+ else if(empty_object || (G.vd->flag & V3D_DRAW_CENTERS))
+ do_draw_center= DESELECT;
+
+ if(do_draw_center != -1) {
+ if(flag & DRAW_PICKING) {
+ /* draw a single point for opengl selection */
+ glBegin(GL_POINTS);
+ glVertex3fv(ob->obmat[3]);
+ glEnd();
+ }
+ else if((flag & DRAW_CONSTCOLOR)==0) {
+ /* we don't draw centers for duplicators and sets */
+#ifdef WITH_VERSE
+ if(ob->vnode)
+ drawcentercircle(ob->obmat[3], VERSE, 1);
+ else
+#endif
+ drawcentercircle(ob->obmat[3], do_draw_center, ob->id.lib || ob->id.us>1);
+ }
+ }
+ }
+
+ /* not for sets, duplicators or picking */
+ if(flag==0 && (!(G.vd->flag & V3D_HIDE_HELPLINES))) {
+ ListBase *list;
+
+ /* draw hook center and offset line */
+ if(ob!=G.obedit) draw_hooks(ob);
+
+ /* help lines and so */
+ if(ob!=G.obedit && ob->parent && (ob->parent->lay & G.vd->lay)) {
+ setlinestyle(3);
+ glBegin(GL_LINES);
+ glVertex3fv(ob->obmat[3]);
+ glVertex3fv(ob->orig);
+ glEnd();
+ setlinestyle(0);
+ }
+
+ /* Drawing the constraint lines */
+ list = &ob->constraints;
+ if (list) {
+ bConstraint *curcon;
+ bConstraintOb *cob;
+ char col[4], col2[4];
+
+ BIF_GetThemeColor3ubv(TH_GRID, col);
+ make_axis_color(col, col2, 'z');
+ glColor3ubv((GLubyte *)col2);
+
+ cob= constraints_make_evalob(ob, NULL, CONSTRAINT_OBTYPE_OBJECT);
+
+ for (curcon = list->first; curcon; curcon=curcon->next) {
+ bConstraintTypeInfo *cti= constraint_get_typeinfo(curcon);
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+
+ if ((curcon->flag & CONSTRAINT_EXPAND) && (cti) && (cti->get_constraint_targets)) {
+ cti->get_constraint_targets(curcon, &targets);
+
+ for (ct= targets.first; ct; ct= ct->next) {
+ /* calculate target's matrix */
+ if (cti->get_target_matrix)
+ cti->get_target_matrix(curcon, cob, ct, bsystem_time(ob, (float)(G.scene->r.cfra), ob->sf));
+ else
+ Mat4One(ct->matrix);
+
+ setlinestyle(3);
+ glBegin(GL_LINES);
+ glVertex3fv(ct->matrix[3]);
+ glVertex3fv(ob->obmat[3]);
+ glEnd();
+ setlinestyle(0);
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(curcon, &targets, 1);
+ }
+ }
+
+ constraints_clear_evalob(cob);
+ }
+ }
+
+ free_old_images();
+}
+
+void draw_object_ext(Base *base)
+{
+
+ if(G.vd==NULL || base==NULL) return;
+
+ if(G.vd->drawtype > OB_WIRE) {
+ G.vd->zbuf= 1;
+ glEnable(GL_DEPTH_TEST);
+ }
+
+ G.f |= G_DRAW_EXT;
+
+ glDrawBuffer(GL_FRONT);
+ persp(PERSP_VIEW);
+
+ if(G.vd->flag & V3D_CLIPPING)
+ view3d_set_clipping(G.vd);
+
+ draw_object(base, 0);
+
+ if(G.vd->flag & V3D_CLIPPING)
+ view3d_clr_clipping();
+
+ G.f &= ~G_DRAW_EXT;
+
+ bglFlush(); /* reveil frontbuffer drawing */
+ glDrawBuffer(GL_BACK);
+
+ if(G.vd->zbuf) {
+ G.vd->zbuf= 0;
+ glDisable(GL_DEPTH_TEST);
+ }
+ curarea->win_swap= WIN_FRONT_OK;
+}
+
+/* ***************** BACKBUF SEL (BBS) ********* */
+
+static void bbs_mesh_verts__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s)
+{
+ int offset = (long) userData;
+ EditVert *eve = EM_get_vert_for_index(index);
+
+ if (eve->h==0) {
+ set_framebuffer_index_color(offset+index);
+ bglVertex3fv(co);
+ }
+}
+static int bbs_mesh_verts(DerivedMesh *dm, int offset)
+{
+ glPointSize( BIF_GetThemeValuef(TH_VERTEX_SIZE) );
+ bglBegin(GL_POINTS);
+ dm->foreachMappedVert(dm, bbs_mesh_verts__mapFunc, (void*)(long) offset);
+ bglEnd();
+ glPointSize(1.0);
+
+ return offset + G.totvert;
+}
+
+static int bbs_mesh_wire__setDrawOptions(void *userData, int index)
+{
+ int offset = (long) userData;
+ EditEdge *eed = EM_get_edge_for_index(index);
+
+ if (eed->h==0) {
+ set_framebuffer_index_color(offset+index);
+ return 1;
+ } else {
+ return 0;
+ }
+}
+static int bbs_mesh_wire(DerivedMesh *dm, int offset)
+{
+ dm->drawMappedEdges(dm, bbs_mesh_wire__setDrawOptions, (void*)(long) offset);
+
+ return offset + G.totedge;
+}
+
+static int bbs_mesh_solid__setSolidDrawOptions(void *userData, int index, int *drawSmooth_r)
+{
+ if (EM_get_face_for_index(index)->h==0) {
+ if (userData) {
+ set_framebuffer_index_color(index+1);
+ }
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static void bbs_mesh_solid__drawCenter(void *userData, int index, float *cent, float *no)
+{
+ EditFace *efa = EM_get_face_for_index(index);
+
+ if (efa->h==0 && efa->fgonf!=EM_FGON) {
+ set_framebuffer_index_color(index+1);
+
+ bglVertex3fv(cent);
+ }
+}
+
+/* two options, facecolors or black */
+static int bbs_mesh_solid_EM(DerivedMesh *dm, int facecol)
+{
+ cpack(0);
+
+ if (facecol) {
+ dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, (void*)(long) 1, 0);
+
+ if( (G.scene->selectmode & SCE_SELECT_FACE) &&
+ (G.vd->drawtype<=OB_SOLID)
+ ) {
+ glPointSize(BIF_GetThemeValuef(TH_FACEDOT_SIZE));
+
+ bglBegin(GL_POINTS);
+ dm->foreachMappedFaceCenter(dm, bbs_mesh_solid__drawCenter, NULL);
+ bglEnd();
+ }
+
+ return 1+G.totface;
+ } else {
+ dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, (void*) 0, 0);
+ return 1;
+ }
+}
+
+static int bbs_mesh_solid__setDrawOpts(void *userData, int index, int *drawSmooth_r)
+{
+ Mesh *me = userData;
+
+ if (!(me->mface[index].flag&ME_HIDE)) {
+ set_framebuffer_index_color(index+1);
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static int bbs_mesh_wire__setDrawOpts(void *userData, int index)
+{
+ struct { Mesh *me; EdgeHash *eh; int offset; } *data = userData;
+ MEdge *med = data->me->medge + index;
+ unsigned long flags = (long)BLI_edgehash_lookup(data->eh, med->v1, med->v2);
+
+ if (flags & 1) {
+ set_framebuffer_index_color(data->offset+index);
+ return 1;
+ } else
+ return 0;
+}
+
+/* TODO remove this - since face select mode now only works with painting */
+static void bbs_mesh_solid(Object *ob)
+{
+ DerivedMesh *dm = mesh_get_derived_final(ob, get_viewedit_datamask());
+ Mesh *me = (Mesh*)ob->data;
+
+ glColor3ub(0, 0, 0);
+ dm->drawMappedFaces(dm, bbs_mesh_solid__setDrawOpts, me, 0);
+
+ /* draw edges for seam marking in faceselect mode, but not when painting,
+ so that painting doesn't get interrupted on an edge */
+ if ((G.f & G_FACESELECT) && !(G.f & (G_VERTEXPAINT|G_TEXTUREPAINT|G_WEIGHTPAINT))) {
+ struct { Mesh *me; EdgeHash *eh; int offset; } userData;
+
+ userData.me = me;
+ userData.eh = get_tface_mesh_marked_edge_info(me);
+ userData.offset = userData.me->totface+1;
+
+ bglPolygonOffset(1.0);
+ dm->drawMappedEdges(dm, bbs_mesh_wire__setDrawOpts, (void*)&userData);
+ bglPolygonOffset(0.0);
+
+ BLI_edgehash_free(userData.eh, NULL);
+ }
+
+ dm->release(dm);
+}
+
+void draw_object_backbufsel(Object *ob)
+{
+
+ mymultmatrix(ob->obmat);
+
+ glClearDepth(1.0); glClear(GL_DEPTH_BUFFER_BIT);
+ glEnable(GL_DEPTH_TEST);
+
+ switch( ob->type) {
+ case OB_MESH:
+ if(ob==G.obedit) {
+ DerivedMesh *dm = editmesh_get_derived_cage(CD_MASK_BAREMESH);
+
+ EM_init_index_arrays(1, 1, 1);
+
+ em_solidoffs= bbs_mesh_solid_EM(dm, G.scene->selectmode & SCE_SELECT_FACE);
+
+ bglPolygonOffset(1.0);
+
+ // we draw edges always, for loop (select) tools
+ em_wireoffs= bbs_mesh_wire(dm, em_solidoffs);
+
+ // we draw verts if vert select mode or if in transform (for snap).
+ if(G.scene->selectmode & SCE_SELECT_VERTEX || G.moving & G_TRANSFORM_EDIT)
+ em_vertoffs= bbs_mesh_verts(dm, em_wireoffs);
+ else em_vertoffs= em_wireoffs;
+
+ bglPolygonOffset(0.0);
+
+ dm->release(dm);
+
+ EM_free_index_arrays();
+ }
+ else bbs_mesh_solid(ob);
+
+ break;
+ case OB_CURVE:
+ case OB_SURF:
+ break;
+ }
+
+ myloadmatrix(G.vd->viewmat);
+}
+
+
+/* ************* draw object instances for bones, for example ****************** */
+/* assumes all matrices/etc set OK */
+
+/* helper function for drawing object instances - meshes */
+static void draw_object_mesh_instance(Object *ob, int dt, int outline)
+{
+ DerivedMesh *dm=NULL, *edm=NULL;
+
+ if(G.obedit && ob->data==G.obedit->data)
+ edm= editmesh_get_derived_base();
+ else
+ dm = mesh_get_derived_final(ob, CD_MASK_BAREMESH);
+
+ if(dt<=OB_WIRE) {
+ if(dm)
+ dm->drawEdges(dm, 1);
+ else if(edm)
+ edm->drawEdges(edm, 1);
+ }
+ else {
+ if(outline)
+ draw_mesh_object_outline(ob, dm?dm:edm);
+
+ if(dm)
+ init_gl_materials(ob, 0);
+ else {
+ glEnable(GL_COLOR_MATERIAL);
+ BIF_ThemeColor(TH_BONE_SOLID);
+ glDisable(GL_COLOR_MATERIAL);
+ }
+
+ glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0);
+ glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW);
+ glEnable(GL_LIGHTING);
+
+ if(dm)
+ dm->drawFacesSolid(dm, set_gl_material);
+ else if(edm)
+ edm->drawMappedFaces(edm, NULL, NULL, 0);
+
+ glDisable(GL_LIGHTING);
+ }
+
+ if(edm) edm->release(edm);
+ if(dm) dm->release(dm);
+}
+
+void draw_object_instance(Object *ob, int dt, int outline)
+{
+ if (ob == NULL)
+ return;
+
+ switch (ob->type) {
+ case OB_MESH:
+ draw_object_mesh_instance(ob, dt, outline);
+ break;
+ case OB_EMPTY:
+ drawaxes(ob->empty_drawsize, 0, ob->empty_drawtype);
+ break;
+ }
+}
+
diff --git a/source/blender/src/drawoops.c b/source/blender/src/drawoops.c
new file mode 100644
index 00000000000..ef32d2c7039
--- /dev/null
+++ b/source/blender/src/drawoops.c
@@ -0,0 +1,521 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "BMF_Api.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "DNA_ID.h"
+#include "DNA_object_types.h"
+#include "DNA_oops_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_view2d_types.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_global.h"
+
+#include "BIF_interface.h"
+#include "BIF_interface_icons.h"
+#include "BIF_language.h"
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+#include "BIF_mywindow.h"
+#include "BIF_outliner.h"
+#include "BIF_resources.h"
+#include "BIF_screen.h"
+
+/* #include "BIF_drawoops.h" bad name :(*/
+#include "BIF_oops.h"
+
+#include "BSE_drawipo.h"
+#include "BSE_drawoops.h"
+
+float aspect;
+void *font;
+
+
+static float icon_width();
+float center_oops_text(char *str);
+
+
+void boundbox_oops(short sel)
+{
+ Oops *oops;
+ float min[2], max[2];
+ int ok= 0;
+
+ if(G.soops==0) return;
+
+ min[0]= 1000.0;
+ max[0]= -1000.0;
+ min[1]= 1000.0;
+ max[1]= -1000.0;
+
+ oops= G.soops->oops.first;
+ while(oops) {
+ if ((oops->hide==0 && !sel) || (sel && oops->flag & SELECT )) {
+ ok= 1;
+
+ min[0]= MIN2(min[0], oops->x);
+ max[0]= MAX2(max[0], oops->x+OOPSX);
+ min[1]= MIN2(min[1], oops->y);
+ max[1]= MAX2(max[1], oops->y+OOPSY);
+ }
+ oops= oops->next;
+ }
+
+ if(ok==0) return;
+
+ G.v2d->tot.xmin= min[0];
+ G.v2d->tot.xmax= max[0];
+ G.v2d->tot.ymin= min[1];
+ G.v2d->tot.ymax= max[1];
+
+}
+
+void give_oopslink_line(Oops *oops, OopsLink *ol, float *v1, float *v2)
+{
+
+ if(ol->to && ol->to->hide==0) {
+ v1[0]= oops->x+ol->xof;
+ v1[1]= oops->y+ol->yof;
+ v2[0]= ol->to->x+OOPSX/2;
+ v2[1]= ol->to->y;
+ }
+ else if(ol->from && ol->from->hide==0) {
+ v1[0]= ol->from->x + ol->xof;
+ v1[1]= ol->from->y + ol->xof;
+ v2[0]= oops->x+OOPSX/2;
+ v2[1]= oops->y;
+ }
+}
+
+void draw_oopslink(Oops *oops)
+{
+ OopsLink *ol;
+ float vec[4][3], dist, spline_step;
+ short curve_res;
+
+ if(oops->type==ID_SCE || oops->type==ID_GR) {
+ if(oops->flag & SELECT) {
+ /* when using python Mesh to make meshes a file was saved
+ that had an oops with no ID, stops a segfault when looking for lib */
+ if(oops->id && oops->id->lib) cpack(0x4080A0);
+ else cpack(0x808080);
+ }
+ else cpack(0x606060);
+ }
+ else {
+ if(oops->flag & SELECT) {
+ if(oops->id && oops->id->lib) cpack(0x11AAFF);
+ else cpack(0xFFFFFF);
+ }
+ else cpack(0x0);
+ }
+
+ glEnable(GL_MAP1_VERTEX_3);
+ vec[0][2]= vec[1][2]= vec[2][2]= vec[3][2]= 0.0; /* only 2d spline, set the Z to 0*/
+
+ ol= oops->link.first;
+ while(ol) {
+ if(ol->to && ol->to->hide==0) {
+
+ give_oopslink_line(oops, ol, vec[0], vec[3]);
+
+ dist= 0.5*VecLenf(vec[0], vec[3]);
+
+ /* check ol->xof and yof for direction */
+ if(ol->xof == 0.0) {
+ vec[1][0]= vec[0][0]-dist;
+ vec[1][1]= vec[0][1];
+ }
+ else if(ol->xof==OOPSX) {
+ vec[1][0]= vec[0][0]+dist;
+ vec[1][1]= vec[0][1];
+ }
+ else {
+ vec[1][0]= vec[0][0];
+ vec[1][1]= vec[0][1]+dist;
+ }
+
+ /* v3 is always pointing down */
+ vec[2][0]= vec[3][0];
+ vec[2][1]= vec[3][1] - dist;
+
+ if( MIN4(vec[0][0], vec[1][0], vec[2][0], vec[3][0]) > G.v2d->cur.xmax); /* clipped */
+ else if ( MAX4(vec[0][0], vec[1][0], vec[2][0], vec[3][0]) < G.v2d->cur.xmin); /* clipped */
+ else {
+ /* calculate a curve resolution to use based on the length of the curve.*/
+ curve_res = MIN2(40, MAX2(2, 2*dist/aspect));
+
+ /* we can reuse the dist variable here to increment the GL curve eval amount*/
+ dist = (float)1/curve_res;
+ spline_step = 0.0;
+
+ glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, vec[0]);
+ glBegin(GL_LINE_STRIP);
+ while (spline_step < 1.000001) {
+ glEvalCoord1f(spline_step);
+ spline_step += dist;
+ }
+ glEnd();
+ }
+
+ }
+ ol= ol->next;
+ }
+}
+
+static float icon_width()
+{
+ /* change it in *one place* when you mess around */
+ return 0.8*OOPSY;
+}
+
+void draw_icon_oops(float *co, short type)
+{
+ BIFIconID icon;
+ float ofs;
+
+ switch(type) {
+ default: return;
+
+ case ID_OB: icon= ICON_OBJECT_HLT; break;
+ case ID_ME: icon= ICON_MESH_HLT; break;
+ case ID_CU: icon= ICON_CURVE_HLT; break;
+ case ID_MB: icon= ICON_MBALL_HLT; break;
+ case ID_LT: icon= ICON_LATTICE_HLT; break;
+ case ID_LA: icon= ICON_LAMP_HLT; break;
+ case ID_MA: icon= ICON_MATERIAL_HLT; break;
+ case ID_TE: icon= ICON_TEXTURE_HLT; break;
+ case ID_IP: icon= ICON_IPO_HLT; break;
+ case ID_LI: icon= ICON_LIBRARY_HLT; break;
+ case ID_IM: icon= ICON_IMAGE_HLT; break;
+ case ID_GR: icon= ICON_CIRCLE_DEHLT; break;
+ }
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ /* height of box is OOPSY...icon is centered vertically */
+ ofs = (OOPSY - icon_width())/2.0;
+ BIF_icon_draw_aspect(co[0], co[1]+ofs, icon, icon_width()*aspect*ICON_DEFAULT_HEIGHT/OOPSY);
+
+ glBlendFunc(GL_ONE, GL_ZERO);
+ glDisable(GL_BLEND);
+}
+
+void mysbox(float x1, float y1, float x2, float y2)
+{
+ float vec[2];
+
+ glBegin(GL_LINE_LOOP);
+ vec[0]= x1; vec[1]= y1;
+ glVertex2fv(vec);
+ vec[0]= x2;
+ glVertex2fv(vec);
+ vec[1]= y2;
+ glVertex2fv(vec);
+ vec[0]= x1;
+ glVertex2fv(vec);
+ glEnd();
+}
+
+unsigned int give_oops_color(short type, short sel, unsigned int *border)
+{
+ unsigned int body;
+ /* also finds out if a dashed line should be drawn */
+
+ switch(type) {
+ case ID_OB:
+ body= 0x707070; break;
+ case ID_SCE:
+ body= 0x608060; break;
+ case ID_MA:
+ body= 0x808060; break;
+ case ID_TE:
+ body= 0x7080a0; break;
+ case ID_IP:
+ body= 0x906050; break;
+ case ID_LA:
+ body= 0x608080; break;
+ case ID_LI:
+ body= 0x2198DC; break;
+ case ID_IM:
+ body= 0x35659F; break;
+ case ID_GR:
+ body= 0x507050; break;
+ default:
+ body= 0x606070; break;
+ }
+
+ if(sel) {
+ if(G.moving) *border= 0xf0f0f0;
+ else *border= 0xc0c0c0;
+ }
+ else *border= 0x0;
+
+
+ return body;
+}
+
+
+float center_oops_text(char *str)
+/* gives x offset at which to draw oops text -- takes icon into account */
+{
+ int len;
+ float width;
+
+ len= strlen(str);
+ if(len < 1) return 0;
+
+ /* center at box width of OOPSX */
+ width= aspect*BIF_GetStringWidth(font, str, 0) + icon_width();
+
+ while(width > OOPSX && len >= 0) {
+ str[len] = 0;
+ width= aspect*BIF_GetStringWidth(font, str, 0) + icon_width();
+ len--;
+ }
+ return (OOPSX - width)/2;
+}
+
+void draw_oops(Oops *oops)
+{
+ OopsLink *ol;
+ float v1[2], x1, y1, x2, y2, f1, f2;
+ unsigned int body, border;
+ short line= 0;
+ char str[FILE_MAXDIR+FILE_MAXFILE+5];
+
+ x1= oops->x;
+ x2= oops->x+OOPSX;
+ y1= oops->y;
+ y2= oops->y+OOPSY;
+
+ /* do clip */
+ if(x2 < G.v2d->cur.xmin || x1 > G.v2d->cur.xmax) return;
+ if(y2 < G.v2d->cur.ymin || y1 > G.v2d->cur.ymax) return;
+
+ body= give_oops_color(oops->type, oops->flag & SELECT, &border);
+ if(oops->id== (ID *)((G.scene->basact) ? (G.scene->basact->object) : 0)) line= 1;
+ else if(oops->id== (ID *)G.scene) line= 1;
+
+ if (!oops->id) return;
+
+ if(oops->id->us) {
+ cpack(body);
+
+ glRectf(x1, y1, x2, y2);
+ }
+
+ if(oops->id->lib) {
+ if(oops->id->flag & LIB_INDIRECT) cpack(0x1144FF);
+ else cpack(0x11AAFF);
+
+ glRectf(x2-0.2*OOPSX, y2-0.2*OOPSX, x2-0.1*OOPSX, y2-0.1*OOPSX);
+ }
+
+ v1[0]= x1;
+ v1[1] = y1;
+
+ if(oops->type==ID_LI) {
+ sprintf(str, " %s", ((Library *)oops->id)->name);
+ }
+ else {
+ sprintf(str, " %s", oops->id->name+2);
+ }
+
+ BIF_SetScale(aspect);
+ v1[0] += center_oops_text(str);
+
+ draw_icon_oops(v1, oops->type);
+ v1[0] += icon_width();
+
+ v1[1] = y1+(y2-y1)/3.0;
+ if(oops->flag & SELECT) BIF_ThemeColor(TH_TEXT_HI);
+ else BIF_ThemeColor(TH_TEXT);
+ glRasterPos2f(v1[0], v1[1]);
+ BIF_RasterPos(v1[0], v1[1]);
+ BIF_SetScale(aspect);
+ BIF_DrawString(font, str, 0);
+
+
+ if(line) setlinestyle(2);
+ cpack(border);
+
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ glRectf(x1, y1, x2, y2);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ if(line) setlinestyle(0);
+
+ /* connection blocks */
+ ol= oops->link.first;
+ while(ol) {
+
+ f1= x1+ol->xof;
+ f2= y1+ol->yof;
+
+ body= give_oops_color(ol->type, oops->flag & SELECT, &border);
+ cpack(body);
+
+ glRectf(f1-.2, f2-.2, f1+.2, f2+.2);
+ cpack(border);
+
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+
+ glRectf(f1-.2, f2-.2, f1+.2, f2+.2);
+
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+
+ ol= ol->next;
+ }
+
+ if(oops->flag & OOPS_REFER) {
+ /* Draw the little rounded connection point */
+ glColor3ub(0, 0, 0);
+ glPushMatrix();
+
+ glTranslatef(oops->x + 0.5*OOPSX, oops->y, 0.0);
+ glutil_draw_filled_arc(0.0, M_PI, 0.05*OOPSX, 7);
+
+ glPopMatrix();
+ }
+}
+
+void drawoopsspace(ScrArea *sa, void *spacedata)
+{
+ SpaceOops *soops= spacedata;
+ Oops *oops;
+ float col[3];
+
+ BIF_GetThemeColor3fv(TH_BACK, col);
+
+ if(soops==0) return;
+
+ /* darker background for oops */
+ if(soops->type!=SO_OUTLINER) {
+ col[0] = col[0] * 0.75; col[1] = col[1] * 0.75; col[2] = col[2] * 0.75;
+ }
+
+ glClearColor(col[0], col[1], col[2], 0.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ if(soops->type==SO_OUTLINER) draw_outliner(sa, soops);
+ else {
+ build_oops(); /* changed to become first call... */
+
+ boundbox_oops(0);
+ calc_scrollrcts(sa, G.v2d, curarea->winx, curarea->winy);
+
+ myortho2(G.v2d->cur.xmin, G.v2d->cur.xmax, G.v2d->cur.ymin, G.v2d->cur.ymax);
+ bwin_clear_viewmat(sa->win); /* clear buttons view */
+ glLoadIdentity();
+
+ aspect= (G.v2d->cur.xmax - G.v2d->cur.xmin)/((float)sa->winx);
+ font= uiSetCurFont_ext(30*aspect);
+
+ calc_ipogrid(); /* for scrollvariables */
+
+ /* drop shadow */
+ BIF_ThemeColorShade(TH_BACK, -96); /* drop shadow color */
+ glRectf(G.v2d->tot.xmin-1, G.v2d->tot.ymin-3, G.v2d->tot.xmax+3,
+ G.v2d->tot.ymax+1);
+
+ /* light square in the center */
+ BIF_GetThemeColor3fv(TH_BACK, col);
+ glColor3fv(col);
+ glRectf(G.v2d->tot.xmin-2, G.v2d->tot.ymin-2, G.v2d->tot.xmax+2,
+ G.v2d->tot.ymax+2);
+
+ /* box around the oops. */
+ cpack(0x0);
+ mysbox(G.v2d->tot.xmin-2, G.v2d->tot.ymin-2, G.v2d->tot.xmax+2,
+ G.v2d->tot.ymax+2);
+
+
+ /* Draw unselected oops links */
+ for(oops= soops->oops.first; oops; oops = oops->next) {
+ if(oops->hide==0 && (oops->flag & SELECT)); else {
+ draw_oopslink(oops);
+ }
+ }
+
+ /* Draw selected oops links */
+ for(oops= soops->oops.first; oops; oops = oops->next) {
+ if(oops->hide==0 && (oops->flag & SELECT)) {
+ draw_oopslink(oops);
+ }
+ }
+
+ for(oops= soops->oops.first; oops; oops = oops->next) {
+ if(oops->hide==0) {
+ if(oops->flag & SELECT); else draw_oops(oops);
+ }
+ }
+
+ for(oops= soops->oops.first; oops; oops = oops->next) {
+ if(oops->hide==0) {
+ if(oops->flag & SELECT) draw_oops(oops);
+ }
+ }
+ }
+
+ /* restore viewport */
+ mywinset(curarea->win);
+
+ /* ortho at pixel level curarea */
+ myortho2(-0.375, sa->winx-0.375, -0.375, sa->winy-0.375);
+
+ if(soops->type==SO_OUTLINER) {
+ if(sa->winx>SCROLLB+10 && sa->winy>SCROLLH+10) {
+ if(G.v2d->scroll) drawscroll(0);
+ }
+ }
+ draw_area_emboss(sa);
+
+ curarea->win_swap= WIN_BACK_OK;
+}
+
+
+
diff --git a/source/blender/src/drawscene.c b/source/blender/src/drawscene.c
new file mode 100644
index 00000000000..297dfcb7fb2
--- /dev/null
+++ b/source/blender/src/drawscene.c
@@ -0,0 +1,142 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * drawing graphics and editing
+ */
+
+#include <math.h>
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_scene.h"
+
+#include "BDR_editobject.h"
+#include "BDR_editface.h"
+#include "BDR_sculptmode.h"
+#include "BDR_vpaint.h"
+
+#include "BIF_space.h"
+#include "BIF_drawscene.h"
+#include "BIF_poseobject.h"
+
+#include "BSE_view.h"
+
+#include "radio.h"
+
+#include "blendef.h" /* old */
+#include "mydevice.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+void set_scene(Scene *sce) /* also see scene.c: set_scene_bg() */
+{
+ bScreen *sc;
+
+ /* ending all modes */
+ if( G.obedit)
+ exit_editmode(EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR);
+
+ if(G.f & G_VERTEXPAINT)
+ set_vpaint();
+ if(G.f & G_TEXTUREPAINT)
+ set_texturepaint();
+ if(G.f & G_WEIGHTPAINT)
+ set_wpaint();
+ if(G.f & G_SCULPTMODE)
+ set_sculptmode();
+
+ G.scene= sce;
+
+ sc= G.main->screen.first;
+ while(sc) {
+ if((U.flag & USER_SCENEGLOBAL) || sc==G.curscreen) {
+
+ if(sce != sc->scene) {
+ /* all areas endlocalview */
+ ScrArea *sa= sc->areabase.first;
+ while(sa) {
+ endlocalview(sa);
+ sa= sa->next;
+ }
+ sc->scene= sce;
+ }
+
+ }
+ sc= sc->id.next;
+ }
+
+ copy_view3d_lock(0); /* space.c */
+
+ /* are there cameras in the views that are not in the scene? */
+ sc= G.main->screen.first;
+ while(sc) {
+ if( (U.flag & USER_SCENEGLOBAL) || sc==G.curscreen) {
+ ScrArea *sa= sc->areabase.first;
+ while(sa) {
+ SpaceLink *sl= sa->spacedata.first;
+ while(sl) {
+ if(sl->spacetype==SPACE_VIEW3D) {
+ View3D *v3d= (View3D*) sl;
+ if (!v3d->camera || !object_in_scene(v3d->camera, sce)) {
+ v3d->camera= scene_find_camera(sc->scene);
+ if (sc==G.curscreen) handle_view3d_lock();
+ if (!v3d->camera && v3d->persp>1) v3d->persp= 1;
+ }
+ }
+ sl= sl->next;
+ }
+ sa= sa->next;
+ }
+ }
+ sc= sc->id.next;
+ }
+
+ set_scene_bg(G.scene);
+ scene_update_for_newframe(G.scene, G.scene->lay);
+
+ set_radglobal();
+
+ /* complete redraw */
+ allqueue(REDRAWALL, 0);
+ allqueue(REDRAWDATASELECT, 0); /* does a remake */
+}
+
+
diff --git a/source/blender/src/drawscript.c b/source/blender/src/drawscript.c
new file mode 100644
index 00000000000..b009c3b8388
--- /dev/null
+++ b/source/blender/src/drawscript.c
@@ -0,0 +1,153 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: drawtext.c.
+ *
+ * Contributor(s): Willian Padovani Germano.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <math.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef _WIN32
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+#include "MEM_guardedalloc.h"
+#include "PIL_time.h"
+
+#include "BMF_Api.h"
+
+#include "BLI_blenlib.h"
+
+#include "DNA_space_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_text.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+
+#include "BPI_script.h"
+#include "BPY_extern.h"
+
+#include "BIF_gl.h"
+#include "BIF_keyval.h"
+#include "BIF_interface.h"
+#include "BIF_drawscript.h"
+#include "BIF_editfont.h"
+#include "BIF_spacetypes.h"
+#include "BIF_usiblender.h"
+#include "BIF_screen.h"
+#include "BIF_toolbox.h"
+#include "BIF_space.h"
+#include "BIF_mywindow.h"
+
+#include "BSE_filesel.h"
+
+#include "mydevice.h"
+#include "blendef.h"
+#include "interface.h"
+
+void drawscriptspace(ScrArea *sa, void *spacedata);
+void winqreadscriptspace(struct ScrArea *sa, void *spacedata, struct BWinEvent *evt);
+
+void drawscriptspace(ScrArea *sa, void *spacedata)
+{
+ SpaceScript *sc = curarea->spacedata.first;
+ Script *script = NULL;
+
+ glClearColor(0.6, 0.6, 0.6, 1.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ myortho2(-0.5, curarea->winrct.xmax-curarea->winrct.xmin-0.5, -0.5, curarea->winrct.ymax-curarea->winrct.ymin-0.5);
+
+ if (!sc->script) return;
+
+ script = sc->script;
+
+ if (script->py_draw) {
+ BPY_spacescript_do_pywin_draw(sc);
+ }
+ /* quick hack for 2.37a for scripts that call the progress bar inside a
+ * file selector callback, to show previous space after finishing, w/o
+ * needing an event */
+ else if (!script->flags && !script->py_event && !script->py_button)
+ addqueue(curarea->win, MOUSEX, 0);
+}
+
+void winqreadscriptspace(struct ScrArea *sa, void *spacedata, struct BWinEvent *evt)
+{
+ unsigned short event = evt->event;
+ short val = evt->val;
+ char ascii = evt->ascii;
+ SpaceScript *sc = curarea->spacedata.first;
+ Script *script = sc->script;
+
+ if (script) {
+ if (script->py_event || script->py_button)
+ BPY_spacescript_do_pywin_event(sc, event, val, ascii);
+
+ /* for file/image sel scripts: if user leaves file/image selection space,
+ * this frees the script (since it can't be accessed anymore): */
+ else if (script->flags == SCRIPT_FILESEL) {
+ script->flags = 0;
+ script->lastspace = SPACE_SCRIPT;
+ }
+
+ if (!script->flags) {/* finished with this script, let's free it */
+ if (script->lastspace != SPACE_SCRIPT)
+ newspace (curarea, script->lastspace);
+ BPY_free_finished_script(script);
+ sc->script = NULL;
+ }
+ }
+ else {
+ if (event == QKEY)
+ if (val && (G.qual & LR_CTRLKEY) && okee("Quit Blender")) exit_usiblender();
+ }
+
+ return;
+}
+
+void free_scriptspace (SpaceScript *sc)
+{
+ if (!sc) return;
+
+ /*free buttons references*/
+ if (sc->but_refs) {
+ BPy_Set_DrawButtonsList(sc->but_refs);
+ BPy_Free_DrawButtonsList();
+ sc->but_refs = NULL;
+ }
+ sc->script = NULL;
+}
diff --git a/source/blender/src/drawseq.c b/source/blender/src/drawseq.c
new file mode 100644
index 00000000000..36a857abfe1
--- /dev/null
+++ b/source/blender/src/drawseq.c
@@ -0,0 +1,1487 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BMF_Api.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "IMB_imbuf_types.h"
+
+#include "DNA_sequence_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_view2d_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BKE_global.h"
+#include "BKE_plugin_types.h"
+#include "BKE_scene.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_cursors.h"
+#include "BIF_gl.h"
+#include "BIF_graphics.h"
+#include "BIF_mywindow.h"
+#include "BIF_screen.h"
+#include "BIF_drawseq.h"
+#include "BIF_editseq.h"
+#include "BIF_glutil.h"
+#include "BIF_resources.h"
+#include "BIF_space.h"
+#include "BIF_interface.h"
+
+#include "BSE_view.h"
+#include "BSE_drawipo.h"
+#include "BSE_sequence.h"
+#include "BSE_seqeffects.h"
+#include "BSE_seqscopes.h"
+#include "BSE_seqaudio.h"
+#include "BSE_time.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "blendef.h" /* CFRA */
+#include "mydevice.h" /* REDRAWSEQ */
+#include "interface.h"
+#include "winlay.h"
+
+#define SEQ_LEFTHANDLE 1
+#define SEQ_RIGHTHANDLE 2
+
+#define SEQ_STRIP_OFSBOTTOM 0.2
+#define SEQ_STRIP_OFSTOP 0.8
+
+int no_rightbox=0, no_leftbox= 0;
+static void draw_seq_handle(Sequence *seq, SpaceSeq *sseq, short direction);
+static void draw_seq_extensions(Sequence *seq, SpaceSeq *sseq);
+static void draw_seq_text(Sequence *seq, float x1, float x2, float y1, float y2);
+static void draw_shadedstrip(Sequence *seq, char *col, float x1, float y1, float x2, float y2);
+static void draw_seq_strip(struct Sequence *seq, struct ScrArea *sa, struct SpaceSeq *sseq);
+
+static char *give_seqname(Sequence *seq)
+{
+ if(seq->type==SEQ_META) return "Meta";
+ else if(seq->type==SEQ_IMAGE) return "Image";
+ else if(seq->type==SEQ_SCENE) return "Scene";
+ else if(seq->type==SEQ_MOVIE) return "Movie";
+ else if(seq->type==SEQ_RAM_SOUND) return "Audio (RAM)";
+ else if(seq->type==SEQ_HD_SOUND) return "Audio (HD)";
+ else if(seq->type<SEQ_EFFECT) return seq->strip->dir;
+ else if(seq->type==SEQ_CROSS) return "Cross";
+ else if(seq->type==SEQ_GAMCROSS) return "Gamma Cross";
+ else if(seq->type==SEQ_ADD) return "Add";
+ else if(seq->type==SEQ_SUB) return "Sub";
+ else if(seq->type==SEQ_MUL) return "Mul";
+ else if(seq->type==SEQ_ALPHAOVER) return "Alpha Over";
+ else if(seq->type==SEQ_ALPHAUNDER) return "Alpha Under";
+ else if(seq->type==SEQ_OVERDROP) return "Over Drop";
+ else if(seq->type==SEQ_WIPE) return "Wipe";
+ else if(seq->type==SEQ_GLOW) return "Glow";
+ else if(seq->type==SEQ_TRANSFORM) return "Transform";
+ else if(seq->type==SEQ_COLOR) return "Color";
+ else if(seq->type==SEQ_SPEED) return "Speed";
+ else if(seq->type==SEQ_PLUGIN) {
+ if(!(seq->flag & SEQ_EFFECT_NOT_LOADED) &&
+ seq->plugin && seq->plugin->doit) return seq->plugin->pname;
+ return "Plugin";
+ }
+ else return "Effect";
+
+}
+static void draw_cfra_seq(void)
+{
+ glColor3ub(0x30, 0x90, 0x50);
+ glLineWidth(2.0);
+ glBegin(GL_LINES);
+ glVertex2f(G.scene->r.cfra, G.v2d->cur.ymin);
+ glVertex2f(G.scene->r.cfra, G.v2d->cur.ymax);
+ glEnd();
+ glLineWidth(1.0);
+}
+
+static void get_seq_color3ubv(Sequence *seq, char *col)
+{
+ char blendcol[3];
+ float hsv[3], rgb[3];
+ SolidColorVars *colvars = (SolidColorVars *)seq->effectdata;
+
+ switch(seq->type) {
+ case SEQ_IMAGE:
+ BIF_GetThemeColor3ubv(TH_SEQ_IMAGE, col);
+ break;
+ case SEQ_META:
+ BIF_GetThemeColor3ubv(TH_SEQ_META, col);
+ break;
+ case SEQ_MOVIE:
+ BIF_GetThemeColor3ubv(TH_SEQ_MOVIE, col);
+ break;
+ case SEQ_SCENE:
+ BIF_GetThemeColor3ubv(TH_SEQ_SCENE, col);
+
+ if(seq->scene==G.scene) {
+ BIF_GetColorPtrBlendShade3ubv(col, col, col, 1.0, 20);
+ }
+ break;
+
+ /* transitions */
+ case SEQ_CROSS:
+ case SEQ_GAMCROSS:
+ case SEQ_WIPE:
+ /* slightly offset hue to distinguish different effects */
+ BIF_GetThemeColor3ubv(TH_SEQ_TRANSITION, col);
+
+ rgb[0] = col[0]/255.0; rgb[1] = col[1]/255.0; rgb[2] = col[2]/255.0;
+ rgb_to_hsv(rgb[0], rgb[1], rgb[2], hsv, hsv+1, hsv+2);
+
+ if (seq->type == SEQ_CROSS) hsv[0]+= 0.04;
+ if (seq->type == SEQ_GAMCROSS) hsv[0]+= 0.08;
+ if (seq->type == SEQ_WIPE) hsv[0]+= 0.12;
+
+ if(hsv[0]>1.0) hsv[0]-=1.0; else if(hsv[0]<0.0) hsv[0]+= 1.0;
+ hsv_to_rgb(hsv[0], hsv[1], hsv[2], rgb, rgb+1, rgb+2);
+ col[0] = (char)(rgb[0]*255); col[1] = (char)(rgb[1]*255); col[2] = (char)(rgb[2]*255);
+ break;
+
+ /* effects */
+ case SEQ_TRANSFORM:
+ case SEQ_SPEED:
+ case SEQ_ADD:
+ case SEQ_SUB:
+ case SEQ_MUL:
+ case SEQ_ALPHAOVER:
+ case SEQ_ALPHAUNDER:
+ case SEQ_OVERDROP:
+ case SEQ_GLOW:
+ /* slightly offset hue to distinguish different effects */
+ BIF_GetThemeColor3ubv(TH_SEQ_EFFECT, col);
+
+ rgb[0] = col[0]/255.0; rgb[1] = col[1]/255.0; rgb[2] = col[2]/255.0;
+ rgb_to_hsv(rgb[0], rgb[1], rgb[2], hsv, hsv+1, hsv+2);
+
+ if (seq->type == SEQ_ADD) hsv[0]+= 0.04;
+ if (seq->type == SEQ_SUB) hsv[0]+= 0.08;
+ if (seq->type == SEQ_MUL) hsv[0]+= 0.12;
+ if (seq->type == SEQ_ALPHAOVER) hsv[0]+= 0.16;
+ if (seq->type == SEQ_ALPHAUNDER) hsv[0]+= 0.20;
+ if (seq->type == SEQ_OVERDROP) hsv[0]+= 0.24;
+ if (seq->type == SEQ_GLOW) hsv[0]+= 0.28;
+ if (seq->type == SEQ_TRANSFORM) hsv[0]+= 0.36;
+
+ if(hsv[0]>1.0) hsv[0]-=1.0; else if(hsv[0]<0.0) hsv[0]+= 1.0;
+ hsv_to_rgb(hsv[0], hsv[1], hsv[2], rgb, rgb+1, rgb+2);
+ col[0] = (char)(rgb[0]*255); col[1] = (char)(rgb[1]*255); col[2] = (char)(rgb[2]*255);
+ break;
+ case SEQ_COLOR:
+ if (colvars->col) {
+ col[0]= (char)(colvars->col[0]*255);
+ col[1]= (char)(colvars->col[1]*255);
+ col[2]= (char)(colvars->col[2]*255);
+ } else {
+ col[0] = col[1] = col[2] = 128;
+ }
+ break;
+ case SEQ_PLUGIN:
+ BIF_GetThemeColor3ubv(TH_SEQ_PLUGIN, col);
+ break;
+ case SEQ_HD_SOUND:
+ case SEQ_RAM_SOUND:
+ BIF_GetThemeColor3ubv(TH_SEQ_AUDIO, col);
+ blendcol[0] = blendcol[1] = blendcol[2] = 128;
+ if(seq->flag & SEQ_MUTE) BIF_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.5, 20);
+ break;
+ default:
+ col[0] = 10; col[1] = 255; col[2] = 40;
+ }
+}
+
+static void drawmeta_contents(Sequence *seqm, float x1, float y1, float x2, float y2)
+{
+ Sequence *seq;
+ float dx;
+ int nr;
+ char col[3];
+
+ nr= 0;
+ WHILE_SEQ(&seqm->seqbase) {
+ nr++;
+ }
+ END_SEQ
+
+ dx= (x2-x1)/nr;
+
+ WHILE_SEQ(&seqm->seqbase) {
+ get_seq_color3ubv(seq, col);
+
+ glColor3ubv((GLubyte *)col);
+
+ glRectf(x1, y1, x1+0.9*dx, y2);
+
+ BIF_GetColorPtrBlendShade3ubv(col, col, col, 0.0, -30);
+ glColor3ubv((GLubyte *)col);
+
+ fdrawbox(x1, y1, x1+0.9*dx, y2);
+
+ x1+= dx;
+ }
+ END_SEQ
+}
+
+static void drawseqwave(Sequence *seq, float x1, float y1, float x2, float y2, int winx)
+{
+ /*
+ x1 is the starting x value to draw the wave,
+ x2 the end x value, same for y1 and y2
+ winx is the zoom level.
+ */
+
+ float
+ f, /* floating point value used to store the X draw location for the wave lines when openGL drawing*/
+ midy, /* fast access to the middle location (y1+y2)/2 */
+ clipxmin, /* the minimum X value, clip this with the window */
+ clipxmax, /* the maximum X value, clip this with the window */
+ sample_step, /* steps to move per sample, floating value must later translate into an int */
+ fsofs, /* steps to move per sample, floating value must later translate into an int */
+ feofs_sofs, /* */
+ sound_width, /* convenience: x2-x1 */
+ wavemulti; /* scale the samples by this value when GL_LINE drawing so it renders the right height */
+
+ int
+ offset, /* initial offset value for the wave drawing */
+ offset_next, /* when in the wave drawing loop this value is the samples intil the next vert */
+ sofs, /* Constrained offset value (~3) for the wave, start */
+ eofs, /* ditto, end */
+ wavesample, /* inner loop storage if the current wave sample value, used to make the 2 values below */
+ wavesamplemin, /* used for finding the min and max wave peaks */
+ wavesamplemax, /* ditto */
+ subsample_step=4; /* when the sample step is 4 every sample of
+ the wave is evaluated for min and max values used to draw the wave,
+ however this is slow ehrn zoomed out so when the sample step is above
+ 1 (the larger the further out the zoom is) so not evaluate all samples, only some. */
+
+ signed short* s;
+ bSound *sound;
+ Uint8 *stream;
+
+ audio_makestream(seq->sound);
+ if(seq->sound==NULL || seq->sound->stream==NULL) return;
+
+ if (seq->flag & SEQ_MUTE) glColor3ub(0x70, 0x80, 0x80); else glColor3ub(0x70, 0xc0, 0xc0);
+
+ sofs = ((int)( FRA2TIME(seq->startdisp-seq->start)*(float)G.scene->audio.mixrate*4.0 )) & (~3);
+ eofs = ((int)( FRA2TIME(seq->enddisp-seq->start)*(float)G.scene->audio.mixrate*4.0 )) & (~3);
+
+ /* clip the drawing area to the screen bounds to save time */
+ sample_step= (G.v2d->cur.xmax - G.v2d->cur.xmin)/winx;
+ clipxmin= MAX2(x1, G.v2d->cur.xmin);
+ clipxmax= MIN2(x2, G.v2d->cur.xmax);
+
+ if (sample_step > 1)
+ subsample_step= ((int)(subsample_step*sample_step*8)) & (~3);
+
+ /* for speedy access */
+ midy = (y1+y2)/2;
+ fsofs= (float)sofs;
+ feofs_sofs= (float)(eofs-sofs);
+ sound_width= x2-x1;
+ sound = seq->sound;
+ stream = sound->stream;
+ wavemulti = (y2-y1)/196605; /*y2-y1 is the height*/
+ wavesample=0;
+
+ /* we need to get the starting offset value, excuse the duplicate code */
+ f=clipxmin;
+ offset= (int) (fsofs + ((f-x1)/sound_width) * feofs_sofs) & (~3);
+
+ /* start the loop, draw a line per sample_step -sample_step is about 1 line drawn per pixel */
+ glBegin(GL_LINES);
+ for (f=x1+sample_step; f<=clipxmax; f+=sample_step) {
+
+ offset_next = (int) (fsofs + ((f-x1)/sound_width) * feofs_sofs) & (~3);
+ if (f > G.v2d->cur.xmin) {
+ /* if this is close to the last sample just exit */
+ if (offset_next >= sound->streamlen) break;
+
+ wavesamplemin = 131070;
+ wavesamplemax = -131070;
+
+ /*find with high and low of the waveform for this draw,
+ evaluate small samples to find this range */
+ while (offset < offset_next) {
+ s = (signed short*)(stream+offset);
+
+ wavesample = s[0]*2 + s[1];
+ if (wavesamplemin>wavesample)
+ wavesamplemin=wavesample;
+ if (wavesamplemax<wavesample)
+ wavesamplemax=wavesample;
+ offset+=subsample_step;
+ }
+ /* draw the wave line, looks good up close and zoomed out */
+ glVertex2f(f, midy-(wavemulti*wavesamplemin) );
+ glVertex2f(f, midy-(wavemulti*wavesamplemax) );
+ } else {
+ while (offset < offset_next) offset+=subsample_step;
+ }
+
+ offset=offset_next;
+ }
+ glEnd();
+}
+
+/* draw a handle, for each end of a sequence strip */
+static void draw_seq_handle(Sequence *seq, SpaceSeq *sseq, short direction)
+{
+ float v1[2], v2[2], v3[2], rx1=0, rx2=0; //for triangles and rect
+ float x1, x2, y1, y2;
+ float pixelx;
+ float handsize;
+ float minhandle, maxhandle;
+ char str[120];
+ unsigned int whichsel=0;
+ View2D *v2d;
+
+ x1= seq->startdisp;
+ x2= seq->enddisp;
+
+ y1= seq->machine+SEQ_STRIP_OFSBOTTOM;
+ y2= seq->machine+SEQ_STRIP_OFSTOP;
+
+ v2d = &sseq->v2d;
+ pixelx = (v2d->cur.xmax - v2d->cur.xmin)/(v2d->mask.xmax - v2d->mask.xmin);
+
+ /* clamp handles to defined size in pixel space */
+ handsize = seq->handsize;
+ minhandle = 7;
+ maxhandle = 40;
+ CLAMP(handsize, minhandle*pixelx, maxhandle*pixelx);
+
+ /* set up co-ordinates/dimensions for either left or right handle */
+ if (direction == SEQ_LEFTHANDLE) {
+ rx1 = x1;
+ rx2 = x1+handsize*0.75;
+
+ v1[0]= x1+handsize/4; v1[1]= y1+( ((y1+y2)/2.0 - y1)/2);
+ v2[0]= x1+handsize/4; v2[1]= y2-( ((y1+y2)/2.0 - y1)/2);
+ v3[0]= v2[0] + handsize/4; v3[1]= (y1+y2)/2.0;
+
+ whichsel = SEQ_LEFTSEL;
+ } else if (direction == SEQ_RIGHTHANDLE) {
+ rx1 = x2-handsize*0.75;
+ rx2 = x2;
+
+ v1[0]= x2-handsize/4; v1[1]= y1+( ((y1+y2)/2.0 - y1)/2);
+ v2[0]= x2-handsize/4; v2[1]= y2-( ((y1+y2)/2.0 - y1)/2);
+ v3[0]= v2[0] - handsize/4; v3[1]= (y1+y2)/2.0;
+
+ whichsel = SEQ_RIGHTSEL;
+ }
+
+ /* draw! */
+ if(seq->type < SEQ_EFFECT ||
+ get_sequence_effect_num_inputs(seq->type) == 0) {
+ glEnable( GL_BLEND );
+
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ if(seq->flag & whichsel) glColor4ub(0, 0, 0, 80);
+ else if (seq->flag & SELECT) glColor4ub(255, 255, 255, 30);
+ else glColor4ub(0, 0, 0, 22);
+
+ glRectf(rx1, y1, rx2, y2);
+
+ if(seq->flag & whichsel) glColor4ub(255, 255, 255, 200);
+ else glColor4ub(0, 0, 0, 50);
+
+ glEnable( GL_POLYGON_SMOOTH );
+ glBegin(GL_TRIANGLES);
+ glVertex2fv(v1); glVertex2fv(v2); glVertex2fv(v3);
+ glEnd();
+
+ glDisable( GL_POLYGON_SMOOTH );
+ glDisable( GL_BLEND );
+ }
+
+ if(G.moving || (seq->flag & whichsel)) {
+ cpack(0xFFFFFF);
+ if (direction == SEQ_LEFTHANDLE) {
+ sprintf(str, "%d", seq->startdisp);
+ glRasterPos3f(rx1, y1-0.15, 0.0);
+ } else {
+ sprintf(str, "%d", seq->enddisp - 1);
+ glRasterPos3f((x2-BMF_GetStringWidth(G.font, str)*pixelx), y2+0.05, 0.0);
+ }
+ BMF_DrawString(G.font, str);
+ }
+}
+
+static void draw_seq_extensions(Sequence *seq, SpaceSeq *sseq)
+{
+ float x1, x2, y1, y2, pixely, a;
+ char col[3], blendcol[3];
+ View2D *v2d;
+
+ if(seq->type >= SEQ_EFFECT) return;
+
+ x1= seq->startdisp;
+ x2= seq->enddisp;
+
+ y1= seq->machine+SEQ_STRIP_OFSBOTTOM;
+ y2= seq->machine+SEQ_STRIP_OFSTOP;
+
+ v2d = &sseq->v2d;
+ pixely = (v2d->cur.ymax - v2d->cur.ymin)/(v2d->mask.ymax - v2d->mask.ymin);
+
+ blendcol[0] = blendcol[1] = blendcol[2] = 120;
+
+ if(seq->startofs) {
+ glEnable( GL_BLEND );
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ get_seq_color3ubv(seq, col);
+
+ if (seq->flag & SELECT) {
+ BIF_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.3, -40);
+ glColor4ub(col[0], col[1], col[2], 170);
+ } else {
+ BIF_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.6, 0);
+ glColor4ub(col[0], col[1], col[2], 110);
+ }
+
+ glRectf((float)(seq->start), y1-SEQ_STRIP_OFSBOTTOM, x1, y1);
+
+ if (seq->flag & SELECT) glColor4ub(col[0], col[1], col[2], 255);
+ else glColor4ub(col[0], col[1], col[2], 160);
+
+ fdrawbox((float)(seq->start), y1-SEQ_STRIP_OFSBOTTOM, x1, y1); //outline
+
+ glDisable( GL_BLEND );
+ }
+ if(seq->endofs) {
+ glEnable( GL_BLEND );
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ get_seq_color3ubv(seq, col);
+
+ if (seq->flag & SELECT) {
+ BIF_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.3, -40);
+ glColor4ub(col[0], col[1], col[2], 170);
+ } else {
+ BIF_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.6, 0);
+ glColor4ub(col[0], col[1], col[2], 110);
+ }
+
+ glRectf(x2, y2, (float)(seq->start+seq->len), y2+SEQ_STRIP_OFSBOTTOM);
+
+ if (seq->flag & SELECT) glColor4ub(col[0], col[1], col[2], 255);
+ else glColor4ub(col[0], col[1], col[2], 160);
+
+ fdrawbox(x2, y2, (float)(seq->start+seq->len), y2+SEQ_STRIP_OFSBOTTOM); //outline
+
+ glDisable( GL_BLEND );
+ }
+ if(seq->startstill) {
+ get_seq_color3ubv(seq, col);
+ BIF_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.75, 40);
+ glColor3ubv((GLubyte *)col);
+
+ draw_shadedstrip(seq, col, x1, y1, (float)(seq->start), y2);
+
+ /* feint pinstripes, helps see exactly which is extended and which isn't,
+ * especially when the extension is very small */
+ if (seq->flag & SELECT) BIF_GetColorPtrBlendShade3ubv(col, col, col, 0.0, 24);
+ else BIF_GetColorPtrBlendShade3ubv(col, col, col, 0.0, -16);
+
+ glColor3ubv((GLubyte *)col);
+
+ for(a=y1; a< y2; a+= pixely*2.0 ) {
+ fdrawline(x1, a, (float)(seq->start), a);
+ }
+ }
+ if(seq->endstill) {
+ get_seq_color3ubv(seq, col);
+ BIF_GetColorPtrBlendShade3ubv(col, blendcol, col, 0.75, 40);
+ glColor3ubv((GLubyte *)col);
+
+ draw_shadedstrip(seq, col, (float)(seq->start+seq->len), y1, x2, y2);
+
+ /* feint pinstripes, helps see exactly which is extended and which isn't,
+ * especially when the extension is very small */
+ if (seq->flag & SELECT) BIF_GetColorPtrBlendShade3ubv(col, col, col, 0.0, 24);
+ else BIF_GetColorPtrBlendShade3ubv(col, col, col, 0.0, -16);
+
+ glColor3ubv((GLubyte *)col);
+
+ for(a=y1; a< y2; a+= pixely*2.0 ) {
+ fdrawline((float)(seq->start+seq->len), a, x2, a);
+ }
+ }
+}
+
+/* draw info text on a sequence strip */
+static void draw_seq_text(Sequence *seq, float x1, float x2, float y1, float y2)
+{
+ float v1[2], v2[2];
+ int len, size;
+ char str[32 + FILE_MAXDIR+FILE_MAXFILE], *strp;
+ short mval[2];
+
+ v1[1]= y1;
+ v2[1]= y2;
+
+ v1[0]= x1;
+ ipoco_to_areaco_noclip(G.v2d, v1, mval);
+ x1= mval[0];
+ v2[0]= x2;
+ ipoco_to_areaco_noclip(G.v2d, v2, mval);
+ x2= mval[0];
+ size= x2-x1;
+
+ if(seq->name[2]) {
+ sprintf(str, "%d | %s: %s", seq->len, give_seqname(seq), seq->name+2);
+ }else{
+ if(seq->type == SEQ_META) {
+ sprintf(str, "%d | %s", seq->len, give_seqname(seq));
+ }
+ else if(seq->type == SEQ_SCENE) {
+ if(seq->scene) sprintf(str, "%d | %s: %s", seq->len, give_seqname(seq), seq->scene->id.name+2);
+ else sprintf(str, "%d | %s", seq->len, give_seqname(seq));
+
+ }
+ else if(seq->type == SEQ_IMAGE) {
+ sprintf(str, "%d | %s%s", seq->len, seq->strip->dir, seq->strip->stripdata->name);
+ }
+ else if(seq->type & SEQ_EFFECT) {
+ int can_float = (seq->type != SEQ_PLUGIN)
+ || (seq->plugin && seq->plugin->version >= 4);
+
+ if(seq->seq3!=seq->seq2 && seq->seq1!=seq->seq3)
+ sprintf(str, "%d | %s: %d>%d (use %d)%s", seq->len, give_seqname(seq), seq->seq1->machine, seq->seq2->machine, seq->seq3->machine, can_float ? "" : " No float, upgrade plugin!");
+ else if (seq->seq1 && seq->seq2)
+ sprintf(str, "%d | %s: %d>%d%s", seq->len, give_seqname(seq), seq->seq1->machine, seq->seq2->machine, can_float ? "" : " No float, upgrade plugin!");
+ else
+ sprintf(str, "%d | %s", seq->len, give_seqname(seq));
+ }
+ else if (seq->type == SEQ_RAM_SOUND) {
+ sprintf(str, "%d | %s", seq->len, seq->strip->stripdata->name);
+ }
+ else if (seq->type == SEQ_HD_SOUND) {
+ sprintf(str, "%d | %s", seq->len, seq->strip->stripdata->name);
+ }
+ else if (seq->type == SEQ_MOVIE) {
+ sprintf(str, "%d | %s%s", seq->len, seq->strip->dir, seq->strip->stripdata->name);
+ }
+ }
+
+ strp= str;
+
+ while( (len= BMF_GetStringWidth(G.font, strp)) > size) {
+ if(len < 10) break;
+ if(strp[1]==0) break;
+ strp++;
+ }
+
+ mval[0]= (x1+x2-len+1)/2;
+ mval[1]= 1;
+ areamouseco_to_ipoco(G.v2d, mval, &x1, &x2);
+
+ if(seq->flag & SELECT) cpack(0xFFFFFF);
+ else cpack(0);
+ glRasterPos3f(x1, y1+SEQ_STRIP_OFSBOTTOM, 0.0);
+ BMF_DrawString(G.font, strp);
+}
+
+/* draws a shaded strip, made from gradient + flat color + gradient */
+static void draw_shadedstrip(Sequence *seq, char *col, float x1, float y1, float x2, float y2)
+{
+ float ymid1, ymid2;
+
+ ymid1 = (y2-y1)*0.25 + y1;
+ ymid2 = (y2-y1)*0.65 + y1;
+
+ glShadeModel(GL_SMOOTH);
+ glBegin(GL_QUADS);
+
+ if(seq->flag & SELECT) BIF_GetColorPtrBlendShade3ubv(col, col, col, 0.0, -50);
+ else BIF_GetColorPtrBlendShade3ubv(col, col, col, 0.0, 0);
+
+ glColor3ubv((GLubyte *)col);
+
+ glVertex2f(x1,y1);
+ glVertex2f(x2,y1);
+
+ if(seq->flag & SELECT) BIF_GetColorPtrBlendShade3ubv(col, col, col, 0.0, 5);
+ else BIF_GetColorPtrBlendShade3ubv(col, col, col, 0.0, -5);
+
+ glColor3ubv((GLubyte *)col);
+
+ glVertex2f(x2,ymid1);
+ glVertex2f(x1,ymid1);
+
+ glEnd();
+
+ glRectf(x1, ymid1, x2, ymid2);
+
+ glBegin(GL_QUADS);
+
+ glVertex2f(x1,ymid2);
+ glVertex2f(x2,ymid2);
+
+ if(seq->flag & SELECT) BIF_GetColorPtrBlendShade3ubv(col, col, col, 0.0, -15);
+ else BIF_GetColorPtrBlendShade3ubv(col, col, col, 0.0, 25);
+
+ glColor3ubv((GLubyte *)col);
+
+ glVertex2f(x2,y2);
+ glVertex2f(x1,y2);
+
+ glEnd();
+
+}
+
+/*
+Draw a sequence strip, bounds check alredy made
+ScrArea is currently only used to get the windows width in pixels
+so wave file sample drawing precission is zoom adjusted
+*/
+static void draw_seq_strip(Sequence *seq, ScrArea *sa, SpaceSeq *sseq)
+{
+ float x1, x2, y1, y2;
+ char col[3], is_single_image;
+ Sequence *last_seq = get_last_seq();
+
+ /* we need to know if this is a single image or not for drawing */
+ is_single_image = (char)check_single_seq(seq);
+
+ /* body */
+ if(seq->startstill) x1= seq->start;
+ else x1= seq->startdisp;
+ y1= seq->machine+SEQ_STRIP_OFSBOTTOM;
+ if(seq->endstill) x2= seq->start+seq->len;
+ else x2= seq->enddisp;
+ y2= seq->machine+SEQ_STRIP_OFSTOP;
+
+
+ /* get the correct color per strip type*/
+ get_seq_color3ubv(seq, col);
+
+ /* draw the main strip body */
+ if (is_single_image) /* single image */
+ draw_shadedstrip(seq, col, seq_tx_get_final_left(seq), y1, seq_tx_get_final_right(seq), y2);
+ else /* normal operation */
+ draw_shadedstrip(seq, col, x1, y1, x2, y2);
+
+ /* draw additional info and controls */
+ if (seq->type == SEQ_RAM_SOUND)
+ drawseqwave(seq, x1, y1, x2, y2, sa->winx);
+
+ if (!is_single_image)
+ draw_seq_extensions(seq, sseq);
+
+ draw_seq_handle(seq, sseq, SEQ_LEFTHANDLE);
+ draw_seq_handle(seq, sseq, SEQ_RIGHTHANDLE);
+
+ /* draw the strip outline */
+ x1= seq->startdisp;
+ x2= seq->enddisp;
+
+ get_seq_color3ubv(seq, col);
+ if (G.moving && (seq->flag & SELECT)) {
+ if(seq->flag & SEQ_OVERLAP) {
+ col[0]= 255; col[1]= col[2]= 40;
+ } else BIF_GetColorPtrBlendShade3ubv(col, col, col, 0.0, 120);
+ }
+ else if (seq == last_seq) BIF_GetColorPtrBlendShade3ubv(col, col, col, 0.0, 120);
+ else if (seq->flag & SELECT) BIF_GetColorPtrBlendShade3ubv(col, col, col, 0.0, -150);
+ else BIF_GetColorPtrBlendShade3ubv(col, col, col, 0.0, -60);
+
+ glColor3ubv((GLubyte *)col);
+ gl_round_box_shade(GL_LINE_LOOP, x1, y1, x2, y2, 0.0, 0.1, 0.0);
+
+
+ /* calculate if seq is long enough to print a name */
+ x1= seq->startdisp+seq->handsize;
+ x2= seq->enddisp-seq->handsize;
+
+ /* but first the contents of a meta */
+ if(seq->type==SEQ_META) drawmeta_contents(seq, x1, y1+0.15, x2, y2-0.15);
+
+ /* info text on the strip */
+ if(x1<G.v2d->cur.xmin) x1= G.v2d->cur.xmin;
+ else if(x1>G.v2d->cur.xmax) x1= G.v2d->cur.xmax;
+ if(x2<G.v2d->cur.xmin) x2= G.v2d->cur.xmin;
+ else if(x2>G.v2d->cur.xmax) x2= G.v2d->cur.xmax;
+
+ /* nice text here would require changing the view matrix for texture text */
+ if(x1 != x2) {
+ draw_seq_text(seq, x1, x2, y1, y2);
+ }
+}
+
+static Sequence *special_seq_update= 0;
+
+void set_special_seq_update(int val)
+{
+ int x;
+
+ /* if mouse over a sequence && LEFTMOUSE */
+ if(val) {
+ special_seq_update= find_nearest_seq(&x);
+ }
+ else special_seq_update= 0;
+}
+
+
+static void draw_image_seq(ScrArea *sa)
+{
+ SpaceSeq *sseq;
+ StripElem *se;
+ struct ImBuf *ibuf;
+ int x1, y1, rectx, recty;
+ int free_ibuf = 0;
+ static int recursive= 0;
+ float zoom;
+
+ glClearColor(0.0, 0.0, 0.0, 0.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ sseq= sa->spacedata.first;
+ if(sseq==0) return;
+
+ rectx= (G.scene->r.size*G.scene->r.xsch)/100;
+ recty= (G.scene->r.size*G.scene->r.ysch)/100;
+
+ /* BIG PROBLEM: the give_ibuf_seq() can call a rendering, which in turn calls redraws...
+ this shouldn't belong in a window drawing....
+ So: solve this once event based.
+ Now we check for recursion, space type and active area again (ton) */
+
+ if(recursive)
+ return;
+ else {
+ recursive= 1;
+ if (!U.prefetchframes || (G.f & G_PLAYANIM) == 0) {
+ ibuf= (ImBuf *)give_ibuf_seq(rectx, recty, (G.scene->r.cfra), sseq->chanshown);
+ } else {
+ ibuf= (ImBuf *)give_ibuf_threaded(rectx, recty, (G.scene->r.cfra), sseq->chanshown);
+ }
+ recursive= 0;
+
+ /* HURMF! the give_ibuf_seq can call image display in this window */
+ if(sa->spacetype!=SPACE_SEQ)
+ return;
+ if(sa!=curarea) {
+ areawinset(sa->win);
+ }
+ }
+
+ if(special_seq_update) {
+ se = special_seq_update->curelem;
+ if(se) {
+ if(se->ok==2) {
+ if(se->se1)
+ ibuf= se->se1->ibuf;
+ }
+ else ibuf= se->ibuf;
+ }
+ }
+ if(ibuf==NULL)
+ return;
+ if(ibuf->rect_float && ibuf->rect==NULL)
+ IMB_rect_from_float(ibuf);
+ if(ibuf->rect==NULL)
+ return;
+
+ if (sseq->mainb == SEQ_DRAW_IMG_WAVEFORM) {
+ ibuf = make_waveform_view_from_ibuf(ibuf);
+ free_ibuf = 1;
+ } else if (sseq->mainb == SEQ_DRAW_IMG_VECTORSCOPE) {
+ ibuf = make_vectorscope_view_from_ibuf(ibuf);
+ free_ibuf = 1;
+ }
+
+ if (sseq->zoom > 0) {
+ zoom = sseq->zoom;
+ } else if (sseq->zoom == 0) {
+ zoom = 1.0;
+ } else {
+ zoom = -1.0/sseq->zoom;
+ }
+
+ /* calc location */
+ x1= (sa->winx-zoom*ibuf->x)/2 + sseq->xof;
+ y1= (sa->winy-zoom*ibuf->y)/2 + sseq->yof;
+
+ /* needed for gla draw */
+ glaDefine2DArea(&curarea->winrct);
+ glPixelZoom(zoom, zoom);
+
+ glaDrawPixelsSafe(x1, y1, ibuf->x, ibuf->y, ibuf->x, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
+
+ glPixelZoom(1.0, 1.0);
+
+ if (free_ibuf) {
+ IMB_freeImBuf(ibuf);
+ }
+
+ sa->win_swap= WIN_BACK_OK;
+}
+
+static void draw_extra_seqinfo(void)
+{
+ Sequence *last_seq = get_last_seq();
+ StripElem *se, *last;
+ float xco, xfac, yco, yfac;
+ int sta, end;
+ char str[256];
+
+ if(last_seq==0) return;
+
+ /* xfac: size of 1 pixel */
+ xfac= G.v2d->cur.xmax - G.v2d->cur.xmin;
+ xfac/= (float)(G.v2d->mask.xmax-G.v2d->mask.xmin);
+ xco= G.v2d->cur.xmin+10*xfac;
+
+ yfac= G.v2d->cur.ymax - G.v2d->cur.ymin;
+ yfac/= (float)(G.v2d->mask.ymax-G.v2d->mask.ymin);
+ yco= G.v2d->cur.ymin+40*yfac;
+
+ BIF_ThemeColor(TH_TEXT_HI);
+
+ /* NAME */
+ glRasterPos3f(xco, yco, 0.0);
+ strncpy(str, give_seqname(last_seq), 255);
+ BMF_DrawString(G.font, str);
+ xco += xfac*BMF_GetStringWidth(G.font, str) +10.0*xfac;
+
+ if(last_seq->type==SEQ_SCENE && last_seq->scene) {
+ glRasterPos3f(xco, yco, 0.0);
+ BMF_DrawString(G.font, last_seq->scene->id.name+2);
+ xco += xfac*BMF_GetStringWidth(G.font, last_seq->scene->id.name+2) +30.0*xfac;
+ }
+
+ /* LEN, dont bother with single images */
+ if (check_single_seq(last_seq)==0) {
+ if(last_seq->type & SEQ_EFFECT)
+ sprintf(str, "len: %d From %d - %d", last_seq->len, last_seq->startdisp, last_seq->enddisp-1);
+ else
+ sprintf(str, "len: %d (%d)", last_seq->enddisp-last_seq->startdisp, last_seq->len);
+
+ glRasterPos3f(xco, yco, 0.0);
+
+ BMF_DrawString(G.font, str);
+ xco += xfac*BMF_GetStringWidth(G.font, str) +10.0*xfac;
+ }
+
+
+ if(last_seq->type==SEQ_IMAGE) {
+ if (last_seq->len > 1) {
+ /* CURRENT */
+ se= (StripElem *)give_stripelem(last_seq, (G.scene->r.cfra));
+ if(se) {
+ sprintf(str, "Cur: %s", se->name);
+ glRasterPos3f(xco, yco, 0.0);
+ BMF_DrawString(G.font, str);
+ xco += xfac*BMF_GetStringWidth(G.font, str) +10.0*xfac;
+ }
+
+ /* FIRST AND LAST */
+
+ if(last_seq->strip) {
+ se= last_seq->strip->stripdata;
+ last= se+last_seq->len-1;
+ if(last_seq->startofs) se+= last_seq->startofs;
+ if(last_seq->endofs) last-= last_seq->endofs;
+
+ sprintf(str, "First: %s at %d Last: %s at %d", se->name, last_seq->startdisp, last->name, last_seq->enddisp-1);
+ glRasterPos3f(xco, yco, 0.0);
+ BMF_DrawString(G.font, str);
+ xco += xfac*BMF_GetStringWidth(G.font, str) +30.0*xfac;
+
+ /* orig size */
+ sprintf(str, "OrigSize: %d x %d", last_seq->strip->orx, last_seq->strip->ory);
+ glRasterPos3f(xco, yco, 0.0);
+ BMF_DrawString(G.font, str);
+ xco += xfac*BMF_GetStringWidth(G.font, str) +30.0*xfac;
+ }
+ } else { /* single image */
+ if (last_seq->strip) {
+ sprintf(str, "Single: %s len: %d", last_seq->strip->stripdata->name, last_seq->enddisp-last_seq->startdisp);
+ glRasterPos3f(xco, yco, 0.0);
+ BMF_DrawString(G.font, str);
+ xco += xfac*BMF_GetStringWidth(G.font, str) +30.0*xfac;
+ }
+ }
+ }
+ else if(last_seq->type==SEQ_MOVIE) {
+
+ sta= last_seq->startofs;
+ end= last_seq->len-1-last_seq->endofs;
+
+ sprintf(str, "%s %s%s First: %d at %d Last: %d at %d Cur: %d",
+ last_seq->name+2, last_seq->strip->dir, last_seq->strip->stripdata->name,
+ sta, last_seq->startdisp, end, last_seq->enddisp-1, (G.scene->r.cfra)-last_seq->startdisp);
+
+ glRasterPos3f(xco, yco, 0.0);
+ BMF_DrawString(G.font, str);
+ }
+ else if(last_seq->type==SEQ_SCENE) {
+ se= (StripElem *)give_stripelem(last_seq, (G.scene->r.cfra));
+ if(se && last_seq->scene) {
+ sprintf(str, "Cur: %d First: %d Last: %d", last_seq->sfra+se->nr, last_seq->sfra, last_seq->sfra+last_seq->len-1);
+ glRasterPos3f(xco, yco, 0.0);
+ BMF_DrawString(G.font, str);
+ }
+ }
+ else if(last_seq->type==SEQ_RAM_SOUND
+ || last_seq->type == SEQ_HD_SOUND) {
+
+ sta= last_seq->startofs;
+ end= last_seq->len-1-last_seq->endofs;
+
+ sprintf(str, "%s %s%s First: %d at %d Last: %d at %d Cur: %d Gain: %.2f dB Pan: %.2f",
+ last_seq->name+2, last_seq->strip->dir, last_seq->strip->stripdata->name,
+ sta, last_seq->startdisp, end, last_seq->enddisp-1, (G.scene->r.cfra)-last_seq->startdisp,
+ last_seq->level, last_seq->pan);
+
+ glRasterPos3f(xco, yco, 0.0);
+ BMF_DrawString(G.font, str);
+ }
+ else if(last_seq->type == SEQ_SPEED) {
+ SpeedControlVars * vars =
+ (SpeedControlVars*) last_seq->effectdata;
+
+ if (vars) {
+ sprintf(str, "Last mapped frame: %d at %d",
+ vars->lastValidFrame,
+ vars->lastValidFrame
+ + last_seq->startdisp);
+
+ glRasterPos3f(xco, yco, 0.0);
+ BMF_DrawString(G.font, str);
+ }
+ }
+}
+
+void seq_reset_imageofs(SpaceSeq *sseq)
+{
+ sseq->xof = sseq->yof = sseq->zoom = 0;
+}
+
+void seq_viewmove(SpaceSeq *sseq)
+{
+ ScrArea *sa;
+ short mval[2], mvalo[2];
+ short rectx, recty, xmin, xmax, ymin, ymax, pad;
+ int oldcursor;
+ Window *win;
+
+ sa = sseq->area;
+ rectx= (G.scene->r.size*G.scene->r.xsch)/100;
+ recty= (G.scene->r.size*G.scene->r.ysch)/100;
+
+ pad = 10;
+ xmin = -(sa->winx/2) - rectx/2 + pad;
+ xmax = sa->winx/2 + rectx/2 - pad;
+ ymin = -(sa->winy/2) - recty/2 + pad;
+ ymax = sa->winy/2 + recty/2 - pad;
+
+ getmouseco_sc(mvalo);
+
+ oldcursor=get_cursor();
+ win=winlay_get_active_window();
+
+ SetBlenderCursor(BC_NSEW_SCROLLCURSOR);
+
+ while(get_mbut()&(L_MOUSE|M_MOUSE)) {
+
+ getmouseco_sc(mval);
+
+ if(mvalo[0]!=mval[0] || mvalo[1]!=mval[1]) {
+
+ sseq->xof -= (mvalo[0]-mval[0]);
+ sseq->yof -= (mvalo[1]-mval[1]);
+
+ /* prevent dragging image outside of the window and losing it! */
+ CLAMP(sseq->xof, xmin, xmax);
+ CLAMP(sseq->yof, ymin, ymax);
+
+ mvalo[0]= mval[0];
+ mvalo[1]= mval[1];
+
+ scrarea_do_windraw(curarea);
+ screen_swapbuffers();
+ }
+ else BIF_wait_for_statechange();
+ }
+ window_set_cursor(win, oldcursor);
+}
+
+#define SEQ_BUT_PLUGIN 1
+#define SEQ_BUT_RELOAD 2
+#define SEQ_BUT_EFFECT 3
+#define SEQ_BUT_RELOAD_ALL 4
+
+void do_seqbuttons(short val)
+{
+ Sequence *last_seq = get_last_seq();
+
+ switch(val) {
+ case SEQ_BUT_PLUGIN:
+ case SEQ_BUT_EFFECT:
+ update_changed_seq_and_deps(last_seq, 0, 1);
+ break;
+
+ case SEQ_BUT_RELOAD:
+ case SEQ_BUT_RELOAD_ALL:
+ update_seq_ipo_rect(last_seq);
+ update_seq_icu_rects(last_seq);
+
+ free_imbuf_seq(); // frees all
+
+ break;
+ }
+
+ if (val == SEQ_BUT_RELOAD_ALL) {
+ allqueue(REDRAWALL, 0);
+ } else {
+ allqueue(REDRAWSEQ, 0);
+ }
+}
+
+static void seq_panel_properties(short cntrl) // SEQ_HANDLER_PROPERTIES
+{
+ Sequence *last_seq = get_last_seq();
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "seq_panel_properties", UI_EMBOSS, UI_HELV, curarea->win);
+ uiPanelControl(UI_PNL_SOLID | UI_PNL_CLOSE | cntrl);
+ uiSetPanelHandler(SEQ_HANDLER_PROPERTIES); // for close and esc
+ if(uiNewPanel(curarea, block, "Strip Properties", "Seq", 10, 230, 318, 204)==0) return;
+
+ if(last_seq==NULL) return;
+
+ if(last_seq->type==SEQ_PLUGIN) {
+ PluginSeq *pis;
+ VarStruct *varstr;
+ int a, xco, yco;
+
+ get_sequence_effect(last_seq);/* make sure, plugin is loaded */
+
+ uiDefBut(block, LABEL, 0, "Type: Plugin", 10,50,70,20, 0, 0, 0, 0, 0, "");
+
+ pis= last_seq->plugin;
+ if(pis->vars==0) return;
+
+ varstr= pis->varstr;
+ if(varstr) {
+ for(a=0; a<pis->vars; a++, varstr++) {
+ xco= 150*(a/6)+10;
+ yco= 125 - 20*(a % 6)+1;
+ uiDefBut(block, varstr->type, SEQ_BUT_PLUGIN, varstr->name, xco,yco,150,19, &(pis->data[a]), varstr->min, varstr->max, 100, 0, varstr->tip);
+
+ }
+ }
+ uiDefButBitS(block, TOG, SEQ_IPO_FRAME_LOCKED,
+ SEQ_BUT_RELOAD_ALL, "IPO Frame locked",
+ 10,-40,150,19, &last_seq->flag,
+ 0.0, 1.0, 0, 0,
+ "Lock the IPO coordinates to the "
+ "global frame counter.");
+
+ }
+ else if(last_seq->type==SEQ_IMAGE) {
+
+ uiDefBut(block, LABEL, 0, "Type: Image", 10,160,150,20, 0, 0, 0, 0, 0, "");
+ uiDefBut(block, TEX, B_NOP, "Name: ", 10,140,150,19, last_seq->name+2, 0.0, 21.0, 100, 0, "");
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, SEQ_MAKE_PREMUL, SEQ_BUT_RELOAD, "Convert to Premul", 10,110,150,19, &last_seq->flag, 0.0, 21.0, 100, 0, "Converts RGB values to become premultiplied with Alpha");
+ uiDefButBitS(block, TOG, SEQ_FILTERY, SEQ_BUT_RELOAD, "FilterY", 10,90,150,19, &last_seq->flag, 0.0, 21.0, 100, 0, "For video movies to remove fields");
+
+ uiDefButBitS(block, TOG, SEQ_FLIPX, SEQ_BUT_RELOAD, "FlipX", 10,70,75,19, &last_seq->flag, 0.0, 21.0, 100, 0, "Flip on the X axis");
+ uiDefButBitS(block, TOG, SEQ_FLIPY, SEQ_BUT_RELOAD, "FlipY", 85,70,75,19, &last_seq->flag, 0.0, 21.0, 100, 0, "Flip on the Y axis");
+
+ uiDefButF(block, NUM, SEQ_BUT_RELOAD, "Mul:", 10,50,150,19, &last_seq->mul, 0.001, 5.0, 100, 0, "Multiply colors");
+ uiDefButS(block, TOG|BIT|7, SEQ_BUT_RELOAD, "Reverse Frames", 10,30,150,19, &last_seq->flag, 0.0, 21.0, 100, 0, "Reverse frame order");
+ uiDefButF(block, NUM, SEQ_BUT_RELOAD, "Strobe:", 10,10,150,19, &last_seq->strobe, 1.0, 30.0, 100, 0, "Only display every nth frame");
+ uiBlockEndAlign(block);
+ }
+ else if(last_seq->type==SEQ_META) {
+
+ uiDefBut(block, LABEL, 0, "Type: Meta", 10,140,150,20, 0, 0, 0, 0, 0, "");
+ uiDefBut(block, TEX, B_NOP, "Name: ", 10,120,150,19, last_seq->name+2, 0.0, 21.0, 100, 0, "");
+
+ }
+ else if(last_seq->type==SEQ_SCENE) {
+
+ uiDefBut(block, LABEL, 0, "Type: Scene", 10,140,150,20, 0, 0, 0, 0, 0, "");
+ uiDefBut(block, TEX, B_NOP, "Name: ", 10,120,150,19, last_seq->name+2, 0.0, 21.0, 100, 0, "");
+ uiDefButS(block, TOG|BIT|7, SEQ_BUT_RELOAD, "Reverse Frames", 10,90,150,19, &last_seq->flag, 0.0, 21.0, 100, 0, "Reverse frame order");
+ }
+ else if(last_seq->type==SEQ_MOVIE) {
+
+ if(last_seq->mul==0.0) last_seq->mul= 1.0;
+
+ uiDefBut(block, LABEL, 0, "Type: Movie", 10,140,150,20, 0, 0, 0, 0, 0, "");
+ uiDefBut(block, TEX, B_NOP, "Name: ", 10,120,150,19, last_seq->name+2, 0.0, 21.0, 100, 0, "");
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, SEQ_MAKE_PREMUL, SEQ_BUT_RELOAD, "Make Premul Alpha ", 10,90,150,19, &last_seq->flag, 0.0, 21.0, 100, 0, "Converts RGB values to become premultiplied with Alpha");
+ uiDefButBitS(block, TOG, SEQ_FILTERY, SEQ_BUT_RELOAD, "FilterY ", 10,70,150,19, &last_seq->flag, 0.0, 21.0, 100, 0, "For video movies to remove fields");
+ uiDefButF(block, NUM, SEQ_BUT_RELOAD, "Mul:", 10,50,150,19, &last_seq->mul, 0.001, 5.0, 100, 0, "Multiply colors");
+
+ uiDefButS(block, TOG|BIT|7, SEQ_BUT_RELOAD, "Reverse Frames", 10,30,150,19, &last_seq->flag, 0.0, 21.0, 100, 0, "Reverse frame order");
+ uiDefButF(block, NUM, SEQ_BUT_RELOAD, "Strobe:", 10,10,150,19, &last_seq->strobe, 1.0, 30.0, 100, 0, "Only display every nth frame");
+ uiDefButI(block, NUM, SEQ_BUT_RELOAD, "Preseek:", 10,-10,150,19, &last_seq->anim_preseek, 0.0, 50.0, 100, 0, "On MPEG-seeking preseek this many frames");
+ uiBlockEndAlign(block);
+ }
+ else if(last_seq->type==SEQ_RAM_SOUND ||
+ last_seq->type==SEQ_HD_SOUND) {
+
+ uiDefBut(block, LABEL, 0, "Type: Audio", 10,140,150,20, 0, 0, 0, 0, 0, "");
+ uiDefBut(block, TEX, 0, "Name: ", 10,120,150,19, last_seq->name+2, 0.0, 21.0, 100, 0, "");
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, SEQ_IPO_FRAME_LOCKED,
+ SEQ_BUT_RELOAD_ALL, "IPO Frame locked",
+ 10,90,150,19, &last_seq->flag,
+ 0.0, 1.0, 0, 0,
+ "Lock the IPO coordinates to the "
+ "global frame counter.");
+
+ uiDefButBitS(block, TOG, SEQ_MUTE, B_NOP, "Mute", 10,70,120,19, &last_seq->flag, 0.0, 21.0, 100, 0, "");
+ uiDefButF(block, NUM, SEQ_BUT_RELOAD, "Gain (dB):", 10,50,150,19, &last_seq->level, -96.0, 6.0, 100, 0, "");
+ uiDefButF(block, NUM, SEQ_BUT_RELOAD, "Pan:", 10,30,150,19, &last_seq->pan, -1.0, 1.0, 100, 0, "");
+ uiBlockEndAlign(block);
+ }
+ else if(last_seq->type>=SEQ_EFFECT) {
+ uiDefBut(block, LABEL, 0, "Type: Effect", 10,140,150,20, 0, 0, 0, 0, 0, "");
+ uiDefBut(block, TEX, B_NOP, "Name: ", 10,120,150,19, last_seq->name+2, 0.0, 21.0, 100, 0, "");
+
+ uiDefButBitS(block, TOG, SEQ_IPO_FRAME_LOCKED,
+ SEQ_BUT_RELOAD_ALL, "IPO Frame locked",
+ 10,90,150,19, &last_seq->flag,
+ 0.0, 1.0, 0, 0,
+ "Lock the IPO coordinates to the "
+ "global frame counter.");
+
+ uiBlockBeginAlign(block);
+ if(last_seq->type==SEQ_WIPE){
+ WipeVars *wipe = (WipeVars *)last_seq->effectdata;
+ char formatstring[256];
+
+ strncpy(formatstring, "Transition Type %t|Single Wipe%x0|Double Wipe %x1|Iris Wipe %x4|Clock Wipe %x5", 255);
+ uiDefButS(block, MENU,SEQ_BUT_EFFECT, formatstring, 10,65,220,22, &wipe->wipetype, 0, 0, 0, 0, "What type of wipe should be performed");
+ uiDefButF(block, NUM,SEQ_BUT_EFFECT,"Blur:", 10,40,220,22, &wipe->edgeWidth,0.0,1.0, 1, 2, "The percent width of the blur edge");
+ switch(wipe->wipetype){ /*Skip Types that do not require angle*/
+ case DO_IRIS_WIPE:
+ case DO_CLOCK_WIPE:
+ break;
+
+ default:
+ uiDefButF(block, NUM,SEQ_BUT_EFFECT,"Angle:", 10,15,220,22, &wipe->angle,-90.0,90.0, 1, 2, "The Angle of the Edge");
+ }
+ uiDefButS(block, TOG,SEQ_BUT_EFFECT,"Wipe In", 10,-10,220,22, &wipe->forward,0,0, 0, 0, "Controls Primary Direction of Wipe");
+ }
+ else if(last_seq->type==SEQ_GLOW){
+ GlowVars *glow = (GlowVars *)last_seq->effectdata;
+
+ uiDefButF(block, NUM, SEQ_BUT_EFFECT, "Threshold:", 10,70,150,19, &glow->fMini, 0.0, 1.0, 0, 0, "Trigger Intensity");
+ uiDefButF(block, NUM, SEQ_BUT_EFFECT, "Clamp:", 10,50,150,19, &glow->fClamp, 0.0, 1.0, 0, 0, "Brightness limit of intensity");
+ uiDefButF(block, NUM, SEQ_BUT_EFFECT, "Boost factor:", 10,30,150,19, &glow->fBoost, 0.0, 10.0, 0, 0, "Brightness multiplier");
+ uiDefButF(block, NUM, SEQ_BUT_EFFECT, "Blur distance:", 10,10,150,19, &glow->dDist, 0.5, 20.0, 0, 0, "Radius of glow effect");
+ uiDefButI(block, NUM, B_NOP, "Quality:", 10,-5,150,19, &glow->dQuality, 1.0, 5.0, 0, 0, "Accuracy of the blur effect");
+ uiDefButI(block, TOG, B_NOP, "Only boost", 10,-25,150,19, &glow->bNoComp, 0.0, 0.0, 0, 0, "Show the glow buffer only");
+ }
+ else if(last_seq->type==SEQ_TRANSFORM){
+ TransformVars *transform = (TransformVars *)last_seq->effectdata;
+
+ uiDefButF(block, NUM, SEQ_BUT_EFFECT, "xScale Start:", 10,70,150,19, &transform->ScalexIni, 0.0, 10.0, 0, 0, "X Scale Start");
+ uiDefButF(block, NUM, SEQ_BUT_EFFECT, "xScale End:", 160,70,150,19, &transform->ScalexFin, 0.0, 10.0, 0, 0, "X Scale End");
+ uiDefButF(block, NUM, SEQ_BUT_EFFECT, "yScale Start:", 10,50,150,19, &transform->ScaleyIni, 0.0, 10.0, 0, 0, "Y Scale Start");
+ uiDefButF(block, NUM, SEQ_BUT_EFFECT, "yScale End:", 160,50,150,19, &transform->ScaleyFin, 0.0, 10.0, 0, 0, "Y Scale End");
+
+ uiDefButI(block, ROW, SEQ_BUT_EFFECT, "Percent", 10, 30, 150, 19, &transform->percent, 0.0, 1.0, 0.0, 0.0, "Percent Translate");
+ uiDefButI(block, ROW, SEQ_BUT_EFFECT, "Pixels", 160, 30, 150, 19, &transform->percent, 0.0, 0.0, 0.0, 0.0, "Pixels Translate");
+ if(transform->percent==1){
+ uiDefButF(block, NUM, SEQ_BUT_EFFECT, "x Start:", 10,10,150,19, &transform->xIni, -500.0, 500.0, 0, 0, "X Position Start");
+ uiDefButF(block, NUM, SEQ_BUT_EFFECT, "x End:", 160,10,150,19, &transform->xFin, -500.0, 500.0, 0, 0, "X Position End");
+ uiDefButF(block, NUM, SEQ_BUT_EFFECT, "y Start:", 10,-10,150,19, &transform->yIni, -500.0, 500.0, 0, 0, "Y Position Start");
+ uiDefButF(block, NUM, SEQ_BUT_EFFECT, "y End:", 160,-10,150,19, &transform->yFin, -500.0, 500.0, 0, 0, "Y Position End");
+ }else{
+ uiDefButF(block, NUM, SEQ_BUT_EFFECT, "x Start:", 10,10,150,19, &transform->xIni, -10000.0, 10000.0, 0, 0, "X Position Start");
+ uiDefButF(block, NUM, SEQ_BUT_EFFECT, "x End:", 160,10,150,19, &transform->xFin, -10000.0, 10000.0, 0, 0, "X Position End");
+ uiDefButF(block, NUM, SEQ_BUT_EFFECT, "y Start:", 10,-10,150,19, &transform->yIni, -10000.0, 10000.0, 0, 0, "Y Position Start");
+ uiDefButF(block, NUM, SEQ_BUT_EFFECT, "y End:", 160,-10,150,19, &transform->yFin, -10000.0, 10000.0, 0, 0, "Y Position End");
+
+ }
+
+
+
+ uiDefButF(block, NUM, SEQ_BUT_EFFECT, "rot Start:",10,-30,150,19, &transform->rotIni, 0.0, 360.0, 0, 0, "Rotation Start");
+ uiDefButF(block, NUM, SEQ_BUT_EFFECT, "rot End:",160,-30,150,19, &transform->rotFin, 0.0, 360.0, 0, 0, "Rotation End");
+
+ uiDefButI(block, ROW, SEQ_BUT_EFFECT, "No Interpolat", 10, -50, 100, 19, &transform->interpolation, 0.0, 0.0, 0.0, 0.0, "No interpolation");
+ uiDefButI(block, ROW, SEQ_BUT_EFFECT, "Bilinear", 101, -50, 100, 19, &transform->interpolation, 0.0, 1.0, 0.0, 0.0, "Bilinear interpolation");
+ uiDefButI(block, ROW, SEQ_BUT_EFFECT, "Bicubic", 202, -50, 100, 19, &transform->interpolation, 0.0, 2.0, 0.0, 0.0, "Bicubic interpolation");
+ } else if(last_seq->type==SEQ_COLOR) {
+ SolidColorVars *colvars = (SolidColorVars *)last_seq->effectdata;
+ uiDefButF(block, COL, SEQ_BUT_RELOAD, "",10,90,150,19, colvars->col, 0, 0, 0, 0, "");
+ } else if(last_seq->type==SEQ_SPEED){
+ SpeedControlVars *sp =
+ (SpeedControlVars *)last_seq->effectdata;
+
+ uiDefButF(block, NUM, SEQ_BUT_RELOAD, "Global Speed:", 10,70,150,19, &sp->globalSpeed, 0.0, 100.0, 0, 0, "Global Speed");
+
+ uiDefButBitI(block, TOG, SEQ_SPEED_INTEGRATE,
+ SEQ_BUT_RELOAD,
+ "IPO is velocity",
+ 10,50,150,19, &sp->flags,
+ 0.0, 1.0, 0, 0,
+ "Interpret the IPO value as a "
+ "velocity instead of a frame number");
+
+ uiDefButBitI(block, TOG, SEQ_SPEED_BLEND,
+ SEQ_BUT_RELOAD,
+ "Enable frame blending",
+ 10,30,150,19, &sp->flags,
+ 0.0, 1.0, 0, 0,
+ "Blend two frames into the "
+ "target for a smoother result");
+
+ uiDefButBitI(block, TOG, SEQ_SPEED_COMPRESS_IPO_Y,
+ SEQ_BUT_RELOAD,
+ "IPO value runs from [0..1]",
+ 10,10,150,19, &sp->flags,
+ 0.0, 1.0, 0, 0,
+ "Scale IPO value to get the "
+ "target frame number.");
+ }
+
+ uiBlockEndAlign(block);
+ }
+}
+
+static void seq_blockhandlers(ScrArea *sa)
+{
+ SpaceSeq *sseq= sa->spacedata.first;
+ short a;
+
+ /* warning; blocks need to be freed each time, handlers dont remove (for ipo moved to drawipospace) */
+ uiFreeBlocksWin(&sa->uiblocks, sa->win);
+
+ for(a=0; a<SPACE_MAXHANDLER; a+=2) {
+ switch(sseq->blockhandler[a]) {
+
+ case SEQ_HANDLER_PROPERTIES:
+ seq_panel_properties(sseq->blockhandler[a+1]);
+ break;
+
+ }
+ /* clear action value for event */
+ sseq->blockhandler[a+1]= 0;
+ }
+ uiDrawBlocksPanels(sa, 0);
+
+}
+
+void drawprefetchseqspace(ScrArea *sa, void *spacedata)
+{
+ SpaceSeq *sseq= sa->spacedata.first;
+ int rectx, recty;
+
+ rectx= (G.scene->r.size*G.scene->r.xsch)/100;
+ recty= (G.scene->r.size*G.scene->r.ysch)/100;
+
+ if(sseq->mainb) {
+ give_ibuf_prefetch_request(
+ rectx, recty, (G.scene->r.cfra), sseq->chanshown);
+ }
+}
+
+void drawseqspace(ScrArea *sa, void *spacedata)
+{
+ SpaceSeq *sseq= sa->spacedata.first;
+ View2D *v2d= &sseq->v2d;
+ Editing *ed;
+ Sequence *seq;
+ float col[3];
+ int ofsx, ofsy;
+ int i;
+
+ ed= G.scene->ed;
+
+ if(sseq->mainb) {
+ draw_image_seq(sa);
+ return;
+ }
+
+ bwin_clear_viewmat(sa->win); /* clear buttons view */
+ glLoadIdentity();
+
+ BIF_GetThemeColor3fv(TH_BACK, col);
+ if(ed && ed->metastack.first) glClearColor(col[0], col[1], col[2]-0.1, 0.0);
+ else glClearColor(col[0], col[1], col[2], 0.0);
+
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ calc_scrollrcts(sa, v2d, sa->winx, sa->winy);
+
+ if(sa->winx>SCROLLB+10 && sa->winy>SCROLLH+10) {
+ if(v2d->scroll) {
+ ofsx= sa->winrct.xmin; /* because of mywin */
+ ofsy= sa->winrct.ymin;
+ glViewport(ofsx+v2d->mask.xmin, ofsy+v2d->mask.ymin, ( ofsx+v2d->mask.xmax-1)-(ofsx+v2d->mask.xmin)+1, ( ofsy+v2d->mask.ymax-1)-( ofsy+v2d->mask.ymin)+1);
+ glScissor(ofsx+v2d->mask.xmin, ofsy+v2d->mask.ymin, ( ofsx+v2d->mask.xmax-1)-(ofsx+v2d->mask.xmin)+1, ( ofsy+v2d->mask.ymax-1)-( ofsy+v2d->mask.ymin)+1);
+ }
+ }
+
+
+ myortho2(v2d->cur.xmin, v2d->cur.xmax, v2d->cur.ymin, v2d->cur.ymax);
+
+ BIF_ThemeColorShade(TH_BACK, -20);
+ glRectf(v2d->cur.xmin, 0.0, v2d->cur.xmax, 1.0);
+
+
+ boundbox_seq();
+ calc_ipogrid();
+
+ i= MAX2(1, ((int)G.v2d->cur.ymin)-1);
+
+ glBegin(GL_QUADS);
+ while (i<v2d->cur.ymax) {
+ if (((int)i) & 1)
+ BIF_ThemeColorShade(TH_BACK, -15);
+ else
+ BIF_ThemeColorShade(TH_BACK, -25);
+
+ glVertex2f(v2d->cur.xmax, i);
+ glVertex2f(v2d->cur.xmin, i);
+ glVertex2f(v2d->cur.xmin, i+1);
+ glVertex2f(v2d->cur.xmax, i+1);
+ i+=1.0;
+ }
+ glEnd();
+
+ /* Force grid lines */
+ i= MAX2(1, ((int)G.v2d->cur.ymin)-1);
+ glBegin(GL_LINES);
+
+ while (i<G.v2d->cur.ymax) {
+ BIF_ThemeColor(TH_GRID);
+ glVertex2f(G.v2d->cur.xmax, i);
+ glVertex2f(G.v2d->cur.xmin, i);
+ i+=1.0;
+ }
+ glEnd();
+
+
+ draw_ipogrid();
+ draw_cfra_seq();
+
+
+ /* sequences: first deselect */
+ if(ed) {
+ seq= ed->seqbasep->first;
+ while(seq) { /* bound box test, dont draw outside the view */
+ if (seq->flag & SELECT ||
+ MIN2(seq->startdisp, seq->start) > v2d->cur.xmax ||
+ MAX2(seq->enddisp, seq->start+seq->len) < v2d->cur.xmin ||
+ seq->machine+1.0 < v2d->cur.ymin ||
+ seq->machine > v2d->cur.ymax)
+ {
+ /* dont draw */
+ } else {
+ draw_seq_strip(seq, sa, sseq);
+ }
+ seq= seq->next;
+ }
+ }
+ ed= G.scene->ed;
+ if(ed) {
+ seq= ed->seqbasep->first;
+ while(seq) { /* bound box test, dont draw outside the view */
+ if (!(seq->flag & SELECT) ||
+ MIN2(seq->startdisp, seq->start) > v2d->cur.xmax ||
+ MAX2(seq->enddisp, seq->start+seq->len) < v2d->cur.xmin ||
+ seq->machine+1.0 < v2d->cur.ymin ||
+ seq->machine > v2d->cur.ymax)
+ {
+ /* dont draw */
+ } else {
+ draw_seq_strip(seq, sa, sseq);
+ }
+ seq= seq->next;
+ }
+ }
+
+ draw_extra_seqinfo();
+
+ /* Draw markers */
+ draw_markers_timespace(1);
+
+ /* restore viewport */
+ mywinset(sa->win);
+
+ /* ortho at pixel level sa */
+ myortho2(-0.375, sa->winx-0.375, -0.375, sa->winy-0.375);
+
+ if(sa->winx>SCROLLB+10 && sa->winy>SCROLLH+10) {
+ if(v2d->scroll) {
+ drawscroll(0);
+ }
+ }
+
+ draw_area_emboss(sa);
+
+ if(sseq->mainb==0) {
+ /* it is important to end a view in a transform compatible with buttons */
+ bwin_scalematrix(sa->win, sseq->blockscale, sseq->blockscale, sseq->blockscale);
+ seq_blockhandlers(sa);
+ }
+
+ sa->win_swap= WIN_BACK_OK;
+}
+
+
diff --git a/source/blender/src/drawsound.c b/source/blender/src/drawsound.c
new file mode 100644
index 00000000000..fd82430e3b7
--- /dev/null
+++ b/source/blender/src/drawsound.c
@@ -0,0 +1,241 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <math.h>
+#include <stdio.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_sound_types.h"
+#include "DNA_space_types.h"
+#include "DNA_screen_types.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_global.h"
+
+#include "BIF_gl.h"
+#include "BIF_mywindow.h"
+#include "BIF_screen.h"
+#include "BIF_editsound.h"
+#include "BIF_resources.h"
+
+#include "BSE_drawipo.h"
+#include "BSE_time.h"
+#include "BMF_Api.h"
+
+#include "blendef.h"
+
+/* local */
+void drawsoundspace(ScrArea *sa, void *spacedata);
+
+/*implementation */
+static void draw_wave(int startsamp, int endsamp, short sampdx, short offset, short *sp, float sampfac, float y)
+{
+ float min, max, v1[2], v2[3];
+ int i, j, deltasp, value; /*deltasp, value: were both shorts but for music files 5min, zooming out cased a crash */
+
+ sp+= offset*startsamp;
+
+ deltasp= offset*sampdx;
+
+ glBegin(GL_LINES);
+ for(i=startsamp; i<endsamp; i+=sampdx, sp+=deltasp) {
+
+ /* filter */
+ min= max= 0.0;
+ for(j=0; j<sampdx; j++) {
+ value= sp[offset*j];
+ if(value < min) min= value;
+ else if(value > max) max= value;
+ }
+ v1[1]= y + 0.002*min;
+ v2[1]= y + 0.002*max;
+
+ v1[0]=v2[0]= sampfac*i;
+
+ glVertex2fv(v1);
+ glVertex2fv(v2);
+ }
+ glEnd();
+}
+
+static void draw_sample(bSample *sample)
+{
+ float sampxlen, sampfac;
+ int samples, startsamp, endsamp;
+ short *sp, sampdx;
+
+ /* one sample is where in v2d space? (v2d space in frames!) */
+ sampfac= FPS/(sample->rate);
+
+ /* how many samples? */
+ samples= sample->len/(sample->channels*(sample->bits/8));
+ /* total len in v2d space */
+ sampxlen= sampfac*samples;
+
+ /* one pixel is how many samples? */
+ sampdx= (samples*((G.v2d->cur.xmax-G.v2d->cur.xmin)/sampxlen))/curarea->winx;
+
+ if(sampdx==0) sampdx= 1;
+
+ /* start and and */
+ startsamp = G.v2d->cur.xmin/sampfac;
+ CLAMP(startsamp, 0, samples-1);
+ endsamp= G.v2d->cur.xmax/sampfac;
+ CLAMP(endsamp, 0, samples-1);
+ endsamp-= sampdx;
+
+ /* set 'tot' for sliders */
+ G.v2d->tot.xmax= sampfac*samples;
+
+ /* channels? */
+ if(sample->channels==2) {
+
+ cpack(0x905050);
+ sp= (short *)(sample->data);
+ draw_wave(startsamp, endsamp, sampdx, 2, sp, sampfac, 85.0);
+
+ cpack(0x506890);
+ sp++;
+ draw_wave(startsamp, endsamp, sampdx, 2, sp, sampfac, 190.0);
+ }
+ else {
+ cpack(0x905050);
+ sp= (short *)(sample->data);
+
+ draw_wave(startsamp, endsamp, sampdx, 1, sp, sampfac, 128.0);
+ }
+}
+
+static void draw_cfra_sound(SpaceSound *ssound)
+{
+ float vec[2];
+
+ if(ssound->flag & SND_CFRA_NUM) {
+ short mval[2];
+ float x, y;
+ char str[32];
+ /* little box with frame */
+
+ getmouseco_areawin(mval);
+
+ if(mval[1]>curarea->winy-10) mval[1]= curarea->winy - 13;
+
+ if (curarea->winy < 25) {
+ if (mval[1]<17) mval[1]= 17;
+ } else if (mval[1]<22) mval[1]= 22;
+
+ areamouseco_to_ipoco(G.v2d, mval, &x, &y);
+
+ if(ssound->flag & SND_DRAWFRAMES)
+ sprintf(str, " %d\n", CFRA);
+ else sprintf(str, " %.2f\n", FRA2TIME(CFRA));
+
+ glRasterPos2f(x, y);
+ glColor3ub(0, 0, 0);
+ BMF_DrawString(G.font, str);
+
+ }
+
+ vec[0]= (G.scene->r.cfra);
+ vec[0]*= G.scene->r.framelen;
+
+ vec[1]= G.v2d->cur.ymin;
+ glColor3ub(0x20, 0x90, 0x20);
+ glLineWidth(4.0);
+
+ glBegin(GL_LINE_STRIP);
+ glVertex2fv(vec);
+ vec[1]= G.v2d->cur.ymax;
+ glVertex2fv(vec);
+ glEnd();
+
+ glLineWidth(1.0);
+
+}
+
+void drawsoundspace(ScrArea *sa, void *spacedata)
+{
+ float col[3];
+ short ofsx, ofsy;
+
+ BIF_GetThemeColor3fv(TH_BACK, col);
+ glClearColor(col[0], col[1], col[2], 0.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ calc_scrollrcts(sa, G.v2d, curarea->winx, curarea->winy);
+
+ if(curarea->winx>SCROLLB+10 && curarea->winy>SCROLLH+10) {
+ if(G.v2d->scroll) {
+ ofsx= curarea->winrct.xmin; /* because mywin */
+ ofsy= curarea->winrct.ymin;
+ glViewport(ofsx+G.v2d->mask.xmin, ofsy+G.v2d->mask.ymin, ( ofsx+G.v2d->mask.xmax-1)-(ofsx+G.v2d->mask.xmin)+1, ( ofsy+G.v2d->mask.ymax-1)-( ofsy+G.v2d->mask.ymin)+1);
+ glScissor(ofsx+G.v2d->mask.xmin, ofsy+G.v2d->mask.ymin, ( ofsx+G.v2d->mask.xmax-1)-(ofsx+G.v2d->mask.xmin)+1, ( ofsy+G.v2d->mask.ymax-1)-( ofsy+G.v2d->mask.ymin)+1);
+ }
+ }
+
+ myortho2(G.v2d->cur.xmin, G.v2d->cur.xmax, G.v2d->cur.ymin, G.v2d->cur.ymax);
+
+ /* boundbox_seq(); */
+ calc_ipogrid();
+ draw_ipogrid();
+
+ if (G.ssound->sound) {
+ sound_initialize_sample(G.ssound->sound);
+ draw_sample(G.ssound->sound->sample);
+ }
+
+ draw_cfra_sound(spacedata);
+ draw_markers_timespace(0);
+
+ /* restore viewport */
+ mywinset(curarea->win);
+
+ /* ortho at pixel level curarea */
+ myortho2(-0.375, curarea->winx-0.375, -0.375, curarea->winy-0.375);
+
+ if(curarea->winx>SCROLLB+10 && curarea->winy>SCROLLH+10) {
+ if(G.v2d->scroll) {
+ drawscroll(0);
+ }
+ }
+
+ myortho2(-0.375, curarea->winx-0.375, -0.375, curarea->winy-0.375);
+ draw_area_emboss(sa);
+ curarea->win_swap= WIN_BACK_OK;
+}
diff --git a/source/blender/src/drawtext.c b/source/blender/src/drawtext.c
new file mode 100644
index 00000000000..1ea29886850
--- /dev/null
+++ b/source/blender/src/drawtext.c
@@ -0,0 +1,2175 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef _WIN32
+#include <unistd.h>
+#else
+#include <io.h>
+#include "BLI_winstuff.h"
+#endif
+#include "MEM_guardedalloc.h"
+#include "PIL_time.h"
+
+#include "BMF_Api.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "DNA_text_types.h"
+#include "DNA_space_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_text.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+#include "BIF_keyval.h"
+#include "BIF_interface.h"
+#include "BIF_drawtext.h"
+#include "BIF_editfont.h"
+#include "BIF_spacetypes.h"
+#include "BIF_usiblender.h"
+#include "BIF_screen.h"
+#include "BIF_toolbox.h"
+#include "BIF_space.h"
+#include "BIF_mywindow.h"
+#include "BIF_resources.h"
+
+#include "BSE_filesel.h"
+
+#include "BPY_extern.h"
+
+#include "mydevice.h"
+#include "blendef.h"
+
+#define TEXTXLOC 38
+
+/* forward declarations */
+
+void drawtextspace(ScrArea *sa, void *spacedata);
+void winqreadtextspace(struct ScrArea *sa, void *spacedata, struct BWinEvent *evt);
+void txt_copy_selectbuffer (Text *text);
+void txt_paste_clipboard(Text *text); /* blank on non Win32 */
+void txt_copy_clipboard(Text *text); /* blank on non Win32 */
+void do_brackets();
+
+int check_bracket(char *string);
+static int check_delim(char *string);
+static int check_numbers(char *string);
+static int check_builtinfuncs(char *string);
+static int check_specialvars(char *string);
+
+static void *last_txt_find_string= NULL;
+
+static BMF_Font *spacetext_get_font(SpaceText *st) {
+ static BMF_Font *scr12= NULL;
+ static BMF_Font *scr15= NULL;
+
+ switch (st->font_id) {
+ default:
+ case 0:
+ if (!scr12)
+ scr12= BMF_GetFont(BMF_kScreen12);
+ return scr12;
+ case 1:
+ if (!scr15)
+ scr15= BMF_GetFont(BMF_kScreen15);
+ return scr15;
+ }
+}
+
+static int spacetext_get_fontwidth(SpaceText *st) {
+ return BMF_GetCharacterWidth(spacetext_get_font(st), ' ');
+}
+
+static char *temp_char_buf= NULL;
+static int *temp_char_accum= NULL;
+static int temp_char_len= 0;
+static int temp_char_pos= 0;
+
+static void temp_char_write(char c, int accum) {
+ if (temp_char_len==0 || temp_char_pos>=temp_char_len) {
+ char *nbuf; int *naccum;
+ int olen= temp_char_len;
+
+ if (olen) temp_char_len*= 2;
+ else temp_char_len= 256;
+
+ nbuf= MEM_mallocN(sizeof(*temp_char_buf)*temp_char_len, "temp_char_buf");
+ naccum= MEM_mallocN(sizeof(*temp_char_accum)*temp_char_len, "temp_char_accum");
+
+ if (olen) {
+ memcpy(nbuf, temp_char_buf, olen);
+ memcpy(naccum, temp_char_accum, olen);
+
+ MEM_freeN(temp_char_buf);
+ MEM_freeN(temp_char_accum);
+ }
+
+ temp_char_buf= nbuf;
+ temp_char_accum= naccum;
+ }
+
+ temp_char_buf[temp_char_pos]= c;
+ temp_char_accum[temp_char_pos]= accum;
+
+ if (c==0) temp_char_pos= 0;
+ else temp_char_pos++;
+}
+
+void free_txt_data(void) {
+ txt_free_cut_buffer();
+
+ if (last_txt_find_string) MEM_freeN(last_txt_find_string);
+ if (temp_char_buf) MEM_freeN(temp_char_buf);
+ if (temp_char_accum) MEM_freeN(temp_char_accum);
+}
+
+static int render_string (char *in) {
+ SpaceText *st= curarea->spacedata.first;
+ int r = 0, i = 0;
+
+ while(*in) {
+ if (*in=='\t') {
+ if (temp_char_pos && *(in-1)=='\t') i= st->tabnumber;
+ else if (st->tabnumber > 0) i= st->tabnumber - (temp_char_pos%st->tabnumber);
+
+ while(i--) temp_char_write(' ', r);
+ } else temp_char_write(*in, r);
+
+ r++;
+ in++;
+ }
+ r= temp_char_pos;
+ temp_char_write(0, 0);
+
+ return r;
+}
+
+void get_format_string(void)
+{
+ SpaceText *st = curarea->spacedata.first;
+ Text *text = st->text;
+ TextLine *tmp;
+ char *in_line;
+ char format[2000], check[200], other[2];
+ unsigned char c;
+ int a, b, len, spot, letter, tabs, mem_amount;
+
+ if(!text) return;
+ tmp = text->lines.first;
+
+ while(tmp) {
+ in_line = tmp->line;
+
+ len = strlen(in_line);
+ /* weak code... but we dont want crashes (ton) */
+ if(len>2000-1) {
+ if (tmp->format) MEM_freeN(tmp->format);
+ tmp->format= NULL;
+ }
+ else {
+
+ spot = 0;
+ tabs = 0;
+ //see how many tabs we have
+ for(a = 0; a <len; a++) {
+ c = (unsigned char) in_line[a];
+ if(c == '\t') {
+ tabs++;
+ }
+ }
+ //calculate the amount of MEM_mallocN we neen
+ mem_amount = (((tabs*st->tabnumber)-tabs)+2)+len; // +2 for good measure
+ if (tmp->format) MEM_freeN(tmp->format);
+ tmp->format = MEM_mallocN(mem_amount, "Syntax_format");
+
+ for (a = 0; a < len; a++) {
+ c = (unsigned char) in_line[a];
+
+ check[0] = c;
+ check[1] = '\0';
+
+ if (check_delim(check))
+ {
+ switch (c) {
+ case '\"':
+ if(in_line[a] == '\"' && in_line[a+1] == '\"' && in_line[a+2] == '\"') {
+ format[spot] = format[spot+1] = format[spot+2] = 'l';
+ spot +=3;
+ a += 3;
+ while(in_line[a] != '\"' || in_line[a-1] != '\"' || in_line[a-2] != '\"') {
+ c = (unsigned char) in_line[a];
+ if(a >= len) {
+ format[spot] = '\0';
+ memcpy(tmp->format, format, strlen(format));
+ if(!(tmp= tmp->next)) {
+ return;
+ } else {
+ in_line = tmp->line;
+ len = strlen(in_line);
+ tabs = 0;
+ for(b = 0; b <len; b++) {
+ c = (unsigned char) in_line[b];
+ if(c == '\t') {
+ tabs++;
+ }
+ }
+ mem_amount = (((tabs*st->tabnumber)-tabs)+2)+len;
+ if (tmp->format) MEM_freeN(tmp->format);
+ tmp->format = MEM_mallocN(mem_amount, "Syntax_format");
+ a = 0; spot = 0;
+ }
+ } else {
+ if(c == '\t' || c == ' ') {
+ if(c == '\t') {
+ for(b = st->tabnumber-(spot%st->tabnumber); b > 0; b--) {
+ format[spot] = ' ';
+ spot++;
+ }
+ a++;
+ } else {
+ format[spot] = ' ';
+ a++; spot++;
+ }
+ } else {
+ format[spot] = 'l';
+ a++; spot++;
+ }
+ }
+ }
+ format[spot] = 'l';
+ spot++;
+ } else {
+ format[spot] = 'l';
+ a++; spot++;
+ while(in_line[a] != '\"') {
+ c = (unsigned char) in_line[a];
+ if(a >= len) {
+ format[spot] = '\0';
+ memcpy(tmp->format, format, strlen(format));
+ if(!(tmp= tmp->next)) {
+ return;
+ } else {
+ in_line = tmp->line;
+ len = strlen(in_line);
+ for(b = 0; b <len; b++) {
+ c = (unsigned char) in_line[b];
+ if(c == '\t') {
+ tabs++;
+ }
+ }
+ //calculate the amount of MEM_mallocN we neen
+ mem_amount = (((tabs*st->tabnumber)-tabs)+2)+len;
+ if (tmp->format) MEM_freeN(tmp->format);
+ tmp->format = MEM_mallocN(mem_amount, "Syntax_format");
+ a = 0; spot = 0;
+ }
+ }
+ if(c == '\t' || c == ' ') {
+ if(c == '\t') {
+ for(b = st->tabnumber-(spot%st->tabnumber); b > 0; b--) {
+ format[spot] = ' ';
+ spot++;
+ }
+ a++;
+ } else {
+ format[spot] = ' ';
+ a++; spot++;
+ }
+ } else {
+ format[spot] = 'l';
+ a++; spot++;
+ }
+ }
+ format[spot] = 'l';
+ spot++;
+ }
+ break;
+ case '\'':
+ if(in_line[a] == '\'' && in_line[a+1] == '\'' && in_line[a+2] == '\'') {
+ format[spot] = format[spot+1] = format[spot+2] = 'l';
+ spot +=3;
+ a += 3;
+ while(in_line[a] != '\'' || in_line[a-1] != '\'' || in_line[a-2] != '\'') {
+ c = (unsigned char) in_line[a];
+ if(a >= len) {
+ format[spot] = '\0';
+ memcpy(tmp->format, format, strlen(format));
+ if(!(tmp= tmp->next)) {
+ return;
+ } else {
+ in_line = tmp->line;
+ len = strlen(in_line);
+ tabs = 0;
+ for(b = 0; b <len; b++) {
+ c = (unsigned char) in_line[b];
+ if(c == '\t') {
+ tabs++;
+ }
+ }
+ mem_amount = (((tabs*st->tabnumber)-tabs)+2)+len;
+ if (tmp->format) MEM_freeN(tmp->format);
+ tmp->format = MEM_mallocN(mem_amount, "Syntax_format");
+ a = 0; spot = 0;
+ }
+ } else {
+ if(c == '\t' || c == ' ') {
+ if(c == '\t') {
+ for(b = st->tabnumber-(spot%st->tabnumber); b > 0; b--) {
+ format[spot] = ' ';
+ spot++;
+ }
+ a++;
+ } else {
+ format[spot] = ' ';
+ a++; spot++;
+ }
+ } else {
+ format[spot] = 'l';
+ a++; spot++;
+ }
+ }
+ }
+ format[spot] = 'l';
+ spot++;
+ } else {
+ format[spot] = 'l';
+ a++; spot++;
+ while(in_line[a] != '\'') {
+ c = (unsigned char) in_line[a];
+ if(a >= len) {
+ format[spot] = '\0';
+ memcpy(tmp->format, format, strlen(format));
+ if(!(tmp= tmp->next)) {
+ return;
+ } else {
+ in_line = tmp->line;
+ len = strlen(in_line);
+ for(b = 0; b <len; b++) {
+ c = (unsigned char) in_line[b];
+ if(c == '\t') {
+ tabs++;
+ }
+ }
+ //calculate the amount of MEM_mallocN we neen
+ mem_amount = (((tabs*st->tabnumber)-tabs)+2)+len;
+ if (tmp->format) MEM_freeN(tmp->format);
+ tmp->format = MEM_mallocN(mem_amount, "Syntax_format");
+ a = 0; spot = 0;
+ }
+ }
+ if(c == '\t' || c == ' ') {
+ if(c == '\t') {
+ for(b = st->tabnumber-(spot%st->tabnumber); b > 0; b--) {
+ format[spot] = ' ';
+ spot++;
+ }
+ a++;
+ } else {
+ format[spot] = ' ';
+ a++; spot++;
+ }
+ } else {
+ format[spot] = 'l';
+ a++; spot++;
+ }
+ }
+ format[spot] = 'l';
+ spot++;
+ }
+ break;
+ case '#':
+ while(a<len) {
+ c = (unsigned char) in_line[a];
+ if(c == '\t' || c == ' ') {
+ if(c == '\t') {
+ for(b = st->tabnumber-(spot%st->tabnumber); b > 0; b--) {
+ format[spot] = '#';
+ spot++;
+ }
+ a++;
+ } else {
+ format[spot] = '#';
+ a++; spot++;
+ }
+ } else {
+ format[spot] = '#';
+ a++; spot++;
+ }
+ }
+ break;
+ case ' ':
+ format[spot] = ' ';
+ spot++;
+ break;
+ case '\t':
+ for(b = st->tabnumber-(spot%st->tabnumber); b > 0; b--) {
+ format[spot] = ' ';
+ spot++;
+ }
+ break;
+ default:
+ format[spot] = 'q';
+ spot++;
+
+ break;
+ }
+ } else if (check_numbers(check)) {
+ while (a < len) {
+ c = (unsigned char) in_line[a];
+ other[0] = c;
+ other[1] = '\0';
+ if (check_delim(other) && c != '.') {
+ a--; break;
+ } else {
+ format[spot] = 'n';
+ a++; spot++;
+ }
+ }
+ } else {
+ letter = 0;
+ while (a < len) {
+ c = (unsigned char) in_line[a];
+ other[0] = c;
+ other[1] = '\0';
+ if (check_delim(other)) {
+ a--;
+ break;
+ } else {
+ check[letter] = (unsigned char) in_line[a];
+ letter++;
+ a++;
+ }
+ }
+ check[letter] = '\0';
+ if (check_builtinfuncs(check)) {
+ for (b = 0; b < strlen(check); b++) {
+ format[spot] = 'b';
+ spot++;
+ }
+ } else if (check_specialvars(check)) { /*If TRUE then color and color next word*/
+ for (b = 0; b < strlen(check); b++) {
+ format[spot] = 'b';
+ spot++;
+ }
+ a++;
+ format[spot] = 'q';
+ spot++; a++;
+ letter = 0;
+ while (a < len) {
+ c = (unsigned char) in_line[a];
+ other[0] = c;
+ other[1] = '\0';
+ if (check_delim(other)) {
+ a--;
+ break;
+ } else {
+ check[letter] = (unsigned char) in_line[a];
+ letter++;
+ a++;
+ }
+ }
+ check[letter] = '\0';
+ for (b = 0; b < strlen(check); b++) {
+ format[spot] = 'v';
+ spot++;
+ }
+ }else {
+ for (b = 0; b < strlen(check); b++) {
+ format[spot] = 'q';
+ spot++;
+ }
+ }
+ }
+ }
+ format[spot] = '\0';
+ memcpy(tmp->format, format, strlen(format));
+ }
+
+ tmp = tmp->next;
+ }
+}
+
+static int text_draw(SpaceText *st, char *str, int cshift, int maxwidth, int draw, int x, int y, char *format) {
+ int r=0, w= 0;
+ char *in;
+ int *acc;
+
+ w= render_string(str);
+ if(w<cshift ) return 0; /* String is shorter than shift */
+
+ in= temp_char_buf+cshift;
+ acc= temp_char_accum+cshift;
+ w= w-cshift;
+
+ if (draw) {
+ if(st->showsyntax && format) {
+ int amount, a;
+ char out[2];
+ format = format+cshift;
+
+ amount = strlen(in);
+
+ for(a = 0; a < amount; a++) {
+ out[0] = (unsigned char) in[a];
+ out[1] = '\0';
+ switch (format[a]) {
+ case 'l':
+ BIF_ThemeColor(TH_SYNTAX_L);
+ break;
+ case 'b':
+ BIF_ThemeColor(TH_SYNTAX_B);
+ break;
+ case '#':
+ BIF_ThemeColor(TH_SYNTAX_C);
+ break;
+ case 'v':
+ BIF_ThemeColor(TH_SYNTAX_V);
+ break;
+ case 'n':
+ BIF_ThemeColor(TH_SYNTAX_N);
+ break;
+ case 'q':
+ BIF_ThemeColor(TH_TEXT);
+ break;
+ default:
+ BIF_ThemeColor(TH_TEXT);
+ break;
+ }
+ glRasterPos2i(x, y);
+ BMF_DrawString(spacetext_get_font(st), out);
+ x = x+BMF_GetStringWidth(spacetext_get_font(st), out);
+ }
+ } else {
+ glRasterPos2i(x, y);
+ BMF_DrawString(spacetext_get_font(st), in);
+ }
+ } else {
+ while (w-- && *acc++ < maxwidth) {
+ r+= spacetext_get_fontwidth(st);
+ }
+ }
+
+ if (cshift && r==0) return 0;
+ else if (st->showlinenrs)
+ return r+TXT_OFFSET+TEXTXLOC;
+ else
+ return r+TXT_OFFSET;
+}
+
+static void set_cursor_to_pos (SpaceText *st, int x, int y, int sel)
+{
+ Text *text;
+ TextLine **linep;
+ int *charp;
+ int w;
+
+ text= st->text;
+
+ if(sel) { linep= &text->sell; charp= &text->selc; }
+ else { linep= &text->curl; charp= &text->curc; }
+
+ y= (curarea->winy - y)/st->lheight;
+
+ y-= txt_get_span(text->lines.first, *linep) - st->top;
+
+ if (y>0) {
+ while (y-- != 0) if((*linep)->next) *linep= (*linep)->next;
+ } else if (y<0) {
+ while (y++ != 0) if((*linep)->prev) *linep= (*linep)->prev;
+ }
+
+ if(st->showlinenrs)
+ x-= TXT_OFFSET+TEXTXLOC;
+ else
+ x-= TXT_OFFSET;
+
+ if (x<0) x= 0;
+ x = (x/spacetext_get_fontwidth(st)) + st->left;
+
+ w= render_string((*linep)->line);
+ if(x<w) *charp= temp_char_accum[x];
+ else *charp= (*linep)->len;
+
+ if(!sel) txt_pop_sel(text);
+}
+
+static void draw_cursor(SpaceText *st) {
+ int h, x, i;
+ Text *text= st->text;
+ TextLine *linef, *linel;
+ int charf, charl;
+
+ if (text->curl==text->sell && text->curc==text->selc) {
+ x= text_draw(st, text->curl->line, st->left, text->curc, 0, 0, 0, NULL);
+
+ if (x) {
+ h= txt_get_span(text->lines.first, text->curl) - st->top;
+
+ BIF_ThemeColor(TH_HILITE);
+
+ glRecti(x-1, curarea->winy-st->lheight*(h)-2, x+1, curarea->winy-st->lheight*(h+1)-2);
+ }
+ } else {
+ int span= txt_get_span(text->curl, text->sell);
+
+ if (span<0) {
+ linef= text->sell;
+ charf= text->selc;
+
+ linel= text->curl;
+ charl= text->curc;
+ } else if (span>0) {
+ linef= text->curl;
+ charf= text->curc;
+
+ linel= text->sell;
+ charl= text->selc;
+ } else {
+ linef= linel= text->curl;
+
+ if (text->curc<text->selc) {
+ charf= text->curc;
+ charl= text->selc;
+ } else {
+ charf= text->selc;
+ charl= text->curc;
+ }
+ }
+
+ /* Walk to the beginning of visible text */
+ h= txt_get_span(text->lines.first, linef) - st->top;
+ while (h++<-1 && linef!=linel) linef= linef->next;
+
+ x= text_draw(st, linef->line, st->left, charf, 0, 0, 0, NULL);
+
+ BIF_ThemeColor(TH_SHADE2);
+
+ if(st->showlinenrs) {
+ if (!x) x= TXT_OFFSET + TEXTXLOC -4;
+ } else {
+ if (!x) x= TXT_OFFSET - 4;
+ }
+
+ while (linef && linef != linel) {
+ h= txt_get_span(text->lines.first, linef) - st->top;
+ if (h>st->viewlines) break;
+
+ glRecti(x, curarea->winy-st->lheight*(h)-2, curarea->winx, curarea->winy-st->lheight*(h+1)-2);
+ if(st->showlinenrs)
+ glRecti(TXT_OFFSET+TEXTXLOC-4, curarea->winy-st->lheight*(h+1)-2, TXT_OFFSET+TEXTXLOC, curarea->winy-st->lheight*(h+2)-2);
+ else
+ glRecti(TXT_OFFSET-4, curarea->winy-st->lheight*(h+1)-2, TXT_OFFSET, curarea->winy-st->lheight*(h+2)-2);
+
+ if(st->showlinenrs)
+ x= TXT_OFFSET + TEXTXLOC;
+ else
+ x= TXT_OFFSET;
+
+ linef= linef->next;
+ }
+
+ h= txt_get_span(text->lines.first, linef) - st->top;
+
+ i= text_draw(st, linel->line, st->left, charl, 0, 0, 0, NULL);
+ if(i) glRecti(x, curarea->winy-st->lheight*(h)-2, i, curarea->winy-st->lheight*(h+1)-2);
+
+ }
+
+ do_brackets();
+ BIF_ThemeColor(TH_TEXT);
+}
+
+static void calc_text_rcts(SpaceText *st)
+{
+ short barheight, barstart;
+ int lbarstart, lbarh, ltexth;
+
+ lbarstart= st->top;
+ lbarh= st->viewlines;
+ ltexth= txt_get_span(st->text->lines.first, st->text->lines.last)+1;
+
+ barheight= (lbarh*(curarea->winy-4))/ltexth;
+ if (barheight<20) barheight=20;
+
+ barstart= (lbarstart*(curarea->winy-4))/ltexth + 8;
+
+ st->txtbar.xmin= 5;
+ st->txtbar.xmax= 17;
+ st->txtbar.ymax= curarea->winy - barstart;
+ st->txtbar.ymin= st->txtbar.ymax - barheight;
+
+ CLAMP(st->txtbar.ymin, 2, curarea->winy-2);
+ CLAMP(st->txtbar.ymax, 2, curarea->winy-2);
+
+ st->pix_per_line= (float) ltexth/curarea->winy;
+ if (st->pix_per_line<.1) st->pix_per_line=.1f;
+
+ lbarstart= MIN2(txt_get_span(st->text->lines.first, st->text->curl),
+ txt_get_span(st->text->lines.first, st->text->sell));
+ lbarh= abs(txt_get_span(st->text->lines.first, st->text->curl)-txt_get_span(st->text->lines.first, st->text->sell));
+
+ barheight= (lbarh*(curarea->winy-4))/ltexth;
+ if (barheight<2) barheight=2;
+
+ barstart= (lbarstart*(curarea->winy-4))/ltexth + 8;
+
+ st->txtscroll.xmin= 5;
+ st->txtscroll.xmax= 17;
+ st->txtscroll.ymax= curarea->winy-barstart;
+ st->txtscroll.ymin= st->txtscroll.ymax - barheight;
+
+ CLAMP(st->txtscroll.ymin, 2, curarea->winy-2);
+ CLAMP(st->txtscroll.ymax, 2, curarea->winy-2);
+}
+
+static void draw_textscroll(SpaceText *st)
+{
+ if (!st->text) return;
+
+ calc_text_rcts(st);
+
+ BIF_ThemeColorShade(TH_SHADE1, -20);
+ glRecti(2, 2, 20, curarea->winy-6);
+ uiEmboss(2, 2, 20, curarea->winy-6, 1);
+
+ BIF_ThemeColor(TH_SHADE1);
+ glRecti(st->txtbar.xmin, st->txtbar.ymin, st->txtbar.xmax, st->txtbar.ymax);
+
+ BIF_ThemeColor(TH_SHADE2);
+ glRecti(st->txtscroll.xmin, st->txtscroll.ymin, st->txtscroll.xmax, st->txtscroll.ymax);
+
+ uiEmboss(st->txtbar.xmin, st->txtbar.ymin, st->txtbar.xmax, st->txtbar.ymax, st->flags & ST_SCROLL_SELECT);
+}
+
+static void screen_skip(SpaceText *st, int lines)
+{
+ int last;
+
+ if (!st) return;
+ if (st->spacetype != SPACE_TEXT) return;
+ if (!st->text) return;
+
+ st->top += lines;
+
+ last= txt_get_span(st->text->lines.first, st->text->lines.last);
+ last= last - (st->viewlines/2);
+
+ if (st->top>last) st->top= last;
+ if (st->top<0) st->top= 0;
+}
+
+/*
+ * mode 1 == view scroll
+ * mode 2 == scrollbar
+ */
+static void do_textscroll(SpaceText *st, int mode)
+{
+ short delta[2]= {0, 0};
+ short mval[2], hold[2], old[2];
+
+ if (!st->text) return;
+
+ calc_text_rcts(st);
+
+ st->flags|= ST_SCROLL_SELECT;
+
+ glDrawBuffer(GL_FRONT);
+ uiEmboss(st->txtbar.xmin, st->txtbar.ymin, st->txtbar.xmax, st->txtbar.ymax, st->flags & ST_SCROLL_SELECT);
+ bglFlush();
+ glDrawBuffer(GL_BACK);
+
+ getmouseco_areawin(mval);
+ old[0]= hold[0]= mval[0];
+ old[1]= hold[1]= mval[1];
+
+ while(get_mbut()&(L_MOUSE|M_MOUSE)) {
+ getmouseco_areawin(mval);
+
+ if(old[0]!=mval[0] || old[1]!=mval[1]) {
+ if (mode==1) {
+ delta[0]= (hold[0]-mval[0])/spacetext_get_fontwidth(st);
+ delta[1]= (mval[1]-hold[1])/st->lheight;
+ }
+ else delta[1]= (hold[1]-mval[1])*st->pix_per_line;
+
+ if (delta[0] || delta[1]) {
+ screen_skip(st, delta[1]);
+ st->left+= delta[0];
+ if (st->left<0) st->left= 0;
+
+ scrarea_do_windraw(curarea);
+ screen_swapbuffers();
+
+ hold[0]=mval[0];
+ hold[1]=mval[1];
+ }
+ old[0]=mval[0];
+ old[1]=mval[1];
+ } else {
+ BIF_wait_for_statechange();
+ }
+ }
+ st->flags^= ST_SCROLL_SELECT;
+
+ glDrawBuffer(GL_FRONT);
+ uiEmboss(st->txtbar.xmin, st->txtbar.ymin, st->txtbar.xmax, st->txtbar.ymax, st->flags & ST_SCROLL_SELECT);
+ bglFlush();
+ glDrawBuffer(GL_BACK);
+}
+
+static void do_selection(SpaceText *st, int selecting)
+{
+ short mval[2], old[2];
+ int sell, selc;
+ int linep2, charp2;
+ int first= 1;
+
+ getmouseco_areawin(mval);
+ old[0]= mval[0];
+ old[1]= mval[1];
+
+ if (!selecting) {
+ int curl= txt_get_span(st->text->lines.first, st->text->curl);
+ int curc= st->text->curc;
+ int linep2, charp2;
+
+ set_cursor_to_pos(st, mval[0], mval[1], 0);
+
+ linep2= txt_get_span(st->text->lines.first, st->text->curl);
+ charp2= st->text->selc;
+
+ if (curl!=linep2 || curc!=charp2)
+ txt_undo_add_toop(st->text, UNDO_CTO, curl, curc, linep2, charp2);
+ }
+
+ sell= txt_get_span(st->text->lines.first, st->text->sell);
+ selc= st->text->selc;
+
+ while(get_mbut()&L_MOUSE) {
+ getmouseco_areawin(mval);
+
+ if (mval[1]<0 || mval[1]>curarea->winy) {
+ int d= (old[1]-mval[1])*st->pix_per_line;
+ if (d) screen_skip(st, d);
+
+ set_cursor_to_pos(st, mval[0], mval[1]<0?0:curarea->winy, 1);
+
+ scrarea_do_windraw(curarea);
+ screen_swapbuffers();
+ } else if (mval[0]<0 || mval[0]>curarea->winx) {
+ if (mval[0]>curarea->winx) st->left++;
+ else if (mval[0]<0 && st->left>0) st->left--;
+
+ set_cursor_to_pos(st, mval[0], mval[1], 1);
+
+ scrarea_do_windraw(curarea);
+ screen_swapbuffers();
+
+ PIL_sleep_ms(10);
+ } else if (first || old[0]!=mval[0] || old[1]!=mval[1]) {
+ set_cursor_to_pos(st, mval[0], mval[1], 1);
+
+ scrarea_do_windraw(curarea);
+ screen_swapbuffers();
+
+ old[0]= mval[0];
+ old[1]= mval[1];
+ first= 1;
+ } else {
+ BIF_wait_for_statechange();
+ }
+ }
+
+ linep2= txt_get_span(st->text->lines.first, st->text->sell);
+ charp2= st->text->selc;
+
+ if (sell!=linep2 || selc!=charp2)
+ txt_undo_add_toop(st->text, UNDO_STO, sell, selc, linep2, charp2);
+}
+
+void drawtextspace(ScrArea *sa, void *spacedata)
+{
+ SpaceText *st= curarea->spacedata.first;
+ Text *text;
+ int i;
+ TextLine *tmp;
+ char linenr[12];
+ float col[3];
+ int linecount = 0;
+
+ BIF_GetThemeColor3fv(TH_BACK, col);
+ glClearColor(col[0], col[1], col[2], 0.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ myortho2(-0.375, (float)(sa->winx)-0.375, -0.375, (float)(sa->winy)-0.375);
+
+ draw_area_emboss(sa);
+
+ text= st->text;
+ if(!text) return;
+
+ /* Make sure all the positional pointers exist */
+ if (!text->curl || !text->sell || !text->lines.first || !text->lines.last)
+ txt_clean_text(text);
+
+ if(st->lheight) st->viewlines= (int) curarea->winy/st->lheight;
+ else st->viewlines= 0;
+
+ if(st->showlinenrs) {
+ cpack(0x8c787c);
+ glRecti(23, 0, (st->lheight==15)?63:59, curarea->winy - 2);
+ }
+
+ BIF_ThemeColor(TH_TEXT);
+
+ draw_cursor(st);
+
+ tmp= text->lines.first;
+ for (i= 0; i<st->top && tmp; i++) {
+ tmp= tmp->next;
+ linecount++;
+ }
+
+ if(st->showsyntax) {
+ if (tmp && !tmp->format) {
+ get_format_string();
+ }
+ }
+
+ for (i=0; i<st->viewlines && tmp; i++, tmp= tmp->next) {
+ if(st->showlinenrs) {
+ BIF_ThemeColor(TH_TEXT);
+ if(((float)(i + linecount + 1)/10000.0) < 1.0) {
+ sprintf(linenr, "%4d", i + linecount + 1);
+ glRasterPos2i(TXT_OFFSET - 7, curarea->winy-st->lheight*(i+1));
+ } else {
+ sprintf(linenr, "%5d", i + linecount + 1);
+ glRasterPos2i(TXT_OFFSET - 11, curarea->winy-st->lheight*(i+1));
+ }
+ BMF_DrawString(spacetext_get_font(st), linenr);
+ text_draw(st, tmp->line, st->left, 0, 1, TXT_OFFSET + TEXTXLOC, curarea->winy-st->lheight*(i+1), tmp->format);
+ } else
+ text_draw(st, tmp->line, st->left, 0, 1, TXT_OFFSET, curarea->winy-st->lheight*(i+1), tmp->format);
+ }
+
+ draw_textscroll(st);
+
+ curarea->win_swap= WIN_BACK_OK;
+}
+
+/* Moves the view to the cursor location,
+ also used to make sure the view isnt outside the file */
+void pop_space_text (SpaceText *st)
+{
+ int i, x;
+
+ if(!st) return;
+ if(!st->text) return;
+ if(!st->text->curl) return;
+
+ i= txt_get_span(st->text->lines.first, st->text->curl);
+ if (st->top+st->viewlines <= i || st->top > i) {
+ st->top= i - st->viewlines/2;
+ }
+
+ x= text_draw(st, st->text->curl->line, st->left, st->text->curc, 0, 0, 0, NULL);
+
+ if (x==0 || x>curarea->winx) {
+ st->left= st->text->curc-0.5*(curarea->winx)/spacetext_get_fontwidth(st);
+ }
+
+ if (st->top < 0) st->top= 0;
+ if (st->left <0) st->left= 0;
+}
+
+void add_text_fs(char *file)
+{
+ SpaceText *st= curarea->spacedata.first;
+ Text *text;
+
+ if (!st) return;
+ if (st->spacetype != SPACE_TEXT) return;
+
+ text= add_text(file);
+
+ st->text= text;
+
+ st->top= 0;
+
+ if (st->showsyntax) get_format_string();
+ allqueue(REDRAWTEXT, 0);
+ allqueue(REDRAWHEADERS, 0);
+}
+
+void free_textspace(SpaceText *st)
+{
+ if (!st) return;
+
+ st->text= NULL;
+}
+
+static void save_mem_text(char *str)
+{
+ SpaceText *st= curarea->spacedata.first;
+ Text *text;
+
+ if (!str) return;
+
+ if (!st) return;
+ if (st->spacetype != SPACE_TEXT) return;
+
+ text= st->text;
+ if(!text) return;
+
+ if (text->name) MEM_freeN(text->name);
+ text->name= MEM_mallocN(strlen(str)+1, "textname");
+ strcpy(text->name, str);
+
+ text->flags ^= TXT_ISMEM;
+
+ txt_write_file(text);
+}
+
+void txt_write_file(Text *text)
+{
+ FILE *fp;
+ TextLine *tmp;
+
+ /* Do we need to get a filename? */
+ if (text->flags & TXT_ISMEM) {
+ if (text->name)
+ activate_fileselect(FILE_SPECIAL, "SAVE TEXT FILE", text->name, save_mem_text);
+ else
+ activate_fileselect(FILE_SPECIAL, "SAVE TEXT FILE", text->id.name+2, save_mem_text);
+ return;
+ }
+
+ /* Should we ask to save over? */
+ if (text->flags & TXT_ISTMP) {
+ if (BLI_exists(text->name)) {
+ if (!okee("Save over")) return;
+ } else if (!okee("Create new file")) return;
+
+ text->flags ^= TXT_ISTMP;
+ }
+
+ fp= fopen(text->name, "w");
+ if (fp==NULL) {
+ error("Unable to save file");
+ return;
+ }
+
+ tmp= text->lines.first;
+ while (tmp) {
+ if (tmp->next) fprintf(fp, "%s\n", tmp->line);
+ else fprintf(fp, "%s", tmp->line);
+
+ tmp= tmp->next;
+ }
+
+ fclose (fp);
+
+ if (text->flags & TXT_ISDIRTY) text->flags ^= TXT_ISDIRTY;
+}
+
+void unlink_text(Text *text)
+{
+ bScreen *scr;
+ ScrArea *area;
+ SpaceLink *sl;
+
+ /* check if this text was used as script link:
+ * this check function unsets the pointers and returns how many
+ * script links used this Text */
+ if (BPY_check_all_scriptlinks (text)) {
+ allqueue(REDRAWBUTSSCRIPT, 0);
+ }
+
+ for (scr= G.main->screen.first; scr; scr= scr->id.next) {
+ for (area= scr->areabase.first; area; area= area->next) {
+ for (sl= area->spacedata.first; sl; sl= sl->next) {
+ if (sl->spacetype==SPACE_TEXT) {
+ SpaceText *st= (SpaceText*) sl;
+
+ if (st->text==text) {
+ st->text= NULL;
+ st->top= 0;
+
+ if (st==area->spacedata.first) {
+ scrarea_queue_redraw(area);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+int jumptoline_interactive(SpaceText *st) {
+ short nlines= txt_get_span(st->text->lines.first, st->text->lines.last)+1;
+ short tmp= txt_get_span(st->text->lines.first, st->text->curl)+1;
+
+ if (button(&tmp, 1, nlines, "Jump to line:")) {
+ txt_move_toline(st->text, tmp-1, 0);
+ pop_space_text(st);
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+
+int bufferlength;
+static char *copybuffer = NULL;
+
+void txt_copy_selectbuffer (Text *text)
+{
+ int length=0;
+ TextLine *tmp, *linef, *linel;
+ int charf, charl;
+
+ if (!text) return;
+ if (!text->curl) return;
+ if (!text->sell) return;
+
+ if (!txt_has_sel(text)) return;
+
+ if (copybuffer) {
+ MEM_freeN(copybuffer);
+ copybuffer= NULL;
+ }
+
+ if (text->curl==text->sell) {
+ linef= linel= text->curl;
+
+ if (text->curc < text->selc) {
+ charf= text->curc;
+ charl= text->selc;
+ } else{
+ charf= text->selc;
+ charl= text->curc;
+ }
+ } else if (txt_get_span(text->curl, text->sell)<0) {
+ linef= text->sell;
+ linel= text->curl;
+
+ charf= text->selc;
+ charl= text->curc;
+ } else {
+ linef= text->curl;
+ linel= text->sell;
+
+ charf= text->curc;
+ charl= text->selc;
+ }
+
+ if (linef == linel) {
+ length= charl-charf;
+
+ copybuffer= MEM_mallocN(length+1, "cut buffera");
+
+ BLI_strncpy(copybuffer, linef->line + charf, length+1);
+ } else {
+ length+= linef->len - charf;
+ length+= charl;
+ length++; /* For the '\n' */
+
+ tmp= linef->next;
+ while (tmp && tmp!= linel) {
+ length+= tmp->len+1;
+ tmp= tmp->next;
+ }
+
+ copybuffer= MEM_mallocN(length+1, "cut bufferb");
+
+ strncpy(copybuffer, linef->line+ charf, linef->len-charf);
+ length= linef->len-charf;
+
+ copybuffer[length++]='\n';
+
+ tmp= linef->next;
+ while (tmp && tmp!=linel) {
+ strncpy(copybuffer+length, tmp->line, tmp->len);
+ length+= tmp->len;
+
+ copybuffer[length++]='\n';
+
+ tmp= tmp->next;
+ }
+ strncpy(copybuffer+length, linel->line, charl);
+ length+= charl;
+
+ copybuffer[length]=0;
+ }
+
+ bufferlength = length;
+}
+
+
+#ifdef _WIN32
+static char *unixNewLine(char *buffer)
+{
+ char *p, *p2, *output;
+
+ /* we can afford the few extra bytes */
+ output= MEM_callocN(strlen(buffer)+1, "unixnewline");
+ for (p= buffer, p2= output; *p; p++)
+ if (*p != '\r') *(p2++)= *p;
+
+ *p2= 0;
+ return(output);
+}
+
+static char *winNewLine(char *buffer)
+{
+ char *p, *p2, *output;
+ int add= 0;
+
+ for (p= buffer; *p; p++)
+ if (*p == '\n') add++;
+
+ bufferlength= p-buffer+add+1;
+ output= MEM_callocN(bufferlength, "winnewline");
+ for (p= buffer, p2= output; *p; p++, p2++) {
+ if (*p == '\n') {
+ *(p2++)= '\r'; *p2= '\n';
+ } else *p2= *p;
+ }
+ *p2= 0;
+
+ return(output);
+}
+#endif
+
+
+void txt_paste_clipboard(Text *text) {
+#ifdef _WIN32
+ char * buffer = NULL;
+
+ if ( OpenClipboard(NULL) ) {
+ HANDLE hData = GetClipboardData( CF_TEXT );
+ buffer = (char*)GlobalLock( hData );
+ if (buffer) {
+ buffer = unixNewLine(buffer);
+ if (buffer) txt_insert_buf(text, buffer);
+ }
+ GlobalUnlock( hData );
+ CloseClipboard();
+ MEM_freeN(buffer);
+ }
+#endif
+}
+
+void txt_copy_clipboard(Text *text) {
+#ifdef _WIN32
+ txt_copy_selectbuffer(text);
+
+ if (OpenClipboard(NULL)) {
+ HLOCAL clipbuffer;
+ char* buffer;
+
+ if (copybuffer) {
+ copybuffer = winNewLine(copybuffer);
+
+ EmptyClipboard();
+ clipbuffer = LocalAlloc(LMEM_FIXED,((bufferlength+1)));
+ buffer = (char *) LocalLock(clipbuffer);
+
+ strncpy(buffer, copybuffer, bufferlength);
+ buffer[bufferlength] = '\0';
+ LocalUnlock(clipbuffer);
+ SetClipboardData(CF_TEXT,clipbuffer);
+ }
+ CloseClipboard();
+ }
+
+ if (copybuffer) {
+ MEM_freeN(copybuffer);
+ copybuffer= NULL;
+ }
+#endif
+}
+
+/*
+ * again==0 show find panel or find
+ * again==1 find text again */
+void txt_find_panel(SpaceText *st, int again)
+{
+ Text *text=st->text;
+ char *findstr= last_txt_find_string;
+
+ if (again==0) {
+ findstr= txt_sel_to_buf(text);
+ } else if (again==1) {
+ char buf[256];
+
+ if (findstr && strlen(findstr)<(sizeof(buf)-1))
+ strcpy(buf, findstr);
+ else
+ buf[0]= 0;
+
+ if (sbutton(buf, 0, sizeof(buf)-1, "Find: ") && buf[0])
+ findstr= BLI_strdup(buf);
+ else
+ findstr= NULL;
+ }
+
+ if (findstr!=last_txt_find_string) {
+ if (last_txt_find_string)
+ MEM_freeN(last_txt_find_string);
+ last_txt_find_string= findstr;
+ }
+
+ if (findstr) {
+ if (txt_find_string(text, findstr))
+ pop_space_text(st);
+ else
+ error("Not found: %s", findstr);
+ }
+}
+
+void run_python_script(SpaceText *st)
+{
+ char *py_filename;
+ Text *text=st->text;
+
+ if (!BPY_txt_do_python_Text(text)) {
+ int lineno = BPY_Err_getLinenumber();
+ // jump to error if happened in current text:
+ py_filename = (char*) BPY_Err_getFilename();
+
+ /* st->text can become NULL: user called Blender.Load(blendfile)
+ * before the end of the script. */
+ if (!st->text) return;
+
+ if (!strcmp(py_filename, st->text->id.name+2)) {
+ error("Python script error, check console");
+ if (lineno >= 0) {
+ txt_move_toline(text, lineno-1, 0);
+ txt_sel_line(text);
+ pop_space_text(st);
+ }
+ } else {
+ error("Error in other (possibly external) file, "\
+ "check console");
+ }
+ }
+}
+
+static void set_tabs(Text *text)
+{
+ SpaceText *st = curarea->spacedata.first;
+ st->currtab_set = setcurr_tab(text);
+}
+
+void winqreadtextspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
+{
+ unsigned short event= evt->event;
+ short val= evt->val;
+ char ascii= evt->ascii;
+ SpaceText *st= curarea->spacedata.first;
+ Text *text= st->text;
+ int do_draw=0, p;
+
+ /* smartass code to prevent the CTRL/ALT events below from not working! */
+ if(G.qual & (LR_ALTKEY|LR_CTRLKEY))
+ if(!ispunct(ascii))
+ ascii= 0;
+
+ text= st->text;
+
+ if (!text) {
+ if (event==RIGHTMOUSE) {
+ switch (pupmenu("File %t|New %x0|Open... %x1")) {
+ case 0:
+ st->text= add_empty_text("Text");
+ st->top= 0;
+
+ allqueue(REDRAWTEXT, 0);
+ allqueue(REDRAWHEADERS, 0);
+ break;
+ case 1:
+ activate_fileselect(FILE_SPECIAL, "Open Text File", G.sce, add_text_fs);
+ break;
+ }
+ }
+ if (val && !ELEM(G.qual, 0, LR_SHIFTKEY)) {
+ if (event==FKEY && G.qual == (LR_ALTKEY|LR_SHIFTKEY)) {
+ switch (pupmenu("File %t|New %x0|Open... %x1")) {
+ case 0:
+ st->text= add_empty_text("Text");
+ st->top= 0;
+
+ allqueue(REDRAWTEXT, 0);
+ allqueue(REDRAWHEADERS, 0);
+ break;
+ case 1:
+ activate_fileselect(FILE_SPECIAL, "Open Text File", G.sce, add_text_fs);
+ break;
+ }
+ }
+ else if (event==QKEY) {
+ if (G.qual & LR_CTRLKEY) {
+ if(okee("Quit Blender")) exit_usiblender();
+ }
+ }
+ else if (event==NKEY) {
+ if (G.qual & LR_ALTKEY) {
+ st->text= add_empty_text("Text");
+ st->top= 0;
+
+ allqueue(REDRAWTEXT, 0);
+ allqueue(REDRAWHEADERS, 0);
+ }
+ }
+ else if (event==OKEY) {
+ if (G.qual & LR_ALTKEY) {
+ activate_fileselect(FILE_SPECIAL, "Open Text File", G.sce, add_text_fs);
+ }
+ }
+ }
+ return;
+ }
+
+ if (event==LEFTMOUSE) {
+ if (val) {
+ short mval[2];
+ set_tabs(text);
+ getmouseco_areawin(mval);
+
+ if (mval[0]>2 && mval[0]<20 && mval[1]>2 && mval[1]<curarea->winy-2) {
+ do_textscroll(st, 2);
+ } else {
+ do_selection(st, G.qual&LR_SHIFTKEY);
+ do_draw= 1;
+ }
+ }
+ } else if (event==MIDDLEMOUSE) {
+ if (val) {
+ do_textscroll(st, 1);
+ }
+ } else if (event==RIGHTMOUSE) {
+ if (val) {
+ p= pupmenu("File %t|New %x0|Open... %x1|Save %x2|Save As...%x3|Execute Script%x4");
+
+ switch(p) {
+ case 0:
+ st->text= add_empty_text("Text");
+ st->top= 0;
+
+ allqueue(REDRAWTEXT, 0);
+ allqueue(REDRAWHEADERS, 0);
+ break;
+
+ case 1:
+ activate_fileselect(FILE_SPECIAL, "Open Text File", G.sce, add_text_fs);
+ break;
+
+ case 3:
+ text->flags |= TXT_ISMEM;
+
+ case 2:
+ txt_write_file(text);
+ do_draw= 1;
+ break;
+ case 4:
+ run_python_script(st);
+ do_draw= 1;
+ break;
+ default:
+ break;
+ }
+ }
+ } else if (ascii) {
+ if (txt_add_char(text, ascii)) {
+ if (st->showsyntax) get_format_string();
+ pop_space_text(st);
+ do_draw= 1;
+ }
+ } else if (val) {
+ switch (event) {
+ case AKEY:
+ if (G.qual & LR_ALTKEY) {
+ txt_move_bol(text, G.qual & LR_SHIFTKEY);
+ do_draw= 1;
+ pop_space_text(st);
+ } else if (G.qual & LR_CTRLKEY) {
+ txt_sel_all(text);
+ do_draw= 1;
+ }
+ break; /* BREAK A */
+ case CKEY:
+ if (G.qual & LR_ALTKEY || G.qual & LR_CTRLKEY) {
+ if(G.qual & LR_SHIFTKEY)
+ txt_copy_clipboard(text);
+ else
+ txt_copy_sel(text);
+
+ do_draw= 1;
+ }
+ break; /* BREAK C */
+ case DKEY:
+ if (G.qual == (LR_CTRLKEY|LR_SHIFTKEY)) {
+ //uncommenting
+ txt_order_cursors(text);
+ uncomment(text);
+ do_draw = 1;
+ if (st->showsyntax) get_format_string();
+ break;
+ } else if (G.qual == LR_CTRLKEY) {
+ txt_delete_char(text);
+ if (st->showsyntax) get_format_string();
+ do_draw= 1;
+ pop_space_text(st);
+ }
+ break; /* BREAK D */
+ case EKEY:
+ if (G.qual == (LR_ALTKEY|LR_SHIFTKEY)) {
+ switch(pupmenu("Edit %t|Cut %x0|Copy %x1|Paste %x2|Print Cut Buffer %x3")) {
+ case 0:
+ txt_cut_sel(text);
+ do_draw= 1;
+ break;
+ case 1:
+ txt_copy_sel(text);
+ do_draw= 1;
+ break;
+ case 2:
+ txt_paste(text);
+ if (st->showsyntax) get_format_string();
+ do_draw= 1;
+ break;
+ case 3:
+ txt_print_cutbuffer();
+ break;
+ }
+ }
+ else if (G.qual == LR_CTRLKEY || G.qual == (LR_CTRLKEY|LR_SHIFTKEY)) {
+ txt_move_eol(text, G.qual & LR_SHIFTKEY);
+ do_draw= 1;
+ pop_space_text(st);
+ }
+ break; /* BREAK E */
+ case FKEY:
+ if (G.qual == (LR_ALTKEY|LR_SHIFTKEY)) {
+ switch(pupmenu("File %t|New %x0|Open... %x1|Save %x2|Save As...%x3")) {
+ case 0:
+ st->text= add_empty_text("Text");
+ st->top= 0;
+
+ allqueue(REDRAWTEXT, 0);
+ allqueue(REDRAWHEADERS, 0);
+ break;
+ case 1:
+ activate_fileselect(FILE_SPECIAL, "Open Text File", G.sce, add_text_fs);
+ break;
+ case 3:
+ text->flags |= TXT_ISMEM;
+ case 2:
+ txt_write_file(text);
+ do_draw= 1;
+ break;
+ }
+ }
+ else if (G.qual == LR_ALTKEY) {
+ if (txt_has_sel(text)) {
+ txt_find_panel(st,0);
+ do_draw= 1;
+ }
+ }
+ else if (G.qual == (LR_ALTKEY|LR_CTRLKEY)) { /* always search button */
+ txt_find_panel(st,1);
+ do_draw= 1;
+ }
+ break; /* BREAK F */
+ case JKEY:
+ if (G.qual == LR_ALTKEY) {
+ do_draw= jumptoline_interactive(st);
+ }
+ break; /* BREAK J */
+ case MKEY:
+ if (G.qual == LR_ALTKEY) {
+ txt_export_to_object(text);
+ do_draw= 1;
+ }
+ break; /* BREAK M */
+ case NKEY:
+ if (G.qual == LR_ALTKEY) {
+ st->text= add_empty_text("Text");
+ st->top= 0;
+
+ allqueue(REDRAWTEXT, 0);
+ allqueue(REDRAWHEADERS, 0);
+
+ }
+ break; /* BREAK N */
+ case OKEY:
+ if (G.qual == LR_ALTKEY) {
+ activate_fileselect(FILE_SPECIAL, "Open Text File", G.sce, add_text_fs);
+ }
+ break; /* BREAK O */
+ case PKEY:
+ if (G.qual == LR_ALTKEY) {
+ run_python_script(st);
+ do_draw= 1;
+ }
+ break; /* BREAK P */
+ case QKEY:
+ if(okee("Quit Blender")) exit_usiblender();
+ break; /* BREAK Q */
+ case RKEY:
+ if (G.qual == LR_ALTKEY) {
+ if (text->compiled) BPY_free_compiled_text(text);
+ text->compiled = NULL;
+ if (okee("Reopen text")) {
+ if (!reopen_text(text))
+ error("Could not reopen file");
+ if (st->showsyntax) get_format_string();
+ }
+ do_draw= 1;
+ }
+ break; /* BREAK R */
+ case SKEY:
+ if (G.qual == (LR_ALTKEY|LR_SHIFTKEY)) {
+ p= pupmenu("Select %t|"
+ "Select All %x0|"
+ "Select Line %x1|"
+ "Jump to Line %x3");
+ switch(p) {
+ case 0:
+ txt_sel_all(text);
+ do_draw= 1;
+ break;
+
+ case 1:
+ txt_sel_line(text);
+ do_draw= 1;
+ break;
+
+ case 3:
+ do_draw= jumptoline_interactive(st);
+ break;
+ }
+ }
+ else if (G.qual & LR_ALTKEY) {
+ /* Event treatment CANNOT enter this if
+ if (G.qual & LR_SHIFTKEY)
+ if (text) text->flags |= TXT_ISMEM;
+ */
+ txt_write_file(text);
+ do_draw= 1;
+ }
+ break; /* BREAK S */
+ case UKEY:
+ //txt_print_undo(text); //debug buffer in console
+ if (G.qual == (LR_ALTKEY|LR_SHIFTKEY)) {
+ txt_do_redo(text);
+ do_draw= 1;
+ }
+ if (G.qual == LR_ALTKEY) {
+ txt_do_undo(text);
+ if (st->showsyntax) get_format_string();
+ do_draw= 1;
+ }
+ break; /* BREAK U */
+ case VKEY:
+ if (G.qual == (LR_ALTKEY| LR_SHIFTKEY)) {
+ switch(pupmenu("View %t|Top of File %x0|Bottom of File %x1|Page Up %x2|Page Down %x3")) {
+ case 0:
+ txt_move_bof(text, 0);
+ do_draw= 1;
+ pop_space_text(st);
+ break;
+ case 1:
+ txt_move_eof(text, 0);
+ do_draw= 1;
+ pop_space_text(st);
+ break;
+ case 2:
+ screen_skip(st, -st->viewlines);
+ do_draw= 1;
+ break;
+ case 3:
+ screen_skip(st, st->viewlines);
+ do_draw= 1;
+ break;
+ }
+ }
+ /* Support for both Alt-V and Ctrl-V for Paste, for backward compatibility reasons */
+ else if (G.qual & LR_ALTKEY || G.qual & LR_CTRLKEY) {
+ /* Throwing in the Shift modifier Paste from the OS clipboard */
+ if (G.qual & LR_SHIFTKEY)
+ txt_paste_clipboard(text);
+ else
+ txt_paste(text);
+ if (st->showsyntax) get_format_string();
+ do_draw= 1;
+ pop_space_text(st);
+ }
+ break; /* BREAK V */
+ case XKEY:
+ if (G.qual == LR_ALTKEY || G.qual == LR_CTRLKEY) {
+ txt_cut_sel(text);
+ if (st->showsyntax) get_format_string();
+ do_draw= 1;
+ pop_space_text(st);
+ }
+ break;
+ case ZKEY:
+ if (G.qual & (LR_ALTKEY|LR_CTRLKEY|LR_COMMANDKEY)) {
+ if (G.qual & LR_SHIFTKEY) {
+ txt_do_redo(text);
+ } else {
+ txt_do_undo(text);
+ }
+ if (st->showsyntax) get_format_string();
+ do_draw= 1;
+ }
+ break;
+ case TABKEY:
+ if (G.qual & LR_SHIFTKEY) {
+ if (txt_has_sel(text)) {
+ txt_order_cursors(text);
+ unindent(text);
+
+ }
+ } else {
+ if ( txt_has_sel(text)) {
+ txt_order_cursors(text);
+ indent(text);
+ } else {
+ txt_add_char(text, '\t');
+ }
+ }
+ if (st->showsyntax) get_format_string();
+ pop_space_text(st);
+ do_draw= 1;
+ st->currtab_set = setcurr_tab(text);
+ break;
+ case RETKEY:
+ //double check tabs before splitting the line
+ st->currtab_set = setcurr_tab(text);
+ txt_split_curline(text);
+ {
+ int a = 0;
+ if (a < st->currtab_set)
+ {
+ while ( a < st->currtab_set) {
+ txt_add_char(text, '\t');
+ a++;
+ }
+ }
+ }
+ if (st->showsyntax) get_format_string();
+ do_draw= 1;
+ pop_space_text(st);
+ break;
+ case BACKSPACEKEY:
+ txt_backspace_char(text);
+ set_tabs(text);
+ if (st->showsyntax) get_format_string();
+ do_draw= 1;
+ pop_space_text(st);
+ break;
+ case DELKEY:
+ txt_delete_char(text);
+ if (st->showsyntax) get_format_string();
+ do_draw= 1;
+ pop_space_text(st);
+ st->currtab_set = setcurr_tab(text);
+ break;
+ case DOWNARROWKEY:
+ txt_move_down(text, G.qual & LR_SHIFTKEY);
+ set_tabs(text);
+ do_draw= 1;
+ pop_space_text(st);
+ break;
+ case LEFTARROWKEY:
+ if (G.qual & LR_COMMANDKEY)
+ txt_move_bol(text, G.qual & LR_SHIFTKEY);
+ else
+ txt_move_left(text, G.qual & LR_SHIFTKEY);
+ set_tabs(text);
+ do_draw= 1;
+ pop_space_text(st);
+ break;
+ case RIGHTARROWKEY:
+ if (G.qual & LR_COMMANDKEY)
+ txt_move_eol(text, G.qual & LR_SHIFTKEY);
+ else
+ txt_move_right(text, G.qual & LR_SHIFTKEY);
+ set_tabs(text);
+ do_draw= 1;
+ pop_space_text(st);
+ break;
+ case UPARROWKEY:
+ txt_move_up(text, G.qual & LR_SHIFTKEY);
+ set_tabs(text);
+ do_draw= 1;
+ pop_space_text(st);
+ break;
+ case PAGEDOWNKEY:
+ screen_skip(st, st->viewlines);
+ do_draw= 1;
+ break;
+ case PAGEUPKEY:
+ screen_skip(st, -st->viewlines);
+ do_draw= 1;
+ break;
+ case HOMEKEY:
+ txt_move_bol(text, G.qual & LR_SHIFTKEY);
+ do_draw= 1;
+ pop_space_text(st);
+ break;
+ case ENDKEY:
+ txt_move_eol(text, G.qual & LR_SHIFTKEY);
+ do_draw= 1;
+ pop_space_text(st);
+ break;
+ case WHEELUPMOUSE:
+ screen_skip(st, -U.wheellinescroll);
+ do_draw= 1;
+ break;
+ case WHEELDOWNMOUSE:
+ screen_skip(st, U.wheellinescroll);
+ do_draw= 1;
+ break;
+ }
+ }
+
+ if (do_draw) {
+ ScrArea *sa;
+
+ for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
+ SpaceText *st= sa->spacedata.first;
+
+ if (st && st->spacetype==SPACE_TEXT) {
+ scrarea_queue_redraw(sa);
+ }
+ }
+ }
+}
+
+void do_brackets(void)
+{
+ SpaceText *st = curarea->spacedata.first;
+ Text *text = st->text;
+ TextLine *tmp, *start;
+ char test[2];
+ int d, pos, open, x, y, x2, y2, h=0;
+
+ if(!text) return;
+
+ tmp = text->curl;
+ start = text->curl;
+
+ test[0] = (unsigned char) tmp->line[text->curc];
+ test[1] = '\0';
+
+ d = check_bracket(test);
+ if (!d) /* If not pri char */
+ {
+ test[0] = (unsigned char) tmp->line[text->curc-1];
+ test[1] = '\0';
+ d = check_bracket(test);
+ if(!d) {
+ return; /*If the current char or prev is not a bracket then return*/
+ } else { /* current char */
+ h= txt_get_span(text->lines.first, start) - st->top;
+ x = text_draw(st, start->line, st->left, text->curc-1, 0, 0, 0, NULL);
+ y = text_draw(st, start->line, st->left, text->curc, 0, 0, 0, NULL);
+ if (d < 4) {
+ pos = text->curc;
+ } else {
+ pos = text->curc-2;
+ }
+ }
+ } else { /* is pri char */
+ h= txt_get_span(text->lines.first, start) - st->top;
+ x = text_draw(st, start->line, st->left, text->curc, 0, 0, 0, NULL);
+ y = text_draw(st, start->line, st->left, text->curc+1, 0, 0, 0, NULL);
+ if (d < 4) {
+ pos = text->curc+1;
+ } else {
+ pos = text->curc-1;
+ }
+ }
+
+ if (d < 4) /*reading forward*/
+ {
+ open = 1;
+ while ( tmp ) {
+ while (pos <= tmp->len) {
+ test[0] = (unsigned char) tmp->line[pos];
+ test[1] = '\0';
+ if(check_bracket(test) == d) {
+ open++;
+ } else if (check_bracket(test) == d+3) {
+ open--;
+ if (open == 0) {
+ BIF_ThemeColorBlend(TH_BACK, TH_SHADE2, 0.5);
+ glRecti(x, curarea->winy-st->lheight*(h)-2, y, curarea->winy-st->lheight*(h+1)-2);
+
+ h= txt_get_span(text->lines.first, tmp) - st->top;
+ x2= text_draw(st, tmp->line, st->left, pos, 0, 0, 0, NULL);
+ y2= text_draw(st, tmp->line, st->left, pos+1, 0, 0, 0, NULL);
+ glRecti(x2, curarea->winy-st->lheight*(h)-2, y2, curarea->winy-st->lheight*(h+1)-2);
+ BIF_ThemeColor(TH_TEXT);
+ return;
+ }
+ }
+ pos++;
+ }
+ tmp = tmp->next;
+ pos = 0;
+ }
+ } else { /* reading back */
+ open = 1;
+ while ( tmp ) {
+ while (pos >= 0) {
+ test[0] = (unsigned char) tmp->line[pos];
+ test[1] = '\0';
+ if(check_bracket(test) == d) {
+ open++;
+ } else if (check_bracket(test) == d-3) {
+ open--;
+ if (open == 0) {
+ BIF_ThemeColorBlend(TH_BACK, TH_SHADE2, 0.5);
+ glRecti(x, curarea->winy-st->lheight*(h)-2, y, curarea->winy-st->lheight*(h+1)-2);
+
+ h= txt_get_span(text->lines.first, tmp) - st->top;
+ x2= text_draw(st, tmp->line, st->left, pos, 0, 0, 0, NULL);
+ y2= text_draw(st, tmp->line, st->left, pos+1, 0, 0, 0, NULL);
+ glRecti(x2, curarea->winy-st->lheight*(h)-2, y2, curarea->winy-st->lheight*(h+1)-2);
+ BIF_ThemeColor(TH_TEXT);
+ return;
+ }
+ }
+ pos--;
+ }
+ tmp = tmp->prev;
+ if (tmp) {
+ pos = tmp->len;
+ }
+ }
+ }
+
+}
+
+int check_bracket(char *string)
+{
+ int number, a = 0;
+ char other[][3] = {"(", "[", "{", ")", "]", "}"};
+
+ number = 6;
+
+ while(a < number) {
+ if(strcmp(other[a], string) == 0)
+ {
+ return a+1;
+ }
+ a++;
+ }
+ return 0;
+}
+
+static int check_builtinfuncs(char *string)
+{
+ int number = 30, a = 0;
+
+ char builtinfuncs[][11] = {"and", "as", "assert", "break", "class", "continue", "def",
+ "del", "elif", "else", "except", "exec", "finally",
+ "for", "from", "global", "if", "import", "in",
+ "is", "lambda", "not", "or", "pass", "print",
+ "raise", "return", "try", "while", "yield"};
+
+ for( a = 0; a < number; a++) {
+ if(!strcmp(builtinfuncs[a], string))
+ return 1;
+ }
+ return 0;
+}
+
+static int check_specialvars(char *string)
+{
+ int number = 2, a = 0;
+ char specialvars[][7] = {"def", "class"};
+
+ for( a = 0; a < number; a++) {
+ if(!strcmp(specialvars[a], string))
+ return a+1;
+ }
+ return 0;
+}
+
+static int check_delim(char *string)
+{
+ int number = 28, a = 0;
+ char other[][3] = {"(", ")", ":", "\"", "\'", " ", "~", "!", "%", "^", "&", "*", "-", "+", "=", "[", "]", "{", "}", ";", "/", "<", ">", "|", ".", "#", "\t", ","};
+
+ for( a = 0; a < number; a++) {
+ if(!strcmp(other[a], string))
+ return 1;
+ }
+ return 0;
+}
+
+static int check_numbers(char *string)
+{
+ int number = 10, a = 0;
+ char other[][2] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"};
+
+ for( a = 0; a < number; a++) {
+ if(!strcmp(other[a], string))
+ return 1;
+ }
+ return 0;
+}
+
+void convert_tabs (struct SpaceText *st, int tab)
+{
+ Text *text = st->text;
+ TextLine *tmp;
+ char *check_line, *new_line, *format;
+ int a, j, extra, number; //unknown for now
+
+ if (!text) return;
+
+ tmp = text->lines.first;
+
+ //first convert to all space, this make it alot easier to convert to tabs because there is no mixtures of ' ' && '\t'
+ while(tmp) {
+ check_line = tmp->line;
+ new_line = MEM_mallocN(render_string(check_line)+1, "Converted_Line");
+ format = MEM_mallocN(render_string(check_line)+1, "Converted_Syntax_format");
+ j = 0;
+ for (a=0; a < strlen(check_line); a++) { //foreach char in line
+ if(check_line[a] == '\t') { //checking for tabs
+ //get the number of spaces this tabs is showing
+ //i dont like doing it this way but will look into it later
+ new_line[j] = '\0';
+ number = render_string(new_line);
+ new_line[j] = '\t';
+ new_line[j+1] = '\0';
+ number = render_string(new_line)-number;
+ for(extra = 0; extra < number; extra++) {
+ new_line[j] = ' ';
+ j++;
+ }
+ } else {
+ new_line[j] = check_line[a];
+ ++j;
+ }
+ }
+ new_line[j] = '\0';
+ // put new_line in the tmp->line spot still need to try and set the curc correctly
+ if (tmp->line) MEM_freeN(tmp->line);
+ if(tmp->format) MEM_freeN(tmp->format);
+
+ tmp->line = new_line;
+ tmp->len = strlen(new_line);
+ tmp->format = format;
+ tmp = tmp->next;
+ }
+
+ if (tab) // Converting to tabs
+ { //start over from the begining
+ tmp = text->lines.first;
+
+ while(tmp) {
+ check_line = tmp->line;
+ extra = 0;
+ for (a = 0; a < strlen(check_line); a++) {
+ number = 0;
+ for (j = 0; j < st->tabnumber; j++) {
+ if ((a+j) <= strlen(check_line)) { //check to make sure we are not pass the end of the line
+ if(check_line[a+j] != ' ') {
+ number = 1;
+ }
+ }
+ }
+ if (!number) { //found all number of space to equal a tab
+ a = a+(st->tabnumber-1);
+ extra = extra+1;
+ }
+ }
+
+ if ( extra > 0 ) { //got tabs make malloc and do what you have to do
+ new_line = MEM_mallocN(strlen(check_line)-(((st->tabnumber*extra)-extra)-1), "Converted_Line");
+ format = MEM_mallocN(strlen(check_line)-(((st->tabnumber*extra)-extra)-1), "Converted_Syntax_format");
+ extra = 0; //reuse vars
+ for (a = 0; a < strlen(check_line); a++) {
+ number = 0;
+ for (j = 0; j < st->tabnumber; j++) {
+ if ((a+j) <= strlen(check_line)) { //check to make sure we are not pass the end of the line
+ if(check_line[a+j] != ' ') {
+ number = 1;
+ }
+ }
+ }
+ if (!number) { //found all number of space to equal a tab
+ new_line[extra] = '\t';
+ a = a+(st->tabnumber-1);
+ ++extra;
+
+ } else { //not adding a tab
+ new_line[extra] = check_line[a];
+ ++extra;
+ }
+ }
+ new_line[extra] = '\0';
+ // put new_line in the tmp->line spot still need to try and set the curc correctly
+ if (tmp->line) MEM_freeN(tmp->line);
+ if(tmp->format) MEM_freeN(tmp->format);
+
+ tmp->line = new_line;
+ tmp->len = strlen(new_line);
+ tmp->format = format;
+ }
+ tmp = tmp->next;
+ }
+ }
+}
diff --git a/source/blender/src/drawtime.c b/source/blender/src/drawtime.c
new file mode 100644
index 00000000000..29538d35d78
--- /dev/null
+++ b/source/blender/src/drawtime.c
@@ -0,0 +1,421 @@
+/**
+ * $Id:
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "DNA_action_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_object_types.h"
+#include "DNA_material_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_sound_types.h"
+#include "DNA_view2d_types.h"
+
+#include "BKE_ipo.h"
+#include "BKE_object.h"
+#include "BKE_material.h"
+#include "BKE_utildefines.h"
+#include "BKE_global.h"
+
+#include "BIF_editaction.h"
+#include "BIF_gl.h"
+#include "BIF_interface.h"
+#include "BIF_interface_icons.h"
+#include "BIF_mywindow.h"
+#include "BIF_screen.h"
+#include "BIF_resources.h"
+#include "BIF_language.h"
+
+#include "BSE_drawipo.h"
+#include "BSE_view.h"
+
+#include "blendef.h"
+#include "interface.h" /* for ui_rasterpos_safe */
+
+/* ---- prototypes ------ */
+void drawtimespace(ScrArea *, void *);
+
+
+static void draw_cfra_time(SpaceTime *stime)
+{
+ float vec[2];
+
+ vec[0]= (G.scene->r.cfra);
+ vec[0]*= G.scene->r.framelen;
+
+ vec[1]= G.v2d->cur.ymin;
+ glColor3ub(0x60, 0xc0, 0x40); // no theme, should be global color once...
+ glLineWidth(3.0);
+
+ glBegin(GL_LINES);
+ glVertex2fv(vec);
+ vec[1]= G.v2d->cur.ymax;
+ glVertex2fv(vec);
+ glEnd();
+
+ glLineWidth(1.0);
+
+ if(stime->flag & TIME_CFRA_NUM) {
+ short mval[2];
+ float x, y;
+ float xscale, yscale;
+ char str[32];
+
+ /* little box with frame drawn beside */
+
+ glFlush(); // huhh... without this glColor won't work for the text...
+ getmouseco_areawin(mval);
+
+ if(mval[1]>curarea->winy-10) mval[1]= curarea->winy - 13;
+
+ if (curarea->winy < 25) {
+ if (mval[1]<17) mval[1]= 17;
+ } else if (mval[1]<22) mval[1]= 22;
+
+ areamouseco_to_ipoco(G.v2d, mval, &x, &y);
+
+ if(stime->flag & TIME_DRAWFRAMES)
+ sprintf(str, " %d", CFRA);
+ else sprintf(str, " %.2f", FRA2TIME(CFRA));
+
+ /* HACK! somehow the green color won't go away... */
+ glColor4ub(0, 0, 0, 0);
+ BIF_ThemeColor(TH_TEXT);
+
+ xscale = (G.v2d->mask.xmax-G.v2d->mask.xmin)/(G.v2d->cur.xmax-G.v2d->cur.xmin);
+ yscale = (G.v2d->mask.ymax-G.v2d->mask.ymin)/(G.v2d->cur.ymax-G.v2d->cur.ymin);
+
+ /* because the frame number text is subject to the same scaling as the contents of the view */
+ glScalef( 1.0/xscale, 1.0/yscale, 1.0);
+
+ ui_rasterpos_safe(x * xscale, y * yscale, 1.0);
+ BIF_DrawString(G.fonts, str, 0);
+ printf("%f -- %f\n", xscale, yscale);
+ glScalef(xscale, yscale, 1.0);
+ }
+
+}
+
+static void draw_marker(TimeMarker *marker, int lines)
+{
+ float xpos, ypixels, xscale, yscale;
+
+ xpos = marker->frame;
+ /* no time correction for framelen! space is drawn with old values */
+
+ ypixels= G.v2d->mask.ymax-G.v2d->mask.ymin;
+ xscale = (G.v2d->mask.xmax-G.v2d->mask.xmin)/(G.v2d->cur.xmax-G.v2d->cur.xmin);
+ yscale = (G.v2d->mask.ymax-G.v2d->mask.ymin)/(G.v2d->cur.ymax-G.v2d->cur.ymin);
+
+ glScalef( 1.0/xscale, 1.0/yscale, 1.0);
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ /* verticle line */
+ if (lines) {
+ setlinestyle(3);
+ if(marker->flag & SELECT)
+ glColor4ub(255,255,255, 96);
+ else
+ glColor4ub(0,0,0, 96);
+
+ glBegin(GL_LINES);
+ glVertex2f((xpos*xscale)+0.5, 12);
+ glVertex2f((xpos*xscale)+0.5, 34*yscale); /* a bit lazy but we know it cant be greater then 34 strips high*/
+ glEnd();
+ setlinestyle(0);
+ }
+
+ /* 5 px to offset icon to align properly, space / pixels corrects for zoom */
+ if(marker->flag & SELECT)
+ BIF_icon_draw(xpos*xscale-5.0, 12.0, ICON_MARKER_HLT);
+ else
+ BIF_icon_draw(xpos*xscale-5.0, 12.0, ICON_MARKER);
+
+ glBlendFunc(GL_ONE, GL_ZERO);
+ glDisable(GL_BLEND);
+
+ /* and the marker name too, shifted slightly to the top-right */
+ if(marker->name && marker->name[0]) {
+ if(marker->flag & SELECT) {
+ BIF_ThemeColor(TH_TEXT_HI);
+ ui_rasterpos_safe(xpos*xscale+4.0, (ypixels<=39.0)?(ypixels-10.0):29.0, 1.0);
+ }
+ else {
+ BIF_ThemeColor(TH_TEXT);
+ if((marker->frame <= G.scene->r.cfra) && (marker->frame+5 > G.scene->r.cfra))
+ ui_rasterpos_safe(xpos*xscale+4.0, (ypixels<=39.0)?(ypixels-10.0):29.0, 1.0);
+ else
+ ui_rasterpos_safe(xpos*xscale+4.0, 17.0, 1.0);
+ }
+ BIF_DrawString(G.font, marker->name, 0);
+ }
+ glScalef(xscale, yscale, 1.0);
+}
+
+static void draw_markers_time(int lines)
+{
+ TimeMarker *marker;
+
+ /* unselected markers are drawn at the first time */
+ for(marker= G.scene->markers.first; marker; marker= marker->next) {
+ if(!(marker->flag & SELECT)) draw_marker(marker, lines);
+ }
+
+ /* selected markers are drawn later ... selected markers have to cover unselected
+ * markers laying at the same position as selected markers
+ * (jiri: it is hack, it could be solved better) */
+ for(marker= G.scene->markers.first; marker; marker= marker->next) {
+ if(marker->flag & SELECT) draw_marker(marker, lines);
+ }
+}
+
+void draw_markers_timespace(int lines)
+{
+ TimeMarker *marker;
+ float yspace, ypixels;
+
+ /* move ortho view to align with slider in bottom */
+ glTranslatef(0.0f, G.v2d->cur.ymin, 0.0f);
+
+ /* bad hacks in drawing markers... inverse correct that as well */
+ yspace= G.v2d->cur.ymax - G.v2d->cur.ymin;
+ ypixels= G.v2d->mask.ymax - G.v2d->mask.ymin;
+ glTranslatef(0.0f, -11.0*yspace/ypixels, 0.0f);
+
+ /* unselected markers are drawn at the first time */
+ for(marker= G.scene->markers.first; marker; marker= marker->next) {
+ if(!(marker->flag & SELECT)) draw_marker(marker, lines);
+ }
+
+ /* selected markers are drawn later ... selected markers have to cover unselected
+ * markers laying at the same position as selected markers */
+ for(marker= G.scene->markers.first; marker; marker= marker->next) {
+ if(marker->flag & SELECT) draw_marker(marker, lines);
+ }
+
+ glTranslatef(0.0f, -G.v2d->cur.ymin, 0.0f);
+ glTranslatef(0.0f, 11.0*yspace/ypixels, 0.0f);
+
+}
+
+void draw_anim_preview_timespace()
+{
+ /* only draw this if preview range is set */
+ if (G.scene->r.psfra) {
+ glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
+ glEnable(GL_BLEND);
+ glColor4f(0, 0, 0, 0.4);
+
+ if (PSFRA < PEFRA) {
+ glRectf(G.v2d->cur.xmin, G.v2d->cur.ymin, PSFRA, G.v2d->cur.ymax);
+ glRectf(PEFRA, G.v2d->cur.ymin, G.v2d->cur.xmax, G.v2d->cur.ymax);
+ }
+ else {
+ glRectf(G.v2d->cur.xmin, G.v2d->cur.ymin, G.v2d->cur.xmax, G.v2d->cur.ymax);
+ }
+
+ glDisable(GL_BLEND);
+ }
+}
+
+static void draw_sfra_efra()
+{
+ BIF_ThemeColorShade(TH_BACK, -25);
+
+ if (PSFRA < PEFRA) {
+ glRectf(G.v2d->cur.xmin, G.v2d->cur.ymin, PSFRA, G.v2d->cur.ymax);
+ glRectf(PEFRA, G.v2d->cur.ymin, G.v2d->cur.xmax, G.v2d->cur.ymax);
+ }
+ else {
+ glRectf(G.v2d->cur.xmin, G.v2d->cur.ymin, G.v2d->cur.xmax, G.v2d->cur.ymax);
+ }
+
+ BIF_ThemeColorShade(TH_BACK, -60);
+ /* thin lines where the actual frames are */
+ fdrawline(PSFRA, G.v2d->cur.ymin, PSFRA, G.v2d->cur.ymax);
+ fdrawline(PEFRA, G.v2d->cur.ymin, PEFRA, G.v2d->cur.ymax);
+
+ glDisable(GL_BLEND);
+}
+
+/*draw all the keys in a list (elems) as lines */
+static void draw_key_list(ListBase elems, char col[3])
+{
+ CfraElem *ce;
+ float drawframe;
+
+ ce= elems.first;
+ while(ce) {
+ drawframe = ce->cfra; //not correct for G.scene->r.framelen;
+ glColor3ub(col[0], col[1], col[2]);
+
+ fdrawline(drawframe, G.v2d->cur.ymin, drawframe, G.v2d->cur.ymax);
+
+ ce= ce->next;
+ }
+}
+
+/* This function draws keyframes that the active object has (as long as
+ * it is not in EditMode). Some filters are available to optimise the
+ * drawing efficiency.
+ */
+static void draw_ob_keys()
+{
+ /* mostly copied from drawobject.c, draw_object() */
+ SpaceTime *stime= curarea->spacedata.first;
+ ListBase elems= {0, 0};
+
+ Object *ob= OBACT;
+ short filter, ok;
+ char col[3];
+ int a;
+
+ if (ob && ob!=G.obedit) {
+ /* Object's IPO block - show all keys */
+ if (ob->ipo) {
+ /* convert the ipo to a list of 'current frame elements' */
+ elems.first= elems.last= NULL;
+ make_cfra_list(ob->ipo, &elems);
+
+ /* draw the list of current frame elements */
+ col[0] = 0xDD; col[1] = 0xD7; col[2] = 0x00;
+ draw_key_list(elems, col);
+
+ BLI_freelistN(&elems);
+ }
+
+ /* Object's Action block - may be filtered in some cases */
+ if (ob->action) {
+ bAction *act = ob->action;
+ bActionChannel *achan;
+
+ /* only apply filter if action is likely to be for pose channels + filter is on */
+ filter= ((stime->flag & TIME_ONLYACTSEL) &&
+ (ob->pose) && (ob->flag & OB_POSEMODE));
+
+ /* go through each channel in the action */
+ for (achan=act->chanbase.first; achan; achan=achan->next) {
+ /* if filtering, check if this channel passes */
+ if (filter) {
+ ok= (SEL_ACHAN(achan))? 1 : 0;
+ }
+ else ok= 1;
+
+ /* convert the ipo to a list of 'current frame elements' */
+ if (achan->ipo && ok) {
+ elems.first= elems.last= NULL;
+ make_cfra_list(achan->ipo, &elems);
+
+ col[0] = 0x00; col[1] = 0x82; col[2] = 0x8B;
+ draw_key_list(elems, col);
+
+ BLI_freelistN(&elems);
+ }
+ }
+ }
+
+ /* Materials (only relevant for geometry objects) - some filtering might occur */
+ filter= (stime->flag & TIME_ONLYACTSEL);
+ for (a=0; a<ob->totcol; a++) {
+ Material *ma= give_current_material(ob, a+1);
+
+ /* the only filter we apply right now is only showing the active material */
+ if (filter) {
+ ok= (ob->actcol==a)? 1 : 0;
+ }
+ else ok= 1;
+
+ if (ma && ma->ipo && ok) {
+ elems.first= elems.last= NULL;
+ make_cfra_list(ma->ipo, &elems);
+
+ col[0] = 0xDD; col[1] = 0xA7; col[2] = 0x00;
+ draw_key_list(elems, col);
+
+ BLI_freelistN(&elems);
+ }
+ }
+ }
+}
+
+void drawtimespace(ScrArea *sa, void *spacedata)
+{
+ SpaceTime *stime= sa->spacedata.first;
+ float col[3];
+
+ BIF_GetThemeColor3fv(TH_BACK, col);
+ glClearColor(col[0], col[1], col[2], 0.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ calc_scrollrcts(sa, &(stime->v2d), curarea->winx, curarea->winy);
+
+ myortho2(stime->v2d.cur.xmin, stime->v2d.cur.xmax, stime->v2d.cur.ymin, stime->v2d.cur.ymax);
+
+ /* draw darkened area outside of active timeline
+ * frame range used is preview range or scene range
+ */
+ draw_sfra_efra();
+
+ /* boundbox_seq(); */
+ calc_ipogrid();
+ draw_ipogrid();
+
+ draw_cfra_time(spacedata);
+ draw_ob_keys();
+ draw_markers_time(0);
+
+ /* restore viewport */
+ mywinset(curarea->win);
+
+ /* ortho at pixel level curarea */
+ myortho2(-0.375, curarea->winx-0.375, -0.375, curarea->winy-0.375);
+
+ /* the bottom with time values */
+ BIF_ThemeColor(TH_HEADER);
+ glRectf(0.0f, 0.0f, (float)curarea->winx, 12.0f);
+ BIF_ThemeColorShade(TH_HEADER, 50);
+ fdrawline(0.0f, 12.0f, (float)curarea->winx, 12.0f);
+ draw_view2d_numbers_horiz(stime->flag & TIME_DRAWFRAMES);
+
+ draw_area_emboss(sa);
+ curarea->win_swap= WIN_BACK_OK;
+}
diff --git a/source/blender/src/drawview.c b/source/blender/src/drawview.c
new file mode 100644
index 00000000000..e437ad86cda
--- /dev/null
+++ b/source/blender/src/drawview.c
@@ -0,0 +1,3465 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+//#define NAN_LINEAR_PHYSICS
+
+#include <math.h>
+#include <string.h>
+
+#ifndef WIN32
+#include <unistd.h>
+#include <sys/times.h>
+#else
+#include <io.h>
+#endif
+
+#ifdef WIN32
+#ifndef snprintf
+#define snprintf _snprintf
+#endif
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "PIL_time.h"
+
+#include "BMF_Api.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "DNA_action_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_brush_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_group_types.h"
+#include "DNA_image_types.h"
+#include "DNA_key_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_world_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_editVert.h"
+
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_anim.h"
+#include "BKE_constraint.h"
+#include "BKE_curve.h"
+#include "BKE_customdata.h"
+#include "BKE_displist.h"
+#include "BKE_depsgraph.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_global.h"
+#include "BKE_lattice.h"
+#include "BKE_library.h"
+#include "BKE_image.h"
+#include "BKE_ipo.h"
+#include "BKE_key.h"
+#include "BKE_main.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_scene.h"
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_butspace.h"
+#include "BIF_drawimage.h"
+#include "BIF_editgroup.h"
+#include "BIF_editarmature.h"
+#include "BIF_editmesh.h"
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+#include "BIF_interface.h"
+#include "BIF_interface_icons.h"
+#include "BIF_mywindow.h"
+#include "BIF_poseobject.h"
+#include "BIF_previewrender.h"
+#include "BIF_resources.h"
+#include "BIF_retopo.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+
+#ifdef WITH_VERSE
+#include "BIF_verse.h"
+#endif
+
+#include "BDR_drawmesh.h"
+#include "BDR_drawobject.h"
+#include "BDR_editobject.h"
+#include "BDR_vpaint.h"
+#include "BDR_sculptmode.h"
+
+#include "BSE_drawview.h"
+#include "BSE_filesel.h"
+#include "BSE_headerbuttons.h"
+#include "BSE_seqaudio.h"
+#include "BSE_sequence.h"
+#include "BSE_trans_types.h"
+#include "BSE_time.h"
+#include "BSE_view.h"
+
+#include "BPY_extern.h"
+
+#include "RE_render_ext.h"
+
+#include "blendef.h"
+#include "mydevice.h"
+#include "butspace.h" // event codes
+
+#include "BIF_transform.h"
+
+#include "RE_pipeline.h" // make_stars
+
+#include "multires.h"
+
+/* For MULTISAMPLE_ARB #define.
+ Note that older systems like irix
+ may not have this, and will need a #ifdef
+ to disable it.*/
+/* #include "GL/glext.h" Disabled for release, to avoid possibly breaking platforms.
+ Instead, the define we need will just be #defined if it's not in the platform opengl.h.
+*/
+
+/* Modules used */
+#include "radio.h"
+
+/* locals */
+void drawname(Object *ob);
+
+static void star_stuff_init_func(void)
+{
+ cpack(-1);
+ glPointSize(1.0);
+ glBegin(GL_POINTS);
+}
+static void star_stuff_vertex_func(float* i)
+{
+ glVertex3fv(i);
+}
+static void star_stuff_term_func(void)
+{
+ glEnd();
+}
+
+void default_gl_light(void)
+{
+ int a;
+
+ /* initialize */
+ if(U.light[0].flag==0 && U.light[1].flag==0 && U.light[2].flag==0) {
+ U.light[0].flag= 1;
+ U.light[0].vec[0]= -0.3; U.light[0].vec[1]= 0.3; U.light[0].vec[2]= 0.9;
+ U.light[0].col[0]= 0.8; U.light[0].col[1]= 0.8; U.light[0].col[2]= 0.8;
+ U.light[0].spec[0]= 0.5; U.light[0].spec[1]= 0.5; U.light[0].spec[2]= 0.5;
+ U.light[0].spec[3]= 1.0;
+
+ U.light[1].flag= 0;
+ U.light[1].vec[0]= 0.5; U.light[1].vec[1]= 0.5; U.light[1].vec[2]= 0.1;
+ U.light[1].col[0]= 0.4; U.light[1].col[1]= 0.4; U.light[1].col[2]= 0.8;
+ U.light[1].spec[0]= 0.3; U.light[1].spec[1]= 0.3; U.light[1].spec[2]= 0.5;
+ U.light[1].spec[3]= 1.0;
+
+ U.light[2].flag= 0;
+ U.light[2].vec[0]= 0.3; U.light[2].vec[1]= -0.3; U.light[2].vec[2]= -0.2;
+ U.light[2].col[0]= 0.8; U.light[2].col[1]= 0.5; U.light[2].col[2]= 0.4;
+ U.light[2].spec[0]= 0.5; U.light[2].spec[1]= 0.4; U.light[2].spec[2]= 0.3;
+ U.light[2].spec[3]= 1.0;
+ }
+
+
+ glLightfv(GL_LIGHT0, GL_POSITION, U.light[0].vec);
+ glLightfv(GL_LIGHT0, GL_DIFFUSE, U.light[0].col);
+ glLightfv(GL_LIGHT0, GL_SPECULAR, U.light[0].spec);
+
+ glLightfv(GL_LIGHT1, GL_POSITION, U.light[1].vec);
+ glLightfv(GL_LIGHT1, GL_DIFFUSE, U.light[1].col);
+ glLightfv(GL_LIGHT1, GL_SPECULAR, U.light[1].spec);
+
+ glLightfv(GL_LIGHT2, GL_POSITION, U.light[2].vec);
+ glLightfv(GL_LIGHT2, GL_DIFFUSE, U.light[2].col);
+ glLightfv(GL_LIGHT2, GL_SPECULAR, U.light[2].spec);
+
+ for(a=0; a<8; a++) {
+ if(a<3) {
+ if(U.light[a].flag) glEnable(GL_LIGHT0+a);
+ else glDisable(GL_LIGHT0+a);
+
+ // clear stuff from other opengl lamp usage
+ glLightf(GL_LIGHT0+a, GL_SPOT_CUTOFF, 180.0);
+ glLightf(GL_LIGHT0+a, GL_CONSTANT_ATTENUATION, 1.0);
+ glLightf(GL_LIGHT0+a, GL_LINEAR_ATTENUATION, 0.0);
+ }
+ else glDisable(GL_LIGHT0+a);
+ }
+
+ glDisable(GL_LIGHTING);
+
+ glDisable(GL_COLOR_MATERIAL);
+}
+
+/* also called when render 'ogl' */
+void init_gl_stuff(void)
+{
+ float mat_ambient[] = { 0.0, 0.0, 0.0, 0.0 };
+ float mat_specular[] = { 0.5, 0.5, 0.5, 1.0 };
+ float mat_shininess[] = { 35.0 };
+ int a, x, y;
+ GLubyte pat[32*32];
+ const GLubyte *patc= pat;
+
+
+ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient);
+ glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_specular);
+ glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
+ glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);
+
+ default_gl_light();
+
+ /* no local viewer, looks ugly in ortho mode */
+ /* glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, &one); */
+
+ glDepthFunc(GL_LEQUAL);
+ /* scaling matrices */
+ glEnable(GL_NORMALIZE);
+
+ glShadeModel(GL_FLAT);
+
+ glDisable(GL_ALPHA_TEST);
+ glDisable(GL_BLEND);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_FOG);
+ glDisable(GL_LIGHTING);
+ glDisable(GL_LOGIC_OP);
+ glDisable(GL_STENCIL_TEST);
+ glDisable(GL_TEXTURE_1D);
+ glDisable(GL_TEXTURE_2D);
+
+ /* default on, disable/enable should be local per function */
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_NORMAL_ARRAY);
+
+ glPixelTransferi(GL_MAP_COLOR, GL_FALSE);
+ glPixelTransferi(GL_RED_SCALE, 1);
+ glPixelTransferi(GL_RED_BIAS, 0);
+ glPixelTransferi(GL_GREEN_SCALE, 1);
+ glPixelTransferi(GL_GREEN_BIAS, 0);
+ glPixelTransferi(GL_BLUE_SCALE, 1);
+ glPixelTransferi(GL_BLUE_BIAS, 0);
+ glPixelTransferi(GL_ALPHA_SCALE, 1);
+ glPixelTransferi(GL_ALPHA_BIAS, 0);
+
+ glPixelTransferi(GL_DEPTH_BIAS, 0);
+ glPixelTransferi(GL_DEPTH_SCALE, 1);
+ glDepthRange(0.0, 1.0);
+
+ a= 0;
+ for(x=0; x<32; x++) {
+ for(y=0; y<4; y++) {
+ if( (x) & 1) pat[a++]= 0x88;
+ else pat[a++]= 0x22;
+ }
+ }
+
+ glPolygonStipple(patc);
+
+
+ init_realtime_GL();
+}
+
+void circf(float x, float y, float rad)
+{
+ GLUquadricObj *qobj = gluNewQuadric();
+
+ gluQuadricDrawStyle(qobj, GLU_FILL);
+
+ glPushMatrix();
+
+ glTranslatef(x, y, 0.);
+
+ gluDisk( qobj, 0.0, rad, 32, 1);
+
+ glPopMatrix();
+
+ gluDeleteQuadric(qobj);
+}
+
+void circ(float x, float y, float rad)
+{
+ GLUquadricObj *qobj = gluNewQuadric();
+
+ gluQuadricDrawStyle(qobj, GLU_SILHOUETTE);
+
+ glPushMatrix();
+
+ glTranslatef(x, y, 0.);
+
+ gluDisk( qobj, 0.0, rad, 32, 1);
+
+ glPopMatrix();
+
+ gluDeleteQuadric(qobj);
+}
+
+/* ********** ********** */
+
+static void draw_bgpic(void)
+{
+ BGpic *bgpic;
+ Image *ima;
+ ImBuf *ibuf= NULL;
+ float vec[4], fac, asp, zoomx, zoomy;
+ float x1, y1, x2, y2, cx, cy;
+
+ bgpic= G.vd->bgpic;
+ if(bgpic==NULL) return;
+
+ ima= bgpic->ima;
+
+ if(ima)
+ ibuf= BKE_image_get_ibuf(ima, &bgpic->iuser);
+ if(ibuf==NULL || (ibuf->rect==NULL && ibuf->rect_float==NULL) )
+ return;
+ if(ibuf->channels!=4)
+ return;
+ if(ibuf->rect==NULL)
+ IMB_rect_from_float(ibuf);
+
+ if(G.vd->persp==2) {
+ rctf vb;
+
+ calc_viewborder(G.vd, &vb);
+
+ x1= vb.xmin;
+ y1= vb.ymin;
+ x2= vb.xmax;
+ y2= vb.ymax;
+ }
+ else {
+ float sco[2];
+
+ /* calc window coord */
+ initgrabz(0.0, 0.0, 0.0);
+ window_to_3d(vec, 1, 0);
+ fac= MAX3( fabs(vec[0]), fabs(vec[1]), fabs(vec[1]) );
+ fac= 1.0/fac;
+
+ asp= ( (float)ibuf->y)/(float)ibuf->x;
+
+ vec[0] = vec[1] = vec[2] = 0.0;
+ view3d_project_float(curarea, vec, sco, G.vd->persmat);
+ cx = sco[0];
+ cy = sco[1];
+
+ x1= cx+ fac*(bgpic->xof-bgpic->size);
+ y1= cy+ asp*fac*(bgpic->yof-bgpic->size);
+ x2= cx+ fac*(bgpic->xof+bgpic->size);
+ y2= cy+ asp*fac*(bgpic->yof+bgpic->size);
+ }
+
+ /* complete clip? */
+
+ if(x2 < 0 ) return;
+ if(y2 < 0 ) return;
+ if(x1 > curarea->winx ) return;
+ if(y1 > curarea->winy ) return;
+
+ zoomx= (x2-x1)/ibuf->x;
+ zoomy= (y2-y1)/ibuf->y;
+
+ /* for some reason; zoomlevels down refuses to use GL_ALPHA_SCALE */
+ if(zoomx < 1.0f || zoomy < 1.0f) {
+ float tzoom= MIN2(zoomx, zoomy);
+ int mip= 0;
+
+ if(ibuf->mipmap[0]==NULL)
+ IMB_makemipmap(ibuf, 0);
+
+ while(tzoom < 1.0f && mip<8 && ibuf->mipmap[mip]) {
+ tzoom*= 2.0f;
+ zoomx*= 2.0f;
+ zoomy*= 2.0f;
+ mip++;
+ }
+ if(mip>0)
+ ibuf= ibuf->mipmap[mip-1];
+ }
+
+ if(G.vd->zbuf) glDisable(GL_DEPTH_TEST);
+
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+
+ glaDefine2DArea(&curarea->winrct);
+
+ glEnable(GL_BLEND);
+
+ glPixelZoom(zoomx, zoomy);
+ glColor4f(1.0, 1.0, 1.0, 1.0-bgpic->blend);
+ glaDrawPixelsTex(x1, y1, ibuf->x, ibuf->y, GL_UNSIGNED_BYTE, ibuf->rect);
+
+ glPixelZoom(1.0, 1.0);
+ glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
+
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+
+ glDisable(GL_BLEND);
+ if(G.vd->zbuf) glEnable(GL_DEPTH_TEST);
+
+ areawinset(curarea->win); // restore viewport / scissor
+}
+
+static void drawgrid_draw(float wx, float wy, float x, float y, float dx)
+{
+ float fx, fy;
+
+ x+= (wx);
+ y+= (wy);
+ fx= x/dx;
+ fx= x-dx*floor(fx);
+
+ while(fx< curarea->winx) {
+ fdrawline(fx, 0.0, fx, (float)curarea->winy);
+ fx+= dx;
+ }
+
+ fy= y/dx;
+ fy= y-dx*floor(fy);
+
+
+ while(fy< curarea->winy) {
+ fdrawline(0.0, fy, (float)curarea->winx, fy);
+ fy+= dx;
+ }
+
+}
+
+// not intern, called in editobject for constraint axis too
+void make_axis_color(char *col, char *col2, char axis)
+{
+ if(axis=='x') {
+ col2[0]= col[0]>219?255:col[0]+36;
+ col2[1]= col[1]<26?0:col[1]-26;
+ col2[2]= col[2]<26?0:col[2]-26;
+ }
+ else if(axis=='y') {
+ col2[0]= col[0]<46?0:col[0]-36;
+ col2[1]= col[1]>189?255:col[1]+66;
+ col2[2]= col[2]<46?0:col[2]-36;
+ }
+ else {
+ col2[0]= col[0]<26?0:col[0]-26;
+ col2[1]= col[1]<26?0:col[1]-26;
+ col2[2]= col[2]>209?255:col[2]+46;
+ }
+
+}
+
+static void drawgrid(void)
+{
+ /* extern short bgpicmode; */
+ float wx, wy, x, y, fw, fx, fy, dx;
+ float vec4[4];
+ char col[3], col2[3];
+ short sublines = G.vd->gridsubdiv;
+
+ vec4[0]=vec4[1]=vec4[2]=0.0;
+ vec4[3]= 1.0;
+ Mat4MulVec4fl(G.vd->persmat, vec4);
+ fx= vec4[0];
+ fy= vec4[1];
+ fw= vec4[3];
+
+ wx= (curarea->winx/2.0); /* because of rounding errors, grid at wrong location */
+ wy= (curarea->winy/2.0);
+
+ x= (wx)*fx/fw;
+ y= (wy)*fy/fw;
+
+ vec4[0]=vec4[1]=G.vd->grid;
+ vec4[2]= 0.0;
+ vec4[3]= 1.0;
+ Mat4MulVec4fl(G.vd->persmat, vec4);
+ fx= vec4[0];
+ fy= vec4[1];
+ fw= vec4[3];
+
+ dx= fabs(x-(wx)*fx/fw);
+ if(dx==0) dx= fabs(y-(wy)*fy/fw);
+
+ glDepthMask(0); // disable write in zbuffer
+
+ /* check zoom out */
+ BIF_ThemeColor(TH_GRID);
+ persp(PERSP_WIN);
+
+ if(dx<6.0) {
+ G.vd->gridview*= sublines;
+ dx*= sublines;
+
+ if(dx<6.0) {
+ G.vd->gridview*= sublines;
+ dx*= sublines;
+
+ if(dx<6.0) {
+ G.vd->gridview*= sublines;
+ dx*=sublines;
+ if(dx<6.0);
+ else {
+ BIF_ThemeColor(TH_GRID);
+ drawgrid_draw(wx, wy, x, y, dx);
+ }
+ }
+ else { // start blending out
+ BIF_ThemeColorBlend(TH_BACK, TH_GRID, dx/60.0);
+ drawgrid_draw(wx, wy, x, y, dx);
+
+ BIF_ThemeColor(TH_GRID);
+ drawgrid_draw(wx, wy, x, y, sublines*dx);
+ }
+ }
+ else { // start blending out (6 < dx < 60)
+ BIF_ThemeColorBlend(TH_BACK, TH_GRID, dx/60.0);
+ drawgrid_draw(wx, wy, x, y, dx);
+
+ BIF_ThemeColor(TH_GRID);
+ drawgrid_draw(wx, wy, x, y, sublines*dx);
+ }
+ }
+ else {
+ if(dx>60.0) { // start blending in
+ G.vd->gridview/= sublines;
+ dx/= sublines;
+ if(dx>60.0) { // start blending in
+ G.vd->gridview/= sublines;
+ dx/= sublines;
+ if(dx>60.0) {
+ BIF_ThemeColor(TH_GRID);
+ drawgrid_draw(wx, wy, x, y, dx);
+ }
+ else {
+ BIF_ThemeColorBlend(TH_BACK, TH_GRID, dx/60.0);
+ drawgrid_draw(wx, wy, x, y, dx);
+ BIF_ThemeColor(TH_GRID);
+ drawgrid_draw(wx, wy, x, y, dx*sublines);
+ }
+ }
+ else {
+ BIF_ThemeColorBlend(TH_BACK, TH_GRID, dx/60.0);
+ drawgrid_draw(wx, wy, x, y, dx);
+ BIF_ThemeColor(TH_GRID);
+ drawgrid_draw(wx, wy, x, y, dx*sublines);
+ }
+ }
+ else {
+ BIF_ThemeColorBlend(TH_BACK, TH_GRID, dx/60.0);
+ drawgrid_draw(wx, wy, x, y, dx);
+ BIF_ThemeColor(TH_GRID);
+ drawgrid_draw(wx, wy, x, y, dx*sublines);
+ }
+ }
+
+ x+= (wx);
+ y+= (wy);
+ BIF_GetThemeColor3ubv(TH_GRID, col);
+
+ setlinestyle(0);
+
+ /* center cross */
+ if(G.vd->view==3) make_axis_color(col, col2, 'y');
+ else make_axis_color(col, col2, 'x');
+ glColor3ubv((GLubyte *)col2);
+
+ fdrawline(0.0, y, (float)curarea->winx, y);
+
+ if(G.vd->view==7) make_axis_color(col, col2, 'y');
+ else make_axis_color(col, col2, 'z');
+ glColor3ubv((GLubyte *)col2);
+
+ fdrawline(x, 0.0, x, (float)curarea->winy);
+
+ glDepthMask(1); // enable write in zbuffer
+ persp(PERSP_VIEW);
+}
+
+
+
+static void drawfloor(void)
+{
+ View3D *vd;
+ float vert[3], grid;
+ int a, gridlines, emphasise;
+ char col[3], col2[3];
+ short draw_line = 0;
+
+ vd= curarea->spacedata.first;
+
+ vert[2]= 0.0;
+
+ if(vd->gridlines<3) return;
+
+ if(G.vd->zbuf && G.obedit) glDepthMask(0); // for zbuffer-select
+
+ gridlines= vd->gridlines/2;
+ grid= gridlines*vd->grid;
+
+ BIF_GetThemeColor3ubv(TH_GRID, col);
+ BIF_GetThemeColor3ubv(TH_BACK, col2);
+
+ /* emphasise division lines lighter instead of darker, if background is darker than grid */
+ if ( ((col[0]+col[1]+col[2])/3+10) > (col2[0]+col2[1]+col2[2])/3 )
+ emphasise = 20;
+ else
+ emphasise = -10;
+
+ /* draw the Y axis and/or grid lines */
+ for(a= -gridlines;a<=gridlines;a++) {
+ if(a==0) {
+ /* check for the 'show Y axis' preference */
+ if (vd->gridflag & V3D_SHOW_Y) {
+ make_axis_color(col, col2, 'y');
+ glColor3ubv((GLubyte *)col2);
+
+ draw_line = 1;
+ } else if (vd->gridflag & V3D_SHOW_FLOOR) {
+ BIF_ThemeColorShade(TH_GRID, emphasise);
+ } else {
+ draw_line = 0;
+ }
+ } else {
+ /* check for the 'show grid floor' preference */
+ if (vd->gridflag & V3D_SHOW_FLOOR) {
+ if( (a % 10)==0) {
+ BIF_ThemeColorShade(TH_GRID, emphasise);
+ }
+ else BIF_ThemeColorShade(TH_GRID, 10);
+
+ draw_line = 1;
+ } else {
+ draw_line = 0;
+ }
+ }
+
+ if (draw_line) {
+ glBegin(GL_LINE_STRIP);
+ vert[0]= a*vd->grid;
+ vert[1]= grid;
+ glVertex3fv(vert);
+ vert[1]= -grid;
+ glVertex3fv(vert);
+ glEnd();
+ }
+ }
+
+ /* draw the X axis and/or grid lines */
+ for(a= -gridlines;a<=gridlines;a++) {
+ if(a==0) {
+ /* check for the 'show X axis' preference */
+ if (vd->gridflag & V3D_SHOW_X) {
+ make_axis_color(col, col2, 'x');
+ glColor3ubv((GLubyte *)col2);
+
+ draw_line = 1;
+ } else if (vd->gridflag & V3D_SHOW_FLOOR) {
+ BIF_ThemeColorShade(TH_GRID, emphasise);
+ } else {
+ draw_line = 0;
+ }
+ } else {
+ /* check for the 'show grid floor' preference */
+ if (vd->gridflag & V3D_SHOW_FLOOR) {
+ if( (a % 10)==0) {
+ BIF_ThemeColorShade(TH_GRID, emphasise);
+ }
+ else BIF_ThemeColorShade(TH_GRID, 10);
+
+ draw_line = 1;
+ } else {
+ draw_line = 0;
+ }
+ }
+
+ if (draw_line) {
+ glBegin(GL_LINE_STRIP);
+ vert[1]= a*vd->grid;
+ vert[0]= grid;
+ glVertex3fv(vert );
+ vert[0]= -grid;
+ glVertex3fv(vert);
+ glEnd();
+ }
+ }
+
+ /* draw the Z axis line */
+ /* check for the 'show Z axis' preference */
+ if (vd->gridflag & V3D_SHOW_Z) {
+ make_axis_color(col, col2, 'z');
+ glColor3ubv((GLubyte *)col2);
+
+ glBegin(GL_LINE_STRIP);
+ vert[0]= 0;
+ vert[1]= 0;
+ vert[2]= grid;
+ glVertex3fv(vert );
+ vert[2]= -grid;
+ glVertex3fv(vert);
+ glEnd();
+ }
+
+ if(G.vd->zbuf && G.obedit) glDepthMask(1);
+
+}
+
+static void drawcursor(View3D *v3d)
+{
+ short mx,my,co[2];
+ int flag;
+
+ /* we dont want the clipping for cursor */
+ flag= v3d->flag;
+ v3d->flag= 0;
+ project_short( give_cursor(), co);
+ v3d->flag= flag;
+
+ mx = co[0];
+ my = co[1];
+
+ if(mx!=IS_CLIPPED) {
+ setlinestyle(0);
+ cpack(0xFF);
+ circ((float)mx, (float)my, 10.0);
+ setlinestyle(4);
+ cpack(0xFFFFFF);
+ circ((float)mx, (float)my, 10.0);
+ setlinestyle(0);
+ cpack(0x0);
+
+ sdrawline(mx-20, my, mx-5, my);
+ sdrawline(mx+5, my, mx+20, my);
+ sdrawline(mx, my-20, mx, my-5);
+ sdrawline(mx, my+5, mx, my+20);
+ }
+}
+
+/* ********* custom clipping *********** */
+
+static void view3d_draw_clipping(View3D *v3d)
+{
+ BoundBox *bb= v3d->clipbb;
+
+ BIF_ThemeColorShade(TH_BACK, -8);
+
+ glBegin(GL_QUADS);
+
+ glVertex3fv(bb->vec[0]); glVertex3fv(bb->vec[1]); glVertex3fv(bb->vec[2]); glVertex3fv(bb->vec[3]);
+ glVertex3fv(bb->vec[0]); glVertex3fv(bb->vec[4]); glVertex3fv(bb->vec[5]); glVertex3fv(bb->vec[1]);
+ glVertex3fv(bb->vec[4]); glVertex3fv(bb->vec[7]); glVertex3fv(bb->vec[6]); glVertex3fv(bb->vec[5]);
+ glVertex3fv(bb->vec[7]); glVertex3fv(bb->vec[3]); glVertex3fv(bb->vec[2]); glVertex3fv(bb->vec[6]);
+ glVertex3fv(bb->vec[1]); glVertex3fv(bb->vec[5]); glVertex3fv(bb->vec[6]); glVertex3fv(bb->vec[2]);
+ glVertex3fv(bb->vec[7]); glVertex3fv(bb->vec[4]); glVertex3fv(bb->vec[0]); glVertex3fv(bb->vec[3]);
+
+ glEnd();
+}
+
+void view3d_set_clipping(View3D *v3d)
+{
+ double plane[4];
+ int a;
+
+ for(a=0; a<4; a++) {
+ QUATCOPY(plane, v3d->clip[a]);
+ glClipPlane(GL_CLIP_PLANE0+a, plane);
+ glEnable(GL_CLIP_PLANE0+a);
+ }
+}
+
+void view3d_clr_clipping(void)
+{
+ int a;
+
+ for(a=0; a<4; a++) {
+ glDisable(GL_CLIP_PLANE0+a);
+ }
+}
+
+int view3d_test_clipping(View3D *v3d, float *vec)
+{
+ /* vec in world coordinates, returns 1 if clipped */
+ float view[3];
+
+ VECCOPY(view, vec);
+
+ if(0.0f < v3d->clip[0][3] + INPR(view, v3d->clip[0]))
+ if(0.0f < v3d->clip[1][3] + INPR(view, v3d->clip[1]))
+ if(0.0f < v3d->clip[2][3] + INPR(view, v3d->clip[2]))
+ if(0.0f < v3d->clip[3][3] + INPR(view, v3d->clip[3]))
+ return 0;
+
+ return 1;
+}
+
+/* ********* end custom clipping *********** */
+
+static void view3d_get_viewborder_size(View3D *v3d, float size_r[2])
+{
+ float winmax= MAX2(v3d->area->winx, v3d->area->winy);
+ float aspect= (float) (G.scene->r.xsch*G.scene->r.xasp)/(G.scene->r.ysch*G.scene->r.yasp);
+
+ if(aspect>1.0) {
+ size_r[0]= winmax;
+ size_r[1]= winmax/aspect;
+ } else {
+ size_r[0]= winmax*aspect;
+ size_r[1]= winmax;
+ }
+}
+
+void calc_viewborder(struct View3D *v3d, rctf *viewborder_r)
+{
+ float zoomfac, size[2];
+ float dx= 0.0f, dy= 0.0f;
+
+ view3d_get_viewborder_size(v3d, size);
+
+ /* magic zoom calculation, no idea what
+ * it signifies, if you find out, tell me! -zr
+ */
+ /* simple, its magic dude!
+ * well, to be honest, this gives a natural feeling zooming
+ * with multiple keypad presses (ton)
+ */
+
+ zoomfac= (M_SQRT2 + v3d->camzoom/50.0);
+ zoomfac= (zoomfac*zoomfac)*0.25;
+
+ size[0]= size[0]*zoomfac;
+ size[1]= size[1]*zoomfac;
+
+ /* center in window */
+ viewborder_r->xmin= 0.5*v3d->area->winx - 0.5*size[0];
+ viewborder_r->ymin= 0.5*v3d->area->winy - 0.5*size[1];
+ viewborder_r->xmax= viewborder_r->xmin + size[0];
+ viewborder_r->ymax= viewborder_r->ymin + size[1];
+
+ dx= v3d->area->winx*G.vd->camdx*zoomfac*2.0f;
+ dy= v3d->area->winy*G.vd->camdy*zoomfac*2.0f;
+
+ /* apply offset */
+ viewborder_r->xmin-= dx;
+ viewborder_r->ymin-= dy;
+ viewborder_r->xmax-= dx;
+ viewborder_r->ymax-= dy;
+
+ if(v3d->camera && v3d->camera->type==OB_CAMERA) {
+ Camera *cam= v3d->camera->data;
+ float w = viewborder_r->xmax - viewborder_r->xmin;
+ float h = viewborder_r->ymax - viewborder_r->ymin;
+ float side = MAX2(w, h);
+
+ viewborder_r->xmin+= cam->shiftx*side;
+ viewborder_r->xmax+= cam->shiftx*side;
+ viewborder_r->ymin+= cam->shifty*side;
+ viewborder_r->ymax+= cam->shifty*side;
+ }
+}
+
+void view3d_set_1_to_1_viewborder(View3D *v3d)
+{
+ float size[2];
+ int im_width= (G.scene->r.size*G.scene->r.xsch)/100;
+
+ view3d_get_viewborder_size(v3d, size);
+
+ v3d->camzoom= (sqrt(4.0*im_width/size[0]) - M_SQRT2)*50.0;
+ v3d->camzoom= CLAMPIS(v3d->camzoom, -30, 300);
+}
+
+
+static void drawviewborder_flymode(void)
+{
+ /* draws 4 edge brackets that frame the safe area where the
+ mouse can move during fly mode without spinning the view */
+ float x1, x2, y1, y2;
+
+ x1= 0.45*(float)curarea->winx;
+ y1= 0.45*(float)curarea->winy;
+ x2= 0.55*(float)curarea->winx;
+ y2= 0.55*(float)curarea->winy;
+ cpack(0);
+
+
+ glBegin(GL_LINES);
+ /* bottom left */
+ glVertex2f(x1,y1);
+ glVertex2f(x1,y1+5);
+
+ glVertex2f(x1,y1);
+ glVertex2f(x1+5,y1);
+
+ /* top right */
+ glVertex2f(x2,y2);
+ glVertex2f(x2,y2-5);
+
+ glVertex2f(x2,y2);
+ glVertex2f(x2-5,y2);
+
+ /* top left */
+ glVertex2f(x1,y2);
+ glVertex2f(x1,y2-5);
+
+ glVertex2f(x1,y2);
+ glVertex2f(x1+5,y2);
+
+ /* bottom right */
+ glVertex2f(x2,y1);
+ glVertex2f(x2,y1+5);
+
+ glVertex2f(x2,y1);
+ glVertex2f(x2-5,y1);
+ glEnd();
+}
+
+
+static void drawviewborder(void)
+{
+ extern void gl_round_box(int mode, float minx, float miny, float maxx, float maxy, float rad); // interface_panel.c
+ float fac, a;
+ float x1, x2, y1, y2;
+ float x3, y3, x4, y4;
+ rctf viewborder;
+ Camera *ca= NULL;
+
+ if(G.vd->camera==NULL)
+ return;
+ if(G.vd->camera->type==OB_CAMERA)
+ ca = G.vd->camera->data;
+
+ calc_viewborder(G.vd, &viewborder);
+ x1= viewborder.xmin;
+ y1= viewborder.ymin;
+ x2= viewborder.xmax;
+ y2= viewborder.ymax;
+
+ /* passepartout, specified in camera edit buttons */
+ if (ca && (ca->flag & CAM_SHOWPASSEPARTOUT) && ca->passepartalpha > 0.000001) {
+ if (ca->passepartalpha == 1.0) {
+ glColor3f(0, 0, 0);
+ } else {
+ glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
+ glEnable(GL_BLEND);
+ glColor4f(0, 0, 0, ca->passepartalpha);
+ }
+ if (x1 > 0.0)
+ glRectf(0.0, (float)curarea->winy, x1, 0.0);
+ if (x2 < (float)curarea->winx)
+ glRectf(x2, (float)curarea->winy, (float)curarea->winx, 0.0);
+ if (y2 < (float)curarea->winy)
+ glRectf(x1, (float)curarea->winy, x2, y2);
+ if (y2 > 0.0)
+ glRectf(x1, y1, x2, 0.0);
+
+ glDisable(GL_BLEND);
+ }
+
+ /* edge */
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+
+ setlinestyle(0);
+ BIF_ThemeColor(TH_BACK);
+ glRectf(x1, y1, x2, y2);
+
+ setlinestyle(3);
+ BIF_ThemeColor(TH_WIRE);
+ glRectf(x1, y1, x2, y2);
+
+ /* camera name - draw in highlighted text color */
+ if (ca && (ca->flag & CAM_SHOWNAME)) {
+ BIF_ThemeColor(TH_TEXT_HI);
+ glRasterPos2f(x1, y1-15);
+
+ BMF_DrawString(G.font, G.vd->camera->id.name+2);
+ BIF_ThemeColor(TH_WIRE);
+ }
+
+
+ /* border */
+ if(G.scene->r.mode & R_BORDER) {
+
+ cpack(0);
+ x3= x1+ G.scene->r.border.xmin*(x2-x1);
+ y3= y1+ G.scene->r.border.ymin*(y2-y1);
+ x4= x1+ G.scene->r.border.xmax*(x2-x1);
+ y4= y1+ G.scene->r.border.ymax*(y2-y1);
+
+ cpack(0x4040FF);
+ glRectf(x3, y3, x4, y4);
+ }
+
+ /* safety border */
+ if (ca && (ca->flag & CAM_SHOWTITLESAFE)) {
+ fac= 0.1;
+
+ a= fac*(x2-x1);
+ x1+= a;
+ x2-= a;
+
+ a= fac*(y2-y1);
+ y1+= a;
+ y2-= a;
+
+ BIF_ThemeColorBlendShade(TH_WIRE, TH_BACK, 0.25, 0);
+
+ uiSetRoundBox(15);
+ gl_round_box(GL_LINE_LOOP, x1, y1, x2, y2, 12.0);
+ }
+
+ setlinestyle(0);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+
+}
+
+void backdrawview3d(int test)
+{
+ struct Base *base;
+
+/*for 2.43 release, don't use glext and just define the constant.
+ this to avoid possibly breaking platforms before release.*/
+#ifndef GL_MULTISAMPLE_ARB
+ #define GL_MULTISAMPLE_ARB 0x809D
+#endif
+
+#ifdef GL_MULTISAMPLE_ARB
+ int m;
+#endif
+
+ if(G.f & G_VERTEXPAINT || G.f & G_WEIGHTPAINT || G.f & G_TEXTUREPAINT);
+ else if(G.obedit && G.vd->drawtype>OB_WIRE && (G.vd->flag & V3D_ZBUF_SELECT));
+ else {
+ G.vd->flag &= ~V3D_NEEDBACKBUFDRAW;
+ return;
+ }
+
+ if( !(G.vd->flag & V3D_NEEDBACKBUFDRAW) ) return;
+
+ if(test) {
+ if(qtest()) {
+ addafterqueue(curarea->win, BACKBUFDRAW, 1);
+ return;
+ }
+ }
+ persp(PERSP_VIEW);
+
+ /*Disable FSAA for backbuffer selection.
+
+ Only works if GL_MULTISAMPLE_ARB is defined by the header
+ file, which is should be for every OS that supports FSAA.*/
+
+#ifdef GL_MULTISAMPLE_ARB
+ m = glIsEnabled(GL_MULTISAMPLE_ARB);
+ if (m) glDisable(GL_MULTISAMPLE_ARB);
+#endif
+
+#ifdef __APPLE__
+ glDrawBuffer(GL_AUX0);
+#endif
+ if(G.vd->drawtype > OB_WIRE) G.vd->zbuf= TRUE;
+ curarea->win_swap &= ~WIN_BACK_OK;
+
+ glDisable(GL_DITHER);
+
+ glClearColor(0.0, 0.0, 0.0, 0.0);
+ if(G.vd->zbuf) {
+ glEnable(GL_DEPTH_TEST);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ }
+ else {
+ glClear(GL_COLOR_BUFFER_BIT);
+ glDisable(GL_DEPTH_TEST);
+ }
+
+ if(G.vd->flag & V3D_CLIPPING)
+ view3d_set_clipping(G.vd);
+
+ G.f |= G_BACKBUFSEL;
+
+ base= (G.scene->basact);
+ if(base && (base->lay & G.vd->lay)) {
+ draw_object_backbufsel(base->object);
+ }
+
+ G.vd->flag &= ~V3D_NEEDBACKBUFDRAW;
+
+ G.f &= ~G_BACKBUFSEL;
+ G.vd->zbuf= FALSE;
+ glDisable(GL_DEPTH_TEST);
+ glEnable(GL_DITHER);
+
+#ifdef __APPLE__
+ glDrawBuffer(GL_BACK); /* we were in aux buffers */
+#endif
+
+ if(G.vd->flag & V3D_CLIPPING)
+ view3d_clr_clipping();
+
+#ifdef GL_MULTISAMPLE_ARB
+ if (m) glEnable(GL_MULTISAMPLE_ARB);
+#endif
+
+ /* it is important to end a view in a transform compatible with buttons */
+ persp(PERSP_WIN); // set ortho
+ bwin_scalematrix(curarea->win, G.vd->blockscale, G.vd->blockscale, G.vd->blockscale);
+
+}
+
+void check_backbuf(void)
+{
+ if(G.vd->flag & V3D_NEEDBACKBUFDRAW)
+ backdrawview3d(0);
+}
+
+/* samples a single pixel (copied from vpaint) */
+unsigned int sample_backbuf(int x, int y)
+{
+ unsigned int col;
+
+ if(x>=curarea->winx || y>=curarea->winy) return 0;
+ x+= curarea->winrct.xmin;
+ y+= curarea->winrct.ymin;
+
+ check_backbuf(); // actually not needed for apple
+
+#ifdef __APPLE__
+ glReadBuffer(GL_AUX0);
+#endif
+ glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col);
+ glReadBuffer(GL_BACK);
+
+ if(G.order==B_ENDIAN) SWITCH_INT(col);
+
+ return framebuffer_to_index(col);
+}
+
+/* reads full rect, converts indices */
+ImBuf *read_backbuf(short xmin, short ymin, short xmax, short ymax)
+{
+ unsigned int *dr, *rd;
+ struct ImBuf *ibuf, *ibuf1;
+ int a;
+ short xminc, yminc, xmaxc, ymaxc, xs, ys;
+
+ /* clip */
+ if(xmin<0) xminc= 0; else xminc= xmin;
+ if(xmax>=curarea->winx) xmaxc= curarea->winx-1; else xmaxc= xmax;
+ if(xminc > xmaxc) return NULL;
+
+ if(ymin<0) yminc= 0; else yminc= ymin;
+ if(ymax>=curarea->winy) ymaxc= curarea->winy-1; else ymaxc= ymax;
+ if(yminc > ymaxc) return NULL;
+
+ ibuf= IMB_allocImBuf((xmaxc-xminc+1), (ymaxc-yminc+1), 32, IB_rect,0);
+
+ check_backbuf(); // actually not needed for apple
+
+#ifdef __APPLE__
+ glReadBuffer(GL_AUX0);
+#endif
+ glReadPixels(curarea->winrct.xmin+xminc, curarea->winrct.ymin+yminc, (xmaxc-xminc+1), (ymaxc-yminc+1), GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
+ glReadBuffer(GL_BACK);
+
+ if(G.order==B_ENDIAN) IMB_convert_rgba_to_abgr(ibuf);
+
+ a= (xmaxc-xminc+1)*(ymaxc-yminc+1);
+ dr= ibuf->rect;
+ while(a--) {
+ if(*dr) *dr= framebuffer_to_index(*dr);
+ dr++;
+ }
+
+ /* put clipped result back, if needed */
+ if(xminc==xmin && xmaxc==xmax && yminc==ymin && ymaxc==ymax)
+ return ibuf;
+
+ ibuf1= IMB_allocImBuf( (xmax-xmin+1),(ymax-ymin+1),32,IB_rect,0);
+ rd= ibuf->rect;
+ dr= ibuf1->rect;
+
+ for(ys= ymin; ys<=ymax; ys++) {
+ for(xs= xmin; xs<=xmax; xs++, dr++) {
+ if( xs>=xminc && xs<=xmaxc && ys>=yminc && ys<=ymaxc) {
+ *dr= *rd;
+ rd++;
+ }
+ }
+ }
+ IMB_freeImBuf(ibuf);
+ return ibuf1;
+}
+
+/* smart function to sample a rect spiralling outside, nice for backbuf selection */
+unsigned int sample_backbuf_rect(short mval[2], int size, unsigned int min, unsigned int max, int *dist, short strict, unsigned int (*indextest)(unsigned int index))
+{
+ struct ImBuf *buf;
+ unsigned int *bufmin, *bufmax, *tbuf;
+ int minx, miny;
+ int a, b, rc, nr, amount, dirvec[4][2];
+ int distance=0;
+ unsigned int index = 0;
+ short indexok = 0;
+
+ amount= (size-1)/2;
+
+ minx = mval[0]-(amount+1);
+ miny = mval[1]-(amount+1);
+ buf = read_backbuf(minx, miny, minx+size-1, miny+size-1);
+ if (!buf) return 0;
+
+ rc= 0;
+
+ dirvec[0][0]= 1; dirvec[0][1]= 0;
+ dirvec[1][0]= 0; dirvec[1][1]= -size;
+ dirvec[2][0]= -1; dirvec[2][1]= 0;
+ dirvec[3][0]= 0; dirvec[3][1]= size;
+
+ bufmin = buf->rect;
+ tbuf = buf->rect;
+ bufmax = buf->rect + size*size;
+ tbuf+= amount*size+ amount;
+
+ for(nr=1; nr<=size; nr++) {
+
+ for(a=0; a<2; a++) {
+ for(b=0; b<nr; b++, distance++) {
+ if (*tbuf && *tbuf>=min && *tbuf<max) { //we got a hit
+ if(strict){
+ indexok = indextest(*tbuf - min+1);
+ if(indexok){
+ *dist= (short) sqrt( (float)distance );
+ index = *tbuf - min+1;
+ goto exit;
+ }
+ }
+ else{
+ *dist= (short) sqrt( (float)distance ); // XXX, this distance is wrong -
+ index = *tbuf - min+1; // messy yah, but indices start at 1
+ goto exit;
+ }
+ }
+
+ tbuf+= (dirvec[rc][0]+dirvec[rc][1]);
+
+ if(tbuf<bufmin || tbuf>=bufmax) {
+ goto exit;
+ }
+ }
+ rc++;
+ rc &= 3;
+ }
+ }
+
+exit:
+ IMB_freeImBuf(buf);
+ return index;
+}
+
+void drawname(Object *ob)
+{
+ cpack(0x404040);
+ glRasterPos3f(0.0, 0.0, 0.0);
+
+ BMF_DrawString(G.font, " ");
+ BMF_DrawString(G.font, ob->id.name+2);
+}
+
+
+static void draw_selected_name(Object *ob)
+{
+ char info[128];
+ short offset=30;
+
+ if(ob->type==OB_ARMATURE) {
+ bArmature *arm= ob->data;
+ char *name= NULL;
+
+ if(ob==G.obedit) {
+ EditBone *ebo;
+ for (ebo=G.edbo.first; ebo; ebo=ebo->next){
+ if ((ebo->flag & BONE_ACTIVE) && (ebo->layer & arm->layer)) {
+ name= ebo->name;
+ break;
+ }
+ }
+ }
+ else if(ob->pose && (ob->flag & OB_POSEMODE)) {
+ bPoseChannel *pchan;
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ if((pchan->bone->flag & BONE_ACTIVE) && (pchan->bone->layer & arm->layer)) {
+ name= pchan->name;
+ break;
+ }
+ }
+ }
+ if(name)
+ sprintf(info, "(%d) %s %s", CFRA, ob->id.name+2, name);
+ else
+ sprintf(info, "(%d) %s", CFRA, ob->id.name+2);
+ }
+ else if(ob->type==OB_MESH) {
+ Key *key= NULL;
+ KeyBlock *kb = NULL;
+ char shapes[75];
+
+ shapes[0] = 0;
+ key = ob_get_key(ob);
+ if(key){
+ kb = BLI_findlink(&key->block, ob->shapenr-1);
+ if(kb){
+ sprintf(shapes, ": %s ", kb->name);
+ if(ob->shapeflag == OB_SHAPE_LOCK){
+ sprintf(shapes, "%s (Pinned)",shapes);
+ }
+ }
+ }
+ sprintf(info, "(%d) %s %s", CFRA, ob->id.name+2, shapes);
+ }
+ else sprintf(info, "(%d) %s", CFRA, ob->id.name+2);
+
+ BIF_ThemeColor(TH_TEXT_HI);
+ if (U.uiflag & USER_SHOW_ROTVIEWICON)
+ offset = 14 + (U.rvisize * 2);
+
+ glRasterPos2i(offset, 10);
+ BMF_DrawString(G.fonts, info);
+}
+
+
+/* Draw a live substitute of the view icon, which is always shown */
+static void draw_view_axis(void)
+{
+ const float k = U.rvisize; /* axis size */
+ const float toll = 0.5; /* used to see when view is quasi-orthogonal */
+ const float start = k + 1.0; /* axis center in screen coordinates, x=y */
+ float ydisp = 0.0; /* vertical displacement to allow obj info text */
+
+ /* rvibright ranges approx. from original axis icon color to gizmo color */
+ float bright = U.rvibright / 15.0f;
+
+ unsigned char col[3];
+ unsigned char gridcol[3];
+ float colf[3];
+
+ float vec[4];
+ float dx, dy;
+ float h, s, v;
+
+ BIF_GetThemeColor3ubv(TH_GRID, (char *)gridcol);
+
+ /* X */
+ vec[0] = vec[3] = 1;
+ vec[1] = vec[2] = 0;
+ QuatMulVecf(G.vd->viewquat, vec);
+
+ make_axis_color((char *)gridcol, (char *)col, 'x');
+ rgb_to_hsv(col[0]/255.0f, col[1]/255.0f, col[2]/255.0f, &h, &s, &v);
+ s = s<0.5 ? s+0.5 : 1.0;
+ v = 0.3;
+ v = (v<1.0-(bright) ? v+bright : 1.0);
+ hsv_to_rgb(h, s, v, colf, colf+1, colf+2);
+ glColor3fv(colf);
+
+ dx = vec[0] * k;
+ dy = vec[1] * k;
+ fdrawline(start, start + ydisp, start + dx, start + dy + ydisp);
+ if (fabs(dx) > toll || fabs(dy) > toll) {
+ glRasterPos2i(start + dx + 2, start + dy + ydisp + 2);
+ BMF_DrawString(G.fonts, "x");
+ }
+
+ /* Y */
+ vec[1] = vec[3] = 1;
+ vec[0] = vec[2] = 0;
+ QuatMulVecf(G.vd->viewquat, vec);
+
+ make_axis_color((char *)gridcol, (char *)col, 'y');
+ rgb_to_hsv(col[0]/255.0f, col[1]/255.0f, col[2]/255.0f, &h, &s, &v);
+ s = s<0.5 ? s+0.5 : 1.0;
+ v = 0.3;
+ v = (v<1.0-(bright) ? v+bright : 1.0);
+ hsv_to_rgb(h, s, v, colf, colf+1, colf+2);
+ glColor3fv(colf);
+
+ dx = vec[0] * k;
+ dy = vec[1] * k;
+ fdrawline(start, start + ydisp, start + dx, start + dy + ydisp);
+ if (fabs(dx) > toll || fabs(dy) > toll) {
+ glRasterPos2i(start + dx + 2, start + dy + ydisp + 2);
+ BMF_DrawString(G.fonts, "y");
+ }
+
+ /* Z */
+ vec[2] = vec[3] = 1;
+ vec[1] = vec[0] = 0;
+ QuatMulVecf(G.vd->viewquat, vec);
+
+ make_axis_color((char *)gridcol, (char *)col, 'z');
+ rgb_to_hsv(col[0]/255.0f, col[1]/255.0f, col[2]/255.0f, &h, &s, &v);
+ s = s<0.5 ? s+0.5 : 1.0;
+ v = 0.5;
+ v = (v<1.0-(bright) ? v+bright : 1.0);
+ hsv_to_rgb(h, s, v, colf, colf+1, colf+2);
+ glColor3fv(colf);
+
+ dx = vec[0] * k;
+ dy = vec[1] * k;
+ fdrawline(start, start + ydisp, start + dx, start + dy + ydisp);
+ if (fabs(dx) > toll || fabs(dy) > toll) {
+ glRasterPos2i(start + dx + 2, start + dy + ydisp + 2);
+ BMF_DrawString(G.fonts, "z");
+ }
+}
+
+
+static void draw_view_icon(void)
+{
+ BIFIconID icon;
+
+ if(G.vd->view==7) icon= ICON_AXIS_TOP;
+ else if(G.vd->view==1) icon= ICON_AXIS_FRONT;
+ else if(G.vd->view==3) icon= ICON_AXIS_SIDE;
+ else return ;
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ BIF_icon_draw(5.0, 5.0, icon);
+
+ glDisable(GL_BLEND);
+}
+
+static void draw_viewport_name(ScrArea *sa)
+{
+ char *name = NULL;
+ char *printable = NULL;
+
+ switch(G.vd->view) {
+ case 1:
+ if (G.vd->persp & V3D_PERSP_DO_3D_PERSP)
+ name = (G.vd->flag2 & V3D_OPP_DIRECTION_NAME) ? "Back Persp" : "Front Persp";
+ else
+ name = (G.vd->flag2 & V3D_OPP_DIRECTION_NAME) ? "Back Ortho" : "Front Ortho";
+ break;
+ case 3:
+ if (G.vd->persp & V3D_PERSP_DO_3D_PERSP)
+ name = (G.vd->flag2 & V3D_OPP_DIRECTION_NAME) ? "Left Persp" : "Right Persp";
+ else
+ name = (G.vd->flag2 & V3D_OPP_DIRECTION_NAME) ? "Left Ortho" : "Right Ortho";
+ break;
+ case 7:
+ if (G.vd->persp & V3D_PERSP_DO_3D_PERSP)
+ name = (G.vd->flag2 & V3D_OPP_DIRECTION_NAME) ? "Bottom Persp" : "Top Persp";
+ else
+ name = (G.vd->flag2 & V3D_OPP_DIRECTION_NAME) ? "Bottom Ortho" : "Top Ortho";
+ break;
+ default:
+ if (G.vd->persp==V3D_PERSP_USE_THE_CAMERA) {
+ if ((G.vd->camera) && (G.vd->camera->type == OB_CAMERA)) {
+ Camera *cam;
+ cam = G.vd->camera->data;
+ name = (cam->type != CAM_ORTHO) ? "Camera Persp" : "Camera Ortho";
+ } else {
+ name = "Object as Camera";
+ }
+ } else {
+ name = (G.vd->persp & V3D_PERSP_DO_3D_PERSP) ? "User Persp" : "User Ortho";
+ }
+ }
+
+ if (G.vd->localview) {
+ printable = malloc(strlen(name) + strlen(" (Local)_")); /* '_' gives space for '\0' */
+ strcpy(printable, name);
+ strcat(printable, " (Local)");
+ } else {
+ printable = name;
+ }
+
+ if (printable) {
+ BIF_ThemeColor(TH_TEXT_HI);
+ glRasterPos2i(10, sa->winy-20);
+ BMF_DrawString(G.fonts, printable);
+ }
+
+ if (G.vd->localview) {
+ free(printable);
+ }
+}
+
+/* ******************* view3d space & buttons ************** */
+
+
+/* temporal struct for storing transform properties */
+typedef struct {
+ float ob_eul[4]; // used for quat too....
+ float ob_scale[3]; // need temp space due to linked values
+ float ob_dims[3];
+ short link_scale;
+ float ve_median[5];
+ int curdef;
+ float *defweightp;
+} TransformProperties;
+
+/* is used for both read and write... */
+static void v3d_editvertex_buts(uiBlock *block, Object *ob, float lim)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve, *evedef=NULL;
+ EditEdge *eed;
+ MDeformVert *dvert=NULL;
+ TransformProperties *tfp= G.vd->properties_storage;
+ float median[5];
+ int tot, totw, totweight, totedge;
+ char defstr[320];
+
+ median[0]= median[1]= median[2]= median[3]= median[4]= 0.0;
+ tot= totw= totweight= totedge= 0;
+ defstr[0]= 0;
+
+ if(ob->type==OB_MESH) {
+ eve= em->verts.first;
+ while(eve) {
+ if(eve->f & 1) {
+ evedef= eve;
+ tot++;
+ VecAddf(median, median, eve->co);
+ }
+ eve= eve->next;
+ }
+ eed= em->edges.first;
+ while(eed) {
+ if((eed->f & SELECT)) {
+ totedge++;
+ median[3]+= eed->crease;
+ }
+ eed= eed->next;
+ }
+
+ /* check for defgroups */
+ if(evedef)
+ dvert= CustomData_em_get(&em->vdata, evedef->data, CD_MDEFORMVERT);
+ if(tot==1 && dvert && dvert->totweight) {
+ bDeformGroup *dg;
+ int i, max=1, init=1;
+ char str[320];
+
+ for (i=0; i<dvert->totweight; i++){
+ dg = BLI_findlink (&ob->defbase, dvert->dw[i].def_nr);
+ if(dg) {
+ max+= snprintf(str, sizeof(str), "%s %%x%d|", dg->name, dvert->dw[i].def_nr);
+ if(max<320) strcat(defstr, str);
+ }
+ else printf("oh no!\n");
+ if(tfp->curdef==dvert->dw[i].def_nr) {
+ init= 0;
+ tfp->defweightp= &dvert->dw[i].weight;
+ }
+ }
+
+ if(init) { // needs new initialized
+ tfp->curdef= dvert->dw[0].def_nr;
+ tfp->defweightp= &dvert->dw[0].weight;
+ }
+ }
+ }
+ else if(ob->type==OB_CURVE || ob->type==OB_SURF) {
+ extern ListBase editNurb; /* editcurve.c */
+ Nurb *nu;
+ BPoint *bp;
+ BezTriple *bezt;
+ int a;
+
+ nu= editNurb.first;
+ while(nu) {
+ if((nu->type & 7)==CU_BEZIER) {
+ bezt= nu->bezt;
+ a= nu->pntsu;
+ while(a--) {
+ if(bezt->f2 & 1) {
+ VecAddf(median, median, bezt->vec[1]);
+ tot++;
+ median[4]+= bezt->weight;
+ totweight++;
+ }
+ else {
+ if(bezt->f1 & 1) {
+ VecAddf(median, median, bezt->vec[0]);
+ tot++;
+ }
+ if(bezt->f3 & 1) {
+ VecAddf(median, median, bezt->vec[2]);
+ tot++;
+ }
+ }
+ bezt++;
+ }
+ }
+ else {
+ bp= nu->bp;
+ a= nu->pntsu*nu->pntsv;
+ while(a--) {
+ if(bp->f1 & 1) {
+ VecAddf(median, median, bp->vec);
+ median[3]+= bp->vec[3];
+ totw++;
+ tot++;
+ median[4]+= bp->weight;
+ totweight++;
+ }
+ bp++;
+ }
+ }
+ nu= nu->next;
+ }
+ }
+ else if(ob->type==OB_LATTICE) {
+ BPoint *bp;
+ int a;
+
+ a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
+ bp= editLatt->def;
+ while(a--) {
+ if(bp->f1 & SELECT) {
+ VecAddf(median, median, bp->vec);
+ tot++;
+ median[4]+= bp->weight;
+ totweight++;
+ }
+ bp++;
+ }
+ }
+
+ if(tot==0) return;
+
+ median[0] /= (float)tot;
+ median[1] /= (float)tot;
+ median[2] /= (float)tot;
+ if(totedge) median[3] /= (float)totedge;
+ else if(totw) median[3] /= (float)totw;
+ if(totweight) median[4] /= (float)totweight;
+
+ if(G.vd->flag & V3D_GLOBAL_STATS)
+ Mat4MulVecfl(ob->obmat, median);
+
+ if(block) { // buttons
+
+ uiBlockBeginAlign(block);
+ if((ob->parent) && (ob->partype == PARBONE)) {
+ uiDefButBitS(block, TOG, V3D_GLOBAL_STATS, REDRAWVIEW3D, "Global", 160, 135, 70, 19, &G.vd->flag, 0, 0, 0, 0, "Displays global values");
+ uiDefButBitS(block, TOGN, V3D_GLOBAL_STATS, REDRAWVIEW3D, "Local", 230, 135, 70, 19, &G.vd->flag, 0, 0, 0, 0, "Displays local values");
+ }
+ else {
+ uiDefButBitS(block, TOG, V3D_GLOBAL_STATS, REDRAWVIEW3D, "Global", 160, 150, 70, 19, &G.vd->flag, 0, 0, 0, 0, "Displays global values");
+ uiDefButBitS(block, TOGN, V3D_GLOBAL_STATS, REDRAWVIEW3D, "Local", 230, 150, 70, 19, &G.vd->flag, 0, 0, 0, 0, "Displays local values");
+ }
+
+ memcpy(tfp->ve_median, median, sizeof(tfp->ve_median));
+
+ uiBlockBeginAlign(block);
+ if(tot==1) {
+ uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Vertex X:", 10, 110, 290, 19, &(tfp->ve_median[0]), -lim, lim, 10, 3, "");
+ uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Vertex Y:", 10, 90, 290, 19, &(tfp->ve_median[1]), -lim, lim, 10, 3, "");
+ uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Vertex Z:", 10, 70, 290, 19, &(tfp->ve_median[2]), -lim, lim, 10, 3, "");
+ if(totw==1)
+ uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Vertex W:", 10, 50, 290, 19, &(tfp->ve_median[3]), 0.01, 100.0, 10, 3, "");
+ uiBlockEndAlign(block);
+
+ if(defstr[0]) {
+ uiDefBut(block, LABEL, 1, "Vertex Deform Groups", 10, 40, 290, 20, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_NOP, "Weight:", 10, 20, 150, 19, tfp->defweightp, 0.0f, 1.0f, 10, 3, "Weight value");
+ uiDefButI(block, MENU, REDRAWVIEW3D, defstr, 160, 20, 140, 19, &tfp->curdef, 0.0, 0.0, 0, 0, "Current Vertex Group");
+ uiBlockEndAlign(block);
+ }
+ else if(totweight)
+ uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Weight:", 10, 20, 290, 19, &(tfp->ve_median[4]), 0.0, 1.0, 10, 3, "");
+
+ }
+ else {
+ uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Median X:", 10, 110, 290, 19, &(tfp->ve_median[0]), -lim, lim, 10, 3, "");
+ uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Median Y:", 10, 90, 290, 19, &(tfp->ve_median[1]), -lim, lim, 10, 3, "");
+ uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Median Z:", 10, 70, 290, 19, &(tfp->ve_median[2]), -lim, lim, 10, 3, "");
+ if(totw==tot)
+ uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Median W:", 10, 50, 290, 19, &(tfp->ve_median[3]), 0.01, 100.0, 10, 3, "");
+ uiBlockEndAlign(block);
+ if(totweight)
+ uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Weight:", 10, 20, 290, 19, &(tfp->ve_median[4]), 0.0, 1.0, 10, 3, "Weight is used for SoftBody Goal");
+ }
+
+ if(totedge==1)
+ uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Crease W:", 10, 30, 290, 19, &(tfp->ve_median[3]), 0.0, 1.0, 10, 3, "");
+ else if(totedge>1)
+ uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Median Crease W:", 10, 30, 290, 19, &(tfp->ve_median[3]), 0.0, 1.0, 10, 3, "");
+
+ }
+ else { // apply
+
+ if(G.vd->flag & V3D_GLOBAL_STATS) {
+ Mat4Invert(ob->imat, ob->obmat);
+ Mat4MulVecfl(ob->imat, median);
+ Mat4MulVecfl(ob->imat, tfp->ve_median);
+ }
+ VecSubf(median, tfp->ve_median, median);
+ median[3]= tfp->ve_median[3]-median[3];
+ median[4]= tfp->ve_median[4]-median[4];
+
+ if(ob->type==OB_MESH) {
+
+ eve= em->verts.first;
+ while(eve) {
+ if(eve->f & 1) {
+ VecAddf(eve->co, eve->co, median);
+ }
+ eve= eve->next;
+ }
+
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->f & SELECT) {
+ /* ensure the median can be set to zero or one */
+ if(tfp->ve_median[3]==0.0f) eed->crease= 0.0f;
+ else if(tfp->ve_median[3]==1.0f) eed->crease= 1.0f;
+ else {
+ eed->crease+= median[3];
+ CLAMP(eed->crease, 0.0, 1.0);
+ }
+ }
+ }
+
+ recalc_editnormals();
+ }
+ else if(ob->type==OB_CURVE || ob->type==OB_SURF) {
+ extern ListBase editNurb; /* editcurve.c */
+ Nurb *nu;
+ BPoint *bp;
+ BezTriple *bezt;
+ int a;
+
+ nu= editNurb.first;
+ while(nu) {
+ if((nu->type & 7)==1) {
+ bezt= nu->bezt;
+ a= nu->pntsu;
+ while(a--) {
+ if(bezt->f2 & 1) {
+ VecAddf(bezt->vec[0], bezt->vec[0], median);
+ VecAddf(bezt->vec[1], bezt->vec[1], median);
+ VecAddf(bezt->vec[2], bezt->vec[2], median);
+ bezt->weight+= median[4];
+ }
+ else {
+ if(bezt->f1 & 1) {
+ VecAddf(bezt->vec[0], bezt->vec[0], median);
+ }
+ if(bezt->f3 & 1) {
+ VecAddf(bezt->vec[2], bezt->vec[2], median);
+ }
+ }
+ bezt++;
+ }
+ }
+ else {
+ bp= nu->bp;
+ a= nu->pntsu*nu->pntsv;
+ while(a--) {
+ if(bp->f1 & 1) {
+ VecAddf(bp->vec, bp->vec, median);
+ bp->vec[3]+= median[3];
+ bp->weight+= median[4];
+ }
+ bp++;
+ }
+ }
+ test2DNurb(nu);
+ testhandlesNurb(nu); /* test for bezier too */
+
+ nu= nu->next;
+ }
+ }
+ else if(ob->type==OB_LATTICE) {
+ BPoint *bp;
+ int a;
+
+ a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
+ bp= editLatt->def;
+ while(a--) {
+ if(bp->f1 & SELECT) {
+ VecAddf(bp->vec, bp->vec, median);
+ bp->weight+= median[4];
+ }
+ bp++;
+ }
+ }
+
+ BIF_undo_push("Transform properties");
+ }
+}
+
+/* assumes armature active */
+static void validate_bonebutton_cb(void *bonev, void *namev)
+{
+ Object *ob= OBACT;
+
+ if(ob && ob->type==OB_ARMATURE) {
+ Bone *bone= bonev;
+ char oldname[32], newname[32];
+
+ /* need to be on the stack */
+ BLI_strncpy(newname, bone->name, 32);
+ BLI_strncpy(oldname, (char *)namev, 32);
+ /* restore */
+ BLI_strncpy(bone->name, oldname, 32);
+
+ armature_bone_rename(ob->data, oldname, newname); // editarmature.c
+ allqueue(REDRAWALL, 0);
+ }
+}
+
+static void v3d_posearmature_buts(uiBlock *block, Object *ob, float lim)
+{
+ uiBut *but;
+ bArmature *arm;
+ bPoseChannel *pchan;
+ Bone *bone= NULL;
+ TransformProperties *tfp= G.vd->properties_storage;
+
+ arm = get_armature(OBACT);
+ if (!arm || !ob->pose) return;
+
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ bone = pchan->bone;
+ if(bone && (bone->flag & BONE_ACTIVE) && (bone->layer & arm->layer))
+ break;
+ }
+ if (!pchan || !bone) return;
+
+ if((ob->parent) && (ob->partype == PARBONE))
+ but= uiDefBut (block, TEX, B_DIFF, "Bone:", 160, 130, 140, 19, bone->name, 1, 31, 0, 0, "");
+ else
+ but= uiDefBut(block, TEX, B_DIFF, "Bone:", 160, 140, 140, 19, bone->name, 1, 31, 0, 0, "");
+ uiButSetFunc(but, validate_bonebutton_cb, bone, NULL);
+
+ QuatToEul(pchan->quat, tfp->ob_eul);
+ tfp->ob_eul[0]*= 180.0/M_PI;
+ tfp->ob_eul[1]*= 180.0/M_PI;
+ tfp->ob_eul[2]*= 180.0/M_PI;
+
+ uiBlockBeginAlign(block);
+ uiDefIconButBitS(block, ICONTOG, OB_LOCK_LOCX, REDRAWVIEW3D, ICON_UNLOCKED, 10,140,20,19, &(pchan->protectflag), 0, 0, 0, 0, "Protects this value from being Transformed");
+ uiDefButF(block, NUM, B_ARMATUREPANEL2, "LocX:", 30, 140, 120, 19, pchan->loc, -lim, lim, 100, 3, "");
+ uiDefIconButBitS(block, ICONTOG, OB_LOCK_LOCY, REDRAWVIEW3D, ICON_UNLOCKED, 10,120,20,19, &(pchan->protectflag), 0, 0, 0, 0, "Protects this value from being Transformed");
+ uiDefButF(block, NUM, B_ARMATUREPANEL2, "LocY:", 30, 120, 120, 19, pchan->loc+1, -lim, lim, 100, 3, "");
+ uiDefIconButBitS(block, ICONTOG, OB_LOCK_LOCZ, REDRAWVIEW3D, ICON_UNLOCKED, 10,100,20,19, &(pchan->protectflag), 0, 0, 0, 0, "Protects this value from being Transformed");
+ uiDefButF(block, NUM, B_ARMATUREPANEL2, "LocZ:", 30, 100, 120, 19, pchan->loc+2, -lim, lim, 100, 3, "");
+
+ uiBlockBeginAlign(block);
+ uiDefIconButBitS(block, ICONTOG, OB_LOCK_ROTX, REDRAWVIEW3D, ICON_UNLOCKED, 10,70,20,19, &(pchan->protectflag), 0, 0, 0, 0, "Protects this value from being Transformed");
+ uiDefButF(block, NUM, B_ARMATUREPANEL3, "RotX:", 30, 70, 120, 19, tfp->ob_eul, -1000.0, 1000.0, 100, 3, "");
+ uiDefIconButBitS(block, ICONTOG, OB_LOCK_ROTY, REDRAWVIEW3D, ICON_UNLOCKED, 10,50,20,19, &(pchan->protectflag), 0, 0, 0, 0, "Protects this value from being Transformed");
+ uiDefButF(block, NUM, B_ARMATUREPANEL3, "RotY:", 30, 50, 120, 19, tfp->ob_eul+1, -1000.0, 1000.0, 100, 3, "");
+ uiDefIconButBitS(block, ICONTOG, OB_LOCK_ROTZ, REDRAWVIEW3D, ICON_UNLOCKED, 10,30,20,19, &(pchan->protectflag), 0, 0, 0, 0, "Protects this value from being Transformed");
+ uiDefButF(block, NUM, B_ARMATUREPANEL3, "RotZ:", 30, 30, 120, 19, tfp->ob_eul+2, -1000.0, 1000.0, 100, 3, "");
+
+ uiBlockBeginAlign(block);
+ uiDefIconButBitS(block, ICONTOG, OB_LOCK_SCALEX, REDRAWVIEW3D, ICON_UNLOCKED, 160,70,20,19, &(pchan->protectflag), 0, 0, 0, 0, "Protects this value from being Transformed");
+ uiDefButF(block, NUM, B_ARMATUREPANEL2, "ScaleX:", 180, 70, 120, 19, pchan->size, -lim, lim, 10, 3, "");
+ uiDefIconButBitS(block, ICONTOG, OB_LOCK_SCALEY, REDRAWVIEW3D, ICON_UNLOCKED, 160,50,20,19, &(pchan->protectflag), 0, 0, 0, 0, "Protects this value from being Transformed");
+ uiDefButF(block, NUM, B_ARMATUREPANEL2, "ScaleY:", 180, 50, 120, 19, pchan->size+1, -lim, lim, 10, 3, "");
+ uiDefIconButBitS(block, ICONTOG, OB_LOCK_SCALEZ, REDRAWVIEW3D, ICON_UNLOCKED, 160,30,20,19, &(pchan->protectflag), 0, 0, 0, 0, "Protects this value from being Transformed");
+ uiDefButF(block, NUM, B_ARMATUREPANEL2, "ScaleZ:", 180, 30, 120, 19, pchan->size+2, -lim, lim, 10, 3, "");
+ uiBlockEndAlign(block);
+}
+
+static void v3d_editarmature_buts(uiBlock *block, Object *ob, float lim)
+{
+ bArmature *arm= G.obedit->data;
+ EditBone *ebone;
+ uiBut *but;
+ TransformProperties *tfp= G.vd->properties_storage;
+
+ ebone= G.edbo.first;
+
+ for (ebone = G.edbo.first; ebone; ebone=ebone->next){
+ if ((ebone->flag & BONE_ACTIVE) && (ebone->layer & arm->layer))
+ break;
+ }
+
+ if (!ebone)
+ return;
+
+ if((ob->parent) && (ob->partype == PARBONE))
+ but= uiDefBut(block, TEX, B_DIFF, "Bone:", 160, 130, 140, 19, ebone->name, 1, 31, 0, 0, "");
+ else
+ but= uiDefBut(block, TEX, B_DIFF, "Bone:", 160, 150, 140, 19, ebone->name, 1, 31, 0, 0, "");
+ uiButSetFunc(but, validate_editbonebutton_cb, ebone, NULL);
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_ARMATUREPANEL1, "HeadX:", 10, 70, 140, 19, ebone->head, -lim, lim, 10, 3, "");
+ uiDefButF(block, NUM, B_ARMATUREPANEL1, "HeadY:", 10, 50, 140, 19, ebone->head+1, -lim, lim, 10, 3, "");
+ uiDefButF(block, NUM, B_ARMATUREPANEL1, "HeadZ:", 10, 30, 140, 19, ebone->head+2, -lim, lim, 10, 3, "");
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_ARMATUREPANEL1, "TailX:", 160, 70, 140, 19, ebone->tail, -lim, lim, 10, 3, "");
+ uiDefButF(block, NUM, B_ARMATUREPANEL1, "TailY:", 160, 50, 140, 19, ebone->tail+1, -lim, lim, 10, 3, "");
+ uiDefButF(block, NUM, B_ARMATUREPANEL1, "TailZ:", 160, 30, 140, 19, ebone->tail+2, -lim, lim, 10, 3, "");
+ uiBlockEndAlign(block);
+
+ tfp->ob_eul[0]= 180.0*ebone->roll/M_PI;
+ uiDefButF(block, NUM, B_ARMATUREPANEL1, "Roll:", 10, 100, 140, 19, tfp->ob_eul, -lim, lim, 1000, 3, "");
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_ARMATUREPANEL1, "TailRadius:", 10, 150, 140, 19, &ebone->rad_tail, 0, lim, 10, 3, "");
+ if (ebone->parent && ebone->flag & BONE_CONNECTED )
+ uiDefButF(block, NUM, B_ARMATUREPANEL1, "HeadRadius:", 10, 130, 140, 19, &ebone->parent->rad_tail, 0, lim, 10, 3, "");
+ else
+ uiDefButF(block, NUM, B_ARMATUREPANEL1, "HeadRadius:", 10, 130, 140, 19, &ebone->rad_head, 0, lim, 10, 3, "");
+ uiBlockEndAlign(block);
+}
+
+static void v3d_editmetaball_buts(uiBlock *block, Object *ob, float lim)
+{
+ extern MetaElem *lastelem;
+
+ if(lastelem) {
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_RECALCMBALL, "LocX:", 10, 70, 140, 19, &lastelem->x, -lim, lim, 100, 3, "");
+ uiDefButF(block, NUM, B_RECALCMBALL, "LocY:", 10, 50, 140, 19, &lastelem->y, -lim, lim, 100, 3, "");
+ uiDefButF(block, NUM, B_RECALCMBALL, "LocZ:", 10, 30, 140, 19, &lastelem->z, -lim, lim, 100, 3, "");
+
+ uiBlockBeginAlign(block);
+ if(lastelem->type!=MB_BALL)
+ uiDefButF(block, NUM, B_RECALCMBALL, "dx:", 160, 70, 140, 19, &lastelem->expx, 0, lim, 100, 3, "");
+ if((lastelem->type!=MB_BALL) && (lastelem->type!=MB_TUBE))
+ uiDefButF(block, NUM, B_RECALCMBALL, "dy:", 160, 50, 140, 19, &lastelem->expy, 0, lim, 100, 3, "");
+ if((lastelem->type==MB_ELIPSOID) || (lastelem->type==MB_CUBE))
+ uiDefButF(block, NUM, B_RECALCMBALL, "dz:", 160, 30, 140, 19, &lastelem->expz, 0, lim, 100, 3, "");
+
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, B_RECALCMBALL, "Radius:", 10, 120, 140, 19, &lastelem->rad, 0, lim, 100, 3, "Size of the active metaball");
+ uiDefButF(block, NUM, B_RECALCMBALL, "Stiffness:", 10, 100, 140, 19, &lastelem->s, 0, 10, 100, 3, "Stiffness of the active metaball");
+ uiBlockEndAlign(block);
+
+ uiDefButS(block, MENU, B_RECALCMBALL, "Type%t|Ball%x0|Tube%x4|Plane%x5|Elipsoid%x6|Cube%x7", 160, 120, 140, 19, &lastelem->type, 0.0, 0.0, 0, 0, "Set active element type");
+
+ }
+}
+
+void do_viewbuts(unsigned short event)
+{
+ BoundBox *bb;
+ View3D *vd;
+ Object *ob= OBACT;
+ TransformProperties *tfp= G.vd->properties_storage;
+
+ vd= G.vd;
+ if(vd==NULL) return;
+
+ switch(event) {
+
+ case B_OBJECTPANEL:
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_OB);
+ allqueue(REDRAWVIEW3D, 1);
+ break;
+
+ case B_OBJECTPANELROT:
+ if(ob) {
+ ob->rot[0]= M_PI*tfp->ob_eul[0]/180.0;
+ ob->rot[1]= M_PI*tfp->ob_eul[1]/180.0;
+ ob->rot[2]= M_PI*tfp->ob_eul[2]/180.0;
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_OB);
+ allqueue(REDRAWVIEW3D, 1);
+ }
+ break;
+
+ case B_OBJECTPANELSCALE:
+ if(ob) {
+
+ /* link scale; figure out which axis changed */
+ if (tfp->link_scale) {
+ float ratio, tmp, max = 0.0;
+ int axis;
+
+ axis = 0;
+ max = fabs(tfp->ob_scale[0] - ob->size[0]);
+ tmp = fabs(tfp->ob_scale[1] - ob->size[1]);
+ if (tmp > max) {
+ axis = 1;
+ max = tmp;
+ }
+ tmp = fabs(tfp->ob_scale[2] - ob->size[2]);
+ if (tmp > max) {
+ axis = 2;
+ max = tmp;
+ }
+
+ if (ob->size[axis] != tfp->ob_scale[axis]) {
+ if (fabs(ob->size[axis]) > FLT_EPSILON) {
+ ratio = tfp->ob_scale[axis] / ob->size[axis];
+ ob->size[0] *= ratio;
+ ob->size[1] *= ratio;
+ ob->size[2] *= ratio;
+ }
+ }
+ }
+ else {
+ VECCOPY(ob->size, tfp->ob_scale);
+
+ }
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_OB);
+ allqueue(REDRAWVIEW3D, 1);
+ }
+ break;
+
+ case B_OBJECTPANELDIMS:
+ bb= object_get_boundbox(ob);
+ if(bb) {
+ float old_dims[3], scale[3], ratio, len[3];
+ int axis;
+
+ Mat4ToSize(ob->obmat, scale);
+
+ len[0] = bb->vec[4][0] - bb->vec[0][0];
+ len[1] = bb->vec[2][1] - bb->vec[0][1];
+ len[2] = bb->vec[1][2] - bb->vec[0][2];
+
+ old_dims[0] = fabs(scale[0]) * len[0];
+ old_dims[1] = fabs(scale[1]) * len[1];
+ old_dims[2] = fabs(scale[2]) * len[2];
+
+ /* for each axis changed */
+ for (axis = 0; axis<3; axis++) {
+ if (fabs(old_dims[axis] - tfp->ob_dims[axis]) > 0.0001) {
+ if (old_dims[axis] > 0.0) {
+ ratio = tfp->ob_dims[axis] / old_dims[axis];
+ if (tfp->link_scale) {
+ ob->size[0] *= ratio;
+ ob->size[1] *= ratio;
+ ob->size[2] *= ratio;
+ break;
+ }
+ else {
+ ob->size[axis] *= ratio;
+ }
+ }
+ else {
+ if (len[axis] > 0) {
+ ob->size[axis] = tfp->ob_dims[axis] / len[axis];
+ }
+ }
+ }
+ }
+
+ /* prevent multiple B_OBJECTPANELDIMS events to keep scaling, cycling with TAB on buttons can cause that */
+ VECCOPY(tfp->ob_dims, old_dims);
+
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_OB);
+ allqueue(REDRAWVIEW3D, 1);
+ }
+ break;
+
+ case B_OBJECTPANELMEDIAN:
+ if(ob) {
+ v3d_editvertex_buts(NULL, ob, 1.0);
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 1);
+ }
+ break;
+
+ /* note; this case also used for parbone */
+ case B_OBJECTPANELPARENT:
+ if(ob) {
+ if(ob->id.lib || test_parent_loop(ob->parent, ob) )
+ ob->parent= NULL;
+ else {
+ DAG_scene_sort(G.scene);
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_OB);
+ }
+ allqueue(REDRAWVIEW3D, 1);
+ allqueue(REDRAWBUTSOBJECT, 0);
+ }
+ break;
+
+ case B_ARMATUREPANEL1:
+ {
+ bArmature *arm= G.obedit->data;
+ EditBone *ebone, *child;
+
+ for (ebone = G.edbo.first; ebone; ebone=ebone->next){
+ if ((ebone->flag & BONE_ACTIVE) && (ebone->layer & arm->layer))
+ break;
+ }
+ if (ebone) {
+ ebone->roll= M_PI*tfp->ob_eul[0]/180.0;
+ // Update our parent
+ if (ebone->parent && ebone->flag & BONE_CONNECTED){
+ VECCOPY (ebone->parent->tail, ebone->head);
+ }
+
+ // Update our children if necessary
+ for (child = G.edbo.first; child; child=child->next){
+ if (child->parent == ebone && (child->flag & BONE_CONNECTED)){
+ VECCOPY (child->head, ebone->tail);
+ }
+ }
+ if(arm->flag & ARM_MIRROR_EDIT) {
+ EditBone *eboflip= armature_bone_get_mirrored(ebone);
+ if(eboflip) {
+ eboflip->roll= -ebone->roll;
+ eboflip->head[0]= -ebone->head[0];
+ eboflip->tail[0]= -ebone->tail[0];
+
+ // Update our parent
+ if (eboflip->parent && eboflip->flag & BONE_CONNECTED){
+ VECCOPY (eboflip->parent->tail, eboflip->head);
+ }
+
+ // Update our children if necessary
+ for (child = G.edbo.first; child; child=child->next){
+ if (child->parent == eboflip && (child->flag & BONE_CONNECTED)){
+ VECCOPY (child->head, eboflip->tail);
+ }
+ }
+ }
+ }
+
+ allqueue(REDRAWVIEW3D, 1);
+ }
+ }
+ break;
+ case B_ARMATUREPANEL3: // rotate button on channel
+ {
+ bArmature *arm;
+ bPoseChannel *pchan;
+ Bone *bone;
+ float eul[3];
+
+ arm = get_armature(OBACT);
+ if (!arm || !ob->pose) return;
+
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ bone = pchan->bone;
+ if(bone && (bone->flag & BONE_ACTIVE) && (bone->layer & arm->layer))
+ break;
+ }
+ if (!pchan) return;
+
+ /* make a copy to eul[3], to allow TAB on buttons to work */
+ eul[0]= M_PI*tfp->ob_eul[0]/180.0;
+ eul[1]= M_PI*tfp->ob_eul[1]/180.0;
+ eul[2]= M_PI*tfp->ob_eul[2]/180.0;
+ EulToQuat(eul, pchan->quat);
+ }
+ /* no break, pass on */
+ case B_ARMATUREPANEL2:
+ {
+ ob->pose->flag |= (POSE_LOCKED|POSE_DO_UNLOCK);
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 1);
+ }
+ break;
+ }
+}
+
+
+static void view3d_panel_object(short cntrl) // VIEW3D_HANDLER_OBJECT
+{
+ uiBlock *block;
+ uiBut *bt;
+ Object *ob= OBACT;
+ TransformProperties *tfp;
+ float lim;
+ static char hexcol[128];
+
+ if(ob==NULL) return;
+
+ /* make sure we got storage */
+ if(G.vd->properties_storage==NULL)
+ G.vd->properties_storage= MEM_callocN(sizeof(TransformProperties), "TransformProperties");
+ tfp= G.vd->properties_storage;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_panel_object", UI_EMBOSS, UI_HELV, curarea->win);
+ uiPanelControl(UI_PNL_SOLID | UI_PNL_CLOSE | cntrl);
+ uiSetPanelHandler(VIEW3D_HANDLER_OBJECT); // for close and esc
+
+ if(!uiNewPanel(curarea, block, "Transform Properties", "View3d", 10, 230, 318, 204))
+ return;
+
+ uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
+
+ if(G.f & (G_VERTEXPAINT|G_TEXTUREPAINT|G_WEIGHTPAINT)) {
+ uiBlockSetFlag(block, UI_BLOCK_FRONTBUFFER); // force old style frontbuffer draw
+ }
+ else {
+ bt= uiDefBut(block, TEX, B_IDNAME, "OB: ", 10,180,140,20, ob->id.name+2, 0.0, 21.0, 0, 0, "");
+#ifdef WITH_VERSE
+ if(ob->vnode) uiButSetFunc(bt, test_and_send_idbutton_cb, ob, ob->id.name);
+ else uiButSetFunc(bt, test_idbutton_cb, ob->id.name, NULL);
+#else
+ uiButSetFunc(bt, test_idbutton_cb, ob->id.name, NULL);
+#endif
+
+ uiBlockBeginAlign(block);
+ uiDefIDPoinBut(block, test_obpoin_but, ID_OB, B_OBJECTPANELPARENT, "Par:", 160, 180, 140, 20, &ob->parent, "Parent Object");
+ if((ob->parent) && (ob->partype == PARBONE)) {
+ bt= uiDefBut(block, TEX, B_OBJECTPANELPARENT, "ParBone:", 160, 160, 140, 20, ob->parsubstr, 0, 30, 0, 0, "");
+ uiButSetCompleteFunc(bt, autocomplete_bone, (void *)ob->parent);
+ }
+ else {
+ strcpy(ob->parsubstr, "");
+ }
+ uiBlockEndAlign(block);
+ }
+
+ lim= 10000.0f*MAX2(1.0, G.vd->grid);
+
+ if(ob==G.obedit) {
+ if(ob->type==OB_ARMATURE) v3d_editarmature_buts(block, ob, lim);
+ if(ob->type==OB_MBALL) v3d_editmetaball_buts(block, ob, lim);
+ else v3d_editvertex_buts(block, ob, lim);
+ }
+ else if(ob->flag & OB_POSEMODE) {
+ v3d_posearmature_buts(block, ob, lim);
+ }
+ else if(G.f & G_WEIGHTPAINT) {
+ uiNewPanelTitle(block, "Weight Paint Properties");
+ weight_paint_buttons(block);
+ }
+ else if(G.f & (G_VERTEXPAINT|G_TEXTUREPAINT)) {
+ extern VPaint Gvp; /* from vpaint */
+ static float hsv[3], old[3]; // used as temp mem for picker
+ float *rgb= NULL;
+ ToolSettings *settings= G.scene->toolsettings;
+
+ if(G.f & G_VERTEXPAINT) rgb= &Gvp.r;
+ else if(settings->imapaint.brush) rgb= settings->imapaint.brush->rgb;
+
+ uiNewPanelTitle(block, "Paint Properties");
+ if (rgb)
+ /* 'f' is for floating panel */
+ uiBlockPickerButtons(block, rgb, hsv, old, hexcol, 'f', REDRAWBUTSEDIT);
+ }
+ else if(G.f & G_SCULPTMODE) {
+ uiNewPanelTitle(block, "Sculpt Properties");
+ sculptmode_draw_interface_tools(block,10,150);
+ } else {
+ BoundBox *bb = NULL;
+
+ uiBlockBeginAlign(block);
+ uiDefIconButBitS(block, ICONTOG, OB_LOCK_LOCX, REDRAWVIEW3D, ICON_UNLOCKED, 10,150,20,19, &(ob->protectflag), 0, 0, 0, 0, "Protects this value from being Transformed");
+ uiDefButF(block, NUM, B_OBJECTPANEL, "LocX:", 30, 150, 120, 19, &(ob->loc[0]), -lim, lim, 100, 3, "");
+ uiDefIconButBitS(block, ICONTOG, OB_LOCK_LOCY, REDRAWVIEW3D, ICON_UNLOCKED, 10,130,20,19, &(ob->protectflag), 0, 0, 0, 0, "Protects this value from being Transformed");
+ uiDefButF(block, NUM, B_OBJECTPANEL, "LocY:", 30, 130, 120, 19, &(ob->loc[1]), -lim, lim, 100, 3, "");
+ uiDefIconButBitS(block, ICONTOG, OB_LOCK_LOCZ, REDRAWVIEW3D, ICON_UNLOCKED, 10,110,20,19, &(ob->protectflag), 0, 0, 0, 0, "Protects this value from being Transformed");
+ uiDefButF(block, NUM, B_OBJECTPANEL, "LocZ:", 30, 110, 120, 19, &(ob->loc[2]), -lim, lim, 100, 3, "");
+
+ tfp->ob_eul[0]= 180.0*ob->rot[0]/M_PI;
+ tfp->ob_eul[1]= 180.0*ob->rot[1]/M_PI;
+ tfp->ob_eul[2]= 180.0*ob->rot[2]/M_PI;
+
+ uiBlockBeginAlign(block);
+ if ((ob->parent) && (ob->partype == PARBONE)) {
+ uiDefIconButBitS(block, ICONTOG, OB_LOCK_ROTX, REDRAWVIEW3D, ICON_UNLOCKED, 160,130,20,19, &(ob->protectflag), 0, 0, 0, 0, "Protects this value from being Transformed");
+ uiDefButF(block, NUM, B_OBJECTPANELROT, "RotX:", 180, 130, 120, 19, &(tfp->ob_eul[0]), -lim, lim, 1000, 3, "");
+ uiDefIconButBitS(block, ICONTOG, OB_LOCK_ROTY, REDRAWVIEW3D, ICON_UNLOCKED, 160,110,20,19, &(ob->protectflag), 0, 0, 0, 0, "Protects this value from being Transformed");
+ uiDefButF(block, NUM, B_OBJECTPANELROT, "RotY:", 180, 110, 120, 19, &(tfp->ob_eul[1]), -lim, lim, 1000, 3, "");
+ uiDefIconButBitS(block, ICONTOG, OB_LOCK_ROTZ, REDRAWVIEW3D, ICON_UNLOCKED, 160,90,20,19, &(ob->protectflag), 0, 0, 0, 0, "Protects this value from being Transformed");
+ uiDefButF(block, NUM, B_OBJECTPANELROT, "RotZ:", 180, 90, 120, 19, &(tfp->ob_eul[2]), -lim, lim, 1000, 3, "");
+
+ }
+ else {
+ uiDefIconButBitS(block, ICONTOG, OB_LOCK_ROTX, REDRAWVIEW3D, ICON_UNLOCKED, 160,150,20,19, &(ob->protectflag), 0, 0, 0, 0, "Protects this value from being Transformed");
+ uiDefButF(block, NUM, B_OBJECTPANELROT, "RotX:", 180, 150, 120, 19, &(tfp->ob_eul[0]), -lim, lim, 1000, 3, "");
+ uiDefIconButBitS(block, ICONTOG, OB_LOCK_ROTY, REDRAWVIEW3D, ICON_UNLOCKED, 160,130,20,19, &(ob->protectflag), 0, 0, 0, 0, "Protects this value from being Transformed");
+ uiDefButF(block, NUM, B_OBJECTPANELROT, "RotY:", 180, 130, 120, 19, &(tfp->ob_eul[1]), -lim, lim, 1000, 3, "");
+ uiDefIconButBitS(block, ICONTOG, OB_LOCK_ROTZ, REDRAWVIEW3D, ICON_UNLOCKED, 160,110,20,19, &(ob->protectflag), 0, 0, 0, 0, "Protects this value from being Transformed");
+ uiDefButF(block, NUM, B_OBJECTPANELROT, "RotZ:", 180, 110, 120, 19, &(tfp->ob_eul[2]), -lim, lim, 1000, 3, "");
+ }
+
+ tfp->ob_scale[0]= ob->size[0];
+ tfp->ob_scale[1]= ob->size[1];
+ tfp->ob_scale[2]= ob->size[2];
+
+ uiBlockBeginAlign(block);
+ uiDefIconButBitS(block, ICONTOG, OB_LOCK_SCALEX, REDRAWVIEW3D, ICON_UNLOCKED, 10,80,20,19, &(ob->protectflag), 0, 0, 0, 0, "Protects this value from being Transformed");
+ uiDefButF(block, NUM, B_OBJECTPANELSCALE, "ScaleX:", 30, 80, 120, 19, &(tfp->ob_scale[0]), -lim, lim, 10, 3, "");
+ uiDefIconButBitS(block, ICONTOG, OB_LOCK_SCALEY, REDRAWVIEW3D, ICON_UNLOCKED, 10,60,20,19, &(ob->protectflag), 0, 0, 0, 0, "Protects this value from being Transformed");
+ uiDefButF(block, NUM, B_OBJECTPANELSCALE, "ScaleY:", 30, 60, 120, 19, &(tfp->ob_scale[1]), -lim, lim, 10, 3, "");
+ uiDefIconButBitS(block, ICONTOG, OB_LOCK_SCALEZ, REDRAWVIEW3D, ICON_UNLOCKED, 10,40,20,19, &(ob->protectflag), 0, 0, 0, 0, "Protects this value from being Transformed");
+ uiDefButF(block, NUM, B_OBJECTPANELSCALE, "ScaleZ:", 30, 40, 120, 19, &(tfp->ob_scale[2]), -lim, lim, 10, 3, "");
+ uiBlockEndAlign(block);
+
+ uiDefButS(block, TOG, REDRAWVIEW3D, "Link Scale", 10, 10, 140, 19, &(tfp->link_scale), 0, 1, 0, 0, "Scale values vary proportionally in all directions");
+
+ bb= object_get_boundbox(ob);
+ if (bb) {
+ float scale[3];
+
+ Mat4ToSize(ob->obmat, scale);
+
+ tfp->ob_dims[0] = fabs(scale[0]) * (bb->vec[4][0] - bb->vec[0][0]);
+ tfp->ob_dims[1] = fabs(scale[1]) * (bb->vec[2][1] - bb->vec[0][1]);
+ tfp->ob_dims[2] = fabs(scale[2]) * (bb->vec[1][2] - bb->vec[0][2]);
+
+ uiBlockBeginAlign(block);
+ if ((ob->parent) && (ob->partype == PARBONE)) {
+ uiDefButF(block, NUM, B_OBJECTPANELDIMS, "DimX:", 160, 60, 140, 19, &(tfp->ob_dims[0]), 0.0, lim, 10, 3, "Manipulate bounding box size");
+ uiDefButF(block, NUM, B_OBJECTPANELDIMS, "DimY:", 160, 40, 140, 19, &(tfp->ob_dims[1]), 0.0, lim, 10, 3, "Manipulate bounding box size");
+ uiDefButF(block, NUM, B_OBJECTPANELDIMS, "DimZ:", 160, 20, 140, 19, &(tfp->ob_dims[2]), 0.0, lim, 10, 3, "Manipulate bounding box size");
+
+ }
+ else {
+ uiDefButF(block, NUM, B_OBJECTPANELDIMS, "DimX:", 160, 80, 140, 19, &(tfp->ob_dims[0]), 0.0, lim, 10, 3, "Manipulate bounding box size");
+ uiDefButF(block, NUM, B_OBJECTPANELDIMS, "DimY:", 160, 60, 140, 19, &(tfp->ob_dims[1]), 0.0, lim, 10, 3, "Manipulate bounding box size");
+ uiDefButF(block, NUM, B_OBJECTPANELDIMS, "DimZ:", 160, 40, 140, 19, &(tfp->ob_dims[2]), 0.0, lim, 10, 3, "Manipulate bounding box size");
+ }
+
+ uiBlockEndAlign(block);
+ }
+ }
+ uiClearButLock();
+}
+
+static void view3d_panel_background(short cntrl) // VIEW3D_HANDLER_BACKGROUND
+{
+ uiBlock *block;
+ View3D *vd;
+
+ vd= G.vd;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_panel_background", UI_EMBOSS, UI_HELV, curarea->win);
+ uiPanelControl(UI_PNL_SOLID | UI_PNL_CLOSE | cntrl);
+ uiSetPanelHandler(VIEW3D_HANDLER_BACKGROUND); // for close and esc
+ if(uiNewPanel(curarea, block, "Background Image", "View3d", 340, 10, 318, 204)==0) return;
+
+ if(G.f & G_VERTEXPAINT || G.f & G_WEIGHTPAINT || G.f & G_TEXTUREPAINT) {
+ uiBlockSetFlag(block, UI_BLOCK_FRONTBUFFER); // force old style frontbuffer draw
+ }
+
+ if(vd->flag & V3D_DISPBGPIC) {
+ if(vd->bgpic==NULL) {
+ vd->bgpic= MEM_callocN(sizeof(BGpic), "bgpic");
+ vd->bgpic->size= 5.0;
+ vd->bgpic->blend= 0.5;
+ vd->bgpic->iuser.fie_ima= 2;
+ vd->bgpic->iuser.ok= 1;
+ }
+ }
+
+ if(!(vd->flag & V3D_DISPBGPIC)) {
+ uiDefButBitS(block, TOG, V3D_DISPBGPIC, B_REDR, "Use Background Image", 10, 180, 150, 20, &vd->flag, 0, 0, 0, 0, "Display an image in the background of this 3D View");
+ uiDefBut(block, LABEL, 1, " ", 160, 180, 150, 20, NULL, 0.0, 0.0, 0, 0, "");
+ }
+ else {
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, V3D_DISPBGPIC, B_REDR, "Use", 10, 225, 50, 20, &vd->flag, 0, 0, 0, 0, "Display an image in the background of this 3D View");
+ uiDefButF(block, NUMSLI, B_REDR, "Blend:", 60, 225, 150, 20, &vd->bgpic->blend, 0.0,1.0, 0, 0, "Set the transparency of the background image");
+ uiDefButF(block, NUM, B_REDR, "Size:", 210, 225, 100, 20, &vd->bgpic->size, 0.1, 250.0*vd->grid, 100, 0, "Set the size (width) of the background image");
+
+ uiDefButF(block, NUM, B_REDR, "X Offset:", 10, 205, 150, 20, &vd->bgpic->xof, -250.0*vd->grid,250.0*vd->grid, 10, 2, "Set the horizontal offset of the background image");
+ uiDefButF(block, NUM, B_REDR, "Y Offset:", 160, 205, 150, 20, &vd->bgpic->yof, -250.0*vd->grid,250.0*vd->grid, 10, 2, "Set the vertical offset of the background image");
+
+ uiblock_image_panel(block, &vd->bgpic->ima, &vd->bgpic->iuser, B_REDR, B_REDR);
+ }
+}
+
+
+static void view3d_panel_properties(short cntrl) // VIEW3D_HANDLER_SETTINGS
+{
+ uiBlock *block;
+ View3D *vd;
+ float *curs;
+
+ vd= G.vd;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_panel_properties", UI_EMBOSS, UI_HELV, curarea->win);
+ uiPanelControl(UI_PNL_SOLID | UI_PNL_CLOSE | cntrl);
+ uiSetPanelHandler(VIEW3D_HANDLER_PROPERTIES); // for close and esc
+ if(uiNewPanel(curarea, block, "View Properties", "View3d", 340, 30, 318, 254)==0) return;
+
+ /* to force height */
+ uiNewPanelHeight(block, 264);
+
+ if(G.f & (G_VERTEXPAINT|G_FACESELECT|G_TEXTUREPAINT|G_WEIGHTPAINT)) {
+ uiBlockSetFlag(block, UI_BLOCK_FRONTBUFFER); // force old style frontbuffer draw
+ }
+
+ uiDefBut(block, LABEL, 1, "Grid:", 10, 220, 150, 19, NULL, 0.0, 0.0, 0, 0, "");
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, REDRAWVIEW3D, "Spacing:", 10, 200, 140, 19, &vd->grid, 0.001, 100.0, 10, 0, "Set the distance between grid lines");
+ uiDefButS(block, NUM, REDRAWVIEW3D, "Lines:", 10, 180, 140, 19, &vd->gridlines, 0.0, 100.0, 100, 0, "Set the number of grid lines in perspective view");
+ uiDefButS(block, NUM, REDRAWVIEW3D, "Divisions:", 10, 160, 140, 19, &vd->gridsubdiv, 1.0, 100.0, 100, 0, "Set the number of grid lines");
+ uiBlockEndAlign(block);
+
+ uiDefBut(block, LABEL, 1, "3D Display:", 160, 220, 150, 19, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefButBitS(block, TOG, V3D_SHOW_FLOOR, REDRAWVIEW3D, "Grid Floor",160, 200, 150, 19, &vd->gridflag, 0, 0, 0, 0, "Show the grid floor in free camera mode");
+ uiDefButBitS(block, TOG, V3D_SHOW_X, REDRAWVIEW3D, "X Axis", 160, 176, 48, 19, &vd->gridflag, 0, 0, 0, 0, "Show the X Axis line");
+ uiDefButBitS(block, TOG, V3D_SHOW_Y, REDRAWVIEW3D, "Y Axis", 212, 176, 48, 19, &vd->gridflag, 0, 0, 0, 0, "Show the Y Axis line");
+ uiDefButBitS(block, TOG, V3D_SHOW_Z, REDRAWVIEW3D, "Z Axis", 262, 176, 48, 19, &vd->gridflag, 0, 0, 0, 0, "Show the Z Axis line");
+
+ uiDefBut(block, LABEL, 1, "View Camera:", 10, 140, 140, 19, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefButF(block, NUM, REDRAWVIEW3D, "Lens:", 10, 120, 140, 19, &vd->lens, 10.0, 120.0, 100, 0, "The lens angle in perspective view");
+ uiBlockBeginAlign(block);
+ uiDefButF(block, NUM, REDRAWVIEW3D, "Clip Start:", 10, 96, 140, 19, &vd->near, vd->grid/100.0, 100.0, 10, 0, "Set the beginning of the range in which 3D objects are displayed (perspective view)");
+ uiDefButF(block, NUM, REDRAWVIEW3D, "Clip End:", 10, 76, 140, 19, &vd->far, 1.0, 10000.0*vd->grid, 100, 0, "Set the end of the range in which 3D objects are displayed (perspective view)");
+ uiBlockEndAlign(block);
+
+ uiDefBut(block, LABEL, 1, "3D Cursor:", 160, 150, 140, 19, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiBlockBeginAlign(block);
+ curs= give_cursor();
+ uiDefButF(block, NUM, REDRAWVIEW3D, "X:", 160, 130, 150, 22, curs, -10000.0*vd->grid, 10000.0*vd->grid, 10, 0, "X co-ordinate of the 3D cursor");
+ uiDefButF(block, NUM, REDRAWVIEW3D, "Y:", 160, 108, 150, 22, curs+1, -10000.0*vd->grid, 10000.0*vd->grid, 10, 0, "Y co-ordinate of the 3D cursor");
+ uiDefButF(block, NUM, REDRAWVIEW3D, "Z:", 160, 86, 150, 22, curs+2, -10000.0*vd->grid, 10000.0*vd->grid, 10, 0, "Z co-ordinate of the 3D cursor");
+ uiBlockEndAlign(block);
+
+ uiDefBut(block, LABEL, 1, "Display:", 10, 50, 150, 19, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, V3D_SELECT_OUTLINE, REDRAWVIEW3D, "Outline Selected", 10, 30, 140, 19, &vd->flag, 0, 0, 0, 0, "Highlight selected objects with an outline, in Solid, Shaded or Textured viewport shading modes");
+ uiDefButBitS(block, TOG, V3D_DRAW_CENTERS, REDRAWVIEW3D, "All Object Centers", 10, 10, 140, 19, &vd->flag, 0, 0, 0, 0, "Draw the center points on all objects");
+ uiDefButBitS(block, TOGN, V3D_HIDE_HELPLINES, REDRAWVIEW3D, "Relationship Lines", 10, -10, 140, 19, &vd->flag, 0, 0, 0, 0, "Draw dashed lines indicating Parent, Constraint, or Hook relationships");
+ uiDefButBitS(block, TOG, V3D_SOLID_TEX, REDRAWVIEW3D, "Solid Tex", 10, -30, 140, 19, &vd->flag2, 0, 0, 0, 0, "Display textures in Solid draw type (Shift T)");
+ uiBlockEndAlign(block);
+
+ uiDefBut(block, LABEL, 1, "View Locking:", 160, 50, 150, 19, NULL, 0.0, 0.0, 0, 0, "");
+ uiBlockBeginAlign(block);
+ uiDefIDPoinBut(block, test_obpoin_but, ID_OB, REDRAWVIEW3D, "Object:", 160, 30, 140, 19, &vd->ob_centre, "Lock view to center to this Object");
+ uiDefBut(block, TEX, REDRAWVIEW3D, "Bone:", 160, 10, 140, 19, vd->ob_centre_bone, 1, 31, 0, 0, "If view locked to Object, use this Bone to lock to view to");
+
+}
+
+static void view3d_panel_preview(ScrArea *sa, short cntrl) // VIEW3D_HANDLER_PREVIEW
+{
+ uiBlock *block;
+ View3D *v3d= sa->spacedata.first;
+ int ofsx, ofsy;
+
+ block= uiNewBlock(&sa->uiblocks, "view3d_panel_preview", UI_EMBOSS, UI_HELV, sa->win);
+ uiPanelControl(UI_PNL_SOLID | UI_PNL_CLOSE | UI_PNL_SCALE | cntrl);
+ uiSetPanelHandler(VIEW3D_HANDLER_PREVIEW); // for close and esc
+
+ ofsx= -150+(sa->winx/2)/v3d->blockscale;
+ ofsy= -100+(sa->winy/2)/v3d->blockscale;
+ if(uiNewPanel(sa, block, "Preview", "View3d", ofsx, ofsy, 300, 200)==0) return;
+
+ uiBlockSetDrawExtraFunc(block, BIF_view3d_previewdraw);
+
+ if(G.scene->recalc & SCE_PRV_CHANGED) {
+ G.scene->recalc &= ~SCE_PRV_CHANGED;
+ //printf("found recalc\n");
+ BIF_view3d_previewrender_free(sa->spacedata.first);
+ BIF_preview_changed(0);
+ }
+}
+
+
+static void view3d_blockhandlers(ScrArea *sa)
+{
+ View3D *v3d= sa->spacedata.first;
+ short a;
+
+ /* warning; blocks need to be freed each time, handlers dont remove */
+ uiFreeBlocksWin(&sa->uiblocks, sa->win);
+
+ /*uv face-sel and wp mode when mixed with wire leave depth enabled causing
+ models to draw over the UI */
+ glDisable(GL_DEPTH_TEST);
+
+ for(a=0; a<SPACE_MAXHANDLER; a+=2) {
+
+ switch(v3d->blockhandler[a]) {
+
+ case VIEW3D_HANDLER_PROPERTIES:
+ view3d_panel_properties(v3d->blockhandler[a+1]);
+ break;
+ case VIEW3D_HANDLER_BACKGROUND:
+ view3d_panel_background(v3d->blockhandler[a+1]);
+ break;
+ case VIEW3D_HANDLER_OBJECT:
+ view3d_panel_object(v3d->blockhandler[a+1]);
+ break;
+ case VIEW3D_HANDLER_PREVIEW:
+ view3d_panel_preview(sa, v3d->blockhandler[a+1]);
+ break;
+ }
+ /* clear action value for event */
+ v3d->blockhandler[a+1]= 0;
+ }
+ uiDrawBlocksPanels(sa, 0);
+
+}
+
+/* ****************** View3d afterdraw *************** */
+
+typedef struct View3DAfter {
+ struct View3DAfter *next, *prev;
+ struct Base *base;
+ int type;
+} View3DAfter;
+
+/* temp storage of Objects that need to be drawn as last */
+void add_view3d_after(View3D *v3d, Base *base, int type)
+{
+ View3DAfter *v3da= MEM_callocN(sizeof(View3DAfter), "View 3d after");
+
+ BLI_addtail(&v3d->afterdraw, v3da);
+ v3da->base= base;
+ v3da->type= type;
+}
+
+/* clears zbuffer and draws it over */
+static void view3d_draw_xray(View3D *v3d, int flag)
+{
+ View3DAfter *v3da, *next;
+ int doit= 0;
+
+ for(v3da= v3d->afterdraw.first; v3da; v3da= v3da->next)
+ if(v3da->type==V3D_XRAY) doit= 1;
+
+ if(doit) {
+ if(v3d->zbuf) glClear(GL_DEPTH_BUFFER_BIT);
+ v3d->xray= TRUE;
+
+ for(v3da= v3d->afterdraw.first; v3da; v3da= next) {
+ next= v3da->next;
+ if(v3da->type==V3D_XRAY) {
+ draw_object(v3da->base, flag);
+ BLI_remlink(&v3d->afterdraw, v3da);
+ MEM_freeN(v3da);
+ }
+ }
+ v3d->xray= FALSE;
+ }
+}
+
+/* disables write in zbuffer and draws it over */
+static void view3d_draw_transp(View3D *v3d, int flag)
+{
+ View3DAfter *v3da, *next;
+
+ glDepthMask(0);
+ v3d->transp= TRUE;
+
+ for(v3da= v3d->afterdraw.first; v3da; v3da= next) {
+ next= v3da->next;
+ if(v3da->type==V3D_TRANSP) {
+ draw_object(v3da->base, flag);
+ BLI_remlink(&v3d->afterdraw, v3da);
+ MEM_freeN(v3da);
+ }
+ }
+ v3d->transp= FALSE;
+
+ glDepthMask(1);
+
+}
+
+/* *********************** */
+
+/*
+ In most cases call draw_dupli_objects,
+ draw_dupli_objects_color was added because when drawing set dupli's
+ we need to force the color
+*/
+static void draw_dupli_objects_color(View3D *v3d, Base *base, int color)
+{
+ ListBase *lb;
+ DupliObject *dob;
+ Base tbase;
+ BoundBox *bb= NULL;
+ GLuint displist=0;
+ short transflag, use_displist= -1; /* -1 is initialize */
+ char dt, dtx;
+
+ if (base->object->restrictflag & OB_RESTRICT_VIEW) return;
+
+ /* test if we can do a displist */
+ if(base->object->transflag & OB_DUPLIGROUP)
+ use_displist= 0;
+
+ tbase.flag= OB_FROMDUPLI|base->flag;
+ lb= object_duplilist(G.scene, base->object);
+
+ for(dob= lb->first; dob; dob= dob->next) {
+ if(dob->no_draw);
+ else {
+ tbase.object= dob->ob;
+
+ /* extra service: draw the duplicator in drawtype of parent */
+ dt= tbase.object->dt; tbase.object->dt= base->object->dt;
+ dtx= tbase.object->dtx; tbase.object->dtx= base->object->dtx;
+
+ /* negative scale flag has to propagate */
+ transflag= tbase.object->transflag;
+ if(base->object->transflag & OB_NEG_SCALE)
+ tbase.object->transflag ^= OB_NEG_SCALE;
+
+ BIF_ThemeColorBlend(color, TH_BACK, 0.5);
+
+ /* generate displist, test for new object */
+ if(use_displist==1 && dob->prev && dob->prev->ob!=dob->ob) {
+ use_displist= -1;
+ glDeleteLists(displist, 1);
+ }
+ /* generate displist */
+ if(use_displist == -1) {
+
+ /* lamp drawing messes with matrices, could be handled smarter... but this works */
+ if(dob->ob->type==OB_LAMP)
+ use_displist= 0;
+ else {
+ /* disable boundbox check for list creation */
+ object_boundbox_flag(dob->ob, OB_BB_DISABLED, 1);
+ /* need this for next part of code */
+ bb= object_get_boundbox(dob->ob);
+
+ Mat4One(dob->ob->obmat); /* obmat gets restored */
+
+ displist= glGenLists(1);
+ glNewList(displist, GL_COMPILE);
+ draw_object(&tbase, DRAW_CONSTCOLOR);
+ glEndList();
+
+ use_displist= 1;
+ object_boundbox_flag(dob->ob, OB_BB_DISABLED, 0);
+ }
+ }
+ if(use_displist) {
+ mymultmatrix(dob->mat);
+ if(boundbox_clip(dob->mat, bb))
+ glCallList(displist);
+ myloadmatrix(G.vd->viewmat);
+ }
+ else {
+ Mat4CpyMat4(dob->ob->obmat, dob->mat);
+ draw_object(&tbase, DRAW_CONSTCOLOR);
+ }
+
+ tbase.object->dt= dt;
+ tbase.object->dtx= dtx;
+ tbase.object->transflag= transflag;
+ }
+ }
+
+ /* Transp afterdraw disabled, afterdraw only stores base pointers, and duplis can be same obj */
+
+ free_object_duplilist(lb); /* does restore */
+
+ if(use_displist)
+ glDeleteLists(displist, 1);
+}
+
+static void draw_dupli_objects(View3D *v3d, Base *base)
+{
+ /* define the color here so draw_dupli_objects_color can be called
+ * from the set loop */
+
+ int color= (base->flag & SELECT)?TH_SELECT:TH_WIRE;
+ /* debug */
+ if(base->object->dup_group && base->object->dup_group->id.us<1)
+ color= TH_REDALERT;
+
+ draw_dupli_objects_color(v3d, base, color);
+}
+
+void view3d_update_depths(View3D *v3d)
+{
+ /* Create storage for, and, if necessary, copy depth buffer */
+ if(!v3d->depths) v3d->depths= MEM_callocN(sizeof(ViewDepths),"ViewDepths");
+ if(v3d->depths) {
+ ViewDepths *d= v3d->depths;
+ if(d->w != v3d->area->winx ||
+ d->h != v3d->area->winy ||
+ !d->depths) {
+ d->w= v3d->area->winx;
+ d->h= v3d->area->winy;
+ if(d->depths)
+ MEM_freeN(d->depths);
+ d->depths= MEM_mallocN(sizeof(float)*d->w*d->h,"View depths");
+ d->damaged= 1;
+ }
+
+ if(d->damaged) {
+ glReadPixels(v3d->area->winrct.xmin,v3d->area->winrct.ymin,d->w,d->h,
+ GL_DEPTH_COMPONENT,GL_FLOAT, d->depths);
+
+ glGetDoublev(GL_DEPTH_RANGE,d->depth_range);
+
+ d->damaged= 0;
+ }
+ }
+}
+
+void drawview3dspace(ScrArea *sa, void *spacedata)
+{
+ View3D *v3d= spacedata;
+ Base *base;
+ Object *ob;
+ Scene *sce;
+ char retopo, sculpt;
+ Object *obact = OBACT;
+
+ /* update all objects, ipos, matrices, displists, etc. Flags set by depgraph or manual,
+ no layer check here, gets correct flushed */
+ /* sets first, we allow per definition current scene to have dependencies on sets */
+ if(G.scene->set) {
+ for(SETLOOPER(G.scene->set, base))
+ object_handle_update(base->object); // bke_object.h
+ }
+ for(base= G.scene->base.first; base; base= base->next)
+ object_handle_update(base->object); // bke_object.h
+
+ setwinmatrixview3d(sa->winx, sa->winy, NULL); /* 0= no pick rect */
+ setviewmatrixview3d(); /* note: calls where_is_object for camera... */
+
+ Mat4MulMat4(v3d->persmat, v3d->viewmat, sa->winmat);
+ Mat4Invert(v3d->persinv, v3d->persmat);
+ Mat4Invert(v3d->viewinv, v3d->viewmat);
+
+ /* calculate pixelsize factor once, is used for lamps and obcenters */
+ {
+ float len1, len2, vec[3];
+
+ VECCOPY(vec, v3d->persinv[0]);
+ len1= Normalize(vec);
+ VECCOPY(vec, v3d->persinv[1]);
+ len2= Normalize(vec);
+
+ v3d->pixsize= 2.0f*(len1>len2?len1:len2);
+
+ /* correct for window size */
+ if(sa->winx > sa->winy) v3d->pixsize/= (float)sa->winx;
+ else v3d->pixsize/= (float)sa->winy;
+ }
+
+ if(v3d->drawtype > OB_WIRE) {
+ if(G.f & G_SIMULATION)
+ glClearColor(0.0, 0.0, 0.0, 0.0);
+ else {
+ float col[3];
+ BIF_GetThemeColor3fv(TH_BACK, col);
+ glClearColor(col[0], col[1], col[2], 0.0);
+ }
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glLoadIdentity();
+ }
+ else {
+ float col[3];
+ BIF_GetThemeColor3fv(TH_BACK, col);
+ glClearColor(col[0], col[1], col[2], 0.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ }
+
+ myloadmatrix(v3d->viewmat);
+ persp(PERSP_STORE); // store correct view for persp(PERSP_VIEW) calls
+
+ if(v3d->flag & V3D_CLIPPING)
+ view3d_draw_clipping(v3d);
+
+ /* set zbuffer after we draw clipping region */
+ if(v3d->drawtype > OB_WIRE) {
+ v3d->zbuf= TRUE;
+ glEnable(GL_DEPTH_TEST);
+ }
+
+ // needs to be done always, gridview is adjusted in drawgrid() now
+ v3d->gridview= v3d->grid;
+
+ if(v3d->view==0 || v3d->persp!=0) {
+ drawfloor();
+ if(v3d->persp==2) {
+ if(G.scene->world) {
+ if(G.scene->world->mode & WO_STARS) {
+ RE_make_stars(NULL, star_stuff_init_func, star_stuff_vertex_func,
+ star_stuff_term_func);
+ }
+ }
+ if(v3d->flag & V3D_DISPBGPIC) draw_bgpic();
+ }
+ }
+ else {
+ drawgrid();
+
+ if(v3d->flag & V3D_DISPBGPIC) {
+ draw_bgpic();
+ }
+ }
+
+ if(v3d->flag & V3D_CLIPPING)
+ view3d_set_clipping(v3d);
+
+ /* draw set first */
+ if(G.scene->set) {
+ for(SETLOOPER(G.scene->set, base)) {
+
+ if(v3d->lay & base->lay) {
+
+ BIF_ThemeColorBlend(TH_WIRE, TH_BACK, 0.6f);
+ draw_object(base, DRAW_CONSTCOLOR);
+
+ if(base->object->transflag & OB_DUPLI) {
+ draw_dupli_objects_color(v3d, base, TH_WIRE);
+ }
+ }
+ }
+
+ /* Transp and X-ray afterdraw stuff */
+ view3d_draw_xray(v3d, DRAW_CONSTCOLOR); // clears zbuffer if it is used!
+ view3d_draw_transp(v3d, DRAW_CONSTCOLOR);
+ }
+
+ /* then draw not selected and the duplis, but skip editmode object */
+ for(base= G.scene->base.first; base; base= base->next) {
+ if(v3d->lay & base->lay) {
+
+ /* dupli drawing */
+ if(base->object->transflag & OB_DUPLI) {
+ draw_dupli_objects(v3d, base);
+ }
+ if((base->flag & SELECT)==0) {
+ if(base->object!=G.obedit) draw_object(base, 0);
+ }
+ }
+ }
+
+ retopo= retopo_mesh_check() || retopo_curve_check();
+ sculpt= (G.f & G_SCULPTMODE) && !G.obedit;
+ if(retopo)
+ view3d_update_depths(v3d);
+
+ /* draw selected and editmode */
+ for(base= G.scene->base.first; base; base= base->next) {
+ if(v3d->lay & base->lay) {
+ if (base->object==G.obedit || ( base->flag & SELECT) )
+ draw_object(base, 0);
+ }
+ }
+
+ if(!retopo && sculpt && !(obact && (obact->dtx & OB_DRAWXRAY)))
+ view3d_update_depths(v3d);
+
+ if(G.moving) {
+ BIF_drawConstraint();
+ if(G.obedit) BIF_drawPropCircle(); // only editmode has proportional edit
+ BIF_drawSnap();
+ }
+
+ if(G.scene->radio) RAD_drawall(v3d->drawtype>=OB_SOLID);
+
+ /* Transp and X-ray afterdraw stuff */
+ view3d_draw_xray(v3d, 0); // clears zbuffer if it is used!
+ view3d_draw_transp(v3d, 0);
+
+ if(!retopo && sculpt && (obact && (OBACT->dtx & OB_DRAWXRAY)))
+ view3d_update_depths(v3d);
+
+ if(v3d->flag & V3D_CLIPPING)
+ view3d_clr_clipping();
+
+ BIF_draw_manipulator(sa);
+
+ if(v3d->zbuf) {
+ v3d->zbuf= FALSE;
+ glDisable(GL_DEPTH_TEST);
+ }
+
+ persp(PERSP_WIN); // set ortho
+
+ /* Draw Sculpt Mode brush */
+ if(!G.obedit && (G.f & G_SCULPTMODE) && area_is_active_area(v3d->area) && sculpt_session()) {
+ PropsetData *pd= sculpt_session()->propset;
+ short r1=100, r2=100, r3=100;
+ short mouse[2];
+
+ if(sculpt_data()->flags & SCULPT_INPUT_SMOOTH)
+ sculpt_stroke_draw();
+
+ if(pd) {
+ if(pd->mode == PropsetSize) {
+ r1= sculptmode_brush()->size;
+ r2= pd->origsize;
+ r3= r1;
+ } else if(pd->mode == PropsetStrength) {
+ r1= 200 - sculptmode_brush()->strength * 2;
+ r2= 200;
+ r3= 200;
+ } else if(pd->mode == PropsetTexRot) {
+ r1= r2= 200;
+ r3= 200;
+ }
+
+ /* Draw brush with texture */
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ glBindTexture(GL_TEXTURE_2D, pd->tex);
+
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ glPushMatrix();
+ glTranslatef(pd->origloc[0], pd->origloc[1], 0);
+ glRotatef(tex_angle(), 0, 0, 1);
+
+ glEnable(GL_TEXTURE_2D);
+ glBegin(GL_QUADS);
+ glColor4f(0,0,0,1);
+ glTexCoord2f(0,0);
+ glVertex2f(-r3, -r3);
+ glTexCoord2f(1,0);
+ glVertex2f(r3, -r3);
+ glTexCoord2f(1,1);
+ glVertex2f(r3, r3);
+ glTexCoord2f(0,1);
+ glVertex2f(-r3, r3);
+ glEnd();
+ glDisable(GL_TEXTURE_2D);
+
+ glPopMatrix();
+
+ if(r1 != r2)
+ fdrawXORcirc(pd->origloc[0], pd->origloc[1], r1);
+ fdrawXORcirc(pd->origloc[0], pd->origloc[1], r2);
+
+ if(pd->mode == PropsetTexRot) {
+ const float ang= pd->origtexrot * (M_PI/180.0f);
+ getmouseco_areawin(mouse);
+ sdrawXORline(pd->origloc[0], pd->origloc[1],
+ pd->origloc[0]+200*cos(ang), pd->origloc[1]+200*sin(ang));
+ sdrawXORline(pd->origloc[0], pd->origloc[1], mouse[0], mouse[1]);
+ }
+ }
+ else if(sculpt_data()->flags & SCULPT_DRAW_BRUSH) {
+ short csc[2], car[2];
+ getmouseco_sc(csc);
+ getmouseco_areawin(car);
+ if(csc[0] > v3d->area->winrct.xmin &&
+ csc[1] > v3d->area->winrct.ymin &&
+ csc[0] < v3d->area->winrct.xmax &&
+ csc[1] < v3d->area->winrct.ymax)
+ fdrawXORcirc((float)car[0], (float)car[1], sculptmode_brush()->size);
+ }
+ }
+ retopo_draw_paint_lines();
+
+ if(v3d->persp>1) drawviewborder();
+ if(v3d->flag2 & V3D_FLYMODE) drawviewborder_flymode();
+ if(!(G.f & G_PLAYANIM)) drawcursor(v3d);
+ if(U.uiflag & USER_SHOW_ROTVIEWICON)
+ draw_view_axis();
+ else
+ draw_view_icon();
+ if(U.uiflag & USER_SHOW_VIEWPORTNAME)
+ draw_viewport_name(sa);
+
+ ob= OBACT;
+ if(ob && (U.uiflag & USER_DRAWVIEWINFO))
+ draw_selected_name(ob);
+
+ draw_area_emboss(sa);
+
+ /* it is important to end a view in a transform compatible with buttons */
+
+ bwin_scalematrix(sa->win, v3d->blockscale, v3d->blockscale, v3d->blockscale);
+ view3d_blockhandlers(sa);
+
+ sa->win_swap= WIN_BACK_OK;
+
+ if(G.f & G_VERTEXPAINT || G.f & G_WEIGHTPAINT || G.f & G_TEXTUREPAINT) {
+ v3d->flag |= V3D_NEEDBACKBUFDRAW;
+ addafterqueue(sa->win, BACKBUFDRAW, 1);
+ }
+ // test for backbuf select
+ if(G.obedit && v3d->drawtype>OB_WIRE && (v3d->flag & V3D_ZBUF_SELECT)) {
+ extern int afterqtest(short win, unsigned short evt); //editscreen.c
+
+ v3d->flag |= V3D_NEEDBACKBUFDRAW;
+ if(afterqtest(sa->win, BACKBUFDRAW)==0) {
+ addafterqueue(sa->win, BACKBUFDRAW, 1);
+ }
+ }
+
+ /* run any view3d draw handler script links */
+ if (sa->scriptlink.totscript)
+ BPY_do_spacehandlers(sa, 0, SPACEHANDLER_VIEW3D_DRAW);
+
+ /* run scene redraw script links */
+ if((G.f & G_DOSCRIPTLINKS) && G.scene->scriptlink.totscript &&
+ !during_script()) {
+ BPY_do_pyscript((ID *)G.scene, SCRIPT_REDRAW);
+ }
+
+}
+
+
+void drawview3d_render(struct View3D *v3d, int winx, int winy)
+{
+ Base *base;
+ Scene *sce;
+ float winmat[4][4];
+
+ update_for_newframe_muted(); /* first, since camera can be animated */
+
+ setwinmatrixview3d(winx, winy, NULL);
+
+ setviewmatrixview3d();
+ myloadmatrix(v3d->viewmat);
+ glMatrixMode(GL_PROJECTION);
+ mygetmatrix(winmat);
+ glMatrixMode(GL_MODELVIEW);
+ Mat4MulMat4(v3d->persmat, v3d->viewmat, winmat);
+ Mat4Invert(v3d->persinv, v3d->persmat);
+ Mat4Invert(v3d->viewinv, v3d->viewmat);
+
+ free_all_realtime_images();
+ reshadeall_displist();
+
+ if(v3d->drawtype > OB_WIRE) {
+ v3d->zbuf= TRUE;
+ glEnable(GL_DEPTH_TEST);
+ }
+
+ if(v3d->flag & V3D_CLIPPING)
+ view3d_set_clipping(v3d);
+
+ if (v3d->drawtype==OB_TEXTURE && G.scene->world) {
+ glClearColor(G.scene->world->horr, G.scene->world->horg, G.scene->world->horb, 0.0);
+ } else {
+ float col[3];
+ BIF_GetThemeColor3fv(TH_BACK, col);
+ glClearColor(col[0], col[1], col[2], 0.0);
+ }
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ /* abuse! to make sure it doesnt draw the helpstuff */
+ G.f |= G_SIMULATION;
+
+ /* first draw set */
+ if(G.scene->set) {
+
+ for(SETLOOPER(G.scene->set, base)) {
+ if(v3d->lay & base->lay) {
+ if ELEM3(base->object->type, OB_LAMP, OB_CAMERA, OB_LATTICE);
+ else {
+ where_is_object(base->object);
+
+ BIF_ThemeColorBlend(TH_WIRE, TH_BACK, 0.6f);
+ draw_object(base, DRAW_CONSTCOLOR);
+
+ if(base->object->transflag & OB_DUPLI) {
+ draw_dupli_objects(v3d, base);
+ }
+ }
+ }
+ }
+
+ /* Transp and X-ray afterdraw stuff */
+ view3d_draw_xray(v3d, DRAW_CONSTCOLOR); // clears zbuffer if it is used!
+ view3d_draw_transp(v3d, DRAW_CONSTCOLOR);
+ }
+
+ /* first not selected and duplis */
+ base= G.scene->base.first;
+ while(base) {
+
+ if(v3d->lay & base->lay) {
+ if ELEM3(base->object->type, OB_LAMP, OB_CAMERA, OB_LATTICE);
+ else {
+
+ if(base->object->transflag & OB_DUPLI) {
+ draw_dupli_objects(v3d, base);
+ }
+ else if((base->flag & SELECT)==0) {
+ draw_object(base, 0);
+ }
+ }
+ }
+
+ base= base->next;
+ }
+
+ /* draw selected */
+ base= G.scene->base.first;
+ while(base) {
+
+ if ( ((base)->flag & SELECT) && ((base)->lay & v3d->lay) ) {
+ if ELEM3(base->object->type, OB_LAMP, OB_CAMERA, OB_LATTICE);
+ else draw_object(base, 0);
+ }
+
+ base= base->next;
+ }
+
+ if(G.scene->radio) RAD_drawall(v3d->drawtype>=OB_SOLID);
+
+ /* Transp and X-ray afterdraw stuff */
+ view3d_draw_xray(v3d, 0); // clears zbuffer if it is used!
+ view3d_draw_transp(v3d, 0);
+
+ if(v3d->flag & V3D_CLIPPING)
+ view3d_clr_clipping();
+
+ if(v3d->zbuf) {
+ v3d->zbuf= FALSE;
+ glDisable(GL_DEPTH_TEST);
+ }
+
+ G.f &= ~G_SIMULATION;
+
+ glFlush();
+
+ glLoadIdentity();
+
+ free_all_realtime_images();
+}
+
+
+double tottime = 0.0;
+static ScrArea *oldsa;
+static double swaptime;
+static int curmode;
+
+int update_time(void)
+{
+ static double ltime;
+ double time;
+
+ if ((U.mixbufsize)
+ && (audiostream_pos() != CFRA)
+ && (G.scene->audio.flag & AUDIO_SYNC)) {
+ return 0;
+ }
+
+ time = PIL_check_seconds_timer();
+
+ tottime += (time - ltime);
+ ltime = time;
+ return (tottime < 0.0);
+}
+
+static void inner_play_prefetch_frame(int mode, int cfra)
+{
+ ScrArea *sa;
+ int oldcfra = CFRA;
+ ScrArea *oldcurarea = curarea;
+
+ if (!U.prefetchframes) {
+ return;
+ }
+
+ CFRA = cfra;
+
+ sa= G.curscreen->areabase.first;
+ while(sa) {
+ if(sa==oldsa) {
+ scrarea_do_winprefetchdraw(sa);
+ }
+ else if(mode & 1) { /* all view3d and seq spaces */
+ if ELEM(sa->spacetype, SPACE_VIEW3D, SPACE_SEQ) {
+ scrarea_do_winprefetchdraw(sa);
+ }
+ }
+ else if(mode & 4) { /* all seq spaces */
+ if (sa->spacetype == SPACE_SEQ) {
+ scrarea_do_winprefetchdraw(sa);
+ }
+ }
+
+ sa= sa->next;
+ }
+
+ CFRA = oldcfra;
+ curarea = oldcurarea;
+}
+
+static void inner_play_prefetch_startup(int mode)
+{
+ int i;
+
+ if (!U.prefetchframes) {
+ return;
+ }
+
+ seq_start_threads();
+
+ for (i = 0; i <= U.prefetchframes; i++) {
+ int cfra = CFRA + i;
+ inner_play_prefetch_frame(mode, cfra);
+ }
+
+ seq_wait_for_prefetch_ready();
+}
+
+static void inner_play_prefetch_shutdown(int mode)
+{
+ if (!U.prefetchframes) {
+ return;
+ }
+ seq_stop_threads();
+}
+
+void inner_play_anim_loop(int init, int mode)
+{
+ ScrArea *sa;
+ static int last_cfra = -1;
+
+ /* init */
+ if(init) {
+ oldsa= curarea;
+ swaptime= 1.0/FPS;
+ tottime= 0.0;
+ curmode= mode;
+ last_cfra = -1;
+
+ return;
+ }
+
+ if (CFRA != last_cfra) {
+ int pf;
+ set_timecursor(CFRA);
+
+ update_for_newframe_nodraw(1); /* adds no events in UI */
+
+ sa= G.curscreen->areabase.first;
+ while(sa) {
+ if(sa==oldsa) {
+ scrarea_do_windraw(sa);
+ }
+ else if(curmode & 1) { /* all view3d and seq spaces */
+ if ELEM(sa->spacetype, SPACE_VIEW3D, SPACE_SEQ) {
+ scrarea_do_windraw(sa);
+ }
+ }
+ else if(curmode & 4) { /* all seq spaces */
+ if (sa->spacetype == SPACE_SEQ) {
+ scrarea_do_windraw(sa);
+ }
+ }
+
+ sa= sa->next;
+ }
+
+ if (last_cfra == -1) {
+ last_cfra = CFRA - 1;
+ }
+
+ if (U.prefetchframes) {
+ pf = last_cfra;
+
+ if (CFRA - last_cfra >= U.prefetchframes ||
+ CFRA - last_cfra < 0) {
+ pf = CFRA - U.prefetchframes;
+ fprintf(stderr,
+ "SEQ-THREAD: Lost sync, "
+ "stopping threads, "
+ "back to skip mode...\n");
+ seq_stop_threads();
+ } else {
+ while (pf < CFRA) {
+ int c;
+ pf++;
+ c = pf + U.prefetchframes;
+ if (c >= PEFRA) {
+ c -= PEFRA;
+ c += PSFRA;
+ }
+
+ inner_play_prefetch_frame(curmode, c);
+ }
+ }
+
+ }
+ }
+
+ last_cfra = CFRA;
+
+ /* make sure that swaptime passed by */
+ tottime -= swaptime;
+ while (update_time()) {
+ PIL_sleep_ms(1);
+ }
+
+ if (CFRA >= PEFRA) {
+ if (tottime > 0.0) {
+ tottime = 0.0;
+ }
+ CFRA = PSFRA;
+ audiostream_stop();
+ audiostream_start( CFRA );
+ } else {
+ if (U.mixbufsize
+ && (G.scene->audio.flag & AUDIO_SYNC)) {
+ CFRA = audiostream_pos();
+ } else {
+ CFRA++;
+ }
+ if (CFRA < last_cfra) {
+ fprintf(stderr,
+ "SEQ-THREAD: CFRA running backwards: %d\n",
+ CFRA);
+ }
+ }
+
+}
+
+/* play_anim: 'mode' defines where to play and if repeat is on (now bitfield):
+ * - mode & 1 : All view3d and seq areas
+ * - mode & 2 : No replay
+ * - mode & 4 : All seq areas
+ */
+int play_anim(int mode)
+{
+ ScrArea *sa, *oldsa;
+ int cfraont;
+ unsigned short event=0;
+ short val;
+
+ /* patch for very very old scenes */
+ if(SFRA==0) SFRA= 1;
+ if(EFRA==0) EFRA= 250;
+
+ if(PSFRA>PEFRA) return 0;
+
+ /* waitcursor(1); */
+ G.f |= G_PLAYANIM; /* in sequence.c and view.c this is handled */
+
+ cfraont= CFRA;
+ oldsa= curarea;
+
+ if (curarea && curarea->spacetype == SPACE_SEQ) {
+ SpaceSeq *sseq = curarea->spacedata.first;
+ if (sseq->mainb == 0) mode |= 4;
+ }
+
+ inner_play_prefetch_startup(mode);
+
+ update_time();
+
+ inner_play_anim_loop(1, mode); /* 1==init */
+
+ audiostream_start( CFRA );
+
+ /* forces all buffers to be OK for current frame (otherwise other windows get redrawn with CFRA+1) */
+ curarea->win_swap= WIN_BACK_OK;
+ screen_swapbuffers();
+
+ while(TRUE) {
+
+ while(qtest()) {
+
+ /* we test events first because of MKEY event */
+
+ event= extern_qread(&val);
+ if(event==ESCKEY) break;
+ else if(event==MIDDLEMOUSE) {
+ if(U.flag & USER_VIEWMOVE) {
+ if(G.qual & LR_SHIFTKEY) viewmove(0);
+ else if(G.qual & LR_CTRLKEY) viewmove(2);
+ else viewmove(1);
+ }
+ else {
+ if(G.qual & LR_SHIFTKEY) viewmove(1);
+ else if(G.qual & LR_CTRLKEY) viewmove(2);
+ else viewmove(0);
+ }
+ }
+ else if(event==MKEY) {
+ if(val) add_marker(CFRA-1);
+ }
+ }
+ if(ELEM3(event, ESCKEY, SPACEKEY, RIGHTMOUSE)) break;
+
+ inner_play_anim_loop(0, 0);
+ screen_swapbuffers();
+
+ if((mode & 2) && CFRA==PEFRA) break; /* no replay */
+ }
+
+ if(event==SPACEKEY);
+ else CFRA= cfraont;
+
+ inner_play_prefetch_shutdown(mode);
+ audiostream_stop();
+
+ if(oldsa!=curarea) areawinset(oldsa->win);
+
+ /* restore all areas */
+ sa= G.curscreen->areabase.first;
+ while(sa) {
+ if( ((mode & 1) && sa->spacetype==SPACE_VIEW3D) || sa==curarea) addqueue(sa->win, REDRAW, 1);
+ sa= sa->next;
+ }
+
+ /* groups could have changed ipo */
+ allspace(REMAKEIPO, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWNLA, 0);
+ allqueue (REDRAWACTION, 0);
+
+ /* restore for cfra */
+ update_for_newframe_muted();
+
+ waitcursor(0);
+ G.f &= ~G_PLAYANIM;
+
+ if (event==ESCKEY || event==SPACEKEY) return 1;
+ else return 0;
+}
diff --git a/source/blender/src/edit.c b/source/blender/src/edit.c
new file mode 100644
index 00000000000..7d784dcecfd
--- /dev/null
+++ b/source/blender/src/edit.c
@@ -0,0 +1,1889 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <math.h>
+#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef WIN32
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "BMF_Api.h"
+
+#include "PIL_time.h"
+
+#include "DNA_action_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_userdef_types.h" /* for U.dupflag */
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_editVert.h"
+#include "BLI_linklist.h"
+
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_anim.h"
+#include "BKE_curve.h"
+#include "BKE_depsgraph.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_displist.h"
+#include "BKE_global.h"
+#include "BKE_ipo.h"
+#include "BKE_lattice.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+#include "BKE_utildefines.h"
+
+#ifdef WITH_VERSE
+#include "BKE_verse.h"
+#endif
+
+#include "BIF_editmesh.h"
+#include "BIF_editview.h"
+#include "BIF_editarmature.h"
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+#include "BIF_interface.h"
+#include "BIF_mywindow.h"
+#include "BIF_resources.h"
+#include "BIF_space.h"
+#include "BIF_screen.h"
+#include "BIF_toolbox.h"
+
+#ifdef WITH_VERSE
+#include "BIF_verse.h"
+#endif
+
+#include "BSE_edit.h"
+#include "BSE_drawipo.h"
+#include "BSE_drawview.h"
+#include "BSE_trans_types.h"
+#include "BSE_view.h"
+
+#include "BDR_editobject.h"
+#include "BDR_editmball.h"
+#include "BDR_editcurve.h"
+
+/* old stuff */
+#include "blendef.h"
+#include "mydevice.h"
+
+/*#include "armature.h"*/
+/* #include "edit.h" */
+#include "nla.h"
+#include "transform.h"
+
+#ifdef __NLA
+#include "BIF_editarmature.h"
+#endif
+
+
+/* circle selection callback */
+typedef void (*select_CBfunc)(short selecting, Object *editobj, short *mval, float rad);
+
+extern void obedit_selectionCB(short selecting, Object *editobj,
+ short *mval, float rad);
+extern void uvedit_selectionCB(short selecting, Object *editobj,
+ short *mval, float rad);
+
+void circle_selectCB(select_CBfunc func);
+
+/* local protos ---------------*/
+void snap_curs_to_firstsel(void);
+
+/* flag==2 only border, flag==3 cross+border
+ flag==5 cross + border + start&end frame
+ */
+int get_border(rcti *rect, short flag)
+{
+ float dvec[4], fac1, fac2;
+ int retval=1;
+ unsigned short event= 0;
+ short mval[2], mvalo[4], val, x1, y1;
+ char str[64];
+
+ mywinset(G.curscreen->mainwin);
+
+ /* slightly larger, 1 pixel at the edge */
+ glReadBuffer(GL_FRONT);
+ glDrawBuffer(GL_FRONT);
+
+ /* removed my_get_frontbuffer, this crashes when it gets a part outside the screen */
+ /* solved it with just a redraw! */
+
+ mywinset(curarea->win);
+
+ glDrawBuffer(GL_FRONT);
+ persp(PERSP_WIN);
+ initgrabz(0.0, 0.0, 0.0);
+
+ if(flag & 1) {
+ getmouseco_areawin(mvalo);
+
+ /* draws the selection initial cross */
+ sdrawXORline4(0, 0, mvalo[1], curarea->winx, mvalo[1]);
+ sdrawXORline4(1, mvalo[0], 0, mvalo[0], curarea->winy);
+ bglFlush();
+
+ while(TRUE) {
+
+ /* selection loop while mouse pressed */
+ getmouseco_areawin(mval);
+
+ if(mvalo[0]!=mval[0] || mvalo[1]!=mval[1]) {
+
+ /* aiming cross */
+ sdrawXORline4(0, 0, mval[1], curarea->winx, mval[1]);
+ sdrawXORline4(1, mval[0], 0, mval[0], curarea->winy);
+ bglFlush();
+
+ mvalo[0]= mval[0];
+ mvalo[1]= mval[1];
+ }
+ event= extern_qread(&val);
+
+ if(event && val) {
+
+ /* for when a renderwindow is open, and a mouse cursor activates it */
+ persp(PERSP_VIEW);
+ mywinset(curarea->win);
+ persp(PERSP_WIN);
+
+ if(event==ESCKEY) {
+ retval= 0;
+ break;
+ }
+ else if(event==BKEY) {
+ /* b has been pressed twice: proceed with circle select */
+ retval= 0;
+ break;
+ }
+ else if(event==LEFTMOUSE) break;
+ else if(event==MIDDLEMOUSE) break;
+ else if(event==RIGHTMOUSE) break;
+ }
+ else PIL_sleep_ms(10);
+
+ } /* end while (TRUE) */
+
+ /* erase XORed lines */
+ sdrawXORline4(-1, 0, 0, 0, 0);
+ }
+ else getmouseco_areawin(mval);
+
+ if(retval) {
+ /* box select */
+ x1= mval[0];
+ y1= mval[1];
+
+ getmouseco_areawin(mvalo);
+
+ sdrawXORline4(0, x1, y1, x1, mvalo[1]);
+ sdrawXORline4(1, x1, mvalo[1], mvalo[0], mvalo[1]);
+ sdrawXORline4(2, mvalo[0], mvalo[1], mvalo[0], y1);
+ sdrawXORline4(3, mvalo[0], y1, x1, y1);
+ bglFlush();
+
+ while(TRUE) {
+ getmouseco_areawin(mval);
+ if(mvalo[0]!=mval[0] || mvalo[1]!=mval[1]) {
+
+ sdrawXORline4(0, x1, y1, x1, mval[1]);
+ sdrawXORline4(1, x1, mval[1], mval[0], mval[1]);
+ sdrawXORline4(2, mval[0], mval[1], mval[0], y1);
+ sdrawXORline4(3, mval[0], y1, x1, y1);
+
+ /* draw size information in corner */
+ if(curarea->spacetype==SPACE_VIEW3D) {
+ BIF_ThemeColor(TH_BACK);
+ glRecti(10, 25, 250, 40);
+
+ if(G.vd->persp==0) {
+ window_to_3d(dvec, mvalo[0]-x1, mvalo[1]-y1);
+
+ sprintf(str, "X %.4f Y %.4f Z %.4f Dia %.4f", dvec[0], dvec[1], dvec[2], sqrt(dvec[0]*dvec[0]+dvec[1]*dvec[1]+dvec[2]*dvec[2]));
+ glColor3f(0.0, 0.0, 0.0);
+ glRasterPos2i(15, 27);
+ BMF_DrawString(G.fonts, str);
+ glColor3f(0.7, 0.7, 0.7);
+ glRasterPos2i(16, 28);
+ BMF_DrawString(G.fonts, str);
+ }
+ else if(G.vd->persp==2) {
+ rctf vb;
+
+ calc_viewborder(G.vd, &vb);
+
+ fac1= (mvalo[0]-x1)/( (float) (vb.xmax-vb.xmin) );
+ fac1*= 0.01*G.scene->r.size*G.scene->r.xsch;
+
+ fac2= (mvalo[1]-y1)/( (float) (vb.ymax-vb.ymin) );
+ fac2*= 0.01*G.scene->r.size*G.scene->r.ysch;
+
+ sprintf(str, "X %.1f Y %.1f Dia %.1f", fabs(fac1), fabs(fac2), sqrt(fac1*fac1 + fac2*fac2) );
+ glColor3f(0.0, 0.0, 0.0);
+ glRasterPos2i(15, 27);
+ BMF_DrawString(G.fonts, str);
+ glColor3f(0.7, 0.7, 0.7);
+ glRasterPos2i(16, 28);
+ BMF_DrawString(G.fonts, str);
+ }
+ }
+ else if(curarea->spacetype==SPACE_IPO) {
+ SpaceIpo *sipo= curarea->spacedata.first;
+
+ BIF_ThemeColor(TH_BACK);
+ glRecti(20, 30, 170, 40);
+
+ mvalo[2]= x1;
+ mvalo[3]= y1;
+ areamouseco_to_ipoco(&sipo->v2d, mval, dvec, dvec+1);
+ areamouseco_to_ipoco(&sipo->v2d, mvalo+2, dvec+2, dvec+3);
+
+ if (flag == 5) {
+ /* setting preview range */
+ if (dvec[0] < dvec[2])
+ sprintf(str, "Preview Range: %d to %d", (int)dvec[0], (int)dvec[2]);
+ else
+ sprintf(str, "Preview Range: %d to %d", (int)dvec[2], (int)dvec[0]);
+ }
+ else
+ sprintf(str, "Time: %.4f Y %.4f", dvec[0]-dvec[2], dvec[1]-dvec[3]);
+
+ BIF_ThemeColor(TH_BACK);
+ glRecti(14, 24, 165, 38);
+
+ glColor3f(0.0, 0.0, 0.0);
+ glRasterPos2i(15, 27);
+ BMF_DrawString(G.fonts, str);
+ glColor3f(0.8, 0.8, 0.8);
+ glRasterPos2i(16, 28);
+ BMF_DrawString(G.fonts, str);
+ }
+ else if ((ELEM3(curarea->spacetype, SPACE_ACTION, SPACE_NLA, SPACE_TIME)) && flag==5) {
+ /* only while setting preview range */
+ View2D *v2d;
+
+ switch (curarea->spacetype)
+ {
+ case SPACE_ACTION:
+ {
+ SpaceAction *saaction= curarea->spacedata.first;
+ v2d= &saaction->v2d;
+ }
+ break;
+ case SPACE_NLA:
+ {
+ SpaceNla *snla= curarea->spacedata.first;
+ v2d= &snla->v2d;
+ }
+ break;
+ default:
+ v2d= G.v2d;
+ break;
+ }
+
+ mvalo[2]= x1;
+ mvalo[3]= y1;
+ areamouseco_to_ipoco(v2d, mval, dvec, dvec+1);
+ areamouseco_to_ipoco(v2d, mvalo+2, dvec+2, dvec+3);
+
+ if (dvec[0] < dvec[2])
+ sprintf(str, "Preview Range: %d to %d", (int)dvec[0], (int)dvec[2]);
+ else
+ sprintf(str, "Preview Range: %d to %d", (int)dvec[2], (int)dvec[0]);
+
+ BIF_ThemeColor(TH_BACK);
+ glRecti(14, 24, 165, 38);
+
+ glColor3f(0.0, 0.0, 0.0);
+ glRasterPos2i(15, 27);
+ BMF_DrawString(G.fonts, str);
+ glColor3f(0.8, 0.8, 0.8);
+ glRasterPos2i(16, 28);
+ BMF_DrawString(G.fonts, str);
+ }
+
+ bglFlush();
+
+ mvalo[0]= mval[0];
+ mvalo[1]= mval[1];
+ }
+
+ event= extern_qread(&val);
+
+ if(event && val==0) {
+ /* still because of the renderwindow... */
+ persp(PERSP_VIEW);
+ mywinset(curarea->win);
+ persp(PERSP_WIN);
+
+ if(event==ESCKEY) {
+ retval= 0;
+ break;
+ }
+ else if(event==LEFTMOUSE) break;
+ else if(event==MIDDLEMOUSE) break;
+ else if(event==RIGHTMOUSE) break;
+ }
+
+ } /* end while (TRUE) */
+ sdrawXORline4(-1, 0, 0, 0, 0);
+
+ if(retval) {
+ rect->xmin= x1;
+ rect->ymin= y1;
+ rect->xmax= mval[0];
+ rect->ymax= mval[1];
+ retval= event;
+
+ /* normalize */
+ if(rect->xmin>rect->xmax) SWAP(int, rect->xmin, rect->xmax);
+ if(rect->ymin>rect->ymax) SWAP(int, rect->ymin, rect->ymax);
+
+ if(rect->xmin==rect->xmax) retval= 0;
+ if(rect->ymin==rect->ymax) retval= 0;
+ }
+ }
+
+
+ /* clear */
+ if(event!=BKEY) {
+ if ELEM(curarea->spacetype, SPACE_VIEW3D, SPACE_IPO) {
+ scrarea_queue_winredraw(curarea);
+ }
+ else if ELEM3(curarea->spacetype, SPACE_ACTION, SPACE_NLA, SPACE_TIME) {
+ scrarea_queue_winredraw(curarea); // only really needed for
+ }
+ }
+
+ bglFlush();
+ glReadBuffer(GL_BACK);
+ glDrawBuffer(GL_BACK);
+
+ persp(PERSP_VIEW);
+
+ /* pressed B again ? -> brush select */
+ if(event==BKEY) {
+ setlinestyle(0);
+ switch (curarea->spacetype) {
+ case SPACE_VIEW3D:
+ if (G.obedit) {
+ if ELEM4(G.obedit->type, OB_MESH, OB_CURVE, OB_SURF, OB_LATTICE) {
+ circle_selectCB(&obedit_selectionCB);
+ }
+ }
+ else if (FACESEL_PAINT_TEST) {
+ circle_selectCB(&obedit_selectionCB);
+ }
+ return 0;
+
+ case SPACE_IMAGE: // brush select in UV editor
+ circle_selectCB(&uvedit_selectionCB);
+ // this is a hack; we return 0 that the caller from get_border
+ // doesn't execute the selection code for border select..
+ return 0;
+ }
+ }
+ return retval;
+}
+
+void draw_sel_circle(short *mval, short *mvalo, float rad, float rado, int selecting)
+{
+ static short no_mvalo=0;
+
+ if(mval==NULL && mvalo==NULL) { /* signal */
+ no_mvalo= 1;
+ return;
+ }
+
+ persp(PERSP_WIN);
+ glReadBuffer(GL_FRONT);
+ glDrawBuffer(GL_FRONT);
+ //setlinestyle(2);
+
+ /* draw circle */
+ if(mvalo && no_mvalo==0) {
+ fdrawXORcirc(mvalo[0], mvalo[1], rado);
+ }
+
+ if(mval) {
+ fdrawXORcirc(mval[0], mval[1], rad);
+ }
+ //setlinestyle(0);
+
+ bglFlush();
+ persp(PERSP_VIEW);
+ glDrawBuffer(GL_BACK);
+ glReadBuffer(GL_BACK);
+
+ no_mvalo= 0;
+}
+
+/** This function does the same as editview.c:circle_select(),
+ * but the selection actions are defined by a callback, making
+ * it (hopefully) reusable for other windows than the 3D view.
+ */
+
+void circle_selectCB(select_CBfunc callback)
+{
+ static float rad= 40.0;
+ float rado;
+ int firsttime=1;
+ int escape= 0;
+ unsigned short event;
+ short mvalo[2], mval[2], val;
+ short selecting=0;
+ Object *obj;
+
+ if(G.obedit) obj = G.obedit;
+ else obj = OBACT;
+
+ mywinset(curarea->win);
+
+ getmouseco_areawin(mvalo);
+ mval[0]= mvalo[0]; mval[1]= mvalo[1];
+
+ draw_sel_circle(mval, NULL, rad, 0.0, selecting); // draws frontbuffer, but sets backbuf again
+
+ rado= rad;
+
+ while(TRUE) {
+
+ if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || rado!=rad || firsttime) {
+ firsttime= 0;
+
+ if(selecting) {
+ callback(selecting, obj, mval, rad);
+ }
+
+ draw_sel_circle(mval, mvalo, rad, rado, selecting);
+
+ mvalo[0]= mval[0];
+ mvalo[1]= mval[1];
+ rado= rad;
+
+ }
+
+ while(qtest()) {
+ event= extern_qread(&val);
+ if (event) {
+
+ /* for when another window is open and a mouse cursor activates it */
+ if(event!=MOUSEY && event!=MOUSEX) mywinset(curarea->win);
+
+ getmouseco_areawin(mval); // important to do here, trust events!
+
+ switch(event) {
+
+ case LEFTMOUSE:
+ case MIDDLEMOUSE:
+ if(val) selecting= event;
+ else selecting= 0;
+ firsttime= 1;
+
+ break;
+ case PAGEUPKEY:
+ case WHEELDOWNMOUSE:
+ case PADPLUSKEY:
+ case EQUALKEY:
+ if(val) if(rad<200.0) rad*= 1.2;
+ break;
+ case PAGEDOWNKEY:
+ case WHEELUPMOUSE:
+ case PADMINUS:
+ case MINUSKEY:
+ if(val) if(rad>5.0) rad/= 1.2;
+ break;
+
+ case ESCKEY: case SPACEKEY: case RIGHTMOUSE: case INPUTCHANGE:
+ case GKEY: case SKEY: case RKEY: case XKEY: case EKEY: case TABKEY:
+ escape= 1;
+ break;
+
+ }
+
+ if(escape) break;
+ }
+ }
+ PIL_sleep_ms(10);
+
+ if(escape) break;
+ }
+
+ /* clear circle */
+ draw_sel_circle(NULL, mvalo, 0, rad, 1);
+ BIF_undo_push("Circle Select");
+ countall();
+ allqueue(REDRAWINFO, 0);
+}
+
+static void count_object(Object *ob, int sel, int totob)
+{
+ Mesh *me;
+ Curve *cu;
+ DerivedMesh *dm;
+ int tot=0, totf=0;
+
+ switch(ob->type) {
+ case OB_MESH:
+ G.totmesh+=totob;
+ me= get_mesh(ob);
+ if(me) {
+ int totvert, totedge, totface;
+ dm = mesh_get_derived_final(ob, get_viewedit_datamask());
+ totvert = dm->getNumVerts(dm);
+ totedge = dm->getNumEdges(dm);
+ totface = dm->getNumFaces(dm);
+
+ G.totvert+= totvert*totob;
+ G.totedge+= totedge*totob;
+ G.totface+= totface*totob;
+ if(sel) {
+ G.totvertsel+= totvert;
+ G.totfacesel+= totface;
+ }
+ }
+ break;
+
+ case OB_LAMP:
+ G.totlamp+=totob;
+ break;
+ case OB_SURF:
+ case OB_CURVE:
+ case OB_FONT:
+ G.totcurve+=totob;
+ tot=totf= 0;
+ cu= ob->data;
+ if(cu->disp.first)
+ count_displist( &cu->disp, &tot, &totf);
+ tot*= totob;
+ totf*= totob;
+ G.totvert+= tot;
+ G.totface+= totf;
+ if(sel) {
+ G.totvertsel+= tot;
+ G.totfacesel+= totf;
+ }
+ break;
+ case OB_MBALL:
+ count_displist( &ob->disp, &tot, &totf);
+ tot*= totob;
+ totf*= totob;
+ G.totvert+= tot;
+ G.totface+= totf;
+ if(sel) {
+ G.totvertsel+= tot;
+ G.totfacesel+= totf;
+ }
+ break;
+ }
+
+}
+
+/* countall does statistics */
+/* is called on most actions, like select/add/delete/layermove */
+void countall()
+{
+ extern ListBase editNurb;
+ Base *base;
+ Object *ob= OBACT;
+ Mesh *me;
+ Nurb *nu;
+ BezTriple *bezt;
+ BPoint *bp;
+ MetaElem *ml;
+ struct EditBone *ebo;
+ int a;
+
+ G.totvert= G.totvertsel= G.totedge= G.totedgesel= G.totfacesel= G.totface= G.totobj=
+ G.totmesh= G.totlamp= G.totcurve= G.totobjsel= G.totbone= G.totbonesel= 0;
+
+ if(G.obedit) {
+
+ if(G.obedit->type==OB_MESH) {
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+ EditEdge *eed;
+ EditFace *efa;
+
+ for(eve= em->verts.first; eve; eve= eve->next) {
+ G.totvert++;
+ if(eve->f & SELECT) G.totvertsel++;
+ }
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ G.totedge++;
+ if(eed->f & SELECT) G.totedgesel++;
+ }
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ G.totface++;
+ if(efa->f & SELECT) G.totfacesel++;
+ }
+
+ EM_validate_selections();
+ }
+ else if (G.obedit->type==OB_ARMATURE){
+ for (ebo=G.edbo.first;ebo;ebo=ebo->next){
+ G.totbone++;
+
+ /* Sync selection to parent for connected children */
+ if ((ebo->flag & BONE_CONNECTED) && ebo->parent){
+ G.totvert--;
+ if (ebo->parent->flag & BONE_TIPSEL)
+ ebo->flag |= BONE_ROOTSEL;
+ else
+ ebo->flag &= ~BONE_ROOTSEL;
+ }
+
+ if (ebo->flag & BONE_TIPSEL)
+ G.totvertsel++;
+ if (ebo->flag & BONE_ROOTSEL)
+ G.totvertsel++;
+
+ if ((ebo->flag & BONE_TIPSEL) && (ebo->flag & BONE_ROOTSEL))
+ ebo->flag |= BONE_SELECTED;
+ else
+ ebo->flag &= ~BONE_SELECTED;
+
+ if(ebo->flag & BONE_SELECTED) G.totbonesel++;
+
+ // If this is a connected child and it's parent is being moved, remove our root
+ if ((ebo->flag & BONE_CONNECTED)&& (ebo->flag & BONE_ROOTSEL) && ebo->parent && (ebo->parent->flag & BONE_TIPSEL)){
+ G.totvertsel--;
+ }
+
+ G.totvert+=2;
+ }
+ }
+ else if ELEM3(G.obedit->type, OB_CURVE, OB_SURF, OB_FONT) {
+ nu= editNurb.first;
+ while(nu) {
+ if((nu->type & 7)==CU_BEZIER) {
+ bezt= nu->bezt;
+ a= nu->pntsu;
+ while(a--) {
+ G.totvert+=3;
+ if(bezt->f1) G.totvertsel++;
+ if(bezt->f2) G.totvertsel++;
+ if(bezt->f3) G.totvertsel++;
+ bezt++;
+ }
+ }
+ else {
+ bp= nu->bp;
+ a= nu->pntsu*nu->pntsv;
+ while(a--) {
+ G.totvert++;
+ if(bp->f1 & 1) G.totvertsel++;
+ bp++;
+ }
+ }
+ nu= nu->next;
+ }
+ }
+ else if(G.obedit->type==OB_MBALL) {
+ /* editmball.c */
+ extern ListBase editelems; /* go away ! */
+
+ ml= editelems.first;
+ while(ml) {
+ G.totvert++;
+ if(ml->flag & SELECT) G.totvertsel++;
+ ml= ml->next;
+ }
+ }
+ else if(G.obedit->type==OB_LATTICE) {
+ bp= editLatt->def;
+
+ a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
+ while(a--) {
+ G.totvert++;
+ if(bp->f1 & 1) G.totvertsel++;
+ bp++;
+ }
+ }
+
+ allqueue(REDRAWINFO, 1); /* 1, because header->win==0! */
+ return;
+ }
+ else if(ob && (ob->flag & OB_POSEMODE)) {
+ if(ob->pose) {
+ bArmature *arm= ob->data;
+ bPoseChannel *pchan;
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ G.totbone++;
+ if(pchan->bone && (pchan->bone->flag & BONE_SELECTED))
+ if(pchan->bone->layer & arm->layer)
+ G.totbonesel++;
+ }
+ }
+ allqueue(REDRAWINFO, 1); /* 1, because header->win==0! */
+ return;
+ }
+ else if(FACESEL_PAINT_TEST) {
+ me= get_mesh((G.scene->basact) ? (G.scene->basact->object) : 0);
+ if(me) {
+ G.totface= me->totface;
+ G.totvert= me->totvert;
+ }
+ allqueue(REDRAWINFO, 1); /* 1, because header->win==0! */
+ return;
+ }
+
+ if(G.scene==NULL) return;
+
+ base= (G.scene->base.first);
+ while(base) {
+ if(G.scene->lay & base->lay) {
+ ob= base->object; /* warning, ob not is obact anymore */
+
+ if(base->flag & SELECT) G.totobjsel++;
+
+ if(ob->parent && (ob->parent->transflag & (OB_DUPLIVERTS|OB_DUPLIFACES))) {
+ int tot= count_duplilist(ob->parent);
+ G.totobj+=tot;
+ count_object(ob, base->flag & SELECT, tot);
+ }
+ else if(ob->transflag & OB_DUPLIFRAMES) {
+ int tot= count_duplilist(ob);
+ G.totobj+=tot;
+ count_object(ob, base->flag & SELECT, tot);
+ }
+ else {
+ count_object(ob, base->flag & SELECT, 1);
+ G.totobj++;
+ }
+ }
+ base= base->next;
+ }
+ allqueue(REDRAWINFO, 1); /* 1, because header->win==0! */
+}
+
+/* ************************************************** */
+/* ********************* old transform stuff ******** */
+/* ************************************************** */
+
+static TransVert *transvmain=NULL;
+static int tottrans= 0;
+
+/* copied from editobject.c, now uses (almost) proper depgraph */
+static void special_transvert_update(void)
+{
+
+ if(G.obedit) {
+
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+
+ if(G.obedit->type==OB_MESH) {
+#ifdef WITH_VERSE
+ if(G.editMesh->vnode)
+ sync_all_verseverts_with_editverts((VNode*)G.editMesh->vnode);
+#endif
+ recalc_editnormals(); // does face centers too
+ }
+ else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) {
+ extern ListBase editNurb;
+ Nurb *nu= editNurb.first;
+ while(nu) {
+ test2DNurb(nu);
+ testhandlesNurb(nu); /* test for bezier too */
+ nu= nu->next;
+ }
+ }
+ else if(G.obedit->type==OB_ARMATURE){
+ bArmature *arm= G.obedit->data;
+ EditBone *ebo;
+ TransVert *tv= transvmain;
+ int a=0;
+
+ /* Ensure all bone tails are correctly adjusted */
+ for (ebo=G.edbo.first; ebo; ebo=ebo->next) {
+ /* adjust tip if both ends selected */
+ if ((ebo->flag & BONE_ROOTSEL) && (ebo->flag & BONE_TIPSEL)) {
+ if (tv) {
+ float diffvec[3];
+
+ VecSubf(diffvec, tv->loc, tv->oldloc);
+ VecAddf(ebo->tail, ebo->tail, diffvec);
+
+ a++;
+ if (a<tottrans) tv++;
+ }
+ }
+ }
+
+ /* Ensure all bones are correctly adjusted */
+ for (ebo=G.edbo.first; ebo; ebo=ebo->next) {
+ if ((ebo->flag & BONE_CONNECTED) && ebo->parent){
+ /* If this bone has a parent tip that has been moved */
+ if (ebo->parent->flag & BONE_TIPSEL){
+ VECCOPY (ebo->head, ebo->parent->tail);
+ }
+ /* If this bone has a parent tip that has NOT been moved */
+ else{
+ VECCOPY (ebo->parent->tail, ebo->head);
+ }
+ }
+ }
+ if(arm->flag & ARM_MIRROR_EDIT)
+ transform_armature_mirror_update();
+ }
+ else if(G.obedit->type==OB_LATTICE) {
+ if(editLatt->flag & LT_OUTSIDE) outside_lattice(editLatt);
+ }
+ }
+}
+
+/* copied from editobject.c, needs to be replaced with new transform code still */
+/* mode: 1 = proportional, 2 = all joints (for bones only) */
+static void make_trans_verts(float *min, float *max, int mode)
+{
+ extern ListBase editNurb;
+ EditMesh *em = G.editMesh;
+ Nurb *nu;
+ BezTriple *bezt;
+ BPoint *bp;
+ TransVert *tv=NULL;
+ MetaElem *ml;
+ EditVert *eve;
+ EditBone *ebo;
+ float total, center[3], centroid[3];
+ int a;
+
+ tottrans= 0; // global!
+
+ INIT_MINMAX(min, max);
+ centroid[0]=centroid[1]=centroid[2]= 0.0;
+
+ /* note for transform refactor: dont rely on countall anymore... its ancient */
+ /* I skip it for editmesh now (ton) */
+ if(G.obedit->type!=OB_MESH) {
+ countall();
+ if(mode) tottrans= G.totvert;
+ else tottrans= G.totvertsel;
+
+ if(G.totvertsel==0) {
+ tottrans= 0;
+ return;
+ }
+ tv=transvmain= MEM_callocN(tottrans*sizeof(TransVert), "maketransverts");
+ }
+
+ /* we count again because of hide (old, not for mesh!) */
+ tottrans= 0;
+
+ if(G.obedit->type==OB_MESH) {
+ int proptrans= 0;
+
+ // transform now requires awareness for select mode, so we tag the f1 flags in verts
+ tottrans= 0;
+ if(G.scene->selectmode & SCE_SELECT_VERTEX) {
+ for(eve= em->verts.first; eve; eve= eve->next) {
+ if(eve->h==0 && (eve->f & SELECT)) {
+ eve->f1= SELECT;
+ tottrans++;
+ }
+ else eve->f1= 0;
+ }
+ }
+ else if(G.scene->selectmode & SCE_SELECT_EDGE) {
+ EditEdge *eed;
+ for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->h==0 && (eed->f & SELECT)) eed->v1->f1= eed->v2->f1= SELECT;
+ }
+ for(eve= em->verts.first; eve; eve= eve->next) if(eve->f1) tottrans++;
+ }
+ else {
+ EditFace *efa;
+ for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->h==0 && (efa->f & SELECT)) {
+ efa->v1->f1= efa->v2->f1= efa->v3->f1= SELECT;
+ if(efa->v4) efa->v4->f1= SELECT;
+ }
+ }
+ for(eve= em->verts.first; eve; eve= eve->next) if(eve->f1) tottrans++;
+ }
+
+ /* proportional edit exception... */
+ if((mode & 1) && tottrans) {
+ for(eve= em->verts.first; eve; eve= eve->next) {
+ if(eve->h==0) {
+ eve->f1 |= 2;
+ proptrans++;
+ }
+ }
+ if(proptrans>tottrans) tottrans= proptrans;
+ }
+
+ /* and now make transverts */
+ if(tottrans) {
+ tv=transvmain= MEM_callocN(tottrans*sizeof(TransVert), "maketransverts");
+
+ for(eve= em->verts.first; eve; eve= eve->next) {
+ if(eve->f1) {
+ VECCOPY(tv->oldloc, eve->co);
+ tv->loc= eve->co;
+ if(eve->no[0]!=0.0 || eve->no[1]!=0.0 ||eve->no[2]!=0.0)
+ tv->nor= eve->no; // note this is a hackish signal (ton)
+ tv->flag= eve->f1 & SELECT;
+ tv++;
+ }
+ }
+ }
+ }
+ else if (G.obedit->type==OB_ARMATURE){
+ bArmature *arm= G.obedit->data;
+
+ for (ebo=G.edbo.first;ebo;ebo=ebo->next){
+ if(ebo->layer & arm->layer) {
+ short tipsel= (ebo->flag & BONE_TIPSEL);
+ short rootsel= (ebo->flag & BONE_ROOTSEL);
+ short rootok= (!(ebo->parent && (ebo->flag & BONE_CONNECTED) && ebo->parent->flag & BONE_TIPSEL));
+
+ if ((tipsel && rootsel) || (rootsel)) {
+ /* Don't add the tip (unless mode & 2, for getting all joints),
+ * otherwise we get zero-length bones as tips will snap to the same
+ * location as heads.
+ */
+ if (rootok) {
+ VECCOPY (tv->oldloc, ebo->head);
+ tv->loc= ebo->head;
+ tv->nor= NULL;
+ tv->flag= 1;
+ tv++;
+ tottrans++;
+ }
+
+ if ((mode & 2) && (tipsel)) {
+ VECCOPY (tv->oldloc, ebo->tail);
+ tv->loc= ebo->tail;
+ tv->nor= NULL;
+ tv->flag= 1;
+ tv++;
+ tottrans++;
+ }
+ }
+ else if (tipsel) {
+ VECCOPY (tv->oldloc, ebo->tail);
+ tv->loc= ebo->tail;
+ tv->nor= NULL;
+ tv->flag= 1;
+ tv++;
+ tottrans++;
+ }
+ }
+ }
+ }
+ else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) {
+ nu= editNurb.first;
+ while(nu) {
+ if((nu->type & 7)==CU_BEZIER) {
+ a= nu->pntsu;
+ bezt= nu->bezt;
+ while(a--) {
+ if(bezt->hide==0) {
+ if((mode & 1) || (bezt->f1 & 1)) {
+ VECCOPY(tv->oldloc, bezt->vec[0]);
+ tv->loc= bezt->vec[0];
+ tv->flag= bezt->f1 & 1;
+ tv++;
+ tottrans++;
+ }
+ if((mode & 1) || (bezt->f2 & 1)) {
+ VECCOPY(tv->oldloc, bezt->vec[1]);
+ tv->loc= bezt->vec[1];
+ tv->val= &(bezt->alfa);
+ tv->oldval= bezt->alfa;
+ tv->flag= bezt->f2 & 1;
+ tv++;
+ tottrans++;
+ }
+ if((mode & 1) || (bezt->f3 & 1)) {
+ VECCOPY(tv->oldloc, bezt->vec[2]);
+ tv->loc= bezt->vec[2];
+ tv->flag= bezt->f3 & 1;
+ tv++;
+ tottrans++;
+ }
+ }
+ bezt++;
+ }
+ }
+ else {
+ a= nu->pntsu*nu->pntsv;
+ bp= nu->bp;
+ while(a--) {
+ if(bp->hide==0) {
+ if((mode & 1) || (bp->f1 & 1)) {
+ VECCOPY(tv->oldloc, bp->vec);
+ tv->loc= bp->vec;
+ tv->val= &(bp->alfa);
+ tv->oldval= bp->alfa;
+ tv->flag= bp->f1 & 1;
+ tv++;
+ tottrans++;
+ }
+ }
+ bp++;
+ }
+ }
+ nu= nu->next;
+ }
+ }
+ else if(G.obedit->type==OB_MBALL) {
+ extern ListBase editelems; /* go away ! */
+ ml= editelems.first;
+ while(ml) {
+ if(ml->flag & SELECT) {
+ tv->loc= &ml->x;
+ VECCOPY(tv->oldloc, tv->loc);
+ tv->val= &(ml->rad);
+ tv->oldval= ml->rad;
+ tv->flag= 1;
+ tv++;
+ tottrans++;
+ }
+ ml= ml->next;
+ }
+ }
+ else if(G.obedit->type==OB_LATTICE) {
+ bp= editLatt->def;
+
+ a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
+
+ while(a--) {
+ if((mode & 1) || (bp->f1 & 1)) {
+ if(bp->hide==0) {
+ VECCOPY(tv->oldloc, bp->vec);
+ tv->loc= bp->vec;
+ tv->flag= bp->f1 & 1;
+ tv++;
+ tottrans++;
+ }
+ }
+ bp++;
+ }
+ }
+
+ /* cent etc */
+ tv= transvmain;
+ total= 0.0;
+ for(a=0; a<tottrans; a++, tv++) {
+ if(tv->flag & SELECT) {
+ centroid[0]+= tv->oldloc[0];
+ centroid[1]+= tv->oldloc[1];
+ centroid[2]+= tv->oldloc[2];
+ total+= 1.0;
+ DO_MINMAX(tv->oldloc, min, max);
+ }
+ }
+ if(total!=0.0) {
+ centroid[0]/= total;
+ centroid[1]/= total;
+ centroid[2]/= total;
+ }
+
+ center[0]= (min[0]+max[0])/2.0;
+ center[1]= (min[1]+max[1])/2.0;
+ center[2]= (min[2]+max[2])/2.0;
+
+}
+
+void snap_sel_to_grid()
+{
+ extern float originmat[3][3]; /* object.c */
+ TransVert *tv;
+ Base *base;
+ Object *ob;
+ float gridf, imat[3][3], bmat[3][3], vec[3];
+ int a;
+
+ gridf= G.vd->gridview;
+
+
+ if(G.obedit) {
+ tottrans= 0;
+
+ if ELEM6(G.obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL)
+ make_trans_verts(bmat[0], bmat[1], 0);
+ if(tottrans==0) return;
+
+ Mat3CpyMat4(bmat, G.obedit->obmat);
+ Mat3Inv(imat, bmat);
+
+ tv= transvmain;
+ for(a=0; a<tottrans; a++, tv++) {
+
+ VECCOPY(vec, tv->loc);
+ Mat3MulVecfl(bmat, vec);
+ VecAddf(vec, vec, G.obedit->obmat[3]);
+ vec[0]= G.vd->gridview*floor(.5+ vec[0]/gridf);
+ vec[1]= G.vd->gridview*floor(.5+ vec[1]/gridf);
+ vec[2]= G.vd->gridview*floor(.5+ vec[2]/gridf);
+ VecSubf(vec, vec, G.obedit->obmat[3]);
+
+ Mat3MulVecfl(imat, vec);
+ VECCOPY(tv->loc, vec);
+
+ }
+
+ special_transvert_update();
+
+ MEM_freeN(transvmain);
+ transvmain= 0;
+
+ allqueue(REDRAWVIEW3D, 0);
+ return;
+ }
+
+ base= (G.scene->base.first);
+ while(base) {
+ if( ( ((base)->flag & SELECT) && ((base)->lay & G.vd->lay) && ((base)->object->id.lib==0))) {
+ ob= base->object;
+ if(ob->flag & OB_POSEMODE) {
+ bPoseChannel *pchan;
+ bArmature *arm= ob->data;
+
+ for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ if(pchan->bone->flag & BONE_SELECTED) {
+ if(pchan->bone->layer & arm->layer) {
+ if((pchan->bone->flag & BONE_CONNECTED)==0) {
+ float vecN[3], nLoc[3];
+
+ /* get nearest grid point to snap to */
+ VECCOPY(nLoc, pchan->pose_mat[3]);
+ vec[0]= gridf * (float)(floor(.5+ nLoc[0]/gridf));
+ vec[1]= gridf * (float)(floor(.5+ nLoc[1]/gridf));
+ vec[2]= gridf * (float)(floor(.5+ nLoc[2]/gridf));
+
+ /* get bone-space location of grid point */
+ armature_loc_pose_to_bone(pchan, vec, vecN);
+
+ /* adjust location */
+ VECCOPY(pchan->loc, vecN);
+ }
+ /* if the bone has a parent and is connected to the parent,
+ * don't do anything - will break chain unless we do auto-ik.
+ */
+ }
+ }
+ }
+ ob->pose->flag |= (POSE_LOCKED|POSE_DO_UNLOCK);
+
+ /* autokeyframing */
+ autokeyframe_pose_cb_func(ob, TFM_TRANSLATION, 0);
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ }
+ else {
+ ob->recalc |= OB_RECALC_OB;
+
+ vec[0]= -ob->obmat[3][0]+G.vd->gridview*floor(.5+ ob->obmat[3][0]/gridf);
+ vec[1]= -ob->obmat[3][1]+G.vd->gridview*floor(.5+ ob->obmat[3][1]/gridf);
+ vec[2]= -ob->obmat[3][2]+G.vd->gridview*floor(.5+ ob->obmat[3][2]/gridf);
+
+ if(ob->parent) {
+ where_is_object(ob);
+
+ Mat3Inv(imat, originmat);
+ Mat3MulVecfl(imat, vec);
+ ob->loc[0]+= vec[0];
+ ob->loc[1]+= vec[1];
+ ob->loc[2]+= vec[2];
+ }
+ else {
+ ob->loc[0]+= vec[0];
+ ob->loc[1]+= vec[1];
+ ob->loc[2]+= vec[2];
+ }
+#ifdef WITH_VERSE
+ if(ob->vnode) b_verse_send_transformation(ob);
+#endif
+
+ /* auto-keyframing */
+ autokeyframe_ob_cb_func(ob, TFM_TRANSLATION);
+ }
+ }
+
+ base= base->next;
+ }
+ DAG_scene_flush_update(G.scene, screen_view3d_layers());
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+void snap_sel_to_curs()
+{
+ extern float originmat[3][3]; /* object.c */
+ TransVert *tv;
+ Base *base;
+ Object *ob;
+ float *curs, imat[3][3], bmat[3][3], vec[3];
+ int a;
+
+ curs= give_cursor();
+
+ if(G.obedit) {
+ tottrans= 0;
+
+ if ELEM6(G.obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL)
+ make_trans_verts(bmat[0], bmat[1], 0);
+ if(tottrans==0) return;
+
+ Mat3CpyMat4(bmat, G.obedit->obmat);
+ Mat3Inv(imat, bmat);
+
+ tv= transvmain;
+ for(a=0; a<tottrans; a++, tv++) {
+ vec[0]= curs[0]-G.obedit->obmat[3][0];
+ vec[1]= curs[1]-G.obedit->obmat[3][1];
+ vec[2]= curs[2]-G.obedit->obmat[3][2];
+
+ Mat3MulVecfl(imat, vec);
+ VECCOPY(tv->loc, vec);
+ }
+
+ special_transvert_update();
+
+ MEM_freeN(transvmain);
+ transvmain= 0;
+
+ allqueue(REDRAWVIEW3D, 0);
+ return;
+ }
+
+ base= (G.scene->base.first);
+ while(base) {
+ if( ( ((base)->flag & SELECT) && ((base)->lay & G.vd->lay) && ((base)->object->id.lib==0))) {
+ ob= base->object;
+ if(ob->flag & OB_POSEMODE) {
+ bPoseChannel *pchan;
+ bArmature *arm= ob->data;
+ float cursp[3];
+
+ Mat4Invert(ob->imat, ob->obmat);
+ VECCOPY(cursp, curs);
+ Mat4MulVecfl(ob->imat, cursp);
+
+ for (pchan = ob->pose->chanbase.first; pchan; pchan=pchan->next) {
+ if(pchan->bone->flag & BONE_SELECTED) {
+ if(pchan->bone->layer & arm->layer) {
+ if((pchan->bone->flag & BONE_CONNECTED)==0) {
+ float curspn[3];
+
+ /* get location of cursor in bone-space */
+ armature_loc_pose_to_bone(pchan, cursp, curspn);
+
+ /* calculate new position */
+ VECCOPY(pchan->loc, curspn);
+ }
+ /* if the bone has a parent and is connected to the parent,
+ * don't do anything - will break chain unless we do auto-ik.
+ */
+ }
+ }
+ }
+ ob->pose->flag |= (POSE_LOCKED|POSE_DO_UNLOCK);
+
+ /* autokeyframing */
+ autokeyframe_pose_cb_func(ob, TFM_TRANSLATION, 0);
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ }
+ else {
+ ob->recalc |= OB_RECALC_OB;
+
+ vec[0]= -ob->obmat[3][0] + curs[0];
+ vec[1]= -ob->obmat[3][1] + curs[1];
+ vec[2]= -ob->obmat[3][2] + curs[2];
+
+ if(ob->parent) {
+ where_is_object(ob);
+
+ Mat3Inv(imat, originmat);
+ Mat3MulVecfl(imat, vec);
+ ob->loc[0]+= vec[0];
+ ob->loc[1]+= vec[1];
+ ob->loc[2]+= vec[2];
+ }
+ else {
+ ob->loc[0]+= vec[0];
+ ob->loc[1]+= vec[1];
+ ob->loc[2]+= vec[2];
+ }
+#ifdef WITH_VERSE
+ if(ob->vnode) b_verse_send_transformation(ob);
+#endif
+
+ /* auto-keyframing */
+ autokeyframe_ob_cb_func(ob, TFM_TRANSLATION);
+ }
+ }
+
+ base= base->next;
+ }
+ DAG_scene_flush_update(G.scene, screen_view3d_layers());
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+void snap_curs_to_grid()
+{
+ float gridf, *curs;
+
+ gridf= G.vd->gridview;
+ curs= give_cursor();
+
+ curs[0]= G.vd->gridview*floor(.5+curs[0]/gridf);
+ curs[1]= G.vd->gridview*floor(.5+curs[1]/gridf);
+ curs[2]= G.vd->gridview*floor(.5+curs[2]/gridf);
+
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+void snap_curs_to_sel()
+{
+ TransVert *tv;
+ Base *base;
+ float *curs, bmat[3][3], vec[3], min[3], max[3], centroid[3];
+ int count, a;
+
+ curs= give_cursor();
+
+ count= 0;
+ INIT_MINMAX(min, max);
+ centroid[0]= centroid[1]= centroid[2]= 0.0;
+
+ if(G.obedit) {
+ tottrans=0;
+
+ if ELEM6(G.obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL)
+ make_trans_verts(bmat[0], bmat[1], 2);
+ if(tottrans==0) return;
+
+ Mat3CpyMat4(bmat, G.obedit->obmat);
+
+ tv= transvmain;
+ for(a=0; a<tottrans; a++, tv++) {
+ VECCOPY(vec, tv->loc);
+ Mat3MulVecfl(bmat, vec);
+ VecAddf(vec, vec, G.obedit->obmat[3]);
+ VecAddf(centroid, centroid, vec);
+ DO_MINMAX(vec, min, max);
+ }
+
+ if(G.vd->around==V3D_CENTROID) {
+ VecMulf(centroid, 1.0/(float)tottrans);
+ VECCOPY(curs, centroid);
+ }
+ else {
+ curs[0]= (min[0]+max[0])/2;
+ curs[1]= (min[1]+max[1])/2;
+ curs[2]= (min[2]+max[2])/2;
+ }
+ MEM_freeN(transvmain);
+ transvmain= 0;
+ }
+ else {
+ Object *ob= OBACT;
+
+ if(ob && (ob->flag & OB_POSEMODE)) {
+ bArmature *arm= ob->data;
+ bPoseChannel *pchan;
+ for (pchan = ob->pose->chanbase.first; pchan; pchan=pchan->next) {
+ if(arm->layer & pchan->bone->layer) {
+ if(pchan->bone->flag & BONE_SELECTED) {
+ VECCOPY(vec, pchan->pose_head);
+ Mat4MulVecfl(ob->obmat, vec);
+ VecAddf(centroid, centroid, vec);
+ DO_MINMAX(vec, min, max);
+ count++;
+ }
+ }
+ }
+ }
+ else {
+ for(base= G.scene->base.first; base; base= base->next) {
+ if(((base)->flag & SELECT) && ((base)->lay & G.vd->lay) ) {
+ VECCOPY(vec, base->object->obmat[3]);
+ VecAddf(centroid, centroid, vec);
+ DO_MINMAX(vec, min, max);
+ count++;
+ }
+ }
+ }
+ if(count) {
+ if(G.vd->around==V3D_CENTROID) {
+ VecMulf(centroid, 1.0/(float)count);
+ VECCOPY(curs, centroid);
+ }
+ else {
+ curs[0]= (min[0]+max[0])/2;
+ curs[1]= (min[1]+max[1])/2;
+ curs[2]= (min[2]+max[2])/2;
+ }
+ }
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+void snap_curs_to_firstsel()
+{
+ TransVert *tv;
+ Base *base;
+ float *curs, bmat[3][3], vec[3], min[3], max[3], centroid[3];
+ int count;
+
+ curs= give_cursor();
+
+ count= 0;
+ INIT_MINMAX(min, max);
+ centroid[0]= centroid[1]= centroid[2]= 0.0;
+
+ if(G.obedit) {
+ tottrans=0;
+
+ if ELEM6(G.obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL)
+ make_trans_verts(bmat[0], bmat[1], 0);
+ if(tottrans==0) return;
+
+ Mat3CpyMat4(bmat, G.obedit->obmat);
+
+ tv= transvmain;
+ VECCOPY(vec, tv->loc);
+ /*Mat3MulVecfl(bmat, vec);
+ VecAddf(vec, vec, G.obedit->obmat[3]);
+ VecAddf(centroid, centroid, vec);
+ DO_MINMAX(vec, min, max);*/
+
+ if(G.vd->around==V3D_CENTROID) {
+ VecMulf(vec, 1.0/(float)tottrans);
+ VECCOPY(curs, vec);
+ }
+ else {
+ curs[0]= vec[0];
+ curs[1]= vec[1];
+ curs[2]= vec[2];
+ }
+ MEM_freeN(transvmain);
+ transvmain= 0;
+ }
+ else {
+ base= (G.scene->base.first);
+ while(base) {
+ if(((base)->flag & SELECT) && ((base)->lay & G.vd->lay) ) {
+ VECCOPY(vec, base->object->obmat[3]);
+ VecAddf(centroid, centroid, vec);
+ DO_MINMAX(vec, min, max);
+ count++;
+ }
+ base= base->next;
+ }
+ if(count) {
+ if(G.vd->around==V3D_CENTROID) {
+ VecMulf(centroid, 1.0/(float)count);
+ VECCOPY(curs, centroid);
+ }
+ else {
+ curs[0]= (min[0]+max[0])/2;
+ curs[1]= (min[1]+max[1])/2;
+ curs[2]= (min[2]+max[2])/2;
+ }
+ }
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+void snap_to_center()
+{
+ extern float originmat[3][3];
+ TransVert *tv;
+ Base *base;
+ Object *ob;
+ float snaploc[3], imat[3][3], bmat[3][3], vec[3], min[3], max[3], centroid[3];
+ int count, a;
+
+ /*calculate the snaplocation (centerpoint) */
+ count= 0;
+ INIT_MINMAX(min, max);
+ centroid[0]= centroid[1]= centroid[2]= 0.0f;
+ snaploc[0]= snaploc[1]= snaploc[2]= 0.0f;
+
+ if(G.obedit) {
+ tottrans= 0;
+
+ if ELEM6(G.obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL)
+ make_trans_verts(bmat[0], bmat[1], 0);
+ if(tottrans==0) return;
+
+ Mat3CpyMat4(bmat, G.obedit->obmat);
+ Mat3Inv(imat, bmat);
+
+ tv= transvmain;
+ for(a=0; a<tottrans; a++, tv++) {
+ VECCOPY(vec, tv->loc);
+ Mat3MulVecfl(bmat, vec);
+ VecAddf(vec, vec, G.obedit->obmat[3]);
+ VecAddf(centroid, centroid, vec);
+ DO_MINMAX(vec, min, max);
+ }
+
+ if(G.vd->around==V3D_CENTROID) {
+ VecMulf(centroid, 1.0/(float)tottrans);
+ VECCOPY(snaploc, centroid);
+ }
+ else {
+ snaploc[0]= (min[0]+max[0])/2;
+ snaploc[1]= (min[1]+max[1])/2;
+ snaploc[2]= (min[2]+max[2])/2;
+ }
+
+ MEM_freeN(transvmain);
+ transvmain= 0;
+ }
+ else {
+ base= (G.scene->base.first);
+ while(base) {
+ if(((base)->flag & SELECT) && ((base)->lay & G.vd->lay) ) {
+ ob= base->object;
+ if(ob->flag & OB_POSEMODE) {
+ bPoseChannel *pchan;
+ bArmature *arm= ob->data;
+
+ for (pchan = ob->pose->chanbase.first; pchan; pchan=pchan->next) {
+ if(pchan->bone->flag & BONE_SELECTED) {
+ if(pchan->bone->layer & arm->layer) {
+ VECCOPY(vec, pchan->pose_mat[3]);
+ VecAddf(centroid, centroid, vec);
+ DO_MINMAX(vec, min, max);
+ count++;
+ }
+ }
+ }
+ }
+ else {
+ /* not armature bones (i.e. objects) */
+ VECCOPY(vec, base->object->obmat[3]);
+ VecAddf(centroid, centroid, vec);
+ DO_MINMAX(vec, min, max);
+ count++;
+ }
+ }
+ base= base->next;
+ }
+ if(count) {
+ if(G.vd->around==V3D_CENTROID) {
+ VecMulf(centroid, 1.0/(float)count);
+ VECCOPY(snaploc, centroid);
+ }
+ else {
+ snaploc[0]= (min[0]+max[0])/2;
+ snaploc[1]= (min[1]+max[1])/2;
+ snaploc[2]= (min[2]+max[2])/2;
+ }
+ }
+ }
+
+ /* Snap the selection to the snaplocation (duh!) */
+ if(G.obedit) {
+ tottrans= 0;
+
+ if ELEM6(G.obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL)
+ make_trans_verts(bmat[0], bmat[1], 0);
+ if(tottrans==0) return;
+
+ Mat3CpyMat4(bmat, G.obedit->obmat);
+ Mat3Inv(imat, bmat);
+
+ tv= transvmain;
+ for(a=0; a<tottrans; a++, tv++) {
+ vec[0]= snaploc[0]-G.obedit->obmat[3][0];
+ vec[1]= snaploc[1]-G.obedit->obmat[3][1];
+ vec[2]= snaploc[2]-G.obedit->obmat[3][2];
+
+ Mat3MulVecfl(imat, vec);
+ VECCOPY(tv->loc, vec);
+ }
+
+ special_transvert_update();
+
+ MEM_freeN(transvmain);
+ transvmain= 0;
+
+ allqueue(REDRAWVIEW3D, 0);
+ return;
+ }
+
+ base= (G.scene->base.first);
+ while(base) {
+ if( ( ((base)->flag & SELECT) && ((base)->lay & G.vd->lay) && ((base)->object->id.lib==0))) {
+ ob= base->object;
+ if(ob->flag & OB_POSEMODE) {
+ bPoseChannel *pchan;
+ bArmature *arm= ob->data;
+
+ for (pchan = ob->pose->chanbase.first; pchan; pchan=pchan->next) {
+ if(pchan->bone->flag & BONE_SELECTED) {
+ if(pchan->bone->layer & arm->layer) {
+ if((pchan->bone->flag & BONE_CONNECTED)==0) {
+ /* get location of cursor in bone-space */
+ armature_loc_pose_to_bone(pchan, snaploc, vec);
+
+ /* calculate new position */
+ VECCOPY(pchan->loc, vec);
+ }
+ /* if the bone has a parent and is connected to the parent,
+ * don't do anything - will break chain unless we do auto-ik.
+ */
+ }
+ }
+ }
+
+ /* autokeyframing */
+ ob->pose->flag |= POSE_DO_UNLOCK;
+ autokeyframe_pose_cb_func(ob, TFM_TRANSLATION, 0);
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ }
+ else {
+ ob->recalc |= OB_RECALC_OB;
+
+ vec[0]= -ob->obmat[3][0] + snaploc[0];
+ vec[1]= -ob->obmat[3][1] + snaploc[1];
+ vec[2]= -ob->obmat[3][2] + snaploc[2];
+
+ if(ob->parent) {
+ where_is_object(ob);
+
+ Mat3Inv(imat, originmat);
+ Mat3MulVecfl(imat, vec);
+ ob->loc[0]+= vec[0];
+ ob->loc[1]+= vec[1];
+ ob->loc[2]+= vec[2];
+ }
+ else {
+ ob->loc[0]+= vec[0];
+ ob->loc[1]+= vec[1];
+ ob->loc[2]+= vec[2];
+ }
+#ifdef WITH_VERSE
+ if(ob->vnode) b_verse_send_transformation(ob);
+#endif
+
+ /* auto-keyframing */
+ autokeyframe_ob_cb_func(ob, TFM_TRANSLATION);
+ }
+ }
+
+ base= base->next;
+ }
+ DAG_scene_flush_update(G.scene, screen_view3d_layers());
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+
+void snapmenu()
+{
+ short event;
+
+ event = pupmenu("Snap %t|Selection -> Grid%x1|Selection -> Cursor%x2|Cursor-> Grid%x3|Cursor-> Selection%x4|Selection-> Center%x5");
+
+ switch (event) {
+ case 1: /*Selection to grid*/
+ snap_sel_to_grid();
+ BIF_undo_push("Snap selection to grid");
+ break;
+ case 2: /*Selection to cursor*/
+ snap_sel_to_curs();
+ BIF_undo_push("Snap selection to cursor");
+ break;
+ case 3: /*Cursor to grid*/
+ snap_curs_to_grid();
+ break;
+ case 4: /*Cursor to selection*/
+ snap_curs_to_sel();
+ break;
+ case 5: /*Selection to center of selection*/
+ snap_to_center();
+ BIF_undo_push("Snap selection to center");
+ break;
+ }
+}
+
+
+#define MERGELIMIT 0.001
+void mergemenu(void)
+{
+
+ short event;
+ int remCount = 0;
+
+ if(G.scene->selectmode & SCE_SELECT_VERTEX)
+ if(G.editMesh->selected.first && G.editMesh->selected.last &&
+ ((EditSelection*)G.editMesh->selected.first)->type == EDITVERT && ((EditSelection*)G.editMesh->selected.last)->type == EDITVERT)
+ event = pupmenu("Merge %t|At First %x6|At Last%x1|At Center%x3|At Cursor%x4|Collapse%x2");
+ else if (G.editMesh->selected.first && ((EditSelection*)G.editMesh->selected.first)->type == EDITVERT)
+ event = pupmenu("Merge %t|At First %x6|At Center%x3|At Cursor%x4|Collapse%x2");
+ else if (G.editMesh->selected.last && ((EditSelection*)G.editMesh->selected.last)->type == EDITVERT)
+ event = pupmenu("Merge %t|At Last %x1|At Center%x3|At Cursor%x4|Collapse%x2");
+ else event = pupmenu("Merge %t|At Center%x3|At Cursor%x4|Collapse%x2");
+ else event = pupmenu("Merge %t|At Center%x3|At Cursor%x4|Collapse%x2");
+ switch (event)
+ {
+ case -1:
+ return;
+ case 3:
+ if(G.qual & LR_CTRLKEY) remCount = merge_target(0,1);
+ else remCount = merge_target(0,0);
+ BIF_undo_push("Merge at center");
+ break;
+ case 4:
+ if(G.qual & LR_CTRLKEY) remCount = merge_target(1,1);
+ else remCount = merge_target(1,0);
+ BIF_undo_push("Merge at cursor");
+ break;
+ case 1:
+ if(G.qual & LR_CTRLKEY) remCount = merge_firstlast(0,1);
+ else remCount = merge_firstlast(0,0);
+ BIF_undo_push("Merge at last selected");
+ break;
+ case 6:
+ if(G.qual & LR_CTRLKEY) remCount = merge_firstlast(1,1);
+ else remCount = merge_firstlast(1,0);
+ BIF_undo_push("Merge at first selected");
+ break;
+ case 2:
+ remCount = collapseEdges();
+ BIF_undo_push("Collapse");
+ break;
+ }
+ notice("Removed %d Vertices", remCount);
+ allqueue(REDRAWVIEW3D, 0);
+ countall();
+}
+#undef MERGELIMIT
+
+
+void delete_context_selected(void)
+{
+ if(G.obedit) {
+ if(G.obedit->type==OB_MESH) delete_mesh();
+ else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) delNurb();
+ else if(G.obedit->type==OB_MBALL) delete_mball();
+ else if (G.obedit->type==OB_ARMATURE) delete_armature();
+ }
+ else delete_obj(0);
+}
+
+void duplicate_context_selected(void)
+{
+ if(G.obedit) {
+ if(G.obedit->type==OB_MESH) adduplicate_mesh();
+ else if(G.obedit->type==OB_ARMATURE) adduplicate_armature();
+ else if(G.obedit->type==OB_MBALL) adduplicate_mball();
+ else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) adduplicate_nurb();
+ }
+ else {
+ adduplicate(0, U.dupflag);
+ }
+}
+
+void toggle_shading(void)
+{
+ if(G.qual & LR_SHIFTKEY) {
+ if(G.qual & LR_ALTKEY) {
+ reshadeall_displist();
+ G.vd->drawtype= OB_SHADED;
+ }
+ else {
+ if(G.vd->drawtype== OB_SHADED) G.vd->drawtype= OB_WIRE;
+ else G.vd->drawtype= OB_SHADED;
+ }
+ }
+ else if(G.qual & LR_ALTKEY) {
+ if(G.vd->drawtype== OB_TEXTURE) G.vd->drawtype= OB_SOLID;
+ else G.vd->drawtype= OB_TEXTURE;
+ }
+ else {
+ if(G.vd->drawtype==OB_SOLID || G.vd->drawtype==OB_SHADED) G.vd->drawtype= OB_WIRE;
+ else G.vd->drawtype= OB_SOLID;
+ }
+
+ if(G.vd->drawtype != OB_WIRE && G.vd->depths) {
+ G.vd->depths->damaged= 1;
+ }
+}
+
+int minmax_verts(float *min, float *max)
+{
+ TransVert *tv;
+ float centroid[3], vec[3], bmat[3][3];
+ int a;
+
+ tottrans=0;
+ if ELEM5(G.obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE)
+ make_trans_verts(bmat[0], bmat[1], 0);
+ if(tottrans==0) return 0;
+
+ Mat3CpyMat4(bmat, G.obedit->obmat);
+
+ tv= transvmain;
+ for(a=0; a<tottrans; a++, tv++) {
+ VECCOPY(vec, tv->loc);
+ Mat3MulVecfl(bmat, vec);
+ VecAddf(vec, vec, G.obedit->obmat[3]);
+ VecAddf(centroid, centroid, vec);
+ DO_MINMAX(vec, min, max);
+ }
+
+ MEM_freeN(transvmain);
+ transvmain= 0;
+ return 1;
+}
+
diff --git a/source/blender/src/editaction.c b/source/blender/src/editaction.c
new file mode 100644
index 00000000000..48a39875cc2
--- /dev/null
+++ b/source/blender/src/editaction.c
@@ -0,0 +1,2916 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): 2007, Joshua Leung (major rewrite of Action Editor)
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <string.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "PIL_time.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "DNA_action_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_key_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_nla_types.h"
+#include "DNA_lattice_types.h"
+
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_constraint.h"
+#include "BKE_curve.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_ipo.h"
+#include "BKE_key.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_utildefines.h"
+#include "BKE_object.h" /* for where_is_object in obanim -> action baking */
+
+#include "BIF_butspace.h"
+#include "BIF_editaction.h"
+#include "BIF_editarmature.h"
+#include "BIF_editnla.h"
+#include "BIF_editview.h"
+#include "BIF_gl.h"
+#include "BIF_interface.h"
+#include "BIF_mywindow.h"
+#include "BIF_poseobject.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_toolbox.h"
+#include "BIF_transform.h"
+
+#include "BSE_edit.h"
+#include "BSE_drawipo.h"
+#include "BSE_headerbuttons.h"
+#include "BSE_editaction_types.h"
+#include "BSE_editipo.h"
+#include "BSE_time.h"
+#include "BSE_trans_types.h"
+
+#include "BDR_drawaction.h"
+#include "BDR_editobject.h"
+
+#include "mydevice.h"
+#include "blendef.h"
+#include "nla.h"
+
+/* **************************************************** */
+/* ACTION API */
+
+/* this function adds a new Action block */
+bAction *add_empty_action (char *name)
+{
+ bAction *act;
+
+ act= alloc_libblock(&G.main->action, ID_AC, name);
+ act->id.flag |= LIB_FAKEUSER;
+ act->id.us++;
+
+ return act;
+}
+
+/* generic get current action call, for action window context */
+bAction *ob_get_action (Object *ob)
+{
+ bActionStrip *strip;
+
+ if(ob->action)
+ return ob->action;
+
+ for (strip=ob->nlastrips.first; strip; strip=strip->next) {
+ if (strip->flag & ACTSTRIP_SELECT)
+ return strip->act;
+ }
+ return NULL;
+}
+
+/* used by ipo, outliner, buttons to find the active channel */
+bActionChannel *get_hilighted_action_channel (bAction *action)
+{
+ bActionChannel *achan;
+
+ if (!action)
+ return NULL;
+
+ for (achan= action->chanbase.first; achan; achan= achan->next) {
+ if(VISIBLE_ACHAN(achan)) {
+ if (SEL_ACHAN(achan) && (achan->flag & ACHAN_HILIGHTED))
+ return achan;
+ }
+ }
+
+ return NULL;
+}
+
+/* ----------------------------------------- */
+
+void remake_action_ipos (bAction *act)
+{
+ bActionChannel *achan;
+ bConstraintChannel *conchan;
+ IpoCurve *icu;
+
+ for (achan= act->chanbase.first; achan; achan= achan->next) {
+ if (achan->ipo) {
+ for (icu = achan->ipo->curve.first; icu; icu=icu->next) {
+ sort_time_ipocurve(icu);
+ testhandles_ipocurve(icu);
+ }
+ }
+ for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next){
+ if (conchan->ipo) {
+ for (icu = conchan->ipo->curve.first; icu; icu=icu->next){
+ sort_time_ipocurve(icu);
+ testhandles_ipocurve(icu);
+ }
+ }
+ }
+ }
+
+ synchronize_action_strips();
+}
+
+/* **************************************************** */
+/* FILTER->EDIT STRUCTURES */
+/*
+ * This method involves generating a list of edit structures which enable
+ * tools to naively perform the actions they require without all the boiler-plate
+ * associated with loops within loops and checking for cases to ignore.
+ */
+
+/* this function allocates memory for a new bActListElem struct for the
+ * provided action channel-data.
+ */
+bActListElem *make_new_actlistelem (void *data, short datatype, void *owner, short ownertype)
+{
+ bActListElem *ale= NULL;
+
+ /* only allocate memory if there is data to convert */
+ if (data) {
+ /* allocate and set generic data */
+ ale= MEM_callocN(sizeof(bActListElem), "bActListElem");
+
+ ale->data= data;
+ ale->type= datatype;
+ ale->owner= owner;
+ ale->ownertype= ownertype;
+
+ /* do specifics */
+ switch (datatype) {
+ case ACTTYPE_ACHAN:
+ {
+ bActionChannel *achan= (bActionChannel *)data;
+
+ ale->flag= achan->flag;
+
+ if (achan->ipo) {
+ ale->key_data= achan->ipo;
+ ale->datatype= ALE_IPO;
+ }
+ else {
+ ale->key_data= NULL;
+ ale->datatype= ALE_NONE;
+ }
+ }
+ break;
+ case ACTTYPE_CONCHAN:
+ {
+ bConstraintChannel *conchan= (bConstraintChannel *)data;
+
+ ale->flag= conchan->flag;
+
+ if (conchan->ipo && conchan->ipo->curve.first) {
+ /* we assume that constraint ipo blocks only have 1 curve:
+ * INFLUENCE, so we pretend that a constraint channel is
+ * really just a Ipo-Curve channel instead.
+ */
+ ale->key_data= conchan->ipo->curve.first;
+ ale->datatype= ALE_ICU;
+ }
+ else {
+ ale->key_data= NULL;
+ ale->datatype= ALE_NONE;
+ }
+ }
+ break;
+ case ACTTYPE_ICU:
+ {
+ IpoCurve *icu= (IpoCurve *)data;
+
+ ale->flag= icu->flag;
+ ale->key_data= icu;
+ ale->datatype= ALE_ICU;
+ }
+ break;
+
+ case ACTTYPE_FILLIPO:
+ case ACTTYPE_FILLCON:
+ {
+ bActionChannel *achan= (bActionChannel *)data;
+
+ if (datatype == ACTTYPE_FILLIPO)
+ ale->flag= FILTER_IPO_ACHAN(achan);
+ else
+ ale->flag= FILTER_CON_ACHAN(achan);
+
+ ale->key_data= NULL;
+ ale->datatype= ALE_NONE;
+ }
+ break;
+ case ACTTYPE_IPO:
+ {
+ ale->flag= 0;
+ ale->key_data= data;
+ ale->datatype= ALE_IPO;
+ }
+ break;
+ }
+ }
+
+ /* return created datatype */
+ return ale;
+}
+
+/* ----------------------------------------- */
+
+static void actdata_filter_action (ListBase *act_data, bAction *act, int filter_mode)
+{
+ bActListElem *ale;
+ bActionChannel *achan;
+ bConstraintChannel *conchan;
+ IpoCurve *icu;
+
+ /* loop over action channels, performing the necessary checks */
+ for (achan= act->chanbase.first; achan; achan= achan->next) {
+ /* only work with this channel and its subchannels if it is visible */
+ if (!(filter_mode & ACTFILTER_VISIBLE) || VISIBLE_ACHAN(achan)) {
+ /* only work with this channel and its subchannels if it is editable */
+ if (!(filter_mode & ACTFILTER_FOREDIT) || EDITABLE_ACHAN(achan)) {
+ /* check if this achan should only be included if it is selected */
+ if (!(filter_mode & ACTFILTER_SEL) || SEL_ACHAN(achan)) {
+ /* are we only interested in the ipo-curves? */
+ if ((filter_mode & ACTFILTER_ONLYICU)==0) {
+ ale= make_new_actlistelem(achan, ACTTYPE_ACHAN, achan, ACTTYPE_ACHAN);
+ if (ale) BLI_addtail(act_data, ale);
+ }
+ }
+ else {
+ /* only consider selected channels - achan not selected */
+ continue;
+ }
+
+ /* check if expanded - if not, continue on to next action channel */
+ if (EXPANDED_ACHAN(achan) == 0 && (filter_mode & ACTFILTER_ONLYICU)==0)
+ continue;
+
+ /* ipo channels */
+ if (achan->ipo) {
+ /* include ipo-expand widget? */
+ if ((filter_mode & ACTFILTER_CHANNELS) && (filter_mode & ACTFILTER_ONLYICU)==0) {
+ ale= make_new_actlistelem(achan, ACTTYPE_FILLIPO, achan, ACTTYPE_ACHAN);
+ if (ale) BLI_addtail(act_data, ale);
+ }
+
+ /* add ipo-curve channels? */
+ if (FILTER_IPO_ACHAN(achan) || (filter_mode & ACTFILTER_ONLYICU)) {
+ /* loop through ipo-curve channels, adding them */
+ for (icu= achan->ipo->curve.first; icu; icu=icu->next) {
+ ale= make_new_actlistelem(icu, ACTTYPE_ICU, achan, ACTTYPE_ACHAN);
+ if (ale) BLI_addtail(act_data, ale);
+ }
+ }
+ }
+
+ /* constraint channels */
+ if (achan->constraintChannels.first) {
+ /* include constraint-expand widget? */
+ if ((filter_mode & ACTFILTER_CHANNELS) && (filter_mode & ACTFILTER_ONLYICU)==0) {
+ ale= make_new_actlistelem(achan, ACTTYPE_FILLCON, achan, ACTTYPE_ACHAN);
+ if (ale) BLI_addtail(act_data, ale);
+ }
+
+ /* add constaint channels? */
+ if (FILTER_CON_ACHAN(achan)) {
+ /* loop through constraint channels, checking and adding them */
+ for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next) {
+ /* only work with this channel and its subchannels if it is editable */
+ if (!(filter_mode & ACTFILTER_FOREDIT) || EDITABLE_CONCHAN(conchan)) {
+ /* check if this conchan should only be included if it is selected */
+ if (!(filter_mode & ACTFILTER_SEL) || SEL_CONCHAN(conchan)) {
+ if ((filter_mode & ACTFILTER_ONLYICU)==0) {
+ ale= make_new_actlistelem(conchan, ACTTYPE_CONCHAN, achan, ACTTYPE_ACHAN);
+ if (ale) BLI_addtail(act_data, ale);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+static void actdata_filter_shapekey (ListBase *act_data, Key *key, int filter_mode)
+{
+ bActListElem *ale;
+ KeyBlock *kb;
+ IpoCurve *icu;
+ int i;
+
+ /* are we filtering for display or editing */
+ if (filter_mode & ACTFILTER_FORDRAWING) {
+ /* for display - loop over shapekeys, adding ipo-curve references where needed */
+ kb= key->block.first;
+
+ /* loop through possible shapekeys, manually creating entries */
+ for (i= 1; i < key->totkey; i++) {
+ ale= MEM_callocN(sizeof(bActListElem), "bActListElem");
+ kb = kb->next;
+
+ ale->data= kb;
+ ale->type= ACTTYPE_SHAPEKEY; /* 'abused' usage of this type */
+ ale->owner= key;
+ ale->ownertype= ACTTYPE_SHAPEKEY;
+ ale->datatype= ALE_NONE;
+ ale->index = i;
+
+ if (key->ipo) {
+ for (icu= key->ipo->curve.first; icu; icu=icu->next) {
+ if (icu->adrcode == i) {
+ ale->key_data= icu;
+ ale->datatype= ALE_ICU;
+ break;
+ }
+ }
+ }
+
+ BLI_addtail(act_data, ale);
+ }
+ }
+ else {
+ /* loop over ipo curves if present - for editing */
+ if (key->ipo) {
+ if (filter_mode & ACTFILTER_IPOKEYS) {
+ ale= make_new_actlistelem(key->ipo, ACTTYPE_IPO, key, ACTTYPE_SHAPEKEY);
+ if (ale) BLI_addtail(act_data, ale);
+ }
+ else {
+ for (icu= key->ipo->curve.first; icu; icu=icu->next) {
+ ale= make_new_actlistelem(icu, ACTTYPE_ICU, key, ACTTYPE_SHAPEKEY);
+ if (ale) BLI_addtail(act_data, ale);
+ }
+ }
+ }
+ }
+}
+
+/* This function filters the active data source to leave only the desired
+ * data types. 'Public' api call.
+ * *act_data: is a pointer to a ListBase, to which the filtered action data
+ * will be placed for use.
+ * filter_mode: how should the data be filtered - bitmapping accessed flags
+ */
+void actdata_filter (ListBase *act_data, int filter_mode, void *data, short datatype)
+{
+ /* only filter data if there's somewhere to put it */
+ if (data && act_data) {
+ bActListElem *ale, *next;
+
+ /* firstly filter the data */
+ switch (datatype) {
+ case ACTCONT_ACTION:
+ actdata_filter_action(act_data, data, filter_mode);
+ break;
+ case ACTCONT_SHAPEKEY:
+ actdata_filter_shapekey(act_data, data, filter_mode);
+ break;
+ }
+
+ /* remove any weedy entries */
+ for (ale= act_data->first; ale; ale= next) {
+ next= ale->next;
+
+ if (ale->type == ACTTYPE_NONE)
+ BLI_freelinkN(act_data, ale);
+
+ if (filter_mode & ACTFILTER_IPOKEYS) {
+ if (ale->datatype != ALE_IPO)
+ BLI_freelinkN(act_data, ale);
+ else if (ale->key_data == NULL)
+ BLI_freelinkN(act_data, ale);
+ }
+ }
+ }
+}
+
+/* **************************************************** */
+/* GENERAL ACTION TOOLS */
+
+
+/* gets the key data from the currently selected
+ * mesh/lattice. If a mesh is not selected, or does not have
+ * key data, then we return NULL (currently only
+ * returns key data for RVK type meshes). If there
+ * is an action that is pinned, return null
+ */
+/* Note: there's a similar function in key.c (ob_get_key) */
+Key *get_action_mesh_key(void)
+{
+ Object *ob;
+ Key *key;
+
+ ob = OBACT;
+ if (ob == NULL)
+ return NULL;
+
+ if (G.saction->pin) return NULL;
+
+ if (ob->type==OB_MESH)
+ key = ((Mesh *)ob->data)->key;
+ else if (ob->type==OB_LATTICE)
+ key = ((Lattice *)ob->data)->key;
+ else
+ return NULL;
+
+ if (key) {
+ if (key->type == KEY_RELATIVE)
+ return key;
+ }
+
+ return NULL;
+}
+
+/* TODO: kill this! */
+int get_nearest_key_num (Key *key, short *mval, float *x)
+{
+ /* returns the key num that cooresponds to the
+ * y value of the mouse click. Does not check
+ * if this is a valid keynum. Also gives the Ipo
+ * x coordinate.
+ */
+ int num;
+ float y;
+
+ areamouseco_to_ipoco(G.v2d, mval, x, &y);
+ num = (int) ((CHANNELHEIGHT/2 - y) / (CHANNELHEIGHT+CHANNELSKIP));
+
+ return (num + 1);
+}
+
+/* this function is used to get a pointer to an action or shapekey
+ * datablock, thus simplying that process.
+ */
+/* this function is intended for use */
+void *get_nearest_act_channel (short mval[], short *ret_type)
+{
+ ListBase act_data = {NULL, NULL};
+ bActListElem *ale;
+ void *data;
+ short datatype;
+ int filter;
+
+ int clickmin, clickmax;
+ float x,y;
+
+ /* determine what type of data we are operating on */
+ data = get_action_context(&datatype);
+ if (data == NULL) {
+ *ret_type= ACTTYPE_NONE;
+ return NULL;
+ }
+
+ areamouseco_to_ipoco(G.v2d, mval, &x, &y);
+ clickmin = (int) (((CHANNELHEIGHT/2) - y) / (CHANNELHEIGHT+CHANNELSKIP));
+ clickmax = clickmin;
+
+ if (clickmax < 0) {
+ *ret_type= ACTTYPE_NONE;
+ return NULL;
+ }
+
+ /* filter data */
+ filter= (ACTFILTER_FORDRAWING | ACTFILTER_VISIBLE | ACTFILTER_CHANNELS);
+ actdata_filter(&act_data, filter, data, datatype);
+
+ for (ale= act_data.first; ale; ale= ale->next) {
+ if (clickmax < 0)
+ break;
+ if (clickmin <= 0) {
+ /* found match */
+ *ret_type= ale->type;
+ data= ale->data;
+
+ BLI_freelistN(&act_data);
+
+ return data;
+ }
+ --clickmin;
+ --clickmax;
+ }
+
+ /* cleanup */
+ BLI_freelistN(&act_data);
+
+ *ret_type= ACTTYPE_NONE;
+ return NULL;
+}
+
+/* used only by mouse_action. It is used to find the location of the nearest
+ * keyframe to where the mouse clicked,
+ */
+static void *get_nearest_action_key (float *selx, short *sel, short *ret_type, bActionChannel **par)
+{
+ ListBase act_data = {NULL, NULL};
+ ListBase act_keys = {NULL, NULL};
+ bActListElem *ale;
+ ActKeyColumn *ak;
+ void *data;
+ short datatype;
+ int filter;
+
+ rctf rectf;
+ float xmin, xmax, x, y;
+ int clickmin, clickmax;
+ short mval[2];
+ short found = 0;
+
+ getmouseco_areawin (mval);
+
+ /* action-channel */
+ *par= NULL;
+
+ /* determine what type of data we are operating on */
+ data = get_action_context(&datatype);
+ if (data == NULL) {
+ *ret_type= ACTTYPE_NONE;
+ return NULL;
+ }
+
+ areamouseco_to_ipoco(G.v2d, mval, &x, &y);
+ clickmin = (int) (((CHANNELHEIGHT/2) - y) / (CHANNELHEIGHT+CHANNELSKIP));
+ clickmax = clickmin;
+
+ mval[0]-=7;
+ areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
+ mval[0]+=14;
+ areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
+
+ /* if action is mapped in NLA, it returns a correction */
+ if (NLA_ACTION_SCALED && datatype==ACTCONT_ACTION) {
+ xmin= get_action_frame(OBACT, rectf.xmin);
+ xmax= get_action_frame(OBACT, rectf.xmax);
+ }
+ else {
+ xmin= rectf.xmin;
+ xmax= rectf.xmax;
+ }
+
+ if (clickmax < 0) {
+ *ret_type= ACTTYPE_NONE;
+ return NULL;
+ }
+
+ /* filter data */
+ filter= (ACTFILTER_FORDRAWING | ACTFILTER_VISIBLE | ACTFILTER_CHANNELS);
+ actdata_filter(&act_data, filter, data, datatype);
+
+ for (ale= act_data.first; ale; ale= ale->next) {
+ if (clickmax < 0)
+ break;
+ if (clickmin <= 0) {
+ /* found match */
+
+ /* make list of keyframes */
+ if (ale->key_data) {
+ switch (ale->datatype) {
+ case ALE_IPO:
+ {
+ Ipo *ipo= (Ipo *)ale->key_data;
+ ipo_to_keylist(ipo, &act_keys, NULL);
+ }
+ break;
+ case ALE_ICU:
+ {
+ IpoCurve *icu= (IpoCurve *)ale->key_data;
+ icu_to_keylist(icu, &act_keys, NULL);
+ }
+ break;
+ }
+ }
+
+ /* loop through keyframes, finding one that was clicked on */
+ for (ak= act_keys.first; ak; ak= ak->next) {
+ if (IN_RANGE(ak->cfra, xmin, xmax)) {
+ *selx= ak->cfra;
+ found= 1;
+ break;
+ }
+ }
+ /* no matching keyframe found - set to mean frame value so it doesn't actually select anything */
+ if (found == 0)
+ *selx= ((xmax+xmin) / 2);
+
+ /* figure out what to return */
+ if (datatype == ACTCONT_ACTION) {
+ *par= ale->owner; /* assume that this is an action channel */
+ *ret_type= ale->type;
+ data = ale->data;
+ }
+ else if (datatype == ACTCONT_SHAPEKEY) {
+ data = ale->key_data;
+ *ret_type= ACTTYPE_ICU;
+ }
+
+ /* cleanup tempolary lists */
+ BLI_freelistN(&act_keys);
+ act_keys.first = act_keys.last = NULL;
+
+ BLI_freelistN(&act_data);
+
+ return data;
+ }
+ --clickmin;
+ --clickmax;
+ }
+
+ /* cleanup */
+ BLI_freelistN(&act_data);
+
+ *ret_type= ACTTYPE_NONE;
+ return NULL;
+}
+
+void *get_action_context (short *datatype)
+{
+ bAction *act;
+ Key *key;
+
+ /* get pointers to active action/shapekey blocks */
+ act = (G.saction)? G.saction->action: NULL;
+ key = get_action_mesh_key();
+
+ if (act) {
+ *datatype= ACTCONT_ACTION;
+ return act;
+ }
+ else if (key) {
+ *datatype= ACTCONT_SHAPEKEY;
+ return key;
+ }
+ else {
+ *datatype= ACTCONT_NONE;
+ return NULL;
+ }
+}
+
+/* **************************************************** */
+/* TRANSFORM TOOLS */
+
+/* main call to start transforming keyframes */
+void transform_action_keys (int mode, int dummy)
+{
+ void *data;
+ short datatype;
+
+ /* determine what type of data we are operating on */
+ data = get_action_context(&datatype);
+ if (data == NULL) return;
+
+ switch (mode) {
+ case 'g':
+ {
+ initTransform(TFM_TIME_TRANSLATE, CTX_NONE);
+ Transform();
+ }
+ break;
+ case 's':
+ {
+ initTransform(TFM_TIME_SCALE, CTX_NONE);
+ Transform();
+ }
+ break;
+ case 't':
+ {
+ initTransform(TFM_TIME_SLIDE, CTX_NONE);
+ Transform();
+ }
+ break;
+ case 'e':
+ {
+ initTransform(TFM_TIME_EXTEND, CTX_NONE);
+ Transform();
+ }
+ break;
+ }
+}
+
+/* ----------------------------------------- */
+
+/* duplicate keyframes */
+void duplicate_action_keys (void)
+{
+ ListBase act_data = {NULL, NULL};
+ bActListElem *ale;
+ void *data;
+ short datatype;
+ int filter;
+
+ /* determine what type of data we are operating on */
+ data = get_action_context(&datatype);
+ if (data == NULL) return;
+
+ /* filter data */
+ filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS);
+ actdata_filter(&act_data, filter, data, datatype);
+
+ /* loop through filtered data and duplicate selected keys */
+ for (ale= act_data.first; ale; ale= ale->next) {
+ duplicate_ipo_keys((Ipo *)ale->key_data);
+ }
+
+ /* free filtered list */
+ BLI_freelistN(&act_data);
+
+ /* now, go into transform-grab mode, to move keys */
+ transform_action_keys('g', 0);
+}
+
+/* this function is responsible for snapping keyframes to frame-times */
+void snap_action_keys(short mode)
+{
+ ListBase act_data = {NULL, NULL};
+ bActListElem *ale;
+ int filter;
+ void *data;
+ short datatype;
+ char str[32];
+
+ /* get data */
+ data= get_action_context(&datatype);
+ if (data == NULL) return;
+
+ /* determine mode */
+ switch (mode) {
+ case 1:
+ strcpy(str, "Snap Keys To Nearest Frame");
+ break;
+ case 2:
+ if (G.saction->flag & SACTION_DRAWTIME)
+ strcpy(str, "Snap Keys To Current Time");
+ else
+ strcpy(str, "Snap Keys To Current Frame");
+ break;
+ case 3:
+ strcpy(str, "Snap Keys To Nearest Marker");
+ break;
+ case 4:
+ strcpy(str, "Snap Keys To Nearest Second");
+ break;
+ default:
+ return;
+ }
+
+ /* filter data */
+ filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS);
+ actdata_filter(&act_data, filter, data, datatype);
+
+ /* snap to frame */
+ for (ale= act_data.first; ale; ale= ale->next) {
+ if (NLA_ACTION_SCALED && datatype==ACTCONT_ACTION) {
+ actstrip_map_ipo_keys(OBACT, ale->key_data, 0, 1);
+ snap_ipo_keys(ale->key_data, mode);
+ actstrip_map_ipo_keys(OBACT, ale->key_data, 1, 1);
+ }
+ else
+ snap_ipo_keys(ale->key_data, mode);
+ }
+ BLI_freelistN(&act_data);
+
+ if (datatype == ACTCONT_ACTION)
+ remake_action_ipos(data);
+
+ BIF_undo_push(str);
+ allspace(REMAKEIPO, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWNLA, 0);
+}
+
+/* this function is responsible for snapping keyframes to frame-times */
+void mirror_action_keys(short mode)
+{
+ ListBase act_data = {NULL, NULL};
+ bActListElem *ale;
+ int filter;
+ void *data;
+ short datatype;
+ char str[32];
+
+ /* get data */
+ data= get_action_context(&datatype);
+ if (data == NULL) return;
+
+ /* determine mode */
+ switch (mode) {
+ case 1:
+ strcpy(str, "Mirror Keys Over Current Frame");
+ break;
+ case 2:
+ strcpy(str, "Mirror Keys Over Y-Axis");
+ break;
+ case 3:
+ strcpy(str, "Mirror Keys Over X-Axis");
+ break;
+ case 4:
+ strcpy(str, "Mirror Keys Over Marker");
+ break;
+ default:
+ return;
+ }
+
+ /* filter data */
+ filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS);
+ actdata_filter(&act_data, filter, data, datatype);
+
+ /* mirror */
+ for (ale= act_data.first; ale; ale= ale->next) {
+ if (NLA_ACTION_SCALED && datatype==ACTCONT_ACTION) {
+ actstrip_map_ipo_keys(OBACT, ale->key_data, 0, 1);
+ mirror_ipo_keys(ale->key_data, mode);
+ actstrip_map_ipo_keys(OBACT, ale->key_data, 1, 1);
+ }
+ else
+ mirror_ipo_keys(ale->key_data, mode);
+ }
+ BLI_freelistN(&act_data);
+
+ if (datatype == ACTCONT_ACTION)
+ remake_action_ipos(data);
+
+ BIF_undo_push(str);
+ allspace(REMAKEIPO, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWNLA, 0);
+}
+
+/* **************************************************** */
+/* ADD/REMOVE KEYFRAMES */
+
+/* This function allows the user to insert keyframes on the current
+ * frame from the Action Editor, using the current values of the channels
+ * to be keyframed.
+ */
+void insertkey_action(void)
+{
+ void *data;
+ short datatype;
+
+ Object *ob= OBACT;
+ short mode;
+ float cfra;
+
+ /* get data */
+ data= get_action_context(&datatype);
+ if (data == NULL) return;
+ cfra = frame_to_float(CFRA);
+
+ if (datatype == ACTCONT_ACTION) {
+ ListBase act_data = {NULL, NULL};
+ bActListElem *ale;
+ int filter;
+
+ /* ask user what to keyframe */
+ mode = pupmenu("Insert Key%t|All Channels%x1|Only Selected Channels%x2");
+ if (mode <= 0) return;
+
+ /* filter data */
+ filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_ONLYICU );
+ if (mode == 2) filter |= ACTFILTER_SEL;
+
+ actdata_filter(&act_data, filter, data, datatype);
+
+ /* loop through ipo curves retrieved */
+ for (ale= act_data.first; ale; ale= ale->next) {
+ /* verify that this is indeed an ipo curve */
+ if (ale->key_data && ale->owner) {
+ bActionChannel *achan= (bActionChannel *)ale->owner;
+ IpoCurve *icu= (IpoCurve *)ale->key_data;
+
+ if (ob)
+ insertkey((ID *)ob, icu->blocktype, achan->name, NULL, icu->adrcode, 0);
+ else
+ insert_vert_icu(icu, cfra, icu->curval, 0);
+ }
+ }
+
+ /* cleanup */
+ BLI_freelistN(&act_data);
+ }
+ else if (datatype == ACTCONT_SHAPEKEY) {
+ Key *key= (Key *)data;
+ IpoCurve *icu;
+
+ /* ask user if they want to insert a keyframe */
+ mode = okee("Insert Keyframe?");
+ if (mode <= 0) return;
+
+ if (key->ipo) {
+ for (icu= key->ipo->curve.first; icu; icu=icu->next) {
+ insert_vert_icu(icu, cfra, icu->curval, 0);
+ }
+ }
+ }
+
+ BIF_undo_push("Insert Key");
+ allspace(REMAKEIPO, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWNLA, 0);
+}
+
+/* delete selected keyframes */
+void delete_action_keys (void)
+{
+ ListBase act_data = {NULL, NULL};
+ bActListElem *ale;
+ void *data;
+ short datatype;
+ int filter;
+
+ /* determine what type of data we are operating on */
+ data = get_action_context(&datatype);
+ if (data == NULL) return;
+
+ /* filter data */
+ filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS);
+ actdata_filter(&act_data, filter, data, datatype);
+
+ /* loop through filtered data and delete selected keys */
+ for (ale= act_data.first; ale; ale= ale->next) {
+ delete_ipo_keys((Ipo *)ale->key_data);
+ }
+
+ /* free filtered list */
+ BLI_freelistN(&act_data);
+
+ if (datatype == ACTCONT_ACTION)
+ remake_action_ipos(data);
+
+ BIF_undo_push("Delete Action Keys");
+ allspace(REMAKEIPO, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWNLA, 0);
+}
+
+/* delete selected keyframes */
+void delete_action_channels (void)
+{
+ ListBase act_data = {NULL, NULL};
+ bActListElem *ale, *next;
+ bAction *act;
+ void *data;
+ short datatype;
+ int filter;
+
+ /* determine what type of data we are operating on */
+ data = get_action_context(&datatype);
+ if (data == NULL) return;
+ if (datatype != ACTCONT_ACTION) return;
+ act= (bAction *)data;
+
+ /* filter data */
+ filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_CHANNELS | ACTFILTER_SEL);
+ actdata_filter(&act_data, filter, data, datatype);
+
+ /* remove irrelevant entries */
+ for (ale= act_data.first; ale; ale= next) {
+ next= ale->next;
+
+ if (ale->type != ACTTYPE_ACHAN)
+ BLI_freelinkN(&act_data, ale);
+ }
+
+ /* clean up action channels */
+ for (ale= act_data.first; ale; ale= next) {
+ bActionChannel *achan= (bActionChannel *)ale->data;
+ bConstraintChannel *conchan, *cnext;
+ next= ale->next;
+
+ /* release reference to ipo users */
+ if (achan->ipo)
+ achan->ipo->id.us--;
+
+ for (conchan= achan->constraintChannels.first; conchan; conchan=cnext) {
+ cnext= conchan->next;
+
+ if (conchan->ipo)
+ conchan->ipo->id.us--;
+ }
+
+ /* free memory */
+ BLI_freelistN(&achan->constraintChannels);
+ BLI_freelinkN(&act->chanbase, achan);
+ BLI_freelinkN(&act_data, ale);
+ }
+
+ remake_action_ipos(data);
+
+ BIF_undo_push("Delete Action Channels");
+ allspace(REMAKEIPO, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWNLA, 0);
+}
+
+/* 'Clean' IPO curves - remove any unnecessary keyframes */
+void clean_action (void)
+{
+ ListBase act_data = {NULL, NULL};
+ bActListElem *ale;
+ int filter;
+ void *data;
+ short datatype, ok;
+
+ /* don't proceed any further if nothing to work on or user refuses */
+ data= get_action_context(&datatype);
+ ok= fbutton(&G.scene->toolsettings->clean_thresh,
+ 0.0000001f, 1.0, 0.001, 0.1,
+ "Clean Threshold");
+ if (!ok) return;
+
+ /* filter data */
+ filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_SEL | ACTFILTER_ONLYICU);
+ actdata_filter(&act_data, filter, data, datatype);
+
+ /* loop through filtered data and clean curves */
+ for (ale= act_data.first; ale; ale= ale->next) {
+ clean_ipo_curve((IpoCurve *)ale->key_data);
+ }
+
+ /* admin and redraws */
+ BLI_freelistN(&act_data);
+
+ BIF_undo_push("Clean Action");
+ allqueue(REMAKEIPO, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWNLA, 0);
+}
+
+/* **************************************************** */
+/* COPY/PASTE FOR ACTIONS */
+/* - The copy/paste buffer currently stores a set of IPO curves, with no
+ * repeating curve-types (i.e. no curves with the same adrcode).
+ * - Only selected keyframes from the source curves are placed here.
+ * - Only 'compatible' pastes are done.
+ */
+
+/* globals for copy/paste data (like for other copy/paste buffers) */
+ListBase actcopybuf = {NULL, NULL};
+
+/* This function frees any MEM_calloc'ed copy/paste buffer data */
+void free_actcopybuf ()
+{
+ IpoCurve *icu;
+
+ while( (icu= actcopybuf.first) ) {
+ BLI_remlink(&actcopybuf, icu);
+ free_ipo_curve(icu);
+ }
+}
+
+/* This function adds data to the copy/paste buffer, freeing existing data first
+ * Only the active action channel gets its selected keyframes copied.
+ */
+void copy_actdata ()
+{
+ ListBase act_data = {NULL, NULL};
+ bActListElem *ale;
+ int filter;
+ void *data;
+ short datatype;
+
+ /* clear buffer first */
+ free_actcopybuf();
+
+ /* get data */
+ data= get_action_context(&datatype);
+ if (data == NULL) return;
+
+ /* filter data */
+ filter= (ACTFILTER_VISIBLE | ACTFILTER_SEL | ACTFILTER_ONLYICU);
+ actdata_filter(&act_data, filter, data, datatype);
+
+ /* each of these entries should be an ipo curve */
+ for (ale= act_data.first; ale; ale= ale->next) {
+ IpoCurve *icu= ale->key_data;
+ IpoCurve *icn;
+ BezTriple *bezt;
+ short nin_buffer= 1;
+ int i;
+
+ /* check if a curve like this exists already in buffer */
+ for (icn= actcopybuf.first; icn; icn= icn->next) {
+ if ((icn->blocktype==icu->blocktype) && (icn->adrcode==icu->adrcode)) {
+ nin_buffer= 0;
+ break;
+ }
+ }
+ /* allocate memory for a new curve if a valid one wasn't found */
+ if (nin_buffer) {
+ icn= MEM_callocN(sizeof(IpoCurve), "actcopybuf");
+
+ *icn= *icu;
+ icn->totvert= 0;
+ icn->bezt = NULL;
+ icn->driver = NULL;
+
+ BLI_addtail(&actcopybuf, icn);
+ }
+
+ /* find selected BezTriples to add to the buffer */
+ for (i=0, bezt=icu->bezt; i < icu->totvert; i++, bezt++) {
+ if (BEZSELECTED(bezt))
+ insert_bezt_icu(icn, bezt);
+ }
+ }
+
+ /* check if anything ended up in the buffer */
+ if (actcopybuf.first==NULL || actcopybuf.last==NULL)
+ error("Nothing copied to buffer");
+
+ /* free temp memory */
+ BLI_freelistN(&act_data);
+}
+
+void paste_actdata ()
+{
+ ListBase act_data = {NULL, NULL};
+ bActListElem *ale;
+ int filter;
+ void *data;
+ short datatype;
+
+ /* check if buffer is empty */
+ if (actcopybuf.first==NULL || actcopybuf.last==NULL) {
+ error("No data in buffer to paste");
+ return;
+ }
+
+ /* get data */
+ data= get_action_context(&datatype);
+ if (data == NULL) return;
+
+ /* filter data */
+ filter= (ACTFILTER_VISIBLE | ACTFILTER_SEL | ACTFILTER_FOREDIT | ACTFILTER_ONLYICU);
+ actdata_filter(&act_data, filter, data, datatype);
+
+ /* from selected channels */
+ for (ale= act_data.first; ale; ale= ale->next) {
+ IpoCurve *icu= ale->key_data;
+ IpoCurve *ico;
+ BezTriple *bezt;
+ int i;
+ float offset= 0.0f;
+ short offsetInit= 1;
+
+ /* find matching ipo-curve */
+ for (ico= actcopybuf.first; ico; ico= ico->next) {
+ if ((ico->blocktype==icu->blocktype) && (ico->adrcode==icu->adrcode)) {
+ /* just start pasting, with the the first keyframe on the current frame, and so on */
+ for (i=0, bezt=ico->bezt; i < ico->totvert; i++, bezt++) {
+ /* initialise offset (if not already done) */
+ if (offsetInit) {
+ offset= CFRA - bezt->vec[1][0];
+ offsetInit= 0;
+ }
+
+ /* temporarily apply offset to src beztriple while copying */
+ bezt->vec[0][0] += offset;
+ bezt->vec[1][0] += offset;
+ bezt->vec[2][0] += offset;
+
+ /* insert the keyframe */
+ insert_bezt_icu(icu, bezt);
+
+ /* un-apply offset from src beztriple after copying */
+ bezt->vec[0][0] -= offset;
+ bezt->vec[1][0] -= offset;
+ bezt->vec[2][0] -= offset;
+ }
+
+ /* recalculate channel's handles? */
+ calchandles_ipocurve(icu);
+
+ /* done for this channel */
+ break;
+ }
+ }
+ }
+
+ /* free temp memory */
+ BLI_freelistN(&act_data);
+
+ /* undo and redraw stuff */
+ allqueue(REDRAWVIEW3D, 0);
+ allspace(REMAKEIPO, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWNLA, 0);
+ BIF_undo_push("Paste Action Keyframes");
+}
+
+/* **************************************************** */
+/* VARIOUS SETTINGS */
+
+/* This function combines several features related to setting
+ * various ipo extrapolation/interpolation
+ */
+void action_set_ipo_flags (short mode, short event)
+{
+ ListBase act_data = {NULL, NULL};
+ bActListElem *ale;
+ void *data;
+ short datatype;
+ int filter;
+
+ /* determine what type of data we are operating on */
+ data = get_action_context(&datatype);
+ if (data == NULL) return;
+
+ /* determine which set of processing we are doing */
+ switch (mode) {
+ case SET_EXTEND_POPUP:
+ {
+ /* present popup menu for ipo extrapolation type */
+ event
+ = pupmenu("Channel Extending Type %t|"
+ "Constant %x11|"
+ "Extrapolation %x12|"
+ "Cyclic %x13|"
+ "Cyclic extrapolation %x14");
+ if (event < 1) return;
+ }
+ break;
+ case SET_IPO_POPUP:
+ {
+ /* present popup menu for ipo interpolation type */
+ event
+ = pupmenu("Channel Ipo Type %t|"
+ "Constant %x1|"
+ "Linear %x2|"
+ "Bezier %x3");
+ if (event < 1) return;
+ }
+ break;
+
+ case SET_IPO_MENU: /* called from menus */
+ case SET_EXTEND_MENU:
+ break;
+
+ default: /* weird, unhandled case */
+ return;
+ }
+
+ /* filter data */
+ filter= (ACTFILTER_VISIBLE | ACTFILTER_SEL | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS);
+ actdata_filter(&act_data, filter, data, datatype);
+
+ /* loop through setting flags */
+ for (ale= act_data.first; ale; ale= ale->next) {
+ Ipo *ipo= (Ipo *)ale->key_data;
+
+ /* depending on the mode */
+ switch (mode) {
+ case SET_EXTEND_POPUP: /* extrapolation */
+ case SET_EXTEND_MENU:
+ {
+ switch (event) {
+ case SET_EXTEND_CONSTANT:
+ setexprap_ipoloop(ipo, IPO_HORIZ);
+ break;
+ case SET_EXTEND_EXTRAPOLATION:
+ setexprap_ipoloop(ipo, IPO_DIR);
+ break;
+ case SET_EXTEND_CYCLIC:
+ setexprap_ipoloop(ipo, IPO_CYCL);
+ break;
+ case SET_EXTEND_CYCLICEXTRAPOLATION:
+ setexprap_ipoloop(ipo, IPO_CYCLX);
+ break;
+ }
+ }
+ break;
+ case SET_IPO_POPUP: /* interpolation */
+ case SET_IPO_MENU:
+ {
+ setipotype_ipo(ipo, event);
+ }
+ break;
+ }
+ }
+
+ /* cleanup */
+ BLI_freelistN(&act_data);
+
+ if (datatype == ACTCONT_ACTION)
+ remake_action_ipos(data);
+
+ BIF_undo_push("Set Ipo Type");
+ allspace(REMAKEIPO, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWNLA, 0);
+}
+
+/* this function sets the handles on keyframes */
+void sethandles_action_keys (int code)
+{
+ ListBase act_data = {NULL, NULL};
+ bActListElem *ale;
+ void *data;
+ short datatype;
+ int filter;
+
+ /* determine what type of data we are operating on */
+ data = get_action_context(&datatype);
+ if (data == NULL) return;
+
+ /* filter data */
+ filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS);
+ actdata_filter(&act_data, filter, data, datatype);
+
+ /* loop through setting flags */
+ for (ale= act_data.first; ale; ale= ale->next) {
+ sethandles_ipo_keys((Ipo *)ale->key_data, code);
+ }
+
+ /* cleanup */
+ BLI_freelistN(&act_data);
+ if (datatype == ACTCONT_ACTION)
+ remake_action_ipos(data);
+
+ BIF_undo_push("Set Handle Type");
+ allspace(REMAKEIPO, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWNLA, 0);
+}
+
+/* ----------------------------------------- */
+
+/* this gets called when nkey is pressed (no Transform Properties panel yet) */
+static void numbuts_action ()
+{
+ void *data;
+ short datatype;
+
+ void *act_channel;
+ short chantype;
+
+ bActionChannel *achan= NULL;
+ bConstraintChannel *conchan= NULL;
+ IpoCurve *icu= NULL;
+ KeyBlock *kb= NULL;
+
+ short mval[2];
+
+ int but=0;
+ char str[64];
+ short expand, protect, mute;
+ float slidermin, slidermax;
+
+
+ /* determine what type of data we are operating on */
+ data = get_action_context(&datatype);
+ if (data == NULL) return;
+
+ /* figure out what is under cursor */
+ getmouseco_areawin(mval);
+ if (mval[0] < NAMEWIDTH)
+ return;
+ act_channel= get_nearest_act_channel(mval, &chantype);
+
+ /* create items for clever-numbut */
+ if (chantype == ACTTYPE_ACHAN) {
+ /* Action Channel */
+ achan= (bActionChannel *)act_channel;
+
+ strcpy(str, achan->name);
+ protect= (achan->flag & ACHAN_PROTECTED);
+ expand = (achan->flag & ACHAN_EXPANDED);
+ mute = (achan->ipo)? (achan->ipo->muteipo): 0;
+
+ add_numbut(but++, TEX, "ActChan: ", 0, 31, str, "Name of Action Channel");
+ add_numbut(but++, TOG|SHO, "Expanded", 0, 24, &expand, "Action Channel is Expanded");
+ add_numbut(but++, TOG|SHO, "Muted", 0, 24, &mute, "Channel is Muted");
+ add_numbut(but++, TOG|SHO, "Protected", 0, 24, &protect, "Channel is Protected");
+ }
+ else if (chantype == ACTTYPE_CONCHAN) {
+ /* Constraint Channel */
+ conchan= (bConstraintChannel *)act_channel;
+
+ strcpy(str, conchan->name);
+ protect= (conchan->flag & CONSTRAINT_CHANNEL_PROTECTED);
+ mute = (conchan->ipo)? (conchan->ipo->muteipo): 0;
+
+ add_numbut(but++, TEX, "ConChan: ", 0, 29, str, "Name of Constraint Channel");
+ add_numbut(but++, TOG|SHO, "Muted", 0, 24, &mute, "Channel is Muted");
+ add_numbut(but++, TOG|SHO, "Protected", 0, 24, &protect, "Channel is Protected");
+ }
+ else if (chantype == ACTTYPE_ICU) {
+ /* IPO Curve */
+ icu= (IpoCurve *)act_channel;
+
+ if (G.saction->pin)
+ sprintf(str, getname_ipocurve(icu, NULL));
+ else
+ sprintf(str, getname_ipocurve(icu, OBACT));
+
+ if (IS_EQ(icu->slide_max, icu->slide_min)) {
+ if (IS_EQ(icu->ymax, icu->ymin)) {
+ icu->slide_min= -100.0;
+ icu->slide_max= 100.0;
+ }
+ else {
+ icu->slide_min= icu->ymin;
+ icu->slide_max= icu->ymax;
+ }
+ }
+ slidermin= icu->slide_min;
+ slidermax= icu->slide_max;
+
+ //protect= (icu->flag & IPO_PROTECT);
+ mute = (icu->flag & IPO_MUTE);
+
+ add_numbut(but++, NUM|FLO, "Slider Min:", -10000, slidermax, &slidermin, 0);
+ add_numbut(but++, NUM|FLO, "Slider Max:", slidermin, 10000, &slidermax, 0);
+ add_numbut(but++, TOG|SHO, "Muted", 0, 24, &mute, "Channel is Muted");
+ //add_numbut(but++, TOG|SHO, "Protected", 0, 24, &protect, "Channel is Protected");
+ }
+ else if (chantype == ACTTYPE_SHAPEKEY) {
+ /* Shape Key */
+ kb= (KeyBlock *)act_channel;
+
+ if (kb->name[0] == '\0') {
+ Key *key= (Key *)data;
+ int keynum= BLI_findindex(&key->block, kb);
+
+ sprintf(str, "Key %d", keynum);
+ }
+ else
+ strcpy(str, kb->name);
+
+ if (kb->slidermin >= kb->slidermax) {
+ kb->slidermin = 0.0;
+ kb->slidermax = 1.0;
+ }
+
+ add_numbut(but++, TEX, "KB: ", 0, 24, str,
+ "Does this really need a tool tip?");
+ add_numbut(but++, NUM|FLO, "Slider Min:",
+ -10000, kb->slidermax, &kb->slidermin, 0);
+ add_numbut(but++, NUM|FLO, "Slider Max:",
+ kb->slidermin, 10000, &kb->slidermax, 0);
+ }
+ else {
+ /* nothing under-cursor */
+ return;
+ }
+
+ /* draw clever-numbut */
+ if (do_clever_numbuts(str, but, REDRAW)) {
+ /* restore settings based on type */
+ if (icu) {
+ icu->slide_min= slidermin;
+ icu->slide_max= slidermax;
+
+ //if (protect) icu->flag |= IPO_PROTECT;
+ //else icu->flag &= ~IPO_PROTECT;
+ if (mute) icu->flag |= IPO_MUTE;
+ else icu->flag &= ~IPO_MUTE;
+ }
+ else if (conchan) {
+ strcpy(conchan->name, str);
+
+ if (protect) conchan->flag |= CONSTRAINT_CHANNEL_PROTECTED;
+ else conchan->flag &= ~CONSTRAINT_CHANNEL_PROTECTED;
+
+ if (conchan->ipo)
+ conchan->ipo->muteipo = mute;
+ }
+ else if (achan) {
+ strcpy(achan->name, str);
+
+ if (expand) achan->flag |= ACHAN_EXPANDED;
+ else achan->flag &= ~ACHAN_EXPANDED;
+
+ if (protect) achan->flag |= ACHAN_PROTECTED;
+ else achan->flag &= ~ACHAN_PROTECTED;
+
+ if (achan->ipo)
+ achan->ipo->muteipo = mute;
+ }
+
+ allqueue(REDRAWACTION, 0);
+ allspace(REMAKEIPO, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+}
+
+
+
+/* **************************************************** */
+/* CHANNEL SELECTION */
+
+static void hilight_channel(bAction *act, bActionChannel *achan, short select)
+{
+ bActionChannel *curchan;
+
+ if (!act)
+ return;
+
+ for (curchan=act->chanbase.first; curchan; curchan=curchan->next) {
+ if (curchan==achan && select)
+ curchan->flag |= ACHAN_HILIGHTED;
+ else
+ curchan->flag &= ~ACHAN_HILIGHTED;
+ }
+}
+
+/* messy call... */
+static void select_poseelement_by_name(char *name, int select)
+{
+ /* Syncs selection of channels with selection of object elements in posemode */
+ Object *ob= OBACT;
+ bPoseChannel *pchan;
+
+ if (!ob || ob->type!=OB_ARMATURE)
+ return;
+
+ if(select==2) {
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next)
+ pchan->bone->flag &= ~(BONE_ACTIVE);
+ }
+
+ pchan= get_pose_channel(ob->pose, name);
+ if(pchan) {
+ if(select)
+ pchan->bone->flag |= (BONE_SELECTED);
+ else
+ pchan->bone->flag &= ~(BONE_SELECTED);
+ if(select==2)
+ pchan->bone->flag |= (BONE_ACTIVE);
+ }
+}
+
+/* apparently within active object context */
+/* called extern, like on bone selection */
+void select_actionchannel_by_name (bAction *act, char *name, int select)
+{
+ bActionChannel *achan;
+
+ if (!act)
+ return;
+
+ for (achan = act->chanbase.first; achan; achan= achan->next) {
+ if (!strcmp(achan->name, name)) {
+ if (select) {
+ achan->flag |= ACHAN_SELECTED;
+ hilight_channel(act, achan, 1);
+ }
+ else {
+ achan->flag &= ~ACHAN_SELECTED;
+ hilight_channel(act, achan, 0);
+ }
+ return;
+ }
+ }
+}
+
+/* select_mode = SELECT_REPLACE
+ * = SELECT_ADD
+ * = SELECT_SUBTRACT
+ * = SELECT_INVERT
+ */
+
+/* exported for outliner (ton) */
+/* apparently within active object context */
+int select_channel(bAction *act, bActionChannel *achan, int selectmode)
+{
+ /* Select the channel based on the selection mode */
+ int flag;
+
+ switch (selectmode) {
+ case SELECT_ADD:
+ achan->flag |= ACHAN_SELECTED;
+ break;
+ case SELECT_SUBTRACT:
+ achan->flag &= ~ACHAN_SELECTED;
+ break;
+ case SELECT_INVERT:
+ achan->flag ^= ACHAN_SELECTED;
+ break;
+ }
+ flag = (achan->flag & ACHAN_SELECTED) ? 1 : 0;
+
+ hilight_channel(act, achan, flag);
+ select_poseelement_by_name(achan->name, flag);
+
+ return flag;
+}
+
+static int select_constraint_channel(bAction *act,
+ bConstraintChannel *conchan,
+ int selectmode)
+{
+ /* Select the constraint channel based on the selection mode */
+ int flag;
+
+ switch (selectmode) {
+ case SELECT_ADD:
+ conchan->flag |= CONSTRAINT_CHANNEL_SELECT;
+ break;
+ case SELECT_SUBTRACT:
+ conchan->flag &= ~CONSTRAINT_CHANNEL_SELECT;
+ break;
+ case SELECT_INVERT:
+ conchan->flag ^= CONSTRAINT_CHANNEL_SELECT;
+ break;
+ }
+ flag = (conchan->flag & CONSTRAINT_CHANNEL_SELECT) ? 1 : 0;
+
+ return flag;
+}
+
+int select_icu_channel(bAction *act, IpoCurve *icu, int selectmode)
+{
+ /* Select the channel based on the selection mode */
+ int flag;
+
+ switch (selectmode) {
+ case SELECT_ADD:
+ icu->flag |= IPO_SELECT;
+ break;
+ case SELECT_SUBTRACT:
+ icu->flag &= ~IPO_SELECT;
+ break;
+ case SELECT_INVERT:
+ icu->flag ^= IPO_SELECT;
+ break;
+ }
+ flag = (icu->flag & IPO_SELECT) ? 1 : 0;
+ return flag;
+}
+
+/* ----------------------------------------- */
+
+/* deselects action channels in given action */
+void deselect_actionchannels (bAction *act, short test)
+{
+ ListBase act_data = {NULL, NULL};
+ bActListElem *ale;
+ int filter, sel=1;
+
+ /* filter data */
+ filter= ACTFILTER_VISIBLE;
+ actdata_filter(&act_data, filter, act, ACTCONT_ACTION);
+
+ /* See if we should be selecting or deselecting */
+ if (test) {
+ for (ale= act_data.first; ale; ale= ale->next) {
+ if (sel == 0)
+ break;
+
+ switch (ale->type) {
+ case ACTTYPE_ACHAN:
+ if (ale->flag & ACHAN_SELECTED)
+ sel= 0;
+ break;
+ case ACTTYPE_CONCHAN:
+ if (ale->flag & CONSTRAINT_CHANNEL_SELECT)
+ sel=0;
+ break;
+ case ACTTYPE_ICU:
+ if (ale->flag & IPO_SELECT)
+ sel=0;
+ break;
+ }
+ }
+ }
+ else
+ sel= 0;
+
+ /* Now set the flags */
+ for (ale= act_data.first; ale; ale= ale->next) {
+ switch (ale->type) {
+ case ACTTYPE_ACHAN:
+ {
+ bActionChannel *achan= (bActionChannel *)ale->data;
+
+ if (sel)
+ achan->flag |= ACHAN_SELECTED;
+ else
+ achan->flag &= ~ACHAN_SELECTED;
+ select_poseelement_by_name(achan->name, sel);
+ }
+ break;
+ case ACTTYPE_CONCHAN:
+ {
+ bConstraintChannel *conchan= (bConstraintChannel *)ale->data;
+
+ if (sel)
+ conchan->flag |= CONSTRAINT_CHANNEL_SELECT;
+ else
+ conchan->flag &= ~CONSTRAINT_CHANNEL_SELECT;
+ }
+ break;
+ case ACTTYPE_ICU:
+ {
+ IpoCurve *icu= (IpoCurve *)ale->data;
+
+ if (sel)
+ icu->flag |= IPO_SELECT;
+ else
+ icu->flag &= ~IPO_SELECT;
+ }
+ break;
+ }
+ }
+
+ /* Cleanup */
+ BLI_freelistN(&act_data);
+}
+
+/* deselects channels in the action editor */
+void deselect_action_channels (short test)
+{
+ void *data;
+ short datatype;
+
+ /* determine what type of data we are operating on */
+ data = get_action_context(&datatype);
+ if (data == NULL) return;
+
+ /* based on type */
+ if (datatype == ACTCONT_ACTION)
+ deselect_actionchannels(data, test);
+ // should shapekey channels be allowed to do this?
+}
+
+/* deselects keyframes in the action editor */
+void deselect_action_keys (short test, short sel)
+{
+ ListBase act_data = {NULL, NULL};
+ bActListElem *ale;
+ int filter;
+ void *data;
+ short datatype;
+
+ /* determine what type of data we are operating on */
+ data = get_action_context(&datatype);
+ if (data == NULL) return;
+
+ /* filter data */
+ filter= (ACTFILTER_VISIBLE | ACTFILTER_IPOKEYS);
+ actdata_filter(&act_data, filter, data, datatype);
+
+ /* See if we should be selecting or deselecting */
+ if (test) {
+ for (ale= act_data.first; ale; ale= ale->next) {
+ if (is_ipo_key_selected(ale->key_data)) {
+ sel= 0;
+ break;
+ }
+ }
+ }
+
+ /* Now set the flags */
+ for (ale= act_data.first; ale; ale= ale->next) {
+ set_ipo_key_selection(ale->key_data, sel);
+ }
+
+ /* Cleanup */
+ BLI_freelistN(&act_data);
+}
+
+/* selects all keyframes in the action editor - per channel or time
+ * mode = 0: all in channel; mode = 1: all in frame
+ */
+void selectall_action_keys (short mval[], short mode, short select_mode)
+{
+ void *data;
+ short datatype;
+
+ /* determine what type of data we are operating on */
+ data = get_action_context(&datatype);
+ if (data == NULL) return;
+
+ if (select_mode == SELECT_REPLACE) {
+ deselect_action_keys(0, 0);
+ select_mode = SELECT_ADD;
+ }
+
+ /* depending on mode */
+ switch (mode) {
+ case 0: /* all in channel*/
+ {
+ void *act_channel;
+ short chantype;
+
+ /* get channel, and act according to type */
+ act_channel= get_nearest_act_channel(mval, &chantype);
+ switch (chantype) {
+ case ACTTYPE_ACHAN:
+ {
+ bActionChannel *achan= (bActionChannel *)act_channel;
+ select_ipo_bezier_keys(achan->ipo, select_mode);
+ }
+ break;
+ case ACTTYPE_CONCHAN:
+ {
+ bConstraintChannel *conchan= (bConstraintChannel *)act_channel;
+ select_ipo_bezier_keys(conchan->ipo, select_mode);
+ }
+ break;
+ case ACTTYPE_ICU:
+ {
+ IpoCurve *icu= (IpoCurve *)act_channel;
+ select_icu_bezier_keys(icu, select_mode);
+ }
+ break;
+ }
+ }
+ break;
+ case 1: /* all in frame */
+ {
+ ListBase act_data = {NULL, NULL};
+ bActListElem *ale;
+ int filter;
+ rcti rect;
+ rctf rectf;
+
+ /* use bounding box to find kframe */
+ rect.xmin = rect.xmax = mval[0];
+ rect.ymin = rect.ymax = mval[1];
+
+ mval[0]= rect.xmin;
+ mval[1]= rect.ymin+2;
+ areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
+ rectf.xmax= rectf.xmin;
+ rectf.ymax= rectf.ymin;
+
+ rectf.xmin = rectf.xmin - 0.5;
+ rectf.xmax = rectf.xmax + 0.5;
+
+ /* filter data */
+ filter= (ACTFILTER_VISIBLE | ACTFILTER_IPOKEYS);
+ actdata_filter(&act_data, filter, data, datatype);
+
+ /* Now set the flags */
+ for (ale= act_data.first; ale; ale= ale->next)
+ borderselect_ipo_key(ale->key_data, rectf.xmin, rectf.xmax, select_mode);
+
+ /* Cleanup */
+ BLI_freelistN(&act_data);
+ }
+ break;
+ }
+
+ allqueue(REDRAWNLA, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWIPO, 0);
+}
+
+void markers_selectkeys_between (void)
+{
+ ListBase act_data = {NULL, NULL};
+ bActListElem *ale;
+ int filter;
+ void *data;
+ short datatype;
+ float min, max;
+
+ /* determine what type of data we are operating on */
+ data = get_action_context(&datatype);
+ if (data == NULL) return;
+
+ /* get extreme markers */
+ get_minmax_markers(1, &min, &max);
+ if (min==max) return;
+ min -= 0.5f;
+ max += 0.5f;
+
+ /* filter data */
+ filter= (ACTFILTER_VISIBLE | ACTFILTER_IPOKEYS);
+ actdata_filter(&act_data, filter, data, datatype);
+
+ /* select keys in-between */
+ for (ale= act_data.first; ale; ale= ale->next) {
+ if(NLA_ACTION_SCALED && datatype==ACTCONT_ACTION) {
+ actstrip_map_ipo_keys(OBACT, ale->key_data, 0, 1);
+ borderselect_ipo_key(ale->key_data, min, max, SELECT_ADD);
+ actstrip_map_ipo_keys(OBACT, ale->key_data, 1, 1);
+ }
+ else {
+ borderselect_ipo_key(ale->key_data, min, max, SELECT_ADD);
+ }
+ }
+
+ /* Cleanup */
+ BLI_freelistN(&act_data);
+}
+
+/* ----------------------------------------- */
+
+/* This function makes a list of the selected keyframes
+ * in the ipo curves it has been passed
+ */
+static void make_sel_cfra_list(Ipo *ipo, ListBase *elems)
+{
+ IpoCurve *icu;
+
+ if (ipo == NULL) return;
+
+ for(icu= ipo->curve.first; icu; icu= icu->next) {
+ BezTriple *bezt;
+ int a= 0;
+
+ for (bezt=icu->bezt; a<icu->totvert; a++, bezt++) {
+ if (bezt && BEZSELECTED(bezt))
+ add_to_cfra_elem(elems, bezt);
+ }
+ }
+}
+
+/* This function selects all key frames in the same column(s) as a already selected key(s)
+ * or marker(s), or all the keyframes on a particular frame (triggered by a RMB on x-scrollbar)
+ */
+void column_select_action_keys(int mode)
+{
+ ListBase elems= {NULL, NULL};
+ CfraElem *ce;
+ IpoCurve *icu;
+ ListBase act_data = {NULL, NULL};
+ bActListElem *ale;
+ int filter;
+ void *data;
+ short datatype;
+
+ /* determine what type of data we are operating on */
+ data = get_action_context(&datatype);
+ if (data == NULL) return;
+
+ /* build list of columns */
+ switch (mode) {
+ case 1: /* list of selected keys */
+ filter= (ACTFILTER_VISIBLE | ACTFILTER_IPOKEYS);
+ actdata_filter(&act_data, filter, data, datatype);
+
+ for (ale= act_data.first; ale; ale= ale->next)
+ make_sel_cfra_list(ale->key_data, &elems);
+
+ BLI_freelistN(&act_data);
+ break;
+ case 2: /* list of selected markers */
+ make_marker_cfra_list(&elems, 1);
+
+ /* apply scaled action correction if needed */
+ if (NLA_ACTION_SCALED && datatype==ACTCONT_ACTION) {
+ for (ce= elems.first; ce; ce= ce->next)
+ ce->cfra= get_action_frame(OBACT, ce->cfra);
+ }
+ break;
+ }
+
+ /* loop through all of the keys and select additional keyframes
+ * based on the keys found to be selected above
+ */
+ filter= (ACTFILTER_VISIBLE | ACTFILTER_ONLYICU);
+ actdata_filter(&act_data, filter, data, datatype);
+
+ for (ale= act_data.first; ale; ale= ale->next) {
+ for(ce= elems.first; ce; ce= ce->next) {
+ for (icu= ale->key_data; icu; icu= icu->next) {
+ BezTriple *bezt;
+ int verts = 0;
+
+ for (bezt=icu->bezt; verts<icu->totvert; bezt++, verts++) {
+ if (bezt) {
+ if( (int)(ce->cfra) == (int)(bezt->vec[1][0]) )
+ bezt->f2 |= 1;
+ }
+ }
+ }
+ }
+ }
+
+ BLI_freelistN(&act_data);
+ BLI_freelistN(&elems);
+}
+
+/* some quick defines for borderselect modes */
+#define ACTEDIT_BORDERSEL_ALL 0
+#define ACTEDIT_BORDERSEL_FRA 1
+#define ACTEDIT_BORDERSEL_CHA 2
+
+/* borderselect: for keyframes only */
+void borderselect_action (void)
+{
+ ListBase act_data = {NULL, NULL};
+ bActListElem *ale;
+ int filter;
+ void *data;
+ short datatype;
+
+ rcti rect;
+ rctf rectf;
+ int val, selectmode, mode;
+ int (*select_function)(BezTriple *);
+ short mval[2];
+ float ymin, ymax;
+
+ /* determine what type of data we are operating on */
+ data = get_action_context(&datatype);
+ if (data == NULL) return;
+
+ /* what should be selected (based on the starting location of cursor) */
+ getmouseco_areawin(mval);
+ if (IN_2D_VERT_SCROLL(mval))
+ mode = ACTEDIT_BORDERSEL_CHA;
+ else if (IN_2D_HORIZ_SCROLL(mval))
+ mode = ACTEDIT_BORDERSEL_FRA;
+ else
+ mode = ACTEDIT_BORDERSEL_ALL;
+
+ /* draw and handle the borderselect stuff (ui) and get the select rect */
+ if ( (val = get_border(&rect, 3)) ) {
+ if (val == LEFTMOUSE) {
+ selectmode = SELECT_ADD;
+ select_function = select_bezier_add;
+ }
+ else {
+ selectmode = SELECT_SUBTRACT;
+ select_function = select_bezier_subtract;
+ }
+
+ mval[0]= rect.xmin;
+ mval[1]= rect.ymin+2;
+ areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
+ mval[0]= rect.xmax;
+ mval[1]= rect.ymax-2;
+ areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
+
+ /* if action is mapped in NLA, it returns a correction */
+ if (NLA_ACTION_SCALED && datatype==ACTCONT_ACTION) {
+ rectf.xmin= get_action_frame(OBACT, rectf.xmin);
+ rectf.xmax= get_action_frame(OBACT, rectf.xmax);
+ }
+
+ ymax = CHANNELHEIGHT/2;
+
+ /* filter data */
+ filter= (ACTFILTER_VISIBLE | ACTFILTER_CHANNELS);
+ actdata_filter(&act_data, filter, data, datatype);
+
+ /* loop over data, doing border select */
+ for (ale= act_data.first; ale; ale= ale->next) {
+ ymin=ymax-(CHANNELHEIGHT+CHANNELSKIP);
+
+ /* what gets selected depends on the mode (based on initial position of cursor) */
+ switch (mode) {
+ case ACTEDIT_BORDERSEL_FRA: /* all in frame(s) */
+ if (ale->key_data) {
+ if (ale->datatype == ALE_IPO)
+ borderselect_ipo_key(ale->key_data, rectf.xmin, rectf.xmax, selectmode);
+ else if (ale->datatype == ALE_ICU)
+ borderselect_icu_key(ale->key_data, rectf.xmin, rectf.xmax, select_function);
+ }
+ break;
+ case ACTEDIT_BORDERSEL_CHA: /* all in channel(s) */
+ if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))) {
+ if (ale->key_data) {
+ if (ale->datatype == ALE_IPO)
+ select_ipo_bezier_keys(ale->key_data, selectmode);
+ else if (ale->datatype == ALE_ICU)
+ select_icu_bezier_keys(ale->key_data, selectmode);
+ }
+ }
+ break;
+ default: /* any keyframe inside region defined by region */
+ if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))) {
+ if (ale->key_data) {
+ if (ale->datatype == ALE_IPO)
+ borderselect_ipo_key(ale->key_data, rectf.xmin, rectf.xmax, selectmode);
+ else if (ale->datatype == ALE_ICU)
+ borderselect_icu_key(ale->key_data, rectf.xmin, rectf.xmax, select_function);
+ }
+ }
+ }
+
+ ymax=ymin;
+ }
+
+ /* cleanup */
+ BLI_freelistN(&act_data);
+
+ BIF_undo_push("Border Select Action");
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWNLA, 0);
+ }
+}
+
+/* **************************************************** */
+/* MOUSE-HANDLING */
+
+/* right-hand side - mouse click */
+static void mouse_action (int selectmode)
+{
+ void *data;
+ short datatype;
+
+ bAction *act= NULL;
+ bActionChannel *achan= NULL;
+ bConstraintChannel *conchan= NULL;
+ IpoCurve *icu= NULL;
+ TimeMarker *marker;
+
+ void *act_channel;
+ short sel, act_type;
+ float selx;
+
+ /* determine what type of data we are operating on */
+ data = get_action_context(&datatype);
+ if (data == NULL) return;
+ if (datatype == ACTCONT_ACTION) act= (bAction *)data;
+
+ act_channel= get_nearest_action_key(&selx, &sel, &act_type, &achan);
+ marker=find_nearest_marker(1);
+
+ if (act_channel) {
+ switch (act_type) {
+ case ACTTYPE_ICU:
+ icu= (IpoCurve *)act_channel;
+ break;
+ case ACTTYPE_CONCHAN:
+ conchan= (bConstraintChannel *)act_channel;
+ break;
+ case ACTTYPE_ACHAN:
+ achan= (bActionChannel *)act_channel;
+ break;
+ default:
+ return;
+ }
+
+ if (selectmode == SELECT_REPLACE) {
+ selectmode = SELECT_ADD;
+
+ deselect_action_keys(0, 0);
+
+ if (datatype == ACTCONT_ACTION) {
+ deselect_action_channels(0);
+
+ achan->flag |= ACHAN_SELECTED;
+ hilight_channel(act, achan, 1);
+ select_poseelement_by_name(achan->name, 2); /* 2 is activate */
+ }
+ }
+
+ if (icu)
+ select_icu_key(icu, selx, selectmode);
+ else if (conchan)
+ select_ipo_key(conchan->ipo, selx, selectmode);
+ else
+ select_ipo_key(achan->ipo, selx, selectmode);
+
+ std_rmouse_transform(transform_action_keys);
+
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWNLA, 0);
+ allqueue(REDRAWOOPS, 0);
+ allqueue(REDRAWBUTSALL, 0);
+ }
+ else if (marker) {
+ /* not channel, so maybe marker */
+ if (selectmode == SELECT_REPLACE) {
+ deselect_markers(0, 0);
+ marker->flag |= SELECT;
+ }
+ else if (selectmode == SELECT_INVERT) {
+ if (marker->flag & SELECT)
+ marker->flag &= ~SELECT;
+ else
+ marker->flag |= SELECT;
+ }
+ else if (selectmode == SELECT_ADD)
+ marker->flag |= SELECT;
+ else if (selectmode == SELECT_SUBTRACT)
+ marker->flag &= ~SELECT;
+
+ std_rmouse_transform(transform_markers);
+
+ allqueue(REDRAWMARKER, 0);
+ }
+}
+
+/* lefthand side - mouse-click */
+static void mouse_actionchannels (short mval[])
+{
+ bAction *act= G.saction->action;
+ void *data, *act_channel;
+ short datatype, chantype;
+
+ /* determine what type of data we are operating on */
+ data = get_action_context(&datatype);
+ if (data == NULL) return;
+
+ /* get channel to work on */
+ act_channel= get_nearest_act_channel(mval, &chantype);
+
+ /* action to take depends on what channel we've got */
+ switch (chantype) {
+ case ACTTYPE_ACHAN:
+ {
+ bActionChannel *achan= (bActionChannel *)act_channel;
+
+ if (mval[0] >= (NAMEWIDTH-16)) {
+ /* toggle protect */
+ achan->flag ^= ACHAN_PROTECTED;
+ }
+ else if ((mval[0] >= (NAMEWIDTH-32)) && (achan->ipo)) {
+ /* toggle mute */
+ achan->ipo->muteipo = (achan->ipo->muteipo)? 0: 1;
+ }
+ else if (mval[0] <= 17) {
+ /* toggle expand */
+ achan->flag ^= ACHAN_EXPANDED;
+ }
+ else {
+ /* select/deselect achan */
+ if (G.qual & LR_SHIFTKEY) {
+ select_channel(act, achan, SELECT_INVERT);
+ }
+ else {
+ deselect_actionchannels(act, 0);
+ select_channel(act, achan, SELECT_ADD);
+ }
+
+ /* messy... set active bone */
+ select_poseelement_by_name(achan->name, 2);
+ }
+ }
+ break;
+ case ACTTYPE_FILLIPO:
+ {
+ bActionChannel *achan= (bActionChannel *)act_channel;
+
+ achan->flag ^= ACHAN_SHOWIPO;
+
+ if ((mval[0] > 24) && (achan->flag & ACHAN_SHOWIPO)) {
+ /* select+make active achan */
+ deselect_actionchannels(act, 0);
+ select_channel(act, achan, SELECT_ADD);
+
+ /* messy... set active bone */
+ select_poseelement_by_name(achan->name, 2);
+ }
+ }
+ break;
+ case ACTTYPE_FILLCON:
+ {
+ bActionChannel *achan= (bActionChannel *)act_channel;
+
+ achan->flag ^= ACHAN_SHOWCONS;
+
+ if ((mval[0] > 24) && (achan->flag & ACHAN_SHOWCONS)) {
+ /* select+make active achan */
+ deselect_actionchannels(act, 0);
+ select_channel(act, achan, SELECT_ADD);
+
+ /* messy... set active bone */
+ select_poseelement_by_name(achan->name, 2);
+ }
+ }
+ break;
+ case ACTTYPE_ICU:
+ {
+ IpoCurve *icu= (IpoCurve *)act_channel;
+
+#if 0 /* disabled until all ipo tools support this -------> */
+ if (mval[0] >= (NAMEWIDTH-16)) {
+ /* toggle protection */
+ icu->flag ^= IPO_PROTECT;
+ }
+#endif /* <------- end of disabled code */
+ if (mval[0] >= (NAMEWIDTH-16)) {
+ /* toggle mute */
+ icu->flag ^= IPO_MUTE;
+ }
+ else {
+ /* select/deselect */
+ select_icu_channel(act, icu, SELECT_INVERT);
+ }
+ }
+ break;
+ case ACTTYPE_CONCHAN:
+ {
+ bConstraintChannel *conchan= (bConstraintChannel *)act_channel;
+
+ if (mval[0] >= (NAMEWIDTH-16)) {
+ /* toggle protection */
+ conchan->flag ^= CONSTRAINT_CHANNEL_PROTECTED;
+ }
+ else if ((mval[0] >= (NAMEWIDTH-32)) && (conchan->ipo)) {
+ /* toggle mute */
+ conchan->ipo->muteipo = (conchan->ipo->muteipo)? 0: 1;
+ }
+ else {
+ /* select/deselect */
+ select_constraint_channel(act, conchan, SELECT_INVERT);
+ }
+ }
+ break;
+ default:
+ return;
+ }
+
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWNLA, 0);
+ allqueue(REDRAWTIME, 0);
+ allqueue(REDRAWOOPS, 0);
+ allqueue(REDRAWBUTSALL, 0);
+}
+
+/* **************************************************** */
+/* ACTION CHANNEL RE-ORDERING */
+
+void top_sel_action ()
+{
+ bAction *act;
+ bActionChannel *achan;
+
+ /* Get the selected action, exit if none are selected */
+ act = G.saction->action;
+ if (!act) return;
+
+ for (achan= act->chanbase.first; achan; achan= achan->next){
+ if (VISIBLE_ACHAN(achan)) {
+ if (SEL_ACHAN(achan) && !(achan->flag & ACHAN_MOVED)){
+ /* take it out off the chain keep data */
+ BLI_remlink (&act->chanbase, achan);
+ /* make it first element */
+ BLI_insertlinkbefore(&act->chanbase, act->chanbase.first, achan);
+ achan->flag |= ACHAN_MOVED;
+ /* restart with rest of list */
+ achan= achan->next;
+ }
+ }
+ }
+ /* clear temp flags */
+ for (achan= act->chanbase.first; achan; achan= achan->next){
+ achan->flag = achan->flag & ~ACHAN_MOVED;
+ }
+
+ /* Clean up and redraw stuff */
+ remake_action_ipos (act);
+ BIF_undo_push("Top Action channel");
+ allspace(REMAKEIPO, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWNLA, 0);
+}
+
+void up_sel_action ()
+{
+ bAction *act;
+ bActionChannel *achan, *prev;
+
+ /* Get the selected action, exit if none are selected */
+ act = G.saction->action;
+ if (!act) return;
+
+ for (achan=act->chanbase.first; achan; achan= achan->next) {
+ if (VISIBLE_ACHAN(achan)) {
+ if (SEL_ACHAN(achan) && !(achan->flag & ACHAN_MOVED)){
+ prev = achan->prev;
+ if (prev) {
+ /* take it out off the chain keep data */
+ BLI_remlink (&act->chanbase, achan);
+ /* push it up */
+ BLI_insertlinkbefore(&act->chanbase, prev, achan);
+ achan->flag |= ACHAN_MOVED;
+ /* restart with rest of list */
+ achan= achan->next;
+ }
+ }
+ }
+ }
+ /* clear temp flags */
+ for (achan=act->chanbase.first; achan; achan= achan->next){
+ achan->flag = achan->flag & ~ACHAN_MOVED;
+ }
+
+ /* Clean up and redraw stuff */
+ remake_action_ipos (act);
+ BIF_undo_push("Up Action channel");
+ allspace(REMAKEIPO, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWNLA, 0);
+}
+
+void down_sel_action ()
+{
+ bAction *act;
+ bActionChannel *achan, *next;
+
+ /* Get the selected action, exit if none are selected */
+ act = G.saction->action;
+ if (!act) return;
+
+ for (achan= act->chanbase.last; achan; achan= achan->prev) {
+ if (VISIBLE_ACHAN(achan)) {
+ if (SEL_ACHAN(achan) && !(achan->flag & ACHAN_MOVED)){
+ next = achan->next;
+ if (next) next = next->next;
+ if (next) {
+ /* take it out off the chain keep data */
+ BLI_remlink (&act->chanbase, achan);
+ /* move it down */
+ BLI_insertlinkbefore(&act->chanbase, next, achan);
+ achan->flag |= ACHAN_MOVED;
+ }
+ else {
+ /* take it out off the chain keep data */
+ BLI_remlink (&act->chanbase, achan);
+ /* add at end */
+ BLI_addtail(&act->chanbase, achan);
+ achan->flag |= ACHAN_MOVED;
+ }
+ }
+ }
+ }
+ /* clear temp flags */
+ for (achan= act->chanbase.first; achan; achan= achan->next){
+ achan->flag = achan->flag & ~ACHAN_MOVED;
+ }
+
+ /* Clean up and redraw stuff */
+ remake_action_ipos (act);
+ BIF_undo_push("Down Action channel");
+ allspace(REMAKEIPO, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWNLA, 0);
+}
+
+void bottom_sel_action ()
+{
+ bAction *act;
+ bActionChannel *achan;
+
+ /* Get the selected action, exit if none are selected */
+ act = G.saction->action;
+ if (!act) return;
+
+ for (achan=act->chanbase.last; achan; achan= achan->prev) {
+ if (VISIBLE_ACHAN(achan)) {
+ if (SEL_ACHAN(achan) && !(achan->flag & ACHAN_MOVED)) {
+ /* take it out off the chain keep data */
+ BLI_remlink (&act->chanbase, achan);
+ /* add at end */
+ BLI_addtail(&act->chanbase, achan);
+ achan->flag |= ACHAN_MOVED;
+ }
+ }
+ }
+ /* clear temp flags */
+ for (achan=act->chanbase.first; achan; achan= achan->next) {
+ achan->flag = achan->flag & ~ACHAN_MOVED;
+ }
+
+ /* Clean up and redraw stuff */
+ remake_action_ipos (act);
+ BIF_undo_push("Bottom Action channel");
+ allspace(REMAKEIPO, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWNLA, 0);
+}
+
+/* **************************************************** */
+/* EVENT HANDLING */
+
+void winqreadactionspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
+{
+ extern void do_actionbuts(unsigned short event); // drawaction.c
+ SpaceAction *saction;
+ void *data;
+ short datatype;
+ float dx, dy;
+ int doredraw= 0;
+ int cfra;
+ short mval[2];
+ unsigned short event= evt->event;
+ short val= evt->val;
+ short mousebut = L_MOUSE;
+
+ if (curarea->win==0) return;
+
+ saction= curarea->spacedata.first;
+ if (!saction)
+ return;
+
+ data= get_action_context(&datatype);
+
+ if (val) {
+ if ( uiDoBlocks(&curarea->uiblocks, event)!=UI_NOTHING ) event= 0;
+
+ /* swap mouse buttons based on user preference */
+ if (U.flag & USER_LMOUSESELECT) {
+ if (event == LEFTMOUSE) {
+ event = RIGHTMOUSE;
+ mousebut = L_MOUSE;
+ } else if (event == RIGHTMOUSE) {
+ event = LEFTMOUSE;
+ mousebut = R_MOUSE;
+ }
+ }
+
+ getmouseco_areawin(mval);
+
+ switch(event) {
+ case UI_BUT_EVENT:
+ do_actionbuts(val); // window itself
+ break;
+
+ case HOMEKEY:
+ do_action_buttons(B_ACTHOME); // header
+ break;
+
+ case AKEY:
+ if (mval[0]<NAMEWIDTH) {
+ deselect_action_channels (1);
+ allqueue (REDRAWVIEW3D, 0);
+ allqueue (REDRAWACTION, 0);
+ allqueue(REDRAWNLA, 0);
+ allqueue (REDRAWIPO, 0);
+ }
+ else if (mval[0]>ACTWIDTH) {
+ if (G.qual == LR_CTRLKEY) {
+ deselect_markers (1, 0);
+ allqueue(REDRAWTIME, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWNLA, 0);
+ allqueue(REDRAWSOUND, 0);
+ }
+ else {
+ deselect_action_keys (1, 1);
+ allqueue (REDRAWACTION, 0);
+ allqueue(REDRAWNLA, 0);
+ allqueue (REDRAWIPO, 0);
+ }
+ }
+ break;
+
+ case BKEY:
+ if (G.qual & LR_CTRLKEY) {
+ borderselect_markers();
+ }
+ else {
+ if (mval[0]>ACTWIDTH)
+ borderselect_action();
+ }
+ break;
+
+ case CKEY:
+ /* scroll the window so the current
+ * frame is in the center.
+ */
+ center_currframe();
+ break;
+
+ case DKEY:
+ if (mval[0]>ACTWIDTH) {
+ if (G.qual == (LR_CTRLKEY|LR_SHIFTKEY))
+ duplicate_marker();
+ else if (G.qual == LR_SHIFTKEY)
+ duplicate_action_keys();
+ }
+ break;
+
+ case EKEY:
+ if (mval[0] >= ACTWIDTH)
+ transform_action_keys('e', 0);
+ break;
+
+ case GKEY:
+ if (G.qual & LR_CTRLKEY) {
+ transform_markers('g', 0);
+ }
+ else {
+ if (mval[0]>=ACTWIDTH)
+ transform_action_keys('g', 0);
+ }
+ break;
+
+ case HKEY:
+ if (G.qual & LR_SHIFTKEY) {
+ if (okee("Set Keys to Auto Handle"))
+ sethandles_action_keys(HD_AUTO);
+ }
+ else {
+ if (okee("Toggle Keys Aligned Handle"))
+ sethandles_action_keys(HD_ALIGN);
+ }
+ break;
+
+ case KKEY:
+ if (G.qual & LR_CTRLKEY) {
+ markers_selectkeys_between();
+ }
+ else {
+ val= (G.qual & LR_SHIFTKEY) ? 2 : 1;
+ column_select_action_keys(val);
+ }
+
+ allqueue(REDRAWMARKER, 0);
+ break;
+
+ case MKEY:
+ if (G.qual & LR_SHIFTKEY) {
+ /* mirror keyframes */
+ if (data) {
+ if (G.saction->flag & SACTION_DRAWTIME)
+ val = pupmenu("Mirror Keys Over%t|Current Time%x1|Vertical Axis%x2|Horizontal Axis %x3|Selected Marker %x4");
+ else
+ val = pupmenu("Mirror Keys Over%t|Current Frame%x1|Vertical Axis%x2|Horizontal Axis %x3|Selected Marker %x4");
+
+ mirror_action_keys(val);
+ }
+ }
+ else {
+ /* marker operations */
+ if (G.qual == 0)
+ add_marker(CFRA);
+ else if (G.qual == LR_CTRLKEY)
+ rename_marker();
+ else
+ break;
+ allqueue(REDRAWMARKER, 0);
+ }
+ break;
+
+ case NKEY:
+ if(G.qual==0) {
+ numbuts_action();
+
+ /* no panel (yet). current numbuts are not easy to put in panel... */
+ //add_blockhandler(curarea, ACTION_HANDLER_PROPERTIES, UI_PNL_TO_MOUSE);
+ //scrarea_queue_winredraw(curarea);
+ }
+ break;
+
+ case OKEY:
+ clean_action();
+ break;
+
+ case PKEY:
+ if (G.qual & LR_CTRLKEY) /* set preview range */
+ anim_previewrange_set();
+ else if (G.qual & LR_ALTKEY) /* clear preview range */
+ anim_previewrange_clear();
+
+ allqueue(REDRAWMARKER, 0);
+ allqueue(REDRAWBUTSALL, 0);
+ break;
+
+ case SKEY:
+ if (mval[0]>=ACTWIDTH) {
+ if (G.qual & LR_SHIFTKEY) {
+ if (data) {
+ if (G.saction->flag & SACTION_DRAWTIME)
+ val = pupmenu("Snap Keys To%t|Nearest Second%x4|Current Time%x2|Nearest Marker %x3");
+ else
+ val = pupmenu("Snap Keys To%t|Nearest Frame%x1|Current Frame%x2|Nearest Marker %x3");
+
+ snap_action_keys(val);
+ }
+ }
+ else {
+ transform_action_keys('s', 0);
+ }
+ }
+ break;
+
+ case TKEY:
+ if (G.qual & LR_SHIFTKEY)
+ action_set_ipo_flags(SET_IPO_POPUP, 0);
+ else if (G.qual & LR_CTRLKEY) {
+ val= pupmenu("Time value%t|Frames %x1|Seconds%x2");
+
+ if (val > 0) {
+ if (val == 2) saction->flag |= SACTION_DRAWTIME;
+ else saction->flag &= ~SACTION_DRAWTIME;
+
+ doredraw= 1;
+ }
+ }
+ else
+ transform_action_keys ('t', 0);
+ break;
+
+ case VKEY:
+ if (okee("Set Keys to Vector Handle"))
+ sethandles_action_keys(HD_VECT);
+ break;
+
+ case PAGEUPKEY:
+ if (datatype == ACTCONT_ACTION) {
+ if(G.qual & LR_SHIFTKEY)
+ top_sel_action();
+ else if (G.qual & LR_CTRLKEY)
+ up_sel_action();
+ else
+ nextprev_marker(1);
+ }
+ else if (datatype == ACTCONT_SHAPEKEY) {
+ /* only jump to markers possible (key channels can't be moved yet) */
+ nextprev_marker(1);
+ }
+ break;
+ case PAGEDOWNKEY:
+ if (datatype == ACTCONT_ACTION) {
+ if(G.qual & LR_SHIFTKEY)
+ bottom_sel_action();
+ else if (G.qual & LR_CTRLKEY)
+ down_sel_action();
+ else
+ nextprev_marker(-1);
+ }
+ else if (datatype == ACTCONT_SHAPEKEY) {
+ /* only jump to markers possible (key channels can't be moved yet) */
+ nextprev_marker(-1);
+ }
+ break;
+
+ case DELKEY:
+ case XKEY:
+ if (okee("Erase selected")) {
+ if (mval[0]<NAMEWIDTH)
+ delete_action_channels();
+ else
+ delete_action_keys();
+
+ if (mval[0] >= NAMEWIDTH)
+ remove_marker();
+
+ allqueue(REDRAWTIME, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWNLA, 0);
+ allqueue(REDRAWSOUND, 0);
+ }
+ break;
+
+ /* LEFTMOUSE and RIGHTMOUSE event codes can be swapped above,
+ * based on user preference USER_LMOUSESELECT
+ */
+ case LEFTMOUSE:
+ if(view2dmove(LEFTMOUSE)) // only checks for sliders
+ break;
+ else if ((G.v2d->mask.xmin==0) || (mval[0]>ACTWIDTH)) {
+ do {
+ getmouseco_areawin(mval);
+
+ areamouseco_to_ipoco(G.v2d, mval, &dx, &dy);
+
+ cfra= (int)dx;
+ if(cfra< 1) cfra= 1;
+
+ if( cfra!=CFRA ) {
+ CFRA= cfra;
+ update_for_newframe();
+ force_draw_all(0);
+ }
+ else PIL_sleep_ms(30);
+
+ } while(get_mbut() & mousebut);
+ break;
+ }
+ /* passed on as selection */
+ case RIGHTMOUSE:
+ /* Clicking in the channel area */
+ if ((G.v2d->mask.xmin) && (mval[0]<NAMEWIDTH)) {
+ if (datatype == ACTCONT_ACTION) {
+ /* mouse is over action channels */
+ if (G.qual & LR_CTRLKEY)
+ numbuts_action();
+ else
+ mouse_actionchannels(mval);
+ }
+ else numbuts_action();
+ }
+ else {
+ short select_mode= (G.qual & LR_SHIFTKEY)? SELECT_INVERT: SELECT_REPLACE;
+
+ /* Clicking in the vertical scrollbar selects
+ * all of the keys for that channel at that height
+ */
+ if (IN_2D_VERT_SCROLL(mval))
+ selectall_action_keys(mval, 0, select_mode);
+
+ /* Clicking in the horizontal scrollbar selects
+ * all of the keys within 0.5 of the nearest integer
+ * frame
+ */
+ else if (IN_2D_HORIZ_SCROLL(mval))
+ selectall_action_keys(mval, 1, select_mode);
+
+ /* Clicking in the main area of the action window
+ * selects keys and markers
+ */
+ else
+ mouse_action(select_mode);
+ }
+ break;
+ case PADPLUSKEY:
+ view2d_zoom(G.v2d, 0.1154, sa->winx, sa->winy);
+ test_view2d(G.v2d, sa->winx, sa->winy);
+ view2d_do_locks(curarea, V2D_LOCK_COPY);
+
+ doredraw= 1;
+ break;
+ case PADMINUS:
+ view2d_zoom(G.v2d, -0.15, sa->winx, sa->winy);
+ test_view2d(G.v2d, sa->winx, sa->winy);
+ view2d_do_locks(curarea, V2D_LOCK_COPY);
+
+ doredraw= 1;
+ break;
+ case MIDDLEMOUSE:
+ case WHEELUPMOUSE:
+ case WHEELDOWNMOUSE:
+ view2dmove(event); /* in drawipo.c */
+ break;
+ }
+ }
+
+ if(doredraw) addqueue(curarea->win, REDRAW, 1);
+
+}
+
+/* **************************************************** */
diff --git a/source/blender/src/editarmature.c b/source/blender/src/editarmature.c
new file mode 100644
index 00000000000..b5675ef9c09
--- /dev/null
+++ b/source/blender/src/editarmature.c
@@ -0,0 +1,3144 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * editarmature.c: Interface for creating and posing armature objects
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "BMF_Api.h"
+
+#include "DNA_action_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_ID.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_nla_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_modifier_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_editVert.h"
+
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_constraint.h"
+#include "BKE_deform.h"
+#include "BKE_depsgraph.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_object.h"
+#include "BKE_subsurf.h"
+#include "BKE_utildefines.h"
+#include "BKE_modifier.h"
+
+#include "BIF_editaction.h"
+#include "BIF_editmode_undo.h"
+#include "BIF_editdeform.h"
+#include "BIF_editarmature.h"
+#include "BIF_editconstraint.h"
+#include "BIF_gl.h"
+#include "BIF_graphics.h"
+#include "BIF_interface.h"
+#include "BIF_meshlaplacian.h"
+#include "BIF_meshtools.h"
+#include "BIF_poseobject.h"
+#include "BIF_mywindow.h"
+#include "BIF_resources.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_toolbox.h"
+#include "BIF_transform.h"
+
+#include "BDR_editobject.h"
+#include "BDR_drawobject.h"
+
+#include "BSE_edit.h"
+#include "BSE_view.h"
+#include "BSE_trans_types.h"
+
+#include "PIL_time.h"
+
+#include "mydevice.h"
+#include "blendef.h"
+#include "nla.h"
+
+extern float center[3], centroid[3]; /* Originally defined in editobject.c */
+
+/* Macros */
+#define TEST_EDITARMATURE {if(G.obedit==0) return; if( (G.vd->lay & G.obedit->lay)==0 ) return;}
+
+/* prototypes for later */
+static EditBone *editbone_name_exists (ListBase *ebones, char *name); // proto for below
+
+/* **************** tools on Editmode Armature **************** */
+
+/* converts Bones to EditBone list, used for tools as well */
+void make_boneList(ListBase* list, ListBase *bones, EditBone *parent)
+{
+ EditBone *eBone;
+ Bone *curBone;
+ float delta[3];
+ float premat[3][3];
+ float postmat[3][3];
+ float imat[3][3];
+ float difmat[3][3];
+
+ for (curBone=bones->first; curBone; curBone=curBone->next){
+ eBone= MEM_callocN(sizeof(EditBone), "make_editbone");
+
+ /* Copy relevant data from bone to eBone */
+ eBone->parent=parent;
+ BLI_strncpy (eBone->name, curBone->name, 32);
+ eBone->flag = curBone->flag;
+
+ /* fix selection flags */
+ if(eBone->flag & BONE_SELECTED) {
+ eBone->flag |= BONE_TIPSEL;
+ if(eBone->parent && (eBone->flag & BONE_CONNECTED))
+ eBone->parent->flag |= BONE_TIPSEL;
+ else
+ eBone->flag |= BONE_ROOTSEL;
+ }
+ else
+ eBone->flag &= ~BONE_ROOTSEL;
+
+ VECCOPY(eBone->head, curBone->arm_head);
+ VECCOPY(eBone->tail, curBone->arm_tail);
+
+ eBone->roll= 0.0;
+
+ /* roll fixing */
+ VecSubf (delta, eBone->tail, eBone->head);
+ vec_roll_to_mat3(delta, 0.0, postmat);
+
+ Mat3CpyMat4(premat, curBone->arm_mat);
+
+ Mat3Inv(imat, postmat);
+ Mat3MulMat3(difmat, imat, premat);
+
+ eBone->roll = atan2(difmat[2][0], difmat[2][2]);
+
+ /* rest of stuff copy */
+ eBone->length= curBone->length;
+ eBone->dist= curBone->dist;
+ eBone->weight= curBone->weight;
+ eBone->xwidth= curBone->xwidth;
+ eBone->zwidth= curBone->zwidth;
+ eBone->ease1= curBone->ease1;
+ eBone->ease2= curBone->ease2;
+ eBone->rad_head= curBone->rad_head;
+ eBone->rad_tail= curBone->rad_tail;
+ eBone->segments = curBone->segments;
+ eBone->layer = curBone->layer;
+
+ BLI_addtail (list, eBone);
+
+ /* Add children if necessary */
+ if (curBone->childbase.first)
+ make_boneList (list, &curBone->childbase, eBone);
+ }
+}
+
+/* nasty stuff for converting roll in editbones into bones */
+/* also sets restposition in armature (arm_mat) */
+static void fix_bonelist_roll (ListBase *bonelist, ListBase *editbonelist)
+{
+ Bone *curBone;
+ EditBone *ebone;
+ float premat[3][3];
+ float postmat[3][3];
+ float difmat[3][3];
+ float imat[3][3];
+ float delta[3];
+
+ for (curBone=bonelist->first; curBone; curBone=curBone->next) {
+ /* sets local matrix and arm_mat (restpos) */
+ where_is_armature_bone(curBone, curBone->parent);
+
+ /* Find the associated editbone */
+ for (ebone = editbonelist->first; ebone; ebone=ebone->next)
+ if ((Bone*)ebone->temp == curBone)
+ break;
+
+ if (ebone) {
+ /* Get the ebone premat */
+ VecSubf (delta, ebone->tail, ebone->head);
+ vec_roll_to_mat3(delta, ebone->roll, premat);
+
+ /* Get the bone postmat */
+ Mat3CpyMat4(postmat, curBone->arm_mat);
+
+ Mat3Inv(imat, premat);
+ Mat3MulMat3(difmat, imat, postmat);
+#if 0
+ printf ("Bone %s\n", curBone->name);
+ printmatrix4 ("premat", premat);
+ printmatrix4 ("postmat", postmat);
+ printmatrix4 ("difmat", difmat);
+ printf ("Roll = %f\n", (-atan2(difmat[2][0], difmat[2][2]) * (180.0/M_PI)));
+#endif
+ curBone->roll = -atan2(difmat[2][0], difmat[2][2]);
+
+ /* and set restposition again */
+ where_is_armature_bone(curBone, curBone->parent);
+ }
+ fix_bonelist_roll (&curBone->childbase, editbonelist);
+ }
+}
+
+/* converts the editbones back to the armature */
+void editbones_to_armature (ListBase *list, Object *ob)
+{
+ bArmature *arm;
+ EditBone *eBone, *neBone;
+ Bone *newBone;
+ Object *obt;
+
+ arm = get_armature(ob);
+ if (!list) return;
+ if (!arm) return;
+
+ /* armature bones */
+ free_bones(arm);
+
+ /* remove zero sized bones, this gives instable restposes */
+ for (eBone=list->first; eBone; eBone= neBone) {
+ float len= VecLenf(eBone->head, eBone->tail);
+ neBone= eBone->next;
+ if(len <= FLT_EPSILON) {
+ EditBone *fBone;
+
+ /* Find any bones that refer to this bone */
+ for (fBone=list->first; fBone; fBone= fBone->next){
+ if (fBone->parent==eBone)
+ fBone->parent= eBone->parent;
+ }
+ printf("Warning; removed zero sized bone: %s\n", eBone->name);
+ BLI_freelinkN (list, eBone);
+ }
+ }
+
+ /* Copy the bones from the editData into the armature */
+ for (eBone=list->first; eBone; eBone=eBone->next){
+ newBone= MEM_callocN (sizeof(Bone), "bone");
+ eBone->temp= newBone; /* Associate the real Bones with the EditBones */
+
+ BLI_strncpy (newBone->name, eBone->name, 32);
+ memcpy (newBone->head, eBone->head, sizeof(float)*3);
+ memcpy (newBone->tail, eBone->tail, sizeof(float)*3);
+ newBone->flag= eBone->flag;
+ if(eBone->flag & BONE_ACTIVE) newBone->flag |= BONE_SELECTED; /* important, editbones can be active with only 1 point selected */
+ newBone->roll = 0.0f;
+
+ newBone->weight = eBone->weight;
+ newBone->dist = eBone->dist;
+
+ newBone->xwidth = eBone->xwidth;
+ newBone->zwidth = eBone->zwidth;
+ newBone->ease1= eBone->ease1;
+ newBone->ease2= eBone->ease2;
+ newBone->rad_head= eBone->rad_head;
+ newBone->rad_tail= eBone->rad_tail;
+ newBone->segments= eBone->segments;
+ newBone->layer = eBone->layer;
+
+ }
+
+ /* Fix parenting in a separate pass to ensure ebone->bone connections
+ are valid at this point */
+ for (eBone=list->first;eBone;eBone=eBone->next) {
+ newBone= (Bone*) eBone->temp;
+ if (eBone->parent){
+ newBone->parent=(Bone*) eBone->parent->temp;
+ BLI_addtail (&newBone->parent->childbase,newBone);
+
+ {
+ float M_boneRest[3][3];
+ float M_parentRest[3][3];
+ float iM_parentRest[3][3];
+ float delta[3];
+
+ /* Get the parent's matrix (rotation only) */
+ VecSubf (delta, eBone->parent->tail, eBone->parent->head);
+ vec_roll_to_mat3(delta, eBone->parent->roll, M_parentRest);
+
+ /* Get this bone's matrix (rotation only) */
+ VecSubf (delta, eBone->tail, eBone->head);
+ vec_roll_to_mat3(delta, eBone->roll, M_boneRest);
+
+ /* Invert the parent matrix */
+ Mat3Inv(iM_parentRest, M_parentRest);
+
+ /* Get the new head and tail */
+ VecSubf (newBone->head, eBone->head, eBone->parent->tail);
+ VecSubf (newBone->tail, eBone->tail, eBone->parent->tail);
+
+ Mat3MulVecfl(iM_parentRest, newBone->head);
+ Mat3MulVecfl(iM_parentRest, newBone->tail);
+ }
+ }
+ /* ...otherwise add this bone to the armature's bonebase */
+ else
+ BLI_addtail (&arm->bonebase,newBone);
+ }
+
+ /* Make a pass through the new armature to fix rolling */
+ /* also builds restposition again (like where_is_armature) */
+ fix_bonelist_roll (&arm->bonebase, list);
+
+ /* so all users of this armature should get rebuilt */
+ for(obt= G.main->object.first; obt; obt= obt->id.next) {
+ if(obt->data==arm)
+ armature_rebuild_pose(obt, arm);
+ }
+
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+}
+
+
+
+void apply_rot_armature (Object *ob, float mat[3][3])
+{
+ ListBase list;
+ EditBone *ebone;
+ bArmature *arm;
+ float scale = Mat3ToScalef(mat); /* store the scale of the matrix here to use on envelopes */
+ arm = get_armature(ob);
+
+ if (!arm)
+ return;
+
+ /* Put the armature into editmode */
+ list.first= list.last = NULL;
+ make_boneList(&list, &arm->bonebase, NULL);
+
+ /* Do the rotations */
+ for (ebone = list.first; ebone; ebone=ebone->next){
+ Mat3MulVecfl(mat, ebone->head);
+ Mat3MulVecfl(mat, ebone->tail);
+
+ ebone->rad_head *= scale;
+ ebone->rad_tail *= scale;
+ ebone->dist *= scale;
+ }
+
+ /* Turn the list into an armature */
+ editbones_to_armature(&list, ob);
+
+ /* Free the editbones */
+ if (list.first){
+ BLI_freelistN (&list);
+ }
+}
+
+/* 0 == do center, 1 == center new, 2 == center cursor */
+void docenter_armature (Object *ob, int centermode)
+{
+ ListBase list;
+ EditBone *ebone;
+ bArmature *arm;
+ float cent[3] = {0.0f, 0.0f, 0.0f};
+ float min[3], max[3];
+ float omat[3][3];
+
+ arm = get_armature(ob);
+ if (!arm) return;
+
+ /* Put the armature into editmode */
+ list.first= list.last = NULL;
+ make_boneList(&list, &arm->bonebase, NULL);
+
+ /* Find the centerpoint */
+ if (centermode == 2) {
+ VECCOPY(cent, give_cursor());
+ Mat4Invert(ob->imat, ob->obmat);
+ Mat4MulVecfl(ob->imat, cent);
+ }
+ else {
+ INIT_MINMAX(min, max);
+
+ for (ebone= list.first; ebone; ebone=ebone->next) {
+ DO_MINMAX(ebone->head, min, max);
+ DO_MINMAX(ebone->tail, min, max);
+ }
+
+ cent[0]= (min[0]+max[0])/2.0f;
+ cent[1]= (min[1]+max[1])/2.0f;
+ cent[2]= (min[2]+max[2])/2.0f;
+ }
+
+ /* Do the adjustments */
+ for (ebone= list.first; ebone; ebone=ebone->next){
+ VecSubf(ebone->head, ebone->head, cent);
+ VecSubf(ebone->tail, ebone->tail, cent);
+ }
+
+ /* Turn the list into an armature */
+ editbones_to_armature(&list, ob);
+
+ /* Free the editbones */
+ if (list.first){
+ BLI_freelistN(&list);
+ }
+
+ /* Adjust object location for new centerpoint */
+ if(centermode && G.obedit==0) {
+ Mat3CpyMat4(omat, ob->obmat);
+
+ Mat3MulVecfl(omat, cent);
+ ob->loc[0]+= cent[0];
+ ob->loc[1]+= cent[1];
+ ob->loc[2]+= cent[2];
+ }
+}
+
+/* Helper function for armature joining - link fixing */
+static void joined_armature_fix_links(Object *tarArm, Object *srcArm, bPoseChannel *pchan, EditBone *curbone)
+{
+ Object *ob;
+ bPose *pose;
+ bPoseChannel *pchant;
+ bConstraint *con;
+
+ /* let's go through all objects in database */
+ for (ob= G.main->object.first; ob; ob= ob->id.next) {
+ /* do some object-type specific things */
+ if (ob->type == OB_ARMATURE) {
+ pose= ob->pose;
+ for (pchant= pose->chanbase.first; pchant; pchant= pchant->next) {
+ for (con= pchant->constraints.first; con; con= con->next) {
+ bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+
+ /* constraint targets */
+ if (cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(con, &targets);
+
+ for (ct= targets.first; ct; ct= ct->next) {
+ if (ct->tar == srcArm) {
+ if (strcmp(ct->subtarget, "")==0) {
+ ct->tar = tarArm;
+ }
+ else if (strcmp(ct->subtarget, pchan->name)==0) {
+ ct->tar = tarArm;
+ strcpy(ct->subtarget, curbone->name);
+ }
+ }
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(con, &targets, 0);
+ }
+
+ /* action constraint? */
+ if (con->type == CONSTRAINT_TYPE_ACTION) {
+ bActionConstraint *data= con->data;
+ bAction *act;
+ bActionChannel *achan;
+
+ if (data->act) {
+ act= data->act;
+
+ for (achan= act->chanbase.first; achan; achan= achan->next) {
+ if (strcmp(achan->name, pchan->name)==0)
+ BLI_strncpy(achan->name, curbone->name, 32);
+ }
+ }
+ }
+
+ }
+ }
+ }
+
+ /* fix object-level constraints */
+ if (ob != srcArm) {
+ for (con= ob->constraints.first; con; con= con->next) {
+ bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+
+ /* constraint targets */
+ if (cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(con, &targets);
+
+ for (ct= targets.first; ct; ct= ct->next) {
+ if (ct->tar == srcArm) {
+ if (strcmp(ct->subtarget, "")==0) {
+ ct->tar = tarArm;
+ }
+ else if (strcmp(ct->subtarget, pchan->name)==0) {
+ ct->tar = tarArm;
+ strcpy(ct->subtarget, curbone->name);
+ }
+ }
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(con, &targets, 0);
+ }
+ }
+ }
+
+ /* See if an object is parented to this armature */
+ if (ob->parent && (ob->parent == srcArm)) {
+ /* Is object parented to a bone of this src armature? */
+ if (ob->partype==PARBONE) {
+ /* bone name in object */
+ if (!strcmp(ob->parsubstr, pchan->name))
+ BLI_strncpy(ob->parsubstr, curbone->name, 32);
+ }
+
+ /* make tar armature be new parent */
+ ob->parent = tarArm;
+ }
+ }
+}
+
+int join_armature(void)
+{
+ Object *ob;
+ bArmature *arm;
+ Base *base, *nextbase;
+ bPose *pose, *opose;
+ bPoseChannel *pchan, *pchann;
+ ListBase ebbase, eblist;
+ EditBone *curbone;
+ float mat[4][4], imat[4][4];
+
+ /* Ensure we're not in editmode and that the active object is an armature*/
+ /* if(G.obedit) return; */ /* Alredy checked in join_menu() */
+
+ ob= OBACT;
+ if(ob->type!=OB_ARMATURE) return 0;
+ if (object_data_is_libdata(ob)) {
+ error_libdata();
+ return 0;
+ }
+ arm= get_armature(ob);
+
+ /* Get editbones of active armature to add editbones to */
+ ebbase.first=ebbase.last= NULL;
+ make_boneList(&ebbase, &arm->bonebase, NULL);
+ pose= ob->pose;
+
+ for (base=FIRSTBASE; base; base=nextbase) {
+ nextbase = base->next;
+ if (TESTBASE(base)){
+ if ((base->object->type==OB_ARMATURE) && (base->object!=ob)){
+ /* Make a list of editbones in current armature */
+ eblist.first=eblist.last= NULL;
+ make_boneList (&eblist, &((bArmature*)base->object->data)->bonebase,NULL);
+
+ /* Get Pose of current armature */
+ opose= base->object->pose;
+
+ /* Find the difference matrix */
+ Mat4Invert(imat, ob->obmat);
+ Mat4MulMat4(mat, base->object->obmat, imat);
+
+ /* Copy bones and posechannels from the object to the edit armature */
+ for (pchan=opose->chanbase.first; pchan; pchan=pchann) {
+ pchann= pchan->next;
+ curbone= editbone_name_exists(&eblist, pchan->name);
+
+ /* Get new name */
+ unique_editbone_name (&ebbase, curbone->name);
+
+ /* Transform the bone */
+ {
+ float premat[4][4];
+ float postmat[4][4];
+ float difmat[4][4];
+ float imat[4][4];
+ float temp[3][3];
+ float delta[3];
+
+ /* Get the premat */
+ VecSubf (delta, curbone->tail, curbone->head);
+ vec_roll_to_mat3(delta, curbone->roll, temp);
+
+ Mat4MulMat34 (premat, temp, mat);
+
+ Mat4MulVecfl(mat, curbone->head);
+ Mat4MulVecfl(mat, curbone->tail);
+
+ /* Get the postmat */
+ VecSubf (delta, curbone->tail, curbone->head);
+ vec_roll_to_mat3(delta, curbone->roll, temp);
+ Mat4CpyMat3(postmat, temp);
+
+ /* Find the roll */
+ Mat4Invert (imat, premat);
+ Mat4MulMat4 (difmat, postmat, imat);
+
+ curbone->roll -= atan2(difmat[2][0], difmat[2][2]);
+
+ }
+
+ /* Fix Constraints and Other Links to this Bone and Armature */
+ joined_armature_fix_links(ob, base->object, pchan, curbone);
+
+ /* Rename pchan */
+ sprintf(pchan->name, curbone->name);
+
+ /* Jump Ship! */
+ BLI_remlink(&eblist, curbone);
+ BLI_addtail(&ebbase, curbone);
+
+ BLI_remlink(&opose->chanbase, pchan);
+ BLI_addtail(&pose->chanbase, pchan);
+ }
+
+ free_and_unlink_base(base);
+ }
+ }
+ }
+
+ DAG_scene_sort(G.scene); // because we removed object(s)
+
+ editbones_to_armature(&ebbase, ob);
+ if (ebbase.first) BLI_freelistN(&ebbase);
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWOOPS, 0);
+ return 1;
+}
+
+/* **************** END tools on Editmode Armature **************** */
+/* **************** PoseMode & EditMode *************************** */
+
+/* only for opengl selection indices */
+Bone *get_indexed_bone (Object *ob, int index)
+{
+ bPoseChannel *pchan;
+ int a= 0;
+
+ if(ob->pose==NULL) return NULL;
+ index>>=16; // bone selection codes use left 2 bytes
+
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next, a++) {
+ if(a==index) return pchan->bone;
+ }
+ return NULL;
+}
+
+/* See if there are any selected bones in this buffer */
+static void *get_bone_from_selectbuffer(Base *base, unsigned int *buffer, short hits, short findunsel)
+{
+ Object *ob= base->object;
+ Bone *bone;
+ EditBone *ebone;
+ void *firstunSel=NULL, *firstSel=NULL, *data;
+ unsigned int hitresult;
+ short i, takeNext=0, sel;
+
+ for (i=0; i< hits; i++){
+ hitresult = buffer[3+(i*4)];
+
+ if (!(hitresult & BONESEL_NOSEL)) { // -1
+ if(hitresult & BONESEL_ANY) { // to avoid including objects in selection
+
+ hitresult &= ~(BONESEL_ANY);
+ /* Determine what the current bone is */
+ if (G.obedit==NULL || base->object!=G.obedit) {
+ /* no singular posemode, so check for correct object */
+ if(base->selcol == (hitresult & 0xFFFF)) {
+ bone = get_indexed_bone(ob, hitresult);
+
+ if (findunsel)
+ sel = (bone->flag & BONE_SELECTED);
+ else
+ sel = !(bone->flag & BONE_SELECTED);
+
+ data = bone;
+ }
+ else {
+ data= NULL;
+ sel= 0;
+ }
+ }
+ else{
+ ebone = BLI_findlink(&G.edbo, hitresult);
+ if (findunsel)
+ sel = (ebone->flag & BONE_SELECTED);
+ else
+ sel = !(ebone->flag & BONE_SELECTED);
+
+ data = ebone;
+ }
+
+ if(data) {
+ if (sel) {
+ if(!firstSel) firstSel= data;
+ takeNext=1;
+ }
+ else {
+ if (!firstunSel)
+ firstunSel=data;
+ if (takeNext)
+ return data;
+ }
+ }
+ }
+ }
+ }
+
+ if (firstunSel)
+ return firstunSel;
+ else
+ return firstSel;
+}
+
+/* used by posemode as well editmode */
+static void *get_nearest_bone (short findunsel)
+{
+ unsigned int buffer[MAXPICKBUF];
+ short hits;
+
+ persp(PERSP_VIEW);
+
+ glInitNames();
+ hits= view3d_opengl_select(buffer, MAXPICKBUF, 0, 0, 0, 0);
+
+ if (hits>0)
+ return get_bone_from_selectbuffer(BASACT, buffer, hits, findunsel);
+
+ return NULL;
+}
+
+/* used by posemode and editmode */
+void select_bone_parent (void)
+{
+ Object *ob;
+ bArmature *arm;
+
+ /* get data */
+ if (G.obedit)
+ ob= G.obedit;
+ else if (OBACT)
+ ob= OBACT;
+ else
+ return;
+ arm= (bArmature *)ob->data;
+
+ /* determine which mode armature is in */
+ if ((!G.obedit) && (ob->flag & OB_POSEMODE)) {
+ /* deal with pose channels */
+ /* channels are sorted on dependency, so the loop below won't result in a flood-select */
+ bPoseChannel *pchan=NULL;
+
+ for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ /* check if bone in original selection */
+ if (pchan->bone->flag & BONE_SELECTED) {
+ bPoseChannel *chanpar= pchan->parent;
+
+ /* check if any parent */
+ if ((chanpar) && ((chanpar->bone->flag & BONE_SELECTED)==0)) {
+ chanpar->bone->flag |= BONE_SELECTED;
+ select_actionchannel_by_name (ob->action, pchan->name, 1);
+ }
+ }
+ }
+ }
+ else if (G.obedit) {
+ /* deal with editbones */
+ EditBone *curbone, *parbone, *parpar;
+
+ /* prevent floods */
+ for (curbone= G.edbo.first; curbone; curbone= curbone->next)
+ curbone->temp= NULL;
+
+ for (curbone= G.edbo.first; curbone; curbone= curbone->next) {
+ /* check if bone selected */
+ if ((curbone->flag & BONE_SELECTED) && curbone->temp==NULL) {
+ parbone= curbone->parent;
+
+ /* check if any parent */
+ if ((parbone) && ((parbone->flag & BONE_SELECTED)==0)) {
+ /* select the parent bone */
+ parbone->flag |= (BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
+
+ /* check if parent has parent */
+ parpar= parbone->parent;
+
+ if ((parpar) && (parbone->flag & BONE_CONNECTED)) {
+ parpar->flag |= BONE_TIPSEL;
+ }
+ /* tag this bone to not flood selection */
+ parbone->temp= parbone;
+ }
+ }
+ }
+
+ /* to be sure... */
+ for (curbone= G.edbo.first; curbone; curbone= curbone->next)
+ curbone->temp= NULL;
+
+ }
+
+ /* undo + redraw pushes */
+ countall(); // flushes selection!
+
+ allqueue (REDRAWVIEW3D, 0);
+ allqueue (REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWBUTSOBJECT, 0);
+ allqueue(REDRAWOOPS, 0);
+
+ BIF_undo_push("Select Parent");
+}
+
+
+/* **************** END PoseMode & EditMode *************************** */
+/* **************** Posemode stuff ********************** */
+
+
+static void selectconnected_posebonechildren (Object *ob, Bone *bone)
+{
+ Bone *curBone;
+
+ if (!(bone->flag & BONE_CONNECTED))
+ return;
+
+ select_actionchannel_by_name (ob->action, bone->name, !(G.qual & LR_SHIFTKEY));
+
+ if (G.qual & LR_SHIFTKEY)
+ bone->flag &= ~BONE_SELECTED;
+ else
+ bone->flag |= BONE_SELECTED;
+
+ for (curBone=bone->childbase.first; curBone; curBone=curBone->next){
+ selectconnected_posebonechildren (ob, curBone);
+ }
+}
+
+/* within active object context */
+void selectconnected_posearmature(void)
+{
+ Bone *bone, *curBone, *next;
+ Object *ob= OBACT;
+
+ if(!ob || !ob->pose) return;
+
+ if (G.qual & LR_SHIFTKEY)
+ bone= get_nearest_bone(0);
+ else
+ bone = get_nearest_bone(1);
+
+ if (!bone)
+ return;
+
+ /* Select parents */
+ for (curBone=bone; curBone; curBone=next){
+ select_actionchannel_by_name (ob->action, curBone->name, !(G.qual & LR_SHIFTKEY));
+ if (G.qual & LR_SHIFTKEY)
+ curBone->flag &= ~BONE_SELECTED;
+ else
+ curBone->flag |= BONE_SELECTED;
+
+ if (curBone->flag & BONE_CONNECTED)
+ next=curBone->parent;
+ else
+ next=NULL;
+ }
+
+ /* Select children */
+ for (curBone=bone->childbase.first; curBone; curBone=next){
+ selectconnected_posebonechildren (ob, curBone);
+ }
+
+ countall(); // flushes selection!
+
+ allqueue (REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWBUTSOBJECT, 0);
+ allqueue (REDRAWACTION, 0);
+ allqueue(REDRAWOOPS, 0);
+ BIF_undo_push("Select connected");
+
+}
+
+/* **************** END Posemode stuff ********************** */
+/* **************** EditMode stuff ********************** */
+
+/* called in space.c */
+void selectconnected_armature(void)
+{
+ EditBone *bone, *curBone, *next;
+
+ if (G.qual & LR_SHIFTKEY)
+ bone= get_nearest_bone(0);
+ else
+ bone= get_nearest_bone(1);
+
+ if (!bone)
+ return;
+
+ /* Select parents */
+ for (curBone=bone; curBone; curBone=next){
+ if (G.qual & LR_SHIFTKEY){
+ curBone->flag &= ~(BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
+ }
+ else{
+ curBone->flag |= (BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
+ }
+
+ if (curBone->flag & BONE_CONNECTED)
+ next=curBone->parent;
+ else
+ next=NULL;
+ }
+
+ /* Select children */
+ while (bone){
+ for (curBone=G.edbo.first; curBone; curBone=next){
+ next = curBone->next;
+ if (curBone->parent == bone){
+ if (curBone->flag & BONE_CONNECTED){
+ if (G.qual & LR_SHIFTKEY)
+ curBone->flag &= ~(BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
+ else
+ curBone->flag |= (BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
+ bone=curBone;
+ break;
+ }
+ else{
+ bone=NULL;
+ break;
+ }
+ }
+ }
+ if (!curBone)
+ bone=NULL;
+
+ }
+
+ countall(); // flushes selection!
+
+ allqueue (REDRAWVIEW3D, 0);
+ allqueue (REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWBUTSOBJECT, 0);
+ allqueue(REDRAWOOPS, 0);
+
+ BIF_undo_push("Select connected");
+
+}
+
+/* does bones and points */
+/* note that BONE ROOT only gets drawn for root bones (or without IK) */
+static EditBone * get_nearest_editbonepoint (int findunsel, int *selmask)
+{
+ EditBone *ebone;
+ unsigned int buffer[MAXPICKBUF];
+ unsigned int hitresult, besthitresult=BONESEL_NOSEL;
+ int i, mindep= 4;
+ short hits, mval[2];
+
+ persp(PERSP_VIEW);
+
+ glInitNames();
+
+ getmouseco_areawin(mval);
+ hits= view3d_opengl_select(buffer, MAXPICKBUF, mval[0]-5, mval[1]-5, mval[0]+5, mval[1]+5);
+ if(hits==0)
+ hits= view3d_opengl_select(buffer, MAXPICKBUF, mval[0]-12, mval[1]-12, mval[0]+12, mval[1]+12);
+
+ /* See if there are any selected bones in this group */
+ if (hits>0) {
+
+ if(hits==1) {
+ if (!(buffer[3] & BONESEL_NOSEL))
+ besthitresult= buffer[3];
+ }
+ else {
+ for (i=0; i< hits; i++) {
+ hitresult= buffer[3+(i*4)];
+ if (!(hitresult & BONESEL_NOSEL)) {
+ int dep;
+
+ ebone = BLI_findlink(&G.edbo, hitresult & ~BONESEL_ANY);
+
+ /* clicks on bone points get advantage */
+ if( hitresult & (BONESEL_ROOT|BONESEL_TIP)) {
+ /* but also the unselected one */
+ if(findunsel) {
+ if( (hitresult & BONESEL_ROOT) && (ebone->flag & BONE_ROOTSEL)==0)
+ dep= 1;
+ else if( (hitresult & BONESEL_TIP) && (ebone->flag & BONE_TIPSEL)==0)
+ dep= 1;
+ else
+ dep= 2;
+ }
+ else dep= 2;
+ }
+ else {
+ /* bone found */
+ if(findunsel) {
+ if((ebone->flag & BONE_SELECTED)==0)
+ dep= 2;
+ else
+ dep= 3;
+ }
+ else dep= 3;
+ }
+ if(dep < mindep) {
+ mindep= dep;
+ besthitresult= hitresult;
+ }
+ }
+ }
+ }
+
+ if (!(besthitresult & BONESEL_NOSEL)) {
+
+ ebone= BLI_findlink(&G.edbo, besthitresult & ~BONESEL_ANY);
+
+ *selmask = 0;
+ if (besthitresult & BONESEL_ROOT)
+ *selmask |= BONE_ROOTSEL;
+ if (besthitresult & BONESEL_TIP)
+ *selmask |= BONE_TIPSEL;
+ if (besthitresult & BONESEL_BONE)
+ *selmask |= BONE_SELECTED;
+ return ebone;
+ }
+ }
+ *selmask = 0;
+ return NULL;
+}
+
+static void delete_bone(EditBone* exBone)
+{
+ EditBone *curBone;
+
+ /* Find any bones that refer to this bone */
+ for (curBone=G.edbo.first;curBone;curBone=curBone->next){
+ if (curBone->parent==exBone){
+ curBone->parent=exBone->parent;
+ curBone->flag &= ~BONE_CONNECTED;
+ }
+ }
+
+ BLI_freelinkN (&G.edbo,exBone);
+}
+
+/* only editmode! */
+void delete_armature(void)
+{
+ bArmature *arm= G.obedit->data;
+ EditBone *curBone, *next;
+ bConstraint *con;
+
+ TEST_EDITARMATURE;
+ if (okee("Erase selected bone(s)")==0) return;
+
+ /* First erase any associated pose channel */
+ if (G.obedit->pose) {
+ bPoseChannel *chan, *next;
+ for (chan=G.obedit->pose->chanbase.first; chan; chan=next) {
+ next= chan->next;
+ curBone = editbone_name_exists (&G.edbo, chan->name);
+
+ if (curBone && (curBone->flag & BONE_SELECTED) && (arm->layer & curBone->layer)) {
+ free_constraints(&chan->constraints);
+ BLI_freelinkN (&G.obedit->pose->chanbase, chan);
+ }
+ else {
+ for (con= chan->constraints.first; con; con= con->next) {
+ bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+
+ if (cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(con, &targets);
+
+ for (ct= targets.first; ct; ct= ct->next) {
+ if (ct->tar == G.obedit) {
+ if (ct->subtarget[0]) {
+ curBone = editbone_name_exists(&G.edbo, ct->subtarget);
+ if (curBone && (curBone->flag & BONE_SELECTED) && (arm->layer & curBone->layer)) {
+ con->flag |= CONSTRAINT_DISABLE;
+ ct->subtarget[0]= 0;
+ }
+ }
+ }
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(con, &targets, 0);
+ }
+ }
+ }
+ }
+ }
+
+
+ for (curBone=G.edbo.first;curBone;curBone=next) {
+ next=curBone->next;
+ if (arm->layer & curBone->layer)
+ if (curBone->flag & BONE_SELECTED)
+ delete_bone(curBone);
+ }
+
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWBUTSOBJECT, 0);
+ allqueue(REDRAWOOPS, 0);
+ countall(); // flushes selection!
+
+ BIF_undo_push("Delete bone(s)");
+}
+
+/* context: editmode armature */
+void mouse_armature(void)
+{
+ EditBone *nearBone = NULL, *ebone;
+ int selmask;
+
+ nearBone= get_nearest_editbonepoint(1, &selmask);
+ if (nearBone) {
+
+ if (!(G.qual & LR_SHIFTKEY)) {
+ deselectall_armature(0, 0);
+ }
+
+ /* by definition the non-root connected bones have no root point drawn,
+ so a root selection needs to be delivered to the parent tip,
+ countall() (bad location) flushes these flags */
+
+ if(selmask & BONE_SELECTED) {
+ if(nearBone->parent && (nearBone->flag & BONE_CONNECTED)) {
+ /* click in a chain */
+ if(G.qual & LR_SHIFTKEY) {
+ /* hold shift inverts this bone's selection */
+ if(nearBone->flag & BONE_SELECTED) {
+ /* deselect this bone */
+ nearBone->flag &= ~(BONE_TIPSEL|BONE_SELECTED);
+ /* only deselect parent tip if it is not selected */
+ if(!(nearBone->parent->flag & BONE_SELECTED))
+ nearBone->parent->flag &= ~BONE_TIPSEL;
+ }
+ else {
+ /* select this bone */
+ nearBone->flag |= BONE_TIPSEL;
+ nearBone->parent->flag |= BONE_TIPSEL;
+ }
+ }
+ else {
+ /* select this bone */
+ nearBone->flag |= BONE_TIPSEL;
+ nearBone->parent->flag |= BONE_TIPSEL;
+ }
+ }
+ else {
+ if(G.qual & LR_SHIFTKEY) {
+ /* hold shift inverts this bone's selection */
+ if(nearBone->flag & BONE_SELECTED)
+ nearBone->flag &= ~(BONE_TIPSEL|BONE_ROOTSEL);
+ else
+ nearBone->flag |= (BONE_TIPSEL|BONE_ROOTSEL);
+ }
+ else nearBone->flag |= (BONE_TIPSEL|BONE_ROOTSEL);
+ }
+ }
+ else {
+ if ((G.qual & LR_SHIFTKEY) && (nearBone->flag & selmask))
+ nearBone->flag &= ~selmask;
+ else
+ nearBone->flag |= selmask;
+ }
+
+ countall(); // flushes selection!
+
+ if(nearBone) {
+ /* then now check for active status */
+ for (ebone=G.edbo.first;ebone;ebone=ebone->next) ebone->flag &= ~BONE_ACTIVE;
+ if(nearBone->flag & BONE_SELECTED) nearBone->flag |= BONE_ACTIVE;
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWBUTSOBJECT, 0);
+ allqueue(REDRAWOOPS, 0);
+ }
+
+ rightmouse_transform();
+}
+
+void free_editArmature(void)
+{
+
+ /* Clear the editbones list */
+ if (G.edbo.first){
+ BLI_freelistN (&G.edbo);
+ }
+}
+
+void remake_editArmature(void)
+{
+ if(okee("Reload original data")==0) return;
+
+ make_editArmature();
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWOOPS, 0);
+ allqueue(REDRAWBUTSHEAD, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWBUTSOBJECT, 0);
+
+// BIF_undo_push("Delete bone");
+
+}
+
+/* Put object in EditMode */
+void make_editArmature(void)
+{
+ bArmature *arm;
+
+ if (G.obedit==0) return;
+
+ free_editArmature();
+
+ arm= get_armature(G.obedit);
+ if (!arm)
+ return;
+
+ make_boneList (&G.edbo, &arm->bonebase,NULL);
+}
+
+/* put EditMode back in Object */
+void load_editArmature(void)
+{
+ bArmature *arm;
+
+ arm= get_armature(G.obedit);
+ if (!arm) return;
+
+ editbones_to_armature(&G.edbo, G.obedit);
+}
+
+/* toggle==0: deselect
+ toggle==1: swap
+ toggle==2: only active tag
+*/
+void deselectall_armature(int toggle, int doundo)
+{
+ bArmature *arm= G.obedit->data;
+ EditBone *eBone;
+ int sel=1;
+
+ if(toggle==1) {
+ /* Determine if there are any selected bones
+ And therefore whether we are selecting or deselecting */
+ for (eBone=G.edbo.first;eBone;eBone=eBone->next){
+// if(arm->layer & eBone->layer) {
+ if (eBone->flag & (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)){
+ sel=0;
+ break;
+ }
+// }
+ }
+ }
+ else sel= toggle;
+
+ /* Set the flags */
+ for (eBone=G.edbo.first;eBone;eBone=eBone->next){
+ if (sel==1) {
+ if(arm->layer & eBone->layer && (eBone->flag & BONE_HIDDEN_A)==0) {
+ eBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ if(eBone->parent)
+ eBone->parent->flag |= (BONE_TIPSEL);
+ }
+ }
+ else if (sel==2)
+ eBone->flag &= ~(BONE_ACTIVE);
+ else
+ eBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL | BONE_ACTIVE);
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWBUTSOBJECT, 0);
+ allqueue(REDRAWOOPS, 0);
+
+ countall(); // flushes selection!
+ if (doundo) {
+ if (sel==1) BIF_undo_push("Select All");
+ else BIF_undo_push("Deselect All");
+ }
+}
+
+/* Sets the roll value of selected bones, depending on the mode
+ * mode == 0: their z-axes point upwards
+ * mode == 1: their z-axes point towards 3d-cursor
+ */
+void auto_align_armature(short mode)
+{
+ bArmature *arm= G.obedit->data;
+ EditBone *ebone;
+ float delta[3];
+ float curmat[3][3];
+ float *cursor= give_cursor();
+
+ for (ebone = G.edbo.first; ebone; ebone=ebone->next) {
+ if(arm->layer & ebone->layer) {
+ if (ebone->flag & BONE_SELECTED) {
+ /* specific method used to calculate roll depends on mode */
+ if (mode == 1) {
+ /* Z-Axis point towards cursor */
+ float mat[4][4], tmat[4][4], imat[4][4];
+ float rmat[4][4], rot[3];
+ float vec[3];
+
+ /* find the current bone matrix as a 4x4 matrix (in Armature Space) */
+ VecSubf(delta, ebone->tail, ebone->head);
+ vec_roll_to_mat3(delta, ebone->roll, curmat);
+ Mat4CpyMat3(mat, curmat);
+ VECCOPY(mat[3], ebone->head);
+
+ /* multiply bone-matrix by object matrix (so that bone-matrix is in WorldSpace) */
+ Mat4MulMat4(tmat, mat, G.obedit->obmat);
+ Mat4Invert(imat, tmat);
+
+ /* find position of cursor relative to bone */
+ VecMat4MulVecfl(vec, imat, cursor);
+
+ /* check that cursor is in usable position */
+ if ((IS_EQ(vec[0], 0)==0) && (IS_EQ(vec[2], 0)==0)) {
+ /* Compute a rotation matrix around y */
+ rot[1] = atan2(vec[0], vec[2]);
+ rot[0] = rot[2] = 0.0f;
+ EulToMat4(rot, rmat);
+
+ /* Multiply the bone matrix by rotation matrix. This should be new bone-matrix */
+ Mat4MulMat4(tmat, rmat, mat);
+ Mat3CpyMat4(curmat, tmat);
+
+ /* Now convert from new bone-matrix, back to a roll value (in radians) */
+ mat3_to_vec_roll(curmat, delta, &ebone->roll);
+ }
+ }
+ else {
+ /* Z-Axis Point Up */
+ float xaxis[3]={1.0, 0.0, 0.0}, yaxis[3], zaxis[3]={0.0, 0.0, 1.0};
+ float targetmat[3][3], imat[3][3], diffmat[3][3];
+
+ /* Find the current bone matrix */
+ VecSubf(delta, ebone->tail, ebone->head);
+ vec_roll_to_mat3(delta, 0.0, curmat);
+
+ /* Make new matrix based on y axis & z-up */
+ VECCOPY (yaxis, curmat[1]);
+
+ Mat3One(targetmat);
+ VECCOPY (targetmat[0], xaxis);
+ VECCOPY (targetmat[1], yaxis);
+ VECCOPY (targetmat[2], zaxis);
+ Mat3Ortho(targetmat);
+
+ /* Find the difference between the two matrices */
+ Mat3Inv(imat, targetmat);
+ Mat3MulMat3(diffmat, imat, curmat);
+
+ ebone->roll = atan2(diffmat[2][0], diffmat[2][2]);
+ }
+ }
+ }
+ }
+}
+
+/* **************** undo for armatures ************** */
+
+static void undoBones_to_editBones(void *lbv)
+{
+ ListBase *lb= lbv;
+ EditBone *ebo, *newebo;
+
+ BLI_freelistN(&G.edbo);
+
+ /* copy */
+ for(ebo= lb->first; ebo; ebo= ebo->next) {
+ newebo= MEM_dupallocN(ebo);
+ ebo->temp= newebo;
+ BLI_addtail(&G.edbo, newebo);
+ }
+
+ /* set pointers */
+ for(newebo= G.edbo.first; newebo; newebo= newebo->next) {
+ if(newebo->parent) newebo->parent= newebo->parent->temp;
+ }
+ /* be sure they dont hang ever */
+ for(newebo= G.edbo.first; newebo; newebo= newebo->next) {
+ newebo->temp= NULL;
+ }
+}
+
+static void *editBones_to_undoBones(void)
+{
+ ListBase *lb;
+ EditBone *ebo, *newebo;
+
+ lb= MEM_callocN(sizeof(ListBase), "listbase undo");
+
+ /* copy */
+ for(ebo= G.edbo.first; ebo; ebo= ebo->next) {
+ newebo= MEM_dupallocN(ebo);
+ ebo->temp= newebo;
+ BLI_addtail(lb, newebo);
+ }
+
+ /* set pointers */
+ for(newebo= lb->first; newebo; newebo= newebo->next) {
+ if(newebo->parent) newebo->parent= newebo->parent->temp;
+ }
+
+ return lb;
+}
+
+static void free_undoBones(void *lbv)
+{
+ ListBase *lb= lbv;
+
+ BLI_freelistN(lb);
+ MEM_freeN(lb);
+}
+
+/* and this is all the undo system needs to know */
+void undo_push_armature(char *name)
+{
+ undo_editmode_push(name, free_undoBones, undoBones_to_editBones, editBones_to_undoBones);
+}
+
+
+
+/* **************** END EditMode stuff ********************** */
+/* *************** Adding stuff in editmode *************** */
+
+/* default bone add, returns it selected, but without tail set */
+static EditBone *add_editbone(char *name)
+{
+ bArmature *arm= G.obedit->data;
+
+ EditBone *bone= MEM_callocN(sizeof(EditBone), "eBone");
+
+ BLI_strncpy (bone->name, name, 32);
+ unique_editbone_name(&G.edbo, bone->name);
+
+ BLI_addtail(&G.edbo, bone);
+
+ bone->flag |= BONE_TIPSEL;
+ bone->weight= 1.0F;
+ bone->dist= 0.25F;
+ bone->xwidth= 0.1;
+ bone->zwidth= 0.1;
+ bone->ease1= 1.0;
+ bone->ease2= 1.0;
+ bone->rad_head= 0.10;
+ bone->rad_tail= 0.05;
+ bone->segments= 1;
+ bone->layer= arm->layer;
+
+ return bone;
+}
+
+static void add_primitive_bone(Object *ob, short newob)
+{
+ float obmat[3][3], curs[3], viewmat[3][3], totmat[3][3], imat[3][3];
+ EditBone *bone;
+
+ VECCOPY (curs, give_cursor());
+
+ /* Get inverse point for head and orientation for tail */
+ Mat4Invert(G.obedit->imat, G.obedit->obmat);
+ Mat4MulVecfl(G.obedit->imat, curs);
+
+ if ( !(newob) || U.flag & USER_ADD_VIEWALIGNED) Mat3CpyMat4(obmat, G.vd->viewmat);
+ else Mat3One(obmat);
+
+ Mat3CpyMat4(viewmat, G.obedit->obmat);
+ Mat3MulMat3(totmat, obmat, viewmat);
+ Mat3Inv(imat, totmat);
+
+ deselectall_armature(0, 0);
+
+ /* Create a bone */
+ bone= add_editbone("Bone");
+
+ VECCOPY(bone->head, curs);
+
+ if ( !(newob) || U.flag & USER_ADD_VIEWALIGNED)
+ VecAddf(bone->tail, bone->head, imat[1]); // bone with unit length 1
+ else
+ VecAddf(bone->tail, bone->head, imat[2]); // bone with unit length 1, pointing up Z
+
+}
+
+void add_primitiveArmature(int type)
+{
+ short newob=0;
+
+ if(G.scene->id.lib) return;
+
+ /* this function also comes from an info window */
+ if ELEM(curarea->spacetype, SPACE_VIEW3D, SPACE_INFO); else return;
+ if(G.vd==NULL) return;
+
+ G.f &= ~(G_VERTEXPAINT+G_TEXTUREPAINT+G_WEIGHTPAINT);
+ setcursor_space(SPACE_VIEW3D, CURSOR_STD);
+
+ check_editmode(OB_ARMATURE);
+
+ /* If we're not the "obedit", make a new object and enter editmode */
+ if(G.obedit==NULL) {
+ add_object(OB_ARMATURE);
+ base_init_from_view3d(BASACT, G.vd);
+ G.obedit= BASACT->object;
+
+ where_is_object(G.obedit);
+
+ make_editArmature();
+ setcursor_space(SPACE_VIEW3D, CURSOR_EDIT);
+ newob=1;
+ }
+
+ /* no primitive support yet */
+ add_primitive_bone(G.obedit, newob);
+
+ countall(); // flushes selection!
+
+ if ( (newob) && !(U.flag & USER_ADD_EDITMODE)) {
+ exit_editmode(2);
+ }
+
+ allqueue(REDRAWALL, 0);
+ BIF_undo_push("Add primitive");
+}
+
+/* the ctrl-click method */
+void addvert_armature(void)
+{
+ bArmature *arm= G.obedit->data;
+ EditBone *ebone, *newbone, *flipbone;
+ float *curs, mat[3][3],imat[3][3];
+ int a, to_root= 0;
+
+ TEST_EDITARMATURE;
+
+ /* find the active or selected bone */
+ for (ebone = G.edbo.first; ebone; ebone=ebone->next)
+ if(arm->layer & ebone->layer)
+ if(ebone->flag & (BONE_ACTIVE|BONE_TIPSEL)) break;
+
+ if(ebone==NULL) {
+ for (ebone = G.edbo.first; ebone; ebone=ebone->next)
+ if(arm->layer & ebone->layer)
+ if(ebone->flag & (BONE_ACTIVE|BONE_ROOTSEL)) break;
+
+ if(ebone==NULL)
+ return;
+ to_root= 1;
+ }
+
+ deselectall_armature(0, 0);
+
+ /* we re-use code for mirror editing... */
+ flipbone= NULL;
+ if(arm->flag & ARM_MIRROR_EDIT)
+ flipbone= armature_bone_get_mirrored(ebone);
+
+ for(a=0; a<2; a++) {
+ if(a==1) {
+ if(flipbone==NULL)
+ break;
+ else {
+ SWAP(EditBone *, flipbone, ebone);
+ }
+ }
+
+ newbone= add_editbone(ebone->name);
+ newbone->flag |= BONE_ACTIVE;
+
+ if(to_root) {
+ VECCOPY(newbone->head, ebone->head);
+ newbone->rad_head= ebone->rad_tail;
+ newbone->parent= ebone->parent;
+ }
+ else {
+ VECCOPY(newbone->head, ebone->tail);
+ newbone->rad_head= ebone->rad_tail;
+ newbone->parent= ebone;
+ newbone->flag |= BONE_CONNECTED;
+ }
+
+ curs= give_cursor();
+ VECCOPY(newbone->tail, curs);
+ VecSubf(newbone->tail, newbone->tail, G.obedit->obmat[3]);
+
+ if(a==1)
+ newbone->tail[0]= -newbone->tail[0];
+
+ Mat3CpyMat4(mat, G.obedit->obmat);
+ Mat3Inv(imat, mat);
+ Mat3MulVecfl(imat, newbone->tail);
+
+ newbone->length= VecLenf(newbone->head, newbone->tail);
+ newbone->rad_tail= newbone->length*0.05f;
+ newbone->dist= newbone->length*0.25f;
+
+ }
+
+
+ countall();
+
+ BIF_undo_push("Add Bone");
+ allqueue(REDRAWVIEW3D, 0);
+
+ while(get_mbut()&R_MOUSE);
+}
+
+
+static EditBone *get_named_editbone(char *name)
+{
+ EditBone *eBone;
+
+ if (name)
+ for (eBone=G.edbo.first; eBone; eBone=eBone->next){
+ if (!strcmp (name, eBone->name))
+ return eBone;
+ }
+
+ return NULL;
+}
+
+static void update_dup_subtarget(EditBone *dupBone)
+{
+ /* If an edit bone has been duplicated, lets
+ * update it's constraints if the subtarget
+ * they point to has also been duplicated
+ */
+ EditBone *oldtarget, *newtarget;
+ bPoseChannel *chan;
+ bConstraint *curcon;
+ ListBase *conlist;
+
+
+ if ( (chan = verify_pose_channel(OBACT->pose, dupBone->name)) ) {
+ if ( (conlist = &chan->constraints) ) {
+ for (curcon = conlist->first; curcon; curcon=curcon->next) {
+ /* does this constraint have a subtarget in
+ * this armature?
+ */
+ bConstraintTypeInfo *cti= constraint_get_typeinfo(curcon);
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+
+ if (cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(curcon, &targets);
+
+ for (ct= targets.first; ct; ct= ct->next) {
+ if ((ct->tar == G.obedit) && (ct->subtarget[0])) {
+ oldtarget = get_named_editbone(ct->subtarget);
+ if (oldtarget) {
+ /* was the subtarget bone duplicated too? If
+ * so, update the constraint to point at the
+ * duplicate of the old subtarget.
+ */
+ if (oldtarget->flag & BONE_SELECTED){
+ newtarget = (EditBone *) oldtarget->temp;
+ strcpy(ct->subtarget, newtarget->name);
+ }
+ }
+ }
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(curcon, &targets, 0);
+ }
+ }
+ }
+ }
+}
+
+
+void adduplicate_armature(void)
+{
+ bArmature *arm= G.obedit->data;
+ EditBone *eBone = NULL;
+ EditBone *curBone;
+ EditBone *firstDup=NULL; /* The beginning of the duplicated bones in the edbo list */
+
+ countall(); // flushes selection!
+
+ /* Find the selected bones and duplicate them as needed */
+ for (curBone=G.edbo.first; curBone && curBone!=firstDup; curBone=curBone->next){
+ if(arm->layer & curBone->layer) {
+ if (curBone->flag & BONE_SELECTED){
+
+ eBone=MEM_callocN(sizeof(EditBone), "addup_editbone");
+ eBone->flag |= BONE_SELECTED;
+
+ /* Copy data from old bone to new bone */
+ memcpy (eBone, curBone, sizeof(EditBone));
+
+ curBone->temp = eBone;
+ eBone->temp = curBone;
+
+ unique_editbone_name (&G.edbo, eBone->name);
+ BLI_addtail (&G.edbo, eBone);
+ if (!firstDup)
+ firstDup=eBone;
+
+ /* Lets duplicate the list of constraints that the
+ * current bone has.
+ */
+ if (OBACT->pose) {
+ bPoseChannel *chanold, *channew;
+ ListBase *listold, *listnew;
+
+ chanold = verify_pose_channel (OBACT->pose, curBone->name);
+ if (chanold) {
+ listold = &chanold->constraints;
+ if (listold) {
+ /* WARNING: this creates a new posechannel, but there will not be an attached bone
+ * yet as the new bones created here are still 'EditBones' not 'Bones'.
+ */
+ channew =
+ verify_pose_channel(OBACT->pose, eBone->name);
+ if (channew) {
+ /* copy transform locks */
+ channew->protectflag = chanold->protectflag;
+
+ /* ik (dof) settings */
+ channew->ikflag = chanold->ikflag;
+ VECCOPY(channew->limitmin, chanold->limitmin);
+ VECCOPY(channew->limitmax, chanold->limitmax);
+ VECCOPY(channew->stiffness, chanold->stiffness);
+ channew->ikstretch= chanold->ikstretch;
+
+ /* constraints */
+ listnew = &channew->constraints;
+ copy_constraints (listnew, listold);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Run though the list and fix the pointers */
+ for (curBone=G.edbo.first; curBone && curBone!=firstDup; curBone=curBone->next){
+ if(arm->layer & curBone->layer) {
+ if (curBone->flag & BONE_SELECTED){
+ eBone=(EditBone*) curBone->temp;
+
+ /* If this bone has no parent,
+ Set the duplicate->parent to NULL
+ */
+ if (!curBone->parent){
+ eBone->parent = NULL;
+ }
+ /* If this bone has a parent that IS selected,
+ Set the duplicate->parent to the curBone->parent->duplicate
+ */
+ else if (curBone->parent->flag & BONE_SELECTED){
+ eBone->parent=(EditBone*) curBone->parent->temp;
+ }
+ /* If this bone has a parent that IS not selected,
+ Set the duplicate->parent to the curBone->parent
+ */
+ else {
+ eBone->parent=(EditBone*) curBone->parent;
+ eBone->flag &= ~BONE_CONNECTED;
+ }
+
+ /* Lets try to fix any constraint subtargets that might
+ have been duplicated */
+ update_dup_subtarget(eBone);
+ }
+ }
+ }
+
+ /* Deselect the old bones and select the new ones */
+
+ for (curBone=G.edbo.first; curBone && curBone!=firstDup; curBone=curBone->next){
+ if(arm->layer & curBone->layer)
+ curBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL | BONE_ACTIVE);
+ }
+
+ BIF_TransformSetUndo("Add Duplicate");
+ initTransform(TFM_TRANSLATION, CTX_NO_PET);
+ Transform();
+
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWBUTSOBJECT, 0);
+ allqueue(REDRAWOOPS, 0);
+}
+
+
+
+/* *************** END Adding stuff in editmode *************** */
+/* *************** Tools in editmode *********** */
+
+
+void hide_selected_armature_bones(void)
+{
+ bArmature *arm= G.obedit->data;
+ EditBone *ebone;
+
+ for (ebone = G.edbo.first; ebone; ebone=ebone->next){
+ if(arm->layer & ebone->layer) {
+ if(ebone->flag & (BONE_SELECTED)) {
+ ebone->flag &= ~(BONE_TIPSEL|BONE_SELECTED|BONE_ROOTSEL|BONE_ACTIVE);
+ ebone->flag |= BONE_HIDDEN_A;
+ }
+ }
+ }
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ BIF_undo_push("Hide Bones");
+}
+
+void hide_unselected_armature_bones(void)
+{
+ EditBone *ebone;
+
+ for (ebone = G.edbo.first; ebone; ebone=ebone->next){
+ bArmature *arm= G.obedit->data;
+ if(arm->layer & ebone->layer) {
+ if(ebone->flag & (BONE_TIPSEL|BONE_SELECTED|BONE_ROOTSEL));
+ else {
+ ebone->flag &= ~BONE_ACTIVE;
+ ebone->flag |= BONE_HIDDEN_A;
+ }
+ }
+ }
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ BIF_undo_push("Hide Unselected Bones");
+}
+
+void show_all_armature_bones(void)
+{
+ EditBone *ebone;
+
+ for (ebone = G.edbo.first; ebone; ebone=ebone->next){
+ bArmature *arm= G.obedit->data;
+ if(arm->layer & ebone->layer) {
+ if(ebone->flag & BONE_HIDDEN_A) {
+ ebone->flag |= (BONE_TIPSEL|BONE_SELECTED|BONE_ROOTSEL);
+ ebone->flag &= ~BONE_HIDDEN_A;
+ }
+ }
+ }
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ BIF_undo_push("Reveal Bones");
+}
+
+void make_bone_parent(void)
+{
+ bArmature *arm= G.obedit->data;
+ EditBone *actbone, *ebone, *selbone;
+ short allchildbones= 0, foundselbone= 0;
+ float offset[3];
+ short val;
+
+ /* find active bone to parent to */
+ for (actbone = G.edbo.first; actbone; actbone=actbone->next) {
+ if (arm->layer & actbone->layer) {
+ if (actbone->flag & BONE_ACTIVE)
+ break;
+ }
+ }
+ if (actbone == NULL) {
+ error("Needs an active bone");
+ return;
+ }
+
+ /* find selected bones */
+ for (ebone = G.edbo.first; ebone; ebone=ebone->next) {
+ if (arm->layer & ebone->layer) {
+ if ((ebone->flag & BONE_SELECTED) && (ebone != actbone)) {
+ foundselbone++;
+ if (ebone->parent != actbone) allchildbones= 1;
+ }
+ }
+ }
+ /* abort if no selected bones, and active bone doesn't have a parent to work with instead */
+ if (foundselbone==0 && actbone->parent==NULL) {
+ error("Need selected bone(s)");
+ return;
+ }
+
+ /* 'Keep Offset' option is only displayed if it's likely to be useful */
+ if (allchildbones)
+ val= pupmenu("Make Parent%t|Connected%x1|Keep Offset%x2");
+ else
+ val= pupmenu("Make Parent%t|Connected%x1");
+
+ if (val < 1) return;
+
+ if (foundselbone==0 && actbone->parent) {
+ /* When only the active bone is selected, and it has a parent,
+ * connect it to the parent, as that is the only possible outcome.
+ */
+ actbone->flag |= BONE_CONNECTED;
+ VECCOPY(actbone->head, actbone->parent->tail);
+ actbone->rad_head= actbone->parent->rad_tail;
+ }
+ else {
+ /* loop through all editbones, parenting all selected bones to the active bone */
+ for (selbone = G.edbo.first; selbone; selbone=selbone->next) {
+ if (arm->layer & selbone->layer) {
+ if ((selbone->flag & BONE_SELECTED) && (selbone!=actbone)) {
+ /* if selbone had a parent we clear parent tip */
+ if (selbone->parent && (selbone->flag & BONE_CONNECTED))
+ selbone->parent->flag &= ~(BONE_TIPSEL);
+
+ /* make actbone the parent of selbone */
+ selbone->parent= actbone;
+
+ /* in actbone tree we cannot have a loop */
+ for (ebone= actbone->parent; ebone; ebone= ebone->parent) {
+ if (ebone->parent==selbone) {
+ ebone->parent= NULL;
+ ebone->flag &= ~BONE_CONNECTED;
+ }
+ }
+
+ if (val == 1) {
+ /* Connected: Child bones will be moved to the parent tip */
+ selbone->flag |= BONE_CONNECTED;
+ VecSubf(offset, actbone->tail, selbone->head);
+
+ VECCOPY(selbone->head, actbone->tail);
+ selbone->rad_head= actbone->rad_tail;
+
+ VecAddf(selbone->tail, selbone->tail, offset);
+
+ /* offset for all its children */
+ for (ebone = G.edbo.first; ebone; ebone=ebone->next) {
+ EditBone *par;
+
+ for (par= ebone->parent; par; par= par->parent) {
+ if (par==selbone) {
+ VecAddf(ebone->head, ebone->head, offset);
+ VecAddf(ebone->tail, ebone->tail, offset);
+ break;
+ }
+ }
+ }
+ }
+ else {
+ /* Offset: Child bones will retain their distance from the parent tip */
+ selbone->flag &= ~BONE_CONNECTED;
+ }
+ }
+
+ }
+ }
+ }
+
+ countall(); /* checks selection */
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWOOPS, 0);
+ BIF_undo_push("Make Parent");
+
+ return;
+}
+
+void clear_bone_parent(void)
+{
+ bArmature *arm= G.obedit->data;
+ EditBone *ebone;
+ short val;
+
+ val= pupmenu("Clear Parent%t|Clear Parent%x1|Disconnect Bone%x2");
+
+ if(val<1) return;
+ for (ebone = G.edbo.first; ebone; ebone=ebone->next) {
+ if(arm->layer & ebone->layer) {
+ if(ebone->flag & BONE_SELECTED) {
+ if(ebone->parent) {
+ /* for nice selection */
+ ebone->parent->flag &= ~(BONE_TIPSEL);
+
+ if(val==1) ebone->parent= NULL;
+ ebone->flag &= ~BONE_CONNECTED;
+ }
+ }
+ }
+ }
+ countall(); // checks selection
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWOOPS, 0);
+ BIF_undo_push("Clear Parent");
+}
+
+
+static EditBone *editbone_name_exists (ListBase *ebones, char *name)
+{
+ EditBone *eBone;
+
+ if (ebones == NULL) ebones = &G.edbo;
+
+ for (eBone=ebones->first; eBone; eBone=eBone->next){
+ if (!strcmp (name, eBone->name))
+ return eBone;
+ }
+ return NULL;
+}
+
+/* note: there's a unique_bone_name() too! */
+void unique_editbone_name (ListBase *ebones, char *name)
+{
+ char tempname[64];
+ int number;
+ char *dot;
+
+
+ if (editbone_name_exists(ebones, name)) {
+
+ /* Strip off the suffix, if it's a number */
+ number= strlen(name);
+ if(number && isdigit(name[number-1])) {
+ dot= strrchr(name, '.'); // last occurrance
+ if (dot)
+ *dot=0;
+ }
+
+ for (number = 1; number <=999; number++){
+ sprintf (tempname, "%s.%03d", name, number);
+ if (!editbone_name_exists(ebones, tempname)){
+ BLI_strncpy (name, tempname, 32);
+ return;
+ }
+ }
+ }
+}
+
+/* context; editmode armature */
+/* if forked && mirror-edit: makes two bones with flipped names */
+void extrude_armature(int forked)
+{
+ bArmature *arm= G.obedit->data;
+ EditBone *newbone, *ebone, *flipbone, *first=NULL;
+ int a, totbone= 0, do_extrude;
+
+ TEST_EDITARMATURE;
+
+ /* since we allow root extrude too, we have to make sure selection is OK */
+ for (ebone = G.edbo.first; ebone; ebone=ebone->next){
+ if(arm->layer & ebone->layer) {
+ if(ebone->flag & BONE_ROOTSEL) {
+ if(ebone->parent && (ebone->flag & BONE_CONNECTED)) {
+ if(ebone->parent->flag & BONE_TIPSEL)
+ ebone->flag &= ~BONE_ROOTSEL;
+ }
+ }
+ }
+ }
+
+ /* Duplicate the necessary bones */
+ for (ebone = G.edbo.first; ((ebone) && (ebone!=first)); ebone=ebone->next){
+ if(arm->layer & ebone->layer) {
+
+ /* we extrude per definition the tip */
+ do_extrude= 0;
+ if (ebone->flag & (BONE_TIPSEL|BONE_SELECTED))
+ do_extrude= 1;
+ else if(ebone->flag & BONE_ROOTSEL) {
+ /* but, a bone with parent deselected we do the root... */
+ if(ebone->parent && (ebone->parent->flag & BONE_TIPSEL));
+ else do_extrude= 2;
+ }
+
+ if (do_extrude) {
+
+ /* we re-use code for mirror editing... */
+ flipbone= NULL;
+ if(arm->flag & ARM_MIRROR_EDIT) {
+ flipbone= armature_bone_get_mirrored(ebone);
+ if (flipbone) {
+ forked= 0; // we extrude 2 different bones
+ if(flipbone->flag & (BONE_TIPSEL|BONE_ROOTSEL|BONE_SELECTED))
+ /* don't want this bone to be selected... */
+ flipbone->flag &= ~(BONE_TIPSEL|BONE_SELECTED|BONE_ROOTSEL|BONE_ACTIVE);
+ }
+ if(flipbone==NULL && forked)
+ flipbone= ebone;
+ }
+
+ for(a=0; a<2; a++) {
+ if(a==1) {
+ if(flipbone==NULL)
+ break;
+ else {
+ SWAP(EditBone *, flipbone, ebone);
+ }
+ }
+
+ totbone++;
+ newbone = MEM_callocN(sizeof(EditBone), "extrudebone");
+
+ if(do_extrude==1) {
+ VECCOPY (newbone->head, ebone->tail);
+ VECCOPY (newbone->tail, newbone->head);
+ newbone->parent = ebone;
+
+ newbone->flag = ebone->flag & BONE_TIPSEL; // copies it, in case mirrored bone
+ }
+ else {
+ VECCOPY(newbone->head, ebone->head);
+ VECCOPY(newbone->tail, ebone->head);
+ newbone->parent= ebone->parent;
+
+ newbone->flag= BONE_TIPSEL;
+ }
+
+ newbone->weight= ebone->weight;
+ newbone->dist= ebone->dist;
+ newbone->xwidth= ebone->xwidth;
+ newbone->zwidth= ebone->zwidth;
+ newbone->ease1= ebone->ease1;
+ newbone->ease2= ebone->ease2;
+ newbone->rad_head= ebone->rad_tail; // dont copy entire bone...
+ newbone->rad_tail= ebone->rad_tail;
+ newbone->segments= 1;
+ newbone->layer= ebone->layer;
+
+ if(newbone->parent) newbone->flag |= BONE_CONNECTED;
+
+ BLI_strncpy (newbone->name, ebone->name, 32);
+
+ if(flipbone && forked) { // only set if mirror edit
+ if(strlen(newbone->name)<30) {
+ if(a==0) strcat(newbone->name, "_L");
+ else strcat(newbone->name, "_R");
+ }
+ }
+ unique_editbone_name(&G.edbo, newbone->name);
+
+ /* Add the new bone to the list */
+ BLI_addtail(&G.edbo, newbone);
+ if (!first)
+ first = newbone;
+
+ /* restore ebone if we were flipping */
+ if(a==1 && flipbone)
+ SWAP(EditBone *, flipbone, ebone);
+
+ }
+ }
+
+ /* Deselect the old bone */
+ ebone->flag &= ~(BONE_TIPSEL|BONE_SELECTED|BONE_ROOTSEL|BONE_ACTIVE);
+ }
+ }
+ /* if only one bone, make this one active */
+ if(totbone==1 && first) first->flag |= BONE_ACTIVE;
+
+ /* Transform the endpoints */
+ countall(); // flushes selection!
+ BIF_TransformSetUndo("Extrude");
+ initTransform(TFM_TRANSLATION, CTX_NO_PET);
+ Transform();
+
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWBUTSOBJECT, 0);
+ allqueue(REDRAWOOPS, 0);
+}
+
+/* context; editmode armature */
+void subdivide_armature(int numcuts)
+{
+ bArmature *arm= G.obedit->data;
+ EditBone *ebone, *newbone, *tbone, *mbone;
+ int a, i;
+
+ if(numcuts < 1) return;
+
+ for (mbone = G.edbo.last; mbone; mbone= mbone->prev) {
+ if(arm->layer & mbone->layer) {
+ if(mbone->flag & BONE_SELECTED) {
+ for(i=numcuts+1; i>1; i--) {
+ /* compute cut ratio first */
+ float cutratio= 1/(float)i;
+ float cutratioI= 1-cutratio;
+
+ /* take care of mirrored stuff */
+ for(a=0; a<2; a++) {
+ float val1[3];
+ float val2[3];
+ float val3[3];
+
+ /* try to find mirrored bone on a != 0 */
+ if(a) {
+ if(arm->flag & ARM_MIRROR_EDIT)
+ ebone= armature_bone_get_mirrored(mbone);
+ else ebone= NULL;
+ }
+ else
+ ebone= mbone;
+
+ if(ebone) {
+ newbone= MEM_mallocN(sizeof(EditBone), "ebone subdiv");
+ *newbone = *ebone;
+ BLI_addtail(&G.edbo, newbone);
+
+ /* calculate location of newbone->head */
+ VECCOPY(val1, ebone->head);
+ VECCOPY(val2, ebone->tail);
+ VECCOPY(val3, newbone->head);
+
+ val3[0]= val1[0]*cutratio+val2[0]*cutratioI;
+ val3[1]= val1[1]*cutratio+val2[1]*cutratioI;
+ val3[2]= val1[2]*cutratio+val2[2]*cutratioI;
+
+ VECCOPY(newbone->head, val3);
+ VECCOPY(newbone->tail, ebone->tail);
+ VECCOPY(ebone->tail, newbone->head);
+
+ newbone->rad_head= 0.5*(ebone->rad_head+ebone->rad_tail);
+ ebone->rad_tail= newbone->rad_head;
+
+ newbone->flag |= BONE_CONNECTED;
+
+ unique_editbone_name (&G.edbo, newbone->name);
+
+ /* correct parent bones */
+ for (tbone = G.edbo.first; tbone; tbone=tbone->next){
+ if(tbone->parent==ebone)
+ tbone->parent= newbone;
+ }
+ newbone->parent= ebone;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if(numcuts==1) BIF_undo_push("Subdivide");
+ else BIF_undo_push("Subdivide multi");
+}
+
+/* ***************** Pose tools ********************* */
+
+void clear_armature(Object *ob, char mode)
+{
+ bPoseChannel *pchan;
+ bArmature *arm;
+
+ arm=get_armature(ob);
+
+ if (!arm)
+ return;
+
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ if(pchan->bone && (pchan->bone->flag & BONE_SELECTED)) {
+ if(arm->layer & pchan->bone->layer) {
+ switch (mode) {
+ case 'r':
+ pchan->quat[1]=pchan->quat[2]=pchan->quat[3]=0.0F; pchan->quat[0]=1.0F;
+ break;
+ case 'g':
+ pchan->loc[0]=pchan->loc[1]=pchan->loc[2]=0.0F;
+ break;
+ case 's':
+ pchan->size[0]=pchan->size[1]=pchan->size[2]=1.0F;
+ break;
+
+ }
+
+ /* the current values from IPO's may not be zero, so tag as unkeyed */
+ pchan->bone->flag |= BONE_UNKEYED;
+ }
+ }
+ }
+
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ /* no update for this object, this will execute the action again */
+ /* is weak... like for ipo editing which uses ctime now... */
+ where_is_pose (ob);
+ ob->recalc= 0;
+}
+
+/* helper for function below */
+static int clear_active_flag(Object *ob, Bone *bone, void *data)
+{
+ bone->flag &= ~BONE_ACTIVE;
+ return 0;
+}
+
+
+/* called from editview.c, for mode-less pose selection */
+int do_pose_selectbuffer(Base *base, unsigned int *buffer, short hits)
+{
+ Object *ob= base->object;
+ Bone *nearBone;
+
+ if (!ob || !ob->pose) return 0;
+
+ nearBone= get_bone_from_selectbuffer(base, buffer, hits, 1);
+
+ if (nearBone) {
+ /* since we do unified select, we don't shift+select a bone if the armature object was not active yet */
+ if (!(G.qual & LR_SHIFTKEY) || base!=BASACT){
+ deselectall_posearmature(ob, 0, 0);
+ nearBone->flag |= (BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL|BONE_ACTIVE);
+ select_actionchannel_by_name(ob->action, nearBone->name, 1);
+ }
+ else {
+ if (nearBone->flag & BONE_SELECTED) {
+ /* if not active, we make it active */
+ if((nearBone->flag & BONE_ACTIVE)==0) {
+ bArmature *arm= ob->data;
+ bone_looper(ob, arm->bonebase.first, NULL, clear_active_flag);
+
+ nearBone->flag |= BONE_ACTIVE;
+ }
+ else {
+ nearBone->flag &= ~(BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL|BONE_ACTIVE);
+ select_actionchannel_by_name(ob->action, nearBone->name, 0);
+ }
+ }
+ else{
+ bArmature *arm= ob->data;
+ bone_looper(ob, arm->bonebase.first, NULL, clear_active_flag);
+
+ nearBone->flag |= (BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL|BONE_ACTIVE);
+ select_actionchannel_by_name(ob->action, nearBone->name, 1);
+ }
+ }
+
+ /* in weightpaint we select the associated vertex group too */
+ if(G.f & G_WEIGHTPAINT) {
+ if(nearBone->flag & BONE_ACTIVE) {
+ vertexgroup_select_by_name(OBACT, nearBone->name);
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ }
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWIPO, 0); /* To force action/constraint ipo update */
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWBUTSOBJECT, 0);
+ allqueue(REDRAWOOPS, 0);
+ }
+
+ return nearBone!=NULL;
+
+}
+
+/* test==0: deselect all
+ test==1: swap select
+ test==2: only clear active tag
+*/
+void deselectall_posearmature (Object *ob, int test, int doundo)
+{
+ bArmature *arm;
+ bPoseChannel *pchan;
+ int selectmode= 0;
+
+ /* we call this from outliner too, but with OBACT set OK */
+ if(!ob || !ob->pose) return;
+ arm= get_armature(ob);
+
+ /* Determine if we're selecting or deselecting */
+ if (test==1) {
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next)
+ if(pchan->bone->layer & arm->layer && !(pchan->bone->flag & BONE_HIDDEN_P))
+ if(pchan->bone->flag & BONE_SELECTED)
+ break;
+
+ if (pchan==NULL)
+ selectmode= 1;
+ }
+ else if(test==2)
+ selectmode= 2;
+
+ /* Set the flags accordingly */
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ if(pchan->bone->layer & arm->layer && !(pchan->bone->flag & BONE_HIDDEN_P)) {
+ if(selectmode==0) pchan->bone->flag &= ~(BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL|BONE_ACTIVE);
+ else if(selectmode==1) pchan->bone->flag |= BONE_SELECTED;
+ else pchan->bone->flag &= ~BONE_ACTIVE;
+ }
+ }
+
+ /* action editor */
+ deselect_actionchannels(ob->action, 0); /* deselects for sure */
+ if(selectmode==1)
+ deselect_actionchannels(ob->action, 1); /* swaps */
+
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWBUTSOBJECT, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWOOPS, 0);
+ allqueue(REDRAWACTION, 0);
+
+ countall();
+
+ if (doundo) {
+ if (selectmode==1) BIF_undo_push("Select All");
+ else BIF_undo_push("Deselect All");
+ }
+}
+
+
+int bone_looper(Object *ob, Bone *bone, void *data,
+ int (*bone_func)(Object *, Bone *, void *))
+{
+
+ /* We want to apply the function bone_func to every bone
+ * in an armature -- feed bone_looper the first bone and
+ * a pointer to the bone_func and watch it go!. The int count
+ * can be useful for counting bones with a certain property
+ * (e.g. skinnable)
+ */
+ int count = 0;
+
+ if (bone) {
+
+ /* only do bone_func if the bone is non null
+ */
+ count += bone_func(ob, bone, data);
+
+ /* try to execute bone_func for the first child
+ */
+ count += bone_looper(ob, bone->childbase.first, data,
+ bone_func);
+
+ /* try to execute bone_func for the next bone at this
+ * depth of the recursion.
+ */
+ count += bone_looper(ob, bone->next, data, bone_func);
+ }
+
+ return count;
+}
+
+
+static int bone_skinnable(Object *ob, Bone *bone, void *data)
+{
+ /* Bones that are deforming
+ * are regarded to be "skinnable" and are eligible for
+ * auto-skinning.
+ *
+ * This function performs 2 functions:
+ *
+ * a) It returns 1 if the bone is skinnable.
+ * If we loop over all bones with this
+ * function, we can count the number of
+ * skinnable bones.
+ * b) If the pointer data is non null,
+ * it is treated like a handle to a
+ * bone pointer -- the bone pointer
+ * is set to point at this bone, and
+ * the pointer the handle points to
+ * is incremented to point to the
+ * next member of an array of pointers
+ * to bones. This way we can loop using
+ * this function to construct an array of
+ * pointers to bones that point to all
+ * skinnable bones.
+ */
+ Bone ***hbone;
+
+ if(!(G.f & G_WEIGHTPAINT) || !(bone->flag & BONE_HIDDEN_P)) {
+ if (!(bone->flag & BONE_NO_DEFORM)) {
+ if (data != NULL) {
+ hbone = (Bone ***) data;
+ **hbone = bone;
+ ++*hbone;
+ }
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int add_defgroup_unique_bone(Object *ob, Bone *bone, void *data)
+{
+ /* This group creates a vertex group to ob that has the
+ * same name as bone (provided the bone is skinnable).
+ * If such a vertex group aleady exist the routine exits.
+ */
+ if (!(bone->flag & BONE_NO_DEFORM)) {
+ if (!get_named_vertexgroup(ob,bone->name)) {
+ add_defgroup_name(ob, bone->name);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int dgroup_skinnable(Object *ob, Bone *bone, void *data)
+{
+ /* Bones that are deforming
+ * are regarded to be "skinnable" and are eligible for
+ * auto-skinning.
+ *
+ * This function performs 2 functions:
+ *
+ * a) If the bone is skinnable, it creates
+ * a vertex group for ob that has
+ * the name of the skinnable bone
+ * (if one doesn't exist already).
+ * b) If the pointer data is non null,
+ * it is treated like a handle to a
+ * bDeformGroup pointer -- the
+ * bDeformGroup pointer is set to point
+ * to the deform group with the bone's
+ * name, and the pointer the handle
+ * points to is incremented to point to the
+ * next member of an array of pointers
+ * to bDeformGroups. This way we can loop using
+ * this function to construct an array of
+ * pointers to bDeformGroups, all with names
+ * of skinnable bones.
+ */
+ bDeformGroup ***hgroup, *defgroup;
+
+ if(!(G.f & G_WEIGHTPAINT) || !(bone->flag & BONE_HIDDEN_P)) {
+ if (!(bone->flag & BONE_NO_DEFORM)) {
+ if ( !(defgroup = get_named_vertexgroup(ob, bone->name)) ) {
+ defgroup = add_defgroup_name(ob, bone->name);
+ }
+
+ if (data != NULL) {
+ hgroup = (bDeformGroup ***) data;
+ **hgroup = defgroup;
+ ++*hgroup;
+ }
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static void add_vgroups__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s)
+{
+ /* DerivedMesh mapFunc for getting final coords in weight paint mode */
+
+ float (*verts)[3] = userData;
+ VECCOPY(verts[index], co);
+}
+
+static void envelope_bone_weighting(Object *ob, Mesh *mesh, float (*verts)[3], int numbones, Bone **bonelist, bDeformGroup **dgrouplist, bDeformGroup **dgroupflip, float (*root)[3], float (*tip)[3], int *selected, float scale)
+{
+ /* Create vertex group weights from envelopes */
+
+ Bone *bone;
+ bDeformGroup *dgroup;
+ float distance;
+ int i, iflip, j;
+
+ /* for each vertex in the mesh */
+ for (i=0; i < mesh->totvert; i++) {
+ iflip = (dgroupflip)? mesh_get_x_mirror_vert(ob, i): 0;
+
+ /* for each skinnable bone */
+ for (j=0; j < numbones; ++j) {
+ if(!selected[j])
+ continue;
+
+ bone = bonelist[j];
+ dgroup = dgrouplist[j];
+
+ /* store the distance-factor from the vertex to the bone */
+ distance = distfactor_to_bone (verts[i], root[j], tip[j],
+ bone->rad_head * scale, bone->rad_tail * scale, bone->dist * scale);
+
+ /* add the vert to the deform group if weight!=0.0 */
+ if (distance!=0.0)
+ add_vert_to_defgroup (ob, dgroup, i, distance, WEIGHT_REPLACE);
+ else
+ remove_vert_defgroup (ob, dgroup, i);
+
+ /* do same for mirror */
+ if (dgroupflip && dgroupflip[j] && iflip >= 0) {
+ if (distance!=0.0)
+ add_vert_to_defgroup (ob, dgroupflip[j], iflip, distance,
+ WEIGHT_REPLACE);
+ else
+ remove_vert_defgroup (ob, dgroupflip[j], iflip);
+ }
+ }
+ }
+}
+
+void add_verts_to_dgroups(Object *ob, Object *par, int heat, int mirror)
+{
+ /* This functions implements the automatic computation of vertex group
+ * weights, either through envelopes or using a heat equilibrium.
+ *
+ * This function can be called both when parenting a mesh to an armature,
+ * or in weightpaint + posemode. In the latter case selection is taken
+ * into account and vertex weights can be mirrored.
+ *
+ * The mesh vertex positions used are either the final deformed coords
+ * from the derivedmesh in weightpaint mode, the final subsurf coords
+ * when parenting, or simply the original mesh coords.
+ */
+
+ bArmature *arm;
+ Bone **bonelist, **bonehandle, *bone;
+ bDeformGroup **dgrouplist, **dgroupflip, **dgrouphandle;
+ bDeformGroup *dgroup, *curdg;
+ Mesh *mesh;
+ float (*root)[3], (*tip)[3], (*verts)[3];
+ int *selected;
+ int numbones, vertsfilled = 0, i, j;
+ int wpmode = (G.f & G_WEIGHTPAINT);
+
+ /* If the parent object is not an armature exit */
+ arm = get_armature(par);
+ if (!arm)
+ return;
+
+ /* count the number of skinnable bones */
+ numbones = bone_looper(ob, arm->bonebase.first, NULL, bone_skinnable);
+
+ if (numbones == 0)
+ return;
+
+ /* create an array of pointer to bones that are skinnable
+ * and fill it with all of the skinnable bones */
+ bonelist = MEM_callocN(numbones*sizeof(Bone *), "bonelist");
+ bonehandle = bonelist;
+ bone_looper(ob, arm->bonebase.first, &bonehandle, bone_skinnable);
+
+ /* create an array of pointers to the deform groups that
+ * coorespond to the skinnable bones (creating them
+ * as necessary. */
+ dgrouplist = MEM_callocN(numbones*sizeof(bDeformGroup *), "dgrouplist");
+ dgroupflip = MEM_callocN(numbones*sizeof(bDeformGroup *), "dgroupflip");
+
+ dgrouphandle = dgrouplist;
+ bone_looper(ob, arm->bonebase.first, &dgrouphandle, dgroup_skinnable);
+
+ /* create an array of root and tip positions transformed into
+ * global coords */
+ root = MEM_callocN(numbones*sizeof(float)*3, "root");
+ tip = MEM_callocN(numbones*sizeof(float)*3, "tip");
+ selected = MEM_callocN(numbones*sizeof(int), "selected");
+
+ for (j=0; j < numbones; ++j) {
+ bone = bonelist[j];
+ dgroup = dgrouplist[j];
+
+ /* compute root and tip */
+ VECCOPY(root[j], bone->arm_head);
+ Mat4MulVecfl(par->obmat, root[j]);
+
+ VECCOPY(tip[j], bone->arm_tail);
+ Mat4MulVecfl(par->obmat, tip[j]);
+
+ /* set selected */
+ if(wpmode) {
+ if ((arm->layer & bone->layer) && (bone->flag & BONE_SELECTED))
+ selected[j] = 1;
+ }
+ else
+ selected[j] = 1;
+
+ /* find flipped group */
+ if(mirror) {
+ char name[32];
+
+ BLI_strncpy(name, dgroup->name, 32);
+ // 0 = don't strip off number extensions
+ bone_flip_name(name, 0);
+
+ for (curdg = ob->defbase.first; curdg; curdg=curdg->next)
+ if (!strcmp(curdg->name, name))
+ break;
+
+ dgroupflip[j] = curdg;
+ }
+ }
+
+ /* create verts */
+ mesh = (Mesh*)ob->data;
+ verts = MEM_callocN(mesh->totvert*sizeof(*verts), "closestboneverts");
+
+ if (wpmode) {
+ /* if in weight paint mode, use final verts from derivedmesh */
+ DerivedMesh *dm = mesh_get_derived_final(ob, CD_MASK_BAREMESH);
+
+ if(dm->foreachMappedVert) {
+ dm->foreachMappedVert(dm, add_vgroups__mapFunc, (void*)verts);
+ vertsfilled = 1;
+ }
+
+ dm->release(dm);
+ }
+ else if (modifiers_findByType(ob, eModifierType_Subsurf)) {
+ /* is subsurf on? Lets use the verts on the limit surface then.
+ * = same amount of vertices as mesh, but vertices moved to the
+ * subsurfed position, like for 'optimal'. */
+ subsurf_calculate_limit_positions(mesh, verts);
+ vertsfilled = 1;
+ }
+
+ /* transform verts to global space */
+ for (i=0; i < mesh->totvert; i++) {
+ if (!vertsfilled)
+ VECCOPY(verts[i], mesh->mvert[i].co)
+ Mat4MulVecfl(ob->obmat, verts[i]);
+ }
+
+ /* compute the weights based on gathered vertices and bones */
+ if (heat)
+ heat_bone_weighting(ob, mesh, verts, numbones, dgrouplist, dgroupflip,
+ root, tip, selected);
+ else
+ envelope_bone_weighting(ob, mesh, verts, numbones, bonelist, dgrouplist,
+ dgroupflip, root, tip, selected, Mat4ToScalef(par->obmat));
+
+ /* free the memory allocated */
+ MEM_freeN(bonelist);
+ MEM_freeN(dgrouplist);
+ MEM_freeN(dgroupflip);
+ MEM_freeN(root);
+ MEM_freeN(tip);
+ MEM_freeN(selected);
+ MEM_freeN(verts);
+}
+
+void create_vgroups_from_armature(Object *ob, Object *par)
+{
+ /* Lets try to create some vertex groups
+ * based on the bones of the parent armature.
+ */
+
+ bArmature *arm;
+ short mode;
+
+ /* If the parent object is not an armature exit */
+ arm = get_armature(par);
+ if (!arm)
+ return;
+
+ /* Prompt the user on whether/how they want the vertex groups
+ * added to the child mesh */
+ mode= pupmenu("Create Vertex Groups? %t|"
+ "Don't Create Groups %x1|"
+ "Name Groups %x2|"
+ "Create From Envelopes %x3|"
+ "Create From Bone Heat %x4|");
+ switch (mode){
+ case 2:
+ /* Traverse the bone list, trying to create empty vertex
+ * groups cooresponding to the bone.
+ */
+ bone_looper(ob, arm->bonebase.first, NULL,
+ add_defgroup_unique_bone);
+ if (ob->type == OB_MESH)
+ create_dverts(ob->data);
+
+ break;
+
+ case 3:
+ case 4:
+ /* Traverse the bone list, trying to create vertex groups
+ * that are populated with the vertices for which the
+ * bone is closest.
+ */
+ add_verts_to_dgroups(ob, par, (mode == 4), 0);
+ break;
+
+ }
+}
+
+static int hide_selected_pose_bone(Object *ob, Bone *bone, void *ptr)
+{
+ bArmature *arm= ob->data;
+
+ if(arm->layer & bone->layer) {
+ if (bone->flag & BONE_SELECTED) {
+ bone->flag |= BONE_HIDDEN_P;
+ bone->flag &= ~BONE_SELECTED;
+ }
+ }
+ return 0;
+}
+
+/* active object is armature */
+void hide_selected_pose_bones(void)
+{
+ bArmature *arm= OBACT->data;
+
+ if (!arm)
+ return;
+
+ bone_looper(OBACT, arm->bonebase.first, NULL,
+ hide_selected_pose_bone);
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWACTION, 0);
+ BIF_undo_push("Hide Bones");
+}
+
+static int hide_unselected_pose_bone(Object *ob, Bone *bone, void *ptr)
+{
+ bArmature *arm= ob->data;
+
+ if(arm->layer & bone->layer) {
+ if (~bone->flag & BONE_SELECTED) {
+ bone->flag |= BONE_HIDDEN_P;
+ }
+ }
+ return 0;
+}
+
+/* active object is armature */
+void hide_unselected_pose_bones(void)
+{
+ bArmature *arm;
+
+ arm=get_armature (OBACT);
+
+ if (!arm)
+ return;
+
+ bone_looper(OBACT, arm->bonebase.first, NULL,
+ hide_unselected_pose_bone);
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ BIF_undo_push("Hide Unselected Bone");
+}
+
+static int show_pose_bone(Object *ob, Bone *bone, void *ptr)
+{
+ bArmature *arm= ob->data;
+
+ if(arm->layer & bone->layer) {
+ if (bone->flag & BONE_HIDDEN_P) {
+ bone->flag &= ~BONE_HIDDEN_P;
+ bone->flag |= BONE_SELECTED;
+ }
+ }
+
+ return 0;
+}
+
+/* active object is armature in posemode */
+void show_all_pose_bones(void)
+{
+ bArmature *arm;
+
+ arm=get_armature (OBACT);
+
+ if (!arm)
+ return;
+
+ bone_looper(OBACT, arm->bonebase.first, NULL,
+ show_pose_bone);
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ BIF_undo_push("Reveal Bones");
+}
+
+
+/* ************* RENAMING DISASTERS ************ */
+
+/* note: there's a unique_editbone_name() too! */
+void unique_bone_name (bArmature *arm, char *name)
+{
+ char tempname[64];
+ int number;
+ char *dot;
+
+ if (get_named_bone(arm, name)) {
+
+ /* Strip off the suffix, if it's a number */
+ number= strlen(name);
+ if(number && isdigit(name[number-1])) {
+ dot= strrchr(name, '.'); // last occurrance
+ if (dot)
+ *dot=0;
+ }
+
+ for (number = 1; number <=999; number++){
+ sprintf (tempname, "%s.%03d", name, number);
+ if (!get_named_bone(arm, tempname)){
+ BLI_strncpy (name, tempname, 32);
+ return;
+ }
+ }
+ }
+}
+
+#define MAXBONENAME 32
+/* helper call for below */
+static void constraint_bone_name_fix(Object *ob, ListBase *conlist, char *oldname, char *newname)
+{
+ bConstraint *curcon;
+ bConstraintTarget *ct;
+
+ for (curcon = conlist->first; curcon; curcon=curcon->next) {
+ bConstraintTypeInfo *cti= constraint_get_typeinfo(curcon);
+ ListBase targets = {NULL, NULL};
+
+ if (cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(curcon, &targets);
+
+ for (ct= targets.first; ct; ct= ct->next) {
+ if (ct->tar == ob) {
+ if (!strcmp(ct->subtarget, oldname) )
+ BLI_strncpy(ct->subtarget, newname, MAXBONENAME);
+ }
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(curcon, &targets, 0);
+ }
+ }
+}
+
+/* called by UI for renaming a bone */
+/* warning: make sure the original bone was not renamed yet! */
+/* seems messy, but thats what you get with not using pointers but channel names :) */
+void armature_bone_rename(bArmature *arm, char *oldnamep, char *newnamep)
+{
+ Object *ob;
+ char newname[MAXBONENAME];
+ char oldname[MAXBONENAME];
+
+ /* names better differ! */
+ if(strncmp(oldnamep, newnamep, MAXBONENAME)) {
+
+ /* we alter newname string... so make copy */
+ BLI_strncpy(newname, newnamep, MAXBONENAME);
+ /* we use oldname for search... so make copy */
+ BLI_strncpy(oldname, oldnamep, MAXBONENAME);
+
+ /* now check if we're in editmode, we need to find the unique name */
+ if(G.obedit && G.obedit->data==arm) {
+ EditBone *eBone;
+
+ eBone= editbone_name_exists(&G.edbo, oldname);
+ if(eBone) {
+ unique_editbone_name (&G.edbo, newname);
+ BLI_strncpy(eBone->name, newname, MAXBONENAME);
+ }
+ else return;
+ }
+ else {
+ Bone *bone= get_named_bone (arm, oldname);
+
+ if(bone) {
+ unique_bone_name (arm, newname);
+ BLI_strncpy(bone->name, newname, MAXBONENAME);
+ }
+ else return;
+ }
+
+ /* do entire dbase */
+ for(ob= G.main->object.first; ob; ob= ob->id.next) {
+ /* we have the object using the armature */
+ if(arm==ob->data) {
+ Object *cob;
+ bAction *act;
+ bActionChannel *achan;
+ bActionStrip *strip;
+
+ /* Rename action channel if necessary */
+ act = ob->action;
+ if (act && !act->id.lib) {
+ /* Find the appropriate channel */
+ achan= get_action_channel(act, oldname);
+ if(achan) BLI_strncpy(achan->name, newname, MAXBONENAME);
+ }
+
+ /* Rename the pose channel, if it exists */
+ if (ob->pose) {
+ bPoseChannel *pchan = get_pose_channel(ob->pose, oldname);
+ if (pchan) {
+ BLI_strncpy (pchan->name, newname, MAXBONENAME);
+ }
+ }
+
+ /* check all nla-strips too */
+ for (strip= ob->nlastrips.first; strip; strip= strip->next) {
+ /* Rename action channel if necessary */
+ act = strip->act;
+ if (act && !act->id.lib) {
+ /* Find the appropriate channel */
+ achan= get_action_channel(act, oldname);
+ if(achan) BLI_strncpy(achan->name, newname, MAXBONENAME);
+ }
+ }
+
+ /* Update any object constraints to use the new bone name */
+ for(cob= G.main->object.first; cob; cob= cob->id.next) {
+ if(cob->constraints.first)
+ constraint_bone_name_fix(ob, &cob->constraints, oldname, newname);
+ if (cob->pose) {
+ bPoseChannel *pchan;
+ for (pchan = cob->pose->chanbase.first; pchan; pchan=pchan->next) {
+ constraint_bone_name_fix(ob, &pchan->constraints, oldname, newname);
+ }
+ }
+ }
+ }
+
+ /* See if an object is parented to this armature */
+ if (ob->parent && (ob->parent->data == arm)) {
+ if(ob->partype==PARBONE) {
+ /* bone name in object */
+ if (!strcmp(ob->parsubstr, oldname))
+ BLI_strncpy(ob->parsubstr, newname, MAXBONENAME);
+ }
+ }
+
+ if(modifiers_usesArmature(ob, arm)) {
+ bDeformGroup *dg;
+ /* bone name in defgroup */
+ for (dg=ob->defbase.first; dg; dg=dg->next) {
+ if(!strcmp(dg->name, oldname))
+ BLI_strncpy(dg->name, newname, MAXBONENAME);
+ }
+ }
+ }
+ }
+}
+
+/* context editmode object */
+void armature_flip_names(void)
+{
+ bArmature *arm= G.obedit->data;
+ EditBone *ebone;
+ char newname[32];
+
+ for (ebone = G.edbo.first; ebone; ebone=ebone->next) {
+ if(arm->layer & ebone->layer) {
+ if(ebone->flag & BONE_SELECTED) {
+ BLI_strncpy(newname, ebone->name, sizeof(newname));
+ bone_flip_name(newname, 1); // 1 = do strip off number extensions
+ armature_bone_rename(G.obedit->data, ebone->name, newname);
+ }
+ }
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWBUTSOBJECT, 0);
+ allqueue (REDRAWACTION, 0);
+ allqueue(REDRAWOOPS, 0);
+ BIF_undo_push("Flip names");
+
+}
+
+/* context; editmode armature */
+EditBone *armature_bone_get_mirrored(EditBone *ebo)
+{
+ EditBone *eboflip= NULL;
+ char name[32];
+
+ BLI_strncpy(name, ebo->name, sizeof(name));
+ bone_flip_name(name, 0); // 0 = don't strip off number extensions
+
+ for (eboflip=G.edbo.first; eboflip; eboflip=eboflip->next)
+ if(ebo!=eboflip)
+ if (!strcmp (name, eboflip->name)) break;
+
+ return eboflip;
+}
+
+/* if editbone (partial) selected, copy data */
+/* context; editmode armature, with mirror editing enabled */
+void transform_armature_mirror_update(void)
+{
+ EditBone *ebo, *eboflip;
+
+ for (ebo=G.edbo.first; ebo; ebo=ebo->next) {
+ /* no layer check, correct mirror is more important */
+ if(ebo->flag & (BONE_TIPSEL|BONE_ROOTSEL)) {
+
+ eboflip= armature_bone_get_mirrored(ebo);
+
+ if(eboflip) {
+ /* we assume X-axis flipping for now */
+ if(ebo->flag & BONE_TIPSEL) {
+ eboflip->tail[0]= -ebo->tail[0];
+ eboflip->tail[1]= ebo->tail[1];
+ eboflip->tail[2]= ebo->tail[2];
+ eboflip->rad_tail= ebo->rad_tail;
+ }
+ if(ebo->flag & BONE_ROOTSEL) {
+ eboflip->head[0]= -ebo->head[0];
+ eboflip->head[1]= ebo->head[1];
+ eboflip->head[2]= ebo->head[2];
+ eboflip->rad_head= ebo->rad_head;
+ }
+ if(ebo->flag & BONE_SELECTED) {
+ eboflip->dist= ebo->dist;
+ eboflip->roll= -ebo->roll;
+ eboflip->xwidth= ebo->xwidth;
+ eboflip->zwidth= ebo->zwidth;
+ }
+ }
+ }
+ }
+}
+
+
diff --git a/source/blender/src/editconstraint.c b/source/blender/src/editconstraint.c
new file mode 100644
index 00000000000..e0588b4c2a0
--- /dev/null
+++ b/source/blender/src/editconstraint.c
@@ -0,0 +1,1103 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "DNA_action_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_text_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_constraint.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_ipo.h"
+#include "BKE_object.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_editaction.h"
+#include "BIF_editarmature.h"
+#include "BIF_editconstraint.h"
+#include "BIF_poseobject.h"
+#include "BIF_interface.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_toolbox.h"
+
+#include "BPY_extern.h"
+
+#include "blendef.h"
+#include "nla.h"
+#include "mydevice.h"
+
+
+ListBase *get_active_constraint_channels (Object *ob, int forcevalid)
+{
+ char ipstr[64];
+
+ if (!ob)
+ return NULL;
+
+ /* See if we are a bone constraint */
+ if (ob->flag & OB_POSEMODE) {
+ bActionChannel *achan;
+ bPoseChannel *pchan;
+
+ pchan = get_active_posechannel(ob);
+ if (pchan) {
+
+ /* Make sure we have an action */
+ if (!ob->action){
+ if (!forcevalid)
+ return NULL;
+
+ ob->action=add_empty_action("Action");
+ }
+
+ /* Make sure we have an actionchannel */
+ achan = get_action_channel(ob->action, pchan->name);
+ if (!achan){
+ if (!forcevalid)
+ return NULL;
+
+ achan = MEM_callocN (sizeof(bActionChannel), "actionChannel");
+
+ strcpy (achan->name, pchan->name);
+ sprintf (ipstr, "%s.%s", ob->action->id.name+2, achan->name);
+ ipstr[23]=0;
+ achan->ipo= add_ipo(ipstr, ID_AC);
+
+ BLI_addtail (&ob->action->chanbase, achan);
+ }
+
+ return &achan->constraintChannels;
+ }
+ else return NULL;
+ }
+ /* else we return object constraints */
+ else {
+ if(ob->ipoflag & OB_ACTION_OB) {
+ bActionChannel *achan = get_action_channel(ob->action, "Object");
+ if(achan)
+ return &achan->constraintChannels;
+ else
+ return NULL;
+ }
+
+ return &ob->constraintChannels;
+ }
+}
+
+
+/* if object in posemode, active bone constraints, else object constraints */
+ListBase *get_active_constraints(Object *ob)
+{
+ if (!ob)
+ return NULL;
+
+ if (ob->flag & OB_POSEMODE) {
+ bPoseChannel *pchan;
+
+ pchan = get_active_posechannel(ob);
+ if (pchan)
+ return &pchan->constraints;
+ }
+ else
+ return &ob->constraints;
+
+ return NULL;
+}
+
+/* single constraint */
+bConstraint *get_active_constraint(Object *ob)
+{
+ ListBase *lb= get_active_constraints(ob);
+
+ if (lb) {
+ bConstraint *con;
+ for (con= lb->first; con; con=con->next)
+ if (con->flag & CONSTRAINT_ACTIVE)
+ return con;
+ }
+ return NULL;
+}
+
+/* single channel, for ipo */
+bConstraintChannel *get_active_constraint_channel(Object *ob)
+{
+ bConstraint *con;
+ bConstraintChannel *chan;
+
+ if (ob->flag & OB_POSEMODE) {
+ if(ob->action) {
+ bPoseChannel *pchan;
+
+ pchan = get_active_posechannel(ob);
+ if (pchan) {
+ for (con= pchan->constraints.first; con; con= con->next)
+ if (con->flag & CONSTRAINT_ACTIVE)
+ break;
+ if (con) {
+ bActionChannel *achan = get_action_channel(ob->action, pchan->name);
+ if (achan) {
+ for (chan= achan->constraintChannels.first; chan; chan= chan->next)
+ if (!strcmp(chan->name, con->name))
+ break;
+ return chan;
+ }
+ }
+ }
+ }
+ }
+ else {
+ for(con= ob->constraints.first; con; con= con->next)
+ if(con->flag & CONSTRAINT_ACTIVE)
+ break;
+ if(con) {
+ ListBase *lb= get_active_constraint_channels(ob, 0);
+
+ if(lb) {
+ for(chan= lb->first; chan; chan= chan->next)
+ if(!strcmp(chan->name, con->name))
+ break;
+ return chan;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+
+bConstraint *add_new_constraint(short type)
+{
+ bConstraint *con;
+ bConstraintTypeInfo *cti;
+
+ con = MEM_callocN(sizeof(bConstraint), "constraint");
+
+ /* Set up a generic constraint datablock */
+ con->type = type;
+ con->flag |= CONSTRAINT_EXPAND;
+ con->enforce = 1.0F;
+ strcpy(con->name, "Const");
+
+ /* Load the data for it */
+ cti = constraint_get_typeinfo(con);
+ if (cti) {
+ con->data = MEM_callocN(cti->size, cti->structName);
+
+ /* only constraints that change any settings need this */
+ if (cti->new_data)
+ cti->new_data(con->data);
+ }
+
+ return con;
+}
+
+void add_constraint_to_object(bConstraint *con, Object *ob)
+{
+ ListBase *list;
+ list = &ob->constraints;
+
+ if (list) {
+ unique_constraint_name(con, list);
+ BLI_addtail(list, con);
+
+ con->flag |= CONSTRAINT_ACTIVE;
+ for (con= con->prev; con; con= con->prev)
+ con->flag &= ~CONSTRAINT_ACTIVE;
+ }
+}
+
+/* checks validity of object pointers, and NULLs,
+ * if Bone doesnt exist it sets the CONSTRAINT_DISABLE flag
+ */
+static void test_constraints (Object *owner, const char substring[])
+{
+
+ bConstraint *curcon;
+ ListBase *conlist= NULL;
+ int type;
+
+ if (owner==NULL) return;
+
+ /* Check parents */
+ /* Get the constraint list for this object */
+
+ if (strlen (substring)) {
+ switch (owner->type) {
+ case OB_ARMATURE:
+ type = CONSTRAINT_OBTYPE_BONE;
+ break;
+ default:
+ type = CONSTRAINT_OBTYPE_OBJECT;
+ break;
+ }
+ }
+ else
+ type = CONSTRAINT_OBTYPE_OBJECT;
+
+
+ switch (type) {
+ case CONSTRAINT_OBTYPE_OBJECT:
+ conlist = &owner->constraints;
+ break;
+ case CONSTRAINT_OBTYPE_BONE:
+ {
+ Bone *bone;
+ bPoseChannel *chan;
+
+ bone = get_named_bone( ((bArmature *)owner->data ), substring );
+ chan = get_pose_channel(owner->pose, substring);
+ if (bone && chan) {
+ conlist = &chan->constraints;
+ }
+ }
+ break;
+ }
+
+ /* Check all constraints - is constraint valid? */
+ if (conlist) {
+ for (curcon = conlist->first; curcon; curcon=curcon->next) {
+ curcon->flag &= ~CONSTRAINT_DISABLE;
+
+ switch (curcon->type) {
+ case CONSTRAINT_TYPE_PYTHON:
+ {
+ bPythonConstraint *data = curcon->data;
+
+ /* is there are valid script? */
+ if (!data->text) {
+ curcon->flag |= CONSTRAINT_DISABLE;
+ break;
+ }
+ else if (!BPY_is_pyconstraint(data->text)) {
+ curcon->flag |= CONSTRAINT_DISABLE;
+ break;
+ }
+
+ /* does the constraint require target input... also validates targets */
+ BPY_pyconstraint_update(owner, curcon);
+ }
+ break;
+ case CONSTRAINT_TYPE_ACTION:
+ {
+ bActionConstraint *data = curcon->data;
+
+ if (!exist_object(data->tar)) {
+ data->tar = NULL;
+ curcon->flag |= CONSTRAINT_DISABLE;
+ break;
+ }
+
+ if ( (data->tar == owner) &&
+ (!get_named_bone(get_armature(owner),
+ data->subtarget))) {
+ curcon->flag |= CONSTRAINT_DISABLE;
+ break;
+ }
+ }
+ break;
+ case CONSTRAINT_TYPE_LOCLIKE:
+ {
+ bLocateLikeConstraint *data = curcon->data;
+
+ if (!exist_object(data->tar)) {
+ data->tar = NULL;
+ curcon->flag |= CONSTRAINT_DISABLE;
+ break;
+ }
+
+ if ( (data->tar == owner) &&
+ (!get_named_bone(get_armature(owner),
+ data->subtarget))) {
+ curcon->flag |= CONSTRAINT_DISABLE;
+ break;
+ }
+ }
+ break;
+ case CONSTRAINT_TYPE_MINMAX:
+ {
+ bMinMaxConstraint *data = curcon->data;
+
+ if (!exist_object(data->tar)) {
+ data->tar = NULL;
+ curcon->flag |= CONSTRAINT_DISABLE;
+ break;
+ }
+
+ if ( (data->tar == owner) &&
+ (!get_named_bone(get_armature(owner),
+ data->subtarget))) {
+ curcon->flag |= CONSTRAINT_DISABLE;
+ break;
+ }
+ }
+ break;
+ case CONSTRAINT_TYPE_ROTLIKE:
+ {
+ bRotateLikeConstraint *data = curcon->data;
+
+ if (!exist_object(data->tar)) {
+ data->tar = NULL;
+ curcon->flag |= CONSTRAINT_DISABLE;
+ break;
+ }
+
+ if ( (data->tar == owner) &&
+ (!get_named_bone(get_armature(owner),
+ data->subtarget))) {
+ curcon->flag |= CONSTRAINT_DISABLE;
+ break;
+ }
+ }
+ break;
+ case CONSTRAINT_TYPE_SIZELIKE:
+ {
+ bSizeLikeConstraint *data = curcon->data;
+
+ if (!exist_object(data->tar)) {
+ data->tar = NULL;
+ curcon->flag |= CONSTRAINT_DISABLE;
+ break;
+ }
+
+ if ( (data->tar == owner) &&
+ (!get_named_bone(get_armature(owner),
+ data->subtarget))) {
+ curcon->flag |= CONSTRAINT_DISABLE;
+ break;
+ }
+ }
+ break;
+ case CONSTRAINT_TYPE_KINEMATIC:
+ {
+ bKinematicConstraint *data = curcon->data;
+
+ if (!exist_object(data->tar)) {
+ data->tar = NULL;
+ curcon->flag |= CONSTRAINT_DISABLE;
+ }
+ else if ( (data->tar == owner) &&
+ (!get_named_bone(get_armature(owner),
+ data->subtarget))) {
+ curcon->flag |= CONSTRAINT_DISABLE;
+ }
+
+ if (data->poletar && !exist_object(data->poletar)) {
+ data->poletar = NULL;
+ }
+ else if ( (data->poletar == owner) &&
+ (!get_named_bone(get_armature(owner),
+ data->polesubtarget))) {
+ curcon->flag |= CONSTRAINT_DISABLE;
+ }
+
+ }
+ break;
+ case CONSTRAINT_TYPE_TRACKTO:
+ {
+ bTrackToConstraint *data = curcon->data;
+ if (!exist_object(data->tar)) {
+ data->tar = NULL;
+ curcon->flag |= CONSTRAINT_DISABLE;
+ break;
+ }
+
+ if ( (data->tar == owner) &&
+ (!get_named_bone(get_armature(owner),
+ data->subtarget))) {
+ curcon->flag |= CONSTRAINT_DISABLE;
+ break;
+ }
+ if (data->reserved2==data->reserved1) {
+ curcon->flag |= CONSTRAINT_DISABLE;
+ break;
+ }
+ if (data->reserved2+3==data->reserved1) {
+ curcon->flag |= CONSTRAINT_DISABLE;
+ break;
+ }
+ }
+ break;
+ case CONSTRAINT_TYPE_LOCKTRACK:
+ {
+ bLockTrackConstraint *data = curcon->data;
+
+ if (!exist_object(data->tar)) {
+ data->tar = NULL;
+ curcon->flag |= CONSTRAINT_DISABLE;
+ break;
+ }
+
+ if ( (data->tar == owner) &&
+ (!get_named_bone(get_armature(owner),
+ data->subtarget))) {
+ curcon->flag |= CONSTRAINT_DISABLE;
+ break;
+ }
+
+ if (data->lockflag==data->trackflag) {
+ curcon->flag |= CONSTRAINT_DISABLE;
+ break;
+ }
+ if (data->lockflag+3==data->trackflag) {
+ curcon->flag |= CONSTRAINT_DISABLE;
+ break;
+ }
+ }
+ break;
+ case CONSTRAINT_TYPE_STRETCHTO:
+ {
+ bStretchToConstraint *data = curcon->data;
+
+ if (!exist_object(data->tar)) {
+ data->tar = NULL;
+ curcon->flag |= CONSTRAINT_DISABLE;
+ break;
+ }
+
+ if ( (data->tar == owner) &&
+ (!get_named_bone(get_armature(owner),
+ data->subtarget))) {
+ curcon->flag |= CONSTRAINT_DISABLE;
+ break;
+ }
+ }
+ break;
+ case CONSTRAINT_TYPE_FOLLOWPATH:
+ {
+ bFollowPathConstraint *data = curcon->data;
+
+ if (!exist_object(data->tar)) {
+ data->tar = NULL;
+ curcon->flag |= CONSTRAINT_DISABLE;
+ break;
+ }
+ if (data->tar->type != OB_CURVE) {
+ data->tar = NULL;
+ curcon->flag |= CONSTRAINT_DISABLE;
+ break;
+ }
+ if (data->upflag==data->trackflag) {
+ curcon->flag |= CONSTRAINT_DISABLE;
+ break;
+ }
+ if (data->upflag+3==data->trackflag) {
+ curcon->flag |= CONSTRAINT_DISABLE;
+ break;
+ }
+ }
+ break;
+ case CONSTRAINT_TYPE_CLAMPTO:
+ {
+ bClampToConstraint *data = curcon->data;
+
+ if (!exist_object(data->tar)) {
+ data->tar = NULL;
+ curcon->flag |= CONSTRAINT_DISABLE;
+ break;
+ }
+
+ if (data->tar->type != OB_CURVE) {
+ data->tar = NULL;
+ curcon->flag |= CONSTRAINT_DISABLE;
+ break;
+ }
+ else {
+ Curve *cu= data->tar->data;
+
+ /* auto-set 'Path' setting on curve so this works */
+ cu->flag |= CU_PATH;
+ }
+ }
+ break;
+ case CONSTRAINT_TYPE_TRANSFORM:
+ {
+ bTransformConstraint *data = curcon->data;
+
+ if (!exist_object(data->tar)) {
+ data->tar = NULL;
+ curcon->flag |= CONSTRAINT_DISABLE;
+ break;
+ }
+
+ if ( (data->tar == owner) &&
+ (!get_named_bone(get_armature(owner),
+ data->subtarget))) {
+ curcon->flag |= CONSTRAINT_DISABLE;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+}
+
+static void test_bonelist_constraints (Object *owner, ListBase *list)
+{
+ Bone *bone;
+
+ for (bone = list->first; bone; bone=bone->next) {
+
+ test_constraints(owner, bone->name);
+ test_bonelist_constraints (owner, &bone->childbase);
+ }
+}
+
+void object_test_constraints (Object *owner)
+{
+ test_constraints(owner, "");
+
+ if(owner->type==OB_ARMATURE) {
+ bArmature *arm;
+ arm = get_armature(owner);
+ if (arm)
+ test_bonelist_constraints (owner, &arm->bonebase);
+ }
+
+}
+
+/* helper function for add_constriant - sets the last target for the active constraint */
+static void set_constraint_nth_target(bConstraint *con, Object *target, char subtarget[], int index)
+{
+ bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+ int num_targets, i;
+
+ if (cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(con, &targets);
+ num_targets= BLI_countlist(&targets);
+
+ if (index < 0) {
+ if (abs(index) < num_targets)
+ index= num_targets - abs(index);
+ else
+ index= num_targets - 1;
+ }
+ else if (index >= num_targets) {
+ index= num_targets - 1;
+ }
+
+ for (ct=targets.first, i=0; ct; ct= ct->next, i++) {
+ if (i == index) {
+ ct->tar= target;
+ strcpy(ct->subtarget, subtarget);
+ break;
+ }
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(con, &targets, 0);
+ }
+}
+
+/* context: active object in posemode, active channel, optional selected channel */
+void add_constraint(int only_IK)
+{
+ Object *ob= OBACT, *obsel=NULL;
+ bPoseChannel *pchanact=NULL, *pchansel=NULL;
+ bConstraint *con=NULL;
+ Base *base;
+ short nr;
+
+ /* paranoia checks */
+ if(ob==NULL || ob==G.obedit) return;
+
+ if(ob->pose && (ob->flag & OB_POSEMODE)) {
+ bArmature *arm= ob->data;
+
+ /* find active channel */
+ pchanact= get_active_posechannel(ob);
+ if(pchanact==NULL) return;
+
+ /* check protection */
+ if(ob->proxy && (pchanact->bone->layer & arm->layer_protected)) {
+ error("Bone is Proxy protected");
+ return;
+ }
+
+ /* find selected bone */
+ for(pchansel= ob->pose->chanbase.first; pchansel; pchansel= pchansel->next) {
+ if(pchansel!=pchanact)
+ if(pchansel->bone->flag & BONE_SELECTED)
+ if(pchansel->bone->layer & arm->layer)
+ break;
+ }
+ }
+
+ /* find selected object */
+ for(base= FIRSTBASE; base; base= base->next)
+ if( TESTBASE(base) && base->object!=ob )
+ obsel= base->object;
+
+ /* the only_IK caller has checked for posemode! */
+ if(only_IK) {
+ for(con= pchanact->constraints.first; con; con= con->next) {
+ if(con->type==CONSTRAINT_TYPE_KINEMATIC) break;
+ }
+ if(con) {
+ error("Pose Channel already has IK");
+ return;
+ }
+
+ if(pchansel)
+ nr= pupmenu("Add IK Constraint%t|To Active Bone%x10");
+ else if(obsel)
+ nr= pupmenu("Add IK Constraint%t|To Active Object%x10");
+ else
+ nr= pupmenu("Add IK Constraint%t|To New Empty Object%x10|Without Target%x11");
+ }
+ else {
+ if(pchanact) {
+ if(pchansel)
+ nr= pupmenu("Add Constraint to Active Bone%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|%l|Track To%x3|Floor%x4|Locked Track%x5|Stretch To%x7|%l|Action%x16|Script%x18");
+ else if(obsel && obsel->type==OB_CURVE)
+ nr= pupmenu("Add Constraint to Active Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|%l|Track To%x3|Floor%x4|Locked Track%x5|Follow Path%x6|Clamp To%x17|Stretch To%x7|%l|Action%x16|Script%x18");
+ else if(obsel)
+ nr= pupmenu("Add Constraint to Active Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|%l|Track To%x3|Floor%x4|Locked Track%x5|Stretch To%x7|%l|Action%x16|Script%x18");
+ else
+ nr= pupmenu("Add Constraint to New Empty Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|%l|Track To%x3|Floor%x4|Locked Track%x5|Stretch To%x7|%l|Action%x16|Script%x18");
+ }
+ else {
+ if(obsel && obsel->type==OB_CURVE)
+ nr= pupmenu("Add Constraint to Active Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|%l|Track To%x3|Floor%x4|Locked Track%x5|Follow Path%x6|Clamp To%x17|%l|Action%x16|Script%x18");
+ else if(obsel)
+ nr= pupmenu("Add Constraint to Active Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|%l|Track To%x3|Floor%x4|Locked Track%x5|%l|Action%x16|Script%x18");
+ else
+ nr= pupmenu("Add Constraint to New Empty Object%t|Child Of%x19|Transformation%x20|%l|Copy Location%x1|Copy Rotation%x2|Copy Scale%x8|%l|Limit Location%x13|Limit Rotation%x14|Limit Scale%x15|%l|Track To%x3|Floor%x4|Locked Track%x5|%l|Action%x16|Script%x18");
+ }
+ }
+
+ if(nr<1) return;
+
+ /* handle IK separate */
+ if(nr==10 || nr==11) {
+
+ /* prevent weird chains... */
+ if(pchansel) {
+ bPoseChannel *pchan= pchanact;
+ while(pchan) {
+ if(pchan==pchansel) break;
+ pchan= pchan->parent;
+ }
+ if(pchan) {
+ error("IK root cannot be linked to IK tip");
+ return;
+ }
+ pchan= pchansel;
+ while(pchan) {
+ if(pchan==pchanact) break;
+ pchan= pchan->parent;
+ }
+ if(pchan) {
+ error("IK tip cannot be linked to IK root");
+ return;
+ }
+ }
+
+ con = add_new_constraint(CONSTRAINT_TYPE_KINEMATIC);
+ BLI_addtail(&pchanact->constraints, con);
+ unique_constraint_name(con, &pchanact->constraints);
+ pchanact->constflag |= PCHAN_HAS_IK; // for draw, but also for detecting while pose solving
+ if(nr==11) pchanact->constflag |= PCHAN_HAS_TARGET;
+ }
+ else {
+
+ if (nr==1) con = add_new_constraint(CONSTRAINT_TYPE_LOCLIKE);
+ else if (nr==2) con = add_new_constraint(CONSTRAINT_TYPE_ROTLIKE);
+ else if (nr==3) con = add_new_constraint(CONSTRAINT_TYPE_TRACKTO);
+ else if (nr==4) con = add_new_constraint(CONSTRAINT_TYPE_MINMAX);
+ else if (nr==5) con = add_new_constraint(CONSTRAINT_TYPE_LOCKTRACK);
+ else if (nr==6) {
+ Curve *cu= obsel->data;
+ cu->flag |= CU_PATH;
+ con = add_new_constraint(CONSTRAINT_TYPE_FOLLOWPATH);
+ }
+ else if (nr==7) con = add_new_constraint(CONSTRAINT_TYPE_STRETCHTO);
+ else if (nr==8) con = add_new_constraint(CONSTRAINT_TYPE_SIZELIKE);
+ else if (nr==13) con = add_new_constraint(CONSTRAINT_TYPE_LOCLIMIT);
+ else if (nr==14) con = add_new_constraint(CONSTRAINT_TYPE_ROTLIMIT);
+ else if (nr==15) con = add_new_constraint(CONSTRAINT_TYPE_SIZELIMIT);
+ else if (nr==16) {
+ /* TODO: add a popup-menu to display list of available actions to use (like for pyconstraints) */
+ con = add_new_constraint(CONSTRAINT_TYPE_ACTION);
+ }
+ else if (nr==17) {
+ Curve *cu= obsel->data;
+ cu->flag |= CU_PATH;
+ con = add_new_constraint(CONSTRAINT_TYPE_CLAMPTO);
+ }
+ else if (nr==18) {
+ char *menustr;
+ int scriptint= 0;
+
+ /* popup a list of usable scripts */
+ menustr = buildmenu_pyconstraints(NULL, &scriptint);
+ scriptint = pupmenu(menustr);
+ MEM_freeN(menustr);
+
+ /* only add constraint if a script was chosen */
+ if (scriptint) {
+ /* add constraint */
+ con = add_new_constraint(CONSTRAINT_TYPE_PYTHON);
+ validate_pyconstraint_cb(con->data, &scriptint);
+
+ /* make sure target allowance is set correctly */
+ BPY_pyconstraint_update(ob, con);
+ }
+ }
+ else if (nr==19) {
+ con = add_new_constraint(CONSTRAINT_TYPE_CHILDOF);
+
+ /* if this constraint is being added to a posechannel, make sure
+ * the constraint gets evaluated in pose-space
+ */
+ if (pchanact) {
+ con->ownspace = CONSTRAINT_SPACE_POSE;
+ con->flag |= CONSTRAINT_SPACEONCE;
+ }
+ }
+ else if (nr==20) con = add_new_constraint(CONSTRAINT_TYPE_TRANSFORM);
+
+ if (con==NULL) return; /* paranoia */
+
+ if (pchanact) {
+ BLI_addtail(&pchanact->constraints, con);
+ unique_constraint_name(con, &pchanact->constraints);
+ pchanact->constflag |= PCHAN_HAS_CONST; /* for draw */
+ }
+ else {
+ BLI_addtail(&ob->constraints, con);
+ unique_constraint_name(con, &ob->constraints);
+ }
+ }
+
+ /* set the target */
+ if (pchansel) {
+ set_constraint_nth_target(con, ob, pchansel->name, 0);
+ }
+ else if(obsel) {
+ set_constraint_nth_target(con, obsel, "", 0);
+ }
+ else if (ELEM4(nr, 11, 13, 14, 15)==0) { /* add new empty as target */
+ Base *base= BASACT, *newbase;
+ Object *obt;
+
+ obt= add_object(OB_EMPTY);
+ /* set layers OK */
+ newbase= BASACT;
+ newbase->lay= base->lay;
+ obt->lay= newbase->lay;
+
+ /* transform cent to global coords for loc */
+ if (pchanact) {
+ if(only_IK)
+ VecMat4MulVecfl(obt->loc, ob->obmat, pchanact->pose_tail);
+ else
+ VecMat4MulVecfl(obt->loc, ob->obmat, pchanact->pose_head);
+ }
+ else
+ VECCOPY(obt->loc, ob->obmat[3]);
+
+ set_constraint_nth_target(con, obt, "", 0);
+
+ /* restore, add_object sets active */
+ BASACT= base;
+ base->flag |= SELECT;
+ }
+
+ /* active flag */
+ con->flag |= CONSTRAINT_ACTIVE;
+ for(con= con->prev; con; con= con->prev)
+ con->flag &= ~CONSTRAINT_ACTIVE;
+
+ DAG_scene_sort(G.scene); // sort order of objects
+
+ if (pchanact) {
+ ob->pose->flag |= POSE_RECALC; // sort pose channels
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); // and all its relations
+ }
+ else
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_OB); // and all its relations
+
+ allqueue (REDRAWVIEW3D, 0);
+ allqueue (REDRAWBUTSOBJECT, 0);
+ allqueue (REDRAWOOPS, 0);
+
+ if (only_IK)
+ BIF_undo_push("Add IK Constraint");
+ else
+ BIF_undo_push("Add Constraint");
+
+}
+
+void ob_clear_constraints(void)
+{
+ Object *ob= OBACT;
+
+ /* paranoia checks */
+ if(!ob) return;
+ if(ob==G.obedit || (ob->flag & OB_POSEMODE)) return;
+
+ if(okee("Clear Constraints")==0) return;
+
+ free_constraints(&ob->constraints);
+
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_OB);
+
+ allqueue (REDRAWVIEW3D, 0);
+ allqueue (REDRAWBUTSOBJECT, 0);
+ allqueue (REDRAWOOPS, 0);
+
+ BIF_undo_push("Clear Constraint(s)");
+
+}
+
+/* con already has the new name */
+void rename_constraint(Object *ob, bConstraint *con, char *oldname)
+{
+ bConstraint *tcon;
+ bConstraintChannel *conchan;
+ ListBase *conlist= NULL;
+ int from_object= 0;
+ char *channame="";
+
+ /* get context by searching for con (primitive...) */
+ for(tcon= ob->constraints.first; tcon; tcon= tcon->next)
+ if(tcon==con)
+ break;
+
+ if(tcon) {
+ conlist= &ob->constraints;
+ channame= "Object";
+ from_object= 1;
+ }
+ else if(ob->pose) {
+ bPoseChannel *pchan;
+
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ for(tcon= pchan->constraints.first; tcon; tcon= tcon->next) {
+ if(tcon==con)
+ break;
+ }
+ if(tcon)
+ break;
+ }
+ if(tcon) {
+ conlist= &pchan->constraints;
+ channame= pchan->name;
+ }
+ }
+
+ if(conlist==NULL) {
+ printf("rename constraint failed\n"); /* should not happen in UI */
+ return;
+ }
+
+ /* first make sure it's a unique name within context */
+ unique_constraint_name (con, conlist);
+
+ /* own channels */
+ if(from_object) {
+ for(conchan= ob->constraintChannels.first; conchan; conchan= conchan->next) {
+ if( strcmp(oldname, conchan->name)==0 )
+ BLI_strncpy(conchan->name, con->name, sizeof(conchan->name));
+ }
+ }
+ /* own action */
+ if(ob->action) {
+ bActionChannel *achan= get_action_channel(ob->action, channame);
+ if(achan) {
+ conchan= get_constraint_channel(&achan->constraintChannels, oldname);
+ if(conchan)
+ BLI_strncpy(conchan->name, con->name, sizeof(conchan->name));
+ }
+ }
+
+}
+
+/* ********************** CONSTRAINT-SPECIFIC STUFF ********************* */
+/* ------------- PyConstraints ------------------ */
+
+/* this callback sets the text-file to be used for selected menu item */
+void validate_pyconstraint_cb(void *arg1, void *arg2)
+{
+ bPythonConstraint *data = arg1;
+ Text *text;
+ int index = *((int *)arg2);
+ int i;
+
+ /* innovative use of a for...loop to search */
+ for (text=G.main->text.first, i=1; text && index!=i; i++, text=text->id.next);
+ data->text = text;
+}
+
+/* this returns a string for the list of usable pyconstraint script names */
+char *buildmenu_pyconstraints(Text *con_text, int *pyconindex)
+{
+ Text *text;
+ char *menustr = MEM_callocN(128, "menustr pyconstraints");
+ char *name, stmp[128];
+ int buf = 128;
+ int used = strlen("Scripts: %t") + 1;
+ int i;
+
+ sprintf(menustr, "%s", "Scripts: %t");
+
+ for (text=G.main->text.first, i=1; text; i++, text=text->id.next) {
+ /* this is important to ensure that right script is shown as active */
+ if (text == con_text) *pyconindex = i;
+
+ /* menu entry is length of name + 3(len(|%X)) + 6 characters for the int.*/
+ if (BPY_is_pyconstraint(text)) {
+ name= text->id.name;
+ if (strlen(name)+used+10 >= buf) {
+ char *newbuf = MEM_callocN(buf+128, "menustr pyconstraints 2");
+ memcpy(newbuf, menustr, used);
+ MEM_freeN(menustr);
+ menustr = newbuf;
+ buf += 128;
+ }
+ sprintf(stmp, "|%s%%x%d", name, i);
+ strcat(menustr, stmp);
+ used += strlen(name)+10;
+ }
+ }
+
+ return menustr;
+}
+
+/* this callback gets called when the 'refresh' button of a pyconstraint gets pressed */
+void update_pyconstraint_cb(void *arg1, void *arg2)
+{
+ Object *owner= (Object *)arg1;
+ bConstraint *con= (bConstraint *)arg2;
+
+ if (owner && con)
+ BPY_pyconstraint_update(owner, con);
+}
+
+/* ------------- Child-Of Constraint ------------------ */
+
+/* ChildOf Constraint - set inverse callback */
+void childof_const_setinv (void *conv, void *unused)
+{
+ bChildOfConstraint *data= (bChildOfConstraint *)conv;
+ Object *ob= OBACT;
+ bPoseChannel *pchan= NULL;
+
+ /* try to find a pose channel */
+ if (ob && ob->pose)
+ pchan= get_active_posechannel(ob);
+
+ /* calculate/set inverse matrix */
+ if (pchan) {
+ bConstraintOb *cob;
+ float ctime= bsystem_time(ob, (float)G.scene->r.cfra, 0.0); /* not accurate... */
+ float pmat[4][4], chmat[4][4], cimat[4][4];
+ float vec0[3]={0,0,0}, vec1[3]={1,1,1};
+
+ /* make copies of pchan's original matrices (to be restored later) */
+ Mat4CpyMat4(pmat, pchan->pose_mat);
+ Mat4CpyMat4(chmat, pchan->chan_mat);
+ Mat4CpyMat4(cimat, pchan->constinv);
+
+
+ /* clear pchan's transform (for constraint solving) */
+ LocEulSizeToMat4(pchan->chan_mat, vec0, vec0, vec1);
+ Mat4MulMat4(pchan->pose_mat, pmat, cimat);
+ Mat4One(pchan->constinv);
+ Mat4One(data->invmat);
+
+
+ /* do constraint solving on pose-matrix containing no transforms
+ * N.B. code is copied from armature.c (where_is_pose_bone)
+ */
+ cob= constraints_make_evalob(ob, pchan, CONSTRAINT_OBTYPE_BONE);
+ solve_constraints(&pchan->constraints, cob, ctime);
+ constraints_clear_evalob(cob);
+
+
+ /* parent-inverse matrix for this constraint is given by taking the
+ * local-space (i.e. without any standard parents + restpose) pose_matrix
+ * (that was calulated with no transforms applied), and inverting it.
+ */
+ Mat4CpyMat4(pchan->constinv, pchan->pose_mat);
+
+ constraint_mat_convertspace(ob, pchan, pchan->constinv,
+ CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL);
+
+ Mat4Invert(data->invmat, pchan->constinv);
+
+
+ /* restore original matrices of pchan */
+ Mat4CpyMat4(pchan->pose_mat, pmat);
+ Mat4CpyMat4(pchan->chan_mat, chmat);
+ Mat4CpyMat4(pchan->constinv, cimat);
+ }
+ else if (ob) {
+ /* use what_does_parent to find inverse - just like for normal parenting.
+ * NOTE: what_does_parent uses a static workob defined in object.c
+ */
+ what_does_parent(ob);
+ Mat4Invert(data->invmat, workob.obmat);
+ }
+ else
+ Mat4One(data->invmat);
+}
+
+/* ChildOf Constraint - clear inverse callback */
+void childof_const_clearinv (void *conv, void *unused)
+{
+ bChildOfConstraint *data= (bChildOfConstraint *)conv;
+
+ /* simply clear the matrix */
+ Mat4One(data->invmat);
+}
diff --git a/source/blender/src/editcurve.c b/source/blender/src/editcurve.c
new file mode 100644
index 00000000000..a710b53da1c
--- /dev/null
+++ b/source/blender/src/editcurve.c
@@ -0,0 +1,4435 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <math.h>
+#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef WIN32
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+#include <stdlib.h>
+#include "MEM_guardedalloc.h"
+
+#include "BMF_Api.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_dynstr.h"
+#include "BLI_rand.h"
+
+#include "DNA_curve_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_key_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_library.h"
+#include "BKE_ipo.h"
+#include "BKE_depsgraph.h"
+#include "BKE_curve.h"
+#include "BKE_global.h"
+#include "BKE_object.h"
+#include "BKE_main.h"
+#include "BKE_key.h"
+
+#include "BIF_editmode_undo.h"
+#include "BIF_gl.h"
+#include "BIF_graphics.h"
+#include "BIF_screen.h"
+#include "BIF_toolbox.h"
+#include "BIF_space.h"
+#include "BIF_editkey.h"
+#include "BIF_mywindow.h"
+#include "BIF_interface.h"
+#include "BIF_transform.h"
+#include "BIF_retopo.h"
+
+#include "BSE_view.h" /* For persp... */
+#include "BSE_edit.h"
+
+#include "BDR_drawobject.h"
+#include "BDR_editcurve.h"
+#include "BDR_editobject.h"
+
+#include "mydevice.h"
+#include "blendef.h"
+
+#include "BDR_editcurve.h"
+/* still need to eradicate a few :( */
+#define callocstructN(x,y,name) (x*)MEM_callocN((y)* sizeof(x),name)
+
+
+ListBase editNurb;
+BPoint *lastselbp;
+Nurb *lastnu; /* for selected */
+
+
+/* void freeNurblist(ListBase *lb); already declared in the kernel */
+
+float nurbcircle[8][2]= {
+ {0.0, -1.0}, {-1.0, -1.0}, {-1.0, 0.0}, {-1.0, 1.0},
+ {0.0, 1.0}, { 1.0, 1.0}, { 1.0, 0.0}, { 1.0, -1.0}
+};
+
+/* ******************* SELECTION FUNCTIONS ********************* */
+
+/* returns 1 in case (de)selection was successful */
+static short select_beztriple(BezTriple *bezt, short selstatus, short flag, short hidden)
+{
+ if(bezt) {
+ if((bezt->hide==0) || (hidden==1)) {
+ if(selstatus==1) { /* selects */
+ bezt->f1 |= flag;
+ bezt->f2 |= flag;
+ bezt->f3 |= flag;
+ return 1;
+ }
+ else { /* deselects */
+ bezt->f1 &= ~flag;
+ bezt->f2 &= ~flag;
+ bezt->f3 &= ~flag;
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* returns 1 in case (de)selection was successful */
+static short select_bpoint(BPoint *bp, short selstatus, short flag, short hidden)
+{
+ if(bp) {
+ if((bp->hide==0) || (hidden==1)) {
+ if(selstatus==1) {
+ bp->f1 |= flag;
+ return 1;
+ }
+ else {
+ bp->f1 &= ~flag;
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static short swap_selection_beztriple(BezTriple *bezt)
+{
+ if(bezt->f2 & 1)
+ return select_beztriple(bezt, DESELECT, 1, VISIBLE);
+ else
+ return select_beztriple(bezt, SELECT, 1, VISIBLE);
+}
+
+static short swap_selection_bpoint(BPoint *bp)
+{
+ if(bp->f1 & 1)
+ return select_bpoint(bp, DESELECT, 1, VISIBLE);
+ else
+ return select_bpoint(bp, SELECT, 1, VISIBLE);
+}
+
+short isNurbsel(Nurb *nu)
+{
+ BezTriple *bezt;
+ BPoint *bp;
+ int a;
+
+ if((nu->type & 7)==CU_BEZIER) {
+ bezt= nu->bezt;
+ a= nu->pntsu;
+ while(a--) {
+ if( (bezt->f1 & 1) || (bezt->f2 & 1) || (bezt->f3 & 1) ) return 1;
+ bezt++;
+ }
+ }
+ else {
+ bp= nu->bp;
+ a= nu->pntsu*nu->pntsv;
+ while(a--) {
+ if( (bp->f1 & 1) ) return 1;
+ bp++;
+ }
+ }
+ return 0;
+}
+
+int isNurbsel_count(Nurb *nu)
+{
+ BezTriple *bezt;
+ BPoint *bp;
+ int a, sel=0;
+
+ if((nu->type & 7)==CU_BEZIER) {
+ bezt= nu->bezt;
+ a= nu->pntsu;
+ while(a--) {
+ if( (bezt->f1 & 1) || (bezt->f2 & 1) || (bezt->f3 & 1) ) sel++;
+ bezt++;
+ }
+ }
+ else {
+ bp= nu->bp;
+ a= nu->pntsu*nu->pntsv;
+ while(a--) {
+ if( (bp->f1 & 1) ) sel++;
+ bp++;
+ }
+ }
+ return sel;
+}
+
+/* ******************* PRINTS ********************* */
+
+void printknots()
+{
+ Nurb *nu;
+ int a, num;
+
+ for(nu= editNurb.first; nu; nu= nu->next) {
+ if(isNurbsel(nu) && (nu->type & 7)==CU_NURBS) {
+ if(nu->knotsu) {
+ num= KNOTSU(nu);
+ for(a=0;a<num;a++) printf("knotu %d: %f\n", a, nu->knotsu[a]);
+ }
+ if(nu->knotsv) {
+ num= KNOTSV(nu);
+ for(a=0;a<num;a++) printf("knotv %d: %f\n", a, nu->knotsv[a]);
+ }
+ }
+ }
+}
+
+#if 0
+static void printweightsNurb__doPrint(void *userData, Nurb *nurb, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
+{
+ char str[30];
+
+ if (bp && (bp->f1&1)) {
+ sprintf(str,"%2.2f", bp->vec[3]);
+
+ cpack(0x737373);
+ glRasterPos2i(x-1, y-1);
+ BMF_DrawString(G.font, str);
+
+ glRasterPos2i(x+1, y+1);
+ BMF_DrawString(G.font, str);
+
+ cpack(0xFFFFFF);
+ glRasterPos2i(x, y);
+ BMF_DrawString(G.font, str);
+ }
+}
+static void printweightsNurb(void)
+{
+ if(G.obedit==0) return;
+
+ persp(PERSP_WIN);
+
+ glDrawBuffer(GL_FRONT);
+ nurbs_foreachScreenVert(printweightsNurb__doPrint, NULL);
+ glDrawBuffer(GL_BACK);
+
+ persp(PERSP_VIEW);
+}
+#endif
+
+
+/* ********************* LOAD and MAKE *************** */
+
+void load_editNurb()
+{
+ /* load editNurb in object */
+ Curve *cu= 0;
+ Nurb *nu, *newnu;
+ KeyBlock *actkey;
+
+ if(G.obedit==0) return;
+
+ if ELEM(G.obedit->type, OB_CURVE, OB_SURF) {
+
+ G.totvert= count_curveverts(&editNurb);
+
+ cu= G.obedit->data;
+
+ /* are there keys? */
+ actkey = ob_get_keyblock(G.obedit);
+ if(actkey) {
+ /* active key: the vertices */
+
+ if(G.totvert) {
+ if(actkey->data) MEM_freeN(actkey->data);
+
+ actkey->data= MEM_callocN(cu->key->elemsize*G.totvert, "actkey->data");
+ actkey->totelem= G.totvert;
+
+ curve_to_key(cu, actkey, &editNurb);
+ }
+ }
+
+ if(cu->key && actkey!=cu->key->refkey) {
+ ;
+ }
+ else {
+ freeNurblist(&(cu->nurb));
+
+ for(nu= editNurb.first; nu; nu= nu->next) {
+ newnu= duplicateNurb(nu);
+ BLI_addtail(&(cu->nurb), newnu);
+
+ if((nu->type & 7)==CU_NURBS) {
+ if(nu->pntsu < nu->orderu) nu->orderu= nu->pntsu;
+ }
+ }
+ }
+
+ }
+
+ lastnu= NULL; /* for selected */
+}
+
+void make_editNurb()
+{
+ /* make copy of baseNurb in editNurb */
+ Curve *cu=0;
+ Nurb *nu, *newnu;
+ KeyBlock *actkey;
+
+ if(G.obedit==NULL) return;
+
+ lastselbp= NULL; /* global for select row */
+
+ if ELEM(G.obedit->type, OB_CURVE, OB_SURF) {
+ freeNurblist(&editNurb);
+
+ cu= G.obedit->data;
+ nu= cu->nurb.first;
+
+ while(nu) {
+ newnu= duplicateNurb(nu);
+ test2DNurb(newnu); // after join, or any other creation of curve
+ BLI_addtail(&editNurb, newnu);
+ nu= nu->next;
+ }
+
+ actkey = ob_get_keyblock(G.obedit);
+ if(actkey) {
+ strcpy(G.editModeTitleExtra, "(Key) ");
+ key_to_curve(actkey, cu, &editNurb);
+ }
+ }
+ else G.obedit= NULL;
+
+ countall();
+
+ lastnu= NULL; /* for selected */
+}
+
+void remake_editNurb()
+{
+
+ if(okee("Reload original data")==0) return;
+
+ make_editNurb();
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+}
+
+
+void separate_nurb()
+{
+ Nurb *nu, *nu1;
+ Object *oldob;
+ Base *base, *oldbase;
+ Curve *cu;
+ ListBase editnurbo;
+
+ if( G.vd==0 || (G.vd->lay & G.obedit->lay)==0 ) return;
+
+ if(okee("Separate")==0) return;
+
+ waitcursor(1);
+
+ cu= G.obedit->data;
+ if(cu->key) {
+ error("Can't separate a curve with vertex keys");
+ return;
+ }
+
+ /* we are going to trick everything as follows:
+ * 1. duplicate base: this is the new one, remember old pointer
+ * 2. set aside all NOT selected curves/nurbs
+ * 3. load_ebaseNurb(): this will be the new base
+ * 4. freelist and restore old nurbs
+ */
+
+ /* only edit-base selected */
+ base= FIRSTBASE;
+ while(base) {
+ if(base->lay & G.vd->lay) {
+ if(base->object==G.obedit) base->flag |= 1;
+ else base->flag &= ~1;
+ }
+ base= base->next;
+ }
+
+ /* set aside: everything that is not selected */
+ editnurbo.first= editnurbo.last= 0;
+ nu= editNurb.first;
+ while(nu) {
+ nu1= nu->next;
+ if(isNurbsel(nu)==0) {
+ BLI_remlink(&editNurb, nu);
+ BLI_addtail(&editnurbo, nu);
+ }
+ nu= nu1;
+ }
+
+ oldob= G.obedit;
+ oldbase= BASACT;
+
+ adduplicate(1, 0); /* no transform and zero so do get a linked dupli */
+
+ G.obedit= BASACT->object; /* basact is set in adduplicate() */
+
+ G.obedit->data= copy_curve(cu);
+ /* because new curve is a copy: reduce user count */
+ cu->id.us--;
+
+ load_editNurb();
+
+ BASACT->flag &= ~SELECT;
+
+ if(editNurb.first) freeNurblist(&editNurb);
+
+ editNurb= editnurbo;
+
+ G.obedit= 0; /* displists behave different in edit mode */
+ DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA); /* this is the separated one */
+ DAG_object_flush_update(G.scene, oldob, OB_RECALC_DATA); /* this is the separated one */
+
+ G.obedit= oldob;
+ BASACT= oldbase;
+ BASACT->flag |= SELECT;
+
+ waitcursor(0);
+
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+
+ lastnu= NULL; /* for selected */
+}
+
+/* ******************* FLAGS ********************* */
+
+
+short isNurbselUV(Nurb *nu, int *u, int *v, int flag)
+{
+ /* return u!=-1: 1 row in u-direction selected. U has value between 0-pntsv
+ * return v!=-1: 1 collumn in v-direction selected. V has value between 0-pntsu
+ */
+ BPoint *bp;
+ int a, b, sel;
+
+ *u= *v= -1;
+
+ bp= nu->bp;
+ for(b=0; b<nu->pntsv; b++) {
+ sel= 0;
+ for(a=0; a<nu->pntsu; a++, bp++) {
+ if(bp->f1 & flag) sel++;
+ }
+ if(sel==nu->pntsu) {
+ if(*u== -1) *u= b;
+ else return 0;
+ }
+ else if(sel>1) return 0; /* because sel==1 is still ok */
+ }
+
+ for(a=0; a<nu->pntsu; a++) {
+ sel= 0;
+ bp= nu->bp+a;
+ for(b=0; b<nu->pntsv; b++, bp+=nu->pntsu) {
+ if(bp->f1 & flag) sel++;
+ }
+ if(sel==nu->pntsv) {
+ if(*v== -1) *v= a;
+ else return 0;
+ }
+ else if(sel>1) return 0;
+ }
+
+ if(*u==-1 && *v>-1) return 1;
+ if(*v==-1 && *u>-1) return 1;
+ return 0;
+}
+
+void setflagsNurb(short flag)
+{
+ Nurb *nu;
+ BezTriple *bezt;
+ BPoint *bp;
+ int a;
+
+ for(nu= editNurb.first; nu; nu= nu->next) {
+ if( (nu->type & 7)==CU_BEZIER) {
+ a= nu->pntsu;
+ bezt= nu->bezt;
+ while(a--) {
+ bezt->f1= bezt->f2= bezt->f3= flag;
+ bezt++;
+ }
+ }
+ else {
+ a= nu->pntsu*nu->pntsv;
+ bp= nu->bp;
+ while(a--) {
+ bp->f1= flag;
+ bp++;
+ }
+ }
+ }
+}
+
+void rotateflagNurb(short flag, float *cent, float rotmat[][3])
+{
+ /* all verts with (flag & 'flag') rotate */
+ Nurb *nu;
+ BPoint *bp;
+ int a;
+
+ for(nu= editNurb.first; nu; nu= nu->next) {
+ if((nu->type & 7)==CU_NURBS) {
+ bp= nu->bp;
+ a= nu->pntsu*nu->pntsv;
+
+ while(a--) {
+ if(bp->f1 & flag) {
+ bp->vec[0]-=cent[0];
+ bp->vec[1]-=cent[1];
+ bp->vec[2]-=cent[2];
+ Mat3MulVecfl(rotmat, bp->vec);
+ bp->vec[0]+=cent[0];
+ bp->vec[1]+=cent[1];
+ bp->vec[2]+=cent[2];
+ }
+ bp++;
+ }
+ }
+ }
+}
+
+
+void translateflagNurb(short flag, float *vec)
+{
+ /* all verts with ('flag' & flag) translate */
+ Nurb *nu;
+ BezTriple *bezt;
+ BPoint *bp;
+ int a;
+
+ for(nu= editNurb.first; nu; nu= nu->next) {
+ if( (nu->type & 7)==CU_BEZIER) {
+ a= nu->pntsu;
+ bezt= nu->bezt;
+ while(a--) {
+ if(bezt->f1 & flag) VecAddf(bezt->vec[0], bezt->vec[0], vec);
+ if(bezt->f2 & flag) VecAddf(bezt->vec[1], bezt->vec[1], vec);
+ if(bezt->f3 & flag) VecAddf(bezt->vec[2], bezt->vec[2], vec);
+ bezt++;
+ }
+ }
+ else {
+ a= nu->pntsu*nu->pntsv;
+ bp= nu->bp;
+ while(a--) {
+ if(bp->f1 & flag) VecAddf(bp->vec, bp->vec, vec);
+ bp++;
+ }
+ }
+
+ test2DNurb(nu);
+ }
+}
+
+void weightflagNurb(short flag, float w, int mode) /* mode==0: replace, mode==1: multiply */
+{
+ Nurb *nu;
+ BPoint *bp;
+ int a;
+
+ for(nu= editNurb.first; nu; nu= nu->next) {
+ if((nu->type & 7)==CU_NURBS) {
+ a= nu->pntsu*nu->pntsv;
+ bp= nu->bp;
+ while(a--) {
+ if(bp->f1 & flag) {
+ if(mode==1) bp->vec[3]*= w;
+ else bp->vec[3]= w;
+ }
+ bp++;
+ }
+ }
+ }
+}
+
+void deleteflagNurb(short flag)
+{
+ Nurb *nu, *next;
+ BPoint *bp, *bpn, *newbp;
+ int a, b, newu, newv, sel;
+
+ if(G.obedit && G.obedit->type==OB_SURF);
+ else return;
+
+ lastselbp= NULL;
+
+ nu= editNurb.first;
+ while(nu) {
+ next= nu->next;
+
+ /* is entire nurb selected */
+ bp= nu->bp;
+ a= nu->pntsu*nu->pntsv;
+ while(a) {
+ a--;
+ if(bp->f1 & flag);
+ else break;
+ bp++;
+ }
+ if(a==0) {
+ BLI_remlink(&editNurb, nu);
+ freeNurb(nu);
+ }
+ else {
+ /* is nurb in U direction selected */
+ newv= nu->pntsv;
+ bp= nu->bp;
+ for(b=0; b<nu->pntsv; b++) {
+ sel= 0;
+ for(a=0; a<nu->pntsu; a++, bp++) {
+ if(bp->f1 & flag) sel++;
+ }
+ if(sel==nu->pntsu) {
+ newv--;
+ }
+ else if(sel>=1) {
+ /* don't delete */
+ break;
+ }
+ }
+ if(newv!=nu->pntsv && b==nu->pntsv) {
+ /* delete */
+ bp= nu->bp;
+ bpn = newbp =
+ (BPoint*) MEM_mallocN(newv * nu->pntsu * sizeof(BPoint), "deleteNurb");
+ for(b=0; b<nu->pntsv; b++) {
+ if((bp->f1 & flag)==0) {
+ memcpy(bpn, bp, nu->pntsu*sizeof(BPoint));
+ bpn+= nu->pntsu;
+ }
+ bp+= nu->pntsu;
+ }
+ nu->pntsv= newv;
+ MEM_freeN(nu->bp);
+ nu->bp= newbp;
+ if(nu->orderv>nu->pntsv) nu->orderv= nu->pntsv;
+
+ makeknots(nu, 2, nu->flagv>>1);
+ }
+ else {
+ /* is the nurb in V direction selected */
+ newu= nu->pntsu;
+ for(a=0; a<nu->pntsu; a++) {
+ bp= nu->bp+a;
+ sel= 0;
+ for(b=0; b<nu->pntsv; b++, bp+=nu->pntsu) {
+ if(bp->f1 & flag) sel++;
+ }
+ if(sel==nu->pntsv) {
+ newu--;
+ }
+ else if(sel>=1) {
+ /* don't delete */
+ break;
+ }
+ }
+ if(newu!=nu->pntsu && a==nu->pntsu) {
+ /* delete */
+ bp= nu->bp;
+ bpn = newbp =
+ (BPoint*) MEM_mallocN(newu * nu->pntsv * sizeof(BPoint), "deleteNurb");
+ for(b=0; b<nu->pntsv; b++) {
+ for(a=0; a<nu->pntsu; a++, bp++) {
+ if((bp->f1 & flag)==0) {
+ *bpn= *bp;
+ bpn++;
+ }
+ }
+ }
+ MEM_freeN(nu->bp);
+ nu->bp= newbp;
+ if(newu==1 && nu->pntsv>1) { /* make a U spline */
+ nu->pntsu= nu->pntsv;
+ nu->pntsv= 1;
+ SWAP(short, nu->orderu, nu->orderv);
+ if(nu->orderu>nu->pntsu) nu->orderu= nu->pntsu;
+ if(nu->knotsv) MEM_freeN(nu->knotsv);
+ nu->knotsv= 0;
+ }
+ else {
+ nu->pntsu= newu;
+ if(nu->orderu>nu->pntsu) nu->orderu= nu->pntsu;
+ }
+ makeknots(nu, 1, nu->flagu>>1);
+ }
+ }
+ }
+ nu= next;
+ }
+}
+
+short extrudeflagNurb(int flag)
+{
+ Nurb *nu;
+ BPoint *bp, *bpn, *newbp;
+ int ok= 0, a, u, v, len;
+
+ if(G.obedit && G.obedit->type==OB_SURF);
+ else return 0;
+
+ nu= editNurb.first;
+ while(nu) {
+
+ if(nu->pntsv==1) {
+ bp= nu->bp;
+ a= nu->pntsu;
+ while(a) {
+ if(bp->f1 & flag);
+ else break;
+ bp++;
+ a--;
+ }
+ if(a==0) {
+ ok= 1;
+ newbp =
+ (BPoint*)MEM_mallocN(2 * nu->pntsu * sizeof(BPoint), "extrudeNurb1");
+ memcpy(newbp, nu->bp, nu->pntsu*sizeof(BPoint) );
+ bp= newbp+ nu->pntsu;
+ memcpy(bp, nu->bp, nu->pntsu*sizeof(BPoint) );
+ MEM_freeN(nu->bp);
+ nu->bp= newbp;
+ a= nu->pntsu;
+ while(a--) {
+ select_bpoint(bp, SELECT, flag, HIDDEN);
+ select_bpoint(newbp, DESELECT, flag, HIDDEN);
+ bp++;
+ newbp++;
+ }
+
+ nu->pntsv= 2;
+ nu->orderv= 2;
+ makeknots(nu, 2, nu->flagv>>1);
+ }
+ }
+ else {
+ /* which row or collumn is selected */
+
+ if( isNurbselUV(nu, &u, &v, flag) ) {
+
+ /* deselect all */
+ bp= nu->bp;
+ a= nu->pntsu*nu->pntsv;
+ while(a--) {
+ select_bpoint(bp, DESELECT, flag, HIDDEN);
+ bp++;
+ }
+
+ if(u==0 || u== nu->pntsv-1) { /* row in u-direction selected */
+ ok= 1;
+ newbp =
+ (BPoint*) MEM_mallocN(nu->pntsu*(nu->pntsv + 1)
+ * sizeof(BPoint), "extrudeNurb1");
+ if(u==0) {
+ len= nu->pntsv*nu->pntsu;
+ memcpy(newbp+nu->pntsu, nu->bp, len*sizeof(BPoint) );
+ memcpy(newbp, nu->bp, nu->pntsu*sizeof(BPoint) );
+ bp= newbp;
+ }
+ else {
+ len= nu->pntsv*nu->pntsu;
+ memcpy(newbp, nu->bp, len*sizeof(BPoint) );
+ memcpy(newbp+len, nu->bp+len-nu->pntsu, nu->pntsu*sizeof(BPoint) );
+ bp= newbp+len;
+ }
+
+ a= nu->pntsu;
+ while(a--) {
+ select_bpoint(bp, SELECT, flag, HIDDEN);
+ bp++;
+ }
+
+ MEM_freeN(nu->bp);
+ nu->bp= newbp;
+ nu->pntsv++;
+ if(nu->resolv<3) nu->resolv++;
+ makeknots(nu, 2, nu->flagv>>1);
+ }
+ else if(v==0 || v== nu->pntsu-1) { /* collumn in v-direction selected */
+ ok= 1;
+ bpn = newbp =
+ (BPoint*) MEM_mallocN((nu->pntsu + 1) * nu->pntsv * sizeof(BPoint), "extrudeNurb1");
+ bp= nu->bp;
+
+ for(a=0; a<nu->pntsv; a++) {
+ if(v==0) {
+ *bpn= *bp;
+ bpn->f1 |= flag;
+ bpn++;
+ }
+ memcpy(bpn, bp, nu->pntsu*sizeof(BPoint));
+ bp+= nu->pntsu;
+ bpn+= nu->pntsu;
+ if(v== nu->pntsu-1) {
+ *bpn= *(bp-1);
+ bpn->f1 |= flag;
+ bpn++;
+ }
+ }
+
+ MEM_freeN(nu->bp);
+ nu->bp= newbp;
+ nu->pntsu++;
+ if(nu->resolu<3) nu->resolu++;
+ makeknots(nu, 1, nu->flagu>>1);
+ }
+ }
+ }
+ nu= nu->next;
+ }
+
+ return ok;
+}
+
+void adduplicateflagNurb(short flag)
+{
+ Nurb *nu, *newnu;
+ BezTriple *bezt, *bezt1;
+ BPoint *bp, *bp1;
+ int a, b, starta, enda, newu, newv;
+ char *usel;
+
+ nu= editNurb.last;
+ while(nu) {
+ if( (nu->type & 7)==CU_BEZIER) {
+ bezt= nu->bezt;
+ for(a=0; a<nu->pntsu; a++) {
+ enda= -1;
+ starta= a;
+ while( (bezt->f1 & flag) || (bezt->f2 & flag) || (bezt->f3 & flag) ) {
+ select_beztriple(bezt, DESELECT, flag, HIDDEN);
+ enda=a;
+ if(a>=nu->pntsu-1) break;
+ a++;
+ bezt++;
+ }
+ if(enda>=starta) {
+ newnu = (Nurb*)MEM_mallocN(sizeof(Nurb), "adduplicateN");
+ memcpy(newnu, nu, sizeof(Nurb));
+ BLI_addtail(&editNurb, newnu);
+ lastnu= newnu;
+ newnu->pntsu= enda-starta+1;
+ newnu->bezt=
+ (BezTriple*)MEM_mallocN((enda - starta + 1) * sizeof(BezTriple), "adduplicateN");
+ memcpy(newnu->bezt, nu->bezt+starta, newnu->pntsu*sizeof(BezTriple));
+
+ b= newnu->pntsu;
+ bezt1= newnu->bezt;
+ while(b--) {
+ select_beztriple(bezt1, SELECT, flag, HIDDEN);
+ bezt1++;
+ }
+
+ if(nu->flagu & 1) {
+ if(starta!=0 || enda!=nu->pntsu-1) newnu->flagu--;
+ }
+ }
+ bezt++;
+ }
+ }
+ else if(nu->pntsv==1) { /* because UV Nurb has a different method for dupli */
+ bp= nu->bp;
+ for(a=0; a<nu->pntsu; a++) {
+ enda= -1;
+ starta= a;
+ while(bp->f1 & flag) {
+ select_bpoint(bp, DESELECT, flag, HIDDEN);
+ enda= a;
+ if(a>=nu->pntsu-1) break;
+ a++;
+ bp++;
+ }
+ if(enda>=starta) {
+ newnu = (Nurb*)MEM_mallocN(sizeof(Nurb), "adduplicateN3");
+ memcpy(newnu, nu, sizeof(Nurb));
+ lastnu= newnu;
+ BLI_addtail(&editNurb, newnu);
+ newnu->pntsu= enda-starta+1;
+ newnu->bp = (BPoint*)MEM_mallocN((enda-starta+1) * sizeof(BPoint), "adduplicateN4");
+ memcpy(newnu->bp, nu->bp+starta, newnu->pntsu*sizeof(BPoint));
+
+ b= newnu->pntsu;
+ bp1= newnu->bp;
+ while(b--) {
+ select_bpoint(bp1, SELECT, flag, HIDDEN);
+ bp1++;
+ }
+
+ if(nu->flagu & 1) {
+ if(starta!=0 || enda!=nu->pntsu-1) newnu->flagu--;
+ }
+
+ /* knots */
+ newnu->knotsu= 0;
+ makeknots(newnu, 1, newnu->flagu>>1);
+ }
+ bp++;
+ }
+ }
+ else {
+ /* a rectangular area in nurb has to be selected */
+ if(isNurbsel(nu)) {
+ usel= MEM_callocN(nu->pntsu, "adduplicateN4");
+ bp= nu->bp;
+ for(a=0; a<nu->pntsv; a++) {
+ for(b=0; b<nu->pntsu; b++, bp++) {
+ if(bp->f1 & flag) usel[b]++;
+ }
+ }
+ newu= 0;
+ newv= 0;
+ for(a=0; a<nu->pntsu; a++) {
+ if(usel[a]) {
+ if(newv==0 || usel[a]==newv) {
+ newv= usel[a];
+ newu++;
+ }
+ else {
+ newv= 0;
+ break;
+ }
+ }
+ }
+ if(newu==0 || newv==0) {
+ printf("Can't duplicate Nurb\n");
+ }
+ else {
+
+ if(newu==1) SWAP(short, newu, newv);
+
+ newnu = (Nurb*)MEM_mallocN(sizeof(Nurb), "adduplicateN5");
+ memcpy(newnu, nu, sizeof(Nurb));
+ BLI_addtail(&editNurb, newnu);
+ lastnu= newnu;
+ newnu->pntsu= newu;
+ newnu->pntsv= newv;
+ newnu->bp =
+ (BPoint*)MEM_mallocN(newu * newv * sizeof(BPoint), "adduplicateN6");
+ newnu->orderu= MIN2(nu->orderu, newu);
+ newnu->orderv= MIN2(nu->orderv, newv);
+
+ bp= newnu->bp;
+ bp1= nu->bp;
+ for(a=0; a<nu->pntsv; a++) {
+ for(b=0; b<nu->pntsu; b++, bp1++) {
+ if(bp1->f1 & flag) {
+ memcpy(bp, bp1, sizeof(BPoint));
+ select_bpoint(bp1, DESELECT, flag, HIDDEN);
+ bp++;
+ }
+ }
+ }
+ if(nu->pntsu==newnu->pntsu) {
+ newnu->knotsu= MEM_mallocN(sizeof(float)*KNOTSU(nu), "adduplicateN6");
+ memcpy(newnu->knotsu, nu->knotsu, sizeof(float)*KNOTSU(nu));
+ }
+ else {
+ newnu->knotsu= 0;
+ makeknots(newnu, 1, newnu->flagu>>1);
+ }
+ if(nu->pntsv==newnu->pntsv) {
+ newnu->knotsv= MEM_mallocN(sizeof(float)*KNOTSV(nu), "adduplicateN7");
+ memcpy(newnu->knotsv, nu->knotsv, sizeof(float)*KNOTSV(nu));
+ }
+ else {
+ newnu->knotsv= 0;
+ makeknots(newnu, 2, newnu->flagv>>1);
+ }
+
+ }
+ MEM_freeN(usel);
+ }
+ }
+
+ nu= nu->prev;
+ }
+
+ /* lastnu changed */
+ allqueue(REDRAWBUTSEDIT, 0);
+}
+
+
+void switchdirectionNurb2(void)
+{
+ Nurb *nu;
+
+ if(G.vd==0 || !(G.obedit->lay & G.vd->lay))
+ return;
+
+ for(nu= editNurb.first; nu; nu= nu->next) {
+ if( isNurbsel(nu) ) switchdirectionNurb(nu);
+ }
+
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+
+ allqueue(REDRAWVIEW3D, 0);
+ BIF_undo_push("Switch direction");
+}
+
+void switchdirection_knots(float *base, int tot)
+{
+ float *fp1, *fp2, *tempf;
+ int a;
+
+ if(base==NULL || tot==0) return;
+
+ /* reverse knots */
+ a= tot;
+ fp1= base;
+ fp2= fp1+(a-1);
+ a/= 2;
+ while(fp1!=fp2 && a>0) {
+ SWAP(float, *fp1, *fp2);
+ a--;
+ fp1++;
+ fp2--;
+ }
+ /* and make in increasing order again */
+ a= tot;
+ fp1= base;
+ fp2=tempf= MEM_mallocN(sizeof(float)*a, "switchdirect");
+ while(a--) {
+ fp2[0]= fabs(fp1[1]-fp1[0]);
+ fp1++;
+ fp2++;
+ }
+
+ a= tot-1;
+ fp1= base;
+ fp2= tempf;
+ fp1[0]= 0.0;
+ fp1++;
+ while(a--) {
+ fp1[0]= fp1[-1]+fp2[0];
+ fp1++;
+ fp2++;
+ }
+ MEM_freeN(tempf);
+}
+
+/* **************** EDIT ************************ */
+
+/* next == 1 -> select next */
+/* next == -1 -> select previous */
+/* cont == 1 -> select continuously */
+/* selstatus, inverts behaviour */
+static void select_adjacent_cp(short next, short cont, short selstatus)
+{
+ Nurb *nu;
+ BezTriple *bezt;
+ BPoint *bp;
+ int a;
+ short lastsel= 0, sel=0;
+
+ if(next==0) return;
+
+ for(nu= editNurb.first; nu; nu= nu->next) {
+ lastsel=0;
+ if((nu->type & 7)==CU_BEZIER) {
+ a= nu->pntsu;
+ bezt= nu->bezt;
+ if(next < 0) bezt= (nu->bezt + (a-1));
+ while(a--) {
+ if(a-abs(next) < 0) break;
+ sel= 0;
+ if((lastsel==0) && (bezt->hide==0) && ((bezt->f2 & 1) || (selstatus==0))) {
+ bezt+=next;
+ if(!(bezt->f2 & 1) || (selstatus==0)) {
+ sel= select_beztriple(bezt, selstatus, 1, VISIBLE);
+ if((sel==1) && (cont==0)) lastsel= 1;
+ }
+ }
+ else {
+ bezt+=next;
+ lastsel= 0;
+ }
+ /* move around in zigzag way so that we go through each */
+ bezt-=(next-next/abs(next));
+ }
+ }
+ else {
+ a= nu->pntsu*nu->pntsv;
+ bp= nu->bp;
+ if(next < 0) bp= (nu->bp + (a-1));
+ while(a--) {
+ if(a-abs(next) < 0) break;
+ sel=0;
+ if((lastsel==0) && (bp->hide==0) && ((bp->f1 & 1) || (selstatus==0))) {
+ bp+=next;
+ if(!(bp->f1 & 1) || (selstatus==0)) {
+ sel= select_bpoint(bp, selstatus, 1, VISIBLE);
+ if((sel==1) && (cont==0)) lastsel= 1;
+ }
+ }
+ else {
+ bp+=next;
+ lastsel= 0;
+ }
+ /* move around in zigzag way so that we go through each */
+ bp-=(next-next/abs(next));
+ }
+ }
+ }
+}
+
+static short nurb_has_selected_cps()
+{
+ Nurb *nu;
+ BezTriple *bezt;
+ BPoint *bp;
+ int a;
+
+ for(nu= editNurb.first; nu; nu= nu->next) {
+ if((nu->type & 7)==CU_BEZIER) {
+ a= nu->pntsu;
+ bezt= nu->bezt;
+ while(a--) {
+ if(bezt->hide==0) {
+ if((bezt->f1 & 1)
+ || (bezt->f2 & 1)
+ || (bezt->f3 & 1)) return 1;
+ }
+ bezt++;
+ }
+ }
+ else {
+ a= nu->pntsu*nu->pntsv;
+ bp= nu->bp;
+ while(a--) {
+ if((bp->hide==0) && (bp->f1 & 1)) return 1;
+ bp++;
+ }
+ }
+ }
+
+ return 0;
+}
+
+void deselectall_nurb()
+{
+ if(!G.vd || !(G.obedit->lay & G.vd->lay))
+ return;
+
+ if(nurb_has_selected_cps()) { /* deselect all */
+ selectend_nurb(FIRST, 0, DESELECT); /* set first control points as unselected */
+ select_adjacent_cp(1, 1, DESELECT); /* cascade selection */
+ }
+ else { /* select all */
+ selectend_nurb(FIRST, 0, SELECT); /* set first control points as selected */
+ select_adjacent_cp(1, 1, SELECT); /* cascade selection */
+ }
+
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ BIF_undo_push("Deselect all");
+}
+
+void hideNurb(int swap)
+{
+ Nurb *nu;
+ BPoint *bp;
+ BezTriple *bezt;
+ int a, sel;
+
+ if(G.obedit==0) return;
+
+ BIF_undo_push("Hide");
+
+ for(nu= editNurb.first; nu; nu= nu->next) {
+ if((nu->type & 7)==CU_BEZIER) {
+ bezt= nu->bezt;
+ a= nu->pntsu;
+ sel= 0;
+ while(a--) {
+ if(BEZSELECTED(bezt)) {
+ select_beztriple(bezt, DESELECT, 1, HIDDEN);
+ bezt->hide= 1;
+ }
+ if(bezt->hide) sel++;
+ bezt++;
+ }
+ if(sel==nu->pntsu) nu->hide= 1;
+ }
+ else {
+ bp= nu->bp;
+ a= nu->pntsu*nu->pntsv;
+ sel= 0;
+ while(a--) {
+ if(swap==0 && (bp->f1 & 1)) {
+ select_bpoint(bp, DESELECT, 1, HIDDEN);
+ bp->hide= 1;
+ }
+ else if(swap && (bp->f1 & 1)==0) {
+ select_bpoint(bp, DESELECT, 1, HIDDEN);
+ bp->hide= 1;
+ }
+ if(bp->hide) sel++;
+ bp++;
+ }
+ if(sel==nu->pntsu*nu->pntsv) nu->hide= 1;
+ }
+ }
+
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+}
+
+void revealNurb()
+{
+ Nurb *nu;
+ BPoint *bp;
+ BezTriple *bezt;
+ int a;
+
+ if(G.obedit==0) return;
+
+ for(nu= editNurb.first; nu; nu= nu->next) {
+ nu->hide= 0;
+ if((nu->type & 7)==CU_BEZIER) {
+ bezt= nu->bezt;
+ a= nu->pntsu;
+ while(a--) {
+ if(bezt->hide) {
+ select_beztriple(bezt, SELECT, 1, HIDDEN);
+ bezt->hide= 0;
+ }
+ bezt++;
+ }
+ }
+ else {
+ bp= nu->bp;
+ a= nu->pntsu*nu->pntsv;
+ while(a--) {
+ if(bp->hide) {
+ select_bpoint(bp, SELECT, 1, HIDDEN);
+ bp->hide= 0;
+ }
+ bp++;
+ }
+ }
+ }
+
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ BIF_undo_push("Reveal");
+
+}
+
+void selectswapNurb()
+{
+ Nurb *nu;
+ BPoint *bp;
+ BezTriple *bezt;
+ int a;
+
+ if(G.obedit==0) return;
+
+ for(nu= editNurb.first; nu; nu= nu->next) {
+ if((nu->type & 7)==CU_BEZIER) {
+ bezt= nu->bezt;
+ a= nu->pntsu;
+ while(a--) {
+ if(bezt->hide==0) {
+ if(bezt->f1 & 1) bezt->f1 &= ~1;
+ else bezt->f1 |= 1;
+ if(bezt->f2 & 1) bezt->f2 &= ~1;
+ else bezt->f2 |= 1;
+ if(bezt->f3 & 1) bezt->f3 &= ~1;
+ else bezt->f3 |= 1;
+ }
+ bezt++;
+ }
+ }
+ else {
+ bp= nu->bp;
+ a= nu->pntsu*nu->pntsv;
+ while(a--) {
+ swap_selection_bpoint(bp);
+ bp++;
+ }
+ }
+ }
+
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ BIF_undo_push("Select swap");
+
+}
+
+/** Divide the line segments associated with the currently selected
+ * curve nodes (Bezier or NURB). If there are no valid segment
+ * selections within the current selection, nothing happens.
+ *
+ * @deffunc subdividenurb subdivideNurb(void)
+ * @return Nothing
+ * @param None
+*/
+void subdivideNurb()
+{
+ Nurb *nu;
+ BezTriple *prevbezt, *bezt, *beztnew, *beztn;
+ BPoint *bp, *prevbp, *bpnew, *bpn;
+ float vec[15];
+ int a, b, sel, amount, *usel, *vsel;
+
+ // printf("*** subdivideNurb: entering subdivide\n");
+
+ for(nu= editNurb.first; nu; nu= nu->next) {
+ amount= 0;
+ if((nu->type & 7)==CU_BEZIER) {
+ /*
+ Insert a point into a 2D Bezier curve.
+ Endpoints are preserved. Otherwise, all selected and inserted points are
+ newly created. Old points are discarded.
+ */
+ /* count */
+ if(nu->flagu & 1) {
+ a= nu->pntsu;
+ bezt= nu->bezt;
+ prevbezt= bezt+(a-1);
+ }
+ else {
+ a= nu->pntsu-1;
+ prevbezt= nu->bezt;
+ bezt= prevbezt+1;
+ }
+ while(a--) {
+ if( BEZSELECTED(prevbezt) && BEZSELECTED(bezt) ) amount++;
+ prevbezt= bezt;
+ bezt++;
+ }
+
+ if(amount) {
+ /* insert */
+ beztnew =
+ (BezTriple*)MEM_mallocN((amount + nu->pntsu) * sizeof(BezTriple), "subdivNurb");
+ beztn= beztnew;
+ if(nu->flagu & 1) {
+ a= nu->pntsu;
+ bezt= nu->bezt;
+ prevbezt= bezt+(a-1);
+ }
+ else {
+ a= nu->pntsu-1;
+ prevbezt= nu->bezt;
+ bezt= prevbezt+1;
+ }
+ while(a--) {
+ memcpy(beztn, prevbezt, sizeof(BezTriple));
+ beztn++;
+
+ if( BEZSELECTED(prevbezt) && BEZSELECTED(bezt) ) {
+ memcpy(beztn, bezt, sizeof(BezTriple));
+
+ /* midpoint subdividing */
+ VecMidf(vec, prevbezt->vec[1], prevbezt->vec[2]);
+ VecMidf(vec+3, prevbezt->vec[2], bezt->vec[0]);
+ VecMidf(vec+6, bezt->vec[0], bezt->vec[1]);
+
+ VecMidf(vec+9, vec, vec+3);
+ VecMidf(vec+12, vec+3, vec+6);
+
+ /* change handle of prev beztn */
+ VECCOPY((beztn-1)->vec[2], vec);
+ /* new point */
+ VECCOPY(beztn->vec[0], vec+9);
+ VecMidf(beztn->vec[1], vec+9, vec+12);
+ VECCOPY(beztn->vec[2], vec+12);
+ /* handle of next bezt */
+ if(a==0 && (nu->flagu & 1)) {VECCOPY(beztnew->vec[0], vec+6);}
+ else {VECCOPY(bezt->vec[0], vec+6);}
+
+ beztn->radius = (prevbezt->radius + bezt->radius)/2.0f;
+ beztn->weight = (prevbezt->weight + bezt->weight)/2.0f;
+
+ beztn++;
+ }
+
+ prevbezt= bezt;
+ bezt++;
+ }
+ /* last point */
+ if((nu->flagu & 1)==0) memcpy(beztn, prevbezt, sizeof(BezTriple));
+
+ MEM_freeN(nu->bezt);
+ nu->bezt= beztnew;
+ nu->pntsu+= amount;
+
+ calchandlesNurb(nu);
+ }
+ } /* End of 'if((nu->type & 7)==CU_BEZIER)' */
+ else if (nu->pntsv==1) {
+ /*
+ All flat lines (ie. co-planar), except flat Nurbs. Flat NURB curves
+ are handled together with the regular NURB plane division, as it
+ should be. I split it off just now, let's see if it is
+ stable... nzc 30-5-'00
+ */
+ /* count */
+ if(nu->flagu & 1) {
+ a= nu->pntsu*nu->pntsv;
+ bp= nu->bp;
+ prevbp= bp+(a-1);
+ }
+ else {
+ a= nu->pntsu-1;
+ prevbp= nu->bp;
+ bp= prevbp+1;
+ }
+ while(a--) {
+ if( (bp->f1 & 1) && (prevbp->f1 & 1) ) amount++;
+ prevbp= bp;
+ bp++;
+ }
+
+ if(amount) {
+ /* insert */
+ bpnew =
+ (BPoint*)MEM_mallocN((amount + nu->pntsu) * sizeof(BPoint), "subdivNurb2");
+ bpn= bpnew;
+
+ if(nu->flagu & 1) {
+ a= nu->pntsu;
+ bp= nu->bp;
+ prevbp= bp+(a-1);
+ }
+ else {
+ a= nu->pntsu-1;
+ prevbp= nu->bp;
+ bp= prevbp+1;
+ }
+ while(a--) {
+ memcpy(bpn, prevbp, sizeof(BPoint));
+ bpn++;
+
+ if( (bp->f1 & 1) && (prevbp->f1 & 1) ) {
+ // printf("*** subdivideNurb: insert 'linear' point\n");
+ memcpy(bpn, bp, sizeof(BPoint));
+ bpn->vec[0]= (prevbp->vec[0]+bp->vec[0])/2.0;
+ bpn->vec[1]= (prevbp->vec[1]+bp->vec[1])/2.0;
+ bpn->vec[2]= (prevbp->vec[2]+bp->vec[2])/2.0;
+ bpn->vec[3]= (prevbp->vec[3]+bp->vec[3])/2.0;
+ bpn++;
+
+ }
+ prevbp= bp;
+ bp++;
+ }
+ if((nu->flagu & 1)==0) memcpy(bpn, prevbp, sizeof(BPoint)); /* last point */
+
+ MEM_freeN(nu->bp);
+ nu->bp= bpnew;
+ nu->pntsu+= amount;
+
+ if(nu->type & 4) {
+ makeknots(nu, 1, nu->flagu>>1);
+ }
+ }
+ } /* End of 'else if(nu->pntsv==1)' */
+ else if((nu->type & 7)==CU_NURBS) {
+ /* This is a very strange test ... */
+ /**
+ Subdivide NURB surfaces - nzc 30-5-'00 -
+
+ Subdivision of a NURB curve can be effected by adding a
+ control point (insertion of a knot), or by raising the
+ degree of the functions used to build the NURB. The
+ expression
+
+ degree = #knots - #controlpoints + 1 (J Walter piece)
+ degree = #knots - #controlpoints (Blender
+ implementation)
+ ( this is confusing.... what is true? Another concern
+ is that the JW piece allows the curve to become
+ explicitly 1st order derivative discontinuous, while
+ this is not what we want here... )
+
+ is an invariant for a single NURB curve. Raising the degree
+ of the NURB is done elsewhere; the degree is assumed
+ constant during this opration. Degree is a property shared
+ by all controlpoints in a curve (even though it is stored
+ per control point - this can be misleading).
+ Adding a knot is done by searching for the place in the
+ knot vector where a certain knot value must be inserted, or
+ by picking an appropriate knot value between two existing
+ ones. The number of controlpoints that is influenced by the
+ insertion depends on the order of the curve. A certain
+ minimum number of knots is needed to form high-order
+ curves, as can be seen from the equation above. In Blender,
+ currently NURBs may be up to 6th order, so we modify at
+ most 6 points. One point is added. For an n-degree curve,
+ n points are discarded, and n+1 points inserted
+ (so effectively, n points are modified). (that holds for
+ the JW piece, but it seems not for our NURBs)
+ In practice, the knot spacing is copied, but the tail
+ (the points following the insertion point) need to be
+ offset to keep the knot series ascending. The knot series
+ is always a series of monotonically ascending integers in
+ Blender. When not enough control points are available to
+ fit the order, duplicates of the endpoints are added as
+ needed.
+ */
+ /* selection-arrays */
+ usel= MEM_callocN(sizeof(int)*nu->pntsu, "subivideNurb3");
+ vsel= MEM_callocN(sizeof(int)*nu->pntsv, "subivideNurb3");
+ sel= 0;
+
+ /* Count the number of selected points. */
+ bp= nu->bp;
+ for(a=0; a<nu->pntsv; a++) {
+ for(b=0; b<nu->pntsu; b++) {
+ if(bp->f1 & 1) {
+ usel[b]++;
+ vsel[a]++;
+ sel++;
+ }
+ bp++;
+ }
+ }
+ if( sel == (nu->pntsu*nu->pntsv) ) { /* subdivide entire nurb */
+ /* Global subdivision is a special case of partial
+ subdivision. Strange it is considered separately... */
+ bpn=bpnew= MEM_mallocN( (2*nu->pntsu-1)*(2*nu->pntsv-1)*sizeof(BPoint), "subdivideNurb4");
+ bp= nu->bp;
+ /* first subdivide rows */
+ for(a=0; a<nu->pntsv; a++) {
+ for(b=0; b<nu->pntsu; b++) {
+ *bpn= *bp;
+ bpn++;
+ bp++;
+ if(b<nu->pntsu-1) {
+ *bpn= *bp;
+ prevbp= bp-1;
+ bpn->vec[0]= (prevbp->vec[0]+bp->vec[0])/2.0;
+ bpn->vec[1]= (prevbp->vec[1]+bp->vec[1])/2.0;
+ bpn->vec[2]= (prevbp->vec[2]+bp->vec[2])/2.0;
+ bpn->vec[3]= (prevbp->vec[3]+bp->vec[3])/2.0;
+ bpn++;
+ }
+ }
+ bpn+= (2*nu->pntsu-1);
+ }
+ /* now insert new */
+ bpn= bpnew+(2*nu->pntsu-1);
+ bp= bpnew+(4*nu->pntsu-2);
+ prevbp= bpnew;
+ for(a=1; a<nu->pntsv; a++) {
+
+ for(b=0; b<2*nu->pntsu-1; b++) {
+ *bpn= *bp;
+ bpn->vec[0]= (prevbp->vec[0]+bp->vec[0])/2.0;
+ bpn->vec[1]= (prevbp->vec[1]+bp->vec[1])/2.0;
+ bpn->vec[2]= (prevbp->vec[2]+bp->vec[2])/2.0;
+ bpn->vec[3]= (prevbp->vec[3]+bp->vec[3])/2.0;
+ bpn++;
+ bp++;
+ prevbp++;
+ }
+ bp+= (2*nu->pntsu-1);
+ bpn+= (2*nu->pntsu-1);
+ prevbp+= (2*nu->pntsu-1);
+ }
+ MEM_freeN(nu->bp);
+ nu->bp= bpnew;
+ nu->pntsu= 2*nu->pntsu-1;
+ nu->pntsv= 2*nu->pntsv-1;
+ makeknots(nu, 1, nu->flagu>>1);
+ makeknots(nu, 2, nu->flagv>>1);
+ } /* End of 'if(sel== nu->pntsu*nu->pntsv)' (subdivide entire NURB) */
+ else {
+ /* subdivide in v direction? */
+ sel= 0;
+ for(a=0; a<nu->pntsv-1; a++) {
+ if(vsel[a]==nu->pntsu && vsel[a+1]==nu->pntsu) sel++;
+ }
+
+ if(sel) { /* V ! */
+ bpn=bpnew= MEM_mallocN( (sel+nu->pntsv)*nu->pntsu*sizeof(BPoint), "subdivideNurb4");
+ bp= nu->bp;
+ for(a=0; a<nu->pntsv; a++) {
+ for(b=0; b<nu->pntsu; b++) {
+ *bpn= *bp;
+ bpn++;
+ bp++;
+ }
+ if( (a<nu->pntsv-1) && vsel[a]==nu->pntsu && vsel[a+1]==nu->pntsu ) {
+ prevbp= bp- nu->pntsu;
+ for(b=0; b<nu->pntsu; b++) {
+ /*
+ This simple bisection must be replaces by a
+ subtle resampling of a number of points. Our
+ task is made slightly easier because each
+ point in our curve is a separate data
+ node. (is it?)
+ */
+ *bpn= *prevbp;
+ bpn->vec[0]= (prevbp->vec[0]+bp->vec[0])/2.0;
+ bpn->vec[1]= (prevbp->vec[1]+bp->vec[1])/2.0;
+ bpn->vec[2]= (prevbp->vec[2]+bp->vec[2])/2.0;
+ bpn->vec[3]= (prevbp->vec[3]+bp->vec[3])/2.0;
+ bpn++;
+ prevbp++;
+ bp++;
+ }
+ bp-= nu->pntsu;
+ }
+ }
+ MEM_freeN(nu->bp);
+ nu->bp= bpnew;
+ nu->pntsv+= sel;
+ makeknots(nu, 2, nu->flagv>>1);
+ }
+ else {
+ /* or in u direction? */
+ sel= 0;
+ for(a=0; a<nu->pntsu-1; a++) {
+ if(usel[a]==nu->pntsv && usel[a+1]==nu->pntsv) sel++;
+ }
+
+ if(sel) { /* U ! */
+ /* Inserting U points is sort of 'default' Flat curves only get */
+ /* U points inserted in them. */
+ bpn=bpnew= MEM_mallocN( (sel+nu->pntsu)*nu->pntsv*sizeof(BPoint), "subdivideNurb4");
+ bp= nu->bp;
+ for(a=0; a<nu->pntsv; a++) {
+ for(b=0; b<nu->pntsu; b++) {
+ *bpn= *bp;
+ bpn++;
+ bp++;
+ if( (b<nu->pntsu-1) && usel[b]==nu->pntsv && usel[b+1]==nu->pntsv ) {
+ /*
+ One thing that bugs me here is that the
+ orders of things are not the same as in
+ the JW piece. Also, this implies that we
+ handle at most 3rd order curves? I miss
+ some symmetry here...
+ */
+ prevbp= bp- 1;
+ *bpn= *prevbp;
+ bpn->vec[0]= (prevbp->vec[0]+bp->vec[0])/2.0;
+ bpn->vec[1]= (prevbp->vec[1]+bp->vec[1])/2.0;
+ bpn->vec[2]= (prevbp->vec[2]+bp->vec[2])/2.0;
+ bpn->vec[3]= (prevbp->vec[3]+bp->vec[3])/2.0;
+ bpn++;
+ }
+ }
+ }
+ MEM_freeN(nu->bp);
+ nu->bp= bpnew;
+ nu->pntsu+= sel;
+ makeknots(nu, 1, nu->flagu>>1); /* shift knots
+ forward */
+ }
+ }
+ }
+ MEM_freeN(usel);
+ MEM_freeN(vsel);
+
+ } /* End of 'if((nu->type & 7)==CU_NURBS)' */
+ }
+
+
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ BIF_undo_push("Subdivide");
+
+}
+
+static void findnearestNurbvert__doClosest(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
+{
+ struct { BPoint *bp; BezTriple *bezt; Nurb *nurb; short dist, hpoint, select, mval[2]; } *data = userData;
+
+ short flag;
+ short temp;
+
+ if (bp) {
+ flag = bp->f1;
+ } else {
+ if (beztindex==0) {
+ flag = bezt->f1;
+ } else if (beztindex==1) {
+ flag = bezt->f2;
+ } else {
+ flag = bezt->f3;
+ }
+ }
+
+ temp = abs(data->mval[0]-x) + abs(data->mval[1]-y);
+ if ((flag&1)==data->select) temp += 5;
+ if (bezt && beztindex==1) temp += 3; /* middle points get a small disadvantage */
+
+ if (temp<data->dist) {
+ data->dist = temp;
+
+ data->bp = bp;
+ data->bezt = bezt;
+ data->nurb = nu;
+ data->hpoint = bezt?beztindex:0;
+ }
+}
+
+static short findnearestNurbvert(short sel, Nurb **nurb, BezTriple **bezt, BPoint **bp)
+{
+ /* sel==1: selected gets a disadvantage */
+ /* in nurb and bezt or bp the nearest is written */
+ /* return 0 1 2: handlepunt */
+ struct { BPoint *bp; BezTriple *bezt; Nurb *nurb; short dist, hpoint, select, mval[2]; } data = {0};
+
+ data.dist = 100;
+ data.hpoint = 0;
+ data.select = sel;
+ getmouseco_areawin(data.mval);
+
+ nurbs_foreachScreenVert(findnearestNurbvert__doClosest, &data);
+
+ *nurb = data.nurb;
+ *bezt = data.bezt;
+ *bp = data.bp;
+
+ return data.hpoint;
+}
+
+
+static void findselectedNurbvert(Nurb **nu, BezTriple **bezt, BPoint **bp)
+{
+ /* in nu and (bezt or bp) selected are written if there's 1 sel. */
+ /* if more points selected in 1 spline: return only nu, bezt and bp are 0 */
+ Nurb *nu1;
+ BezTriple *bezt1;
+ BPoint *bp1;
+ int a;
+
+ *nu= 0;
+ *bezt= 0;
+ *bp= 0;
+ for(nu1= editNurb.first; nu1; nu1= nu1->next) {
+ if((nu1->type & 7)==CU_BEZIER) {
+ bezt1= nu1->bezt;
+ a= nu1->pntsu;
+ while(a--) {
+ if( (bezt1->f1 & 1) || (bezt1->f2 & 1) || (bezt1->f3 & 1) ) {
+ if(*nu!=0 && *nu!= nu1) {
+ *nu= 0;
+ *bp= 0;
+ *bezt= 0;
+ return;
+ }
+ else if(*bezt || *bp) {
+ *bp= 0;
+ *bezt= 0;
+ }
+ else {
+ *bezt= bezt1;
+ *nu= nu1;
+ }
+ }
+ bezt1++;
+ }
+ }
+ else {
+ bp1= nu1->bp;
+ a= nu1->pntsu*nu1->pntsv;
+ while(a--) {
+ if( bp1->f1 & 1 ) {
+ if(*nu!=0 && *nu!= nu1) {
+ *bp= 0;
+ *bezt= 0;
+ *nu= 0;
+ return;
+ }
+ else if(*bezt || *bp) {
+ *bp= 0;
+ *bezt= 0;
+ }
+ else {
+ *bp= bp1;
+ *nu= nu1;
+ }
+ }
+ bp1++;
+ }
+ }
+ }
+}
+
+int convertspline(short type, Nurb *nu)
+{
+ BezTriple *bezt;
+ BPoint *bp;
+ int a, c, nr;
+
+ if((nu->type & 7)==0) { /* Poly */
+ if(type==CU_BEZIER) { /* to Bezier with vecthandles */
+ nr= nu->pntsu;
+ bezt =
+ (BezTriple*)MEM_callocN(nr * sizeof(BezTriple), "setsplinetype2");
+ nu->bezt= bezt;
+ a= nr;
+ bp= nu->bp;
+ while(a--) {
+ VECCOPY(bezt->vec[1], bp->vec);
+ bezt->f1=bezt->f2=bezt->f3= bp->f1;
+ bezt->h1= bezt->h2= HD_VECT;
+ bezt->weight= bp->weight;
+ bezt->radius= bp->radius;
+ bp++;
+ bezt++;
+ }
+ MEM_freeN(nu->bp);
+ nu->bp= 0;
+ nu->pntsu= nr;
+ nu->type &= ~7;
+ nu->type |= 1;
+ calchandlesNurb(nu);
+ }
+ else if(type==4) { /* to Nurb */
+ nu->type &= ~7;
+ nu->type+= 4;
+ nu->orderu= 4;
+ nu->flagu &= 1;
+ nu->flagu += 4;
+ makeknots(nu, 1, nu->flagu>>1);
+ a= nu->pntsu*nu->pntsv;
+ bp= nu->bp;
+ while(a--) {
+ bp->vec[3]= 1.0;
+ bp++;
+ }
+ }
+ }
+ else if((nu->type & 7)==CU_BEZIER) { /* Bezier */
+ if(type==0 || type==4) { /* to Poly or Nurb */
+ nr= 3*nu->pntsu;
+ nu->bp = MEM_callocN(nr * sizeof(BPoint), "setsplinetype");
+ a= nu->pntsu;
+ bezt= nu->bezt;
+ bp= nu->bp;
+ while(a--) {
+ if(type==0 && bezt->h1==HD_VECT && bezt->h2==HD_VECT) {
+ /* vector handle becomes 1 poly vertice */
+ VECCOPY(bp->vec, bezt->vec[1]);
+ bp->vec[3]= 1.0;
+ bp->f1= bezt->f2;
+ nr-= 2;
+ bp->radius= bezt->radius;
+ bp->weight= bezt->weight;
+ bp++;
+ }
+ else {
+ for(c=0;c<3;c++) {
+ VECCOPY(bp->vec, bezt->vec[c]);
+ bp->vec[3]= 1.0;
+ if(c==0) bp->f1= bezt->f1;
+ else if(c==1) bp->f1= bezt->f2;
+ else bp->f1= bezt->f3;
+ bp->radius= bezt->radius;
+ bp->weight= bezt->weight;
+ bp++;
+ }
+ }
+ bezt++;
+ }
+ MEM_freeN(nu->bezt);
+ nu->bezt= 0;
+ nu->pntsu= nr;
+ nu->pntsv= 1;
+ nu->orderu= 4;
+ nu->orderv= 1;
+ nu->type &= ~7;
+ nu->type+= type;
+ if(nu->flagu & 1) c= nu->orderu-1;
+ else c= 0;
+ if(type== 4) {
+ nu->flagu &= 1;
+ nu->flagu += 4;
+ makeknots(nu, 1, nu->flagu>>1);
+ }
+ }
+ }
+ else if( (nu->type & 7)==CU_NURBS) {
+ if(type==0) { /* to Poly */
+ nu->type &= ~7;
+ if(nu->knotsu) MEM_freeN(nu->knotsu); /* python created nurbs have a knotsu of zero */
+ nu->knotsu= 0;
+ if(nu->knotsv) MEM_freeN(nu->knotsv);
+ nu->knotsv= 0;
+ }
+ else if(type==CU_BEZIER) { /* to Bezier */
+ nr= nu->pntsu/3;
+
+ if(nr<2)
+ return 1; /* conversion impossible */
+ else {
+ bezt = MEM_callocN(nr * sizeof(BezTriple), "setsplinetype2");
+ nu->bezt= bezt;
+ a= nr;
+ bp= nu->bp;
+ while(a--) {
+ VECCOPY(bezt->vec[0], bp->vec);
+ bezt->f1= bp->f1;
+ bp++;
+ VECCOPY(bezt->vec[1], bp->vec);
+ bezt->f2= bp->f1;
+ bp++;
+ VECCOPY(bezt->vec[2], bp->vec);
+ bezt->f3= bp->f1;
+ bezt->radius= bp->radius;
+ bezt->weight= bp->weight;
+ bp++;
+ bezt++;
+ }
+ MEM_freeN(nu->bp);
+ nu->bp= 0;
+ MEM_freeN(nu->knotsu);
+ nu->knotsu= 0;
+ nu->pntsu= nr;
+ nu->type &= ~7;
+ nu->type+= 1;
+ }
+ }
+ }
+ return 0;
+}
+
+void setsplinetype(short type)
+{
+ Nurb *nu;
+
+ if(type==CU_CARDINAL || type==CU_BSPLINE) {
+ error("Not implemented yet");
+ return;
+ }
+
+ for(nu= editNurb.first; nu; nu= nu->next) {
+ if(isNurbsel(nu)) {
+ if (convertspline(type, nu))
+ error("no conversion possible");
+ }
+ }
+ BIF_undo_push("Set spline type");
+
+}
+
+/* ******************** SKINNING LOFTING!!! ******************** */
+
+void rotate_direction_nurb(Nurb *nu)
+{
+ BPoint *bp1, *bp2, *temp;
+ int u, v;
+
+ SWAP(short, nu->pntsu, nu->pntsv);
+ SWAP(short, nu->orderu, nu->orderv);
+ SWAP(short, nu->resolu, nu->resolv);
+ SWAP(short, nu->flagu, nu->flagv);
+
+ SWAP(float *, nu->knotsu, nu->knotsv);
+ switchdirection_knots(nu->knotsv, KNOTSV(nu) );
+
+ temp= MEM_dupallocN(nu->bp);
+ bp1= nu->bp;
+ for(v=0; v<nu->pntsv; v++) {
+ for(u=0; u<nu->pntsu; u++, bp1++) {
+ bp2= temp + (nu->pntsu-u-1)*(nu->pntsv) + v;
+ *bp1= *bp2;
+ }
+ }
+
+ MEM_freeN(temp);
+}
+
+int is_u_selected(Nurb *nu, int u)
+{
+ BPoint *bp;
+ int v;
+
+ /* what about resolu == 2? */
+ bp= nu->bp+u;
+ for(v=0; v<nu->pntsv-1; v++, bp+=nu->pntsu) {
+ if(v) if(bp->f1 & 1) return 1;
+ }
+
+ return 0;
+}
+
+/* ******************************** */
+
+typedef struct NurbSort {
+ struct NurbSort *next, *prev;
+ Nurb *nu;
+ float vec[3];
+} NurbSort;
+
+static ListBase nsortbase= {0, 0};
+/* static NurbSort *nusmain; */ /* this var seems to go unused... at least in this file */
+
+void make_selection_list_nurb()
+{
+ ListBase nbase= {0, 0};
+ NurbSort *nus, *nustest, *headdo, *taildo;
+ Nurb *nu;
+ BPoint *bp;
+ float dist, headdist, taildist;
+ int a;
+
+ for(nu= editNurb.first; nu; nu= nu->next) {
+ if( isNurbsel(nu) ) {
+
+ nus = (NurbSort*)MEM_callocN(sizeof(NurbSort), "sort");
+ BLI_addhead(&nbase, nus);
+ nus->nu= nu;
+
+ bp= nu->bp;
+ a= nu->pntsu;
+ while(a--) {
+ VecAddf(nus->vec, nus->vec, bp->vec);
+ bp++;
+ }
+ VecMulf(nus->vec, 1.0/(float)nu->pntsu);
+
+
+ }
+ }
+
+ /* just add the first one */
+ nus= nbase.first;
+ BLI_remlink(&nbase, nus);
+ BLI_addtail( &nsortbase, nus);
+
+ /* now add, either at head or tail, the closest one */
+ while(nbase.first) {
+
+ headdist= taildist= 1.0e30;
+ headdo= taildo= 0;
+
+ nustest= nbase.first;
+ while(nustest) {
+ dist= VecLenf(nustest->vec, ((NurbSort *)nsortbase.first)->vec);
+
+ if(dist<headdist) {
+ headdist= dist;
+ headdo= nustest;
+ }
+ dist= VecLenf(nustest->vec, ((NurbSort *)nsortbase.last)->vec);
+
+ if(dist<taildist) {
+ taildist= dist;
+ taildo= nustest;
+ }
+ nustest= nustest->next;
+ }
+
+ if(headdist<taildist) {
+ BLI_remlink(&nbase, headdo);
+ BLI_addhead(&nsortbase, headdo);
+ }
+ else {
+ BLI_remlink(&nbase, taildo);
+ BLI_addtail(&nsortbase, taildo);
+ }
+ }
+}
+
+void merge_2_nurb(Nurb *nu1, Nurb *nu2)
+{
+ BPoint *bp, *bp1, *bp2, *temp;
+ float len1, len2;
+ int origu, u, v;
+
+ /* first nurbs will be changed to make u = resolu-1 selected */
+ /* 2nd nurbs will be changed to make u = 0 selected */
+
+ /* first nurbs: u = resolu-1 selected */
+
+ if( is_u_selected(nu1, nu1->pntsu-1) );
+ else {
+ rotate_direction_nurb(nu1);
+ if( is_u_selected(nu1, nu1->pntsu-1) );
+ else {
+ rotate_direction_nurb(nu1);
+ if( is_u_selected(nu1, nu1->pntsu-1) );
+ else {
+ rotate_direction_nurb(nu1);
+ if( is_u_selected(nu1, nu1->pntsu-1) );
+ else {
+ /* rotate again, now its OK! */
+ if(nu1->pntsv!=1) rotate_direction_nurb(nu1);
+ return;
+ }
+ }
+ }
+ }
+
+ /* 2nd nurbs: u = 0 selected */
+ if( is_u_selected(nu2, 0) );
+ else {
+ rotate_direction_nurb(nu2);
+ if( is_u_selected(nu2, 0) );
+ else {
+ rotate_direction_nurb(nu2);
+ if( is_u_selected(nu2, 0) );
+ else {
+ rotate_direction_nurb(nu2);
+ if( is_u_selected(nu2, 0) );
+ else {
+ /* rotate again, now its OK! */
+ if(nu1->pntsu==1) rotate_direction_nurb(nu1);
+ if(nu2->pntsv!=1) rotate_direction_nurb(nu2);
+ return;
+ }
+ }
+ }
+ }
+
+ if( nu1->pntsv != nu2->pntsv ) {
+ error("Resolution doesn't match");
+ return;
+ }
+
+ /* ok, now nu1 has the rightmost collumn and nu2 the leftmost collumn selected */
+ /* maybe we need a 'v' flip of nu2? */
+
+ bp1= nu1->bp+nu1->pntsu-1;
+ bp2= nu2->bp;
+ len1= 0.0;
+
+ for(v=0; v<nu1->pntsv; v++, bp1+=nu1->pntsu, bp2+=nu2->pntsu) {
+ len1+= VecLenf(bp1->vec, bp2->vec);
+ }
+
+ bp1= nu1->bp + nu1->pntsu-1;
+ bp2= nu2->bp + nu2->pntsu*(nu2->pntsv-1);
+ len2= 0.0;
+
+ for(v=0; v<nu1->pntsv; v++, bp1+=nu1->pntsu, bp2-=nu2->pntsu) {
+ len2+= VecLenf(bp1->vec, bp2->vec);
+ }
+
+ /* merge */
+ origu= nu1->pntsu;
+ nu1->pntsu+= nu2->pntsu;
+ nu1->resolu+= nu2->pntsu;
+ if(nu1->resolv < nu2->resolv) nu1->resolv= nu2->resolv;
+ if(nu1->orderu<3) nu1->orderu++;
+ if(nu1->orderv<3) nu1->orderv++;
+ temp= nu1->bp;
+ nu1->bp= MEM_mallocN(nu1->pntsu*nu1->pntsv*sizeof(BPoint), "mergeBP");
+
+ bp= nu1->bp;
+ bp1= temp;
+
+ for(v=0; v<nu1->pntsv; v++) {
+
+ /* switch direction? */
+ if(len1<len2) bp2= nu2->bp + v*nu2->pntsu;
+ else bp2= nu2->bp + (nu1->pntsv-v-1)*nu2->pntsu;
+
+ for(u=0; u<nu1->pntsu; u++, bp++) {
+ if(u<origu) {
+ *bp= *bp1; bp1++;
+ select_bpoint(bp, SELECT, 1, HIDDEN);
+ }
+ else {
+ *bp= *bp2; bp2++;
+ }
+ }
+ }
+
+ if((nu1->type & 7)==4) {
+ /* merge knots */
+ makeknots(nu1, 1, nu1->flagu>>1);
+
+ /* make knots, for merged curved for example */
+ makeknots(nu1, 2, nu1->flagv>>1);
+ }
+
+ MEM_freeN(temp);
+ BLI_remlink(&editNurb, nu2);
+ freeNurb(nu2);
+}
+
+void merge_nurb()
+{
+ NurbSort *nus1, *nus2;
+ int ok= 1;
+
+ make_selection_list_nurb();
+
+ if(nsortbase.first == nsortbase.last) {
+ BLI_freelistN(&nsortbase);
+ error("Too few selections to merge");
+ return;
+ }
+
+ nus1= nsortbase.first;
+ nus2= nus1->next;
+
+ /* resolution match, to avoid uv rotations */
+ if(nus1->nu->pntsv==1) {
+ if(nus1->nu->pntsu==nus2->nu->pntsu || nus1->nu->pntsu==nus2->nu->pntsv);
+ else ok= 0;
+ }
+ else if(nus2->nu->pntsv==1) {
+ if(nus2->nu->pntsu==nus1->nu->pntsu || nus2->nu->pntsu==nus1->nu->pntsv);
+ else ok= 0;
+ }
+ else if( nus1->nu->pntsu==nus2->nu->pntsu || nus1->nu->pntsv==nus2->nu->pntsv);
+ else if( nus1->nu->pntsu==nus2->nu->pntsv || nus1->nu->pntsv==nus2->nu->pntsu);
+ else {
+ ok= 0;
+ }
+
+ if(ok==0) {
+ error("Resolution doesn't match");
+ BLI_freelistN(&nsortbase);
+ return;
+ }
+
+ while(nus2) {
+ merge_2_nurb(nus1->nu, nus2->nu);
+ nus2= nus2->next;
+ }
+
+ BLI_freelistN(&nsortbase);
+
+ countall();
+ lastnu= NULL;
+
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ BIF_undo_push("Merge");
+
+}
+
+
+void addsegment_nurb()
+{
+ /* joins 2 curves */
+ Nurb *nu, *nu1=0, *nu2=0;
+ BezTriple *bezt;
+ BPoint *bp;
+ float *fp, offset;
+ int a;
+
+ /* first decide if this is a surface merge! */
+ if(G.obedit->type==OB_SURF) nu= editNurb.first;
+ else nu= NULL;
+
+ while(nu) {
+ if( isNurbsel(nu) ) {
+
+ if(nu->pntsu>1 && nu->pntsv>1) break;
+ if(isNurbsel_count(nu)>1) break;
+ if(isNurbsel_count(nu)==1) {
+ /* only 1 selected, not first or last, a little complex, but intuitive */
+ if(nu->pntsv==1) {
+ if( (nu->bp->f1 & 1) || ((nu->bp+nu->pntsu-1)->f1 & 1));
+ else break;
+ }
+ }
+ }
+ nu= nu->next;
+ }
+ if(nu) {
+ merge_nurb();
+ return;
+ }
+
+ /* find both nurbs and points, nu1 will be put behind nu2 */
+ for(nu= editNurb.first; nu; nu= nu->next) {
+ if((nu->flagu & 1)==0) { /* not cyclic */
+ if( (nu->type & 7)==CU_BEZIER ) {
+ bezt= nu->bezt;
+ if(nu1==0) {
+ if( BEZSELECTED(bezt) ) nu1= nu;
+ else {
+ bezt= bezt+(nu->pntsu-1);
+ if( BEZSELECTED(bezt) ) {
+ nu1= nu;
+ switchdirectionNurb(nu);
+ }
+ }
+ }
+ else if(nu2==0) {
+ if( BEZSELECTED(bezt) ) {
+ nu2= nu;
+ switchdirectionNurb(nu);
+ }
+ else {
+ bezt= bezt+(nu->pntsu-1);
+ if( BEZSELECTED(bezt) ) {
+ nu2= nu;
+ }
+ }
+ }
+ else break;
+ }
+ else if(nu->pntsv==1) {
+ bp= nu->bp;
+ if(nu1==0) {
+ if( bp->f1 & 1) nu1= nu;
+ else {
+ bp= bp+(nu->pntsu-1);
+ if( bp->f1 & 1 ) {
+ nu1= nu;
+ switchdirectionNurb(nu);
+ }
+ }
+ }
+ else if(nu2==0) {
+ if( bp->f1 & 1) {
+ nu2= nu;
+ switchdirectionNurb(nu);
+ }
+ else {
+ bp= bp+(nu->pntsu-1);
+ if( bp->f1 & 1 ) {
+ nu2= nu;
+ }
+ }
+ }
+ else break;
+ }
+ }
+ }
+
+ if((nu1 && nu2) && (nu1!=nu2)) {
+ if( nu1->type==nu2->type) {
+ if((nu1->type & 7)==CU_BEZIER) {
+ bezt =
+ (BezTriple*)MEM_mallocN((nu1->pntsu+nu2->pntsu) * sizeof(BezTriple), "addsegmentN");
+ memcpy(bezt, nu2->bezt, nu2->pntsu*sizeof(BezTriple));
+ memcpy(bezt+nu2->pntsu, nu1->bezt, nu1->pntsu*sizeof(BezTriple));
+ MEM_freeN(nu1->bezt);
+ nu1->bezt= bezt;
+ nu1->pntsu+= nu2->pntsu;
+ BLI_remlink(&editNurb, nu2);
+ freeNurb(nu2);
+ calchandlesNurb(nu1);
+ }
+ else {
+ bp =
+ (BPoint*)MEM_mallocN((nu1->pntsu+nu2->pntsu) * sizeof(BPoint), "addsegmentN2");
+ memcpy(bp, nu2->bp, nu2->pntsu*sizeof(BPoint) );
+ memcpy(bp+nu2->pntsu, nu1->bp, nu1->pntsu*sizeof(BPoint));
+ MEM_freeN(nu1->bp);
+ nu1->bp= bp;
+
+ a= nu1->pntsu+nu1->orderu;
+
+ nu1->pntsu+= nu2->pntsu;
+ BLI_remlink(&editNurb, nu2);
+
+ /* now join the knots */
+ if((nu1->type & 7)==4) {
+ if(nu1->knotsu==NULL) {
+ makeknots(nu1, 1, nu1->flagu>>1);
+ }
+ else {
+ fp= MEM_mallocN(sizeof(float)*KNOTSU(nu1), "addsegment3");
+ memcpy(fp, nu1->knotsu, sizeof(float)*a);
+ MEM_freeN(nu1->knotsu);
+ nu1->knotsu= fp;
+
+
+ offset= nu1->knotsu[a-1] +1.0;
+ fp= nu1->knotsu+a;
+ for(a=0; a<nu2->pntsu; a++, fp++) {
+ if(nu2->knotsu)
+ *fp= offset+nu2->knotsu[a+1];
+ else
+ *fp = offset;
+ }
+ }
+ }
+ freeNurb(nu2);
+ }
+ }
+
+ lastnu= NULL; /* for selected */
+
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ BIF_undo_push("Add segment");
+
+ }
+ else error("Can't make segment");
+}
+
+void mouse_nurb()
+{
+ Nurb *nu;
+ BezTriple *bezt=0;
+ BPoint *bp=0;
+ short hand;
+
+ hand= findnearestNurbvert(1, &nu, &bezt, &bp);
+
+ if(bezt || bp) {
+ if((G.qual & LR_SHIFTKEY)==0) {
+
+ setflagsNurb(0);
+
+ if(bezt) {
+
+ if(hand==1) select_beztriple(bezt, SELECT, 1, HIDDEN);
+ else if(hand==0) bezt->f1|= 1;
+ else bezt->f3|= 1;
+ }
+ else {
+ lastselbp= bp;
+ select_bpoint(bp, SELECT, 1, HIDDEN);
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ else {
+ if(bezt) {
+ if(hand==1) {
+ if(bezt->f2 & 1) select_beztriple(bezt, DESELECT, 1, HIDDEN);
+ else select_beztriple(bezt, SELECT, 1, HIDDEN);
+ }
+ else if(hand==0) {
+ if(bezt->f1 & 1) {
+ bezt->f1 &= ~1;
+ }
+ else {
+ bezt->f1 |= 1;
+ }
+ }
+ else {
+ if(bezt->f3 & 1) {
+ bezt->f3 &= ~1;
+ }
+ else {
+ bezt->f3 |= 1;
+ }
+ }
+ }
+ else {
+ if(bp->f1 & 1) select_bpoint(bp, DESELECT, 1, HIDDEN);
+ else {
+ select_bpoint(bp, SELECT, 1, HIDDEN);
+ lastselbp= bp;
+ }
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+
+ }
+
+ countall();
+ }
+
+ rightmouse_transform();
+
+ if(nu!=lastnu) {
+ lastnu= nu;
+ allqueue(REDRAWBUTSEDIT, 0);
+ }
+
+}
+
+/* from what I can gather, the mode==0 magic number spins and bridges the nurbs based on the
+ * orientation of the global 3d view (yuck yuck!) mode==1 does the same, but doesn't bridge up
+ * up the new geometry, mode==2 now does the same as 0, but aligned to world axes, not the view.
+*/
+static void spin_nurb(float *dvec, short mode)
+{
+ Nurb *nu;
+ float *curs, si,phi,n[3],q[4],cmat[3][3],tmat[3][3],imat[3][3];
+ float cent[3],bmat[3][3], rotmat[3][3], scalemat1[3][3], scalemat2[3][3];
+ float persmat[3][3], persinv[3][3];
+ short a,ok;
+
+ if(G.vd==0 || G.obedit==0 || G.obedit->type!=OB_SURF) return;
+ if( (G.vd->lay & G.obedit->lay)==0 ) return;
+
+ if (mode != 2) Mat3CpyMat4(persmat, G.vd->viewmat);
+ else Mat3One(persmat);
+ Mat3Inv(persinv, persmat);
+
+ /* imat and center and size */
+ Mat3CpyMat4(bmat, G.obedit->obmat);
+ Mat3Inv(imat, bmat);
+
+ curs= give_cursor();
+ VECCOPY(cent, curs);
+ VecSubf(cent, cent, G.obedit->obmat[3]);
+ Mat3MulVecfl(imat,cent);
+
+ if(dvec || mode==2) {
+ n[0]=n[1]= 0.0;
+ n[2]= 1.0;
+ } else {
+ n[0]= G.vd->viewinv[2][0];
+ n[1]= G.vd->viewinv[2][1];
+ n[2]= G.vd->viewinv[2][2];
+ Normalize(n);
+ }
+
+ phi= M_PI/8.0;
+ q[0]= cos(phi);
+ si= sin(phi);
+ q[1]= n[0]*si;
+ q[2]= n[1]*si;
+ q[3]= n[2]*si;
+ QuatToMat3(q, cmat);
+ Mat3MulMat3(tmat, cmat, bmat);
+ Mat3MulMat3(rotmat, imat, tmat);
+
+ Mat3One(scalemat1);
+ scalemat1[0][0]= sqrt(2.0);
+ scalemat1[1][1]= sqrt(2.0);
+
+ Mat3MulMat3(tmat,persmat,bmat);
+ Mat3MulMat3(cmat,scalemat1,tmat);
+ Mat3MulMat3(tmat,persinv,cmat);
+ Mat3MulMat3(scalemat1,imat,tmat);
+
+ Mat3One(scalemat2);
+ scalemat2[0][0]/= sqrt(2.0);
+ scalemat2[1][1]/= sqrt(2.0);
+
+ Mat3MulMat3(tmat,persmat,bmat);
+ Mat3MulMat3(cmat,scalemat2,tmat);
+ Mat3MulMat3(tmat,persinv,cmat);
+ Mat3MulMat3(scalemat2,imat,tmat);
+
+ ok= 1;
+
+ for(a=0;a<7;a++) {
+ if(mode==0 || mode==2) ok= extrudeflagNurb(1);
+ else adduplicateflagNurb(1);
+ if(ok==0) {
+ error("Can't spin");
+ break;
+ }
+ rotateflagNurb(1,cent,rotmat);
+
+ if(mode==0 || mode==2) {
+ if( (a & 1)==0 ) {
+ rotateflagNurb(1,cent,scalemat1);
+ weightflagNurb(1, 0.25*sqrt(2.0), 1);
+ }
+ else {
+ rotateflagNurb(1,cent,scalemat2);
+ weightflagNurb(1, 4.0/sqrt(2.0), 1);
+ }
+ }
+ if(dvec) {
+ Mat3MulVecfl(bmat,dvec);
+ translateflagNurb(1,dvec);
+ }
+ }
+
+ if(ok) {
+ for(nu= editNurb.first; nu; nu= nu->next) {
+ if(isNurbsel(nu)) {
+ nu->orderv= 4;
+ nu->flagv |= 1;
+ makeknots(nu, 2, nu->flagv>>1);
+ }
+ }
+ }
+
+}
+
+/* external one, for undo */
+void spinNurb(float *dvec, short mode)
+{
+ spin_nurb(dvec, mode);
+ BIF_undo_push("Spin");
+}
+
+void addvert_Nurb(int mode)
+{
+ Nurb *nu;
+ BezTriple *bezt, *newbezt = NULL;
+ BPoint *bp, *newbp = NULL;
+ float *curs, mat[3][3],imat[3][3], temp[3];
+
+ if(G.obedit==0 || G.vd == 0) return;
+ if( (G.vd->lay & G.obedit->lay)==0 ) return;
+
+ Mat3CpyMat4(mat, G.obedit->obmat);
+ Mat3Inv(imat,mat);
+
+ findselectedNurbvert(&nu, &bezt, &bp);
+ if(bezt==0 && bp==0) return;
+
+ if((nu->type & 7)==CU_BEZIER) {
+ /* which bezpoint? */
+ if(bezt== nu->bezt) { /* first */
+ bezt->f1= bezt->f2= bezt->f3= 0;
+ newbezt =
+ (BezTriple*)MEM_callocN((nu->pntsu+1) * sizeof(BezTriple), "addvert_Nurb");
+ memcpy(newbezt+1, bezt, nu->pntsu*sizeof(BezTriple));
+ *newbezt= *bezt;
+ newbezt->f1= newbezt->f2= newbezt->f3= 1;
+ if(newbezt->h1 >= 0) newbezt->h2= newbezt->h1;
+ else newbezt->h2= newbezt->h1= HD_ALIGN; /* does this ever happen? */
+ VECCOPY(temp, bezt->vec[1]);
+ MEM_freeN(nu->bezt);
+ nu->bezt= newbezt;
+ bezt= newbezt+1;
+ }
+ else if(bezt== (nu->bezt+nu->pntsu-1)) { /* last */
+ bezt->f1= bezt->f2= bezt->f3= 0;
+ newbezt =
+ (BezTriple*)MEM_callocN((nu->pntsu+1) * sizeof(BezTriple), "addvert_Nurb");
+ memcpy(newbezt, nu->bezt, nu->pntsu*sizeof(BezTriple));
+ *(newbezt+nu->pntsu)= *bezt;
+ VECCOPY(temp, bezt->vec[1]);
+ MEM_freeN(nu->bezt);
+ nu->bezt= newbezt;
+ newbezt+= nu->pntsu;
+ newbezt->f1= newbezt->f2= newbezt->f3= 1;
+ if(newbezt->h1 >= 0) newbezt->h2= newbezt->h1;
+ else newbezt->h2= newbezt->h1= HD_ALIGN; /* does this ever happen? */
+ bezt= nu->bezt+nu->pntsu-1;
+ }
+ else bezt= 0;
+
+ if(bezt) {
+ nu->pntsu++;
+
+ if(mode=='e') {
+ VECCOPY(newbezt->vec[0], bezt->vec[0]);
+ VECCOPY(newbezt->vec[1], bezt->vec[1]);
+ VECCOPY(newbezt->vec[2], bezt->vec[2]);
+ }
+ else {
+ curs= give_cursor();
+
+ VECCOPY(newbezt->vec[1], curs);
+ VecSubf(newbezt->vec[1],newbezt->vec[1],G.obedit->obmat[3]);
+ Mat3MulVecfl(imat,newbezt->vec[1]);
+ VecSubf(temp, newbezt->vec[1],temp);
+ VecAddf(newbezt->vec[0], bezt->vec[0],temp);
+ VecAddf(newbezt->vec[2], bezt->vec[2],temp);
+ calchandlesNurb(nu);
+ }
+ }
+ }
+ else if(nu->pntsv==1) {
+ /* which b-point? */
+ if(bp== nu->bp) { /* first */
+ bp->f1= 0;
+ newbp =
+ (BPoint*)MEM_callocN((nu->pntsu+1) * sizeof(BPoint), "addvert_Nurb3");
+ memcpy(newbp+1, bp, nu->pntsu*sizeof(BPoint));
+ *newbp= *bp;
+ newbp->f1= 1;
+ MEM_freeN(nu->bp);
+ nu->bp= newbp;
+ bp= newbp + 1;
+ }
+ else if(bp== (nu->bp+nu->pntsu-1)) { /* last */
+ bp->f1= 0;
+ newbp =
+ (BPoint*)MEM_callocN((nu->pntsu+1) * sizeof(BPoint), "addvert_Nurb4");
+ memcpy(newbp, nu->bp, nu->pntsu*sizeof(BPoint));
+ *(newbp+nu->pntsu)= *bp;
+ MEM_freeN(nu->bp);
+ nu->bp= newbp;
+ newbp+= nu->pntsu;
+ newbp->f1= 1;
+ bp= newbp - 1;
+ }
+ else bp= 0;
+
+ if(bp) {
+ nu->pntsu++;
+
+ if(nu->resolu<3) nu->resolu++;
+ makeknots(nu, 1, nu->flagu>>1);
+
+ if(mode=='e') {
+ VECCOPY(newbp->vec, bp->vec);
+ }
+ else {
+ curs= give_cursor();
+
+ VECCOPY(newbp->vec, curs);
+ VecSubf(newbp->vec, newbp->vec, G.obedit->obmat[3]);
+ Mat3MulVecfl(imat,newbp->vec);
+ newbp->vec[3]= 1.0;
+ }
+ }
+ }
+
+ retopo_do_all();
+
+ test2DNurb(nu);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+
+ if(mode=='e') {
+ BIF_TransformSetUndo("Extrude");
+ initTransform(TFM_TRANSLATION, CTX_NO_PET);
+ Transform();
+ }
+ else while(get_mbut()&R_MOUSE) BIF_wait_for_statechange();
+
+ if(mode!='e') {
+ /* dependencies with other objects, should become event */
+ BIF_undo_push("Add vertex");
+
+ }
+}
+
+void extrude_nurb()
+{
+ Nurb *nu;
+ int ok= 0;
+
+ if(G.obedit && G.obedit->type==OB_SURF) {
+
+ /* first test: curve? */
+ for(nu= editNurb.first; nu; nu= nu->next) {
+ if(nu->pntsv==1 && isNurbsel_count(nu)==1 ) break;
+ }
+ if(nu) {
+ addvert_Nurb('e');
+ }
+ else {
+
+
+ ok= extrudeflagNurb(1); /* '1'= flag */
+
+ if(ok) {
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ countall();
+ BIF_TransformSetUndo("Extrude");
+ initTransform(TFM_TRANSLATION, CTX_NO_PET);
+ Transform();
+ }
+ }
+ }
+}
+
+
+
+void makecyclicNurb()
+{
+ Nurb *nu;
+ BezTriple *bezt;
+ BPoint *bp;
+ float *fp;
+ int a, b, cyclmode=0;
+
+ for(nu= editNurb.first; nu; nu= nu->next) {
+ if( nu->pntsu>1 || nu->pntsv>1) {
+ if( (nu->type & 7)==0 ) {
+ a= nu->pntsu;
+ bp= nu->bp;
+ while(a--) {
+ if( bp->f1 & 1 ) {
+ if(nu->flagu & CU_CYCLIC) nu->flagu--;
+ else nu->flagu++;
+ break;
+ }
+ bp++;
+ }
+ }
+ else if( (nu->type & 7)==CU_BEZIER ) {
+ a= nu->pntsu;
+ bezt= nu->bezt;
+ while(a--) {
+ if( BEZSELECTED(bezt) ) {
+ if(nu->flagu & CU_CYCLIC) nu->flagu--;
+ else nu->flagu++;
+ break;
+ }
+ bezt++;
+ }
+ calchandlesNurb(nu);
+ }
+ else if(nu->pntsv==1 && (nu->type & 7)==CU_NURBS) {
+ a= nu->pntsu;
+ bp= nu->bp;
+ while(a--) {
+ if( bp->f1 & 1 ) {
+ if(nu->flagu & CU_CYCLIC) nu->flagu--;
+ else {
+ nu->flagu++;
+ nu->flagu &= ~2; /* endpoint flag, fixme */
+ fp= MEM_mallocN(sizeof(float)*KNOTSU(nu), "makecyclicN");
+ b= (nu->orderu+nu->pntsu);
+ memcpy(fp, nu->knotsu, sizeof(float)*b);
+ MEM_freeN(nu->knotsu);
+ nu->knotsu= fp;
+
+ makeknots(nu, 1, 0); /* 1==u 0==uniform */
+
+ }
+ break;
+ }
+ bp++;
+ }
+ }
+ else if(nu->type==CU_NURBS) {
+ if(cyclmode==0) {
+ cyclmode= pupmenu("Toggle %t|cyclic U%x1|cyclic V%x2");
+ if(cyclmode < 1) return;
+ }
+ a= nu->pntsu*nu->pntsv;
+ bp= nu->bp;
+ while(a--) {
+
+ if( bp->f1 & 1) {
+ if(cyclmode==1 && nu->pntsu>1) {
+ if(nu->flagu & CU_CYCLIC) nu->flagu--;
+ else {
+ nu->flagu++;
+ fp= MEM_mallocN(sizeof(float)*KNOTSU(nu), "makecyclicN");
+ b= (nu->orderu+nu->pntsu);
+ memcpy(fp, nu->knotsu, sizeof(float)*b);
+ MEM_freeN(nu->knotsu);
+ nu->knotsu= fp;
+
+ makeknots(nu, 1, 0); /* 1==u 0==uniform */
+ }
+ }
+ if(cyclmode==2 && nu->pntsv>1) {
+ if(nu->flagv & 1) nu->flagv--;
+ else {
+ nu->flagv++;
+ fp= MEM_mallocN(sizeof(float)*KNOTSV(nu), "makecyclicN");
+ b= (nu->orderv+nu->pntsv);
+ memcpy(fp, nu->knotsv, sizeof(float)*b);
+ MEM_freeN(nu->knotsv);
+ nu->knotsv= fp;
+
+ makeknots(nu, 2, 0); /* 2==v 0==uniform */
+ }
+ }
+ break;
+ }
+ bp++;
+ }
+
+ }
+ }
+ }
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ BIF_undo_push("Cyclic");
+}
+
+void selectconnected_nurb()
+{
+ Nurb *nu;
+ BezTriple *bezt;
+ BPoint *bp;
+ int a;
+
+ findnearestNurbvert(1, &nu, &bezt, &bp);
+ if(bezt) {
+ a= nu->pntsu;
+ bezt= nu->bezt;
+ while(a--) {
+ if(G.qual & LR_SHIFTKEY) select_beztriple(bezt, DESELECT, 1, VISIBLE);
+ else select_beztriple(bezt, SELECT, 1, VISIBLE);
+ bezt++;
+ }
+ }
+ else if(bp) {
+ a= nu->pntsu*nu->pntsv;
+ bp= nu->bp;
+ while(a--) {
+ if(G.qual & LR_SHIFTKEY) select_bpoint(bp, DESELECT, 1, VISIBLE);
+ else select_bpoint(bp, SELECT, 1, VISIBLE);
+ bp++;
+ }
+ }
+
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ BIF_undo_push("Select connected");
+
+}
+
+void selectrow_nurb()
+{
+ static BPoint *last=0;
+ static int direction=0;
+ Nurb *nu;
+ BPoint *bp;
+ int u = 0, v = 0, a, b, ok=0;
+
+ if(editNurb.first==0) return;
+ if(G.obedit==NULL || G.obedit->type!=OB_SURF) return;
+ if(lastselbp==NULL) return;
+
+ /* find the correct nurb and toggle with u of v */
+ for(nu= editNurb.first; nu; nu= nu->next) {
+ bp= nu->bp;
+ for(v=0; v<nu->pntsv; v++) {
+ for(u=0; u<nu->pntsu; u++, bp++) {
+ if(bp==lastselbp) {
+ if(bp->f1 & 1) {
+ ok= 1;
+ break;
+ }
+ }
+ }
+ if(ok) break;
+ }
+ if(ok) {
+ if(last==lastselbp) {
+ direction= 1-direction;
+ setflagsNurb(0);
+ }
+ last= lastselbp;
+
+ bp= nu->bp;
+ for(a=0; a<nu->pntsv; a++) {
+ for(b=0; b<nu->pntsu; b++, bp++) {
+ if(direction) {
+ if(a==v) select_bpoint(bp, SELECT, 1, VISIBLE);
+ }
+ else {
+ if(b==u) select_bpoint(bp, SELECT, 1, VISIBLE);
+ }
+ }
+ }
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ return;
+ }
+ }
+ BIF_undo_push("Select Row");
+
+}
+
+/* (de)selects first or last of visible part of each Nurb depending on selFirst */
+/* selFirst: defines the end of which to select */
+/* doswap: defines if selection state of each first/last control point is swapped */
+/* selstatus: selection status in case doswap is false */
+void selectend_nurb(short selfirst, short doswap, short selstatus)
+{
+ Nurb *nu;
+ BPoint *bp;
+ BezTriple *bezt;
+ int a;
+ short sel;
+
+ if(G.obedit==0) return;
+
+ for(nu= editNurb.first; nu; nu= nu->next) {
+ sel= 0;
+ if((nu->type & 7)==CU_BEZIER) {
+ a= nu->pntsu;
+
+ /* which point? */
+ if(selfirst==0) { /* select last */
+ bezt= (nu->bezt + (a-1));
+ }
+ else { /* select first */
+ bezt= nu->bezt;
+ }
+
+ while(a--) {
+ if(doswap) sel= swap_selection_beztriple(bezt);
+ else sel= select_beztriple(bezt, selstatus, 1, VISIBLE);
+
+ if(sel==1) break;
+ }
+ }
+ else {
+ a= nu->pntsu*nu->pntsv;
+
+ /* which point? */
+ if(selfirst==0) { /* select last */
+ bp= (nu->bp + (a-1));
+ }
+ else{ /* select first */
+ bp= nu->bp;
+ }
+
+ while(a--) {
+ if (bp->hide == 0) {
+ if(doswap) sel= swap_selection_bpoint(bp);
+ else sel= select_bpoint(bp, selstatus, 1, VISIBLE);
+
+ if(sel==1) break;
+ }
+ }
+ }
+ }
+
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ BIF_undo_push("Select/Deselect End");
+}
+
+void select_next_nurb()
+{
+ if(G.obedit==0) return;
+
+ select_adjacent_cp(1, 0, SELECT);
+
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ BIF_undo_push("Select Next");
+}
+
+void select_prev_nurb()
+{
+ if(G.obedit==0) return;
+
+ select_adjacent_cp(-1, 0, SELECT);
+
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ BIF_undo_push("Select Previous");
+}
+
+void select_more_nurb()
+{
+ Nurb *nu;
+ BPoint *bp, *tempbp;
+ int a;
+ short sel= 0;
+ short *selbpoints;
+
+ if(G.obedit==0) return;
+
+ /* note that NURBS surface is a special case because we mimic */
+ /* the behaviour of "select more" of mesh tools. */
+ /* The algorithm is designed to work in planar cases so it */
+ /* may not be optimal always (example: end of NURBS sphere) */
+ if(G.obedit->type==OB_SURF) {
+ for(nu= editNurb.first; nu; nu= nu->next) {
+ a= nu->pntsu*nu->pntsv;
+ bp= nu->bp;
+ selbpoints= MEM_callocN(sizeof(short)*a-nu->pntsu, "selectlist");
+ while(a > 0) {
+ if((selbpoints[a]!=1) && (bp->hide==0) && (bp->f1 & 1)) {
+ /* upper control point */
+ if(a%nu->pntsu != 0) {
+ tempbp= bp-1;
+ if(!(tempbp->f1 & 1)) select_bpoint(tempbp, SELECT, 1, VISIBLE);
+ }
+
+ /* left control point. select only if it is not selected already */
+ if(a-nu->pntsu > 0) {
+ sel= 0;
+ tempbp= bp+nu->pntsu;
+ if(!(tempbp->f1 & 1)) sel= select_bpoint(tempbp, SELECT, 1, VISIBLE);
+ /* make sure selected bpoint is discarded */
+ if(sel == 1) selbpoints[a-nu->pntsu]= 1;
+ }
+
+ /* right control point */
+ if(a+nu->pntsu < nu->pntsu*nu->pntsv) {
+ tempbp= bp-nu->pntsu;
+ if(!(tempbp->f1 & 1)) select_bpoint(tempbp, SELECT, 1, VISIBLE);
+ }
+
+ /* lower control point. skip next bp in case selection was made */
+ if(a%nu->pntsu != 1) {
+ sel= 0;
+ tempbp= bp+1;
+ if(!(tempbp->f1 & 1)) sel= select_bpoint(tempbp, SELECT, 1, VISIBLE);
+ if(sel) {
+ bp++;
+ a--;
+ }
+ }
+ }
+
+ bp++;
+ a--;
+ }
+
+ MEM_freeN(selbpoints);
+ }
+ }
+ else {
+ select_adjacent_cp(1, 0, SELECT);
+ select_adjacent_cp(-1, 0, SELECT);
+ }
+
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ BIF_undo_push("Select More");
+}
+
+/* basic method: deselect if control point doesn't have all neighbours selected */
+void select_less_nurb()
+{
+ Nurb *nu;
+ BPoint *bp;
+ BezTriple *bezt;
+ int a;
+ short sel= 0, lastsel= 0;
+ short *selbpoints;
+
+ if(G.obedit==0) return;
+
+ if(G.obedit->type==OB_SURF) {
+ for(nu= editNurb.first; nu; nu= nu->next) {
+ a= nu->pntsu*nu->pntsv;
+ bp= nu->bp;
+ selbpoints= MEM_callocN(sizeof(short)*a, "selectlist");
+ while(a--) {
+ if((bp->hide==0) && (bp->f1 & 1)) {
+ sel= 0;
+
+ /* check if neighbours have been selected */
+ /* edges of surface are an exception */
+ if((a+1)%nu->pntsu==0) sel++;
+ else {
+ bp--;
+ if((selbpoints[a+1]==1) || ((bp->hide==0) && (bp->f1 & 1))) sel++;
+ bp++;
+ }
+
+ if((a+1)%nu->pntsu==1) sel++;
+ else {
+ bp++;
+ if((bp->hide==0) && (bp->f1 & 1)) sel++;
+ bp--;
+ }
+
+ if(a+1 > nu->pntsu*nu->pntsv-nu->pntsu) sel++;
+ else {
+ bp-=nu->pntsu;
+ if((selbpoints[a+nu->pntsu]==1) || ((bp->hide==0) && (bp->f1 & 1))) sel++;
+ bp+=nu->pntsu;
+ }
+
+ if(a < nu->pntsu) sel++;
+ else {
+ bp+=nu->pntsu;
+ if((bp->hide==0) && (bp->f1 & 1)) sel++;
+ bp-=nu->pntsu;
+ }
+
+ if(sel!=4) {
+ select_bpoint(bp, DESELECT, 1, VISIBLE);
+ selbpoints[a]= 1;
+ }
+ }
+ else lastsel= 0;
+
+ bp++;
+ }
+
+ MEM_freeN(selbpoints);
+ }
+ }
+ else {
+ for(nu= editNurb.first; nu; nu= nu->next) {
+ lastsel=0;
+ /* check what type of curve/nurb it is */
+ if((nu->type & 7)==CU_BEZIER) {
+ a= nu->pntsu;
+ bezt= nu->bezt;
+ while(a--) {
+ if((bezt->hide==0) && (bezt->f2 & 1)) {
+ if(lastsel==1) sel= 1;
+ else sel= 0;
+
+ /* check if neighbours have been selected */
+ /* first and last are exceptions */
+ if(a==nu->pntsu-1) sel++;
+ else {
+ bezt--;
+ if((bezt->hide==0) && (bezt->f2 & 1)) sel++;
+ bezt++;
+ }
+
+ if(a==0) sel++;
+ else {
+ bezt++;
+ if((bezt->hide==0) && (bezt->f2 & 1)) sel++;
+ bezt--;
+ }
+
+ if(sel!=2) {
+ select_beztriple(bezt, DESELECT, 1, VISIBLE);
+ lastsel= 1;
+ }
+ else lastsel= 0;
+ }
+ else lastsel= 0;
+
+ bezt++;
+ }
+ }
+ else {
+ a= nu->pntsu*nu->pntsv;
+ bp= nu->bp;
+ while(a--) {
+ if((lastsel==0) && (bp->hide==0) && (bp->f1 & 1)) {
+ if(lastsel!=0) sel= 1;
+ else sel= 0;
+
+ /* first and last are exceptions */
+ if(a==nu->pntsu*nu->pntsv-1) sel++;
+ else {
+ bp--;
+ if((bp->hide==0) && (bp->f1 & 1)) sel++;
+ bp++;
+ }
+
+ if(a==0) sel++;
+ else {
+ bp++;
+ if((bp->hide==0) && (bp->f1 & 1)) sel++;
+ bp--;
+ }
+
+ if(sel!=2) {
+ select_bpoint(bp, DESELECT, 1, VISIBLE);
+ lastsel= 1;
+ }
+ else lastsel= 0;
+ }
+ else lastsel= 0;
+
+ bp++;
+ }
+ }
+ }
+ }
+
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ BIF_undo_push("Select Less");
+}
+
+/* this function could be moved elsewhere as it can be reused in other parts of the source needing randomized list */
+/* returns list containing -1 in indices that have been left out of the list. otherwise index contains reference */
+/* to next index. basically *list contains a linked list */
+static void generate_pickable_list(int *list, int size, int pickamount)
+{
+ int i, j, removable;
+
+ BLI_srand( BLI_rand() ); /* random seed */
+
+ /* generate list in form 0->1, 1->2, 2->3, ... i-2->i-1, i->0 */
+ for(i=0; i<size; i++) {
+ if(i == size-1) list[i]= 0;
+ else list[i]= i+1;
+ }
+
+ for(i=0; i<size-pickamount; i++) {
+ removable= floor(BLI_frand()*(size-1)+0.5); /* with rounding. frand returns [0,1] */
+
+ /* seek proper item as the one randomly selected might not be appropriate */
+ for(j=0; j<size; j++, removable++) {
+ if(list[removable] != -1) break;
+ if(removable == size-1) removable= -1;
+ }
+
+ /* pick unwanted item out of the list */
+ list[list[removable]]= -1; /* mark former last as invalid */
+
+ if(list[removable] == size-1) list[removable]= 0;
+ else list[removable]= list[removable]+1;
+ }
+}
+
+void select_random_nurb()
+{
+ Nurb *nu;
+ BezTriple *bezt;
+ BPoint *bp;
+ static short randfac= 50;
+ int amounttoselect, amountofcps, a, i, k= 0;
+ int *itemstobeselected;
+
+ if(!G.obedit) return;
+
+ if(!button(&randfac,0, 100,"Percentage:")) return;
+
+ if(randfac == 0) return;
+
+ amountofcps= count_curveverts_without_handles(&editNurb);
+ itemstobeselected= MEM_callocN(sizeof(int) * amountofcps, "selectitems");
+ amounttoselect= floor(randfac * amountofcps / 100 + 0.5);
+ generate_pickable_list(itemstobeselected, amountofcps, amounttoselect);
+
+ /* select elements */
+ for(i=1, nu= editNurb.first; nu; nu= nu->next) {
+ if((nu->type & 7)==CU_BEZIER) {
+ bezt= nu->bezt;
+ a= nu->pntsu;
+ while(a--) {
+ if(itemstobeselected[k] != -1) select_beztriple(bezt, SELECT, 1, VISIBLE);
+ k++;
+ bezt++;
+ }
+ }
+ else {
+ bp= nu->bp;
+ a= nu->pntsu*nu->pntsv;
+ while(a--) {
+ if(itemstobeselected[k] != -1) select_bpoint(bp, SELECT, 1, VISIBLE);
+ k++;
+ bp++;
+ }
+ }
+ }
+
+ MEM_freeN(itemstobeselected);
+
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ BIF_undo_push("Select Random");
+}
+
+void select_every_nth_nurb()
+{
+ static short nfac= 2;
+
+ if(!G.obedit) return;
+
+ if(!button(&nfac, 2, 25,"N:")) return;
+
+ select_adjacent_cp(nfac, 1, SELECT);
+ select_adjacent_cp(-nfac, 1, SELECT);
+
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ BIF_undo_push("Select Every Nth");
+}
+
+void adduplicate_nurb()
+{
+
+ if(G.vd==0 || (G.vd->lay & G.obedit->lay)==0 ) return;
+
+ adduplicateflagNurb(1);
+
+ countall();
+ BIF_TransformSetUndo("Add Duplicate");
+ initTransform(TFM_TRANSLATION, CTX_NO_PET);
+ Transform();
+}
+
+void delNurb()
+{
+ Nurb *nu, *next, *nu1;
+ BezTriple *bezt, *bezt1, *bezt2;
+ BPoint *bp, *bp1, *bp2;
+ int a;
+ short event, cut = 0;
+
+ if(G.obedit==0 ) return;
+ if(G.vd==0 || (G.vd->lay & G.obedit->lay)==0 ) return;
+
+ if(G.obedit->type==OB_SURF) event= pupmenu("Erase %t|Selected%x0|All%x2");
+ else event= pupmenu("Erase %t|Selected%x0|Segment%x1|All%x2");
+
+ if(event== -1) return;
+
+ if(G.obedit->type==OB_SURF) {
+ if(event==0) deleteflagNurb(1);
+ else freeNurblist(&editNurb);
+
+ countall();
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ BIF_undo_push("Delete");
+
+ return;
+ }
+
+ if(event==0) {
+ /* first loop, can we remove entire pieces? */
+ nu= editNurb.first;
+ while(nu) {
+ next= nu->next;
+ if( (nu->type & 7)==CU_BEZIER ) {
+ bezt= nu->bezt;
+ a= nu->pntsu;
+ if(a) {
+ while(a) {
+ if( BEZSELECTED(bezt) );
+ else break;
+ a--;
+ bezt++;
+ }
+ if(a==0) {
+ BLI_remlink(&editNurb, nu);
+ freeNurb(nu);
+ }
+ }
+ }
+ else {
+ bp= nu->bp;
+ a= nu->pntsu*nu->pntsv;
+ if(a) {
+ while(a) {
+ if(bp->f1 & 1 );
+ else break;
+ a--;
+ bp++;
+ }
+ if(a==0) {
+ BLI_remlink(&editNurb, nu);
+ freeNurb(nu);
+ }
+ }
+ }
+ nu= next;
+ }
+ /* 2nd loop, delete small pieces: just for curves */
+ nu= editNurb.first;
+ while(nu) {
+ next= nu->next;
+ event= 0;
+ if( (nu->type & 7)==CU_BEZIER ) {
+ bezt= nu->bezt;
+ for(a=0;a<nu->pntsu;a++) {
+ if( BEZSELECTED(bezt) ) {
+ memcpy(bezt, bezt+1, (nu->pntsu-a-1)*sizeof(BezTriple));
+ nu->pntsu--;
+ a--;
+ event= 1;
+ }
+ else bezt++;
+ }
+ if(event) {
+ bezt1 =
+ (BezTriple*)MEM_mallocN((nu->pntsu) * sizeof(BezTriple), "delNurb");
+ memcpy(bezt1, nu->bezt, (nu->pntsu)*sizeof(BezTriple) );
+ MEM_freeN(nu->bezt);
+ nu->bezt= bezt1;
+ calchandlesNurb(nu);
+ }
+ }
+ else if(nu->pntsv==1) {
+ bp= nu->bp;
+
+ for(a=0;a<nu->pntsu;a++) {
+ if( bp->f1 & 1 ) {
+ memcpy(bp, bp+1, (nu->pntsu-a-1)*sizeof(BPoint));
+ nu->pntsu--;
+ a--;
+ event= 1;
+ }
+ else {
+ bp++;
+ }
+ }
+ if(event) {
+ bp1 = (BPoint*)MEM_mallocN(nu->pntsu * sizeof(BPoint), "delNurb2");
+ memcpy(bp1, nu->bp, (nu->pntsu)*sizeof(BPoint) );
+ MEM_freeN(nu->bp);
+ nu->bp= bp1;
+ }
+ makeknots(nu, 1, nu->flagu>>1);
+ }
+ nu= next;
+ }
+ }
+ else if(event==1) { /* erase segment */
+ /* find the 2 selected points */
+ bezt1= bezt2= 0;
+ bp1= bp2= 0;
+ nu= editNurb.first;
+ nu1= 0;
+ while(nu) {
+ next= nu->next;
+ if( (nu->type & 7)==CU_BEZIER ) {
+ bezt= nu->bezt;
+ for(a=0; a<nu->pntsu-1; a++) {
+ if( BEZSELECTED(bezt) ) {
+ bezt1= bezt;
+ bezt2= bezt+1;
+ if( (bezt2->f1 & 1) || (bezt2->f2 & 1) || (bezt2->f3 & 1) ) ;
+ else { /* maybe do not make cyclic */
+ if(a==0 && (nu->flagu & 1) ) {
+ bezt2= bezt+(nu->pntsu-1);
+ if( (bezt2->f1 & 1) || (bezt2->f2 & 1) || (bezt2->f3 & 1) ) {
+ nu->flagu--;
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ BIF_undo_push("Delete");
+ }
+ }
+ return;
+ }
+ cut= a;
+ nu1= nu;
+ break;
+ }
+ bezt++;
+ }
+ }
+ else if(nu->pntsv==1) {
+ bp= nu->bp;
+ for(a=0; a<nu->pntsu-1; a++) {
+ if( bp->f1 & 1 ) {
+ bp1= bp;
+ bp2= bp+1;
+ if( bp2->f1 & 1 ) ;
+ else { /* maybe do not make cyclic */
+ if(a==0 && (nu->flagu & 1) ) {
+ bp2= bp+(nu->pntsu-1);
+ if( bp2->f1 & 1 ) {
+ nu->flagu--;
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ BIF_undo_push("Delete");
+ }
+ }
+ return;
+ }
+ cut= a;
+ nu1= nu;
+ break;
+ }
+ bp++;
+ }
+ }
+ if(nu1) break;
+
+ nu= nu->next;
+ }
+ if(nu1) {
+ if(bezt1) {
+ if(nu1->pntsu==2) { /* remove completely */
+ BLI_remlink(&editNurb, nu);
+ freeNurb(nu);
+ }
+ else if(nu1->flagu & 1) { /* cyclic */
+ bezt =
+ (BezTriple*)MEM_mallocN((cut+1) * sizeof(BezTriple), "delNurb1");
+ memcpy(bezt, nu1->bezt,(cut+1)*sizeof(BezTriple));
+ a= nu1->pntsu-cut-1;
+ memcpy(nu1->bezt, bezt2, a*sizeof(BezTriple));
+ memcpy(nu1->bezt+a, bezt, (cut+1)*sizeof(BezTriple));
+ nu1->flagu--;
+ MEM_freeN(bezt);
+ calchandlesNurb(nu);
+ }
+ else { /* add new curve */
+
+/* seems to be an error here... but where? (a can become zero) */
+
+ nu =
+ (Nurb*)MEM_mallocN(sizeof(Nurb), "delNurb2");
+ memcpy(nu, nu1, sizeof(Nurb));
+ BLI_addtail(&editNurb, nu);
+ nu->bezt =
+ (BezTriple*)MEM_mallocN((cut+1) * sizeof(BezTriple), "delNurb3");
+ memcpy(nu->bezt, nu1->bezt,(cut+1)*sizeof(BezTriple));
+ a= nu1->pntsu-cut-1;
+
+ bezt =
+ (BezTriple*)MEM_mallocN(a * sizeof(BezTriple), "delNurb4");
+ memcpy(bezt, nu1->bezt+cut+1,a*sizeof(BezTriple));
+ MEM_freeN(nu1->bezt);
+ nu1->bezt= bezt;
+ nu1->pntsu= a;
+ nu->pntsu= cut+1;
+
+
+ calchandlesNurb(nu);
+ calchandlesNurb(nu1);
+ }
+ }
+ else if(bp1) {
+ if(nu1->pntsu==2) { /* remove completely */
+ BLI_remlink(&editNurb, nu);
+ freeNurb(nu);
+ }
+ else if(nu1->flagu & 1) { /* cyclic */
+ bp =
+ (BPoint*)MEM_mallocN((cut+1) * sizeof(BPoint), "delNurb5");
+ memcpy(bp, nu1->bp,(cut+1)*sizeof(BPoint));
+ a= nu1->pntsu-cut-1;
+ memcpy(nu1->bp, bp2, a*sizeof(BPoint));
+ memcpy(nu1->bp+a, bp, (cut+1)*sizeof(BPoint));
+ nu1->flagu--;
+ MEM_freeN(bp);
+ }
+ else { /* add new curve */
+ nu = (Nurb*)MEM_mallocN(sizeof(Nurb), "delNurb6");
+ memcpy(nu, nu1, sizeof(Nurb));
+ BLI_addtail(&editNurb, nu);
+ nu->bp =
+ (BPoint*)MEM_mallocN((cut+1) * sizeof(BPoint), "delNurb7");
+ memcpy(nu->bp, nu1->bp,(cut+1)*sizeof(BPoint));
+ a= nu1->pntsu-cut-1;
+ bp =
+ (BPoint*)MEM_mallocN(a * sizeof(BPoint), "delNurb8");
+ memcpy(bp, nu1->bp+cut+1,a*sizeof(BPoint));
+ MEM_freeN(nu1->bp);
+ nu1->bp= bp;
+ nu1->pntsu= a;
+ nu->pntsu= cut+1;
+ }
+ }
+ }
+ }
+ else if(event==2) {
+ freeNurblist(&editNurb);
+ }
+
+ countall();
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ BIF_undo_push("Delete");
+
+}
+
+void nurb_set_smooth(short event)
+{
+ Nurb *nu;
+
+ if(G.obedit==0) return;
+
+ if(G.obedit->type != OB_CURVE) return;
+
+ for(nu= editNurb.first; nu; nu= nu->next) {
+ if(isNurbsel(nu)) {
+ if(event==1) nu->flag |= CU_SMOOTH;
+ else if(event==0) nu->flag &= ~CU_SMOOTH;
+ }
+ }
+
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+
+ if(event==1) BIF_undo_push("Set Smooth");
+ else if(event==0) BIF_undo_push("Set Solid");
+}
+
+int join_curve(int type)
+{
+ Base *base, *nextb;
+ Object *ob;
+ Curve *cu;
+ Nurb *nu, *newnu;
+ BezTriple *bezt;
+ BPoint *bp;
+ ListBase tempbase;
+ float imat[4][4], cmat[4][4];
+ int a;
+
+ ob= OBACT;
+ if (object_data_is_libdata(ob)) {
+ error_libdata();
+ return 0;
+ }
+
+ if(!G.vd || ob->type!=type) return 0;
+ if(ob->lay & G.vd->lay); else return 0;
+ tempbase.first= tempbase.last= 0;
+
+ /* trasnform all selected curves inverse in obact */
+ Mat4Invert(imat, ob->obmat);
+
+ base= FIRSTBASE;
+ while(base) {
+ nextb= base->next;
+ if TESTBASE(base) {
+ if(base->object->type==type) {
+ if(base->object != ob) {
+
+ cu= base->object->data;
+
+ if(cu->nurb.first) {
+ /* watch it: switch order here really goes wrong */
+ Mat4MulMat4(cmat, base->object->obmat, imat);
+
+ nu= cu->nurb.first;
+ while(nu) {
+ newnu= duplicateNurb(nu);
+ BLI_addtail(&tempbase, newnu);
+
+ if( (bezt= newnu->bezt) ) {
+ a= newnu->pntsu;
+ while(a--) {
+ Mat4MulVecfl(cmat, bezt->vec[0]);
+ Mat4MulVecfl(cmat, bezt->vec[1]);
+ Mat4MulVecfl(cmat, bezt->vec[2]);
+ bezt++;
+ }
+ }
+ if( (bp= newnu->bp) ) {
+ a= newnu->pntsu*nu->pntsv;
+ while(a--) {
+ Mat4MulVecfl(cmat, bp->vec);
+ bp++;
+ }
+ }
+ nu= nu->next;
+ }
+ }
+
+ free_and_unlink_base(base);
+ }
+ }
+ }
+ base= nextb;
+ }
+
+ cu= ob->data;
+ addlisttolist(&cu->nurb, &tempbase);
+
+ DAG_scene_sort(G.scene); // because we removed object(s), call before editmode!
+
+ enter_editmode(EM_WAITCURSOR);
+ exit_editmode(EM_FREEDATA|EM_WAITCURSOR);
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ BIF_undo_push("Join");
+ return 1;
+}
+
+
+
+Nurb *addNurbprim(int type, int stype, int newname)
+/* type: &8= 2D; 0=poly,1 bez, 4 nurb
+ * stype: 0: 2/4 points curve
+ * 1: 8 points circle
+ * 2: 4x4 patch Nurb
+ * 3: tube 4:sphere 5:donut
+ * 6: 5 points, 5th order straight line (for anim path)
+ */
+{
+ static int xzproj= 0;
+ Nurb *nu = NULL;
+ BezTriple *bezt;
+ BPoint *bp;
+ float *curs, cent[3],vec[3],imat[3][3],mat[3][3];
+ float fac,cmat[3][3], grid;
+ int a, b;
+
+ if (G.vd) grid = G.vd->grid;
+ else grid = 1.0;
+
+ /* imat and center and size */
+ if(G.obedit) {
+
+ Mat3CpyMat4(mat, G.obedit->obmat);
+ curs= give_cursor();
+ VECCOPY(cent, curs);
+ cent[0]-= G.obedit->obmat[3][0];
+ cent[1]-= G.obedit->obmat[3][1];
+ cent[2]-= G.obedit->obmat[3][2];
+
+ if (G.vd) {
+ if ( !(newname) || U.flag & USER_ADD_VIEWALIGNED) Mat3CpyMat4(imat, G.vd->viewmat);
+ else Mat3One(imat);
+ Mat3MulVecfl(imat, cent);
+ Mat3MulMat3(cmat, imat, mat);
+ Mat3Inv(imat, cmat);
+ }
+ setflagsNurb(0);
+ }
+ else {
+ Mat3One(imat);
+ cent[0]= cent[1]= cent[2]= 0.0;
+ }
+
+ if ELEM5(stype, 0, 1, 2, 4, 6) {
+ nu = (Nurb*)MEM_callocN(sizeof(Nurb), "addNurbprim");
+ nu->type= type;
+ nu->resolu= 12;
+ nu->resolv= 12;
+ }
+
+ switch(stype) {
+ case 0: /* curve */
+ if(newname) {
+ rename_id((ID *)G.obedit, "Curve");
+ rename_id((ID *)G.obedit->data, "Curve");
+ }
+ if((type & 7)==CU_BEZIER) {
+ nu->pntsu= 2;
+ nu->bezt =
+ (BezTriple*)MEM_callocN(2 * sizeof(BezTriple), "addNurbprim1");
+ bezt= nu->bezt;
+ bezt->h1= bezt->h2= HD_ALIGN;
+ bezt->f1= bezt->f2= bezt->f3= 1;
+ bezt->radius = 1.0;
+
+ for(a=0;a<3;a++) {
+ VECCOPY(bezt->vec[a], cent);
+ }
+ bezt->vec[1][0]+= -grid;
+ bezt->vec[0][0]+= -1.5*grid;
+ bezt->vec[0][1]+= -0.5*grid;
+ bezt->vec[2][0]+= -0.5*grid;
+ bezt->vec[2][1]+= 0.5*grid;
+ for(a=0;a<3;a++) Mat3MulVecfl(imat, bezt->vec[a]);
+
+ bezt++;
+ bezt->h1= bezt->h2= HD_ALIGN;
+ bezt->f1= bezt->f2= bezt->f3= 1;
+ bezt->radius = bezt->weight = 1.0;
+
+ for(a=0;a<3;a++) {
+ VECCOPY(bezt->vec[a], cent);
+ }
+ bezt->vec[1][0]+= grid;
+ for(a=0;a<3;a++) Mat3MulVecfl(imat, bezt->vec[a]);
+
+ calchandlesNurb(nu);
+ }
+ else {
+
+ nu->pntsu= 4;
+ nu->pntsv= 1;
+ nu->orderu= 4;
+ nu->bp= callocstructN(BPoint, 4, "addNurbprim3");
+
+ bp= nu->bp;
+ for(a=0;a<4;a++, bp++) {
+ VECCOPY(bp->vec, cent);
+ bp->vec[3]= 1.0;
+ bp->f1= 1;
+ bp->radius = bp->weight = 1.0;
+ }
+
+ bp= nu->bp;
+ bp->vec[0]+= -1.5*grid;
+ bp++;
+ bp->vec[0]+= -grid;
+ bp->vec[1]+= grid;
+ bp++;
+ bp->vec[0]+= grid;
+ bp->vec[1]+= grid;
+ bp++;
+ bp->vec[0]+= 1.5*grid;
+
+ bp= nu->bp;
+ for(a=0;a<4;a++, bp++) Mat3MulVecfl(imat,bp->vec);
+
+ if((type & 7)==4) {
+ nu->knotsu= 0; /* makeknots allocates */
+ makeknots(nu, 1, nu->flagu>>1);
+ }
+
+ }
+ break;
+ case 6: /* 5 point path */
+ nu->pntsu= 5;
+ nu->pntsv= 1;
+ nu->orderu= 5;
+ nu->flagu= 2; /* endpoint */
+ nu->resolu= 32;
+ nu->bp= callocstructN(BPoint, 5, "addNurbprim3");
+
+ bp= nu->bp;
+ for(a=0;a<5;a++, bp++) {
+ VECCOPY(bp->vec, cent);
+ bp->vec[3]= 1.0;
+ bp->f1= 1;
+ bp->radius = bp->weight = 1.0;
+ }
+
+ bp= nu->bp;
+ bp->vec[0]+= -2.0*grid;
+ bp++;
+ bp->vec[0]+= -grid;
+ bp++; bp++;
+ bp->vec[0]+= grid;
+ bp++;
+ bp->vec[0]+= 2.0*grid;
+
+ bp= nu->bp;
+ for(a=0;a<5;a++, bp++) Mat3MulVecfl(imat,bp->vec);
+
+ if((type & 7)==4) {
+ nu->knotsu= 0; /* makeknots allocates */
+ makeknots(nu, 1, nu->flagu>>1);
+ }
+
+ break;
+ case 1: /* circle */
+ if(newname) {
+ rename_id((ID *)G.obedit, "CurveCircle");
+ rename_id((ID *)G.obedit->data, "CurveCircle");
+ }
+ if((type & 7)==CU_BEZIER) {
+ nu->pntsu= 4;
+ nu->bezt= callocstructN(BezTriple, 4, "addNurbprim1");
+ nu->flagu= 1;
+ bezt= nu->bezt;
+
+ for(a=0;a<3;a++) {
+ VECCOPY(bezt->vec[a], cent);
+ }
+ bezt->h1= bezt->h2= HD_AUTO;
+ bezt->f1= bezt->f2= bezt->f3= 1;
+ bezt->vec[1][0]+= -grid;
+ for(a=0;a<3;a++) Mat3MulVecfl(imat,bezt->vec[a]);
+ bezt->radius = bezt->weight = 1.0;
+
+ bezt++;
+ for(a=0;a<3;a++) {
+ VECCOPY(bezt->vec[a], cent);
+ }
+ bezt->h1= bezt->h2= HD_AUTO;
+ bezt->f1= bezt->f2= bezt->f3= 1;
+ bezt->vec[1][1]+= grid;
+ for(a=0;a<3;a++) Mat3MulVecfl(imat,bezt->vec[a]);
+ bezt->radius = bezt->weight = 1.0;
+
+ bezt++;
+ for(a=0;a<3;a++) {
+ VECCOPY(bezt->vec[a], cent);
+ }
+ bezt->h1= bezt->h2= HD_AUTO;
+ bezt->f1= bezt->f2= bezt->f3= 1;
+ bezt->vec[1][0]+= grid;
+ for(a=0;a<3;a++) Mat3MulVecfl(imat,bezt->vec[a]);
+ bezt->radius = bezt->weight = 1.0;
+
+ bezt++;
+ for(a=0;a<3;a++) {
+ VECCOPY(bezt->vec[a], cent);
+ }
+ bezt->h1= bezt->h2= HD_AUTO;
+ bezt->f1= bezt->f2= bezt->f3= 1;
+ bezt->vec[1][1]+= -grid;
+ for(a=0;a<3;a++) Mat3MulVecfl(imat,bezt->vec[a]);
+ bezt->radius = bezt->weight = 1.0;
+
+ calchandlesNurb(nu);
+ }
+ else if( (type & 7)==CU_NURBS ) { /* nurb */
+ nu->pntsu= 8;
+ nu->pntsv= 1;
+ nu->orderu= 4;
+ nu->bp= callocstructN(BPoint, 8, "addNurbprim6");
+ nu->flagu= 1;
+ bp= nu->bp;
+
+ for(a=0; a<8; a++) {
+ bp->f1= 1;
+ VECCOPY(bp->vec, cent);
+
+ if(xzproj==0) {
+ bp->vec[0]+= nurbcircle[a][0]*grid;
+ bp->vec[1]+= nurbcircle[a][1]*grid;
+ }
+ else {
+ bp->vec[0]+= 0.25*nurbcircle[a][0]*grid-.75*grid;
+ bp->vec[2]+= 0.25*nurbcircle[a][1]*grid;
+ }
+ if(a & 1) bp->vec[3]= 0.25*sqrt(2.0);
+ else bp->vec[3]= 1.0;
+ Mat3MulVecfl(imat,bp->vec);
+ bp->radius = bp->weight = 1.0;
+
+ bp++;
+ }
+
+ makeknots(nu, 1, nu->flagu>>1);
+ }
+ break;
+ case 2: /* 4x4 patch */
+ if( (type & 7)==CU_NURBS ) { /* nurb */
+ if(newname) {
+ rename_id((ID *)G.obedit, "Surf");
+ rename_id((ID *)G.obedit->data, "Surf");
+ }
+
+ nu->pntsu= 4;
+ nu->pntsv= 4;
+ nu->orderu= 4;
+ nu->orderv= 4;
+ nu->flag= CU_SMOOTH;
+ nu->bp= callocstructN(BPoint, 4*4, "addNurbprim6");
+ nu->flagu= 0;
+ nu->flagv= 0;
+ bp= nu->bp;
+
+ for(a=0; a<4; a++) {
+ for(b=0; b<4; b++) {
+ VECCOPY(bp->vec, cent);
+ bp->f1= 1;
+ fac= (float)a -1.5;
+ bp->vec[0]+= fac*grid;
+ fac= (float)b -1.5;
+ bp->vec[1]+= fac*grid;
+ if(a==1 || a==2) if(b==1 || b==2) {
+ bp->vec[2]+= grid;
+ }
+ Mat3MulVecfl(imat,bp->vec);
+ bp->vec[3]= 1.0;
+ bp++;
+ }
+ }
+
+ makeknots(nu, 1, nu->flagu>>1);
+ makeknots(nu, 2, nu->flagv>>1);
+ }
+ break;
+ case 3: /* tube */
+ if( (type & 7)==CU_NURBS ) {
+ if(newname) {
+ rename_id((ID *)G.obedit, "SurfTube");
+ rename_id((ID *)G.obedit->data, "SurfTube");
+ }
+
+ nu= addNurbprim(4, 1, newname); /* circle */
+ nu->resolu= 32;
+ nu->flag= CU_SMOOTH;
+ BLI_addtail(&editNurb, nu); /* temporal for extrude and translate */
+ vec[0]=vec[1]= 0.0;
+ vec[2]= -grid;
+ Mat3MulVecfl(imat, vec);
+ translateflagNurb(1, vec);
+ extrudeflagNurb(1);
+ vec[0]= -2*vec[0];
+ vec[1]= -2*vec[1];
+ vec[2]= -2*vec[2];
+ translateflagNurb(1, vec);
+
+ BLI_remlink(&editNurb, nu);
+
+ a= nu->pntsu*nu->pntsv;
+ bp= nu->bp;
+ while(a-- >0) {
+ bp->f1 |= 1;
+ bp++;
+ }
+ }
+ break;
+ case 4: /* sphere */
+ if( (type & 7)==CU_NURBS ) {
+ if(newname) {
+ rename_id((ID *)G.obedit, "SurfSphere");
+ rename_id((ID *)G.obedit->data, "SurfSphere");
+ }
+
+ nu->pntsu= 5;
+ nu->pntsv= 1;
+ nu->orderu= 3;
+ nu->resolu= 24;
+ nu->resolv= 32;
+ nu->flag= CU_SMOOTH;
+ nu->bp= callocstructN(BPoint, 5, "addNurbprim6");
+ nu->flagu= 0;
+ bp= nu->bp;
+
+ for(a=0; a<5; a++) {
+ bp->f1= 1;
+ VECCOPY(bp->vec, cent);
+ bp->vec[0]+= nurbcircle[a][0]*grid;
+ bp->vec[2]+= nurbcircle[a][1]*grid;
+ if(a & 1) bp->vec[3]= 0.5*sqrt(2.0);
+ else bp->vec[3]= 1.0;
+ Mat3MulVecfl(imat,bp->vec);
+ bp++;
+ }
+ nu->flagu= 4;
+ makeknots(nu, 1, nu->flagu>>1);
+
+ BLI_addtail(&editNurb, nu); /* temporal for spin */
+ if(newname) spin_nurb(0, 2);
+ else spin_nurb(0, 0);
+
+ makeknots(nu, 2, nu->flagv>>1);
+
+ a= nu->pntsu*nu->pntsv;
+ bp= nu->bp;
+ while(a-- >0) {
+ bp->f1 |= 1;
+ bp++;
+ }
+ BLI_remlink(&editNurb, nu);
+ }
+ break;
+ case 5: /* donut */
+ if( (type & 7)==CU_NURBS ) {
+ if(newname) {
+ rename_id((ID *)G.obedit, "SurfDonut");
+ rename_id((ID *)G.obedit->data, "SurfDonut");
+ }
+
+ xzproj= 1;
+ nu= addNurbprim(4, 1, newname); /* circle */
+ xzproj= 0;
+ nu->resolu= 24;
+ nu->resolv= 32;
+ nu->flag= CU_SMOOTH;
+ BLI_addtail(&editNurb, nu); /* temporal for extrude and translate */
+ if(newname) spin_nurb(0, 2);
+ else spin_nurb(0, 0);
+
+ BLI_remlink(&editNurb, nu);
+
+ a= nu->pntsu*nu->pntsv;
+ bp= nu->bp;
+ while(a-- >0) {
+ bp->f1 |= 1;
+ bp++;
+ }
+
+ }
+ break;
+ }
+
+ /* always do: */
+ nu->flag= CU_SMOOTH;
+
+ test2DNurb(nu);
+
+ return nu;
+}
+
+void default_curve_ipo(Curve *cu)
+{
+ IpoCurve *icu;
+ BezTriple *bezt;
+
+ if(cu->ipo) return;
+
+ cu->ipo= add_ipo("CurveIpo", ID_CU);
+
+ icu= MEM_callocN(sizeof(IpoCurve), "ipocurve");
+
+ icu->blocktype= ID_CU;
+ icu->adrcode= CU_SPEED;
+ icu->flag= IPO_VISIBLE|IPO_SELECT|IPO_AUTO_HORIZ;
+ set_icu_vars(icu);
+
+ BLI_addtail( &(cu->ipo->curve), icu);
+
+ icu->bezt= bezt= MEM_callocN(2*sizeof(BezTriple), "defaultipo");
+ icu->totvert= 2;
+
+ bezt->hide= IPO_BEZ;
+ bezt->f1=bezt->f2= bezt->f3= SELECT;
+ bezt->h1= bezt->h2= HD_AUTO;
+ bezt++;
+ bezt->vec[1][0]= 100.0;
+ bezt->vec[1][1]= 1.0;
+ bezt->hide= IPO_BEZ;
+ bezt->f1=bezt->f2= bezt->f3= SELECT;
+ bezt->h1= bezt->h2= HD_AUTO;
+
+ calchandles_ipocurve(icu);
+}
+
+void add_primitiveCurve(int stype)
+{
+ Nurb *nu;
+ Curve *cu;
+ int type, newname= 0;
+
+ if(G.vd==0) return;
+ if(G.scene->id.lib) return;
+
+ /* this function also comes from an info window */
+ if ELEM(curarea->spacetype, SPACE_VIEW3D, SPACE_INFO); else return;
+
+ if(stype>=10 && stype<20) type= CU_2D+1;
+ else if(stype>=20 && stype<30) type= CU_2D+2;
+ else if(stype>=30 && stype<40) type= CU_2D+3;
+ else if(stype>=40 && stype<50) {
+ if(stype==46) type= 4;
+ else type= CU_2D+4;
+ }
+ else type= CU_2D;
+
+ check_editmode(OB_CURVE);
+
+ /* if no obedit: new object and enter editmode */
+ if(G.obedit==NULL) {
+ add_object_draw(OB_CURVE);
+ base_init_from_view3d(BASACT, G.vd);
+ G.obedit= BASACT->object;
+
+ where_is_object(G.obedit);
+
+ make_editNurb();
+ setcursor_space(SPACE_VIEW3D, CURSOR_EDIT);
+ newname= 1;
+
+ cu= G.obedit->data;
+ if(stype==46) {
+ cu->flag |= (CU_3D+CU_PATH);
+
+ default_curve_ipo(cu);
+ }
+ }
+ else {
+ cu= G.obedit->data;
+ }
+
+ if(cu->flag & CU_3D) type &= ~CU_2D;
+
+ stype= (stype % 10);
+
+ nu= addNurbprim(type, stype, newname); /* 2D */
+
+ BLI_addtail(&editNurb, nu);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+
+ countall();
+
+ /* if a new object was created, it stores it in Curve, for reload original data and undo */
+ if ( !(newname) || U.flag & USER_ADD_EDITMODE) {
+ if(newname) load_editNurb();
+ } else {
+ exit_editmode(2);
+ }
+
+ allqueue(REDRAWALL, 0);
+
+ BIF_undo_push("Add Curve");
+}
+
+void add_primitiveNurb(int type)
+{
+ Nurb *nu;
+ int newname= 0;
+
+ if(G.scene->id.lib) return;
+ if ELEM(curarea->spacetype, SPACE_VIEW3D, SPACE_INFO); else return;
+
+ check_editmode(OB_SURF);
+
+ /* if no obedit: new object and enter editmode */
+ if(G.obedit==0) {
+ add_object_draw(OB_SURF);
+ base_init_from_view3d(BASACT, G.vd);
+ G.obedit= BASACT->object;
+
+ where_is_object(G.obedit);
+
+ make_editNurb();
+ setcursor_space(SPACE_VIEW3D, CURSOR_EDIT);
+ newname= 1;
+ }
+
+ nu= addNurbprim(4, type, newname);
+ BLI_addtail(&editNurb,nu);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+
+ countall();
+
+ /* if a new object was created, it stores it in Curve, for reload original data and undo */
+ if ( !(newname) || U.flag & USER_ADD_EDITMODE) {
+ if(newname) load_editNurb();
+ } else {
+ exit_editmode(2);
+ }
+ allqueue(REDRAWALL, 0);
+
+ BIF_undo_push("Add Surface");
+}
+
+
+
+void clear_tilt()
+{
+ Nurb *nu;
+ BezTriple *bezt;
+ BPoint *bp;
+ int a;
+
+ if(okee("Clear tilt")==0) return;
+
+ for(nu= editNurb.first; nu; nu= nu->next) {
+ if( nu->bezt ) {
+ bezt= nu->bezt;
+ a= nu->pntsu;
+ while(a--) {
+ if(BEZSELECTED(bezt)) bezt->alfa= 0.0;
+ bezt++;
+ }
+ }
+ else if(nu->bp) {
+ bp= nu->bp;
+ a= nu->pntsu*nu->pntsv;
+ while(a--) {
+ if(bp->f1 & 1) bp->alfa= 0.0;
+ bp++;
+ }
+ }
+ }
+
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ BIF_undo_push("Clear tilt");
+
+}
+
+int bezt_compare (const void *e1, const void *e2)
+{
+ BezTriple *b1 = *((BezTriple**)e1);
+ BezTriple *b2 = *((BezTriple**)e2);
+
+ /* Check numerical values */
+ float val = b1->vec[1][0] - b2->vec[1][0];
+
+ if (val<0)
+ return -1;
+
+ if (val>0)
+ return 1;
+
+ /* Check selected flags : Ensures that selected keys will be listed first */
+
+ if ((b1->f2 & 1) && !(b2->f2 & 1))
+ return -1;
+ if (!(b1->f2 & 1) && (b2->f2 & 1))
+ return 1;
+
+ return 0;
+}
+
+
+/* **************** undo for curves ************** */
+
+static void undoCurve_to_editCurve(void *lbv)
+{
+ ListBase *lb= lbv;
+ Nurb *nu, *newnu;
+ int nr, lastnunr= 0;
+
+ /* we try to restore lastnu too, for buttons */
+ for(nu= editNurb.first; nu; nu = nu->next, lastnunr++) if(nu==lastnu) break;
+
+ freeNurblist(&editNurb);
+
+ /* copy */
+ for(nu= lb->first; nu; nu= nu->next) {
+ newnu= duplicateNurb(nu);
+ BLI_addtail(&editNurb, newnu);
+ }
+ /* restore */
+ for(nr=0, lastnu= editNurb.first; lastnu; lastnu = lastnu->next, nr++) if(nr==lastnunr) break;
+
+}
+
+static void *editCurve_to_undoCurve(void)
+{
+ ListBase *lb;
+ Nurb *nu, *newnu;
+
+ lb= MEM_callocN(sizeof(ListBase), "listbase undo");
+
+ /* copy */
+ for(nu= editNurb.first; nu; nu= nu->next) {
+ newnu= duplicateNurb(nu);
+ BLI_addtail(lb, newnu);
+ }
+ return lb;
+}
+
+static void free_undoCurve(void *lbv)
+{
+ ListBase *lb= lbv;
+
+ freeNurblist(lb);
+ MEM_freeN(lb);
+}
+
+/* and this is all the undo system needs to know */
+void undo_push_curve(char *name)
+{
+ undo_editmode_push(name, free_undoCurve, undoCurve_to_editCurve, editCurve_to_undoCurve);
+}
+
+
+
+/***/
diff --git a/source/blender/src/editdeform.c b/source/blender/src/editdeform.c
new file mode 100644
index 00000000000..6d0c34f2bf8
--- /dev/null
+++ b/source/blender/src/editdeform.c
@@ -0,0 +1,897 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * Creator-specific support for vertex deformation groups
+ * Added: apply deform function (ton)
+ */
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_curve_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_editVert.h"
+
+#include "BKE_customdata.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_depsgraph.h"
+#include "BKE_deform.h"
+#include "BKE_displist.h"
+#include "BKE_global.h"
+#include "BKE_lattice.h"
+#include "BKE_mesh.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_interface.h"
+#include "BIF_editdeform.h"
+#include "BIF_editmesh.h"
+#include "BIF_space.h"
+#include "BIF_toolbox.h"
+
+#include "BSE_edit.h"
+
+#include "butspace.h"
+#include "mydevice.h"
+#include "editmesh.h"
+#include "multires.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* only in editmode */
+void sel_verts_defgroup (int select)
+{
+ EditVert *eve;
+ Object *ob;
+ int i;
+ MDeformVert *dvert;
+
+ ob= G.obedit;
+
+ if (!ob)
+ return;
+
+ switch (ob->type){
+ case OB_MESH:
+ for (eve=G.editMesh->verts.first; eve; eve=eve->next){
+ dvert= CustomData_em_get(&G.editMesh->vdata, eve->data, CD_MDEFORMVERT);
+
+ if (dvert && dvert->totweight){
+ for (i=0; i<dvert->totweight; i++){
+ if (dvert->dw[i].def_nr == (ob->actdef-1)){
+ if (select) eve->f |= SELECT;
+ else eve->f &= ~SELECT;
+
+ break;
+ }
+ }
+ }
+ }
+ /* this has to be called, because this function operates on vertices only */
+ if(select) EM_select_flush(); // vertices to edges/faces
+ else EM_deselect_flush();
+
+ break;
+ case OB_LATTICE:
+ if(editLatt->dvert) {
+ BPoint *bp;
+ int a, tot;
+
+ dvert= editLatt->dvert;
+
+ tot= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
+ for(a=0, bp= editLatt->def; a<tot; a++, bp++, dvert++) {
+ for (i=0; i<dvert->totweight; i++){
+ if (dvert->dw[i].def_nr == (ob->actdef-1)) {
+ if(select) bp->f1 |= SELECT;
+ else bp->f1 &= ~SELECT;
+
+ break;
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ countall();
+
+}
+
+/* check if deform vertex has defgroup index */
+MDeformWeight *get_defweight (MDeformVert *dv, int defgroup)
+{
+ int i;
+
+ if (!dv || defgroup<0)
+ return NULL;
+
+ for (i=0; i<dv->totweight; i++){
+ if (dv->dw[i].def_nr == defgroup)
+ return dv->dw+i;
+ }
+ return NULL;
+}
+
+/* Ensures that mv has a deform weight entry for
+ the specified defweight group */
+/* Note this function is mirrored in editmesh_tools.c, for use for editvertices */
+MDeformWeight *verify_defweight (MDeformVert *dv, int defgroup)
+{
+ MDeformWeight *newdw;
+
+ /* do this check always, this function is used to check for it */
+ if (!dv || defgroup<0)
+ return NULL;
+
+ newdw = get_defweight (dv, defgroup);
+ if (newdw)
+ return newdw;
+
+ newdw = MEM_callocN (sizeof(MDeformWeight)*(dv->totweight+1), "deformWeight");
+ if (dv->dw){
+ memcpy (newdw, dv->dw, sizeof(MDeformWeight)*dv->totweight);
+ MEM_freeN (dv->dw);
+ }
+ dv->dw=newdw;
+
+ dv->dw[dv->totweight].weight=0.0f;
+ dv->dw[dv->totweight].def_nr=defgroup;
+ /* Group index */
+
+ dv->totweight++;
+
+ return dv->dw+(dv->totweight-1);
+}
+
+void add_defgroup (Object *ob)
+{
+ add_defgroup_name (ob, "Group");
+}
+
+bDeformGroup *add_defgroup_name (Object *ob, char *name)
+{
+ bDeformGroup *defgroup;
+
+ if (!ob)
+ return NULL;
+
+ defgroup = MEM_callocN (sizeof(bDeformGroup), "add deformGroup");
+
+ BLI_strncpy (defgroup->name, name, 32);
+
+ BLI_addtail(&ob->defbase, defgroup);
+ unique_vertexgroup_name(defgroup, ob);
+
+ ob->actdef = BLI_countlist(&ob->defbase);
+
+ return defgroup;
+}
+
+void duplicate_defgroup ( Object *ob )
+{
+ bDeformGroup *dg, *cdg;
+ char name[32], s[32];
+ MDeformWeight *org, *cpy;
+ MDeformVert *dvert;
+ Mesh *me;
+ int i, idg, icdg;
+
+ if (ob->type != OB_MESH)
+ return;
+
+ dg = BLI_findlink (&ob->defbase, (ob->actdef-1));
+ if (!dg)
+ return;
+
+ BLI_snprintf (name, 32, "%s_copy", dg->name);
+ while (get_named_vertexgroup (ob, name)) {
+ if ((strlen (name) + 6) > 32) {
+ error ("Error: the name for the new group is > 32 characters");
+ return;
+ }
+ strcpy (s, name);
+ BLI_snprintf (name, 32, "%s_copy", s);
+ }
+
+ cdg = copy_defgroup (dg);
+ strcpy (cdg->name, name);
+ BLI_addtail (&ob->defbase, cdg);
+
+ idg = (ob->actdef-1);
+ ob->actdef = BLI_countlist (&ob->defbase);
+ icdg = (ob->actdef-1);
+
+ me = get_mesh (ob);
+ if (!me->dvert)
+ return;
+
+ for (i = 0; i < me->totvert; i++) {
+ dvert = me->dvert+i;
+ org = get_defweight (dvert, idg);
+ if (org) {
+ cpy = verify_defweight (dvert, icdg);
+ cpy->weight = org->weight;
+ }
+ }
+}
+
+void del_defgroup_in_object_mode ( Object *ob )
+{
+ bDeformGroup *dg;
+ MDeformVert *dvert;
+ Mesh *me;
+ int i, e;
+
+ if ((!ob) || (ob->type != OB_MESH))
+ return;
+
+ dg = BLI_findlink (&ob->defbase, (ob->actdef-1));
+ if (!dg)
+ return;
+
+ me = get_mesh (ob);
+ if (me->dvert) {
+ for (i = 0; i < me->totvert; i++) {
+ dvert = me->dvert + i;
+ if (dvert) {
+ if (get_defweight (dvert, (ob->actdef-1)))
+ remove_vert_defgroup (ob, dg, i);
+ }
+ }
+
+ for (i = 0; i < me->totvert; i++) {
+ dvert = me->dvert+i;
+ if (dvert) {
+ for (e = 0; e < dvert->totweight; e++) {
+ if (dvert->dw[e].def_nr > (ob->actdef-1))
+ dvert->dw[e].def_nr--;
+ }
+ }
+ }
+ }
+
+ /* Update the active deform index if necessary */
+ if (ob->actdef == BLI_countlist(&ob->defbase))
+ ob->actdef--;
+
+ /* Remove the group */
+ BLI_freelinkN (&ob->defbase, dg);
+}
+
+void del_defgroup (Object *ob)
+{
+ bDeformGroup *defgroup;
+ int i;
+
+ if (!ob)
+ return;
+
+ if (!ob->actdef)
+ return;
+
+ defgroup = BLI_findlink(&ob->defbase, ob->actdef-1);
+ if (!defgroup)
+ return;
+
+ /* Make sure that no verts are using this group */
+ remove_verts_defgroup(1);
+
+ /* Make sure that any verts with higher indices are adjusted accordingly */
+ if(ob->type==OB_MESH) {
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+ MDeformVert *dvert;
+
+ for (eve=em->verts.first; eve; eve=eve->next){
+ dvert= CustomData_em_get(&G.editMesh->vdata, eve->data, CD_MDEFORMVERT);
+
+ if (dvert)
+ for (i=0; i<dvert->totweight; i++)
+ if (dvert->dw[i].def_nr > (ob->actdef-1))
+ dvert->dw[i].def_nr--;
+ }
+ }
+ else {
+ BPoint *bp;
+ MDeformVert *dvert= editLatt->dvert;
+ int a, tot;
+
+ if (dvert) {
+ tot= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
+ for(a=0, bp= editLatt->def; a<tot; a++, bp++, dvert++) {
+ for (i=0; i<dvert->totweight; i++){
+ if (dvert->dw[i].def_nr > (ob->actdef-1))
+ dvert->dw[i].def_nr--;
+ }
+ }
+ }
+ }
+
+ /* Update the active deform index if necessary */
+ if (ob->actdef==BLI_countlist(&ob->defbase))
+ ob->actdef--;
+
+ /* Remove the group */
+ BLI_freelinkN (&ob->defbase, defgroup);
+
+ /* remove all dverts */
+ if(ob->actdef==0) {
+ if(ob->type==OB_MESH) {
+ Mesh *me= ob->data;
+ CustomData_free_layer_active(&me->vdata, CD_MDEFORMVERT, me->totvert);
+ me->dvert= NULL;
+ }
+ else {
+ if (editLatt->dvert) {
+ MEM_freeN(editLatt->dvert);
+ editLatt->dvert= NULL;
+ }
+ }
+ }
+}
+
+void create_dverts(ID *id)
+{
+ /* create deform verts
+ */
+
+ if( GS(id->name)==ID_ME) {
+ Mesh *me= (Mesh *)id;
+ me->dvert= CustomData_add_layer(&me->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, me->totvert);
+ }
+ else if( GS(id->name)==ID_LT) {
+ Lattice *lt= (Lattice *)id;
+ lt->dvert= MEM_callocN(sizeof(MDeformVert)*lt->pntsu*lt->pntsv*lt->pntsw, "lattice deformVert");
+ }
+}
+
+/* for mesh in object mode
+ lattice can be in editmode */
+void remove_vert_def_nr (Object *ob, int def_nr, int vertnum)
+{
+ /* This routine removes the vertex from the deform
+ * group with number def_nr.
+ *
+ * This routine is meant to be fast, so it is the
+ * responsibility of the calling routine to:
+ * a) test whether ob is non-NULL
+ * b) test whether ob is a mesh
+ * c) calculate def_nr
+ */
+
+ MDeformWeight *newdw;
+ MDeformVert *dvert= NULL;
+ int i;
+
+ /* get the deform vertices corresponding to the
+ * vertnum
+ */
+ if(ob->type==OB_MESH) {
+ if( ((Mesh*)ob->data)->dvert )
+ dvert = ((Mesh*)ob->data)->dvert + vertnum;
+ }
+ else if(ob->type==OB_LATTICE) {
+ Lattice *lt= ob->data;
+
+ if(ob==G.obedit)
+ lt= editLatt;
+
+ if(lt->dvert)
+ dvert = lt->dvert + vertnum;
+ }
+
+ if(dvert==NULL)
+ return;
+
+ /* for all of the deform weights in the
+ * deform vert
+ */
+ for (i=dvert->totweight - 1 ; i>=0 ; i--){
+
+ /* if the def_nr is the same as the one
+ * for our weight group then remove it
+ * from this deform vert.
+ */
+ if (dvert->dw[i].def_nr == def_nr) {
+ dvert->totweight--;
+
+ /* if there are still other deform weights
+ * attached to this vert then remove this
+ * deform weight, and reshuffle the others
+ */
+ if (dvert->totweight) {
+ newdw = MEM_mallocN (sizeof(MDeformWeight)*(dvert->totweight),
+ "deformWeight");
+ if (dvert->dw){
+ memcpy (newdw, dvert->dw, sizeof(MDeformWeight)*i);
+ memcpy (newdw+i, dvert->dw+i+1,
+ sizeof(MDeformWeight)*(dvert->totweight-i));
+ MEM_freeN (dvert->dw);
+ }
+ dvert->dw=newdw;
+ }
+ /* if there are no other deform weights
+ * left then just remove the deform weight
+ */
+ else {
+ MEM_freeN (dvert->dw);
+ dvert->dw = NULL;
+ break;
+ }
+ }
+ }
+
+}
+
+/* for Mesh in Object mode */
+/* allows editmode for Lattice */
+void add_vert_defnr (Object *ob, int def_nr, int vertnum,
+ float weight, int assignmode)
+{
+ /* add the vert to the deform group with the
+ * specified number
+ */
+ MDeformVert *dv= NULL;
+ MDeformWeight *newdw;
+ int i;
+
+ /* get the vert */
+ if(ob->type==OB_MESH) {
+ if(((Mesh*)ob->data)->dvert)
+ dv = ((Mesh*)ob->data)->dvert + vertnum;
+ }
+ else if(ob->type==OB_LATTICE) {
+ Lattice *lt;
+
+ if(ob==G.obedit)
+ lt= editLatt;
+ else
+ lt= ob->data;
+
+ if(lt->dvert)
+ dv = lt->dvert + vertnum;
+ }
+
+ if(dv==NULL)
+ return;
+
+ /* Lets first check to see if this vert is
+ * already in the weight group -- if so
+ * lets update it
+ */
+ for (i=0; i<dv->totweight; i++){
+
+ /* if this weight cooresponds to the
+ * deform group, then add it using
+ * the assign mode provided
+ */
+ if (dv->dw[i].def_nr == def_nr){
+
+ switch (assignmode) {
+ case WEIGHT_REPLACE:
+ dv->dw[i].weight=weight;
+ break;
+ case WEIGHT_ADD:
+ dv->dw[i].weight+=weight;
+ if (dv->dw[i].weight >= 1.0)
+ dv->dw[i].weight = 1.0;
+ break;
+ case WEIGHT_SUBTRACT:
+ dv->dw[i].weight-=weight;
+ /* if the weight is zero or less then
+ * remove the vert from the deform group
+ */
+ if (dv->dw[i].weight <= 0.0)
+ remove_vert_def_nr(ob, def_nr, vertnum);
+ break;
+ }
+ return;
+ }
+ }
+
+ /* if the vert wasn't in the deform group then
+ * we must take a different form of action ...
+ */
+
+ switch (assignmode) {
+ case WEIGHT_SUBTRACT:
+ /* if we are subtracting then we don't
+ * need to do anything
+ */
+ return;
+
+ case WEIGHT_REPLACE:
+ case WEIGHT_ADD:
+ /* if we are doing an additive assignment, then
+ * we need to create the deform weight
+ */
+ newdw = MEM_callocN (sizeof(MDeformWeight)*(dv->totweight+1),
+ "deformWeight");
+ if (dv->dw){
+ memcpy (newdw, dv->dw, sizeof(MDeformWeight)*dv->totweight);
+ MEM_freeN (dv->dw);
+ }
+ dv->dw=newdw;
+
+ dv->dw[dv->totweight].weight=weight;
+ dv->dw[dv->totweight].def_nr=def_nr;
+
+ dv->totweight++;
+ break;
+ }
+}
+
+/* called while not in editmode */
+void add_vert_to_defgroup (Object *ob, bDeformGroup *dg, int vertnum,
+ float weight, int assignmode)
+{
+ /* add the vert to the deform group with the
+ * specified assign mode
+ */
+ int def_nr;
+
+ /* get the deform group number, exit if
+ * it can't be found
+ */
+ def_nr = get_defgroup_num(ob, dg);
+ if (def_nr < 0) return;
+
+ /* if there's no deform verts then
+ * create some
+ */
+ if(ob->type==OB_MESH) {
+ if (!((Mesh*)ob->data)->dvert)
+ create_dverts(ob->data);
+ }
+ else if(ob->type==OB_LATTICE) {
+ if (!((Lattice*)ob->data)->dvert)
+ create_dverts(ob->data);
+ }
+
+ /* call another function to do the work
+ */
+ add_vert_defnr (ob, def_nr, vertnum, weight, assignmode);
+}
+
+/* Only available in editmode */
+void assign_verts_defgroup (void)
+{
+ extern float editbutvweight; /* buttons.c */
+ Object *ob;
+ EditVert *eve;
+ bDeformGroup *dg, *eg;
+ MDeformWeight *newdw;
+ MDeformVert *dvert;
+ int i, done;
+
+ if(multires_level1_test()) return;
+
+ ob= G.obedit;
+
+ if (!ob)
+ return;
+
+ dg=BLI_findlink(&ob->defbase, ob->actdef-1);
+ if (!dg){
+ error ("No vertex group is active");
+ return;
+ }
+
+ switch (ob->type){
+ case OB_MESH:
+ if (!CustomData_has_layer(&G.editMesh->vdata, CD_MDEFORMVERT))
+ EM_add_data_layer(&G.editMesh->vdata, CD_MDEFORMVERT);
+
+ /* Go through the list of editverts and assign them */
+ for (eve=G.editMesh->verts.first; eve; eve=eve->next){
+ dvert= CustomData_em_get(&G.editMesh->vdata, eve->data, CD_MDEFORMVERT);
+
+ if (dvert && (eve->f & 1)){
+ done=0;
+ /* See if this vert already has a reference to this group */
+ /* If so: Change its weight */
+ done=0;
+ for (i=0; i<dvert->totweight; i++){
+ eg = BLI_findlink (&ob->defbase, dvert->dw[i].def_nr);
+ /* Find the actual group */
+ if (eg==dg){
+ dvert->dw[i].weight=editbutvweight;
+ done=1;
+ break;
+ }
+ }
+ /* If not: Add the group and set its weight */
+ if (!done){
+ newdw = MEM_callocN (sizeof(MDeformWeight)*(dvert->totweight+1), "deformWeight");
+ if (dvert->dw){
+ memcpy (newdw, dvert->dw, sizeof(MDeformWeight)*dvert->totweight);
+ MEM_freeN (dvert->dw);
+ }
+ dvert->dw=newdw;
+
+ dvert->dw[dvert->totweight].weight= editbutvweight;
+ dvert->dw[dvert->totweight].def_nr= ob->actdef-1;
+
+ dvert->totweight++;
+
+ }
+ }
+ }
+ break;
+ case OB_LATTICE:
+ {
+ BPoint *bp;
+ int a, tot;
+
+ if(editLatt->dvert==NULL)
+ create_dverts(&editLatt->id);
+
+ tot= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
+ for(a=0, bp= editLatt->def; a<tot; a++, bp++) {
+ if(bp->f1 & SELECT)
+ add_vert_defnr (ob, ob->actdef-1, a, editbutvweight, WEIGHT_REPLACE);
+ }
+ }
+ break;
+ default:
+ printf ("Assigning deformation groups to unknown object type\n");
+ break;
+ }
+
+}
+
+/* mesh object mode, lattice can be in editmode */
+void remove_vert_defgroup (Object *ob, bDeformGroup *dg, int vertnum)
+{
+ /* This routine removes the vertex from the specified
+ * deform group.
+ */
+
+ int def_nr;
+
+ /* if the object is NULL abort
+ */
+ if (!ob)
+ return;
+
+ /* get the deform number that cooresponds
+ * to this deform group, and abort if it
+ * can not be found.
+ */
+ def_nr = get_defgroup_num(ob, dg);
+ if (def_nr < 0) return;
+
+ /* call another routine to do the work
+ */
+ remove_vert_def_nr (ob, def_nr, vertnum);
+}
+
+/* Only available in editmode */
+/* removes from active defgroup, if allverts==0 only selected vertices */
+void remove_verts_defgroup (int allverts)
+{
+ Object *ob;
+ EditVert *eve;
+ MDeformVert *dvert;
+ MDeformWeight *newdw;
+ bDeformGroup *dg, *eg;
+ int i;
+
+ if(multires_level1_test()) return;
+
+ ob= G.obedit;
+
+ if (!ob)
+ return;
+
+ dg=BLI_findlink(&ob->defbase, ob->actdef-1);
+ if (!dg){
+ error ("No vertex group is active");
+ return;
+ }
+
+ switch (ob->type){
+ case OB_MESH:
+ for (eve=G.editMesh->verts.first; eve; eve=eve->next){
+ dvert= CustomData_em_get(&G.editMesh->vdata, eve->data, CD_MDEFORMVERT);
+
+ if (dvert && dvert->dw && ((eve->f & 1) || allverts)){
+ for (i=0; i<dvert->totweight; i++){
+ /* Find group */
+ eg = BLI_findlink (&ob->defbase, dvert->dw[i].def_nr);
+ if (eg == dg){
+ dvert->totweight--;
+ if (dvert->totweight){
+ newdw = MEM_mallocN (sizeof(MDeformWeight)*(dvert->totweight), "deformWeight");
+
+ if (dvert->dw){
+ memcpy (newdw, dvert->dw, sizeof(MDeformWeight)*i);
+ memcpy (newdw+i, dvert->dw+i+1, sizeof(MDeformWeight)*(dvert->totweight-i));
+ MEM_freeN (dvert->dw);
+ }
+ dvert->dw=newdw;
+ }
+ else{
+ MEM_freeN (dvert->dw);
+ dvert->dw=NULL;
+ break;
+ }
+ }
+ }
+ }
+ }
+ break;
+ case OB_LATTICE:
+
+ if(editLatt->dvert) {
+ BPoint *bp;
+ int a, tot= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
+
+ for(a=0, bp= editLatt->def; a<tot; a++, bp++) {
+ if(allverts || (bp->f1 & SELECT))
+ remove_vert_defgroup (ob, dg, a);
+ }
+ }
+ break;
+
+ default:
+ printf ("Removing deformation groups from unknown object type\n");
+ break;
+ }
+}
+
+void vertexgroup_select_by_name(Object *ob, char *name)
+{
+ bDeformGroup *curdef;
+ int actdef= 1;
+
+ if(ob==NULL) return;
+
+ for (curdef = ob->defbase.first; curdef; curdef=curdef->next, actdef++){
+ if (!strcmp(curdef->name, name)) {
+ ob->actdef= actdef;
+ return;
+ }
+ }
+ ob->actdef=0; // this signals on painting to create a new one, if a bone in posemode is selected */
+}
+
+/* This function provides a shortcut for adding/removing verts from
+ * vertex groups. It is called by the Ctrl-G hotkey in EditMode for Meshes
+ * and Lattices. (currently only restricted to those two)
+ * It is only responsible for
+ */
+void vgroup_assign_with_menu(void)
+{
+ Object *ob= G.obedit;
+ int defCount;
+ int mode;
+
+ /* prevent crashes */
+ if (ob==NULL) return;
+
+ defCount= BLI_countlist(&ob->defbase);
+
+ /* give user choices of adding to current/new or removing from current */
+ if (defCount && ob->actdef)
+ mode = pupmenu("Vertex Groups %t|Add Selected to New Group %x1|Add Selected to Active Group %x2|Remove Selected from Active Group %x3");
+ else
+ mode= pupmenu("Vertex Groups %t|Add Selected to New Group %x1");
+
+ /* handle choices */
+ switch (mode) {
+ case 1: /* add to new group */
+ add_defgroup(ob);
+ assign_verts_defgroup();
+ allqueue(REDRAWVIEW3D, 1);
+ BIF_undo_push("Assign to vertex group");
+ break;
+ case 2: /* add to current group */
+ assign_verts_defgroup();
+ allqueue(REDRAWVIEW3D, 1);
+ BIF_undo_push("Assign to vertex group");
+ break;
+ case 3: /* remove from current group */
+ remove_verts_defgroup(0);
+ allqueue(REDRAWVIEW3D, 1);
+ BIF_undo_push("Remove from vertex group");
+ break;
+ }
+}
+
+/* This function provides a shortcut for commonly used vertex group
+ * functions - change weight (not implemented), change active group, delete active group,
+ * when Ctrl-Shift-G is used in EditMode, for Meshes and Lattices (only for now).
+ */
+void vgroup_operation_with_menu(void)
+{
+ Object *ob= G.obedit;
+ int defCount;
+ int mode;
+
+ /* prevent crashes and useless cases */
+ if (ob==NULL) return;
+
+ defCount= BLI_countlist(&ob->defbase);
+ if (defCount == 0) return;
+
+ /* give user choices of adding to current/new or removing from current */
+ if (ob->actdef)
+ mode = pupmenu("Vertex Groups %t|Change Active Group%x1|Delete Active Group%x2");
+ else
+ mode= pupmenu("Vertex Groups %t|Change Active Group%x1");
+
+ /* handle choices */
+ switch (mode) {
+ case 1: /* change active group*/
+ {
+ char *menustr= get_vertexgroup_menustr(ob);
+ short nr;
+
+ if (menustr) {
+ nr= pupmenu(menustr);
+
+ if ((nr >= 1) && (nr <= defCount))
+ ob->actdef= nr;
+
+ MEM_freeN(menustr);
+ }
+ allqueue(REDRAWBUTSALL, 0);
+ }
+ break;
+ case 2: /* delete active group */
+ {
+ del_defgroup(ob);
+ allqueue (REDRAWVIEW3D, 1);
+ allqueue(REDRAWOOPS, 0);
+ BIF_undo_push("Delete vertex group");
+ }
+ break;
+ }
+}
+
+/* ******************* other deform edit stuff ********** */
+
+void object_apply_deform(Object *ob)
+{
+ notice("Apply Deformation now only availble in Modifier buttons");
+}
+
diff --git a/source/blender/src/editface.c b/source/blender/src/editface.c
new file mode 100644
index 00000000000..d3af5cc47e8
--- /dev/null
+++ b/source/blender/src/editface.c
@@ -0,0 +1,1437 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+
+#include <math.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_heap.h"
+#include "BLI_edgehash.h"
+#include "BLI_editVert.h"
+
+#include "MTC_matrixops.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "DNA_image_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_space_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_brush.h"
+#include "BKE_customdata.h"
+#include "BKE_depsgraph.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_displist.h"
+#include "BKE_global.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
+#include "BKE_customdata.h"
+
+#include "BSE_view.h"
+#include "BSE_edit.h"
+#include "BSE_drawview.h" /* for backdrawview3d */
+
+#include "BIF_editsima.h"
+#include "BIF_editmesh.h"
+#include "BIF_interface.h"
+#include "BIF_mywindow.h"
+#include "BIF_toolbox.h"
+#include "BIF_resources.h"
+#include "BIF_screen.h"
+#include "BIF_gl.h"
+#include "BIF_graphics.h"
+#include "BIF_space.h" /* for allqueue */
+
+#include "BDR_drawmesh.h"
+#include "BDR_editface.h"
+#include "BDR_vpaint.h"
+
+#include "BDR_editface.h"
+#include "BDR_vpaint.h"
+
+#include "mydevice.h"
+#include "blendef.h"
+#include "butspace.h"
+#include "multires.h"
+
+#include "BSE_trans_types.h"
+
+#include "BDR_unwrapper.h"
+#include "BDR_editobject.h"
+
+#include "BPY_extern.h"
+#include "BPY_menus.h"
+
+/* Pupmenu codes: */
+#define UV_CUBE_MAPPING 2
+#define UV_CYL_MAPPING 3
+#define UV_SPHERE_MAPPING 4
+#define UV_BOUNDS_MAPPING 5
+#define UV_RESET_MAPPING 6
+#define UV_WINDOW_MAPPING 7
+#define UV_UNWRAP_MAPPING 8
+#define UV_CYL_EX 32
+#define UV_SPHERE_EX 34
+
+/* Some macro tricks to make pupmenu construction look nicer :-)
+ Sorry, just did it for fun. */
+
+#define _STR(x) " " #x
+#define STRING(x) _STR(x)
+
+#define MENUSTRING(string, code) string " %x" STRING(code)
+#define MENUTITLE(string) string " %t|"
+
+
+/* returns 0 if not found, otherwise 1 */
+int facesel_face_pick(Mesh *me, short *mval, unsigned int *index, short rect)
+{
+ if (!me || me->totface==0)
+ return 0;
+
+ if (G.vd->flag & V3D_NEEDBACKBUFDRAW) {
+ check_backbuf();
+ persp(PERSP_VIEW);
+ }
+
+ if (rect) {
+ /* sample rect to increase changes of selecting, so that when clicking
+ on an edge in the backbuf, we can still select a face */
+ int dist;
+ *index = sample_backbuf_rect(mval, 3, 1, me->totface+1, &dist,0,NULL);
+ }
+ else
+ /* sample only on the exact position */
+ *index = sample_backbuf(mval[0], mval[1]);
+
+ if ((*index)<=0 || (*index)>(unsigned int)me->totface)
+ return 0;
+
+ (*index)--;
+
+ return 1;
+}
+
+/* returns 0 if not found, otherwise 1 */
+static int facesel_edge_pick(Mesh *me, short *mval, unsigned int *index)
+{
+ int dist;
+ unsigned int min = me->totface + 1;
+ unsigned int max = me->totface + me->totedge + 1;
+
+ if (me->totedge == 0)
+ return 0;
+
+ if (G.vd->flag & V3D_NEEDBACKBUFDRAW) {
+ check_backbuf();
+ persp(PERSP_VIEW);
+ }
+
+ *index = sample_backbuf_rect(mval, 50, min, max, &dist,0,NULL);
+
+ if (*index == 0)
+ return 0;
+
+ (*index)--;
+
+ return 1;
+}
+
+/* only operates on the edit object - this is all thats needed at the moment */
+static void uv_calc_center_vector(float *result, Object *ob, EditMesh *em)
+{
+ float min[3], max[3], *cursx;
+
+ EditFace *efa;
+ switch (G.vd->around)
+ {
+ case V3D_CENTER: /* bounding box center */
+ min[0]= min[1]= min[2]= 1e20f;
+ max[0]= max[1]= max[2]= -1e20f;
+
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ if (efa->f & SELECT) {
+ DO_MINMAX(efa->v1->co, min, max);
+ DO_MINMAX(efa->v2->co, min, max);
+ DO_MINMAX(efa->v3->co, min, max);
+ if(efa->v4) DO_MINMAX(efa->v4->co, min, max);
+ }
+ }
+ VecMidf(result, min, max);
+ break;
+ case V3D_CURSOR: /*cursor center*/
+ cursx= give_cursor();
+ /* shift to objects world */
+ result[0]= cursx[0]-ob->obmat[3][0];
+ result[1]= cursx[1]-ob->obmat[3][1];
+ result[2]= cursx[2]-ob->obmat[3][2];
+ break;
+ case V3D_LOCAL: /*object center*/
+ case V3D_CENTROID: /* multiple objects centers, only one object here*/
+ default:
+ result[0]= result[1]= result[2]= 0.0;
+ break;
+ }
+}
+
+static void uv_calc_map_matrix(float result[][4], Object *ob, float upangledeg, float sideangledeg, float radius)
+{
+ float rotup[4][4], rotside[4][4], viewmatrix[4][4], rotobj[4][4];
+ float sideangle= 0.0, upangle= 0.0;
+ int k;
+
+ /* get rotation of the current view matrix */
+ Mat4CpyMat4(viewmatrix,G.vd->viewmat);
+ /* but shifting */
+ for( k= 0; k< 4; k++) viewmatrix[3][k] =0.0;
+
+ /* get rotation of the current object matrix */
+ Mat4CpyMat4(rotobj,ob->obmat);
+ /* but shifting */
+ for( k= 0; k< 4; k++) rotobj[3][k] =0.0;
+
+ Mat4Clr(*rotup);
+ Mat4Clr(*rotside);
+
+ /* compensate front/side.. against opengl x,y,z world definition */
+ /* this is "kanonen gegen spatzen", a few plus minus 1 will do here */
+ /* i wanted to keep the reason here, so we're rotating*/
+ sideangle= M_PI * (sideangledeg + 180.0) /180.0;
+ rotside[0][0]= (float)cos(sideangle);
+ rotside[0][1]= -(float)sin(sideangle);
+ rotside[1][0]= (float)sin(sideangle);
+ rotside[1][1]= (float)cos(sideangle);
+ rotside[2][2]= 1.0f;
+
+ upangle= M_PI * upangledeg /180.0;
+ rotup[1][1]= (float)cos(upangle)/radius;
+ rotup[1][2]= -(float)sin(upangle)/radius;
+ rotup[2][1]= (float)sin(upangle)/radius;
+ rotup[2][2]= (float)cos(upangle)/radius;
+ rotup[0][0]= (float)1.0/radius;
+
+ /* calculate transforms*/
+ Mat4MulSerie(result,rotup,rotside,viewmatrix,rotobj,NULL,NULL,NULL,NULL);
+}
+
+static void uv_calc_shift_project(float *target, float *shift, float rotmat[][4], int projectionmode, float *source, float *min, float *max)
+{
+ float pv[3];
+
+ VecSubf(pv, source, shift);
+ Mat4MulVecfl(rotmat, pv);
+
+ switch(projectionmode) {
+ case B_UVAUTO_CYLINDER:
+ tubemap(pv[0], pv[1], pv[2], &target[0],&target[1]);
+ /* split line is always zero */
+ if (target[0] >= 1.0f) target[0] -= 1.0f;
+ break;
+
+ case B_UVAUTO_SPHERE:
+ spheremap(pv[0], pv[1], pv[2], &target[0],&target[1]);
+ /* split line is always zero */
+ if (target[0] >= 1.0f) target[0] -= 1.0f;
+ break;
+
+ case 3: /* ortho special case for BOUNDS */
+ target[0] = -pv[0];
+ target[1] = pv[2];
+ break;
+
+ case 4:
+ {
+ /* very special case for FROM WINDOW */
+ float pv4[4], dx, dy, x= 0.0, y= 0.0;
+
+ dx= G.vd->area->winx;
+ dy= G.vd->area->winy;
+
+ VecCopyf(pv4, source);
+ pv4[3] = 1.0;
+
+ /* rotmat is the object matrix in this case */
+ Mat4MulVec4fl(rotmat,pv4);
+
+ /* almost project_short */
+ Mat4MulVec4fl(G.vd->persmat,pv4);
+ if (fabs(pv4[3]) > 0.00001) { /* avoid division by zero */
+ target[0] = dx/2.0 + (dx/2.0)*pv4[0]/pv4[3];
+ target[1] = dy/2.0 + (dy/2.0)*pv4[1]/pv4[3];
+ }
+ else {
+ /* scaling is lost but give a valid result */
+ target[0] = dx/2.0 + (dx/2.0)*pv4[0];
+ target[1] = dy/2.0 + (dy/2.0)*pv4[1];
+ }
+
+ /* G.vd->persmat seems to do this funky scaling */
+ if(dx > dy) {
+ y= (dx-dy)/2.0;
+ dy = dx;
+ }
+ else {
+ x= (dy-dx)/2.0;
+ dx = dy;
+ }
+ target[0]= (x + target[0])/dx;
+ target[1]= (y + target[1])/dy;
+
+ }
+ break;
+
+ default:
+ target[0] = 0.0;
+ target[1] = 1.0;
+ }
+
+ /* we know the values here and may need min_max later */
+ /* max requests independand from min; not fastest but safest */
+ if(min) {
+ min[0] = MIN2(target[0], min[0]);
+ min[1] = MIN2(target[1], min[1]);
+ }
+ if(max) {
+ max[0] = MAX2(target[0], max[0]);
+ max[1] = MAX2(target[1], max[1]);
+ }
+}
+
+void calculate_uv_map(unsigned short mapmode)
+{
+ MTFace *tface;
+ Object *ob;
+ float dx, dy, rotatematrix[4][4], radius= 1.0, min[3], cent[3], max[3];
+ float fac= 1.0, upangledeg= 0.0, sideangledeg= 90.0;
+ int i, b, mi, n;
+
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+
+ if(G.scene->toolsettings->uvcalc_mapdir==1) {
+ upangledeg= 90.0;
+ sideangledeg= 0.0;
+ } else {
+ upangledeg= 0.0;
+ if(G.scene->toolsettings->uvcalc_mapalign==1) sideangledeg= 0.0;
+ else sideangledeg= 90.0;
+ }
+
+ /* add uvs if there not here */
+ if (!EM_texFaceCheck()) {
+ if (em && em->faces.first)
+ EM_add_data_layer(&em->fdata, CD_MTFACE);
+
+ if (!EM_texFaceCheck())
+ return;
+
+ /* select new UV's */
+ if ((G.sima && G.sima->flag & SI_SYNC_UVSEL)==0) {
+ for(efa=em->faces.first; efa; efa=efa->next) {
+ MTFace *tf= (MTFace *)CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ SIMA_FACESEL_SET(efa, tf);
+ }
+ }
+ }
+
+ ob=OBACT;
+
+ switch(mapmode) {
+ case B_UVAUTO_BOUNDS:
+ min[0]= min[1]= 10000000.0;
+ max[0]= max[1]= -10000000.0;
+
+ cent[0] = cent[1] = cent[2] = 0.0;
+ uv_calc_map_matrix(rotatematrix, ob, upangledeg, sideangledeg, 1.0f);
+
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ if (efa->f & SELECT) {
+ tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ uv_calc_shift_project(tface->uv[0],cent,rotatematrix,3, efa->v1->co, min,max);
+ uv_calc_shift_project(tface->uv[1],cent,rotatematrix,3, efa->v2->co, min,max);
+ uv_calc_shift_project(tface->uv[2],cent,rotatematrix,3, efa->v3->co,min,max);
+ if(efa->v4)
+ uv_calc_shift_project(tface->uv[3],cent,rotatematrix,3, efa->v4->co,min,max);
+ }
+ }
+
+ /* rescale UV to be in 1/1 */
+ dx= (max[0]-min[0]);
+ dy= (max[1]-min[1]);
+
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ if (efa->f & SELECT) {
+ tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ if(efa->v4) b= 3; else b= 2;
+ for(; b>=0; b--) {
+ tface->uv[b][0]= ((tface->uv[b][0]-min[0])*fac)/dx;
+ tface->uv[b][1]= 1.0-fac+((tface->uv[b][1]-min[1])/* *fac */)/dy;
+ }
+ }
+ }
+ break;
+
+ case B_UVAUTO_WINDOW:
+ cent[0] = cent[1] = cent[2] = 0.0;
+ Mat4CpyMat4(rotatematrix,ob->obmat);
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ if (efa->f & SELECT) {
+ tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ uv_calc_shift_project(tface->uv[0],cent,rotatematrix,4, efa->v1->co, NULL,NULL);
+ uv_calc_shift_project(tface->uv[1],cent,rotatematrix,4, efa->v2->co, NULL,NULL);
+ uv_calc_shift_project(tface->uv[2],cent,rotatematrix,4, efa->v3->co, NULL,NULL);
+ if(efa->v4)
+ uv_calc_shift_project(tface->uv[3],cent,rotatematrix,4, efa->v4->co, NULL,NULL);
+ }
+ }
+ break;
+
+ case B_UVAUTO_RESET:
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ if (efa->f & SELECT) {
+ tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ default_uv(tface->uv, 1.0);
+ }
+ }
+ break;
+
+ case B_UVAUTO_CYLINDER:
+ case B_UVAUTO_SPHERE:
+ uv_calc_center_vector(cent, ob, em);
+
+ if(mapmode==B_UVAUTO_CYLINDER) radius = G.scene->toolsettings->uvcalc_radius;
+
+ /* be compatible to the "old" sphere/cylinder mode */
+ if (G.scene->toolsettings->uvcalc_mapdir== 2)
+ Mat4One(rotatematrix);
+ else
+ uv_calc_map_matrix(rotatematrix,ob,upangledeg,sideangledeg,radius);
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ if (efa->f & SELECT) {
+ tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ uv_calc_shift_project(tface->uv[0],cent,rotatematrix,mapmode, efa->v1->co, NULL,NULL);
+ uv_calc_shift_project(tface->uv[1],cent,rotatematrix,mapmode, efa->v2->co, NULL,NULL);
+ uv_calc_shift_project(tface->uv[2],cent,rotatematrix,mapmode, efa->v3->co, NULL,NULL);
+ n = 3;
+ if(efa->v4) {
+ uv_calc_shift_project(tface->uv[3],cent,rotatematrix,mapmode, efa->v4->co, NULL,NULL);
+ n=4;
+ }
+
+ mi = 0;
+ for (i = 1; i < n; i++)
+ if (tface->uv[i][0] > tface->uv[mi][0]) mi = i;
+
+ for (i = 0; i < n; i++) {
+ if (i != mi) {
+ dx = tface->uv[mi][0] - tface->uv[i][0];
+ if (dx > 0.5) tface->uv[i][0] += 1.0;
+ }
+ }
+ }
+ }
+
+ break;
+
+ case B_UVAUTO_CUBE:
+ {
+ /* choose x,y,z axis for projetion depending on the largest normal */
+ /* component, but clusters all together around the center of map */
+ float no[3];
+ short cox, coy;
+ float *loc= ob->obmat[3];
+ /*MVert *mv= me->mvert;*/
+ float cubesize = G.scene->toolsettings->uvcalc_cubesize;
+
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ if (efa->f & SELECT) {
+ tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ CalcNormFloat(efa->v1->co, efa->v2->co, efa->v3->co, no);
+
+ no[0]= fabs(no[0]);
+ no[1]= fabs(no[1]);
+ no[2]= fabs(no[2]);
+
+ cox=0; coy= 1;
+ if(no[2]>=no[0] && no[2]>=no[1]);
+ else if(no[1]>=no[0] && no[1]>=no[2]) coy= 2;
+ else { cox= 1; coy= 2; }
+
+ tface->uv[0][0]= 0.5+0.5*cubesize*(loc[cox] + efa->v1->co[cox]);
+ tface->uv[0][1]= 0.5+0.5*cubesize*(loc[coy] + efa->v1->co[coy]);
+ dx = floor(tface->uv[0][0]);
+ dy = floor(tface->uv[0][1]);
+ tface->uv[0][0] -= dx;
+ tface->uv[0][1] -= dy;
+ tface->uv[1][0]= 0.5+0.5*cubesize*(loc[cox] + efa->v2->co[cox]);
+ tface->uv[1][1]= 0.5+0.5*cubesize*(loc[coy] + efa->v2->co[coy]);
+ tface->uv[1][0] -= dx;
+ tface->uv[1][1] -= dy;
+ tface->uv[2][0]= 0.5+0.5*cubesize*(loc[cox] + efa->v3->co[cox]);
+ tface->uv[2][1]= 0.5+0.5*cubesize*(loc[coy] + efa->v3->co[coy]);
+ tface->uv[2][0] -= dx;
+ tface->uv[2][1] -= dy;
+ if(efa->v4) {
+ tface->uv[3][0]= 0.5+0.5*cubesize*(loc[cox] + efa->v4->co[cox]);
+ tface->uv[3][1]= 0.5+0.5*cubesize*(loc[coy] + efa->v4->co[coy]);
+ tface->uv[3][0] -= dx;
+ tface->uv[3][1] -= dy;
+ }
+ }
+ }
+ break;
+ }
+ default:
+ return;
+ } /* end switch mapmode */
+
+ /* clipping and wrapping */
+ if(G.sima && G.sima->flag & SI_CLIP_UV) {
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ if (!(efa->f & SELECT)) continue;
+ tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+
+ dx= dy= 0;
+ if(efa->v4) b= 3; else b= 2;
+ for(; b>=0; b--) {
+ while(tface->uv[b][0] + dx < 0.0) dx+= 0.5;
+ while(tface->uv[b][0] + dx > 1.0) dx-= 0.5;
+ while(tface->uv[b][1] + dy < 0.0) dy+= 0.5;
+ while(tface->uv[b][1] + dy > 1.0) dy-= 0.5;
+ }
+
+ if(efa->v4) b= 3; else b= 2;
+ for(; b>=0; b--) {
+ tface->uv[b][0]+= dx;
+ CLAMP(tface->uv[b][0], 0.0, 1.0);
+
+ tface->uv[b][1]+= dy;
+ CLAMP(tface->uv[b][1], 0.0, 1.0);
+ }
+ }
+ }
+
+ BIF_undo_push("UV calculation");
+
+ object_uvs_changed(OBACT);
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWIMAGE, 0);
+}
+
+/* last_sel, use em->act_face otherwise get the last selected face in the editselections
+ * at the moment, last_sel is mainly useful for gaking sure the space image dosnt flicker */
+MTFace *get_active_mtface(EditFace **act_efa, MCol **mcol, short sloppy)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa = NULL;
+ EditSelection *ese;
+
+ if(!EM_texFaceCheck())
+ return NULL;
+
+ /* first check the active face */
+ if (sloppy && em->act_face) {
+ efa = em->act_face;
+ } else {
+ ese = em->selected.last;
+ for (; ese; ese=ese->prev){
+ if(ese->type == EDITFACE) {
+ efa = (EditFace *)ese->data;
+
+ if (efa->h) efa= NULL;
+ else break;
+ }
+ }
+ }
+
+ if (sloppy && !efa) {
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ if (efa->f & SELECT)
+ break;
+ }
+ }
+
+ if (efa) {
+ if (mcol) {
+ if (CustomData_has_layer(&em->fdata, CD_MCOL))
+ *mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
+ else
+ *mcol = NULL;
+ }
+ if (act_efa) *act_efa = efa;
+ return CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ }
+ if (act_efa) *act_efa= NULL;
+ if(mcol) *mcol = NULL;
+ return NULL;
+}
+
+void default_uv(float uv[][2], float size)
+{
+ int dy;
+
+ if(size>1.0) size= 1.0;
+
+ dy= 1.0-size;
+
+ uv[0][0]= 0;
+ uv[0][1]= size+dy;
+
+ uv[1][0]= 0;
+ uv[1][1]= dy;
+
+ uv[2][0]= size;
+ uv[2][1]= dy;
+
+ uv[3][0]= size;
+ uv[3][1]= size+dy;
+}
+
+void make_tfaces(Mesh *me)
+{
+ if(!me->mtface) {
+ if(me->mr) {
+ multires_add_layer(me, &me->mr->fdata, CD_MTFACE,
+ CustomData_number_of_layers(&me->fdata, CD_MTFACE));
+ }
+ else {
+ me->mtface= CustomData_add_layer(&me->fdata, CD_MTFACE, CD_DEFAULT,
+ NULL, me->totface);
+ }
+ }
+}
+
+void reveal_tface()
+{
+ Mesh *me;
+ MFace *mface;
+ int a;
+
+ me= get_mesh(OBACT);
+ if(me==0 || me->totface==0) return;
+
+ mface= me->mface;
+ a= me->totface;
+ while(a--) {
+ if(mface->flag & ME_HIDE) {
+ mface->flag |= ME_FACE_SEL;
+ mface->flag -= ME_HIDE;
+ }
+ mface++;
+ }
+
+ BIF_undo_push("Reveal face");
+
+ object_tface_flags_changed(OBACT, 0);
+}
+
+void hide_tface()
+{
+ Mesh *me;
+ MFace *mface;
+ int a;
+
+ me= get_mesh(OBACT);
+ if(me==0 || me->totface==0) return;
+
+ if(G.qual & LR_ALTKEY) {
+ reveal_tface();
+ return;
+ }
+
+ mface= me->mface;
+ a= me->totface;
+ while(a--) {
+ if(mface->flag & ME_HIDE);
+ else {
+ if(G.qual & LR_SHIFTKEY) {
+ if( (mface->flag & ME_FACE_SEL)==0) mface->flag |= ME_HIDE;
+ }
+ else {
+ if( (mface->flag & ME_FACE_SEL)) mface->flag |= ME_HIDE;
+ }
+ }
+ if(mface->flag & ME_HIDE) mface->flag &= ~ME_FACE_SEL;
+
+ mface++;
+ }
+
+ BIF_undo_push("Hide face");
+
+ object_tface_flags_changed(OBACT, 0);
+}
+
+void select_linked_tfaces(int mode)
+{
+ Object *ob;
+ Mesh *me;
+ short mval[2];
+ unsigned int index=0;
+
+ ob = OBACT;
+ me = get_mesh(ob);
+ if(me==0 || me->totface==0) return;
+
+ if (mode==0 || mode==1) {
+ if (!(ob->lay & G.vd->lay))
+ error("The active object is not in this layer");
+
+ getmouseco_areawin(mval);
+ if (!facesel_face_pick(me, mval, &index, 1)) return;
+ }
+
+ select_linked_tfaces_with_seams(mode, me, index);
+}
+
+void deselectall_tface()
+{
+ Mesh *me;
+ MFace *mface;
+ int a, sel;
+
+ me= get_mesh(OBACT);
+ if(me==0) return;
+
+ mface= me->mface;
+ a= me->totface;
+ sel= 0;
+ while(a--) {
+ if(mface->flag & ME_HIDE);
+ else if(mface->flag & ME_FACE_SEL) sel= 1;
+ mface++;
+ }
+
+ mface= me->mface;
+ a= me->totface;
+ while(a--) {
+ if(mface->flag & ME_HIDE);
+ else {
+ if(sel) mface->flag &= ~ME_FACE_SEL;
+ else mface->flag |= ME_FACE_SEL;
+ }
+ mface++;
+ }
+
+ BIF_undo_push("(De)select all faces");
+
+ object_tface_flags_changed(OBACT, 0);
+}
+
+void selectswap_tface(void)
+{
+ Mesh *me;
+ MFace *mface;
+ int a;
+
+ me= get_mesh(OBACT);
+ if(me==0) return;
+
+ mface= me->mface;
+ a= me->totface;
+ while(a--) {
+ if(mface->flag & ME_HIDE);
+ else {
+ if(mface->flag & ME_FACE_SEL) mface->flag &= ~ME_FACE_SEL;
+ else mface->flag |= ME_FACE_SEL;
+ }
+ mface++;
+ }
+
+ BIF_undo_push("Select inverse face");
+
+ object_tface_flags_changed(OBACT, 0);
+}
+
+int minmax_tface(float *min, float *max)
+{
+ Object *ob;
+ Mesh *me;
+ MFace *mf;
+ MTFace *tf;
+ MVert *mv;
+ int a, ok=0;
+ float vec[3], bmat[3][3];
+
+ ob = OBACT;
+ if (ob==0) return ok;
+ me= get_mesh(ob);
+ if(me==0 || me->mtface==0) return ok;
+
+ Mat3CpyMat4(bmat, ob->obmat);
+
+ mv= me->mvert;
+ mf= me->mface;
+ tf= me->mtface;
+ for (a=me->totface; a>0; a--, mf++, tf++) {
+ if (mf->flag & ME_HIDE || !(mf->flag & ME_FACE_SEL))
+ continue;
+
+ VECCOPY(vec, (mv+mf->v1)->co);
+ Mat3MulVecfl(bmat, vec);
+ VecAddf(vec, vec, ob->obmat[3]);
+ DO_MINMAX(vec, min, max);
+
+ VECCOPY(vec, (mv+mf->v2)->co);
+ Mat3MulVecfl(bmat, vec);
+ VecAddf(vec, vec, ob->obmat[3]);
+ DO_MINMAX(vec, min, max);
+
+ VECCOPY(vec, (mv+mf->v3)->co);
+ Mat3MulVecfl(bmat, vec);
+ VecAddf(vec, vec, ob->obmat[3]);
+ DO_MINMAX(vec, min, max);
+
+ if (mf->v4) {
+ VECCOPY(vec, (mv+mf->v4)->co);
+ Mat3MulVecfl(bmat, vec);
+ VecAddf(vec, vec, ob->obmat[3]);
+ DO_MINMAX(vec, min, max);
+ }
+ ok= 1;
+ }
+ return ok;
+}
+
+#define ME_SEAM_DONE ME_SEAM_LAST /* reuse this flag */
+
+static float seam_cut_cost(Mesh *me, int e1, int e2, int vert)
+{
+ MVert *v = me->mvert + vert;
+ MEdge *med1 = me->medge + e1, *med2 = me->medge + e2;
+ MVert *v1 = me->mvert + ((med1->v1 == vert)? med1->v2: med1->v1);
+ MVert *v2 = me->mvert + ((med2->v1 == vert)? med2->v2: med2->v1);
+ float cost, d1[3], d2[3];
+
+ cost = VecLenf(v1->co, v->co);
+ cost += VecLenf(v->co, v2->co);
+
+ VecSubf(d1, v->co, v1->co);
+ VecSubf(d2, v2->co, v->co);
+
+ cost = cost + 0.5f*cost*(2.0f - fabs(d1[0]*d2[0] + d1[1]*d2[1] + d1[2]*d2[2]));
+
+ return cost;
+}
+
+static void seam_add_adjacent(Mesh *me, Heap *heap, int mednum, int vertnum, int *nedges, int *edges, int *prevedge, float *cost)
+{
+ int startadj, endadj = nedges[vertnum+1];
+
+ for (startadj = nedges[vertnum]; startadj < endadj; startadj++) {
+ int adjnum = edges[startadj];
+ MEdge *medadj = me->medge + adjnum;
+ float newcost;
+
+ if (medadj->flag & ME_SEAM_DONE)
+ continue;
+
+ newcost = cost[mednum] + seam_cut_cost(me, mednum, adjnum, vertnum);
+
+ if (cost[adjnum] > newcost) {
+ cost[adjnum] = newcost;
+ prevedge[adjnum] = mednum;
+ BLI_heap_insert(heap, newcost, (void*)adjnum);
+ }
+ }
+}
+
+static int seam_shortest_path(Mesh *me, int source, int target)
+{
+ Heap *heap;
+ EdgeHash *ehash;
+ float *cost;
+ MEdge *med;
+ int a, *nedges, *edges, *prevedge, mednum = -1, nedgeswap = 0;
+ MFace *mf;
+
+ /* mark hidden edges as done, so we don't use them */
+ ehash = BLI_edgehash_new();
+
+ for (a=0, mf=me->mface; a<me->totface; a++, mf++) {
+ if (!(mf->flag & ME_HIDE)) {
+ BLI_edgehash_insert(ehash, mf->v1, mf->v2, NULL);
+ BLI_edgehash_insert(ehash, mf->v2, mf->v3, NULL);
+ if (mf->v4) {
+ BLI_edgehash_insert(ehash, mf->v3, mf->v4, NULL);
+ BLI_edgehash_insert(ehash, mf->v4, mf->v1, NULL);
+ }
+ else
+ BLI_edgehash_insert(ehash, mf->v3, mf->v1, NULL);
+ }
+ }
+
+ for (a=0, med=me->medge; a<me->totedge; a++, med++)
+ if (!BLI_edgehash_haskey(ehash, med->v1, med->v2))
+ med->flag |= ME_SEAM_DONE;
+
+ BLI_edgehash_free(ehash, NULL);
+
+ /* alloc */
+ nedges = MEM_callocN(sizeof(*nedges)*me->totvert+1, "SeamPathNEdges");
+ edges = MEM_mallocN(sizeof(*edges)*me->totedge*2, "SeamPathEdges");
+ prevedge = MEM_mallocN(sizeof(*prevedge)*me->totedge, "SeamPathPrevious");
+ cost = MEM_mallocN(sizeof(*cost)*me->totedge, "SeamPathCost");
+
+ /* count edges, compute adjacent edges offsets and fill adjacent edges */
+ for (a=0, med=me->medge; a<me->totedge; a++, med++) {
+ nedges[med->v1+1]++;
+ nedges[med->v2+1]++;
+ }
+
+ for (a=1; a<me->totvert; a++) {
+ int newswap = nedges[a+1];
+ nedges[a+1] = nedgeswap + nedges[a];
+ nedgeswap = newswap;
+ }
+ nedges[0] = nedges[1] = 0;
+
+ for (a=0, med=me->medge; a<me->totedge; a++, med++) {
+ edges[nedges[med->v1+1]++] = a;
+ edges[nedges[med->v2+1]++] = a;
+
+ cost[a] = 1e20f;
+ prevedge[a] = -1;
+ }
+
+ /* regular dijkstra shortest path, but over edges instead of vertices */
+ heap = BLI_heap_new();
+ BLI_heap_insert(heap, 0.0f, (void*)source);
+ cost[source] = 0.0f;
+
+ while (!BLI_heap_empty(heap)) {
+ mednum = (int)BLI_heap_popmin(heap);
+ med = me->medge + mednum;
+
+ if (mednum == target)
+ break;
+
+ if (med->flag & ME_SEAM_DONE)
+ continue;
+
+ med->flag |= ME_SEAM_DONE;
+
+ seam_add_adjacent(me, heap, mednum, med->v1, nedges, edges, prevedge, cost);
+ seam_add_adjacent(me, heap, mednum, med->v2, nedges, edges, prevedge, cost);
+ }
+
+ MEM_freeN(nedges);
+ MEM_freeN(edges);
+ MEM_freeN(cost);
+ BLI_heap_free(heap, NULL);
+
+ for (a=0, med=me->medge; a<me->totedge; a++, med++)
+ med->flag &= ~ME_SEAM_DONE;
+
+ if (mednum != target) {
+ MEM_freeN(prevedge);
+ return 0;
+ }
+
+ /* follow path back to source and mark as seam */
+ if (mednum == target) {
+ short allseams = 1;
+
+ mednum = target;
+ do {
+ med = me->medge + mednum;
+ if (!(med->flag & ME_SEAM)) {
+ allseams = 0;
+ break;
+ }
+ mednum = prevedge[mednum];
+ } while (mednum != source);
+
+ mednum = target;
+ do {
+ med = me->medge + mednum;
+ if (allseams)
+ med->flag &= ~ME_SEAM;
+ else
+ med->flag |= ME_SEAM;
+ mednum = prevedge[mednum];
+ } while (mednum != -1);
+ }
+
+ MEM_freeN(prevedge);
+ return 1;
+}
+
+static void seam_select(Mesh *me, short *mval, short path)
+{
+ unsigned int index = 0;
+ MEdge *medge, *med;
+ int a, lastindex = -1;
+
+ if (!facesel_edge_pick(me, mval, &index))
+ return;
+
+ for (a=0, med=me->medge; a<me->totedge; a++, med++) {
+ if (med->flag & ME_SEAM_LAST) {
+ lastindex = a;
+ med->flag &= ~ME_SEAM_LAST;
+ break;
+ }
+ }
+
+ medge = me->medge + index;
+ if (!path || (lastindex == -1) || (index == lastindex) ||
+ !seam_shortest_path(me, lastindex, index))
+ medge->flag ^= ME_SEAM;
+ medge->flag |= ME_SEAM_LAST;
+
+ G.f |= G_DRAWSEAMS;
+
+ if (G.rt == 8)
+ unwrap_lscm(1);
+
+ BIF_undo_push("Mark Seam");
+
+ object_tface_flags_changed(OBACT, 1);
+}
+
+void seam_edgehash_insert_face(EdgeHash *ehash, MFace *mf)
+{
+ BLI_edgehash_insert(ehash, mf->v1, mf->v2, NULL);
+ BLI_edgehash_insert(ehash, mf->v2, mf->v3, NULL);
+ if (mf->v4) {
+ BLI_edgehash_insert(ehash, mf->v3, mf->v4, NULL);
+ BLI_edgehash_insert(ehash, mf->v4, mf->v1, NULL);
+ }
+ else
+ BLI_edgehash_insert(ehash, mf->v3, mf->v1, NULL);
+}
+
+void seam_mark_clear_tface(short mode)
+{
+ Mesh *me;
+ MFace *mf;
+ MEdge *med;
+ int a;
+
+ me= get_mesh(OBACT);
+ if(me==0 || me->totface==0) return;
+
+ if (mode == 0)
+ mode = pupmenu("Seams%t|Mark Border Seam %x1|Clear Seam %x2");
+
+ if (mode != 1 && mode != 2)
+ return;
+
+ if (mode == 2) {
+ EdgeHash *ehash = BLI_edgehash_new();
+
+ for (a=0, mf=me->mface; a<me->totface; a++, mf++)
+ if (!(mf->flag & ME_HIDE) && (mf->flag & ME_FACE_SEL))
+ seam_edgehash_insert_face(ehash, mf);
+
+ for (a=0, med=me->medge; a<me->totedge; a++, med++)
+ if (BLI_edgehash_haskey(ehash, med->v1, med->v2))
+ med->flag &= ~ME_SEAM;
+
+ BLI_edgehash_free(ehash, NULL);
+ }
+ else {
+ /* mark edges that are on both selected and deselected faces */
+ EdgeHash *ehash1 = BLI_edgehash_new();
+ EdgeHash *ehash2 = BLI_edgehash_new();
+
+ for (a=0, mf=me->mface; a<me->totface; a++, mf++) {
+ if ((mf->flag & ME_HIDE) || !(mf->flag & ME_FACE_SEL))
+ seam_edgehash_insert_face(ehash1, mf);
+ else
+ seam_edgehash_insert_face(ehash2, mf);
+ }
+
+ for (a=0, med=me->medge; a<me->totedge; a++, med++)
+ if (BLI_edgehash_haskey(ehash1, med->v1, med->v2) &&
+ BLI_edgehash_haskey(ehash2, med->v1, med->v2))
+ med->flag |= ME_SEAM;
+
+ BLI_edgehash_free(ehash1, NULL);
+ BLI_edgehash_free(ehash2, NULL);
+ }
+
+ if (G.rt == 8)
+ unwrap_lscm(1);
+
+ G.f |= G_DRAWSEAMS;
+ BIF_undo_push("Mark Seam");
+
+ object_tface_flags_changed(OBACT, 1);
+}
+
+void face_select()
+{
+ Object *ob;
+ Mesh *me;
+ MFace *mface, *msel;
+ short mval[2];
+ unsigned int a, index;
+
+ /* Get the face under the cursor */
+ ob = OBACT;
+ if (!(ob->lay & G.vd->lay)) {
+ error("The active object is not in this layer");
+ }
+ me = get_mesh(ob);
+ getmouseco_areawin(mval);
+
+ if (G.qual & LR_ALTKEY) {
+ seam_select(me, mval, (G.qual & LR_SHIFTKEY) != 0);
+ return;
+ }
+
+ if (!facesel_face_pick(me, mval, &index, 1)) return;
+
+ msel= (((MFace*)me->mface)+index);
+ if (msel->flag & ME_HIDE) return;
+
+ /* clear flags */
+ mface = me->mface;
+ a = me->totface;
+ if ((G.qual & LR_SHIFTKEY)==0) {
+ while (a--) {
+ mface->flag &= ~ME_FACE_SEL;
+ mface++;
+ }
+ }
+
+ me->act_face = (int)index;
+
+ if (G.qual & LR_SHIFTKEY) {
+ if (msel->flag & ME_FACE_SEL)
+ msel->flag &= ~ME_FACE_SEL;
+ else
+ msel->flag |= ME_FACE_SEL;
+ }
+ else msel->flag |= ME_FACE_SEL;
+
+ /* image window redraw */
+
+ BIF_undo_push("Select UV face");
+
+ object_tface_flags_changed(OBACT, 1);
+}
+
+void face_borderselect()
+{
+ Mesh *me;
+ MFace *mface;
+ rcti rect;
+ struct ImBuf *ibuf;
+ unsigned int *rt;
+ int a, sx, sy, index, val;
+ char *selar;
+
+ me= get_mesh(OBACT);
+ if(me==0) return;
+ if(me->totface==0) return;
+
+ val= get_border(&rect, 3);
+
+ /* why readbuffer here? shouldn't be necessary (maybe a flush or so) */
+ glReadBuffer(GL_BACK);
+#ifdef __APPLE__
+ glReadBuffer(GL_AUX0); /* apple only */
+#endif
+
+ if(val) {
+ selar= MEM_callocN(me->totface+1, "selar");
+
+ sx= (rect.xmax-rect.xmin+1);
+ sy= (rect.ymax-rect.ymin+1);
+ if(sx*sy<=0) return;
+
+ ibuf = IMB_allocImBuf(sx,sy,32,IB_rect,0);
+ rt = ibuf->rect;
+ glReadPixels(rect.xmin+curarea->winrct.xmin, rect.ymin+curarea->winrct.ymin, sx, sy, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
+ if(G.order==B_ENDIAN) IMB_convert_rgba_to_abgr(ibuf);
+
+ a= sx*sy;
+ while(a--) {
+ if(*rt) {
+ index= framebuffer_to_index(*rt);
+ if(index<=me->totface) selar[index]= 1;
+ }
+ rt++;
+ }
+
+ mface= me->mface;
+ for(a=1; a<=me->totface; a++, mface++) {
+ if(selar[a]) {
+ if(mface->flag & ME_HIDE);
+ else {
+ if(val==LEFTMOUSE) mface->flag |= ME_FACE_SEL;
+ else mface->flag &= ~ME_FACE_SEL;
+ }
+ }
+ }
+
+ IMB_freeImBuf(ibuf);
+ MEM_freeN(selar);
+
+ BIF_undo_push("Border Select UV face");
+
+ object_tface_flags_changed(OBACT, 0);
+ }
+#ifdef __APPLE__
+ glReadBuffer(GL_BACK);
+#endif
+}
+
+void uv_autocalc_tface()
+{
+ short mode, i=0, has_pymenu=0; /* pymenu must be bigger then UV_*_MAPPING */
+ BPyMenu *pym;
+ char menu_number[3];
+
+ /* uvmenu, will add python items */
+ char uvmenu[4096]=MENUTITLE("UV Calculation")
+ MENUSTRING("Unwrap", UV_UNWRAP_MAPPING) "|%l|"
+
+ MENUSTRING("Cube Projection", UV_CUBE_MAPPING) "|"
+ MENUSTRING("Cylinder from View", UV_CYL_MAPPING) "|"
+ MENUSTRING("Sphere from View", UV_SPHERE_MAPPING) "|%l|"
+
+ MENUSTRING("Project From View", UV_WINDOW_MAPPING) "|"
+ MENUSTRING("Project from View (Bounds)",UV_BOUNDS_MAPPING) "|%l|"
+
+ MENUSTRING("Reset", UV_RESET_MAPPING);
+
+ /* note that we account for the 10 previous entries with i+10: */
+ for (pym = BPyMenuTable[PYMENU_UVCALCULATION]; pym; pym = pym->next, i++) {
+
+ if (!has_pymenu) {
+ strcat(uvmenu, "|%l");
+ has_pymenu = 1;
+ }
+
+ strcat(uvmenu, "|");
+ strcat(uvmenu, pym->name);
+ strcat(uvmenu, " %x");
+ sprintf(menu_number, "%d", i+10);
+ strcat(uvmenu, menu_number);
+ }
+
+ mode= pupmenu(uvmenu);
+
+ if (mode >= 10) {
+ BPY_menu_do_python(PYMENU_UVCALCULATION, mode - 10);
+ return;
+ }
+
+ switch(mode) {
+ case UV_CUBE_MAPPING:
+ calculate_uv_map(B_UVAUTO_CUBE); break;
+ case UV_CYL_MAPPING:
+ calculate_uv_map(B_UVAUTO_CYLINDER); break;
+ case UV_SPHERE_MAPPING:
+ calculate_uv_map(B_UVAUTO_SPHERE); break;
+ case UV_BOUNDS_MAPPING:
+ calculate_uv_map(B_UVAUTO_BOUNDS); break;
+ case UV_RESET_MAPPING:
+ calculate_uv_map(B_UVAUTO_RESET); break;
+ case UV_WINDOW_MAPPING:
+ calculate_uv_map(B_UVAUTO_WINDOW); break;
+ case UV_UNWRAP_MAPPING:
+ unwrap_lscm(0); break;
+ }
+}
+
+/* Texture Paint */
+
+void set_texturepaint() /* toggle */
+{
+ Object *ob = OBACT;
+ Mesh *me = 0;
+
+ scrarea_queue_headredraw(curarea);
+ if(ob==NULL) return;
+
+ if (object_data_is_libdata(ob)) {
+ error_libdata();
+ return;
+ }
+
+ me= get_mesh(ob);
+
+ if(me)
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+
+ if(G.f & G_TEXTUREPAINT) {
+ G.f &= ~G_TEXTUREPAINT;
+ texpaint_enable_mipmap();
+ }
+ else if (me) {
+ G.f |= G_TEXTUREPAINT;
+
+ if(me->mtface==NULL)
+ make_tfaces(me);
+
+ brush_check_exists(&G.scene->toolsettings->imapaint.brush);
+ texpaint_disable_mipmap();
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+}
+
+static void texpaint_project(Object *ob, float *model, float *proj, float *co, float *pco)
+{
+ VECCOPY(pco, co);
+ pco[3]= 1.0f;
+
+ Mat4MulVecfl(ob->obmat, pco);
+ Mat4MulVecfl((float(*)[4])model, pco);
+ Mat4MulVec4fl((float(*)[4])proj, pco);
+}
+
+static void texpaint_tri_weights(Object *ob, float *v1, float *v2, float *v3, float *co, float *w)
+{
+ float pv1[4], pv2[4], pv3[4], h[3], divw;
+ float model[16], proj[16], wmat[3][3], invwmat[3][3];
+ GLint view[4];
+
+ /* compute barycentric coordinates */
+
+ /* get the needed opengl matrices */
+ glGetIntegerv(GL_VIEWPORT, view);
+ glGetFloatv(GL_MODELVIEW_MATRIX, model);
+ glGetFloatv(GL_PROJECTION_MATRIX, proj);
+ view[0] = view[1] = 0;
+
+ /* project the verts */
+ texpaint_project(ob, model, proj, v1, pv1);
+ texpaint_project(ob, model, proj, v2, pv2);
+ texpaint_project(ob, model, proj, v3, pv3);
+
+ /* do inverse view mapping, see gluProject man page */
+ h[0]= (co[0] - view[0])*2.0f/view[2] - 1;
+ h[1]= (co[1] - view[1])*2.0f/view[3] - 1;
+ h[2]= 1.0f;
+
+ /* solve for (w1,w2,w3)/perspdiv in:
+ h*perspdiv = Project*Model*(w1*v1 + w2*v2 + w3*v3) */
+
+ wmat[0][0]= pv1[0]; wmat[1][0]= pv2[0]; wmat[2][0]= pv3[0];
+ wmat[0][1]= pv1[1]; wmat[1][1]= pv2[1]; wmat[2][1]= pv3[1];
+ wmat[0][2]= pv1[3]; wmat[1][2]= pv2[3]; wmat[2][2]= pv3[3];
+
+ Mat3Inv(invwmat, wmat);
+ Mat3MulVecfl(invwmat, h);
+
+ VECCOPY(w, h);
+
+ /* w is still divided by perspdiv, make it sum to one */
+ divw= w[0] + w[1] + w[2];
+ if(divw != 0.0f)
+ VecMulf(w, 1.0f/divw);
+}
+
+/* compute uv coordinates of mouse in face */
+void texpaint_pick_uv(Object *ob, Mesh *mesh, unsigned int faceindex, short *xy, float *uv)
+{
+ DerivedMesh *dm = mesh_get_derived_final(ob, CD_MASK_BAREMESH);
+ int *index = dm->getFaceDataArray(dm, CD_ORIGINDEX);
+ MTFace *tface = dm->getFaceDataArray(dm, CD_MTFACE), *tf;
+ int numfaces = dm->getNumFaces(dm), a;
+ float p[2], w[3], absw, minabsw;
+ MFace mf;
+ MVert mv[4];
+
+ minabsw = 1e10;
+ uv[0] = uv[1] = 0.0;
+
+ persp(PERSP_VIEW);
+
+ /* test all faces in the derivedmesh with the original index of the picked face */
+ for (a = 0; a < numfaces; a++) {
+ if (index[a] == faceindex) {
+ dm->getFace(dm, a, &mf);
+
+ dm->getVert(dm, mf.v1, &mv[0]);
+ dm->getVert(dm, mf.v2, &mv[1]);
+ dm->getVert(dm, mf.v3, &mv[2]);
+ if (mf.v4)
+ dm->getVert(dm, mf.v4, &mv[3]);
+
+ tf= &tface[a];
+
+ p[0]= xy[0];
+ p[1]= xy[1];
+
+ if (mf.v4) {
+ /* the triangle with the largest absolute values is the one
+ with the most negative weights */
+ texpaint_tri_weights(ob, mv[0].co, mv[1].co, mv[3].co, p, w);
+ absw= fabs(w[0]) + fabs(w[1]) + fabs(w[2]);
+ if(absw < minabsw) {
+ uv[0]= tf->uv[0][0]*w[0] + tf->uv[1][0]*w[1] + tf->uv[3][0]*w[2];
+ uv[1]= tf->uv[0][1]*w[0] + tf->uv[1][1]*w[1] + tf->uv[3][1]*w[2];
+ minabsw = absw;
+ }
+
+ texpaint_tri_weights(ob, mv[1].co, mv[2].co, mv[3].co, p, w);
+ absw= fabs(w[0]) + fabs(w[1]) + fabs(w[2]);
+ if (absw < minabsw) {
+ uv[0]= tf->uv[1][0]*w[0] + tf->uv[2][0]*w[1] + tf->uv[3][0]*w[2];
+ uv[1]= tf->uv[1][1]*w[0] + tf->uv[2][1]*w[1] + tf->uv[3][1]*w[2];
+ minabsw = absw;
+ }
+ }
+ else {
+ texpaint_tri_weights(ob, mv[0].co, mv[1].co, mv[2].co, p, w);
+ absw= fabs(w[0]) + fabs(w[1]) + fabs(w[2]);
+ if (absw < minabsw) {
+ uv[0]= tf->uv[0][0]*w[0] + tf->uv[1][0]*w[1] + tf->uv[2][0]*w[2];
+ uv[1]= tf->uv[0][1]*w[0] + tf->uv[1][1]*w[1] + tf->uv[2][1]*w[2];
+ minabsw = absw;
+ }
+ }
+ }
+ }
+
+ dm->release(dm);
+}
diff --git a/source/blender/src/editfont.c b/source/blender/src/editfont.c
new file mode 100644
index 00000000000..a3de5d03283
--- /dev/null
+++ b/source/blender/src/editfont.c
@@ -0,0 +1,1289 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <wchar.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef WIN32
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+
+#include "MTC_matrixops.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "DNA_curve_types.h"
+#include "DNA_object_types.h"
+#include "DNA_vfont_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_text_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_depsgraph.h"
+#include "BKE_font.h"
+#include "BKE_object.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_editfont.h"
+#include "BIF_editmode_undo.h"
+#include "BIF_toolbox.h"
+#include "BIF_space.h"
+#include "BIF_mywindow.h"
+
+#include "BDR_editobject.h"
+
+#include "mydevice.h"
+
+#include "blendef.h"
+
+#define MAXTEXT 32766
+
+/* -- prototypes --------*/
+VFont *get_builtin_font(void);
+
+int textediting=0;
+
+extern struct SelBox *selboxes; /* from blenkernel/font.c */
+
+static char findaccent(char char1, unsigned int code)
+{
+ char new= 0;
+
+ if(char1=='a') {
+ if(code=='`') new= 224;
+ else if(code==39) new= 225;
+ else if(code=='^') new= 226;
+ else if(code=='~') new= 227;
+ else if(code=='"') new= 228;
+ else if(code=='o') new= 229;
+ else if(code=='e') new= 230;
+ else if(code=='-') new= 170;
+ }
+ else if(char1=='c') {
+ if(code==',') new= 231;
+ if(code=='|') new= 162;
+ }
+ else if(char1=='e') {
+ if(code=='`') new= 232;
+ else if(code==39) new= 233;
+ else if(code=='^') new= 234;
+ else if(code=='"') new= 235;
+ }
+ else if(char1=='i') {
+ if(code=='`') new= 236;
+ else if(code==39) new= 237;
+ else if(code=='^') new= 238;
+ else if(code=='"') new= 239;
+ }
+ else if(char1=='n') {
+ if(code=='~') new= 241;
+ }
+ else if(char1=='o') {
+ if(code=='`') new= 242;
+ else if(code==39) new= 243;
+ else if(code=='^') new= 244;
+ else if(code=='~') new= 245;
+ else if(code=='"') new= 246;
+ else if(code=='/') new= 248;
+ else if(code=='-') new= 186;
+ else if(code=='e') new= 143;
+ }
+ else if(char1=='s') {
+ if(code=='s') new= 167;
+ }
+ else if(char1=='u') {
+ if(code=='`') new= 249;
+ else if(code==39) new= 250;
+ else if(code=='^') new= 251;
+ else if(code=='"') new= 252;
+ }
+ else if(char1=='y') {
+ if(code==39) new= 253;
+ else if(code=='"') new= 255;
+ }
+ else if(char1=='A') {
+ if(code=='`') new= 192;
+ else if(code==39) new= 193;
+ else if(code=='^') new= 194;
+ else if(code=='~') new= 195;
+ else if(code=='"') new= 196;
+ else if(code=='o') new= 197;
+ else if(code=='e') new= 198;
+ }
+ else if(char1=='C') {
+ if(code==',') new= 199;
+ }
+ else if(char1=='E') {
+ if(code=='`') new= 200;
+ else if(code==39) new= 201;
+ else if(code=='^') new= 202;
+ else if(code=='"') new= 203;
+ }
+ else if(char1=='I') {
+ if(code=='`') new= 204;
+ else if(code==39) new= 205;
+ else if(code=='^') new= 206;
+ else if(code=='"') new= 207;
+ }
+ else if(char1=='N') {
+ if(code=='~') new= 209;
+ }
+ else if(char1=='O') {
+ if(code=='`') new= 210;
+ else if(code==39) new= 211;
+ else if(code=='^') new= 212;
+ else if(code=='~') new= 213;
+ else if(code=='"') new= 214;
+ else if(code=='/') new= 216;
+ else if(code=='e') new= 141;
+ }
+ else if(char1=='U') {
+ if(code=='`') new= 217;
+ else if(code==39) new= 218;
+ else if(code=='^') new= 219;
+ else if(code=='"') new= 220;
+ }
+ else if(char1=='Y') {
+ if(code==39) new= 221;
+ }
+ else if(char1=='1') {
+ if(code=='4') new= 188;
+ if(code=='2') new= 189;
+ }
+ else if(char1=='3') {
+ if(code=='4') new= 190;
+ }
+ else if(char1==':') {
+ if(code=='-') new= 247;
+ }
+ else if(char1=='-') {
+ if(code==':') new= 247;
+ if(code=='|') new= 135;
+ if(code=='+') new= 177;
+ }
+ else if(char1=='|') {
+ if(code=='-') new= 135;
+ if(code=='=') new= 136;
+ }
+ else if(char1=='=') {
+ if(code=='|') new= 136;
+ }
+ else if(char1=='+') {
+ if(code=='-') new= 177;
+ }
+
+ if(new) return new;
+ else return char1;
+}
+
+wchar_t *copybuf=NULL;
+wchar_t *copybufinfo=NULL;
+
+static wchar_t *textbuf=NULL;
+static CharInfo *textbufinfo=NULL;
+static wchar_t *oldstr=NULL;
+static CharInfo *oldstrinfo=NULL;
+
+void update_string(Curve *cu)
+{
+ int len;
+
+ // Free the old curve string
+ MEM_freeN(cu->str);
+
+ // Calculate the actual string length in UTF-8 variable characters
+ len = wcsleninu8(textbuf);
+
+ // Alloc memory for UTF-8 variable char length string
+ cu->str = MEM_callocN(len + sizeof(wchar_t), "str");
+
+ // Copy the wchar to UTF-8
+ wcs2utf8s(cu->str, textbuf);
+}
+
+static int insert_into_textbuf(Curve *cu, unsigned long c)
+{
+ if (cu->len<MAXTEXT-1) {
+ int x;
+
+ for(x= cu->len; x>cu->pos; x--) textbuf[x]= textbuf[x-1];
+ for(x= cu->len; x>cu->pos; x--) textbufinfo[x]= textbufinfo[x-1];
+ textbuf[cu->pos]= c;
+ textbufinfo[cu->pos] = cu->curinfo;
+ textbufinfo[cu->pos].kern = 0;
+ if (G.obedit->actcol>0)
+ textbufinfo[cu->pos].mat_nr = G.obedit->actcol;
+ else
+ textbufinfo[cu->pos].mat_nr = 0;
+
+ cu->pos++;
+ cu->len++;
+ textbuf[cu->len]='\0';
+
+ update_string(cu);
+
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+void add_lorem(void)
+{
+ char *p, *p2;
+ int i;
+ Curve *cu=G.obedit->data;
+ static char* lastlorem;
+
+ if (lastlorem)
+ p= lastlorem;
+ else
+ p= BIF_lorem;
+
+ i= rand()/(RAND_MAX/6)+4;
+
+ for (p2=p; *p2 && i; p2++) {
+ insert_into_textbuf(cu, *p2);
+ if (*p2=='.') i--;
+ }
+ lastlorem = p2+1;
+ if (strlen(lastlorem)<5) lastlorem = BIF_lorem;
+
+ insert_into_textbuf(cu, '\n');
+ insert_into_textbuf(cu, '\n');
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+void load_3dtext_fs(char *file)
+{
+ FILE *fp;
+ int filelen;
+ char *strp;
+ Curve *cu=G.obedit->data;
+
+ fp= fopen(file, "r");
+ if (!fp) return;
+
+ fseek(fp, 0L, SEEK_END);
+ filelen = ftell(fp);
+ fseek(fp, 0L, SEEK_SET);
+
+ strp = MEM_callocN(filelen+4, "tempstr");
+
+ filelen = fread(strp, 1, filelen, fp);
+ fclose(fp);
+ strp[filelen]= 0;
+
+ if(cu->len+filelen<MAXTEXT)
+ {
+ int tmplen;
+ wchar_t *mem = MEM_callocN((sizeof(wchar_t)*filelen)+(4*sizeof(wchar_t)), "temporary");
+ tmplen = utf8towchar_(mem, strp);
+ wcscat(textbuf, mem);
+ MEM_freeN(mem);
+ cu->len += tmplen;
+ cu->pos= cu->len;
+ }
+ MEM_freeN(strp);
+
+ update_string(cu);
+
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+VFont *get_builtin_font(void)
+{
+ VFont *vf;
+
+ for (vf= G.main->vfont.first; vf; vf= vf->id.next)
+ if (BLI_streq(vf->name, "<builtin>"))
+ return vf;
+
+ return load_vfont("<builtin>");
+}
+
+
+void txt_export_to_object(struct Text *text)
+{
+ ID *id;
+ Curve *cu;
+ struct TextLine *tmp;
+ int nchars = 0;
+// char sdir[FILE_MAXDIR];
+// char sfile[FILE_MAXFILE];
+
+ if(!text) return;
+
+ id = (ID *)text;
+
+ if (G.obedit && G.obedit->type==OB_FONT) return;
+ check_editmode(OB_FONT);
+
+ add_object(OB_FONT);
+
+ base_init_from_view3d(BASACT, G.vd);
+ G.obedit= BASACT->object;
+ where_is_object(G.obedit);
+
+ cu= G.obedit->data;
+
+/*
+// renames object, careful with long filenames.
+
+ if (text->name) {
+ //ID *find_id(char *type, char *name)
+ BLI_split_dirfile(text->name, sdir, sfile);
+// rename_id((ID *)G.obedit, sfile);
+ rename_id((ID *)cu, sfile);
+ id->us++;
+ }
+*/
+ cu->vfont= get_builtin_font();
+ cu->vfont->id.us++;
+
+ tmp= text->lines.first;
+ while(cu->len<MAXTEXT && tmp) {
+ nchars += strlen(tmp->line) + 1;
+ tmp = tmp->next;
+ }
+
+ if(cu->str) MEM_freeN(cu->str);
+ if(cu->strinfo) MEM_freeN(cu->strinfo);
+
+ cu->str= MEM_mallocN(nchars+4, "str");
+ cu->strinfo= MEM_callocN((nchars+4)*sizeof(CharInfo), "strinfo");
+ cu->totbox= cu->actbox= 1;
+ cu->tb= MEM_callocN(MAXTEXTBOX*sizeof(TextBox), "textbox");
+ cu->tb[0].w = cu->tb[0].h = 0.0;
+
+ tmp= text->lines.first;
+ strcpy(cu->str, tmp->line);
+ cu->len= strlen(tmp->line);
+ cu->pos= cu->len;
+
+ tmp= tmp->next;
+
+ while(cu->len<MAXTEXT && tmp) {
+ strcat(cu->str, "\n");
+ strcat(cu->str, tmp->line);
+ cu->len+= strlen(tmp->line) + 1;
+ cu->pos= cu->len;
+ tmp= tmp->next;
+ }
+
+ make_editText();
+ exit_editmode(EM_FREEDATA|EM_WAITCURSOR);
+
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+
+void txt_export_to_objects(struct Text *text)
+{
+ ID *id;
+ Curve *cu;
+ struct TextLine *curline;
+ int nchars;
+ int linenum = 0;
+ float offset[3] = {0.0,0.0,0.0};
+
+ if(!text) return;
+
+ id = (ID *)text;
+
+ if (G.obedit && G.obedit->type==OB_FONT) return;
+ check_editmode(OB_FONT);
+
+ curline = text->lines.first;
+ while(curline){
+ /*skip lines with no text, but still make space for them*/
+ if(curline->line[0] == '\0'){
+ linenum++;
+ curline = curline->next;
+ continue;
+ }
+
+ nchars = 0;
+ add_object(OB_FONT);
+
+ base_init_from_view3d(BASACT, G.vd);
+ G.obedit= BASACT->object;
+ where_is_object(G.obedit);
+
+ /* Do the translation */
+ offset[0] = 0;
+ offset[1] = -linenum;
+ offset[2] = 0;
+
+ Mat4Mul3Vecfl(G.vd->viewinv,offset);
+
+ G.obedit->loc[0] += offset[0];
+ G.obedit->loc[1] += offset[1];
+ G.obedit->loc[2] += offset[2];
+ /* End Translation */
+
+ cu= G.obedit->data;
+
+ cu->vfont= get_builtin_font();
+ cu->vfont->id.us++;
+
+ nchars = strlen(curline->line) + 1;
+
+ if(cu->str) MEM_freeN(cu->str);
+ if(cu->strinfo) MEM_freeN(cu->strinfo);
+
+ cu->str= MEM_mallocN(nchars+4, "str");
+ cu->strinfo= MEM_callocN((nchars+4)*sizeof(CharInfo), "strinfo");
+ cu->totbox= cu->actbox= 1;
+ cu->tb= MEM_callocN(MAXTEXTBOX*sizeof(TextBox), "textbox");
+ cu->tb[0].w = cu->tb[0].h = 0.0;
+
+ strcpy(cu->str, curline->line);
+ cu->len= strlen(curline->line);
+ cu->pos= cu->len;
+
+ make_editText();
+ exit_editmode(EM_FREEDATA|EM_WAITCURSOR);
+
+ linenum++;
+ curline = curline->next;
+ }
+ BIF_undo_push("Add Text as Objects");
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static short next_word(Curve *cu)
+{
+ short s;
+ for (s=cu->pos; (cu->str[s]) && (cu->str[s]!=' ') && (cu->str[s]!='\n') &&
+ (cu->str[s]!=1) && (cu->str[s]!='\r'); s++);
+ if (cu->str[s]) return(s+1); else return(s);
+}
+
+static short prev_word(Curve *cu)
+{
+ short s;
+
+ if (cu->pos==0) return(0);
+ for (s=cu->pos-2; (cu->str[s]) && (cu->str[s]!=' ') && (cu->str[s]!='\n') &&
+ (cu->str[s]!=1) && (cu->str[s]!='\r'); s--);
+ if (cu->str[s]) return(s+1); else return(s);
+}
+
+
+
+static int killselection(int ins) /* 1 == new character */
+{
+ int selend, selstart, direction;
+ Curve *cu= G.obedit->data;
+ int offset = 0;
+ int getfrom;
+
+ direction = getselection(&selstart, &selend);
+ if (direction) {
+ int size;
+ if (ins) offset = 1;
+ if (cu->pos >= selstart) cu->pos = selstart+offset;
+ if ((direction == -1) && ins) {
+ selstart++;
+ selend++;
+ }
+ getfrom = selend+offset;
+ if (ins==0) getfrom++;
+ size = (cu->len * sizeof(wchar_t)) - (selstart * sizeof(wchar_t)) + (offset*sizeof(wchar_t));
+ memmove(textbuf+selstart, textbuf+getfrom, size);
+ memmove(textbufinfo+selstart, textbufinfo+getfrom, ((cu->len-selstart)+offset)*sizeof(CharInfo));
+ cu->len -= (selend-selstart)+offset;
+ cu->selstart = cu->selend = 0;
+ }
+ return(direction);
+}
+
+static void copyselection(void)
+{
+ int selstart, selend;
+
+ if (getselection(&selstart, &selend)) {
+ memcpy(copybuf, textbuf+selstart, ((selend-selstart)+1)*sizeof(wchar_t));
+ copybuf[(selend-selstart)+1]=0;
+ memcpy(copybufinfo, textbufinfo+selstart, ((selend-selstart)+1)*sizeof(CharInfo));
+ }
+}
+
+static void pasteselection(void)
+{
+ Curve *cu= G.obedit->data;
+
+ int len= wcslen(copybuf);
+
+ // Verify that the copy buffer => [copy buffer len] + cu->len < MAXTEXT
+ if(cu->len + len <= MAXTEXT)
+ {
+ if (len) {
+ int size = (cu->len * sizeof(wchar_t)) - (cu->pos*sizeof(wchar_t)) + sizeof(wchar_t);
+ memmove(textbuf+cu->pos+len, textbuf+cu->pos, size);
+ memcpy(textbuf+cu->pos, copybuf, len * sizeof(wchar_t));
+
+ memmove(textbufinfo+cu->pos+len, textbufinfo+cu->pos, (cu->len-cu->pos+1)*sizeof(CharInfo));
+ memcpy(textbufinfo+cu->pos, copybufinfo, len*sizeof(CharInfo));
+
+ cu->len += len;
+ cu->pos += len;
+ }
+ }
+ else
+ {
+ error("Text too long");
+ }
+}
+
+int style_to_sel(int style, int toggle)
+{
+ int selstart, selend;
+ int i;
+ Curve *cu;
+
+ if (G.obedit && (G.obedit->type == OB_FONT)) {
+ cu= G.obedit->data;
+
+ if (getselection(&selstart, &selend)) {
+ for (i=selstart; i<=selend; i++) {
+ if (toggle==0) {
+ textbufinfo[i].flag &= ~style;
+ } else {
+ textbufinfo[i].flag |= style;
+ }
+ }
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int mat_to_sel(void) {
+ int selstart, selend;
+ int i;
+ Curve *cu;
+
+ if (G.obedit && (G.obedit->type == OB_FONT)) {
+ cu= G.obedit->data;
+
+ if (getselection(&selstart, &selend)) {
+ for (i=selstart; i<=selend; i++) {
+ textbufinfo[i].mat_nr = G.obedit->actcol;
+ }
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void do_textedit(unsigned short event, short val, unsigned long _ascii)
+{
+ Curve *cu;
+ static int accentcode= 0;
+ int x, doit=0, cursmove=0;
+ unsigned long ascii = _ascii;
+ short kern;
+
+ cu= G.obedit->data;
+
+ if(ascii) {
+
+ /* handle case like TAB (TAB==9) */
+ if( (ascii > 31 && ascii < 254 && ascii != 127) || (ascii==13) || (ascii==10) || (ascii==8)) {
+
+ if(accentcode) {
+ if(cu->pos>0) textbuf[cu->pos-1]= findaccent(textbuf[cu->pos-1], ascii);
+ accentcode= 0;
+ }
+ else if(cu->len<MAXTEXT-1) {
+ if(G.qual & LR_ALTKEY ) {
+
+ /* might become obsolete, apple has default values for this, other OS's too? */
+
+ if(ascii=='t') ascii= 137;
+ else if(ascii=='c') ascii= 169;
+ else if(ascii=='f') ascii= 164;
+ else if(ascii=='g') ascii= 176;
+ else if(ascii=='l') ascii= 163;
+ else if(ascii=='r') ascii= 174;
+ else if(ascii=='s') ascii= 223;
+ else if(ascii=='v') ascii= 1001;
+ else if(ascii=='y') ascii= 165;
+ else if(ascii=='.') ascii= 138;
+ else if(ascii=='1') ascii= 185;
+ else if(ascii=='2') ascii= 178;
+ else if(ascii=='3') ascii= 179;
+ else if(ascii=='%') ascii= 139;
+ else if(ascii=='?') ascii= 191;
+ else if(ascii=='!') ascii= 161;
+ else if(ascii=='x') ascii= 215;
+ else if(ascii=='>') ascii= 187;
+ else if(ascii=='<') ascii= 171;
+ }
+ if(ascii==1001) {
+ int file, filelen;
+ char *strp;
+
+/* this should be solved by clipboard support */
+#ifdef __WIN32_DISABLED
+ file= open("C:\\windows\\temp\\cutbuf", O_BINARY|O_RDONLY);
+#else
+ file= open("/tmp/.cutbuffer", O_BINARY|O_RDONLY);
+#endif
+ if(file>0) {
+
+ filelen = BLI_filesize(file);
+
+ strp= MEM_mallocN(filelen+4, "tempstr");
+ read(file, strp, filelen);
+ close(file);
+ strp[filelen]= 0;
+
+ if(cu->len+filelen<MAXTEXT) {
+ int tmplen;
+ wchar_t *mem = MEM_callocN((sizeof(wchar_t)*filelen)+(4*sizeof(wchar_t)), "temporary");
+ tmplen = utf8towchar_(mem, strp);
+ wcscat(textbuf, mem);
+ MEM_freeN(mem);
+ cu->len += tmplen;
+ cu->pos= cu->len;
+ }
+ MEM_freeN(strp);
+ }
+ }
+ else {
+ insert_into_textbuf(cu, ascii);
+ }
+ }
+
+ killselection(1);
+
+ doit= 1;
+ }
+ else
+ {
+ insert_into_textbuf(cu, ascii);
+ doit = 1;
+ }
+ }
+ else if(val) {
+ cursmove= 0;
+
+ switch(event) {
+ case ENDKEY:
+ if ((G.qual & LR_SHIFTKEY) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
+ while(cu->pos<cu->len) {
+ if( textbuf[cu->pos]==0) break;
+ if( textbuf[cu->pos]=='\n') break;
+ if( textbufinfo[cu->pos].flag & CU_WRAP ) break;
+ cu->pos++;
+ }
+ cursmove=FO_CURS;
+ break;
+
+ case HOMEKEY:
+ if ((G.qual & LR_SHIFTKEY) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
+ while(cu->pos>0) {
+ if( textbuf[cu->pos-1]=='\n') break;
+ if( textbufinfo[cu->pos-1].flag & CU_WRAP ) break;
+ cu->pos--;
+ }
+ cursmove=FO_CURS;
+ break;
+
+ case RETKEY:
+ if(G.qual & LR_CTRLKEY) {
+ insert_into_textbuf(cu, 1);
+ if (textbuf[cu->pos]!='\n') insert_into_textbuf(cu, '\n');
+ }
+ else {
+ insert_into_textbuf(cu, '\n');
+ }
+ cu->selstart = cu->selend = 0;
+ doit= 1;
+ break;
+
+ case RIGHTARROWKEY:
+ if ((G.qual & LR_SHIFTKEY) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
+ if (G.qual & LR_CTRLKEY) {
+ cu->pos= next_word(cu);
+ cursmove= FO_CURS;
+ }
+ else if (G.qual & LR_ALTKEY) {
+ kern = textbufinfo[cu->pos-1].kern;
+ kern += 1;
+ if (kern>20) kern = 20;
+ textbufinfo[cu->pos-1].kern = kern;
+ doit = 1;
+ }
+ else {
+ cu->pos++;
+ cursmove= FO_CURS;
+ }
+
+ break;
+
+ case LEFTARROWKEY:
+ if ((G.qual & LR_SHIFTKEY) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
+ if (G.qual & LR_CTRLKEY) {
+ cu->pos= prev_word(cu);
+ cursmove= FO_CURS;
+ }
+ else if (G.qual & LR_ALTKEY) {
+ kern = textbufinfo[cu->pos-1].kern;
+ kern -= 1;
+ if (kern<-20) kern = -20;
+ textbufinfo[cu->pos-1].kern = kern;
+ doit = 1;
+ }
+ else {
+ cu->pos--;
+ cursmove=FO_CURS;
+ }
+ break;
+
+ case UPARROWKEY:
+ if ((G.qual & LR_SHIFTKEY) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
+ if(G.qual & LR_ALTKEY) {
+ if (cu->pos && textbuf[cu->pos - 1] < 255) {
+ textbuf[cu->pos - 1]++;
+ doit= 1;
+ }
+ }
+ else cursmove=FO_CURSUP;
+ break;
+
+ case PAGEUPKEY:
+ if ((G.qual & LR_SHIFTKEY) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
+ cursmove=FO_PAGEUP;
+ break;
+
+ case DOWNARROWKEY:
+ if ((G.qual & LR_SHIFTKEY) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
+ if(G.qual & LR_ALTKEY) {
+ if (cu->pos && textbuf[cu->pos - 1] > 1) {
+ textbuf[cu->pos - 1]--;
+ doit= 1;
+ }
+ }
+ else cursmove= FO_CURSDOWN;
+ break;
+
+ case PAGEDOWNKEY:
+ if ((G.qual & LR_SHIFTKEY) && (cu->selstart==0)) cu->selstart = cu->selend = cu->pos+1;
+ cursmove=FO_PAGEDOWN;
+ break;
+
+ case BACKSPACEKEY:
+ if(cu->len!=0) {
+ if(G.qual & LR_ALTKEY) {
+ if(cu->pos>0) accentcode= 1;
+ }
+ else if (G.qual & LR_CTRLKEY) {
+ cu->len = cu->pos = 0;
+ textbuf[0]= 0;
+ doit= 1;
+ }
+ else {
+ if (killselection(0)==0) {
+ if (cu->pos>0) {
+ for(x=cu->pos;x<=cu->len;x++) textbuf[x-1]= textbuf[x];
+ for(x=cu->pos;x<=cu->len;x++) textbufinfo[x-1]= textbufinfo[x];
+ cu->pos--;
+ textbuf[--cu->len]='\0';
+ doit=1;
+ }
+ } else doit=1;
+ }
+ }
+ break;
+
+ case DELKEY:
+ if(cu->len!=0) {
+ if (killselection(0)==0) {
+ if(cu->pos<cu->len) {
+ for(x=cu->pos;x<cu->len;x++) textbuf[x]= textbuf[x+1];
+ for(x=cu->pos;x<cu->len;x++) textbufinfo[x]= textbufinfo[x+1];
+ textbuf[--cu->len]='\0';
+ doit=1;
+ }
+ } else doit=1;
+ }
+ break;
+
+ case IKEY:
+ if (G.qual & LR_CTRLKEY) {
+ cu->curinfo.flag ^= CU_ITALIC;
+ if (style_to_sel(CU_ITALIC, cu->curinfo.flag & CU_ITALIC)) doit= 1;
+ allqueue(REDRAWBUTSEDIT, 0);
+ }
+ break;
+
+ case BKEY:
+ if (G.qual & LR_CTRLKEY) {
+ cu->curinfo.flag ^= CU_BOLD;
+ if (style_to_sel(CU_BOLD, cu->curinfo.flag & CU_BOLD)) doit= 1;
+ allqueue(REDRAWBUTSEDIT, 0);
+ }
+ break;
+
+ case UKEY:
+ if (G.qual & LR_CTRLKEY) {
+ cu->curinfo.flag ^= CU_UNDERLINE;
+ if (style_to_sel(CU_UNDERLINE, cu->curinfo.flag & CU_UNDERLINE)) doit= 1;
+ allqueue(REDRAWBUTSEDIT, 0);
+ }
+ break;
+
+ case XKEY:
+ if (G.qual & LR_CTRLKEY) {
+ copyselection();
+ killselection(0);
+ doit= 1;
+ }
+ break;
+
+ case CKEY:
+ if (G.qual & LR_CTRLKEY) {
+ copyselection();
+ }
+ break;
+
+ case VKEY:
+ if (G.qual & LR_CTRLKEY) {
+ pasteselection();
+ doit= 1;
+ }
+ break;
+
+ }
+
+ if(cursmove) {
+ if ((G.qual & LR_SHIFTKEY)==0) {
+ if (cu->selstart) {
+ cu->selstart = cu->selend = 0;
+ update_string(cu);
+ text_to_curve(G.obedit, FO_SELCHANGE);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ }
+ if(cu->pos>cu->len) cu->pos= cu->len;
+ else if(cu->pos>=MAXTEXT) cu->pos= MAXTEXT;
+ else if(cu->pos<0) cu->pos= 0;
+ }
+ }
+ if(doit || cursmove) {
+
+ if (cu->pos) {
+ cu->curinfo = textbufinfo[cu->pos-1];
+ } else cu->curinfo = textbufinfo[0];
+
+ if (G.obedit->totcol>0) {
+ G.obedit->actcol = textbufinfo[cu->pos-1].mat_nr;
+ }
+ allqueue(REDRAWBUTSEDIT, 0);
+ update_string(cu);
+ text_to_curve(G.obedit, cursmove);
+ if (cursmove && (G.qual & LR_SHIFTKEY)) {
+ cu->selend = cu->pos;
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ }
+ if(cursmove==0) {
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ }
+
+ BIF_undo_push("Textedit");
+ allqueue(REDRAWVIEW3D, 0);
+ }
+}
+
+void paste_unicodeText(char *filename)
+{
+ Curve *cu= G.obedit->data;
+ int filelen, doit= 0;
+ char *strp;
+ FILE *fp = NULL;
+
+ fp= fopen(filename, "r");
+
+ if(fp) {
+
+ fseek( fp, 0L, SEEK_END );
+ filelen = ftell( fp );
+ fseek( fp, 0L, SEEK_SET );
+
+ strp= MEM_mallocN(filelen+4, "tempstr");
+ //fread() instead of read(),
+ //because windows read() converts text to DOS \r\n linebreaks
+ //causing double linebreaks in the 3d text
+ filelen = fread(strp, 1, filelen, fp);
+ fclose(fp);
+ strp[filelen]= 0;
+
+
+ if(cu->len+filelen<MAXTEXT)
+ {
+ int tmplen;
+ wchar_t *mem = MEM_callocN((sizeof(wchar_t)*filelen)+(4*sizeof(wchar_t)), "temporary");
+ tmplen = utf8towchar_(mem, strp);
+// mem =utf8s2wc(strp);
+ wcscat(textbuf, mem);
+ MEM_freeN(mem);
+ cu->len += tmplen;
+ cu->pos= cu->len;
+ }
+ MEM_freeN(strp);
+ doit = 1;
+ }
+ if(doit) {
+ update_string(cu);
+ text_to_curve(G.obedit, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ BIF_undo_push("Paste text");
+ }
+}
+
+void paste_editText(void)
+{
+ Curve *cu= G.obedit->data;
+ int filelen, doit= 0;
+ char *strp;
+ FILE *fp = NULL;
+
+#ifdef WIN32
+ fp= fopen("C:\\windows\\temp\\cutbuf.txt", "r");
+
+// The following is more likely to work on all Win32 installations.
+// suggested by Douglas Toltzman. Needs windows include files...
+/*
+ char tempFileName[MAX_PATH];
+ DWORD pathlen;
+ static const char cutbufname[]="cutbuf.txt";
+
+ if ((pathlen=GetTempPath(sizeof(tempFileName),tempFileName)) > 0 &&
+ pathlen + sizeof(cutbufname) <= sizeof(tempFileName))
+ {
+ strcat(tempFileName,cutbufname);
+ file= open(tempFileName, O_BINARY|O_RDONLY);
+ }
+*/
+#else
+ fp= fopen("/tmp/.cutbuffer", "r");
+#endif
+
+ if(fp) {
+
+ fseek(fp, 0L, SEEK_END);
+ filelen = ftell( fp );
+ fseek(fp, 0L, SEEK_SET);
+
+ strp= MEM_mallocN(filelen+4, "tempstr");
+ // fread() instead of read(),
+ // because windows read() converts text to DOS \r\n linebreaks
+ // causing double linebreaks in the 3d text
+ filelen = fread(strp, 1, filelen, fp);
+ fclose(fp);
+ strp[filelen]= 0;
+
+ if(cu->len+filelen<MAXTEXT) {
+ int tmplen;
+ wchar_t *mem = MEM_callocN((sizeof(wchar_t) * filelen) + (4 * sizeof(wchar_t)), "temporary");
+ tmplen = utf8towchar_(mem, strp);
+ wcscat(textbuf, mem);
+ MEM_freeN(mem);
+ cu->len += tmplen;
+ cu->pos= cu->len;
+ }
+ MEM_freeN(strp);
+ doit = 1;
+ }
+ if(doit) {
+ update_string(cu);
+ text_to_curve(G.obedit, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ BIF_undo_push("Paste text");
+ }
+}
+
+
+void make_editText(void)
+{
+ Curve *cu;
+ cu= G.obedit->data;
+
+ if(textbuf==NULL) textbuf= MEM_callocN((MAXTEXT+4)*sizeof(wchar_t), "texteditbuf");
+ if(textbufinfo==NULL) textbufinfo= MEM_callocN((MAXTEXT+4)*sizeof(CharInfo), "texteditbufinfo");
+ if(copybuf==NULL) copybuf= MEM_callocN((MAXTEXT+4)*sizeof(wchar_t), "texteditcopybuf");
+ if(copybufinfo==NULL) copybufinfo= MEM_callocN((MAXTEXT+4)*sizeof(CharInfo), "texteditcopybufinfo");
+ if(oldstr==NULL) oldstr= MEM_callocN((MAXTEXT+4)*sizeof(wchar_t), "oldstrbuf");
+
+ // Convert the original text to wchar_t
+ utf8towchar_(textbuf, cu->str);
+ wcscpy(oldstr, textbuf);
+
+ cu->len= wcslen(textbuf);
+
+ memcpy(textbufinfo, cu->strinfo, (cu->len)*sizeof(CharInfo));
+
+ oldstrinfo= cu->strinfo;
+ cu->strinfo= textbufinfo;
+
+ if(cu->pos>cu->len) cu->pos= cu->len;
+
+ if (cu->pos) {
+ cu->curinfo = textbufinfo[cu->pos-1];
+ } else cu->curinfo = textbufinfo[0];
+
+ // Convert to UTF-8
+ update_string(cu);
+
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+
+ textediting= 1;
+ BIF_undo_push("Original");
+}
+
+
+void load_editText(void)
+{
+ Curve *cu;
+
+ cu= G.obedit->data;
+
+ MEM_freeN(oldstr);
+ oldstr= NULL;
+ MEM_freeN(oldstrinfo);
+ oldstrinfo= NULL;
+
+ update_string(cu);
+
+ cu->strinfo= MEM_callocN((cu->len+4)*sizeof(CharInfo), "texteditinfo");
+ memcpy(cu->strinfo, textbufinfo, (cu->len)*sizeof(CharInfo));
+
+ cu->len= strlen(cu->str);
+
+ /* this memory system is weak... */
+ MEM_freeN(textbuf);
+ MEM_freeN(textbufinfo);
+ textbuf= NULL;
+ textbufinfo= NULL;
+
+ if (selboxes) {
+ MEM_freeN(selboxes);
+ selboxes= NULL;
+ }
+
+ textediting= 0;
+
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+
+}
+
+
+void remake_editText(void)
+{
+ Curve *cu;
+
+ if(okee("Reload original text")==0) return;
+
+ // Copy the oldstr to textbuf temporary global variable
+ wcscpy(textbuf, oldstr);
+
+ // Set the object length and position
+ cu= G.obedit->data;
+ cu->len= wcslen(textbuf);
+ if(cu->pos>cu->len) cu->pos= cu->len;
+
+ update_string(cu);
+
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+
+ BIF_undo_push("Reload");
+}
+
+
+void free_editText(void)
+{
+ if(oldstr) MEM_freeN(oldstr);
+ if(oldstrinfo) MEM_freeN(oldstrinfo);
+ if(textbuf) MEM_freeN(textbuf);
+ textbuf = oldstr = NULL;
+ textbufinfo = oldstrinfo = NULL;
+ textediting= 0;
+}
+
+
+void add_primitiveFont(int dummy_argument)
+{
+ Curve *cu;
+
+ if (G.obedit && G.obedit->type==OB_FONT) return;
+ check_editmode(OB_FONT);
+
+ add_object_draw(OB_FONT);
+ base_init_from_view3d(BASACT, G.vd);
+
+ where_is_object(BASACT->object);
+
+ cu= BASACT->object->data;
+
+ cu->vfont= cu->vfontb= cu->vfonti= cu->vfontbi= get_builtin_font();
+ cu->vfont->id.us+=4;
+ cu->str= MEM_mallocN(12, "str");
+ strcpy(cu->str, "Text");
+ cu->pos= 4;
+ cu->strinfo= MEM_callocN(12*sizeof(CharInfo), "strinfo");
+ cu->totbox= cu->actbox= 1;
+ cu->tb= MEM_callocN(MAXTEXTBOX*sizeof(TextBox), "textbox");
+ cu->tb[0].w = cu->tb[0].h = 0.0;
+
+ enter_editmode(EM_WAITCURSOR);
+
+ allqueue(REDRAWALL, 0);
+}
+
+void to_upper(void)
+{
+ Curve *cu;
+ int len, ok;
+ wchar_t *str;
+
+ if(G.obedit==0) {
+ return;
+ }
+
+ ok= 0;
+ cu= G.obedit->data;
+
+ len= wcslen(textbuf);
+ str= textbuf;
+ while(len) {
+ if( *str>=97 && *str<=122) {
+ ok= 1;
+ *str-= 32;
+ }
+ len--;
+ str++;
+ }
+
+ if(ok==0) {
+ len= wcslen(textbuf);
+ str= textbuf;
+ while(len) {
+ if( *str>=65 && *str<=90) {
+ *str+= 32;
+ }
+ len--;
+ str++;
+ }
+ }
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ BIF_undo_push("To upper");
+
+ update_string(cu);
+}
+
+
+/* **************** undo for font object ************** */
+
+static void undoFont_to_editFont(void *strv)
+{
+ Curve *cu= G.obedit->data;
+ char *str= strv;
+
+ cu->pos= *((short *)str);
+ cu->len= *((short *)(str+2));
+
+ memcpy(textbuf, str+4, (cu->len+1)*sizeof(wchar_t));
+ memcpy(textbufinfo, str+4 + (cu->len+1)*sizeof(wchar_t), cu->len*sizeof(CharInfo));
+
+ cu->selstart = cu->selend = 0;
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+
+ update_string(cu);
+
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static void *editFont_to_undoFont(void)
+{
+ Curve *cu= G.obedit->data;
+ char *str;
+
+ // The undo buffer includes [MAXTEXT+6]=actual string and [MAXTEXT+4]*sizeof(CharInfo)=charinfo
+ str= MEM_callocN((MAXTEXT+6)*sizeof(wchar_t) + (MAXTEXT+4)*sizeof(CharInfo), "string undo");
+
+ // Copy the string and string information
+ memcpy(str+4, textbuf, (cu->len+1)*sizeof(wchar_t));
+ memcpy(str+4 + (cu->len+1)*sizeof(wchar_t), textbufinfo, cu->len*sizeof(CharInfo));
+
+ *((short *)str)= cu->pos;
+ *((short *)(str+2))= cu->len;
+
+ return str;
+}
+
+static void free_undoFont(void *strv)
+{
+ MEM_freeN(strv);
+}
+
+/* and this is all the undo system needs to know */
+void undo_push_font(char *name)
+{
+ undo_editmode_push(name, free_undoFont, undoFont_to_editFont, editFont_to_undoFont);
+}
+
+
+
+/***/
diff --git a/source/blender/src/editgroup.c b/source/blender/src/editgroup.c
new file mode 100644
index 00000000000..b17e6efee1b
--- /dev/null
+++ b/source/blender/src/editgroup.c
@@ -0,0 +1,186 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "DNA_group_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_depsgraph.h"
+#include "BKE_group.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+
+#include "BIF_interface.h"
+#include "BIF_editgroup.h"
+#include "BIF_space.h"
+#include "BIF_toolbox.h"
+
+#include "blendef.h"
+#include "mydevice.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+void add_selected_to_group(Group *group)
+{
+ Base *base;
+
+ for(base=FIRSTBASE; base; base= base->next) {
+ if TESTBASE(base) {
+ add_to_group(group, base->object);
+ base->object->flag |= OB_FROMGROUP;
+ base->flag |= OB_FROMGROUP;
+ }
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSOBJECT, 0);
+ DAG_scene_sort(G.scene);
+ BIF_undo_push("Add to Group");
+}
+
+void add_selected_to_act_ob_groups(void)
+{
+ Object *ob= OBACT, *obt;
+ Base *base;
+ Group *group;
+
+ if (!ob) return;
+
+ /* linking to same group requires its own loop so we can avoid
+ looking up the active objects groups each time */
+
+ group= G.main->group.first;
+ while(group) {
+ if(object_in_group(ob, group)) {
+ /* Assign groups to selected objects */
+ base= FIRSTBASE;
+ while(base) {
+ if(TESTBASE(base)) {
+ obt= base->object;
+ add_to_group(group, obt);
+ obt->flag |= OB_FROMGROUP;
+ base->flag |= OB_FROMGROUP;
+ }
+ base= base->next;
+ }
+ }
+ group= group->id.next;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSOBJECT, 0);
+ DAG_scene_sort(G.scene);
+ BIF_undo_push("Add to Active Objects Group");
+}
+
+
+void rem_selected_from_group(void)
+{
+ Base *base;
+ Group *group;
+
+ for(base=FIRSTBASE; base; base= base->next) {
+ if TESTBASE(base) {
+
+ while( (group = find_group(base->object)) ) {
+ rem_from_group(group, base->object);
+ }
+ base->object->flag &= ~OB_FROMGROUP;
+ base->flag &= ~OB_FROMGROUP;
+ }
+ }
+
+ DAG_scene_sort(G.scene);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSOBJECT, 0);
+ BIF_undo_push("Remove from Group");
+}
+
+void group_operation_with_menu(void)
+{
+ Group *group= NULL;
+ int mode;
+
+ /* are there existing groups? */
+ for(group= G.main->group.first; group; group= group->id.next)
+ if(group->id.lib==NULL)
+ break;
+
+ if(group)
+ mode= pupmenu("Groups %t|Add to Existing Group %x3|Add to Active Objects Groups %x4|Add to New Group %x1|Remove from All Groups %x2");
+ else
+ mode= pupmenu("Groups %t|Add to New Group %x1|Remove from All Groups %x2");
+
+ group_operation(mode);
+}
+
+void group_operation(int mode)
+{
+ Group *group= NULL;
+
+ /* are there existing groups? */
+ for(group= G.main->group.first; group; group= group->id.next)
+ if(group->id.lib==NULL)
+ break;
+
+ if(mode>0) {
+ if(group==NULL || mode==1) group= add_group( "Group" );
+ if(mode==3) {
+ int tot= BLI_countlist(&G.main->group);
+ char *strp= MEM_callocN(tot*32 + 32, "group menu"), *strp1;
+
+ strp1= strp;
+ for(tot=1, group= G.main->group.first; group; group= group->id.next, tot++) {
+ if(group->id.lib==NULL) {
+ strp1 += sprintf(strp1, "%s %%x%d|", group->id.name+2, tot);
+ }
+ }
+ tot= pupmenu(strp);
+ MEM_freeN(strp);
+ if(tot>0) group= BLI_findlink(&G.main->group, tot-1);
+ else return;
+ }
+
+ if(mode==4) add_selected_to_act_ob_groups();
+ else if(mode==1 || mode==3) add_selected_to_group(group);
+ else if(mode==2) rem_selected_from_group();
+ }
+}
diff --git a/source/blender/src/editimasel.c b/source/blender/src/editimasel.c
new file mode 100644
index 00000000000..ed5465e938f
--- /dev/null
+++ b/source/blender/src/editimasel.c
@@ -0,0 +1,1137 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef WIN32
+#include <sys/times.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_depsgraph.h"
+#include "BKE_utildefines.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_storage_types.h"
+
+#ifdef WIN32
+#include "BLI_winstuff.h"
+#endif
+
+#include "DNA_armature_types.h"
+#include "DNA_action_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_image_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_object_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_space_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_vfont_types.h"
+#include "DNA_view3d_types.h"
+
+
+#include "BIF_filelist.h"
+#include "BIF_space.h"
+#include "BIF_screen.h"
+#include "BIF_interface.h"
+#include "BIF_mywindow.h"
+#include "BIF_imasel.h"
+#include "BIF_gl.h"
+#include "BIF_fsmenu.h"
+#include "BIF_editview.h"
+#include "BIF_toolbox.h"
+
+#include "BLO_readfile.h"
+
+#include "BPI_script.h"
+
+#include "BSE_drawipo.h"
+#include "BSE_drawimasel.h"
+#include "BSE_edit.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "blendef.h"
+#include "mydevice.h"
+
+/* for events */
+#define NOTACTIVE 0
+#define ACTIVATE 1
+#define INACTIVATE 2
+/* for state of file */
+#define ACTIVE 2
+
+static void imasel_select_objects(SpaceImaSel *simasel);
+
+static int imasel_has_func(SpaceImaSel *simasel)
+{
+ if(simasel->returnfunc || simasel->returnfunc_event || simasel->returnfunc_args)
+ return 1;
+ return 0;
+}
+
+/* ugly, needs to be moved to platform specific files - elubie */
+#if defined WIN32 || defined __BeOS
+static int fnmatch(const char *pattern, const char *string, int flags)
+{
+ return 0;
+}
+#else
+ #include <fnmatch.h>
+#endif
+
+/**************** IMAGESELECT ******************************/
+
+/* the complete call; pulldown menu, and three callback types */
+static void activate_imageselect_(int type, char *title, char *file, short *menup, char *pupmenu,
+ void (*func)(char *),
+ void (*func_event)(unsigned short),
+ void (*func_args)(char *, void *arg1, void *arg2),
+ void *arg1, void *arg2)
+{
+ SpaceImaSel *simasel;
+ char group[24], name[FILE_MAX], temp[FILE_MAX];
+
+ if(curarea==0) return;
+ if(curarea->win==0) return;
+
+ newspace(curarea, SPACE_IMASEL);
+ scrarea_queue_winredraw(curarea);
+
+ /* sometime double, when area already is SPACE_IMASEL with a different file name */
+ if(curarea->headwin) addqueue(curarea->headwin, CHANGED, 1);
+
+ name[2]= 0;
+ BLI_strncpy(name, file, sizeof(name));
+
+ simasel= curarea->spacedata.first;
+
+ simasel->returnfunc= func;
+ simasel->returnfunc_event= func_event;
+ simasel->returnfunc_args= func_args;
+ simasel->arg1= arg1;
+ simasel->arg2= arg2;
+
+ simasel->type= type;
+ simasel->scrollpos = 0.0f;
+
+ if(simasel->pupmenu)
+ MEM_freeN(simasel->pupmenu);
+ simasel->pupmenu= pupmenu;
+ simasel->menup= menup;
+
+ /* sfile->act is used for databrowse: double names of library objects */
+ simasel->active_file= -1;
+
+ if(!simasel->files) {
+ simasel->files = BIF_filelist_new();
+ }
+
+ if(BLI_convertstringcode(name, G.sce, G.scene->r.cfra)) simasel->flag |= FILE_STRINGCODE;
+ else simasel->flag &= ~FILE_STRINGCODE;
+
+ if (U.uiflag & USER_HIDE_DOT)
+ simasel->flag |= FILE_HIDE_DOT;
+
+ if(type==FILE_MAIN) {
+ char *groupname;
+
+ BLI_strncpy(simasel->file, name+2, sizeof(simasel->file));
+
+ groupname = BLO_idcode_to_name( GS(name) );
+ if (groupname) {
+ BLI_strncpy(simasel->dir, groupname, sizeof(simasel->dir) - 1);
+ strcat(simasel->dir, "/");
+ }
+
+ /* free all */
+ if (simasel->files) {
+ BIF_filelist_freelib(simasel->files);
+ BIF_filelist_free(simasel->files);
+ BIF_filelist_setdir(simasel->files, simasel->dir);
+ BIF_filelist_settype(simasel->files, type);
+ }
+ }
+ else if(type==FILE_LOADLIB) {
+ BLI_strncpy(simasel->dir, name, sizeof(simasel->dir));
+ BIF_filelist_setdir(simasel->files, simasel->dir);
+ if( BIF_filelist_islibrary(simasel->files, temp, group) ) {
+ /* force a reload of the library-filelist */
+ BIF_filelist_free(simasel->files);
+ BIF_filelist_freelib(simasel->files);
+ BIF_filelist_setdir(simasel->files, simasel->dir);
+ BIF_filelist_settype(simasel->files, type);
+ }
+ else {
+ BLI_split_dirfile(file, temp, name);
+ BLI_strncpy(simasel->dir, temp, sizeof(simasel->dir));
+ BIF_filelist_setdir(simasel->files, simasel->dir);
+ BIF_filelist_free(simasel->files);
+ BIF_filelist_freelib(simasel->files);
+ BIF_filelist_settype(simasel->files, type);
+ }
+ }
+ else { /* FILE_BLENDER */
+ BLI_split_dirfile(file, temp, name);
+ BIF_filelist_free(simasel->files);
+ BIF_filelist_setdir(simasel->files, temp);
+ BIF_filelist_settype(simasel->files, type);
+
+ BLI_cleanup_dir(G.sce, simasel->dir);
+
+ /* free: filelist and libfiledata became incorrect */
+ BIF_filelist_freelib(simasel->files);
+ }
+ BLI_strncpy(simasel->title, title, sizeof(simasel->title));
+ /* filetoname= 1; */ /* TODO: elubie - check what this means */
+}
+
+void activate_imageselect(int type, char *title, char *file, void (*func)(char *))
+{
+ activate_imageselect_(type, title, file, NULL, NULL, func, NULL, NULL, NULL, NULL);
+}
+
+void activate_imageselect_menu(int type, char *title, char *file, char *pupmenu, short *menup, void (*func)(char *))
+{
+ activate_imageselect_(type, title, file, menup, pupmenu, func, NULL, NULL, NULL, NULL);
+}
+
+void activate_imageselect_args(int type, char *title, char *file, void (*func)(char *, void *, void *), void *arg1, void *arg2)
+{
+ activate_imageselect_(type, title, file, NULL, NULL, NULL, NULL, func, arg1, arg2);
+}
+
+void activate_databrowse_imasel(ID *id, int idcode, int fromcode, int retval, short *menup, void (*func)(unsigned short))
+{
+ ListBase *lb;
+ SpaceImaSel *simasel;
+ char str[32];
+
+ if(id==NULL) {
+ lb= wich_libbase(G.main, idcode);
+ id= lb->first;
+ }
+
+ if(id) BLI_strncpy(str, id->name, sizeof(str));
+ else return;
+
+ activate_imageselect_(FILE_MAIN, "SELECT DATABLOCK", str, menup, NULL, NULL, func, NULL, NULL, NULL);
+
+ simasel= curarea->spacedata.first;
+ simasel->retval= retval;
+ simasel->menup= menup;
+
+ BIF_filelist_setipotype(simasel->files, fromcode);
+ BIF_filelist_hasfunc(simasel->files, imasel_has_func(simasel));
+}
+
+
+static void set_active_file(SpaceImaSel *simasel, short x, short y)
+{
+ short tilex, tiley;
+ int active_tile;
+ int active_file;
+ int stridex;
+ struct direntry* file;
+ rcti viewrect = simasel->viewrect;
+ int fileoffset;
+ int rowoffset;
+ int rowleftover;
+ float scrollofs;
+ int numfiles;
+ int tilewidth = simasel->prv_w + TILE_BORDER_X*4;
+ int tileheight = simasel->prv_h + TILE_BORDER_Y*4 + U.fontsize;
+
+ numfiles = BIF_filelist_numfiles(simasel->files);
+
+ if (simasel->numtilesx > 0) {
+ fileoffset = numfiles*(simasel->scrollpos / simasel->scrollarea) + 0.5;
+ rowoffset = (fileoffset / simasel->numtilesx)*simasel->numtilesx;
+ rowleftover = fileoffset % simasel->numtilesx;
+ scrollofs = (float)tileheight*(float)rowleftover/(float)simasel->numtilesx;
+
+ stridex = (viewrect.xmax - viewrect.xmin) / (tilewidth);
+ tilex = ( (x-viewrect.xmin)) / (tilewidth);
+ tiley = (viewrect.ymax - viewrect.ymin + scrollofs - y) / (tileheight);
+ if (tilex >= simasel->numtilesx) tilex = simasel->numtilesx-1;
+ if (tiley >= simasel->numtilesy+1) tiley = simasel->numtilesy;
+ if (tilex < 0) tilex=0;
+ if (tiley < 0) tiley = 0;
+ active_tile = tilex + stridex*tiley;
+ active_file = rowoffset + active_tile;
+
+ if (active_file >= 0 && active_file < BIF_filelist_numfiles(simasel->files) )
+ {
+ simasel->active_file = active_file;
+ if (simasel->selstate & ACTIVATE) {
+ file = BIF_filelist_file(simasel->files, simasel->active_file);
+ file->flags |= ACTIVE;
+ }
+ } else {
+ simasel->active_file = -1;
+ }
+ } else {
+ simasel->active_file = -1;
+ }
+}
+
+static void set_active_bookmark(SpaceImaSel *simasel, short y)
+{
+ int nentries = fsmenu_get_nentries();
+ short posy = simasel->bookmarkrect.ymax - TILE_BORDER_Y - y;
+ simasel->active_bookmark = ((float)posy / (U.fontsize*3.0f/2.0f));
+ if (simasel->active_bookmark < 0 || simasel->active_bookmark > nentries) {
+ simasel->active_bookmark = -1;
+ }
+}
+
+static void imasel_prevspace()
+{
+ SpaceImaSel *simasel;
+
+ simasel= curarea->spacedata.first;
+
+ /* cleanup */
+ if(simasel->spacetype==SPACE_IMASEL) {
+ if(simasel->pupmenu) {
+ MEM_freeN(simasel->pupmenu);
+ simasel->pupmenu= NULL;
+ }
+ }
+
+ if(simasel->next) {
+
+ BLI_remlink(&curarea->spacedata, simasel);
+ BLI_addtail(&curarea->spacedata, simasel);
+
+ simasel= curarea->spacedata.first;
+
+ if (simasel->spacetype == SPACE_SCRIPT) {
+ SpaceScript *sc = (SpaceScript *)simasel;
+ if (sc->script) sc->script->flags &=~SCRIPT_FILESEL;
+ }
+
+ newspace(curarea, simasel->spacetype);
+ }
+ else newspace(curarea, SPACE_INFO);
+}
+
+static void free_imasel_spec(char *dir)
+{
+ /* all filesels with 'dir' are freed */
+ bScreen *sc;
+
+ sc= G.main->screen.first;
+ while(sc) {
+ ScrArea *sa= sc->areabase.first;
+ while(sa) {
+ SpaceLink *sl= sa->spacedata.first;
+ while(sl) {
+ if(sl->spacetype==SPACE_FILE) {
+ SpaceImaSel *simasel= (SpaceImaSel*) sl;
+ if (BLI_streq(simasel->dir, dir)) {
+ BIF_filelist_free(simasel->files);
+ }
+ }
+ sl= sl->next;
+ }
+ sa= sa->next;
+ }
+ sc= sc->id.next;
+ }
+}
+
+static void do_library_append(SpaceImaSel *simasel)
+{
+ Library *lib;
+ char dir[FILE_MAXDIR], group[32];
+
+ if ( BIF_filelist_islibrary(simasel->files, dir, group)==0 ) {
+ error("Not a library");
+ } else if (!BIF_filelist_lib(simasel->files) ) {
+ error("Library not loaded");
+ } else if (group[0]==0) {
+ error("Nothing indicated");
+ } else if (BLI_streq(G.main->name, dir)) {
+ error("Cannot use current file as library");
+ } else {
+ Object *ob;
+ int idcode = BIF_groupname_to_code(group);
+
+ if((simasel->flag & FILE_LINK)==0) {
+ /* tag everything, all untagged data can be made local */
+ ID *id;
+ ListBase *lbarray[MAX_LIBARRAY];
+ int a;
+
+ a= set_listbasepointers(G.main, lbarray);
+ while(a--) {
+ for(id= lbarray[a]->first; id; id= id->next) id->flag |= LIB_APPEND_TAG;
+ }
+ }
+
+ BIF_filelist_append_library(simasel->files, dir, simasel->file, simasel->flag, idcode);
+
+ /* DISPLISTS? */
+ ob= G.main->object.first;
+ while(ob) {
+ if(ob->id.lib) {
+ ob->recalc |= OB_RECALC;
+ }
+ ob= ob->id.next;
+ }
+
+ /* and now find the latest append lib file */
+ lib= G.main->library.first;
+ while(lib) {
+ if (BLI_streq(dir, lib->filename)) break;
+ lib= lib->id.next;
+ }
+
+ /* make local */
+ if(lib) {
+ if((simasel->flag & FILE_LINK)==0)
+ all_local(lib,1);
+ }
+
+ DAG_scene_sort(G.scene);
+
+ /* in sfile->dir is the whole lib name */
+ BLI_strncpy(G.lib, simasel->dir, sizeof(G.lib) );
+
+ }
+}
+
+/* NOTE: this is called for file read, after the execfunc no UI memory is valid! */
+static void imasel_execute(SpaceImaSel *simasel)
+{
+ struct direntry *file;
+ char name[FILE_MAX];
+ int a;
+ int n;
+
+ imasel_prevspace();
+
+ if(simasel->type==FILE_LOADLIB) {
+ if(simasel->flag & FILE_STRINGCODE) {
+ if (!G.relbase_valid) {
+ okee("You have to save the .blend file before using relative paths! Using absolute path instead.");
+ simasel->flag &= ~FILE_STRINGCODE;
+ }
+ }
+
+ do_library_append(simasel);
+ BIF_undo_push("Append from file");
+ allqueue(REDRAWALL, 1);
+ }
+ else if(imasel_has_func(simasel)) {
+ fsmenu_insert_entry(simasel->dir, 1, 0);
+
+ if(simasel->type==FILE_MAIN) { /* DATABROWSE */
+ if (simasel->menup) { /* with value pointing to ID block index */
+ int notfound = 1;
+
+ /* Need special handling since hiding .* datablocks means that
+ simasel->active_file is no longer the same as files->nr.
+
+ Also, toggle HIDE_DOT on and off can make simasel->active_file not longer
+ correct (meaning it doesn't point to the correct item in the filelist.
+
+ simasel->file is always correct, so first with check if, for the item
+ corresponding to simasel->active_file, the name is the same.
+
+ If it isn't (or if simasel->active_file is not good), go over filelist and take
+ the correct one.
+
+ This means that selecting a datablock than hiding it makes it
+ unselectable. Not really a problem.
+
+ - theeth
+ */
+
+ *simasel->menup= -1;
+ n = BIF_filelist_numfiles(simasel->files);
+ if(simasel->files) {
+ if( (simasel->active_file>=0) && (simasel->active_file < n) ) {
+ file = BIF_filelist_file(simasel->files, simasel->active_file);
+ if ( strcmp(file->relname, simasel->file)==0) {
+ notfound = 0;
+ *simasel->menup= file->nr;
+ }
+ }
+ if (notfound) {
+ for(a=0; a<n; a++) {
+ file = BIF_filelist_file(simasel->files, a);
+ if( strcmp(file->relname, simasel->file)==0) {
+ *simasel->menup= file->nr;
+ break;
+ }
+ }
+ }
+ }
+ }
+ if(simasel->returnfunc_event)
+ simasel->returnfunc_event(simasel->retval);
+ else if(simasel->returnfunc_args)
+ simasel->returnfunc_args(NULL, simasel->arg1, simasel->arg2);
+ }
+ else {
+ if(strncmp(simasel->title, "Save", 4)==0) free_imasel_spec(simasel->dir);
+ if(strncmp(simasel->title, "Export", 6)==0) free_imasel_spec(simasel->dir);
+
+ BLI_strncpy(name, simasel->dir, sizeof(name));
+ strcat(name, simasel->file);
+
+ if(simasel->flag & FILE_STRINGCODE) {
+ if (!G.relbase_valid) {
+ /* skip save */
+ if(strncmp(simasel->title, "Save", 4)) {
+ okee("You have to save the .blend file before using relative paths! Using absolute path instead.");
+ simasel->flag &= ~FILE_STRINGCODE;
+ }
+ }
+ else {
+ BLI_makestringcode(G.sce, name);
+ }
+ }
+ if(simasel->returnfunc)
+ simasel->returnfunc(name);
+ else if(simasel->returnfunc_args)
+ simasel->returnfunc_args(name, simasel->arg1, simasel->arg2);
+ }
+ }
+}
+
+static void do_imasel_buttons(short event, SpaceImaSel *simasel)
+{
+ char butname[FILE_MAX];
+
+ if (event == B_FS_FILENAME) {
+ if (strchr(simasel->file, '*') || strchr(simasel->file, '?') || strchr(simasel->file, '[')) {
+ int i, match = FALSE;
+ struct direntry *file;
+ int n = BIF_filelist_numfiles(simasel->files);
+ for (i = 2; i < n; i++) {
+ file = BIF_filelist_file(simasel->files, i);
+ if (fnmatch(simasel->file, file->relname, 0) == 0) {
+ file->flags |= ACTIVE;
+ match = TRUE;
+ }
+ }
+ if (match) simasel->file[0] = '\0';
+ if(simasel->type==FILE_MAIN) imasel_select_objects(simasel);
+ scrarea_queue_winredraw(curarea);
+ }
+ }
+ else if(event== B_FS_DIRNAME) {
+ /* reuse the butname variable */
+ BLI_cleanup_dir(G.sce, simasel->dir);
+
+ BLI_make_file_string(G.sce, butname, simasel->dir, "");
+ BLI_strncpy(simasel->dir, butname, sizeof(simasel->dir));
+
+ /* strip the trailing slash if its a real dir */
+ if (strlen(butname)!=1)
+ butname[strlen(butname)-1]=0;
+
+ /* updating the directory in the filelist */
+ BIF_filelist_setdir(simasel->files, simasel->dir);
+
+ if(simasel->type & FILE_UNIX) {
+ if (!BLI_exists(butname)) {
+ if (okee("Makedir")) {
+ BLI_recurdir_fileops(butname);
+ if (!BLI_exists(butname)) {
+ BIF_filelist_free(simasel->files);
+ BIF_filelist_parent(simasel->files);
+ BLI_strncpy(simasel->dir, BIF_filelist_dir(simasel->files), 80);
+ }
+ } else {
+ BIF_filelist_free(simasel->files);
+ BIF_filelist_parent(simasel->files);
+ BLI_strncpy(simasel->dir, BIF_filelist_dir(simasel->files), 80);
+ }
+ }
+ }
+ BIF_filelist_free(simasel->files);
+ simasel->file[0] = '\0';
+ simasel->scrollpos = 0;
+ simasel->active_file = -1;
+ scrarea_queue_winredraw(curarea);
+ }
+ else if(event== B_FS_DIR_MENU) {
+ char *selected= fsmenu_get_entry(simasel->menu-1);
+
+ /* which string */
+ if (selected) {
+ BLI_strncpy(simasel->dir, selected, sizeof(simasel->dir));
+ BLI_make_exist(simasel->dir);
+ BLI_cleanup_dir(G.sce, simasel->dir);
+ BIF_filelist_free(simasel->files);
+ BIF_filelist_setdir(simasel->files, simasel->dir);
+ simasel->file[0] = '\0';
+ simasel->scrollpos = 0;
+ simasel->active_file = -1;
+ scrarea_queue_redraw(curarea);
+ }
+
+ simasel->active_file = -1;
+
+ }
+ else if(event== B_FS_PARDIR) {
+ BIF_filelist_free(simasel->files);
+ BIF_filelist_parent(simasel->files);
+ BLI_strncpy(simasel->dir, BIF_filelist_dir(simasel->files), 80);
+ simasel->file[0] = '\0';
+ simasel->active_file = -1;
+ simasel->scrollpos = 0;
+ scrarea_queue_redraw(curarea);
+ }
+ else if(event== B_FS_LOAD) {
+ if(simasel->type)
+ imasel_execute(simasel);
+ }
+ else if(event== B_FS_CANCEL)
+ imasel_prevspace();
+ else if(event== B_FS_LIBNAME) {
+ Library *lib= BLI_findlink(&G.main->library, simasel->menu);
+ if(lib) {
+ BLI_strncpy(simasel->dir, lib->filename, sizeof(simasel->dir));
+ BLI_make_exist(simasel->dir);
+ BLI_cleanup_dir(G.sce, simasel->dir);
+ BIF_filelist_free(simasel->files);
+ BIF_filelist_setdir(simasel->files, simasel->dir);
+ simasel->file[0] = '\0';
+ simasel->scrollpos = 0;
+ simasel->active_file = -1;
+ scrarea_queue_winredraw(curarea);
+ }
+ } else if(event== B_FS_BOOKMARK) {
+ char name[FILE_MAX];
+ BLI_make_file_string(G.sce, name, BLI_gethome(), ".Bfs");
+ fsmenu_insert_entry(simasel->dir, 1, 1);
+ scrarea_queue_winredraw(curarea);
+ fsmenu_write_file(name);
+ }
+
+}
+
+static void imasel_home(ScrArea *sa, SpaceImaSel *simasel)
+{
+ simasel->v2d.cur.xmin= simasel->v2d.cur.ymin= 0.0f;
+ simasel->v2d.cur.xmax= sa->winx;
+ simasel->v2d.cur.ymax= sa->winy;
+
+ simasel->v2d.tot= simasel->v2d.cur;
+ test_view2d(G.v2d, sa->winx, sa->winy);
+
+}
+
+static struct direntry* get_hilited_entry(SpaceImaSel *simasel)
+{
+ struct direntry *file;
+ file = BIF_filelist_file(simasel->files, simasel->active_file);
+ return file;
+}
+
+static void do_filescroll(SpaceImaSel *simasel)
+{
+ short mval[2], oldy, yo;
+ float scrollarea, scrollstep;
+
+ /* for beauty */
+ scrarea_do_windraw(curarea);
+ screen_swapbuffers();
+
+ getmouseco_areawin(mval);
+ oldy= yo= mval[1];
+
+ while(get_mbut()&L_MOUSE) {
+ getmouseco_areawin(mval);
+
+ if(yo!=mval[1]) {
+ scrollarea = ((float)simasel->v2d.vert.ymax - (float)simasel->v2d.vert.ymin);
+ scrollstep = yo - mval[1];
+ simasel->scrollpos += scrollstep;
+
+ if (simasel->scrollpos<0)
+ simasel->scrollpos=0;
+ if (simasel->scrollpos > scrollarea - simasel->scrollheight)
+ simasel->scrollpos = scrollarea - simasel->scrollheight;
+ scrarea_do_windraw(curarea);
+ screen_swapbuffers();
+
+ yo= mval[1];
+ }
+ else BIF_wait_for_statechange();
+ }
+
+ /* for beauty */
+ scrarea_do_windraw(curarea);
+ screen_swapbuffers();
+
+}
+
+/* ******************* DATA SELECT ********************* */
+
+static void imasel_select_objects(SpaceImaSel *simasel)
+{
+ Object *ob;
+ Base *base;
+ Scene *sce;
+ struct direntry* file;
+ int a;
+ int totfile;
+
+ /* only when F4 DATABROWSE */
+ if(imasel_has_func(simasel)) return;
+
+ totfile = BIF_filelist_numfiles(simasel->files);
+
+ if( strcmp(simasel->dir, "Object/")==0 ) {
+ for(a=0; a<totfile; a++) {
+ file = BIF_filelist_file(simasel->files, a);
+ ob= (Object *)file->poin;
+
+ if(ob) {
+ if(file->flags & ACTIVE) ob->flag |= SELECT;
+ else ob->flag &= ~SELECT;
+ }
+
+ }
+ base= FIRSTBASE;
+ while(base) {
+ base->flag= base->object->flag;
+ base= base->next;
+ }
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWOOPS, 0);
+ }
+ else if( strcmp(simasel->dir, "Scene/")==0 ) {
+
+ for(a=0; a<totfile; a++) {
+ file = BIF_filelist_file(simasel->files, a);
+ sce= (Scene *)file->poin;
+ if(sce) {
+ if(file->flags & ACTIVE) sce->r.scemode |= R_BG_RENDER;
+ else sce->r.scemode &= ~R_BG_RENDER;
+ }
+
+ }
+ allqueue(REDRAWBUTSSCENE, 0);
+ }
+}
+
+static void active_imasel_object(SpaceImaSel *simasel)
+{
+ Object *ob;
+ struct direntry* file;
+
+ /* only when F4 DATABROWSE */
+ if(imasel_has_func(simasel)) return;
+
+ if( strcmp(simasel->dir, "Object/")==0 ) {
+ int n = BIF_filelist_numfiles(simasel->files);
+ if(simasel->active_file >= 0 && simasel->active_file < n) {
+ file = BIF_filelist_file(simasel->files, simasel->active_file);
+ ob= (Object *)file->poin;
+
+ if(ob) {
+ set_active_object(ob);
+ if(BASACT && BASACT->object==ob) {
+ BASACT->flag |= SELECT;
+ file->flags |= ACTIVE;
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWOOPS, 0);
+ scrarea_queue_winredraw(curarea);
+ }
+ }
+ }
+ }
+}
+
+
+
+void winqreadimaselspace(ScrArea *, void *, BWinEvent *);
+
+
+void winqreadimaselspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
+{
+ unsigned short event= evt->event;
+ short val= evt->val;
+ SpaceImaSel *simasel;
+
+ char str[FILE_MAXDIR+FILE_MAXFILE+12];
+ short mval[2];
+ short do_draw = 0;
+ short do_headdraw = 0;
+ int numfiles;
+ struct direntry *file;
+ float scrollstep = 0;
+ float scrollarea;
+
+ // if(val==0) return;
+ simasel= curarea->spacedata.first;
+
+ if (!simasel->files)
+ return;
+
+ if (BIF_filelist_empty(simasel->files))
+ return;
+
+ numfiles = BIF_filelist_numfiles(simasel->files);
+
+ /* calc_scrollrcts(sa, &(simasel->v2d), sa->winx, sa->winy); */
+ calc_imasel_rcts(simasel, sa->winx, sa->winy);
+
+ /* prevent looping */
+ if(simasel->selstate && !(get_mbut() & R_MOUSE)) simasel->selstate= 0;
+
+ if(val) {
+
+ if( event!=RETKEY && event!=PADENTER)
+ if( uiDoBlocks(&curarea->uiblocks, event)!=UI_NOTHING ) event= 0;
+
+ switch(event) {
+
+ case UI_BUT_EVENT:
+ do_imasel_buttons(val, simasel);
+ break;
+ case RENDERPREVIEW:
+ do_draw= 1;
+ /* draw_imasel_previews(sa, simasel); */
+ break;
+ case REDRAWIMASEL:
+ do_draw= 1;
+ break;
+ case WHEELDOWNMOUSE:
+ numfiles = BIF_filelist_numfiles(simasel->files);
+ scrollarea = ((float)simasel->v2d.vert.ymax - (float)simasel->v2d.vert.ymin);
+ scrollstep = ((scrollarea-simasel->scrollheight)/numfiles)*simasel->numtilesx;
+ simasel->scrollpos += scrollstep;
+ if (simasel->scrollpos > scrollarea - simasel->scrollheight)
+ simasel->scrollpos = scrollarea - simasel->scrollheight;
+ do_draw= 1;
+ break;
+ case WHEELUPMOUSE:
+ numfiles = BIF_filelist_numfiles(simasel->files);
+ scrollarea = ((float)simasel->v2d.vert.ymax - (float)simasel->v2d.vert.ymin);
+ scrollstep = ((scrollarea-simasel->scrollheight)/numfiles)*simasel->numtilesx;
+ simasel->scrollpos -= scrollstep;
+ if (simasel->scrollpos<0)
+ simasel->scrollpos=0;
+ do_draw= 1;
+ break;
+ case PAGEUPKEY:
+ numfiles = BIF_filelist_numfiles(simasel->files);
+ scrollarea = ((float)simasel->v2d.vert.ymax - (float)simasel->v2d.vert.ymin);
+ scrollstep = ((scrollarea-simasel->scrollheight)/numfiles)
+ *simasel->numtilesx*simasel->numtilesy;
+ simasel->scrollpos -= scrollstep;
+ if (simasel->scrollpos<0)
+ simasel->scrollpos=0;
+ do_draw= 1;
+ break;
+ case PAGEDOWNKEY:
+ numfiles = BIF_filelist_numfiles(simasel->files);
+ scrollarea = ((float)simasel->v2d.vert.ymax - (float)simasel->v2d.vert.ymin);
+ scrollstep = ((scrollarea-simasel->scrollheight)/numfiles)
+ * simasel->numtilesx*simasel->numtilesy;
+ simasel->scrollpos += scrollstep;
+ if (simasel->scrollpos > scrollarea - simasel->scrollheight)
+ simasel->scrollpos = scrollarea - simasel->scrollheight;
+ do_draw= 1;
+ break;
+ case HOMEKEY:
+ simasel->scrollpos=0;
+ imasel_home(sa, simasel);
+ do_draw= 1;
+ break;
+ case ENDKEY:
+ simasel->scrollpos = simasel->scrollarea;
+ do_draw= 1;
+ break;
+
+ case ESCKEY:
+ BIF_filelist_free(simasel->files);
+ imasel_prevspace();
+ break;
+ case PERIODKEY:
+ BIF_filelist_free(simasel->files);
+ simasel->active_file = -1;
+ do_draw = 1;
+ break;
+ case LEFTMOUSE:
+ case MIDDLEMOUSE:
+ getmouseco_areawin(mval);
+ if(mval[0]>simasel->v2d.vert.xmin && mval[0]<simasel->v2d.vert.xmax && mval[1]>simasel->v2d.vert.ymin && mval[1]<simasel->v2d.vert.ymax) {
+ do_filescroll(simasel);
+ }
+ else if(mval[0]>simasel->viewrect.xmin && mval[0]<simasel->viewrect.xmax
+ && mval[1]>simasel->viewrect.ymin && mval[1]<simasel->viewrect.ymax) {
+ set_active_file(simasel, mval[0], mval[1]);
+ if (simasel->active_file >= 0 && simasel->active_file < numfiles) {
+ file = BIF_filelist_file(simasel->files, simasel->active_file);
+
+ if(file && S_ISDIR(file->type)) {
+
+ BIF_filelist_appenddir(simasel->files, file->relname);
+ BLI_strncpy(simasel->dir, BIF_filelist_dir(simasel->files), FILE_MAXDIR);
+ strcat(simasel->dir,"/");
+ simasel->file[0] = '\0';
+ BLI_cleanup_dir(G.sce, simasel->dir);
+ BIF_filelist_free(simasel->files);
+ simasel->active_file = -1;
+ simasel->scrollpos = 0;
+ do_draw = 1;
+ do_headdraw = 1;
+
+ }
+ else if (file)
+ {
+ if (file->relname) {
+ if (simasel->img) {
+ IMB_freeImBuf(simasel->img);
+ simasel->img = NULL;
+ }
+ BLI_strncpy(simasel->file, file->relname, FILE_MAXFILE);
+ if(event==MIDDLEMOUSE && BIF_filelist_gettype(simasel->files))
+ imasel_execute(simasel);
+ }
+
+ }
+ if(BIF_filelist_gettype(simasel->files)==FILE_MAIN) {
+ active_imasel_object(simasel);
+ }
+
+ do_draw = 1;
+ }
+ }
+ else {
+ simasel->active_file = -1;
+ if (simasel->flag & FILE_BOOKMARKS) {
+ if(mval[0]>simasel->bookmarkrect.xmin && mval[0]<simasel->bookmarkrect.xmax && mval[1]>simasel->bookmarkrect.ymin && mval[1]<simasel->bookmarkrect.ymax) {
+ int nentries = fsmenu_get_nentries();
+
+ set_active_bookmark(simasel, mval[1]);
+ if (simasel->active_bookmark >= 0 && simasel->active_bookmark < nentries) {
+ char *selected= fsmenu_get_entry(simasel->active_bookmark);
+ /* which string */
+ if (selected) {
+ BLI_strncpy(simasel->dir, selected, sizeof(simasel->dir));
+ BLI_make_exist(simasel->dir);
+ BLI_cleanup_dir(G.sce, simasel->dir);
+ BIF_filelist_free(simasel->files);
+ BIF_filelist_setdir(simasel->files, simasel->dir);
+ simasel->file[0] = '\0';
+ simasel->scrollpos = 0;
+ simasel->active_file = -1;
+ do_headdraw = 1;
+ }
+ }
+ } else {
+ simasel->active_bookmark = -1;
+ }
+ do_draw= 1;
+ }
+ }
+ break;
+ case RIGHTMOUSE:
+ getmouseco_areawin(mval);
+ if(mval[0]>simasel->viewrect.xmin && mval[0]<simasel->viewrect.xmax
+ && mval[1]>simasel->viewrect.ymin && mval[1]<simasel->viewrect.ymax) {
+ set_active_file(simasel, mval[0], mval[1]);
+ if(simasel->active_file >=0 && simasel->active_file<numfiles) {
+ simasel->selstate = NOTACTIVE;
+ file = BIF_filelist_file(simasel->files, simasel->active_file);
+ if (file->flags & ACTIVE) {
+ file->flags &= ~ACTIVE;
+ simasel->selstate = INACTIVATE;
+ }
+ else {
+ file->flags |= ACTIVE;
+ simasel->selstate = ACTIVATE;
+ }
+ do_draw= 1;
+ }
+ }
+ break;
+ case MOUSEY:
+ case MOUSEX:
+ getmouseco_areawin(mval);
+ if(mval[0]>simasel->viewrect.xmin && mval[0]<simasel->viewrect.xmax && mval[1]>simasel->viewrect.ymin && mval[1]<simasel->viewrect.ymax) {
+ set_active_file(simasel, mval[0], mval[1]);
+ simasel->active_bookmark = -1;
+ if(simasel->active_file >=0 && simasel->active_file<numfiles) {
+ file = BIF_filelist_file(simasel->files, simasel->active_file);
+ if (simasel->selstate == INACTIVATE) {
+ file->flags &= ~ACTIVE;
+ }
+ else if (simasel->selstate == ACTIVATE) {
+ file->flags |= ACTIVE;
+ }
+ do_draw= 1;
+ }
+ } else {
+ simasel->active_file = -1;
+ if (simasel->flag & FILE_BOOKMARKS) {
+ if(mval[0]>simasel->bookmarkrect.xmin && mval[0]<simasel->bookmarkrect.xmax && mval[1]>simasel->bookmarkrect.ymin && mval[1]<simasel->bookmarkrect.ymax) {
+ set_active_bookmark(simasel, mval[1]);
+ } else {
+ simasel->active_bookmark = -1;
+ }
+ do_draw= 1;
+ }
+ }
+ break;
+ case AKEY:
+ BIF_filelist_swapselect(simasel->files);
+ if(simasel->type==FILE_MAIN) imasel_select_objects(simasel);
+ do_draw= 1;
+ break;
+ case BKEY:
+ toggle_blockhandler(sa, IMASEL_HANDLER_IMAGE, UI_PNL_UNSTOW);
+ scrarea_queue_winredraw(sa);
+ break;
+ case PKEY:
+ if(G.qual & LR_SHIFTKEY) {
+ extern char bprogname[]; /* usiblender.c */
+
+ sprintf(str, "%s -a \"%s%s\"", bprogname, simasel->dir, simasel->file);
+ system(str);
+ }
+ else
+ {
+ BIF_filelist_free(simasel->files);
+ BIF_filelist_parent(simasel->files);
+ BLI_strncpy(simasel->dir, BIF_filelist_dir(simasel->files), 80);
+ simasel->file[0] = '\0';
+ simasel->active_file = -1;
+ simasel->scrollpos = 0;
+ do_headdraw = 1;
+ }
+ do_draw = 1;
+ break;
+ case XKEY:
+ getmouseco_areawin(mval);
+ if (simasel->flag & FILE_BOOKMARKS) {
+ if(mval[0]>simasel->bookmarkrect.xmin && mval[0]<simasel->bookmarkrect.xmax && mval[1]>simasel->bookmarkrect.ymin && mval[1]<simasel->bookmarkrect.ymax) {
+ int nentries = fsmenu_get_nentries();
+ set_active_bookmark(simasel, mval[1]);
+ if (simasel->active_bookmark >= 0 && simasel->active_bookmark < nentries) {
+ char name[FILE_MAX];
+ BLI_make_file_string(G.sce, name, BLI_gethome(), ".Bfs");
+ fsmenu_remove_entry(simasel->active_bookmark);
+ fsmenu_write_file(name);
+ simasel->active_bookmark = -1;
+ do_draw = 1;
+ }
+ }
+ }
+ break;
+ }
+ }
+ else if(event==RIGHTMOUSE) {
+ simasel->selstate = NOTACTIVE;
+ if(simasel->type==FILE_MAIN) imasel_select_objects(simasel);
+ }
+ else if(event==LEFTMOUSE) {
+ if(simasel->type==FILE_MAIN) {
+ getmouseco_areawin(mval);
+ set_active_file(simasel, mval[0], mval[1]);
+ }
+ }
+ /* XXX, stupid patch, curarea can become undone
+ * because of file loading... fixme zr
+ */
+ if(curarea) {
+ if(do_draw) scrarea_queue_winredraw(curarea);
+ if(do_headdraw) scrarea_queue_headredraw(curarea);
+ }
+}
+
+
+/* copied from filesel.c */
+void clever_numbuts_imasel()
+{
+ SpaceImaSel *simasel;
+ char orgname[FILE_MAXDIR+FILE_MAXFILE+12];
+ char filename[FILE_MAXDIR+FILE_MAXFILE+12];
+ char newname[FILE_MAXDIR+FILE_MAXFILE+12];
+ struct direntry *file;
+ int len;
+
+ simasel= curarea->spacedata.first;
+
+ if(BIF_filelist_gettype(simasel->files)==FILE_MAIN) return;
+
+ len = 110;
+ file = get_hilited_entry(simasel);
+
+ if (file != NULL && !(S_ISDIR(file->type))){
+
+ BLI_make_file_string(G.sce, orgname, simasel->dir, file->relname);
+ BLI_strncpy(filename, file->relname, sizeof(filename));
+
+ add_numbut(0, TEX, "", 0, len, filename, "Rename File");
+
+ if( do_clever_numbuts("Rename File", 1, REDRAW) ) {
+ BLI_make_file_string(G.sce, newname, simasel->dir, filename);
+
+ if( strcmp(orgname, newname) != 0 ) {
+ BLI_rename(orgname, newname);
+ BIF_filelist_free(simasel->files);
+ }
+ }
+
+ scrarea_queue_winredraw(curarea);
+ }
+}
diff --git a/source/blender/src/editipo.c b/source/blender/src/editipo.c
new file mode 100644
index 00000000000..52b485c539b
--- /dev/null
+++ b/source/blender/src/editipo.c
@@ -0,0 +1,5625 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation, 2005. Full recode.
+ * Roland Hess, 2007. Visual Key refactor.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+
+/* this code feels over-complex, mostly because I choose in the past to devise a system
+ that converts the Ipo blocks (linked to Object, Material, etc), into a copy of that
+ data which is being worked on; the 'editipo'.
+ The editipo then can have 'ipokey' data, which is optimized for editing curves as if
+ it were key positions. This is still a great feature to work with, which makes ipo editing
+ in Blender still valuable. However, getting this beast under control was hard, even
+ for me... (ton) */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#ifndef WIN32
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+#include "MEM_guardedalloc.h"
+#include "PIL_time.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "DNA_constraint_types.h"
+#include "DNA_action_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_group_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_key_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_material_types.h"
+#include "DNA_object_types.h"
+#include "DNA_object_fluidsim.h"
+#include "DNA_screen_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
+#include "DNA_sequence_types.h"
+#include "DNA_sound_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_world_types.h"
+
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_anim.h"
+#include "BKE_constraint.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_group.h"
+#include "BKE_ipo.h"
+#include "BKE_key.h"
+#include "BKE_material.h"
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_butspace.h"
+#include "BIF_editaction.h"
+#include "BIF_editconstraint.h"
+#include "BIF_editkey.h"
+#include "BIF_editnla.h"
+#include "BIF_editseq.h"
+#include "BIF_editview.h"
+#include "BIF_interface.h"
+#include "BIF_mywindow.h"
+#include "BIF_poseobject.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_toolbox.h"
+#include "BIF_poseobject.h"
+
+#include "BDR_drawobject.h"
+#include "BDR_editobject.h"
+#include "BDR_editcurve.h" // for bezt_compare
+
+#include "BSE_trans_types.h"
+#include "BSE_editipo_types.h"
+#include "BSE_drawipo.h"
+#include "BSE_editipo.h"
+#include "BSE_edit.h"
+#include "BSE_drawview.h"
+#include "BSE_headerbuttons.h"
+#include "BSE_node.h"
+#include "BSE_sequence.h"
+#include "BSE_time.h"
+
+#include "blendef.h"
+#include "mydevice.h"
+#include "transform.h"
+
+extern int ob_ar[];
+extern int ma_ar[];
+extern int seq_ar[];
+extern int cu_ar[];
+extern int wo_ar[];
+extern int la_ar[];
+extern int cam_ar[];
+extern int snd_ar[];
+extern int ac_ar[];
+extern int co_ar[];
+extern int te_ar[];
+extern int fluidsim_ar[]; // NT
+
+/* forwards */
+#define IPOTHRESH 0.9
+
+/* tests if only one editipo is active */
+static void check_active_editipo(void)
+{
+ EditIpo *ei, *actei;
+ int a;
+
+ actei= G.sipo->editipo;
+ if(actei) {
+ for(a=0; a<G.sipo->totipo; a++, actei++) {
+ if(actei->flag & IPO_ACTIVE)
+ break;
+ }
+ if(actei==NULL) {
+ /* set visible active */
+ for(a=0, ei=G.sipo->editipo; a<G.sipo->totipo; a++, ei++) {
+ if(ei->flag & IPO_VISIBLE)
+ break;
+ }
+ if(ei==NULL) ei=G.sipo->editipo;
+ ei->flag |= IPO_ACTIVE;
+ if(ei->icu) ei->icu->flag |= IPO_ACTIVE;
+ }
+ else {
+ /* make sure no others are active */
+ for(a=0, ei=G.sipo->editipo; a<G.sipo->totipo; a++, ei++) {
+ if(ei!=actei) {
+ ei->flag &= ~IPO_ACTIVE;
+ if(ei->icu) ei->icu->flag &= ~IPO_ACTIVE;
+ }
+ }
+ }
+ }
+}
+
+/* sets this ei channel active */
+static void set_active_editipo(EditIpo *actei)
+{
+ EditIpo *ei;
+ int a;
+
+ for(a=0, ei=G.sipo->editipo; a<G.sipo->totipo; a++, ei++) {
+ ei->flag &= ~IPO_ACTIVE;
+ if(ei->icu) ei->icu->flag &= ~IPO_ACTIVE;
+ }
+ actei->flag |= IPO_ACTIVE;
+ if(actei->icu) actei->icu->flag |= IPO_ACTIVE;
+}
+
+EditIpo *get_active_editipo(void)
+{
+ EditIpo *ei;
+ int a;
+
+ if(G.sipo==NULL)
+ return NULL;
+
+ /* prevent confusing situations, like for sequencer */
+ if(G.sipo->totipo==1) {
+ ei= G.sipo->editipo;
+ ei->flag |= IPO_ACTIVE;
+ return ei;
+ }
+ for(a=0, ei=G.sipo->editipo; a<G.sipo->totipo; a++, ei++)
+ if(ei->flag & IPO_ACTIVE)
+ return ei;
+
+ return NULL;
+}
+
+static void set_active_key(int index)
+{
+ if(G.sipo->blocktype==ID_KE && G.sipo->from) {
+ Object *ob= (Object *)G.sipo->from;
+ Key *key= ob_get_key(ob);
+
+ if(key) {
+ KeyBlock *curkb;
+
+ curkb= BLI_findlink(&key->block, index-1);
+ if(curkb) {
+ ob->shapenr= index;
+ ob->shapeflag |= OB_SHAPE_TEMPLOCK;
+
+ /* calc keypos */
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ }
+ }
+ }
+}
+
+void editipo_changed(SpaceIpo *si, int doredraw)
+{
+ EditIpo *ei;
+ View2D *v2d;
+ Key *key;
+ KeyBlock *kb;
+ int a, first=1;
+
+ ei= si->editipo;
+ if(ei==0)
+ return;
+
+ for(a=0; a<si->totipo; a++, ei++) {
+
+ if(ei->icu) {
+
+ /* twice because of ittererating new autohandle */
+ calchandles_ipocurve(ei->icu);
+ calchandles_ipocurve(ei->icu);
+
+ if(ei->flag & IPO_VISIBLE) {
+
+ boundbox_ipocurve(ei->icu, 0);
+ sort_time_ipocurve(ei->icu);
+ if(first) {
+ si->v2d.tot= ei->icu->totrct;
+ first= 0;
+ }
+ else BLI_union_rctf(&(si->v2d.tot), &(ei->icu->totrct));
+ }
+ }
+ }
+
+
+ v2d= &(si->v2d);
+
+ /* keylines? */
+ if(si->blocktype==ID_KE) {
+ key= ob_get_key((Object *)G.sipo->from);
+ if(key && key->block.first) {
+ kb= key->block.first;
+ if(kb->pos < v2d->tot.ymin) v2d->tot.ymin= kb->pos;
+ kb= key->block.last;
+ if(kb->pos > v2d->tot.ymax) v2d->tot.ymax= kb->pos;
+ }
+ }
+
+ /* is there no curve? */
+ if(first) {
+ v2d->tot.xmin= 0.0;
+ v2d->tot.xmax= EFRA;
+ v2d->tot.ymin= (float)-0.1;
+ v2d->tot.ymax= (float)1.1;
+
+ if(si->blocktype==ID_SEQ) {
+ v2d->tot.xmin= -5.0;
+ v2d->tot.xmax= 105.0;
+ v2d->tot.ymin= (float)-0.1;
+ v2d->tot.ymax= (float)1.1;
+ }
+ }
+
+ si->tot= v2d->tot;
+
+ if(doredraw) {
+ /* if you always call do_ipo: you get problems with insertkey, for example
+ * when inserting only a 'loc' the 'ob->rot' value then is changed.
+ */
+
+ if(si->blocktype==ID_OB) {
+ /* clear delta loc,rot,size (when free/delete ipo) */
+ clear_delta_obipo(si->ipo);
+
+ }
+
+ do_ipo(si->ipo);
+
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWTIME, 0);
+ allqueue(REDRAWNLA, 0);
+ allqueue(REDRAWBUTSOBJECT, 0);
+
+ if(si->blocktype==ID_OB) {
+ Object *ob= (Object *)si->from;
+ if(ob) DAG_object_flush_update(G.scene, ob, OB_RECALC_OB);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWNLA, 0);
+ }
+
+ else if(si->blocktype==ID_MA) allqueue(REDRAWBUTSSHADING, 0);
+ else if(si->blocktype==ID_TE) allqueue(REDRAWBUTSSHADING, 0);
+ else if(si->blocktype==ID_WO) allqueue(REDRAWBUTSSHADING, 0);
+ else if(si->blocktype==ID_LA) allqueue(REDRAWBUTSSHADING, 0);
+// else if(si->blocktype==ID_SO) allqueue(REDRAWBUTSSOUND, 0);
+ else if(si->blocktype==ID_CA) {
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ else if(si->blocktype==ID_SEQ) free_imbuf_seq_with_ipo(si->ipo);
+ else if(si->blocktype==ID_PO) {
+ Object *ob= OBACT;
+ if(ob && ob->pose) {
+ DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA);
+ }
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWNLA, 0);
+ }
+ else if(si->blocktype==ID_KE) {
+ DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ else if(si->blocktype==ID_CU) {
+ DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ }
+
+ if(si->showkey) make_ipokey();
+
+ if(si->actname[0])
+ synchronize_action_strips();
+}
+
+void scale_editipo(void)
+{
+ /* comes from buttons, scale with G.sipo->tot rect */
+
+ EditIpo *ei;
+ BezTriple *bezt;
+ float facx, facy;
+ int a, b;
+
+ facx= (G.sipo->tot.xmax-G.sipo->tot.xmin)/(G.sipo->v2d.tot.xmax-G.sipo->v2d.tot.xmin);
+ facy= (G.sipo->tot.ymax-G.sipo->tot.ymin)/(G.sipo->v2d.tot.ymax-G.sipo->v2d.tot.ymin);
+
+ ei= G.sipo->editipo;
+ if(ei==0) return;
+ for(a=0; a<G.sipo->totipo; a++, ei++) {
+ if (ISPOIN(ei, flag & IPO_VISIBLE, icu)) {
+ bezt= ei->icu->bezt;
+ b= ei->icu->totvert;
+ while(b--) {
+
+ bezt->vec[0][0]= facx*(bezt->vec[0][0] - G.sipo->v2d.tot.xmin) + G.sipo->tot.xmin;
+ bezt->vec[1][0]= facx*(bezt->vec[1][0] - G.sipo->v2d.tot.xmin) + G.sipo->tot.xmin;
+ bezt->vec[2][0]= facx*(bezt->vec[2][0] - G.sipo->v2d.tot.xmin) + G.sipo->tot.xmin;
+
+ bezt->vec[0][1]= facy*(bezt->vec[0][1] - G.sipo->v2d.tot.ymin) + G.sipo->tot.ymin;
+ bezt->vec[1][1]= facy*(bezt->vec[1][1] - G.sipo->v2d.tot.ymin) + G.sipo->tot.ymin;
+ bezt->vec[2][1]= facy*(bezt->vec[2][1] - G.sipo->v2d.tot.ymin) + G.sipo->tot.ymin;
+
+ bezt++;
+ }
+ }
+ }
+
+ editipo_changed(G.sipo, 1);
+
+ BIF_undo_push("Scale Edit Ipo");
+ allqueue(REDRAWNLA, 0);
+ allqueue (REDRAWACTION, 0);
+ allqueue(REDRAWIPO, 0);
+}
+
+static void make_ob_editipo(Object *ob, SpaceIpo *si)
+{
+ EditIpo *ei;
+ int a, len, colipo=0;
+ char *name;
+
+ if(ob->type==OB_MESH) colipo= 1;
+
+ ei= si->editipo= MEM_callocN(OB_TOTIPO*sizeof(EditIpo), "editipo");
+
+ si->totipo= OB_TOTIPO;
+
+ for(a=0; a<OB_TOTIPO; a++) {
+ name = getname_ob_ei(ob_ar[a], colipo);
+ strcpy(ei->name, name);
+ ei->adrcode= ob_ar[a];
+
+ if ELEM6(ei->adrcode, OB_ROT_X, OB_ROT_Y, OB_ROT_Z, OB_DROT_X, OB_DROT_Y, OB_DROT_Z) ei->disptype= IPO_DISPDEGR;
+ else if(ei->adrcode==OB_LAY) ei->disptype= IPO_DISPBITS;
+ else if(ei->adrcode==OB_TIME) ei->disptype= IPO_DISPTIME;
+
+ ei->col= ipo_rainbow(a, OB_TOTIPO);
+
+ if(colipo) {
+ len= strlen(ei->name);
+ if(len) {
+ if( ei->name[ len-1 ]=='R') ei->col= 0x5050FF;
+ else if( ei->name[ len-1 ]=='G') ei->col= 0x50FF50;
+ else if( ei->name[ len-1 ]=='B') ei->col= 0xFF7050;
+ }
+ }
+
+ ei->icu= find_ipocurve(si->ipo, ei->adrcode);
+ if(ei->icu) {
+ ei->flag= ei->icu->flag;
+ }
+
+
+ ei++;
+ }
+ //fprintf(stderr,"FSIMAKE_OPBJ call %d \n", si->totipo);
+}
+
+// copied from make_seq_editipo
+static void make_fluidsim_editipo(SpaceIpo *si) // NT
+{
+ EditIpo *ei;
+ int a;
+ char *name;
+ ei= si->editipo= MEM_callocN(FLUIDSIM_TOTIPO*sizeof(EditIpo), "fluidsim_editipo");
+ si->totipo = FLUIDSIM_TOTIPO;
+ for(a=0; a<FLUIDSIM_TOTIPO; a++) {
+ //fprintf(stderr,"FSINAME %d %d \n",a,fluidsim_ar[a], (int)(getname_fluidsim_ei(fluidsim_ar[a])) );
+ name = getname_fluidsim_ei(fluidsim_ar[a]);
+ strcpy(ei->name, name);
+ ei->adrcode= fluidsim_ar[a];
+ ei->col= ipo_rainbow(a, FLUIDSIM_TOTIPO);
+ ei->icu= find_ipocurve(si->ipo, ei->adrcode);
+ if(ei->icu) {
+ ei->flag = ei->icu->flag;
+ }
+ //else { ei->flag |= IPO_VISIBLE; }
+ //fprintf(stderr,"FSIMAKE eif%d,icuf%d icu%d %d|%d\n", ei->flag,ei->icu->flag, (int)ei->icu, IPO_VISIBLE,IPO_SELECT);
+ //fprintf(stderr,"FSIMAKE eif%d icu%d %d|%d\n", ei->flag, (int)ei->icu, IPO_VISIBLE,IPO_SELECT);
+ ei++;
+ }
+}
+
+static void make_seq_editipo(SpaceIpo *si)
+{
+ EditIpo *ei;
+ int a;
+ char *name;
+
+ ei= si->editipo= MEM_callocN(SEQ_TOTIPO*sizeof(EditIpo), "editipo");
+
+ si->totipo= SEQ_TOTIPO;
+
+
+ for(a=0; a<SEQ_TOTIPO; a++) {
+ name = getname_seq_ei(seq_ar[a]);
+ strcpy(ei->name, name);
+ ei->adrcode= seq_ar[a];
+
+ ei->col= ipo_rainbow(a, SEQ_TOTIPO);
+
+ ei->icu= find_ipocurve(si->ipo, ei->adrcode);
+ if(ei->icu) {
+ ei->flag= ei->icu->flag;
+ }
+ else ei->flag |= IPO_VISIBLE;
+
+ ei++;
+ }
+}
+
+static void make_cu_editipo(SpaceIpo *si)
+{
+ EditIpo *ei;
+ int a;
+ char *name;
+
+ ei= si->editipo= MEM_callocN(CU_TOTIPO*sizeof(EditIpo), "editipo");
+
+ si->totipo= CU_TOTIPO;
+
+
+ for(a=0; a<CU_TOTIPO; a++) {
+ name = getname_cu_ei(cu_ar[a]);
+ strcpy(ei->name, name);
+ ei->adrcode= cu_ar[a];
+
+ ei->col= ipo_rainbow(a, CU_TOTIPO);
+
+ ei->icu= find_ipocurve(si->ipo, ei->adrcode);
+ if(ei->icu) {
+ ei->flag= ei->icu->flag;
+ }
+ else ei->flag |= IPO_VISIBLE;
+
+ ei++;
+ }
+}
+
+static void make_key_editipo(SpaceIpo *si)
+{
+ Key *key;
+ KeyBlock *kb=NULL;
+ EditIpo *ei;
+ int a;
+
+ key= ob_get_key((Object *)G.sipo->from);
+ if(key==NULL) return;
+
+ si->totipo= BLI_countlist(&key->block);
+ ei= si->editipo= MEM_callocN(si->totipo*sizeof(EditIpo), "editipo");
+
+ for(a=0, kb= key->block.first; a<si->totipo; a++, ei++, kb= kb->next) {
+
+ if(kb->name[0] != 0) strncpy(ei->name, kb->name, 31); // length both same
+ ei->adrcode= kb->adrcode;
+
+ ei->col= ipo_rainbow(a, KEY_TOTIPO);
+
+ ei->icu= find_ipocurve(si->ipo, ei->adrcode);
+ if(ei->icu) {
+ ei->flag= ei->icu->flag;
+ }
+ else if(a==0)
+ if(key && key->type==KEY_NORMAL)
+ ei->flag |= IPO_VISIBLE;
+
+ /* active ipo is tied to active shape */
+ {
+ Object *ob= OBACT;
+ if(a==ob->shapenr-1)
+ set_active_editipo(ei);
+ }
+ }
+
+ ei= si->editipo;
+ if(key && key->type==KEY_RELATIVE) {
+ strcpy(ei->name, "----");
+ }
+ else {
+ ei->flag |= IPO_VISIBLE;
+ }
+}
+
+static void make_mat_editipo(SpaceIpo *si)
+{
+ EditIpo *ei;
+ int a, len;
+ char *name;
+
+ if(si->from==0) return;
+
+ ei= si->editipo= MEM_callocN(MA_TOTIPO*sizeof(EditIpo), "editipo");
+
+ si->totipo= MA_TOTIPO;
+
+ for(a=0; a<MA_TOTIPO; a++) {
+ name = getname_mat_ei(ma_ar[a]);
+ strcpy(ei->name, name);
+ ei->adrcode= ma_ar[a];
+
+ if(ei->adrcode & MA_MAP1) {
+ ei->adrcode-= MA_MAP1;
+ ei->adrcode |= texchannel_to_adrcode(si->channel);
+ }
+ else {
+ if(ei->adrcode==MA_MODE) ei->disptype= IPO_DISPBITS;
+ }
+
+ ei->col= ipo_rainbow(a, MA_TOTIPO);
+
+ len= strlen(ei->name);
+ if(len) {
+ if( ei->name[ len-1 ]=='R') ei->col= 0x5050FF;
+ else if( ei->name[ len-1 ]=='G') ei->col= 0x50FF50;
+ else if( ei->name[ len-1 ]=='B') ei->col= 0xFF7050;
+ }
+
+ ei->icu= find_ipocurve(si->ipo, ei->adrcode);
+ if(ei->icu) {
+ ei->flag= ei->icu->flag;
+ }
+
+ ei++;
+ }
+}
+
+static void make_texture_editipo(SpaceIpo *si)
+{
+ EditIpo *ei;
+ int a, len;
+ char *name;
+
+ if(si->from==0) return;
+
+ ei= si->editipo= MEM_callocN(TE_TOTIPO*sizeof(EditIpo), "editipo");
+
+ si->totipo= TE_TOTIPO;
+
+ for(a=0; a<TE_TOTIPO; a++) {
+ name = getname_tex_ei(te_ar[a]);
+ strcpy(ei->name, name);
+ ei->adrcode= te_ar[a];
+
+ ei->col= ipo_rainbow(a, TE_TOTIPO);
+
+ len= strlen(ei->name);
+ if(len) {
+ if( ei->name[ len-1 ]=='R') ei->col= 0x5050FF;
+ else if( ei->name[ len-1 ]=='G') ei->col= 0x50FF50;
+ else if( ei->name[ len-1 ]=='B') ei->col= 0xFF7050;
+ }
+ ei->icu= find_ipocurve(si->ipo, ei->adrcode);
+ if(ei->icu) {
+ ei->flag= ei->icu->flag;
+ }
+
+ ei++;
+ }
+}
+
+static void make_world_editipo(SpaceIpo *si)
+{
+ EditIpo *ei;
+ int a, len;
+ char *name;
+
+ if(si->from==0) return;
+
+ ei= si->editipo= MEM_callocN(WO_TOTIPO*sizeof(EditIpo), "editipo");
+
+ si->totipo= WO_TOTIPO;
+
+ for(a=0; a<WO_TOTIPO; a++) {
+ name = getname_world_ei(wo_ar[a]);
+
+ strcpy(ei->name, name);
+ ei->adrcode= wo_ar[a];
+
+ if(ei->adrcode & MA_MAP1) {
+ ei->adrcode-= MA_MAP1;
+ ei->adrcode |= texchannel_to_adrcode(si->channel);
+ }
+ else {
+ if(ei->adrcode==MA_MODE) ei->disptype= IPO_DISPBITS;
+ }
+
+ ei->col= ipo_rainbow(a, WO_TOTIPO);
+
+ len= strlen(ei->name);
+ if(len) {
+ if( ei->name[ len-1 ]=='R') ei->col= 0x5050FF;
+ else if( ei->name[ len-1 ]=='G') ei->col= 0x50FF50;
+ else if( ei->name[ len-1 ]=='B') ei->col= 0xFF7050;
+ }
+
+ ei->icu= find_ipocurve(si->ipo, ei->adrcode);
+ if(ei->icu) {
+ ei->flag= ei->icu->flag;
+ }
+
+ ei++;
+ }
+}
+
+static void make_lamp_editipo(SpaceIpo *si)
+{
+ EditIpo *ei;
+ int a;
+ char *name;
+
+ ei= si->editipo= MEM_callocN(LA_TOTIPO*sizeof(EditIpo), "editipo");
+
+ si->totipo= LA_TOTIPO;
+
+ for(a=0; a<LA_TOTIPO; a++) {
+ name = getname_la_ei(la_ar[a]);
+ strcpy(ei->name, name);
+ ei->adrcode= la_ar[a];
+
+ if(ei->adrcode & MA_MAP1) {
+ ei->adrcode-= MA_MAP1;
+ ei->adrcode |= texchannel_to_adrcode(si->channel);
+ }
+
+ ei->col= ipo_rainbow(a, LA_TOTIPO);
+
+ ei->icu= find_ipocurve(si->ipo, ei->adrcode);
+ if(ei->icu) {
+ ei->flag= ei->icu->flag;
+ }
+
+ ei++;
+ }
+}
+
+static void make_camera_editipo(SpaceIpo *si)
+{
+ EditIpo *ei;
+ int a;
+ char *name;
+
+ ei= si->editipo= MEM_callocN(CAM_TOTIPO*sizeof(EditIpo), "editipo");
+
+ si->totipo= CAM_TOTIPO;
+
+
+ for(a=0; a<CAM_TOTIPO; a++) {
+ name = getname_cam_ei(cam_ar[a]);
+ strcpy(ei->name, name);
+ ei->adrcode= cam_ar[a];
+
+ ei->col= ipo_rainbow(a, CAM_TOTIPO);
+
+ ei->icu= find_ipocurve(si->ipo, ei->adrcode);
+ if(ei->icu) {
+ ei->flag= ei->icu->flag;
+ }
+
+ ei++;
+ }
+}
+
+static int make_constraint_editipo(Ipo *ipo, EditIpo **si)
+{
+ EditIpo *ei;
+ int a;
+ char *name;
+
+ ei= *si= MEM_callocN(CO_TOTIPO*sizeof(EditIpo), "editipo");
+
+ for(a=0; a<CO_TOTIPO; a++) {
+ name = getname_co_ei(co_ar[a]);
+ strcpy(ei->name, name);
+ ei->adrcode= co_ar[a];
+
+ ei->col= ipo_rainbow(a, CO_TOTIPO);
+
+ ei->icu= find_ipocurve(ipo, ei->adrcode);
+ if(ei->icu) {
+ ei->flag= ei->icu->flag;
+ }
+
+ ei++;
+ }
+
+ return CO_TOTIPO;
+}
+
+static int make_bone_editipo(Ipo *ipo, EditIpo **si)
+{
+ EditIpo *ei;
+ int a;
+ char *name;
+
+ ei= *si= MEM_callocN(AC_TOTIPO*sizeof(EditIpo), "editipo");
+
+ for(a=0; a<AC_TOTIPO; a++) {
+ name = getname_ac_ei(ac_ar[a]);
+ strcpy(ei->name, name);
+ ei->adrcode= ac_ar[a];
+
+ ei->col= ipo_rainbow(a, AC_TOTIPO);
+
+ ei->icu= find_ipocurve(ipo, ei->adrcode);
+ if(ei->icu) {
+ ei->flag= ei->icu->flag;
+ }
+
+ ei++;
+ }
+
+ return AC_TOTIPO;
+}
+
+static void make_sound_editipo(SpaceIpo *si)
+{
+ EditIpo *ei;
+ int a;
+ char *name;
+
+ ei= si->editipo= MEM_callocN(SND_TOTIPO*sizeof(EditIpo), "editipo");
+
+ si->totipo= SND_TOTIPO;
+
+
+ for(a=0; a<SND_TOTIPO; a++) {
+ name = getname_snd_ei(snd_ar[a]);
+ strcpy(ei->name, name);
+ ei->adrcode= snd_ar[a];
+
+ ei->col= ipo_rainbow(a, SND_TOTIPO);
+
+ ei->icu= find_ipocurve(si->ipo, ei->adrcode);
+ if(ei->icu) {
+ ei->flag= ei->icu->flag;
+ }
+
+ ei++;
+ }
+}
+
+/* only called in test_editipo() below */
+static void make_editipo(void)
+{
+ EditIpo *ei;
+ Object *ob;
+ rctf *rf;
+ int a;
+
+ if(G.sipo->editipo)
+ MEM_freeN(G.sipo->editipo);
+
+ G.sipo->editipo= NULL;
+ G.sipo->totipo= 0;
+
+ if(G.sipo->from==NULL) return;
+
+ ob= OBACT;
+
+ if(G.sipo->ipo) G.sipo->showkey= G.sipo->ipo->showkey;
+
+ if(G.sipo->blocktype==ID_SEQ) {
+ make_seq_editipo(G.sipo);
+ }
+ else if(G.sipo->blocktype==ID_WO) {
+ make_world_editipo(G.sipo);
+ }
+ else if(G.sipo->blocktype==ID_OB) {
+ if (ob) {
+ ob->ipowin= ID_OB;
+ make_ob_editipo(ob, G.sipo);
+ }
+ }
+ else if(G.sipo->blocktype==ID_MA) {
+ if (ob) {
+ ob->ipowin= ID_MA;
+ make_mat_editipo(G.sipo);
+ }
+ }
+ else if(G.sipo->blocktype==ID_CU) {
+ if (ob) {
+ ob->ipowin= ID_CU;
+ make_cu_editipo(G.sipo);
+ }
+ }
+ else if(G.sipo->blocktype==ID_KE) {
+ if (ob) {
+ ob->ipowin= ID_KE;
+ make_key_editipo(G.sipo);
+ }
+ }
+ else if(G.sipo->blocktype==ID_LA) {
+ if (ob) {
+ ob->ipowin= ID_LA;
+ make_lamp_editipo(G.sipo);
+ }
+ }
+ else if(G.sipo->blocktype==ID_TE) {
+ if (ob) {
+ ob->ipowin= ID_TE;
+ make_texture_editipo(G.sipo);
+ }
+ }
+ else if(G.sipo->blocktype==ID_CA) {
+ if (ob) {
+ ob->ipowin= ID_CA;
+ make_camera_editipo(G.sipo);
+ }
+ }
+ else if(G.sipo->blocktype==ID_SO) {
+ if (ob) {
+ ob->ipowin= ID_SO;
+ make_sound_editipo(G.sipo);
+ }
+ }
+ else if(G.sipo->blocktype==ID_CO){
+ G.sipo->totipo = make_constraint_editipo(G.sipo->ipo, (EditIpo**)&G.sipo->editipo);
+ if (ob) {
+ ob->ipowin= ID_CO;
+ }
+ }
+ else if(G.sipo->blocktype==ID_PO) {
+
+ G.sipo->totipo = make_bone_editipo(G.sipo->ipo, (EditIpo**)&G.sipo->editipo);
+ if (ob) {
+ ob->ipowin= ID_PO;
+ }
+ }
+ else if(G.sipo->blocktype==ID_FLUIDSIM) {
+ if (ob) { // NT
+ ob->ipowin= ID_FLUIDSIM;
+ make_fluidsim_editipo(G.sipo);
+ }
+ }
+
+ if(G.sipo->editipo==0) return;
+
+ ei= G.sipo->editipo;
+ for(a=0; a<G.sipo->totipo; a++, ei++) {
+ if(ei->icu) ei->icu->flag= ei->flag;
+ }
+ editipo_changed(G.sipo, 0);
+
+ /* sets globals, bad stuff but we need these variables in other parts of code */
+ get_status_editipo();
+
+ if(G.sipo->ipo) {
+
+ if (G.sipo->pin)
+ rf= &(G.sipo->v2d.cur);
+ else
+ rf= &(G.sipo->ipo->cur);
+
+ if(rf->xmin<rf->xmax && rf->ymin<rf->ymax) G.v2d->cur= *rf;
+ else ipo_default_v2d_cur(G.sipo->blocktype, &G.v2d->cur);
+ }
+ else {
+ ipo_default_v2d_cur(G.sipo->blocktype, &G.v2d->cur);
+ }
+
+ view2d_do_locks(curarea, V2D_LOCK_COPY);
+}
+
+/* evaluates context in the current UI */
+/* blocktype is type of ipo */
+/* from is the base pointer to find data to change (ob in case of action or pose) */
+static void get_ipo_context(short blocktype, ID **from, Ipo **ipo, char *actname, char *constname)
+{
+ Object *ob= OBACT;
+
+ *from= NULL;
+ *ipo= NULL;
+
+ if(blocktype==ID_CO) {
+ if (ob) {
+ bConstraintChannel *chan;
+ bConstraint *con= get_active_constraint(ob);
+
+ if(con) {
+ BLI_strncpy(constname, con->name, 32);
+
+ chan= get_active_constraint_channel(ob);
+ if(chan) {
+ *ipo= chan->ipo;
+ BLI_strncpy(constname, con->name, 32);
+ }
+
+ *from= &ob->id;
+
+ /* set actname if in posemode */
+ if(ob->action) {
+ if(ob->flag & OB_POSEMODE) {
+ bPoseChannel *pchan= get_active_posechannel(ob);
+ if(pchan)
+ BLI_strncpy(actname, pchan->name, 32);
+ }
+ else if(ob->ipoflag & OB_ACTION_OB)
+ strcpy(actname, "Object");
+ }
+ }
+ }
+ }
+ else if(blocktype==ID_PO) {
+ if (ob && ob->action && ob->type==OB_ARMATURE) {
+ bPoseChannel *pchan= get_active_posechannel(ob);
+
+ *from= (ID *)ob;
+ if (pchan) {
+ bActionChannel *achan;
+
+ BLI_strncpy(actname, pchan->name, 32); /* also set when no channel yet */
+
+ achan= get_action_channel(ob->action, pchan->name);
+ if(achan)
+ *ipo= achan->ipo;
+ }
+ }
+
+ }
+ else if(blocktype==ID_OB) {
+ if(ob) {
+ *from= (ID *)ob;
+ if(ob->ipoflag & OB_ACTION_OB) {
+ if (ob->action) {
+ bActionChannel *achan= get_action_channel(ob->action, "Object");
+ if(achan) {
+ *ipo= achan->ipo;
+ BLI_strncpy(actname, achan->name, 32);
+ }
+ }
+ }
+ else {
+ *ipo= ob->ipo;
+ }
+ }
+ }
+ else if(blocktype==ID_SEQ) {
+ Sequence *last_seq = get_last_seq();
+
+ if(last_seq && ((last_seq->type & SEQ_EFFECT)||(last_seq->type == SEQ_HD_SOUND)||(last_seq->type == SEQ_RAM_SOUND))) {
+ *from= (ID *)last_seq;
+ *ipo= last_seq->ipo;
+ }
+ }
+ else if(blocktype==ID_WO) {
+ World *wo= G.scene->world;
+ *from= (ID *)wo;
+ if(wo) *ipo= wo->ipo;
+ }
+ else if(blocktype==ID_TE) {
+ if(ob) {
+ Tex *tex= give_current_texture(ob, ob->actcol);
+ *from= (ID *)tex;
+ if(tex) *ipo= tex->ipo;
+ }
+ }
+ else if(blocktype==ID_MA) {
+ if(ob) {
+ Material *ma= give_current_material(ob, ob->actcol);
+ ma= editnode_get_active_material(ma);
+ *from= (ID *)ma;
+ if(ma) *ipo= ma->ipo;
+ }
+ }
+ else if(blocktype==ID_KE) {
+ if(ob) {
+ Key *key= ob_get_key(ob);
+
+ if(ob->ipoflag & OB_ACTION_KEY) {
+ if (ob->action) {
+ bActionChannel *achan= get_action_channel(ob->action, "Shape");
+ if(achan) {
+ *ipo= achan->ipo;
+ BLI_strncpy(actname, achan->name, 32);
+ }
+ }
+ }
+ else if(key) *ipo= key->ipo;
+
+ *from= (ID *)ob;
+ }
+ }
+ else if(blocktype==ID_CU) {
+ if(ob && ob->type==OB_CURVE) {
+ Curve *cu= ob->data;
+ *from= (ID *)cu;
+ *ipo= cu->ipo;
+ }
+ }
+ else if(blocktype==ID_LA) {
+ if(ob && ob->type==OB_LAMP) {
+ Lamp *la= ob->data;
+ *from= (ID *)la;
+ *ipo= la->ipo;
+ }
+ }
+ else if(blocktype==ID_CA) {
+ if(ob && ob->type==OB_CAMERA) {
+ Camera *ca= ob->data;
+ *from= (ID *)ca;
+ if(ca) *ipo= ca->ipo;
+ }
+ }
+ else if(blocktype==ID_SO) {
+
+ // if (G.buts && G.buts->mainb == BUTS_SOUND) {
+ // bSound *sound = G.buts->lockpoin;
+ // *from= (ID *)sound;
+ // if(sound) *ipo= sound->ipo;
+ // }
+ }
+ else if(blocktype==ID_FLUIDSIM) {
+ if(ob && ( ob->fluidsimFlag & OB_FLUIDSIM_ENABLE)) {
+ FluidsimSettings *fss= ob->fluidsimSettings;
+ *from= (ID *)ob;
+ if(fss) *ipo= fss->ipo;
+ }
+ }
+}
+
+/* called on each redraw, check if editipo data has to be remade */
+/* if doit already set, it always makes (in case no ipo exists, we need to see the channels */
+void test_editipo(int doit)
+{
+
+ if(G.sipo->pin==0) {
+ Ipo *ipo;
+ ID *from;
+ char actname[32]="", constname[32]="";
+
+ get_ipo_context(G.sipo->blocktype, &from, &ipo, actname, constname);
+
+ if(G.sipo->ipo != ipo) {
+ G.sipo->ipo= ipo;
+ if(ipo) G.v2d->cur= ipo->cur;
+ doit= 1;
+ }
+ if(G.sipo->from != from) {
+ G.sipo->from= from;
+ doit= 1;
+ }
+ if( strcmp(G.sipo->actname, actname)) {
+ BLI_strncpy(G.sipo->actname, actname, 32);
+ doit= 1;
+ }
+ if( strcmp(G.sipo->constname, constname)) {
+ BLI_strncpy(G.sipo->constname, constname, 32);
+ doit= 1;
+ }
+
+ if(G.sipo->ipo)
+ G.sipo->ipo->cur = G.v2d->cur;
+
+ }
+
+ if(G.sipo->editipo==NULL || doit) {
+ make_editipo();
+ }
+}
+
+/* ****************** EditIpo ************************ */
+
+int totipo_edit=0, totipo_sel=0, totipo_curve=0, totipo_vis=0, totipo_vert=0, totipo_vertsel=0, totipo_key=0, totipo_keysel=0;
+
+void get_status_editipo(void)
+{
+ EditIpo *ei;
+ IpoKey *ik;
+ BezTriple *bezt;
+ int a, b;
+
+ totipo_vis= 0;
+ totipo_curve= 0;
+ totipo_sel= 0;
+ totipo_edit= 0;
+ totipo_vert= 0;
+ totipo_vertsel= 0;
+ totipo_key= 0;
+ totipo_keysel= 0;
+
+ if(G.sipo->ipo && G.sipo->ipo->id.lib) return;
+
+ ei= G.sipo->editipo;
+ if(ei==0) return;
+ for(a=0; a<G.sipo->totipo; a++) {
+ if( ei->flag & IPO_VISIBLE ) {
+ totipo_vis++;
+ if(ei->flag & IPO_SELECT) totipo_sel++;
+ if(ei->icu && ei->icu->totvert) totipo_curve++;
+ if(G.sipo->showkey || (ei->flag & IPO_EDIT)) {
+
+ /* if showkey: do count the vertices (for grab) */
+ if(G.sipo->showkey==0) totipo_edit++;
+
+ if(ei->icu) {
+ if(ei->icu->bezt) {
+ bezt= ei->icu->bezt;
+ b= ei->icu->totvert;
+ while(b--) {
+ if(ei->icu->ipo==IPO_BEZ) {
+ if(bezt->f1 & 1) totipo_vertsel++;
+ if(bezt->f3 & 1) totipo_vertsel++;
+ totipo_vert+= 2;
+ }
+ if(bezt->f2 & 1) totipo_vertsel++;
+
+ totipo_vert++;
+ bezt++;
+ }
+ }
+ }
+ }
+ }
+ ei++;
+ }
+
+ if(G.sipo->showkey) {
+ ik= G.sipo->ipokey.first;
+ while(ik) {
+ totipo_key++;
+ if(ik->flag & 1) totipo_keysel++;
+ ik= ik->next;
+ }
+ }
+}
+
+/* synchronize editipo flag with icu flag and ipokey flags */
+void update_editipo_flags(void)
+{
+ EditIpo *ei;
+ IpoKey *ik;
+ int a;
+
+ ei= G.sipo->editipo;
+ if(ei) {
+ for(a=0; a<G.sipo->totipo; a++, ei++) {
+ if(ei->icu) ei->icu->flag= ei->flag;
+ }
+ }
+ if(G.sipo->showkey) {
+ ik= G.sipo->ipokey.first;
+ while(ik) {
+ for(a=0; a<G.sipo->totipo; a++) {
+ if(ik->data[a]) {
+ if(ik->flag & 1) {
+ ik->data[a]->f1 |= 1;
+ ik->data[a]->f2 |= 1;
+ ik->data[a]->f3 |= 1;
+ }
+ else {
+ ik->data[a]->f1 &= ~1;
+ ik->data[a]->f2 &= ~1;
+ ik->data[a]->f3 &= ~1;
+ }
+ }
+ }
+ ik= ik->next;
+ }
+ }
+}
+
+/* sort of enter/leave editmode for curves */
+void set_editflag_editipo(void)
+{
+ EditIpo *ei;
+ int a; /* , tot= 0, ok= 0; */
+
+ /* after showkey immediately go to editing of selected points */
+ if(G.sipo->showkey) {
+ G.sipo->showkey= 0;
+ if(G.sipo->ipo) G.sipo->ipo->showkey= 0;
+ ei= G.sipo->editipo;
+ for(a=0; a<G.sipo->totipo; a++, ei++) ei->flag |= IPO_SELECT;
+ scrarea_queue_headredraw(curarea);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+
+ get_status_editipo();
+
+ if(G.sipo->ipo && G.sipo->ipo->id.lib) return;
+
+ ei= G.sipo->editipo;
+ for(a=0; a<G.sipo->totipo; a++, ei++) {
+ if(ei->icu) {
+ if(ei->flag & IPO_VISIBLE) {
+
+ if(totipo_edit==0 && (ei->flag & IPO_SELECT)) {
+ ei->flag |= IPO_EDIT;
+ ei->icu->flag= ei->flag;
+ }
+ else if(totipo_edit && (ei->flag & IPO_EDIT)) {
+ ei->flag -= IPO_EDIT;
+ ei->icu->flag= ei->flag;
+ }
+ else if(totipo_vis==1) {
+ if(ei->flag & IPO_EDIT) ei->flag -= IPO_EDIT;
+ else ei->flag |= IPO_EDIT;
+ ei->icu->flag= ei->flag;
+ }
+ }
+ }
+ }
+ scrarea_queue_headredraw(curarea);
+ scrarea_queue_winredraw(curarea);
+}
+
+static short findnearest_ipovert(IpoCurve **icu, BezTriple **bezt)
+{
+ /* selected verts get a disadvantage */
+ /* in icu and (bezt or bp) the nearest is written */
+ /* return 0 1 2: handlepunt */
+ EditIpo *ei;
+ BezTriple *bezt1;
+ int dist= 100, temp, a, b;
+ short mval[2], hpoint=0, sco[3][2];
+
+ *icu= 0;
+ *bezt= 0;
+
+ getmouseco_areawin(mval);
+
+ ei= G.sipo->editipo;
+ for(a=0; a<G.sipo->totipo; a++, ei++) {
+ if (ISPOIN3(ei, flag & IPO_VISIBLE, flag & IPO_EDIT, icu)) {
+
+ if(ei->icu->bezt) {
+ bezt1= ei->icu->bezt;
+ b= ei->icu->totvert;
+ while(b--) {
+
+ ipoco_to_areaco_noclip(G.v2d, bezt1->vec[0], sco[0]);
+ ipoco_to_areaco_noclip(G.v2d, bezt1->vec[1], sco[1]);
+ ipoco_to_areaco_noclip(G.v2d, bezt1->vec[2], sco[2]);
+
+ if(ei->disptype==IPO_DISPBITS) {
+ temp= abs(mval[0]- sco[1][0]);
+ }
+ else temp= abs(mval[0]- sco[1][0])+ abs(mval[1]- sco[1][1]);
+
+ if( bezt1->f2 & 1) temp+=5;
+ if(temp<dist) {
+ hpoint= 1;
+ *bezt= bezt1;
+ dist= temp;
+ *icu= ei->icu;
+ }
+
+ if(ei->disptype!=IPO_DISPBITS && ei->icu->ipo==IPO_BEZ) {
+ /* middle points get an advantage */
+ temp= -3+abs(mval[0]- sco[0][0])+ abs(mval[1]- sco[0][1]);
+ if( bezt1->f1 & 1) temp+=5;
+ if(temp<dist) {
+ hpoint= 0;
+ *bezt= bezt1;
+ dist= temp;
+ *icu= ei->icu;
+ }
+
+ temp= abs(mval[0]- sco[2][0])+ abs(mval[1]- sco[2][1]);
+ if( bezt1->f3 & 1) temp+=5;
+ if(temp<dist) {
+ hpoint= 2;
+ *bezt=bezt1;
+ dist= temp;
+ *icu= ei->icu;
+ }
+ }
+ bezt1++;
+ }
+ }
+ }
+ }
+
+ return hpoint;
+}
+
+void mouse_select_ipo(void)
+{
+ Object *ob;
+ KeyBlock *actkb=NULL;
+ EditIpo *ei, *actei= 0;
+ IpoCurve *icu;
+ IpoKey *ik, *actik;
+ BezTriple *bezt;
+ TimeMarker *marker;
+ float x, y, dist, mindist;
+ int a, oldflag = 0, hand, ok;
+ short mval[2], xo, yo;
+
+ if(G.sipo->editipo==0) return;
+
+ get_status_editipo();
+ marker=find_nearest_marker(1);
+
+ /* map ipo-points for editing if scaled ipo */
+ if (NLA_IPO_SCALED) {
+ actstrip_map_ipo_keys(OBACT, G.sipo->ipo, 0, 0);
+ }
+
+ if(G.sipo->showkey) {
+ getmouseco_areawin(mval);
+
+ areamouseco_to_ipoco(G.v2d, mval, &x, &y);
+ actik= 0;
+ mindist= 1000.0;
+ ik= G.sipo->ipokey.first;
+ while(ik) {
+ dist= (float)(fabs(ik->val-x));
+ if(ik->flag & 1) dist+= 1.0;
+ if(dist < mindist) {
+ actik= ik;
+ mindist= dist;
+ }
+ ik= ik->next;
+ }
+ if(actik) {
+ oldflag= actik->flag;
+
+ if(G.qual & LR_SHIFTKEY);
+ else deselectall_editipo();
+
+ if(G.qual & LR_SHIFTKEY) {
+ if(oldflag & 1) actik->flag &= ~1;
+ else actik->flag |= 1;
+ }
+ else {
+ actik->flag |= 1;
+ }
+ }
+ }
+ else if(totipo_edit) {
+
+ hand= findnearest_ipovert(&icu, &bezt);
+
+ if(G.qual & LR_SHIFTKEY) {
+ if(bezt) {
+ if(hand==1) {
+ if(BEZSELECTED(bezt)) {
+ bezt->f1= bezt->f2= bezt->f3= 0;
+ }
+ else {
+ bezt->f1= bezt->f2= bezt->f3= 1;
+ }
+ }
+ else if(hand==0) {
+ if(bezt->f1 & 1) bezt->f1= 0;
+ else bezt->f1= 1;
+ }
+ else {
+ if(bezt->f3 & 1) bezt->f3= 0;
+ else bezt->f3= 1;
+ }
+ }
+ }
+ else {
+ deselectall_editipo();
+
+ if(bezt) {
+ if(hand==1) {
+ bezt->f1|= 1; bezt->f2|= 1; bezt->f3|= 1;
+ }
+ else if(hand==0) bezt->f1|= 1;
+ else bezt->f3|= 1;
+ }
+ }
+ }
+ else if (marker) {
+ /* select timeline marker */
+ if ((G.qual & LR_SHIFTKEY)==0) {
+ oldflag= marker->flag;
+ deselect_markers(0, 0);
+
+ if (oldflag & SELECT)
+ marker->flag &= ~SELECT;
+ else
+ marker->flag |= SELECT;
+ }
+ else {
+ marker->flag |= SELECT;
+ }
+ }
+ else {
+
+ /* vertex keys ? */
+ if(G.sipo->blocktype==ID_KE && G.sipo->from) {
+ Key *key;
+ KeyBlock *kb, *curkb;
+ int i, index= 1;
+
+ ob= (Object *)G.sipo->from;
+ key= ob_get_key(ob);
+ curkb= BLI_findlink(&key->block, ob->shapenr-1);
+
+ ei= G.sipo->editipo;
+ if(key->type==KEY_NORMAL || (ei->flag & IPO_VISIBLE)) {
+ getmouseco_areawin(mval);
+
+ areamouseco_to_ipoco(G.v2d, mval, &x, &y);
+ /* how much is 20 pixels? */
+ mindist= (float)(20.0*(G.v2d->cur.ymax-G.v2d->cur.ymin)/(float)curarea->winy);
+
+ for(i=1, kb= key->block.first; kb; kb= kb->next, i++) {
+ dist= (float)(fabs(kb->pos-y));
+ if(kb==curkb) dist+= (float)0.01;
+ if(dist < mindist) {
+ actkb= kb;
+ mindist= dist;
+ index= i;
+ }
+ }
+ if(actkb) {
+ ok= TRUE;
+ if(G.obedit && actkb!=curkb) {
+ ok= okee("Copy key after leaving Edit Mode");
+ }
+ if(ok) {
+ /* also does all keypos */
+ deselectall_editipo();
+ set_active_key(index);
+ set_active_editipo(ei+index-1);
+ }
+ }
+ }
+ }
+
+ /* select curve */
+ if(actkb==NULL) {
+ if(totipo_vis==1) {
+ ei= G.sipo->editipo;
+ for(a=0; a<G.sipo->totipo; a++, ei++) {
+ if(ei->icu) {
+ if(ei->flag & IPO_VISIBLE) actei= ei;
+ }
+ }
+ }
+ else if(totipo_vis>1) {
+ actei= select_proj_ipo(0, 0);
+ }
+
+ if(actei) oldflag= actei->flag;
+
+ if(G.qual & LR_SHIFTKEY);
+ else deselectall_editipo();
+
+ if(actei) {
+ if(G.qual & LR_SHIFTKEY) {
+ if(oldflag & IPO_SELECT) actei->flag &= ~IPO_SELECT;
+ else actei->flag |= IPO_SELECT;
+ }
+ else {
+ actei->flag |= IPO_SELECT;
+ }
+ set_active_editipo(actei);
+ }
+ }
+ }
+
+ /* undo mapping of ipo-points for editing if scaled ipo */
+ if (NLA_IPO_SCALED) {
+ actstrip_map_ipo_keys(OBACT, G.sipo->ipo, 1, 0);
+ }
+
+ update_editipo_flags();
+
+ force_draw(0);
+ BIF_undo_push("Select Ipo");
+
+ if(G.sipo->showkey && G.sipo->blocktype==ID_OB) {
+ ob= OBACT;
+ if(ob && (ob->ipoflag & OB_DRAWKEY)) allqueue(REDRAWVIEW3D, 0);
+ }
+ /* points inside of curve are drawn selected too */
+ if(G.sipo->blocktype==ID_CU)
+ allqueue(REDRAWVIEW3D, 0);
+
+ getmouseco_areawin(mval);
+ xo= mval[0];
+ yo= mval[1];
+
+ while(get_mbut()&R_MOUSE) {
+ getmouseco_areawin(mval);
+ if(abs(mval[0]-xo)+abs(mval[1]-yo) > 4) {
+
+ if (marker) {
+ transform_markers('g', 0);
+ }
+ else {
+ if(actkb) move_keys(OBACT);
+ else transform_ipo('g');
+ }
+
+ return;
+ }
+ BIF_wait_for_statechange();
+ }
+}
+
+
+/* *********************************** */
+
+/* handling of right-hand channel/curve buttons in ipo window */
+void do_ipowin_buts(short event)
+{
+ EditIpo *ei = NULL;
+ int a;
+
+ /* without shift, all other channels are made invisible */
+ if((G.qual & LR_SHIFTKEY)==0) {
+ if(event>G.sipo->totipo) return;
+ ei = G.sipo->editipo;
+ for(a=0; a<G.sipo->totipo; a++) {
+ if(a!=event) ei->flag &= ~IPO_VISIBLE;
+ else ei->flag |= IPO_VISIBLE;
+ ei++;
+ }
+ }
+
+ /* set active */
+ if(event>=0 && event<G.sipo->totipo) {
+ ei= G.sipo->editipo; // void pointer...
+ set_active_editipo(ei+event);
+ set_active_key(event+1); // only if there's a key, of course
+ }
+ scrarea_queue_winredraw(curarea);
+
+ update_editipo_flags();
+ get_status_editipo();
+
+ if(G.sipo->showkey) {
+ make_ipokey();
+ if(G.sipo->blocktype==ID_OB) allqueue(REDRAWVIEW3D, 0);
+ }
+
+}
+
+/* the fake buttons to the left of channel names, for select/deselect curves */
+void do_ipo_selectbuttons(void)
+{
+ EditIpo *ei, *ei1;
+ int a, nr;
+ short mval[2];
+
+ if(G.sipo->showkey) return;
+
+ /* do not allow editipo here: convert editipos to selected */
+ get_status_editipo();
+ if(totipo_edit) {
+ set_editflag_editipo();
+ }
+
+ /* which */
+ getmouseco_areawin(mval);
+
+ nr= -(mval[1]-curarea->winy+30-G.sipo->butofs-IPOBUTY)/IPOBUTY;
+ if(G.sipo->blocktype==ID_KE) nr--; /* keys show something else in first channel */
+
+ if(nr>=0 && nr<G.sipo->totipo) {
+ ei= G.sipo->editipo;
+ ei+= nr;
+
+ set_active_editipo(ei);
+ set_active_key(nr+1);
+
+ if(ei->icu) {
+ if((ei->flag & IPO_VISIBLE)==0) {
+ ei->flag |= IPO_VISIBLE|IPO_SELECT;
+ }
+
+ if((G.qual & LR_SHIFTKEY)==0) {
+ ei1= G.sipo->editipo;
+ for(a=0; a<G.sipo->totipo; a++) {
+ ei1->flag &= ~IPO_SELECT;
+ ei1++;
+ }
+ }
+
+ if(ei->flag & IPO_SELECT) {
+ ei->flag &= ~IPO_SELECT;
+ }
+ else {
+ ei->flag |= IPO_SELECT;
+ }
+
+ update_editipo_flags();
+ scrarea_queue_winredraw(curarea);
+ }
+ }
+ BIF_undo_push("Select Ipo curve");
+}
+
+/* ********************************* Inserting keys ********************************************* */
+
+/* depending type, it returns ipo, if needed it creates one */
+/* returns either action ipo or "real" ipo */
+/* arguments define full context;
+ - *from has to be set always, to Object in case of Actions
+ - blocktype defines available channels of Ipo struct (blocktype ID_OB can be in action too)
+ - if actname, use this to locate action, and optional constname to find the channel
+*/
+
+/* note; check header_ipo.c, spaceipo_assign_ipo() too */
+Ipo *verify_ipo(ID *from, short blocktype, char *actname, char *constname)
+{
+
+ if(from==NULL || from->lib) return NULL;
+
+ /* first check action ipos */
+ if(actname && actname[0]) {
+ Object *ob= (Object *)from;
+ bActionChannel *achan;
+
+ if(GS(from->name)!=ID_OB) {
+ printf("called ipo system for action with wrong base pointer\n");
+ return NULL;
+ }
+
+ if(ob->action==NULL)
+ ob->action= add_empty_action("Action");
+
+ achan= verify_action_channel(ob->action, actname);
+
+ if(achan) {
+ /* constraint exception */
+ if(blocktype==ID_CO) {
+ bConstraintChannel *conchan= verify_constraint_channel(&achan->constraintChannels, constname);
+ if(conchan->ipo==NULL) {
+ conchan->ipo= add_ipo("CoIpo", ID_CO);
+ }
+ return conchan->ipo;
+ }
+ else {
+ if(achan->ipo==NULL) {
+ achan->ipo= add_ipo("ActIpo", blocktype);
+ }
+
+ return achan->ipo;
+ }
+ }
+ }
+ else {
+
+ switch(GS(from->name)) {
+ case ID_OB:
+ {
+ Object *ob= (Object *)from;
+ /* constraint exception */
+ if(blocktype==ID_CO) {
+ bConstraintChannel *conchan= verify_constraint_channel(&ob->constraintChannels, constname);
+ if(conchan->ipo==NULL) {
+ conchan->ipo= add_ipo("CoIpo", ID_CO);
+ }
+ return conchan->ipo;
+ }
+ else if(blocktype==ID_OB) {
+ if(ob->ipo==NULL) {
+ ob->ipo= add_ipo("ObIpo", ID_OB);
+ }
+ return ob->ipo;
+ }
+ else if(blocktype==ID_KE) {
+ Key *key= ob_get_key((Object *)from);
+
+ if(key) {
+ if(key->ipo==NULL) {
+ key->ipo= add_ipo("KeyIpo", ID_KE);
+ }
+ return key->ipo;
+ }
+ return NULL;
+ }
+ else if(blocktype== ID_FLUIDSIM) {
+ Object *ob= (Object *)from;
+ if(ob->fluidsimFlag & OB_FLUIDSIM_ENABLE) {
+ FluidsimSettings *fss= ob->fluidsimSettings;
+ if(fss->ipo==NULL) {
+ fss->ipo= add_ipo("FluidsimIpo", ID_FLUIDSIM);
+ //fprintf(stderr,"FSIPO NEW!\n");
+ }
+ return fss->ipo;
+ }
+ }
+ }
+ break;
+ case ID_MA:
+ {
+ Material *ma= (Material *)from;
+
+ if(ma->ipo==NULL) {
+ ma->ipo= add_ipo("MatIpo", ID_MA);
+ }
+ return ma->ipo;
+ }
+ break;
+ case ID_TE:
+ {
+ Tex *tex= (Tex *)from;
+
+ if(tex->ipo==NULL) {
+ tex->ipo= add_ipo("TexIpo", ID_TE);
+ }
+ return tex->ipo;
+ }
+ break;
+ case ID_SEQ:
+ {
+ Sequence *seq= (Sequence *)from; /* note, sequence is mimicing Id */
+
+ if((seq->type & SEQ_EFFECT)||
+ (seq->type == SEQ_RAM_SOUND)||
+ (seq->type == SEQ_HD_SOUND)) {
+ if(seq->ipo==NULL) {
+ seq->ipo= add_ipo("SeqIpo", ID_SEQ);
+ }
+ update_seq_ipo_rect(seq);
+ return seq->ipo;
+ }
+ }
+ break;
+ case ID_CU:
+ {
+ Curve *cu= (Curve *)from;
+
+ if(cu->ipo==NULL) {
+ cu->ipo= add_ipo("CuIpo", ID_CU);
+ }
+ return cu->ipo;
+ }
+ break;
+ case ID_WO:
+ {
+ World *wo= (World *)from;
+
+ if(wo->ipo==NULL) {
+ wo->ipo= add_ipo("WoIpo", ID_WO);
+ }
+ return wo->ipo;
+ }
+ break;
+ case ID_LA:
+ {
+ Lamp *la= (Lamp *)from;
+
+ if(la->ipo==NULL) {
+ la->ipo= add_ipo("LaIpo", ID_LA);
+ }
+ return la->ipo;
+ }
+ break;
+ case ID_CA:
+ {
+ Camera *ca= (Camera *)from;
+
+ if(ca->ipo==NULL) {
+ ca->ipo= add_ipo("CaIpo", ID_CA);
+ }
+ return ca->ipo;
+ }
+ break;
+ case ID_SO:
+ {
+ bSound *snd= (bSound *)from;
+
+ if(snd->ipo==NULL) {
+ snd->ipo= add_ipo("SndIpo", ID_SO);
+ }
+ return snd->ipo;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/* returns and creates
+ * Make sure functions check for NULL or they will crash!
+ * */
+IpoCurve *verify_ipocurve(ID *from, short blocktype, char *actname, char *constname, int adrcode)
+{
+ Ipo *ipo;
+ IpoCurve *icu= NULL;
+
+ /* return 0 if lib */
+ /* creates ipo too */
+ ipo= verify_ipo(from, blocktype, actname, constname);
+
+ if(ipo && ipo->id.lib==NULL && from->lib==NULL) {
+
+ for(icu= ipo->curve.first; icu; icu= icu->next) {
+ if(icu->adrcode==adrcode) break;
+ }
+ if(icu==NULL) {
+ icu= MEM_callocN(sizeof(IpoCurve), "ipocurve");
+
+ icu->flag |= IPO_VISIBLE|IPO_AUTO_HORIZ;
+ icu->blocktype= blocktype;
+ icu->adrcode= adrcode;
+
+ set_icu_vars(icu);
+
+ BLI_addtail( &(ipo->curve), icu);
+
+ switch (GS(from->name)) {
+ case ID_SEQ: {
+ Sequence *seq= (Sequence *)from;
+
+ update_seq_icu_rects(seq);
+ break;
+ }
+ }
+ }
+ }
+
+ return icu;
+}
+
+/* This function adds a given BezTriple to an IPO-Curve. It will allocate
+ * memory for the array if needed, and will insert the BezTriple into a
+ * suitable place in chronological order.
+ *
+ * NOTE: any recalculate of the IPO-Curve that needs to be done will need to
+ * be done by the caller.
+ */
+int insert_bezt_icu (IpoCurve *icu, BezTriple *bezt)
+{
+ BezTriple *newb, *beztd;
+ int i= 0;
+
+ if (icu->bezt == NULL) {
+ icu->bezt= MEM_callocN(sizeof(BezTriple), "beztriple");
+ *(icu->bezt)= *bezt;
+ icu->totvert= 1;
+ }
+ else {
+ beztd= icu->bezt;
+ for (i = 0; i <= icu->totvert; i++, beztd++) {
+ /* no double points - threshold to determine this should be good enough */
+ if ((i < icu->totvert) && IS_EQT(beztd->vec[1][0], bezt->vec[1][0], 0.00001)) {
+ *(beztd)= *bezt;
+ break;
+ }
+ /* if we've reached the end of the icu array, or bezt is to be pasted before current */
+ if (i==icu->totvert || beztd->vec[1][0] > bezt->vec[1][0]) {
+ newb= MEM_callocN( (icu->totvert+1)*sizeof(BezTriple), "beztriple");
+
+ /* add the beztriples that should occur before the beztriple to be pasted (originally in ei->icu) */
+ if (i > 0)
+ memcpy(newb, icu->bezt, i*sizeof(BezTriple));
+
+ /* add beztriple to paste at index j */
+ *(newb+i)= *bezt;
+
+ /* add the beztriples that occur after the beztriple to be pasted (originally in icu) */
+ if (i < icu->totvert)
+ memcpy(newb+i+1, icu->bezt+i, (icu->totvert-i)*sizeof(BezTriple));
+
+ MEM_freeN(icu->bezt);
+ icu->bezt= newb;
+
+ icu->totvert++;
+ break;
+ }
+ }
+ }
+
+ /* we need to return the index, so that some tools which do post-processing can
+ * detect where we added the BezTriple in the array
+ */
+ return i;
+}
+
+/* This function is a wrapper for insert_bezt_icu, and should be used when
+ * adding a new keyframe to a curve, when the keyframe doesn't exist anywhere
+ * else yet.
+ *
+ * 'fast' - is only for the python API where importing BVH's would take an extreamly long time.
+ */
+void insert_vert_icu (IpoCurve *icu, float x, float y, short fast)
+{
+ BezTriple beztr;
+ int a, h1, h2;
+
+ /* set all three points, for nicer start position */
+ memset(&beztr, 0, sizeof(BezTriple));
+ beztr.vec[0][0]= x;
+ beztr.vec[0][1]= y;
+ beztr.vec[1][0]= x;
+ beztr.vec[1][1]= y;
+ beztr.vec[2][0]= x;
+ beztr.vec[2][1]= y;
+ beztr.hide= IPO_BEZ;
+ beztr.f1= beztr.f2= beztr.f3= SELECT;
+ beztr.h1= beztr.h2= HD_AUTO;
+
+ /* add temp beztriple to keyframes */
+ a= insert_bezt_icu(icu, &beztr);
+ if (!fast) calchandles_ipocurve(icu);
+
+ /* set handletype */
+ if (icu->totvert > 2) {
+ BezTriple *bezt;
+
+ h1= h2= HD_AUTO;
+ bezt= (icu->bezt + a);
+
+ if (a > 0) h1= (bezt-1)->h2;
+ if (a < icu->totvert-1) h2= (bezt+1)->h1;
+
+ bezt->h1= h1;
+ bezt->h2= h2;
+
+ if (!fast) calchandles_ipocurve(icu);
+ }
+}
+
+void add_vert_ipo(void)
+{
+ EditIpo *ei;
+ float x, y;
+ int val;
+ short mval[2];
+
+ if(G.sipo->ipo && G.sipo->ipo->id.lib) return;
+ if(G.sipo->showkey) {
+ G.sipo->showkey= 0;
+ free_ipokey(&G.sipo->ipokey);
+ }
+
+ getmouseco_areawin(mval);
+
+ if(mval[0]>G.v2d->mask.xmax) return;
+
+ ei= get_active_editipo();
+ if(ei==NULL) {
+ error("No active Ipo curve");
+ return;
+ }
+ ei->flag |= IPO_VISIBLE; /* can happen it is active but not visible */
+
+ areamouseco_to_ipoco(G.v2d, mval, &x, &y);
+
+ /* convert click-time to ipo-time */
+ if (NLA_IPO_SCALED) {
+ x= get_action_frame(OBACT, x);
+ }
+
+ if(ei->icu==NULL) {
+ if(G.sipo->from) {
+ ei->icu= verify_ipocurve(G.sipo->from, G.sipo->blocktype, G.sipo->actname, G.sipo->constname, ei->adrcode);
+ if (ei->icu)
+ ei->flag |= ei->icu->flag & IPO_AUTO_HORIZ; /* new curve could have been added, weak... */
+ else
+ error("Cannot create an IPO curve, you may be using libdata");
+ }
+ }
+ if(ei->icu==NULL) return;
+
+ if(ei->disptype==IPO_DISPBITS) {
+ ei->icu->vartype= IPO_BITS;
+ val= (int)floor(y-0.5);
+ if(val<0) val= 0;
+ y= (float)(1 << val);
+ }
+
+ insert_vert_icu(ei->icu, x, y, 0);
+
+ /* to be sure: if icu was 0, or only 1 curve visible */
+ ei->flag |= IPO_SELECT;
+ ei->icu->flag= ei->flag;
+
+ editipo_changed(G.sipo, 1);
+ BIF_undo_push("Add Ipo vertex");
+}
+
+static void *get_context_ipo_poin(ID *id, int blocktype, char *actname, IpoCurve *icu, int *vartype)
+{
+ if(blocktype==ID_PO) {
+ if(GS(id->name)==ID_OB) {
+ Object *ob= (Object *)id;
+ bPoseChannel *pchan= get_pose_channel(ob->pose, actname);
+
+ *vartype= IPO_FLOAT;
+ return get_pchan_ipo_poin(pchan, icu->adrcode);
+ }
+ return NULL;
+ }
+ else
+ return get_ipo_poin(id, icu, vartype);
+
+}
+
+#define KEYNEEDED_DONTADD 0
+#define KEYNEEDED_JUSTADD 1
+#define KEYNEEDED_DELPREV 2
+#define KEYNEEDED_DELNEXT 3
+
+static int new_key_needed(IpoCurve *icu, float cFrame, float nValue)
+{
+ /* This function determines whether a new keyframe is needed */
+ /* Cases where keyframes should not be added:
+ * 1. Keyframe to be added bewteen two keyframes with similar values
+ * 2. Keyframe to be added on frame where two keyframes are already situated
+ * 3. Keyframe lies at point that intersects the linear line between two keyframes
+ */
+
+ BezTriple *bezt=NULL, *prev=NULL;
+ int totCount, i;
+ float valA = 0.0f, valB = 0.0f;
+
+ /* safety checking */
+ if (!icu) return KEYNEEDED_JUSTADD;
+ totCount= icu->totvert;
+ if (totCount==0) return KEYNEEDED_JUSTADD;
+
+ /* loop through checking if any are the same */
+ bezt= icu->bezt;
+ for (i=0; i<totCount; i++) {
+ float prevPosi=0.0f, prevVal=0.0f;
+ float beztPosi=0.0f, beztVal=0.0f;
+
+ /* get current time+value */
+ beztPosi= bezt->vec[1][0];
+ beztVal= bezt->vec[1][1];
+
+ if (prev) {
+ /* there is a keyframe before the one currently being examined */
+
+ /* get previous time+value */
+ prevPosi= prev->vec[1][0];
+ prevVal= prev->vec[1][1];
+
+ /* keyframe to be added at point where there are already two similar points? */
+ if (IS_EQ(prevPosi, cFrame) && IS_EQ(beztPosi, cFrame) && IS_EQ(beztPosi, prevPosi)) {
+ return KEYNEEDED_DONTADD;
+ }
+
+ /* keyframe between prev+current points ? */
+ if ((prevPosi <= cFrame) && (cFrame <= beztPosi)) {
+ /* is the value of keyframe to be added the same as keyframes on either side ? */
+ if (IS_EQ(prevVal, nValue) && IS_EQ(beztVal, nValue) && IS_EQ(prevVal, beztVal)) {
+ return KEYNEEDED_DONTADD;
+ }
+ else {
+ float realVal;
+
+ /* get real value of curve at that point */
+ realVal= eval_icu(icu, cFrame);
+
+ /* compare whether it's the same as proposed */
+ if (IS_EQ(realVal, nValue))
+ return KEYNEEDED_DONTADD;
+ else
+ return KEYNEEDED_JUSTADD;
+ }
+ }
+
+ /* new keyframe before prev beztriple? */
+ if (cFrame < prevPosi) {
+ /* A new keyframe will be added. However, whether the previous beztriple
+ * stays around or not depends on whether the values of previous/current
+ * beztriples and new keyframe are the same.
+ */
+ if (IS_EQ(prevVal, nValue) && IS_EQ(beztVal, nValue) && IS_EQ(prevVal, beztVal))
+ return KEYNEEDED_DELNEXT;
+ else
+ return KEYNEEDED_JUSTADD;
+ }
+ }
+ else {
+ /* just add a keyframe if there's only one keyframe
+ * and the new one occurs before the exisiting one does.
+ */
+ if ((cFrame < beztPosi) && (totCount==1))
+ return KEYNEEDED_JUSTADD;
+ }
+
+ /* continue. frame to do not yet passed (or other conditions not met) */
+ if (i < (totCount-1)) {
+ prev= bezt;
+ bezt++;
+ }
+ else
+ break;
+ }
+
+ /* Frame in which to add a new-keyframe occurs after all other keys
+ * -> If there are at least two existing keyframes, then if the values of the
+ * last two keyframes and the new-keyframe match, the last existing keyframe
+ * gets deleted as it is no longer required.
+ * -> Otherwise, a keyframe is just added. 1.0 is added so that fake-2nd-to-last
+ * keyframe is not equal to last keyframe.
+ */
+ bezt= (icu->bezt + (icu->totvert - 1));
+ valA= bezt->vec[1][1];
+
+ if (prev)
+ valB= prev->vec[1][1];
+ else
+ valB= bezt->vec[1][1] + 1.0f;
+
+ if (IS_EQ(valA, nValue) && IS_EQ(valA, valB))
+ return KEYNEEDED_DELPREV;
+ else
+ return KEYNEEDED_JUSTADD;
+}
+
+/* a duplicate of insertkey that does not check for routing to insertmatrixkey
+ to avoid recursion problems */
+static void insertkey_nonrecurs(ID *id, int blocktype, char *actname, char *constname, int adrcode)
+{
+ IpoCurve *icu;
+ Object *ob;
+ void *poin= NULL;
+ float curval, cfra;
+ int vartype;
+ int matset=0;
+
+ if (matset==0) {
+ icu= verify_ipocurve(id, blocktype, actname, constname, adrcode);
+
+ if(icu) {
+
+ poin= get_context_ipo_poin(id, blocktype, actname, icu, &vartype);
+
+ if(poin) {
+ curval= read_ipo_poin(poin, vartype);
+
+ cfra= frame_to_float(CFRA);
+
+ /* if action is mapped in NLA, it returns a correction */
+ if(actname && actname[0] && GS(id->name)==ID_OB)
+ cfra= get_action_frame((Object *)id, cfra);
+
+ if( GS(id->name)==ID_OB ) {
+ ob= (Object *)id;
+ if(ob->sf!=0.0 && (ob->ipoflag & OB_OFFS_OB) ) {
+ /* actually frametofloat calc again! */
+ cfra-= ob->sf*G.scene->r.framelen;
+ }
+ }
+
+ insert_vert_icu(icu, cfra, curval, 0);
+ }
+ }
+ }
+}
+
+int insertmatrixkey(ID *id, int blocktype, char *actname, char *constname, int adrcode)
+{
+ int matindex=0;
+ /* branch on adrcode and blocktype, generating the proper matrix-based
+ values to send to insertfloatkey */
+ if (GS(id->name)==ID_OB) {
+ Object *ob= (Object *)id;
+
+ if ( blocktype==ID_OB ){ //working with an object
+ if ((ob)&&!(ob->parent)) {
+ if ((adrcode==OB_ROT_X)||(adrcode==OB_ROT_Y)||(adrcode==OB_ROT_Z)) { //get a rotation
+ float eul[3];
+ switch (adrcode) {
+ case OB_ROT_X:
+ matindex=0;
+ break;
+ case OB_ROT_Y:
+ matindex=1;
+ break;
+ case OB_ROT_Z:
+ matindex=2;
+ break;
+ }
+ Mat4ToEul(ob->obmat, eul);
+ insertfloatkey(id, ID_OB, actname, NULL, adrcode, eul[matindex]*(5.72958));
+ return 1;
+ } else if ((adrcode==OB_LOC_X)||(adrcode==OB_LOC_Y)||(adrcode==OB_LOC_Z)) {//get a translation
+ switch (adrcode) {
+ case OB_LOC_X:
+ matindex=0;
+ break;
+ case OB_LOC_Y:
+ matindex=1;
+ break;
+ case OB_LOC_Z:
+ matindex=2;
+ break;
+ }
+ insertfloatkey(id, ID_OB, actname, NULL, adrcode, ob->obmat[3][matindex]);
+ return 1;
+ }
+ }
+ } else if ( blocktype==ID_PO) { //working with a pose channel
+ bPoseChannel *pchan= get_pose_channel(ob->pose, actname);
+ if (pchan) {
+ if ((adrcode==AC_LOC_X)||(adrcode==AC_LOC_Y)||(adrcode==AC_LOC_Z)) {
+ switch (adrcode) {
+ case AC_LOC_X:
+ matindex=0;
+ break;
+ case AC_LOC_Y:
+ matindex=1;
+ break;
+ case AC_LOC_Z:
+ matindex=2;
+ break;
+ }
+ if (!(pchan->bone->parent)||((pchan->bone->parent)&&!(pchan->bone->flag&BONE_CONNECTED))) { /* don't use for non-connected child bones */
+ float delta_mat[4][4];
+ armature_mat_pose_to_delta(delta_mat, pchan->pose_mat, pchan->bone->arm_mat);
+ insertfloatkey(id, ID_PO, pchan->name, NULL, adrcode, delta_mat[3][matindex]);
+ return 1;
+ }
+ } else if ((adrcode==AC_QUAT_W)||(adrcode==AC_QUAT_X)||(adrcode==AC_QUAT_Y)||(adrcode==AC_QUAT_Z)) {
+ float tmat[4][4], trimat[3][3], localQuat[4];
+
+ switch (adrcode) {
+ case AC_QUAT_W:
+ matindex=0;
+ break;
+ case AC_QUAT_X:
+ matindex=1;
+ break;
+ case AC_QUAT_Y:
+ matindex=2;
+ break;
+ case AC_QUAT_Z:
+ matindex=3;
+ break;
+ }
+
+ /* it should be reasonable to assume that we are keyframing on the active object, although it is not
+ * strictly required for this particular space conversion, arg1 must not be null for this to work
+ */
+ Mat4CpyMat4(tmat, pchan->pose_mat);
+ constraint_mat_convertspace(OBACT, pchan, tmat, CONSTRAINT_SPACE_POSE, CONSTRAINT_SPACE_LOCAL);
+
+ Mat3CpyMat4(trimat, tmat);
+ Mat3ToQuat_is_ok(trimat, localQuat);
+ insertfloatkey(id, ID_PO, pchan->name, NULL, adrcode, localQuat[matindex]);
+
+ return 1;
+ }
+ }
+ }
+ }
+ /* failed to set a matrix key -- use traditional, but the non-recursing version */
+ insertkey_nonrecurs(id,blocktype,actname,constname,adrcode);
+ return 0;
+}
+
+static int match_adr_constraint(ID * id, int blocktype, char *actname, int adrcode)
+{ /* This function matches constraint blocks with adrcodes to see if the
+ visual keying method should be used. For example, an object looking to key
+ location and having a CopyLoc constraint would return true. */
+
+ Object *ob=NULL;
+ int foundmatch=0;
+ int searchtype=0;
+ bConstraint *conref=NULL, *con=NULL;
+
+ /*Retrieve constraint list*/
+ if( GS(id->name)==ID_OB )
+ ob= (Object *)id;
+ if (ob) {
+ if (blocktype==ID_PO) {
+ bPoseChannel *pchan= get_pose_channel(ob->pose, actname);
+ conref=pchan->constraints.first;
+ } else if (blocktype==ID_OB) {
+ conref=ob->constraints.first;
+ }
+
+ if (conref) {
+ /*Set search type: 1 is for translation contraints, 2 is for rotation*/
+ if ((adrcode==OB_LOC_X)||(adrcode==OB_LOC_Y)||(adrcode==OB_LOC_Z)||(adrcode==AC_LOC_X)||(adrcode==AC_LOC_Y)||(adrcode==AC_LOC_Z)) {
+ searchtype=1;
+ } else if ((adrcode==OB_ROT_X)||(adrcode==OB_ROT_Y)||(adrcode==OB_ROT_Z)||(adrcode==AC_QUAT_W)||(adrcode==AC_QUAT_X)||(adrcode==AC_QUAT_Y)||(adrcode==AC_QUAT_Z)) {
+ searchtype=2;
+ }
+
+ if (searchtype>0) {
+ for (con=conref; (con)&&(foundmatch==0); con=con->next) {
+ switch (con->type) {
+ /* match constraint types to which kinds of keying they would affect */
+ case CONSTRAINT_TYPE_CHILDOF:
+ foundmatch=1;
+ break;
+ case CONSTRAINT_TYPE_TRACKTO:
+ if (searchtype==2) foundmatch=1;
+ break;
+ case CONSTRAINT_TYPE_FOLLOWPATH:
+ foundmatch=1;
+ break;
+ case CONSTRAINT_TYPE_ROTLIMIT:
+ if (searchtype==2) foundmatch=1;
+ break;
+ case CONSTRAINT_TYPE_LOCLIMIT:
+ if (searchtype==1) foundmatch=1;
+ break;
+ case CONSTRAINT_TYPE_ROTLIKE:
+ if (searchtype==2) foundmatch=1;
+ break;
+ case CONSTRAINT_TYPE_LOCLIKE:
+ if (searchtype==1) foundmatch=1;
+ break;
+ case CONSTRAINT_TYPE_LOCKTRACK:
+ if (searchtype==2) foundmatch=1;
+ break;
+ case CONSTRAINT_TYPE_DISTANCELIMIT:
+ if (searchtype==1) foundmatch=1;
+ break;
+ case CONSTRAINT_TYPE_MINMAX:
+ if (searchtype==1) foundmatch=1;
+ break;
+ case CONSTRAINT_TYPE_TRANSFORM:
+ foundmatch=1;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return foundmatch;
+
+}
+
+void insertkey(ID *id, int blocktype, char *actname, char *constname, int adrcode, short fast)
+{
+ IpoCurve *icu;
+ Object *ob;
+ void *poin= NULL;
+ float curval, cfra;
+ int vartype;
+ int matset=0;
+
+ if ((G.flags&G_AUTOMATKEYS)&&(match_adr_constraint(id, blocktype, actname, adrcode))) {
+ matset=insertmatrixkey(id, blocktype, actname, constname, adrcode);
+ }
+ if (matset==0) {
+ icu= verify_ipocurve(id, blocktype, actname, constname, adrcode);
+
+ if(icu) {
+
+ poin= get_context_ipo_poin(id, blocktype, actname, icu, &vartype);
+
+ if(poin) {
+ curval= read_ipo_poin(poin, vartype);
+
+ cfra= frame_to_float(CFRA);
+
+ /* if action is mapped in NLA, it returns a correction */
+ if(actname && actname[0] && GS(id->name)==ID_OB)
+ cfra= get_action_frame((Object *)id, cfra);
+
+ if( GS(id->name)==ID_OB ) {
+ ob= (Object *)id;
+ if(ob->sf!=0.0 && (ob->ipoflag & OB_OFFS_OB) ) {
+ /* actually frametofloat calc again! */
+ cfra-= ob->sf*G.scene->r.framelen;
+ }
+ }
+
+ insert_vert_icu(icu, cfra, curval, fast);
+ }
+ }
+ }
+}
+
+
+
+/* This function is a 'smarter' version of the insert key code.
+ * It uses an auxilliary function to check whether a keyframe is really needed */
+void insertkey_smarter(ID *id, int blocktype, char *actname, char *constname, int adrcode)
+{
+ IpoCurve *icu;
+ Object *ob;
+ void *poin= NULL;
+ float curval, cfra;
+ int vartype;
+ int insert_mode;
+
+ icu= verify_ipocurve(id, blocktype, actname, constname, adrcode);
+
+ if(icu) {
+
+ poin= get_context_ipo_poin(id, blocktype, actname, icu, &vartype);
+
+ if(poin) {
+ curval= read_ipo_poin(poin, vartype);
+
+ cfra= frame_to_float(CFRA);
+
+ /* if action is mapped in NLA, it returns a correction */
+ if(actname && actname[0] && GS(id->name)==ID_OB)
+ cfra= get_action_frame((Object *)id, cfra);
+
+ if( GS(id->name)==ID_OB ) {
+ ob= (Object *)id;
+ if(ob->sf!=0.0 && (ob->ipoflag & OB_OFFS_OB) ) {
+ /* actually frametofloat calc again! */
+ cfra-= ob->sf*G.scene->r.framelen;
+ }
+ }
+
+ /* check whether this curve really needs a new keyframe */
+ insert_mode= new_key_needed(icu, cfra, curval);
+
+ /* insert new keyframe at current frame */
+ if (insert_mode)
+ insert_vert_icu(icu, cfra, curval, 0);
+
+ /* delete keyframe immediately before/after newly added */
+ switch (insert_mode) {
+ case KEYNEEDED_DELPREV:
+ delete_icu_key(icu, icu->totvert-2);
+ break;
+ case KEYNEEDED_DELNEXT:
+ delete_icu_key(icu, 1);
+ break;
+ }
+ }
+ }
+}
+
+/* For inserting keys based on an arbitrary float value */
+void insertfloatkey(ID *id, int blocktype, char *actname, char *constname, int adrcode, float floatkey)
+{
+ IpoCurve *icu;
+ Object *ob;
+ void *poin= NULL;
+ float cfra;
+ int vartype;
+
+ icu= verify_ipocurve(id, blocktype, actname, constname, adrcode);
+
+ if(icu) {
+
+ poin= get_context_ipo_poin(id, blocktype, actname, icu, &vartype);
+
+ if(poin) {
+
+ cfra= frame_to_float(CFRA);
+
+ /* if action is mapped in NLA, it returns a correction */
+ if(actname && actname[0] && GS(id->name)==ID_OB)
+ cfra= get_action_frame((Object *)id, cfra);
+
+ if( GS(id->name)==ID_OB ) {
+ ob= (Object *)id;
+ if(ob->sf!=0.0 && (ob->ipoflag & OB_OFFS_OB) ) {
+ /* actually frametofloat calc again! */
+ cfra-= ob->sf*G.scene->r.framelen;
+ }
+ }
+
+ /* insert new keyframe at current frame */
+ insert_vert_icu(icu, cfra, floatkey, 0);
+ }
+ }
+}
+
+void insertkey_editipo(void)
+{
+ EditIpo *ei;
+ IpoKey *ik;
+ ID *id;
+ float *fp, cfra, *insertvals;
+ int a, nr, ok, tot;
+ short event;
+
+ ei= get_active_editipo();
+ if(ei && ei->icu && ei->icu->driver)
+ event= pupmenu("Insert Curve %t|Default one-to-one mapping %x3");
+ else if(G.sipo->showkey)
+ event= pupmenu("Insert Key Vertices %t|Current Frame %x1|Selected Keys %x2");
+ else
+ event= pupmenu("Insert Key Vertices %t|Current Frame %x1");
+
+ if(event<1) return;
+
+ if(event==3) {
+ IpoDriver *driver= ei->icu->driver;
+
+ if(ei->icu->bezt) MEM_freeN(ei->icu->bezt);
+ ei->icu->totvert= 0;
+ ei->icu->bezt= NULL;
+
+ insert_vert_icu(ei->icu, 0.0f, 0.0f, 0);
+
+ if(ELEM3(driver->adrcode, OB_ROT_X, OB_ROT_Y, OB_ROT_Z)) {
+ if(ei->disptype==IPO_DISPDEGR)
+ insert_vert_icu(ei->icu, 18.0f, 18.0f, 0);
+ else
+ insert_vert_icu(ei->icu, 18.0f, 1.0f, 0);
+ }
+ else
+ insert_vert_icu(ei->icu, 1.0f, 1.0f, 0);
+
+ ei->flag |= IPO_SELECT|IPO_VISIBLE;
+ ei->icu->flag= ei->flag;
+ ei->icu->extrap= IPO_DIR;
+
+ do_ipo_buttons(B_IPOHOME);
+ }
+ else {
+ ei= G.sipo->editipo;
+ for(nr=0; nr<G.sipo->totipo; nr++, ei++) {
+ if (ISPOIN(ei, flag & IPO_VISIBLE, icu)) {
+
+ ok= 0;
+ if(G.sipo->showkey) ok= 1;
+ else if(ei->flag & IPO_SELECT) ok= 1;
+
+ if(ok) {
+ /* count amount */
+ if(event==1) tot= 1;
+ else {
+ ik= G.sipo->ipokey.first;
+ tot= 0;
+ while(ik) {
+ if(ik->flag & 1) tot++;
+ ik= ik->next;
+ }
+ }
+ if(tot) {
+
+ /* correction for ob timeoffs */
+ cfra= frame_to_float(CFRA);
+ id= G.sipo->from;
+ if(id && GS(id->name)==ID_OB ) {
+ Object *ob= (Object *)id;
+ if(ob->sf!=0.0 && (ob->ipoflag & OB_OFFS_OB) ) {
+ cfra-= ob->sf*G.scene->r.framelen;
+ }
+ }
+ else if(id && GS(id->name)==ID_SEQ) {
+ Sequence *last_seq = get_last_seq(); /* editsequence.c */
+
+ if(last_seq && (last_seq->flag & SEQ_IPO_FRAME_LOCKED) == 0) {
+ cfra= (float)(100.0*(cfra-last_seq->startdisp)/((float)(last_seq->enddisp-last_seq->startdisp)));
+ }
+ }
+
+ /* convert cfra to ipo-time */
+ if (NLA_IPO_SCALED) {
+ cfra= get_action_frame(OBACT, cfra);
+ }
+
+ insertvals= MEM_mallocN(sizeof(float)*2*tot, "insertkey_editipo");
+ /* make sure icu->curval is correct */
+ calc_ipo(G.sipo->ipo, cfra);
+
+ if(event==1) {
+ insertvals[0]= cfra;
+
+ insertvals[1]= ei->icu->curval;
+ }
+ else {
+ fp= insertvals;
+ ik= G.sipo->ipokey.first;
+ while(ik) {
+ if(ik->flag & 1) {
+ calc_ipo(G.sipo->ipo, ik->val);
+
+ fp[0]= ik->val;
+ fp[1]= ei->icu->curval;
+ fp+= 2;
+ }
+ ik= ik->next;
+ }
+ }
+ fp= insertvals;
+ for(a=0; a<tot; a++, fp+=2) {
+ insert_vert_icu(ei->icu, fp[0], fp[1], 0);
+ }
+
+ MEM_freeN(insertvals);
+ calc_ipo(G.sipo->ipo, (float)CFRA);
+ }
+ }
+ }
+ }
+ }
+ BIF_undo_push("Insert Key Ipo");
+ allqueue (REDRAWACTION, 0);
+ allqueue(REDRAWNLA, 0);
+ allqueue(REDRAWIPO, 0);
+ allspace(REMAKEIPO, 0);
+}
+
+
+void common_insertkey(void)
+{
+ Base *base;
+ Object *ob;
+ Material *ma;
+ ID *id;
+ IpoCurve *icu;
+ World *wo;
+ Lamp *la;
+ Tex *te;
+ int tlay, map, event;
+ char menustr[256];
+
+ if(curarea->spacetype==SPACE_IPO) {
+ insertkey_editipo();
+ }
+ else if(curarea->spacetype==SPACE_ACTION) {
+ insertkey_action();
+ }
+ else if(curarea->spacetype==SPACE_BUTS) {
+ if(G.buts->mainb==CONTEXT_SHADING) {
+ int tab= G.buts->tab[CONTEXT_SHADING];
+
+ if(tab==TAB_SHADING_MAT) {
+ ma = G.buts->lockpoin;
+ ma = editnode_get_active_material(ma);
+ id = (ID *)ma;
+
+ if(id) {
+ event= pupmenu("Insert Key %t|RGB%x0|Alpha%x1|Halo Size%x2|Mode %x3|All Color%x10|All Mirror%x14|Ofs%x12|Size%x13|All Mapping%x11");
+ if(event== -1) return;
+
+ map= texchannel_to_adrcode(ma->texact);
+
+ if(event==0 || event==10) {
+ insertkey(id, ID_MA, NULL, NULL, MA_COL_R, 0);
+ insertkey(id, ID_MA, NULL, NULL, MA_COL_G, 0);
+ insertkey(id, ID_MA, NULL, NULL, MA_COL_B, 0);
+ }
+ if(event==1 || event==10) {
+ insertkey(id, ID_MA, NULL, NULL, MA_ALPHA, 0);
+ }
+ if(event==2 || event==10) {
+ insertkey(id, ID_MA, NULL, NULL, MA_HASIZE, 0);
+ }
+ if(event==3 || event==10) {
+ insertkey(id, ID_MA, NULL, NULL, MA_MODE, 0);
+ }
+ if(event==10) {
+ insertkey(id, ID_MA, NULL, NULL, MA_SPEC_R, 0);
+ insertkey(id, ID_MA, NULL, NULL, MA_SPEC_G, 0);
+ insertkey(id, ID_MA, NULL, NULL, MA_SPEC_B, 0);
+ insertkey(id, ID_MA, NULL, NULL, MA_REF, 0);
+ insertkey(id, ID_MA, NULL, NULL, MA_EMIT, 0);
+ insertkey(id, ID_MA, NULL, NULL, MA_AMB, 0);
+ insertkey(id, ID_MA, NULL, NULL, MA_SPEC, 0);
+ insertkey(id, ID_MA, NULL, NULL, MA_HARD, 0);
+ insertkey(id, ID_MA, NULL, NULL, MA_MODE, 0);
+ insertkey(id, ID_MA, NULL, NULL, MA_TRANSLU, 0);
+ insertkey(id, ID_MA, NULL, NULL, MA_ADD, 0);
+ }
+ if(event==14) {
+ insertkey(id, ID_MA, NULL, NULL, MA_RAYM, 0);
+ insertkey(id, ID_MA, NULL, NULL, MA_FRESMIR, 0);
+ insertkey(id, ID_MA, NULL, NULL, MA_FRESMIRI, 0);
+ insertkey(id, ID_MA, NULL, NULL, MA_FRESTRA, 0);
+ insertkey(id, ID_MA, NULL, NULL, MA_FRESTRAI, 0);
+ }
+ if(event==12 || event==11) {
+ insertkey(id, ID_MA, NULL, NULL, map+MAP_OFS_X, 0);
+ insertkey(id, ID_MA, NULL, NULL, map+MAP_OFS_Y, 0);
+ insertkey(id, ID_MA, NULL, NULL, map+MAP_OFS_Z, 0);
+ }
+ if(event==13 || event==11) {
+ insertkey(id, ID_MA, NULL, NULL, map+MAP_SIZE_X, 0);
+ insertkey(id, ID_MA, NULL, NULL, map+MAP_SIZE_Y, 0);
+ insertkey(id, ID_MA, NULL, NULL, map+MAP_SIZE_Z, 0);
+ }
+ if(event==11) {
+ insertkey(id, ID_MA, NULL, NULL, map+MAP_R, 0);
+ insertkey(id, ID_MA, NULL, NULL, map+MAP_G, 0);
+ insertkey(id, ID_MA, NULL, NULL, map+MAP_B, 0);
+ insertkey(id, ID_MA, NULL, NULL, map+MAP_DVAR, 0);
+ insertkey(id, ID_MA, NULL, NULL, map+MAP_COLF, 0);
+ insertkey(id, ID_MA, NULL, NULL, map+MAP_NORF, 0);
+ insertkey(id, ID_MA, NULL, NULL, map+MAP_VARF, 0);
+ insertkey(id, ID_MA, NULL, NULL, map+MAP_DISP, 0);
+ }
+ }
+ }
+ else if(tab==TAB_SHADING_WORLD) {
+ id= G.buts->lockpoin;
+ wo= G.buts->lockpoin;
+ if(id) {
+ event= pupmenu("Insert Key %t|Zenith RGB%x0|Horizon RGB%x1|Mist%x2|Stars %x3|Offset%x12|Size%x13");
+ if(event== -1) return;
+
+ map= texchannel_to_adrcode(wo->texact);
+
+ if(event==0) {
+ insertkey(id, ID_WO, NULL, NULL, WO_ZEN_R, 0);
+ insertkey(id, ID_WO, NULL, NULL, WO_ZEN_G, 0);
+ insertkey(id, ID_WO, NULL, NULL, WO_ZEN_B, 0);
+ }
+ if(event==1) {
+ insertkey(id, ID_WO, NULL, NULL, WO_HOR_R, 0);
+ insertkey(id, ID_WO, NULL, NULL, WO_HOR_G, 0);
+ insertkey(id, ID_WO, NULL, NULL, WO_HOR_B, 0);
+ }
+ if(event==2) {
+ insertkey(id, ID_WO, NULL, NULL, WO_MISI, 0);
+ insertkey(id, ID_WO, NULL, NULL, WO_MISTDI, 0);
+ insertkey(id, ID_WO, NULL, NULL, WO_MISTSTA, 0);
+ insertkey(id, ID_WO, NULL, NULL, WO_MISTHI, 0);
+ }
+ if(event==3) {
+ insertkey(id, ID_WO, NULL, NULL, WO_STAR_R, 0);
+ insertkey(id, ID_WO, NULL, NULL, WO_STAR_G, 0);
+ insertkey(id, ID_WO, NULL, NULL, WO_STAR_B, 0);
+ insertkey(id, ID_WO, NULL, NULL, WO_STARDIST, 0);
+ insertkey(id, ID_WO, NULL, NULL, WO_STARSIZE, 0);
+ }
+ if(event==12) {
+ insertkey(id, ID_WO, NULL, NULL, map+MAP_OFS_X, 0);
+ insertkey(id, ID_WO, NULL, NULL, map+MAP_OFS_Y, 0);
+ insertkey(id, ID_WO, NULL, NULL, map+MAP_OFS_Z, 0);
+ }
+ if(event==13) {
+ insertkey(id, ID_WO, NULL, NULL, map+MAP_SIZE_X, 0);
+ insertkey(id, ID_WO, NULL, NULL, map+MAP_SIZE_Y, 0);
+ insertkey(id, ID_WO, NULL, NULL, map+MAP_SIZE_Z, 0);
+ }
+ }
+ }
+ else if(tab==TAB_SHADING_LAMP) {
+ id= G.buts->lockpoin;
+ la= G.buts->lockpoin;
+ if(id) {
+ event= pupmenu("Insert Key %t|RGB%x0|Energy%x1|Spot Size%x2|Offset%x12|Size%x13");
+ if(event== -1) return;
+
+ map= texchannel_to_adrcode(la->texact);
+
+ if(event==0) {
+ insertkey(id, ID_LA, NULL, NULL, LA_COL_R, 0);
+ insertkey(id, ID_LA, NULL, NULL, LA_COL_G, 0);
+ insertkey(id, ID_LA, NULL, NULL, LA_COL_B, 0);
+ }
+ if(event==1) {
+ insertkey(id, ID_LA, NULL, NULL, LA_ENERGY, 0);
+ }
+ if(event==2) {
+ insertkey(id, ID_LA, NULL, NULL, LA_SPOTSI, 0);
+ }
+ if(event==12) {
+ insertkey(id, ID_LA, NULL, NULL, map+MAP_OFS_X, 0);
+ insertkey(id, ID_LA, NULL, NULL, map+MAP_OFS_Y, 0);
+ insertkey(id, ID_LA, NULL, NULL, map+MAP_OFS_Z, 0);
+ }
+ if(event==13) {
+ insertkey(id, ID_LA, NULL, NULL, map+MAP_SIZE_X, 0);
+ insertkey(id, ID_LA, NULL, NULL, map+MAP_SIZE_Y, 0);
+ insertkey(id, ID_LA, NULL, NULL, map+MAP_SIZE_Z, 0);
+ }
+
+ }
+ }
+ else if(tab==TAB_SHADING_TEX) {
+ id= G.buts->lockpoin;
+ te= G.buts->lockpoin;
+ if(id) {
+ event= pupmenu("Insert Key %t|Clouds%x0|Marble%x1|Stucci%x2|Wood%x3|Magic%x4|Blend%x5|Musgrave%x6|Voronoi%x7|DistortedNoise%x8|ColorFilter%x9");
+ if(event== -1) return;
+
+ if(event==0) {
+ insertkey(id, ID_TE, NULL, NULL, TE_NSIZE, 0);
+ insertkey(id, ID_TE, NULL, NULL, TE_NDEPTH, 0);
+ insertkey(id, ID_TE, NULL, NULL, TE_NTYPE, 0);
+ insertkey(id, ID_TE, NULL, NULL, TE_MG_TYP, 0);
+ insertkey(id, ID_TE, NULL, NULL, TE_N_BAS1, 0);
+ }
+ if(event==1) {
+ insertkey(id, ID_TE, NULL, NULL, TE_NSIZE, 0);
+ insertkey(id, ID_TE, NULL, NULL, TE_NDEPTH, 0);
+ insertkey(id, ID_TE, NULL, NULL, TE_NTYPE, 0);
+ insertkey(id, ID_TE, NULL, NULL, TE_TURB, 0);
+ insertkey(id, ID_TE, NULL, NULL, TE_MG_TYP, 0);
+ insertkey(id, ID_TE, NULL, NULL, TE_N_BAS1, 0);
+ insertkey(id, ID_TE, NULL, NULL, TE_N_BAS2, 0);
+ }
+ if(event==2) {
+ insertkey(id, ID_TE, NULL, NULL, TE_NSIZE, 0);
+ insertkey(id, ID_TE, NULL, NULL, TE_NTYPE, 0);
+ insertkey(id, ID_TE, NULL, NULL, TE_TURB, 0);
+ insertkey(id, ID_TE, NULL, NULL, TE_MG_TYP, 0);
+ insertkey(id, ID_TE, NULL, NULL, TE_N_BAS1, 0);
+ }
+ if(event==3) {
+ insertkey(id, ID_TE, NULL, NULL, TE_NSIZE, 0);
+ insertkey(id, ID_TE, NULL, NULL, TE_NTYPE, 0);
+ insertkey(id, ID_TE, NULL, NULL, TE_TURB, 0);
+ insertkey(id, ID_TE, NULL, NULL, TE_MG_TYP, 0);
+ insertkey(id, ID_TE, NULL, NULL, TE_N_BAS1, 0);
+ insertkey(id, ID_TE, NULL, NULL, TE_N_BAS2, 0);
+ }
+ if(event==4) {
+ insertkey(id, ID_TE, NULL, NULL, TE_NDEPTH, 0);
+ insertkey(id, ID_TE, NULL, NULL, TE_TURB, 0);
+ }
+ if(event==5) {
+ insertkey(id, ID_TE, NULL, NULL, TE_MG_TYP, 0);
+ }
+ if(event==6) {
+ insertkey(id, ID_TE, NULL, NULL, TE_MG_TYP, 0);
+ insertkey(id, ID_TE, NULL, NULL, TE_MGH, 0);
+ insertkey(id, ID_TE, NULL, NULL, TE_MG_LAC, 0);
+ insertkey(id, ID_TE, NULL, NULL, TE_MG_OCT, 0);
+ insertkey(id, ID_TE, NULL, NULL, TE_MG_OFF, 0);
+ insertkey(id, ID_TE, NULL, NULL, TE_MG_GAIN, 0);
+ }
+ if(event==7) {
+ insertkey(id, ID_TE, NULL, NULL, TE_VNW1, 0);
+ insertkey(id, ID_TE, NULL, NULL, TE_VNW2, 0);
+ insertkey(id, ID_TE, NULL, NULL, TE_VNW3, 0);
+ insertkey(id, ID_TE, NULL, NULL, TE_VNW4, 0);
+ insertkey(id, ID_TE, NULL, NULL, TE_VNMEXP, 0);
+ insertkey(id, ID_TE, NULL, NULL, TE_VN_DISTM, 0);
+ insertkey(id, ID_TE, NULL, NULL, TE_VN_COLT, 0);
+ insertkey(id, ID_TE, NULL, NULL, TE_ISCA, 0);
+ insertkey(id, ID_TE, NULL, NULL, TE_NSIZE, 0);
+ }
+ if(event==8) {
+ insertkey(id, ID_TE, NULL, NULL, TE_MG_OCT, 0);
+ insertkey(id, ID_TE, NULL, NULL, TE_MG_OFF, 0);
+ insertkey(id, ID_TE, NULL, NULL, TE_MG_GAIN, 0);
+ insertkey(id, ID_TE, NULL, NULL, TE_DISTA, 0);
+ }
+ if(event==9) {
+ insertkey(id, ID_TE, NULL, NULL, TE_COL_R, 0);
+ insertkey(id, ID_TE, NULL, NULL, TE_COL_G, 0);
+ insertkey(id, ID_TE, NULL, NULL, TE_COL_B, 0);
+ insertkey(id, ID_TE, NULL, NULL, TE_BRIGHT, 0);
+ insertkey(id, ID_TE, NULL, NULL, TE_CONTRA, 0);
+ }
+ }
+ }
+ }
+ else if(G.buts->mainb==CONTEXT_OBJECT) {
+ ob= OBACT;
+ if(ob) {
+ id= (ID *) (ob);
+ if(id) {
+ if(ob->type==OB_MESH)
+ event= pupmenu("Insert Key %t|Surface Damping%x0|Random Damping%x1|Permeability%x2|Force Strength%x3|Force Falloff%x4");
+ else
+ event= pupmenu("Insert Key %t|Force Strength%x3|Force Falloff%x4");
+ if(event == -1) return;
+
+ if(event==0) {
+ insertkey(id, ID_OB, NULL, NULL, OB_PD_SDAMP, 0);
+ }
+ if(event==1) {
+ insertkey(id, ID_OB, NULL, NULL, OB_PD_RDAMP, 0);
+ }
+ if(event==2) {
+ insertkey(id, ID_OB, NULL, NULL, OB_PD_PERM, 0);
+ }
+ if(event==3) {
+ insertkey(id, ID_OB, NULL, NULL, OB_PD_FSTR, 0);
+ }
+ if(event==4) {
+ insertkey(id, ID_OB, NULL, NULL, OB_PD_FFALL, 0);
+ }
+
+ }
+ }
+ }
+ else if(G.buts->mainb==CONTEXT_EDITING) {
+ ob= OBACT;
+ if(ob && ob->type==OB_CAMERA) {
+ id= G.buts->lockpoin;
+ if(id) {
+ /* yafray: insert key extended with aperture and focal distance */
+ /* qdn: FocalDistance now enabled for Blender as wel, for use with defocus node */
+ if (G.scene->r.renderer==R_INTERN)
+ event= pupmenu("Insert Key %t|Lens%x0|Clipping%x1|FocalDistance%x3|Viewplane Shift%x4");
+ else
+ event= pupmenu("Insert Key %t|Lens%x0|Clipping%x1|Aperture%x2|FocalDistance%x3");
+ if(event== -1) return;
+
+ if(event==0) {
+ insertkey(id, ID_CA, NULL, NULL, CAM_LENS, 0);
+ }
+ else if(event==1) {
+ insertkey(id, ID_CA, NULL, NULL, CAM_STA, 0);
+ insertkey(id, ID_CA, NULL, NULL, CAM_END, 0);
+ }
+ else if(event==2) {
+ insertkey(id, ID_CA, NULL, NULL, CAM_YF_APERT, 0);
+ }
+ else if(event==3) {
+ insertkey(id, ID_CA, NULL, NULL, CAM_YF_FDIST, 0);
+ }
+ else if(event==4) {
+ insertkey(id, ID_CA, NULL, NULL, CAM_SHIFT_X, 0);
+ insertkey(id, ID_CA, NULL, NULL, CAM_SHIFT_Y, 0);
+ }
+ }
+ }
+ }
+ else if(FALSE /* && G.buts->mainb==BUTS_SOUND */) {
+ if(G.ssound) {
+ id= G.buts->lockpoin;
+ if(id) {
+ event= pupmenu("Insert Key %t|Volume%x0|Pitch%x1|Panning%x2|Attennuation%x3");
+ if(event== -1) return;
+
+ if(event==0) {
+ insertkey(id, ID_SO, NULL, NULL, SND_VOLUME, 0);
+ }
+ if(event==1) {
+ insertkey(id, ID_SO, NULL, NULL, SND_PITCH, 0);
+ }
+ if(event==2) {
+ insertkey(id, ID_SO, NULL, NULL, SND_PANNING, 0);
+ }
+ if(event==3) {
+ insertkey(id, ID_SO, NULL, NULL, SND_ATTEN, 0);
+ }
+ }
+ }
+ }
+
+ BIF_undo_push("Insert Key Buttons");
+
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWNLA, 0);
+ allqueue(REDRAWIPO, 0);
+ allspace(REMAKEIPO, 0);
+
+ }
+ else if(curarea->spacetype==SPACE_VIEW3D) {
+ ob= OBACT;
+
+ if (ob && (ob->flag & OB_POSEMODE)) {
+ bPoseChannel *pchan;
+
+ set_pose_keys(ob); /* sets pchan->flag to POSE_KEY if bone selected, and clears if not */
+ for (pchan=ob->pose->chanbase.first; pchan; pchan=pchan->next)
+ if (pchan->flag & POSE_KEY)
+ break;
+ if(pchan==NULL) return;
+ strcpy(menustr, "Insert Key%t|Loc%x0|Rot%x1|Scale%x2|LocRot%x3|LocRotScale%x4|Avail%x9|Needed%x15|VisualLoc%x11|VisualRot%x12|VisualLocRot%x13");
+ }
+ else {
+ base= FIRSTBASE;
+ while(base) {
+ if (TESTBASELIB(base)) break;
+ base= base->next;
+ }
+ if(base==NULL) return;
+ strcpy(menustr, "Insert Key%t|Loc%x0|Rot%x1|Scale%x2|LocRot%x3|LocRotScale%x4|Layer%x5|Avail%x9|Needed%x15|VisualLoc%x11|VisualRot%x12|VisualLocRot%x13");
+ }
+
+ if(ob) {
+ if(ob->type==OB_MESH) strcat(menustr, "| %x6|Mesh%x7");
+ else if(ob->type==OB_LATTICE) strcat(menustr, "| %x6|Lattice%x7");
+ else if(ob->type==OB_CURVE) strcat(menustr, "| %x6|Curve%x7");
+ else if(ob->type==OB_SURF) strcat(menustr, "| %x6|Surface%x7");
+ }
+
+ event= pupmenu(menustr);
+ if(event== -1) return;
+
+ if(event==7) { // ob != NULL
+ insert_shapekey(ob);
+ return;
+ }
+
+ if (ob && (ob->flag & OB_POSEMODE)){
+ bPoseChannel *pchan;
+
+ if (ob->action && ob->action->id.lib) {
+ error ("Can't key libactions");
+ return;
+ }
+
+ id= &ob->id;
+ for (pchan=ob->pose->chanbase.first; pchan; pchan=pchan->next) {
+ if (pchan->flag & POSE_KEY) {
+ /* insert relevant keyframes */
+ if(event==0 || event==3 ||event==4) {
+ insertkey(id, ID_PO, pchan->name, NULL, AC_LOC_X, 0);
+ insertkey(id, ID_PO, pchan->name, NULL, AC_LOC_Y, 0);
+ insertkey(id, ID_PO, pchan->name, NULL, AC_LOC_Z, 0);
+ }
+ if(event==1 || event==3 || event==4) {
+ insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_X, 0);
+ insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_Y, 0);
+ insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_Z, 0);
+ insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_W, 0);
+ }
+ if(event==2 || event==4) {
+ insertkey(id, ID_PO, pchan->name, NULL, AC_SIZE_X, 0);
+ insertkey(id, ID_PO, pchan->name, NULL, AC_SIZE_Y, 0);
+ insertkey(id, ID_PO, pchan->name, NULL, AC_SIZE_Z, 0);
+ }
+ if (event==9 && ob->action) {
+ bActionChannel *achan;
+
+ for (achan = ob->action->chanbase.first; achan; achan=achan->next){
+ if (achan->ipo && !strcmp (achan->name, pchan->name)){
+ for (icu = achan->ipo->curve.first; icu; icu=icu->next){
+ insertkey(id, ID_PO, achan->name, NULL, icu->adrcode, 0);
+ }
+ break;
+ }
+ }
+ }
+ if(event==11 || event==13) {
+ int matok=0;
+ /* check one to make sure we're not trying to set visual loc keys on
+ bones inside of a chain, which only leads to tears. */
+ matok= insertmatrixkey(id, ID_PO, pchan->name, NULL, AC_LOC_X);
+ insertmatrixkey(id, ID_PO, pchan->name, NULL, AC_LOC_Y);
+ insertmatrixkey(id, ID_PO, pchan->name, NULL, AC_LOC_Z);
+
+ if (matok == 0) {
+ insertkey(id, ID_PO, pchan->name, NULL, AC_LOC_X, 0);
+ insertkey(id, ID_PO, pchan->name, NULL, AC_LOC_Y, 0);
+ insertkey(id, ID_PO, pchan->name, NULL, AC_LOC_Z, 0);
+ }
+ }
+ if(event==12 || event==13) {
+ int matok=0;
+ /* check one to make sure we're not trying to set visual rot keys on
+ bones inside of a chain, which only leads to tears. */
+ matok= insertmatrixkey(id, ID_PO, pchan->name, NULL, AC_QUAT_W);
+ insertmatrixkey(id, ID_PO, pchan->name, NULL, AC_QUAT_X);
+ insertmatrixkey(id, ID_PO, pchan->name, NULL, AC_QUAT_Y);
+ insertmatrixkey(id, ID_PO, pchan->name, NULL, AC_QUAT_Z);
+
+ if (matok == 0) {
+ insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_W, 0);
+ insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_X, 0);
+ insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_Y, 0);
+ insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_Z, 0);
+ }
+ }
+ if (event==15 && ob->action) {
+ bActionChannel *achan;
+
+ for (achan = ob->action->chanbase.first; achan; achan=achan->next){
+ if (achan->ipo && !strcmp (achan->name, pchan->name)){
+ for (icu = achan->ipo->curve.first; icu; icu=icu->next){
+ insertkey_smarter(id, ID_PO, achan->name, NULL, icu->adrcode);
+ }
+ break;
+ }
+ }
+ }
+
+ /* clear unkeyed flag (it doesn't matter if it's set or not) */
+ if (pchan->bone)
+ pchan->bone->flag &= ~BONE_UNKEYED;
+ }
+ }
+ if(ob->action)
+ remake_action_ipos(ob->action);
+
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWNLA, 0);
+ }
+ else {
+ base= FIRSTBASE;
+ while(base) {
+ if (TESTBASELIB(base)) {
+ char *actname= NULL;
+
+ id= (ID *)(base->object);
+
+ if(base->object->ipoflag & OB_ACTION_OB)
+ actname= "Object";
+
+ /* all curves in ipo deselect */
+ if(base->object->ipo || base->object->action) {
+ if (base->object->ipo) {
+ icu= base->object->ipo->curve.first;
+ }
+ else {
+ bActionChannel *achan;
+ achan= get_action_channel(base->object->action, actname);
+
+ if (achan && achan->ipo)
+ icu= achan->ipo->curve.first;
+ else
+ icu= NULL;
+ }
+
+ while(icu) {
+ icu->flag &= ~IPO_SELECT;
+
+ switch (event) {
+ case 9:
+ insertkey(id, ID_OB, actname, NULL, icu->adrcode, 0);
+ break;
+ case 15:
+ insertkey_smarter(id, ID_OB, actname, NULL, icu->adrcode);
+ break;
+ }
+ icu= icu->next;
+ }
+ }
+
+ if(event==0 || event==3 ||event==4) {
+ insertkey(id, ID_OB, actname, NULL, OB_LOC_X, 0);
+ insertkey(id, ID_OB, actname, NULL, OB_LOC_Y, 0);
+ insertkey(id, ID_OB, actname, NULL, OB_LOC_Z, 0);
+ }
+ if(event==1 || event==3 ||event==4) {
+ insertkey(id, ID_OB, actname, NULL, OB_ROT_X, 0);
+ insertkey(id, ID_OB, actname, NULL, OB_ROT_Y, 0);
+ insertkey(id, ID_OB, actname, NULL, OB_ROT_Z, 0);
+ }
+ if(event==2 || event==4) {
+ insertkey(id, ID_OB, actname, NULL, OB_SIZE_X, 0);
+ insertkey(id, ID_OB, actname, NULL, OB_SIZE_Y, 0);
+ insertkey(id, ID_OB, actname, NULL, OB_SIZE_Z, 0);
+ }
+ if(event==5) {
+ /* remove localview */
+ tlay= base->object->lay;
+ base->object->lay &= 0xFFFFFF;
+ insertkey(id, ID_OB, actname, NULL, OB_LAY, 0);
+ base->object->lay= tlay;
+ }
+ if(event==11 || event==13) {
+ insertmatrixkey(id, ID_OB, actname, NULL, OB_LOC_X);
+ insertmatrixkey(id, ID_OB, actname, NULL, OB_LOC_Y);
+ insertmatrixkey(id, ID_OB, actname, NULL, OB_LOC_Z);
+ }
+ if(event==12 || event==13) {
+ insertmatrixkey(id, ID_OB, actname, NULL, OB_ROT_X);
+ insertmatrixkey(id, ID_OB, actname, NULL, OB_ROT_Y);
+ insertmatrixkey(id, ID_OB, actname, NULL, OB_ROT_Z);
+ }
+ base->object->recalc |= OB_RECALC_OB;
+ }
+ base= base->next;
+ }
+ }
+
+ if(event==0) BIF_undo_push("Insert Loc Key");
+ else if(event==1) BIF_undo_push("Insert Rot Key");
+ else if(event==2) BIF_undo_push("Insert Scale Key");
+ else if(event==3) BIF_undo_push("Insert LocRot Key");
+ else if(event==4) BIF_undo_push("Insert LocRotScale Key");
+ else if(event==5) BIF_undo_push("Insert Layer Key");
+ else if(event==7) BIF_undo_push("Insert Vertex Key");
+ else if(event==9) BIF_undo_push("Insert Avail Key");
+ else if(event==11) BIF_undo_push("Insert VisualLoc Key");
+ else if(event==12) BIF_undo_push("Insert VisualRot Key");
+ else if(event==13) BIF_undo_push("Insert VisualLocRot Key");
+ else if(event==15) BIF_undo_push("Insert Needed Key");
+
+ DAG_scene_flush_update(G.scene, screen_view3d_layers());
+
+ allspace(REMAKEIPO, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWNLA, 0);
+ }
+
+}
+
+/* ****************************************************************************** */
+
+void add_duplicate_editipo(void)
+{
+ Object *ob;
+ EditIpo *ei;
+ IpoCurve *icu;
+ BezTriple *bezt, *beztn, *newb;
+ int tot, a, b;
+
+ get_status_editipo();
+ if(totipo_vertsel==0) return;
+
+ ei= G.sipo->editipo;
+ for(a=0; a<G.sipo->totipo; a++, ei++) {
+ if (ISPOIN3(ei, flag & IPO_VISIBLE, icu, icu->bezt)) {
+ if(G.sipo->showkey || (ei->flag & IPO_EDIT)) {
+ icu= ei->icu;
+
+ /* how many points */
+ tot= 0;
+ b= icu->totvert;
+ bezt= icu->bezt;
+ while(b--) {
+ if(bezt->f2 & 1) tot++;
+ bezt++;
+ }
+
+ if(tot) {
+ icu->totvert+= tot;
+ newb= beztn= MEM_mallocN(icu->totvert*sizeof(BezTriple), "bezt");
+ bezt= icu->bezt;
+ b= icu->totvert-tot;
+ while(b--) {
+ *beztn= *bezt;
+ if(bezt->f2 & 1) {
+ beztn->f1= beztn->f2= beztn->f3= 0;
+ beztn++;
+ *beztn= *bezt;
+ }
+ beztn++;
+ bezt++;
+ }
+ MEM_freeN(icu->bezt);
+ icu->bezt= newb;
+
+ calchandles_ipocurve(icu);
+ }
+ }
+ }
+ }
+
+ if(G.sipo->showkey) {
+ make_ipokey();
+ if(G.sipo->blocktype==ID_OB) {
+ ob= OBACT;
+ if(ob && (ob->ipoflag & OB_DRAWKEY)) allqueue(REDRAWVIEW3D, 0);
+ }
+ }
+ BIF_undo_push("Duplicate Ipo");
+ transform_ipo('g');
+}
+
+void remove_doubles_ipo(void)
+{
+ EditIpo *ei;
+ IpoKey *ik, *ikn;
+ BezTriple *bezt, *newb, *new1;
+ float val;
+ int mode, a, b;
+
+ ei= G.sipo->editipo;
+ for(a=0; a<G.sipo->totipo; a++, ei++) {
+ if (ISPOIN3(ei, flag & IPO_VISIBLE, icu, icu->bezt)) {
+
+ /* OR the curve is selected OR in editmode OR in keymode */
+ mode= 0;
+ if(G.sipo->showkey || (ei->flag & IPO_EDIT)) mode= 1;
+ else if(ei->flag & IPO_SELECT) mode= 2;
+
+ if(mode) {
+ bezt= ei->icu->bezt;
+ newb= new1= MEM_mallocN(ei->icu->totvert*sizeof(BezTriple), "newbezt");
+ *newb= *bezt;
+ b= ei->icu->totvert-1;
+ bezt++;
+ while(b--) {
+
+ /* can we remove? */
+ if(mode==2 || (bezt->f2 & 1)) {
+
+ /* are the points different? */
+ if( fabs( bezt->vec[1][0]-newb->vec[1][0] ) > 0.9 ) {
+ newb++;
+ *newb= *bezt;
+ }
+ else {
+ /* median */
+ VecMidf(newb->vec[0], newb->vec[0], bezt->vec[0]);
+ VecMidf(newb->vec[1], newb->vec[1], bezt->vec[1]);
+ VecMidf(newb->vec[2], newb->vec[2], bezt->vec[2]);
+
+ newb->h1= newb->h2= HD_FREE;
+
+ ei->icu->totvert--;
+ }
+
+ }
+ else {
+ newb++;
+ *newb= *bezt;
+ }
+ bezt++;
+ }
+
+ MEM_freeN(ei->icu->bezt);
+ ei->icu->bezt= new1;
+
+ calchandles_ipocurve(ei->icu);
+ }
+ }
+ }
+
+ editipo_changed(G.sipo, 1); /* makes ipokeys again! */
+
+ /* remove double keys */
+ if(G.sipo->showkey) {
+ ik= G.sipo->ipokey.first;
+ ikn= ik->next;
+
+ while(ik && ikn) {
+ if( (ik->flag & 1) && (ikn->flag & 1) ) {
+ if( fabs(ik->val-ikn->val) < 0.9 ) {
+ val= (float)((ik->val + ikn->val)/2.0);
+
+ for(a=0; a<G.sipo->totipo; a++) {
+ if(ik->data[a]) ik->data[a]->vec[1][0]= val;
+ if(ikn->data[a]) ikn->data[a]->vec[1][0]= val;
+ }
+ }
+ }
+ ik= ikn;
+ ikn= ikn->next;
+
+ }
+
+ editipo_changed(G.sipo, 1); /* makes ipokeys agian! */
+
+ }
+ deselectall_editipo();
+}
+
+
+void clean_ipo(void)
+{
+ EditIpo *ei;
+ short ok;
+ int b;
+
+ ok= fbutton(&G.scene->toolsettings->clean_thresh,
+ 0.0000001f, 1.0, 0.001, 0.1,
+ "Threshold");
+ if (!ok) return;
+
+ get_status_editipo();
+
+ ei= G.sipo->editipo;
+ for(b=0; b<G.sipo->totipo; b++, ei++) {
+ if (ISPOIN3(ei, flag & IPO_VISIBLE, icu, icu->bezt)) {
+
+ ok= 0;
+ if(G.sipo->showkey) ok= 1;
+ else if(totipo_vert && (ei->flag & IPO_EDIT)) ok= 2;
+ else if(totipo_vert==0 && (ei->flag & IPO_SELECT)) ok= 3;
+
+ if(ok) {
+ /* only clean if ok */
+ clean_ipo_curve(ei->icu);
+ }
+ }
+ }
+
+ editipo_changed(G.sipo, 1);
+ BIF_undo_push("Clean IPO");
+}
+
+void clean_ipo_curve(IpoCurve *icu)
+{
+ BezTriple *old_bezts, *bezt, *beztn;
+ BezTriple *lastb;
+ int totCount, i;
+ float thresh;
+
+ /* check if any points */
+ if (icu == NULL || icu->totvert <= 1)
+ return;
+
+ /* get threshold for match-testing */
+ thresh= G.scene->toolsettings->clean_thresh;
+
+ /* make a copy of the old BezTriples, and clear IPO curve */
+ old_bezts = icu->bezt;
+ totCount = icu->totvert;
+ icu->bezt = NULL;
+ icu->totvert = 0;
+
+ /* now insert first keyframe, as it should be ok */
+ bezt = old_bezts;
+ insert_vert_icu(icu, bezt->vec[1][0], bezt->vec[1][1], 0);
+
+ /* Loop through BezTriples, comparing them. Skip any that do
+ * not fit the criteria for "ok" points.
+ */
+ for (i=1; i<totCount; i++) {
+ float prev[2], cur[2], next[2];
+
+ /* get BezTriples and their values */
+ if (i < (totCount - 1)) {
+ beztn = (old_bezts + (i+1));
+ next[0]= beztn->vec[1][0]; next[1]= beztn->vec[1][1];
+ }
+ else {
+ beztn = NULL;
+ next[0] = next[1] = 0.0f;
+ }
+ lastb= (icu->bezt + (icu->totvert - 1));
+ bezt= (old_bezts + i);
+
+ /* get references for quicker access */
+ prev[0] = lastb->vec[1][0]; prev[1] = lastb->vec[1][1];
+ cur[0] = bezt->vec[1][0]; cur[1] = bezt->vec[1][1];
+
+ /* check if current bezt occurs at same time as last ok */
+ if (IS_EQT(cur[0], prev[0], thresh)) {
+ /* If there is a next beztriple, and if occurs at the same time, only insert
+ * if there is a considerable distance between the points, and also if the
+ * current is further away than the next one is to the previous.
+ */
+ if (beztn && (IS_EQT(cur[0], next[0], thresh)) &&
+ (IS_EQT(next[1], prev[1], thresh)==0))
+ {
+ /* only add if current is further away from previous */
+ if (cur[1] > next[1]) {
+ if (IS_EQT(cur[1], prev[1], thresh) == 0) {
+ /* add new keyframe */
+ insert_vert_icu(icu, cur[0], cur[1], 0);
+ }
+ }
+ }
+ else {
+ /* only add if values are a considerable distance apart */
+ if (IS_EQT(cur[1], prev[1], thresh) == 0) {
+ /* add new keyframe */
+ insert_vert_icu(icu, cur[0], cur[1], 0);
+ }
+ }
+ }
+ else {
+ /* checks required are dependent on whether this is last keyframe or not */
+ if (beztn) {
+ /* does current have same value as previous and next? */
+ if (IS_EQT(cur[1], prev[1], thresh) == 0) {
+ /* add new keyframe*/
+ insert_vert_icu(icu, cur[0], cur[1], 0);
+ }
+ else if (IS_EQT(cur[1], next[1], thresh) == 0) {
+ /* add new keyframe */
+ insert_vert_icu(icu, cur[0], cur[1], 0);
+ }
+ }
+ else {
+ /* add if value doesn't equal that of previous */
+ if (IS_EQT(cur[1], prev[1], thresh) == 0) {
+ /* add new keyframe */
+ insert_vert_icu(icu, cur[0], cur[1], 0);
+ }
+ }
+ }
+ }
+
+ /* now free the memory used by the old BezTriples */
+ if (old_bezts)
+ MEM_freeN(old_bezts);
+}
+
+void smooth_ipo(void)
+{
+ EditIpo *ei;
+ short ok;
+ int b;
+
+ get_status_editipo();
+
+ ei= G.sipo->editipo;
+ for(b=0; b<G.sipo->totipo; b++, ei++) {
+ if (ISPOIN3(ei, flag & IPO_VISIBLE, icu, icu->bezt)) {
+
+ ok= 0;
+ if(G.sipo->showkey) ok= 1;
+ else if(totipo_vert && (ei->flag & IPO_EDIT)) ok= 2;
+ else if(totipo_vert==0 && (ei->flag & IPO_SELECT)) ok= 3;
+
+ if(ok) {
+ IpoCurve *icu= ei->icu;
+ BezTriple *bezt;
+ float meanValSum = 0.0f, meanVal;
+ float valDiff;
+ int i, totSel = 0;
+
+ /* check if enough points */
+ if (icu->totvert >= 3) {
+ /* first loop through - obtain average value */
+ bezt= icu->bezt;
+ for (i=1; i < icu->totvert; i++, bezt++) {
+ if (BEZSELECTED(bezt)) {
+ /* line point's handles up with point's vertical position */
+ bezt->vec[0][1]= bezt->vec[2][1]= bezt->vec[1][1];
+ if(bezt->h1==HD_AUTO || bezt->h1==HD_VECT) bezt->h1= HD_ALIGN;
+ if(bezt->h2==HD_AUTO || bezt->h2==HD_VECT) bezt->h2= HD_ALIGN;
+
+ /* add value to total */
+ meanValSum += bezt->vec[1][1];
+ totSel++;
+ }
+ }
+
+ /* calculate mean value */
+ meanVal= meanValSum / totSel;
+
+ /* second loop through - update point positions */
+ bezt= icu->bezt;
+ for (i=0; i < icu->totvert; i++, bezt++) {
+ if (BEZSELECTED(bezt)) {
+ /* 1. calculate difference between the points
+ * 2. move point half-way along that distance
+ */
+ if (bezt->vec[1][1] > meanVal) {
+ /* bezt val above mean */
+ valDiff= bezt->vec[1][1] - meanVal;
+ bezt->vec[1][1]= meanVal + (valDiff / 2);
+ }
+ else {
+ /* bezt val below mean */
+ valDiff= meanVal - bezt->vec[1][1];
+ bezt->vec[1][1] = bezt->vec[1][1] + (valDiff / 2);
+ }
+ }
+ }
+ }
+
+ /* recalc handles */
+ calchandles_ipocurve(icu);
+ }
+ }
+ }
+
+ editipo_changed(G.sipo, 1);
+ BIF_undo_push("Smooth IPO");
+}
+
+void join_ipo_menu(void)
+{
+ int mode = 0;
+ mode= pupmenu("Join %t|All Selected %x1|Selected Doubles %x2");
+
+ if (mode == -1) return;
+
+ join_ipo(mode);
+}
+
+void join_ipo(int mode)
+{
+ EditIpo *ei;
+ IpoKey *ik;
+ IpoCurve *icu;
+ BezTriple *bezt, *beztn, *newb;
+ float val;
+ int tot, a, b;
+
+ get_status_editipo();
+
+ /* Mode events:
+ * All Selected: 1
+ * Selected Doubles: 2
+ */
+
+ if( mode==2 ) {
+ remove_doubles_ipo();
+ return;
+ }
+
+ /* first: multiple selected verts in 1 curve */
+ ei= G.sipo->editipo;
+ for(a=0; a<G.sipo->totipo; a++, ei++) {
+ if (ISPOIN3(ei, flag & IPO_VISIBLE, icu, icu->bezt)) {
+ if(G.sipo->showkey || (ei->flag & IPO_EDIT)) {
+ icu= ei->icu;
+
+ /* how many points */
+ tot= 0;
+ b= icu->totvert;
+ bezt= icu->bezt;
+ while(b--) {
+ if(bezt->f2 & 1) tot++;
+ bezt++;
+ }
+
+ if(tot>1) {
+ tot--;
+ icu->totvert-= tot;
+
+ newb= MEM_mallocN(icu->totvert*sizeof(BezTriple), "bezt");
+ /* the first point is the new one */
+ beztn= newb+1;
+ tot= 0;
+
+ bezt= icu->bezt;
+ b= icu->totvert+tot+1;
+ while(b--) {
+
+ if(bezt->f2 & 1) {
+ if(tot==0) *newb= *bezt;
+ else {
+ VecAddf(newb->vec[0], newb->vec[0], bezt->vec[0]);
+ VecAddf(newb->vec[1], newb->vec[1], bezt->vec[1]);
+ VecAddf(newb->vec[2], newb->vec[2], bezt->vec[2]);
+ }
+ tot++;
+ }
+ else {
+ *beztn= *bezt;
+ beztn++;
+ }
+ bezt++;
+ }
+
+ VecMulf(newb->vec[0], (float)(1.0/((float)tot)));
+ VecMulf(newb->vec[1], (float)(1.0/((float)tot)));
+ VecMulf(newb->vec[2], (float)(1.0/((float)tot)));
+
+ MEM_freeN(icu->bezt);
+ icu->bezt= newb;
+
+ sort_time_ipocurve(icu);
+ calchandles_ipocurve(icu);
+ }
+ }
+ }
+ }
+
+ /* next: in keymode: join multiple selected keys */
+
+ editipo_changed(G.sipo, 1); /* makes ipokeys again! */
+
+ if(G.sipo->showkey) {
+ ik= G.sipo->ipokey.first;
+ val= 0.0;
+ tot= 0;
+ while(ik) {
+ if(ik->flag & 1) {
+ for(a=0; a<G.sipo->totipo; a++) {
+ if(ik->data[a]) {
+ val+= ik->data[a]->vec[1][0];
+ break;
+ }
+ }
+ tot++;
+ }
+ ik= ik->next;
+ }
+ if(tot>1) {
+ val/= (float)tot;
+
+ ik= G.sipo->ipokey.first;
+ while(ik) {
+ if(ik->flag & 1) {
+ for(a=0; a<G.sipo->totipo; a++) {
+ if(ik->data[a]) {
+ ik->data[a]->vec[1][0]= val;
+ }
+ }
+ }
+ ik= ik->next;
+ }
+ editipo_changed(G.sipo, 0);
+ }
+ }
+ deselectall_editipo();
+ BIF_undo_push("Join Ipo");
+}
+
+void ipo_snap_menu(void)
+{
+ short event;
+
+ event= pupmenu("Snap %t|Horizontal %x1|To Next %x2|To Frame %x3|To Current Frame%x4");
+ if(event < 1) return;
+
+ ipo_snap(event);
+}
+
+void ipo_snap(short event)
+{
+ EditIpo *ei;
+ BezTriple *bezt;
+ float dx = 0.0;
+ int a, b;
+ short ok, ok2;
+
+ /* events:
+ * Horizontal : 1
+ * To Next: 2
+ * To Frame: 3
+ * To Current Frame: 4
+ */
+
+ get_status_editipo();
+
+ /* map ipo-points for editing if scaled ipo */
+ if (NLA_IPO_SCALED) {
+ actstrip_map_ipo_keys(OBACT, G.sipo->ipo, 0, 0);
+ }
+
+ ei= G.sipo->editipo;
+ for(b=0; b<G.sipo->totipo; b++, ei++) {
+ if (ISPOIN3(ei, flag & IPO_VISIBLE, icu, icu->bezt)) {
+
+ ok2= 0;
+ if(G.sipo->showkey) ok2= 1;
+ else if(totipo_vert && (ei->flag & IPO_EDIT)) ok2= 2;
+ else if(totipo_vert==0 && (ei->flag & IPO_SELECT)) ok2= 3;
+
+ if(ok2) {
+ bezt= ei->icu->bezt;
+ a= ei->icu->totvert;
+ while(a--) {
+ ok= 0;
+ if(totipo_vert) {
+ if(bezt->f2 & 1) ok= 1;
+ }
+ else ok= 1;
+
+ if(ok) {
+ if(event==1) {
+ bezt->vec[0][1]= bezt->vec[2][1]= bezt->vec[1][1];
+ if(bezt->h1==HD_AUTO || bezt->h1==HD_VECT) bezt->h1= HD_ALIGN;
+ if(bezt->h2==HD_AUTO || bezt->h2==HD_VECT) bezt->h2= HD_ALIGN;
+ }
+ else if(event==2) {
+ if(a) {
+ bezt->vec[0][1]= bezt->vec[1][1]= bezt->vec[2][1]= (bezt+1)->vec[1][1];
+ if(bezt->h1==HD_AUTO || bezt->h1==HD_VECT) bezt->h1= HD_ALIGN;
+ if(bezt->h2==HD_AUTO || bezt->h2==HD_VECT) bezt->h2= HD_ALIGN;
+ }
+ }
+ else if(event==3) {
+ bezt->vec[1][0]= (float)(floor(bezt->vec[1][0]+0.5));
+ }
+ else if(event==4) { /* to current frame */
+
+ if(ok2==1 || ok2==2) {
+
+ if(G.sipo->blocktype==ID_SEQ) {
+ Sequence *seq;
+
+ seq= (Sequence *)G.sipo->from;
+ if(seq && (seq->flag & SEQ_IPO_FRAME_LOCKED) == 0) {
+ dx= (float)(CFRA-seq->startdisp);
+ dx= (float)(100.0*dx/((float)(seq->enddisp-seq->startdisp)));
+
+ dx-= bezt->vec[1][0];
+ } else {
+ dx= G.scene->r.framelen*CFRA - bezt->vec[1][0];
+ }
+ }
+ else dx= G.scene->r.framelen*CFRA - bezt->vec[1][0];
+
+ bezt->vec[0][0]+= dx;
+ bezt->vec[1][0]+= dx;
+ bezt->vec[2][0]+= dx;
+ }
+ }
+ }
+
+ bezt++;
+ }
+ calchandles_ipocurve(ei->icu);
+ }
+ }
+ }
+
+ /* undo mapping of ipo-points for editing if scaled ipo */
+ if (NLA_IPO_SCALED) {
+ actstrip_map_ipo_keys(OBACT, G.sipo->ipo, 1, 0);
+ }
+
+ editipo_changed(G.sipo, 1);
+ BIF_undo_push("Snap Ipo");
+}
+
+void ipo_mirror_menu(void)
+{
+ int mode = 0;
+ mode= pupmenu("Mirror Over%t|Current Frame%x1|Vertical Axis%x2|Horizontal Axis%x3");
+
+ if (mode == -1) return;
+
+ ipo_mirror(mode);
+}
+
+void ipo_mirror(short mode)
+{
+ EditIpo *ei;
+ BezTriple *bezt;
+
+ int a, b;
+ short ok, ok2, i;
+ float diff;
+
+ /* what's this for? */
+ get_status_editipo();
+
+ /* get edit ipo */
+ ei= G.sipo->editipo;
+ if (!ei) return;
+
+ /* map ipo-points for editing if scaled ipo */
+ if (NLA_IPO_SCALED) {
+ actstrip_map_ipo_keys(OBACT, G.sipo->ipo, 0, 0);
+ }
+
+ /* look throught ipo curves */
+ for(b=0; b<G.sipo->totipo; b++, ei++) {
+ if (ISPOIN3(ei, flag & IPO_VISIBLE, icu, icu->bezt)) {
+
+ ok2= 0;
+ if(G.sipo->showkey) ok2= 1;
+ else if(totipo_vert && (ei->flag & IPO_EDIT)) ok2= 2;
+ else if(totipo_vert==0 && (ei->flag & IPO_SELECT)) ok2= 3;
+
+ if(ok2) {
+ bezt= ei->icu->bezt;
+ a= ei->icu->totvert;
+
+ /* loop through beztriples, mirroring them */
+ while(a--) {
+ ok= 0;
+ if(totipo_vert) {
+ if(bezt->f2 & 1) ok= 1;
+ }
+ else ok= 1;
+
+ if(ok) {
+ switch (mode) {
+ case 1: /* mirror over current frame */
+ {
+ for (i=0; i<3; i++) {
+ diff= ((float)CFRA - bezt->vec[i][0]);
+ bezt->vec[i][0]= ((float)CFRA + diff);
+ }
+ }
+ break;
+ case 2: /* mirror over vertical axis (frame 0) */
+ {
+ for (i=0; i<3; i++) {
+ diff= (0.0f - bezt->vec[i][0]);
+ bezt->vec[i][0]= (0.0f + diff);
+ }
+ }
+ break;
+ case 3: /* mirror over horizontal axis */
+ {
+ for (i=0; i<3; i++) {
+ diff= (0.0f - bezt->vec[i][1]);
+ bezt->vec[i][1]= (0.0f + diff);
+ }
+ }
+ break;
+ }
+ }
+
+ bezt++;
+ }
+
+ /* sort out order and handles */
+ sort_time_ipocurve(ei->icu);
+ calchandles_ipocurve(ei->icu);
+ }
+ }
+ }
+
+ /* undo mapping of ipo-points for editing if scaled ipo */
+ if (NLA_IPO_SCALED) {
+ actstrip_map_ipo_keys(OBACT, G.sipo->ipo, 1, 0);
+ }
+
+ /* cleanup and undo push */
+ editipo_changed(G.sipo, 1);
+ BIF_undo_push("Mirror Ipo");
+}
+
+/*
+ * When deleting an IPO curve from Python, check if the Ipo is being
+ * edited and if so clear the pointer to the old curve.
+ */
+
+void del_ipoCurve ( IpoCurve * icu )
+{
+ int i;
+ EditIpo *ei= G.sipo->editipo;
+ if (!ei) return;
+
+ for(i=0; i<G.sipo->totipo; i++, ei++) {
+ if ( ei->icu == icu ) {
+ ei->flag &= ~(IPO_SELECT | IPO_EDIT);
+ ei->icu= NULL;
+ return;
+ }
+ }
+}
+
+void del_ipo(int need_check)
+{
+ EditIpo *ei;
+ BezTriple *bezt, *bezt1;
+ int a, b;
+ int del, event;
+
+ get_status_editipo();
+ if(G.sipo->ipo && G.sipo->ipo->id.lib) return;
+
+ if(totipo_edit==0 && totipo_sel==0 && totipo_vertsel==0) {
+ if (need_check) {
+ if(okee("Erase selected keys"))
+ delete_key(OBACT);
+ }
+ else
+ delete_key(OBACT);
+ return;
+ }
+
+ if (need_check)
+ if( okee("Erase selected")==0 ) return;
+
+ // first round, can we delete entire parts?
+ ei= G.sipo->editipo;
+ for(a=0; a<G.sipo->totipo; a++, ei++) {
+
+ del= 0;
+
+ if(G.sipo->showkey==0 && totipo_edit==0) {
+ if (ISPOIN3(ei, flag & IPO_VISIBLE, flag & IPO_SELECT, icu)) {
+ del= 1;
+ }
+ }
+ else {
+ if (ISPOIN(ei, flag & IPO_VISIBLE, icu)) {
+ if(G.sipo->showkey || (ei->flag & IPO_EDIT)) {
+ if(ei->icu->bezt) {
+ bezt= ei->icu->bezt;
+ b= ei->icu->totvert;
+ if(b) {
+ while(b) {
+ if( BEZSELECTED(bezt) );
+ else break;
+ b--;
+ bezt++;
+ }
+ if(b==0) del= 1;
+ }
+ }
+ }
+ }
+ }
+
+ if(del) {
+ if(ei->icu->driver==NULL) {
+ BLI_remlink( &(G.sipo->ipo->curve), ei->icu);
+
+ free_ipo_curve(ei->icu);
+
+ ei->flag &= ~IPO_SELECT;
+ ei->flag &= ~IPO_EDIT;
+ ei->icu= NULL;
+ }
+ else {
+ if(ei->icu->bezt) MEM_freeN(ei->icu->bezt);
+ ei->icu->bezt= NULL;
+ ei->icu->totvert= 0;
+ ei->flag &= ~IPO_EDIT;
+ }
+ }
+ }
+
+ // 2nd round, small parts: just curves
+ ei= G.sipo->editipo;
+ for(b=0; b<G.sipo->totipo; b++, ei++) {
+ if (ISPOIN(ei, flag & IPO_VISIBLE, icu)) {
+ if(G.sipo->showkey || (ei->flag & IPO_EDIT)) {
+
+ event= 0;
+ if(ei->icu->bezt) {
+
+ bezt= ei->icu->bezt;
+ for(a=0; a<ei->icu->totvert; a++) {
+ if( BEZSELECTED(bezt) ) {
+ memcpy(bezt, bezt+1, (ei->icu->totvert-a-1)*sizeof(BezTriple));
+ ei->icu->totvert--;
+ a--;
+ event= 1;
+ }
+ else bezt++;
+ }
+ if(event) {
+ if(ei->icu->totvert) {
+ bezt1 = (BezTriple*) MEM_mallocN(ei->icu->totvert * sizeof(BezTriple), "delNurb");
+ memcpy(bezt1, ei->icu->bezt, (ei->icu->totvert)*sizeof(BezTriple) );
+ MEM_freeN(ei->icu->bezt);
+ ei->icu->bezt= bezt1;
+ }
+ else {
+ MEM_freeN(ei->icu->bezt);
+ ei->icu->bezt= NULL;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ get_status_editipo(); /* count again */
+ check_active_editipo();
+
+ BIF_undo_push("Delete Ipo");
+ allqueue(REDRAWNLA, 0);
+ allqueue (REDRAWACTION, 0);
+ allqueue(REDRAWIPO, 0);
+ allspace(REMAKEIPO, 0);
+}
+
+/* ******************** copy paste buffer ******************** */
+ListBase ipocopybuf={0, 0};
+int totipocopybuf=0;
+
+void free_ipocopybuf(void)
+{
+ IpoCurve *icu;
+
+ while( (icu= ipocopybuf.first) ) {
+ BLI_remlink(&ipocopybuf, icu);
+ free_ipo_curve(icu);
+ }
+ totipocopybuf= 0;
+}
+
+void copy_editipo(void)
+{
+ EditIpo *ei;
+ IpoCurve *icu;
+ int a;
+
+ if(G.sipo->showkey) {
+ error("cannot copy\n");
+ return;
+ }
+
+ free_ipocopybuf();
+
+ ei= G.sipo->editipo;
+ for(a=0; a<G.sipo->totipo; a++, ei++) {
+ if (ISPOIN(ei, flag & IPO_VISIBLE, icu)) {
+ if( (ei->flag & IPO_EDIT) || (ei->flag & IPO_SELECT) ) {
+ icu= MEM_callocN(sizeof(IpoCurve), "ipocopybuf");
+ *icu= *(ei->icu);
+ BLI_addtail(&ipocopybuf, icu);
+ icu->bezt= MEM_dupallocN(icu->bezt);
+ icu->driver= MEM_dupallocN(icu->driver);
+
+ totipocopybuf++;
+ }
+ }
+ }
+
+ if(totipocopybuf==0) error("Copy buffer is empty");
+}
+
+void paste_editipo(void)
+{
+ EditIpo *ei;
+ IpoCurve *icu;
+ int a;
+
+ if (G.sipo->showkey) return;
+
+ if (totipocopybuf==0) return;
+ if (G.sipo->ipo==0) return;
+ if (G.sipo->ipo && G.sipo->ipo->id.lib) return;
+
+ get_status_editipo();
+
+ if (totipo_vis==0) {
+ error("No visible channels");
+ return;
+ }
+ else if (totipo_vis!=totipocopybuf && totipo_sel!=totipocopybuf) {
+ error("Incompatible paste");
+ return;
+ }
+
+ icu= ipocopybuf.first;
+
+ for (a=0, ei=G.sipo->editipo; a<G.sipo->totipo; a++, ei++) {
+ if (ei->flag & IPO_VISIBLE) {
+ /* don't attempt pasting if no valid buffer-curve to paste from anymore */
+ if (icu == 0) return;
+
+ /* if in editmode, paste keyframes */
+ if (ei->flag & IPO_EDIT) {
+ BezTriple *bezt;
+ float offset= 0.0f;
+ short offsetInit= 0;
+ int i;
+
+ /* make sure an ipo-curve exists (it may not, as this is an editipo) */
+ ei->icu= verify_ipocurve(G.sipo->from, G.sipo->blocktype, G.sipo->actname, G.sipo->constname, ei->adrcode);
+ if (ei->icu == NULL) return;
+
+ /* Copy selected beztriples from source icu onto this edit-icu,
+ * with all added keyframes being offsetted by the difference between
+ * the first source keyframe and the current frame.
+ */
+ for (i=0, bezt=icu->bezt; i < icu->totvert; i++, bezt++) {
+ /* skip if not selected */
+ if (BEZSELECTED(bezt) == 0) continue;
+
+ /* initialise offset (if not already done) */
+ if (offsetInit==0) {
+ offset= CFRA - bezt->vec[1][0];
+ offsetInit= 1;
+ }
+ /* temporarily apply offset to src beztriple while copying */
+ bezt->vec[0][0] += offset;
+ bezt->vec[1][0] += offset;
+ bezt->vec[2][0] += offset;
+
+ /* insert the keyframe */
+ insert_bezt_icu(ei->icu, bezt);
+
+ /* un-apply offset from src beztriple after copying */
+ bezt->vec[0][0] -= offset;
+ bezt->vec[1][0] -= offset;
+ bezt->vec[2][0] -= offset;
+ }
+
+ /* recalculate handles of curve that data was pasted into */
+ calchandles_ipocurve(ei->icu);
+
+ /* advance to next copy/paste buffer ipo-curve */
+ icu= icu->next;
+ }
+
+ /* otherwise paste entire curve data if selected */
+ else if (ei->flag & IPO_SELECT) {
+ /* make sure an ipo-curve exists (it may not, as this is an editipo) */
+ ei->icu= verify_ipocurve(G.sipo->from, G.sipo->blocktype, G.sipo->actname, G.sipo->constname, ei->adrcode);
+ if (ei->icu==NULL) return;
+
+ /* clear exisiting dynamic memory (keyframes, driver) */
+ if (ei->icu->bezt) MEM_freeN(ei->icu->bezt);
+ ei->icu->bezt= NULL;
+ if (ei->icu->driver) MEM_freeN(ei->icu->driver);
+ ei->icu->driver= NULL;
+
+ ei->icu->totvert= icu->totvert;
+ ei->icu->flag= ei->flag= icu->flag;
+ ei->icu->extrap= icu->extrap;
+ ei->icu->ipo= icu->ipo;
+
+ /* make a copy of the source icu's data */
+ if (icu->bezt)
+ ei->icu->bezt= MEM_dupallocN(icu->bezt);
+ if (icu->driver)
+ ei->icu->driver= MEM_dupallocN(icu->driver);
+
+ /* advance to next copy/paste buffer ipo-curve */
+ icu= icu->next;
+ }
+ }
+ }
+
+ editipo_changed(G.sipo, 1);
+ BIF_undo_push("Paste Ipo curves");
+}
+
+/* *********************** */
+
+
+static int find_other_handles(EditIpo *eicur, float ctime, BezTriple **beztar)
+{
+ EditIpo *ei;
+ BezTriple *bezt;
+ int a, b, c= 1, totvert;
+
+ ei= G.sipo->editipo;
+ for(a=0; a<G.sipo->totipo; a++, ei++) {
+ if(ei!=eicur && ei->icu && (ei->flag & IPO_VISIBLE)) {
+
+ bezt= ei->icu->bezt;
+ totvert= ei->icu->totvert;
+
+ for(b=0; b<totvert; b++, bezt++) {
+ if( bezt->vec[1][0] < ctime+IPOTHRESH && bezt->vec[1][0] > ctime-IPOTHRESH) {
+ if(c>2) return 0;
+ beztar[c]= bezt;
+ c++;
+ }
+ }
+ }
+ }
+
+ if(c==3) return 1;
+ return 0;
+}
+
+void set_speed_editipo(float speed)
+{
+ EditIpo *ei;
+ BezTriple *bezt, *beztar[3];
+ float vec1[3], vec2[3];
+ int a, b, totvert, didit=0, done_error = 0;
+
+ if(G.sipo->ipo && G.sipo->ipo->id.lib) return;
+
+ /* starting with 1 visible curve, selected point, associated points: do lencorr! */
+
+ ei= G.sipo->editipo;
+ for(a=0; a<G.sipo->totipo; a++, ei++) {
+ if (ISPOIN(ei, flag & IPO_VISIBLE, icu)) {
+ bezt= ei->icu->bezt;
+ totvert= ei->icu->totvert;
+
+ for(b=0; b<totvert; b++, bezt++) {
+ if(BEZSELECTED(bezt)) {
+
+ beztar[0]= bezt;
+
+ if( find_other_handles(ei, bezt->vec[1][0], beztar) ) {
+ beztar[0]->h1= beztar[0]->h2= HD_ALIGN;
+ beztar[1]->h1= beztar[1]->h2= HD_ALIGN;
+ beztar[2]->h1= beztar[2]->h2= HD_ALIGN;
+
+ vec1[0]= (beztar[0]->vec[1][1] - beztar[0]->vec[0][1]) / (beztar[0]->vec[1][0] - beztar[0]->vec[0][0]) ;
+ vec2[0]= (beztar[0]->vec[1][1] - beztar[0]->vec[2][1]) / (beztar[0]->vec[2][0] - beztar[0]->vec[1][0]) ;
+
+ vec1[1]= (beztar[1]->vec[1][1] - beztar[1]->vec[0][1]) / (beztar[1]->vec[1][0] - beztar[1]->vec[0][0]) ;
+ vec2[1]= (beztar[1]->vec[1][1] - beztar[1]->vec[2][1]) / (beztar[1]->vec[2][0] - beztar[1]->vec[1][0]) ;
+
+ vec1[2]= (beztar[2]->vec[1][1] - beztar[2]->vec[0][1]) / (beztar[2]->vec[1][0] - beztar[2]->vec[0][0]) ;
+ vec2[2]= (beztar[2]->vec[1][1] - beztar[2]->vec[2][1]) / (beztar[2]->vec[2][0] - beztar[2]->vec[1][0]) ;
+
+ Normalize(vec1);
+ Normalize(vec2);
+
+ VecMulf(vec1, speed);
+ VecMulf(vec2, speed);
+
+ beztar[0]->vec[0][1]= beztar[0]->vec[1][1] - vec1[0]*(beztar[0]->vec[1][0] - beztar[0]->vec[0][0]) ;
+ beztar[0]->vec[2][1]= beztar[0]->vec[1][1] - vec2[0]*(beztar[0]->vec[2][0] - beztar[0]->vec[1][0]) ;
+
+ beztar[1]->vec[0][1]= beztar[1]->vec[1][1] - vec1[1]*(beztar[1]->vec[1][0] - beztar[1]->vec[0][0]) ;
+ beztar[1]->vec[2][1]= beztar[1]->vec[1][1] - vec2[1]*(beztar[1]->vec[2][0] - beztar[1]->vec[1][0]) ;
+
+ beztar[2]->vec[0][1]= beztar[2]->vec[1][1] - vec1[2]*(beztar[2]->vec[1][0] - beztar[2]->vec[0][0]) ;
+ beztar[2]->vec[2][1]= beztar[2]->vec[1][1] - vec2[2]*(beztar[2]->vec[2][0] - beztar[2]->vec[1][0]) ;
+
+ didit= 1;
+ }
+ else {
+ if (done_error==0) {
+ error("Only works for 3 visible curves with handles");
+ }
+ done_error = 1;
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ if(didit==0) error("Did not set speed");
+
+ editipo_changed(G.sipo, 1);
+ BIF_undo_push("Set speed IPO");
+ allqueue(REDRAWNLA, 0);
+ allqueue (REDRAWACTION, 0);
+ allqueue(REDRAWIPO, 0);
+
+}
+
+
+/* **************************************************** */
+
+/* IPOKEY:
+ *
+ * there are three ways to use this system:
+ * 1. below: for drawing and editing in Ipo window
+ * 2. for drawing key positions in View3D (see ipo.c and drawobject.c)
+ * 3. editing keys in View3D (below and in editobject.c)
+ *
+ */
+
+
+void free_ipokey(ListBase *lb)
+{
+ IpoKey *ik;
+
+ ik= lb->first;
+ while(ik) {
+ if(ik->data) MEM_freeN(ik->data);
+ ik= ik->next;
+ }
+ BLI_freelistN(lb);
+}
+
+
+void add_to_ipokey(ListBase *lb, BezTriple *bezt, int nr, int len)
+{
+ IpoKey *ik, *ikn;
+
+ ik= lb->first;
+ while(ik) {
+
+ if( ik->val==bezt->vec[1][0] ) {
+ if(ik->data[nr]==0) { /* double points! */
+ ik->data[nr]= bezt;
+ if(bezt->f2 & 1) ik->flag= 1;
+ return;
+ }
+ }
+ else if(ik->val > bezt->vec[1][0]) break;
+
+ ik= ik->next;
+ }
+
+ ikn= MEM_callocN(sizeof(IpoKey), "add_to_ipokey");
+ if(ik) BLI_insertlinkbefore(lb, ik, ikn);
+ else BLI_addtail(lb, ikn);
+
+ ikn->data= MEM_callocN(sizeof(float *)*len, "add_to_ipokey");
+ ikn->data[nr]= bezt;
+ ikn->val= bezt->vec[1][0];
+
+ if(bezt->f2 & 1) ikn->flag= 1;
+}
+
+void make_ipokey(void)
+{
+ EditIpo *ei;
+ IpoKey *ik;
+ ListBase *lb;
+ BezTriple *bezt;
+ int a, b, sel, desel, totvert;
+
+ lb= &G.sipo->ipokey;
+ free_ipokey(lb);
+
+ ei= G.sipo->editipo;
+ if(ei==0) return;
+ for(a=0; a<G.sipo->totipo; a++, ei++) {
+ if (ISPOIN(ei, flag & IPO_VISIBLE, icu)) {
+ bezt= ei->icu->bezt;
+ totvert= ei->icu->totvert;
+
+ for(b=0; b<totvert; b++, bezt++) {
+ add_to_ipokey(lb, bezt, a, G.sipo->totipo);
+ }
+
+ ei->flag &= ~IPO_SELECT;
+ ei->flag &= ~IPO_EDIT;
+ ei->icu->flag= ei->flag;
+ }
+ }
+
+ /* test selectflags & scaling */
+ ik= lb->first;
+ while(ik) {
+ sel= desel= 0;
+ for(a=0; a<G.sipo->totipo; a++) {
+ if(ik->data[a]) {
+ bezt= ik->data[a];
+ if(bezt->f2 & 1) sel++;
+ else desel++;
+ }
+ }
+ if(sel && desel) sel= 0;
+ for(a=0; a<G.sipo->totipo; a++) {
+ if(ik->data[a]) {
+ bezt= ik->data[a];
+ if(sel) {
+ bezt->f1 |= 1;
+ bezt->f2 |= 1;
+ bezt->f3 |= 1;
+ }
+ else {
+ bezt->f1 &= ~1;
+ bezt->f2 &= ~1;
+ bezt->f3 &= ~1;
+ }
+ }
+ }
+ if(sel) ik->flag = 1;
+ else ik->flag= 0;
+
+ /* map ipo-keys for drawing/editing if scaled ipo */
+ if (NLA_IPO_SCALED) {
+ ik->val= get_action_frame_inv(OBACT, ik->val);
+ }
+
+ ik= ik->next;
+ }
+
+ get_status_editipo();
+}
+
+void make_ipokey_transform(Object *ob, ListBase *lb, int sel)
+{
+ IpoCurve *icu;
+ BezTriple *bezt;
+ IpoKey *ik;
+ int a, adrcode = 0, ok, dloc=0, drot=0, dsize=0;
+
+ if(ob->ipo==NULL) return;
+ if(ob->ipo->showkey==0) return;
+
+ /* test: are there delta curves? */
+ icu= ob->ipo->curve.first;
+ while(icu) {
+ if(icu->flag & IPO_VISIBLE) {
+ switch(icu->adrcode) {
+ case OB_DLOC_X:
+ case OB_DLOC_Y:
+ case OB_DLOC_Z:
+ dloc= 1;
+ break;
+ case OB_DROT_X:
+ case OB_DROT_Y:
+ case OB_DROT_Z:
+ drot= 1;
+ break;
+ case OB_DSIZE_X:
+ case OB_DSIZE_Y:
+ case OB_DSIZE_Z:
+ dsize= 1;
+ break;
+ }
+ }
+ icu= icu->next;
+ }
+
+ icu= ob->ipo->curve.first;
+ while(icu) {
+ if(icu->flag & IPO_VISIBLE) {
+ ok= 0;
+
+ switch(icu->adrcode) {
+ case OB_DLOC_X:
+ case OB_DLOC_Y:
+ case OB_DLOC_Z:
+ case OB_DROT_X:
+ case OB_DROT_Y:
+ case OB_DROT_Z:
+ case OB_DSIZE_X:
+ case OB_DSIZE_Y:
+ case OB_DSIZE_Z:
+ ok= 1;
+ break;
+
+ case OB_LOC_X:
+ case OB_LOC_Y:
+ case OB_LOC_Z:
+ if(dloc==0) ok= 1;
+ break;
+ case OB_ROT_X:
+ case OB_ROT_Y:
+ case OB_ROT_Z:
+ if(drot==0) ok= 1;
+ break;
+ case OB_SIZE_X:
+ case OB_SIZE_Y:
+ case OB_SIZE_Z:
+ if(dsize==0) ok= 1;
+ break;
+ }
+ if(ok) {
+ for(a=0; a<OB_TOTIPO; a++) {
+ if(icu->adrcode==ob_ar[a]) {
+ adrcode= a;
+ break;
+ }
+ }
+
+ bezt= icu->bezt;
+ a= icu->totvert;
+ while(a--) {
+ if(sel==0 || (bezt->f2 & 1)) {
+ add_to_ipokey(lb, bezt, adrcode, OB_TOTIPO);
+ }
+ bezt++;
+ }
+ }
+ }
+ icu= icu->next;
+ }
+
+
+ ik= lb->first;
+ while(ik) {
+ /* map ipo-keys for drawing/editing if scaled ipo */
+ if (NLA_IPO_SCALED) {
+ ik->val= get_action_frame_inv(OBACT, ik->val);
+ }
+
+ ik= ik->next;
+ }
+}
+
+void update_ipokey_val(void) /* after moving vertices */
+{
+ IpoKey *ik;
+ int a;
+
+ ik= G.sipo->ipokey.first;
+ while(ik) {
+ for(a=0; a<G.sipo->totipo; a++) {
+ if(ik->data[a]) {
+ ik->val= ik->data[a]->vec[1][0];
+
+ /* map ipo-keys for drawing/editing if scaled ipo */
+ if (NLA_IPO_SCALED) {
+ ik->val= get_action_frame_inv(OBACT, ik->val);
+ }
+ break;
+ }
+ }
+ ik= ik->next;
+ }
+}
+
+void set_tob_old(float *old, float *poin)
+{
+ old[0]= *(poin);
+ old[3]= *(poin-3);
+ old[6]= *(poin+3);
+}
+
+void set_ipo_pointers_transob(IpoKey *ik, TransOb *tob)
+{
+ BezTriple *bezt;
+ int a, delta= 0;
+
+ tob->locx= tob->locy= tob->locz= 0;
+ tob->rotx= tob->roty= tob->rotz= 0;
+ tob->sizex= tob->sizey= tob->sizez= 0;
+
+ for(a=0; a<OB_TOTIPO; a++) {
+ if(ik->data[a]) {
+ bezt= ik->data[a];
+
+ switch( ob_ar[a] ) {
+ case OB_LOC_X:
+ case OB_DLOC_X:
+ tob->locx= &(bezt->vec[1][1]); break;
+ case OB_LOC_Y:
+ case OB_DLOC_Y:
+ tob->locy= &(bezt->vec[1][1]); break;
+ case OB_LOC_Z:
+ case OB_DLOC_Z:
+ tob->locz= &(bezt->vec[1][1]); break;
+
+ case OB_DROT_X:
+ delta= 1;
+ case OB_ROT_X:
+ tob->rotx= &(bezt->vec[1][1]); break;
+ case OB_DROT_Y:
+ delta= 1;
+ case OB_ROT_Y:
+ tob->roty= &(bezt->vec[1][1]); break;
+ case OB_DROT_Z:
+ delta= 1;
+ case OB_ROT_Z:
+ tob->rotz= &(bezt->vec[1][1]); break;
+
+ case OB_SIZE_X:
+ case OB_DSIZE_X:
+ tob->sizex= &(bezt->vec[1][1]); break;
+ case OB_SIZE_Y:
+ case OB_DSIZE_Y:
+ tob->sizey= &(bezt->vec[1][1]); break;
+ case OB_SIZE_Z:
+ case OB_DSIZE_Z:
+ tob->sizez= &(bezt->vec[1][1]); break;
+ }
+ }
+ }
+
+ /* oldvals for e.g. undo */
+ if(tob->locx) set_tob_old(tob->oldloc, tob->locx);
+ if(tob->locy) set_tob_old(tob->oldloc+1, tob->locy);
+ if(tob->locz) set_tob_old(tob->oldloc+2, tob->locz);
+
+ /* store first oldrot, for mapping curves ('1'=10 degrees) and correct calculation */
+ if(tob->rotx) set_tob_old(tob->oldrot+3, tob->rotx);
+ if(tob->roty) set_tob_old(tob->oldrot+4, tob->roty);
+ if(tob->rotz) set_tob_old(tob->oldrot+5, tob->rotz);
+
+ /* store the first oldsize, this is not allowed to be dsize! */
+ if(tob->sizex) set_tob_old(tob->oldsize+3, tob->sizex);
+ if(tob->sizey) set_tob_old(tob->oldsize+4, tob->sizey);
+ if(tob->sizez) set_tob_old(tob->oldsize+5, tob->sizez);
+
+ tob->flag= TOB_IPO;
+ if(delta) tob->flag |= TOB_IPODROT;
+}
+
+
+
+static int float_to_frame (float frame)
+{
+ int to= (int) floor(0.5 + frame/G.scene->r.framelen );
+
+ return to;
+}
+
+void movekey_ipo(int dir) /* only call external from view3d queue */
+{
+ IpoKey *ik;
+ float toframe = 0.0;
+ int a;
+
+ if(G.sipo->showkey==0) return;
+
+ ik= G.sipo->ipokey.first;
+ if (dir==-1) {
+ while (ik && float_to_frame(ik->val)<CFRA) {
+ toframe= ik->val;
+ ik= ik->next;
+ }
+ } else {
+ while (ik && float_to_frame(ik->val)<=CFRA) {
+ ik= ik->next;
+ }
+ if (ik) toframe= ik->val;
+ }
+
+ a= float_to_frame(toframe);
+
+ if (a!=CFRA && a>0) {
+ CFRA= a;
+
+ update_for_newframe();
+ }
+
+ BIF_undo_push("Move Key");
+ allqueue(REDRAWNLA, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWIPO, 0);
+ allspace(REMAKEIPO, 0);
+
+}
+
+void movekey_obipo(int dir) /* only call external from view3d queue */
+{
+ Base *base;
+ Object *ob;
+ ListBase elems;
+ IpoKey *ik;
+ int a;
+ float toframe= CFRA;
+
+ if (!G.vd)
+ return;
+
+ base= FIRSTBASE;
+ while(base) {
+ if TESTBASELIB(base) {
+ ob= base->object;
+ if(ob->ipo && ob->ipo->showkey) {
+ elems.first= elems.last= 0;
+ make_ipokey_transform(ob, &elems, 0);
+
+ if(elems.first) {
+ ik= elems.first;
+ if (dir==-1) {
+ while (ik && float_to_frame(ik->val)<CFRA) {
+ toframe= ik->val;
+ ik= ik->next;
+ }
+ } else {
+ while (ik && float_to_frame(ik->val)<=CFRA) {
+ ik= ik->next;
+ }
+ if (ik) toframe= ik->val;
+ }
+
+ free_ipokey(&elems);
+ }
+ }
+ }
+
+ base= base->next;
+ }
+
+ a= float_to_frame(toframe);
+
+ if (a!=CFRA && a>0) {
+ CFRA= a;
+
+ update_for_newframe();
+ }
+
+ BIF_undo_push("Move Key");
+ allqueue(REDRAWNLA, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWIPO, 0);
+ allspace(REMAKEIPO, 0);
+
+}
+/* **************************************************** */
+/* IPO TRANSFORM TOOLS
+ *
+ * Only the helper functions are stored here these days. They are here as
+ * there are heaps of ugly globals which the IPO editor relies on.
+ * However, the actual transforms go through the transform system these days.
+ */
+
+/* Helper function for make_ipo_transdata, which is reponsible for associating
+ * source data with transform data
+ */
+static void bezt_to_transdata (TransData *td, TransData2D *td2d, float *loc, float *cent, short selected, short onlytime)
+{
+ /* New location from td gets dumped onto the old-location of td2d, which then
+ * gets copied to the actual data at td2d->loc2d (bezt->vec[n])
+ *
+ * Due to NLA scaling, we apply NLA scaling to some of the verts here,
+ * and then that scaling will be undone after transform is done.
+ */
+
+ if (NLA_IPO_SCALED) {
+ td2d->loc[0] = get_action_frame_inv(OBACT, loc[0]);
+ td2d->loc[1] = loc[1];
+ td2d->loc[2] = 0.0f;
+ td2d->loc2d = loc;
+
+ td->flag = 0;
+ td->loc = td2d->loc;
+ VECCOPY(td->center, cent);
+ VECCOPY(td->iloc, td->loc);
+ }
+ else {
+ td2d->loc[0] = loc[0];
+ td2d->loc[1] = loc[1];
+ td2d->loc[2] = 0.0f;
+ td2d->loc2d = loc;
+
+ td->flag = 0;
+ td->loc = td2d->loc;
+ VECCOPY(td->center, cent);
+ VECCOPY(td->iloc, td->loc);
+ }
+
+ memset(td->axismtx, 0, sizeof(td->axismtx));
+ td->axismtx[2][2] = 1.0f;
+
+ td->ext= NULL; td->tdi= NULL; td->val= NULL;
+
+ if (selected) {
+ td->flag |= TD_SELECTED;
+ td->dist= 0.0;
+ }
+ else
+ td->dist= MAXFLOAT;
+
+ if (onlytime)
+ td->flag |= TD_TIMEONLY;
+
+ Mat3One(td->mtx);
+ Mat3One(td->smtx);
+}
+
+/* This function is called by createTransIpoData and remake_ipo_transdata to
+ * create the TransData and TransData2D arrays for transform. The costly counting
+ * stage is only performed for createTransIpoData case, and is indicated by t->total==-1;
+ */
+void make_ipo_transdata (TransInfo *t)
+{
+ TransData *td = NULL;
+ TransData2D *td2d = NULL;
+
+ EditIpo *ei;
+ BezTriple *bezt;
+ int a, b;
+
+ /* countsel and propmode are used for proportional edit, which is not yet available */
+ int count=0/*, countsel=0*/;
+ /*int propmode = t->flag & T_PROP_EDIT;*/
+
+ /* count data and allocate memory (if needed) */
+ if (t->total == 0) {
+ /* count data first */
+ if (totipo_vertsel) {
+ /* we're probably in editmode, so only selected verts */
+ count= totipo_vertsel;
+ }
+ else if (totipo_edit==0 && totipo_sel!=0) {
+ /* we're not in editmode, so entire curves get moved */
+ ei= G.sipo->editipo;
+ for (a=0; a<G.sipo->totipo; a++, ei++) {
+ if (ISPOIN3(ei, flag & IPO_VISIBLE, flag & IPO_SELECT, icu)) {
+ if (ei->icu->bezt && ei->icu->ipo==IPO_BEZ)
+ count+= 3*ei->icu->totvert;
+ else
+ count+= ei->icu->totvert;
+ }
+ }
+ if (count==0) return;
+ }
+ else {
+ /* this case should not happen */
+ return;
+ }
+
+ /* memory allocation */
+ /*t->total= (propmode)? count: countsel;*/
+ t->total= count;
+ t->data= MEM_callocN(t->total*sizeof(TransData), "TransData (IPO Editor)");
+ /* for each 2d vert a 3d vector is allocated, so that they can be treated just as if they were 3d verts */
+ t->data2d= MEM_callocN(t->total*sizeof(TransData2D), "TransData2D (IPO Editor)");
+ }
+
+ td= t->data;
+ td2d= t->data2d;
+
+ /* add verts */
+ if (totipo_vertsel) {
+ /* we're probably in editmode, so only selected verts */
+ ei= G.sipo->editipo;
+ for (a=0; a<G.sipo->totipo; a++, ei++) {
+ /* only consider those curves that are visible and are being edited/used for showkeys */
+ if (ISPOIN(ei, flag & IPO_VISIBLE, icu)) {
+ if ( (ei->flag & IPO_EDIT) || G.sipo->showkey) {
+ if (ei->icu->bezt) {
+ short onlytime= (ei->disptype==IPO_DISPBITS) ? 1 : (G.sipo->showkey) ? 1 : 0;
+ bezt= ei->icu->bezt;
+
+ for (b=0; b < ei->icu->totvert; b++, bezt++) {
+ /* only include handles if selected, and interpolaton mode uses beztriples */
+ if (ei->icu->ipo==IPO_BEZ) {
+ if (bezt->f1 & 1)
+ bezt_to_transdata(td++, td2d++, bezt->vec[0], bezt->vec[1], 1, onlytime);
+ if (bezt->f3 & 1)
+ bezt_to_transdata(td++, td2d++, bezt->vec[2], bezt->vec[1], 1, onlytime);
+ }
+
+ /* only include main vert if selected */
+ if (bezt->f2 & 1) {
+ bezt_to_transdata(td++, td2d++, bezt->vec[1], bezt->vec[1], 1, onlytime);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (totipo_edit==0 && totipo_sel!=0) {
+ /* we're not in editmode, so entire curves get moved */
+ ei= G.sipo->editipo;
+ for (a=0; a<G.sipo->totipo; a++, ei++) {
+ /* only include curves that are visible and selected */
+ if (ISPOIN3(ei, flag & IPO_VISIBLE, flag & IPO_SELECT, icu)) {
+ if (ei->icu->bezt) {
+ short onlytime= (ei->disptype==IPO_DISPBITS) ? 1 : (G.sipo->showkey) ? 1 : 0;
+ bezt= ei->icu->bezt;
+ b= ei->icu->totvert;
+
+ for (b=0; b < ei->icu->totvert; b++, bezt++) {
+ /* only include handles if interpolation mode is bezier not bpoint */
+ if (ei->icu->ipo==IPO_BEZ) {
+ bezt_to_transdata(td++, td2d++, bezt->vec[0], bezt->vec[1], 1, onlytime);
+ bezt_to_transdata(td++, td2d++, bezt->vec[2], bezt->vec[1], 1, onlytime);
+ }
+
+ /* always include the main handle */
+ bezt_to_transdata(td++, td2d++, bezt->vec[1], bezt->vec[1], 1, onlytime);
+ }
+ }
+ }
+ }
+ }
+}
+
+/* ------------------------ */
+
+/* struct for use in re-sorting BezTriples during IPO transform */
+typedef struct BeztMap {
+ BezTriple *bezt;
+ int oldIndex;
+ int newIndex;
+} BeztMap;
+
+
+/* This function converts an IpoCurve's BezTriple array to a BeztMap array
+ * NOTE: this allocates memory that will need to get freed later
+ */
+static BeztMap *bezt_to_beztmaps (BezTriple *bezts, int totvert)
+{
+ BezTriple *bezt= bezts;
+ BeztMap *bezm, *bezms;
+ int i;
+
+ /* allocate memory for this array */
+ if (totvert==0 || bezts==NULL)
+ return NULL;
+ bezm= bezms= MEM_callocN(sizeof(BeztMap)*totvert, "BeztMaps");
+
+ /* assign beztriples to beztmaps */
+ for (i=0; i < totvert; i++, bezm++, bezt++) {
+ bezm->bezt= bezt;
+ bezm->oldIndex= i;
+ bezm->newIndex= i;
+ }
+
+ return bezms;
+}
+
+/* This function copies the code of sort_time_ipocurve, but acts on BeztMap structs instead */
+static void sort_time_beztmaps (BeztMap *bezms, int totvert)
+{
+ BeztMap *bezm;
+ int i, ok= 1;
+
+ /* keep repeating the process until nothing is out of place anymore */
+ while (ok) {
+ ok= 0;
+
+ bezm= bezms;
+ i= totvert;
+ while (i--) {
+ /* is current bezm out of order (i.e. occurs later than next)? */
+ if (i > 0) {
+ if ( bezm->bezt->vec[1][0] > (bezm+1)->bezt->vec[1][0]) {
+ bezm->newIndex++;
+ (bezm+1)->newIndex--;
+
+ SWAP(BeztMap, *bezm, *(bezm+1));
+
+ ok= 1;
+ }
+ }
+
+ bezm++;
+ }
+ }
+}
+
+/* This function firstly adjusts the pointers that the transdata has to each BezTriple*/
+static void beztmap_to_data (TransInfo *t, EditIpo *ei, BeztMap *bezms, int totvert)
+{
+ BezTriple *bezts = ei->icu->bezt;
+ BeztMap *bezm;
+ TransData2D *td;
+ int i, j;
+ char *adjusted;
+
+ /* dynamically allocate an array of chars to mark whether an TransData's
+ * pointers have been fixed already, so that we don't override ones that are
+ * already done (assumes sizeof(char)==1)
+ */
+ adjusted= MEM_callocN(t->total, "beztmap_adjusted_map");
+
+ /* for each beztmap item, find if it is used anywhere */
+ bezm= bezms;
+ for (i= 0; i < totvert; i++, bezm++) {
+ /* loop through transdata, testing if we have a hit */
+ td= t->data2d;
+ for (j= 0; j < t->total; j++, td++) {
+ /* skip item if already marked */
+ if (adjusted[j] != 0) continue;
+
+ if (totipo_vertsel) {
+ /* only selected verts */
+ if (ei->icu->ipo==IPO_BEZ) {
+ if (bezm->bezt->f1 & 1) {
+ if (td->loc2d == bezm->bezt->vec[0]) {
+ td->loc2d= (bezts + bezm->newIndex)->vec[0];
+ adjusted[j] = 1;
+ break;
+ }
+ }
+ if (bezm->bezt->f3 & 1) {
+ if (td->loc2d == bezm->bezt->vec[2]) {
+ td->loc2d= (bezts + bezm->newIndex)->vec[2];
+ adjusted[j] = 1;
+ break;
+ }
+ }
+ }
+ if (bezm->bezt->f2 & 1) {
+ if (td->loc2d == bezm->bezt->vec[1]) {
+ td->loc2d= (bezts + bezm->newIndex)->vec[1];
+ adjusted[j] = 1;
+ break;
+ }
+ }
+ }
+ else {
+ /* whole curve */
+ if (ei->icu->ipo==IPO_BEZ) {
+ if (td->loc2d == bezm->bezt->vec[0]) {
+ td->loc2d= (bezts + bezm->newIndex)->vec[0];
+ adjusted[j] = 1;
+ break;
+ }
+
+ if (td->loc2d == bezm->bezt->vec[2]) {
+ td->loc2d= (bezts + bezm->newIndex)->vec[2];
+ adjusted[j] = 1;
+ break;
+ }
+ }
+ if (td->loc2d == bezm->bezt->vec[1]) {
+ td->loc2d= (bezts + bezm->newIndex)->vec[1];
+ adjusted[j] = 1;
+ break;
+ }
+ }
+ }
+
+ }
+
+ /* free temp memory used for 'adjusted' array */
+ MEM_freeN(adjusted);
+}
+
+/* This function is called by recalcData during the Transform loop to recalculate
+ * the handles of curves and sort the keyframes so that the curves draw correctly.
+ * It is only called if some keyframes have moved out of order.
+ */
+void remake_ipo_transdata (TransInfo *t)
+{
+ EditIpo *ei;
+ int a;
+
+ /* sort and reassign verts */
+ ei= G.sipo->editipo;
+ for (a=0; a<G.sipo->totipo; a++, ei++) {
+ if (ISPOIN(ei, flag & IPO_VISIBLE, icu)) {
+ if (ei->icu->bezt) {
+ BeztMap *bezm;
+
+ /* adjust transform-data pointers */
+ bezm= bezt_to_beztmaps(ei->icu->bezt, ei->icu->totvert);
+ sort_time_beztmaps(bezm, ei->icu->totvert);
+ beztmap_to_data(t, ei, bezm, ei->icu->totvert);
+
+ /* re-sort actual beztriples (perhaps this could be done using the beztmaps to save time?) */
+ sort_time_ipocurve(ei->icu);
+
+ /* free mapping stuff */
+ MEM_freeN(bezm);
+
+ /* make sure handles are all set correctly */
+ testhandles_ipocurve(ei->icu);
+ }
+ }
+ }
+
+ /* remake ipokeys */
+ if (G.sipo->showkey) make_ipokey();
+}
+
+/* This function acts as the entrypoint for transforms in the IPO editor (as for
+ * the Action and NLA editors). The actual transform loop is not here anymore.
+ */
+void transform_ipo (int mode)
+{
+ short tmode;
+
+ /* data-validation */
+ if (G.sipo->ipo && G.sipo->ipo->id.lib) return;
+ if (G.sipo->editipo==0) return;
+
+ /* convert ascii-based mode to transform system constants (mode) */
+ switch (mode) {
+ case 'g':
+ tmode= TFM_TRANSLATION;
+ break;
+ case 'r':
+ tmode= TFM_ROTATION;
+ break;
+ case 's':
+ tmode= TFM_RESIZE;
+ break;
+ default:
+ tmode= 0;
+ return;
+ }
+
+ /* the transform system method involved depends on the selection */
+ get_status_editipo();
+ if (totipo_vertsel) {
+ /* we're probably in editmode, so only selected verts - transform system */
+ initTransform(tmode, CTX_NONE);
+ Transform();
+ }
+ else if (totipo_edit==0 && totipo_sel!=0) {
+ /* we're not in editmode, so entire curves get moved - transform system*/
+ initTransform(tmode, CTX_NONE);
+ Transform();
+ }
+ else {
+ /* shapekey mode? special transform code */
+ if (totipo_edit==0)
+ move_keys(OBACT);
+ return;
+ }
+
+ /* cleanup */
+ editipo_changed(G.sipo, 1);
+}
+
+/**************************************************/
+
+void filter_sampledata(float *data, int sfra, int efra)
+{
+ float *da;
+ int a;
+
+ da= data+1;
+ for(a=sfra+1; a<efra; a++, da++) {
+ da[0]=(float)( 0.25*da[-1] + 0.5*da[0] + 0.25*da[1]);
+ }
+
+}
+
+void sampledata_to_ipocurve(float *data, int sfra, int efra, IpoCurve *icu)
+{
+ BezTriple *bezt;
+ float *da;
+ int a, tot;
+
+ filter_sampledata(data, sfra, efra);
+ filter_sampledata(data, sfra, efra);
+
+ icu->ipo= IPO_LIN;
+
+ if(icu->bezt) MEM_freeN(icu->bezt);
+ icu->bezt= NULL;
+
+ tot= 1; /* first point */
+ da= data+1;
+ for(a=sfra+1; a<efra; a++, da++) {
+ if( IS_EQ(da[0], da[1])==0 && IS_EQ(da[1], da[2])==0 ) tot++;
+ }
+
+ icu->totvert= tot;
+ bezt= icu->bezt= MEM_callocN(tot*sizeof(BezTriple), "samplebezt");
+ bezt->vec[1][0]= (float)sfra;
+ bezt->vec[1][1]= data[0];
+ bezt++;
+ da= data+1;
+ for(a=sfra+1; a<efra; a++, da++) {
+ if( IS_EQ(da[0], da[1])==0 && IS_EQ(da[1], da[2])==0 ) {
+ bezt->vec[1][0]= (float)a;
+ bezt->vec[1][1]= da[0];
+ bezt++;
+ }
+ }
+}
+
+void ipo_record(void)
+{
+ /* only 1 or 2 active curves
+ * make a copy (ESC)
+ *
+ * reference point is the current situation (or 0)
+ * dx (dy) is the height correction factor
+ * CTRL: start record
+ */
+ extern double tottime;
+ EditIpo *ei, *ei1=0, *ei2=0;
+ ScrArea *sa, *oldarea;
+// Ipo *ipo;
+ Object *ob;
+ void *poin;
+ double swaptime;
+ float or1, or2 = 0.0, fac, *data1, *data2;
+ int type, a, afbreek=0, firsttime=1, cfrao, cfra, sfra, efra;
+ unsigned short event = 0;
+ short anim, val, xn, yn, mvalo[2], mval[2];
+ char str[128];
+
+ if(G.sipo->from==NULL) return;
+ if(SFRA>=EFRA) return;
+
+ anim= pupmenu("Record Mouse %t|Still %x1|Play Animation %x2");
+ if(anim < 1) return;
+ if(anim!=2) anim= 0;
+
+ ob= OBACT;
+ /* find the curves... */
+
+ ei= G.sipo->editipo;
+ for(a=0; a<G.sipo->totipo; a++) {
+ if(ei->flag & IPO_VISIBLE) {
+
+ if(ei1==0) ei1= ei;
+ else if(ei2==0) ei2= ei;
+ else {
+ error("Maximum 2 visible curves");
+ return;
+ }
+ }
+ ei++;
+ }
+
+ if(ei1==0) {
+ error("Select 1 or 2 channels");
+ return;
+ }
+
+ /* make curves ready, start values */
+ if(ei1->icu==NULL)
+ ei1->icu= verify_ipocurve(G.sipo->from, G.sipo->blocktype, G.sipo->actname, G.sipo->constname, ei1->adrcode);
+ if(ei1->icu==NULL) return;
+
+ poin= get_ipo_poin(G.sipo->from, ei1->icu, &type);
+ if(poin) ei1->icu->curval= read_ipo_poin(poin, type);
+ or1= ei1->icu->curval;
+ ei1->icu->flag |= IPO_LOCK;
+
+ if(ei2) {
+ if(ei2->icu==NULL)
+ ei2->icu= verify_ipocurve(G.sipo->from, G.sipo->blocktype, G.sipo->actname, G.sipo->constname, ei2->adrcode);
+ if(ei2->icu==NULL) return;
+
+ poin= get_ipo_poin(G.sipo->from, ei2->icu, &type);
+ if(poin) ei2->icu->curval= read_ipo_poin(poin, type);
+ or2= ei2->icu->curval;
+ ei2->icu->flag |= IPO_LOCK;
+ }
+ fac= G.v2d->cur.ymax - G.v2d->cur.ymin;
+ fac/= (float)curarea->winy;
+
+ /* which area */
+ oldarea= curarea;
+ sa= G.curscreen->areabase.first;
+ while(sa) {
+ if(sa->win) {
+ if(G.sipo->blocktype==ID_MA || G.sipo->blocktype==ID_LA) {
+ if(sa->spacetype==SPACE_BUTS) break;
+ }
+ else {
+ if(sa->spacetype==SPACE_VIEW3D) break;
+ }
+ }
+ sa= sa->next;
+ }
+ if(sa) areawinset(sa->win);
+
+ /* can we? */
+ while(get_mbut()&L_MOUSE) BIF_wait_for_statechange();
+ data1= MEM_callocN(sizeof(float)*(EFRA-SFRA+1), "data1");
+ data2= MEM_callocN(sizeof(float)*(EFRA-SFRA+1), "data2");
+
+ getmouseco_areawin(mvalo);
+ xn= mvalo[0]; yn= mvalo[1];
+ waitcursor(1);
+
+ tottime= 0.0;
+ swaptime= 1.0/FPS;
+
+ cfrao= CFRA;
+ cfra=efra= SFRA;
+ sfra= EFRA;
+
+ while(afbreek==0) {
+
+ getmouseco_areawin(mval);
+
+ if(mval[0]!= mvalo[0] || mval[1]!=mvalo[1] || firsttime || (G.qual & LR_CTRLKEY)) {
+ if(anim) CFRA= cfra;
+ else firsttime= 0;
+
+ set_timecursor(cfra);
+
+ /* do ipo: first all, then the specific ones */
+ if(anim==2) {
+ do_ob_ipo(ob);
+ do_ob_key(ob);
+ }
+
+ ei1->icu->curval= or1 + fac*(mval[0]-xn);
+ if(ei2) ei2->icu->curval= or2 + fac*(mval[1]-yn);
+
+ do_ipo_nocalc(G.sipo->ipo);
+
+ if(G.qual & LR_CTRLKEY) {
+ sprintf(str, "Recording... %d\n", cfra);
+ data1[ cfra-SFRA ]= ei1->icu->curval;
+ if(ei2) data2[ cfra-SFRA ]= ei2->icu->curval;
+
+ sfra= MIN2(sfra, cfra);
+ efra= MAX2(efra, cfra);
+ }
+ else sprintf(str, "Mouse Recording. Use Ctrl to start. LeftMouse or Space to end");
+
+ do_ob_key(ob);
+ ob->recalc |= OB_RECALC;
+
+ headerprint(str);
+
+ if(sa) scrarea_do_windraw(sa);
+
+ /* minimal wait swaptime */
+ tottime -= swaptime;
+ while (update_time()) PIL_sleep_ms(1);
+
+ screen_swapbuffers();
+
+ tottime= 0.0;
+
+ mvalo[0]= mval[0];
+ mvalo[1]= mval[1];
+
+ if(anim || (G.qual & LR_CTRLKEY)) {
+ cfra++;
+ if(cfra>EFRA) cfra= SFRA;
+ }
+ }
+
+ while(qtest()) {
+ event= extern_qread(&val);
+ if(val) {
+ switch(event) {
+ case LEFTMOUSE: case ESCKEY: case SPACEKEY: case RETKEY:
+ afbreek= 1;
+ break;
+ }
+ }
+ if(afbreek) break;
+ }
+ }
+
+ if(event!=ESCKEY) {
+ sampledata_to_ipocurve(data1+sfra-SFRA, sfra, efra, ei1->icu);
+ if(ei2) sampledata_to_ipocurve(data2+sfra-SFRA, sfra, efra, ei2->icu);
+
+ /* not nice when this is on */
+ if(G.sipo->showkey) {
+ G.sipo->showkey= 0;
+ free_ipokey(&G.sipo->ipokey);
+ }
+ }
+ else {
+ /* undo: start values */
+ poin= get_ipo_poin(G.sipo->from, ei1->icu, &type);
+ if(poin) write_ipo_poin(poin, type, or1);
+ if(ei1->icu->bezt==NULL) {
+ BLI_remlink( &(G.sipo->ipo->curve), ei1->icu);
+ MEM_freeN(ei1->icu);
+ ei1->icu= NULL;
+ }
+ if(ei2) {
+ poin= get_ipo_poin(G.sipo->from, ei2->icu, &type);
+ if(poin) write_ipo_poin(poin, type, or2);
+ if(ei2->icu->bezt==NULL) {
+ BLI_remlink( &(G.sipo->ipo->curve), ei2->icu);
+ MEM_freeN(ei2->icu);
+ ei2->icu= NULL;
+ }
+ }
+ }
+
+ if(ei1->icu) ei1->icu->flag &= ~IPO_LOCK;
+ if(ei2 && ei2->icu) ei2->icu->flag &= ~IPO_LOCK;
+
+ editipo_changed(G.sipo, 0);
+ do_ipo(G.sipo->ipo);
+ waitcursor(0);
+
+ allqueue(REDRAWVIEW3D, 0);
+ if(sa) scrarea_queue_headredraw(sa); /* headerprint */
+ scrarea_queue_redraw(oldarea);
+ CFRA= cfrao;
+
+ /* for the time being? */
+ update_for_newframe();
+ BIF_undo_push("Ipo Record");
+
+ MEM_freeN(data1);
+ MEM_freeN(data2);
+}
+
+/* while transform, update for curves */
+void remake_object_ipos(Object *ob)
+{
+ IpoCurve *icu;
+
+ if (!ob)
+ return;
+ if (!ob->ipo)
+ return;
+
+ for (icu = ob->ipo->curve.first; icu; icu=icu->next){
+ sort_time_ipocurve(icu);
+ testhandles_ipocurve(icu);
+ }
+}
+
+/* Only delete the nominated keyframe from provided ipo-curve.
+ * Not recommended to be used many times successively. For that
+ * there is delete_ipo_keys(). */
+void delete_icu_key(IpoCurve *icu, int index)
+{
+ /* firstly check that index is valid */
+ if (index < 0)
+ index *= -1;
+ if (index >= icu->totvert)
+ return;
+ if (!icu) return;
+
+ /* Delete this key */
+ memcpy (&icu->bezt[index], &icu->bezt[index+1], sizeof (BezTriple)*(icu->totvert-index-1));
+ icu->totvert--;
+
+ /* recalc handles */
+ calchandles_ipocurve(icu);
+}
+
+void delete_ipo_keys(Ipo *ipo)
+{
+ IpoCurve *icu, *next;
+ int i;
+
+ if (!ipo)
+ return;
+
+ for (icu=ipo->curve.first; icu; icu=next){
+ next = icu->next;
+ for (i=0; i<icu->totvert; i++){
+ if (icu->bezt[i].f2 & 1){
+ // Delete the item
+ memcpy (&icu->bezt[i], &icu->bezt[i+1], sizeof (BezTriple)*(icu->totvert-i-1));
+ icu->totvert--;
+ i--;
+ }
+ }
+ if (!icu->totvert){
+ /* Delete the curve */
+ BLI_remlink( &(ipo->curve), icu);
+ free_ipo_curve(icu);
+ }
+ }
+}
+
+
+int add_trans_ipo_keys(Ipo *ipo, TransVert *tv, int tvtot)
+{
+ int i;
+ IpoCurve *icu;
+
+ if (!ipo)
+ return tvtot;
+
+ for (icu=ipo->curve.first; icu; icu=icu->next){
+ for (i=0; i<icu->totvert; i++){
+ if (icu->bezt[i].f2 & 1){
+ tv[tvtot+0].loc=icu->bezt[i].vec[0];
+ tv[tvtot+1].loc=icu->bezt[i].vec[1];
+ tv[tvtot+2].loc=icu->bezt[i].vec[2];
+
+ memcpy (&tv[tvtot+0].oldloc, icu->bezt[i].vec[0], sizeof (float)*3);
+ memcpy (&tv[tvtot+1].oldloc, icu->bezt[i].vec[1], sizeof (float)*3);
+ memcpy (&tv[tvtot+2].oldloc, icu->bezt[i].vec[2], sizeof (float)*3);
+ tvtot+=3;
+ }
+ }
+ }
+
+ return tvtot;
+}
+
+void duplicate_ipo_keys(Ipo *ipo)
+{
+ IpoCurve *icu;
+ int i;
+ BezTriple *newbezt;
+
+ if (!ipo)
+ return;
+
+ for (icu=ipo->curve.first; icu; icu=icu->next){
+ for (i=0; i<icu->totvert; i++){
+ /* If a key is selected */
+ if (icu->bezt[i].f2 & 1){
+ /* Expand the list */
+ newbezt = MEM_callocN(sizeof(BezTriple) * (icu->totvert+1), "beztriple");
+ memcpy (newbezt, icu->bezt, sizeof(BezTriple) * (i+1));
+ memcpy (newbezt+i+1, icu->bezt+i, sizeof(BezTriple));
+ memcpy (newbezt+i+2, icu->bezt+i+1, sizeof (BezTriple) *(icu->totvert-(i+1)));
+ icu->totvert++;
+ MEM_freeN (icu->bezt);
+ icu->bezt=newbezt;
+ /* Unselect the current key*/
+ icu->bezt[i].f1 &= ~ 1;
+ icu->bezt[i].f2 &= ~ 1;
+ icu->bezt[i].f3 &= ~ 1;
+ i++;
+ /* Select the copied key */
+ icu->bezt[i].f1 |= 1;
+ icu->bezt[i].f2 |= 1;
+ icu->bezt[i].f3 |= 1;
+
+ }
+ }
+ }
+}
+
+void move_to_frame(void)
+{
+ EditIpo *ei;
+ BezTriple *bezt;
+ ID *id;
+ float cfra;
+ int a, b;
+
+ if(G.sipo->editipo==0) return;
+
+ ei= G.sipo->editipo;
+
+ for(a=0; a<G.sipo->totipo; a++, ei++) {
+ if (ISPOIN(ei, flag & IPO_VISIBLE, icu)) {
+ if(G.sipo->showkey || (ei->flag & IPO_EDIT)) {
+
+ if(ei->icu->bezt) {
+
+ b= ei->icu->totvert;
+ bezt= ei->icu->bezt;
+ while(b--) {
+ if(BEZSELECTED(bezt)) {
+
+ cfra= bezt->vec[1][0]/G.scene->r.framelen;
+
+ id= G.sipo->from;
+ if(id && GS(id->name)==ID_OB ) {
+ Object *ob= (Object *)id;
+ if(ob->sf!=0.0 && (ob->ipoflag & OB_OFFS_OB) ) {
+ cfra+= ob->sf/G.scene->r.framelen;
+ }
+ }
+ CFRA= (int)floor(cfra+0.5);
+
+ if(CFRA < 1) CFRA= 1;
+ update_for_newframe();
+
+ break;
+ }
+ bezt++;
+ }
+ }
+ }
+ }
+ }
+ BIF_undo_push("Set frame to selected Ipo vertex");
+}
diff --git a/source/blender/src/editipo_lib.c b/source/blender/src/editipo_lib.c
new file mode 100644
index 00000000000..f10e100df7d
--- /dev/null
+++ b/source/blender/src/editipo_lib.c
@@ -0,0 +1,390 @@
+/**
+ * $Id:
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation, 2005. Full recode
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/* ********** General calls (minimal dependencies) for editing Ipos in Blender ************* */
+
+#include <stdio.h>
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "DNA_curve_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_key_types.h"
+#include "DNA_object_types.h"
+#include "DNA_space_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_global.h"
+#include "BKE_ipo.h"
+#include "BKE_key.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_resources.h"
+
+#include "BSE_edit.h"
+#include "BSE_editipo_types.h"
+#include "BSE_editipo.h"
+#include "BSE_drawipo.h"
+
+#include "blendef.h"
+#include "mydevice.h"
+
+char *ob_ic_names[OB_TOTNAM] = { "LocX", "LocY", "LocZ", "dLocX", "dLocY", "dLocZ",
+ "RotX", "RotY", "RotZ", "dRotX", "dRotY", "dRotZ",
+ "ScaleX", "ScaleY", "ScaleZ", "dScaleX", "dScaleY", "dScaleZ",
+ "Layer", "Time", "ColR", "ColG", "ColB", "ColA",
+ "FStreng", "FFall", "RDamp", "Damping", "Perm" };
+
+char *co_ic_names[CO_TOTNAM] = { "Inf" };
+char *mtex_ic_names[TEX_TOTNAM] = { "OfsX", "OfsY", "OfsZ", "SizeX", "SizeY", "SizeZ",
+ "texR", "texG", "texB", "DefVar", "Col", "Nor", "Var",
+ "Disp" };
+char *tex_ic_names[TE_TOTNAM] = { "NSize", "NDepth", "NType", "Turb", "Vnw1", "Vnw2",
+ "Vnw3", "Vnw4", "MinkMExp", "DistM", "ColT", "iScale",
+ "DistA", "MgType", "MgH", "Lacu", "Oct", "MgOff",
+ "MgGain", "NBase1", "NBase2", "ColR", "ColG", "ColB", "Bright", "Contras"};
+char *ma_ic_names[MA_TOTNAM] = { "R", "G", "B", "SpecR", "SpecG", "SpecB", "MirR",
+ "MirG", "MirB", "Ref", "Alpha", "Emit", "Amb", "Spec",
+ "Hard", "SpTra", "Ior", "Mode", "HaSize", "Translu",
+ "RayMir", "FresMir", "FresMirI", "FresTra", "FresTraI",
+ "TraGlow" };
+char *seq_ic_names[SEQ_TOTNAM] = { "Fac" };
+char *cu_ic_names[CU_TOTNAM] = { "Speed" };
+char *key_ic_names[KEY_TOTNAM] = { "Speed", "Key 1", "Key 2", "Key 3", "Key 4", "Key 5",
+ "Key 6", "Key 7", "Key 8", "Key 9", "Key 10",
+ "Key 11", "Key 12", "Key 13", "Key 14", "Key 15",
+ "Key 16", "Key 17", "Key 18", "Key 19", "Key 20",
+ "Key 21", "Key 22", "Key 23", "Key 24", "Key 25",
+ "Key 26", "Key 27", "Key 28", "Key 29", "Key 30",
+ "Key 31", "Key 32", "Key 33", "Key 34", "Key 35",
+ "Key 36", "Key 37", "Key 38", "Key 39", "Key 40",
+ "Key 41", "Key 42", "Key 43", "Key 44", "Key 45",
+ "Key 46", "Key 47", "Key 48", "Key 49", "Key 50",
+ "Key 51", "Key 52", "Key 53", "Key 54", "Key 55",
+ "Key 56", "Key 57", "Key 58", "Key 59", "Key 60",
+ "Key 61", "Key 62", "Key 63"};
+char *wo_ic_names[WO_TOTNAM] = { "HorR", "HorG", "HorB", "ZenR", "ZenG", "ZenB", "Expos",
+ "Misi", "MisDi", "MisSta", "MisHi", "StarR", "StarB",
+ "StarG", "StarDi", "StarSi" };
+char *la_ic_names[LA_TOTNAM] = { "Energ", "R", "G", "B", "Dist", "SpoSi", "SpoBl",
+ "Quad1", "Quad2", "HaInt" };
+/* yafray: two curve names added, 'Apert' for aperture, and 'FDist' for focal distance */
+char *cam_ic_names[CAM_TOTNAM] = { "Lens", "ClSta", "ClEnd", "Apert", "FDist", "ShiftX", "ShiftY" };
+char *snd_ic_names[SND_TOTNAM] = { "Vol", "Pitch", "Pan", "Atten" };
+char *ac_ic_names[AC_TOTNAM] = {"LocX", "LocY", "LocZ", "ScaleX", "ScaleY",
+ "ScaleZ", "QuatW", "QuatX", "QuatY", "QuatZ"};
+char *ic_name_empty[1] ={ "" };
+char *fluidsim_ic_names[FLUIDSIM_TOTNAM] = { "Fac-Visc", "Fac-Time", "GravX","GravY","GravZ", "VelX","VelY","VelZ", "Active" };
+
+/* gets the appropriate icon for the given blocktype */
+int geticon_ipo_blocktype(short blocktype)
+{
+ switch (blocktype) {
+ case ID_OB:
+ return ICON_OBJECT;
+ case ID_PO:
+ return ICON_POSE_HLT;
+ case ID_KE:
+ return ICON_EDIT;
+ case ID_MA:
+ return ICON_MATERIAL;
+ case ID_WO:
+ return ICON_WORLD;
+ case ID_CU:
+ return ICON_CURVE;
+ case ID_CA:
+ return ICON_CAMERA;
+ case ID_LA:
+ return ICON_LAMP;
+ case ID_TE:
+ return ICON_TEXTURE;
+ case ID_CO:
+ return ICON_CONSTRAINT;
+ case ID_FLUIDSIM:
+ return ICON_WORLD; // uggh
+ default:
+ return 0; // what about blank icon?
+ }
+}
+
+/* get name of ipo-curve
+ * - icu should be valid pointer
+ * - ob is only needed for a shapekey-related hack
+ */
+char *getname_ipocurve(IpoCurve *icu, Object *ob)
+{
+ switch (icu->blocktype) {
+ case ID_OB:
+ return getname_ob_ei(icu->adrcode, 0); /* dummy 2nd arg */
+ case ID_PO:
+ return getname_ac_ei(icu->adrcode);
+ case ID_KE:
+ {
+ static char name[32];
+ Key *key= ob_get_key(ob);
+ KeyBlock *kb= key_get_keyblock(key, icu->adrcode);
+
+ /* only return name if it has been set, otherwise use
+ * default method using static string (Key #)
+ */
+ if ((kb) && (kb->name[0] != '\0'))
+ return kb->name; /* return keyblock's name */
+
+ /* in case keyblock is not named or no key/keyblock was found */
+ sprintf(name, "Key %d", icu->adrcode);
+ return name;
+ }
+
+ default: /* fixme - add all of the other types! */
+ return NULL;
+ }
+}
+
+char *getname_ac_ei(int nr)
+{
+ switch(nr) {
+ case AC_LOC_X:
+ case AC_LOC_Y:
+ case AC_LOC_Z:
+ return ac_ic_names[nr-1];
+ case AC_SIZE_X:
+ case AC_SIZE_Y:
+ case AC_SIZE_Z:
+ return ac_ic_names[nr-10];
+ case AC_QUAT_X:
+ case AC_QUAT_Y:
+ case AC_QUAT_Z:
+ case AC_QUAT_W:
+ return ac_ic_names[nr-19];
+ default:
+ return ic_name_empty[0]; /* empty */
+ }
+}
+
+char *getname_co_ei(int nr)
+{
+ switch(nr){
+ case CO_ENFORCE:
+ return co_ic_names[nr-1];
+ }
+ return ic_name_empty[0];
+}
+
+char *getname_ob_ei(int nr, int colipo)
+{
+ if(nr>=OB_LOC_X && nr <= OB_PD_PERM) return ob_ic_names[nr-1];
+
+ return ic_name_empty[0];
+}
+
+char *getname_tex_ei(int nr)
+{
+ if(nr>=TE_NSIZE && nr<=TE_CONTRA) return tex_ic_names[nr-1];
+
+ return ic_name_empty[0];
+}
+
+char *getname_mtex_ei(int nr)
+{
+ if(nr>=MAP_OFS_X && nr<=MAP_DISP) return mtex_ic_names[nr-1];
+
+ return ic_name_empty[0];
+}
+
+char *getname_mat_ei(int nr)
+{
+ if(nr>=MA_MAP1) return getname_mtex_ei((nr & (MA_MAP1-1)));
+ else {
+ if(nr>=MA_COL_R && nr<=MA_ADD) return ma_ic_names[nr-1];
+ }
+ return ic_name_empty[0];
+}
+
+char *getname_world_ei(int nr)
+{
+ if(nr>=MA_MAP1) return getname_mtex_ei((nr & (MA_MAP1-1)));
+ else {
+ if(nr>=WO_HOR_R && nr<=WO_STARSIZE) return wo_ic_names[nr-1];
+ }
+ return ic_name_empty[0];
+}
+
+char *getname_seq_ei(int nr)
+{
+ if(nr == SEQ_FAC1) return seq_ic_names[nr-1];
+ return ic_name_empty[0];
+}
+
+char *getname_cu_ei(int nr)
+{
+ if(nr==CU_SPEED) return cu_ic_names[nr-1];
+ return ic_name_empty[0];
+}
+
+char *getname_la_ei(int nr)
+{
+ if(nr>=MA_MAP1) return getname_mtex_ei((nr & (MA_MAP1-1)));
+ else {
+ if(nr>=LA_ENERGY && nr<=LA_HALOINT) return la_ic_names[nr-1];
+ }
+ return ic_name_empty[0];
+}
+
+char *getname_cam_ei(int nr)
+{
+ if(nr>=CAM_LENS && nr<=CAM_SHIFT_Y) return cam_ic_names[nr-1];
+ return ic_name_empty[0];
+}
+
+char *getname_snd_ei(int nr)
+{
+ if(nr>=SND_VOLUME && nr<=SND_ATTEN) return snd_ic_names[nr-1];
+ return ic_name_empty[0];
+}
+
+char *getname_fluidsim_ei(int nr)
+{
+ if(nr <= FLUIDSIM_TOTIPO) return fluidsim_ic_names[nr-1];
+ return ic_name_empty[0];
+}
+
+
+void boundbox_ipocurve(IpoCurve *icu, int selectedonly)
+{
+ BezTriple *bezt;
+ float vec[3]={0.0,0.0,0.0};
+ float min[3], max[3];
+ int a;
+
+ if(icu->totvert) {
+ INIT_MINMAX(min, max);
+
+ if(icu->bezt ) {
+ a= icu->totvert;
+ bezt= icu->bezt;
+ while(a--) {
+ if(icu->vartype & IPO_BITS) {
+ if((bezt->f2 & 1) || !selectedonly) {
+ vec[0]= bezt->vec[1][0];
+ vec[1]= 0.0;
+ DO_MINMAX(vec, min, max);
+
+ vec[1]= 16.0;
+ DO_MINMAX(vec, min, max);
+ }
+ }
+ else {
+ if((bezt->f1 & 1) || !selectedonly) {
+ if(icu->ipo==IPO_BEZ && a!=icu->totvert-1)
+ DO_MINMAX(bezt->vec[0], min, max);
+ }
+ if((bezt->f2 & 1) || !selectedonly)
+ DO_MINMAX(bezt->vec[1], min, max);
+ if((bezt->f3 & 1) || !selectedonly) {
+ if(icu->ipo==IPO_BEZ && a!=0)
+ DO_MINMAX(bezt->vec[2], min, max);
+ }
+ }
+
+ bezt++;
+ }
+ }
+ if(min[0]==max[0]) max[0]= (float)(min[0]+1.0);
+ if(min[1]==max[1]) max[1]= (float)(min[1]+0.1);
+
+ icu->totrct.xmin= min[0];
+ icu->totrct.ymin= min[1];
+ icu->totrct.xmax= max[0];
+ icu->totrct.ymax= max[1];
+ }
+ else {
+ icu->totrct.xmin= icu->totrct.ymin= 0.0;
+ icu->totrct.xmax= EFRA;
+ icu->totrct.ymax= 1.0;
+ }
+}
+
+void boundbox_ipo(Ipo *ipo, rctf *bb, int selectedonly)
+{
+ IpoCurve *icu;
+ int first= 1;
+
+ icu= ipo->curve.first;
+ while(icu) {
+
+ boundbox_ipocurve(icu, selectedonly);
+
+ if(first) {
+ *bb= icu->totrct;
+ first= 0;
+ }
+ else BLI_union_rctf(bb, &(icu->totrct));
+
+ icu= icu->next;
+ }
+}
+
+
+unsigned int ipo_rainbow(int cur, int tot)
+{
+ float dfac, fac, sat;
+
+ dfac= (float)(1.0/( (float)tot+1.0));
+
+ /* this calculation makes 2 or 4 different cycles of rainbow colors */
+ if(cur< tot/2) fac= (float)(cur*2.0f*dfac);
+ else fac= (float)((cur-tot/2)*2.0f*dfac +dfac);
+ if(tot > 32) fac= fac*1.95f;
+ if(fac>1.0f) fac-= 1.0f;
+
+ if(fac>0.5f && fac<0.8f) sat= 0.4f;
+ else sat= 0.5f;
+
+ return hsv_to_cpack(fac, sat, 1.0f);
+}
+
+/* exported to python, hrms... (ton) */
+int texchannel_to_adrcode(int channel)
+{
+ switch(channel) {
+ case 0: return MA_MAP1;
+ case 1: return MA_MAP2;
+ case 2: return MA_MAP3;
+ case 3: return MA_MAP4;
+ case 4: return MA_MAP5;
+ case 5: return MA_MAP6;
+ case 6: return MA_MAP7;
+ case 7: return MA_MAP8;
+ case 8: return MA_MAP9;
+ case 9: return MA_MAP10;
+ default: return 0;
+ }
+}
+
+
diff --git a/source/blender/src/editipo_mods.c b/source/blender/src/editipo_mods.c
new file mode 100644
index 00000000000..c0fea15ac88
--- /dev/null
+++ b/source/blender/src/editipo_mods.c
@@ -0,0 +1,1356 @@
+/**
+ * $Id:
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation, 2005. Full recode
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+
+/* ********** Selection and set Handle code for editing Ipos in Blender ************* */
+/*
+ mouse_select_ipo() is in editipo.c
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#ifndef WIN32
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "DNA_curve_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_key_types.h"
+#include "DNA_object_types.h"
+#include "DNA_space_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_global.h"
+#include "BKE_action.h"
+#include "BKE_ipo.h"
+#include "BKE_key.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_editaction.h"
+#include "BIF_interface.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_toolbox.h"
+
+#include "BSE_edit.h"
+#include "BSE_editipo_types.h"
+#include "BSE_editipo.h"
+#include "BSE_drawipo.h"
+#include "BSE_trans_types.h"
+#include "BSE_time.h"
+
+#include "BDR_drawobject.h"
+
+#include "blendef.h"
+#include "mydevice.h"
+
+extern int totipo_edit, totipo_sel, totipo_vertsel, totipo_vis;
+
+void ipo_toggle_showkey(void)
+{
+ if(G.sipo->showkey) G.sipo->showkey= 0;
+ else G.sipo->showkey= 1;
+
+ free_ipokey(&G.sipo->ipokey);
+ if(G.sipo->ipo) G.sipo->ipo->showkey= G.sipo->showkey;
+
+ BIF_undo_push("Toggle Show Key Ipo");
+}
+
+void swap_selectall_editipo(void)
+{
+ Object *ob;
+ EditIpo *ei;
+ IpoKey *ik;
+ BezTriple *bezt;
+ int a, b; /* , sel=0; */
+
+ get_status_editipo();
+
+ if(G.sipo->showkey) {
+ ik= G.sipo->ipokey.first;
+ while(ik) {
+ if(totipo_vertsel) ik->flag &= ~1;
+ else ik->flag |= 1;
+ ik= ik->next;
+ }
+ update_editipo_flags();
+
+ if(G.sipo->showkey && G.sipo->blocktype==ID_OB ) {
+ ob= OBACT;
+ if(ob && (ob->ipoflag & OB_DRAWKEY)) draw_object_ext(BASACT);
+ }
+ }
+ else if(totipo_edit==0) {
+ ei= G.sipo->editipo;
+ if (ei){
+ for(a=0; a<G.sipo->totipo; a++) {
+ if( ei->flag & IPO_VISIBLE ) {
+ if(totipo_sel) ei->flag &= ~IPO_SELECT;
+ else ei->flag |= IPO_SELECT;
+ }
+ ei++;
+ }
+ update_editipo_flags();
+ }
+ get_status_editipo();
+ }
+ else {
+ ei= G.sipo->editipo;
+ for(a=0; a<G.sipo->totipo; a++) {
+ if (ISPOIN3(ei, flag & IPO_VISIBLE, flag & IPO_EDIT, icu )) {
+ bezt= ei->icu->bezt;
+ if(bezt) {
+ b= ei->icu->totvert;
+ while(b--) {
+ if(totipo_vertsel) {
+ bezt->f1= bezt->f2= bezt->f3= 0;
+ }
+ else {
+ bezt->f1= bezt->f2= bezt->f3= 1;
+ }
+ bezt++;
+ }
+ }
+ }
+ ei++;
+ }
+
+ }
+
+ BIF_undo_push("Swap Select All Ipo");
+ scrarea_queue_winredraw(curarea);
+
+}
+
+void swap_visible_editipo(void)
+{
+ EditIpo *ei;
+ Object *ob;
+ int a; /* , sel=0; */
+
+ get_status_editipo();
+
+
+ ei= G.sipo->editipo;
+ for(a=0; a<G.sipo->totipo; a++) {
+ if(totipo_vis==0) {
+ if(ei->icu) {
+ ei->flag |= IPO_VISIBLE;
+ ei->flag |= IPO_SELECT;
+ }
+ }
+ else
+ ei->flag &= ~IPO_VISIBLE;
+ ei++;
+ }
+
+ update_editipo_flags();
+
+ if(G.sipo->showkey) {
+
+ make_ipokey();
+
+ ob= OBACT;
+ if(ob && (ob->ipoflag & OB_DRAWKEY)) allqueue(REDRAWVIEW3D, 0);
+ }
+
+ scrarea_queue_winredraw(curarea);
+ BIF_undo_push("Swap Visible Ipo");
+}
+
+void deselectall_editipo(void)
+{
+ EditIpo *ei;
+ IpoKey *ik;
+ BezTriple *bezt;
+ int a, b; /* , sel=0; */
+
+ get_status_editipo();
+
+ if(G.sipo->showkey) {
+ ik= G.sipo->ipokey.first;
+ while(ik) {
+ ik->flag &= ~1;
+ ik= ik->next;
+ }
+ update_editipo_flags();
+
+ }
+ else if(totipo_edit==0) {
+
+ ei= G.sipo->editipo;
+ for(a=0; a<G.sipo->totipo; a++) {
+ if( ei->flag & IPO_VISIBLE ) {
+ ei->flag &= ~IPO_SELECT;
+ }
+ ei++;
+ }
+ update_editipo_flags();
+ }
+ else {
+ ei= G.sipo->editipo;
+ for(a=0; a<G.sipo->totipo; a++) {
+ if (ISPOIN3(ei, flag & IPO_VISIBLE, flag & IPO_EDIT, icu )) {
+ if(ei->icu->bezt) {
+ bezt= ei->icu->bezt;
+ b= ei->icu->totvert;
+ while(b--) {
+ bezt->f1= bezt->f2= bezt->f3= 0;
+ bezt++;
+ }
+ }
+ }
+ ei++;
+ }
+ }
+
+ BIF_undo_push("(De)select all Ipo");
+ scrarea_queue_winredraw(curarea);
+}
+
+
+static int icu_keys_bezier_loop(IpoCurve *icu,
+ int (*bezier_function)(BezTriple *),
+ void (ipocurve_function)(struct IpoCurve *icu))
+{
+ /* This loops through the beziers in the Ipocurve, and executes
+ * the generic user provided 'bezier_function' on each one.
+ * Optionally executes the generic function ipocurve_function on the
+ * IPO curve after looping (eg. calchandles_ipocurve)
+ */
+
+ int b;
+ BezTriple *bezt;
+
+ b = icu->totvert;
+ bezt = icu->bezt;
+
+ /* if bezier_function has been specified
+ * then loop through each bezier executing
+ * it.
+ */
+
+ if (bezier_function != NULL) {
+ while(b--) {
+ /* exit with return code 1 if the bezier function
+ * returns 1 (good for when you are only interested
+ * in finding the first bezier that
+ * satisfies a condition).
+ */
+ if (bezier_function(bezt)) return 1;
+ bezt++;
+ }
+ }
+
+ /* if ipocurve_function has been specified
+ * then execute it
+ */
+ if (ipocurve_function != NULL)
+ ipocurve_function(icu);
+
+ return 0;
+
+}
+
+static int ipo_keys_bezier_loop(Ipo *ipo,
+ int (*bezier_function)(BezTriple *),
+ void (ipocurve_function)(struct IpoCurve *icu))
+{
+ /* This loops through the beziers that are attached to
+ * the selected keys on the Ipocurves of the Ipo, and executes
+ * the generic user provided 'bezier_function' on each one.
+ * Optionally executes the generic function ipocurve_function on a
+ * IPO curve after looping (eg. calchandles_ipocurve)
+ */
+
+ IpoCurve *icu;
+
+ if(ipo==NULL) return 0;
+
+ /* Loop through each curve in the Ipo
+ */
+ for (icu=ipo->curve.first; icu; icu=icu->next){
+ if (icu_keys_bezier_loop(icu,bezier_function, ipocurve_function))
+ return 1;
+ }
+
+ return 0;
+}
+
+static int selected_bezier_loop(int (*looptest)(EditIpo *),
+ int (*bezier_function)(BezTriple *),
+ void (ipocurve_function)(struct IpoCurve *icu))
+{
+ /* This loops through the beziers that are attached to
+ * selected keys in editmode in the IPO window, and executes
+ * the generic user-provided 'bezier_function' on each one
+ * that satisfies the 'looptest' function. Optionally executes
+ * the generic function ipocurve_function on a IPO curve
+ * after looping (eg. calchandles_ipocurve)
+ */
+
+ EditIpo *ei;
+ BezTriple *bezt;
+ int a, b;
+
+ /* Get the first Edit Ipo from the selected Ipos
+ */
+ ei= G.sipo->editipo;
+
+ /* Loop throught all of the selected Ipo's
+ */
+ for(a=0; a<G.sipo->totipo; a++, ei++) {
+ /* Do a user provided test on the Edit Ipo
+ * to determine whether we want to process it
+ */
+ if (looptest(ei)) {
+ /* Loop through the selected
+ * beziers on the Edit Ipo
+ */
+ bezt = ei->icu->bezt;
+ b = ei->icu->totvert;
+
+ /* if bezier_function has been specified
+ * then loop through each bezier executing
+ * it.
+ */
+ if (bezier_function != NULL) {
+ while(b--) {
+ /* exit with return code 1 if the bezier function
+ * returns 1 (good for when you are only interested
+ * in finding the first bezier that
+ * satisfies a condition).
+ */
+ if (bezier_function(bezt)) return 1;
+ bezt++;
+ }
+ }
+
+ /* if ipocurve_function has been specified
+ * then execute it
+ */
+ if (ipocurve_function != NULL)
+ ipocurve_function(ei->icu);
+ }
+ /* nufte flourdje zim ploopydu <-- random dutch looking comment ;) */
+ /* looks more like russian to me! (ton) */
+ }
+
+ return 0;
+}
+
+int select_bezier_add(BezTriple *bezt)
+{
+ /* Select the bezier triple */
+ bezt->f1 |= 1;
+ bezt->f2 |= 1;
+ bezt->f3 |= 1;
+ return 0;
+}
+
+int select_bezier_subtract(BezTriple *bezt)
+{
+ /* Deselect the bezier triple */
+ bezt->f1 &= ~1;
+ bezt->f2 &= ~1;
+ bezt->f3 &= ~1;
+ return 0;
+}
+
+int select_bezier_invert(BezTriple *bezt)
+{
+ /* Invert the selection for the bezier triple */
+ bezt->f2 ^= 1;
+ if ( bezt->f2 & 1 ) {
+ bezt->f1 |= 1;
+ bezt->f3 |= 1;
+ }
+ else {
+ bezt->f1 &= ~1;
+ bezt->f3 &= ~1;
+ }
+ return 0;
+}
+
+static int set_bezier_auto(BezTriple *bezt)
+{
+ /* Sets the selected bezier handles to type 'auto'
+ */
+
+ /* is a handle selected? If so
+ * set it to type auto
+ */
+ if(bezt->f1 || bezt->f3) {
+ if(bezt->f1) bezt->h1= 1; /* the secret code for auto */
+ if(bezt->f3) bezt->h2= 1;
+
+ /* if the handles are not of the same type, set them
+ * to type free
+ */
+ if(bezt->h1!=bezt->h2) {
+ if ELEM(bezt->h1, HD_ALIGN, HD_AUTO) bezt->h1= HD_FREE;
+ if ELEM(bezt->h2, HD_ALIGN, HD_AUTO) bezt->h2= HD_FREE;
+ }
+ }
+ return 0;
+}
+
+static int set_bezier_vector(BezTriple *bezt)
+{
+ /* Sets the selected bezier handles to type 'vector'
+ */
+
+ /* is a handle selected? If so
+ * set it to type vector
+ */
+ if(bezt->f1 || bezt->f3) {
+ if(bezt->f1) bezt->h1= 2; /* the code for vector */
+ if(bezt->f3) bezt->h2= 2;
+
+ /* if the handles are not of the same type, set them
+ * to type free
+ */
+ if(bezt->h1!=bezt->h2) {
+ if ELEM(bezt->h1, HD_ALIGN, HD_AUTO) bezt->h1= HD_FREE;
+ if ELEM(bezt->h2, HD_ALIGN, HD_AUTO) bezt->h2= HD_FREE;
+ }
+ }
+ return 0;
+}
+
+static int bezier_isfree(BezTriple *bezt)
+{
+ /* queries whether the handle should be set
+ * to type 'free' (I think)
+ */
+ if(bezt->f1 && bezt->h1) return 1;
+ if(bezt->f3 && bezt->h2) return 1;
+ return 0;
+}
+
+static int set_bezier_free(BezTriple *bezt)
+{
+ /* Sets selected bezier handles to type 'free'
+ */
+ if(bezt->f1) bezt->h1= HD_FREE;
+ if(bezt->f3) bezt->h2= HD_FREE;
+ return 0;
+}
+
+static int set_bezier_align(BezTriple *bezt)
+{
+ /* Sets selected bezier handles to type 'align'
+ */
+ if(bezt->f1) bezt->h1= HD_ALIGN;
+ if(bezt->f3) bezt->h2= HD_ALIGN;
+ return 0;
+}
+
+static int vis_edit_icu_bez(EditIpo *ei)
+{
+ /* A 4 part test for an EditIpo :
+ * is it a) visible
+ * b) in edit mode
+ * c) does it contain an Ipo Curve
+ * d) does that ipo curve have a bezier
+ *
+ * (The reason why I don't just use the macro
+ * is I need a pointer to a function.)
+ */
+ return (ISPOIN4(ei, flag & IPO_VISIBLE, flag & IPO_EDIT, icu, icu->bezt));
+}
+
+void select_ipo_bezier_keys(Ipo *ipo, int selectmode)
+{
+ /* Select all of the beziers in all
+ * of the Ipo curves belonging to the
+ * Ipo, using the selection mode.
+ */
+ switch (selectmode) {
+ case SELECT_ADD:
+ ipo_keys_bezier_loop(ipo, select_bezier_add, NULL);
+ break;
+ case SELECT_SUBTRACT:
+ ipo_keys_bezier_loop(ipo, select_bezier_subtract, NULL);
+ break;
+ case SELECT_INVERT:
+ ipo_keys_bezier_loop(ipo, select_bezier_invert, NULL);
+ break;
+ }
+}
+
+void select_icu_bezier_keys(IpoCurve *icu, int selectmode)
+{
+ /* Select all of the beziers in all
+ * of the Ipo curves belonging to the
+ * Ipo, using the selection mode.
+ */
+ switch (selectmode) {
+ case SELECT_ADD:
+ icu_keys_bezier_loop(icu, select_bezier_add, NULL);
+ break;
+ case SELECT_SUBTRACT:
+ icu_keys_bezier_loop(icu, select_bezier_subtract, NULL);
+ break;
+ case SELECT_INVERT:
+ icu_keys_bezier_loop(icu, select_bezier_invert, NULL);
+ break;
+ }
+}
+
+void sethandles_ipo_keys(Ipo *ipo, int code)
+{
+ /* this function lets you set bezier handles all to
+ * one type for some Ipo's (e.g. with hotkeys through
+ * the action window).
+ */
+
+ /* code==1: set autohandle */
+ /* code==2: set vectorhandle */
+ /* als code==3 (HD_ALIGN) toggelt het, vectorhandles worden HD_FREE */
+
+ switch(code) {
+ case 1:
+ /*** Set to auto ***/
+ ipo_keys_bezier_loop(ipo, set_bezier_auto,
+ calchandles_ipocurve);
+ break;
+ case 2:
+ /*** Set to vector ***/
+ ipo_keys_bezier_loop(ipo, set_bezier_vector,
+ calchandles_ipocurve);
+ break;
+ default:
+ if ( ipo_keys_bezier_loop(ipo, bezier_isfree, NULL) ) {
+ /*** Set to free ***/
+ ipo_keys_bezier_loop(ipo, set_bezier_free,
+ calchandles_ipocurve);
+ }
+ else {
+ /*** Set to align ***/
+ ipo_keys_bezier_loop(ipo, set_bezier_align,
+ calchandles_ipocurve);
+ }
+ break;
+ }
+}
+
+static int snap_bezier_nearest(BezTriple *bezt)
+{
+ if(bezt->f2 & SELECT)
+ bezt->vec[1][0]= (float)(floor(bezt->vec[1][0]+0.5));
+ return 0;
+}
+
+static int snap_bezier_nearestsec(BezTriple *bezt)
+{
+ float secf = FPS;
+ if(bezt->f2 & SELECT)
+ bezt->vec[1][0]= (float)(floor(bezt->vec[1][0]/secf + 0.5f) * secf);
+ return 0;
+}
+
+static int snap_bezier_cframe(BezTriple *bezt)
+{
+ if(bezt->f2 & SELECT)
+ bezt->vec[1][0]= (float)CFRA;
+ return 0;
+}
+
+static int snap_bezier_nearmarker(BezTriple *bezt)
+{
+ if(bezt->f2 & SELECT)
+ bezt->vec[1][0]= (float)find_nearest_marker_time(bezt->vec[1][0]);
+
+ return 0;
+}
+
+void snap_ipo_keys(Ipo *ipo, short snaptype)
+{
+ switch (snaptype) {
+ case 1: /* snap to nearest frame */
+ ipo_keys_bezier_loop(ipo, snap_bezier_nearest, calchandles_ipocurve);
+ break;
+ case 2: /* snap to current frame */
+ ipo_keys_bezier_loop(ipo, snap_bezier_cframe, calchandles_ipocurve);
+ break;
+ case 3: /* snap to nearest marker */
+ ipo_keys_bezier_loop(ipo, snap_bezier_nearmarker, calchandles_ipocurve);
+ break;
+ case 4: /* snap to nearest second */
+ ipo_keys_bezier_loop(ipo, snap_bezier_nearestsec, calchandles_ipocurve);
+ break;
+ default: /* just in case */
+ ipo_keys_bezier_loop(ipo, snap_bezier_nearest, calchandles_ipocurve);
+ break;
+ }
+}
+
+static int mirror_bezier_cframe(BezTriple *bezt)
+{
+ float diff;
+
+ if(bezt->f2 & SELECT) {
+ diff= ((float)CFRA - bezt->vec[1][0]);
+ bezt->vec[1][0]= ((float)CFRA + diff);
+ }
+
+ return 0;
+}
+
+static int mirror_bezier_yaxis(BezTriple *bezt)
+{
+ float diff;
+
+ if(bezt->f2 & SELECT) {
+ diff= (0.0f - bezt->vec[1][0]);
+ bezt->vec[1][0]= (0.0f + diff);
+ }
+
+ return 0;
+}
+
+static int mirror_bezier_xaxis(BezTriple *bezt)
+{
+ float diff;
+
+ if(bezt->f2 & SELECT) {
+ diff= (0.0f - bezt->vec[1][1]);
+ bezt->vec[1][1]= (0.0f + diff);
+ }
+
+ return 0;
+}
+
+static int mirror_bezier_marker(BezTriple *bezt)
+{
+ static TimeMarker *marker;
+ static short initialised = 0;
+ float diff;
+
+ /* In order for this mirror function to work without
+ * any extra arguments being added, we use the case
+ * of bezt==NULL to denote that we should find the
+ * marker to mirror over. The static pointer is safe
+ * to use this way, as it will be set to null after
+ * each cycle in which this is called.
+ */
+
+ if (bezt) {
+ /* mirroring time */
+ if((bezt->f2 & SELECT) && (marker)) {
+ diff= (marker->frame - bezt->vec[1][0]);
+ bezt->vec[1][0]= (marker->frame + diff);
+ }
+ }
+ else {
+ /* initialisation time */
+ if (initialised) {
+ /* reset everything for safety */
+ marker = NULL;
+ initialised = 0;
+ }
+ else {
+ /* try to find a marker */
+ for (marker= G.scene->markers.first; marker; marker=marker->next) {
+ if (marker->flag & SELECT) {
+ initialised = 1;
+ break;
+ }
+ }
+
+ if (initialised == 0)
+ marker = NULL;
+ }
+ }
+
+ return 0;
+}
+
+void mirror_ipo_keys(Ipo *ipo, short mirror_type)
+{
+ switch (mirror_type) {
+ case 1: /* mirror over current frame */
+ ipo_keys_bezier_loop(ipo, mirror_bezier_cframe, calchandles_ipocurve);
+ break;
+ case 2: /* mirror over frame 0 */
+ ipo_keys_bezier_loop(ipo, mirror_bezier_yaxis, calchandles_ipocurve);
+ break;
+ case 3: /* mirror over value 0 */
+ ipo_keys_bezier_loop(ipo, mirror_bezier_xaxis, calchandles_ipocurve);
+ break;
+ case 4: /* mirror over marker */
+ mirror_bezier_marker(NULL);
+ ipo_keys_bezier_loop(ipo, mirror_bezier_marker, calchandles_ipocurve);
+ mirror_bezier_marker(NULL);
+ break;
+ default: /* just in case */
+ ipo_keys_bezier_loop(ipo, mirror_bezier_yaxis, calchandles_ipocurve);
+ break;
+ }
+}
+
+/* currently only used by some action editor tools, but may soon get used by ipo editor */
+/* restore = whether to map points back to ipo-time
+ * only_keys = whether to only adjust the location of the center point of beztriples
+ */
+void actstrip_map_ipo_keys(Object *ob, Ipo *ipo, short restore, short only_keys)
+{
+ IpoCurve *icu;
+ BezTriple *bezt;
+ int a;
+
+ if (ipo==NULL) return;
+
+ /* loop through all ipo curves, adjusting the times of the selected keys */
+ for (icu= ipo->curve.first; icu; icu= icu->next) {
+ for (a=0, bezt=icu->bezt; a<icu->totvert; a++, bezt++) {
+ /* are the times being adjusted for editing, or has editing finished */
+ if (restore) {
+ if (only_keys == 0) {
+ bezt->vec[0][0]= get_action_frame(ob, bezt->vec[0][0]);
+ bezt->vec[2][0]= get_action_frame(ob, bezt->vec[2][0]);
+ }
+ bezt->vec[1][0]= get_action_frame(ob, bezt->vec[1][0]);
+ }
+ else {
+ if (only_keys == 0) {
+ bezt->vec[0][0]= get_action_frame_inv(ob, bezt->vec[0][0]);
+ bezt->vec[2][0]= get_action_frame_inv(ob, bezt->vec[2][0]);
+ }
+ bezt->vec[1][0]= get_action_frame_inv(ob, bezt->vec[1][0]);
+ }
+ }
+ }
+}
+
+static void ipo_curves_auto_horiz(void)
+{
+ EditIpo *ei;
+ int a, set= 1;
+
+ ei= G.sipo->editipo;
+ for(a=0; a<G.sipo->totipo; a++, ei++) {
+ if (ISPOIN3(ei, flag & IPO_VISIBLE, flag & IPO_SELECT, icu))
+ if(ei->flag & IPO_AUTO_HORIZ) set= 0;
+ }
+
+ ei= G.sipo->editipo;
+ for(a=0; a<G.sipo->totipo; a++, ei++) {
+ if (ISPOIN3(ei, flag & IPO_VISIBLE, flag & IPO_SELECT, icu)) {
+ if(set) ei->flag |= IPO_AUTO_HORIZ;
+ else ei->flag &= ~IPO_AUTO_HORIZ;
+ }
+ }
+ update_editipo_flags();
+}
+
+void sethandles_ipo(int code)
+{
+ /* this function lets you set bezier handles all to
+ * one type for some selected keys in edit mode in the
+ * IPO window (e.g. with hotkeys)
+ */
+
+ /* code==1: set autohandle */
+ /* code==2: set vectorhandle */
+ /* als code==3 (HD_ALIGN) toggelt het, vectorhandles worden HD_FREE */
+
+ if(G.sipo->ipo && G.sipo->ipo->id.lib) return;
+
+ switch(code) {
+ case HD_AUTO:
+ /*** Set to auto ***/
+ selected_bezier_loop(vis_edit_icu_bez, set_bezier_auto,
+ calchandles_ipocurve);
+ break;
+ case HD_VECT:
+ /*** Set to vector ***/
+ selected_bezier_loop(vis_edit_icu_bez, set_bezier_vector,
+ calchandles_ipocurve);
+ break;
+ case HD_AUTO_ANIM:
+ /* set to enforce autohandles to be horizontal on extremes */
+ ipo_curves_auto_horiz();
+
+ break;
+ default:
+ if (selected_bezier_loop(vis_edit_icu_bez, bezier_isfree, NULL) ) {
+ /*** Set to free ***/
+ selected_bezier_loop(vis_edit_icu_bez, set_bezier_free,
+ calchandles_ipocurve);
+ }
+ else {
+ /*** Set to align ***/
+ selected_bezier_loop(vis_edit_icu_bez, set_bezier_align,
+ calchandles_ipocurve);
+ }
+ break;
+ }
+
+ editipo_changed(G.sipo, 1);
+ BIF_undo_push("Set handles Ipo");
+}
+
+
+static void set_ipocurve_constant(struct IpoCurve *icu) {
+ /* Sets the type of the IPO curve to constant
+ */
+ icu->ipo= IPO_CONST;
+}
+
+static void set_ipocurve_linear(struct IpoCurve *icu) {
+ /* Sets the type of the IPO curve to linear
+ */
+ icu->ipo= IPO_LIN;
+}
+
+static void set_ipocurve_bezier(struct IpoCurve *icu) {
+ /* Sets the type of the IPO curve to bezier
+ */
+
+ /* dont regenerate hendels for bezier ipo curves */
+ if (icu->ipo==IPO_BEZ) return;
+
+ /* curve handels aren't generated for non bezier curve types */
+ icu->ipo= IPO_BEZ;
+ calchandles_ipocurve(icu);
+}
+
+
+void setipotype_ipo(Ipo *ipo, int code)
+{
+ /* Sets the type of the each ipo curve in the
+ * Ipo to a value based on the code
+ */
+ switch (code) {
+ case 1:
+ ipo_keys_bezier_loop(ipo, NULL, set_ipocurve_constant);
+ break;
+ case 2:
+ ipo_keys_bezier_loop(ipo, NULL, set_ipocurve_linear);
+ break;
+ case 3:
+ ipo_keys_bezier_loop(ipo, NULL, set_ipocurve_bezier);
+ break;
+ }
+}
+
+void setexprap_ipoloop(Ipo *ipo, int code)
+{
+ IpoCurve *icu;
+
+ /* Loop through each curve in the Ipo */
+ for (icu=ipo->curve.first; icu; icu=icu->next)
+ icu->extrap= code;
+}
+
+void set_ipotype(void)
+{
+ EditIpo *ei;
+ int a;
+ short event;
+
+ if(G.sipo->ipo && G.sipo->ipo->id.lib) return;
+ if(G.sipo->showkey) return;
+ get_status_editipo();
+
+ if(G.sipo->blocktype==ID_KE && totipo_edit==0 && totipo_sel==0) {
+ Key *key= ob_get_key((Object *)G.sipo->from);
+ Object *ob= OBACT;
+ KeyBlock *kb;
+
+ if(key==NULL) return;
+ kb= BLI_findlink(&key->block, ob->shapenr-1);
+ if(kb==NULL) return;
+
+ event= pupmenu("Key Type %t|Linear %x1|Cardinal %x2|B Spline %x3");
+ if(event < 1) return;
+
+ kb->type= 0;
+ if(event==1) kb->type= KEY_LINEAR;
+ if(event==2) kb->type= KEY_CARDINAL;
+ if(event==3) kb->type= KEY_BSPLINE;
+ }
+ else {
+ event= pupmenu("Ipo Type %t|Constant %x1|Linear %x2|Bezier %x3");
+ if(event < 1) return;
+
+ ei= G.sipo->editipo;
+ for(a=0; a<G.sipo->totipo; a++, ei++) {
+ if (ISPOIN3(ei, flag & IPO_VISIBLE, flag & IPO_SELECT, icu)) {
+ if(event==1) ei->icu->ipo= IPO_CONST;
+ else if(event==2) ei->icu->ipo= IPO_LIN;
+ else ei->icu->ipo= IPO_BEZ;
+ }
+ }
+ }
+ BIF_undo_push("Set ipo type");
+ scrarea_queue_winredraw(curarea);
+}
+
+void borderselect_ipo(void)
+{
+ EditIpo *ei;
+ IpoKey *ik;
+ BezTriple *bezt;
+ rcti rect;
+ rctf rectf;
+ int a, b, val;
+ short mval[2];
+
+ get_status_editipo();
+
+ val= get_border(&rect, 3);
+
+ if(val) {
+ /* map ipo-points for editing if scaled ipo */
+ if (NLA_IPO_SCALED) {
+ actstrip_map_ipo_keys(OBACT, G.sipo->ipo, 0, 0);
+ }
+
+ mval[0]= rect.xmin;
+ mval[1]= rect.ymin;
+ areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
+ mval[0]= rect.xmax;
+ mval[1]= rect.ymax;
+ areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
+
+ if(G.sipo->showkey) {
+ ik= G.sipo->ipokey.first;
+ while(ik) {
+ if(rectf.xmin<ik->val && rectf.xmax>ik->val) {
+ if(val==LEFTMOUSE) ik->flag |= 1;
+ else ik->flag &= ~1;
+ }
+ ik= ik->next;
+ }
+ update_editipo_flags();
+ }
+ else if(totipo_edit==0) {
+ if(rect.xmin<rect.xmax && rect.ymin<rect.ymax)
+ select_proj_ipo(&rectf, val);
+ }
+ else {
+
+ ei= G.sipo->editipo;
+ for(a=0; a<G.sipo->totipo; a++, ei++) {
+ if (ISPOIN3(ei, flag & IPO_VISIBLE, flag & IPO_EDIT, icu)) {
+ if(ei->icu->bezt) {
+ b= ei->icu->totvert;
+ bezt= ei->icu->bezt;
+ while(b--) {
+ int bit= (val==LEFTMOUSE);
+
+ if(BLI_in_rctf(&rectf, bezt->vec[0][0], bezt->vec[0][1]))
+ bezt->f1 = (bezt->f1&~1) | bit;
+ if(BLI_in_rctf(&rectf, bezt->vec[1][0], bezt->vec[1][1]))
+ bezt->f2 = (bezt->f2&~1) | bit;
+ if(BLI_in_rctf(&rectf, bezt->vec[2][0], bezt->vec[2][1]))
+ bezt->f3 = (bezt->f3&~1) | bit;
+
+ bezt++;
+ }
+ }
+ }
+ }
+ }
+
+ /* undo mapping of ipo-points for drawing if scaled ipo */
+ if (NLA_IPO_SCALED) {
+ actstrip_map_ipo_keys(OBACT, G.sipo->ipo, 1, 0);
+ }
+
+ BIF_undo_push("Border select Ipo");
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWNLA, 0);
+ }
+}
+
+
+
+void nextkey(ListBase *elems, int dir)
+{
+ IpoKey *ik, *previk;
+ int totsel;
+
+ if(dir==1) ik= elems->last;
+ else ik= elems->first;
+ previk= 0;
+ totsel= 0;
+
+ while(ik) {
+
+ if(ik->flag) totsel++;
+
+ if(previk) {
+ if(G.qual & LR_SHIFTKEY) {
+ if(ik->flag) previk->flag= 1;
+ }
+ else previk->flag= ik->flag;
+ }
+
+ previk= ik;
+ if(dir==1) ik= ik->prev;
+ else ik= ik->next;
+
+ if(G.qual & LR_SHIFTKEY);
+ else if(ik==0) previk->flag= 0;
+ }
+
+ /* when no key select: */
+ if(totsel==0) {
+ if(dir==1) ik= elems->first;
+ else ik= elems->last;
+
+ if(ik) ik->flag= 1;
+ }
+}
+
+
+void nextkey_ipo(int dir) /* call from ipo queue */
+{
+ IpoKey *ik;
+ int a;
+
+ if(G.sipo->showkey==0) return;
+
+ nextkey(&G.sipo->ipokey, dir);
+
+ /* copy to beziers */
+ ik= G.sipo->ipokey.first;
+ while(ik) {
+ for(a=0; a<G.sipo->totipo; a++) {
+ if(ik->data[a]) ik->data[a]->f1= ik->data[a]->f2= ik->data[a]->f3= ik->flag;
+ }
+ ik= ik->next;
+ }
+
+ allqueue(REDRAWNLA, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWIPO, 0);
+ if(G.sipo->blocktype == ID_OB) allqueue(REDRAWVIEW3D, 0);
+}
+
+void nextkey_obipo(int dir) /* only call external from view3d queue */
+{
+ Base *base;
+ Object *ob;
+ ListBase elems;
+ IpoKey *ik;
+ int a;
+
+ if (!G.vd) {
+ error("Can't do this! Open a 3D window");
+ return;
+ }
+
+ /* problem: this doesnt work when you mix dLoc keys with Loc keys */
+
+ base= FIRSTBASE;
+ while(base) {
+ if TESTBASE(base) {
+ ob= base->object;
+ if( (ob->ipoflag & OB_DRAWKEY) && ob->ipo && ob->ipo->showkey) {
+ elems.first= elems.last= 0;
+ make_ipokey_transform(ob, &elems, 0);
+
+ if(elems.first) {
+
+ nextkey(&elems, dir);
+
+ /* copy to beziers */
+ ik= elems.first;
+ while(ik) {
+ for(a=0; a<OB_TOTIPO; a++) {
+ if(ik->data[a]) ik->data[a]->f1= ik->data[a]->f2= ik->data[a]->f3= ik->flag;
+ }
+ ik= ik->next;
+ }
+
+ free_ipokey(&elems);
+ }
+ }
+ }
+
+ base= base->next;
+ }
+ allqueue(REDRAWNLA, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ allspace(REMAKEIPO, 0);
+ allqueue(REDRAWIPO, 0);
+}
+
+int is_ipo_key_selected(Ipo *ipo)
+{
+ int i;
+ IpoCurve *icu;
+
+ if (!ipo)
+ return 0;
+
+ for (icu=ipo->curve.first; icu; icu=icu->next){
+ for (i=0; i<icu->totvert; i++)
+ if (BEZSELECTED(&icu->bezt[i]))
+ return 1;
+ }
+
+ return 0;
+}
+
+void set_ipo_key_selection(Ipo *ipo, int sel)
+{
+ int i;
+ IpoCurve *icu;
+
+ if (!ipo)
+ return;
+
+ for (icu=ipo->curve.first; icu; icu=icu->next){
+ for (i=0; i<icu->totvert; i++){
+ if (sel == 2) {
+ icu->bezt[i].f1^=1;
+ icu->bezt[i].f2^=1;
+ icu->bezt[i].f3^=1;
+ }
+ else if (sel == 1){
+ icu->bezt[i].f1|=1;
+ icu->bezt[i].f2|=1;
+ icu->bezt[i].f3|=1;
+ }
+ else{
+ icu->bezt[i].f1&=~1;
+ icu->bezt[i].f2&=~1;
+ icu->bezt[i].f3&=~1;
+ }
+ }
+ }
+}
+
+int fullselect_ipo_keys(Ipo *ipo)
+{
+ int i;
+ IpoCurve *icu;
+ int tvtot = 0;
+
+ if (!ipo)
+ return tvtot;
+
+ for (icu=ipo->curve.first; icu; icu=icu->next) {
+ for (i=0; i<icu->totvert; i++){
+ if (icu->bezt[i].f2 & 1){
+ tvtot+=3;
+ icu->bezt[i].f1 |= 1;
+ icu->bezt[i].f3 |= 1;
+ }
+ }
+ }
+
+ return tvtot;
+}
+
+
+void borderselect_icu_key(IpoCurve *icu, float xmin, float xmax,
+ int (*select_function)(BezTriple *))
+{
+ /* Selects all bezier triples in the Ipocurve
+ * between times xmin and xmax, using the selection
+ * function.
+ */
+
+ int i;
+
+ /* loop through all of the bezier triples in
+ * the Ipocurve -- if the triple occurs between
+ * times xmin and xmax then select it using the selection
+ * function
+ */
+ for (i=0; i<icu->totvert; i++){
+ if (icu->bezt[i].vec[1][0] > xmin && icu->bezt[i].vec[1][0] < xmax ){
+ select_function(&(icu->bezt[i]));
+ }
+ }
+}
+
+void borderselect_ipo_key(Ipo *ipo, float xmin, float xmax, int selectmode)
+{
+ /* Selects all bezier triples in each Ipocurve of the
+ * Ipo between times xmin and xmax, using the selection mode.
+ */
+
+ IpoCurve *icu;
+ int (*select_function)(BezTriple *);
+
+ /* If the ipo is no good then return */
+ if (!ipo)
+ return;
+
+ /* Set the selection function based on the
+ * selection mode.
+ */
+ switch(selectmode) {
+ case SELECT_ADD:
+ select_function = select_bezier_add;
+ break;
+ case SELECT_SUBTRACT:
+ select_function = select_bezier_subtract;
+ break;
+ case SELECT_INVERT:
+ select_function = select_bezier_invert;
+ break;
+ default:
+ return;
+ }
+
+ /* loop through all of the bezier triples in all
+ * of the Ipocurves -- if the triple occurs between
+ * times xmin and xmax then select it using the selection
+ * function
+ */
+ for (icu=ipo->curve.first; icu; icu=icu->next){
+ borderselect_icu_key(icu, xmin, xmax, select_function);
+ }
+}
+
+void select_ipo_key(Ipo *ipo, float selx, int selectmode)
+{
+ /* Selects all bezier triples in each Ipocurve of the
+ * Ipo at time selx, using the selection mode.
+ */
+ int i;
+ IpoCurve *icu;
+ int (*select_function)(BezTriple *);
+
+ /* If the ipo is no good then return */
+ if (!ipo)
+ return;
+
+ /* Set the selection function based on the
+ * selection mode.
+ */
+ switch(selectmode) {
+ case SELECT_ADD:
+ select_function = select_bezier_add;
+ break;
+ case SELECT_SUBTRACT:
+ select_function = select_bezier_subtract;
+ break;
+ case SELECT_INVERT:
+ select_function = select_bezier_invert;
+ break;
+ default:
+ return;
+ }
+
+ /* loop through all of the bezier triples in all
+ * of the Ipocurves -- if the triple occurs at
+ * time selx then select it using the selection
+ * function
+ */
+ for (icu=ipo->curve.first; icu; icu=icu->next){
+ for (i=0; i<icu->totvert; i++){
+ if (icu->bezt[i].vec[1][0]==selx){
+ select_function(&(icu->bezt[i]));
+ }
+ }
+ }
+}
+
+void select_icu_key(IpoCurve *icu, float selx, int selectmode)
+{
+ /* Selects all bezier triples in the Ipocurve
+ * at time selx, using the selection mode.
+ * This is kind of sloppy the obvious similarities
+ * with the above function, forgive me ...
+ */
+ int i;
+ int (*select_function)(BezTriple *);
+
+ /* If the icu is no good then return */
+ if (!icu)
+ return;
+
+ /* Set the selection function based on the
+ * selection mode.
+ */
+ switch(selectmode) {
+ case SELECT_ADD:
+ select_function = select_bezier_add;
+ break;
+ case SELECT_SUBTRACT:
+ select_function = select_bezier_subtract;
+ break;
+ case SELECT_INVERT:
+ select_function = select_bezier_invert;
+ break;
+ default:
+ return;
+ }
+
+ /* loop through all of the bezier triples in
+ * the Ipocurve -- if the triple occurs at
+ * time selx then select it using the selection
+ * function
+ */
+ for (i=0; i<icu->totvert; i++){
+ if (icu->bezt[i].vec[1][0]==selx){
+ select_function(&(icu->bezt[i]));
+ }
+ }
+}
+
+void set_exprap_ipo(int mode)
+{
+ EditIpo *ei;
+ int a;
+
+ if(G.sipo->ipo && G.sipo->ipo->id.lib) return;
+ /* in case of keys: always ok */
+
+ ei= G.sipo->editipo;
+ for(a=0; a<G.sipo->totipo; a++, ei++) {
+ if (ISPOIN(ei, flag & IPO_VISIBLE, icu)) {
+ if( (ei->flag & IPO_EDIT) || (ei->flag & IPO_SELECT) || (G.sipo->showkey) ) {
+ ei->icu->extrap= mode;
+ }
+ }
+ }
+
+ editipo_changed(G.sipo, 1);
+ BIF_undo_push("Set extrapolation Ipo");
+}
diff --git a/source/blender/src/editkey.c b/source/blender/src/editkey.c
new file mode 100644
index 00000000000..671889d6431
--- /dev/null
+++ b/source/blender/src/editkey.c
@@ -0,0 +1,773 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <math.h>
+#include <string.h>
+
+#ifndef WIN32
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "DNA_action_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_key_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_view2d_types.h"
+
+#include "BKE_action.h"
+#include "BKE_anim.h"
+#include "BKE_curve.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_ipo.h"
+#include "BKE_key.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_editkey.h"
+#include "BIF_editview.h"
+#include "BIF_mywindow.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_toolbox.h"
+#include "BIF_interface.h"
+
+#include "BSE_editipo.h"
+#include "BSE_trans_types.h"
+
+#include "BDR_editobject.h"
+
+#include "blendef.h"
+#include "mydevice.h"
+
+extern ListBase editNurb; /* in editcurve.c */
+
+/* temporary storage for slider values */
+/* pretty bad static stuff... is secured in drawaction.c though */
+float meshslidervals[256] = {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.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, 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.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, 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.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, 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.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, 0.0, 0.0, 0.0, 0.0};
+
+static IpoCurve *get_key_icu(Ipo *ipo, int keynum)
+{
+ /* return the Ipocurve that has the specified
+ * keynum as ardcode -- return NULL if no such
+ * curve exists.
+ */
+ IpoCurve *icu;
+
+ if (!ipo)
+ return NULL;
+
+ for (icu = ipo->curve.first; icu ; icu = icu->next) {
+ if (!icu->adrcode) continue;
+ if (icu->adrcode == keynum) return icu;
+ }
+
+ return NULL;
+}
+
+BezTriple *get_bezt_icu_time(IpoCurve *icu, float *frame, float *val)
+{
+ /* this function tries to find a bezier that is within
+ * 0.25 time units from the specified frame. If there
+ * are more than one such beziers, it returns the
+ * closest one.
+ */
+ int i;
+ float d, dmin = 0.25, newframe;
+ BezTriple *bezt = NULL;
+
+ newframe = *frame;
+
+ for (i=0; i<icu->totvert; i++){
+ d = fabs(icu->bezt[i].vec[1][0] - *frame);
+ if (d < dmin) {
+ dmin = d;
+ newframe = icu->bezt[i].vec[1][0];
+ *val = icu->bezt[i].vec[1][1];
+ bezt = icu->bezt + i;
+ }
+ }
+
+ *frame = newframe;
+ return bezt;
+}
+
+static void rvk_slider_func(void *voidob, void *voidkeynum)
+{
+ /* the callback for the rvk sliders ... copies the
+ * value from the temporary array into a bezier at the
+ * right frame on the right ipo curve (creating both the
+ * ipo curve and the bezier if needed).
+ */
+ Object *ob= voidob;
+ IpoCurve *icu=NULL;
+ BezTriple *bezt=NULL;
+ float cfra, rvkval;
+ int keynum = (long) voidkeynum;
+
+ cfra = frame_to_float(CFRA);
+
+ /* ipo on action or ob? */
+ if(ob->ipoflag & OB_ACTION_KEY)
+ icu = verify_ipocurve(&ob->id, ID_KE, "Shape", NULL, keynum);
+ else
+ icu = verify_ipocurve(&ob->id, ID_KE, NULL, NULL, keynum);
+
+ if (icu) {
+ /* if the ipocurve exists, try to get a bezier
+ * for this frame
+ */
+ bezt = get_bezt_icu_time(icu, &cfra, &rvkval);
+
+ /* create the bezier triple if one doesn't exist,
+ * otherwise modify it's value
+ */
+ if (bezt == NULL) {
+ insert_vert_icu(icu, cfra, meshslidervals[keynum], 0);
+ }
+ else {
+ bezt->vec[1][1] = meshslidervals[keynum];
+ }
+
+ /* make sure the Ipo's are properly process and
+ * redraw as necessary
+ */
+ sort_time_ipocurve(icu);
+ testhandles_ipocurve(icu);
+
+ ob->shapeflag &= ~OB_SHAPE_TEMPLOCK;
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ }
+ else error("Cannot edit this Shape Key");
+
+ allqueue (REDRAWVIEW3D, 0);
+ allqueue (REDRAWACTION, 0);
+ allqueue (REDRAWNLA, 0);
+ allqueue (REDRAWIPO, 0);
+ allspace(REMAKEIPO, 0);
+}
+
+static float getrvkval(Ipo *ipo, int keynum)
+{
+ /* get the value of the rvk from the
+ * ipo curve at the current time -- return 0
+ * if no ipo curve exists
+ */
+ IpoCurve *icu=NULL;
+ BezTriple *bezt=NULL;
+ float rvkval = 0.0;
+ float cfra;
+
+ cfra = frame_to_float(CFRA);
+ icu = get_key_icu(ipo, keynum);
+ if (icu) {
+ bezt = get_bezt_icu_time(icu, &cfra, &rvkval);
+ if (!bezt) {
+ rvkval = eval_icu(icu, cfra);
+ }
+ }
+
+ return rvkval;
+
+}
+
+void make_rvk_slider(uiBlock *block, Object *ob, int keynum,
+ int x, int y, int w, int h, char *tip)
+{
+ /* create a slider for the rvk */
+ uiBut *but;
+ Ipo *ipo= NULL;
+ Key *key= ob_get_key(ob);
+ KeyBlock *kb;
+ float min, max;
+ int i;
+
+ if(key==NULL) return;
+
+ /* ipo on action or ob? */
+ if(ob->ipoflag & OB_ACTION_KEY) {
+ if(ob->action) {
+ bActionChannel *achan;
+
+ achan= get_action_channel(ob->action, "Shape");
+ if(achan) ipo= achan->ipo;
+ }
+ }
+ else ipo= key->ipo;
+
+ /* global array */
+ meshslidervals[keynum] = getrvkval(ipo, keynum);
+
+ kb= key->block.first;
+ for (i=0; i<keynum; ++i) kb = kb->next;
+
+ if ( (kb->slidermin >= kb->slidermax) ) {
+ kb->slidermin = 0.0;
+ kb->slidermax = 1.0;
+ }
+
+ min = (kb->slidermin < meshslidervals[keynum]) ?
+ kb->slidermin: meshslidervals[keynum];
+
+ max = (kb->slidermax > meshslidervals[keynum]) ?
+ kb->slidermax: meshslidervals[keynum];
+
+ but=uiDefButF(block, NUMSLI, REDRAWVIEW3D, "",
+ x, y , w, h,
+ meshslidervals+keynum, min, max, 10, 2, tip);
+
+ uiButSetFunc(but, rvk_slider_func, ob, (void *)(long)keynum);
+ // no hilite, the winmatrix is not correct later on...
+ uiButSetFlag(but, UI_NO_HILITE);
+
+}
+
+static void default_key_ipo(Key *key)
+{
+ IpoCurve *icu;
+ BezTriple *bezt;
+
+ key->ipo= add_ipo("KeyIpo", ID_KE);
+
+ icu= MEM_callocN(sizeof(IpoCurve), "ipocurve");
+
+ icu->blocktype= ID_KE;
+ icu->adrcode= KEY_SPEED;
+ icu->flag= IPO_VISIBLE|IPO_SELECT|IPO_AUTO_HORIZ;
+ set_icu_vars(icu);
+
+ BLI_addtail( &(key->ipo->curve), icu);
+
+ icu->bezt= bezt= MEM_callocN(2*sizeof(BezTriple), "defaultipo");
+ icu->totvert= 2;
+
+ bezt->hide= IPO_BEZ;
+ bezt->f1=bezt->f2= bezt->f3= SELECT;
+ bezt->h1= bezt->h2= HD_AUTO;
+ bezt++;
+ bezt->vec[1][0]= 100.0;
+ bezt->vec[1][1]= 1.0;
+ bezt->hide= IPO_BEZ;
+ bezt->f1=bezt->f2= bezt->f3= SELECT;
+ bezt->h1= bezt->h2= HD_AUTO;
+
+ calchandles_ipocurve(icu);
+}
+
+
+
+/* **************************************** */
+
+void mesh_to_key(Mesh *me, KeyBlock *kb)
+{
+ MVert *mvert;
+ float *fp;
+ int a;
+
+ if(me->totvert==0) return;
+
+ if(kb->data) MEM_freeN(kb->data);
+
+ kb->data= MEM_callocN(me->key->elemsize*me->totvert, "kb->data");
+ kb->totelem= me->totvert;
+
+ mvert= me->mvert;
+ fp= kb->data;
+ for(a=0; a<kb->totelem; a++, fp+=3, mvert++) {
+ VECCOPY(fp, mvert->co);
+
+ }
+}
+
+void key_to_mesh(KeyBlock *kb, Mesh *me)
+{
+ MVert *mvert;
+ float *fp;
+ int a, tot;
+
+ mvert= me->mvert;
+ fp= kb->data;
+
+ tot= MIN2(kb->totelem, me->totvert);
+
+ for(a=0; a<tot; a++, fp+=3, mvert++) {
+ VECCOPY(mvert->co, fp);
+ }
+}
+
+static KeyBlock *add_keyblock(Key *key)
+{
+ KeyBlock *kb;
+ float curpos= -0.1;
+ int tot;
+
+ kb= key->block.last;
+ if(kb) curpos= kb->pos;
+
+ kb= MEM_callocN(sizeof(KeyBlock), "Keyblock");
+ BLI_addtail(&key->block, kb);
+ kb->type= KEY_CARDINAL;
+ tot= BLI_countlist(&key->block);
+ if(tot==1) strcpy(kb->name, "Basis");
+ else sprintf(kb->name, "Key %d", tot-1);
+ kb->adrcode= tot-1;
+
+ key->totkey++;
+ if(key->totkey==1) key->refkey= kb;
+
+
+ if(key->type == KEY_RELATIVE)
+ kb->pos= curpos+0.1;
+ else {
+ curpos= bsystem_time(0, (float)CFRA, 0.0);
+ if(calc_ipo_spec(key->ipo, KEY_SPEED, &curpos)==0) {
+ curpos /= 100.0;
+ }
+ kb->pos= curpos;
+
+ sort_keys(key);
+ }
+ return kb;
+}
+
+void insert_meshkey(Mesh *me, short rel)
+{
+ Key *key;
+ KeyBlock *kb;
+
+ if(me->key==NULL) {
+ me->key= add_key( (ID *)me);
+
+ if(rel)
+ me->key->type = KEY_RELATIVE;
+ else
+ default_key_ipo(me->key);
+ }
+ key= me->key;
+
+ kb= add_keyblock(key);
+
+ mesh_to_key(me, kb);
+}
+
+/* ******************** */
+
+void latt_to_key(Lattice *lt, KeyBlock *kb)
+{
+ BPoint *bp;
+ float *fp;
+ int a, tot;
+
+ tot= lt->pntsu*lt->pntsv*lt->pntsw;
+ if(tot==0) return;
+
+ if(kb->data) MEM_freeN(kb->data);
+
+ kb->data= MEM_callocN(lt->key->elemsize*tot, "kb->data");
+ kb->totelem= tot;
+
+ bp= lt->def;
+ fp= kb->data;
+ for(a=0; a<kb->totelem; a++, fp+=3, bp++) {
+ VECCOPY(fp, bp->vec);
+ }
+}
+
+void key_to_latt(KeyBlock *kb, Lattice *lt)
+{
+ BPoint *bp;
+ float *fp;
+ int a, tot;
+
+ bp= lt->def;
+ fp= kb->data;
+
+ tot= lt->pntsu*lt->pntsv*lt->pntsw;
+ tot= MIN2(kb->totelem, tot);
+
+ for(a=0; a<tot; a++, fp+=3, bp++) {
+ VECCOPY(bp->vec, fp);
+ }
+
+}
+
+/* exported to python... hrms, should not, use object levels! (ton) */
+void insert_lattkey(Lattice *lt, short rel)
+{
+ Key *key;
+ KeyBlock *kb;
+
+ if(lt->key==NULL) {
+ lt->key= add_key( (ID *)lt);
+ default_key_ipo(lt->key);
+ }
+ key= lt->key;
+
+ kb= add_keyblock(key);
+
+ latt_to_key(lt, kb);
+}
+
+/* ******************************** */
+
+void curve_to_key(Curve *cu, KeyBlock *kb, ListBase *nurb)
+{
+ Nurb *nu;
+ BezTriple *bezt;
+ BPoint *bp;
+ float *fp;
+ int a, tot;
+
+ /* count */
+ tot= count_curveverts(nurb);
+ if(tot==0) return;
+
+ if(kb->data) MEM_freeN(kb->data);
+
+ kb->data= MEM_callocN(cu->key->elemsize*tot, "kb->data");
+ kb->totelem= tot;
+
+ nu= nurb->first;
+ fp= kb->data;
+ while(nu) {
+
+ if(nu->bezt) {
+ bezt= nu->bezt;
+ a= nu->pntsu;
+ while(a--) {
+ VECCOPY(fp, bezt->vec[0]);
+ fp+= 3;
+ VECCOPY(fp, bezt->vec[1]);
+ fp+= 3;
+ VECCOPY(fp, bezt->vec[2]);
+ fp+= 3;
+ fp[0]= bezt->alfa;
+ fp+= 3; /* alphas */
+ bezt++;
+ }
+ }
+ else {
+ bp= nu->bp;
+ a= nu->pntsu*nu->pntsv;
+ while(a--) {
+ VECCOPY(fp, bp->vec);
+ fp[3]= bp->alfa;
+
+ fp+= 4;
+ bp++;
+ }
+ }
+ nu= nu->next;
+ }
+}
+
+void key_to_curve(KeyBlock *kb, Curve *cu, ListBase *nurb)
+{
+ Nurb *nu;
+ BezTriple *bezt;
+ BPoint *bp;
+ float *fp;
+ int a, tot;
+
+ nu= nurb->first;
+ fp= kb->data;
+
+ tot= count_curveverts(nurb);
+
+ tot= MIN2(kb->totelem, tot);
+
+ while(nu && tot>0) {
+
+ if(nu->bezt) {
+ bezt= nu->bezt;
+ a= nu->pntsu;
+ while(a-- && tot>0) {
+ VECCOPY(bezt->vec[0], fp);
+ fp+= 3;
+ VECCOPY(bezt->vec[1], fp);
+ fp+= 3;
+ VECCOPY(bezt->vec[2], fp);
+ fp+= 3;
+ bezt->alfa= fp[0];
+ fp+= 3; /* alphas */
+
+ tot-= 3;
+ bezt++;
+ }
+ }
+ else {
+ bp= nu->bp;
+ a= nu->pntsu*nu->pntsv;
+ while(a-- && tot>0) {
+ VECCOPY(bp->vec, fp);
+ bp->alfa= fp[3];
+
+ fp+= 4;
+ tot--;
+ bp++;
+ }
+ }
+ nu= nu->next;
+ }
+}
+
+
+void insert_curvekey(Curve *cu, short rel)
+{
+ Key *key;
+ KeyBlock *kb;
+
+ if(cu->key==NULL) {
+ cu->key= add_key( (ID *)cu);
+
+ if (rel)
+ cu->key->type = KEY_RELATIVE;
+ else
+ default_key_ipo(cu->key);
+ }
+ key= cu->key;
+
+ kb= add_keyblock(key);
+
+ if(editNurb.first) curve_to_key(cu, kb, &editNurb);
+ else curve_to_key(cu, kb, &cu->nurb);
+}
+
+
+/* ******************** */
+
+void insert_shapekey(Object *ob)
+{
+ if(get_mesh(ob) && get_mesh(ob)->mr) {
+ error("Cannot create shape keys on a multires mesh.");
+ }
+ else {
+ Key *key;
+
+ if(ob->type==OB_MESH) insert_meshkey(ob->data, 1);
+ else if ELEM(ob->type, OB_CURVE, OB_SURF) insert_curvekey(ob->data, 1);
+ else if(ob->type==OB_LATTICE) insert_lattkey(ob->data, 1);
+
+ key= ob_get_key(ob);
+ ob->shapenr= BLI_countlist(&key->block);
+
+ BIF_undo_push("Add Shapekey");
+ allspace(REMAKEIPO, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWNLA, 0);
+ allqueue(REDRAWBUTSOBJECT, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ }
+}
+
+void delete_key(Object *ob)
+{
+ KeyBlock *kb;
+ Key *key;
+ IpoCurve *icu;
+
+ key= ob_get_key(ob);
+ if(key==NULL) return;
+
+ kb= BLI_findlink(&key->block, ob->shapenr-1);
+
+ if(kb) {
+ BLI_remlink(&key->block, kb);
+ key->totkey--;
+ if(key->refkey== kb) key->refkey= key->block.first;
+
+ if(kb->data) MEM_freeN(kb->data);
+ MEM_freeN(kb);
+
+ for(kb= key->block.first; kb; kb= kb->next) {
+ if(kb->adrcode>=ob->shapenr)
+ kb->adrcode--;
+ }
+
+ if(key->ipo) {
+
+ for(icu= key->ipo->curve.first; icu; icu= icu->next) {
+ if(icu->adrcode==ob->shapenr-1) {
+ BLI_remlink(&key->ipo->curve, icu);
+ free_ipo_curve(icu);
+ break;
+ }
+ }
+ for(icu= key->ipo->curve.first; icu; icu= icu->next)
+ if(icu->adrcode>=ob->shapenr)
+ icu->adrcode--;
+ }
+
+ if(ob->shapenr>1) ob->shapenr--;
+ }
+
+ if(key->totkey==0) {
+ if(GS(key->from->name)==ID_ME) ((Mesh *)key->from)->key= NULL;
+ else if(GS(key->from->name)==ID_CU) ((Curve *)key->from)->key= NULL;
+ else if(GS(key->from->name)==ID_LT) ((Lattice *)key->from)->key= NULL;
+
+ free_libblock_us(&(G.main->key), key);
+ scrarea_queue_headredraw(curarea); /* ipo remove too */
+ }
+
+ DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA);
+
+ BIF_undo_push("Delete Shapekey");
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ allspace(REMAKEIPO, 0);
+ allqueue(REDRAWIPO, 0);
+}
+
+void move_keys(Object *ob)
+{
+ Key *key;
+ KeyBlock *kb;
+ float div, dy, oldpos, vec[3], dvec[3];
+ int afbreek=0, firsttime= 1;
+ unsigned short event = 0;
+ short mval[2], val, xo, yo;
+ char str[32];
+
+ if(G.sipo->blocktype!=ID_KE) return;
+
+ if(G.sipo->ipo && G.sipo->ipo->id.lib) return;
+ if(G.sipo->editipo==NULL) return;
+
+ key= ob_get_key(ob);
+ if(key==NULL) return;
+
+ /* which kb is involved */
+ kb= BLI_findlink(&key->block, ob->shapenr-1);
+ if(kb==NULL) return;
+
+ oldpos= kb->pos;
+
+ getmouseco_areawin(mval);
+ xo= mval[0];
+ yo= mval[1];
+ dvec[0]=dvec[1]=dvec[2]= 0.0;
+
+ while(afbreek==0) {
+ getmouseco_areawin(mval);
+ if(mval[0]!=xo || mval[1]!=yo || firsttime) {
+ firsttime= 0;
+
+ dy= (float)(mval[1]- yo);
+
+ div= (float)(G.v2d->mask.ymax-G.v2d->mask.ymin);
+ dvec[1]+= (G.v2d->cur.ymax-G.v2d->cur.ymin)*(dy)/div;
+
+ VECCOPY(vec, dvec);
+
+ apply_keyb_grid(vec, 0.0, 1.0, 0.1, U.flag & USER_AUTOGRABGRID);
+ apply_keyb_grid(vec+1, 0.0, 1.0, 0.1, U.flag & USER_AUTOGRABGRID);
+
+ kb->pos= oldpos+vec[1];
+
+ sprintf(str, "Y: %.3f ", vec[1]);
+ headerprint(str);
+
+ xo= mval[0];
+ yo= mval[1];
+
+ force_draw(0);
+ }
+ else BIF_wait_for_statechange();
+
+ while(qtest()) {
+ event= extern_qread(&val);
+ if(val) {
+ switch(event) {
+ case ESCKEY:
+ case LEFTMOUSE:
+ case SPACEKEY:
+ afbreek= 1;
+ break;
+ default:
+ arrows_move_cursor(event);
+ }
+ }
+ }
+ }
+
+ if(event==ESCKEY) {
+ kb->pos= oldpos;
+ }
+
+ sort_keys(key);
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+
+ /* for boundbox */
+ editipo_changed(G.sipo, 0);
+
+ BIF_undo_push("Move Shapekey(s)");
+ allspace(REMAKEIPO, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ scrarea_queue_redraw(curarea);
+}
diff --git a/source/blender/src/editlattice.c b/source/blender/src/editlattice.c
new file mode 100644
index 00000000000..9aa363a654f
--- /dev/null
+++ b/source/blender/src/editlattice.c
@@ -0,0 +1,327 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * i.t.t. wat de naam doet vermoeden: ook algemene lattice (calc) functies
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "DNA_curve_types.h"
+#include "DNA_key_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_key.h"
+#include "BKE_lattice.h"
+#include "BKE_mesh.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_editlattice.h"
+#include "BIF_editmode_undo.h"
+#include "BIF_editkey.h"
+#include "BIF_space.h"
+#include "BIF_screen.h"
+#include "BIF_toolbox.h"
+
+#include "BSE_edit.h"
+
+#include "BDR_editobject.h"
+#include "BDR_drawobject.h"
+
+#include "blendef.h"
+#include "mydevice.h"
+
+#include "BKE_armature.h"
+
+/* ***************************** */
+
+void free_editLatt(void)
+{
+ if(editLatt) {
+ if(editLatt->def) MEM_freeN(editLatt->def);
+ if(editLatt->dvert)
+ free_dverts(editLatt->dvert, editLatt->pntsu*editLatt->pntsv*editLatt->pntsw);
+
+ MEM_freeN(editLatt);
+ editLatt= NULL;
+ }
+}
+
+
+static void setflagsLatt(int flag)
+{
+ BPoint *bp;
+ int a;
+
+ bp= editLatt->def;
+
+ a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
+
+ while(a--) {
+ if(bp->hide==0) {
+ bp->f1= flag;
+ }
+ bp++;
+ }
+}
+
+
+
+void make_editLatt(void)
+{
+ Lattice *lt;
+ KeyBlock *actkey;
+
+ free_editLatt();
+
+ lt= G.obedit->data;
+
+ actkey = ob_get_keyblock(G.obedit);
+ if(actkey) {
+ strcpy(G.editModeTitleExtra, "(Key) ");
+ key_to_latt(actkey, lt);
+ }
+
+ editLatt= MEM_dupallocN(lt);
+ editLatt->def= MEM_dupallocN(lt->def);
+
+ if(lt->dvert) {
+ int tot= lt->pntsu*lt->pntsv*lt->pntsw;
+ editLatt->dvert = MEM_mallocN (sizeof (MDeformVert)*tot, "Lattice MDeformVert");
+ copy_dverts(editLatt->dvert, lt->dvert, tot);
+ }
+
+ BIF_undo_push("original");
+}
+
+
+void load_editLatt(void)
+{
+ Lattice *lt;
+ KeyBlock *actkey;
+ BPoint *bp;
+ float *fp;
+ int tot;
+
+ lt= G.obedit->data;
+
+ actkey = ob_get_keyblock(G.obedit);
+ if(actkey) {
+ /* active key: vertices */
+ tot= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
+
+ if(actkey->data) MEM_freeN(actkey->data);
+
+ fp=actkey->data= MEM_callocN(lt->key->elemsize*tot, "actkey->data");
+ actkey->totelem= tot;
+
+ bp= editLatt->def;
+ while(tot--) {
+ VECCOPY(fp, bp->vec);
+ fp+= 3;
+ bp++;
+ }
+ }
+ else {
+
+ MEM_freeN(lt->def);
+
+ lt->def= MEM_dupallocN(editLatt->def);
+
+ lt->flag= editLatt->flag;
+
+ lt->pntsu= editLatt->pntsu;
+ lt->pntsv= editLatt->pntsv;
+ lt->pntsw= editLatt->pntsw;
+
+ lt->typeu= editLatt->typeu;
+ lt->typev= editLatt->typev;
+ lt->typew= editLatt->typew;
+ }
+
+ if(lt->dvert) {
+ free_dverts(lt->dvert, lt->pntsu*lt->pntsv*lt->pntsw);
+ lt->dvert= NULL;
+ }
+
+ if(editLatt->dvert) {
+ int tot= lt->pntsu*lt->pntsv*lt->pntsw;
+
+ lt->dvert = MEM_mallocN (sizeof (MDeformVert)*tot, "Lattice MDeformVert");
+ copy_dverts(lt->dvert, editLatt->dvert, tot);
+ }
+
+}
+
+void remake_editLatt(void)
+{
+ if(okee("Reload original data")==0) return;
+
+ make_editLatt();
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+
+ BIF_undo_push("Reload original");
+}
+
+
+void deselectall_Latt(void)
+{
+ BPoint *bp;
+ int a;
+
+ bp= editLatt->def;
+
+ a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
+
+ allqueue(REDRAWVIEW3D, 0);
+
+ while(a--) {
+ if(bp->hide==0) {
+ if(bp->f1) {
+ setflagsLatt(0);
+ countall();
+ BIF_undo_push("(De)select all");
+ return;
+ }
+ }
+ bp++;
+ }
+ setflagsLatt(1);
+ countall();
+ BIF_undo_push("(De)select all");
+}
+
+static void findnearestLattvert__doClosest(void *userData, BPoint *bp, int x, int y)
+{
+ struct { BPoint *bp; short dist, select, mval[2]; } *data = userData;
+ float temp = abs(data->mval[0]-x) + abs(data->mval[1]-y);
+
+ if ((bp->f1&1)==data->select) temp += 5;
+ if (temp<data->dist) {
+ data->dist = temp;
+
+ data->bp = bp;
+ }
+}
+static BPoint *findnearestLattvert(int sel)
+{
+ /* sel==1: selected gets a disadvantage */
+ /* in nurb and bezt or bp the nearest is written */
+ /* return 0 1 2: handlepunt */
+ struct { BPoint *bp; short dist, select, mval[2]; } data = {0};
+
+ data.dist = 100;
+ data.select = sel;
+ getmouseco_areawin(data.mval);
+
+ lattice_foreachScreenVert(findnearestLattvert__doClosest, &data);
+
+ return data.bp;
+}
+
+
+void mouse_lattice(void)
+{
+ BPoint *bp=0;
+
+ bp= findnearestLattvert(1);
+
+ if(bp) {
+ if((G.qual & LR_SHIFTKEY)==0) {
+
+ setflagsLatt(0);
+ bp->f1 |= 1;
+
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ else {
+
+ if(bp->f1 & 1) bp->f1 &= ~1;
+ else bp->f1 |= 1;
+
+ allqueue(REDRAWVIEW3D, 0);
+
+ }
+
+ countall();
+ BIF_undo_push("Select");
+ }
+
+ rightmouse_transform();
+
+}
+
+
+/* **************** undo for lattice object ************** */
+
+static void undoLatt_to_editLatt(void *defv)
+{
+ int a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
+
+ memcpy(editLatt->def, defv, a*sizeof(BPoint));
+}
+
+static void *editLatt_to_undoLatt(void)
+{
+
+ return MEM_dupallocN(editLatt->def);
+}
+
+static void free_undoLatt(void *defv)
+{
+ MEM_freeN(defv);
+}
+
+/* and this is all the undo system needs to know */
+void undo_push_lattice(char *name)
+{
+ undo_editmode_push(name, free_undoLatt, undoLatt_to_editLatt, editLatt_to_undoLatt);
+}
+
+
+
+/***/
diff --git a/source/blender/src/editmball.c b/source/blender/src/editmball.c
new file mode 100644
index 00000000000..06b2e8b5dd7
--- /dev/null
+++ b/source/blender/src/editmball.c
@@ -0,0 +1,533 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <math.h>
+#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_rand.h"
+
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_object.h"
+
+#include "BIF_gl.h"
+#include "BIF_graphics.h"
+#include "BIF_screen.h"
+#include "BIF_toolbox.h"
+#include "BIF_space.h"
+#include "BIF_editmode_undo.h"
+#include "BIF_transform.h"
+
+#include "BDR_editobject.h"
+#include "BDR_editmball.h"
+
+#include "BSE_edit.h"
+#include "BSE_view.h"
+
+#include "blendef.h"
+#include "mydevice.h"
+
+extern short editbutflag;
+
+ListBase editelems= {0, 0};
+MetaElem *lastelem;
+
+/* this function is called, when MetaBall Object is
+ * switched from object mode to edit mode */
+void make_editMball()
+{
+ MetaBall *mb;
+ MetaElem *ml, *newmb;
+
+ BLI_freelistN(&editelems);
+ lastelem= 0;
+
+ mb= G.obedit->data;
+ ml= mb->elems.first;
+
+ while(ml) {
+ newmb= MEM_dupallocN(ml);
+ BLI_addtail(&editelems, newmb);
+ if(ml->flag & SELECT) lastelem= newmb;
+
+ ml= ml->next;
+ }
+
+ allqueue(REDRAWBUTSEDIT, 0);
+
+ countall();
+}
+
+/* this function is called, when MetaBall Object switched from
+ * edit mode to object mode. List od MetaElements is copied
+ * from editelems to to object->data structure (mb->elems) */
+void load_editMball()
+{
+ /* load mball in object */
+ MetaBall *mb;
+ MetaElem *ml, *newml;
+
+ if(G.obedit==NULL) return;
+
+ mb= G.obedit->data;
+ BLI_freelistN(&(mb->elems));
+
+
+ ml= editelems.first;
+ while(ml) {
+ newml= MEM_dupallocN(ml);
+ BLI_addtail(&(mb->elems), newml);
+
+ ml= ml->next;
+ }
+}
+
+/* add new MetaElement primitive */
+void add_primitiveMball(int dummy_argument)
+{
+ MetaElem *ml;
+ float *curs, mat[3][3], cent[3], imat[3][3], cmat[3][3];
+
+ if(G.scene->id.lib) return;
+
+ /* this function also comes from an info window */
+ if ELEM(curarea->spacetype, SPACE_VIEW3D, SPACE_INFO); else return;
+
+ check_editmode(OB_MBALL);
+
+ /* if no obedit: new object and enter editmode */
+ if(G.obedit==NULL) {
+ add_object_draw(OB_MBALL);
+ base_init_from_view3d(BASACT, G.vd);
+ G.obedit= BASACT->object;
+
+ where_is_object(G.obedit); // need now, for imat
+
+ make_editMball();
+ setcursor_space(SPACE_VIEW3D, CURSOR_EDIT);
+ }
+
+ /* deselect */
+ ml= editelems.first;
+ while(ml) {
+ ml->flag &= ~SELECT;
+ ml= ml->next;
+ }
+
+ /* imat and center and size */
+ Mat3CpyMat4(mat, G.obedit->obmat);
+
+ curs= give_cursor();
+ VECCOPY(cent, curs);
+ cent[0]-= G.obedit->obmat[3][0];
+ cent[1]-= G.obedit->obmat[3][1];
+ cent[2]-= G.obedit->obmat[3][2];
+
+ if (G.vd) {
+ Mat3CpyMat4(imat, G.vd->viewmat);
+ Mat3MulVecfl(imat, cent);
+ Mat3MulMat3(cmat, imat, mat);
+ Mat3Inv(imat,cmat);
+
+ Mat3MulVecfl(imat, cent);
+ }
+
+ ml= MEM_callocN(sizeof(MetaElem), "metaelem");
+ BLI_addtail(&editelems, ml);
+
+ ml->x= cent[0];
+ ml->y= cent[1];
+ ml->z= cent[2];
+ ml->quat[0]= 1.0;
+ ml->quat[1]= 0.0;
+ ml->quat[2]= 0.0;
+ ml->quat[3]= 0.0;
+ ml->rad= 2.0;
+ ml->s= 2.0;
+ ml->flag= SELECT | MB_SCALE_RAD;
+
+ switch(dummy_argument) {
+ case 1:
+ ml->type = MB_BALL;
+ ml->expx= ml->expy= ml->expz= 1.0;
+ break;
+ case 2:
+ ml->type = MB_TUBE;
+ ml->expx= ml->expy= ml->expz= 1.0;
+ break;
+ case 3:
+ ml->type = MB_PLANE;
+ ml->expx= ml->expy= ml->expz= 1.0;
+ break;
+ case 4:
+ ml->type = MB_ELIPSOID;
+ ml->expx= 1.2f;
+ ml->expy= 0.8f;
+ ml->expz= 1.0;
+ break;
+ case 5:
+ ml->type = MB_CUBE;
+ ml->expx= ml->expy= ml->expz= 1.0;
+ break;
+ default:
+ break;
+ }
+
+ lastelem= ml;
+
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); // added ball can influence others
+
+ countall();
+ allqueue(REDRAWALL, 0);
+ BIF_undo_push("Add MetaElem");
+}
+
+/* deselect all MetaElements */
+void deselectall_mball()
+{
+ MetaElem *ml;
+ int sel= 0;
+
+ ml= editelems.first;
+ while(ml) {
+ if(ml->flag & SELECT) break;
+ ml= ml->next;
+ }
+
+ if(ml) sel= 1;
+
+ ml= editelems.first;
+ while(ml) {
+ if(sel) ml->flag &= ~SELECT;
+ else ml->flag |= SELECT;
+ ml= ml->next;
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+ countall();
+ BIF_undo_push("Deselect MetaElem");
+}
+
+/* inverts metaball selection */
+void selectinverse_mball()
+{
+ MetaElem *ml;
+
+ ml= editelems.first;
+ while(ml) {
+ if(ml->flag & SELECT) ml->flag &= ~SELECT;
+ else ml->flag |= SELECT;
+ ml= ml->next;
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+ countall();
+ BIF_undo_push("Invert MetaElem");
+}
+
+/* select random metaball selection */
+void selectrandom_mball()
+{
+ MetaElem *ml;
+ static short randfac= 50;
+
+ if(!button(&randfac,0, 100,"Percentage:")) return;
+
+ ml= editelems.first;
+ BLI_srand( BLI_rand() ); /* random seed */
+ while(ml) {
+ if((BLI_frand() * 100) < randfac) ml->flag |= SELECT;
+ ml= ml->next;
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+ countall();
+ BIF_undo_push("Random MetaElem");
+}
+
+/* select MetaElement with mouse click (user can select radius circle or
+ * stiffness circle) */
+void mouse_mball()
+{
+ static MetaElem *startelem=0;
+ MetaElem *ml, *act=0;
+ int a, hits;
+ unsigned int buffer[MAXPICKBUF];
+
+ hits= view3d_opengl_select(buffer, MAXPICKBUF, 0, 0, 0, 0);
+
+ /* does startelem exist? */
+ ml= editelems.first;
+ while(ml) {
+ if(ml==startelem) break;
+ ml= ml->next;
+ }
+ if(ml==NULL) startelem= editelems.first;
+
+ if(hits>0) {
+ ml= startelem;
+ while(ml) {
+
+ for(a=0; a<hits; a++) {
+ /* index converted for gl stuff */
+ if(ml->selcol1==buffer[ 4 * a + 3 ]){
+ ml->flag |= MB_SCALE_RAD;
+ act= ml;
+ }
+ if(ml->selcol2==buffer[ 4 * a + 3 ]){
+ ml->flag &= ~MB_SCALE_RAD;
+ act= ml;
+ }
+
+ }
+
+ if(act) break;
+
+ ml= ml->next;
+ if(ml==NULL) ml= editelems.first;
+ if(ml==startelem) break;
+ }
+ if(act) {
+ if((G.qual & LR_SHIFTKEY)==0) {
+ deselectall_mball();
+ if(act->flag & SELECT) deselectall_mball();
+ act->flag |= SELECT;
+ }
+ else {
+ if(act->flag & SELECT) {
+ act->flag &= ~SELECT;
+ }
+ else act->flag |= SELECT;
+ }
+ lastelem= act;
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ }
+ }
+
+ allqueue(REDRAWBUTSOBJECT, 0);
+ countall();
+ rightmouse_transform();
+}
+
+/* duplicate selected MetaElements */
+void adduplicate_mball()
+{
+ MetaElem *ml, *newml;
+
+ ml= editelems.last;
+ while(ml) {
+ if(ml->flag & SELECT) {
+ newml= MEM_dupallocN(ml);
+ BLI_addtail(&editelems, newml);
+ lastelem= newml;
+ ml->flag &= ~SELECT;
+ }
+ ml= ml->prev;
+ }
+
+ BIF_TransformSetUndo("Add Duplicate");
+ countall();
+ initTransform(TFM_TRANSLATION, CTX_NO_PET);
+ Transform();
+ allqueue(REDRAWBUTSEDIT, 0);
+}
+
+/* Delete all selected MetaElems (not MetaBall) */
+void delete_mball()
+{
+ MetaElem *ml, *next;
+
+ if(okee("Erase selected")==0) return;
+
+ ml= editelems.first;
+ while(ml) {
+ next= ml->next;
+ if(ml->flag & SELECT) {
+ if(lastelem==ml) lastelem= 0;
+ BLI_remlink(&editelems, ml);
+ MEM_freeN(ml);
+ }
+ ml= next;
+ }
+
+ DAG_scene_sort(G.scene);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ countall();
+ BIF_undo_push("Delete MetaElem");
+}
+
+/* free all MetaElems from ListBase */
+void freeMetaElemlist(ListBase *lb)
+{
+ MetaElem *ml, *next;
+
+ if(lb==NULL) return;
+
+ ml= lb->first;
+ while(ml){
+ next= ml->next;
+ BLI_remlink(lb, ml);
+ MEM_freeN(ml);
+ ml= next;
+ }
+
+ lb->first= lb->last= NULL;
+
+}
+
+/* ************* undo for MetaBalls ************* */
+
+static void undoMball_to_editMball(void *lbv)
+{
+ ListBase *lb= lbv;
+ MetaElem *ml, *newml;
+ unsigned int nr, lastmlnr= 0;
+
+ /* we try to restore lastelem, which used in for example in button window */
+ for(ml= editelems.first; ml; ml= ml->next, lastmlnr++)
+ if(lastelem==ml) break;
+
+ freeMetaElemlist(&editelems);
+
+ /* copy 'undo' MetaElems to 'edit' MetaElems */
+ ml= lb->first;
+ while(ml){
+ newml= MEM_dupallocN(ml);
+ BLI_addtail(&editelems, newml);
+ ml= ml->next;
+ }
+
+ for(nr=0, lastelem= editelems.first; lastelem; lastelem= lastelem->next, nr++)
+ if(nr==lastmlnr) break;
+
+ countall();
+}
+
+static void *editMball_to_undoMball(void)
+{
+ ListBase *lb;
+ MetaElem *ml, *newml;
+
+ /* allocate memory for undo ListBase */
+ lb= MEM_callocN(sizeof(ListBase), "listbase undo");
+ lb->first= lb->last= NULL;
+
+ /* copy contents of current ListBase to the undo ListBase */
+ ml= editelems.first;
+ while(ml){
+ newml= MEM_dupallocN(ml);
+ BLI_addtail(lb, newml);
+ ml= ml->next;
+ }
+
+ return lb;
+}
+
+/* free undo ListBase of MetaElems */
+static void free_undoMball(void *lbv)
+{
+ ListBase *lb= lbv;
+
+ freeMetaElemlist(lb);
+ MEM_freeN(lb);
+}
+
+/* this is undo system for MetaBalls */
+void undo_push_mball(char *name)
+{
+ undo_editmode_push(name, free_undoMball, undoMball_to_editMball, editMball_to_undoMball);
+}
+
+/* Hide selected/unselected MetaElems */
+void hide_mball(char hide)
+{
+ MetaElem *ml;
+
+ ml= editelems.first;
+
+ while(ml){
+ if(hide){
+ if(!(ml->flag & SELECT))
+ ml->flag |= MB_HIDE;
+ }
+ else{
+ if(ml->flag & SELECT)
+ ml->flag |= MB_HIDE;
+ }
+ ml= ml->next;
+ }
+
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ countall();
+ BIF_undo_push("Hide MetaElems");
+}
+
+/* Unhide all edited MetaElems */
+void reveal_mball(void)
+{
+ MetaElem *ml;
+
+ ml= editelems.first;
+
+ while(ml){
+ ml->flag &= ~MB_HIDE;
+ ml= ml->next;
+ }
+
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ countall();
+ BIF_undo_push("Unhide MetaElems");
+}
+
diff --git a/source/blender/src/editmesh.c b/source/blender/src/editmesh.c
new file mode 100644
index 00000000000..15f4e652490
--- /dev/null
+++ b/source/blender/src/editmesh.c
@@ -0,0 +1,2205 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "PIL_time.h"
+
+#include "DNA_customdata_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_object_force.h"
+#include "DNA_screen_types.h"
+#include "DNA_key_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_material_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_editVert.h"
+#include "BLI_dynstr.h"
+#include "BLI_rand.h"
+
+#include "BKE_DerivedMesh.h"
+#include "BKE_depsgraph.h"
+#include "BKE_customdata.h"
+#include "BKE_global.h"
+#include "BKE_key.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
+
+#ifdef WITH_VERSE
+#include "BKE_verse.h"
+#endif
+
+#include "BIF_editkey.h"
+#include "BIF_editmesh.h"
+#include "BIF_editmode_undo.h"
+#include "BIF_interface.h"
+#include "BIF_meshtools.h"
+#include "BIF_mywindow.h"
+#include "BIF_retopo.h"
+#include "BIF_space.h"
+#include "BIF_screen.h"
+#include "BIF_toolbox.h"
+
+#ifdef WITH_VERSE
+#include "BIF_verse.h"
+#endif
+
+#include "BSE_view.h"
+#include "BSE_edit.h"
+#include "BSE_trans_types.h"
+
+#include "BDR_drawobject.h"
+#include "BDR_editobject.h"
+#include "BDR_editface.h"
+#include "BDR_vpaint.h"
+
+#include "LBM_fluidsim.h"
+
+#include "multires.h"
+#include "mydevice.h"
+#include "blendef.h"
+
+/* own include */
+#include "editmesh.h"
+
+/*
+
+editmesh.c:
+- add/alloc/free data
+- hashtables
+- enter/exit editmode
+
+*/
+
+
+/* ***************** HASH ********************* */
+
+
+#define EDHASHSIZE (512*512)
+#define EDHASH(a, b) (a % EDHASHSIZE)
+
+
+/* ************ ADD / REMOVE / FIND ****************** */
+
+/* used to bypass normal calloc with fast one */
+static void *(*callocvert)(size_t, size_t) = calloc;
+static void *(*callocedge)(size_t, size_t) = calloc;
+static void *(*callocface)(size_t, size_t) = calloc;
+
+EditVert *addvertlist(float *vec, EditVert *example)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+ static int hashnr= 0;
+
+ eve= callocvert(sizeof(EditVert), 1);
+ BLI_addtail(&em->verts, eve);
+
+ if(vec) VECCOPY(eve->co, vec);
+
+ eve->hash= hashnr++;
+ if( hashnr>=EDHASHSIZE) hashnr= 0;
+
+ /* new verts get keyindex of -1 since they did not
+ * have a pre-editmode vertex order
+ */
+ eve->keyindex = -1;
+#ifdef WITH_VERSE
+ createVerseVert(eve);
+#endif
+
+ if(example)
+ CustomData_em_copy_data(&em->vdata, &em->vdata, example->data, &eve->data);
+ else
+ CustomData_em_set_default(&em->vdata, &eve->data);
+
+ return eve;
+}
+
+void free_editvert (EditVert *eve)
+{
+#ifdef WITH_VERSE
+ if(eve->vvert) {
+ /* it prevents from removing all verse vertexes
+ * during entering edit mode ... messy solution */
+ if(G.editMesh->vnode)
+ b_verse_send_vertex_delete(eve);
+ else
+ ((VerseVert*)eve->vvert)->vertex = NULL;
+ }
+#endif
+
+ EM_remove_selection(eve, EDITVERT);
+ CustomData_em_free_block(&G.editMesh->vdata, &eve->data);
+ if(eve->fast==0)
+ free(eve);
+}
+
+
+EditEdge *findedgelist(EditVert *v1, EditVert *v2)
+{
+ EditVert *v3;
+ struct HashEdge *he;
+
+ /* swap ? */
+ if( v1 > v2) {
+ v3= v2;
+ v2= v1;
+ v1= v3;
+ }
+
+ if(G.editMesh->hashedgetab==NULL)
+ G.editMesh->hashedgetab= MEM_callocN(EDHASHSIZE*sizeof(struct HashEdge), "hashedgetab");
+
+ he= G.editMesh->hashedgetab + EDHASH(v1->hash, v2->hash);
+
+ while(he) {
+
+ if(he->eed && he->eed->v1==v1 && he->eed->v2==v2) return he->eed;
+
+ he= he->next;
+ }
+ return 0;
+}
+
+static void insert_hashedge(EditEdge *eed)
+{
+ /* assuming that eed is not in the list yet, and that a find has been done before */
+
+ struct HashEdge *first, *he;
+
+ first= G.editMesh->hashedgetab + EDHASH(eed->v1->hash, eed->v2->hash);
+
+ if( first->eed==0 ) {
+ first->eed= eed;
+ }
+ else {
+ he= &eed->hash;
+ he->eed= eed;
+ he->next= first->next;
+ first->next= he;
+ }
+}
+
+static void remove_hashedge(EditEdge *eed)
+{
+ /* assuming eed is in the list */
+
+ struct HashEdge *first, *he, *prev=NULL;
+
+ he=first= G.editMesh->hashedgetab + EDHASH(eed->v1->hash, eed->v2->hash);
+
+ while(he) {
+ if(he->eed == eed) {
+ /* remove from list */
+ if(he==first) {
+ if(first->next) {
+ he= first->next;
+ first->eed= he->eed;
+ first->next= he->next;
+ }
+ else he->eed= 0;
+ }
+ else {
+ prev->next= he->next;
+ }
+ return;
+ }
+ prev= he;
+ he= he->next;
+ }
+}
+
+EditEdge *addedgelist(EditVert *v1, EditVert *v2, EditEdge *example)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *v3;
+ EditEdge *eed;
+ int swap= 0;
+
+ if(v1==v2) return NULL;
+ if(v1==NULL || v2==NULL) return NULL;
+
+ /* swap ? */
+ if(v1>v2) {
+ v3= v2;
+ v2= v1;
+ v1= v3;
+ swap= 1;
+ }
+
+ /* find in hashlist */
+ eed= findedgelist(v1, v2);
+
+ if(eed==NULL) {
+
+ eed= (EditEdge *)callocedge(sizeof(EditEdge), 1);
+ eed->v1= v1;
+ eed->v2= v2;
+ BLI_addtail(&em->edges, eed);
+ eed->dir= swap;
+ insert_hashedge(eed);
+
+ /* copy edge data:
+ rule is to do this with addedgelist call, before addfacelist */
+ if(example) {
+ eed->crease= example->crease;
+ eed->sharp = example->sharp;
+ eed->seam = example->seam;
+ eed->h |= (example->h & EM_FGON);
+ }
+ }
+
+ return eed;
+}
+
+void remedge(EditEdge *eed)
+{
+ EditMesh *em = G.editMesh;
+
+ BLI_remlink(&em->edges, eed);
+ remove_hashedge(eed);
+}
+
+void free_editedge(EditEdge *eed)
+{
+ EM_remove_selection(eed, EDITEDGE);
+ if(eed->fast==0){
+ free(eed);
+ }
+}
+
+void free_editface(EditFace *efa)
+{
+#ifdef WITH_VERSE
+ if(efa->vface) {
+ /* it prevents from removing all verse faces
+ * during entering edit mode ... messy solution */
+ if(G.editMesh->vnode)
+ b_verse_send_face_delete(efa);
+ else
+ ((VerseFace*)efa->vface)->face = NULL;
+ }
+#endif
+ EM_remove_selection(efa, EDITFACE);
+
+ if (G.editMesh->act_face==efa)
+ EM_set_actFace(NULL);
+
+ CustomData_em_free_block(&G.editMesh->fdata, &efa->data);
+ if(efa->fast==0)
+ free(efa);
+}
+
+void free_vertlist(ListBase *edve)
+{
+ EditVert *eve, *next;
+
+ if (!edve) return;
+
+ eve= edve->first;
+ while(eve) {
+ next= eve->next;
+ free_editvert(eve);
+ eve= next;
+ }
+ edve->first= edve->last= NULL;
+}
+
+void free_edgelist(ListBase *lb)
+{
+ EditEdge *eed, *next;
+
+ eed= lb->first;
+ while(eed) {
+ next= eed->next;
+ free_editedge(eed);
+ eed= next;
+ }
+ lb->first= lb->last= NULL;
+}
+
+void free_facelist(ListBase *lb)
+{
+ EditFace *efa, *next;
+
+ efa= lb->first;
+ while(efa) {
+ next= efa->next;
+ free_editface(efa);
+ efa= next;
+ }
+ lb->first= lb->last= NULL;
+}
+
+EditFace *addfacelist(EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4, EditFace *example, EditFace *exampleEdges)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+ EditEdge *e1, *e2=0, *e3=0, *e4=0;
+
+ /* added sanity check... seems to happen for some tools, or for enter editmode for corrupted meshes */
+ if(v1==v4 || v2==v4 || v3==v4) v4= NULL;
+
+ /* add face to list and do the edges */
+ if(exampleEdges) {
+ e1= addedgelist(v1, v2, exampleEdges->e1);
+ e2= addedgelist(v2, v3, exampleEdges->e2);
+ if(v4) e3= addedgelist(v3, v4, exampleEdges->e3);
+ else e3= addedgelist(v3, v1, exampleEdges->e3);
+ if(v4) e4= addedgelist(v4, v1, exampleEdges->e4);
+ }
+ else {
+ e1= addedgelist(v1, v2, NULL);
+ e2= addedgelist(v2, v3, NULL);
+ if(v4) e3= addedgelist(v3, v4, NULL);
+ else e3= addedgelist(v3, v1, NULL);
+ if(v4) e4= addedgelist(v4, v1, NULL);
+ }
+
+ if(v1==v2 || v2==v3 || v1==v3) return NULL;
+ if(e2==0) return NULL;
+
+ efa= (EditFace *)callocface(sizeof(EditFace), 1);
+ efa->v1= v1;
+ efa->v2= v2;
+ efa->v3= v3;
+ efa->v4= v4;
+
+ efa->e1= e1;
+ efa->e2= e2;
+ efa->e3= e3;
+ efa->e4= e4;
+
+ if(example) {
+ efa->mat_nr= example->mat_nr;
+ efa->flag= example->flag;
+ CustomData_em_copy_data(&em->fdata, &em->fdata, example->data, &efa->data);
+ }
+ else {
+ if (G.obedit && G.obedit->actcol)
+ efa->mat_nr= G.obedit->actcol-1;
+
+ CustomData_em_set_default(&em->fdata, &efa->data);
+ }
+
+ BLI_addtail(&em->faces, efa);
+
+ if(efa->v4) {
+ CalcNormFloat4(efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co, efa->n);
+ CalcCent4f(efa->cent, efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co);
+ }
+ else {
+ CalcNormFloat(efa->v1->co, efa->v2->co, efa->v3->co, efa->n);
+ CalcCent3f(efa->cent, efa->v1->co, efa->v2->co, efa->v3->co);
+ }
+
+#ifdef WITH_VERSE
+ createVerseFace(efa);
+#endif
+
+ return efa;
+}
+
+/* ************************ end add/new/find ************ */
+
+/* ************************ Edit{Vert,Edge,Face} utilss ***************************** */
+
+/* some nice utility functions */
+
+EditVert *editedge_getOtherVert(EditEdge *eed, EditVert *eve)
+{
+ if (eve==eed->v1) {
+ return eed->v2;
+ } else if (eve==eed->v2) {
+ return eed->v1;
+ } else {
+ return NULL;
+ }
+}
+
+EditVert *editedge_getSharedVert(EditEdge *eed, EditEdge *eed2)
+{
+ if (eed->v1==eed2->v1 || eed->v1==eed2->v2) {
+ return eed->v1;
+ } else if (eed->v2==eed2->v1 || eed->v2==eed2->v2) {
+ return eed->v2;
+ } else {
+ return NULL;
+ }
+}
+
+int editedge_containsVert(EditEdge *eed, EditVert *eve)
+{
+ return (eed->v1==eve || eed->v2==eve);
+}
+
+int editface_containsVert(EditFace *efa, EditVert *eve)
+{
+ return (efa->v1==eve || efa->v2==eve || efa->v3==eve || (efa->v4 && efa->v4==eve));
+}
+
+int editface_containsEdge(EditFace *efa, EditEdge *eed)
+{
+ return (efa->e1==eed || efa->e2==eed || efa->e3==eed || (efa->e4 && efa->e4==eed));
+}
+
+
+/* ************************ stuct EditMesh manipulation ***************************** */
+
+/* fake callocs for fastmalloc below */
+static void *calloc_fastvert(size_t size, size_t nr)
+{
+ EditVert *eve= G.editMesh->curvert++;
+ eve->fast= 1;
+ return eve;
+}
+static void *calloc_fastedge(size_t size, size_t nr)
+{
+ EditEdge *eed= G.editMesh->curedge++;
+ eed->fast= 1;
+ return eed;
+}
+static void *calloc_fastface(size_t size, size_t nr)
+{
+ EditFace *efa= G.editMesh->curface++;
+ efa->fast= 1;
+ return efa;
+}
+
+/* allocate 1 chunk for all vertices, edges, faces. These get tagged to
+ prevent it from being freed
+*/
+static void init_editmesh_fastmalloc(EditMesh *em, int totvert, int totedge, int totface)
+{
+ if(totvert) em->allverts= MEM_callocN(totvert*sizeof(EditVert), "allverts");
+ else em->allverts= NULL;
+ em->curvert= em->allverts;
+
+ if(totedge==0) totedge= 4*totface; // max possible
+
+ if(totedge) em->alledges= MEM_callocN(totedge*sizeof(EditEdge), "alledges");
+ else em->alledges= NULL;
+ em->curedge= em->alledges;
+
+ if(totface) em->allfaces= MEM_callocN(totface*sizeof(EditFace), "allfaces");
+ else em->allfaces= NULL;
+ em->curface= em->allfaces;
+
+ callocvert= calloc_fastvert;
+ callocedge= calloc_fastedge;
+ callocface= calloc_fastface;
+}
+
+static void end_editmesh_fastmalloc(void)
+{
+ callocvert= calloc;
+ callocedge= calloc;
+ callocface= calloc;
+}
+
+void free_editMesh(EditMesh *em)
+{
+#ifdef WITH_VERSE
+ struct VNode *vnode=NULL;
+#endif
+ if(em==NULL) return;
+
+#ifdef WITH_VERSE
+ if(em->vnode) {
+ vnode = (VNode*)em->vnode;
+ em->vnode = NULL;
+ }
+#endif
+
+ if(em->verts.first) free_vertlist(&em->verts);
+ if(em->edges.first) free_edgelist(&em->edges);
+ if(em->faces.first) free_facelist(&em->faces);
+ if(em->selected.first) BLI_freelistN(&(em->selected));
+
+ CustomData_free(&em->vdata, 0);
+ CustomData_free(&em->fdata, 0);
+
+ if(em->derivedFinal) {
+ if (em->derivedFinal!=em->derivedCage) {
+ em->derivedFinal->needsFree= 1;
+ em->derivedFinal->release(em->derivedFinal);
+ }
+ em->derivedFinal= NULL;
+ }
+ if(em->derivedCage) {
+ em->derivedCage->needsFree= 1;
+ em->derivedCage->release(em->derivedCage);
+ em->derivedCage= NULL;
+ }
+
+#ifdef WITH_VERSE
+ if(vnode) {
+ em->vnode = (void*)vnode;
+ }
+#endif
+
+ /* DEBUG: hashtabs are slowest part of enter/exit editmode. here a testprint */
+#if 0
+ if(em->hashedgetab) {
+ HashEdge *he, *hen;
+ int a, used=0, max=0, nr;
+ he= em->hashedgetab;
+ for(a=0; a<EDHASHSIZE; a++, he++) {
+ if(he->eed) used++;
+ hen= he->next;
+ nr= 0;
+ while(hen) {
+ nr++;
+ hen= hen->next;
+ }
+ if(max<nr) max= nr;
+ }
+ printf("hastab used %d max %d\n", used, max);
+ }
+#endif
+ if(em->hashedgetab) MEM_freeN(em->hashedgetab);
+ em->hashedgetab= NULL;
+
+ if(em->allverts) MEM_freeN(em->allverts);
+ if(em->alledges) MEM_freeN(em->alledges);
+ if(em->allfaces) MEM_freeN(em->allfaces);
+
+ em->allverts= em->curvert= NULL;
+ em->alledges= em->curedge= NULL;
+ em->allfaces= em->curface= NULL;
+
+ mesh_octree_table(NULL, NULL, 'e');
+
+ G.totvert= G.totface= 0;
+
+ if(em->retopo_paint_data) retopo_free_paint_data(em->retopo_paint_data);
+ em->retopo_paint_data= NULL;
+}
+
+/* on G.editMesh */
+static void editMesh_set_hash(void)
+{
+ EditEdge *eed;
+
+ G.editMesh->hashedgetab= NULL;
+
+ for(eed=G.editMesh->edges.first; eed; eed= eed->next) {
+ if( findedgelist(eed->v1, eed->v2)==NULL )
+ insert_hashedge(eed);
+ }
+
+}
+
+
+/* ************************ IN & OUT EDITMODE ***************************** */
+
+
+static void edge_normal_compare(EditEdge *eed, EditFace *efa1)
+{
+ EditFace *efa2;
+ float cent1[3], cent2[3];
+ float inp;
+
+ efa2 = eed->tmp.f;
+ if(efa1==efa2) return;
+
+ inp= efa1->n[0]*efa2->n[0] + efa1->n[1]*efa2->n[1] + efa1->n[2]*efa2->n[2];
+ if(inp<0.999 && inp >-0.999) eed->f2= 1;
+
+ if(efa1->v4) CalcCent4f(cent1, efa1->v1->co, efa1->v2->co, efa1->v3->co, efa1->v4->co);
+ else CalcCent3f(cent1, efa1->v1->co, efa1->v2->co, efa1->v3->co);
+ if(efa2->v4) CalcCent4f(cent2, efa2->v1->co, efa2->v2->co, efa2->v3->co, efa2->v4->co);
+ else CalcCent3f(cent2, efa2->v1->co, efa2->v2->co, efa2->v3->co);
+
+ VecSubf(cent1, cent2, cent1);
+ Normalize(cent1);
+ inp= cent1[0]*efa1->n[0] + cent1[1]*efa1->n[1] + cent1[2]*efa1->n[2];
+
+ if(inp < -0.001 ) eed->f1= 1;
+}
+
+#if 0
+typedef struct {
+ EditEdge *eed;
+ float noLen,no[3];
+ int adjCount;
+} EdgeDrawFlagInfo;
+
+static int edgeDrawFlagInfo_cmp(const void *av, const void *bv)
+{
+ const EdgeDrawFlagInfo *a = av;
+ const EdgeDrawFlagInfo *b = bv;
+
+ if (a->noLen<b->noLen) return -1;
+ else if (a->noLen>b->noLen) return 1;
+ else return 0;
+}
+#endif
+
+static void edge_drawflags(void)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+ EditEdge *eed, *e1, *e2, *e3, *e4;
+ EditFace *efa;
+
+ /* - count number of times edges are used in faces: 0 en 1 time means draw edge
+ * - edges more than 1 time used: in *tmp.f is pointer to first face
+ * - check all faces, when normal differs to much: draw (flag becomes 1)
+ */
+
+ /* later on: added flags for 'cylinder' and 'sphere' intersection tests in old
+ game engine (2.04)
+ */
+
+ recalc_editnormals();
+
+ /* init */
+ eve= em->verts.first;
+ while(eve) {
+ eve->f1= 1; /* during test it's set at zero */
+ eve= eve->next;
+ }
+ eed= em->edges.first;
+ while(eed) {
+ eed->f2= eed->f1= 0;
+ eed->tmp.f = 0;
+ eed= eed->next;
+ }
+
+ efa= em->faces.first;
+ while(efa) {
+ e1= efa->e1;
+ e2= efa->e2;
+ e3= efa->e3;
+ e4= efa->e4;
+ if(e1->f2<4) e1->f2+= 1;
+ if(e2->f2<4) e2->f2+= 1;
+ if(e3->f2<4) e3->f2+= 1;
+ if(e4 && e4->f2<4) e4->f2+= 1;
+
+ if(e1->tmp.f == 0) e1->tmp.f = (void *) efa;
+ if(e2->tmp.f == 0) e2->tmp.f = (void *) efa;
+ if(e3->tmp.f ==0) e3->tmp.f = (void *) efa;
+ if(e4 && (e4->tmp.f == 0)) e4->tmp.f = (void *) efa;
+
+ efa= efa->next;
+ }
+
+ if(G.f & G_ALLEDGES) {
+ efa= em->faces.first;
+ while(efa) {
+ if(efa->e1->f2>=2) efa->e1->f2= 1;
+ if(efa->e2->f2>=2) efa->e2->f2= 1;
+ if(efa->e3->f2>=2) efa->e3->f2= 1;
+ if(efa->e4 && efa->e4->f2>=2) efa->e4->f2= 1;
+
+ efa= efa->next;
+ }
+ }
+ else {
+
+ /* handle single-edges for 'test cylinder flag' (old engine) */
+
+ eed= em->edges.first;
+ while(eed) {
+ if(eed->f2==1) eed->f1= 1;
+ eed= eed->next;
+ }
+
+ /* all faces, all edges with flag==2: compare normal */
+ efa= em->faces.first;
+ while(efa) {
+ if(efa->e1->f2==2) edge_normal_compare(efa->e1, efa);
+ else efa->e1->f2= 1;
+ if(efa->e2->f2==2) edge_normal_compare(efa->e2, efa);
+ else efa->e2->f2= 1;
+ if(efa->e3->f2==2) edge_normal_compare(efa->e3, efa);
+ else efa->e3->f2= 1;
+ if(efa->e4) {
+ if(efa->e4->f2==2) edge_normal_compare(efa->e4, efa);
+ else efa->e4->f2= 1;
+ }
+ efa= efa->next;
+ }
+
+ /* sphere collision flag */
+
+ eed= em->edges.first;
+ while(eed) {
+ if(eed->f1!=1) {
+ eed->v1->f1= eed->v2->f1= 0;
+ }
+ eed= eed->next;
+ }
+
+ }
+}
+
+/* turns Mesh into editmesh */
+void make_editMesh()
+{
+ Mesh *me= G.obedit->data;
+ EditMesh *em= G.editMesh;
+ MFace *mface;
+ MVert *mvert;
+ MSelect *mselect;
+ KeyBlock *actkey;
+ EditVert *eve, **evlist, *eve1, *eve2, *eve3, *eve4;
+ EditFace *efa;
+ EditEdge *eed;
+ EditSelection *ese;
+ int tot, a, eekadoodle= 0;
+
+#ifdef WITH_VERSE
+ if(me->vnode){
+ create_edit_mesh_from_geom_node(me->vnode);
+ return;
+ }
+#endif
+
+ /* because of reload */
+ free_editMesh(em);
+
+ em->act_face = NULL;
+ G.totvert= tot= me->totvert;
+ G.totedge= me->totedge;
+ G.totface= me->totface;
+
+ if(tot==0) {
+ countall();
+ return;
+ }
+
+ /* initialize fastmalloc for editmesh */
+ init_editmesh_fastmalloc(em, me->totvert, me->totedge, me->totface);
+
+ actkey = ob_get_keyblock(G.obedit);
+ if(actkey) {
+ strcpy(G.editModeTitleExtra, "(Key) ");
+ key_to_mesh(actkey, me);
+ tot= actkey->totelem;
+ }
+
+ /* make editverts */
+ CustomData_copy(&me->vdata, &em->vdata, CD_MASK_EDITMESH, CD_CALLOC, 0);
+ mvert= me->mvert;
+
+ evlist= (EditVert **)MEM_mallocN(tot*sizeof(void *),"evlist");
+ for(a=0; a<tot; a++, mvert++) {
+ eve= addvertlist(mvert->co, NULL);
+ evlist[a]= eve;
+
+ // face select sets selection in next loop
+ if( (FACESEL_PAINT_TEST)==0 )
+ eve->f |= (mvert->flag & 1);
+
+ if (mvert->flag & ME_HIDE) eve->h= 1;
+ eve->no[0]= mvert->no[0]/32767.0;
+ eve->no[1]= mvert->no[1]/32767.0;
+ eve->no[2]= mvert->no[2]/32767.0;
+
+ /* lets overwrite the keyindex of the editvert
+ * with the order it used to be in before
+ * editmode
+ */
+ eve->keyindex = a;
+
+ CustomData_to_em_block(&me->vdata, &em->vdata, a, &eve->data);
+ }
+
+ if(actkey && actkey->totelem!=me->totvert);
+ else {
+ MEdge *medge= me->medge;
+
+ CustomData_copy(&me->edata, &em->edata, CD_MASK_EDITMESH, CD_CALLOC, 0);
+ /* make edges */
+ for(a=0; a<me->totedge; a++, medge++) {
+ eed= addedgelist(evlist[medge->v1], evlist[medge->v2], NULL);
+ /* eed can be zero when v1 and v2 are identical, dxf import does this... */
+ if(eed) {
+ eed->crease= ((float)medge->crease)/255.0;
+
+ if(medge->flag & ME_SEAM) eed->seam= 1;
+ if(medge->flag & ME_SHARP) eed->sharp = 1;
+ if(medge->flag & SELECT) eed->f |= SELECT;
+ if(medge->flag & ME_FGON) eed->h= EM_FGON; // 2 different defines!
+ if(medge->flag & ME_HIDE) eed->h |= 1;
+ if(G.scene->selectmode==SCE_SELECT_EDGE)
+ EM_select_edge(eed, eed->f & SELECT); // force edge selection to vertices, seems to be needed ...
+ CustomData_to_em_block(&me->edata,&em->edata, a, &eed->data);
+ }
+ }
+
+ CustomData_copy(&me->fdata, &em->fdata, CD_MASK_EDITMESH, CD_CALLOC, 0);
+
+ /* make faces */
+ mface= me->mface;
+
+ for(a=0; a<me->totface; a++, mface++) {
+ eve1= evlist[mface->v1];
+ eve2= evlist[mface->v2];
+ if(!mface->v3) eekadoodle= 1;
+ eve3= evlist[mface->v3];
+ if(mface->v4) eve4= evlist[mface->v4]; else eve4= NULL;
+
+ efa= addfacelist(eve1, eve2, eve3, eve4, NULL, NULL);
+
+ if(efa) {
+ CustomData_to_em_block(&me->fdata, &em->fdata, a, &efa->data);
+
+ efa->mat_nr= mface->mat_nr;
+ efa->flag= mface->flag & ~ME_HIDE;
+
+ /* select and hide face flag */
+ if(mface->flag & ME_FACE_SEL) {
+ efa->f |= SELECT;
+ }
+ if(mface->flag & ME_HIDE) efa->h= 1;
+
+ if((FACESEL_PAINT_TEST) && (efa->f & SELECT))
+ EM_select_face(efa, 1); /* flush down */
+
+ if (a==me->act_face)
+ em->act_face = efa;
+ }
+ }
+ }
+
+ if(eekadoodle)
+ error("This Mesh has old style edgecodes, please put it in the bugtracker!");
+
+ MEM_freeN(evlist);
+
+ end_editmesh_fastmalloc(); // resets global function pointers
+
+ if(me->mselect){
+ //restore editselections
+ EM_init_index_arrays(1,1,1);
+ mselect = me->mselect;
+
+ for(a=0; a<me->totselect; a++, mselect++){
+ /*check if recorded selection is still valid, if so copy into editmesh*/
+ if( (mselect->type == EDITVERT && me->mvert[mselect->index].flag & SELECT) || (mselect->type == EDITEDGE && me->medge[mselect->index].flag & SELECT) || (mselect->type == EDITFACE && me->mface[mselect->index].flag & ME_FACE_SEL) ){
+ ese = MEM_callocN(sizeof(EditSelection), "Edit Selection");
+ ese->type = mselect->type;
+ if(ese->type == EDITVERT) ese->data = EM_get_vert_for_index(mselect->index); else
+ if(ese->type == EDITEDGE) ese->data = EM_get_edge_for_index(mselect->index); else
+ if(ese->type == EDITFACE) ese->data = EM_get_face_for_index(mselect->index);
+ BLI_addtail(&(em->selected),ese);
+ }
+ }
+ EM_free_index_arrays();
+ }
+ /* this creates coherent selections. also needed for older files */
+ EM_selectmode_set();
+ /* paranoia check to enforce hide rules */
+ EM_hide_reset();
+ /* sets helper flags which arent saved */
+ EM_fgon_flags();
+
+ countall();
+
+}
+
+/* makes Mesh out of editmesh */
+void load_editMesh(void)
+{
+ EditMesh *em = G.editMesh;
+ Mesh *me= G.obedit->data;
+ MVert *mvert, *oldverts;
+ MEdge *medge;
+ MFace *mface;
+ MSelect *mselect;
+ EditVert *eve;
+ EditFace *efa;
+ EditEdge *eed;
+ EditSelection *ese;
+ float *fp, *newkey, *oldkey, nor[3];
+ int i, a, ototvert, totedge=0;
+
+#ifdef WITH_VERSE
+ if(em->vnode) {
+ struct VNode *vnode = (VNode*)em->vnode;
+ ((VGeomData*)vnode->data)->editmesh = NULL;
+ em->vnode = NULL;
+ }
+#endif
+
+ countall();
+
+ /* this one also tests of edges are not in faces: */
+ /* eed->f2==0: not in face, f2==1: draw it */
+ /* eed->f1 : flag for dynaface (cylindertest, old engine) */
+ /* eve->f1 : flag for dynaface (sphere test, old engine) */
+ /* eve->f2 : being used in vertexnormals */
+ edge_drawflags();
+
+ eed= em->edges.first;
+ while(eed) {
+ totedge++;
+ eed= eed->next;
+ }
+
+ /* new Vertex block */
+ if(G.totvert==0) mvert= NULL;
+ else mvert= MEM_callocN(G.totvert*sizeof(MVert), "loadeditMesh vert");
+
+ /* new Edge block */
+ if(totedge==0) medge= NULL;
+ else medge= MEM_callocN(totedge*sizeof(MEdge), "loadeditMesh edge");
+
+ /* new Face block */
+ if(G.totface==0) mface= NULL;
+ else mface= MEM_callocN(G.totface*sizeof(MFace), "loadeditMesh face");
+
+ /* lets save the old verts just in case we are actually working on
+ * a key ... we now do processing of the keys at the end */
+ oldverts= me->mvert;
+ ototvert= me->totvert;
+
+ /* don't free this yet */
+ CustomData_set_layer(&me->vdata, CD_MVERT, NULL);
+
+ /* free custom data */
+ CustomData_free(&me->vdata, me->totvert);
+ CustomData_free(&me->edata, me->totedge);
+ CustomData_free(&me->fdata, me->totface);
+
+ /* add new custom data */
+ me->totvert= G.totvert;
+ me->totedge= totedge;
+ me->totface= G.totface;
+
+ CustomData_copy(&em->vdata, &me->vdata, CD_MASK_MESH, CD_CALLOC, me->totvert);
+ CustomData_copy(&em->edata, &me->edata, CD_MASK_MESH, CD_CALLOC, me->totedge);
+ CustomData_copy(&em->fdata, &me->fdata, CD_MASK_MESH, CD_CALLOC, me->totface);
+
+ CustomData_add_layer(&me->vdata, CD_MVERT, CD_ASSIGN, mvert, me->totvert);
+ CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, medge, me->totedge);
+ CustomData_add_layer(&me->fdata, CD_MFACE, CD_ASSIGN, mface, me->totface);
+ mesh_update_customdata_pointers(me);
+
+ /* the vertices, use ->tmp.l as counter */
+ eve= em->verts.first;
+ a= 0;
+
+ while(eve) {
+ VECCOPY(mvert->co, eve->co);
+ mvert->mat_nr= 255; /* what was this for, halos? */
+
+ /* vertex normal */
+ VECCOPY(nor, eve->no);
+ VecMulf(nor, 32767.0);
+ VECCOPY(mvert->no, nor);
+
+ /* note: it used to remove me->dvert when it was not in use, cancelled
+ that... annoying when you have a fresh vgroup */
+ CustomData_from_em_block(&em->vdata, &me->vdata, eve->data, a);
+
+ eve->tmp.l = a++; /* counter */
+
+ mvert->flag= 0;
+ if(eve->f1==1) mvert->flag |= ME_SPHERETEST;
+ mvert->flag |= (eve->f & SELECT);
+ if (eve->h) mvert->flag |= ME_HIDE;
+
+#ifdef WITH_VERSE
+ if(eve->vvert) {
+ ((VerseVert*)eve->vvert)->vertex = NULL;
+ eve->vvert = NULL;
+ }
+#endif
+ eve= eve->next;
+ mvert++;
+ }
+
+ /* the edges */
+ a= 0;
+ eed= em->edges.first;
+ while(eed) {
+ medge->v1= (unsigned int) eed->v1->tmp.l;
+ medge->v2= (unsigned int) eed->v2->tmp.l;
+
+ medge->flag= (eed->f & SELECT) | ME_EDGERENDER;
+ if(eed->f2<2) medge->flag |= ME_EDGEDRAW;
+ if(eed->f2==0) medge->flag |= ME_LOOSEEDGE;
+ if(eed->sharp) medge->flag |= ME_SHARP;
+ if(eed->seam) medge->flag |= ME_SEAM;
+ if(eed->h & EM_FGON) medge->flag |= ME_FGON; // different defines yes
+ if(eed->h & 1) medge->flag |= ME_HIDE;
+
+ medge->crease= (char)(255.0*eed->crease);
+ CustomData_from_em_block(&em->edata, &me->edata, eed->data, a);
+
+ eed->tmp.l = a++;
+
+ medge++;
+ eed= eed->next;
+ }
+
+ /* the faces */
+ a = 0;
+ efa= em->faces.first;
+ i = 0;
+ me->act_face = -1;
+ while(efa) {
+ mface= &((MFace *) me->mface)[i];
+
+ mface->v1= (unsigned int) efa->v1->tmp.l;
+ mface->v2= (unsigned int) efa->v2->tmp.l;
+ mface->v3= (unsigned int) efa->v3->tmp.l;
+ if (efa->v4) mface->v4 = (unsigned int) efa->v4->tmp.l;
+
+ mface->mat_nr= efa->mat_nr;
+
+ mface->flag= efa->flag;
+ /* bit 0 of flag is already taken for smooth... */
+
+ if(efa->h) {
+ mface->flag |= ME_HIDE;
+ mface->flag &= ~ME_FACE_SEL;
+ } else {
+ if(efa->f & 1) mface->flag |= ME_FACE_SEL;
+ else mface->flag &= ~ME_FACE_SEL;
+ }
+
+ /* mat_nr in vertex */
+ if(me->totcol>1) {
+ mvert= me->mvert+mface->v1;
+ if(mvert->mat_nr == (char)255) mvert->mat_nr= mface->mat_nr;
+ mvert= me->mvert+mface->v2;
+ if(mvert->mat_nr == (char)255) mvert->mat_nr= mface->mat_nr;
+ mvert= me->mvert+mface->v3;
+ if(mvert->mat_nr == (char)255) mvert->mat_nr= mface->mat_nr;
+ if(mface->v4) {
+ mvert= me->mvert+mface->v4;
+ if(mvert->mat_nr == (char)255) mvert->mat_nr= mface->mat_nr;
+ }
+ }
+
+ /* watch: efa->e1->f2==0 means loose edge */
+
+ if(efa->e1->f2==1) {
+ efa->e1->f2= 2;
+ }
+ if(efa->e2->f2==1) {
+ efa->e2->f2= 2;
+ }
+ if(efa->e3->f2==1) {
+ efa->e3->f2= 2;
+ }
+ if(efa->e4 && efa->e4->f2==1) {
+ efa->e4->f2= 2;
+ }
+
+ CustomData_from_em_block(&em->fdata, &me->fdata, efa->data, i);
+
+ /* no index '0' at location 3 or 4 */
+ test_index_face(mface, &me->fdata, i, efa->v4?4:3);
+
+ if (EM_get_actFace() == efa)
+ me->act_face = a;
+
+#ifdef WITH_VERSE
+ if(efa->vface) {
+ ((VerseFace*)efa->vface)->face = NULL;
+ efa->vface = NULL;
+ }
+#endif
+ efa->tmp.l = a++;
+ i++;
+ efa= efa->next;
+ }
+
+ /* patch hook indices and vertex parents */
+ {
+ Object *ob;
+ ModifierData *md;
+ EditVert *eve, **vertMap = NULL;
+ int i,j;
+
+ for (ob=G.main->object.first; ob; ob=ob->id.next) {
+ if (ob->parent==G.obedit && ELEM(ob->partype, PARVERT1,PARVERT3)) {
+
+ /* duplicate code from below, make it function later...? */
+ if (!vertMap) {
+ vertMap = MEM_callocN(sizeof(*vertMap)*ototvert, "vertMap");
+
+ for (eve=em->verts.first; eve; eve=eve->next) {
+ if (eve->keyindex!=-1)
+ vertMap[eve->keyindex] = eve;
+ }
+ }
+ if(ob->par1 < ototvert) {
+ eve = vertMap[ob->par1];
+ if(eve) ob->par1= eve->tmp.l;
+ }
+ if(ob->par2 < ototvert) {
+ eve = vertMap[ob->par2];
+ if(eve) ob->par2= eve->tmp.l;
+ }
+ if(ob->par3 < ototvert) {
+ eve = vertMap[ob->par3];
+ if(eve) ob->par3= eve->tmp.l;
+ }
+
+ }
+ if (ob->data==me) {
+ for (md=ob->modifiers.first; md; md=md->next) {
+ if (md->type==eModifierType_Hook) {
+ HookModifierData *hmd = (HookModifierData*) md;
+
+ if (!vertMap) {
+ vertMap = MEM_callocN(sizeof(*vertMap)*ototvert, "vertMap");
+
+ for (eve=em->verts.first; eve; eve=eve->next) {
+ if (eve->keyindex!=-1)
+ vertMap[eve->keyindex] = eve;
+ }
+ }
+
+ for (i=j=0; i<hmd->totindex; i++) {
+ if(hmd->indexar[i] < ototvert) {
+ eve = vertMap[hmd->indexar[i]];
+
+ if (eve) {
+ hmd->indexar[j++] = eve->tmp.l;
+ }
+ }
+ else j++;
+ }
+
+ hmd->totindex = j;
+ }
+ }
+ }
+ }
+
+ if (vertMap) MEM_freeN(vertMap);
+ }
+
+ /* are there keys? */
+ if(me->key) {
+ KeyBlock *currkey, *actkey = ob_get_keyblock(G.obedit);
+
+ /* Lets reorder the key data so that things line up roughly
+ * with the way things were before editmode */
+ currkey = me->key->block.first;
+ while(currkey) {
+
+ fp= newkey= MEM_callocN(me->key->elemsize*G.totvert, "currkey->data");
+ oldkey = currkey->data;
+
+ eve= em->verts.first;
+
+ i = 0;
+ mvert = me->mvert;
+ while(eve) {
+ if (eve->keyindex >= 0 && eve->keyindex < currkey->totelem) { // valid old vertex
+ if(currkey == actkey) {
+ if (actkey == me->key->refkey) {
+ VECCOPY(fp, mvert->co);
+ }
+ else {
+ VECCOPY(fp, mvert->co);
+ if(oldverts) {
+ VECCOPY(mvert->co, oldverts[eve->keyindex].co);
+ }
+ }
+ }
+ else {
+ if(oldkey) {
+ VECCOPY(fp, oldkey + 3 * eve->keyindex);
+ }
+ }
+ }
+ else {
+ VECCOPY(fp, mvert->co);
+ }
+ fp+= 3;
+ ++i;
+ ++mvert;
+ eve= eve->next;
+ }
+ currkey->totelem= G.totvert;
+ if(currkey->data) MEM_freeN(currkey->data);
+ currkey->data = newkey;
+
+ currkey= currkey->next;
+ }
+ }
+
+ if(oldverts) MEM_freeN(oldverts);
+
+ i = 0;
+ for(ese=em->selected.first; ese; ese=ese->next) i++;
+ me->totselect = i;
+ if(i==0) mselect= NULL;
+ else mselect= MEM_callocN(i*sizeof(MSelect), "loadeditMesh selections");
+
+ if(me->mselect) MEM_freeN(me->mselect);
+ me->mselect= mselect;
+
+ for(ese=em->selected.first; ese; ese=ese->next){
+ mselect->type = ese->type;
+ if(ese->type == EDITVERT) mselect->index = ((EditVert*)ese->data)->tmp.l;
+ else if(ese->type == EDITEDGE) mselect->index = ((EditEdge*)ese->data)->tmp.l;
+ else if(ese->type == EDITFACE) mselect->index = ((EditFace*)ese->data)->tmp.l;
+ mselect++;
+ }
+
+ /* to be sure: clear ->tmp.l pointers */
+ eve= em->verts.first;
+ while(eve) {
+ eve->tmp.l = 0;
+ eve= eve->next;
+ }
+
+ eed= em->edges.first;
+ while(eed) {
+ eed->tmp.l = 0;
+ eed= eed->next;
+ }
+
+ efa= em->faces.first;
+ while(efa) {
+ efa->tmp.l = 0;
+ efa= efa->next;
+ }
+
+ /* remake softbody of all users */
+ if(me->id.us>1) {
+ Base *base;
+ for(base= G.scene->base.first; base; base= base->next) {
+ if(base->object->data==me) {
+ base->object->softflag |= OB_SB_REDO;
+ base->object->recalc |= OB_RECALC_DATA;
+ }
+ }
+ }
+
+ mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
+}
+
+void remake_editMesh(void)
+{
+ make_editMesh();
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ BIF_undo_push("Undo all changes");
+}
+
+/* *************** (partial exit editmode) *************/
+
+
+void separatemenu(void)
+{
+ short event;
+
+ if(G.editMesh->verts.first==NULL) return;
+
+ event = pupmenu("Separate %t|Selected%x1|All Loose Parts%x2|By Material%x3");
+
+ if (event==0) return;
+ waitcursor(1);
+
+ switch (event) {
+ case 1:
+ separate_mesh();
+ break;
+ case 2:
+ separate_mesh_loose();
+ break;
+ case 3:
+ separate_material();
+ break;
+ }
+ waitcursor(0);
+}
+
+void separate_material(void)
+{
+ EditMesh *em = G.editMesh;
+ unsigned char curr_mat;
+ Mesh *me;
+
+ if(multires_test()) return;
+
+ me= get_mesh(G.obedit);
+ if(me->key) {
+ error("Can't separate with vertex keys");
+ return;
+ }
+
+ if(G.obedit && em) {
+ if(G.obedit->type == OB_MESH) {
+ for (curr_mat = 1; curr_mat < G.obedit->totcol; ++curr_mat) {
+ /* clear selection, we're going to use that to select material group */
+ EM_clear_flag_all(SELECT);
+ /* select the material */
+ editmesh_select_by_material(curr_mat);
+ /* and now separate */
+ separate_mesh();
+ }
+ }
+ }
+
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+
+}
+
+void separate_mesh(void)
+{
+ EditMesh *em = G.editMesh;
+ EditMesh emcopy;
+ EditVert *eve, *v1;
+ EditEdge *eed, *e1;
+ EditFace *efa, *vl1;
+ Object *oldob;
+ Mesh *me, *men;
+ Base *base, *oldbase;
+ ListBase edve, eded, edvl;
+#ifdef WITH_VERSE
+ struct VNode *vnode = NULL;
+#endif
+
+ TEST_EDITMESH
+ if(multires_test()) return;
+
+ waitcursor(1);
+
+ me= get_mesh(G.obedit);
+ if(me->key) {
+ error("Can't separate with vertex keys");
+ return;
+ }
+
+ /* blender crashes in derivedmesh drawing if I don't do this... but why?
+ Anyhoo, this function is horrible anyway (ton)
+ the fluidsimFlag also has to be reset btw. (n_t) */
+ if(G.obedit->fluidsimSettings) {
+ fluidsimSettingsFree(G.obedit->fluidsimSettings);
+ G.obedit->fluidsimSettings = NULL;
+ G.obedit->fluidsimFlag = 0;
+ }
+
+ if(em->selected.first) BLI_freelistN(&(em->selected)); /* clear the selection order */
+
+ EM_selectmode_set(); // enforce full consistant selection flags
+
+ /* we are going to abuse the system as follows:
+ * 1. add a duplicate object: this will be the new one, we remember old pointer
+ * 2: then do a split if needed.
+ * 3. put apart: all NOT selected verts, edges, faces
+ * 4. call load_editMesh(): this will be the new object
+ * 5. freelist and get back old verts, edges, facs
+ */
+
+ /* make only obedit selected */
+ base= FIRSTBASE;
+ while(base) {
+ if(base->lay & G.vd->lay) {
+ if(base->object==G.obedit) base->flag |= SELECT;
+ else base->flag &= ~SELECT;
+ }
+ base= base->next;
+ }
+
+#ifdef WITH_VERSE
+ if(G.editMesh->vnode) {
+ vnode = G.editMesh->vnode;
+ G.editMesh->vnode = NULL;
+ }
+#endif
+ /* no test for split, split doesn't split when a loose part is selected */
+ /* SPLIT: first make duplicate */
+ adduplicateflag(SELECT);
+
+#ifdef WITH_VERSE
+ if(vnode) {
+ G.editMesh->vnode = vnode;
+ }
+#endif
+ /* SPLIT: old faces have 3x flag 128 set, delete these ones */
+ delfaceflag(128);
+
+ /* since we do tricky things with verts/edges/faces, this makes sure all is selected coherent */
+ EM_selectmode_set();
+
+ /* set apart: everything that is not selected */
+ edve.first= edve.last= eded.first= eded.last= edvl.first= edvl.last= 0;
+ eve= em->verts.first;
+ while(eve) {
+ v1= eve->next;
+ if((eve->f & SELECT)==0) {
+ BLI_remlink(&em->verts, eve);
+ BLI_addtail(&edve, eve);
+#ifdef WITH_VERSE
+ if(eve->vvert) {
+ ((VerseVert*)eve->vvert)->vertex = NULL;
+ eve->vvert = NULL;
+ }
+#endif
+ }
+
+ eve= v1;
+ }
+ eed= em->edges.first;
+ while(eed) {
+ e1= eed->next;
+ if((eed->f & SELECT)==0) {
+ BLI_remlink(&em->edges, eed);
+ BLI_addtail(&eded, eed);
+ }
+ eed= e1;
+ }
+ efa= em->faces.first;
+ while(efa) {
+ vl1= efa->next;
+ if((efa->f & SELECT)==0) {
+ BLI_remlink(&em->faces, efa);
+ BLI_addtail(&edvl, efa);
+#ifdef WITH_VERSE
+ if(efa->vface) {
+ ((VerseFace*)efa->vface)->face = NULL;
+ efa->vface = NULL;
+ }
+#endif
+ }
+ efa= vl1;
+ }
+
+ oldob= G.obedit;
+ oldbase= BASACT;
+
+#ifdef WITH_VERSE
+ if(G.obedit->vnode) {
+ vnode = G.obedit->vnode;
+ G.obedit->vnode = NULL;
+ }
+#endif
+ adduplicate(1, 0); /* notrans and a linked duplicate */
+
+#ifdef WITH_VERSE
+ if(vnode) {
+ G.obedit->vnode = vnode;
+ }
+#endif
+
+ G.obedit= BASACT->object; /* basact was set in adduplicate() */
+
+ men= copy_mesh(me);
+ set_mesh(G.obedit, men);
+ /* because new mesh is a copy: reduce user count */
+ men->id.us--;
+
+ load_editMesh();
+
+ BASACT->flag &= ~SELECT;
+
+ /* we cannot free the original buffer... */
+ emcopy= *G.editMesh;
+ emcopy.allverts= NULL;
+ emcopy.alledges= NULL;
+ emcopy.allfaces= NULL;
+ emcopy.derivedFinal= emcopy.derivedCage= NULL;
+ memset(&emcopy.vdata, 0, sizeof(emcopy.vdata));
+ memset(&emcopy.fdata, 0, sizeof(emcopy.fdata));
+ free_editMesh(&emcopy);
+
+ em->verts= edve;
+ em->edges= eded;
+ em->faces= edvl;
+
+ /* hashedges are freed now, make new! */
+ editMesh_set_hash();
+
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ G.obedit= oldob;
+ BASACT= oldbase;
+ BASACT->flag |= SELECT;
+
+ waitcursor(0);
+
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+
+}
+
+void separate_mesh_loose(void)
+{
+ EditMesh *em = G.editMesh;
+ EditMesh emcopy;
+ EditVert *eve, *v1;
+ EditEdge *eed, *e1;
+ EditFace *efa, *vl1;
+ Object *oldob=NULL;
+ Mesh *me, *men;
+ Base *base, *oldbase;
+ ListBase edve, eded, edvl;
+ int vertsep=0;
+ short done=0, check=1;
+#ifdef WITH_VERSE
+ struct VNode *vnode = NULL;
+#endif
+
+ me= get_mesh(G.obedit);
+#ifdef WITH_VERSE
+ if(me->vnode) {
+ error("Can't separate a mesh shared at verse server");
+ return;
+ }
+#endif
+ if(me->key) {
+ error("Can't separate a mesh with vertex keys");
+ return;
+ }
+
+ /* same problem as in separate_mesh above (n_t) */
+ if(G.obedit->fluidsimSettings) {
+ fluidsimSettingsFree(G.obedit->fluidsimSettings);
+ G.obedit->fluidsimSettings = NULL;
+ G.obedit->fluidsimFlag = 0;
+ }
+
+ TEST_EDITMESH
+ if(multires_test()) return;
+ waitcursor(1);
+
+ /* we are going to abuse the system as follows:
+ * 1. add a duplicate object: this will be the new one, we remember old pointer
+ * 2: then do a split if needed.
+ * 3. put apart: all NOT selected verts, edges, faces
+ * 4. call load_editMesh(): this will be the new object
+ * 5. freelist and get back old verts, edges, facs
+ */
+
+ while(!done){
+ vertsep=check=1;
+
+ countall();
+
+ /* make only obedit selected */
+ base= FIRSTBASE;
+ while(base) {
+ if(base->lay & G.vd->lay) {
+ if(base->object==G.obedit) base->flag |= SELECT;
+ else base->flag &= ~SELECT;
+ }
+ base= base->next;
+ }
+
+ /*--------- Select connected-----------*/
+
+ EM_clear_flag_all(SELECT);
+
+ /* Select a random vert to start with */
+ eve= em->verts.first;
+ eve->f |= SELECT;
+
+ while(check==1) {
+ check= 0;
+ eed= em->edges.first;
+ while(eed) {
+ if(eed->h==0) {
+ if(eed->v1->f & SELECT) {
+ if( (eed->v2->f & SELECT)==0 ) {
+ eed->v2->f |= SELECT;
+ vertsep++;
+ check= 1;
+ }
+ }
+ else if(eed->v2->f & SELECT) {
+ if( (eed->v1->f & SELECT)==0 ) {
+ eed->v1->f |= SELECT;
+ vertsep++;
+ check= SELECT;
+ }
+ }
+ }
+ eed= eed->next;
+ }
+ }
+ /*----------End of select connected--------*/
+
+
+ /* If the amount of vertices that is about to be split == the total amount
+ of verts in the mesh, it means that there is only 1 unconnected object, so we don't have to separate
+ */
+ if(G.totvert==vertsep) done=1;
+ else{
+ /* No splitting: select connected goes fine */
+
+ EM_select_flush(); // from verts->edges->faces
+
+ /* set apart: everything that is not selected */
+ edve.first= edve.last= eded.first= eded.last= edvl.first= edvl.last= 0;
+ eve= em->verts.first;
+ while(eve) {
+ v1= eve->next;
+ if((eve->f & SELECT)==0) {
+ BLI_remlink(&em->verts, eve);
+ BLI_addtail(&edve, eve);
+#ifdef WITH_VERSE
+ if(eve->vvert) {
+ b_verse_send_vertex_delete(eve);
+ }
+#endif
+ }
+ eve= v1;
+ }
+ eed= em->edges.first;
+ while(eed) {
+ e1= eed->next;
+ if( (eed->f & SELECT)==0 ) {
+ BLI_remlink(&em->edges, eed);
+ BLI_addtail(&eded, eed);
+ }
+ eed= e1;
+ }
+ efa= em->faces.first;
+ while(efa) {
+ vl1= efa->next;
+ if( (efa->f & SELECT)==0 ) {
+ BLI_remlink(&em->faces, efa);
+ BLI_addtail(&edvl, efa);
+#ifdef WITH_VERSE
+ if(efa->vface) {
+ b_verse_send_face_delete(efa);
+ }
+#endif
+ }
+ efa= vl1;
+ }
+
+ oldob= G.obedit;
+ oldbase= BASACT;
+
+#ifdef WITH_VERSE
+ if(G.obedit->vnode) {
+ vnode = G.obedit->vnode;
+ G.obedit->vnode = NULL;
+ }
+#endif
+ adduplicate(1, 0); /* notrans and a linked duplicate*/
+#ifdef WITH_VERSE
+ if(vnode) {
+ G.obedit->vnode = vnode;
+ }
+#endif
+
+ G.obedit= BASACT->object; /* basact was set in adduplicate() */
+
+ men= copy_mesh(me);
+ set_mesh(G.obedit, men);
+ /* because new mesh is a copy: reduce user count */
+ men->id.us--;
+
+ load_editMesh();
+
+ BASACT->flag &= ~SELECT;
+
+ /* we cannot free the original buffer... */
+ emcopy= *G.editMesh;
+ emcopy.allverts= NULL;
+ emcopy.alledges= NULL;
+ emcopy.allfaces= NULL;
+ emcopy.derivedFinal= emcopy.derivedCage= NULL;
+ memset(&emcopy.vdata, 0, sizeof(emcopy.vdata));
+ memset(&emcopy.fdata, 0, sizeof(emcopy.fdata));
+ free_editMesh(&emcopy);
+
+ em->verts= edve;
+ em->edges= eded;
+ em->faces= edvl;
+
+ /* hashedges are freed now, make new! */
+ editMesh_set_hash();
+
+ G.obedit= oldob;
+ BASACT= oldbase;
+ BASACT->flag |= SELECT;
+
+ }
+ }
+
+ /* unselect the vertices that we (ab)used for the separation*/
+ EM_clear_flag_all(SELECT);
+
+ waitcursor(0);
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+}
+
+/* ******************************************** */
+
+/* *************** UNDO ***************************** */
+/* new mesh undo, based on pushing editmesh data itself */
+/* reuses same code as for global and curve undo... unify that (ton) */
+
+/* only one 'hack', to save memory it doesn't store the first push, but does a remake editmesh */
+
+/* a compressed version of editmesh data */
+
+typedef struct EditVertC
+{
+ float no[3];
+ float co[3];
+ unsigned char f, h;
+ int keyindex;
+} EditVertC;
+
+typedef struct EditEdgeC
+{
+ int v1, v2;
+ unsigned char f, h, seam, sharp, pad;
+ short crease, fgoni;
+} EditEdgeC;
+
+typedef struct EditFaceC
+{
+ int v1, v2, v3, v4;
+ unsigned char mat_nr, flag, f, h, fgonf;
+ short pad1;
+} EditFaceC;
+
+typedef struct EditSelectionC{
+ short type;
+ int index;
+}EditSelectionC;
+
+typedef struct EM_MultiresUndo {
+ int users;
+ Multires *mr;
+} EM_MultiresUndo;
+
+typedef struct UndoMesh {
+ EditVertC *verts;
+ EditEdgeC *edges;
+ EditFaceC *faces;
+ EditSelectionC *selected;
+ int totvert, totedge, totface, totsel;
+ short selectmode;
+ RetopoPaintData *retopo_paint_data;
+ char retopo_mode;
+ CustomData vdata, edata, fdata;
+ EM_MultiresUndo *mru;
+} UndoMesh;
+
+/* for callbacks */
+
+static void free_undoMesh(void *umv)
+{
+ UndoMesh *um= umv;
+
+ if(um->verts) MEM_freeN(um->verts);
+ if(um->edges) MEM_freeN(um->edges);
+ if(um->faces) MEM_freeN(um->faces);
+ if(um->selected) MEM_freeN(um->selected);
+ if(um->retopo_paint_data) retopo_free_paint_data(um->retopo_paint_data);
+ CustomData_free(&um->vdata, um->totvert);
+ CustomData_free(&um->edata, um->totedge);
+ CustomData_free(&um->fdata, um->totface);
+ if(um->mru) {
+ --um->mru->users;
+ if(um->mru->users==0) {
+ multires_free(um->mru->mr);
+ um->mru->mr= NULL;
+ MEM_freeN(um->mru);
+ }
+ }
+ MEM_freeN(um);
+}
+
+static void *editMesh_to_undoMesh(void)
+{
+ EditMesh *em= G.editMesh;
+ UndoMesh *um;
+ EditVert *eve;
+ EditEdge *eed;
+ EditFace *efa;
+ EditSelection *ese;
+ EditVertC *evec=NULL;
+ EditEdgeC *eedc=NULL;
+ EditFaceC *efac=NULL;
+ EditSelectionC *esec=NULL;
+ int a;
+
+ um= MEM_callocN(sizeof(UndoMesh), "undomesh");
+
+ um->selectmode = G.scene->selectmode;
+
+ for(eve=em->verts.first; eve; eve= eve->next) um->totvert++;
+ for(eed=em->edges.first; eed; eed= eed->next) um->totedge++;
+ for(efa=em->faces.first; efa; efa= efa->next) um->totface++;
+ for(ese=em->selected.first; ese; ese=ese->next) um->totsel++;
+ /* malloc blocks */
+
+ if(um->totvert) evec= um->verts= MEM_callocN(um->totvert*sizeof(EditVertC), "allvertsC");
+ if(um->totedge) eedc= um->edges= MEM_callocN(um->totedge*sizeof(EditEdgeC), "alledgesC");
+ if(um->totface) efac= um->faces= MEM_callocN(um->totface*sizeof(EditFaceC), "allfacesC");
+ if(um->totsel) esec= um->selected= MEM_callocN(um->totsel*sizeof(EditSelectionC), "allselections");
+
+ if(um->totvert) CustomData_copy(&em->vdata, &um->vdata, CD_MASK_EDITMESH, CD_CALLOC, um->totvert);
+ if(um->totedge) CustomData_copy(&em->edata, &um->edata, CD_MASK_EDITMESH, CD_CALLOC, um->totedge);
+ if(um->totface) CustomData_copy(&em->fdata, &um->fdata, CD_MASK_EDITMESH, CD_CALLOC, um->totface);
+
+ /* now copy vertices */
+ a = 0;
+ for(eve=em->verts.first; eve; eve= eve->next, evec++, a++) {
+ VECCOPY(evec->co, eve->co);
+ VECCOPY(evec->no, eve->no);
+
+ evec->f= eve->f;
+ evec->h= eve->h;
+ evec->keyindex= eve->keyindex;
+ eve->tmp.l = a; /*store index*/
+
+ CustomData_from_em_block(&em->vdata, &um->vdata, eve->data, a);
+ }
+
+ /* copy edges */
+ a = 0;
+ for(eed=em->edges.first; eed; eed= eed->next, eedc++, a++) {
+ eedc->v1= (int)eed->v1->tmp.l;
+ eedc->v2= (int)eed->v2->tmp.l;
+ eedc->f= eed->f;
+ eedc->h= eed->h;
+ eedc->seam= eed->seam;
+ eedc->sharp= eed->sharp;
+ eedc->crease= (short)(eed->crease*255.0);
+ eedc->fgoni= eed->fgoni;
+ eed->tmp.l = a; /*store index*/
+ CustomData_from_em_block(&em->edata, &um->edata, eed->data, a);
+
+ }
+
+ /* copy faces */
+ a = 0;
+ for(efa=em->faces.first; efa; efa= efa->next, efac++, a++) {
+ efac->v1= (int)efa->v1->tmp.l;
+ efac->v2= (int)efa->v2->tmp.l;
+ efac->v3= (int)efa->v3->tmp.l;
+ if(efa->v4) efac->v4= (int)efa->v4->tmp.l;
+ else efac->v4= -1;
+
+ efac->mat_nr= efa->mat_nr;
+ efac->flag= efa->flag;
+ efac->f= efa->f;
+ efac->h= efa->h;
+ efac->fgonf= efa->fgonf;
+
+ efa->tmp.l = a; /*store index*/
+
+ CustomData_from_em_block(&em->fdata, &um->fdata, efa->data, a);
+ }
+
+ a = 0;
+ for(ese=em->selected.first; ese; ese=ese->next, esec++){
+ esec->type = ese->type;
+ if(ese->type == EDITVERT) a = esec->index = ((EditVert*)ese->data)->tmp.l;
+ else if(ese->type == EDITEDGE) a = esec->index = ((EditEdge*)ese->data)->tmp.l;
+ else if(ese->type == EDITFACE) a = esec->index = ((EditFace*)ese->data)->tmp.l;
+ }
+
+ um->retopo_paint_data= retopo_paint_data_copy(em->retopo_paint_data);
+ um->retopo_mode= G.scene->toolsettings->retopo_mode;
+
+ {
+ Multires *mr= get_mesh(G.obedit)->mr;
+ UndoMesh *prev= undo_editmode_get_prev(G.obedit);
+
+ um->mru= NULL;
+
+ if(mr) {
+ if(prev && prev->mru && prev->mru->mr && prev->mru->mr->current == mr->current) {
+ um->mru= prev->mru;
+ ++um->mru->users;
+ }
+ else {
+ um->mru= MEM_callocN(sizeof(EM_MultiresUndo), "EM_MultiresUndo");
+ um->mru->users= 1;
+ um->mru->mr= multires_copy(mr);
+ }
+ }
+ }
+
+ return um;
+}
+
+static void undoMesh_to_editMesh(void *umv)
+{
+ UndoMesh *um= (UndoMesh*)umv;
+ EditMesh *em= G.editMesh;
+ EditVert *eve, **evar=NULL;
+ EditEdge *eed;
+ EditFace *efa;
+ EditSelection *ese;
+ EditVertC *evec;
+ EditEdgeC *eedc;
+ EditFaceC *efac;
+ EditSelectionC *esec;
+ int a=0;
+
+#ifdef WITH_VERSE
+ struct VNode *vnode = G.editMesh->vnode;
+ if(vnode) {
+ /* send delete command to all verse vertexes and verse face ...
+ * verse mesh will be recreated from new edit mesh */
+ destroy_versemesh(vnode);
+ }
+#endif
+ G.scene->selectmode = um->selectmode;
+
+ free_editMesh(G.editMesh);
+
+ /* malloc blocks */
+ memset(em, 0, sizeof(EditMesh));
+
+ init_editmesh_fastmalloc(em, um->totvert, um->totedge, um->totface);
+
+#ifdef WITH_VERSE
+ G.editMesh->vnode = vnode;
+#endif
+
+ CustomData_free(&em->vdata, 0);
+ CustomData_free(&em->edata, 0);
+ CustomData_free(&em->fdata, 0);
+
+ CustomData_copy(&um->vdata, &em->vdata, CD_MASK_EDITMESH, CD_CALLOC, 0);
+ CustomData_copy(&um->edata, &em->edata, CD_MASK_EDITMESH, CD_CALLOC, 0);
+ CustomData_copy(&um->fdata, &em->fdata, CD_MASK_EDITMESH, CD_CALLOC, 0);
+
+ /* now copy vertices */
+
+ if(um->totvert) evar= MEM_mallocN(um->totvert*sizeof(EditVert *), "vertex ar");
+ for(a=0, evec= um->verts; a<um->totvert; a++, evec++) {
+ eve= addvertlist(evec->co, NULL);
+ evar[a]= eve;
+
+ VECCOPY(eve->no, evec->no);
+ eve->f= evec->f;
+ eve->h= evec->h;
+ eve->keyindex= evec->keyindex;
+
+ CustomData_to_em_block(&um->vdata, &em->vdata, a, &eve->data);
+ }
+
+ /* copy edges */
+ for(a=0, eedc= um->edges; a<um->totedge; a++, eedc++) {
+ eed= addedgelist(evar[eedc->v1], evar[eedc->v2], NULL);
+
+ eed->f= eedc->f;
+ eed->h= eedc->h;
+ eed->seam= eedc->seam;
+ eed->sharp= eedc->sharp;
+ eed->fgoni= eedc->fgoni;
+ eed->crease= ((float)eedc->crease)/255.0;
+ CustomData_to_em_block(&um->edata, &em->edata, a, &eed->data);
+ }
+
+ /* copy faces */
+ for(a=0, efac= um->faces; a<um->totface; a++, efac++) {
+ if(efac->v4 != -1)
+ efa= addfacelist(evar[efac->v1], evar[efac->v2], evar[efac->v3], evar[efac->v4], NULL, NULL);
+ else
+ efa= addfacelist(evar[efac->v1], evar[efac->v2], evar[efac->v3], NULL, NULL ,NULL);
+
+ efa->mat_nr= efac->mat_nr;
+ efa->flag= efac->flag;
+ efa->f= efac->f;
+ efa->h= efac->h;
+ efa->fgonf= efac->fgonf;
+
+ CustomData_to_em_block(&um->fdata, &em->fdata, a, &efa->data);
+ }
+
+ end_editmesh_fastmalloc();
+ if(evar) MEM_freeN(evar);
+
+ G.totvert = um->totvert;
+ G.totedge = um->totedge;
+ G.totface = um->totface;
+ /*restore stored editselections*/
+ if(um->totsel){
+ EM_init_index_arrays(1,1,1);
+ for(a=0, esec= um->selected; a<um->totsel; a++, esec++){
+ ese = MEM_callocN(sizeof(EditSelection), "Edit Selection");
+ ese->type = esec->type;
+ if(ese->type == EDITVERT) ese->data = EM_get_vert_for_index(esec->index); else
+ if(ese->type == EDITEDGE) ese->data = EM_get_edge_for_index(esec->index); else
+ if(ese->type == EDITFACE) ese->data = EM_get_face_for_index(esec->index);
+ BLI_addtail(&(em->selected),ese);
+ }
+ EM_free_index_arrays();
+ }
+
+ retopo_free_paint();
+ em->retopo_paint_data= retopo_paint_data_copy(um->retopo_paint_data);
+ G.scene->toolsettings->retopo_mode= um->retopo_mode;
+ if(G.scene->toolsettings->retopo_mode) {
+ if(G.vd->depths) G.vd->depths->damaged= 1;
+ retopo_queue_updates(G.vd);
+ retopo_paint_view_update(G.vd);
+ }
+
+ {
+ Mesh *me= get_mesh(G.obedit);
+ multires_free(me->mr);
+ me->mr= NULL;
+ if(um->mru && um->mru->mr) me->mr= multires_copy(um->mru->mr);
+ }
+}
+
+
+/* and this is all the undo system needs to know */
+void undo_push_mesh(char *name)
+{
+ undo_editmode_push(name, free_undoMesh, undoMesh_to_editMesh, editMesh_to_undoMesh);
+}
+
+
+
+/* *************** END UNDO *************/
+
+static EditVert **g_em_vert_array = NULL;
+static EditEdge **g_em_edge_array = NULL;
+static EditFace **g_em_face_array = NULL;
+
+void EM_init_index_arrays(int forVert, int forEdge, int forFace)
+{
+ EditVert *eve;
+ EditEdge *eed;
+ EditFace *efa;
+ int i;
+
+ if (forVert) {
+ g_em_vert_array = MEM_mallocN(sizeof(*g_em_vert_array)*G.totvert, "em_v_arr");
+
+ for (i=0,eve=G.editMesh->verts.first; eve; i++,eve=eve->next)
+ g_em_vert_array[i] = eve;
+ }
+
+ if (forEdge) {
+ g_em_edge_array = MEM_mallocN(sizeof(*g_em_edge_array)*G.totedge, "em_e_arr");
+
+ for (i=0,eed=G.editMesh->edges.first; eed; i++,eed=eed->next)
+ g_em_edge_array[i] = eed;
+ }
+
+ if (forFace) {
+ g_em_face_array = MEM_mallocN(sizeof(*g_em_face_array)*G.totface, "em_f_arr");
+
+ for (i=0,efa=G.editMesh->faces.first; efa; i++,efa=efa->next)
+ g_em_face_array[i] = efa;
+ }
+}
+
+void EM_free_index_arrays(void)
+{
+ if (g_em_vert_array) MEM_freeN(g_em_vert_array);
+ if (g_em_edge_array) MEM_freeN(g_em_edge_array);
+ if (g_em_face_array) MEM_freeN(g_em_face_array);
+ g_em_vert_array = NULL;
+ g_em_edge_array = NULL;
+ g_em_face_array = NULL;
+}
+
+EditVert *EM_get_vert_for_index(int index)
+{
+ return g_em_vert_array?g_em_vert_array[index]:NULL;
+}
+
+EditEdge *EM_get_edge_for_index(int index)
+{
+ return g_em_edge_array?g_em_edge_array[index]:NULL;
+}
+
+EditFace *EM_get_face_for_index(int index)
+{
+ return g_em_face_array?g_em_face_array[index]:NULL;
+}
+
+/* can we edit UV's for this mesh?*/
+int EM_texFaceCheck(void)
+{
+ /* some of these checks could be a touch overkill */
+ if ( (G.obedit) &&
+ (G.obedit->type == OB_MESH) &&
+ (G.editMesh) &&
+ (G.editMesh->faces.first) &&
+ (CustomData_has_layer(&G.editMesh->fdata, CD_MTFACE)))
+ return 1;
+ return 0;
+}
+
+/* can we edit colors for this mesh?*/
+int EM_vertColorCheck(void)
+{
+ /* some of these checks could be a touch overkill */
+ if ( (G.obedit) &&
+ (G.obedit->type == OB_MESH) &&
+ (G.editMesh) &&
+ (G.editMesh->faces.first) &&
+ (CustomData_has_layer(&G.editMesh->fdata, CD_MCOL)))
+ return 1;
+ return 0;
+}
+
diff --git a/source/blender/src/editmesh_add.c b/source/blender/src/editmesh_add.c
new file mode 100644
index 00000000000..d594a5d94cd
--- /dev/null
+++ b/source/blender/src/editmesh_add.c
@@ -0,0 +1,1349 @@
+/**
+ * $Id:
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_editVert.h"
+
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_utildefines.h"
+
+#ifdef WITH_VERSE
+#include "BKE_verse.h"
+#endif
+
+
+#include "BIF_editmesh.h"
+#include "BIF_graphics.h"
+#include "BIF_interface.h"
+#include "BIF_mywindow.h"
+#include "BIF_retopo.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_toolbox.h"
+#include "BIF_transform.h"
+
+#ifdef WITH_VERSE
+#include "BIF_verse.h"
+#endif
+
+#include "BDR_editobject.h"
+
+#include "BSE_view.h"
+#include "BSE_edit.h"
+
+#include "blendef.h"
+#include "multires.h"
+#include "mydevice.h"
+
+#include "editmesh.h"
+
+/* bpymenu */
+#include "BPY_extern.h"
+#include "BPY_menus.h"
+
+static float icovert[12][3] = {
+ {0,0,-200},
+ {144.72, -105.144,-89.443},
+ {-55.277, -170.128,-89.443},
+ {-178.885,0,-89.443},
+ {-55.277,170.128,-89.443},
+ {144.72,105.144,-89.443},
+ {55.277,-170.128,89.443},
+ {-144.72,-105.144,89.443},
+ {-144.72,105.144,89.443},
+ {55.277,170.128,89.443},
+ {178.885,0,89.443},
+ {0,0,200}
+};
+static short icoface[20][3] = {
+ {1,0,2},
+ {1,0,5},
+ {2,0,3},
+ {3,0,4},
+ {4,0,5},
+ {1,5,10},
+ {2,1,6},
+ {3,2,7},
+ {4,3,8},
+ {5,4,9},
+ {10,1,6},
+ {6,2,7},
+ {7,3,8},
+ {8,4,9},
+ {9,5,10},
+ {6,10,11},
+ {7,6,11},
+ {8,7,11},
+ {9,8,11},
+ {10,9,11}
+};
+
+static void get_view_aligned_coordinate(float *fp)
+{
+ float dvec[3];
+ short mx, my, mval[2];
+
+ getmouseco_areawin(mval);
+ mx= mval[0];
+ my= mval[1];
+
+ project_short_noclip(fp, mval);
+
+ initgrabz(fp[0], fp[1], fp[2]);
+
+ if(mval[0]!=IS_CLIPPED) {
+ window_to_3d(dvec, mval[0]-mx, mval[1]-my);
+ VecSubf(fp, fp, dvec);
+ }
+}
+
+void add_click_mesh(void)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve, *v1;
+ float min[3], max[3];
+ int done= 0;
+
+ TEST_EDITMESH
+ if(multires_test()) return;
+
+ INIT_MINMAX(min, max);
+
+ for(v1= em->verts.first;v1; v1=v1->next) {
+ if(v1->f & SELECT) {
+ DO_MINMAX(v1->co, min, max);
+ done= 1;
+ }
+ }
+
+ /* call extrude? */
+ if(done) {
+ EditEdge *eed;
+ float vec[3], cent[3], mat[3][3];
+ float nor[3]= {0.0, 0.0, 0.0};
+
+ /* check for edges that are half selected, use for rotation */
+ done= 0;
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if( (eed->v1->f & SELECT)+(eed->v2->f & SELECT) == SELECT ) {
+ if(eed->v1->f & SELECT) VecSubf(vec, eed->v1->co, eed->v2->co);
+ else VecSubf(vec, eed->v2->co, eed->v1->co);
+ VecAddf(nor, nor, vec);
+ done= 1;
+ }
+ }
+ if(done) Normalize(nor);
+
+ /* center */
+ VecAddf(cent, min, max);
+ VecMulf(cent, 0.5f);
+ VECCOPY(min, cent);
+
+ Mat4MulVecfl(G.obedit->obmat, min); // view space
+ get_view_aligned_coordinate(min);
+ Mat4Invert(G.obedit->imat, G.obedit->obmat);
+ Mat4MulVecfl(G.obedit->imat, min); // back in object space
+
+ VecSubf(min, min, cent);
+
+ /* calculate rotation */
+ Mat3One(mat);
+ if(done) {
+ float dot;
+
+ VECCOPY(vec, min);
+ Normalize(vec);
+ dot= INPR(vec, nor);
+
+ if( fabs(dot)<0.999) {
+ float cross[3], si, q1[4];
+
+ Crossf(cross, nor, vec);
+ Normalize(cross);
+ dot= 0.5f*saacos(dot);
+ si= (float)sin(dot);
+ q1[0]= (float)cos(dot);
+ q1[1]= cross[0]*si;
+ q1[2]= cross[1]*si;
+ q1[3]= cross[2]*si;
+
+ QuatToMat3(q1, mat);
+ }
+ }
+
+ extrudeflag(SELECT, nor);
+ rotateflag(SELECT, cent, mat);
+ translateflag(SELECT, min);
+
+ recalc_editnormals();
+ }
+ else {
+ float mat[3][3],imat[3][3];
+ float *curs= give_cursor();
+
+ eve= addvertlist(0, NULL);
+
+ Mat3CpyMat4(mat, G.obedit->obmat);
+ Mat3Inv(imat, mat);
+
+ VECCOPY(eve->co, curs);
+ VecSubf(eve->co, eve->co, G.obedit->obmat[3]);
+
+ Mat3MulVecfl(imat, eve->co);
+
+ eve->f= SELECT;
+ }
+
+ retopo_do_all();
+
+ countall();
+
+#ifdef WITH_VERSE
+ if(G.editMesh->vnode) {
+ sync_all_verseverts_with_editverts((VNode*)G.editMesh->vnode);
+ }
+#endif
+
+ BIF_undo_push("Add vertex/edge/face");
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+
+ while(get_mbut()&R_MOUSE);
+
+}
+
+/* selected faces get hidden edges */
+static void make_fgon(int make)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+ EditEdge *eed;
+ EditVert *eve;
+ float *nor=NULL; // reference
+ int done=0;
+
+ if(!make) {
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->f & SELECT) {
+ efa->fgonf= 0;
+ efa->e1->h &= ~EM_FGON;
+ efa->e2->h &= ~EM_FGON;
+ efa->e3->h &= ~EM_FGON;
+ if(efa->e4) efa->e4->h &= ~EM_FGON;
+ }
+ }
+ allqueue(REDRAWVIEW3D, 0);
+ EM_fgon_flags(); // redo flags and indices for fgons
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ BIF_undo_push("Clear FGon");
+ return;
+ }
+
+ /* tagging edges. rule is:
+ - edge used by exactly 2 selected faces
+ - no vertices allowed with only tagged edges (return)
+ - face normals are allowed to difffer
+
+ */
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ eed->f1= 0; // amount of selected
+ eed->f2= 0; // amount of unselected
+ }
+
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->f & SELECT) {
+ if(nor==NULL) nor= efa->n;
+ if(efa->e1->f1 < 3) efa->e1->f1++;
+ if(efa->e2->f1 < 3) efa->e2->f1++;
+ if(efa->e3->f1 < 3) efa->e3->f1++;
+ if(efa->e4 && efa->e4->f1 < 3) efa->e4->f1++;
+ }
+ else {
+ if(efa->e1->f2 < 3) efa->e1->f2++;
+ if(efa->e2->f2 < 3) efa->e2->f2++;
+ if(efa->e3->f2 < 3) efa->e3->f2++;
+ if(efa->e4 && efa->e4->f2 < 3) efa->e4->f2++;
+ }
+ }
+ // now eed->f1 becomes tagged edge
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->f1==2 && eed->f2==0) eed->f1= 1;
+ else eed->f1= 0;
+ }
+
+ // no vertices allowed with only tagged edges
+ for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->f1) {
+ eed->v1->f1 |= 1;
+ eed->v2->f1 |= 1;
+ }
+ else {
+ eed->v1->f1 |= 2;
+ eed->v2->f1 |= 2;
+ }
+ }
+ for(eve= em->verts.first; eve; eve= eve->next) {
+ if(eve->f1==1) break;
+ }
+ if(eve) {
+ error("Cannot make polygon with interior vertices");
+ return;
+ }
+
+ // check for faces
+ if(nor==NULL) {
+ error("No faces selected to make FGon");
+ return;
+ }
+
+ // and there we go
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->f1) {
+ eed->h |= EM_FGON;
+ done= 1;
+ }
+ }
+
+ if(done==0) {
+ error("Didn't find FGon to create");
+ }
+ else {
+ EM_fgon_flags(); // redo flags and indices for fgons
+
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ BIF_undo_push("Make FGon");
+ }
+}
+
+/* precondition; 4 vertices selected, check for 4 edges and create face */
+static EditFace *addface_from_edges(void)
+{
+ EditMesh *em = G.editMesh;
+ EditEdge *eed, *eedar[4]={NULL, NULL, NULL, NULL};
+ EditVert *v1=NULL, *v2=NULL, *v3=NULL, *v4=NULL;
+ int a;
+
+ /* find the 4 edges */
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->f & SELECT) {
+ if(eedar[0]==NULL) eedar[0]= eed;
+ else if(eedar[1]==NULL) eedar[1]= eed;
+ else if(eedar[2]==NULL) eedar[2]= eed;
+ else eedar[3]= eed;
+
+ }
+ }
+
+
+ if(eedar[3]) {
+ /* first 2 points */
+ v1= eedar[0]->v1;
+ v2= eedar[0]->v2;
+
+ /* find the 2 edges connected to first edge */
+ for(a=1; a<4; a++) {
+ if( eedar[a]->v1 == v2) v3= eedar[a]->v2;
+ else if(eedar[a]->v2 == v2) v3= eedar[a]->v1;
+ else if( eedar[a]->v1 == v1) v4= eedar[a]->v2;
+ else if(eedar[a]->v2 == v1) v4= eedar[a]->v1;
+ }
+
+ /* verify if last edge exists */
+ if(v3 && v4) {
+ for(a=1; a<4; a++) {
+ if( eedar[a]->v1==v3 && eedar[a]->v2==v4) break;
+ if( eedar[a]->v2==v3 && eedar[a]->v1==v4) break;
+ }
+ if(a!=4) {
+ return addfacelist(v1, v2, v3, v4, NULL, NULL);
+ }
+ }
+ }
+ return NULL;
+}
+
+/* this also allows to prevent triangles being made in quads */
+static int compareface_overlaps(EditFace *vl1, EditFace *vl2)
+{
+ EditVert *v1, *v2, *v3, *v4;
+ int equal= 0;
+
+ v1= vl2->v1;
+ v2= vl2->v2;
+ v3= vl2->v3;
+ v4= vl2->v4;
+
+ if(vl1==vl2) return 0;
+
+ if(v4==NULL && vl1->v4==NULL) {
+ if(vl1->v1==v1 || vl1->v2==v1 || vl1->v3==v1) equal++;
+ if(vl1->v1==v2 || vl1->v2==v2 || vl1->v3==v2) equal++;
+ if(vl1->v1==v3 || vl1->v2==v3 || vl1->v3==v3) equal++;
+ }
+ else {
+ if(vl1->v1==v1 || vl1->v2==v1 || vl1->v3==v1 || vl1->v4==v1) equal++;
+ if(vl1->v1==v2 || vl1->v2==v2 || vl1->v3==v2 || vl1->v4==v2) equal++;
+ if(vl1->v1==v3 || vl1->v2==v3 || vl1->v3==v3 || vl1->v4==v3) equal++;
+ if(vl1->v1==v4 || vl1->v2==v4 || vl1->v3==v4 || vl1->v4==v4) equal++;
+ }
+
+ if(v4 && vl1->v4) {
+ if(equal==4) return 1;
+ }
+ else
+ if(equal>=3) return 1;
+
+ return 0;
+}
+
+/* checks for existance, and for tria overlapping inside quad */
+static EditFace *exist_face_overlaps(EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa, efatest;
+
+ efatest.v1= v1;
+ efatest.v2= v2;
+ efatest.v3= v3;
+ efatest.v4= v4;
+
+ efa= em->faces.first;
+ while(efa) {
+ if(compareface_overlaps(&efatest, efa)) return efa;
+ efa= efa->next;
+ }
+ return NULL;
+}
+
+/* will be new face smooth or solid? depends on smoothness of face neighbours
+ * of new face, if function return 1, then new face will be smooth, when functio
+ * will return zero, then new face will be solid */
+static void fix_new_face(EditFace *eface)
+{
+ struct EditMesh *em = G.editMesh;
+ struct EditFace *efa;
+ struct EditEdge *eed=NULL;
+ struct EditVert *v1 = eface->v1, *v2 = eface->v2, *v3 = eface->v3, *v4 = eface->v4;
+ struct EditVert *ev1=NULL, *ev2=NULL;
+ short smooth=0; /* "total smoothnes" of faces in neighbourhood */
+ short coef; /* "weight" of smoothness */
+ short count=0; /* number of edges with same direction as eface */
+ short vi00=0, vi01=0, vi10=0, vi11=0; /* vertex indexes */
+
+ efa = em->faces.first;
+
+ while(efa) {
+
+ if(efa==eface) {
+ efa = efa->next;
+ continue;
+ }
+
+ coef = 0;
+ ev1 = ev2 = NULL;
+ eed = NULL;
+
+ if(efa->v1==v1 || efa->v2==v1 || efa->v3==v1 || efa->v4==v1) {
+ ev1 = v1;
+ coef++;
+ }
+ if(efa->v1==v2 || efa->v2==v2 || efa->v3==v2 || efa->v4==v2) {
+ if(ev1) ev2 = v2;
+ else ev1 = v2;
+ coef++;
+ }
+ if(efa->v1==v3 || efa->v2==v3 || efa->v3==v3 || efa->v4==v3) {
+ if(coef<2) {
+ if(ev1) ev2 = v3;
+ else ev1 = v3;
+ }
+ coef++;
+ }
+ if((v4) && (efa->v1==v4 || efa->v2==v4 || efa->v3==v4 || efa->v4==v4)) {
+ if(ev1 && coef<2) ev2 = v4;
+ coef++;
+ }
+
+ /* "democracy" of smoothness */
+ if(efa->flag & ME_SMOOTH)
+ smooth += coef;
+ else
+ smooth -= coef;
+
+ /* try to find edge using vertexes ev1 and ev2 */
+ if((ev1) && (ev2) && (ev1!=ev2)) eed = findedgelist(ev1, ev2);
+
+ /* has bordering edge of efa same direction as edge of eface ? */
+ if(eed) {
+ if(eed->v1==v1) vi00 = 1;
+ else if(eed->v1==v2) vi00 = 2;
+ else if(eed->v1==v3) vi00 = 3;
+ else if(v4 && eed->v1==v4) vi00 = 4;
+
+ if(eed->v2==v1) vi01 = 1;
+ else if(eed->v2==v2) vi01 = 2;
+ else if(eed->v2==v3) vi01 = 3;
+ else if(v4 && eed->v2==v4) vi01 = 4;
+
+ if(v4) {
+ if(vi01==1 && vi00==4) vi00 = 0;
+ if(vi01==4 && vi00==1) vi01 = 0;
+ }
+ else {
+ if(vi01==1 && vi00==3) vi00 = 0;
+ if(vi01==3 && vi00==1) vi01 = 0;
+ }
+
+ if(eed->v1==efa->v1) vi10 = 1;
+ else if(eed->v1==efa->v2) vi10 = 2;
+ else if(eed->v1==efa->v3) vi10 = 3;
+ else if(efa->v4 && eed->v1==efa->v4) vi10 = 4;
+
+ if(eed->v2==efa->v1) vi11 = 1;
+ else if(eed->v2==efa->v2) vi11 = 2;
+ else if(eed->v2==efa->v3) vi11 = 3;
+ else if(efa->v4 && eed->v2==efa->v4) vi11 = 4;
+
+ if(efa->v4) {
+ if(vi11==1 && vi10==4) vi10 = 0;
+ if(vi11==4 && vi10==1) vi11 = 0;
+ }
+ else {
+ if(vi11==1 && vi10==3) vi10 = 0;
+ if(vi11==3 && vi10==1) vi11 = 0;
+ }
+
+ if(((vi00>vi01) && (vi10>vi11)) ||
+ ((vi00<vi01) && (vi10<vi11)))
+ count++;
+ else
+ count--;
+ }
+
+ efa = efa->next;
+ }
+
+ /* set up smoothness according voting of face in neighbourhood */
+ if(smooth >= 0)
+ eface->flag |= ME_SMOOTH;
+ else
+ eface->flag &= ~ME_SMOOTH;
+
+ /* flip face, when too much "face normals" in neighbourhood is different */
+ if(count > 0) {
+ flipface(eface);
+#ifdef WITH_VERSE
+ if(eface->vface) {
+ struct VNode *vnode;
+ struct VLayer *vlayer;
+ vnode = (VNode*)((Mesh*)G.obedit->data)->vnode;
+ vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER);
+ add_item_to_send_queue(&(vlayer->queue), (void*)eface->vface, VERSE_FACE);
+ }
+#endif
+ }
+}
+
+void addfaces_from_edgenet()
+{
+ EditVert *eve1, *eve2, *eve3, *eve4;
+ EditMesh *em= G.editMesh;
+
+ for(eve1= em->verts.first; eve1; eve1= eve1->next) {
+ for(eve2= em->verts.first; (eve1->f & 1) && eve2; eve2= eve2->next) {
+ if(findedgelist(eve1,eve2)) {
+ for(eve3= em->verts.first; (eve2->f & 1) && eve3; eve3= eve3->next) {
+ if((eve2!=eve3 && (eve3->f & 1) && findedgelist(eve1,eve3))) {
+ EditEdge *sh_edge= NULL;
+ EditVert *sh_vert= NULL;
+
+ sh_edge= findedgelist(eve2,eve3);
+
+ if(sh_edge) { /* Add a triangle */
+ if(!exist_face_overlaps(eve1,eve2,eve3,NULL))
+ fix_new_face(addfacelist(eve1,eve2,eve3,NULL,NULL,NULL));
+ }
+ else { /* Check for a shared vertex */
+ for(eve4= em->verts.first; eve4; eve4= eve4->next) {
+ if(eve4!=eve1 && eve4!=eve2 && eve4!=eve3 && (eve4->f & 1) &&
+ !findedgelist(eve1,eve4) && findedgelist(eve2,eve4) &&
+ findedgelist(eve3,eve4)) {
+ sh_vert= eve4;
+ break;
+ }
+ }
+
+ if(sh_vert) {
+ if(sh_vert) {
+ if(!exist_face_overlaps(eve1,eve2,eve4,eve3))
+ fix_new_face(addfacelist(eve1,eve2,eve4,eve3,NULL,NULL));
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ countall();
+
+ EM_select_flush();
+
+ BIF_undo_push("Add faces");
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+}
+
+void addedgeface_mesh(void)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve, *neweve[4];
+ EditEdge *eed;
+ EditFace *efa;
+ short amount=0;
+
+ if( (G.vd->lay & G.obedit->lay)==0 ) return;
+ if(multires_test()) return;
+
+ /* how many selected ? */
+ if(G.scene->selectmode & SCE_SELECT_EDGE) {
+ /* in edge mode finding selected vertices means flushing down edge codes... */
+ /* can't make face with only edge selection info... */
+ EM_selectmode_set();
+ }
+
+ for(eve= em->verts.first; eve; eve= eve->next) {
+ if(eve->f & SELECT) {
+ amount++;
+ if(amount>4) break;
+ neweve[amount-1]= eve;
+ }
+ }
+
+ if(amount==2) {
+ eed= addedgelist(neweve[0], neweve[1], NULL);
+ EM_select_edge(eed, 1);
+ BIF_undo_push("Add edge");
+ allqueue(REDRAWVIEW3D, 0);
+ countall();
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ return;
+ }
+ else if(amount > 4) {
+
+ /* Python Menu */
+ BPyMenu *pym;
+ char menu_number[3];
+ int i=0, has_pymenu=0, ret;
+
+ /* facemenu, will add python items */
+ char facemenu[4096]= "Make Faces%t|Auto%x1|Make FGon%x2|Clear FGon%x3";
+
+ /* note that we account for the 10 previous entries with i+4: */
+ for (pym = BPyMenuTable[PYMENU_MESHFACEKEY]; pym; pym = pym->next, i++) {
+
+ if (!has_pymenu) {
+ strcat(facemenu, "|%l");
+ has_pymenu = 1;
+ }
+
+ strcat(facemenu, "|");
+ strcat(facemenu, pym->name);
+ strcat(facemenu, " %x");
+ sprintf(menu_number, "%d", i+4);
+ strcat(facemenu, menu_number);
+ }
+
+ ret= pupmenu(facemenu);
+
+ if(ret==1) addfaces_from_edgenet();
+ else if(ret==2) make_fgon(1);
+ else if(ret==3) make_fgon(0);
+ else if (ret >= 4) {
+ BPY_menu_do_python(PYMENU_MESHFACEKEY, ret - 4);
+ return;
+ }
+ return;
+ }
+ else if(amount<2) {
+ error("Incorrect number of vertices to make edge/face");
+ return;
+ }
+
+ efa= NULL; // check later
+
+ if(amount==3) {
+
+ if(exist_face_overlaps(neweve[0], neweve[1], neweve[2], NULL)==0) {
+ efa= addfacelist(neweve[0], neweve[1], neweve[2], 0, NULL, NULL);
+ EM_select_face(efa, 1);
+ }
+ else error("The selected vertices already form a face");
+ }
+ else if(amount==4) {
+ /* this test survives when theres 2 triangles */
+ if(exist_face(neweve[0], neweve[1], neweve[2], neweve[3])==0) {
+ int tria= 0;
+
+ /* remove trias if they exist, 4 cases.... */
+ if(exist_face(neweve[0], neweve[1], neweve[2], NULL)) tria++;
+ if(exist_face(neweve[0], neweve[1], neweve[3], NULL)) tria++;
+ if(exist_face(neweve[0], neweve[2], neweve[3], NULL)) tria++;
+ if(exist_face(neweve[1], neweve[2], neweve[3], NULL)) tria++;
+
+ if(tria==2) join_triangles();
+ else if(exist_face_overlaps(neweve[0], neweve[1], neweve[2], neweve[3])==0) {
+ /* If there are 4 Verts, But more selected edges, we need to call addfaces_from_edgenet */
+ EditEdge *eedcheck;
+ int count;
+ count = 0;
+ for(eedcheck= em->edges.first; eedcheck; eedcheck= eedcheck->next) {
+ if(eedcheck->f & SELECT) {
+ count++;
+ }
+ }
+
+ if(count++ > 4){
+ addfaces_from_edgenet();
+ return;
+ } else {
+ /* if 4 edges exist, we just create the face, convex or not */
+ efa= addface_from_edges();
+ if(efa==NULL) {
+ /* the order of vertices can be anything, 6 cases to check */
+ if( convex(neweve[0]->co, neweve[1]->co, neweve[2]->co, neweve[3]->co) ) {
+ efa= addfacelist(neweve[0], neweve[1], neweve[2], neweve[3], NULL, NULL);
+ }
+ else if( convex(neweve[0]->co, neweve[2]->co, neweve[3]->co, neweve[1]->co) ) {
+ efa= addfacelist(neweve[0], neweve[2], neweve[3], neweve[1], NULL, NULL);
+ }
+ else if( convex(neweve[0]->co, neweve[2]->co, neweve[1]->co, neweve[3]->co) ) {
+ efa= addfacelist(neweve[0], neweve[2], neweve[1], neweve[3], NULL, NULL);
+ }
+
+ else if( convex(neweve[1]->co, neweve[2]->co, neweve[3]->co, neweve[0]->co) ) {
+ efa= addfacelist(neweve[1], neweve[2], neweve[3], neweve[0], NULL, NULL);
+ }
+ else if( convex(neweve[1]->co, neweve[3]->co, neweve[0]->co, neweve[2]->co) ) {
+ efa= addfacelist(neweve[1], neweve[3], neweve[0], neweve[2], NULL, NULL);
+ }
+ else if( convex(neweve[1]->co, neweve[3]->co, neweve[2]->co, neweve[0]->co) ) {
+ efa= addfacelist(neweve[1], neweve[3], neweve[2], neweve[0], NULL, NULL);
+ }
+ else error("The selected vertices form a concave quad");
+ }
+ }
+ }
+ else error("The selected vertices already form a face");
+ }
+ else error("The selected vertices already form a face");
+ }
+
+ if(efa) {
+ EM_select_face(efa, 1);
+
+ fix_new_face(efa);
+
+ recalc_editnormals();
+ BIF_undo_push("Add face");
+ }
+
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+}
+
+
+void adduplicate_mesh(void)
+{
+
+ TEST_EDITMESH
+ if(multires_test()) return;
+
+ waitcursor(1);
+
+ adduplicateflag(SELECT);
+
+ waitcursor(0);
+ countall();
+
+ /* We need to force immediate calculation here because
+ * transform may use derived objects (which are now stale).
+ *
+ * This shouldn't be necessary, derived queries should be
+ * automatically building this data if invalid. Or something.
+ */
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ object_handle_update(G.obedit);
+
+ BIF_TransformSetUndo("Add Duplicate");
+ initTransform(TFM_TRANSLATION, CTX_NO_PET);
+ Transform();
+}
+
+/* check whether an object to add mesh to exists, if not, create one
+* returns 1 if new object created, else 0 */
+int confirm_objectExists( Mesh **me, float mat[][3] )
+{
+ int newob = 0;
+
+ /* deselectall */
+ EM_clear_flag_all(SELECT);
+
+ /* if no obedit: new object and enter editmode */
+ if(G.obedit==NULL) {
+ /* add_object actually returns an object ! :-)
+ But it also stores the added object struct in
+ G.scene->basact->object (BASACT->object) */
+
+ add_object_draw(OB_MESH);
+
+ G.obedit= BASACT->object;
+
+ where_is_object(G.obedit);
+
+ make_editMesh();
+ setcursor_space(SPACE_VIEW3D, CURSOR_EDIT);
+ newob= 1;
+ }
+ *me = G.obedit->data;
+
+ /* imat and center and size */
+ Mat3CpyMat4(mat, G.obedit->obmat);
+
+ return newob;
+}
+
+void make_prim(int type, float imat[3][3], int tot, int seg,
+ int subdiv, float dia, float d, int ext, int fill,
+ float cent[3])
+{
+ /*
+ * type - for the type of shape
+ * dia - the radius for cone,sphere cylinder etc.
+ * d - depth for the cone
+ * ext - ?
+ * fill - end capping, and option to fill in circle
+ * cent[3] - center of the data.
+ * */
+
+ EditMesh *em = G.editMesh;
+ EditVert *eve, *v1=NULL, *v2, *v3, *v4=NULL, *vtop, *vdown;
+ float phi, phid, vec[3];
+ float q[4], cmat[3][3], nor[3]= {0.0, 0.0, 0.0};
+ short a, b;
+
+ phid= 2*M_PI/tot;
+ phi= .25*M_PI;
+
+ switch(type) {
+ case 10: /* grid */
+ /* clear flags */
+ eve= em->verts.first;
+ while(eve) {
+ eve->f= 0;
+ eve= eve->next;
+ }
+ /* one segment first: the X axis */
+ phi= 1.0;
+ phid= 2.0/((float)tot-1);
+ for(a=0;a<tot;a++) {
+ vec[0]= cent[0]+dia*phi;
+ vec[1]= cent[1]- dia;
+ vec[2]= cent[2];
+ Mat3MulVecfl(imat,vec);
+ eve= addvertlist(vec, NULL);
+ eve->f= 1+2+4;
+ if (a) {
+ addedgelist(eve->prev, eve, NULL);
+ }
+ phi-=phid;
+ }
+ /* extrude and translate */
+ vec[0]= vec[2]= 0.0;
+ vec[1]= dia*phid;
+ Mat3MulVecfl(imat, vec);
+ for(a=0;a<seg-1;a++) {
+ extrudeflag_vert(2, nor); // nor unused
+ translateflag(2, vec);
+ }
+ break;
+ case 11: /* UVsphere */
+
+ /* clear all flags */
+ eve= em->verts.first;
+ while(eve) {
+ eve->f= 0;
+ eve= eve->next;
+ }
+
+ /* one segment first */
+ phi= 0;
+ phid/=2;
+ for(a=0; a<=tot; a++) {
+ vec[0]= dia*sin(phi);
+ vec[1]= 0.0;
+ vec[2]= dia*cos(phi);
+ eve= addvertlist(vec, NULL);
+ eve->f= 1+2+4;
+ if(a==0) v1= eve;
+ else addedgelist(eve->prev, eve, NULL);
+ phi+= phid;
+ }
+
+ /* extrude and rotate */
+ phi= M_PI/seg;
+ q[0]= cos(phi);
+ q[3]= sin(phi);
+ q[1]=q[2]= 0;
+ QuatToMat3(q, cmat);
+
+ for(a=0; a<seg; a++) {
+ extrudeflag_vert(2, nor); // nor unused
+ rotateflag(2, v1->co, cmat);
+ }
+
+ removedoublesflag(4, 0, 0.0001);
+
+ /* and now do imat */
+ eve= em->verts.first;
+ while(eve) {
+ if(eve->f & SELECT) {
+ VecAddf(eve->co,eve->co,cent);
+ Mat3MulVecfl(imat,eve->co);
+ }
+ eve= eve->next;
+ }
+ break;
+ case 12: /* Icosphere */
+ {
+ EditVert *eva[12];
+ EditEdge *eed;
+
+ /* clear all flags */
+ eve= em->verts.first;
+ while(eve) {
+ eve->f= 0;
+ eve= eve->next;
+ }
+ dia/=200;
+ for(a=0;a<12;a++) {
+ vec[0]= dia*icovert[a][0];
+ vec[1]= dia*icovert[a][1];
+ vec[2]= dia*icovert[a][2];
+ eva[a]= addvertlist(vec, NULL);
+ eva[a]->f= 1+2;
+ }
+ for(a=0;a<20;a++) {
+ EditFace *evtemp;
+ v1= eva[ icoface[a][0] ];
+ v2= eva[ icoface[a][1] ];
+ v3= eva[ icoface[a][2] ];
+ evtemp = addfacelist(v1, v2, v3, 0, NULL, NULL);
+ evtemp->e1->f = 1+2;
+ evtemp->e2->f = 1+2;
+ evtemp->e3->f = 1+2;
+ }
+
+ dia*=200;
+ for(a=1; a<subdiv; a++) esubdivideflag(2, dia, 0,1,0);
+ /* and now do imat */
+ eve= em->verts.first;
+ while(eve) {
+ if(eve->f & 2) {
+ VecAddf(eve->co,eve->co,cent);
+ Mat3MulVecfl(imat,eve->co);
+ }
+ eve= eve->next;
+ }
+
+ // Clear the flag 2 from the edges
+ for(eed=em->edges.first;eed;eed=eed->next){
+ if(eed->f & 2){
+ eed->f &= !2;
+ }
+ }
+ }
+ break;
+ case 13: /* Monkey */
+ {
+ extern int monkeyo, monkeynv, monkeynf;
+ extern signed char monkeyf[][4];
+ extern signed char monkeyv[][3];
+ EditVert **tv= MEM_mallocN(sizeof(*tv)*monkeynv*2, "tv");
+ EditFace *efa;
+ int i;
+
+ for (i=0; i<monkeynv; i++) {
+ float v[3];
+ v[0]= (monkeyv[i][0]+127)/128.0, v[1]= monkeyv[i][1]/128.0, v[2]= monkeyv[i][2]/128.0;
+ tv[i]= addvertlist(v, NULL);
+ tv[i]->f |= SELECT;
+ tv[monkeynv+i]= (fabs(v[0]= -v[0])<0.001)?tv[i]:addvertlist(v, NULL);
+ tv[monkeynv+i]->f |= SELECT;
+ }
+ for (i=0; i<monkeynf; i++) {
+ efa= addfacelist(tv[monkeyf[i][0]+i-monkeyo], tv[monkeyf[i][1]+i-monkeyo], tv[monkeyf[i][2]+i-monkeyo], (monkeyf[i][3]!=monkeyf[i][2])?tv[monkeyf[i][3]+i-monkeyo]:NULL, NULL, NULL);
+ efa= addfacelist(tv[monkeynv+monkeyf[i][2]+i-monkeyo], tv[monkeynv+monkeyf[i][1]+i-monkeyo], tv[monkeynv+monkeyf[i][0]+i-monkeyo], (monkeyf[i][3]!=monkeyf[i][2])?tv[monkeynv+monkeyf[i][3]+i-monkeyo]:NULL, NULL, NULL);
+ }
+
+ MEM_freeN(tv);
+
+ /* and now do imat */
+ for(eve= em->verts.first; eve; eve= eve->next) {
+ if(eve->f & SELECT) {
+ VecAddf(eve->co,eve->co,cent);
+ Mat3MulVecfl(imat,eve->co);
+ }
+ }
+ recalc_editnormals();
+ }
+ break;
+ default: /* all types except grid, sphere... */
+ if(ext==0 && type!=7) d= 0;
+
+ /* vertices */
+ vtop= vdown= v1= v2= 0;
+ for(b=0; b<=ext; b++) {
+ for(a=0; a<tot; a++) {
+
+ vec[0]= cent[0]+dia*sin(phi);
+ vec[1]= cent[1]+dia*cos(phi);
+ vec[2]= cent[2]+d;
+
+ Mat3MulVecfl(imat, vec);
+ eve= addvertlist(vec, NULL);
+ eve->f= SELECT;
+ if(a==0) {
+ if(b==0) v1= eve;
+ else v2= eve;
+ }
+ phi+=phid;
+ }
+ d= -d;
+ }
+ /* center vertices */
+ /* type 7, a cone can only have 1 one side filled
+ * if the cone has no capping, dont add vtop */
+ if((fill && type>1) || type == 7) {
+ VECCOPY(vec,cent);
+ vec[2]-= -d;
+ Mat3MulVecfl(imat,vec);
+ vdown= addvertlist(vec, NULL);
+ if((ext || type==7) && fill) {
+ VECCOPY(vec,cent);
+ vec[2]-= d;
+ Mat3MulVecfl(imat,vec);
+ vtop= addvertlist(vec, NULL);
+ }
+ } else {
+ vdown= v1;
+ vtop= v2;
+ }
+ if(vtop) vtop->f= SELECT;
+ if(vdown) vdown->f= SELECT;
+
+ /* top and bottom face */
+ if(fill || type==7) {
+ if(tot==4 && (type==0 || type==1)) {
+ v3= v1->next->next;
+ if(ext) v4= v2->next->next;
+
+ addfacelist(v3, v1->next, v1, v3->next, NULL, NULL);
+ if(ext) addfacelist(v2, v2->next, v4, v4->next, NULL, NULL);
+
+ }
+ else {
+ v3= v1;
+ v4= v2;
+ for(a=1; a<tot; a++) {
+ addfacelist(vdown, v3, v3->next, 0, NULL, NULL);
+ v3= v3->next;
+ if(ext && fill) {
+ addfacelist(vtop, v4, v4->next, 0, NULL, NULL);
+ v4= v4->next;
+ }
+ }
+ if(type>1) {
+ addfacelist(vdown, v3, v1, 0, NULL, NULL);
+ if(ext) addfacelist(vtop, v4, v2, 0, NULL, NULL);
+ }
+ }
+ }
+ else if(type==4) { /* we need edges for a circle */
+ v3= v1;
+ for(a=1;a<tot;a++) {
+ addedgelist(v3, v3->next, NULL);
+ v3= v3->next;
+ }
+ addedgelist(v3, v1, NULL);
+ }
+ /* side faces */
+ if(ext) {
+ v3= v1;
+ v4= v2;
+ for(a=1; a<tot; a++) {
+ addfacelist(v3, v3->next, v4->next, v4, NULL, NULL);
+ v3= v3->next;
+ v4= v4->next;
+ }
+ addfacelist(v3, v1, v2, v4, NULL, NULL);
+ }
+ else if(type==7 && fill) {
+ /* add the bottom flat area of the cone
+ * if capping is disabled dont bother */
+ v3= v1;
+ for(a=1; a<tot; a++) {
+ addfacelist(vtop, v3->next, v3, 0, NULL, NULL);
+ v3= v3->next;
+ }
+ addfacelist(vtop, v1, v3, 0, NULL, NULL);
+ }
+ }
+ /* simple selection flush OK, based on fact it's a single model */
+ EM_select_flush(); /* flushes vertex -> edge -> face selection */
+
+ if(type!=0 && type!=13)
+ righthandfaces(1); /* otherwise monkey has eyes in wrong direction */
+}
+
+void add_primitiveMesh(int type)
+{
+ Mesh *me;
+ float *curs, d, dia, phi, phid, cent[3], imat[3][3], mat[3][3];
+ float cmat[3][3];
+ static int tot=32, seg=32, subdiv=2,
+ /* so each type remembers its fill setting */
+ fill_circle=0, fill_cone=1, fill_cylinder=1;
+
+ int ext=0, fill=0, totoud, newob=0;
+ char *undostr="Add Primitive";
+ char *name=NULL;
+
+ if(G.scene->id.lib) return;
+
+ /* this function also comes from an info window */
+ if ELEM(curarea->spacetype, SPACE_VIEW3D, SPACE_INFO); else return;
+ if(G.vd==0) return;
+
+ if (G.obedit && G.obedit->type==OB_MESH && multires_test()) return;
+
+ /* if editmode exists for other type, it exits */
+ check_editmode(OB_MESH);
+
+ if(G.f & (G_VERTEXPAINT+G_TEXTUREPAINT)) {
+ G.f &= ~(G_VERTEXPAINT+G_TEXTUREPAINT);
+ setcursor_space(SPACE_VIEW3D, CURSOR_EDIT);
+ }
+
+ totoud= tot; /* store, and restore when cube/plane */
+
+ dia= G.vd->grid;
+ d= G.vd->grid;
+
+ /* ext==extrudeflag, tot==amount of vertices in basis */
+ switch(type) {
+ case 0: /* plane */
+ tot= 4;
+ ext= 0;
+ fill= 1;
+ newob = confirm_objectExists( &me, mat );
+ if(newob) name = "Plane";
+ undostr="Add Plane";
+ break;
+ case 1: /* cube */
+ tot= 4;
+ ext= 1;
+ fill= 1;
+ newob = confirm_objectExists( &me, mat );
+ if(newob) name = "Cube";
+ undostr="Add Cube";
+ break;
+ case 4: /* circle */
+ add_numbut(0, NUM|INT, "Vertices:", 3, 500, &tot, NULL);
+ add_numbut(1, NUM|FLO, "Radius:", 0.001*G.vd->grid, 100*G.vd->grid, &dia, NULL);
+ add_numbut(2, TOG|INT, "Fill", 0, 0, &(fill_circle), NULL);
+ if (!(do_clever_numbuts("Add Circle", 3, REDRAW))) return;
+ ext= 0;
+ fill = fill_circle;
+ newob = confirm_objectExists( &me, mat );
+ if(newob) name = "Circle";
+ undostr="Add Circle";
+ break;
+ case 5: /* cylinder */
+ d*=2;
+ add_numbut(0, NUM|INT, "Vertices:", 2, 500, &tot, NULL);
+ add_numbut(1, NUM|FLO, "Radius:", 0.001*G.vd->grid, 100*G.vd->grid, &dia, NULL);
+ add_numbut(2, NUM|FLO, "Depth:", 0.001*G.vd->grid, 100*G.vd->grid, &d, NULL);
+ add_numbut(3, TOG|INT, "Cap Ends", 0, 0, &(fill_cylinder), NULL);
+ if (!(do_clever_numbuts("Add Cylinder", 4, REDRAW))) return;
+ ext= 1;
+ fill = fill_cylinder;
+ d/=2;
+ newob = confirm_objectExists( &me, mat );
+ if(newob) {
+ if (fill) name = "Cylinder";
+ else name = "Tube";
+ }
+ undostr="Add Cylinder";
+ break;
+ case 7: /* cone */
+ d*=2;
+ add_numbut(0, NUM|INT, "Vertices:", 2, 500, &tot, NULL);
+ add_numbut(1, NUM|FLO, "Radius:", 0.001*G.vd->grid, 100*G.vd->grid, &dia, NULL);
+ add_numbut(2, NUM|FLO, "Depth:", 0.001*G.vd->grid, 100*G.vd->grid, &d, NULL);
+ add_numbut(3, TOG|INT, "Cap End", 0, 0, &(fill_cone), NULL);
+ if (!(do_clever_numbuts("Add Cone", 4, REDRAW))) return;
+ d/=2;
+ ext= 0;
+ fill = fill_cone;
+ newob = confirm_objectExists( &me, mat );
+ if(newob) name = "Cone";
+ undostr="Add Cone";
+ break;
+ case 10: /* grid */
+ add_numbut(0, NUM|INT, "X res:", 3, 1000, &tot, NULL);
+ add_numbut(1, NUM|INT, "Y res:", 3, 1000, &seg, NULL);
+ if (!(do_clever_numbuts("Add Grid", 2, REDRAW))) return;
+ newob = confirm_objectExists( &me, mat );
+ if(newob) name = "Grid";
+ undostr="Add Grid";
+ break;
+ case 11: /* UVsphere */
+ add_numbut(0, NUM|INT, "Segments:", 3, 500, &seg, NULL);
+ add_numbut(1, NUM|INT, "Rings:", 3, 500, &tot, NULL);
+ add_numbut(2, NUM|FLO, "Radius:", 0.001*G.vd->grid, 100*G.vd->grid, &dia, NULL);
+
+ if (!(do_clever_numbuts("Add UV Sphere", 3, REDRAW))) return;
+
+ newob = confirm_objectExists( &me, mat );
+ if(newob) name = "Sphere";
+ undostr="Add UV Sphere";
+ break;
+ case 12: /* Icosphere */
+ add_numbut(0, NUM|INT, "Subdivision:", 1, 500, &subdiv, NULL);
+ add_numbut(1, NUM|FLO, "Radius:", 0.001*G.vd->grid, 100*G.vd->grid, &dia, NULL);
+ if (!(do_clever_numbuts("Add Ico Sphere", 2, REDRAW))) return;
+
+ newob = confirm_objectExists( &me, mat );
+ if(newob) name = "Sphere";
+ undostr="Add Ico Sphere";
+ break;
+ case 13: /* Monkey */
+ newob = confirm_objectExists( &me, mat );
+ if(newob) name = "Suzanne";
+ undostr="Add Monkey";
+ break;
+ default:
+ newob = confirm_objectExists( &me, mat );
+ break;
+ }
+
+ if( name!=NULL ) {
+ rename_id((ID *)G.obedit, name );
+ rename_id((ID *)me, name );
+ }
+
+ d = -d;
+ curs= give_cursor();
+ VECCOPY(cent, curs);
+ cent[0]-= G.obedit->obmat[3][0];
+ cent[1]-= G.obedit->obmat[3][1];
+ cent[2]-= G.obedit->obmat[3][2];
+
+ if ( !(newob) || U.flag & USER_ADD_VIEWALIGNED) Mat3CpyMat4(imat, G.vd->viewmat);
+ else Mat3One(imat);
+ Mat3MulVecfl(imat, cent);
+ Mat3MulMat3(cmat, imat, mat);
+ Mat3Inv(imat,cmat);
+
+
+ if(type == 0 || type == 1) /* plane, cube (diameter of 1.41 makes it unit size) */
+ dia *= sqrt(2.0);
+
+ phid= 2*M_PI/tot;
+ phi= .25*M_PI;
+
+ make_prim(type, imat, tot, seg, subdiv, dia, d, ext, fill, cent);
+
+ if(type<2) tot = totoud;
+
+ /* simple selection flush OK, based on fact it's a single model */
+ EM_select_flush(); // flushes vertex -> edge -> face selection
+
+ if(type!=0 && type!=13) righthandfaces(1); /* otherwise monkey has eyes in wrong direction... */
+ countall();
+
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+
+ /* if a new object was created, it stores it in Mesh, for reload original data and undo */
+ if ( !(newob) || U.flag & USER_ADD_EDITMODE) {
+ if(newob) load_editMesh();
+ } else {
+ exit_editmode(2);
+ }
+
+ allqueue(REDRAWINFO, 1); /* 1, because header->win==0! */
+ allqueue(REDRAWALL, 0);
+
+ BIF_undo_push(undostr);
+}
+
diff --git a/source/blender/src/editmesh_lib.c b/source/blender/src/editmesh_lib.c
new file mode 100644
index 00000000000..14a522bdbff
--- /dev/null
+++ b/source/blender/src/editmesh_lib.c
@@ -0,0 +1,2207 @@
+/**
+ * $Id:
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/*
+
+editmesh_lib: generic (no UI, no menus) operations/evaluators for editmesh data
+
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_editVert.h"
+
+#include "BKE_customdata.h"
+#include "BKE_global.h"
+#include "BKE_mesh.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_editmesh.h"
+
+#ifdef WITH_VERSE
+#include "BIF_verse.h"
+#endif
+
+#include "BSE_edit.h"
+
+#include "editmesh.h"
+
+/* this replaces the active flag used in uv/face mode */
+void EM_set_actFace(EditFace *efa)
+{
+ G.editMesh->act_face = efa;
+}
+
+EditFace * EM_get_actFace(void)
+{
+ return G.editMesh->act_face;
+}
+
+/* ********* Selection History ************ */
+static int EM_check_selection(void *data)
+{
+ EditSelection *ese;
+
+ for(ese = G.editMesh->selected.first; ese; ese = ese->next){
+ if(ese->data == data) return 1;
+ }
+
+ return 0;
+}
+
+void EM_remove_selection(void *data, int type)
+{
+ EditSelection *ese;
+ for(ese=G.editMesh->selected.first; ese; ese = ese->next){
+ if(ese->data == data){
+ BLI_freelinkN(&(G.editMesh->selected),ese);
+ break;
+ }
+ }
+}
+
+void EM_store_selection(void *data, int type)
+{
+ EditSelection *ese;
+ if(!EM_check_selection(data)){
+ ese = (EditSelection*) MEM_callocN( sizeof(EditSelection), "Edit Selection");
+ ese->type = type;
+ ese->data = data;
+ BLI_addtail(&(G.editMesh->selected),ese);
+ }
+}
+
+void EM_validate_selections(void)
+{
+ EditSelection *ese, *nextese;
+ EditMesh *em = G.editMesh;
+ ese = em->selected.first;
+ while(ese){
+ nextese = ese->next;
+ if(ese->type == EDITVERT && !(((EditVert*)ese->data)->f & SELECT)) BLI_freelinkN(&(em->selected), ese);
+ else if(ese->type == EDITEDGE && !(((EditEdge*)ese->data)->f & SELECT)) BLI_freelinkN(&(em->selected), ese);
+ else if(ese->type == EDITFACE && !(((EditFace*)ese->data)->f & SELECT)) BLI_freelinkN(&(em->selected), ese);
+ ese = nextese;
+ }
+}
+
+static void EM_strip_selections(void)
+{
+ EditSelection *ese, *nextese;
+ if(!(G.scene->selectmode & SCE_SELECT_VERTEX)){
+ ese = G.editMesh->selected.first;
+ while(ese){
+ nextese = ese->next;
+ if(ese->type == EDITVERT) BLI_freelinkN(&(G.editMesh->selected),ese);
+ ese = nextese;
+ }
+ }
+ if(!(G.scene->selectmode & SCE_SELECT_EDGE)){
+ ese=G.editMesh->selected.first;
+ while(ese){
+ nextese = ese->next;
+ if(ese->type == EDITEDGE) BLI_freelinkN(&(G.editMesh->selected), ese);
+ ese = nextese;
+ }
+ }
+ if(!(G.scene->selectmode & SCE_SELECT_FACE)){
+ ese=G.editMesh->selected.first;
+ while(ese){
+ nextese = ese->next;
+ if(ese->type == EDITFACE) BLI_freelinkN(&(G.editMesh->selected), ese);
+ ese = nextese;
+ }
+ }
+}
+
+/* generic way to get data from an EditSelection type
+These functions were written to be used by the Modifier widget when in Rotate about active mode,
+but can be used anywhere.
+EM_editselection_center
+EM_editselection_normal
+EM_editselection_plane
+*/
+void EM_editselection_center(float *center, EditSelection *ese)
+{
+ if (ese->type==EDITVERT) {
+ EditVert *eve= ese->data;
+ VecCopyf(center, eve->co);
+ } else if (ese->type==EDITEDGE) {
+ EditEdge *eed= ese->data;
+ VecAddf(center, eed->v1->co, eed->v2->co);
+ VecMulf(center, 0.5);
+ } else if (ese->type==EDITFACE) {
+ EditFace *efa= ese->data;
+ VecCopyf(center, efa->cent);
+ }
+}
+
+void EM_editselection_normal(float *normal, EditSelection *ese)
+{
+ if (ese->type==EDITVERT) {
+ EditVert *eve= ese->data;
+ VecCopyf(normal, eve->no);
+ } else if (ese->type==EDITEDGE) {
+ EditEdge *eed= ese->data;
+ float plane[3]; /* need a plane to correct the normal */
+ float vec[3]; /* temp vec storage */
+
+ VecAddf(normal, eed->v1->no, eed->v2->no);
+ VecSubf(plane, eed->v2->co, eed->v1->co);
+
+ /* the 2 vertex normals will be close but not at rightangles to the edge
+ for rotate about edge we want them to be at right angles, so we need to
+ do some extra colculation to correct the vert normals,
+ we need the plane for this */
+ Crossf(vec, normal, plane);
+ Crossf(normal, plane, vec);
+ Normalize(normal);
+
+ } else if (ese->type==EDITFACE) {
+ EditFace *efa= ese->data;
+ VecCopyf(normal, efa->n);
+ }
+}
+
+/* Calculate a plane that is rightangles to the edge/vert/faces normal
+also make the plane run allong an axis that is related to the geometry,
+because this is used for the manipulators Y axis.*/
+void EM_editselection_plane(float *plane, EditSelection *ese)
+{
+ if (ese->type==EDITVERT) {
+ EditVert *eve= ese->data;
+ float vec[3]={0,0,0};
+
+ if (ese->prev) { /*use previously selected data to make a usefull vertex plane */
+ EM_editselection_center(vec, ese->prev);
+ VecSubf(plane, vec, eve->co);
+ } else {
+ /* make a fake plane thats at rightangles to the normal
+ we cant make a crossvec from a vec thats the same as the vec
+ unlikely but possible, so make sure if the normal is (0,0,1)
+ that vec isnt the same or in the same direction even.*/
+ if (eve->no[0]<0.5) vec[0]=1;
+ else if (eve->no[1]<0.5) vec[1]=1;
+ else vec[2]=1;
+ Crossf(plane, eve->no, vec);
+ }
+ } else if (ese->type==EDITEDGE) {
+ EditEdge *eed= ese->data;
+
+ /*the plane is simple, it runs allong the edge
+ however selecting different edges can swap the direction of the y axis.
+ this makes it less likely for the y axis of the manipulator
+ (running along the edge).. to flip less often.
+ at least its more pradictable */
+ if (eed->v2->co[1] > eed->v1->co[1]) /*check which to do first */
+ VecSubf(plane, eed->v2->co, eed->v1->co);
+ else
+ VecSubf(plane, eed->v1->co, eed->v2->co);
+
+ } else if (ese->type==EDITFACE) {
+ EditFace *efa= ese->data;
+ float vec[3];
+ if (efa->v4) { /*if its a quad- set the plane along the 2 longest edges.*/
+ float vecA[3], vecB[3];
+ VecSubf(vecA, efa->v4->co, efa->v3->co);
+ VecSubf(vecB, efa->v1->co, efa->v2->co);
+ VecAddf(plane, vecA, vecB);
+
+ VecSubf(vecA, efa->v1->co, efa->v4->co);
+ VecSubf(vecB, efa->v2->co, efa->v3->co);
+ VecAddf(vec, vecA, vecB);
+ /*use the biggest edge length*/
+ if (plane[0]*plane[0]+plane[1]*plane[1]+plane[2]*plane[2] < vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2])
+ VecCopyf(plane, vec);
+ } else {
+ /*start with v1-2 */
+ VecSubf(plane, efa->v1->co, efa->v2->co);
+
+ /*test the edge between v2-3, use if longer */
+ VecSubf(vec, efa->v2->co, efa->v3->co);
+ if (plane[0]*plane[0]+plane[1]*plane[1]+plane[2]*plane[2] < vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2])
+ VecCopyf(plane, vec);
+
+ /*test the edge between v1-3, use if longer */
+ VecSubf(vec, efa->v3->co, efa->v1->co);
+ if (plane[0]*plane[0]+plane[1]*plane[1]+plane[2]*plane[2] < vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2])
+ VecCopyf(plane, vec);
+ }
+ }
+ Normalize(plane);
+}
+
+
+
+void EM_select_face(EditFace *efa, int sel)
+{
+ if(sel) {
+ efa->f |= SELECT;
+ efa->e1->f |= SELECT;
+ efa->e2->f |= SELECT;
+ efa->e3->f |= SELECT;
+ if(efa->e4) efa->e4->f |= SELECT;
+ efa->v1->f |= SELECT;
+ efa->v2->f |= SELECT;
+ efa->v3->f |= SELECT;
+ if(efa->v4) efa->v4->f |= SELECT;
+ }
+ else {
+ efa->f &= ~SELECT;
+ efa->e1->f &= ~SELECT;
+ efa->e2->f &= ~SELECT;
+ efa->e3->f &= ~SELECT;
+ if(efa->e4) efa->e4->f &= ~SELECT;
+ efa->v1->f &= ~SELECT;
+ efa->v2->f &= ~SELECT;
+ efa->v3->f &= ~SELECT;
+ if(efa->v4) efa->v4->f &= ~SELECT;
+ }
+}
+
+void EM_select_edge(EditEdge *eed, int sel)
+{
+ if(sel) {
+ eed->f |= SELECT;
+ eed->v1->f |= SELECT;
+ eed->v2->f |= SELECT;
+ }
+ else {
+ eed->f &= ~SELECT;
+ eed->v1->f &= ~SELECT;
+ eed->v2->f &= ~SELECT;
+ }
+}
+
+void EM_select_face_fgon(EditFace *efa, int val)
+{
+ EditMesh *em = G.editMesh;
+ short index=0;
+
+ if(efa->fgonf==0) EM_select_face(efa, val);
+ else {
+ if(efa->e1->fgoni) index= efa->e1->fgoni;
+ if(efa->e2->fgoni) index= efa->e2->fgoni;
+ if(efa->e3->fgoni) index= efa->e3->fgoni;
+ if(efa->v4 && efa->e4->fgoni) index= efa->e4->fgoni;
+
+ if(index==0) printf("wrong fgon select\n");
+
+ // select all ngon faces with index
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->fgonf) {
+ if(efa->e1->fgoni==index || efa->e2->fgoni==index ||
+ efa->e3->fgoni==index || (efa->e4 && efa->e4->fgoni==index) ) {
+ EM_select_face(efa, val);
+ }
+ }
+ }
+ }
+}
+
+
+/* only vertices */
+int faceselectedOR(EditFace *efa, int flag)
+{
+ if ((efa->v1->f | efa->v2->f | efa->v3->f | (efa->v4?efa->v4->f:0))&flag) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+// replace with (efa->f & SELECT)
+int faceselectedAND(EditFace *efa, int flag)
+{
+ if ((efa->v1->f & efa->v2->f & efa->v3->f & (efa->v4?efa->v4->f:flag))&flag) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+int EM_nfaces_selected(void)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+ int count= 0;
+
+ for (efa= em->faces.first; efa; efa= efa->next)
+ if (efa->f & SELECT)
+ count++;
+
+ return count;
+}
+
+#if 0
+static int EM_nedges(void)
+{
+ EditMesh *em = G.editMesh;
+ EditEdge *eed;
+ int count= 0;
+
+ for (eed= em->edges.first; eed; eed= eed->next) count++;
+ return count;
+}
+#endif
+
+int EM_nvertices_selected(void)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+ int count= 0;
+
+ for (eve= em->verts.first; eve; eve= eve->next)
+ if (eve->f & SELECT)
+ count++;
+
+ return count;
+}
+
+void EM_clear_flag_all(int flag)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+ EditEdge *eed;
+ EditFace *efa;
+
+ for (eve= em->verts.first; eve; eve= eve->next) eve->f &= ~flag;
+ for (eed= em->edges.first; eed; eed= eed->next) eed->f &= ~flag;
+ for (efa= em->faces.first; efa; efa= efa->next) efa->f &= ~flag;
+
+ if(flag & SELECT) BLI_freelistN(&(G.editMesh->selected));
+}
+
+void EM_set_flag_all(int flag)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+ EditEdge *eed;
+ EditFace *efa;
+
+ for (eve= em->verts.first; eve; eve= eve->next) if(eve->h==0) eve->f |= flag;
+ for (eed= em->edges.first; eed; eed= eed->next) if(eed->h==0) eed->f |= flag;
+ for (efa= em->faces.first; efa; efa= efa->next) if(efa->h==0) efa->f |= flag;
+
+}
+
+/* flush for changes in vertices only */
+void EM_deselect_flush(void)
+{
+ EditMesh *em = G.editMesh;
+ EditEdge *eed;
+ EditFace *efa;
+
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->v1->f & eed->v2->f & SELECT);
+ else eed->f &= ~SELECT;
+ }
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->v4) {
+ if(efa->v1->f & efa->v2->f & efa->v3->f & efa->v4->f & SELECT );
+ else efa->f &= ~SELECT;
+ }
+ else {
+ if(efa->v1->f & efa->v2->f & efa->v3->f & SELECT );
+ else efa->f &= ~SELECT;
+ }
+ }
+}
+
+
+/* flush selection to edges & faces */
+
+/* this only based on coherent selected vertices, for example when adding new
+ objects. call clear_flag_all() before you select vertices to be sure it ends OK!
+
+*/
+
+void EM_select_flush(void)
+{
+ EditMesh *em = G.editMesh;
+ EditEdge *eed;
+ EditFace *efa;
+
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->v1->f & eed->v2->f & SELECT) eed->f |= SELECT;
+ }
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->v4) {
+ if(efa->v1->f & efa->v2->f & efa->v3->f & efa->v4->f & SELECT ) efa->f |= SELECT;
+ }
+ else {
+ if(efa->v1->f & efa->v2->f & efa->v3->f & SELECT ) efa->f |= SELECT;
+ }
+ }
+}
+
+/* when vertices or edges can be selected, also make fgon consistant */
+static void check_fgons_selection()
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa, *efan;
+ EditEdge *eed;
+ ListBase *lbar;
+ int sel, desel, index, totfgon= 0;
+
+ /* count amount of fgons */
+ for(eed= em->edges.first; eed; eed= eed->next)
+ if(eed->fgoni>totfgon) totfgon= eed->fgoni;
+
+ if(totfgon==0) return;
+
+ lbar= MEM_callocN((totfgon+1)*sizeof(ListBase), "listbase array");
+
+ /* put all fgons in lbar */
+ for(efa= em->faces.first; efa; efa= efan) {
+ efan= efa->next;
+ index= efa->e1->fgoni;
+ if(index==0) index= efa->e2->fgoni;
+ if(index==0) index= efa->e3->fgoni;
+ if(index==0 && efa->e4) index= efa->e4->fgoni;
+ if(index) {
+ BLI_remlink(&em->faces, efa);
+ BLI_addtail(&lbar[index], efa);
+ }
+ }
+
+ /* now check the fgons */
+ for(index=1; index<=totfgon; index++) {
+ /* we count on vertices/faces/edges being set OK, so we only have to set ngon itself */
+ sel= desel= 0;
+ for(efa= lbar[index].first; efa; efa= efa->next) {
+ if(efa->e1->fgoni==0) {
+ if(efa->e1->f & SELECT) sel++;
+ else desel++;
+ }
+ if(efa->e2->fgoni==0) {
+ if(efa->e2->f & SELECT) sel++;
+ else desel++;
+ }
+ if(efa->e3->fgoni==0) {
+ if(efa->e3->f & SELECT) sel++;
+ else desel++;
+ }
+ if(efa->e4 && efa->e4->fgoni==0) {
+ if(efa->e4->f & SELECT) sel++;
+ else desel++;
+ }
+
+ if(sel && desel) break;
+ }
+
+ if(sel && desel) sel= 0;
+ else if(sel) sel= 1;
+ else sel= 0;
+
+ /* select/deselect and put back */
+ for(efa= lbar[index].first; efa; efa= efa->next) {
+ if(sel) efa->f |= SELECT;
+ else efa->f &= ~SELECT;
+ }
+ addlisttolist(&em->faces, &lbar[index]);
+ }
+
+ MEM_freeN(lbar);
+}
+
+
+/* flush to edges & faces */
+
+/* based on select mode it selects edges/faces
+ assumed is that verts/edges/faces were properly selected themselves
+ with the calls above
+*/
+
+void EM_selectmode_flush(void)
+{
+ EditMesh *em = G.editMesh;
+ EditEdge *eed;
+ EditFace *efa;
+
+ // flush to edges & faces
+ if(G.scene->selectmode & SCE_SELECT_VERTEX) {
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->v1->f & eed->v2->f & SELECT) eed->f |= SELECT;
+ else eed->f &= ~SELECT;
+ }
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->v4) {
+ if(efa->v1->f & efa->v2->f & efa->v3->f & efa->v4->f & SELECT) efa->f |= SELECT;
+ else efa->f &= ~SELECT;
+ }
+ else {
+ if(efa->v1->f & efa->v2->f & efa->v3->f & SELECT) efa->f |= SELECT;
+ else efa->f &= ~SELECT;
+ }
+ }
+ }
+ // flush to faces
+ else if(G.scene->selectmode & SCE_SELECT_EDGE) {
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->e4) {
+ if(efa->e1->f & efa->e2->f & efa->e3->f & efa->e4->f & SELECT) efa->f |= SELECT;
+ else efa->f &= ~SELECT;
+ }
+ else {
+ if(efa->e1->f & efa->e2->f & efa->e3->f & SELECT) efa->f |= SELECT;
+ else efa->f &= ~SELECT;
+ }
+ }
+ }
+ // make sure selected faces have selected edges too, for extrude (hack?)
+ else if(G.scene->selectmode & SCE_SELECT_FACE) {
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->f & SELECT) EM_select_face(efa, 1);
+ }
+ }
+ check_fgons_selection();
+
+}
+
+void EM_convertsel(short oldmode, short selectmode)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+ EditEdge *eed;
+ EditFace *efa;
+ /*clear flags*/
+ for(eve= em->verts.first; eve; eve= eve->next) eve->f1 = 0;
+ for(eed= em->edges.first; eed; eed= eed->next) eed->f1 = 0;
+ for(efa= em->faces.first; efa; efa= efa->next) efa->f1 = 0;
+
+ /*have to find out what the selectionmode was previously*/
+ if(oldmode == SCE_SELECT_VERTEX) {
+ if(selectmode == SCE_SELECT_EDGE){
+ /*select all edges associated with every selected vertex*/
+ for(eed= em->edges.first; eed; eed= eed->next){
+ if(eed->v1->f&SELECT) eed->f1 = 1;
+ else if(eed->v2->f&SELECT) eed->f1 = 1;
+ }
+
+ for(eed= em->edges.first; eed; eed= eed->next){
+ if(eed->f1 == 1) EM_select_edge(eed,1);
+ }
+ }
+ else if(selectmode == SCE_SELECT_FACE){
+ /*select all faces associated with every selected vertex*/
+ for(efa= em->faces.first; efa; efa= efa->next){
+ if(efa->v1->f&SELECT) efa->f1 = 1;
+ else if(efa->v2->f&SELECT) efa->f1 = 1;
+ else if(efa->v3->f&SELECT) efa->f1 = 1;
+ else{
+ if(efa->v4){
+ if(efa->v4->f&SELECT) efa->f1 =1;
+ }
+ }
+ }
+ for(efa= em->faces.first; efa; efa= efa->next){
+ if(efa->f1 == 1) EM_select_face(efa,1);
+ }
+ }
+ }
+
+ if(oldmode == SCE_SELECT_EDGE){
+ if(selectmode == SCE_SELECT_FACE){
+ for(efa= em->faces.first; efa; efa= efa->next){
+ if(efa->e1->f&SELECT) efa->f1 = 1;
+ else if(efa->e2->f&SELECT) efa->f1 = 1;
+ else if(efa->e3->f&SELECT) efa->f1 = 1;
+ else if(efa->e4){
+ if(efa->e4->f&SELECT) efa->f1 = 1;
+ }
+ }
+ for(efa= em->faces.first; efa; efa= efa->next){
+ if(efa->f1 == 1) EM_select_face(efa,1);
+ }
+ }
+ }
+
+ check_fgons_selection();
+}
+
+/* when switching select mode, makes sure selection is consistant for editing */
+/* also for paranoia checks to make sure edge or face mode works */
+void EM_selectmode_set(void)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+ EditEdge *eed;
+ EditFace *efa;
+
+ EM_strip_selections(); /*strip EditSelections from em->selected that are not relevant to new mode*/
+ if(G.scene->selectmode & SCE_SELECT_VERTEX) {
+ /* vertices -> edges -> faces */
+ for (eed= em->edges.first; eed; eed= eed->next) eed->f &= ~SELECT;
+ for (efa= em->faces.first; efa; efa= efa->next) efa->f &= ~SELECT;
+
+ EM_select_flush();
+ }
+ else if(G.scene->selectmode & SCE_SELECT_EDGE) {
+ /* deselect vertices, and select again based on edge select */
+ for(eve= em->verts.first; eve; eve= eve->next) eve->f &= ~SELECT;
+ for(eed= em->edges.first; eed; eed= eed->next)
+ if(eed->f & SELECT) EM_select_edge(eed, 1);
+ /* selects faces based on edge status */
+ EM_selectmode_flush();
+ }
+ else if(G.scene->selectmode & SCE_SELECT_FACE) {
+ /* deselect eges, and select again based on face select */
+ for(eed= em->edges.first; eed; eed= eed->next) EM_select_edge(eed, 0);
+
+ for(efa= em->faces.first; efa; efa= efa->next)
+ if(efa->f & SELECT) EM_select_face(efa, 1);
+ }
+}
+
+/* paranoia check, actually only for entering editmode. rule:
+- vertex hidden, always means edge is hidden too
+- edge hidden, always means face is hidden too
+- face hidden, dont change anything
+*/
+void EM_hide_reset(void)
+{
+ EditMesh *em = G.editMesh;
+ EditEdge *eed;
+ EditFace *efa;
+
+ for(eed= em->edges.first; eed; eed= eed->next)
+ if(eed->v1->h || eed->v2->h) eed->h |= 1;
+
+ for(efa= em->faces.first; efa; efa= efa->next)
+ if((efa->e1->h & 1) || (efa->e2->h & 1) || (efa->e3->h & 1) || (efa->e4 && (efa->e4->h & 1)))
+ efa->h= 1;
+
+}
+
+void EM_data_interp_from_verts(EditVert *v1, EditVert *v2, EditVert *eve, float fac)
+{
+ EditMesh *em= G.editMesh;
+ void *src[2];
+ float w[2];
+
+ if (v1->data && v2->data) {
+ src[0]= v1->data;
+ src[1]= v2->data;
+ w[0] = 1.0f-fac;
+ w[1] = fac;
+
+ CustomData_em_interp(&em->vdata, src, w, NULL, 2, eve->data);
+ }
+}
+
+void EM_data_interp_from_faces(EditFace *efa1, EditFace *efa2, EditFace *efan, int i1, int i2, int i3, int i4)
+{
+ EditMesh *em= G.editMesh;
+ float w[2][4][4];
+ void *src[2];
+ int count = (efa2)? 2: 1;
+
+ if (efa1->data) {
+ /* set weights for copying from corners directly to other corners */
+ memset(w, 0, sizeof(w));
+
+ w[i1/4][0][i1%4]= 1.0f;
+ w[i2/4][1][i2%4]= 1.0f;
+ w[i3/4][2][i3%4]= 1.0f;
+ if (i4 != -1)
+ w[i4/4][3][i4%4]= 1.0f;
+
+ src[0]= efa1->data;
+ src[1]= (efa2)? efa2->data: NULL;
+
+ CustomData_em_interp(&em->fdata, src, NULL, (float*)w, count, efan->data);
+ }
+}
+
+EditFace *EM_face_from_faces(EditFace *efa1, EditFace *efa2, int i1, int i2, int i3, int i4)
+{
+ EditFace *efan;
+ EditVert **v[2];
+
+ v[0]= &efa1->v1;
+ v[1]= (efa2)? &efa2->v1: NULL;
+
+ efan= addfacelist(v[i1/4][i1%4], v[i2/4][i2%4], v[i3/4][i3%4],
+ (i4 == -1)? 0: v[i4/4][i4%4], efa1, NULL);
+
+ EM_data_interp_from_faces(efa1, efa2, efan, i1, i2, i3, i4);
+
+ return efan;
+}
+
+static void update_data_blocks(CustomData *olddata, CustomData *data)
+{
+ EditMesh *em= G.editMesh;
+ EditFace *efa;
+ EditVert *eve;
+ void *block;
+
+ if (data == &G.editMesh->vdata) {
+ for(eve= em->verts.first; eve; eve= eve->next) {
+ block = NULL;
+ CustomData_em_set_default(data, &block);
+ CustomData_em_copy_data(olddata, data, eve->data, &block);
+ CustomData_em_free_block(olddata, &eve->data);
+ eve->data= block;
+ }
+ }
+ else if (data == &G.editMesh->fdata) {
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ block = NULL;
+ CustomData_em_set_default(data, &block);
+ CustomData_em_copy_data(olddata, data, efa->data, &block);
+ CustomData_em_free_block(olddata, &efa->data);
+ efa->data= block;
+ }
+ }
+}
+
+void EM_add_data_layer(CustomData *data, int type)
+{
+ CustomData olddata;
+
+ olddata= *data;
+ olddata.layers= (olddata.layers)? MEM_dupallocN(olddata.layers): NULL;
+ CustomData_add_layer(data, type, CD_CALLOC, NULL, 0);
+
+ update_data_blocks(&olddata, data);
+ if (olddata.layers) MEM_freeN(olddata.layers);
+}
+
+void EM_free_data_layer(CustomData *data, int type)
+{
+ CustomData olddata;
+
+ olddata= *data;
+ olddata.layers= (olddata.layers)? MEM_dupallocN(olddata.layers): NULL;
+ CustomData_free_layer_active(data, type, 0);
+
+ update_data_blocks(&olddata, data);
+ if (olddata.layers) MEM_freeN(olddata.layers);
+}
+
+/* ******** EXTRUDE ********* */
+
+static void add_normal_aligned(float *nor, float *add)
+{
+ if( INPR(nor, add) < 0.0 )
+ VecSubf(nor, nor, add);
+ else
+ VecAddf(nor, nor, add);
+}
+
+static void set_edge_directions_f2(int val)
+{
+ EditMesh *em= G.editMesh;
+ EditFace *efa;
+ int do_all= 1;
+
+ /* edge directions are used for extrude, to detect direction of edges that make new faces */
+ /* we have set 'f2' flags in edges that need to get a direction set (e.g. get new face) */
+ /* the val argument differs... so we need it as arg */
+
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->f & SELECT) {
+ do_all= 0;
+ if(efa->e1->f2<val) {
+ if(efa->e1->v1 == efa->v1) efa->e1->dir= 0;
+ else efa->e1->dir= 1;
+ }
+ if(efa->e2->f2<val) {
+ if(efa->e2->v1 == efa->v2) efa->e2->dir= 0;
+ else efa->e2->dir= 1;
+ }
+ if(efa->e3->f2<val) {
+ if(efa->e3->v1 == efa->v3) efa->e3->dir= 0;
+ else efa->e3->dir= 1;
+ }
+ if(efa->e4 && efa->e4->f2<val) {
+ if(efa->e4->v1 == efa->v4) efa->e4->dir= 0;
+ else efa->e4->dir= 1;
+ }
+ }
+ }
+ /* ok, no faces done... then we at least set it for exterior edges */
+ if(do_all) {
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->e1->v1 == efa->v1) efa->e1->dir= 0;
+ else efa->e1->dir= 1;
+ if(efa->e2->v1 == efa->v2) efa->e2->dir= 0;
+ else efa->e2->dir= 1;
+ if(efa->e3->v1 == efa->v3) efa->e3->dir= 0;
+ else efa->e3->dir= 1;
+ if(efa->e4) {
+ if(efa->e4->v1 == efa->v4) efa->e4->dir= 0;
+ else efa->e4->dir= 1;
+ }
+ }
+ }
+}
+
+/* individual face extrude */
+/* will use vertex normals for extrusion directions, so *nor is unaffected */
+short extrudeflag_face_indiv(short flag, float *nor)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve, *v1, *v2, *v3, *v4;
+ EditEdge *eed;
+ EditFace *efa, *nextfa;
+
+ if(G.obedit==0 || get_mesh(G.obedit)==0) return 0;
+
+ /* selected edges with 1 or more selected face become faces */
+ /* selected faces each makes new faces */
+ /* always remove old faces, keeps volumes manifold */
+ /* select the new extrusion, deselect old */
+
+ /* step 1; init, count faces in edges */
+ recalc_editnormals();
+
+ for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0; // new select flag
+
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ eed->f2= 0; // amount of unselected faces
+ }
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->f & SELECT);
+ else {
+ efa->e1->f2++;
+ efa->e2->f2++;
+ efa->e3->f2++;
+ if(efa->e4) efa->e4->f2++;
+ }
+ }
+
+ /* step 2: make new faces from faces */
+ for(efa= em->faces.last; efa; efa= efa->prev) {
+ if(efa->f & SELECT) {
+ v1= addvertlist(efa->v1->co, efa->v1);
+ v2= addvertlist(efa->v2->co, efa->v2);
+ v3= addvertlist(efa->v3->co, efa->v3);
+
+ v1->f1= v2->f1= v3->f1= 1;
+ VECCOPY(v1->no, efa->n);
+ VECCOPY(v2->no, efa->n);
+ VECCOPY(v3->no, efa->n);
+ if(efa->v4) {
+ v4= addvertlist(efa->v4->co, efa->v4);
+ v4->f1= 1;
+ VECCOPY(v4->no, efa->n);
+ }
+ else v4= NULL;
+
+ /* side faces, clockwise */
+ addfacelist(efa->v2, v2, v1, efa->v1, efa, NULL);
+ addfacelist(efa->v3, v3, v2, efa->v2, efa, NULL);
+ if(efa->v4) {
+ addfacelist(efa->v4, v4, v3, efa->v3, efa, NULL);
+ addfacelist(efa->v1, v1, v4, efa->v4, efa, NULL);
+ }
+ else {
+ addfacelist(efa->v1, v1, v3, efa->v3, efa, NULL);
+ }
+ /* top face */
+ addfacelist(v1, v2, v3, v4, efa, NULL);
+ }
+ }
+
+ /* step 3: remove old faces */
+ efa= em->faces.first;
+ while(efa) {
+ nextfa= efa->next;
+ if(efa->f & SELECT) {
+ BLI_remlink(&em->faces, efa);
+ free_editface(efa);
+ }
+ efa= nextfa;
+ }
+
+ /* step 4: redo selection */
+ EM_clear_flag_all(SELECT);
+
+ for(eve= em->verts.first; eve; eve= eve->next) {
+ if(eve->f1) eve->f |= SELECT;
+ }
+
+ EM_select_flush();
+
+ return 'n';
+}
+
+
+/* extrudes individual edges */
+/* nor is filled with constraint vector */
+short extrudeflag_edges_indiv(short flag, float *nor)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+ EditEdge *eed;
+ EditFace *efa;
+
+ for(eve= em->verts.first; eve; eve= eve->next) eve->tmp.v = NULL;
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ eed->tmp.f = NULL;
+ eed->f2= ((eed->f & flag)!=0);
+ }
+
+ set_edge_directions_f2(2);
+
+ /* sample for next loop */
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ efa->e1->tmp.f = efa;
+ efa->e2->tmp.f = efa;
+ efa->e3->tmp.f = efa;
+ if(efa->e4) efa->e4->tmp.f = efa;
+ }
+ /* make the faces */
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->f & flag) {
+ if(eed->v1->tmp.v == NULL)
+ eed->v1->tmp.v = addvertlist(eed->v1->co, eed->v1);
+ if(eed->v2->tmp.v == NULL)
+ eed->v2->tmp.v = addvertlist(eed->v2->co, eed->v2);
+
+ if(eed->dir==1)
+ addfacelist(eed->v1, eed->v2,
+ eed->v2->tmp.v, eed->v1->tmp.v,
+ eed->tmp.f, NULL);
+ else
+ addfacelist(eed->v2, eed->v1,
+ eed->v1->tmp.v, eed->v2->tmp.v,
+ eed->tmp.f, NULL);
+
+ /* for transform */
+ if(eed->tmp.f) {
+ efa = eed->tmp.f;
+ if (efa->f & SELECT) add_normal_aligned(nor, efa->n);
+ }
+ }
+ }
+ Normalize(nor);
+
+ /* set correct selection */
+ EM_clear_flag_all(SELECT);
+ for(eve= em->verts.last; eve; eve= eve->prev) {
+ if(eve->tmp.v) {
+ eve->tmp.v->f |= flag;
+ }
+ }
+
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->v1->f & eed->v2->f & flag) eed->f |= flag;
+ }
+
+ if(nor[0]==0.0 && nor[1]==0.0 && nor[2]==0.0) return 'g'; // g is grab
+ return 'n'; // n is for normal constraint
+}
+
+/* extrudes individual vertices */
+short extrudeflag_verts_indiv(short flag, float *nor)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+
+ /* make the edges */
+ for(eve= em->verts.first; eve; eve= eve->next) {
+ if(eve->f & flag) {
+ eve->tmp.v = addvertlist(eve->co, eve);
+ addedgelist(eve, eve->tmp.v, NULL);
+ }
+ else eve->tmp.v = NULL;
+ }
+
+ /* set correct selection */
+ EM_clear_flag_all(SELECT);
+
+ for(eve= em->verts.last; eve; eve= eve->prev)
+ if (eve->tmp.v)
+ eve->tmp.v->f |= flag;
+
+ return 'g'; // g is grab
+}
+
+
+/* this is actually a recode of extrudeflag(), using proper edge/face select */
+/* hurms, doesnt use 'flag' yet, but its not called by primitive making stuff anyway */
+static short extrudeflag_edge(short flag, float *nor)
+{
+ /* all select edges/faces: extrude */
+ /* old select is cleared, in new ones it is set */
+ EditMesh *em = G.editMesh;
+ EditVert *eve, *nextve;
+ EditEdge *eed, *nexted;
+ EditFace *efa, *nextfa;
+ short del_old= 0;
+ ModifierData *md;
+
+ if(G.obedit==0 || get_mesh(G.obedit)==0) return 0;
+
+ md = G.obedit->modifiers.first;
+
+ /* selected edges with 0 or 1 selected face become faces */
+ /* selected faces generate new faces */
+
+ /* if *one* selected face has edge with unselected face; remove old selected faces */
+
+ /* if selected edge is not used anymore; remove */
+ /* if selected vertex is not used anymore: remove */
+
+ /* select the new extrusion, deselect old */
+
+
+ /* step 1; init, count faces in edges */
+ recalc_editnormals();
+
+ for(eve= em->verts.first; eve; eve= eve->next) {
+ eve->tmp.v = NULL;
+ eve->f1= 0;
+ }
+
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ eed->f1= 0; // amount of unselected faces
+ eed->f2= 0; // amount of selected faces
+ if(eed->f & SELECT) {
+ eed->v1->f1= 1; // we call this 'selected vertex' now
+ eed->v2->f1= 1;
+ }
+ eed->tmp.f = NULL; // here we tuck face pointer, as sample
+ }
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->f & SELECT) {
+ efa->e1->f2++;
+ efa->e2->f2++;
+ efa->e3->f2++;
+ if(efa->e4) efa->e4->f2++;
+
+ // sample for next loop
+ efa->e1->tmp.f = efa;
+ efa->e2->tmp.f = efa;
+ efa->e3->tmp.f = efa;
+ if(efa->e4) efa->e4->tmp.f = efa;
+ }
+ else {
+ efa->e1->f1++;
+ efa->e2->f1++;
+ efa->e3->f1++;
+ if(efa->e4) efa->e4->f1++;
+ }
+ }
+
+ /* If a mirror modifier with clipping is on, we need to adjust some
+ * of the cases above to handle edges on the line of symmetry.
+ */
+ for (; md; md=md->next) {
+ if (md->type==eModifierType_Mirror) {
+ MirrorModifierData *mmd = (MirrorModifierData*) md;
+
+ if(mmd->flag & MOD_MIR_CLIPPING) {
+ for (eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->f2 == 1) {
+
+ if (mmd->flag & MOD_MIR_AXIS_X)
+ if ( (fabs(eed->v1->co[0]) < mmd->tolerance) &&
+ (fabs(eed->v2->co[0]) < mmd->tolerance) )
+ ++eed->f2;
+
+ if (mmd->flag & MOD_MIR_AXIS_Y)
+ if ( (fabs(eed->v1->co[1]) < mmd->tolerance) &&
+ (fabs(eed->v2->co[1]) < mmd->tolerance) )
+ ++eed->f2;
+
+ if (mmd->flag & MOD_MIR_AXIS_Z)
+ if ( (fabs(eed->v1->co[2]) < mmd->tolerance) &&
+ (fabs(eed->v2->co[2]) < mmd->tolerance) )
+ ++eed->f2;
+ }
+ }
+ }
+ }
+ }
+
+ set_edge_directions_f2(2);
+
+ /* step 1.5: if *one* selected face has edge with unselected face; remove old selected faces */
+ for(efa= em->faces.last; efa; efa= efa->prev) {
+ if(efa->f & SELECT) {
+ if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1 || (efa->e4 && efa->e4->f1)) {
+ del_old= 1;
+ break;
+ }
+ }
+ }
+
+ /* step 2: make new faces from edges */
+ for(eed= em->edges.last; eed; eed= eed->prev) {
+ if(eed->f & SELECT) {
+ if(eed->f2<2) {
+ if(eed->v1->tmp.v == NULL)
+ eed->v1->tmp.v = addvertlist(eed->v1->co, eed->v1);
+ if(eed->v2->tmp.v == NULL)
+ eed->v2->tmp.v = addvertlist(eed->v2->co, eed->v2);
+
+ /* if del_old, the preferred normal direction is exact
+ * opposite as for keep old faces
+ */
+ if(eed->dir!=del_old)
+ addfacelist(eed->v1, eed->v2,
+ eed->v2->tmp.v, eed->v1->tmp.v,
+ eed->tmp.f, NULL);
+ else
+ addfacelist(eed->v2, eed->v1,
+ eed->v1->tmp.v, eed->v2->tmp.v,
+ eed->tmp.f, NULL);
+ }
+ }
+ }
+
+ /* step 3: make new faces from faces */
+ for(efa= em->faces.last; efa; efa= efa->prev) {
+ if(efa->f & SELECT) {
+ if (efa->v1->tmp.v == NULL)
+ efa->v1->tmp.v = addvertlist(efa->v1->co, efa->v1);
+ if (efa->v2->tmp.v ==NULL)
+ efa->v2->tmp.v = addvertlist(efa->v2->co, efa->v2);
+ if (efa->v3->tmp.v ==NULL)
+ efa->v3->tmp.v = addvertlist(efa->v3->co, efa->v3);
+ if (efa->v4 && (efa->v4->tmp.v == NULL))
+ efa->v4->tmp.v = addvertlist(efa->v4->co, efa->v4);
+
+ if(del_old==0) { // keep old faces means flipping normal
+ if(efa->v4)
+ addfacelist(efa->v4->tmp.v, efa->v3->tmp.v,
+ efa->v2->tmp.v, efa->v1->tmp.v, efa, efa);
+ else
+ addfacelist(efa->v3->tmp.v, efa->v2->tmp.v,
+ efa->v1->tmp.v, NULL, efa, efa);
+ }
+ else {
+ if(efa->v4)
+ addfacelist(efa->v1->tmp.v, efa->v2->tmp.v,
+ efa->v3->tmp.v, efa->v4->tmp.v, efa, efa);
+ else
+ addfacelist(efa->v1->tmp.v, efa->v2->tmp.v,
+ efa->v3->tmp.v, NULL, efa, efa);
+ }
+
+ /* for transform */
+ add_normal_aligned(nor, efa->n);
+ }
+ }
+
+ if(del_old) {
+ /* step 4: remove old faces, if del_old */
+ efa= em->faces.first;
+ while(efa) {
+ nextfa= efa->next;
+ if(efa->f & SELECT) {
+ BLI_remlink(&em->faces, efa);
+ free_editface(efa);
+ }
+ efa= nextfa;
+ }
+
+ /* step 5: remove selected unused edges */
+ /* start tagging again */
+ for(eed= em->edges.first; eed; eed= eed->next) eed->f1=0;
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ efa->e1->f1= 1;
+ efa->e2->f1= 1;
+ efa->e3->f1= 1;
+ if(efa->e4) efa->e4->f1= 1;
+ }
+ /* remove */
+ eed= em->edges.first;
+ while(eed) {
+ nexted= eed->next;
+ if(eed->f & SELECT) {
+ if(eed->f1==0) {
+ remedge(eed);
+ free_editedge(eed);
+ }
+ }
+ eed= nexted;
+ }
+
+ /* step 6: remove selected unused vertices */
+ for(eed= em->edges.first; eed; eed= eed->next)
+ eed->v1->f1= eed->v2->f1= 0;
+
+ eve= em->verts.first;
+ while(eve) {
+ nextve= eve->next;
+ if(eve->f1) {
+ // hack... but we need it for step 7, redoing selection
+ if(eve->tmp.v) eve->tmp.v->tmp.v= eve->tmp.v;
+
+ BLI_remlink(&em->verts, eve);
+ free_editvert(eve);
+ }
+ eve= nextve;
+ }
+ }
+
+ Normalize(nor); // translation normal grab
+
+ /* step 7: redo selection */
+ EM_clear_flag_all(SELECT);
+
+ for(eve= em->verts.first; eve; eve= eve->next) {
+ if(eve->tmp.v) {
+ eve->tmp.v->f |= SELECT;
+ }
+ }
+
+ EM_select_flush();
+
+ if(nor[0]==0.0 && nor[1]==0.0 && nor[2]==0.0) return 'g'; // grab
+ return 'n'; // normal constraint
+}
+
+short extrudeflag_vert(short flag, float *nor)
+{
+ /* all verts/edges/faces with (f & 'flag'): extrude */
+ /* from old verts, 'flag' is cleared, in new ones it is set */
+ EditMesh *em = G.editMesh;
+ EditVert *eve, *v1, *v2, *v3, *v4, *nextve;
+ EditEdge *eed, *e1, *e2, *e3, *e4, *nexted;
+ EditFace *efa, *efa2, *nextvl;
+ short sel=0, del_old= 0, is_face_sel=0;
+ ModifierData *md;
+
+ if(G.obedit==0 || get_mesh(G.obedit)==0) return 0;
+
+ md = G.obedit->modifiers.first;
+
+ /* clear vert flag f1, we use this to detect a loose selected vertice */
+ eve= em->verts.first;
+ while(eve) {
+ if(eve->f & flag) eve->f1= 1;
+ else eve->f1= 0;
+ eve= eve->next;
+ }
+ /* clear edges counter flag, if selected we set it at 1 */
+ eed= em->edges.first;
+ while(eed) {
+ if( (eed->v1->f & flag) && (eed->v2->f & flag) ) {
+ eed->f2= 1;
+ eed->v1->f1= 0;
+ eed->v2->f1= 0;
+ }
+ else eed->f2= 0;
+
+ eed->f1= 1; /* this indicates it is an 'old' edge (in this routine we make new ones) */
+ eed->tmp.f = NULL; /* used as sample */
+
+ eed= eed->next;
+ }
+
+ /* we set a flag in all selected faces, and increase the associated edge counters */
+
+ efa= em->faces.first;
+ while(efa) {
+ efa->f1= 0;
+
+ if(faceselectedAND(efa, flag)) {
+ e1= efa->e1;
+ e2= efa->e2;
+ e3= efa->e3;
+ e4= efa->e4;
+
+ if(e1->f2 < 3) e1->f2++;
+ if(e2->f2 < 3) e2->f2++;
+ if(e3->f2 < 3) e3->f2++;
+ if(e4 && e4->f2 < 3) e4->f2++;
+
+ efa->f1= 1;
+ is_face_sel= 1; // for del_old
+ }
+ else if(faceselectedOR(efa, flag)) {
+ e1= efa->e1;
+ e2= efa->e2;
+ e3= efa->e3;
+ e4= efa->e4;
+
+ if( (e1->v1->f & flag) && (e1->v2->f & flag) ) e1->f1= 2;
+ if( (e2->v1->f & flag) && (e2->v2->f & flag) ) e2->f1= 2;
+ if( (e3->v1->f & flag) && (e3->v2->f & flag) ) e3->f1= 2;
+ if( e4 && (e4->v1->f & flag) && (e4->v2->f & flag) ) e4->f1= 2;
+ }
+
+ // sample for next loop
+ efa->e1->tmp.f = efa;
+ efa->e2->tmp.f = efa;
+ efa->e3->tmp.f = efa;
+ if(efa->e4) efa->e4->tmp.f = efa;
+
+ efa= efa->next;
+ }
+
+ set_edge_directions_f2(3);
+
+ /* the current state now is:
+ eve->f1==1: loose selected vertex
+
+ eed->f2==0 : edge is not selected, no extrude
+ eed->f2==1 : edge selected, is not part of a face, extrude
+ eed->f2==2 : edge selected, is part of 1 face, extrude
+ eed->f2==3 : edge selected, is part of more faces, no extrude
+
+ eed->f1==0: new edge
+ eed->f1==1: edge selected, is part of selected face, when eed->f==3: remove
+ eed->f1==2: edge selected, part of a partially selected face
+
+ efa->f1==1 : duplicate this face
+ */
+
+ /* If a mirror modifier with clipping is on, we need to adjust some
+ * of the cases above to handle edges on the line of symmetry.
+ */
+ for (; md; md=md->next) {
+ if (md->type==eModifierType_Mirror) {
+ MirrorModifierData *mmd = (MirrorModifierData*) md;
+
+ if(mmd->flag & MOD_MIR_CLIPPING) {
+ for (eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->f2 == 2) {
+
+ if (mmd->flag & MOD_MIR_AXIS_X)
+ if ( (fabs(eed->v1->co[0]) < mmd->tolerance) &&
+ (fabs(eed->v2->co[0]) < mmd->tolerance) )
+ ++eed->f2;
+
+ if (mmd->flag & MOD_MIR_AXIS_Y)
+ if ( (fabs(eed->v1->co[1]) < mmd->tolerance) &&
+ (fabs(eed->v2->co[1]) < mmd->tolerance) )
+ ++eed->f2;
+ if (mmd->flag & MOD_MIR_AXIS_Z)
+ if ( (fabs(eed->v1->co[2]) < mmd->tolerance) &&
+ (fabs(eed->v2->co[2]) < mmd->tolerance) )
+ ++eed->f2;
+ }
+ }
+ }
+ }
+ }
+
+ /* copy all selected vertices, */
+ /* write pointer to new vert in old struct at eve->tmp.v */
+ eve= em->verts.last;
+ while(eve) {
+ eve->f &= ~128; /* clear, for later test for loose verts */
+ if(eve->f & flag) {
+ sel= 1;
+ v1= addvertlist(0, NULL);
+
+ VECCOPY(v1->co, eve->co);
+ v1->f= eve->f;
+ eve->f-= flag;
+ eve->tmp.v = v1;
+ }
+ else eve->tmp.v = 0;
+ eve= eve->prev;
+ }
+
+ if(sel==0) return 0;
+
+ /* all edges with eed->f2==1 or eed->f2==2 become faces */
+
+ /* if del_old==1 then extrude is in partial geometry, to keep it manifold.
+ verts with f1==0 and (eve->f & 128)==0) are removed
+ edges with eed->f2>2 are removed
+ faces with efa->f1 are removed
+ if del_old==0 the extrude creates a volume.
+ */
+
+ /* find if we delete old faces */
+ if(is_face_sel) {
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if( (eed->f2==1 || eed->f2==2) ) {
+ if(eed->f1==2) {
+ del_old= 1;
+ break;
+ }
+ }
+ }
+ }
+
+ eed= em->edges.last;
+ while(eed) {
+ nexted= eed->prev;
+ if( eed->f2<3) {
+ eed->v1->f |= 128; /* = no loose vert! */
+ eed->v2->f |= 128;
+ }
+ if( (eed->f2==1 || eed->f2==2) ) {
+
+ /* if del_old, the preferred normal direction is exact opposite as for keep old faces */
+ if(eed->dir != del_old)
+ efa2 = addfacelist(eed->v1, eed->v2,
+ eed->v2->tmp.v, eed->v1->tmp.v,
+ eed->tmp.f, NULL);
+ else
+ efa2 = addfacelist(eed->v2, eed->v1,
+ eed->v1->tmp.v, eed->v2->tmp.v,
+ eed->tmp.f, NULL);
+
+ /* Needs smarter adaption of existing creases.
+ * If addedgelist is used, make sure seams are set to 0 on these
+ * new edges, since we do not want to add any seams on extrusion.
+ */
+ efa2->e1->crease= eed->crease;
+ efa2->e2->crease= eed->crease;
+ efa2->e3->crease= eed->crease;
+ if(efa2->e4) efa2->e4->crease= eed->crease;
+ }
+
+ eed= nexted;
+ }
+ if(del_old) {
+ eed= em->edges.first;
+ while(eed) {
+ nexted= eed->next;
+ if(eed->f2==3 && eed->f1==1) {
+ remedge(eed);
+ free_editedge(eed);
+ }
+ eed= nexted;
+ }
+ }
+ /* duplicate faces, if necessary remove old ones */
+ efa= em->faces.first;
+ while(efa) {
+ nextvl= efa->next;
+ if(efa->f1 & 1) {
+
+ v1 = efa->v1->tmp.v;
+ v2 = efa->v2->tmp.v;
+ v3 = efa->v3->tmp.v;
+ if(efa->v4)
+ v4 = efa->v4->tmp.v;
+ else
+ v4= 0;
+
+ /* hmm .. not sure about edges here */
+ if(del_old==0) // if we keep old, we flip normal
+ efa2= addfacelist(v3, v2, v1, v4, efa, efa);
+ else
+ efa2= addfacelist(v1, v2, v3, v4, efa, efa);
+
+ /* for transform */
+ add_normal_aligned(nor, efa->n);
+
+ if(del_old) {
+ BLI_remlink(&em->faces, efa);
+ free_editface(efa);
+ }
+ }
+ efa= nextvl;
+ }
+
+ Normalize(nor); // for grab
+
+ /* for all vertices with eve->tmp.v!=0
+ if eve->f1==1: make edge
+ if flag!=128 : if del_old==1: remove
+ */
+ eve= em->verts.last;
+ while(eve) {
+ nextve= eve->prev;
+ if(eve->tmp.v) {
+ if(eve->f1==1) addedgelist(eve, eve->tmp.v, NULL);
+ else if( (eve->f & 128)==0) {
+ if(del_old) {
+ BLI_remlink(&em->verts,eve);
+ free_editvert(eve);
+ eve= NULL;
+ }
+ }
+ }
+ if(eve) {
+ eve->f &= ~128;
+ }
+ eve= nextve;
+ }
+ // since its vertex select mode now, it also deselects higher order
+ EM_selectmode_flush();
+
+ if(nor[0]==0.0 && nor[1]==0.0 && nor[2]==0.0) return 'g'; // g is grab, for correct undo print
+ return 'n';
+}
+
+/* generic extrude */
+short extrudeflag(short flag, float *nor)
+{
+ if(G.scene->selectmode & SCE_SELECT_VERTEX)
+ return extrudeflag_vert(flag, nor);
+ else
+ return extrudeflag_edge(flag, nor);
+
+}
+
+void rotateflag(short flag, float *cent, float rotmat[][3])
+{
+ /* all verts with (flag & 'flag') rotate */
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+
+ eve= em->verts.first;
+ while(eve) {
+ if(eve->f & flag) {
+ eve->co[0]-=cent[0];
+ eve->co[1]-=cent[1];
+ eve->co[2]-=cent[2];
+ Mat3MulVecfl(rotmat,eve->co);
+ eve->co[0]+=cent[0];
+ eve->co[1]+=cent[1];
+ eve->co[2]+=cent[2];
+ }
+ eve= eve->next;
+ }
+}
+
+void translateflag(short flag, float *vec)
+{
+ /* all verts with (flag & 'flag') translate */
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+
+ eve= em->verts.first;
+ while(eve) {
+ if(eve->f & flag) {
+ eve->co[0]+=vec[0];
+ eve->co[1]+=vec[1];
+ eve->co[2]+=vec[2];
+ }
+ eve= eve->next;
+ }
+}
+
+/* helper call for below */
+static EditVert *adduplicate_vertex(EditVert *eve, int flag)
+{
+ /* FIXME: copy deformation weight from eve ok here? */
+ EditVert *v1= addvertlist(eve->co, eve);
+
+ v1->f= eve->f;
+ eve->f-= flag;
+ eve->f|= 128;
+
+ eve->tmp.v = v1;
+
+ return v1;
+}
+
+/* old selection has flag 128 set, and flag 'flag' cleared
+new selection has flag 'flag' set */
+void adduplicateflag(int flag)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve, *v1, *v2, *v3, *v4;
+ EditEdge *eed, *newed;
+ EditFace *efa, *newfa;
+
+ EM_clear_flag_all(128);
+ EM_selectmode_set(); // paranoia check, selection now is consistant
+
+ /* vertices first */
+ for(eve= em->verts.last; eve; eve= eve->prev) {
+
+ if(eve->f & flag)
+ adduplicate_vertex(eve, flag);
+ else
+ eve->tmp.v = NULL;
+ }
+
+ /* copy edges, note that vertex selection can be independent of edge */
+ for(eed= em->edges.last; eed; eed= eed->prev) {
+ if( eed->f & flag ) {
+ v1 = eed->v1->tmp.v;
+ if(v1==NULL) v1= adduplicate_vertex(eed->v1, flag);
+ v2 = eed->v2->tmp.v;
+ if(v2==NULL) v2= adduplicate_vertex(eed->v2, flag);
+
+ newed= addedgelist(v1, v2, eed);
+
+ newed->f= eed->f;
+ eed->f -= flag;
+ eed->f |= 128;
+ }
+ }
+
+ /* then duplicate faces, again create new vertices if needed */
+ for(efa= em->faces.last; efa; efa= efa->prev) {
+ if(efa->f & flag) {
+ v1 = efa->v1->tmp.v;
+ if(v1==NULL) v1= adduplicate_vertex(efa->v1, flag);
+ v2 = efa->v2->tmp.v;
+ if(v2==NULL) v2= adduplicate_vertex(efa->v2, flag);
+ v3 = efa->v3->tmp.v;
+ if(v3==NULL) v3= adduplicate_vertex(efa->v3, flag);
+ if(efa->v4) {
+ v4 = efa->v4->tmp.v;
+ if(v4==NULL) v4= adduplicate_vertex(efa->v4, flag);
+ }
+ else v4= NULL;
+
+ newfa= addfacelist(v1, v2, v3, v4, efa, efa);
+
+ newfa->f= efa->f;
+ efa->f -= flag;
+ efa->f |= 128;
+ }
+ }
+
+ EM_fgon_flags(); // redo flags and indices for fgons
+}
+
+void delfaceflag(int flag)
+{
+ EditMesh *em = G.editMesh;
+ /* delete all faces with 'flag', including loose edges and loose vertices */
+ /* this is maybe a bit weird, but this function is used for 'split' and 'separate' */
+ /* in remaining vertices/edges 'flag' is cleared */
+ EditVert *eve,*nextve;
+ EditEdge *eed, *nexted;
+ EditFace *efa,*nextvl;
+
+ /* to detect loose edges, we put f2 flag on 1 */
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->f & flag) eed->f2= 1;
+ else eed->f2= 0;
+ }
+
+ /* delete faces */
+ efa= em->faces.first;
+ while(efa) {
+ nextvl= efa->next;
+ if(efa->f & flag) {
+
+ efa->e1->f2= 1;
+ efa->e2->f2= 1;
+ efa->e3->f2= 1;
+ if(efa->e4) {
+ efa->e4->f2= 1;
+ }
+
+ BLI_remlink(&em->faces, efa);
+ free_editface(efa);
+ }
+ efa= nextvl;
+ }
+
+ /* all remaining faces: make sure we keep the edges */
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ efa->e1->f2= 0;
+ efa->e2->f2= 0;
+ efa->e3->f2= 0;
+ if(efa->e4) {
+ efa->e4->f2= 0;
+ }
+ }
+
+ /* remove tagged edges, and clear remaining ones */
+ eed= em->edges.first;
+ while(eed) {
+ nexted= eed->next;
+
+ if(eed->f2==1) {
+ remedge(eed);
+ free_editedge(eed);
+ }
+ else {
+ eed->f &= ~flag;
+ eed->v1->f &= ~flag;
+ eed->v2->f &= ~flag;
+ }
+ eed= nexted;
+ }
+
+ /* vertices with 'flag' now are the loose ones, and will be removed */
+ eve= em->verts.first;
+ while(eve) {
+ nextve= eve->next;
+ if(eve->f & flag) {
+ BLI_remlink(&em->verts, eve);
+ free_editvert(eve);
+ }
+ eve= nextve;
+ }
+
+}
+
+/* ********************* */
+#if 0
+static int check_vnormal_flip(float *n, float *vnorm)
+{
+ float inp;
+
+ inp= n[0]*vnorm[0]+n[1]*vnorm[1]+n[2]*vnorm[2];
+
+ /* angles 90 degrees: dont flip */
+ if(inp> -0.000001) return 0;
+
+ return 1;
+}
+#endif
+
+void flipface(EditFace *efa)
+{
+ if(efa->v4) {
+ SWAP(EditVert *, efa->v2, efa->v4);
+ SWAP(EditEdge *, efa->e1, efa->e4);
+ SWAP(EditEdge *, efa->e2, efa->e3);
+ EM_data_interp_from_faces(efa, NULL, efa, 0, 3, 2, 1);
+ }
+ else {
+ SWAP(EditVert *, efa->v2, efa->v3);
+ SWAP(EditEdge *, efa->e1, efa->e3);
+ efa->e2->dir= 1-efa->e2->dir;
+ EM_data_interp_from_faces(efa, NULL, efa, 0, 2, 1, 3);
+ }
+
+ if(efa->v4) CalcNormFloat4(efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co, efa->n);
+ else CalcNormFloat(efa->v1->co, efa->v2->co, efa->v3->co, efa->n);
+}
+
+
+void flip_editnormals(void)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+
+ efa= em->faces.first;
+ while(efa) {
+ if( efa->f & SELECT ){
+ flipface(efa);
+ }
+ efa= efa->next;
+ }
+#ifdef WITH_VERSE
+ if(G.editMesh->vnode)
+ sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode);
+#endif
+}
+
+/* does face centers too */
+void recalc_editnormals(void)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+ EditVert *eve;
+
+ for(eve= em->verts.first; eve; eve=eve->next) {
+ eve->no[0] = eve->no[1] = eve->no[2] = 0.0;
+ }
+
+ for(efa= em->faces.first; efa; efa=efa->next) {
+ if(efa->v4) {
+ CalcNormFloat4(efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co, efa->n);
+ CalcCent4f(efa->cent, efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co);
+ VecAddf(efa->v4->no, efa->v4->no, efa->n);
+ }
+ else {
+ CalcNormFloat(efa->v1->co, efa->v2->co, efa->v3->co, efa->n);
+ CalcCent3f(efa->cent, efa->v1->co, efa->v2->co, efa->v3->co);
+ }
+ VecAddf(efa->v1->no, efa->v1->no, efa->n);
+ VecAddf(efa->v2->no, efa->v2->no, efa->n);
+ VecAddf(efa->v3->no, efa->v3->no, efa->n);
+ }
+
+ /* following Mesh convention; we use vertex coordinate itself for normal in this case */
+ for(eve= em->verts.first; eve; eve=eve->next) {
+ if (Normalize(eve->no)==0.0) {
+ VECCOPY(eve->no, eve->co);
+ Normalize(eve->no);
+ }
+ }
+}
+
+int compareface(EditFace *vl1, EditFace *vl2)
+{
+ EditVert *v1, *v2, *v3, *v4;
+
+ if(vl1->v4 && vl2->v4) {
+ v1= vl2->v1;
+ v2= vl2->v2;
+ v3= vl2->v3;
+ v4= vl2->v4;
+
+ if(vl1->v1==v1 || vl1->v2==v1 || vl1->v3==v1 || vl1->v4==v1) {
+ if(vl1->v1==v2 || vl1->v2==v2 || vl1->v3==v2 || vl1->v4==v2) {
+ if(vl1->v1==v3 || vl1->v2==v3 || vl1->v3==v3 || vl1->v4==v3) {
+ if(vl1->v1==v4 || vl1->v2==v4 || vl1->v3==v4 || vl1->v4==v4) {
+ return 1;
+ }
+ }
+ }
+ }
+ }
+ else if(vl1->v4==0 && vl2->v4==0) {
+ v1= vl2->v1;
+ v2= vl2->v2;
+ v3= vl2->v3;
+
+ if(vl1->v1==v1 || vl1->v2==v1 || vl1->v3==v1) {
+ if(vl1->v1==v2 || vl1->v2==v2 || vl1->v3==v2) {
+ if(vl1->v1==v3 || vl1->v2==v3 || vl1->v3==v3) {
+ return 1;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* checks for existance, not tria overlapping inside quad */
+EditFace *exist_face(EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa, efatest;
+
+ efatest.v1= v1;
+ efatest.v2= v2;
+ efatest.v3= v3;
+ efatest.v4= v4;
+
+ efa= em->faces.first;
+ while(efa) {
+ if(compareface(&efatest, efa)) return efa;
+ efa= efa->next;
+ }
+ return NULL;
+}
+
+/* evaluate if entire quad is a proper convex quad */
+int convex(float *v1, float *v2, float *v3, float *v4)
+{
+ float nor[3], nor1[3], nor2[3], vec[4][2];
+
+ /* define projection, do both trias apart, quad is undefined! */
+ CalcNormFloat(v1, v2, v3, nor1);
+ CalcNormFloat(v1, v3, v4, nor2);
+ nor[0]= ABS(nor1[0]) + ABS(nor2[0]);
+ nor[1]= ABS(nor1[1]) + ABS(nor2[1]);
+ nor[2]= ABS(nor1[2]) + ABS(nor2[2]);
+
+ if(nor[2] >= nor[0] && nor[2] >= nor[1]) {
+ vec[0][0]= v1[0]; vec[0][1]= v1[1];
+ vec[1][0]= v2[0]; vec[1][1]= v2[1];
+ vec[2][0]= v3[0]; vec[2][1]= v3[1];
+ vec[3][0]= v4[0]; vec[3][1]= v4[1];
+ }
+ else if(nor[1] >= nor[0] && nor[1]>= nor[2]) {
+ vec[0][0]= v1[0]; vec[0][1]= v1[2];
+ vec[1][0]= v2[0]; vec[1][1]= v2[2];
+ vec[2][0]= v3[0]; vec[2][1]= v3[2];
+ vec[3][0]= v4[0]; vec[3][1]= v4[2];
+ }
+ else {
+ vec[0][0]= v1[1]; vec[0][1]= v1[2];
+ vec[1][0]= v2[1]; vec[1][1]= v2[2];
+ vec[2][0]= v3[1]; vec[2][1]= v3[2];
+ vec[3][0]= v4[1]; vec[3][1]= v4[2];
+ }
+
+ /* linetests, the 2 diagonals have to instersect to be convex */
+ if( IsectLL2Df(vec[0], vec[2], vec[1], vec[3]) > 0 ) return 1;
+ return 0;
+}
+
+
+/* ********************* Fake Polgon support (FGon) ***************** */
+
+
+/* results in:
+ - faces having ->fgonf flag set (also for draw)
+ - edges having ->fgoni index set (for select)
+*/
+
+float EM_face_area(EditFace *efa)
+{
+ if(efa->v4) return AreaQ3Dfl(efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co);
+ else return AreaT3Dfl(efa->v1->co, efa->v2->co, efa->v3->co);
+}
+
+float EM_face_perimeter(EditFace *efa)
+{
+ if(efa->v4) return
+ VecLenf(efa->v1->co, efa->v2->co)+
+ VecLenf(efa->v2->co, efa->v3->co)+
+ VecLenf(efa->v3->co, efa->v4->co)+
+ VecLenf(efa->v4->co, efa->v1->co);
+
+ else return
+ VecLenf(efa->v1->co, efa->v2->co)+
+ VecLenf(efa->v2->co, efa->v3->co)+
+ VecLenf(efa->v3->co, efa->v1->co);
+}
+
+void EM_fgon_flags(void)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa, *efan, *efamax;
+ EditEdge *eed;
+ ListBase listb={NULL, NULL};
+ float size, maxsize;
+ short done, curindex= 1;
+
+ // for each face with fgon edge AND not fgon flag set
+ for(eed= em->edges.first; eed; eed= eed->next) eed->fgoni= 0; // index
+ for(efa= em->faces.first; efa; efa= efa->next) efa->fgonf= 0; // flag
+
+ // for speed & simplicity, put fgon face candidates in new listbase
+ efa= em->faces.first;
+ while(efa) {
+ efan= efa->next;
+ if( (efa->e1->h & EM_FGON) || (efa->e2->h & EM_FGON) ||
+ (efa->e3->h & EM_FGON) || (efa->e4 && (efa->e4->h & EM_FGON)) ) {
+ BLI_remlink(&em->faces, efa);
+ BLI_addtail(&listb, efa);
+ }
+ efa= efan;
+ }
+
+ // find an undone face with fgon edge
+ for(efa= listb.first; efa; efa= efa->next) {
+ if(efa->fgonf==0) {
+
+ // init this face
+ efa->fgonf= EM_FGON;
+ if(efa->e1->h & EM_FGON) efa->e1->fgoni= curindex;
+ if(efa->e2->h & EM_FGON) efa->e2->fgoni= curindex;
+ if(efa->e3->h & EM_FGON) efa->e3->fgoni= curindex;
+ if(efa->e4 && (efa->e4->h & EM_FGON)) efa->e4->fgoni= curindex;
+
+ // we search for largest face, to give facedot drawing rights
+ maxsize= EM_face_area(efa);
+ efamax= efa;
+
+ // now flush curendex over edges and set faceflags
+ done= 1;
+ while(done==1) {
+ done= 0;
+
+ for(efan= listb.first; efan; efan= efan->next) {
+ if(efan->fgonf==0) {
+ // if one if its edges has index set, do other too
+ if( (efan->e1->fgoni==curindex) || (efan->e2->fgoni==curindex) ||
+ (efan->e3->fgoni==curindex) || (efan->e4 && (efan->e4->fgoni==curindex)) ) {
+
+ efan->fgonf= EM_FGON;
+ if(efan->e1->h & EM_FGON) efan->e1->fgoni= curindex;
+ if(efan->e2->h & EM_FGON) efan->e2->fgoni= curindex;
+ if(efan->e3->h & EM_FGON) efan->e3->fgoni= curindex;
+ if(efan->e4 && (efan->e4->h & EM_FGON)) efan->e4->fgoni= curindex;
+
+ size= EM_face_area(efan);
+ if(size>maxsize) {
+ efamax= efan;
+ maxsize= size;
+ }
+ done= 1;
+ }
+ }
+ }
+ }
+
+ efamax->fgonf |= EM_FGON_DRAW;
+ curindex++;
+
+ }
+ }
+
+ // put fgon face candidates back in listbase
+ efa= listb.first;
+ while(efa) {
+ efan= efa->next;
+ BLI_remlink(&listb, efa);
+ BLI_addtail(&em->faces, efa);
+ efa= efan;
+ }
+
+ // remove fgon flags when edge not in fgon (anymore)
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->fgoni==0) eed->h &= ~EM_FGON;
+ }
+
+}
+
+/* editmesh vertmap, copied from intern.mesh.c
+ * if do_face_idx_array is 0 it means we need to run it as well as freeing
+ * */
+
+UvVertMap *make_uv_vert_map_EM(int selected, int do_face_idx_array, float *limit)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *ev;
+ EditFace *efa;
+ int totverts;
+
+ /* vars from original func */
+ UvVertMap *vmap;
+ UvMapVert *buf;
+ MTFace *tf;
+ unsigned int a;
+ int i, totuv, nverts;
+
+ if (do_face_idx_array)
+ EM_init_index_arrays(0, 0, 1);
+
+ /* we need the vert */
+ for (ev= em->verts.first, totverts=0; ev; ev= ev->next, totverts++) {
+ ev->tmp.l = totverts;
+ }
+
+ totuv = 0;
+
+ /* generate UvMapVert array */
+ for (efa= em->faces.first; efa; efa= efa->next)
+ if(!selected || ((!efa->h) && (efa->f & SELECT)))
+ totuv += (efa->v4)? 4: 3;
+
+ if(totuv==0)
+ return NULL;
+
+ vmap= (UvVertMap*)MEM_mallocN(sizeof(*vmap), "UvVertMap");
+ if (!vmap)
+ return NULL;
+
+ vmap->vert= (UvMapVert**)MEM_callocN(sizeof(*vmap->vert)*totverts, "UvMapVert*");
+ buf= vmap->buf= (UvMapVert*)MEM_mallocN(sizeof(*vmap->buf)*totuv, "UvMapVert");
+
+ if (!vmap->vert || !vmap->buf) {
+ free_uv_vert_map(vmap);
+ return NULL;
+ }
+
+ for (a=0, efa= em->faces.first; efa; a++, efa= efa->next) {
+ if(!selected || ((!efa->h) && (efa->f & SELECT))) {
+ nverts= (efa->v4)? 4: 3;
+
+ for(i=0; i<nverts; i++) {
+ buf->tfindex= i;
+ buf->f= a;
+ buf->separate = 0;
+
+ buf->next= vmap->vert[(*(&efa->v1 + i))->tmp.l];
+ vmap->vert[(*(&efa->v1 + i))->tmp.l]= buf;
+
+ buf++;
+ }
+ }
+ }
+
+ /* sort individual uvs for each vert */
+ for(a=0, ev=em->verts.first; ev; a++, ev= ev->next) {
+ UvMapVert *newvlist= NULL, *vlist=vmap->vert[a];
+ UvMapVert *iterv, *v, *lastv, *next;
+ float *uv, *uv2, uvdiff[2];
+
+ while(vlist) {
+ v= vlist;
+ vlist= vlist->next;
+ v->next= newvlist;
+ newvlist= v;
+
+ efa = EM_get_face_for_index(v->f);
+ tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ uv = tf->uv[v->tfindex];
+
+ lastv= NULL;
+ iterv= vlist;
+
+ while(iterv) {
+ next= iterv->next;
+ efa = EM_get_face_for_index(iterv->f);
+ tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ uv2 = tf->uv[iterv->tfindex];
+
+ Vec2Subf(uvdiff, uv2, uv);
+
+ if(fabs(uv[0]-uv2[0]) < limit[0] && fabs(uv[1]-uv2[1]) < limit[1]) {
+ if(lastv) lastv->next= next;
+ else vlist= next;
+ iterv->next= newvlist;
+ newvlist= iterv;
+ }
+ else
+ lastv=iterv;
+
+ iterv= next;
+ }
+
+ newvlist->separate = 1;
+ }
+
+ vmap->vert[a]= newvlist;
+ }
+
+ if (do_face_idx_array)
+ EM_free_index_arrays();
+
+ return vmap;
+}
+
+UvMapVert *get_uv_map_vert_EM(UvVertMap *vmap, unsigned int v)
+{
+ return vmap->vert[v];
+}
+
+void free_uv_vert_map_EM(UvVertMap *vmap)
+{
+ if (vmap) {
+ if (vmap->vert) MEM_freeN(vmap->vert);
+ if (vmap->buf) MEM_freeN(vmap->buf);
+ MEM_freeN(vmap);
+ }
+}
+
diff --git a/source/blender/src/editmesh_loop.c b/source/blender/src/editmesh_loop.c
new file mode 100644
index 00000000000..c44a0607464
--- /dev/null
+++ b/source/blender/src/editmesh_loop.c
@@ -0,0 +1,954 @@
+/**
+ * $Id:
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/*
+
+editmesh_loop: tools with own drawing subloops, select, knife, subdiv
+
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_editVert.h"
+#include "BLI_ghash.h"
+
+#include "BKE_depsgraph.h"
+#include "BKE_displist.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_utildefines.h"
+
+#ifdef WITH_VERSE
+#include "BKE_verse.h"
+#endif
+
+#include "BIF_cursors.h"
+#include "BIF_editmesh.h"
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+#include "BIF_graphics.h"
+#include "BIF_interface.h"
+#include "BIF_mywindow.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_toolbox.h"
+
+#ifdef WITH_VERSE
+#include "BIF_verse.h"
+#endif
+
+#include "BSE_view.h"
+#include "BSE_edit.h"
+#include "BSE_drawview.h"
+
+#include "BDR_drawobject.h"
+#include "BDR_editobject.h"
+#include "PIL_time.h"
+
+#include "mydevice.h"
+#include "blendef.h"
+
+#include "editmesh.h"
+
+/* next 2 includes for knife tool... shouldnt be! (ton) */
+#include "GHOST_C-api.h"
+#include "winlay.h"
+
+
+/* New LoopCut */
+static void edgering_sel(EditEdge *startedge, int select, int previewlines)
+{
+ EditMesh *em = G.editMesh;
+ EditEdge *eed;
+ EditFace *efa;
+ EditVert *v[2][2];
+ float co[2][3];
+ int looking= 1,i;
+
+ /* in eed->f1 we put the valence (amount of faces in edge) */
+ /* in eed->f2 we put tagged flag as correct loop */
+ /* in efa->f1 we put tagged flag as correct to select */
+
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ eed->f1= 0;
+ eed->f2= 0;
+ }
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ efa->f1= 0;
+ if(efa->h==0) {
+ efa->e1->f1++;
+ efa->e2->f1++;
+ efa->e3->f1++;
+ if(efa->e4) efa->e4->f1++;
+ }
+ }
+
+ // tag startedge OK
+ startedge->f2= 1;
+
+ while(looking) {
+ looking= 0;
+
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->e4 && efa->f1==0 && efa->h == 0) { // not done quad
+ if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { // valence ok
+
+ // if edge tagged, select opposing edge and mark face ok
+ if(efa->e1->f2) {
+ efa->e3->f2= 1;
+ efa->f1= 1;
+ looking= 1;
+ }
+ else if(efa->e2->f2) {
+ efa->e4->f2= 1;
+ efa->f1= 1;
+ looking= 1;
+ }
+ if(efa->e3->f2) {
+ efa->e1->f2= 1;
+ efa->f1= 1;
+ looking= 1;
+ }
+ if(efa->e4->f2) {
+ efa->e2->f2= 1;
+ efa->f1= 1;
+ looking= 1;
+ }
+ }
+ }
+ }
+ }
+
+ if(previewlines > 0 && select == 0){
+ persp(PERSP_VIEW);
+ glPushMatrix();
+ mymultmatrix(G.obedit->obmat);
+ //glColor3ub(0, 255, 255);
+ //glBegin(GL_LINES);
+ //glVertex3f(nearest->v1->co[0],nearest->v1->co[1],nearest->v1->co[2]);
+ //glVertex3f(nearest->v2->co[0],nearest->v2->co[1],nearest->v2->co[2]);
+ //glEnd();
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->v4 == NULL) { continue; }
+ if(efa->h == 0){
+ if(efa->e1->f2 == 1){
+ if(efa->e1->h == 1 || efa->e3->h == 1 )
+ continue;
+
+ v[0][0] = efa->v1;
+ v[0][1] = efa->v2;
+ v[1][0] = efa->v4;
+ v[1][1] = efa->v3;
+ } else if(efa->e2->f2 == 1){
+ if(efa->e2->h == 1 || efa->e4->h == 1)
+ continue;
+ v[0][0] = efa->v2;
+ v[0][1] = efa->v3;
+ v[1][0] = efa->v1;
+ v[1][1] = efa->v4;
+ } else { continue; }
+
+ for(i=1;i<=previewlines;i++){
+ co[0][0] = (v[0][1]->co[0] - v[0][0]->co[0])*(i/((float)previewlines+1))+v[0][0]->co[0];
+ co[0][1] = (v[0][1]->co[1] - v[0][0]->co[1])*(i/((float)previewlines+1))+v[0][0]->co[1];
+ co[0][2] = (v[0][1]->co[2] - v[0][0]->co[2])*(i/((float)previewlines+1))+v[0][0]->co[2];
+
+ co[1][0] = (v[1][1]->co[0] - v[1][0]->co[0])*(i/((float)previewlines+1))+v[1][0]->co[0];
+ co[1][1] = (v[1][1]->co[1] - v[1][0]->co[1])*(i/((float)previewlines+1))+v[1][0]->co[1];
+ co[1][2] = (v[1][1]->co[2] - v[1][0]->co[2])*(i/((float)previewlines+1))+v[1][0]->co[2];
+ glColor3ub(255, 0, 255);
+ glBegin(GL_LINES);
+ glVertex3f(co[0][0],co[0][1],co[0][2]);
+ glVertex3f(co[1][0],co[1][1],co[1][2]);
+ glEnd();
+ }
+ }
+ }
+ glPopMatrix();
+ } else {
+
+ /* (de)select the edges */
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->f2) EM_select_edge(eed, select);
+ }
+ }
+}
+void CutEdgeloop(int numcuts)
+{
+ EditMesh *em = G.editMesh;
+ EditEdge *nearest=NULL, *eed;
+ float fac;
+ int keys = 0, holdnum=0, selectmode, dist;
+ short mvalo[2] = {0,0}, mval[2];
+ short event, val, choosing=1, cancel=0, cuthalf = 0, smooth=0;
+ short hasHidden = 0;
+ char msg[128];
+
+ selectmode = G.scene->selectmode;
+
+ if(G.scene->selectmode & SCE_SELECT_FACE){
+ G.scene->selectmode = SCE_SELECT_EDGE;
+ EM_selectmode_set();
+ }
+
+
+ BIF_undo_push("Loopcut Begin");
+ while(choosing && !cancel){
+ getmouseco_areawin(mval);
+ if (mval[0] != mvalo[0] || mval[1] != mvalo[1]) {
+ mvalo[0] = mval[0];
+ mvalo[1] = mval[1];
+ dist= 50;
+ nearest = findnearestedge(&dist); // returns actual distance in dist
+ scrarea_do_windraw(curarea); // after findnearestedge, backbuf!
+
+ sprintf(msg,"Number of Cuts: %d",numcuts);
+ if(smooth){
+ sprintf(msg,"%s (S)mooth: on",msg);
+ } else {
+ sprintf(msg,"%s (S)mooth: off",msg);
+ }
+
+ headerprint(msg);
+ /* Need to figure preview */
+ if(nearest){
+ edgering_sel(nearest, 0, numcuts);
+ }
+ screen_swapbuffers();
+
+ /* backbuffer refresh for non-apples (no aux) */
+#ifndef __APPLE__
+ if(G.vd->drawtype>OB_WIRE && (G.vd->flag & V3D_ZBUF_SELECT)) {
+ backdrawview3d(0);
+ }
+#endif
+ }
+ else PIL_sleep_ms(10); // idle
+
+
+ while(qtest())
+ {
+ val=0;
+ event= extern_qread(&val);
+ if(val && (event == MOUSEX || event == MOUSEY)){ ; }
+ else if(val && ((event==LEFTMOUSE || event==RETKEY) || (event == MIDDLEMOUSE || event==PADENTER)))
+ {
+ if(event == MIDDLEMOUSE){
+ cuthalf = 1;
+ }
+ if (nearest==NULL)
+ cancel = 1;
+ choosing=0;
+ mvalo[0] = -1;
+ }
+ else if(val && (event==ESCKEY || event==RIGHTMOUSE ))
+ {
+ choosing=0;
+ cancel = 1;
+ mvalo[0] = -1;
+ }
+ else if(val && (event==PADPLUSKEY || event==WHEELUPMOUSE))
+ {
+ numcuts++;
+ mvalo[0] = -1;
+ }
+ else if(val && (event==PADMINUS || event==WHEELDOWNMOUSE))
+ {
+ if(numcuts > 1){
+ numcuts--;
+ mvalo[0] = -1;
+ }
+ }
+ else if(val && event==SKEY)
+ {
+ if(smooth){smooth=0;}
+ else { smooth=1; }
+ mvalo[0] = -1;
+ }
+
+ else if(val){
+ holdnum = -1;
+ switch(event){
+ case PAD9:
+ case NINEKEY:
+ holdnum = 9; break;
+ case PAD8:
+ case EIGHTKEY:
+ holdnum = 8;break;
+ case PAD7:
+ case SEVENKEY:
+ holdnum = 7;break;
+ case PAD6:
+ case SIXKEY:
+ holdnum = 6;break;
+ case PAD5:
+ case FIVEKEY:
+ holdnum = 5;break;
+ case PAD4:
+ case FOURKEY:
+ holdnum = 4;break;
+ case PAD3:
+ case THREEKEY:
+ holdnum = 3; break;
+ case PAD2:
+ case TWOKEY:
+ holdnum = 2;break;
+ case PAD1:
+ case ONEKEY:
+ holdnum = 1; break;
+ case PAD0:
+ case ZEROKEY:
+ holdnum = 0;break;
+ case BACKSPACEKEY:
+ holdnum = -2;break;
+ }
+ if(holdnum >= 0 && numcuts*10 < 130){
+ if(keys == 0){ // first level numeric entry
+ if(holdnum > 0){
+ numcuts = holdnum;
+ keys++;
+ }
+ } else if(keys > 0){//highrt level numeric entry
+ numcuts *= 10;
+ numcuts += holdnum;
+ keys++;
+ }
+ } else if (holdnum == -2){// backspace
+ if (keys > 1){
+ numcuts /= 10;
+ keys--;
+ } else {
+ numcuts=1;
+ keys = 0;
+ }
+ }
+ mvalo[0] = -1;
+ break;
+ } // End Numeric Entry
+ } //End while(qtest())
+ } // End Choosing
+ scrarea_queue_winredraw(curarea);
+
+ if(cancel){
+ return;
+ }
+ /* clean selection */
+ for(eed=em->edges.first; eed; eed = eed->next){
+ EM_select_edge(eed,0);
+ }
+ /* select edge ring */
+ edgering_sel(nearest, 1, 0);
+
+ /* now cut the loops */
+ if(smooth){
+ fac= 1.0f;
+ if(fbutton(&fac, 0.0f, 5.0f, 10, 10, "Smooth:")==0) return;
+ fac= 0.292f*fac;
+ esubdivideflag(SELECT,fac,B_SMOOTH,numcuts,SUBDIV_SELECT_LOOPCUT);
+ } else {
+ esubdivideflag(SELECT,0,0,numcuts,SUBDIV_SELECT_LOOPCUT);
+ }
+ /* if this was a single cut, enter edgeslide mode */
+ if(numcuts == 1 && hasHidden == 0){
+ if(cuthalf)
+ EdgeSlide(1,0.0);
+ else {
+ if(EdgeSlide(0,0.0) == -1){
+ BIF_undo();
+ }
+ }
+ }
+
+ if(G.scene->selectmode != selectmode){
+ G.scene->selectmode = selectmode;
+ EM_selectmode_set();
+ }
+
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+#ifdef WITH_VERSE
+ if(G.editMesh->vnode)
+ sync_all_verseverts_with_editverts((VNode*)G.editMesh->vnode);
+#endif
+ scrarea_queue_headredraw(curarea);
+ scrarea_queue_winredraw(curarea);
+ return;
+}
+
+
+/* *************** LOOP SELECT ************* */
+#if 0
+static short edgeFaces(EditEdge *e)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *search=NULL;
+ short count = 0;
+
+ search = em->faces.first;
+ while(search){
+ if((search->e1 == e || search->e2 == e) || (search->e3 == e || search->e4 == e))
+ count++;
+ search = search->next;
+ }
+ return count;
+}
+#endif
+
+/* this utility function checks to see if 2 edit edges share a face,
+ returns 1 if they do
+ returns 0 if they do not, or if the function is passed the same edge 2 times
+*/
+short sharesFace(EditEdge* e1, EditEdge* e2)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *search=NULL;
+
+ search = em->faces.first;
+ if (e1 == e2){
+ return 0 ;
+ }
+ while(search){
+ if(
+ ((search->e1 == e1 || search->e2 == e1) || (search->e3 == e1 || search->e4 == e1)) &&
+ ((search->e1 == e2 || search->e2 == e2) || (search->e3 == e2 || search->e4 == e2))
+ ) {
+ return 1;
+ }
+ search = search->next;
+ }
+ return 0;
+}
+
+
+/* ***************** TRAIL ************************
+
+Read a trail of mouse coords and return them as an array of CutCurve structs
+len returns number of mouse coords read before commiting with RETKEY
+It is up to the caller to free the block when done with it,
+
+XXX Is only used here, so local inside this file (ton)
+ */
+
+#define TRAIL_POLYLINE 1 /* For future use, They don't do anything yet */
+#define TRAIL_FREEHAND 2
+#define TRAIL_MIXED 3 /* (1|2) */
+#define TRAIL_AUTO 4
+#define TRAIL_MIDPOINTS 8
+
+typedef struct CutCurve {
+ float x;
+ float y;
+} CutCurve;
+
+static CutCurve *get_mouse_trail(int *len, char mode, char cutmode, struct GHash *gh)
+{
+ CutCurve *curve,*temp;
+ EditVert *snapvert;
+ float *scr, mval[2], lastx=0, lasty=0;
+ int i=0, j, blocks=1, lasti=0;
+ int dist, tolerance;
+ short event, val, qual, vsnap=0, ldown=0, restart=0, rubberband=0;
+ short mval1[2], lockaxis=0, lockx=0, locky=0, oldmode;
+
+ *len=0;
+ tolerance = 75;
+
+ curve=(CutCurve *)MEM_callocN(1024*sizeof(CutCurve), "MouseTrail");
+
+ if (!curve) {
+ printf("failed to allocate memory in get_mouse_trail()\n");
+ return(NULL);
+ }
+ mywinset(curarea->win);
+
+
+ if(cutmode != KNIFE_MULTICUT){
+ /*redraw backbuffer if in zbuffered selection mode but not vertex selection*/
+ if(G.vd->drawtype>OB_WIRE && (G.vd->flag & V3D_ZBUF_SELECT)) {
+ oldmode = G.scene->selectmode;
+ G.scene->selectmode = SCE_SELECT_VERTEX;
+ backdrawview3d(0);
+ G.scene->selectmode = oldmode;
+ }
+ glDrawBuffer(GL_FRONT);
+ headerprint("(LMB) draw, (Ctrl held while drawing) snap to vertex, (MMB) constrain to x/y screen axis, (Enter) cut "
+ "(with Ctrl to select cut line), (Esc) cancel");
+ }
+ else{
+ glDrawBuffer(GL_FRONT);
+ headerprint("(LMB) draw, (MMB) constrain to x/y screen axis, (Enter) cut (with Ctrl to select cut line), (Esc) cancel");
+ }
+
+ persp(PERSP_WIN);
+
+ glColor3ub(255, 0, 255);
+
+ while(TRUE) {
+
+ event=extern_qread(&val); /* Enter or RMB indicates finish */
+ if(val) {
+ if(event==RETKEY || event==PADENTER) break;
+ }
+
+ if( event==ESCKEY || event==RIGHTMOUSE ) {
+ if (curve) MEM_freeN(curve);
+ *len=0;
+ bglFlush();
+ glDrawBuffer(GL_BACK);
+ return(NULL);
+ break;
+ }
+
+ if (rubberband) { /* rubberband mode, undraw last rubberband */
+ glLineWidth(2.0);
+ sdrawXORline((int)curve[i-1].x, (int)curve[i-1].y,(int)mval[0],(int) mval[1]);
+ glLineWidth(1.0);
+ glFlush();
+ rubberband=0;
+ }
+
+ /*handle vsnap*/
+ vsnap = 0;
+ if(cutmode != KNIFE_MULTICUT){
+ qual = get_qual();
+ if(qual & LR_CTRLKEY) vsnap = 1;
+ }
+
+ if(vsnap){
+ persp(PERSP_VIEW);
+ dist = tolerance;
+ snapvert = findnearestvert(&dist, SELECT, 0);
+ glColor3ub(255, 0, 255);
+ glDrawBuffer(GL_FRONT);
+ persp(PERSP_WIN);
+ if(snapvert && (dist < tolerance)){
+ scr = BLI_ghash_lookup(gh, snapvert);
+ mval[0] = scr[0];
+ mval[1] = scr[1];
+ }
+ else{
+ getmouseco_areawin(mval1);
+ mval[0] = (float)mval1[0];
+ mval[1] = (float)mval1[1];
+ }
+ }
+
+ else{
+ getmouseco_areawin(mval1);
+ mval[0] = (float)mval1[0];
+ mval[1] = (float)mval1[1];
+ }
+
+
+ if (lockaxis==1) mval[1]=locky;
+ if (lockaxis==2) mval[0]=lockx;
+
+ if ( ((i==0) || (mval[0]!=curve[i-1].x) || (mval[1]!=curve[i-1].y))
+ && (get_mbut() & L_MOUSE) ){ /* record changes only, if LMB down */
+
+ lastx=curve[i].x=mval[0];
+ lasty=curve[i].y=mval[1];
+
+ lockaxis=0;
+
+ i++;
+
+ ldown=1;
+ if (restart) {
+ for(j=1;j<i;j++) sdrawXORline((int)curve[j-1].x, (int)curve[j-1].y, (int)curve[j].x, (int)curve[j].y);
+ if (rubberband) sdrawXORline((int)curve[j].x, (int)curve[j].y, (int)mval[0], (int)mval[1]);
+ glFlush();
+ rubberband=0;
+ lasti=i=0;
+ restart=0;
+ ldown=0;
+ }
+ }
+
+ if ((event==MIDDLEMOUSE)&&(get_mbut()&M_MOUSE)&&(i)){/*MMB Down*/
+ /*determine which axis to lock to, or clear if locked */
+ if (lockaxis) lockaxis=0;
+ else if (abs(curve[i-1].x-mval[0]) > abs(curve[i-1].y-mval[1])) lockaxis=1;
+ else lockaxis=2;
+
+ if (lockaxis) {
+ lockx=lastx;
+ locky=lasty;
+ }
+ }
+
+ if ((i>1)&&(i!=lasti)) { /*Draw recorded part of curve */
+ sdrawline((int)curve[i-2].x, (int)curve[i-2].y, (int)curve[i-1].x, (int)curve[i-1].y);
+ glFlush();
+ }
+
+ if ((i==lasti)&&(i>0)) { /*Draw rubberband */
+ glLineWidth(2.0);
+ sdrawXORline((int)curve[i-1].x, (int)curve[i-1].y,(int)mval[0], (int)mval[1]);
+ glLineWidth(1.0);
+ glFlush();
+ rubberband=1;
+ }
+ lasti=i;
+
+ if (i>=blocks*1024) { /* reallocate data if out of room */
+ temp=curve;
+ curve=(CutCurve *)MEM_callocN((blocks+1)*1024*sizeof(CutCurve), "MouseTrail");
+ if (!curve) {
+ printf("failed to re-allocate memory in get_mouse_trail()\n");
+ return(NULL);
+ }
+ memcpy(curve, temp, blocks*1024*sizeof(CutCurve));
+ blocks++;
+ MEM_freeN(temp);
+ }
+ }
+
+ bglFlush();
+ glDrawBuffer(GL_BACK);
+ persp(PERSP_VIEW);
+
+ *len=i;
+
+ return(curve);
+}
+
+
+
+
+/* ******************************************************************** */
+/* Knife Subdivide Tool. Subdivides edges intersected by a mouse trail
+ drawn by user.
+
+ Currently mapped to KKey when in MeshEdit mode.
+ Usage:
+ Hit Shift K, Select Centers or Exact
+ Hold LMB down to draw path, hit RETKEY.
+ ESC cancels as expected.
+
+ Contributed by Robert Wenzlaff (Det. Thorn).
+*/
+
+/* prototype */
+static float seg_intersect(struct EditEdge * e, CutCurve *c, int len, char mode, struct GHash *gh);
+
+void KnifeSubdivide(char mode)
+{
+ EditMesh *em = G.editMesh;
+ EditEdge *eed;
+ EditVert *eve;
+ CutCurve *curve;
+ Window *win;
+
+ struct GHash *gh;
+ int oldcursor, len=0;
+ float isect=0.0;
+ short numcuts=1;
+ float *scr, co[4];
+
+ if (G.obedit==0) return;
+
+ if (EM_nvertices_selected() < 2) {
+ error("No edges are selected to operate on");
+ return;
+ }
+
+ if (mode==KNIFE_PROMPT) {
+ short val= pupmenu("Cut Type %t|Exact Line%x1|Midpoints%x2|Multicut%x3");
+ if(val<1) return;
+ mode = val; // warning, mode is char, pupmenu returns -1 with ESC
+ }
+
+ if(mode == KNIFE_MULTICUT) {
+ if(button(&numcuts, 2, 128, "Number of Cuts:")==0) return;
+ }
+
+ /* Set a knife cursor here */
+ oldcursor=get_cursor();
+
+ win=winlay_get_active_window();
+
+ SetBlenderCursor(BC_KNIFECURSOR);
+
+ for(eed=em->edges.first; eed; eed= eed->next) eed->tmp.fp = 0.0; /*store percentage of edge cut for KNIFE_EXACT here.*/
+
+ /*the floating point coordinates of verts in screen space will be stored in a hash table according to the vertices pointer*/
+ gh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
+ for(eve=em->verts.first; eve; eve=eve->next){
+ scr = MEM_mallocN(sizeof(float)*2, "Vertex Screen Coordinates");
+ VECCOPY(co, eve->co);
+ co[3]= 1.0;
+ Mat4MulVec4fl(G.obedit->obmat, co);
+ project_float(co,scr);
+ BLI_ghash_insert(gh, eve, scr);
+ eve->f1 = 0; /*store vertex intersection flag here*/
+
+ }
+
+ curve=get_mouse_trail(&len, TRAIL_MIXED, mode, gh);
+
+ if (curve && len && mode){
+ eed= em->edges.first;
+ while(eed) {
+ if( eed->v1->f & eed->v2->f & SELECT ){ // NOTE: uses vertex select, subdiv doesnt do edges yet
+ isect=seg_intersect(eed, curve, len, mode, gh);
+ if (isect) eed->f2= 1;
+ else eed->f2=0;
+ eed->tmp.fp= isect;
+ //printf("isect=%i\n", isect);
+ }
+ else {
+ eed->f2=0;
+ eed->f1=0;
+ }
+ eed= eed->next;
+ }
+
+ if (mode==KNIFE_EXACT) esubdivideflag(1, 0, B_KNIFE|B_PERCENTSUBD,1,SUBDIV_SELECT_ORIG);
+ else if (mode==KNIFE_MIDPOINT) esubdivideflag(1, 0, B_KNIFE,1,SUBDIV_SELECT_ORIG);
+ else if (mode==KNIFE_MULTICUT) esubdivideflag(1, 0, B_KNIFE,numcuts,SUBDIV_SELECT_ORIG);
+
+ eed=em->edges.first;
+ while(eed){
+ eed->f2=0;
+ eed->f1=0;
+ eed=eed->next;
+ }
+ }
+ /* Return to old cursor and flags...*/
+
+ addqueue(curarea->win, REDRAW, 0);
+ window_set_cursor(win, oldcursor);
+ BLI_ghash_free(gh, NULL, (GHashValFreeFP)MEM_freeN);
+ if (curve) MEM_freeN(curve);
+
+#ifdef WITH_VERSE
+ if(G.editMesh->vnode)
+ sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode);
+#endif
+
+ BIF_undo_push("Knife");
+}
+
+/* seg_intersect() Determines if and where a mouse trail intersects an EditEdge */
+
+static float seg_intersect(EditEdge *e, CutCurve *c, int len, char mode, struct GHash *gh)
+{
+#define MAXSLOPE 100000
+ float x11, y11, x12=0, y12=0, x2max, x2min, y2max;
+ float y2min, dist, lastdist=0, xdiff2, xdiff1;
+ float m1, b1, m2, b2, x21, x22, y21, y22, xi;
+ float yi, x1min, x1max, y1max, y1min, perc=0;
+ float *scr;
+ float threshold;
+ int i;
+
+ //threshold = 0.000001; /*tolerance for vertex intersection*/
+ threshold = G.scene->toolsettings->select_thresh / 100;
+
+ /* Get screen coords of verts */
+ scr = BLI_ghash_lookup(gh, e->v1);
+ x21=scr[0];
+ y21=scr[1];
+
+ scr = BLI_ghash_lookup(gh, e->v2);
+ x22=scr[0];
+ y22=scr[1];
+
+ xdiff2=(x22-x21);
+ if (xdiff2) {
+ m2=(y22-y21)/xdiff2;
+ b2= ((x22*y21)-(x21*y22))/xdiff2;
+ }
+ else {
+ m2=MAXSLOPE; /* Verticle slope */
+ b2=x22;
+ }
+
+ /*check for *exact* vertex intersection first*/
+ if(mode!=KNIFE_MULTICUT){
+ for (i=0; i<len; i++){
+ if (i>0){
+ x11=x12;
+ y11=y12;
+ }
+ else {
+ x11=c[i].x;
+ y11=c[i].y;
+ }
+ x12=c[i].x;
+ y12=c[i].y;
+
+ /*test e->v1*/
+ if((x11 == x21 && y11 == y21) || (x12 == x21 && y12 == y21)){
+ e->v1->f1 = 1;
+ perc = 0;
+ return(perc);
+ }
+ /*test e->v2*/
+ else if((x11 == x22 && y11 == y22) || (x12 == x22 && y12 == y22)){
+ e->v2->f1 = 1;
+ perc = 0;
+ return(perc);
+ }
+ }
+ }
+
+ /*now check for edge interesect (may produce vertex intersection as well)*/
+ for (i=0; i<len; i++){
+ if (i>0){
+ x11=x12;
+ y11=y12;
+ }
+ else {
+ x11=c[i].x;
+ y11=c[i].y;
+ }
+ x12=c[i].x;
+ y12=c[i].y;
+
+ /* Perp. Distance from point to line */
+ if (m2!=MAXSLOPE) dist=(y12-m2*x12-b2);/* /sqrt(m2*m2+1); Only looking for */
+ /* change in sign. Skip extra math */
+ else dist=x22-x12;
+
+ if (i==0) lastdist=dist;
+
+ /* if dist changes sign, and intersect point in edge's Bound Box*/
+ if ((lastdist*dist)<=0){
+ xdiff1=(x12-x11); /* Equation of line between last 2 points */
+ if (xdiff1){
+ m1=(y12-y11)/xdiff1;
+ b1= ((x12*y11)-(x11*y12))/xdiff1;
+ }
+ else{
+ m1=MAXSLOPE;
+ b1=x12;
+ }
+ x2max=MAX2(x21,x22)+0.001; /* prevent missed edges */
+ x2min=MIN2(x21,x22)-0.001; /* due to round off error */
+ y2max=MAX2(y21,y22)+0.001;
+ y2min=MIN2(y21,y22)-0.001;
+
+ /* Found an intersect, calc intersect point */
+ if (m1==m2){ /* co-incident lines */
+ /* cut at 50% of overlap area*/
+ x1max=MAX2(x11, x12);
+ x1min=MIN2(x11, x12);
+ xi= (MIN2(x2max,x1max)+MAX2(x2min,x1min))/2.0;
+
+ y1max=MAX2(y11, y12);
+ y1min=MIN2(y11, y12);
+ yi= (MIN2(y2max,y1max)+MAX2(y2min,y1min))/2.0;
+ }
+ else if (m2==MAXSLOPE){
+ xi=x22;
+ yi=m1*x22+b1;
+ }
+ else if (m1==MAXSLOPE){
+ xi=x12;
+ yi=m2*x12+b2;
+ }
+ else {
+ xi=(b1-b2)/(m2-m1);
+ yi=(b1*m2-m1*b2)/(m2-m1);
+ }
+
+ /* Intersect inside bounding box of edge?*/
+ if ((xi>=x2min)&&(xi<=x2max)&&(yi<=y2max)&&(yi>=y2min)){
+ /*test for vertex intersect that may be 'close enough'*/
+ if(mode!=KNIFE_MULTICUT){
+ if(xi <= (x21 + threshold) && xi >= (x21 - threshold)){
+ if(yi <= (y21 + threshold) && yi >= (y21 - threshold)){
+ e->v1->f1 = 1;
+ perc = 0;
+ break;
+ }
+ }
+ if(xi <= (x22 + threshold) && xi >= (x22 - threshold)){
+ if(yi <= (y22 + threshold) && yi >= (y22 - threshold)){
+ e->v2->f1 = 1;
+ perc = 0;
+ break;
+ }
+ }
+ }
+ if ((m2<=1.0)&&(m2>=-1.0)) perc = (xi-x21)/(x22-x21);
+ else perc=(yi-y21)/(y22-y21); /*lower slope more accurate*/
+ //isect=32768.0*(perc+0.0000153); /* Percentage in 1/32768ths */
+ break;
+ }
+ }
+ lastdist=dist;
+ }
+ return(perc);
+}
+
+void LoopMenu() /* Called by KKey */
+{
+ short ret;
+
+ ret=pupmenu("Loop/Cut Menu %t|Loop Cut (CTRL-R)%x2|"
+ "Knife (Exact) %x3|Knife (Midpoints)%x4|Knife (Multicut)%x5");
+
+ switch (ret){
+ case 2:
+ CutEdgeloop(1);
+ break;
+ case 3:
+ KnifeSubdivide(KNIFE_EXACT);
+ break;
+ case 4:
+ KnifeSubdivide(KNIFE_MIDPOINT);
+ break;
+ case 5:
+ KnifeSubdivide(KNIFE_MULTICUT);
+ break;
+ }
+
+}
+
diff --git a/source/blender/src/editmesh_mods.c b/source/blender/src/editmesh_mods.c
new file mode 100644
index 00000000000..ae10cef0879
--- /dev/null
+++ b/source/blender/src/editmesh_mods.c
@@ -0,0 +1,4132 @@
+/**
+ * $Id:
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/*
+
+editmesh_mods.c, UI level access, no geometry changes
+
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "MTC_matrixops.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_material_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_editVert.h"
+#include "BLI_rand.h"
+
+#include "BKE_displist.h"
+#include "BKE_depsgraph.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_customdata.h"
+#include "BKE_global.h"
+#include "BKE_mesh.h"
+#include "BKE_material.h"
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
+
+#ifdef WITH_VERSE
+#include "BKE_verse.h"
+#endif
+
+#include "BIF_editmesh.h"
+#include "BIF_resources.h"
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+#include "BIF_graphics.h"
+#include "BIF_interface.h"
+#include "BIF_meshtools.h"
+#include "BIF_mywindow.h"
+#include "BIF_resources.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_toolbox.h"
+#include "BIF_editsima.h"
+
+#ifdef WITH_VERSE
+#include "BIF_verse.h"
+#endif
+
+#include "BDR_drawobject.h"
+#include "BDR_editobject.h"
+
+#include "BSE_drawview.h"
+#include "BSE_edit.h"
+#include "BSE_view.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "RE_render_ext.h" /* externtex */
+
+#include "multires.h"
+#include "mydevice.h"
+#include "blendef.h"
+
+#include "editmesh.h"
+
+
+/* ****************************** MIRROR **************** */
+
+void EM_select_mirrored(void)
+{
+ if(G.scene->selectmode & SCE_SELECT_VERTEX) {
+ EditMesh *em = G.editMesh;
+ EditVert *eve, *v1;
+
+ for(eve= em->verts.first; eve; eve= eve->next) {
+ if(eve->f & SELECT) {
+ v1= editmesh_get_x_mirror_vert(G.obedit, eve->co);
+ if(v1) {
+ eve->f &= ~SELECT;
+ v1->f |= SELECT;
+ }
+ }
+ }
+ }
+}
+
+void EM_automerge(int update) {
+ int len;
+ if (G.scene->automerge) {
+ if (G.obedit && G.obedit->type==OB_MESH) {
+ len = removedoublesflag(1, 1, G.scene->toolsettings->doublimit);
+ if (len) {
+ G.totvert -= len; /* saves doing a countall */
+ if (update) {
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ }
+ }
+ }
+ }
+}
+
+/* ****************************** SELECTION ROUTINES **************** */
+
+unsigned int em_solidoffs=0, em_wireoffs=0, em_vertoffs=0; /* set in drawobject.c ... for colorindices */
+
+/* facilities for border select and circle select */
+static char *selbuf= NULL;
+
+/* opengl doesn't support concave... */
+static void draw_triangulated(short mcords[][2], short tot)
+{
+ ListBase lb={NULL, NULL};
+ DispList *dl;
+ float *fp;
+ int a;
+
+ /* make displist */
+ dl= MEM_callocN(sizeof(DispList), "poly disp");
+ dl->type= DL_POLY;
+ dl->parts= 1;
+ dl->nr= tot;
+ dl->verts= fp= MEM_callocN(tot*3*sizeof(float), "poly verts");
+ BLI_addtail(&lb, dl);
+
+ for(a=0; a<tot; a++, fp+=3) {
+ fp[0]= (float)mcords[a][0];
+ fp[1]= (float)mcords[a][1];
+ }
+
+ /* do the fill */
+ filldisplist(&lb, &lb);
+
+ /* do the draw */
+ dl= lb.first; /* filldisplist adds in head of list */
+ if(dl->type==DL_INDEX3) {
+ int *index;
+
+ a= dl->parts;
+ fp= dl->verts;
+ index= dl->index;
+ glBegin(GL_TRIANGLES);
+ while(a--) {
+ glVertex3fv(fp+3*index[0]);
+ glVertex3fv(fp+3*index[1]);
+ glVertex3fv(fp+3*index[2]);
+ index+= 3;
+ }
+ glEnd();
+ }
+
+ freedisplist(&lb);
+}
+
+
+/* reads rect, and builds selection array for quick lookup */
+/* returns if all is OK */
+int EM_init_backbuf_border(short xmin, short ymin, short xmax, short ymax)
+{
+ struct ImBuf *buf;
+ unsigned int *dr;
+ int a;
+
+ if(G.obedit==NULL || G.vd->drawtype<OB_SOLID || (G.vd->flag & V3D_ZBUF_SELECT)==0) return 0;
+ if(em_vertoffs==0) return 0;
+
+ buf= read_backbuf(xmin, ymin, xmax, ymax);
+ if(buf==NULL) return 0;
+
+ dr = buf->rect;
+
+ /* build selection lookup */
+ selbuf= MEM_callocN(em_vertoffs+1, "selbuf");
+
+ a= (xmax-xmin+1)*(ymax-ymin+1);
+ while(a--) {
+ if(*dr>0 && *dr<=em_vertoffs)
+ selbuf[*dr]= 1;
+ dr++;
+ }
+ IMB_freeImBuf(buf);
+ return 1;
+}
+
+int EM_check_backbuf(unsigned int index)
+{
+ if(selbuf==NULL) return 1;
+ if(index>0 && index<=em_vertoffs)
+ return selbuf[index];
+ return 0;
+}
+
+void EM_free_backbuf(void)
+{
+ if(selbuf) MEM_freeN(selbuf);
+ selbuf= NULL;
+}
+
+/* mcords is a polygon mask
+ - grab backbuffer,
+ - draw with black in backbuffer,
+ - grab again and compare
+ returns 'OK'
+*/
+int EM_mask_init_backbuf_border(short mcords[][2], short tot, short xmin, short ymin, short xmax, short ymax)
+{
+ unsigned int *dr, *drm;
+ struct ImBuf *buf, *bufmask;
+ int a;
+
+ /* method in use for face selecting too */
+ if(G.obedit==NULL) {
+ if(FACESEL_PAINT_TEST);
+ else return 0;
+ }
+ else if(G.vd->drawtype<OB_SOLID || (G.vd->flag & V3D_ZBUF_SELECT)==0) return 0;
+
+ if(em_vertoffs==0) return 0;
+
+ buf= read_backbuf(xmin, ymin, xmax, ymax);
+ if(buf==NULL) return 0;
+
+ dr = buf->rect;
+
+ /* draw the mask */
+#ifdef __APPLE__
+ glDrawBuffer(GL_AUX0);
+#endif
+ glDisable(GL_DEPTH_TEST);
+
+ persp(PERSP_WIN);
+ glColor3ub(0, 0, 0);
+
+ /* yah, opengl doesn't do concave... tsk! */
+ draw_triangulated(mcords, tot);
+
+ glBegin(GL_LINE_LOOP); /* for zero sized masks, lines */
+ for(a=0; a<tot; a++) glVertex2s(mcords[a][0], mcords[a][1]);
+ glEnd();
+
+ persp(PERSP_VIEW);
+ glFinish(); /* to be sure readpixels sees mask */
+
+ glDrawBuffer(GL_BACK);
+
+ /* grab mask */
+ bufmask= read_backbuf(xmin, ymin, xmax, ymax);
+ drm = bufmask->rect;
+ if(bufmask==NULL) return 0; /* only when mem alloc fails, go crash somewhere else! */
+
+ /* build selection lookup */
+ selbuf= MEM_callocN(em_vertoffs+1, "selbuf");
+
+ a= (xmax-xmin+1)*(ymax-ymin+1);
+ while(a--) {
+ if(*dr>0 && *dr<=em_vertoffs && *drm==0) selbuf[*dr]= 1;
+ dr++; drm++;
+ }
+ IMB_freeImBuf(buf);
+ IMB_freeImBuf(bufmask);
+ return 1;
+
+}
+
+/* circle shaped sample area */
+int EM_init_backbuf_circle(short xs, short ys, short rads)
+{
+ struct ImBuf *buf;
+ unsigned int *dr;
+ short xmin, ymin, xmax, ymax, xc, yc;
+ int radsq;
+
+ /* method in use for face selecting too */
+ if(G.obedit==NULL) {
+ if(FACESEL_PAINT_TEST);
+ else return 0;
+ }
+ else if(G.vd->drawtype<OB_SOLID || (G.vd->flag & V3D_ZBUF_SELECT)==0) return 0;
+ if(em_vertoffs==0) return 0;
+
+ xmin= xs-rads; xmax= xs+rads;
+ ymin= ys-rads; ymax= ys+rads;
+ buf= read_backbuf(xmin, ymin, xmax, ymax);
+ if(buf==NULL) return 0;
+
+ dr = buf->rect;
+
+ /* build selection lookup */
+ selbuf= MEM_callocN(em_vertoffs+1, "selbuf");
+ radsq= rads*rads;
+ for(yc= -rads; yc<=rads; yc++) {
+ for(xc= -rads; xc<=rads; xc++, dr++) {
+ if(xc*xc + yc*yc < radsq) {
+ if(*dr>0 && *dr<=em_vertoffs) selbuf[*dr]= 1;
+ }
+ }
+ }
+
+ IMB_freeImBuf(buf);
+ return 1;
+
+}
+
+static void findnearestvert__doClosest(void *userData, EditVert *eve, int x, int y, int index)
+{
+ struct { short mval[2], pass, select, strict; int dist, lastIndex, closestIndex; EditVert *closest; } *data = userData;
+
+ if (data->pass==0) {
+ if (index<=data->lastIndex)
+ return;
+ } else {
+ if (index>data->lastIndex)
+ return;
+ }
+
+ if (data->dist>3) {
+ int temp = abs(data->mval[0] - x) + abs(data->mval[1]- y);
+ if ((eve->f&1) == data->select) {
+ if (data->strict == 1)
+ return;
+ else
+ temp += 5;
+ }
+
+ if (temp<data->dist) {
+ data->dist = temp;
+ data->closest = eve;
+ data->closestIndex = index;
+ }
+ }
+}
+
+
+
+
+static unsigned int findnearestvert__backbufIndextest(unsigned int index){
+ EditVert *eve = BLI_findlink(&G.editMesh->verts, index-1);
+ if(eve && (eve->f & SELECT)) return 0;
+ return 1;
+}
+/**
+ * findnearestvert
+ *
+ * dist (in/out): minimal distance to the nearest and at the end, actual distance
+ * sel: selection bias
+ * if SELECT, selected vertice are given a 5 pixel bias to make them farter than unselect verts
+ * if 0, unselected vertice are given the bias
+ * strict: if 1, the vertice corresponding to the sel parameter are ignored and not just biased
+ */
+EditVert *findnearestvert(int *dist, short sel, short strict)
+{
+ short mval[2];
+
+ getmouseco_areawin(mval);
+ if(G.vd->drawtype>OB_WIRE && (G.vd->flag & V3D_ZBUF_SELECT)){
+ int distance;
+ unsigned int index;
+ EditVert *eve;
+
+ if(strict) index = sample_backbuf_rect(mval, 50, em_wireoffs, 0xFFFFFF, &distance, strict, findnearestvert__backbufIndextest);
+ else index = sample_backbuf_rect(mval, 50, em_wireoffs, 0xFFFFFF, &distance, 0, NULL);
+
+ eve = BLI_findlink(&G.editMesh->verts, index-1);
+
+ if(eve && distance < *dist) {
+ *dist = distance;
+ return eve;
+ } else {
+ return NULL;
+ }
+
+ }
+ else {
+ struct { short mval[2], pass, select, strict; int dist, lastIndex, closestIndex; EditVert *closest; } data;
+ static int lastSelectedIndex=0;
+ static EditVert *lastSelected=NULL;
+
+ if (lastSelected && BLI_findlink(&G.editMesh->verts, lastSelectedIndex)!=lastSelected) {
+ lastSelectedIndex = 0;
+ lastSelected = NULL;
+ }
+
+ data.lastIndex = lastSelectedIndex;
+ data.mval[0] = mval[0];
+ data.mval[1] = mval[1];
+ data.select = sel;
+ data.dist = *dist;
+ data.strict = strict;
+ data.closest = NULL;
+ data.closestIndex = 0;
+
+ data.pass = 0;
+ mesh_foreachScreenVert(findnearestvert__doClosest, &data, 1);
+
+ if (data.dist>3) {
+ data.pass = 1;
+ mesh_foreachScreenVert(findnearestvert__doClosest, &data, 1);
+ }
+
+ *dist = data.dist;
+ lastSelected = data.closest;
+ lastSelectedIndex = data.closestIndex;
+
+ return data.closest;
+ }
+}
+
+/* returns labda for closest distance v1 to line-piece v2-v3 */
+static float labda_PdistVL2Dfl( float *v1, float *v2, float *v3)
+{
+ float rc[2], len;
+
+ rc[0]= v3[0]-v2[0];
+ rc[1]= v3[1]-v2[1];
+ len= rc[0]*rc[0]+ rc[1]*rc[1];
+ if(len==0.0f)
+ return 0.0f;
+
+ return ( rc[0]*(v1[0]-v2[0]) + rc[1]*(v1[1]-v2[1]) )/len;
+}
+
+/* note; uses G.vd, so needs active 3d window */
+static void findnearestedge__doClosest(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
+{
+ struct { float mval[2]; int dist; EditEdge *closest; } *data = userData;
+ float v1[2], v2[2];
+ int distance;
+
+ v1[0] = x0;
+ v1[1] = y0;
+ v2[0] = x1;
+ v2[1] = y1;
+
+ distance= PdistVL2Dfl(data->mval, v1, v2);
+
+ if(eed->f & SELECT) distance+=5;
+ if(distance < data->dist) {
+ if(G.vd->flag & V3D_CLIPPING) {
+ float labda= labda_PdistVL2Dfl(data->mval, v1, v2);
+ float vec[3];
+
+ vec[0]= eed->v1->co[0] + labda*(eed->v2->co[0] - eed->v1->co[0]);
+ vec[1]= eed->v1->co[1] + labda*(eed->v2->co[1] - eed->v1->co[1]);
+ vec[2]= eed->v1->co[2] + labda*(eed->v2->co[2] - eed->v1->co[2]);
+ Mat4MulVecfl(G.obedit->obmat, vec);
+
+ if(view3d_test_clipping(G.vd, vec)==0) {
+ data->dist = distance;
+ data->closest = eed;
+ }
+ }
+ else {
+ data->dist = distance;
+ data->closest = eed;
+ }
+ }
+}
+EditEdge *findnearestedge(int *dist)
+{
+ short mval[2];
+
+ getmouseco_areawin(mval);
+
+ if(G.vd->drawtype>OB_WIRE && (G.vd->flag & V3D_ZBUF_SELECT)) {
+ int distance;
+ unsigned int index = sample_backbuf_rect(mval, 50, em_solidoffs, em_wireoffs, &distance,0, NULL);
+ EditEdge *eed = BLI_findlink(&G.editMesh->edges, index-1);
+
+ if (eed && distance<*dist) {
+ *dist = distance;
+ return eed;
+ } else {
+ return NULL;
+ }
+ }
+ else {
+ struct { float mval[2]; int dist; EditEdge *closest; } data;
+
+ data.mval[0] = mval[0];
+ data.mval[1] = mval[1];
+ data.dist = *dist;
+ data.closest = NULL;
+
+ mesh_foreachScreenEdge(findnearestedge__doClosest, &data, 2);
+
+ *dist = data.dist;
+ return data.closest;
+ }
+}
+
+static void findnearestface__getDistance(void *userData, EditFace *efa, int x, int y, int index)
+{
+ struct { short mval[2]; int dist; EditFace *toFace; } *data = userData;
+
+ if (efa==data->toFace) {
+ int temp = abs(data->mval[0]-x) + abs(data->mval[1]-y);
+
+ if (temp<data->dist)
+ data->dist = temp;
+ }
+}
+static void findnearestface__doClosest(void *userData, EditFace *efa, int x, int y, int index)
+{
+ struct { short mval[2], pass; int dist, lastIndex, closestIndex; EditFace *closest; } *data = userData;
+
+ if (data->pass==0) {
+ if (index<=data->lastIndex)
+ return;
+ } else {
+ if (index>data->lastIndex)
+ return;
+ }
+
+ if (data->dist>3) {
+ int temp = abs(data->mval[0]-x) + abs(data->mval[1]-y);
+
+ if (temp<data->dist) {
+ data->dist = temp;
+ data->closest = efa;
+ data->closestIndex = index;
+ }
+ }
+}
+static EditFace *findnearestface(int *dist)
+{
+ short mval[2];
+
+ getmouseco_areawin(mval);
+
+ if(G.vd->drawtype>OB_WIRE && (G.vd->flag & V3D_ZBUF_SELECT)) {
+ unsigned int index = sample_backbuf(mval[0], mval[1]);
+ EditFace *efa = BLI_findlink(&G.editMesh->faces, index-1);
+
+ if (efa) {
+ struct { short mval[2]; int dist; EditFace *toFace; } data;
+
+ data.mval[0] = mval[0];
+ data.mval[1] = mval[1];
+ data.dist = 0x7FFF; /* largest short */
+ data.toFace = efa;
+
+ mesh_foreachScreenFace(findnearestface__getDistance, &data);
+
+ if(G.scene->selectmode == SCE_SELECT_FACE || data.dist<*dist) { /* only faces, no dist check */
+ *dist= data.dist;
+ return efa;
+ }
+ }
+
+ return NULL;
+ }
+ else {
+ struct { short mval[2], pass; int dist, lastIndex, closestIndex; EditFace *closest; } data;
+ static int lastSelectedIndex=0;
+ static EditFace *lastSelected=NULL;
+
+ if (lastSelected && BLI_findlink(&G.editMesh->faces, lastSelectedIndex)!=lastSelected) {
+ lastSelectedIndex = 0;
+ lastSelected = NULL;
+ }
+
+ data.lastIndex = lastSelectedIndex;
+ data.mval[0] = mval[0];
+ data.mval[1] = mval[1];
+ data.dist = *dist;
+ data.closest = NULL;
+ data.closestIndex = 0;
+
+ data.pass = 0;
+ mesh_foreachScreenFace(findnearestface__doClosest, &data);
+
+ if (data.dist>3) {
+ data.pass = 1;
+ mesh_foreachScreenFace(findnearestface__doClosest, &data);
+ }
+
+ *dist = data.dist;
+ lastSelected = data.closest;
+ lastSelectedIndex = data.closestIndex;
+
+ return data.closest;
+ }
+}
+
+/* for interactivity, frontbuffer draw in current window */
+static void draw_dm_mapped_vert__mapFunc(void *theVert, int index, float *co, float *no_f, short *no_s)
+{
+ if (EM_get_vert_for_index(index)==theVert) {
+ bglVertex3fv(co);
+ }
+}
+static void draw_dm_mapped_vert(DerivedMesh *dm, EditVert *eve)
+{
+ EM_init_index_arrays(1, 0, 0);
+ bglBegin(GL_POINTS);
+ dm->foreachMappedVert(dm, draw_dm_mapped_vert__mapFunc, eve);
+ bglEnd();
+ EM_free_index_arrays();
+}
+
+static int draw_dm_mapped_edge__setDrawOptions(void *theEdge, int index)
+{
+ return EM_get_edge_for_index(index)==theEdge;
+}
+static void draw_dm_mapped_edge(DerivedMesh *dm, EditEdge *eed)
+{
+ EM_init_index_arrays(0, 1, 0);
+ dm->drawMappedEdges(dm, draw_dm_mapped_edge__setDrawOptions, eed);
+ EM_free_index_arrays();
+}
+
+static void draw_dm_mapped_face_center__mapFunc(void *theFace, int index, float *cent, float *no)
+{
+ if (EM_get_face_for_index(index)==theFace) {
+ bglVertex3fv(cent);
+ }
+}
+static void draw_dm_mapped_face_center(DerivedMesh *dm, EditFace *efa)
+{
+ EM_init_index_arrays(0, 0, 1);
+ bglBegin(GL_POINTS);
+ dm->foreachMappedFaceCenter(dm, draw_dm_mapped_face_center__mapFunc, efa);
+ bglEnd();
+ EM_free_index_arrays();
+}
+
+static void unified_select_draw(EditVert *eve, EditEdge *eed, EditFace *efa)
+{
+ DerivedMesh *dm = editmesh_get_derived_cage(CD_MASK_BAREMESH);
+
+ glDrawBuffer(GL_FRONT);
+
+ persp(PERSP_VIEW);
+
+ if(G.vd->flag & V3D_CLIPPING)
+ view3d_set_clipping(G.vd);
+
+ glPushMatrix();
+ mymultmatrix(G.obedit->obmat);
+
+ /* face selected */
+ if(efa) {
+ if(G.scene->selectmode & SCE_SELECT_VERTEX) {
+ glPointSize(BIF_GetThemeValuef(TH_VERTEX_SIZE));
+
+ if(efa->f & SELECT) BIF_ThemeColor(TH_VERTEX_SELECT);
+ else BIF_ThemeColor(TH_VERTEX);
+
+ bglBegin(GL_POINTS);
+ bglVertex3fv(efa->v1->co);
+ bglVertex3fv(efa->v2->co);
+ bglVertex3fv(efa->v3->co);
+ if(efa->v4) bglVertex3fv(efa->v4->co);
+ bglEnd();
+ }
+
+ if(G.scene->selectmode & (SCE_SELECT_EDGE|SCE_SELECT_FACE)) {
+ if(efa->fgonf==0) {
+ BIF_ThemeColor((efa->f & SELECT)?TH_EDGE_SELECT:TH_WIRE);
+
+ draw_dm_mapped_edge(dm, efa->e1);
+ draw_dm_mapped_edge(dm, efa->e2);
+ draw_dm_mapped_edge(dm, efa->e3);
+ if (efa->e4) {
+ draw_dm_mapped_edge(dm, efa->e4);
+ }
+ }
+ }
+
+ if(G.scene->selectmode & SCE_SELECT_FACE && (G.vd->drawtype!=OB_TEXTURE)) {
+ if(efa->fgonf==0) {
+ glPointSize(BIF_GetThemeValuef(TH_FACEDOT_SIZE));
+ BIF_ThemeColor((efa->f & SELECT)?TH_FACE_DOT:TH_WIRE);
+
+ draw_dm_mapped_face_center(dm, efa);
+ }
+ }
+ }
+ /* edge selected */
+ if(eed) {
+ if(G.scene->selectmode & (SCE_SELECT_EDGE|SCE_SELECT_FACE)) {
+ BIF_ThemeColor((eed->f & SELECT)?TH_EDGE_SELECT:TH_WIRE);
+
+ draw_dm_mapped_edge(dm, eed);
+ }
+ if(G.scene->selectmode & SCE_SELECT_VERTEX) {
+ glPointSize(BIF_GetThemeValuef(TH_VERTEX_SIZE));
+
+ BIF_ThemeColor((eed->f & SELECT)?TH_VERTEX_SELECT:TH_VERTEX);
+
+ draw_dm_mapped_vert(dm, eed->v1);
+ draw_dm_mapped_vert(dm, eed->v2);
+ }
+ }
+ if(eve) {
+ if(G.scene->selectmode & SCE_SELECT_VERTEX) {
+ glPointSize(BIF_GetThemeValuef(TH_VERTEX_SIZE));
+
+ BIF_ThemeColor((eve->f & SELECT)?TH_VERTEX_SELECT:TH_VERTEX);
+
+ draw_dm_mapped_vert(dm, eve);
+ }
+ }
+
+ glPointSize(1.0);
+ glPopMatrix();
+
+ bglFlush();
+ glDrawBuffer(GL_BACK);
+
+ if(G.vd->flag & V3D_CLIPPING)
+ view3d_clr_clipping();
+
+ /* signal that frontbuf differs from back */
+ curarea->win_swap= WIN_FRONT_OK;
+
+ dm->release(dm);
+}
+
+
+/* best distance based on screen coords.
+ use g.scene->selectmode to define how to use
+ selected vertices and edges get disadvantage
+ return 1 if found one
+*/
+static int unified_findnearest(EditVert **eve, EditEdge **eed, EditFace **efa)
+{
+ int dist= 75;
+
+ *eve= NULL;
+ *eed= NULL;
+ *efa= NULL;
+
+ if(G.scene->selectmode & SCE_SELECT_VERTEX)
+ *eve= findnearestvert(&dist, SELECT, 0);
+ if(G.scene->selectmode & SCE_SELECT_FACE)
+ *efa= findnearestface(&dist);
+
+ dist-= 20; /* since edges select lines, we give dots advantage of 20 pix */
+ if(G.scene->selectmode & SCE_SELECT_EDGE)
+ *eed= findnearestedge(&dist);
+
+ /* return only one of 3 pointers, for frontbuffer redraws */
+ if(*eed) {
+ *efa= NULL; *eve= NULL;
+ }
+ else if(*efa) {
+ *eve= NULL;
+ }
+
+ return (*eve || *eed || *efa);
+}
+
+/* this as a way to compare the ares, perim of 2 faces thay will scale to different sizes
+ *0.5 so smaller faces arnt ALWAYS selected with a thresh of 1.0 */
+#define SCALE_CMP(a,b) ((a+a*thresh >= b) && (a-(a*thresh*0.5) <= b))
+
+/* **************** GROUP SELECTS ************** */
+/* selects new faces/edges/verts based on the
+ existing selection
+
+FACES GROUP
+ mode 1: same material
+ mode 2: same image
+ mode 3: same area
+ mode 4: same perimeter
+ mode 5: same normal
+ mode 6: same co-planer
+*/
+int facegroup_select(short mode)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa, *base_efa=NULL;
+ unsigned int selcount=0; /*count how many new faces we select*/
+
+ /*deselcount, count how many deselected faces are left, so we can bail out early
+ also means that if there are no deselected faces, we can avoid a lot of looping */
+ unsigned int deselcount=0;
+
+ short ok=0;
+ float thresh=G.scene->toolsettings->select_thresh;
+
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if (!efa->h) {
+ if (efa->f & SELECT) {
+ efa->f1=1;
+ ok=1;
+ } else {
+ efa->f1=0;
+ deselcount++; /* a deselected face we may select later */
+ }
+ }
+ }
+
+ if (!ok || !deselcount) /* no data selected OR no more data to select */
+ return 0;
+
+ /*if mode is 3 then record face areas, 4 record perimeter */
+ if (mode==3) {
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ efa->tmp.fp= EM_face_area(efa);
+ }
+ } else if (mode==4) {
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ efa->tmp.fp= EM_face_perimeter(efa);
+ }
+ }
+
+ for(base_efa= em->faces.first; base_efa; base_efa= base_efa->next) {
+ if (base_efa->f1) { /* This was one of the faces originaly selected */
+ if (mode==1) { /* same material */
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if (
+ !(efa->f & SELECT) &&
+ !efa->h &&
+ base_efa->mat_nr == efa->mat_nr
+ ) {
+ EM_select_face(efa, 1);
+ selcount++;
+ deselcount--;
+ if (!deselcount) /*have we selected all posible faces?, if so return*/
+ return selcount;
+ }
+ }
+ } else if (mode==2) { /* same image */
+ MTFace *tf, *base_tf;
+
+ base_tf = (MTFace*)CustomData_em_get(&em->fdata, base_efa->data,
+ CD_MTFACE);
+
+ if(!base_tf)
+ return selcount;
+
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if (!(efa->f & SELECT) && !efa->h) {
+ tf = (MTFace*)CustomData_em_get(&em->fdata, efa->data,
+ CD_MTFACE);
+
+ if(base_tf->tpage == tf->tpage) {
+ EM_select_face(efa, 1);
+ selcount++;
+ deselcount--;
+ if (!deselcount) /*have we selected all posible faces?, if so return*/
+ return selcount;
+ }
+ }
+ }
+ } else if (mode==3 || mode==4) { /* same area OR same perimeter, both use the same temp var */
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if (
+ (!(efa->f & SELECT) && !efa->h) &&
+ SCALE_CMP(base_efa->tmp.fp, efa->tmp.fp)
+ ) {
+ EM_select_face(efa, 1);
+ selcount++;
+ deselcount--;
+ if (!deselcount) /*have we selected all posible faces?, if so return*/
+ return selcount;
+ }
+ }
+ } else if (mode==5) { /* same normal */
+ float angle;
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if (!(efa->f & SELECT) && !efa->h) {
+ angle= VecAngle2(base_efa->n, efa->n);
+ if (angle/180.0<=thresh) {
+ EM_select_face(efa, 1);
+ selcount++;
+ deselcount--;
+ if (!deselcount) /*have we selected all posible faces?, if so return*/
+ return selcount;
+ }
+ }
+ }
+ } else if (mode==6) { /* same planer */
+ float angle, base_dot, dot;
+ base_dot= Inpf(base_efa->cent, base_efa->n);
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if (!(efa->f & SELECT) && !efa->h) {
+ angle= VecAngle2(base_efa->n, efa->n);
+ if (angle/180.0<=thresh) {
+ dot=Inpf(efa->cent, base_efa->n);
+ if (fabs(base_dot-dot) <= thresh) {
+ EM_select_face(efa, 1);
+ selcount++;
+ deselcount--;
+ if (!deselcount) /*have we selected all posible faces?, if so return*/
+ return selcount;
+ }
+ }
+ }
+ }
+ }
+ }
+ } /* end base_efa loop */
+ return selcount;
+}
+
+
+/*
+EDGE GROUP
+ mode 1: same length
+ mode 2: same direction
+ mode 3: same number of face users
+ mode 4: similar face angles.
+ mode 5: similar crease
+ mode 6: similar seam
+ mode 7: similar sharp
+*/
+
+/* this function is only used by edgegroup_select's edge angle */
+
+
+
+int edgegroup_select(short mode)
+{
+ EditMesh *em = G.editMesh;
+ EditEdge *eed, *base_eed=NULL;
+ unsigned int selcount=0; /* count how many new edges we select*/
+
+ /*count how many visible selected edges there are,
+ so we can return when there are none left */
+ unsigned int deselcount=0;
+
+ short ok=0;
+ float thresh=G.scene->toolsettings->select_thresh;
+
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if (!eed->h) {
+ if (eed->f & SELECT) {
+ eed->f1=1;
+ ok=1;
+ } else {
+ eed->f1=0;
+ deselcount++;
+ }
+ /* set all eed->tmp.l to 0 we use it later.
+ for counting face users*/
+ eed->tmp.l=0;
+ eed->f2=0; /* only for mode 4, edge animations */
+ }
+ }
+
+ if (!ok || !deselcount) /* no data selected OR no more data to select*/
+ return 0;
+
+ if (mode==1) { /*store length*/
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if (!eed->h) /* dont calc data for hidden edges*/
+ eed->tmp.fp= VecLenf(eed->v1->co, eed->v2->co);
+ }
+ } else if (mode==3) { /*store face users*/
+ EditFace *efa;
+ /* cound how many faces each edge uses use tmp->l */
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ efa->e1->tmp.l++;
+ efa->e2->tmp.l++;
+ efa->e3->tmp.l++;
+ if (efa->e4) efa->e4->tmp.l++;
+ }
+ } else if (mode==4) { /*store edge angles */
+ EditFace *efa;
+ int j;
+ /* cound how many faces each edge uses use tmp.l */
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ /* here we use the edges temp data to assign a face
+ if a face has alredy been assigned (eed->f2==1)
+ we calculate the angle between the current face and
+ the edges previously found face.
+ store the angle in eed->tmp.fp (loosing the face eed->tmp.f)
+ but tagging eed->f2==2, so we know not to look at it again.
+ This only works for edges that connect to 2 faces. but its good enough
+ */
+
+ /* se we can loop through face edges*/
+ j=0;
+ eed= efa->e1;
+ while (j<4) {
+ if (j==1) eed= efa->e2;
+ else if (j==2) eed= efa->e3;
+ else if (j==3) {
+ eed= efa->e4;
+ if (!eed)
+ break;
+ } /* done looping */
+
+ if (!eed->h) { /* dont calc data for hidden edges*/
+ if (eed->f2==2)
+ break;
+ else if (eed->f2==0) /* first access, assign the face */
+ eed->tmp.f= efa;
+ else if (eed->f2==1) /* second, we assign the angle*/
+ eed->tmp.fp= VecAngle2(eed->tmp.f->n, efa->n)/180;
+ eed->f2++; /* f2==0 no face assigned. f2==1 one face found. f2==2 angle calculated.*/
+ }
+ j++;
+ }
+ }
+ }
+
+ for(base_eed= em->edges.first; base_eed; base_eed= base_eed->next) {
+ if (base_eed->f1) {
+ if (mode==1) { /* same length */
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if (
+ !(eed->f & SELECT) &&
+ !eed->h &&
+ SCALE_CMP(base_eed->tmp.fp, eed->tmp.fp)
+ ) {
+ EM_select_edge(eed, 1);
+ selcount++;
+ deselcount--;
+ if (!deselcount) /*have we selected all posible faces?, if so return*/
+ return selcount;
+ }
+ }
+ } else if (mode==2) { /* same direction */
+ float base_dir[3], dir[3], angle;
+ VecSubf(base_dir, base_eed->v1->co, base_eed->v2->co);
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if (!(eed->f & SELECT) && !eed->h) {
+ VecSubf(dir, eed->v1->co, eed->v2->co);
+ angle= VecAngle2(base_dir, dir);
+
+ if (angle>90) /* use the smallest angle between the edges */
+ angle= fabs(angle-180.0f);
+
+ if (angle/90.0<=thresh) {
+ EM_select_edge(eed, 1);
+ selcount++;
+ deselcount--;
+ if (!deselcount) /*have we selected all posible faces?, if so return*/
+ return selcount;
+ }
+ }
+ }
+ } else if (mode==3) { /* face users */
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if (
+ !(eed->f & SELECT) &&
+ !eed->h &&
+ base_eed->tmp.l==eed->tmp.l
+ ) {
+ EM_select_edge(eed, 1);
+ selcount++;
+ deselcount--;
+ if (!deselcount) /*have we selected all posible faces?, if so return*/
+ return selcount;
+ }
+ }
+ } else if (mode==4 && base_eed->f2==2) { /* edge angles, f2==2 means the edge has an angle. */
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if (
+ !(eed->f & SELECT) &&
+ !eed->h &&
+ eed->f2==2 &&
+ (fabs(base_eed->tmp.fp-eed->tmp.fp)<=thresh)
+ ) {
+ EM_select_edge(eed, 1);
+ selcount++;
+ deselcount--;
+ if (!deselcount) /*have we selected all posible faces?, if so return*/
+ return selcount;
+ }
+ }
+ } else if (mode==5) { /* edge crease */
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if (
+ !(eed->f & SELECT) &&
+ !eed->h &&
+ (fabs(base_eed->crease-eed->crease) <= thresh)
+ ) {
+ EM_select_edge(eed, 1);
+ selcount++;
+ deselcount--;
+ if (!deselcount) /*have we selected all posible faces?, if so return*/
+ return selcount;
+ }
+ }
+ } else if (mode==6) { /* edge seam */
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if (
+ !(eed->f & SELECT) &&
+ !eed->h &&
+ (eed->seam == base_eed->seam)
+ ) {
+ EM_select_edge(eed, 1);
+ selcount++;
+ deselcount--;
+ if (!deselcount) /*have we selected all posible faces?, if so return*/
+ return selcount;
+ }
+ }
+ } else if (mode==7) { /* edge sharp */
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if (
+ !(eed->f & SELECT) &&
+ !eed->h &&
+ (eed->sharp == base_eed->sharp)
+ ) {
+ EM_select_edge(eed, 1);
+ selcount++;
+ deselcount--;
+ if (!deselcount) /*have we selected all posible faces?, if so return*/
+ return selcount;
+ }
+ }
+ }
+ }
+ }
+ return selcount;
+}
+
+
+/*
+VERT GROUP
+ mode 1: same normal
+ mode 2: same number of face users
+ mode 3: same vertex groups
+*/
+int vertgroup_select(short mode)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve, *base_eve=NULL;
+
+ unsigned int selcount=0; /* count how many new edges we select*/
+
+ /*count how many visible selected edges there are,
+ so we can return when there are none left */
+ unsigned int deselcount=0;
+
+ short ok=0;
+ float thresh=G.scene->toolsettings->select_thresh;
+
+ for(eve= em->verts.first; eve; eve= eve->next) {
+ if (!eve->h) {
+ if (eve->f & SELECT) {
+ eve->f1=1;
+ ok=1;
+ } else {
+ eve->f1=0;
+ deselcount++;
+ }
+ /* set all eve->tmp.l to 0 we use them later.*/
+ eve->tmp.l=0;
+ }
+
+ }
+
+ if (!ok || !deselcount) /* no data selected OR no more data to select*/
+ return 0;
+
+
+ if (mode==2) { /* store face users */
+ EditFace *efa;
+
+ /* count how many faces each edge uses use tmp->l */
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ efa->v1->tmp.l++;
+ efa->v2->tmp.l++;
+ efa->v3->tmp.l++;
+ if (efa->v4) efa->v4->tmp.l++;
+ }
+ }
+
+
+ for(base_eve= em->verts.first; base_eve; base_eve= base_eve->next) {
+ if (base_eve->f1) {
+
+ if (mode==1) { /* same normal */
+ float angle;
+ for(eve= em->verts.first; eve; eve= eve->next) {
+ if (!(eve->f & SELECT) && !eve->h) {
+ angle= VecAngle2(base_eve->no, eve->no);
+ if (angle/180.0<=thresh) {
+ eve->f |= SELECT;
+ selcount++;
+ deselcount--;
+ if (!deselcount) /*have we selected all posible faces?, if so return*/
+ return selcount;
+ }
+ }
+ }
+ } else if (mode==2) { /* face users */
+ for(eve= em->verts.first; eve; eve= eve->next) {
+ if (
+ !(eve->f & SELECT) &&
+ !eve->h &&
+ base_eve->tmp.l==eve->tmp.l
+ ) {
+ eve->f |= SELECT;
+ selcount++;
+ deselcount--;
+ if (!deselcount) /*have we selected all posible faces?, if so return*/
+ return selcount;
+ }
+ }
+ } else if (mode==3) { /* vertex groups */
+ MDeformVert *dvert, *base_dvert;
+ short i, j; /* weight index */
+
+ base_dvert= CustomData_em_get(&em->vdata, base_eve->data,
+ CD_MDEFORMVERT);
+
+ if (!base_dvert || base_dvert->totweight == 0)
+ return selcount;
+
+ for(eve= em->verts.first; eve; eve= eve->next) {
+ dvert= CustomData_em_get(&em->vdata, eve->data,
+ CD_MDEFORMVERT);
+
+ if (dvert && !(eve->f & SELECT) && !eve->h && dvert->totweight) {
+ /* do the extra check for selection in the following if, so were not
+ checking verts that may be alredy selected */
+ for (i=0; base_dvert->totweight >i && !(eve->f & SELECT); i++) {
+ for (j=0; dvert->totweight >j; j++) {
+ if (base_dvert->dw[i].def_nr==dvert->dw[j].def_nr) {
+ eve->f |= SELECT;
+ selcount++;
+ deselcount--;
+ if (!deselcount) /*have we selected all posible faces?, if so return*/
+ return selcount;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ } /* end basevert loop */
+ return selcount;
+}
+
+/* EditMode menu triggered from space.c by pressing Shift+G
+handles face/edge vert context and
+facegroup_select/edgegroup_select/vertgroup_select do all the work
+*/
+
+void select_mesh_group_menu()
+{
+ short ret;
+ int selcount, first_item=1, multi=0;
+ char str[512] = "Select Similar "; /* total max length is 404 at the moment */
+
+ if (!ELEM3(G.scene->selectmode, SCE_SELECT_VERTEX, SCE_SELECT_EDGE, SCE_SELECT_FACE)) {
+ multi=1;
+ }
+
+ if(G.scene->selectmode & SCE_SELECT_VERTEX) {
+ if (multi) strcat(str, "%t|Vertices%x-1|");
+ else strcat(str, "Vertices %t|");
+ strcat(str, " Normal %x1| Face Users %x2| Shared Vertex Groups%x3");
+ first_item=0;
+ }
+
+ if(G.scene->selectmode & SCE_SELECT_EDGE) {
+ if (multi) {
+ if (first_item) strcat(str, "%t|Edges%x-1|");
+ else strcat(str, "|%l|Edges%x-1|");
+ } else strcat(str, "Edges %t|");
+
+ strcat(str, " Length %x10| Direction %x20| Face Users%x30| Face Angle%x40| Crease%x50| Seam%x60| Sharp%x70");
+ first_item=0;
+ }
+
+ if(G.scene->selectmode & SCE_SELECT_FACE) {
+ if (multi) {
+ strcat(str, "|%l|Faces%x-1|");
+ } else strcat(str, "Faces %t|");
+ strcat(str, " Material %x100| Image %x200| Area %x300| Perimeter %x400| Normal %x500| Co-Planar %x600");
+
+ }
+
+ ret= pupmenu(str);
+ if (ret<1) return;
+
+ if (ret<10) {
+ selcount= vertgroup_select(ret);
+ if (selcount) { /* update if data was selected */
+ EM_select_flush(); /* so that selected verts, go onto select faces */
+ G.totvertsel += selcount;
+ allqueue(REDRAWVIEW3D, 0);
+ if (EM_texFaceCheck())
+ allqueue(REDRAWIMAGE, 0);
+ BIF_undo_push("Select Similar Vertices");
+ }
+ return;
+ }
+
+ if (ret<100) {
+ selcount= edgegroup_select(ret/10);
+
+ if (selcount) { /* update if data was selected */
+ /*EM_select_flush();*/ /* dont use because it can end up selecting more edges and is not usefull*/
+ G.totedgesel+=selcount;
+ allqueue(REDRAWVIEW3D, 0);
+ if (EM_texFaceCheck())
+ allqueue(REDRAWIMAGE, 0);
+ BIF_undo_push("Select Similar Edges");
+ }
+ return;
+ }
+
+ if (ret<1000) {
+ selcount= facegroup_select(ret/100);
+ if (selcount) { /* update if data was selected */
+ G.totfacesel+=selcount;
+ allqueue(REDRAWVIEW3D, 0);
+ if (EM_texFaceCheck())
+ allqueue(REDRAWIMAGE, 0);
+ BIF_undo_push("Select Similar Faces");
+ }
+ return;
+ }
+}
+
+int mesh_layers_menu_charlen(CustomData *data, int type)
+{
+ int i, len = 0;
+ /* see if there is a duplicate */
+ for(i=0; i<data->totlayer; i++) {
+ if((&data->layers[i])->type == type) {
+ /* we could count the chars here but we'll just assumeme each
+ * is 32 chars with some room for the menu text - 40 should be fine */
+ len+=40;
+ }
+ }
+ return len;
+}
+
+/* this function adds menu text into an existing string.
+ * this string's size should be allocated with mesh_layers_menu_charlen */
+void mesh_layers_menu_concat(CustomData *data, int type, char *str) {
+ int i, count = 0;
+ char *str_pt = str;
+ CustomDataLayer *layer;
+
+ /* see if there is a duplicate */
+ for(i=0; i<data->totlayer; i++) {
+ layer = &data->layers[i];
+ if(layer->type == type) {
+ str_pt += sprintf(str_pt, "%s%%x%d|", layer->name, count);
+ count++;
+ }
+ }
+}
+
+int mesh_layers_menu(CustomData *data, int type) {
+ int ret;
+ char *str_pt, *str;
+
+ str_pt = str = MEM_mallocN(mesh_layers_menu_charlen(data, type) + 18, "layer menu");
+ str[0] = '\0';
+
+ str_pt += sprintf(str_pt, "Layers%%t|");
+
+ mesh_layers_menu_concat(data, type, str_pt);
+
+ ret = pupmenu(str);
+ MEM_freeN(str);
+ return ret;
+}
+
+/* ctrl+c in mesh editmode */
+void mesh_copy_menu(void)
+{
+ EditMesh *em = G.editMesh;
+ EditSelection *ese;
+ short ret, change=0;
+
+ if (!em) return;
+
+ ese = em->selected.last;
+
+ if (!ese) return;
+
+ if(ese->type == EDITVERT) {
+ /*EditVert *ev, *ev_act = (EditVert*)ese->data;
+ ret= pupmenu("");*/
+ } else if(ese->type == EDITEDGE) {
+ EditEdge *eed, *eed_act = (EditEdge*)ese->data;
+ float vec[3], vec_mid[3], eed_len, eed_len_act;
+
+ ret= pupmenu("Copy Active Edge to Selected%t|Crease%x1|Length%x2");
+ if (ret<1) return;
+
+ eed_len_act = VecLenf(eed_act->v1->co, eed_act->v2->co);
+
+ switch (ret) {
+ case 1: /* copy crease */
+ for(eed=em->edges.first; eed; eed=eed->next) {
+ if (eed->f & SELECT && eed != eed_act && eed->crease != eed_act->crease) {
+ eed->crease = eed_act->crease;
+ change = 1;
+ }
+ }
+ break;
+
+ case 2: /* copy length */
+
+ for(eed=em->edges.first; eed; eed=eed->next) {
+ if (eed->f & SELECT && eed != eed_act) {
+
+ eed_len = VecLenf(eed->v1->co, eed->v2->co);
+
+ if (eed_len == eed_len_act) continue;
+ /* if this edge is zero length we cont do anything with it*/
+ if (eed_len == 0.0f) continue;
+ if (eed_len_act == 0.0f) {
+ VecAddf(vec_mid, eed->v1->co, eed->v2->co);
+ VecMulf(vec_mid, 0.5);
+ VECCOPY(eed->v1->co, vec_mid);
+ VECCOPY(eed->v2->co, vec_mid);
+ } else {
+ /* copy the edge length */
+ VecAddf(vec_mid, eed->v1->co, eed->v2->co);
+ VecMulf(vec_mid, 0.5);
+
+ /* SCALE 1 */
+ VecSubf(vec, eed->v1->co, vec_mid);
+ VecMulf(vec, eed_len_act/eed_len);
+ VecAddf(eed->v1->co, vec, vec_mid);
+
+ /* SCALE 2 */
+ VecSubf(vec, eed->v2->co, vec_mid);
+ VecMulf(vec, eed_len_act/eed_len);
+ VecAddf(eed->v2->co, vec, vec_mid);
+ }
+ change = 1;
+ }
+ }
+
+ if (change)
+ recalc_editnormals();
+
+
+ break;
+ }
+
+ } else if(ese->type == EDITFACE) {
+ EditFace *efa, *efa_act = (EditFace*)ese->data;
+ MTFace *tf, *tf_act;
+ MCol *mcol, *mcol_act;
+
+ ret= pupmenu(
+ "Copy Face Selected%t|"
+ "Active Material%x1|Active Image%x2|Active UV Coords%x3|"
+ "Active Mode%x4|Active Transp%x5|Active Vertex Colors%x6|%l|"
+
+ "TexFace UVs from layer%x7|"
+ "TexFace Images from layer%x8|"
+ "TexFace All from layer%x9|"
+ "Vertex Colors from layer%x10");
+
+ if (ret<1) return;
+
+ tf_act = CustomData_em_get(&em->fdata, efa_act->data, CD_MTFACE);
+ mcol_act = CustomData_em_get(&em->fdata, efa_act->data, CD_MCOL);
+
+ switch (ret) {
+ case 1: /* copy material */
+ for(efa=em->faces.first; efa; efa=efa->next) {
+ if (efa->f & SELECT && efa->mat_nr != efa_act->mat_nr) {
+ efa->mat_nr = efa_act->mat_nr;
+ change = 1;
+ }
+ }
+ break;
+ case 2: /* copy image */
+ if (!tf_act) {
+ error("mesh has no uv/image layers");
+ return;
+ }
+ for(efa=em->faces.first; efa; efa=efa->next) {
+ if (efa->f & SELECT && efa != efa_act) {
+ tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ if (tf_act->tpage) {
+ tf->tpage = tf_act->tpage;
+ tf->mode |= TF_TEX;
+ } else {
+ tf->tpage = NULL;
+ tf->mode &= ~TF_TEX;
+ }
+ tf->tile= tf_act->tile;
+ change = 1;
+ }
+ }
+ break;
+
+ case 3: /* copy UV's */
+ if (!tf_act) {
+ error("mesh has no uv/image layers");
+ return;
+ }
+ for(efa=em->faces.first; efa; efa=efa->next) {
+ if (efa->f & SELECT && efa != efa_act) {
+ tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ memcpy(tf->uv, tf_act->uv, sizeof(tf->uv));
+ change = 1;
+ }
+ }
+ break;
+ case 4: /* mode's */
+ if (!tf_act) {
+ error("mesh has no uv/image layers");
+ return;
+ }
+ for(efa=em->faces.first; efa; efa=efa->next) {
+ if (efa->f & SELECT && efa != efa_act) {
+ tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ tf->mode= tf_act->mode;
+ change = 1;
+ }
+ }
+ break;
+ case 5: /* copy transp's */
+ if (!tf_act) {
+ error("mesh has no uv/image layers");
+ return;
+ }
+ for(efa=em->faces.first; efa; efa=efa->next) {
+ if (efa->f & SELECT && efa != efa_act) {
+ tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ tf->transp= tf_act->transp;
+ change = 1;
+ }
+ }
+ break;
+
+ case 6: /* copy vcols's */
+ if (!mcol_act) {
+ error("mesh has no color layers");
+ return;
+ } else {
+ /* guess the 4th color if needs be */
+ float val =- 1;
+
+ if (!efa_act->v4) {
+ /* guess the othe vale, we may need to use it
+ *
+ * Modifying the 4th value of the mcol is ok here since its not seen
+ * on a triangle
+ * */
+ val = ((float)(mcol_act->r + (mcol_act+1)->r + (mcol_act+2)->r)) / 3; CLAMP(val, 0, 255);
+ (mcol_act+3)->r = (char)val;
+
+ val = ((float)(mcol_act->g + (mcol_act+1)->g + (mcol_act+2)->g)) / 3; CLAMP(val, 0, 255);
+ (mcol_act+3)->g = (char)val;
+
+ val = ((float)(mcol_act->b + (mcol_act+1)->b + (mcol_act+2)->b)) / 3; CLAMP(val, 0, 255);
+ (mcol_act+3)->b = (char)val;
+ }
+
+
+ for(efa=em->faces.first; efa; efa=efa->next) {
+ if (efa->f & SELECT && efa != efa_act) {
+ /* TODO - make copy from tri to quad guess the 4th vert */
+ mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
+ memcpy(mcol, mcol_act, sizeof(MCol)*4);
+ change = 1;
+ }
+ }
+ }
+
+ break;
+
+
+ /* copy from layer */
+ case 7:
+ case 8:
+ case 9:
+ if (!tf_act) {
+ error("mesh has no uv/image layers");
+ return;
+ } else if (CustomData_number_of_layers(&em->fdata, CD_MTFACE)<2) {
+ error("mesh does not have multiple uv/image layers");
+ return;
+ } else {
+ int layer_orig_idx, layer_idx;
+
+ layer_idx = mesh_layers_menu(&em->fdata, CD_MTFACE);
+ if (layer_idx<0) return;
+
+ /* warning, have not updated mesh pointers however this is not needed since we swicth back */
+ layer_orig_idx = CustomData_get_active_layer(&em->fdata, CD_MTFACE);
+ if (layer_idx==layer_orig_idx)
+ return;
+
+ /* get the tfaces */
+ CustomData_set_layer_active(&em->fdata, CD_MTFACE, (int)layer_idx);
+ /* store the tfaces in our temp */
+ for(efa=em->faces.first; efa; efa=efa->next) {
+ if (efa->f & SELECT) {
+ efa->tmp.p = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ }
+ }
+ CustomData_set_layer_active(&em->fdata, CD_MTFACE, layer_orig_idx);
+ }
+ break;
+
+ case 10: /* select vcol layers - make sure this stays in sync with above code */
+ if (!mcol_act) {
+ error("mesh has no color layers");
+ return;
+ } else if (CustomData_number_of_layers(&em->fdata, CD_MCOL)<2) {
+ error("mesh does not have multiple color layers");
+ return;
+ } else {
+ int layer_orig_idx, layer_idx;
+
+ layer_idx = mesh_layers_menu(&em->fdata, CD_MCOL);
+ if (layer_idx<0) return;
+
+ /* warning, have not updated mesh pointers however this is not needed since we swicth back */
+ layer_orig_idx = CustomData_get_active_layer(&em->fdata, CD_MCOL);
+ if (layer_idx==layer_orig_idx)
+ return;
+
+ /* get the tfaces */
+ CustomData_set_layer_active(&em->fdata, CD_MCOL, (int)layer_idx);
+ /* store the tfaces in our temp */
+ for(efa=em->faces.first; efa; efa=efa->next) {
+ if (efa->f & SELECT) {
+ efa->tmp.p = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
+ }
+ }
+ CustomData_set_layer_active(&em->fdata, CD_MCOL, layer_orig_idx);
+
+ }
+ break;
+ }
+
+ /* layer copy only - sanity checks done above */
+ switch (ret) {
+ case 7: /* copy UV's only */
+ for(efa=em->faces.first; efa; efa=efa->next) {
+ if (efa->f & SELECT) {
+ tf_act = (MTFace *)efa->tmp.p; /* not active but easier to use this way */
+ tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ memcpy(tf->uv, tf_act->uv, sizeof(tf->uv));
+ change = 1;
+ }
+ }
+ break;
+ case 8: /* copy image settings only */
+ for(efa=em->faces.first; efa; efa=efa->next) {
+ if (efa->f & SELECT) {
+ tf_act = (MTFace *)efa->tmp.p; /* not active but easier to use this way */
+ tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ if (tf_act->tpage) {
+ tf->tpage = tf_act->tpage;
+ tf->mode |= TF_TEX;
+ } else {
+ tf->tpage = NULL;
+ tf->mode &= ~TF_TEX;
+ }
+ tf->tile= tf_act->tile;
+ change = 1;
+ }
+ }
+ break;
+ case 9: /* copy all tface info */
+ for(efa=em->faces.first; efa; efa=efa->next) {
+ if (efa->f & SELECT) {
+ tf_act = (MTFace *)efa->tmp.p; /* not active but easier to use this way */
+ tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ memcpy(tf->uv, ((MTFace *)efa->tmp.p)->uv, sizeof(tf->uv));
+ tf->tpage = tf_act->tpage;
+ tf->mode = tf_act->mode;
+ tf->transp = tf_act->transp;
+ change = 1;
+ }
+ }
+ break;
+ case 10:
+ for(efa=em->faces.first; efa; efa=efa->next) {
+ if (efa->f & SELECT) {
+ mcol_act = (MCol *)efa->tmp.p;
+ mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
+ memcpy(mcol, mcol_act, sizeof(MCol)*4);
+ change = 1;
+ }
+ }
+ break;
+ }
+
+ }
+
+ if (change) {
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+
+ if(ese->type == EDITVERT) BIF_undo_push("Copy Vert Attribute");
+ else if (ese->type == EDITEDGE) BIF_undo_push("Copy Edge Attribute");
+ else if (ese->type == EDITFACE) BIF_undo_push("Copy Face Attribute");
+ }
+
+}
+
+
+/* **************** LOOP SELECTS *************** */
+
+/* selects quads in loop direction of indicated edge */
+/* only flush over edges with valence <= 2 */
+void faceloop_select(EditEdge *startedge, int select)
+{
+ EditMesh *em = G.editMesh;
+ EditEdge *eed;
+ EditFace *efa;
+ int looking= 1;
+
+ /* in eed->f1 we put the valence (amount of faces in edge) */
+ /* in eed->f2 we put tagged flag as correct loop */
+ /* in efa->f1 we put tagged flag as correct to select */
+
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ eed->f1= 0;
+ eed->f2= 0;
+ }
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ efa->f1= 0;
+ if(efa->h==0) {
+ efa->e1->f1++;
+ efa->e2->f1++;
+ efa->e3->f1++;
+ if(efa->e4) efa->e4->f1++;
+ }
+ }
+
+ /* tag startedge OK*/
+ startedge->f2= 1;
+
+ while(looking) {
+ looking= 0;
+
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->e4 && efa->f1==0) { /* not done quad */
+ if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { /* valence ok */
+
+ /* if edge tagged, select opposing edge and mark face ok */
+ if(efa->e1->f2) {
+ efa->e3->f2= 1;
+ efa->f1= 1;
+ looking= 1;
+ }
+ else if(efa->e2->f2) {
+ efa->e4->f2= 1;
+ efa->f1= 1;
+ looking= 1;
+ }
+ if(efa->e3->f2) {
+ efa->e1->f2= 1;
+ efa->f1= 1;
+ looking= 1;
+ }
+ if(efa->e4->f2) {
+ efa->e2->f2= 1;
+ efa->f1= 1;
+ looking= 1;
+ }
+ }
+ }
+ }
+ }
+
+ /* (de)select the faces */
+ if(select!=2) {
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->f1) EM_select_face(efa, select);
+ }
+ }
+}
+
+
+/* helper for edgeloop_select, checks for eed->f2 tag in faces */
+static int edge_not_in_tagged_face(EditEdge *eed)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->h==0) {
+ if(efa->e1==eed || efa->e2==eed || efa->e3==eed || efa->e4==eed) { /* edge is in face */
+ if(efa->e1->f2 || efa->e2->f2 || efa->e3->f2 || (efa->e4 && efa->e4->f2)) { /* face is tagged */
+ return 0;
+ }
+ }
+ }
+ }
+ return 1;
+}
+
+/* selects or deselects edges that:
+- if edges has 2 faces:
+ - has vertices with valence of 4
+ - not shares face with previous edge
+- if edge has 1 face:
+ - has vertices with valence 4
+ - not shares face with previous edge
+ - but also only 1 face
+- if edge no face:
+ - has vertices with valence 2
+*/
+static void edgeloop_select(EditEdge *starteed, int select)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+ EditEdge *eed;
+ EditFace *efa;
+ int looking= 1;
+
+ /* in f1 we put the valence (amount of edges in a vertex, or faces in edge) */
+ /* in eed->f2 and efa->f1 we put tagged flag as correct loop */
+ for(eve= em->verts.first; eve; eve= eve->next) {
+ eve->f1= 0;
+ eve->f2= 0;
+ }
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ eed->f1= 0;
+ eed->f2= 0;
+ if((eed->h & 1)==0) { /* fgon edges add to valence too */
+ eed->v1->f1++; eed->v2->f1++;
+ }
+ }
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ efa->f1= 0;
+ if(efa->h==0) {
+ efa->e1->f1++;
+ efa->e2->f1++;
+ efa->e3->f1++;
+ if(efa->e4) efa->e4->f1++;
+ }
+ }
+
+ /* looped edges & vertices get tagged f2 */
+ starteed->f2= 1;
+ if(starteed->v1->f1<5) starteed->v1->f2= 1;
+ if(starteed->v2->f1<5) starteed->v2->f2= 1;
+ /* sorry, first edge isnt even ok */
+ if(starteed->v1->f2==0 && starteed->v2->f2==0) looking= 0;
+
+ while(looking) {
+ looking= 0;
+
+ /* find correct valence edges which are not tagged yet, but connect to tagged one */
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->h==0 && eed->f2==0) { /* edge not hidden, not tagged */
+ if( (eed->v1->f1<5 && eed->v1->f2) || (eed->v2->f1<5 && eed->v2->f2)) { /* valence of vertex OK, and is tagged */
+ /* new edge is not allowed to be in face with tagged edge */
+ if(edge_not_in_tagged_face(eed)) {
+ if(eed->f1==starteed->f1) { /* same amount of faces */
+ looking= 1;
+ eed->f2= 1;
+ if(eed->v2->f1<5) eed->v2->f2= 1;
+ if(eed->v1->f1<5) eed->v1->f2= 1;
+ }
+ }
+ }
+ }
+ }
+ }
+ /* and we do the select */
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->f2) EM_select_edge(eed, select);
+ }
+}
+
+/*
+ Almostly exactly the same code as faceloop select
+*/
+static void edgering_select(EditEdge *startedge, int select){
+ EditMesh *em = G.editMesh;
+ EditEdge *eed;
+ EditFace *efa;
+ int looking= 1;
+
+ /* in eed->f1 we put the valence (amount of faces in edge) */
+ /* in eed->f2 we put tagged flag as correct loop */
+ /* in efa->f1 we put tagged flag as correct to select */
+
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ eed->f1= 0;
+ eed->f2= 0;
+ }
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ efa->f1= 0;
+ if(efa->h==0) {
+ efa->e1->f1++;
+ efa->e2->f1++;
+ efa->e3->f1++;
+ if(efa->e4) efa->e4->f1++;
+ }
+ }
+
+ /* tag startedge OK */
+ startedge->f2= 1;
+
+ while(looking) {
+ looking= 0;
+
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->e4 && efa->f1==0 && !efa->h) { /* not done quad */
+ if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { /* valence ok */
+
+ /* if edge tagged, select opposing edge and mark face ok */
+ if(efa->e1->f2) {
+ efa->e3->f2= 1;
+ efa->f1= 1;
+ looking= 1;
+ }
+ else if(efa->e2->f2) {
+ efa->e4->f2= 1;
+ efa->f1= 1;
+ looking= 1;
+ }
+ if(efa->e3->f2) {
+ efa->e1->f2= 1;
+ efa->f1= 1;
+ looking= 1;
+ }
+ if(efa->e4->f2) {
+ efa->e2->f2= 1;
+ efa->f1= 1;
+ looking= 1;
+ }
+ }
+ }
+ }
+ }
+
+ /* (de)select the edges */
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->f2) EM_select_edge(eed, select);
+ }
+}
+
+void loop_multiselect(int looptype)
+{
+ EditEdge *eed;
+ EditEdge **edarray;
+ int edindex, edfirstcount;
+
+ /*edarray = MEM_mallocN(sizeof(*edarray)*G.totedgesel,"edge array");*/
+ edarray = MEM_mallocN(sizeof(EditEdge*)*G.totedgesel,"edge array");
+ edindex = 0;
+ edfirstcount = G.totedgesel;
+
+ for(eed=G.editMesh->edges.first; eed; eed=eed->next){
+ if(eed->f&SELECT){
+ edarray[edindex] = eed;
+ edindex += 1;
+ }
+ }
+
+ if(looptype){
+ for(edindex = 0; edindex < edfirstcount; edindex +=1){
+ eed = edarray[edindex];
+ edgering_select(eed,SELECT);
+ }
+ countall();
+ EM_selectmode_flush();
+ BIF_undo_push("Edge Ring Multi-Select");
+ }
+ else{
+ for(edindex = 0; edindex < edfirstcount; edindex +=1){
+ eed = edarray[edindex];
+ edgeloop_select(eed,SELECT);
+ }
+ countall();
+ EM_selectmode_flush();
+ BIF_undo_push("Edge Loop Multi-Select");
+ }
+ MEM_freeN(edarray);
+ allqueue(REDRAWVIEW3D,0);
+ if (EM_texFaceCheck())
+ allqueue(REDRAWIMAGE, 0);
+}
+
+/* ***************** MAIN MOUSE SELECTION ************** */
+
+/* just to have the functions nice together */
+static void mouse_mesh_loop(void)
+{
+ EditEdge *eed;
+ int select= 1;
+ int dist= 50;
+
+ eed= findnearestedge(&dist);
+ if(eed) {
+
+ if((G.qual & LR_SHIFTKEY)==0) EM_clear_flag_all(SELECT);
+
+ if((eed->f & SELECT)==0) select=1;
+ else if(G.qual & LR_SHIFTKEY) select=0;
+
+ if(G.scene->selectmode & SCE_SELECT_FACE) {
+ faceloop_select(eed, select);
+ }
+ else if(G.scene->selectmode & SCE_SELECT_EDGE) {
+ if(G.qual == (LR_CTRLKEY | LR_ALTKEY) || G.qual == (LR_CTRLKEY | LR_ALTKEY |LR_SHIFTKEY))
+ edgering_select(eed, select);
+ else if(G.qual & LR_ALTKEY)
+ edgeloop_select(eed, select);
+ }
+ else if(G.scene->selectmode & SCE_SELECT_VERTEX) {
+ if(G.qual == (LR_CTRLKEY | LR_ALTKEY) || G.qual == (LR_CTRLKEY | LR_ALTKEY |LR_SHIFTKEY))
+ edgering_select(eed, select);
+ else if(G.qual & LR_ALTKEY)
+ edgeloop_select(eed, select);
+ }
+
+ /* frontbuffer draw of last selected only */
+ unified_select_draw(NULL, eed, NULL);
+
+ EM_selectmode_flush();
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ if (EM_texFaceCheck())
+ allqueue(REDRAWIMAGE, 0);
+ }
+}
+
+
+/* here actual select happens */
+void mouse_mesh(void)
+{
+ EditVert *eve;
+ EditEdge *eed;
+ EditFace *efa;
+
+ if(G.qual & LR_ALTKEY) mouse_mesh_loop();
+ else if(unified_findnearest(&eve, &eed, &efa)) {
+
+ if((G.qual & LR_SHIFTKEY)==0) EM_clear_flag_all(SELECT);
+
+ if(efa) {
+ /* set the last selected face */
+ EM_set_actFace(efa);
+
+ if( (efa->f & SELECT)==0 ) {
+ EM_store_selection(efa, EDITFACE);
+ EM_select_face_fgon(efa, 1);
+ }
+ else if(G.qual & LR_SHIFTKEY) {
+ EM_remove_selection(efa, EDITFACE);
+ EM_select_face_fgon(efa, 0);
+ }
+ }
+ else if(eed) {
+ if((eed->f & SELECT)==0) {
+ EM_store_selection(eed, EDITEDGE);
+ EM_select_edge(eed, 1);
+ }
+ else if(G.qual & LR_SHIFTKEY) {
+ EM_remove_selection(eed, EDITEDGE);
+ EM_select_edge(eed, 0);
+ }
+ }
+ else if(eve) {
+ if((eve->f & SELECT)==0) {
+ eve->f |= SELECT;
+ EM_store_selection(eve, EDITVERT);
+ }
+ else if(G.qual & LR_SHIFTKEY){
+ EM_remove_selection(eve, EDITVERT);
+ eve->f &= ~SELECT;
+ }
+ }
+
+ /* frontbuffer draw of last selected only */
+ unified_select_draw(eve, eed, efa);
+
+ EM_selectmode_flush();
+ countall();
+
+ allqueue(REDRAWVIEW3D, 0);
+ if (EM_texFaceCheck()) {
+ allqueue(REDRAWIMAGE, 0);
+ allqueue(REDRAWBUTSEDIT, 0); /* for the texture face panel */
+ }
+ }
+
+ rightmouse_transform();
+}
+
+
+void selectconnected_mesh_all(void)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *v1,*v2;
+ EditEdge *eed;
+ short done=1, toggle=0;
+
+ if(em->edges.first==0) return;
+
+ while(done==1) {
+ done= 0;
+
+ toggle++;
+ if(toggle & 1) eed= em->edges.first;
+ else eed= em->edges.last;
+
+ while(eed) {
+ v1= eed->v1;
+ v2= eed->v2;
+ if(eed->h==0) {
+ if(v1->f & SELECT) {
+ if( (v2->f & SELECT)==0 ) {
+ v2->f |= SELECT;
+ done= 1;
+ }
+ }
+ else if(v2->f & SELECT) {
+ if( (v1->f & SELECT)==0 ) {
+ v1->f |= SELECT;
+ done= 1;
+ }
+ }
+ }
+ if(toggle & 1) eed= eed->next;
+ else eed= eed->prev;
+ }
+ }
+
+ /* now use vertex select flag to select rest */
+ EM_select_flush();
+
+ countall();
+
+ allqueue(REDRAWVIEW3D, 0);
+ if (EM_texFaceCheck())
+ allqueue(REDRAWIMAGE, 0);
+ BIF_undo_push("Select Connected (All)");
+}
+
+void selectconnected_mesh(void)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve, *v1, *v2;
+ EditEdge *eed;
+ EditFace *efa;
+ short done=1, sel, toggle=0;
+
+ if(em->edges.first==0) return;
+
+ if( unified_findnearest(&eve, &eed, &efa)==0 ) {
+ error("Nothing indicated ");
+ return;
+ }
+
+ sel= 1;
+ if(G.qual & LR_SHIFTKEY) sel=0;
+
+ /* clear test flags */
+ for(v1= em->verts.first; v1; v1= v1->next) v1->f1= 0;
+
+ /* start vertex/face/edge */
+ if(eve) eve->f1= 1;
+ else if(eed) eed->v1->f1= eed->v2->f1= 1;
+ else efa->v1->f1= efa->v2->f1= efa->v3->f1= 1;
+
+ /* set flag f1 if affected */
+ while(done==1) {
+ done= 0;
+ toggle++;
+
+ if(toggle & 1) eed= em->edges.first;
+ else eed= em->edges.last;
+
+ while(eed) {
+ v1= eed->v1;
+ v2= eed->v2;
+
+ if(eed->h==0) {
+ if(v1->f1 && v2->f1==0) {
+ v2->f1= 1;
+ done= 1;
+ }
+ else if(v1->f1==0 && v2->f1) {
+ v1->f1= 1;
+ done= 1;
+ }
+ }
+
+ if(toggle & 1) eed= eed->next;
+ else eed= eed->prev;
+ }
+ }
+
+ /* now use vertex f1 flag to select/deselect */
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->v1->f1 && eed->v2->f1)
+ EM_select_edge(eed, sel);
+ }
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->v1->f1 && efa->v2->f1 && efa->v3->f1 && (efa->v4==NULL || efa->v4->f1))
+ EM_select_face(efa, sel);
+ }
+ /* no flush needed, connected geometry is done */
+
+ countall();
+
+ allqueue(REDRAWVIEW3D, 0);
+ if (EM_texFaceCheck())
+ allqueue(REDRAWIMAGE, 0);
+
+ BIF_undo_push("Select Linked");
+
+}
+
+/* for use with selectconnected_delimit_mesh only! */
+#define is_edge_delimit_ok(eed) ((eed->tmp.l == 1) && (eed->seam==0))
+#define is_face_tag(efa) is_edge_delimit_ok(efa->e1) || is_edge_delimit_ok(efa->e2) || is_edge_delimit_ok(efa->e3) || (efa->v4 && is_edge_delimit_ok(efa->e4))
+
+#define face_tag(efa)\
+ if(efa->v4) efa->tmp.l= efa->e1->tmp.l= efa->e2->tmp.l= efa->e3->tmp.l= efa->e4->tmp.l= 1;\
+ else efa->tmp.l= efa->e1->tmp.l= efa->e2->tmp.l= efa->e3->tmp.l= 1;
+
+/* all - 1) use all faces for extending the selection 2) only use the mouse face
+ * sel - 1) select 0) deselect
+ * */
+static void selectconnected_delimit_mesh__internal(short all, short sel)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+ short done=1, change=0;
+ int dist = 75;
+ EditEdge *eed;
+ if(em->faces.first==0) return;
+
+ /* flag all edges as off*/
+ for(eed= em->edges.first; eed; eed= eed->next)
+ eed->tmp.l=0;
+
+ if (all) {
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if (efa->f & SELECT) {
+ face_tag(efa);
+ } else {
+ efa->tmp.l = 0;
+ }
+ }
+ } else {
+ EditFace *efa_mouse = findnearestface(&dist);
+
+ if( !efa_mouse ) {
+ error("Nothing indicated ");
+ return;
+ }
+
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ efa->tmp.l = 0;
+ }
+ efa_mouse->tmp.l = 1;
+ face_tag(efa_mouse);
+ }
+
+ while(done==1) {
+ done= 0;
+ /* simple algo - select all faces that have a selected edge
+ * this intern selects the edge, repeat until nothing is left to do */
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if ((efa->tmp.l == 0) && (!efa->h)) {
+ if (is_face_tag(efa)) {
+ face_tag(efa);
+ done= 1;
+ }
+ }
+ }
+ }
+
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if (efa->tmp.l) {
+ if (sel) {
+ if (!(efa->f & SELECT)) {
+ EM_select_face(efa, 1);
+ change = 1;
+ }
+ } else {
+ if (efa->f & SELECT) {
+ EM_select_face(efa, 0);
+ change = 1;
+ }
+ }
+ }
+ }
+
+ if (!change)
+ return;
+
+ if (!sel) /* make sure de-selecting faces didnt de-select the verts/edges connected to selected faces, this is common with boundries */
+ for(efa= em->faces.first; efa; efa= efa->next)
+ if (efa->f & SELECT)
+ EM_select_face(efa, 1);
+
+ countall();
+
+ allqueue(REDRAWVIEW3D, 0);
+ if (EM_texFaceCheck())
+ allqueue(REDRAWIMAGE, 0);
+
+ BIF_undo_push("Select Linked Delimeted");
+
+}
+
+#undef is_edge_delimit_ok
+#undef is_face_tag
+#undef face_tag
+
+void selectconnected_delimit_mesh(void)
+{
+ selectconnected_delimit_mesh__internal(0, ((G.qual & LR_SHIFTKEY)==0));
+}
+void selectconnected_delimit_mesh_all(void)
+{
+ selectconnected_delimit_mesh__internal(1, 1);
+}
+
+
+/* swap is 0 or 1, if 1 it hides not selected */
+void hide_mesh(int swap)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+ EditEdge *eed;
+ EditFace *efa;
+ int a;
+
+ if(G.obedit==0) return;
+
+ /* hide happens on least dominant select mode, and flushes up, not down! (helps preventing errors in subsurf) */
+ /* - vertex hidden, always means edge is hidden too
+ - edge hidden, always means face is hidden too
+ - face hidden, only set face hide
+ - then only flush back down what's absolute hidden
+ */
+ if(G.scene->selectmode & SCE_SELECT_VERTEX) {
+ for(eve= em->verts.first; eve; eve= eve->next) {
+ if((eve->f & SELECT)!=swap) {
+ eve->f &= ~SELECT;
+ eve->h= 1;
+ }
+ }
+
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->v1->h || eed->v2->h) {
+ eed->h |= 1;
+ eed->f &= ~SELECT;
+ }
+ }
+
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->e1->h & 1 || efa->e2->h & 1 || efa->e3->h & 1 || (efa->e4 && efa->e4->h & 1)) {
+ efa->h= 1;
+ efa->f &= ~SELECT;
+ }
+ }
+ }
+ else if(G.scene->selectmode & SCE_SELECT_EDGE) {
+
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if((eed->f & SELECT)!=swap) {
+ eed->h |= 1;
+ EM_select_edge(eed, 0);
+ }
+ }
+
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->e1->h & 1 || efa->e2->h & 1 || efa->e3->h & 1 || (efa->e4 && efa->e4->h & 1)) {
+ efa->h= 1;
+ efa->f &= ~SELECT;
+ }
+ }
+ }
+ else {
+
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if((efa->f & SELECT)!=swap) {
+ efa->h= 1;
+ EM_select_face(efa, 0);
+ }
+ }
+ }
+
+ /* flush down, only whats 100% hidden */
+ for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
+ for(eed= em->edges.first; eed; eed= eed->next) eed->f1= 0;
+
+ if(G.scene->selectmode & SCE_SELECT_FACE) {
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->h) a= 1; else a= 2;
+ efa->e1->f1 |= a;
+ efa->e2->f1 |= a;
+ efa->e3->f1 |= a;
+ if(efa->e4) efa->e4->f1 |= a;
+ }
+ }
+
+ if(G.scene->selectmode >= SCE_SELECT_EDGE) {
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->f1==1) eed->h |= 1;
+ if(eed->h & 1) a= 1; else a= 2;
+ eed->v1->f1 |= a;
+ eed->v2->f1 |= a;
+ }
+ }
+
+ if(G.scene->selectmode >= SCE_SELECT_VERTEX) {
+ for(eve= em->verts.first; eve; eve= eve->next) {
+ if(eve->f1==1) eve->h= 1;
+ }
+ }
+
+ G.totedgesel= G.totfacesel= G.totvertsel= 0;
+ allqueue(REDRAWVIEW3D, 0);
+ if(EM_texFaceCheck())
+ allqueue(REDRAWIMAGE, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ BIF_undo_push("Hide");
+}
+
+
+void reveal_mesh(void)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+ EditEdge *eed;
+ EditFace *efa;
+
+ if(G.obedit==0) return;
+
+ for(eve= em->verts.first; eve; eve= eve->next) {
+ if(eve->h) {
+ eve->h= 0;
+ eve->f |= SELECT;
+ }
+ }
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->h & 1) {
+ eed->h &= ~1;
+ if(G.scene->selectmode & SCE_SELECT_VERTEX);
+ else EM_select_edge(eed, 1);
+ }
+ }
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->h) {
+ efa->h= 0;
+ if(G.scene->selectmode & (SCE_SELECT_EDGE|SCE_SELECT_VERTEX));
+ else EM_select_face(efa, 1);
+ }
+ }
+
+ EM_fgon_flags(); /* redo flags and indices for fgons */
+ EM_selectmode_flush();
+ countall();
+
+ allqueue(REDRAWVIEW3D, 0);
+ if (EM_texFaceCheck())
+ allqueue(REDRAWIMAGE, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ BIF_undo_push("Reveal");
+}
+
+/* TODO - improve this with sync sel and selection flushing */
+void hide_tface_uv(int swap)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+ MTFace *tface;
+
+ if( is_uv_tface_editing_allowed()==0 ) return;
+
+ /* call the mesh function if we are in mesh sync sel */
+ if (G.sima->flag & SI_SYNC_UVSEL) {
+ hide_mesh(swap);
+ return;
+ }
+
+ if(swap) {
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->f & SELECT) {
+ tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ if((tface->flag & (TF_SEL1|TF_SEL2|TF_SEL3))==0) {
+ if(!efa->v4)
+ EM_select_face(efa, 0);
+ else if(!(tface->flag & TF_SEL4))
+ EM_select_face(efa, 0);
+ }
+ }
+ }
+ } else {
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->f & SELECT) {
+ tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ if(tface->flag & (TF_SEL1|TF_SEL2|TF_SEL3))
+ EM_select_face(efa, 0);
+ else if(efa->v4 && tface->flag & TF_SEL4)
+ EM_select_face(efa, 0);
+ }
+ }
+ }
+
+ /*deselects too many but ok for now*/
+ EM_deselect_flush();
+ EM_validate_selections();
+
+ BIF_undo_push("Hide UV");
+
+ object_tface_flags_changed(OBACT, 0);
+}
+
+void reveal_tface_uv(void)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+ MTFace *tface;
+
+ if( is_uv_tface_editing_allowed()==0 ) return;
+
+ /* call the mesh function if we are in mesh sync sel */
+ if (G.sima->flag & SI_SYNC_UVSEL) {
+ reveal_mesh();
+ return;
+ }
+
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ if (!(efa->h)) {
+ if (!(efa->f & SELECT)) {
+ EM_select_face(efa, 1);
+ tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ tface->flag |= (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
+ }
+ }
+ }
+
+ EM_selectmode_flush();
+
+ BIF_undo_push("Reveal UV");
+
+ object_tface_flags_changed(OBACT, 0);
+}
+
+void select_faces_by_numverts(int numverts)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+
+ /* Selects trias/qiads or isolated verts, and edges that do not have 2 neighboring
+ * faces
+ */
+
+ /* for loose vertices/edges, we first select all, loop below will deselect */
+ if(numverts==5)
+ EM_set_flag_all(SELECT);
+ else if(G.scene->selectmode!=SCE_SELECT_FACE) {
+ error("Only works in face selection mode");
+ return;
+ }
+
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if (efa->e4) {
+ EM_select_face(efa, (numverts==4) );
+ }
+ else {
+ EM_select_face(efa, (numverts==3) );
+ }
+ }
+
+ countall();
+ addqueue(curarea->win, REDRAW, 0);
+ if (EM_texFaceCheck())
+ allqueue(REDRAWIMAGE, 0);
+
+ if (numverts==3)
+ BIF_undo_push("Select Triangles");
+ else if (numverts==4)
+ BIF_undo_push("Select Quads");
+ else
+ BIF_undo_push("Select non-Triangles/Quads");
+}
+
+void select_sharp_edges(void)
+{
+ /* Find edges that have exactly two neighboring faces,
+ * check the angle between those faces, and if angle is
+ * small enough, select the edge
+ */
+ EditMesh *em = G.editMesh;
+ EditEdge *eed;
+ EditFace *efa;
+ EditFace **efa1;
+ EditFace **efa2;
+ long edgecount = 0, i;
+ static short sharpness = 135;
+ float fsharpness;
+
+ if(G.scene->selectmode==SCE_SELECT_FACE) {
+ error("Doesn't work in face selection mode");
+ return;
+ }
+
+ if(button(&sharpness,0, 180,"Max Angle:")==0) return;
+ /* if faces are at angle 'sharpness', then the face normals
+ * are at angle 180.0 - 'sharpness' (convert to radians too)
+ */
+ fsharpness = ((180.0 - sharpness) * M_PI) / 180.0;
+
+ i=0;
+ /* count edges, use tmp.l */
+ eed= em->edges.first;
+ while(eed) {
+ edgecount++;
+ eed->tmp.l = i;
+ eed= eed->next;
+ ++i;
+ }
+
+ /* for each edge, we want a pointer to two adjacent faces */
+ efa1 = MEM_callocN(edgecount*sizeof(EditFace *),
+ "pairs of edit face pointers");
+ efa2 = MEM_callocN(edgecount*sizeof(EditFace *),
+ "pairs of edit face pointers");
+
+#define face_table_edge(eed) { \
+ i = eed->tmp.l; \
+ if (i != -1) { \
+ if (efa1[i]) { \
+ if (efa2[i]) { \
+ /* invalidate, edge has more than two neighbors */ \
+ eed->tmp.l = -1; \
+ } \
+ else { \
+ efa2[i] = efa; \
+ } \
+ } \
+ else { \
+ efa1[i] = efa; \
+ } \
+ } \
+ }
+
+ /* find the adjacent faces of each edge, we want only two */
+ efa= em->faces.first;
+ while(efa) {
+ face_table_edge(efa->e1);
+ face_table_edge(efa->e2);
+ face_table_edge(efa->e3);
+ if (efa->e4) {
+ face_table_edge(efa->e4);
+ }
+ efa= efa->next;
+ }
+
+#undef face_table_edge
+
+ eed = em->edges.first;
+ while(eed) {
+ i = eed->tmp.l;
+ if (i != -1) {
+ /* edge has two or less neighboring faces */
+ if ( (efa1[i]) && (efa2[i]) ) {
+ /* edge has exactly two neighboring faces, check angle */
+ float angle;
+ angle = saacos(efa1[i]->n[0]*efa2[i]->n[0] +
+ efa1[i]->n[1]*efa2[i]->n[1] +
+ efa1[i]->n[2]*efa2[i]->n[2]);
+ if (fabs(angle) >= fsharpness)
+ EM_select_edge(eed, 1);
+ }
+ }
+
+ eed= eed->next;
+ }
+
+ MEM_freeN(efa1);
+ MEM_freeN(efa2);
+
+ countall();
+ addqueue(curarea->win, REDRAW, 0);
+ if (EM_texFaceCheck())
+ allqueue(REDRAWIMAGE, 0);
+
+ BIF_undo_push("Select Sharp Edges");
+}
+
+void select_linked_flat_faces(void)
+{
+ /* Find faces that are linked to selected faces that are
+ * relatively flat (angle between faces is higher than
+ * specified angle)
+ */
+ EditMesh *em = G.editMesh;
+ EditEdge *eed;
+ EditFace *efa;
+ EditFace **efa1;
+ EditFace **efa2;
+ long edgecount = 0, i, faceselcount=0, faceselcountold=0;
+ static short sharpness = 135;
+ float fsharpness;
+
+ if(G.scene->selectmode!=SCE_SELECT_FACE) {
+ error("Only works in face selection mode");
+ return;
+ }
+
+ if(button(&sharpness,0, 180,"Min Angle:")==0) return;
+ /* if faces are at angle 'sharpness', then the face normals
+ * are at angle 180.0 - 'sharpness' (convert to radians too)
+ */
+ fsharpness = ((180.0 - sharpness) * M_PI) / 180.0;
+
+ i=0;
+ /* count edges, use tmp.l */
+ eed= em->edges.first;
+ while(eed) {
+ edgecount++;
+ eed->tmp.l = i;
+ eed= eed->next;
+ ++i;
+ }
+
+ /* for each edge, we want a pointer to two adjacent faces */
+ efa1 = MEM_callocN(edgecount*sizeof(EditFace *),
+ "pairs of edit face pointers");
+ efa2 = MEM_callocN(edgecount*sizeof(EditFace *),
+ "pairs of edit face pointers");
+
+#define face_table_edge(eed) { \
+ i = eed->tmp.l; \
+ if (i != -1) { \
+ if (efa1[i]) { \
+ if (efa2[i]) { \
+ /* invalidate, edge has more than two neighbors */ \
+ eed->tmp.l = -1; \
+ } \
+ else { \
+ efa2[i] = efa; \
+ } \
+ } \
+ else { \
+ efa1[i] = efa; \
+ } \
+ } \
+ }
+
+ /* find the adjacent faces of each edge, we want only two */
+ efa= em->faces.first;
+ while(efa) {
+ face_table_edge(efa->e1);
+ face_table_edge(efa->e2);
+ face_table_edge(efa->e3);
+ if (efa->e4) {
+ face_table_edge(efa->e4);
+ }
+
+ /* while were at it, count the selected faces */
+ if (efa->f & SELECT) ++faceselcount;
+
+ efa= efa->next;
+ }
+
+#undef face_table_edge
+
+ eed= em->edges.first;
+ while(eed) {
+ i = eed->tmp.l;
+ if (i != -1) {
+ /* edge has two or less neighboring faces */
+ if ( (efa1[i]) && (efa2[i]) ) {
+ /* edge has exactly two neighboring faces, check angle */
+ float angle;
+ angle = saacos(efa1[i]->n[0]*efa2[i]->n[0] +
+ efa1[i]->n[1]*efa2[i]->n[1] +
+ efa1[i]->n[2]*efa2[i]->n[2]);
+ /* invalidate: edge too sharp */
+ if (fabs(angle) >= fsharpness)
+ eed->tmp.l = -1;
+ }
+ else {
+ /* invalidate: less than two neighbors */
+ eed->tmp.l = -1;
+ }
+ }
+
+ eed= eed->next;
+ }
+
+#define select_flat_neighbor(eed) { \
+ i = eed->tmp.l; \
+ if (i!=-1) { \
+ if (! (efa1[i]->f & SELECT) ) { \
+ EM_select_face(efa1[i], 1); \
+ ++faceselcount; \
+ } \
+ if (! (efa2[i]->f & SELECT) ) { \
+ EM_select_face(efa2[i], 1); \
+ ++faceselcount; \
+ } \
+ } \
+ }
+
+ while (faceselcount != faceselcountold) {
+ faceselcountold = faceselcount;
+
+ efa= em->faces.first;
+ while(efa) {
+ if (efa->f & SELECT) {
+ select_flat_neighbor(efa->e1);
+ select_flat_neighbor(efa->e2);
+ select_flat_neighbor(efa->e3);
+ if (efa->e4) {
+ select_flat_neighbor(efa->e4);
+ }
+ }
+ efa= efa->next;
+ }
+ }
+
+#undef select_flat_neighbor
+
+ MEM_freeN(efa1);
+ MEM_freeN(efa2);
+
+ countall();
+ addqueue(curarea->win, REDRAW, 0);
+ if (EM_texFaceCheck())
+ allqueue(REDRAWIMAGE, 0);
+ BIF_undo_push("Select Linked Flat Faces");
+}
+
+void select_non_manifold(void)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+ EditEdge *eed;
+ EditFace *efa;
+
+ /* Selects isolated verts, and edges that do not have 2 neighboring
+ * faces
+ */
+
+ if(G.scene->selectmode==SCE_SELECT_FACE) {
+ error("Doesn't work in face selection mode");
+ return;
+ }
+
+ eve= em->verts.first;
+ while(eve) {
+ /* this will count how many edges are connected
+ * to this vert */
+ eve->f1= 0;
+ eve= eve->next;
+ }
+
+ eed= em->edges.first;
+ while(eed) {
+ /* this will count how many faces are connected to
+ * this edge */
+ eed->f1= 0;
+ /* increase edge count for verts */
+ ++eed->v1->f1;
+ ++eed->v2->f1;
+ eed= eed->next;
+ }
+
+ efa= em->faces.first;
+ while(efa) {
+ /* increase face count for edges */
+ ++efa->e1->f1;
+ ++efa->e2->f1;
+ ++efa->e3->f1;
+ if (efa->e4)
+ ++efa->e4->f1;
+ efa= efa->next;
+ }
+
+ /* select verts that are attached to an edge that does not
+ * have 2 neighboring faces */
+ eed= em->edges.first;
+ while(eed) {
+ if (eed->h==0 && eed->f1 != 2) {
+ EM_select_edge(eed, 1);
+ }
+ eed= eed->next;
+ }
+
+ /* select isolated verts */
+ eve= em->verts.first;
+ while(eve) {
+ if (eve->f1 == 0) {
+ if (!eve->h) eve->f |= SELECT;
+ }
+ eve= eve->next;
+ }
+
+ countall();
+ addqueue(curarea->win, REDRAW, 0);
+ if (EM_texFaceCheck())
+ allqueue(REDRAWIMAGE, 0);
+ BIF_undo_push("Select Non Manifold");
+}
+
+void selectswap_mesh(void) /* UI level */
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+ EditEdge *eed;
+ EditFace *efa;
+
+ if(G.scene->selectmode & SCE_SELECT_VERTEX) {
+
+ for(eve= em->verts.first; eve; eve= eve->next) {
+ if(eve->h==0) {
+ if(eve->f & SELECT) eve->f &= ~SELECT;
+ else eve->f|= SELECT;
+ }
+ }
+ }
+ else if(G.scene->selectmode & SCE_SELECT_EDGE) {
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->h==0) {
+ EM_select_edge(eed, !(eed->f & SELECT));
+ }
+ }
+ }
+ else {
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->h==0) {
+ EM_select_face(efa, !(efa->f & SELECT));
+ }
+ }
+ }
+
+ EM_selectmode_flush();
+
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ if (EM_texFaceCheck())
+ allqueue(REDRAWIMAGE, 0);
+
+ BIF_undo_push("Select Swap");
+
+}
+
+void deselectall_mesh(void) /* this toggles!!!, UI level */
+{
+
+ if(G.obedit->lay & G.vd->lay) {
+
+ if( EM_nvertices_selected() ) {
+ EM_clear_flag_all(SELECT);
+ BIF_undo_push("Deselect All");
+ }
+ else {
+ EM_set_flag_all(SELECT);
+ BIF_undo_push("Select All");
+ }
+
+ countall();
+
+ if (EM_texFaceCheck())
+ allqueue(REDRAWIMAGE, 0);
+
+ allqueue(REDRAWVIEW3D, 0);
+ }
+}
+
+void select_more(void)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+ EditEdge *eed;
+ EditFace *efa;
+
+ for(eve= em->verts.first; eve; eve= eve->next) {
+ if(eve->f & SELECT) eve->f1= 1;
+ else eve->f1 = 0;
+ }
+
+ /* set f1 flags in vertices to select 'more' */
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->h==0) {
+ if (eed->v1->f & SELECT)
+ eed->v2->f1 = 1;
+ if (eed->v2->f & SELECT)
+ eed->v1->f1 = 1;
+ }
+ }
+
+ /* new selected edges, but not in facemode */
+ if(G.scene->selectmode <= SCE_SELECT_EDGE) {
+
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->h==0) {
+ if(eed->v1->f1 && eed->v2->f1) EM_select_edge(eed, 1);
+ }
+ }
+ }
+ /* new selected faces */
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->h==0) {
+ if(efa->v1->f1 && efa->v2->f1 && efa->v3->f1 && (efa->v4==NULL || efa->v4->f1))
+ EM_select_face(efa, 1);
+ }
+ }
+
+ countall();
+ addqueue(curarea->win, REDRAW, 0);
+ if (EM_texFaceCheck())
+ allqueue(REDRAWIMAGE, 0);
+ BIF_undo_push("Select More");
+}
+
+void select_less(void)
+{
+ EditMesh *em = G.editMesh;
+ EditEdge *eed;
+ EditFace *efa;
+
+ if(G.scene->selectmode <= SCE_SELECT_EDGE) {
+ /* eed->f1 == 1: edge with a selected and deselected vert */
+
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ eed->f1= 0;
+ if(eed->h==0) {
+
+ if ( !(eed->v1->f & SELECT) && (eed->v2->f & SELECT) )
+ eed->f1= 1;
+ if ( (eed->v1->f & SELECT) && !(eed->v2->f & SELECT) )
+ eed->f1= 1;
+ }
+ }
+
+ /* deselect edges with flag set */
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if (eed->h==0 && eed->f1 == 1) {
+ EM_select_edge(eed, 0);
+ }
+ }
+ EM_deselect_flush();
+
+ }
+ else {
+ /* deselect faces with 1 or more deselect edges */
+ /* eed->f1 == mixed selection edge */
+ for(eed= em->edges.first; eed; eed= eed->next) eed->f1= 0;
+
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->h==0) {
+ if(efa->f & SELECT) {
+ efa->e1->f1 |= 1;
+ efa->e2->f1 |= 1;
+ efa->e3->f1 |= 1;
+ if(efa->e4) efa->e4->f1 |= 1;
+ }
+ else {
+ efa->e1->f1 |= 2;
+ efa->e2->f1 |= 2;
+ efa->e3->f1 |= 2;
+ if(efa->e4) efa->e4->f1 |= 2;
+ }
+ }
+ }
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->h==0) {
+ if(efa->e1->f1==3 || efa->e2->f1==3 || efa->e3->f1==3 || (efa->e4 && efa->e4->f1==3)) {
+ EM_select_face(efa, 0);
+ }
+ }
+ }
+ EM_selectmode_flush();
+
+ }
+
+ countall();
+ BIF_undo_push("Select Less");
+ allqueue(REDRAWVIEW3D, 0);
+ if (EM_texFaceCheck())
+ allqueue(REDRAWIMAGE, 0);
+}
+
+
+void selectrandom_mesh(void) /* randomly selects a user-set % of vertices/edges/faces */
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+ EditEdge *eed;
+ EditFace *efa;
+ static short randfac = 50;
+
+ if(G.obedit==NULL || (G.obedit->lay & G.vd->lay)==0) return;
+
+ /* Get the percentage of vertices to randomly select as 'randfac' */
+ if(button(&randfac,0, 100,"Percentage:")==0) return;
+
+ BLI_srand( BLI_rand() ); /* random seed */
+
+ if(G.scene->selectmode & SCE_SELECT_VERTEX) {
+ for(eve= em->verts.first; eve; eve= eve->next) {
+ if(eve->h==0) {
+ if ( (BLI_frand() * 100) < randfac)
+ eve->f |= SELECT;
+ }
+ }
+ EM_selectmode_flush();
+ countall();
+ BIF_undo_push("Select Random: Vertices");
+ }
+ else if(G.scene->selectmode & SCE_SELECT_EDGE) {
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->h==0) {
+ if ( (BLI_frand() * 100) < randfac)
+ EM_select_edge(eed, 1);
+ }
+ }
+ EM_selectmode_flush();
+ countall();
+ BIF_undo_push("Select Random:Edges");
+ }
+ else {
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->h==0) {
+ if ( (BLI_frand() * 100) < randfac)
+ EM_select_face(efa, 1);
+ }
+ }
+
+ EM_selectmode_flush();
+ countall();
+ BIF_undo_push("Select Random:Faces");
+ }
+ allqueue(REDRAWVIEW3D, 0);
+ if (EM_texFaceCheck())
+ allqueue(REDRAWIMAGE, 0);
+}
+
+void editmesh_select_by_material(int index)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+
+ for (efa=em->faces.first; efa; efa= efa->next) {
+ if (efa->mat_nr==index) {
+ EM_select_face(efa, 1);
+ }
+ }
+
+ EM_selectmode_flush();
+}
+
+void editmesh_deselect_by_material(int index)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+
+ for (efa=em->faces.first; efa; efa= efa->next) {
+ if (efa->mat_nr==index) {
+ EM_select_face(efa, 0);
+ }
+ }
+
+ EM_selectmode_flush();
+}
+
+void EM_selectmode_menu(void)
+{
+ int val;
+
+ if(G.scene->selectmode & SCE_SELECT_VERTEX) pupmenu_set_active(1);
+ else if(G.scene->selectmode & SCE_SELECT_EDGE) pupmenu_set_active(2);
+ else pupmenu_set_active(3);
+
+ val= pupmenu("Select Mode%t|Vertices|Edges|Faces");
+
+
+ if(val>0) {
+ if(val==1){
+ G.scene->selectmode= SCE_SELECT_VERTEX;
+ EM_selectmode_set();
+ countall();
+ BIF_undo_push("Selectmode Set: Vertex");
+ }
+ else if(val==2){
+ if((G.qual==LR_CTRLKEY)) EM_convertsel(G.scene->selectmode, SCE_SELECT_EDGE);
+ G.scene->selectmode= SCE_SELECT_EDGE;
+ EM_selectmode_set();
+ countall();
+ BIF_undo_push("Selectmode Set: Edge");
+ }
+
+ else{
+ if((G.qual==LR_CTRLKEY)) EM_convertsel(G.scene->selectmode, SCE_SELECT_FACE);
+ G.scene->selectmode= SCE_SELECT_FACE;
+ EM_selectmode_set();
+ countall();
+ BIF_undo_push("Selectmode Set: Vertex");
+ }
+
+ allqueue(REDRAWVIEW3D, 1);
+ if (EM_texFaceCheck())
+ allqueue(REDRAWIMAGE, 0);
+ }
+}
+
+/* ************************* SEAMS AND EDGES **************** */
+
+void editmesh_mark_seam(int clear)
+{
+ EditMesh *em= G.editMesh;
+ EditEdge *eed;
+
+ if(multires_level1_test()) return;
+
+ /* auto-enable seams drawing */
+ if(clear==0) {
+ if(!(G.f & G_DRAWSEAMS)) {
+ G.f |= G_DRAWSEAMS;
+ allqueue(REDRAWBUTSEDIT, 0);
+ }
+ }
+
+ if(clear) {
+ eed= em->edges.first;
+ while(eed) {
+ if((eed->h==0) && (eed->f & SELECT)) {
+ eed->seam = 0;
+ }
+ eed= eed->next;
+ }
+ BIF_undo_push("Mark Seam");
+ }
+ else {
+ eed= em->edges.first;
+ while(eed) {
+ if((eed->h==0) && (eed->f & SELECT)) {
+ eed->seam = 1;
+ }
+ eed= eed->next;
+ }
+ BIF_undo_push("Clear Seam");
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+void editmesh_mark_sharp(int set)
+{
+ EditMesh *em= G.editMesh;
+ EditEdge *eed;
+
+#if 0
+ /* auto-enable sharp edge drawing */
+ if(set) {
+ if(!(G.f & G_DRAWSEAMS)) {
+ G.f |= G_DRAWSEAMS;
+ allqueue(REDRAWBUTSEDIT, 0);
+ }
+ }
+#endif
+
+ if(multires_level1_test()) return;
+
+ if(set) {
+ eed= em->edges.first;
+ while(eed) {
+ if(!eed->h && (eed->f & SELECT)) eed->sharp = 1;
+ eed = eed->next;
+ }
+ } else {
+ eed= em->edges.first;
+ while(eed) {
+ if(!eed->h && (eed->f & SELECT)) eed->sharp = 0;
+ eed = eed->next;
+ }
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+void BME_Menu() {
+ short ret;
+ ret= pupmenu("BME modeller%t|Select Edges of Vert%x1");
+
+ switch(ret)
+ {
+ case 1:
+ //BME_edges_of_vert();
+ break;
+ }
+}
+
+
+
+void Vertex_Menu() {
+ short ret;
+ ret= pupmenu("Vertex Specials%t|Remove Doubles%x1|Merge%x2|Smooth %x3|Select Vertex Path%x4|Blend From Shape%x5|Propagate To All Shapes%x6");
+
+ switch(ret)
+ {
+ case 1:
+ notice("Removed %d Vertices", removedoublesflag(1, 0, G.scene->toolsettings->doublimit));
+ BIF_undo_push("Remove Doubles");
+ break;
+ case 2:
+ mergemenu();
+ break;
+ case 3:
+ vertexsmooth();
+ break;
+ case 4:
+ pathselect();
+ BIF_undo_push("Select Vertex Path");
+ break;
+ case 5:
+ shape_copy_select_from();
+ break;
+ case 6:
+ shape_propagate();
+ break;
+ }
+ /* some items crashed because this is in the original W menu but not here. should really manage this better */
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+}
+
+
+void Edge_Menu() {
+ short ret;
+
+ ret= pupmenu("Edge Specials%t|Mark Seam %x1|Clear Seam %x2|Rotate Edge CW%x3|Rotate Edge CCW%x4|Loopcut%x6|Edge Slide%x5|Edge Loop Select%x7|Edge Ring Select%x8|Loop to Region%x9|Region to Loop%x10|Mark Sharp%x11|Clear Sharp%x12");
+
+ switch(ret)
+ {
+ case 1:
+ editmesh_mark_seam(0);
+ break;
+ case 2:
+ editmesh_mark_seam(1);
+ break;
+ case 3:
+ edge_rotate_selected(2);
+ break;
+ case 4:
+ edge_rotate_selected(1);
+ break;
+ case 5:
+ EdgeSlide(0,0.0);
+ BIF_undo_push("EdgeSlide");
+ break;
+ case 6:
+ CutEdgeloop(1);
+ BIF_undo_push("Loopcut New");
+ break;
+ case 7:
+ loop_multiselect(0);
+ break;
+ case 8:
+ loop_multiselect(1);
+ break;
+ case 9:
+ loop_to_region();
+ break;
+ case 10:
+ region_to_loop();
+ break;
+ case 11:
+ editmesh_mark_sharp(1);
+ BIF_undo_push("Mark Sharp");
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ break;
+ case 12:
+ editmesh_mark_sharp(0);
+ BIF_undo_push("Clear Sharp");
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ break;
+ }
+ /* some items crashed because this is in the original W menu but not here. should really manage this better */
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+}
+
+void Face_Menu() {
+ short ret;
+ ret= pupmenu(
+ "Face Specials%t|Flip Normals%x1|Bevel%x2|Shade Smooth%x3|Shade Flat%x4|"
+ "Triangulate (Ctrl T)%x5|Quads from Triangles (Alt J)%x6|Flip Triangle Edges (Ctrl Shift F)%x7|%l|"
+ "Face Mode Set%x8|Face Mode Clear%x9|%l|"
+ "UV Rotate (Shift - CCW)%x10|UV Mirror (Shift - Switch Axis)%x11|"
+ "Color Rotate (Shift - CCW)%x12|Color Mirror (Shift - Switch Axis)%x13");
+
+ switch(ret)
+ {
+ case 1:
+ flip_editnormals();
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ BIF_undo_push("Flip Normals");
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+ case 2:
+ bevel_menu();
+ break;
+ case 3:
+ mesh_set_smooth_faces(1);
+ break;
+ case 4:
+ mesh_set_smooth_faces(0);
+ break;
+
+ case 5: /* Quads to Tris */
+ convert_to_triface(0);
+ allqueue(REDRAWVIEW3D, 0);
+ countall();
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ break;
+ case 6: /* Tris to Quads */
+ join_triangles();
+ break;
+ case 7: /* Flip triangle edges */
+ edge_flip();
+ break;
+ case 8:
+ mesh_set_face_flags(1);
+ break;
+ case 9:
+ mesh_set_face_flags(0);
+ break;
+
+ /* uv texface options */
+ case 10:
+ mesh_rotate_uvs();
+ break;
+ case 11:
+ mesh_mirror_uvs();
+ break;
+ case 12:
+ mesh_rotate_colors();
+ break;
+ case 13:
+ mesh_mirror_colors();
+ break;
+ }
+ /* some items crashed because this is in the original W menu but not here. should really manage this better */
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+}
+
+
+/* **************** NORMALS ************** */
+
+void righthandfaces(int select) /* makes faces righthand turning */
+{
+ EditMesh *em = G.editMesh;
+ EditEdge *eed, *ed1, *ed2, *ed3, *ed4;
+ EditFace *efa, *startvl;
+ float maxx, nor[3], cent[3];
+ int totsel, found, foundone, direct, turn, tria_nr;
+
+ /* based at a select-connected to witness loose objects */
+
+ /* count per edge the amount of faces */
+
+ /* find the ultimate left, front, upper face (not manhattan dist!!) */
+ /* also evaluate both triangle cases in quad, since these can be non-flat */
+
+ /* put normal to the outside, and set the first direction flags in edges */
+
+ /* then check the object, and set directions / direction-flags: but only for edges with 1 or 2 faces */
+ /* this is in fact the 'select connected' */
+
+ /* in case (selected) faces were not done: start over with 'find the ultimate ...' */
+
+ waitcursor(1);
+
+ eed= em->edges.first;
+ while(eed) {
+ eed->f2= 0; /* edge direction */
+ eed->f1= 0; /* counter */
+ eed= eed->next;
+ }
+
+ /* count faces and edges */
+ totsel= 0;
+ efa= em->faces.first;
+ while(efa) {
+ if(select==0 || (efa->f & SELECT) ) {
+ efa->f1= 1;
+ totsel++;
+ efa->e1->f1++;
+ efa->e2->f1++;
+ efa->e3->f1++;
+ if(efa->v4) efa->e4->f1++;
+ }
+ else efa->f1= 0;
+
+ efa= efa->next;
+ }
+
+ while(totsel>0) {
+ /* from the outside to the inside */
+
+ efa= em->faces.first;
+ startvl= NULL;
+ maxx= -1.0e10;
+ tria_nr= 0;
+
+ while(efa) {
+ if(efa->f1) {
+ CalcCent3f(cent, efa->v1->co, efa->v2->co, efa->v3->co);
+ cent[0]= cent[0]*cent[0] + cent[1]*cent[1] + cent[2]*cent[2];
+
+ if(cent[0]>maxx) {
+ maxx= cent[0];
+ startvl= efa;
+ tria_nr= 0;
+ }
+ if(efa->v4) {
+ CalcCent3f(cent, efa->v1->co, efa->v3->co, efa->v4->co);
+ cent[0]= cent[0]*cent[0] + cent[1]*cent[1] + cent[2]*cent[2];
+
+ if(cent[0]>maxx) {
+ maxx= cent[0];
+ startvl= efa;
+ tria_nr= 1;
+ }
+ }
+ }
+ efa= efa->next;
+ }
+
+ if (startvl==NULL)
+ startvl= em->faces.first;
+
+ /* set first face correct: calc normal */
+
+ if(tria_nr==1) {
+ CalcNormFloat(startvl->v1->co, startvl->v3->co, startvl->v4->co, nor);
+ CalcCent3f(cent, startvl->v1->co, startvl->v3->co, startvl->v4->co);
+ } else {
+ CalcNormFloat(startvl->v1->co, startvl->v2->co, startvl->v3->co, nor);
+ CalcCent3f(cent, startvl->v1->co, startvl->v2->co, startvl->v3->co);
+ }
+ /* first normal is oriented this way or the other */
+ if(select) {
+ if(select==2) {
+ if(cent[0]*nor[0]+cent[1]*nor[1]+cent[2]*nor[2] > 0.0) flipface(startvl);
+ }
+ else {
+ if(cent[0]*nor[0]+cent[1]*nor[1]+cent[2]*nor[2] < 0.0) flipface(startvl);
+ }
+ }
+ else if(cent[0]*nor[0]+cent[1]*nor[1]+cent[2]*nor[2] < 0.0) flipface(startvl);
+
+
+ eed= startvl->e1;
+ if(eed->v1==startvl->v1) eed->f2= 1;
+ else eed->f2= 2;
+
+ eed= startvl->e2;
+ if(eed->v1==startvl->v2) eed->f2= 1;
+ else eed->f2= 2;
+
+ eed= startvl->e3;
+ if(eed->v1==startvl->v3) eed->f2= 1;
+ else eed->f2= 2;
+
+ eed= startvl->e4;
+ if(eed) {
+ if(eed->v1==startvl->v4) eed->f2= 1;
+ else eed->f2= 2;
+ }
+
+ startvl->f1= 0;
+ totsel--;
+
+ /* test normals */
+ found= 1;
+ direct= 1;
+ while(found) {
+ found= 0;
+ if(direct) efa= em->faces.first;
+ else efa= em->faces.last;
+ while(efa) {
+ if(efa->f1) {
+ turn= 0;
+ foundone= 0;
+
+ ed1= efa->e1;
+ ed2= efa->e2;
+ ed3= efa->e3;
+ ed4= efa->e4;
+
+ if(ed1->f2) {
+ if(ed1->v1==efa->v1 && ed1->f2==1) turn= 1;
+ if(ed1->v2==efa->v1 && ed1->f2==2) turn= 1;
+ foundone= 1;
+ }
+ else if(ed2->f2) {
+ if(ed2->v1==efa->v2 && ed2->f2==1) turn= 1;
+ if(ed2->v2==efa->v2 && ed2->f2==2) turn= 1;
+ foundone= 1;
+ }
+ else if(ed3->f2) {
+ if(ed3->v1==efa->v3 && ed3->f2==1) turn= 1;
+ if(ed3->v2==efa->v3 && ed3->f2==2) turn= 1;
+ foundone= 1;
+ }
+ else if(ed4 && ed4->f2) {
+ if(ed4->v1==efa->v4 && ed4->f2==1) turn= 1;
+ if(ed4->v2==efa->v4 && ed4->f2==2) turn= 1;
+ foundone= 1;
+ }
+
+ if(foundone) {
+ found= 1;
+ totsel--;
+ efa->f1= 0;
+
+ if(turn) {
+ if(ed1->v1==efa->v1) ed1->f2= 2;
+ else ed1->f2= 1;
+ if(ed2->v1==efa->v2) ed2->f2= 2;
+ else ed2->f2= 1;
+ if(ed3->v1==efa->v3) ed3->f2= 2;
+ else ed3->f2= 1;
+ if(ed4) {
+ if(ed4->v1==efa->v4) ed4->f2= 2;
+ else ed4->f2= 1;
+ }
+
+ flipface(efa);
+
+ }
+ else {
+ if(ed1->v1== efa->v1) ed1->f2= 1;
+ else ed1->f2= 2;
+ if(ed2->v1==efa->v2) ed2->f2= 1;
+ else ed2->f2= 2;
+ if(ed3->v1==efa->v3) ed3->f2= 1;
+ else ed3->f2= 2;
+ if(ed4) {
+ if(ed4->v1==efa->v4) ed4->f2= 1;
+ else ed4->f2= 2;
+ }
+ }
+ }
+ }
+ if(direct) efa= efa->next;
+ else efa= efa->prev;
+ }
+ direct= 1-direct;
+ }
+ }
+
+ recalc_editnormals();
+
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+
+#ifdef WITH_VERSE
+ if(G.editMesh->vnode)
+ sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode);
+#endif
+
+ waitcursor(0);
+}
+
+
+/* ********** ALIGN WITH VIEW **************** */
+
+
+static void editmesh_calc_selvert_center(float cent_r[3])
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+ int nsel= 0;
+
+ cent_r[0]= cent_r[1]= cent_r[0]= 0.0;
+
+ for (eve= em->verts.first; eve; eve= eve->next) {
+ if (eve->f & SELECT) {
+ cent_r[0]+= eve->co[0];
+ cent_r[1]+= eve->co[1];
+ cent_r[2]+= eve->co[2];
+ nsel++;
+ }
+ }
+
+ if (nsel) {
+ cent_r[0]/= nsel;
+ cent_r[1]/= nsel;
+ cent_r[2]/= nsel;
+ }
+}
+
+static int mface_is_selected(MFace *mf)
+{
+ return (!(mf->flag & ME_HIDE) && (mf->flag & ME_FACE_SEL));
+}
+
+ /* XXX, code for both these functions should be abstract,
+ * then unified, then written for other things (like objects,
+ * which would use same as vertices method), then added
+ * to interface! Hoera! - zr
+ */
+void faceselect_align_view_to_selected(View3D *v3d, Mesh *me, int axis)
+{
+ float norm[3];
+ int i, totselected = 0;
+
+ norm[0]= norm[1]= norm[2]= 0.0;
+ for (i=0; i<me->totface; i++) {
+ MFace *mf= ((MFace*) me->mface) + i;
+
+ if (mface_is_selected(mf)) {
+ float *v1, *v2, *v3, fno[3];
+
+ v1= me->mvert[mf->v1].co;
+ v2= me->mvert[mf->v2].co;
+ v3= me->mvert[mf->v3].co;
+ if (mf->v4) {
+ float *v4= me->mvert[mf->v4].co;
+ CalcNormFloat4(v1, v2, v3, v4, fno);
+ } else {
+ CalcNormFloat(v1, v2, v3, fno);
+ }
+
+ norm[0]+= fno[0];
+ norm[1]+= fno[1];
+ norm[2]+= fno[2];
+
+ totselected++;
+ }
+ }
+
+ if (totselected == 0)
+ error("No faces selected.");
+ else
+ view3d_align_axis_to_vector(v3d, axis, norm);
+}
+
+/* helper for below, to survive non-uniform scaled objects */
+static void face_getnormal_obspace(EditFace *efa, float *fno)
+{
+ float vec[4][3];
+
+ VECCOPY(vec[0], efa->v1->co);
+ Mat4Mul3Vecfl(G.obedit->obmat, vec[0]);
+ VECCOPY(vec[1], efa->v2->co);
+ Mat4Mul3Vecfl(G.obedit->obmat, vec[1]);
+ VECCOPY(vec[2], efa->v3->co);
+ Mat4Mul3Vecfl(G.obedit->obmat, vec[2]);
+ if(efa->v4) {
+ VECCOPY(vec[3], efa->v4->co);
+ Mat4Mul3Vecfl(G.obedit->obmat, vec[3]);
+
+ CalcNormFloat4(vec[0], vec[1], vec[2], vec[3], fno);
+ }
+ else CalcNormFloat(vec[0], vec[1], vec[2], fno);
+}
+
+
+void editmesh_align_view_to_selected(View3D *v3d, int axis)
+{
+ EditMesh *em = G.editMesh;
+ int nselverts= EM_nvertices_selected();
+ float norm[3]={0.0, 0.0, 0.0}; /* used for storing the mesh normal */
+
+ if (nselverts==0) {
+ error("No faces or vertices selected.");
+ }
+ else if (EM_nfaces_selected()) {
+ EditFace *efa;
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ if (faceselectedAND(efa, SELECT)) {
+ float fno[3];
+
+ face_getnormal_obspace(efa, fno);
+ norm[0]+= fno[0];
+ norm[1]+= fno[1];
+ norm[2]+= fno[2];
+ }
+ }
+
+ view3d_align_axis_to_vector(v3d, axis, norm);
+ }
+ else if (nselverts>2) {
+ float cent[3];
+ EditVert *eve, *leve= NULL;
+
+ editmesh_calc_selvert_center(cent);
+ for (eve= em->verts.first; eve; eve= eve->next) {
+ if (eve->f & SELECT) {
+ if (leve) {
+ float tno[3];
+ CalcNormFloat(cent, leve->co, eve->co, tno);
+
+ /* XXX, fixme, should be flipped intp a
+ * consistent direction. -zr
+ */
+ norm[0]+= tno[0];
+ norm[1]+= tno[1];
+ norm[2]+= tno[2];
+ }
+ leve= eve;
+ }
+ }
+
+ Mat4Mul3Vecfl(G.obedit->obmat, norm);
+ view3d_align_axis_to_vector(v3d, axis, norm);
+ }
+ else if (nselverts==2) { /* Align view to edge (or 2 verts) */
+ EditVert *eve, *leve= NULL;
+
+ for (eve= em->verts.first; eve; eve= eve->next) {
+ if (eve->f & SELECT) {
+ if (leve) {
+ norm[0]= leve->co[0] - eve->co[0];
+ norm[1]= leve->co[1] - eve->co[1];
+ norm[2]= leve->co[2] - eve->co[2];
+ break; /* we know there are only 2 verts so no need to keep looking */
+ }
+ leve= eve;
+ }
+ }
+ Mat4Mul3Vecfl(G.obedit->obmat, norm);
+ view3d_align_axis_to_vector(v3d, axis, norm);
+ }
+ else if (nselverts==1) { /* Align view to vert normal */
+ EditVert *eve;
+
+ for (eve= em->verts.first; eve; eve= eve->next) {
+ if (eve->f & SELECT) {
+ norm[0]= eve->no[0];
+ norm[1]= eve->no[1];
+ norm[2]= eve->no[2];
+ break; /* we know this is the only selected vert, so no need to keep looking */
+ }
+ }
+ Mat4Mul3Vecfl(G.obedit->obmat, norm);
+ view3d_align_axis_to_vector(v3d, axis, norm);
+ }
+}
+
+/* **************** VERTEX DEFORMS *************** */
+
+void vertexsmooth(void)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+ EditEdge *eed;
+ float *adror, *adr, fac;
+ float fvec[3];
+ int teller=0;
+ ModifierData *md= G.obedit->modifiers.first;
+
+ if(G.obedit==0) return;
+
+ /* count */
+ eve= em->verts.first;
+ while(eve) {
+ if(eve->f & SELECT) teller++;
+ eve= eve->next;
+ }
+ if(teller==0) return;
+
+ adr=adror= (float *)MEM_callocN(3*sizeof(float *)*teller, "vertsmooth");
+ eve= em->verts.first;
+ while(eve) {
+ if(eve->f & SELECT) {
+ eve->tmp.p = (void*)adr;
+ eve->f1= 0;
+ eve->f2= 0;
+ adr+= 3;
+ }
+ eve= eve->next;
+ }
+
+ /* if there is a mirror modifier with clipping, flag the verts that
+ * are within tolerance of the plane(s) of reflection
+ */
+ for (; md; md=md->next) {
+ if (md->type==eModifierType_Mirror) {
+ MirrorModifierData *mmd = (MirrorModifierData*) md;
+
+ if(mmd->flag & MOD_MIR_CLIPPING) {
+ for (eve= em->verts.first; eve; eve= eve->next) {
+ if(eve->f & SELECT) {
+
+ switch(mmd->axis){
+ case 0:
+ if (fabs(eve->co[0]) < mmd->tolerance)
+ eve->f2 |= 1;
+ break;
+ case 1:
+ if (fabs(eve->co[1]) < mmd->tolerance)
+ eve->f2 |= 2;
+ break;
+ case 2:
+ if (fabs(eve->co[2]) < mmd->tolerance)
+ eve->f2 |= 4;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ eed= em->edges.first;
+ while(eed) {
+ if( (eed->v1->f & SELECT) || (eed->v2->f & SELECT) ) {
+ fvec[0]= (eed->v1->co[0]+eed->v2->co[0])/2.0;
+ fvec[1]= (eed->v1->co[1]+eed->v2->co[1])/2.0;
+ fvec[2]= (eed->v1->co[2]+eed->v2->co[2])/2.0;
+
+ if((eed->v1->f & SELECT) && eed->v1->f1<255) {
+ eed->v1->f1++;
+ VecAddf(eed->v1->tmp.p, eed->v1->tmp.p, fvec);
+ }
+ if((eed->v2->f & SELECT) && eed->v2->f1<255) {
+ eed->v2->f1++;
+ VecAddf(eed->v2->tmp.p, eed->v2->tmp.p, fvec);
+ }
+ }
+ eed= eed->next;
+ }
+
+ eve= em->verts.first;
+ while(eve) {
+ if(eve->f & SELECT) {
+ if(eve->f1) {
+ adr = eve->tmp.p;
+ fac= 0.5/(float)eve->f1;
+
+ eve->co[0]= 0.5*eve->co[0]+fac*adr[0];
+ eve->co[1]= 0.5*eve->co[1]+fac*adr[1];
+ eve->co[2]= 0.5*eve->co[2]+fac*adr[2];
+
+ /* clip if needed by mirror modifier */
+ if (eve->f2) {
+ if (eve->f2 & 1) {
+ eve->co[0]= 0.0f;
+ }
+ if (eve->f2 & 2) {
+ eve->co[1]= 0.0f;
+ }
+ if (eve->f2 & 4) {
+ eve->co[2]= 0.0f;
+ }
+ }
+ }
+ eve->tmp.p= NULL;
+ }
+ eve= eve->next;
+ }
+ MEM_freeN(adror);
+
+ recalc_editnormals();
+
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+
+#ifdef WITH_VERSE
+ if(G.editMesh->vnode)
+ sync_all_verseverts_with_editverts(G.editMesh->vnode);
+#endif
+ BIF_undo_push("Vertex Smooth");
+}
+
+void vertexnoise(void)
+{
+ EditMesh *em = G.editMesh;
+ Material *ma;
+ Tex *tex;
+ EditVert *eve;
+ float b2, ofs, vec[3];
+
+ if(G.obedit==0) return;
+
+ ma= give_current_material(G.obedit, G.obedit->actcol);
+ if(ma==0 || ma->mtex[0]==0 || ma->mtex[0]->tex==0) {
+ return;
+ }
+ tex= ma->mtex[0]->tex;
+
+ ofs= tex->turbul/200.0;
+
+ eve= (struct EditVert *)em->verts.first;
+ while(eve) {
+ if(eve->f & SELECT) {
+
+ if(tex->type==TEX_STUCCI) {
+
+ b2= BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1], eve->co[2]);
+ if(tex->stype) ofs*=(b2*b2);
+ vec[0]= 0.2*(b2-BLI_hnoise(tex->noisesize, eve->co[0]+ofs, eve->co[1], eve->co[2]));
+ vec[1]= 0.2*(b2-BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1]+ofs, eve->co[2]));
+ vec[2]= 0.2*(b2-BLI_hnoise(tex->noisesize, eve->co[0], eve->co[1], eve->co[2]+ofs));
+
+ VecAddf(eve->co, eve->co, vec);
+ }
+ else {
+ float tin, dum;
+ externtex(ma->mtex[0], eve->co, &tin, &dum, &dum, &dum, &dum);
+ eve->co[2]+= 0.05*tin;
+ }
+ }
+ eve= eve->next;
+ }
+
+ recalc_editnormals();
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+#ifdef WITH_VERSE
+ if(G.editMesh->vnode)
+ sync_all_verseverts_with_editverts(G.editMesh->vnode);
+#endif
+ BIF_undo_push("Vertex Noise");
+}
+
+void vertices_to_sphere(void)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+ Object *ob= OBACT;
+ float *curs, len, vec[3], cent[3], fac, facm, imat[3][3], bmat[3][3];
+ int tot;
+ short perc=100;
+
+ if(ob==0) return;
+ TEST_EDITMESH
+
+ if(button(&perc, 1, 100, "Percentage:")==0) return;
+
+ fac= perc/100.0;
+ facm= 1.0-fac;
+
+ Mat3CpyMat4(bmat, ob->obmat);
+ Mat3Inv(imat, bmat);
+
+ /* center */
+ curs= give_cursor();
+ cent[0]= curs[0]-ob->obmat[3][0];
+ cent[1]= curs[1]-ob->obmat[3][1];
+ cent[2]= curs[2]-ob->obmat[3][2];
+ Mat3MulVecfl(imat, cent);
+
+ len= 0.0;
+ tot= 0;
+ eve= em->verts.first;
+ while(eve) {
+ if(eve->f & SELECT) {
+ tot++;
+ len+= VecLenf(cent, eve->co);
+ }
+ eve= eve->next;
+ }
+ len/=tot;
+
+ if(len==0.0) len= 10.0;
+
+ eve= em->verts.first;
+ while(eve) {
+ if(eve->f & SELECT) {
+ vec[0]= eve->co[0]-cent[0];
+ vec[1]= eve->co[1]-cent[1];
+ vec[2]= eve->co[2]-cent[2];
+
+ Normalize(vec);
+
+ eve->co[0]= fac*(cent[0]+vec[0]*len) + facm*eve->co[0];
+ eve->co[1]= fac*(cent[1]+vec[1]*len) + facm*eve->co[1];
+ eve->co[2]= fac*(cent[2]+vec[2]*len) + facm*eve->co[2];
+
+ }
+ eve= eve->next;
+ }
+
+ recalc_editnormals();
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+#ifdef WITH_VERSE
+ if(G.editMesh->vnode)
+ sync_all_verseverts_with_editverts(G.editMesh->vnode);
+#endif
+ BIF_undo_push("To Sphere");
+}
+
diff --git a/source/blender/src/editmesh_tools.c b/source/blender/src/editmesh_tools.c
new file mode 100644
index 00000000000..a68fca3b294
--- /dev/null
+++ b/source/blender/src/editmesh_tools.c
@@ -0,0 +1,6800 @@
+/**
+ * $Id:
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Johnny Matthews, Geoffrey Bantle.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/*
+
+editmesh_tool.c: UI called tools for editmesh, geometry changes here, otherwise in mods.c
+
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "BMF_Api.h"
+#include "DNA_mesh_types.h"
+#include "DNA_material_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_key_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_editVert.h"
+#include "BLI_rand.h"
+#include "BLI_ghash.h"
+#include "BLI_linklist.h"
+#include "BLI_heap.h"
+
+#include "BKE_depsgraph.h"
+#include "BKE_customdata.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_utildefines.h"
+
+#ifdef WITH_VERSE
+#include "BKE_verse.h"
+#endif
+
+#include "BIF_cursors.h"
+#include "BIF_editmesh.h"
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+#include "BIF_graphics.h"
+#include "BIF_interface.h"
+#include "BIF_mywindow.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_resources.h"
+#include "BIF_toolbox.h"
+#include "BIF_transform.h"
+
+#ifdef WITH_VERSE
+#include "BIF_verse.h"
+#endif
+
+#include "BDR_drawobject.h"
+#include "BDR_editobject.h"
+
+#include "BSE_view.h"
+#include "BSE_edit.h"
+
+#include "blendef.h"
+#include "multires.h"
+#include "mydevice.h"
+
+#include "editmesh.h"
+
+#include "MTC_vectorops.h"
+
+#include "PIL_time.h"
+
+/* local prototypes ---------------*/
+void bevel_menu(void);
+static void free_tagged_edges_faces(EditEdge *eed, EditFace *efa);
+
+/********* qsort routines *********/
+
+
+typedef struct xvertsort {
+ float x;
+ EditVert *v1;
+} xvertsort;
+
+static int vergxco(const void *v1, const void *v2)
+{
+ const xvertsort *x1=v1, *x2=v2;
+
+ if( x1->x > x2->x ) return 1;
+ else if( x1->x < x2->x) return -1;
+ return 0;
+}
+
+struct facesort {
+ unsigned long x;
+ struct EditFace *efa;
+};
+
+
+static int vergface(const void *v1, const void *v2)
+{
+ const struct facesort *x1=v1, *x2=v2;
+
+ if( x1->x > x2->x ) return 1;
+ else if( x1->x < x2->x) return -1;
+ return 0;
+}
+
+
+/* *********************************** */
+
+void convert_to_triface(int direction)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa, *efan, *next;
+ float fac;
+
+ if(multires_test()) return;
+
+ efa= em->faces.last;
+ while(efa) {
+ next= efa->prev;
+ if(efa->v4) {
+ if(efa->f & SELECT) {
+ /* choose shortest diagonal for split */
+ fac= VecLenf(efa->v1->co, efa->v3->co) - VecLenf(efa->v2->co, efa->v4->co);
+ /* this makes sure exact squares get split different in both cases */
+ if( (direction==0 && fac<FLT_EPSILON) || (direction && fac>0.0f) ) {
+ efan= EM_face_from_faces(efa, NULL, 0, 1, 2, -1);
+ if(efa->f & SELECT) EM_select_face(efan, 1);
+ efan= EM_face_from_faces(efa, NULL, 0, 2, 3, -1);
+ if(efa->f & SELECT) EM_select_face(efan, 1);
+ }
+ else {
+ efan= EM_face_from_faces(efa, NULL, 0, 1, 3, -1);
+ if(efa->f & SELECT) EM_select_face(efan, 1);
+ efan= EM_face_from_faces(efa, NULL, 1, 2, 3, -1);
+ if(efa->f & SELECT) EM_select_face(efan, 1);
+ }
+
+ BLI_remlink(&em->faces, efa);
+ free_editface(efa);
+ }
+ }
+ efa= next;
+ }
+
+ EM_fgon_flags(); // redo flags and indices for fgons
+
+#ifdef WITH_VERSE
+ if(G.editMesh->vnode)
+ sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode);
+#endif
+ BIF_undo_push("Convert Quads to Triangles");
+
+}
+
+int removedoublesflag(short flag, short automerge, float limit) /* return amount */
+{
+ /*
+ flag - Test with vert->flags
+ automerge - Alternative operation, merge unselected into selected.
+ Used for "Auto Weld" mode. warning.
+ limit - Quick manhattan distance between verts.
+ */
+
+ EditMesh *em = G.editMesh;
+ /* all verts with (flag & 'flag') are being evaluated */
+ EditVert *eve, *v1, *nextve;
+ EditEdge *eed, *e1, *nexted;
+ EditFace *efa, *nextvl;
+ xvertsort *sortblock, *sb, *sb1;
+ struct facesort *vlsortblock, *vsb, *vsb1;
+ int a, b, test, amount;
+
+ if(multires_test()) return 0;
+
+
+ /* flag 128 is cleared, count */
+
+ /* Normal non weld operation */
+ eve= em->verts.first;
+ amount= 0;
+ while(eve) {
+ eve->f &= ~128;
+ if(eve->h==0 && (automerge || (eve->f & flag))) amount++;
+ eve= eve->next;
+ }
+ if(amount==0) return 0;
+
+ /* allocate memory and qsort */
+ sb= sortblock= MEM_mallocN(sizeof(xvertsort)*amount,"sortremovedoub");
+ eve= em->verts.first;
+ while(eve) {
+ if(eve->h==0 && (automerge || (eve->f & flag))) {
+ sb->x= eve->co[0]+eve->co[1]+eve->co[2];
+ sb->v1= eve;
+ sb++;
+ }
+ eve= eve->next;
+ }
+ qsort(sortblock, amount, sizeof(xvertsort), vergxco);
+
+
+ /* test for doubles */
+ sb= sortblock;
+ if (automerge) {
+ for(a=0; a<amount; a++, sb++) {
+ eve= sb->v1;
+ if( (eve->f & 128)==0 ) {
+ sb1= sb+1;
+ for(b=a+1; b<amount && (eve->f & 128)==0; b++, sb1++) {
+ if(sb1->x - sb->x > limit) break;
+
+ /* when automarge, only allow unselected->selected */
+ v1= sb1->v1;
+ if( (v1->f & 128)==0 ) {
+ if ((eve->f & flag)==0 && (v1->f & flag)==1) {
+ if( (float)fabs(v1->co[0]-eve->co[0])<=limit &&
+ (float)fabs(v1->co[1]-eve->co[1])<=limit &&
+ (float)fabs(v1->co[2]-eve->co[2])<=limit)
+ { /* unique bit */
+ eve->f|= 128;
+ eve->tmp.v = v1;
+ }
+ } else if( (eve->f & flag)==1 && (v1->f & flag)==0 ) {
+ if( (float)fabs(v1->co[0]-eve->co[0])<=limit &&
+ (float)fabs(v1->co[1]-eve->co[1])<=limit &&
+ (float)fabs(v1->co[2]-eve->co[2])<=limit)
+ { /* unique bit */
+ v1->f|= 128;
+ v1->tmp.v = eve;
+ }
+ }
+ }
+ }
+ }
+ }
+ } else {
+ for(a=0; a<amount; a++, sb++) {
+ eve= sb->v1;
+ if( (eve->f & 128)==0 ) {
+ sb1= sb+1;
+ for(b=a+1; b<amount; b++, sb1++) {
+ /* first test: simpel dist */
+ if(sb1->x - sb->x > limit) break;
+ v1= sb1->v1;
+
+ /* second test: is vertex allowed */
+ if( (v1->f & 128)==0 ) {
+ if( (float)fabs(v1->co[0]-eve->co[0])<=limit &&
+ (float)fabs(v1->co[1]-eve->co[1])<=limit &&
+ (float)fabs(v1->co[2]-eve->co[2])<=limit)
+ {
+ v1->f|= 128;
+ v1->tmp.v = eve;
+ }
+ }
+ }
+ }
+ }
+ }
+ MEM_freeN(sortblock);
+
+ if (!automerge)
+ for(eve = em->verts.first; eve; eve=eve->next)
+ if((eve->f & flag) && (eve->f & 128))
+ EM_data_interp_from_verts(eve, eve->tmp.v, eve->tmp.v, 0.5f);
+
+ /* test edges and insert again */
+ eed= em->edges.first;
+ while(eed) {
+ eed->f2= 0;
+ eed= eed->next;
+ }
+ eed= em->edges.last;
+ while(eed) {
+ nexted= eed->prev;
+
+ if(eed->f2==0) {
+ if( (eed->v1->f & 128) || (eed->v2->f & 128) ) {
+ remedge(eed);
+
+ if(eed->v1->f & 128) eed->v1 = eed->v1->tmp.v;
+ if(eed->v2->f & 128) eed->v2 = eed->v2->tmp.v;
+ e1= addedgelist(eed->v1, eed->v2, eed);
+
+ if(e1) e1->f2= 1;
+ if(e1!=eed) free_editedge(eed);
+ }
+ }
+ eed= nexted;
+ }
+
+ /* first count amount of test faces */
+ efa= (struct EditFace *)em->faces.first;
+ amount= 0;
+ while(efa) {
+ efa->f1= 0;
+ if(efa->v1->f & 128) efa->f1= 1;
+ else if(efa->v2->f & 128) efa->f1= 1;
+ else if(efa->v3->f & 128) efa->f1= 1;
+ else if(efa->v4 && (efa->v4->f & 128)) efa->f1= 1;
+
+ if(efa->f1==1) amount++;
+ efa= efa->next;
+ }
+
+ /* test faces for double vertices, and if needed remove them */
+ efa= (struct EditFace *)em->faces.first;
+ while(efa) {
+ nextvl= efa->next;
+ if(efa->f1==1) {
+
+ if(efa->v1->f & 128) efa->v1= efa->v1->tmp.v;
+ if(efa->v2->f & 128) efa->v2= efa->v2->tmp.v;
+ if(efa->v3->f & 128) efa->v3= efa->v3->tmp.v;
+ if(efa->v4 && (efa->v4->f & 128)) efa->v4= efa->v4->tmp.v;
+
+ test= 0;
+ if(efa->v1==efa->v2) test+=1;
+ if(efa->v2==efa->v3) test+=2;
+ if(efa->v3==efa->v1) test+=4;
+ if(efa->v4==efa->v1) test+=8;
+ if(efa->v3==efa->v4) test+=16;
+ if(efa->v2==efa->v4) test+=32;
+
+ if(test) {
+ if(efa->v4) {
+ if(test==1 || test==2) {
+ efa->v2= efa->v3;
+ efa->v3= efa->v4;
+ efa->v4= 0;
+
+ EM_data_interp_from_faces(efa, NULL, efa, 0, 2, 3, 3);
+
+ test= 0;
+ }
+ else if(test==8 || test==16) {
+ efa->v4= 0;
+ test= 0;
+ }
+ else {
+ BLI_remlink(&em->faces, efa);
+ free_editface(efa);
+ amount--;
+ }
+ }
+ else {
+ BLI_remlink(&em->faces, efa);
+ free_editface(efa);
+ amount--;
+ }
+ }
+
+ if(test==0) {
+ /* set edge pointers */
+ efa->e1= findedgelist(efa->v1, efa->v2);
+ efa->e2= findedgelist(efa->v2, efa->v3);
+ if(efa->v4==0) {
+ efa->e3= findedgelist(efa->v3, efa->v1);
+ efa->e4= 0;
+ }
+ else {
+ efa->e3= findedgelist(efa->v3, efa->v4);
+ efa->e4= findedgelist(efa->v4, efa->v1);
+ }
+ }
+ }
+ efa= nextvl;
+ }
+
+ /* double faces: sort block */
+ /* count again, now all selected faces */
+ amount= 0;
+ efa= em->faces.first;
+ while(efa) {
+ efa->f1= 0;
+ if(faceselectedOR(efa, 1)) {
+ efa->f1= 1;
+ amount++;
+ }
+ efa= efa->next;
+ }
+
+ if(amount) {
+ /* double faces: sort block */
+ vsb= vlsortblock= MEM_mallocN(sizeof(struct facesort)*amount, "sortremovedoub");
+ efa= em->faces.first;
+ while(efa) {
+ if(efa->f1 & 1) {
+ if(efa->v4) vsb->x= (unsigned long) MIN4( (unsigned long)efa->v1, (unsigned long)efa->v2, (unsigned long)efa->v3, (unsigned long)efa->v4);
+ else vsb->x= (unsigned long) MIN3( (unsigned long)efa->v1, (unsigned long)efa->v2, (unsigned long)efa->v3);
+
+ vsb->efa= efa;
+ vsb++;
+ }
+ efa= efa->next;
+ }
+
+ qsort(vlsortblock, amount, sizeof(struct facesort), vergface);
+
+ vsb= vlsortblock;
+ for(a=0; a<amount; a++) {
+ efa= vsb->efa;
+ if( (efa->f1 & 128)==0 ) {
+ vsb1= vsb+1;
+
+ for(b=a+1; b<amount; b++) {
+
+ /* first test: same pointer? */
+ if(vsb->x != vsb1->x) break;
+
+ /* second test: is test permitted? */
+ efa= vsb1->efa;
+ if( (efa->f1 & 128)==0 ) {
+ if( compareface(efa, vsb->efa)) efa->f1 |= 128;
+
+ }
+ vsb1++;
+ }
+ }
+ vsb++;
+ }
+
+ MEM_freeN(vlsortblock);
+
+ /* remove double faces */
+ efa= (struct EditFace *)em->faces.first;
+ while(efa) {
+ nextvl= efa->next;
+ if(efa->f1 & 128) {
+ BLI_remlink(&em->faces, efa);
+ free_editface(efa);
+ }
+ efa= nextvl;
+ }
+ }
+
+ /* remove double vertices */
+ a= 0;
+ eve= (struct EditVert *)em->verts.first;
+ while(eve) {
+ nextve= eve->next;
+ if(automerge || eve->f & flag) {
+ if(eve->f & 128) {
+ a++;
+ BLI_remlink(&em->verts, eve);
+ free_editvert(eve);
+ }
+ }
+ eve= nextve;
+ }
+
+#ifdef WITH_VERSE
+ if((a>0) && (G.editMesh->vnode)) {
+ sync_all_verseverts_with_editverts((VNode*)G.editMesh->vnode);
+ sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode);
+ }
+#endif
+
+ return a; /* amount */
+}
+
+/* called from buttons */
+static void xsortvert_flag__doSetX(void *userData, EditVert *eve, int x, int y, int index)
+{
+ xvertsort *sortblock = userData;
+
+ sortblock[index].x = x;
+}
+void xsortvert_flag(int flag)
+{
+ EditMesh *em = G.editMesh;
+ /* all verts with (flag & 'flag') are sorted */
+ EditVert *eve;
+ xvertsort *sortblock;
+ ListBase tbase;
+ int i, amount = BLI_countlist(&em->verts);
+
+ if(multires_test()) return;
+
+ sortblock = MEM_callocN(sizeof(xvertsort)*amount,"xsort");
+ for (i=0,eve=em->verts.first; eve; i++,eve=eve->next)
+ if(eve->f & flag)
+ sortblock[i].v1 = eve;
+ mesh_foreachScreenVert(xsortvert_flag__doSetX, sortblock, 0);
+ qsort(sortblock, amount, sizeof(xvertsort), vergxco);
+
+ /* make temporal listbase */
+ tbase.first= tbase.last= 0;
+ for (i=0; i<amount; i++) {
+ eve = sortblock[i].v1;
+
+ if (eve) {
+ BLI_remlink(&em->verts, eve);
+ BLI_addtail(&tbase, eve);
+ }
+ }
+
+ addlisttolist(&em->verts, &tbase);
+
+ MEM_freeN(sortblock);
+
+#ifdef WITH_VERSE
+ if(G.editMesh->vnode)
+ sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode);
+#endif
+
+ BIF_undo_push("Xsort");
+
+}
+
+/* called from buttons */
+void hashvert_flag(int flag)
+{
+ /* switch vertex order using hash table */
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+ struct xvertsort *sortblock, *sb, onth, *newsort;
+ ListBase tbase;
+ int amount, a, b;
+
+ if(multires_test()) return;
+
+ /* count */
+ eve= em->verts.first;
+ amount= 0;
+ while(eve) {
+ if(eve->f & flag) amount++;
+ eve= eve->next;
+ }
+ if(amount==0) return;
+
+ /* allocate memory */
+ sb= sortblock= (struct xvertsort *)MEM_mallocN(sizeof(struct xvertsort)*amount,"sortremovedoub");
+ eve= em->verts.first;
+ while(eve) {
+ if(eve->f & flag) {
+ sb->v1= eve;
+ sb++;
+ }
+ eve= eve->next;
+ }
+
+ BLI_srand(1);
+
+ sb= sortblock;
+ for(a=0; a<amount; a++, sb++) {
+ b= (int)(amount*BLI_drand());
+ if(b>=0 && b<amount) {
+ newsort= sortblock+b;
+ onth= *sb;
+ *sb= *newsort;
+ *newsort= onth;
+ }
+ }
+
+ /* make temporal listbase */
+ tbase.first= tbase.last= 0;
+ sb= sortblock;
+ while(amount--) {
+ eve= sb->v1;
+ BLI_remlink(&em->verts, eve);
+ BLI_addtail(&tbase, eve);
+ sb++;
+ }
+
+ addlisttolist(&em->verts, &tbase);
+
+ MEM_freeN(sortblock);
+#ifdef WITH_VERSE
+ if(G.editMesh->vnode)
+ sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode);
+#endif
+ BIF_undo_push("Hash");
+
+}
+
+/* generic extern called extruder */
+void extrude_mesh(void)
+{
+ float nor[3]= {0.0, 0.0, 0.0};
+ short nr, transmode= 0;
+
+ TEST_EDITMESH
+ if(multires_test()) return;
+
+ if(G.scene->selectmode & SCE_SELECT_VERTEX) {
+ if(G.totvertsel==0) nr= 0;
+ else if(G.totvertsel==1) nr= 4;
+ else if(G.totedgesel==0) nr= 4;
+ else if(G.totfacesel==0)
+ nr= pupmenu("Extrude %t|Only Edges%x3|Only Vertices%x4");
+ else if(G.totfacesel==1)
+ nr= pupmenu("Extrude %t|Region %x1|Only Edges%x3|Only Vertices%x4");
+ else
+ nr= pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3|Only Vertices%x4");
+ }
+ else if(G.scene->selectmode & SCE_SELECT_EDGE) {
+ if (G.totedgesel==0) nr = 0;
+ else if (G.totedgesel==1) nr = 3;
+ else if(G.totfacesel==0) nr = 3;
+ else if(G.totfacesel==1)
+ nr= pupmenu("Extrude %t|Region %x1|Only Edges%x3");
+ else
+ nr= pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3");
+ }
+ else {
+ if (G.totfacesel == 0) nr = 0;
+ else if (G.totfacesel == 1) nr = 1;
+ else
+ nr= pupmenu("Extrude %t|Region %x1||Individual Faces %x2");
+ }
+
+ if(nr<1) return;
+
+ if(nr==1) transmode= extrudeflag(SELECT, nor);
+ else if(nr==4) transmode= extrudeflag_verts_indiv(SELECT, nor);
+ else if(nr==3) transmode= extrudeflag_edges_indiv(SELECT, nor);
+ else transmode= extrudeflag_face_indiv(SELECT, nor);
+
+ if(transmode==0) {
+ error("No valid selection");
+ }
+ else {
+ EM_fgon_flags();
+ countall();
+
+ /* We need to force immediate calculation here because
+ * transform may use derived objects (which are now stale).
+ *
+ * This shouldn't be necessary, derived queries should be
+ * automatically building this data if invalid. Or something.
+ */
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ object_handle_update(G.obedit);
+
+ /* individual faces? */
+ BIF_TransformSetUndo("Extrude");
+ if(nr==2) {
+ initTransform(TFM_SHRINKFATTEN, CTX_NO_PET);
+ Transform();
+ }
+ else {
+ initTransform(TFM_TRANSLATION, CTX_NO_PET);
+ if(transmode=='n') {
+ Mat4MulVecfl(G.obedit->obmat, nor);
+ VecSubf(nor, nor, G.obedit->obmat[3]);
+ BIF_setSingleAxisConstraint(nor, NULL);
+ }
+ Transform();
+ }
+ }
+
+}
+
+void split_mesh(void)
+{
+
+ TEST_EDITMESH
+ if(multires_test()) return;
+
+ if(okee(" Split ")==0) return;
+
+ waitcursor(1);
+
+ /* make duplicate first */
+ adduplicateflag(SELECT);
+ /* old faces have flag 128 set, delete them */
+ delfaceflag(128);
+ recalc_editnormals();
+
+ waitcursor(0);
+
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+
+#ifdef WITH_VERSE
+ if(G.editMesh->vnode)
+ sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode);
+#endif
+
+ BIF_undo_push("Split");
+
+}
+
+void extrude_repeat_mesh(int steps, float offs)
+{
+ float dvec[3], tmat[3][3], bmat[3][3], nor[3]= {0.0, 0.0, 0.0};
+ short a;
+
+ TEST_EDITMESH
+ if(multires_test()) return;
+
+ /* dvec */
+ dvec[0]= G.vd->persinv[2][0];
+ dvec[1]= G.vd->persinv[2][1];
+ dvec[2]= G.vd->persinv[2][2];
+ Normalize(dvec);
+ dvec[0]*= offs;
+ dvec[1]*= offs;
+ dvec[2]*= offs;
+
+ /* base correction */
+ Mat3CpyMat4(bmat, G.obedit->obmat);
+ Mat3Inv(tmat, bmat);
+ Mat3MulVecfl(tmat, dvec);
+
+ for(a=0; a<steps; a++) {
+ extrudeflag(SELECT, nor);
+ translateflag(SELECT, dvec);
+ }
+
+ recalc_editnormals();
+
+ EM_fgon_flags();
+ countall();
+
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+
+ BIF_undo_push("Extrude Repeat");
+}
+
+void spin_mesh(int steps, float degr, float *dvec, int mode)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve,*nextve;
+ float nor[3]= {0.0, 0.0, 0.0};
+ float *curs, si,n[3],q[4],cmat[3][3],imat[3][3], tmat[3][3];
+ float cent[3],bmat[3][3];
+ float phi;
+ short a,ok;
+
+ TEST_EDITMESH
+ if(multires_test()) return;
+
+ /* imat and center and size */
+ Mat3CpyMat4(bmat, G.obedit->obmat);
+ Mat3Inv(imat,bmat);
+
+ curs= give_cursor();
+ VECCOPY(cent, curs);
+ cent[0]-= G.obedit->obmat[3][0];
+ cent[1]-= G.obedit->obmat[3][1];
+ cent[2]-= G.obedit->obmat[3][2];
+ Mat3MulVecfl(imat, cent);
+
+ phi= degr*M_PI/360.0;
+ phi/= steps;
+ if(G.scene->toolsettings->editbutflag & B_CLOCKWISE) phi= -phi;
+
+ if(dvec) {
+ n[0]= G.vd->viewinv[1][0];
+ n[1]= G.vd->viewinv[1][1];
+ n[2]= G.vd->viewinv[1][2];
+ } else {
+ n[0]= G.vd->viewinv[2][0];
+ n[1]= G.vd->viewinv[2][1];
+ n[2]= G.vd->viewinv[2][2];
+ }
+ Normalize(n);
+
+ q[0]= (float)cos(phi);
+ si= (float)sin(phi);
+ q[1]= n[0]*si;
+ q[2]= n[1]*si;
+ q[3]= n[2]*si;
+ QuatToMat3(q, cmat);
+
+ Mat3MulMat3(tmat,cmat,bmat);
+ Mat3MulMat3(bmat,imat,tmat);
+
+ if(mode==0) if(G.scene->toolsettings->editbutflag & B_KEEPORIG) adduplicateflag(1);
+ ok= 1;
+
+ for(a=0;a<steps;a++) {
+ if(mode==0) ok= extrudeflag(SELECT, nor);
+ else adduplicateflag(SELECT);
+ if(ok==0) {
+ error("No valid vertices are selected");
+ break;
+ }
+ rotateflag(SELECT, cent, bmat);
+ if(dvec) {
+ Mat3MulVecfl(bmat,dvec);
+ translateflag(SELECT, dvec);
+ }
+ }
+
+ if(ok==0) {
+ /* no vertices or only loose ones selected, remove duplicates */
+ eve= em->verts.first;
+ while(eve) {
+ nextve= eve->next;
+ if(eve->f & SELECT) {
+ BLI_remlink(&em->verts,eve);
+ free_editvert(eve);
+ }
+ eve= nextve;
+ }
+ }
+ recalc_editnormals();
+
+ EM_fgon_flags();
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+
+
+ if(dvec==NULL) BIF_undo_push("Spin");
+}
+
+void screw_mesh(int steps, int turns)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve,*v1=0,*v2=0;
+ EditEdge *eed;
+ float dvec[3], nor[3];
+
+ TEST_EDITMESH
+ if(multires_test()) return;
+
+ /* clear flags */
+ eve= em->verts.first;
+ while(eve) {
+ eve->f1= 0;
+ eve= eve->next;
+ }
+ /* edges set flags in verts */
+ eed= em->edges.first;
+ while(eed) {
+ if(eed->v1->f & SELECT) {
+ if(eed->v2->f & SELECT) {
+ /* watch: f1 is a byte */
+ if(eed->v1->f1<2) eed->v1->f1++;
+ if(eed->v2->f1<2) eed->v2->f1++;
+ }
+ }
+ eed= eed->next;
+ }
+ /* find two vertices with eve->f1==1, more or less is wrong */
+ eve= em->verts.first;
+ while(eve) {
+ if(eve->f1==1) {
+ if(v1==0) v1= eve;
+ else if(v2==0) v2= eve;
+ else {
+ v1=0;
+ break;
+ }
+ }
+ eve= eve->next;
+ }
+ if(v1==0 || v2==0) {
+ error("You have to select a string of connected vertices too");
+ return;
+ }
+
+ /* calculate dvec */
+ dvec[0]= ( (v1->co[0]- v2->co[0]) )/(steps);
+ dvec[1]= ( (v1->co[1]- v2->co[1]) )/(steps);
+ dvec[2]= ( (v1->co[2]- v2->co[2]) )/(steps);
+
+ VECCOPY(nor, G.obedit->obmat[2]);
+
+ if(nor[0]*dvec[0]+nor[1]*dvec[1]+nor[2]*dvec[2]>0.000) {
+ dvec[0]= -dvec[0];
+ dvec[1]= -dvec[1];
+ dvec[2]= -dvec[2];
+ }
+
+ spin_mesh(turns*steps, turns*360, dvec, 0);
+
+ BIF_undo_push("Spin");
+}
+
+
+static void erase_edges(ListBase *l)
+{
+ EditEdge *ed, *nexted;
+
+ ed = (EditEdge *) l->first;
+ while(ed) {
+ nexted= ed->next;
+ if( (ed->v1->f & SELECT) || (ed->v2->f & SELECT) ) {
+ remedge(ed);
+ free_editedge(ed);
+ }
+ ed= nexted;
+ }
+}
+
+static void erase_faces(ListBase *l)
+{
+ EditFace *f, *nextf;
+
+ f = (EditFace *) l->first;
+
+ while(f) {
+ nextf= f->next;
+ if( faceselectedOR(f, SELECT) ) {
+ BLI_remlink(l, f);
+ free_editface(f);
+ }
+ f = nextf;
+ }
+}
+
+static void erase_vertices(ListBase *l)
+{
+ EditVert *v, *nextv;
+
+ v = (EditVert *) l->first;
+ while(v) {
+ nextv= v->next;
+ if(v->f & 1) {
+ BLI_remlink(l, v);
+ free_editvert(v);
+ }
+ v = nextv;
+ }
+}
+
+void delete_mesh(void)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa, *nextvl;
+ EditVert *eve,*nextve;
+ EditEdge *eed,*nexted;
+ short event;
+ int count;
+ char *str="Erase";
+
+ TEST_EDITMESH
+ if(multires_test()) return;
+
+ event= pupmenu("Erase %t|Vertices%x10|Edges%x1|Faces%x2|All%x3|Edges & Faces%x4|Only Faces%x5|Edge Loop%x6");
+ if(event<1) return;
+
+ if(event==10 ) {
+ str= "Erase Vertices";
+ erase_edges(&em->edges);
+ erase_faces(&em->faces);
+ erase_vertices(&em->verts);
+ }
+ else if(event==6) {
+ if(!EdgeLoopDelete()) {
+ BIF_undo();
+ }
+ }
+ else if(event==4) {
+ str= "Erase Edges & Faces";
+ efa= em->faces.first;
+ while(efa) {
+ nextvl= efa->next;
+ /* delete only faces with 1 or more edges selected */
+ count= 0;
+ if(efa->e1->f & SELECT) count++;
+ if(efa->e2->f & SELECT) count++;
+ if(efa->e3->f & SELECT) count++;
+ if(efa->e4 && (efa->e4->f & SELECT)) count++;
+ if(count) {
+ BLI_remlink(&em->faces, efa);
+ free_editface(efa);
+ }
+ efa= nextvl;
+ }
+ eed= em->edges.first;
+ while(eed) {
+ nexted= eed->next;
+ if(eed->f & SELECT) {
+ remedge(eed);
+ free_editedge(eed);
+ }
+ eed= nexted;
+ }
+ efa= em->faces.first;
+ while(efa) {
+ nextvl= efa->next;
+ event=0;
+ if( efa->v1->f & SELECT) event++;
+ if( efa->v2->f & SELECT) event++;
+ if( efa->v3->f & SELECT) event++;
+ if(efa->v4 && (efa->v4->f & SELECT)) event++;
+
+ if(event>1) {
+ BLI_remlink(&em->faces, efa);
+ free_editface(efa);
+ }
+ efa= nextvl;
+ }
+ }
+ else if(event==1) {
+ str= "Erase Edges";
+ // faces first
+ efa= em->faces.first;
+ while(efa) {
+ nextvl= efa->next;
+ event=0;
+ if( efa->e1->f & SELECT) event++;
+ if( efa->e2->f & SELECT) event++;
+ if( efa->e3->f & SELECT) event++;
+ if(efa->e4 && (efa->e4->f & SELECT)) event++;
+
+ if(event) {
+ BLI_remlink(&em->faces, efa);
+ free_editface(efa);
+ }
+ efa= nextvl;
+ }
+ eed= em->edges.first;
+ while(eed) {
+ nexted= eed->next;
+ if(eed->f & SELECT) {
+ remedge(eed);
+ free_editedge(eed);
+ }
+ eed= nexted;
+ }
+ /* to remove loose vertices: */
+ eed= em->edges.first;
+ while(eed) {
+ if( eed->v1->f & SELECT) eed->v1->f-=SELECT;
+ if( eed->v2->f & SELECT) eed->v2->f-=SELECT;
+ eed= eed->next;
+ }
+ eve= em->verts.first;
+ while(eve) {
+ nextve= eve->next;
+ if(eve->f & SELECT) {
+ BLI_remlink(&em->verts,eve);
+ free_editvert(eve);
+ }
+ eve= nextve;
+ }
+
+ }
+ else if(event==2) {
+ str="Erase Faces";
+ delfaceflag(SELECT);
+ }
+ else if(event==3) {
+ str= "Erase All";
+ if(em->verts.first) free_vertlist(&em->verts);
+ if(em->edges.first) free_edgelist(&em->edges);
+ if(em->faces.first) free_facelist(&em->faces);
+ if(em->selected.first) BLI_freelistN(&(em->selected));
+ }
+ else if(event==5) {
+ str= "Erase Only Faces";
+ efa= em->faces.first;
+ while(efa) {
+ nextvl= efa->next;
+ if(efa->f & SELECT) {
+ BLI_remlink(&em->faces, efa);
+ free_editface(efa);
+ }
+ efa= nextvl;
+ }
+ }
+
+ EM_fgon_flags(); // redo flags and indices for fgons
+
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ BIF_undo_push(str);
+}
+
+
+/* Got this from scanfill.c. You will need to juggle around the
+ * callbacks for the scanfill.c code a bit for this to work. */
+void fill_mesh(void)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve,*v1;
+ EditEdge *eed,*e1,*nexted;
+ EditFace *efa,*nextvl, *efan;
+ short ok;
+
+ if(G.obedit==0 || (G.obedit->type!=OB_MESH)) return;
+ if(multires_test()) return;
+
+ waitcursor(1);
+
+ /* copy all selected vertices */
+ eve= em->verts.first;
+ while(eve) {
+ if(eve->f & SELECT) {
+ v1= BLI_addfillvert(eve->co);
+ eve->tmp.v= v1;
+ v1->tmp.v= eve;
+ v1->xs= 0; // used for counting edges
+ }
+ eve= eve->next;
+ }
+ /* copy all selected edges */
+ eed= em->edges.first;
+ while(eed) {
+ if( (eed->v1->f & SELECT) && (eed->v2->f & SELECT) ) {
+ e1= BLI_addfilledge(eed->v1->tmp.v, eed->v2->tmp.v);
+ e1->v1->xs++;
+ e1->v2->xs++;
+ }
+ eed= eed->next;
+ }
+ /* from all selected faces: remove vertices and edges to prevent doubles */
+ /* all edges add values, faces subtract,
+ then remove edges with vertices ->xs<2 */
+ efa= em->faces.first;
+ ok= 0;
+ while(efa) {
+ nextvl= efa->next;
+ if( faceselectedAND(efa, 1) ) {
+ efa->v1->tmp.v->xs--;
+ efa->v2->tmp.v->xs--;
+ efa->v3->tmp.v->xs--;
+ if(efa->v4) efa->v4->tmp.v->xs--;
+ ok= 1;
+
+ }
+ efa= nextvl;
+ }
+ if(ok) { /* there are faces selected */
+ eed= filledgebase.first;
+ while(eed) {
+ nexted= eed->next;
+ if(eed->v1->xs<2 || eed->v2->xs<2) {
+ BLI_remlink(&filledgebase,eed);
+ }
+ eed= nexted;
+ }
+ }
+
+ if(BLI_edgefill(0, (G.obedit && G.obedit->actcol)?(G.obedit->actcol-1):0)) {
+ efa= fillfacebase.first;
+ while(efa) {
+ /* normals default pointing up */
+ efan= addfacelist(efa->v3->tmp.v, efa->v2->tmp.v,
+ efa->v1->tmp.v, 0, NULL, NULL);
+ if(efan) EM_select_face(efan, 1);
+ efa= efa->next;
+ }
+ }
+
+ BLI_end_edgefill();
+
+ waitcursor(0);
+ EM_select_flush();
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+
+#ifdef WITH_VERSE
+ if(G.editMesh->vnode)
+ sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode);
+#endif
+
+ BIF_undo_push("Fill");
+}
+/*GB*/
+/*-------------------------------------------------------------------------------*/
+/*--------------------------- Edge Based Subdivide ------------------------------*/
+
+#define EDGENEW 2
+#define FACENEW 2
+#define EDGEINNER 4
+#define EDGEOLD 8
+
+/*used by faceloop cut to select only edges valid for edge slide*/
+#define DOUBLEOPFILL 16
+
+/* calculates offset for co, based on fractal, sphere or smooth settings */
+static void alter_co(float *co, EditEdge *edge, float rad, int beauty, float perc)
+{
+ float vec1[3], fac;
+
+ if(beauty & B_SMOOTH) {
+ /* we calculate an offset vector vec1[], to be added to *co */
+ float len, fac, nor[3], nor1[3], nor2[3];
+
+ VecSubf(nor, edge->v1->co, edge->v2->co);
+ len= 0.5f*Normalize(nor);
+
+ VECCOPY(nor1, edge->v1->no);
+ VECCOPY(nor2, edge->v2->no);
+
+ /* cosine angle */
+ fac= nor[0]*nor1[0] + nor[1]*nor1[1] + nor[2]*nor1[2] ;
+
+ vec1[0]= fac*nor1[0];
+ vec1[1]= fac*nor1[1];
+ vec1[2]= fac*nor1[2];
+
+ /* cosine angle */
+ fac= -nor[0]*nor2[0] - nor[1]*nor2[1] - nor[2]*nor2[2] ;
+
+ vec1[0]+= fac*nor2[0];
+ vec1[1]+= fac*nor2[1];
+ vec1[2]+= fac*nor2[2];
+
+ vec1[0]*= rad*len;
+ vec1[1]*= rad*len;
+ vec1[2]*= rad*len;
+
+ co[0] += vec1[0];
+ co[1] += vec1[1];
+ co[2] += vec1[2];
+ }
+ else {
+ if(rad > 0.0) { /* subdivide sphere */
+ Normalize(co);
+ co[0]*= rad;
+ co[1]*= rad;
+ co[2]*= rad;
+ }
+ else if(rad< 0.0) { /* fractal subdivide */
+ fac= rad* VecLenf(edge->v1->co, edge->v2->co);
+ vec1[0]= fac*(float)(0.5-BLI_drand());
+ vec1[1]= fac*(float)(0.5-BLI_drand());
+ vec1[2]= fac*(float)(0.5-BLI_drand());
+ VecAddf(co, co, vec1);
+ }
+
+ }
+}
+
+/* assumes in the edge is the correct interpolated vertices already */
+/* percent defines the interpolation, rad and beauty are for special options */
+/* results in new vertex with correct coordinate, vertex normal and weight group info */
+static EditVert *subdivide_edge_addvert(EditEdge *edge, float rad, int beauty, float percent)
+{
+ EditVert *ev;
+ float co[3];
+
+ co[0] = (edge->v2->co[0]-edge->v1->co[0])*percent + edge->v1->co[0];
+ co[1] = (edge->v2->co[1]-edge->v1->co[1])*percent + edge->v1->co[1];
+ co[2] = (edge->v2->co[2]-edge->v1->co[2])*percent + edge->v1->co[2];
+
+ /* offset for smooth or sphere or fractal */
+ alter_co(co, edge, rad, beauty, percent);
+
+ ev = addvertlist(co, NULL);
+
+ /* vert data (vgroups, ..) */
+ EM_data_interp_from_verts(edge->v1, edge->v2, ev, percent);
+
+ /* normal */
+ ev->no[0] = (edge->v2->no[0]-edge->v1->no[0])*percent + edge->v1->no[0];
+ ev->no[1] = (edge->v2->no[1]-edge->v1->no[1])*percent + edge->v1->no[1];
+ ev->no[2] = (edge->v2->no[2]-edge->v1->no[2])*percent + edge->v1->no[2];
+ Normalize(ev->no);
+
+ return ev;
+}
+
+static void flipvertarray(EditVert** arr, short size)
+{
+ EditVert *hold;
+ int i;
+
+ for(i=0; i<size/2; i++) {
+ hold = arr[i];
+ arr[i] = arr[size-i-1];
+ arr[size-i-1] = hold;
+ }
+}
+
+static void facecopy(EditFace *source, EditFace *target)
+{
+ EditMesh *em= G.editMesh;
+ float *v1 = source->v1->co, *v2 = source->v2->co, *v3 = source->v3->co;
+ float *v4 = source->v4? source->v4->co: NULL;
+ float w[4][4];
+
+ CustomData_em_copy_data(&em->fdata, &em->fdata, source->data, &target->data);
+
+ target->mat_nr = source->mat_nr;
+ target->flag = source->flag;
+ target->h = source->h;
+
+ InterpWeightsQ3Dfl(v1, v2, v3, v4, target->v1->co, w[0]);
+ InterpWeightsQ3Dfl(v1, v2, v3, v4, target->v2->co, w[1]);
+ InterpWeightsQ3Dfl(v1, v2, v3, v4, target->v3->co, w[2]);
+ if (target->v4)
+ InterpWeightsQ3Dfl(v1, v2, v3, v4, target->v4->co, w[3]);
+
+ CustomData_em_interp(&em->fdata, &source->data, NULL, (float*)w, 1, target->data);
+}
+
+static void fill_quad_single(EditFace *efa, struct GHash *gh, int numcuts, int seltype)
+{
+ EditEdge *cedge=NULL;
+ EditVert *v[4], **verts;
+ EditFace *hold;
+ short start=0, end, left, right, vertsize,i;
+
+ v[0] = efa->v1;
+ v[1] = efa->v2;
+ v[2] = efa->v3;
+ v[3] = efa->v4;
+
+ if(efa->e1->f & SELECT) { cedge = efa->e1; start = 0;}
+ else if(efa->e2->f & SELECT) { cedge = efa->e2; start = 1;}
+ else if(efa->e3->f & SELECT) { cedge = efa->e3; start = 2;}
+ else if(efa->e4->f & SELECT) { cedge = efa->e4; start = 3;}
+
+ // Point verts to the array of new verts for cedge
+ verts = BLI_ghash_lookup(gh, cedge);
+ //This is the index size of the verts array
+ vertsize = numcuts+2;
+
+ // Is the original v1 the same as the first vert on the selected edge?
+ // if not, the edge is running the opposite direction in this face so flip
+ // the array to the correct direction
+
+ if(verts[0] != v[start]) {flipvertarray(verts,numcuts+2);}
+ end = (start+1)%4;
+ left = (start+2)%4;
+ right = (start+3)%4;
+
+ /*
+ We should have something like this now
+
+ end start
+ 3 2 1 0
+ |---*---*---|
+ | |
+ | |
+ | |
+ -------------
+ left right
+
+ where start,end,left, right are indexes of EditFace->v1, etc (stored in v)
+ and 0,1,2... are the indexes of the new verts stored in verts
+
+ We will fill this case like this or this depending on even or odd cuts
+
+ |---*---*---| |---*---|
+ | / \ | | / \ |
+ | / \ | | / \ |
+ |/ \| |/ \|
+ ------------- ---------
+ */
+
+ // Make center face
+ if(vertsize % 2 == 0) {
+ hold = addfacelist(verts[(vertsize-1)/2],verts[((vertsize-1)/2)+1],v[left],v[right], NULL,NULL);
+ hold->e2->f2 |= EDGEINNER;
+ hold->e4->f2 |= EDGEINNER;
+ }else{
+ hold = addfacelist(verts[(vertsize-1)/2],v[left],v[right],NULL, NULL,NULL);
+ hold->e1->f2 |= EDGEINNER;
+ hold->e3->f2 |= EDGEINNER;
+ }
+ facecopy(efa,hold);
+
+ // Make side faces
+ for(i=0;i<(vertsize-1)/2;i++) {
+ hold = addfacelist(verts[i],verts[i+1],v[right],NULL,NULL,NULL);
+ facecopy(efa,hold);
+ if(i+1 != (vertsize-1)/2) {
+ if(seltype == SUBDIV_SELECT_INNER) {
+ hold->e2->f2 |= EDGEINNER;
+ }
+ }
+ hold = addfacelist(verts[vertsize-2-i],verts[vertsize-1-i],v[left],NULL,NULL,NULL);
+ facecopy(efa,hold);
+ if(i+1 != (vertsize-1)/2) {
+ if(seltype == SUBDIV_SELECT_INNER) {
+ hold->e3->f2 |= EDGEINNER;
+ }
+ }
+ }
+}
+
+static void fill_tri_single(EditFace *efa, struct GHash *gh, int numcuts, int seltype)
+{
+ EditEdge *cedge=NULL;
+ EditVert *v[3], **verts;
+ EditFace *hold;
+ short start=0, end, op, vertsize,i;
+
+ v[0] = efa->v1;
+ v[1] = efa->v2;
+ v[2] = efa->v3;
+
+ if(efa->e1->f & SELECT) { cedge = efa->e1; start = 0;}
+ else if(efa->e2->f & SELECT) { cedge = efa->e2; start = 1;}
+ else if(efa->e3->f & SELECT) { cedge = efa->e3; start = 2;}
+
+ // Point verts to the array of new verts for cedge
+ verts = BLI_ghash_lookup(gh, cedge);
+ //This is the index size of the verts array
+ vertsize = numcuts+2;
+
+ // Is the original v1 the same as the first vert on the selected edge?
+ // if not, the edge is running the opposite direction in this face so flip
+ // the array to the correct direction
+
+ if(verts[0] != v[start]) {flipvertarray(verts,numcuts+2);}
+ end = (start+1)%3;
+ op = (start+2)%3;
+
+ /*
+ We should have something like this now
+
+ end start
+ 3 2 1 0
+ |---*---*---|
+ \ |
+ \ |
+ \ |
+ \ |
+ \ |
+ \ |
+ |op
+
+ where start,end,op are indexes of EditFace->v1, etc (stored in v)
+ and 0,1,2... are the indexes of the new verts stored in verts
+
+ We will fill this case like this or this depending on even or odd cuts
+
+ 3 2 1 0
+ |---*---*---|
+ \ \ \ |
+ \ \ \ |
+ \ \ \ |
+ \ \ \|
+ \ \\|
+ \ |
+ |op
+ */
+
+ // Make side faces
+ for(i=0;i<(vertsize-1);i++) {
+ hold = addfacelist(verts[i],verts[i+1],v[op],NULL,NULL,NULL);
+ if(i+1 != vertsize-1) {
+ if(seltype == SUBDIV_SELECT_INNER) {
+ hold->e2->f2 |= EDGEINNER;
+ }
+ }
+ facecopy(efa,hold);
+ }
+}
+
+static void fill_quad_double_op(EditFace *efa, struct GHash *gh, int numcuts)
+{
+ EditEdge *cedge[2]={NULL, NULL};
+ EditVert *v[4], **verts[2];
+ EditFace *hold;
+ short start=0, end, left, right, vertsize,i;
+
+ v[0] = efa->v1;
+ v[1] = efa->v2;
+ v[2] = efa->v3;
+ v[3] = efa->v4;
+
+ if(efa->e1->f & SELECT) { cedge[0] = efa->e1; cedge[1] = efa->e3; start = 0;}
+ else if(efa->e2->f & SELECT) { cedge[0] = efa->e2; cedge[1] = efa->e4; start = 1;}
+
+ // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1]
+ verts[0] = BLI_ghash_lookup(gh, cedge[0]);
+ verts[1] = BLI_ghash_lookup(gh, cedge[1]);
+ //This is the index size of the verts array
+ vertsize = numcuts+2;
+
+ // Is the original v1 the same as the first vert on the selected edge?
+ // if not, the edge is running the opposite direction in this face so flip
+ // the array to the correct direction
+
+ if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);}
+ end = (start+1)%4;
+ left = (start+2)%4;
+ right = (start+3)%4;
+ if(verts[1][0] != v[left]) {flipvertarray(verts[1],numcuts+2);}
+ /*
+ We should have something like this now
+
+ end start
+ 3 2 1 0
+ |---*---*---|
+ | |
+ | |
+ | |
+ |---*---*---|
+ 0 1 2 3
+ left right
+
+ We will fill this case like this or this depending on even or odd cuts
+
+ |---*---*---|
+ | | | |
+ | | | |
+ | | | |
+ |---*---*---|
+ */
+
+ // Make side faces
+ for(i=0;i<vertsize-1;i++) {
+ hold = addfacelist(verts[0][i],verts[0][i+1],verts[1][vertsize-2-i],verts[1][vertsize-1-i],NULL,NULL);
+ if(i < vertsize-2) {
+ hold->e2->f2 |= EDGEINNER;
+ hold->e2->f2 |= DOUBLEOPFILL;
+ }
+ facecopy(efa,hold);
+ }
+}
+
+static void fill_quad_double_adj_path(EditFace *efa, struct GHash *gh, int numcuts)
+{
+ EditEdge *cedge[2]={NULL, NULL};
+ EditVert *v[4], **verts[2];
+ EditFace *hold;
+ short start=0, start2=0, vertsize,i;
+
+ v[0] = efa->v1;
+ v[1] = efa->v2;
+ v[2] = efa->v3;
+ v[3] = efa->v4;
+
+ if(efa->e1->f & SELECT && efa->e2->f & SELECT) {cedge[0] = efa->e1; cedge[1] = efa->e2; start = 0; start2 = 1;}
+ if(efa->e2->f & SELECT && efa->e3->f & SELECT) {cedge[0] = efa->e2; cedge[1] = efa->e3; start = 1; start2 = 2;}
+ if(efa->e3->f & SELECT && efa->e4->f & SELECT) {cedge[0] = efa->e3; cedge[1] = efa->e4; start = 2; start2 = 3;}
+ if(efa->e4->f & SELECT && efa->e1->f & SELECT) {cedge[0] = efa->e4; cedge[1] = efa->e1; start = 3; start2 = 0;}
+
+ // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1]
+ verts[0] = BLI_ghash_lookup(gh, cedge[0]);
+ verts[1] = BLI_ghash_lookup(gh, cedge[1]);
+ //This is the index size of the verts array
+ vertsize = numcuts+2;
+
+ // Is the original v1 the same as the first vert on the selected edge?
+ // if not, the edge is running the opposite direction in this face so flip
+ // the array to the correct direction
+
+ if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);}
+ if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);}
+ /*
+ We should have something like this now
+
+ end start
+ 3 2 1 0
+ start2 0|---*---*---|
+ | |
+ 1* |
+ | |
+ 2* |
+ | |
+ end2 3|-----------|
+
+ We will fill this case like this or this depending on even or odd cuts
+ |---*---*---|
+ | / / / |
+ * / / |
+ | / / |
+ * / |
+ | / |
+ |-----------|
+ */
+
+ // Make outside tris
+ hold = addfacelist(verts[0][vertsize-2],verts[0][vertsize-1],verts[1][1],NULL,NULL,NULL);
+ /* when ctrl is depressed, only want verts on the cutline selected */
+ if (G.qual != LR_CTRLKEY)
+ hold->e3->f2 |= EDGEINNER;
+ facecopy(efa,hold);
+ hold = addfacelist(verts[0][0],verts[1][vertsize-1],v[(start2+2)%4],NULL,NULL,NULL);
+ /* when ctrl is depressed, only want verts on the cutline selected */
+ if (G.qual != LR_CTRLKEY)
+ hold->e1->f2 |= EDGEINNER;
+ facecopy(efa,hold);
+ //if(G.scene->toolsettings->editbutflag & B_AUTOFGON) {
+ // hold->e1->h |= EM_FGON;
+ //}
+ // Make side faces
+
+ for(i=0;i<numcuts;i++) {
+ hold = addfacelist(verts[0][i],verts[0][i+1],verts[1][vertsize-1-(i+1)],verts[1][vertsize-1-i],NULL,NULL);
+ hold->e2->f2 |= EDGEINNER;
+ facecopy(efa,hold);
+ }
+ //EM_fgon_flags();
+
+}
+
+static void fill_quad_double_adj_fan(EditFace *efa, struct GHash *gh, int numcuts)
+{
+ EditEdge *cedge[2]={NULL, NULL};
+ EditVert *v[4], *op=NULL, **verts[2];
+ EditFace *hold;
+ short start=0, start2=0, vertsize,i;
+
+ v[0] = efa->v1;
+ v[1] = efa->v2;
+ v[2] = efa->v3;
+ v[3] = efa->v4;
+
+ if(efa->e1->f & SELECT && efa->e2->f & SELECT) {cedge[0] = efa->e1; cedge[1] = efa->e2; start = 0; start2 = 1; op = efa->v4;}
+ if(efa->e2->f & SELECT && efa->e3->f & SELECT) {cedge[0] = efa->e2; cedge[1] = efa->e3; start = 1; start2 = 2; op = efa->v1;}
+ if(efa->e3->f & SELECT && efa->e4->f & SELECT) {cedge[0] = efa->e3; cedge[1] = efa->e4; start = 2; start2 = 3; op = efa->v2;}
+ if(efa->e4->f & SELECT && efa->e1->f & SELECT) {cedge[0] = efa->e4; cedge[1] = efa->e1; start = 3; start2 = 0; op = efa->v3;}
+
+
+ // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1]
+ verts[0] = BLI_ghash_lookup(gh, cedge[0]);
+ verts[1] = BLI_ghash_lookup(gh, cedge[1]);
+ //This is the index size of the verts array
+ vertsize = numcuts+2;
+
+ // Is the original v1 the same as the first vert on the selected edge?
+ // if not, the edge is running the opposite direction in this face so flip
+ // the array to the correct direction
+
+ if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);}
+ if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);}
+ /*
+ We should have something like this now
+
+ end start
+ 3 2 1 0
+ start2 0|---*---*---|
+ | |
+ 1* |
+ | |
+ 2* |
+ | |
+ end2 3|-----------|op
+
+ We will fill this case like this or this (warning horrible ascii art follows)
+ |---*---*---|
+ | \ \ \ |
+ *---\ \ \ |
+ | \ \ \ \|
+ *---- \ \ \ |
+ | --- \\\|
+ |-----------|
+ */
+
+ for(i=0;i<=numcuts;i++) {
+ hold = addfacelist(op,verts[1][numcuts-i],verts[1][numcuts-i+1],NULL,NULL,NULL);
+ hold->e1->f2 |= EDGEINNER;
+ facecopy(efa,hold);
+
+ hold = addfacelist(op,verts[0][i],verts[0][i+1],NULL,NULL,NULL);
+ hold->e3->f2 |= EDGEINNER;
+ facecopy(efa,hold);
+ }
+}
+
+static void fill_quad_double_adj_inner(EditFace *efa, struct GHash *gh, int numcuts)
+{
+ EditEdge *cedge[2]={NULL, NULL};
+ EditVert *v[4], *op=NULL, **verts[2],**inner;
+ EditFace *hold;
+ short start=0, start2=0, vertsize,i;
+ float co[3];
+
+ v[0] = efa->v1;
+ v[1] = efa->v2;
+ v[2] = efa->v3;
+ v[3] = efa->v4;
+
+ if(efa->e1->f & SELECT && efa->e2->f & SELECT) {cedge[0] = efa->e1; cedge[1] = efa->e2; start = 0; start2 = 1; op = efa->v4;}
+ if(efa->e2->f & SELECT && efa->e3->f & SELECT) {cedge[0] = efa->e2; cedge[1] = efa->e3; start = 1; start2 = 2; op = efa->v1;}
+ if(efa->e3->f & SELECT && efa->e4->f & SELECT) {cedge[0] = efa->e3; cedge[1] = efa->e4; start = 2; start2 = 3; op = efa->v2;}
+ if(efa->e4->f & SELECT && efa->e1->f & SELECT) {cedge[0] = efa->e4; cedge[1] = efa->e1; start = 3; start2 = 0; op = efa->v3;}
+
+
+ // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1]
+ verts[0] = BLI_ghash_lookup(gh, cedge[0]);
+ verts[1] = BLI_ghash_lookup(gh, cedge[1]);
+ //This is the index size of the verts array
+ vertsize = numcuts+2;
+
+ // Is the original v1 the same as the first vert on the selected edge?
+ // if not, the edge is running the opposite direction in this face so flip
+ // the array to the correct direction
+
+ if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);}
+ if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);}
+ /*
+ We should have something like this now
+
+ end start
+ 3 2 1 0
+ start2 0|---*---*---|
+ | |
+ 1* |
+ | |
+ 2* |
+ | |
+ end2 3|-----------|op
+
+ We will fill this case like this or this (warning horrible ascii art follows)
+ |---*-----*---|
+ | * / |
+ * \ / |
+ | * |
+ | / \ |
+ * \ |
+ | \ |
+ |-------------|
+ */
+
+ // Add Inner Vert(s)
+ inner = MEM_mallocN(sizeof(EditVert*)*numcuts,"New inner verts");
+
+ for(i=0;i<numcuts;i++) {
+ co[0] = (verts[0][numcuts-i]->co[0] + verts[1][i+1]->co[0] ) / 2 ;
+ co[1] = (verts[0][numcuts-i]->co[1] + verts[1][i+1]->co[1] ) / 2 ;
+ co[2] = (verts[0][numcuts-i]->co[2] + verts[1][i+1]->co[2] ) / 2 ;
+ inner[i] = addvertlist(co, NULL);
+ inner[i]->f2 |= EDGEINNER;
+
+ EM_data_interp_from_verts(verts[0][numcuts-i], verts[1][i+1], inner[i], 0.5f);
+ }
+
+ // Add Corner Quad
+ hold = addfacelist(verts[0][numcuts+1],verts[1][1],inner[0],verts[0][numcuts],NULL,NULL);
+ hold->e2->f2 |= EDGEINNER;
+ hold->e3->f2 |= EDGEINNER;
+ facecopy(efa,hold);
+ // Add Bottom Quads
+ hold = addfacelist(verts[0][0],verts[0][1],inner[numcuts-1],op,NULL,NULL);
+ hold->e2->f2 |= EDGEINNER;
+ facecopy(efa,hold);
+
+ hold = addfacelist(op,inner[numcuts-1],verts[1][numcuts],verts[1][numcuts+1],NULL,NULL);
+ hold->e2->f2 |= EDGEINNER;
+ facecopy(efa,hold);
+
+ //if(G.scene->toolsettings->editbutflag & B_AUTOFGON) {
+ // hold->e1->h |= EM_FGON;
+ //}
+ // Add Fill Quads (if # cuts > 1)
+
+ for(i=0;i<numcuts-1;i++) {
+ hold = addfacelist(inner[i],verts[1][i+1],verts[1][i+2],inner[i+1],NULL,NULL);
+ hold->e1->f2 |= EDGEINNER;
+ hold->e3->f2 |= EDGEINNER;
+ facecopy(efa,hold);
+
+ hold = addfacelist(inner[i],inner[i+1],verts[0][numcuts-1-i],verts[0][numcuts-i],NULL,NULL);
+ hold->e2->f2 |= EDGEINNER;
+ hold->e4->f2 |= EDGEINNER;
+ facecopy(efa,hold);
+
+ //if(G.scene->toolsettings->editbutflag & B_AUTOFGON) {
+ // hold->e1->h |= EM_FGON;
+ //}
+ }
+
+ //EM_fgon_flags();
+
+ MEM_freeN(inner);
+}
+
+static void fill_tri_double(EditFace *efa, struct GHash *gh, int numcuts)
+{
+ EditEdge *cedge[2]={NULL, NULL};
+ EditVert *v[3], **verts[2];
+ EditFace *hold;
+ short start=0, start2=0, vertsize,i;
+
+ v[0] = efa->v1;
+ v[1] = efa->v2;
+ v[2] = efa->v3;
+
+ if(efa->e1->f & SELECT && efa->e2->f & SELECT) {cedge[0] = efa->e1; cedge[1] = efa->e2; start = 0; start2 = 1;}
+ if(efa->e2->f & SELECT && efa->e3->f & SELECT) {cedge[0] = efa->e2; cedge[1] = efa->e3; start = 1; start2 = 2;}
+ if(efa->e3->f & SELECT && efa->e1->f & SELECT) {cedge[0] = efa->e3; cedge[1] = efa->e1; start = 2; start2 = 0;}
+
+ // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1]
+ verts[0] = BLI_ghash_lookup(gh, cedge[0]);
+ verts[1] = BLI_ghash_lookup(gh, cedge[1]);
+ //This is the index size of the verts array
+ vertsize = numcuts+2;
+
+ // Is the original v1 the same as the first vert on the selected edge?
+ // if not, the edge is running the opposite direction in this face so flip
+ // the array to the correct direction
+
+ if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);}
+ if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);}
+ /*
+ We should have something like this now
+
+ end start
+ 3 2 1 0
+ start2 0|---*---*---|
+ | /
+ 1* /
+ | /
+ 2* /
+ | /
+ end2 3|
+
+ We will fill this case like this or this depending on even or odd cuts
+ |---*---*---|
+ | / / /
+ * / /
+ | / /
+ * /
+ | /
+ |
+ */
+
+ // Make outside tri
+ hold = addfacelist(verts[0][vertsize-2],verts[0][vertsize-1],verts[1][1],NULL,NULL,NULL);
+ hold->e3->f2 |= EDGEINNER;
+ facecopy(efa,hold);
+ // Make side faces
+
+ for(i=0;i<numcuts;i++) {
+ hold = addfacelist(verts[0][i],verts[0][i+1],verts[1][vertsize-1-(i+1)],verts[1][vertsize-1-i],NULL,NULL);
+ hold->e2->f2 |= EDGEINNER;
+ facecopy(efa,hold);
+ }
+}
+
+static void fill_quad_triple(EditFace *efa, struct GHash *gh, int numcuts)
+{
+ EditEdge *cedge[3]={0};
+ EditVert *v[4], **verts[3];
+ EditFace *hold;
+ short start=0, start2=0, start3=0, vertsize, i, repeats;
+
+ v[0] = efa->v1;
+ v[1] = efa->v2;
+ v[2] = efa->v3;
+ v[3] = efa->v4;
+
+ if(!(efa->e1->f & SELECT)) {
+ cedge[0] = efa->e2;
+ cedge[1] = efa->e3;
+ cedge[2] = efa->e4;
+ start = 1;start2 = 2;start3 = 3;
+ }
+ if(!(efa->e2->f & SELECT)) {
+ cedge[0] = efa->e3;
+ cedge[1] = efa->e4;
+ cedge[2] = efa->e1;
+ start = 2;start2 = 3;start3 = 0;
+ }
+ if(!(efa->e3->f & SELECT)) {
+ cedge[0] = efa->e4;
+ cedge[1] = efa->e1;
+ cedge[2] = efa->e2;
+ start = 3;start2 = 0;start3 = 1;
+ }
+ if(!(efa->e4->f & SELECT)) {
+ cedge[0] = efa->e1;
+ cedge[1] = efa->e2;
+ cedge[2] = efa->e3;
+ start = 0;start2 = 1;start3 = 2;
+ }
+ // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1]
+ verts[0] = BLI_ghash_lookup(gh, cedge[0]);
+ verts[1] = BLI_ghash_lookup(gh, cedge[1]);
+ verts[2] = BLI_ghash_lookup(gh, cedge[2]);
+ //This is the index size of the verts array
+ vertsize = numcuts+2;
+
+ // Is the original v1 the same as the first vert on the selected edge?
+ // if not, the edge is running the opposite direction in this face so flip
+ // the array to the correct direction
+
+ if(verts[0][0] != v[start]) {flipvertarray(verts[0],numcuts+2);}
+ if(verts[1][0] != v[start2]) {flipvertarray(verts[1],numcuts+2);}
+ if(verts[2][0] != v[start3]) {flipvertarray(verts[2],numcuts+2);}
+ /*
+ We should have something like this now
+
+ start2
+ 3 2 1 0
+ start3 0|---*---*---|3
+ | |
+ 1* *2
+ | |
+ 2* *1
+ | |
+ 3|-----------|0 start
+
+ We will fill this case like this or this depending on even or odd cuts
+ there are a couple of differences. For odd cuts, there is a tri in the
+ middle as well as 1 quad at the bottom (not including the extra quads
+ for odd cuts > 1
+
+ For even cuts, there is a quad in the middle and 2 quads on the bottom
+
+ they are numbered here for clarity
+
+ 1 outer tris and bottom quads
+ 2 inner tri or quad
+ 3 repeating quads
+
+ |---*---*---*---|
+ |1/ / \ \ 1|
+ |/ 3 / \ 3 \|
+ * / 2 \ *
+ | / \ |
+ |/ \ |
+ *---------------*
+ | 3 |
+ | |
+ *---------------*
+ | |
+ | 1 |
+ | |
+ |---------------|
+
+ |---*---*---*---*---|
+ | 1/ / \ \ 1|
+ | / / \ \ |
+ |/ 3 / \ 3 \|
+ * / \ *
+ | / \ |
+ | / 2 \ |
+ |/ \|
+ *-------------------*
+ | |
+ | 3 |
+ | |
+ *-------------------*
+ | |
+ | 1 |
+ | |
+ *-------------------*
+ | |
+ | 1 |
+ | |
+ |-------------------|
+
+ */
+
+ // Make outside tris
+ hold = addfacelist(verts[0][vertsize-2],verts[0][vertsize-1],verts[1][1],NULL,NULL,NULL);
+ hold->e3->f2 |= EDGEINNER;
+ facecopy(efa,hold);
+ hold = addfacelist(verts[1][vertsize-2],verts[1][vertsize-1],verts[2][1],NULL,NULL,NULL);
+ hold->e3->f2 |= EDGEINNER;
+ facecopy(efa,hold);
+ // Make bottom quad
+ hold = addfacelist(verts[0][0],verts[0][1],verts[2][vertsize-2],verts[2][vertsize-1],NULL,NULL);
+ hold->e2->f2 |= EDGEINNER;
+ facecopy(efa,hold);
+ //If it is even cuts, add the 2nd lower quad
+ if(numcuts % 2 == 0) {
+ hold = addfacelist(verts[0][1],verts[0][2],verts[2][vertsize-3],verts[2][vertsize-2],NULL,NULL);
+ hold->e2->f2 |= EDGEINNER;
+ facecopy(efa,hold);
+ // Also Make inner quad
+ hold = addfacelist(verts[1][numcuts/2],verts[1][(numcuts/2)+1],verts[2][numcuts/2],verts[0][(numcuts/2)+1],NULL,NULL);
+ hold->e3->f2 |= EDGEINNER;
+ //if(G.scene->toolsettings->editbutflag & B_AUTOFGON) {
+ // hold->e3->h |= EM_FGON;
+ //}
+ facecopy(efa,hold);
+ repeats = (numcuts / 2) -1;
+ } else {
+ // Make inner tri
+ hold = addfacelist(verts[1][(numcuts/2)+1],verts[2][(numcuts/2)+1],verts[0][(numcuts/2)+1],NULL,NULL,NULL);
+ hold->e2->f2 |= EDGEINNER;
+ //if(G.scene->toolsettings->editbutflag & B_AUTOFGON) {
+ // hold->e2->h |= EM_FGON;
+ //}
+ facecopy(efa,hold);
+ repeats = ((numcuts+1) / 2)-1;
+ }
+
+ // cuts for 1 and 2 do not have the repeating quads
+ if(numcuts < 3) {repeats = 0;}
+ for(i=0;i<repeats;i++) {
+ //Make side repeating Quads
+ hold = addfacelist(verts[1][i+1],verts[1][i+2],verts[0][vertsize-i-3],verts[0][vertsize-i-2],NULL,NULL);
+ hold->e2->f2 |= EDGEINNER;
+ facecopy(efa,hold);
+ hold = addfacelist(verts[1][vertsize-i-3],verts[1][vertsize-i-2],verts[2][i+1],verts[2][i+2],NULL,NULL);
+ hold->e4->f2 |= EDGEINNER;
+ facecopy(efa,hold);
+ }
+ // Do repeating bottom quads
+ for(i=0;i<repeats;i++) {
+ if(numcuts % 2 == 1) {
+ hold = addfacelist(verts[0][1+i],verts[0][2+i],verts[2][vertsize-3-i],verts[2][vertsize-2-i],NULL,NULL);
+ } else {
+ hold = addfacelist(verts[0][2+i],verts[0][3+i],verts[2][vertsize-4-i],verts[2][vertsize-3-i],NULL,NULL);
+ }
+ hold->e2->f2 |= EDGEINNER;
+ facecopy(efa,hold);
+ }
+ //EM_fgon_flags();
+}
+
+static void fill_quad_quadruple(EditFace *efa, struct GHash *gh, int numcuts, float rad, int beauty)
+{
+ EditVert **verts[4], ***innerverts;
+ EditFace *hold;
+ EditEdge temp;
+ short vertsize, i, j;
+
+ // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1]
+ verts[0] = BLI_ghash_lookup(gh, efa->e1);
+ verts[1] = BLI_ghash_lookup(gh, efa->e2);
+ verts[2] = BLI_ghash_lookup(gh, efa->e3);
+ verts[3] = BLI_ghash_lookup(gh, efa->e4);
+
+ //This is the index size of the verts array
+ vertsize = numcuts+2;
+
+ // Is the original v1 the same as the first vert on the selected edge?
+ // if not, the edge is running the opposite direction in this face so flip
+ // the array to the correct direction
+
+ if(verts[0][0] != efa->v1) {flipvertarray(verts[0],numcuts+2);}
+ if(verts[1][0] != efa->v2) {flipvertarray(verts[1],numcuts+2);}
+ if(verts[2][0] == efa->v3) {flipvertarray(verts[2],numcuts+2);}
+ if(verts[3][0] == efa->v4) {flipvertarray(verts[3],numcuts+2);}
+ /*
+ We should have something like this now
+ 1
+
+ 3 2 1 0
+ 0|---*---*---|0
+ | |
+ 1* *1
+ 2 | | 4
+ 2* *2
+ | |
+ 3|---*---*---|3
+ 3 2 1 0
+
+ 3
+ // we will fill a 2 dim array of editvert*s to make filling easier
+ // the innervert order is shown
+
+ 0 0---1---2---3
+ | | | |
+ 1 0---1---2---3
+ | | | |
+ 2 0---1---2---3
+ | | | |
+ 3 0---1---2---3
+
+ */
+ innerverts = MEM_mallocN(sizeof(EditVert*)*(numcuts+2),"quad-quad subdiv inner verts outer array");
+ for(i=0;i<numcuts+2;i++) {
+ innerverts[i] = MEM_mallocN(sizeof(EditVert*)*(numcuts+2),"quad-quad subdiv inner verts inner array");
+ }
+
+ // first row is e1 last row is e3
+ for(i=0;i<numcuts+2;i++) {
+ innerverts[0][i] = verts[0][(numcuts+1)-i];
+ innerverts[numcuts+1][i] = verts[2][(numcuts+1)-i];
+ }
+
+ for(i=1;i<=numcuts;i++) {
+ /* we create a fake edge for the next loop */
+ temp.v2 = innerverts[i][0] = verts[1][i];
+ temp.v1 = innerverts[i][numcuts+1] = verts[3][i];
+
+ for(j=1;j<=numcuts;j++) {
+ float percent= (float)j/(float)(numcuts+1);
+
+ innerverts[i][(numcuts+1)-j]= subdivide_edge_addvert(&temp, rad, beauty, percent);
+ }
+ }
+ // Fill with faces
+ for(i=0;i<numcuts+1;i++) {
+ for(j=0;j<numcuts+1;j++) {
+ hold = addfacelist(innerverts[i][j+1],innerverts[i][j],innerverts[i+1][j],innerverts[i+1][j+1],NULL,NULL);
+ hold->e1->f2 = EDGENEW;
+ hold->e2->f2 = EDGENEW;
+ hold->e3->f2 = EDGENEW;
+ hold->e4->f2 = EDGENEW;
+
+ if(i != 0) { hold->e1->f2 |= EDGEINNER; }
+ if(j != 0) { hold->e2->f2 |= EDGEINNER; }
+ if(i != numcuts) { hold->e3->f2 |= EDGEINNER; }
+ if(j != numcuts) { hold->e4->f2 |= EDGEINNER; }
+
+ facecopy(efa,hold);
+ }
+ }
+ // Clean up our dynamic multi-dim array
+ for(i=0;i<numcuts+2;i++) {
+ MEM_freeN(innerverts[i]);
+ }
+ MEM_freeN(innerverts);
+}
+
+static void fill_tri_triple(EditFace *efa, struct GHash *gh, int numcuts, float rad, int beauty)
+{
+ EditVert **verts[3], ***innerverts;
+ short vertsize, i, j;
+ EditFace *hold;
+ EditEdge temp;
+
+ // Point verts[0] and [1] to the array of new verts for cedge[0] and cedge[1]
+ verts[0] = BLI_ghash_lookup(gh, efa->e1);
+ verts[1] = BLI_ghash_lookup(gh, efa->e2);
+ verts[2] = BLI_ghash_lookup(gh, efa->e3);
+
+ //This is the index size of the verts array
+ vertsize = numcuts+2;
+
+ // Is the original v1 the same as the first vert on the selected edge?
+ // if not, the edge is running the opposite direction in this face so flip
+ // the array to the correct direction
+
+ if(verts[0][0] != efa->v1) {flipvertarray(verts[0],numcuts+2);}
+ if(verts[1][0] != efa->v2) {flipvertarray(verts[1],numcuts+2);}
+ if(verts[2][0] != efa->v3) {flipvertarray(verts[2],numcuts+2);}
+ /*
+ We should have something like this now
+ 3
+
+ 3 2 1 0
+ 0|---*---*---|3
+ | /
+ 1 1* *2
+ | /
+ 2* *1 2
+ | /
+ 3|/
+ 0
+
+ we will fill a 2 dim array of editvert*s to make filling easier
+
+ 3
+
+ 0 0---1---2---3---4
+ | / | / |/ | /
+ 1 0---1----2---3
+ 1 | / | / | /
+ 2 0----1---2 2
+ | / | /
+ |/ |/
+ 3 0---1
+ | /
+ |/
+ 4 0
+
+ */
+
+ innerverts = MEM_mallocN(sizeof(EditVert*)*(numcuts+2),"tri-tri subdiv inner verts outer array");
+ for(i=0;i<numcuts+2;i++) {
+ innerverts[i] = MEM_mallocN(sizeof(EditVert*)*((numcuts+2)-i),"tri-tri subdiv inner verts inner array");
+ }
+ //top row is e3 backwards
+ for(i=0;i<numcuts+2;i++) {
+ innerverts[0][i] = verts[2][(numcuts+1)-i];
+ }
+
+ for(i=1;i<=numcuts+1;i++) {
+ //fake edge, first vert is from e1, last is from e2
+ temp.v1= innerverts[i][0] = verts[0][i];
+ temp.v2= innerverts[i][(numcuts+1)-i] = verts[1][(numcuts+1)-i];
+
+ for(j=1;j<(numcuts+1)-i;j++) {
+ float percent= (float)j/(float)((numcuts+1)-i);
+
+ innerverts[i][((numcuts+1)-i)-j]= subdivide_edge_addvert(&temp, rad, beauty, 1-percent);
+ }
+ }
+
+ // Now fill the verts with happy little tris :)
+ for(i=0;i<=numcuts+1;i++) {
+ for(j=0;j<(numcuts+1)-i;j++) {
+ //We always do the first tri
+ hold = addfacelist(innerverts[i][j+1],innerverts[i][j],innerverts[i+1][j],NULL,NULL,NULL);
+ hold->e1->f2 |= EDGENEW;
+ hold->e2->f2 |= EDGENEW;
+ hold->e3->f2 |= EDGENEW;
+ if(i != 0) { hold->e1->f2 |= EDGEINNER; }
+ if(j != 0) { hold->e2->f2 |= EDGEINNER; }
+ if(j+1 != (numcuts+1)-i) {hold->e3->f2 |= EDGEINNER;}
+
+ facecopy(efa,hold);
+ //if there are more to come, we do the 2nd
+ if(j+1 <= numcuts-i) {
+ hold = addfacelist(innerverts[i+1][j],innerverts[i+1][j+1],innerverts[i][j+1],NULL,NULL,NULL);
+ facecopy(efa,hold);
+ hold->e1->f2 |= EDGENEW;
+ hold->e2->f2 |= EDGENEW;
+ hold->e3->f2 |= EDGENEW;
+ }
+ }
+ }
+
+ // Clean up our dynamic multi-dim array
+ for(i=0;i<numcuts+2;i++) {
+ MEM_freeN(innerverts[i]);
+ }
+ MEM_freeN(innerverts);
+}
+
+//Next two fill types are for knife exact only and are provided to allow for knifing through vertices
+//This means there is no multicut!
+static void fill_quad_doublevert(EditFace *efa, int v1, int v2){
+ EditFace *hold;
+ /*
+ Depending on which two vertices have been knifed through (v1 and v2), we
+ triangulate like the patterns below.
+ X-------| |-------X
+ | \ | | / |
+ | \ | | / |
+ | \ | | / |
+ --------X X--------
+ */
+
+ if(v1 == 1 && v2 == 3){
+ hold= addfacelist(efa->v1, efa->v2, efa->v3, 0, efa, NULL);
+ hold->e1->f2 |= EDGENEW;
+ hold->e2->f2 |= EDGENEW;
+ hold->e3->f2 |= EDGENEW;
+ hold->e3->f2 |= EDGEINNER;
+ facecopy(efa, hold);
+
+ hold= addfacelist(efa->v1, efa->v3, efa->v4, 0, efa, NULL);
+ hold->e1->f2 |= EDGENEW;
+ hold->e2->f2 |= EDGENEW;
+ hold->e3->f2 |= EDGENEW;
+ hold->e1->f2 |= EDGEINNER;
+ facecopy(efa, hold);
+ }
+ else{
+ hold= addfacelist(efa->v1, efa->v2, efa->v4, 0, efa, NULL);
+ hold->e1->f2 |= EDGENEW;
+ hold->e2->f2 |= EDGENEW;
+ hold->e3->f2 |= EDGENEW;
+ hold->e2->f2 |= EDGEINNER;
+ facecopy(efa, hold);
+
+ hold= addfacelist(efa->v2, efa->v3, efa->v4, 0, efa, NULL);
+ hold->e1->f2 |= EDGENEW;
+ hold->e2->f2 |= EDGENEW;
+ hold->e3->f2 |= EDGENEW;
+ hold->e3->f2 |= EDGEINNER;
+ facecopy(efa, hold);
+ }
+}
+
+static void fill_quad_singlevert(EditFace *efa, struct GHash *gh)
+{
+ EditEdge *cedge=NULL;
+ EditVert *v[4], **verts;
+ EditFace *hold;
+ short start=0, end, left, right, vertsize;
+
+ v[0] = efa->v1;
+ v[1] = efa->v2;
+ v[2] = efa->v3;
+ v[3] = efa->v4;
+
+ if(efa->e1->f & SELECT) { cedge = efa->e1; start = 0;}
+ else if(efa->e2->f & SELECT) { cedge = efa->e2; start = 1;}
+ else if(efa->e3->f & SELECT) { cedge = efa->e3; start = 2;}
+ else if(efa->e4->f & SELECT) { cedge = efa->e4; start = 3;}
+
+ // Point verts to the array of new verts for cedge
+ verts = BLI_ghash_lookup(gh, cedge);
+ //This is the index size of the verts array
+ vertsize = 3;
+
+ // Is the original v1 the same as the first vert on the selected edge?
+ // if not, the edge is running the opposite direction in this face so flip
+ // the array to the correct direction
+
+ if(verts[0] != v[start]) {flipvertarray(verts,3);}
+ end = (start+1)%4;
+ left = (start+2)%4;
+ right = (start+3)%4;
+
+/*
+ We should have something like this now
+
+ end start
+ 2 1 0
+ |-----*-----|
+ | |
+ | |
+ | |
+ -------------
+ left right
+
+ where start,end,left, right are indexes of EditFace->v1, etc (stored in v)
+ and 0,1,2 are the indexes of the new verts stored in verts. We fill like
+ this, depending on whether its vertex 'left' or vertex 'right' thats
+ been knifed through...
+
+ |---*---| |---*---|
+ | / | | \ |
+ | / | | \ |
+ |/ | | \|
+ X-------- --------X
+*/
+
+ if(v[left]->f1){
+ //triangle is composed of cutvert, end and left
+ hold = addfacelist(verts[1],v[end],v[left],NULL, NULL,NULL);
+ hold->e1->f2 |= EDGENEW;
+ hold->e2->f2 |= EDGENEW;
+ hold->e3->f2 |= EDGENEW;
+ hold->e3->f2 |= EDGEINNER;
+ facecopy(efa, hold);
+
+ //quad is composed of cutvert, left, right and start
+ hold = addfacelist(verts[1],v[left],v[right],v[start], NULL, NULL);
+ hold->e1->f2 |= EDGENEW;
+ hold->e2->f2 |= EDGENEW;
+ hold->e3->f2 |= EDGENEW;
+ hold->e4->f2 |= EDGENEW;
+ hold->e1->f2 |= EDGEINNER;
+ facecopy(efa, hold);
+ }
+ else if(v[right]->f1){
+ //triangle is composed of cutvert, right and start
+ hold = addfacelist(verts[1],v[right],v[start], NULL, NULL, NULL);
+ hold->e1->f2 |= EDGENEW;
+ hold->e2->f2 |= EDGENEW;
+ hold->e3->f2 |= EDGENEW;
+ hold->e1->f2 |= EDGEINNER;
+ facecopy(efa, hold);
+ //quad is composed of cutvert, end, left, right
+ hold = addfacelist(verts[1],v[end], v[left], v[right], NULL, NULL);
+ hold->e1->f2 |= EDGENEW;
+ hold->e2->f2 |= EDGENEW;
+ hold->e3->f2 |= EDGENEW;
+ hold->e4->f2 |= EDGENEW;
+ hold->e4->f2 |= EDGEINNER;
+ facecopy(efa, hold);
+ }
+
+}
+
+// This function takes an example edge, the current point to create and
+// the total # of points to create, then creates the point and return the
+// editvert pointer to it.
+static EditVert *subdivideedgenum(EditEdge *edge, int curpoint, int totpoint, float rad, int beauty)
+{
+ EditVert *ev;
+ float percent;
+
+ if (beauty & (B_PERCENTSUBD) && totpoint == 1)
+ //percent=(float)(edge->tmp.l)/32768.0f;
+ percent= edge->tmp.fp;
+ else
+ percent= (float)curpoint/(float)(totpoint+1);
+
+ ev= subdivide_edge_addvert(edge, rad, beauty, percent);
+ ev->f = edge->v1->f;
+
+ return ev;
+}
+
+void esubdivideflag(int flag, float rad, int beauty, int numcuts, int seltype)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *ef;
+ EditEdge *eed, *cedge, *sort[4];
+ EditVert **templist;
+ struct GHash *gh;
+ float length[4], v1mat[3], v2mat[3], v3mat[3], v4mat[3];
+ int i, j, edgecount, touchcount, facetype,hold;
+
+ if(multires_test()) return;
+
+ //Set faces f1 to 0 cause we need it later
+ for(ef=em->faces.first;ef;ef = ef->next) {
+ ef->f1 = 0;
+ }
+
+ //Flush vertex flags upward to the edges
+ for(eed = em->edges.first;eed;eed = eed->next) {
+ //if(eed->f & flag && eed->v1->f == eed->v2->f) {
+ // eed->f |= eed->v1->f;
+ // }
+ eed->f2 = 0;
+ if(eed->f & flag) {
+ eed->f2 |= EDGEOLD;
+ }
+ }
+
+
+ // We store an array of verts for each edge that is subdivided,
+ // we put this array as a value in a ghash which is keyed by the EditEdge*
+
+ // Now for beauty subdivide deselect edges based on length
+ if(beauty & B_BEAUTY) {
+ for(ef = em->faces.first;ef;ef = ef->next) {
+ if(!ef->v4) {
+ continue;
+ }
+ if(ef->f & SELECT) {
+ VECCOPY(v1mat, ef->v1->co);
+ VECCOPY(v2mat, ef->v2->co);
+ VECCOPY(v3mat, ef->v3->co);
+ VECCOPY(v4mat, ef->v4->co);
+ Mat4Mul3Vecfl(G.obedit->obmat, v1mat);
+ Mat4Mul3Vecfl(G.obedit->obmat, v2mat);
+ Mat4Mul3Vecfl(G.obedit->obmat, v3mat);
+ Mat4Mul3Vecfl(G.obedit->obmat, v4mat);
+
+ length[0] = VecLenf(v1mat, v2mat);
+ length[1] = VecLenf(v2mat, v3mat);
+ length[2] = VecLenf(v3mat, v4mat);
+ length[3] = VecLenf(v4mat, v1mat);
+ sort[0] = ef->e1;
+ sort[1] = ef->e2;
+ sort[2] = ef->e3;
+ sort[3] = ef->e4;
+
+
+ // Beauty Short Edges
+ if(beauty & B_BEAUTY_SHORT) {
+ for(j=0;j<2;j++) {
+ hold = -1;
+ for(i=0;i<4;i++) {
+ if(length[i] < 0) {
+ continue;
+ } else if(hold == -1) {
+ hold = i;
+ } else {
+ if(length[hold] < length[i]) {
+ hold = i;
+ }
+ }
+ }
+ sort[hold]->f &= ~SELECT;
+ sort[hold]->f2 |= EDGENEW;
+ length[hold] = -1;
+ }
+ }
+
+ // Beauty Long Edges
+ else {
+ for(j=0;j<2;j++) {
+ hold = -1;
+ for(i=0;i<4;i++) {
+ if(length[i] < 0) {
+ continue;
+ } else if(hold == -1) {
+ hold = i;
+ } else {
+ if(length[hold] > length[i]) {
+ hold = i;
+ }
+ }
+ }
+ sort[hold]->f &= ~SELECT;
+ sort[hold]->f2 |= EDGENEW;
+ length[hold] = -1;
+ }
+ }
+ }
+ }
+ }
+
+ gh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
+
+ // If we are knifing, We only need the selected edges that were cut, so deselect if it was not cut
+ if(beauty & B_KNIFE) {
+ for(eed= em->edges.first;eed;eed=eed->next) {
+ if( eed->tmp.fp == 0 ) {
+ EM_select_edge(eed,0);
+ }
+ }
+ }
+ // So for each edge, if it is selected, we allocate an array of size cuts+2
+ // so we can have a place for the v1, the new verts and v2
+ for(eed=em->edges.first;eed;eed = eed->next) {
+ if(eed->f & flag) {
+ templist = MEM_mallocN(sizeof(EditVert*)*(numcuts+2),"vertlist");
+ templist[0] = eed->v1;
+ for(i=0;i<numcuts;i++) {
+ // This function creates the new vert and returns it back
+ // to the array
+ templist[i+1] = subdivideedgenum(eed, i+1, numcuts, rad, beauty);
+ //while we are here, we can copy edge info from the original edge
+ cedge = addedgelist(templist[i],templist[i+1],eed);
+ // Also set the edge f2 to EDGENEW so that we can use this info later
+ cedge->f2 = EDGENEW;
+ }
+ templist[i+1] = eed->v2;
+ //Do the last edge too
+ cedge = addedgelist(templist[i],templist[i+1],eed);
+ cedge->f2 = EDGENEW;
+ // Now that the edge is subdivided, we can put its verts in the ghash
+ BLI_ghash_insert(gh, eed, templist);
+ }
+ }
+
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ // Now for each face in the mesh we need to figure out How many edges were cut
+ // and which filling method to use for that face
+ for(ef = em->faces.first;ef;ef = ef->next) {
+ edgecount = 0;
+ facetype = 3;
+ if(ef->e1->f & flag) {edgecount++;}
+ if(ef->e2->f & flag) {edgecount++;}
+ if(ef->e3->f & flag) {edgecount++;}
+ if(ef->v4) {
+ facetype = 4;
+ if(ef->e4->f & flag) {edgecount++;}
+ }
+ if(facetype == 4) {
+ switch(edgecount) {
+ case 0:
+ if(beauty & B_KNIFE && numcuts == 1){
+ /*Test for when knifing through two opposite verts but no edges*/
+ touchcount = 0;
+ if(ef->v1->f1) touchcount++;
+ if(ef->v2->f1) touchcount++;
+ if(ef->v3->f1) touchcount++;
+ if(ef->v4->f1) touchcount++;
+ if(touchcount == 2){
+ if(ef->v1->f1 && ef->v3->f1){
+ ef->f1 = SELECT;
+ fill_quad_doublevert(ef, 1, 3);
+ }
+ else if(ef->v2->f1 && ef->v4->f1){
+ ef->f1 = SELECT;
+ fill_quad_doublevert(ef, 2, 4);
+ }
+ }
+ }
+ break;
+
+ case 1:
+ if(beauty & B_KNIFE && numcuts == 1){
+ /*Test for when knifing through an edge and one vert*/
+ touchcount = 0;
+ if(ef->v1->f1) touchcount++;
+ if(ef->v2->f1) touchcount++;
+ if(ef->v3->f1) touchcount++;
+ if(ef->v4->f1) touchcount++;
+
+ if(touchcount == 1){
+ if( (ef->e1->f & flag && ( !ef->e1->v1->f1 && !ef->e1->v2->f1 )) ||
+ (ef->e2->f & flag && ( !ef->e2->v1->f1 && !ef->e2->v2->f1 )) ||
+ (ef->e3->f & flag && ( !ef->e3->v1->f1 && !ef->e3->v2->f1 )) ||
+ (ef->e4->f & flag && ( !ef->e4->v1->f1 && !ef->e4->v2->f1 )) ){
+
+ ef->f1 = SELECT;
+ fill_quad_singlevert(ef, gh);
+ }
+ else{
+ ef->f1 = SELECT;
+ fill_quad_single(ef, gh, numcuts, seltype);
+ }
+ }
+ else{
+ ef->f1 = SELECT;
+ fill_quad_single(ef, gh, numcuts, seltype);
+ }
+ }
+ else{
+ ef->f1 = SELECT;
+ fill_quad_single(ef, gh, numcuts, seltype);
+ }
+ break;
+ case 2: ef->f1 = SELECT;
+ // if there are 2, we check if edge 1 and 3 are either both on or off that way
+ // we can tell if the selected pair is Adjacent or Opposite of each other
+ if((ef->e1->f & flag && ef->e3->f & flag) ||
+ (ef->e2->f & flag && ef->e4->f & flag)) {
+ fill_quad_double_op(ef, gh, numcuts);
+ }else{
+ switch(G.scene->toolsettings->cornertype) {
+ case 0: fill_quad_double_adj_path(ef, gh, numcuts); break;
+ case 1: fill_quad_double_adj_inner(ef, gh, numcuts); break;
+ case 2: fill_quad_double_adj_fan(ef, gh, numcuts); break;
+ }
+
+ }
+ break;
+ case 3: ef->f1 = SELECT;
+ fill_quad_triple(ef, gh, numcuts);
+ break;
+ case 4: ef->f1 = SELECT;
+ fill_quad_quadruple(ef, gh, numcuts, rad, beauty);
+ break;
+ }
+ } else {
+ switch(edgecount) {
+ case 0: break;
+ case 1: ef->f1 = SELECT;
+ fill_tri_single(ef, gh, numcuts, seltype);
+ break;
+ case 2: ef->f1 = SELECT;
+ fill_tri_double(ef, gh, numcuts);
+ break;
+ case 3: ef->f1 = SELECT;
+ fill_tri_triple(ef, gh, numcuts, rad, beauty);
+ break;
+ }
+ }
+ }
+
+ // Delete Old Edges and Faces
+ for(eed = em->edges.first;eed;eed = eed->next) {
+ if(BLI_ghash_haskey(gh,eed)) {
+ eed->f1 = SELECT;
+ } else {
+ eed->f1 = 0;
+ }
+ }
+ free_tagged_edges_faces(em->edges.first, em->faces.first);
+
+ if(seltype == SUBDIV_SELECT_ORIG && G.qual != LR_CTRLKEY) {
+ for(eed = em->edges.first;eed;eed = eed->next) {
+ if(eed->f2 & EDGENEW || eed->f2 & EDGEOLD) {
+ eed->f |= flag;
+ EM_select_edge(eed,1);
+
+ }else{
+ eed->f &= !flag;
+ EM_select_edge(eed,0);
+ }
+ }
+ } else if ((seltype == SUBDIV_SELECT_INNER || seltype == SUBDIV_SELECT_INNER_SEL)|| G.qual == LR_CTRLKEY) {
+ for(eed = em->edges.first;eed;eed = eed->next) {
+ if(eed->f2 & EDGEINNER) {
+ eed->f |= flag;
+ EM_select_edge(eed,1);
+ if(eed->v1->f & EDGEINNER) eed->v1->f |= SELECT;
+ if(eed->v2->f & EDGEINNER) eed->v2->f |= SELECT;
+ }else{
+ eed->f &= !flag;
+ EM_select_edge(eed,0);
+ }
+ }
+ } else if(seltype == SUBDIV_SELECT_LOOPCUT){
+ for(eed = em->edges.first;eed;eed = eed->next) {
+ if(eed->f2 & DOUBLEOPFILL){
+ eed->f |= flag;
+ EM_select_edge(eed,1);
+ }else{
+ eed->f &= !flag;
+ EM_select_edge(eed,0);
+ }
+ }
+ }
+ if(G.scene->selectmode & SCE_SELECT_VERTEX) {
+ for(eed = em->edges.first;eed;eed = eed->next) {
+ if(eed->f & SELECT) {
+ eed->v1->f |= SELECT;
+ eed->v2->f |= SELECT;
+ }
+ }
+ }
+
+ //fix hide flags for edges. First pass, hide edges of hidden faces
+ for(ef=em->faces.first; ef; ef=ef->next){
+ if(ef->h){
+ ef->e1->h |= 1;
+ ef->e2->h |= 1;
+ ef->e3->h |= 1;
+ if(ef->e4) ef->e4->h |= 1;
+ }
+ }
+ //second pass: unhide edges of visible faces adjacent to hidden faces
+ for(ef=em->faces.first; ef; ef=ef->next){
+ if(ef->h == 0){
+ ef->e1->h &= ~1;
+ ef->e2->h &= ~1;
+ ef->e3->h &= ~1;
+ if(ef->e4) ef->e4->h &= ~1;
+ }
+ }
+
+ // Free the ghash and call MEM_freeN on all the value entries to return
+ // that memory
+ BLI_ghash_free(gh, NULL, (GHashValFreeFP)MEM_freeN);
+
+ EM_selectmode_flush();
+ for(ef=em->faces.first;ef;ef = ef->next) {
+ if(ef->e4) {
+ if( (ef->e1->f & SELECT && ef->e2->f & SELECT) &&
+ (ef->e3->f & SELECT && ef->e4->f & SELECT) ) {
+ ef->f |= SELECT;
+ }
+ } else {
+ if( (ef->e1->f & SELECT && ef->e2->f & SELECT) && ef->e3->f & SELECT) {
+ ef->f |= SELECT;
+ }
+ }
+ }
+
+ recalc_editnormals();
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+}
+
+static int count_selected_edges(EditEdge *ed)
+{
+ int totedge = 0;
+ while(ed) {
+ ed->tmp.p = 0;
+ if( ed->f & SELECT ) totedge++;
+ ed= ed->next;
+ }
+ return totedge;
+}
+
+/* hurms, as if this makes code readable! It's pointerpointer hiding... (ton) */
+typedef EditFace *EVPtr;
+typedef EVPtr EVPTuple[2];
+
+/** builds EVPTuple array efaa of face tuples (in fact pointers to EditFaces)
+ sharing one edge.
+ arguments: selected edge list, face list.
+ Edges will also be tagged accordingly (see eed->f2) */
+
+static int collect_quadedges(EVPTuple *efaa, EditEdge *eed, EditFace *efa)
+{
+ EditEdge *e1, *e2, *e3;
+ EVPtr *evp;
+ int i = 0;
+
+ /* run through edges, if selected, set pointer edge-> facearray */
+ while(eed) {
+ eed->f2= 0;
+ eed->f1= 0;
+ if( eed->f & SELECT ) {
+ eed->tmp.p = (EditVert *) (&efaa[i]);
+ i++;
+ }
+ else eed->tmp.p = NULL;
+
+ eed= eed->next;
+ }
+
+
+ /* find edges pointing to 2 faces by procedure:
+
+ - run through faces and their edges, increase
+ face counter e->f1 for each face
+ */
+
+ while(efa) {
+ efa->f1= 0;
+ if(efa->v4==0 && (efa->f & SELECT)) { /* if selected triangle */
+ e1= efa->e1;
+ e2= efa->e2;
+ e3= efa->e3;
+ if(e1->f2<3 && e1->tmp.p) {
+ if(e1->f2<2) {
+ evp= (EVPtr *) e1->tmp.p;
+ evp[(int)e1->f2] = efa;
+ }
+ e1->f2+= 1;
+ }
+ if(e2->f2<3 && e2->tmp.p) {
+ if(e2->f2<2) {
+ evp= (EVPtr *) e2->tmp.p;
+ evp[(int)e2->f2]= efa;
+ }
+ e2->f2+= 1;
+ }
+ if(e3->f2<3 && e3->tmp.p) {
+ if(e3->f2<2) {
+ evp= (EVPtr *) e3->tmp.p;
+ evp[(int)e3->f2]= efa;
+ }
+ e3->f2+= 1;
+ }
+ }
+ else {
+ /* set to 3 to make sure these are not flipped or joined */
+ efa->e1->f2= 3;
+ efa->e2->f2= 3;
+ efa->e3->f2= 3;
+ if (efa->e4) efa->e4->f2= 3;
+ }
+
+ efa= efa->next;
+ }
+ return i;
+}
+
+
+/* returns vertices of two adjacent triangles forming a quad
+ - can be righthand or lefthand
+
+ 4-----3
+ |\ |
+ | \ 2 | <- efa1
+ | \ |
+ efa-> | 1 \ |
+ | \|
+ 1-----2
+
+*/
+#define VTEST(face, num, other) \
+ (face->v##num != other->v1 && face->v##num != other->v2 && face->v##num != other->v3)
+
+static void givequadverts(EditFace *efa, EditFace *efa1, EditVert **v1, EditVert **v2, EditVert **v3, EditVert **v4, int *vindex)
+{
+ if VTEST(efa, 1, efa1) {
+ *v1= efa->v1;
+ *v2= efa->v2;
+ vindex[0]= 0;
+ vindex[1]= 1;
+ }
+ else if VTEST(efa, 2, efa1) {
+ *v1= efa->v2;
+ *v2= efa->v3;
+ vindex[0]= 1;
+ vindex[1]= 2;
+ }
+ else if VTEST(efa, 3, efa1) {
+ *v1= efa->v3;
+ *v2= efa->v1;
+ vindex[0]= 2;
+ vindex[1]= 0;
+ }
+
+ if VTEST(efa1, 1, efa) {
+ *v3= efa1->v1;
+ *v4= efa1->v2;
+ vindex[2]= 0;
+ vindex[3]= 1;
+ }
+ else if VTEST(efa1, 2, efa) {
+ *v3= efa1->v2;
+ *v4= efa1->v3;
+ vindex[2]= 1;
+ vindex[3]= 2;
+ }
+ else if VTEST(efa1, 3, efa) {
+ *v3= efa1->v3;
+ *v4= efa1->v1;
+ vindex[2]= 2;
+ vindex[3]= 0;
+ }
+ else
+ *v3= *v4= NULL;
+}
+
+/* Helper functions for edge/quad edit features*/
+static void untag_edges(EditFace *f)
+{
+ f->e1->f1 = 0;
+ f->e2->f1 = 0;
+ f->e3->f1 = 0;
+ if (f->e4) f->e4->f1 = 0;
+}
+
+/** remove and free list of tagged edges and faces */
+static void free_tagged_edges_faces(EditEdge *eed, EditFace *efa)
+{
+ EditMesh *em= G.editMesh;
+ EditEdge *nexted;
+ EditFace *nextvl;
+
+ while(efa) {
+ nextvl= efa->next;
+ if(efa->f1) {
+ BLI_remlink(&em->faces, efa);
+ free_editface(efa);
+ }
+ else
+ /* avoid deleting edges that are still in use */
+ untag_edges(efa);
+ efa= nextvl;
+ }
+
+ while(eed) {
+ nexted= eed->next;
+ if(eed->f1) {
+ remedge(eed);
+ free_editedge(eed);
+ }
+ eed= nexted;
+ }
+}
+
+/* note; the EM_selectmode_set() calls here illustrate how badly constructed it all is... from before the
+ edge/face flags, with very mixed results.... */
+void beauty_fill(void)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *v1, *v2, *v3, *v4;
+ EditEdge *eed, *nexted;
+ EditEdge dia1, dia2;
+ EditFace *efa, *w;
+ // void **efaar, **efaa;
+ EVPTuple *efaar;
+ EVPtr *efaa;
+ float len1, len2, len3, len4, len5, len6, opp1, opp2, fac1, fac2;
+ int totedge, ok, notbeauty=8, onedone, vindex[4];
+
+ if(multires_test()) return;
+
+ /* - all selected edges with two faces
+ * - find the faces: store them in edges (using datablock)
+ * - per edge: - test convex
+ * - test edge: flip?
+ * - if true: remedge, addedge, all edges at the edge get new face pointers
+ */
+
+ EM_selectmode_set(); // makes sure in selectmode 'face' the edges of selected faces are selected too
+
+ totedge = count_selected_edges(em->edges.first);
+ if(totedge==0) return;
+
+ /* temp block with face pointers */
+ efaar= (EVPTuple *) MEM_callocN(totedge * sizeof(EVPTuple), "beautyfill");
+
+ while (notbeauty) {
+ notbeauty--;
+
+ ok = collect_quadedges(efaar, em->edges.first, em->faces.first);
+
+ /* there we go */
+ onedone= 0;
+
+ eed= em->edges.first;
+ while(eed) {
+ nexted= eed->next;
+
+ /* f2 is set in collect_quadedges() */
+ if(eed->f2==2 && eed->h==0) {
+
+ efaa = (EVPtr *) eed->tmp.p;
+
+ /* none of the faces should be treated before, nor be part of fgon */
+ ok= 1;
+ efa= efaa[0];
+ if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1) ok= 0;
+ if(efa->fgonf) ok= 0;
+ efa= efaa[1];
+ if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1) ok= 0;
+ if(efa->fgonf) ok= 0;
+
+ if(ok) {
+ /* test convex */
+ givequadverts(efaa[0], efaa[1], &v1, &v2, &v3, &v4, vindex);
+ if(v1 && v2 && v3 && v4) {
+ if( convex(v1->co, v2->co, v3->co, v4->co) ) {
+
+ /* test edges */
+ if( (v1) > (v3) ) {
+ dia1.v1= v3;
+ dia1.v2= v1;
+ }
+ else {
+ dia1.v1= v1;
+ dia1.v2= v3;
+ }
+
+ if( (v2) > (v4) ) {
+ dia2.v1= v4;
+ dia2.v2= v2;
+ }
+ else {
+ dia2.v1= v2;
+ dia2.v2= v4;
+ }
+
+ /* testing rule:
+ * the area divided by the total edge lengths
+ */
+
+ len1= VecLenf(v1->co, v2->co);
+ len2= VecLenf(v2->co, v3->co);
+ len3= VecLenf(v3->co, v4->co);
+ len4= VecLenf(v4->co, v1->co);
+ len5= VecLenf(v1->co, v3->co);
+ len6= VecLenf(v2->co, v4->co);
+
+ opp1= AreaT3Dfl(v1->co, v2->co, v3->co);
+ opp2= AreaT3Dfl(v1->co, v3->co, v4->co);
+
+ fac1= opp1/(len1+len2+len5) + opp2/(len3+len4+len5);
+
+ opp1= AreaT3Dfl(v2->co, v3->co, v4->co);
+ opp2= AreaT3Dfl(v2->co, v4->co, v1->co);
+
+ fac2= opp1/(len2+len3+len6) + opp2/(len4+len1+len6);
+
+ ok= 0;
+ if(fac1 > fac2) {
+ if(dia2.v1==eed->v1 && dia2.v2==eed->v2) {
+ eed->f1= 1;
+ efa= efaa[0];
+ efa->f1= 1;
+ efa= efaa[1];
+ efa->f1= 1;
+
+ w= EM_face_from_faces(efaa[0], efaa[1],
+ vindex[0], vindex[1], 4+vindex[2], -1);
+ w->f |= SELECT;
+
+
+ w= EM_face_from_faces(efaa[0], efaa[1],
+ vindex[0], 4+vindex[2], 4+vindex[3], -1);
+ w->f |= SELECT;
+
+ onedone= 1;
+ }
+ }
+ else if(fac1 < fac2) {
+ if(dia1.v1==eed->v1 && dia1.v2==eed->v2) {
+ eed->f1= 1;
+ efa= efaa[0];
+ efa->f1= 1;
+ efa= efaa[1];
+ efa->f1= 1;
+
+
+ w= EM_face_from_faces(efaa[0], efaa[1],
+ vindex[1], 4+vindex[2], 4+vindex[3], -1);
+ w->f |= SELECT;
+
+
+ w= EM_face_from_faces(efaa[0], efaa[1],
+ vindex[0], 4+vindex[1], 4+vindex[3], -1);
+ w->f |= SELECT;
+
+ onedone= 1;
+ }
+ }
+ }
+ }
+ }
+
+ }
+ eed= nexted;
+ }
+
+ free_tagged_edges_faces(em->edges.first, em->faces.first);
+
+ if(onedone==0) break;
+
+ EM_selectmode_set(); // new edges/faces were added
+ }
+
+ MEM_freeN(efaar);
+
+ EM_select_flush();
+
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+#ifdef WITH_VERSE
+ if(G.editMesh->vnode)
+ sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode);
+#endif
+ BIF_undo_push("Beauty Fill");
+}
+
+
+/* ******************** BEGIN TRIANGLE TO QUAD ************************************* */
+static float measure_facepair(EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4, float limit){
+
+ /*gives a 'weight' to a pair of triangles that join an edge to decide how good a join they would make*/
+ /*Note: this is more complicated than it needs to be and should be cleaned up...*/
+ float measure = 0.0, noA1[3], noA2[3], noB1[3], noB2[3], normalADiff, normalBDiff,
+ edgeVec1[3], edgeVec2[3], edgeVec3[3], edgeVec4[3], diff,
+ minarea, maxarea, areaA, areaB;
+
+ /*First Test: Normal difference*/
+ CalcNormFloat(v1->co, v2->co, v3->co, noA1);
+ CalcNormFloat(v1->co, v3->co, v4->co, noA2);
+
+ if(noA1[0] == noA2[0] && noA1[1] == noA2[1] && noA1[2] == noA2[2]) normalADiff = 0.0;
+ else normalADiff = VecAngle2(noA1, noA2);
+ //if(!normalADiff) normalADiff = 179;
+ CalcNormFloat(v2->co, v3->co, v4->co, noB1);
+ CalcNormFloat(v4->co, v1->co, v2->co, noB2);
+
+ if(noB1[0] == noB2[0] && noB1[1] == noB2[1] && noB1[2] == noB2[2]) normalBDiff = 0.0;
+ else normalBDiff = VecAngle2(noB1, noB2);
+ //if(!normalBDiff) normalBDiff = 179;
+
+ measure += (normalADiff/360) + (normalBDiff/360);
+ if(measure > limit) return measure;
+
+ /*Second test: Colinearity*/
+ VecSubf(edgeVec1, v1->co, v2->co);
+ VecSubf(edgeVec2, v2->co, v3->co);
+ VecSubf(edgeVec3, v3->co, v4->co);
+ VecSubf(edgeVec4, v4->co, v1->co);
+
+ diff = 0.0;
+
+ diff = (
+ fabs(VecAngle2(edgeVec1, edgeVec2) - 90) +
+ fabs(VecAngle2(edgeVec2, edgeVec3) - 90) +
+ fabs(VecAngle2(edgeVec3, edgeVec4) - 90) +
+ fabs(VecAngle2(edgeVec4, edgeVec1) - 90)) / 360;
+ if(!diff) return 0.0;
+
+ measure += diff;
+ if(measure > limit) return measure;
+
+ /*Third test: Concavity*/
+ areaA = AreaT3Dfl(v1->co, v2->co, v3->co) + AreaT3Dfl(v1->co, v3->co, v4->co);
+ areaB = AreaT3Dfl(v2->co, v3->co, v4->co) + AreaT3Dfl(v4->co, v1->co, v2->co);
+
+ if(areaA <= areaB) minarea = areaA;
+ else minarea = areaB;
+
+ if(areaA >= areaB) maxarea = areaA;
+ else maxarea = areaB;
+
+ if(!maxarea) measure += 1;
+ else measure += (1 - (minarea / maxarea));
+
+ return measure;
+}
+
+#define T2QUV_LIMIT 0.005
+#define T2QCOL_LIMIT 3
+static int compareFaceAttribs(EditFace *f1, EditFace *f2, EditEdge *eed)
+{
+ /*Test to see if the per-face attributes for the joining edge match within limit*/
+ MTFace *tf1, *tf2;
+ unsigned int *col1, *col2;
+ short i,attrok=0, flag = G.scene->toolsettings->editbutflag, fe1[2], fe2[2];
+
+ tf1 = CustomData_em_get(&G.editMesh->fdata, f1->data, CD_MTFACE);
+ tf2 = CustomData_em_get(&G.editMesh->fdata, f2->data, CD_MTFACE);
+
+ col1 = CustomData_em_get(&G.editMesh->fdata, f1->data, CD_MCOL);
+ col2 = CustomData_em_get(&G.editMesh->fdata, f2->data, CD_MCOL);
+
+ /*store indices for faceedges*/
+ f1->v1->f1 = 0;
+ f1->v2->f1 = 1;
+ f1->v3->f1 = 2;
+
+ fe1[0] = eed->v1->f1;
+ fe1[1] = eed->v2->f1;
+
+ f2->v1->f1 = 0;
+ f2->v2->f1 = 1;
+ f2->v3->f1 = 2;
+
+ fe2[0] = eed->v1->f1;
+ fe2[1] = eed->v2->f1;
+
+ /*compare faceedges for each face attribute. Additional per face attributes can be added later*/
+ /*do UVs*/
+ if(flag & B_JOINTRIA_UV){
+
+ if(tf1 == NULL || tf2 == NULL) attrok |= B_JOINTRIA_UV;
+ else if(tf1->tpage != tf2->tpage); /*do nothing*/
+ else{
+ for(i = 0; i < 2; i++){
+ if(tf1->uv[fe1[i]][0] + T2QUV_LIMIT > tf2->uv[fe2[i]][0] && tf1->uv[fe1[i]][0] - T2QUV_LIMIT < tf2->uv[fe2[i]][0] &&
+ tf1->uv[fe1[i]][1] + T2QUV_LIMIT > tf2->uv[fe2[i]][1] && tf1->uv[fe1[i]][1] - T2QUV_LIMIT < tf2->uv[fe2[i]][1]) attrok |= B_JOINTRIA_UV;
+ }
+ }
+ }
+
+ /*do VCOLs*/
+ if(flag & B_JOINTRIA_VCOL){
+ if(!col1 || !col2) attrok |= B_JOINTRIA_VCOL;
+ else{
+ char *f1vcol, *f2vcol;
+ for(i = 0; i < 2; i++){
+ f1vcol = (char *)&(col1[fe1[i]]);
+ f2vcol = (char *)&(col2[fe2[i]]);
+
+ /*compare f1vcol with f2vcol*/
+ if( f1vcol[1] + T2QCOL_LIMIT > f2vcol[1] && f1vcol[1] - T2QCOL_LIMIT < f2vcol[1] &&
+ f1vcol[2] + T2QCOL_LIMIT > f2vcol[2] && f1vcol[2] - T2QCOL_LIMIT < f2vcol[2] &&
+ f1vcol[3] + T2QCOL_LIMIT > f2vcol[3] && f1vcol[3] - T2QCOL_LIMIT < f2vcol[3]) attrok |= B_JOINTRIA_VCOL;
+ }
+ }
+ }
+
+ if( ((attrok & B_JOINTRIA_UV) == (flag & B_JOINTRIA_UV)) && ((attrok & B_JOINTRIA_VCOL) == (flag & B_JOINTRIA_VCOL)) ) return 1;
+ return 0;
+}
+
+static int fplcmp(const void *v1, const void *v2)
+{
+ const EditEdge *e1= *((EditEdge**)v1), *e2=*((EditEdge**)v2);
+
+ if( e1->crease > e2->crease) return 1;
+ else if( e1->crease < e2->crease) return -1;
+
+ return 0;
+}
+
+/*Bitflags for edges.*/
+#define T2QDELETE 1
+#define T2QCOMPLEX 2
+#define T2QJOIN 4
+void join_triangles(void)
+{
+ EditMesh *em=G.editMesh;
+ EditVert *v1, *v2, *v3, *v4, *eve;
+ EditEdge *eed, **edsortblock = NULL, **edb = NULL;
+ EditFace *efa;
+ EVPTuple *efaar = NULL;
+ EVPtr *efaa = NULL;
+ float *creases = NULL;
+ float measure; /*Used to set tolerance*/
+ float limit = G.scene->toolsettings->jointrilimit;
+ int i, ok, totedge=0, totseledge=0, complexedges, vindex[4];
+
+ /*test for multi-resolution data*/
+ if(multires_test()) return;
+
+ /*if we take a long time on very dense meshes we want waitcursor to display*/
+ waitcursor(1);
+
+ totseledge = count_selected_edges(em->edges.first);
+ if(totseledge==0) return;
+
+ /*abusing crease value to store weights for edge pairs. Nasty*/
+ for(eed=em->edges.first; eed; eed=eed->next) totedge++;
+ if(totedge) creases = MEM_callocN(sizeof(float) * totedge, "Join Triangles Crease Array");
+ for(eed=em->edges.first, i = 0; eed; eed=eed->next, i++){
+ creases[i] = eed->crease;
+ eed->crease = 0.0;
+ }
+
+ /*clear temp flags*/
+ for(eve=em->verts.first; eve; eve=eve->next) eve->f1 = eve->f2 = 0;
+ for(eed=em->edges.first; eed; eed=eed->next) eed->f2 = eed->f1 = 0;
+ for(efa=em->faces.first; efa; efa=efa->next) efa->f1 = efa->tmp.l = 0;
+
+ /*For every selected 2 manifold edge, create pointers to its two faces.*/
+ efaar= (EVPTuple *) MEM_callocN(totseledge * sizeof(EVPTuple), "Tri2Quad");
+ ok = collect_quadedges(efaar, em->edges.first, em->faces.first);
+ complexedges = 0;
+
+ if(ok){
+
+
+ /*clear tmp.l flag and store number of faces that are selected and coincident to current face here.*/
+ for(eed=em->edges.first; eed; eed=eed->next){
+ /* eed->f2 is 2 only if this edge is part of exactly two
+ triangles, and both are selected, and it has EVPTuple assigned */
+ if(eed->f2 == 2){
+ efaa= (EVPtr *) eed->tmp.p;
+ efaa[0]->tmp.l++;
+ efaa[1]->tmp.l++;
+ }
+ }
+
+ for(eed=em->edges.first; eed; eed=eed->next){
+ if(eed->f2 == 2){
+ efaa= (EVPtr *) eed->tmp.p;
+ v1 = v2 = v3 = v4 = NULL;
+ givequadverts(efaa[0], efaa[1], &v1, &v2, &v3, &v4, vindex);
+ if(v1 && v2 && v3 && v4){
+ /*test if simple island first. This mimics 2.42 behaviour and the tests are less restrictive.*/
+ if(efaa[0]->tmp.l == 1 && efaa[1]->tmp.l == 1){
+ if( convex(v1->co, v2->co, v3->co, v4->co) ){
+ eed->f1 |= T2QJOIN;
+ efaa[0]->f1 = 1; //mark for join
+ efaa[1]->f1 = 1; //mark for join
+ }
+ }
+ else{
+
+ /* The face pair is part of a 'complex' island, so the rules for dealing with it are more involved.
+ Depending on what options the user has chosen, this face pair can be 'thrown out' based upon the following criteria:
+
+ 1: the two faces do not share the same material
+ 2: the edge joining the two faces is marked as sharp.
+ 3: the two faces UV's do not make a good match
+ 4: the two faces Vertex colors do not make a good match
+
+ If the face pair passes all the applicable tests, it is then given a 'weight' with the measure_facepair() function.
+ This measures things like concavity, colinearity ect. If this weight is below the threshold set by the user
+ the edge joining them is marked as being 'complex' and will be compared against other possible pairs which contain one of the
+ same faces in the current pair later.
+
+ This technique is based upon an algorithm that Campbell Barton developed for his Tri2Quad script that was previously part of
+ the python scripts bundled with Blender releases.
+ */
+
+ if(G.scene->toolsettings->editbutflag & B_JOINTRIA_SHARP && eed->sharp); /*do nothing*/
+ else if(G.scene->toolsettings->editbutflag & B_JOINTRIA_MAT && efaa[0]->mat_nr != efaa[1]->mat_nr); /*do nothing*/
+ else if(((G.scene->toolsettings->editbutflag & B_JOINTRIA_UV) || (G.scene->toolsettings->editbutflag & B_JOINTRIA_VCOL)) &&
+ compareFaceAttribs(efaa[0], efaa[1], eed) == 0); /*do nothing*/
+ else{
+ measure = measure_facepair(v1, v2, v3, v4, limit);
+ if(measure < limit){
+ complexedges++;
+ eed->f1 |= T2QCOMPLEX;
+ eed->crease = measure; /*we dont mark edges for join yet*/
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /*Quicksort the complex edges according to their weighting*/
+ if(complexedges){
+ edsortblock = edb = MEM_callocN(sizeof(EditEdge*) * complexedges, "Face Pairs quicksort Array");
+ for(eed = em->edges.first; eed; eed=eed->next){
+ if(eed->f1 & T2QCOMPLEX){
+ *edb = eed;
+ edb++;
+ }
+ }
+ qsort(edsortblock, complexedges, sizeof(EditEdge*), fplcmp);
+ /*now go through and mark the edges who get the highest weighting*/
+ for(edb=edsortblock, i=0; i < complexedges; edb++, i++){
+ efaa = (EVPtr *)((*edb)->tmp.p); /*suspect!*/
+ if( !efaa[0]->f1 && !efaa[1]->f1){
+ efaa[0]->f1 = 1; //mark for join
+ efaa[1]->f1 = 1; //mark for join
+ (*edb)->f1 |= T2QJOIN;
+ }
+ }
+ }
+
+ /*finally go through all edges marked for join (simple and complex) and create new faces*/
+ for(eed=em->edges.first; eed; eed=eed->next){
+ if(eed->f1 & T2QJOIN){
+ efaa= (EVPtr *)eed->tmp.p;
+ v1 = v2 = v3 = v4 = NULL;
+ givequadverts(efaa[0], efaa[1], &v1, &v2, &v3, &v4, vindex);
+ if((v1 && v2 && v3 && v4) && (exist_face(v1, v2, v3, v4)==0)){ /*exist_face is very slow! Needs to be adressed.*/
+ /*flag for delete*/
+ eed->f1 |= T2QDELETE;
+ /*create new quad and select*/
+ efa = EM_face_from_faces(efaa[0], efaa[1], vindex[0], vindex[1], 4+vindex[2], 4+vindex[3]);
+ EM_select_face(efa,1);
+ }
+ else{
+ efaa[0]->f1 = 0;
+ efaa[1]->f1 = 0;
+ }
+ }
+ }
+ }
+
+ /*free data and cleanup*/
+ if(creases){
+ for(eed=em->edges.first, i = 0; eed; eed=eed->next, i++) eed->crease = creases[i];
+ MEM_freeN(creases);
+ }
+ for(eed=em->edges.first; eed; eed=eed->next){
+ if(eed->f1 & T2QDELETE) eed->f1 = 1;
+ else eed->f1 = 0;
+ }
+ free_tagged_edges_faces(em->edges.first, em->faces.first);
+ if(efaar) MEM_freeN(efaar);
+ if(edsortblock) MEM_freeN(edsortblock);
+
+ EM_selectmode_flush();
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ #ifdef WITH_VERSE
+ if(G.editMesh->vnode)
+ sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode);
+ #endif
+ waitcursor(0);
+ BIF_undo_push("Convert Triangles to Quads");
+}
+/* ******************** END TRIANGLE TO QUAD ************************************* */
+
+#define FACE_MARKCLEAR(f) (f->f1 = 1)
+
+/* quick hack, basically a copy of beauty_fill */
+void edge_flip(void)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *v1, *v2, *v3, *v4;
+ EditEdge *eed, *nexted;
+ EditFace *efa, *w;
+ //void **efaar, **efaa;
+ EVPTuple *efaar;
+ EVPtr *efaa;
+ int totedge, ok, vindex[4];
+
+ /* - all selected edges with two faces
+ * - find the faces: store them in edges (using datablock)
+ * - per edge: - test convex
+ * - test edge: flip?
+ - if true: remedge, addedge, all edges at the edge get new face pointers
+ */
+
+ EM_selectmode_flush(); // makes sure in selectmode 'face' the edges of selected faces are selected too
+
+ totedge = count_selected_edges(em->edges.first);
+ if(totedge==0) return;
+
+ /* temporary array for : edge -> face[1], face[2] */
+ efaar= (EVPTuple *) MEM_callocN(totedge * sizeof(EVPTuple), "edgeflip");
+
+ ok = collect_quadedges(efaar, em->edges.first, em->faces.first);
+
+ eed= em->edges.first;
+ while(eed) {
+ nexted= eed->next;
+
+ if(eed->f2==2) { /* points to 2 faces */
+
+ efaa= (EVPtr *) eed->tmp.p;
+
+ /* don't do it if flagged */
+
+ ok= 1;
+ efa= efaa[0];
+ if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1) ok= 0;
+ efa= efaa[1];
+ if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1) ok= 0;
+
+ if(ok) {
+ /* test convex */
+ givequadverts(efaa[0], efaa[1], &v1, &v2, &v3, &v4, vindex);
+
+/*
+ 4-----3 4-----3
+ |\ | | /|
+ | \ 1 | | 1 / |
+ | \ | -> | / |
+ | 0 \ | | / 0 |
+ | \| |/ |
+ 1-----2 1-----2
+*/
+ /* make new faces */
+ if (v1 && v2 && v3) {
+ if( convex(v1->co, v2->co, v3->co, v4->co) ) {
+ if(exist_face(v1, v2, v3, v4)==0) {
+ /* outch this may break seams */
+ w= EM_face_from_faces(efaa[0], efaa[1], vindex[0],
+ vindex[1], 4+vindex[2], -1);
+
+ EM_select_face(w, 1);
+
+ /* outch this may break seams */
+ w= EM_face_from_faces(efaa[0], efaa[1], vindex[0],
+ 4+vindex[2], 4+vindex[3], -1);
+
+ EM_select_face(w, 1);
+ }
+ /* tag as to-be-removed */
+ FACE_MARKCLEAR(efaa[1]);
+ FACE_MARKCLEAR(efaa[0]);
+ eed->f1 = 1;
+
+ } /* endif test convex */
+ }
+ }
+ }
+ eed= nexted;
+ }
+
+ /* clear tagged edges and faces: */
+ free_tagged_edges_faces(em->edges.first, em->faces.first);
+
+ MEM_freeN(efaar);
+
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+#ifdef WITH_VERSE
+ if(G.editMesh->vnode)
+ sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode);
+#endif
+ BIF_undo_push("Flip Triangle Edges");
+
+}
+
+static void edge_rotate(EditEdge *eed,int dir)
+{
+ EditMesh *em = G.editMesh;
+ EditVert **verts[2];
+ EditFace *face[2], *efa, *newFace[2];
+ EditEdge **edges[2], **hiddenedges, *srchedge;
+ int facecount, p1, p2, p3, p4, fac1, fac2, i, j;
+ int numhidden, numshared, p[2][4];
+
+ /* check to make sure that the edge is only part of 2 faces */
+ facecount = 0;
+ for(efa = em->faces.first;efa;efa = efa->next) {
+ if((efa->e1 == eed || efa->e2 == eed) || (efa->e3 == eed || efa->e4 == eed)) {
+ if(facecount >= 2) {
+ /* more than two faces with this edge */
+ return;
+ }
+ else {
+ face[facecount] = efa;
+ facecount++;
+ }
+ }
+ }
+
+ if(facecount < 2)
+ return;
+
+ /* how many edges does each face have */
+ if(face[0]->e4) fac1= 4;
+ else fac1= 3;
+
+ if(face[1]->e4) fac2= 4;
+ else fac2= 3;
+
+ /* make a handy array for verts and edges */
+ verts[0]= &face[0]->v1;
+ edges[0]= &face[0]->e1;
+ verts[1]= &face[1]->v1;
+ edges[1]= &face[1]->e1;
+
+ /* we don't want to rotate edges between faces that share more than one edge */
+ numshared= 0;
+ for(i=0; i<fac1; i++)
+ for(j=0; j<fac2; j++)
+ if (edges[0][i] == edges[1][j])
+ numshared++;
+
+ if(numshared > 1)
+ return;
+
+ /* coplaner faces only please */
+ if(Inpf(face[0]->n,face[1]->n) <= 0.000001)
+ return;
+
+ /* we want to construct an array of vertex indicis in both faces, starting at
+ the last vertex of the edge being rotated.
+ - first we find the two vertices that lie on the rotating edge
+ - then we make sure they are ordered according to the face vertex order
+ - and then we construct the array */
+ p1= p2= p3= p4= 0;
+
+ for(i=0; i<4; i++) {
+ if(eed->v1 == verts[0][i]) p1 = i;
+ if(eed->v2 == verts[0][i]) p2 = i;
+ if(eed->v1 == verts[1][i]) p3 = i;
+ if(eed->v2 == verts[1][i]) p4 = i;
+ }
+
+ if((p1+1)%fac1 == p2)
+ SWAP(int, p1, p2);
+ if((p3+1)%fac2 == p4)
+ SWAP(int, p3, p4);
+
+ for (i = 0; i < 4; i++) {
+ p[0][i]= (p1 + i)%fac1;
+ p[1][i]= (p3 + i)%fac2;
+ }
+
+ /* create an Array of the Edges who have h set prior to rotate */
+ numhidden = 0;
+ for(srchedge = em->edges.first;srchedge;srchedge = srchedge->next)
+ if(srchedge->h && ((srchedge->v1->f & SELECT) || (srchedge->v2->f & SELECT)))
+ numhidden++;
+
+ hiddenedges = MEM_mallocN(sizeof(EditVert*)*numhidden+1, "RotateEdgeHiddenVerts");
+ if(!hiddenedges) {
+ error("Malloc Was not happy!");
+ return;
+ }
+
+ numhidden = 0;
+ for(srchedge=em->edges.first; srchedge; srchedge=srchedge->next)
+ if(srchedge->h && (srchedge->v1->f & SELECT || srchedge->v2->f & SELECT))
+ hiddenedges[numhidden++] = srchedge;
+
+ /* create the 2 new faces */
+ if(fac1 == 3 && fac2 == 3) {
+ /* no need of reverse setup */
+
+ newFace[0]= EM_face_from_faces(face[0], face[1], p[0][1], p[0][2], 4+p[1][1], -1);
+ newFace[1]= EM_face_from_faces(face[1], face[0], p[1][1], p[1][2], 4+p[0][1], -1);
+ }
+ else if(fac1 == 4 && fac2 == 3) {
+ if(dir == 1) {
+ newFace[0]= EM_face_from_faces(face[0], face[1], p[0][1], p[0][2], p[0][3], 4+p[1][1]);
+ newFace[1]= EM_face_from_faces(face[1], face[0], p[1][1], p[1][2], 4+p[0][1], -1);
+ } else if (dir == 2) {
+ newFace[0]= EM_face_from_faces(face[0], face[1], p[0][2], 4+p[1][1], p[0][0], p[0][1]);
+ newFace[1]= EM_face_from_faces(face[1], face[0], 4+p[0][2], p[1][0], p[1][1], -1);
+
+ verts[0][p[0][2]]->f |= SELECT;
+ verts[1][p[1][1]]->f |= SELECT;
+ }
+ }
+ else if(fac1 == 3 && fac2 == 4) {
+ if(dir == 1) {
+ newFace[0]= EM_face_from_faces(face[0], face[1], p[0][1], p[0][2], 4+p[1][1], -1);
+ newFace[1]= EM_face_from_faces(face[1], face[0], p[1][1], p[1][2], p[1][3], 4+p[0][1]);
+ } else if (dir == 2) {
+ newFace[0]= EM_face_from_faces(face[0], face[1], p[0][0], p[0][1], 4+p[1][2], -1);
+ newFace[1]= EM_face_from_faces(face[1], face[0], p[1][1], p[1][2], 4+p[0][1], 4+p[0][2]);
+
+ verts[0][p[0][1]]->f |= SELECT;
+ verts[1][p[1][2]]->f |= SELECT;
+ }
+
+ }
+ else if(fac1 == 4 && fac2 == 4) {
+ if(dir == 1) {
+ newFace[0]= EM_face_from_faces(face[0], face[1], p[0][1], p[0][2], p[0][3], 4+p[1][1]);
+ newFace[1]= EM_face_from_faces(face[1], face[0], p[1][1], p[1][2], p[1][3], 4+p[0][1]);
+ } else if (dir == 2) {
+ newFace[0]= EM_face_from_faces(face[0], face[1], p[0][2], p[0][3], 4+p[1][1], 4+p[1][2]);
+ newFace[1]= EM_face_from_faces(face[1], face[0], p[1][2], p[1][3], 4+p[0][1], 4+p[0][2]);
+
+ verts[0][p[0][2]]->f |= SELECT;
+ verts[1][p[1][2]]->f |= SELECT;
+ }
+ }
+ else
+ return; /* This should never happen */
+
+ if(dir == 1 || (fac1 == 3 && fac2 == 3)) {
+ verts[0][p[0][1]]->f |= SELECT;
+ verts[1][p[1][1]]->f |= SELECT;
+ }
+
+ /* copy old edge's flags to new center edge*/
+ for(srchedge=em->edges.first;srchedge;srchedge=srchedge->next) {
+ if((srchedge->v1->f & SELECT) && (srchedge->v2->f & SELECT)) {
+ srchedge->f = eed->f;
+ srchedge->h = eed->h;
+ srchedge->dir = eed->dir;
+ srchedge->seam = eed->seam;
+ srchedge->crease = eed->crease;
+ }
+ }
+
+ /* resetting hidden flag */
+ for(numhidden--; numhidden>=0; numhidden--)
+ hiddenedges[numhidden]->h= 1;
+
+ /* check for orhphan edges */
+ for(srchedge=em->edges.first; srchedge; srchedge=srchedge->next)
+ srchedge->f1= -1;
+
+ /* cleanup */
+ MEM_freeN(hiddenedges);
+
+ /* get rid of the old edge and faces*/
+ remedge(eed);
+ free_editedge(eed);
+ BLI_remlink(&em->faces, face[0]);
+ free_editface(face[0]);
+ BLI_remlink(&em->faces, face[1]);
+ free_editface(face[1]);
+}
+
+/* only accepts 1 selected edge, or 2 selected faces */
+void edge_rotate_selected(int dir)
+{
+ EditEdge *eed;
+ EditFace *efa;
+ short edgeCount = 0;
+
+ /*clear new flag for new edges, count selected edges */
+ for(eed= G.editMesh->edges.first; eed; eed= eed->next) {
+ eed->f1= 0;
+ eed->f2 &= ~2;
+ if(eed->f & SELECT) edgeCount++;
+ }
+
+ if(edgeCount>1) {
+ /* more selected edges, check faces */
+ for(efa= G.editMesh->faces.first; efa; efa= efa->next) {
+ if(efa->f & SELECT) {
+ efa->e1->f1++;
+ efa->e2->f1++;
+ efa->e3->f1++;
+ if(efa->e4) efa->e4->f1++;
+ }
+ }
+ edgeCount= 0;
+ for(eed= G.editMesh->edges.first; eed; eed= eed->next) {
+ if(eed->f1==2) edgeCount++;
+ }
+ if(edgeCount==1) {
+ for(eed= G.editMesh->edges.first; eed; eed= eed->next) {
+ if(eed->f1==2) {
+ edge_rotate(eed,dir);
+ break;
+ }
+ }
+ }
+ else error("Select one edge or two adjacent faces");
+ }
+ else if(edgeCount==1) {
+ for(eed= G.editMesh->edges.first; eed; eed= eed->next) {
+ if(eed->f & SELECT) {
+ EM_select_edge(eed, 0);
+ edge_rotate(eed,dir);
+ break;
+ }
+ }
+ }
+ else error("Select one edge or two adjacent faces");
+
+
+ /* flush selected vertices (again) to edges/faces */
+ EM_select_flush();
+
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+
+#ifdef WITH_VERSE
+ if(G.editMesh->vnode)
+ sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode);
+#endif
+
+ BIF_undo_push("Rotate Edge");
+}
+
+/******************* BEVEL CODE STARTS HERE ********************/
+
+static void bevel_displace_vec(float *midvec, float *v1, float *v2, float *v3, float d, float no[3])
+{
+ float a[3], c[3], n_a[3], n_c[3], mid[3], ac, ac2, fac;
+
+ VecSubf(a, v1, v2);
+ VecSubf(c, v3, v2);
+
+ Crossf(n_a, a, no);
+ Normalize(n_a);
+ Crossf(n_c, no, c);
+ Normalize(n_c);
+
+ Normalize(a);
+ Normalize(c);
+ ac = Inpf(a, c);
+
+ if (ac == 1 || ac == -1) {
+ midvec[0] = midvec[1] = midvec[2] = 0;
+ return;
+ }
+ ac2 = ac * ac;
+ fac = (float)sqrt((ac2 + 2*ac + 1)/(1 - ac2) + 1);
+ VecAddf(mid, n_c, n_a);
+ Normalize(mid);
+ VecMulf(mid, d * fac);
+ VecAddf(mid, mid, v2);
+ VecCopyf(midvec, mid);
+}
+
+/* Finds the new point using the sinus law to extrapolate a triangle
+ Lots of sqrts which would not be good for a real time algo
+ Using the mid point of the extrapolation of both sides
+ Useless for coplanar quads, but that doesn't happen too often */
+static void fix_bevel_wrap(float *midvec, float *v1, float *v2, float *v3, float *v4, float d, float no[3])
+{
+ float a[3], b[3], c[3], l_a, l_b, l_c, s_a, s_b, s_c, Pos1[3], Pos2[3], Dir[3];
+
+ VecSubf(a, v3, v2);
+ l_a = Normalize(a);
+ VecSubf(b, v4, v3);
+ Normalize(b);
+ VecSubf(c, v1, v2);
+ Normalize(c);
+
+ s_b = Inpf(a, c);
+ s_b = (float)sqrt(1 - (s_b * s_b));
+ s_a = Inpf(b, c);
+ s_a = (float)sqrt(1 - (s_a * s_a));
+ VecMulf(a, -1);
+ s_c = Inpf(a, b);
+ s_c = (float)sqrt(1 - (s_c * s_c));
+
+ l_b = s_b * l_a / s_a;
+ l_c = s_c * l_a / s_a;
+
+ VecMulf(b, l_b);
+ VecMulf(c, l_c);
+
+ VecAddf(Pos1, v2, c);
+ VecAddf(Pos2, v3, b);
+
+ VecAddf(Dir, Pos1, Pos2);
+ VecMulf(Dir, 0.5);
+
+ bevel_displace_vec(midvec, v3, Dir, v2, d, no);
+
+}
+
+
+static char detect_wrap(float *o_v1, float *o_v2, float *v1, float *v2, float *no)
+{
+ float o_a[3], a[3], o_c[3], c[3];
+
+ VecSubf(o_a, o_v1, o_v2);
+ VecSubf(a, v1, v2);
+
+ Crossf(o_c, o_a, no);
+ Crossf(c, a, no);
+
+ if (Inpf(c, o_c) <= 0)
+ return 1;
+ else
+ return 0;
+}
+
+// Detects and fix a quad wrapping after the resize
+// Arguments are the orginal verts followed by the final verts and then the bevel size and the normal
+static void fix_bevel_quad_wrap(float *o_v1, float *o_v2, float *o_v3, float *o_v4, float *v1, float *v2, float *v3, float *v4, float d, float *no)
+{
+ float vec[3];
+ char wrap[4];
+
+ // Quads can wrap partially. Watch out
+ wrap[0] = detect_wrap(o_v1, o_v2, v1, v2, no); // Edge 1-2
+ wrap[1] = detect_wrap(o_v2, o_v3, v2, v3, no); // Edge 2-3
+ wrap[2] = detect_wrap(o_v3, o_v4, v3, v4, no); // Edge 3-4
+ wrap[3] = detect_wrap(o_v4, o_v1, v4, v1, no); // Edge 4-1
+
+ // Edge 1 inverted
+ if (wrap[0] == 1 && wrap[1] == 0 && wrap[2] == 0 && wrap[3] == 0) {
+ fix_bevel_wrap(vec, o_v2, o_v3, o_v4, o_v1, d, no);
+ VECCOPY(v1, vec);
+ VECCOPY(v2, vec);
+ }
+ // Edge 2 inverted
+ else if (wrap[0] == 0 && wrap[1] == 1 && wrap[2] == 0 && wrap[3] == 0) {
+ fix_bevel_wrap(vec, o_v3, o_v4, o_v1, o_v2, d, no);
+ VECCOPY(v2, vec);
+ VECCOPY(v3, vec);
+ }
+ // Edge 3 inverted
+ else if (wrap[0] == 0 && wrap[1] == 0 && wrap[2] == 1 && wrap[3] == 0) {
+ fix_bevel_wrap(vec, o_v4, o_v1, o_v2, o_v3, d, no);
+ VECCOPY(v3, vec);
+ VECCOPY(v4, vec);
+ }
+ // Edge 4 inverted
+ else if (wrap[0] == 0 && wrap[1] == 0 && wrap[2] == 0 && wrap[3] == 1) {
+ fix_bevel_wrap(vec, o_v1, o_v2, o_v3, o_v4, d, no);
+ VECCOPY(v4, vec);
+ VECCOPY(v1, vec);
+ }
+ // Edge 2 and 4 inverted
+ else if (wrap[0] == 0 && wrap[1] == 1 && wrap[2] == 0 && wrap[3] == 1) {
+ VecAddf(vec, v2, v3);
+ VecMulf(vec, 0.5);
+ VECCOPY(v2, vec);
+ VECCOPY(v3, vec);
+ VecAddf(vec, v1, v4);
+ VecMulf(vec, 0.5);
+ VECCOPY(v1, vec);
+ VECCOPY(v4, vec);
+ }
+ // Edge 1 and 3 inverted
+ else if (wrap[0] == 1 && wrap[1] == 0 && wrap[2] == 1 && wrap[3] == 0) {
+ VecAddf(vec, v1, v2);
+ VecMulf(vec, 0.5);
+ VECCOPY(v1, vec);
+ VECCOPY(v2, vec);
+ VecAddf(vec, v3, v4);
+ VecMulf(vec, 0.5);
+ VECCOPY(v3, vec);
+ VECCOPY(v4, vec);
+ }
+ // Totally inverted
+ else if (wrap[0] == 1 && wrap[1] == 1 && wrap[2] == 1 && wrap[3] == 1) {
+ VecAddf(vec, v1, v2);
+ VecAddf(vec, vec, v3);
+ VecAddf(vec, vec, v4);
+ VecMulf(vec, 0.25);
+ VECCOPY(v1, vec);
+ VECCOPY(v2, vec);
+ VECCOPY(v3, vec);
+ VECCOPY(v4, vec);
+ }
+
+}
+
+// Detects and fix a tri wrapping after the resize
+// Arguments are the orginal verts followed by the final verts and the normal
+// Triangles cannot wrap partially (not in this situation
+static void fix_bevel_tri_wrap(float *o_v1, float *o_v2, float *o_v3, float *v1, float *v2, float *v3, float *no)
+{
+ if (detect_wrap(o_v1, o_v2, v1, v2, no)) {
+ float vec[3];
+ VecAddf(vec, o_v1, o_v2);
+ VecAddf(vec, vec, o_v3);
+ VecMulf(vec, 1.0f/3.0f);
+ VECCOPY(v1, vec);
+ VECCOPY(v2, vec);
+ VECCOPY(v3, vec);
+ }
+}
+
+static void bevel_shrink_faces(float d, int flag)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+ float vec[3], no[3], v1[3], v2[3], v3[3], v4[3];
+
+ /* move edges of all faces with efa->f1 & flag closer towards their centers */
+ efa= em->faces.first;
+ while (efa) {
+ if (efa->f1 & flag) {
+ VECCOPY(v1, efa->v1->co);
+ VECCOPY(v2, efa->v2->co);
+ VECCOPY(v3, efa->v3->co);
+ VECCOPY(no, efa->n);
+ if (efa->v4 == NULL) {
+ bevel_displace_vec(vec, v1, v2, v3, d, no);
+ VECCOPY(efa->v2->co, vec);
+ bevel_displace_vec(vec, v2, v3, v1, d, no);
+ VECCOPY(efa->v3->co, vec);
+ bevel_displace_vec(vec, v3, v1, v2, d, no);
+ VECCOPY(efa->v1->co, vec);
+
+ fix_bevel_tri_wrap(v1, v2, v3, efa->v1->co, efa->v2->co, efa->v3->co, no);
+ } else {
+ VECCOPY(v4, efa->v4->co);
+ bevel_displace_vec(vec, v1, v2, v3, d, no);
+ VECCOPY(efa->v2->co, vec);
+ bevel_displace_vec(vec, v2, v3, v4, d, no);
+ VECCOPY(efa->v3->co, vec);
+ bevel_displace_vec(vec, v3, v4, v1, d, no);
+ VECCOPY(efa->v4->co, vec);
+ bevel_displace_vec(vec, v4, v1, v2, d, no);
+ VECCOPY(efa->v1->co, vec);
+
+ fix_bevel_quad_wrap(v1, v2, v3, v4, efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co, d, no);
+ }
+ }
+ efa= efa->next;
+ }
+}
+
+static void bevel_shrink_draw(float d, int flag)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+ float vec[3], no[3], v1[3], v2[3], v3[3], v4[3], fv1[3], fv2[3], fv3[3], fv4[3];
+
+ /* move edges of all faces with efa->f1 & flag closer towards their centers */
+ efa= em->faces.first;
+ while (efa) {
+ VECCOPY(v1, efa->v1->co);
+ VECCOPY(v2, efa->v2->co);
+ VECCOPY(v3, efa->v3->co);
+ VECCOPY(no, efa->n);
+ if (efa->v4 == NULL) {
+ bevel_displace_vec(vec, v1, v2, v3, d, no);
+ VECCOPY(fv2, vec);
+ bevel_displace_vec(vec, v2, v3, v1, d, no);
+ VECCOPY(fv3, vec);
+ bevel_displace_vec(vec, v3, v1, v2, d, no);
+ VECCOPY(fv1, vec);
+
+ fix_bevel_tri_wrap(v1, v2, v3, fv1, fv2, fv3, no);
+
+ glBegin(GL_LINES);
+ glVertex3fv(fv1);
+ glVertex3fv(fv2);
+ glEnd();
+ glBegin(GL_LINES);
+ glVertex3fv(fv2);
+ glVertex3fv(fv3);
+ glEnd();
+ glBegin(GL_LINES);
+ glVertex3fv(fv1);
+ glVertex3fv(fv3);
+ glEnd();
+ } else {
+ VECCOPY(v4, efa->v4->co);
+ bevel_displace_vec(vec, v4, v1, v2, d, no);
+ VECCOPY(fv1, vec);
+ bevel_displace_vec(vec, v1, v2, v3, d, no);
+ VECCOPY(fv2, vec);
+ bevel_displace_vec(vec, v2, v3, v4, d, no);
+ VECCOPY(fv3, vec);
+ bevel_displace_vec(vec, v3, v4, v1, d, no);
+ VECCOPY(fv4, vec);
+
+ fix_bevel_quad_wrap(v1, v2, v3, v4, fv1, fv2, fv3, fv4, d, no);
+
+ glBegin(GL_LINES);
+ glVertex3fv(fv1);
+ glVertex3fv(fv2);
+ glEnd();
+ glBegin(GL_LINES);
+ glVertex3fv(fv2);
+ glVertex3fv(fv3);
+ glEnd();
+ glBegin(GL_LINES);
+ glVertex3fv(fv3);
+ glVertex3fv(fv4);
+ glEnd();
+ glBegin(GL_LINES);
+ glVertex3fv(fv1);
+ glVertex3fv(fv4);
+ glEnd();
+ }
+ efa= efa->next;
+ }
+}
+
+static void bevel_mesh(float bsize, int allfaces)
+{
+ EditMesh *em = G.editMesh;
+//#define BEV_DEBUG
+/* Enables debug printfs and assigns material indices: */
+/* 2 = edge quad */
+/* 3 = fill polygon (vertex clusters) */
+
+ EditFace *efa, *example; //, *nextvl;
+ EditEdge *eed, *eed2;
+ EditVert *neweve[1024], *eve, *eve2, *eve3, *v1, *v2, *v3, *v4; //, *eve4;
+ //short found4, search;
+ //float f1, f2, f3, f4;
+ float cent[3], min[3], max[3];
+ int a, b, c;
+ float limit= 0.001f;
+
+ if(multires_test()) return;
+
+ waitcursor(1);
+
+ removedoublesflag(1, 0, limit);
+
+ /* tag all original faces */
+ efa= em->faces.first;
+ while (efa) {
+ efa->f1= 0;
+ if (faceselectedAND(efa, 1)||allfaces) {
+ efa->f1= 1;
+ efa->v1->f |= 128;
+ efa->v2->f |= 128;
+ efa->v3->f |= 128;
+ if (efa->v4) efa->v4->f |= 128;
+ }
+ efa->v1->f &= ~64;
+ efa->v2->f &= ~64;
+ efa->v3->f &= ~64;
+ if (efa->v4) efa->v4->f &= ~64;
+
+ efa= efa->next;
+ }
+
+#ifdef BEV_DEBUG
+ fprintf(stderr,"bevel_mesh: split\n");
+#endif
+
+ efa= em->faces.first;
+ while (efa) {
+ if (efa->f1 & 1) {
+ efa->f1-= 1;
+ v1= addvertlist(efa->v1->co, efa->v1);
+ v1->f= efa->v1->f & ~128;
+ efa->v1->tmp.v = v1;
+
+ v1= addvertlist(efa->v2->co, efa->v2);
+ v1->f= efa->v2->f & ~128;
+ efa->v2->tmp.v = v1;
+
+ v1= addvertlist(efa->v3->co, efa->v3);
+ v1->f= efa->v3->f & ~128;
+ efa->v3->tmp.v = v1;
+
+ if (efa->v4) {
+ v1= addvertlist(efa->v4->co, efa->v4);
+ v1->f= efa->v4->f & ~128;
+ efa->v4->tmp.v = v1;
+ }
+
+ /* Needs better adaption of creases? */
+ addedgelist(efa->e1->v1->tmp.v,
+ efa->e1->v2->tmp.v,
+ efa->e1);
+ addedgelist(efa->e2->v1->tmp.v,
+ efa->e2->v2->tmp.v,
+ efa->e2);
+ addedgelist(efa->e3->v1->tmp.v,
+ efa->e3->v2->tmp.v,
+ efa->e3);
+ if (efa->e4) addedgelist(efa->e4->v1->tmp.v,
+ efa->e4->v2->tmp.v,
+ efa->e4);
+
+ if(efa->v4) {
+ v1 = efa->v1->tmp.v;
+ v2 = efa->v2->tmp.v;
+ v3 = efa->v3->tmp.v;
+ v4 = efa->v4->tmp.v;
+ addfacelist(v1, v2, v3, v4, efa,NULL);
+ } else {
+ v1= efa->v1->tmp.v;
+ v2= efa->v2->tmp.v;
+ v3= efa->v3->tmp.v;
+ addfacelist(v1, v2, v3, 0, efa,NULL);
+ }
+
+ efa= efa-> next;
+ } else {
+ efa= efa->next;
+ }
+ }
+
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if( (efa->v1->f & 128) && (efa->v2->f & 128) && (efa->v3->f & 128) ) {
+ if(efa->v4==NULL || (efa->v4->f & 128)) efa->f |= 128;
+ }
+ }
+
+ delfaceflag(128); // works with face flag now
+
+ /* tag all faces for shrink*/
+ efa= em->faces.first;
+ while (efa) {
+ if (faceselectedAND(efa, 1)||allfaces) {
+ efa->f1= 2;
+ }
+ efa= efa->next;
+ }
+
+#ifdef BEV_DEBUG
+ fprintf(stderr,"bevel_mesh: make edge quads\n");
+#endif
+
+ /* find edges that are on each other and make quads between them */
+
+ eed= em->edges.first;
+ while(eed) {
+ eed->f2= eed->f1= 0;
+ if ( ((eed->v1->f & eed->v2->f) & 1) || allfaces)
+ eed->f1 |= 4; /* original edges */
+ eed->tmp.v = 0;
+ eed= eed->next;
+ }
+
+ eed= em->edges.first;
+ while (eed) {
+ if ( ((eed->f1 & 2)==0) && (eed->f1 & 4) ) {
+ eed2= em->edges.first;
+ while (eed2) {
+ if ( (eed2 != eed) && ((eed2->f1 & 2)==0) && (eed->f1 & 4) ) {
+ if (
+ (eed->v1 != eed2->v1) &&
+ (eed->v1 != eed2->v2) &&
+ (eed->v2 != eed2->v1) &&
+ (eed->v2 != eed2->v2) && (
+ ( VecCompare(eed->v1->co, eed2->v1->co, limit) &&
+ VecCompare(eed->v2->co, eed2->v2->co, limit) ) ||
+ ( VecCompare(eed->v1->co, eed2->v2->co, limit) &&
+ VecCompare(eed->v2->co, eed2->v1->co, limit) ) ) )
+ {
+
+#ifdef BEV_DEBUG
+ fprintf(stderr, "bevel_mesh: edge quad\n");
+#endif
+
+ eed->f1 |= 2; /* these edges are finished */
+ eed2->f1 |= 2;
+
+ example= NULL;
+ efa= em->faces.first; /* search example face (for mat_nr, ME_SMOOTH, ...) */
+ while (efa) {
+ if ( (efa->e1 == eed) ||
+ (efa->e2 == eed) ||
+ (efa->e3 == eed) ||
+ (efa->e4 && (efa->e4 == eed)) ) {
+ example= efa;
+ efa= NULL;
+ }
+ if (efa) efa= efa->next;
+ }
+
+ neweve[0]= eed->v1; neweve[1]= eed->v2;
+ neweve[2]= eed2->v1; neweve[3]= eed2->v2;
+
+ if(exist_face(neweve[0], neweve[1], neweve[2], neweve[3])==0) {
+ efa= NULL;
+
+ if (VecCompare(eed->v1->co, eed2->v2->co, limit)) {
+ efa= addfacelist(neweve[0], neweve[1], neweve[2], neweve[3], example,NULL);
+ } else {
+ efa= addfacelist(neweve[0], neweve[2], neweve[3], neweve[1], example,NULL);
+ }
+
+ if(efa) {
+ float inp;
+ CalcNormFloat(efa->v1->co, efa->v2->co, efa->v3->co, efa->n);
+ inp= efa->n[0]*G.vd->viewmat[0][2] + efa->n[1]*G.vd->viewmat[1][2] + efa->n[2]*G.vd->viewmat[2][2];
+ if(inp < 0.0) flipface(efa);
+#ifdef BEV_DEBUG
+ efa->mat_nr= 1;
+#endif
+ } else fprintf(stderr,"bevel_mesh: error creating face\n");
+ }
+ eed2= NULL;
+ }
+ }
+ if (eed2) eed2= eed2->next;
+ }
+ }
+ eed= eed->next;
+ }
+
+ eed= em->edges.first;
+ while(eed) {
+ eed->f2= eed->f1= 0;
+ eed->f1= 0;
+ eed->v1->f1 &= ~1;
+ eed->v2->f1 &= ~1;
+ eed->tmp.v = 0;
+ eed= eed->next;
+ }
+
+#ifdef BEV_DEBUG
+ fprintf(stderr,"bevel_mesh: find clusters\n");
+#endif
+
+ /* Look for vertex clusters */
+
+ eve= em->verts.first;
+ while (eve) {
+ eve->f &= ~(64|128);
+ eve->tmp.v = NULL;
+ eve= eve->next;
+ }
+
+ /* eve->f: 128: first vertex in a list (->tmp.v) */
+ /* 64: vertex is in a list */
+
+ eve= em->verts.first;
+ while (eve) {
+ eve2= em->verts.first;
+ eve3= NULL;
+ while (eve2) {
+ if ((eve2 != eve) && ((eve2->f & (64|128))==0)) {
+ if (VecCompare(eve->co, eve2->co, limit)) {
+ if ((eve->f & (128|64)) == 0) {
+ /* fprintf(stderr,"Found vertex cluster:\n *\n *\n"); */
+ eve->f |= 128;
+ eve->tmp.v = eve2;
+ eve3= eve2;
+ } else if ((eve->f & 64) == 0) {
+ /* fprintf(stderr," *\n"); */
+ if (eve3) eve3->tmp.v = eve2;
+ eve2->f |= 64;
+ eve3= eve2;
+ }
+ }
+ }
+ eve2= eve2->next;
+ if (!eve2) {
+ if (eve3) eve3->tmp.v = NULL;
+ }
+ }
+ eve= eve->next;
+ }
+
+#ifdef BEV_DEBUG
+ fprintf(stderr,"bevel_mesh: shrink faces\n");
+#endif
+
+ bevel_shrink_faces(bsize, 2);
+
+#ifdef BEV_DEBUG
+ fprintf(stderr,"bevel_mesh: fill clusters\n");
+#endif
+
+ /* Make former vertex clusters faces */
+
+ eve= em->verts.first;
+ while (eve) {
+ eve->f &= ~64;
+ eve= eve->next;
+ }
+
+ eve= em->verts.first;
+ while (eve) {
+ if (eve->f & 128) {
+ eve->f &= ~128;
+ a= 0;
+ neweve[a]= eve;
+ eve2 = eve->tmp.v;
+ while (eve2) {
+ a++;
+ neweve[a]= eve2;
+ eve2 = eve2->tmp.v;
+ }
+ a++;
+ efa= NULL;
+ if (a>=3) {
+ example= NULL;
+ efa= em->faces.first; /* search example face */
+ while (efa) {
+ if ( (efa->v1 == neweve[0]) ||
+ (efa->v2 == neweve[0]) ||
+ (efa->v3 == neweve[0]) ||
+ (efa->v4 && (efa->v4 == neweve[0])) ) {
+ example= efa;
+ efa= NULL;
+ }
+ if (efa) efa= efa->next;
+ }
+#ifdef BEV_DEBUG
+ fprintf(stderr,"bevel_mesh: Making %d-gon\n", a);
+#endif
+ if (a>4) {
+ cent[0]= cent[1]= cent[2]= 0.0;
+ INIT_MINMAX(min, max);
+ for (b=0; b<a; b++) {
+ VecAddf(cent, cent, neweve[b]->co);
+ DO_MINMAX(neweve[b]->co, min, max);
+ }
+ cent[0]= (min[0]+max[0])/2;
+ cent[1]= (min[1]+max[1])/2;
+ cent[2]= (min[2]+max[2])/2;
+ eve2= addvertlist(cent, NULL);
+ eve2->f |= 1;
+ eed= em->edges.first;
+ while (eed) {
+ c= 0;
+ for (b=0; b<a; b++)
+ if ((neweve[b]==eed->v1) || (neweve[b]==eed->v2)) c++;
+ if (c==2) {
+ if(exist_face(eed->v1, eed->v2, eve2, 0)==0) {
+ efa= addfacelist(eed->v1, eed->v2, eve2, 0, example,NULL);
+#ifdef BEV_DEBUG
+ efa->mat_nr= 2;
+#endif
+ }
+ }
+ eed= eed->next;
+ }
+ } else if (a==4) {
+ if(exist_face(neweve[0], neweve[1], neweve[2], neweve[3])==0) {
+ /* the order of vertices can be anything, three cases to check */
+ if( convex(neweve[0]->co, neweve[1]->co, neweve[2]->co, neweve[3]->co) ) {
+ efa= addfacelist(neweve[0], neweve[1], neweve[2], neweve[3], NULL, NULL);
+ }
+ else if( convex(neweve[0]->co, neweve[2]->co, neweve[3]->co, neweve[1]->co) ) {
+ efa= addfacelist(neweve[0], neweve[2], neweve[3], neweve[1], NULL, NULL);
+ }
+ else if( convex(neweve[0]->co, neweve[2]->co, neweve[1]->co, neweve[3]->co) ) {
+ efa= addfacelist(neweve[0], neweve[2], neweve[1], neweve[3], NULL, NULL);
+ }
+ }
+ }
+ else if (a==3) {
+ if(exist_face(neweve[0], neweve[1], neweve[2], 0)==0)
+ efa= addfacelist(neweve[0], neweve[1], neweve[2], 0, example, NULL);
+ }
+ if(efa) {
+ float inp;
+ CalcNormFloat(neweve[0]->co, neweve[1]->co, neweve[2]->co, efa->n);
+ inp= efa->n[0]*G.vd->viewmat[0][2] + efa->n[1]*G.vd->viewmat[1][2] + efa->n[2]*G.vd->viewmat[2][2];
+ if(inp < 0.0) flipface(efa);
+#ifdef BEV_DEBUG
+ efa->mat_nr= 2;
+#endif
+ }
+ }
+ }
+ eve= eve->next;
+ }
+
+ eve= em->verts.first;
+ while (eve) {
+ eve->f1= 0;
+ eve->f &= ~(128|64);
+ eve->tmp.v= NULL;
+ eve= eve->next;
+ }
+
+ recalc_editnormals();
+ waitcursor(0);
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+
+ removedoublesflag(1, 0, limit);
+
+ /* flush selected vertices to edges/faces */
+ EM_select_flush();
+
+#undef BEV_DEBUG
+}
+
+static void bevel_mesh_recurs(float bsize, short recurs, int allfaces)
+{
+ float d;
+ short nr;
+
+ d= bsize;
+ for (nr=0; nr<recurs; nr++) {
+ bevel_mesh(d, allfaces);
+ if (nr==0) d /= 3; else d /= 2;
+ }
+}
+
+void bevel_menu()
+{
+ char Finished = 0, Canceled = 0, str[100], Recalc = 0;
+ short mval[2], oval[2], curval[2], event = 0, recurs = 1, nr;
+ float vec[3], d, drawd=0.0, center[3], fac = 1;
+
+ getmouseco_areawin(mval);
+ oval[0] = mval[0]; oval[1] = mval[1];
+
+ // Silly hackish code to initialise the variable (warning if not done)
+ // while still drawing in the first iteration (and without using another variable)
+ curval[0] = mval[0] + 1; curval[1] = mval[1] + 1;
+
+ // Init grabz for window to vec conversions
+ initgrabz(-G.vd->ofs[0], -G.vd->ofs[1], -G.vd->ofs[2]);
+ window_to_3d(center, mval[0], mval[1]);
+
+ if(button(&recurs, 1, 4, "Recursion:")==0) return;
+
+ for (nr=0; nr<recurs-1; nr++) {
+ if (nr==0) fac += 1.0f/3.0f; else fac += 1.0f/(3 * nr * 2.0f);
+ }
+
+ EM_set_flag_all(SELECT);
+
+ SetBlenderCursor(SYSCURSOR);
+
+ while (Finished == 0)
+ {
+ getmouseco_areawin(mval);
+ if (mval[0] != curval[0] || mval[1] != curval[1] || (Recalc == 1))
+ {
+ Recalc = 0;
+ curval[0] = mval[0];
+ curval[1] = mval[1];
+
+ window_to_3d(vec, mval[0]-oval[0], mval[1]-oval[1]);
+ d = Normalize(vec) / 10;
+
+
+ drawd = d * fac;
+ if (G.qual & LR_CTRLKEY)
+ drawd = (float) floor(drawd * 10.0f)/10.0f;
+ if (G.qual & LR_SHIFTKEY)
+ drawd /= 10;
+
+ /*------------- Preview lines--------------- */
+
+ /* uses callback mechanism to draw it all in current area */
+ scrarea_do_windraw(curarea);
+
+ /* set window matrix to perspective, default an area returns with buttons transform */
+ persp(PERSP_VIEW);
+ /* make a copy, for safety */
+ glPushMatrix();
+ /* multiply with the object transformation */
+ mymultmatrix(G.obedit->obmat);
+
+ glColor3ub(255, 255, 0);
+
+ // PREVIEW CODE GOES HERE
+ bevel_shrink_draw(drawd, 2);
+
+ /* restore matrix transform */
+ glPopMatrix();
+
+ sprintf(str, "Bevel Size: %.4f LMB to confirm, RMB to cancel, SPACE to input directly.", drawd);
+ headerprint(str);
+
+ /* this also verifies other area/windows for clean swap */
+ screen_swapbuffers();
+
+ persp(PERSP_WIN);
+
+ glDrawBuffer(GL_FRONT);
+
+ BIF_ThemeColor(TH_WIRE);
+
+ setlinestyle(3);
+ glBegin(GL_LINE_STRIP);
+ glVertex2sv(mval);
+ glVertex2sv(oval);
+ glEnd();
+ setlinestyle(0);
+
+ persp(PERSP_VIEW);
+ bglFlush(); // flush display for frontbuffer
+ glDrawBuffer(GL_BACK);
+ }
+ while(qtest()) {
+ short val=0;
+ event= extern_qread(&val); // extern_qread stores important events for the mainloop to handle
+
+ /* val==0 on key-release event */
+ if(val && (event==ESCKEY || event==RIGHTMOUSE || event==LEFTMOUSE || event==RETKEY || event==ESCKEY)) {
+ if (event==RIGHTMOUSE || event==ESCKEY)
+ Canceled = 1;
+ Finished = 1;
+ }
+ else if (val && event==SPACEKEY) {
+ if (fbutton(&d, 0.000, 10.000, 10, 0, "Width:")!=0) {
+ drawd = d * fac;
+ Finished = 1;
+ }
+ }
+ else if (val) {
+ /* On any other keyboard event, recalc */
+ Recalc = 1;
+ }
+
+ }
+ }
+ if (Canceled==0) {
+ SetBlenderCursor(BC_WAITCURSOR);
+ bevel_mesh_recurs(drawd/fac, recurs, 1);
+ righthandfaces(1);
+ SetBlenderCursor(SYSCURSOR);
+ BIF_undo_push("Bevel");
+ }
+}
+
+/* *********** END BEVEL *********/
+
+typedef struct SlideVert {
+ EditEdge *up,*down;
+ EditVert origvert;
+} SlideVert;
+
+int EdgeLoopDelete(void) {
+ if(!EdgeSlide(1, 1)) {
+ return 0;
+ }
+ select_more();
+ removedoublesflag(1,0, 0.001);
+ EM_select_flush();
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ return 1;
+}
+
+int EdgeSlide(short immediate, float imperc)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+ EditEdge *eed,*first=NULL,*last=NULL, *temp = NULL;
+ EditVert *ev, *nearest;
+ LinkNode *edgelist = NULL, *vertlist=NULL, *look;
+ GHash *vertgh;
+ SlideVert *tempsv;
+ float perc = 0, percp = 0,vertdist, projectMat[4][4], viewMat[4][4];
+ float shiftlabda= 0.0f,len = 0.0f;
+ int i = 0,j, numsel, numadded=0, timesthrough = 0, vertsel=0, prop=1, cancel = 0,flip=0;
+ int wasshift = 0;
+ short event, draw=1;
+ short mval[2], mvalo[2];
+ char str[128];
+ float labda = 0.0f;
+
+ view3d_get_object_project_mat(curarea, G.obedit, projectMat, viewMat);
+
+ mvalo[0] = -1; mvalo[1] = -1;
+ numsel =0;
+
+ // Get number of selected edges and clear some flags
+ for(eed=em->edges.first;eed;eed=eed->next) {
+ eed->f1 = 0;
+ eed->f2 = 0;
+ if(eed->f & SELECT) numsel++;
+ }
+
+ for(ev=em->verts.first;ev;ev=ev->next) {
+ ev->f1 = 0;
+ }
+
+ //Make sure each edge only has 2 faces
+ // make sure loop doesn't cross face
+ for(efa=em->faces.first;efa;efa=efa->next) {
+ int ct = 0;
+ if(efa->e1->f & SELECT) {
+ ct++;
+ efa->e1->f1++;
+ if(efa->e1->f1 > 2) {
+ error("3+ face edge");
+ return 0;
+ }
+ }
+ if(efa->e2->f & SELECT) {
+ ct++;
+ efa->e2->f1++;
+ if(efa->e2->f1 > 2) {
+ error("3+ face edge");
+ return 0;
+ }
+ }
+ if(efa->e3->f & SELECT) {
+ ct++;
+ efa->e3->f1++;
+ if(efa->e3->f1 > 2) {
+ error("3+ face edge");
+ return 0;
+ }
+ }
+ if(efa->e4 && efa->e4->f & SELECT) {
+ ct++;
+ efa->e4->f1++;
+ if(efa->e4->f1 > 2) {
+ error("3+ face edge");
+ return 0;
+ }
+ }
+ // Make sure loop is not 2 edges of same face
+ if(ct > 1) {
+ error("loop crosses itself");
+ return 0;
+ }
+ }
+ // Get # of selected verts
+ for(ev=em->verts.first;ev;ev=ev->next) {
+ if(ev->f & SELECT) vertsel++;
+ }
+
+ // Test for multiple segments
+ if(vertsel > numsel+1) {
+ error("Was not a single edge loop");
+ return 0;
+ }
+
+ // Get the edgeloop in order - mark f1 with SELECT once added
+ for(eed=em->edges.first;eed;eed=eed->next) {
+ if((eed->f & SELECT) && !(eed->f1 & SELECT)) {
+ // If this is the first edge added, just put it in
+ if(!edgelist) {
+ BLI_linklist_prepend(&edgelist,eed);
+ numadded++;
+ first = eed;
+ last = eed;
+ eed->f1 = SELECT;
+ } else {
+ if(editedge_getSharedVert(eed, last)) {
+ BLI_linklist_append(&edgelist,eed);
+ eed->f1 = SELECT;
+ numadded++;
+ last = eed;
+ } else if(editedge_getSharedVert(eed, first)) {
+ BLI_linklist_prepend(&edgelist,eed);
+ eed->f1 = SELECT;
+ numadded++;
+ first = eed;
+ }
+ }
+ }
+ if(eed->next == NULL && numadded != numsel) {
+ eed=em->edges.first;
+ timesthrough++;
+ }
+
+ // It looks like there was an unexpected case - Hopefully should not happen
+ if(timesthrough >= numsel*2) {
+ BLI_linklist_free(edgelist,NULL);
+ error("could not order loop");
+ return 0;
+ }
+ }
+
+ // Put the verts in order in a linklist
+ look = edgelist;
+ while(look) {
+ eed = look->link;
+ if(!vertlist) {
+ if(look->next) {
+ temp = look->next->link;
+
+ //This is the first entry takes care of extra vert
+ if(eed->v1 != temp->v1 && eed->v1 != temp->v2) {
+ BLI_linklist_append(&vertlist,eed->v1);
+ eed->v1->f1 = 1;
+ } else {
+ BLI_linklist_append(&vertlist,eed->v2);
+ eed->v2->f1 = 1;
+ }
+ } else {
+ //This is the case that we only have 1 edge
+ BLI_linklist_append(&vertlist,eed->v1);
+ eed->v1->f1 = 1;
+ }
+ }
+ // for all the entries
+ if(eed->v1->f1 != 1) {
+ BLI_linklist_append(&vertlist,eed->v1);
+ eed->v1->f1 = 1;
+ } else if(eed->v2->f1 != 1) {
+ BLI_linklist_append(&vertlist,eed->v2);
+ eed->v2->f1 = 1;
+ }
+ look = look->next;
+ }
+
+ // populate the SlideVerts
+
+ vertgh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
+ look = vertlist;
+ while(look) {
+ i=0;
+ j=0;
+ ev = look->link;
+ tempsv = (struct SlideVert*)MEM_mallocN(sizeof(struct SlideVert),"SlideVert");
+ tempsv->up = NULL;
+ tempsv->down = NULL;
+ tempsv->origvert.co[0] = ev->co[0];
+ tempsv->origvert.co[1] = ev->co[1];
+ tempsv->origvert.co[2] = ev->co[2];
+ tempsv->origvert.no[0] = ev->no[0];
+ tempsv->origvert.no[1] = ev->no[1];
+ tempsv->origvert.no[2] = ev->no[2];
+ // i is total edges that vert is on
+ // j is total selected edges that vert is on
+
+ for(eed=em->edges.first;eed;eed=eed->next) {
+ if(eed->v1 == ev || eed->v2 == ev) {
+ i++;
+ if(eed->f & SELECT) {
+ j++;
+ }
+ }
+ }
+ // If the vert is in the middle of an edge loop, it touches 2 selected edges and 2 unselected edges
+ if(i == 4 && j == 2) {
+ for(eed=em->edges.first;eed;eed=eed->next) {
+ if(editedge_containsVert(eed, ev)) {
+ if(!(eed->f & SELECT)) {
+ if(!tempsv->up) {
+ tempsv->up = eed;
+ } else if (!(tempsv->down)) {
+ tempsv->down = eed;
+ }
+ }
+ }
+ }
+ }
+ // If it is on the end of the loop, it touches 1 selected and as least 2 more unselected
+ if(i >= 3 && j == 1) {
+ for(eed=em->edges.first;eed;eed=eed->next) {
+ if(editedge_containsVert(eed, ev) && eed->f & SELECT) {
+ for(efa = em->faces.first;efa;efa=efa->next) {
+ if(editface_containsEdge(efa, eed)) {
+ if(editedge_containsVert(efa->e1, ev) && efa->e1 != eed) {
+ if(!tempsv->up) {
+ tempsv->up = efa->e1;
+ } else if (!(tempsv->down)) {
+ tempsv->down = efa->e1;
+ }
+ }
+ if(editedge_containsVert(efa->e2, ev) && efa->e2 != eed) {
+ if(!tempsv->up) {
+ tempsv->up = efa->e2;
+ } else if (!(tempsv->down)) {
+ tempsv->down = efa->e2;
+ }
+ }
+ if(editedge_containsVert(efa->e3, ev) && efa->e3 != eed) {
+ if(!tempsv->up) {
+ tempsv->up = efa->e3;
+ } else if (!(tempsv->down)) {
+ tempsv->down = efa->e3;
+ }
+ }
+ if(efa->e4) {
+ if(editedge_containsVert(efa->e4, ev) && efa->e4 != eed) {
+ if(!tempsv->up) {
+ tempsv->up = efa->e4;
+ } else if (!(tempsv->down)) {
+ tempsv->down = efa->e4;
+ }
+ }
+ }
+
+ }
+ }
+ }
+ }
+ }
+ if(i > 4 && j == 2) {
+ BLI_ghash_free(vertgh, NULL, (GHashValFreeFP)MEM_freeN);
+ BLI_linklist_free(vertlist,NULL);
+ BLI_linklist_free(edgelist,NULL);
+ return 0;
+ }
+ BLI_ghash_insert(vertgh,ev,tempsv);
+
+ look = look->next;
+ }
+
+ // make sure the UPs nad DOWNs are 'faceloops'
+ // Also find the nearest slidevert to the cursor
+ getmouseco_areawin(mval);
+ look = vertlist;
+ nearest = NULL;
+ vertdist = -1;
+ while(look) {
+ if(look->next != NULL) {
+ SlideVert *sv;
+
+ tempsv = BLI_ghash_lookup(vertgh,(EditVert*)look->link);
+ sv = BLI_ghash_lookup(vertgh,(EditVert*)look->next->link);
+
+ if(!tempsv->up || !tempsv->down) {
+ error("Missing rails");
+ BLI_ghash_free(vertgh, NULL, (GHashValFreeFP)MEM_freeN);
+ BLI_linklist_free(vertlist,NULL);
+ BLI_linklist_free(edgelist,NULL);
+ return 0;
+ }
+
+ if(G.f & G_DRAW_EDGELEN) {
+ if(!(tempsv->up->f & SELECT)) {
+ tempsv->up->f |= SELECT;
+ tempsv->up->f2 |= 16;
+ } else {
+ tempsv->up->f2 |= ~16;
+ }
+ if(!(tempsv->down->f & SELECT)) {
+ tempsv->down->f |= SELECT;
+ tempsv->down->f2 |= 16;
+ } else {
+ tempsv->down->f2 |= ~16;
+ }
+ }
+
+ if(sv) {
+ float tempdist, co[2];
+
+ if(!sharesFace(tempsv->up,sv->up)) {
+ EditEdge *swap;
+ swap = sv->up;
+ sv->up = sv->down;
+ sv->down = swap;
+ }
+
+ view3d_project_float(curarea, tempsv->origvert.co, co, projectMat);
+
+ tempdist = sqrt(pow(co[0] - mval[0],2)+pow(co[1] - mval[1],2));
+
+ if(vertdist < 0) {
+ vertdist = tempdist;
+ nearest = (EditVert*)look->link;
+ } else if ( tempdist < vertdist ) {
+ vertdist = tempdist;
+ nearest = (EditVert*)look->link;
+ }
+ }
+ }
+
+
+
+ look = look->next;
+ }
+ // we should have enough info now to slide
+
+ len = 0.0f;
+
+ percp = -1;
+ while(draw) {
+ /* For the % calculation */
+ short mval[2];
+ float rc[2];
+ float v2[2], v3[2];
+ EditVert *centerVert, *upVert, *downVert;
+
+
+
+ getmouseco_areawin(mval);
+
+ if (!immediate && (mval[0] == mvalo[0] && mval[1] == mvalo[1])) {
+ PIL_sleep_ms(10);
+ } else {
+
+ mvalo[0] = mval[0];
+ mvalo[1] = mval[1];
+
+ //Adjust Edgeloop
+ if(immediate) {
+ perc = imperc;
+ }
+ percp = perc;
+ if(prop) {
+ look = vertlist;
+ while(look) {
+ EditVert *tempev;
+ ev = look->link;
+ tempsv = BLI_ghash_lookup(vertgh,ev);
+
+ tempev = editedge_getOtherVert((perc>=0)?tempsv->up:tempsv->down, ev);
+ VecLerpf(ev->co, tempsv->origvert.co, tempev->co, fabs(perc));
+
+ look = look->next;
+ }
+ }
+ else {
+ //Non prop code
+ look = vertlist;
+ while(look) {
+ float newlen;
+ ev = look->link;
+ tempsv = BLI_ghash_lookup(vertgh,ev);
+ newlen = (len / VecLenf(editedge_getOtherVert(tempsv->up,ev)->co,editedge_getOtherVert(tempsv->down,ev)->co));
+ if(newlen > 1.0) {newlen = 1.0;}
+ if(newlen < 0.0) {newlen = 0.0;}
+ if(flip == 0) {
+ VecLerpf(ev->co, editedge_getOtherVert(tempsv->down,ev)->co, editedge_getOtherVert(tempsv->up,ev)->co, fabs(newlen));
+ } else{
+ VecLerpf(ev->co, editedge_getOtherVert(tempsv->up,ev)->co, editedge_getOtherVert(tempsv->down,ev)->co, fabs(newlen));
+ }
+ look = look->next;
+ }
+
+ }
+
+ tempsv = BLI_ghash_lookup(vertgh,nearest);
+
+ centerVert = editedge_getSharedVert(tempsv->up, tempsv->down);
+ upVert = editedge_getOtherVert(tempsv->up, centerVert);
+ downVert = editedge_getOtherVert(tempsv->down, centerVert);
+ // Highlight the Control Edges
+
+ scrarea_do_windraw(curarea);
+ persp(PERSP_VIEW);
+ glPushMatrix();
+ mymultmatrix(G.obedit->obmat);
+
+ glColor3ub(0, 255, 0);
+ glBegin(GL_LINES);
+ glVertex3fv(upVert->co);
+ glVertex3fv(downVert->co);
+ glEnd();
+
+ if(prop == 0) {
+ // draw start edge for non-prop
+ glPointSize(5);
+ glBegin(GL_POINTS);
+ glColor3ub(255,0,255);
+ if(flip) {
+ glVertex3fv(upVert->co);
+ } else {
+ glVertex3fv(downVert->co);
+ }
+ glEnd();
+ }
+
+
+ glPopMatrix();
+
+ view3d_project_float(curarea, upVert->co, v2, projectMat);
+ view3d_project_float(curarea, downVert->co, v3, projectMat);
+
+ /* Determine the % on which the loop should be cut */
+
+ rc[0]= v3[0]-v2[0];
+ rc[1]= v3[1]-v2[1];
+ len= rc[0]*rc[0]+ rc[1]*rc[1];
+ if (len==0) {len = 0.0001;}
+
+ if ((G.qual & LR_SHIFTKEY)==0) {
+ wasshift = 0;
+ labda= ( rc[0]*((mval[0]-v2[0])) + rc[1]*((mval[1]-v2[1])) )/len;
+ }
+ else {
+ if (wasshift==0) {
+ wasshift = 1;
+ shiftlabda = labda;
+ }
+ labda= ( rc[0]*((mval[0]-v2[0])) + rc[1]*((mval[1]-v2[1])) )/len / 10.0 + shiftlabda;
+ }
+
+
+ if(labda<=0.0) labda=0.0;
+ else if(labda>=1.0)labda=1.0;
+
+ perc=((1-labda)*2)-1;
+
+ if(G.qual == 0) {
+ perc *= 100;
+ perc = floor(perc);
+ perc /= 100;
+ } else if (G.qual == LR_CTRLKEY) {
+ perc *= 10;
+ perc = floor(perc);
+ perc /= 10;
+ }
+ if(prop) {
+ sprintf(str, "(P)ercentage: %f", perc);
+ } else {
+ len = VecLenf(upVert->co,downVert->co)*((perc+1)/2);
+ if(flip == 1) {
+ len = VecLenf(upVert->co,downVert->co) - len;
+ }
+ sprintf(str, "Non (P)rop Length: %f, Press (F) to flip control side", len);
+ }
+
+
+
+ headerprint(str);
+ screen_swapbuffers();
+ }
+ if(!immediate) {
+ while(qtest()) {
+ short val=0;
+ event= extern_qread(&val); // extern_qread stores important events for the mainloop to handle
+
+ /* val==0 on key-release event */
+ if (val) {
+ if(ELEM(event, ESCKEY, RIGHTMOUSE)) {
+ prop = 1; // Go back to prop mode
+ imperc = 0; // This is the % that gets set for immediate
+ immediate = 1; //Run through eval code 1 more time
+ cancel = 1; // Return -1
+ mvalo[0] = -1;
+ } else if(ELEM3(event, PADENTER, LEFTMOUSE, RETKEY)) {
+ draw = 0; // End looping now
+ } else if(event==MIDDLEMOUSE) {
+ perc = 0;
+ immediate = 1;
+ } else if(event==PKEY) {
+ (prop == 1) ? (prop = 0):(prop = 1);
+ mvalo[0] = -1;
+ } else if(event==FKEY) {
+ (flip == 1) ? (flip = 0):(flip = 1);
+ mvalo[0] = -1;
+ } else if(ELEM(event, RIGHTARROWKEY, WHEELUPMOUSE)) { // Scroll through Control Edges
+ look = vertlist;
+ while(look) {
+ if(nearest == (EditVert*)look->link) {
+ if(look->next == NULL) {
+ nearest = (EditVert*)vertlist->link;
+ } else {
+ nearest = (EditVert*)look->next->link;
+ }
+ mvalo[0] = -1;
+ break;
+ }
+ look = look->next;
+ }
+ } else if(ELEM(event, LEFTARROWKEY, WHEELDOWNMOUSE)) { // Scroll through Control Edges
+ look = vertlist;
+ while(look) {
+ if(look->next) {
+ if(look->next->link == nearest) {
+ nearest = (EditVert*)look->link;
+ mvalo[0] = -1;
+ break;
+ }
+ } else {
+ if((EditVert*)vertlist->link == nearest) {
+ nearest = look->link;
+ mvalo[0] = -1;
+ break;
+ }
+ }
+ look = look->next;
+ }
+ }
+ }
+ }
+ } else {
+ draw = 0;
+ }
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ }
+
+
+ if(G.f & G_DRAW_EDGELEN) {
+ look = vertlist;
+ while(look) {
+ tempsv = BLI_ghash_lookup(vertgh,(EditVert*)look->link);
+ if(tempsv != NULL) {
+ tempsv->up->f &= !SELECT;
+ tempsv->down->f &= !SELECT;
+ }
+ look = look->next;
+ }
+ }
+
+ force_draw(0);
+
+ EM_automerge(0);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ scrarea_queue_winredraw(curarea);
+
+ //BLI_ghash_free(edgesgh, freeGHash, NULL);
+ BLI_ghash_free(vertgh, NULL, (GHashValFreeFP)MEM_freeN);
+ BLI_linklist_free(vertlist,NULL);
+ BLI_linklist_free(edgelist,NULL);
+
+ if(cancel == 1) {
+ return -1;
+ }
+ else {
+#ifdef WITH_VERSE
+ if(G.editMesh->vnode) {
+ sync_all_verseverts_with_editverts((VNode*)G.editMesh->vnode);
+ sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode);
+ }
+#endif
+ }
+ return 1;
+}
+
+/* -------------------- More tools ------------------ */
+
+void mesh_set_face_flags(short mode)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+ MTFace *tface;
+ short m_tex=0, m_tiles=0, m_shared=0, m_light=0, m_invis=0, m_collision=0, m_twoside=0, m_obcolor=0;
+ short flag = 0, change = 0;
+
+ if (!EM_texFaceCheck()) {
+ error("not a mesh with uv/image layers");
+ return;
+ }
+
+ add_numbut(0, TOG|SHO, "Texture", 0, 0, &m_tex, NULL);
+ add_numbut(1, TOG|SHO, "Tiles", 0, 0, &m_tiles, NULL);
+ add_numbut(2, TOG|SHO, "Shared", 0, 0, &m_shared, NULL);
+ add_numbut(3, TOG|SHO, "Light", 0, 0, &m_light, NULL);
+ add_numbut(4, TOG|SHO, "Invisible", 0, 0, &m_invis, NULL);
+ add_numbut(5, TOG|SHO, "Collision", 0, 0, &m_collision, NULL);
+ add_numbut(6, TOG|SHO, "Twoside", 0, 0, &m_twoside, NULL);
+ add_numbut(7, TOG|SHO, "ObColor", 0, 0, &m_obcolor, NULL);
+
+ if (!do_clever_numbuts((mode ? "Set Flags" : "Clear Flags"), 8, REDRAW))
+ return;
+
+ if (m_tex) flag |= TF_TEX;
+ if (m_tiles) flag |= TF_TILES;
+ if (m_shared) flag |= TF_SHAREDCOL;
+ if (m_light) flag |= TF_LIGHT;
+ if (m_invis) flag |= TF_INVISIBLE;
+ if (m_collision) flag |= TF_DYNAMIC;
+ if (m_twoside) flag |= TF_TWOSIDE;
+ if (m_obcolor) flag |= TF_OBCOL;
+
+ efa= em->faces.first;
+ while(efa) {
+ if(efa->f & SELECT) {
+ tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ if (mode) tface->mode |= flag;
+ else tface->mode &= ~flag;
+ }
+ efa= efa->next;
+ }
+
+ if (change) {
+ BIF_undo_push((mode ? "Set Flags" : "Clear Flags"));
+
+ allqueue(REDRAWIMAGE, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+}
+
+void mesh_set_smooth_faces(short event)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+
+ if(G.obedit==0) return;
+
+ if(G.obedit->type != OB_MESH) return;
+
+ efa= em->faces.first;
+ while(efa) {
+ if(efa->f & SELECT) {
+ if(event==1) efa->flag |= ME_SMOOTH;
+ else if(event==0) efa->flag &= ~ME_SMOOTH;
+ }
+ efa= efa->next;
+ }
+
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+
+ if(event==1) BIF_undo_push("Set Smooth");
+ else if(event==0) BIF_undo_push("Set Solid");
+}
+
+/* helper to find edge for edge_rip */
+static float mesh_rip_edgedist(float mat[][4], float *co1, float *co2, short *mval)
+{
+ float vec1[3], vec2[3], mvalf[2];
+
+ view3d_project_float(curarea, co1, vec1, mat);
+ view3d_project_float(curarea, co2, vec2, mat);
+ mvalf[0]= (float)mval[0];
+ mvalf[1]= (float)mval[1];
+
+ return PdistVL2Dfl(mvalf, vec1, vec2);
+}
+
+/* helper for below */
+static void mesh_rip_setface(EditFace *sefa)
+{
+ /* put new vertices & edges in best face */
+ if(sefa->v1->tmp.v) sefa->v1= sefa->v1->tmp.v;
+ if(sefa->v2->tmp.v) sefa->v2= sefa->v2->tmp.v;
+ if(sefa->v3->tmp.v) sefa->v3= sefa->v3->tmp.v;
+ if(sefa->v4 && sefa->v4->tmp.v) sefa->v4= sefa->v4->tmp.v;
+
+ sefa->e1= addedgelist(sefa->v1, sefa->v2, sefa->e1);
+ sefa->e2= addedgelist(sefa->v2, sefa->v3, sefa->e2);
+ if(sefa->v4) {
+ sefa->e3= addedgelist(sefa->v3, sefa->v4, sefa->e3);
+ sefa->e4= addedgelist(sefa->v4, sefa->v1, sefa->e4);
+ }
+ else
+ sefa->e3= addedgelist(sefa->v3, sefa->v1, sefa->e3);
+
+}
+
+/* based on mouse cursor position, it defines how is being ripped */
+void mesh_rip(void)
+{
+ extern void faceloop_select(EditEdge *startedge, int select);
+ EditMesh *em = G.editMesh;
+ EditVert *eve, *nextve;
+ EditEdge *eed, *seed= NULL;
+ EditFace *efa, *sefa= NULL;
+ float projectMat[4][4], viewMat[4][4], vec[3], dist, mindist;
+ short doit= 1, mval[2],propmode,prop;
+
+ propmode = G.scene->prop_mode;
+ G.scene->prop_mode = 0;
+ prop = G.scene->proportional;
+ G.scene->proportional = 0;
+
+ /* select flush... vertices are important */
+ EM_selectmode_set();
+
+ getmouseco_areawin(mval);
+ view3d_get_object_project_mat(curarea, G.obedit, projectMat, viewMat);
+
+ /* find best face, exclude triangles and break on face select or faces with 2 edges select */
+ mindist= 1000000.0f;
+ for(efa= em->faces.first; efa; efa=efa->next) {
+ if( efa->f & 1)
+ break;
+ if(efa->v4 && faceselectedOR(efa, SELECT) ) {
+ int totsel=0;
+
+ if(efa->e1->f & SELECT) totsel++;
+ if(efa->e2->f & SELECT) totsel++;
+ if(efa->e3->f & SELECT) totsel++;
+ if(efa->e4->f & SELECT) totsel++;
+
+ if(totsel>1)
+ break;
+ view3d_project_float(curarea, efa->cent, vec, projectMat);
+ dist= sqrt( (vec[0]-mval[0])*(vec[0]-mval[0]) + (vec[1]-mval[1])*(vec[1]-mval[1]) );
+ if(dist<mindist) {
+ mindist= dist;
+ sefa= efa;
+ }
+ }
+ }
+
+ if(efa) {
+ error("Can't perform ripping with faces selected this way");
+ return;
+ }
+ if(sefa==NULL) {
+ error("No proper selection or faces included");
+ return;
+ }
+
+
+ /* duplicate vertices, new vertices get selected */
+ for(eve = em->verts.last; eve; eve= eve->prev) {
+ eve->tmp.v = NULL;
+ if(eve->f & SELECT) {
+ eve->tmp.v = addvertlist(eve->co, eve);
+ eve->f &= ~SELECT;
+ eve->tmp.v->f |= SELECT;
+ }
+ }
+
+ /* find the best candidate edge */
+ /* or one of sefa edges is selected... */
+ if(sefa->e1->f & SELECT) seed= sefa->e2;
+ if(sefa->e2->f & SELECT) seed= sefa->e1;
+ if(sefa->e3->f & SELECT) seed= sefa->e2;
+ if(sefa->e4 && sefa->e4->f & SELECT) seed= sefa->e3;
+
+ /* or we do the distance trick */
+ if(seed==NULL) {
+ mindist= 1000000.0f;
+ if(sefa->e1->v1->tmp.v || sefa->e1->v2->tmp.v) {
+ dist = mesh_rip_edgedist(projectMat,
+ sefa->e1->v1->co,
+ sefa->e1->v2->co, mval);
+ if(dist<mindist) {
+ seed= sefa->e1;
+ mindist= dist;
+ }
+ }
+ if(sefa->e2->v1->tmp.v || sefa->e2->v2->tmp.v) {
+ dist = mesh_rip_edgedist(projectMat,
+ sefa->e2->v1->co,
+ sefa->e2->v2->co, mval);
+ if(dist<mindist) {
+ seed= sefa->e2;
+ mindist= dist;
+ }
+ }
+ if(sefa->e3->v1->tmp.v || sefa->e3->v2->tmp.v) {
+ dist= mesh_rip_edgedist(projectMat,
+ sefa->e3->v1->co,
+ sefa->e3->v2->co, mval);
+ if(dist<mindist) {
+ seed= sefa->e3;
+ mindist= dist;
+ }
+ }
+ if(sefa->e4 && (sefa->e4->v1->tmp.v || sefa->e4->v2->tmp.v)) {
+ dist= mesh_rip_edgedist(projectMat,
+ sefa->e4->v1->co,
+ sefa->e4->v2->co, mval);
+ if(dist<mindist) {
+ seed= sefa->e4;
+ mindist= dist;
+ }
+ }
+ }
+
+ if(seed==NULL) { // never happens?
+ error("No proper edge found to start");
+ return;
+ }
+
+ faceloop_select(seed, 2); // tmp abuse for finding all edges that need duplicated, returns OK faces with f1
+
+ /* duplicate edges in the loop, with at least 1 vertex selected, needed for selection flip */
+ for(eed = em->edges.last; eed; eed= eed->prev) {
+ eed->tmp.v = NULL;
+ if((eed->v1->tmp.v) || (eed->v2->tmp.v)) {
+ EditEdge *newed;
+
+ newed= addedgelist(eed->v1->tmp.v?eed->v1->tmp.v:eed->v1,
+ eed->v2->tmp.v?eed->v2->tmp.v:eed->v2, eed);
+ if(eed->f & SELECT) {
+ eed->f &= ~SELECT;
+ newed->f |= SELECT;
+ }
+ eed->tmp.v = (EditVert *)newed;
+ }
+ }
+
+ /* first clear edges to help finding neighbours */
+ for(eed = em->edges.last; eed; eed= eed->prev) eed->f1= 0;
+
+ /* put new vertices & edges && flag in best face */
+ mesh_rip_setface(sefa);
+
+ /* starting with neighbours of best face, we loop over the seam */
+ sefa->f1= 2;
+ doit= 1;
+ while(doit) {
+ doit= 0;
+
+ for(efa= em->faces.first; efa; efa=efa->next) {
+ /* new vert in face */
+ if (efa->v1->tmp.v || efa->v2->tmp.v ||
+ efa->v3->tmp.v || (efa->v4 && efa->v4->tmp.v)) {
+ /* face is tagged with loop */
+ if(efa->f1==1) {
+ mesh_rip_setface(efa);
+ efa->f1= 2;
+ doit= 1;
+ }
+ }
+ }
+ }
+
+ /* remove loose edges, that were part of a ripped face */
+ for(eve = em->verts.first; eve; eve= eve->next) eve->f1= 0;
+ for(eed = em->edges.last; eed; eed= eed->prev) eed->f1= 0;
+ for(efa= em->faces.first; efa; efa=efa->next) {
+ efa->e1->f1= 1;
+ efa->e2->f1= 1;
+ efa->e3->f1= 1;
+ if(efa->e4) efa->e4->f1= 1;
+ }
+
+ for(eed = em->edges.last; eed; eed= seed) {
+ seed= eed->prev;
+ if(eed->f1==0) {
+ if(eed->v1->tmp.v || eed->v2->tmp.v ||
+ (eed->v1->f & SELECT) || (eed->v2->f & SELECT)) {
+ remedge(eed);
+ free_editedge(eed);
+ eed= NULL;
+ }
+ }
+ if(eed) {
+ eed->v1->f1= 1;
+ eed->v2->f1= 1;
+ }
+ }
+
+ /* and remove loose selected vertices, that got duplicated accidentally */
+ for(eve = em->verts.first; eve; eve= nextve) {
+ nextve= eve->next;
+ if(eve->f1==0 && (eve->tmp.v || (eve->f & SELECT))) {
+ BLI_remlink(&em->verts,eve);
+ free_editvert(eve);
+ }
+ }
+
+ countall(); // apparently always needed when adding stuff, derived mesh
+
+#ifdef WITH_VERSE
+ if(G.editMesh->vnode) {
+ sync_all_verseverts_with_editverts((VNode*)G.editMesh->vnode);
+ sync_all_versefaces_with_editfaces((VNode*)G.editMesh->vnode);
+ }
+#endif
+
+ BIF_TransformSetUndo("Rip");
+ initTransform(TFM_TRANSLATION, 0);
+ Transform();
+
+ G.scene->prop_mode = propmode;
+ G.scene->proportional = prop;
+}
+
+void shape_propagate(){
+ EditMesh *em = G.editMesh;
+ EditVert *ev = NULL;
+ Mesh* me = (Mesh*)G.obedit->data;
+ Key* ky = NULL;
+ KeyBlock* kb = NULL;
+ Base* base=NULL;
+
+
+ if(me->key){
+ ky = me->key;
+ } else {
+ error("Object Has No Key");
+ return;
+ }
+
+ if(ky->block.first){
+ for(ev = em->verts.first; ev ; ev = ev->next){
+ if(ev->f & SELECT){
+ for(kb=ky->block.first;kb;kb = kb->next){
+ float *data;
+ data = kb->data;
+ VECCOPY(data+(ev->keyindex*3),ev->co);
+ }
+ }
+ }
+ } else {
+ error("Object Has No Blendshapes");
+ return;
+ }
+
+ //TAG Mesh Objects that share this data
+ for(base = G.scene->base.first; base; base = base->next){
+ if(base->object && base->object->data == me){
+ base->object->recalc = OB_RECALC_DATA;
+ }
+ }
+
+ BIF_undo_push("Propagate Blendshape Verts");
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ return;
+}
+
+void shape_copy_from_lerp(KeyBlock* thisBlock, KeyBlock* fromBlock)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *ev = NULL;
+ short mval[2], curval[2], event = 0, finished = 0, canceled = 0, fullcopy=0 ;
+ float perc = 0;
+ char str[64];
+ float *data, *odata;
+
+ data = fromBlock->data;
+ odata = thisBlock->data;
+
+ getmouseco_areawin(mval);
+ curval[0] = mval[0] + 1; curval[1] = mval[1] + 1;
+
+ while (finished == 0)
+ {
+ getmouseco_areawin(mval);
+ if (mval[0] != curval[0] || mval[1] != curval[1])
+ {
+
+ if(mval[0] > curval[0])
+ perc += 0.1;
+ else if(mval[0] < curval[0])
+ perc -= 0.1;
+
+ if(perc < 0) perc = 0;
+ if(perc > 1) perc = 1;
+
+ curval[0] = mval[0];
+ curval[1] = mval[1];
+
+ if(fullcopy == 1){
+ perc = 1;
+ }
+
+ for(ev = em->verts.first; ev ; ev = ev->next){
+ if(ev->f & SELECT){
+ VecLerpf(ev->co,odata+(ev->keyindex*3),data+(ev->keyindex*3),perc);
+ }
+ }
+ sprintf(str,"Blending at %d%c MMB to Copy at 100%c",(int)(perc*100),'%','%');
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ headerprint(str);
+ force_draw(0);
+
+ if(fullcopy == 1){
+ break;
+ }
+
+ } else {
+ PIL_sleep_ms(10);
+ }
+
+ while(qtest()) {
+ short val=0;
+ event= extern_qread(&val);
+ if(val){
+ if(ELEM3(event, PADENTER, LEFTMOUSE, RETKEY)){
+ finished = 1;
+ }
+ else if (event == MIDDLEMOUSE){
+ fullcopy = 1;
+ }
+ else if (ELEM3(event,ESCKEY,RIGHTMOUSE,RIGHTMOUSE)){
+ canceled = 1;
+ finished = 1;
+ }
+ }
+ }
+ }
+ if(!canceled)
+ BIF_undo_push("Copy Blendshape Verts");
+ else
+ for(ev = em->verts.first; ev ; ev = ev->next){
+ if(ev->f & SELECT){
+ VECCOPY(ev->co, odata+(ev->keyindex*3));
+ }
+ }
+ return;
+}
+
+
+
+void shape_copy_select_from()
+{
+ Mesh* me = (Mesh*)G.obedit->data;
+ EditMesh *em = G.editMesh;
+ EditVert *ev = NULL;
+ int totverts = 0,curshape = G.obedit->shapenr;
+
+ Key* ky = NULL;
+ KeyBlock *kb = NULL,*thisBlock = NULL;
+ int maxlen=32, nr=0, a=0;
+ char *menu;
+
+ if(me->key){
+ ky = me->key;
+ } else {
+ error("Object Has No Key");
+ return;
+ }
+
+ if(ky->block.first){
+ for(kb=ky->block.first;kb;kb = kb->next){
+ maxlen += 40; // Size of a block name
+ if(a == curshape-1){
+ thisBlock = kb;
+ }
+
+ a++;
+ }
+ a=0;
+ menu = MEM_callocN(maxlen, "Copy Shape Menu Text");
+ strcpy(menu, "Copy Vert Positions from Shape %t|");
+ for(kb=ky->block.first;kb;kb = kb->next){
+ if(a != curshape-1){
+ sprintf(menu,"%s %s %cx%d|",menu,kb->name,'%',a);
+ }
+ a++;
+ }
+ nr = pupmenu_col(menu, 20);
+ MEM_freeN(menu);
+ } else {
+ error("Object Has No Blendshapes");
+ return;
+ }
+
+ a = 0;
+
+ for(kb=ky->block.first;kb;kb = kb->next){
+ if(a == nr){
+
+ for(ev = em->verts.first;ev;ev = ev->next){
+ totverts++;
+ }
+
+ if(me->totvert != totverts){
+ error("Shape Has had Verts Added/Removed, please cycle editmode before copying");
+ return;
+ }
+ shape_copy_from_lerp(thisBlock,kb);
+
+ return;
+ }
+ a++;
+ }
+ return;
+}
+
+/* Collection Routines|Currently used by the improved merge code*/
+/* buildEdge_collection() creates a list of lists*/
+/* these lists are filled with edges that are topologically connected.*/
+/* This whole tool needs to be redone, its rather poorly implemented...*/
+
+typedef struct Collection{
+ struct Collection *next, *prev;
+ int index;
+ ListBase collectionbase;
+} Collection;
+
+typedef struct CollectedEdge{
+ struct CollectedEdge *next, *prev;
+ EditEdge *eed;
+} CollectedEdge;
+
+#define MERGELIMIT 0.000001
+
+static void build_edgecollection(ListBase *allcollections)
+{
+ EditEdge *eed;
+ Collection *edgecollection, *newcollection;
+ CollectedEdge *newedge;
+
+ int currtag = 1;
+ short ebalanced = 0;
+ short collectionfound = 0;
+
+ for (eed=G.editMesh->edges.first; eed; eed = eed->next){
+ eed->tmp.l = 0;
+ eed->v1->tmp.l = 0;
+ eed->v2->tmp.l = 0;
+ }
+
+ /*1st pass*/
+ for(eed=G.editMesh->edges.first; eed; eed=eed->next){
+ if(eed->f&SELECT){
+ eed->v1->tmp.l = currtag;
+ eed->v2->tmp.l = currtag;
+ currtag +=1;
+ }
+ }
+
+ /*2nd pass - Brute force. Loop through selected faces until there are no 'unbalanced' edges left (those with both vertices 'tmp.l' tag matching */
+ while(ebalanced == 0){
+ ebalanced = 1;
+ for(eed=G.editMesh->edges.first; eed; eed = eed->next){
+ if(eed->f&SELECT){
+ if(eed->v1->tmp.l != eed->v2->tmp.l) /*unbalanced*/{
+ if(eed->v1->tmp.l > eed->v2->tmp.l && eed->v2->tmp.l !=0) eed->v1->tmp.l = eed->v2->tmp.l;
+ else if(eed->v1 != 0) eed->v2->tmp.l = eed->v1->tmp.l;
+ ebalanced = 0;
+ }
+ }
+ }
+ }
+
+ /*3rd pass, set all the edge flags (unnessecary?)*/
+ for(eed=G.editMesh->edges.first; eed; eed = eed->next){
+ if(eed->f&SELECT) eed->tmp.l = eed->v1->tmp.l;
+ }
+
+ for(eed=G.editMesh->edges.first; eed; eed=eed->next){
+ if(eed->f&SELECT){
+ if(allcollections->first){
+ for(edgecollection = allcollections->first; edgecollection; edgecollection=edgecollection->next){
+ if(edgecollection->index == eed->tmp.l){
+ newedge = MEM_mallocN(sizeof(CollectedEdge), "collected edge");
+ newedge->eed = eed;
+ BLI_addtail(&(edgecollection->collectionbase), newedge);
+ collectionfound = 1;
+ break;
+ }
+ else collectionfound = 0;
+ }
+ }
+ if(allcollections->first == NULL || collectionfound == 0){
+ newcollection = MEM_mallocN(sizeof(Collection), "element collection");
+ newcollection->index = eed->tmp.l;
+ newcollection->collectionbase.first = 0;
+ newcollection->collectionbase.last = 0;
+
+ newedge = MEM_mallocN(sizeof(CollectedEdge), "collected edge");
+ newedge->eed = eed;
+
+ BLI_addtail(&(newcollection->collectionbase), newedge);
+ BLI_addtail(allcollections, newcollection);
+ }
+ }
+
+ }
+}
+
+static void freecollections(ListBase *allcollections)
+{
+ struct Collection *curcollection;
+
+ for(curcollection = allcollections->first; curcollection; curcollection = curcollection->next)
+ BLI_freelistN(&(curcollection->collectionbase));
+ BLI_freelistN(allcollections);
+}
+
+/*Begin UV Edge Collapse Code
+ Like Edge subdivide, Edge Collapse should handle UV's intelligently, but since UV's are a per-face attribute, normal edge collapse will fail
+ in areas such as the boundries of 'UV islands'. So for each edge collection we need to build a set of 'welded' UV vertices and edges for it.
+ The welded UV edges can then be sorted and collapsed.
+*/
+typedef struct wUV{
+ struct wUV *next, *prev;
+ ListBase nodes;
+ float u, v; /*cached copy of UV coordinates pointed to by nodes*/
+ EditVert *eve;
+ int f;
+} wUV;
+
+typedef struct wUVNode{
+ struct wUVNode *next, *prev;
+ float *u; /*pointer to original tface data*/
+ float *v; /*pointer to original tface data*/
+} wUVNode;
+
+typedef struct wUVEdge{
+ struct wUVEdge *next, *prev;
+ float v1uv[2], v2uv[2]; /*nasty.*/
+ struct wUV *v1, *v2; /*oriented same as editedge*/
+ EditEdge *eed;
+ int f;
+} wUVEdge;
+
+typedef struct wUVEdgeCollect{ /*used for grouping*/
+ struct wUVEdgeCollect *next, *prev;
+ wUVEdge *uved;
+ int id;
+} wUVEdgeCollect;
+
+static void append_weldedUV(EditFace *efa, EditVert *eve, int tfindex, ListBase *uvverts)
+{
+ wUV *curwvert, *newwvert;
+ wUVNode *newnode;
+ int found;
+ MTFace *tf = CustomData_em_get(&G.editMesh->fdata, efa->data, CD_MTFACE);
+
+ found = 0;
+
+ for(curwvert=uvverts->first; curwvert; curwvert=curwvert->next){
+ if(curwvert->eve == eve && curwvert->u == tf->uv[tfindex][0] && curwvert->v == tf->uv[tfindex][1]){
+ newnode = MEM_callocN(sizeof(wUVNode), "Welded UV Vert Node");
+ newnode->u = &(tf->uv[tfindex][0]);
+ newnode->v = &(tf->uv[tfindex][1]);
+ BLI_addtail(&(curwvert->nodes), newnode);
+ found = 1;
+ break;
+ }
+ }
+
+ if(!found){
+ newnode = MEM_callocN(sizeof(wUVNode), "Welded UV Vert Node");
+ newnode->u = &(tf->uv[tfindex][0]);
+ newnode->v = &(tf->uv[tfindex][1]);
+
+ newwvert = MEM_callocN(sizeof(wUV), "Welded UV Vert");
+ newwvert->u = *(newnode->u);
+ newwvert->v = *(newnode->v);
+ newwvert->eve = eve;
+
+ BLI_addtail(&(newwvert->nodes), newnode);
+ BLI_addtail(uvverts, newwvert);
+
+ }
+}
+
+static void build_weldedUVs(ListBase *uvverts)
+{
+ EditFace *efa;
+ for(efa=G.editMesh->faces.first; efa; efa=efa->next){
+ if(efa->v1->f1) append_weldedUV(efa, efa->v1, 0, uvverts);
+ if(efa->v2->f1) append_weldedUV(efa, efa->v2, 1, uvverts);
+ if(efa->v3->f1) append_weldedUV(efa, efa->v3, 2, uvverts);
+ if(efa->v4 && efa->v4->f1) append_weldedUV(efa, efa->v4, 3, uvverts);
+ }
+}
+
+static void append_weldedUVEdge(EditFace *efa, EditEdge *eed, ListBase *uvedges)
+{
+ wUVEdge *curwedge, *newwedge;
+ int v1tfindex, v2tfindex, found;
+ MTFace *tf = CustomData_em_get(&G.editMesh->fdata, efa->data, CD_MTFACE);
+
+ found = 0;
+
+ if(eed->v1 == efa->v1) v1tfindex = 0;
+ else if(eed->v1 == efa->v2) v1tfindex = 1;
+ else if(eed->v1 == efa->v3) v1tfindex = 2;
+ else /* if(eed->v1 == efa->v4) */ v1tfindex = 3;
+
+ if(eed->v2 == efa->v1) v2tfindex = 0;
+ else if(eed->v2 == efa->v2) v2tfindex = 1;
+ else if(eed->v2 == efa->v3) v2tfindex = 2;
+ else /* if(eed->v2 == efa->v4) */ v2tfindex = 3;
+
+ for(curwedge=uvedges->first; curwedge; curwedge=curwedge->next){
+ if(curwedge->eed == eed && curwedge->v1uv[0] == tf->uv[v1tfindex][0] && curwedge->v1uv[1] == tf->uv[v1tfindex][1] && curwedge->v2uv[0] == tf->uv[v2tfindex][0] && curwedge->v2uv[1] == tf->uv[v2tfindex][1]){
+ found = 1;
+ break; //do nothing, we don't need another welded uv edge
+ }
+ }
+
+ if(!found){
+ newwedge = MEM_callocN(sizeof(wUVEdge), "Welded UV Edge");
+ newwedge->v1uv[0] = tf->uv[v1tfindex][0];
+ newwedge->v1uv[1] = tf->uv[v1tfindex][1];
+ newwedge->v2uv[0] = tf->uv[v2tfindex][0];
+ newwedge->v2uv[1] = tf->uv[v2tfindex][1];
+ newwedge->eed = eed;
+
+ BLI_addtail(uvedges, newwedge);
+ }
+}
+
+static void build_weldedUVEdges(ListBase *uvedges, ListBase *uvverts)
+{
+ wUV *curwvert;
+ wUVEdge *curwedge;
+ EditFace *efa;
+
+ for(efa=G.editMesh->faces.first; efa; efa=efa->next){
+ if(efa->e1->f1) append_weldedUVEdge(efa, efa->e1, uvedges);
+ if(efa->e2->f1) append_weldedUVEdge(efa, efa->e2, uvedges);
+ if(efa->e3->f1) append_weldedUVEdge(efa, efa->e3, uvedges);
+ if(efa->e4 && efa->e4->f1) append_weldedUVEdge(efa, efa->e4, uvedges);
+ }
+
+
+ //link vertices: for each uvedge, search uvverts to populate v1 and v2 pointers
+ for(curwedge=uvedges->first; curwedge; curwedge=curwedge->next){
+ for(curwvert=uvverts->first; curwvert; curwvert=curwvert->next){
+ if(curwedge->eed->v1 == curwvert->eve && curwedge->v1uv[0] == curwvert->u && curwedge->v1uv[1] == curwvert->v){
+ curwedge->v1 = curwvert;
+ break;
+ }
+ }
+ for(curwvert=uvverts->first; curwvert; curwvert=curwvert->next){
+ if(curwedge->eed->v2 == curwvert->eve && curwedge->v2uv[0] == curwvert->u && curwedge->v2uv[1] == curwvert->v){
+ curwedge->v2 = curwvert;
+ break;
+ }
+ }
+ }
+}
+
+static void free_weldedUVs(ListBase *uvverts)
+{
+ wUV *curwvert;
+ for(curwvert = uvverts->first; curwvert; curwvert=curwvert->next) BLI_freelistN(&(curwvert->nodes));
+ BLI_freelistN(uvverts);
+}
+
+static void collapse_edgeuvs(void)
+{
+ ListBase uvedges, uvverts, allcollections;
+ wUVEdge *curwedge;
+ wUVNode *curwnode;
+ wUVEdgeCollect *collectedwuve, *newcollectedwuve;
+ Collection *wuvecollection, *newcollection;
+ int curtag, balanced, collectionfound= 0, vcount;
+ float avg[2];
+
+ if (!EM_texFaceCheck())
+ return;
+
+ uvverts.first = uvverts.last = uvedges.first = uvedges.last = allcollections.first = allcollections.last = NULL;
+
+ build_weldedUVs(&uvverts);
+ build_weldedUVEdges(&uvedges, &uvverts);
+
+ curtag = 0;
+
+ for(curwedge=uvedges.first; curwedge; curwedge=curwedge->next){
+ curwedge->v1->f = curtag;
+ curwedge->v2->f = curtag;
+ curtag +=1;
+ }
+
+ balanced = 0;
+ while(!balanced){
+ balanced = 1;
+ for(curwedge=uvedges.first; curwedge; curwedge=curwedge->next){
+ if(curwedge->v1->f != curwedge->v2->f){
+ if(curwedge->v1->f > curwedge->v2->f) curwedge->v1->f = curwedge->v2->f;
+ else curwedge->v2->f = curwedge->v1->f;
+ balanced = 0;
+ }
+ }
+ }
+
+ for(curwedge=uvedges.first; curwedge; curwedge=curwedge->next) curwedge->f = curwedge->v1->f;
+
+
+ for(curwedge=uvedges.first; curwedge; curwedge=curwedge->next){
+ if(allcollections.first){
+ for(wuvecollection = allcollections.first; wuvecollection; wuvecollection=wuvecollection->next){
+ if(wuvecollection->index == curwedge->f){
+ newcollectedwuve = MEM_callocN(sizeof(wUVEdgeCollect), "Collected Welded UV Edge");
+ newcollectedwuve->uved = curwedge;
+ BLI_addtail(&(wuvecollection->collectionbase), newcollectedwuve);
+ collectionfound = 1;
+ break;
+ }
+
+ else collectionfound = 0;
+ }
+ }
+ if(allcollections.first == NULL || collectionfound == 0){
+ newcollection = MEM_callocN(sizeof(Collection), "element collection");
+ newcollection->index = curwedge->f;
+ newcollection->collectionbase.first = 0;
+ newcollection->collectionbase.last = 0;
+
+ newcollectedwuve = MEM_callocN(sizeof(wUVEdgeCollect), "Collected Welded UV Edge");
+ newcollectedwuve->uved = curwedge;
+
+ BLI_addtail(&(newcollection->collectionbase), newcollectedwuve);
+ BLI_addtail(&allcollections, newcollection);
+ }
+ }
+
+ for(wuvecollection=allcollections.first; wuvecollection; wuvecollection=wuvecollection->next){
+
+ vcount = avg[0] = avg[1] = 0;
+
+ for(collectedwuve= wuvecollection->collectionbase.first; collectedwuve; collectedwuve = collectedwuve->next){
+ avg[0] += collectedwuve->uved->v1uv[0];
+ avg[1] += collectedwuve->uved->v1uv[1];
+
+ avg[0] += collectedwuve->uved->v2uv[0];
+ avg[1] += collectedwuve->uved->v2uv[1];
+
+ vcount +=2;
+
+ }
+
+ avg[0] /= vcount; avg[1] /= vcount;
+
+ for(collectedwuve= wuvecollection->collectionbase.first; collectedwuve; collectedwuve = collectedwuve->next){
+ for(curwnode=collectedwuve->uved->v1->nodes.first; curwnode; curwnode=curwnode->next){
+ *(curwnode->u) = avg[0];
+ *(curwnode->v) = avg[1];
+ }
+ for(curwnode=collectedwuve->uved->v2->nodes.first; curwnode; curwnode=curwnode->next){
+ *(curwnode->u) = avg[0];
+ *(curwnode->v) = avg[1];
+ }
+ }
+ }
+
+ free_weldedUVs(&uvverts);
+ BLI_freelistN(&uvedges);
+ freecollections(&allcollections);
+}
+
+/*End UV Edge collapse code*/
+
+static void collapseuvs(void)
+{
+ EditFace *efa;
+ MTFace *tf;
+ int uvcount;
+ float uvav[2];
+
+ if (!EM_texFaceCheck())
+ return;
+
+ uvcount = 0;
+ uvav[0] = 0;
+ uvav[1] = 0;
+
+ for(efa = G.editMesh->faces.first; efa; efa=efa->next){
+ tf = CustomData_em_get(&G.editMesh->fdata, efa->data, CD_MTFACE);
+
+ if(efa->v1->f1){
+ uvav[0] += tf->uv[0][0];
+ uvav[1] += tf->uv[0][1];
+ uvcount += 1;
+ }
+ if(efa->v2->f1){
+ uvav[0] += tf->uv[1][0];
+ uvav[1] += tf->uv[1][1];
+ uvcount += 1;
+ }
+ if(efa->v3->f1){
+ uvav[0] += tf->uv[2][0];
+ uvav[1] += tf->uv[2][1];
+ uvcount += 1;
+ }
+ if(efa->v4 && efa->v4->f1){
+ uvav[0] += tf->uv[3][0];
+ uvav[1] += tf->uv[3][1];
+ uvcount += 1;
+ }
+ }
+
+ if(uvcount > 0) {
+ uvav[0] /= uvcount;
+ uvav[1] /= uvcount;
+
+ for(efa = G.editMesh->faces.first; efa; efa=efa->next){
+ tf = CustomData_em_get(&G.editMesh->fdata, efa->data, CD_MTFACE);
+
+ if(efa->v1->f1){
+ tf->uv[0][0] = uvav[0];
+ tf->uv[0][1] = uvav[1];
+ }
+ if(efa->v2->f1){
+ tf->uv[1][0] = uvav[0];
+ tf->uv[1][1] = uvav[1];
+ }
+ if(efa->v3->f1){
+ tf->uv[2][0] = uvav[0];
+ tf->uv[2][1] = uvav[1];
+ }
+ if(efa->v4 && efa->v4->f1){
+ tf->uv[3][0] = uvav[0];
+ tf->uv[3][1] = uvav[1];
+ }
+ }
+ }
+}
+
+int collapseEdges(void)
+{
+ EditVert *eve;
+ EditEdge *eed;
+
+ ListBase allcollections;
+ CollectedEdge *curredge;
+ Collection *edgecollection;
+
+ int totedges, groupcount, mergecount,vcount;
+ float avgcount[3];
+
+ allcollections.first = 0;
+ allcollections.last = 0;
+
+ mergecount = 0;
+
+ if(multires_test()) return 0;
+
+ build_edgecollection(&allcollections);
+ groupcount = BLI_countlist(&allcollections);
+
+
+ for(edgecollection = allcollections.first; edgecollection; edgecollection = edgecollection->next){
+ totedges = BLI_countlist(&(edgecollection->collectionbase));
+ mergecount += totedges;
+ avgcount[0] = 0; avgcount[1] = 0; avgcount[2] = 0;
+
+ vcount = 0;
+
+ for(curredge = edgecollection->collectionbase.first; curredge; curredge = curredge->next){
+ avgcount[0] += ((EditEdge*)curredge->eed)->v1->co[0];
+ avgcount[1] += ((EditEdge*)curredge->eed)->v1->co[1];
+ avgcount[2] += ((EditEdge*)curredge->eed)->v1->co[2];
+
+ avgcount[0] += ((EditEdge*)curredge->eed)->v2->co[0];
+ avgcount[1] += ((EditEdge*)curredge->eed)->v2->co[1];
+ avgcount[2] += ((EditEdge*)curredge->eed)->v2->co[2];
+
+ vcount +=2;
+ }
+
+ avgcount[0] /= vcount; avgcount[1] /=vcount; avgcount[2] /= vcount;
+
+ for(curredge = edgecollection->collectionbase.first; curredge; curredge = curredge->next){
+ VECCOPY(((EditEdge*)curredge->eed)->v1->co,avgcount);
+ VECCOPY(((EditEdge*)curredge->eed)->v2->co,avgcount);
+ }
+
+ if (EM_texFaceCheck()) {
+ /*uv collapse*/
+ for(eve=G.editMesh->verts.first; eve; eve=eve->next) eve->f1 = 0;
+ for(eed=G.editMesh->edges.first; eed; eed=eed->next) eed->f1 = 0;
+ for(curredge = edgecollection->collectionbase.first; curredge; curredge = curredge->next){
+ curredge->eed->v1->f1 = 1;
+ curredge->eed->v2->f1 = 1;
+ curredge->eed->f1 = 1;
+ }
+ collapse_edgeuvs();
+ }
+
+ }
+ freecollections(&allcollections);
+ removedoublesflag(1, 0, MERGELIMIT);
+ /*get rid of this!*/
+ countall();
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ if (EM_texFaceCheck())
+ allqueue(REDRAWIMAGE, 0);
+ return mergecount;
+}
+
+int merge_firstlast(int first, int uvmerge)
+{
+ EditVert *eve,*mergevert;
+ EditSelection *ese;
+
+ if(multires_test()) return 0;
+
+ /* do sanity check in mergemenu in edit.c ?*/
+ if(first == 0){
+ ese = G.editMesh->selected.last;
+ mergevert= (EditVert*)ese->data;
+ }
+ else{
+ ese = G.editMesh->selected.first;
+ mergevert = (EditVert*)ese->data;
+ }
+
+ if(mergevert->f&SELECT){
+ for (eve=G.editMesh->verts.first; eve; eve=eve->next){
+ if (eve->f&SELECT)
+ VECCOPY(eve->co,mergevert->co);
+ }
+ }
+
+ if(uvmerge && CustomData_has_layer(&G.editMesh->fdata, CD_MTFACE)){
+
+ for(eve=G.editMesh->verts.first; eve; eve=eve->next) eve->f1 = 0;
+ for(eve=G.editMesh->verts.first; eve; eve=eve->next){
+ if(eve->f&SELECT) eve->f1 = 1;
+ }
+ collapseuvs();
+ }
+
+ countall();
+ return removedoublesflag(1, 0, MERGELIMIT);
+}
+
+int merge_target(int target, int uvmerge)
+{
+ EditVert *eve;
+
+ if(multires_test()) return 0;
+
+ if(target) snap_sel_to_curs();
+ else snap_to_center();
+
+ if(uvmerge && CustomData_has_layer(&G.editMesh->fdata, CD_MTFACE)){
+ for(eve=G.editMesh->verts.first; eve; eve=eve->next) eve->f1 = 0;
+ for(eve=G.editMesh->verts.first; eve; eve=eve->next){
+ if(eve->f&SELECT) eve->f1 = 1;
+ }
+ collapseuvs();
+ }
+
+ countall();
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ return removedoublesflag(1, 0, MERGELIMIT);
+
+}
+#undef MERGELIMIT
+
+typedef struct PathNode{
+ int u;
+ int visited;
+ ListBase edges;
+} PathNode;
+
+typedef struct PathEdge{
+ struct PathEdge *next, *prev;
+ int v;
+ float w;
+} PathEdge;
+
+void pathselect(void)
+{
+ EditVert *eve, *s, *t;
+ EditEdge *eed;
+ EditSelection *ese;
+ PathEdge *newpe, *currpe;
+ PathNode *currpn;
+ PathNode *Q;
+ int v, *previous, pathvert, pnindex; /*pnindex redundant?*/
+ int unbalanced, totnodes;
+ short physical;
+ float *cost;
+ Heap *heap; /*binary heap for sorting pointers to PathNodes based upon a 'cost'*/
+
+ s = t = NULL;
+
+ countall(); /*paranoid?*/
+
+ ese = ((EditSelection*)G.editMesh->selected.last);
+ if(ese && ese->type == EDITVERT && ese->prev && ese->prev->type == EDITVERT){
+ physical= pupmenu("Distance Method? %t|Edge Length%x1|Topological%x0");
+
+ t = (EditVert*)ese->data;
+ s = (EditVert*)ese->prev->data;
+
+ /*need to find out if t is actually reachable by s....*/
+ for(eve=G.editMesh->verts.first; eve; eve=eve->next){
+ eve->f1 = 0;
+ }
+
+ s->f1 = 1;
+
+ unbalanced = 1;
+ totnodes = 1;
+ while(unbalanced){
+ unbalanced = 0;
+ for(eed=G.editMesh->edges.first; eed; eed=eed->next){
+ if(!eed->h){
+ if(eed->v1->f1 && !eed->v2->f1){
+ eed->v2->f1 = 1;
+ totnodes++;
+ unbalanced = 1;
+ }
+ else if(eed->v2->f1 && !eed->v1->f1){
+ eed->v1->f1 = 1;
+ totnodes++;
+ unbalanced = 1;
+ }
+ }
+ }
+ }
+
+
+
+ if(s->f1 && t->f1){ /*t can be reached by s*/
+ Q = MEM_callocN(sizeof(PathNode)*totnodes, "Path Select Nodes");
+ totnodes = 0;
+ for(eve=G.editMesh->verts.first; eve; eve=eve->next){
+ if(eve->f1){
+ Q[totnodes].u = totnodes;
+ Q[totnodes].edges.first = 0;
+ Q[totnodes].edges.last = 0;
+ Q[totnodes].visited = 0;
+ eve->tmp.p = &(Q[totnodes]);
+ totnodes++;
+ }
+ else eve->tmp.p = NULL;
+ }
+
+ for(eed=G.editMesh->edges.first; eed; eed=eed->next){
+ if(!eed->h){
+ if(eed->v1->f1){
+ currpn = ((PathNode*)eed->v1->tmp.p);
+
+ newpe = MEM_mallocN(sizeof(PathEdge), "Path Edge");
+ newpe->v = ((PathNode*)eed->v2->tmp.p)->u;
+ if(physical){
+ newpe->w = VecLenf(eed->v1->co, eed->v2->co);
+ }
+ else newpe->w = 1;
+ newpe->next = 0;
+ newpe->prev = 0;
+ BLI_addtail(&(currpn->edges), newpe);
+ }
+ if(eed->v2->f1){
+ currpn = ((PathNode*)eed->v2->tmp.p);
+ newpe = MEM_mallocN(sizeof(PathEdge), "Path Edge");
+ newpe->v = ((PathNode*)eed->v1->tmp.p)->u;
+ if(physical){
+ newpe->w = VecLenf(eed->v1->co, eed->v2->co);
+ }
+ else newpe->w = 1;
+ newpe->next = 0;
+ newpe->prev = 0;
+ BLI_addtail(&(currpn->edges), newpe);
+ }
+ }
+ }
+
+ heap = BLI_heap_new();
+ cost = MEM_callocN(sizeof(float)*totnodes, "Path Select Costs");
+ previous = MEM_callocN(sizeof(int)*totnodes, "PathNode indices");
+
+ for(v=0; v < totnodes; v++){
+ cost[v] = 1000000;
+ previous[v] = -1; /*array of indices*/
+ }
+
+ pnindex = ((PathNode*)s->tmp.p)->u;
+ cost[pnindex] = 0;
+ BLI_heap_insert(heap, 0.0f, (void*)pnindex);
+
+ while( !BLI_heap_empty(heap) ){
+
+ pnindex = (int)BLI_heap_popmin(heap);
+ currpn = &(Q[pnindex]);
+
+ if(currpn == (PathNode*)t->tmp.p) /*target has been reached....*/
+ break;
+
+ for(currpe=currpn->edges.first; currpe; currpe=currpe->next){
+ if(!Q[currpe->v].visited){
+ if( cost[currpe->v] > (cost[currpn->u ] + currpe->w) ){
+ cost[currpe->v] = cost[currpn->u] + currpe->w;
+ previous[currpe->v] = currpn->u;
+ Q[currpe->v].visited = 1;
+ BLI_heap_insert(heap, cost[currpe->v], (void*)currpe->v);
+ }
+ }
+ }
+ }
+
+ pathvert = ((PathNode*)t->tmp.p)->u;
+ while(pathvert != -1){
+ for(eve=G.editMesh->verts.first; eve; eve=eve->next){
+ if(eve->f1){
+ if( ((PathNode*)eve->tmp.p)->u == pathvert) eve->f |= SELECT;
+ }
+ }
+ pathvert = previous[pathvert];
+ }
+
+ for(v=0; v < totnodes; v++) BLI_freelistN(&(Q[v].edges));
+ MEM_freeN(Q);
+ MEM_freeN(cost);
+ MEM_freeN(previous);
+ BLI_heap_free(heap, NULL);
+ EM_select_flush();
+ countall();
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ if (EM_texFaceCheck())
+ allqueue(REDRAWIMAGE, 0);
+ }
+ }
+ else{
+ error("Path Selection requires that exactly two vertices be selected");
+ return;
+ }
+}
+
+void region_to_loop(void)
+{
+ EditEdge *eed;
+ EditFace *efa;
+
+ if(G.totfacesel){
+ for(eed=G.editMesh->edges.first; eed; eed=eed->next) eed->f1 = 0;
+
+ for(efa=G.editMesh->faces.first; efa; efa=efa->next){
+ if(efa->f&SELECT){
+ efa->e1->f1++;
+ efa->e2->f1++;
+ efa->e3->f1++;
+ if(efa->e4)
+ efa->e4->f1++;
+ }
+ }
+
+ EM_clear_flag_all(SELECT);
+
+ for(eed=G.editMesh->edges.first; eed; eed=eed->next){
+ if(eed->f1 == 1) EM_select_edge(eed, 1);
+ }
+
+ G.scene->selectmode = SCE_SELECT_EDGE;
+ EM_selectmode_set();
+ countall();
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ if (EM_texFaceCheck())
+ allqueue(REDRAWIMAGE, 0);
+ BIF_undo_push("Face Region to Edge Loop");
+
+ }
+}
+
+static int validate_loop(Collection *edgecollection)
+{
+ EditEdge *eed;
+ EditFace *efa;
+ CollectedEdge *curredge;
+
+ /*1st test*/
+ for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next){
+ curredge->eed->v1->f1 = 0;
+ curredge->eed->v2->f1 = 0;
+ }
+ for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next){
+ curredge->eed->v1->f1++;
+ curredge->eed->v2->f1++;
+ }
+ for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next){
+ if(curredge->eed->v1->f1 > 2) return(0); else
+ if(curredge->eed->v2->f1 > 2) return(0);
+ }
+
+ /*2nd test*/
+ for(eed = G.editMesh->edges.first; eed; eed=eed->next) eed->f1 = 0;
+ for(efa=G.editMesh->faces.first; efa; efa=efa->next){
+ efa->e1->f1++;
+ efa->e2->f1++;
+ efa->e3->f1++;
+ if(efa->e4) efa->e4->f1++;
+ }
+ for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next){
+ if(curredge->eed->f1 > 2) return(0);
+ }
+ return(1);
+}
+
+static int loop_bisect(Collection *edgecollection){
+
+ EditFace *efa, *sf1, *sf2;
+ EditEdge *eed, *sed;
+ CollectedEdge *curredge;
+ int totsf1, totsf2, unbalanced,balancededges;
+
+ for(eed=G.editMesh->edges.first; eed; eed=eed->next) eed->f1 = eed->f2 = 0;
+ for(efa=G.editMesh->faces.first; efa; efa=efa->next) efa->f1 = 0;
+
+ for(curredge = (CollectedEdge*)edgecollection->collectionbase.first; curredge; curredge=curredge->next) curredge->eed->f1 = 1;
+
+ sf1 = sf2 = NULL;
+ sed = ((CollectedEdge*)edgecollection->collectionbase.first)->eed;
+
+ for(efa=G.editMesh->faces.first; efa; efa=efa->next){
+ if(sf2) break;
+ else if(sf1){
+ if(efa->e1 == sed || efa->e2 == sed || efa->e3 == sed || ( (efa->e4) ? efa->e4 == sed : 0) ) sf2 = efa;
+ }
+ else{
+ if(efa->e1 == sed || efa->e2 == sed || efa->e3 == sed || ( (efa->e4) ? efa->e4 == sed : 0) ) sf1 = efa;
+ }
+ }
+
+ if(sf1==NULL || sf2==NULL)
+ return(-1);
+
+ if(!(sf1->e1->f1)) sf1->e1->f2 = 1;
+ if(!(sf1->e2->f1)) sf1->e2->f2 = 1;
+ if(!(sf1->e3->f1)) sf1->e3->f2 = 1;
+ if(sf1->e4 && !(sf1->e4->f1)) sf1->e4->f2 = 1;
+ sf1->f1 = 1;
+ totsf1 = 1;
+
+ if(!(sf2->e1->f1)) sf2->e1->f2 = 2;
+ if(!(sf2->e2->f1)) sf2->e2->f2 = 2;
+ if(!(sf2->e3->f1)) sf2->e3->f2 = 2;
+ if(sf2->e4 && !(sf2->e4->f1)) sf2->e4->f2 = 2;
+ sf2->f1 = 2;
+ totsf2 = 1;
+
+ /*do sf1*/
+ unbalanced = 1;
+ while(unbalanced){
+ unbalanced = 0;
+ for(efa=G.editMesh->faces.first; efa; efa=efa->next){
+ balancededges = 0;
+ if(efa->f1 == 0){
+ if(efa->e1->f2 == 1 || efa->e2->f2 == 1 || efa->e3->f2 == 1 || ( (efa->e4) ? efa->e4->f2 == 1 : 0) ){
+ balancededges += efa->e1->f2 = (efa->e1->f1) ? 0 : 1;
+ balancededges += efa->e2->f2 = (efa->e2->f1) ? 0 : 1;
+ balancededges += efa->e3->f2 = (efa->e3->f1) ? 0 : 1;
+ if(efa->e4) balancededges += efa->e4->f2 = (efa->e4->f1) ? 0 : 1;
+ if(balancededges){
+ unbalanced = 1;
+ efa->f1 = 1;
+ totsf1++;
+ }
+ }
+ }
+ }
+ }
+
+ /*do sf2*/
+ unbalanced = 1;
+ while(unbalanced){
+ unbalanced = 0;
+ for(efa=G.editMesh->faces.first; efa; efa=efa->next){
+ balancededges = 0;
+ if(efa->f1 == 0){
+ if(efa->e1->f2 == 2 || efa->e2->f2 == 2 || efa->e3->f2 == 2 || ( (efa->e4) ? efa->e4->f2 == 2 : 0) ){
+ balancededges += efa->e1->f2 = (efa->e1->f1) ? 0 : 2;
+ balancededges += efa->e2->f2 = (efa->e2->f1) ? 0 : 2;
+ balancededges += efa->e3->f2 = (efa->e3->f1) ? 0 : 2;
+ if(efa->e4) balancededges += efa->e4->f2 = (efa->e4->f1) ? 0 : 2;
+ if(balancededges){
+ unbalanced = 1;
+ efa->f1 = 2;
+ totsf2++;
+ }
+ }
+ }
+ }
+ }
+
+ if(totsf1 < totsf2) return(1);
+ else return(2);
+}
+
+void loop_to_region(void)
+{
+ EditFace *efa;
+ ListBase allcollections={NULL,NULL};
+ Collection *edgecollection;
+ int testflag;
+
+ build_edgecollection(&allcollections);
+
+ for(edgecollection = (Collection *)allcollections.first; edgecollection; edgecollection=edgecollection->next){
+ if(validate_loop(edgecollection)){
+ testflag = loop_bisect(edgecollection);
+ for(efa=G.editMesh->faces.first; efa; efa=efa->next){
+ if(efa->f1 == testflag){
+ if(efa->f&SELECT) EM_select_face(efa, 0);
+ else EM_select_face(efa,1);
+ }
+ }
+ }
+ }
+
+ for(efa=G.editMesh->faces.first; efa; efa=efa->next){ /*fix this*/
+ if(efa->f&SELECT) EM_select_face(efa,1);
+ }
+
+ countall();
+ freecollections(&allcollections);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ if (EM_texFaceCheck())
+ allqueue(REDRAWIMAGE, 0);
+ BIF_undo_push("Edge Loop to Face Region");
+}
+
+
+/* texface and vertex color editmode tools for the face menu */
+
+void mesh_rotate_uvs(void)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+ short change = 0, ccw;
+ MTFace *tf;
+ float u1, v1;
+
+ if (!EM_texFaceCheck()) {
+ error("mesh has no uv/image layers");
+ return;
+ }
+
+ ccw = (G.qual == LR_SHIFTKEY);
+
+ for(efa=em->faces.first; efa; efa=efa->next) {
+ if (efa->f & SELECT) {
+ tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ u1= tf->uv[0][0];
+ v1= tf->uv[0][1];
+
+ if (ccw) {
+ if(efa->v4) {
+ tf->uv[0][0]= tf->uv[3][0];
+ tf->uv[0][1]= tf->uv[3][1];
+
+ tf->uv[3][0]= tf->uv[2][0];
+ tf->uv[3][1]= tf->uv[2][1];
+ } else {
+ tf->uv[0][0]= tf->uv[2][0];
+ tf->uv[0][1]= tf->uv[2][1];
+ }
+
+ tf->uv[2][0]= tf->uv[1][0];
+ tf->uv[2][1]= tf->uv[1][1];
+
+ tf->uv[1][0]= u1;
+ tf->uv[1][1]= v1;
+ } else {
+ tf->uv[0][0]= tf->uv[1][0];
+ tf->uv[0][1]= tf->uv[1][1];
+
+ tf->uv[1][0]= tf->uv[2][0];
+ tf->uv[1][1]= tf->uv[2][1];
+
+ if(efa->v4) {
+ tf->uv[2][0]= tf->uv[3][0];
+ tf->uv[2][1]= tf->uv[3][1];
+
+ tf->uv[3][0]= u1;
+ tf->uv[3][1]= v1;
+ }
+ else {
+ tf->uv[2][0]= u1;
+ tf->uv[2][1]= v1;
+ }
+ }
+ change = 1;
+ }
+ }
+
+ if (change) {
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ BIF_undo_push("Rotate UV face");
+ }
+}
+
+void mesh_mirror_uvs(void)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+ short change = 0;
+ MTFace *tf;
+ float u1, v1;
+
+ if (!EM_texFaceCheck()) {
+ error("mesh has no uv/image layers");
+ return;
+ }
+
+ for(efa=em->faces.first; efa; efa=efa->next) {
+ if (efa->f & SELECT) {
+ tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ u1= tf->uv[0][0];
+ v1= tf->uv[0][1];
+ if(efa->v4) {
+ tf->uv[0][0]= tf->uv[3][0];
+ tf->uv[0][1]= tf->uv[3][1];
+
+ tf->uv[3][0]= u1;
+ tf->uv[3][1]= v1;
+
+ u1= tf->uv[1][0];
+ v1= tf->uv[1][1];
+
+ tf->uv[1][0]= tf->uv[2][0];
+ tf->uv[1][1]= tf->uv[2][1];
+
+ tf->uv[2][0]= u1;
+ tf->uv[2][1]= v1;
+ }
+ else {
+ tf->uv[0][0]= tf->uv[2][0];
+ tf->uv[0][1]= tf->uv[2][1];
+ tf->uv[2][0]= u1;
+ tf->uv[2][1]= v1;
+ }
+ change = 1;
+ }
+ }
+
+ if (change) {
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ BIF_undo_push("Mirror UV face");
+ }
+}
+
+void mesh_rotate_colors(void)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+ short change = 0, ccw;
+ MCol tmpcol, *mcol;
+ if (!EM_vertColorCheck()) {
+ error("mesh has no color layers");
+ return;
+ }
+
+ ccw = (G.qual == LR_SHIFTKEY);
+
+ for(efa=em->faces.first; efa; efa=efa->next) {
+ if (efa->f & SELECT) {
+ mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
+ tmpcol= mcol[0];
+
+ if (ccw) {
+ if(efa->v4) {
+ mcol[0]= mcol[3];
+ mcol[3]= mcol[2];
+ } else {
+ mcol[0]= mcol[2];
+ }
+ mcol[2]= mcol[1];
+ mcol[1]= tmpcol;
+ } else {
+ mcol[0]= mcol[1];
+ mcol[1]= mcol[2];
+
+ if(efa->v4) {
+ mcol[2]= mcol[3];
+ mcol[3]= tmpcol;
+ }
+ else
+ mcol[2]= tmpcol;
+ }
+ change = 1;
+ }
+ }
+
+ if (change) {
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ BIF_undo_push("Rotate Color face");
+ }
+}
+
+void mesh_mirror_colors(void)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+ short change = 0;
+ MCol tmpcol, *mcol;
+ if (!EM_vertColorCheck()) {
+ error("mesh has no color layers");
+ return;
+ }
+
+ for(efa=em->faces.first; efa; efa=efa->next) {
+ if (efa->f & SELECT) {
+ mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
+ tmpcol= mcol[0];
+
+ mcol[0]= mcol[1];
+ mcol[1]= mcol[2];
+
+ if(efa->v4) {
+ mcol[2]= mcol[3];
+ mcol[3]= tmpcol;
+ }
+ else {
+ mcol[2]= tmpcol;
+ }
+ change = 1;
+ }
+ }
+
+ if (change) {
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ BIF_undo_push("Mirror Color face");
+ }
+}
diff --git a/source/blender/src/editmode_undo.c b/source/blender/src/editmode_undo.c
new file mode 100644
index 00000000000..22a399ae1e2
--- /dev/null
+++ b/source/blender/src/editmode_undo.c
@@ -0,0 +1,348 @@
+/**
+ * $Id:
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_object.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_dynstr.h"
+
+#include "BKE_utildefines.h"
+
+#include "BIF_editmesh.h"
+#include "BIF_interface.h"
+#include "BIF_screen.h"
+#include "BIF_resources.h"
+#include "BIF_toolbox.h"
+#include "BIF_space.h"
+
+#include "BDR_editcurve.h"
+
+#include "BSE_edit.h"
+
+#include "mydevice.h"
+
+/* ***************** generic editmode undo system ********************* */
+/*
+
+Add this in your local code:
+
+void undo_editmode_push(char *name,
+ void (*freedata)(void *), // pointer to function freeing data
+ void (*to_editmode)(void *), // data to editmode conversion
+ void * (*from_editmode)(void)) // editmode to data conversion
+
+
+Further exported for UI is:
+
+void undo_editmode_step(int step); // undo and redo
+void undo_editmode_clear(void) // free & clear all data
+void undo_editmode_menu(void) // history menu
+
+
+*/
+/* ********************************************************************* */
+
+/* local prototypes --------------- */
+ void undo_editmode_step(int step); // undo and redo
+ void undo_editmode_clear(void); // free & clear all data
+ void undo_editmode_menu(void); // history menu
+ void undo_editmode_push(char *name, void (*freedata)(void *),
+ void (*to_editmode)(void *), void *(*from_editmode)(void));
+ struct uiBlock *editmode_undohistorymenu(void *arg_unused);
+
+
+
+#define MAXUNDONAME 64
+typedef struct UndoElem {
+ struct UndoElem *next, *prev;
+ ID id; // copy of editmode object ID
+ Object *ob; // pointer to edited object
+ int type; // type of edited object
+ void *undodata;
+ char name[MAXUNDONAME];
+ void (*freedata)(void *);
+ void (*to_editmode)(void *);
+ void * (*from_editmode)(void);
+} UndoElem;
+
+static ListBase undobase={NULL, NULL};
+static UndoElem *curundo= NULL;
+
+
+/* ********************* xtern api calls ************* */
+
+static void undo_restore(UndoElem *undo)
+{
+ if(undo) {
+ waitcursor(1);
+ undo->to_editmode(undo->undodata);
+ waitcursor(0);
+
+ countall();
+ }
+}
+
+/* name can be a dynamic string */
+void undo_editmode_push(char *name, void (*freedata)(void *),
+ void (*to_editmode)(void *), void *(*from_editmode)(void))
+{
+ UndoElem *uel;
+ int nr;
+
+ /* at first here was code to prevent an "original" key to be insterted twice
+ this was giving conflicts for example when mesh changed due to keys or apply */
+
+ /* remove all undos after (also when curundo==NULL) */
+ while(undobase.last != curundo) {
+ uel= undobase.last;
+ BLI_remlink(&undobase, uel);
+ uel->freedata(uel->undodata);
+ MEM_freeN(uel);
+ }
+
+ /* make new */
+ curundo= uel= MEM_callocN(sizeof(UndoElem), "undo file");
+ strncpy(uel->name, name, MAXUNDONAME-1);
+ BLI_addtail(&undobase, uel);
+
+ uel->freedata= freedata;
+ uel->to_editmode= to_editmode;
+ uel->from_editmode= from_editmode;
+
+ /* and limit amount to the maximum */
+ nr= 0;
+ uel= undobase.last;
+ while(uel) {
+ nr++;
+ if(nr==U.undosteps) break;
+ uel= uel->prev;
+ }
+ if(uel) {
+ while(undobase.first!=uel) {
+ UndoElem *first= undobase.first;
+ BLI_remlink(&undobase, first);
+ first->freedata(first->undodata);
+ MEM_freeN(first);
+ }
+ }
+
+ /* copy */
+ curundo->undodata= curundo->from_editmode();
+ curundo->ob= G.obedit;
+ curundo->id= G.obedit->id;
+ curundo->type= G.obedit->type;
+}
+
+
+/* helper to remove clean other objects from undo stack */
+static void undo_clean_stack(void)
+{
+ UndoElem *uel, *next;
+ int mixed= 0;
+
+ /* global undo changes pointers, so we also allow identical names */
+ /* side effect: when deleting/renaming object and start editing new one with same name */
+
+ uel= undobase.first;
+ while(uel) {
+ next= uel->next;
+
+ /* for when objects are converted, renamed, or global undo changes pointers... */
+ if(uel->type==G.obedit->type && strcmp(uel->id.name, G.obedit->id.name)==0) {
+ uel->ob= G.obedit;
+ }
+ else {
+ mixed= 1;
+ BLI_remlink(&undobase, uel);
+ uel->freedata(uel->undodata);
+ MEM_freeN(uel);
+ }
+
+ uel= next;
+ }
+
+ if(mixed) curundo= undobase.last;
+}
+
+/* 1= an undo, -1 is a redo. we have to make sure 'curundo' remains at current situation */
+void undo_editmode_step(int step)
+{
+
+ /* prevent undo to happen on wrong object, stack can be a mix */
+ undo_clean_stack();
+
+ if(step==0) {
+ undo_restore(curundo);
+ }
+ else if(step==1) {
+
+ if(curundo==NULL || curundo->prev==NULL) error("No more steps to undo");
+ else {
+ if(G.f & G_DEBUG) printf("undo %s\n", curundo->name);
+ curundo= curundo->prev;
+ undo_restore(curundo);
+ }
+ }
+ else {
+ /* curundo has to remain current situation! */
+
+ if(curundo==NULL || curundo->next==NULL) error("No more steps to redo");
+ else {
+ undo_restore(curundo->next);
+ curundo= curundo->next;
+ if(G.f & G_DEBUG) printf("redo %s\n", curundo->name);
+ }
+ }
+
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 1);
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWIMAGE, 0);
+}
+
+void undo_editmode_clear(void)
+{
+ UndoElem *uel;
+
+ uel= undobase.first;
+ while(uel) {
+ uel->freedata(uel->undodata);
+ uel= uel->next;
+ }
+ BLI_freelistN(&undobase);
+ curundo= NULL;
+}
+
+/* based on index nr it does a restore */
+static void undo_number(int nr)
+{
+ UndoElem *uel;
+ int a=1;
+
+ for(uel= undobase.first; uel; uel= uel->next, a++) {
+ if(a==nr) break;
+ }
+ curundo= uel;
+ undo_editmode_step(0);
+}
+
+/* ************** for interaction with menu/pullown */
+
+void undo_editmode_menu(void)
+{
+ UndoElem *uel;
+ DynStr *ds= BLI_dynstr_new();
+ short event;
+ char *menu;
+
+ undo_clean_stack(); // removes other objects from it
+
+ BLI_dynstr_append(ds, "Editmode Undo History %t");
+
+ for(uel= undobase.first; uel; uel= uel->next) {
+ BLI_dynstr_append(ds, "|");
+ BLI_dynstr_append(ds, uel->name);
+ }
+
+ menu= BLI_dynstr_get_cstring(ds);
+ BLI_dynstr_free(ds);
+
+ event= pupmenu_col(menu, 20);
+ MEM_freeN(menu);
+
+ if(event>0) undo_number(event);
+}
+
+static void do_editmode_undohistorymenu(void *arg, int event)
+{
+
+ if(G.obedit==NULL || event<1) return;
+
+ if (event==1) {
+ if(G.obedit->type==OB_MESH) remake_editMesh();
+ }
+ else undo_number(event-1);
+
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+uiBlock *editmode_undohistorymenu(void *arg_unused)
+{
+ uiBlock *block;
+ UndoElem *uel;
+ short yco = 20, menuwidth = 120;
+ short item=2;
+
+ undo_clean_stack(); // removes other objects from it
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_edit_mesh_undohistorymenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_editmode_undohistorymenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Undo All Changes", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+
+ for(uel= undobase.first; uel; uel= uel->next, item++) {
+ if (uel==curundo) uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, uel->name, 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, (float)item, "");
+ if (uel==curundo) uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+ }
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+void *undo_editmode_get_prev(Object *ob)
+{
+ UndoElem *ue= undobase.last;
+ if(ue && ue->prev && ue->prev->ob==ob) return ue->prev->undodata;
+ return NULL;
+}
diff --git a/source/blender/src/editnla.c b/source/blender/src/editnla.c
new file mode 100644
index 00000000000..ec3b1c834e5
--- /dev/null
+++ b/source/blender/src/editnla.c
@@ -0,0 +1,2029 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL *****
+ *
+ * This file is a horrible mess: An attmept to cram some
+ * final functionality into blender before it is too late.
+ *
+ * Hopefully it can be tidied up at a later date...
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "PIL_time.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+
+#include "DNA_action_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_object_types.h"
+#include "DNA_nla_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BKE_action.h"
+#include "BKE_blender.h"
+#include "BKE_depsgraph.h"
+#include "BKE_group.h"
+#include "BKE_global.h"
+#include "BKE_ipo.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_nla.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_screen.h"
+#include "BIF_interface.h"
+#include "BIF_butspace.h"
+#include "BIF_space.h"
+#include "BIF_mywindow.h"
+#include "BIF_editview.h"
+#include "BIF_toolbox.h"
+#include "BIF_editnla.h"
+#include "BIF_editaction.h"
+#include "BIF_transform.h"
+
+#include "BSE_editipo.h"
+#include "BSE_editnla_types.h"
+#include "BSE_headerbuttons.h"
+#include "BSE_drawipo.h"
+#include "BSE_editaction_types.h"
+#include "BSE_trans_types.h"
+#include "BSE_edit.h"
+#include "BSE_filesel.h"
+#include "BDR_editobject.h"
+#include "BSE_drawnla.h"
+#include "BSE_time.h"
+
+#include "blendef.h"
+#include "mydevice.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* Note: A lot of these pretty much duplicate the behaviour of the
+action windows. The functions should be shared, not copy-pasted */
+
+static void mouse_nla(int selectmode);
+static Base *get_nearest_nlachannel_ob_key (float *index, short *sel);
+static bAction *get_nearest_nlachannel_ac_key (float *index, short *sel);
+static Base *get_nearest_nlastrip (bActionStrip **rstrip, short *sel);
+static void mouse_nlachannels(short mval[2]);
+
+/* ******************** SPACE: NLA ********************** */
+
+void shift_nlastrips_up(void) {
+
+ Base *base;
+ bActionStrip *strip, *prevstrip;
+
+ for (base=G.scene->base.first; base; base=base->next) {
+ if (base->object->nlaflag & OB_NLA_COLLAPSED)
+ continue;
+
+ for (strip = base->object->nlastrips.first;
+ strip; strip=strip->next){
+ if (strip->flag & ACTSTRIP_SELECT) {
+ if ( (prevstrip = strip->prev) ) {
+ if (prevstrip->prev)
+ prevstrip->prev->next = strip;
+ if (strip->next)
+ strip->next->prev = prevstrip;
+ strip->prev = prevstrip->prev;
+ prevstrip->next = strip->next;
+ strip->next = prevstrip;
+ prevstrip->prev = strip;
+
+ if (prevstrip == base->object->nlastrips.first)
+ base->object->nlastrips.first = strip;
+ if (strip == base->object->nlastrips.last)
+ base->object->nlastrips.last = prevstrip;
+
+ strip = prevstrip;
+ }
+ else {
+ break;
+ }
+ }
+ }
+ }
+ BIF_undo_push("Shift NLA strip");
+ allqueue (REDRAWNLA, 0);
+
+}
+
+void shift_nlastrips_down(void) {
+
+ Base *base;
+ bActionStrip *strip, *nextstrip;
+
+ for (base=G.scene->base.first; base; base=base->next) {
+ if (base->object->nlaflag & OB_NLA_COLLAPSED)
+ continue;
+
+ for (strip = base->object->nlastrips.last;
+ strip; strip=strip->prev){
+ if (strip->flag & ACTSTRIP_SELECT) {
+ if ( (nextstrip = strip->next) ) {
+ if (nextstrip->next)
+ nextstrip->next->prev = strip;
+ if (strip->prev)
+ strip->prev->next = nextstrip;
+ strip->next = nextstrip->next;
+ nextstrip->prev = strip->prev;
+ strip->prev = nextstrip;
+ nextstrip->next = strip;
+
+ if (nextstrip == base->object->nlastrips.last)
+ base->object->nlastrips.last = strip;
+ if (strip == base->object->nlastrips.first)
+ base->object->nlastrips.first = nextstrip;
+
+ strip = nextstrip;
+ }
+ else {
+ break;
+ }
+ }
+ }
+ }
+
+ BIF_undo_push("Shift NLA strips");
+ allqueue (REDRAWNLA, 0);
+}
+
+void synchronize_action_strips(void)
+{
+ Base *base;
+ bActionStrip *strip;
+
+ for (base=G.scene->base.first; base; base=base->next) {
+ /* step 1: adjust strip-lengths */
+ for (strip = base->object->nlastrips.last; strip; strip=strip->prev) {
+ if (strip->flag & ACTSTRIP_LOCK_ACTION) {
+ float actstart, actend;
+
+ calc_action_range(strip->act, &actstart, &actend, 1);
+
+ if(strip->actstart!=actstart || strip->actend!=actend) {
+ float mapping= (strip->end - strip->start)/(strip->actend - strip->actstart);
+
+ strip->start+= mapping*(actstart - strip->actstart);
+ strip->end+= mapping*(actend - strip->actend);
+
+ strip->actstart= actstart;
+ strip->actend= actend;
+ }
+ }
+ }
+
+ /* step 2: adjust blendin/out values for each strip if option is turned on */
+ for (strip= base->object->nlastrips.first; strip; strip=strip->next) {
+ if (strip->flag & ACTSTRIP_AUTO_BLENDS) {
+ bActionStrip *prev= strip->prev;
+ bActionStrip *next= strip->next;
+ float pr[2], nr[2];
+
+ strip->blendin = 0.0f;
+ strip->blendout = 0.0f;
+
+ /* setup test ranges */
+ if (prev && next) {
+ /* init range for previous strip */
+ pr[0]= prev->start;
+ pr[1]= prev->end;
+
+ /* init range for next strip */
+ nr[0]= next->start;
+ nr[1]= next->end;
+ }
+ else if (prev) {
+ /* next strip's range is same as previous strip's range */
+ pr[0] = nr[0] = prev->start;
+ pr[1] = nr[1] = prev->end;
+ }
+ else if (next) {
+ /* previous strip's range is same as next strip's range */
+ pr[0] = nr[0] = next->start;
+ pr[1] = nr[1] = next->end;
+ }
+ else {
+ /* there shouldn't be any more strips to loop through for this operation */
+ break;
+ }
+
+ /* test various cases */
+ if ( IN_RANGE(pr[1], strip->start, strip->end) &&
+ (IN_RANGE(pr[0], strip->start, strip->end)==0) )
+ {
+ /* previous strip intersects start of current */
+
+ if ( IN_RANGE(nr[1], strip->start, strip->end) &&
+ (IN_RANGE(nr[0], strip->start, strip->end)==0) )
+ {
+ /* next strip also intersects start of current */
+ if (nr[1] < pr[1])
+ strip->blendin= nr[1] - strip->start;
+ else
+ strip->blendin= pr[1] - strip->start;
+ }
+ else if (IN_RANGE(nr[0], strip->start, strip->end) &&
+ (IN_RANGE(nr[1], strip->start, strip->end)==0))
+ {
+ /* next strip intersects end of current */
+ strip->blendout= strip->end - nr[0];
+ strip->blendin= pr[1] - strip->start;
+ }
+ else {
+ /* only previous strip intersects current */
+ strip->blendin= pr[1] - strip->start;
+ }
+ }
+ else if (IN_RANGE(pr[0], strip->start, strip->end) &&
+ (IN_RANGE(pr[1], strip->start, strip->end)==0) )
+ {
+ /* previous strip intersects end of current */
+
+ if ( IN_RANGE(nr[0], strip->start, strip->end) &&
+ (IN_RANGE(nr[1], strip->start, strip->end)==0) )
+ {
+ /* next strip also intersects end of current */
+ if (nr[1] > pr[1])
+ strip->blendout= strip->end - nr[0];
+ else
+ strip->blendout= strip->end - pr[0];
+ }
+ else if (IN_RANGE(nr[1], strip->start, strip->end) &&
+ (IN_RANGE(nr[0], strip->start, strip->end)==0))
+ {
+ /* next strip intersects start of current */
+ strip->blendin= nr[1] - strip->start;
+ strip->blendout= strip->end - pr[0];
+ }
+ else {
+ /* only previous strip intersects current */
+ strip->blendout= strip->end - pr[0];
+ }
+ }
+ else if (IN_RANGE(nr[1], strip->start, strip->end) &&
+ (IN_RANGE(nr[0], strip->start, strip->end)==0) )
+ {
+ /* next strip intersects start of current */
+
+ if ( IN_RANGE(pr[1], strip->start, strip->end) &&
+ (IN_RANGE(pr[0], strip->start, strip->end)==0) )
+ {
+ /* previous strip also intersects start of current */
+ if (pr[1] < nr[1])
+ strip->blendin= pr[1] - strip->start;
+ else
+ strip->blendin= nr[1] - strip->start;
+ }
+ else if (IN_RANGE(pr[0], strip->start, strip->end) &&
+ (IN_RANGE(pr[1], strip->start, strip->end)==0))
+ {
+ /* previous strip intersects end of current */
+ strip->blendout= strip->end - pr[0];
+ strip->blendin= nr[1] - strip->start;
+ }
+ else {
+ /* only next strip intersects current */
+ strip->blendin= nr[1] - strip->start;
+ }
+ }
+ else if (IN_RANGE(nr[0], strip->start, strip->end) &&
+ (IN_RANGE(nr[1], strip->start, strip->end)==0) )
+ {
+ /* next strip intersects end of current */
+
+ if ( IN_RANGE(pr[0], strip->start, strip->end) &&
+ (IN_RANGE(pr[1], strip->start, strip->end)==0) )
+ {
+ /* previous strip also intersects end of current */
+ if (pr[1] > nr[1])
+ strip->blendout= strip->end - pr[0];
+ else
+ strip->blendout= strip->end - nr[0];
+ }
+ else if (IN_RANGE(pr[1], strip->start, strip->end) &&
+ (IN_RANGE(pr[0], strip->start, strip->end)==0))
+ {
+ /* previous strip intersects start of current */
+ strip->blendin= pr[1] - strip->start;
+ strip->blendout= strip->end - nr[0];
+ }
+ else {
+ /* only next strip intersects current */
+ strip->blendout= strip->end - nr[0];
+ }
+ }
+
+ /* make sure blending stays in ranges */
+ CLAMP(strip->blendin, 0, (strip->end-strip->start));
+ CLAMP(strip->blendout, 0, (strip->end-strip->start));
+ }
+ }
+ }
+
+}
+
+void reset_action_strips(int val)
+{
+ Base *base;
+ bActionStrip *strip;
+
+ for (base=G.scene->base.first; base; base=base->next) {
+ if (base->object->nlaflag & OB_NLA_COLLAPSED)
+ continue;
+
+ for (strip = base->object->nlastrips.last; strip; strip=strip->prev) {
+ if (strip->flag & ACTSTRIP_SELECT) {
+ if(val==2) {
+ calc_action_range(strip->act, &strip->actstart, &strip->actend, 1);
+ }
+ else if(val==1) {
+ float mapping= (strip->actend - strip->actstart)/(strip->end - strip->start);
+
+ strip->end= strip->start + mapping*(strip->end - strip->start);
+ }
+ base->object->ctime= -1234567.0f; // eveil!
+ DAG_object_flush_update(G.scene, base->object, OB_RECALC_OB|OB_RECALC_DATA);
+ }
+ }
+ }
+ BIF_undo_push("Reset NLA strips");
+ allqueue (REDRAWVIEW3D, 0);
+ allqueue (REDRAWACTION, 0);
+ allqueue (REDRAWNLA, 0);
+}
+
+void snap_action_strips(int snap_mode)
+{
+ Base *base;
+ bActionStrip *strip;
+
+ for (base=G.scene->base.first; base; base=base->next) {
+ /* object has ipo - these keyframes should be able to be snapped, even if strips are collapsed */
+ if (base->object->ipo) {
+ snap_ipo_keys(base->object->ipo, snap_mode);
+ }
+
+ /* object is collapsed - action and nla strips not shown/editable */
+ if (base->object->nlaflag & OB_NLA_COLLAPSED)
+ continue;
+
+ /* snap action strips */
+ for (strip = base->object->nlastrips.last; strip; strip=strip->prev) {
+ if (strip->flag & ACTSTRIP_SELECT) {
+ if (snap_mode==1) {
+ /* nearest frame */
+ strip->start= floor(strip->start+0.5);
+ strip->end= floor(strip->end+0.5);
+ }
+ else if (snap_mode==2) {
+ /* current frame */
+ float diff;
+ if (CFRA < strip->start) {
+ diff = (strip->start - CFRA);
+ strip->start -= diff;
+ strip->end -= diff;
+ }
+ else {
+ diff = (CFRA - strip->start);
+ strip->start += diff;
+ strip->end += diff;
+ }
+ }
+ else if (snap_mode==3) {
+ /* nearest second */
+ float secf = FPS;
+ strip->start= (float)(floor(strip->start/secf + 0.5f) * secf);
+ strip->end= (float)(floor(strip->end/secf + 0.5f) * secf);
+ }
+ }
+ }
+
+ /* object has action */
+ if (base->object->action) {
+ ListBase act_data = {NULL, NULL};
+ bActListElem *ale;
+ int filter;
+
+ /* filter action data */
+ filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS);
+ actdata_filter(&act_data, filter, base->object->action, ACTCONT_ACTION);
+
+ /* snap to frame */
+ for (ale= act_data.first; ale; ale= ale->next) {
+ actstrip_map_ipo_keys(base->object, ale->key_data, 0, 1);
+ snap_ipo_keys(ale->key_data, snap_mode);
+ actstrip_map_ipo_keys(base->object, ale->key_data, 1, 1);
+ }
+ BLI_freelistN(&act_data);
+
+ remake_action_ipos(base->object->action);
+ }
+ }
+ BIF_undo_push("Snap NLA strips");
+ allqueue (REDRAWVIEW3D, 0);
+ allqueue (REMAKEIPO, 0);
+ allqueue (REDRAWIPO, 0);
+ allqueue (REDRAWACTION, 0);
+ allqueue (REDRAWNLA, 0);
+}
+
+static void set_active_strip(Object *ob, bActionStrip *act)
+{
+ bActionStrip *strip;
+
+ for (strip = ob->nlastrips.first; strip; strip=strip->next)
+ strip->flag &= ~ACTSTRIP_ACTIVE;
+
+ if(act) {
+ act->flag |= ACTSTRIP_ACTIVE;
+
+ if(ob->action!=act->act) {
+ if(ob->action) ob->action->id.us--;
+ if(act->act->id.lib) {
+ ob->action= NULL;
+ }
+ else {
+ ob->action= act->act;
+ id_us_plus(&ob->action->id);
+ }
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWNLA, 0);
+ ob->ctime= -1234567.0f; // eveil!
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_OB|OB_RECALC_DATA);
+ }
+ }
+}
+
+void convert_nla(void)
+{
+ bActionStrip *strip;
+ Object *ob= OBACT;
+ char str[128];
+ short event;
+
+ if ((ob==NULL)||(ob->action==NULL)) {
+ error("Need active Object to convert Action to NLA Strip");
+ return;
+ }
+
+ sprintf(str, "Convert Action%%t|%s to NLA Strip%%x1", ob->action->id.name+2);
+ event = pupmenu(str);
+
+ if (event==1) {
+ if (ob->action) {
+ deselect_nlachannel_keys(0);
+ strip = convert_action_to_strip(ob); //creates a new NLA strip from the action in given object
+ set_active_strip(ob, strip);
+ BIF_undo_push("Convert NLA");
+ allqueue (REDRAWNLA, 0);
+ }
+ }
+}
+
+static void add_nla_block(short event)
+{
+ Object *ob= OBACT;
+ bAction *act=NULL;
+ bActionStrip *strip;
+ int cur;
+
+ if (event!=-1){
+ for (cur = 1, act=G.main->action.first; act; act=act->id.next, cur++){
+ if (cur==event){
+ break;
+ }
+ }
+ }
+
+ /* Bail out if no action was chosen */
+ if (!act){
+ return;
+ }
+
+ /* Initialize the new action block */
+ strip = MEM_callocN(sizeof(bActionStrip), "bActionStrip");
+
+ deselect_nlachannel_keys(0);
+
+ /* Link the action to the strip */
+ strip->act = act;
+ id_us_plus(&act->id);
+ calc_action_range(strip->act, &strip->actstart, &strip->actend, 1);
+ strip->start = G.scene->r.cfra; /* could be mval[0] another time... */
+ strip->end = strip->start + (strip->actend-strip->actstart);
+ /* simple prevention of zero strips */
+ if(strip->start>strip->end-2)
+ strip->end= strip->start+100;
+ strip->repeat = 1.0;
+
+ strip->flag = ACTSTRIP_SELECT|ACTSTRIP_LOCK_ACTION;
+
+ find_stridechannel(ob, strip);
+ set_active_strip(ob, strip);
+ strip->object= group_get_member_with_action(ob->dup_group, act);
+ if(strip->object)
+ id_lib_extern(&strip->object->id); /* checks lib data, sets correct flag for saving then */
+
+ if(ob->nlastrips.first == NULL)
+ ob->nlaflag |= OB_NLA_OVERRIDE;
+
+ BLI_addtail(&ob->nlastrips, strip);
+
+ BIF_undo_push("Add NLA strip");
+}
+
+static void add_nla_block_by_name(char name[32], Object *ob, short hold, short add, float repeat)
+{
+ bAction *act=NULL;
+ bActionStrip *strip;
+ int cur;
+
+ if (name){
+ for (cur = 1, act=G.main->action.first; act; act=act->id.next, cur++){
+ if (strcmp(name,act->id.name)==0) {
+ break;
+ }
+ }
+ }
+
+ /* Bail out if no action was chosen */
+ if (!act){
+ return;
+ }
+
+ /* Initialize the new action block */
+ strip = MEM_callocN(sizeof(bActionStrip), "bActionStrip");
+
+ deselect_nlachannel_keys(0);
+
+ /* Link the action to the strip */
+ strip->act = act;
+ calc_action_range(strip->act, &strip->actstart, &strip->actend, 1);
+ strip->start = G.scene->r.cfra; /* could be mval[0] another time... */
+ strip->end = strip->start + (strip->actend-strip->actstart);
+ /* simple prevention of zero strips */
+ if(strip->start>strip->end-2)
+ strip->end= strip->start+100;
+
+ strip->flag = ACTSTRIP_SELECT|ACTSTRIP_LOCK_ACTION; //|ACTSTRIP_USEMATCH;
+
+ if (hold==1)
+ strip->flag = strip->flag|ACTSTRIP_HOLDLASTFRAME;
+
+ if (add==1)
+ strip->mode = ACTSTRIPMODE_ADD;
+
+ find_stridechannel(ob, strip);
+
+ set_active_strip(ob, strip);
+
+ strip->repeat = repeat;
+
+ act->id.us++;
+
+ if(ob->nlastrips.first == NULL)
+ ob->nlaflag |= OB_NLA_OVERRIDE;
+
+ BLI_addtail(&ob->nlastrips, strip);
+}
+
+static void add_nla_databrowse_callback(unsigned short val)
+{
+ /* val is not used, databrowse needs it to optional pass an event */
+ short event;
+
+ if(OBACT==NULL) return;
+
+ event= G.snla->menunr; /* set by databrowse or pupmenu */
+
+ add_nla_block(event);
+}
+
+/* Adds strip to to active Object */
+void add_nlablock(void)
+{
+ Object *ob= OBACT;
+ short event;
+ short nr=0;
+ char *str, title[64];
+
+ if(ob==NULL) {
+ error("Need active Object to add NLA strips");
+ return;
+ }
+
+ sprintf(title, "Add Action strip to: %s", ob->id.name+2);
+
+ /* Popup action menu */
+ IDnames_to_pupstring(&str, title, NULL, &G.main->action, (ID *)G.scene, &nr);
+
+ if(nr==-2) {
+ MEM_freeN(str);
+
+ activate_databrowse((ID *)NULL, ID_AC, 0, 0, &G.snla->menunr,
+ add_nla_databrowse_callback );
+
+ return;
+ }
+ else {
+ event = pupmenu_col(str, 20);
+ MEM_freeN(str);
+ add_nla_block(event);
+ }
+}
+
+/* Creates a new action, and makes a new actionstrip of that */
+void add_empty_nlablock(void)
+{
+ Object *ob= OBACT;
+ bAction *act= NULL;
+ bActionStrip *strip;
+
+ /* check for active object first - will add strip to active object */
+ if (ob == NULL)
+ return;
+
+ /* make new action */
+ if ((ob->type == OB_ARMATURE) && (ob->flag & OB_POSEMODE))
+ act= add_empty_action("ObAction");
+ else
+ act= add_empty_action("Action");
+
+ /* make a new strip for it */
+ add_nla_block_by_name(act->id.name, ob, 0, 1, 1.0f);
+ strip= ob->nlastrips.last;
+
+ /* change some settings of the strip - try to avoid bad scaling */
+ if ((EFRA-CFRA) < 100) {
+ strip->flag |= ACTSTRIP_AUTO_BLENDS;
+ strip->flag &= ~ACTSTRIP_LOCK_ACTION;
+ strip->actstart = CFRA;
+ strip->actend = CFRA + 100;
+
+ strip->start = CFRA;
+ strip->end = CFRA + 100;
+ }
+ else {
+ strip->flag |= ACTSTRIP_AUTO_BLENDS;
+ strip->flag &= ~ACTSTRIP_LOCK_ACTION;
+ strip->actstart = CFRA;
+ strip->actend = EFRA;
+
+ strip->start = CFRA;
+ strip->end = EFRA;
+ }
+
+ BIF_undo_push("Add NLA strip");
+}
+
+/* Adds strip to to active Object */
+static void relink_active_strip(void)
+{
+ Object *ob= OBACT;
+ bActionStrip *strip;
+ bAction *act;
+ short event;
+ short cur;
+ char *str;
+
+ if(ob==NULL) return;
+ if(ob->nlaflag & OB_NLA_COLLAPSED) return;
+
+ for (strip = ob->nlastrips.first; strip; strip=strip->next)
+ if(strip->flag & ACTSTRIP_ACTIVE)
+ break;
+
+ if(strip==NULL) return;
+
+ /* Popup action menu */
+ IDnames_to_pupstring(&str, "Relink Action strip", NULL, &G.main->action, (ID *)G.scene, NULL);
+ if(str) {
+ event = pupmenu_col(str, 20);
+ MEM_freeN(str);
+
+ for (cur = 1, act=G.main->action.first; act; act=act->id.next, cur++){
+ if (cur==event){
+ break;
+ }
+ }
+
+ if(act) {
+ if(strip->act) strip->act->id.us--;
+ strip->act = act;
+ id_us_plus(&act->id);
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWNLA, 0);
+ }
+ }
+}
+
+
+
+/* Left hand side of channels display, selects objects */
+static void mouse_nlachannels(short mval[2])
+{
+ bActionStrip *strip= NULL;
+ Base *base;
+ Object *ob=NULL;
+ float x,y;
+ int click, obclick=0, actclick=0;
+ int wsize;
+
+ wsize = (count_nla_levels ()*(NLACHANNELHEIGHT+NLACHANNELSKIP));
+ wsize+= NLACHANNELHEIGHT/2;
+
+ areamouseco_to_ipoco(G.v2d, mval, &x, &y);
+ click = (int)floor( ((float)wsize - y) / (NLACHANNELHEIGHT+NLACHANNELSKIP));
+
+ if (click<0)
+ return;
+
+ for (base = G.scene->base.first; base; base=base->next){
+ if (nla_filter(base)) {
+ ob= base->object;
+
+ /* See if this is a base selected */
+ if (click==0) {
+ obclick= 1;
+ break;
+ }
+ click--;
+
+ /* see if any strips under object */
+ if ((ob->nlaflag & OB_NLA_COLLAPSED)==0) {
+ /* See if this is an action */
+ if (ob->action){
+ if (click==0) {
+ actclick= 1;
+ break;
+ }
+ click--;
+ }
+
+ /* See if this is an nla strip */
+ if(ob->nlastrips.first) {
+ for (strip = ob->nlastrips.first; strip; strip=strip->next){
+ if (click==0) break;
+ click--;
+ }
+ if (strip && click==0) break;
+ }
+ }
+ }
+ }
+
+ if (!base)
+ return;
+
+ /* Handle object strip selection */
+ if (G.qual & LR_SHIFTKEY) {
+ if (base->flag & SELECT) base->flag &= ~SELECT;
+ else base->flag |= SELECT;
+ }
+ else {
+ deselect_nlachannels (0); // Auto clear
+ base->flag |= SELECT;
+ }
+ ob->flag= base->flag;
+
+ if(base!=BASACT) set_active_base(base);
+
+ if(actclick) /* de-activate all strips */
+ set_active_strip(ob, NULL);
+ else if(strip) {
+ if(mval[0] >= (NLAWIDTH-16)) /* toggle strip muting */
+ strip->flag ^= ACTSTRIP_MUTE;
+ else /* set action */
+ set_active_strip(ob, strip);
+ }
+
+ /* icon toggles beside strip */
+ if (obclick && mval[0]<20) {
+ /* collapse option for NLA object strip */
+ ob->nlaflag ^= OB_NLA_COLLAPSED;
+ }
+ else if(obclick && mval[0]<36) {
+ /* override option for NLA */
+ ob->nlaflag ^= OB_NLA_OVERRIDE;
+ }
+ else if((obclick) && (ob->ipo) && (mval[0] >= (NLAWIDTH-16))) {
+ /* mute Object IPO-block */
+ ob->ipo->muteipo = (ob->ipo->muteipo)? 0: 1;
+ }
+
+ ob->ctime= -1234567.0f; // eveil!
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_OB|OB_RECALC_DATA);
+
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWNLA, 0);
+
+}
+
+void deselect_nlachannel_keys (int test)
+{
+ Base *base;
+ int sel=1;
+ bActionChannel *chan;
+ bActionStrip *strip;
+ bConstraintChannel *conchan;
+
+ /* Determine if this is selection or deselection */
+ if (test){
+ for (base=G.scene->base.first; base && sel; base=base->next){
+ /* Test object ipos */
+ if (is_ipo_key_selected(base->object->ipo)){
+ sel = 0;
+ break;
+ }
+
+ /* Test object constraint ipos */
+ if (sel){
+ for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
+ if (is_ipo_key_selected(conchan->ipo)){
+ sel=0;
+ break;
+ }
+ }
+ }
+
+ /* check if collapsed */
+ if (base->object->nlaflag & OB_NLA_COLLAPSED)
+ continue;
+
+ /* Test action ipos */
+ if (sel){
+ if (base->object->action){
+ for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
+ if (is_ipo_key_selected(chan->ipo)){
+ sel=0;
+ break;
+ }
+
+ /* Test action constraints */
+ if (sel){
+ for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
+ if (is_ipo_key_selected(conchan->ipo)){
+ sel=0;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Test NLA strips */
+ if (sel){
+ for (strip=base->object->nlastrips.first; strip; strip=strip->next){
+ if (strip->flag & ACTSTRIP_SELECT){
+ sel = 0;
+ break;
+ }
+ }
+ }
+ }
+ }
+ else
+ sel=0;
+
+
+ /* Set the flags */
+ for (base=G.scene->base.first; base; base=base->next){
+ /* Set the object ipos */
+ set_ipo_key_selection(base->object->ipo, sel);
+
+ /* Set the object constraint ipos */
+ for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
+ set_ipo_key_selection(conchan->ipo, sel);
+ }
+
+ /* check if collapsed */
+ if (base->object->nlaflag & OB_NLA_COLLAPSED)
+ continue;
+
+ /* Set the action ipos */
+ if (base->object->action){
+ for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
+ set_ipo_key_selection(chan->ipo, sel);
+ /* Set the action constraint ipos */
+ for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
+ set_ipo_key_selection(conchan->ipo, sel);
+ }
+ }
+
+ /* Set the nlastrips */
+ for (strip=base->object->nlastrips.first; strip; strip=strip->next){
+ if (sel)
+ strip->flag |= ACTSTRIP_SELECT;
+ else
+ strip->flag &= ~ACTSTRIP_SELECT;
+ }
+ }
+}
+
+/* very bad call! */
+static void recalc_all_ipos(void)
+{
+ Ipo *ipo;
+ IpoCurve *icu;
+
+ /* Go to each ipo */
+ for (ipo=G.main->ipo.first; ipo; ipo=ipo->id.next){
+ for (icu = ipo->curve.first; icu; icu=icu->next){
+ sort_time_ipocurve(icu);
+ testhandles_ipocurve(icu);
+ }
+ }
+}
+
+void transform_nlachannel_keys(int mode, int dummy)
+{
+ switch (mode) {
+ case 'g':
+ {
+ initTransform(TFM_TIME_TRANSLATE, CTX_NONE);
+ Transform();
+ }
+ break;
+ case 's':
+ {
+ initTransform(TFM_TIME_SCALE, CTX_NONE);
+ Transform();
+ }
+ break;
+ case 'e':
+ {
+ initTransform(TFM_TIME_EXTEND, CTX_NONE);
+ Transform();
+ }
+ break;
+ }
+}
+
+void delete_nlachannel_keys(void)
+{
+ Base *base;
+ bActionChannel *chan;
+ bConstraintChannel *conchan;
+ bActionStrip *strip, *nextstrip;
+
+ for (base = G.scene->base.first; base; base=base->next){
+ /* Delete object ipos */
+ delete_ipo_keys(base->object->ipo);
+
+ /* Delete object constraint keys */
+ for(conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
+ delete_ipo_keys(conchan->ipo);
+
+ /* skip actions and nlastrips if object collapsed */
+ if (base->object->nlaflag & OB_NLA_COLLAPSED)
+ continue;
+
+ /* Delete NLA strips */
+ for (strip = base->object->nlastrips.first; strip; strip=nextstrip){
+ nextstrip=strip->next;
+ if (strip->flag & ACTSTRIP_SELECT){
+ free_actionstrip(strip);
+ BLI_remlink(&base->object->nlastrips, strip);
+ MEM_freeN(strip);
+ }
+ }
+
+ /* Delete action ipos */
+ if (base->object->action){
+ for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
+ if (EDITABLE_ACHAN(chan))
+ delete_ipo_keys(chan->ipo);
+
+ /* Delete action constraint keys */
+ for(conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
+ if (EDITABLE_CONCHAN(conchan))
+ delete_ipo_keys(conchan->ipo);
+ }
+ }
+ }
+ }
+
+ recalc_all_ipos(); // bad
+ synchronize_action_strips();
+
+ BIF_undo_push("Delete NLA keys");
+ allspace(REMAKEIPO,0);
+ allqueue (REDRAWVIEW3D, 0);
+ allqueue(REDRAWNLA, 0);
+ allqueue(REDRAWIPO, 0);
+}
+
+void duplicate_nlachannel_keys(void)
+{
+ Base *base;
+ bActionChannel *chan;
+ bConstraintChannel *conchan;
+ bActionStrip *strip, *laststrip;
+
+ /* Find selected items */
+ for (base = G.scene->base.first; base; base=base->next){
+ /* Duplicate object keys */
+ duplicate_ipo_keys(base->object->ipo);
+
+ /* Duplicate object constraint keys */
+ for(conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
+ duplicate_ipo_keys(conchan->ipo);
+
+ /* skip actions and nlastrips if object collapsed */
+ if (base->object->nlaflag & OB_NLA_COLLAPSED)
+ continue;
+
+ /* Duplicate nla strips */
+ laststrip = base->object->nlastrips.last;
+ for (strip=base->object->nlastrips.first; strip; strip=strip->next){
+ if (strip->flag & ACTSTRIP_SELECT){
+ bActionStrip *newstrip;
+
+ copy_actionstrip(&newstrip, &strip);
+
+ BLI_addtail(&base->object->nlastrips, newstrip);
+
+ strip->flag &= ~ACTSTRIP_SELECT;
+ newstrip->flag |= ACTSTRIP_SELECT;
+ set_active_strip(base->object, newstrip);
+
+ }
+ if (strip==laststrip)
+ break;
+ }
+
+ /* Duplicate actionchannel keys */
+ if (base->object->action){
+ for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
+ if (EDITABLE_ACHAN(chan))
+ duplicate_ipo_keys(chan->ipo);
+
+ /* Duplicate action constraint keys */
+ for(conchan=chan->constraintChannels.first; conchan; conchan=conchan->next) {
+ if (EDITABLE_CONCHAN(conchan))
+ duplicate_ipo_keys(conchan->ipo);
+ }
+ }
+ }
+ }
+
+ BIF_undo_push("Duplicate NLA");
+ transform_nlachannel_keys ('g', 0);
+}
+
+void borderselect_nla(void)
+{
+ Base *base;
+ rcti rect;
+ rctf rectf;
+ int val, selectmode;
+ short mval[2];
+ float ymin, ymax;
+ bActionStrip *strip;
+ bConstraintChannel *conchan;
+
+ if ( (val = get_border (&rect, 3)) ){
+ if (val == LEFTMOUSE)
+ selectmode = SELECT_ADD;
+ else
+ selectmode = SELECT_SUBTRACT;
+
+ mval[0]= rect.xmin;
+ mval[1]= rect.ymin+2;
+ areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
+ mval[0]= rect.xmax;
+ mval[1]= rect.ymax-2;
+ areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
+
+ ymax = count_nla_levels();
+ ymax*= (NLACHANNELHEIGHT+NLACHANNELSKIP);
+ ymax+= (NLACHANNELHEIGHT+NLACHANNELSKIP)/2;
+
+ for (base=G.scene->base.first; base; base=base->next){
+ if (nla_filter(base)) {
+
+ ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
+
+ /* Check object ipos */
+ if (base->object->ipo){
+ if (!((ymax < rectf.ymin) || (ymin > rectf.ymax)))
+ borderselect_ipo_key(base->object->ipo, rectf.xmin, rectf.xmax,
+ selectmode);
+ }
+ /* Check object constraint ipos */
+ for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
+ if (!((ymax < rectf.ymin) || (ymin > rectf.ymax)))
+ borderselect_ipo_key(conchan->ipo, rectf.xmin, rectf.xmax,
+ selectmode);
+ }
+
+ ymax=ymin;
+
+ /* skip actions and nlastrips if object collapsed */
+ if (base->object->nlaflag & OB_NLA_COLLAPSED)
+ continue;
+
+ /* Check action ipos */
+ if (base->object->action){
+ bActionChannel *chan;
+ float xmin, xmax;
+
+ ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
+
+ /* if action is mapped in NLA, it returns a correction */
+ xmin= get_action_frame(base->object, rectf.xmin);
+ xmax= get_action_frame(base->object, rectf.xmax);
+
+ if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
+ for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
+ borderselect_ipo_key(chan->ipo, xmin, xmax, selectmode);
+ /* Check action constraint ipos */
+ for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
+ borderselect_ipo_key(conchan->ipo, xmin, xmax, selectmode);
+ }
+ }
+
+ ymax=ymin;
+ } /* End of if action */
+
+ /* Skip nlastrips */
+ for (strip=base->object->nlastrips.first; strip; strip=strip->next){
+ ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
+ //
+ if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
+ if (!((rectf.xmax<strip->start) || (rectf.xmin>strip->end))){
+ if (val==1)
+ strip->flag |= ACTSTRIP_SELECT;
+ else
+ strip->flag &= ~ACTSTRIP_SELECT;
+ }
+ }
+
+ ymax=ymin;
+ }
+ }
+ }
+ BIF_undo_push("Border select NLA");
+ allqueue(REDRAWMARKER, 0);
+ }
+}
+
+/* right hand side of window, does ipokeys, actionkeys or strips */
+static void mouse_nla(int selectmode)
+{
+ Base *base;
+ bAction *act;
+ bActionChannel *chan;
+ bActionStrip *rstrip;
+ bConstraintChannel *conchan;
+ TimeMarker *marker;
+ float selx;
+ short mval[2];
+ short sel, isdone=0;
+
+ getmouseco_areawin (mval);
+
+ /* Try object ipo or ob-constraint ipo selection */
+ base= get_nearest_nlachannel_ob_key(&selx, &sel);
+ marker=find_nearest_marker(1);
+ if (base) {
+ isdone= 1;
+
+ if (selectmode == SELECT_REPLACE){
+ deselect_nlachannel_keys(0);
+ selectmode = SELECT_ADD;
+ }
+
+ select_ipo_key(base->object->ipo, selx, selectmode);
+
+ /* Try object constraint selection */
+ for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
+ select_ipo_key(conchan->ipo, selx, selectmode);
+ }
+ else if (marker) {
+ /* marker */
+ if (selectmode == SELECT_REPLACE) {
+ deselect_markers(0, 0);
+ marker->flag |= SELECT;
+ }
+ else if (selectmode == SELECT_INVERT) {
+ if (marker->flag & SELECT)
+ marker->flag &= ~SELECT;
+ else
+ marker->flag |= SELECT;
+ }
+ else if (selectmode == SELECT_ADD)
+ marker->flag |= SELECT;
+ else if (selectmode == SELECT_SUBTRACT)
+ marker->flag &= ~SELECT;
+
+ std_rmouse_transform(transform_markers);
+
+ allqueue(REDRAWMARKER, 0);
+ }
+ else {
+ /* Try action ipo selection */
+ act= get_nearest_nlachannel_ac_key(&selx, &sel);
+ if (act) {
+ isdone= 1;
+
+ if (selectmode == SELECT_REPLACE){
+ deselect_nlachannel_keys(0);
+ selectmode = SELECT_ADD;
+ }
+
+ for (chan=act->chanbase.first; chan; chan=chan->next) {
+ select_ipo_key(chan->ipo, selx, selectmode);
+ /* Try action constraint selection */
+ for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
+ select_ipo_key(conchan->ipo, selx, selectmode);
+ }
+ }
+ else {
+
+ /* Try nla strip selection */
+ base= get_nearest_nlastrip(&rstrip, &sel);
+ if (base){
+ isdone= 1;
+
+ if (!(G.qual & LR_SHIFTKEY)){
+ deselect_nlachannel_keys(0);
+ sel = 0;
+ }
+
+ if (sel)
+ rstrip->flag &= ~ACTSTRIP_SELECT;
+ else
+ rstrip->flag |= ACTSTRIP_SELECT;
+
+ set_active_strip(base->object, rstrip);
+
+ if(base!=BASACT) set_active_base(base);
+ }
+ }
+ }
+
+ if(isdone) {
+ std_rmouse_transform(transform_nlachannel_keys);
+
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWNLA, 0);
+ }
+}
+
+/* This function is currently more complicated than it seems like it should be.
+* However, this will be needed once the nla strip timeline is more complex */
+static Base *get_nearest_nlastrip (bActionStrip **rstrip, short *sel)
+{
+ Base *base, *firstbase=NULL;
+ bActionStrip *strip, *firststrip=NULL, *foundstrip=NULL;
+ rctf rectf;
+ float ymin, ymax;
+ short mval[2];
+ short foundsel = 0;
+
+ getmouseco_areawin (mval);
+
+ mval[0]-=7;
+ areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
+
+ mval[0]+=14;
+ areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
+
+ ymax = count_nla_levels();
+ ymax*=(NLACHANNELHEIGHT + NLACHANNELSKIP);
+ ymax+= NLACHANNELHEIGHT/2;
+
+ for (base = G.scene->base.first; base; base=base->next){
+ if (nla_filter(base)) {
+
+ /* Skip object ipos */
+ ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP);
+
+ /* check if skip strips if collapsed */
+ if (base->object->nlaflag & OB_NLA_COLLAPSED)
+ continue;
+
+ /* Skip action ipos */
+ if (base->object->action)
+ ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP);
+
+ /* the strips */
+ for (strip=base->object->nlastrips.first; strip; strip=strip->next){
+ ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
+ /* Do Ytest */
+ if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
+ /* Do XTest */
+ if (!((rectf.xmax<strip->start) || (rectf.xmin>strip->end))){
+ if (!firstbase){
+ firstbase=base;
+ firststrip=strip;
+ *sel = strip->flag & ACTSTRIP_SELECT;
+ }
+
+ if (strip->flag & ACTSTRIP_SELECT){
+ if (!foundsel){
+ foundsel=1;
+ foundstrip = strip;
+ }
+ }
+ else if (foundsel && strip != foundstrip){
+ *rstrip=strip;
+ *sel = 0;
+ return base;
+ }
+ }
+ }
+ ymax=ymin;
+ }
+ }
+ }
+ *rstrip=firststrip;
+ return firstbase;
+}
+
+static Base *get_nearest_nlachannel_ob_key (float *index, short *sel)
+{
+ Base *base;
+ IpoCurve *icu;
+ Base *firstbase=NULL;
+ bConstraintChannel *conchan;
+ int foundsel=0;
+ float firstvertx=-1, foundx=-1;
+ int i;
+ short mval[2];
+ float ymin, ymax;
+ rctf rectf;
+
+ *index=0;
+
+ getmouseco_areawin (mval);
+
+ mval[0]-=7;
+ areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
+
+ mval[0]+=14;
+ areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
+
+ ymax = count_nla_levels();
+
+ ymax*= (NLACHANNELHEIGHT + NLACHANNELSKIP);
+ ymax+= NLACHANNELHEIGHT/2;
+
+ *sel=0;
+
+ for (base=G.scene->base.first; base; base=base->next){
+ if (nla_filter(base)) {
+
+ ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
+
+ /* Handle object ipo selection */
+ if (base->object->ipo){
+ if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
+ for (icu=base->object->ipo->curve.first; icu; icu=icu->next){
+ for (i=0; i<icu->totvert; i++){
+ if (icu->bezt[i].vec[1][0] > rectf.xmin && icu->bezt[i].vec[1][0] <= rectf.xmax ){
+ if (!firstbase){
+ firstbase=base;
+ firstvertx=icu->bezt[i].vec[1][0];
+ *sel = icu->bezt[i].f2 & 1;
+ }
+
+ if (icu->bezt[i].f2 & 1){
+ if (!foundsel){
+ foundsel=1;
+ foundx = icu->bezt[i].vec[1][0];
+ }
+ }
+ else if (foundsel && icu->bezt[i].vec[1][0] != foundx){
+ *index=icu->bezt[i].vec[1][0];
+ *sel = 0;
+ return base;
+ }
+ }
+ }
+ }
+ }
+ }
+ /* Handle object constraint ipos */
+ for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
+ if ( !((ymax < rectf.ymin) || (ymin > rectf.ymax)) && conchan->ipo){
+ for (icu=conchan->ipo->curve.first; icu; icu=icu->next){
+ for (i=0; i<icu->totvert; i++){
+ if (icu->bezt[i].vec[1][0] > rectf.xmin && icu->bezt[i].vec[1][0] <= rectf.xmax ){
+ if (!firstbase){
+ firstbase=base;
+ firstvertx=icu->bezt[i].vec[1][0];
+ *sel = icu->bezt[i].f2 & 1;
+ }
+
+ if (icu->bezt[i].f2 & 1){
+ if (!foundsel){
+ foundsel=1;
+ foundx = icu->bezt[i].vec[1][0];
+ }
+ }
+ else if (foundsel && icu->bezt[i].vec[1][0] != foundx){
+ *index=icu->bezt[i].vec[1][0];
+ *sel = 0;
+ return base;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ ymax=ymin;
+
+ /* Skip actions and nlastrips if object is collapsed */
+ if (base->object->nlaflag & OB_NLA_COLLAPSED)
+ continue;
+
+ /* Skip action ipos */
+ if (base->object->action){
+ ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP);
+ }
+ /* Skip nlastrips */
+ ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP)*BLI_countlist(&base->object->nlastrips);
+ }
+ }
+
+ *index=firstvertx;
+ return firstbase;
+}
+
+static bAction *get_nearest_nlachannel_ac_key (float *index, short *sel)
+{
+ Base *base;
+ IpoCurve *icu;
+ bAction *firstact=NULL;
+ bActionChannel *chan;
+ bConstraintChannel *conchan;
+ rctf rectf;
+ float firstvert=-1, foundx=-1;
+ float ymin, ymax, xmin, xmax;
+ int i;
+ int foundsel=0;
+ short mval[2];
+
+ *index=0;
+
+ getmouseco_areawin (mval);
+
+ mval[0]-=7;
+ areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
+
+ mval[0]+=14;
+ areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
+
+ ymax = count_nla_levels();
+
+ ymax*= (NLACHANNELHEIGHT + NLACHANNELSKIP);
+ ymax+= NLACHANNELHEIGHT/2;
+
+ *sel=0;
+
+ for (base=G.scene->base.first; base; base=base->next){
+ /* Handle object ipo selection */
+ if (nla_filter(base)) {
+
+ /* Skip object ipo and ob-constraint ipo */
+ ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
+
+ /* skip this object if it is collapsed */
+ if (base->object->nlaflag & OB_NLA_COLLAPSED)
+ continue;
+
+ ymax=ymin;
+
+ /* Handle action ipos */
+ if (base->object->action){
+ bAction *act= base->object->action;
+
+ /* if action is mapped in NLA, it returns a correction */
+ xmin= get_action_frame(base->object, rectf.xmin);
+ xmax= get_action_frame(base->object, rectf.xmax);
+
+ ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
+ if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
+ for (chan=act->chanbase.first; chan; chan=chan->next){
+ if(chan->ipo) {
+ for (icu=chan->ipo->curve.first; icu; icu=icu->next){
+ for (i=0; i<icu->totvert; i++){
+ if (icu->bezt[i].vec[1][0] > xmin && icu->bezt[i].vec[1][0] <= xmax ){
+ if (!firstact){
+ firstact= act;
+ firstvert=icu->bezt[i].vec[1][0];
+ *sel = icu->bezt[i].f2 & 1;
+ }
+
+ if (icu->bezt[i].f2 & 1){
+ if (!foundsel){
+ foundsel=1;
+ foundx = icu->bezt[i].vec[1][0];
+ }
+ }
+ else if (foundsel && icu->bezt[i].vec[1][0] != foundx){
+ *index=icu->bezt[i].vec[1][0];
+ *sel = 0;
+ return act;
+ }
+ }
+ }
+ }
+ }
+
+ for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
+ ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
+ if ( !((ymax < rectf.ymin) || (ymin > rectf.ymax)) && conchan->ipo){
+ for (icu=conchan->ipo->curve.first; icu; icu=icu->next){
+ for (i=0; i<icu->totvert; i++){
+ if (icu->bezt[i].vec[1][0] > xmin && icu->bezt[i].vec[1][0] <= xmax ){
+ if (!firstact){
+ firstact=base->object->action;
+ firstvert=icu->bezt[i].vec[1][0];
+ *sel = icu->bezt[i].f2 & 1;
+ }
+
+ if (icu->bezt[i].f2 & 1){
+ if (!foundsel){
+ foundsel=1;
+ foundx = icu->bezt[i].vec[1][0];
+ }
+ }
+ else if (foundsel && icu->bezt[i].vec[1][0] != foundx){
+ *index=icu->bezt[i].vec[1][0];
+ *sel = 0;
+ return base->object->action;
+ }
+ }
+ }
+ }
+ }
+ ymax=ymin;
+ }
+
+
+ }
+ }
+ ymax=ymin;
+ }
+
+ /* Skip nlastrips */
+ ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP)*BLI_countlist(&base->object->nlastrips);
+ }
+ }
+
+ *index=firstvert;
+ return firstact;
+}
+
+void deselect_nlachannels(int test)
+{
+ Base *base;
+ int sel = 1;
+
+ if (test){
+ for (base=G.scene->base.first; base; base=base->next){
+ /* Check base flags for previous selection */
+ if (base->flag & SELECT){
+ sel=0;
+ break;
+ }
+ }
+ }
+ else
+ sel = 0;
+
+ /* Select objects */
+ for (base=G.scene->base.first; base; base=base->next){
+ if (sel){
+ if (nla_filter(base))
+ base->flag |= SELECT;
+ }
+ else
+ base->flag &= ~SELECT;
+
+ base->object->flag= base->flag;
+ }
+}
+
+static Object *get_object_from_active_strip(void) {
+
+ Base *base;
+ bActionStrip *strip;
+
+ for (base=G.scene->base.first; base; base=base->next) {
+ if ((base->object->nlaflag & OB_NLA_COLLAPSED)==0) {
+ for (strip = base->object->nlastrips.first;
+ strip; strip=strip->next){
+ if (strip->flag & ACTSTRIP_SELECT) {
+ return base->object;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+
+void winqreadnlaspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
+{
+ unsigned short event= evt->event;
+ short val= evt->val;
+ SpaceNla *snla = curarea->spacedata.first;
+ int doredraw= 0;
+ short mval[2];
+ float dx,dy;
+ int cfra;
+ short mousebut = L_MOUSE;
+ Object *ob; //in shift-B / bake
+
+ if (curarea->win==0) return;
+ if (!snla) return;
+
+ if(val) {
+ if( uiDoBlocks(&curarea->uiblocks, event)!=UI_NOTHING ) event= 0;
+
+ /* swap mouse buttons based on user preference */
+ if (U.flag & USER_LMOUSESELECT) {
+ if (event == LEFTMOUSE) {
+ event = RIGHTMOUSE;
+ mousebut = L_MOUSE;
+ } else if (event == RIGHTMOUSE) {
+ event = LEFTMOUSE;
+ mousebut = R_MOUSE;
+ }
+ }
+
+ getmouseco_areawin(mval);
+
+ switch(event) {
+ case UI_BUT_EVENT:
+ do_nlabuts(val); // in drawnla.c
+ break;
+
+ case HOMEKEY:
+ do_nla_buttons(B_NLAHOME);
+ break;
+
+ case EQUALKEY:
+ shift_nlastrips_up();
+ break;
+
+ case PAGEUPKEY:
+ if (G.qual & LR_CTRLKEY)
+ shift_nlastrips_up();
+ else {
+ nextprev_marker(1);
+ allqueue(REDRAWMARKER, 0);
+ }
+ break;
+
+ case MINUSKEY:
+ shift_nlastrips_down();
+ break;
+
+ case PAGEDOWNKEY:
+ if (G.qual & LR_CTRLKEY)
+ shift_nlastrips_down();
+ else {
+ nextprev_marker(-1);
+ allqueue(REDRAWMARKER, 0);
+ }
+ break;
+
+ case AKEY:
+ if (G.qual & LR_SHIFTKEY){
+ add_nlablock();
+ allqueue (REDRAWNLA, 0);
+ allqueue (REDRAWVIEW3D, 0);
+ }
+ else if (G.qual & LR_CTRLKEY) {
+ deselect_markers(1, 0);
+ allqueue(REDRAWMARKER, 0);
+ }
+ else{
+ if (mval[0]>=NLAWIDTH)
+ deselect_nlachannel_keys(1);
+ else{
+ deselect_nlachannels(1);
+ allqueue (REDRAWVIEW3D, 0);
+ }
+ allqueue (REDRAWNLA, 0);
+ allqueue (REDRAWIPO, 0);
+ BIF_undo_push("(De)select all NLA");
+ }
+ break;
+
+ case BKEY:
+ if (G.qual & LR_SHIFTKEY){
+ bake_all_to_action();
+ allqueue (REDRAWNLA, 0);
+ allqueue (REDRAWVIEW3D, 0);
+ BIF_undo_push("Bake All To Action");
+ ob = get_object_from_active_strip();
+ //build_match_caches(ob);
+ }
+ else if (G.qual & LR_CTRLKEY)
+ borderselect_markers();
+ else
+ borderselect_nla();
+ break;
+
+ case CKEY:
+ if(G.qual==LR_CTRLKEY) {
+ if(okee("Copy Modifiers"))
+ copy_action_modifiers();
+ }
+ else convert_nla();
+ break;
+
+ case DKEY:
+ if (G.qual == (LR_CTRLKEY|LR_SHIFTKEY) && mval[0]>=NLAWIDTH) {
+ duplicate_marker();
+ }
+ else if (G.qual & LR_SHIFTKEY && mval[0]>=NLAWIDTH){
+ duplicate_nlachannel_keys();
+ update_for_newframe_muted();
+ }
+
+ break;
+
+ case EKEY:
+ if (mval[0] >= NLAWIDTH) {
+ transform_nlachannel_keys ('e', 0);
+ update_for_newframe_muted();
+ }
+ break;
+
+ case GKEY:
+ if (mval[0]>=NLAWIDTH) {
+ if (G.qual & LR_CTRLKEY) {
+ transform_markers('g', 0);
+ }
+ else {
+ transform_nlachannel_keys ('g', 0);
+ update_for_newframe_muted();
+ }
+ }
+ break;
+
+ case MKEY:
+ /* marker operations */
+ if (G.qual == 0)
+ add_marker(CFRA);
+ else if (G.qual == LR_CTRLKEY)
+ rename_marker();
+ else
+ break;
+ allqueue(REDRAWMARKER, 0);
+ break;
+
+ case NKEY:
+ if(G.qual==0) {
+ toggle_blockhandler(curarea, NLA_HANDLER_PROPERTIES, UI_PNL_TO_MOUSE);
+ scrarea_queue_winredraw(curarea);
+ }
+ else if (G.qual & LR_SHIFTKEY) {
+ add_empty_nlablock();
+ }
+ break;
+ case LKEY:
+ relink_active_strip();
+ break;
+
+ case PKEY:
+ if (G.qual & LR_CTRLKEY) /* set preview range */
+ anim_previewrange_set();
+ else if (G.qual & LR_ALTKEY) /* clear preview range */
+ anim_previewrange_clear();
+ allqueue(REDRAWMARKER, 0);
+ break;
+
+ case SKEY:
+ if(G.qual==LR_ALTKEY) {
+ val= pupmenu("Action Strip Scale%t|Clear Strip Scale%x1|Remap Start/End%x2");
+ if(val==1)
+ reset_action_strips(1);
+ else if(val==2)
+ reset_action_strips(2);
+ }
+ else if(G.qual & LR_SHIFTKEY) {
+ if (snla->flag & SNLA_DRAWTIME)
+ val= pupmenu("Snap To%t|Nearest Second%x3|Current Time%x2");
+ else
+ val= pupmenu("Snap To%t|Nearest Frame%x1|Current Frame%x2");
+ if (ELEM3(val, 1, 2, 3))
+ snap_action_strips(val);
+ }
+ else {
+ if (mval[0]>=NLAWIDTH)
+ transform_nlachannel_keys ('s', 0);
+ update_for_newframe_muted();
+ }
+ break;
+
+ case TKEY:
+ if (G.qual & LR_CTRLKEY) {
+ val= pupmenu("Time value%t|Frames %x1|Seconds%x2");
+
+ if (val > 0) {
+ if (val == 2) snla->flag |= SNLA_DRAWTIME;
+ else snla->flag &= ~SNLA_DRAWTIME;
+
+ doredraw= 1;
+ }
+ }
+ break;
+
+ case DELKEY:
+ case XKEY:
+ if (mval[0]>=NLAWIDTH) {
+ if (okee("Erase selected?")) {
+ delete_nlachannel_keys();
+ update_for_newframe_muted();
+
+ remove_marker();
+
+ allqueue(REDRAWMARKER, 0);
+ }
+ }
+ break;
+
+ /* LEFTMOUSE and RIGHTMOUSE event codes can be swapped above,
+ * based on user preference USER_LMOUSESELECT
+ */
+ case LEFTMOUSE:
+ if(view2dmove(LEFTMOUSE))
+ break; // only checks for sliders
+ else if (mval[0]>=snla->v2d.mask.xmin) {
+ do {
+ getmouseco_areawin(mval);
+
+ areamouseco_to_ipoco(G.v2d, mval, &dx, &dy);
+
+ cfra= (int)dx;
+ if(cfra< 1) cfra= 1;
+
+ if( cfra!=CFRA ) {
+ CFRA= cfra;
+ update_for_newframe();
+ force_draw_all(0);
+ }
+ else PIL_sleep_ms(30);
+
+ } while(get_mbut() & mousebut);
+ break;
+ }
+ /* else pass on! */
+ case RIGHTMOUSE:
+ if (mval[0]>=snla->v2d.mask.xmin) {
+ if(G.qual & LR_SHIFTKEY)
+ mouse_nla(SELECT_INVERT);
+ else
+ mouse_nla(SELECT_REPLACE);
+ }
+ else
+ mouse_nlachannels(mval);
+ break;
+
+ case PADPLUSKEY:
+ view2d_zoom(G.v2d, 0.1154, sa->winx, sa->winy);
+ test_view2d(G.v2d, sa->winx, sa->winy);
+ view2d_do_locks(curarea, V2D_LOCK_COPY);
+ doredraw= 1;
+ break;
+ case PADMINUS:
+ view2d_zoom(G.v2d, -0.15, sa->winx, sa->winy);
+ test_view2d(G.v2d, sa->winx, sa->winy);
+ view2d_do_locks(curarea, V2D_LOCK_COPY);
+ doredraw= 1;
+ break;
+ case MIDDLEMOUSE:
+ case WHEELUPMOUSE:
+ case WHEELDOWNMOUSE:
+ view2dmove(event); /* in drawipo.c */
+ break;
+ }
+ }
+
+ if(doredraw) scrarea_queue_winredraw(curarea);
+}
+
+void bake_all_to_action(void)
+{
+ Object *ob;
+ bAction *newAction;
+ Ipo *ipo;
+ ID *id;
+ short hold, add;
+ float repeat;
+
+ /* burn object-level motion into a new action */
+ ob = get_object_from_active_strip();
+ if (ob) {
+ if (ob->flag&OB_ARMATURE) {
+ //newAction = bake_obIPO_to_action(ob);
+ newAction = NULL;
+ if (newAction) {
+ /* unlink the object's IPO */
+ ipo=ob->ipo;
+ if (ipo) {
+ id = &ipo->id;
+ if (id->us > 0)
+ id->us--;
+ ob->ipo = NULL;
+ }
+
+ /* add the new Action to NLA as a strip */
+ hold=1;
+ add=1;
+ repeat=1.0;
+ printf("about to add nla block...\n");
+ add_nla_block_by_name(newAction->id.name, ob, hold, add, repeat);
+ BIF_undo_push("Add NLA strip");
+ }
+ }
+ }
+}
+
+void copy_action_modifiers(void)
+{
+ bActionStrip *strip, *actstrip;
+ Object *ob= OBACT;
+
+ if(ob==NULL)
+ return;
+
+ /* active strip */
+ for (actstrip=ob->nlastrips.first; actstrip; actstrip=actstrip->next)
+ if(actstrip->flag & ACTSTRIP_ACTIVE)
+ break;
+ if(actstrip==NULL)
+ return;
+
+ /* copy to selected items */
+ for (strip=ob->nlastrips.first; strip; strip=strip->next){
+ if (strip->flag & ACTSTRIP_SELECT) {
+ if(strip!=actstrip) {
+ if (strip->modifiers.first)
+ BLI_freelistN(&strip->modifiers);
+ if (actstrip->modifiers.first)
+ duplicatelist (&strip->modifiers, &actstrip->modifiers);
+ }
+ }
+ }
+
+ BIF_undo_push("Copy Action Modifiers");
+ allqueue(REDRAWNLA, 0);
+ DAG_scene_flush_update(G.scene, screen_view3d_layers());
+}
+
diff --git a/source/blender/src/editnode.c b/source/blender/src/editnode.c
new file mode 100644
index 00000000000..e5e83152ae2
--- /dev/null
+++ b/source/blender/src/editnode.c
@@ -0,0 +1,2244 @@
+/**
+ * $Id:
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_action_types.h"
+#include "DNA_color_types.h"
+#include "DNA_image_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_object_types.h"
+#include "DNA_material_types.h"
+#include "DNA_node_types.h"
+#include "DNA_space_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BKE_colortools.h"
+#include "BKE_global.h"
+#include "BKE_image.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_node.h"
+#include "BKE_material.h"
+#include "BKE_scene.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_cursors.h"
+#include "BIF_editview.h"
+#include "BIF_gl.h"
+#include "BIF_graphics.h"
+#include "BIF_imasel.h"
+#include "BIF_interface.h"
+#include "BIF_mywindow.h"
+#include "BIF_previewrender.h"
+#include "BIF_resources.h"
+#include "BIF_renderwin.h"
+#include "BIF_space.h"
+#include "BIF_screen.h"
+#include "BIF_toolbox.h"
+
+#include "BSE_drawipo.h"
+#include "BSE_edit.h"
+#include "BSE_filesel.h"
+#include "BSE_headerbuttons.h"
+#include "BSE_node.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "BDR_editobject.h"
+
+#include "RE_pipeline.h"
+#include "IMB_imbuf_types.h"
+
+#include "blendef.h"
+#include "butspace.h"
+#include "PIL_time.h"
+#include "mydevice.h"
+#include "winlay.h"
+
+
+/* currently called from BIF_preview_changed */
+void snode_tag_dirty(SpaceNode *snode)
+{
+ bNode *node;
+
+ if(snode->treetype==NTREE_SHADER) {
+ if(snode->nodetree) {
+ for(node= snode->nodetree->nodes.first; node; node= node->next) {
+ if(node->type==SH_NODE_OUTPUT)
+ node->lasty= 0;
+ }
+ snode->flag |= SNODE_DO_PREVIEW; /* this adds an afterqueue on a redraw, to allow button previews to work first */
+ }
+ }
+ allqueue(REDRAWNODE, 1);
+}
+
+static void shader_node_previewrender(ScrArea *sa, SpaceNode *snode)
+{
+ bNode *node;
+
+ if(snode->id==NULL) return;
+ if( ((Material *)snode->id )->use_nodes==0 ) return;
+
+ for(node= snode->nodetree->nodes.first; node; node= node->next) {
+ if(node->type==SH_NODE_OUTPUT) {
+ if(node->flag & NODE_DO_OUTPUT) {
+ if(node->lasty<PREVIEW_RENDERSIZE-2) {
+ RenderInfo ri;
+// int test= node->lasty;
+
+ ri.curtile = 0;
+ ri.tottile = 0;
+ ri.rect = NULL;
+ ri.pr_rectx = PREVIEW_RENDERSIZE;
+ ri.pr_recty = PREVIEW_RENDERSIZE;
+
+ BIF_previewrender(snode->id, &ri, NULL, PR_DO_RENDER); /* sends redraw event */
+ if(ri.rect) MEM_freeN(ri.rect);
+
+ /* when not finished... */
+ if(ri.curtile<ri.tottile)
+ addafterqueue(sa->win, RENDERPREVIEW, 1);
+// if(test!=node->lasty)
+// printf("node rendered to %d\n", node->lasty);
+
+ break;
+ }
+ }
+ }
+ }
+}
+
+
+static void snode_handle_recalc(SpaceNode *snode)
+{
+ if(snode->treetype==NTREE_SHADER) {
+ BIF_preview_changed(ID_MA); /* signals buttons windows and node editors */
+ }
+ else if(snode->treetype==NTREE_COMPOSIT) {
+ if(G.scene->use_nodes) {
+ snode->nodetree->timecursor= set_timecursor;
+ G.afbreek= 0;
+ snode->nodetree->test_break= blender_test_break;
+
+ BIF_store_spare();
+
+ ntreeCompositExecTree(snode->nodetree, &G.scene->r, 1); /* 1 is do_previews */
+
+ snode->nodetree->timecursor= NULL;
+ snode->nodetree->test_break= NULL;
+ waitcursor(0);
+
+ allqueue(REDRAWNODE, 1);
+ allqueue(REDRAWIMAGE, 1);
+ if(G.scene->r.scemode & R_DOCOMP) {
+ BIF_redraw_render_rect(); /* seems to screwup display? */
+ mywinset(curarea->win);
+ }
+ }
+ }
+}
+
+static void shader_node_event(SpaceNode *snode, short event)
+{
+ switch(event) {
+ case B_REDR:
+ allqueue(REDRAWNODE, 1);
+ break;
+ default:
+ /* B_NODE_EXEC */
+ snode_handle_recalc(snode);
+ break;
+
+ }
+}
+
+static void load_node_image(char *str) /* called from fileselect */
+{
+ SpaceNode *snode= curarea->spacedata.first;
+ bNode *node= nodeGetActive(snode->edittree);
+ Image *ima= NULL;
+
+ ima= BKE_add_image_file(str);
+ if(ima) {
+ if(node->id)
+ node->id->us--;
+
+ node->id= &ima->id;
+ id_us_plus(node->id);
+
+ BLI_strncpy(node->name, node->id->name+2, 21);
+
+ BKE_image_signal(ima, node->storage, IMA_SIGNAL_RELOAD);
+
+ NodeTagChanged(snode->edittree, node);
+ snode_handle_recalc(snode);
+ allqueue(REDRAWNODE, 0);
+ }
+}
+
+static bNode *snode_get_editgroup(SpaceNode *snode)
+{
+ bNode *gnode;
+
+ /* get the groupnode */
+ for(gnode= snode->nodetree->nodes.first; gnode; gnode= gnode->next)
+ if(gnode->flag & NODE_GROUP_EDIT)
+ break;
+ return gnode;
+}
+
+/* node has to be of type 'render layers' */
+/* is a bit clumsy copying renderdata here... scene nodes use render size of current render */
+static void composite_node_render(SpaceNode *snode, bNode *node)
+{
+ RenderData rd;
+ Scene *scene= NULL;
+ int scemode, actlay;
+
+ /* the button press won't show up otherwise, button hilites disabled */
+ force_draw(0);
+
+ if(node->id && node->id!=(ID *)G.scene) {
+ scene= G.scene;
+ set_scene_bg((Scene *)node->id);
+ rd= G.scene->r;
+ G.scene->r.xsch= scene->r.xsch;
+ G.scene->r.ysch= scene->r.ysch;
+ G.scene->r.size= scene->r.size;
+ G.scene->r.mode &= ~(R_BORDER|R_DOCOMP);
+ G.scene->r.mode |= scene->r.mode & R_BORDER;
+ G.scene->r.border= scene->r.border;
+ }
+
+ scemode= G.scene->r.scemode;
+ actlay= G.scene->r.actlay;
+
+ G.scene->r.scemode |= R_SINGLE_LAYER;
+ G.scene->r.actlay= node->custom1;
+
+ BIF_do_render(0);
+
+ G.scene->r.scemode= scemode;
+ G.scene->r.actlay= actlay;
+
+ node->custom2= 0;
+
+ if(scene) {
+ G.scene->r= rd;
+ set_scene_bg(scene);
+ }
+}
+
+static void composit_node_event(SpaceNode *snode, short event)
+{
+
+ switch(event) {
+ case B_REDR:
+ allqueue(REDRAWNODE, 1);
+ break;
+ case B_NODE_LOADIMAGE:
+ {
+ bNode *node= nodeGetActive(snode->edittree);
+ char name[FILE_MAXDIR+FILE_MAXFILE];
+
+ if(node->id)
+ strcpy(name, ((Image *)node->id)->name);
+ else strcpy(name, U.textudir);
+ if (G.qual & LR_CTRLKEY) {
+ activate_imageselect(FILE_SPECIAL, "SELECT IMAGE", name, load_node_image);
+ } else {
+ activate_fileselect(FILE_SPECIAL, "SELECT IMAGE", name, load_node_image);
+ }
+ break;
+ }
+ case B_NODE_TREE_EXEC:
+ snode_handle_recalc(snode);
+ break;
+ default:
+ /* B_NODE_EXEC */
+ {
+ bNode *node= BLI_findlink(&snode->edittree->nodes, event-B_NODE_EXEC);
+ if(node) {
+ NodeTagChanged(snode->edittree, node);
+ NodeTagIDChanged(snode->nodetree, node->id); /* Scene-layer nodes, texture nodes, image nodes, all can be used many times */
+
+ /* not the best implementation of the world... but we need it to work now :) */
+ if(node->type==CMP_NODE_R_LAYERS && node->custom2) {
+ composite_node_render(snode, node);
+ /* new event, a render can go fullscreen and open new window */
+ addqueue(curarea->win, UI_BUT_EVENT, B_NODE_TREE_EXEC);
+ }
+ else {
+ node= snode_get_editgroup(snode);
+ if(node)
+ NodeTagIDChanged(snode->nodetree, node->id);
+
+ snode_handle_recalc(snode);
+ }
+ }
+ }
+ }
+}
+
+
+/* assumes nothing being done in ntree yet, sets the default in/out node */
+/* called from shading buttons or header */
+void node_shader_default(Material *ma)
+{
+ bNode *in, *out;
+ bNodeSocket *fromsock, *tosock;
+
+ /* but lets check it anyway */
+ if(ma->nodetree) {
+ printf("error in shader initialize\n");
+ return;
+ }
+
+ ma->nodetree= ntreeAddTree(NTREE_SHADER);
+
+ out= nodeAddNodeType(ma->nodetree, SH_NODE_OUTPUT, NULL);
+ out->locx= 300.0f; out->locy= 300.0f;
+
+ in= nodeAddNodeType(ma->nodetree, SH_NODE_MATERIAL, NULL);
+ in->locx= 10.0f; in->locy= 300.0f;
+ nodeSetActive(ma->nodetree, in);
+
+ /* only a link from color to color */
+ fromsock= in->outputs.first;
+ tosock= out->inputs.first;
+ nodeAddLink(ma->nodetree, in, fromsock, out, tosock);
+
+ ntreeSolveOrder(ma->nodetree); /* needed for pointers */
+}
+
+/* assumes nothing being done in ntree yet, sets the default in/out node */
+/* called from shading buttons or header */
+void node_composit_default(Scene *sce)
+{
+ bNode *in, *out;
+ bNodeSocket *fromsock, *tosock;
+
+ /* but lets check it anyway */
+ if(sce->nodetree) {
+ printf("error in composit initialize\n");
+ return;
+ }
+
+ sce->nodetree= ntreeAddTree(NTREE_COMPOSIT);
+
+ out= nodeAddNodeType(sce->nodetree, CMP_NODE_COMPOSITE, NULL);
+ out->locx= 300.0f; out->locy= 400.0f;
+
+ in= nodeAddNodeType(sce->nodetree, CMP_NODE_R_LAYERS, NULL);
+ in->locx= 10.0f; in->locy= 400.0f;
+ nodeSetActive(sce->nodetree, in);
+
+ /* links from color to color */
+ fromsock= in->outputs.first;
+ tosock= out->inputs.first;
+ nodeAddLink(sce->nodetree, in, fromsock, out, tosock);
+
+ ntreeSolveOrder(sce->nodetree); /* needed for pointers */
+
+ ntreeCompositForceHidden(sce->nodetree);
+}
+
+/* Here we set the active tree(s), even called for each redraw now, so keep it fast :) */
+void snode_set_context(SpaceNode *snode)
+{
+ Object *ob= OBACT;
+ bNode *node= NULL;
+
+ snode->nodetree= NULL;
+ snode->id= snode->from= NULL;
+
+ if(snode->treetype==NTREE_SHADER) {
+ /* need active object, or we allow pinning... */
+ if(ob) {
+ Material *ma= give_current_material(ob, ob->actcol);
+ if(ma) {
+ snode->from= material_from(ob, ob->actcol);
+ snode->id= &ma->id;
+ snode->nodetree= ma->nodetree;
+ }
+ }
+ }
+ else if(snode->treetype==NTREE_COMPOSIT) {
+ snode->from= NULL;
+ snode->id= &G.scene->id;
+
+ /* bit clumsy but reliable way to see if we draw first time */
+ if(snode->nodetree==NULL)
+ ntreeCompositForceHidden(G.scene->nodetree);
+
+ snode->nodetree= G.scene->nodetree;
+ }
+
+ /* find editable group */
+ if(snode->nodetree)
+ for(node= snode->nodetree->nodes.first; node; node= node->next)
+ if(node->flag & NODE_GROUP_EDIT)
+ break;
+
+ if(node && node->id)
+ snode->edittree= (bNodeTree *)node->id;
+ else
+ snode->edittree= snode->nodetree;
+}
+
+/* on activate image viewer, check if we show it */
+static void node_active_image(Image *ima)
+{
+ ScrArea *sa;
+ SpaceImage *sima= NULL;
+
+ /* find an imagewindow showing render result */
+ for(sa=G.curscreen->areabase.first; sa; sa= sa->next) {
+ if(sa->spacetype==SPACE_IMAGE) {
+ sima= sa->spacedata.first;
+ if(sima->image && sima->image->source!=IMA_SRC_VIEWER)
+ break;
+ }
+ }
+ if(sa && sima) {
+ sima->image= ima;
+ scrarea_queue_winredraw(sa);
+ scrarea_queue_headredraw(sa);
+ }
+}
+
+
+static void node_set_active(SpaceNode *snode, bNode *node)
+{
+
+ nodeSetActive(snode->edittree, node);
+
+ if(node->type!=NODE_GROUP) {
+
+ /* tree specific activate calls */
+ if(snode->treetype==NTREE_SHADER) {
+
+ /* when we select a material, active texture is cleared, for buttons */
+ if(node->id && GS(node->id->name)==ID_MA)
+ nodeClearActiveID(snode->edittree, ID_TE);
+ if(node->id)
+ BIF_preview_changed(-1); /* temp hack to force texture preview to update */
+
+ allqueue(REDRAWBUTSSHADING, 1);
+ allqueue(REDRAWIPO, 0);
+ }
+ else if(snode->treetype==NTREE_COMPOSIT) {
+ /* make active viewer, currently only 1 supported... */
+ if( ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) {
+ bNode *tnode;
+ int was_output= node->flag & NODE_DO_OUTPUT;
+
+ for(tnode= snode->edittree->nodes.first; tnode; tnode= tnode->next)
+ if( ELEM(tnode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER))
+ tnode->flag &= ~NODE_DO_OUTPUT;
+
+ node->flag |= NODE_DO_OUTPUT;
+ if(was_output==0) {
+ bNode *gnode;
+
+ NodeTagChanged(snode->edittree, node);
+
+ /* if inside group, tag entire group */
+ gnode= snode_get_editgroup(snode);
+ if(gnode)
+ NodeTagIDChanged(snode->nodetree, gnode->id);
+
+ snode_handle_recalc(snode);
+ }
+
+ /* addnode() doesnt link this yet... */
+ node->id= (ID *)BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
+ }
+ else if(node->type==CMP_NODE_IMAGE) {
+ if(node->id)
+ node_active_image((Image *)node->id);
+ }
+ else if(node->type==CMP_NODE_R_LAYERS) {
+ if(node->id==NULL || node->id==(ID *)G.scene) {
+ G.scene->r.actlay= node->custom1;
+ allqueue(REDRAWBUTSSCENE, 0);
+ }
+ }
+ }
+ }
+}
+
+void snode_make_group_editable(SpaceNode *snode, bNode *gnode)
+{
+ bNode *node;
+
+ /* make sure nothing has group editing on */
+ for(node= snode->nodetree->nodes.first; node; node= node->next)
+ node->flag &= ~NODE_GROUP_EDIT;
+
+ if(gnode==NULL) {
+ /* with NULL argument we do a toggle */
+ if(snode->edittree==snode->nodetree)
+ gnode= nodeGetActive(snode->nodetree);
+ }
+
+ if(gnode && gnode->type==NODE_GROUP && gnode->id) {
+ if(gnode->id->lib) {
+ if(okee("Make Group Local"))
+ ntreeMakeLocal((bNodeTree *)gnode->id);
+ else
+ return;
+ }
+ gnode->flag |= NODE_GROUP_EDIT;
+ snode->edittree= (bNodeTree *)gnode->id;
+
+ /* deselect all other nodes, so we can also do grabbing of entire subtree */
+ for(node= snode->nodetree->nodes.first; node; node= node->next)
+ node->flag &= ~SELECT;
+ gnode->flag |= SELECT;
+
+ }
+ else
+ snode->edittree= snode->nodetree;
+
+ ntreeSolveOrder(snode->nodetree);
+
+ /* finally send out events for new active node */
+ if(snode->treetype==NTREE_SHADER) {
+ allqueue(REDRAWBUTSSHADING, 0);
+
+ BIF_preview_changed(-1); /* temp hack to force texture preview to update */
+ }
+
+ allqueue(REDRAWNODE, 0);
+}
+
+void node_ungroup(SpaceNode *snode)
+{
+ bNode *gnode;
+
+ /* are we inside of a group? */
+ gnode= snode_get_editgroup(snode);
+ if(gnode)
+ snode_make_group_editable(snode, NULL);
+
+ gnode= nodeGetActive(snode->edittree);
+ if(gnode==NULL) return;
+
+ if(gnode->type!=NODE_GROUP)
+ error("Not a group");
+ else {
+ if(nodeGroupUnGroup(snode->edittree, gnode)) {
+
+ BIF_undo_push("Deselect all nodes");
+ allqueue(REDRAWNODE, 0);
+ }
+ else
+ error("Can't ungroup");
+ }
+}
+
+/* when links in groups change, inputs/outputs change, nodes added/deleted... */
+static void snode_verify_groups(SpaceNode *snode)
+{
+ bNode *gnode;
+
+ gnode= snode_get_editgroup(snode);
+
+ /* does all materials */
+ if(gnode)
+ nodeVerifyGroup((bNodeTree *)gnode->id);
+
+}
+
+static void node_addgroup(SpaceNode *snode)
+{
+ bNodeTree *ngroup;
+ int tot= 0, offs, val;
+ char *strp;
+
+ if(snode->edittree!=snode->nodetree) {
+ error("Can not add a Group in a Group");
+ return;
+ }
+
+ /* construct menu with choices */
+ for(ngroup= G.main->nodetree.first; ngroup; ngroup= ngroup->id.next) {
+ if(ngroup->type==snode->treetype)
+ tot++;
+ }
+ if(tot==0) {
+ error("No groups available in database");
+ return;
+ }
+ strp= MEM_mallocN(32*tot+32, "menu");
+ strcpy(strp, "Add Group %t");
+ offs= strlen(strp);
+
+ for(tot=0, ngroup= G.main->nodetree.first; ngroup; ngroup= ngroup->id.next, tot++) {
+ if(ngroup->type==snode->treetype)
+ offs+= sprintf(strp+offs, "|%s %%x%d", ngroup->id.name+2, tot);
+ }
+
+ val= pupmenu(strp);
+ if(val>=0) {
+ ngroup= BLI_findlink(&G.main->nodetree, val);
+ if(ngroup) {
+ bNode *node= nodeAddNodeType(snode->edittree, NODE_GROUP, ngroup);
+
+ /* generics */
+ if(node) {
+ float locx, locy;
+ short mval[2];
+
+ node_deselectall(snode, 0);
+
+ getmouseco_areawin(mval);
+ areamouseco_to_ipoco(G.v2d, mval, &locx, &locy);
+
+ node->locx= locx;
+ node->locy= locy + 60.0f; // arbitrary.. so its visible
+ node->flag |= SELECT;
+
+ id_us_plus(node->id);
+
+ node_set_active(snode, node);
+ BIF_undo_push("Add Node");
+ }
+ }
+ }
+ MEM_freeN(strp);
+}
+
+
+/* ************************** Node generic ************** */
+
+/* allows to walk the list in order of visibility */
+static bNode *next_node(bNodeTree *ntree)
+{
+ static bNode *current=NULL, *last= NULL;
+
+ if(ntree) {
+ /* set current to the first selected node */
+ for(current= ntree->nodes.last; current; current= current->prev)
+ if(current->flag & NODE_SELECT)
+ break;
+
+ /* set last to the first unselected node */
+ for(last= ntree->nodes.last; last; last= last->prev)
+ if((last->flag & NODE_SELECT)==0)
+ break;
+
+ if(current==NULL)
+ current= last;
+
+ return NULL;
+ }
+ /* no nodes, or we are ready */
+ if(current==NULL)
+ return NULL;
+
+ /* now we walk the list backwards, but we always return current */
+ if(current->flag & NODE_SELECT) {
+ bNode *node= current;
+
+ /* find previous selected */
+ current= current->prev;
+ while(current && (current->flag & NODE_SELECT)==0)
+ current= current->prev;
+
+ /* find first unselected */
+ if(current==NULL)
+ current= last;
+
+ return node;
+ }
+ else {
+ bNode *node= current;
+
+ /* find previous unselected */
+ current= current->prev;
+ while(current && (current->flag & NODE_SELECT))
+ current= current->prev;
+
+ return node;
+ }
+
+ return NULL;
+}
+
+/* is rct in visible part of node? */
+static bNode *visible_node(SpaceNode *snode, rctf *rct)
+{
+ bNode *tnode;
+
+ for(next_node(snode->edittree); (tnode=next_node(NULL));) {
+ if(BLI_isect_rctf(&tnode->totr, rct, NULL))
+ break;
+ }
+ return tnode;
+}
+
+void snode_home(ScrArea *sa, SpaceNode *snode)
+{
+ bNode *node;
+ int first= 1;
+
+ snode->v2d.cur.xmin= snode->v2d.cur.ymin= 0.0f;
+ snode->v2d.cur.xmax= sa->winx;
+ snode->v2d.cur.xmax= sa->winy;
+
+ if(snode->edittree) {
+ for(node= snode->edittree->nodes.first; node; node= node->next) {
+ if(first) {
+ first= 0;
+ snode->v2d.cur= node->totr;
+ }
+ else {
+ BLI_union_rctf(&snode->v2d.cur, &node->totr);
+ }
+ }
+ }
+ snode->v2d.tot= snode->v2d.cur;
+
+ snode->xof = snode->yof = 0.0;
+
+ test_view2d(G.v2d, sa->winx, sa->winy);
+
+}
+
+void snode_zoom_out(ScrArea *sa)
+{
+ float dx;
+
+ dx= (float)(0.15*(G.v2d->cur.xmax-G.v2d->cur.xmin));
+ G.v2d->cur.xmin-= dx;
+ G.v2d->cur.xmax+= dx;
+ dx= (float)(0.15*(G.v2d->cur.ymax-G.v2d->cur.ymin));
+ G.v2d->cur.ymin-= dx;
+ G.v2d->cur.ymax+= dx;
+ test_view2d(G.v2d, sa->winx, sa->winy);
+}
+
+void snode_zoom_in(ScrArea *sa)
+{
+ float dx;
+
+ dx= (float)(0.1154*(G.v2d->cur.xmax-G.v2d->cur.xmin));
+ G.v2d->cur.xmin+= dx;
+ G.v2d->cur.xmax-= dx;
+ dx= (float)(0.1154*(G.v2d->cur.ymax-G.v2d->cur.ymin));
+ G.v2d->cur.ymin+= dx;
+ G.v2d->cur.ymax-= dx;
+ test_view2d(G.v2d, sa->winx, sa->winy);
+}
+
+static void snode_bg_viewmove(SpaceNode *snode)
+{
+ ScrArea *sa;
+ Image *ima;
+ ImBuf *ibuf;
+ Window *win;
+ short mval[2], mvalo[2];
+ short rectx, recty, xmin, xmax, ymin, ymax, pad;
+ int oldcursor;
+
+ ima= BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
+ ibuf= BKE_image_get_ibuf(ima, NULL);
+
+ sa = snode->area;
+
+ if(ibuf) {
+ rectx = ibuf->x;
+ recty = ibuf->y;
+ } else {
+ rectx = recty = 1;
+ }
+
+ pad = 10;
+ xmin = -(sa->winx/2) - rectx/2 + pad;
+ xmax = sa->winx/2 + rectx/2 - pad;
+ ymin = -(sa->winy/2) - recty/2 + pad;
+ ymax = sa->winy/2 + recty/2 - pad;
+
+ getmouseco_sc(mvalo);
+
+ /* store the old cursor to temporarily change it */
+ oldcursor=get_cursor();
+ win=winlay_get_active_window();
+
+ SetBlenderCursor(BC_NSEW_SCROLLCURSOR);
+
+ while(get_mbut()&(L_MOUSE|M_MOUSE)) {
+
+ getmouseco_sc(mval);
+
+ if(mvalo[0]!=mval[0] || mvalo[1]!=mval[1]) {
+
+ snode->xof -= (mvalo[0]-mval[0]);
+ snode->yof -= (mvalo[1]-mval[1]);
+
+ /* prevent dragging image outside of the window and losing it! */
+ CLAMP(snode->xof, xmin, xmax);
+ CLAMP(snode->yof, ymin, ymax);
+
+ mvalo[0]= mval[0];
+ mvalo[1]= mval[1];
+
+ scrarea_do_windraw(curarea);
+ screen_swapbuffers();
+ }
+ else BIF_wait_for_statechange();
+ }
+
+ window_set_cursor(win, oldcursor);
+}
+
+/* checks mouse position, and returns found node/socket */
+/* type is SOCK_IN and/or SOCK_OUT */
+static int find_indicated_socket(SpaceNode *snode, bNode **nodep, bNodeSocket **sockp, int in_out)
+{
+ bNode *node;
+ bNodeSocket *sock;
+ rctf rect;
+ short mval[2];
+
+ getmouseco_areawin(mval);
+
+ /* check if we click in a socket */
+ for(node= snode->edittree->nodes.first; node; node= node->next) {
+
+ areamouseco_to_ipoco(G.v2d, mval, &rect.xmin, &rect.ymin);
+
+ rect.xmin -= NODE_SOCKSIZE+3;
+ rect.ymin -= NODE_SOCKSIZE+3;
+ rect.xmax = rect.xmin + 2*NODE_SOCKSIZE+6;
+ rect.ymax = rect.ymin + 2*NODE_SOCKSIZE+6;
+
+ if (!(node->flag & NODE_HIDDEN)) {
+ /* extra padding inside and out - allow dragging on the text areas too */
+ if (in_out == SOCK_IN) {
+ rect.xmax += NODE_SOCKSIZE;
+ rect.xmin -= NODE_SOCKSIZE*4;
+ } else if (in_out == SOCK_OUT) {
+ rect.xmax += NODE_SOCKSIZE*4;
+ rect.xmin -= NODE_SOCKSIZE;
+ }
+ }
+
+ if(in_out & SOCK_IN) {
+ for(sock= node->inputs.first; sock; sock= sock->next) {
+ if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
+ if(BLI_in_rctf(&rect, sock->locx, sock->locy)) {
+ if(node == visible_node(snode, &rect)) {
+ *nodep= node;
+ *sockp= sock;
+ return 1;
+ }
+ }
+ }
+ }
+ }
+ if(in_out & SOCK_OUT) {
+ for(sock= node->outputs.first; sock; sock= sock->next) {
+ if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
+ if(BLI_in_rctf(&rect, sock->locx, sock->locy)) {
+ if(node == visible_node(snode, &rect)) {
+ *nodep= node;
+ *sockp= sock;
+ return 1;
+ }
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+/* ********************* transform ****************** */
+
+/* releases on event, only intern (for extern see below) */
+/* we need argument ntree to allow operations on edittree or nodetree */
+static void transform_nodes(bNodeTree *ntree, char mode, char *undostr)
+{
+ bNode *node;
+ float mxstart, mystart, mx, my, *oldlocs, *ol;
+ int cont=1, tot=0, cancel=0, firsttime=1;
+ short mval[2], mvalo[2];
+
+ /* count total */
+ for(node= ntree->nodes.first; node; node= node->next)
+ if(node->flag & SELECT) tot++;
+
+ if(tot==0) return;
+
+ /* store oldlocs */
+ ol= oldlocs= MEM_mallocN(sizeof(float)*2*tot, "oldlocs transform");
+ for(node= ntree->nodes.first; node; node= node->next) {
+ if(node->flag & SELECT) {
+ ol[0]= node->locx; ol[1]= node->locy;
+ ol+= 2;
+ }
+ }
+
+ getmouseco_areawin(mvalo);
+ areamouseco_to_ipoco(G.v2d, mvalo, &mxstart, &mystart);
+
+ while(cont) {
+
+ getmouseco_areawin(mval);
+ if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || firsttime) {
+
+ firsttime= 0;
+
+ areamouseco_to_ipoco(G.v2d, mval, &mx, &my);
+ mvalo[0]= mval[0];
+ mvalo[1]= mval[1];
+
+ for(ol= oldlocs, node= ntree->nodes.first; node; node= node->next) {
+ if(node->flag & SELECT) {
+ node->locx= ol[0] + mx-mxstart;
+ node->locy= ol[1] + my-mystart;
+ ol+= 2;
+ }
+ }
+
+ force_draw(0);
+ }
+ else
+ PIL_sleep_ms(10);
+
+ while (qtest()) {
+ short val;
+ unsigned short event= extern_qread(&val);
+
+ switch (event) {
+ case LEFTMOUSE:
+ case SPACEKEY:
+ case RETKEY:
+ cont=0;
+ break;
+ case ESCKEY:
+ case RIGHTMOUSE:
+ if(val) {
+ cancel=1;
+ cont=0;
+ }
+ break;
+ default:
+ if(val) arrows_move_cursor(event);
+ break;
+ }
+ }
+
+ }
+
+ if(cancel) {
+ for(ol= oldlocs, node= ntree->nodes.first; node; node= node->next) {
+ if(node->flag & SELECT) {
+ node->locx= ol[0];
+ node->locy= ol[1];
+ ol+= 2;
+ }
+ }
+
+ }
+ else
+ BIF_undo_push(undostr);
+
+ allqueue(REDRAWNODE, 1);
+ MEM_freeN(oldlocs);
+}
+
+/* external call, also for callback */
+void node_transform_ext(int mode, int unused)
+{
+ SpaceNode *snode= curarea->spacedata.first;
+
+ transform_nodes(snode->edittree, 'g', "Move Node");
+}
+
+
+/* releases on event, only 1 node */
+static void scale_node(SpaceNode *snode, bNode *node)
+{
+ float mxstart, mystart, mx, my, oldwidth;
+ int cont=1, cancel=0;
+ short mval[2], mvalo[2];
+
+ /* store old */
+ if(node->flag & NODE_HIDDEN)
+ oldwidth= node->miniwidth;
+ else
+ oldwidth= node->width;
+
+ getmouseco_areawin(mvalo);
+ areamouseco_to_ipoco(G.v2d, mvalo, &mxstart, &mystart);
+
+ while(cont) {
+
+ getmouseco_areawin(mval);
+ if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1]) {
+
+ areamouseco_to_ipoco(G.v2d, mval, &mx, &my);
+ mvalo[0]= mval[0];
+ mvalo[1]= mval[1];
+
+ if(node->flag & NODE_HIDDEN) {
+ node->miniwidth= oldwidth + mx-mxstart;
+ CLAMP(node->miniwidth, 0.0f, 100.0f);
+ }
+ else {
+ node->width= oldwidth + mx-mxstart;
+ CLAMP(node->width, node->typeinfo->minwidth, node->typeinfo->maxwidth);
+ }
+
+ force_draw(0);
+ }
+ else
+ PIL_sleep_ms(10);
+
+ while (qtest()) {
+ short val;
+ unsigned short event= extern_qread(&val);
+
+ switch (event) {
+ case LEFTMOUSE:
+ case SPACEKEY:
+ case RETKEY:
+ cont=0;
+ break;
+ case ESCKEY:
+ case RIGHTMOUSE:
+ if(val) {
+ cancel=1;
+ cont=0;
+ }
+ break;
+ }
+ }
+
+ }
+
+ if(cancel) {
+ node->width= oldwidth;
+ }
+ else
+ BIF_undo_push("Scale Node");
+
+ allqueue(REDRAWNODE, 1);
+}
+
+
+
+/* ********************** select ******************** */
+
+/* used in buttons to check context, also checks for edited groups */
+bNode *editnode_get_active_idnode(bNodeTree *ntree, short id_code)
+{
+ bNode *node;
+
+ /* check for edited group */
+ for(node= ntree->nodes.first; node; node= node->next)
+ if(node->flag & NODE_GROUP_EDIT)
+ break;
+ if(node)
+ return nodeGetActiveID((bNodeTree *)node->id, id_code);
+ else
+ return nodeGetActiveID(ntree, id_code);
+}
+
+/* used in buttons to check context, also checks for edited groups */
+Material *editnode_get_active_material(Material *ma)
+{
+ if(ma && ma->use_nodes && ma->nodetree) {
+ bNode *node= editnode_get_active_idnode(ma->nodetree, ID_MA);
+ if(node)
+ return (Material *)node->id;
+ else
+ return NULL;
+ }
+ return ma;
+}
+
+/* used in buttons to check context, also checks for edited groups */
+bNode *editnode_get_active(bNodeTree *ntree)
+{
+ bNode *node;
+
+ /* check for edited group */
+ for(node= ntree->nodes.first; node; node= node->next)
+ if(node->flag & NODE_GROUP_EDIT)
+ break;
+ if(node)
+ return nodeGetActive((bNodeTree *)node->id);
+ else
+ return nodeGetActive(ntree);
+}
+
+
+/* no undo here! */
+void node_deselectall(SpaceNode *snode, int swap)
+{
+ bNode *node;
+
+ if(swap) {
+ for(node= snode->edittree->nodes.first; node; node= node->next)
+ if(node->flag & SELECT)
+ break;
+ if(node==NULL) {
+ for(node= snode->edittree->nodes.first; node; node= node->next)
+ node->flag |= SELECT;
+ allqueue(REDRAWNODE, 0);
+ return;
+ }
+ /* else pass on to deselect */
+ }
+
+ for(node= snode->edittree->nodes.first; node; node= node->next)
+ node->flag &= ~SELECT;
+
+ allqueue(REDRAWNODE, 0);
+}
+
+int node_has_hidden_sockets(bNode *node)
+{
+ bNodeSocket *sock;
+
+ for(sock= node->inputs.first; sock; sock= sock->next)
+ if(sock->flag & SOCK_HIDDEN)
+ return 1;
+ for(sock= node->outputs.first; sock; sock= sock->next)
+ if(sock->flag & SOCK_HIDDEN)
+ return 1;
+ return 0;
+}
+
+
+static void node_hide_unhide_sockets(SpaceNode *snode, bNode *node)
+{
+ bNodeSocket *sock;
+
+ /* unhide all */
+ if( node_has_hidden_sockets(node) ) {
+ for(sock= node->inputs.first; sock; sock= sock->next)
+ sock->flag &= ~SOCK_HIDDEN;
+ for(sock= node->outputs.first; sock; sock= sock->next)
+ sock->flag &= ~SOCK_HIDDEN;
+ }
+ else {
+ bNode *gnode= snode_get_editgroup(snode);
+
+ /* hiding inside group should not break links in other group users */
+ if(gnode) {
+ nodeGroupSocketUseFlags((bNodeTree *)gnode->id);
+ for(sock= node->inputs.first; sock; sock= sock->next)
+ if(!(sock->flag & SOCK_IN_USE))
+ if(sock->link==NULL)
+ sock->flag |= SOCK_HIDDEN;
+ for(sock= node->outputs.first; sock; sock= sock->next)
+ if(!(sock->flag & SOCK_IN_USE))
+ if(nodeCountSocketLinks(snode->edittree, sock)==0)
+ sock->flag |= SOCK_HIDDEN;
+ }
+ else {
+ /* hide unused sockets */
+ for(sock= node->inputs.first; sock; sock= sock->next) {
+ if(sock->link==NULL)
+ sock->flag |= SOCK_HIDDEN;
+ }
+ for(sock= node->outputs.first; sock; sock= sock->next) {
+ if(nodeCountSocketLinks(snode->edittree, sock)==0)
+ sock->flag |= SOCK_HIDDEN;
+ }
+ }
+ }
+
+ allqueue(REDRAWNODE, 1);
+ snode_verify_groups(snode);
+ BIF_undo_push("Hide/Unhide sockets");
+
+}
+
+static int do_header_node(SpaceNode *snode, bNode *node, float mx, float my)
+{
+ rctf totr= node->totr;
+
+ totr.ymin= totr.ymax-20.0f;
+
+ totr.xmax= totr.xmin+15.0f;
+ if(BLI_in_rctf(&totr, mx, my)) {
+ node->flag |= NODE_HIDDEN;
+ allqueue(REDRAWNODE, 0);
+ return 1;
+ }
+
+ totr.xmax= node->totr.xmax;
+ totr.xmin= totr.xmax-18.0f;
+ if(node->typeinfo->flag & NODE_PREVIEW) {
+ if(BLI_in_rctf(&totr, mx, my)) {
+ node->flag ^= NODE_PREVIEW;
+ allqueue(REDRAWNODE, 0);
+ return 1;
+ }
+ totr.xmin-=18.0f;
+ }
+ if(node->type == NODE_GROUP) {
+ if(BLI_in_rctf(&totr, mx, my)) {
+ snode_make_group_editable(snode, node);
+ return 1;
+ }
+ totr.xmin-=18.0f;
+ }
+ if(node->typeinfo->flag & NODE_OPTIONS) {
+ if(BLI_in_rctf(&totr, mx, my)) {
+ node->flag ^= NODE_OPTIONS;
+ allqueue(REDRAWNODE, 0);
+ return 1;
+ }
+ totr.xmin-=18.0f;
+ }
+ /* hide unused sockets */
+ if(BLI_in_rctf(&totr, mx, my)) {
+ node_hide_unhide_sockets(snode, node);
+ }
+
+
+ totr= node->totr;
+ totr.xmin= totr.xmax-10.0f;
+ totr.ymax= totr.ymin+10.0f;
+ if(BLI_in_rctf(&totr, mx, my)) {
+ scale_node(snode, node);
+ return 1;
+ }
+ return 0;
+}
+
+static int do_header_hidden_node(SpaceNode *snode, bNode *node, float mx, float my)
+{
+ rctf totr= node->totr;
+
+ totr.xmax= totr.xmin+15.0f;
+ if(BLI_in_rctf(&totr, mx, my)) {
+ node->flag &= ~NODE_HIDDEN;
+ allqueue(REDRAWNODE, 0);
+ return 1;
+ }
+
+ totr.xmax= node->totr.xmax;
+ totr.xmin= node->totr.xmax-15.0f;
+ if(BLI_in_rctf(&totr, mx, my)) {
+ scale_node(snode, node);
+ return 1;
+ }
+ return 0;
+}
+
+
+/* return 0: nothing done */
+static int node_mouse_select(SpaceNode *snode, unsigned short event)
+{
+ bNode *node;
+ float mx, my;
+ short mval[2];
+
+ getmouseco_areawin(mval);
+ areamouseco_to_ipoco(G.v2d, mval, &mx, &my);
+
+ for(next_node(snode->edittree); (node=next_node(NULL));) {
+
+ /* first check for the headers or scaling widget */
+ if(node->flag & NODE_HIDDEN) {
+ if(do_header_hidden_node(snode, node, mx, my))
+ return 1;
+ }
+ else {
+ if(do_header_node(snode, node, mx, my))
+ return 1;
+ }
+
+ /* node body */
+ if(BLI_in_rctf(&node->totr, mx, my))
+ break;
+ }
+ if(node) {
+ if((G.qual & LR_SHIFTKEY)==0)
+ node_deselectall(snode, 0);
+
+ if(G.qual & LR_SHIFTKEY) {
+ if(node->flag & SELECT)
+ node->flag &= ~SELECT;
+ else
+ node->flag |= SELECT;
+ }
+ else
+ node->flag |= SELECT;
+
+ node_set_active(snode, node);
+
+ /* not so nice (no event), but function below delays redraw otherwise */
+ force_draw(0);
+
+ std_rmouse_transform(node_transform_ext); /* does undo push for select */
+
+ return 1;
+ }
+ return 0;
+}
+
+/* return 0, nothing done */
+static int node_mouse_groupheader(SpaceNode *snode)
+{
+ bNode *gnode;
+ float mx, my;
+ short mval[2];
+
+ gnode= snode_get_editgroup(snode);
+ if(gnode==NULL) return 0;
+
+ getmouseco_areawin(mval);
+ areamouseco_to_ipoco(G.v2d, mval, &mx, &my);
+
+ /* click in header or outside? */
+ if(BLI_in_rctf(&gnode->totr, mx, my)==0) {
+ rctf rect= gnode->totr;
+
+ rect.ymax += NODE_DY;
+ if(BLI_in_rctf(&rect, mx, my)==0)
+ snode_make_group_editable(snode, NULL); /* toggles, so exits editmode */
+ else
+ transform_nodes(snode->nodetree, 'g', "Move group");
+
+ return 1;
+ }
+ return 0;
+}
+
+static int node_socket_hilights(SpaceNode *snode, int in_out)
+{
+ bNode *node;
+ bNodeSocket *sock, *tsock, *socksel= NULL;
+ float mx, my;
+ short mval[2], redraw= 0;
+
+ if(snode->edittree==NULL) return 0;
+
+ getmouseco_areawin(mval);
+ areamouseco_to_ipoco(G.v2d, mval, &mx, &my);
+
+ /* deselect socks */
+ for(node= snode->edittree->nodes.first; node; node= node->next) {
+ for(sock= node->inputs.first; sock; sock= sock->next) {
+ if(sock->flag & SELECT) {
+ sock->flag &= ~SELECT;
+ redraw++;
+ socksel= sock;
+ }
+ }
+ for(sock= node->outputs.first; sock; sock= sock->next) {
+ if(sock->flag & SELECT) {
+ sock->flag &= ~SELECT;
+ redraw++;
+ socksel= sock;
+ }
+ }
+ }
+
+ if(find_indicated_socket(snode, &node, &tsock, in_out)) {
+ tsock->flag |= SELECT;
+ if(redraw==1 && tsock==socksel) redraw= 0;
+ else redraw= 1;
+ }
+
+ return redraw;
+}
+
+void node_border_select(SpaceNode *snode)
+{
+ bNode *node;
+ rcti rect;
+ rctf rectf;
+ short val, mval[2];
+
+ if ( (val = get_border(&rect, 3)) ) {
+
+ mval[0]= rect.xmin;
+ mval[1]= rect.ymin;
+ areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
+ mval[0]= rect.xmax;
+ mval[1]= rect.ymax;
+ areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
+
+ for(node= snode->edittree->nodes.first; node; node= node->next) {
+ if(BLI_isect_rctf(&rectf, &node->totr, NULL)) {
+ if(val==LEFTMOUSE)
+ node->flag |= SELECT;
+ else
+ node->flag &= ~SELECT;
+ }
+ }
+ allqueue(REDRAWNODE, 1);
+ BIF_undo_push("Border select nodes");
+ }
+}
+
+/* ****************** Add *********************** */
+
+void snode_autoconnect(SpaceNode *snode, bNode *node_to, int flag)
+{
+ bNodeSocket *sock, *sockfrom[8];
+ bNode *node, *nodefrom[8];
+ int totsock= 0, socktype=0;
+
+ if(node_to->inputs.first==NULL)
+ return;
+
+ /* no inputs for node allowed (code it) */
+
+ /* connect first 1 socket type now */
+ for(sock= node_to->inputs.first; sock; sock= sock->next)
+ if(socktype<sock->type)
+ socktype= sock->type;
+
+
+ /* find potential sockets, max 8 should work */
+ for(node= snode->edittree->nodes.first; node; node= node->next) {
+ if((node->flag & flag) && node!=node_to) {
+ for(sock= node->outputs.first; sock; sock= sock->next) {
+ if(!(sock->flag & (SOCK_HIDDEN|SOCK_UNAVAIL))) {
+ sockfrom[totsock]= sock;
+ nodefrom[totsock]= node;
+ totsock++;
+ if(totsock>7)
+ break;
+ }
+ }
+ }
+ if(totsock>7)
+ break;
+ }
+
+ /* now just get matching socket types and create links */
+ for(sock= node_to->inputs.first; sock; sock= sock->next) {
+ int a;
+
+ for(a=0; a<totsock; a++) {
+ if(sockfrom[a]) {
+ if(sock->type==sockfrom[a]->type && sock->type==socktype) {
+ nodeAddLink(snode->edittree, nodefrom[a], sockfrom[a], node_to, sock);
+ sockfrom[a]= NULL;
+ break;
+ }
+ }
+ }
+ }
+
+ ntreeSolveOrder(snode->edittree);
+}
+
+/* can be called from menus too, but they should do own undopush and redraws */
+bNode *node_add_node(SpaceNode *snode, int type, float locx, float locy)
+{
+ bNode *node= NULL, *gnode;
+
+ node_deselectall(snode, 0);
+
+ if(type>=NODE_GROUP_MENU) {
+ if(snode->edittree!=snode->nodetree) {
+ error("Can not add a Group in a Group");
+ return NULL;
+ }
+ else {
+ bNodeTree *ngroup= BLI_findlink(&G.main->nodetree, type-NODE_GROUP_MENU);
+ if(ngroup)
+ node= nodeAddNodeType(snode->edittree, NODE_GROUP, ngroup);
+ }
+ }
+ else
+ node= nodeAddNodeType(snode->edittree, type, NULL);
+
+ /* generics */
+ if(node) {
+ node->locx= locx;
+ node->locy= locy + 60.0f; // arbitrary.. so its visible
+ node->flag |= SELECT;
+
+ gnode= snode_get_editgroup(snode);
+ if(gnode) {
+ node->locx -= gnode->locx;
+ node->locy -= gnode->locy;
+ }
+
+ snode_verify_groups(snode);
+ node_set_active(snode, node);
+
+ if(node->id)
+ id_us_plus(node->id);
+
+ if(snode->nodetree->type==NTREE_COMPOSIT)
+ ntreeCompositForceHidden(snode->edittree);
+
+ NodeTagChanged(snode->edittree, node);
+ }
+ return node;
+}
+
+void node_adduplicate(SpaceNode *snode)
+{
+
+ ntreeCopyTree(snode->edittree, 1); /* 1 == internally selected nodes */
+
+ ntreeSolveOrder(snode->edittree);
+ snode_verify_groups(snode);
+ snode_handle_recalc(snode);
+
+ transform_nodes(snode->edittree, 'g', "Duplicate");
+}
+
+#if 0
+static void node_insert_convertor(SpaceNode *snode, bNodeLink *link)
+{
+ bNode *newnode= NULL;
+
+ if(link->fromsock->type==SOCK_RGBA && link->tosock->type==SOCK_VALUE) {
+ if(snode->edittree->type==NTREE_SHADER)
+ newnode= node_add_node(snode, SH_NODE_RGBTOBW, 0.0f, 0.0f);
+ else if(snode->edittree->type==NTREE_COMPOSIT)
+ newnode= node_add_node(snode, CMP_NODE_RGBTOBW, 0.0f, 0.0f);
+ else
+ newnode= NULL;
+ }
+ else if(link->fromsock->type==SOCK_VALUE && link->tosock->type==SOCK_RGBA) {
+ if(snode->edittree->type==NTREE_SHADER)
+ newnode= node_add_node(snode, SH_NODE_VALTORGB, 0.0f, 0.0f);
+ else if(snode->edittree->type==NTREE_COMPOSIT)
+ newnode= node_add_node(snode, CMP_NODE_VALTORGB, 0.0f, 0.0f);
+ else
+ newnode= NULL;
+ }
+
+ if(newnode) {
+ /* dangerous assumption to use first in/out socks, but thats fine for now */
+ newnode->flag |= NODE_HIDDEN;
+ newnode->locx= 0.5f*(link->fromsock->locx + link->tosock->locx);
+ newnode->locy= 0.5f*(link->fromsock->locy + link->tosock->locy) + HIDDEN_RAD;
+
+ nodeAddLink(snode->edittree, newnode, newnode->outputs.first, link->tonode, link->tosock);
+ link->tonode= newnode;
+ link->tosock= newnode->inputs.first;
+ }
+}
+
+#endif
+
+/* loop that adds a nodelink, called by function below */
+/* in_out = starting socket */
+static int node_add_link_drag(SpaceNode *snode, bNode *node, bNodeSocket *sock, int in_out)
+{
+ bNode *tnode;
+ bNodeSocket *tsock= NULL;
+ bNodeLink *link= NULL;
+ short mval[2], mvalo[2], firsttime=1; /* firsttime reconnects a link broken by caller */
+
+ /* we make a temporal link */
+ if(in_out==SOCK_OUT)
+ link= nodeAddLink(snode->edittree, node, sock, NULL, NULL);
+ else
+ link= nodeAddLink(snode->edittree, NULL, NULL, node, sock);
+
+ getmouseco_areawin(mvalo);
+ while (get_mbut() & L_MOUSE) {
+
+ getmouseco_areawin(mval);
+ if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || firsttime) {
+ firsttime= 0;
+
+ mvalo[0]= mval[0];
+ mvalo[1]= mval[1];
+
+ if(in_out==SOCK_OUT) {
+ if(find_indicated_socket(snode, &tnode, &tsock, SOCK_IN)) {
+ if(nodeFindLink(snode->edittree, sock, tsock)==NULL) {
+ if(tnode!=node && link->tonode!=tnode && link->tosock!= tsock) {
+ link->tonode= tnode;
+ link->tosock= tsock;
+ ntreeSolveOrder(snode->edittree); /* for interactive red line warning */
+ }
+ }
+ }
+ else {
+ link->tonode= NULL;
+ link->tosock= NULL;
+ }
+ }
+ else {
+ if(find_indicated_socket(snode, &tnode, &tsock, SOCK_OUT)) {
+ if(nodeFindLink(snode->edittree, sock, tsock)==NULL) {
+ if(nodeCountSocketLinks(snode->edittree, tsock) < tsock->limit) {
+ if(tnode!=node && link->fromnode!=tnode && link->fromsock!= tsock) {
+ link->fromnode= tnode;
+ link->fromsock= tsock;
+ ntreeSolveOrder(snode->edittree); /* for interactive red line warning */
+ }
+ }
+ }
+ }
+ else {
+ link->fromnode= NULL;
+ link->fromsock= NULL;
+ }
+ }
+ /* hilight target sockets only */
+ node_socket_hilights(snode, in_out==SOCK_OUT?SOCK_IN:SOCK_OUT);
+
+ force_draw(0);
+ }
+ else BIF_wait_for_statechange();
+ }
+
+ /* remove link? */
+ if(link->tonode==NULL || link->fromnode==NULL) {
+ nodeRemLink(snode->edittree, link);
+ }
+ else {
+ bNodeLink *tlink;
+
+ /* send changed events for original tonode and new */
+ if(link->tonode)
+ NodeTagChanged(snode->edittree, link->tonode);
+
+ /* we might need to remove a link */
+ if(in_out==SOCK_OUT) {
+ if(tsock && nodeCountSocketLinks(snode->edittree, link->tosock) > tsock->limit) {
+
+ for(tlink= snode->edittree->links.first; tlink; tlink= tlink->next) {
+ if(link!=tlink && tlink->tosock==link->tosock)
+ break;
+ }
+ if(tlink) {
+ /* is there a free input socket with same type? */
+ for(tsock= tlink->tonode->inputs.first; tsock; tsock= tsock->next) {
+ if(tsock->type==tlink->fromsock->type)
+ if(nodeCountSocketLinks(snode->edittree, tsock) < tsock->limit)
+ break;
+ }
+ if(tsock)
+ tlink->tosock= tsock;
+ else {
+ nodeRemLink(snode->edittree, tlink);
+ }
+ }
+ }
+ }
+ }
+
+ ntreeSolveOrder(snode->edittree);
+ snode_verify_groups(snode);
+ snode_handle_recalc(snode);
+
+ allqueue(REDRAWNODE, 0);
+ BIF_undo_push("Add link");
+
+ return 1;
+}
+
+/* return 1 when socket clicked */
+static int node_add_link(SpaceNode *snode)
+{
+ bNode *node;
+ bNodeLink *link;
+ bNodeSocket *sock;
+
+ /* output indicated? */
+ if(find_indicated_socket(snode, &node, &sock, SOCK_OUT)) {
+ if(nodeCountSocketLinks(snode->edittree, sock)<sock->limit)
+ return node_add_link_drag(snode, node, sock, SOCK_OUT);
+ else {
+ /* find if we break a link */
+ for(link= snode->edittree->links.first; link; link= link->next) {
+ if(link->fromsock==sock)
+ break;
+ }
+ if(link) {
+ node= link->tonode;
+ sock= link->tosock;
+ nodeRemLink(snode->edittree, link);
+ return node_add_link_drag(snode, node, sock, SOCK_IN);
+ }
+ }
+ }
+ /* or an input? */
+ else if(find_indicated_socket(snode, &node, &sock, SOCK_IN)) {
+ if(nodeCountSocketLinks(snode->edittree, sock)<sock->limit)
+ return node_add_link_drag(snode, node, sock, SOCK_IN);
+ else {
+ /* find if we break a link */
+ for(link= snode->edittree->links.first; link; link= link->next) {
+ if(link->tosock==sock)
+ break;
+ }
+ if(link) {
+ /* send changed event to original tonode */
+ if(link->tonode)
+ NodeTagChanged(snode->edittree, link->tonode);
+
+ node= link->fromnode;
+ sock= link->fromsock;
+ nodeRemLink(snode->edittree, link);
+ return node_add_link_drag(snode, node, sock, SOCK_OUT);
+ }
+ }
+ }
+
+ return 0;
+}
+
+void node_delete(SpaceNode *snode)
+{
+ bNode *node, *next;
+
+ for(node= snode->edittree->nodes.first; node; node= next) {
+ next= node->next;
+ if(node->flag & SELECT) {
+ /* check id user here, nodeFreeNode is called for free dbase too */
+ if(node->id)
+ node->id->us--;
+ nodeFreeNode(snode->edittree, node);
+ }
+ }
+
+ snode_verify_groups(snode);
+ snode_handle_recalc(snode);
+ BIF_undo_push("Delete nodes");
+ allqueue(REDRAWNODE, 1);
+}
+
+void node_hide(SpaceNode *snode)
+{
+ bNode *node;
+ int nothidden=0, ishidden=0;
+
+ for(node= snode->edittree->nodes.first; node; node= node->next) {
+ if(node->flag & SELECT) {
+ if(node->flag & NODE_HIDDEN)
+ ishidden++;
+ else
+ nothidden++;
+ }
+ }
+ for(node= snode->edittree->nodes.first; node; node= node->next) {
+ if(node->flag & SELECT) {
+ if( (ishidden && nothidden) || ishidden==0)
+ node->flag |= NODE_HIDDEN;
+ else
+ node->flag &= ~NODE_HIDDEN;
+ }
+ }
+ BIF_undo_push("Hide nodes");
+ allqueue(REDRAWNODE, 1);
+}
+
+void node_insert_key(SpaceNode *snode)
+{
+ bNode *node= editnode_get_active(snode->edittree);
+
+ if(node->type==CMP_NODE_TIME) {
+ if(node->custom1<node->custom2) {
+
+ CurveMapping *cumap= node->storage;
+ float fval, curval;
+
+ curval= (float)(CFRA - node->custom1)/(float)(node->custom2-node->custom1);
+ fval= curvemapping_evaluateF(cumap, 0, curval);
+
+ if(fbutton(&fval, 0.0f, 1.0f, 10, 10, "Insert Value")) {
+ curvemap_insert(cumap->cm, curval, fval);
+
+ BIF_undo_push("Insert key in Time node");
+ allqueue(REDRAWNODE, 1);
+ }
+ }
+ }
+}
+
+void node_select_linked(SpaceNode *snode, int out)
+{
+ bNodeLink *link;
+ bNode *node;
+
+ /* NODE_TEST is the free flag */
+ for(node= snode->edittree->nodes.first; node; node= node->next)
+ node->flag &= ~NODE_TEST;
+
+ for(link= snode->edittree->links.first; link; link= link->next) {
+ if(out) {
+ if(link->fromnode->flag & NODE_SELECT)
+ link->tonode->flag |= NODE_TEST;
+ }
+ else {
+ if(link->tonode->flag & NODE_SELECT)
+ link->fromnode->flag |= NODE_TEST;
+ }
+ }
+
+ for(node= snode->edittree->nodes.first; node; node= node->next)
+ if(node->flag & NODE_TEST)
+ node->flag |= NODE_SELECT;
+
+ BIF_undo_push("Select Linked nodes");
+ allqueue(REDRAWNODE, 1);
+}
+
+static void node_border_link_delete(SpaceNode *snode)
+{
+ rcti rect;
+ short val, mval[2], mvalo[2];
+
+ /* to make this work more friendly, we first wait for a mouse move */
+ getmouseco_areawin(mvalo);
+ while (get_mbut() & L_MOUSE) {
+ getmouseco_areawin(mval);
+ if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1])
+ break;
+ else BIF_wait_for_statechange();
+ }
+ if((get_mbut() & L_MOUSE)==0)
+ return;
+
+ /* now change cursor and draw border */
+ setcursor_space(SPACE_NODE, CURSOR_VPAINT);
+
+ if ( (val = get_border(&rect, 2)) ) {
+ if(rect.xmin<rect.xmax && rect.ymin<rect.ymax) {
+ //#define NODE_MAXPICKBUF 256
+ bNodeLink *link, *next;
+ GLuint buffer[256];
+ rctf rectf;
+ int code=0, hits;
+
+ mval[0]= rect.xmin;
+ mval[1]= rect.ymin;
+ areamouseco_to_ipoco(&snode->v2d, mval, &rectf.xmin, &rectf.ymin);
+ mval[0]= rect.xmax;
+ mval[1]= rect.ymax;
+ areamouseco_to_ipoco(&snode->v2d, mval, &rectf.xmax, &rectf.ymax);
+
+ myortho2(rectf.xmin, rectf.xmax, rectf.ymin, rectf.ymax);
+
+ glSelectBuffer(256, buffer);
+ glRenderMode(GL_SELECT);
+ glInitNames();
+ glPushName(-1);
+
+ /* draw links */
+ for(link= snode->edittree->links.first; link; link= link->next) {
+ glLoadName(code++);
+ node_draw_link(snode, link);
+ }
+
+ hits= glRenderMode(GL_RENDER);
+ glPopName();
+ if(hits>0) {
+ int a;
+ for(a=0; a<hits; a++) {
+ bNodeLink *link= BLI_findlink(&snode->edittree->links, buffer[ (4 * a) + 3]);
+ if(link)
+ link->fromnode= NULL; /* first tag for delete, otherwise indices are wrong */
+ }
+ for(link= snode->edittree->links.first; link; link= next) {
+ next= link->next;
+ if(link->fromnode==NULL) {
+ NodeTagChanged(snode->edittree, link->tonode);
+ nodeRemLink(snode->edittree, link);
+ }
+ }
+ ntreeSolveOrder(snode->edittree);
+ snode_verify_groups(snode);
+ snode_handle_recalc(snode);
+ }
+ allqueue(REDRAWNODE, 0);
+ BIF_undo_push("Erase links");
+ }
+ }
+
+ setcursor_space(SPACE_NODE, CURSOR_STD);
+}
+
+/* goes over all scenes, reads render layerss */
+void node_read_renderlayers(SpaceNode *snode)
+{
+ Scene *scene;
+ bNode *node;
+
+ /* first tag scenes unread */
+ for(scene= G.main->scene.first; scene; scene= scene->id.next)
+ scene->id.flag |= LIB_DOIT;
+
+ for(node= snode->edittree->nodes.first; node; node= node->next) {
+ if(node->type==CMP_NODE_R_LAYERS) {
+ ID *id= node->id;
+ if(id==NULL) id= (ID *)G.scene;
+ if(id->flag & LIB_DOIT) {
+ RE_ReadRenderResult(G.scene, (Scene *)id);
+ ntreeCompositTagRender((Scene *)id);
+ id->flag &= ~LIB_DOIT;
+ }
+ }
+ }
+
+ snode_handle_recalc(snode);
+}
+
+/* called from header_info, when deleting a scene
+ * goes over all scenes other than the input, checks if they have
+ * render layer nodes referencing the to-be-deleted scene, and
+ * resets them to NULL. */
+void clear_scene_in_nodes(Scene *sce)
+{
+ Scene *sce1;
+ bNode *node;
+
+ sce1= G.main->scene.first;
+ while(sce1) {
+ if(sce1!=sce) {
+ if (sce1->nodetree) {
+ for(node= sce1->nodetree->nodes.first; node; node= node->next) {
+ if(node->type==CMP_NODE_R_LAYERS) {
+ Scene *nodesce= (Scene *)node->id;
+
+ if (nodesce==sce) node->id = NULL;
+ }
+ }
+ }
+ }
+ sce1= sce1->id.next;
+ }
+}
+
+
+/* gets active viewer user */
+struct ImageUser *ntree_get_active_iuser(bNodeTree *ntree)
+{
+ bNode *node;
+
+ if(ntree)
+ for(node= ntree->nodes.first; node; node= node->next)
+ if( ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER))
+ if(node->flag & NODE_DO_OUTPUT)
+ return node->storage;
+ return NULL;
+}
+
+void imagepaint_composite_tags(bNodeTree *ntree, Image *image, ImageUser *iuser)
+{
+ bNode *node;
+
+ if(ntree==NULL)
+ return;
+
+ /* search for renderresults */
+ if(image->type==IMA_TYPE_R_RESULT) {
+ for(node= ntree->nodes.first; node; node= node->next) {
+ if(node->type==CMP_NODE_R_LAYERS && node->id==NULL) {
+ /* imageuser comes from ImageWin, so indexes are offset 1 */
+ if(node->custom1==iuser->layer-1)
+ NodeTagChanged(ntree, node);
+ }
+ }
+ }
+ else {
+ for(node= ntree->nodes.first; node; node= node->next) {
+ if(node->id== &image->id)
+ NodeTagChanged(ntree, node);
+ }
+ }
+}
+
+/* ********************** */
+
+void node_make_group(SpaceNode *snode)
+{
+ bNode *gnode;
+
+ if(snode->edittree!=snode->nodetree) {
+ error("Can not add a new Group in a Group");
+ return;
+ }
+
+ /* for time being... is too complex to handle */
+ if(snode->treetype==NTREE_COMPOSIT) {
+ for(gnode=snode->nodetree->nodes.first; gnode; gnode= gnode->next) {
+ if(gnode->flag & SELECT)
+ if(gnode->type==CMP_NODE_R_LAYERS)
+ break;
+ }
+ if(gnode) {
+ error("Can not add RenderLayer in a Group");
+ return;
+ }
+ }
+
+ gnode= nodeMakeGroupFromSelected(snode->nodetree);
+ if(gnode==NULL) {
+ error("Can not make Group");
+ }
+ else {
+ nodeSetActive(snode->nodetree, gnode);
+ ntreeSolveOrder(snode->nodetree);
+ allqueue(REDRAWNODE, 0);
+ BIF_undo_push("Make Node Group");
+ }
+}
+
+/* ******************** main event loop ****************** */
+
+/* special version to prevent overlapping buttons, has a bit of hack... */
+/* yes, check for example composit_node_event(), file window use... */
+static int node_uiDoBlocks(ScrArea *sa, short event)
+{
+ SpaceNode *snode= sa->spacedata.first;
+ ListBase *lb= &sa->uiblocks;
+ ListBase listb= *lb;
+ bNode *node;
+ rctf rect;
+ void *prev, *next;
+ int retval= UI_NOTHING;
+ short mval[2];
+
+ getmouseco_areawin(mval);
+ areamouseco_to_ipoco(G.v2d, mval, &rect.xmin, &rect.ymin);
+
+ /* this happens after filesel usage... */
+ if(lb->first==NULL) {
+ return UI_NOTHING;
+ }
+
+ rect.xmin -= 2.0f;
+ rect.ymin -= 2.0f;
+ rect.xmax = rect.xmin + 4.0f;
+ rect.ymax = rect.ymin + 4.0f;
+
+ for(node= snode->edittree->nodes.first; node; node= node->next) {
+ uiBlock *block;
+ char str[32];
+
+ /* retreive unique block name, see also drawnode.c */
+ sprintf(str, "node buttons %p", node);
+ block= uiGetBlock(str, sa);
+
+ if(block) {
+ if(node == visible_node(snode, &rect)) {
+
+ /* when there's menus, the prev pointer becomes zero! */
+ prev= ((struct Link *)block)->prev;
+ next= ((struct Link *)block)->next;
+ ((struct Link *)block)->prev= NULL;
+ ((struct Link *)block)->next= NULL;
+
+ lb->first= lb->last= block;
+ retval= uiDoBlocks(lb, event);
+
+ ((struct Link *)block)->prev= prev;
+ ((struct Link *)block)->next= next;
+
+ break;
+ }
+ }
+ }
+
+ *lb= listb;
+
+ return retval;
+}
+
+void winqreadnodespace(ScrArea *sa, void *spacedata, BWinEvent *evt)
+{
+ SpaceNode *snode= spacedata;
+ unsigned short event= evt->event;
+ short val= evt->val, doredraw=0, fromlib= 0;
+
+ if(sa->win==0) return;
+ if(snode->nodetree==NULL) return;
+
+ if(val) {
+
+ if( node_uiDoBlocks(sa, event)!=UI_NOTHING ) event= 0;
+
+ fromlib= (snode->id && snode->id->lib);
+
+ switch(event) {
+ case LEFTMOUSE:
+ if(fromlib) {
+ if(node_mouse_groupheader(snode)==0)
+ node_mouse_select(snode, event);
+ }
+ else {
+ if(node_add_link(snode)==0)
+ if(node_mouse_groupheader(snode)==0)
+ if(node_mouse_select(snode, event)==0)
+ node_border_link_delete(snode);
+ }
+ break;
+
+ case RIGHTMOUSE:
+ if(!node_mouse_select(snode, event))
+ toolbox_n();
+
+ break;
+ case MIDDLEMOUSE:
+ if (G.qual==LR_SHIFTKEY) {
+ snode_bg_viewmove(snode);
+ } else {
+ view2dmove(event);
+ }
+ case WHEELUPMOUSE:
+ case WHEELDOWNMOUSE:
+ view2dmove(event); /* in drawipo.c */
+ break;
+
+ case MOUSEY:
+ doredraw= node_socket_hilights(snode, SOCK_IN|SOCK_OUT);
+ break;
+
+ case UI_BUT_EVENT:
+ /* future: handlerize this! */
+ if(snode->treetype==NTREE_SHADER)
+ shader_node_event(snode, val);
+ else if(snode->treetype==NTREE_COMPOSIT)
+ composit_node_event(snode, val);
+ break;
+
+ case RENDERPREVIEW:
+ if(snode->treetype==NTREE_SHADER)
+ shader_node_previewrender(sa, snode);
+ break;
+
+ case PADPLUSKEY:
+ snode_zoom_in(sa);
+ doredraw= 1;
+ break;
+ case PADMINUS:
+ snode_zoom_out(sa);
+ doredraw= 1;
+ break;
+ case HOMEKEY:
+ snode_home(sa, snode);
+ doredraw= 1;
+ break;
+ case TABKEY:
+ if(fromlib) fromlib= -1;
+ else snode_make_group_editable(snode, NULL);
+ break;
+
+ case AKEY:
+ if(G.qual==LR_SHIFTKEY) {
+ if(fromlib) fromlib= -1;
+ else toolbox_n_add();
+ }
+ else if(G.qual==0) {
+ node_deselectall(snode, 1);
+ BIF_undo_push("Deselect all nodes");
+ }
+ break;
+ case BKEY:
+ if(G.qual==0)
+ node_border_select(snode);
+ break;
+ case CKEY: /* sort again, showing cyclics */
+ ntreeSolveOrder(snode->edittree);
+ doredraw= 1;
+ break;
+ case DKEY:
+ if(G.qual==LR_SHIFTKEY) {
+ if(fromlib) fromlib= -1;
+ else node_adduplicate(snode);
+ }
+ break;
+ case EKEY:
+ snode_handle_recalc(snode);
+ break;
+ case GKEY:
+ if(fromlib) fromlib= -1;
+ else {
+ if(G.qual==LR_CTRLKEY) {
+ if(okee("Make Group"))
+ node_make_group(snode);
+ }
+ else if(G.qual==LR_ALTKEY) {
+ if(okee("Ungroup"))
+ node_ungroup(snode);
+ }
+ else if(G.qual==LR_SHIFTKEY) {
+ node_addgroup(snode);
+ }
+ else
+ transform_nodes(snode->edittree, 'g', "Move Node");
+ }
+ break;
+ case HKEY:
+ node_hide(snode);
+ break;
+ case IKEY:
+ node_insert_key(snode);
+ break;
+ case LKEY:
+ node_select_linked(snode, G.qual==LR_SHIFTKEY);
+ break;
+ case RKEY:
+ if(okee("Read saved Render Layers"))
+ node_read_renderlayers(snode);
+ break;
+ case DELKEY:
+ case XKEY:
+ if(fromlib) fromlib= -1;
+ else node_delete(snode);
+ break;
+ }
+ }
+
+ if(fromlib==-1)
+ error_libdata();
+ if(doredraw)
+ scrarea_queue_winredraw(sa);
+ if(doredraw==2)
+ scrarea_queue_headredraw(sa);
+}
+
+
diff --git a/source/blender/src/editobject.c b/source/blender/src/editobject.c
new file mode 100644
index 00000000000..997593b30b1
--- /dev/null
+++ b/source/blender/src/editobject.c
@@ -0,0 +1,5554 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/**
+ * Theorie: (matrices) A x B x C == A x ( B x C x Binv) x B
+ * ofwel: OB x PAR x EDIT = OB x (PAR x EDIT x PARinv) x PAR
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef WIN32
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+#include "MEM_guardedalloc.h"
+#include "PIL_time.h"
+
+#include "BMF_Api.h"
+
+
+#include "IMB_imbuf_types.h"
+
+#include "DNA_action_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_effect_types.h"
+#include "DNA_group_types.h"
+#include "DNA_image_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_key_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_nla_types.h"
+#include "DNA_object_types.h"
+#include "DNA_object_fluidsim.h"
+#include "DNA_object_force.h"
+#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_property_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_vfont_types.h"
+#include "DNA_world_types.h"
+#include "DNA_modifier_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_editVert.h"
+#include "BLI_ghash.h"
+
+#include "BKE_action.h"
+#include "BKE_anim.h"
+#include "BKE_armature.h"
+#include "BKE_constraint.h"
+#include "BKE_customdata.h"
+#include "BKE_blender.h"
+#include "BKE_booleanops.h"
+#include "BKE_curve.h"
+#include "BKE_displist.h"
+#include "BKE_depsgraph.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_effect.h"
+#include "BKE_font.h"
+#include "BKE_global.h"
+#include "BKE_group.h"
+#include "BKE_ipo.h"
+#include "BKE_image.h"
+#include "BKE_key.h"
+#include "BKE_lattice.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_mball.h"
+#include "BKE_mesh.h"
+#include "BKE_nla.h"
+#include "BKE_object.h"
+#include "BKE_property.h"
+#include "BKE_sca.h"
+#include "BKE_scene.h"
+#include "BKE_softbody.h"
+#include "BKE_subsurf.h"
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
+#include "BKE_modifier.h"
+
+#include "BIF_butspace.h"
+#include "BIF_editconstraint.h"
+#include "BIF_editdeform.h"
+#include "BIF_editfont.h"
+#include "BIF_editlattice.h"
+#include "BIF_editmesh.h"
+#include "BIF_editoops.h"
+#include "BIF_editview.h"
+#include "BIF_editarmature.h"
+#include "BIF_gl.h"
+#include "BIF_graphics.h"
+#include "BIF_interface.h"
+#include "BIF_meshtools.h"
+#include "BIF_mywindow.h"
+#include "BIF_resources.h"
+#include "BIF_retopo.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_toolbox.h"
+#include "BIF_toets.h"
+
+#ifdef WITH_VERSE
+#include "BIF_verse.h"
+#endif
+
+#include "BSE_edit.h"
+#include "BSE_editipo.h"
+#include "BSE_filesel.h" /* For activate_databrowse() */
+#include "BSE_view.h"
+#include "BSE_drawview.h"
+#include "BSE_trans_types.h"
+#include "BSE_editipo_types.h"
+
+#include "BDR_vpaint.h"
+#include "BDR_sculptmode.h"
+#include "BDR_editface.h"
+#include "BDR_editmball.h"
+#include "BDR_editobject.h"
+#include "BDR_drawobject.h"
+#include "BDR_editcurve.h"
+#include "BDR_unwrapper.h"
+
+#include <time.h>
+#include "mydevice.h"
+#include "nla.h"
+
+#include "blendef.h"
+#include "butspace.h"
+#include "multires.h"
+#include "BIF_transform.h"
+
+#include "BIF_poseobject.h"
+
+
+/* --------------------------------- */
+
+void add_object_draw(int type) /* for toolbox or menus, only non-editmode stuff */
+{
+ Object *ob;
+
+ G.f &= ~(G_VERTEXPAINT+G_TEXTUREPAINT+G_WEIGHTPAINT+G_SCULPTMODE);
+ setcursor_space(SPACE_VIEW3D, CURSOR_STD);
+
+ if ELEM3(curarea->spacetype, SPACE_VIEW3D, SPACE_BUTS, SPACE_INFO) {
+ if (G.obedit) exit_editmode(EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR); /* freedata, and undo */
+ ob= add_object(type);
+ set_active_base(BASACT);
+ base_init_from_view3d(BASACT, G.vd);
+
+ /* only undo pushes on objects without editmode... */
+ if(type==OB_EMPTY) BIF_undo_push("Add Empty");
+ else if(type==OB_LAMP) {
+ BIF_undo_push("Add Lamp");
+ reshadeall_displist(); /* only frees */
+ }
+ else if(type==OB_LATTICE) BIF_undo_push("Add Lattice");
+ else if(type==OB_CAMERA) BIF_undo_push("Add Camera");
+
+ allqueue(REDRAWVIEW3D, 0);
+ }
+
+ redraw_test_buttons(OBACT);
+
+ allqueue(REDRAWALL, 0);
+
+ deselect_all_area_oops();
+ set_select_flag_oops();
+
+ DAG_scene_sort(G.scene);
+ allqueue(REDRAWINFO, 1); /* 1, because header->win==0! */
+}
+
+void add_objectLamp(short type)
+{
+ Lamp *la;
+
+ /* this function also comes from an info window */
+ if ELEM(curarea->spacetype, SPACE_VIEW3D, SPACE_INFO); else return;
+
+ if(G.obedit==0) {
+ add_object_draw(OB_LAMP);
+ base_init_from_view3d(BASACT, G.vd);
+ }
+
+ la = BASACT->object->data;
+ la->type = type;
+
+ allqueue(REDRAWALL, 0);
+}
+
+/* remove base from a specific scene */
+/* note: now unlinks constraints as well */
+void free_and_unlink_base_from_scene(Scene *scene, Base *base)
+{
+ BLI_remlink(&scene->base, base);
+ free_libblock_us(&G.main->object, base->object);
+ MEM_freeN(base);
+}
+
+/* remove base from the current scene */
+void free_and_unlink_base(Base *base)
+{
+ if (base==BASACT)
+ BASACT= NULL;
+ free_and_unlink_base_from_scene(G.scene, base);
+}
+
+void delete_obj(int ok)
+{
+ Base *base;
+ int islamp= 0;
+
+ if(G.obedit) return;
+ if(G.scene->id.lib) return;
+
+ if(G.f & G_SCULPTMODE) set_sculptmode();
+
+ base= FIRSTBASE;
+ while(base) {
+ Base *nbase= base->next;
+
+ if TESTBASE(base) {
+ if(ok==0) {
+ /* Shift Del is global delete */
+ if (G.qual & LR_SHIFTKEY) {
+ if(!okee("Erase selected Object(s) Globally")) return;
+ ok= 2;
+ } else {
+ if(!okee("Erase selected Object(s)")) return;
+ ok= 1;
+ }
+ }
+
+ if(base->object->type==OB_LAMP) islamp= 1;
+#ifdef WITH_VERSE
+ if(base->object->vnode) b_verse_delete_object(base->object);
+#endif
+ if (ok==2) {
+ Scene *scene;
+ Base *base_other;
+
+ for (scene= G.main->scene.first; scene; scene= scene->id.next) {
+ if (scene != G.scene && !(scene->id.lib)) {
+ base_other= object_in_scene( base->object, scene );
+ if (base_other) {
+ if (base_other == scene->basact) scene->basact= NULL; /* in case the object was active */
+ free_and_unlink_base_from_scene( scene, base_other );
+ }
+ }
+ }
+ }
+
+ /* remove from current scene only */
+ free_and_unlink_base(base);
+ }
+
+ base= nbase;
+ }
+ countall();
+
+ G.f &= ~(G_VERTEXPAINT+G_TEXTUREPAINT+G_WEIGHTPAINT);
+ setcursor_space(SPACE_VIEW3D, CURSOR_STD);
+
+ if(islamp) reshadeall_displist(); /* only frees displist */
+
+ redraw_test_buttons(OBACT);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue (REDRAWACTION, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWDATASELECT, 0);
+ allspace(OOPS_TEST, 0);
+ allqueue(REDRAWOOPS, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWNLA, 0);
+
+ DAG_scene_sort(G.scene);
+
+ BIF_undo_push("Delete object(s)");
+}
+
+static int return_editmesh_indexar(int *tot, int **indexar, float *cent)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+ int *index, nr, totvert=0;
+
+ for(eve= em->verts.first; eve; eve= eve->next) {
+ if(eve->f & SELECT) totvert++;
+ }
+ if(totvert==0) return 0;
+
+ *indexar= index= MEM_mallocN(4*totvert, "hook indexar");
+ *tot= totvert;
+ nr= 0;
+ cent[0]= cent[1]= cent[2]= 0.0;
+
+ for(eve= em->verts.first; eve; eve= eve->next) {
+ if(eve->f & SELECT) {
+ *index= nr; index++;
+ VecAddf(cent, cent, eve->co);
+ }
+ nr++;
+ }
+
+ VecMulf(cent, 1.0f/(float)totvert);
+
+ return totvert;
+}
+
+static int return_editmesh_vgroup(char *name, float *cent)
+{
+ EditMesh *em = G.editMesh;
+ MDeformVert *dvert;
+ EditVert *eve;
+ int i, totvert=0;
+
+ cent[0]= cent[1]= cent[2]= 0.0;
+
+ if(G.obedit->actdef) {
+
+ /* find the vertices */
+ for(eve= em->verts.first; eve; eve= eve->next) {
+ dvert= CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT);
+
+ if(dvert) {
+ for(i=0; i<dvert->totweight; i++){
+ if(dvert->dw[i].def_nr == (G.obedit->actdef-1)) {
+ totvert++;
+ VecAddf(cent, cent, eve->co);
+ }
+ }
+ }
+ }
+ if(totvert) {
+ bDeformGroup *defGroup = BLI_findlink(&G.obedit->defbase, G.obedit->actdef-1);
+ strcpy(name, defGroup->name);
+ VecMulf(cent, 1.0f/(float)totvert);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static void select_editmesh_hook(HookModifierData *hmd)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+ int index=0, nr=0;
+
+ for(eve= em->verts.first; eve; eve= eve->next, nr++) {
+ if(nr==hmd->indexar[index]) {
+ eve->f |= SELECT;
+ if(index < hmd->totindex-1) index++;
+ }
+ }
+ EM_select_flush();
+}
+
+static int return_editlattice_indexar(int *tot, int **indexar, float *cent)
+{
+ BPoint *bp;
+ int *index, nr, totvert=0, a;
+
+ /* count */
+ a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
+ bp= editLatt->def;
+ while(a--) {
+ if(bp->f1 & SELECT) {
+ if(bp->hide==0) totvert++;
+ }
+ bp++;
+ }
+
+ if(totvert==0) return 0;
+
+ *indexar= index= MEM_mallocN(4*totvert, "hook indexar");
+ *tot= totvert;
+ nr= 0;
+ cent[0]= cent[1]= cent[2]= 0.0;
+
+ a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
+ bp= editLatt->def;
+ while(a--) {
+ if(bp->f1 & SELECT) {
+ if(bp->hide==0) {
+ *index= nr; index++;
+ VecAddf(cent, cent, bp->vec);
+ }
+ }
+ bp++;
+ nr++;
+ }
+
+ VecMulf(cent, 1.0f/(float)totvert);
+
+ return totvert;
+}
+
+static void select_editlattice_hook(HookModifierData *hmd)
+{
+ BPoint *bp;
+ int index=0, nr=0, a;
+
+ /* count */
+ a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
+ bp= editLatt->def;
+ while(a--) {
+ if(hmd->indexar[index]==nr) {
+ bp->f1 |= SELECT;
+ if(index < hmd->totindex-1) index++;
+ }
+ nr++;
+ bp++;
+ }
+}
+
+static int return_editcurve_indexar(int *tot, int **indexar, float *cent)
+{
+ extern ListBase editNurb;
+ Nurb *nu;
+ BPoint *bp;
+ BezTriple *bezt;
+ int *index, a, nr, totvert=0;
+
+ for(nu= editNurb.first; nu; nu= nu->next) {
+ if((nu->type & 7)==CU_BEZIER) {
+ bezt= nu->bezt;
+ a= nu->pntsu;
+ while(a--) {
+ if(bezt->f1 & SELECT) totvert++;
+ if(bezt->f2 & SELECT) totvert++;
+ if(bezt->f3 & SELECT) totvert++;
+ bezt++;
+ }
+ }
+ else {
+ bp= nu->bp;
+ a= nu->pntsu*nu->pntsv;
+ while(a--) {
+ if(bp->f1 & SELECT) totvert++;
+ bp++;
+ }
+ }
+ }
+ if(totvert==0) return 0;
+
+ *indexar= index= MEM_mallocN(4*totvert, "hook indexar");
+ *tot= totvert;
+ nr= 0;
+ cent[0]= cent[1]= cent[2]= 0.0;
+
+ for(nu= editNurb.first; nu; nu= nu->next) {
+ if((nu->type & 7)==CU_BEZIER) {
+ bezt= nu->bezt;
+ a= nu->pntsu;
+ while(a--) {
+ if(bezt->f1 & SELECT) {
+ *index= nr; index++;
+ VecAddf(cent, cent, bezt->vec[0]);
+ }
+ nr++;
+ if(bezt->f2 & SELECT) {
+ *index= nr; index++;
+ VecAddf(cent, cent, bezt->vec[1]);
+ }
+ nr++;
+ if(bezt->f3 & SELECT) {
+ *index= nr; index++;
+ VecAddf(cent, cent, bezt->vec[2]);
+ }
+ nr++;
+ bezt++;
+ }
+ }
+ else {
+ bp= nu->bp;
+ a= nu->pntsu*nu->pntsv;
+ while(a--) {
+ if(bp->f1 & SELECT) {
+ *index= nr; index++;
+ VecAddf(cent, cent, bp->vec);
+ }
+ nr++;
+ bp++;
+ }
+ }
+ }
+
+ VecMulf(cent, 1.0f/(float)totvert);
+
+ return totvert;
+}
+
+static void select_editcurve_hook(HookModifierData *hmd)
+{
+ extern ListBase editNurb;
+ Nurb *nu;
+ BPoint *bp;
+ BezTriple *bezt;
+ int index=0, a, nr=0;
+
+ for(nu= editNurb.first; nu; nu= nu->next) {
+ if((nu->type & 7)==CU_BEZIER) {
+ bezt= nu->bezt;
+ a= nu->pntsu;
+ while(a--) {
+ if(nr == hmd->indexar[index]) {
+ bezt->f1 |= SELECT;
+ if(index<hmd->totindex-1) index++;
+ }
+ nr++;
+ if(nr == hmd->indexar[index]) {
+ bezt->f2 |= SELECT;
+ if(index<hmd->totindex-1) index++;
+ }
+ nr++;
+ if(nr == hmd->indexar[index]) {
+ bezt->f3 |= SELECT;
+ if(index<hmd->totindex-1) index++;
+ }
+ nr++;
+
+ bezt++;
+ }
+ }
+ else {
+ bp= nu->bp;
+ a= nu->pntsu*nu->pntsv;
+ while(a--) {
+ if(nr == hmd->indexar[index]) {
+ bp->f1 |= SELECT;
+ if(index<hmd->totindex-1) index++;
+ }
+ nr++;
+ bp++;
+ }
+ }
+ }
+}
+
+void hook_select(HookModifierData *hmd)
+{
+ if(G.obedit->type==OB_MESH) select_editmesh_hook(hmd);
+ else if(G.obedit->type==OB_LATTICE) select_editlattice_hook(hmd);
+ else if(G.obedit->type==OB_CURVE) select_editcurve_hook(hmd);
+ else if(G.obedit->type==OB_SURF) select_editcurve_hook(hmd);
+}
+
+int hook_getIndexArray(int *tot, int **indexar, char *name, float *cent_r)
+{
+ *indexar= NULL;
+ *tot= 0;
+ name[0]= 0;
+
+ switch(G.obedit->type) {
+ case OB_MESH:
+ /* check selected vertices first */
+ if( return_editmesh_indexar(tot, indexar, cent_r)) return 1;
+ else return return_editmesh_vgroup(name, cent_r);
+ case OB_CURVE:
+ case OB_SURF:
+ return return_editcurve_indexar(tot, indexar, cent_r);
+ case OB_LATTICE:
+ return return_editlattice_indexar(tot, indexar, cent_r);
+ default:
+ return 0;
+ }
+}
+
+void add_hook(void)
+{
+ ModifierData *md = NULL;
+ HookModifierData *hmd = NULL;
+ Object *ob=NULL;
+ int mode;
+
+ if(G.obedit==NULL) return;
+
+ if(modifiers_findByType(G.obedit, eModifierType_Hook))
+ mode= pupmenu("Hooks %t|Add, To New Empty %x1|Add, To Selected Object %x2|Remove... %x3|Reassign... %x4|Select... %x5|Clear Offset...%x6");
+ else
+ mode= pupmenu("Hooks %t|Add, New Empty %x1|Add, To Selected Object %x2");
+
+ if(mode<1) return;
+
+ /* preconditions */
+
+ if(mode==2) { /* selected object */
+ Base *base= FIRSTBASE;
+ while(base) {
+ if TESTBASELIB(base) {
+ if(base!=BASACT) {
+ ob= base->object;
+ break;
+ }
+ }
+ base= base->next;
+ }
+ if(ob==NULL) {
+ error("Requires selected Object");
+ return;
+ }
+ }
+ else if(mode!=1) {
+ int maxlen=0, a, nr;
+ char *cp;
+
+ /* make pupmenu with hooks */
+ for(md=G.obedit->modifiers.first; md; md= md->next) {
+ if (md->type==eModifierType_Hook)
+ maxlen+=32;
+ }
+
+ if(maxlen==0) {
+ error("Object has no hooks yet");
+ return;
+ }
+
+ cp= MEM_callocN(maxlen+32, "temp string");
+ if(mode==3) strcpy(cp, "Remove %t|");
+ else if(mode==4) strcpy(cp, "Reassign %t|");
+ else if(mode==5) strcpy(cp, "Select %t|");
+ else if(mode==6) strcpy(cp, "Clear Offset %t|");
+
+ for(md=G.obedit->modifiers.first; md; md= md->next) {
+ if (md->type==eModifierType_Hook) {
+ strcat(cp, md->name);
+ strcat(cp, " |");
+ }
+ }
+
+ nr= pupmenu(cp);
+ MEM_freeN(cp);
+
+ if(nr<1) return;
+
+ a= 1;
+ for(md=G.obedit->modifiers.first; md; md=md->next) {
+ if (md->type==eModifierType_Hook) {
+ if(a==nr) break;
+ a++;
+ }
+ }
+
+ hmd = (HookModifierData*) md;
+ ob= hmd->object;
+ }
+
+ /* do it, new hooks or reassign */
+ if(mode==1 || mode==2 || mode==4) {
+ float cent[3];
+ int tot, ok, *indexar;
+ char name[32];
+
+ ok = hook_getIndexArray(&tot, &indexar, name, cent);
+
+ if(ok==0) {
+ error("Requires selected vertices or active Vertex Group");
+ }
+ else {
+
+ if(mode==1) {
+ Base *base= BASACT, *newbase;
+
+ ob= add_object(OB_EMPTY);
+ /* set layers OK */
+ newbase= BASACT;
+ newbase->lay= base->lay;
+ ob->lay= newbase->lay;
+
+ /* transform cent to global coords for loc */
+ VecMat4MulVecfl(ob->loc, G.obedit->obmat, cent);
+
+ /* restore, add_object sets active */
+ BASACT= base;
+ }
+ /* if mode is 2 or 4, ob has been set */
+
+ /* new hook */
+ if(mode==1 || mode==2) {
+ ModifierData *md = G.obedit->modifiers.first;
+
+ while (md && modifierType_getInfo(md->type)->type==eModifierTypeType_OnlyDeform) {
+ md = md->next;
+ }
+
+ hmd = (HookModifierData*) modifier_new(eModifierType_Hook);
+ BLI_insertlinkbefore(&G.obedit->modifiers, md, hmd);
+ sprintf(hmd->modifier.name, "Hook-%s", ob->id.name+2);
+ }
+ else if (hmd->indexar) MEM_freeN(hmd->indexar); /* reassign, hook was set */
+
+ hmd->object= ob;
+ hmd->indexar= indexar;
+ VECCOPY(hmd->cent, cent);
+ hmd->totindex= tot;
+ BLI_strncpy(hmd->name, name, 32);
+
+ if(mode==1 || mode==2) {
+ /* matrix calculus */
+ /* vert x (obmat x hook->imat) x hook->obmat x ob->imat */
+ /* (parentinv ) */
+
+ where_is_object(ob);
+
+ Mat4Invert(ob->imat, ob->obmat);
+ /* apparently this call goes from right to left... */
+ Mat4MulSerie(hmd->parentinv, ob->imat, G.obedit->obmat, NULL,
+ NULL, NULL, NULL, NULL, NULL);
+ }
+ }
+ }
+ else if(mode==3) { /* remove */
+ BLI_remlink(&G.obedit->modifiers, md);
+ modifier_free(md);
+ }
+ else if(mode==5) { /* select */
+ hook_select(hmd);
+ }
+ else if(mode==6) { /* clear offset */
+ where_is_object(ob); /* ob is hook->parent */
+
+ Mat4Invert(ob->imat, ob->obmat);
+ /* this call goes from right to left... */
+ Mat4MulSerie(hmd->parentinv, ob->imat, G.obedit->obmat, NULL,
+ NULL, NULL, NULL, NULL, NULL);
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSOBJECT, 0);
+ DAG_scene_sort(G.scene);
+
+ BIF_undo_push("Add hook");
+}
+
+void make_track(void)
+{
+ Base *base;
+ short mode=0;
+
+ if(G.scene->id.lib) return;
+ if(G.obedit) {
+ return;
+ }
+ if(BASACT==0) return;
+
+ mode= pupmenu("Make Track %t|TrackTo Constraint %x1|LockTrack Constraint %x2|Old Track %x3");
+ if (mode == 0){
+ return;
+ }
+ else if (mode == 1){
+ bConstraint *con;
+ bTrackToConstraint *data;
+
+ base= FIRSTBASE;
+ while(base) {
+ if TESTBASELIB(base) {
+ if(base!=BASACT) {
+ con = add_new_constraint(CONSTRAINT_TYPE_TRACKTO);
+ strcpy (con->name, "AutoTrack");
+
+ data = con->data;
+ data->tar = BASACT->object;
+ base->object->recalc |= OB_RECALC;
+
+ /* Lamp and Camera track differently by default */
+ if (base->object->type == OB_LAMP || base->object->type == OB_CAMERA) {
+ data->reserved1 = TRACK_nZ;
+ data->reserved2 = UP_Y;
+ }
+
+ add_constraint_to_object(con, base->object);
+ }
+ }
+ base= base->next;
+ }
+
+ }
+ else if (mode == 2){
+ bConstraint *con;
+ bLockTrackConstraint *data;
+
+ base= FIRSTBASE;
+ while(base) {
+ if TESTBASELIB(base) {
+ if(base!=BASACT) {
+ con = add_new_constraint(CONSTRAINT_TYPE_LOCKTRACK);
+ strcpy (con->name, "AutoTrack");
+
+ data = con->data;
+ data->tar = BASACT->object;
+ base->object->recalc |= OB_RECALC;
+
+ /* Lamp and Camera track differently by default */
+ if (base->object->type == OB_LAMP || base->object->type == OB_CAMERA) {
+ data->trackflag = TRACK_nZ;
+ data->lockflag = LOCK_Y;
+ }
+
+ add_constraint_to_object(con, base->object);
+ }
+ }
+ base= base->next;
+ }
+
+ }
+ else if (mode == 3){
+ base= FIRSTBASE;
+ while(base) {
+ if TESTBASELIB(base) {
+ if(base!=BASACT) {
+ base->object->track= BASACT->object;
+ base->object->recalc |= OB_RECALC;
+ }
+ }
+ base= base->next;
+ }
+ }
+
+ allqueue(REDRAWOOPS, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_scene_sort(G.scene);
+
+ BIF_undo_push("Make Track");
+}
+
+void apply_obmat(Object *ob)
+{
+ float mat[3][3], imat[3][3], tmat[3][3];
+
+ /* from obmat to loc rot size */
+
+ if(ob==0) return;
+ Mat3CpyMat4(mat, ob->obmat);
+
+ VECCOPY(ob->loc, ob->obmat[3]);
+
+ if(ob->transflag & OB_QUAT) {
+ Mat3ToQuat(mat, ob->quat);
+ QuatToMat3(ob->quat, tmat);
+ }
+ else {
+ Mat3ToEul(mat, ob->rot);
+ EulToMat3(ob->rot, tmat);
+ }
+ Mat3Inv(imat, tmat);
+
+ Mat3MulMat3(tmat, imat, mat);
+
+ ob->size[0]= tmat[0][0];
+ ob->size[1]= tmat[1][1];
+ ob->size[2]= tmat[2][2];
+
+}
+
+void clear_parent(void)
+{
+ Object *par;
+ Base *base;
+ int mode;
+
+ if(G.obedit) return;
+ if(G.scene->id.lib) return;
+
+ mode= pupmenu("OK? %t|Clear Parent %x1|Clear and Keep Transformation (Clear Track) %x2|Clear Parent Inverse %x3");
+
+ if(mode<1) return;
+
+ base= FIRSTBASE;
+ while(base) {
+ if TESTBASELIB(base) {
+ par= NULL;
+ if(mode==1 || mode==2) {
+ par= base->object->parent;
+ base->object->parent= NULL;
+ base->object->recalc |= OB_RECALC;
+
+ if(mode==2) {
+ base->object->track= NULL;
+ apply_obmat(base->object);
+ }
+ }
+ else if(mode==3) {
+ Mat4One(base->object->parentinv);
+ base->object->recalc |= OB_RECALC;
+ }
+ }
+ base= base->next;
+ }
+
+ DAG_scene_sort(G.scene);
+ DAG_scene_flush_update(G.scene, screen_view3d_layers());
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWOOPS, 0);
+
+ BIF_undo_push("Clear Parent");
+}
+
+void clear_track(void)
+{
+ Base *base;
+ int mode;
+
+ if(G.obedit) return;
+ if(G.scene->id.lib) return;
+
+ mode= pupmenu("OK? %t|Clear Track %x1| Clear Track and Keep Transform %x2");
+
+ if(mode<1) return;
+
+ base= FIRSTBASE;
+ while(base) {
+ if TESTBASELIB(base) {
+ base->object->track= NULL;
+ base->object->recalc |= OB_RECALC;
+
+ if(mode==2) {
+ apply_obmat(base->object);
+ }
+ }
+ base= base->next;
+ }
+
+ DAG_scene_sort(G.scene);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWOOPS, 0);
+
+ BIF_undo_push("Clear Track");
+}
+
+void clear_object(char mode)
+{
+ Base *base;
+ Object *ob;
+ float *v1, *v3, mat[3][3];
+ int armature_clear= 0;
+ char *str=NULL;
+
+ if(G.obedit) return;
+ if(G.scene->id.lib) return;
+
+ if(mode=='r') str= "Clear rotation";
+ else if(mode=='g') str= "Clear location";
+ else if(mode=='s') str= "Clear scale";
+ else if(mode=='o') str= "Clear origin";
+ else return;
+
+ base= FIRSTBASE;
+ while(base) {
+ if TESTBASELIB(base) {
+ ob= base->object;
+
+ if ((ob->flag & OB_POSEMODE)) {
+ /* only clear pose transforms if:
+ * - with a mesh in weightpaint mode, it's related armature needs to be cleared
+ * - with clearing transform of object being edited at the time
+ */
+ if ((G.f & G_WEIGHTPAINT) || ob==OBACT) {
+ clear_armature(ob, mode);
+ armature_clear= 1; /* silly system to prevent another dag update, so no action applied */
+ }
+ }
+ else if((G.f & G_WEIGHTPAINT)==0) {
+
+ if(mode=='r') {
+ memset(ob->rot, 0, 3*sizeof(float));
+ memset(ob->drot, 0, 3*sizeof(float));
+ QuatOne(ob->quat);
+ QuatOne(ob->dquat);
+#ifdef WITH_VERSE
+ if(ob->vnode) {
+ struct VNode *vnode = (VNode*)ob->vnode;
+ ((VObjectData*)vnode->data)->flag |= ROT_SEND_READY;
+ b_verse_send_transformation(ob);
+ }
+#endif
+
+ }
+ else if(mode=='g') {
+ memset(ob->loc, 0, 3*sizeof(float));
+ memset(ob->dloc, 0, 3*sizeof(float));
+#ifdef WITH_VERSE
+ if(ob->vnode) {
+ struct VNode *vnode = (VNode*)ob->vnode;
+ ((VObjectData*)vnode->data)->flag |= POS_SEND_READY;
+ b_verse_send_transformation(ob);
+ }
+#endif
+
+ }
+ else if(mode=='s') {
+ memset(ob->dsize, 0, 3*sizeof(float));
+ ob->size[0]= 1.0;
+ ob->size[1]= 1.0;
+ ob->size[2]= 1.0;
+#ifdef WITH_VERSE
+ if(ob->vnode) {
+ struct VNode *vnode = (VNode*)ob->vnode;
+ ((VObjectData*)vnode->data)->flag |= SCALE_SEND_READY;
+ b_verse_send_transformation(ob);
+ }
+#endif
+
+ }
+ else if(mode=='o') {
+ if(ob->parent) {
+ v1= ob->loc;
+ v3= ob->parentinv[3];
+
+ Mat3CpyMat4(mat, ob->parentinv);
+ VECCOPY(v3, v1);
+ v3[0]= -v3[0];
+ v3[1]= -v3[1];
+ v3[2]= -v3[2];
+ Mat3MulVecfl(mat, v3);
+ }
+ }
+
+ ob->recalc |= OB_RECALC_OB;
+ }
+ }
+ base= base->next;
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+ if(armature_clear==0) /* in this case flush was done */
+ DAG_scene_flush_update(G.scene, screen_view3d_layers());
+ BIF_undo_push(str);
+}
+
+void reset_slowparents(void)
+{
+ /* back to original locations */
+ Base *base;
+
+ base= FIRSTBASE;
+ while(base) {
+ if(base->object->parent) {
+ if(base->object->partype & PARSLOW) {
+ base->object->partype -= PARSLOW;
+ where_is_object(base->object);
+ base->object->partype |= PARSLOW;
+ }
+ }
+ base= base->next;
+ }
+}
+
+void set_slowparent(void)
+{
+ Base *base;
+
+ if( okee("Set slow parent")==0 ) return;
+
+ base= FIRSTBASE;
+ while(base) {
+ if TESTBASELIB(base) {
+ if(base->object->parent) base->object->partype |= PARSLOW;
+ }
+ base= base->next;
+ }
+ BIF_undo_push("Slow parent");
+}
+
+void make_vertex_parent(void)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+ Base *base;
+ Nurb *nu;
+ BezTriple *bezt;
+ BPoint *bp;
+ Object *par, *ob;
+ int a, v1=0, v2=0, v3=0, v4=0, nr=1;
+
+ /* we need 1 to 3 selected vertices */
+
+ if(G.obedit->type==OB_MESH) {
+ eve= em->verts.first;
+ while(eve) {
+ if(eve->f & 1) {
+ if(v1==0) v1= nr;
+ else if(v2==0) v2= nr;
+ else if(v3==0) v3= nr;
+ else if(v4==0) v4= nr;
+ else break;
+ }
+ nr++;
+ eve= eve->next;
+ }
+ }
+ else if ELEM(G.obedit->type, OB_SURF, OB_CURVE) {
+ extern ListBase editNurb;
+ nu= editNurb.first;
+ while(nu) {
+ if((nu->type & 7)==CU_BEZIER) {
+ bezt= nu->bezt;
+ a= nu->pntsu;
+ while(a--) {
+ if(BEZSELECTED(bezt)) {
+ if(v1==0) v1= nr;
+ else if(v2==0) v2= nr;
+ else if(v3==0) v3= nr;
+ else if(v4==0) v4= nr;
+ else break;
+ }
+ nr++;
+ bezt++;
+ }
+ }
+ else {
+ bp= nu->bp;
+ a= nu->pntsu*nu->pntsv;
+ while(a--) {
+ if(bp->f1 & SELECT) {
+ if(v1==0) v1= nr;
+ else if(v2==0) v2= nr;
+ else if(v3==0) v3= nr;
+ else if(v4==0) v4= nr;
+ else break;
+ }
+ nr++;
+ bp++;
+ }
+ }
+ nu= nu->next;
+ }
+ }
+ else if(G.obedit->type==OB_LATTICE) {
+
+ a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
+ bp= editLatt->def;
+ while(a--) {
+ if(bp->f1 & SELECT) {
+ if(v1==0) v1= nr;
+ else if(v2==0) v2= nr;
+ else if(v3==0) v3= nr;
+ else if(v4==0) v4= nr;
+ else break;
+ }
+ nr++;
+ bp++;
+ }
+ }
+
+ if(v4 || !((v1 && v2==0 && v3==0) || (v1 && v2 && v3)) ) {
+ error("Select either 1 or 3 vertices to parent to");
+ return;
+ }
+
+ if(okee("Make vertex parent")==0) return;
+
+ base= FIRSTBASE;
+ while(base) {
+ if TESTBASELIB(base) {
+ if(base!=BASACT) {
+
+ ob= base->object;
+ ob->recalc |= OB_RECALC;
+ par= BASACT->object->parent;
+
+ while(par) {
+ if(par==ob) break;
+ par= par->parent;
+ }
+ if(par) {
+ error("Loop in parents");
+ }
+ else {
+ ob->parent= BASACT->object;
+ if(v3) {
+ ob->partype= PARVERT3;
+ ob->par1= v1-1;
+ ob->par2= v2-1;
+ ob->par3= v3-1;
+
+ /* inverse parent matrix */
+ what_does_parent(ob);
+ Mat4Invert(ob->parentinv, workob.obmat);
+ clear_workob();
+ }
+ else {
+ ob->partype= PARVERT1;
+ ob->par1= v1-1;
+
+ /* inverse parent matrix */
+ what_does_parent(ob);
+ Mat4Invert(ob->parentinv, workob.obmat);
+ clear_workob();
+ }
+ }
+ }
+ }
+ base= base->next;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+
+ DAG_scene_sort(G.scene);
+ /* BIF_undo_push(str); not, conflicts with editmode undo... */
+}
+
+static Object *group_objects_menu(Group *group)
+{
+ GroupObject *go;
+ int len= 0;
+ short a, nr;
+ char *str;
+
+ for(go= group->gobject.first; go; go= go->next) {
+ if(go->ob)
+ len++;
+ }
+ if(len==0) return NULL;
+
+ str= MEM_callocN(40+32*len, "menu");
+
+ strcpy(str, "Make Proxy for: %t");
+ a= strlen(str);
+ for(nr=1, go= group->gobject.first; go; go= go->next, nr++) {
+ a+= sprintf(str+a, "|%s %%x%d", go->ob->id.name+2, nr);
+ }
+
+ a= pupmenu_col(str, 20);
+ MEM_freeN(str);
+ if(a>0) {
+ go= BLI_findlink(&group->gobject, a-1);
+ return go->ob;
+ }
+ return NULL;
+}
+
+
+/* adds empty object to become local replacement data of a library-linked object */
+void make_proxy(void)
+{
+ Object *ob= OBACT;
+ Object *gob= NULL;
+
+ if(G.scene->id.lib) return;
+ if(ob==NULL) return;
+
+
+ if(ob->dup_group && ob->dup_group->id.lib) {
+ gob= ob;
+ /* gives menu with list of objects in group */
+ ob= group_objects_menu(ob->dup_group);
+ }
+ else if(ob->id.lib) {
+ if(okee("Make Proxy Object")==0)
+ return;
+ }
+ else {
+ error("Can only make proxy for a referenced object or group");
+ return;
+ }
+
+ if(ob) {
+ Object *newob;
+ Base *newbase, *oldbase= BASACT;
+ char name[32];
+
+ newob= add_object(OB_EMPTY);
+ if(gob)
+ strcpy(name, gob->id.name+2);
+ else
+ strcpy(name, ob->id.name+2);
+ strcat(name, "_proxy");
+ rename_id(&newob->id, name);
+
+ /* set layers OK */
+ newbase= BASACT; /* add_object sets active... */
+ newbase->lay= oldbase->lay;
+ newob->lay= newbase->lay;
+
+ /* remove base, leave user count of object, it gets linked in object_make_proxy */
+ if(gob==NULL) {
+ BLI_remlink(&G.scene->base, oldbase);
+ MEM_freeN(oldbase);
+ }
+ object_make_proxy(newob, ob, gob);
+
+ DAG_scene_sort(G.scene);
+ DAG_object_flush_update(G.scene, newob, OB_RECALC);
+ allqueue(REDRAWALL, 0);
+ BIF_undo_push("Make Proxy Object");
+ }
+}
+
+int test_parent_loop(Object *par, Object *ob)
+{
+ /* test if 'ob' is a parent somewhere in par's parents */
+
+ if(par==0) return 0;
+ if(ob == par) return 1;
+
+ return test_parent_loop(par->parent, ob);
+
+}
+
+void make_parent(void)
+{
+ Base *base;
+ Object *par;
+ bPoseChannel *pchan= NULL;
+ short qual, mode=0;
+
+ if(G.scene->id.lib) return;
+ if(G.obedit) {
+ if ELEM4(G.obedit->type, OB_MESH, OB_CURVE, OB_SURF, OB_LATTICE) make_vertex_parent();
+ else if (G.obedit->type==OB_ARMATURE) make_bone_parent();
+ return;
+ }
+ if(BASACT==0) return;
+
+ qual= G.qual;
+ par= BASACT->object;
+
+ if(par->type == OB_LATTICE){
+ mode= pupmenu("Make Parent %t|Normal Parent %x1|Lattice Deform %x2");
+ if(mode<=0){
+ return;
+ }
+ else if(mode==1) {
+ mode= PAROBJECT;
+ }
+ else if(mode==2) {
+ mode= PARSKEL;
+ }
+ }
+ else if(par->type == OB_CURVE){
+ mode= pupmenu("Make Parent %t|Normal Parent %x1|Follow Path %x2|Curve Deform %x3|Path Constraint %x4");
+ if(mode<=0){
+ return;
+ }
+ else if(mode==1) {
+ mode= PAROBJECT;
+ }
+ else if(mode==2) {
+ Curve *cu= par->data;
+
+ mode= PAROBJECT;
+ if((cu->flag & CU_PATH)==0) {
+ cu->flag |= CU_PATH|CU_FOLLOW;
+ makeDispListCurveTypes(par, 0); /* force creation of path data */
+ }
+ else cu->flag |= CU_FOLLOW;
+ }
+ else if(mode==3) {
+ mode= PARSKEL;
+ }
+ else if(mode==4) {
+ bConstraint *con;
+ bFollowPathConstraint *data;
+
+ base= FIRSTBASE;
+ while(base) {
+ if TESTBASELIB(base) {
+ if(base!=BASACT) {
+ float cmat[4][4], vec[3];
+
+ con = add_new_constraint(CONSTRAINT_TYPE_FOLLOWPATH);
+ strcpy (con->name, "AutoPath");
+
+ data = con->data;
+ data->tar = BASACT->object;
+
+ add_constraint_to_object(con, base->object);
+
+ get_constraint_target_matrix(con, 0, CONSTRAINT_OBTYPE_OBJECT, NULL, cmat, G.scene->r.cfra - base->object->sf);
+ VecSubf(vec, base->object->obmat[3], cmat[3]);
+
+ base->object->loc[0] = vec[0];
+ base->object->loc[1] = vec[1];
+ base->object->loc[2] = vec[2];
+ }
+ }
+ base= base->next;
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_scene_sort(G.scene);
+ BIF_undo_push("Make Parent");
+ return;
+ }
+ }
+ else if(par->type == OB_ARMATURE){
+
+ base= FIRSTBASE;
+ while(base) {
+ if TESTBASELIB(base) {
+ if(base!=BASACT) {
+ if(ELEM(base->object->type, OB_MESH, OB_LATTICE)) {
+ if(par->flag & OB_POSEMODE)
+ mode= pupmenu("Make Parent To%t|Bone %x1|Armature %x2|Object %x3");
+ else
+ mode= pupmenu("Make Parent To%t|Armature %x2|Object %x3");
+ break;
+ }
+ else {
+ if(par->flag & OB_POSEMODE)
+ mode= pupmenu("Make Parent To %t|Bone %x1|Object %x3");
+ else
+ mode= pupmenu("Make Parent To %t|Object %x3");
+ break;
+ }
+ }
+ }
+ base= base->next;
+ }
+
+ switch (mode){
+ case 1:
+ mode=PARBONE;
+ pchan= get_active_posechannel(par);
+
+ if(pchan==NULL) {
+ error("No active Bone");
+ allqueue(REDRAWVIEW3D, 0);
+ return;
+ }
+
+ break;
+ case 2:
+ mode=PARSKEL;
+ break;
+ case 3:
+ mode=PAROBJECT;
+ break;
+ default:
+ return;
+ }
+ }
+ else {
+ if(qual & LR_SHIFTKEY) {
+ if(okee("Make parent without inverse")==0) return;
+ }
+ else {
+ if(qual & LR_ALTKEY) {
+ if(okee("Make vertex parent")==0) return;
+ }
+ else if(okee("Make parent")==0) return;
+
+ /* now we'll clearparentandkeeptransform all objects */
+ base= FIRSTBASE;
+ while(base) {
+ if TESTBASELIB(base) {
+ if(base!=BASACT && base->object->parent) {
+ base->object->parent= NULL;
+ apply_obmat(base->object);
+ }
+ }
+ base= base->next;
+ }
+ }
+ }
+
+ par->recalc |= OB_RECALC_OB;
+
+ base= FIRSTBASE;
+ while(base) {
+ if TESTBASELIB(base) {
+ if(base!=BASACT) {
+
+ if( test_parent_loop(par, base->object) ) {
+ error("Loop in parents");
+ }
+ else {
+
+ base->object->recalc |= OB_RECALC_OB|OB_RECALC_DATA;
+
+ /* the ifs below are horrible code (ton) */
+
+ if (par->type==OB_ARMATURE) {
+ base->object->partype= mode;
+ if (pchan)
+ strcpy (base->object->parsubstr, pchan->name);
+ else
+ base->object->parsubstr[0]=0;
+ }
+ else {
+ if(qual & LR_ALTKEY) {
+ base->object->partype= PARVERT1;
+ }
+ else if(ELEM(par->type, OB_CURVE, OB_LATTICE)) {
+ base->object->partype= mode;
+ }
+ else {
+ base->object->partype= PAROBJECT;
+ }
+ }
+
+ base->object->parent= par;
+
+ /* calculate inverse parent matrix? */
+ if( (qual & LR_SHIFTKEY) ) {
+ /* not... */
+ Mat4One(base->object->parentinv);
+ memset(base->object->loc, 0, 3*sizeof(float));
+ }
+ else {
+ if(mode==PARSKEL && base->object->type==OB_MESH && par->type == OB_ARMATURE) {
+ /* Prompt the user as to whether he wants to
+ * add some vertex groups based on the bones
+ * in the parent armature.
+ */
+ create_vgroups_from_armature(base->object,
+ par);
+
+ base->object->partype= PAROBJECT;
+ what_does_parent(base->object);
+ Mat4One (base->object->parentinv);
+ base->object->partype= mode;
+ }
+ else
+ what_does_parent(base->object);
+ Mat4Invert(base->object->parentinv, workob.obmat);
+ }
+ }
+ }
+ }
+ base= base->next;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWOOPS, 0);
+
+ DAG_scene_sort(G.scene);
+ DAG_scene_flush_update(G.scene, screen_view3d_layers());
+
+ BIF_undo_push("make Parent");
+}
+
+
+void enter_editmode(int wc)
+{
+ Base *base;
+ Object *ob;
+ Mesh *me;
+ bArmature *arm;
+ int ok= 0;
+
+ if(G.scene->id.lib) return;
+ base= BASACT;
+ if(base==0) return;
+ if((G.vd==NULL || (base->lay & G.vd->lay))==0) return;
+
+ strcpy(G.editModeTitleExtra, "");
+
+ ob= base->object;
+ if(ob->data==0) return;
+
+ if (object_data_is_libdata(ob)) {
+ error_libdata();
+ return;
+ }
+
+ if(wc) waitcursor(1);
+
+ if(ob->type==OB_MESH) {
+ me= get_mesh(ob);
+ if( me==0 ) return;
+ if(me->pv) sculptmode_pmv_off(me);
+ ok= 1;
+ G.obedit= ob;
+ make_editMesh();
+ allqueue(REDRAWBUTSLOGIC, 0);
+ /*if(G.f & G_FACESELECT) allqueue(REDRAWIMAGE, 0);*/
+ if (EM_texFaceCheck())
+ allqueue(REDRAWIMAGE, 0);
+
+ }
+ if (ob->type==OB_ARMATURE){
+ arm= base->object->data;
+ if (!arm) return;
+ /*
+ * The function object_data_is_libdata make a problem here, the
+ * check for ob->proxy return 0 and let blender enter to edit mode
+ * this causa a crash when you try leave the edit mode.
+ * The problem is that i can't remove the ob->proxy check from
+ * object_data_is_libdata that prevent the bugfix #6614, so
+ * i add this little hack here.
+ */
+ if(arm->id.lib) {
+ error_libdata();
+ return;
+ }
+ ok=1;
+ G.obedit=ob;
+ make_editArmature();
+ /* to ensure all goes in restposition and without striding */
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC);
+
+ allqueue (REDRAWVIEW3D,0);
+ }
+ else if(ob->type==OB_FONT) {
+ G.obedit= ob;
+ ok= 1;
+ make_editText();
+ }
+ else if(ob->type==OB_MBALL) {
+ G.obedit= ob;
+ ok= 1;
+ make_editMball();
+ }
+ else if(ob->type==OB_LATTICE) {
+ G.obedit= ob;
+ ok= 1;
+ make_editLatt();
+ }
+ else if(ob->type==OB_SURF || ob->type==OB_CURVE) {
+ ok= 1;
+ G.obedit= ob;
+ make_editNurb();
+ }
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWOOPS, 0);
+ countall();
+
+ if(ok) {
+ setcursor_space(SPACE_VIEW3D, CURSOR_EDIT);
+
+ allqueue(REDRAWVIEW3D, 1);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+
+ }
+ else G.obedit= NULL;
+
+ if(wc) waitcursor(0);
+
+ scrarea_queue_headredraw(curarea);
+}
+
+void exit_editmode(int flag) /* freedata==0 at render, 1= freedata, 2= do undo buffer too */
+{
+ Object *ob;
+ int freedata = flag & EM_FREEDATA;
+
+ if(G.obedit==NULL) return;
+
+ if(flag & EM_WAITCURSOR) waitcursor(1);
+ if(G.obedit->type==OB_MESH) {
+
+ /* temporal */
+ countall();
+
+ if(EM_texFaceCheck())
+ allqueue(REDRAWIMAGE, 0);
+
+ if(retopo_mesh_paint_check())
+ retopo_end_okee();
+
+ if(G.totvert>MESH_MAX_VERTS) {
+ error("Too many vertices");
+ return;
+ }
+ load_editMesh();
+
+ if(freedata) free_editMesh(G.editMesh);
+
+ if(G.f & G_WEIGHTPAINT)
+ mesh_octree_table(G.obedit, NULL, 'e');
+ }
+ else if (G.obedit->type==OB_ARMATURE){
+ load_editArmature();
+ if (freedata) free_editArmature();
+ }
+ else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) {
+ extern ListBase editNurb;
+ load_editNurb();
+ if(freedata) freeNurblist(&editNurb);
+ }
+ else if(G.obedit->type==OB_FONT && freedata) {
+ load_editText();
+ }
+ else if(G.obedit->type==OB_LATTICE) {
+ load_editLatt();
+ if(freedata) free_editLatt();
+ }
+ else if(G.obedit->type==OB_MBALL) {
+ extern ListBase editelems;
+ load_editMball();
+ if(freedata) BLI_freelistN(&editelems);
+ }
+
+ ob= G.obedit;
+
+ /* for example; displist make is different in editmode */
+ if(freedata) G.obedit= NULL;
+
+ /* total remake of softbody data */
+ if(modifiers_isSoftbodyEnabled(ob)) {
+ if (ob->soft && ob->soft->keys) {
+ notice("Erase Baked SoftBody");
+ }
+
+ sbObjectToSoftbody(ob);
+ }
+
+ if(ob->type==OB_MESH && get_mesh(ob)->mr)
+ multires_edge_level_update(ob, get_mesh(ob));
+
+ /* also flush ob recalc, doesn't take much overhead, but used for particles */
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_OB|OB_RECALC_DATA);
+
+ if(freedata) {
+ setcursor_space(SPACE_VIEW3D, CURSOR_STD);
+ }
+
+ countall();
+ allqueue(REDRAWVIEW3D, 1);
+ allqueue(REDRAWBUTSALL, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWNLA, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWOOPS, 0);
+
+ scrarea_queue_headredraw(curarea);
+
+ if(G.obedit==NULL && (flag & EM_FREEUNDO))
+ BIF_undo_push("Editmode");
+
+ if(flag & EM_WAITCURSOR) waitcursor(0);
+}
+
+void check_editmode(int type)
+{
+
+ if (G.obedit==0 || G.obedit->type==type) return;
+
+ exit_editmode(EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR); /* freedata, and undo */
+}
+
+/* 0 == do center, 1 == center new, 2 == center cursor */
+
+void docenter(int centermode)
+{
+ EditMesh *em = G.editMesh;
+ Base *base;
+ Object *ob;
+ Mesh *me, *tme;
+ Curve *cu;
+/* BezTriple *bezt;
+ BPoint *bp; */
+ Nurb *nu, *nu1;
+ EditVert *eve;
+ float cent[3], centn[3], min[3], max[3], omat[3][3];
+ int a, total= 0;
+
+ /* keep track of what is changed */
+ int tot_change=0, tot_lib_error=0, tot_key_error=0, tot_multiuser_arm_error=0;
+ MVert *mvert;
+
+ if(G.scene->id.lib || G.vd==NULL) return;
+
+ cent[0]= cent[1]= cent[2]= 0.0;
+
+ if(G.obedit) {
+
+ INIT_MINMAX(min, max);
+
+ if(G.obedit->type==OB_MESH) {
+ for(eve= em->verts.first; eve; eve= eve->next) {
+ if(G.vd->around==V3D_CENTROID) {
+ total++;
+ VECADD(cent, cent, eve->co);
+ }
+ else {
+ DO_MINMAX(eve->co, min, max);
+ }
+ }
+
+ if(G.vd->around==V3D_CENTROID) {
+ VecMulf(cent, 1.0f/(float)total);
+ }
+ else {
+ cent[0]= (min[0]+max[0])/2.0f;
+ cent[1]= (min[1]+max[1])/2.0f;
+ cent[2]= (min[2]+max[2])/2.0f;
+ }
+
+ for(eve= em->verts.first; eve; eve= eve->next) {
+ VecSubf(eve->co, eve->co, cent);
+ }
+
+ recalc_editnormals();
+ tot_change++;
+ }
+ }
+
+ /* reset flags */
+ for (base=FIRSTBASE; base; base= base->next) {
+ if TESTBASELIB(base)
+ base->object->flag &= ~OB_DONE;
+ }
+
+ for (me= G.main->mesh.first; me; me= me->id.next) {
+ me->flag &= ~ME_ISDONE;
+ }
+
+ base= FIRSTBASE;
+ while(base) {
+
+ if TESTBASELIB(base) {
+ if((base->object->flag & OB_DONE)==0) {
+ base->object->flag |= OB_DONE;
+
+ if(base->object->id.lib) {
+ tot_lib_error++;
+ }
+ else if(G.obedit==0 && (me=get_mesh(base->object)) ) {
+
+ if(me->key) {
+ /*error("Can't change the center of a mesh with vertex keys");
+ return;*/
+ tot_key_error++;
+ } else if (me->id.lib) {
+ tot_lib_error++;
+ } else {
+ if(centermode==2) {
+ VECCOPY(cent, give_cursor());
+ Mat4Invert(base->object->imat, base->object->obmat);
+ Mat4MulVecfl(base->object->imat, cent);
+ } else {
+ INIT_MINMAX(min, max);
+ mvert= me->mvert;
+ for(a=0; a<me->totvert; a++, mvert++) {
+ DO_MINMAX(mvert->co, min, max);
+ }
+
+ cent[0]= (min[0]+max[0])/2.0f;
+ cent[1]= (min[1]+max[1])/2.0f;
+ cent[2]= (min[2]+max[2])/2.0f;
+ }
+
+ mvert= me->mvert;
+ for(a=0; a<me->totvert; a++, mvert++) {
+ VecSubf(mvert->co, mvert->co, cent);
+ }
+ me->flag |= ME_ISDONE;
+
+ if(centermode) {
+ Mat3CpyMat4(omat, base->object->obmat);
+
+ VECCOPY(centn, cent);
+ Mat3MulVecfl(omat, centn);
+ base->object->loc[0]+= centn[0];
+ base->object->loc[1]+= centn[1];
+ base->object->loc[2]+= centn[2];
+
+ /* other users? */
+ ob= G.main->object.first;
+ while(ob) {
+ if((ob->flag & OB_DONE)==0) {
+ tme= get_mesh(ob);
+
+ if(tme==me) {
+
+ ob->flag |= OB_DONE;
+ ob->recalc= OB_RECALC_OB|OB_RECALC_DATA;
+
+ Mat3CpyMat4(omat, ob->obmat);
+ VECCOPY(centn, cent);
+ Mat3MulVecfl(omat, centn);
+ ob->loc[0]+= centn[0];
+ ob->loc[1]+= centn[1];
+ ob->loc[2]+= centn[2];
+
+ if(tme && (tme->flag & ME_ISDONE)==0) {
+ mvert= tme->mvert;
+ for(a=0; a<tme->totvert; a++, mvert++) {
+ VecSubf(mvert->co, mvert->co, cent);
+ }
+ tme->flag |= ME_ISDONE;
+ }
+ }
+ }
+
+ ob= ob->id.next;
+ }
+ }
+ tot_change++;
+ }
+ }
+ else if ELEM(base->object->type, OB_CURVE, OB_SURF) {
+
+ /* totally weak code here... (ton) */
+ if(G.obedit==base->object) {
+ extern ListBase editNurb;
+ nu1= editNurb.first;
+ cu= G.obedit->data;
+ }
+ else {
+ cu= base->object->data;
+ nu1= cu->nurb.first;
+ }
+
+ if (cu->id.lib) {
+ tot_lib_error++;
+ } else {
+ if(centermode==2) {
+ VECCOPY(cent, give_cursor());
+ Mat4Invert(base->object->imat, base->object->obmat);
+ Mat4MulVecfl(base->object->imat, cent);
+
+ /* don't allow Z change if curve is 2D */
+ if( !( cu->flag & CU_3D ) )
+ cent[2] = 0.0;
+ } else {
+ INIT_MINMAX(min, max);
+
+ nu= nu1;
+ while(nu) {
+ minmaxNurb(nu, min, max);
+ nu= nu->next;
+ }
+
+ cent[0]= (min[0]+max[0])/2.0f;
+ cent[1]= (min[1]+max[1])/2.0f;
+ cent[2]= (min[2]+max[2])/2.0f;
+ }
+
+ nu= nu1;
+ while(nu) {
+ if( (nu->type & 7)==1) {
+ a= nu->pntsu;
+ while (a--) {
+ VecSubf(nu->bezt[a].vec[0], nu->bezt[a].vec[0], cent);
+ VecSubf(nu->bezt[a].vec[1], nu->bezt[a].vec[1], cent);
+ VecSubf(nu->bezt[a].vec[2], nu->bezt[a].vec[2], cent);
+ }
+ }
+ else {
+ a= nu->pntsu*nu->pntsv;
+ while (a--)
+ VecSubf(nu->bp[a].vec, nu->bp[a].vec, cent);
+ }
+ nu= nu->next;
+ }
+
+ if(centermode && G.obedit==0) {
+ Mat3CpyMat4(omat, base->object->obmat);
+
+ Mat3MulVecfl(omat, cent);
+ base->object->loc[0]+= cent[0];
+ base->object->loc[1]+= cent[1];
+ base->object->loc[2]+= cent[2];
+ }
+
+ tot_change++;
+ if(G.obedit) {
+ if (centermode==0) {
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ }
+ break;
+ }
+ }
+ }
+ else if(base->object->type==OB_FONT) {
+ /* get from bb */
+
+ cu= base->object->data;
+
+ if(cu->bb==0) {
+ /* do nothing*/
+ } else if (cu->id.lib) {
+ tot_lib_error++;
+ } else {
+ cu->xof= -0.5f*( cu->bb->vec[4][0] - cu->bb->vec[0][0]);
+ cu->yof= -0.5f -0.5f*( cu->bb->vec[0][1] - cu->bb->vec[2][1]); /* extra 0.5 is the height of above line */
+
+ /* not really ok, do this better once! */
+ cu->xof /= cu->fsize;
+ cu->yof /= cu->fsize;
+
+ allqueue(REDRAWBUTSEDIT, 0);
+ tot_change++;
+ }
+ }
+ else if(base->object->type==OB_ARMATURE) {
+ bArmature *arm = base->object->data;
+
+ if (arm->id.lib) {
+ tot_lib_error++;
+ } else if(arm->id.us>1) {
+ /*error("Can't apply to a multi user armature");
+ return;*/
+ tot_multiuser_arm_error++;
+ } else {
+ /* Function to recenter armatures in editarmature.c
+ * Bone + object locations are handled there.
+ */
+ docenter_armature(base->object, centermode);
+ tot_change++;
+ if(G.obedit)
+ break;
+ }
+ }
+ base->object->recalc= OB_RECALC_OB|OB_RECALC_DATA;
+ }
+ }
+ base= base->next;
+ }
+ if (tot_change) {
+ DAG_scene_flush_update(G.scene, screen_view3d_layers());
+ allqueue(REDRAWVIEW3D, 0);
+ BIF_undo_push("Do Center");
+ }
+
+ /* Warn if any errors occured */
+ if (tot_lib_error+tot_key_error+tot_multiuser_arm_error) {
+ char err[512];
+ sprintf(err, "Warning %i Object(s) Not Centered, %i Changed:", tot_lib_error+tot_key_error+tot_multiuser_arm_error, tot_change);
+
+ if (tot_lib_error)
+ sprintf(err+strlen(err), "|%i linked library objects", tot_lib_error);
+ if (tot_key_error)
+ sprintf(err+strlen(err), "|%i mesh key object(s)", tot_key_error);
+ if (tot_multiuser_arm_error)
+ sprintf(err+strlen(err), "|%i multiuser armature object(s)", tot_multiuser_arm_error);
+
+ error(err);
+ }
+}
+
+void docenter_new(void)
+{
+ if(G.scene->id.lib) return;
+
+ if(G.obedit) {
+ error("Unable to center new in Edit Mode");
+ }
+ else {
+ docenter(1);
+ }
+}
+
+void docenter_cursor(void)
+{
+ if(G.scene->id.lib) return;
+
+ if(G.obedit) {
+ error("Unable to center cursor in Edit Mode");
+ }
+ else {
+ docenter(2);
+ }
+}
+
+void movetolayer(void)
+{
+ Base *base;
+ unsigned int lay= 0, local;
+ int islamp= 0;
+
+ if(G.scene->id.lib) return;
+
+ base= FIRSTBASE;
+ while(base) {
+ if TESTBASE(base) lay |= base->lay;
+ base= base->next;
+ }
+ if(lay==0) return;
+ lay &= 0xFFFFFF;
+
+ if(lay==0) return;
+
+ if(G.vd->localview) {
+ /* now we can move out of localview. */
+ if (!okee("Move from localview")) return;
+ base= FIRSTBASE;
+ while(base) {
+ if TESTBASE(base) {
+ lay= base->lay & ~G.vd->lay;
+ base->lay= lay;
+ base->object->lay= lay;
+ base->object->flag &= ~SELECT;
+ base->flag &= ~SELECT;
+ if(base->object->type==OB_LAMP) islamp= 1;
+ }
+ base= base->next;
+ }
+ } else {
+ if( movetolayer_buts(&lay, NULL)==0 ) return;
+
+ /* normal non localview operation */
+ base= FIRSTBASE;
+ while(base) {
+ if TESTBASE(base) {
+ /* upper byte is used for local view */
+ local= base->lay & 0xFF000000;
+ base->lay= lay + local;
+ base->object->lay= lay;
+ if(base->object->type==OB_LAMP) islamp= 1;
+ }
+ base= base->next;
+ }
+ }
+ if(islamp) reshadeall_displist(); /* only frees */
+
+ /* warning, active object may be hidden now */
+
+ countall();
+ DAG_scene_sort(G.scene);
+
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWOOPS, 0);
+ allqueue(REDRAWINFO, 0);
+
+ BIF_undo_push("Move to layer");
+}
+
+/* THIS IS BAD CODE! do not bring back before it has a real implementation (ton) */
+void split_font()
+{
+ Object *ob = OBACT;
+ Base *oldbase = BASACT;
+ Curve *cu= ob->data;
+ char *p= cu->str;
+ int slen= strlen(p);
+ int i;
+
+ for (i = 0; i<=slen; p++, i++) {
+ adduplicate(1, U.dupflag);
+ cu= OBACT->data;
+ cu->sepchar = i+1;
+ text_to_curve(OBACT, 0); /* pass 1: only one letter, adapt position */
+ text_to_curve(OBACT, 0); /* pass 2: remake */
+ freedisplist(&OBACT->disp);
+ makeDispListCurveTypes(OBACT, 0);
+
+ OBACT->flag &= ~SELECT;
+ BASACT->flag &= ~SELECT;
+ oldbase->flag |= SELECT;
+ oldbase->object->flag |= SELECT;
+ set_active_base(oldbase);
+ }
+}
+
+void special_editmenu(void)
+{
+ static short numcuts= 2;
+ Object *ob= OBACT;
+ float fac;
+ int nr,ret;
+ short randfac;
+
+ if(ob==NULL) return;
+
+ if(G.obedit==NULL) {
+
+ if(ob->flag & OB_POSEMODE) {
+ pose_special_editmenu();
+ }
+ else if(FACESEL_PAINT_TEST) {
+ Mesh *me= get_mesh(ob);
+ MTFace *tface;
+ MFace *mface;
+ int a;
+
+ if(me==0 || me->mtface==0) return;
+
+ nr= pupmenu("Specials%t|Set Tex%x1| Shared%x2| Light%x3| Invisible%x4| Collision%x5| TwoSide%x6|Clr Tex%x7| Shared%x8| Light%x9| Invisible%x10| Collision%x11| TwoSide%x12");
+
+ tface= me->mtface;
+ mface= me->mface;
+ for(a=me->totface; a>0; a--, tface++, mface++) {
+ if(mface->flag & ME_FACE_SEL) {
+ switch(nr) {
+ case 1:
+ tface->mode |= TF_TEX; break;
+ case 2:
+ tface->mode |= TF_SHAREDCOL; break;
+ case 3:
+ tface->mode |= TF_LIGHT; break;
+ case 4:
+ tface->mode |= TF_INVISIBLE; break;
+ case 5:
+ tface->mode |= TF_DYNAMIC; break;
+ case 6:
+ tface->mode |= TF_TWOSIDE; break;
+ case 7:
+ tface->mode &= ~TF_TEX;
+ tface->tpage= 0;
+ break;
+ case 8:
+ tface->mode &= ~TF_SHAREDCOL; break;
+ case 9:
+ tface->mode &= ~TF_LIGHT; break;
+ case 10:
+ tface->mode &= ~TF_INVISIBLE; break;
+ case 11:
+ tface->mode &= ~TF_DYNAMIC; break;
+ case 12:
+ tface->mode &= ~TF_TWOSIDE; break;
+ }
+ }
+ }
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ BIF_undo_push("Change texture face");
+ }
+ else if(G.f & G_VERTEXPAINT) {
+ Mesh *me= get_mesh(ob);
+
+ if(me==0 || (me->mcol==NULL && me->mtface==NULL) ) return;
+
+ nr= pupmenu("Specials%t|Shared VertexCol%x1");
+ if(nr==1) {
+
+ do_shared_vertexcol(me);
+
+ BIF_undo_push("Shared VertexCol");
+
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ }
+ }
+ else if(G.f & G_WEIGHTPAINT) {
+ Object *par= modifiers_isDeformedByArmature(ob);
+
+ if(par && (par->flag & OB_POSEMODE)) {
+ nr= pupmenu("Specials%t|Apply Bone Envelopes to Vertex Groups %x1|Apply Bone Heat Weights to Vertex Groups %x2");
+
+ if(nr==1 || nr==2)
+ pose_adds_vgroups(ob, (nr == 2));
+ }
+ }
+ else {
+ Base *base, *base_select= NULL;
+
+ /* Get the active object mesh. */
+ Mesh *me= get_mesh(ob);
+
+ /* Booleans, if the active object is a mesh... */
+ if (me && ob->id.lib==NULL) {
+
+ /* Bring up a little menu with the boolean operation choices on. */
+ nr= pupmenu("Boolean Tools%t|Intersect%x1|Union%x2|Difference%x3|Add Intersect Modifier%x4|Add Union Modifier%x5|Add Difference Modifier%x6");
+
+ if (nr > 0) {
+ /* user has made a choice of a menu element.
+ All of the boolean functions require 2 mesh objects
+ we search through the object list to find the other
+ selected item and make sure it is distinct and a mesh. */
+
+ for(base= FIRSTBASE; base; base= base->next) {
+ if TESTBASELIB(base) {
+ if(base->object != ob) base_select= base;
+ }
+ }
+
+ if (base_select) {
+ if (get_mesh(base_select->object)) {
+ if(nr <= 3){
+ waitcursor(1);
+ ret = NewBooleanMesh(BASACT,base_select,nr);
+ if (ret==0) {
+ error("An internal error occurred");
+ } else if(ret==-1) {
+ error("Selected meshes must have faces to perform boolean operations");
+ } else if (ret==-2) {
+ error("Both meshes must be a closed mesh");
+ }
+ else BIF_undo_push("Boolean");
+ waitcursor(0);
+ } else {
+ BooleanModifierData *bmd = NULL;
+ bmd = (BooleanModifierData *)modifier_new(eModifierType_Boolean);
+ BLI_addtail(&ob->modifiers, bmd);
+ bmd->object = base_select->object;
+ bmd->modifier.mode |= eModifierMode_Realtime;
+ switch(nr){
+ case 4: bmd->operation = eBooleanModifierOp_Intersect; break;
+ case 5: bmd->operation = eBooleanModifierOp_Union; break;
+ case 6: bmd->operation = eBooleanModifierOp_Difference; break;
+ }
+ do_common_editbuts(B_CHANGEDEP);
+ BIF_undo_push("Add Boolean modifier");
+ }
+ } else {
+ error("Please select 2 meshes");
+ }
+ } else {
+ error("Please select 2 meshes");
+ }
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ else if (ob->type == OB_FONT) {
+ /* removed until this gets a decent implementation (ton) */
+/* nr= pupmenu("Split %t|Characters%x1");
+ if (nr > 0) {
+ switch(nr) {
+ case 1: split_font();
+ }
+ }
+*/
+ }
+ }
+ }
+ else if(G.obedit->type==OB_MESH) {
+ /* This is all that is needed, since all other functionality is in Ctrl+ V/E/F but some users didnt like, so for now have the old/big menu */
+ /*
+ nr= pupmenu("Subdivide Mesh%t|Subdivide%x1|Subdivide Multi%x2|Subdivide Multi Fractal%x3|Subdivide Smooth%x4");
+ switch(nr) {
+ case 1:
+ waitcursor(1);
+ esubdivideflag(1, 0.0, G.scene->toolsettings->editbutflag, 1, 0);
+
+ BIF_undo_push("ESubdivide Single");
+ break;
+ case 2:
+ if(button(&numcuts, 1, 128, "Number of Cuts:")==0) return;
+ waitcursor(1);
+ esubdivideflag(1, 0.0, G.scene->toolsettings->editbutflag, numcuts, 0);
+ BIF_undo_push("ESubdivide");
+ break;
+ case 3:
+ if(button(&numcuts, 1, 128, "Number of Cuts:")==0) return;
+ randfac= 10;
+ if(button(&randfac, 1, 100, "Rand fac:")==0) return;
+ waitcursor(1);
+ fac= -( (float)randfac )/100;
+ esubdivideflag(1, fac, G.scene->toolsettings->editbutflag, numcuts, 0);
+ BIF_undo_push("Subdivide Fractal");
+ break;
+
+ case 4:
+ fac= 1.0f;
+ if(fbutton(&fac, 0.0f, 5.0f, 10, 10, "Smooth:")==0) return;
+ fac= 0.292f*fac;
+
+ waitcursor(1);
+ esubdivideflag(1, fac, G.scene->toolsettings->editbutflag | B_SMOOTH, 1, 0);
+ BIF_undo_push("Subdivide Smooth");
+ break;
+ }
+ */
+
+ nr= pupmenu("Specials%t|Subdivide%x1|Subdivide Multi%x2|Subdivide Multi Fractal%x3|Subdivide Smooth%x12|Merge%x4|Remove Doubles%x5|Hide%x6|Reveal%x7|Select Swap%x8|Flip Normals %x9|Smooth %x10|Bevel %x11|Set Smooth %x14|Set Solid %x15|Blend From Shape%x16|Propagate To All Shapes%x17|Select Vertex Path%x18");
+
+ switch(nr) {
+ case 1:
+ waitcursor(1);
+ esubdivideflag(1, 0.0, G.scene->toolsettings->editbutflag, 1, 0);
+
+ BIF_undo_push("ESubdivide Single");
+ break;
+ case 2:
+ if(button(&numcuts, 1, 128, "Number of Cuts:")==0) return;
+ waitcursor(1);
+ esubdivideflag(1, 0.0, G.scene->toolsettings->editbutflag, numcuts, 0);
+ BIF_undo_push("ESubdivide");
+ break;
+ case 3:
+ if(button(&numcuts, 1, 128, "Number of Cuts:")==0) return;
+ randfac= 10;
+ if(button(&randfac, 1, 100, "Rand fac:")==0) return;
+ waitcursor(1);
+ fac= -( (float)randfac )/100;
+ esubdivideflag(1, fac, G.scene->toolsettings->editbutflag, numcuts, 0);
+ BIF_undo_push("Subdivide Fractal");
+ break;
+
+ case 12: /* smooth */
+ /* if(button(&numcuts, 1, 128, "Number of Cuts:")==0) return; */
+ fac= 1.0f;
+ if(fbutton(&fac, 0.0f, 5.0f, 10, 10, "Smooth:")==0) return;
+ fac= 0.292f*fac;
+
+ waitcursor(1);
+ esubdivideflag(1, fac, G.scene->toolsettings->editbutflag | B_SMOOTH, 1, 0);
+ BIF_undo_push("Subdivide Smooth");
+ break;
+
+ case 4:
+ mergemenu();
+ break;
+ case 5:
+ notice("Removed %d Vertices", removedoublesflag(1, 0, G.scene->toolsettings->doublimit));
+ BIF_undo_push("Remove Doubles");
+ break;
+ case 6:
+ hide_mesh(0);
+ break;
+ case 7:
+ reveal_mesh();
+ break;
+ case 8:
+ selectswap_mesh();
+ break;
+ case 9:
+ flip_editnormals();
+ BIF_undo_push("Flip Normals");
+ break;
+ case 10:
+ vertexsmooth();
+ break;
+ case 11:
+ bevel_menu();
+ break;
+ case 14:
+ mesh_set_smooth_faces(1);
+ break;
+ case 15:
+ mesh_set_smooth_faces(0);
+ break;
+ case 16:
+ shape_copy_select_from();
+ break;
+ case 17:
+ shape_propagate();
+ break;
+ case 18:
+ pathselect();
+ BIF_undo_push("Select Vertex Path");
+ break;
+ }
+
+
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+
+ if(nr>0) waitcursor(0);
+
+ }
+ else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) {
+
+ nr= pupmenu("Specials%t|Subdivide%x1|Switch Direction%x2|Set Goal Weight %x3|Set Radius %x4");
+
+ switch(nr) {
+ case 1:
+ subdivideNurb();
+ break;
+ case 2:
+ switchdirectionNurb2();
+ break;
+ case 3:
+ {
+ static float weight= 1.0f;
+ extern ListBase editNurb;
+ Nurb *nu;
+ BezTriple *bezt;
+ BPoint *bp;
+ int a;
+
+ if(fbutton(&weight, 0.0f, 1.0f, 10, 10, "Set Weight")) {
+ for(nu= editNurb.first; nu; nu= nu->next) {
+ if(nu->bezt) {
+ for(bezt=nu->bezt, a=0; a<nu->pntsu; a++, bezt++) {
+ if(bezt->f2 & SELECT)
+ bezt->weight= weight;
+ }
+ }
+ else if(nu->bp) {
+ for(bp=nu->bp, a=0; a<nu->pntsu*nu->pntsv; a++, bp++) {
+ if(bp->f1 & SELECT)
+ bp->weight= weight;
+ }
+ }
+ }
+ }
+ }
+ break;
+ case 4:
+ {
+ static float radius= 1.0f;
+ extern ListBase editNurb;
+ Nurb *nu;
+ BezTriple *bezt;
+ BPoint *bp;
+ int a;
+
+ if(fbutton(&radius, 0.0001f, 10.0f, 10, 10, "Set Radius")) {
+ for(nu= editNurb.first; nu; nu= nu->next) {
+ if(nu->bezt) {
+ for(bezt=nu->bezt, a=0; a<nu->pntsu; a++, bezt++) {
+ if(bezt->f2 & SELECT)
+ bezt->radius= radius;
+ }
+ }
+ else if(nu->bp) {
+ for(bp=nu->bp, a=0; a<nu->pntsu*nu->pntsv; a++, bp++) {
+ if(bp->f1 & SELECT)
+ bp->radius= radius;
+ }
+ }
+ }
+ }
+
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSALL, 0);
+ allqueue(REDRAWINFO, 1); /* 1, because header->win==0! */
+
+ }
+ break;
+ }
+
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ }
+ else if(G.obedit->type==OB_ARMATURE) {
+ nr= pupmenu("Specials%t|Subdivide %x1|Subdivide Multi%x2|Flip Left-Right Names%x3");
+ if(nr==1)
+ subdivide_armature(1);
+ if(nr==2) {
+ if(button(&numcuts, 1, 128, "Number of Cuts:")==0) return;
+ waitcursor(1);
+ subdivide_armature(numcuts);
+ }
+ else if(nr==3)
+ armature_flip_names();
+ }
+ else if(G.obedit->type==OB_LATTICE) {
+ static float weight= 1.0f;
+ if(fbutton(&weight, 0.0f, 1.0f, 10, 10, "Set Weight")) {
+ int a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
+ BPoint *bp= editLatt->def;
+
+ while(a--) {
+ if(bp->f1 & SELECT)
+ bp->weight= weight;
+ bp++;
+ }
+ }
+ }
+
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+
+}
+
+static void curvetomesh(Object *ob)
+{
+ Curve *cu;
+ DispList *dl;
+
+ ob->flag |= OB_DONE;
+ cu= ob->data;
+
+ dl= cu->disp.first;
+ if(dl==0) makeDispListCurveTypes(ob, 0); /* force creation */
+
+ nurbs_to_mesh(ob); /* also does users */
+ if (ob->type != OB_MESH) {
+ error("can't convert curve to mesh");
+ } else {
+ object_free_modifiers(ob);
+ }
+}
+
+void convertmenu(void)
+{
+ Base *base, *basen=NULL, *basact, *basedel=NULL;
+ Object *obact, *ob, *ob1;
+ Curve *cu;
+ Nurb *nu;
+ MetaBall *mb;
+ Mesh *me;
+ int ok=0, nr = 0, a;
+
+ if(G.scene->id.lib) return;
+
+ obact= OBACT;
+ if(obact==0) return;
+ if(!obact->flag & SELECT) return;
+ if(G.obedit) return;
+
+ basact= BASACT; /* will be restored */
+
+ if(obact->type==OB_FONT) {
+ nr= pupmenu("Convert Font to%t|Curve%x1|Curve (Single filling group)%x2|Mesh%x3");
+ if(nr>0) ok= 1;
+ }
+ else if(obact->type==OB_MBALL) {
+ nr= pupmenu("Convert Metaball to%t|Mesh (keep original)%x1|Mesh (Delete Original)%x2");
+ if(nr>0) ok= 1;
+ }
+ else if(obact->type==OB_CURVE) {
+ nr= pupmenu("Convert Curve to%t|Mesh");
+ if(nr>0) ok= 1;
+ }
+ else if(obact->type==OB_SURF) {
+ nr= pupmenu("Convert Nurbs Surface to%t|Mesh");
+ if(nr>0) ok= 1;
+ }
+ else if(obact->type==OB_MESH) {
+ nr= pupmenu("Convert Modifiers to%t|Mesh (Keep Original)%x1|Mesh (Delete Original)%x2");
+ if(nr>0) ok= 1;
+ }
+ if(ok==0) return;
+
+ /* don't forget multiple users! */
+
+ /* reset flags */
+ base= FIRSTBASE;
+ while(base) {
+ if TESTBASELIB(base) {
+ base->object->flag &= ~OB_DONE;
+ }
+ base= base->next;
+ }
+
+ base= FIRSTBASE;
+ while(base) {
+ if TESTBASELIB(base) {
+
+ ob= base->object;
+
+ if(ob->flag & OB_DONE);
+ else if(ob->type==OB_MESH && ob->modifiers.first) { /* converting a mesh with no modifiers causes a segfault */
+ DerivedMesh *dm;
+
+ basedel = base;
+
+ ob->flag |= OB_DONE;
+
+ ob1= copy_object(ob);
+ ob1->recalc |= OB_RECALC;
+
+ basen= MEM_mallocN(sizeof(Base), "duplibase");
+ *basen= *base;
+ BLI_addhead(&G.scene->base, basen); /* addhead: otherwise eternal loop */
+ basen->object= ob1;
+ basen->flag |= SELECT;
+ base->flag &= ~SELECT;
+ ob->flag &= ~SELECT;
+
+ /* decrement original mesh's usage count */
+ me= ob1->data;
+ me->id.us--;
+
+ /* make a new copy of the mesh */
+ ob1->data= copy_mesh(me);
+ G.totmesh++;
+
+ /* make new mesh data from the original copy */
+ dm= mesh_get_derived_final(ob1, CD_MASK_MESH);
+ /* dm= mesh_create_derived_no_deform(ob1, NULL); this was called original (instead of get_derived). man o man why! (ton) */
+
+ DM_to_mesh(dm, ob1->data);
+
+ dm->release(dm);
+ object_free_modifiers(ob1); /* after derivedmesh calls! */
+
+ /* If the original object is active then make this object active */
+ if (ob == obact) {
+ set_active_base( basen );
+ basact = basen;
+ }
+ }
+ else if(ob->type==OB_FONT) {
+ ob->flag |= OB_DONE;
+
+ ob->type= OB_CURVE;
+ cu= ob->data;
+
+ if(cu->vfont) {
+ cu->vfont->id.us--;
+ cu->vfont= 0;
+ }
+ if(cu->vfontb) {
+ cu->vfontb->id.us--;
+ cu->vfontb= 0;
+ }
+ if(cu->vfonti) {
+ cu->vfonti->id.us--;
+ cu->vfonti= 0;
+ }
+ if(cu->vfontbi) {
+ cu->vfontbi->id.us--;
+ cu->vfontbi= 0;
+ }
+ /* other users */
+ if(cu->id.us>1) {
+ ob1= G.main->object.first;
+ while(ob1) {
+ if(ob1->data==cu) {
+ ob1->type= OB_CURVE;
+ ob1->recalc |= OB_RECALC;
+ }
+ ob1= ob1->id.next;
+ }
+ }
+ if (nr==2 || nr==3) {
+ nu= cu->nurb.first;
+ while(nu) {
+ nu->charidx= 0;
+ nu= nu->next;
+ }
+ }
+ if (nr==3) {
+ curvetomesh(ob);
+ }
+ }
+ else if ELEM(ob->type, OB_CURVE, OB_SURF) {
+ if(nr==1) {
+ curvetomesh(ob);
+ }
+ }
+ else if(ob->type==OB_MBALL) {
+
+ if(nr==1 || nr == 2) {
+ ob= find_basis_mball(ob);
+
+ if(ob->disp.first && !(ob->flag&OB_DONE)) {
+ basedel = base;
+
+ ob->flag |= OB_DONE;
+
+ ob1= copy_object(ob);
+ ob1->recalc |= OB_RECALC;
+
+ basen= MEM_mallocN(sizeof(Base), "duplibase");
+ *basen= *base;
+ BLI_addhead(&G.scene->base, basen); /* addhead: othwise eternal loop */
+ basen->object= ob1;
+ basen->flag |= SELECT;
+ basedel->flag &= ~SELECT;
+ ob->flag &= ~SELECT;
+
+ mb= ob1->data;
+ mb->id.us--;
+
+ ob1->data= add_mesh("Mesh");
+ G.totmesh++;
+ ob1->type= OB_MESH;
+
+ me= ob1->data;
+ me->totcol= mb->totcol;
+ if(ob1->totcol) {
+ me->mat= MEM_dupallocN(mb->mat);
+ for(a=0; a<ob1->totcol; a++) id_us_plus((ID *)me->mat[a]);
+ }
+
+ mball_to_mesh(&ob->disp, ob1->data);
+
+ /* So we can see the wireframe */
+ BASACT= basen;
+
+ /* If the original object is active then make this object active */
+ if (ob == obact) {
+ set_active_base( basen );
+ basact = basen;
+ }
+
+ }
+ }
+ }
+ }
+ base= base->next;
+ if(basedel != NULL && nr == 2) {
+ if(basedel==basact)
+ basact= NULL;
+ free_and_unlink_base(basedel);
+ }
+ basedel = NULL;
+ }
+
+ /* texspace and normals */
+ if(!basen) BASACT= base;
+
+ enter_editmode(EM_WAITCURSOR);
+ exit_editmode(EM_FREEDATA|EM_WAITCURSOR); /* freedata, but no undo */
+ BASACT= basact;
+
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWOOPS, 0);
+ allspace(OOPS_TEST, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ BIF_undo_push("Convert Object");
+
+ DAG_scene_sort(G.scene);
+}
+
+ /* Change subdivision properties of mesh object ob, if
+ * level==-1 then toggle subsurf, else set to level.
+ * *set allows to toggle multiple selections
+ */
+static void object_flip_subdivison(Object *ob, int *set, int level, int mode)
+{
+ ModifierData *md;
+
+ if(ob->type!=OB_MESH)
+ return;
+
+ md = modifiers_findByType(ob, eModifierType_Subsurf);
+
+ if (md) {
+ SubsurfModifierData *smd = (SubsurfModifierData*) md;
+
+ if (level == -1) {
+ if(*set == -1)
+ *set= smd->modifier.mode&(mode);
+
+ if (*set) {
+ smd->modifier.mode &= ~(mode);
+ } else {
+ smd->modifier.mode |= (mode);
+ }
+ } else {
+ smd->levels = level;
+ }
+ }
+ else if(*set != 0) {
+ SubsurfModifierData *smd = (SubsurfModifierData*) modifier_new(eModifierType_Subsurf);
+
+ BLI_addtail(&ob->modifiers, smd);
+
+ if (level!=-1) {
+ smd->levels = level;
+ }
+
+ if(*set == -1)
+ *set= 1;
+ }
+ ob->recalc |= OB_RECALC_DATA;
+}
+
+/* Change subdivision properties of mesh object ob, if
+* level==-1 then toggle subsurf, else set to level.
+*/
+
+void flip_subdivison(int level)
+{
+ Base *base;
+ int set= -1;
+ int mode;
+
+ if(G.qual & LR_ALTKEY)
+ mode= eModifierMode_Realtime;
+ else
+ mode= eModifierMode_Render|eModifierMode_Realtime;
+
+ for(base= G.scene->base.first; base; base= base->next) {
+ if(((level==-1) && (TESTBASE(base))) || (TESTBASELIB(base))) {
+ object_flip_subdivison(base->object, &set, level, mode);
+ if(base->object->dup_group) {
+ GroupObject *go;
+ for(go= base->object->dup_group->gobject.first; go; go= go->next)
+ object_flip_subdivison(go->ob, &set, level, mode);
+ }
+ }
+ }
+
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWOOPS, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWBUTSOBJECT, 0);
+ DAG_scene_flush_update(G.scene, screen_view3d_layers());
+
+ BIF_undo_push("Switch subsurf on/off");
+}
+
+static void copymenu_properties(Object *ob)
+{
+ bProperty *prop, *propn, *propc;
+ Base *base;
+ int nr, tot=0;
+ char *str;
+
+ prop= ob->prop.first;
+ while(prop) {
+ tot++;
+ prop= prop->next;
+ }
+
+ if(tot==0) {
+ error("No properties in the active object to copy");
+ return;
+ }
+
+ str= MEM_callocN(24+32*tot, "copymenu prop");
+
+ strcpy(str, "Copy Property %t");
+
+ tot= 0;
+ prop= ob->prop.first;
+ while(prop) {
+ tot++;
+ strcat(str, " |");
+ strcat(str, prop->name);
+ prop= prop->next;
+ }
+
+ nr= pupmenu(str);
+ if(nr>0) {
+ tot= 0;
+ prop= ob->prop.first;
+ while(prop) {
+ tot++;
+ if(tot==nr) break;
+ prop= prop->next;
+ }
+ if(prop) {
+ propc= prop;
+
+ base= FIRSTBASE;
+ while(base) {
+ if(base != BASACT) {
+ if(TESTBASELIB(base)) {
+ prop= get_property(base->object, propc->name);
+ if(prop) {
+ free_property(prop);
+ BLI_remlink(&base->object->prop, prop);
+ }
+ propn= copy_property(propc);
+ BLI_addtail(&base->object->prop, propn);
+ }
+ }
+ base= base->next;
+ }
+ }
+ }
+ MEM_freeN(str);
+ allqueue(REDRAWVIEW3D, 0);
+
+ BIF_undo_push("Copy properties");
+}
+
+static void copymenu_logicbricks(Object *ob)
+{
+ Base *base;
+
+ base= FIRSTBASE;
+ while(base) {
+ if(base->object != ob) {
+ if(TESTBASELIB(base)) {
+
+ /* first: free all logic */
+ free_sensors(&base->object->sensors);
+ unlink_controllers(&base->object->controllers);
+ free_controllers(&base->object->controllers);
+ unlink_actuators(&base->object->actuators);
+ free_actuators(&base->object->actuators);
+
+ /* now copy it, this also works without logicbricks! */
+ clear_sca_new_poins_ob(ob);
+ copy_sensors(&base->object->sensors, &ob->sensors);
+ copy_controllers(&base->object->controllers, &ob->controllers);
+ copy_actuators(&base->object->actuators, &ob->actuators);
+ set_sca_new_poins_ob(base->object);
+
+ /* some menu settings */
+ base->object->scavisflag= ob->scavisflag;
+ base->object->scaflag= ob->scaflag;
+
+ }
+ }
+ base= base->next;
+ }
+ BIF_undo_push("Copy logic");
+}
+
+static void copymenu_modifiers(Object *ob)
+{
+ Base *base;
+ int i, event;
+ char str[512];
+ char *errorstr= NULL;
+
+ strcpy(str, "Copy Modifiers %t");
+
+ sprintf(str+strlen(str), "|All%%x%d|%%l", NUM_MODIFIER_TYPES);
+
+ for (i=eModifierType_None+1; i<NUM_MODIFIER_TYPES; i++) {
+ ModifierTypeInfo *mti = modifierType_getInfo(i);
+
+ if (ELEM(i, eModifierType_Hook, eModifierType_Softbody)) continue;
+
+ if ( (mti->flags&eModifierTypeFlag_AcceptsCVs) ||
+ (ob->type==OB_MESH && (mti->flags&eModifierTypeFlag_AcceptsMesh))) {
+ sprintf(str+strlen(str), "|%s%%x%d", mti->name, i);
+ }
+ }
+
+ event = pupmenu(str);
+ if(event<=0) return;
+
+ for (base= FIRSTBASE; base; base= base->next) {
+ if(base->object != ob) {
+ if(TESTBASELIB(base)) {
+ ModifierData *md;
+
+ base->object->recalc |= OB_RECALC_OB|OB_RECALC_DATA;
+
+ if (base->object->type==ob->type) {
+ /* copy all */
+ if (event==NUM_MODIFIER_TYPES) {
+ object_free_modifiers(base->object);
+
+ for (md=ob->modifiers.first; md; md=md->next) {
+ if (md->type!=eModifierType_Hook) {
+ ModifierData *nmd = modifier_new(md->type);
+ modifier_copyData(md, nmd);
+ BLI_addtail(&base->object->modifiers, nmd);
+ }
+ }
+ } else {
+ /* copy specific types */
+ ModifierData *md, *mdn;
+
+ /* remove all with type 'event' */
+ for (md=base->object->modifiers.first; md; md=mdn) {
+ mdn= md->next;
+ if(md->type==event) {
+ BLI_remlink(&base->object->modifiers, md);
+ modifier_free(md);
+ }
+ }
+
+ /* copy all with type 'event' */
+ for (md=ob->modifiers.first; md; md=md->next) {
+ if (md->type==event) {
+
+ mdn = modifier_new(event);
+ BLI_addtail(&base->object->modifiers, mdn);
+
+ modifier_copyData(md, mdn);
+ }
+ }
+ }
+ }
+ else
+ errorstr= "Did not copy modifiers to other Object types";
+ }
+ }
+ }
+
+ if(errorstr) notice(errorstr);
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSOBJECT, 0);
+ DAG_scene_sort(G.scene);
+
+ BIF_undo_push("Copy modifiers");
+}
+
+/* both pointers should exist */
+static void copy_texture_space(Object *to, Object *ob)
+{
+ float *poin1= NULL, *poin2= NULL;
+ int texflag= 0;
+
+ if(ob->type==OB_MESH) {
+ texflag= ((Mesh *)ob->data)->texflag;
+ poin2= ((Mesh *)ob->data)->loc;
+ }
+ else if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
+ texflag= ((Curve *)ob->data)->texflag;
+ poin2= ((Curve *)ob->data)->loc;
+ }
+ else if(ob->type==OB_MBALL) {
+ texflag= ((MetaBall *)ob->data)->texflag;
+ poin2= ((MetaBall *)ob->data)->loc;
+ }
+ else
+ return;
+
+ if(to->type==OB_MESH) {
+ ((Mesh *)to->data)->texflag= texflag;
+ poin1= ((Mesh *)to->data)->loc;
+ }
+ else if (ELEM3(to->type, OB_CURVE, OB_SURF, OB_FONT)) {
+ ((Curve *)to->data)->texflag= texflag;
+ poin1= ((Curve *)to->data)->loc;
+ }
+ else if(to->type==OB_MBALL) {
+ ((MetaBall *)to->data)->texflag= texflag;
+ poin1= ((MetaBall *)to->data)->loc;
+ }
+ else
+ return;
+
+ memcpy(poin1, poin2, 9*sizeof(float)); /* this was noted in DNA_mesh, curve, mball */
+
+ if(to->type==OB_MESH) ;
+ else if(to->type==OB_MBALL) tex_space_mball(to);
+ else tex_space_curve(to->data);
+
+}
+
+void copy_attr(short event)
+{
+ Object *ob;
+ Base *base;
+ Curve *cu, *cu1;
+ Nurb *nu;
+ int do_scene_sort= 0;
+
+ if(G.scene->id.lib) return;
+
+ if(!(ob=OBACT)) return;
+
+ if(G.obedit) {
+ /* obedit_copymenu(); */
+ return;
+ }
+ if(event==9) {
+ copymenu_properties(ob);
+ return;
+ }
+ else if(event==10) {
+ copymenu_logicbricks(ob);
+ return;
+ }
+ else if(event==24) {
+ copymenu_modifiers(ob);
+ return;
+ }
+
+ base= FIRSTBASE;
+ while(base) {
+ if(base != BASACT) {
+ if(TESTBASELIB(base)) {
+ base->object->recalc |= OB_RECALC_OB;
+
+ if(event==1) { /* loc */
+ VECCOPY(base->object->loc, ob->loc);
+ VECCOPY(base->object->dloc, ob->dloc);
+ }
+ else if(event==2) { /* rot */
+ VECCOPY(base->object->rot, ob->rot);
+ VECCOPY(base->object->drot, ob->drot);
+ VECCOPY(base->object->quat, ob->quat);
+ VECCOPY(base->object->dquat, ob->dquat);
+ }
+ else if(event==3) { /* size */
+ VECCOPY(base->object->size, ob->size);
+ VECCOPY(base->object->dsize, ob->dsize);
+ }
+ else if(event==4) { /* drawtype */
+ base->object->dt= ob->dt;
+ base->object->dtx= ob->dtx;
+ base->object->empty_drawtype= ob->empty_drawtype;
+ base->object->empty_drawsize= ob->empty_drawsize;
+ }
+ else if(event==5) { /* time offs */
+ base->object->sf= ob->sf;
+ }
+ else if(event==6) { /* dupli */
+ base->object->dupon= ob->dupon;
+ base->object->dupoff= ob->dupoff;
+ base->object->dupsta= ob->dupsta;
+ base->object->dupend= ob->dupend;
+
+ base->object->transflag &= ~OB_DUPLI;
+ base->object->transflag |= (ob->transflag & OB_DUPLI);
+
+ base->object->dup_group= ob->dup_group;
+ if(ob->dup_group)
+ id_us_plus((ID *)ob->dup_group);
+ }
+ else if(event==7) { /* mass */
+ base->object->mass= ob->mass;
+ }
+ else if(event==8) { /* damping */
+ base->object->damping= ob->damping;
+ base->object->rdamping= ob->rdamping;
+ }
+ else if(event==17) { /* tex space */
+ copy_texture_space(base->object, ob);
+ }
+ else if(event==18) { /* font settings */
+
+ if(base->object->type==ob->type) {
+ cu= ob->data;
+ cu1= base->object->data;
+
+ cu1->spacemode= cu->spacemode;
+ cu1->spacing= cu->spacing;
+ cu1->linedist= cu->linedist;
+ cu1->shear= cu->shear;
+ cu1->fsize= cu->fsize;
+ cu1->xof= cu->xof;
+ cu1->yof= cu->yof;
+ cu1->textoncurve= cu->textoncurve;
+ cu1->wordspace= cu->wordspace;
+ cu1->ulpos= cu->ulpos;
+ cu1->ulheight= cu->ulheight;
+ if(cu1->vfont) cu1->vfont->id.us--;
+ cu1->vfont= cu->vfont;
+ id_us_plus((ID *)cu1->vfont);
+ if(cu1->vfontb) cu1->vfontb->id.us--;
+ cu1->vfontb= cu->vfontb;
+ id_us_plus((ID *)cu1->vfontb);
+ if(cu1->vfonti) cu1->vfonti->id.us--;
+ cu1->vfonti= cu->vfonti;
+ id_us_plus((ID *)cu1->vfonti);
+ if(cu1->vfontbi) cu1->vfontbi->id.us--;
+ cu1->vfontbi= cu->vfontbi;
+ id_us_plus((ID *)cu1->vfontbi);
+
+ text_to_curve(base->object, 0); /* needed? */
+
+
+ strcpy(cu1->family, cu->family);
+
+ base->object->recalc |= OB_RECALC_DATA;
+ }
+ }
+ else if(event==19) { /* bevel settings */
+
+ if ELEM(base->object->type, OB_CURVE, OB_FONT) {
+ cu= ob->data;
+ cu1= base->object->data;
+
+ cu1->bevobj= cu->bevobj;
+ cu1->taperobj= cu->taperobj;
+ cu1->width= cu->width;
+ cu1->bevresol= cu->bevresol;
+ cu1->ext1= cu->ext1;
+ cu1->ext2= cu->ext2;
+
+ base->object->recalc |= OB_RECALC_DATA;
+ }
+ }
+ else if(event==25) { /* curve resolution */
+
+ if ELEM(base->object->type, OB_CURVE, OB_FONT) {
+ cu= ob->data;
+ cu1= base->object->data;
+
+ cu1->resolu= cu->resolu;
+ cu1->resolu_ren= cu->resolu_ren;
+
+ nu= cu1->nurb.first;
+
+ while(nu) {
+ nu->resolu= cu1->resolu;
+ nu= nu->next;
+ }
+
+ base->object->recalc |= OB_RECALC_DATA;
+ }
+ }
+ else if(event==20) { /* particle settings */
+ PartEff *pa1, *pa2;
+ char *p1, *p2;
+
+ pa1= give_parteff(ob);
+ pa2= give_parteff(base->object);
+
+ if(pa1==0 && pa2) {
+ BLI_remlink( &(base->object->effect), pa2);
+ free_effect( (Effect *) pa2);
+ }
+ else if(pa1 && pa2==0) {
+ free_effects(&(base->object->effect));
+ copy_effects(&(base->object->effect), &ob->effect);
+ build_particle_system(base->object);
+ }
+ else if(pa1 && pa2) {
+ if(pa2->keys) MEM_freeN(pa2->keys);
+
+ p1= (char *)pa1; p2= (char *)pa2;
+ memcpy( p2+8, p1+8, sizeof(PartEff) - 8);
+ pa2->keys= 0;
+
+ build_particle_system(base->object);
+ }
+ }
+ else if(event==21){
+ if (base->object->type==OB_MESH) {
+ ModifierData *md = modifiers_findByType(ob, eModifierType_Subsurf);
+
+ if (md) {
+ ModifierData *tmd = modifiers_findByType(base->object, eModifierType_Subsurf);
+
+ if (!tmd) {
+ tmd = modifier_new(eModifierType_Subsurf);
+ BLI_addtail(&base->object->modifiers, tmd);
+ }
+
+ modifier_copyData(md, tmd);
+ base->object->recalc |= OB_RECALC_DATA;
+ }
+ }
+ }
+ else if(event==22) {
+ /* Clear the constraints on the target */
+ free_constraints(&base->object->constraints);
+ free_constraint_channels(&base->object->constraintChannels);
+
+ /* Copy the constraint channels over */
+ copy_constraints(&base->object->constraints, &ob->constraints);
+ if (U.dupflag& USER_DUP_IPO)
+ copy_constraint_channels(&base->object->constraintChannels, &ob->constraintChannels);
+ else
+ clone_constraint_channels (&base->object->constraintChannels, &ob->constraintChannels);
+
+ do_scene_sort= 1;
+ }
+ else if(event==23) {
+ base->object->softflag= ob->softflag;
+ if(base->object->soft) sbFree(base->object->soft);
+
+ base->object->soft= copy_softbody(ob->soft);
+
+ if (!modifiers_findByType(base->object, eModifierType_Softbody)) {
+ BLI_addhead(&base->object->modifiers, modifier_new(eModifierType_Softbody));
+ }
+ }
+ else if(event==26) {
+ copy_nlastrips(&base->object->nlastrips, &ob->nlastrips);
+ }
+ else if(event==27) { /* autosmooth */
+ if (base->object->type==OB_MESH) {
+ Mesh *me= ob->data;
+ Mesh *cme= base->object->data;
+ cme->smoothresh= me->smoothresh;
+ if(me->flag & ME_AUTOSMOOTH)
+ cme->flag |= ME_AUTOSMOOTH;
+ else
+ cme->flag &= ~ME_AUTOSMOOTH;
+ }
+ }
+ else if(event==28) { /* UV orco */
+ if ELEM(base->object->type, OB_CURVE, OB_SURF) {
+ cu= ob->data;
+ cu1= base->object->data;
+
+ if(cu->flag & CU_UV_ORCO)
+ cu1->flag |= CU_UV_ORCO;
+ else
+ cu1->flag &= ~CU_UV_ORCO;
+ }
+ }
+ else if(event==29) { /* protected bits */
+ base->object->protectflag= ob->protectflag;
+ }
+ else if(event==30) { /* index object */
+ base->object->index= ob->index;
+ }
+ }
+ }
+ base= base->next;
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+ if(do_scene_sort)
+ DAG_scene_sort(G.scene);
+
+ DAG_scene_flush_update(G.scene, screen_view3d_layers());
+
+ if(event==20) {
+ allqueue(REDRAWBUTSOBJECT, 0);
+ }
+
+ BIF_undo_push("Copy Attributes");
+}
+
+void copy_attr_menu()
+{
+ Object *ob;
+ short event;
+ char str[512];
+
+ if(!(ob=OBACT)) return;
+
+ if (G.obedit) {
+ if (ob->type == OB_MESH)
+ mesh_copy_menu();
+ return;
+ }
+
+ /* Object Mode */
+
+ /* If you change this menu, don't forget to update the menu in header_view3d.c
+ * view3d_edit_object_copyattrmenu() and in toolbox.c
+ */
+
+ strcpy(str, "Copy Attributes %t|Location%x1|Rotation%x2|Size%x3|Draw Options%x4|Time Offset%x5|Dupli%x6|%l|Mass%x7|Damping%x8|Properties%x9|Logic Bricks%x10|Protected Transform%x29|%l");
+
+ strcat (str, "|Object Constraints%x22");
+ strcat (str, "|NLA Strips%x26");
+
+ if ELEM5(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL) {
+ strcat(str, "|Texture Space%x17");
+ }
+
+ if(ob->type == OB_FONT) strcat(str, "|Font Settings%x18|Bevel Settings%x19");
+ if(ob->type == OB_CURVE) strcat(str, "|Bevel Settings%x19|UV Orco%x28");
+
+ if((ob->type == OB_FONT) || (ob->type == OB_CURVE)) {
+ strcat(str, "|Curve Resolution%x25");
+ }
+
+ if(ob->type==OB_MESH){
+ strcat(str, "|Subsurf Settings%x21|AutoSmooth%x27");
+ }
+
+ if( give_parteff(ob) ) strcat(str, "|Particle Settings%x20");
+
+ if(ob->soft) strcat(str, "|Soft Body Settings%x23");
+
+ strcat(str, "|Pass Index%x30");
+
+ if(ob->type==OB_MESH || ob->type==OB_CURVE || ob->type==OB_LATTICE || ob->type==OB_SURF){
+ strcat(str, "|Modifiers ...%x24");
+ }
+
+ event= pupmenu(str);
+ if(event<= 0) return;
+
+ copy_attr(event);
+}
+
+
+void link_to_scene(unsigned short nr)
+{
+ Scene *sce= (Scene*) BLI_findlink(&G.main->scene, G.curscreen->scenenr-1);
+ Base *base, *nbase;
+
+ if(sce==0) return;
+ if(sce->id.lib) return;
+
+ base= FIRSTBASE;
+ while(base) {
+ if(TESTBASE(base)) {
+
+ nbase= MEM_mallocN( sizeof(Base), "newbase");
+ *nbase= *base;
+ BLI_addhead( &(sce->base), nbase);
+ id_us_plus((ID *)base->object);
+ }
+ base= base->next;
+ }
+}
+
+void make_links_menu()
+{
+ Object *ob;
+ short event=0;
+ char str[140];
+
+ if(!(ob=OBACT)) return;
+
+ strcpy(str, "Make Links %t|To Scene...%x1|%l|Object Ipo%x4");
+
+ if(ob->type==OB_MESH)
+ strcat(str, "|Mesh Data%x2|Materials%x3");
+ else if(ob->type==OB_CURVE)
+ strcat(str, "|Curve Data%x2|Materials%x3");
+ else if(ob->type==OB_FONT)
+ strcat(str, "|Text Data%x2|Materials%x3");
+ else if(ob->type==OB_SURF)
+ strcat(str, "|Surface Data%x2|Materials%x3");
+ else if(ob->type==OB_MBALL)
+ strcat(str, "|Materials%x3");
+ else if(ob->type==OB_CAMERA)
+ strcat(str, "|Camera Data%x2");
+ else if(ob->type==OB_LAMP)
+ strcat(str, "|Lamp Data%x2");
+ else if(ob->type==OB_LATTICE)
+ strcat(str, "|Lattice Data%x2");
+ else if(ob->type==OB_ARMATURE)
+ strcat(str, "|Armature Data%x2");
+
+ event= pupmenu(str);
+
+ if(event<= 0) return;
+
+ make_links(event);
+}
+
+void make_links(short event)
+{
+ Object *ob, *obt;
+ Base *base, *nbase, *sbase;
+ Scene *sce = NULL;
+ ID *id;
+ int a;
+ short nr=0;
+ char *strp;
+
+ if(!(ob=OBACT)) return;
+
+ if(event==1) {
+ IDnames_to_pupstring(&strp, NULL, NULL, &(G.main->scene), 0, &nr);
+
+ if(nr == -2) {
+ MEM_freeN(strp);
+
+ activate_databrowse((ID *)G.scene, ID_SCE, 0, B_INFOSCE, &(G.curscreen->scenenr), link_to_scene );
+
+ return;
+ }
+ else {
+ event= pupmenu_col(strp, 20);
+ MEM_freeN(strp);
+
+ if(event<= 0) return;
+
+ nr= 1;
+ sce= G.main->scene.first;
+ while(sce) {
+ if(nr==event) break;
+ nr++;
+ sce= sce->id.next;
+ }
+ if(sce==G.scene) {
+ error("This is the current scene");
+ return;
+ }
+ if(sce==0 || sce->id.lib) return;
+
+ /* remember: is needed below */
+ event= 1;
+ }
+ }
+
+ /* All non group linking */
+ base= FIRSTBASE;
+ while(base) {
+ if(event==1 || base != BASACT) {
+
+ obt= base->object;
+
+ if(TESTBASE(base)) {
+
+ if(event==1) { /* to scene */
+
+ /* test if already linked */
+ sbase= sce->base.first;
+ while(sbase) {
+ if(sbase->object==base->object) break;
+ sbase= sbase->next;
+ }
+ if(sbase) { /* remove */
+ base= base->next;
+ continue;
+ }
+
+ nbase= MEM_mallocN( sizeof(Base), "newbase");
+ *nbase= *base;
+ BLI_addhead( &(sce->base), nbase);
+ id_us_plus((ID *)base->object);
+ }
+ }
+ if(TESTBASELIB(base)) {
+ if(event==2 || event==5) { /* obdata */
+ if(ob->type==obt->type) {
+
+ id= obt->data;
+ id->us--;
+
+ id= ob->data;
+ id_us_plus(id);
+ obt->data= id;
+
+ /* if amount of material indices changed: */
+ test_object_materials(obt->data);
+
+ obt->recalc |= OB_RECALC_DATA;
+ }
+ }
+ else if(event==4) { /* ob ipo */
+ if(obt->ipo) obt->ipo->id.us--;
+ obt->ipo= ob->ipo;
+ if(obt->ipo) {
+ id_us_plus((ID *)obt->ipo);
+ do_ob_ipo(obt);
+ }
+ }
+ else if(event==6) {
+ if(ob->dup_group) ob->dup_group->id.us--;
+ obt->dup_group= ob->dup_group;
+ if(obt->dup_group) {
+ id_us_plus((ID *)obt->dup_group);
+ obt->transflag |= OB_DUPLIGROUP;
+ }
+ }
+ else if(event==3) { /* materials */
+
+ /* new approach, using functions from kernel */
+ for(a=0; a<ob->totcol; a++) {
+ Material *ma= give_current_material(ob, a+1);
+ assign_material(obt, ma, a+1); /* also works with ma==NULL */
+ }
+ }
+ }
+ }
+ base= base->next;
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWOOPS, 0);
+ allqueue(REDRAWBUTSHEAD, 0);
+
+ DAG_scene_flush_update(G.scene, screen_view3d_layers());
+
+ BIF_undo_push("Create links");
+}
+
+void apply_object()
+{
+ Base *base, *basact;
+ Object *ob;
+ Mesh *me;
+ Curve *cu;
+ Nurb *nu;
+ BPoint *bp;
+ BezTriple *bezt;
+ MVert *mvert;
+ float mat[3][3];
+ int a;
+
+ if(G.scene->id.lib) return;
+ if(G.obedit) return;
+ basact= BASACT;
+
+ if(G.qual & LR_SHIFTKEY) {
+ ob= OBACT;
+ if(ob==0) return;
+
+ if(ob->transflag & OB_DUPLI) {
+ make_duplilist_real();
+ }
+ else {
+ if(okee("Apply deformation")) {
+ object_apply_deform(ob);
+ BIF_undo_push("Apply deformation");
+ }
+ }
+ allqueue(REDRAWVIEW3D, 0);
+
+ return;
+ }
+
+ if(okee("Apply scale and rotation")==0) return;
+
+ base= FIRSTBASE;
+ while(base) {
+ if TESTBASELIB(base) {
+ ob= base->object;
+
+ if(ob->type==OB_MESH) {
+ object_to_mat3(ob, mat);
+ me= ob->data;
+
+ if(me->id.us>1) {
+ error("Can't apply to a multi user mesh");
+ return;
+ }
+ if(me->key) {
+ error("Can't apply to a mesh with vertex keys");
+ return;
+ }
+
+ mvert= me->mvert;
+ for(a=0; a<me->totvert; a++, mvert++) {
+ Mat3MulVecfl(mat, mvert->co);
+ }
+ ob->size[0]= ob->size[1]= ob->size[2]= 1.0;
+ ob->rot[0]= ob->rot[1]= ob->rot[2]= 0.0;
+ QuatOne(ob->quat);
+
+ where_is_object(ob);
+
+ /* texspace and normals */
+ BASACT= base;
+ enter_editmode(EM_WAITCURSOR);
+ BIF_undo_push("Applied object"); /* editmode undo itself */
+ exit_editmode(EM_FREEDATA|EM_WAITCURSOR); /* freedata, but no undo */
+ BASACT= basact;
+
+ }
+ else if (ob->type==OB_ARMATURE){
+ bArmature *arm;
+
+ object_to_mat3(ob, mat);
+ arm= ob->data;
+ if(arm->id.us>1) {
+ error("Can't apply to a multi user armature");
+ return;
+ }
+
+ apply_rot_armature (ob, mat);
+ /* Reset the object's transforms */
+ ob->size[0]= ob->size[1]= ob->size[2]= 1.0;
+ ob->rot[0]= ob->rot[1]= ob->rot[2]= 0.0;
+ QuatOne(ob->quat);
+
+ where_is_object(ob);
+ }
+ else if ELEM(ob->type, OB_CURVE, OB_SURF) {
+ float scale;
+ object_to_mat3(ob, mat);
+ scale = Mat3ToScalef(mat);
+ cu= ob->data;
+
+ if(cu->id.us>1) {
+ error("Can't apply to a multi user curve");
+ return;
+ }
+ if(cu->key) {
+ error("Can't apply to a curve with vertex keys");
+ return;
+ }
+
+ nu= cu->nurb.first;
+ while(nu) {
+ if( (nu->type & 7)==1) {
+ a= nu->pntsu;
+ bezt= nu->bezt;
+ while(a--) {
+ Mat3MulVecfl(mat, bezt->vec[0]);
+ Mat3MulVecfl(mat, bezt->vec[1]);
+ Mat3MulVecfl(mat, bezt->vec[2]);
+ bezt->radius *= scale;
+ bezt++;
+ }
+ }
+ else {
+ a= nu->pntsu*nu->pntsv;
+ bp= nu->bp;
+ while(a--) {
+ Mat3MulVecfl(mat, bp->vec);
+ bp++;
+ }
+ }
+ nu= nu->next;
+ }
+
+ ob->size[0]= ob->size[1]= ob->size[2]= 1.0;
+ ob->rot[0]= ob->rot[1]= ob->rot[2]= 0.0;
+ QuatOne(ob->quat);
+
+ where_is_object(ob);
+
+ /* texspace and normals */
+ BASACT= base;
+ enter_editmode(EM_WAITCURSOR);
+ BIF_undo_push("Applied object"); /* editmode undo itself */
+ exit_editmode(EM_FREEDATA|EM_WAITCURSOR); /* freedata, but no undo */
+ BASACT= basact;
+ }
+ }
+ base= base->next;
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+ BIF_undo_push("Apply object");
+}
+
+
+
+/* ************ GENERAL *************** */
+
+
+/* now only used in 2d spaces, like ipo, nla, sima... */
+void apply_keyb_grid(float *val, float fac1, float fac2, float fac3, int invert)
+{
+ /* fac1 is for 'nothing', fac2 for CTRL, fac3 for SHIFT */
+ int ctrl;
+
+ if(invert) {
+ if(G.qual & LR_CTRLKEY) ctrl= 0;
+ else ctrl= 1;
+ }
+ else ctrl= (G.qual & LR_CTRLKEY);
+
+ if(ctrl && (G.qual & LR_SHIFTKEY)) {
+ if(fac3!= 0.0) *val= fac3*floor(*val/fac3 +.5);
+ }
+ else if(ctrl) {
+ if(fac2!= 0.0) *val= fac2*floor(*val/fac2 +.5);
+ }
+ else {
+ if(fac1!= 0.0) *val= fac1*floor(*val/fac1 +.5);
+ }
+}
+
+int cylinder_intersect_test(void)
+{
+ EditMesh *em = G.editMesh;
+ float *oldloc, speed[3], s, t, labda, labdacor, dist, len, len2, axis[3], *base, rc[3], n[3], o[3];
+ EditVert *v1;
+
+ v1= em->verts.first;
+
+ base= v1->co;
+ v1= v1->next;
+ VecSubf(axis, v1->co, base);
+
+ v1= v1->next;
+ oldloc= v1->co;
+ v1= v1->next;
+ VecSubf(speed, v1->co, oldloc);
+
+ VecSubf(rc, oldloc, base);
+
+ /* the axis */
+ len2= Normalize(axis);
+
+ Crossf(n, speed, axis);
+ len= Normalize(n);
+ if(len==0.0) return 0;
+
+ dist= fabs( rc[0]*n[0] + rc[1]*n[1] + rc[2]*n[2] );
+
+ if( dist>=G.scene->editbutsize ) return 0;
+
+ Crossf(o, rc, axis);
+ t= -(o[0]*n[0] + o[1]*n[1] + o[2]*n[2])/len;
+
+ Crossf(o, n, axis);
+ s= fabs(sqrt(G.scene->editbutsize*G.scene->editbutsize-dist*dist) / (o[0]*speed[0] + o[1]*speed[1] + o[2]*speed[2]));
+
+ labdacor= t-s;
+ labda= t+s;
+
+ /* two cases with no intersection point */
+ if(labdacor>=1.0 && labda>=1.0) return 0;
+ if(labdacor<=0.0 && labda<=0.0) return 0;
+
+ /* calc normal */
+ /* intersection: */
+
+ rc[0]= oldloc[0] + labdacor*speed[0] - base[0];
+ rc[1]= oldloc[1] + labdacor*speed[1] - base[1];
+ rc[2]= oldloc[2] + labdacor*speed[2] - base[2];
+
+ s= (rc[0]*axis[0] + rc[1]*axis[1] + rc[2]*axis[2]) ;
+
+ if(s<0.0 || s>len2) return 0;
+
+ n[0]= (rc[0] - s*axis[0]);
+ n[1]= (rc[1] - s*axis[1]);
+ n[2]= (rc[2] - s*axis[2]);
+
+ printf("var1: %f, var2: %f, var3: %f\n", labdacor, len2, s);
+ printf("var1: %f, var2: %f, var3: %f\n", rc[0], rc[1], rc[2]);
+ printf("var1: %f, var2: %f, var3: %f\n", n[0], n[1], n[2]);
+
+ return 1;
+}
+
+int sphere_intersect_test(void)
+{
+ EditMesh *em = G.editMesh;
+ float *oldloc, speed[3], labda, labdacor, len, bsq, u, disc, *base, rc[3];
+ EditVert *v1;
+
+ v1= em->verts.first;
+ base= v1->co;
+
+ v1= v1->next;
+ oldloc= v1->co;
+
+ v1= v1->next;
+ VecSubf(speed, v1->co, oldloc);
+ len= Normalize(speed);
+ if(len==0.0) return 0;
+
+ VecSubf(rc, oldloc, base);
+ bsq= rc[0]*speed[0] + rc[1]*speed[1] + rc[2]*speed[2];
+ u= rc[0]*rc[0] + rc[1]*rc[1] + rc[2]*rc[2] - G.scene->editbutsize*G.scene->editbutsize;
+
+ disc= bsq*bsq - u;
+
+ if(disc>=0.0) {
+ disc= sqrt(disc);
+ labdacor= (-bsq - disc)/len; /* entry point */
+ labda= (-bsq + disc)/len;
+
+ printf("var1: %f, var2: %f, var3: %f\n", labdacor, labda, G.scene->editbutsize);
+ }
+ else return 0;
+
+ /* intersection and normal */
+ rc[0]= oldloc[0] + labdacor*speed[0] - base[0];
+ rc[1]= oldloc[1] + labdacor*speed[1] - base[1];
+ rc[2]= oldloc[2] + labdacor*speed[2] - base[2];
+
+
+ return 1;
+}
+
+
+void std_rmouse_transform(void (*xf_func)(int, int))
+{
+ short mval[2];
+ short xo, yo;
+ short timer=0;
+ short mousebut;
+
+ /* check for left mouse select/right mouse select */
+
+ if(curarea->spacetype==SPACE_NODE)
+ mousebut = L_MOUSE|R_MOUSE;
+ else if (U.flag & USER_LMOUSESELECT)
+ mousebut = L_MOUSE;
+ else
+ mousebut = R_MOUSE;
+
+ getmouseco_areawin(mval);
+ xo= mval[0];
+ yo= mval[1];
+
+ while(get_mbut() & mousebut) {
+ getmouseco_areawin(mval);
+ if(abs(mval[0]-xo)+abs(mval[1]-yo) > 10) {
+ if(curarea->spacetype==SPACE_VIEW3D) {
+#ifdef TWEAK_MODE
+ initTransform(TFM_TRANSLATION, CTX_TWEAK);
+#else
+ initTransform(TFM_TRANSLATION, CTX_NONE);
+#endif
+ Transform();
+ }
+ else if(curarea->spacetype==SPACE_IMAGE) {
+ initTransform(TFM_TRANSLATION, CTX_NONE);
+ Transform();
+ }
+ else if(xf_func)
+ xf_func('g', 0);
+
+ while(get_mbut() & mousebut) BIF_wait_for_statechange();
+ return;
+ }
+ else {
+ PIL_sleep_ms(10);
+ timer++;
+ if(timer>=10*U.tb_rightmouse) {
+ if(curarea->spacetype==SPACE_VIEW3D) {
+ toolbox_n();
+ return;
+ }
+ }
+ }
+ }
+ /* if gets here it's a select */
+ BIF_undo_push("Select");
+}
+
+void rightmouse_transform(void)
+{
+ std_rmouse_transform(NULL);
+}
+
+
+/* ************************************** */
+
+
+static void single_object_users__forwardModifierLinks(void *userData, Object *ob, Object **obpoin)
+{
+ ID_NEW(*obpoin);
+}
+void single_object_users(int flag)
+{
+ Base *base;
+ Object *ob, *obn;
+
+ clear_sca_new_poins(); /* sensor/contr/act */
+
+ /* duplicate */
+ base= FIRSTBASE;
+ while(base) {
+ ob= base->object;
+
+ if( (base->flag & flag)==flag) {
+
+ if(ob->id.lib==NULL && ob->id.us>1) {
+
+ obn= copy_object(ob);
+ ob->id.us--;
+ base->object= obn;
+ }
+ }
+ base= base->next;
+ }
+
+ ID_NEW(G.scene->camera);
+ if(G.vd) ID_NEW(G.vd->camera);
+
+ /* object pointers */
+ base= FIRSTBASE;
+ while(base) {
+ ob= base->object;
+ if(ob->id.lib==NULL) {
+ if( (base->flag & flag)==flag) {
+
+ relink_constraints(&base->object->constraints);
+ if (base->object->pose){
+ bPoseChannel *chan;
+ for (chan = base->object->pose->chanbase.first; chan; chan=chan->next){
+ relink_constraints(&chan->constraints);
+ }
+ }
+ modifiers_foreachObjectLink(base->object, single_object_users__forwardModifierLinks, NULL);
+
+ ID_NEW(ob->parent);
+ ID_NEW(ob->track);
+ }
+ }
+ base= base->next;
+ }
+
+ set_sca_new_poins();
+}
+
+void new_id_matar(Material **matar, int totcol)
+{
+ ID *id;
+ int a;
+
+ for(a=0; a<totcol; a++) {
+ id= (ID *)matar[a];
+ if(id && id->lib==0) {
+ if(id->newid) {
+ matar[a]= (Material *)id->newid;
+ id_us_plus(id->newid);
+ id->us--;
+ }
+ else if(id->us>1) {
+ matar[a]= copy_material(matar[a]);
+ id->us--;
+ id->newid= (ID *)matar[a];
+ }
+ }
+ }
+}
+
+void single_obdata_users(int flag)
+{
+ Object *ob;
+ Lamp *la;
+ Curve *cu;
+ Camera *cam;
+ Base *base;
+ Mesh *me;
+ ID *id;
+ int a;
+
+#ifdef WITH_VERSE
+ base= FIRSTBASE;
+ while(base) {
+ ob= base->object;
+ if(ob->vnode) {
+ error("Can't make data single user, when data are shared at verse server");
+ return;
+ }
+ base = base->next;
+ }
+#endif
+
+ base= FIRSTBASE;
+ while(base) {
+ ob= base->object;
+ if(ob->id.lib==NULL && (base->flag & flag)==flag ) {
+ id= ob->data;
+
+ if(id && id->us>1 && id->lib==0) {
+ ob->recalc= OB_RECALC_DATA;
+
+ switch(ob->type) {
+ case OB_LAMP:
+ if(id && id->us>1 && id->lib==NULL) {
+ ob->data= la= copy_lamp(ob->data);
+ for(a=0; a<MAX_MTEX; a++) {
+ if(la->mtex[a]) {
+ ID_NEW(la->mtex[a]->object);
+ }
+ }
+ }
+ break;
+ case OB_CAMERA:
+ ob->data= copy_camera(ob->data);
+ break;
+ case OB_MESH:
+ me= ob->data= copy_mesh(ob->data);
+ if(me && me->key)
+ ipo_idnew(me->key->ipo); /* drivers */
+ break;
+ case OB_MBALL:
+ ob->data= copy_mball(ob->data);
+ break;
+ case OB_CURVE:
+ case OB_SURF:
+ case OB_FONT:
+ ob->data= cu= copy_curve(ob->data);
+ ID_NEW(cu->bevobj);
+ ID_NEW(cu->taperobj);
+ break;
+ case OB_LATTICE:
+ ob->data= copy_lattice(ob->data);
+ break;
+ case OB_ARMATURE:
+ ob->recalc |= OB_RECALC_DATA;
+ ob->data= copy_armature(ob->data);
+ armature_rebuild_pose(ob, ob->data);
+ break;
+ default:
+ printf("ERROR single_obdata_users: %s\n", id->name);
+ error("Read console");
+ return;
+ }
+
+ id->us--;
+ id->newid= ob->data;
+
+ }
+
+ id= (ID *)ob->action;
+ if (id && id->us>1 && id->lib==NULL){
+ if(id->newid){
+ ob->action= (bAction *)id->newid;
+ id_us_plus(id->newid);
+ }
+ else {
+ ob->action= copy_action(ob->action);
+ id->us--;
+ id->newid=(ID *)ob->action;
+ }
+ }
+ id= (ID *)ob->ipo;
+ if(id && id->us>1 && id->lib==NULL) {
+ if(id->newid) {
+ ob->ipo= (Ipo *)id->newid;
+ id_us_plus(id->newid);
+ }
+ else {
+ ob->ipo= copy_ipo(ob->ipo);
+ id->us--;
+ id->newid= (ID *)ob->ipo;
+ }
+ ipo_idnew(ob->ipo); /* drivers */
+ }
+ /* other ipos */
+ switch(ob->type) {
+ case OB_LAMP:
+ la= ob->data;
+ if(la->ipo && la->ipo->id.us>1) {
+ la->ipo->id.us--;
+ la->ipo= copy_ipo(la->ipo);
+ ipo_idnew(la->ipo); /* drivers */
+ }
+ break;
+ case OB_CAMERA:
+ cam= ob->data;
+ if(cam->ipo && cam->ipo->id.us>1) {
+ cam->ipo->id.us--;
+ cam->ipo= copy_ipo(cam->ipo);
+ ipo_idnew(cam->ipo); /* drivers */
+ }
+ break;
+ }
+
+ }
+ base= base->next;
+ }
+
+ me= G.main->mesh.first;
+ while(me) {
+ ID_NEW(me->texcomesh);
+ me= me->id.next;
+ }
+}
+
+
+void single_mat_users(int flag)
+{
+ Object *ob;
+ Base *base;
+ Material *ma, *man;
+ Tex *tex;
+ int a, b;
+
+
+ base= FIRSTBASE;
+ while(base) {
+ ob= base->object;
+ if(ob->id.lib==NULL && (flag==0 || (base->flag & SELECT)) ) {
+
+ for(a=1; a<=ob->totcol; a++) {
+ ma= give_current_material(ob, a);
+ if(ma) {
+ /* do not test for LIB_NEW: this functions guaranteed delivers single_users! */
+
+ if(ma->id.us>1) {
+ man= copy_material(ma);
+
+ man->id.us= 0;
+ assign_material(ob, man, a);
+
+ if(ma->ipo) {
+ man->ipo= copy_ipo(ma->ipo);
+ ma->ipo->id.us--;
+ ipo_idnew(ma->ipo); /* drivers */
+ }
+
+ for(b=0; b<MAX_MTEX; b++) {
+ if(ma->mtex[b] && ma->mtex[b]->tex) {
+ tex= ma->mtex[b]->tex;
+ if(tex->id.us>1) {
+ ma->mtex[b]->tex= copy_texture(tex);
+ tex->id.us--;
+ }
+ }
+ }
+
+ }
+ }
+ }
+ }
+ base= base->next;
+ }
+}
+
+void do_single_tex_user(Tex **from)
+{
+ Tex *tex, *texn;
+
+ tex= *from;
+ if(tex==0) return;
+
+ if(tex->id.newid) {
+ *from= (Tex *)tex->id.newid;
+ id_us_plus(tex->id.newid);
+ tex->id.us--;
+ }
+ else if(tex->id.us>1) {
+ texn= copy_texture(tex);
+ tex->id.newid= (ID *)texn;
+ tex->id.us--;
+ *from= texn;
+ }
+
+}
+
+void single_tex_users_expand()
+{
+ /* only when 'parent' blocks are LIB_NEW */
+ Material *ma;
+ Lamp *la;
+ World *wo;
+ int b;
+
+ ma= G.main->mat.first;
+ while(ma) {
+ if(ma->id.flag & LIB_NEW) {
+ for(b=0; b<MAX_MTEX; b++) {
+ if(ma->mtex[b] && ma->mtex[b]->tex) {
+ do_single_tex_user( &(ma->mtex[b]->tex) );
+ }
+ }
+ }
+ ma= ma->id.next;
+ }
+
+ la= G.main->lamp.first;
+ while(la) {
+ if(la->id.flag & LIB_NEW) {
+ for(b=0; b<MAX_MTEX; b++) {
+ if(la->mtex[b] && la->mtex[b]->tex) {
+ do_single_tex_user( &(la->mtex[b]->tex) );
+ }
+ }
+ }
+ la= la->id.next;
+ }
+ wo= G.main->world.first;
+ while(wo) {
+ if(wo->id.flag & LIB_NEW) {
+ for(b=0; b<MAX_MTEX; b++) {
+ if(wo->mtex[b] && wo->mtex[b]->tex) {
+ do_single_tex_user( &(wo->mtex[b]->tex) );
+ }
+ }
+ }
+ wo= wo->id.next;
+ }
+}
+
+void single_mat_users_expand(void)
+{
+ /* only when 'parent' blocks are LIB_NEW */
+
+ Object *ob;
+ Mesh *me;
+ Curve *cu;
+ MetaBall *mb;
+ Material *ma;
+ int a;
+
+ ob= G.main->object.first;
+ while(ob) {
+ if(ob->id.flag & LIB_NEW) {
+ new_id_matar(ob->mat, ob->totcol);
+ }
+ ob= ob->id.next;
+ }
+
+ me= G.main->mesh.first;
+ while(me) {
+ if(me->id.flag & LIB_NEW) {
+ new_id_matar(me->mat, me->totcol);
+ }
+ me= me->id.next;
+ }
+
+ cu= G.main->curve.first;
+ while(cu) {
+ if(cu->id.flag & LIB_NEW) {
+ new_id_matar(cu->mat, cu->totcol);
+ }
+ cu= cu->id.next;
+ }
+
+ mb= G.main->mball.first;
+ while(mb) {
+ if(mb->id.flag & LIB_NEW) {
+ new_id_matar(mb->mat, mb->totcol);
+ }
+ mb= mb->id.next;
+ }
+
+ /* material imats */
+ ma= G.main->mat.first;
+ while(ma) {
+ if(ma->id.flag & LIB_NEW) {
+ for(a=0; a<MAX_MTEX; a++) {
+ if(ma->mtex[a]) {
+ ID_NEW(ma->mtex[a]->object);
+ }
+ }
+ }
+ ma= ma->id.next;
+ }
+}
+
+void single_user(void)
+{
+ int nr;
+
+ if(G.scene->id.lib) return;
+
+ clear_id_newpoins();
+
+ nr= pupmenu("Make Single User%t|Object|Object & ObData|Object & ObData & Materials+Tex|Materials+Tex");
+ if(nr>0) {
+
+ if(nr==1) single_object_users(1);
+
+ else if(nr==2) {
+ single_object_users(1);
+ single_obdata_users(1);
+ }
+ else if(nr==3) {
+ single_object_users(1);
+ single_obdata_users(1);
+ single_mat_users(1); /* also tex */
+
+ }
+ else if(nr==4) {
+ single_mat_users(1);
+ }
+
+ clear_id_newpoins();
+
+ countall();
+ allqueue(REDRAWALL, 0);
+ BIF_undo_push("Single user");
+ }
+}
+
+/* ************************************************************* */
+
+/* helper for below, ma was checked to be not NULL */
+static void make_local_makelocalmaterial(Material *ma)
+{
+ ID *id;
+ int b;
+
+ make_local_material(ma);
+
+ for(b=0; b<MAX_MTEX; b++) {
+ if(ma->mtex[b] && ma->mtex[b]->tex) {
+ make_local_texture(ma->mtex[b]->tex);
+ }
+ }
+
+ id= (ID *)ma->ipo;
+ if(id && id->lib) make_local_ipo(ma->ipo);
+
+ /* nodetree? XXX */
+}
+
+void make_local_menu(void)
+{
+ int mode;
+
+ /* If you modify this menu, please remember to update view3d_edit_object_makelocalmenu
+ * in header_view3d.c and the menu in toolbox.c
+ */
+
+ if(G.scene->id.lib) return;
+
+ mode = pupmenu("Make Local%t|Selected Objects %x1|Selected Objects and Data %x2|All %x3");
+
+ if (mode <= 0) return;
+
+ make_local(mode);
+}
+
+void make_local(int mode)
+{
+ Base *base;
+ Object *ob;
+ bActionStrip *strip;
+ Material *ma, ***matarar;
+ Lamp *la;
+ Curve *cu;
+ ID *id;
+ int a, b;
+
+ /* WATCH: the function new_id(..) re-inserts the id block!!! */
+ if(G.scene->id.lib) return;
+
+ if(mode==3) {
+ all_local(NULL, 0); /* NULL is all libs */
+ allqueue(REDRAWALL, 0);
+ return;
+ }
+ else if(mode<1) return;
+
+ clear_id_newpoins();
+
+ base= FIRSTBASE;
+ while(base) {
+ ob= base->object;
+ if( (base->flag & SELECT)) {
+ if(ob->id.lib) {
+ make_local_object(ob);
+ }
+ }
+ base= base->next;
+ }
+
+ /* maybe object pointers */
+ base= FIRSTBASE;
+ while(base) {
+ ob= base->object;
+ if( (base->flag & SELECT)) {
+ if(ob->id.lib==NULL) {
+ ID_NEW(ob->parent);
+ ID_NEW(ob->track);
+ }
+ }
+ base= base->next;
+ }
+
+ base= FIRSTBASE;
+ while(base) {
+ ob= base->object;
+ if( (base->flag & SELECT) ) {
+
+ id= ob->data;
+
+ if(id && mode>1) {
+
+ switch(ob->type) {
+ case OB_LAMP:
+ make_local_lamp((Lamp *)id);
+
+ la= ob->data;
+ id= (ID *)la->ipo;
+ if(id && id->lib) make_local_ipo(la->ipo);
+
+ break;
+ case OB_CAMERA:
+ make_local_camera((Camera *)id);
+ break;
+ case OB_MESH:
+ make_local_mesh((Mesh *)id);
+ make_local_key( ((Mesh *)id)->key );
+ break;
+ case OB_MBALL:
+ make_local_mball((MetaBall *)id);
+ break;
+ case OB_CURVE:
+ case OB_SURF:
+ case OB_FONT:
+ cu= (Curve *)id;
+ make_local_curve(cu);
+ id= (ID *)cu->ipo;
+ if(id && id->lib) make_local_ipo(cu->ipo);
+ make_local_key( cu->key );
+ break;
+ case OB_LATTICE:
+ make_local_lattice((Lattice *)id);
+ make_local_key( ((Lattice *)id)->key );
+ break;
+ case OB_ARMATURE:
+ make_local_armature ((bArmature *)id);
+ break;
+ }
+ }
+ id= (ID *)ob->ipo;
+ if(id && id->lib) make_local_ipo(ob->ipo);
+
+ id= (ID *)ob->action;
+ if(id && id->lib) make_local_action(ob->action);
+
+ for (strip=ob->nlastrips.first; strip; strip=strip->next) {
+ if(strip->act && strip->act->id.lib)
+ make_local_action(strip->act);
+ }
+
+ }
+ base= base->next;
+ }
+
+ if(mode>1) {
+ base= FIRSTBASE;
+ while(base) {
+ ob= base->object;
+ if(base->flag & SELECT ) {
+
+ if(ob->type==OB_LAMP) {
+ la= ob->data;
+ for(b=0; b<MAX_MTEX; b++) {
+ if(la->mtex[b] && la->mtex[b]->tex) {
+ make_local_texture(la->mtex[b]->tex);
+ }
+ }
+ }
+ else {
+
+ for(a=0; a<ob->totcol; a++) {
+ ma= ob->mat[a];
+ if(ma)
+ make_local_makelocalmaterial(ma);
+ }
+
+ matarar= (Material ***)give_matarar(ob);
+ if (matarar) {
+ for(a=0; a<ob->totcol; a++) {
+ ma= (*matarar)[a];
+ if(ma)
+ make_local_makelocalmaterial(ma);
+ }
+ }
+ }
+ }
+ base= base->next;
+ }
+ }
+
+ allqueue(REDRAWALL, 0);
+ BIF_undo_push("Make local");
+}
+
+static void copy_object__forwardModifierLinks(void *userData, Object *ob,
+ ID **idpoin)
+{
+ /* this is copied from ID_NEW; it might be better to have a macro */
+ if(*idpoin && (*idpoin)->newid) *idpoin = (*idpoin)->newid;
+}
+
+
+/* after copying objects, copied data should get new pointers */
+static void copy_object_set_idnew(int dupflag)
+{
+ Base *base;
+ Object *ob;
+ Material *ma, *mao;
+ ID *id;
+ Ipo *ipo;
+ bActionStrip *strip;
+ int a;
+
+ /* check object pointers */
+ for(base= FIRSTBASE; base; base= base->next) {
+ if TESTBASELIB(base) {
+ ob= base->object;
+ relink_constraints(&ob->constraints);
+ if (ob->pose){
+ bPoseChannel *chan;
+ for (chan = ob->pose->chanbase.first; chan; chan=chan->next){
+ relink_constraints(&chan->constraints);
+ }
+ }
+ modifiers_foreachIDLink(ob, copy_object__forwardModifierLinks, NULL);
+ ID_NEW(ob->parent);
+ ID_NEW(ob->track);
+ ID_NEW(ob->proxy);
+ ID_NEW(ob->proxy_group);
+
+ for(strip= ob->nlastrips.first; strip; strip= strip->next) {
+ bActionModifier *amod;
+ for(amod= strip->modifiers.first; amod; amod= amod->next)
+ ID_NEW(amod->ob);
+ }
+ }
+ }
+
+ /* materials */
+ if( dupflag & USER_DUP_MAT) {
+ mao= G.main->mat.first;
+ while(mao) {
+ if(mao->id.newid) {
+
+ ma= (Material *)mao->id.newid;
+
+ if(dupflag & USER_DUP_TEX) {
+ for(a=0; a<MAX_MTEX; a++) {
+ if(ma->mtex[a]) {
+ id= (ID *)ma->mtex[a]->tex;
+ if(id) {
+ ID_NEW_US(ma->mtex[a]->tex)
+ else ma->mtex[a]->tex= copy_texture(ma->mtex[a]->tex);
+ id->us--;
+ }
+ }
+ }
+ }
+ id= (ID *)ma->ipo;
+ if(id) {
+ ID_NEW_US(ma->ipo)
+ else ma->ipo= copy_ipo(ma->ipo);
+ id->us--;
+ }
+ }
+ mao= mao->id.next;
+ }
+ }
+
+ /* lamps */
+ if( dupflag & USER_DUP_IPO) {
+ Lamp *la= G.main->lamp.first;
+ while(la) {
+ if(la->id.newid) {
+ Lamp *lan= (Lamp *)la->id.newid;
+ id= (ID *)lan->ipo;
+ if(id) {
+ ID_NEW_US(lan->ipo)
+ else lan->ipo= copy_ipo(lan->ipo);
+ id->us--;
+ }
+ }
+ la= la->id.next;
+ }
+ }
+
+ /* ipos */
+ ipo= G.main->ipo.first;
+ while(ipo) {
+ if(ipo->id.lib==NULL && ipo->id.newid) {
+ Ipo *ipon= (Ipo *)ipo->id.newid;
+ IpoCurve *icu;
+ for(icu= ipon->curve.first; icu; icu= icu->next) {
+ if(icu->driver) {
+ ID_NEW(icu->driver->ob);
+ }
+ }
+ }
+ ipo= ipo->id.next;
+ }
+
+ set_sca_new_poins();
+
+ clear_id_newpoins();
+
+}
+
+/* This function duplicated the current visible selection, its used by Duplicate and Linked Duplicate
+Alt+D/Shift+D as well as Pythons Object.Duplicate(), it takes
+mode:
+ 0: Duplicate with transform, Redraw.
+ 1: Duplicate, no transform, Redraw
+ 2: Duplicate, no transform, no redraw (Only used by python)
+if true the user will not be dropped into grab mode directly after and..
+dupflag: a flag made from constants declared in DNA_userdef_types.h
+ The flag tells adduplicate() weather to copy data linked to the object, or to reference the existing data.
+ U.dupflag for default operations or you can construct a flag as python does
+ if the dupflag is 0 then no data will be copied (linked duplicate) */
+
+void adduplicate(int mode, int dupflag)
+{
+ Base *base, *basen;
+ Material ***matarar;
+ Object *ob, *obn;
+ ID *id;
+ int a, didit;
+
+ if(G.scene->id.lib) return;
+ clear_id_newpoins();
+ clear_sca_new_poins(); /* sensor/contr/act */
+
+ base= FIRSTBASE;
+ while(base) {
+ if TESTBASE(base) {
+
+ ob= base->object;
+ if(ob->flag & OB_POSEMODE) {
+ ; /* nothing? */
+ }
+ else {
+ obn= copy_object(ob);
+ obn->recalc |= OB_RECALC;
+
+ basen= MEM_mallocN(sizeof(Base), "duplibase");
+ *basen= *base;
+ BLI_addhead(&G.scene->base, basen); /* addhead: prevent eternal loop */
+ basen->object= obn;
+ base->flag &= ~SELECT;
+
+ if(basen->flag & OB_FROMGROUP) {
+ Group *group;
+ for(group= G.main->group.first; group; group= group->id.next) {
+ if(object_in_group(ob, group))
+ add_to_group(group, obn);
+ }
+ obn->flag |= OB_FROMGROUP; /* this flag is unset with copy_object() */
+ }
+
+ if(BASACT==base) BASACT= basen;
+
+ /* duplicates using userflags */
+
+ if(dupflag & USER_DUP_IPO) {
+ bConstraintChannel *chan;
+ id= (ID *)obn->ipo;
+
+ if(id) {
+ ID_NEW_US( obn->ipo)
+ else obn->ipo= copy_ipo(obn->ipo);
+ id->us--;
+ }
+ /* Handle constraint ipos */
+ for (chan=obn->constraintChannels.first; chan; chan=chan->next){
+ id= (ID *)chan->ipo;
+ if(id) {
+ ID_NEW_US( chan->ipo)
+ else chan->ipo= copy_ipo(chan->ipo);
+ id->us--;
+ }
+ }
+ }
+ if(dupflag & USER_DUP_ACT){ /* Not buttons in the UI to modify this, add later? */
+ id= (ID *)obn->action;
+ if (id){
+ ID_NEW_US(obn->action)
+ else{
+ obn->action= copy_action(obn->action);
+ }
+ id->us--;
+ }
+ }
+ if(dupflag & USER_DUP_MAT) {
+ for(a=0; a<obn->totcol; a++) {
+ id= (ID *)obn->mat[a];
+ if(id) {
+ ID_NEW_US(obn->mat[a])
+ else obn->mat[a]= copy_material(obn->mat[a]);
+ id->us--;
+ }
+ }
+ }
+
+ id= obn->data;
+ didit= 0;
+
+ switch(obn->type) {
+ case OB_MESH:
+ if(dupflag & USER_DUP_MESH) {
+ ID_NEW_US2( obn->data )
+ else {
+ obn->data= copy_mesh(obn->data);
+
+ if(obn->fluidsimSettings) {
+ obn->fluidsimSettings->orgMesh = (Mesh *)obn->data;
+ }
+
+ didit= 1;
+ }
+ id->us--;
+ }
+ break;
+ case OB_CURVE:
+ if(dupflag & USER_DUP_CURVE) {
+ ID_NEW_US2(obn->data )
+ else {
+ obn->data= copy_curve(obn->data);
+ didit= 1;
+ }
+ id->us--;
+ }
+ break;
+ case OB_SURF:
+ if(dupflag & USER_DUP_SURF) {
+ ID_NEW_US2( obn->data )
+ else {
+ obn->data= copy_curve(obn->data);
+ didit= 1;
+ }
+ id->us--;
+ }
+ break;
+ case OB_FONT:
+ if(dupflag & USER_DUP_FONT) {
+ ID_NEW_US2( obn->data )
+ else {
+ obn->data= copy_curve(obn->data);
+ didit= 1;
+ }
+ id->us--;
+ }
+ break;
+ case OB_MBALL:
+ if(dupflag & USER_DUP_MBALL) {
+ ID_NEW_US2(obn->data )
+ else {
+ obn->data= copy_mball(obn->data);
+ didit= 1;
+ }
+ id->us--;
+ }
+ break;
+ case OB_LAMP:
+ if(dupflag & USER_DUP_LAMP) {
+ ID_NEW_US2(obn->data )
+ else obn->data= copy_lamp(obn->data);
+ id->us--;
+ }
+ break;
+
+ case OB_ARMATURE:
+ obn->recalc |= OB_RECALC_DATA;
+ if(obn->pose) obn->pose->flag |= POSE_RECALC;
+
+ if(dupflag & USER_DUP_ARM) {
+ ID_NEW_US2(obn->data )
+ else {
+ obn->data= copy_armature(obn->data);
+ armature_rebuild_pose(obn, obn->data);
+ didit= 1;
+ }
+ id->us--;
+ }
+
+ break;
+
+ case OB_LATTICE:
+ if(dupflag!=0) {
+ ID_NEW_US2(obn->data )
+ else obn->data= copy_lattice(obn->data);
+ id->us--;
+ }
+ break;
+ case OB_CAMERA:
+ if(dupflag!=0) {
+ ID_NEW_US2(obn->data )
+ else obn->data= copy_camera(obn->data);
+ id->us--;
+ }
+ break;
+ }
+
+ if(dupflag & USER_DUP_MAT) {
+ matarar= give_matarar(obn);
+ if(didit && matarar) {
+ for(a=0; a<obn->totcol; a++) {
+ id= (ID *)(*matarar)[a];
+ if(id) {
+ ID_NEW_US( (*matarar)[a] )
+ else (*matarar)[a]= copy_material((*matarar)[a]);
+
+ id->us--;
+ }
+ }
+ }
+ }
+#ifdef WITH_VERSE
+ /* send new created object to verse server,
+ * when original object was linked with object node */
+ if(ob->vnode) {
+ b_verse_duplicate_object(((VNode*)ob->vnode)->session, ob, obn);
+ }
+#endif
+ }
+
+ }
+ base= base->next;
+ }
+
+ copy_object_set_idnew(dupflag);
+
+ DAG_scene_sort(G.scene);
+ DAG_scene_flush_update(G.scene, screen_view3d_layers());
+
+ countall();
+ if(mode==0) {
+ BIF_TransformSetUndo("Add Duplicate");
+ initTransform(TFM_TRANSLATION, CTX_NONE);
+ Transform();
+ }
+ set_active_base(BASACT);
+ if(mode!=2) { /* mode of 2 is used by python to avoid unrequested redraws */
+ allqueue(REDRAWNLA, 0);
+ allqueue(REDRAWACTION, 0); /* also oops */
+ allqueue(REDRAWIPO, 0); /* also oops */
+ }
+}
+
+void make_duplilist_real()
+{
+ Base *base, *basen;
+ Object *ob;
+ /* extern ListBase duplilist; */
+
+ if(okee("Make dupli objects real")==0) return;
+
+ clear_id_newpoins();
+
+ base= FIRSTBASE;
+ while(base) {
+ if TESTBASE(base) {
+
+ if(base->object->transflag & OB_DUPLI) {
+ ListBase *lb= object_duplilist(G.scene, base->object);
+ DupliObject *dob;
+
+ for(dob= lb->first; dob; dob= dob->next) {
+ ob= copy_object(dob->ob);
+ /* font duplis can have a totcol without material, we get them from parent
+ * should be implemented better...
+ */
+ if(ob->mat==NULL) ob->totcol= 0;
+
+ basen= MEM_dupallocN(base);
+ basen->flag &= ~OB_FROMDUPLI;
+ BLI_addhead(&G.scene->base, basen); /* addhead: othwise eternal loop */
+ basen->object= ob;
+ ob->ipo= NULL; /* make sure apply works */
+ ob->parent= ob->track= NULL;
+ ob->disp.first= ob->disp.last= NULL;
+ ob->transflag &= ~OB_DUPLI;
+
+ Mat4CpyMat4(ob->obmat, dob->mat);
+ apply_obmat(ob);
+ }
+
+ copy_object_set_idnew(0);
+
+ free_object_duplilist(lb);
+
+ base->object->transflag &= ~OB_DUPLI;
+ }
+ }
+ base= base->next;
+ }
+
+ DAG_scene_sort(G.scene);
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWOOPS, 0);
+
+ BIF_undo_push("Make duplicates real");
+}
+
+void selectlinks_menu(void)
+{
+ Object *ob;
+ int nr;
+
+ ob= OBACT;
+ if(ob==0) return;
+
+ /* If you modify this menu, please remember to update view3d_select_linksmenu
+ * in header_view3d.c and the menu in toolbox.c
+ */
+ nr= pupmenu("Select Linked%t|Object Ipo%x1|ObData%x2|Material%x3|Texture%x4|DupliGroup%x5");
+
+ if (nr <= 0) return;
+
+ selectlinks(nr);
+}
+
+void selectlinks(int nr)
+{
+ Object *ob;
+ Base *base;
+ void *obdata = NULL;
+ Ipo *ipo = NULL;
+ Material *mat = NULL, *mat1;
+ Tex *tex=0;
+ int a, b;
+ short changed = 0;
+ /* events (nr):
+ * Object Ipo: 1
+ * ObData: 2
+ * Current Material: 3
+ * Current Texture: 4
+ * DupliGroup: 5
+ */
+
+
+ ob= OBACT;
+ if(ob==0) return;
+
+ if(nr==1) {
+ ipo= ob->ipo;
+ if(ipo==0) return;
+ }
+ else if(nr==2) {
+ if(ob->data==0) return;
+ obdata= ob->data;
+ }
+ else if(nr==3 || nr==4) {
+ mat= give_current_material(ob, ob->actcol);
+ if(mat==0) return;
+ if(nr==4) {
+ if(mat->mtex[ (int)mat->texact ]) tex= mat->mtex[ (int)mat->texact ]->tex;
+ if(tex==0) return;
+ }
+ }
+ else if(nr==5) {
+ if(ob->dup_group==NULL) return;
+ }
+ else return;
+
+ base= FIRSTBASE;
+ while(base) {
+ if (BASE_SELECTABLE(base) && !(base->flag & SELECT)) {
+ if(nr==1) {
+ if(base->object->ipo==ipo) base->flag |= SELECT;
+ changed = 1;
+ }
+ else if(nr==2) {
+ if(base->object->data==obdata) base->flag |= SELECT;
+ changed = 1;
+ }
+ else if(nr==3 || nr==4) {
+ ob= base->object;
+
+ for(a=1; a<=ob->totcol; a++) {
+ mat1= give_current_material(ob, a);
+ if(nr==3) {
+ if(mat1==mat) base->flag |= SELECT;
+ changed = 1;
+ }
+ else if(mat1 && nr==4) {
+ for(b=0; b<MAX_MTEX; b++) {
+ if(mat1->mtex[b]) {
+ if(tex==mat1->mtex[b]->tex) {
+ base->flag |= SELECT;
+ changed = 1;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if(nr==5) {
+ if(base->object->dup_group==ob->dup_group) {
+ base->flag |= SELECT;
+ changed = 1;
+ }
+ }
+ base->object->flag= base->flag;
+ }
+ base= base->next;
+ }
+
+ if (changed) {
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWDATASELECT, 0);
+ allqueue(REDRAWOOPS, 0);
+ BIF_undo_push("Select linked");
+ }
+}
+
+void image_aspect(void)
+{
+ /* all selected objects with an image map: scale in image aspect */
+ Base *base;
+ Object *ob;
+ Material *ma;
+ Tex *tex;
+ float x, y, space;
+ int a, b, done;
+
+ if(G.obedit) return;
+ if(G.scene->id.lib) return;
+
+ base= FIRSTBASE;
+ while(base) {
+ if TESTBASELIB(base) {
+ ob= base->object;
+ done= 0;
+
+ for(a=1; a<=ob->totcol; a++) {
+ ma= give_current_material(ob, a);
+ if(ma) {
+ for(b=0; b<MAX_MTEX; b++) {
+ if(ma->mtex[b] && ma->mtex[b]->tex) {
+ tex= ma->mtex[b]->tex;
+ if(tex->type==TEX_IMAGE && tex->ima) {
+ ImBuf *ibuf= BKE_image_get_ibuf(tex->ima, NULL);
+
+ /* texturespace */
+ space= 1.0;
+ if(ob->type==OB_MESH) {
+ float size[3];
+ mesh_get_texspace(ob->data, NULL, NULL, size);
+ space= size[0]/size[1];
+ }
+ else if ELEM3(ob->type, OB_CURVE, OB_FONT, OB_SURF) {
+ Curve *cu= ob->data;
+ space= cu->size[0]/cu->size[1];
+ }
+
+ x= ibuf->x/space;
+ y= ibuf->y;
+
+ if(x>y) ob->size[0]= ob->size[1]*x/y;
+ else ob->size[1]= ob->size[0]*y/x;
+
+ done= 1;
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_OB);
+ }
+ }
+ if(done) break;
+ }
+ }
+ if(done) break;
+ }
+ }
+ base= base->next;
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+ BIF_undo_push("Image aspect");
+}
+
+void set_ob_ipoflags(void)
+{
+ Base *base;
+ int set= 1;
+
+ if (!G.vd) {
+ error("Can't do this! Open a 3D window");
+ return;
+ }
+
+ base= FIRSTBASE;
+ while(base) {
+ if TESTBASELIB(base) {
+ if(base->object->ipoflag & OB_DRAWKEY) {
+ set= 0;
+ break;
+ }
+ }
+ base= base->next;
+ }
+
+ base= FIRSTBASE;
+ while(base) {
+ if TESTBASELIB(base) {
+ if(set) {
+ base->object->ipoflag |= OB_DRAWKEY;
+ if(base->object->ipo) base->object->ipo->showkey= 1;
+ }
+ else {
+ base->object->ipoflag &= ~OB_DRAWKEY;
+ if(base->object->ipo) base->object->ipo->showkey= 0;
+ }
+ }
+ base= base->next;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSOBJECT, 0);
+ allqueue(REDRAWNLA, 0);
+ allqueue (REDRAWACTION, 0);
+ allspace(REMAKEIPO, 0);
+ allqueue(REDRAWIPO, 0);
+}
+
+void select_select_keys(void)
+{
+ Base *base;
+ IpoCurve *icu;
+ BezTriple *bezt;
+ int a;
+
+ if (!G.vd) {
+ error("Can't do this! Open a 3D window");
+ return;
+ }
+
+ if(G.scene->id.lib) return;
+
+ if(okee("Show and select all keys")==0) return;
+
+ base= FIRSTBASE;
+ while(base) {
+ if TESTBASELIB(base) {
+ if(base->object->ipo) {
+ base->object->ipoflag |= OB_DRAWKEY;
+ base->object->ipo->showkey= 1;
+ icu= base->object->ipo->curve.first;
+ while(icu) {
+ a= icu->totvert;
+ bezt= icu->bezt;
+ while(a--) {
+ bezt->f1 |= SELECT;
+ bezt->f2 |= SELECT;
+ bezt->f3 |= SELECT;
+ bezt++;
+ }
+ icu= icu->next;
+ }
+ }
+ }
+ base= base->next;
+ }
+
+ allqueue(REDRAWNLA, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ allspace(REMAKEIPO, 0);
+ allqueue(REDRAWIPO, 0);
+
+ BIF_undo_push("Select keys");
+
+}
+
+
+int vergbaseco(const void *a1, const void *a2)
+{
+ Base **x1, **x2;
+
+ x1= (Base **) a1;
+ x2= (Base **) a2;
+
+ if( (*x1)->sy > (*x2)->sy ) return 1;
+ else if( (*x1)->sy < (*x2)->sy) return -1;
+ else if( (*x1)->sx > (*x2)->sx ) return 1;
+ else if( (*x1)->sx < (*x2)->sx ) return -1;
+
+ return 0;
+}
+
+
+void auto_timeoffs(void)
+{
+ Base *base, **basesort, **bs;
+ float start, delta;
+ int tot=0, a;
+ short offset=25;
+
+ if(BASACT==0 || G.vd==NULL) return;
+ if(button(&offset, 0, 1000,"Total time")==0) return;
+
+ /* make array of all bases, xco yco (screen) */
+ base= FIRSTBASE;
+ while(base) {
+ if(TESTBASELIB(base)) {
+ tot++;
+ }
+ base= base->next;
+ }
+
+ delta= (float)offset/(float)tot;
+ start= OBACT->sf;
+
+ bs= basesort= MEM_mallocN(sizeof(void *)*tot,"autotimeoffs");
+ base= FIRSTBASE;
+
+ while(base) {
+ if(TESTBASELIB(base)) {
+ *bs= base;
+ bs++;
+ }
+ base= base->next;
+ }
+ qsort(basesort, tot, sizeof(void *), vergbaseco);
+
+ bs= basesort;
+ for(a=0; a<tot; a++) {
+
+ (*bs)->object->sf= start;
+ start+= delta;
+
+ bs++;
+ }
+ MEM_freeN(basesort);
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSOBJECT, 0);
+}
+
+void texspace_edit(void)
+{
+ Base *base;
+ int nr=0;
+
+ /* first test if from visible and selected objects
+ * texspacedraw is set:
+ */
+
+ if(G.obedit) return;
+
+ base= FIRSTBASE;
+ while(base) {
+ if TESTBASELIB(base) {
+ break;
+ }
+ base= base->next;
+ }
+
+ if(base==0) {
+ return;
+ }
+
+ nr= pupmenu("Texture Space %t|Grab/Move%x1|Size%x2");
+ if(nr<1) return;
+
+ base= FIRSTBASE;
+ while(base) {
+ if TESTBASELIB(base) {
+ base->object->dtx |= OB_TEXSPACE;
+ }
+ base= base->next;
+ }
+
+
+ if(nr==1) {
+ initTransform(TFM_TRANSLATION, CTX_TEXTURE);
+ Transform();
+ }
+ else if(nr==2) {
+ initTransform(TFM_RESIZE, CTX_TEXTURE);
+ Transform();
+ }
+ else if(nr==3) {
+ initTransform(TFM_ROTATION, CTX_TEXTURE);
+ Transform();
+ }
+}
+
+/* ******************************************************************** */
+/* Mirror function in Edit Mode */
+
+void mirrormenu(void)
+{
+ short mode = 0;
+
+
+ if (G.obedit==0) {
+ mode=pupmenu("Mirror Axis %t|X Local%x4|Y Local%x5|Z Local%x6|");
+
+ if (mode==-1) return; /* return */
+ Mirror(mode); /* separating functionality from interface | call*/
+ }
+ else {
+ mode=pupmenu("Mirror Axis %t|X Global%x1|Y Global%x2|Z Global%x3|%l|X Local%x4|Y Local%x5|Z Local%x6|%l|X View%x7|Y View%x8|Z View%x9|");
+
+ if (mode==-1) return; /* return */
+ Mirror(mode); /* separating functionality from interface | call*/
+ }
+}
+
+void hookmenu(void)
+{
+ /* only called in object mode */
+ short event, changed=0;
+ Object *ob;
+ Base *base;
+ ModifierData *md;
+ HookModifierData *hmd;
+
+ event= pupmenu("Modify Hooks for Selected...%t|Reset Offset%x1|Recenter at Cursor%x2");
+ if (event==-1) return;
+ if (event==2 && !(G.vd)) {
+ error("Cannot perform this operation without a 3d view");
+ return;
+ }
+
+ for (base= FIRSTBASE; base; base= base->next) {
+ if TESTBASELIB(base) {
+ for (md = base->object->modifiers.first; md; md=md->next) {
+ if (md->type==eModifierType_Hook) {
+ ob = base->object;
+ hmd = (HookModifierData*) md;
+
+ /*
+ * Copied from modifiers_cursorHookCenter and
+ * modifiers_clearHookOffset, should consolidate
+ * */
+
+ if (event==1) {
+ if(hmd->object) {
+ Mat4Invert(hmd->object->imat, hmd->object->obmat);
+ Mat4MulSerie(hmd->parentinv, hmd->object->imat, ob->obmat, NULL, NULL, NULL, NULL, NULL, NULL);
+
+ changed= 1;
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ }
+ } else {
+ float *curs = give_cursor();
+ float bmat[3][3], imat[3][3];
+
+ where_is_object(ob);
+
+ Mat3CpyMat4(bmat, ob->obmat);
+ Mat3Inv(imat, bmat);
+
+ curs= give_cursor();
+ hmd->cent[0]= curs[0]-ob->obmat[3][0];
+ hmd->cent[1]= curs[1]-ob->obmat[3][1];
+ hmd->cent[2]= curs[2]-ob->obmat[3][2];
+ Mat3MulVecfl(imat, hmd->cent);
+
+ changed= 1;
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ }
+ }
+ }
+ }
+ }
+
+ if (changed) {
+ if (event==1)
+ BIF_undo_push("Clear hook offset for selected");
+ else if (event==2)
+ BIF_undo_push("Hook cursor center for selected");
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ }
+}
+
+/*
+ * Returns true if the Object data is a from an external blend file (libdata)
+ */
+int object_data_is_libdata(Object *ob)
+{
+ if (!ob) return 0;
+ if (ob->proxy) return 0;
+ if (ob->id.lib) return 1;
+ if (!ob->data) return 0;
+ if (((ID *)ob->data)->lib) return 1;
+ return 0;
+}
+
+void hide_objects(int select)
+{
+ Base *base;
+ short changed = 0, changed_act = 0;
+ for(base = FIRSTBASE; base; base=base->next){
+ if(TESTBASELIB(base)==select){
+ base->flag &= ~SELECT;
+ base->object->flag = base->flag;
+ base->object->restrictflag |= OB_RESTRICT_VIEW;
+ changed = 1;
+ if (base==BASACT) {
+ BASACT= NULL;
+ changed_act = 1;
+ }
+ }
+ }
+ if (changed) {
+ if(select) BIF_undo_push("Hide Selected Objects");
+ else if(select) BIF_undo_push("Hide Unselected Objects");
+ DAG_scene_sort(G.scene);
+ allqueue(REDRAWVIEW3D,0);
+ allqueue(REDRAWOOPS,0);
+ allqueue(REDRAWDATASELECT,0);
+ if (changed_act) { /* these spaces depend on the active object */
+ allqueue(REDRAWBUTSALL,0);
+ allqueue(REDRAWIPO,0);
+ allqueue(REDRAWACTION,0);
+ }
+ countall();
+ }
+}
+
+void show_objects(void)
+{
+ Base *base;
+ int changed = 0;
+ for(base = FIRSTBASE; base; base=base->next){
+ if((base->lay & G.vd->lay) && base->object->restrictflag & OB_RESTRICT_VIEW) {
+ base->flag |= SELECT;
+ base->object->flag = base->flag;
+ base->object->restrictflag &= ~OB_RESTRICT_VIEW;
+ changed = 1;
+ }
+ }
+ if (changed) {
+ BIF_undo_push("Unhide Objects");
+ DAG_scene_sort(G.scene);
+ allqueue(REDRAWVIEW3D,0);
+ allqueue(REDRAWOOPS,0);
+ countall();
+ }
+}
diff --git a/source/blender/src/editoops.c b/source/blender/src/editoops.c
new file mode 100644
index 00000000000..cb654646d0f
--- /dev/null
+++ b/source/blender/src/editoops.c
@@ -0,0 +1,675 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef WIN32
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "DNA_material_types.h"
+#include "DNA_object_types.h"
+#include "DNA_oops_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_image_types.h"
+#include "DNA_ipo_types.h"
+
+#include "BKE_global.h"
+#include "BKE_scene.h"
+#include "BKE_library.h"
+#include "BKE_material.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_space.h"
+#include "BIF_screen.h"
+#include "BIF_editoops.h"
+#include "BIF_editview.h"
+#include "BIF_drawscene.h"
+#include "BIF_mywindow.h"
+#include "BIF_toolbox.h"
+#include "BIF_interface.h"
+
+#include "BDR_editobject.h"
+
+#include "BSE_edit.h"
+#include "BSE_drawipo.h"
+
+#include "blendef.h"
+#include "mydevice.h"
+
+
+typedef struct TransOops {
+ float *loc;
+ float oldloc[2];
+} TransOops;
+
+struct ID *idt;
+
+
+static void oops_to_select_objects(void)
+{
+ Oops *oops;
+ Base *base;
+ Object *ob;
+
+ if(G.soops==0) return;
+
+ oops= G.soops->oops.first;
+ while(oops) {
+ if(oops->hide==0) {
+ if(oops->type==ID_OB) {
+ ob= (Object *)oops->id;
+ if ((ob->restrictflag & OB_RESTRICT_VIEW)==0) {
+ if(oops->flag & SELECT) ob->flag |= SELECT;
+ else ob->flag &= ~SELECT;
+ }
+ }
+ }
+ oops= oops->next;
+ }
+ base= FIRSTBASE;
+ while(base) {
+ if(base->flag != base->object->flag) {
+ base->flag= base->object->flag;
+ }
+ base= base->next;
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWOOPS, 0);
+}
+
+void swap_select_all_oops(void)
+{
+ Oops *oops;
+ int sel= 0;
+
+ if(G.soops==0) return;
+
+ oops= G.soops->oops.first;
+ while(oops) {
+ if(oops->hide==0) {
+ if(oops->flag & SELECT) {
+ sel= 1;
+ break;
+ }
+ }
+ oops= oops->next;
+ }
+
+ oops= G.soops->oops.first;
+ while(oops) {
+ if(oops->hide==0) {
+ if(sel) oops->flag &= ~SELECT;
+ else oops->flag |= SELECT;
+ }
+ oops= oops->next;
+ }
+
+ oops_to_select_objects(); /* also redraw */
+
+ G.soops->lockpoin= NULL;
+}
+
+/* never used... check CVS 1.12 for the code */
+/* static void select_swap_oops(void) */
+
+static void deselect_all_oops(void)
+{
+ Oops *oops;
+
+ if(G.soops==0) return;
+
+ oops= G.soops->oops.first;
+ while(oops) {
+ if(oops->hide==0) {
+ oops->flag &= ~SELECT;
+ }
+ oops= oops->next;
+ }
+ G.soops->lockpoin= NULL;
+}
+
+void set_select_flag_oops(void) /* all areas */
+{
+ SpaceOops *so;
+ ScrArea *sa;
+
+ sa= G.curscreen->areabase.first;
+ while(sa) {
+ if(sa->spacetype==SPACE_OOPS) {
+ so= sa->spacedata.first;
+ so->flag |= SO_NEWSELECTED;
+ }
+ sa= sa->next;
+ }
+ if(G.soops) G.soops->lockpoin= NULL;
+}
+
+void deselect_all_area_oops(void) /* all areas */
+{
+ SpaceOops *so;
+ Oops *oops;
+ ScrArea *sa;
+
+ sa= G.curscreen->areabase.first;
+ while(sa) {
+ if(sa->spacetype==SPACE_OOPS) {
+ so= sa->spacedata.first;
+
+ oops= so->oops.first;
+ while(oops) {
+ oops->flag &= ~SELECT;
+ oops= oops->next;
+ }
+ }
+ sa= sa->next;
+ }
+
+ if(G.soops) G.soops->lockpoin= NULL;
+}
+
+void transform_oops(int mode, int context)
+{
+ TransOops *transmain, *tv;
+ Oops *oops;
+ float dx, dy, div, dvec[3], cent[3], min[3], max[3];
+ float sizefac, size[2], xref=1.0, yref=1.0;
+ int a, tot= 0, midtog= 0;
+ unsigned short event = 0;
+ short firsttime= 1, proj = 0, afbreek=0, xc, yc, xo, yo, xn, yn, mval[2];
+ short val;
+ char str[32];
+
+ if(G.soops==0) return;
+
+ /* which oopses... */
+ oops= G.soops->oops.first;
+ while(oops) {
+ if(oops->hide==0) {
+ if(oops->flag & SELECT) {
+ tot++;
+ }
+ }
+ oops= oops->next;
+ }
+
+ if(tot==0) return;
+
+ G.moving= 1;
+
+ INIT_MINMAX(min, max);
+
+ tv=transmain= MEM_callocN(tot*sizeof(TransOops), "transmain");
+ oops= G.soops->oops.first;
+ while(oops) {
+ if(oops->hide==0) {
+ if(oops->flag & SELECT) {
+ tv->loc= &oops->x;
+ tv->oldloc[0]= tv->loc[0];
+ tv->oldloc[1]= tv->loc[1];
+ DO_MINMAX2(tv->loc, min, max);
+ tv++;
+ }
+ }
+ oops= oops->next;
+ }
+
+ cent[0]= (min[0]+max[0])/2.0;
+ cent[1]= (min[1]+max[1])/2.0;
+
+ ipoco_to_areaco_noclip(G.v2d, cent, mval);
+ xc= mval[0];
+ yc= mval[1];
+
+ getmouseco_areawin(mval);
+ xo= xn= mval[0];
+ yo= yn= mval[1];
+ dvec[0]= dvec[1]= 0.0;
+
+ sizefac= sqrt( (float)((yc-yn)*(yc-yn)+(xn-xc)*(xn-xc)) );
+ if(sizefac<2.0) sizefac= 2.0;
+
+ while(afbreek==0) {
+ getmouseco_areawin(mval);
+ if(mval[0]!=xo || mval[1]!=yo || firsttime) {
+
+ if(mode=='g') {
+
+ dx= mval[0]- xo;
+ dy= mval[1]- yo;
+
+ div= G.v2d->mask.xmax-G.v2d->mask.xmin;
+ dvec[0]+= (G.v2d->cur.xmax-G.v2d->cur.xmin)*(dx)/div;
+
+ div= G.v2d->mask.ymax-G.v2d->mask.ymin;
+ dvec[1]+= (G.v2d->cur.ymax-G.v2d->cur.ymin)*(dy)/div;
+
+ if(midtog) dvec[proj]= 0.0;
+
+ tv= transmain;
+ for(a=0; a<tot; a++, tv++) {
+
+ tv->loc[0]= tv->oldloc[0]+dvec[0];
+ tv->loc[1]= tv->oldloc[1]+dvec[1];
+
+ }
+
+ sprintf(str, "X: %.2f Y: %.2f ", dvec[0], dvec[1]);
+ headerprint(str);
+ }
+ else if(mode=='s') {
+ size[0]=size[1]= (sqrt( (float)((yc-mval[1])*(yc-mval[1])+(mval[0]-xc)*(mval[0]-xc)) ))/sizefac;
+
+ if(midtog) size[proj]= 1.0;
+ size[0]*= xref;
+ size[1]*= yref;
+
+ tv= transmain;
+ for(a=0; a<tot; a++, tv++) {
+
+ tv->loc[0]= size[0]*(tv->oldloc[0]-cent[0])+ cent[0];
+ tv->loc[1]= size[1]*(tv->oldloc[1]-cent[1])+ cent[1];
+
+ }
+
+ sprintf(str, "sizeX: %.3f sizeY: %.3f ", size[0], size[1]);
+ headerprint(str);
+ }
+
+
+ xo= mval[0];
+ yo= mval[1];
+
+ force_draw(0);
+
+ firsttime= 0;
+
+ }
+ else BIF_wait_for_statechange();
+
+ while(qtest()) {
+ event= extern_qread(&val);
+ if(val) {
+ switch(event) {
+ case ESCKEY:
+ case RIGHTMOUSE:
+ case LEFTMOUSE:
+ case SPACEKEY:
+ case RETKEY:
+ afbreek= 1;
+ break;
+ case MIDDLEMOUSE:
+
+ midtog= ~midtog;
+ if(midtog) {
+ if( abs(mval[0]-xn) > abs(mval[1]-yn)) proj= 1;
+ else proj= 0;
+ firsttime= 1;
+ }
+
+ break;
+ default:
+ arrows_move_cursor(event);
+ }
+ }
+ if(afbreek) break;
+ }
+ }
+
+ if(event==ESCKEY || event==RIGHTMOUSE) {
+ tv= transmain;
+ for(a=0; a<tot; a++, tv++) {
+ tv->loc[0]= tv->oldloc[0];
+ tv->loc[1]= tv->oldloc[1];
+ }
+ }
+ MEM_freeN(transmain);
+
+ G.moving= 0;
+
+ scrarea_queue_redraw(curarea);
+}
+
+static Oops *find_nearest_oops(void)
+{
+ Oops *oops;
+ float x, y;
+ short mval[2];
+
+ getmouseco_areawin(mval);
+ areamouseco_to_ipoco(G.v2d, mval, &x, &y);
+
+ oops= G.soops->oops.first;
+ while(oops) {
+ if(oops->hide == 0) {
+ if(oops->x <=x && oops->x+OOPSX >= x) {
+ if(oops->y <=y && oops->y+OOPSY >= y) {
+ return oops;
+ }
+ }
+ }
+ oops= oops->next;
+ }
+ return 0;
+}
+
+static void do_activate_oops(Oops *oops)
+{
+ Base *base;
+ Object *ob;
+
+ switch(oops->type) {
+ case ID_SCE:
+ if(oops->id) set_scene((Scene *)oops->id);
+ break;
+ case ID_OB:
+ base= FIRSTBASE;
+ while(base) {
+ if(base->object == (Object *)oops->id) break;
+ base= base->next;
+ }
+ if(base) {
+ if(G.obedit==NULL) set_active_base(base); /* editview.c */
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWOOPS, 0);
+ allqueue(REDRAWINFO, 1);
+ }
+ break;
+ case ID_MA:
+ ob= OBACT;
+ if(ob && oops->id) {
+ assign_material(ob, (Material *)oops->id, ob->actcol);
+ allqueue(REDRAWBUTSSHADING, 0);
+ scrarea_queue_winredraw(curarea);
+ }
+ break;
+
+ case ID_IM:
+ if(oops->id && G.sima) {
+ /* only set if the new image isnt alredy active */
+ if ((ID *)G.sima->image != oops->id) {
+ G.sima->image = (Image *)oops->id;
+ allqueue(REDRAWIMAGE, 0);
+ scrarea_queue_winredraw(curarea);
+ }
+ }
+ break;
+ /*
+ case ID_IP:
+ if(oops->id && G.sipo) {
+ *//* only set if the new ipo isnt alredy active *//*
+ if ((ID *)G.sipo->ipo != oops->id) {
+ G.sipo->ipo = (Ipo *)oops->id;
+ allqueue(REDRAWIPO, 0);
+ scrarea_queue_winredraw(curarea);
+ }
+ }
+ break;
+ */
+ }
+}
+
+void mouse_select_oops(void)
+{
+ Oops *oops;
+ extern float oopslastx, oopslasty; /* oops.c */
+
+ if(G.soops==0) return;
+
+ /* which oopses... */
+ oops= G.soops->oops.first;
+
+ oops= find_nearest_oops();
+ if(oops==0) return;
+
+ if((G.qual & LR_SHIFTKEY)==0) deselect_all_oops();
+
+ if(oops) {
+ /* last_seq= seq; */
+
+ if(G.qual==0) {
+ oops->flag |= SELECT;
+ }
+ else {
+ if(oops->flag & SELECT) {
+ oops->flag &= ~SELECT;
+ }
+ else {
+ oops->flag |= SELECT;
+ }
+ }
+
+ oopslastx= oops->x;
+ oopslasty= oops->y;
+
+ if(G.qual & LR_CTRLKEY) do_activate_oops(oops);
+ G.soops->lockpoin= oops;
+ }
+
+ oops_to_select_objects(); /* also redraw */
+ scrarea_queue_headredraw(curarea);
+
+ force_draw(1);
+
+ std_rmouse_transform(transform_oops);
+}
+
+void borderselect_oops(void)
+{
+ Oops *oops;
+ rcti rect;
+ rctf rectf, rq;
+ int val;
+ short mval[2];
+
+ if(G.soops==0) return;
+
+ val= get_border(&rect, 3);
+
+ if(val) {
+ mval[0]= rect.xmin;
+ mval[1]= rect.ymin;
+ areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
+ mval[0]= rect.xmax;
+ mval[1]= rect.ymax;
+ areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
+
+ oops= G.soops->oops.first;
+ while(oops) {
+ if(oops->hide == 0) {
+
+ rq.xmin= oops->x;
+ rq.xmax= oops->x+OOPSX;
+ rq.ymin= oops->y;
+ rq.ymax= oops->y+OOPSY;
+
+ if(BLI_isect_rctf(&rq, &rectf, 0)) {
+ if(val==LEFTMOUSE) {
+ oops->flag |= SELECT;
+ }
+ else {
+ oops->flag &= ~SELECT;
+ }
+ }
+ }
+ oops= oops->next;
+ }
+
+ oops_to_select_objects(); /* also redraw */
+ }
+}
+
+static void select_oops_lib(ID *id)
+{
+ Oops *oops;
+
+ oops= G.soops->oops.first;
+ while(oops) {
+ if(oops->hide==0) {
+ if(oops->id->lib== (Library *)id) oops->flag |= OOPS_DOSELECT;
+ }
+ oops= oops->next;
+ }
+}
+
+void select_linked_oops(void)
+{
+ Oops *oops;
+ OopsLink *ol;
+
+ if(G.soops==0) return;
+
+ oops= G.soops->oops.first;
+ while(oops) {
+ if(oops->hide==0) {
+ if(oops->flag & SELECT) {
+ if(oops->type==ID_LI) select_oops_lib(oops->id);
+ ol= oops->link.first;
+ while(ol) {
+ if(ol->to && ol->to->hide==0) ol->to->flag |= OOPS_DOSELECT;
+ ol= ol->next;
+ }
+ }
+ }
+ oops= oops->next;
+ }
+
+ oops= G.soops->oops.first;
+ while(oops) {
+ if(oops->hide==0) {
+ if(oops->flag & OOPS_DOSELECT) {
+ oops->flag |= SELECT;
+ oops->flag &= ~OOPS_DOSELECT;
+ }
+ }
+ oops= oops->next;
+ }
+
+ oops_to_select_objects(); /* also redraw */
+
+}
+
+void select_backlinked_oops(void)
+{
+ Oops *oops;
+ OopsLink *ol;
+
+ if(G.soops==0) return;
+
+ oops= G.soops->oops.first;
+ while(oops) {
+ if(oops->hide==0) {
+ if( (oops->flag & SELECT)==0) {
+ ol= oops->link.first;
+ while(ol) {
+ if(ol->to && ol->to->hide==0) {
+ if(ol->to->flag & SELECT) oops->flag |= OOPS_DOSELECT;
+ }
+ ol= ol->next;
+ }
+ }
+ }
+ oops= oops->next;
+ }
+
+ oops= G.soops->oops.first;
+ while(oops) {
+ if(oops->hide==0) {
+ if(oops->flag & OOPS_DOSELECT) {
+ oops->flag |= SELECT;
+ oops->flag &= ~OOPS_DOSELECT;
+ }
+ }
+ oops= oops->next;
+ }
+
+ oops_to_select_objects(); /* also redraw */
+
+}
+
+
+void clever_numbuts_oops()
+{
+ Oops *oops;
+ Object *ob;
+ char str1[10];
+ static char naam[256];
+ static char naam2[256];
+ static short doit;
+ int len;
+
+ if(G.soops->lockpoin) {
+ oops= G.soops->lockpoin;
+ ob = (Object *)oops->id;
+ if(oops->type==ID_LI) strcpy(naam, ((Library *)oops->id)->name);
+ else strcpy(naam, oops->id->name);
+
+ strcpy(naam2, naam+2);
+ str1[0]= oops->id->name[0];
+ str1[1]= oops->id->name[1];
+ str1[2]= ':';
+ str1[3]= 0;
+ if(strcmp(str1, "SC:")==0) strcpy(str1, "SCE:");
+ else if(strcmp(str1, "SR:")==0) strcpy(str1, "SCR:");
+
+// if( GS(id->name)==ID_IP) len= 110;
+// else len= 120;
+ len = 110;
+
+ add_numbut(0, TEX, str1, 0, len, naam2, "Rename Object");
+ if((oops->type==ID_OB || oops->type==ID_ME) && ob->type != OB_EMPTY) {
+ // add_numbut(1, TEX, str1, 0, len, naam2, "Name Object");
+ add_numbut(1, TOG|SHO, "Rename Linked Data", 0, 0, &doit, "Rename corresponding Datablock as well");
+ do_clever_numbuts("Rename Datablock", 2, REDRAW);
+ } else {
+ do_clever_numbuts("Rename Datablock", 1, REDRAW);
+ }
+
+ rename_id((ID *)oops->id, naam2);
+ }
+}
diff --git a/source/blender/src/editscreen.c b/source/blender/src/editscreen.c
new file mode 100644
index 00000000000..b51f90cb490
--- /dev/null
+++ b/source/blender/src/editscreen.c
@@ -0,0 +1,3819 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * All screen functions that are related to the interface
+ * handling and drawing. Might be split up as well later...
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "nla.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h> /* isprint */
+#include <stdio.h>
+#include <math.h>
+
+#include "GHOST_Types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "PIL_time.h"
+
+#include "BMF_Api.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "DNA_action_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_sound_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BLO_writefile.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_blender.h"
+#include "BKE_screen.h"
+
+#ifdef WITH_VERSE
+#include "BKE_verse.h"
+#endif
+
+#include "BIF_cursors.h"
+#include "BIF_drawscene.h"
+#include "BIF_editsound.h"
+#include "BIF_glutil.h"
+#include "BIF_gl.h"
+#include "BIF_graphics.h"
+#include "BIF_interface.h"
+#include "BIF_interface_icons.h"
+#include "BIF_mainqueue.h"
+#include "BIF_mywindow.h"
+#include "BIF_previewrender.h"
+#include "BIF_renderwin.h"
+#include "BIF_retopo.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_toets.h"
+#include "BIF_toolbox.h"
+#include "BIF_usiblender.h"
+#include "BIF_keyval.h"
+#include "BIF_resources.h"
+
+#include "BSE_edit.h"
+#include "BSE_filesel.h"
+#include "BSE_headerbuttons.h"
+#include "BSE_seqaudio.h"
+#include "BSE_view.h"
+
+#include "BPY_extern.h"
+#include "mydevice.h"
+#include "blendef.h"
+
+#include "winlay.h"
+
+/* TIPS:
+ *
+ * - WATCH THE EDGES, VERTICES HAVE TO BE IN ORDER...
+ (lowest pointer first). Otherwise unpredictable effects!
+ * - problem: flags here are not nicely implemented. After usage
+ always reset to zero.
+ */
+
+/* comment added to test orange branch */
+
+static void testareas(void);
+static void area_autoplayscreen(void);
+static void wait_for_event(void);
+
+
+/* ********* Globals *********** */
+
+static Window *mainwin= NULL;
+static int prefsizx= 0, prefsizy= 0, prefstax= 0, prefstay= 0, start_maximized= 1;
+static short dodrawscreen= 1;
+static ScrArea *areawinar[MAXWIN];
+static ScrArea *g_activearea= NULL;
+short winqueue_break= 0;
+ScrArea *curarea= 0;
+
+/* prototypes -------------------*/
+int afterqtest(short win, unsigned short evt);
+unsigned short screen_qread(short *val, char *ascii);
+void add_to_mainqueue(Window *win, void *user_data, short evt, short val, char ascii);
+static void drawscredge_area(ScrArea *sa);
+
+/**********************************************************************/
+
+extern int textediting;
+
+static void screen_set_cursor(bScreen *sc)
+{
+ if (sc->winakt>3) {
+ ScrArea *sa= areawinar[sc->winakt];
+
+ set_cursor(sa->cursor);
+ } else {
+ set_cursor(CURSOR_STD);
+ }
+}
+
+void waitcursor(int val)
+{
+ if(G.curscreen) {
+ if(val) {
+ set_cursor(CURSOR_WAIT);
+ } else {
+ screen_set_cursor(G.curscreen);
+ }
+ }
+}
+
+static int choose_cursor(ScrArea *sa)
+{
+ if (sa->spacetype==SPACE_VIEW3D) {
+ if(G.obedit) return CURSOR_EDIT;
+ else if(G.f & (G_VERTEXPAINT|G_WEIGHTPAINT|G_TEXTUREPAINT))
+ return CURSOR_VPAINT;
+ else if(FACESEL_PAINT_TEST) return CURSOR_FACESEL;
+ else if(G.f & G_SCULPTMODE) return CURSOR_EDIT;
+ else return CURSOR_STD;
+ }
+ else if (sa->spacetype==SPACE_TEXT) {
+ return CURSOR_TEXTEDIT;
+ }
+ else {
+ return CURSOR_STD;
+ }
+}
+
+void wich_cursor(ScrArea *sa)
+{
+ sa->cursor= choose_cursor(sa);
+
+ /* well... the waitcursor() is not a state, so this call will cancel it out */
+ if(get_cursor()!=CURSOR_WAIT)
+ screen_set_cursor(G.curscreen);
+}
+
+
+void setcursor_space(int spacetype, short cur)
+{
+ bScreen *sc;
+ ScrArea *sa;
+
+ for (sc= G.main->screen.first; sc; sc= sc->id.next)
+ for (sa= sc->areabase.first; sa; sa= sa->next)
+ if(sa->spacetype==spacetype)
+ sa->cursor= cur;
+
+ screen_set_cursor(G.curscreen);
+}
+
+
+/* ********* IN/OUT ************* */
+
+void getmouseco_sc(short *mval) /* screen coordinates */
+{
+ getmouse(mval);
+}
+
+/* mouse_cursor called during a script (via Window.QHandle) need
+ * this function for getmouseco_areawin to work: */
+void set_g_activearea(ScrArea *sa)
+{
+ if (sa) g_activearea = sa;
+}
+
+void getmouseco_areawin(short *mval) /* internal area coordinates */
+{
+ getmouseco_sc(mval);
+
+ if(g_activearea && g_activearea->win) {
+ mval[0]-= g_activearea->winrct.xmin;
+ mval[1]-= g_activearea->winrct.ymin;
+ }
+}
+
+void getmouseco_headwin(short *mval) /* internal area coordinates */
+{
+ getmouseco_sc(mval);
+
+ if(g_activearea && g_activearea->headwin) {
+ mval[0]-= g_activearea->headrct.xmin;
+ mval[1]-= g_activearea->headrct.ymin;
+ }
+}
+
+void headerprint(char *str)
+{
+ if(curarea->headertype) {
+ areawinset(curarea->headwin);
+
+ headerbox(curarea);
+
+ BIF_ThemeColor(TH_MENU_TEXT); /* better than cpack(0x0) color no? (desoto) */
+ glRasterPos2i(20+curarea->headbutofs, 6);
+ BMF_DrawString(G.font, str);
+
+ curarea->head_swap= WIN_BACK_OK;
+ areawinset(curarea->win);
+ }
+ else {
+ // dunno... thats for later (ton)
+ }
+}
+
+/* *********** STUFF ************** */
+
+static int scredge_is_horizontal(ScrEdge *se)
+{
+ return (se->v1->vec.y == se->v2->vec.y);
+}
+
+static ScrEdge *screen_find_active_scredge(bScreen *sc, short *mval)
+{
+ ScrEdge *se;
+
+ for (se= sc->edgebase.first; se; se= se->next) {
+ if (scredge_is_horizontal(se)) {
+ short min, max;
+ min= MIN2(se->v1->vec.x, se->v2->vec.x);
+ max= MAX2(se->v1->vec.x, se->v2->vec.x);
+
+ if (abs(mval[1]-se->v1->vec.y)<=2 && mval[0] >= min && mval[0]<=max)
+ return se;
+ }
+ else {
+ short min, max;
+ min= MIN2(se->v1->vec.y, se->v2->vec.y);
+ max= MAX2(se->v1->vec.y, se->v2->vec.y);
+
+ if (abs(mval[0]-se->v1->vec.x)<=2 && mval[1] >= min && mval[1]<=max)
+ return se;
+ }
+ }
+
+ return NULL;
+}
+
+void areawinset(short win)
+{
+ if(win>3) {
+ curarea= areawinar[win];
+ if(curarea==0) {
+ printf("error in areawinar %d ,areawinset\n", win);
+ return;
+ }
+
+ BIF_SetTheme(curarea);
+
+ switch(curarea->spacetype) {
+ case SPACE_VIEW3D:
+ G.vd= curarea->spacedata.first;
+ break;
+ case SPACE_IPO:
+ G.sipo= curarea->spacedata.first;
+ G.v2d= &G.sipo->v2d;
+ break;
+ case SPACE_BUTS:
+ G.buts= curarea->spacedata.first;
+ G.v2d= &G.buts->v2d;
+ break;
+ case SPACE_SEQ: {
+ SpaceSeq *sseq= curarea->spacedata.first;
+ G.v2d= &sseq->v2d;
+ break;
+ }
+ case SPACE_OOPS:
+ G.soops= curarea->spacedata.first;
+ G.v2d= &G.soops->v2d;
+ break;
+ case SPACE_IMAGE:
+ G.sima= curarea->spacedata.first;
+ G.v2d= &G.sima->v2d;
+ break;
+ case SPACE_SOUND:
+ G.ssound= curarea->spacedata.first;
+ G.v2d= &G.ssound->v2d;
+ break;
+ case SPACE_ACTION:
+ G.saction= curarea->spacedata.first;
+ G.v2d= &G.saction->v2d;
+ break;
+ case SPACE_NLA:
+ G.snla= curarea->spacedata.first;
+ G.v2d= &G.snla->v2d;
+ break;
+ case SPACE_TIME:
+ {
+ SpaceTime *stime= curarea->spacedata.first;
+ G.v2d= &stime->v2d;
+ }
+ break;
+ case SPACE_NODE:
+ {
+ SpaceNode *snode= curarea->spacedata.first;
+ G.v2d= &snode->v2d;
+ }
+ break;
+ case SPACE_IMASEL:
+ {
+ SpaceImaSel *simasel= curarea->spacedata.first;
+ G.v2d= &simasel->v2d;
+ }
+ default:
+ break;
+ }
+ }
+
+ if(win) mywinset(win);
+}
+
+#define SCR_BACK 0.55
+#define SCR_ROUND 12
+
+void headerbox(ScrArea *area)
+{
+ float width= area->winx;
+ int active=0;
+
+ glClearColor(SCR_BACK, SCR_BACK, SCR_BACK, 0.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ active= area_is_active_area(area);
+
+ if(active) BIF_ThemeColor(TH_HEADER);
+ else BIF_ThemeColor(TH_HEADERDESEL);
+
+ /* weird values here... is because of window matrix that centers buttons */
+ if(area->headertype==HEADERTOP) {
+ uiSetRoundBox(3);
+ uiRoundBoxEmboss(-0.5+area->headbutofs, -10.0, width-1.5+area->headbutofs, HEADERY-2.0, SCR_ROUND, active);
+ }
+ else {
+ uiSetRoundBox(12);
+ uiRoundBoxEmboss(-0.5+area->headbutofs, -3.5, width-1.5+area->headbutofs, HEADERY+10, SCR_ROUND, active);
+ }
+
+ uiSetRoundBox(15);
+}
+
+int area_is_active_area(ScrArea *area)
+{
+ return (g_activearea && area==g_activearea);
+}
+
+void scrarea_do_headdraw(ScrArea *area)
+{
+ if (area->headertype) {
+ areawinset(area->headwin);
+
+ headerbox(area);
+
+ /* we make scissor test slightly smaller not to destroy rounded headers */
+ glScissor(area->headrct.xmin+5, area->headrct.ymin, area->winx-10, HEADERY);
+
+ switch(area->spacetype) {
+ case SPACE_FILE: file_buttons(); break;
+ case SPACE_INFO: info_buttons(); break;
+ case SPACE_VIEW3D: view3d_buttons(); break;
+ case SPACE_IPO: ipo_buttons(); break;
+ case SPACE_BUTS: buts_buttons(); break;
+ case SPACE_SEQ: seq_buttons(); break;
+ case SPACE_IMAGE: image_buttons(); break;
+ case SPACE_IMASEL: imasel_buttons(); break;
+ case SPACE_OOPS: oops_buttons(); break;
+ case SPACE_TEXT: text_buttons(); break;
+ case SPACE_SCRIPT:script_buttons(); break;
+ case SPACE_SOUND: sound_buttons(); break;
+ case SPACE_ACTION: action_buttons(); break;
+ case SPACE_NLA: nla_buttons(); break;
+ case SPACE_TIME: time_buttons(area); break;
+ case SPACE_NODE: node_buttons(area); break;
+ }
+ uiClearButLock();
+
+ //glScissor(area->winrct.xmin, area->winrct.xmax, area->winx, area->winy);
+ area->head_swap= WIN_BACK_OK;
+ }
+}
+void scrarea_do_headchange(ScrArea *area)
+{
+ float ofs= area->headbutofs;
+
+ if (area->headertype==HEADERDOWN) {
+ bwin_ortho2(area->headwin, -0.375+ofs, area->headrct.xmax-area->headrct.xmin-0.375+ofs, -3.375, area->headrct.ymax-area->headrct.ymin-3.375+1.0);
+ } else if (area->headertype==HEADERTOP) {
+ bwin_ortho2(area->headwin, -0.375+ofs, area->headrct.xmax-area->headrct.xmin-0.375+ofs, -2.375-1.0, area->headrct.ymax-area->headrct.ymin-2.375);
+ }
+}
+
+
+static void openheadwin(ScrArea *sa);
+static void closeheadwin(ScrArea *sa);
+
+static void scrarea_change_headertype(ScrArea *sa, int newtype)
+{
+ sa->headertype= newtype;
+
+ if (!newtype) {
+ if (sa->headwin) {
+ uiFreeBlocksWin(&sa->uiblocks, sa->headwin);
+ closeheadwin(sa);
+ }
+ } else {
+ if (!sa->headwin) {
+ openheadwin(sa);
+ }
+ }
+
+ testareas();
+ mainqenter(DRAWEDGES, 1);
+ winqueue_break= 1;
+}
+
+static void headmenu(ScrArea *sa)
+{
+ short val= pupmenu("Header %t|Top%x2|Bottom %x1|No Header %x0");
+
+ if(val> -1) {
+ scrarea_change_headertype(sa, val);
+ }
+}
+
+static void addqueue_ext(short win, unsigned short event, short val, char ascii)
+{
+ if (win<4 || !areawinar[win]) {
+ /* other win ids are for mainwin & renderwin */
+ }
+ else {
+ BWinEvent evt;
+ evt.event= event;
+ evt.val= val;
+ evt.ascii= ascii;
+
+ bwin_qadd(win, &evt);
+ }
+}
+
+void addqueue(short win, unsigned short event, short val)
+{
+ addqueue_ext(win, event, val, 0);
+}
+
+void scrarea_queue_winredraw(ScrArea *area)
+{
+ addqueue(area->win, REDRAW, 1);
+}
+void scrarea_queue_headredraw(ScrArea *area)
+{
+ if (area->headwin) addqueue(area->headwin, REDRAW, 1);
+}
+void scrarea_queue_redraw(ScrArea *area)
+{
+ scrarea_queue_winredraw(area);
+ scrarea_queue_headredraw(area);
+}
+
+static void scrollheader(ScrArea *area);
+static void scrarea_dispatch_header_events(ScrArea *sa)
+{
+ ScrArea *tempsa;
+ BWinEvent evt;
+ short do_redraw=0, do_change=0;
+
+ areawinset(sa->headwin);
+
+ while(bwin_qread(sa->headwin, &evt)) {
+ if(evt.val) {
+ if( uiDoBlocks(&curarea->uiblocks, evt.event)!=UI_NOTHING ) evt.event= 0;
+
+ switch(evt.event) {
+ case UI_BUT_EVENT:
+ do_headerbuttons(evt.val);
+ break;
+
+ case LEFTMOUSE:
+ if (G.qual & LR_CTRLKEY) {
+ window_lower(mainwin);
+ } else {
+ window_raise(mainwin);
+ }
+ break;
+
+ case MIDDLEMOUSE:
+ scrollheader(sa);
+ break;
+ case RIGHTMOUSE:
+ headmenu(sa);
+ break;
+ case REDRAW:
+ do_redraw= 1;
+ break;
+ case CHANGED:
+ sa->head_swap= 0;
+ do_change= 1;
+ do_redraw= 1;
+ break;
+ default:
+ if (winqueue_break == 0) {
+ scrarea_do_winhandle(sa, &evt);
+ if (winqueue_break == 0) areawinset(sa->headwin);
+ }
+ }
+
+ if(winqueue_break) return;
+ }
+ }
+
+ /* test: does window still exist? */
+ tempsa= areawinar[sa->headwin];
+ if(tempsa==0) return;
+
+ /* this functional separation does not work as well as i expected... */
+ if(do_change) scrarea_do_headchange(sa);
+ if(do_redraw) scrarea_do_headdraw(sa);
+}
+
+static void scrarea_dispatch_events(ScrArea *sa)
+{
+ ScrArea *tempsa;
+ BWinEvent evt;
+ short do_redraw=0, do_change=0;
+
+ if(sa!=curarea || sa->win!=mywinget()) areawinset(sa->win);
+
+ while(bwin_qread(sa->win, &evt)) {
+ if(evt.event==REDRAW) {
+ do_redraw= 1;
+ }
+ else if(evt.event==CHANGED) {
+ sa->win_swap= 0;
+ do_change= 1;
+ do_redraw= 1;
+ }
+ else {
+ scrarea_do_winhandle(sa, &evt);
+ }
+
+ if(winqueue_break) return;
+ }
+
+ /* test: does window still exist */
+ tempsa= areawinar[sa->win];
+ if(tempsa==0) return;
+
+ if (do_change || do_redraw) {
+ areawinset(sa->win);
+ if(do_change)
+ scrarea_do_winchange(curarea);
+ if(do_redraw)
+ scrarea_do_windraw(curarea);
+ }
+}
+
+/***/
+
+
+void markdirty_all()
+{
+ ScrArea *sa;
+ for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
+ if(sa->win) {
+ scrarea_queue_winredraw(sa);
+ sa->win_swap &= ~WIN_FRONT_OK;
+ }
+ if(sa->headwin) {
+ scrarea_queue_headredraw(sa);
+ sa->head_swap &= ~WIN_FRONT_OK;
+ }
+ }
+}
+
+/* but no redraw! */
+void markdirty_all_back(void)
+{
+ ScrArea *sa;
+
+ for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
+ if(sa->win) {
+ sa->win_swap &= ~WIN_BACK_OK;
+ }
+ if(sa->headwin) {
+ sa->head_swap &= ~WIN_BACK_OK;
+ }
+ }
+
+ /* if needed; backbuffer selection redraw */
+ if(G.vd) G.vd->flag |= V3D_NEEDBACKBUFDRAW;
+
+}
+
+void markdirty_win_back(short winid)
+{
+ ScrArea *sa= areawinar[winid];
+ if(sa) {
+ if(sa->win==winid) sa->win_swap &= ~WIN_BACK_OK;
+ else sa->head_swap &= ~WIN_BACK_OK;
+ }
+}
+
+
+int is_allowed_to_change_screen(bScreen *new)
+{
+ /* not when curscreen is full
+ * not when obedit && old->scene!=new->scene
+ */
+
+ if(new==0) return 0;
+ if(G.curscreen->full != SCREENNORMAL) return 0;
+ if(curarea->full) return 0;
+ if(G.obedit) {
+ if(G.curscreen->scene!=new->scene) return 0;
+ }
+ return 1;
+}
+
+void splash(void *data, int datasize, char *string)
+{
+ ImBuf *bbuf;
+ int oldwin;
+ short val;
+
+ bbuf= IMB_ibImageFromMemory((int *)data, datasize, IB_rect);
+
+ if (bbuf) {
+ oldwin = mywinget();
+ mywinset(G.curscreen->mainwin);
+
+ if (string) {
+ int x, y, maxy;
+ unsigned int *rect;
+
+ rect = bbuf->rect;
+ maxy = MIN2(bbuf->y, 18);
+
+ for (y = 0; y < maxy; y++) {
+ for (x = 0; x < bbuf->x; x++) {
+ *rect = 0xffffffff;
+ rect++;
+ }
+ }
+ }
+ glDrawBuffer(GL_FRONT);
+
+ uiDrawBoxShadow(200, (prefsizx-bbuf->x)/2, (prefsizy-bbuf->y)/2, (prefsizx+bbuf->x)/2, (prefsizy+bbuf->y)/2);
+
+ glRasterPos2i((prefsizx-bbuf->x)/2, (prefsizy-bbuf->y)/2);
+ glDrawPixels(bbuf->x, bbuf->y, GL_RGBA, GL_UNSIGNED_BYTE, bbuf->rect);
+
+ if (string) {
+ void *font;
+ int width;
+
+ if (BMF_GetStringWidth(font= G.font, string) > bbuf->x)
+ if (BMF_GetStringWidth(font= G.fonts, string) > bbuf->x)
+ font= G.fontss;
+
+ width= BMF_GetStringWidth(font, string);
+
+ glColor3ub(0, 0, 0);
+ glRasterPos2i((prefsizx-width)/2, (prefsizy-bbuf->y)/2 + 6);
+ BMF_DrawString(font, string);
+ }
+
+ bglFlush();
+ glDrawBuffer(GL_BACK);
+
+ IMB_freeImBuf(bbuf);
+
+ // flush input buffers ....
+ // this might break some things
+
+ while (get_mbut()) {
+ BIF_wait_for_statechange();
+ }
+ while(qtest()) {
+ extern_qread(&val);
+ }
+
+ wait_for_event();
+
+ mywinset(oldwin);
+ markdirty_all();
+ mainqenter(DRAWEDGES, 1);
+ }
+}
+
+static void moveareas(ScrEdge *edge);
+static void joinarea_interactive(ScrArea *area, ScrEdge *onedge);
+static void splitarea_interactive(ScrArea *area, ScrEdge *onedge);
+static ScrArea *test_edge_area(ScrArea *sa, ScrEdge *se);
+static ScrEdge *screen_findedge(bScreen *sc, ScrVert *v1, ScrVert *v2);
+
+static int isjoinable(ScrArea *area, ScrEdge *onedge)
+{
+ struct ScrArea *sa1 = area, *sa2;
+ struct ScrEdge *se;
+
+ sa1 = test_edge_area(sa1, onedge);
+ if(sa1==0) return 0;
+
+ /* find directions with same edge */
+ sa2= G.curscreen->areabase.first;
+ while(sa2) {
+ if(sa2 != sa1) {
+ se= screen_findedge(G.curscreen, sa2->v1, sa2->v2);
+ if(onedge==se) return 1;
+ se= screen_findedge(G.curscreen, sa2->v2, sa2->v3);
+ if(onedge==se) return 1;
+ se= screen_findedge(G.curscreen, sa2->v3, sa2->v4);
+ if(onedge==se) return 1;
+ se= screen_findedge(G.curscreen, sa2->v4, sa2->v1);
+ if(onedge==se) return 1;
+ }
+ sa2= sa2->next;
+ }
+
+ return 0;
+}
+
+static void screen_edge_edit_event(ScrArea *actarea, ScrEdge *actedge, short evt, short val)
+{
+ if (val) {
+ // don't allow users to edit full screens
+ if (actarea && actarea->full)
+ return;
+
+ if (evt==LEFTMOUSE) {
+ moveareas(actedge);
+ } else if (evt==MIDDLEMOUSE || evt==RIGHTMOUSE) {
+ int edgeop;
+ char str[64] = "Split Area%x1|";
+
+ if(isjoinable(actarea, actedge)) strcat(str, "Join Areas%x2|");
+ if (actarea->headertype) strcat(str, "No Header%x3");
+ else strcat(str, "Add Header%x3");
+
+ edgeop= pupmenu(str);
+ if (edgeop==1) splitarea_interactive(actarea, actedge);
+ else if (edgeop==2) joinarea_interactive(actarea, actedge);
+ else if (edgeop==3) scrarea_change_headertype(actarea,
+ actarea->headertype?0:HEADERDOWN);
+ }
+ else blenderqread(evt, val); // global hotkeys
+ }
+}
+
+/***/
+
+extern void mywindow_init_mainwin(Window *win, int orx, int ory, int sizex, int sizey);
+void test_scale_screen(bScreen *);
+
+static void resize_screens(int x, int y, int w, int h) {
+ prefstax= x;
+ prefstay= y;
+ prefsizx= w;
+ prefsizy= h;
+
+ test_scale_screen(G.curscreen);
+ testareas();
+}
+
+static void init_mainwin(void)
+{
+ int orx, ory, sizex, sizey;
+
+ glEnable(GL_SCISSOR_TEST);
+
+ window_get_position(mainwin, &orx, &ory);
+ window_get_size(mainwin, &sizex, &sizey);
+
+ /* XXX, temporary stupid fix for minimize at windows */
+ if (!sizex && !sizey) {
+ return;
+ }
+
+ mywindow_init_mainwin(mainwin, orx, ory, sizex, sizey);
+ resize_screens(orx, ory, sizex, sizey);
+}
+
+/***/
+
+static short afterqueue[MAXQUEUE][3];
+static int nafterqitems= 0;
+
+void addafterqueue(short win, unsigned short evt, short val)
+{
+ if (nafterqitems<MAXQUEUE) {
+ int a;
+
+ /* only one afterqueue event of each type */
+ for(a=0; a<nafterqitems; a++) {
+ if(afterqueue[a][0]==win && afterqueue[a][1]==evt) {
+ afterqueue[a][2]= val;
+ return;
+ }
+ }
+ afterqueue[nafterqitems][0]= win;
+ afterqueue[nafterqitems][1]= evt;
+ afterqueue[nafterqitems][2]= val;
+ nafterqitems++;
+ }
+}
+
+static void append_afterqueue(void)
+{
+ while (nafterqitems) {
+ short win= afterqueue[nafterqitems-1][0];
+ unsigned short evt= afterqueue[nafterqitems-1][1];
+ short val= afterqueue[nafterqitems-1][2];
+
+ addqueue(win, evt, val);
+
+ nafterqitems--;
+ }
+}
+
+/* check for event in afterqueue, used in force_draw in space.c */
+int afterqtest(short win, unsigned short evt)
+{
+ int a;
+
+ for(a=0; a<nafterqitems; a++) {
+ if(afterqueue[a][0]==win && afterqueue[a][1]==evt) return 1;
+ }
+ return 0;
+}
+
+
+static char ext_load_str[256]= {0, 0};
+void add_readfile_event(char *filename)
+{
+ mainqenter(LOAD_FILE, 1);
+ strcpy(ext_load_str, filename);
+ BLI_convertstringcode(ext_load_str, G.sce, G.scene->r.cfra);
+}
+
+static short ext_reshape= 0, ext_redraw=0, ext_inputchange=0, ext_mousemove=0, ext_undopush=0;
+
+static void flush_extqd_events(void) {
+ if (ext_inputchange) {
+ mainqenter(INPUTCHANGE, ext_inputchange);
+ } else if (ext_reshape) {
+ mainqenter(RESHAPE, ext_redraw);
+ } else if (ext_redraw) {
+ mainqenter(REDRAW, ext_redraw);
+ } else if (ext_undopush) {
+ mainqenter(UNDOPUSH, ext_undopush);
+ } else if (ext_mousemove) {
+ short mouse[2];
+
+ getmouseco_sc(mouse);
+
+ mainqenter(MOUSEX, mouse[0]);
+ mainqenter(MOUSEY, mouse[1]);
+ }
+
+ ext_inputchange= ext_reshape= ext_redraw= ext_mousemove= ext_undopush= 0;
+}
+
+int qtest(void)
+{
+ if (!mainqtest()) {
+ winlay_process_events(0);
+ }
+
+ return mainqtest();
+}
+
+ /* return true if events are waiting anywhere */
+int anyqtest(void)
+{
+ ScrArea *sa;
+
+ if (nafterqitems || qtest()) return 1;
+
+ for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
+ if (bwin_qtest(sa->win)) return 1;
+ if (sa->headwin && bwin_qtest(sa->headwin)) return 1;
+ }
+
+ return 0;
+}
+
+static void wait_for_event(void)
+{
+ while (!mainqtest()) {
+ winlay_process_events(1);
+ }
+}
+
+unsigned short screen_qread(short *val, char *ascii)
+{
+ unsigned short event;
+
+ wait_for_event();
+
+ event= mainqread(val, ascii);
+
+ if(event==RIGHTSHIFTKEY || event==LEFTSHIFTKEY) {
+ if(*val) G.qual |= LR_SHIFTKEY;
+ else G.qual &= ~LR_SHIFTKEY;
+ }
+ else if(event==RIGHTALTKEY || event==LEFTALTKEY) {
+ if(*val) G.qual |= LR_ALTKEY;
+ else G.qual &= ~LR_ALTKEY;
+ }
+ else if(event==RIGHTCTRLKEY || event==LEFTCTRLKEY) {
+ if(*val) G.qual |= LR_CTRLKEY;
+ else G.qual &= ~LR_CTRLKEY;
+ }
+ else if(event==COMMANDKEY) { // OSX
+ if(*val) G.qual |= LR_COMMANDKEY;
+ else G.qual &= ~LR_COMMANDKEY;
+ }
+
+ return event;
+}
+
+unsigned short extern_qread_ext(short *val, char *ascii)
+{
+ /* stores last INPUTCHANGE and last REDRAW */
+ unsigned short event;
+
+ event= screen_qread(val, ascii);
+ if(event==RESHAPE) ext_reshape= *val;
+ else if(event==REDRAW) ext_redraw= *val;
+ else if(event==UNDOPUSH) ext_undopush= *val;
+ else if(event==INPUTCHANGE) ext_inputchange= *val;
+ else if(event==MOUSEY || event==MOUSEX) ext_mousemove= 1;
+ else if((G.qual & (LR_CTRLKEY|LR_ALTKEY)) && event==F3KEY) {
+ if(*val) {
+ BIF_screendump(0);
+ return ESCKEY; /* go out of menu, if that was set */
+ }
+ }
+
+ return event;
+}
+unsigned short extern_qread(short *val)
+{
+ char ascii;
+ return extern_qread_ext(val, &ascii);
+}
+
+int blender_test_break(void)
+{
+ if (!G.background) {
+ static double ltime= 0;
+ double curtime= PIL_check_seconds_timer();
+
+ /* only check for breaks every 10 milliseconds
+ * if we get called more often.
+ */
+ if ((curtime-ltime)>.001) {
+ ltime= curtime;
+
+ while(qtest()) {
+ short val;
+ if (extern_qread(&val) == ESCKEY) {
+ G.afbreek= 1;
+ }
+ }
+ }
+ }
+
+ return (G.afbreek==1);
+}
+
+void reset_autosave(void) {
+ window_set_timer(mainwin, U.savetime*60*1000, AUTOSAVE_FILE);
+}
+
+/* ************ handlers ************** */
+
+/* don't know yet how the handlers will evolve, for simplicity
+i choose for an array with eventcodes, this saves in a file!
+*/
+void add_screenhandler(bScreen *sc, short eventcode, short val)
+{
+ short a;
+
+ // find empty spot
+ for(a=0; a<SCREEN_MAXHANDLER; a+=2) {
+ if( sc->handler[a]==eventcode ) {
+ sc->handler[a+1]= val;
+ break;
+ }
+ else if( sc->handler[a]==0) {
+ sc->handler[a]= eventcode;
+ sc->handler[a+1]= val;
+ break;
+ }
+ }
+ if(a==SCREEN_MAXHANDLER) printf("error; max (4) screen handlers reached!\n");
+}
+
+void rem_screenhandler(bScreen *sc, short eventcode)
+{
+ short a;
+
+ for(a=0; a<SCREEN_MAXHANDLER; a+=2) {
+ if( sc->handler[a]==eventcode) {
+ sc->handler[a]= 0;
+ break;
+ }
+ }
+}
+
+int has_screenhandler(bScreen *sc, short eventcode)
+{
+ short a;
+
+ for(a=0; a<SCREEN_MAXHANDLER; a+=2) {
+ if( sc->handler[a]==eventcode) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static void animated_screen(bScreen *sc, short val)
+{
+ if (U.mixbufsize && (val & TIME_WITH_SEQ_AUDIO)) {
+ if(CFRA>=PEFRA) {
+ CFRA= PSFRA;
+ audiostream_stop();
+ audiostream_start( CFRA );
+ }
+ else {
+ int cfra = audiostream_pos();
+ if(cfra <= CFRA) CFRA++;
+ else CFRA= cfra;
+ }
+ }
+ else {
+ CFRA++;
+ if(CFRA > PEFRA) CFRA= PSFRA;
+ }
+
+ update_for_newframe_nodraw(1);
+
+ if(val & TIME_ALL_3D_WIN)
+ allqueue(REDRAWVIEW3D, 0);
+ else if(val & TIME_LEFTMOST_3D_WIN) {
+ ScrArea *sa= sc->areabase.first, *samin=NULL;
+ int min= 10000;
+ for(; sa; sa= sa->next) {
+ if(sa->spacetype==SPACE_VIEW3D) {
+ if(sa->winrct.xmin - sa->winrct.ymin < min) {
+ samin= sa;
+ min= sa->winrct.xmin - sa->winrct.ymin;
+ }
+ }
+ }
+ if(samin) scrarea_queue_winredraw(samin);
+ }
+ if(val & TIME_ALL_ANIM_WIN) allqueue(REDRAWANIM, 0);
+ if(val & TIME_ALL_BUTS_WIN) allqueue(REDRAWBUTSALL, 0);
+ if(val & TIME_SEQ) {
+ allqueue(REDRAWSEQ, 0);
+ }
+
+ allqueue(REDRAWTIME, 0);
+}
+
+/* because we still have to cope with subloops, this function is called
+in viewmove() for example too */
+
+/* returns 1 if something was handled */
+/* restricts to frames-per-second setting for frequency of updates */
+int do_screenhandlers(bScreen *sc)
+{
+ static double ltime=0.0;
+ double swaptime, time;
+ short a, done= 0;
+
+ time = PIL_check_seconds_timer();
+ swaptime= 1.0/FPS;
+
+ /* only now do the handlers */
+ if(swaptime < time-ltime || ltime==0.0) {
+
+ ltime= time;
+
+ for(a=0; a<SCREEN_MAXHANDLER; a+=2) {
+ switch(sc->handler[a]) {
+ case SCREEN_HANDLER_ANIM:
+ animated_screen(sc, sc->handler[a+1]);
+ done= 1;
+ break;
+ case SCREEN_HANDLER_PYTHON:
+ done= 1;
+ break;
+ case SCREEN_HANDLER_VERSE:
+#ifdef WITH_VERSE
+ b_verse_update();
+#endif
+
+ done= 1;
+ break;
+ }
+ }
+ }
+ else if( qtest()==0) PIL_sleep_ms(5); // 5 milliseconds pause, for idle
+
+ /* separate check for if we need to add to afterqueue */
+ /* is only to keep mainqueue awqke */
+ for(a=0; a<SCREEN_MAXHANDLER; a+=2) {
+ if(sc->handler[a]) {
+ ScrArea *sa= sc->areabase.first;
+ if(sa->headwin) addafterqueue(sa->headwin, SCREEN_HANDLER, 1);
+ else addafterqueue(sa->win, SCREEN_HANDLER, 1);
+ }
+ }
+
+ return done;
+}
+
+/* ****** end screen handlers ************ */
+
+static void drawscreen(void)
+{
+ ScrArea *sa;
+
+ mywinset(G.curscreen->mainwin);
+ myortho2(-0.375, (float)G.curscreen->sizex-0.375, -0.375, (float)G.curscreen->sizey-0.375);
+
+ sa= G.curscreen->areabase.first;
+ while(sa) {
+ drawscredge_area(sa);
+ sa= sa->next;
+ }
+
+ /* this double draw patch seems to be needed for certain sgi's (octane, indigo2) */
+#if defined(__sgi) || defined(__sun__) || defined( __sun ) || defined (__sparc) || defined (__sparc__)
+ glDrawBuffer(GL_FRONT);
+
+ sa= G.curscreen->areabase.first;
+ while(sa) {
+ drawscredge_area(sa);
+ sa= sa->next;
+ }
+
+ glDrawBuffer(GL_BACK);
+#endif
+}
+
+static void screen_dispatch_events(void) {
+ int events_remaining= 1;
+ ScrArea *sa;
+
+ window_make_active(mainwin); // added it here instead of screenmain (ton)
+
+ while (events_remaining) {
+ events_remaining= 0;
+
+ winqueue_break= 0;
+ for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
+ /* first check header, then rest. Header sometimes has initialization code */
+ if (sa->headwin && bwin_qtest(sa->headwin)) {
+ scrarea_dispatch_header_events(sa);
+ events_remaining= 1;
+ }
+ if (winqueue_break) break;
+
+ if (bwin_qtest(sa->win)) {
+ scrarea_dispatch_events(sa);
+ events_remaining= 1;
+ }
+ if (winqueue_break) break;
+ }
+
+ if (winqueue_break) break;
+ }
+
+ /* winqueue_break isnt the best of all solutions... but it is called on switching screens,
+ so drawing should wait for all redraw/init events to be handled */
+ if (winqueue_break==0) {
+ if (dodrawscreen) {
+ drawscreen();
+ dodrawscreen= 0;
+ }
+
+ screen_swapbuffers();
+ do_screenhandlers(G.curscreen);
+ }
+}
+
+static ScrArea *screen_find_area_for_pt(bScreen *sc, short *mval)
+{
+ ScrArea *sa;
+
+ /* hotspot area of 1 pixel extra */
+
+ for (sa= sc->areabase.first; sa; sa= sa->next) {
+ if( sa->totrct.xmin + 1 < mval[0] )
+ if( sa->totrct.ymin + 1 < mval[1] )
+ if( sa->totrct.xmax - 1 > mval[0] )
+ if( sa->totrct.ymax - 1 > mval[1] )
+ return sa;
+ }
+ return NULL;
+}
+
+/* ugly yah, will disappear on better event system */
+/* is called from interface.c after button events */
+static char delayed_undo_name[64];
+void screen_delayed_undo_push(char *name)
+{
+ strncpy(delayed_undo_name, name, 63);
+ mainqenter(UNDOPUSH, 1);
+}
+
+void screenmain(void)
+{
+ int has_input= 1;
+ int firsttime = 1;
+ int onload_script = 0;
+
+ window_make_active(mainwin);
+
+ while (1) {
+ unsigned short event;
+ short val, towin;
+ char ascii;
+
+ flush_extqd_events();
+ if (nafterqitems && !qtest()) {
+ append_afterqueue();
+ event= val= ascii= 0;
+ } else {
+ event= screen_qread(&val, &ascii);
+ }
+
+ // window_make_active(mainwin); // (only for inputchange, removed, (ton))
+
+ if (event==INPUTCHANGE) {
+ window_make_active(mainwin);
+ G.qual= get_qual();
+ }
+
+ /* If the main window is active, find the current active ScrArea
+ * underneath the mouse cursor, updating the headers & cursor for
+ * the appropriate internal window if things have changed.
+ *
+ * If the main window is not active, deactivate the internal
+ * window.
+ */
+ if (has_input || g_activearea==NULL || G.curscreen->winakt) {
+ ScrArea *newactarea;
+ int newactwin;
+ short mval[2];
+
+ getmouseco_sc(mval);
+ newactarea= screen_find_area_for_pt(G.curscreen, mval);
+
+ if (newactarea) {
+ if (BLI_in_rcti(&newactarea->headrct, mval[0], mval[1])) {
+ newactwin= newactarea->headwin;
+ set_cursor(CURSOR_STD);
+ } else {
+ newactwin= newactarea->win;
+ }
+ } else {
+ newactwin= 0;
+ }
+
+ if (newactarea && (newactarea != g_activearea)) {
+ if (g_activearea) scrarea_queue_headredraw(g_activearea);
+ scrarea_queue_headredraw(newactarea);
+ if (!(BLI_in_rcti(&newactarea->headrct, mval[0], mval[1]))) /* header always gets std cursor */
+ set_cursor(newactarea->cursor);
+ g_activearea= newactarea;
+ }
+ /* when you move mouse from header to window, buttons can remain hilited otherwise */
+ if(newactwin != G.curscreen->winakt) {
+ if (g_activearea) scrarea_queue_headredraw(g_activearea);
+ }
+ G.curscreen->winakt= newactwin;
+
+ if (G.curscreen->winakt) {
+ areawinset(G.curscreen->winakt);
+ if (!(BLI_in_rcti(&newactarea->headrct, mval[0], mval[1]))) /* header always gets std cursor */
+ set_cursor(choose_cursor(g_activearea));
+ }
+ }
+ else {
+ if (g_activearea) {
+ scrarea_queue_headredraw(g_activearea);
+ }
+ g_activearea= NULL;
+ G.curscreen->winakt= 0;
+ }
+
+ towin= 0;
+ if (event==WINCLOSE) {
+ exit_usiblender();
+ }
+ else if (event==DRAWEDGES) {
+ dodrawscreen= 1;
+ }
+ else if (event==RESHAPE) {
+ init_mainwin();
+ markdirty_all();
+ dodrawscreen= 1;
+ }
+ else if (event==REDRAW) {
+ markdirty_all();
+ dodrawscreen= 1;
+ }
+ else if( event==UNDOPUSH) {
+ BIF_undo_push(delayed_undo_name);
+ }
+ else if (event==AUTOSAVE_FILE) {
+ BIF_write_autosave();
+ }
+ else if (event==LOAD_FILE) {
+ BIF_read_file(ext_load_str);
+ sound_initialize_sounds();
+ }
+ else if ((event==ONLOAD_SCRIPT) && BPY_has_onload_script()) {
+ /* event queued in setup_app_data() in blender.c, where G.f is checked */
+ onload_script = 1;
+ firsttime = 1; /* see last 'if' in this function */
+ }
+ else {
+ towin= 1;
+ }
+
+ if (!g_activearea) {
+ towin= 0;
+ }
+ else if (event==QKEY) {
+ if((G.obedit && G.obedit->type==OB_FONT && g_activearea->spacetype==SPACE_VIEW3D)||g_activearea->spacetype==SPACE_TEXT||g_activearea->spacetype==SPACE_SCRIPT);
+ else {
+ if(val && (G.qual & LR_CTRLKEY)) {
+ if(okee("Quit Blender")) exit_usiblender();
+ }
+ towin= 0;
+ }
+ }
+ else if (event==RIGHTARROWKEY) {
+ if(textediting==0 && val && (G.qual & LR_CTRLKEY)) {
+ bScreen *sc= G.curscreen->id.next;
+
+ /* if screen is last, set it to first */
+ if(sc == NULL)
+ sc= G.main->screen.first;
+
+ if(is_allowed_to_change_screen(sc)) setscreen(sc);
+ g_activearea= NULL;
+ towin= 0;
+ }
+ }
+ else if (event==LEFTARROWKEY) {
+ if(textediting==0 && val && (G.qual & LR_CTRLKEY)) {
+ bScreen *sc= G.curscreen->id.prev;
+
+ /* if screen is first, set it to last */
+ if(sc == NULL)
+ sc= G.main->screen.last;
+
+ if(is_allowed_to_change_screen(sc)) setscreen(sc);
+ g_activearea= NULL;
+ towin= 0;
+ }
+ }
+ else if (!G.curscreen->winakt) {
+ ScrEdge *actedge;
+ short mval[2];
+
+ getmouseco_sc(mval);
+ actedge= screen_find_active_scredge(G.curscreen, mval);
+
+ if (actedge) {
+ if (scredge_is_horizontal(actedge)) {
+ set_cursor(CURSOR_Y_MOVE);
+ } else {
+ set_cursor(CURSOR_X_MOVE);
+ }
+ // this does global hotkeys too
+ screen_edge_edit_event(g_activearea, actedge, event, val);
+ } else {
+ set_cursor(CURSOR_STD);
+ }
+
+ towin= 0;
+ }
+ else if (event==ZKEY) {
+ if(val && G.qual==(LR_ALTKEY|LR_SHIFTKEY|LR_CTRLKEY)) {
+ extern void set_debug_swapbuffers_ovveride(bScreen *sc, int mode);
+
+ int which= pupmenu("Swapbuffers%t|Simple|Debug|DebugSwap|Redraw|Default|KillSwap");
+
+ switch (which) {
+ case 1: set_debug_swapbuffers_ovveride(G.curscreen, 's'); break;
+ case 2: set_debug_swapbuffers_ovveride(G.curscreen, 'd'); break;
+ case 3: set_debug_swapbuffers_ovveride(G.curscreen, 'f'); break;
+ case 4: set_debug_swapbuffers_ovveride(G.curscreen, 'r'); break;
+ case 5: set_debug_swapbuffers_ovveride(G.curscreen, 0); break;
+ case 6:
+ if (g_activearea) {
+ g_activearea->head_swap= 0;
+ g_activearea->win_swap= 0;
+ }
+ break;
+ }
+ towin= 0;
+ }
+ }
+ else if (event==SPACEKEY) {
+ if ((g_activearea->spacetype!=SPACE_TEXT) &&
+ ( !((g_activearea->spacetype==SPACE_VIEW3D) && ((G.obedit) && G.obedit->type==OB_FONT)) ) &&
+ val &&
+ (G.qual & LR_SHIFTKEY)) {
+ area_fullscreen();
+ g_activearea= NULL;
+ towin= 0;
+ }
+ else {
+ if((G.obedit && G.obedit->type==OB_FONT && g_activearea->spacetype==SPACE_VIEW3D)||g_activearea->spacetype==SPACE_TEXT||g_activearea->spacetype==SPACE_SCRIPT||g_activearea->spacetype==SPACE_SEQ);
+ else if(G.qual==0) {
+ if(val) toolbox_n();
+ towin= 0;
+ }
+ }
+ }
+ else if(ELEM(event, UPARROWKEY, DOWNARROWKEY)) {
+ if(val && (G.qual & LR_CTRLKEY)) {
+ area_fullscreen();
+ g_activearea= NULL;
+ towin= 0;
+ }
+ }
+
+ if (towin && event) {
+ if (blenderqread(event, val)) // the global keys
+ addqueue_ext(G.curscreen->winakt, event, val, ascii);
+ }
+
+ /* only process subwindow queue's once the
+ * main queue has been emptyied.
+ */
+ event= qtest();
+ if (event==0 || event==EXECUTE) {
+ screen_dispatch_events();
+ }
+
+ if(G.f & G_DEBUG) {
+ GLenum error = glGetError();
+ if (error)
+ printf("GL error: %s\n", gluErrorString(error));
+ }
+ /* Bizar hack. The event queue has mutated... */
+ if ( (firsttime) && (event == 0) ) {
+
+ if (onload_script) {
+ /* OnLoad scriptlink */
+ BPY_do_pyscript(&G.scene->id, SCRIPT_ONLOAD);
+ onload_script = 0;
+ }
+ else if (G.fileflags & G_FILE_AUTOPLAY) {
+ // SET AUTOPLAY in G.flags for
+ // other fileloads
+
+ G.flags |= G_FILE_AUTOPLAY;
+ area_autoplayscreen();
+
+ // Let The Games Begin
+ // fake a 'p' keypress
+
+ mainqenter(PKEY, 1);
+ } else {
+ extern char datatoc_splash_jpg[];
+ extern int datatoc_splash_jpg_size;
+
+ //if (! ((G.main->versionfile >= G.version)
+ // || G.save_over)) {
+ splash((void *)datatoc_splash_jpg,
+ datatoc_splash_jpg_size, NULL);
+ //}
+ }
+ firsttime = 0;
+ }
+ }
+}
+
+#if 0
+//#ifdef _WIN32 // FULLSCREEN
+void mainwindow_toggle_fullscreen(int fullscreen)
+{
+ if (fullscreen) U.uiflag |= USER_FLIPFULLSCREEN;
+ else U.uiflag &= ~USER_FLIPFULLSCREEN;
+
+ window_toggle_fullscreen(mainwin, fullscreen);
+}
+#endif
+
+void mainwindow_raise(void)
+{
+ if(mainwin)
+ window_raise(mainwin);
+}
+
+void mainwindow_make_active(void)
+{
+ if(mainwin)
+ window_make_active(mainwin);
+}
+
+void mainwindow_close(void)
+{
+ if(mainwin)
+ window_destroy(mainwin);
+ mainwin= NULL;
+}
+
+void mainwindow_set_filename_to_title(char *filename)
+{
+ char str[FILE_MAXDIR + FILE_MAXFILE];
+ char dir[FILE_MAXDIR];
+ char file[FILE_MAXFILE];
+
+ BLI_split_dirfile(filename, dir, file);
+
+ if(BLI_streq(file, ".B.blend") || filename[0] =='\0')
+ sprintf(str, "Blender");
+ else
+ sprintf(str, "Blender [%s]", filename);
+
+ window_set_title(mainwin, str);
+}
+
+/* ********* AREAS ************* */
+
+void setprefsize(int stax, int stay, int sizx, int sizy, int maximized)
+{
+ int scrwidth, scrheight;
+
+ winlay_get_screensize(&scrwidth, &scrheight);
+
+ if(sizx<320) sizx= 320;
+ if(sizy<256) sizy= 256;
+
+ if(stay+sizy>scrheight) {
+ fprintf(stderr," height prob \n");
+ sizy= scrheight-stay;
+ }
+
+ if(sizx<320 || sizy<256) {
+ printf("ERROR: illegal prefsize\n");
+ return;
+ }
+
+ prefstax= stax;
+ prefstay= stay;
+ prefsizx= sizx;
+ prefsizy= sizy;
+
+ start_maximized= maximized;
+}
+
+
+static ScrVert *screen_addvert(bScreen *sc, short x, short y)
+{
+ ScrVert *sv= MEM_callocN(sizeof(ScrVert), "addscrvert");
+ sv->vec.x= x;
+ sv->vec.y= y;
+
+ BLI_addtail(&sc->vertbase, sv);
+ return sv;
+}
+
+static void sortscrvert(ScrVert **v1, ScrVert **v2)
+{
+ ScrVert *tmp;
+
+ if (*v1 > *v2) {
+ tmp= *v1;
+ *v1= *v2;
+ *v2= tmp;
+ }
+}
+
+static ScrEdge *screen_addedge(bScreen *sc, ScrVert *v1, ScrVert *v2)
+{
+ ScrEdge *se= MEM_callocN(sizeof(ScrEdge), "addscredge");
+
+ sortscrvert(&v1, &v2);
+ se->v1= v1;
+ se->v2= v2;
+
+ BLI_addtail(&sc->edgebase, se);
+ return se;
+}
+
+static ScrEdge *screen_findedge(bScreen *sc, ScrVert *v1, ScrVert *v2)
+{
+ ScrEdge *se;
+
+ sortscrvert(&v1, &v2);
+ for (se= sc->edgebase.first; se; se= se->next)
+ if(se->v1==v1 && se->v2==v2)
+ return se;
+
+ return NULL;
+}
+
+static void removedouble_scrverts(void)
+{
+ ScrVert *v1, *verg;
+ ScrEdge *se;
+ ScrArea *sa;
+
+ verg= G.curscreen->vertbase.first;
+ while(verg) {
+ if(verg->newv==0) { /* !!! */
+ v1= verg->next;
+ while(v1) {
+ if(v1->newv==0) { /* !?! */
+ if(v1->vec.x==verg->vec.x && v1->vec.y==verg->vec.y) {
+ /* printf("doublevert\n"); */
+ v1->newv= verg;
+ }
+ }
+ v1= v1->next;
+ }
+ }
+ verg= verg->next;
+ }
+
+ /* replace pointers in edges and faces */
+ se= G.curscreen->edgebase.first;
+ while(se) {
+ if(se->v1->newv) se->v1= se->v1->newv;
+ if(se->v2->newv) se->v2= se->v2->newv;
+ /* edges changed: so.... */
+ sortscrvert(&(se->v1), &(se->v2));
+ se= se->next;
+ }
+ sa= G.curscreen->areabase.first;
+ while(sa) {
+ if(sa->v1->newv) sa->v1= sa->v1->newv;
+ if(sa->v2->newv) sa->v2= sa->v2->newv;
+ if(sa->v3->newv) sa->v3= sa->v3->newv;
+ if(sa->v4->newv) sa->v4= sa->v4->newv;
+ sa= sa->next;
+ }
+
+ /* remove */
+ verg= G.curscreen->vertbase.first;
+ while(verg) {
+ v1= verg->next;
+ if(verg->newv) {
+ BLI_remlink(&G.curscreen->vertbase, verg);
+ MEM_freeN(verg);
+ }
+ verg= v1;
+ }
+
+}
+
+static void removenotused_scrverts(void)
+{
+ ScrVert *sv, *svn;
+ ScrEdge *se;
+
+ /* we assume edges are ok */
+
+ se= G.curscreen->edgebase.first;
+ while(se) {
+ se->v1->flag= 1;
+ se->v2->flag= 1;
+ se= se->next;
+ }
+
+ sv= G.curscreen->vertbase.first;
+ while(sv) {
+ svn= sv->next;
+ if(sv->flag==0) {
+ BLI_remlink(&G.curscreen->vertbase, sv);
+ MEM_freeN(sv);
+ }
+ else sv->flag= 0;
+ sv= svn;
+ }
+}
+
+static void removedouble_scredges(void)
+{
+ ScrEdge *verg, *se, *sn;
+
+ /* compare */
+ verg= G.curscreen->edgebase.first;
+ while(verg) {
+ se= verg->next;
+ while(se) {
+ sn= se->next;
+ if(verg->v1==se->v1 && verg->v2==se->v2) {
+ BLI_remlink(&G.curscreen->edgebase, se);
+ MEM_freeN(se);
+ }
+ se= sn;
+ }
+ verg= verg->next;
+ }
+}
+
+static void removenotused_scredges(void)
+{
+ ScrEdge *se, *sen;
+ ScrArea *sa;
+ int a=0;
+
+ /* sets flags when edge is used in area */
+ sa= G.curscreen->areabase.first;
+ while(sa) {
+ se= screen_findedge(G.curscreen, sa->v1, sa->v2);
+ if(se==0) printf("error: area %d edge 1 bestaat niet\n", a);
+ else se->flag= 1;
+ se= screen_findedge(G.curscreen, sa->v2, sa->v3);
+ if(se==0) printf("error: area %d edge 2 bestaat niet\n", a);
+ else se->flag= 1;
+ se= screen_findedge(G.curscreen, sa->v3, sa->v4);
+ if(se==0) printf("error: area %d edge 3 bestaat niet\n", a);
+ else se->flag= 1;
+ se= screen_findedge(G.curscreen, sa->v4, sa->v1);
+ if(se==0) printf("error: area %d edge 4 bestaat niet\n", a);
+ else se->flag= 1;
+ sa= sa->next;
+ a++;
+ }
+ se= G.curscreen->edgebase.first;
+ while(se) {
+ sen= se->next;
+ if(se->flag==0) {
+ BLI_remlink(&G.curscreen->edgebase, se);
+ MEM_freeN(se);
+ }
+ else se->flag= 0;
+ se= sen;
+ }
+}
+
+void calc_arearcts(ScrArea *sa)
+{
+
+ if(sa->v1->vec.x>0) sa->totrct.xmin= sa->v1->vec.x+1;
+ else sa->totrct.xmin= sa->v1->vec.x;
+ if(sa->v4->vec.x<G.curscreen->sizex-1) sa->totrct.xmax= sa->v4->vec.x-1;
+ else sa->totrct.xmax= sa->v4->vec.x;
+
+ if(sa->v1->vec.y>0) sa->totrct.ymin= sa->v1->vec.y+1;
+ else sa->totrct.ymin= sa->v1->vec.y;
+ if(sa->v2->vec.y<G.curscreen->sizey-1) sa->totrct.ymax= sa->v2->vec.y-1;
+ else sa->totrct.ymax= sa->v2->vec.y;
+
+ sa->winrct= sa->totrct;
+ sa->headrct= sa->totrct;
+ if(sa->headertype) {
+ if(sa->headertype==HEADERDOWN) {
+ sa->headrct.ymax= sa->headrct.ymin+HEADERY;
+ sa->winrct.ymin= sa->headrct.ymax+1;
+ }
+ else if(sa->headertype==HEADERTOP) {
+ sa->headrct.ymin= sa->headrct.ymax-HEADERY;
+ sa->winrct.ymax= sa->headrct.ymin-1;
+ }
+ }
+ else {
+ sa->headrct.ymax= sa->headrct.ymin;
+ }
+ if(sa->winrct.ymin>sa->winrct.ymax) sa->winrct.ymin= sa->winrct.ymax;
+
+ /* for speedup */
+ sa->winx= sa->winrct.xmax-sa->winrct.xmin+1;
+ sa->winy= sa->winrct.ymax-sa->winrct.ymin+1;
+}
+
+static void openheadwin(ScrArea *sa)
+{
+ sa->headwin= myswinopen(G.curscreen->mainwin,
+ sa->headrct.xmin, sa->headrct.xmax, sa->headrct.ymin, sa->headrct.ymax);
+
+ glMatrixMode(GL_MODELVIEW);
+
+ areawinar[sa->headwin]= sa; /* otherwise addqueue does not work */
+
+ scrarea_do_headchange(sa); /* headchange is no callback, apply right away. this is for render-to-imagewindow... this can be called on startup by sequencer, which invokes redraw before all events are handled. bad stuff... */
+ addqueue(sa->headwin, CHANGED, 1);
+}
+
+static void openareawin(ScrArea *sa)
+{
+ sa->win= myswinopen(G.curscreen->mainwin,
+ sa->winrct.xmin, sa->winrct.xmax, sa->winrct.ymin, sa->winrct.ymax);
+
+ areawinar[sa->win]= sa; /* otherwise addqueue does not work */
+ addqueue(sa->win, CHANGED, 1);
+}
+
+static void closeheadwin(ScrArea *sa)
+{
+ if(sa->headwin) mywinclose(sa->headwin);
+ sa->headwin= 0;
+}
+
+static void closeareawin(ScrArea *sa)
+{
+ uiFreeBlocksWin(&sa->uiblocks, sa->win);
+
+ if(sa->win) mywinclose(sa->win);
+ sa->win= 0;
+}
+
+static void del_area(ScrArea *sa)
+{
+ closeareawin(sa);
+ closeheadwin(sa);
+
+ freespacelist(sa);
+
+ uiFreeBlocks(&sa->uiblocks);
+ uiFreePanels(&sa->panels);
+
+ BPY_free_scriptlink(&sa->scriptlink);
+
+ if(sa==curarea) curarea= NULL;
+ if(sa==g_activearea) g_activearea= NULL;
+}
+
+/* sa2 to sa1, we swap spaces for fullscreen to keep all allocated data */
+static void copy_areadata(ScrArea *sa1, ScrArea *sa2, int swap_space)
+{
+ Panel *pa1, *pa2, *patab;
+ ScriptLink *slink1 = &sa1->scriptlink, *slink2 = &sa2->scriptlink;
+
+ sa1->headertype= sa2->headertype;
+ sa1->spacetype= sa2->spacetype;
+ Mat4CpyMat4(sa1->winmat, sa2->winmat);
+
+ if(swap_space) {
+ SWAP(ListBase, sa1->spacedata, sa2->spacedata);
+ /* exception: ensure preview is reset */
+ if(sa1->spacetype==SPACE_VIEW3D)
+ BIF_view3d_previewrender_free(sa1->spacedata.first);
+ }
+ else {
+ freespacelist(sa1);
+ duplicatespacelist(sa1, &sa1->spacedata, &sa2->spacedata);
+ }
+
+ BLI_freelistN(&sa1->panels);
+ duplicatelist(&sa1->panels, &sa2->panels);
+
+ /* space handler script links */
+ if (slink1->totscript) {
+ MEM_freeN(slink1->scripts);
+ MEM_freeN(slink1->flag);
+ slink1->totscript = 0;
+ }
+ if (slink2->totscript) {
+ slink1->scripts = MEM_dupallocN(slink2->scripts);
+ slink1->flag = MEM_dupallocN(slink2->flag);
+ slink1->totscript = slink2->totscript;
+ }
+
+ /* copy pointers */
+ pa1= sa1->panels.first;
+ while(pa1) {
+
+ patab= sa1->panels.first;
+ pa2= sa2->panels.first;
+ while(patab) {
+ if( pa1->paneltab == pa2) {
+ pa1->paneltab = patab;
+ break;
+ }
+ patab= patab->next;
+ pa2= pa2->next;
+ }
+ pa1= pa1->next;
+ }
+}
+
+static ScrArea *screen_addarea(bScreen *sc, ScrVert *v1, ScrVert *v2, ScrVert *v3, ScrVert *v4, short headertype, short spacetype)
+{
+ ScrArea *sa= MEM_callocN(sizeof(ScrArea), "addscrarea");
+ sa->cursor= CURSOR_STD;
+ sa->v1= v1;
+ sa->v2= v2;
+ sa->v3= v3;
+ sa->v4= v4;
+ sa->headertype= headertype;
+ sa->spacetype= spacetype;
+
+ calc_arearcts(sa);
+
+ if (sa->headertype) openheadwin(sa);
+ openareawin(sa);
+
+ BLI_addtail(&sc->areabase, sa);
+ return sa;
+}
+
+static int rcti_eq(rcti *a, rcti *b) {
+ return ((a->xmin==b->xmin && a->xmax==b->xmax) &&
+ (a->ymin==b->ymin && a->ymax==b->ymax));
+}
+
+static void testareas(void)
+{
+ ScrArea *sa, *next;
+
+ /* test for header, if removed, or moved */
+ /* test for window, if removed, or moved */
+
+ for(sa= G.curscreen->areabase.first; sa; sa= sa->next) {
+ rcti oldhr= sa->headrct;
+ rcti oldwr= sa->winrct;
+
+ next= sa->next;
+
+ calc_arearcts(sa);
+
+ /* ilegally scaled down area.... */
+ if(sa->totrct.xmin>=sa->totrct.xmax || sa->totrct.ymin>=sa->totrct.ymax) {
+ del_area(sa);
+ BLI_remlink(&G.curscreen->areabase, sa);
+ MEM_freeN(sa);
+ printf("Warning, removed zero sized window from screen %s\n", G.curscreen->id.name+2);
+ }
+ else {
+ /* test header */
+ if (sa->headwin) {
+ if (!rcti_eq(&oldhr, &sa->headrct)) {
+ mywinposition(sa->headwin, sa->headrct.xmin, sa->headrct.xmax, sa->headrct.ymin, sa->headrct.ymax);
+ addqueue(sa->headwin, CHANGED, 1);
+ }
+
+ if(sa->headbutlen<sa->winx) {
+ sa->headbutofs= 0;
+ addqueue(sa->headwin, CHANGED, 1);
+ }
+ else if(sa->headbutofs+sa->winx > sa->headbutlen) {
+ sa->headbutofs= sa->headbutlen-sa->winx;
+ addqueue(sa->headwin, CHANGED, 1);
+ }
+ }
+
+ if (!rcti_eq(&oldwr, &sa->winrct)) {
+ SpaceLink *sl= sa->spacedata.first;
+
+ mywinposition(sa->win, sa->winrct.xmin, sa->winrct.xmax, sa->winrct.ymin, sa->winrct.ymax);
+ addqueue(sa->win, CHANGED, 1);
+
+ /* exception handling... probably we need generic event */
+ for(; sl; sl= sl->next)
+ if(sl->spacetype==SPACE_VIEW3D)
+ BIF_view3d_previewrender_free((View3D *)sl);
+ }
+ }
+ }
+
+ /* remake global windowarray */
+ memset(areawinar, 0, sizeof(void *)*MAXWIN);
+ for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
+ areawinar[sa->headwin]= sa;
+ areawinar[sa->win]= sa;
+ }
+
+ /* test if winakt is OK */
+ if( areawinar[G.curscreen->winakt]==0) G.curscreen->winakt= 0;
+}
+
+static ScrArea *test_edge_area(ScrArea *sa, ScrEdge *se)
+{
+ /* test if edge is in area, if not,
+ then find an area that has it */
+
+ ScrEdge *se1=0, *se2=0, *se3=0, *se4=0;
+
+ if(sa) {
+ se1= screen_findedge(G.curscreen, sa->v1, sa->v2);
+ se2= screen_findedge(G.curscreen, sa->v2, sa->v3);
+ se3= screen_findedge(G.curscreen, sa->v3, sa->v4);
+ se4= screen_findedge(G.curscreen, sa->v4, sa->v1);
+ }
+ if(se1!=se && se2!=se && se3!=se && se4!=se) {
+
+ sa= G.curscreen->areabase.first;
+ while(sa) {
+ /* a bit optimise? */
+ if(se->v1==sa->v1 || se->v1==sa->v2 || se->v1==sa->v3 || se->v1==sa->v4) {
+ se1= screen_findedge(G.curscreen, sa->v1, sa->v2);
+ se2= screen_findedge(G.curscreen, sa->v2, sa->v3);
+ se3= screen_findedge(G.curscreen, sa->v3, sa->v4);
+ se4= screen_findedge(G.curscreen, sa->v4, sa->v1);
+ if(se1==se || se2==se || se3==se || se4==se) return sa;
+ }
+ sa= sa->next;
+ }
+ }
+
+ return sa; /* is null when not find */
+}
+
+ScrArea *closest_bigger_area(void)
+{
+ ScrArea *sa, *big=0;
+ float cent[3], vec[3],len, len1, len2, len3, dist=1000;
+ short mval[2];
+
+ getmouseco_sc(mval);
+
+ cent[0]= mval[0];
+ cent[1]= mval[1];
+ cent[2]= vec[2]= 0;
+
+ sa= G.curscreen->areabase.first;
+ while(sa) {
+ if(sa!=curarea) {
+ if(sa->winy>=curarea->winy) {
+
+ /* mimimum of the 4 corners */
+ vec[0]= sa->v1->vec.x; vec[1]= sa->v1->vec.y;
+ len= VecLenf(vec, cent);
+ vec[0]= sa->v2->vec.x; vec[1]= sa->v2->vec.y;
+ len1= VecLenf(vec, cent);
+ vec[0]= sa->v3->vec.x; vec[1]= sa->v3->vec.y;
+ len2= VecLenf(vec, cent);
+ vec[0]= sa->v4->vec.x; vec[1]= sa->v4->vec.y;
+ len3= VecLenf(vec, cent);
+
+ len= MIN4(len, len1, len2, len3);
+
+ /* plus center */
+ vec[0]= (sa->v2->vec.x+sa->v3->vec.x)/2;
+ vec[1]= (sa->v1->vec.y+sa->v2->vec.y)/2;
+
+ len+= 0.5*VecLenf(vec, cent);
+
+ /* min size */
+ len-= sa->winy+sa->winx;
+
+ if(len<dist) {
+ dist= len;
+ big= sa;
+ }
+ }
+ }
+ sa= sa->next;
+ }
+
+ if(big) return big;
+ else return curarea;
+}
+
+/* ************ SCREEN MANAGEMENT ************** */
+
+static int statechanged= 0;
+void BIF_wait_for_statechange(void)
+{
+ if (!statechanged) {
+ /* Safety, don't wait more than 0.1 seconds */
+ double stime= PIL_check_seconds_timer();
+ while (!statechanged) {
+ winlay_process_events(1);
+ if ((PIL_check_seconds_timer()-stime)>0.1) break;
+ }
+ statechanged= 0;
+ }
+ else PIL_sleep_ms(3); /* statechanged can be set '1' while holding mousebutton, causing locks */
+
+}
+void getmouse(short *mval)
+{
+ winlay_process_events(0);
+ window_get_mouse(mainwin, mval);
+}
+short get_qual(void)
+{
+ winlay_process_events(0);
+ return window_get_qual(mainwin);
+}
+short get_mbut(void)
+{
+ winlay_process_events(0);
+ return window_get_mbut(mainwin);
+}
+
+/* return values of tablet data related functions are documented
+ * in the Window struct, ghostwinlay.c */
+float get_pressure(void)
+{
+ winlay_process_events(0);
+ return window_get_pressure(mainwin);
+}
+void get_tilt(float *xtilt, float *ytilt)
+{
+ winlay_process_events(0);
+ window_get_tilt(mainwin, xtilt, ytilt);
+}
+short get_activedevice(void)
+{
+ winlay_process_events(0);
+ return window_get_activedevice(mainwin);
+}
+
+void add_to_mainqueue(Window *win, void *user_data, short evt, short val, char ascii)
+{
+
+ statechanged= 1;
+
+ /* accept the extended ascii set (ton) */
+ if( !val || ascii<32 ) {
+ ascii= '\0';
+ }
+
+ mainqenter_ext(evt, val, ascii);
+}
+
+/* ScrVert ordering in a ScrArea:
+
+2---------3
+| |
+| |
+1---------4
+
+*/
+
+static bScreen *addscreen(char *name) /* use setprefsize() if you want something else than a full windpw */
+{
+ /* this function sets variabele G.curscreen,
+ * that global is about used everywhere!
+ */
+ bScreen *sc;
+ ScrVert *sv1, *sv2, *sv3, *sv4;
+ short startx, starty, endx, endy;
+
+ sc= G.curscreen= alloc_libblock(&G.main->screen, ID_SCR, name);
+
+ if (!prefsizx) {
+ prefstax= 0;
+ prefstay= 0;
+
+ winlay_get_screensize(&prefsizx, &prefsizy);
+ }
+
+ startx= prefstax;
+ starty= prefstay;
+ endx= prefstax+prefsizx-1;
+ endy= prefstay+prefsizy-1;
+
+ sc->startx= startx; sc->starty= starty;
+ sc->endx= endx; sc->endy= endy;
+ sc->sizex= sc->endx-sc->startx+1;
+ sc->sizey= sc->endy-sc->starty+1;
+
+ sc->scene= G.scene;
+
+ if (!mainwin) {
+ if (G.windowstate == G_WINDOWSTATE_FULLSCREEN)
+ mainwin= window_open("Blender", sc->startx, sc->starty, sc->sizex, sc->sizey, G_WINDOWSTATE_FULLSCREEN);
+ else
+ mainwin= window_open("Blender", sc->startx, sc->starty, sc->sizex, sc->sizey, start_maximized);
+
+ if (!mainwin) {
+ printf("ERROR: Unable to open Blender window\n");
+ exit(1);
+ }
+
+ window_set_handler(mainwin, add_to_mainqueue, NULL);
+ init_mainwin();
+ mywinset(1);
+
+ /* for visual speed, but still needed? */
+ glClearColor(.55, .55, .55, 0.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ window_swap_buffers(mainwin);
+
+ /* this is unneeded and with large monitors can be a
+ * pain so commenting out */
+ /* warp_pointer(sc->sizex/2, sc->sizey/2); */
+
+ mainqenter(REDRAW, 1);
+ }
+
+ sc->mainwin= 1;
+
+ sv1= screen_addvert(sc, 0, 0);
+ sv2= screen_addvert(sc, 0, sc->endy-sc->starty);
+ sv3= screen_addvert(sc, sc->sizex-1, sc->sizey-1);
+ sv4= screen_addvert(sc, sc->sizex-1, 0);
+
+ screen_addedge(sc, sv1, sv2);
+ screen_addedge(sc, sv2, sv3);
+ screen_addedge(sc, sv3, sv4);
+ screen_addedge(sc, sv4, sv1);
+
+ screen_addarea(sc, sv1, sv2, sv3, sv4, HEADERDOWN, SPACE_INFO);
+
+ G.curscreen= sc;
+
+ return sc;
+}
+
+void setscreen(bScreen *sc)
+{
+ bScreen *sc1;
+ ScrArea *sa;
+ short mval[2];
+
+ if(sc->full) { /* find associated full */
+ sc1= G.main->screen.first;
+ while(sc1) {
+ sa= sc1->areabase.first;
+ if(sa->full==sc) {
+ sc= sc1;
+ break;
+ }
+ sc1= sc1->id.next;
+ }
+ if(sc1==0) printf("setscreen error\n");
+ }
+
+ /* de-activate G.curscreen */
+ if (G.curscreen && G.curscreen != sc) {
+ sa= G.curscreen->areabase.first;
+ while(sa) {
+ if(sa->win) mywinclose(sa->win);
+ sa->win= 0;
+ if(sa->headwin) mywinclose(sa->headwin);
+ sa->headwin= 0;
+
+ uiFreeBlocks(&sa->uiblocks);
+
+ sa= sa->next;
+ }
+ }
+ else if(G.curscreen) markdirty_all(); /* at least redraw */
+
+ if (G.curscreen != sc) {
+ mywinset(sc->mainwin);
+ }
+
+ G.curscreen= sc;
+
+ for (sa= sc->areabase.first; sa; sa= sa->next) {
+ /* XXX, fixme zr */
+/* if (sa->win || sa->headwin) */
+/* printf("error in setscreen (win): %d, %d\n", sa->win, sa->headwin); */
+ if (!sa->win)
+ openareawin(sa);
+ if (!sa->headwin && sa->headertype)
+ openheadwin(sa);
+ }
+
+ /* recalculate winakt */
+ getmouseco_sc(mval);
+
+ test_scale_screen(sc);
+ testareas();
+
+ for(sa= sc->areabase.first; sa; sa= sa->next) {
+ SpaceLink *sl;
+
+ for(sl= sa->spacedata.first; sl; sl= sl->next) {
+ sl->area= sa;
+
+ if(sl->spacetype==SPACE_OOPS) {
+ SpaceOops *soops= (SpaceOops *) sl;
+
+ /* patch for old files */
+ if(soops->v2d.cur.xmin==soops->v2d.cur.xmax) {
+ init_v2d_oops(sa, soops);
+ }
+ }
+ else if(sl->spacetype==SPACE_BUTS) {
+ SpaceButs *sbuts= (SpaceButs *)sl;
+ sbuts->re_align= 1; // force an align call, maybe new panels were added, also for after file reading
+ }
+ }
+
+ sa->cursor= CURSOR_STD;
+ }
+
+ if(G.scene!=sc->scene)
+ set_scene(sc->scene);
+
+ countall();
+
+ G.curscreen->winakt= 0;
+ curarea= sc->areabase.first;
+
+ mainqenter(DRAWEDGES, 1);
+ dodrawscreen= 1; /* patch! even gets lost,,,? */
+
+ winqueue_break= 1; /* means leave queue everywhere */
+}
+
+static void splitarea(ScrArea *sa, char dir, float fac);
+
+void area_fullscreen(void) /* with curarea */
+{
+ /* this function toggles: if area is full then the parent will be restored */
+ bScreen *sc, *oldscreen;
+ ScrArea *sa, *newa, *old;
+ short headertype, fulltype;
+
+ if(curarea->full) {
+ sc= curarea->full; /* the old screen */
+ fulltype = sc->full;
+
+ // refuse to go out of SCREENAUTOPLAY as long as G_FLAGS_AUTOPLAY
+ // is set
+
+ if (fulltype != SCREENAUTOPLAY || (G.flags & G_FILE_AUTOPLAY) == 0) {
+ sc->full= 0;
+
+ /* find old area */
+ old= sc->areabase.first;
+ while(old) {
+ if(old->full) break;
+ old= old->next;
+ }
+ if(old==0) {error("something wrong in areafullscreen"); return;}
+
+ if (fulltype == SCREENAUTOPLAY) {
+ // in autoplay screens the headers are disabled by
+ // default. So use the old headertype instead
+ headertype = old->headertype;
+ } else {
+ // normal fullscreen. Use current headertype
+ headertype = curarea->headertype;
+ }
+
+ copy_areadata(old, curarea, 1); /* 1 = swap spacelist */
+ old->headertype = headertype;
+
+ old->full= 0;
+
+ unlink_screen(G.curscreen);
+ free_libblock(&G.main->screen, G.curscreen);
+ G.curscreen= NULL;
+
+ setscreen(sc);
+ }
+
+ }
+ else {
+ /* is there only 1 area? */
+ if(G.curscreen->areabase.first==G.curscreen->areabase.last) return;
+ if(curarea->spacetype==SPACE_INFO) return;
+
+ G.curscreen->full = SCREENFULL;
+
+ old= curarea;
+ oldscreen= G.curscreen;
+ sc= addscreen("temp"); /* this sets G.curscreen */
+
+ splitarea( (ScrArea *)sc->areabase.first, 'h', 0.99);
+ newa= sc->areabase.first;
+ newspace(newa->next, SPACE_INFO);
+
+ curarea= old;
+ G.curscreen= oldscreen; /* needed because of setscreen */
+
+ /* copy area */
+ copy_areadata(newa, curarea, 1); /* 1 = swap spacelist */
+
+ curarea->full= oldscreen;
+ newa->full= oldscreen;
+ newa->next->full= oldscreen;
+
+ setscreen(sc);
+ wich_cursor(newa);
+ }
+
+ if(curarea->full)
+ retopo_force_update();
+
+ /* there's also events in queue for this, but we call fullscreen for render output
+ now, and that doesn't go back to queue. Bad code, but doesn't hurt... (ton) */
+ for(sa= G.curscreen->areabase.first; sa; sa= sa->next) {
+ scrarea_do_headchange(sa);
+ scrarea_do_winchange(sa);
+ }
+ /* bad code #2: setscreen() ends with first area active. fullscreen render assumes this too */
+ curarea= sc->areabase.first;
+
+ if(!curarea->full)
+ retopo_force_update();
+}
+
+static void area_autoplayscreen(void)
+{
+ bScreen *sc, *oldscreen;
+ ScrArea *newa, *old, *sa;
+
+ if (curarea->full) {
+ area_fullscreen();
+ }
+
+ if (curarea->full == NULL) {
+ sa = G.curscreen->areabase.first;
+ while (sa) {
+ if (sa->spacetype == SPACE_VIEW3D) {
+ break;
+ }
+ sa= sa->next;
+ }
+
+ if (sa) {
+ areawinset(sa->win);
+ G.curscreen->full = SCREENAUTOPLAY;
+
+ old= curarea;
+ oldscreen= G.curscreen;
+ sc= addscreen("temp"); /* this sets G.curscreen */
+
+ newa= sc->areabase.first;
+
+ curarea= old;
+ G.curscreen= oldscreen; /* because of setscreen */
+
+ /* copy area settings */
+ copy_areadata(newa, curarea, 1); /* swap spacedata */
+ newa->headertype= 0;
+
+ curarea->full= oldscreen;
+ newa->full= oldscreen;
+
+ setscreen(sc);
+ wich_cursor(newa);
+ }
+ }
+}
+
+static void copy_screen(bScreen *to, bScreen *from)
+{
+ ScrVert *s1, *s2;
+ ScrEdge *se;
+ ScrArea *sa, *saf;
+
+ /* free 'to' */
+ free_screen(to);
+ winqueue_break= 1; /* leave queues everywhere */
+
+ duplicatelist(&to->vertbase, &from->vertbase);
+ duplicatelist(&to->edgebase, &from->edgebase);
+ duplicatelist(&to->areabase, &from->areabase);
+
+ s1= from->vertbase.first;
+ s2= to->vertbase.first;
+ while(s1) {
+ s1->newv= s2;
+ s2= s2->next;
+ s1= s1->next;
+ }
+ se= to->edgebase.first;
+ while(se) {
+ se->v1= se->v1->newv;
+ se->v2= se->v2->newv;
+ sortscrvert(&(se->v1), &(se->v2));
+ se= se->next;
+ }
+
+ sa= to->areabase.first;
+ saf= from->areabase.first;
+ while(sa) {
+ sa->v1= sa->v1->newv;
+ sa->v2= sa->v2->newv;
+ sa->v3= sa->v3->newv;
+ sa->v4= sa->v4->newv;
+ sa->win= 0;
+ sa->headwin= 0;
+
+ sa->spacedata.first= sa->spacedata.last= NULL;
+ sa->uiblocks.first= sa->uiblocks.last= NULL;
+ sa->panels.first= sa->panels.last= NULL;
+ sa->scriptlink.totscript= 0;
+
+ copy_areadata(sa, saf, 0);
+
+ sa= sa->next;
+ saf= saf->next;
+ }
+
+ /* put at zero (needed?) */
+ s1= from->vertbase.first;
+ while(s1) {
+ s1->newv= 0;
+ s1= s1->next;
+ }
+}
+
+void duplicate_screen(void)
+{
+ bScreen *sc, *oldscreen;
+
+ if(G.curscreen->full != SCREENNORMAL) return;
+
+ /* make new screen: */
+
+ oldscreen= G.curscreen;
+ sc= addscreen(oldscreen->id.name+2); /* this sets G.curscreen */
+ copy_screen(sc, oldscreen);
+
+ G.curscreen= oldscreen;
+ setscreen(sc);
+
+}
+
+
+/* ************ END SCREEN MANAGEMENT ************** */
+/* ************ JOIN/SPLIT/MOVE ************** */
+
+typedef struct point{
+ float x,y;
+}_point;
+
+/* draw vertical shape visualising future joining (left as well
+ * right direction of future joining) */
+static void draw_horizontal_join_shape(ScrArea *sa, char dir)
+{
+ _point points[10];
+ short i;
+ float w, h;
+ float width = sa->v3->vec.x - sa->v1->vec.x;
+ float height = sa->v3->vec.y - sa->v1->vec.y;
+
+ if(height<width) {
+ h = height/8;
+ w = height/4;
+ }
+ else {
+ h = width/8;
+ w = width/4;
+ }
+
+ points[0].x = sa->v1->vec.x;
+ points[0].y = sa->v1->vec.y + height/2;
+
+ points[1].x = sa->v1->vec.x;
+ points[1].y = sa->v1->vec.y;
+
+ points[2].x = sa->v4->vec.x - w;
+ points[2].y = sa->v4->vec.y;
+
+ points[3].x = sa->v4->vec.x - w;
+ points[3].y = sa->v4->vec.y + height/2 - 2*h;
+
+ points[4].x = sa->v4->vec.x - 2*w;
+ points[4].y = sa->v4->vec.y + height/2;
+
+ points[5].x = sa->v4->vec.x - w;
+ points[5].y = sa->v4->vec.y + height/2 + 2*h;
+
+ points[6].x = sa->v3->vec.x - w;
+ points[6].y = sa->v3->vec.y;
+
+ points[7].x = sa->v2->vec.x;
+ points[7].y = sa->v2->vec.y;
+
+ points[8].x = sa->v4->vec.x;
+ points[8].y = sa->v4->vec.y + height/2 - h;
+
+ points[9].x = sa->v4->vec.x;
+ points[9].y = sa->v4->vec.y + height/2 + h;
+
+ if(dir=='l') {
+ /* when direction is left, then we flip direction of arrow */
+ float cx = sa->v1->vec.x + width;
+ for(i=0;i<10;i++) {
+ points[i].x -= cx;
+ points[i].x = -points[i].x;
+ points[i].x += sa->v1->vec.x;
+ }
+ }
+
+ glBegin(GL_POLYGON);
+ for(i=0;i<5;i++)
+ glVertex2f(points[i].x, points[i].y);
+ glEnd();
+ glBegin(GL_POLYGON);
+ for(i=4;i<8;i++)
+ glVertex2f(points[i].x, points[i].y);
+ glVertex2f(points[0].x, points[0].y);
+ glEnd();
+
+ glRectf(points[2].x, points[2].y, points[8].x, points[8].y);
+ glRectf(points[6].x, points[6].y, points[9].x, points[9].y);
+}
+
+/* draw vertical shape visualising future joining (up/down direction) */
+static void draw_vertical_join_shape(ScrArea *sa, char dir)
+{
+ _point points[10];
+ short i;
+ float w, h;
+ float width = sa->v3->vec.x - sa->v1->vec.x;
+ float height = sa->v3->vec.y - sa->v1->vec.y;
+
+ if(height<width) {
+ h = height/4;
+ w = height/8;
+ }
+ else {
+ h = width/4;
+ w = width/8;
+ }
+
+ points[0].x = sa->v1->vec.x + width/2;
+ points[0].y = sa->v3->vec.y;
+
+ points[1].x = sa->v2->vec.x;
+ points[1].y = sa->v2->vec.y;
+
+ points[2].x = sa->v1->vec.x;
+ points[2].y = sa->v1->vec.y + h;
+
+ points[3].x = sa->v1->vec.x + width/2 - 2*w;
+ points[3].y = sa->v1->vec.y + h;
+
+ points[4].x = sa->v1->vec.x + width/2;
+ points[4].y = sa->v1->vec.y + 2*h;
+
+ points[5].x = sa->v1->vec.x + width/2 + 2*w;
+ points[5].y = sa->v1->vec.y + h;
+
+ points[6].x = sa->v4->vec.x;
+ points[6].y = sa->v4->vec.y + h;
+
+ points[7].x = sa->v3->vec.x;
+ points[7].y = sa->v3->vec.y;
+
+ points[8].x = sa->v1->vec.x + width/2 - w;
+ points[8].y = sa->v1->vec.y;
+
+ points[9].x = sa->v1->vec.x + width/2 + w;
+ points[9].y = sa->v1->vec.y;
+
+ if(dir=='u') {
+ /* when direction is up, then we flip direction of arrow */
+ float cy = sa->v1->vec.y + height;
+ for(i=0;i<10;i++) {
+ points[i].y -= cy;
+ points[i].y = -points[i].y;
+ points[i].y += sa->v1->vec.y;
+ }
+ }
+
+ glBegin(GL_POLYGON);
+ for(i=0;i<5;i++)
+ glVertex2f(points[i].x, points[i].y);
+ glEnd();
+ glBegin(GL_POLYGON);
+ for(i=4;i<8;i++)
+ glVertex2f(points[i].x, points[i].y);
+ glVertex2f(points[0].x, points[0].y);
+ glEnd();
+
+ glRectf(points[2].x, points[2].y, points[8].x, points[8].y);
+ glRectf(points[6].x, points[6].y, points[9].x, points[9].y);
+}
+
+/* draw join shape due to direction of joining */
+static void draw_join_shape(ScrArea *sa, char dir)
+{
+ if(dir=='u' || dir=='d')
+ draw_vertical_join_shape(sa, dir);
+ else
+ draw_horizontal_join_shape(sa, dir);
+}
+
+/* draw screen area darker with arrow (visualisation of future joining) */
+static void scrarea_draw_shape_dark(ScrArea *sa, char dir)
+{
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_BLEND);
+ glColor4ub(0, 0, 0, 105);
+ draw_join_shape(sa, dir);
+ glDisable(GL_BLEND);
+}
+
+/* draw screen area ligher with arrow shape ("eraser" of previous dark shape) */
+static void scrarea_draw_shape_light(ScrArea *sa, char dir)
+{
+ glBlendFunc(GL_DST_COLOR, GL_SRC_ALPHA);
+ glEnable(GL_BLEND);
+ /* value 181 was hardly computed: 181~105 */
+ glColor4ub(255, 255, 255, 181);
+ draw_join_shape(sa, dir);
+ glDisable(GL_BLEND);
+}
+
+static void joinarea_interactive(ScrArea *area, ScrEdge *onedge)
+{
+ struct ScrArea *sa1 = area, *sa2, *scr;
+ struct ScrArea *up=0, *down=0, *right=0, *left=0;
+ struct ScrEdge *se;
+ unsigned short event;
+ short ok=0, val=0, mval[2];
+ char dir=0;
+
+ sa1 = test_edge_area(sa1, onedge);
+ if(sa1==0) return;
+
+ /* find directions with same edge */
+ sa2= G.curscreen->areabase.first;
+ while(sa2) {
+ if(sa2 != sa1) {
+ se= screen_findedge(G.curscreen, sa2->v1, sa2->v2);
+ if(onedge==se) right= sa2;
+ se= screen_findedge(G.curscreen, sa2->v2, sa2->v3);
+ if(onedge==se) down= sa2;
+ se= screen_findedge(G.curscreen, sa2->v3, sa2->v4);
+ if(onedge==se) left= sa2;
+ se= screen_findedge(G.curscreen, sa2->v4, sa2->v1);
+ if(onedge==se) up= sa2;
+ }
+ sa2= sa2->next;
+ }
+
+ if(left) val++;
+ if(up) val++;
+ if(right) val++;
+ if(down) val++;
+
+ if(val==0) return;
+ else if(val==1) {
+ if(left) {
+ right = sa1;
+ sa2 = left;
+ dir = 'h';
+ }
+ else if(right) {
+ left = sa1;
+ sa2 = right;
+ dir = 'h';
+ }
+ else if(up) {
+ down = sa1;
+ sa2= up;
+ dir = 'v';
+ }
+ else if(down) {
+ up = sa1;
+ sa2 = down;
+ dir = 'v';
+ }
+ }
+
+ mywinset(G.curscreen->mainwin);
+
+ /* initial set up screen area asigned for destroying */
+ scr = sa2;
+
+ /* set up standard cursor */
+ set_cursor(CURSOR_STD);
+
+ /* should already have a good matrix */
+ glReadBuffer(GL_FRONT);
+ glDrawBuffer(GL_FRONT);
+
+ /* to prevent flickering after clicking at "Join Areas " */
+ getmouseco_sc(mval);
+ if(dir=='h') {
+ if(scr==left && mval[0]>=onedge->v1->vec.x) scr = right;
+ else if(scr==right && mval[0]<onedge->v1->vec.x) scr = left;
+ }
+ else if(dir=='v') {
+ if(scr==down && mval[1]>=onedge->v1->vec.y) scr = up;
+ else if(scr==up && mval[1]<onedge->v1->vec.y) scr = down;
+ }
+
+ /* draw scr screen area with dark shape */
+ if(scr==left)
+ scrarea_draw_shape_dark(scr,'r');
+ else if(scr==right)
+ scrarea_draw_shape_dark(scr,'l');
+ else if(scr==up)
+ scrarea_draw_shape_dark(scr,'d');
+ else if(scr==down)
+ scrarea_draw_shape_dark(scr,'u');
+ bglFlush();
+
+ /* "never ending loop" of interactive selection */
+ while(!ok) {
+ getmouseco_sc(mval);
+
+ /* test if position of mouse is on the "different side" of
+ * "joining edge" */
+ if(dir=='h') {
+ if(scr==left && mval[0]>=onedge->v1->vec.x) {
+ scrarea_draw_shape_light(scr,'r');
+ scr = right;
+ scrarea_draw_shape_dark(scr,'l');
+ }
+ else if(scr==right && mval[0]<onedge->v1->vec.x) {
+ scrarea_draw_shape_light(scr,'l');
+ scr = left;
+ scrarea_draw_shape_dark(scr,'r');
+ }
+ }
+ else if(dir=='v') {
+ if(scr==down && mval[1]>=onedge->v1->vec.y) {
+ scrarea_draw_shape_light(scr,'u');
+ scr = up;
+ scrarea_draw_shape_dark(scr,'d');
+ }
+ else if(scr==up && mval[1]<onedge->v1->vec.y){
+ scrarea_draw_shape_light(scr,'d');
+ scr = down;
+ scrarea_draw_shape_dark(scr,'u');
+ }
+ }
+
+
+ /* get pressed keys and mouse buttons */
+ event = extern_qread(&val);
+
+ /* confirm joining of two screen areas */
+ if(val && event==LEFTMOUSE) ok= 1;
+
+ /* cancel joining of joining */
+ if(val && (event==ESCKEY || event==RIGHTMOUSE)) ok= -1;
+
+ bglFlush();
+ }
+
+ glReadBuffer(GL_BACK);
+ glDrawBuffer(GL_BACK);
+
+ /* joining af screen areas was confirmed ... proceed joining */
+ if(ok==1) {
+ if(sa2!=scr) {
+ sa1 = sa2;
+ sa2 = scr;
+ }
+
+ if(sa2==left) {
+ sa1->v1= sa2->v1;
+ sa1->v2= sa2->v2;
+ screen_addedge(G.curscreen, sa1->v2, sa1->v3);
+ screen_addedge(G.curscreen, sa1->v1, sa1->v4);
+ }
+ else if(sa2==up) {
+ sa1->v2= sa2->v2;
+ sa1->v3= sa2->v3;
+ screen_addedge(G.curscreen, sa1->v1, sa1->v2);
+ screen_addedge(G.curscreen, sa1->v3, sa1->v4);
+ }
+ else if(sa2==right) {
+ sa1->v3= sa2->v3;
+ sa1->v4= sa2->v4;
+ screen_addedge(G.curscreen, sa1->v2, sa1->v3);
+ screen_addedge(G.curscreen, sa1->v1, sa1->v4);
+ }
+ else if(sa2==down) {
+ sa1->v1= sa2->v1;
+ sa1->v4= sa2->v4;
+ screen_addedge(G.curscreen, sa1->v1, sa1->v2);
+ screen_addedge(G.curscreen, sa1->v3, sa1->v4);
+ }
+
+ del_area(sa2);
+ BLI_remlink(&G.curscreen->areabase, sa2);
+ MEM_freeN(sa2);
+
+ removedouble_scredges();
+ removenotused_scredges();
+ removenotused_scrverts();
+
+ testareas();
+ mainqenter(DRAWEDGES, 1);
+
+ /* test cursor en inputwindow */
+ mainqenter(MOUSEY, -1);
+ }
+}
+
+static short testsplitpoint(ScrArea *sa, char dir, float fac)
+/* return 0: no split possible */
+/* else return (integer) screencoordinate split point */
+{
+ short x, y;
+
+ /* area big enough? */
+ if(sa->v4->vec.x- sa->v1->vec.x <= 2*AREAMINX) return 0;
+ if(sa->v2->vec.y- sa->v1->vec.y <= 2*AREAMINY) return 0;
+
+ /* to be sure */
+ if(fac<0.0) fac= 0.0;
+ if(fac>1.0) fac= 1.0;
+
+ if(dir=='h') {
+ y= sa->v1->vec.y+ fac*(sa->v2->vec.y- sa->v1->vec.y);
+
+ if(sa->v2->vec.y==G.curscreen->sizey-1 && sa->v2->vec.y- y < HEADERY)
+ y= sa->v2->vec.y- HEADERY;
+
+ else if(sa->v1->vec.y==0 && y- sa->v1->vec.y < HEADERY)
+ y= sa->v1->vec.y+ HEADERY;
+
+ else if(y- sa->v1->vec.y < AREAMINY) y= sa->v1->vec.y+ AREAMINY;
+ else if(sa->v2->vec.y- y < AREAMINY) y= sa->v2->vec.y- AREAMINY;
+ else y-= (y % AREAGRID);
+
+ return y;
+ }
+ else {
+ x= sa->v1->vec.x+ fac*(sa->v4->vec.x- sa->v1->vec.x);
+ if(x- sa->v1->vec.x < AREAMINX) x= sa->v1->vec.x+ AREAMINX;
+ else if(sa->v4->vec.x- x < AREAMINX) x= sa->v4->vec.x- AREAMINX;
+ else x-= (x % AREAGRID);
+
+ return x;
+ }
+}
+
+static void splitarea(ScrArea *sa, char dir, float fac)
+{
+ bScreen *sc;
+ ScrArea *newa=NULL;
+ ScrVert *sv1, *sv2;
+ short split;
+
+ if(sa==0) return;
+
+ split= testsplitpoint(sa, dir, fac);
+ if(split==0) return;
+
+ sc= G.curscreen;
+
+ areawinset(sa->win);
+
+ if(dir=='h') {
+ /* new vertices */
+ sv1= screen_addvert(sc, sa->v1->vec.x, split);
+ sv2= screen_addvert(sc, sa->v4->vec.x, split);
+
+ /* new edges */
+ screen_addedge(sc, sa->v1, sv1);
+ screen_addedge(sc, sv1, sa->v2);
+ screen_addedge(sc, sa->v3, sv2);
+ screen_addedge(sc, sv2, sa->v4);
+ screen_addedge(sc, sv1, sv2);
+
+ /* new areas: top */
+ newa= screen_addarea(sc, sv1, sa->v2, sa->v3, sv2, sa->headertype, sa->spacetype);
+ copy_areadata(newa, sa, 0);
+
+ /* area below */
+ sa->v2= sv1;
+ sa->v3= sv2;
+
+ }
+ else {
+ /* new vertices */
+ sv1= screen_addvert(sc, split, sa->v1->vec.y);
+ sv2= screen_addvert(sc, split, sa->v2->vec.y);
+
+ /* new edges */
+ screen_addedge(sc, sa->v1, sv1);
+ screen_addedge(sc, sv1, sa->v4);
+ screen_addedge(sc, sa->v2, sv2);
+ screen_addedge(sc, sv2, sa->v3);
+ screen_addedge(sc, sv1, sv2);
+
+ /* new areas: left */
+ newa= screen_addarea(sc, sa->v1, sa->v2, sv2, sv1, sa->headertype, sa->spacetype);
+ copy_areadata(newa, sa, 0);
+
+ /* area right */
+ sa->v1= sv1;
+ sa->v2= sv2;
+ }
+
+ if(sa->spacetype==SPACE_BUTS) {
+ addqueue(sa->win, UI_BUT_EVENT, B_BUTSHOME);
+ addqueue(newa->win, UI_BUT_EVENT, B_BUTSHOME);
+ }
+
+ /* remove double vertices en edges */
+ removedouble_scrverts();
+ removedouble_scredges();
+ removenotused_scredges();
+
+ mainqenter(DRAWEDGES, 1);
+ dodrawscreen= 1; /* patch! event gets lost,,,? */
+ testareas();
+}
+
+static void scrarea_draw_splitpoint(ScrArea *sa, char dir, float fac)
+{
+ int split= testsplitpoint(sa, dir, fac);
+
+ if (split) {
+ if(dir=='h') {
+ sdrawXORline(sa->totrct.xmin, split, sa->totrct.xmax, split);
+ sdrawXORline(sa->totrct.xmin, split-1, sa->totrct.xmax, split-1);
+ } else {
+ sdrawXORline(split, sa->totrct.ymin, split, sa->totrct.ymax);
+ sdrawXORline(split-1, sa->totrct.ymin, split-1, sa->totrct.ymax);
+ }
+ }
+}
+
+static void splitarea_interactive(ScrArea *area, ScrEdge *onedge)
+{
+ ScrArea *scr, *sa= area;
+ float fac= 0.0;
+ unsigned short event;
+ short ok= 0, val, split = 0, mval[2], mvalo[2]= {-1, -1}, first= 1;
+ char dir;
+
+ if(sa->win==0) return;
+ if(sa->full) return;
+ if(myswinopen_allowed()==0) {
+ error("Max amount of subwindows reached");
+ return;
+ }
+
+ dir= scredge_is_horizontal(onedge)?'v':'h';
+
+ mywinset(G.curscreen->mainwin);
+ /* should already have a good matrix */
+ glReadBuffer(GL_FRONT);
+ glDrawBuffer(GL_FRONT);
+
+ /* keep track of grid and minsize */
+ while(ok==0) {
+ getmouseco_sc(mval);
+
+ /* this part of code allows to choose, what window will be splited */
+ /* cursor is out of the current ScreenArea */
+ if((mval[0] < sa->v1->vec.x) || (mval[0] > sa->v3->vec.x) ||
+ (mval[1] < sa->v1->vec.y) || (mval[1] > sa->v3->vec.y)){
+ scr= (ScrArea*)G.curscreen->areabase.first;
+ while(scr){
+ if((mval[0] > scr->v1->vec.x) && (mval[0] < scr->v4->vec.x) &&
+ (mval[1] < scr->v2->vec.y) && (mval[1] > scr->v1->vec.y)){
+ /* test: is ScreenArea enough big for splitting */
+ short tsplit= testsplitpoint(scr, dir, fac);
+ if(tsplit){
+ split = tsplit;
+ /* delete old line from previous ScreenArea */
+ if(!first) scrarea_draw_splitpoint(sa, dir, fac);
+ sa= scr;
+ first= 1;
+ break;
+ }
+ }
+ scr= scr->next;
+ }
+ }
+
+ if (first || (dir=='v' && mval[0]!=mvalo[0]) || (dir=='h' && mval[1]!=mvalo[1])) {
+ if (!first) {
+ scrarea_draw_splitpoint(sa, dir, fac);
+ }
+
+ if(dir=='h') {
+ fac= mval[1]- (sa->v1->vec.y);
+ fac/= sa->v2->vec.y- sa->v1->vec.y;
+ } else {
+ fac= mval[0]- sa->v1->vec.x;
+ fac/= sa->v4->vec.x- sa->v1->vec.x;
+ }
+
+ split= testsplitpoint(sa, dir, fac);
+ if (split) {
+ scrarea_draw_splitpoint(sa, dir, fac);
+ } else {
+ ok= -1;
+ }
+
+ mvalo[0]= mval[0];
+ mvalo[1]= mval[1];
+ first= 0;
+ }
+
+ event= extern_qread(&val);
+
+ /* change direction of splitting between horizontal and vertical
+ * patch was offered by Guillaume */
+ if(val && (event==TABKEY || event==MIDDLEMOUSE)) {
+ scrarea_draw_splitpoint(sa, dir, fac);
+ if(dir=='h') {
+ dir='v';
+ set_cursor(CURSOR_Y_MOVE);
+ } else {
+ dir='h';
+ set_cursor(CURSOR_X_MOVE);
+ }
+ first= 1;
+ }
+
+ if(val && event==LEFTMOUSE) {
+ if(dir=='h') {
+ fac= split- (sa->v1->vec.y);
+ fac/= sa->v2->vec.y- sa->v1->vec.y;
+ }
+ else {
+ fac= split- sa->v1->vec.x;
+ fac/= sa->v4->vec.x- sa->v1->vec.x;
+ }
+ ok= 1;
+ }
+ if(val && (event==ESCKEY || event==RIGHTMOUSE)) {
+ ok= -1;
+ }
+ bglFlush();
+ }
+
+ if (!first) {
+ scrarea_draw_splitpoint(sa, dir, fac);
+ bglFlush();
+ }
+ glReadBuffer(GL_BACK);
+ glDrawBuffer(GL_BACK);
+
+ if(ok==1) {
+ splitarea(sa, dir, fac);
+ mainqenter(DRAWEDGES, 1);
+ dodrawscreen= 1; /* patch! event gets lost,,,? */
+ }
+}
+
+View3D *find_biggest_view3d(void)
+{
+ ScrArea *sa= find_biggest_area_of_type(SPACE_VIEW3D);
+
+ if (sa) {
+ return (View3D*) sa->spacedata.first;
+ } else {
+ return NULL;
+ }
+}
+
+ScrArea *find_biggest_area_of_type(int spacecode)
+{
+ ScrArea *sa, *biggest= NULL;
+ int bigsize= 0;
+
+ for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
+ if (spacecode==0 || sa->spacetype==spacecode) {
+ int x= sa->v3->vec.x - sa->v1->vec.x;
+ int y= sa->v3->vec.y - sa->v1->vec.y;
+ int size= x*x + y*y;
+
+ if (!biggest || size>bigsize) {
+ biggest= sa;
+ bigsize= size;
+ }
+ }
+ }
+
+ return biggest;
+}
+
+ScrArea *find_biggest_area(void)
+{
+ return find_biggest_area_of_type(0);
+}
+
+static void select_connected_scredge(bScreen *sc, ScrEdge *edge)
+{
+ ScrEdge *se;
+ ScrVert *sv;
+ int oneselected;
+ char dir;
+
+ /* select connected, only in the right direction */
+ /* 'dir' is the direction of EDGE */
+
+ if(edge->v1->vec.x==edge->v2->vec.x) dir= 'v';
+ else dir= 'h';
+
+ sv= sc->vertbase.first;
+ while(sv) {
+ sv->flag= 0;
+ sv= sv->next;
+ }
+
+ edge->v1->flag= 1;
+ edge->v2->flag= 1;
+
+ oneselected= 1;
+ while(oneselected) {
+ se= sc->edgebase.first;
+ oneselected= 0;
+ while(se) {
+ if(se->v1->flag + se->v2->flag==1) {
+ if(dir=='h') if(se->v1->vec.y==se->v2->vec.y) {
+ se->v1->flag= se->v2->flag= 1;
+ oneselected= 1;
+ }
+ if(dir=='v') if(se->v1->vec.x==se->v2->vec.x) {
+ se->v1->flag= se->v2->flag= 1;
+ oneselected= 1;
+ }
+ }
+ se= se->next;
+ }
+ }
+}
+
+void test_scale_screen(bScreen *sc)
+/* test if screen vertices should be scaled */
+/* also check offset */
+{
+ ScrVert *sv=0;
+ ScrEdge *se;
+ ScrArea *sa, *san;
+ int yval;
+ float facx, facy, tempf, min[2], max[2];
+
+ sc->startx= prefstax;
+ sc->starty= prefstay;
+ sc->endx= prefstax+prefsizx-1;
+ sc->endy= prefstay+prefsizy-1;
+
+ /* calculate size */
+ sv= sc->vertbase.first;
+ min[0]= min[1]= 0.0;
+ max[0]= sc->sizex;
+ max[1]= sc->sizey;
+ while(sv) {
+ min[0]= MIN2(min[0], sv->vec.x);
+ min[1]= MIN2(min[1], sv->vec.y);
+ max[0]= MAX2(max[0], sv->vec.x);
+ max[1]= MAX2(max[1], sv->vec.y);
+ sv= sv->next;
+ }
+
+ /* always make 0.0 left under */
+ sv= sc->vertbase.first;
+ while(sv) {
+ sv->vec.x -= min[0];
+ sv->vec.y -= min[1];
+ sv= sv->next;
+ }
+
+
+ sc->sizex= max[0]-min[0];
+ sc->sizey= max[1]-min[1];
+
+ if(sc->sizex!= prefsizx || sc->sizey!= prefsizy) {
+ facx= prefsizx;
+ facx/= (float)sc->sizex;
+ facy= prefsizy;
+ facy/= (float)sc->sizey;
+
+ /* make sure it fits! */
+ sv= sc->vertbase.first;
+ while(sv) {
+ tempf= ((float)sv->vec.x)*facx;
+ sv->vec.x= (short)(tempf+0.5);
+ sv->vec.x+= AREAGRID-1;
+ sv->vec.x-= (sv->vec.x % AREAGRID);
+
+ CLAMP(sv->vec.x, 0, prefsizx);
+
+ tempf= ((float)sv->vec.y )*facy;
+ sv->vec.y= (short)(tempf+0.5);
+ sv->vec.y+= AREAGRID-1;
+ sv->vec.y-= (sv->vec.y % AREAGRID);
+
+ CLAMP(sv->vec.y, 0, prefsizy);
+
+ sv= sv->next;
+ }
+
+ sc->sizex= prefsizx;
+ sc->sizey= prefsizy;
+ }
+
+ /* test for collapsed areas. This could happen in some blender version... */
+ sa= sc->areabase.first;
+ while(sa) {
+ san= sa->next;
+ if(sa->v1==sa->v2 || sa->v3==sa->v4 || sa->v2==sa->v3) {
+ del_area(sa);
+ BLI_remlink(&sc->areabase, sa);
+ MEM_freeN(sa);
+ }
+ sa= san;
+ }
+
+ /* make each window at least HEADERY high */
+ sa= sc->areabase.first;
+ while(sa) {
+
+ if(sa->v1->vec.y+HEADERY > sa->v2->vec.y) {
+ /* lower edge */
+ se= screen_findedge(sc, sa->v4, sa->v1);
+ if(se && sa->v1!=sa->v2 ) {
+ select_connected_scredge(sc, se);
+
+ /* all selected vertices get the right offset */
+ yval= sa->v2->vec.y-HEADERY;
+ sv= sc->vertbase.first;
+ while(sv) {
+ /* if is a collapsed area */
+ if(sv!=sa->v2 && sv!=sa->v3) {
+ if(sv->flag) sv->vec.y= yval;
+ }
+ sv= sv->next;
+ }
+ }
+ }
+
+ sa= sa->next;
+ }
+
+}
+
+static void draw_front_xor_dirdist_line(char dir, int dist, int start, int end)
+{
+ if (dir=='h') {
+ sdrawXORline(start, dist, end, dist);
+ sdrawXORline(start, dist+1, end, dist+1);
+ } else {
+ sdrawXORline(dist, start, dist, end);
+ sdrawXORline(dist+1, start, dist+1, end);
+ }
+}
+
+static void moveareas(ScrEdge *edge)
+{
+ ScrVert *v1;
+ ScrArea *sa;
+ short mvalo[2], mval_prev=-1;
+ short edge_start, edge_end, edge_position;
+ short bigger, smaller, headery, areaminy;
+ int delta, doit;
+ char dir;
+
+ if(edge->border) return;
+
+ dir= scredge_is_horizontal(edge)?'h':'v';
+
+ select_connected_scredge(G.curscreen, edge);
+
+ edge_position= (dir=='h')?edge->v1->vec.y:edge->v1->vec.x;
+ edge_start= 10000;
+ edge_end= -10000;
+ for (v1= G.curscreen->vertbase.first; v1; v1= v1->next) {
+ if (v1->flag) {
+ if (dir=='h') {
+ edge_start= MIN2(edge_start, v1->vec.x);
+ edge_end= MAX2(edge_end, v1->vec.x);
+ } else {
+ edge_start= MIN2(edge_start, v1->vec.y);
+ edge_end= MAX2(edge_end, v1->vec.y);
+ }
+ }
+ }
+
+ /* now all verices with 'flag==1' are the ones that can be moved. */
+ /* we check all areas and test for free space with MINSIZE */
+ bigger= smaller= 10000;
+ sa= G.curscreen->areabase.first;
+ while(sa) {
+ if(dir=='h') { /* if top or down edge selected, test height */
+ if(sa->headertype) {
+ headery= HEADERY;
+ areaminy= AREAMINY;
+ }
+ else {
+ headery= 0;
+ areaminy= AREAMINY; /*areaminy= EDGEWIDTH;*/
+ }
+
+ if(sa->v1->flag && sa->v4->flag) {
+ int y1;
+ if(sa->v2->vec.y==G.curscreen->sizey-1) /* top edge */
+ y1= sa->v2->vec.y - sa->v1->vec.y-headery-EDGEWIDTH;
+ else
+ y1= sa->v2->vec.y - sa->v1->vec.y-areaminy;
+ bigger= MIN2(bigger, y1);
+ }
+ else if(sa->v2->flag && sa->v3->flag) {
+ int y1;
+ if(sa->v1->vec.y==0) /* bottom edge */
+ y1= sa->v2->vec.y - sa->v1->vec.y-headery-EDGEWIDTH;
+ else
+ y1= sa->v2->vec.y - sa->v1->vec.y-areaminy;
+ smaller= MIN2(smaller, y1);
+ }
+ }
+ else { /* if left or right edge selected, test width */
+ if(sa->v1->flag && sa->v2->flag) {
+ int x1= sa->v4->vec.x - sa->v1->vec.x-AREAMINX;
+ bigger= MIN2(bigger, x1);
+ }
+ else if(sa->v3->flag && sa->v4->flag) {
+ int x1= sa->v4->vec.x - sa->v1->vec.x-AREAMINX;
+ smaller= MIN2(smaller, x1);
+ }
+ }
+ sa= sa->next;
+ }
+
+ mywinset(G.curscreen->mainwin);
+
+ glReadBuffer(GL_FRONT);
+ glDrawBuffer(GL_FRONT);
+
+ doit= delta= 0;
+ getmouseco_sc(mvalo);
+ draw_front_xor_dirdist_line(dir, edge_position+delta, edge_start, edge_end);
+
+ while (!doit) {
+ short val;
+ unsigned short event= extern_qread(&val);
+
+ if (event==MOUSEY) {
+ short mval[2];
+
+ getmouseco_sc(mval);
+ if ((dir=='h' && mval_prev != mval[1]) || (dir=='v' && mval_prev != mval[0])) {
+ /* update the previous val with this one for comparison next loop */
+ if (dir=='h') mval_prev = mval[1];
+ else mval_prev = mval[0];
+
+ draw_front_xor_dirdist_line(dir, edge_position+delta, edge_start, edge_end);
+
+ delta= (dir=='h')?(mval[1]-mvalo[1]):(mval[0]-mvalo[0]);
+ delta= CLAMPIS(delta, -smaller, bigger);
+ draw_front_xor_dirdist_line(dir, edge_position+delta, edge_start, edge_end);
+ bglFlush();
+ }
+ }
+ else if (event==LEFTMOUSE) {
+ doit= 1;
+ }
+ else if (val) {
+ if (ELEM(event, ESCKEY, RIGHTMOUSE))
+ doit= -1;
+ else if (ELEM(event, SPACEKEY, RETKEY))
+ doit= 1;
+ }
+ else BIF_wait_for_statechange();
+
+ }
+ draw_front_xor_dirdist_line(dir, edge_position+delta, edge_start, edge_end);
+ bglFlush();
+ glReadBuffer(GL_BACK);
+ glDrawBuffer(GL_BACK);
+
+ if (doit==1) {
+ for (v1= G.curscreen->vertbase.first; v1; v1= v1->next) {
+ if (v1->flag) {
+ /* that way a nice AREAGRID */
+ if((dir=='v') && v1->vec.x>0 && v1->vec.x<G.curscreen->sizex-1) {
+ v1->vec.x+= delta;
+ if(delta != bigger && delta != -smaller) v1->vec.x-= (v1->vec.x % AREAGRID);
+ }
+ if((dir=='h') && v1->vec.y>0 && v1->vec.y<G.curscreen->sizey-1) {
+ v1->vec.y+= delta;
+
+ v1->vec.y+= AREAGRID-1;
+ v1->vec.y-= (v1->vec.y % AREAGRID);
+
+ /* prevent too small top header */
+ if(v1->vec.y > G.curscreen->sizey-HEADERY)
+ v1->vec.y= G.curscreen->sizey-HEADERY;
+ }
+ }
+ v1->flag= 0;
+ }
+
+ removedouble_scrverts();
+ removedouble_scredges();
+ testareas();
+ }
+
+ mainqenter(DRAWEDGES, 1);
+ dodrawscreen= 1; /* patch! event gets lost,,,? */
+}
+
+static void scrollheader(ScrArea *area)
+{
+ short mval[2], mvalo[2];
+
+ if(area->headbutlen<area->winx) {
+ area->headbutofs= 0;
+ }
+ else if(area->headbutofs+area->winx > area->headbutlen) {
+ area->headbutofs= area->headbutlen-area->winx;
+ }
+
+ getmouseco_sc(mvalo);
+
+ while(get_mbut() & M_MOUSE) {
+ getmouseco_sc(mval);
+ if(mval[0]!=mvalo[0]) {
+ area->headbutofs-= (mval[0]-mvalo[0]);
+
+ if(area->headbutlen-area->winx < area->headbutofs) area->headbutofs= area->headbutlen-area->winx;
+ if(area->headbutofs<0) area->headbutofs= 0;
+
+ scrarea_do_headchange(area);
+ scrarea_do_headdraw(area);
+
+ screen_swapbuffers();
+
+ mvalo[0]= mval[0];
+ } else {
+ BIF_wait_for_statechange();
+ }
+ }
+}
+
+int select_area(int spacetype)
+{
+ /* call from edit routines, when there are more areas
+ * of type 'spacetype', you can indicate an area manually
+ */
+ ScrArea *sa, *sact = NULL;
+ int tot=0;
+ unsigned short event = 0;
+ short val, mval[2];
+
+ sa= G.curscreen->areabase.first;
+ while(sa) {
+ if(sa->spacetype==spacetype) {
+ sact= sa;
+ tot++;
+ }
+ sa= sa->next;
+ }
+
+ if(tot==0) {
+ error("Can't do this! Open correct window");
+ return 0;
+ }
+
+ if(tot==1) {
+ if(curarea!=sact) areawinset(sact->win);
+ return 1;
+ }
+ else if(tot>1) {
+ set_cursor(CURSOR_HELP);
+ while(1) {
+ event= extern_qread(&val);
+
+ if (val) {
+ if(event==ESCKEY) break;
+ if(event==LEFTMOUSE) break;
+ if(event==SPACEKEY) break;
+ } else {
+ BIF_wait_for_statechange();
+ }
+ }
+ screen_set_cursor(G.curscreen);
+
+ /* recalculate winakt */
+ getmouseco_sc(mval);
+
+ if(event==LEFTMOUSE) {
+ ScrArea *sa= screen_find_area_for_pt(G.curscreen, mval);
+
+ if (sa &&sa->spacetype==spacetype) {
+ G.curscreen->winakt= sa->win;
+ areawinset(G.curscreen->winakt);
+ } else {
+ error("Wrong window");
+ return 0;
+ }
+ }
+ }
+
+ if(event==LEFTMOUSE) return 1;
+ else return 0;
+}
+
+/* ************ END JOIN/SPLIT/MOVE ************** */
+/* **************** DRAW SCREENEDGES ***************** */
+
+
+void draw_area_emboss(ScrArea *sa)
+{
+
+ /* set transp line */
+ glEnable( GL_BLEND );
+ glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
+
+ /* right */
+ glColor4ub(0,0,0, 50);
+ sdrawline(sa->winx-1, 0, sa->winx-1, sa->winy-1);
+
+ /* bottom */
+ if(sa->headertype!=HEADERDOWN) {
+ glColor4ub(0,0,0, 80);
+ sdrawline(0, 0, sa->winx-1, 0);
+ }
+
+ /* top */
+ if(sa->headertype!=HEADERTOP) {
+ glColor4ub(255,255,255, 60);
+ sdrawline(0, sa->winy-1, sa->winx-1, sa->winy-1);
+ }
+ /* left */
+ glColor4ub(255,255,255, 50);
+ sdrawline(0, 0, 0, sa->winy);
+
+ glDisable( GL_BLEND );
+}
+
+
+void drawscredge_area(ScrArea *sa)
+{
+ short x1= sa->v1->vec.x;
+ short y1= sa->v1->vec.y;
+ short x2= sa->v3->vec.x;
+ short y2= sa->v3->vec.y;
+
+ /* this to fill the (undrawn) edge area with back color first */
+ glColor3f(SCR_BACK,SCR_BACK,SCR_BACK);
+ sdrawline(x2, y1, x2, y2);
+ sdrawline(x1, y1, x2, y1);
+
+ cpack(0x0);
+
+ /* Simple hack to make sure round corners arntdrawn with the minimal theme,
+ * Nothing wrong with it IMHO, but just be aware its used so the following
+ * if's never compare true with HEADERTOP or HEADERDOWN */
+ if (BIF_GetThemeValue(TH_BUT_DRAWTYPE) == TH_MINIMAL)
+ sa->headertype = -sa->headertype;
+
+ /* right border area */
+ if(sa->headertype==HEADERTOP) sdrawline(x2, y1, x2, y2-SCR_ROUND+1);
+ else if(sa->headertype==HEADERDOWN) sdrawline(x2, y1+SCR_ROUND-1, x2, y2);
+ else sdrawline(x2, y1, x2, y2);
+
+ /* left border area */
+ if(x1>0) { // otherwise it draws the emboss of window over
+ if(sa->headertype==HEADERTOP) sdrawline(x1, y1, x1, y2-SCR_ROUND+1);
+ else if(sa->headertype==HEADERDOWN) sdrawline(x1, y1+SCR_ROUND-1, x1, y2);
+ else sdrawline(x1, y1, x1, y2);
+ }
+ /* top border area */
+ if(sa->headertype==HEADERTOP) sdrawline(x1+SCR_ROUND-3, y2, x2-SCR_ROUND+3, y2);
+ else sdrawline(x1, y2, x2, y2);
+
+ /* bottom border area */
+ if(sa->headertype==HEADERDOWN) sdrawline(x1+SCR_ROUND-3, y1, x2-SCR_ROUND+3, y1);
+ else sdrawline(x1, y1, x2, y1);
+
+ /* restore real header type */
+ if (BIF_GetThemeValue(TH_BUT_DRAWTYPE) == TH_MINIMAL)
+ sa->headertype = -sa->headertype;
+}
+
+/* ********************************* */
+
+/* for depgraph updating, all layers visible in a screen */
+unsigned int screen_view3d_layers(void)
+{
+ ScrArea *sa;
+ int layer= G.scene->lay; /* as minimum this */
+
+ for(sa= G.curscreen->areabase.first; sa; sa= sa->next) {
+ if(sa->spacetype==SPACE_VIEW3D)
+ layer |= ((View3D *)sa->spacedata.first)->lay;
+ }
+ return layer;
+}
+
+bScreen *default_twosplit()
+{
+ bScreen *sc= addscreen("screen");
+ ScrArea *sa;
+
+ splitarea( (ScrArea *)sc->areabase.first, 'h', 0.99);
+ sa= sc->areabase.first;
+ newspace(sa, SPACE_VIEW3D);
+ newspace(sa->next, SPACE_INFO);
+
+ return sc;
+}
+
+void initscreen(void)
+{
+ default_twosplit();
+}
+
+static int curcursor;
+
+int get_cursor(void) {
+ return curcursor;
+}
+
+void set_cursor(int curs) {
+ if (G.background == 0) {
+ if (curs!=curcursor) {
+ curcursor= curs;
+ window_set_cursor(mainwin, curs);
+ }
+ }
+}
+
+void unlink_screen(bScreen *sc) {
+ ScrArea *sa;
+
+ for (sa= sc->areabase.first; sa; sa= sa->next)
+ del_area(sa);
+}
+
+void warp_pointer(int x, int y)
+{
+ window_warp_pointer(mainwin, x, y);
+}
+
+void set_timecursor(int nr)
+{
+ /* 10 8x8 digits */
+ static char number_bitmaps[10][8]= {
+ {0, 56, 68, 68, 68, 68, 68, 56},
+ {0, 24, 16, 16, 16, 16, 16, 56},
+ {0, 60, 66, 32, 16, 8, 4, 126},
+ {0, 124, 32, 16, 56, 64, 66, 60},
+ {0, 32, 48, 40, 36, 126, 32, 32},
+ {0, 124, 4, 60, 64, 64, 68, 56},
+ {0, 56, 4, 4, 60, 68, 68, 56},
+ {0, 124, 64, 32, 16, 8, 8, 8},
+ {0, 60, 66, 66, 60, 66, 66, 60},
+ {0, 56, 68, 68, 120, 64, 68, 56}
+ };
+ unsigned char mask[16][2];
+ unsigned char bitmap[16][2];
+ int i, idx;
+
+ memset(&bitmap, 0x00, sizeof(bitmap));
+ memset(&mask, 0xFF, sizeof(mask));
+
+ /* print number bottom right justified */
+ for (idx= 3; nr && idx>=0; idx--) {
+ char *digit= number_bitmaps[nr%10];
+ int x = idx%2;
+ int y = idx/2;
+
+ for (i=0; i<8; i++)
+ bitmap[i + y*8][x]= digit[i];
+ nr/= 10;
+ }
+
+ curcursor= CURSOR_NONE;
+ window_set_custom_cursor(mainwin, mask, bitmap, 7, 7);
+ BIF_renderwin_set_custom_cursor(mask, bitmap);
+}
diff --git a/source/blender/src/editseq.c b/source/blender/src/editseq.c
new file mode 100644
index 00000000000..eed3145284c
--- /dev/null
+++ b/source/blender/src/editseq.c
@@ -0,0 +1,3703 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef WIN32
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+#include <sys/types.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_storage_types.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "DNA_ipo_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_sequence_types.h"
+#include "DNA_view2d_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_sound_types.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_plugin_types.h"
+#include "BKE_global.h"
+#include "BKE_image.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_scene.h"
+
+#include "BIF_space.h"
+#include "BIF_interface.h"
+#include "BIF_screen.h"
+#include "BIF_drawseq.h"
+#include "BIF_editseq.h"
+#include "BIF_mywindow.h"
+#include "BIF_toolbox.h"
+#include "BIF_writemovie.h"
+#include "BIF_editview.h"
+#include "BIF_scrarea.h"
+#include "BIF_editsound.h"
+#include "BIF_imasel.h"
+
+#include "BSE_edit.h"
+#include "BSE_sequence.h"
+#include "BSE_seqeffects.h"
+#include "BSE_filesel.h"
+#include "BSE_drawipo.h"
+#include "BSE_seqaudio.h"
+#include "BSE_time.h"
+
+#include "BDR_editobject.h"
+
+#include "blendef.h"
+#include "mydevice.h"
+
+static Sequence *_last_seq=0;
+static int _last_seq_init=0;
+
+#ifdef WIN32
+char last_imagename[FILE_MAXDIR+FILE_MAXFILE]= "c:\\";
+#else
+char last_imagename[FILE_MAXDIR+FILE_MAXFILE]= "/";
+#endif
+
+char last_sounddir[FILE_MAXDIR+FILE_MAXFILE]= "";
+
+#define SEQ_DESEL ~(SELECT+SEQ_LEFTSEL+SEQ_RIGHTSEL)
+
+static int test_overlap_seq(Sequence *);
+static void shuffle_seq(Sequence *);
+
+Sequence *get_last_seq()
+{
+ if(!_last_seq_init) {
+ Editing *ed;
+ Sequence *seq;
+
+ ed= G.scene->ed;
+ if(!ed) return NULL;
+
+ for(seq= ed->seqbasep->first; seq; seq=seq->next)
+ if(seq->flag & SELECT)
+ _last_seq= seq;
+
+ _last_seq_init = 1;
+ }
+
+ return _last_seq;
+}
+
+void set_last_seq(Sequence *seq)
+{
+ _last_seq = seq;
+ _last_seq_init = 1;
+}
+
+void clear_last_seq(Sequence *seq)
+{
+ _last_seq = NULL;
+ _last_seq_init = 0;
+}
+
+
+/* seq funcs's for transforming internally
+ notice the difference between start/end and left/right.
+
+ left and right are the bounds at which the setuence is rendered,
+start and end are from the start and fixed length of the sequence.
+*/
+int seq_tx_get_start(Sequence *seq) {
+ return seq->start;
+}
+int seq_tx_get_end(Sequence *seq)
+{
+ return seq->start+seq->len;
+}
+
+int seq_tx_get_final_left(Sequence *seq)
+{
+ return (seq->start - seq->startstill) + seq->startofs;
+}
+int seq_tx_get_final_right(Sequence *seq)
+{
+ return ((seq->start+seq->len) + seq->endstill) - seq->endofs;
+}
+
+void seq_tx_set_final_left(Sequence *seq, int val)
+{
+ if (val < (seq)->start) {
+ seq->startstill = abs(val - (seq)->start);
+ (seq)->startofs = 0;
+ } else {
+ seq->startofs = abs(val - (seq)->start);
+ seq->startstill = 0;
+ }
+}
+
+void seq_tx_set_final_right(Sequence *seq, int val)
+{
+ if (val > (seq)->start + (seq)->len) {
+ seq->endstill = abs(val - (seq->start + (seq)->len));
+ (seq)->endofs = 0;
+ } else {
+ seq->endofs = abs(val - ((seq)->start + (seq)->len));
+ seq->endstill = 0;
+ }
+}
+
+/* check if one side can be transformed */
+int seq_tx_check_left(Sequence *seq)
+{
+ if (seq->flag & SELECT) {
+ if (seq->flag & SEQ_LEFTSEL)
+ return 1;
+ else if (seq->flag & SEQ_RIGHTSEL)
+ return 0;
+
+ return 1; /* selected and neither left or right handles are, so let us move both */
+ }
+ return 0;
+}
+
+int seq_tx_check_right(Sequence *seq)
+{
+ if (seq->flag & SELECT) {
+ if (seq->flag & SEQ_RIGHTSEL)
+ return 1;
+ else if (seq->flag & SEQ_LEFTSEL)
+ return 0;
+
+ return 1; /* selected and neither left or right handles are, so let us move both */
+ }
+ return 0;
+}
+
+/* used so we can do a quick check for single image seq
+ since they work a bit differently to normal image seq's (during transform) */
+int check_single_seq(Sequence *seq)
+{
+ if ( seq->len==1 && (seq->type == SEQ_IMAGE || seq->type == SEQ_COLOR))
+ return 1;
+ else
+ return 0;
+}
+
+static void fix_single_image_seq(Sequence *seq)
+{
+ int left, start, offset;
+ if (!check_single_seq(seq))
+ return;
+
+ /* make sure the image is always at the start since there is only one,
+ adjusting its start should be ok */
+ left = seq_tx_get_final_left(seq);
+ start = seq->start;
+ if (start != left) {
+ offset = left - start;
+ seq_tx_set_final_left( seq, seq_tx_get_final_left(seq) - offset );
+ seq_tx_set_final_right( seq, seq_tx_get_final_right(seq) - offset );
+ seq->start += offset;
+ }
+}
+
+static void change_plugin_seq(char *str) /* called from fileselect */
+{
+ struct SeqEffectHandle sh;
+ Sequence *last_seq= get_last_seq();
+
+ if(last_seq && last_seq->type != SEQ_PLUGIN) return;
+
+ sh = get_sequence_effect(last_seq);
+ sh.free(last_seq);
+ sh.init_plugin(last_seq, str);
+
+ last_seq->machine = MAX3(last_seq->seq1->machine,
+ last_seq->seq2->machine,
+ last_seq->seq3->machine);
+
+ if( test_overlap_seq(last_seq) ) shuffle_seq(last_seq);
+
+ BIF_undo_push("Load/Change Plugin, Sequencer");
+}
+
+
+void boundbox_seq(void)
+{
+ Sequence *seq;
+ Editing *ed;
+ float min[2], max[2];
+
+ ed= G.scene->ed;
+ if(ed==0) return;
+
+ min[0]= 0.0;
+ max[0]= EFRA+1;
+ min[1]= 0.0;
+ max[1]= 8.0;
+
+ seq= ed->seqbasep->first;
+ while(seq) {
+
+ if( min[0] > seq->startdisp-1) min[0]= seq->startdisp-1;
+ if( max[0] < seq->enddisp+1) max[0]= seq->enddisp+1;
+ if( max[1] < seq->machine+2.0) max[1]= seq->machine+2.0;
+
+ seq= seq->next;
+ }
+
+ G.v2d->tot.xmin= min[0];
+ G.v2d->tot.xmax= max[0];
+ G.v2d->tot.ymin= min[1];
+ G.v2d->tot.ymax= max[1];
+
+}
+
+int sequence_is_free_transformable(Sequence * seq)
+{
+ return seq->type < SEQ_EFFECT
+ || (get_sequence_effect_num_inputs(seq->type) == 0);
+}
+
+Sequence *find_neighboring_sequence(Sequence *test, int lr, int sel) {
+/* looks to the left on lr==1, to the right on lr==2
+ sel - 0==unselected, 1==selected, -1==done care*/
+ Sequence *seq;
+ Editing *ed;
+
+ ed= G.scene->ed;
+ if(ed==0) return 0;
+
+ if (sel>0) sel = SELECT;
+
+ seq= ed->seqbasep->first;
+ while(seq) {
+ if( (seq!=test) &&
+ (test->machine==seq->machine) &&
+ (test->depth==seq->depth) &&
+ ((sel == -1) || (sel && (seq->flag & SELECT)) || (sel==0 && (seq->flag & SELECT)==0) ))
+ {
+ switch (lr) {
+ case 1:
+ if (test->startdisp == (seq->enddisp)) {
+ return seq;
+ }
+ break;
+ case 2:
+ if (test->enddisp == (seq->startdisp)) {
+ return seq;
+ }
+ break;
+ }
+ }
+ seq= seq->next;
+ }
+ return NULL;
+}
+
+Sequence *find_next_prev_sequence(Sequence *test, int lr, int sel) {
+/* looks to the left on lr==1, to the right on lr==2
+ sel - 0==unselected, 1==selected, -1==done care*/
+ Sequence *seq,*best_seq = NULL;
+ Editing *ed;
+
+ int dist, best_dist;
+ best_dist = MAXFRAME*2;
+
+ ed= G.scene->ed;
+ if(ed==0) return 0;
+
+ if (sel) sel = SELECT;
+
+ seq= ed->seqbasep->first;
+ while(seq) {
+ if( (seq!=test) &&
+ (test->machine==seq->machine) &&
+ (test->depth==seq->depth) &&
+ ((sel == -1) || (sel==(seq->flag & SELECT))))
+ {
+ dist = MAXFRAME*2;
+
+ switch (lr) {
+ case 1:
+ if (seq->enddisp <= test->startdisp) {
+ dist = test->enddisp - seq->startdisp;
+ }
+ break;
+ case 2:
+ if (seq->startdisp >= test->enddisp) {
+ dist = seq->startdisp - test->enddisp;
+ }
+ break;
+ }
+
+ if (dist==0) {
+ best_seq = seq;
+ break;
+ } else if (dist < best_dist) {
+ best_dist = dist;
+ best_seq = seq;
+ }
+ }
+ seq= seq->next;
+ }
+ return best_seq; /* can be null */
+}
+
+
+Sequence *find_nearest_seq(int *hand)
+{
+ Sequence *seq;
+ Editing *ed;
+ float x, y;
+ short mval[2];
+ float pixelx;
+ float handsize;
+ float displen;
+ View2D *v2d = G.v2d;
+ *hand= 0;
+
+ ed= G.scene->ed;
+ if(ed==0) return 0;
+
+ pixelx = (v2d->cur.xmax - v2d->cur.xmin)/(v2d->mask.xmax - v2d->mask.xmin);
+
+ getmouseco_areawin(mval);
+ areamouseco_to_ipoco(G.v2d, mval, &x, &y);
+
+ seq= ed->seqbasep->first;
+
+ while(seq) {
+ if(seq->machine == (int)y) {
+ /* check for both normal strips, and strips that have been flipped horizontally */
+ if( ((seq->startdisp < seq->enddisp) && (seq->startdisp<=x && seq->enddisp>=x)) ||
+ ((seq->startdisp > seq->enddisp) && (seq->startdisp>=x && seq->enddisp<=x)) )
+ {
+ if(sequence_is_free_transformable(seq)) {
+
+ /* clamp handles to defined size in pixel space */
+
+ handsize = seq->handsize;
+ displen = (float)abs(seq->startdisp - seq->enddisp);
+
+ if (displen / pixelx > 16) { /* dont even try to grab the handles of small strips */
+ /* Set the max value to handle to 1/3 of the total len when its less then 28.
+ * This is important because otherwise selecting handles happens even when you click in the middle */
+
+ if ((displen/3) < 30*pixelx) {
+ handsize = displen/3;
+ } else {
+ CLAMP(handsize, 7*pixelx, 30*pixelx);
+ }
+
+ if( handsize+seq->startdisp >=x )
+ *hand= 1;
+ else if( -handsize+seq->enddisp <=x )
+ *hand= 2;
+ }
+ }
+ return seq;
+ }
+ }
+ seq= seq->next;
+ }
+ return 0;
+}
+
+void update_seq_ipo_rect(Sequence * seq)
+{
+ float start;
+ float end;
+
+ if (!seq || !seq->ipo) {
+ return;
+ }
+ start = -5.0;
+ end = 105.0;
+
+ /* Adjust IPO window to sequence and
+ avoid annoying snap-back to startframe
+ when Lock Time is on */
+ if (G.v2d->flag & V2D_VIEWLOCK) {
+ if ((seq->flag & SEQ_IPO_FRAME_LOCKED) != 0) {
+ start = -5.0 + seq->startdisp;
+ end = 5.0 + seq->enddisp;
+ } else {
+ start = (float)G.scene->r.sfra - 0.1;
+ end = G.scene->r.efra;
+ }
+ }
+
+ seq->ipo->cur.xmin= start;
+ seq->ipo->cur.xmax= end;
+}
+
+void update_seq_icu_rects(Sequence * seq)
+{
+ IpoCurve *icu= NULL;
+ struct SeqEffectHandle sh;
+
+ if (!seq || !seq->ipo) {
+ return;
+ }
+
+ if(!(seq->type & SEQ_EFFECT)) {
+ return;
+ }
+
+ sh = get_sequence_effect(seq);
+
+ for(icu= seq->ipo->curve.first; icu; icu= icu->next) {
+ sh.store_icu_yrange(seq, icu->adrcode, &icu->ymin, &icu->ymax);
+ }
+}
+
+static int test_overlap_seq(Sequence *test)
+{
+ Sequence *seq;
+ Editing *ed;
+
+ ed= G.scene->ed;
+ if(ed==0) return 0;
+
+ seq= ed->seqbasep->first;
+ while(seq) {
+ if(seq!=test) {
+ if(test->machine==seq->machine) {
+ if(test->depth==seq->depth) {
+ if( (test->enddisp <= seq->startdisp) || (test->startdisp >= seq->enddisp) );
+ else return 1;
+ }
+ }
+ }
+ seq= seq->next;
+ }
+ return 0;
+}
+
+static void shuffle_seq(Sequence *test)
+{
+ Editing *ed;
+ Sequence *seq;
+ int a, start;
+
+ ed= G.scene->ed;
+ if(ed==0) return;
+
+ /* is there more than 1 select: only shuffle y */
+ a=0;
+ seq= ed->seqbasep->first;
+ while(seq) {
+ if(seq->flag & SELECT) a++;
+ seq= seq->next;
+ }
+
+ if(a<2 && test->type==SEQ_IMAGE) {
+ start= test->start;
+
+ for(a= 1; a<50; a++) {
+ test->start= start+a;
+ calc_sequence(test);
+ if( test_overlap_seq(test)==0) return;
+ test->start= start-a;
+ calc_sequence(test);
+ if( test_overlap_seq(test)==0) return;
+ }
+ test->start= start;
+ }
+
+ test->machine++;
+ calc_sequence(test);
+ while( test_overlap_seq(test) ) {
+ if(test->machine >= MAXSEQ) {
+ error("There is no more space to add a sequence strip");
+
+ BLI_remlink(ed->seqbasep, test);
+ free_sequence(test);
+ return;
+ }
+ test->machine++;
+ calc_sequence(test);
+ }
+}
+
+static int seq_is_parent(Sequence *par, Sequence *seq)
+{
+ return ((par->seq1 == seq) || (par->seq2 == seq) || (par->seq3 == seq));
+}
+
+static int seq_is_predecessor(Sequence *pred, Sequence *seq)
+{
+ if(pred == seq) return 0;
+ else if(seq_is_parent(pred, seq)) return 1;
+ else if(pred->seq1 && seq_is_predecessor(pred->seq1, seq)) return 1;
+ else if(pred->seq2 && seq_is_predecessor(pred->seq2, seq)) return 1;
+ else if(pred->seq3 && seq_is_predecessor(pred->seq3, seq)) return 1;
+
+ return 0;
+}
+
+static void deselect_all_seq(void)
+{
+ Sequence *seq;
+ Editing *ed;
+
+ ed= G.scene->ed;
+ if(ed==0) return;
+
+ WHILE_SEQ(ed->seqbasep) {
+ seq->flag &= SEQ_DESEL;
+ }
+ END_SEQ
+
+ BIF_undo_push("(De)select all Strips, Sequencer");
+}
+
+static void recurs_sel_seq(Sequence *seqm)
+{
+ Sequence *seq;
+
+ seq= seqm->seqbase.first;
+ while(seq) {
+
+ if(seqm->flag & (SEQ_LEFTSEL+SEQ_RIGHTSEL)) seq->flag &= SEQ_DESEL;
+ else if(seqm->flag & SELECT) seq->flag |= SELECT;
+ else seq->flag &= SEQ_DESEL;
+
+ if(seq->seqbase.first) recurs_sel_seq(seq);
+
+ seq= seq->next;
+ }
+}
+
+void swap_select_seq(void)
+{
+ Sequence *seq;
+ Editing *ed;
+ int sel=0;
+
+ ed= G.scene->ed;
+ if(ed==0) return;
+
+ WHILE_SEQ(ed->seqbasep) {
+ if(seq->flag & SELECT) sel= 1;
+ }
+ END_SEQ
+
+ WHILE_SEQ(ed->seqbasep) {
+ /* always deselect all to be sure */
+ seq->flag &= SEQ_DESEL;
+ if(sel==0) seq->flag |= SELECT;
+ }
+ END_SEQ
+
+ allqueue(REDRAWSEQ, 0);
+ BIF_undo_push("Swap Selected Strips, Sequencer");
+
+}
+
+void select_channel_direction(Sequence *test,int lr) {
+/* selects all strips in a channel to one direction of the passed strip */
+ Sequence *seq;
+ Editing *ed;
+
+ ed= G.scene->ed;
+ if(ed==0) return;
+
+ seq= ed->seqbasep->first;
+ while(seq) {
+ if(seq!=test) {
+ if (test->machine==seq->machine) {
+ if(test->depth==seq->depth) {
+ if (((lr==1)&&(test->startdisp > (seq->startdisp)))||((lr==2)&&(test->startdisp < (seq->startdisp)))) {
+ seq->flag |= SELECT;
+ recurs_sel_seq(seq);
+ }
+ }
+ }
+ }
+ seq= seq->next;
+ }
+ test->flag |= SELECT;
+ recurs_sel_seq(test);
+}
+
+void select_dir_from_last(int lr)
+{
+ Sequence *seq=get_last_seq();
+ if (seq==NULL)
+ return;
+
+ select_channel_direction(seq,lr);
+ allqueue(REDRAWSEQ, 0);
+
+ if (lr==1) BIF_undo_push("Select Strips to the Left, Sequencer");
+ else BIF_undo_push("Select Strips to the Right, Sequencer");
+}
+
+void select_surrounding_handles(Sequence *test)
+{
+ Sequence *neighbor;
+
+ neighbor=find_neighboring_sequence(test, 1, -1);
+ if (neighbor) {
+ neighbor->flag |= SELECT;
+ recurs_sel_seq(neighbor);
+ neighbor->flag |= SEQ_RIGHTSEL;
+ }
+ neighbor=find_neighboring_sequence(test, 2, -1);
+ if (neighbor) {
+ neighbor->flag |= SELECT;
+ recurs_sel_seq(neighbor);
+ neighbor->flag |= SEQ_LEFTSEL;
+ }
+ test->flag |= SELECT;
+}
+
+void select_surround_from_last()
+{
+ Sequence *seq=get_last_seq();
+
+ if (seq==NULL)
+ return;
+
+ select_surrounding_handles(seq);
+ allqueue(REDRAWSEQ, 0);
+ BIF_undo_push("Select Surrounding Handles, Sequencer");
+}
+
+void select_neighbor_from_last(int lr)
+{
+ Sequence *seq=get_last_seq();
+ Sequence *neighbor;
+ int change = 0;
+ if (seq) {
+ neighbor=find_neighboring_sequence(seq, lr, -1);
+ if (neighbor) {
+ switch (lr) {
+ case 1:
+ neighbor->flag |= SELECT;
+ recurs_sel_seq(neighbor);
+ neighbor->flag |= SEQ_RIGHTSEL;
+ seq->flag |= SEQ_LEFTSEL;
+ break;
+ case 2:
+ neighbor->flag |= SELECT;
+ recurs_sel_seq(neighbor);
+ neighbor->flag |= SEQ_LEFTSEL;
+ seq->flag |= SEQ_RIGHTSEL;
+ break;
+ }
+ seq->flag |= SELECT;
+ change = 1;
+ }
+ }
+ if (change) {
+ allqueue(REDRAWSEQ, 0);
+
+ if (lr==1) BIF_undo_push("Select Left Handles, Sequencer");
+ else BIF_undo_push("Select Right Handles, Sequencer");
+ }
+}
+
+void mouse_select_seq(void)
+{
+ Sequence *seq,*neighbor;
+ int hand,seldir;
+ TimeMarker *marker;
+
+ marker=find_nearest_marker(1);
+
+ if (marker) {
+ int oldflag;
+ /* select timeline marker */
+ if ((G.qual & LR_SHIFTKEY)==0) {
+ oldflag= marker->flag;
+ deselect_markers(0, 0);
+
+ if (oldflag & SELECT)
+ marker->flag &= ~SELECT;
+ else
+ marker->flag |= SELECT;
+ }
+ else {
+ marker->flag |= SELECT;
+ }
+ allqueue(REDRAWMARKER, 0);
+ force_draw(0);
+
+ BIF_undo_push("Select Strips, Sequencer");
+
+ } else {
+
+ seq= find_nearest_seq(&hand);
+ if(!(G.qual & LR_SHIFTKEY)&&!(G.qual & LR_ALTKEY)&&!(G.qual & LR_CTRLKEY)) deselect_all_seq();
+
+ if(seq) {
+ set_last_seq(seq);
+
+ if ((seq->type == SEQ_IMAGE) || (seq->type == SEQ_MOVIE)) {
+ if(seq->strip) {
+ strncpy(last_imagename, seq->strip->dir, FILE_MAXDIR-1);
+ }
+ } else
+ if (seq->type == SEQ_HD_SOUND || seq->type == SEQ_RAM_SOUND) {
+ if(seq->strip) {
+ strncpy(last_sounddir, seq->strip->dir, FILE_MAXDIR-1);
+ }
+ }
+
+ if((G.qual & LR_SHIFTKEY) && (seq->flag & SELECT)) {
+ if(hand==0) seq->flag &= SEQ_DESEL;
+ else if(hand==1) {
+ if(seq->flag & SEQ_LEFTSEL)
+ seq->flag &= ~SEQ_LEFTSEL;
+ else seq->flag |= SEQ_LEFTSEL;
+ }
+ else if(hand==2) {
+ if(seq->flag & SEQ_RIGHTSEL)
+ seq->flag &= ~SEQ_RIGHTSEL;
+ else seq->flag |= SEQ_RIGHTSEL;
+ }
+ }
+ else {
+ seq->flag |= SELECT;
+ if(hand==1) seq->flag |= SEQ_LEFTSEL;
+ if(hand==2) seq->flag |= SEQ_RIGHTSEL;
+ }
+
+ /* On Ctrl-Alt selection, select the strip and bordering handles */
+ if ((G.qual & LR_CTRLKEY) && (G.qual & LR_ALTKEY)) {
+ if (!(G.qual & LR_SHIFTKEY)) deselect_all_seq();
+ seq->flag |= SELECT;
+ select_surrounding_handles(seq);
+
+ /* Ctrl signals Left, Alt signals Right
+ First click selects adjacent handles on that side.
+ Second click selects all strips in that direction.
+ If there are no adjacent strips, it just selects all in that direction. */
+ } else if (((G.qual & LR_CTRLKEY) || (G.qual & LR_ALTKEY)) && (seq->flag & SELECT)) {
+
+ if (G.qual & LR_CTRLKEY) seldir=1;
+ else seldir=2;
+ neighbor=find_neighboring_sequence(seq, seldir, -1);
+ if (neighbor) {
+ switch (seldir) {
+ case 1:
+ if ((seq->flag & SEQ_LEFTSEL)&&(neighbor->flag & SEQ_RIGHTSEL)) {
+ if (!(G.qual & LR_SHIFTKEY)) deselect_all_seq();
+ select_channel_direction(seq,1);
+ } else {
+ neighbor->flag |= SELECT;
+ recurs_sel_seq(neighbor);
+ neighbor->flag |= SEQ_RIGHTSEL;
+ seq->flag |= SEQ_LEFTSEL;
+ }
+ break;
+ case 2:
+ if ((seq->flag & SEQ_RIGHTSEL)&&(neighbor->flag & SEQ_LEFTSEL)) {
+ if (!(G.qual & LR_SHIFTKEY)) deselect_all_seq();
+ select_channel_direction(seq,2);
+ } else {
+ neighbor->flag |= SELECT;
+ recurs_sel_seq(neighbor);
+ neighbor->flag |= SEQ_LEFTSEL;
+ seq->flag |= SEQ_RIGHTSEL;
+ }
+ break;
+ }
+ } else {
+ if (!(G.qual & LR_SHIFTKEY)) deselect_all_seq();
+ select_channel_direction(seq,seldir);
+ }
+ }
+
+ recurs_sel_seq(seq);
+ }
+ force_draw(0);
+
+ if(get_last_seq()) allqueue(REDRAWIPO, 0);
+ BIF_undo_push("Select Strips, Sequencer");
+
+ std_rmouse_transform(transform_seq_nomarker);
+ }
+
+ /* marker transform */
+ if (marker) {
+ short mval[2], xo, yo;
+ getmouseco_areawin(mval);
+ xo= mval[0];
+ yo= mval[1];
+
+ while(get_mbut()&R_MOUSE) {
+ getmouseco_areawin(mval);
+ if(abs(mval[0]-xo)+abs(mval[1]-yo) > 4) {
+ transform_markers('g', 0);
+ allqueue(REDRAWMARKER, 0);
+ return;
+ }
+ BIF_wait_for_statechange();
+ }
+ }
+}
+
+
+Sequence *alloc_sequence(ListBase *lb, int cfra, int machine)
+{
+ Sequence *seq;
+
+ /*ed= G.scene->ed;*/
+
+ seq= MEM_callocN( sizeof(Sequence), "addseq");
+ BLI_addtail(lb, seq);
+
+ set_last_seq(seq);
+
+ *( (short *)seq->name )= ID_SEQ;
+ seq->name[2]= 0;
+
+ seq->flag= SELECT;
+ seq->start= cfra;
+ seq->machine= machine;
+ seq->mul= 1.0;
+
+ return seq;
+}
+
+static Sequence *sfile_to_sequence(SpaceFile *sfile, int cfra, int machine, int last)
+{
+ Sequence *seq;
+ Strip *strip;
+ StripElem *se;
+ int totsel, a;
+ char name[160], rel[160];
+
+ /* are there selected files? */
+ totsel= 0;
+ for(a=0; a<sfile->totfile; a++) {
+ if(sfile->filelist[a].flags & ACTIVE) {
+ if( (sfile->filelist[a].type & S_IFDIR)==0 ) {
+ totsel++;
+ }
+ }
+ }
+
+ if(last) {
+ /* if not, a file handed to us? */
+ if(totsel==0 && sfile->file[0]) totsel= 1;
+ }
+
+ if(totsel==0) return 0;
+
+ /* make seq */
+ seq= alloc_sequence(((Editing *)G.scene->ed)->seqbasep, cfra, machine);
+ seq->len= totsel;
+
+ if(totsel==1) {
+ seq->startstill= 25;
+ seq->endstill= 24;
+ }
+
+ calc_sequence(seq);
+
+ if(sfile->flag & FILE_STRINGCODE) {
+ strcpy(name, sfile->dir);
+ strcpy(rel, G.sce);
+ BLI_makestringcode(rel, name);
+ } else {
+ strcpy(name, sfile->dir);
+ }
+
+ /* strip and stripdata */
+ seq->strip= strip= MEM_callocN(sizeof(Strip), "strip");
+ strip->len= totsel;
+ strip->us= 1;
+ strncpy(strip->dir, name, FILE_MAXDIR-1);
+ strip->stripdata= se= MEM_callocN(totsel*sizeof(StripElem), "stripelem");
+
+ for(a=0; a<sfile->totfile; a++) {
+ if(sfile->filelist[a].flags & ACTIVE) {
+ if( (sfile->filelist[a].type & S_IFDIR)==0 ) {
+ strncpy(se->name, sfile->filelist[a].relname, FILE_MAXFILE-1);
+ se->ok= 1;
+ se++;
+ }
+ }
+ }
+ /* no selected file: */
+ if(totsel==1 && se==strip->stripdata) {
+ strncpy(se->name, sfile->file, FILE_MAXFILE-1);
+ se->ok= 1;
+ }
+
+ /* last active name */
+ strncpy(last_imagename, seq->strip->dir, FILE_MAXDIR-1);
+
+ return seq;
+}
+
+
+static int sfile_to_mv_sequence_load(SpaceFile *sfile, int cfra,
+ int machine, int index )
+{
+ Sequence *seq;
+ struct anim *anim;
+ Strip *strip;
+ StripElem *se;
+ int totframe, a;
+ char name[160], rel[160];
+ char str[FILE_MAXDIR+FILE_MAXFILE];
+
+ totframe= 0;
+
+ strncpy(str, sfile->dir, FILE_MAXDIR-1);
+ if(index<0)
+ strncat(str, sfile->file, FILE_MAXDIR-1);
+ else
+ strncat(str, sfile->filelist[index].relname, FILE_MAXDIR-1);
+
+ /* is it a movie? */
+ anim = openanim(str, IB_rect);
+ if(anim==0) {
+ error("The selected file is not a movie or "
+ "FFMPEG-support not compiled in!");
+ return(cfra);
+ }
+
+ totframe= IMB_anim_get_duration(anim);
+
+ /* make seq */
+ seq= alloc_sequence(((Editing *)G.scene->ed)->seqbasep, cfra, machine);
+ seq->len= totframe;
+ seq->type= SEQ_MOVIE;
+ seq->anim= anim;
+ seq->anim_preseek = IMB_anim_get_preseek(anim);
+
+ calc_sequence(seq);
+
+ if(sfile->flag & FILE_STRINGCODE) {
+ strcpy(name, sfile->dir);
+ strcpy(rel, G.sce);
+ BLI_makestringcode(rel, name);
+ } else {
+ strcpy(name, sfile->dir);
+ }
+
+ /* strip and stripdata */
+ seq->strip= strip= MEM_callocN(sizeof(Strip), "strip");
+ strip->len= totframe;
+ strip->us= 1;
+ strncpy(strip->dir, name, FILE_MAXDIR-1);
+ strip->stripdata= se= MEM_callocN(totframe*sizeof(StripElem), "stripelem");
+
+ /* name movie in first strip */
+ if(index<0)
+ strncpy(se->name, sfile->file, FILE_MAXFILE-1);
+ else
+ strncpy(se->name, sfile->filelist[index].relname, FILE_MAXFILE-1);
+
+ for(a=1; a<=totframe; a++, se++) {
+ se->ok= 1;
+ se->nr= a;
+ }
+
+ /* last active name */
+ strncpy(last_imagename, seq->strip->dir, FILE_MAXDIR-1);
+ return(cfra+totframe);
+}
+
+static void sfile_to_mv_sequence(SpaceFile *sfile, int cfra, int machine)
+{
+ int a, totsel;
+
+ totsel= 0;
+ for(a= 0; a<sfile->totfile; a++) {
+ if(sfile->filelist[a].flags & ACTIVE) {
+ if ((sfile->filelist[a].type & S_IFDIR)==0) {
+ totsel++;
+ }
+ }
+ }
+
+ if((totsel==0) && (sfile->file[0])) {
+ cfra= sfile_to_mv_sequence_load(sfile, cfra, machine, -1);
+ return;
+ }
+
+ if(totsel==0) return;
+
+ /* ok. check all the select file, and load it. */
+ for(a= 0; a<sfile->totfile; a++) {
+ if(sfile->filelist[a].flags & ACTIVE) {
+ if ((sfile->filelist[a].type & S_IFDIR)==0) {
+ /* load and update current frame. */
+ cfra= sfile_to_mv_sequence_load(sfile, cfra, machine, a);
+ }
+ }
+ }
+}
+
+static Sequence *sfile_to_ramsnd_sequence(SpaceFile *sfile,
+ int cfra, int machine)
+{
+ Sequence *seq;
+ bSound *sound;
+ Strip *strip;
+ StripElem *se;
+ double totframe;
+ int a;
+ char name[160], rel[160];
+ char str[256];
+
+ totframe= 0.0;
+
+ strncpy(str, sfile->dir, FILE_MAXDIR-1);
+ strncat(str, sfile->file, FILE_MAXFILE-1);
+
+ sound= sound_new_sound(str);
+ if (!sound || sound->sample->type == SAMPLE_INVALID) {
+ error("Unsupported audio format");
+ return 0;
+ }
+ if (sound->sample->bits != 16) {
+ error("Only 16 bit audio is supported");
+ return 0;
+ }
+ sound->id.us=1;
+ sound->flags |= SOUND_FLAGS_SEQUENCE;
+ audio_makestream(sound);
+
+ totframe= (int) ( ((float)(sound->streamlen-1)/
+ ( (float)G.scene->audio.mixrate*4.0 ))* FPS);
+
+ /* make seq */
+ seq= alloc_sequence(((Editing *)G.scene->ed)->seqbasep, cfra, machine);
+ seq->len= totframe;
+ seq->type= SEQ_RAM_SOUND;
+ seq->sound = sound;
+
+ calc_sequence(seq);
+
+ if(sfile->flag & FILE_STRINGCODE) {
+ strcpy(name, sfile->dir);
+ strcpy(rel, G.sce);
+ BLI_makestringcode(rel, name);
+ } else {
+ strcpy(name, sfile->dir);
+ }
+
+ /* strip and stripdata */
+ seq->strip= strip= MEM_callocN(sizeof(Strip), "strip");
+ strip->len= totframe;
+ strip->us= 1;
+ strncpy(strip->dir, name, FILE_MAXDIR-1);
+ strip->stripdata= se= MEM_callocN(totframe*sizeof(StripElem), "stripelem");
+
+ /* name sound in first strip */
+ strncpy(se->name, sfile->file, FILE_MAXFILE-1);
+
+ for(a=1; a<=totframe; a++, se++) {
+ se->ok= 2; /* why? */
+ se->ibuf= 0;
+ se->nr= a;
+ }
+
+ /* last active name */
+ strncpy(last_sounddir, seq->strip->dir, FILE_MAXDIR-1);
+
+ return seq;
+}
+
+static int sfile_to_hdsnd_sequence_load(SpaceFile *sfile, int cfra,
+ int machine, int index)
+{
+ Sequence *seq;
+ struct hdaudio *hdaudio;
+ Strip *strip;
+ StripElem *se;
+ int totframe, a;
+ char name[160], rel[160];
+ char str[FILE_MAXDIR+FILE_MAXFILE];
+
+ totframe= 0;
+
+ strncpy(str, sfile->dir, FILE_MAXDIR-1);
+ if(index<0)
+ strncat(str, sfile->file, FILE_MAXDIR-1);
+ else
+ strncat(str, sfile->filelist[index].relname, FILE_MAXDIR-1);
+
+ /* is it a sound file? */
+ hdaudio = sound_open_hdaudio(str);
+ if(hdaudio==0) {
+ error("The selected file is not a sound file or "
+ "FFMPEG-support not compiled in!");
+ return(cfra);
+ }
+
+ totframe= sound_hdaudio_get_duration(hdaudio, FPS);
+
+ /* make seq */
+ seq= alloc_sequence(((Editing *)G.scene->ed)->seqbasep, cfra, machine);
+ seq->len= totframe;
+ seq->type= SEQ_HD_SOUND;
+ seq->hdaudio= hdaudio;
+
+ calc_sequence(seq);
+
+ if(sfile->flag & FILE_STRINGCODE) {
+ strcpy(name, sfile->dir);
+ strcpy(rel, G.sce);
+ BLI_makestringcode(rel, name);
+ } else {
+ strcpy(name, sfile->dir);
+ }
+
+ /* strip and stripdata */
+ seq->strip= strip= MEM_callocN(sizeof(Strip), "strip");
+ strip->len= totframe;
+ strip->us= 1;
+ strncpy(strip->dir, name, FILE_MAXDIR-1);
+ strip->stripdata= se= MEM_callocN(totframe*sizeof(StripElem), "stripelem");
+
+ /* name movie in first strip */
+ if(index<0)
+ strncpy(se->name, sfile->file, FILE_MAXFILE-1);
+ else
+ strncpy(se->name, sfile->filelist[index].relname, FILE_MAXFILE-1);
+
+ for(a=1; a<=totframe; a++, se++) {
+ se->ok= 2;
+ se->ibuf = 0;
+ se->nr= a;
+ }
+
+ /* last active name */
+ strncpy(last_sounddir, seq->strip->dir, FILE_MAXDIR-1);
+ return(cfra+totframe);
+}
+
+static void sfile_to_hdsnd_sequence(SpaceFile *sfile, int cfra, int machine)
+{
+ int totsel, a;
+
+ totsel= 0;
+ for(a= 0; a<sfile->totfile; a++) {
+ if(sfile->filelist[a].flags & ACTIVE) {
+ if((sfile->filelist[a].type & S_IFDIR)==0) {
+ totsel++;
+ }
+ }
+ }
+
+ if((totsel==0) && (sfile->file[0])) {
+ cfra= sfile_to_hdsnd_sequence_load(sfile, cfra, machine, -1);
+ return;
+ }
+
+ if(totsel==0) return;
+
+ /* ok, check all the select file, and load it. */
+ for(a= 0; a<sfile->totfile; a++) {
+ if(sfile->filelist[a].flags & ACTIVE) {
+ if((sfile->filelist[a].type & S_IFDIR)==0) {
+ /* load and update current frame. */
+ cfra= sfile_to_hdsnd_sequence_load(sfile, cfra, machine, a);
+ }
+ }
+ }
+}
+
+
+static void add_image_strips(char *name)
+{
+ SpaceFile *sfile;
+ struct direntry *files;
+ float x, y;
+ int a, totfile, cfra, machine;
+ short mval[2];
+
+ deselect_all_seq();
+
+ /* restore windowmatrices */
+ areawinset(curarea->win);
+ drawseqspace(curarea, curarea->spacedata.first);
+
+ /* search sfile */
+ sfile= scrarea_find_space_of_type(curarea, SPACE_FILE);
+ if(sfile==0) return;
+
+ /* where will it be */
+ getmouseco_areawin(mval);
+ areamouseco_to_ipoco(G.v2d, mval, &x, &y);
+ cfra= (int)(x+0.5);
+ machine= (int)(y+0.5);
+
+ waitcursor(1);
+
+ /* also read contents of directories */
+ files= sfile->filelist;
+ totfile= sfile->totfile;
+ sfile->filelist= 0;
+ sfile->totfile= 0;
+
+ for(a=0; a<totfile; a++) {
+ if(files[a].flags & ACTIVE) {
+ if( (files[a].type & S_IFDIR) ) {
+ strncat(sfile->dir, files[a].relname, FILE_MAXFILE-1);
+ strcat(sfile->dir,"/");
+ read_dir(sfile);
+
+ /* select all */
+ swapselect_file(sfile);
+
+ if ( sfile_to_sequence(sfile, cfra, machine, 0) ) machine++;
+
+ parent(sfile);
+ }
+ }
+ }
+
+ sfile->filelist= files;
+ sfile->totfile= totfile;
+
+ /* read directory itself */
+ sfile_to_sequence(sfile, cfra, machine, 1);
+
+ waitcursor(0);
+
+ BIF_undo_push("Add Image Strip, Sequencer");
+ transform_seq_nomarker('g', 0);
+
+}
+
+static void add_movie_strip(char *name)
+{
+ SpaceFile *sfile;
+ float x, y;
+ int cfra, machine;
+ short mval[2];
+
+ deselect_all_seq();
+
+ /* restore windowmatrices */
+ areawinset(curarea->win);
+ drawseqspace(curarea, curarea->spacedata.first);
+
+ /* search sfile */
+ sfile= scrarea_find_space_of_type(curarea, SPACE_FILE);
+ if(sfile==0) return;
+
+ /* where will it be */
+ getmouseco_areawin(mval);
+ areamouseco_to_ipoco(G.v2d, mval, &x, &y);
+ cfra= (int)(x+0.5);
+ machine= (int)(y+0.5);
+
+ waitcursor(1);
+
+ /* read directory itself */
+ sfile_to_mv_sequence(sfile, cfra, machine);
+
+ waitcursor(0);
+
+ BIF_undo_push("Add Movie Strip, Sequencer");
+ transform_seq_nomarker('g', 0);
+
+}
+
+static void add_movie_and_hdaudio_strip(char *name)
+{
+ SpaceFile *sfile;
+ float x, y;
+ int cfra, machine;
+ short mval[2];
+
+ deselect_all_seq();
+
+ /* restore windowmatrices */
+ areawinset(curarea->win);
+ drawseqspace(curarea, curarea->spacedata.first);
+
+ /* search sfile */
+ sfile= scrarea_find_space_of_type(curarea, SPACE_FILE);
+ if(sfile==0) return;
+
+ /* where will it be */
+ getmouseco_areawin(mval);
+ areamouseco_to_ipoco(G.v2d, mval, &x, &y);
+ cfra= (int)(x+0.5);
+ machine= (int)(y+0.5);
+
+ waitcursor(1);
+
+ /* read directory itself */
+ sfile_to_hdsnd_sequence(sfile, cfra, machine);
+ sfile_to_mv_sequence(sfile, cfra, machine);
+
+ waitcursor(0);
+
+ BIF_undo_push("Add Movie and HD-Audio Strip, Sequencer");
+ transform_seq_nomarker('g', 0);
+
+}
+
+static void add_sound_strip_ram(char *name)
+{
+ SpaceFile *sfile;
+ float x, y;
+ int cfra, machine;
+ short mval[2];
+
+ deselect_all_seq();
+
+ sfile= scrarea_find_space_of_type(curarea, SPACE_FILE);
+ if (sfile==0) return;
+
+ /* where will it be */
+ getmouseco_areawin(mval);
+ areamouseco_to_ipoco(G.v2d, mval, &x, &y);
+ cfra= (int)(x+0.5);
+ machine= (int)(y+0.5);
+
+ waitcursor(1);
+
+ sfile_to_ramsnd_sequence(sfile, cfra, machine);
+
+ waitcursor(0);
+
+ BIF_undo_push("Add Sound (RAM) Strip, Sequencer");
+ transform_seq_nomarker('g', 0);
+}
+
+static void add_sound_strip_hd(char *name)
+{
+ SpaceFile *sfile;
+ float x, y;
+ int cfra, machine;
+ short mval[2];
+
+ deselect_all_seq();
+
+ sfile= scrarea_find_space_of_type(curarea, SPACE_FILE);
+ if (sfile==0) return;
+
+ /* where will it be */
+ getmouseco_areawin(mval);
+ areamouseco_to_ipoco(G.v2d, mval, &x, &y);
+ cfra= (int)(x+0.5);
+ machine= (int)(y+0.5);
+
+ waitcursor(1);
+
+ sfile_to_hdsnd_sequence(sfile, cfra, machine);
+
+ waitcursor(0);
+
+ BIF_undo_push("Add Sound (HD) Strip, Sequencer");
+ transform_seq_nomarker('g', 0);
+}
+
+#if 0
+static void reload_sound_strip(char *name)
+{
+ Editing *ed;
+ Sequence *seq, *seqact;
+ SpaceFile *sfile;
+ Sequence *last_seq= get_last_seq();
+
+ ed= G.scene->ed;
+
+ if(last_seq==0 || last_seq->type!=SEQ_SOUND) return;
+ seqact= last_seq; /* last_seq changes in alloc_sequence */
+
+ /* search sfile */
+ sfile= scrarea_find_space_of_type(curarea, SPACE_FILE);
+ if(sfile==0) return;
+
+ waitcursor(1);
+
+ seq = sfile_to_snd_sequence(sfile, seqact->start, seqact->machine);
+ printf("seq->type: %i\n", seq->type);
+ if(seq && seq!=seqact) {
+ /* i'm not sure about this one, seems to work without it -- sgefant */
+ free_strip(seqact->strip);
+
+ seqact->strip= seq->strip;
+
+ seqact->len= seq->len;
+ calc_sequence(seqact);
+
+ seq->strip= 0;
+ free_sequence(seq);
+ BLI_remlink(ed->seqbasep, seq);
+
+ seq= ed->seqbasep->first;
+
+ }
+
+ waitcursor(0);
+
+ allqueue(REDRAWSEQ, 0);
+}
+#endif
+
+static void reload_image_strip(char *name)
+{
+ Editing *ed;
+ Sequence *seq, *seqact;
+ SpaceFile *sfile;
+ Sequence *last_seq= get_last_seq();
+
+ ed= G.scene->ed;
+
+ if(last_seq==0 || last_seq->type!=SEQ_IMAGE) return;
+ seqact= last_seq; /* last_seq changes in alloc_sequence */
+
+ /* search sfile */
+ sfile= scrarea_find_space_of_type(curarea, SPACE_FILE);
+ if(sfile==0) return;
+
+ waitcursor(1);
+
+ seq= sfile_to_sequence(sfile, seqact->start, seqact->machine, 1);
+ if(seq && seq!=seqact) {
+ free_strip(seqact->strip);
+
+ seqact->strip= seq->strip;
+
+ seqact->len= seq->len;
+ calc_sequence(seqact);
+
+ seq->strip= 0;
+ free_sequence(seq);
+ BLI_remlink(ed->seqbasep, seq);
+
+ update_changed_seq_and_deps(seqact, 1, 1);
+ }
+ waitcursor(0);
+
+ allqueue(REDRAWSEQ, 0);
+}
+
+static int event_to_efftype(int event)
+{
+ if(event==2) return SEQ_CROSS;
+ if(event==3) return SEQ_GAMCROSS;
+ if(event==4) return SEQ_ADD;
+ if(event==5) return SEQ_SUB;
+ if(event==6) return SEQ_MUL;
+ if(event==7) return SEQ_ALPHAOVER;
+ if(event==8) return SEQ_ALPHAUNDER;
+ if(event==9) return SEQ_OVERDROP;
+ if(event==10) return SEQ_PLUGIN;
+ if(event==13) return SEQ_WIPE;
+ if(event==14) return SEQ_GLOW;
+ if(event==15) return SEQ_TRANSFORM;
+ if(event==16) return SEQ_COLOR;
+ if(event==17) return SEQ_SPEED;
+ return 0;
+}
+
+static int seq_effect_find_selected(Editing *ed, Sequence *activeseq, int type, Sequence **selseq1, Sequence **selseq2, Sequence **selseq3)
+{
+ Sequence *seq1= 0, *seq2= 0, *seq3= 0, *seq;
+
+ if (!activeseq)
+ seq2= get_last_seq();
+
+ for(seq=ed->seqbasep->first; seq; seq=seq->next) {
+ if(seq->flag & SELECT) {
+ if (seq->type == SEQ_RAM_SOUND
+ || seq->type == SEQ_HD_SOUND) {
+ error("Can't apply effects to "
+ "audio sequence strips");
+ return 0;
+ }
+ if((seq != activeseq) && (seq != seq2)) {
+ if(seq2==0) seq2= seq;
+ else if(seq1==0) seq1= seq;
+ else if(seq3==0) seq3= seq;
+ else {
+ error("Can't apply effect to more than 3 sequence strips");
+ return 0;
+ }
+ }
+ }
+ }
+
+ /* make sequence selection a little bit more intuitive
+ for 3 strips: the last-strip should be sequence3 */
+ if (seq3 != 0 && seq2 != 0) {
+ Sequence *tmp = seq2;
+ seq2 = seq3;
+ seq3 = tmp;
+ }
+
+
+ switch(get_sequence_effect_num_inputs(type)) {
+ case 0:
+ seq1 = seq2 = seq3 = 0;
+ break;
+ case 1:
+ if(seq2==0) {
+ error("Need at least one selected sequence strip");
+ return 0;
+ }
+ if(seq1==0) seq1= seq2;
+ if(seq3==0) seq3= seq2;
+ case 2:
+ if(seq1==0 || seq2==0) {
+ error("Need 2 selected sequence strips");
+ return 0;
+ }
+ if(seq3==0) seq3= seq2;
+ }
+
+ *selseq1= seq1;
+ *selseq2= seq2;
+ *selseq3= seq3;
+
+ return 1;
+}
+
+static int add_seq_effect(int type, char *str)
+{
+ Editing *ed;
+ Sequence *newseq, *seq1, *seq2, *seq3;
+ Strip *strip;
+ float x, y;
+ int cfra, machine;
+ short mval[2];
+ struct SeqEffectHandle sh;
+
+ if(G.scene->ed==0) return 0;
+ ed= G.scene->ed;
+
+ if(!seq_effect_find_selected(ed, NULL, event_to_efftype(type), &seq1, &seq2, &seq3))
+ return 0;
+
+ deselect_all_seq();
+
+ /* where will it be (cfra is not realy needed) */
+ getmouseco_areawin(mval);
+ areamouseco_to_ipoco(G.v2d, mval, &x, &y);
+ cfra= (int)(x+0.5);
+ machine= (int)(y+0.5);
+
+ /* allocate and initialize */
+ newseq= alloc_sequence(((Editing *)G.scene->ed)->seqbasep, cfra, machine);
+ newseq->type= event_to_efftype(type);
+
+ sh = get_sequence_effect(newseq);
+
+ newseq->seq1= seq1;
+ newseq->seq2= seq2;
+ newseq->seq3= seq3;
+
+ sh.init(newseq);
+
+ if (!seq1) {
+ newseq->len= 1;
+ newseq->startstill= 25;
+ newseq->endstill= 24;
+ }
+
+ calc_sequence(newseq);
+
+ newseq->strip= strip= MEM_callocN(sizeof(Strip), "strip");
+ strip->len= newseq->len;
+ strip->us= 1;
+ if(newseq->len>0)
+ strip->stripdata= MEM_callocN(newseq->len*sizeof(StripElem), "stripelem");
+
+ /* initialize plugin */
+ if(newseq->type == SEQ_PLUGIN) {
+ sh.init_plugin(newseq, str);
+
+ if(newseq->plugin==0) {
+ BLI_remlink(ed->seqbasep, newseq);
+ free_sequence(newseq);
+ set_last_seq(NULL);
+ return 0;
+ }
+ }
+
+ /* set find a free spot to but the strip */
+ if (newseq->seq1) {
+ newseq->machine= MAX3(newseq->seq1->machine,
+ newseq->seq2->machine,
+ newseq->seq3->machine);
+ }
+ if(test_overlap_seq(newseq)) shuffle_seq(newseq);
+
+ update_changed_seq_and_deps(newseq, 1, 1);
+
+ /* push undo and go into grab mode */
+ if(newseq->type == SEQ_PLUGIN) {
+ BIF_undo_push("Add Plugin Strip, Sequencer");
+ } else {
+ BIF_undo_push("Add Effect Strip, Sequencer");
+ }
+
+ transform_seq_nomarker('g', 0);
+
+ return 1;
+}
+
+static void load_plugin_seq(char *str) /* called from fileselect */
+{
+ add_seq_effect(10, str);
+}
+
+void add_sequence(int type)
+{
+ Editing *ed;
+ Sequence *seq;
+ Strip *strip;
+ Scene *sce;
+ float x, y;
+ int cfra, machine;
+ short nr, event, mval[2];
+ char *str;
+
+ if (type >= 0){
+ /* bypass pupmenu for calls from menus (aphex) */
+ switch(type){
+ case SEQ_SCENE:
+ event = 101;
+ break;
+ case SEQ_IMAGE:
+ event = 1;
+ break;
+ case SEQ_MOVIE:
+ event = 102;
+ break;
+ case SEQ_RAM_SOUND:
+ event = 103;
+ break;
+ case SEQ_HD_SOUND:
+ event = 104;
+ break;
+ case SEQ_MOVIE_AND_HD_SOUND:
+ event = 105;
+ break;
+ case SEQ_PLUGIN:
+ event = 10;
+ break;
+ case SEQ_CROSS:
+ event = 2;
+ break;
+ case SEQ_ADD:
+ event = 4;
+ break;
+ case SEQ_SUB:
+ event = 5;
+ break;
+ case SEQ_ALPHAOVER:
+ event = 7;
+ break;
+ case SEQ_ALPHAUNDER:
+ event = 8;
+ break;
+ case SEQ_GAMCROSS:
+ event = 3;
+ break;
+ case SEQ_MUL:
+ event = 6;
+ break;
+ case SEQ_OVERDROP:
+ event = 9;
+ break;
+ case SEQ_WIPE:
+ event = 13;
+ break;
+ case SEQ_GLOW:
+ event = 14;
+ break;
+ case SEQ_TRANSFORM:
+ event = 15;
+ break;
+ case SEQ_COLOR:
+ event = 16;
+ break;
+ case SEQ_SPEED:
+ event = 17;
+ break;
+ default:
+ event = 0;
+ break;
+ }
+ }
+ else {
+ event= pupmenu("Add Sequence Strip%t"
+ "|Image Sequence%x1"
+ "|Movie%x102"
+#ifdef WITH_FFMPEG
+ "|Movie + Audio (HD)%x105"
+ "|Audio (RAM)%x103"
+ "|Audio (HD)%x104"
+#else
+ "|Audio (Wav)%x103"
+#endif
+ "|Scene%x101"
+ "|Plugin%x10"
+ "|Cross%x2"
+ "|Gamma Cross%x3"
+ "|Add%x4"
+ "|Sub%x5"
+ "|Mul%x6"
+ "|Alpha Over%x7"
+ "|Alpha Under%x8"
+ "|Alpha Over Drop%x9"
+ "|Wipe%x13"
+ "|Glow%x14"
+ "|Transforms%x15"
+ "|Color Generator%x16"
+ "|Speed Control%x17");
+ }
+
+ if(event<1) return;
+
+ if(G.scene->ed==0) {
+ ed= G.scene->ed= MEM_callocN( sizeof(Editing), "addseq");
+ ed->seqbasep= &ed->seqbase;
+ }
+ else ed= G.scene->ed;
+
+ switch(event) {
+ case 1:
+ /* Image Dosnt work at the moment - TODO */
+ //if(G.qual & LR_CTRLKEY)
+ // activate_imageselect(FILE_SPECIAL, "Select Images", last_imagename, add_image_strips);
+ //else
+ activate_fileselect(FILE_SPECIAL, "Select Images", last_imagename, add_image_strips);
+ break;
+ case 105:
+ activate_fileselect(FILE_SPECIAL, "Select Movie+Audio", last_imagename, add_movie_and_hdaudio_strip);
+ break;
+ case 102:
+
+ activate_fileselect(FILE_SPECIAL, "Select Movie", last_imagename, add_movie_strip);
+ break;
+ case 101:
+ /* new menu: */
+ IDnames_to_pupstring(&str, NULL, NULL, &G.main->scene, (ID *)G.scene, NULL);
+
+ event= pupmenu_col(str, 20);
+
+ if(event> -1) {
+ nr= 1;
+ sce= G.main->scene.first;
+ while(sce) {
+ if( event==nr) break;
+ nr++;
+ sce= sce->id.next;
+ }
+ if(sce) {
+
+ deselect_all_seq();
+
+ /* where ? */
+ getmouseco_areawin(mval);
+ areamouseco_to_ipoco(G.v2d, mval, &x, &y);
+ cfra= (int)(x+0.5);
+ machine= (int)(y+0.5);
+
+ seq= alloc_sequence(((Editing *)G.scene->ed)->seqbasep, cfra, machine);
+ seq->type= SEQ_SCENE;
+ seq->scene= sce;
+ seq->sfra= sce->r.sfra;
+ seq->len= sce->r.efra - sce->r.sfra + 1;
+
+ seq->strip= strip= MEM_callocN(sizeof(Strip), "strip");
+ strncpy(seq->name + 2, sce->id.name + 2,
+ sizeof(seq->name) - 2);
+ strip->len= seq->len;
+ strip->us= 1;
+ if(seq->len>0) strip->stripdata= MEM_callocN(seq->len*sizeof(StripElem), "stripelem");
+
+ BIF_undo_push("Add Scene Strip, Sequencer");
+ transform_seq_nomarker('g', 0);
+ }
+ }
+ MEM_freeN(str);
+
+ break;
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 13:
+ case 14:
+ case 15:
+ case 16:
+ case 17:
+ if(get_last_seq()==0 &&
+ get_sequence_effect_num_inputs( event_to_efftype(event))> 0)
+ error("Need at least one active sequence strip");
+ else if(event==10)
+ activate_fileselect(FILE_SPECIAL, "Select Plugin", U.plugseqdir, load_plugin_seq);
+ else
+ add_seq_effect(event, NULL);
+
+ break;
+ case 103:
+ if (!last_sounddir[0]) strncpy(last_sounddir, U.sounddir, FILE_MAXDIR-1);
+ activate_fileselect(FILE_SPECIAL, "Select Audio (RAM)", last_sounddir, add_sound_strip_ram);
+ break;
+ case 104:
+ if (!last_sounddir[0]) strncpy(last_sounddir, U.sounddir, FILE_MAXDIR-1);
+ activate_fileselect(FILE_SPECIAL, "Select Audio (HD)", last_sounddir, add_sound_strip_hd);
+ break;
+ }
+}
+
+void change_sequence(void)
+{
+ Sequence *last_seq= get_last_seq();
+ Scene *sce;
+ short event;
+
+ if(last_seq==0) return;
+
+ if(last_seq->type & SEQ_EFFECT) {
+ event = pupmenu("Change Effect%t"
+ "|Switch A <-> B %x1"
+ "|Switch B <-> C %x10"
+ "|Plugin%x11"
+ "|Recalculate%x12"
+ "|Cross%x2"
+ "|Gamma Cross%x3"
+ "|Add%x4"
+ "|Sub%x5"
+ "|Mul%x6"
+ "|Alpha Over%x7"
+ "|Alpha Under%x8"
+ "|Alpha Over Drop%x9"
+ "|Wipe%x13"
+ "|Glow%x14"
+ "|Transform%x15"
+ "|Color Generator%x16"
+ "|Speed Control%x17");
+ if(event > 0) {
+ if(event==1) {
+ SWAP(Sequence *,last_seq->seq1,last_seq->seq2);
+ }
+ else if(event==10) {
+ SWAP(Sequence *,last_seq->seq2,last_seq->seq3);
+ }
+ else if(event==11) {
+ activate_fileselect(
+ FILE_SPECIAL, "Select Plugin",
+ U.plugseqdir, change_plugin_seq);
+ }
+ else if(event==12);
+ /* recalculate: only new_stripdata */
+ else {
+ /* free previous effect and init new effect */
+ struct SeqEffectHandle sh;
+
+ if (get_sequence_effect_num_inputs(
+ last_seq->type)
+ < get_sequence_effect_num_inputs(
+ event_to_efftype(event))) {
+ error("New effect needs more "
+ "input strips!");
+ } else {
+ sh = get_sequence_effect(last_seq);
+ sh.free(last_seq);
+
+ last_seq->type
+ = event_to_efftype(event);
+
+ sh = get_sequence_effect(last_seq);
+ sh.init(last_seq);
+ }
+ }
+
+ update_changed_seq_and_deps(last_seq, 0, 1);
+ allqueue(REDRAWSEQ, 0);
+ BIF_undo_push("Change Strip Effect, Sequencer");
+ }
+ }
+ else if(last_seq->type == SEQ_IMAGE) {
+ if(okee("Change images")) {
+ activate_fileselect(FILE_SPECIAL,
+ "Select Images",
+ last_imagename,
+ reload_image_strip);
+ }
+ }
+ else if(last_seq->type == SEQ_MOVIE) {
+ ;
+ }
+ else if(last_seq->type == SEQ_SCENE) {
+ event= pupmenu("Change Scene%t|Update Start and End");
+
+ if(event==1) {
+ sce= last_seq->scene;
+
+ last_seq->len= sce->r.efra - sce->r.sfra + 1;
+ last_seq->sfra= sce->r.sfra;
+ update_changed_seq_and_deps(last_seq, 1, 1);
+
+ allqueue(REDRAWSEQ, 0);
+ }
+ }
+
+}
+
+void reload_sequence(void)
+{
+ Editing *ed= G.scene->ed;
+ Sequence *seq;
+ WHILE_SEQ(ed->seqbasep) {
+ if(seq->flag & SELECT) {
+ update_changed_seq_and_deps(seq, 0, 1);
+ }
+ }
+ END_SEQ
+ allqueue(REDRAWSEQ, 0);
+}
+
+void reassign_inputs_seq_effect()
+{
+ Editing *ed= G.scene->ed;
+ Sequence *seq1, *seq2, *seq3, *last_seq = get_last_seq();
+
+ if(last_seq==0 || !(last_seq->type & SEQ_EFFECT)) return;
+ if(ed==0) return;
+
+ if(!seq_effect_find_selected(ed, last_seq, last_seq->type, &seq1, &seq2, &seq3))
+ return;
+
+ /* see reassigning would create a cycle */
+ if(seq_is_predecessor(seq1, last_seq) || seq_is_predecessor(seq2, last_seq) ||
+ seq_is_predecessor(seq3, last_seq)) {
+ error("Can't reassign inputs: no cycles allowed");
+ return;
+ }
+
+ last_seq->seq1 = seq1;
+ last_seq->seq2 = seq2;
+ last_seq->seq3 = seq3;
+
+ update_changed_seq_and_deps(last_seq, 1, 1);
+
+ allqueue(REDRAWSEQ, 0);
+}
+
+static Sequence *del_seq_find_replace_recurs(Sequence *seq)
+{
+ Sequence *seq1, *seq2, *seq3;
+
+ /* try to find a replacement input sequence, and flag for later deletion if
+ no replacement can be found */
+
+ if(!seq)
+ return NULL;
+ else if(!(seq->type & SEQ_EFFECT))
+ return ((seq->flag & SELECT)? NULL: seq);
+ else if(!(seq->flag & SELECT)) {
+ /* try to find replacement for effect inputs */
+ seq1= del_seq_find_replace_recurs(seq->seq1);
+ seq2= del_seq_find_replace_recurs(seq->seq2);
+ seq3= del_seq_find_replace_recurs(seq->seq3);
+
+ if(seq1==seq->seq1 && seq2==seq->seq2 && seq3==seq->seq3);
+ else if(seq1 || seq2 || seq3) {
+ seq->seq1= (seq1)? seq1: (seq2)? seq2: seq3;
+ seq->seq2= (seq2)? seq2: (seq1)? seq1: seq3;
+ seq->seq3= (seq3)? seq3: (seq1)? seq1: seq2;
+
+ update_changed_seq_and_deps(seq, 1, 1);
+ }
+ else
+ seq->flag |= SELECT; /* mark for delete */
+ }
+
+ if (seq->flag & SELECT) {
+ if((seq1 = del_seq_find_replace_recurs(seq->seq1))) return seq1;
+ if((seq2 = del_seq_find_replace_recurs(seq->seq2))) return seq2;
+ if((seq3 = del_seq_find_replace_recurs(seq->seq3))) return seq3;
+ else return NULL;
+ }
+ else
+ return seq;
+}
+
+static void recurs_del_seq_flag(ListBase *lb, short flag, short deleteall)
+{
+ Sequence *seq, *seqn;
+ Sequence *last_seq = get_last_seq();
+
+ seq= lb->first;
+ while(seq) {
+ seqn= seq->next;
+ if((seq->flag & flag) || deleteall) {
+ if(seq->type==SEQ_RAM_SOUND && seq->sound)
+ seq->sound->id.us--;
+
+ BLI_remlink(lb, seq);
+ if(seq==last_seq) set_last_seq(0);
+ if(seq->type==SEQ_META) recurs_del_seq_flag(&seq->seqbase, flag, 1);
+ if(seq->ipo) seq->ipo->id.us--;
+ free_sequence(seq);
+ }
+ seq= seqn;
+ }
+}
+
+void del_seq(void)
+{
+ Sequence *seq;
+ MetaStack *ms;
+ Editing *ed;
+
+ if(okee("Erase selected")==0) return;
+
+ ed= G.scene->ed;
+ if(ed==0) return;
+
+ /* free imbufs of all dependent strips */
+ for(seq=ed->seqbasep->first; seq; seq=seq->next)
+ if(seq->flag & SELECT)
+ update_changed_seq_and_deps(seq, 1, 0);
+
+ /* for effects, try to find a replacement input */
+ for(seq=ed->seqbasep->first; seq; seq=seq->next)
+ if((seq->type & SEQ_EFFECT) && !(seq->flag & SELECT))
+ del_seq_find_replace_recurs(seq);
+
+ /* delete all selected strips */
+ recurs_del_seq_flag(ed->seqbasep, SELECT, 0);
+
+ /* updates lengths etc */
+ seq= ed->seqbasep->first;
+ while(seq) {
+ calc_sequence(seq);
+ seq= seq->next;
+ }
+
+ /* free parent metas */
+ ms= ed->metastack.last;
+ while(ms) {
+ ms->parseq->strip->len= 0; /* force new alloc */
+ calc_sequence(ms->parseq);
+ ms= ms->prev;
+ }
+
+ BIF_undo_push("Delete Strip(s), Sequencer");
+ allqueue(REDRAWSEQ, 0);
+}
+
+static void recurs_dupli_seq(ListBase *old, ListBase *new)
+{
+ Sequence *seq, *seqn;
+ Sequence *last_seq = get_last_seq();
+ StripElem *se;
+ int a;
+
+ seq= old->first;
+
+ while(seq) {
+ seq->tmp= NULL;
+ if(seq->flag & SELECT) {
+
+ if(seq->type==SEQ_META) {
+ seqn= MEM_dupallocN(seq);
+ seq->tmp= seqn;
+ BLI_addtail(new, seqn);
+
+ seqn->strip= MEM_dupallocN(seq->strip);
+
+ if(seq->len>0) seq->strip->stripdata= MEM_callocN(seq->len*sizeof(StripElem), "stripelem");
+
+ seq->flag &= SEQ_DESEL;
+ seqn->flag &= ~(SEQ_LEFTSEL+SEQ_RIGHTSEL);
+
+ seqn->seqbase.first= seqn->seqbase.last= 0;
+ recurs_dupli_seq(&seq->seqbase,&seqn->seqbase);
+
+ }
+ else if(seq->type == SEQ_SCENE) {
+ seqn= MEM_dupallocN(seq);
+ seq->tmp= seqn;
+ BLI_addtail(new, seqn);
+
+ seqn->strip= MEM_dupallocN(seq->strip);
+
+ if(seq->len>0) seqn->strip->stripdata = MEM_callocN(seq->len*sizeof(StripElem), "stripelem");
+
+ seq->flag &= SEQ_DESEL;
+ seqn->flag &= ~(SEQ_LEFTSEL+SEQ_RIGHTSEL);
+ }
+ else if(seq->type == SEQ_MOVIE) {
+ seqn= MEM_dupallocN(seq);
+ seq->tmp= seqn;
+ BLI_addtail(new, seqn);
+
+ seqn->strip= MEM_dupallocN(seq->strip);
+ seqn->anim= 0;
+
+ if(seqn->len>0) {
+ seqn->strip->stripdata= MEM_callocN(seq->len*sizeof(StripElem), "stripelem");
+ /* copy first elem */
+ *seqn->strip->stripdata= *seq->strip->stripdata;
+ se= seqn->strip->stripdata;
+ a= seq->len;
+ while(a--) {
+ se->ok= 1;
+ se++;
+ }
+ }
+
+ seq->flag &= SEQ_DESEL;
+ seqn->flag &= ~(SEQ_LEFTSEL+SEQ_RIGHTSEL);
+ }
+ else if(seq->type == SEQ_RAM_SOUND) {
+ seqn= MEM_dupallocN(seq);
+ seq->tmp= seqn;
+ BLI_addtail(new, seqn);
+
+ seqn->strip= MEM_dupallocN(seq->strip);
+ seqn->anim= 0;
+ seqn->sound->id.us++;
+ if(seqn->ipo) seqn->ipo->id.us++;
+
+ if(seqn->len>0) {
+ seqn->strip->stripdata= MEM_callocN(seq->len*sizeof(StripElem), "stripelem");
+ /* copy first elem */
+ *seqn->strip->stripdata= *seq->strip->stripdata;
+ se= seqn->strip->stripdata;
+ a= seq->len;
+ while(a--) {
+ se->ok= 1;
+ se++;
+ }
+ }
+
+ seq->flag &= SEQ_DESEL;
+ seqn->flag &= ~(SEQ_LEFTSEL+SEQ_RIGHTSEL);
+ }
+ else if(seq->type == SEQ_HD_SOUND) {
+ seqn= MEM_dupallocN(seq);
+ seq->tmp= seqn;
+ BLI_addtail(new, seqn);
+
+ seqn->strip= MEM_dupallocN(seq->strip);
+ seqn->anim= 0;
+ seqn->hdaudio = 0;
+ if(seqn->ipo) seqn->ipo->id.us++;
+
+ if(seqn->len>0) {
+ seqn->strip->stripdata= MEM_callocN(seq->len*sizeof(StripElem), "stripelem");
+ /* copy first elem */
+ *seqn->strip->stripdata= *seq->strip->stripdata;
+ se= seqn->strip->stripdata;
+ a= seq->len;
+ while(a--) {
+ se->ok= 1;
+ se++;
+ }
+ }
+
+ seq->flag &= SEQ_DESEL;
+ seqn->flag &= ~(SEQ_LEFTSEL+SEQ_RIGHTSEL);
+ }
+ else if(seq->type < SEQ_EFFECT) {
+ seqn= MEM_dupallocN(seq);
+ seq->tmp= seqn;
+ BLI_addtail(new, seqn);
+
+ seqn->strip->us++;
+ seq->flag &= SEQ_DESEL;
+
+ seqn->flag &= ~(SEQ_LEFTSEL+SEQ_RIGHTSEL);
+ }
+ else {
+ seqn= MEM_dupallocN(seq);
+ seq->tmp= seqn;
+ BLI_addtail(new, seqn);
+
+ if(seq->seq1 && seq->seq1->tmp) seqn->seq1= seq->seq1->tmp;
+ if(seq->seq2 && seq->seq2->tmp) seqn->seq2= seq->seq2->tmp;
+ if(seq->seq3 && seq->seq3->tmp) seqn->seq3= seq->seq3->tmp;
+
+ if(seqn->ipo) seqn->ipo->id.us++;
+
+ if (seq->type & SEQ_EFFECT) {
+ struct SeqEffectHandle sh;
+ sh = get_sequence_effect(seq);
+ if(sh.copy)
+ sh.copy(seq, seqn);
+ }
+
+ seqn->strip= MEM_dupallocN(seq->strip);
+
+ if(seq->len>0) seq->strip->stripdata= MEM_callocN(seq->len*sizeof(StripElem), "stripelem");
+
+ seq->flag &= SEQ_DESEL;
+
+ seqn->flag &= ~(SEQ_LEFTSEL+SEQ_RIGHTSEL);
+ }
+ if (seq == last_seq) {
+ set_last_seq(seqn);
+ }
+ }
+ seq= seq->next;
+ }
+}
+
+void add_duplicate_seq(void)
+{
+ Editing *ed;
+ ListBase new;
+
+ ed= G.scene->ed;
+ if(ed==0) return;
+
+ new.first= new.last= 0;
+
+ recurs_dupli_seq(ed->seqbasep, &new);
+ addlisttolist(ed->seqbasep, &new);
+
+ BIF_undo_push("Add Duplicate, Sequencer");
+ transform_seq_nomarker('g', 0);
+}
+
+int insert_gap(int gap, int cfra)
+{
+ Sequence *seq;
+ Editing *ed;
+ int done=0;
+
+ /* all strips >= cfra are shifted */
+ ed= G.scene->ed;
+ if(ed==0) return 0;
+
+ WHILE_SEQ(ed->seqbasep) {
+ if(seq->startdisp >= cfra) {
+ seq->start+= gap;
+ calc_sequence(seq);
+ done= 1;
+ }
+ }
+ END_SEQ
+
+ return done;
+}
+
+void touch_seq_files(void)
+{
+ Sequence *seq;
+ Editing *ed;
+ char str[256];
+
+ /* touch all strips with movies */
+ ed= G.scene->ed;
+ if(ed==0) return;
+
+ if(okee("Touch and print selected movies")==0) return;
+
+ waitcursor(1);
+
+ WHILE_SEQ(ed->seqbasep) {
+ if(seq->flag & SELECT) {
+ if(seq->type==SEQ_MOVIE) {
+ if(seq->strip && seq->strip->stripdata) {
+ BLI_make_file_string(G.sce, str, seq->strip->dir, seq->strip->stripdata->name);
+ BLI_touch(seq->name);
+ }
+ }
+
+ }
+ }
+ END_SEQ
+
+ waitcursor(0);
+}
+
+void set_filter_seq(void)
+{
+ Sequence *seq;
+ Editing *ed;
+
+ ed= G.scene->ed;
+ if(ed==0) return;
+
+ if(okee("Set FilterY")==0) return;
+
+ WHILE_SEQ(ed->seqbasep) {
+ if(seq->flag & SELECT) {
+ if(seq->type==SEQ_MOVIE) {
+ seq->flag |= SEQ_FILTERY;
+ }
+
+ }
+ }
+ END_SEQ
+
+}
+
+void seq_remap_paths(void)
+{
+ Sequence *seq, *last_seq = get_last_seq();
+ Editing *ed;
+ char from[FILE_MAX], to[FILE_MAX], stripped[FILE_MAX];
+
+ ed= G.scene->ed;
+ if(ed==NULL || last_seq==NULL)
+ return;
+
+ BLI_strncpy(from, last_seq->strip->dir, FILE_MAX);
+ if (0==sbutton(from, 0, sizeof(from)-1, "From: "))
+ return;
+
+ strcpy(to, from);
+ if (0==sbutton(to, 0, sizeof(to)-1, "To: "))
+ return;
+
+ if (strcmp(to, from)==0)
+ return;
+
+ WHILE_SEQ(ed->seqbasep) {
+ if(seq->flag & SELECT) {
+ if(strncmp(seq->strip->dir, from, strlen(from))==0) {
+ printf("found %s\n", seq->strip->dir);
+
+ /* strip off the beginning */
+ stripped[0]= 0;
+ BLI_strncpy(stripped, seq->strip->dir + strlen(from), FILE_MAX);
+
+ /* new path */
+ BLI_strncpy(seq->strip->dir, to, FILE_MAX);
+ strcat(seq->strip->dir, stripped);
+ printf("new %s\n", seq->strip->dir);
+ }
+ }
+ }
+ END_SEQ
+
+ BIF_undo_push("Remap Paths, Sequencer");
+ allqueue(REDRAWSEQ, 0);
+}
+
+
+void no_gaps(void)
+{
+ Editing *ed;
+ int cfra, first= 0, done;
+
+ ed= G.scene->ed;
+ if(ed==0) return;
+
+ for(cfra= CFRA; cfra<=EFRA; cfra++) {
+ if(first==0) {
+ if( evaluate_seq_frame(cfra) ) first= 1;
+ }
+ else {
+ done= 1;
+ while( evaluate_seq_frame(cfra) == 0) {
+ done= insert_gap(-1, cfra);
+ if(done==0) break;
+ }
+ if(done==0) break;
+ }
+ }
+
+ BIF_undo_push("No Gaps, Sequencer");
+ allqueue(REDRAWSEQ, 0);
+}
+
+
+/* ****************** META ************************* */
+
+void make_meta(void)
+{
+ Sequence *seq, *seqm, *next;
+ Editing *ed;
+ int tot;
+
+ ed= G.scene->ed;
+ if(ed==0) return;
+
+ /* is there more than 1 select */
+ tot= 0;
+ seq= ed->seqbasep->first;
+ while(seq) {
+ if(seq->flag & SELECT) {
+ tot++;
+ if (seq->type == SEQ_RAM_SOUND) {
+ error("Can't make Meta Strip from audio");
+ return;
+ }
+ }
+ seq= seq->next;
+ }
+ if(tot < 2) return;
+
+ if(okee("Make Meta Strip")==0) return;
+
+ /* test relationships */
+ seq= ed->seqbasep->first;
+ while(seq) {
+ if(seq->flag & SELECT) {
+ if(seq->type & SEQ_EFFECT) {
+ if(seq->seq1 &&
+ (seq->seq1->flag & SELECT)==0) tot= 0;
+ if(seq->seq2 &&
+ (seq->seq2->flag & SELECT)==0) tot= 0;
+ if(seq->seq3 &&
+ (seq->seq3->flag & SELECT)==0) tot= 0;
+ }
+ }
+ else if(seq->type & SEQ_EFFECT) {
+ if(seq->seq1 &&
+ (seq->seq1->flag & SELECT)) tot= 0;
+ if(seq->seq2 &&
+ (seq->seq2->flag & SELECT)) tot= 0;
+ if(seq->seq3 &&
+ (seq->seq3->flag & SELECT)) tot= 0;
+ }
+ if(tot==0) break;
+ seq= seq->next;
+ }
+ if(tot==0) {
+ error("Please select all related strips");
+ return;
+ }
+
+ /* remove all selected from main list, and put in meta */
+
+ seqm= alloc_sequence(((Editing *)G.scene->ed)->seqbasep, 1, 1);
+ seqm->type= SEQ_META;
+ seqm->flag= SELECT;
+
+ seq= ed->seqbasep->first;
+ while(seq) {
+ next= seq->next;
+ if(seq!=seqm && (seq->flag & SELECT)) {
+ BLI_remlink(ed->seqbasep, seq);
+ BLI_addtail(&seqm->seqbase, seq);
+ }
+ seq= next;
+ }
+ calc_sequence(seqm);
+
+ seqm->strip= MEM_callocN(sizeof(Strip), "metastrip");
+ seqm->strip->len= seqm->len;
+ seqm->strip->us= 1;
+ if(seqm->len) seqm->strip->stripdata= MEM_callocN(seqm->len*sizeof(StripElem), "metastripdata");
+ set_meta_stripdata(seqm);
+
+ BIF_undo_push("Make Meta Strip, Sequencer");
+ allqueue(REDRAWSEQ, 0);
+}
+
+static int seq_depends_on_meta(Sequence *seq, Sequence *seqm)
+{
+ if (seq == seqm) return 1;
+ else if (seq->seq1 && seq_depends_on_meta(seq->seq1, seqm)) return 1;
+ else if (seq->seq2 && seq_depends_on_meta(seq->seq2, seqm)) return 1;
+ else if (seq->seq3 && seq_depends_on_meta(seq->seq3, seqm)) return 1;
+ else return 0;
+}
+
+void un_meta(void)
+{
+ Editing *ed;
+ Sequence *seq, *last_seq = get_last_seq();
+
+ ed= G.scene->ed;
+ if(ed==0) return;
+
+ if(last_seq==0 || last_seq->type!=SEQ_META) return;
+
+ if(okee("Un Meta Strip")==0) return;
+
+ addlisttolist(ed->seqbasep, &last_seq->seqbase);
+
+ last_seq->seqbase.first= 0;
+ last_seq->seqbase.last= 0;
+
+ BLI_remlink(ed->seqbasep, last_seq);
+ free_sequence(last_seq);
+
+ /* emtpy meta strip, delete all effects depending on it */
+ for(seq=ed->seqbasep->first; seq; seq=seq->next)
+ if((seq->type & SEQ_EFFECT) && seq_depends_on_meta(seq, last_seq))
+ seq->flag |= SEQ_FLAG_DELETE;
+
+ recurs_del_seq_flag(ed->seqbasep, SEQ_FLAG_DELETE, 0);
+
+ /* test for effects and overlap */
+ WHILE_SEQ(ed->seqbasep) {
+ if(seq->flag & SELECT) {
+ seq->flag &= ~SEQ_OVERLAP;
+ if( test_overlap_seq(seq) ) {
+ shuffle_seq(seq);
+ }
+ }
+ }
+ END_SEQ;
+
+ sort_seq();
+
+ BIF_undo_push("Un-Make Meta Strip, Sequencer");
+ allqueue(REDRAWSEQ, 0);
+
+}
+
+void exit_meta(void)
+{
+ Sequence *seq;
+ MetaStack *ms;
+ Editing *ed;
+
+ ed= G.scene->ed;
+ if(ed==0) return;
+
+ if(ed->metastack.first==0) return;
+
+ ms= ed->metastack.last;
+ BLI_remlink(&ed->metastack, ms);
+
+ ed->seqbasep= ms->oldbasep;
+
+ /* recalc entire meta */
+ set_meta_stripdata(ms->parseq);
+
+ /* recalc all: the meta can have effects connected to it */
+ seq= ed->seqbasep->first;
+ while(seq) {
+ calc_sequence(seq);
+ seq= seq->next;
+ }
+
+ set_last_seq(ms->parseq);
+
+ ms->parseq->flag= SELECT;
+ recurs_sel_seq(ms->parseq);
+
+ MEM_freeN(ms);
+ allqueue(REDRAWSEQ, 0);
+
+ BIF_undo_push("Exit Meta Strip, Sequence");
+}
+
+
+void enter_meta(void)
+{
+ MetaStack *ms;
+ Editing *ed;
+ Sequence *last_seq= get_last_seq();
+
+ ed= G.scene->ed;
+ if(ed==0) return;
+
+ if(last_seq==0 || last_seq->type!=SEQ_META || last_seq->flag==0) {
+ exit_meta();
+ return;
+ }
+
+ ms= MEM_mallocN(sizeof(MetaStack), "metastack");
+ BLI_addtail(&ed->metastack, ms);
+ ms->parseq= last_seq;
+ ms->oldbasep= ed->seqbasep;
+
+ ed->seqbasep= &last_seq->seqbase;
+
+ set_last_seq(NULL);
+ allqueue(REDRAWSEQ, 0);
+ BIF_undo_push("Enter Meta Strip, Sequence");
+}
+
+
+/* ****************** END META ************************* */
+
+static int seq_get_snaplimit(void)
+{
+ /* fake mouse coords to get the snap value
+ a bit lazy but its only done once pre transform */
+ float xmouse, ymouse, x;
+ short mval[2] = {24, 0}; /* 24 screen px snap */
+ areamouseco_to_ipoco(G.v2d, mval, &xmouse, &ymouse);
+ x = xmouse;
+ mval[0] = 0;
+ areamouseco_to_ipoco(G.v2d, mval, &xmouse, &ymouse);
+ return (int)(x - xmouse);
+}
+
+typedef struct TransSeq {
+ int start, machine;
+ int startstill, endstill;
+ int startdisp, enddisp;
+ int startofs, endofs;
+ int final_left, final_right;
+ int len;
+} TransSeq;
+
+/* use to impose limits when dragging/extending - so impossible situations dont happen */
+static void transform_grab_xlimits(Sequence *seq, int leftflag, int rightflag)
+{
+ if(leftflag) {
+ if (seq_tx_get_final_left(seq) >= seq_tx_get_final_right(seq)) {
+ seq_tx_set_final_left(seq, seq_tx_get_final_right(seq)-1);
+ }
+
+ if (check_single_seq(seq)==0) {
+ if (seq_tx_get_final_left(seq) >= seq_tx_get_end(seq)) {
+ seq_tx_set_final_left(seq, seq_tx_get_end(seq)-1);
+ }
+
+ /* dosnt work now - TODO */
+ /*
+ if (seq_tx_get_start(seq) >= seq_tx_get_final_right(seq)) {
+ int ofs;
+ ofs = seq_tx_get_start(seq) - seq_tx_get_final_right(seq);
+ seq->start -= ofs;
+ seq_tx_set_final_left(seq, seq_tx_get_final_left(seq) + ofs );
+ }*/
+
+ }
+ }
+
+ if(rightflag) {
+ if (seq_tx_get_final_right(seq) <= seq_tx_get_final_left(seq)) {
+ seq_tx_set_final_right(seq, seq_tx_get_final_left(seq)+1);
+ }
+
+ if (check_single_seq(seq)==0) {
+ if (seq_tx_get_final_right(seq) <= seq_tx_get_start(seq)) {
+ seq_tx_set_final_right(seq, seq_tx_get_start(seq)+1);
+ }
+ }
+ }
+
+ /* sounds cannot be extended past their endpoints */
+ if (seq->type == SEQ_RAM_SOUND || seq->type == SEQ_HD_SOUND) {
+ seq->startstill= 0;
+ seq->endstill= 0;
+ }
+}
+
+void transform_seq(int mode, int context)
+{
+ SpaceSeq *sseq= curarea->spacedata.first;
+ Sequence *seq, *last_seq;
+ Editing *ed;
+ float dx, dy, dvec[2], div;
+ TransSeq *transmain, *ts;
+ int totstrip=0, firsttime=1, afbreek=0, midtog= 0, proj= 0;
+ int ix, iy; /* these values are used for storing the mouses offset from its original location */
+ int ix_old = 0;
+ unsigned short event = 0;
+ short mval[2], val, xo, yo, xn, yn;
+ char str[32];
+ char side= 'L'; /* for extend mode only - use to know which side to extend on */
+ char marker_moved=0; /* if we mvoed a marker, redraw all marker views */
+ /* used for extend in a number of places */
+ int cfra = CFRA;
+
+ /* for snapping */
+ char snapskip = 0, snap, snap_old= 0;
+ int snapdist_max = seq_get_snaplimit();
+ /* at the moment there are only 4 possible snap points,
+ - last_seq (start,end)
+ - selected bounds (start/end)
+ - last_seq (next/prev)
+ - current frame */
+ int snap_points[4], snap_point_num = 0;
+ int j; /* loop on snap_points */
+
+ /* for markers */
+ int *oldframe = NULL, totmark=0, a;
+ TimeMarker *marker;
+
+
+ if(mode!='g' && mode!='e') return; /* from gesture */
+
+ /* which seqs are involved */
+ ed= G.scene->ed;
+ if(ed==0) return;
+
+ WHILE_SEQ(ed->seqbasep) {
+ if(seq->flag & SELECT) totstrip++;
+ }
+ END_SEQ
+
+
+ if (sseq->flag & SEQ_MARKER_TRANS) {
+ for(marker= G.scene->markers.first; marker; marker= marker->next) {
+ if(marker->flag & SELECT) totmark++;
+ }
+ }
+ if(totstrip==0 && totmark==0) return;
+
+ G.moving= 1;
+
+ last_seq = get_last_seq();
+
+ ts=transmain= MEM_callocN(totstrip*sizeof(TransSeq), "transseq");
+
+ WHILE_SEQ(ed->seqbasep) {
+
+ if(seq->flag & SELECT) {
+ ts->start= seq->start;
+ ts->machine= seq->machine;
+ ts->startstill= seq->startstill;
+ ts->endstill= seq->endstill;
+ ts->startofs= seq->startofs;
+ ts->endofs= seq->endofs;
+
+ /* for extend only */
+ if (mode=='e') {
+ ts->final_left = seq_tx_get_final_left(seq);
+ ts->final_right = seq_tx_get_final_right(seq);
+ }
+ ts++;
+ }
+ }
+ END_SEQ
+
+ getmouseco_areawin(mval);
+
+ /* choose the side based on which side of the playhead the mouse is on */
+ if (mode=='e') {
+ float xmouse, ymouse;
+ areamouseco_to_ipoco(G.v2d, mval, &xmouse, &ymouse);
+ side = (xmouse > cfra) ? 'R' : 'L';
+ }
+
+ /* Markers */
+ if (sseq->flag & SEQ_MARKER_TRANS && totmark) {
+ oldframe= MEM_mallocN(totmark*sizeof(int), "marker array");
+ for(a=0, marker= G.scene->markers.first; marker; marker= marker->next) {
+ if(marker->flag & SELECT) {
+ if (mode=='e') {
+
+ /* when extending, invalidate markers on the other side by using an invalid frame value */
+ if ((side == 'L' && marker->frame > cfra) || (side == 'R' && marker->frame < cfra)) {
+ oldframe[a] = MAXFRAME+1;
+ } else {
+ oldframe[a]= marker->frame;
+ }
+ } else {
+ oldframe[a]= marker->frame;
+ }
+ a++;
+ }
+ }
+ }
+
+ xo=xn= mval[0];
+ yo=yn= mval[1];
+ dvec[0]= dvec[1]= 0.0;
+
+ while(afbreek==0) {
+ getmouseco_areawin(mval);
+ G.qual = get_qual();
+ snap = (G.qual & LR_CTRLKEY) ? 1 : 0;
+
+ if(mval[0]!=xo || mval[1]!=yo || firsttime || snap != snap_old) {
+ if (firsttime) {
+ snap_old = snap;
+ firsttime= 0;
+ }
+
+ /* run for either grab or extend */
+ dx= mval[0]- xo;
+ dy= mval[1]- yo;
+
+ div= G.v2d->mask.xmax-G.v2d->mask.xmin;
+ dx= (G.v2d->cur.xmax-G.v2d->cur.xmin)*(dx)/div;
+
+ div= G.v2d->mask.ymax-G.v2d->mask.ymin;
+ dy= (G.v2d->cur.ymax-G.v2d->cur.ymin)*(dy)/div;
+
+ if(G.qual & LR_SHIFTKEY) {
+ if(dx>1.0) dx= 1.0; else if(dx<-1.0) dx= -1.0;
+ }
+
+ dvec[0]+= dx;
+ dvec[1]+= dy;
+
+ if(midtog) dvec[proj]= 0.0;
+ ix= floor(dvec[0]+0.5);
+ iy= floor(dvec[1]+0.5);
+
+ ts= transmain;
+
+ /* SNAP! use the active Seq */
+ snap = G.qual & LR_CTRLKEY ? 1 : 0;
+
+ if (!snap) {
+ snapskip = 0;
+ } else {
+ int dist;
+ int snap_ofs= 0;
+ int snap_dist= snapdist_max;
+
+ /* Get sequence points to snap to the markers */
+
+ snap_point_num=0;
+ if (last_seq && (last_seq->flag & SELECT)) { /* active seq bounds */
+ if(seq_tx_check_left(last_seq))
+ snap_points[snap_point_num++] = seq_tx_get_final_left(last_seq);
+ if(seq_tx_check_right(last_seq))
+ snap_points[snap_point_num++] = seq_tx_get_final_right(last_seq);
+
+ }
+ if (totstrip > 1) { /* selection bounds */
+ int bounds_left = MAXFRAME*2;
+ int bounds_right = -(MAXFRAME*2);
+
+ WHILE_SEQ(ed->seqbasep) {
+ if(seq->flag & SELECT) {
+ if(seq_tx_check_left(seq))
+ bounds_left = MIN2(bounds_left, seq_tx_get_final_left(seq));
+ if(seq_tx_check_right(seq))
+ bounds_right = MAX2(bounds_right,seq_tx_get_final_right(seq));
+ }
+ }
+ END_SEQ
+
+ /* its possible there were no points to set on either side */
+ if (bounds_left != MAXFRAME*2)
+ snap_points[snap_point_num++] = bounds_left;
+ if (bounds_right != -(MAXFRAME*2))
+ snap_points[snap_point_num++] = bounds_right;
+ }
+
+
+ /* Define so we can snap to other points without hassle */
+
+#define TESTSNAP(test_frame)\
+ for(j=0; j<snap_point_num; j++) {\
+ /* see if this beats the current best snap point */\
+ dist = abs(snap_points[j] - test_frame);\
+ if (dist < snap_dist) {\
+ snap_ofs = test_frame - snap_points[j];\
+ snap_dist = dist;\
+ }\
+ }
+
+
+ /* Detect the best marker to snap to! */
+ for(a=0, marker= G.scene->markers.first; marker; a++, marker= marker->next) {
+
+ /* dont snap to a marker on the wrong extend side */
+ if (mode=='e' && ((side == 'L' && marker->frame > cfra) || (side == 'R' && marker->frame < cfra)))
+ continue;
+
+ /* when we are moving markers, dont snap to selected markers, durr */
+ if ((sseq->flag & SEQ_MARKER_TRANS)==0 || (marker->flag & SELECT)==0) {
+
+ /* loop over the sticky points - max 4 */
+ TESTSNAP(marker->frame);
+ if (snap_dist == 0) break; /* alredy snapped? - stop looking */
+ }
+ }
+
+ if (snap_dist) {
+ TESTSNAP(cfra);
+ }
+
+ /* check seq's next to the active also - nice for quick snapping */
+ if (snap_dist && last_seq && seq_tx_check_left(last_seq)) {
+ seq = find_next_prev_sequence(last_seq, 1, 0); /* left */
+ if(seq && !seq_tx_check_right(seq))
+ TESTSNAP(seq_tx_get_final_right(seq));
+ }
+
+ if (snap_dist && last_seq && seq_tx_check_right(last_seq)) {
+ seq = find_next_prev_sequence(last_seq, 2, 0); /* right */
+ if(seq && !seq_tx_check_left(seq))
+ TESTSNAP(seq_tx_get_final_left(seq));
+ }
+
+#undef TESTSNAP
+
+ if (abs(ix_old-ix) >= snapdist_max) {
+ /* mouse has moved out of snap range */
+ snapskip = 0;
+ } else if (snap_dist==0) {
+ /* nowhere to move, dont do anything */
+ snapskip = 1;
+ } else if (snap_dist < snapdist_max) {
+ /* do the snapping by adjusting the mouse offset value */
+ ix = ix_old + snap_ofs;
+ }
+ }
+
+ if (mode=='g' && !snapskip) {
+ /* Grab */
+ WHILE_SEQ(ed->seqbasep) {
+ if(seq->flag & SELECT) {
+ int myofs;
+ // SEQ_DEBUG_INFO(seq);
+
+ /* X Transformation */
+ if(seq->flag & SEQ_LEFTSEL) {
+ myofs = (ts->startofs - ts->startstill);
+ seq_tx_set_final_left(seq, ts->start + (myofs + ix));
+ }
+ if(seq->flag & SEQ_RIGHTSEL) {
+ myofs = (ts->endstill - ts->endofs);
+ seq_tx_set_final_right(seq, ts->start + seq->len + (myofs + ix));
+ }
+ transform_grab_xlimits(seq, seq->flag & SEQ_LEFTSEL, seq->flag & SEQ_RIGHTSEL);
+
+ if( (seq->flag & (SEQ_LEFTSEL+SEQ_RIGHTSEL))==0 ) {
+ if(sequence_is_free_transformable(seq)) seq->start= ts->start+ ix;
+
+ /* Y Transformation */
+ if(seq->depth==0) seq->machine= ts->machine+ iy;
+
+ if(seq->machine<1) seq->machine= 1;
+ else if(seq->machine>= MAXSEQ) seq->machine= MAXSEQ;
+ }
+ calc_sequence(seq);
+ ts++;
+ }
+ }
+ END_SEQ
+
+ /* Markers */
+ if (sseq->flag & SEQ_MARKER_TRANS) {
+ for(a=0, marker= G.scene->markers.first; marker; marker= marker->next) {
+ if(marker->flag & SELECT) {
+ marker->frame= oldframe[a] + ix;
+ marker_moved=1;
+ a++;
+ }
+ }
+ }
+
+ /* Extend, grabs one side of the current frame */
+ } else if (mode=='e' && !snapskip) {
+ int myofs; /* offset from start of the seq clip */
+ int xnew, final_left, final_right; /* just to store results from seq_tx_get_final_left/right */
+
+ /* we dont use seq side selection flags for this,
+ instead we need to calculate which sides to move
+ based on its initial position from the cursor */
+ int move_left, move_right;
+
+ /* Extend, Similar to grab but operate on one side of the cursor */
+ WHILE_SEQ(ed->seqbasep) {
+ if(seq->flag & SELECT) {
+ /* only move the contents of the metastrip otherwise the transformation is applied twice */
+ if (sequence_is_free_transformable(seq) && seq->type != SEQ_META) {
+
+ move_left = move_right = 0;
+
+ //SEQ_DEBUG_INFO(seq);
+
+ final_left = seq_tx_get_final_left(seq);
+ final_right = seq_tx_get_final_right(seq);
+
+ /* Only X Axis moving */
+
+ /* work out which sides to move first */
+ if (side=='L') {
+ if (final_left <= cfra || ts->final_left <= cfra) move_left = 1;
+ if (final_right <= cfra || ts->final_right <= cfra) move_right = 1;
+ } else {
+ if (final_left >= cfra || ts->final_left >= cfra) move_left = 1;
+ if (final_right >= cfra || ts->final_right >= cfra) move_right = 1;
+ }
+
+ if (move_left && move_right) {
+ /* simple move - dont need to do anything complicated */
+ seq->start= ts->start+ ix;
+ } else {
+ if (side=='L') {
+ if (move_left) {
+
+ /* Similar to other funcs */
+ myofs = (ts->startofs - ts->startstill);
+ xnew = ts->start + (ix + myofs);
+
+ /* make sure the we dont resize down to 0 or less in size
+ also include the startstill so the contense dosnt go outside the bounds,
+ if the seq->startofs is 0 then its ignored */
+
+ /* TODO remove, add check to transform_grab_xlimits, works ok for now */
+ if (xnew + seq->startstill > final_right-1) {
+ xnew = (final_right-1) - seq->startstill;
+ }
+ /* Note, this is the only case where the start needs to be adjusted
+ since its not needed when modifying the end or when moving the entire sequence */
+ //seq->start = ts->start+ix; // This works when xnew is not clamped, line below takes clamping into account
+ seq->start= xnew - myofs; /* TODO see above */
+ /* done with unique stuff */
+
+ seq_tx_set_final_left(seq, xnew);
+ transform_grab_xlimits(seq, 1, 0);
+
+ /* Special case again - setting the end back to what it was */
+ seq_tx_set_final_right(seq, final_right);
+ }
+ if (move_right) {
+ myofs = (ts->endstill - ts->endofs);
+ xnew = ts->start + seq->len + (myofs + ix);
+ seq_tx_set_final_right(seq, xnew);
+ transform_grab_xlimits(seq, 0, 1);
+ }
+ } else { /* R */
+ if (move_left) {
+ myofs = (ts->startofs - ts->startstill);
+ xnew = ts->start + (myofs + ix);
+ seq_tx_set_final_left(seq, xnew);
+ transform_grab_xlimits(seq, 1, 0);
+ }
+ if (move_right) {
+ myofs = (ts->endstill - ts->endofs);
+ xnew = ts->start + seq->len + (myofs + ix);
+ seq_tx_set_final_right(seq, xnew);
+ transform_grab_xlimits(seq, 0, 1);
+ }
+ }
+ }
+ }
+ calc_sequence(seq);
+ ts++;
+ }
+ }
+ END_SEQ
+
+ /* markers */
+ if (sseq->flag & SEQ_MARKER_TRANS) {
+ for(a=0, marker= G.scene->markers.first; marker; marker= marker->next) {\
+ if (marker->flag & SELECT) {
+ if(oldframe[a] != MAXFRAME+1) {
+ marker->frame= oldframe[a] + ix;
+ marker_moved=1;
+ }
+ a++;
+ }
+ }
+ }
+ }
+
+ sprintf(str, "X: %d Y: %d ", ix, iy);
+ headerprint(str);
+
+ /* remember the last value for snapping,
+ only set if we are not currently snapped,
+ prevents locking on a keyframe */
+ if (!snapskip)
+ ix_old = ix;
+
+ /* just to tell if ctrl was pressed, this means we get a recalc when pressing ctrl */
+ snap_old = snap;
+
+ /* rememver last mouse values so we can skip transform when nothing happens */
+ xo= mval[0];
+ yo= mval[1];
+
+ /* test for effect and overlap */
+ WHILE_SEQ(ed->seqbasep) {
+ if(seq->flag & SELECT) {
+ seq->flag &= ~SEQ_OVERLAP;
+ if( test_overlap_seq(seq) ) {
+ seq->flag |= SEQ_OVERLAP;
+ }
+ }
+ else if(seq->type & SEQ_EFFECT) {
+ if(seq->seq1 && seq->seq1->flag & SELECT) calc_sequence(seq);
+ else if(seq->seq2 && seq->seq2->flag & SELECT) calc_sequence(seq);
+ else if(seq->seq3 && seq->seq3->flag & SELECT) calc_sequence(seq);
+ }
+ }
+ END_SEQ;
+
+ force_draw(0);
+
+ }
+ else BIF_wait_for_statechange();
+
+ while(qtest()) {
+ event= extern_qread(&val);
+ if(val) {
+ switch(event) {
+ case ESCKEY:
+ case LEFTMOUSE:
+ case RIGHTMOUSE:
+ case SPACEKEY:
+ case RETKEY:
+ afbreek= 1;
+ break;
+ case MIDDLEMOUSE:
+ midtog= ~midtog;
+ if(midtog) {
+ if( abs(mval[0]-xn) > abs(mval[1]-yn)) proj= 1;
+ else proj= 0;
+ firsttime= 1;
+ }
+ break;
+ default:
+ arrows_move_cursor(event);
+ }
+ }
+ if(afbreek) break;
+ }
+ }
+
+ if((event==ESCKEY) || (event==RIGHTMOUSE)) {
+
+ ts= transmain;
+ WHILE_SEQ(ed->seqbasep) {
+ if(seq->flag & SELECT) {
+ seq->start= ts->start;
+ seq->machine= ts->machine;
+ seq->startstill= ts->startstill;
+ seq->endstill= ts->endstill;
+ seq->startofs= ts->startofs;
+ seq->endofs= ts->endofs;
+
+ calc_sequence(seq);
+ seq->flag &= ~SEQ_OVERLAP;
+
+ ts++;
+ } else if(seq->type & SEQ_EFFECT) {
+ if(seq->seq1 && seq->seq1->flag & SELECT) calc_sequence(seq);
+ else if(seq->seq2 && seq->seq2->flag & SELECT) calc_sequence(seq);
+ else if(seq->seq3 && seq->seq3->flag & SELECT) calc_sequence(seq);
+ }
+ }
+ END_SEQ
+
+
+ /* Markers */
+ if (sseq->flag & SEQ_MARKER_TRANS) {
+ for(a=0, marker= G.scene->markers.first; marker; marker= marker->next) {
+ if (marker->flag & SELECT) {
+ if(oldframe[a] != MAXFRAME+1) {
+ marker->frame= oldframe[a];
+ }
+ a++;
+ }
+ }
+ marker_moved = 0;
+ }
+ } else {
+
+ /* images, effects and overlap */
+ WHILE_SEQ(ed->seqbasep) {
+
+ /* fixes single image strips - makes sure their start is not out of bounds
+ ideally this would be done during transform since data is rendered at that time
+ however it ends up being a lot messier! - Campbell */
+ fix_single_image_seq(seq);
+
+ if(seq->type == SEQ_META) {
+ calc_sequence(seq);
+ seq->flag &= ~SEQ_OVERLAP;
+ if( test_overlap_seq(seq) ) shuffle_seq(seq);
+ }
+ else if(seq->flag & SELECT) {
+ calc_sequence(seq);
+ seq->flag &= ~SEQ_OVERLAP;
+ if( test_overlap_seq(seq) ) shuffle_seq(seq);
+ }
+ else if(seq->type & SEQ_EFFECT) calc_sequence(seq);
+ }
+ END_SEQ
+
+ /* as last: */
+ sort_seq();
+ }
+
+ G.moving= 0;
+ MEM_freeN(transmain);
+
+ if (sseq->flag & SEQ_MARKER_TRANS && totmark)
+ MEM_freeN(oldframe);
+
+ if (mode=='g')
+ BIF_undo_push("Transform Grab, Sequencer");
+ else if (mode=='e')
+ BIF_undo_push("Transform Extend, Sequencer");
+
+ if (marker_moved)
+ allqueue(REDRAWMARKER, 0);
+ else
+ allqueue(REDRAWSEQ, 0);
+}
+
+/* since grab can move markers, we must turn this off before adding a new sequence
+ I am not so happy with this, but the baddness in contained here - Campbell */
+void transform_seq_nomarker(int mode, int context) {
+ SpaceSeq *sseq= curarea->spacedata.first;
+ int flag_back;
+ if (!sseq) return; /* should never happen */
+ flag_back = sseq->flag;
+ sseq->flag &= ~SEQ_MARKER_TRANS;
+
+ transform_seq(mode, context);
+
+ sseq->flag = flag_back;
+}
+
+void seq_cut(int cutframe)
+{
+ Editing *ed;
+ Sequence *seq;
+ TransSeq *ts, *transmain;
+ int tot=0;
+ ListBase newlist;
+
+ ed= G.scene->ed;
+ if(ed==0) return;
+
+ /* test for validity */
+ for(seq= ed->seqbasep->first; seq; seq= seq->next) {
+ if(seq->flag & SELECT) {
+ if(cutframe > seq->startdisp && cutframe < seq->enddisp)
+ if(seq->type==SEQ_META) break;
+ }
+ }
+ if(seq) {
+ error("Cannot Cut Meta Strips");
+ return;
+ }
+
+ /* we build an array of TransSeq, to denote which strips take part in cutting */
+ for(seq= ed->seqbasep->first; seq; seq= seq->next) {
+ if(seq->flag & SELECT) {
+ if(cutframe > seq->startdisp && cutframe < seq->enddisp)
+ tot++;
+ else
+ seq->flag &= ~SELECT; // bad code, but we need it for recurs_dupli_seq... note that this ~SELECT assumption is used in loops below too (ton)
+ }
+ }
+
+ if(tot==0) {
+ error("No Strips to Cut");
+ return;
+ }
+
+ ts=transmain= MEM_callocN(tot*sizeof(TransSeq), "transseq");
+
+ for(seq= ed->seqbasep->first; seq; seq= seq->next) {
+ if(seq->flag & SELECT) {
+
+ ts->start= seq->start;
+ ts->machine= seq->machine;
+ ts->startstill= seq->startstill;
+ ts->endstill= seq->endstill;
+ ts->startdisp= seq->startdisp;
+ ts->enddisp= seq->enddisp;
+ ts->startofs= seq->startofs;
+ ts->endofs= seq->endofs;
+ ts->len= seq->len;
+
+ ts++;
+ }
+ }
+
+ for(seq= ed->seqbasep->first; seq; seq= seq->next) {
+ if(seq->flag & SELECT) {
+
+ /* strips with extended stillframes before */
+ if ((seq->startstill) && (cutframe <seq->start)) {
+ seq->start= cutframe -1;
+ seq->startstill= cutframe -seq->startdisp -1;
+ seq->len= 1;
+ seq->endstill= 0;
+ }
+
+ /* normal strip */
+ else if ((cutframe >=seq->start)&&(cutframe <=(seq->start+seq->len))) {
+ seq->endofs = (seq->start+seq->len) - cutframe;
+ }
+
+ /* strips with extended stillframes after */
+ else if (((seq->start+seq->len) < cutframe) && (seq->endstill)) {
+ seq->endstill -= seq->enddisp - cutframe;
+ }
+
+ calc_sequence(seq);
+ }
+ }
+
+ newlist.first= newlist.last= NULL;
+
+ /* now we duplicate the cut strip and move it into place afterwards */
+ recurs_dupli_seq(ed->seqbasep, &newlist);
+ addlisttolist(ed->seqbasep, &newlist);
+
+ ts= transmain;
+
+ /* go through all the strips and correct them based on their stored values */
+ for(seq= ed->seqbasep->first; seq; seq= seq->next) {
+ if(seq->flag & SELECT) {
+
+ /* strips with extended stillframes before */
+ if ((seq->startstill) && (cutframe == seq->start + 1)) {
+ seq->start = ts->start;
+ seq->startstill= ts->start- cutframe;
+ seq->len = ts->len;
+ seq->endstill = ts->endstill;
+ }
+
+ /* normal strip */
+ else if ((cutframe>=seq->start)&&(cutframe<=(seq->start+seq->len))) {
+ seq->startstill = 0;
+ seq->startofs = cutframe - ts->start;
+ seq->endofs = ts->endofs;
+ seq->endstill = ts->endstill;
+ }
+
+ /* strips with extended stillframes after */
+ else if (((seq->start+seq->len) < cutframe) && (seq->endstill)) {
+ seq->start = cutframe - ts->len +1;
+ seq->startofs = ts->len-1;
+ seq->endstill = ts->enddisp - cutframe -1;
+ seq->startstill = 0;
+ }
+ calc_sequence(seq);
+
+ ts++;
+ }
+ }
+
+ /* as last: */
+ sort_seq();
+ MEM_freeN(transmain);
+
+ allqueue(REDRAWSEQ, 0);
+ BIF_undo_push("Cut Strips, Sequencer");
+}
+
+void seq_separate_images(void)
+{
+ Editing *ed;
+ Sequence *seq, *seq_new, *seq_next;
+ Strip *strip_new;
+ StripElem *se, *se_new;
+ int start_ofs, cfra, frame_end;
+ static int step= 1;
+
+ add_numbut(0, NUM|INT, "Image Duration:", 1, 256, &step, NULL);
+ if (!do_clever_numbuts("Separate Images", 1, REDRAW))
+ return;
+
+ ed= G.scene->ed;
+ if(ed==0) return;
+
+ seq= ed->seqbasep->first;
+
+ while (seq) {
+ if((seq->flag & SELECT) && (seq->type == SEQ_IMAGE) && (seq->len > 1)) {
+ /* remove seq so overlap tests dont conflict,
+ see free_sequence below for the real free'ing */
+ seq_next = seq->next;
+ BLI_remlink(ed->seqbasep, seq);
+ if(seq->ipo) seq->ipo->id.us--;
+
+ start_ofs = cfra = seq_tx_get_final_left(seq);
+ frame_end = seq_tx_get_final_right(seq);
+
+ while (cfra < frame_end) {
+ /* new seq */
+ se = give_stripelem(seq, cfra);
+
+ seq_new= alloc_sequence(((Editing *)G.scene->ed)->seqbasep, start_ofs, seq->machine);
+ seq_new->type= SEQ_IMAGE;
+ seq_new->len = 1;
+ seq_new->endstill = step-1;
+
+ /* new strip */
+ seq_new->strip= strip_new= MEM_callocN(sizeof(Strip)*1, "strip");
+ strip_new->len= 1;
+ strip_new->us= 1;
+ strncpy(strip_new->dir, seq->strip->dir, FILE_MAXDIR-1);
+
+ /* new stripdata */
+ strip_new->stripdata= se_new= MEM_callocN(sizeof(StripElem)*1, "stripelem");
+ strncpy(se_new->name, se->name, FILE_MAXFILE-1);
+ se_new->ok= 1;
+
+ calc_sequence(seq_new);
+ seq_new->flag &= ~SEQ_OVERLAP;
+ if (test_overlap_seq(seq_new)) {
+ shuffle_seq(seq_new);
+ }
+
+ cfra++;
+ start_ofs += step;
+ }
+
+ free_sequence(seq);
+ seq = seq->next;
+ } else {
+ seq = seq->next;
+ }
+ }
+
+ /* as last: */
+ sort_seq();
+ BIF_undo_push("Separate Image Strips, Sequencer");
+ allqueue(REDRAWSEQ, 0);
+}
+
+/* run recursivly to select linked */
+static int select_more_less_seq__internal(int sel, int linked) {
+ Editing *ed;
+ Sequence *seq, *neighbor;
+ int change=0;
+ int isel;
+
+ ed= G.scene->ed;
+ if(ed==0) return 0;
+
+ if (sel) {
+ sel = SELECT;
+ isel = 0;
+ } else {
+ sel = 0;
+ isel = SELECT;
+ }
+
+ if (!linked) {
+ /* if not linked we only want to touch each seq once, newseq */
+ for(seq= ed->seqbasep->first; seq; seq= seq->next) {
+ seq->tmp = NULL;
+ }
+ }
+
+ for(seq= ed->seqbasep->first; seq; seq= seq->next) {
+ if((int)(seq->flag & SELECT) == sel) {
+ if ((linked==0 && seq->tmp)==0) {
+ /* only get unselected nabours */
+ neighbor = find_neighboring_sequence(seq, 1, isel);
+ if (neighbor) {
+ if (sel) {neighbor->flag |= SELECT; recurs_sel_seq(neighbor);}
+ else neighbor->flag &= ~SELECT;
+ if (linked==0) neighbor->tmp = (Sequence *)1;
+ change = 1;
+ }
+ neighbor = find_neighboring_sequence(seq, 2, isel);
+ if (neighbor) {
+ if (sel) {neighbor->flag |= SELECT; recurs_sel_seq(neighbor);}
+ else neighbor->flag &= ~SELECT;
+ if (linked==0) neighbor->tmp = (void *)1;
+ change = 1;
+ }
+ }
+ }
+ }
+
+ return change;
+}
+
+void select_less_seq(void)
+{
+ if (select_more_less_seq__internal(0, 0)) {
+ BIF_undo_push("Select Less, Sequencer");
+ allqueue(REDRAWSEQ, 0);
+ }
+}
+
+void select_more_seq(void)
+{
+ if (select_more_less_seq__internal(1, 0)) {
+ BIF_undo_push("Select More, Sequencer");
+ allqueue(REDRAWSEQ, 0);
+ }
+}
+
+/* TODO not all modes supported - if you feel like being picky, add them! ;) */
+void select_linked_seq(int mode) {
+ Editing *ed;
+ Sequence *seq, *mouse_seq;
+ int selected, hand;
+
+ ed= G.scene->ed;
+ if(ed==0) return;
+
+ /* replace current selection */
+ if (mode==0 || mode==2) {
+ /* this works like UV, not mesh */
+ if (mode==0) {
+ mouse_seq= find_nearest_seq(&hand);
+ if (!mouse_seq)
+ return; /* user error as with mesh?? */
+
+ for(seq= ed->seqbasep->first; seq; seq= seq->next) {
+ seq->flag &= ~SELECT;
+ }
+ mouse_seq->flag |= SELECT;
+ recurs_sel_seq(mouse_seq);
+ }
+
+ selected = 1;
+ while (selected) {
+ selected = select_more_less_seq__internal(1, 1);
+ }
+ BIF_undo_push("Select Linked, Sequencer");
+ allqueue(REDRAWSEQ, 0);
+ }
+ /* TODO - more modes... */
+}
+
+void seq_snap_menu(void)
+{
+ short event;
+
+ event= pupmenu("Snap %t|To Current Frame%x1");
+ if(event < 1) return;
+
+ seq_snap(event);
+}
+
+void seq_snap(short event)
+{
+ Editing *ed;
+ Sequence *seq;
+
+ ed= G.scene->ed;
+ if(ed==0) return;
+
+ /* problem: contents of meta's are all shifted to the same position... */
+
+ /* also check metas */
+ WHILE_SEQ(ed->seqbasep) {
+ if(seq->flag & SELECT) {
+ if(sequence_is_free_transformable(seq)) seq->start= CFRA-seq->startofs+seq->startstill;
+ calc_sequence(seq);
+ }
+ }
+ END_SEQ
+
+
+ /* test for effects and overlap */
+ WHILE_SEQ(ed->seqbasep) {
+ if(seq->flag & SELECT) {
+ seq->flag &= ~SEQ_OVERLAP;
+ if( test_overlap_seq(seq) ) {
+ shuffle_seq(seq);
+ }
+ }
+ else if(seq->type & SEQ_EFFECT) {
+ if(seq->seq1 && (seq->seq1->flag & SELECT))
+ calc_sequence(seq);
+ else if(seq->seq2 && (seq->seq2->flag & SELECT))
+ calc_sequence(seq);
+ else if(seq->seq3 && (seq->seq3->flag & SELECT))
+ calc_sequence(seq);
+ }
+ }
+ END_SEQ;
+
+ /* as last: */
+ sort_seq();
+
+ BIF_undo_push("Snap Strips, Sequencer");
+ allqueue(REDRAWSEQ, 0);
+}
+
+void borderselect_seq(void)
+{
+ Sequence *seq;
+ Editing *ed;
+ rcti rect;
+ rctf rectf, rq;
+ int val;
+ short mval[2];
+
+ ed= G.scene->ed;
+ if(ed==0) return;
+
+ val= get_border(&rect, 3);
+
+ if(val) {
+ mval[0]= rect.xmin;
+ mval[1]= rect.ymin;
+ areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
+ mval[0]= rect.xmax;
+ mval[1]= rect.ymax;
+ areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
+
+ seq= ed->seqbasep->first;
+ while(seq) {
+
+ if(seq->startstill) rq.xmin= seq->start;
+ else rq.xmin= seq->startdisp;
+ rq.ymin= seq->machine+0.2;
+ if(seq->endstill) rq.xmax= seq->start+seq->len;
+ else rq.xmax= seq->enddisp;
+ rq.ymax= seq->machine+0.8;
+
+ if(BLI_isect_rctf(&rq, &rectf, 0)) {
+ if(val==LEFTMOUSE) {
+ seq->flag |= SELECT;
+ }
+ else {
+ seq->flag &= ~SELECT;
+ }
+ recurs_sel_seq(seq);
+ }
+
+ seq= seq->next;
+ }
+
+ BIF_undo_push("Border Select, Sequencer");
+ addqueue(curarea->win, REDRAW, 1);
+ }
+}
diff --git a/source/blender/src/editsima.c b/source/blender/src/editsima.c
new file mode 100644
index 00000000000..18191c970df
--- /dev/null
+++ b/source/blender/src/editsima.c
@@ -0,0 +1,2343 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef WIN32
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_editVert.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "DNA_image_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h" // only for uvedit_selectionCB() (struct Object)
+#include "DNA_packedFile_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_colortools.h"
+#include "BKE_depsgraph.h"
+#include "BKE_displist.h"
+#include "BKE_image.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_mesh.h"
+#include "BKE_node.h"
+#include "BKE_object.h"
+#include "BKE_packedFile.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+#include "BIF_imasel.h"
+#include "BIF_interface.h"
+#include "BIF_drawimage.h"
+#include "BIF_editview.h"
+#include "BIF_editsima.h"
+#include "BIF_mywindow.h"
+#include "BIF_previewrender.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_toolbox.h"
+#include "BIF_transform.h"
+#include "BIF_writeimage.h"
+#include "BIF_editmesh.h"
+
+#include "BSE_drawipo.h"
+#include "BSE_edit.h"
+#include "BSE_filesel.h"
+#include "BSE_trans_types.h"
+
+#include "BDR_editobject.h"
+#include "BDR_unwrapper.h"
+
+#include "BMF_Api.h"
+
+#include "RE_pipeline.h"
+
+#include "blendef.h"
+#include "multires.h"
+#include "mydevice.h"
+#include "editmesh.h"
+
+/* local prototypes */
+void sel_uvco_inside_radius(short , EditFace *efa, MTFace *, int , float *, float *, short);
+void uvedit_selectionCB(short , Object *, short *, float ); /* used in edit.c*/
+
+void object_uvs_changed(Object *ob)
+{
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWIMAGE, 0);
+}
+
+void object_tface_flags_changed(Object *ob, int updateButtons)
+{
+ if (updateButtons) allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWIMAGE, 0);
+}
+
+int is_uv_tface_editing_allowed_silent(void)
+{
+ if(!EM_texFaceCheck()) return 0;
+ if(G.sima->mode!=SI_TEXTURE) return 0;
+ if(multires_level1_test()) return 0;
+ return 1;
+}
+
+int is_uv_tface_editing_allowed(void)
+{
+ if(!G.obedit) error("Enter Edit Mode to perform this action");
+
+ return is_uv_tface_editing_allowed_silent();
+}
+
+void get_connected_limit_tface_uv(float *limit)
+{
+ ImBuf *ibuf= BKE_image_get_ibuf(G.sima->image, &G.sima->iuser);
+ if(ibuf && ibuf->x > 0 && ibuf->y > 0) {
+ limit[0]= 0.05/(float)ibuf->x;
+ limit[1]= 0.05/(float)ibuf->y;
+ }
+ else
+ limit[0]= limit[1]= 0.05/256.0;
+}
+
+void be_square_tface_uv(EditMesh *em)
+{
+ EditFace *efa;
+ MTFace *tface;
+ /* if 1 vertex selected: doit (with the selected vertex) */
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ if (efa->v4) {
+ tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ if (SIMA_FACEDRAW_CHECK(efa, tface)) {
+ if (SIMA_UVSEL_CHECK(efa, tface, 0)) {
+ if( tface->uv[1][0] == tface->uv[2][0] ) {
+ tface->uv[1][1]= tface->uv[0][1];
+ tface->uv[3][0]= tface->uv[0][0];
+ }
+ else {
+ tface->uv[1][0]= tface->uv[0][0];
+ tface->uv[3][1]= tface->uv[0][1];
+ }
+
+ }
+ if (SIMA_UVSEL_CHECK(efa, tface, 1)) {
+ if( tface->uv[2][1] == tface->uv[3][1] ) {
+ tface->uv[2][0]= tface->uv[1][0];
+ tface->uv[0][1]= tface->uv[1][1];
+ }
+ else {
+ tface->uv[2][1]= tface->uv[1][1];
+ tface->uv[0][0]= tface->uv[1][0];
+ }
+
+ }
+ if (SIMA_UVSEL_CHECK(efa, tface, 2)) {
+ if( tface->uv[3][0] == tface->uv[0][0] ) {
+ tface->uv[3][1]= tface->uv[2][1];
+ tface->uv[1][0]= tface->uv[2][0];
+ }
+ else {
+ tface->uv[3][0]= tface->uv[2][0];
+ tface->uv[1][1]= tface->uv[2][1];
+ }
+ }
+ if (SIMA_UVSEL_CHECK(efa, tface, 3)) {
+ if( tface->uv[0][1] == tface->uv[1][1] ) {
+ tface->uv[0][0]= tface->uv[3][0];
+ tface->uv[2][1]= tface->uv[3][1];
+ }
+ else {
+ tface->uv[0][1]= tface->uv[3][1];
+ tface->uv[2][0]= tface->uv[3][0];
+ }
+
+ }
+ }
+ }
+ }
+}
+
+void transform_aspect_ratio_tface_uv(float *aspx, float *aspy)
+{
+ int w, h;
+ float xuser_asp, yuser_asp;
+
+ aspect_sima(G.sima, &xuser_asp, &yuser_asp);
+
+ transform_width_height_tface_uv(&w, &h);
+ *aspx= (float)w/256.0f * xuser_asp;
+ *aspy= (float)h/256.0f * yuser_asp;
+}
+
+void transform_width_height_tface_uv(int *width, int *height)
+{
+ ImBuf *ibuf= BKE_image_get_ibuf(G.sima->image, &G.sima->iuser);
+
+ if(ibuf) {
+ *width= ibuf->x;
+ *height= ibuf->y;
+ }
+ else {
+ *width= 256;
+ *height= 256;
+ }
+}
+
+void mirror_tface_uv(char mirroraxis)
+{
+ if (mirroraxis == 'x')
+ Mirror(1); /* global x */
+ else if (mirroraxis == 'y')
+ Mirror(2); /* global y */
+}
+
+void mirrormenu_tface_uv(void)
+{
+ short mode= 0;
+
+ if( is_uv_tface_editing_allowed()==0 ) return;
+
+ mode= pupmenu("Mirror%t|X Axis%x1|Y Axis%x2|");
+
+ if(mode==-1) return;
+
+ if(mode==1) mirror_tface_uv('x');
+ else if(mode==2) mirror_tface_uv('y');
+
+ BIF_undo_push("Mirror UV");
+}
+
+void weld_align_tface_uv(char tool)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+ MTFace *tface;
+ float cent[2];
+
+ if( is_uv_tface_editing_allowed()==0 ) return;
+ cent_tface_uv(cent, 0);
+
+ if(tool == 'x' || tool == 'w') {
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ if (SIMA_FACEDRAW_CHECK(efa, tface)) {
+ if (SIMA_UVSEL_CHECK(efa, tface, 0))
+ tface->uv[0][0]= cent[0];
+ if (SIMA_UVSEL_CHECK(efa, tface, 1))
+ tface->uv[1][0]= cent[0];
+ if (SIMA_UVSEL_CHECK(efa, tface, 2))
+ tface->uv[2][0]= cent[0];
+ if (efa->v4 && SIMA_UVSEL_CHECK(efa, tface, 3))
+ tface->uv[3][0]= cent[0];
+ }
+ }
+ }
+
+ if(tool == 'y' || tool == 'w') {
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ if (SIMA_FACEDRAW_CHECK(efa, tface)) {
+ if (SIMA_UVSEL_CHECK(efa, tface, 0))
+ tface->uv[0][1]= cent[1];
+ if (SIMA_UVSEL_CHECK(efa, tface, 1))
+ tface->uv[1][1]= cent[1];
+ if (SIMA_UVSEL_CHECK(efa, tface, 2))
+ tface->uv[2][1]= cent[1];
+ if (efa->v4 && SIMA_UVSEL_CHECK(efa, tface, 3))
+ tface->uv[3][1]= cent[1];
+ }
+ }
+ }
+
+ object_uvs_changed(OBACT);
+}
+
+// just for averaging UV's
+typedef struct UVVertAverage {
+ float uv[2];
+ int count;
+} UVVertAverage;
+
+void stitch_vert_uv_tface(void)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+ EditVert *eve;
+ MTFace *tface;
+ int count;
+ UVVertAverage *uv_average, *uvav;
+
+ if( is_uv_tface_editing_allowed()==0 ) return;
+
+ // index and count verts
+ for (count=0, eve=em->verts.first; eve; count++, eve= eve->next) {
+ eve->tmp.l = count;
+ }
+
+ uv_average = MEM_callocN(sizeof(UVVertAverage) * count, "Stitch");
+
+ // gather uv averages per vert
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ if (SIMA_FACEDRAW_CHECK(efa, tface)) {
+ if (SIMA_UVSEL_CHECK(efa, tface, 0)) {
+ uvav = uv_average + efa->v1->tmp.l;
+ uvav->count++;
+ uvav->uv[0] += tface->uv[0][0];
+ uvav->uv[1] += tface->uv[0][1];
+ }
+ if (SIMA_UVSEL_CHECK(efa, tface, 1)) {
+ uvav = uv_average + efa->v2->tmp.l;
+ uvav->count++;
+ uvav->uv[0] += tface->uv[1][0];
+ uvav->uv[1] += tface->uv[1][1];
+ }
+ if (SIMA_UVSEL_CHECK(efa, tface, 2)) {
+ uvav = uv_average + efa->v3->tmp.l;
+ uvav->count++;
+ uvav->uv[0] += tface->uv[2][0];
+ uvav->uv[1] += tface->uv[2][1];
+ }
+ if (efa->v4 && SIMA_UVSEL_CHECK(efa, tface, 3)) {
+ uvav = uv_average + efa->v4->tmp.l;
+ uvav->count++;
+ uvav->uv[0] += tface->uv[3][0];
+ uvav->uv[1] += tface->uv[3][1];
+ }
+ }
+ }
+
+ // apply uv welding
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ if (SIMA_FACEDRAW_CHECK(efa, tface)) {
+ if (SIMA_UVSEL_CHECK(efa, tface, 0)) {
+ uvav = uv_average + efa->v1->tmp.l;
+ tface->uv[0][0] = uvav->uv[0]/uvav->count;
+ tface->uv[0][1] = uvav->uv[1]/uvav->count;
+ }
+ if (SIMA_UVSEL_CHECK(efa, tface, 1)) {
+ uvav = uv_average + efa->v2->tmp.l;
+ tface->uv[1][0] = uvav->uv[0]/uvav->count;
+ tface->uv[1][1] = uvav->uv[1]/uvav->count;
+ }
+ if (SIMA_UVSEL_CHECK(efa, tface, 2)) {
+ uvav = uv_average + efa->v3->tmp.l;
+ tface->uv[2][0] = uvav->uv[0]/uvav->count;
+ tface->uv[2][1] = uvav->uv[1]/uvav->count;
+ }
+ if (efa->v4 && SIMA_UVSEL_CHECK(efa, tface, 3)) {
+ uvav = uv_average + efa->v4->tmp.l;
+ tface->uv[3][0] = uvav->uv[0]/uvav->count;
+ tface->uv[3][1] = uvav->uv[1]/uvav->count;
+ }
+ }
+ }
+ MEM_freeN(uv_average);
+ object_uvs_changed(OBACT);
+}
+
+void weld_align_menu_tface_uv(void)
+{
+ short mode= 0;
+
+ if( is_uv_tface_editing_allowed()==0 ) return;
+
+ mode= pupmenu("Weld/Align%t|Weld%x1|Align X%x2|Align Y%x3");
+
+ if(mode==-1) return;
+ if(mode==1) weld_align_tface_uv('w');
+ else if(mode==2) weld_align_tface_uv('x');
+ else if(mode==3) weld_align_tface_uv('y');
+
+ if(mode==1) BIF_undo_push("Weld UV");
+ else if(mode==2 || mode==3) BIF_undo_push("Align UV");
+}
+
+void select_invert_tface_uv(void)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+ MTFace *tface;
+
+ if( is_uv_tface_editing_allowed()==0 ) return;
+
+ if (G.sima->flag & SI_SYNC_UVSEL) {
+ /* Warning, this is not that good (calling editmode stuff from UV),
+ TODO look into changing it */
+ selectswap_mesh();
+ return;
+ } else {
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ tface = CustomData_em_get(&G.editMesh->fdata, efa->data, CD_MTFACE);
+ if (SIMA_FACEDRAW_CHECK(efa, tface)) {
+ tface->flag ^= TF_SEL1;
+ tface->flag ^= TF_SEL2;
+ tface->flag ^= TF_SEL3;
+ if(efa->v4) tface->flag ^= TF_SEL4;
+ }
+ }
+ }
+ BIF_undo_push("Select Inverse UV");
+
+ allqueue(REDRAWIMAGE, 0);
+}
+
+void select_swap_tface_uv(void)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+ MTFace *tface;
+ int sel=0;
+
+ if( is_uv_tface_editing_allowed()==0 ) return;
+
+ if (G.sima->flag & SI_SYNC_UVSEL) {
+ deselectall_mesh();
+ return;
+ } else {
+
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ tface = CustomData_em_get(&G.editMesh->fdata, efa->data, CD_MTFACE);
+ if (SIMA_FACEDRAW_CHECK(efa, tface)) {
+ if(tface->flag & (TF_SEL1+TF_SEL2+TF_SEL3+TF_SEL4)) {
+ sel= 1;
+ break;
+ }
+ }
+ }
+
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ tface = CustomData_em_get(&G.editMesh->fdata, efa->data, CD_MTFACE);
+ if (SIMA_FACEDRAW_CHECK(efa, tface)) {
+ if(efa->v4) {
+ if(sel) tface->flag &= ~(TF_SEL1+TF_SEL2+TF_SEL3+TF_SEL4);
+ else tface->flag |= (TF_SEL1+TF_SEL2+TF_SEL3+TF_SEL4);
+ }
+ else {
+ if(sel) tface->flag &= ~(TF_SEL1+TF_SEL2+TF_SEL3+TF_SEL4);
+ else tface->flag |= (TF_SEL1+TF_SEL2+TF_SEL3);
+ }
+ }
+ }
+ }
+ BIF_undo_push("Select swap");
+
+ allqueue(REDRAWIMAGE, 0);
+}
+
+static int msel_hit(float *limit, unsigned int *hitarray, unsigned int vertexid, float **uv, float *uv2, int sticky)
+{
+ int i;
+ for(i=0; i< 4; i++) {
+ if(hitarray[i] == vertexid) {
+ if(sticky == 2) {
+ if(fabs(uv[i][0]-uv2[0]) < limit[0] &&
+ fabs(uv[i][1]-uv2[1]) < limit[1])
+ return 1;
+ }
+ else return 1;
+ }
+ }
+ return 0;
+}
+
+static void find_nearest_tface(MTFace **nearesttf, EditFace **nearestefa)
+{
+ EditMesh *em= G.editMesh;
+ MTFace *tf;
+ EditFace *efa;
+ int i, nverts, mindist, dist, fcenter[2], uval[2];
+ short mval[2];
+
+ getmouseco_areawin(mval);
+
+ mindist= 0x7FFFFFF;
+ *nearesttf= NULL;
+ *nearestefa= NULL;
+
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ if (SIMA_FACEDRAW_CHECK(efa, tf)) {
+ fcenter[0]= fcenter[1]= 0;
+ nverts= efa->v4? 4: 3;
+ for(i=0; i<nverts; i++) {
+ uvco_to_areaco_noclip(tf->uv[i], uval);
+ fcenter[0] += uval[0];
+ fcenter[1] += uval[1];
+ }
+
+ fcenter[0] /= nverts;
+ fcenter[1] /= nverts;
+
+ dist= abs(mval[0]- fcenter[0])+ abs(mval[1]- fcenter[1]);
+ if (dist < mindist) {
+ *nearesttf= tf;
+ *nearestefa= efa;
+ mindist= dist;
+ }
+ }
+ }
+}
+
+static int nearest_uv_between(MTFace *tf, int nverts, int id, short *mval, int *uval)
+{
+ float m[3], v1[3], v2[3], c1, c2;
+ int id1, id2;
+
+ id1= (id+nverts-1)%nverts;
+ id2= (id+nverts+1)%nverts;
+
+ m[0] = (float)(mval[0]-uval[0]);
+ m[1] = (float)(mval[1]-uval[1]);
+ Vec2Subf(v1, tf->uv[id1], tf->uv[id]);
+ Vec2Subf(v2, tf->uv[id2], tf->uv[id]);
+
+ /* m and v2 on same side of v-v1? */
+ c1= v1[0]*m[1] - v1[1]*m[0];
+ c2= v1[0]*v2[1] - v1[1]*v2[0];
+
+ if (c1*c2 < 0.0f)
+ return 0;
+
+ /* m and v1 on same side of v-v2? */
+ c1= v2[0]*m[1] - v2[1]*m[0];
+ c2= v2[0]*v1[1] - v2[1]*v1[0];
+
+ return (c1*c2 >= 0.0f);
+}
+
+void find_nearest_uv(MTFace **nearesttf, EditFace **nearestefa, unsigned int *nearestv, int *nearestuv)
+{
+ EditMesh *em= G.editMesh;
+ EditFace *efa;
+ MTFace *tf;
+ int i, nverts, mindist, dist, uval[2];
+ short mval[2];
+
+ getmouseco_areawin(mval);
+
+ mindist= 0x7FFFFFF;
+ if (nearesttf) *nearesttf= NULL;
+ if (nearestefa) *nearestefa= NULL;
+
+ if (nearestv) {
+ EditVert *ev;
+ for (i=0, ev=em->verts.first; ev; ev = ev->next, i++)
+ ev->tmp.l = i;
+ }
+
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ if (SIMA_FACEDRAW_CHECK(efa, tf)) {
+ nverts= efa->v4? 4: 3;
+ for(i=0; i<nverts; i++) {
+ uvco_to_areaco_noclip(tf->uv[i], uval);
+ dist= abs(mval[0]-uval[0]) + abs(mval[1]-uval[1]);
+
+ if (SIMA_UVSEL_CHECK(efa, tf, i))
+ dist += 5;
+
+ if(dist<=mindist) {
+ if(dist==mindist)
+ if (!nearest_uv_between(tf, nverts, i, mval, uval))
+ continue;
+
+ mindist= dist;
+ *nearestuv= i;
+
+ if (nearesttf) *nearesttf= tf;
+ if (nearestefa) *nearestefa= efa;
+ if (nearestv) {
+ if (i==0) *nearestv= efa->v1->tmp.l;
+ else if (i==1) *nearestv= efa->v2->tmp.l;
+ else if (i==2) *nearestv= efa->v3->tmp.l;
+ else *nearestv= efa->v4->tmp.l;
+ }
+ }
+ }
+ }
+ }
+}
+
+void mouse_select_sima(void)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+ MTFace *tf, *nearesttf;
+ EditFace *nearestefa=NULL;
+ int a, selectsticky, actface, nearestuv, i;
+ char sticky= 0;
+ short flush = 0; /* 0 == dont flush, 1 == sel, -1 == desel; only use when selection sync is enabled */
+ unsigned int hitv[4], nearestv;
+ float *hituv[4], limit[2];
+
+ if( is_uv_tface_editing_allowed()==0 ) return;
+
+ get_connected_limit_tface_uv(limit);
+
+ if (G.sima->flag & SI_SYNC_UVSEL) {
+ /* copy from mesh */
+ if (G.scene->selectmode == SCE_SELECT_FACE) {
+ actface= 1;
+ sticky= 0;
+ } else {
+ actface= (G.qual & LR_ALTKEY || G.sima->flag & SI_SELACTFACE);
+ sticky= 2;
+ }
+ } else {
+ /* normal operation */
+ actface= (G.qual & LR_ALTKEY || G.sima->flag & SI_SELACTFACE);
+
+ switch(G.sima->sticky) {
+ case SI_STICKY_LOC:
+ sticky=2;
+ break;
+ case SI_STICKY_DISABLE:
+ sticky=0;
+ break;
+ case SI_STICKY_VERTEX:
+ if(G.qual & LR_CTRLKEY) {
+ sticky=0;
+ } else {
+ sticky=1;
+ }
+ break;
+ }
+ }
+
+ if(actface) {
+ find_nearest_tface(&nearesttf, &nearestefa);
+ if(nearesttf==NULL)
+ return;
+
+ EM_set_actFace(nearestefa);
+
+ for (i=0; i<4; i++)
+ hituv[i]= nearesttf->uv[i];
+
+ hitv[0]= nearestefa->v1->tmp.l;
+ hitv[1]= nearestefa->v2->tmp.l;
+ hitv[2]= nearestefa->v3->tmp.l;
+
+ if (nearestefa->v4) hitv[3]= nearestefa->v4->tmp.l;
+ else hitv[3]= 0xFFFFFFFF;
+ }
+ else {
+ find_nearest_uv(&nearesttf, &nearestefa, &nearestv, &nearestuv);
+ if(nearesttf==NULL)
+ return;
+
+ if(sticky) {
+ for(i=0; i<4; i++)
+ hitv[i]= 0xFFFFFFFF;
+ hitv[nearestuv]= nearestv;
+ hituv[nearestuv]= nearesttf->uv[nearestuv];
+ }
+ }
+
+ if(G.qual & LR_SHIFTKEY) {
+ /* (de)select face */
+ if(actface) {
+ if(SIMA_FACESEL_CHECK(nearestefa, nearesttf)) {
+ SIMA_FACESEL_UNSET(nearestefa, nearesttf);
+ selectsticky= 0;
+ }
+ else {
+ SIMA_FACESEL_SET(nearestefa, nearesttf);
+ selectsticky= 1;
+ }
+ flush = -1;
+ }
+ /* (de)select uv node */
+ else {
+ if (SIMA_UVSEL_CHECK(nearestefa, nearesttf, nearestuv)) {
+ SIMA_UVSEL_UNSET(nearestefa, nearesttf, nearestuv);
+ selectsticky= 0;
+ }
+ else {
+ SIMA_UVSEL_SET(nearestefa, nearesttf, nearestuv);
+ selectsticky= 1;
+ }
+ flush = 1;
+ }
+
+ /* (de)select sticky uv nodes */
+ if(sticky || actface) {
+ EditVert *ev;
+
+ for (a=0, ev=em->verts.first; ev; ev = ev->next, a++)
+ ev->tmp.l = a;
+
+ /* deselect */
+ if(selectsticky==0) {
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ if (SIMA_FACEDRAW_CHECK(efa, tf)) {
+ /*if(nearesttf && tf!=nearesttf) tf->flag &=~ TF_ACTIVE;*/ /* TODO - deal with editmesh active face */
+ if (!sticky) continue;
+
+ if(msel_hit(limit, hitv, efa->v1->tmp.l, hituv, tf->uv[0], sticky))
+ SIMA_UVSEL_UNSET(efa, tf, 0);
+ if(msel_hit(limit, hitv, efa->v2->tmp.l, hituv, tf->uv[1], sticky))
+ SIMA_UVSEL_UNSET(efa, tf, 1);
+ if(msel_hit(limit, hitv, efa->v3->tmp.l, hituv, tf->uv[2], sticky))
+ SIMA_UVSEL_UNSET(efa, tf, 2);
+ if (efa->v4)
+ if(msel_hit(limit, hitv, efa->v4->tmp.l, hituv, tf->uv[3], sticky))
+ SIMA_UVSEL_UNSET(efa, tf, 3);
+ }
+ }
+ flush = -1;
+ }
+ /* select */
+ else {
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ if (SIMA_FACEDRAW_CHECK(efa, tf)) {
+ if (!sticky) continue;
+ if(msel_hit(limit, hitv, efa->v1->tmp.l, hituv, tf->uv[0], sticky))
+ SIMA_UVSEL_SET(efa, tf, 0);
+ if(msel_hit(limit, hitv, efa->v2->tmp.l, hituv, tf->uv[1], sticky))
+ SIMA_UVSEL_SET(efa, tf, 1);
+ if(msel_hit(limit, hitv, efa->v3->tmp.l, hituv, tf->uv[2], sticky))
+ SIMA_UVSEL_SET(efa, tf, 2);
+ if (efa->v4)
+ if(msel_hit(limit, hitv, efa->v4->tmp.l, hituv, tf->uv[3], sticky))
+ SIMA_UVSEL_SET(efa, tf, 3);
+ }
+ }
+ EM_set_actFace(nearestefa);
+ flush = 1;
+ }
+ }
+ }
+ else {
+ /* select face and deselect other faces */
+ if(actface) {
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ SIMA_FACESEL_UNSET(efa, tf);
+ }
+ if(nearesttf) {
+ SIMA_FACESEL_SET(nearestefa, nearesttf);
+ EM_set_actFace(nearestefa);
+ }
+
+ }
+
+ /* deselect uvs, and select sticky uvs */
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ if (SIMA_FACEDRAW_CHECK(efa, tf)) {
+ if(!actface) SIMA_FACESEL_UNSET(efa, tf);
+ if(!sticky) continue;
+
+ if(msel_hit(limit, hitv, efa->v1->tmp.l, hituv, tf->uv[0], sticky))
+ SIMA_UVSEL_SET(efa, tf, 0);
+ if(msel_hit(limit, hitv, efa->v2->tmp.l, hituv, tf->uv[1], sticky))
+ SIMA_UVSEL_SET(efa, tf, 1);
+ if(msel_hit(limit, hitv, efa->v3->tmp.l, hituv, tf->uv[2], sticky))
+ SIMA_UVSEL_SET(efa, tf, 2);
+ if(efa->v4)
+ if(msel_hit(limit, hitv, efa->v4->tmp.l, hituv, tf->uv[3], sticky))
+ SIMA_UVSEL_SET(efa, tf, 3);
+ flush= 1;
+ }
+ }
+
+ if(!actface) {
+ SIMA_UVSEL_SET(nearestefa, nearesttf, nearestuv);
+ flush= 1;
+ }
+ }
+
+ force_draw(1);
+
+ if (G.sima->flag & SI_SYNC_UVSEL) {
+ /* flush for mesh selection */
+ if (G.scene->selectmode != SCE_SELECT_FACE) {
+ if (flush==1) EM_select_flush();
+ else if (flush==-1) EM_deselect_flush();
+ }
+ allqueue(REDRAWVIEW3D, 0); /* mesh selection has changed */
+ }
+
+ BIF_undo_push("Select UV");
+ rightmouse_transform();
+}
+
+void borderselect_sima(short whichuvs)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+ MTFace *tface;
+ rcti rect;
+ rctf rectf;
+ int val, ok = 1;
+ short mval[2], select;
+
+ if( is_uv_tface_editing_allowed()==0) return;
+
+ val= get_border(&rect, 3);
+ select = (val==LEFTMOUSE) ? 1 : 0;
+
+ if(val) {
+ mval[0]= rect.xmin;
+ mval[1]= rect.ymin;
+ areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
+ mval[0]= rect.xmax;
+ mval[1]= rect.ymax;
+ areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
+
+ if (draw_uvs_face_check() && whichuvs != UV_SELECT_PINNED) {
+ float cent[2];
+ ok = 0;
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ /* assume not touched */
+ efa->tmp.l = 0;
+ tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ if (SIMA_FACEDRAW_CHECK(efa, tface)) {
+ tface_center(tface, cent, (void *)efa->v4);
+ if(BLI_in_rctf(&rectf, cent[0], cent[1])) {
+ efa->tmp.l = ok = 1;
+ }
+ }
+ }
+ /* (de)selects all tagged faces and deals with sticky modes */
+ if (ok)
+ uvface_setsel__internal(select);
+ } else {
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ if (SIMA_FACEDRAW_CHECK(efa, tface)) {
+ if (whichuvs == UV_SELECT_ALL || (G.sima->flag & SI_SYNC_UVSEL) ) {
+ /* SI_SYNC_UVSEL - cant do pinned selection */
+ if(BLI_in_rctf(&rectf, tface->uv[0][0], tface->uv[0][1])) {
+ if(select) SIMA_UVSEL_SET(efa, tface, 0);
+ else SIMA_UVSEL_UNSET(efa, tface, 0);
+ }
+ if(BLI_in_rctf(&rectf, tface->uv[1][0], tface->uv[1][1])) {
+ if(select) SIMA_UVSEL_SET(efa, tface, 1);
+ else SIMA_UVSEL_UNSET(efa, tface, 1);
+ }
+ if(BLI_in_rctf(&rectf, tface->uv[2][0], tface->uv[2][1])) {
+ if(select) SIMA_UVSEL_SET(efa, tface, 2);
+ else SIMA_UVSEL_UNSET(efa, tface, 2);
+ }
+ if(efa->v4 && BLI_in_rctf(&rectf, tface->uv[3][0], tface->uv[3][1])) {
+ if(select) SIMA_UVSEL_SET(efa, tface, 3);
+ else SIMA_UVSEL_UNSET(efa, tface, 3);
+ }
+ } else if (whichuvs == UV_SELECT_PINNED) {
+ if ((tface->unwrap & TF_PIN1) &&
+ BLI_in_rctf(&rectf, tface->uv[0][0], tface->uv[0][1])) {
+
+ if(select) SIMA_UVSEL_SET(efa, tface, 0);
+ else SIMA_UVSEL_UNSET(efa, tface, 0);
+ }
+ if ((tface->unwrap & TF_PIN2) &&
+ BLI_in_rctf(&rectf, tface->uv[1][0], tface->uv[1][1])) {
+
+ if(select) SIMA_UVSEL_SET(efa, tface, 1);
+ else SIMA_UVSEL_UNSET(efa, tface, 1);
+ }
+ if ((tface->unwrap & TF_PIN3) &&
+ BLI_in_rctf(&rectf, tface->uv[2][0], tface->uv[2][1])) {
+
+ if(select) SIMA_UVSEL_SET(efa, tface, 2);
+ else SIMA_UVSEL_UNSET(efa, tface, 2);
+ }
+ if ((efa->v4) && (tface->unwrap & TF_PIN4) && BLI_in_rctf(&rectf, tface->uv[3][0], tface->uv[3][1])) {
+ if(select) SIMA_UVSEL_SET(efa, tface, 3);
+ else SIMA_UVSEL_UNSET(efa, tface, 3);
+ }
+ }
+ }
+ }
+ }
+ if (ok) {
+ /* make sure newly selected vert selection is updated*/
+ if (G.sima->flag & SI_SYNC_UVSEL) {
+ if (G.scene->selectmode != SCE_SELECT_FACE) {
+ if (select) EM_select_flush();
+ else EM_deselect_flush();
+ }
+ }
+ allqueue(REDRAWVIEW3D, 0); /* mesh selection has changed */
+
+ BIF_undo_push("Border select UV");
+ scrarea_queue_winredraw(curarea);
+ }
+ }
+}
+
+int snap_uv_sel_to_curs(void)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+ MTFace *tface;
+ short change = 0;
+
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ if (SIMA_FACEDRAW_CHECK(efa, tface)) {
+ if (SIMA_UVSEL_CHECK(efa, tface, 0)) VECCOPY2D(tface->uv[0], G.v2d->cursor);
+ if (SIMA_UVSEL_CHECK(efa, tface, 1)) VECCOPY2D(tface->uv[1], G.v2d->cursor);
+ if (SIMA_UVSEL_CHECK(efa, tface, 2)) VECCOPY2D(tface->uv[2], G.v2d->cursor);
+ if (efa->v4)
+ if (SIMA_UVSEL_CHECK(efa, tface, 3)) VECCOPY2D(tface->uv[3], G.v2d->cursor);
+ change = 1;
+ }
+ }
+ return change;
+}
+
+int snap_uv_sel_to_adj_unsel(void)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+ EditVert *eve;
+ MTFace *tface;
+ short change = 0;
+ int count = 0;
+ float *coords;
+ short *usercount, users;
+
+ /* set all verts to -1 : an unused index*/
+ for (eve= em->verts.first; eve; eve= eve->next)
+ eve->tmp.l=-1;
+
+ /* index every vert that has a selected UV using it, but only once so as to
+ * get unique indicies and to count how much to malloc */
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ if (SIMA_FACEDRAW_CHECK(efa, tface)) {
+ if (SIMA_UVSEL_CHECK(efa, tface, 0) && efa->v1->tmp.l==-1) efa->v1->tmp.l= count++;
+ if (SIMA_UVSEL_CHECK(efa, tface, 1) && efa->v2->tmp.l==-1) efa->v2->tmp.l= count++;
+ if (SIMA_UVSEL_CHECK(efa, tface, 2) && efa->v3->tmp.l==-1) efa->v3->tmp.l= count++;
+ if (efa->v4)
+ if (SIMA_UVSEL_CHECK(efa, tface, 3) && efa->v4->tmp.l==-1) efa->v4->tmp.l= count++;
+ change = 1;
+
+ /* optional speedup */
+ efa->tmp.p = tface;
+ } else {
+ efa->tmp.p = NULL;
+ }
+ }
+
+ coords = MEM_callocN(sizeof(float)*count*2, "snap to adjacent coords");
+ usercount = MEM_callocN(sizeof(short)*count, "snap to adjacent counts");
+
+ /* add all UV coords from visible, unselected UV coords as well as counting them to average later */
+ for (efa= em->faces.first; efa; efa= efa->next) {
+// tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+// if (SIMA_FACEDRAW_CHECK(efa, tface)) {
+ if ((tface=(MTFace *)efa->tmp.p)) {
+
+ /* is this an unselected UV we can snap to? */
+ if (efa->v1->tmp.l >= 0 && (!SIMA_UVSEL_CHECK(efa, tface, 0))) {
+ coords[efa->v1->tmp.l*2] += tface->uv[0][0];
+ coords[(efa->v1->tmp.l*2)+1] += tface->uv[0][1];
+ usercount[efa->v1->tmp.l]++;
+ change = 1;
+ }
+ if (efa->v2->tmp.l >= 0 && (!SIMA_UVSEL_CHECK(efa, tface, 1))) {
+ coords[efa->v2->tmp.l*2] += tface->uv[1][0];
+ coords[(efa->v2->tmp.l*2)+1] += tface->uv[1][1];
+ usercount[efa->v2->tmp.l]++;
+ change = 1;
+ }
+ if (efa->v3->tmp.l >= 0 && (!SIMA_UVSEL_CHECK(efa, tface, 2))) {
+ coords[efa->v3->tmp.l*2] += tface->uv[2][0];
+ coords[(efa->v3->tmp.l*2)+1] += tface->uv[2][1];
+ usercount[efa->v3->tmp.l]++;
+ change = 1;
+ }
+
+ if (efa->v4) {
+ if (efa->v4->tmp.l >= 0 && (!SIMA_UVSEL_CHECK(efa, tface, 3))) {
+ coords[efa->v4->tmp.l*2] += tface->uv[3][0];
+ coords[(efa->v4->tmp.l*2)+1] += tface->uv[3][1];
+ usercount[efa->v4->tmp.l]++;
+ change = 1;
+ }
+ }
+ }
+ }
+
+ /* no other verts selected, bail out */
+ if (!change) {
+ MEM_freeN(coords);
+ MEM_freeN(usercount);
+ return change;
+ }
+
+ /* copy the averaged unselected UVs back to the selected UVs */
+ for (efa= em->faces.first; efa; efa= efa->next) {
+// tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+// if (SIMA_FACEDRAW_CHECK(efa, tface)) {
+ if ((tface=(MTFace *)efa->tmp.p)) {
+
+ if ( SIMA_UVSEL_CHECK(efa, tface, 0) &&
+ efa->v1->tmp.l >= 0 &&
+ (users = usercount[efa->v1->tmp.l])
+ ) {
+ tface->uv[0][0] = coords[efa->v1->tmp.l*2] / users;
+ tface->uv[0][1] = coords[(efa->v1->tmp.l*2)+1] / users;
+ }
+
+ if ( SIMA_UVSEL_CHECK(efa, tface, 1) &&
+ efa->v2->tmp.l >= 0 &&
+ (users = usercount[efa->v2->tmp.l])
+ ) {
+ tface->uv[1][0] = coords[efa->v2->tmp.l*2] / users;
+ tface->uv[1][1] = coords[(efa->v2->tmp.l*2)+1] / users;
+ }
+
+ if ( SIMA_UVSEL_CHECK(efa, tface, 2) &&
+ efa->v3->tmp.l >= 0 &&
+ (users = usercount[efa->v3->tmp.l])
+ ) {
+ tface->uv[2][0] = coords[efa->v3->tmp.l*2] / users;
+ tface->uv[2][1] = coords[(efa->v3->tmp.l*2)+1] / users;
+ }
+
+ if (efa->v4) {
+ if ( SIMA_UVSEL_CHECK(efa, tface, 3) &&
+ efa->v4->tmp.l >= 0 &&
+ (users = usercount[efa->v4->tmp.l])
+ ) {
+ tface->uv[3][0] = coords[efa->v4->tmp.l*2] / users;
+ tface->uv[3][1] = coords[(efa->v4->tmp.l*2)+1] / users;
+ }
+ }
+ }
+ }
+
+ MEM_freeN(coords);
+ MEM_freeN(usercount);
+ return change;
+}
+
+void snap_coord_to_pixel(float *uvco, float w, float h)
+{
+ uvco[0] = ((float) ((int)((uvco[0]*w) + 0.5))) / w;
+ uvco[1] = ((float) ((int)((uvco[1]*h) + 0.5))) / h;
+}
+
+int snap_uv_sel_to_pixels(void) /* warning, sanity checks must alredy be done */
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+ MTFace *tface;
+ int wi, hi;
+ float w, h;
+ short change = 0;
+
+ transform_width_height_tface_uv(&wi, &hi);
+ w = (float)wi;
+ h = (float)hi;
+
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ if (SIMA_FACEDRAW_CHECK(efa, tface)) {
+ if (SIMA_UVSEL_CHECK(efa, tface, 0)) snap_coord_to_pixel(tface->uv[0], w, h);
+ if (SIMA_UVSEL_CHECK(efa, tface, 1)) snap_coord_to_pixel(tface->uv[1], w, h);
+ if (SIMA_UVSEL_CHECK(efa, tface, 2)) snap_coord_to_pixel(tface->uv[2], w, h);
+ if (efa->v4)
+ if (SIMA_UVSEL_CHECK(efa, tface, 3)) snap_coord_to_pixel(tface->uv[3], w, h);
+ change = 1;
+ }
+ }
+ return change;
+}
+
+void snap_uv_curs_to_pixels(void)
+{
+ int wi, hi;
+ float w, h;
+
+ transform_width_height_tface_uv(&wi, &hi);
+ w = (float)wi;
+ h = (float)hi;
+ snap_coord_to_pixel(G.v2d->cursor, w, h);
+}
+
+int snap_uv_curs_to_sel(void)
+{
+ if( is_uv_tface_editing_allowed()==0 ) return 0;
+ return cent_tface_uv(G.v2d->cursor, 0);
+}
+
+void snap_menu_sima(void)
+{
+ short event;
+ if( is_uv_tface_editing_allowed()==0 || !G.v2d) return; /* !G.v2d should never happen */
+
+ event = pupmenu("Snap %t|Selection -> Pixels%x1|Selection -> Cursor%x2|Selection -> Adjacent Unselected%x3|Cursor -> Pixel%x4|Cursor -> Selection%x5");
+ switch (event) {
+ case 1:
+ if (snap_uv_sel_to_pixels()) {
+ BIF_undo_push("Snap UV Selection to Pixels");
+ object_uvs_changed(OBACT);
+ }
+ break;
+ case 2:
+ if (snap_uv_sel_to_curs()) {
+ BIF_undo_push("Snap UV Selection to Cursor");
+ object_uvs_changed(OBACT);
+ }
+ break;
+ case 3:
+ if (snap_uv_sel_to_adj_unsel()) {
+ BIF_undo_push("Snap UV Selection to Cursor");
+ object_uvs_changed(OBACT);
+ }
+ break;
+ case 4:
+ snap_uv_curs_to_pixels();
+ scrarea_queue_winredraw(curarea);
+ break;
+ case 5:
+ if (snap_uv_curs_to_sel())
+ allqueue(REDRAWIMAGE, 0);
+ break;
+ }
+}
+
+
+/** This is an ugly function to set the Tface selection flags depending
+ * on whether its UV coordinates are inside the normalized
+ * area with radius rad and offset offset. These coordinates must be
+ * normalized to 1.0
+ * Just for readability...
+ */
+
+void sel_uvco_inside_radius(short sel, EditFace *efa, MTFace *tface, int index, float *offset, float *ell, short select_index)
+{
+ // normalized ellipse: ell[0] = scaleX,
+ // [1] = scaleY
+
+ float *uv = tface->uv[index];
+ float x, y, r2;
+
+ x = (uv[0] - offset[0]) * ell[0];
+ y = (uv[1] - offset[1]) * ell[1];
+
+ r2 = x * x + y * y;
+ if (r2 < 1.0) {
+ if (sel == LEFTMOUSE) SIMA_UVSEL_SET(efa, tface, select_index);
+ else SIMA_UVSEL_UNSET(efa, tface, select_index);
+ }
+}
+
+// see below:
+/** gets image dimensions of the 2D view 'v' */
+static void getSpaceImageDimension(SpaceImage *sima, float *xy)
+{
+ ImBuf *ibuf= BKE_image_get_ibuf(sima->image, &sima->iuser);
+
+ if (ibuf) {
+ xy[0] = ibuf->x * sima->zoom;
+ xy[1] = ibuf->y * sima->zoom;
+ } else {
+ xy[0] = 256 * sima->zoom;
+ xy[1] = 256 * sima->zoom;
+ }
+}
+
+/** Callback function called by circle_selectCB to enable
+ * brush select in UV editor.
+ */
+
+void uvedit_selectionCB(short selecting, Object *editobj, short *mval, float rad)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+ float offset[2];
+ MTFace *tface;
+ float ellipse[2]; // we need to deal with ellipses, as
+ // non square textures require for circle
+ // selection. this ellipse is normalized; r = 1.0
+
+ getSpaceImageDimension(curarea->spacedata.first, ellipse);
+ ellipse[0] /= rad;
+ ellipse[1] /= rad;
+
+ areamouseco_to_ipoco(G.v2d, mval, &offset[0], &offset[1]);
+
+ if (selecting) {
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ sel_uvco_inside_radius(selecting, efa, tface, 0, offset, ellipse, 0);
+ sel_uvco_inside_radius(selecting, efa, tface, 1, offset, ellipse, 1);
+ sel_uvco_inside_radius(selecting, efa, tface, 2, offset, ellipse, 2);
+ if (efa->v4)
+ sel_uvco_inside_radius(selecting, efa, tface, 3, offset, ellipse, 3);
+ }
+
+ if(G.f & G_DRAWFACES) { /* full redraw only if necessary */
+ draw_sel_circle(0, 0, 0, 0, 0); /* signal */
+ force_draw(0);
+ }
+ else { /* force_draw() is no good here... */
+ glDrawBuffer(GL_FRONT);
+ draw_uvs_sima();
+ bglFlush();
+ glDrawBuffer(GL_BACK);
+ }
+
+
+ if (selecting == LEFTMOUSE) EM_select_flush();
+ else EM_deselect_flush();
+
+ if (G.sima->lock && (G.sima->flag & SI_SYNC_UVSEL))
+ force_draw_plus(SPACE_VIEW3D, 0);
+ }
+}
+
+
+void mouseco_to_curtile(void)
+{
+ float fx, fy;
+ short mval[2];
+
+ if( is_uv_tface_editing_allowed()==0) return;
+
+ if(G.sima->image && G.sima->image->tpageflag & IMA_TILES) {
+
+ G.sima->flag |= SI_EDITTILE;
+
+ while(get_mbut()&L_MOUSE) {
+
+ calc_image_view(G.sima, 'f');
+
+ getmouseco_areawin(mval);
+ areamouseco_to_ipoco(G.v2d, mval, &fx, &fy);
+
+ if(fx>=0.0 && fy>=0.0 && fx<1.0 && fy<1.0) {
+
+ fx= (fx)*G.sima->image->xrep;
+ fy= (fy)*G.sima->image->yrep;
+
+ mval[0]= fx;
+ mval[1]= fy;
+
+ G.sima->curtile= mval[1]*G.sima->image->xrep + mval[0];
+ }
+
+ scrarea_do_windraw(curarea);
+ screen_swapbuffers();
+ }
+
+ G.sima->flag &= ~SI_EDITTILE;
+
+ image_set_tile(G.sima, 2);
+
+ allqueue(REDRAWVIEW3D, 0);
+ scrarea_queue_winredraw(curarea);
+ }
+}
+
+/* Could be used for other 2D views also */
+void mouseco_to_cursor_sima(void)
+{
+ short mval[2];
+ getmouseco_areawin(mval);
+ areamouseco_to_ipoco(G.v2d, mval, &G.v2d->cursor[0], &G.v2d->cursor[1]);
+ scrarea_queue_winredraw(curarea);
+}
+
+void stitch_limit_uv_tface(void)
+{
+ MTFace *tf;
+ int a, vtot;
+ float newuv[2], limit[2];
+ UvMapVert *vlist, *iterv;
+ EditMesh *em = G.editMesh;
+ EditVert *ev;
+ EditFace *efa;
+
+ struct UvVertMap *vmap;
+
+
+ if(is_uv_tface_editing_allowed()==0)
+ return;
+ if(G.sima->flag & SI_SYNC_UVSEL) {
+ error("Can't stitch when Sync Mesh Selection is enabled");
+ return;
+ }
+
+ limit[0]= limit[1]= 20.0;
+ add_numbut(0, NUM|FLO, "Limit:", 0.1, 1000.0, &limit[0], NULL);
+ if (!do_clever_numbuts("Stitch UVs", 1, REDRAW))
+ return;
+
+ limit[0]= limit[1]= limit[0]/256.0;
+ if(G.sima->image) {
+ ImBuf *ibuf= BKE_image_get_ibuf(G.sima->image, &G.sima->iuser);
+
+ if(ibuf && ibuf->x > 0 && ibuf->y > 0) {
+ limit[1]= limit[0]/(float)ibuf->y;
+ limit[0]= limit[0]/(float)ibuf->x;
+ }
+ }
+
+ /*vmap= make_uv_vert_map(me->mface, tf, me->totface, me->totvert, 1, limit);*/
+ EM_init_index_arrays(0, 0, 1);
+ vmap= make_uv_vert_map_EM(1, 0, limit);
+ if(vmap == NULL)
+ return;
+
+ for(a=0, ev= em->verts.first; ev; a++, ev= ev->next) {
+ vlist= get_uv_map_vert_EM(vmap, a);
+
+ while(vlist) {
+ newuv[0]= 0; newuv[1]= 0;
+ vtot= 0;
+
+ for(iterv=vlist; iterv; iterv=iterv->next) {
+ if((iterv != vlist) && iterv->separate)
+ break;
+ efa = EM_get_face_for_index(iterv->f);
+ tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+
+ if (tf[iterv->f].flag & TF_SEL_MASK(iterv->tfindex)) {
+ newuv[0] += tf->uv[iterv->tfindex][0];
+ newuv[1] += tf->uv[iterv->tfindex][1];
+ vtot++;
+ }
+ }
+
+ if (vtot > 1) {
+ newuv[0] /= vtot; newuv[1] /= vtot;
+
+ for(iterv=vlist; iterv; iterv=iterv->next) {
+ if((iterv != vlist) && iterv->separate)
+ break;
+ efa = EM_get_face_for_index(iterv->f);
+ tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ if (tf->flag & TF_SEL_MASK(iterv->tfindex)) {
+ tf->uv[iterv->tfindex][0]= newuv[0];
+ tf->uv[iterv->tfindex][1]= newuv[1];
+ }
+ }
+ }
+ vlist= iterv;
+ }
+ }
+
+ free_uv_vert_map_EM(vmap);
+ EM_free_index_arrays();
+
+ if(G.sima->flag & SI_BE_SQUARE) be_square_tface_uv(em);
+
+ BIF_undo_push("Stitch UV");
+
+ object_uvs_changed(OBACT);
+}
+
+void select_linked_tface_uv(int mode) /* TODO */
+{
+ EditMesh *em= G.editMesh;
+ EditFace *efa, *nearestefa=NULL;
+ MTFace *tf, *nearesttf=NULL;
+ UvVertMap *vmap;
+ UvMapVert *vlist, *iterv, *startv;
+ unsigned int *stack, stacksize= 0, nearestv;
+ char *flag;
+ int a, nearestuv, i, nverts, j;
+ float limit[2];
+ if(is_uv_tface_editing_allowed()==0)
+ return;
+
+ if(G.sima->flag & SI_SYNC_UVSEL) {
+ error("Can't select linked when Sync Mesh Selection is enabled");
+ return;
+ }
+
+ if (mode == 2) {
+ nearesttf= NULL;
+ nearestuv= 0;
+ }
+ if (mode!=2) {
+ find_nearest_uv(&nearesttf, &nearestefa, &nearestv, &nearestuv);
+ if(nearesttf==NULL)
+ return;
+ }
+
+ get_connected_limit_tface_uv(limit);
+ vmap= make_uv_vert_map_EM(1, 1, limit);
+ if(vmap == NULL)
+ return;
+
+ stack= MEM_mallocN(sizeof(*stack)* BLI_countlist(&em->faces), "UvLinkStack");
+ flag= MEM_callocN(sizeof(*flag)*BLI_countlist(&em->faces), "UvLinkFlag");
+
+ if (mode == 2) {
+ for (a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
+ tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ if (SIMA_FACEDRAW_CHECK(efa, tf)) {
+ if(tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)) {
+ stack[stacksize]= a;
+ stacksize++;
+ flag[a]= 1;
+ }
+ }
+ }
+ } else {
+ for (a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
+ tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ if(tf == nearesttf) {
+ stack[stacksize]= a;
+ stacksize++;
+ flag[a]= 1;
+ break;
+ }
+ }
+ }
+
+ while(stacksize > 0) {
+ stacksize--;
+ a= stack[stacksize];
+
+ for (j=0, efa= em->faces.first; efa; efa= efa->next, j++) {
+ if (j==a) {
+ tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ break;
+ }
+ }
+
+ nverts= efa->v4? 4: 3;
+
+ for(i=0; i<nverts; i++) {
+ /* make_uv_vert_map_EM sets verts tmp.l to the indicies */
+ vlist= get_uv_map_vert_EM(vmap, (*(&efa->v1 + i))->tmp.l);
+
+ startv= vlist;
+
+ for(iterv=vlist; iterv; iterv=iterv->next) {
+ if(iterv->separate)
+ startv= iterv;
+ if(iterv->f == a)
+ break;
+ }
+
+ for(iterv=startv; iterv; iterv=iterv->next) {
+ if((startv != iterv) && (iterv->separate))
+ break;
+ else if(!flag[iterv->f]) {
+ flag[iterv->f]= 1;
+ stack[stacksize]= iterv->f;;
+ stacksize++;
+ }
+ }
+ }
+ }
+
+ if(mode==0 || mode==2) {
+ for (a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
+ tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ if(flag[a])
+ tf->flag |= (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
+ else
+ tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
+ }
+ }
+ else if(mode==1) {
+ for (a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
+ if(flag[a]) {
+ tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ if (efa->v4) {
+ if((tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)))
+ break;
+ }
+ else if(tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3))
+ break;
+ }
+ }
+
+ if (efa) {
+ for (a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
+ if(flag[a]) {
+ tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
+ }
+ }
+ }
+ else {
+ for (a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
+ if(flag[a]) {
+ tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ tf->flag |= (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
+ }
+ }
+ }
+ }
+
+ MEM_freeN(stack);
+ MEM_freeN(flag);
+ free_uv_vert_map_EM(vmap);
+
+ BIF_undo_push("Select linked UV");
+ scrarea_queue_winredraw(curarea);
+}
+
+void unlink_selection(void)
+{
+ EditMesh *em= G.editMesh;
+ EditFace *efa;
+ MTFace *tface;
+
+ if( is_uv_tface_editing_allowed()==0 ) return;
+
+ if(G.sima->flag & SI_SYNC_UVSEL) {
+ error("Can't select unlinked when Sync Mesh Selection is enabled");
+ return;
+ }
+
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ if (SIMA_FACEDRAW_CHECK(efa, tface)) {
+ if(efa->v4) {
+ if(~tface->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4))
+ tface->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
+ } else {
+ if(~tface->flag & (TF_SEL1|TF_SEL2|TF_SEL3))
+ tface->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3);
+ }
+ }
+ }
+
+ BIF_undo_push("Unlink UV selection");
+ scrarea_queue_winredraw(curarea);
+}
+
+/* this function sets the selection on tagged faces
+ * This is needed because setting the selection on a face is done in
+ * a number of places but it also needs to respect the sticky modes
+ * for the UV verts - dealing with the sticky modes is best done in a seperate function
+ *
+ * de-selects faces that have been tagged on efa->tmp.l
+ */
+void uvface_setsel__internal(short select)
+{
+
+ /* All functions calling this should call
+ * draw_uvs_face_check()
+ */
+
+
+ /* selecting UV Faces with some modes requires us to change
+ * the selection in other faces (depending on the stickt mode)
+ *
+ * This only needs to be done when the Mesh is not used for selection
+ * (So for sticky modes - vertex or location based)
+ * */
+
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+ MTFace *tf;
+ int nverts, i;
+
+ if ((G.sima->flag & SI_SYNC_UVSEL)==0 && G.sima->sticky == SI_STICKY_VERTEX) {
+ /* tag all verts as untouched,
+ * then touch the ones that have a face center in the loop
+ * and select all MTFace UV's that use a touched vert */
+
+ EditVert *eve;
+
+ for (eve= em->verts.first; eve; eve= eve->next)
+ eve->tmp.l = 0;
+
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ if (efa->tmp.l) {
+ if (efa->v4) {
+ efa->v1->tmp.l= efa->v2->tmp.l= efa->v3->tmp.l= efa->v4->tmp.l=1;
+ } else {
+ efa->v1->tmp.l= efa->v2->tmp.l= efa->v3->tmp.l= 1;
+ }
+ }
+ }
+ /* now select tagged verts */
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ nverts= efa->v4? 4: 3;
+ for(i=0; i<nverts; i++) {
+ if ((*(&efa->v1 + i))->tmp.l) {
+ if (select) {
+ SIMA_UVSEL_SET(efa, tf, i);
+ } else {
+ SIMA_UVSEL_UNSET(efa, tf, i);
+ }
+ }
+ }
+ }
+ } else if ((G.sima->flag & SI_SYNC_UVSEL)==0 && G.sima->sticky == SI_STICKY_LOC) {
+ EditFace *efa_vlist;
+ MTFace *tf_vlist;
+ UvMapVert *vlist, *start_vlist=NULL, *vlist_iter;
+ struct UvVertMap *vmap;
+ float limit[2];
+ int efa_index;
+ //EditVert *eve; /* removed vert counting for now */
+ //int a;
+
+ get_connected_limit_tface_uv(limit);
+
+ EM_init_index_arrays(0, 0, 1);
+ vmap= make_uv_vert_map_EM(0, 0, limit);
+
+ /* verts are numbered above in make_uv_vert_map_EM, make sure this stays true! */
+ /*for (a=0, eve= em->verts.first; eve; a++, eve= eve->next)
+ eve->tmp.l = a; */
+
+ if(vmap == NULL)
+ return;
+
+ for (efa_index=0, efa= em->faces.first; efa; efa_index++, efa= efa->next) {
+ if (efa->tmp.l) {
+ tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ nverts= efa->v4? 4: 3;
+ for(i=0; i<nverts; i++) {
+ if (select) {
+ SIMA_UVSEL_SET(efa, tf, i);
+ } else {
+ SIMA_UVSEL_UNSET(efa, tf, i);
+ }
+
+ vlist= vlist_iter= get_uv_map_vert_EM(vmap, (*(&efa->v1 + i))->tmp.l);
+
+ while (vlist_iter) {
+ if (vlist_iter->separate)
+ start_vlist = vlist_iter;
+
+ if (efa_index == vlist_iter->f) {
+ break;
+ }
+ vlist_iter = vlist_iter->next;
+ }
+
+ vlist_iter = start_vlist;
+ while (vlist_iter) {
+
+ if (vlist_iter != start_vlist && vlist_iter->separate)
+ break;
+
+ if (efa_index != vlist_iter->f) {
+ efa_vlist = EM_get_face_for_index(vlist_iter->f);
+ tf_vlist = CustomData_em_get(&em->fdata, efa_vlist->data, CD_MTFACE);
+
+ if (select) {
+ SIMA_UVSEL_SET(efa_vlist, tf_vlist, vlist_iter->tfindex);
+ } else {
+ SIMA_UVSEL_UNSET(efa_vlist, tf_vlist, vlist_iter->tfindex);
+ }
+ }
+ vlist_iter = vlist_iter->next;
+ }
+ }
+ }
+ }
+ EM_free_index_arrays();
+ free_uv_vert_map_EM(vmap);
+
+ } else { /* SI_STICKY_DISABLE or G.sima->flag & SI_SYNC_UVSEL */
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ if (efa->tmp.l) {
+ tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ if (select) {
+ SIMA_FACESEL_SET(efa, tf);
+ } else {
+ SIMA_FACESEL_UNSET(efa, tf);
+ }
+ }
+ }
+ }
+}
+
+void pin_tface_uv(int mode)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+ MTFace *tface;
+
+ if( is_uv_tface_editing_allowed()==0 ) return;
+
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ if (SIMA_FACEDRAW_CHECK(efa, tface)) {
+ if(mode ==1) {
+ if(SIMA_UVSEL_CHECK(efa, tface, 0)) tface->unwrap |= TF_PIN1;
+ if(SIMA_UVSEL_CHECK(efa, tface, 1)) tface->unwrap |= TF_PIN2;
+ if(SIMA_UVSEL_CHECK(efa, tface, 2)) tface->unwrap |= TF_PIN3;
+ if(efa->v4)
+ if(SIMA_UVSEL_CHECK(efa, tface, 3)) tface->unwrap |= TF_PIN4;
+ }
+ else if (mode ==0) {
+ if(SIMA_UVSEL_CHECK(efa, tface, 0)) tface->unwrap &= ~TF_PIN1;
+ if(SIMA_UVSEL_CHECK(efa, tface, 1)) tface->unwrap &= ~TF_PIN2;
+ if(SIMA_UVSEL_CHECK(efa, tface, 2)) tface->unwrap &= ~TF_PIN3;
+ if(efa->v4)
+ if(SIMA_UVSEL_CHECK(efa, tface, 3)) tface->unwrap &= ~TF_PIN4;
+ }
+ }
+ }
+
+ BIF_undo_push("Pin UV");
+ scrarea_queue_winredraw(curarea);
+}
+
+void select_pinned_tface_uv(void)
+{
+ EditMesh *em= G.editMesh;
+ EditFace *efa;
+ MTFace *tface;
+
+ if( is_uv_tface_editing_allowed()==0 ) return;
+
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ if (SIMA_FACEDRAW_CHECK(efa, tface)) {
+ if (tface->unwrap & TF_PIN1) SIMA_UVSEL_SET(efa, tface, 0);
+ if (tface->unwrap & TF_PIN2) SIMA_UVSEL_SET(efa, tface, 1);
+ if (tface->unwrap & TF_PIN3) SIMA_UVSEL_SET(efa, tface, 2);
+ if(efa->v4) {
+ if (tface->unwrap & TF_PIN4) SIMA_UVSEL_SET(efa, tface, 3);
+ }
+
+ }
+ }
+
+ if (G.sima->flag & SI_SYNC_UVSEL) {
+ allqueue(REDRAWVIEW3D, 0); /* mesh selection has changed */
+ }
+
+ BIF_undo_push("Select Pinned UVs");
+ scrarea_queue_winredraw(curarea);
+}
+
+int minmax_tface_uv(float *min, float *max)
+{
+ EditMesh *em= G.editMesh;
+ EditFace *efa;
+ MTFace *tf;
+ int sel;
+
+ if( is_uv_tface_editing_allowed()==0 ) return 0;
+
+ INIT_MINMAX2(min, max);
+
+ sel= 0;
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ if (SIMA_FACEDRAW_CHECK(efa, tf)) {
+ if (SIMA_UVSEL_CHECK(efa, tf, 0)) DO_MINMAX2(tf->uv[0], min, max);
+ if (SIMA_UVSEL_CHECK(efa, tf, 1)) DO_MINMAX2(tf->uv[1], min, max);
+ if (SIMA_UVSEL_CHECK(efa, tf, 2)) DO_MINMAX2(tf->uv[2], min, max);
+ if (efa->v4 && (SIMA_UVSEL_CHECK(efa, tf, 3))) DO_MINMAX2(tf->uv[3], min, max);
+ sel = 1;
+ }
+ }
+ return sel;
+}
+
+int cent_tface_uv(float *cent, int mode)
+{
+ float min[2], max[2];
+ short change= 0;
+
+ if (mode==0) {
+ if (minmax_tface_uv(min, max))
+ change = 1;
+
+ } else if (mode==1) {
+ EditFace *efa;
+ MTFace *tf;
+ INIT_MINMAX2(min, max);
+
+ for (efa= G.editMesh->faces.first; efa; efa= efa->next) {
+ tf = CustomData_em_get(&G.editMesh->fdata, efa->data, CD_MTFACE);
+ if (SIMA_FACEDRAW_CHECK(efa, tf)) {
+ if (SIMA_UVSEL_CHECK(efa, tf, 0)) { DO_MINMAX2(tf->uv[0], min, max); change= 1;}
+ if (SIMA_UVSEL_CHECK(efa, tf, 1)) { DO_MINMAX2(tf->uv[1], min, max); change= 1;}
+ if (SIMA_UVSEL_CHECK(efa, tf, 2)) { DO_MINMAX2(tf->uv[2], min, max); change= 1;}
+ if (efa->v4 && (SIMA_UVSEL_CHECK(efa, tf, 3))) { DO_MINMAX2(tf->uv[3], min, max); change= 1;}
+ }
+ }
+ }
+
+ if (change) {
+ cent[0]= (min[0]+max[0])/2.0;
+ cent[1]= (min[1]+max[1])/2.0;
+ return 1;
+ }
+ return 0;
+}
+
+static void sima_show_info(int channels, int x, int y, char *cp, float *fp, int *zp, float *zpf)
+{
+ short ofs;
+ char str[256];
+
+ ofs= sprintf(str, "X: %d Y: %d ", x, y);
+ if(cp)
+ ofs+= sprintf(str+ofs, "| R: %d G: %d B: %d A: %d ", cp[0], cp[1], cp[2], cp[3]);
+ if(fp) {
+ if(channels==4)
+ ofs+= sprintf(str+ofs, "| R: %.3f G: %.3f B: %.3f A: %.3f ", fp[0], fp[1], fp[2], fp[3]);
+ else if(channels==1)
+ ofs+= sprintf(str+ofs, "| Val: %.3f ", fp[0]);
+ else if(channels==3)
+ ofs+= sprintf(str+ofs, "| R: %.3f G: %.3f B: %.3f ", fp[0], fp[1], fp[2]);
+ }
+ if(zp)
+ ofs+= sprintf(str+ofs, "| Z: %.4f ", 0.5+0.5*( ((float)*zp)/(float)0x7fffffff));
+ if(zpf)
+ ofs+= sprintf(str+ofs, "| Z: %.3f ", *zpf);
+
+ glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_BLEND);
+
+ glColor4f(.0,.0,.0,.25);
+ glRectf(0.0, 0.0, curarea->winx, 30.0);
+ glDisable(GL_BLEND);
+
+ glColor3ub(255, 255, 255);
+ glRasterPos2i(10, 10);
+
+ BMF_DrawString(G.fonts, str);
+
+}
+
+void sima_sample_color(void)
+{
+ ImBuf *ibuf= BKE_image_get_ibuf(G.sima->image, &G.sima->iuser);
+ float fx, fy;
+ short mval[2], mvalo[2], firsttime=1;
+
+ if(ibuf==NULL)
+ return;
+
+ calc_image_view(G.sima, 'f');
+ getmouseco_areawin(mvalo);
+
+ while(get_mbut() & L_MOUSE) {
+
+ getmouseco_areawin(mval);
+ if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || firsttime) {
+ firsttime= 0;
+ areamouseco_to_ipoco(G.v2d, mval, &fx, &fy);
+
+ if(fx>=0.0 && fy>=0.0 && fx<1.0 && fy<1.0) {
+ float *fp= NULL, *zpf= NULL;
+ int *zp= NULL;
+ char *cp= NULL;
+
+ int x= (int) (fx*ibuf->x);
+ int y= (int) (fy*ibuf->y);
+
+ if(x>=ibuf->x) x= ibuf->x-1;
+ if(y>=ibuf->y) y= ibuf->y-1;
+
+ if(ibuf->rect)
+ cp= (char *)(ibuf->rect + y*ibuf->x + x);
+ if(ibuf->zbuf)
+ zp= ibuf->zbuf + y*ibuf->x + x;
+ if(ibuf->zbuf_float)
+ zpf= ibuf->zbuf_float + y*ibuf->x + x;
+ if(ibuf->rect_float)
+ fp= (ibuf->rect_float + (ibuf->channels)*(y*ibuf->x + x));
+
+ if(G.sima->cumap) {
+ float vec[3];
+ if(fp==NULL) {
+ fp= vec;
+ vec[0]= (float)cp[0]/255.0f;
+ vec[1]= (float)cp[1]/255.0f;
+ vec[2]= (float)cp[2]/255.0f;
+ }
+
+ if(ibuf->channels==4) {
+ if(G.qual & LR_CTRLKEY) {
+ curvemapping_set_black_white(G.sima->cumap, NULL, fp);
+ curvemapping_do_ibuf(G.sima->cumap, ibuf);
+ }
+ else if(G.qual & LR_SHIFTKEY) {
+ curvemapping_set_black_white(G.sima->cumap, fp, NULL);
+ curvemapping_do_ibuf(G.sima->cumap, ibuf);
+ }
+ }
+ }
+
+ scrarea_do_windraw(curarea);
+ myortho2(-0.375, curarea->winx-0.375, -0.375, curarea->winy-0.375);
+ glLoadIdentity();
+ sima_show_info(ibuf->channels, x, y, cp, fp, zp, zpf);
+ screen_swapbuffers();
+ }
+
+ }
+ BIF_wait_for_statechange();
+ }
+
+ scrarea_queue_winredraw(curarea);
+}
+
+/* Image functions */
+
+static void load_image_filesel(char *str) /* called from fileselect */
+{
+ Image *ima= NULL;
+
+ ima= BKE_add_image_file(str);
+ if(ima) {
+ BKE_image_signal(ima, &G.sima->iuser, IMA_SIGNAL_RELOAD);
+ image_changed(G.sima, ima);
+ }
+ BIF_undo_push("Load image UV");
+ allqueue(REDRAWIMAGE, 0);
+}
+
+static void replace_image_filesel(char *str) /* called from fileselect */
+{
+ if (!G.sima->image)
+ return;
+
+ strncpy(G.sima->image->name, str, sizeof(G.sima->image->name)-1); /* we cant do much if the str is longer then 240 :/ */
+ BKE_image_signal(G.sima->image, &G.sima->iuser, IMA_SIGNAL_RELOAD);
+ BIF_undo_push("Replace image UV");
+ allqueue(REDRAWIMAGE, 0);
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+
+static void save_image_doit(char *name)
+{
+ Image *ima= G.sima->image;
+ ImBuf *ibuf= BKE_image_get_ibuf(ima, &G.sima->iuser);
+ int len;
+ char str[FILE_MAXDIR+FILE_MAXFILE];
+
+ if (ibuf) {
+ BLI_strncpy(str, name, sizeof(str));
+
+ BLI_convertstringcode(str, G.sce, G.scene->r.cfra);
+
+ if(G.scene->r.scemode & R_EXTENSION)
+ BKE_add_image_extension(str, G.sima->imtypenr);
+
+ if (saveover(str)) {
+
+ /* enforce user setting for RGB or RGBA, but skip BW */
+ if(G.scene->r.planes==32)
+ ibuf->depth= 32;
+ else if(G.scene->r.planes==24)
+ ibuf->depth= 24;
+
+ waitcursor(1);
+ if(G.sima->imtypenr==R_MULTILAYER) {
+ RenderResult *rr= BKE_image_get_renderresult(ima);
+ if(rr) {
+ RE_WriteRenderResult(rr, str, G.scene->r.quality);
+
+ BLI_strncpy(ima->name, name, sizeof(ima->name));
+ BLI_strncpy(ibuf->name, str, sizeof(ibuf->name));
+
+ /* should be function? nevertheless, saving only happens here */
+ for(ibuf= ima->ibufs.first; ibuf; ibuf= ibuf->next)
+ ibuf->userflags &= ~IB_BITMAPDIRTY;
+
+ }
+ else error("Did not write, no Multilayer Image");
+ }
+ else if (BKE_write_ibuf(ibuf, str, G.sima->imtypenr, G.scene->r.subimtype, G.scene->r.quality)) {
+ BLI_strncpy(ima->name, name, sizeof(ima->name));
+ BLI_strncpy(ibuf->name, str, sizeof(ibuf->name));
+
+ ibuf->userflags &= ~IB_BITMAPDIRTY;
+
+ /* change type? */
+ if( ELEM(ima->source, IMA_SRC_GENERATED, IMA_SRC_VIEWER)) {
+ ima->source= IMA_SRC_FILE;
+ ima->type= IMA_TYPE_IMAGE;
+ }
+ if(ima->type==IMA_TYPE_R_RESULT)
+ ima->type= IMA_TYPE_IMAGE;
+
+ /* name image as how we saved it */
+ len= strlen(str);
+ while (len > 0 && str[len - 1] != '/' && str[len - 1] != '\\') len--;
+ rename_id(&ima->id, str+len);
+ }
+ else {
+ error("Couldn't write image: %s", str);
+ }
+
+ allqueue(REDRAWHEADERS, 0);
+ allqueue(REDRAWBUTSSHADING, 0);
+
+ waitcursor(0);
+ }
+ }
+}
+
+void open_image_sima(short imageselect)
+{
+ char name[FILE_MAXDIR+FILE_MAXFILE];
+
+ if(G.sima->image)
+ strcpy(name, G.sima->image->name);
+ else
+ strcpy(name, U.textudir);
+
+ if(imageselect)
+ activate_imageselect(FILE_SPECIAL, "Open Image", name, load_image_filesel);
+ else
+ activate_fileselect(FILE_SPECIAL, "Open Image", name, load_image_filesel);
+}
+
+void replace_image_sima(short imageselect)
+{
+ char name[FILE_MAXDIR+FILE_MAXFILE];
+
+ if(G.sima->image)
+ strcpy(name, G.sima->image->name);
+ else
+ strcpy(name, U.textudir);
+
+ if(imageselect)
+ activate_imageselect(FILE_SPECIAL, "Replace Image", name, replace_image_filesel);
+ else
+ activate_fileselect(FILE_SPECIAL, "Replace Image", name, replace_image_filesel);
+}
+
+
+static char *filesel_imagetype_string(Image *ima)
+{
+ char *strp, *str= MEM_callocN(14*32, "menu for filesel");
+
+ strp= str;
+ str += sprintf(str, "Save Image as: %%t|");
+ str += sprintf(str, "Targa %%x%d|", R_TARGA);
+ str += sprintf(str, "Targa Raw %%x%d|", R_RAWTGA);
+ str += sprintf(str, "PNG %%x%d|", R_PNG);
+ str += sprintf(str, "BMP %%x%d|", R_BMP);
+ str += sprintf(str, "Jpeg %%x%d|", R_JPEG90);
+ str += sprintf(str, "Iris %%x%d|", R_IRIS);
+ if(G.have_libtiff)
+ str += sprintf(str, "Tiff %%x%d|", R_TIFF);
+ str += sprintf(str, "Radiance HDR %%x%d|", R_RADHDR);
+ str += sprintf(str, "Cineon %%x%d|", R_CINEON);
+ str += sprintf(str, "DPX %%x%d|", R_DPX);
+#ifdef WITH_OPENEXR
+ str += sprintf(str, "OpenEXR %%x%d|", R_OPENEXR);
+ /* saving sequences of multilayer won't work, they copy buffers */
+ if(ima->source==IMA_SRC_SEQUENCE && ima->type==IMA_TYPE_MULTILAYER);
+ else str += sprintf(str, "MultiLayer %%x%d|", R_MULTILAYER);
+#endif
+ return strp;
+}
+
+/* always opens fileselect */
+void save_as_image_sima(void)
+{
+ Image *ima = G.sima->image;
+ ImBuf *ibuf= BKE_image_get_ibuf(ima, &G.sima->iuser);
+ char name[FILE_MAXDIR+FILE_MAXFILE];
+
+ if (ima) {
+ strcpy(name, ima->name);
+
+ if (ibuf) {
+ char *strp;
+
+ strp= filesel_imagetype_string(ima);
+
+ /* cant save multilayer sequence, ima->rr isn't valid for a specific frame */
+ if(ima->rr && !(ima->source==IMA_SRC_SEQUENCE && ima->type==IMA_TYPE_MULTILAYER))
+ G.sima->imtypenr= R_MULTILAYER;
+ else if(ima->type==IMA_TYPE_R_RESULT)
+ G.sima->imtypenr= G.scene->r.imtype;
+ else G.sima->imtypenr= BKE_ftype_to_imtype(ibuf->ftype);
+
+ activate_fileselect_menu(FILE_SPECIAL, "Save Image", name, strp, &G.sima->imtypenr, save_image_doit);
+ }
+ }
+}
+
+/* if exists, saves over without fileselect */
+void save_image_sima(void)
+{
+ Image *ima = G.sima->image;
+ ImBuf *ibuf= BKE_image_get_ibuf(ima, &G.sima->iuser);
+ char name[FILE_MAXDIR+FILE_MAXFILE];
+
+ if (ima) {
+ strcpy(name, ima->name);
+
+ if (ibuf) {
+ if (BLI_exists(ibuf->name)) {
+ if(BKE_image_get_renderresult(ima))
+ G.sima->imtypenr= R_MULTILAYER;
+ else
+ G.sima->imtypenr= BKE_ftype_to_imtype(ibuf->ftype);
+
+ save_image_doit(ibuf->name);
+ }
+ else
+ save_as_image_sima();
+ }
+ }
+}
+
+void save_image_sequence_sima(void)
+{
+ ImBuf *ibuf;
+ int tot= 0;
+ char di[FILE_MAX], fi[FILE_MAX];
+
+ if(G.sima->image==NULL)
+ return;
+ if(G.sima->image->source!=IMA_SRC_SEQUENCE)
+ return;
+ if(G.sima->image->type==IMA_TYPE_MULTILAYER) {
+ error("Cannot save Multilayer Sequences");
+ return;
+ }
+
+ /* get total */
+ for(ibuf= G.sima->image->ibufs.first; ibuf; ibuf= ibuf->next)
+ if(ibuf->userflags & IB_BITMAPDIRTY)
+ tot++;
+
+ if(tot==0) {
+ notice("No Images have been changed");
+ return;
+ }
+ /* get a filename for menu */
+ for(ibuf= G.sima->image->ibufs.first; ibuf; ibuf= ibuf->next)
+ if(ibuf->userflags & IB_BITMAPDIRTY)
+ break;
+
+ BLI_strncpy(di, ibuf->name, FILE_MAX);
+ BLI_splitdirstring(di, fi);
+
+ sprintf(fi, "%d Image(s) will be saved in %s", tot, di);
+ if(okee(fi)) {
+
+ for(ibuf= G.sima->image->ibufs.first; ibuf; ibuf= ibuf->next) {
+ if(ibuf->userflags & IB_BITMAPDIRTY) {
+ char name[FILE_MAX];
+ BLI_strncpy(name, ibuf->name, sizeof(name));
+
+ BLI_convertstringcode(name, G.sce, 0);
+
+ if(0 == IMB_saveiff(ibuf, name, IB_rect | IB_zbuf | IB_zbuffloat)) {
+ error("Could not write image", name);
+ break;
+ }
+ printf("Saved: %s\n", ibuf->name);
+ ibuf->userflags &= ~IB_BITMAPDIRTY;
+ }
+ }
+ }
+}
+
+void reload_image_sima(void)
+{
+ if (G.sima ) {
+ BKE_image_signal(G.sima->image, &G.sima->iuser, IMA_SIGNAL_RELOAD);
+ /* image_changed(G.sima, 0); - do we really need this? */
+ }
+
+ allqueue(REDRAWIMAGE, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ BIF_preview_changed(ID_TE);
+}
+
+void new_image_sima(void)
+{
+ static int width= 256, height= 256;
+ static short uvtestgrid= 0;
+ static float color[] = {0, 0, 0, 1};
+ char name[22];
+ Image *ima;
+
+ strcpy(name, "Untitled");
+
+ add_numbut(0, TEX, "Name:", 0, 21, name, NULL);
+ add_numbut(1, NUM|INT, "Width:", 1, 5000, &width, NULL);
+ add_numbut(2, NUM|INT, "Height:", 1, 5000, &height, NULL);
+ add_numbut(3, COL, "", 0, 0, &color, NULL);
+ add_numbut(4, NUM|FLO, "Alpha:", 0.0, 1.0, &color[3], NULL);
+ add_numbut(5, TOG|SHO, "UV Test Grid", 0, 0, &uvtestgrid, NULL);
+ if (!do_clever_numbuts("New Image", 6, REDRAW))
+ return;
+
+ ima = BKE_add_image_size(width, height, name, uvtestgrid, color);
+ image_changed(G.sima, ima);
+ BKE_image_signal(G.sima->image, &G.sima->iuser, IMA_SIGNAL_USER_NEW_IMAGE);
+ BIF_undo_push("Add image");
+
+ allqueue(REDRAWIMAGE, 0);
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+void pack_image_sima()
+{
+ Image *ima = G.sima->image;
+
+ if (ima) {
+ if(ima->source!=IMA_SRC_SEQUENCE && ima->source!=IMA_SRC_MOVIE) {
+ if (ima->packedfile) {
+ if (G.fileflags & G_AUTOPACK)
+ if (okee("Disable AutoPack?"))
+ G.fileflags &= ~G_AUTOPACK;
+
+ if ((G.fileflags & G_AUTOPACK) == 0) {
+ unpackImage(ima, PF_ASK);
+ BIF_undo_push("Unpack image");
+ }
+ }
+ else {
+ ImBuf *ibuf= BKE_image_get_ibuf(ima, &G.sima->iuser);
+ if (ibuf && (ibuf->userflags & IB_BITMAPDIRTY)) {
+ if(okee("Can't pack painted image. Use Repack as PNG?"))
+ BKE_image_memorypack(ima);
+ }
+ else {
+ ima->packedfile = newPackedFile(ima->name);
+ BIF_undo_push("Pack image");
+ }
+ }
+
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWHEADERS, 0);
+ }
+ }
+}
+
+
+
+/* goes over all ImageUsers, and sets frame numbers if auto-refresh is set */
+void BIF_image_update_frame(void)
+{
+ Tex *tex;
+
+ /* texture users */
+ for(tex= G.main->tex.first; tex; tex= tex->id.next) {
+ if(tex->type==TEX_IMAGE && tex->ima)
+ if(ELEM(tex->ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE))
+ if(tex->iuser.flag & IMA_ANIM_ALWAYS)
+ BKE_image_user_calc_imanr(&tex->iuser, G.scene->r.cfra, 0);
+
+ }
+ /* image window, compo node users */
+ if(G.curscreen) {
+ ScrArea *sa;
+ for(sa= G.curscreen->areabase.first; sa; sa= sa->next) {
+ if(sa->spacetype==SPACE_VIEW3D) {
+ View3D *v3d= sa->spacedata.first;
+ if(v3d->bgpic)
+ if(v3d->bgpic->iuser.flag & IMA_ANIM_ALWAYS)
+ BKE_image_user_calc_imanr(&v3d->bgpic->iuser, G.scene->r.cfra, 0);
+ }
+ else if(sa->spacetype==SPACE_IMAGE) {
+ SpaceImage *sima= sa->spacedata.first;
+ if(sima->iuser.flag & IMA_ANIM_ALWAYS)
+ BKE_image_user_calc_imanr(&sima->iuser, G.scene->r.cfra, 0);
+ }
+ else if(sa->spacetype==SPACE_NODE) {
+ SpaceNode *snode= sa->spacedata.first;
+ if((snode->treetype==NTREE_COMPOSIT) && (snode->nodetree)) {
+ bNode *node;
+ for(node= snode->nodetree->nodes.first; node; node= node->next) {
+ if(node->id && node->type==CMP_NODE_IMAGE) {
+ Image *ima= (Image *)node->id;
+ ImageUser *iuser= node->storage;
+ if(ELEM(ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE))
+ if(iuser->flag & IMA_ANIM_ALWAYS)
+ BKE_image_user_calc_imanr(iuser, G.scene->r.cfra, 0);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void aspect_sima(SpaceImage *sima, float *x, float *y)
+{
+ *x = *y = 1.0;
+
+ if( (sima->image == 0) ||
+ (sima->image->type == IMA_TYPE_R_RESULT) ||
+ (sima->image->type == IMA_TYPE_COMPOSITE) ||
+ (sima->image->tpageflag & IMA_TILES) ||
+ (sima->image->aspx==0.0 || sima->image->aspy==0.0)
+ ) {
+ return;
+ }
+
+ /* x is always 1 */
+ *y = sima->image->aspy / sima->image->aspx;
+}
diff --git a/source/blender/src/editsound.c b/source/blender/src/editsound.c
new file mode 100644
index 00000000000..2e333b9f43e
--- /dev/null
+++ b/source/blender/src/editsound.c
@@ -0,0 +1,1063 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <fcntl.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef WIN32
+#define __USE_XOPEN /* Needed for swab on linux */
+#include <unistd.h>
+#undef __USE_XOPEN
+#else
+
+#include <io.h>
+#endif
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_sound_types.h"
+#include "DNA_packedFile_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_sound.h"
+#include "BKE_library.h"
+#include "BKE_packedFile.h"
+
+#include "BIF_space.h"
+#include "BIF_screen.h"
+#include "BIF_interface.h"
+#include "BIF_editsound.h"
+#include "BIF_mywindow.h"
+#include "BIF_toolbox.h"
+
+#include "BSE_drawipo.h"
+#include "BSE_headerbuttons.h"
+#include "BSE_time.h"
+
+#include "BDR_editobject.h"
+
+#include "blendef.h"
+
+#include "mydevice.h"
+
+#include "SND_C-api.h"
+#include "SND_DependKludge.h"
+
+#include "SYS_System.h"
+
+#include "PIL_time.h"
+
+
+/* this might move to the external header */
+void* sound_get_libraryinterface(void);
+
+static SND_SceneHandle ghSoundScene=NULL;
+static SND_AudioDeviceInterfaceHandle ghAudioDeviceInterface=NULL;
+
+/* que? why only here? because of the type define? */
+bSound *sound_find_sound(char *id_name);
+void sound_read_wav_data(bSound * sound, PackedFile * pf);
+void sound_stop_sound(void *object, bSound *sound);
+void winqreadsoundspace(struct ScrArea *sa, void *spacedata, struct BWinEvent *evt);
+/* void sound_stop_all_sounds(void); already in BIF_editsound.h */
+
+
+
+/* Right. Now for some implementation: */
+void winqreadsoundspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
+{
+ SpaceSound *ssound= spacedata;
+ unsigned short event= evt->event;
+ short val= evt->val;
+ float dx, dy;
+ int doredraw= 0, cfra, first = 0;
+ short mval[2], nr;
+ short mousebut = L_MOUSE;
+
+ if(curarea->win==0) return;
+
+ if(val) {
+
+ if( uiDoBlocks(&curarea->uiblocks, event)!=UI_NOTHING ) event= 0;
+
+ /* swap mouse buttons based on user preference */
+ if (U.flag & USER_LMOUSESELECT) {
+ if (event == LEFTMOUSE) {
+ event = RIGHTMOUSE;
+ mousebut = L_MOUSE;
+ } else if (event == RIGHTMOUSE) {
+ event = LEFTMOUSE;
+ mousebut = R_MOUSE;
+ }
+ }
+
+ switch(event) {
+ case LEFTMOUSE:
+ ssound->flag |= SND_CFRA_NUM;
+ do {
+ getmouseco_areawin(mval);
+ areamouseco_to_ipoco(G.v2d, mval, &dx, &dy);
+
+ cfra = (int)dx;
+ if(cfra< 1) cfra= 1;
+
+ if( cfra!=CFRA || first )
+ {
+ first= 0;
+ CFRA= cfra;
+ update_for_newframe();
+ force_draw_plus(SPACE_VIEW3D, 1);
+ }
+ else PIL_sleep_ms(30);
+
+ } while(get_mbut() & mousebut);
+ ssound->flag &= ~SND_CFRA_NUM;
+
+ doredraw= 1;
+
+ break;
+ case MIDDLEMOUSE:
+ case WHEELUPMOUSE:
+ case WHEELDOWNMOUSE:
+ view2dmove(event); /* in drawipo.c */
+ break;
+ case RIGHTMOUSE:
+ {
+ TimeMarker *marker;
+
+ getmouseco_areawin(mval);
+ areamouseco_to_ipoco(G.v2d, mval, &dx, &dy);
+
+ marker = find_nearest_marker(0);
+ if (marker) {
+ if ((G.qual & LR_SHIFTKEY)==0)
+ deselect_markers(0, 0);
+
+ if (marker->flag & SELECT)
+ marker->flag &= ~SELECT;
+ else
+ marker->flag |= SELECT;
+ }
+
+ force_draw(0);
+ std_rmouse_transform(transform_markers);
+ }
+ break;
+
+ case PADPLUSKEY:
+ dx= (float)(0.1154*(G.v2d->cur.xmax-G.v2d->cur.xmin));
+ G.v2d->cur.xmin+= dx;
+ G.v2d->cur.xmax-= dx;
+ test_view2d(G.v2d, curarea->winx, curarea->winy);
+ view2d_do_locks(curarea, V2D_LOCK_COPY);
+ doredraw= 1;
+ break;
+ case PADMINUS:
+ dx= (float)(0.15*(G.v2d->cur.xmax-G.v2d->cur.xmin));
+ G.v2d->cur.xmin-= dx;
+ G.v2d->cur.xmax+= dx;
+ test_view2d(G.v2d, curarea->winx, curarea->winy);
+ view2d_do_locks(curarea, V2D_LOCK_COPY);
+ doredraw= 1;
+ break;
+ case HOMEKEY:
+ do_sound_buttons(B_SOUNDHOME);
+ break;
+
+ case PAGEUPKEY: /* cfra to next marker */
+ nextprev_marker(1);
+ break;
+ case PAGEDOWNKEY: /* cfra to prev marker */
+ nextprev_marker(-1);
+ break;
+
+ case AKEY: /* select/deselect all */
+ deselect_markers(1, 0);
+
+ allqueue(REDRAWMARKER, 0);
+ break;
+
+ case BKEY: /* borderselect markers */
+ borderselect_markers();
+ break;
+
+ case DKEY: /* duplicate selected marker(s) */
+ if (G.qual & LR_SHIFTKEY) {
+ duplicate_marker();
+
+ allqueue(REDRAWMARKER, 0);
+ }
+ break;
+
+ case GKEY:
+ transform_markers('g', 0);
+ break;
+
+ case MKEY: /* add marker or rename first selected */
+ if (G.qual & LR_CTRLKEY)
+ rename_marker();
+ else
+ add_marker(CFRA);
+
+ allqueue(REDRAWMARKER, 0);
+ break;
+
+ case TKEY: /* toggle time display */
+ nr= pupmenu("Time value%t|Frames %x1|Seconds%x2");
+ if (nr>0) {
+ if(nr==1) ssound->flag |= SND_DRAWFRAMES;
+ else ssound->flag &= ~SND_DRAWFRAMES;
+ doredraw= 1;
+ }
+
+ break;
+
+ case DELKEY: /* delete selected markers */
+ case XKEY:
+ if (okee("Erase selected")) {
+ remove_marker();
+ allqueue(REDRAWMARKER, 0);
+ }
+ break;
+ }
+ }
+
+ if(doredraw)
+ scrarea_queue_winredraw(curarea);
+}
+
+
+
+void sound_initialize_sounds(void)
+{
+ bSound *sound;
+
+ if(ghSoundScene) {
+
+ /* clear the soundscene */
+ SND_RemoveAllSounds(ghSoundScene);
+ SND_RemoveAllSamples(ghSoundScene);
+ }
+
+ /* initialize sample blocks (doesnt call audio system, needs to be done once after load */
+ sound = G.main->sound.first;
+ while (sound) {
+ sound_sample_is_null(sound);
+ sound = (bSound *) sound->id.next;
+ }
+}
+
+
+
+bSound *sound_make_copy(bSound *originalsound)
+{
+ bSound *sound = NULL;
+ char name[160];
+ int len;
+
+ if(ghSoundScene==NULL) sound_init_audio();
+
+ /* only copy sounds that are sounds */
+ if (originalsound)
+ {
+ /* do some name magic */
+ strcpy(name, originalsound->name);
+ len = strlen(name);
+ while ((len > 0) && (name[len - 1] != '/') && (name[len - 1] != '\\'))
+ len--;
+
+ /* allocate the needed memory */
+ sound = alloc_libblock(&G.main->sound, ID_SO, name + len);
+
+ /* create a soundobject */
+ sound->snd_sound = SND_CreateSound();
+
+ /* set the samplename */
+ strcpy(sound->name, name);
+ SND_SetSampleName(sound->snd_sound, sound->name);
+
+ /* add the new object to the soundscene */
+ SND_AddSound(ghSoundScene, sound->snd_sound);
+
+ /* and copy the data from the original */
+ sound->attenuation = originalsound->attenuation;
+ sound->distance = originalsound->distance;
+ sound->max_gain = originalsound->max_gain;
+ sound->min_gain = originalsound->min_gain;
+ sound->newpackedfile = originalsound->newpackedfile;
+ sound->panning = originalsound->panning;
+ sound->pitch = originalsound->pitch;
+ sound->sample = originalsound->sample;
+ sound->volume = originalsound->volume;
+
+ if (originalsound->flags & SOUND_FLAGS_3D)
+ sound->flags |= SOUND_FLAGS_3D;
+ else
+ sound->flags &= ~SOUND_FLAGS_3D;
+ }
+
+ return sound;
+}
+
+
+
+void sound_initialize_sample(bSound *sound)
+{
+ if(ghSoundScene==NULL) sound_init_audio();
+
+ if (sound && sound->sample == NULL)
+ sound_sample_is_null(sound);
+}
+
+
+void sound_read_wav_data(bSound *sound, PackedFile *pf)
+{
+ int i, temp;
+ short shortbuf, *temps;
+ int longbuf;
+ char buffer[25];
+ char *data = NULL;
+ char *tempc;
+ bSample *sample = NULL;
+ int channels, rate, bits, len;
+
+ /* prepare for the worst... */
+ sound->sample->type = SAMPLE_INVALID;
+
+ rewindPackedFile(pf);
+
+ /* check to see if it is a file in "RIFF WAVE fmt" format */
+ if (readPackedFile(pf, buffer, 16) != 16) {
+ if (G.f & G_DEBUG) printf("File too short\n");
+ return;
+ }
+
+ if(!(memcmp(buffer, "RIFF", 4) && memcmp(&(buffer[8]), "WAVEfmt ", 8))) {
+ readPackedFile(pf, &i, 4);// start of data
+ if(G.order==B_ENDIAN)
+ SWITCH_INT(i);
+
+ /* read the sampleformat */
+ readPackedFile(pf, &shortbuf, 2);
+ if(G.order==B_ENDIAN) {
+ SWITCH_SHORT(shortbuf);
+ }
+
+ /* read the number of channels */
+ readPackedFile(pf, &shortbuf, 2);
+
+ if(G.order==B_ENDIAN) {
+ SWITCH_SHORT(shortbuf);
+ }
+
+ /* check the number of channels */
+ if(shortbuf != 1 && shortbuf != 2) {
+ if (G.f & G_DEBUG) printf("Unsupported number of channels\n");
+ return;
+ }
+ channels = shortbuf;
+
+ /* read the samplerate */
+ readPackedFile(pf, &longbuf, 4);
+
+
+ if(G.order==B_ENDIAN)
+ SWITCH_INT(longbuf);
+ rate = longbuf;
+
+ /* read the bitrate */
+ // Ton's way
+ readPackedFile(pf, &temp, 4);
+
+ if(G.order==B_ENDIAN)
+ SWITCH_INT(temp);
+
+ if(channels && rate)
+ bits= 8*temp/(rate * channels);
+
+ // Frank's way
+
+ readPackedFile(pf, &shortbuf, 2);
+ readPackedFile(pf, &shortbuf, 2);
+ if(G.order==B_ENDIAN) {
+ SWITCH_SHORT(shortbuf);
+ }
+ bits = shortbuf;
+
+ seekPackedFile(pf, i-16, SEEK_CUR);
+ readPackedFile(pf, buffer, 4);
+ /* check if we have a 'data' chunk */
+ while(memcmp(buffer, "data", 4)!=0) {
+ if (readPackedFile(pf, &i, 4) != 4)
+ break;
+
+ if(G.order==B_ENDIAN)
+ SWITCH_INT(i);
+
+ seekPackedFile(pf, i, SEEK_CUR);
+ if (readPackedFile(pf, buffer, 4) != 4)
+ break;
+ }
+
+ /* guess not */
+ if (memcmp(buffer, "data", 4) !=0) {
+ if (G.f & G_DEBUG) printf("No data found\n");
+ }
+ /* or maybe we do! */
+ else {
+ readPackedFile(pf, &longbuf, 4);
+ if(G.order==B_ENDIAN) SWITCH_INT(longbuf);
+
+ /* handle 8 and 16 bit samples differently */
+ /* intrr: removed, longbuf is length in bytes, not samples */
+ if (bits == 16)
+ data = (char *)MEM_mallocN(longbuf, "sample data");
+ else
+ data = (char *)MEM_mallocN(longbuf*2, "sample data");
+
+ len = longbuf /*/ 4.0*/; /* for some strange reason the sample length is off by a factor of 4... */
+ /* intrr's comment: Funny eh, how one 16-bit stereo sample is 4 bytes? :-) */
+
+ if(data) {
+ readPackedFile(pf, data, len);
+ /* data is only used to draw! */
+ if (bits == 8) {
+ temps = (short *) data;
+ tempc = (char *) data;
+ for (i = len - 1; i >= 0; i--)
+ temps[i] = tempc[i] << 8;
+ }
+ else {
+ if(G.order==B_ENDIAN) {
+ swab(data, data, len);
+ }
+ }
+ /* fill the sound with the found data */
+ sample = sound->sample;
+ sample->channels = channels;
+ sample->rate = rate;
+ sample->bits = bits;
+ sample->len = len;
+ sample->data = data;
+ sample->type = SAMPLE_WAV;
+ }
+ }
+ }
+ else {
+ sound->sample->type = SAMPLE_INVALID;
+ if (G.f & G_DEBUG) printf("Unsupported sound format: %s\n", sound->name);
+ }
+}
+
+
+
+/* ugly, but it works (for now) */
+static int sound_get_filetype_from_header(bSound *sound, PackedFile *pf)
+{
+ int filetype = SAMPLE_INVALID;
+ int i;
+ char buffer[25];
+ short shortbuf;
+
+ rewindPackedFile(pf);
+
+ if (readPackedFile(pf, buffer, 16) != 16) {
+ if (G.f & G_DEBUG) printf("File too short\n");
+ return filetype;
+ }
+
+ if(!(memcmp(buffer, "RIFF", 4) && memcmp(&(buffer[8]), "WAVEfmt ", 8))) {
+ readPackedFile(pf, &i, 4);
+ if(G.order==B_ENDIAN)
+ SWITCH_INT(i);
+
+ /* read the sampleformat */
+ readPackedFile(pf, &shortbuf, 2);
+ if(G.order==B_ENDIAN) {
+ char s_i, *p_i;
+ p_i= (char *)&(shortbuf);
+ s_i= p_i[0];
+ p_i[0]= p_i[1];
+ p_i[1]= s_i;
+ }
+
+ if (shortbuf == SND_WAVE_FORMAT_PCM) {
+ filetype = SAMPLE_WAV;
+ }
+ else
+ /* only fmod supports compressed wav */
+#ifdef USE_FMOD
+ {
+ /* and only valid publishers may use compressed wav */
+ switch (shortbuf)
+ {
+ case SND_WAVE_FORMAT_ADPCM:
+ case SND_WAVE_FORMAT_ALAW:
+ case SND_WAVE_FORMAT_MULAW:
+ case SND_WAVE_FORMAT_DIALOGIC_OKI_ADPCM:
+ case SND_WAVE_FORMAT_CONTROL_RES_VQLPC:
+ case SND_WAVE_FORMAT_GSM_610:
+ case SND_WAVE_FORMAT_MPEG3:
+ filetype = SAMPLE_WAV;
+ break;
+ default:
+#endif
+ {
+ filetype = SAMPLE_INVALID;
+ if (G.f & G_DEBUG) printf("Unsupported wav compression\n");
+ }
+ }
+#ifdef USE_FMOD
+ }
+ }
+ else if (!memcmp(buffer, "OggS", 4)) {
+ filetype = SAMPLE_OGG_VORBIS;
+ }
+ else if ((!memcmp(buffer, "ID3", 3)) || (!memcmp(buffer, "", 2))) {
+ filetype = SAMPLE_MP3;
+ }
+#endif
+ else {
+ filetype = SAMPLE_INVALID;
+ if (G.f & G_DEBUG) printf("Unsupported sound format: %s\n", sound->name);
+ }
+
+ return filetype;
+}
+
+
+
+static int check_filetype(bSound *sound, PackedFile *pf)
+{
+// char* pdest;
+ sound->sample->type = SAMPLE_INVALID;
+/*
+ // parse the name for the extension to see what kind of sample it is
+ pdest = strrchr(sound->sample->name, '.');
+
+ // a simple check to see what kind of sample we're dealing with
+ if (stricmp(pdest, ".wav") == 0)
+ sound->sample->type = SAMPLE_WAV;
+
+#ifdef USE_FMOD
+ if (stricmp(pdest, ".mp2") == 0)
+ sound->sample->type = SAMPLE_MP2;
+ if (stricmp(pdest, ".mp3") == 0)
+ sound->sample->type = SAMPLE_MP3;
+ if (stricmp(pdest, ".ogg") == 0)
+ sound->sample->type = SAMPLE_OGG_VORBIS;
+ if (stricmp(pdest, ".raw") == 0)
+ sound->sample->type = SAMPLE_RAW;
+ if (stricmp(pdest, ".wma") == 0)
+ sound->sample->type = SAMPLE_WMA;
+ if (stricmp(pdest, ".asf") == 0)
+ sound->sample->type = SAMPLE_ASF;
+#endif
+*/
+ sound->sample->type = sound_get_filetype_from_header(sound, pf);
+
+ /* get some info from the sample */
+ switch (sound->sample->type) {
+ case SAMPLE_WAV:
+ {
+ sound_read_wav_data(sound, pf);
+ break;
+ }
+ case SAMPLE_OGG_VORBIS:
+ case SAMPLE_MP3:
+ case SAMPLE_MP2:
+ case SAMPLE_RAW:
+ case SAMPLE_WMA:
+ case SAMPLE_ASF:
+ break;
+ default:
+ {
+ if (G.f & G_DEBUG) printf("No valid sample: %s\n", sound->name);
+ break;
+ }
+ }
+
+ return sound->sample->type;
+}
+
+
+
+int sound_load_sample(bSound *sound)
+{
+ int result = FALSE;
+ PackedFile *pf;
+ int freePF = FALSE;
+ int buffer = -1;
+
+ if(ghSoundScene==NULL) sound_init_audio();
+
+ /* check the sample (valid?) */
+ if (sound->sample->type == SAMPLE_UNKNOWN || sound->snd_sound == NULL) {
+ /* find... */
+ pf = sound_find_packedfile(sound);
+
+ /* ...or create a (temp)packedfile */
+ if (pf == NULL) {
+ pf = newPackedFile(sound->name);
+
+ /* if autopack is off, free the pf afterwards */
+ if ((G.fileflags & G_AUTOPACK) == 0)
+ freePF = TRUE;
+ }
+
+ /* if we have a valid pf... */
+ if (pf) {
+ /* check the content of the pf */
+ check_filetype(sound, pf);
+
+ /* check if the sampletype is supported */
+ if (sound->sample->type != SAMPLE_INVALID && sound->sample->type != SAMPLE_UNKNOWN) {
+ /* register the sample at the audiodevice */
+ buffer = SND_AddSample(ghSoundScene, sound->sample->name, pf->data, pf->size);
+
+ /* create a soundobject */
+ sound->snd_sound = SND_CreateSound();
+ SND_SetSampleName(sound->snd_sound, sound->sample->name);
+
+ /* add the soundobject to the soundscene */
+ if (SND_CheckBuffer(ghSoundScene, sound->snd_sound))
+ SND_AddSound(ghSoundScene, sound->snd_sound);
+ else
+ if (G.f & G_DEBUG) printf("error: sample didn't load properly\n");
+
+ /* if it was places in buffer[0] or higher, it succeeded */
+ if (buffer >= 0)
+ result = TRUE;
+ }
+ /* if not, free the pf */
+ else {
+ freePF = TRUE;
+ }
+
+ /* if you want it freed, make it so */
+ if (freePF) {
+ freePackedFile(pf);
+ pf = NULL;
+ }
+ /* or else connect the pf to the sound and sample */
+// else {
+ sound->newpackedfile = pf;
+ sound->sample->packedfile = pf;
+// }
+ }
+ else {
+ if (G.f & G_DEBUG) printf("%s: File not found!\n", sound->name);
+ sound->sample->type = SAMPLE_INVALID;
+ }
+ }
+ /* if the sample ain't invalid, we're ready to go! */
+ else if (sound->sample->type != SAMPLE_INVALID) {
+ result = TRUE;
+ }
+
+ return result;
+}
+
+
+
+bSound *sound_new_sound(char *name)
+{
+ bSound *sound = NULL;
+ int len, file;
+ char str[FILE_MAXDIR+FILE_MAXFILE];
+
+ if(ghSoundScene==NULL) sound_init_audio();
+
+ if (!G.scene->audio.mixrate) G.scene->audio.mixrate = 44100;
+ /* convert the name to absolute path */
+ strcpy(str, name);
+ BLI_convertstringcode(str, G.sce, G.scene->r.cfra);
+
+ /* check if the sample on disk can be opened */
+ file = open(str, O_BINARY|O_RDONLY);
+
+ if (file != -1) {
+ close(file);
+
+
+ /* do some name magic */
+ len = strlen(name);
+ while (len > 0 && name[len - 1] != '/' && name[len - 1] != '\\')
+ len--;
+
+ /* allocate some memory for the sound */
+ sound = alloc_libblock(&G.main->sound, ID_SO, name + len);
+ strcpy(sound->name, name);
+
+ /* intialize and check the sample */
+ sound_initialize_sample(sound);
+
+ /* load the sample & check if this blender supports the sound format */
+// sound_load_sample(sound);
+
+ if (sound->sample->type == SAMPLE_INVALID) {
+ free_libblock(&G.main->sound, sound);
+ sound = NULL;
+ }
+ else
+ {
+ sound->volume = 1.0;
+ sound->attenuation = 1.0;
+ sound->distance = 1.0;
+ sound->min_gain = 0.0;
+ sound->max_gain = 1.0;
+ }
+ }
+
+ return (sound);
+}
+
+
+
+int sound_set_sample(bSound *sound, bSample *sample)
+{
+ int result = TRUE;
+
+ if(ghSoundScene==NULL) sound_init_audio();
+
+ /* delete the soundobject */
+ if (sound->snd_sound) {
+ SND_RemoveSound(ghSoundScene, sound->snd_sound);
+ sound->snd_sound = NULL;
+ }
+
+ /* connect the sample to the sound */
+ sound->sample = sample;
+ sound->newpackedfile = NULL;
+
+ if (sound->sample) {
+
+ /* and set the right pf */
+ sound->newpackedfile = sample->packedfile;
+
+ /* if the sampletype is unknown initialize it */
+ if (sound->sample->type == SAMPLE_UNKNOWN) {
+ sound_initialize_sample(sound);
+
+ /* load the sample & check if this blender supports the sound format */
+ if (!sound_load_sample(sound)) {
+ result = FALSE;
+ }
+ }
+ }
+
+ return result;
+}
+
+
+
+bSample *sound_new_sample(bSound *sound)
+{
+ bSample *sample = NULL;
+ int len;
+ char *name;
+
+ if (sound != NULL) {
+ name = sound->name;
+ len = strlen(name);
+ /* do some name magic */
+ while (len > 0 && name[len - 1] != '/' && name[len - 1] != '\\')
+ len--;
+
+ /* allocate the memory for the sample */
+ sample = MEM_callocN(sizeof(bSample), "sample");
+ BLI_strncpy(sample->id.name+2, name+len, 20);
+ BLI_addtail(samples, sample); /* samples is ugly global */
+
+ sample->data = &sample->fakedata[0];
+ sample->type = SAMPLE_UNKNOWN;
+
+ /* some default settings. We get divide by zero if these values are not set */
+ sample->channels = 1;
+ sample->rate = 44100;
+ sample->bits = 16;
+ sample->alindex = SAMPLE_INVALID;
+
+ /* convert sound->name to abolute filename */
+ strcpy(sample->name, sound->name);
+ BLI_convertstringcode(sample->name, G.sce, G.scene->r.cfra);
+
+ /* connect the pf to the sample */
+ if (sound->newpackedfile)
+ sample->packedfile = sound->newpackedfile;
+ else
+ sample->packedfile = sound_find_packedfile(sound);
+ }
+
+ return(sample);
+}
+
+
+
+/* find a sample that might already be loaded */
+bSample *sound_find_sample(bSound *sound)
+{
+ bSample *sample;
+ char name[FILE_MAXDIR + FILE_MAXFILE];
+ char samplename[FILE_MAXDIR + FILE_MAXFILE];
+
+ // convert sound->name to abolute filename
+ strcpy(name, sound->name);
+ BLI_convertstringcode(name, G.sce, G.scene->r.cfra);
+
+ /* search through the list of loaded samples */
+ sample = samples->first;
+ while (sample) {
+ strcpy(samplename, sample->name);
+ BLI_convertstringcode(samplename, G.sce, G.scene->r.cfra);
+
+ if (strcmp(name, samplename) == 0) {
+ break;
+ }
+ sample = sample->id.next;
+ }
+
+ return (sample);
+}
+
+
+
+int sound_sample_is_null(bSound *sound)
+{
+ int result = FALSE;
+ bSample *sample;
+
+ if(ghSoundScene==NULL) sound_init_audio();
+
+ /* find the right sample or else create one */
+ if (sound->sample == NULL) {
+ /* find... */
+ sample = sound_find_sample(sound);
+
+ /* or a new one? */
+ if (sample == NULL)
+ sample = sound_new_sample(sound);
+
+ if (sound_set_sample(sound, sample))
+ result = TRUE;
+ }
+
+ return result;
+}
+
+
+
+void sound_stop_all_sounds(void)
+{
+#if GAMEBLENDER == 1
+ if(ghSoundScene) {
+ SND_StopAllSounds(ghSoundScene);
+ SND_Proceed(ghAudioDeviceInterface, ghSoundScene);
+ }
+#endif
+}
+
+
+
+void sound_end_all_sounds(void)
+{
+#if GAMEBLENDER == 1
+ if(ghSoundScene) {
+ sound_stop_all_sounds();
+ SND_RemoveAllSounds(ghSoundScene);
+ }
+#endif
+}
+
+
+
+void sound_play_sound(bSound *sound)
+{
+#if GAMEBLENDER == 1
+ if(ghSoundScene==NULL) sound_init_audio();
+
+ /* first check if we want sound or not */
+ SND_IsPlaybackWanted(ghSoundScene);
+
+ /* stop all previous sounds */
+ SND_StopAllSounds(ghSoundScene);
+
+ if (sound != NULL && sound->sample != NULL)
+ {
+ /* load the sample if needed */
+ if (sound_load_sample(sound))
+ {
+ /* set all kinds of parameters */
+ SND_SetListenerGain(ghSoundScene, G.listener->gain);
+ SND_SetDopplerFactor(ghSoundScene, G.listener->dopplerfactor);
+ SND_SetDopplerVelocity(ghSoundScene, G.listener->dopplervelocity);
+
+ SND_SetGain((SND_ObjectHandle)sound->snd_sound, (sound->volume));
+ SND_SetPitch((SND_ObjectHandle)sound->snd_sound, (exp((sound->pitch / 12.0) * log(2.0))));
+
+ if (sound->flags & SOUND_FLAGS_LOOP)
+ {
+ SND_SetLoopMode((SND_ObjectHandle)sound->snd_sound, SND_LOOP_NORMAL);
+#ifdef SOUND_UNDER_DEVELOPMENT
+/* SND_SetLoopPoints((SND_ObjectHandle)sound->snd_sound, sound->loopstart, sound->loopend);
+*/
+#endif
+ if (sound->flags & SOUND_FLAGS_BIDIRECTIONAL_LOOP)
+ SND_SetLoopMode((SND_ObjectHandle)sound->snd_sound, SND_LOOP_BIDIRECTIONAL);
+ else
+ SND_SetLoopMode((SND_ObjectHandle)sound->snd_sound, SND_LOOP_NORMAL);
+
+ }
+ else
+ {
+ SND_SetLoopMode((SND_ObjectHandle)sound->snd_sound, SND_LOOP_OFF);
+ }
+
+ if (sound->flags & SOUND_FLAGS_3D)
+ {
+ SND_SetRollOffFactor((SND_ObjectHandle)sound->snd_sound, sound->attenuation);
+ SND_SetReferenceDistance((SND_ObjectHandle)sound->snd_sound, sound->distance);
+ SND_SetMinimumGain((SND_ObjectHandle)sound->snd_sound, sound->min_gain);
+ SND_SetMaximumGain((SND_ObjectHandle)sound->snd_sound, sound->max_gain);
+ }
+ else
+ {
+ SND_SetRollOffFactor((SND_ObjectHandle)sound->snd_sound, 0);
+ SND_SetReferenceDistance((SND_ObjectHandle)sound->snd_sound, 1);
+ SND_SetMinimumGain((SND_ObjectHandle)sound->snd_sound, 1);
+ SND_SetMaximumGain((SND_ObjectHandle)sound->snd_sound, 1);
+ }
+
+ if (G.f & G_DEBUG) printf("Set pitch to: %f\n", SND_GetPitch((SND_ObjectHandle)sound->snd_sound));
+ if (G.f & G_DEBUG) printf("Set gain to: %f\n", SND_GetGain((SND_ObjectHandle)sound->snd_sound));
+ if (G.f & G_DEBUG) printf("Set looping to: %d\n", SND_GetLoopMode((SND_ObjectHandle)sound->snd_sound));
+
+ /* play the sound */
+ SND_StartSound(ghSoundScene, (SND_ObjectHandle)sound->snd_sound);
+
+ /* update the device */
+ SND_Proceed(ghAudioDeviceInterface, ghSoundScene);
+ }
+ }
+ else
+ {
+ if (G.f & G_DEBUG)
+ {
+ printf("uninitialized sound !\n");
+ if (sound)
+ {
+ printf("sound: %p\n", sound);
+ if (sound->sample)
+ {
+ printf("sample: %p\n", sound->sample);
+ if (sound->snd_sound)
+ printf("hSoundObject: %p\n", sound->snd_sound);
+ }
+ }
+ else
+ {
+ printf("sound == NULL\n");
+ }
+ }
+ }
+#endif
+}
+
+
+
+bSound *sound_find_sound(char *id_name)
+{
+ bSound *sound;
+
+ // look for sound with same *id* name
+ sound = G.main->sound.first;
+ while (sound)
+ {
+ if (strcmp(sound->id.name + 2, id_name) == 0)
+ break;
+
+ sound = sound->id.next;
+ }
+
+ return sound;
+}
+
+void sound_init_audio(void)
+{
+ int noaudio;
+ SYS_SystemHandle hSystem = NULL;
+
+ if(ghSoundScene==NULL) {
+ hSystem = SYS_GetSystem();
+ noaudio = SYS_GetCommandLineInt(hSystem,"noaudio",0);
+
+ if (noaudio)/*(noaudio) intrr: disable game engine audio (openal) */
+ SND_SetDeviceType(snd_e_dummydevice);
+
+ ghAudioDeviceInterface = SND_GetAudioDevice();
+ ghSoundScene = SND_CreateScene(ghAudioDeviceInterface);
+ // also called after read new file, but doesnt work when no audio initialized
+ sound_initialize_sounds();
+ }
+}
+
+
+int sound_get_mixrate(void)
+{
+ return MIXRATE;
+}
+
+
+void sound_exit_audio(void)
+{
+ if(ghSoundScene) {
+ SND_DeleteScene(ghSoundScene);
+ SND_ReleaseDevice();
+ ghSoundScene = NULL;
+ }
+}
diff --git a/source/blender/src/edittime.c b/source/blender/src/edittime.c
new file mode 100644
index 00000000000..f90fd1c2eda
--- /dev/null
+++ b/source/blender/src/edittime.c
@@ -0,0 +1,1008 @@
+/**
+ * $Id: BIF_edittime.c
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <math.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "DNA_action_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_object_types.h"
+#include "DNA_material_types.h"
+#include "DNA_space_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BKE_ipo.h"
+#include "BKE_utildefines.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_library.h"
+
+#include "BIF_space.h"
+#include "BIF_screen.h"
+#include "BIF_interface.h"
+#include "BIF_toolbox.h"
+#include "BIF_mywindow.h"
+#include "BIF_editaction.h"
+
+#include "BSE_drawipo.h"
+#include "BSE_edit.h"
+#include "BSE_headerbuttons.h"
+#include "BSE_time.h"
+
+#include "BDR_editobject.h"
+
+#include "blendef.h"
+
+#include "mydevice.h"
+
+#include "PIL_time.h"
+
+/* declarations */
+void winqreadtimespace(ScrArea *, void *, BWinEvent *);
+
+/* ************* Marker API **************** */
+
+/* add TimeMarker at curent frame */
+void add_marker(int frame)
+{
+ TimeMarker *marker;
+
+ /* two markers can't be at the same place */
+ for(marker= G.scene->markers.first; marker; marker= marker->next)
+ if(marker->frame == frame) return;
+ /* deselect all */
+ for(marker= G.scene->markers.first; marker; marker= marker->next)
+ marker->flag &= ~SELECT;
+
+ marker = MEM_callocN(sizeof(TimeMarker), "TimeMarker");
+ marker->flag= SELECT;
+ marker->frame= frame;
+ BLI_addtail(&(G.scene->markers), marker);
+
+ BIF_undo_push("Add Marker");
+}
+
+
+
+/* remove selected TimeMarkers */
+void remove_marker(void)
+{
+ TimeMarker *marker, *nmarker;
+ short changed= 0;
+
+ for(marker= G.scene->markers.first; marker; marker= nmarker) {
+ nmarker= marker->next;
+ if(marker->flag & SELECT) {
+ BLI_freelinkN(&(G.scene->markers), marker);
+ changed= 1;
+ }
+ }
+
+ if (changed)
+ BIF_undo_push("Remove Marker");
+}
+
+/* rename first selected TimeMarker */
+void rename_marker(void)
+{
+ TimeMarker *marker;
+ char name[64];
+
+ for(marker= G.scene->markers.first; marker; marker= marker->next) {
+ if(marker->flag & SELECT) {
+ strcpy(name, marker->name);
+ if (sbutton(name, 0, sizeof(name)-1, "Name: "))
+ BLI_strncpy(marker->name, name, sizeof(marker->name));
+ break;
+ }
+ }
+
+// BIF_undo_push("Rename Marker");
+}
+
+/* duplicate selected TimeMarkers */
+void duplicate_marker(void)
+{
+ TimeMarker *marker, *newmarker;
+
+ /* go through the list of markers, duplicate selected markers and add duplicated copies
+ * to the begining of the list (unselect original markers) */
+ for(marker= G.scene->markers.first; marker; marker= marker->next) {
+ if(marker->flag & SELECT){
+ /* unselect selected marker */
+ marker->flag &= ~SELECT;
+ /* create and set up new marker */
+ newmarker = MEM_callocN(sizeof(TimeMarker), "TimeMarker");
+ newmarker->flag= SELECT;
+ newmarker->frame= marker->frame;
+ BLI_strncpy(newmarker->name, marker->name, sizeof(marker->name));
+ /* new marker is added to the begining of list */
+ BLI_addhead(&(G.scene->markers), newmarker);
+ }
+ }
+
+ transform_markers('g', 0);
+}
+
+void transform_markers(int mode, int smode) // mode and smode unused here, for callback
+{
+ SpaceLink *slink= curarea->spacedata.first;
+ SpaceTime *stime= curarea->spacedata.first;
+ SpaceAction *saction = curarea->spacedata.first;
+ TimeMarker *marker, *selmarker=NULL;
+ float dx, fac;
+ int a, ret_val= 0, totmark=0, *oldframe, offs, firsttime=1;
+ unsigned short event;
+ short val, pmval[2], mval[2], mvalo[2];
+ char str[32];
+
+ for(marker= G.scene->markers.first; marker; marker= marker->next) {
+ if(marker->flag & SELECT) totmark++;
+ }
+ if(totmark==0) return;
+
+ oldframe= MEM_mallocN(totmark*sizeof(int), "marker array");
+ for(a=0, marker= G.scene->markers.first; marker; marker= marker->next) {
+ if(marker->flag & SELECT) {
+ oldframe[a]= marker->frame;
+ selmarker= marker; // used for hederprint
+ a++;
+ }
+ }
+
+ dx= G.v2d->mask.xmax-G.v2d->mask.xmin;
+ dx= (G.v2d->cur.xmax-G.v2d->cur.xmin)/dx;
+
+ getmouseco_areawin(pmval);
+ mvalo[0]= pmval[0];
+
+ while(ret_val == 0) {
+
+ getmouseco_areawin(mval);
+
+ if (mval[0] != mvalo[0] || firsttime) {
+ mvalo[0]= mval[0];
+ firsttime= 0;
+
+ fac= (((float)(mval[0] - pmval[0]))*dx);
+
+ if (ELEM(slink->spacetype, SPACE_TIME, SPACE_SOUND))
+ apply_keyb_grid(&fac, 0.0, FPS, 0.1*FPS, 0);
+ else
+ apply_keyb_grid(&fac, 0.0, 1.0, 0.1, U.flag & USER_AUTOGRABGRID);
+ offs= (int)fac;
+
+ for(a=0, marker= G.scene->markers.first; marker; marker= marker->next) {
+ if(marker->flag & SELECT) {
+ marker->frame= oldframe[a] + offs;
+ a++;
+ }
+ }
+
+ if(totmark==1) { // we print current marker value
+ if (ELEM(slink->spacetype, SPACE_TIME, SPACE_SOUND)) {
+ if (stime->flag & TIME_DRAWFRAMES)
+ sprintf(str, "Marker %d offset %d", selmarker->frame, offs);
+ else
+ sprintf(str, "Marker %.2f offset %.2f", FRA2TIME(selmarker->frame), FRA2TIME(offs));
+ }
+ else if (slink->spacetype == SPACE_ACTION) {
+ if (saction->flag & SACTION_DRAWTIME)
+ sprintf(str, "Marker %.2f offset %.2f", FRA2TIME(selmarker->frame), FRA2TIME(offs));
+ else
+ sprintf(str, "Marker %.2f offset %.2f", (double)(selmarker->frame), (double)(offs));
+ }
+ else {
+ sprintf(str, "Marker %.2f offset %.2f", (double)(selmarker->frame), (double)(offs));
+ }
+ }
+ else {
+ if (ELEM(slink->spacetype, SPACE_TIME, SPACE_SOUND)) {
+ if (stime->flag & TIME_DRAWFRAMES)
+ sprintf(str, "Marker offset %d ", offs);
+ else
+ sprintf(str, "Marker offset %.2f ", FRA2TIME(offs));
+ }
+ else if (slink->spacetype == SPACE_ACTION) {
+ if (saction->flag & SACTION_DRAWTIME)
+ sprintf(str, "Marker offset %.2f ", FRA2TIME(offs));
+ else
+ sprintf(str, "Marker offset %.2f ", (double)(offs));
+ }
+ else {
+ sprintf(str, "Marker offset %.2f ", (double)(offs));
+ }
+ }
+ headerprint(str);
+
+ force_draw(0); // areas identical to this, 0 = no header
+ }
+ else PIL_sleep_ms(10); // idle
+
+ /* emptying queue and reading events */
+ while( qtest() ) {
+ event= extern_qread(&val);
+
+ if(val) {
+ if(event==ESCKEY || event==RIGHTMOUSE) ret_val= 2;
+ else if(event==LEFTMOUSE || event==RETKEY || event==SPACEKEY) ret_val= 1;
+ }
+ }
+ }
+
+ /* restore? */
+ if(ret_val==2) {
+ for(a=0, marker= G.scene->markers.first; marker; marker= marker->next) {
+ if(marker->flag & SELECT) {
+ marker->frame= oldframe[a];
+ a++;
+ }
+ }
+ }
+ else {
+ BIF_undo_push("Move Markers");
+ }
+ MEM_freeN(oldframe);
+ allqueue(REDRAWMARKER, 0);
+}
+
+/* select/deselect all TimeMarkers
+ * test - based on current selections?
+ * sel - selection status to set all markers to if blanket apply status
+ */
+void deselect_markers(short test, short sel)
+{
+ TimeMarker *marker;
+
+ /* check if need to find out whether to how to select markers */
+ if (test) {
+ /* dependant on existing selection */
+ /* determine if select all or deselect all */
+ sel = 1;
+ for (marker= G.scene->markers.first; marker; marker= marker->next) {
+ if (marker->flag & SELECT) {
+ sel = 0;
+ break;
+ }
+ }
+
+ /* do selection */
+ for (marker= G.scene->markers.first; marker; marker= marker->next) {
+ if (sel == 2) {
+ marker->flag ^= SELECT;
+ }
+ else if (sel == 1) {
+ if ((marker->flag & SELECT)==0)
+ marker->flag |= SELECT;
+ }
+ else {
+ if (marker->flag & SELECT)
+ marker->flag &= ~SELECT;
+ }
+ }
+ }
+ else {
+ /* not dependant on existing selection */
+ for (marker= G.scene->markers.first; marker; marker= marker->next) {
+ if (sel==2) {
+ marker->flag ^= SELECT;
+ }
+ else if (sel==1) {
+ if ((marker->flag & SELECT)==0)
+ marker->flag |= SELECT;
+ }
+ else {
+ if (marker->flag & SELECT)
+ marker->flag &= ~SELECT;
+ }
+ }
+ }
+}
+
+static void borderselect_markers_func(float xmin, float xmax, int selectmode)
+{
+ TimeMarker *marker;
+
+ for(marker= G.scene->markers.first; marker; marker= marker->next) {
+ if ((marker->frame > xmin) && (marker->frame <= xmax)) {
+ switch (selectmode) {
+ case SELECT_ADD:
+ if ((marker->flag & SELECT) == 0)
+ marker->flag |= SELECT;
+ break;
+ case SELECT_SUBTRACT:
+ if (marker->flag & SELECT)
+ marker->flag &= ~SELECT;
+ break;
+ }
+ }
+ }
+}
+
+/* border-select markers */
+void borderselect_markers(void)
+{
+ rcti rect;
+ rctf rectf;
+ int val, selectmode;
+ short mval[2];
+
+ if ( (val = get_border(&rect, 3)) ){
+ if (val == LEFTMOUSE)
+ selectmode = SELECT_ADD;
+ else
+ selectmode = SELECT_SUBTRACT;
+
+ mval[0]= rect.xmin;
+ mval[1]= rect.ymin+2;
+ areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
+ mval[0]= rect.xmax;
+ mval[1]= rect.ymax-2;
+ areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
+
+ /* do markers */
+ borderselect_markers_func(rectf.xmin, rectf.xmax, selectmode);
+
+ BIF_undo_push("Border Select Markers");
+ allqueue(REDRAWMARKER, 0);
+ }
+}
+
+void nextprev_marker(short dir)
+{
+ TimeMarker *marker, *cur=NULL, *first, *last;
+ int mindist= MAXFRAME, dist;
+
+ first= last= G.scene->markers.first;
+ for(marker= G.scene->markers.first; marker; marker= marker->next) {
+ /* find closest to current frame first */
+ dist= (marker->frame/G.scene->r.framelen) - CFRA;
+ if(dir==1 && dist>0 && dist<mindist) {
+ mindist= dist;
+ cur= marker;
+ }
+ else if(dir==-1 && dist<0 && -dist<mindist) {
+ mindist= -dist;
+ cur= marker;
+ }
+ /* find first/last */
+ if(marker->frame > last->frame) last= marker;
+ if(marker->frame < first->frame) first= marker;
+ }
+
+ if(cur==NULL) {
+ if(dir==1) cur= first;
+ else cur= last;
+ }
+ if(cur) {
+ CFRA= cur->frame/G.scene->r.framelen;
+ update_for_newframe();
+ allqueue(REDRAWALL, 0);
+ }
+}
+
+void get_minmax_markers(short sel, float *first, float *last)
+{
+ TimeMarker *marker;
+ ListBase *markers;
+ float min, max;
+ int selcount = 0;
+
+ markers= &(G.scene->markers);
+
+ if (sel)
+ for (marker= markers->first; marker; marker= marker->next) {
+ if (marker->flag & SELECT)
+ selcount++;
+ }
+ else {
+ selcount= BLI_countlist(markers);
+ }
+
+ if (markers->first && markers->last) {
+ min= ((TimeMarker *)markers->first)->frame;
+ max= ((TimeMarker *)markers->last)->frame;
+ }
+ else {
+ *first = 0.0f;
+ *last = 0.0f;
+ return;
+ }
+
+ if (selcount > 1) {
+ for (marker= markers->first; marker; marker= marker->next) {
+ if (sel) {
+ if (marker->flag & SELECT) {
+ if (marker->frame < min)
+ min= marker->frame;
+ else if (marker->frame > max)
+ max= marker->frame;
+ }
+ }
+ else {
+ if (marker->frame < min)
+ min= marker->frame;
+ else if (marker->frame > max)
+ max= marker->frame;
+ }
+ }
+ }
+
+ *first= min;
+ *last= max;
+}
+
+TimeMarker *find_nearest_marker(int clip_y)
+{
+ TimeMarker *marker;
+ float xmin, xmax;
+ rctf rectf;
+ short mval[2];
+
+ getmouseco_areawin (mval);
+
+ /* first clip selection in Y */
+ if((clip_y) && (mval[1] > 30))
+ return NULL;
+
+ mval[0]-=7;
+ areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
+ mval[0]+=14;
+ areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
+
+ xmin= rectf.xmin;
+ xmax= rectf.xmax;
+
+ for(marker= G.scene->markers.first; marker; marker= marker->next) {
+ if ((marker->frame > xmin) && (marker->frame <= xmax)) {
+ return marker;
+ }
+ }
+
+ return NULL;
+}
+
+/* Adds a marker to list of cfra elems */
+void add_marker_to_cfra_elem(ListBase *lb, TimeMarker *marker, short only_sel)
+{
+ CfraElem *ce, *cen;
+
+ /* should this one only be considered if it is selected? */
+ if ((only_sel) && ((marker->flag & SELECT)==0))
+ return;
+
+ /* try to find a previous cfra elem */
+ ce= lb->first;
+ while(ce) {
+
+ if( ce->cfra==marker->frame ) {
+ /* do because of double keys */
+ if(marker->flag & SELECT) ce->sel= marker->flag;
+ return;
+ }
+ else if(ce->cfra > marker->frame) break;
+
+ ce= ce->next;
+ }
+
+ cen= MEM_callocN(sizeof(CfraElem), "add_to_cfra_elem");
+ if(ce) BLI_insertlinkbefore(lb, ce, cen);
+ else BLI_addtail(lb, cen);
+
+ cen->cfra= marker->frame;
+ cen->sel= marker->flag;
+}
+
+/* This function makes a list of all the markers. The only_sel
+ * argument is used to specify whether only the selected markers
+ * are added.
+ */
+void make_marker_cfra_list(ListBase *lb, short only_sel)
+{
+ TimeMarker *marker;
+
+ for (marker= G.scene->markers.first; marker; marker= marker->next) {
+ add_marker_to_cfra_elem(lb, marker, only_sel);
+ }
+}
+
+int find_nearest_marker_time(float dx)
+{
+ TimeMarker *marker, *nearest= NULL;
+ float dist, min_dist= 1000000;
+
+ for(marker= G.scene->markers.first; marker; marker= marker->next) {
+ dist = ABS((float)marker->frame - dx);
+ if(dist < min_dist){
+ min_dist= dist;
+ nearest= marker;
+ }
+ }
+
+ if(nearest) return nearest->frame;
+ else return (int)floor(dx);
+}
+
+/* *********** End Markers - Markers API *************** */
+/* select/deselect TimeMarker at current frame */
+static void select_timeline_marker_frame(int frame, unsigned char shift)
+{
+ TimeMarker *marker;
+ int select=0;
+
+ for(marker= G.scene->markers.first; marker; marker= marker->next) {
+ /* if Shift is not set, then deselect Markers */
+ if(!shift) marker->flag &= ~SELECT;
+ /* this way a not-shift select will allways give 1 selected marker */
+ if((marker->frame == frame) && (!select)) {
+ if(marker->flag & SELECT)
+ marker->flag &= ~SELECT;
+ else
+ marker->flag |= SELECT;
+ select = 1;
+ }
+ }
+}
+
+/* *********** end Markers - TimeLine *************** */
+
+/* set the animation preview range of scene */
+void anim_previewrange_set()
+{
+ extern float get_action_frame(Object *ob, float cframe);
+ rcti rect;
+ rctf rectf;
+ short val, mval[2];
+
+ /* set range by drawing border-select rectangle */
+ if ( (val = get_border(&rect, 5)) ) {
+ /* get frame numbers */
+ mval[0]= rect.xmin;
+ mval[1]= rect.ymin+2;
+ areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
+ mval[0]= rect.xmax;
+ mval[1]= rect.ymax-2;
+ areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
+
+ /* set preview-range */
+ if (rectf.xmin < 1) rectf.xmin = 1.0f;
+ if (rectf.xmax < 1) rectf.xmax = 1.0f;
+ G.scene->r.psfra= rectf.xmin;
+ G.scene->r.pefra= rectf.xmax;
+
+ BIF_undo_push("Set anim-preview range");
+ allqueue(REDRAWTIME, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWNLA, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWBUTSALL, 0);
+ }
+}
+
+/* clear the animation preview range for scene */
+void anim_previewrange_clear()
+{
+ G.scene->r.psfra = 0;
+ G.scene->r.pefra = 0;
+
+ BIF_undo_push("Clear anim-preview range");
+ allqueue(REDRAWTIME, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWNLA, 0);
+ allqueue(REDRAWBUTSALL, 0);
+}
+
+/* ************ end Animation Preview Range ********** */
+
+
+static int float_to_frame(float frame)
+{
+ int to= (int) floor(0.5 + frame/G.scene->r.framelen );
+
+ return to;
+}
+
+static float find_closest_cfra_elem(ListBase elems, int dir, float closest)
+{
+ CfraElem *ce;
+
+ for(ce= elems.first; ce; ce= ce->next) {
+ if (dir==-1) {
+ if( float_to_frame(ce->cfra)<CFRA) {
+ if ((ce->cfra > closest) || (closest == CFRA)) {
+ closest= ce->cfra;
+ }
+ }
+ }
+ else {
+ if(float_to_frame(ce->cfra)>CFRA) {
+ if ((ce->cfra < closest) || (closest == CFRA)) {
+ closest= ce->cfra;
+ }
+ }
+ }
+ }
+ return closest;
+}
+
+void nextprev_timeline_key(short dir)
+{
+ /*mostly copied from drawobject.c, draw_object() AND editipo.c, movekey_obipo() */
+ Object *ob;
+ bActionChannel *achan;
+ bAction *act;
+ ListBase elems;
+ float closest= CFRA;
+ int a;
+
+ if (OBACT) {
+ ob = OBACT;
+
+ if(ob) {
+ if(ob!=G.obedit) {
+ if(ob->ipo) {
+ /* convert the ipo to a list of 'current frame elements' */
+
+ elems.first= elems.last= NULL;
+ make_cfra_list(ob->ipo, &elems);
+
+ closest= find_closest_cfra_elem(elems, dir, closest);
+
+ BLI_freelistN(&elems);
+ }
+
+ if(ob->action) {
+ act = ob->action;
+ /* go through each channel in the action */
+ for (achan=act->chanbase.first; achan; achan=achan->next){
+ /* convert the ipo to a list of 'current frame elements' */
+
+ if(achan->ipo) {
+ elems.first= elems.last= NULL;
+ make_cfra_list(achan->ipo, &elems);
+
+ closest= find_closest_cfra_elem(elems, dir, closest);
+
+ BLI_freelistN(&elems);
+ }
+ }
+ }
+
+ for(a=0; a<ob->totcol; a++) {
+ Material *ma= give_current_material(ob, a+1);
+ if(ma && ma->ipo) {
+ elems.first= elems.last= NULL;
+ make_cfra_list(ma->ipo, &elems);
+
+ closest= find_closest_cfra_elem(elems, dir, closest);
+
+ BLI_freelistN(&elems);
+ }
+ }
+ }
+ }
+
+ a= float_to_frame(closest);
+
+ if (a!=CFRA) {
+ CFRA= a;
+ update_for_newframe();
+ }
+
+ BIF_undo_push("Next/Prev Key");
+ allqueue(REDRAWALL, 0);
+ }
+}
+
+/* return the current marker for this frame,
+we can have more then 1 marker per frame, this just returns the first :/ */
+TimeMarker *get_frame_marker(int frame)
+{
+ TimeMarker *marker, *best_marker = NULL;
+ int best_frame = -MAXFRAME*2;
+ for (marker= G.scene->markers.first; marker; marker= marker->next) {
+ if (marker->frame==frame) {
+ return marker;
+ }
+
+ if ( marker->frame > best_frame && marker->frame < frame) {
+ best_marker = marker;
+ best_frame = marker->frame;
+ }
+ }
+
+ return best_marker;
+}
+
+
+void timeline_frame_to_center(void)
+{
+ float dtime;
+
+ dtime= CFRA*(G.scene->r.framelen) - (G.v2d->cur.xmin + G.v2d->cur.xmax)/2.0;
+ G.v2d->cur.xmin += dtime;
+ G.v2d->cur.xmax += dtime;
+ scrarea_queue_winredraw(curarea);
+}
+
+/* copy of this is actually in editscreen.c, but event based */
+static void timeline_force_draw(short val)
+{
+ ScrArea *sa, *tempsa, *samin= NULL;
+ int dodraw;
+
+ if(val & TIME_LEFTMOST_3D_WIN) {
+ ScrArea *sa= G.curscreen->areabase.first;
+ int min= 10000;
+ for(; sa; sa= sa->next) {
+ if(sa->spacetype==SPACE_VIEW3D) {
+ if(sa->winrct.xmin - sa->winrct.ymin < min) {
+ samin= sa;
+ min= sa->winrct.xmin - sa->winrct.ymin;
+ }
+ }
+ }
+ }
+
+ tempsa= curarea;
+ sa= G.curscreen->areabase.first;
+ while(sa) {
+ dodraw= 0;
+ if(sa->spacetype==SPACE_VIEW3D) {
+ if(sa==samin || (val & TIME_ALL_3D_WIN)) dodraw= 1;
+ }
+ else if(ELEM6(sa->spacetype, SPACE_NLA, SPACE_IPO, SPACE_SEQ, SPACE_BUTS, SPACE_ACTION, SPACE_SOUND)) {
+ if(val & TIME_ALL_ANIM_WIN) dodraw= 1;
+ }
+ else if(sa->spacetype==SPACE_BUTS) {
+ if(val & TIME_ALL_BUTS_WIN) dodraw= 1;
+ }
+ else if(sa->spacetype==SPACE_IMAGE) {
+ if (val & TIME_ALL_IMAGE_WIN) dodraw = 1;
+ }
+ else if(sa->spacetype==SPACE_SEQ) {
+ if (val & TIME_SEQ) dodraw = 1;
+ }
+ else if(sa->spacetype==SPACE_TIME) dodraw= 2;
+
+ if(dodraw) {
+ areawinset(sa->win);
+ scrarea_do_windraw(sa);
+ if(dodraw==2) scrarea_do_headdraw(sa);
+ }
+ sa= sa->next;
+ }
+ areawinset(tempsa->win);
+
+ screen_swapbuffers();
+
+}
+
+/* ***************************** */
+
+/* Right. Now for some implementation: */
+void winqreadtimespace(ScrArea *sa, void *spacedata, BWinEvent *evt)
+{
+ SpaceTime *stime= spacedata;
+ unsigned short event= evt->event;
+ short val= evt->val;
+ float dx, dy;
+ int doredraw= 0, cfra, first = 0;
+ short mval[2], nr;
+ short mousebut = L_MOUSE;
+
+ if(sa->win==0) return;
+
+ if(val) {
+
+ if( uiDoBlocks(&sa->uiblocks, event)!=UI_NOTHING ) event= 0;
+
+ /* swap mouse buttons based on user preference */
+ if (U.flag & USER_LMOUSESELECT) {
+ if (event == LEFTMOUSE) {
+ event = RIGHTMOUSE;
+ mousebut = L_MOUSE;
+ } else if (event == RIGHTMOUSE) {
+ event = LEFTMOUSE;
+ mousebut = R_MOUSE;
+ }
+ }
+
+ switch(event) {
+ case LEFTMOUSE:
+ stime->flag |= TIME_CFRA_NUM;
+ do {
+ getmouseco_areawin(mval);
+ areamouseco_to_ipoco(G.v2d, mval, &dx, &dy);
+
+ cfra = (int)dx;
+ if(cfra< MINFRAME) cfra= MINFRAME;
+
+ if( cfra!=CFRA || first )
+ {
+ first= 0;
+ CFRA= cfra;
+ update_for_newframe_nodraw(0); // 1= nosound
+ timeline_force_draw(stime->redraws);
+ }
+ else PIL_sleep_ms(30);
+
+ } while(get_mbut() & mousebut);
+
+ stime->flag &= ~TIME_CFRA_NUM;
+ allqueue(REDRAWALL, 0);
+ break;
+
+ case RIGHTMOUSE: /* select/deselect marker */
+ getmouseco_areawin(mval);
+ areamouseco_to_ipoco(G.v2d, mval, &dx, &dy);
+
+ cfra= find_nearest_marker_time(dx);
+
+ if (G.qual && LR_SHIFTKEY)
+ select_timeline_marker_frame(cfra, 1);
+ else
+ select_timeline_marker_frame(cfra, 0);
+
+ force_draw(0);
+ std_rmouse_transform(transform_markers);
+
+ break;
+ case MIDDLEMOUSE:
+ case WHEELUPMOUSE:
+ case WHEELDOWNMOUSE:
+ view2dmove(event); /* in drawipo.c */
+ break;
+ case PADPLUSKEY:
+ dx= (float)(0.1154*(G.v2d->cur.xmax-G.v2d->cur.xmin));
+ G.v2d->cur.xmin+= dx;
+ G.v2d->cur.xmax-= dx;
+ test_view2d(G.v2d, sa->winx, sa->winy);
+ view2d_do_locks(curarea, V2D_LOCK_COPY);
+ doredraw= 1;
+ break;
+ case PADMINUS:
+ dx= (float)(0.15*(G.v2d->cur.xmax-G.v2d->cur.xmin));
+ G.v2d->cur.xmin-= dx;
+ G.v2d->cur.xmax+= dx;
+ test_view2d(G.v2d, sa->winx, sa->winy);
+ view2d_do_locks(curarea, V2D_LOCK_COPY);
+ doredraw= 1;
+ break;
+ case HOMEKEY:
+ first= G.scene->r.sfra;
+ if(first >= G.scene->r.efra) first= G.scene->r.efra;
+ G.v2d->cur.xmin=G.v2d->tot.xmin= (float)first-2;
+ G.v2d->cur.xmax=G.v2d->tot.xmax= (float)G.scene->r.efra+2;
+ doredraw= 1;
+ break;
+
+ case PAGEUPKEY: /* next keyframe */
+ if(G.qual==LR_CTRLKEY)
+ nextprev_timeline_key(1);
+ else
+ nextprev_marker(1);
+ break;
+ case PAGEDOWNKEY: /* prev keyframe */
+ if(G.qual==LR_CTRLKEY)
+ nextprev_timeline_key(-1);
+ else
+ nextprev_marker(-1);
+ break;
+
+ case AKEY:
+ /* deselect all TimeMarkers */
+ deselect_markers(1, 0);
+ allqueue(REDRAWMARKER, 0);
+ break;
+ case BKEY:
+ /* borderselect markers */
+ borderselect_markers();
+ break;
+ case DKEY:
+ if(G.qual==LR_SHIFTKEY)
+ duplicate_marker();
+ break;
+ case CKEY:
+ timeline_frame_to_center();
+ break;
+ case GKEY: /* move marker */
+ transform_markers('g', 0);
+ break;
+ case EKEY: /* set end frame */
+ if (G.scene->r.psfra) {
+ if (CFRA < G.scene->r.psfra)
+ G.scene->r.psfra= CFRA;
+ G.scene->r.pefra= CFRA;
+ }
+ else
+ G.scene->r.efra = CFRA;
+ allqueue(REDRAWALL, 1);
+ break;
+ case MKEY: /* add, rename marker */
+ if (G.qual & LR_CTRLKEY)
+ rename_marker();
+ else
+ add_marker(CFRA);
+ allqueue(REDRAWMARKER, 0);
+ break;
+ case PKEY: /* preview-range stuff */
+ if (G.qual & LR_CTRLKEY) /* set preview range */
+ anim_previewrange_set();
+ else if (G.qual & LR_ALTKEY) /* clear preview range */
+ anim_previewrange_clear();
+ break;
+ case SKEY: /* set start frame */
+ if (G.scene->r.psfra) {
+ if (G.scene->r.pefra < CFRA)
+ G.scene->r.pefra= CFRA;
+ G.scene->r.psfra= CFRA;
+ }
+ else
+ G.scene->r.sfra = CFRA;
+ allqueue(REDRAWALL, 1);
+ break;
+ case TKEY: /* popup menu */
+ nr= pupmenu("Time value%t|Frames %x1|Seconds%x2");
+ if (nr>0) {
+ if(nr==1) stime->flag |= TIME_DRAWFRAMES;
+ else stime->flag &= ~TIME_DRAWFRAMES;
+ doredraw= 1;
+ }
+ break;
+ case DELKEY:
+ case XKEY:
+ if( okee("Erase selected")==0 ) break;
+
+ remove_marker();
+ allqueue(REDRAWMARKER, 0);
+ break;
+ }
+ }
+
+ if(doredraw)
+ scrarea_queue_winredraw(sa);
+}
+
+
diff --git a/source/blender/src/editview.c b/source/blender/src/editview.c
new file mode 100644
index 00000000000..a11ef953c22
--- /dev/null
+++ b/source/blender/src/editview.c
@@ -0,0 +1,2776 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * cursor/gestures/selecteren
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "MEM_guardedalloc.h"
+
+#include "IMB_imbuf.h"
+#include "PIL_time.h"
+
+#include "DNA_action_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_group_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_ipo_types.h" /* for fly mode recording */
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_editVert.h"
+
+#include "BKE_armature.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_group.h"
+#include "BKE_lattice.h"
+#include "BKE_main.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h" /* fly mode where_is_object to get camera location */
+#include "BKE_utildefines.h"
+#include "BKE_customdata.h"
+
+#include "BIF_drawimage.h"
+#include "BIF_butspace.h"
+#include "BIF_editaction.h"
+#include "BIF_editarmature.h"
+#include "BIF_editgroup.h"
+#include "BIF_editmesh.h"
+#include "BIF_editoops.h"
+#include "BIF_editsima.h"
+#include "BIF_editview.h"
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+#include "BIF_interface.h"
+#include "BIF_mywindow.h"
+#include "BIF_previewrender.h" /* use only so fly mode can preview when its done */
+#include "BIF_space.h"
+#include "BIF_screen.h"
+#include "BIF_toolbox.h"
+
+#include "BDR_editobject.h" /* For headerprint */
+#include "BDR_sculptmode.h"
+#include "BDR_vpaint.h"
+#include "BDR_editface.h"
+#include "BDR_drawobject.h"
+#include "BDR_editcurve.h"
+
+#include "BSE_edit.h"
+#include "BSE_view.h" /* give_cursor() */
+#include "BSE_editipo.h"
+#include "BSE_drawview.h"
+
+#include "editmesh.h" /* borderselect uses it... */
+#include "blendef.h"
+#include "mydevice.h"
+
+#include "BIF_transform.h"
+#include "BIF_toets.h" /* persptoetsen */
+
+extern ListBase editNurb; /* originally from exports.h, memory from editcurve.c*/
+/* editmball.c */
+extern ListBase editelems;
+
+/* fly mode uses this */
+extern void setcameratoview3d(void);
+
+/* local prototypes */
+
+void EM_backbuf_checkAndSelectVerts(EditMesh *em, int select)
+{
+ EditVert *eve;
+ int index= em_wireoffs;
+
+ for(eve= em->verts.first; eve; eve= eve->next, index++) {
+ if(eve->h==0) {
+ if(EM_check_backbuf(index)) {
+ eve->f = select?(eve->f|1):(eve->f&~1);
+ }
+ }
+ }
+}
+
+void EM_backbuf_checkAndSelectEdges(EditMesh *em, int select)
+{
+ EditEdge *eed;
+ int index= em_solidoffs;
+
+ for(eed= em->edges.first; eed; eed= eed->next, index++) {
+ if(eed->h==0) {
+ if(EM_check_backbuf(index)) {
+ EM_select_edge(eed, select);
+ }
+ }
+ }
+}
+
+void EM_backbuf_checkAndSelectFaces(EditMesh *em, int select)
+{
+ EditFace *efa;
+ int index= 1;
+
+ for(efa= em->faces.first; efa; efa= efa->next, index++) {
+ if(efa->h==0) {
+ if(EM_check_backbuf(index)) {
+ EM_select_face_fgon(efa, select);
+ }
+ }
+ }
+}
+
+void EM_backbuf_checkAndSelectTFaces(Mesh *me, int select)
+{
+ MFace *mface = me->mface;
+ int a;
+
+ if (mface) {
+ for(a=1; a<=me->totface; a++, mface++) {
+ if(EM_check_backbuf(a)) {
+ mface->flag = select?(mface->flag|ME_FACE_SEL):(mface->flag&~ME_FACE_SEL);
+ }
+ }
+ }
+}
+
+void arrows_move_cursor(unsigned short event)
+{
+ short mval[2];
+
+ getmouseco_sc(mval);
+
+ if(event==UPARROWKEY) {
+ warp_pointer(mval[0], mval[1]+1);
+ } else if(event==DOWNARROWKEY) {
+ warp_pointer(mval[0], mval[1]-1);
+ } else if(event==LEFTARROWKEY) {
+ warp_pointer(mval[0]-1, mval[1]);
+ } else if(event==RIGHTARROWKEY) {
+ warp_pointer(mval[0]+1, mval[1]);
+ }
+}
+
+/* simple API for object selection, rather than just using the flag
+ * this takes into account the 'restrict selection in 3d view' flag.
+ * deselect works always, the restriction just prevents selection */
+void select_base_v3d(Base *base, short mode)
+{
+ if (base) {
+ if (mode==BA_SELECT) {
+ if (!(base->object->restrictflag & OB_RESTRICT_SELECT))
+ if (mode==BA_SELECT) base->flag |= SELECT;
+ }
+ else if (mode==BA_DESELECT) {
+ base->flag &= ~SELECT;
+ }
+ }
+}
+
+/* *********************** GESTURE AND LASSO ******************* */
+
+/* helper also for borderselect */
+static int edge_fully_inside_rect(rcti *rect, short x1, short y1, short x2, short y2)
+{
+ return BLI_in_rcti(rect, x1, y1) && BLI_in_rcti(rect, x2, y2);
+}
+
+static int edge_inside_rect(rcti *rect, short x1, short y1, short x2, short y2)
+{
+ int d1, d2, d3, d4;
+
+ /* check points in rect */
+ if(edge_fully_inside_rect(rect, x1, y1, x2, y2)) return 1;
+
+ /* check points completely out rect */
+ if(x1<rect->xmin && x2<rect->xmin) return 0;
+ if(x1>rect->xmax && x2>rect->xmax) return 0;
+ if(y1<rect->ymin && y2<rect->ymin) return 0;
+ if(y1>rect->ymax && y2>rect->ymax) return 0;
+
+ /* simple check lines intersecting. */
+ d1= (y1-y2)*(x1- rect->xmin ) + (x2-x1)*(y1- rect->ymin );
+ d2= (y1-y2)*(x1- rect->xmin ) + (x2-x1)*(y1- rect->ymax );
+ d3= (y1-y2)*(x1- rect->xmax ) + (x2-x1)*(y1- rect->ymax );
+ d4= (y1-y2)*(x1- rect->xmax ) + (x2-x1)*(y1- rect->ymin );
+
+ if(d1<0 && d2<0 && d3<0 && d4<0) return 0;
+ if(d1>0 && d2>0 && d3>0 && d4>0) return 0;
+
+ return 1;
+}
+
+
+#define MOVES_GESTURE 50
+#define MOVES_LASSO 500
+
+static int lasso_inside(short mcords[][2], short moves, short sx, short sy)
+{
+ /* we do the angle rule, define that all added angles should be about zero or 2*PI */
+ float angletot=0.0, len, dot, ang, cross, fp1[2], fp2[2];
+ int a;
+ short *p1, *p2;
+
+ if(sx==IS_CLIPPED)
+ return 0;
+
+ p1= mcords[moves-1];
+ p2= mcords[0];
+
+ /* first vector */
+ fp1[0]= (float)(p1[0]-sx);
+ fp1[1]= (float)(p1[1]-sy);
+ len= sqrt(fp1[0]*fp1[0] + fp1[1]*fp1[1]);
+ fp1[0]/= len;
+ fp1[1]/= len;
+
+ for(a=0; a<moves; a++) {
+ /* second vector */
+ fp2[0]= (float)(p2[0]-sx);
+ fp2[1]= (float)(p2[1]-sy);
+ len= sqrt(fp2[0]*fp2[0] + fp2[1]*fp2[1]);
+ fp2[0]/= len;
+ fp2[1]/= len;
+
+ /* dot and angle and cross */
+ dot= fp1[0]*fp2[0] + fp1[1]*fp2[1];
+ ang= fabs(saacos(dot));
+
+ cross= (float)((p1[1]-p2[1])*(p1[0]-sx) + (p2[0]-p1[0])*(p1[1]-sy));
+
+ if(cross<0.0) angletot-= ang;
+ else angletot+= ang;
+
+ /* circulate */
+ fp1[0]= fp2[0]; fp1[1]= fp2[1];
+ p1= p2;
+ p2= mcords[a+1];
+ }
+
+ if( fabs(angletot) > 4.0 ) return 1;
+ return 0;
+}
+
+/* edge version for lasso select. we assume boundbox check was done */
+static int lasso_inside_edge(short mcords[][2], short moves, int x0, int y0, int x1, int y1)
+{
+ short v1[2], v2[2];
+ int a;
+
+ if(x0==IS_CLIPPED || x1==IS_CLIPPED)
+ return 0;
+
+ v1[0] = x0, v1[1] = y0;
+ v2[0] = x1, v2[1] = y1;
+
+ /* check points in lasso */
+ if(lasso_inside(mcords, moves, v1[0], v1[1])) return 1;
+ if(lasso_inside(mcords, moves, v2[0], v2[1])) return 1;
+
+ /* no points in lasso, so we have to intersect with lasso edge */
+
+ if( IsectLL2Ds(mcords[0], mcords[moves-1], v1, v2) > 0) return 1;
+ for(a=0; a<moves-1; a++) {
+ if( IsectLL2Ds(mcords[a], mcords[a+1], v1, v2) > 0) return 1;
+ }
+
+ return 0;
+}
+
+
+/* warning; lasso select with backbuffer-check draws in backbuf with persp(PERSP_WIN)
+ and returns with persp(PERSP_VIEW). After lasso select backbuf is not OK
+*/
+static void do_lasso_select_pose(Object *ob, short mcords[][2], short moves, short select)
+{
+ bPoseChannel *pchan;
+ float vec[3];
+ short sco1[2], sco2[2];
+
+ if(ob->type!=OB_ARMATURE || ob->pose==NULL) return;
+
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ VECCOPY(vec, pchan->pose_head);
+ Mat4MulVecfl(ob->obmat, vec);
+ project_short(vec, sco1);
+ VECCOPY(vec, pchan->pose_tail);
+ Mat4MulVecfl(ob->obmat, vec);
+ project_short(vec, sco2);
+
+ if(lasso_inside_edge(mcords, moves, sco1[0], sco1[1], sco2[0], sco2[1])) {
+ if(select) pchan->bone->flag |= BONE_SELECTED;
+ else pchan->bone->flag &= ~(BONE_ACTIVE|BONE_SELECTED);
+ }
+ }
+}
+
+
+static void do_lasso_select_objects(short mcords[][2], short moves, short select)
+{
+ Base *base;
+
+ for(base= G.scene->base.first; base; base= base->next) {
+ if(base->lay & G.vd->lay) {
+ project_short(base->object->obmat[3], &base->sx);
+ if(lasso_inside(mcords, moves, base->sx, base->sy)) {
+
+ if(select) select_base_v3d(base, BA_SELECT);
+ else select_base_v3d(base, BA_DESELECT);
+ base->object->flag= base->flag;
+ }
+ if(base->object->flag & OB_POSEMODE) {
+ do_lasso_select_pose(base->object, mcords, moves, select);
+ }
+ }
+ }
+}
+
+static void lasso_select_boundbox(rcti *rect, short mcords[][2], short moves)
+{
+ short a;
+
+ rect->xmin= rect->xmax= mcords[0][0];
+ rect->ymin= rect->ymax= mcords[0][1];
+
+ for(a=1; a<moves; a++) {
+ if(mcords[a][0]<rect->xmin) rect->xmin= mcords[a][0];
+ else if(mcords[a][0]>rect->xmax) rect->xmax= mcords[a][0];
+ if(mcords[a][1]<rect->ymin) rect->ymin= mcords[a][1];
+ else if(mcords[a][1]>rect->ymax) rect->ymax= mcords[a][1];
+ }
+}
+
+static void do_lasso_select_mesh__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
+{
+ struct { rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
+
+ if (BLI_in_rcti(data->rect, x, y) && lasso_inside(data->mcords, data->moves, x, y)) {
+ eve->f = data->select?(eve->f|1):(eve->f&~1);
+ }
+}
+static void do_lasso_select_mesh__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
+{
+ struct { rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
+
+ if (EM_check_backbuf(em_solidoffs+index)) {
+ if (data->pass==0) {
+ if ( edge_fully_inside_rect(data->rect, x0, y0, x1, y1) &&
+ lasso_inside(data->mcords, data->moves, x0, y0) &&
+ lasso_inside(data->mcords, data->moves, x1, y1)) {
+ EM_select_edge(eed, data->select);
+ data->done = 1;
+ }
+ } else {
+ if (lasso_inside_edge(data->mcords, data->moves, x0, y0, x1, y1)) {
+ EM_select_edge(eed, data->select);
+ }
+ }
+ }
+}
+static void do_lasso_select_mesh__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
+{
+ struct { rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
+
+ if (BLI_in_rcti(data->rect, x, y) && lasso_inside(data->mcords, data->moves, x, y)) {
+ EM_select_face_fgon(efa, data->select);
+ }
+}
+
+static void do_lasso_select_mesh(short mcords[][2], short moves, short select)
+{
+ struct { rcti *rect; short (*mcords)[2], moves, select, pass, done; } data;
+ EditMesh *em = G.editMesh;
+ rcti rect;
+ int bbsel;
+
+ lasso_select_boundbox(&rect, mcords, moves);
+
+ data.rect = &rect;
+ data.mcords = mcords;
+ data.moves = moves;
+ data.select = select;
+ data.done = 0;
+ data.pass = 0;
+
+ bbsel= EM_mask_init_backbuf_border(mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
+
+ if(G.scene->selectmode & SCE_SELECT_VERTEX) {
+ if (bbsel) {
+ EM_backbuf_checkAndSelectVerts(em, select);
+ } else {
+ mesh_foreachScreenVert(do_lasso_select_mesh__doSelectVert, &data, 1);
+ }
+ }
+ if(G.scene->selectmode & SCE_SELECT_EDGE) {
+ /* Does both bbsel and non-bbsel versions (need screen cos for both) */
+
+ data.pass = 0;
+ mesh_foreachScreenEdge(do_lasso_select_mesh__doSelectEdge, &data, 0);
+
+ if (data.done==0) {
+ data.pass = 1;
+ mesh_foreachScreenEdge(do_lasso_select_mesh__doSelectEdge, &data, 0);
+ }
+ }
+
+ if(G.scene->selectmode & SCE_SELECT_FACE) {
+ if (bbsel) {
+ EM_backbuf_checkAndSelectFaces(em, select);
+ } else {
+ mesh_foreachScreenFace(do_lasso_select_mesh__doSelectFace, &data);
+ }
+ }
+
+ EM_free_backbuf();
+ EM_selectmode_flush();
+}
+
+/* this is an exception in that its the only lasso that dosnt use the 3d view (uses space image view) */
+static void do_lasso_select_mesh_uv(short mcords[][2], short moves, short select)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+ MTFace *tf;
+ int screenUV[2], nverts, i, ok = 1;
+ rcti rect;
+
+ lasso_select_boundbox(&rect, mcords, moves);
+
+ if (draw_uvs_face_check()) { /* Face Center Sel */
+ float cent[2];
+ ok = 0;
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ /* assume not touched */
+ efa->tmp.l = 0;
+ tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ if ((select) != (SIMA_FACESEL_CHECK(efa, tf))) {
+ tface_center(tf, cent, (void *)efa->v4);
+ uvco_to_areaco_noclip(cent, screenUV);
+ if (BLI_in_rcti(&rect, screenUV[0], screenUV[1]) && lasso_inside(mcords, moves, screenUV[0], screenUV[1])) {
+ efa->tmp.l = ok = 1;
+ }
+ }
+ }
+ /* (de)selects all tagged faces and deals with sticky modes */
+ if (ok)
+ uvface_setsel__internal(select);
+
+ } else { /* Vert Sel*/
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ if (SIMA_FACEDRAW_CHECK(efa, tf)) {
+ nverts= efa->v4? 4: 3;
+ for(i=0; i<nverts; i++) {
+ if ((select) != (SIMA_UVSEL_CHECK(efa, tf, i))) {
+ uvco_to_areaco_noclip(tf->uv[i], screenUV);
+ if (BLI_in_rcti(&rect, screenUV[0], screenUV[1]) && lasso_inside(mcords, moves, screenUV[0], screenUV[1])) {
+ if (select) {
+ SIMA_UVSEL_SET(efa, tf, i);
+ } else {
+ SIMA_UVSEL_UNSET(efa, tf, i);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if (ok && G.sima->flag & SI_SYNC_UVSEL) {
+ if (select) EM_select_flush();
+ else EM_deselect_flush();
+ }
+}
+
+static void do_lasso_select_curve__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
+{
+ struct { short (*mcords)[2]; short moves; short select; } *data = userData;
+
+ if (lasso_inside(data->mcords, data->moves, x, y)) {
+ if (bp) {
+ bp->f1 = data->select?(bp->f1|1):(bp->f1&~1);
+ } else {
+ if (G.f & G_HIDDENHANDLES) {
+ /* can only be beztindex==0 here since handles are hidden */
+ bezt->f1 = bezt->f2 = bezt->f3 = data->select?(bezt->f1|1):(bezt->f1&~1);
+ } else {
+ if (beztindex==0) {
+ bezt->f1 = data->select?(bezt->f1|1):(bezt->f1&~1);
+ } else if (beztindex==1) {
+ bezt->f2 = data->select?(bezt->f2|1):(bezt->f2&~1);
+ } else {
+ bezt->f3 = data->select?(bezt->f3|1):(bezt->f3&~1);
+ }
+ }
+ }
+ }
+}
+static void do_lasso_select_curve(short mcords[][2], short moves, short select)
+{
+ struct { short (*mcords)[2]; short moves; short select; } data;
+
+ data.mcords = mcords;
+ data.moves = moves;
+ data.select = select;
+
+ nurbs_foreachScreenVert(do_lasso_select_curve__doSelect, &data);
+}
+
+static void do_lasso_select_lattice__doSelect(void *userData, BPoint *bp, int x, int y)
+{
+ struct { short (*mcords)[2]; short moves; short select; } *data = userData;
+
+ if (lasso_inside(data->mcords, data->moves, x, y)) {
+ bp->f1 = data->select?(bp->f1|1):(bp->f1&~1);
+ }
+}
+static void do_lasso_select_lattice(short mcords[][2], short moves, short select)
+{
+ struct { short (*mcords)[2]; short moves; short select; } data;
+
+ data.mcords = mcords;
+ data.moves = moves;
+ data.select = select;
+
+ lattice_foreachScreenVert(do_lasso_select_lattice__doSelect, &data);
+}
+
+static void do_lasso_select_armature(short mcords[][2], short moves, short select)
+{
+ EditBone *ebone;
+ float vec[3];
+ short sco1[2], sco2[2], didpoint;
+
+ for (ebone=G.edbo.first; ebone; ebone=ebone->next) {
+
+ VECCOPY(vec, ebone->head);
+ Mat4MulVecfl(G.obedit->obmat, vec);
+ project_short(vec, sco1);
+ VECCOPY(vec, ebone->tail);
+ Mat4MulVecfl(G.obedit->obmat, vec);
+ project_short(vec, sco2);
+
+ didpoint= 0;
+ if(lasso_inside(mcords, moves, sco1[0], sco1[1])) {
+ if(select) ebone->flag |= BONE_ROOTSEL;
+ else ebone->flag &= ~BONE_ROOTSEL;
+ didpoint= 1;
+ }
+ if(lasso_inside(mcords, moves, sco2[0], sco2[1])) {
+ if(select) ebone->flag |= BONE_TIPSEL;
+ else ebone->flag &= ~BONE_TIPSEL;
+ didpoint= 1;
+ }
+ /* if one of points selected, we skip the bone itself */
+ if(didpoint==0 && lasso_inside_edge(mcords, moves, sco1[0], sco1[1], sco2[0], sco2[1])) {
+ if(select) ebone->flag |= BONE_TIPSEL|BONE_ROOTSEL|BONE_SELECTED;
+ else ebone->flag &= ~(BONE_ACTIVE|BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
+ }
+ }
+ countall(); /* abused for flushing selection */
+}
+
+static void do_lasso_select_facemode(short mcords[][2], short moves, short select)
+{
+ Mesh *me;
+ rcti rect;
+
+ me= get_mesh(OBACT);
+ if(me==NULL || me->mtface==NULL) return;
+ if(me->totface==0) return;
+
+ em_vertoffs= me->totface+1; /* max index array */
+
+ lasso_select_boundbox(&rect, mcords, moves);
+ EM_mask_init_backbuf_border(mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
+
+ EM_backbuf_checkAndSelectTFaces(me, select);
+
+ EM_free_backbuf();
+
+ object_tface_flags_changed(OBACT, 0);
+}
+
+static void do_lasso_select(short mcords[][2], short moves, short select)
+{
+ if(G.obedit==NULL) {
+ if(FACESEL_PAINT_TEST)
+ do_lasso_select_facemode(mcords, moves, select);
+ else if(G.f & (G_VERTEXPAINT|G_TEXTUREPAINT|G_WEIGHTPAINT))
+ ;
+ else
+ do_lasso_select_objects(mcords, moves, select);
+ }
+ else if(G.obedit->type==OB_MESH) {
+ if(curarea->spacetype==SPACE_VIEW3D) {
+ do_lasso_select_mesh(mcords, moves, select);
+ } else if (EM_texFaceCheck()){
+ do_lasso_select_mesh_uv(mcords, moves, select);
+ }
+ } else if(G.obedit->type==OB_CURVE || G.obedit->type==OB_SURF)
+ do_lasso_select_curve(mcords, moves, select);
+ else if(G.obedit->type==OB_LATTICE)
+ do_lasso_select_lattice(mcords, moves, select);
+ else if(G.obedit->type==OB_ARMATURE)
+ do_lasso_select_armature(mcords, moves, select);
+
+ BIF_undo_push("Lasso select");
+
+ if (EM_texFaceCheck())
+ allqueue(REDRAWIMAGE, 0);
+
+ allqueue(REDRAWVIEW3D, 0);
+ countall();
+}
+
+/* un-draws and draws again */
+static void draw_lasso_select(short mcords[][2], short moves, short end)
+{
+ int a;
+
+ setlinestyle(2);
+ /* clear draw */
+ if(moves>1) {
+ for(a=1; a<=moves-1; a++) {
+ sdrawXORline(mcords[a-1][0], mcords[a-1][1], mcords[a][0], mcords[a][1]);
+ }
+ sdrawXORline(mcords[moves-1][0], mcords[moves-1][1], mcords[0][0], mcords[0][1]);
+ }
+ if(!end) {
+ /* new draw */
+ for(a=1; a<=moves; a++) {
+ sdrawXORline(mcords[a-1][0], mcords[a-1][1], mcords[a][0], mcords[a][1]);
+ }
+ sdrawXORline(mcords[moves][0], mcords[moves][1], mcords[0][0], mcords[0][1]);
+ }
+ setlinestyle(0);
+}
+
+
+static char interpret_move(short mcord[][2], int count)
+{
+ float x1, x2, y1, y2, d1, d2, inp, sq, mouse[MOVES_GESTURE][2];
+ int i, j, dir = 0;
+
+ if (count <= 10) return ('g');
+
+ /* from short to float (drawing is with shorts) */
+ for(j=0; j<count; j++) {
+ mouse[j][0]= mcord[j][0];
+ mouse[j][1]= mcord[j][1];
+ }
+
+ /* new method:
+ *
+ * starting from end points, calculate center with maximum distance
+ * dependant at the angle s / g / r is defined
+ */
+
+
+ /* filter */
+
+ for( j = 3 ; j > 0; j--){
+ x1 = mouse[1][0];
+ y1 = mouse[1][1];
+ for (i = 2; i < count; i++){
+ x2 = mouse[i-1][0];
+ y2 = mouse[i-1][1];
+ mouse[i-1][0] = ((x1 + mouse[i][0]) /4.0) + (x2 / 2.0);
+ mouse[i-1][1] = ((y1 + mouse[i][1]) /4.0) + (y2 / 2.0);
+ x1 = x2;
+ y1 = y2;
+ }
+ }
+
+ /* make overview of directions */
+ for (i = 0; i <= count - 2; i++){
+ x1 = mouse[i][0] - mouse[i + 1][0];
+ y1 = mouse[i][1] - mouse[i + 1][1];
+
+ if (x1 < -0.5){
+ if (y1 < -0.5) dir |= 32;
+ else if (y1 > 0.5) dir |= 128;
+ else dir |= 64;
+ } else if (x1 > 0.5){
+ if (y1 < -0.5) dir |= 8;
+ else if (y1 > 0.5) dir |= 2;
+ else dir |= 4;
+ } else{
+ if (y1 < -0.5) dir |= 16;
+ else if (y1 > 0.5) dir |= 1;
+ else dir |= 0;
+ }
+ }
+
+ /* move all crosses to the right */
+ for (i = 7; i>=0 ; i--){
+ if (dir & 128) dir = (dir << 1) + 1;
+ else break;
+ }
+ dir &= 255;
+ for (i = 7; i>=0 ; i--){
+ if ((dir & 1) == 0) dir >>= 1;
+ else break;
+ }
+
+ /* in theory: 1 direction: straight line
+ * multiple sequential directions: circle
+ * non-sequential, and 1 bit set in upper 4 bits: size
+ */
+ switch(dir){
+ case 1:
+ return ('g');
+ break;
+ case 3:
+ case 7:
+ x1 = mouse[0][0] - mouse[count >> 1][0];
+ y1 = mouse[0][1] - mouse[count >> 1][1];
+ x2 = mouse[count >> 1][0] - mouse[count - 1][0];
+ y2 = mouse[count >> 1][1] - mouse[count - 1][1];
+ d1 = (x1 * x1) + (y1 * y1);
+ d2 = (x2 * x2) + (y2 * y2);
+ sq = sqrt(d1);
+ x1 /= sq;
+ y1 /= sq;
+ sq = sqrt(d2);
+ x2 /= sq;
+ y2 /= sq;
+ inp = (x1 * x2) + (y1 * y2);
+ /*printf("%f\n", inp);*/
+ if (inp > 0.9) return ('g');
+ else return ('r');
+ break;
+ case 15:
+ case 31:
+ case 63:
+ case 127:
+ case 255:
+ return ('r');
+ break;
+ default:
+ /* for size at least one of the higher bits has to be set */
+ if (dir < 16) return ('r');
+ else return ('s');
+ }
+
+ return (0);
+}
+
+
+/* return 1 to denote gesture did something, also does lasso */
+int gesture(void)
+{
+ unsigned short event=0;
+ int i= 1, end= 0, a;
+ short mcords[MOVES_LASSO][2]; /* the larger size */
+ short mval[2], val, timer=0, mousebut, lasso=0, maxmoves;
+
+ if (U.flag & USER_LMOUSESELECT) mousebut = R_MOUSE;
+ else mousebut = L_MOUSE;
+
+ /* check for lasso */
+ if(G.qual & LR_CTRLKEY) {
+ if(curarea->spacetype==SPACE_VIEW3D) {
+ if(G.obedit==NULL) {
+ if(G.f & (G_VERTEXPAINT|G_TEXTUREPAINT|G_WEIGHTPAINT)) return 0;
+ }
+ lasso= 1;
+ } else if (curarea->spacetype==SPACE_IMAGE) {
+ if(G.obedit) {
+ lasso= 1;
+ }
+ }
+ }
+
+ glDrawBuffer(GL_FRONT);
+ persp(PERSP_WIN); /* ortho at pixel level */
+
+ getmouseco_areawin(mval);
+
+ mcords[0][0] = mval[0];
+ mcords[0][1] = mval[1];
+
+ if(lasso) maxmoves= MOVES_LASSO;
+ else maxmoves= MOVES_GESTURE;
+
+ while(get_mbut() & mousebut) {
+
+ if(qtest()) event= extern_qread(&val);
+ else if(i==1) {
+ /* not drawing yet... check for toolbox */
+ PIL_sleep_ms(10);
+ timer++;
+ if(timer>=10*U.tb_leftmouse) {
+ glDrawBuffer(GL_BACK); /* !! */
+ toolbox_n();
+ return 1;
+ }
+ }
+
+ switch (event) {
+ case MOUSEY:
+ getmouseco_areawin(mval);
+ if( abs(mval[0]-mcords[i-1][0])>3 || abs(mval[1]-mcords[i-1][1])>3 ) {
+ mcords[i][0] = mval[0];
+ mcords[i][1] = mval[1];
+
+ if(i) {
+ if(lasso) draw_lasso_select(mcords, i, 0);
+ else sdrawXORline(mcords[i-1][0], mcords[i-1][1], mcords[i][0], mcords[i][1]);
+ bglFlush();
+ }
+ i++;
+ }
+ break;
+ case MOUSEX:
+ break;
+ case LEFTMOUSE:
+ break;
+ default:
+ if(event) end= 1; /* blender returns 0 */
+ break;
+ }
+ if (i == maxmoves || end == 1) break;
+ }
+
+ /* clear */
+ if(lasso) draw_lasso_select(mcords, i, 1);
+ else for(a=1; a<i; a++) {
+ sdrawXORline(mcords[a-1][0], mcords[a-1][1], mcords[a][0], mcords[a][1]);
+ }
+
+ persp(PERSP_VIEW);
+ glDrawBuffer(GL_BACK);
+
+ if (i > 2) {
+ if(lasso) do_lasso_select(mcords, i, (G.qual & LR_SHIFTKEY)==0);
+ else {
+ i = interpret_move(mcords, i);
+
+ if(i) {
+ if(curarea->spacetype==SPACE_IPO) transform_ipo(i);
+ else if(curarea->spacetype==SPACE_OOPS) transform_oops('g', 0);
+ else {
+ int context;
+
+ if(curarea->spacetype==SPACE_IMAGE) context= CTX_NONE;
+ else context= CTX_NONE;
+
+ if(i=='g') {
+ initTransform(TFM_TRANSLATION, context);
+ Transform();
+ }
+ else if(i=='r') {
+ initTransform(TFM_ROTATION, context);
+ Transform();
+ }
+ else {
+ initTransform(TFM_RESIZE, context);
+ Transform();
+ }
+ }
+ }
+ }
+ return 1;
+ }
+ return 0;
+}
+
+void mouse_cursor(void)
+{
+ float dx, dy, fz, *fp = NULL, dvec[3], oldcurs[3];
+ short mval[2], mx, my, lr_click=0;
+
+ if(gesture()) return;
+
+ getmouseco_areawin(mval);
+
+ mx= mval[0];
+ my= mval[1];
+
+ fp= give_cursor();
+
+ if(G.obedit && ((G.qual & LR_CTRLKEY) || get_mbut()&R_MOUSE )) lr_click= 1;
+ VECCOPY(oldcurs, fp);
+
+ project_short_noclip(fp, mval);
+
+ initgrabz(fp[0], fp[1], fp[2]);
+
+ if(mval[0]!=IS_CLIPPED) {
+
+ window_to_3d(dvec, mval[0]-mx, mval[1]-my);
+ VecSubf(fp, fp, dvec);
+
+ }
+ else {
+
+ dx= ((float)(mx-(curarea->winx/2)))*G.vd->zfac/(curarea->winx/2);
+ dy= ((float)(my-(curarea->winy/2)))*G.vd->zfac/(curarea->winy/2);
+
+ fz= G.vd->persmat[0][3]*fp[0]+ G.vd->persmat[1][3]*fp[1]+ G.vd->persmat[2][3]*fp[2]+ G.vd->persmat[3][3];
+ fz= fz/G.vd->zfac;
+
+ fp[0]= (G.vd->persinv[0][0]*dx + G.vd->persinv[1][0]*dy+ G.vd->persinv[2][0]*fz)-G.vd->ofs[0];
+ fp[1]= (G.vd->persinv[0][1]*dx + G.vd->persinv[1][1]*dy+ G.vd->persinv[2][1]*fz)-G.vd->ofs[1];
+ fp[2]= (G.vd->persinv[0][2]*dx + G.vd->persinv[1][2]*dy+ G.vd->persinv[2][2]*fz)-G.vd->ofs[2];
+ }
+
+ allqueue(REDRAWVIEW3D, 1);
+
+ if(lr_click) {
+ if(G.obedit->type==OB_MESH) add_click_mesh();
+ else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) addvert_Nurb(0);
+ else if (G.obedit->type==OB_ARMATURE) addvert_armature();
+ VECCOPY(fp, oldcurs);
+ }
+
+}
+
+void deselectall(void) /* is toggle */
+{
+ Base *base;
+ int a=0, ok=0;
+
+ base= FIRSTBASE;
+ while(base) {
+ /* is there a visible selected object */
+ if(base->lay & G.vd->lay &&
+ (base->object->restrictflag & OB_RESTRICT_VIEW)==0 &&
+ (base->object->restrictflag & OB_RESTRICT_SELECT)==0
+ ) {
+ if (base->flag & SELECT) {
+ ok= a= 1;
+ break;
+ } else {
+ ok=1;
+ }
+ }
+ base= base->next;
+ }
+
+ if (!ok) return;
+
+ base= FIRSTBASE;
+ while(base) {
+ if(base->lay & G.vd->lay &&
+ (base->object->restrictflag & OB_RESTRICT_VIEW)==0 &&
+ (base->object->restrictflag & OB_RESTRICT_SELECT)==0
+ ) {
+ if(a)
+ select_base_v3d(base, BA_DESELECT);
+ else
+ select_base_v3d(base, BA_SELECT);
+ base->object->flag= base->flag;
+ }
+ base= base->next;
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWDATASELECT, 0);
+ allqueue(REDRAWNLA, 0);
+
+ countall();
+ BIF_undo_push("(De)select all");
+}
+
+/* inverts object selection */
+void selectswap(void)
+{
+ Base *base;
+
+ for(base= FIRSTBASE; base; base= base->next) {
+ if(base->lay & G.vd->lay &&
+ (base->object->restrictflag & OB_RESTRICT_VIEW)==0
+ ) {
+ if TESTBASE(base)
+ select_base_v3d(base, BA_DESELECT);
+ else
+ select_base_v3d(base, BA_SELECT);
+ base->object->flag= base->flag;
+ }
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWDATASELECT, 0);
+ allqueue(REDRAWNLA, 0);
+
+ countall();
+ BIF_undo_push("Select Inverse");
+}
+
+
+/* selects all objects of a particular type, on currently visible layers */
+void selectall_type(short obtype)
+{
+ Base *base;
+
+ base= FIRSTBASE;
+ while(base) {
+ if((base->lay & G.vd->lay) &&
+ (base->object->type == obtype) &&
+ (base->object->restrictflag & OB_RESTRICT_VIEW)==0
+ ) {
+ select_base_v3d(base, BA_SELECT);
+ base->object->flag= base->flag;
+ }
+ base= base->next;
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWDATASELECT, 0);
+ allqueue(REDRAWNLA, 0);
+
+ countall();
+ BIF_undo_push("Select all per type");
+}
+/* selects all objects on a particular layer */
+void selectall_layer(unsigned int layernum)
+{
+ Base *base;
+
+ base= FIRSTBASE;
+ while(base) {
+ if(base->lay == (1<< (layernum -1)) &&
+ (base->object->restrictflag & OB_RESTRICT_VIEW)==0
+ ) {
+ select_base_v3d(base, BA_SELECT);
+ base->object->flag= base->flag;
+ }
+ base= base->next;
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWDATASELECT, 0);
+ allqueue(REDRAWNLA, 0);
+
+ countall();
+ BIF_undo_push("Select all per layer");
+}
+
+static void deselectall_except(Base *b) /* deselect all except b */
+{
+ Base *base;
+
+ base= FIRSTBASE;
+ while(base) {
+ if (base->flag & SELECT) {
+ if(b!=base) {
+ select_base_v3d(base, BA_DESELECT);
+ base->object->flag= base->flag;
+ }
+ }
+ base= base->next;
+ }
+}
+
+#if 0
+/* smart function to sample a rect spiralling outside, nice for backbuf selection */
+static unsigned int samplerect(unsigned int *buf, int size, unsigned int dontdo)
+{
+ Base *base;
+ unsigned int *bufmin,*bufmax;
+ int a,b,rc,tel,aantal,dirvec[4][2],maxob;
+ unsigned int retval=0;
+
+ base= LASTBASE;
+ if(base==0) return 0;
+ maxob= base->selcol;
+
+ aantal= (size-1)/2;
+ rc= 0;
+
+ dirvec[0][0]= 1;
+ dirvec[0][1]= 0;
+ dirvec[1][0]= 0;
+ dirvec[1][1]= -size;
+ dirvec[2][0]= -1;
+ dirvec[2][1]= 0;
+ dirvec[3][0]= 0;
+ dirvec[3][1]= size;
+
+ bufmin= buf;
+ bufmax= buf+ size*size;
+ buf+= aantal*size+ aantal;
+
+ for(tel=1;tel<=size;tel++) {
+
+ for(a=0;a<2;a++) {
+ for(b=0;b<tel;b++) {
+
+ if(*buf && *buf<=maxob && *buf!=dontdo) return *buf;
+ if( *buf==dontdo ) retval= dontdo; /* if only color dontdo is available, still return dontdo */
+
+ buf+= (dirvec[rc][0]+dirvec[rc][1]);
+
+ if(buf<bufmin || buf>=bufmax) return retval;
+ }
+ rc++;
+ rc &= 3;
+ }
+ }
+ return retval;
+}
+#endif
+
+void set_active_base(Base *base)
+{
+ Base *tbase;
+
+ /* activating a non-mesh, should end a couple of modes... */
+ if(base) {
+ if(base->object->type!=OB_MESH) {
+ if(G.f & G_SCULPTMODE)
+ set_sculptmode(); /* toggle */
+ if(G.f & G_WEIGHTPAINT)
+ set_wpaint(); /* toggle */
+ if(G.f & G_VERTEXPAINT)
+ set_vpaint(); /* toggle */
+ if(G.f & G_TEXTUREPAINT)
+ set_texturepaint(); /* Switch off tex paint */
+ }
+ }
+
+ /* sets scene->basact */
+ BASACT= base;
+
+ if(base) {
+
+ /* signals to buttons */
+ redraw_test_buttons(base->object);
+
+ /* signal to ipo */
+ allqueue(REDRAWIPO, base->object->ipowin);
+
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWNLA, 0);
+ allqueue(REDRAWNODE, 0);
+
+ /* signal to action */
+ select_actionchannel_by_name(base->object->action, "Object", 1);
+
+ /* disable temporal locks */
+ for(tbase=FIRSTBASE; tbase; tbase= tbase->next) {
+ if(base!=tbase && (tbase->object->shapeflag & OB_SHAPE_TEMPLOCK)) {
+ tbase->object->shapeflag &= ~OB_SHAPE_TEMPLOCK;
+ DAG_object_flush_update(G.scene, tbase->object, OB_RECALC_DATA);
+ }
+ }
+ }
+}
+
+void set_active_object(Object *ob)
+{
+ Base *base;
+
+ for(base= FIRSTBASE; base; base= base->next) {
+ if(base->object==ob) {
+ set_active_base(base);
+ return;
+ }
+ }
+}
+
+static void select_all_from_groups(Base *basact)
+{
+ Group *group;
+ GroupObject *go;
+ int deselect= basact->flag & SELECT;
+
+ for(group= G.main->group.first; group; group= group->id.next) {
+ if(object_in_group(basact->object, group)) {
+ for(go= group->gobject.first; go; go= go->next) {
+ if(deselect) go->ob->flag &= ~SELECT;
+ else {
+ if ((go->ob->restrictflag & OB_RESTRICT_SELECT)==0 &&
+ (go->ob->restrictflag & OB_RESTRICT_VIEW)==0)
+ go->ob->flag |= SELECT;
+ }
+ }
+ }
+ }
+ /* sync bases */
+ for(basact= G.scene->base.first; basact; basact= basact->next) {
+ if(basact->object->flag & SELECT)
+ select_base_v3d(basact, BA_SELECT);
+ else
+ select_base_v3d(basact, BA_DESELECT);
+ }
+}
+
+/* The max number of menu items in an object select menu */
+#define SEL_MENU_SIZE 22
+
+static Base *mouse_select_menu(unsigned int *buffer, int hits, short *mval)
+{
+ Base *baseList[SEL_MENU_SIZE]={NULL}; /*baseList is used to store all possible bases to bring up a menu */
+ Base *base;
+ short baseCount = 0;
+ char menuText[20 + SEL_MENU_SIZE*32] = "Select Object%t"; /* max ob name = 22 */
+ char str[32];
+
+ for(base=FIRSTBASE; base; base= base->next) {
+ if BASE_SELECTABLE(base) {
+ baseList[baseCount] = NULL;
+
+ /* two selection methods, the CTRL select uses max dist of 15 */
+ if(buffer) {
+ int a;
+ for(a=0; a<hits; a++) {
+ /* index was converted */
+ if(base->selcol==buffer[ (4 * a) + 3 ]) baseList[baseCount] = base;
+ }
+ }
+ else {
+ int temp, dist=15;
+
+ project_short(base->object->obmat[3], &base->sx);
+
+ temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
+ if(temp<dist ) baseList[baseCount] = base;
+ }
+
+ if(baseList[baseCount]) {
+ if (baseCount < SEL_MENU_SIZE) {
+ baseList[baseCount] = base;
+ sprintf(str, "|%s %%x%d", base->object->id.name+2, baseCount+1); /* max ob name == 22 */
+ strcat(menuText, str);
+ baseCount++;
+ }
+ }
+ }
+ }
+
+ if(baseCount<=1) return baseList[0];
+ else {
+ baseCount = pupmenu(menuText);
+
+ if (baseCount != -1) { /* If nothing is selected then dont do anything */
+ return baseList[baseCount-1];
+ }
+ else return NULL;
+ }
+}
+
+/* we want a select buffer with bones, if there are... */
+/* so check three selection levels and compare */
+static short mixed_bones_object_selectbuffer(unsigned int *buffer, short *mval)
+{
+ int offs;
+ short a, hits15, hits9=0, hits5=0;
+ short has_bones15=0, has_bones9=0, has_bones5=0;
+
+ hits15= view3d_opengl_select(buffer, MAXPICKBUF, mval[0]-14, mval[1]-14, mval[0]+14, mval[1]+14);
+ if(hits15>0) {
+ for(a=0; a<hits15; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones15= 1;
+
+ offs= 4*hits15;
+ hits9= view3d_opengl_select(buffer+offs, MAXPICKBUF-offs, mval[0]-9, mval[1]-9, mval[0]+9, mval[1]+9);
+ if(hits9>0) {
+ for(a=0; a<hits9; a++) if(buffer[offs+4*a+3] & 0xFFFF0000) has_bones9= 1;
+
+ offs+= 4*hits9;
+ hits5= view3d_opengl_select(buffer+offs, MAXPICKBUF-offs, mval[0]-5, mval[1]-5, mval[0]+5, mval[1]+5);
+ if(hits5>0) {
+ for(a=0; a<hits5; a++) if(buffer[offs+4*a+3] & 0xFFFF0000) has_bones5= 1;
+ }
+ }
+
+ if(has_bones5) {
+ offs= 4*hits15 + 4*hits9;
+ memcpy(buffer, buffer+offs, 4*offs);
+ return hits5;
+ }
+ if(has_bones9) {
+ offs= 4*hits15;
+ memcpy(buffer, buffer+offs, 4*offs);
+ return hits9;
+ }
+ if(has_bones15) {
+ return hits15;
+ }
+
+ if(hits5>0) {
+ offs= 4*hits15 + 4*hits9;
+ memcpy(buffer, buffer+offs, 4*offs);
+ return hits5;
+ }
+ if(hits9>0) {
+ offs= 4*hits15;
+ memcpy(buffer, buffer+offs, 4*offs);
+ return hits9;
+ }
+ return hits15;
+ }
+
+ return 0;
+}
+
+void mouse_select(void)
+{
+ Base *base, *startbase=NULL, *basact=NULL, *oldbasact=NULL;
+ unsigned int buffer[MAXPICKBUF];
+ int temp, a, dist=100;
+ short hits, mval[2];
+
+ /* always start list from basact in wire mode */
+ startbase= FIRSTBASE;
+ if(BASACT && BASACT->next) startbase= BASACT->next;
+
+ getmouseco_areawin(mval);
+
+ /* This block uses the control key to make the object selected by its center point rather then its contents */
+ if(G.obedit==0 && (G.qual & LR_CTRLKEY)) {
+
+ /* note; shift+alt goes to group-flush-selecting */
+ if(G.qual == (LR_ALTKEY|LR_CTRLKEY))
+ basact= mouse_select_menu(NULL, 0, mval);
+ else {
+ base= startbase;
+ while(base) {
+ if BASE_SELECTABLE(base) {
+ project_short(base->object->obmat[3], &base->sx);
+
+ temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
+ if(base==BASACT) temp+=10;
+ if(temp<dist ) {
+
+ dist= temp;
+ basact= base;
+ }
+ }
+ base= base->next;
+
+ if(base==0) base= FIRSTBASE;
+ if(base==startbase) break;
+ }
+ }
+ }
+ else {
+ /* if objects have posemode set, the bones are in the same selection buffer */
+
+ hits= mixed_bones_object_selectbuffer(buffer, mval);
+
+ if(hits>0) {
+ int has_bones= 0;
+
+ for(a=0; a<hits; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones= 1;
+
+ /* note; shift+alt goes to group-flush-selecting */
+ if(has_bones==0 && (G.qual == LR_ALTKEY))
+ basact= mouse_select_menu(buffer, hits, mval);
+ else {
+ static short lastmval[2]={-100, -100};
+ int donearest= 0;
+
+ /* define if we use solid nearest select or not */
+ if(G.vd->drawtype>OB_WIRE) {
+ donearest= 1;
+ if( ABS(mval[0]-lastmval[0])<3 && ABS(mval[1]-lastmval[1])<3) {
+ if(!has_bones) /* hrms, if theres bones we always do nearest */
+ donearest= 0;
+ }
+ }
+ lastmval[0]= mval[0]; lastmval[1]= mval[1];
+
+ if(donearest) {
+ unsigned int min= 0xFFFFFFFF;
+ int selcol= 0, notcol=0;
+
+
+ if(has_bones) {
+ /* we skip non-bone hits */
+ for(a=0; a<hits; a++) {
+ if( min > buffer[4*a+1] && (buffer[4*a+3] & 0xFFFF0000) ) {
+ min= buffer[4*a+1];
+ selcol= buffer[4*a+3] & 0xFFFF;
+ }
+ }
+ }
+ else {
+ /* only exclude active object when it is selected... */
+ if(BASACT && (BASACT->flag & SELECT) && hits>1) notcol= BASACT->selcol;
+
+ for(a=0; a<hits; a++) {
+ if( min > buffer[4*a+1] && notcol!=(buffer[4*a+3] & 0xFFFF)) {
+ min= buffer[4*a+1];
+ selcol= buffer[4*a+3] & 0xFFFF;
+ }
+ }
+ }
+
+ base= FIRSTBASE;
+ while(base) {
+ if(base->lay & G.vd->lay) {
+ if(base->selcol==selcol) break;
+ }
+ base= base->next;
+ }
+ if(base) basact= base;
+ }
+ else {
+
+ base= startbase;
+ while(base) {
+ /* skip objects with select restriction, to prevent prematurely ending this loop
+ * with an un-selectable choice */
+ if (base->object->restrictflag & OB_RESTRICT_SELECT) {
+ base=base->next;
+ if(base==NULL) base= FIRSTBASE;
+ if(base==startbase) break;
+ }
+
+ if(base->lay & G.vd->lay) {
+ for(a=0; a<hits; a++) {
+ if(has_bones) {
+ /* skip non-bone objects */
+ if((buffer[4*a+3] & 0xFFFF0000)) {
+ if(base->selcol== (buffer[(4*a)+3] & 0xFFFF))
+ basact= base;
+ }
+ }
+ else {
+ if(base->selcol== (buffer[(4*a)+3] & 0xFFFF))
+ basact= base;
+ }
+ }
+ }
+
+ if(basact) break;
+
+ base= base->next;
+ if(base==NULL) base= FIRSTBASE;
+ if(base==startbase) break;
+ }
+ }
+ }
+
+ if(has_bones && basact) {
+ if( do_pose_selectbuffer(basact, buffer, hits) ) { /* then bone is found */
+
+ /* we make the armature selected:
+ not-selected active object in posemode won't work well for tools */
+ basact->flag|= SELECT;
+ basact->object->flag= basact->flag;
+
+ /* in weightpaint, we use selected bone to select vertexgroup, so no switch to new active object */
+ if(G.f & G_WEIGHTPAINT) {
+ /* prevent activating */
+ basact= NULL;
+ }
+ }
+ /* prevent bone selecting to pass on to object selecting */
+ if(basact==BASACT)
+ basact= NULL;
+ }
+ }
+ }
+
+ /* so, do we have something selected? */
+ if(basact) {
+
+ if(G.obedit) {
+ /* only do select */
+ deselectall_except(basact);
+ select_base_v3d(basact, BA_SELECT);
+ }
+ /* also prevent making it active on mouse selection */
+ else if BASE_SELECTABLE(basact) {
+
+ oldbasact= BASACT;
+ BASACT= basact;
+
+ if((G.qual & LR_SHIFTKEY)==0) {
+ deselectall_except(basact);
+ select_base_v3d(basact, BA_SELECT);
+ }
+ else if(G.qual==(LR_SHIFTKEY|LR_ALTKEY)) {
+ select_all_from_groups(basact);
+ }
+ else {
+ if(basact->flag & SELECT) {
+ if(basact==oldbasact)
+ select_base_v3d(basact, BA_DESELECT);
+ }
+ else select_base_v3d(basact, BA_SELECT);
+ }
+
+ /* copy */
+ basact->object->flag= basact->flag;
+
+ if(oldbasact != basact) {
+ set_active_base(basact);
+ }
+
+ /* for visual speed, only in wire mode */
+ if(G.vd->drawtype==OB_WIRE) {
+ /* however, not for posemodes */
+ if(basact->object->flag & OB_POSEMODE);
+ else if(oldbasact && (oldbasact->object->flag & OB_POSEMODE));
+ else {
+ if(oldbasact && oldbasact != basact && (oldbasact->lay & G.vd->lay))
+ draw_object_ext(oldbasact);
+ draw_object_ext(basact);
+ }
+ }
+
+ allqueue(REDRAWBUTSLOGIC, 0);
+ allqueue(REDRAWDATASELECT, 0);
+ allqueue(REDRAWBUTSOBJECT, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWNLA, 0);
+ allqueue(REDRAWTIME, 0);
+ allqueue(REDRAWHEADERS, 0); /* To force display update for the posebutton */
+ }
+ /* also because multiple 3d windows can be open */
+ allqueue(REDRAWVIEW3D, 0);
+
+ }
+
+ countall();
+
+ rightmouse_transform(); /* does undo push! */
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int edge_inside_circle(short centx, short centy, short rad, short x1, short y1, short x2, short y2)
+{
+ int radsq= rad*rad;
+ float v1[2], v2[2], v3[2];
+
+ /* check points in circle itself */
+ if( (x1-centx)*(x1-centx) + (y1-centy)*(y1-centy) <= radsq ) return 1;
+ if( (x2-centx)*(x2-centx) + (y2-centy)*(y2-centy) <= radsq ) return 1;
+
+ /* pointdistline */
+ v3[0]= centx;
+ v3[1]= centy;
+ v1[0]= x1;
+ v1[1]= y1;
+ v2[0]= x2;
+ v2[1]= y2;
+
+ if( PdistVL2Dfl(v3, v1, v2) < (float)rad ) return 1;
+
+ return 0;
+}
+
+static void do_nurbs_box_select__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
+{
+ struct { rcti *rect; int select; } *data = userData;
+
+ if (BLI_in_rcti(data->rect, x, y)) {
+ if (bp) {
+ bp->f1 = data->select?(bp->f1|1):(bp->f1&~1);
+ } else {
+ if (G.f & G_HIDDENHANDLES) {
+ /* can only be beztindex==0 here since handles are hidden */
+ bezt->f1 = bezt->f2 = bezt->f3 = data->select?(bezt->f1|1):(bezt->f1&~1);
+ } else {
+ if (beztindex==0) {
+ bezt->f1 = data->select?(bezt->f1|1):(bezt->f1&~1);
+ } else if (beztindex==1) {
+ bezt->f2 = data->select?(bezt->f2|1):(bezt->f2&~1);
+ } else {
+ bezt->f3 = data->select?(bezt->f3|1):(bezt->f3&~1);
+ }
+ }
+ }
+ }
+}
+static void do_nurbs_box_select(rcti *rect, int select)
+{
+ struct { rcti *rect; int select; } data;
+
+ data.rect = rect;
+ data.select = select;
+
+ nurbs_foreachScreenVert(do_nurbs_box_select__doSelect, &data);
+}
+
+static void do_lattice_box_select__doSelect(void *userData, BPoint *bp, int x, int y)
+{
+ struct { rcti *rect; int select; } *data = userData;
+
+ if (BLI_in_rcti(data->rect, x, y)) {
+ bp->f1 = data->select?(bp->f1|1):(bp->f1&~1);
+ }
+}
+static void do_lattice_box_select(rcti *rect, int select)
+{
+ struct { rcti *rect; int select, pass, done; } data;
+
+ data.rect = rect;
+ data.select = select;
+
+ lattice_foreachScreenVert(do_lattice_box_select__doSelect, &data);
+}
+
+static void do_mesh_box_select__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
+{
+ struct { rcti *rect; short select, pass, done; } *data = userData;
+
+ if (BLI_in_rcti(data->rect, x, y)) {
+ eve->f = data->select?(eve->f|1):(eve->f&~1);
+ }
+}
+static void do_mesh_box_select__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
+{
+ struct { rcti *rect; short select, pass, done; } *data = userData;
+
+ if(EM_check_backbuf(em_solidoffs+index)) {
+ if (data->pass==0) {
+ if (edge_fully_inside_rect(data->rect, x0, y0, x1, y1)) {
+ EM_select_edge(eed, data->select);
+ data->done = 1;
+ }
+ } else {
+ if (edge_inside_rect(data->rect, x0, y0, x1, y1)) {
+ EM_select_edge(eed, data->select);
+ }
+ }
+ }
+}
+static void do_mesh_box_select__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
+{
+ struct { rcti *rect; short select, pass, done; } *data = userData;
+
+ if (BLI_in_rcti(data->rect, x, y)) {
+ EM_select_face_fgon(efa, data->select);
+ }
+}
+static void do_mesh_box_select(rcti *rect, int select)
+{
+ struct { rcti *rect; short select, pass, done; } data;
+ EditMesh *em = G.editMesh;
+ int bbsel;
+
+ data.rect = rect;
+ data.select = select;
+ data.pass = 0;
+ data.done = 0;
+
+ bbsel= EM_init_backbuf_border(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
+
+ if(G.scene->selectmode & SCE_SELECT_VERTEX) {
+ if (bbsel) {
+ EM_backbuf_checkAndSelectVerts(em, select);
+ } else {
+ mesh_foreachScreenVert(do_mesh_box_select__doSelectVert, &data, 1);
+ }
+ }
+ if(G.scene->selectmode & SCE_SELECT_EDGE) {
+ /* Does both bbsel and non-bbsel versions (need screen cos for both) */
+
+ data.pass = 0;
+ mesh_foreachScreenEdge(do_mesh_box_select__doSelectEdge, &data, 0);
+
+ if (data.done==0) {
+ data.pass = 1;
+ mesh_foreachScreenEdge(do_mesh_box_select__doSelectEdge, &data, 0);
+ }
+ }
+
+ if(G.scene->selectmode & SCE_SELECT_FACE) {
+ if(bbsel) {
+ EM_backbuf_checkAndSelectFaces(em, select);
+ } else {
+ mesh_foreachScreenFace(do_mesh_box_select__doSelectFace, &data);
+ }
+ }
+
+ EM_free_backbuf();
+
+ EM_selectmode_flush();
+}
+
+/**
+ * Does the 'borderselect' command. (Select verts based on selecting with a
+ * border: key 'b'). All selecting seems to be done in the get_border part.
+ */
+void borderselect(void)
+{
+ rcti rect;
+ Base *base;
+ MetaElem *ml;
+ unsigned int buffer[MAXPICKBUF];
+ int a, index;
+ short hits, val;
+
+ if(G.obedit==NULL && (FACESEL_PAINT_TEST)) {
+ face_borderselect();
+ return;
+ }
+
+ a = 0;
+#ifdef __APPLE__
+ a = is_a_really_crappy_intel_card();
+#endif
+ if (!a) setlinestyle(2);
+ val= get_border(&rect, 3);
+ if (!a) setlinestyle(0);
+
+ if(val==0) {
+ if (EM_texFaceCheck())
+ allqueue(REDRAWIMAGE, 0);
+ return;
+ }
+
+ if(G.obedit) {
+ if(G.obedit->type==OB_MESH) {
+ do_mesh_box_select(&rect, (val==LEFTMOUSE));
+ allqueue(REDRAWVIEW3D, 0);
+ if (EM_texFaceCheck())
+ allqueue(REDRAWIMAGE, 0);
+
+ }
+ else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) {
+ do_nurbs_box_select(&rect, val==LEFTMOUSE);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ else if(G.obedit->type==OB_MBALL) {
+ hits= view3d_opengl_select(buffer, MAXPICKBUF, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
+
+ ml= editelems.first;
+
+ while(ml) {
+ for(a=0; a<hits; a++) {
+ if(ml->selcol1==buffer[ (4 * a) + 3 ]) {
+ ml->flag |= MB_SCALE_RAD;
+ if(val==LEFTMOUSE) ml->flag |= SELECT;
+ else ml->flag &= ~SELECT;
+ break;
+ }
+ if(ml->selcol2==buffer[ (4 * a) + 3 ]) {
+ ml->flag &= ~MB_SCALE_RAD;
+ if(val==LEFTMOUSE) ml->flag |= SELECT;
+ else ml->flag &= ~SELECT;
+ break;
+ }
+ }
+ ml= ml->next;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ else if(G.obedit->type==OB_ARMATURE) {
+ EditBone *ebone;
+
+ /* clear flag we use to detect point was affected */
+ for(ebone= G.edbo.first; ebone; ebone= ebone->next)
+ ebone->flag &= ~BONE_DONE;
+
+ hits= view3d_opengl_select(buffer, MAXPICKBUF, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
+
+ /* first we only check points inside the border */
+ for (a=0; a<hits; a++){
+ index = buffer[(4*a)+3];
+ if (index!=-1) {
+ ebone = BLI_findlink(&G.edbo, index & ~(BONESEL_ANY));
+ if (index & BONESEL_TIP) {
+ ebone->flag |= BONE_DONE;
+ if (val==LEFTMOUSE) ebone->flag |= BONE_TIPSEL;
+ else ebone->flag &= ~BONE_TIPSEL;
+ }
+
+ if (index & BONESEL_ROOT) {
+ ebone->flag |= BONE_DONE;
+ if (val==LEFTMOUSE) ebone->flag |= BONE_ROOTSEL;
+ else ebone->flag &= ~BONE_ROOTSEL;
+ }
+ }
+ }
+
+ /* now we have to flush tag from parents... */
+ for(ebone= G.edbo.first; ebone; ebone= ebone->next) {
+ if(ebone->parent && (ebone->flag & BONE_CONNECTED)) {
+ if(ebone->parent->flag & BONE_DONE)
+ ebone->flag |= BONE_DONE;
+ }
+ }
+
+ /* only select/deselect entire bones when no points where in the rect */
+ for (a=0; a<hits; a++){
+ index = buffer[(4*a)+3];
+ if (index!=-1) {
+ ebone = BLI_findlink(&G.edbo, index & ~(BONESEL_ANY));
+ if (index & BONESEL_BONE) {
+ if(!(ebone->flag & BONE_DONE)) {
+ if (val==LEFTMOUSE)
+ ebone->flag |= (BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
+ else
+ ebone->flag &= ~(BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
+ }
+ }
+ }
+ }
+
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWBUTSOBJECT, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ else if(G.obedit->type==OB_LATTICE) {
+ do_lattice_box_select(&rect, val==LEFTMOUSE);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ }
+ else { /* no editmode, unified for bones and objects */
+ Bone *bone;
+ unsigned int *vbuffer=NULL; /* selection buffer */
+ unsigned int *col; /* color in buffer */
+ short selecting = 0;
+ Object *ob= OBACT;
+ int bone_only;
+
+ if((ob) && (ob->flag & OB_POSEMODE))
+ bone_only= 1;
+ else
+ bone_only= 0;
+
+ if (val==LEFTMOUSE)
+ selecting = 1;
+
+ /* selection buffer now has bones potentially too, so we add MAXPICKBUF */
+ vbuffer = MEM_mallocN(4 * (G.totobj+MAXPICKBUF) * sizeof(unsigned int), "selection buffer");
+ hits= view3d_opengl_select(vbuffer, 4*(G.totobj+MAXPICKBUF), rect.xmin, rect.ymin, rect.xmax, rect.ymax);
+ /*
+ LOGIC NOTES (theeth):
+ The buffer and ListBase have the same relative order, which makes the selection
+ very simple. Loop through both data sets at the same time, if the color
+ is the same as the object, we have a hit and can move to the next color
+ and object pair, if not, just move to the next object,
+ keeping the same color until we have a hit.
+
+ The buffer order is defined by OGL standard, hopefully no stupid GFX card
+ does it incorrectly.
+ */
+
+ if (hits>0) { /* no need to loop if there's no hit */
+ base= FIRSTBASE;
+ col = vbuffer + 3;
+ while(base && hits) {
+ Base *next = base->next;
+ if(base->lay & G.vd->lay) {
+ while (base->selcol == (*col & 0xFFFF)) { /* we got an object */
+
+ if(*col & 0xFFFF0000) { /* we got a bone */
+ bone = get_indexed_bone(base->object, *col & ~(BONESEL_ANY));
+ if(bone) {
+ if(selecting) {
+ bone->flag |= BONE_SELECTED;
+ select_actionchannel_by_name(base->object->action, bone->name, 1);
+ }
+ else {
+ bone->flag &= ~(BONE_ACTIVE|BONE_SELECTED);
+ select_actionchannel_by_name(base->object->action, bone->name, 0);
+ }
+ }
+ }
+ else if(!bone_only) {
+ if (selecting)
+ select_base_v3d(base, BA_SELECT);
+ else
+ select_base_v3d(base, BA_DESELECT);
+
+ base->object->flag= base->flag;
+ }
+
+ col+=4; /* next color */
+ hits--;
+ if(hits==0) break;
+ }
+ }
+
+ base= next;
+ }
+ }
+ /* frontbuffer flush */
+ bglFlush();
+
+ MEM_freeN(vbuffer);
+
+ allqueue(REDRAWDATASELECT, 0);
+ allqueue(REDRAWBUTSLOGIC, 0);
+ allqueue(REDRAWNLA, 0);
+ }
+
+ countall();
+
+ allqueue(REDRAWBUTSOBJECT, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWINFO, 0);
+
+ BIF_undo_push("Border select");
+
+} /* end of borderselect() */
+
+/* ------------------------------------------------------------------------- */
+
+/** The following functions are quick & dirty callback functions called
+ * on the Circle select function (press B twice in Editmode)
+ * They were torn out of the circle_select to make the latter more reusable
+ * The callback version of circle_select (called circle_selectCB) was moved
+ * to edit.c because of it's (wanted) generality.
+
+ XXX These callback functions are still dirty, because they call globals...
+ */
+
+static void mesh_selectionCB__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
+{
+ struct { short select, mval[2]; float radius; } *data = userData;
+ int mx = x - data->mval[0], my = y - data->mval[1];
+ float r = sqrt(mx*mx + my*my);
+
+ if (r<=data->radius) {
+ eve->f = data->select?(eve->f|1):(eve->f&~1);
+ }
+}
+static void mesh_selectionCB__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
+{
+ struct { short select, mval[2]; float radius; } *data = userData;
+
+ if (edge_inside_circle(data->mval[0], data->mval[1], (short) data->radius, x0, y0, x1, y1)) {
+ EM_select_edge(eed, data->select);
+ }
+}
+static void mesh_selectionCB__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
+{
+ struct { short select, mval[2]; float radius; } *data = userData;
+ int mx = x - data->mval[0], my = y - data->mval[1];
+ float r = sqrt(mx*mx + my*my);
+
+ if (r<=data->radius) {
+ EM_select_face_fgon(efa, data->select);
+ }
+}
+static void mesh_selectionCB(int selecting, Object *editobj, short *mval, float rad)
+{
+ struct { short select, mval[2]; float radius; } data;
+ EditMesh *em = G.editMesh;
+ int bbsel;
+
+ if(!G.obedit && (FACESEL_PAINT_TEST)) {
+ Mesh *me = get_mesh(OBACT);
+
+ if (me) {
+ em_vertoffs= me->totface+1; /* max index array */
+
+ bbsel= EM_init_backbuf_circle(mval[0], mval[1], (short)(rad+1.0));
+ EM_backbuf_checkAndSelectTFaces(me, selecting==LEFTMOUSE);
+ EM_free_backbuf();
+
+ object_tface_flags_changed(OBACT, 0);
+ }
+
+ return;
+ }
+
+ bbsel= EM_init_backbuf_circle(mval[0], mval[1], (short)(rad+1.0));
+
+ data.select = (selecting==LEFTMOUSE);
+ data.mval[0] = mval[0];
+ data.mval[1] = mval[1];
+ data.radius = rad;
+
+ if(G.scene->selectmode & SCE_SELECT_VERTEX) {
+ if(bbsel) {
+ EM_backbuf_checkAndSelectVerts(em, selecting==LEFTMOUSE);
+ } else {
+ mesh_foreachScreenVert(mesh_selectionCB__doSelectVert, &data, 1);
+ }
+ }
+
+ if(G.scene->selectmode & SCE_SELECT_EDGE) {
+ if (bbsel) {
+ EM_backbuf_checkAndSelectEdges(em, selecting==LEFTMOUSE);
+ } else {
+ mesh_foreachScreenEdge(mesh_selectionCB__doSelectEdge, &data, 0);
+ }
+ }
+
+ if(G.scene->selectmode & SCE_SELECT_FACE) {
+ if(bbsel) {
+ EM_backbuf_checkAndSelectFaces(em, selecting==LEFTMOUSE);
+ } else {
+ mesh_foreachScreenFace(mesh_selectionCB__doSelectFace, &data);
+ }
+ }
+
+ EM_free_backbuf();
+ EM_selectmode_flush();
+}
+
+
+static void nurbscurve_selectionCB__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
+{
+ struct { short select, mval[2]; float radius; } *data = userData;
+ int mx = x - data->mval[0], my = y - data->mval[1];
+ float r = sqrt(mx*mx + my*my);
+
+ if (r<=data->radius) {
+ if (bp) {
+ bp->f1 = data->select?(bp->f1|1):(bp->f1&~1);
+ } else {
+ if (beztindex==0) {
+ bezt->f1 = data->select?(bezt->f1|1):(bezt->f1&~1);
+ } else if (beztindex==1) {
+ bezt->f2 = data->select?(bezt->f2|1):(bezt->f2&~1);
+ } else {
+ bezt->f3 = data->select?(bezt->f3|1):(bezt->f3&~1);
+ }
+ }
+ }
+}
+static void nurbscurve_selectionCB(int selecting, Object *editobj, short *mval, float rad)
+{
+ struct { short select, mval[2]; float radius; } data;
+
+ data.select = (selecting==LEFTMOUSE);
+ data.mval[0] = mval[0];
+ data.mval[1] = mval[1];
+ data.radius = rad;
+
+ nurbs_foreachScreenVert(nurbscurve_selectionCB__doSelect, &data);
+}
+
+
+static void latticecurve_selectionCB__doSelect(void *userData, BPoint *bp, int x, int y)
+{
+ struct { short select, mval[2]; float radius; } *data = userData;
+ int mx = x - data->mval[0], my = y - data->mval[1];
+ float r = sqrt(mx*mx + my*my);
+
+ if (r<=data->radius) {
+ bp->f1 = data->select?(bp->f1|1):(bp->f1&~1);
+ }
+}
+static void lattice_selectionCB(int selecting, Object *editobj, short *mval, float rad)
+{
+ struct { short select, mval[2]; float radius; } data;
+
+ data.select = (selecting==LEFTMOUSE);
+ data.mval[0] = mval[0];
+ data.mval[1] = mval[1];
+ data.radius = rad;
+
+ lattice_foreachScreenVert(latticecurve_selectionCB__doSelect, &data);
+}
+
+/** Callbacks for selection in Editmode */
+
+void obedit_selectionCB(short selecting, Object *editobj, short *mval, float rad)
+{
+ switch(editobj->type) {
+ case OB_MESH:
+ mesh_selectionCB(selecting, editobj, mval, rad);
+ break;
+ case OB_CURVE:
+ case OB_SURF:
+ nurbscurve_selectionCB(selecting, editobj, mval, rad);
+ break;
+ case OB_LATTICE:
+ lattice_selectionCB(selecting, editobj, mval, rad);
+ break;
+ default:
+ return;
+ }
+
+ draw_sel_circle(0, 0, 0, 0, 0); /* signal */
+ force_draw(0);
+}
+
+void set_render_border(void)
+{
+ rcti rect;
+ short val;
+
+ val= get_border(&rect, 3);
+ if(val) {
+ rctf vb;
+
+ calc_viewborder(G.vd, &vb);
+
+ G.scene->r.border.xmin= ((float)rect.xmin-vb.xmin)/(vb.xmax-vb.xmin);
+ G.scene->r.border.ymin= ((float)rect.ymin-vb.ymin)/(vb.ymax-vb.ymin);
+ G.scene->r.border.xmax= ((float)rect.xmax-vb.xmin)/(vb.xmax-vb.xmin);
+ G.scene->r.border.ymax= ((float)rect.ymax-vb.ymin)/(vb.ymax-vb.ymin);
+
+ CLAMP(G.scene->r.border.xmin, 0.0, 1.0);
+ CLAMP(G.scene->r.border.ymin, 0.0, 1.0);
+ CLAMP(G.scene->r.border.xmax, 0.0, 1.0);
+ CLAMP(G.scene->r.border.ymax, 0.0, 1.0);
+
+ allqueue(REDRAWVIEWCAM, 1);
+
+ /* drawing a border surrounding the entire camera view switches off border rendering */
+ if (G.scene->r.border.xmin <= 0.0 && G.scene->r.border.xmax >= 1.0 &&
+ G.scene->r.border.ymin <= 0.0 && G.scene->r.border.ymax >= 1.0)
+ {
+ G.scene->r.mode &= ~R_BORDER;
+ } else {
+ G.scene->r.mode |= R_BORDER;
+ }
+
+ allqueue(REDRAWBUTSSCENE, 1);
+ }
+}
+
+void view3d_border_zoom(void)
+{
+ /* Zooms in on a border drawn by the user */
+ rcti rect;
+ short val;
+ float dvec[3], vb[2], xscale, yscale, scale;
+
+ /* SMOOTHVIEW */
+ float new_dist;
+ float new_ofs[3];
+
+ /* doesn't work fine for perspective */
+ if(G.vd->persp==1)
+ return;
+
+ val = get_border(&rect, 3); //box select input
+ if(val)
+ {
+ /* find the current window width and height */
+ vb[0] = G.vd->area->winx;
+ vb[1] = G.vd->area->winy;
+
+ new_dist = G.vd->dist;
+ new_ofs[0] = G.vd->ofs[0];
+ new_ofs[1] = G.vd->ofs[1];
+ new_ofs[2] = G.vd->ofs[2];
+
+ /* convert the drawn rectangle into 3d space */
+ initgrabz(-new_ofs[0], -new_ofs[1], -new_ofs[2]);
+
+ window_to_3d(dvec, (rect.xmin+rect.xmax-vb[0])/2, (rect.ymin+rect.ymax-vb[1])/2);
+
+ /* center the view to the center of the rectangle */
+ VecSubf(new_ofs, new_ofs, dvec);
+
+ /* work out the ratios, so that everything selected fits when we zoom */
+ xscale = ((rect.xmax-rect.xmin)/vb[0]);
+ yscale = ((rect.ymax-rect.ymin)/vb[1]);
+ scale = (xscale >= yscale)?xscale:yscale;
+
+ /* zoom in as required, or as far as we can go */
+ new_dist = ((new_dist*scale) >= 0.001*G.vd->grid)? new_dist*scale:0.001*G.vd->grid;
+
+ smooth_view(G.vd, new_ofs, NULL, &new_dist, NULL);
+
+ }
+}
+
+void fly(void)
+{
+ /*
+ fly mode - Shift+F
+ a fly loop where the user can move move the view as if they are flying
+ */
+ float speed=0.0, /* the speed the view is moving per redraw */
+ mat[3][3], /* 3x3 copy of the view matrix so we can move allong the view axis */
+ dvec[3]={0,0,0}, /* this is the direction thast added to the view offset per redraw */
+ dvec_old[3]={0,0,0}, /* old for some lag */
+ dvec_tmp[3]={0,0,0}, /* old for some lag */
+ dvec_lag=0.0, /* old for some lag */
+
+ /* Camera Uprighting variables */
+ roll, /* similar to the angle between the camera's up and the Z-up, but its very rough so just roll*/
+ upvec[3]={0,0,0}, /* stores the view's up vector */
+
+ dist_backup, /* backup the views distance since we use a zero dist for fly mode */
+ rot_backup[4], /* backup the views quat incase the user cancels flying in non camera mode */
+ ofs_backup[3], /* backup the views offset incase the user cancels flying in non camera mode */
+ moffset[2], /* mouse offset from the views center */
+ tmp_quat[4], /* used for rotating the view */
+ winxf, winyf, /* scale the mouse movement by this value - scales mouse movement to the view size */
+ time_redraw, time_redraw_clamped, time_wheel; /*time how fast it takes for us to redraw, this is so simple scenes dont fly too fast */
+
+ /* time_lastwheel is used to accelerate when using the mousewheel a lot */
+ double time_current, time_lastdraw, time_currwheel, time_lastwheel;
+
+ short val, /* used for toets to see if a buttons pressed */
+ cent_orig[2], /* view center */
+ cent[2], /* view center modified */
+ mval[2], /* mouse location */
+ action=0, /* while zero stay in fly mode and wait for action, also used to see if we accepted or canceled 1:ok 2:Cancel */
+ xmargin, ymargin; /* x and y margin are define the safe area where the mouses movement wont rotate the view */
+ unsigned short
+ toets; /* for reading the event */
+ unsigned char
+ apply_rotation= 1, /* if the user presses shift they can look about without movinf the direction there looking*/
+ axis= 2, /* Axis index to move allong by default Z to move allong the view */
+ persp_backup, /* remember if were ortho or not, only used for restoring the view if it was a ortho view */
+ pan_view=0; /* if true, pan the view instead of rotating */
+
+ /* relative view axis locking - xlock, zlock
+ 0; disabled
+ 1; enabled but not checking because mouse hasnt moved outside the margin since locking was checked an not needed
+ when the mouse moves, locking is set to 2 so checks are done.
+ 2; mouse moved and checking needed, if no view altering is donem its changed back to 1 */
+ short xlock=0, zlock=0;
+ float xlock_momentum=0.0f, zlock_momentum=0.0f; /* nicer dynamics */
+
+ /* for recording */
+ int playing_anim = has_screenhandler(G.curscreen, SCREEN_HANDLER_ANIM);
+ int cfra = -1; /*so the first frame always has a key added */
+ char *actname="";
+
+ if(curarea->spacetype!=SPACE_VIEW3D) return;
+
+ if(G.vd->persp==2 && G.vd->camera->id.lib) {
+ error("Cannot fly a camera from an external library");
+ return;
+ }
+
+ if(G.vd->ob_centre) {
+ error("Cannot fly when the view is locked to an object");
+ return;
+ }
+
+
+ /* detect weather to start with Z locking */
+ upvec[0]=1; upvec[1]=0; upvec[2]=0;
+ Mat3CpyMat4(mat, G.vd->viewinv);
+ Mat3MulVecfl(mat, upvec);
+ if (fabs(upvec[2]) < 0.1)
+ zlock = 1;
+ upvec[0]=0; upvec[1]=0; upvec[2]=0;
+
+ persp_backup= G.vd->persp;
+ dist_backup= G.vd->dist;
+ if (G.vd->persp==2) { /* Camera */
+ if(G.vd->camera->constraints.first) {
+ error("Cannot fly an object with constraints");
+ return;
+ }
+
+ /* store the origoinal camera loc and rot */
+ VECCOPY(ofs_backup, G.vd->camera->loc);
+ VECCOPY(rot_backup, G.vd->camera->rot);
+
+ where_is_object(G.vd->camera);
+ VECCOPY(G.vd->ofs, G.vd->camera->obmat[3]);
+ VecMulf(G.vd->ofs, -1.0f); /*flip the vector*/
+
+ G.vd->dist=0.0;
+ G.vd->viewbut=0;
+
+ /* used for recording */
+ if(G.vd->camera->ipoflag & OB_ACTION_OB)
+ actname= "Object";
+
+ } else {
+ /* perspective or ortho */
+ if (G.vd->persp==0)
+ G.vd->persp= 1; /*if ortho projection, make perspective */
+ QUATCOPY(rot_backup, G.vd->viewquat);
+ VECCOPY(ofs_backup, G.vd->ofs);
+ G.vd->dist= 0.0;
+
+ upvec[2]=dist_backup; /*x and y are 0*/
+ Mat3MulVecfl(mat, upvec);
+ VecSubf(G.vd->ofs, G.vd->ofs, upvec);
+ /*Done with correcting for the dist*/
+ }
+
+ /* the dist defines a vector that is infront of the offset
+ to rotate the view about.
+ this is no good for fly mode because we
+ want to rotate about the viewers center.
+ but to correct the dist removal we must
+ alter offset so the view dosent jump. */
+
+ xmargin= (short)((float)(curarea->winx)/20.0);
+ ymargin= (short)((float)(curarea->winy)/20.0);
+
+ cent_orig[0]= curarea->winrct.xmin+(curarea->winx)/2;
+ cent_orig[1]= curarea->winrct.ymin+(curarea->winy)/2;
+
+ warp_pointer(cent_orig[0], cent_orig[1]);
+
+ /* we have to rely on events to give proper mousecoords after a warp_pointer */
+ mval[0]= cent[0]= (curarea->winx)/2;
+ mval[1]= cent[1]= (curarea->winy)/2;
+ /* window size minus margin - use this to get the mouse range for rotation */
+ winxf= (float)(curarea->winx)-(xmargin*2);
+ winyf= (float)(curarea->winy)-(ymargin*2);
+
+
+ time_lastdraw= time_lastwheel= PIL_check_seconds_timer();
+
+ G.vd->flag2 |= V3D_FLYMODE; /* so we draw the corner margins */
+ scrarea_do_windraw(curarea);
+ screen_swapbuffers();
+
+ while(action==0) { /* keep flying, no acton taken */
+ while(qtest()) {
+ toets= extern_qread(&val);
+
+ if(val) {
+ if(toets==MOUSEY) getmouseco_areawin(mval);
+ else if(toets==ESCKEY || toets==RIGHTMOUSE) {
+ action= 2; /* Canceled */
+ break;
+ } else if(toets==SPACEKEY || toets==LEFTMOUSE) {
+ action= 1; /* Accepted */
+ break;
+ } else if(toets==PADPLUSKEY || toets==EQUALKEY || toets==WHEELUPMOUSE) {
+ time_currwheel= PIL_check_seconds_timer();
+ time_wheel = (float)(time_currwheel - time_lastwheel);
+ time_lastwheel = time_currwheel;
+ /*printf("Wheel %f\n", time_wheel);*/
+ /*Mouse wheel delays range from 0.5==slow to 0.01==fast*/
+ time_wheel = 1+ (10 - (20*MIN2(time_wheel, 0.5))); /* 0-0.5 -> 0-5.0 */
+
+ if (speed<0) speed=0;
+ else {
+ if (G.qual & LR_SHIFTKEY)
+ speed+= G.vd->grid*time_wheel*0.1;
+ else
+ speed+= G.vd->grid*time_wheel;
+ }
+
+ } else if(toets==PADMINUS || toets==MINUSKEY || toets==WHEELDOWNMOUSE) {
+ time_currwheel= PIL_check_seconds_timer();
+ time_wheel = (float)(time_currwheel - time_lastwheel);
+ time_lastwheel = time_currwheel;
+ time_wheel = 1+ (10 - (20*MIN2(time_wheel, 0.5))); /* 0-0.5 -> 0-5.0 */
+
+ if (speed>0) speed=0;
+ else {
+ if (G.qual & LR_SHIFTKEY)
+ speed-= G.vd->grid*time_wheel*0.1;
+ else
+ speed-= G.vd->grid*time_wheel;
+ }
+
+ } else if (toets==MIDDLEMOUSE) {
+ /* make it so the camera direction dosent follow the view
+ good for flying backwards! - Only when MMB is held */
+
+ /*apply_rotation=0;*/
+ pan_view= 1;
+
+ /* impliment WASD keys */
+ } else if(toets==WKEY) {
+ if (speed<0) speed=-speed; /* flip speed rather then stopping, game like motion */
+ else speed+= G.vd->grid; /* increse like mousewheel if were alredy moving in that difection*/
+ axis= 2;
+ } else if(toets==SKEY) { /*SAME as above but flipped */
+ if (speed>0) speed=-speed;
+ else speed-= G.vd->grid;
+ axis= 2;
+
+ } else if(toets==AKEY) {
+ if (speed<0) speed=-speed;
+ axis= 0;
+ } else if(toets==DKEY) {
+ if (speed>0) speed=-speed;
+ axis= 0;
+ } else if(toets==FKEY) {
+ if (speed<0) speed=-speed;
+ axis= 1;
+ } else if(toets==RKEY) {
+ if (speed>0) speed=-speed;
+ axis= 1;
+
+ /* axis locking */
+ } else if(toets==XKEY) {
+ if (xlock) xlock=0;
+ else {
+ xlock = 2;
+ xlock_momentum = 0.0;
+ }
+ } else if(toets==ZKEY) {
+ if (zlock) zlock=0;
+ else {
+ zlock = 2;
+ zlock_momentum = 0.0;
+ }
+ }
+
+ } else {
+ /* mouse buttons lifted */
+ if (toets==MIDDLEMOUSE && pan_view) {
+ /*apply_rotation=1;*/
+ warp_pointer(cent_orig[0], cent_orig[1]);
+ pan_view= 0;
+ }
+ }
+ }
+ if(action != 0) break;
+
+ moffset[0]= mval[0]-cent[0];
+ moffset[1]= mval[1]-cent[1];
+
+ /* enforce a view margin */
+ if (moffset[0]>xmargin) moffset[0]-=xmargin;
+ else if (moffset[0]<-xmargin)moffset[0]+=xmargin;
+ else moffset[0]=0;
+
+ if (moffset[1]>ymargin) moffset[1]-=ymargin;
+ else if (moffset[1]<-ymargin)moffset[1]+=ymargin;
+ else moffset[1]=0;
+
+ /* scale the mouse offset so the distance the mouse moves isnt linear */
+ if (moffset[0]) {
+ moffset[0]= moffset[0]/winxf;
+ moffset[0]= moffset[0]*fabs(moffset[0]);
+ }
+
+ if (moffset[1]) {
+ moffset[1]= moffset[1]/winyf;
+ moffset[1]= moffset[1]*fabs(moffset[1]);
+ }
+
+ /* Should we redraw? */
+ if(speed!=0.0 || moffset[0] || moffset[1] || zlock || xlock || dvec[0] || dvec[1] || dvec[2] ) {
+
+ time_current= PIL_check_seconds_timer();
+ time_redraw= (float)(time_current-time_lastdraw);
+ time_redraw_clamped= MIN2(0.05, time_redraw); /* clamt the redraw time to avoid jitter in roll correction */
+ time_lastdraw= time_current;
+ /*fprintf(stderr, "%f\n", time_redraw);*/ /* 0.002 is a small redraw 0.02 is larger */
+
+ /* Scale the time to use shift to scale the speed down- just like
+ shift slows many other areas of blender down */
+ if (G.qual & LR_SHIFTKEY)
+ speed= speed * (1-time_redraw_clamped);
+
+ Mat3CpyMat4(mat, G.vd->viewinv);
+
+ if (pan_view) {
+ /* pan only */
+ dvec_tmp[0]= -moffset[0];
+ dvec_tmp[1]= -moffset[1];
+ dvec_tmp[2]= 0;
+
+ if (G.qual & LR_SHIFTKEY) {
+ dvec_tmp[0] *= 0.1;
+ dvec_tmp[1] *= 0.1;
+ }
+
+ Mat3MulVecfl(mat, dvec_tmp);
+ VecMulf(dvec_tmp, time_redraw*200.0 * G.vd->grid);
+
+ } else {
+ /* rotate about the X axis- look up/down */
+ if (moffset[1]) {
+ upvec[0]=1;
+ upvec[1]=0;
+ upvec[2]=0;
+ Mat3MulVecfl(mat, upvec);
+ VecRotToQuat( upvec, (float)moffset[1]*-time_redraw*20, tmp_quat); /* Rotate about the relative up vec */
+ QuatMul(G.vd->viewquat, G.vd->viewquat, tmp_quat);
+
+ if (xlock) xlock = 2; /*check for rotation*/
+ if (zlock) zlock = 2;
+ xlock_momentum= 0.0;
+ }
+
+ /* rotate about the Y axis- look left/right */
+ if (moffset[0]) {
+
+ if (zlock) {
+ upvec[0]=0;
+ upvec[1]=0;
+ upvec[2]=1;
+ } else {
+ upvec[0]=0;
+ upvec[1]=1;
+ upvec[2]=0;
+ Mat3MulVecfl(mat, upvec);
+ }
+
+ VecRotToQuat( upvec, (float)moffset[0]*time_redraw*20, tmp_quat); /* Rotate about the relative up vec */
+ QuatMul(G.vd->viewquat, G.vd->viewquat, tmp_quat);
+
+ if (xlock) xlock = 2;/*check for rotation*/
+ if (zlock) zlock = 2;
+ }
+
+ if (zlock==2) {
+ upvec[0]=1;
+ upvec[1]=0;
+ upvec[2]=0;
+ Mat3MulVecfl(mat, upvec);
+
+ /*make sure we have some z rolling*/
+ if (fabs(upvec[2]) > 0.00001) {
+ roll= upvec[2]*5;
+ upvec[0]=0; /*rotate the view about this axis*/
+ upvec[1]=0;
+ upvec[2]=1;
+
+ Mat3MulVecfl(mat, upvec);
+ VecRotToQuat( upvec, roll*time_redraw_clamped*zlock_momentum*0.1, tmp_quat); /* Rotate about the relative up vec */
+ QuatMul(G.vd->viewquat, G.vd->viewquat, tmp_quat);
+
+ zlock_momentum += 0.05;
+ } else {
+ zlock=1; /* dont check until the view rotates again */
+ zlock_momentum= 0.0;
+ }
+ }
+
+ if (xlock==2 && moffset[1]==0) { /*only apply xcorrect when mouse isnt applying x rot*/
+ upvec[0]=0;
+ upvec[1]=0;
+ upvec[2]=1;
+ Mat3MulVecfl(mat, upvec);
+ /*make sure we have some z rolling*/
+ if (fabs(upvec[2]) > 0.00001) {
+ roll= upvec[2]*-5;
+
+ upvec[0]=1; /*rotate the view about this axis*/
+ upvec[1]=0;
+ upvec[2]=0;
+
+ Mat3MulVecfl(mat, upvec);
+
+ VecRotToQuat( upvec, roll*time_redraw_clamped*xlock_momentum*0.1, tmp_quat); /* Rotate about the relative up vec */
+ QuatMul(G.vd->viewquat, G.vd->viewquat, tmp_quat);
+
+ xlock_momentum += 0.05;
+ } else {
+ xlock=1; /* see above */
+ xlock_momentum= 0.0;
+ }
+ }
+
+
+ if (apply_rotation) {
+ /* Normal operation */
+ /* define dvec, view direction vector */
+ dvec_tmp[0]= dvec_tmp[1]= dvec_tmp[2]= 0;
+ /* move along the current axis */
+ dvec_tmp[axis]= 1.0f;
+
+ Mat3MulVecfl(mat, dvec_tmp);
+
+ VecMulf(dvec_tmp, speed*time_redraw*0.25);
+ }
+ }
+
+ /* impose a directional lag */
+ dvec_lag = 1.0/(1+(time_redraw*5));
+ dvec[0] = dvec_tmp[0]*(1-dvec_lag) + dvec_old[0]*dvec_lag;
+ dvec[1] = dvec_tmp[1]*(1-dvec_lag) + dvec_old[1]*dvec_lag;
+ dvec[2] = dvec_tmp[2]*(1-dvec_lag) + dvec_old[2]*dvec_lag;
+
+
+ if (G.vd->persp==2) {
+ if (G.vd->camera->protectflag & OB_LOCK_LOCX)
+ dvec[0] = 0.0;
+ if (G.vd->camera->protectflag & OB_LOCK_LOCY)
+ dvec[1] = 0.0;
+ if (G.vd->camera->protectflag & OB_LOCK_LOCZ)
+ dvec[2] = 0.0;
+ }
+
+ VecAddf(G.vd->ofs, G.vd->ofs, dvec);
+ if (zlock && xlock)
+ headerprint("FlyKeys Speed:(+/- | Wheel), Upright Axis:X on/Z on, Slow:Shift, Direction:WASDRF, Ok:LMB, Pan:MMB, Cancel:RMB");
+ else if (zlock)
+ headerprint("FlyKeys Speed:(+/- | Wheel), Upright Axis:X off/Z on, Slow:Shift, Direction:WASDRF, Ok:LMB, Pan:MMB, Cancel:RMB");
+ else if (xlock)
+ headerprint("FlyKeys Speed:(+/- | Wheel), Upright Axis:X on/Z off, Slow:Shift, Direction:WASDRF, Ok:LMB, Pan:MMB, Cancel:RMB");
+ else
+ headerprint("FlyKeys Speed:(+/- | Wheel), Upright Axis:X off/Z off, Slow:Shift, Direction:WASDRF, Ok:LMB, Pan:MMB, Cancel:RMB");
+
+ do_screenhandlers(G.curscreen); /* advance the next frame */
+
+ /* we are in camera view so apply the view ofs and quat to the view matrix and set the camera to teh view */
+ if (G.vd->persp==2) {
+ G.vd->persp= 1; /*set this so setviewmatrixview3d uses the ofs and quat instead of the camera */
+ setviewmatrixview3d();
+ setcameratoview3d();
+ G.vd->persp= 2;
+
+ /* record the motion */
+ if (G.flags & G_RECORDKEYS && (!playing_anim || cfra != G.scene->r.cfra)) {
+ cfra = G.scene->r.cfra;
+
+ if (xlock || zlock || moffset[0] || moffset[1]) {
+ insertkey(&G.vd->camera->id, ID_OB, actname, NULL, OB_ROT_X, 0);
+ insertkey(&G.vd->camera->id, ID_OB, actname, NULL, OB_ROT_Y, 0);
+ insertkey(&G.vd->camera->id, ID_OB, actname, NULL, OB_ROT_Z, 0);
+ }
+ if (speed) {
+ insertkey(&G.vd->camera->id, ID_OB, actname, NULL, OB_LOC_X, 0);
+ insertkey(&G.vd->camera->id, ID_OB, actname, NULL, OB_LOC_Y, 0);
+ insertkey(&G.vd->camera->id, ID_OB, actname, NULL, OB_LOC_Z, 0);
+ }
+ }
+ }
+ scrarea_do_windraw(curarea);
+ screen_swapbuffers();
+ } else
+ /*were not redrawing but we need to update the time else the view will jump */
+ time_lastdraw= PIL_check_seconds_timer();
+ /* end drawing */
+ VECCOPY(dvec_old, dvec);
+ }
+
+ G.vd->dist= dist_backup;
+
+ /* Revert to original view? */
+ if (action == 2) { /* action == 2 means the user pressed Esc of RMB, and not to apply view to camera */
+ if (persp_backup==2) { /* a camera view */
+ G.vd->viewbut=1;
+ VECCOPY(G.vd->camera->loc, ofs_backup);
+ VECCOPY(G.vd->camera->rot, rot_backup);
+ DAG_object_flush_update(G.scene, G.vd->camera, OB_RECALC_OB);
+ } else {
+ /* Non Camera we need to reset the view back to the original location bacause the user canceled*/
+ QUATCOPY(G.vd->viewquat, rot_backup);
+ VECCOPY(G.vd->ofs, ofs_backup);
+ G.vd->persp= persp_backup;
+ }
+ }
+ else if (persp_backup==2) { /* camera */
+ float mat3[3][3];
+ Mat3CpyMat4(mat3, G.vd->camera->obmat);
+ Mat3ToCompatibleEul(mat3, G.vd->camera->rot, rot_backup);
+
+ DAG_object_flush_update(G.scene, G.vd->camera, OB_RECALC_OB);
+
+ if (G.flags & G_RECORDKEYS) {
+ allqueue(REDRAWIPO, 0);
+ allspace(REMAKEIPO, 0);
+ allqueue(REDRAWNLA, 0);
+ allqueue(REDRAWTIME, 0);
+ }
+ }
+ else { /* not camera */
+ /* Apply the fly mode view */
+ /*restore the dist*/
+ upvec[0]= upvec[1]= 0;
+ upvec[2]=dist_backup; /*x and y are 0*/
+ Mat3CpyMat4(mat, G.vd->viewinv);
+ Mat3MulVecfl(mat, upvec);
+ VecAddf(G.vd->ofs, G.vd->ofs, upvec);
+ /*Done with correcting for the dist */
+ }
+
+ G.vd->flag2 &= ~V3D_FLYMODE;
+ allqueue(REDRAWVIEW3D, 0);
+ BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT); /* not working at the moment not sure why */
+}
+
+void view3d_edit_clipping(View3D *v3d)
+{
+
+ if(v3d->flag & V3D_CLIPPING) {
+ v3d->flag &= ~V3D_CLIPPING;
+ scrarea_queue_winredraw(curarea);
+ if(v3d->clipbb) MEM_freeN(v3d->clipbb);
+ v3d->clipbb= NULL;
+ }
+ else {
+ rcti rect;
+ double mvmatrix[16];
+ double projmatrix[16];
+ double xs, ys, p[3];
+ GLint viewport[4];
+ short val;
+
+ /* get border in window coords */
+ setlinestyle(2);
+ val= get_border(&rect, 3);
+ setlinestyle(0);
+ if(val==0) return;
+
+ v3d->flag |= V3D_CLIPPING;
+ v3d->clipbb= MEM_mallocN(sizeof(BoundBox), "clipbb");
+
+ /* convert border to 3d coordinates */
+
+ /* Get the matrices needed for gluUnProject */
+ glGetIntegerv(GL_VIEWPORT, viewport);
+ glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
+ glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
+
+ /* near zero floating point values can give issues with gluUnProject
+ in side view on some implementations */
+ if(fabs(mvmatrix[0]) < 1e-6) mvmatrix[0]= 0.0;
+ if(fabs(mvmatrix[5]) < 1e-6) mvmatrix[5]= 0.0;
+
+ /* Set up viewport so that gluUnProject will give correct values */
+ viewport[0] = 0;
+ viewport[1] = 0;
+
+ /* four clipping planes and bounding volume */
+ /* first do the bounding volume */
+ for(val=0; val<4; val++) {
+
+ xs= (val==0||val==3)?rect.xmin:rect.xmax;
+ ys= (val==0||val==1)?rect.ymin:rect.ymax;
+
+ gluUnProject(xs, ys, 0.0, mvmatrix, projmatrix, viewport, &p[0], &p[1], &p[2]);
+ VECCOPY(v3d->clipbb->vec[val], p);
+
+ gluUnProject(xs, ys, 1.0, mvmatrix, projmatrix, viewport, &p[0], &p[1], &p[2]);
+ VECCOPY(v3d->clipbb->vec[4+val], p);
+ }
+
+ /* then plane equations */
+ for(val=0; val<4; val++) {
+
+ CalcNormFloat(v3d->clipbb->vec[val], v3d->clipbb->vec[val==3?0:val+1], v3d->clipbb->vec[val+4],
+ v3d->clip[val]);
+
+ v3d->clip[val][3]= - v3d->clip[val][0]*v3d->clipbb->vec[val][0]
+ - v3d->clip[val][1]*v3d->clipbb->vec[val][1]
+ - v3d->clip[val][2]*v3d->clipbb->vec[val][2];
+ }
+ }
+}
+
diff --git a/source/blender/src/eventdebug.c b/source/blender/src/eventdebug.c
new file mode 100644
index 00000000000..6c6a137a789
--- /dev/null
+++ b/source/blender/src/eventdebug.c
@@ -0,0 +1,195 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#include "mydevice.h"
+#include "blendef.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+char *event_to_string(short);
+
+char *event_to_string(short evt) {
+#define smap(evt) case evt: return #evt
+ switch (evt) {
+ default: return "<unknown>";
+ smap(CHANGED);
+ smap(DRAWEDGES);
+ smap(BACKBUFDRAW);
+ smap(EXECUTE);
+ smap(LOAD_FILE);
+ smap(RESHAPE);
+ smap(UI_BUT_EVENT);
+ smap(REDRAWVIEW3D);
+ smap(REDRAWVIEWCAM);
+ smap(REDRAWHEADERS);
+ smap(REDRAWVIEW3D_Z);
+ smap(REDRAWALL);
+ smap(REDRAWINFO);
+ smap(RENDERPREVIEW);
+ smap(REDRAWIPO);
+ smap(REDRAWDATASELECT);
+ smap(REDRAWSEQ);
+ smap(REDRAWIMAGE);
+ smap(REDRAWOOPS);
+ smap(REDRAWIMASEL);
+ smap(AFTERIMASELIMA);
+ smap(AFTERIMASELGET);
+ smap(AFTERIMAWRITE);
+ smap(IMALEFTMOUSE);
+ smap(AFTERPIBREAD);
+ smap(REDRAWTEXT);
+ smap(REDRAWSCRIPT);
+ smap(REDRAWACTION);
+ smap(LEFTMOUSE);
+ smap(MIDDLEMOUSE);
+ smap(RIGHTMOUSE);
+ smap(MOUSEX);
+ smap(MOUSEY);
+ smap(TIMER0);
+ smap(TIMER1);
+ smap(TIMER2);
+ smap(TIMER3);
+ smap(KEYBD);
+ smap(RAWKEYBD);
+ smap(REDRAW);
+ smap(INPUTCHANGE);
+ smap(QFULL);
+ smap(WINFREEZE);
+ smap(WINTHAW);
+ smap(WINCLOSE);
+ smap(WINQUIT);
+ smap(Q_FIRSTTIME);
+ smap(AKEY);
+ smap(BKEY);
+ smap(CKEY);
+ smap(DKEY);
+ smap(EKEY);
+ smap(FKEY);
+ smap(GKEY);
+ smap(HKEY);
+ smap(IKEY);
+ smap(JKEY);
+ smap(KKEY);
+ smap(LKEY);
+ smap(MKEY);
+ smap(NKEY);
+ smap(OKEY);
+ smap(PKEY);
+ smap(QKEY);
+ smap(RKEY);
+ smap(SKEY);
+ smap(TKEY);
+ smap(UKEY);
+ smap(VKEY);
+ smap(WKEY);
+ smap(XKEY);
+ smap(YKEY);
+ smap(ZKEY);
+ smap(ZEROKEY);
+ smap(ONEKEY);
+ smap(TWOKEY);
+ smap(THREEKEY);
+ smap(FOURKEY);
+ smap(FIVEKEY);
+ smap(SIXKEY);
+ smap(SEVENKEY);
+ smap(EIGHTKEY);
+ smap(NINEKEY);
+ smap(CAPSLOCKKEY);
+ smap(LEFTCTRLKEY);
+ smap(LEFTALTKEY);
+ smap(RIGHTALTKEY);
+ smap(RIGHTCTRLKEY);
+ smap(RIGHTSHIFTKEY);
+ smap(LEFTSHIFTKEY);
+ smap(ESCKEY);
+ smap(TABKEY);
+ smap(RETKEY);
+ smap(SPACEKEY);
+ smap(LINEFEEDKEY);
+ smap(BACKSPACEKEY);
+ smap(DELKEY);
+ smap(SEMICOLONKEY);
+ smap(PERIODKEY);
+ smap(COMMAKEY);
+ smap(QUOTEKEY);
+ smap(ACCENTGRAVEKEY);
+ smap(MINUSKEY);
+ smap(SLASHKEY);
+ smap(BACKSLASHKEY);
+ smap(EQUALKEY);
+ smap(LEFTBRACKETKEY);
+ smap(RIGHTBRACKETKEY);
+ smap(LEFTARROWKEY);
+ smap(DOWNARROWKEY);
+ smap(RIGHTARROWKEY);
+ smap(UPARROWKEY);
+ smap(PAD0);
+ smap(PAD1);
+ smap(PAD2);
+ smap(PAD3);
+ smap(PAD4);
+ smap(PAD5);
+ smap(PAD6);
+ smap(PAD7);
+ smap(PAD8);
+ smap(PAD9);
+ smap(PADPERIOD);
+ smap(PADSLASHKEY);
+ smap(PADASTERKEY);
+ smap(PADMINUS);
+ smap(PADENTER);
+ smap(PADPLUSKEY);
+ smap(F1KEY);
+ smap(F2KEY);
+ smap(F3KEY);
+ smap(F4KEY);
+ smap(F5KEY);
+ smap(F6KEY);
+ smap(F7KEY);
+ smap(F8KEY);
+ smap(F9KEY);
+ smap(F10KEY);
+ smap(F11KEY);
+ smap(F12KEY);
+ smap(PAUSEKEY);
+ smap(INSERTKEY);
+ smap(HOMEKEY);
+ smap(PAGEUPKEY);
+ smap(PAGEDOWNKEY);
+ smap(ENDKEY);
+ smap(REDRAWNLA);
+ smap(ONLOAD_SCRIPT);
+ }
+ #undef smap
+}
diff --git a/source/blender/src/filelist.c b/source/blender/src/filelist.c
new file mode 100644
index 00000000000..45341c2b798
--- /dev/null
+++ b/source/blender/src/filelist.c
@@ -0,0 +1,1141 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2007 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+
+/* global includes */
+
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef WIN32
+#include <unistd.h>
+#else
+#include <io.h>
+#include <direct.h>
+#endif
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_linklist.h"
+#include "BLI_storage_types.h"
+
+#ifdef WIN32
+#include "BLI_winstuff.h"
+#endif
+
+#include "BKE_utildefines.h"
+#include "BKE_global.h"
+#include "BIF_filelist.h"
+#include "BKE_library.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BLO_readfile.h"
+
+#include "DNA_space_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_ID.h"
+#include "DNA_object_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_material_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_world_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_userdef_types.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+#include "IMB_thumbs.h"
+
+#include "PIL_time.h"
+
+#include "datatoc.h"
+
+/* Elubie: VERY, really very ugly and evil! Remove asap!!! */
+/* for state of file */
+#define ACTIVE 2
+
+/* max length of library group name within filesel */
+#define GROUP_MAX 32
+
+typedef struct FileList
+{
+ struct direntry *filelist;
+ int *fidx;
+
+ int numfiles;
+ int numfiltered;
+ char dir[FILE_MAXDIR];
+ short type;
+ short ipotype;
+ struct BlendHandle *libfiledata;
+ int has_func;
+ short prv_w;
+ short prv_h;
+ short hide_dot;
+ unsigned int filter;
+} FileList;
+
+int BIF_groupname_to_code(char *group)
+{
+ char buf[32];
+ char *lslash;
+
+ BLI_strncpy(buf, group, 31);
+ lslash= BLI_last_slash(buf);
+ if (lslash)
+ lslash[0]= '\0';
+
+ return BLO_idcode_from_name(buf);
+}
+
+
+#define SPECIAL_IMG_SIZE 48
+#define SPECIAL_IMG_ROWS 4
+#define SPECIAL_IMG_COLS 4
+
+#define SPECIAL_IMG_FOLDER 0
+#define SPECIAL_IMG_PARENT 1
+#define SPECIAL_IMG_REFRESH 2
+#define SPECIAL_IMG_BLENDFILE 3
+#define SPECIAL_IMG_SOUNDFILE 4
+#define SPECIAL_IMG_MOVIEFILE 5
+#define SPECIAL_IMG_PYTHONFILE 6
+#define SPECIAL_IMG_TEXTFILE 7
+#define SPECIAL_IMG_FONTFILE 8
+#define SPECIAL_IMG_UNKNOWNFILE 9
+#define SPECIAL_IMG_MAX SPECIAL_IMG_UNKNOWNFILE + 1
+
+static ImBuf* gSpecialFileImages[SPECIAL_IMG_MAX];
+
+
+/* ******************* SORT ******************* */
+
+static int compare_name(const void *a1, const void *a2)
+{
+ const struct direntry *entry1=a1, *entry2=a2;
+
+ /* type is is equal to stat.st_mode */
+
+ if (S_ISDIR(entry1->type)){
+ if (S_ISDIR(entry2->type)==0) return (-1);
+ } else{
+ if (S_ISDIR(entry2->type)) return (1);
+ }
+ if (S_ISREG(entry1->type)){
+ if (S_ISREG(entry2->type)==0) return (-1);
+ } else{
+ if (S_ISREG(entry2->type)) return (1);
+ }
+ if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1);
+ if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1);
+
+ /* make sure "." and ".." are always first */
+ if( strcmp(entry1->relname, ".")==0 ) return (-1);
+ if( strcmp(entry2->relname, ".")==0 ) return (1);
+ if( strcmp(entry1->relname, "..")==0 ) return (-1);
+
+ return (BLI_strcasecmp(entry1->relname,entry2->relname));
+}
+
+static int compare_date(const void *a1, const void *a2)
+{
+ const struct direntry *entry1=a1, *entry2=a2;
+
+ /* type is equal to stat.st_mode */
+
+ if (S_ISDIR(entry1->type)){
+ if (S_ISDIR(entry2->type)==0) return (-1);
+ } else{
+ if (S_ISDIR(entry2->type)) return (1);
+ }
+ if (S_ISREG(entry1->type)){
+ if (S_ISREG(entry2->type)==0) return (-1);
+ } else{
+ if (S_ISREG(entry2->type)) return (1);
+ }
+ if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1);
+ if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1);
+
+ /* make sure "." and ".." are always first */
+ if( strcmp(entry1->relname, ".")==0 ) return (-1);
+ if( strcmp(entry2->relname, ".")==0 ) return (1);
+ if( strcmp(entry1->relname, "..")==0 ) return (-1);
+
+ if ( entry1->s.st_mtime < entry2->s.st_mtime) return 1;
+ if ( entry1->s.st_mtime > entry2->s.st_mtime) return -1;
+
+ else return BLI_strcasecmp(entry1->relname,entry2->relname);
+}
+
+static int compare_size(const void *a1, const void *a2)
+{
+ const struct direntry *entry1=a1, *entry2=a2;
+
+ /* type is equal to stat.st_mode */
+
+ if (S_ISDIR(entry1->type)){
+ if (S_ISDIR(entry2->type)==0) return (-1);
+ } else{
+ if (S_ISDIR(entry2->type)) return (1);
+ }
+ if (S_ISREG(entry1->type)){
+ if (S_ISREG(entry2->type)==0) return (-1);
+ } else{
+ if (S_ISREG(entry2->type)) return (1);
+ }
+ if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1);
+ if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1);
+
+ /* make sure "." and ".." are always first */
+ if( strcmp(entry1->relname, ".")==0 ) return (-1);
+ if( strcmp(entry2->relname, ".")==0 ) return (1);
+ if( strcmp(entry1->relname, "..")==0 ) return (-1);
+
+ if ( entry1->s.st_size < entry2->s.st_size) return 1;
+ if ( entry1->s.st_size > entry2->s.st_size) return -1;
+ else return BLI_strcasecmp(entry1->relname,entry2->relname);
+}
+
+static int compare_extension(const void *a1, const void *a2) {
+ const struct direntry *entry1=a1, *entry2=a2;
+ char *sufix1, *sufix2;
+ char *nil="";
+
+ if (!(sufix1= strstr (entry1->relname, ".blend.gz")))
+ sufix1= strrchr (entry1->relname, '.');
+ if (!(sufix2= strstr (entry2->relname, ".blend.gz")))
+ sufix2= strrchr (entry2->relname, '.');
+ if (!sufix1) sufix1= nil;
+ if (!sufix2) sufix2= nil;
+
+ /* type is is equal to stat.st_mode */
+
+ if (S_ISDIR(entry1->type)){
+ if (S_ISDIR(entry2->type)==0) return (-1);
+ } else{
+ if (S_ISDIR(entry2->type)) return (1);
+ }
+ if (S_ISREG(entry1->type)){
+ if (S_ISREG(entry2->type)==0) return (-1);
+ } else{
+ if (S_ISREG(entry2->type)) return (1);
+ }
+ if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1);
+ if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1);
+
+ /* make sure "." and ".." are always first */
+ if( strcmp(entry1->relname, ".")==0 ) return (-1);
+ if( strcmp(entry2->relname, ".")==0 ) return (1);
+ if( strcmp(entry1->relname, "..")==0 ) return (-1);
+ if( strcmp(entry2->relname, "..")==0 ) return (-1);
+
+ return (BLI_strcasecmp(sufix1, sufix2));
+}
+
+void BIF_filelist_filter(FileList* filelist)
+{
+ char dir[FILE_MAX], group[GROUP_MAX];
+ int num_filtered = 0;
+ int i, j;
+
+ if (!filelist->filelist)
+ return;
+
+ if ( ( (filelist->type == FILE_LOADLIB) && BIF_filelist_islibrary(filelist, dir, group))
+ || (filelist->type == FILE_MAIN) ) {
+ filelist->filter = 0;
+ }
+
+ if (!filelist->filter) {
+ if (filelist->fidx) {
+ MEM_freeN(filelist->fidx);
+ filelist->fidx = NULL;
+ }
+ filelist->fidx = (int *)MEM_callocN(filelist->numfiles*sizeof(int), "filteridx");
+ for (i = 0; i < filelist->numfiles; ++i) {
+ filelist->fidx[i] = i;
+ }
+ filelist->numfiltered = filelist->numfiles;
+ return;
+ }
+
+ // How many files are left after filter ?
+ for (i = 0; i < filelist->numfiles; ++i) {
+ if (filelist->filelist[i].flags & filelist->filter) {
+ num_filtered++;
+ }
+ else if (filelist->filelist[i].type & S_IFDIR) {
+ if (filelist->filter & FOLDERFILE) {
+ num_filtered++;
+ }
+ }
+ }
+
+ if (filelist->fidx) {
+ MEM_freeN(filelist->fidx);
+ filelist->fidx = NULL;
+ }
+ filelist->fidx = (int *)MEM_callocN(num_filtered*sizeof(int), "filteridx");
+ filelist->numfiltered = num_filtered;
+
+ for (i = 0, j=0; i < filelist->numfiles; ++i) {
+ if (filelist->filelist[i].flags & filelist->filter) {
+ filelist->fidx[j++] = i;
+ }
+ else if (filelist->filelist[i].type & S_IFDIR) {
+ if (filelist->filter & FOLDERFILE) {
+ filelist->fidx[j++] = i;
+ }
+ }
+ }
+}
+
+void BIF_filelist_init_icons()
+{
+ short x, y, k;
+ ImBuf *bbuf;
+ ImBuf *ibuf;
+ bbuf = IMB_ibImageFromMemory((int *)datatoc_prvicons, datatoc_prvicons_size, IB_rect);
+ if (bbuf) {
+ for (y=0; y<SPECIAL_IMG_ROWS; y++) {
+ for (x=0; x<SPECIAL_IMG_COLS; x++) {
+ int tile = SPECIAL_IMG_COLS*y + x;
+ if (tile < SPECIAL_IMG_MAX) {
+ ibuf = IMB_allocImBuf(SPECIAL_IMG_SIZE, SPECIAL_IMG_SIZE, 32, IB_rect, 0);
+ for (k=0; k<SPECIAL_IMG_SIZE; k++) {
+ memcpy(&ibuf->rect[k*SPECIAL_IMG_SIZE], &bbuf->rect[(k+y*SPECIAL_IMG_SIZE)*SPECIAL_IMG_SIZE*SPECIAL_IMG_COLS+x*SPECIAL_IMG_SIZE], SPECIAL_IMG_SIZE*sizeof(int));
+ }
+ gSpecialFileImages[tile] = ibuf;
+ }
+ }
+ }
+ IMB_freeImBuf(bbuf);
+ }
+
+}
+
+void BIF_filelist_free_icons()
+{
+ int i;
+ for (i=0; i < SPECIAL_IMG_MAX; ++i) {
+ IMB_freeImBuf(gSpecialFileImages[i]);
+ gSpecialFileImages[i] = NULL;
+ }
+}
+
+struct FileList* BIF_filelist_new()
+{
+ FileList* p = MEM_callocN( sizeof(FileList), "filelist" );
+ p->filelist = 0;
+ p->numfiles = 0;
+ p->dir[0] = '\0';
+ p->libfiledata = 0;
+ p->type = 0;
+ p->has_func = 0;
+ p->filter = 0;
+ return p;
+}
+
+struct FileList* BIF_filelist_copy(struct FileList* filelist)
+{
+ FileList* p = BIF_filelist_new();
+ BLI_strncpy(p->dir, filelist->dir, FILE_MAXDIR);
+ p->filelist = NULL;
+ p->fidx = NULL;
+ p->type = filelist->type;
+ p->ipotype = filelist->ipotype;
+ p->has_func = filelist->has_func;
+
+ return p;
+}
+
+void BIF_filelist_free(struct FileList* filelist)
+{
+ int i;
+
+ if (!filelist) {
+ printf("Attemtping to delete empty filelist.\n");
+ return;
+ }
+
+ if (filelist->fidx) {
+ MEM_freeN(filelist->fidx);
+ filelist->fidx = NULL;
+ }
+
+ for (i = 0; i < filelist->numfiles; ++i) {
+ if (filelist->filelist[i].image) {
+ IMB_freeImBuf(filelist->filelist[i].image);
+ }
+ filelist->filelist[i].image = 0;
+ if (filelist->filelist[i].relname)
+ MEM_freeN(filelist->filelist[i].relname);
+ filelist->filelist[i].relname = 0;
+ if (filelist->filelist[i].string)
+ MEM_freeN(filelist->filelist[i].string);
+ filelist->filelist[i].string = 0;
+ }
+
+ filelist->numfiles = 0;
+ free(filelist->filelist);
+ filelist->filelist = 0;
+ filelist->filter = 0;
+ filelist->numfiltered =0;
+}
+
+void BIF_filelist_freelib(struct FileList* filelist)
+{
+ if(filelist->libfiledata)
+ BLO_blendhandle_close(filelist->libfiledata);
+ filelist->libfiledata= 0;
+}
+
+struct BlendHandle *BIF_filelist_lib(struct FileList* filelist)
+{
+ return filelist->libfiledata;
+}
+
+int BIF_filelist_numfiles(struct FileList* filelist)
+{
+ return filelist->numfiltered;
+}
+
+const char * BIF_filelist_dir(struct FileList* filelist)
+{
+ return filelist->dir;
+}
+
+void BIF_filelist_setdir(struct FileList* filelist, const char *dir)
+{
+ BLI_strncpy(filelist->dir, dir, FILE_MAXDIR);
+}
+
+void BIF_filelist_appenddir(struct FileList* filelist, const char *relname)
+{
+ strcat(filelist->dir, relname);
+ BLI_cleanup_dir(G.sce, filelist->dir);
+}
+
+void BIF_filelist_imgsize(struct FileList* filelist, short w, short h)
+{
+ filelist->prv_w = w;
+ filelist->prv_h = h;
+}
+
+void BIF_filelist_loadimage(struct FileList* filelist, int index)
+{
+ ImBuf *imb = NULL;
+ int imgwidth = filelist->prv_w;
+ int imgheight = filelist->prv_h;
+ short ex, ey, dx, dy;
+ float scaledx, scaledy;
+ int fidx = 0;
+
+ if ( (index < 0) || (index >= filelist->numfiltered) ) {
+ return;
+ }
+ fidx = filelist->fidx[index];
+
+ if (!filelist->filelist[fidx].image)
+ {
+ if (filelist->type != FILE_MAIN)
+ {
+ if ( filelist->filelist[fidx].flags & IMAGEFILE ) {
+ imb = IMB_thumb_manage(filelist->dir, filelist->filelist[fidx].relname, THB_NORMAL, THB_SOURCE_IMAGE);
+ } else if ( filelist->filelist[fidx].flags & MOVIEFILE ) {
+ imb = IMB_thumb_manage(filelist->dir, filelist->filelist[fidx].relname, THB_NORMAL, THB_SOURCE_MOVIE);
+ if (!imb) {
+ /* remember that file can't be loaded via IMB_open_anim */
+ filelist->filelist[fidx].flags &= ~MOVIEFILE;
+ filelist->filelist[fidx].flags |= MOVIEFILE_ICON;
+ }
+ }
+ if (imb) {
+ if (imb->x > imb->y) {
+ scaledx = (float)imgwidth;
+ scaledy = ( (float)imb->y/(float)imb->x )*imgwidth;
+ }
+ else {
+ scaledy = (float)imgheight;
+ scaledx = ( (float)imb->x/(float)imb->y )*imgheight;
+ }
+ ex = (short)scaledx;
+ ey = (short)scaledy;
+
+ dx = imgwidth - ex;
+ dy = imgheight - ey;
+
+ IMB_scaleImBuf(imb, ex, ey);
+
+ }
+ filelist->filelist[fidx].image = imb;
+
+ }
+ }
+}
+
+struct ImBuf * BIF_filelist_getimage(struct FileList* filelist, int index)
+{
+ ImBuf* ibuf = NULL;
+ int fidx = 0;
+ if ( (index < 0) || (index >= filelist->numfiltered) ) {
+ return NULL;
+ }
+ fidx = filelist->fidx[index];
+ ibuf = filelist->filelist[fidx].image;
+
+ if (ibuf == NULL) {
+ struct direntry *file = &filelist->filelist[fidx];
+ if (file->type & S_IFDIR) {
+ if ( strcmp(filelist->filelist[fidx].relname, "..") == 0) {
+ ibuf = gSpecialFileImages[SPECIAL_IMG_PARENT];
+ } else if ( strcmp(filelist->filelist[fidx].relname, ".") == 0) {
+ ibuf = gSpecialFileImages[SPECIAL_IMG_REFRESH];
+ } else {
+ ibuf = gSpecialFileImages[SPECIAL_IMG_FOLDER];
+ }
+ } else {
+ ibuf = gSpecialFileImages[SPECIAL_IMG_UNKNOWNFILE];
+ }
+
+ if (file->flags & BLENDERFILE) {
+ ibuf = gSpecialFileImages[SPECIAL_IMG_BLENDFILE];
+ } else if ( (file->flags & MOVIEFILE) || (file->flags & MOVIEFILE_ICON) ) {
+ ibuf = gSpecialFileImages[SPECIAL_IMG_MOVIEFILE];
+ } else if (file->flags & SOUNDFILE) {
+ ibuf = gSpecialFileImages[SPECIAL_IMG_SOUNDFILE];
+ } else if (file->flags & PYSCRIPTFILE) {
+ ibuf = gSpecialFileImages[SPECIAL_IMG_PYTHONFILE];
+ } else if (file->flags & FTFONTFILE) {
+ ibuf = gSpecialFileImages[SPECIAL_IMG_FONTFILE];
+ } else if (file->flags & TEXTFILE) {
+ ibuf = gSpecialFileImages[SPECIAL_IMG_TEXTFILE];
+ }
+ }
+ return ibuf;
+}
+
+struct direntry * BIF_filelist_file(struct FileList* filelist, int index)
+{
+ int fidx = 0;
+
+ if ( (index < 0) || (index >= filelist->numfiltered) ) {
+ return NULL;
+ }
+ fidx = filelist->fidx[index];
+
+ return &filelist->filelist[fidx];
+}
+
+int BIF_filelist_find(struct FileList* filelist, char *file)
+{
+ int index = -1;
+ int i;
+ int fidx = -1;
+
+ if (!filelist->fidx)
+ return fidx;
+
+
+ for (i = 0; i < filelist->numfiles; ++i) {
+ if ( strcmp(filelist->filelist[i].relname, file) == 0) {
+ index = i;
+ break;
+ }
+ }
+
+ for (i = 0; i < filelist->numfiltered; ++i) {
+ if (filelist->fidx[i] == index) {
+ fidx = i;
+ break;
+ }
+ }
+ return fidx;
+}
+
+void BIF_filelist_hidedot(struct FileList* filelist, short hide)
+{
+ filelist->hide_dot = hide;
+}
+
+void BIF_filelist_setfilter(struct FileList* filelist, unsigned int filter)
+{
+ filelist->filter = filter;
+}
+
+void BIF_filelist_readdir(struct FileList* filelist)
+{
+ char wdir[FILE_MAXDIR];
+ int finished = 0;
+
+ if (!filelist) return;
+ filelist->fidx = 0;
+ filelist->filelist = 0;
+
+ if(filelist->type==FILE_MAIN) {
+ BIF_filelist_from_main(filelist);
+ finished = 1;
+ } else if(filelist->type==FILE_LOADLIB) {
+ BLI_cleanup_dir(G.sce, filelist->dir);
+ BIF_filelist_from_library(filelist);
+ if(filelist->libfiledata) {
+ finished = 1;
+ }
+ }
+
+ if (!finished) {
+ BLI_getwdN(wdir);
+
+ BLI_cleanup_dir(G.sce, filelist->dir);
+ BLI_hide_dot_files(filelist->hide_dot);
+ filelist->numfiles = BLI_getdir(filelist->dir, &(filelist->filelist));
+
+ chdir(wdir);
+ BIF_filelist_setfiletypes(filelist, G.have_quicktime);
+ BIF_filelist_filter(filelist);
+
+ }
+}
+
+int BIF_filelist_empty(struct FileList* filelist)
+{
+ return filelist->filelist == 0;
+}
+
+void BIF_filelist_parent(struct FileList* filelist)
+{
+#ifdef WIN32
+ char c = '\\';
+#else
+ char c = '/';
+#endif
+ char *dir = filelist->dir;
+ size_t len = strlen(dir);
+
+ while( (len > 0) && (dir[len-1] == c) )
+ {
+ --len;
+ dir[len] = '\0';
+ }
+ while ( (len > 0) && (dir[len-1] != c) )
+ {
+ --len;
+ dir[len] = '\0';
+ }
+ if (len == 0)
+ {
+ dir[0] = c; dir[1] = '\0';
+ }
+#ifdef WIN32
+ strcat(filelist->dir, "\\");
+#else
+ strcat(filelist->dir, "/");
+#endif
+
+ BLI_cleanup_dir(G.sce, filelist->dir);
+ BLI_make_exist(filelist->dir);
+ BIF_filelist_readdir(filelist);
+}
+
+void BIF_filelist_setfiletypes(struct FileList* filelist, short has_quicktime)
+{
+ struct direntry *file;
+ int num;
+
+ file= filelist->filelist;
+
+ for(num=0; num<filelist->numfiles; num++, file++) {
+ file->flags= 0;
+ file->type= file->s.st_mode; /* restore the mess below */
+
+ /* Don't check extensions for directories */
+ if (file->type & S_IFDIR)
+ continue;
+
+
+
+ if(BLO_has_bfile_extension(file->relname)) {
+ file->flags |= BLENDERFILE;
+ if(filelist->type==FILE_LOADLIB) {
+ char name[FILE_MAXDIR+FILE_MAXFILE];
+ BLI_strncpy(name, filelist->dir, sizeof(name));
+ strcat(name, file->relname);
+
+ /* prevent current file being used as acceptable dir */
+ if (BLI_streq(G.main->name, name)==0) {
+ file->type &= ~S_IFMT;
+ file->type |= S_IFDIR;
+ }
+ }
+ } else if(BLI_testextensie(file->relname, ".py")) {
+ file->flags |= PYSCRIPTFILE;
+ } else if(BLI_testextensie(file->relname, ".txt")) {
+ file->flags |= TEXTFILE;
+ } else if( BLI_testextensie(file->relname, ".ttf")
+ || BLI_testextensie(file->relname, ".ttc")
+ || BLI_testextensie(file->relname, ".pfb")
+ || BLI_testextensie(file->relname, ".otf")
+ || BLI_testextensie(file->relname, ".otc")) {
+ file->flags |= FTFONTFILE;
+ } else if (has_quicktime){
+ if( BLI_testextensie(file->relname, ".int")
+ || BLI_testextensie(file->relname, ".inta")
+ || BLI_testextensie(file->relname, ".jpg")
+ || BLI_testextensie(file->relname, ".jpeg")
+ || BLI_testextensie(file->relname, ".tga")
+ || BLI_testextensie(file->relname, ".rgb")
+ || BLI_testextensie(file->relname, ".rgba")
+ || BLI_testextensie(file->relname, ".bmp")
+ || BLI_testextensie(file->relname, ".png")
+ || BLI_testextensie(file->relname, ".iff")
+ || BLI_testextensie(file->relname, ".lbm")
+ || BLI_testextensie(file->relname, ".gif")
+ || BLI_testextensie(file->relname, ".psd")
+ || BLI_testextensie(file->relname, ".tif")
+ || BLI_testextensie(file->relname, ".tiff")
+ || BLI_testextensie(file->relname, ".pct")
+ || BLI_testextensie(file->relname, ".pict")
+ || BLI_testextensie(file->relname, ".pntg") //macpaint
+ || BLI_testextensie(file->relname, ".qtif")
+ || BLI_testextensie(file->relname, ".sgi")
+#ifdef WITH_DDS
+ || BLI_testextensie(file->relname, ".dds")
+#endif
+#ifdef WITH_OPENEXR
+ || BLI_testextensie(file->relname, ".exr")
+#endif
+ ) {
+ file->flags |= IMAGEFILE;
+ }
+ else if(BLI_testextensie(file->relname, ".avi")
+ || BLI_testextensie(file->relname, ".flc")
+ || BLI_testextensie(file->relname, ".mov")
+ || BLI_testextensie(file->relname, ".movie")
+ || BLI_testextensie(file->relname, ".mp4")
+ || BLI_testextensie(file->relname, ".m4v")
+ || BLI_testextensie(file->relname, ".mv")) {
+ file->flags |= MOVIEFILE;
+ }
+ else if(BLI_testextensie(file->relname, ".wav")) {
+ file->flags |= SOUNDFILE;
+ }
+ } else { // no quicktime
+ if(BLI_testextensie(file->relname, ".int")
+ || BLI_testextensie(file->relname, ".inta")
+ || BLI_testextensie(file->relname, ".jpg")
+ || BLI_testextensie(file->relname, ".tga")
+ || BLI_testextensie(file->relname, ".rgb")
+ || BLI_testextensie(file->relname, ".rgba")
+ || BLI_testextensie(file->relname, ".bmp")
+ || BLI_testextensie(file->relname, ".png")
+ || BLI_testextensie(file->relname, ".iff")
+ || BLI_testextensie(file->relname, ".tif")
+ || BLI_testextensie(file->relname, ".tiff")
+#ifdef WITH_DDS
+ || BLI_testextensie(file->relname, ".dds")
+#endif
+#ifdef WITH_OPENEXR
+ || BLI_testextensie(file->relname, ".exr")
+#endif
+ || BLI_testextensie(file->relname, ".lbm")
+ || BLI_testextensie(file->relname, ".sgi")) {
+ file->flags |= IMAGEFILE;
+ }
+ else if(BLI_testextensie(file->relname, ".avi")
+ || BLI_testextensie(file->relname, ".mp4")
+ || BLI_testextensie(file->relname, ".mv")) {
+ file->flags |= MOVIEFILE;
+ }
+ else if(BLI_testextensie(file->relname, ".wav")) {
+ file->flags |= SOUNDFILE;
+ }
+ }
+ }
+}
+
+void BIF_filelist_swapselect(struct FileList* filelist)
+{
+ struct direntry *file;
+ int num, act= 0;
+
+ file= filelist->filelist;
+ for(num=0; num<filelist->numfiles; num++, file++) {
+ if(file->flags & ACTIVE) {
+ act= 1;
+ break;
+ }
+ }
+ file= filelist->filelist+2;
+ for(num=2; num<filelist->numfiles; num++, file++) {
+ if(act) file->flags &= ~ACTIVE;
+ else file->flags |= ACTIVE;
+ }
+}
+
+int BIF_filelist_islibrary(struct FileList* filelist, char* dir, char* group)
+{
+ /* return ok when a blenderfile, in dir is the filename,
+ * in group the type of libdata
+ */
+ int len;
+ char *fd;
+
+ strcpy(dir, filelist->dir);
+ len= strlen(dir);
+ if(len<7) return 0;
+ if( dir[len-1] != '/' && dir[len-1] != '\\') return 0;
+
+ group[0]= 0;
+ dir[len-1]= 0;
+
+ /* Find the last slash */
+ fd= (strrchr(dir, '/')>strrchr(dir, '\\'))?strrchr(dir, '/'):strrchr(dir, '\\');
+
+ if(fd==0) return 0;
+ *fd= 0;
+ if(BLO_has_bfile_extension(fd+1)) {
+ *fd= '/';
+ }
+ else {
+ char *gp = fd+1; // in case we have a .blend file, gp points to the group
+
+ /* Find the last slash */
+ fd= (strrchr(dir, '/')>strrchr(dir, '\\'))?strrchr(dir, '/'):strrchr(dir, '\\');
+ if (!fd || !BLO_has_bfile_extension(fd+1)) return 0;
+
+ /* now we know that we are in a blend file and it is safe to
+ assume that gp actually points to a group */
+ BLI_strncpy(group, gp, GROUP_MAX);
+ }
+ return 1;
+}
+
+void BIF_filelist_from_library(struct FileList* filelist)
+{
+ LinkNode *l, *names, *previews;
+ struct ImBuf* ima;
+ int ok, i, nnames, idcode;
+ char filename[FILE_MAXDIR+FILE_MAXFILE];
+ char dir[FILE_MAXDIR], group[GROUP_MAX];
+
+ filelist->type = FILE_LOADLIB;
+
+ /* name test */
+ ok= BIF_filelist_islibrary(filelist, dir, group);
+ if (!ok) {
+ /* free */
+ if(filelist->libfiledata) BLO_blendhandle_close(filelist->libfiledata);
+ filelist->libfiledata= 0;
+ return;
+ }
+
+ BLI_strncpy(filename, G.sce, sizeof(filename)); // G.sce = last file loaded, for UI
+
+ /* there we go */
+ /* for the time being only read filedata when libfiledata==0 */
+ if (filelist->libfiledata==0) {
+ filelist->libfiledata= BLO_blendhandle_from_file(dir);
+ if(filelist->libfiledata==0) return;
+ }
+
+ idcode= BIF_groupname_to_code(group);
+
+ // memory for strings is passed into filelist[i].relname
+ // and free'd in freefilelist
+ previews = NULL;
+ if (idcode) {
+ previews= BLO_blendhandle_get_previews(filelist->libfiledata, idcode);
+ names= BLO_blendhandle_get_datablock_names(filelist->libfiledata, idcode);
+ /* ugh, no rewind, need to reopen */
+ BLO_blendhandle_close(filelist->libfiledata);
+ filelist->libfiledata= BLO_blendhandle_from_file(dir);
+
+ } else {
+ names= BLO_blendhandle_get_linkable_groups(filelist->libfiledata);
+ }
+
+ nnames= BLI_linklist_length(names);
+
+ filelist->numfiles= nnames + 2;
+ filelist->filelist= malloc(filelist->numfiles * sizeof(*filelist->filelist));
+ memset(filelist->filelist, 0, filelist->numfiles * sizeof(*filelist->filelist));
+
+ filelist->filelist[0].relname= BLI_strdup(".");
+ filelist->filelist[0].type |= S_IFDIR;
+ filelist->filelist[1].relname= BLI_strdup("..");
+ filelist->filelist[1].type |= S_IFDIR;
+
+ for (i=0, l= names; i<nnames; i++, l= l->next) {
+ char *blockname= l->link;
+
+ filelist->filelist[i + 2].relname= BLI_strdup(blockname);
+ if (!idcode)
+ filelist->filelist[i + 2].type |= S_IFDIR;
+ }
+
+ if(previews) {
+ for (i=0, l= previews; i<nnames; i++, l= l->next) {
+ PreviewImage *img= l->link;
+
+ if (img) {
+ unsigned int w = img->w[PREVIEW_MIPMAP_LARGE];
+ unsigned int h = img->h[PREVIEW_MIPMAP_LARGE];
+ unsigned int *rect = img->rect[PREVIEW_MIPMAP_LARGE];
+
+ /* first allocate imbuf for copying preview into it */
+ if (w > 0 && h > 0 && rect) {
+ ima = IMB_allocImBuf(w, h, 32, IB_rect, 0);
+ memcpy(ima->rect, rect, w*h*sizeof(unsigned int));
+ filelist->filelist[i + 2].image = ima;
+ filelist->filelist[i + 2].flags = IMAGEFILE;
+ }
+ }
+ }
+ }
+
+ BLI_linklist_free(names, free);
+ if (previews) BLI_linklist_free(previews, (void(*)(void*)) MEM_freeN);
+
+ BIF_filelist_sort(filelist, FILE_SORTALPHA);
+
+ BLI_strncpy(G.sce, filename, sizeof(filename)); // prevent G.sce to change
+
+ filelist->filter = 0;
+ BIF_filelist_filter(filelist);
+}
+
+void BIF_filelist_append_library(struct FileList *filelist, char *dir, char *file, short flag, int idcode)
+{
+ BLO_library_append_(&filelist->libfiledata, filelist->filelist, filelist->numfiles, dir, file, flag, idcode);
+}
+
+void BIF_filelist_from_main(struct FileList *filelist)
+{
+ ID *id;
+ struct direntry *files, *firstlib = NULL;
+ ListBase *lb;
+ int a, fake, idcode, ok, totlib, totbl;
+
+ filelist->type = FILE_MAIN;
+
+ if(filelist->dir[0]=='/') filelist->dir[0]= 0;
+
+ if(filelist->dir[0]) {
+ idcode= BIF_groupname_to_code(filelist->dir);
+ if(idcode==0) filelist->dir[0]= 0;
+ }
+
+ if( filelist->dir[0]==0) {
+
+ /* make directories */
+ filelist->numfiles= 23;
+ filelist->filelist= (struct direntry *)malloc(filelist->numfiles * sizeof(struct direntry));
+
+ for(a=0; a<filelist->numfiles; a++) {
+ memset( &(filelist->filelist[a]), 0 , sizeof(struct direntry));
+ filelist->filelist[a].type |= S_IFDIR;
+ }
+
+ filelist->filelist[0].relname= BLI_strdup("..");
+ filelist->filelist[1].relname= BLI_strdup(".");
+ filelist->filelist[2].relname= BLI_strdup("Scene");
+ filelist->filelist[3].relname= BLI_strdup("Object");
+ filelist->filelist[4].relname= BLI_strdup("Mesh");
+ filelist->filelist[5].relname= BLI_strdup("Curve");
+ filelist->filelist[6].relname= BLI_strdup("Metaball");
+ filelist->filelist[7].relname= BLI_strdup("Material");
+ filelist->filelist[8].relname= BLI_strdup("Texture");
+ filelist->filelist[9].relname= BLI_strdup("Image");
+ filelist->filelist[10].relname= BLI_strdup("Ika");
+ filelist->filelist[11].relname= BLI_strdup("Wave");
+ filelist->filelist[12].relname= BLI_strdup("Lattice");
+ filelist->filelist[13].relname= BLI_strdup("Lamp");
+ filelist->filelist[14].relname= BLI_strdup("Camera");
+ filelist->filelist[15].relname= BLI_strdup("Ipo");
+ filelist->filelist[16].relname= BLI_strdup("World");
+ filelist->filelist[17].relname= BLI_strdup("Screen");
+ filelist->filelist[18].relname= BLI_strdup("VFont");
+ filelist->filelist[19].relname= BLI_strdup("Text");
+ filelist->filelist[20].relname= BLI_strdup("Armature");
+ filelist->filelist[21].relname= BLI_strdup("Action");
+ filelist->filelist[22].relname= BLI_strdup("NodeTree");
+ BIF_filelist_sort(filelist, FILE_SORTALPHA);
+ }
+ else {
+
+ /* make files */
+ idcode= BIF_groupname_to_code(filelist->dir);
+
+ lb= wich_libbase(G.main, idcode );
+ if(lb==0) return;
+
+ id= lb->first;
+ filelist->numfiles= 0;
+ while(id) {
+
+ if(filelist->has_func && idcode==ID_IP) {
+ if(filelist->ipotype== ((Ipo *)id)->blocktype) filelist->numfiles++;
+ }
+ else if (!filelist->hide_dot || id->name[2] != '.') {
+ filelist->numfiles++;
+ }
+
+ id= id->next;
+ }
+
+ if(!filelist->has_func) filelist->numfiles+= 2;
+ filelist->filelist= (struct direntry *)malloc(filelist->numfiles * sizeof(struct direntry));
+
+ files = filelist->filelist;
+
+ if(!filelist->has_func) {
+ memset( &(filelist->filelist[0]), 0 , sizeof(struct direntry));
+ filelist->filelist[0].relname= BLI_strdup(".");
+ filelist->filelist[0].type |= S_IFDIR;
+ memset( &(filelist->filelist[1]), 0 , sizeof(struct direntry));
+ filelist->filelist[1].relname= BLI_strdup("..");
+ filelist->filelist[1].type |= S_IFDIR;
+
+ files+= 2;
+ }
+
+ id= lb->first;
+ totlib= totbl= 0;
+
+ while(id) {
+
+ ok= 0;
+ if(filelist->has_func && idcode==ID_IP) {
+ if(filelist->ipotype== ((Ipo *)id)->blocktype) ok= 1;
+ }
+ else ok= 1;
+
+ if(ok) {
+ /* TODO: hide dot files - elubie */
+ memset( files, 0 , sizeof(struct direntry));
+ if(id->lib==NULL)
+ files->relname= BLI_strdup(id->name+2);
+ else {
+ files->relname= MEM_mallocN(FILE_MAXDIR+FILE_MAXFILE+32, "filename for lib");
+ sprintf(files->relname, "%s | %s", id->lib->name, id->name+2);
+ }
+ /* files->type |= S_IFDIR; */
+ if(!filelist->has_func) { /* F4 DATA BROWSE */
+ if(idcode==ID_OB) {
+ if( ((Object *)id)->flag & SELECT) files->flags |= ACTIVE;
+ }
+ else if(idcode==ID_SCE) {
+ if( ((Scene *)id)->r.scemode & R_BG_RENDER) files->flags |= ACTIVE;
+ }
+ }
+ files->nr= totbl+1;
+ files->poin= id;
+ fake= id->flag & LIB_FAKEUSER;
+ if(idcode == ID_MA || idcode == ID_TE || idcode == ID_LA || idcode == ID_WO || idcode == ID_IM) {
+ files->flags |= IMAGEFILE;
+ }
+ if(id->lib && fake) sprintf(files->extra, "LF %d", id->us);
+ else if(id->lib) sprintf(files->extra, "L %d", id->us);
+ else if(fake) sprintf(files->extra, "F %d", id->us);
+ else sprintf(files->extra, " %d", id->us);
+
+ if(id->lib) {
+ if(totlib==0) firstlib= files;
+ totlib++;
+ }
+
+ files++;
+ totbl++;
+ }
+
+ id= id->next;
+ }
+
+ /* only qsort of library blocks */
+ if(totlib>1) {
+ qsort(firstlib, totlib, sizeof(struct direntry), compare_name);
+ }
+ }
+ filelist->filter = 0;
+ BIF_filelist_filter(filelist);
+}
+
+
+void BIF_filelist_settype(struct FileList* filelist, int type)
+{
+ filelist->type = type;
+}
+
+short BIF_filelist_gettype(struct FileList* filelist)
+{
+ return filelist->type;
+}
+
+void BIF_filelist_sort(struct FileList* filelist, short sort)
+{
+ struct direntry *file;
+ int num;/* , act= 0; */
+
+ switch(sort) {
+ case FILE_SORTALPHA:
+ qsort(filelist->filelist, filelist->numfiles, sizeof(struct direntry), compare_name);
+ break;
+ case FILE_SORTDATE:
+ qsort(filelist->filelist, filelist->numfiles, sizeof(struct direntry), compare_date);
+ break;
+ case FILE_SORTSIZE:
+ qsort(filelist->filelist, filelist->numfiles, sizeof(struct direntry), compare_size);
+ break;
+ case FILE_SORTEXTENS:
+ qsort(filelist->filelist, filelist->numfiles, sizeof(struct direntry), compare_extension);
+ }
+
+ file= filelist->filelist;
+ for(num=0; num<filelist->numfiles; num++, file++) {
+ file->flags &= ~HILITE;
+ }
+ BIF_filelist_filter(filelist);
+}
+
+
+void BIF_filelist_setipotype(struct FileList* filelist, short ipotype)
+{
+ filelist->ipotype = ipotype;
+}
+
+void BIF_filelist_hasfunc(struct FileList* filelist, int has_func)
+{
+ filelist->has_func = has_func;
+}
+
diff --git a/source/blender/src/filesel.c b/source/blender/src/filesel.c
new file mode 100644
index 00000000000..d304125ca9a
--- /dev/null
+++ b/source/blender/src/filesel.c
@@ -0,0 +1,2597 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#ifdef WIN32
+#include <io.h>
+#include <direct.h>
+#include "BLI_winstuff.h"
+#else
+#include <unistd.h>
+#include <sys/times.h>
+#endif
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include "MEM_guardedalloc.h"
+
+#include "BMF_Api.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_linklist.h"
+#include "BLI_storage_types.h"
+#include "BLI_dynstr.h"
+
+#include "IMB_imbuf.h"
+
+#include "DNA_armature_types.h"
+#include "DNA_action_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_image_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_space_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_vfont_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_action.h"
+#include "BKE_constraint.h"
+#include "BKE_curve.h"
+#include "BKE_depsgraph.h"
+#include "BKE_font.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_editview.h"
+#include "BIF_filelist.h"
+#include "BIF_gl.h"
+#include "BIF_interface.h"
+#include "BIF_language.h"
+#include "BIF_mywindow.h"
+#include "BIF_resources.h"
+#include "BIF_space.h"
+#include "BIF_screen.h"
+#include "BIF_toolbox.h"
+#include "BIF_usiblender.h"
+
+#include "BLO_readfile.h"
+
+#include "BDR_editcurve.h"
+#include "BDR_editobject.h"
+
+#include "BPI_script.h"
+#include "BSE_filesel.h"
+#include "BSE_view.h"
+
+#include "mydevice.h"
+#include "blendef.h"
+#include "nla.h"
+
+#include "BIF_fsmenu.h" /* include ourselves */
+
+#ifdef INTERNATIONAL
+#include "FTF_Api.h"
+#endif
+
+#if defined WIN32 || defined __BeOS
+static int fnmatch(const char *pattern, const char *string, int flags)
+{
+ return 0;
+}
+#else
+ #include <fnmatch.h>
+#endif
+
+#ifndef WIN32
+#include <sys/param.h>
+#endif
+
+#define FILESELHEAD 60
+#define FILESEL_DY 16
+
+/* for events */
+#define NOTACTIVE 0
+#define ACTIVATE 1
+#define INACTIVATE 2
+/* for state of file */
+#define ACTIVE 2
+
+#define STARTSWITH(x, y) (strncmp(x, y, sizeof(x) - 1) == 0)
+
+/* button events */
+#define B_FS_FILENAME 1
+#define B_FS_DIRNAME 2
+#define B_FS_DIR_MENU 3
+#define B_FS_PARDIR 4
+#define B_FS_LOAD 5
+#define B_FS_CANCEL 6
+#define B_FS_LIBNAME 7
+
+/* max length of library group name within filesel */
+#define GROUP_MAX 32
+
+static int is_a_library(SpaceFile *sfile, char *dir, char *group);
+static void do_library_append(SpaceFile *sfile);
+static void library_to_filelist(SpaceFile *sfile);
+static void filesel_select_objects(struct SpaceFile *sfile);
+static void active_file_object(struct SpaceFile *sfile);
+static int groupname_to_code(char *group);
+
+extern void countall(void);
+
+/* very bad local globals */
+
+static rcti scrollrct, textrct, bar;
+static int filebuty1, filebuty2, page_ofs, collumwidth, selecting=0;
+static int filetoname= 0;
+static float pixels_to_ofs;
+static char otherdir[FILE_MAX];
+static ScrArea *otherarea;
+
+/* ******************* SORT ******************* */
+
+static int compare_name(const void *a1, const void *a2)
+{
+ const struct direntry *entry1=a1, *entry2=a2;
+
+ /* type is is equal to stat.st_mode */
+
+ if (S_ISDIR(entry1->type)){
+ if (S_ISDIR(entry2->type)==0) return (-1);
+ } else{
+ if (S_ISDIR(entry2->type)) return (1);
+ }
+ if (S_ISREG(entry1->type)){
+ if (S_ISREG(entry2->type)==0) return (-1);
+ } else{
+ if (S_ISREG(entry2->type)) return (1);
+ }
+ if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1);
+ if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1);
+
+ /* make sure "." and ".." are always first */
+ if( strcmp(entry1->relname, ".")==0 ) return (-1);
+ if( strcmp(entry2->relname, ".")==0 ) return (1);
+ if( strcmp(entry1->relname, "..")==0 ) return (-1);
+
+ return (BLI_strcasecmp(entry1->relname,entry2->relname));
+}
+
+static int compare_date(const void *a1, const void *a2)
+{
+ const struct direntry *entry1=a1, *entry2=a2;
+
+ /* type is equal to stat.st_mode */
+
+ if (S_ISDIR(entry1->type)){
+ if (S_ISDIR(entry2->type)==0) return (-1);
+ } else{
+ if (S_ISDIR(entry2->type)) return (1);
+ }
+ if (S_ISREG(entry1->type)){
+ if (S_ISREG(entry2->type)==0) return (-1);
+ } else{
+ if (S_ISREG(entry2->type)) return (1);
+ }
+ if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1);
+ if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1);
+
+ /* make sure "." and ".." are always first */
+ if( strcmp(entry1->relname, ".")==0 ) return (-1);
+ if( strcmp(entry2->relname, ".")==0 ) return (1);
+ if( strcmp(entry1->relname, "..")==0 ) return (-1);
+
+ if ( entry1->s.st_mtime < entry2->s.st_mtime) return 1;
+ if ( entry1->s.st_mtime > entry2->s.st_mtime) return -1;
+
+ else return BLI_strcasecmp(entry1->relname,entry2->relname);
+}
+
+static int compare_size(const void *a1, const void *a2)
+{
+ const struct direntry *entry1=a1, *entry2=a2;
+
+ /* type is equal to stat.st_mode */
+
+ if (S_ISDIR(entry1->type)){
+ if (S_ISDIR(entry2->type)==0) return (-1);
+ } else{
+ if (S_ISDIR(entry2->type)) return (1);
+ }
+ if (S_ISREG(entry1->type)){
+ if (S_ISREG(entry2->type)==0) return (-1);
+ } else{
+ if (S_ISREG(entry2->type)) return (1);
+ }
+ if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1);
+ if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1);
+
+ /* make sure "." and ".." are always first */
+ if( strcmp(entry1->relname, ".")==0 ) return (-1);
+ if( strcmp(entry2->relname, ".")==0 ) return (1);
+ if( strcmp(entry1->relname, "..")==0 ) return (-1);
+
+ if ( entry1->s.st_size < entry2->s.st_size) return 1;
+ if ( entry1->s.st_size > entry2->s.st_size) return -1;
+ else return BLI_strcasecmp(entry1->relname,entry2->relname);
+}
+
+static int compare_extension(const void *a1, const void *a2) {
+ const struct direntry *entry1=a1, *entry2=a2;
+ char *sufix1, *sufix2;
+ char *nil="";
+
+ if (!(sufix1= strstr (entry1->relname, ".blend.gz")))
+ sufix1= strrchr (entry1->relname, '.');
+ if (!(sufix2= strstr (entry2->relname, ".blend.gz")))
+ sufix2= strrchr (entry2->relname, '.');
+ if (!sufix1) sufix1= nil;
+ if (!sufix2) sufix2= nil;
+
+ /* type is is equal to stat.st_mode */
+
+ if (S_ISDIR(entry1->type)){
+ if (S_ISDIR(entry2->type)==0) return (-1);
+ } else{
+ if (S_ISDIR(entry2->type)) return (1);
+ }
+ if (S_ISREG(entry1->type)){
+ if (S_ISREG(entry2->type)==0) return (-1);
+ } else{
+ if (S_ISREG(entry2->type)) return (1);
+ }
+ if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1);
+ if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1);
+
+ /* make sure "." and ".." are always first */
+ if( strcmp(entry1->relname, ".")==0 ) return (-1);
+ if( strcmp(entry2->relname, ".")==0 ) return (1);
+ if( strcmp(entry1->relname, "..")==0 ) return (-1);
+ if( strcmp(entry2->relname, "..")==0 ) return (-1);
+
+ return (BLI_strcasecmp(sufix1, sufix2));
+}
+
+/* **************************************** */
+static int filesel_has_func(SpaceFile *sfile)
+{
+ if(sfile->returnfunc || sfile->returnfunc_event || sfile->returnfunc_args)
+ return 1;
+ return 0;
+}
+
+void filesel_statistics(SpaceFile *sfile, int *totfile, int *selfile, float *totlen, float *sellen)
+{
+ double len;
+ int a;
+
+ *totfile= *selfile= 0;
+ *totlen= *sellen= 0;
+
+ if(sfile->filelist==0) return;
+
+ for(a=0; a<sfile->totfile; a++) {
+ if( (sfile->filelist[a].type & S_IFDIR)==0 ) {
+ (*totfile) ++;
+
+ len = sfile->filelist[a].s.st_size;
+ (*totlen) += (float)(len/1048576.0);
+
+ if(sfile->filelist[a].flags & ACTIVE) {
+ (*selfile) ++;
+ (*sellen) += (float)(len/1048576.0);
+ }
+ }
+ }
+}
+
+/* *************** HELP FUNCTIONS ******************* */
+
+
+/* not called when browsing .blend itself */
+void test_flags_file(SpaceFile *sfile)
+{
+ struct direntry *file;
+ int num;
+
+ file= sfile->filelist;
+
+ for(num=0; num<sfile->totfile; num++, file++) {
+ file->flags= 0;
+ file->type= file->s.st_mode; /* restore the mess below */
+
+ /* Don't check extensions for directories */
+ if (file->type & S_IFDIR)
+ continue;
+
+ if(sfile->type==FILE_BLENDER || sfile->type==FILE_LOADLIB) {
+ if(BLO_has_bfile_extension(file->relname)) {
+ file->flags |= BLENDERFILE;
+
+ if(sfile->type==FILE_LOADLIB) {
+ char name[FILE_MAX];
+ BLI_strncpy(name, sfile->dir, sizeof(name));
+ strcat(name, file->relname);
+
+ /* prevent current file being used as acceptable dir */
+ if (BLI_streq(G.main->name, name)==0) {
+ file->type &= ~S_IFMT;
+ file->type |= S_IFDIR;
+ }
+ }
+ }
+ } else if (sfile->type==FILE_SPECIAL || sfile->type==FILE_LOADFONT){
+ if(BLI_testextensie(file->relname, ".py")) {
+ file->flags |= PYSCRIPTFILE;
+ } else if( BLI_testextensie(file->relname, ".ttf")
+ || BLI_testextensie(file->relname, ".ttc")
+ || BLI_testextensie(file->relname, ".pfb")
+ || BLI_testextensie(file->relname, ".otf")
+ || BLI_testextensie(file->relname, ".otc")) {
+ file->flags |= FTFONTFILE;
+ } else if (G.have_libtiff &&
+ (BLI_testextensie(file->relname, ".tif")
+ || BLI_testextensie(file->relname, ".tiff"))) {
+ file->flags |= IMAGEFILE;
+ } else if (BLI_testextensie(file->relname, ".exr")) {
+ file->flags |= IMAGEFILE;
+ } else if (G.have_quicktime){
+ if( BLI_testextensie(file->relname, ".jpg")
+ || BLI_testextensie(file->relname, ".jpeg")
+ || BLI_testextensie(file->relname, ".hdr")
+ || BLI_testextensie(file->relname, ".exr")
+ || BLI_testextensie(file->relname, ".tga")
+ || BLI_testextensie(file->relname, ".rgb")
+ || BLI_testextensie(file->relname, ".bmp")
+ || BLI_testextensie(file->relname, ".png")
+#ifdef WITH_DDS
+ || BLI_testextensie(file->relname, ".dds")
+#endif
+ || BLI_testextensie(file->relname, ".iff")
+ || BLI_testextensie(file->relname, ".lbm")
+ || BLI_testextensie(file->relname, ".gif")
+ || BLI_testextensie(file->relname, ".psd")
+ || BLI_testextensie(file->relname, ".tif")
+ || BLI_testextensie(file->relname, ".tiff")
+ || BLI_testextensie(file->relname, ".pct")
+ || BLI_testextensie(file->relname, ".pict")
+ || BLI_testextensie(file->relname, ".pntg") //macpaint
+ || BLI_testextensie(file->relname, ".qtif")
+ || BLI_testextensie(file->relname, ".cin")
+ || BLI_testextensie(file->relname, ".dpx")
+ || BLI_testextensie(file->relname, ".sgi")) {
+ file->flags |= IMAGEFILE;
+ }
+ else if(BLI_testextensie(file->relname, ".avi")
+ || BLI_testextensie(file->relname, ".flc")
+ || BLI_testextensie(file->relname, ".dv")
+ || BLI_testextensie(file->relname, ".mov")
+ || BLI_testextensie(file->relname, ".movie")
+ || BLI_testextensie(file->relname, ".mv")) {
+ file->flags |= MOVIEFILE;
+ }
+ } else { // no quicktime
+ if(BLI_testextensie(file->relname, ".jpg")
+ || BLI_testextensie(file->relname, ".hdr")
+ || BLI_testextensie(file->relname, ".exr")
+ || BLI_testextensie(file->relname, ".tga")
+ || BLI_testextensie(file->relname, ".rgb")
+ || BLI_testextensie(file->relname, ".bmp")
+ || BLI_testextensie(file->relname, ".png")
+#ifdef WITH_DDS
+ || BLI_testextensie(file->relname, ".dds")
+#endif
+ || BLI_testextensie(file->relname, ".iff")
+ || BLI_testextensie(file->relname, ".lbm")
+ || BLI_testextensie(file->relname, ".cin")
+ || BLI_testextensie(file->relname, ".dpx")
+ || BLI_testextensie(file->relname, ".sgi")) {
+ file->flags |= IMAGEFILE;
+ }
+ else if(BLI_testextensie(file->relname, ".avi")
+ || BLI_testextensie(file->relname, ".mv")) {
+ file->flags |= MOVIEFILE;
+ }
+ else if(BLI_testextensie(file->relname, ".wav")) {
+ file->flags |= SOUNDFILE;
+ }
+ }
+ }
+ }
+}
+
+
+void sort_filelist(SpaceFile *sfile)
+{
+ struct direntry *file;
+ int num;/* , act= 0; */
+
+ switch(sfile->sort) {
+ case FILE_SORTALPHA:
+ qsort(sfile->filelist, sfile->totfile, sizeof(struct direntry), compare_name);
+ break;
+ case FILE_SORTDATE:
+ qsort(sfile->filelist, sfile->totfile, sizeof(struct direntry), compare_date);
+ break;
+ case FILE_SORTSIZE:
+ qsort(sfile->filelist, sfile->totfile, sizeof(struct direntry), compare_size);
+ break;
+ case FILE_SORTEXTENS:
+ qsort(sfile->filelist, sfile->totfile, sizeof(struct direntry), compare_extension);
+ }
+
+ sfile->act= -1;
+
+ file= sfile->filelist;
+ for(num=0; num<sfile->totfile; num++, file++) {
+ file->flags &= ~HILITE;
+ }
+
+}
+
+void read_dir(SpaceFile *sfile)
+{
+ int num, len;
+ char wdir[FILE_MAX];
+
+ /* sfile->act is used for example in databrowse: double names of library objects */
+ sfile->act= -1;
+
+ if(sfile->type==FILE_MAIN) {
+ main_to_filelist(sfile);
+ return;
+ }
+ else if(sfile->type==FILE_LOADLIB) {
+ library_to_filelist(sfile);
+ if(sfile->libfiledata) return;
+ }
+
+ BLI_hide_dot_files(sfile->flag & FILE_HIDE_DOT);
+
+ BLI_getwdN(wdir);
+ sfile->totfile= BLI_getdir(sfile->dir, &(sfile->filelist));
+ chdir(wdir);
+
+ if(sfile->sort!=FILE_SORTALPHA) sort_filelist(sfile);
+
+ sfile->maxnamelen= 0;
+
+ for (num=0; num<sfile->totfile; num++) {
+
+ len = BMF_GetStringWidth(G.font, sfile->filelist[num].relname);
+ if (len > sfile->maxnamelen) sfile->maxnamelen = len;
+
+ if(filetoname) {
+ if(strcmp(sfile->file, sfile->filelist[num].relname)==0) {
+
+ sfile->ofs= num-( sfile->collums*(curarea->winy-FILESELHEAD-20)/(2*FILESEL_DY));
+ filetoname= 0;
+ }
+ }
+ }
+ test_flags_file(sfile);
+
+ filetoname= 0;
+}
+
+void freefilelist(SpaceFile *sfile)
+{
+ int num;
+
+ num= sfile->totfile-1;
+
+ if (sfile->filelist==0) return;
+
+ for(; num>=0; num--){
+ MEM_freeN(sfile->filelist[num].relname);
+
+ if (sfile->filelist[num].string) MEM_freeN(sfile->filelist[num].string);
+ }
+ free(sfile->filelist);
+ sfile->filelist= 0;
+}
+
+static void split_sfile(SpaceFile *sfile, char *s1)
+{
+ char string[FILE_MAX], dir[FILE_MAX], file[FILE_MAX];
+
+ BLI_strncpy(string, s1, sizeof(string));
+
+ BLI_split_dirfile(string, dir, file);
+
+ if(sfile->filelist) {
+ if(strcmp(dir, sfile->dir)!=0) {
+ freefilelist(sfile);
+ }
+ else test_flags_file(sfile);
+ }
+ BLI_strncpy(sfile->file, file, sizeof(sfile->file));
+
+ BLI_make_file_string(G.sce, sfile->dir, dir, "");
+}
+
+
+void parent(SpaceFile *sfile)
+{
+ short a;
+ char *dir;
+
+ /* if databrowse: no parent */
+ if(sfile->type==FILE_MAIN && filesel_has_func(sfile)) return;
+
+ dir= sfile->dir;
+
+#ifdef WIN32
+ if( (a = strlen(dir)) ) { /* remove all '/' at the end */
+ while(dir[a-1] == '\\') {
+ a--;
+ dir[a] = 0;
+ if (a<=0) break;
+ }
+ }
+ if( (a = strlen(dir)) ) { /* then remove all until '/' */
+ while(dir[a-1] != '\\') {
+ a--;
+ dir[a] = 0;
+ if (a<=0) break;
+ }
+ }
+ if( (a = strlen(dir)) ) {
+ if (dir[a-1] != '\\') strcat(dir,"\\");
+ }
+ else if(sfile->type!=FILE_MAIN) {
+ get_default_root(dir);
+ }
+#else
+ if( (a = strlen(dir)) ) { /* remove all '/' at the end */
+ while(dir[a-1] == '/') {
+ a--;
+ dir[a] = 0;
+ if (a<=0) break;
+ }
+ }
+ if( (a = strlen(dir)) ) { /* then remove until '/' */
+ while(dir[a-1] != '/') {
+ a--;
+ dir[a] = 0;
+ if (a<=0) break;
+ }
+ }
+ if ( (a = strlen(dir)) ) {
+ if (dir[a-1] != '/') strcat(dir,"/");
+ }
+ else if(sfile->type!=FILE_MAIN) strcpy(dir,"/");
+#endif
+
+ /* to be sure */
+ BLI_make_exist(sfile->dir);
+
+ freefilelist(sfile);
+ sfile->ofs= 0;
+ scrarea_queue_winredraw(curarea);
+}
+
+void swapselect_file(SpaceFile *sfile)
+{
+ struct direntry *file;
+ int num, act= 0;
+
+ file= sfile->filelist;
+ for(num=0; num<sfile->totfile; num++, file++) {
+ if(file->flags & ACTIVE) {
+ act= 1;
+ break;
+ }
+ }
+ file= sfile->filelist+2;
+ for(num=2; num<sfile->totfile; num++, file++) {
+ if(act) file->flags &= ~ACTIVE;
+ else file->flags |= ACTIVE;
+ }
+}
+
+static int find_active_file(SpaceFile *sfile, short x, short y)
+{
+ int ofs;
+
+ if(y > textrct.ymax) y= textrct.ymax;
+ if(y <= textrct.ymin) y= textrct.ymin+1;
+
+ ofs= (x-textrct.xmin)/collumwidth;
+ if(ofs<0) ofs= 0;
+ ofs*= (textrct.ymax-textrct.ymin);
+
+ return sfile->ofs+ (ofs+textrct.ymax-y)/FILESEL_DY;
+
+}
+
+
+/* ********************** DRAW ******************************* */
+
+static void calc_file_rcts(SpaceFile *sfile)
+{
+ int tot, h, len;
+ float fac, start, totfile;
+
+ scrollrct.xmin= 15;
+ scrollrct.xmax= 35;
+ scrollrct.ymin= 10;
+ scrollrct.ymax= curarea->winy-10-FILESELHEAD;
+
+ textrct.xmin= scrollrct.xmax+10;
+ textrct.xmax= curarea->winx-10;
+ textrct.ymin= scrollrct.ymin;
+ textrct.ymax= scrollrct.ymax;
+
+ if(textrct.xmax-textrct.xmin <60) textrct.xmax= textrct.xmin+60;
+
+ len= (textrct.ymax-textrct.ymin) % FILESEL_DY;
+ textrct.ymin+= len;
+ scrollrct.ymin+= len;
+
+ filebuty1= curarea->winy-FILESELHEAD;
+ filebuty2= filebuty1+FILESELHEAD/2 -6;
+
+
+ /* amount of collums */
+ len= sfile->maxnamelen+25;
+
+ if(sfile->type==FILE_MAIN) len+= 100;
+ else if(sfile->flag & FILE_SHOWSHORT) len+= 100;
+ else len+= 380;
+
+ sfile->collums= (textrct.xmax-textrct.xmin)/len;
+
+ if(sfile->collums<1) sfile->collums= 1;
+ else if(sfile->collums>8) sfile->collums= 8;
+
+ /* this flag aint yet defined in user menu, needed? */
+// if((U.flag & USER_FSCOLLUM)==0) sfile->collums= 1;
+
+ collumwidth= (textrct.xmax-textrct.xmin)/sfile->collums;
+
+
+ totfile= sfile->totfile + 0.5f;
+
+ tot= (int)(FILESEL_DY*totfile);
+ if(tot) fac= ((float)sfile->collums*(scrollrct.ymax-scrollrct.ymin))/( (float)tot);
+ else fac= 1.0;
+
+ if(sfile->ofs<0) sfile->ofs= 0;
+
+ if(tot) start= ( (float)sfile->ofs)/(totfile);
+ else start= 0.0;
+ if(fac>1.0) fac= 1.0f;
+
+ if(start+fac>1.0) {
+ sfile->ofs= (short)ceil((1.0-fac)*totfile);
+ start= ( (float)sfile->ofs)/(totfile);
+ fac= 1.0f-start;
+ }
+
+ bar.xmin= scrollrct.xmin+2;
+ bar.xmax= scrollrct.xmax-2;
+ h= (scrollrct.ymax-scrollrct.ymin)-4;
+ bar.ymax= (int)(scrollrct.ymax-2- start*h);
+ bar.ymin= (int)(bar.ymax- fac*h);
+
+ pixels_to_ofs= (totfile)/(float)(h+3);
+ page_ofs= (int)(fac*totfile);
+}
+
+int filescrollselect= 0;
+
+static void draw_filescroll(SpaceFile *sfile)
+{
+
+ if(scrollrct.ymin+10 >= scrollrct.ymax) return;
+
+ BIF_ThemeColor(TH_BACK);
+ glRecti(scrollrct.xmin, scrollrct.ymin, scrollrct.xmax, scrollrct.ymax);
+
+ uiEmboss(scrollrct.xmin, scrollrct.ymin, scrollrct.xmax, scrollrct.ymax, 1);
+
+ BIF_ThemeColor(TH_HEADER);
+ glRecti(bar.xmin+2, bar.ymin+2, bar.xmax-2, bar.ymax-2);
+
+ uiEmboss(bar.xmin+2, bar.ymin+2, bar.xmax-2, bar.ymax-2, filescrollselect);
+
+}
+
+static void linerect(int id, int x, int y)
+{
+ if(id & ACTIVE) {
+ if(id & HILITE) BIF_ThemeColorShade(TH_HILITE, 20);
+ else BIF_ThemeColor(TH_HILITE);
+ }
+ else if(id & HILITE) BIF_ThemeColorShade(TH_BACK, 20);
+ else BIF_ThemeColor(TH_BACK);
+
+ glRects(x-17, y-3, x+collumwidth-21, y+11);
+
+}
+
+static void print_line(SpaceFile *sfile, struct direntry *files, int x, int y)
+{
+ int boxcol=0;
+ char *s;
+
+ boxcol= files->flags & (HILITE + ACTIVE);
+
+ if(boxcol) {
+ linerect(boxcol, x, y);
+ }
+
+ // this is where the little boxes in the file view are being drawn according to the file type
+ if(files->flags & BLENDERFILE) {
+ cpack(0xA0A0);
+ glRects(x-14, y, x-8, y+7);
+ }
+ else if(files->flags & PSXFILE) {
+ cpack(0xA060B0);
+ glRects(x-14, y, x-8, y+7);
+ }
+ else if(files->flags & IMAGEFILE) {
+ cpack(0xF08040);
+ glRects(x-14, y, x-8, y+7);
+ }
+ else if(files->flags & MOVIEFILE) {
+ cpack(0x70A070);
+ glRects(x-14, y, x-8, y+7);
+ }
+ else if(files->flags & PYSCRIPTFILE) {
+ cpack(0x4477dd);
+ glRects(x-14, y, x-8, y+7);
+ }
+ else if(files->flags & SOUNDFILE) {
+ cpack(0xa0a000);
+ glRects(x-14, y, x-8, y+7);
+ }
+ else if(files->flags & FTFONTFILE) {
+ cpack(0xff2371);
+ glRects(x-14, y, x-8, y+7);
+ }
+
+ if(S_ISDIR(files->type)) BIF_ThemeColor(TH_TEXT_HI);
+ else BIF_ThemeColor(TH_TEXT);
+
+ s = files->string;
+ if(s) {
+ glRasterPos2i(x, y);
+#ifdef WITH_ICONV
+ {
+ struct LANGMenuEntry *lme;
+ lme = find_language(U.language);
+
+ if ((lme !=NULL) && (!strcmp(lme->code, "ja_JP") ||
+ !strcmp(lme->code, "zh_CN")))
+ {
+ BIF_RasterPos((float)x, (float)y);
+#ifdef WIN32
+ BIF_DrawString(G.font, files->relname, ((U.transopts & USER_TR_MENUS) | CONVERT_TO_UTF8));
+#else
+ BIF_DrawString(G.font, files->relname, (U.transopts & USER_TR_MENUS));
+#endif
+ } else {
+ BMF_DrawString(G.font, files->relname);
+ }
+ }
+#else
+ BMF_DrawString(G.font, files->relname);
+#endif /* WITH_ICONV */
+
+ x += sfile->maxnamelen + 100;
+
+ glRasterPos2i(x - BMF_GetStringWidth(G.font, files->size), y);
+ BMF_DrawString(G.font, files->size);
+
+ if(sfile->flag & FILE_SHOWSHORT) return;
+
+#ifndef WIN32
+ /* rwx rwx rwx */
+ x += 20; glRasterPos2i(x, y);
+ BMF_DrawString(G.font, files->mode1);
+
+ x += 30; glRasterPos2i(x, y);
+ BMF_DrawString(G.font, files->mode2);
+
+ x += 30; glRasterPos2i(x, y);
+ BMF_DrawString(G.font, files->mode3);
+
+ /* owner time date */
+ x += 30; glRasterPos2i(x, y);
+ BMF_DrawString(G.font, files->owner);
+#endif
+
+ x += 60; glRasterPos2i(x, y);
+ BMF_DrawString(G.font, files->time);
+
+ x += 50; glRasterPos2i(x, y);
+ BMF_DrawString(G.font, files->date);
+ }
+ else {
+ glRasterPos2i(x, y);
+ BMF_DrawString(G.font, files->relname);
+
+ if(files->nr) { /* extra info */
+ x+= sfile->maxnamelen+20;
+ glRasterPos2i(x, y);
+ BMF_DrawString(G.font, files->extra);
+ }
+ }
+}
+
+
+static int calc_filesel_line(SpaceFile *sfile, int nr, int *valx, int *valy)
+{
+ /* get screen coordinate of a line */
+ int val, coll;
+
+ nr-= sfile->ofs;
+
+ /* amount of lines */
+ val= (textrct.ymax-textrct.ymin)/FILESEL_DY;
+ if (val == 0) coll = 0;
+ else coll= nr/val;
+ nr -= coll*val;
+
+ *valy= textrct.ymax-FILESEL_DY+3 - nr*FILESEL_DY;
+ *valx= coll*collumwidth + textrct.xmin+20;
+
+ if(nr<0 || coll > sfile->collums) return 0;
+ return 1;
+}
+
+static void set_active_file(SpaceFile *sfile, int act)
+{
+ struct direntry *file;
+ int num, redraw= 0;
+ unsigned int newflag;
+ int old=0, newi=0;
+
+ file= sfile->filelist;
+ if(file==0) return;
+
+ for(num=0; num<sfile->totfile; num++, file++) {
+ if(num==act) {
+
+ if(selecting && num>1) {
+ newflag= HILITE | (file->flags & ~ACTIVE);
+ if(selecting==ACTIVATE) newflag |= ACTIVE;
+
+ if(file->flags != newflag) redraw|= 1;
+ file->flags= newflag;
+ }
+ else {
+ if(file->flags & HILITE);
+ else {
+ file->flags |= HILITE;
+ redraw|= 2;
+ newi= num;
+ }
+ }
+ }
+ else {
+ if(file->flags & HILITE) {
+ file->flags &= ~HILITE;
+ redraw|= 2;
+ old= num;
+ }
+ }
+
+ }
+ // removed frontbuffer draw here
+ if(redraw) {
+ scrarea_queue_winredraw(curarea);
+ }
+}
+
+
+static void draw_filetext(SpaceFile *sfile)
+{
+ struct direntry *files;
+ int a, x, y;
+ short mval[2];
+
+ if(textrct.ymin+10 >= textrct.ymax) return;
+
+
+ /* box */
+ BIF_ThemeColor(TH_BACK);
+ glRecti(textrct.xmin, textrct.ymin, textrct.xmax, textrct.ymax);
+
+ /* collums */
+ x= textrct.xmin+collumwidth;
+ for(a=1; a<sfile->collums; a++, x+= collumwidth) {
+ cpack(0x303030);
+ sdrawline(x, textrct.ymin, x, textrct.ymax);
+ cpack(0xB0B0B0);
+ sdrawline(x+1, textrct.ymin, x+1, textrct.ymax);
+ }
+
+ if(sfile->filelist==0) return;
+
+ /* test: if mouse is not in area: clear HILITE */
+ getmouseco_areawin(mval);
+
+ if(mval[0]<0 || mval[0]>curarea->winx) {
+ files= sfile->filelist+sfile->ofs;
+ for(a= sfile->ofs; a<sfile->totfile; a++, files++) files->flags &= ~HILITE;
+ }
+
+ files= sfile->filelist+sfile->ofs;
+ for(a= sfile->ofs; a<sfile->totfile; a++, files++) {
+
+ if( calc_filesel_line(sfile, a, &x, &y)==0 ) break;
+ print_line(sfile, files, x, y);
+ }
+
+ /* clear drawing errors, with text at the right hand side: */
+ BIF_ThemeColor(TH_HEADER);
+ glRecti(textrct.xmax, textrct.ymin, textrct.xmax+10, textrct.ymax);
+ uiEmboss(textrct.xmin, textrct.ymin, textrct.xmax, textrct.ymax, 1);
+}
+
+static char *library_string(void)
+{
+ Library *lib;
+ char *str;
+ int nr=0, tot= BLI_countlist(&G.main->library);
+
+ if(tot==0) return NULL;
+ str= MEM_callocN(tot*(FILE_MAXDIR+FILE_MAX), "filesel lib menu");
+
+ for(tot=0, lib= G.main->library.first; lib; lib= lib->id.next, nr++) {
+ tot+= sprintf(str+tot, "%s %%x%d|", lib->name, nr);
+ }
+ return str;
+}
+
+void drawfilespace(ScrArea *sa, void *spacedata)
+{
+ SpaceFile *sfile;
+ uiBlock *block;
+ float col[3];
+ int act, loadbutton;
+ short mval[2];
+ char name[20];
+ char *menu, *strp= NULL;
+
+ myortho2(-0.375, sa->winx-0.375, -0.375, sa->winy-0.375);
+
+ BIF_GetThemeColor3fv(TH_HEADER, col); // basic undrawn color is border
+ glClearColor(col[0], col[1], col[2], 0.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ sfile= sa->spacedata.first;
+ if(sfile->filelist==NULL) {
+ read_dir(sfile);
+
+ calc_file_rcts(sfile);
+
+ /* calculate act */
+ getmouseco_areawin(mval);
+ act= find_active_file(sfile, mval[0], mval[1]);
+ if(act>=0 && act<sfile->totfile)
+ sfile->filelist[act].flags |= HILITE;
+ }
+ else calc_file_rcts(sfile);
+
+ /* check if we load library, extra button */
+ if(sfile->type==FILE_LOADLIB)
+ strp= library_string();
+
+ /* HEADER */
+ sprintf(name, "win %d", sa->win);
+ block= uiNewBlock(&sa->uiblocks, name, UI_EMBOSS, UI_HELV, sa->win);
+
+ /* browse 1 datablock */
+ uiSetButLock( sfile->type==FILE_MAIN && filesel_has_func(sfile), NULL);
+
+ /* space available for load/save buttons? */
+ loadbutton= MAX2(80, 20+BMF_GetStringWidth(G.font, sfile->title));
+ if(textrct.xmax-textrct.xmin > loadbutton+20) {
+ if(sfile->title[0]==0) loadbutton= 0;
+ }
+ else loadbutton= 0;
+
+ uiBlockBeginAlign(block);
+ uiDefBut(block, TEX, B_FS_DIRNAME,"", textrct.xmin + (strp?20:0), filebuty2, textrct.xmax-textrct.xmin-loadbutton - (strp?20:0), 21, sfile->dir, 0.0, (float)FILE_MAXDIR-1, 0, 0, "Directory, enter a directory and press enter to create it"); /* Directory input */
+ if(loadbutton) {
+ uiSetCurFont(block, UI_HELV);
+ uiDefBut(block, BUT, B_FS_LOAD, sfile->title, textrct.xmax-loadbutton, filebuty2, loadbutton, 21, sfile->dir, 0.0, (float)FILE_MAXFILE-1, 0, 0, "");
+ }
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefBut(block, TEX, B_FS_FILENAME,"", textrct.xmin, filebuty1, textrct.xmax-textrct.xmin-loadbutton, 21, sfile->file, 0.0, (float)FILE_MAXFILE-1, 0, 0, "File, increment version number with (+/-)"); /* File input */
+ if(loadbutton) {
+ uiSetCurFont(block, UI_HELV);
+ uiDefBut(block, BUT, B_FS_CANCEL, "Cancel", textrct.xmax-loadbutton, filebuty1, loadbutton, 21, sfile->file, 0.0, (float)FILE_MAXFILE-1, 0, 0, "");
+ }
+ uiBlockEndAlign(block);
+
+ menu= fsmenu_build_menu();
+ if(menu[0]) /* happens when no .Bfs is there, and first time browse */
+ uiDefButS(block, MENU, B_FS_DIR_MENU, menu, scrollrct.xmin, filebuty1, scrollrct.xmax-scrollrct.xmin, 21, &sfile->menu, 0, 0, 0, 0, "");
+ MEM_freeN(menu);
+
+ uiBlockBeginAlign(block);
+ uiDefBut(block, BUT, B_FS_PARDIR, "P", scrollrct.xmin, filebuty2, scrollrct.xmax-scrollrct.xmin, 21, 0, 0, 0, 0, 0, "Move to the parent directory (PKEY)");
+ if(strp) {
+ uiDefIconTextButS(block, MENU, B_FS_LIBNAME, ICON_LIBRARY_DEHLT, strp, scrollrct.xmin+20, filebuty2, scrollrct.xmax-scrollrct.xmin, 21, &sfile->menu, 0, 0, 0, 0, "");
+ MEM_freeN(strp);
+ }
+
+ uiDrawBlock(block);
+
+ draw_filescroll(sfile);
+ draw_filetext(sfile);
+
+ /* others diskfree etc ? */
+ scrarea_queue_headredraw(sa);
+
+ myortho2(-0.375, (float)(sa->winx)-0.375, -0.375, (float)(sa->winy)-0.375);
+ draw_area_emboss(sa);
+
+ sa->win_swap= WIN_BACK_OK;
+}
+
+
+static void do_filescroll(SpaceFile *sfile)
+{
+ short mval[2], oldy, yo;
+
+ calc_file_rcts(sfile);
+
+ filescrollselect= 1;
+
+ /* for beauty */
+ scrarea_do_windraw(curarea);
+ screen_swapbuffers();
+
+ getmouseco_areawin(mval);
+ oldy= yo= mval[1];
+
+ while(get_mbut()&L_MOUSE) {
+ getmouseco_areawin(mval);
+
+ if(yo!=mval[1]) {
+ int dy= floor(0.5+((float)(oldy-mval[1]))*pixels_to_ofs);
+
+ if(dy) {
+ sfile->ofs+= dy;
+ if(sfile->ofs<0) {
+ sfile->ofs= 0;
+ oldy= mval[1];
+ }
+ else oldy= floor(0.5+ (float)oldy - (float)dy/pixels_to_ofs);
+
+ scrarea_do_windraw(curarea);
+ screen_swapbuffers();
+
+ }
+
+ yo= mval[1];
+ }
+ else BIF_wait_for_statechange();
+ }
+ filescrollselect= 0;
+
+ /* for beauty */
+ scrarea_do_windraw(curarea);
+ screen_swapbuffers();
+
+}
+
+static void do_filescrollwheel(SpaceFile *sfile, int move)
+{
+ // by phase
+ int lines, rt;
+
+ calc_file_rcts(sfile);
+
+ lines = (int)(textrct.ymax-textrct.ymin)/FILESEL_DY;
+ rt = lines * sfile->collums;
+
+ if(sfile->totfile > rt) {
+ sfile->ofs+= move;
+ if( sfile->ofs + rt > sfile->totfile + 1)
+ sfile->ofs = sfile->totfile - rt + 1;
+ }
+
+ if(sfile->ofs<0) {
+ sfile->ofs= 0;
+ }
+}
+
+/* the complete call; pulldown menu, and three callback types */
+static void activate_fileselect_(int type, char *title, char *file, short *menup, char *pupmenu,
+ void (*func)(char *),
+ void (*func_event)(unsigned short),
+ void (*func_args)(char *, void *arg1, void *arg2),
+ void *arg1, void *arg2)
+{
+ SpaceFile *sfile;
+ char group[GROUP_MAX], name[FILE_MAX], temp[FILE_MAX];
+
+ if(curarea==0) return;
+ if(curarea->win==0) return;
+
+ newspace(curarea, SPACE_FILE);
+ scrarea_queue_winredraw(curarea);
+
+ /* sometime double, when area already is SPACE_FILE with a different file name */
+ if(curarea->headwin) addqueue(curarea->headwin, CHANGED, 1);
+
+ name[2]= 0;
+ BLI_strncpy(name, file, sizeof(name));
+
+ sfile= curarea->spacedata.first;
+
+ sfile->returnfunc= func;
+ sfile->returnfunc_event= func_event;
+ sfile->returnfunc_args= func_args;
+ sfile->arg1= arg1;
+ sfile->arg2= arg2;
+
+ sfile->type= type;
+ sfile->ofs= 0;
+
+ if(sfile->pupmenu)
+ MEM_freeN(sfile->pupmenu);
+ sfile->pupmenu= pupmenu;
+ sfile->menup= menup;
+
+ /* sfile->act is used for databrowse: double names of library objects */
+ sfile->act= -1;
+
+ if(G.relbase_valid && BLI_convertstringcode(name, G.sce, G.scene->r.cfra))
+ sfile->flag |= FILE_STRINGCODE;
+ else
+ sfile->flag &= ~FILE_STRINGCODE;
+
+ if (U.uiflag & USER_HIDE_DOT)
+ sfile->flag |= FILE_HIDE_DOT;
+
+ if(type==FILE_MAIN) {
+ char *groupname;
+
+ BLI_strncpy(sfile->file, name+2, sizeof(sfile->file));
+
+ groupname = BLO_idcode_to_name( GS(name) );
+ if (groupname) {
+ BLI_strncpy(sfile->dir, groupname, sizeof(sfile->dir) - 1);
+ strcat(sfile->dir, "/");
+ }
+
+ /* free all */
+ if(sfile->libfiledata) BLO_blendhandle_close(sfile->libfiledata);
+ sfile->libfiledata= 0;
+
+ freefilelist(sfile);
+ }
+ else if(type==FILE_LOADLIB) {
+ BLI_strncpy(sfile->dir, name, sizeof(sfile->dir));
+ if( is_a_library(sfile, temp, group) ) {
+ /* force a reload of the library-filelist */
+ freefilelist(sfile);
+ }
+ else {
+ split_sfile(sfile, name);
+ if(sfile->libfiledata) BLO_blendhandle_close(sfile->libfiledata);
+ sfile->libfiledata= NULL;
+ }
+ }
+ else { /* FILE_BLENDER or FILE_LOADFONT */
+ split_sfile(sfile, name); /* test filelist too */
+ BLI_cleanup_dir(G.sce, sfile->dir);
+
+ /* free: filelist and libfiledata became incorrect */
+ if(sfile->libfiledata) BLO_blendhandle_close(sfile->libfiledata);
+ sfile->libfiledata= 0;
+ }
+ BLI_strncpy(sfile->title, title, sizeof(sfile->title));
+ filetoname= 1;
+}
+
+void activate_fileselect(int type, char *title, char *file, void (*func)(char *))
+{
+ activate_fileselect_(type, title, file, NULL, NULL, func, NULL, NULL, NULL, NULL);
+}
+
+void activate_fileselect_menu(int type, char *title, char *file, char *pupmenu, short *menup, void (*func)(char *))
+{
+ activate_fileselect_(type, title, file, menup, pupmenu, func, NULL, NULL, NULL, NULL);
+}
+
+void activate_fileselect_args(int type, char *title, char *file, void (*func)(char *, void *, void *), void *arg1, void *arg2)
+{
+ activate_fileselect_(type, title, file, NULL, NULL, NULL, NULL, func, arg1, arg2);
+}
+
+void activate_databrowse(ID *id, int idcode, int fromcode, int retval, short *menup, void (*func)(unsigned short))
+{
+ ListBase *lb;
+ SpaceFile *sfile;
+ char str[32];
+
+ if(id==NULL) {
+ lb= wich_libbase(G.main, idcode);
+ id= lb->first;
+ }
+
+ if(id) BLI_strncpy(str, id->name, sizeof(str));
+ else return;
+
+ activate_fileselect_(FILE_MAIN, "SELECT DATABLOCK", str, menup, NULL, NULL, func, NULL, NULL, NULL);
+
+ sfile= curarea->spacedata.first;
+ sfile->retval= retval;
+ sfile->ipotype= fromcode;
+}
+
+void activate_databrowse_args(struct ID *id, int idcode, int fromcode, short *menup, void (*func)(char *, void *, void *), void *arg1, void *arg2)
+{
+ ListBase *lb;
+ SpaceFile *sfile;
+ char str[32];
+
+ if(id==NULL) {
+ lb= wich_libbase(G.main, idcode);
+ id= lb->first;
+ }
+
+ if(id) BLI_strncpy(str, id->name, sizeof(str));
+ else return;
+
+ activate_fileselect_(FILE_MAIN, "SELECT DATABLOCK", str, menup, NULL, NULL, NULL, func, arg1, arg2);
+
+ sfile= curarea->spacedata.first;
+ sfile->ipotype= fromcode;
+}
+
+void filesel_prevspace()
+{
+ SpaceFile *sfile= curarea->spacedata.first;
+
+ /* cleanup */
+ if(sfile->spacetype==SPACE_FILE) {
+ if(sfile->pupmenu) {
+ MEM_freeN(sfile->pupmenu);
+ sfile->pupmenu= NULL;
+ }
+ }
+
+ if(sfile->next) {
+
+ BLI_remlink(&curarea->spacedata, sfile);
+ BLI_addtail(&curarea->spacedata, sfile);
+
+ sfile= curarea->spacedata.first;
+
+ if (sfile->spacetype == SPACE_SCRIPT) {
+ SpaceScript *sc = (SpaceScript *)sfile;
+ if (sc->script) sc->script->flags &=~SCRIPT_FILESEL;
+ }
+
+ newspace(curarea, sfile->spacetype);
+ }
+ else newspace(curarea, SPACE_INFO);
+}
+
+static int countselect(SpaceFile *sfile)
+{
+ int a, count=0;
+
+ for(a=0; a<sfile->totfile; a++) {
+ if(sfile->filelist[a].flags & ACTIVE) {
+ count++;
+ }
+ }
+ return count;
+}
+
+static int getotherdir(void)
+{
+ ScrArea *sa;
+ SpaceFile *sfile=0;
+
+ sa= G.curscreen->areabase.first;
+ while(sa) {
+ if(sa!=curarea) {
+ if(sa->spacetype==SPACE_FILE) {
+
+ /* already found one */
+ if(sfile) return 0;
+
+ sfile= sa->spacedata.first;
+
+ if(sfile->type & FILE_UNIX) {
+ otherarea= sa;
+ BLI_make_file_string(G.sce, otherdir, sfile->dir, "");
+ }
+ else sfile= 0;
+ }
+ }
+ sa= sa->next;
+ }
+ if(sfile) return 1;
+ return 0;
+}
+
+static void reread_other_fs(void)
+{
+ SpaceFile *sfile;
+
+ /* watch it: only call when getotherdir returned OK */
+
+ sfile= otherarea->spacedata.first;
+ freefilelist(sfile);
+ scrarea_queue_winredraw(otherarea);
+}
+
+
+void free_filesel_spec(char *dir)
+{
+ /* all filesels with 'dir' are freed */
+ bScreen *sc;
+
+ sc= G.main->screen.first;
+ while(sc) {
+ ScrArea *sa= sc->areabase.first;
+ while(sa) {
+ SpaceLink *sl= sa->spacedata.first;
+ while(sl) {
+ if(sl->spacetype==SPACE_FILE) {
+ SpaceFile *sfile= (SpaceFile*) sl;
+ if (BLI_streq(sfile->dir, dir)) {
+ freefilelist(sfile);
+ }
+ }
+ sl= sl->next;
+ }
+ sa= sa->next;
+ }
+ sc= sc->id.next;
+ }
+}
+
+/* NOTE: this is called for file read, after the execfunc no UI memory is valid! */
+static void filesel_execute(SpaceFile *sfile)
+{
+ struct direntry *files;
+ char name[FILE_MAX];
+ int a;
+
+ filesel_prevspace();
+
+ if(sfile->type==FILE_LOADLIB) {
+ if(sfile->flag & FILE_STRINGCODE) {
+ if (!G.relbase_valid) {
+ okee("You have to save the .blend file before using relative paths! Using absolute path instead.");
+ sfile->flag &= ~FILE_STRINGCODE;
+ }
+ }
+
+ do_library_append(sfile);
+ BIF_undo_push("Append from file");
+ allqueue(REDRAWALL, 1);
+ }
+ else if(filesel_has_func(sfile)) {
+ fsmenu_insert_entry(sfile->dir, 1, 0);
+
+ if(sfile->type==FILE_MAIN) { /* DATABROWSE */
+ if (sfile->menup) { /* with value pointing to ID block index */
+ int notfound = 1;
+
+ /* Need special handling since hiding .* datablocks means that
+ sfile->act is no longer the same as files->nr.
+
+ Also, toggle HIDE_DOT on and off can make sfile->act not longer
+ correct (meaning it doesn't point to the correct item in the filelist.
+
+ sfile->file is always correct, so first with check if, for the item
+ corresponding to sfile->act, the name is the same.
+
+ If it isn't (or if sfile->act is not good), go over filelist and take
+ the correct one.
+
+ This means that selecting a datablock than hiding it makes it
+ unselectable. Not really a problem.
+
+ - theeth
+ */
+
+ *sfile->menup= -1;
+
+ if(sfile->act>=0) {
+ if(sfile->filelist) {
+ files= sfile->filelist+sfile->act;
+ if ( strcmp(files->relname, sfile->file)==0) {
+ notfound = 0;
+ *sfile->menup= files->nr;
+ }
+ }
+ }
+ if (notfound) {
+ for(a=0; a<sfile->totfile; a++) {
+ if( strcmp(sfile->filelist[a].relname, sfile->file)==0) {
+ *sfile->menup= sfile->filelist[a].nr;
+ break;
+ }
+ }
+ }
+ }
+ if(sfile->returnfunc_event)
+ sfile->returnfunc_event(sfile->retval);
+ else if(sfile->returnfunc_args)
+ sfile->returnfunc_args(NULL, sfile->arg1, sfile->arg2);
+ }
+ else {
+ if(strncmp(sfile->title, "Save", 4)==0) free_filesel_spec(sfile->dir);
+ if(strncmp(sfile->title, "Export", 6)==0) free_filesel_spec(sfile->dir);
+
+ BLI_strncpy(name, sfile->dir, sizeof(name));
+ strcat(name, sfile->file);
+
+ if(sfile->flag & FILE_STRINGCODE) {
+ /* still weak, but we don't want saving files to make relative paths */
+ if(strncmp(sfile->title, "Save", 4))
+ BLI_makestringcode(G.sce, name);
+ }
+ if(sfile->returnfunc)
+ sfile->returnfunc(name);
+ else if(sfile->returnfunc_args)
+ sfile->returnfunc_args(name, sfile->arg1, sfile->arg2);
+ }
+ }
+}
+
+static void do_filesel_buttons(short event, SpaceFile *sfile)
+{
+ char butname[FILE_MAX];
+
+ if (event == B_FS_FILENAME) {
+ if (strchr(sfile->file, '*') || strchr(sfile->file, '?') || strchr(sfile->file, '[')) {
+ int i, match = FALSE;
+
+ for (i = 2; i < sfile->totfile; i++) {
+ if (fnmatch(sfile->file, sfile->filelist[i].relname, 0) == 0) {
+ sfile->filelist[i].flags |= ACTIVE;
+ match = TRUE;
+ }
+ }
+ if (match) sfile->file[0] = '\0';
+ if(sfile->type==FILE_MAIN) filesel_select_objects(sfile);
+ scrarea_queue_winredraw(curarea);
+ }
+ }
+ else if(event== B_FS_DIRNAME) {
+ /* reuse the butname variable */
+ BLI_cleanup_dir(G.sce, sfile->dir);
+
+ BLI_make_file_string(G.sce, butname, sfile->dir, "");
+ BLI_strncpy(sfile->dir, butname, sizeof(sfile->dir));
+
+ /* strip the trailing slash if its a real dir */
+ if (strlen(butname)!=1)
+ butname[strlen(butname)-1]=0;
+
+ if(sfile->type & FILE_UNIX) {
+ if (!BLI_exists(butname)) {
+ if (okee("Makedir")) {
+ BLI_recurdir_fileops(butname);
+ if (!BLI_exists(butname)) parent(sfile);
+ } else parent(sfile);
+ }
+ }
+ freefilelist(sfile);
+ sfile->ofs= 0;
+ scrarea_queue_winredraw(curarea);
+ }
+ else if(event== B_FS_DIR_MENU) {
+ char *selected= fsmenu_get_entry(sfile->menu-1);
+
+ /* which string */
+ if (selected) {
+ BLI_strncpy(sfile->dir, selected, sizeof(sfile->dir));
+ BLI_make_exist(sfile->dir);
+ BLI_cleanup_dir(G.sce, sfile->dir);
+ freefilelist(sfile);
+ sfile->ofs= 0;
+ scrarea_queue_winredraw(curarea);
+ }
+
+ sfile->act= -1;
+
+ }
+ else if(event== B_FS_PARDIR)
+ parent(sfile);
+ else if(event== B_FS_LOAD) {
+ if(sfile->type)
+ filesel_execute(sfile);
+ }
+ else if(event== B_FS_CANCEL)
+ filesel_prevspace();
+ else if(event== B_FS_LIBNAME) {
+ Library *lib= BLI_findlink(&G.main->library, sfile->menu);
+ if(lib) {
+ BLI_strncpy(sfile->dir, lib->filename, sizeof(sfile->dir));
+ BLI_make_exist(sfile->dir);
+ BLI_cleanup_dir(G.sce, sfile->dir);
+ freefilelist(sfile);
+ sfile->ofs= 0;
+ scrarea_queue_winredraw(curarea);
+ sfile->act= -1;
+ }
+ }
+
+}
+
+/****/
+
+typedef void (*ReplaceFP)(ID *oldblock, ID *newblock);
+
+static void change_id_link(void *linkpv, void *newlinkv) {
+ ID **linkp= (ID**) linkpv;
+ ID *newlink= newlinkv;
+
+ if (*linkp) {
+ (*linkp)->us--;
+ }
+ (*linkp)= newlink;
+ if (newlink) {
+ id_us_plus(newlink);
+ }
+}
+
+static void replace_image(ID *oldblock, ID *newblock) {
+ Image *oldima= (Image*) oldblock;
+ Image *newima= (Image*) newblock;
+ bScreen *sc;
+ Scene *sce;
+ Tex *tex;
+ Mesh *me;
+
+ for (tex= G.main->tex.first; tex; tex= tex->id.next) {
+ if (tex->env && tex->env->type == ENV_LOAD && tex->env->ima == oldima)
+ change_id_link(&tex->env->ima, newima);
+ if (tex->ima == oldima)
+ change_id_link(&tex->ima, newima);
+ }
+
+ for (sce= G.main->scene.first; sce; sce= sce->id.next) {
+ if (sce->ima == oldima)
+ change_id_link(&sce->ima, newima);
+ }
+
+ for (sc= G.main->screen.first; sc; sc= sc->id.next) {
+ ScrArea *sa;
+
+ for (sa= sc->areabase.first; sa; sa= sa->next) {
+ SpaceLink *sl;
+
+ for (sl= sa->spacedata.first; sl; sl= sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d= (View3D*) sl;
+ BGpic *bgp= v3d->bgpic;
+
+ if (bgp && bgp->ima == oldima)
+ change_id_link(&bgp->ima, newima);
+ } else if (sl->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima= (SpaceImage*) sl;
+
+ if (sima->image == oldima)
+ change_id_link(&sima->image, newima);
+ }
+ }
+ }
+ }
+
+ for (me= G.main->mesh.first; me; me= me->id.next) {
+ int i, a;
+ MTFace *tface;
+
+ for(i=0; i<me->fdata.totlayer; i++) {
+ if(me->fdata.layers[i].type == CD_MTFACE) {
+ tface= (MTFace*)me->fdata.layers[i].data;
+
+ for (a=0; a<me->totface; a++, tface++) {
+ if (tface->tpage == oldima) {
+ /* not change_id_link, tpage's aren't owners :(
+ * see hack below.
+ */
+ tface->tpage= newima;
+ }
+ }
+ }
+ }
+ }
+
+ /* Nasty hack, necessary because tpages don't act
+ * as a user, so there lots of image user count
+ * munging occurs... this will ensure the image
+ * really dies.
+ */
+ oldima->id.us= 0;
+}
+
+static void replace_material(ID *oldblock, ID *newblock)
+{
+ Material *old= (Material*) oldblock;
+ Material *new= (Material*) newblock;
+ Material ***matarar;
+ ID *id;
+ Object *ob;
+ int a;
+
+ ob= G.main->object.first;
+ while(ob) {
+ if(ob->totcol && ob->id.lib==0) {
+ matarar= give_matarar(ob);
+ for(a=1; a<=ob->totcol; a++) {
+ if(ob->mat[a-1] == old) {
+ if(old) old->id.us--;
+ id_us_plus((ID *)new);
+ ob->mat[a-1]= new;
+ }
+ id= ob->data;
+ if( (*matarar)[a-1] == old && id->lib==0) {
+ if(old) old->id.us--;
+ id_us_plus((ID *)new);
+ (*matarar)[a-1]= new;
+ }
+ }
+ }
+ ob= ob->id.next;
+ }
+}
+
+static ReplaceFP get_id_replace_function(int idcode) {
+ switch (idcode) {
+ case ID_MA:
+ return &replace_material;
+ case ID_IM:
+ return &replace_image;
+ default:
+ return NULL;
+ }
+}
+
+static void databrowse_replace(SpaceFile *sfile, int idcode)
+{
+ ReplaceFP replace_func= get_id_replace_function(idcode);
+
+ if (!replace_func) {
+ error("Replacing %s blocks is unsupported", BLO_idcode_to_name(idcode));
+ } else if (sfile->act==-1) {
+ error("Select target with leftmouse");
+ } else {
+ ID *target= (ID*) sfile->filelist[sfile->act].poin;
+
+ if (target) {
+ char buf[128];
+
+ sprintf(buf, "Replace with %s: %s", BLO_idcode_to_name(idcode), target->name+2);
+
+ if (okee(buf)) {
+ int i;
+
+ for (i = 0; i <sfile->totfile; i++)
+ if ((sfile->filelist[i].flags&ACTIVE) && sfile->filelist[i].poin!=target)
+ replace_func(sfile->filelist[i].poin, target);
+ }
+ }
+ }
+
+ freefilelist(sfile);
+ scrarea_queue_winredraw(curarea);
+}
+
+static void fs_fake_users(SpaceFile *sfile)
+{
+ ID *id;
+ int a;
+
+ /* only for F4 DATABROWSE */
+ if(filesel_has_func(sfile)) return;
+
+ for(a=0; a<sfile->totfile; a++) {
+ if(sfile->filelist[a].flags & ACTIVE) {
+ id= (ID *)sfile->filelist[a].poin;
+ if(id) {
+ if( id->flag & LIB_FAKEUSER) {
+ id->flag -= LIB_FAKEUSER;
+ id->us--;
+ }
+ else {
+ id->flag |= LIB_FAKEUSER;
+ id->us++;
+ }
+ }
+ }
+ }
+ freefilelist(sfile);
+ scrarea_queue_winredraw(curarea);
+}
+
+
+static int get_hilited_entry(SpaceFile *sfile)
+{
+ int a;
+
+ for(a=0; a<sfile->totfile; a++) {
+ if(sfile->filelist[a].flags & HILITE) {
+ return a;
+ }
+ }
+ return -1;
+}
+
+
+void winqreadfilespace(ScrArea *sa, void *spacedata, BWinEvent *evt)
+{
+ unsigned short event= evt->event;
+ short val= evt->val;
+ static int acto=0;
+ SpaceFile *sfile;
+ int act, do_draw= 0, i, test, ret = 0;
+ short qual, mval[2];
+ char str[FILE_MAX+12];
+
+ sfile= curarea->spacedata.first;
+ if(sfile==0) return;
+ if(sfile->filelist==0) {
+ return;
+ }
+
+ if(curarea->win==0) return;
+ calc_file_rcts(sfile);
+ getmouseco_areawin(mval);
+
+ /* prevent looping */
+ if(selecting && !(get_mbut() & R_MOUSE)) selecting= 0;
+
+ if(val) {
+
+ if( event!=RETKEY && event!=PADENTER)
+ if( uiDoBlocks(&curarea->uiblocks, event)!=UI_NOTHING ) event= 0;
+
+ switch(event) {
+
+ case UI_BUT_EVENT:
+ do_filesel_buttons(val, sfile);
+ break;
+
+ case WHEELDOWNMOUSE:
+ do_filescrollwheel(sfile, U.wheellinescroll);
+ act= find_active_file(sfile, mval[0], mval[1]);
+ set_active_file(sfile, act);
+ do_draw= 1;
+ break;
+ case WHEELUPMOUSE:
+ do_filescrollwheel(sfile, -U.wheellinescroll);
+ act= find_active_file(sfile, mval[0], mval[1]);
+ set_active_file(sfile, act);
+ do_draw= 1;
+ break;
+
+ case LEFTMOUSE:
+ case MIDDLEMOUSE:
+ if(mval[0]>scrollrct.xmin && mval[0]<scrollrct.xmax && mval[1]>scrollrct.ymin && mval[1]<scrollrct.ymax) {
+ do_filescroll(sfile);
+ }
+ else if(mval[0]>textrct.xmin && mval[0]<textrct.xmax && mval[1]>textrct.ymin && mval[1]<textrct.ymax) {
+
+ /* sfile->act is used in databrowse: double names of library objects */
+
+ sfile->act= act= find_active_file(sfile, mval[0], mval[1]);
+
+ if(act>=0 && act<sfile->totfile) {
+ if(S_ISDIR(sfile->filelist[act].type)) {
+ /* the path is too long and we are not going up! */
+ if (strcmp(sfile->filelist[act].relname, ".") &&
+ strcmp(sfile->filelist[act].relname, "..") &&
+ strlen(sfile->dir) + strlen(sfile->filelist[act].relname) >= FILE_MAXDIR )
+ {
+ error("Path too long, cannot enter this directory");
+ } else {
+ strcat(sfile->dir, sfile->filelist[act].relname);
+ strcat(sfile->dir,"/");
+ BLI_cleanup_dir(G.sce, sfile->dir);
+ freefilelist(sfile);
+ sfile->ofs= 0;
+ do_draw= 1;
+ }
+ }
+ else {
+ if( strcmp(sfile->file, sfile->filelist[act].relname)) {
+ char tmpstr[240];
+ do_draw= 1;
+ BLI_strncpy(sfile->file, sfile->filelist[act].relname, sizeof(sfile->file));
+ if (sfile->f_fp) {
+ sprintf (tmpstr, "%s%s", sfile->dir, sfile->file);
+ /* printf ("%s\n", tmpstr); */
+ #ifdef INTERNATIONAL
+ if (!FTF_GetNewFont ((const unsigned char *)tmpstr, 0, U.fontsize))
+ error ("No font file");
+ #endif
+ }
+ }
+ if(event==MIDDLEMOUSE && sfile->type) filesel_execute(sfile);
+ }
+ }
+ }
+ break;
+ case RIGHTMOUSE:
+ act= find_active_file(sfile, mval[0], mval[1]);
+ acto= act;
+ if(act>=0 && act<sfile->totfile) {
+
+ if (sfile->filelist[act].flags & ACTIVE) {
+ sfile->filelist[act].flags &= ~ACTIVE;
+ selecting = INACTIVATE;
+ }
+ else {
+ test= sfile->filelist[act].relname[0];
+ if (act>=2 || test!='.') sfile->filelist[act].flags |= ACTIVE;
+
+ selecting = ACTIVATE;
+ }
+ do_draw= 1;
+ }
+ break;
+ case MOUSEY:
+ act= find_active_file(sfile, mval[0], mval[1]);
+ if (act!=acto) {
+ set_active_file(sfile, act);
+ }
+ if(selecting && act!=acto) {
+
+ while(1) {
+ if (acto >= 2 && acto < sfile->totfile) {
+ if (selecting == ACTIVATE) sfile->filelist[acto].flags |= ACTIVE;
+ else if (selecting == INACTIVATE) sfile->filelist[acto].flags &= ~ACTIVE;
+ }
+ if (acto < act) acto++;
+ else if (acto > act) acto--;
+ else break;
+
+ }
+
+ }
+ acto= act;
+ break;
+
+ case PAGEUPKEY:
+ sfile->ofs-= page_ofs;
+ do_draw= 1;
+ break;
+ case PAGEDOWNKEY:
+ sfile->ofs+= page_ofs;
+ do_draw= 1;
+ break;
+ case HOMEKEY:
+ sfile->ofs= 0;
+ do_draw= 1;
+ break;
+ case ENDKEY:
+ sfile->ofs= sfile->totfile;
+ do_draw= 1;
+ break;
+
+ case AKEY:
+ swapselect_file(sfile);
+ if(sfile->type==FILE_MAIN) filesel_select_objects(sfile);
+ do_draw= 1;
+ break;
+
+ case BKEY:
+ case CKEY:
+ case LKEY:
+ if(event==LKEY && sfile->type==FILE_MAIN && (G.qual & LR_CTRLKEY)) {
+ databrowse_replace(sfile, groupname_to_code(sfile->dir));
+ break;
+ }
+ /* pass */
+ case MKEY:
+ if(sfile->type==FILE_MAIN) break;
+
+ if(!countselect(sfile)) {
+ error("No files selected");
+ break;
+ }
+
+ if(!getotherdir()) {
+ error("No second fileselect");
+ break;
+ }
+
+ if (!strcmp(sfile->dir, otherdir)) {
+ error("Same directories");
+ break;
+ }
+
+ if(event==BKEY) sprintf(str, "Backup to %s", otherdir);
+ else if(event==CKEY) sprintf(str, "Copy to %s", otherdir);
+ else if(event==LKEY) sprintf(str, "Linked copy to %s", otherdir);
+ else if(event==MKEY) sprintf(str, "Move to %s", otherdir);
+
+ if (!okee(str)) break;
+
+ for (i = 0; i<sfile->totfile; i++){
+ if (sfile->filelist[i].flags & ACTIVE) {
+ BLI_make_file_string(G.sce, str, sfile->dir, sfile->filelist[i].relname);
+
+ if(event==BKEY) ret= BLI_backup(sfile->filelist[i].relname, sfile->dir, otherdir);
+ else if(event==CKEY) ret= BLI_copy_fileops(str, otherdir);
+ else if(event==LKEY) ret= BLI_link(str, otherdir);
+ else if(event==MKEY) ret= BLI_move(str, otherdir);
+
+ if (ret) {error("Command failed, see console"); break;}
+ else sfile->filelist[i].flags &= ~ACTIVE;
+ }
+ }
+ do_draw= 1;
+ if(event==BKEY || event==MKEY)
+ freefilelist(sfile);
+
+ reread_other_fs();
+
+ break;
+
+ case XKEY:
+ test = get_hilited_entry(sfile);
+
+ if (test != -1 && !(S_ISDIR(sfile->filelist[test].type))){
+ BLI_make_file_string(G.sce, str, sfile->dir, sfile->filelist[test].relname);
+
+ if( okee("Remove %s", str) ) {
+ ret = BLI_delete(str, 0, 0);
+ if (ret) {
+ error("Command failed, see console");
+ } else {
+ freefilelist(sfile);
+ do_draw= 1;
+ }
+ }
+ }
+ break;
+
+ case RKEY:
+ if(sfile->type==FILE_MAIN) {
+ databrowse_replace(sfile, groupname_to_code(sfile->dir));
+ break;
+ }
+ /* pass to TKEY! */
+
+ case TKEY:
+ if(sfile->type==FILE_MAIN) break;
+
+ if(!countselect(sfile)) {
+ error("No files selected");
+ break;
+ }
+
+ if(event==TKEY) sprintf(str, "Touch");
+ else if(event==RKEY) sprintf(str, "Remove from %s", sfile->dir);
+
+ qual= G.qual; /* because after okee() you released the SHIFT */
+ if (!okee(str)) break;
+
+ for (i = 0; i <sfile->totfile; i++) {
+ if (sfile->filelist[i].flags & ACTIVE) {
+ BLI_make_file_string(G.sce, str, sfile->dir, sfile->filelist[i].relname);
+
+ if(event==TKEY) ret= BLI_touch(str);
+ else if(event==RKEY) {
+ if(qual & LR_SHIFTKEY) ret= BLI_delete(str, 0, 1);
+ else if(S_ISDIR(sfile->filelist[i].type)) ret= BLI_delete(str, 1, 0);
+ else ret= BLI_delete(str, 0, 0);
+ }
+
+ if (ret) {error("Command failed, see console"); break;}
+ else sfile->filelist[i].flags &= ~ACTIVE;
+ }
+ }
+ do_draw= 1;
+ freefilelist(sfile);
+
+ break;
+
+ case PKEY:
+ if(G.qual & LR_SHIFTKEY) {
+ extern char bprogname[]; /* usiblender.c */
+#ifdef WIN32
+ sprintf(str, "%s -a \"%s%s\"", bprogname, sfile->dir, sfile->file);
+#else
+ sprintf(str, "\"%s\" -a \"%s%s\"", bprogname, sfile->dir, sfile->file);
+#endif
+ system(str);
+ }
+ else
+ parent(sfile);
+
+ break;
+
+ case IKEY:
+ if(sfile->type==FILE_MAIN) break;
+
+ sprintf(str, "$IMAGEEDITOR %s%s", sfile->dir, sfile->file);
+ system(str);
+ break;
+
+ case EKEY:
+ if(sfile->type==FILE_MAIN) break;
+
+ sprintf(str, "$WINEDITOR %s%s", sfile->dir, sfile->file);
+ system(str);
+ break;
+
+ case FKEY:
+ if(sfile->type==FILE_MAIN) {
+ fs_fake_users(sfile);
+ }
+ break;
+
+ case PADPLUSKEY:
+ case EQUALKEY:
+ if (G.qual & LR_CTRLKEY) BLI_newname(sfile->file, +100);
+ else if (G.qual & LR_SHIFTKEY) BLI_newname(sfile->file, +10);
+ else BLI_newname(sfile->file, +1);
+
+ do_draw= 1;
+ break;
+
+ case PADMINUS:
+ case MINUSKEY:
+ if (G.qual & LR_CTRLKEY) BLI_newname(sfile->file, -100);
+ else if (G.qual & LR_SHIFTKEY) BLI_newname(sfile->file, -10);
+ else BLI_newname(sfile->file, -1);
+
+ do_draw= 1;
+ break;
+
+ case BACKSLASHKEY:
+ case SLASHKEY:
+ if(sfile->type==FILE_MAIN) break;
+
+#ifdef WIN32
+ BLI_strncpy(sfile->dir, "\\", sizeof(sfile->dir));
+#else
+ BLI_strncpy(sfile->dir, "/", sizeof(sfile->dir));
+#endif
+ freefilelist(sfile);
+ sfile->ofs= 0;
+ do_draw= 1;
+ break;
+ case PERIODKEY:
+ freefilelist(sfile);
+ do_draw= 1;
+ break;
+ case ESCKEY:
+ filesel_prevspace();
+ break;
+ case PADENTER:
+ case RETKEY:
+ if(sfile->type) filesel_execute(sfile);
+ break;
+ }
+ }
+ else if(event==RIGHTMOUSE) {
+ selecting = NOTACTIVE;
+ if(sfile->type==FILE_MAIN) filesel_select_objects(sfile);
+ }
+ else if(event==LEFTMOUSE) {
+ if(sfile->type==FILE_MAIN) active_file_object(sfile);
+ }
+
+ /* XXX, stupid patch, curarea can become undone
+ * because of file loading... fixme zr
+ */
+ if(do_draw && curarea) scrarea_queue_winredraw(curarea);
+}
+
+
+
+
+/* ************* LIBRARY FILESEL ******************* */
+
+static int groupname_to_code(char *group)
+{
+ char buf[GROUP_MAX];
+ char *lslash;
+
+ BLI_strncpy(buf, group, GROUP_MAX);
+ lslash= BLI_last_slash(buf);
+ if (lslash)
+ lslash[0]= '\0';
+
+ return BLO_idcode_from_name(buf);
+}
+
+static int is_a_library(SpaceFile *sfile, char *dir, char *group)
+{
+ /* return ok when a blenderfile, in dir is the filename,
+ * in group the type of libdata
+ */
+ int len;
+ char *fd;
+
+ strcpy(dir, sfile->dir);
+ len= strlen(dir);
+ if(len<7) return 0;
+ if( dir[len-1] != '/' && dir[len-1] != '\\') return 0;
+
+ group[0]= 0;
+ dir[len-1]= 0;
+
+ /* Find the last slash */
+ fd= (strrchr(dir, '/')>strrchr(dir, '\\'))?strrchr(dir, '/'):strrchr(dir, '\\');
+
+ if(fd==0) return 0;
+ *fd= 0;
+ if(BLO_has_bfile_extension(fd+1)) {
+ /* the last part of the dir is a .blend file, no group follows */
+ *fd= '/'; /* put back the removed slash separating the dir and the .blend file name */
+ }
+ else {
+ char *gp = fd+1; // in case we have a .blend file, gp points to the group
+
+ /* Find the last slash */
+ fd= (strrchr(dir, '/')>strrchr(dir, '\\'))?strrchr(dir, '/'):strrchr(dir, '\\');
+ if (!fd || !BLO_has_bfile_extension(fd+1)) return 0;
+
+ /* now we know that we are in a blend file and it is safe to
+ assume that gp actually points to a group */
+ BLI_strncpy(group, gp, GROUP_MAX);
+ }
+ return 1;
+}
+
+static void do_library_append(SpaceFile *sfile)
+{
+ Library *lib;
+ char dir[FILE_MAX], group[GROUP_MAX];
+
+ if ( is_a_library(sfile, dir, group)==0 ) {
+ error("Not a library");
+ } else if (!sfile->libfiledata) {
+ error("Library not loaded");
+ } else if (group[0]==0) {
+ error("Nothing indicated");
+ } else if (BLI_streq(G.main->name, dir)) {
+ error("Cannot use current file as library");
+ } else {
+ Object *ob;
+ int idcode = groupname_to_code(group);
+
+ if((sfile->flag & FILE_LINK)==0)
+ /* tag everything, all untagged data can be made local */
+ flag_all_listbases_ids(LIB_APPEND_TAG, 1);
+
+ BLO_library_append(sfile, dir, idcode);
+
+ /* DISPLISTS? */
+ ob= G.main->object.first;
+ while(ob) {
+ if(ob->id.lib) {
+ ob->recalc |= OB_RECALC;
+ }
+ ob= ob->id.next;
+ }
+
+ /* and now find the latest append lib file */
+ lib= G.main->library.first;
+ while(lib) {
+ if (BLI_streq(dir, lib->filename)) break;
+ lib= lib->id.next;
+ }
+
+ /* make local */
+ if(lib && (sfile->flag & FILE_LINK)==0) {
+ all_local(lib, 1);
+ /* important we unset, otherwise these object wont
+ * link into other scenes from this blend file */
+ flag_all_listbases_ids(LIB_APPEND_TAG, 0);
+ }
+
+ DAG_scene_sort(G.scene);
+
+ /* in sfile->dir is the whole lib name */
+ BLI_strncpy(G.lib, sfile->dir, sizeof(G.lib) );
+ }
+}
+
+static void library_to_filelist(SpaceFile *sfile)
+{
+ LinkNode *l, *names;
+ int ok, i, nnames, idcode;
+ char filename[FILE_MAX];
+ char dir[FILE_MAX], group[GROUP_MAX];
+
+ /* name test */
+ ok= is_a_library(sfile, dir, group);
+ if (!ok) {
+ /* free */
+ if(sfile->libfiledata) BLO_blendhandle_close(sfile->libfiledata);
+ sfile->libfiledata= 0;
+ return;
+ }
+
+ BLI_strncpy(filename, G.sce, sizeof(filename)); // G.sce = last file loaded, for UI
+
+ /* there we go */
+ /* for the time being only read filedata when libfiledata==0 */
+ if (sfile->libfiledata==0) {
+ sfile->libfiledata= BLO_blendhandle_from_file(dir); // this sets G.sce, we dont want it
+
+ if(sfile->libfiledata==0) return;
+ }
+
+ idcode= groupname_to_code(group);
+
+ // memory for strings is passed into filelist[i].relname
+ // and free'd in freefilelist
+ if (idcode) {
+ names= BLO_blendhandle_get_datablock_names(sfile->libfiledata, idcode);
+ } else {
+ names= BLO_blendhandle_get_linkable_groups(sfile->libfiledata);
+ }
+
+ nnames= BLI_linklist_length(names);
+
+ sfile->totfile= nnames + 2;
+ sfile->filelist= malloc(sfile->totfile * sizeof(*sfile->filelist));
+ memset(sfile->filelist, 0, sfile->totfile * sizeof(*sfile->filelist));
+
+ sfile->filelist[0].relname= BLI_strdup(".");
+ sfile->filelist[0].type |= S_IFDIR;
+ sfile->filelist[1].relname= BLI_strdup("..");
+ sfile->filelist[1].type |= S_IFDIR;
+
+ for (i=0, l= names; i<nnames; i++, l= l->next) {
+ char *blockname= BLI_strdup(l->link);
+
+ sfile->filelist[i + 2].relname= blockname;
+ if (!idcode)
+ sfile->filelist[i + 2].type |= S_IFDIR;
+ }
+
+ BLI_linklist_free(names, free);
+
+ qsort(sfile->filelist, sfile->totfile, sizeof(struct direntry), compare_name);
+
+ sfile->maxnamelen= 0;
+ for(i=0; i<sfile->totfile; i++) {
+ int len = BMF_GetStringWidth(G.font, sfile->filelist[i].relname);
+ if (len > sfile->maxnamelen)
+ sfile->maxnamelen = len;
+ }
+
+ BLI_strncpy(G.sce, filename, sizeof(filename)); // prevent G.sce to change
+
+}
+
+/* ******************* DATA SELECT ********************* */
+
+static void filesel_select_objects(SpaceFile *sfile)
+{
+ Object *ob;
+ Base *base;
+ Scene *sce;
+ int a;
+
+ /* only when F4 DATABROWSE */
+ if(filesel_has_func(sfile)) return;
+
+ if( strcmp(sfile->dir, "Object/")==0 ) {
+ for(a=0; a<sfile->totfile; a++) {
+
+ ob= (Object *)sfile->filelist[a].poin;
+
+ if(ob && (ob->flag & OB_RESTRICT_VIEW)==0) {
+ if(sfile->filelist[a].flags & ACTIVE) ob->flag |= SELECT;
+ else ob->flag &= ~SELECT;
+ }
+
+ }
+ base= FIRSTBASE;
+ while(base) {
+ base->flag= base->object->flag;
+ base= base->next;
+ }
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWOOPS, 0);
+ }
+ else if( strcmp(sfile->dir, "Scene/")==0 ) {
+
+ for(a=0; a<sfile->totfile; a++) {
+
+ sce= (Scene *)sfile->filelist[a].poin;
+ if(sce) {
+ if(sfile->filelist[a].flags & ACTIVE) sce->r.scemode |= R_BG_RENDER;
+ else sce->r.scemode &= ~R_BG_RENDER;
+ }
+
+ }
+ allqueue(REDRAWBUTSSCENE, 0);
+ }
+}
+
+static void active_file_object(SpaceFile *sfile)
+{
+ Object *ob;
+
+ /* only when F4 DATABROWSE */
+ if(filesel_has_func(sfile)) return;
+
+ if( strcmp(sfile->dir, "Object/")==0 ) {
+ if(sfile->act >= 0) {
+
+ ob= (Object *)sfile->filelist[sfile->act].poin;
+
+ if(ob && (ob->flag & OB_RESTRICT_VIEW)==0) {
+ set_active_object(ob);
+ if(BASACT && BASACT->object==ob) {
+ BASACT->flag |= SELECT;
+ sfile->filelist[sfile->act].flags |= ACTIVE;
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWOOPS, 0);
+ scrarea_queue_winredraw(curarea);
+ }
+ }
+ }
+ }
+}
+
+
+void main_to_filelist(SpaceFile *sfile)
+{
+ ID *id;
+ struct direntry *files, *firstlib = NULL;
+ ListBase *lb;
+ int a, fake, idcode, len, ok, totlib, totbl;
+ short hide = 0;
+
+ if (sfile->flag & FILE_HIDE_DOT)
+ hide = 1;
+
+ if(sfile->dir[0]=='/') sfile->dir[0]= 0;
+
+ if(sfile->dir[0]) {
+ idcode= groupname_to_code(sfile->dir);
+ if(idcode==0) sfile->dir[0]= 0;
+ }
+
+ if( sfile->dir[0]==0) {
+
+ /* make directories */
+ sfile->totfile= 24;
+ sfile->filelist= (struct direntry *)malloc(sfile->totfile * sizeof(struct direntry));
+
+ for(a=0; a<sfile->totfile; a++) {
+ memset( &(sfile->filelist[a]), 0 , sizeof(struct direntry));
+ sfile->filelist[a].type |= S_IFDIR;
+ }
+
+ sfile->filelist[0].relname= BLI_strdup("..");
+ sfile->filelist[1].relname= BLI_strdup(".");
+ sfile->filelist[2].relname= BLI_strdup("Scene");
+ sfile->filelist[3].relname= BLI_strdup("Group");
+ sfile->filelist[4].relname= BLI_strdup("Object");
+ sfile->filelist[5].relname= BLI_strdup("Mesh");
+ sfile->filelist[6].relname= BLI_strdup("Curve");
+ sfile->filelist[7].relname= BLI_strdup("Metaball");
+ sfile->filelist[8].relname= BLI_strdup("Material");
+ sfile->filelist[9].relname= BLI_strdup("Texture");
+ sfile->filelist[10].relname= BLI_strdup("Image");
+ sfile->filelist[11].relname= BLI_strdup("Wave");
+ sfile->filelist[12].relname= BLI_strdup("Lattice");
+ sfile->filelist[13].relname= BLI_strdup("Lamp");
+ sfile->filelist[14].relname= BLI_strdup("Camera");
+ sfile->filelist[15].relname= BLI_strdup("Ipo");
+ sfile->filelist[16].relname= BLI_strdup("World");
+ sfile->filelist[17].relname= BLI_strdup("Screen");
+ sfile->filelist[18].relname= BLI_strdup("VFont");
+ sfile->filelist[19].relname= BLI_strdup("Text");
+ sfile->filelist[20].relname= BLI_strdup("Armature");
+ sfile->filelist[21].relname= BLI_strdup("Action");
+ sfile->filelist[22].relname= BLI_strdup("NodeTree");
+ sfile->filelist[23].relname= BLI_strdup("Brush");
+
+ qsort(sfile->filelist, sfile->totfile, sizeof(struct direntry), compare_name);
+ }
+ else {
+
+ /* make files */
+ idcode= groupname_to_code(sfile->dir);
+
+ lb= wich_libbase(G.main, idcode );
+ if(lb==0) return;
+
+ id= lb->first;
+ sfile->totfile= 0;
+ while(id) {
+ if(filesel_has_func(sfile) && idcode==ID_IP) {
+ if(sfile->ipotype== ((Ipo *)id)->blocktype) sfile->totfile++;
+ }
+ else if (hide==0 || id->name[2] != '.')
+ sfile->totfile++;
+
+ id= id->next;
+ }
+
+ if(!filesel_has_func(sfile)) sfile->totfile+= 2;
+ sfile->filelist= (struct direntry *)malloc(sfile->totfile * sizeof(struct direntry));
+
+ files= sfile->filelist;
+
+ if(!filesel_has_func(sfile)) {
+ memset( &(sfile->filelist[0]), 0 , sizeof(struct direntry));
+ sfile->filelist[0].relname= BLI_strdup(".");
+ sfile->filelist[0].type |= S_IFDIR;
+ memset( &(sfile->filelist[1]), 0 , sizeof(struct direntry));
+ sfile->filelist[1].relname= BLI_strdup("..");
+ sfile->filelist[1].type |= S_IFDIR;
+
+ files+= 2;
+ }
+
+ id= lb->first;
+ totlib= totbl= 0;
+
+ while(id) {
+
+ ok= 0;
+ if(filesel_has_func(sfile) && idcode==ID_IP) {
+ if(sfile->ipotype== ((Ipo *)id)->blocktype) ok= 1;
+ }
+ else ok= 1;
+
+ if(ok) {
+
+ if (hide==0 || id->name[2] != '.') {
+ memset( files, 0 , sizeof(struct direntry));
+ if(id->lib==NULL)
+ files->relname= BLI_strdup(id->name+2);
+ else {
+ char tmp[FILE_MAX], fi[FILE_MAXFILE];
+ BLI_strncpy(tmp, id->lib->name, FILE_MAX);
+ BLI_splitdirstring(tmp, fi);
+ files->relname= MEM_mallocN(FILE_MAXFILE+32, "filename for lib");
+ sprintf(files->relname, "%s / %s", fi, id->name+2);
+ }
+
+ if(!filesel_has_func(sfile)) { /* F4 DATA BROWSE */
+ if(idcode==ID_OB) {
+ if( ((Object *)id)->flag & SELECT) files->flags |= ACTIVE;
+ }
+ else if(idcode==ID_SCE) {
+ if( ((Scene *)id)->r.scemode & R_BG_RENDER) files->flags |= ACTIVE;
+ }
+ }
+ files->nr= totbl+1;
+ files->poin= id;
+ fake= id->flag & LIB_FAKEUSER;
+
+ if(id->lib && fake) sprintf(files->extra, "LF %d", id->us);
+ else if(id->lib) sprintf(files->extra, "L %d", id->us);
+ else if(fake) sprintf(files->extra, "F %d", id->us);
+ else sprintf(files->extra, " %d", id->us);
+
+ if(id->lib) {
+ if(totlib==0) firstlib= files;
+ totlib++;
+ }
+
+ files++;
+ }
+ totbl++;
+ }
+
+ id= id->next;
+ }
+
+ /* only qsort of libraryblokken */
+ if(totlib>1) {
+ qsort(firstlib, totlib, sizeof(struct direntry), compare_name);
+ }
+ }
+
+ sfile->maxnamelen= 0;
+ for(a=0; a<sfile->totfile; a++) {
+ len = BMF_GetStringWidth(G.font, sfile->filelist[a].relname);
+ if (len > sfile->maxnamelen) sfile->maxnamelen = len;
+
+ if(filetoname) {
+ if( strcmp(sfile->file, sfile->filelist[a].relname)==0) {
+ sfile->ofs= a-( sfile->collums*(curarea->winy-FILESELHEAD-10)/(2*FILESEL_DY));
+ filetoname= 0;
+ if(filesel_has_func(sfile)) sfile->filelist[a].flags |= ACTIVE;
+ }
+ }
+ }
+}
+
+
+void clever_numbuts_filesel()
+{
+ SpaceFile *sfile;
+ char orgname[FILE_MAX+12];
+ char filename[FILE_MAX+12];
+ char newname[FILE_MAX+12];
+ int test;
+ int len;
+
+ sfile= curarea->spacedata.first;
+
+ if(sfile->type==FILE_MAIN) return;
+
+ len = 110;
+ test = get_hilited_entry(sfile);
+
+ if (test != -1 && !(S_ISDIR(sfile->filelist[test].type))){
+ BLI_make_file_string(G.sce, orgname, sfile->dir, sfile->filelist[test].relname);
+ BLI_strncpy(filename, sfile->filelist[test].relname, sizeof(filename));
+
+ add_numbut(0, TEX, "", 0, len, filename, "Rename File");
+
+ if( do_clever_numbuts("Rename File", 1, REDRAW) ) {
+ BLI_make_file_string(G.sce, newname, sfile->dir, filename);
+
+ if( strcmp(orgname, newname) != 0 ) {
+ BLI_rename(orgname, newname);
+ freefilelist(sfile);
+ }
+ }
+
+ scrarea_queue_winredraw(curarea);
+ }
+}
+
diff --git a/source/blender/src/fluidsim.c b/source/blender/src/fluidsim.c
new file mode 100644
index 00000000000..e9609d40570
--- /dev/null
+++ b/source/blender/src/fluidsim.c
@@ -0,0 +1,1147 @@
+/**
+ * fluidsim.c
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#include "MEM_guardedalloc.h"
+
+/* types */
+#include "DNA_curve_types.h"
+#include "DNA_object_types.h"
+#include "DNA_object_fluidsim.h"
+#include "DNA_key_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_key_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "MTC_matrixops.h"
+
+#include "BKE_customdata.h"
+#include "BKE_displist.h"
+#include "BKE_effect.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_key.h"
+#include "BKE_scene.h"
+#include "BKE_object.h"
+#include "BKE_softbody.h"
+#include "BKE_utildefines.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_ipo.h"
+#include "LBM_fluidsim.h"
+// warning - double elbeem.h in intern/extern...
+#include "elbeem.h"
+
+#include "BLI_editVert.h"
+#include "BIF_editdeform.h"
+#include "BIF_gl.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_cursors.h"
+#include "BIF_interface.h"
+#include "BSE_headerbuttons.h"
+
+#include "mydevice.h"
+#include "blendef.h"
+#include "SDL.h"
+#include "SDL_thread.h"
+#include "SDL_mutex.h"
+#include <sys/stat.h>
+
+#ifdef WIN32 /* Windos */
+//#include "BLI_winstuff.h"
+#ifndef snprintf
+#define snprintf _snprintf
+#endif
+#endif
+// SDL redefines main for SDL_main, not needed here...
+#undef main
+
+#ifdef __APPLE__ /* MacOS X */
+#undef main
+#endif
+
+// from DerivedMesh.c
+void initElbeemMesh(struct Object *ob, int *numVertices, float **vertices, int *numTriangles, int **triangles, int useGlobalCoords);
+
+/* from header info.c */
+extern int start_progress_bar(void);
+extern void end_progress_bar(void);
+extern int progress_bar(float done, char *busy_info);
+
+double fluidsimViscosityPreset[6] = {
+ -1.0, /* unused */
+ -1.0, /* manual */
+ 1.0e-6, /* water */
+ 5.0e-5, /* some (thick) oil */
+ 2.0e-3, /* ca. honey */
+ -1.0 /* end */
+};
+
+char* fluidsimViscosityPresetString[6] = {
+ "UNUSED", /* unused */
+ "UNUSED", /* manual */
+ " = 1.0 * 10^-6", /* water */
+ " = 5.0 * 10^-5", /* some (thick) oil */
+ " = 2.0 * 10^-3", /* ca. honey */
+ "INVALID" /* end */
+};
+
+typedef struct {
+ DerivedMesh dm;
+
+ // similar to MeshDerivedMesh
+ struct Object *ob; // pointer to parent object
+ float *extverts, *nors; // face normals, colors?
+ Mesh *fsmesh; // mesh struct to display (either surface, or original one)
+ char meshFree; // free the mesh afterwards? (boolean)
+} fluidsimDerivedMesh;
+
+
+
+/* enable/disable overall compilation */
+#ifndef DISABLE_ELBEEM
+
+
+/* ********************** fluid sim settings struct functions ********************** */
+
+/* allocates and initializes general main data */
+FluidsimSettings *fluidsimSettingsNew(struct Object *srcob)
+{
+ //char blendDir[FILE_MAXDIR], blendFile[FILE_MAXFILE];
+ FluidsimSettings *fss;
+
+ /* this call uses derivedMesh methods... */
+ if(srcob->type!=OB_MESH) return NULL;
+
+ fss= MEM_callocN( sizeof(FluidsimSettings), "fluidsimsettings memory");
+
+ fss->type = 0;
+ fss->show_advancedoptions = 0;
+
+ fss->resolutionxyz = 50;
+ fss->previewresxyz = 25;
+ fss->realsize = 0.03;
+ fss->guiDisplayMode = 2; // preview
+ fss->renderDisplayMode = 3; // render
+
+ fss->viscosityMode = 2; // default to water
+ fss->viscosityValue = 1.0;
+ fss->viscosityExponent = 6;
+ fss->gravx = 0.0;
+ fss->gravy = 0.0;
+ fss->gravz = -9.81;
+ fss->animStart = 0.0;
+ fss->animEnd = 0.30;
+ fss->gstar = 0.005; // used as normgstar
+ fss->maxRefine = -1;
+ // maxRefine is set according to resolutionxyz during bake
+
+ // fluid/inflow settings
+ fss->iniVelx =
+ fss->iniVely =
+ fss->iniVelz = 0.0;
+
+ /* elubie: changed this to default to the same dir as the render output
+ to prevent saving to C:\ on Windows */
+ BLI_strncpy(fss->surfdataPath, U.tempdir, FILE_MAX);
+ fss->orgMesh = (Mesh *)srcob->data;
+ fss->meshSurface = NULL;
+ fss->meshBB = NULL;
+ fss->meshSurfNormals = NULL;
+
+ // first init of bounding box
+ fss->bbStart[0] = 0.0;
+ fss->bbStart[1] = 0.0;
+ fss->bbStart[2] = 0.0;
+ fss->bbSize[0] = 1.0;
+ fss->bbSize[1] = 1.0;
+ fss->bbSize[2] = 1.0;
+ fluidsimGetAxisAlignedBB(srcob->data, srcob->obmat, fss->bbStart, fss->bbSize, &fss->meshBB);
+
+ // todo - reuse default init from elbeem!
+ fss->typeFlags = 0;
+ fss->domainNovecgen = 0;
+ fss->volumeInitType = 1; // volume
+ fss->partSlipValue = 0.0;
+
+ fss->generateTracers = 0;
+ fss->generateParticles = 0.0;
+ fss->surfaceSmoothing = 1.0;
+ fss->surfaceSubdivs = 1.0;
+ fss->particleInfSize = 0.0;
+ fss->particleInfAlpha = 0.0;
+
+ return fss;
+}
+
+/* duplicate struct, analogous to free */
+static Mesh *fluidsimCopyMesh(Mesh *me)
+{
+ Mesh *dup = MEM_dupallocN(me);
+
+ CustomData_copy(&me->vdata, &dup->vdata, CD_MASK_MESH, CD_DUPLICATE, me->totvert);
+ CustomData_copy(&me->edata, &dup->edata, CD_MASK_MESH, CD_DUPLICATE, me->totedge);
+ CustomData_copy(&me->fdata, &dup->fdata, CD_MASK_MESH, CD_DUPLICATE, me->totface);
+
+ return dup;
+}
+
+FluidsimSettings* fluidsimSettingsCopy(FluidsimSettings *fss)
+{
+ FluidsimSettings *dupfss;
+
+ if(!fss) return NULL;
+ dupfss = MEM_dupallocN(fss);
+
+ if(fss->meshSurface)
+ dupfss->meshSurface = fluidsimCopyMesh(fss->meshSurface);
+ if(fss->meshBB)
+ dupfss->meshBB = fluidsimCopyMesh(fss->meshBB);
+
+ if(fss->meshSurfNormals) dupfss->meshSurfNormals = MEM_dupallocN(fss->meshSurfNormals);
+
+ return dupfss;
+}
+
+/* free struct */
+static void fluidsimFreeMesh(Mesh *me)
+{
+ CustomData_free(&me->vdata, me->totvert);
+ CustomData_free(&me->edata, me->totedge);
+ CustomData_free(&me->fdata, me->totface);
+
+ MEM_freeN(me);
+}
+
+void fluidsimSettingsFree(FluidsimSettings *fss)
+{
+ if(fss->meshSurface) {
+ fluidsimFreeMesh(fss->meshSurface);
+ fss->meshSurface = NULL;
+ }
+ if(fss->meshBB) {
+ fluidsimFreeMesh(fss->meshBB);
+ fss->meshBB = NULL;
+ }
+
+ if(fss->meshSurfNormals){ MEM_freeN(fss->meshSurfNormals); fss->meshSurfNormals=NULL; }
+
+ MEM_freeN(fss);
+}
+
+
+/* helper function */
+void fluidsimGetGeometryObjFilename(struct Object *ob, char *dst) { //, char *srcname) {
+ //snprintf(dst,FILE_MAXFILE, "%s_cfgdata_%s.bobj.gz", srcname, ob->id.name);
+ snprintf(dst,FILE_MAXFILE, "fluidcfgdata_%s.bobj.gz", ob->id.name);
+}
+
+
+
+
+/* ******************************************************************************** */
+/* ********************** fluid sim channel helper functions ********************** */
+/* ******************************************************************************** */
+
+// no. of entries for the two channel sizes
+#define CHANNEL_FLOAT 1
+#define CHANNEL_VEC 3
+
+#define FS_FREE_ONECHANNEL(c,str) { \
+ if(c){ MEM_freeN(c); c=NULL; } \
+} // end ONE CHANN, debug: fprintf(stderr,"freeing " str " \n");
+
+#define FS_FREE_CHANNELS { \
+ FS_FREE_ONECHANNEL(timeAtIndex,"timeAtIndex");\
+ FS_FREE_ONECHANNEL(timeAtFrame,"timeAtFrame");\
+ FS_FREE_ONECHANNEL(channelDomainTime,"channelDomainTime"); \
+ FS_FREE_ONECHANNEL(channelDomainGravity,"channelDomainGravity");\
+ FS_FREE_ONECHANNEL(channelDomainViscosity,"channelDomainViscosity");\
+ for(i=0;i<256;i++) { \
+ FS_FREE_ONECHANNEL(channelObjMove[i][0],"channelObjMove0"); \
+ FS_FREE_ONECHANNEL(channelObjMove[i][1],"channelObjMove1"); \
+ FS_FREE_ONECHANNEL(channelObjMove[i][2],"channelObjMove2"); \
+ FS_FREE_ONECHANNEL(channelObjInivel[i],"channelObjInivel"); \
+ FS_FREE_ONECHANNEL(channelObjActive[i],"channelObjActive"); \
+ } \
+} // end FS FREE CHANNELS
+
+
+// simplify channels before printing
+// for API this is done anyway upon init
+#if 0
+static void fluidsimPrintChannel(FILE *file, float *channel, int paramsize, char *str, int entries)
+{
+ int i,j;
+ int channelSize = paramsize;
+
+ if(entries==3) {
+ elbeemSimplifyChannelVec3( channel, &channelSize);
+ } else if(entries==1) {
+ elbeemSimplifyChannelFloat( channel, &channelSize);
+ } else {
+ // invalid, cant happen?
+ }
+
+ fprintf(file, " CHANNEL %s = \n", str);
+ for(i=0; i<channelSize;i++) {
+ fprintf(file," ");
+ for(j=0;j<=entries;j++) { // also print time value
+ fprintf(file," %f ", channel[i*(entries+1)+j] );
+ if(j==entries-1){ fprintf(file," "); }
+ }
+ fprintf(file," \n");
+ }
+
+ fprintf(file, " ; \n" );
+}
+#endif
+
+static void fluidsimInitChannel(float **setchannel, int size, float *time,
+ int *icuIds, float *defaults, Ipo* ipo, int entries) {
+ int i,j;
+ IpoCurve* icus[3];
+ char *cstr = NULL;
+ float *channel = NULL;
+ float aniFrlen = G.scene->r.framelen;
+ if((entries<1) || (entries>3)) {
+ printf("fluidsimInitChannel::Error - invalid no. of entries: %d\n",entries);
+ entries = 1;
+ }
+
+ cstr = "fluidsiminit_channelfloat";
+ if(entries>1) cstr = "fluidsiminit_channelvec";
+ channel = MEM_callocN( size* (entries+1)* sizeof(float), cstr );
+
+ if(ipo) {
+ for(j=0; j<entries; j++) icus[j] = find_ipocurve(ipo, icuIds[j] );
+ } else {
+ for(j=0; j<entries; j++) icus[j] = NULL;
+ }
+
+ for(j=0; j<entries; j++) {
+ if(icus[j]) {
+ for(i=1; i<=size; i++) {
+ calc_icu(icus[j], aniFrlen*((float)i) );
+ channel[(i-1)*(entries+1) + j] = icus[j]->curval;
+ }
+ } else {
+ for(i=1; i<=size; i++) { channel[(i-1)*(entries+1) + j] = defaults[j]; }
+ }
+ //printf("fluidsimInitChannel entry:%d , ",j); for(i=1; i<=size; i++) { printf(" val%d:%f ",i, channel[(i-1)*(entries+1) + j] ); } printf(" \n"); // DEBUG
+ }
+ // set time values
+ for(i=1; i<=size; i++) {
+ channel[(i-1)*(entries+1) + entries] = time[i];
+ }
+
+ *setchannel = channel;
+}
+
+static void fluidsimInitMeshChannel(float **setchannel, int size, Object *obm, int vertices, float *time) {
+ float *channel = NULL;
+ int mallsize = size* (3*vertices+1);
+ int frame,i;
+ int numVerts=0, numTris=0;
+ int setsize = 3*vertices+1;
+
+ channel = MEM_callocN( mallsize* sizeof(float), "fluidsim_meshchannel" );
+
+ //fprintf(stderr,"\n\nfluidsimInitMeshChannel size%d verts%d mallsize%d \n\n\n",size,vertices,mallsize);
+ for(frame=1; frame<=size; frame++) {
+ float *verts=NULL;
+ int *tris=NULL;
+ G.scene->r.cfra = frame;
+ scene_update_for_newframe(G.scene, G.scene->lay);
+
+ initElbeemMesh(obm, &numVerts, &verts, &numTris, &tris, 1);
+ //fprintf(stderr,"\nfluidsimInitMeshChannel frame%d verts%d/%d \n\n",frame,vertices,numVerts);
+ for(i=0; i<3*vertices;i++) {
+ channel[(frame-1)*setsize + i] = verts[i];
+ //fprintf(stdout," frame%d vert%d=%f \n",frame,i,verts[i]);
+ //if(i%3==2) fprintf(stdout,"\n");
+ }
+ channel[(frame-1)*setsize + setsize-1] = time[frame];
+
+ MEM_freeN(verts);
+ MEM_freeN(tris);
+ }
+ *setchannel = channel;
+}
+
+
+/* ******************************************************************************** */
+/* ********************** simulation thread ************************* */
+/* ******************************************************************************** */
+
+SDL_mutex *globalBakeLock=NULL;
+int globalBakeState = 0; // 0 everything ok, -1 abort simulation, -2 sim error, 1 sim done
+int globalBakeFrame = 0;
+
+// run simulation in seperate thread
+static int fluidsimSimulateThread(void *unused) { // *ptr) {
+ //char* fnameCfgPath = (char*)(ptr);
+ int ret=0;
+
+ ret = elbeemSimulate();
+ SDL_mutexP(globalBakeLock);
+ if(globalBakeState==0) {
+ if(ret==0) {
+ // if no error, set to normal exit
+ globalBakeState = 1;
+ } else {
+ // simulation failed, display error
+ globalBakeState = -2;
+ }
+ }
+ SDL_mutexV(globalBakeLock);
+ return ret;
+}
+
+
+int runSimulationCallback(void *data, int status, int frame) {
+ //elbeemSimulationSettings *settings = (elbeemSimulationSettings*)data;
+ //printf("elbeem blender cb s%d, f%d, domainid:%d \n", status,frame, settings->domainId ); // DEBUG
+
+ if(!globalBakeLock) return FLUIDSIM_CBRET_ABORT;
+ if(status==FLUIDSIM_CBSTATUS_NEWFRAME) {
+ SDL_mutexP(globalBakeLock);
+ globalBakeFrame = frame-1;
+ SDL_mutexV(globalBakeLock);
+ }
+
+ //if((frameCounter==3) && (!frameStop)) { frameStop=1; return 1; }
+
+ SDL_mutexP(globalBakeLock);
+ if(globalBakeState!=0) {
+ return FLUIDSIM_CBRET_ABORT;
+ }
+ SDL_mutexV(globalBakeLock);
+ return FLUIDSIM_CBRET_CONTINUE;
+}
+
+
+/* ******************************************************************************** */
+/* ********************** write fluidsim config to file ************************* */
+/* ******************************************************************************** */
+
+void fluidsimBake(struct Object *ob)
+{
+ FILE *fileCfg;
+ int i;
+ struct Object *fsDomain = NULL;
+ FluidsimSettings *domainSettings;
+ struct Object *obit = NULL; /* object iterator */
+ int origFrame = G.scene->r.cfra;
+ char debugStrBuffer[256];
+ int dirExist = 0;
+ int gridlevels = 0;
+ int simAborted = 0; // was the simulation aborted by user?
+ int doExportOnly = 0;
+ char *exportEnvStr = "BLENDER_ELBEEMEXPORTONLY";
+ const char *strEnvName = "BLENDER_ELBEEMDEBUG"; // from blendercall.cpp
+ //char *channelNames[3] = { "translation","rotation","scale" };
+
+ char *suffixConfig = "fluidsim.cfg";
+ char *suffixSurface = "fluidsurface";
+ char newSurfdataPath[FILE_MAXDIR+FILE_MAXFILE]; // modified output settings
+ char targetDir[FILE_MAXDIR+FILE_MAXFILE]; // store & modify output settings
+ char targetFile[FILE_MAXDIR+FILE_MAXFILE]; // temp. store filename from targetDir for access
+ int outStringsChanged = 0; // modified? copy back before baking
+ int haveSomeFluid = 0; // check if any fluid objects are set
+
+ // config vars, inited before either export or run...
+ double calcViscosity = 0.0;
+ int noFrames;
+ double aniFrameTime;
+ float aniFrlen;
+ int channelObjCount;
+ float *bbStart = NULL;
+ float *bbSize = NULL;
+ float domainMat[4][4];
+ float invDomMat[4][4];
+ // channel data
+ int allchannelSize; // fixed by no. of frames
+ int startFrame = 1; // dont use G.scene->r.sfra here, always start with frame 1
+ // easy frame -> sim time calc
+ float *timeAtFrame=NULL, *timeAtIndex=NULL;
+ // domain
+ float *channelDomainTime = NULL;
+ float *channelDomainViscosity = NULL;
+ float *channelDomainGravity = NULL;
+ // objects (currently max. 256 objs)
+ float *channelObjMove[256][3]; // object movments , 0=trans, 1=rot, 2=scale
+ float *channelObjInivel[256]; // initial velocities
+ float *channelObjActive[256]; // obj active channel
+
+ if(getenv(strEnvName)) {
+ int dlevel = atoi(getenv(strEnvName));
+ elbeemSetDebugLevel(dlevel);
+ snprintf(debugStrBuffer,256,"fluidsimBake::msg: Debug messages activated due to envvar '%s'\n",strEnvName);
+ elbeemDebugOut(debugStrBuffer);
+ }
+ if(getenv(exportEnvStr)) {
+ doExportOnly = atoi(getenv(exportEnvStr));
+ snprintf(debugStrBuffer,256,"fluidsimBake::msg: Exporting mode set to '%d' due to envvar '%s'\n",doExportOnly, exportEnvStr);
+ elbeemDebugOut(debugStrBuffer);
+ }
+
+ // make sure it corresponds to startFrame setting
+ // old: noFrames = G.scene->r.efra - G.scene->r.sfra +1;
+ noFrames = G.scene->r.efra - 0;
+ if(noFrames<=0) {
+ pupmenu("Fluidsim Bake Error%t|No frames to export - check your animation range settings. Aborted%x0");
+ return;
+ }
+
+ /* no object pointer, find in selected ones.. */
+ if(!ob) {
+ Base *base;
+ for(base=G.scene->base.first; base; base= base->next) {
+ if ( ((base)->flag & SELECT)
+ // ignore layer setting for now? && ((base)->lay & G.vd->lay)
+ ) {
+ if((!ob)&&(base->object->fluidsimFlag & OB_FLUIDSIM_ENABLE)&&(base->object->type==OB_MESH)) {
+ if(base->object->fluidsimSettings->type == OB_FLUIDSIM_DOMAIN) {
+ ob = base->object;
+ }
+ }
+ }
+ }
+ // no domains found?
+ if(!ob) return;
+ }
+
+ /* check if there's another domain... */
+ for(obit= G.main->object.first; obit; obit= obit->id.next) {
+ if((obit->fluidsimFlag & OB_FLUIDSIM_ENABLE)&&(obit->type==OB_MESH)) {
+ if(obit->fluidsimSettings->type == OB_FLUIDSIM_DOMAIN) {
+ if(obit != ob) {
+ //snprintf(debugStrBuffer,256,"fluidsimBake::warning - More than one domain!\n"); elbeemDebugOut(debugStrBuffer);
+ pupmenu("Fluidsim Bake Error%t|There should be only one domain object! Aborted%x0");
+ return;
+ }
+ }
+ }
+ }
+ /* these both have to be valid, otherwise we wouldnt be here */
+ /* dont use ob here after...*/
+ fsDomain = ob;
+ domainSettings = ob->fluidsimSettings;
+ ob = NULL;
+ /* rough check of settings... */
+ if(domainSettings->previewresxyz > domainSettings->resolutionxyz) {
+ snprintf(debugStrBuffer,256,"fluidsimBake::warning - Preview (%d) >= Resolution (%d)... setting equal.\n", domainSettings->previewresxyz , domainSettings->resolutionxyz);
+ elbeemDebugOut(debugStrBuffer);
+ domainSettings->previewresxyz = domainSettings->resolutionxyz;
+ }
+ // set adaptive coarsening according to resolutionxyz
+ // this should do as an approximation, with in/outflow
+ // doing this more accurate would be overkill
+ // perhaps add manual setting?
+ if(domainSettings->maxRefine <0) {
+ if(domainSettings->resolutionxyz>128) {
+ gridlevels = 2;
+ } else
+ if(domainSettings->resolutionxyz>64) {
+ gridlevels = 1;
+ } else {
+ gridlevels = 0;
+ }
+ } else {
+ gridlevels = domainSettings->maxRefine;
+ }
+ snprintf(debugStrBuffer,256,"fluidsimBake::msg: Baking %s, refine: %d\n", fsDomain->id.name , gridlevels );
+ elbeemDebugOut(debugStrBuffer);
+
+ // check if theres any fluid
+ // abort baking if not...
+ for(obit= G.main->object.first; obit; obit= obit->id.next) {
+ if( (obit->fluidsimFlag & OB_FLUIDSIM_ENABLE) &&
+ (obit->type==OB_MESH) && (
+ (obit->fluidsimSettings->type == OB_FLUIDSIM_FLUID) ||
+ (obit->fluidsimSettings->type == OB_FLUIDSIM_INFLOW) )
+ ) {
+ haveSomeFluid = 1;
+ }
+ }
+ if(!haveSomeFluid) {
+ pupmenu("Fluidsim Bake Error%t|No fluid objects in scene... Aborted%x0");
+ return;
+ }
+
+ // prepare names...
+ strncpy(targetDir, domainSettings->surfdataPath, FILE_MAXDIR);
+ strncpy(newSurfdataPath, domainSettings->surfdataPath, FILE_MAXDIR);
+ BLI_convertstringcode(targetDir, G.sce, 0); // fixed #frame-no
+
+ strcpy(targetFile, targetDir);
+ strcat(targetFile, suffixConfig);
+ if(!doExportOnly) { strcat(targetFile,".tmp"); } // dont overwrite/delete original file
+ // make sure all directories exist
+ // as the bobjs use the same dir, this only needs to be checked
+ // for the cfg output
+ BLI_make_existing_file(targetFile);
+
+ // check selected directory
+ // simply try to open cfg file for writing to test validity of settings
+ fileCfg = fopen(targetFile, "w");
+ if(fileCfg) {
+ dirExist = 1; fclose(fileCfg);
+ // remove cfg dummy from directory test
+ if(!doExportOnly) { BLI_delete(targetFile, 0,0); }
+ }
+
+ if((strlen(targetDir)<1) || (!dirExist)) {
+ char blendDir[FILE_MAXDIR+FILE_MAXFILE], blendFile[FILE_MAXDIR+FILE_MAXFILE];
+ // invalid dir, reset to current/previous
+ strcpy(blendDir, G.sce);
+ BLI_splitdirstring(blendDir, blendFile);
+ if(strlen(blendFile)>6){
+ int len = strlen(blendFile);
+ if( (blendFile[len-6]=='.')&& (blendFile[len-5]=='b')&& (blendFile[len-4]=='l')&&
+ (blendFile[len-3]=='e')&& (blendFile[len-2]=='n')&& (blendFile[len-1]=='d') ){
+ blendFile[len-6] = '\0';
+ }
+ }
+ // todo... strip .blend ?
+ snprintf(newSurfdataPath,FILE_MAXFILE+FILE_MAXDIR,"//fluidsimdata/%s_%s_", blendFile, fsDomain->id.name);
+
+ snprintf(debugStrBuffer,256,"fluidsimBake::error - warning resetting output dir to '%s'\n", newSurfdataPath);
+ elbeemDebugOut(debugStrBuffer);
+ outStringsChanged=1;
+ }
+
+ // check if modified output dir is ok
+ if(outStringsChanged) {
+ char dispmsg[FILE_MAXDIR+FILE_MAXFILE+256];
+ int selection=0;
+ strcpy(dispmsg,"Output settings set to: '");
+ strcat(dispmsg, newSurfdataPath);
+ strcat(dispmsg, "'%t|Continue with changed settings%x1|Discard and abort%x0");
+
+ // ask user if thats what he/she wants...
+ selection = pupmenu(dispmsg);
+ if(selection<1) return; // 0 from menu, or -1 aborted
+ strcpy(targetDir, newSurfdataPath);
+ strncpy(domainSettings->surfdataPath, newSurfdataPath, FILE_MAXDIR);
+ BLI_convertstringcode(targetDir, G.sce, 0); // fixed #frame-no
+ }
+
+ // --------------------------------------------------------------------------------------------
+ // dump data for start frame
+ // CHECK more reasonable to number frames according to blender?
+ // dump data for frame 0
+ G.scene->r.cfra = startFrame;
+ scene_update_for_newframe(G.scene, G.scene->lay);
+
+ // init common export vars for both file export and run
+ for(i=0; i<256; i++) {
+ channelObjMove[i][0] = channelObjMove[i][1] = channelObjMove[i][2] = NULL;
+ channelObjInivel[i] = NULL;
+ channelObjActive[i] = NULL;
+ }
+ allchannelSize = G.scene->r.efra; // always use till last frame
+ aniFrameTime = (domainSettings->animEnd - domainSettings->animStart)/(double)noFrames;
+ // blender specific - scale according to map old/new settings in anim panel:
+ aniFrlen = G.scene->r.framelen;
+ if(domainSettings->viscosityMode==1) {
+ /* manual mode, visc=value/(10^-vexp) */
+ calcViscosity = (1.0/pow(10.0,domainSettings->viscosityExponent)) * domainSettings->viscosityValue;
+ } else {
+ calcViscosity = fluidsimViscosityPreset[ domainSettings->viscosityMode ];
+ }
+
+ bbStart = fsDomain->fluidsimSettings->bbStart;
+ bbSize = fsDomain->fluidsimSettings->bbSize;
+ fluidsimGetAxisAlignedBB(fsDomain->data, fsDomain->obmat, bbStart, bbSize, &domainSettings->meshBB);
+
+ // always init
+ { int timeIcu[1] = { FLUIDSIM_TIME };
+ float timeDef[1] = { 1. };
+ int gravIcu[3] = { FLUIDSIM_GRAV_X, FLUIDSIM_GRAV_Y, FLUIDSIM_GRAV_Z };
+ float gravDef[3];
+ int viscIcu[1] = { FLUIDSIM_VISC };
+ float viscDef[1] = { 1. };
+
+ gravDef[0] = domainSettings->gravx;
+ gravDef[1] = domainSettings->gravy;
+ gravDef[2] = domainSettings->gravz;
+
+ // time channel is a bit special, init by hand...
+ timeAtIndex = MEM_callocN( (allchannelSize+1)*1*sizeof(float), "fluidsiminit_timeatindex");
+ for(i=0; i<=G.scene->r.efra; i++) {
+ timeAtIndex[i] = (float)(i-startFrame);
+ }
+ fluidsimInitChannel( &channelDomainTime, allchannelSize, timeAtIndex, timeIcu,timeDef, domainSettings->ipo, CHANNEL_FLOAT ); // NDEB
+ // time channel is a multiplicator for aniFrameTime
+ if(channelDomainTime) {
+ for(i=0; i<allchannelSize; i++) {
+ channelDomainTime[i*2+0] = aniFrameTime * channelDomainTime[i*2+0];
+ if(channelDomainTime[i*2+0]<0.) channelDomainTime[i*2+0] = 0.;
+ }
+ }
+ timeAtFrame = MEM_callocN( (allchannelSize+1)*1*sizeof(float), "fluidsiminit_timeatframe");
+ timeAtFrame[0] = timeAtFrame[1] = domainSettings->animStart; // start at index 1
+ if(channelDomainTime) {
+ for(i=2; i<=allchannelSize; i++) {
+ timeAtFrame[i] = timeAtFrame[i-1]+channelDomainTime[(i-1)*2+0];
+ }
+ } else {
+ for(i=2; i<=allchannelSize; i++) { timeAtFrame[i] = timeAtFrame[i-1]+aniFrameTime; }
+ }
+
+ fluidsimInitChannel( &channelDomainViscosity, allchannelSize, timeAtFrame, viscIcu,viscDef, domainSettings->ipo, CHANNEL_FLOAT ); // NDEB
+ if(channelDomainViscosity) {
+ for(i=0; i<allchannelSize; i++) { channelDomainViscosity[i*2+0] = calcViscosity * channelDomainViscosity[i*2+0]; }
+ }
+ fluidsimInitChannel( &channelDomainGravity, allchannelSize, timeAtFrame, gravIcu,gravDef, domainSettings->ipo, CHANNEL_VEC );
+ } // domain channel init
+
+ // init obj movement channels
+ channelObjCount=0;
+ for(obit= G.main->object.first; obit; obit= obit->id.next) {
+ //{ snprintf(debugStrBuffer,256,"DEBUG object name=%s, type=%d ...\n", obit->id.name, obit->type); elbeemDebugOut(debugStrBuffer); } // DEBUG
+ if( (obit->fluidsimFlag & OB_FLUIDSIM_ENABLE) &&
+ (obit->type==OB_MESH) &&
+ (obit->fluidsimSettings->type != OB_FLUIDSIM_DOMAIN) && // if has to match 3 places! // CHECKMATCH
+ (obit->fluidsimSettings->type != OB_FLUIDSIM_PARTICLE) ) {
+
+ // cant use fluidsimInitChannel for obj channels right now, due
+ // to the special DXXX channels, and the rotation specialities
+ IpoCurve *icuex[3][3];
+ //IpoCurve *par_icuex[3][3];
+ int icuIds[3][3] = {
+ {OB_LOC_X, OB_LOC_Y, OB_LOC_Z},
+ {OB_ROT_X, OB_ROT_Y, OB_ROT_Z},
+ {OB_SIZE_X, OB_SIZE_Y, OB_SIZE_Z}
+ };
+ // relative ipos
+ IpoCurve *icudex[3][3];
+ //IpoCurve *par_icudex[3][3];
+ int icudIds[3][3] = {
+ {OB_DLOC_X, OB_DLOC_Y, OB_DLOC_Z},
+ {OB_DROT_X, OB_DROT_Y, OB_DROT_Z},
+ {OB_DSIZE_X, OB_DSIZE_Y, OB_DSIZE_Z}
+ };
+ int j,k;
+ float vals[3] = {0.0,0.0,0.0};
+ int o = channelObjCount;
+ int inivelIcu[3] = { FLUIDSIM_VEL_X, FLUIDSIM_VEL_Y, FLUIDSIM_VEL_Z };
+ float inivelDefs[3];
+ int activeIcu[1] = { FLUIDSIM_ACTIVE };
+ float activeDefs[1] = { 1 }; // default to on
+
+ inivelDefs[0] = obit->fluidsimSettings->iniVelx;
+ inivelDefs[1] = obit->fluidsimSettings->iniVely;
+ inivelDefs[2] = obit->fluidsimSettings->iniVelz;
+
+ // check & init loc,rot,size
+ for(j=0; j<3; j++) {
+ for(k=0; k<3; k++) {
+ icuex[j][k] = find_ipocurve(obit->ipo, icuIds[j][k] );
+ icudex[j][k] = find_ipocurve(obit->ipo, icudIds[j][k] );
+ //if(obit->parent) {
+ //par_icuex[j][k] = find_ipocurve(obit->parent->ipo, icuIds[j][k] );
+ //par_icudex[j][k] = find_ipocurve(obit->parent->ipo, icudIds[j][k] );
+ //}
+ }
+ }
+
+ for(j=0; j<3; j++) {
+ channelObjMove[o][j] = MEM_callocN( allchannelSize*4*sizeof(float), "fluidsiminit_objmovchannel");
+ for(i=1; i<=allchannelSize; i++) {
+
+ for(k=0; k<3; k++) {
+ if(icuex[j][k]) {
+ // IPO exists, use it ...
+ calc_icu(icuex[j][k], aniFrlen*((float)i) );
+ vals[k] = icuex[j][k]->curval;
+ if(obit->parent) {
+ // add parent transform, multiply scaling, add trafo&rot
+ //calc_icu(par_icuex[j][k], aniFrlen*((float)i) );
+ //if(j==2) { vals[k] *= par_icuex[j][k]->curval; }
+ //else { vals[k] += par_icuex[j][k]->curval; }
+ }
+ } else {
+ // use defaults from static values
+ float setval=0.0;
+ if(j==0) {
+ setval = obit->loc[k];
+ if(obit->parent){ setval += obit->parent->loc[k]; }
+ } else if(j==1) {
+ setval = ( 180.0*obit->rot[k] )/( 10.0*M_PI );
+ if(obit->parent){ setval = ( 180.0*(obit->rot[k]+obit->parent->rot[k]) )/( 10.0*M_PI ); }
+ } else {
+ setval = obit->size[k];
+ if(obit->parent){ setval *= obit->parent->size[k]; }
+ }
+ vals[k] = setval;
+ }
+ if(icudex[j][k]) {
+ calc_icu(icudex[j][k], aniFrlen*((float)i) );
+ //vals[k] += icudex[j][k]->curval;
+ // add transform, multiply scaling, add trafo&rot
+ if(j==2) { vals[k] *= icudex[j][k]->curval; }
+ else { vals[k] += icudex[j][k]->curval; }
+ if(obit->parent) {
+ // add parent transform, multiply scaling, add trafo&rot
+ //calc_icu(par_icuex[j][k], aniFrlen*((float)i) );
+ //if(j==2) { vals[k] *= par_icudex[j][k]->curval; }
+ //else { vals[k] += par_icudex[j][k]->curval; }
+ }
+ }
+ } // k
+
+ for(k=0; k<3; k++) {
+ float set = vals[k];
+ if(j==1) { // rot is downscaled by 10 for ipo !?
+ set = 360.0 - (10.0*set);
+ }
+ channelObjMove[o][j][(i-1)*4 + k] = set;
+ } // k
+ channelObjMove[o][j][(i-1)*4 + 3] = timeAtFrame[i];
+ }
+ }
+
+ fluidsimInitChannel( &channelObjInivel[o], allchannelSize, timeAtFrame, inivelIcu,inivelDefs, obit->fluidsimSettings->ipo, CHANNEL_VEC );
+ fluidsimInitChannel( &channelObjActive[o], allchannelSize, timeAtFrame, activeIcu,activeDefs, obit->fluidsimSettings->ipo, CHANNEL_FLOAT );
+
+ channelObjCount++;
+
+ }
+ }
+
+ // init trafo matrix
+ MTC_Mat4CpyMat4(domainMat, fsDomain->obmat);
+ if(!Mat4Invert(invDomMat, domainMat)) {
+ snprintf(debugStrBuffer,256,"fluidsimBake::error - Invalid obj matrix?\n");
+ elbeemDebugOut(debugStrBuffer);
+ // FIXME add fatal msg
+ FS_FREE_CHANNELS;
+ return;
+ }
+
+
+ // --------------------------------------------------------------------------------------------
+ // start writing / exporting
+ strcpy(targetFile, targetDir);
+ strcat(targetFile, suffixConfig);
+ if(!doExportOnly) { strcat(targetFile,".tmp"); } // dont overwrite/delete original file
+ // make sure these directories exist as well
+ if(outStringsChanged) {
+ BLI_make_existing_file(targetFile);
+ }
+
+ if(!doExportOnly) {
+ SDL_Thread *simthr = NULL;
+
+ // perform simulation with El'Beem api and SDL threads
+ elbeemSimulationSettings fsset;
+ elbeemResetSettings(&fsset);
+ fsset.version = 1;
+
+ // setup global settings
+ for(i=0 ; i<3; i++) fsset.geoStart[i] = bbStart[i];
+ for(i=0 ; i<3; i++) fsset.geoSize[i] = bbSize[i];
+ // simulate with 50^3
+ fsset.resolutionxyz = (int)domainSettings->resolutionxyz;
+ fsset.previewresxyz = (int)domainSettings->previewresxyz;
+ // 10cm water domain
+ fsset.realsize = domainSettings->realsize;
+ fsset.viscosity = calcViscosity;
+ // earth gravity
+ fsset.gravity[0] = domainSettings->gravx;
+ fsset.gravity[1] = domainSettings->gravy;
+ fsset.gravity[2] = domainSettings->gravz;
+ // simulate 5 frames, each 0.03 seconds, output to ./apitest_XXX.bobj.gz
+ fsset.animStart = domainSettings->animStart;
+ fsset.aniFrameTime = aniFrameTime;
+ fsset.noOfFrames = noFrames - 1; // is otherwise subtracted in parser
+ strcpy(targetFile, targetDir);
+ strcat(targetFile, suffixSurface);
+ // defaults for compressibility and adaptive grids
+ fsset.gstar = domainSettings->gstar;
+ fsset.maxRefine = domainSettings->maxRefine; // check <-> gridlevels
+ fsset.generateParticles = domainSettings->generateParticles;
+ fsset.numTracerParticles = domainSettings->generateTracers;
+ fsset.surfaceSmoothing = domainSettings->surfaceSmoothing;
+ fsset.surfaceSubdivs = domainSettings->surfaceSubdivs;
+ fsset.farFieldSize = domainSettings->farFieldSize;
+ strcpy( fsset.outputPath, targetFile);
+
+ // domain channels
+ fsset.channelSizeFrameTime =
+ fsset.channelSizeViscosity =
+ fsset.channelSizeGravity = allchannelSize;
+ fsset.channelFrameTime = channelDomainTime;
+ fsset.channelViscosity = channelDomainViscosity;
+ fsset.channelGravity = channelDomainGravity;
+
+ fsset.runsimCallback = &runSimulationCallback;
+ fsset.runsimUserData = &fsset;
+
+ if( (domainSettings->typeFlags&OB_FSBND_NOSLIP)) fsset.domainobsType = FLUIDSIM_OBSTACLE_NOSLIP;
+ else if((domainSettings->typeFlags&OB_FSBND_PARTSLIP)) fsset.domainobsType = FLUIDSIM_OBSTACLE_PARTSLIP;
+ else if((domainSettings->typeFlags&OB_FSBND_FREESLIP)) fsset.domainobsType = FLUIDSIM_OBSTACLE_FREESLIP;
+ fsset.domainobsPartslip = domainSettings->partSlipValue;
+ fsset.generateVertexVectors = (domainSettings->domainNovecgen==0);
+
+ // init blender trafo matrix
+ // fprintf(stderr,"elbeemInit - mpTrafo:\n");
+ { int j;
+ for(i=0; i<4; i++) {
+ for(j=0; j<4; j++) {
+ fsset.surfaceTrafo[i*4+j] = invDomMat[j][i];
+ // fprintf(stderr,"elbeemInit - mpTrafo %d %d = %f (%d) \n", i,j, fsset.surfaceTrafo[i*4+j] , (i*4+j) );
+ }
+ } }
+
+ // init solver with settings
+ elbeemInit();
+ elbeemAddDomain(&fsset);
+
+ // init objects
+ channelObjCount = 0;
+ for(obit= G.main->object.first; obit; obit= obit->id.next) {
+ //{ snprintf(debugStrBuffer,256,"DEBUG object name=%s, type=%d ...\n", obit->id.name, obit->type); elbeemDebugOut(debugStrBuffer); } // DEBUG
+ if( (obit->fluidsimFlag & OB_FLUIDSIM_ENABLE) && // if has to match 3 places! // CHECKMATCH
+ (obit->type==OB_MESH) &&
+ (obit->fluidsimSettings->type != OB_FLUIDSIM_DOMAIN) &&
+ (obit->fluidsimSettings->type != OB_FLUIDSIM_PARTICLE)
+ ) {
+ float *verts=NULL;
+ int *tris=NULL;
+ int numVerts=0, numTris=0;
+ int o = channelObjCount;
+ int deform = (obit->fluidsimSettings->domainNovecgen); // misused value
+ // todo - use blenderInitElbeemMesh
+ elbeemMesh fsmesh;
+ elbeemResetMesh( &fsmesh );
+ fsmesh.type = obit->fluidsimSettings->type;;
+ // get name of object for debugging solver
+ fsmesh.name = obit->id.name;
+
+ initElbeemMesh(obit, &numVerts, &verts, &numTris, &tris, 0);
+ fsmesh.numVertices = numVerts;
+ fsmesh.numTriangles = numTris;
+ fsmesh.vertices = verts;
+ fsmesh.triangles = tris;
+
+ fsmesh.channelSizeTranslation =
+ fsmesh.channelSizeRotation =
+ fsmesh.channelSizeScale =
+ fsmesh.channelSizeInitialVel =
+ fsmesh.channelSizeActive = allchannelSize;
+
+ fsmesh.channelTranslation = channelObjMove[o][0];
+ fsmesh.channelRotation = channelObjMove[o][1];
+ fsmesh.channelScale = channelObjMove[o][2];
+ fsmesh.channelActive = channelObjActive[o];
+ if( (fsmesh.type == OB_FLUIDSIM_FLUID) ||
+ (fsmesh.type == OB_FLUIDSIM_INFLOW) ) {
+ fsmesh.channelInitialVel = channelObjInivel[o];
+ fsmesh.localInivelCoords = ((obit->fluidsimSettings->typeFlags&OB_FSINFLOW_LOCALCOORD)?1:0);
+ }
+
+ if( (obit->fluidsimSettings->typeFlags&OB_FSBND_NOSLIP)) fsmesh.obstacleType = FLUIDSIM_OBSTACLE_NOSLIP;
+ else if((obit->fluidsimSettings->typeFlags&OB_FSBND_PARTSLIP)) fsmesh.obstacleType = FLUIDSIM_OBSTACLE_PARTSLIP;
+ else if((obit->fluidsimSettings->typeFlags&OB_FSBND_FREESLIP)) fsmesh.obstacleType = FLUIDSIM_OBSTACLE_FREESLIP;
+ fsmesh.obstaclePartslip = obit->fluidsimSettings->partSlipValue;
+ fsmesh.volumeInitType = obit->fluidsimSettings->volumeInitType;
+ fsmesh.obstacleImpactFactor = obit->fluidsimSettings->surfaceSmoothing; // misused value
+
+ // animated meshes
+ if(deform) {
+ fsmesh.channelSizeVertices = allchannelSize;
+ fluidsimInitMeshChannel( &fsmesh.channelVertices, allchannelSize, obit, numVerts, timeAtFrame);
+ G.scene->r.cfra = startFrame;
+ scene_update_for_newframe(G.scene, G.scene->lay);
+ // remove channels
+ fsmesh.channelTranslation =
+ fsmesh.channelRotation =
+ fsmesh.channelScale = NULL;
+ }
+
+ elbeemAddMesh(&fsmesh);
+
+ if(verts) MEM_freeN(verts);
+ if(tris) MEM_freeN(tris);
+ if(fsmesh.channelVertices) MEM_freeN(fsmesh.channelVertices);
+ channelObjCount++;
+ } // valid mesh
+ } // objects
+ //domainSettings->type = OB_FLUIDSIM_DOMAIN; // enable for bake display again
+ //fsDomain->fluidsimFlag = OB_FLUIDSIM_ENABLE; // disable during bake
+
+ globalBakeLock = SDL_CreateMutex();
+ // set to neutral, -1 means user abort, -2 means init error
+ globalBakeState = 0;
+ globalBakeFrame = 0;
+ simthr = SDL_CreateThread(fluidsimSimulateThread, targetFile);
+
+ if(!simthr) {
+ snprintf(debugStrBuffer,256,"fluidsimBake::error: Unable to create thread... running without one.\n");
+ elbeemDebugOut(debugStrBuffer);
+ set_timecursor(0);
+ elbeemSimulate();
+ } else {
+ int done = 0;
+ unsigned short event=0;
+ short val;
+ float noFramesf = (float)noFrames;
+ float percentdone = 0.0;
+ int lastRedraw = -1;
+
+ start_progress_bar();
+
+ while(done==0) {
+ char busy_mess[80];
+
+ waitcursor(1);
+
+ // lukep we add progress bar as an interim mesure
+ percentdone = globalBakeFrame / noFramesf;
+ sprintf(busy_mess, "baking fluids %d / %d |||", globalBakeFrame, (int) noFramesf);
+ progress_bar(percentdone, busy_mess );
+
+ SDL_Delay(2000); // longer delay to prevent frequent redrawing
+ SDL_mutexP(globalBakeLock);
+ if(globalBakeState != 0) done = 1; // 1=ok, <0=error/abort
+ SDL_mutexV(globalBakeLock);
+
+ while(qtest()) {
+ event = extern_qread(&val);
+ if(event == ESCKEY) {
+ // abort...
+ SDL_mutexP(globalBakeLock);
+ done = -1;
+ globalBakeFrame = 0;
+ globalBakeState = -1;
+ simAborted = 1;
+ SDL_mutexV(globalBakeLock);
+ break;
+ }
+ }
+
+ // redraw the 3D for showing progress once in a while...
+ if(lastRedraw!=globalBakeFrame) {
+ ScrArea *sa;
+ G.scene->r.cfra = startFrame+globalBakeFrame;
+ lastRedraw = globalBakeFrame;
+ update_for_newframe_muted();
+ sa= G.curscreen->areabase.first;
+ while(sa) {
+ if(sa->spacetype == SPACE_VIEW3D) { scrarea_do_windraw(sa); }
+ sa= sa->next;
+ }
+ screen_swapbuffers();
+ } // redraw
+ }
+ SDL_WaitThread(simthr,NULL);
+ end_progress_bar();
+ }
+ SDL_DestroyMutex(globalBakeLock);
+ globalBakeLock = NULL;
+ } // El'Beem API init, thread creation
+ // --------------------------------------------------------------------------------------------
+ else
+ { // write config file to be run with command line simulator
+ pupmenu("Fluidsim Bake Message%t|Config file export not supported.%x0");
+ } // config file export done!
+
+ // --------------------------------------------------------------------------------------------
+ FS_FREE_CHANNELS;
+
+ // go back to "current" blender time
+ waitcursor(0);
+ G.scene->r.cfra = origFrame;
+ scene_update_for_newframe(G.scene, G.scene->lay);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSOBJECT, 0);
+
+ if(!simAborted) {
+ char fsmessage[512];
+ char elbeemerr[256];
+ strcpy(fsmessage,"Fluidsim Bake Error: ");
+ // check if some error occurred
+ if(globalBakeState==-2) {
+ strcat(fsmessage,"Failed to initialize [Msg: ");
+
+ elbeemGetErrorString(elbeemerr);
+ strcat(fsmessage,elbeemerr);
+
+ strcat(fsmessage,"] |OK%x0");
+ pupmenu(fsmessage);
+ } // init error
+ }
+}
+
+
+#else /* DISABLE_ELBEEM */
+
+/* compile dummy functions for disabled fluid sim */
+
+FluidsimSettings *fluidsimSettingsNew(struct Object *srcob) {
+ return NULL;
+}
+
+void fluidsimSettingsFree(FluidsimSettings *fss) {
+}
+
+FluidsimSettings* fluidsimSettingsCopy(FluidsimSettings *fss) {
+ return NULL;
+}
+
+/* only compile dummy functions */
+void fluidsimBake(struct Object *ob) {
+}
+
+#endif /* DISABLE_ELBEEM */
+
diff --git a/source/blender/src/fsmenu.c b/source/blender/src/fsmenu.c
new file mode 100644
index 00000000000..319fb8de48f
--- /dev/null
+++ b/source/blender/src/fsmenu.c
@@ -0,0 +1,257 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BMF_Api.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_linklist.h"
+#include "BLI_dynstr.h"
+#include "BIF_usiblender.h"
+
+
+#include "BIF_fsmenu.h" /* include ourselves */
+
+
+/* FSMENU HANDLING */
+
+ /* FSMenuEntry's without paths indicate seperators */
+typedef struct _FSMenuEntry FSMenuEntry;
+struct _FSMenuEntry {
+ FSMenuEntry *next;
+
+ char *path;
+ short save;
+};
+
+static FSMenuEntry *fsmenu= 0;
+
+int fsmenu_get_nentries(void)
+{
+ FSMenuEntry *fsme;
+ int count= 0;
+
+ for (fsme= fsmenu; fsme; fsme= fsme->next)
+ count++;
+
+ return count;
+}
+int fsmenu_is_entry_a_seperator(int idx)
+{
+ FSMenuEntry *fsme;
+
+ for (fsme= fsmenu; fsme && idx; fsme= fsme->next)
+ idx--;
+
+ return (fsme && !fsme->path)?1:0;
+}
+char *fsmenu_get_entry(int idx)
+{
+ FSMenuEntry *fsme;
+
+ for (fsme= fsmenu; fsme && idx; fsme= fsme->next)
+ idx--;
+
+ return fsme?fsme->path:NULL;
+}
+char *fsmenu_build_menu(void)
+{
+ DynStr *ds= BLI_dynstr_new();
+ FSMenuEntry *fsme;
+ char *menustr;
+
+ for (fsme= fsmenu; fsme; fsme= fsme->next) {
+ if (!fsme->path) {
+ /* clean consecutive seperators and ignore trailing ones */
+ if (fsme->next) {
+ if (fsme->next->path) {
+ BLI_dynstr_append(ds, "%l|");
+ } else {
+ FSMenuEntry *next= fsme->next;
+ fsme->next= next->next;
+ MEM_freeN(next);
+ }
+ }
+ } else {
+ if (fsme->save) {
+ BLI_dynstr_append(ds, "o ");
+ } else {
+ BLI_dynstr_append(ds, " ");
+ }
+ BLI_dynstr_append(ds, fsme->path);
+ if (fsme->next) BLI_dynstr_append(ds, "|");
+ }
+ }
+
+ menustr= BLI_dynstr_get_cstring(ds);
+ BLI_dynstr_free(ds);
+ return menustr;
+}
+static FSMenuEntry *fsmenu_get_last_separator(void)
+{
+ FSMenuEntry *fsme, *lsep=NULL;
+
+ for (fsme= fsmenu; fsme; fsme= fsme->next)
+ if (!fsme->path)
+ lsep= fsme;
+
+ return lsep;
+}
+
+static FSMenuEntry *fsmenu_get_first_separator(void)
+{
+ FSMenuEntry *fsme, *lsep=NULL;
+
+ for (fsme= fsmenu; fsme; fsme= fsme->next)
+ if (!fsme->path) {
+ lsep= fsme;
+ break;
+ }
+
+ return lsep;
+}
+
+void fsmenu_insert_entry(char *path, int sorted, short save)
+{
+ FSMenuEntry *prev;
+ FSMenuEntry *fsme;
+
+ if (save) {
+ prev = fsmenu_get_first_separator();
+ } else {
+ prev = fsmenu_get_last_separator();
+ }
+ fsme= prev?prev->next:fsmenu;
+
+ for (; fsme; prev= fsme, fsme= fsme->next) {
+ if (fsme->path) {
+ if (BLI_streq(path, fsme->path)) {
+ return;
+ } else if (sorted && strcmp(path, fsme->path)<0) {
+ break;
+ }
+ } else {
+ // if we're bookmarking this, file should come
+ // before the last separator, only automatically added
+ // current dir go after the last sep.
+ if (save) {
+ break;
+ }
+ }
+ }
+
+ fsme= MEM_mallocN(sizeof(*fsme), "fsme");
+ fsme->path= BLI_strdup(path);
+ fsme->save = save;
+
+ if (prev) {
+ fsme->next= prev->next;
+ prev->next= fsme;
+ } else {
+ fsme->next= fsmenu;
+ fsmenu= fsme;
+ }
+}
+void fsmenu_append_separator(void)
+{
+ if (fsmenu) {
+ FSMenuEntry *fsme= fsmenu;
+
+ while (fsme->next) fsme= fsme->next;
+
+ fsme->next= MEM_mallocN(sizeof(*fsme), "fsme");
+ fsme->next->next= NULL;
+ fsme->next->path= NULL;
+ }
+}
+void fsmenu_remove_entry(int idx)
+{
+ FSMenuEntry *prev= NULL, *fsme= fsmenu;
+
+ for (fsme= fsmenu; fsme && idx; prev= fsme, fsme= fsme->next)
+ idx--;
+
+ if (fsme) {
+ /* you should only be able to remove entries that were
+ not added by default, like windows drives.
+ also separators (where path == NULL) shouldn't be removed */
+ if (fsme->save && fsme->path) {
+
+ /* remove fsme from list */
+ if (prev) {
+ prev->next= fsme->next;
+ } else {
+ fsmenu= fsme->next;
+ }
+ /* free entry */
+ MEM_freeN(fsme->path);
+ MEM_freeN(fsme);
+ }
+ }
+}
+
+void fsmenu_write_file(const char *filename)
+{
+ FSMenuEntry *fsme= fsmenu;
+
+ FILE *fp = fopen(filename, "w");
+ if (!fp) return;
+
+ for (fsme= fsmenu; fsme; fsme= fsme->next) {
+ if (fsme->path && fsme->save) {
+ fprintf(fp, "%s\n", fsme->path);
+ }
+ }
+ fclose(fp);
+}
+
+void fsmenu_free(void)
+{
+ FSMenuEntry *fsme= fsmenu;
+
+ while (fsme) {
+ FSMenuEntry *n= fsme->next;
+
+ if (fsme->path) MEM_freeN(fsme->path);
+ MEM_freeN(fsme);
+
+ fsme= n;
+ }
+}
+
+
+
diff --git a/source/blender/src/ghostwinlay.c b/source/blender/src/ghostwinlay.c
new file mode 100644
index 00000000000..597a23a20d7
--- /dev/null
+++ b/source/blender/src/ghostwinlay.c
@@ -0,0 +1,835 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+#include "DNA_userdef_types.h" /* U.flag & TWOBUTTONMOUSE */
+
+#include "BLI_blenlib.h"
+
+#include "GHOST_C-api.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_global.h"
+
+#include "BIF_gl.h"
+#include "BIF_graphics.h"
+#include "BIF_mywindow.h"
+#include "BIF_screen.h"
+#include "BIF_usiblender.h"
+#include "BIF_cursors.h"
+
+#include "mydevice.h"
+#include "blendef.h"
+
+#include "winlay.h"
+
+#ifdef __APPLE__
+#include <OpenGL/OpenGL.h>
+#define __CARBONSOUND__
+ /* XXX BIG WARNING: carbon.h should not be included in blender/src code, it conflicts with struct ID */
+#define ID ID_
+#include <Carbon/Carbon.h>
+
+/*declarations*/
+int checkAppleVideoCard(void);
+void getMacAvailableBounds(short *, short *, short *, short *);
+
+#endif
+///
+
+struct _Window {
+ GHOST_WindowHandle ghostwin;
+
+ /* Handler and private data for handler */
+ WindowHandlerFP handler;
+ void *user_data;
+
+ /* Window state */
+ int size[2], position[2];
+ int active, visible;
+
+ /* Last known mouse/button/qualifier state */
+ int lmouse[2];
+ int lqual; /* (LR_SHFTKEY, LR_CTRLKEY, LR_ALTKEY, LR_COMMANDKEY) */
+ int lmbut; /* (L_MOUSE, M_MOUSE, R_MOUSE) */
+
+ /* xtilt and ytilt represent how much the pen is tilted away from
+ * vertically upright in either the X or Y direction, with X and Y the
+ * axes of the tablet surface.
+ * In other words, Xtilt and Ytilt are components of a vector created by projecting
+ * the pen's angle in 3D space vertically downwards on to the XY plane
+ * --Matt
+ */
+ float pressure; /* tablet pressure - 0.0 (no pressure) to 1.0 (full pressure) */
+ /* mouse clicks and non-contacting stylus buttons generate pressure of 0.0. */
+ float xtilt, ytilt; /* tablet tilt value - x and y components of 3D angle
+ * ranging from 0.0 (pen upright) to 1.0 (pen fully leaning over) */
+ short activedevice; /* Active input device currently in use (DEV_MOUSE, DEV_STYLUS, DEV_ERASER) */
+
+
+ /* Tracks the faked mouse button, if non-zero it is
+ * the event number of the last faked button.
+ */
+ int faked_mbut;
+
+ GHOST_TimerTaskHandle timer;
+ int timer_event;
+};
+
+///
+
+#ifdef __APPLE__
+
+/* to avoid killing small end comps, we want to allow
+ blender to start maximised if all the followings are true :
+ - Renderer is OpenGL capable
+ - Hardware acceleration
+ - VRAM > 16 Mo
+
+ we will bail out if VRAM is less than 8Mo
+ */
+
+static int macPrefState = 0;
+
+int checkAppleVideoCard(void) {
+ long theErr;
+ unsigned long display_mask;
+ CGLRendererInfoObj rend;
+ long nrend;
+ int j;
+ long value;
+ long maxvram = 0; /* we get always more than 1 renderer, check one, at least, has 8 Mo */
+
+ display_mask = CGDisplayIDToOpenGLDisplayMask (CGMainDisplayID() );
+
+ theErr = CGLQueryRendererInfo( display_mask, &rend, &nrend);
+ if (theErr == 0) {
+ theErr = CGLDescribeRenderer (rend, 0, kCGLRPRendererCount, &nrend);
+ if (theErr == 0) {
+ for (j = 0; j < nrend; j++) {
+ theErr = CGLDescribeRenderer (rend, j, kCGLRPVideoMemory, &value);
+ if (value > maxvram)
+ maxvram = value;
+ if ((theErr == 0) && (value >= 20000000)) {
+ theErr = CGLDescribeRenderer (rend, j, kCGLRPAccelerated, &value);
+ if ((theErr == 0) && (value != 0)) {
+ theErr = CGLDescribeRenderer (rend, j, kCGLRPCompliant, &value);
+ if ((theErr == 0) && (value != 0)) {
+ /*fprintf(stderr,"make it big\n");*/
+ CGLDestroyRendererInfo (rend);
+ macPrefState = 8;
+ return 1;
+ }
+ }
+ }
+ }
+ }
+ }
+ if (maxvram < 7500000 ) { /* put a standard alert and quit*/
+ SInt16 junkHit;
+ char inError[] = "* Not enough VRAM ";
+ char inText[] = "* blender needs at least 8Mb ";
+ inError[0] = 16;
+ inText[0] = 28;
+
+ fprintf(stderr, " vram is %li . not enough, aborting\n", maxvram);
+ StandardAlert ( kAlertStopAlert, (ConstStr255Param) &inError, (ConstStr255Param)&inText,NULL,&junkHit);
+ abort();
+ }
+ CGLDestroyRendererInfo (rend);
+ return 0;
+}
+
+void getMacAvailableBounds(short *top, short *left, short *bottom, short *right) {
+ Rect outAvailableRect;
+
+ GetAvailableWindowPositioningBounds ( GetMainDevice(), &outAvailableRect);
+
+ *top = outAvailableRect.top;
+ *left = outAvailableRect.left;
+ *bottom = outAvailableRect.bottom;
+ *right = outAvailableRect.right;
+}
+
+#endif
+
+
+static GHOST_SystemHandle g_system= 0;
+
+ /* Some simple ghost <-> blender conversions */
+
+static GHOST_TStandardCursor convert_cursor(int curs) {
+ switch(curs) {
+ default:
+ case CURSOR_STD: return GHOST_kStandardCursorDefault;
+ case CURSOR_VPAINT: return GHOST_kStandardCursorRightArrow;
+ case CURSOR_FACESEL: return GHOST_kStandardCursorRightArrow;
+ case CURSOR_WAIT: return GHOST_kStandardCursorWait;
+ case CURSOR_EDIT: return GHOST_kStandardCursorCrosshair;
+ case CURSOR_HELP: return GHOST_kStandardCursorHelp;
+ case CURSOR_X_MOVE: return GHOST_kStandardCursorLeftRight;
+ case CURSOR_Y_MOVE: return GHOST_kStandardCursorUpDown;
+ case CURSOR_PENCIL: return GHOST_kStandardCursorPencil;
+ }
+}
+
+static int convert_mbut(GHOST_TButtonMask but) {
+ if (but == GHOST_kButtonMaskLeft) {
+ return LEFTMOUSE;
+ } else if (but == GHOST_kButtonMaskRight) {
+ return RIGHTMOUSE;
+ } else {
+ return MIDDLEMOUSE;
+ }
+}
+
+static int convert_key(GHOST_TKey key) {
+ if (key>=GHOST_kKeyA && key<=GHOST_kKeyZ) {
+ return (AKEY + ((int) key - GHOST_kKeyA));
+ } else if (key>=GHOST_kKey0 && key<=GHOST_kKey9) {
+ return (ZEROKEY + ((int) key - GHOST_kKey0));
+ } else if (key>=GHOST_kKeyNumpad0 && key<=GHOST_kKeyNumpad9) {
+ return (PAD0 + ((int) key - GHOST_kKeyNumpad0));
+ } else if (key>=GHOST_kKeyF1 && key<=GHOST_kKeyF12) {
+ return (F1KEY + ((int) key - GHOST_kKeyF1));
+ } else {
+ switch (key) {
+ case GHOST_kKeyBackSpace: return BACKSPACEKEY;
+ case GHOST_kKeyTab: return TABKEY;
+ case GHOST_kKeyLinefeed: return LINEFEEDKEY;
+ case GHOST_kKeyClear: return 0;
+ case GHOST_kKeyEnter: return RETKEY;
+
+ case GHOST_kKeyEsc: return ESCKEY;
+ case GHOST_kKeySpace: return SPACEKEY;
+ case GHOST_kKeyQuote: return QUOTEKEY;
+ case GHOST_kKeyComma: return COMMAKEY;
+ case GHOST_kKeyMinus: return MINUSKEY;
+ case GHOST_kKeyPeriod: return PERIODKEY;
+ case GHOST_kKeySlash: return SLASHKEY;
+
+ case GHOST_kKeySemicolon: return SEMICOLONKEY;
+ case GHOST_kKeyEqual: return EQUALKEY;
+
+ case GHOST_kKeyLeftBracket: return LEFTBRACKETKEY;
+ case GHOST_kKeyRightBracket: return RIGHTBRACKETKEY;
+ case GHOST_kKeyBackslash: return BACKSLASHKEY;
+ case GHOST_kKeyAccentGrave: return ACCENTGRAVEKEY;
+
+ case GHOST_kKeyLeftShift: return LEFTSHIFTKEY;
+ case GHOST_kKeyRightShift: return RIGHTSHIFTKEY;
+ case GHOST_kKeyLeftControl: return LEFTCTRLKEY;
+ case GHOST_kKeyRightControl: return RIGHTCTRLKEY;
+ case GHOST_kKeyCommand: return COMMANDKEY;
+ case GHOST_kKeyLeftAlt: return LEFTALTKEY;
+ case GHOST_kKeyRightAlt: return RIGHTALTKEY;
+
+ case GHOST_kKeyCapsLock: return CAPSLOCKKEY;
+ case GHOST_kKeyNumLock: return 0;
+ case GHOST_kKeyScrollLock: return 0;
+
+ case GHOST_kKeyLeftArrow: return LEFTARROWKEY;
+ case GHOST_kKeyRightArrow: return RIGHTARROWKEY;
+ case GHOST_kKeyUpArrow: return UPARROWKEY;
+ case GHOST_kKeyDownArrow: return DOWNARROWKEY;
+
+ case GHOST_kKeyPrintScreen: return 0;
+ case GHOST_kKeyPause: return PAUSEKEY;
+
+ case GHOST_kKeyInsert: return INSERTKEY;
+ case GHOST_kKeyDelete: return DELKEY;
+ case GHOST_kKeyHome: return HOMEKEY;
+ case GHOST_kKeyEnd: return ENDKEY;
+ case GHOST_kKeyUpPage: return PAGEUPKEY;
+ case GHOST_kKeyDownPage: return PAGEDOWNKEY;
+
+ case GHOST_kKeyNumpadPeriod: return PADPERIOD;
+ case GHOST_kKeyNumpadEnter: return PADENTER;
+ case GHOST_kKeyNumpadPlus: return PADPLUSKEY;
+ case GHOST_kKeyNumpadMinus: return PADMINUS;
+ case GHOST_kKeyNumpadAsterisk: return PADASTERKEY;
+ case GHOST_kKeyNumpadSlash: return PADSLASHKEY;
+
+ case GHOST_kKeyGrLess: return GRLESSKEY;
+
+ case GHOST_kKeyUnknown: return UNKNOWNKEY;
+
+ default:
+ return 0;
+ }
+ }
+}
+
+ /***/
+
+
+static Window *window_new(GHOST_WindowHandle ghostwin)
+{
+ Window *win= MEM_callocN(sizeof(*win), "Window");
+ win->ghostwin= ghostwin;
+
+ return win;
+}
+
+static void window_handle(Window *win, short event, short val)
+{
+ if (win->handler) {
+ win->handler(win, win->user_data, event, val, 0);
+ }
+}
+
+static void window_handle_ext(Window *win, short event, short val, short extra)
+{
+ if (win->handler) {
+ win->handler(win, win->user_data, event, val, extra);
+ }
+}
+
+static void window_free(Window *win)
+{
+ MEM_freeN(win);
+}
+
+ /***/
+
+static Window *active_gl_window= NULL;
+
+Window *window_open(char *title, int posx, int posy, int sizex, int sizey, int start_maximized)
+{
+ GHOST_WindowHandle ghostwin;
+ GHOST_TWindowState inital_state;
+ int scr_w, scr_h;
+
+ winlay_get_screensize(&scr_w, &scr_h);
+ posy= (scr_h-posy-sizey);
+
+ if (start_maximized == G_WINDOWSTATE_FULLSCREEN)
+ inital_state = start_maximized?GHOST_kWindowStateFullScreen:GHOST_kWindowStateNormal;
+ else
+ inital_state = start_maximized?GHOST_kWindowStateMaximized:GHOST_kWindowStateNormal;
+#ifdef __APPLE__
+ inital_state += macPrefState;
+#endif
+
+ ghostwin= GHOST_CreateWindow(g_system,
+ title,
+ posx, posy, sizex, sizey,
+ inital_state,
+ GHOST_kDrawingContextTypeOpenGL,
+ 0 /* no stereo */);
+
+ if (ghostwin) {
+ Window *win= window_new(ghostwin);
+
+ if (win) {
+ GHOST_SetWindowUserData(ghostwin, win);
+
+ win->position[0]= posx;
+ win->position[1]= posy;
+ win->size[0]= sizex;
+ win->size[1]= sizey;
+
+ win->lmouse[0]= win->size[0]/2;
+ win->lmouse[1]= win->size[1]/2;
+
+
+ } else {
+ GHOST_DisposeWindow(g_system, ghostwin);
+ }
+
+ return win;
+ } else {
+ return NULL;
+ }
+}
+
+void window_set_handler(Window *win, WindowHandlerFP handler, void *user_data)
+{
+ win->handler= handler;
+ win->user_data= user_data;
+}
+
+static void window_timer_proc(GHOST_TimerTaskHandle timer, GHOST_TUns64 time)
+{
+ Window *win= GHOST_GetTimerTaskUserData(timer);
+
+ win->handler(win, win->user_data, win->timer_event, 0, 0);
+}
+
+void window_set_timer(Window *win, int delay_ms, int event)
+{
+ if (win->timer) GHOST_RemoveTimer(g_system, win->timer);
+
+ win->timer_event= event;
+ win->timer= GHOST_InstallTimer(g_system, delay_ms, delay_ms, window_timer_proc, win);
+}
+
+void window_destroy(Window *win) {
+ if (active_gl_window==win) {
+ active_gl_window= NULL;
+ }
+
+ if (win->timer) {
+ GHOST_RemoveTimer(g_system, win->timer);
+ win->timer= NULL;
+ }
+
+ GHOST_DisposeWindow(g_system, win->ghostwin);
+ window_free(win);
+}
+
+void window_set_cursor(Window *win, int curs) {
+ if (curs==CURSOR_NONE) {
+ GHOST_SetCursorVisibility(win->ghostwin, 0);
+ } else {
+ GHOST_SetCursorVisibility(win->ghostwin, 1);
+
+ /* detect if we use system cursor or Blender cursor */
+ switch(curs) {
+ case CURSOR_TEXTEDIT:
+ SetBlenderCursor(BC_TEXTEDITCURSOR);
+ break;
+ case CURSOR_VPAINT:
+ SetBlenderCursor(BC_PAINTBRUSHCURSOR);
+ break;
+ default:
+ GHOST_SetCursorShape(win->ghostwin, convert_cursor(curs));
+ }
+ }
+}
+
+void window_set_custom_cursor(Window *win, unsigned char mask[16][2],
+ unsigned char bitmap[16][2], int hotx, int hoty) {
+ GHOST_SetCustomCursorShape(win->ghostwin, bitmap, mask, hotx, hoty);
+}
+
+void window_set_custom_cursor_ex(Window *win, BCursor *cursor, int useBig) {
+ if (useBig) {
+ GHOST_SetCustomCursorShapeEx(win->ghostwin,
+ (GHOST_TUns8 *)cursor->big_bm, (GHOST_TUns8 *)cursor->big_mask,
+ cursor->big_sizex,cursor->big_sizey,
+ cursor->big_hotx,cursor->big_hoty,
+ cursor->fg_color, cursor->bg_color);
+ } else {
+ GHOST_SetCustomCursorShapeEx(win->ghostwin,
+ (GHOST_TUns8 *)cursor->small_bm, (GHOST_TUns8 *)cursor->small_mask,
+ cursor->small_sizex,cursor->small_sizey,
+ cursor->small_hotx,cursor->small_hoty,
+ cursor->fg_color, cursor->bg_color);
+ }
+}
+
+void window_make_active(Window *win) {
+ if (win != active_gl_window) {
+ win->lmbut= 0; /* keeps hanging when mousepressed while other window opened */
+ active_gl_window= win;
+ GHOST_ActivateWindowDrawingContext(win->ghostwin);
+ }
+}
+
+void window_swap_buffers(Window *win) {
+ GHOST_SwapWindowBuffers(win->ghostwin);
+}
+
+static int query_qual(char qual) {
+ GHOST_TModifierKeyMask left, right;
+ int val= 0;
+
+ if (qual=='s') {
+ left= GHOST_kModifierKeyLeftShift;
+ right= GHOST_kModifierKeyRightShift;
+ } else if (qual=='c') {
+ left= GHOST_kModifierKeyLeftControl;
+ right= GHOST_kModifierKeyRightControl;
+ } else if (qual=='C') {
+ left= right= GHOST_kModifierKeyCommand;
+ } else {
+ left= GHOST_kModifierKeyLeftAlt;
+ right= GHOST_kModifierKeyRightAlt;
+ }
+
+ GHOST_GetModifierKeyState(g_system, left, &val);
+ if (!val)
+ GHOST_GetModifierKeyState(g_system, right, &val);
+
+ return val;
+}
+
+static int change_bit(int val, int bit, int to_on) {
+ return to_on?(val|bit):(val&~bit);
+}
+
+static void update_tablet_data(Window *win, Window *ghostwin) {
+ const GHOST_TabletData *td= GHOST_GetTabletData(ghostwin);
+
+ /* if there's tablet data from an active tablet device then use it,
+ * otherwise set all tablet related data to default */
+ if ((td != NULL) && ELEM(td->Active, DEV_STYLUS, DEV_ERASER)) {
+ win->activedevice = (short)td->Active;
+ win->pressure = td->Pressure;
+ win->xtilt = td->Xtilt;
+ win->ytilt = td->Ytilt;
+ } else {
+ win->activedevice = DEV_MOUSE;
+ win->pressure = 0.0;
+ win->xtilt = win->ytilt = 0.0;
+ }
+}
+
+
+static int event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr private)
+{
+ GHOST_TEventType type= GHOST_GetEventType(evt);
+
+ if (type == GHOST_kEventQuit) {
+ exit_usiblender();
+ } else {
+ GHOST_WindowHandle ghostwin= GHOST_GetEventWindow(evt);
+ GHOST_TEventDataPtr data= GHOST_GetEventData(evt);
+ Window *win;
+
+ if (!ghostwin) {
+ // XXX - should be checked, why are we getting an event here, and
+ // what is it?
+
+ return 1;
+ } else if (!GHOST_ValidWindow(g_system, ghostwin)) {
+ // XXX - should be checked, why are we getting an event here, and
+ // what is it?
+
+ return 1;
+ } else {
+ win= GHOST_GetWindowUserData(ghostwin);
+ }
+
+ switch (type) {
+ case GHOST_kEventCursorMove: {
+ if(win->active == 1) {
+ GHOST_TEventCursorData *cd= data;
+
+ int cx, cy;
+
+ GHOST_ScreenToClient(win->ghostwin, cd->x, cd->y, &cx, &cy);
+ win->lmouse[0]= cx;
+ win->lmouse[1]= (win->size[1]-1) - cy;
+
+ update_tablet_data(win, ghostwin);
+ window_handle(win, MOUSEX, win->lmouse[0]);
+ window_handle(win, MOUSEY, win->lmouse[1]);
+ }
+ break;
+ }
+ case GHOST_kEventButtonDown:
+ case GHOST_kEventButtonUp: {
+ GHOST_TEventButtonData *bd= data;
+ int val= (type==GHOST_kEventButtonDown);
+ int bbut= convert_mbut(bd->button);
+
+ if (bbut==LEFTMOUSE) {
+ if (val) {
+ if (win->lqual & LR_COMMANDKEY) {
+ bbut= win->faked_mbut= RIGHTMOUSE;
+ } else if ((win->lqual & LR_ALTKEY) && (U.flag & USER_TWOBUTTONMOUSE)) {
+ /* finally, it actually USES the userpref! :) -intrr */
+ bbut= win->faked_mbut= MIDDLEMOUSE;
+ }
+ } else {
+ if (win->faked_mbut) {
+ bbut= win->faked_mbut;
+ win->faked_mbut= 0;
+ }
+ }
+ }
+
+ if (bbut==LEFTMOUSE) {
+ win->lmbut= change_bit(win->lmbut, L_MOUSE, val);
+ } else if (bbut==MIDDLEMOUSE) {
+ win->lmbut= change_bit(win->lmbut, M_MOUSE, val);
+ } else {
+ win->lmbut= change_bit(win->lmbut, R_MOUSE, val);
+ }
+
+ update_tablet_data(win, ghostwin);
+ window_handle(win, bbut, val);
+
+ break;
+ }
+
+ case GHOST_kEventKeyDown:
+ case GHOST_kEventKeyUp: {
+ GHOST_TEventKeyData *kd= data;
+ int val= (type==GHOST_kEventKeyDown);
+ int bkey= convert_key(kd->key);
+
+ if (bkey) {
+ if (bkey==LEFTSHIFTKEY || bkey==RIGHTSHIFTKEY) {
+ win->lqual= change_bit(win->lqual, LR_SHIFTKEY, val);
+ } else if (bkey==LEFTCTRLKEY || bkey==RIGHTCTRLKEY) {
+ win->lqual= change_bit(win->lqual, LR_CTRLKEY, val);
+ } else if (bkey==LEFTALTKEY || bkey==RIGHTALTKEY) {
+ win->lqual= change_bit(win->lqual, LR_ALTKEY, val);
+ } else if (bkey==COMMANDKEY) {
+ win->lqual= change_bit(win->lqual, LR_COMMANDKEY, val);
+ }
+
+ window_handle_ext(win, bkey, val, kd->ascii);
+ }
+
+ break;
+ }
+
+ case GHOST_kEventWheel: {
+ GHOST_TEventWheelData* wheelData = (GHOST_TEventWheelData*) data;
+ if (wheelData->z > 0) {
+ window_handle(win, WHEELUPMOUSE, 1);
+ } else {
+ window_handle(win, WHEELDOWNMOUSE, 1);
+ }
+ break;
+ }
+
+ case GHOST_kEventWindowDeactivate:
+ case GHOST_kEventWindowActivate: {
+ win->active= (type==GHOST_kEventWindowActivate);
+ window_handle(win, INPUTCHANGE, win->active);
+
+ if (win->active) {
+ if ((win->lqual & LR_SHIFTKEY) && !query_qual('s')) {
+ win->lqual= change_bit(win->lqual, LR_SHIFTKEY, 0);
+ window_handle(win, LEFTSHIFTKEY, 0);
+ }
+ if ((win->lqual & LR_CTRLKEY) && !query_qual('c')) {
+ win->lqual= change_bit(win->lqual, LR_CTRLKEY, 0);
+ window_handle(win, LEFTCTRLKEY, 0);
+ }
+ if ((win->lqual & LR_ALTKEY) && !query_qual('a')) {
+ win->lqual= change_bit(win->lqual, LR_ALTKEY, 0);
+ window_handle(win, LEFTALTKEY, 0);
+ }
+ if ((win->lqual & LR_COMMANDKEY) && !query_qual('C')) {
+ win->lqual= change_bit(win->lqual, LR_COMMANDKEY, 0);
+ window_handle(win, LR_COMMANDKEY, 0);
+ }
+
+ /*
+ * XXX quick hack so OSX version works better
+ * when the window is clicked on (focused).
+ *
+ * it used to pass on the old win->lmouse value,
+ * which causes a wrong click in Blender.
+ * Actually, a 'focus' click should not be passed
+ * on to blender... (ton)
+ */
+ if(1) { /* enables me to add locals */
+ int cx, cy, wx, wy;
+ GHOST_GetCursorPosition(g_system, &wx, &wy);
+
+ GHOST_ScreenToClient(win->ghostwin, wx, wy, &cx, &cy);
+ win->lmouse[0]= cx;
+ win->lmouse[1]= (win->size[1]-1) - cy;
+ window_handle(win, MOUSEX, win->lmouse[0]);
+ window_handle(win, MOUSEY, win->lmouse[1]);
+ }
+ }
+
+ break;
+ }
+ case GHOST_kEventWindowClose: {
+ window_handle(win, WINCLOSE, 1);
+ break;
+ }
+ case GHOST_kEventWindowUpdate: {
+ window_handle(win, REDRAW, 1);
+ break;
+ }
+ case GHOST_kEventWindowSize: {
+ GHOST_RectangleHandle client_rect;
+ int l, t, r, b, scr_w, scr_h;
+
+ client_rect= GHOST_GetClientBounds(win->ghostwin);
+ GHOST_GetRectangle(client_rect, &l, &t, &r, &b);
+
+ GHOST_DisposeRectangle(client_rect);
+
+ winlay_get_screensize(&scr_w, &scr_h);
+ win->position[0]= l;
+ win->position[1]= scr_h - b - 1;
+ win->size[0]= r-l;
+ win->size[1]= b-t;
+
+ window_handle(win, RESHAPE, 1);
+ break;
+ }
+ case GHOST_kEventUnknown:
+ case GHOST_kEventQuit:
+ case GHOST_kNumEventTypes:
+ break;
+ }
+ }
+
+ return 1;
+}
+
+char *window_get_title(Window *win) {
+ char *title= GHOST_GetTitle(win->ghostwin);
+ char *mem_title= BLI_strdup(title);
+ free(title);
+
+ return mem_title;
+}
+
+void window_set_title(Window *win, char *title) {
+ GHOST_SetTitle(win->ghostwin, title);
+}
+
+short window_get_qual(Window *win)
+{
+ int qual= 0;
+
+ if( query_qual('s')) qual |= LR_SHIFTKEY;
+ if( query_qual('a')) qual |= LR_ALTKEY;
+ if( query_qual('c')) qual |= LR_CTRLKEY;
+ return qual;
+// return win->lqual;
+}
+
+short window_get_mbut(Window *win) {
+ return win->lmbut;
+}
+
+void window_get_mouse(Window *win, short *mval) {
+ mval[0]= win->lmouse[0];
+ mval[1]= win->lmouse[1];
+}
+
+float window_get_pressure(Window *win) {
+ return win->pressure;
+}
+
+void window_get_tilt(Window *win, float *xtilt, float *ytilt) {
+ *xtilt= win->xtilt;
+ *ytilt= win->ytilt;
+}
+
+short window_get_activedevice(Window *win) {
+ return win->activedevice;
+}
+
+void window_get_position(Window *win, int *posx_r, int *posy_r) {
+ *posx_r= win->position[0];
+ *posy_r= win->position[1];
+}
+
+void window_get_size(Window *win, int *width_r, int *height_r) {
+ *width_r= win->size[0];
+ *height_r= win->size[1];
+}
+
+void window_set_size(Window *win, int width, int height) {
+ GHOST_SetClientSize(win->ghostwin, width, height);
+}
+
+void window_lower(Window *win) {
+ GHOST_SetWindowOrder(win->ghostwin, GHOST_kWindowOrderBottom);
+}
+
+void window_raise(Window *win) {
+ GHOST_SetWindowOrder(win->ghostwin, GHOST_kWindowOrderTop);
+#ifdef _WIN32
+ markdirty_all(); /* to avoid redraw errors in fullscreen mode (aphex) */
+#endif
+}
+
+#if 0
+//#ifdef _WIN32 //FULLSCREEN
+void window_toggle_fullscreen(Window *win, int fullscreen) {
+ /* these two lines make sure front and backbuffer are equal. for swapbuffers */
+ markdirty_all();
+ screen_swapbuffers();
+
+ if(fullscreen)
+ GHOST_SetWindowState(win->ghostwin, GHOST_kWindowStateFullScreen);
+ else
+ GHOST_SetWindowState(win->ghostwin, GHOST_kWindowStateMaximized);
+}
+#endif
+
+void window_warp_pointer(Window *win, int x, int y) {
+ int oldx=x, oldy=y;
+
+ y= win->size[1] - y - 1;
+ GHOST_ClientToScreen(win->ghostwin, x, y, &x, &y);
+ GHOST_SetCursorPosition(g_system, x, y);
+
+ /* on OSX (for example) the setcursor doesnt create event */
+ win->lmouse[0]= oldx;
+ win->lmouse[1]= oldy;
+}
+
+void window_queue_redraw(Window *win) {
+ GHOST_InvalidateWindow(win->ghostwin); // ghost will send back a redraw to blender
+}
+
+/***/
+
+void winlay_process_events(int wait_for_event) {
+ GHOST_ProcessEvents(g_system, wait_for_event);
+ GHOST_DispatchEvents(g_system);
+}
+
+void winlay_get_screensize(int *width_r, int *height_r) {
+ unsigned int uiwidth;
+ unsigned int uiheight;
+
+ if (!g_system) {
+ GHOST_EventConsumerHandle consumer= GHOST_CreateEventConsumer(event_proc, NULL);
+
+ g_system= GHOST_CreateSystem();
+ GHOST_AddEventConsumer(g_system, consumer);
+ }
+
+ GHOST_GetMainDisplayDimensions(g_system, &uiwidth, &uiheight);
+ *width_r= uiwidth;
+ *height_r= uiheight;
+}
+
+Window *winlay_get_active_window(void) {
+ return active_gl_window;
+}
diff --git a/source/blender/src/glutil.c b/source/blender/src/glutil.c
new file mode 100644
index 00000000000..13922bb7eef
--- /dev/null
+++ b/source/blender/src/glutil.c
@@ -0,0 +1,695 @@
+
+
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_vec_types.h"
+#include "DNA_listBase.h"
+
+#include "BKE_utildefines.h"
+
+#include "BLI_arithb.h"
+#include "BLI_threads.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+#include "BIF_mywindow.h"
+
+#ifndef GL_CLAMP_TO_EDGE
+#define GL_CLAMP_TO_EDGE 0x812F
+#endif
+
+
+ /* Invert line handling */
+
+#define glToggle(mode, onoff) (((onoff)?glEnable:glDisable)(mode))
+
+void set_inverted_drawing(int enable)
+{
+ glLogicOp(enable?GL_INVERT:GL_COPY);
+
+ /* Use GL_BLEND_EQUATION_EXT on sgi (if we have it),
+ * apparently GL_COLOR_LOGIC_OP doesn't work on O2?
+ * Is this an sgi bug or our bug?
+ */
+#if defined(__sgi) && defined(GL_BLEND_EQUATION_EXT)
+ glBlendEquationEXT(enable?GL_LOGIC_OP:GL_FUNC_ADD_EXT);
+ glToggle(GL_BLEND, enable);
+#else
+ glToggle(GL_COLOR_LOGIC_OP, enable);
+#endif
+
+ glToggle(GL_DITHER, !enable);
+}
+
+void sdrawXORline(int x0, int y0, int x1, int y1)
+{
+ if(x0==x1 && y0==y1) return;
+
+ set_inverted_drawing(1);
+
+ glBegin(GL_LINES);
+ glVertex2i(x0, y0);
+ glVertex2i(x1, y1);
+ glEnd();
+
+ set_inverted_drawing(0);
+}
+
+void glutil_draw_front_xor_line(int x0, int y0, int x1, int y1)
+{
+ glReadBuffer(GL_FRONT);
+ glDrawBuffer(GL_FRONT);
+ sdrawXORline(x0, y0, x1, y1);
+ glFlush();
+ glReadBuffer(GL_BACK);
+ glDrawBuffer(GL_BACK);
+
+}
+
+void sdrawXORline4(int nr, int x0, int y0, int x1, int y1)
+{
+ static short old[4][2][2];
+ static char flags[4]= {0, 0, 0, 0};
+
+ /* with builtin memory, max 4 lines */
+
+ set_inverted_drawing(1);
+
+ glBegin(GL_LINES);
+ if(nr== -1) { /* flush */
+ for (nr=0; nr<4; nr++) {
+ if (flags[nr]) {
+ glVertex2sv(old[nr][0]);
+ glVertex2sv(old[nr][1]);
+ flags[nr]= 0;
+ }
+ }
+ } else {
+ if(nr>=0 && nr<4) {
+ if(flags[nr]) {
+ glVertex2sv(old[nr][0]);
+ glVertex2sv(old[nr][1]);
+ }
+
+ old[nr][0][0]= x0;
+ old[nr][0][1]= y0;
+ old[nr][1][0]= x1;
+ old[nr][1][1]= y1;
+
+ flags[nr]= 1;
+ }
+
+ glVertex2i(x0, y0);
+ glVertex2i(x1, y1);
+ }
+ glEnd();
+
+ set_inverted_drawing(0);
+}
+
+void fdrawXORellipse(float xofs, float yofs, float hw, float hh)
+{
+ if(hw==0) return;
+
+ set_inverted_drawing(1);
+
+ glPushMatrix();
+ glTranslatef(xofs, yofs, 0.0);
+ glScalef(1,hh/hw,1);
+ glutil_draw_lined_arc(0.0, M_PI*2.0, hw, 20);
+ glPopMatrix();
+
+ set_inverted_drawing(0);
+}
+void fdrawXORcirc(float xofs, float yofs, float rad)
+{
+ set_inverted_drawing(1);
+
+ glPushMatrix();
+ glTranslatef(xofs, yofs, 0.0);
+ glutil_draw_lined_arc(0.0, M_PI*2.0, rad, 20);
+ glPopMatrix();
+
+ set_inverted_drawing(0);
+}
+
+void glutil_draw_filled_arc(float start, float angle, float radius, int nsegments) {
+ int i;
+
+ glBegin(GL_TRIANGLE_FAN);
+ glVertex2f(0.0, 0.0);
+ for (i=0; i<nsegments; i++) {
+ float t= (float) i/(nsegments-1);
+ float cur= start + t*angle;
+
+ glVertex2f(cos(cur)*radius, sin(cur)*radius);
+ }
+ glEnd();
+}
+
+void glutil_draw_lined_arc(float start, float angle, float radius, int nsegments) {
+ int i;
+
+ glBegin(GL_LINE_STRIP);
+ for (i=0; i<nsegments; i++) {
+ float t= (float) i/(nsegments-1);
+ float cur= start + t*angle;
+
+ glVertex2f(cos(cur)*radius, sin(cur)*radius);
+ }
+ glEnd();
+}
+
+int glaGetOneInteger(int param)
+{
+ GLint i;
+ glGetIntegerv(param, &i);
+ return i;
+}
+
+float glaGetOneFloat(int param)
+{
+ GLfloat v;
+ glGetFloatv(param, &v);
+ return v;
+}
+
+void glaRasterPosSafe2f(float x, float y, float known_good_x, float known_good_y)
+{
+ GLubyte dummy= 0;
+
+ /* As long as known good coordinates are correct
+ * this is guarenteed to generate an ok raster
+ * position (ignoring potential (real) overflow
+ * issues).
+ */
+ glRasterPos2f(known_good_x, known_good_y);
+
+ /* Now shift the raster position to where we wanted
+ * it in the first place using the glBitmap trick.
+ */
+ glBitmap(0, 0, 0, 0, x - known_good_x, y - known_good_y, &dummy);
+}
+
+static int get_cached_work_texture(int *w_r, int *h_r)
+{
+ static GLint texid= -1;
+ static int tex_w= 256;
+ static int tex_h= 256;
+
+ if (texid==-1) {
+ GLint ltexid= glaGetOneInteger(GL_TEXTURE_2D);
+ unsigned char *tbuf;
+
+ glGenTextures(1, (GLuint *)&texid);
+
+ glBindTexture(GL_TEXTURE_2D, texid);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ tbuf= MEM_callocN(tex_w*tex_h*4, "tbuf");
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, tex_w, tex_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, tbuf);
+ MEM_freeN(tbuf);
+
+ glBindTexture(GL_TEXTURE_2D, ltexid);
+ }
+
+ *w_r= tex_w;
+ *h_r= tex_h;
+ return texid;
+}
+
+void glaDrawPixelsTex(float x, float y, int img_w, int img_h, int format, void *rect)
+{
+ unsigned char *uc_rect= (unsigned char*) rect;
+ float *f_rect= (float *)rect;
+ float xzoom= glaGetOneFloat(GL_ZOOM_X), yzoom= glaGetOneFloat(GL_ZOOM_Y);
+ int ltexid= glaGetOneInteger(GL_TEXTURE_2D);
+ int lrowlength= glaGetOneInteger(GL_UNPACK_ROW_LENGTH);
+ int subpart_x, subpart_y, tex_w, tex_h;
+ int texid= get_cached_work_texture(&tex_w, &tex_h);
+ int nsubparts_x= (img_w+(tex_w-1))/tex_w;
+ int nsubparts_y= (img_h+(tex_h-1))/tex_h;
+
+ /* Specify the color outside this function, and tex will modulate it.
+ * This is useful for changing alpha without using glPixelTransferf()
+ */
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, img_w);
+ glBindTexture(GL_TEXTURE_2D, texid);
+
+ /* don't want nasty border artifacts */
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ for (subpart_y=0; subpart_y<nsubparts_y; subpart_y++) {
+ for (subpart_x=0; subpart_x<nsubparts_x; subpart_x++) {
+ int subpart_w= (subpart_x==nsubparts_x-1)?(img_w-subpart_x*tex_w):tex_w;
+ int subpart_h= (subpart_y==nsubparts_y-1)?(img_h-subpart_y*tex_h):tex_h;
+ float rast_x= x+subpart_x*tex_w*xzoom;
+ float rast_y= y+subpart_y*tex_h*yzoom;
+
+ if(format==GL_FLOAT)
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, subpart_w, subpart_h, GL_RGBA, GL_FLOAT, &f_rect[(subpart_y*tex_w)*img_w*4 + (subpart_x*tex_w)*4]);
+ else
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, subpart_w, subpart_h, GL_RGBA, GL_UNSIGNED_BYTE, &uc_rect[(subpart_y*tex_w)*img_w*4 + (subpart_x*tex_w)*4]);
+
+ glEnable(GL_TEXTURE_2D);
+ glBegin(GL_QUADS);
+ glTexCoord2f(0, 0);
+ glVertex2f(rast_x, rast_y);
+
+ glTexCoord2f((float) (subpart_w-1)/tex_w, 0);
+ glVertex2f(rast_x+subpart_w*xzoom, rast_y);
+
+ glTexCoord2f((float) (subpart_w-1)/tex_w, (float) subpart_h/tex_h);
+ glVertex2f(rast_x+subpart_w*xzoom, rast_y+subpart_h*yzoom);
+
+ glTexCoord2f(0, (float) subpart_h/tex_h);
+ glVertex2f(rast_x, rast_y+subpart_h*yzoom);
+ glEnd();
+ glDisable(GL_TEXTURE_2D);
+ }
+ }
+
+ glBindTexture(GL_TEXTURE_2D, ltexid);
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, lrowlength);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+}
+
+#define FTOCHAR(val) val<=0.0f?0: (val>=1.0f?255: (char)(255.0f*val))
+void glaDrawPixelsSafe_to32(float fx, float fy, int img_w, int img_h, int row_w, float *rectf)
+{
+ float *rf;
+ int x, y;
+ char *rect32, *rc;
+
+ /* copy imgw-imgh to a temporal 32 bits rect */
+ if(img_w<1 || img_h<1) return;
+
+ rc= rect32= MEM_mallocN(img_w*img_h*sizeof(int), "temp 32 bits");
+
+ for(y=0; y<img_h; y++) {
+ rf= rectf;
+ for(x=0; x<img_w; x++, rf+=4, rc+=4) {
+ rc[0]= FTOCHAR(rf[0]);
+ rc[1]= FTOCHAR(rf[1]);
+ rc[2]= FTOCHAR(rf[2]);
+ rc[3]= FTOCHAR(rf[3]);
+ }
+ rectf+= 4*row_w;
+ }
+
+ glaDrawPixelsSafe(fx, fy, img_w, img_h, img_w, GL_RGBA, GL_UNSIGNED_BYTE, rect32);
+
+ MEM_freeN(rect32);
+}
+
+void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int format, int type, void *rect)
+{
+ float xzoom= glaGetOneFloat(GL_ZOOM_X);
+ float yzoom= glaGetOneFloat(GL_ZOOM_Y);
+
+ /* The pixel space coordinate of the intersection of
+ * the [zoomed] image with the origin.
+ */
+ float ix= -x/xzoom;
+ float iy= -y/yzoom;
+
+ /* The maximum pixel amounts the image can be cropped
+ * at the lower left without exceeding the origin.
+ */
+ int off_x= floor(MAX2(ix, 0));
+ int off_y= floor(MAX2(iy, 0));
+
+ /* The zoomed space coordinate of the raster position
+ * (starting at the lower left most unclipped pixel).
+ */
+ float rast_x= x + off_x*xzoom;
+ float rast_y= y + off_y*yzoom;
+
+ GLfloat scissor[4];
+ int draw_w, draw_h;
+
+ /* Determine the smallest number of pixels we need to draw
+ * before the image would go off the upper right corner.
+ *
+ * It may seem this is just an optimization but some graphics
+ * cards (ATI) freak out if there is a large zoom factor and
+ * a large number of pixels off the screen (probably at some
+ * level the number of image pixels to draw is getting multiplied
+ * by the zoom and then clamped). Making sure we draw the
+ * fewest pixels possible keeps everyone mostly happy (still
+ * fails if we zoom in on one really huge pixel so that it
+ * covers the entire screen).
+ */
+ glGetFloatv(GL_SCISSOR_BOX, scissor);
+ draw_w = MIN2(img_w-off_x, ceil((scissor[2]-rast_x)/xzoom));
+ draw_h = MIN2(img_h-off_y, ceil((scissor[3]-rast_y)/yzoom));
+
+ if (draw_w>0 && draw_h>0) {
+ int old_row_length = glaGetOneInteger(GL_UNPACK_ROW_LENGTH);
+
+ /* Don't use safe RasterPos (slower) if we can avoid it. */
+ if (rast_x>=0 && rast_y>=0) {
+ glRasterPos2f(rast_x, rast_y);
+ } else {
+ glaRasterPosSafe2f(rast_x, rast_y, 0, 0);
+ }
+
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, row_w);
+ if(format==GL_LUMINANCE || format==GL_RED) {
+ if(type==GL_FLOAT) {
+ float *f_rect= (float *)rect;
+ glDrawPixels(draw_w, draw_h, format, type, f_rect + (off_y*row_w + off_x));
+ }
+ else if(type==GL_INT || type==GL_UNSIGNED_INT) {
+ int *i_rect= (int *)rect;
+ glDrawPixels(draw_w, draw_h, format, type, i_rect + (off_y*row_w + off_x));
+ }
+ }
+ else { /* RGBA */
+ if(type==GL_FLOAT) {
+ float *f_rect= (float *)rect;
+ glDrawPixels(draw_w, draw_h, format, type, f_rect + (off_y*row_w + off_x)*4);
+ }
+ else if(type==GL_UNSIGNED_BYTE) {
+ unsigned char *uc_rect= (unsigned char *) rect;
+ glDrawPixels(draw_w, draw_h, format, type, uc_rect + (off_y*row_w + off_x)*4);
+ }
+ }
+
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, old_row_length);
+ }
+}
+
+/* 2D Drawing Assistance */
+
+void glaDefine2DArea(rcti *screen_rect)
+{
+ int sc_w= screen_rect->xmax - screen_rect->xmin;
+ int sc_h= screen_rect->ymax - screen_rect->ymin;
+
+ glViewport(screen_rect->xmin, screen_rect->ymin, sc_w, sc_h);
+ glScissor(screen_rect->xmin, screen_rect->ymin, sc_w, sc_h);
+
+ /* The 0.375 magic number is to shift the matrix so that
+ * both raster and vertex integer coordinates fall at pixel
+ * centers properly. For a longer discussion see the OpenGL
+ * Programming Guide, Appendix H, Correctness Tips.
+ */
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0.0, sc_w, 0.0, sc_h, -1, 1);
+ glTranslatef(0.375, 0.375, 0.0);
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+}
+
+struct gla2DDrawInfo {
+ int orig_vp[4], orig_sc[4];
+ float orig_projmat[16], orig_viewmat[16];
+
+ rcti screen_rect;
+ rctf world_rect;
+
+ float wo_to_sc[2];
+};
+
+void gla2DGetMap(gla2DDrawInfo *di, rctf *rect)
+{
+ *rect= di->world_rect;
+}
+
+void gla2DSetMap(gla2DDrawInfo *di, rctf *rect)
+{
+ int sc_w, sc_h;
+ float wo_w, wo_h;
+
+ di->world_rect= *rect;
+
+ sc_w= (di->screen_rect.xmax-di->screen_rect.xmin);
+ sc_h= (di->screen_rect.ymax-di->screen_rect.ymin);
+ wo_w= (di->world_rect.xmax-di->world_rect.xmin);
+ wo_h= (di->world_rect.ymax-di->world_rect.ymin);
+
+ di->wo_to_sc[0]= sc_w/wo_w;
+ di->wo_to_sc[1]= sc_h/wo_h;
+}
+
+
+gla2DDrawInfo *glaBegin2DDraw(rcti *screen_rect, rctf *world_rect)
+{
+ gla2DDrawInfo *di= MEM_mallocN(sizeof(*di), "gla2DDrawInfo");
+ int sc_w, sc_h;
+ float wo_w, wo_h;
+
+ glGetIntegerv(GL_VIEWPORT, (GLint *)di->orig_vp);
+ glGetIntegerv(GL_SCISSOR_BOX, (GLint *)di->orig_sc);
+ glGetFloatv(GL_PROJECTION_MATRIX, (GLfloat *)di->orig_projmat);
+ glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *)di->orig_viewmat);
+
+ di->screen_rect= *screen_rect;
+ if (world_rect) {
+ di->world_rect= *world_rect;
+ } else {
+ di->world_rect.xmin= di->screen_rect.xmin;
+ di->world_rect.ymin= di->screen_rect.ymin;
+ di->world_rect.xmax= di->screen_rect.xmax;
+ di->world_rect.ymax= di->screen_rect.ymax;
+ }
+
+ sc_w= (di->screen_rect.xmax-di->screen_rect.xmin);
+ sc_h= (di->screen_rect.ymax-di->screen_rect.ymin);
+ wo_w= (di->world_rect.xmax-di->world_rect.xmin);
+ wo_h= (di->world_rect.ymax-di->world_rect.ymin);
+
+ di->wo_to_sc[0]= sc_w/wo_w;
+ di->wo_to_sc[1]= sc_h/wo_h;
+
+ glaDefine2DArea(&di->screen_rect);
+
+ return di;
+}
+
+void gla2DDrawTranslatePt(gla2DDrawInfo *di, float wo_x, float wo_y, int *sc_x_r, int *sc_y_r)
+{
+ *sc_x_r= (wo_x - di->world_rect.xmin)*di->wo_to_sc[0];
+ *sc_y_r= (wo_y - di->world_rect.ymin)*di->wo_to_sc[1];
+}
+void gla2DDrawTranslatePtv(gla2DDrawInfo *di, float world[2], int screen_r[2])
+{
+ screen_r[0]= (world[0] - di->world_rect.xmin)*di->wo_to_sc[0];
+ screen_r[1]= (world[1] - di->world_rect.ymin)*di->wo_to_sc[1];
+}
+
+void glaEnd2DDraw(gla2DDrawInfo *di)
+{
+ glViewport(di->orig_vp[0], di->orig_vp[1], di->orig_vp[2], di->orig_vp[3]);
+ glScissor(di->orig_vp[0], di->orig_vp[1], di->orig_vp[2], di->orig_vp[3]);
+ glMatrixMode(GL_PROJECTION);
+ glLoadMatrixf(di->orig_projmat);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadMatrixf(di->orig_viewmat);
+
+ MEM_freeN(di);
+}
+
+/* **************** glPoint hack ************************ */
+
+static int curmode=0;
+static int pointhack=0;
+static GLubyte Squaredot[16] = { 0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff};
+
+void bglBegin(int mode)
+{
+ curmode= mode;
+
+ if(mode==GL_POINTS) {
+ float value[4];
+ glGetFloatv(GL_POINT_SIZE_RANGE, value);
+ if(value[1]<2.0) {
+ glGetFloatv(GL_POINT_SIZE, value);
+ pointhack= floor(value[0]+0.5);
+ if(pointhack>4) pointhack= 4;
+ }
+ else glBegin(mode);
+ }
+}
+
+
+void bglVertex3fv(float *vec)
+{
+ switch(curmode) {
+ case GL_POINTS:
+ if(pointhack) {
+ glRasterPos3fv(vec);
+ glBitmap(pointhack, pointhack, (float)pointhack/2.0, (float)pointhack/2.0, 0.0, 0.0, Squaredot);
+ }
+ else glVertex3fv(vec);
+ break;
+ }
+}
+
+void bglVertex3f(float x, float y, float z)
+{
+ switch(curmode) {
+ case GL_POINTS:
+ if(pointhack) {
+ glRasterPos3f(x, y, z);
+ glBitmap(pointhack, pointhack, (float)pointhack/2.0, (float)pointhack/2.0, 0.0, 0.0, Squaredot);
+ }
+ else glVertex3f(x, y, z);
+ break;
+ }
+}
+
+void bglVertex2fv(float *vec)
+{
+ switch(curmode) {
+ case GL_POINTS:
+ if(pointhack) {
+ glRasterPos2fv(vec);
+ glBitmap(pointhack, pointhack, (float)pointhack/2, pointhack/2, 0.0, 0.0, Squaredot);
+ }
+ else glVertex2fv(vec);
+ break;
+ }
+}
+
+
+void bglEnd(void)
+{
+ if(pointhack) pointhack= 0;
+ else glEnd();
+
+}
+
+/* Uses current OpenGL state to get view matrices for gluProject/gluUnProject */
+void bgl_get_mats(bglMats *mats)
+{
+ const double badvalue= 1.0e-6;
+
+ glGetDoublev(GL_MODELVIEW_MATRIX, mats->modelview);
+ glGetDoublev(GL_PROJECTION_MATRIX, mats->projection);
+ glGetIntegerv(GL_VIEWPORT, (GLint *)mats->viewport);
+
+ /* Very strange code here - it seems that certain bad values in the
+ modelview matrix can cause gluUnProject to give bad results. */
+ if(mats->modelview[0] < badvalue &&
+ mats->modelview[0] > -badvalue)
+ mats->modelview[0]= 0;
+ if(mats->modelview[5] < badvalue &&
+ mats->modelview[5] > -badvalue)
+ mats->modelview[5]= 0;
+
+ /* Set up viewport so that gluUnProject will give correct values */
+ mats->viewport[0] = 0;
+ mats->viewport[1] = 0;
+}
+
+/* *************** glPolygonOffset hack ************* */
+
+// both temporal, so here for now (ton)
+#include "BKE_global.h"
+#include "DNA_view3d_types.h"
+
+/* dist is only for ortho now... */
+void bglPolygonOffset(float dist)
+{
+ static float winmat[16], offset=0.0;
+
+ if(dist!=0.0) {
+ float offs;
+
+ // glEnable(GL_POLYGON_OFFSET_FILL);
+ // glPolygonOffset(-1.0, -1.0);
+
+ /* hack below is to mimic polygon offset */
+ glMatrixMode(GL_PROJECTION);
+ glGetFloatv(GL_PROJECTION_MATRIX, (float *)winmat);
+
+ /* dist is from camera to center point */
+
+ if(winmat[15]>0.5) offs= 0.00001*dist*G.vd->dist; // ortho tweaking
+ else offs= 0.0005*dist; // should be clipping value or so...
+
+ winmat[14]-= offs;
+ offset+= offs;
+
+ glLoadMatrixf(winmat);
+ glMatrixMode(GL_MODELVIEW);
+ }
+ else {
+
+ glMatrixMode(GL_PROJECTION);
+ winmat[14]+= offset;
+ offset= 0.0;
+ glLoadMatrixf(winmat);
+ glMatrixMode(GL_MODELVIEW);
+ }
+}
+
+int is_a_really_crappy_intel_card(void)
+{
+ static int well_is_it= -1;
+
+ /* Do you understand the implication? Do you? */
+ if (well_is_it==-1)
+ well_is_it= (strcmp((char*) glGetString(GL_VENDOR), "Intel Inc.") == 0);
+
+ return well_is_it;
+}
+
+void bglFlush(void)
+{
+ glFlush();
+#ifdef __APPLE__
+ if(is_a_really_crappy_intel_card())
+ myswapbuffers(); //hack to get mac intel graphics to show frontbuffer
+#endif
+}
+
+
diff --git a/source/blender/src/hddaudio.c b/source/blender/src/hddaudio.c
new file mode 100644
index 00000000000..b655671a051
--- /dev/null
+++ b/source/blender/src/hddaudio.c
@@ -0,0 +1,577 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributor(s): Peter Schlaile <peter [at] schlaile [dot] de> 2005
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <fcntl.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WITH_FFMPEG
+#include <ffmpeg/avformat.h>
+#include <ffmpeg/avcodec.h>
+#include <ffmpeg/rational.h>
+#if LIBAVFORMAT_VERSION_INT < (49 << 16)
+#define FFMPEG_OLD_FRAME_RATE 1
+#else
+#define FFMPEG_CODEC_IS_POINTER 1
+#endif
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "BIF_editsound.h"
+
+#include "blendef.h"
+
+#ifdef WITH_FFMPEG
+extern void do_init_ffmpeg();
+#endif
+
+struct hdaudio {
+ int sample_rate;
+ int channels;
+ int audioStream;
+
+#ifdef WITH_FFMPEG
+ char * filename;
+ AVCodec *pCodec;
+ AVFormatContext *pFormatCtx;
+ AVCodecContext *pCodecCtx;
+ int frame_position;
+ int frame_duration;
+ int frame_alloc_duration;
+ int decode_pos;
+ int frame_size;
+ short * decode_cache;
+ short * decode_cache_zero;
+ short * resample_cache;
+ int decode_cache_size;
+ int target_channels;
+ int target_rate;
+ int resample_samples_written;
+ int resample_samples_in;
+ ReSampleContext *resampler;
+#else
+
+
+#endif
+};
+
+#ifdef WITH_FFMPEG
+#ifdef FFMPEG_CODEC_IS_POINTER
+static AVCodecContext* get_codec_from_stream(AVStream* stream)
+{
+ return stream->codec;
+}
+#else
+static AVCodecContext* get_codec_from_stream(AVStream* stream)
+{
+ return &stream->codec;
+}
+#endif
+#endif
+
+struct hdaudio * sound_open_hdaudio(char * filename)
+{
+#ifdef WITH_FFMPEG
+ struct hdaudio * rval;
+ int i, audioStream;
+
+ AVCodec *pCodec;
+ AVFormatContext *pFormatCtx;
+ AVCodecContext *pCodecCtx;
+
+ do_init_ffmpeg();
+
+ if(av_open_input_file(&pFormatCtx, filename, NULL, 0, NULL)!=0) {
+ return 0;
+ }
+
+ if(av_find_stream_info(pFormatCtx)<0) {
+ av_close_input_file(pFormatCtx);
+ return 0;
+ }
+
+ dump_format(pFormatCtx, 0, filename, 0);
+
+
+ /* Find the first audio stream */
+ audioStream=-1;
+ for(i=0; i<pFormatCtx->nb_streams; i++)
+ if(get_codec_from_stream(pFormatCtx->streams[i])
+ ->codec_type == CODEC_TYPE_AUDIO)
+ {
+ audioStream=i;
+ break;
+ }
+
+ if(audioStream == -1) {
+ av_close_input_file(pFormatCtx);
+ return 0;
+ }
+
+ pCodecCtx = get_codec_from_stream(pFormatCtx->streams[audioStream]);
+
+ /* Find the decoder for the audio stream */
+ pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
+ if(pCodec == NULL) {
+ av_close_input_file(pFormatCtx);
+ return 0;
+ }
+
+ if(avcodec_open(pCodecCtx, pCodec)<0) {
+ av_close_input_file(pFormatCtx);
+ return 0;
+ }
+
+ rval = (struct hdaudio *)MEM_mallocN(sizeof(struct hdaudio),
+ "hdaudio struct");
+
+ rval->filename = strdup(filename);
+ rval->sample_rate = pCodecCtx->sample_rate;
+ rval->channels = pCodecCtx->channels;
+
+ rval->pFormatCtx = pFormatCtx;
+ rval->pCodecCtx = pCodecCtx;
+ rval->pCodec = pCodec;
+ rval->audioStream = audioStream;
+ rval->frame_position = -10;
+
+ rval->frame_duration = AV_TIME_BASE / 10;
+ rval->frame_alloc_duration = AV_TIME_BASE;
+ rval->decode_cache_size =
+ (long long) rval->sample_rate * rval->channels
+ * rval->frame_alloc_duration / AV_TIME_BASE
+ * 2;
+
+ rval->decode_cache = (short*) MEM_mallocN(
+ rval->decode_cache_size * sizeof(short)
+ + AVCODEC_MAX_AUDIO_FRAME_SIZE,
+ "hdaudio decode cache");
+ rval->decode_cache_zero = rval->decode_cache;
+ rval->decode_pos = 0;
+ rval->target_channels = -1;
+ rval->target_rate = -1;
+ rval->resampler = 0;
+ rval->resample_cache = 0;
+ rval->resample_samples_written = 0;
+ rval->resample_samples_in = 0;
+ return rval;
+#else
+ return 0;
+#endif
+}
+
+struct hdaudio * sound_copy_hdaudio(struct hdaudio * c)
+{
+#ifdef WITH_FFMPEG
+ return sound_open_hdaudio(c->filename);
+#else
+ return 0;
+#endif
+}
+
+long sound_hdaudio_get_duration(struct hdaudio * hdaudio, double frame_rate)
+{
+#ifdef WITH_FFMPEG
+ return hdaudio->pFormatCtx->duration * frame_rate / AV_TIME_BASE;
+#else
+ return 0;
+#endif
+}
+
+#ifdef WITH_FFMPEG
+static void sound_hdaudio_extract_small_block(
+ struct hdaudio * hdaudio,
+ short * target_buffer,
+ int sample_position /* units of target_rate */,
+ int target_rate,
+ int target_channels,
+ int nb_samples /* in target */)
+{
+ AVPacket packet;
+ int frame_position;
+ int frame_size = (long long) target_rate
+ * hdaudio->frame_duration / AV_TIME_BASE;
+ int in_frame_size = (long long) hdaudio->sample_rate
+ * hdaudio->frame_duration / AV_TIME_BASE;
+ int rate_conversion =
+ (target_rate != hdaudio->sample_rate)
+ || (target_channels != hdaudio->channels);
+ int sample_ofs = target_channels * (sample_position % frame_size);
+
+ frame_position = sample_position / frame_size;
+
+ if (hdaudio == 0) return;
+
+ if (rate_conversion) {
+ if (hdaudio->resampler &&
+ (hdaudio->target_rate != target_rate
+ || hdaudio->target_channels != target_channels)) {
+ audio_resample_close(hdaudio->resampler);
+ hdaudio->resampler = 0;
+ }
+ if (!hdaudio->resampler) {
+ hdaudio->resampler = audio_resample_init(
+ target_channels, hdaudio->channels,
+ target_rate, hdaudio->sample_rate);
+ hdaudio->target_rate = target_rate;
+ hdaudio->target_channels = target_channels;
+ if (hdaudio->resample_cache) {
+ MEM_freeN(hdaudio->resample_cache);
+ }
+
+
+ hdaudio->resample_cache = (short*) MEM_mallocN(
+ (long long)
+ hdaudio->target_channels
+ * frame_size * 2
+ * sizeof(short),
+ "hdaudio resample cache");
+ if (frame_position == hdaudio->frame_position) {
+ hdaudio->resample_samples_in =
+ in_frame_size * 7 / 4;
+ hdaudio->resample_samples_written
+ = audio_resample(
+ hdaudio->resampler,
+ hdaudio->resample_cache,
+ hdaudio->decode_cache_zero,
+ in_frame_size * 7 / 4);
+ }
+ }
+ }
+
+ if (frame_position == hdaudio->frame_position + 1
+ && in_frame_size * hdaudio->channels <= hdaudio->decode_pos) {
+ int bl_size = in_frame_size * hdaudio->channels;
+ int decode_pos = hdaudio->decode_pos;
+
+ hdaudio->frame_position = frame_position;
+
+ memmove(hdaudio->decode_cache,
+ hdaudio->decode_cache + bl_size,
+ (decode_pos - bl_size) * sizeof(short));
+
+ decode_pos -= bl_size;
+
+ memset(hdaudio->decode_cache + decode_pos, 0,
+ (hdaudio->decode_cache_size - decode_pos)
+ * sizeof(short));
+
+
+ while(av_read_frame(hdaudio->pFormatCtx, &packet) >= 0) {
+ int data_size;
+ int len;
+ uint8_t *audio_pkt_data;
+ int audio_pkt_size;
+
+ if(packet.stream_index != hdaudio->audioStream) {
+ av_free_packet(&packet);
+ continue;
+ }
+
+ audio_pkt_data = packet.data;
+ audio_pkt_size = packet.size;
+
+ while (audio_pkt_size > 0) {
+ len = avcodec_decode_audio(
+ hdaudio->pCodecCtx,
+ hdaudio->decode_cache
+ + decode_pos,
+ &data_size,
+ audio_pkt_data,
+ audio_pkt_size);
+ if (len <= 0) {
+ audio_pkt_size = 0;
+ break;
+ }
+
+ audio_pkt_size -= len;
+ audio_pkt_data += len;
+
+ if (data_size <= 0) {
+ continue;
+ }
+
+ decode_pos += data_size / sizeof(short);
+ if (decode_pos + data_size
+ / sizeof(short)
+ > hdaudio->decode_cache_size) {
+ break;
+ }
+ }
+ av_free_packet(&packet);
+
+ if (decode_pos + data_size / sizeof(short)
+ > hdaudio->decode_cache_size) {
+ break;
+ }
+ }
+
+ if (rate_conversion) {
+ int written = hdaudio->resample_samples_written
+ * target_channels;
+ int ofs = target_channels * frame_size;
+ int recycle = written - ofs;
+ int next_in = in_frame_size
+ + (3.0/4.0
+ - (double) recycle / (double)
+ (frame_size * target_channels)
+ ) * in_frame_size;
+
+ memmove(hdaudio->resample_cache,
+ hdaudio->resample_cache + ofs,
+ recycle * sizeof(short));
+
+ hdaudio->resample_samples_written
+ = audio_resample(
+ hdaudio->resampler,
+ hdaudio->resample_cache + recycle,
+ hdaudio->decode_cache_zero
+ + hdaudio->resample_samples_in
+ * hdaudio->channels
+ - bl_size,
+ next_in)
+ + recycle / target_channels;
+
+ hdaudio->resample_samples_in = next_in;
+ }
+
+ hdaudio->decode_pos = decode_pos;
+ }
+
+ if (frame_position != hdaudio->frame_position) {
+ long decode_pos = 0;
+ long long st_time = hdaudio->pFormatCtx
+ ->streams[hdaudio->audioStream]->start_time;
+ double time_base =
+ av_q2d(hdaudio->pFormatCtx
+ ->streams[hdaudio->audioStream]->time_base);
+ long long pos = (long long) frame_position * AV_TIME_BASE
+ * hdaudio->frame_duration / AV_TIME_BASE;
+
+ long long seek_pos;
+
+ hdaudio->frame_position = frame_position;
+
+ if (st_time == AV_NOPTS_VALUE) {
+ st_time = 0;
+ }
+
+ pos += st_time * AV_TIME_BASE * time_base;
+
+ /* seek a little bit before the target position,
+ (ffmpeg seek algorithm doesn't seem to work always as
+ specified...)
+ */
+
+ seek_pos = pos - (AV_TIME_BASE
+ * hdaudio->frame_duration
+ / AV_TIME_BASE / 10);
+ if (seek_pos < 0) {
+ seek_pos = pos;
+ }
+
+ av_seek_frame(hdaudio->pFormatCtx, -1,
+ seek_pos,
+ AVSEEK_FLAG_ANY | AVSEEK_FLAG_BACKWARD);
+ avcodec_flush_buffers(hdaudio->pCodecCtx);
+
+ memset(hdaudio->decode_cache, 0,
+ hdaudio->decode_cache_size * sizeof(short));
+
+ hdaudio->decode_cache_zero = hdaudio->decode_cache;
+
+ while(av_read_frame(hdaudio->pFormatCtx, &packet) >= 0) {
+ int data_size;
+ int len;
+ uint8_t *audio_pkt_data;
+ int audio_pkt_size;
+
+ if(packet.stream_index != hdaudio->audioStream) {
+ av_free_packet(&packet);
+ continue;
+ }
+
+ audio_pkt_data = packet.data;
+ audio_pkt_size = packet.size;
+
+ if (!hdaudio->decode_cache_zero
+ && audio_pkt_size > 0) {
+ long long diff;
+
+ if (packet.pts == AV_NOPTS_VALUE) {
+ fprintf(stderr,
+ "hdaudio: audio "
+ "pts=NULL audio "
+ "distortion!\n");
+ diff = 0;
+ } else {
+ long long pts = packet.pts;
+ long long spts = (long long) (
+ pos / time_base / AV_TIME_BASE
+ + 0.5);
+ diff = spts - pts;
+ if (diff < 0) {
+ fprintf(stderr,
+ "hdaudio: "
+ "negative seek: "
+ "%lld < %lld "
+ "(pos=%lld) "
+ "audio distortion!!\n",
+ spts, pts, pos);
+ diff = 0;
+ }
+ }
+
+
+ diff *= hdaudio->sample_rate * time_base;
+ diff *= hdaudio->channels;
+
+ if (diff > hdaudio->decode_cache_size / 2) {
+ fprintf(stderr,
+ "hdaudio: audio "
+ "diff too large!!\n");
+ diff = 0;
+ }
+
+ hdaudio->decode_cache_zero
+ = hdaudio->decode_cache + diff;
+ }
+
+ while (audio_pkt_size > 0) {
+ len = avcodec_decode_audio(
+ hdaudio->pCodecCtx,
+ hdaudio->decode_cache
+ + decode_pos,
+ &data_size,
+ audio_pkt_data,
+ audio_pkt_size);
+ if (len <= 0) {
+ audio_pkt_size = 0;
+ break;
+ }
+
+ audio_pkt_size -= len;
+ audio_pkt_data += len;
+
+ if (data_size <= 0) {
+ continue;
+ }
+
+ decode_pos += data_size / sizeof(short);
+ if (decode_pos + data_size
+ / sizeof(short)
+ > hdaudio->decode_cache_size) {
+ break;
+ }
+ }
+
+ av_free_packet(&packet);
+
+ if (decode_pos + data_size / sizeof(short)
+ > hdaudio->decode_cache_size) {
+ break;
+ }
+ }
+ if (rate_conversion) {
+ hdaudio->resample_samples_written
+ = audio_resample(hdaudio->resampler,
+ hdaudio->resample_cache,
+ hdaudio->decode_cache_zero,
+ in_frame_size * 7 / 4);
+ hdaudio->resample_samples_in =
+ in_frame_size * 7 / 4;
+ }
+ hdaudio->decode_pos = decode_pos;
+ }
+
+ memcpy(target_buffer, (rate_conversion
+ ? hdaudio->resample_cache
+ : hdaudio->decode_cache_zero) + sample_ofs,
+ nb_samples * target_channels * sizeof(short));
+}
+#endif
+
+
+void sound_hdaudio_extract(struct hdaudio * hdaudio,
+ short * target_buffer,
+ int sample_position /* units of target_rate */,
+ int target_rate,
+ int target_channels,
+ int nb_samples /* in target */)
+{
+#ifdef WITH_FFMPEG
+ long long max_samples = (long long) target_rate
+ * hdaudio->frame_duration / AV_TIME_BASE / 4;
+
+ while (nb_samples > max_samples) {
+ sound_hdaudio_extract_small_block(hdaudio, target_buffer,
+ sample_position,
+ target_rate,
+ target_channels,
+ max_samples);
+ target_buffer += max_samples * target_channels;
+ sample_position += max_samples;
+ nb_samples -= max_samples;
+ }
+ if (nb_samples > 0) {
+ sound_hdaudio_extract_small_block(hdaudio, target_buffer,
+ sample_position,
+ target_rate,
+ target_channels,
+ nb_samples);
+ }
+#else
+
+#endif
+}
+
+void sound_close_hdaudio(struct hdaudio * hdaudio)
+{
+#ifdef WITH_FFMPEG
+
+ if (hdaudio) {
+ avcodec_close(hdaudio->pCodecCtx);
+ av_close_input_file(hdaudio->pFormatCtx);
+ MEM_freeN (hdaudio->decode_cache);
+ if (hdaudio->resample_cache) {
+ MEM_freeN(hdaudio->resample_cache);
+ }
+ free(hdaudio->filename);
+ MEM_freeN (hdaudio);
+ }
+#else
+
+#endif
+}
+
diff --git a/source/blender/src/header_action.c b/source/blender/src/header_action.c
new file mode 100644
index 00000000000..4a803926a94
--- /dev/null
+++ b/source/blender/src/header_action.c
@@ -0,0 +1,1240 @@
+/**
+ * header_action.c oct-2003
+ *
+ * Functions to draw the "Action Editor" window header
+ * and handle user events sent to it.
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): 2007, Joshua Leung (Action Editor recode)
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "DNA_action_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_ID.h"
+#include "DNA_ipo_types.h"
+#include "DNA_key_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "BIF_editaction.h"
+#include "BIF_interface.h"
+#include "BIF_poseobject.h"
+#include "BIF_resources.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_toolbox.h"
+
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_constraint.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_utildefines.h"
+
+#include "BDR_drawaction.h"
+#include "BSE_drawipo.h"
+#include "BSE_headerbuttons.h"
+#include "BSE_time.h"
+
+#include "nla.h"
+
+#include "blendef.h"
+#include "mydevice.h"
+
+/* enums declaring constants that are used as menu event codes */
+
+enum {
+ ACTMENU_VIEW_CENTERVIEW= 0,
+ ACTMENU_VIEW_AUTOUPDATE,
+ ACTMENU_VIEW_PLAY3D,
+ ACTMENU_VIEW_PLAYALL,
+ ACTMENU_VIEW_ALL,
+ ACTMENU_VIEW_MAXIMIZE,
+ ACTMENU_VIEW_LOCK,
+ ACTMENU_VIEW_SLIDERS,
+ ACTMENU_VIEW_NEXTMARKER,
+ ACTMENU_VIEW_PREVMARKER,
+ ACTMENU_VIEW_TIME,
+};
+
+enum {
+ ACTMENU_SEL_BORDER = 0,
+ ACTMENU_SEL_BORDERM,
+ ACTMENU_SEL_ALL_KEYS,
+ ACTMENU_SEL_ALL_CHAN,
+ ACTMENU_SEL_ALL_MARKERS,
+ ACTMENU_SEL_INVERSE_KEYS,
+ ACTMENU_SEL_INVERSE_MARKERS
+};
+
+enum {
+ ACTMENU_SEL_COLUMN_KEYS = 1,
+ ACTMENU_SEL_COLUMN_MARKERSCOLUMN,
+ ACTMENU_SEL_COLUMN_MARKERSBETWEEN
+};
+
+enum {
+ ACTMENU_KEY_DUPLICATE = 0,
+ ACTMENU_KEY_DELETE,
+ ACTMENU_KEY_CLEAN
+};
+
+enum {
+ ACTMENU_KEY_CHANPOS_MOVE_CHANNEL_UP = 0,
+ ACTMENU_KEY_CHANPOS_MOVE_CHANNEL_DOWN,
+ ACTMENU_KEY_CHANPOS_MOVE_CHANNEL_TOP,
+ ACTMENU_KEY_CHANPOS_MOVE_CHANNEL_BOTTOM
+};
+
+enum {
+ ACTMENU_KEY_TRANSFORM_MOVE = 0,
+ ACTMENU_KEY_TRANSFORM_SCALE,
+ ACTMENU_KEY_TRANSFORM_SLIDE,
+ ACTMENU_KEY_TRANSFORM_EXTEND
+};
+
+enum {
+ ACTMENU_KEY_HANDLE_AUTO = 0,
+ ACTMENU_KEY_HANDLE_ALIGN,
+ ACTMENU_KEY_HANDLE_FREE,
+ ACTMENU_KEY_HANDLE_VECTOR
+};
+
+enum {
+ ACTMENU_KEY_INTERP_CONST = 0,
+ ACTMENU_KEY_INTERP_LINEAR,
+ ACTMENU_KEY_INTERP_BEZIER
+};
+
+enum {
+ ACTMENU_KEY_EXTEND_CONST = 0,
+ ACTMENU_KEY_EXTEND_EXTRAPOLATION,
+ ACTMENU_KEY_EXTEND_CYCLIC,
+ ACTMENU_KEY_EXTEND_CYCLICEXTRAPOLATION
+};
+
+enum {
+ ACTMENU_KEY_SNAP_NEARFRAME = 1,
+ ACTMENU_KEY_SNAP_CURFRAME,
+ ACTMENU_KEY_SNAP_NEARMARK,
+ ACTMENU_KEY_SNAP_NEARTIME,
+};
+
+enum {
+ ACTMENU_KEY_MIRROR_CURFRAME = 1,
+ ACTMENU_KEY_MIRROR_YAXIS,
+ ACTMENU_KEY_MIRROR_XAXIS,
+ ACTMENU_KEY_MIRROR_MARKER
+};
+
+enum {
+ ACTMENU_MARKERS_ADD = 0,
+ ACTMENU_MARKERS_DUPLICATE,
+ ACTMENU_MARKERS_DELETE,
+ ACTMENU_MARKERS_NAME,
+ ACTMENU_MARKERS_MOVE
+};
+
+void do_action_buttons(unsigned short event)
+{
+ Object *ob= OBACT;
+
+ switch(event) {
+ case B_ACTHOME: /* HOMEKEY in Action Editor */
+ /* Find X extents */
+ G.v2d->cur.xmin = 0;
+ G.v2d->cur.ymin=-SCROLLB;
+
+ if (G.saction->action) {
+ float extra;
+
+ calc_action_range(G.saction->action, &G.v2d->cur.xmin, &G.v2d->cur.xmax, 0);
+ if (G.saction->pin==0 && ob) {
+ G.v2d->cur.xmin= get_action_frame_inv(ob, G.v2d->cur.xmin);
+ G.v2d->cur.xmax= get_action_frame_inv(ob, G.v2d->cur.xmax);
+ }
+ extra= 0.05*(G.v2d->cur.xmax - G.v2d->cur.xmin);
+ G.v2d->cur.xmin-= extra;
+ G.v2d->cur.xmax+= extra;
+
+ if (G.v2d->cur.xmin==G.v2d->cur.xmax) {
+ G.v2d->cur.xmax= -5;
+ G.v2d->cur.xmax= 100;
+ }
+ }
+ else { /* shapekeys and/or no action */
+ G.v2d->cur.xmin= -5.0;
+ G.v2d->cur.xmax= 65.0;
+ }
+
+ G.v2d->cur.ymin= -75.0;
+ G.v2d->cur.ymax= 5.0;
+
+ G.v2d->tot= G.v2d->cur;
+ test_view2d(G.v2d, curarea->winx, curarea->winy);
+ view2d_do_locks(curarea, V2D_LOCK_COPY);
+
+ addqueue (curarea->win, REDRAW, 1);
+
+ break;
+
+ /* copy/paste/paste-flip buttons in 3d-view header in PoseMode */
+ case B_ACTCOPY:
+ copy_posebuf();
+ allqueue(REDRAWVIEW3D, 1);
+ break;
+ case B_ACTPASTE:
+ paste_posebuf(0);
+ allqueue(REDRAWVIEW3D, 1);
+ break;
+ case B_ACTPASTEFLIP:
+ paste_posebuf(1);
+ allqueue(REDRAWVIEW3D, 1);
+ break;
+
+ /* copy/paste buttons in Action Editor header */
+ case B_ACTCOPYKEYS:
+ copy_actdata();
+ break;
+ case B_ACTPASTEKEYS:
+ paste_actdata();
+ break;
+
+ case B_ACTPIN: /* __PINFAKE */
+/* if (G.saction->flag & SACTION_PIN) {
+ if (G.saction->action)
+ G.saction->action->id.us ++;
+ }
+ else {
+ if (G.saction->action)
+ G.saction->action->id.us --;
+ }
+*/ /* end PINFAKE */
+ allqueue(REDRAWACTION, 1);
+ break;
+ }
+}
+
+static void do_action_viewmenu(void *arg, int event)
+{
+ extern int play_anim(int mode);
+
+ switch(event) {
+ case ACTMENU_VIEW_CENTERVIEW: /* Center View to Current Frame */
+ center_currframe();
+ break;
+ case ACTMENU_VIEW_AUTOUPDATE: /* Update Automatically */
+ if (BTST(G.saction->lock, 0))
+ G.saction->lock = BCLR(G.saction->lock, 0);
+ else
+ G.saction->lock = BSET(G.saction->lock, 0);
+ break;
+ case ACTMENU_VIEW_PLAY3D: /* Play Back Animation */
+ play_anim(0);
+ break;
+ case ACTMENU_VIEW_PLAYALL: /* Play Back Animation in All */
+ play_anim(1);
+ break;
+ case ACTMENU_VIEW_ALL: /* View All */
+ do_action_buttons(B_ACTHOME);
+ break;
+ case ACTMENU_VIEW_LOCK:
+ G.v2d->flag ^= V2D_VIEWLOCK;
+ if(G.v2d->flag & V2D_VIEWLOCK)
+ view2d_do_locks(curarea, 0);
+ break;
+ case ACTMENU_VIEW_SLIDERS: /* Show sliders (when applicable) */
+ G.saction->flag ^= SACTION_SLIDERS;
+ break;
+ case ACTMENU_VIEW_MAXIMIZE: /* Maximize Window */
+ /* using event B_FULL */
+ break;
+ case ACTMENU_VIEW_NEXTMARKER: /* jump to next marker */
+ nextprev_marker(1);
+ break;
+ case ACTMENU_VIEW_PREVMARKER: /* jump to previous marker */
+ nextprev_marker(-1);
+ break;
+ case ACTMENU_VIEW_TIME: /* switch between frames and seconds display */
+ G.saction->flag ^= SACTION_DRAWTIME;
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *action_viewmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "action_viewmenu",
+ UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_action_viewmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Center View to Current Frame|C", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1,
+ ACTMENU_VIEW_CENTERVIEW, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6,
+ menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ if (G.saction->flag & SACTION_DRAWTIME) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Show Frames|Ctrl T", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1,
+ ACTMENU_VIEW_TIME, "");
+ }
+ else {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Show Seconds|Ctrl T", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1,
+ ACTMENU_VIEW_TIME, "");
+ }
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, (G.saction->flag & SACTION_SLIDERS)?ICON_CHECKBOX_HLT:ICON_CHECKBOX_DEHLT,
+ "Show Sliders|", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1,
+ ACTMENU_VIEW_SLIDERS, "");
+
+ uiDefIconTextBut(block, BUTM, 1, (G.v2d->flag & V2D_VIEWLOCK)?ICON_CHECKBOX_HLT:ICON_CHECKBOX_DEHLT,
+ "Lock Time to Other Windows|", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1,
+ ACTMENU_VIEW_LOCK, "");
+
+ uiDefIconTextBut(block, BUTM, 1, BTST(G.saction->lock, 0)?ICON_CHECKBOX_HLT:ICON_CHECKBOX_DEHLT,
+ "Update Automatically|", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1,
+ ACTMENU_VIEW_AUTOUPDATE, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6,
+ menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Jump To Next Marker|PageUp", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0, ACTMENU_VIEW_NEXTMARKER, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Jump To Prev Marker|PageDown", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0, ACTMENU_VIEW_PREVMARKER, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6,
+ menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Play Back Animation|Alt A", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1,
+ ACTMENU_VIEW_PLAY3D, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Play Back Animation in 3D View|Alt Shift A", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1,
+ ACTMENU_VIEW_PLAYALL, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6,
+ menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "View All|Home", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1,
+ ACTMENU_VIEW_ALL, "");
+
+ if (!curarea->full)
+ uiDefIconTextBut(block, BUTM, B_FULL, ICON_BLANK1,
+ "Maximize Window|Ctrl UpArrow", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_VIEW_MAXIMIZE, "");
+ else
+ uiDefIconTextBut(block, BUTM, B_FULL, ICON_BLANK1,
+ "Tile Window|Ctrl DownArrow", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_VIEW_MAXIMIZE, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+static void do_action_selectmenu_columnmenu(void *arg, int event)
+{
+ SpaceAction *saction;
+ bAction *act;
+ Key *key;
+
+ saction = curarea->spacedata.first;
+ if (!saction) return;
+
+ act = saction->action;
+ key = get_action_mesh_key();
+
+#if 0 // actionrewite
+ if (event == ACTMENU_SEL_COLUMN_MARKERSBETWEEN) {
+ markers_selectkeys_between();
+ }
+ else if (ELEM(event, ACTMENU_SEL_COLUMN_KEYS, ACTMENU_SEL_COLUMN_MARKERSCOLUMN)) {
+ if (act)
+ column_select_actionkeys(act, event);
+ else if (key)
+ column_select_shapekeys(key, event);
+ }
+ else
+ return;
+#endif // actionrewite
+
+ allqueue(REDRAWTIME, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWNLA, 0);
+ allqueue(REDRAWSOUND, 0);
+}
+
+static uiBlock *action_selectmenu_columnmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "action_selectmenu_columnmenu",
+ UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_action_selectmenu_columnmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "On Selected Keys|K", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_SEL_COLUMN_KEYS, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "On Selected Markers|Shift K", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_SEL_COLUMN_MARKERSCOLUMN, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Between Selected Markers|Ctrl K", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_SEL_COLUMN_MARKERSBETWEEN, "");
+
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+
+ return block;
+}
+
+static void do_action_selectmenu(void *arg, int event)
+{
+ SpaceAction *saction;
+ bAction *act;
+ Key *key;
+
+ saction = curarea->spacedata.first;
+ if (!saction) return;
+
+ act = saction->action;
+ key = get_action_mesh_key();
+
+ switch(event)
+ {
+ case ACTMENU_SEL_BORDER: /* Border Select */
+ borderselect_action();
+ break;
+
+ case ACTMENU_SEL_BORDERM: /* Border Select */
+ borderselect_markers();
+ break;
+
+ case ACTMENU_SEL_ALL_KEYS: /* Select/Deselect All Keys */
+ deselect_action_keys(1, 1);
+ allqueue (REDRAWACTION, 0);
+ allqueue(REDRAWNLA, 0);
+ allqueue (REDRAWIPO, 0);
+ break;
+
+ case ACTMENU_SEL_ALL_CHAN: /* Select/Deselect All Channels */
+ deselect_action_channels(1);
+ allqueue (REDRAWVIEW3D, 0);
+ allqueue (REDRAWACTION, 0);
+ allqueue(REDRAWNLA, 0);
+ allqueue (REDRAWIPO, 0);
+ break;
+
+ case ACTMENU_SEL_ALL_MARKERS: /* select/deselect all markers */
+ deselect_markers(1, 0);
+ allqueue(REDRAWMARKER, 0);
+ break;
+
+ case ACTMENU_SEL_INVERSE_KEYS: /* invert selection status of keys */
+ deselect_action_keys(0, 2);
+ allqueue (REDRAWACTION, 0);
+ allqueue(REDRAWNLA, 0);
+ allqueue (REDRAWIPO, 0);
+ break;
+
+ case ACTMENU_SEL_INVERSE_MARKERS: /* invert selection of markers */
+ deselect_markers(0, 2);
+ allqueue(REDRAWMARKER, 0);
+ break;
+ }
+}
+
+static uiBlock *action_selectmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "action_selectmenu",
+ UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_action_selectmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Border Select Keys|B", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_SEL_BORDER, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Border Select Markers|Ctrl B", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_SEL_BORDERM, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6,
+ menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Select/Deselect All Keys|A", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_SEL_ALL_KEYS, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Select/Deselect All Markers|Ctrl A", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_SEL_ALL_MARKERS, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Select/Deselect All Channels", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_SEL_ALL_CHAN, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6,
+ menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Inverse Keys", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_SEL_INVERSE_KEYS, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Inverse Markers", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_SEL_INVERSE_MARKERS, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6,
+ menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBlockBut(block, action_selectmenu_columnmenu,
+ NULL, ICON_RIGHTARROW_THIN, "Column Select Keys", 0, yco-=20, 120, 20, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+static void do_action_keymenu_transformmenu(void *arg, int event)
+{
+ switch (event)
+ {
+ case ACTMENU_KEY_TRANSFORM_MOVE:
+ transform_action_keys('g', 0);
+ break;
+ case ACTMENU_KEY_TRANSFORM_SCALE:
+ transform_action_keys('s', 0);
+ break;
+ case ACTMENU_KEY_TRANSFORM_SLIDE:
+ transform_action_keys('t', 0);
+ break;
+ case ACTMENU_KEY_TRANSFORM_EXTEND:
+ transform_action_keys('e', 0);
+ break;
+ }
+
+ scrarea_queue_winredraw(curarea);
+}
+
+static uiBlock *action_keymenu_transformmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "action_keymenu_transformmenu",
+ UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_action_keymenu_transformmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Grab/Move|G", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_KEY_TRANSFORM_MOVE, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Grab/Extend from Frame|E", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_KEY_TRANSFORM_EXTEND, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Scale|S", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_KEY_TRANSFORM_SCALE, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Time Slide|T", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_KEY_TRANSFORM_SLIDE, "");
+
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+
+ return block;
+}
+
+static void do_action_keymenu_handlemenu(void *arg, int event)
+{
+ switch (event) {
+ case ACTMENU_KEY_HANDLE_AUTO:
+ sethandles_action_keys(HD_AUTO);
+ break;
+
+ case ACTMENU_KEY_HANDLE_ALIGN:
+ case ACTMENU_KEY_HANDLE_FREE:
+ /* OK, this is kinda dumb, need to fix the
+ * toggle crap in sethandles_ipo_keys()
+ */
+ sethandles_action_keys(HD_ALIGN);
+ break;
+
+ case ACTMENU_KEY_HANDLE_VECTOR:
+ sethandles_action_keys(HD_VECT);
+ break;
+ }
+}
+
+static uiBlock *action_keymenu_handlemenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "action_keymenu_handlemenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_action_keymenu_handlemenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Auto|Shift H", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_KEY_HANDLE_AUTO, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Aligned|H", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_KEY_HANDLE_ALIGN, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Free|H", 0, yco-=20, menuwidth,
+ 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_KEY_HANDLE_FREE, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Vector|V", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_KEY_HANDLE_VECTOR, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+
+ return block;
+}
+
+static void do_action_keymenu_intpolmenu(void *arg, int event)
+{
+ switch(event)
+ {
+ case ACTMENU_KEY_INTERP_CONST:
+ action_set_ipo_flags(SET_IPO_MENU, SET_IPO_CONSTANT);
+ break;
+ case ACTMENU_KEY_INTERP_LINEAR:
+ action_set_ipo_flags(SET_IPO_MENU, SET_IPO_LINEAR);
+ break;
+ case ACTMENU_KEY_INTERP_BEZIER:
+ action_set_ipo_flags(SET_IPO_MENU, SET_IPO_BEZIER);
+ break;
+ }
+
+ scrarea_queue_winredraw(curarea);
+}
+
+static uiBlock *action_keymenu_intpolmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "action_keymenu_intpolmenu",
+ UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_action_keymenu_intpolmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Constant|Shift T, 1", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_KEY_INTERP_CONST, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Linear|Shift T, 2", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_KEY_INTERP_LINEAR, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Bezier|Shift T, 3", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_KEY_INTERP_BEZIER, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+
+ return block;
+}
+
+static void do_action_keymenu_extendmenu(void *arg, int event)
+{
+ switch(event)
+ {
+ case ACTMENU_KEY_EXTEND_CONST:
+ action_set_ipo_flags(SET_EXTEND_MENU, SET_EXTEND_CONSTANT);
+ break;
+ case ACTMENU_KEY_EXTEND_EXTRAPOLATION:
+ action_set_ipo_flags(SET_EXTEND_MENU, SET_EXTEND_EXTRAPOLATION);
+ break;
+ case ACTMENU_KEY_EXTEND_CYCLIC:
+ action_set_ipo_flags(SET_EXTEND_MENU, SET_EXTEND_CYCLIC);
+ break;
+ case ACTMENU_KEY_EXTEND_CYCLICEXTRAPOLATION:
+ action_set_ipo_flags(SET_EXTEND_MENU, SET_EXTEND_CYCLICEXTRAPOLATION);
+ break;
+ }
+
+ scrarea_queue_winredraw(curarea);
+}
+
+static uiBlock *action_keymenu_extendmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "action_keymenu_extendmenu",
+ UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_action_keymenu_extendmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Constant", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_KEY_EXTEND_CONST, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Extrapolation", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_KEY_EXTEND_EXTRAPOLATION, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Cyclic", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_KEY_EXTEND_CYCLIC, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Cyclic Extrapolation", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_KEY_EXTEND_CYCLICEXTRAPOLATION, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+
+ return block;
+}
+
+static void do_action_keymenu_chanposmenu(void *arg, int event)
+{
+ switch(event)
+ {
+ case ACTMENU_KEY_CHANPOS_MOVE_CHANNEL_DOWN:
+ down_sel_action();
+ break;
+ case ACTMENU_KEY_CHANPOS_MOVE_CHANNEL_UP:
+ up_sel_action();
+ break;
+ case ACTMENU_KEY_CHANPOS_MOVE_CHANNEL_TOP:
+ top_sel_action();
+ break;
+ case ACTMENU_KEY_CHANPOS_MOVE_CHANNEL_BOTTOM:
+ bottom_sel_action();
+ break;
+ }
+
+ scrarea_queue_winredraw(curarea);
+}
+
+static uiBlock *action_keymenu_chanposmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "action_keymenu_chanposmenu",
+ UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_action_keymenu_chanposmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Move Up|Ctrl Page Up", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_KEY_CHANPOS_MOVE_CHANNEL_UP, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Move Down|Ctrl Page Down", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_KEY_CHANPOS_MOVE_CHANNEL_DOWN, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6,
+ menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Move to Top|Shift Page Up", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_KEY_CHANPOS_MOVE_CHANNEL_TOP, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Move to Bottom|Shift Page Down", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_KEY_CHANPOS_MOVE_CHANNEL_BOTTOM, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+
+ return block;
+}
+
+static void do_action_keymenu_snapmenu(void *arg, int event)
+{
+ switch(event)
+ {
+ case ACTMENU_KEY_SNAP_NEARFRAME:
+ case ACTMENU_KEY_SNAP_CURFRAME:
+ case ACTMENU_KEY_SNAP_NEARMARK:
+ case ACTMENU_KEY_SNAP_NEARTIME:
+ snap_action_keys(event);
+ break;
+ }
+
+ scrarea_queue_winredraw(curarea);
+}
+
+static uiBlock *action_keymenu_snapmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "action_keymenu_snapmenu",
+ UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_action_keymenu_snapmenu, NULL);
+
+ if (G.saction->flag & SACTION_DRAWTIME) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Nearest Second|Shift S, 1", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_KEY_SNAP_NEARTIME, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Current Time|Shift S, 2", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_KEY_SNAP_CURFRAME, "");
+
+ }
+ else {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Nearest Frame|Shift S, 1", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_KEY_SNAP_NEARFRAME, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Current Frame|Shift S, 2", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_KEY_SNAP_CURFRAME, "");
+ }
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Nearest Marker|Shift S, 3", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_KEY_SNAP_NEARMARK, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+
+ return block;
+}
+
+static void do_action_keymenu_mirrormenu(void *arg, int event)
+{
+ switch(event)
+ {
+ case ACTMENU_KEY_MIRROR_CURFRAME:
+ case ACTMENU_KEY_MIRROR_YAXIS:
+ mirror_action_keys(event);
+ break;
+ }
+
+ scrarea_queue_winredraw(curarea);
+}
+
+static uiBlock *action_keymenu_mirrormenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "action_keymenu_mirrormenu",
+ UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_action_keymenu_mirrormenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Current Frame|Shift M, 1", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_KEY_MIRROR_CURFRAME, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Vertical Axis|Shift M, 2", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_KEY_MIRROR_YAXIS, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Horizontal Axis|Shift M, 3", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_KEY_MIRROR_XAXIS, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Selected Marker|Shift M, 4", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_KEY_MIRROR_MARKER, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+
+ return block;
+}
+
+static void do_action_keymenu(void *arg, int event)
+{
+ SpaceAction *saction;
+ bAction *act;
+ Key *key;
+
+ saction = curarea->spacedata.first;
+ if (!saction) return;
+
+ act = saction->action;
+ key = get_action_mesh_key();
+
+ switch(event)
+ {
+ case ACTMENU_KEY_DUPLICATE:
+ duplicate_action_keys();
+ break;
+ case ACTMENU_KEY_DELETE:
+ delete_action_keys ();
+ break;
+ case ACTMENU_KEY_CLEAN:
+ clean_action();
+ break;
+ }
+}
+
+static uiBlock *action_keymenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "action_keymenu",
+ UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_action_keymenu, NULL);
+
+ uiDefIconTextBlockBut(block, action_keymenu_transformmenu,
+ NULL, ICON_RIGHTARROW_THIN, "Transform", 0, yco-=20, 120, 20, "");
+
+ uiDefIconTextBlockBut(block, action_keymenu_snapmenu,
+ NULL, ICON_RIGHTARROW_THIN, "Snap", 0, yco-=20, 120, 20, "");
+
+ uiDefIconTextBlockBut(block, action_keymenu_mirrormenu,
+ NULL, ICON_RIGHTARROW_THIN, "Mirror", 0, yco-=20, 120, 20, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6,
+ menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Duplicate|Shift D", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_KEY_DUPLICATE, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Delete|X", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_KEY_DELETE, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6,
+ menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Clean Action|O", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0,
+ ACTMENU_KEY_CLEAN, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6,
+ menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBlockBut(block, action_keymenu_handlemenu,
+ NULL, ICON_RIGHTARROW_THIN,
+ "Handle Type", 0, yco-=20, 120, 20, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6,
+ menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBlockBut(block, action_keymenu_extendmenu,
+ NULL, ICON_RIGHTARROW_THIN,
+ "Extend Mode", 0, yco-=20, 120, 20, "");
+ uiDefIconTextBlockBut(block, action_keymenu_intpolmenu,
+ NULL, ICON_RIGHTARROW_THIN,
+ "Interpolation Mode", 0, yco-=20, 120, 20, "");
+ uiDefIconTextBlockBut(block, action_keymenu_chanposmenu,
+ NULL, ICON_RIGHTARROW_THIN,
+ "Channel Ordering", 0, yco-=20, 120, 20, "");
+
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+static void do_action_markermenu(void *arg, int event)
+{
+ switch(event)
+ {
+ case ACTMENU_MARKERS_ADD:
+ add_marker(CFRA);
+ break;
+ case ACTMENU_MARKERS_DUPLICATE:
+ duplicate_marker();
+ break;
+ case ACTMENU_MARKERS_DELETE:
+ remove_marker();
+ break;
+ case ACTMENU_MARKERS_NAME:
+ rename_marker();
+ break;
+ case ACTMENU_MARKERS_MOVE:
+ transform_markers('g', 0);
+ break;
+ }
+
+ allqueue(REDRAWMARKER, 0);
+}
+
+static uiBlock *action_markermenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "action_markermenu",
+ UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_action_markermenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Add Marker|M", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, ACTMENU_MARKERS_ADD, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Duplicate Marker|Ctrl Shift D", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, ACTMENU_MARKERS_DUPLICATE, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Delete Marker|X", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, ACTMENU_MARKERS_DELETE, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "(Re)Name Marker|Ctrl M", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, ACTMENU_MARKERS_NAME, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Grab/Move Marker|Ctrl G", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, ACTMENU_MARKERS_MOVE, "");
+
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+void action_buttons(void)
+{
+ uiBlock *block;
+ short xco, xmax;
+ char name[256];
+ Object *ob;
+ ID *from;
+
+ if (G.saction == NULL)
+ return;
+
+ /* copied from drawactionspace.... */
+ if (!G.saction->pin) {
+ if (OBACT)
+ G.saction->action = OBACT->action;
+ else
+ G.saction->action= NULL;
+ }
+
+ sprintf(name, "header %d", curarea->headwin);
+ block= uiNewBlock(&curarea->uiblocks, name,
+ UI_EMBOSS, UI_HELV, curarea->headwin);
+
+ if (area_is_active_area(curarea))
+ uiBlockSetCol(block, TH_HEADER);
+ else
+ uiBlockSetCol(block, TH_HEADERDESEL);
+
+ curarea->butspacetype= SPACE_ACTION;
+
+ xco = 8;
+
+ uiDefIconTextButC(block, ICONTEXTROW,B_NEWSPACE, ICON_VIEW3D,
+ windowtype_pup(), xco, 0, XIC+10, YIC,
+ &(curarea->butspacetype), 1.0, SPACEICONMAX, 0, 0,
+ "Displays Current Window Type. "
+ "Click for menu of available types.");
+
+ xco += XIC + 14;
+
+ uiBlockSetEmboss(block, UI_EMBOSSN);
+ if (curarea->flag & HEADER_NO_PULLDOWN) {
+ uiDefIconButBitS(block, TOG, HEADER_NO_PULLDOWN, B_FLIPINFOMENU,
+ ICON_DISCLOSURE_TRI_RIGHT,
+ xco,2,XIC,YIC-2,
+ &(curarea->flag), 0, 0, 0, 0,
+ "Show pulldown menus");
+ }
+ else {
+ uiDefIconButBitS(block, TOG, HEADER_NO_PULLDOWN, B_FLIPINFOMENU,
+ ICON_DISCLOSURE_TRI_DOWN,
+ xco,2,XIC,YIC-2,
+ &(curarea->flag), 0, 0, 0, 0,
+ "Hide pulldown menus");
+ }
+ uiBlockSetEmboss(block, UI_EMBOSS);
+ xco+=XIC;
+
+ if ((curarea->flag & HEADER_NO_PULLDOWN)==0) {
+ /* pull down menus */
+ uiBlockSetEmboss(block, UI_EMBOSSP);
+
+ xmax= GetButStringLength("View");
+ uiDefPulldownBut(block, action_viewmenu, NULL,
+ "View", xco, -2, xmax-3, 24, "");
+ xco+= xmax;
+
+ xmax= GetButStringLength("Select");
+ uiDefPulldownBut(block, action_selectmenu, NULL,
+ "Select", xco, -2, xmax-3, 24, "");
+ xco+= xmax;
+
+ xmax= GetButStringLength("Marker");
+ uiDefPulldownBut(block, action_markermenu, NULL,
+ "Marker", xco, -2, xmax-3, 24, "");
+ xco+= xmax;
+
+ xmax= GetButStringLength("Key");
+ uiDefPulldownBut(block, action_keymenu, NULL,
+ "Key", xco, -2, xmax-3, 24, "");
+ xco+= xmax;
+ }
+
+ uiBlockSetEmboss(block, UI_EMBOSS);
+
+ /* NAME ETC */
+ ob= OBACT;
+ from = (ID *)ob;
+
+ xco= std_libbuttons(block, xco, 0, B_ACTPIN, &G.saction->pin,
+ B_ACTIONBROWSE, ID_AC, 0, (ID*)G.saction->action,
+ from, &(G.saction->actnr), B_ACTALONE,
+ B_ACTLOCAL, B_ACTIONDELETE, 0, 0);
+
+ uiClearButLock();
+
+ /* draw AUTOSNAP */
+ xco += 8;
+
+ if (G.saction->flag & SACTION_DRAWTIME) {
+ uiDefButS(block, MENU, B_REDR,
+ "Auto-Snap Keyframes %t|Off %x0|Second Step %x1|Nearest Second %x2|Nearest Marker %x3",
+ xco,0,70,YIC, &(G.saction->autosnap), 0, 1, 0, 0,
+ "Auto-snapping mode for keyframes when transforming");
+ }
+ else {
+ uiDefButS(block, MENU, B_REDR,
+ "Auto-Snap Keyframes %t|Off %x0|Frame Step %x1|Nearest Frame %x2|Nearest Marker %x3",
+ xco,0,70,YIC, &(G.saction->autosnap), 0, 1, 0, 0,
+ "Auto-snapping mode for keyframes when transforming");
+ }
+
+ xco += (70 + 8);
+
+ /* COPY PASTE */
+ uiBlockBeginAlign(block);
+ if (curarea->headertype==HEADERTOP) {
+ uiDefIconBut(block, BUT, B_ACTCOPYKEYS, ICON_COPYUP, xco,0,XIC,YIC, 0, 0, 0, 0, 0, "Copies the selected keyframes from the selected channel(s) to the buffer");
+ uiDefIconBut(block, BUT, B_ACTPASTEKEYS, ICON_PASTEUP, xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0, "Pastes the keyframes from the buffer");
+ }
+ else {
+ uiDefIconBut(block, BUT, B_ACTCOPYKEYS, ICON_COPYDOWN, xco,0,XIC,YIC, 0, 0, 0, 0, 0, "Copies the selected keyframes from the selected channel(s) to the buffer");
+ uiDefIconBut(block, BUT, B_ACTPASTEKEYS, ICON_PASTEDOWN, xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0, "Pastes the keyframes from the buffer");
+ }
+ uiBlockEndAlign(block);
+ xco += (XIC + 8);
+
+ /* draw LOCK */
+ uiDefIconButS(block, ICONTOG, 1, ICON_UNLOCKED, xco, 0, XIC, YIC,
+ &(G.saction->lock), 0, 0, 0, 0,
+ "Updates other affected window spaces automatically "
+ "to reflect changes in real time");
+
+ /* always as last */
+ curarea->headbutlen = xco + 2*XIC;
+
+ uiDrawBlock(block);
+}
diff --git a/source/blender/src/header_buttonswin.c b/source/blender/src/header_buttonswin.c
new file mode 100644
index 00000000000..15ef5962e99
--- /dev/null
+++ b/source/blender/src/header_buttonswin.c
@@ -0,0 +1,728 @@
+/**
+ * header_buttonswin.c oct-2003
+ *
+ * Functions to draw the "Buttons Window" window header
+ * and handle user events sent to it.
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "DNA_ID.h"
+#include "DNA_armature_types.h"
+#include "DNA_brush_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_material_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_world_types.h"
+
+#include "BIF_editconstraint.h"
+#include "BIF_interface.h"
+#include "BIF_previewrender.h"
+#include "BIF_resources.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_butspace.h"
+
+#include "BKE_armature.h"
+#include "BKE_blender.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_node.h"
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
+
+#include "BSE_drawipo.h"
+#include "BSE_node.h"
+#include "BSE_headerbuttons.h"
+
+#include "MEM_guardedalloc.h"
+#include "BLI_blenlib.h"
+
+#include "blendef.h"
+#include "mydevice.h"
+#include "butspace.h"
+
+Material matcopybuf;
+
+void clear_matcopybuf(void)
+{
+ memset(&matcopybuf, 0, sizeof(Material));
+}
+
+void free_matcopybuf(void)
+{
+ extern MTex mtexcopybuf; /* buttons.c */
+ int a;
+
+ for(a=0; a<MAX_MTEX; a++) {
+ if(matcopybuf.mtex[a]) {
+ MEM_freeN(matcopybuf.mtex[a]);
+ matcopybuf.mtex[a]= NULL;
+ }
+ }
+
+ if(matcopybuf.ramp_col) MEM_freeN(matcopybuf.ramp_col);
+ if(matcopybuf.ramp_spec) MEM_freeN(matcopybuf.ramp_spec);
+
+ matcopybuf.ramp_col= NULL;
+ matcopybuf.ramp_spec= NULL;
+
+ if(matcopybuf.nodetree) {
+ ntreeFreeTree(matcopybuf.nodetree);
+ MEM_freeN(matcopybuf.nodetree);
+ matcopybuf.nodetree= NULL;
+ }
+ default_mtex(&mtexcopybuf);
+}
+
+void do_buts_buttons(short event)
+{
+ static short matcopied=0;
+ MTex *mtex;
+ Material *ma;
+ ID id;
+ int a;
+ float dx, dy;
+ if(curarea->win==0) return;
+
+ switch(event) {
+ case B_BUTSHOME:
+ uiSetPanel_view2d(curarea);
+ G.v2d->cur= G.v2d->tot;
+ test_view2d(G.v2d, curarea->winx, curarea->winy);
+
+ /* we always put in left/top */
+ dy= G.v2d->tot.ymax - G.v2d->cur.ymax;
+ G.v2d->cur.ymin += dy;
+ G.v2d->cur.ymax += dy;
+ dx= G.v2d->tot.xmin - G.v2d->cur.xmin;
+ G.v2d->cur.xmin += dx;
+ G.v2d->cur.xmax += dx;
+
+ scrarea_queue_winredraw(curarea);
+ break;
+ case B_BUTSPREVIEW:
+ BIF_preview_changed(ID_TE);
+ G.buts->oldkeypress = 0;
+ scrarea_queue_headredraw(curarea);
+ scrarea_queue_winredraw(curarea);
+ break;
+ case B_CONTEXT_SWITCH:
+ G.buts->oldkeypress = 0;
+ scrarea_queue_headredraw(curarea);
+ scrarea_queue_winredraw(curarea);
+ break;
+ case B_MATCOPY:
+ if(G.buts->lockpoin) {
+ ma= G.buts->lockpoin;
+ if(matcopied) free_matcopybuf();
+
+ memcpy(&matcopybuf, ma, sizeof(Material));
+ if(matcopybuf.ramp_col) matcopybuf.ramp_col= MEM_dupallocN(matcopybuf.ramp_col);
+ if(matcopybuf.ramp_spec) matcopybuf.ramp_spec= MEM_dupallocN(matcopybuf.ramp_spec);
+
+ for(a=0; a<MAX_MTEX; a++) {
+ mtex= matcopybuf.mtex[a];
+ if(mtex) {
+ matcopybuf.mtex[a]= MEM_dupallocN(mtex);
+ }
+ }
+ matcopybuf.nodetree= ntreeCopyTree(ma->nodetree, 0);
+ matcopied= 1;
+ }
+ break;
+ case B_MATPASTE:
+ if(matcopied && G.buts->lockpoin) {
+ ma= G.buts->lockpoin;
+
+ /* free current mat */
+ if(ma->ramp_col) MEM_freeN(ma->ramp_col);
+ if(ma->ramp_spec) MEM_freeN(ma->ramp_spec);
+ for(a=0; a<MAX_MTEX; a++) {
+ mtex= ma->mtex[a];
+ if(mtex && mtex->tex) mtex->tex->id.us--;
+ if(mtex) MEM_freeN(mtex);
+ }
+
+ if(ma->nodetree) {
+ ntreeFreeTree(ma->nodetree);
+ MEM_freeN(ma->nodetree);
+ }
+
+ id= (ma->id);
+ memcpy(ma, &matcopybuf, sizeof(Material));
+ (ma->id)= id;
+
+ if(matcopybuf.ramp_col) ma->ramp_col= MEM_dupallocN(matcopybuf.ramp_col);
+ if(matcopybuf.ramp_spec) ma->ramp_spec= MEM_dupallocN(matcopybuf.ramp_spec);
+
+ for(a=0; a<MAX_MTEX; a++) {
+ mtex= ma->mtex[a];
+ if(mtex) {
+ ma->mtex[a]= MEM_dupallocN(mtex);
+ if(mtex->tex) id_us_plus((ID *)mtex->tex);
+ }
+ }
+
+ ma->nodetree= ntreeCopyTree(matcopybuf.nodetree, 0);
+
+ BIF_preview_changed(ID_MA);
+ BIF_undo_push("Paste material settings");
+ scrarea_queue_winredraw(curarea);
+ }
+ break;
+ case B_MESHTYPE:
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+ }
+}
+
+void buttons_active_id(ID **id, ID **idfrom)
+{
+ Object *ob= OBACT;
+ Material *ma;
+
+ *id= NULL;
+ *idfrom= (ID *)ob;
+
+ if(G.buts->mainb==CONTEXT_SCENE) {
+ int tab= G.buts->tab[CONTEXT_SCENE];
+
+ if(tab==TAB_SCENE_RENDER) *id= (ID *)G.scene;
+ else if(tab==TAB_SCENE_SOUND) {
+ ID *search;
+
+ // validate lockpoin, maybe its not a sound
+ if (G.buts->lockpoin) {
+ search = G.main->sound.first;
+ while (search) {
+ if (search == G.buts->lockpoin) {
+ break;
+ }
+ search = search->next;
+ }
+ if (search == NULL) {
+ *id = G.main->sound.first;
+ } else {
+ *id = search;
+ }
+ }
+ else {
+ *id = G.main->sound.first;
+ }
+
+ }
+ }
+ else if(G.buts->mainb==CONTEXT_SHADING) {
+ int tab= G.buts->tab[CONTEXT_SHADING];
+
+ if(tab==TAB_SHADING_LAMP) {
+ if(ob && ob->type==OB_LAMP) {
+ *id= ob->data;
+ }
+ }
+ else if(tab==TAB_SHADING_MAT) {
+ if(ob && (ob->type<OB_LAMP) && ob->type) {
+ *id= (ID *)give_current_material(ob, ob->actcol);
+ *idfrom= material_from(ob, ob->actcol);
+ }
+ }
+ else if(tab==TAB_SHADING_WORLD) {
+ *id= (ID *)G.scene->world;
+ *idfrom= (ID *)G.scene;
+ }
+ else if(tab==TAB_SHADING_TEX) {
+ MTex *mtex;
+
+ if(G.buts->mainbo==G.buts->mainb && G.buts->tabo!=tab) {
+ if(G.buts->tabo==TAB_SHADING_LAMP) G.buts->texfrom= 2;
+ else if(G.buts->tabo==TAB_SHADING_WORLD) G.buts->texfrom= 1;
+ else if(G.buts->tabo==TAB_SHADING_MAT) G.buts->texfrom= 0;
+ }
+
+ if(G.buts->texfrom==0) {
+ if(ob && ob->type<OB_LAMP && ob->type) {
+ bNode *node= NULL;
+
+ ma= give_current_material(ob, ob->actcol);
+ if(ma && ma->use_nodes)
+ node= editnode_get_active_idnode(ma->nodetree, ID_TE);
+
+ if(node) {
+ *idfrom= NULL;
+ *id= node->id;
+ }
+ else {
+ ma= editnode_get_active_material(ma);
+ *idfrom= (ID *)ma;
+ if(ma) {
+ mtex= ma->mtex[ ma->texact ];
+ if(mtex) *id= (ID *)mtex->tex;
+ }
+ }
+ }
+ }
+ else if(G.buts->texfrom==1) {
+ World *wrld= G.scene->world;
+ *idfrom= (ID *)wrld;
+ if(wrld) {
+ mtex= wrld->mtex[ wrld->texact];
+ if(mtex) *id= (ID *)mtex->tex;
+ }
+ }
+ else if(G.buts->texfrom==2) {
+ Lamp *la;
+ if(ob && ob->type==OB_LAMP) {
+ la= ob->data;
+ *idfrom= (ID *)la;
+ mtex= la->mtex[ la->texact];
+ if(mtex) *id= (ID *)mtex->tex;
+ }
+ }
+ else if(G.buts->texfrom==3) {
+ if(G.f & G_SCULPTMODE) {
+ if(G.scene->sculptdata.texact != -1) {
+ mtex= G.scene->sculptdata.mtex[G.scene->sculptdata.texact];
+ if(mtex) *id= (ID*)mtex->tex;
+ }
+ } else {
+ Brush *brush= G.scene->toolsettings->imapaint.brush;
+ if (brush) {
+ mtex= brush->mtex[brush->texact];
+ if(mtex) *id= (ID*)mtex->tex;
+ }
+ }
+ }
+ }
+ }
+ else if(G.buts->mainb==CONTEXT_OBJECT || G.buts->mainb==CONTEXT_LOGIC) {
+ if(ob) {
+ *idfrom= (ID *)G.scene;
+ *id= (ID *)ob;
+ }
+ }
+ else if(G.buts->mainb==CONTEXT_EDITING) {
+ if(ob && ob->data) {
+ *id= ob->data;
+ }
+ }
+}
+
+static void do_buts_view_shadingmenu(void *arg, int event)
+{
+ G.buts->mainb = CONTEXT_SHADING;
+
+ allqueue(REDRAWBUTSALL, 0);
+}
+
+
+static uiBlock *buts_view_shadingmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "buts_view_shadingmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_buts_view_shadingmenu, NULL);
+
+ if((G.buts->mainb == CONTEXT_SHADING) && (G.buts->tab[CONTEXT_SHADING]==TAB_SHADING_LAMP)) {
+ uiDefIconTextButC(block, BUTM, B_REDR, ICON_CHECKBOX_HLT, "Lamp|F5",
+ 0, yco-=20, menuwidth, 19, &(G.buts->tab[CONTEXT_SHADING]), (float)TAB_SHADING_LAMP, 0.0, 0, 10, "");
+ } else {
+ uiDefIconTextButC(block, BUTM, B_REDR, ICON_CHECKBOX_DEHLT, "Lamp|F5",
+ 0, yco-=20, menuwidth, 19, &(G.buts->tab[CONTEXT_SHADING]), (float)TAB_SHADING_LAMP, 0.0, 0, 10, "");
+ }
+
+ if((G.buts->mainb == CONTEXT_SHADING) && (G.buts->tab[CONTEXT_SHADING]==TAB_SHADING_MAT)) {
+ uiDefIconTextButC(block, BUTM, B_REDR, ICON_CHECKBOX_HLT, "Material|F5",
+ 0, yco-=20, menuwidth, 19, &(G.buts->tab[CONTEXT_SHADING]), (float)TAB_SHADING_MAT, 0.0, 0, 10, "");
+ } else {
+ uiDefIconTextButC(block, BUTM, B_REDR, ICON_CHECKBOX_DEHLT, "Material|F5",
+ 0, yco-=20, menuwidth, 19, &(G.buts->tab[CONTEXT_SHADING]), (float)TAB_SHADING_MAT, 0.0, 0, 10, "");
+ }
+
+ if((G.buts->mainb == CONTEXT_SHADING) && (G.buts->tab[CONTEXT_SHADING]==TAB_SHADING_TEX)) {
+ uiDefIconTextButC(block, BUTM, B_REDR, ICON_CHECKBOX_HLT, "Texture|F6",
+ 0, yco-=20, menuwidth, 19, &(G.buts->tab[CONTEXT_SHADING]), (float)TAB_SHADING_TEX, 0.0, 0, 10, "");
+ } else {
+ uiDefIconTextButC(block, BUTM, B_REDR, ICON_CHECKBOX_DEHLT, "Texture|F6",
+ 0, yco-=20, menuwidth, 19, &(G.buts->tab[CONTEXT_SHADING]), (float)TAB_SHADING_TEX, 0.0, 0, 10, "");
+ }
+
+ if((G.buts->mainb == CONTEXT_SHADING) && (G.buts->tab[CONTEXT_SHADING]==TAB_SHADING_RAD)) {
+ uiDefIconTextButC(block, BUTM, B_REDR, ICON_CHECKBOX_HLT, "Radiosity",
+ 0, yco-=20, menuwidth, 19, &(G.buts->tab[CONTEXT_SHADING]), (float)TAB_SHADING_RAD, 0.0, 0, 10, "");
+ } else {
+ uiDefIconTextButC(block, BUTM, B_REDR, ICON_CHECKBOX_DEHLT, "Radiosity",
+ 0, yco-=20, menuwidth, 19, &(G.buts->tab[CONTEXT_SHADING]), (float)TAB_SHADING_RAD, 0.0, 0, 10, "");
+ }
+
+ if((G.buts->mainb == CONTEXT_SHADING) && (G.buts->tab[CONTEXT_SHADING]==TAB_SHADING_WORLD)) {
+ uiDefIconTextButC(block, BUTM, B_REDR, ICON_CHECKBOX_HLT, "World|F8",
+ 0, yco-=20, menuwidth, 19, &(G.buts->tab[CONTEXT_SHADING]), (float)TAB_SHADING_WORLD, 1.0, 0, 10, "");
+ } else {
+ uiDefIconTextButC(block, BUTM, B_REDR, ICON_CHECKBOX_DEHLT, "World|F8",
+ 0, yco-=20, menuwidth, 19, &(G.buts->tab[CONTEXT_SHADING]), (float)TAB_SHADING_WORLD, 1.0, 0, 10, "");
+ }
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+
+ return block;
+}
+
+static void do_buts_view_scenemenu(void *arg, int event)
+{
+ G.buts->mainb = CONTEXT_SCENE;
+
+ allqueue(REDRAWBUTSALL, 0);
+}
+
+
+static uiBlock *buts_view_scenemenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "buts_view_scenemenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_buts_view_scenemenu, NULL);
+
+ if((G.buts->mainb == CONTEXT_SCENE) && (G.buts->tab[CONTEXT_SCENE]==TAB_SCENE_RENDER)) {
+ uiDefIconTextButC(block, BUTM, B_REDR, ICON_CHECKBOX_HLT, "Render|F10",
+ 0, yco-=20, menuwidth, 19, &(G.buts->tab[CONTEXT_SCENE]), (float)TAB_SCENE_RENDER, 0.0, 0, 10, "");
+ } else {
+ uiDefIconTextButC(block, BUTM, B_REDR, ICON_CHECKBOX_DEHLT, "Render|F10",
+ 0, yco-=20, menuwidth, 19, &(G.buts->tab[CONTEXT_SCENE]), (float)TAB_SCENE_RENDER, 0.0, 0, 10, "");
+ }
+
+ if((G.buts->mainb == CONTEXT_SCENE) && (G.buts->tab[CONTEXT_SCENE]==TAB_SCENE_ANIM)) {
+ uiDefIconTextButC(block, BUTM, B_REDR, ICON_CHECKBOX_HLT, "Animation",
+ 0, yco-=20, menuwidth, 19, &(G.buts->tab[CONTEXT_SCENE]), (float)TAB_SCENE_ANIM, 0.0, 0, 10, "");
+ } else {
+ uiDefIconTextButC(block, BUTM, B_REDR, ICON_CHECKBOX_DEHLT, "Animation",
+ 0, yco-=20, menuwidth, 19, &(G.buts->tab[CONTEXT_SCENE]), (float)TAB_SCENE_ANIM, 0.0, 0, 10, "");
+ }
+
+ if((G.buts->mainb == CONTEXT_SCENE) && (G.buts->tab[CONTEXT_SCENE]==TAB_SCENE_SOUND)) {
+ uiDefIconTextButC(block, BUTM, B_REDR, ICON_CHECKBOX_HLT, "Sound",
+ 0, yco-=20, menuwidth, 19, &(G.buts->tab[CONTEXT_SCENE]), (float)TAB_SCENE_SOUND, 0.0, 0, 10, "");
+ } else {
+ uiDefIconTextButC(block, BUTM, B_REDR, ICON_CHECKBOX_DEHLT, "Sound",
+ 0, yco-=20, menuwidth, 19, &(G.buts->tab[CONTEXT_SCENE]), (float)TAB_SCENE_SOUND, 0.0, 0, 10, "");
+ }
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+
+ return block;
+}
+
+static void do_buts_view_alignmenu(void *arg, int event)
+{
+ SpaceButs *sbuts= curarea->spacedata.first;
+
+ switch(event) {
+ case 0: /* panel alignment */
+ case 1:
+ case 2:
+ sbuts->align= event;
+ if(event) {
+ uiAlignPanelStep(curarea, 1.0);
+ do_buts_buttons(B_BUTSHOME);
+ }
+ break;
+ }
+
+ allqueue(REDRAWBUTSALL, 0);
+}
+
+
+static uiBlock *buts_view_alignmenu(void *arg_unused)
+{
+ SpaceButs *sbuts= curarea->spacedata.first;
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "buts_view_alignmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_buts_view_alignmenu, NULL);
+
+ if (sbuts->align == 1) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Horizontal", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Horizontal", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+
+ if (sbuts->align == 2) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Vertical", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Vertical", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+
+ if (sbuts->align == 0) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Free", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+ else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Free", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+
+ return block;
+}
+
+static void do_buts_viewmenu(void *arg, int event)
+{
+ SpaceButs *sbuts= curarea->spacedata.first;
+
+ switch(event) {
+ case 1: /* zoom in */
+ view2d_zoom(&sbuts->v2d, 0.06f, curarea->winx, curarea->winy);
+ break;
+ case 2: /* zoom out */
+ view2d_zoom(&sbuts->v2d, -0.075f, curarea->winx, curarea->winy);
+ break;
+ case 3: /* View All */
+ do_buts_buttons(B_BUTSHOME);
+ break;
+ case 4: /* Maximize Window */
+ /* using event B_FULL */
+ break;
+ case 10: /* empty for the context events */
+ break;
+ }
+ allqueue(REDRAWBUTSALL, 0);
+}
+
+static uiBlock *buts_viewmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "buts_viewmenu",
+ UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_buts_viewmenu, NULL);
+
+ if(G.buts->mainb==CONTEXT_LOGIC) {
+ uiDefIconTextButS(block, BUTM, B_REDR, ICON_CHECKBOX_HLT, "Logic|F4",
+ 0, yco-=20, menuwidth, 19, &(G.buts->mainb), CONTEXT_LOGIC, 0.0, 0, 10, "");
+ } else {
+ uiDefIconTextButS(block, BUTM, B_REDR, ICON_CHECKBOX_DEHLT, "Logic|F4",
+ 0, yco-=20, menuwidth, 19, &(G.buts->mainb), CONTEXT_LOGIC, 0.0, 0, 10, "");
+ }
+
+ if(G.buts->mainb==CONTEXT_SCRIPT) {
+ uiDefIconTextButS(block, BUTM, B_REDR, ICON_CHECKBOX_HLT, "Script",
+ 0, yco-=20, menuwidth, 19, &(G.buts->mainb), (float)CONTEXT_SCRIPT, 0.0, 0, 10, "");
+ } else {
+ uiDefIconTextButS(block, BUTM, B_REDR, ICON_CHECKBOX_DEHLT, "Script",
+ 0, yco-=20, menuwidth, 19, &(G.buts->mainb), (float)CONTEXT_SCRIPT, 0.0, 0, 10, "");
+ }
+
+ uiDefIconTextBlockBut(block, buts_view_shadingmenu, NULL, ICON_RIGHTARROW_THIN, "Shading", 0, yco-=20, 120, 19, "");
+
+ if(G.buts->mainb==CONTEXT_OBJECT) {
+ uiDefIconTextButS(block, BUTM, B_REDR, ICON_CHECKBOX_HLT, "Object|F7",
+ 0, yco-=20, menuwidth, 19, &(G.buts->mainb), (float)CONTEXT_OBJECT, 0.0, 0, 10, "");
+ } else {
+ uiDefIconTextButS(block, BUTM, B_REDR, ICON_CHECKBOX_DEHLT, "Object|F7",
+ 0, yco-=20, menuwidth, 19, &(G.buts->mainb), (float)CONTEXT_OBJECT, 0.0, 0, 10, "");
+ }
+
+ if(G.buts->mainb==CONTEXT_EDITING) {
+ uiDefIconTextButS(block, BUTM, B_REDR, ICON_CHECKBOX_HLT, "Editing|F9",
+ 0, yco-=20, menuwidth, 19, &(G.buts->mainb), (float)CONTEXT_EDITING, 0.0, 0, 10, "");
+ } else {
+ uiDefIconTextButS(block, BUTM, B_REDR, ICON_CHECKBOX_DEHLT, "Editing|F9",
+ 0, yco-=20, menuwidth, 19, &(G.buts->mainb), (float)CONTEXT_EDITING, 0.0, 0, 10, "");
+ }
+
+ uiDefIconTextBlockBut(block, buts_view_scenemenu, NULL, ICON_RIGHTARROW_THIN, "Scene", 0, yco-=20, 120, 19, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBlockBut(block, buts_view_alignmenu, NULL, ICON_RIGHTARROW_THIN, "Align", 0, yco-=20, 120, 19, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Zoom In|NumPad +", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Zoom Out|NumPad -", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "View All|Home", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+
+ if (!curarea->full)
+ uiDefIconTextBut(block, BUTM, B_FULL, ICON_BLANK1, "Maximize Window|Ctrl UpArrow", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
+ else
+ uiDefIconTextBut(block, BUTM, B_FULL, ICON_BLANK1, "Tile Window|Ctrl DownArrow", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+void buts_buttons(void)
+{
+ uiBlock *block;
+ ID *id, *idfrom;
+ short xco, xmax, t_base= 0;
+ char naam[20];
+
+ sprintf(naam, "header %d", curarea->headwin);
+ block= uiNewBlock(&curarea->uiblocks, naam, UI_EMBOSS, UI_HELV, curarea->headwin);
+
+ if(area_is_active_area(curarea)) uiBlockSetCol(block, TH_HEADER);
+ else uiBlockSetCol(block, TH_HEADERDESEL);
+
+ curarea->butspacetype= SPACE_BUTS;
+
+ xco = 8;
+
+ uiDefIconTextButC(block, ICONTEXTROW,B_NEWSPACE, ICON_VIEW3D,
+ windowtype_pup(), xco, 0, XIC+10, YIC,
+ &(curarea->butspacetype), 1.0, SPACEICONMAX, 0, 0,
+ "Displays Current Window Type. "
+ "Click for menu of available types.");
+
+ xco += XIC + 14;
+
+ uiBlockSetEmboss(block, UI_EMBOSSN);
+ if (curarea->flag & HEADER_NO_PULLDOWN) {
+ uiDefIconButBitS(block, TOG, HEADER_NO_PULLDOWN, B_FLIPINFOMENU,
+ ICON_DISCLOSURE_TRI_RIGHT,
+ xco,2,XIC,YIC-2,
+ &(curarea->flag), 0, 0, 0, 0,
+ "Show pulldown menus");
+ }
+ else {
+ uiDefIconButBitS(block, TOG, HEADER_NO_PULLDOWN, B_FLIPINFOMENU,
+ ICON_DISCLOSURE_TRI_DOWN,
+ xco,2,XIC,YIC-2,
+ &(curarea->flag), 0, 0, 0, 0,
+ "Hide pulldown menus");
+ }
+ uiBlockSetEmboss(block, UI_EMBOSS);
+ xco+=XIC;
+
+ if((curarea->flag & HEADER_NO_PULLDOWN)==0) {
+ /* pull down menus */
+ uiBlockSetEmboss(block, UI_EMBOSSP);
+
+ xmax= GetButStringLength("Panels");
+ uiDefPulldownBut(block, buts_viewmenu, NULL,
+ "Panels", xco, -2, xmax-3, 24, "");
+ xco+= xmax;
+
+ }
+
+ uiBlockSetEmboss(block, UI_EMBOSS);
+
+
+ /* FULL WINDOW */
+// if(curarea->full) uiDefIconBut(block, BUT,B_FULL, ICON_SPLITSCREEN, xco,0,XIC,YIC, 0, 0, 0, 0, 0, "Returns to multiple views window (CTRL+Up arrow)");
+// else uiDefIconBut(block, BUT,B_FULL, ICON_FULLSCREEN, xco,0,XIC,YIC, 0, 0, 0, 0, 0, "Makes current window full screen (CTRL+Down arrow)");
+
+ /* HOME */
+// uiDefIconBut(block, BUT, B_BUTSHOME, ICON_HOME, xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0, "Zooms window to home view showing all items (HOMEKEY)");
+// xco+=XIC;
+
+ uiBlockBeginAlign(block);
+ uiDefIconButS(block, ROW, B_CONTEXT_SWITCH, ICON_GAME, xco, 0, XIC, YIC, &(G.buts->mainb), 0.0, (float)CONTEXT_LOGIC, 0, 0, "Logic (F4) ");
+ uiDefIconButS(block, ROW, B_CONTEXT_SWITCH, ICON_SCRIPT, xco+=XIC, 0, XIC, YIC, &(G.buts->mainb), 0.0, (float)CONTEXT_SCRIPT, 0, 0, "Script ");
+ uiDefIconButS(block, ROW, B_BUTSPREVIEW, ICON_MATERIAL_DEHLT,xco+=XIC, 0, XIC, YIC, &(G.buts->mainb), 0.0, (float)CONTEXT_SHADING, 0, 0, "Shading (F5) ");
+ uiDefIconButS(block, ROW, B_CONTEXT_SWITCH, ICON_OBJECT, xco+=XIC, 0, XIC, YIC, &(G.buts->mainb), 0.0, (float)CONTEXT_OBJECT, 0, 0, "Object (F7) ");
+ uiDefIconButS(block, ROW, B_CONTEXT_SWITCH, ICON_EDIT, xco+=XIC, 0, XIC, YIC, &(G.buts->mainb), 0.0, (float)CONTEXT_EDITING, 0, 0, "Editing (F9) ");
+ uiDefIconButS(block, ROW, B_CONTEXT_SWITCH, ICON_SCENE_DEHLT, xco+=XIC, 0, XIC, YIC, &(G.buts->mainb), 0.0, (float)CONTEXT_SCENE, 0, 0, "Scene (F10) ");
+
+ xco+= XIC;
+
+ /* select the context to be drawn, per contex/tab the actual context is tested */
+ uiBlockSetEmboss(block, UI_EMBOSS); // normal
+ switch(G.buts->mainb) {
+ case CONTEXT_SCENE:
+ uiBlockBeginAlign(block);
+ uiDefIconButC(block, ROW, B_CONTEXT_SWITCH, ICON_SCENE, xco+=XIC, t_base, XIC, YIC, &(G.buts->tab[CONTEXT_SCENE]), 1.0, (float)TAB_SCENE_RENDER, 0, 0, "Render buttons ");
+ uiDefIconButC(block, ROW, B_CONTEXT_SWITCH, ICON_ANIM, xco+=XIC, t_base, XIC, YIC, &(G.buts->tab[CONTEXT_SCENE]), 1.0, (float)TAB_SCENE_ANIM, 0, 0, "Anim/playback buttons");
+ uiDefIconButC(block, ROW, B_CONTEXT_SWITCH, ICON_SOUND, xco+=XIC, t_base, XIC, YIC, &(G.buts->tab[CONTEXT_SCENE]), 1.0, (float)TAB_SCENE_SOUND, 0, 0, "Sound block buttons");
+
+ break;
+ case CONTEXT_OBJECT:
+ uiBlockBeginAlign(block);
+ uiDefIconButC(block, ROW, B_CONTEXT_SWITCH, ICON_OBJECT, xco+=XIC, t_base, XIC, YIC, &(G.buts->tab[CONTEXT_OBJECT]), 1.0, (float)TAB_OBJECT_OBJECT, 0, 0, "Object buttons ");
+ uiDefIconButC(block, ROW, B_CONTEXT_SWITCH, ICON_EFFECTS, xco+=XIC, t_base, XIC, YIC, &(G.buts->tab[CONTEXT_OBJECT]), 1.0, (float)TAB_OBJECT_PHYSICS, 0, 0, "Physics buttons");
+
+ break;
+ case CONTEXT_SHADING:
+ uiBlockBeginAlign(block);
+ uiDefIconButC(block, ROW, B_BUTSPREVIEW, ICON_LAMP, xco+=XIC, t_base, XIC, YIC, &(G.buts->tab[CONTEXT_SHADING]), 1.0, (float)TAB_SHADING_LAMP, 0, 0, "Lamp buttons");
+ uiDefIconButC(block, ROW, B_BUTSPREVIEW, ICON_MATERIAL, xco+=XIC, t_base, XIC, YIC, &(G.buts->tab[CONTEXT_SHADING]), 1.0, (float)TAB_SHADING_MAT, 0, 0, "Material buttons");
+ uiDefIconButC(block, ROW, B_BUTSPREVIEW, ICON_TEXTURE, xco+=XIC, t_base, XIC, YIC, &(G.buts->tab[CONTEXT_SHADING]), 1.0, (float)TAB_SHADING_TEX, 0, 0, "Texture buttons(F6)");
+ uiDefIconButC(block, ROW, B_CONTEXT_SWITCH, ICON_RADIO,xco+=XIC, t_base, XIC, YIC, &(G.buts->tab[CONTEXT_SHADING]), 1.0, (float)TAB_SHADING_RAD, 0, 0, "Radiosity buttons");
+ uiDefIconButC(block, ROW, B_BUTSPREVIEW, ICON_WORLD, xco+=XIC, t_base, XIC, YIC, &(G.buts->tab[CONTEXT_SHADING]), 1.0, (float)TAB_SHADING_WORLD, 0, 0, "World buttons");
+
+ break;
+ case CONTEXT_EDITING:
+
+ break;
+ case CONTEXT_SCRIPT:
+
+ break;
+ case CONTEXT_LOGIC:
+
+ break;
+ }
+
+ uiBlockEndAlign(block);
+
+ xco+=XIC;
+ uiDefButI(block, NUM, B_NEWFRAME, "", (xco+20),0,60,YIC, &(G.scene->r.cfra), 1.0, MAXFRAMEF, 0, 0, "Displays Current Frame of animation. Click to change.");
+ xco+= 80;
+
+ buttons_active_id(&id, &idfrom);
+ G.buts->lockpoin= id;
+
+ /* always do as last */
+ uiDrawBlock(block);
+ curarea->headbutlen= xco;
+}
diff --git a/source/blender/src/header_filesel.c b/source/blender/src/header_filesel.c
new file mode 100644
index 00000000000..999fa2733af
--- /dev/null
+++ b/source/blender/src/header_filesel.c
@@ -0,0 +1,194 @@
+/**
+ * header_filesel.c oct-2003
+ *
+ * Functions to draw the "File Browser" window header
+ * and handle user events sent to it.
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "DNA_ID.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BIF_gl.h"
+#include "BIF_interface.h"
+#include "BIF_language.h"
+#include "BIF_resources.h"
+#include "BIF_screen.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BLI_blenlib.h"
+#include "BSE_filesel.h"
+#include "BSE_headerbuttons.h"
+
+#include "blendef.h"
+#include "mydevice.h"
+
+void do_file_buttons(short event)
+{
+ SpaceFile *sfile;
+
+ if(curarea->win==0) return;
+ sfile= curarea->spacedata.first;
+
+ switch(event) {
+ case B_SORTFILELIST:
+ sort_filelist(sfile);
+ scrarea_queue_winredraw(curarea);
+ break;
+ case B_RELOADDIR:
+ freefilelist(sfile);
+ scrarea_queue_winredraw(curarea);
+ break;
+ }
+
+}
+
+void file_buttons(void)
+{
+ SpaceFile *sfile;
+ uiBlock *block;
+ float df, totlen, sellen;
+ short xco, xcotitle;
+ int totfile, selfile;
+ char naam[256];
+
+ sfile= curarea->spacedata.first;
+
+ sprintf(naam, "header %d", curarea->headwin);
+ block= uiNewBlock(&curarea->uiblocks, naam, UI_EMBOSS, UI_HELV, curarea->headwin);
+
+ if(area_is_active_area(curarea)) uiBlockSetCol(block, TH_HEADER);
+ else uiBlockSetCol(block, TH_HEADERDESEL);
+
+ curarea->butspacetype= SPACE_FILE;
+
+ xco = 8;
+
+ uiDefIconTextButC(block, ICONTEXTROW,B_NEWSPACE, ICON_VIEW3D, windowtype_pup(), xco,0,XIC+10,YIC, &(curarea->butspacetype), 1.0, SPACEICONMAX, 0, 0, "Displays Current Window Type. Click for menu of available types.");
+
+ xco+= XIC+22;
+
+ /* FULL WINDOW */
+ if(curarea->full) uiDefIconBut(block, BUT,B_FULL, ICON_SPLITSCREEN, xco,0,XIC,YIC, 0, 0, 0, 0, 0, "Returns to multiple views window (CTRL+Up arrow)");
+ else uiDefIconBut(block, BUT,B_FULL, ICON_FULLSCREEN, xco,0,XIC,YIC, 0, 0, 0, 0, 0, "Makes current window full screen (CTRL+Down arrow)");
+
+ /* SORT TYPE */
+ xco+=XIC;
+ uiBlockBeginAlign(block);
+ uiDefIconButS(block, ROW, B_SORTFILELIST, ICON_SORTALPHA, xco+=XIC,0,XIC,YIC, &sfile->sort, 1.0, 0.0, 0, 0, "Sorts files alphabetically");
+ uiDefIconButS(block, ROW, B_SORTFILELIST, ICON_SORTBYEXT, xco+=XIC,0,XIC,YIC, &sfile->sort, 1.0, 3.0, 0, 0, "Sorts files by extension");
+ uiDefIconButS(block, ROW, B_SORTFILELIST, ICON_SORTTIME, xco+=XIC,0,XIC,YIC, &sfile->sort, 1.0, 1.0, 0, 0, "Sorts files by time");
+ uiDefIconButS(block, ROW, B_SORTFILELIST, ICON_SORTSIZE, xco+=XIC,0,XIC,YIC, &sfile->sort, 1.0, 2.0, 0, 0, "Sorts files by size");
+ uiBlockEndAlign(block);
+
+ cpack(0x0);
+ xco+=XIC+10;
+
+ xcotitle= xco;
+ xco+= BIF_GetStringWidth(G.font, sfile->title, (U.transopts & USER_TR_BUTTONS));
+
+ if(sfile->pupmenu && sfile->menup) {
+ uiDefButS(block, MENU, B_NOP, sfile->pupmenu, xco+10,0,90,20, sfile->menup, 0, 0, 0, 0, "");
+ xco+= 100;
+ }
+ uiBlockBeginAlign(block);
+ uiDefIconButBitS(block, ICONTOG, FILE_SHOWSHORT, B_SORTFILELIST, ICON_LONGDISPLAY,xco+=XIC,0,XIC,YIC, &sfile->flag, 0, 0, 0, 0, "Toggles long info");
+ uiDefIconButBitS(block, TOG, FILE_HIDE_DOT, B_RELOADDIR, ICON_GHOST,xco+=XIC,0,XIC,YIC, &sfile->flag, 0, 0, 0, 0, "Hides dot files");
+ uiBlockEndAlign(block);
+
+ uiDefButBitS(block, TOG, FILE_STRINGCODE, 0, "Relative Paths", xco+=XIC+20,0,100,YIC, &sfile->flag, 0, 0, 0, 0, "Makes sure returned paths are relative to the current .blend file");
+
+ xco+=90;
+
+ if(sfile->type==FILE_LOADLIB) {
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOGN, FILE_LINK, B_REDR, "Append", xco+=XIC,0,100,YIC, &sfile->flag, 0, 0, 0, 0, "Copies selected data into current project");
+ uiDefButBitS(block, TOG, FILE_LINK, B_REDR, "Link", xco+=100,0,100,YIC, &sfile->flag, 0, 0, 0, 0, "Creates a link to selected data from current project");
+ uiBlockEndAlign(block);
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, FILE_AUTOSELECT, B_REDR, "Autosel", xco+=125,0,65,YIC, &sfile->flag, 0, 0, 0, 0, "Autoselect imported objects");
+ uiDefButBitS(block, TOG, FILE_ACTIVELAY, B_REDR, "Active Layer", xco+=65,0,80,YIC, &sfile->flag, 0, 0, 0, 0, "Append object(s) in active layer");
+ uiDefButBitS(block, TOG, FILE_ATCURSOR, B_REDR, "At Cursor", xco+=80,0,65,YIC, &sfile->flag, 0, 0, 0, 0, "Append object(s) at cursor, use centroid if more than one object is selected");
+ uiBlockEndAlign(block);
+
+ xco+= 100; // scroll
+
+ } else if(sfile->type==FILE_BLENDER) {
+ uiDefButBitI(block, TOGN, G_FILE_NO_UI, B_REDR, "Load UI", xco+=XIC,0,80,YIC, &G.fileflags, 0, 0, 0, 0, "Load the UI setup as well as the scene data");
+
+ xco+= 100; // scroll
+ }
+ #ifdef INTERNATIONAL
+ else if(sfile->type==FILE_LOADFONT) {
+ uiDefIconButBitS(block, TOG, FILE_SHOWSHORT, B_SORTFILELIST, ICON_FONTPREVIEW, xco+= XIC, 0, XIC, YIC, &sfile->f_fp, 0, 0, 0, 0, "Activate font preview");
+ if (sfile->f_fp)
+ uiDefButC(block, FTPREVIEW, 0, "Font preview", xco+= XIC, 0, 100, YIC, sfile->fp_str, (float)0, (float)16, 0, 0, "Font preview");
+
+ xco+= 100; // scroll
+ }
+ #endif
+
+ uiDrawBlock(block);
+
+ glRasterPos2f((float)xcotitle, 5.0);
+ BIF_RasterPos((float)xcotitle, 5.0); // stupid texture fonts
+ BIF_ThemeColor(TH_TEXT);
+ BIF_DrawString(uiBlockGetCurFont(block), sfile->title, (U.transopts & USER_TR_BUTTONS));
+
+ if(sfile->type==FILE_UNIX) {
+ df= BLI_diskfree(sfile->dir)/(1048576.0);
+
+ filesel_statistics(sfile, &totfile, &selfile, &totlen, &sellen);
+
+ sprintf(naam, "Free: %.3f MB Files: (%d) %d (%.3f) %.3f MB", df, selfile,totfile, sellen, totlen);
+
+ cpack(0x0);
+ glRasterPos2f((float)xco, 5.0);
+ BIF_RasterPos((float)xco, 5.0); // texture fonts
+
+ BIF_DrawString(G.font, naam, 0);
+ }
+
+ /* always do as last */
+ curarea->headbutlen= xco+2*XIC;
+}
diff --git a/source/blender/src/header_image.c b/source/blender/src/header_image.c
new file mode 100644
index 00000000000..5b8c33309a0
--- /dev/null
+++ b/source/blender/src/header_image.c
@@ -0,0 +1,1305 @@
+/**
+ * header_image.c oct-2003
+ *
+ * Functions to draw the "UV/Image Editor" window header
+ * and handle user events sent to it.
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "DNA_brush_types.h"
+#include "DNA_ID.h"
+#include "DNA_image_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_customdata_types.h" /* for UV layer menu */
+
+#include "BLI_blenlib.h"
+
+#include "BDR_drawmesh.h"
+#include "BDR_unwrapper.h"
+
+#include "BKE_brush.h"
+#include "BKE_colortools.h"
+#include "BKE_global.h"
+#include "BKE_image.h"
+#include "BKE_main.h"
+#include "BKE_utildefines.h"
+#include "BLI_editVert.h" /* for UV layer menu */
+#include "BKE_customdata.h" /* ditto */
+
+#include "BIF_butspace.h"
+#include "BIF_drawimage.h"
+#include "BIF_editsima.h"
+#include "BIF_imasel.h"
+#include "BIF_interface.h"
+#include "BIF_resources.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_transform.h"
+#include "BIF_toolbox.h"
+#include "BIF_editmesh.h"
+
+#include "BSE_drawview.h"
+#include "BSE_filesel.h"
+#include "BSE_headerbuttons.h"
+#include "BSE_trans_types.h"
+
+#include "BPY_extern.h"
+#include "BPY_menus.h"
+
+#include "IMB_imbuf_types.h"
+
+#include "RE_pipeline.h"
+
+#include "blendef.h"
+#include "butspace.h"
+#include "mydevice.h"
+
+void do_image_buttons(unsigned short event)
+{
+ ToolSettings *settings= G.scene->toolsettings;
+ ID *id, *idtest;
+ int nr;
+
+ if(curarea->win==0) return;
+
+ if(event<=100) {
+ if(event<=50) do_global_buttons2(event);
+ else do_global_buttons(event);
+ return;
+ }
+
+ switch(event) {
+ case B_SIMAPIN:
+ allqueue (REDRAWIMAGE, 0);
+ break;
+ case B_SIMAGEHOME:
+ image_home();
+ break;
+
+ case B_SIMABROWSE:
+ if(G.sima->imanr== -2) {
+ if(G.qual & LR_CTRLKEY) {
+ activate_databrowse_imasel((ID *)G.sima->image, ID_IM, 0, B_SIMABROWSE,
+ &G.sima->imanr, do_image_buttons);
+ } else {
+ activate_databrowse((ID *)G.sima->image, ID_IM, 0, B_SIMABROWSE,
+ &G.sima->imanr, do_image_buttons);
+ }
+ return;
+ }
+ if(G.sima->imanr < 0) break;
+
+ nr= 1;
+ id= (ID *)G.sima->image;
+
+ idtest= BLI_findlink(&G.main->image, G.sima->imanr-1);
+ if(idtest==NULL) { /* no new */
+ return;
+ }
+
+ if(idtest!=id) {
+ G.sima->image= (Image *)idtest;
+ if(idtest->us==0) idtest->us= 1;
+ BKE_image_signal(G.sima->image, &G.sima->iuser, IMA_SIGNAL_USER_NEW_IMAGE);
+ allqueue(REDRAWIMAGE, 0);
+ }
+ /* also when image is the same: assign! 0==no tileflag: */
+ image_changed(G.sima, (Image *)idtest);
+ BIF_undo_push("Assign image UV");
+
+ break;
+ case B_SIMAGETILE:
+ image_set_tile(G.sima, 1); /* 1: only tileflag */
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWIMAGE, 0);
+ break;
+ case B_SIMA3DVIEWDRAW:
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+ case B_SIMA_REDR_IMA_3D:
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWIMAGE, 0);
+ break;
+ case B_SIMAGEPAINTTOOL:
+ if(G.sima->flag & SI_DRAWTOOL)
+ /* add new brush if none exists */
+ brush_check_exists(&G.scene->toolsettings->imapaint.brush);
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWIMAGE, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+
+ case B_SIMAPACKIMA:
+ pack_image_sima();
+ break;
+
+ case B_SIMA_REPACK:
+ BKE_image_memorypack(G.sima->image);
+ allqueue(REDRAWIMAGE, 0);
+ break;
+
+ case B_SIMA_USE_ALPHA:
+ G.sima->flag &= ~(SI_SHOW_ALPHA|SI_SHOW_ZBUF);
+ scrarea_queue_winredraw(curarea);
+ scrarea_queue_headredraw(curarea);
+ break;
+ case B_SIMA_SHOW_ALPHA:
+ G.sima->flag &= ~(SI_USE_ALPHA|SI_SHOW_ZBUF);
+ scrarea_queue_winredraw(curarea);
+ scrarea_queue_headredraw(curarea);
+ break;
+ case B_SIMA_SHOW_ZBUF:
+ G.sima->flag &= ~(SI_SHOW_ALPHA|SI_USE_ALPHA);
+ scrarea_queue_winredraw(curarea);
+ scrarea_queue_headredraw(curarea);
+ break;
+ case B_SIMARELOAD:
+ reload_image_sima();
+ break;
+ case B_SIMAGELOAD:
+ open_image_sima(0);
+ break;
+ case B_SIMANAME:
+ if(G.sima->image) {
+ Image *ima;
+ char str[FILE_MAXDIR+FILE_MAXFILE];
+
+ /* name in ima has been changed by button! */
+ BLI_strncpy(str, G.sima->image->name, sizeof(str));
+ ima= BKE_add_image_file(str);
+ if(ima) {
+ BKE_image_signal(ima, &G.sima->iuser, IMA_SIGNAL_RELOAD);
+ image_changed(G.sima, ima);
+ }
+ BIF_undo_push("Load image");
+ allqueue(REDRAWIMAGE, 0);
+ }
+ break;
+ case B_SIMAMULTI:
+ if(G.sima && G.sima->image) {
+ BKE_image_multilayer_index(G.sima->image->rr, &G.sima->iuser);
+ allqueue(REDRAWIMAGE, 0);
+ }
+ break;
+ case B_TRANS_IMAGE:
+ image_editvertex_buts(NULL);
+ break;
+ case B_CURSOR_IMAGE:
+ image_editcursor_buts(NULL);
+ break;
+
+ case B_TWINANIM:
+ {
+ Image *ima;
+ int nr;
+
+ ima = G.sima->image;
+ if (ima) {
+ if(ima->flag & IMA_TWINANIM) {
+ nr= ima->xrep*ima->yrep;
+ if(ima->twsta>=nr) ima->twsta= 1;
+ if(ima->twend>=nr) ima->twend= nr-1;
+ if(ima->twsta>ima->twend) ima->twsta= 1;
+ allqueue(REDRAWIMAGE, 0);
+ }
+ }
+ break;
+ }
+ case B_SIMACLONEBROWSE:
+ if (settings->imapaint.brush)
+ if (brush_clone_image_set_nr(settings->imapaint.brush, G.sima->menunr))
+ allqueue(REDRAWIMAGE, 0);
+ break;
+
+ case B_SIMACLONEDELETE:
+ if (settings->imapaint.brush)
+ if (brush_clone_image_delete(settings->imapaint.brush))
+ allqueue(REDRAWIMAGE, 0);
+ break;
+
+ case B_SIMABRUSHCHANGE:
+ allqueue(REDRAWIMAGE, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ break;
+
+ case B_SIMACURVES:
+ curvemapping_do_ibuf(G.sima->cumap, imagewindow_get_ibuf(G.sima));
+ allqueue(REDRAWIMAGE, 0);
+ break;
+
+ case B_SIMARANGE:
+ curvemapping_set_black_white(G.sima->cumap, NULL, NULL);
+ curvemapping_do_ibuf(G.sima->cumap, imagewindow_get_ibuf(G.sima));
+ allqueue(REDRAWIMAGE, 0);
+ break;
+
+ case B_SIMABRUSHBROWSE:
+ if(G.sima->menunr==-2) {
+ activate_databrowse((ID*)settings->imapaint.brush, ID_BR, 0, B_SIMABRUSHBROWSE, &G.sima->menunr, do_global_buttons);
+ break;
+ }
+ else if(G.sima->menunr < 0) break;
+
+ if(brush_set_nr(&settings->imapaint.brush, G.sima->menunr)) {
+ BIF_undo_push("Browse Brush");
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWIMAGE, 0);
+ }
+ break;
+ case B_SIMABRUSHDELETE:
+ if(brush_delete(&settings->imapaint.brush)) {
+ BIF_undo_push("Unlink Brush");
+ allqueue(REDRAWIMAGE, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ }
+ break;
+ case B_KEEPDATA:
+ brush_toggle_fake_user(settings->imapaint.brush);
+ allqueue(REDRAWIMAGE, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ break;
+ case B_SIMABRUSHLOCAL:
+ if(settings->imapaint.brush && settings->imapaint.brush->id.lib) {
+ if(okee("Make local")) {
+ make_local_brush(settings->imapaint.brush);
+ allqueue(REDRAWIMAGE, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ }
+ }
+ break;
+ case B_SIMABTEXBROWSE:
+ if(settings->imapaint.brush) {
+ Brush *brush= settings->imapaint.brush;
+
+ if(G.sima->menunr==-2) {
+ MTex *mtex= brush->mtex[brush->texact];
+ ID *id= (ID*)((mtex)? mtex->tex: NULL);
+ if(G.qual & LR_CTRLKEY) {
+ activate_databrowse_imasel(id, ID_TE, 0, B_SIMABTEXBROWSE, &G.sima->menunr, do_image_buttons);
+ } else {
+ activate_databrowse(id, ID_TE, 0, B_SIMABTEXBROWSE, &G.sima->menunr, do_image_buttons);
+ }
+ break;
+ }
+ else if(G.sima->menunr < 0) break;
+
+ if(brush_texture_set_nr(brush, G.sima->menunr)) {
+ BIF_undo_push("Browse Brush Texture");
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWIMAGE, 0);
+ }
+ }
+ break;
+ case B_SIMABTEXDELETE:
+ if(settings->imapaint.brush) {
+ if (brush_texture_delete(settings->imapaint.brush)) {
+ BIF_undo_push("Unlink Brush Texture");
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWIMAGE, 0);
+ }
+ }
+ break;
+ case B_SIMA_PLAY:
+ play_anim(0);
+ break;
+ case B_SIMA_RECORD:
+ imagespace_composite_flipbook(curarea);
+ break;
+ }
+}
+
+static void do_image_buttons_set_uvlayer_callback(void *act, void *data)
+{
+ CustomData_set_layer_active(&G.editMesh->fdata, CD_MTFACE, *((int *)act));
+
+ BIF_undo_push("Set Active UV Texture");
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWIMAGE, 0);
+}
+
+static void do_image_view_viewnavmenu(void *arg, int event)
+{
+ switch(event) {
+ case 1: /* Zoom In */
+ image_viewzoom(PADPLUSKEY, 0);
+ break;
+ case 2: /* Zoom Out */
+ image_viewzoom(PADMINUS, 0);
+ break;
+ case 3: /* Zoom 8:1 */
+ image_viewzoom(PAD8, 0);
+ break;
+ case 4: /* Zoom 4:1 */
+ image_viewzoom(PAD4, 0);
+ break;
+ case 5: /* Zoom 2:1 */
+ image_viewzoom(PAD2, 0);
+ break;
+ case 6: /* Zoom 1:1 */
+ image_viewzoom(PAD1, 0);
+ break;
+ case 7: /* Zoom 1:2 */
+ image_viewzoom(PAD2, 1);
+ break;
+ case 8: /* Zoom 1:4 */
+ image_viewzoom(PAD4, 1);
+ break;
+ case 9: /* Zoom 1:8 */
+ image_viewzoom(PAD8, 1);
+ break;
+ }
+ allqueue(REDRAWIMAGE, 0);
+}
+
+static uiBlock *image_view_viewnavmenu(void *arg_unused)
+{
+/* static short tog=0; */
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "image_view_viewnavmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_image_view_viewnavmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Zoom In|NumPad +", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Zoom Out|NumPad -", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Zoom 1:8|Shift+NumPad 8", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Zoom 1:4|Shift+NumPad 4", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Zoom 1:2|Shift+NumPad 2", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 5, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Zoom 1:1|NumPad 1", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 6, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Zoom 2:1|NumPad 2", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 7, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Zoom 4:1|NumPad 4", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 8, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Zoom 8:1|NumPad 8", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 9, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 50);
+ return block;
+}
+
+static void do_image_viewmenu(void *arg, int event)
+{
+
+ switch(event) {
+ case 0: /* Update Automatically */
+ if(G.sima->lock) G.sima->lock = 0;
+ else G.sima->lock = 1;
+ break;
+ case 1: /* View All */
+ do_image_buttons(B_SIMAGEHOME);
+ break;
+ case 2: /* Maximize Window */
+ /* using event B_FULL */
+ break;
+ case 4: /* Realtime Panel... */
+ add_blockhandler(curarea, IMAGE_HANDLER_VIEW_PROPERTIES, UI_PNL_UNSTOW);
+ break;
+ case 5: /* Draw Shadow Mesh */
+ G.sima->flag ^= SI_DRAWSHADOW;
+ allqueue(REDRAWIMAGE, 0);
+ break;
+ case 6: /* Draw Faces */
+ G.f ^= G_DRAWFACES;
+ allqueue(REDRAWIMAGE, 0);
+ break;
+ case 7: /* Properties Panel */
+ add_blockhandler(curarea, IMAGE_HANDLER_PROPERTIES, UI_PNL_UNSTOW);
+ break;
+ case 8: /* Paint Panel... */
+ add_blockhandler(curarea, IMAGE_HANDLER_PAINT, UI_PNL_UNSTOW);
+ break;
+ case 9:
+ image_viewcenter();
+ case 10: /* Display Normalized Coordinates */
+ G.sima->flag ^= SI_COORDFLOATS;
+ allqueue(REDRAWIMAGE, 0);
+ break;
+ case 11: /* Curves Panel... */
+ add_blockhandler(curarea, IMAGE_HANDLER_CURVES, UI_PNL_UNSTOW);
+ break;
+ case 12: /* composite preview */
+ toggle_blockhandler(curarea, IMAGE_HANDLER_PREVIEW, 0);
+ scrarea_queue_winredraw(curarea);
+ break;
+ case 13: /* Realtime Panel... */
+ add_blockhandler(curarea, IMAGE_HANDLER_GAME_PROPERTIES, UI_PNL_UNSTOW);
+ break;
+ case 14: /* Draw active image UV's only*/
+ G.sima->flag ^= SI_LOCAL_UV;
+ allqueue(REDRAWIMAGE, 0);
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *image_viewmenu(void *arg_unused)
+{
+/* static short tog=0; */
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "image_viewmenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_image_viewmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_MENU_PANEL, "View Properties...", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_MENU_PANEL, "Image Properties...|N", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 7, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_MENU_PANEL, "Real-time Properties...", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 13, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_MENU_PANEL, "Paint Tool...|C", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 8, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_MENU_PANEL, "Curves Tool...", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 11, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_MENU_PANEL, "Composite Preview...|Shift P", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 12, "");
+
+ if(G.sima->flag & SI_COORDFLOATS) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Display Normalized Coordinates|", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 10, "");
+ else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Display Normalized Coordinates|", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 10, "");
+ if(G.f & G_DRAWFACES) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Draw Faces", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 6, "");
+ else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Draw Faces|", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 6, "");
+ if(G.sima->flag & SI_DRAWSHADOW) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Draw Shadow Mesh", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 5, "");
+ else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Draw Shadow Mesh|", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 5, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ if(G.sima->flag & SI_LOCAL_UV) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "UV Local View|NumPad /", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 14, "");
+ else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "UV Local View|NumPad /", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 14, "");
+ if(!(G.sima->flag & SI_LOCAL_UV)) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "UV Global View|NumPad /", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 14, "");
+ else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "UV Global View|NumPad /", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 14, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBlockBut(block, image_view_viewnavmenu, NULL, ICON_RIGHTARROW_THIN, "View Navigation", 0, yco-=20, 120, 19, "");
+
+ if(G.sima->lock) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Update Automatically|", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+ } else {
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Update Automatically|", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+ }
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "View Selected|NumPad .", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 9, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "View All|Home", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+
+ if(!curarea->full) uiDefIconTextBut(block, BUTM, B_FULL, ICON_BLANK1, "Maximize Window|Ctrl UpArrow", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
+ else uiDefIconTextBut(block, BUTM, B_FULL, ICON_BLANK1, "Tile Window|Ctrl DownArrow", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+static void do_image_selectmenu(void *arg, int event)
+{
+ switch(event)
+ {
+ case 0: /* Border Select */
+ borderselect_sima(UV_SELECT_ALL);
+ break;
+ case 8: /* Border Select Pinned */
+ borderselect_sima(UV_SELECT_PINNED);
+ break;
+ case 1: /* Select/Deselect All */
+ select_swap_tface_uv();
+ break;
+ case 9: /* Select Inverse */
+ select_invert_tface_uv();
+ break;
+ case 2: /* Unlink Selection */
+ unlink_selection();
+ break;
+ case 3: /* Linked UVs */
+ select_linked_tface_uv(2);
+ break;
+ case 6: /* Toggle Active Face Select */
+ if(G.sima->flag & SI_SELACTFACE)
+ G.sima->flag &= ~SI_SELACTFACE;
+ else
+ G.sima->flag |= SI_SELACTFACE;
+ allqueue(REDRAWIMAGE, 0);
+ break;
+ case 7: /* Pinned UVs */
+ select_pinned_tface_uv();
+ break;
+ }
+}
+
+static uiBlock *image_selectmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "image_selectmenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_image_selectmenu, NULL);
+
+
+ if ((G.sima->flag & SI_SYNC_UVSEL)==0 || (G.sima->flag & SI_SYNC_UVSEL && (G.scene->selectmode != SCE_SELECT_FACE))) {
+ if(G.sima->flag & SI_SELACTFACE) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Active Face Select|C", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 6, "");
+ else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Active Face Select|C", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 6, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+ }
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Border Select|B", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Border Select Pinned|Shift B", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 8, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select/Deselect All|A", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Inverse", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 9, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Unlink Selection|Alt L", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Pinned UVs|Shift P", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 7, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Linked UVs|Ctrl L", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+static void do_image_image_rtmappingmenu(void *arg, int event)
+{
+ switch(event) {
+ case 0: /* UV Co-ordinates */
+ G.sima->image->flag &= ~IMA_REFLECT;
+ break;
+ case 1: /* Reflection */
+ G.sima->image->flag |= IMA_REFLECT;
+ break;
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *image_image_rtmappingmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "image_image_rtmappingmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_image_image_rtmappingmenu, NULL);
+
+ if (G.sima->image->flag & IMA_REFLECT) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "UV Co-ordinates", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Reflection", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ } else {
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "UV Co-ordinates", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Reflection", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ }
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+static void do_image_imagemenu(void *arg, int event)
+{
+ /* events >=20 are registered bpython scripts */
+ if (event >= 20) BPY_menu_do_python(PYMENU_IMAGE, event - 20);
+
+ switch(event)
+ {
+ case 0:
+ open_image_sima((G.qual==LR_CTRLKEY));
+ break;
+ case 1:
+ replace_image_sima((G.qual==LR_CTRLKEY));
+ break;
+ case 2:
+ pack_image_sima();
+ break;
+ case 4: /* Texture Painting */
+ brush_check_exists(&G.scene->toolsettings->imapaint.brush);
+ if(G.sima->flag & SI_DRAWTOOL) G.sima->flag &= ~SI_DRAWTOOL;
+ else G.sima->flag |= SI_DRAWTOOL;
+ allqueue(REDRAWBUTSSHADING, 0);
+ break;
+ case 5:
+ save_as_image_sima();
+ break;
+ case 6:
+ reload_image_sima();
+ break;
+ case 7:
+ new_image_sima();
+ break;
+ case 8:
+ save_image_sima();
+ break;
+ case 9:
+ save_image_sequence_sima();
+ break;
+ case 10:
+ BKE_image_memorypack(G.sima->image);
+ allqueue(REDRAWIMAGE, 0);
+ break;
+ }
+}
+
+static uiBlock *image_imagemenu(void *arg_unused)
+{
+ ImBuf *ibuf= BKE_image_get_ibuf(G.sima->image, &G.sima->iuser);
+ uiBlock *block;
+ short yco= 0, menuwidth=150;
+ BPyMenu *pym;
+ int i = 0;
+
+ block= uiNewBlock(&curarea->uiblocks, "image_imagemenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_image_imagemenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "New...|Alt N", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 7, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Open...|Alt O", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 0, "");
+
+ if (G.sima->image) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Replace...", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Reload|Alt R", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 6, "");
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Save|Alt S", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 8, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Save As...", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 5, "");
+ if(G.sima->image->source==IMA_SRC_SEQUENCE)
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Save Changed Images", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 9, "");
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ if (G.sima->image->packedfile) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Unpack Image...", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
+ } else {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Pack Image", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
+ }
+
+ /* only for dirty && specific image types */
+ if(ibuf && (ibuf->userflags & IB_BITMAPDIRTY))
+ if( ELEM(G.sima->image->source, IMA_SRC_FILE, IMA_SRC_GENERATED))
+ if(G.sima->image->type!=IMA_TYPE_MULTILAYER)
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Pack Image as PNG", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 10, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=7, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ if(G.sima->flag & SI_DRAWTOOL) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Texture Painting", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
+ } else {
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Texture Painting", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
+ }
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=7, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBlockBut(block, image_image_rtmappingmenu, NULL, ICON_RIGHTARROW_THIN, "Realtime Texture Mapping", 0, yco-=20, 120, 19, "");
+ // uiDefIconTextBut(block, BUTM, 1, ICON_MENU_PANEL, "Realtime Texture Animation|", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 7, "");
+ }
+
+ /* note that we acount for the N previous entries with i+20: */
+ for (pym = BPyMenuTable[PYMENU_IMAGE]; pym; pym = pym->next, i++) {
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_PYTHON, pym->name, 0, yco-=20, menuwidth, 19,
+ NULL, 0.0, 0.0, 1, i+20,
+ pym->tooltip?pym->tooltip:pym->filename);
+ }
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 80);
+
+ return block;
+}
+
+static void do_image_uvs_showhidemenu(void *arg, int event)
+{
+ switch(event) {
+ case 4: /* show hidden faces */
+ reveal_tface_uv();
+ break;
+ case 5: /* hide selected faces */
+ hide_tface_uv(0);
+ break;
+ case 6: /* hide deselected faces */
+ hide_tface_uv(1);
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *image_uvs_showhidemenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "image_uvs_showhidemenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_image_uvs_showhidemenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Show Hidden Faces|Alt H", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Hide Selected Faces|H", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Hide Deselected Faces|Shift H", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 6, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+static void do_image_uvs_propfalloffmenu(void *arg, int event)
+{
+ G.scene->prop_mode= event;
+ allqueue(REDRAWVIEW3D, 1);
+}
+
+static uiBlock *image_uvs_propfalloffmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "image_uvs_propfalloffmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_image_uvs_propfalloffmenu, NULL);
+
+ if (G.scene->prop_mode==PROP_SMOOTH) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Smooth|Shift O", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, PROP_SMOOTH, "");
+ else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Smooth|Shift O", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, PROP_SMOOTH, "");
+ if (G.scene->prop_mode==PROP_SPHERE) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Sphere|Shift O", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, PROP_SPHERE, "");
+ else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Sphere|Shift O", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, PROP_SPHERE, "");
+ if (G.scene->prop_mode==PROP_ROOT) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Root|Shift O", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, PROP_ROOT, "");
+ else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Root|Shift O", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, PROP_ROOT, "");
+ if (G.scene->prop_mode==PROP_SHARP) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Sharp|Shift O", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, PROP_SHARP, "");
+ else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Sharp|Shift O", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, PROP_SHARP, "");
+ if (G.scene->prop_mode==PROP_LIN) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Linear|Shift O", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, PROP_LIN, "");
+ else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Linear|Shift O", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, PROP_LIN, "");
+ if (G.scene->prop_mode==PROP_CONST) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Constant|Shift O", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, PROP_CONST, "");
+ else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Constant|Shift O", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, PROP_CONST, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+static void do_image_uvs_transformmenu(void *arg, int event)
+{
+ switch(event) {
+ case 0: /* Grab */
+ initTransform(TFM_TRANSLATION, CTX_NONE);
+ Transform();
+ break;
+ case 1: /* Rotate */
+ initTransform(TFM_ROTATION, CTX_NONE);
+ Transform();
+ break;
+ case 2: /* Scale */
+ initTransform(TFM_RESIZE, CTX_NONE);
+ Transform();
+ break;
+ }
+}
+
+static uiBlock *image_uvs_transformmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "image_uvs_transformmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_image_uvs_transformmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Grab/Move|G", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Rotate|R", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Scale|S", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+static void do_image_uvs_mirrormenu(void *arg, int event)
+{
+ switch(event) {
+ case 0: /* X axis */
+ mirror_tface_uv('x');
+ break;
+ case 1: /* Y axis */
+ mirror_tface_uv('y');
+ break;
+ }
+
+ BIF_undo_push("Mirror UV");
+}
+
+static uiBlock *image_uvs_mirrormenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "image_uvs_mirrormenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_image_uvs_mirrormenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "X Axis|M, 1", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Y Axis|M, 2", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+static void do_image_uvs_weldalignmenu(void *arg, int event)
+{
+ switch(event) {
+ case 0: /* Weld */
+ weld_align_tface_uv('w');
+ break;
+ case 1: /* Align X */
+ weld_align_tface_uv('x');
+ break;
+ case 2: /* Align Y */
+ weld_align_tface_uv('y');
+ break;
+ }
+
+ if(event==0) BIF_undo_push("Weld UV");
+ else if(event==1 || event==2) BIF_undo_push("Align UV");
+}
+
+static uiBlock *image_uvs_weldalignmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "image_uvs_weldalignmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_image_uvs_weldalignmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Weld|W, 1", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Align X|W, 2", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Align Y|W, 3", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+static void do_image_uvs_scriptsmenu(void *arg, int event)
+{
+ BPY_menu_do_python(PYMENU_UV, event);
+
+ allqueue(REDRAWIMAGE, 0);
+}
+
+static uiBlock *image_uvs_scriptsmenu (void *args_unused)
+{
+ uiBlock *block;
+ BPyMenu *pym;
+ int i= 0;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "image_uvs_scriptsmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_image_uvs_scriptsmenu, NULL);
+
+ /* note that we acount for the N previous entries with i+20: */
+ for (pym = BPyMenuTable[PYMENU_UV]; pym; pym = pym->next, i++) {
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_PYTHON, pym->name, 0, yco-=20, menuwidth, 19,
+ NULL, 0.0, 0.0, 1, i,
+ pym->tooltip?pym->tooltip:pym->filename);
+ }
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+
+ return block;
+}
+
+static void do_image_uvsmenu(void *arg, int event)
+{
+
+ switch(event) {
+// case 0: /* UV Transform Properties Panel... */
+// add_blockhandler(curarea, IMAGE_HANDLER_TRANSFORM_PROPERTIES, UI_PNL_UNSTOW);
+// break;
+ case 1: /* UVs Constrained Rectangular */
+ if(G.sima->flag & SI_BE_SQUARE) G.sima->flag &= ~SI_BE_SQUARE;
+ else G.sima->flag |= SI_BE_SQUARE;
+ break;
+ case 2: /* UVs Clipped to Image Size */
+ if(G.sima->flag & SI_CLIP_UV) G.sima->flag &= ~SI_CLIP_UV;
+ else G.sima->flag |= SI_CLIP_UV;
+ break;
+ case 3: /* Limit Stitch UVs */
+ stitch_limit_uv_tface();
+ break;
+ case 4: /* Stitch UVs */
+ stitch_vert_uv_tface();
+ break;
+ case 5: /* Proportional Edit (toggle) */
+ if(G.scene->proportional)
+ G.scene->proportional= 0;
+ else
+ G.scene->proportional= 1;
+ break;
+ case 7: /* UVs Snap to Pixel */
+ G.sima->flag ^= SI_PIXELSNAP;
+ break;
+ case 8:
+ pin_tface_uv(1);
+ break;
+ case 9:
+ pin_tface_uv(0);
+ break;
+ case 10:
+ unwrap_lscm(0);
+ break;
+ case 11:
+ if(G.sima->flag & SI_LIVE_UNWRAP) G.sima->flag &= ~SI_LIVE_UNWRAP;
+ else G.sima->flag |= SI_LIVE_UNWRAP;
+ break;
+ case 12:
+ minimize_stretch_tface_uv();
+ break;
+ case 13:
+ pack_charts_tface_uv();
+ break;
+ }
+}
+
+static uiBlock *image_uvsmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "image_uvsmenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_image_uvsmenu, NULL);
+
+ //uiDefIconTextBut(block, BUTM, 1, ICON_MENU_PANEL, "Transform Properties...|N", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+ if(G.sima->flag & SI_PIXELSNAP) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Snap to Pixels|", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 7, "");
+ else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Snap to Pixels|", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 7, "");
+
+ if(G.sima->flag & SI_BE_SQUARE) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Quads Constrained Rectangular|", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
+ else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Quads Constrained Rectangular|", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
+
+ if(G.sima->flag & SI_CLIP_UV) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Layout Clipped to Image Size|", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
+ else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Layout Clipped to Image Size|", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ if(G.sima->flag & SI_LIVE_UNWRAP) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Live Unwrap Transform", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 11, "");
+ else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Live Unwrap Transform", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 11, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Unwrap|E", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 10, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Unpin|Alt P", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 9, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Pin|P", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 8, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Pack Charts|Ctrl P", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 13, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Minimize Stretch|Ctrl V", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 12, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Limit Stitch...|Shift V", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Stitch|V", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBlockBut(block, image_uvs_transformmenu, NULL, ICON_RIGHTARROW_THIN, "Transform", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, image_uvs_mirrormenu, NULL, ICON_RIGHTARROW_THIN, "Mirror", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, image_uvs_weldalignmenu, NULL, ICON_RIGHTARROW_THIN, "Weld/Align", 0, yco-=20, 120, 19, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ if(G.scene->proportional)
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Proportional Editing|O", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+ else
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Proportional Editing|O", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+
+ uiDefIconTextBlockBut(block, image_uvs_propfalloffmenu, NULL, ICON_RIGHTARROW_THIN, "Proportional Falloff", 0, yco-=20, 120, 19, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBlockBut(block, image_uvs_showhidemenu, NULL, ICON_RIGHTARROW_THIN, "Show/Hide Faces", 0, yco-=20, menuwidth, 19, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBlockBut(block, image_uvs_scriptsmenu, NULL, ICON_RIGHTARROW_THIN, "Scripts", 0, yco-=20, 120, 19, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+void image_buttons(void)
+{
+ Image *ima;
+ ImBuf *ibuf;
+ uiBlock *block;
+ short xco, xmax;
+ char naam[256], *menuname;
+ char is_render; /* true if the image is a render or composite */
+
+ int allow_pin= B_SIMAPIN;
+
+ /* This should not be a static var */
+ static int headerbuttons_packdummy;
+
+
+ is_render = ((G.sima->image!=NULL) && ((G.sima->image->type == IMA_TYPE_R_RESULT) || (G.sima->image->type == IMA_TYPE_COMPOSITE)));
+
+ headerbuttons_packdummy = 0;
+
+ sprintf(naam, "header %d", curarea->headwin);
+ block= uiNewBlock(&curarea->uiblocks, naam, UI_EMBOSS, UI_HELV, curarea->headwin);
+
+ if(area_is_active_area(curarea)) uiBlockSetCol(block, TH_HEADER);
+ else uiBlockSetCol(block, TH_HEADERDESEL);
+
+ what_image(G.sima);
+ ima= G.sima->image;
+ ibuf= BKE_image_get_ibuf(ima, &G.sima->iuser);
+
+ curarea->butspacetype= SPACE_IMAGE;
+
+ xco = 8;
+ uiDefIconTextButC(block, ICONTEXTROW,B_NEWSPACE, ICON_VIEW3D, windowtype_pup(), xco,0,XIC+10,YIC, &(curarea->butspacetype), 1.0, SPACEICONMAX, 0, 0, "Current Window Type. Click for menu of available types.");
+ xco+= XIC+14;
+
+ uiBlockSetEmboss(block, UI_EMBOSSN);
+ if(curarea->flag & HEADER_NO_PULLDOWN) {
+ uiDefIconButBitS(block, TOG, HEADER_NO_PULLDOWN, B_FLIPINFOMENU, ICON_DISCLOSURE_TRI_RIGHT,
+ xco,2,XIC,YIC-2,
+ &(curarea->flag), 0, 0, 0, 0, "Show pulldown menus");
+ } else {
+ uiDefIconButBitS(block, TOG, HEADER_NO_PULLDOWN, B_FLIPINFOMENU, ICON_DISCLOSURE_TRI_DOWN,
+ xco,2,XIC,YIC-2,
+ &(curarea->flag), 0, 0, 0, 0, "Hide pulldown menus");
+ }
+ uiBlockSetEmboss(block, UI_EMBOSS);
+ xco+=XIC;
+
+ if((curarea->flag & HEADER_NO_PULLDOWN)==0) {
+
+ /* pull down menus */
+ uiBlockSetEmboss(block, UI_EMBOSSP);
+
+ xmax= GetButStringLength("View");
+ uiDefPulldownBut(block, image_viewmenu, NULL, "View", xco, -2, xmax-3, 24, "");
+ xco+= xmax;
+
+ if((EM_texFaceCheck()) && !(ima && (G.sima->flag & SI_DRAWTOOL))) {
+ xmax= GetButStringLength("Select");
+ uiDefPulldownBut(block, image_selectmenu, NULL, "Select", xco, -2, xmax-3, 24, "");
+ xco+= xmax;
+ }
+
+ if (ibuf && (ibuf->userflags & IB_BITMAPDIRTY))
+ menuname= "Image*";
+ else
+ menuname= "Image";
+ xmax= GetButStringLength(menuname);
+ uiDefPulldownBut(block, image_imagemenu, NULL, menuname, xco, -2, xmax-3, 24, "");
+ xco+= xmax;
+ if((EM_texFaceCheck()) && !(ima && (G.sima->flag & SI_DRAWTOOL))) {
+ xmax= GetButStringLength("UVs");
+ uiDefPulldownBut(block, image_uvsmenu, NULL, "UVs", xco, -2, xmax-3, 24, "");
+ xco+= xmax;
+ }
+ }
+
+ /* other buttons: */
+ uiBlockSetEmboss(block, UI_EMBOSS);
+
+ if (is_render)
+ allow_pin = 0;
+
+ xco= 8 + std_libbuttons(block, xco, 0, allow_pin, &G.sima->pin, B_SIMABROWSE, ID_IM, 0, (ID *)ima, 0, &(G.sima->imanr), 0, 0, B_IMAGEDELETE, 0, 0);
+
+ if( ima && !ELEM3(ima->source, IMA_SRC_SEQUENCE, IMA_SRC_MOVIE, IMA_SRC_VIEWER) && ima->ok) {
+
+ if (ima->packedfile) {
+ headerbuttons_packdummy = 1;
+ }
+ if (ima->packedfile && ibuf && (ibuf->userflags & IB_BITMAPDIRTY))
+ uiDefIconButBitI(block, TOG, 1, B_SIMA_REPACK, ICON_UGLYPACKAGE, xco,0,XIC,YIC, &headerbuttons_packdummy, 0, 0, 0, 0, "Re-Pack this image as PNG");
+ else
+ uiDefIconButBitI(block, TOG, 1, B_SIMAPACKIMA, ICON_PACKAGE, xco,0,XIC,YIC, &headerbuttons_packdummy, 0, 0, 0, 0, "Pack/Unpack this image");
+
+ xco+= XIC+8;
+ }
+
+ /* UV EditMode buttons, not painting or rencering or compositing */
+ if ( EM_texFaceCheck() && (G.sima->flag & SI_DRAWTOOL)==0 && !is_render) {
+ uiBut *ubut;
+ int layercount;
+
+ uiDefIconTextButS(block, ICONTEXTROW, B_NOP, ICON_ROTATE,
+ "Pivot: %t|Bounding Box Center %x0|Median Point %x3|2D Cursor %x1",
+ xco,0,XIC+10,YIC, &(G.v2d->around), 0, 3.0, 0, 0,
+ "Rotation/Scaling Pivot (Hotkeys: Comma, Shift Comma, Period)");
+ xco+= XIC + 18;
+
+ uiBlockBeginAlign(block);
+ uiDefIconButBitI(block, TOGN, SI_SYNC_UVSEL, B_REDR, ICON_NO_GO_LEFT, xco,0,XIC,YIC, &G.sima->flag, 0, 0, 0, 0, "Mesh independant selection");
+ xco+= XIC;
+ if ((G.sima->flag & SI_SYNC_UVSEL)==0) {
+
+ /* would use these if const's could go in strings
+ * SI_STICKY_LOC SI_STICKY_DISABLE SI_STICKY_VERTEX */
+ ubut = uiDefIconTextButC(block, ICONTEXTROW, B_REDR, ICON_STICKY_UVS_LOC,
+ "Sticky UV Selection: %t|Disable%x1|Shared Location%x0|Shared Vertex%x2",
+ xco,0,XIC+10,YIC, &(G.sima->sticky), 0, 3.0, 0, 0,
+ "Sticky UV Selection (Hotkeys: Shift C, Alt C, Ctrl C)");
+ xco+= XIC + 16;
+
+ } else {
+ xco+= 6;
+ }
+ uiBlockEndAlign(block);
+
+ /* Snap copied right out of view3d header */
+ uiBlockBeginAlign(block);
+
+ if (G.scene->snap_flag & SCE_SNAP) {
+ uiDefIconButBitS(block, TOG, SCE_SNAP, B_REDR, ICON_SNAP_GEO,xco,0,XIC,YIC, &G.scene->snap_flag, 0, 0, 0, 0, "Use Snap or Grid (Shift Tab)");
+ xco+= XIC;
+ uiDefButS(block, MENU, B_NOP, "Mode%t|Closest%x0|Center%x1|Median%x2",xco,0,70,YIC, &G.scene->snap_target, 0, 0, 0, 0, "Snap Target Mode");
+ xco+= 70;
+ } else {
+ uiDefIconButBitS(block, TOG, SCE_SNAP, B_REDR, ICON_SNAP_GEAR,xco,0,XIC,YIC, &G.scene->snap_flag, 0, 0, 0, 0, "Snap while Ctrl is held during transform (Shift Tab)");
+ xco+= XIC;
+ }
+
+ uiBlockEndAlign(block);
+ xco+= 10;
+ /* end snap */
+
+ /* Layer Menu */
+ layercount = CustomData_number_of_layers(&G.editMesh->fdata, CD_MTFACE);
+ if (layercount>1 && layercount < 12) { /* could allow any number but limit of 11 means no malloc needed */
+ static int act;
+ char str_menu[384], *str_pt; /*384 allows for 11 layers */
+
+
+ act = CustomData_get_active_layer(&G.editMesh->fdata, CD_MTFACE);
+
+ /*str_pt = (char *)MEM_mallocN(layercount*40 , "uvmenu"); str[0]='\0';*/
+ str_pt = str_menu;
+ str_pt[0]='\0';
+ mesh_layers_menu_concat(&G.editMesh->fdata, CD_MTFACE, str_pt);
+ ubut = uiDefButI(block, MENU, B_NOP, str_menu ,xco,0,85,YIC, &act, 0, 0, 0, 0, "Active UV Layer for editing");
+ uiButSetFunc(ubut, do_image_buttons_set_uvlayer_callback, &act, NULL);
+
+ /*MEM_freeN(str);*/
+ xco+= 90;
+ }
+ }
+
+ if (ima) {
+ RenderResult *rr= BKE_image_get_renderresult(ima);
+
+ xco+= 8;
+
+ if(rr) {
+ uiBlockBeginAlign(block);
+ uiblock_layer_pass_buttons(block, rr, &G.sima->iuser, B_REDR, xco, 0, 160);
+ uiBlockEndAlign(block);
+ xco+= 166;
+ }
+ uiDefIconButBitI(block, TOG, SI_DRAWTOOL, B_SIMAGEPAINTTOOL, ICON_TPAINT_HLT, xco,0,XIC,YIC, &G.sima->flag, 0, 0, 0, 0, "Enables painting textures on the image with left mouse button");
+
+ xco+= XIC+8;
+
+ uiBlockBeginAlign(block);
+ if(ibuf==NULL || ibuf->channels==4) {
+ uiDefIconButBitI(block, TOG, SI_USE_ALPHA, B_SIMA_USE_ALPHA, ICON_TRANSP_HLT, xco,0,XIC,YIC, &G.sima->flag, 0, 0, 0, 0, "Draws image with alpha");
+ xco+= XIC;
+ uiDefIconButBitI(block, TOG, SI_SHOW_ALPHA, B_SIMA_SHOW_ALPHA, ICON_DOT, xco,0,XIC,YIC, &G.sima->flag, 0, 0, 0, 0, "Draws only alpha");
+ xco+= XIC;
+ }
+ if(ibuf) {
+ if(ibuf->zbuf || ibuf->zbuf_float || (ibuf->channels==1)) {
+ uiDefIconButBitI(block, TOG, SI_SHOW_ZBUF, B_SIMA_SHOW_ZBUF, ICON_SOLID, xco,0,XIC,YIC, &G.sima->flag, 0, 0, 0, 0, "Draws zbuffer values");
+ xco+= XIC;
+ }
+ }
+ xco+= 8;
+
+ uiBlockBeginAlign(block);
+ if(ima->type==IMA_TYPE_COMPOSITE) {
+ uiDefIconBut(block, BUT, B_SIMA_RECORD, ICON_REC, xco, 0, XIC, YIC, 0, 0, 0, 0, 0, "Record Composite");
+ xco+= XIC;
+ }
+ if((ima->type==IMA_TYPE_COMPOSITE) || ELEM(ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) {
+ uiDefIconBut(block, BUT, B_SIMA_PLAY, ICON_PLAY, xco, 0, XIC, YIC, 0, 0, 0, 0, 0, "Play");
+ xco+= XIC;
+ }
+ uiBlockEndAlign(block);
+ xco+= 8;
+ }
+
+ /* draw LOCK */
+ uiDefIconButS(block, ICONTOG, 0, ICON_UNLOCKED, xco,0,XIC,YIC, &(G.sima->lock), 0, 0, 0, 0, "Updates other affected window spaces automatically to reflect changes in real time");
+
+ /* Always do this last */
+ curarea->headbutlen= xco+2*XIC;
+
+ uiDrawBlock(block);
+}
+
diff --git a/source/blender/src/header_imasel.c b/source/blender/src/header_imasel.c
new file mode 100644
index 00000000000..1402e8c244e
--- /dev/null
+++ b/source/blender/src/header_imasel.c
@@ -0,0 +1,211 @@
+/**
+ * header_imasel.c oct-2003
+ *
+ * Functions to draw the "Image Browser" window header
+ * and handle user events sent to it.
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "BMF_Api.h"
+
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_utildefines.h"
+
+#include "DNA_ID.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BIF_filelist.h"
+#include "BIF_gl.h"
+#include "BIF_imasel.h"
+#include "BIF_interface.h"
+#include "BIF_language.h"
+#include "BIF_resources.h"
+#include "BIF_screen.h"
+#include "BSE_headerbuttons.h"
+
+#include "blendef.h"
+
+
+void do_imasel_buttons(short event)
+{
+ SpaceImaSel *simasel;
+
+ simasel= curarea->spacedata.first;
+
+ if(curarea->win==0) return;
+
+ switch(event) {
+ case B_SORTIMASELLIST:
+ BIF_filelist_sort(simasel->files, simasel->sort);
+ scrarea_queue_winredraw(curarea);
+ break;
+
+ case B_RELOADIMASELDIR:
+ BIF_filelist_free(simasel->files);
+ scrarea_queue_winredraw(curarea);
+ break;
+ case B_FILTERIMASELDIR:
+ if (simasel->flag & FILE_FILTER) {
+ BIF_filelist_setfilter(simasel->files,simasel->filter);
+ BIF_filelist_filter(simasel->files);
+ scrarea_queue_winredraw(curarea);
+ } else {
+ BIF_filelist_setfilter(simasel->files,0);
+ BIF_filelist_filter(simasel->files);
+ scrarea_queue_winredraw(curarea);
+ }
+ break;
+ }
+}
+
+void imasel_buttons(void)
+{
+ SpaceImaSel *simasel;
+ uiBlock *block;
+ short xco, xcotitle;
+ char naam[256];
+ char dir[FILE_MAXDIR], group[32];
+ short type;
+ int do_filter = 0;
+
+ simasel= curarea->spacedata.first;
+
+ sprintf(naam, "header %d", curarea->headwin);
+ block= uiNewBlock(&curarea->uiblocks, naam, UI_EMBOSS, UI_HELV, curarea->headwin);
+
+ if(area_is_active_area(curarea)) uiBlockSetCol(block, TH_HEADER);
+ else uiBlockSetCol(block, TH_HEADERDESEL);
+
+ curarea->butspacetype= SPACE_IMASEL;
+
+ xco = 8;
+
+ uiDefIconTextButC(block, ICONTEXTROW,B_NEWSPACE, ICON_VIEW3D, windowtype_pup(), xco,0,XIC+10,YIC, &(curarea->butspacetype), 1.0, SPACEICONMAX, 0, 0, "Displays Current Window Type. Click for menu of available types.");
+
+ xco+= XIC+22;
+
+ /* FULL WINDOW */
+ if(curarea->full) uiDefIconBut(block, BUT,B_FULL, ICON_SPLITSCREEN, xco,0,XIC,YIC, 0, 0, 0, 0, 0, "");
+ else uiDefIconBut(block, BUT,B_FULL, ICON_FULLSCREEN, xco,0,XIC,YIC, 0, 0, 0, 0, 0, "");
+
+ /* SORT TYPE */
+ xco+=XIC;
+ uiBlockBeginAlign(block);
+ uiDefIconButS(block, ROW, B_SORTIMASELLIST, ICON_SORTALPHA, xco+=XIC,0,XIC,YIC, &simasel->sort, 1.0, 0.0, 0, 0, "Sorts files alphabetically");
+ uiDefIconButS(block, ROW, B_SORTIMASELLIST, ICON_SORTBYEXT, xco+=XIC,0,XIC,YIC, &simasel->sort, 1.0, 3.0, 0, 0, "Sorts files by extension");
+ uiDefIconButS(block, ROW, B_SORTIMASELLIST, ICON_SORTTIME, xco+=XIC,0,XIC,YIC, &simasel->sort, 1.0, 1.0, 0, 0, "Sorts files by time");
+ uiDefIconButS(block, ROW, B_SORTIMASELLIST, ICON_SORTSIZE, xco+=XIC,0,XIC,YIC, &simasel->sort, 1.0, 2.0, 0, 0, "Sorts files by size");
+ uiBlockEndAlign(block);
+
+ cpack(0x0);
+ xco+=XIC+10;
+ uiDefIconButBitS(block, TOG, FILE_BOOKMARKS, B_RELOADIMASELDIR, ICON_BOOKMARKS,xco+=XIC,0,XIC,YIC, &simasel->flag, 0, 0, 0, 0, "Toggles Bookmarks on/off");
+ xco+=XIC+10;
+
+ xcotitle= xco;
+ xco+= BIF_GetStringWidth(G.font, simasel->title, (U.transopts & USER_TR_BUTTONS));
+
+ if(simasel->pupmenu && simasel->menup) {
+ uiDefButS(block, MENU, B_NOP, simasel->pupmenu, xco+10,0,90,20, simasel->menup, 0, 0, 0, 0, "");
+ xco+= 100;
+ }
+ uiBlockBeginAlign(block);
+ uiDefIconButBitS(block, TOG, FILE_HIDE_DOT, B_RELOADIMASELDIR, ICON_GHOST,xco+=XIC,0,XIC,YIC, &simasel->flag, 0, 0, 0, 0, "Hides dot files");
+ uiBlockEndAlign(block);
+ xco+=20;
+
+ type = simasel->type;
+ if (type == FILE_LOADLIB) {
+ do_filter = !BIF_filelist_islibrary(simasel->files, dir, group);
+ } else {
+ do_filter = (type != FILE_MAIN);
+ }
+ if ( do_filter ) {
+ uiDefIconButBitS(block, TOG, FILE_FILTER, B_FILTERIMASELDIR, ICON_SORTBYEXT,xco+=XIC,0,XIC,YIC, &simasel->flag, 0, 0, 0, 0, "Filter files");
+ if (simasel->flag & FILE_FILTER) {
+ xco+=4;
+ uiBlockBeginAlign(block);
+ uiDefIconButBitS(block, TOG, IMAGEFILE, B_FILTERIMASELDIR, ICON_IMAGE_COL,xco+=XIC,0,XIC,YIC, &simasel->filter, 0, 0, 0, 0, "Show images");
+ uiDefIconButBitS(block, TOG, BLENDERFILE, B_FILTERIMASELDIR, ICON_BLENDER,xco+=XIC,0,XIC,YIC, &simasel->filter, 0, 0, 0, 0, "Show .blend files");
+ uiDefIconButBitS(block, TOG, MOVIEFILE, B_FILTERIMASELDIR, ICON_SEQUENCE,xco+=XIC,0,XIC,YIC, &simasel->filter, 0, 0, 0, 0, "Show movies");
+ uiDefIconButBitS(block, TOG, PYSCRIPTFILE, B_FILTERIMASELDIR, ICON_PYTHON,xco+=XIC,0,XIC,YIC, &simasel->filter, 0, 0, 0, 0, "Show python scripts");
+ uiDefIconButBitS(block, TOG, FTFONTFILE, B_FILTERIMASELDIR, ICON_SYNTAX,xco+=XIC,0,XIC,YIC, &simasel->filter, 0, 0, 0, 0, "Show fonts");
+ uiDefIconButBitS(block, TOG, SOUNDFILE, B_FILTERIMASELDIR, ICON_SOUND,xco+=XIC,0,XIC,YIC, &simasel->filter, 0, 0, 0, 0, "Show sound files");
+ uiDefIconButBitS(block, TOG, TEXTFILE, B_FILTERIMASELDIR, ICON_TEXT,xco+=XIC,0,XIC,YIC, &simasel->filter, 0, 0, 0, 0, "Show text files");
+ uiDefIconButBitS(block, TOG, FOLDERFILE, B_FILTERIMASELDIR, ICON_FILESEL,xco+=XIC,0,XIC,YIC, &simasel->filter, 0, 0, 0, 0, "Show folders");
+ uiBlockEndAlign(block);
+ }
+ }
+
+ uiDefButBitS(block, TOG, FILE_STRINGCODE, 0, "Relative Paths", xco+=XIC+20,0,100,YIC, &simasel->flag, 0, 0, 0, 0, "Makes sure returned paths are relative to the current .blend file");
+ xco+=90;
+
+ if(simasel->type==FILE_LOADLIB) {
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOGN, FILE_LINK, B_REDR, "Append", xco+=XIC,0,100,YIC, &simasel->flag, 0, 0, 0, 0, "Copies selected data into current project");
+ uiDefButBitS(block, TOG, FILE_LINK, B_REDR, "Link", xco+=100,0,100,YIC, &simasel->flag, 0, 0, 0, 0, "Creates a link to selected data from current project");
+ uiBlockEndAlign(block);
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, FILE_AUTOSELECT, B_REDR, "Autosel", xco+=125,0,65,YIC, &simasel->flag, 0, 0, 0, 0, "Autoselect imported objects");
+ uiDefButBitS(block, TOG, FILE_ACTIVELAY, B_REDR, "Active Layer", xco+=65,0,80,YIC, &simasel->flag, 0, 0, 0, 0, "Append object(s) in active layer");
+ uiDefButBitS(block, TOG, FILE_ATCURSOR, B_REDR, "At Cursor", xco+=80,0,65,YIC, &simasel->flag, 0, 0, 0, 0, "Append object(s) at cursor, use centroid if more than one object is selected");
+ uiBlockEndAlign(block);
+
+ xco+= 100; // scroll
+
+ } else if(simasel->type==FILE_BLENDER) {
+ uiDefButBitI(block, TOGN, G_FILE_NO_UI, B_REDR, "Load UI", xco+=XIC,0,80,YIC, &G.fileflags, 0, 0, 0, 0, "Load the UI setup as well as the scene data");
+
+ xco+= 100; // scroll
+ }
+
+ glRasterPos2f((float)xcotitle, 5.0);
+ BIF_RasterPos((float)xcotitle, 5.0); // stupid texture fonts
+ BIF_ThemeColor(TH_TEXT);
+ BIF_DrawString(uiBlockGetCurFont(block), simasel->title, (U.transopts & USER_TR_BUTTONS));
+
+ /* always do as last */
+ curarea->headbutlen= xco+2*XIC;
+
+ uiDrawBlock(block);
+}
diff --git a/source/blender/src/header_info.c b/source/blender/src/header_info.c
new file mode 100644
index 00000000000..0cd8a0dc08d
--- /dev/null
+++ b/source/blender/src/header_info.c
@@ -0,0 +1,2119 @@
+/**
+ * header_info.c oct-2003
+ *
+ * Functions to draw the "User Preferences" window header
+ * and handle user events sent to it.
+ *
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "DNA_group_types.h"
+#include "DNA_ID.h"
+#include "DNA_image_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_object_types.h"
+#include "DNA_packedFile_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_world_types.h"
+
+#include "BDR_editcurve.h"
+#include "BDR_editmball.h"
+#include "BDR_editobject.h"
+#include "BDR_editface.h"
+#include "BDR_vpaint.h"
+
+#include "BIF_editarmature.h"
+#include "BIF_editfont.h"
+#include "BIF_editmesh.h"
+#include "BIF_gl.h"
+#include "BIF_interface.h"
+#include "BIF_language.h"
+#include "BIF_mainqueue.h"
+#include "BIF_meshtools.h"
+#include "BIF_previewrender.h"
+#include "BIF_renderwin.h"
+#include "BIF_resources.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_toets.h"
+#include "BIF_toolbox.h"
+#include "BIF_usiblender.h"
+#include "BIF_writeimage.h"
+#include "BIF_drawscene.h"
+
+#ifdef WITH_VERSE
+#include "BIF_verse.h"
+#endif
+
+#include "BKE_blender.h"
+#include "BKE_depsgraph.h"
+#include "BKE_exotic.h"
+#include "BKE_global.h"
+#include "BKE_image.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_node.h"
+#include "BKE_packedFile.h"
+#include "BKE_scene.h"
+#include "BKE_world.h"
+
+#ifdef WITH_VERSE
+#include "BKE_verse.h"
+#endif
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+#include "BLO_writefile.h"
+
+#include "BSE_editipo.h"
+#include "BSE_filesel.h"
+#include "BIF_imasel.h"
+#include "BSE_headerbuttons.h"
+#include "BSE_node.h"
+#include "BSE_sequence.h"
+#include "BSE_edit.h"
+
+#include "IMB_imbuf_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BPY_extern.h"
+#include "BPY_menus.h"
+
+#include "blendef.h"
+#include "interface.h"
+#include "mydevice.h"
+
+extern char versionstr[]; /* from blender.c */
+
+/*----------------------------------*/
+/* Progress bar vars and functions: */
+
+/* strubi shamelessly abused the status line as a progress bar...
+ * feel free to kill him after release */
+
+static int g_progress_bar = 0;
+static char *g_progress_info = 0;
+static float g_done;
+
+int start_progress_bar(void)
+{
+ g_progress_bar = 1;
+ return 1; // we never fail (yet)
+}
+
+void end_progress_bar(void)
+{
+ g_progress_bar = 0;
+}
+
+static void update_progress_bar(float done, char *info)
+{
+ g_done = done;
+ g_progress_info = info;
+}
+
+/** Progress bar
+ 'done': a value between 0.0 and 1.0, showing progress
+ 'info': a info text what is currently being done
+
+ Make sure that the progress bar is always called with:
+ done = 0.0 first
+ and
+ done = 1.0 last -- or alternatively use:
+
+ start_progressbar();
+ do_stuff_and_callback_progress_bar();
+ end_progressbar();
+*/
+
+int progress_bar(float done, char *busy_info)
+{
+ ScrArea *sa;
+ short val;
+
+ /* User break (ESC) */
+ while (qtest()) {
+ if (extern_qread(&val) == ESCKEY)
+ return 0;
+ }
+ if (done == 0.0) {
+ start_progress_bar();
+ } else if (done > 0.99) {
+ end_progress_bar();
+ }
+
+ sa= G.curscreen->areabase.first;
+ while(sa) {
+ if (sa->spacetype == SPACE_INFO) {
+ update_progress_bar(done, busy_info);
+
+ curarea = sa;
+
+ scrarea_do_headdraw(curarea);
+ areawinset(curarea->win);
+ sa->head_swap= WIN_BACK_OK;
+ screen_swapbuffers();
+ }
+ sa = sa->next;
+ }
+ return 1;
+}
+/* -- End of progress bar definitions ------- */
+
+extern char temp_dir[]; /* XXXXX BAD BAD BAD from exotic.c */
+
+void write_vrml_fs()
+{
+ if(G.obedit) {
+ error("Can't save VRML. Press TAB to leave EditMode");
+ }
+ else {
+ if(temp_dir[0]==0) strcpy(temp_dir, G.sce);
+
+ activate_fileselect(FILE_SPECIAL, "Export VRML 1.0", temp_dir, write_vrml);
+ }
+}
+
+void write_dxf_fs()
+{
+ if(G.obedit) {
+ error("Can't save DXF. Press TAB to leave EditMode");
+ }
+ else {
+
+ if(temp_dir[0]==0) strcpy(temp_dir, G.sce);
+
+ activate_fileselect(FILE_SPECIAL, "Export DXF", temp_dir, write_dxf);
+ }
+}
+
+void write_stl_fs()
+{
+ if(G.obedit) {
+ error("Can't save STL. Press TAB to leave EditMode");
+ }
+ else {
+
+ if(temp_dir[0]==0) strcpy(temp_dir, G.sce);
+
+ activate_fileselect(FILE_SPECIAL, "Export STL", temp_dir, write_stl);
+ }
+}
+/* ------------ */
+
+int buttons_do_unpack()
+{
+ int how;
+ char menu[2048];
+ char *line = menu;
+ int ret_value = RET_OK, count = 0;
+
+ count = countPackedFiles();
+
+ if(!count) {
+ pupmenu("No packed files. Autopack disabled");
+ return ret_value;
+ }
+ if (count == 1)
+ line += sprintf(line, "Unpack 1 file%%t");
+ else
+ line += sprintf(line, "Unpack %d files%%t", count);
+
+ line += sprintf(line, "|Use files in current directory (create when necessary)%%x%d", PF_USE_LOCAL);
+ line += sprintf(line, "|Write files to current directory (overwrite existing files)%%x%d", PF_WRITE_LOCAL);
+ line += sprintf(line, "|%%l|Use files in original location (create when necessary)%%x%d", PF_USE_ORIGINAL);
+ line += sprintf(line, "|Write files to original location (overwrite existing files)%%x%d", PF_WRITE_ORIGINAL);
+ line += sprintf(line, "|%%l|Disable AutoPack, keep all packed files %%x%d", PF_KEEP);
+ line += sprintf(line, "|Ask for each file %%x%d", PF_ASK);
+
+ how = pupmenu(menu);
+
+ if(how == -1)
+ ret_value = RET_CANCEL;
+ else {
+ if (how != PF_KEEP) unpackAll(how);
+ G.fileflags &= ~G_AUTOPACK;
+ }
+
+ return ret_value;
+}
+
+/* here, because of all creator stuff */
+
+Scene *copy_scene(Scene *sce, int level)
+{
+ /* level 0: al objects shared
+ * level 1: al object-data shared
+ * level 2: full copy
+ */
+ Scene *scen;
+ Base *base, *obase;
+
+ /* level 0 */
+ scen= copy_libblock(sce);
+ duplicatelist(&(scen->base), &(sce->base));
+
+ clear_id_newpoins();
+
+ id_us_plus((ID *)scen->world);
+ id_us_plus((ID *)scen->set);
+
+ scen->ed= NULL;
+ scen->radio= NULL;
+ scen->theDag= NULL;
+ scen->toolsettings= MEM_dupallocN(sce->toolsettings);
+
+ duplicatelist(&(scen->markers), &(sce->markers));
+ duplicatelist(&(scen->r.layers), &(sce->r.layers));
+
+ scen->nodetree= ntreeCopyTree(sce->nodetree, 0);
+
+ obase= sce->base.first;
+ base= scen->base.first;
+ while(base) {
+ id_us_plus(&base->object->id);
+ if(obase==sce->basact) scen->basact= base;
+
+ obase= obase->next;
+ base= base->next;
+ }
+
+ if(level==0) return scen;
+
+ /* level 1 */
+ G.scene= scen;
+
+ single_object_users(0);
+
+ /* camera */
+ ID_NEW(G.scene->camera);
+
+ /* level 2 */
+ if(level>=2) {
+ if(scen->world) {
+ id_us_plus(&scen->world->id);
+ scen->world= copy_world(scen->world);
+ }
+ single_obdata_users(0);
+ single_mat_users_expand();
+ single_tex_users_expand();
+
+ scen->radio= MEM_dupallocN(sce->radio);
+
+ }
+
+ clear_id_newpoins();
+
+ BPY_copy_scriptlink(&sce->scriptlink);
+ // make a private copy of the avicodecdata
+
+ if (sce->r.avicodecdata) {
+
+ scen->r.avicodecdata = MEM_dupallocN(sce->r.avicodecdata);
+ scen->r.avicodecdata->lpFormat = MEM_dupallocN(scen->r.avicodecdata->lpFormat);
+ scen->r.avicodecdata->lpParms = MEM_dupallocN(scen->r.avicodecdata->lpParms);
+ }
+
+ // make a private copy of the qtcodecdata
+
+ if (sce->r.qtcodecdata) {
+ scen->r.qtcodecdata = MEM_dupallocN(sce->r.qtcodecdata);
+ scen->r.qtcodecdata->cdParms = MEM_dupallocN(scen->r.qtcodecdata->cdParms);
+ }
+
+ return scen;
+}
+
+void do_info_buttons(unsigned short event)
+{
+ bScreen *sc, *oldscreen;
+ Scene *sce, *sce1;
+ ScrArea *sa;
+ int nr;
+
+ switch(event) {
+ case B_INFOSCR: /* menu select screen */
+
+ if( G.curscreen->screennr== -2) {
+ if(curarea->winy <50) {
+ sa= closest_bigger_area();
+ areawinset(sa->win);
+ }
+ activate_databrowse((ID *)G.curscreen, ID_SCR, 0, B_INFOSCR,
+ &G.curscreen->screennr, do_info_buttons);
+ return;
+ }
+ if( G.curscreen->screennr < 0) return;
+
+ sc= G.main->screen.first;
+ nr= 1;
+ while(sc) {
+ if(nr==G.curscreen->screennr) {
+ if(is_allowed_to_change_screen(sc)) setscreen(sc);
+ else error("Unable to perform function in EditMode");
+ break;
+ }
+ nr++;
+ sc= sc->id.next;
+ }
+ /* last item: NEW SCREEN */
+ if(sc==0) {
+ nr= pupmenu("New Screen%t|Empty%x1|Duplicate%x2");
+
+ if(nr==1) default_twosplit();
+ if(nr==2) duplicate_screen();
+ }
+ break;
+ case B_INFODELSCR:
+/*do this event only with buttons, so it can never be called with full-window*/
+
+ if(G.curscreen->id.prev) sc= G.curscreen->id.prev;
+ else if(G.curscreen->id.next) sc= G.curscreen->id.next;
+ else return;
+ if(okee("Delete current screen")) {
+ /* find new G.curscreen */
+
+ oldscreen= G.curscreen;
+ setscreen(sc); /* this test if sc has a full */
+ unlink_screen(oldscreen);
+ free_libblock(&G.main->screen, oldscreen);
+ }
+ scrarea_queue_headredraw(curarea);
+
+ break;
+ case B_INFOSCE: /* menu select scene */
+
+ if( G.curscreen->scenenr== -2) {
+ if(curarea->winy <50) {
+ sa= closest_bigger_area();
+ areawinset(sa->win);
+ }
+ activate_databrowse((ID *)G.scene, ID_SCE, 0, B_INFOSCE,
+ &G.curscreen->scenenr, do_info_buttons);
+ return;
+ }
+ if( G.curscreen->scenenr < 0) return;
+
+ sce= G.main->scene.first;
+ nr= 1;
+ while(sce) {
+ if(nr==G.curscreen->scenenr) {
+ if(sce!=G.scene) set_scene(sce);
+ break;
+ }
+ nr++;
+ sce= sce->id.next;
+ }
+ /* last item: NEW SCENE */
+ if(sce==0) {
+ nr= pupmenu("Add scene%t|Empty|Link Objects|Link ObData|Full Copy");
+ if(nr<= 0) return;
+ if(nr==1) {
+ ListBase lb;
+
+ sce= add_scene(G.scene->id.name+2);
+ /* pretty bad ass copying here. we should use copy_scene to do all (ton) */
+ lb= sce->r.layers;
+ sce->r= G.scene->r;
+ sce->r.layers= lb;
+#ifdef _WIN32
+ if (sce->r.avicodecdata) {
+ sce->r.avicodecdata = MEM_dupallocN(G.scene->r.avicodecdata);
+ sce->r.avicodecdata->lpFormat = MEM_dupallocN(G.scene->r.avicodecdata->lpFormat);
+ sce->r.avicodecdata->lpParms = MEM_dupallocN(G.scene->r.avicodecdata->lpParms);
+ }
+#endif
+#ifdef WITH_QUICKTIME
+ if (sce->r.qtcodecdata) {
+ sce->r.qtcodecdata = MEM_dupallocN(G.scene->r.qtcodecdata);
+ sce->r.qtcodecdata->cdParms = MEM_dupallocN(G.scene->r.qtcodecdata->cdParms);
+ }
+#endif
+ }
+ else sce= copy_scene(G.scene, nr-2);
+
+ set_scene(sce);
+ }
+ countall();
+ BIF_preview_changed(ID_TE);
+
+ break;
+ case B_INFODELSCE:
+
+ if(G.scene->id.prev) sce= G.scene->id.prev;
+ else if(G.scene->id.next) sce= G.scene->id.next;
+ else return;
+ if(okee("Delete current scene")) {
+
+ /* exit modes... could become single call once */
+ exit_editmode(EM_FREEDATA|EM_WAITCURSOR);
+ if(G.f & G_VERTEXPAINT) set_vpaint(); /* Switch off vertex paint */
+ if(G.f & G_TEXTUREPAINT) set_texturepaint(); /* Switch off tex paint */
+ if(G.f & G_WEIGHTPAINT) set_wpaint(); /* Switch off weight paint */
+
+ /* check all sets */
+ sce1= G.main->scene.first;
+ while(sce1) {
+ if(sce1->set == G.scene) sce1->set= 0;
+ sce1= sce1->id.next;
+ }
+
+ /* check all sequences */
+ clear_scene_in_allseqs(G.scene);
+
+ /* check render layer nodes in other scenes */
+ clear_scene_in_nodes(G.scene);
+
+ /* al screens */
+ sc= G.main->screen.first;
+ while(sc) {
+ if(sc->scene == G.scene) sc->scene= sce;
+ sc= sc->id.next;
+ }
+ free_libblock(&G.main->scene, G.scene);
+ set_scene(sce);
+ countall();
+ }
+
+ break;
+ }
+}
+
+static void check_packAll()
+{
+ // first check for dirty images
+ Image *ima;
+
+ for(ima = G.main->image.first; ima; ima= ima->id.next) {
+ if (ima->ibufs.first) { /* XXX FIX */
+ ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL);
+
+ if (ibuf && (ibuf->userflags &= IB_BITMAPDIRTY))
+ break;
+ }
+ }
+
+ if (ima == NULL || okee("Some images are painted on. These changes will be lost. Continue ?")) {
+ packAll();
+ G.fileflags |= G_AUTOPACK;
+ }
+}
+
+static int write_runtime(char *str, char *exename)
+{
+ char *freestr= NULL;
+ char *ext = 0;
+
+#ifdef _WIN32
+ ext = ".exe";
+#endif
+
+#ifdef __APPLE__
+ ext = ".app";
+#endif
+ if (ext && (!BLI_testextensie(str, ext))) {
+ freestr= MEM_mallocN(strlen(str) + strlen(ext) + 1, "write_runtime_check");
+ sprintf(freestr,"%s%s", str, ext);
+ str= freestr;
+ }
+
+ if (!BLI_exists(str) || saveover(str))
+ BLO_write_runtime(str, exename);
+
+ if (freestr)
+ MEM_freeN(freestr);
+
+ return 0;
+}
+
+static void write_runtime_check_dynamic(char *str)
+{
+ write_runtime(str, "blenderdynplayer.exe");
+}
+
+static void write_runtime_check(char *str)
+{
+ char player[128];
+
+ strcpy(player, "blenderplayer");
+
+#ifdef _WIN32
+ strcat(player, ".exe");
+#endif
+
+#ifdef __APPLE__
+ strcat(player, ".app");
+#endif
+
+ write_runtime(str, player);
+}
+/* end keyed functions */
+
+/************************** MAIN MENU *****************************/
+/************************** FILE *****************************/
+
+
+static void do_info_file_importmenu(void *arg, int event)
+{
+ ScrArea *sa;
+
+ if(curarea->spacetype==SPACE_INFO) {
+ sa= find_biggest_area_of_type(SPACE_SCRIPT);
+ if (!sa) sa= closest_bigger_area();
+ areawinset(sa->win);
+ }
+
+ /* events >=3 are registered bpython scripts */
+ if (event >= 3) {
+ BPY_menu_do_python(PYMENU_IMPORT, event - 3);
+ BIF_undo_push("Import file");
+ }
+ else {
+ switch(event) {
+
+ case 0: /* DXF */
+ activate_fileselect(FILE_BLENDER, "Import DXF", G.sce, BIF_read_file);
+ break;
+ case 1: /* VRML 1.0 */
+ activate_fileselect(FILE_BLENDER, "Import VRML 1.0", G.sce, BIF_read_file);
+ break;
+ case 2: /* STL */
+ activate_fileselect(FILE_BLENDER, "Import STL", G.sce, BIF_read_file);
+ break;
+
+ }
+ }
+ allqueue(REDRAWINFO, 0);
+}
+
+static uiBlock *info_file_importmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+ BPyMenu *pym;
+ int i = 0;
+
+ block= uiNewBlock(&curarea->uiblocks, "importmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_info_file_importmenu, NULL);
+ //uiBlockSetXOfs(block, -50); // offset to parent button
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "VRML 1.0...",
+ 0, yco-=20, 120, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "DXF...",
+ 0, yco-=20, 120, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "STL...",
+ 0, yco-=20, 120, 19, NULL, 0.0, 0.0, 1, 2, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ for (pym = BPyMenuTable[PYMENU_IMPORT]; pym; pym = pym->next, i++) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_PYTHON, pym->name, 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, i+3, pym->tooltip?pym->tooltip:pym->filename);
+ }
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+
+ return block;
+}
+
+static void do_info_file_exportmenu(void *arg, int event)
+{
+ ScrArea *sa;
+
+ if(curarea->spacetype==SPACE_INFO) {
+ sa= find_biggest_area_of_type(SPACE_SCRIPT);
+ if (!sa) sa= closest_bigger_area();
+ areawinset(sa->win);
+ }
+
+ /* events >=3 are registered bpython scripts */
+ if (event >= 3) BPY_menu_do_python(PYMENU_EXPORT, event - 3);
+
+ else switch(event) {
+
+ case 0:
+ write_vrml_fs();
+ break;
+ case 1:
+ write_dxf_fs();
+ break;
+ case 2:
+ write_stl_fs();
+ break;
+ }
+ allqueue(REDRAWINFO, 0);
+}
+
+static uiBlock *info_file_exportmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+ BPyMenu *pym;
+ int i = 0;
+
+ block= uiNewBlock(&curarea->uiblocks, "exportmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_info_file_exportmenu, NULL);
+ //uiBlockSetXOfs(block, -50); // offset to parent button
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "VRML 1.0...|Ctrl F2",
+ 0, yco-=20, 120, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "DXF...|Shift F2",
+ 0, yco-=20, 120, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "STL...",
+ 0, yco-=20, 120, 19, NULL, 0.0, 0.0, 1, 2, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ /* note that we acount for the 3 previous entries with i+3: */
+ for (pym = BPyMenuTable[PYMENU_EXPORT]; pym; pym = pym->next, i++) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_PYTHON, pym->name, 0, yco-=20, menuwidth, 19,
+ NULL, 0.0, 0.0, 1, i+3,
+ pym->tooltip?pym->tooltip:pym->filename);
+ }
+
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+
+ return block;
+}
+
+#ifdef WITH_VERSE
+
+extern ListBase session_list;
+
+static void do_verse_filemenu(void *arg, int event)
+{
+ char address[64]; /* lenght of domain name is 63 characters or less */
+ VerseSession *session = NULL;
+ ScrArea *sa;
+
+ if(curarea->spacetype==SPACE_INFO) {
+ sa= closest_bigger_area();
+ areawinset(sa->win);
+ }
+
+ switch(event) {
+ case 0:
+ waitcursor(1);
+ printf("Connecting to localhost!\n");
+ b_verse_connect("localhost");
+ waitcursor(0);
+ break;
+ case 1:
+ address[0] = '\0';
+ if(sbutton(address, 0, 63, "Server:")) {
+ waitcursor(1);
+ printf("Connecting to %s\n", address);
+ b_verse_connect(address);
+ waitcursor(0);
+ }
+ break;
+ case 2:
+ session = session_menu();
+ if(session) {
+ printf("Disconnecting session: %s!\n", session->address);
+ end_verse_session(session);
+ }
+ break;
+ case 3:
+ printf("Disconnecting all sessions!\n");
+ end_all_verse_sessions();
+ break;
+ case 4:
+ printf("sending get to master server\n");
+ b_verse_ms_get();
+ break;
+ }
+}
+
+static uiBlock *verse_filemenu(void *unusedargs)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "verse_filemenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_verse_filemenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Connect to localhost", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Connect ...", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ if(session_list.first != NULL) {
+ if(session_list.first != session_list.last) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Disconnect ...",
+ 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Disconnect all",
+ 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+ }
+ else {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Disconnect",
+ 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+ }
+
+ }
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Get Servers", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+
+ return block;
+}
+#endif
+
+static void do_info_filemenu(void *arg, int event)
+{
+ ScrArea *sa;
+ char dir[FILE_MAXDIR];
+
+ if(curarea->spacetype==SPACE_INFO) {
+ sa= closest_bigger_area();
+ areawinset(sa->win);
+ }
+
+ /* these are no defines, easier this way, the codes are in the function below */
+ switch(event) {
+ case 0:
+ if (okee("Erase All")) {
+ if (!BIF_read_homefile(0, 1))
+ error("No file ~/.B.blend");
+ }
+ break;
+ case 1: /* open */
+ activate_fileselect(FILE_BLENDER, "Open", G.sce, BIF_read_file);
+ break;
+ case 3: /* append */
+ activate_fileselect(FILE_LOADLIB, "Load Library", G.lib, 0);
+ break;
+ case 4: /* save */
+ strcpy(dir, G.sce);
+ untitled(dir);
+ activate_fileselect(FILE_BLENDER, "Save As", dir, BIF_write_file);
+ break;
+ case 5:
+ strcpy(dir, G.sce);
+ if (untitled(dir)) {
+ activate_fileselect(FILE_BLENDER, "Save As", dir, BIF_write_file);
+ } else {
+ BIF_write_file(dir);
+ free_filesel_spec(dir);
+ }
+ break;
+ case 6: /* save image */
+ BIF_save_rendered_image_fs();
+ break;
+ case 7:
+ activate_imageselect(FILE_LOADLIB, "Load Library", G.lib, 0);
+ break;
+ case 22: /* save runtime */
+ activate_fileselect(FILE_SPECIAL, "Save Runtime", "", write_runtime_check);
+ break;
+ case 23: /* save dynamic runtime */
+ activate_fileselect(FILE_SPECIAL, "Save Dynamic Runtime", "", write_runtime_check_dynamic);
+ break;
+ case 24:
+ BIF_screendump(0);
+ break;
+ case 25:
+ BIF_screendump(1);
+ break;
+ case 10: /* pack data */
+ check_packAll();
+ break;
+ case 11: /* unpack to current dir */
+ unpackAll(PF_WRITE_LOCAL);
+ G.fileflags &= ~G_AUTOPACK;
+ break;
+ case 12: /* unpack data */
+ if (buttons_do_unpack() != RET_CANCEL) {
+ /* Clear autopack bit only if user selected one of the unpack options */
+ G.fileflags &= ~G_AUTOPACK;
+ }
+ break;
+ case 13:
+ exit_usiblender();
+ break;
+ case 15: /* recover previous session */
+ {
+ extern short winqueue_break; /* editscreen.c */
+ int save_over;
+ char str[FILE_MAXDIR+FILE_MAXFILE];
+ char scestr[FILE_MAXDIR+FILE_MAXFILE];
+
+ strcpy(scestr, G.sce); /* temporal store */
+ save_over = G.save_over;
+ BLI_make_file_string("/", str, U.tempdir, "quit.blend");
+ BKE_read_file(str, NULL);
+ G.save_over = save_over;
+ strcpy(G.sce, scestr);
+
+ winqueue_break= 1; /* leave queues everywhere */
+
+ BKE_reset_undo();
+ BKE_write_undo("original"); /* save current state */
+ refresh_interface_font();
+ }
+ break;
+ case 31: /* save default settings */
+ BIF_write_homefile();
+ break;
+ case 32:
+ if (okee("Erase All")) {
+ if (!BIF_read_homefile(1, 1))
+ error("Can't read data from memory!");
+ }
+ break;
+ case 35: /* compress toggle */
+ U.flag ^= (USER_FILECOMPRESS);
+ break;
+ }
+ allqueue(REDRAWINFO, 0);
+}
+
+static void do_info_operecentmenu(void *arg, int event)
+{
+ struct RecentFile *recent;
+
+ if(event==0 && G.sce[0]) {
+ BIF_read_file(G.sce);
+ }
+ else { /* Global */
+ recent = BLI_findlink(&(G.recent_files), event-1);
+ BIF_read_file(recent->filename);
+ }
+}
+
+static uiBlock *info_openrecentmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120, i;
+ struct RecentFile *recent;
+
+ block= uiNewBlock(&curarea->uiblocks, "info_openrecentmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_info_operecentmenu, NULL);
+
+ if (G.sce[0]) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, G.sce, 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+ }
+
+ for (recent = G.recent_files.first, i=0; i<U.recent_files && recent; recent = recent->next, i++) {
+ if (strcmp(recent->filename, G.sce)!=0) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, recent->filename, 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, i+1, "");
+ }
+ }
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+static uiBlock *info_filemenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco=0;
+ short menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "info_filemenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_info_filemenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "New|Ctrl X", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Open...|F1", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+#ifdef WITH_VERSE
+ uiDefIconTextBlockBut(block, verse_filemenu, NULL, ICON_RIGHTARROW_THIN, "Verse", 0, yco-=20, menuwidth, 19, "");
+#endif
+ uiDefIconTextBlockBut(block, info_openrecentmenu, NULL, ICON_RIGHTARROW_THIN, "Open Recent",0, yco-=20, 120, 19, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Recover Last Session", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 15, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Save|Ctrl W", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Save As...|F2", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+
+ if(U.flag & USER_FILECOMPRESS) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Compress File", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 35, "Enable file compression");
+ } else {
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Compress File", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 35, "Enable file compression");
+ }
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Save Image...|F3", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 6, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Dump Subwindow|Ctrl F3", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 24, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Dump Screen|Ctrl Shift F3", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 25, "");
+#if GAMEBLENDER == 1
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Save Runtime...", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 22, "");
+#ifdef _WIN32
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Save Dynamic Runtime...", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 23, "");
+#endif
+#endif
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Save Default Settings|Ctrl U", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 31, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Load Factory Settings", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 32, "");
+
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Append or Link|Shift F1", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Append or Link (Image Browser)|Ctrl F1", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 7, "");
+ uiDefIconTextBlockBut(block, info_file_importmenu, NULL, ICON_RIGHTARROW_THIN, "Import", 0, yco-=20, menuwidth, 19, "");
+ uiDefIconTextBlockBut(block, info_file_exportmenu, NULL, ICON_RIGHTARROW_THIN, "Export", 0, yco-=20, menuwidth, 19, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Pack Data", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 10, "");
+// uiDefBut(block, BUTM, 1, "Unpack Data to current dir", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 11, "Removes all packed files from the project and saves them to the current directory");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Unpack Data...", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 12, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Quit Blender|Ctrl Q", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 13, "");
+
+ uiBlockSetDirection(block, UI_DOWN);
+ uiTextBoundsBlock(block, 80);
+
+ return block;
+}
+
+/**************************** ADD ******************************/
+
+void do_info_add_meshmenu(void *arg, int event)
+{
+ if (event>=20) {
+ BPY_menu_do_python(PYMENU_ADDMESH, event - 20);
+ } else {
+ switch(event) {
+ case 0:
+ /* Plane */
+ add_primitiveMesh(0);
+ break;
+ case 1:
+ /* Cube */
+ add_primitiveMesh(1);
+ break;
+ case 2:
+ /* Circle */
+ add_primitiveMesh(4);
+ break;
+ case 3:
+ /* UVsphere */
+ add_primitiveMesh(11);
+ break;
+ case 4:
+ /* IcoSphere */
+ add_primitiveMesh(12);
+ break;
+ case 5:
+ /* Cylinder */
+ add_primitiveMesh(5);
+ break;
+ case 7:
+ /* Cone */
+ add_primitiveMesh(7);
+ break;
+ case 8:
+ /* Grid */
+ add_primitiveMesh(10);
+ break;
+ case 9:
+ /* Monkey */
+ add_primitiveMesh(13);
+ break;
+ default:
+ break;
+ }
+ }
+ allqueue(REDRAWINFO, 0);
+}
+
+static uiBlock *info_add_meshmenu(void *arg_unused)
+{
+/* static short tog=0; */
+ uiBlock *block;
+ short yco= 0;
+
+ /* Python Menu */
+ BPyMenu *pym;
+ int i=0;
+
+ block= uiNewBlock(&curarea->uiblocks, "add_meshmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_info_add_meshmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Plane|", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Cube|", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Circle|", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "UVsphere", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 3, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "IcoSphere|", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 4, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Cylinder|", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 5, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Cone|", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 7, "");
+ uiDefIconTextBut(block, SEPR, 0, ICON_BLANK1, "", 0, yco-=6, 160, 6, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Grid|", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 8, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Monkey|", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 9, "");
+
+
+ pym = BPyMenuTable[PYMENU_ADDMESH];
+ if (pym) {
+ uiDefIconTextBut(block, SEPR, 0, ICON_BLANK1, "", 0, yco-=6, 160, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ for (; pym; pym = pym->next, i++) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_PYTHON, pym->name, 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, i+20, pym->tooltip?pym->tooltip:pym->filename);
+ }
+ }
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+void do_info_add_curvemenu(void *arg, int event)
+{
+
+ switch(event) {
+ case 0:
+ /* Bezier Curve */
+ add_primitiveCurve(10);
+ break;
+ case 1:
+ /* Bezier Circle */
+ add_primitiveCurve(11);
+ break;
+ case 2:
+ /* NURB Curve */
+ add_primitiveCurve(40);
+ break;
+ case 3:
+ /* NURB Circle */
+ add_primitiveCurve(41);
+ break;
+ case 4:
+ /* Path */
+ add_primitiveCurve(46);
+ break;
+ default:
+ break;
+ }
+ allqueue(REDRAWINFO, 0);
+}
+
+static uiBlock *info_add_curvemenu(void *arg_unused)
+{
+/* static short tog=0; */
+ uiBlock *block;
+ short yco= 0;
+
+ block= uiNewBlock(&curarea->uiblocks, "add_curvemenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_info_add_curvemenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Bezier Curve|", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Bezier Circle|", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "NURBS Curve|", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "NURBS Circle", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 3, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Path|", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 4, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+
+void do_info_add_surfacemenu(void *arg, int event)
+{
+
+ switch(event) {
+ case 0:
+ /* Curve */
+ add_primitiveNurb(0);
+ break;
+ case 1:
+ /* Circle */
+ add_primitiveNurb(1);
+ break;
+ case 2:
+ /* Surface */
+ add_primitiveNurb(2);
+ break;
+ case 3:
+ /* Tube */
+ add_primitiveNurb(3);
+ break;
+ case 4:
+ /* Sphere */
+ add_primitiveNurb(4);
+ break;
+ case 5:
+ /* Donut */
+ add_primitiveNurb(5);
+ break;
+ default:
+ break;
+ }
+ allqueue(REDRAWINFO, 0);
+}
+
+static uiBlock *info_add_surfacemenu(void *arg_unused)
+{
+/* static short tog=0; */
+ uiBlock *block;
+ short yco= 0;
+
+ block= uiNewBlock(&curarea->uiblocks, "add_surfacemenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_info_add_surfacemenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "NURBS Curve|", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "NURBS Circle|", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "NURBS Surface|", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "NURBS Tube", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 3, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "NURBS Sphere|", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 4, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "NURBS Donut|", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 5, "");
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+void do_info_add_metamenu(void *arg, int event)
+{
+
+ switch(event) {
+ case 0:
+ /* Ball */
+ add_primitiveMball(1);
+ break;
+ case 1:
+ /* Tube */
+ add_primitiveMball(2);
+ break;
+ case 2:
+ /* Plane */
+ add_primitiveMball(3);
+ break;
+ case 3:
+ /* Elipsoid */
+ add_primitiveMball(4);
+ break;
+ case 4:
+ /* Cube */
+ add_primitiveMball(5);
+ break;
+ default:
+ break;
+ }
+ allqueue(REDRAWINFO, 0);
+}
+
+
+static uiBlock *info_add_metamenu(void *arg_unused)
+{
+/* static short tog=0; */
+ uiBlock *block;
+ short xco= 0;
+
+ block= uiNewBlock(&curarea->uiblocks, "add_metamenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_info_add_metamenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,"Meta Ball|", 0, xco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Meta Tube|", 0, xco-=20, 160, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Meta Plane|", 0, xco-=20, 160, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Meta Ellipsoid|", 0, xco-=20, 160, 19, NULL, 0.0, 0.0, 1, 3, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Meta Cube|", 0, xco-=20, 160, 19, NULL, 0.0, 0.0, 1, 4, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+void do_info_add_lampmenu(void *arg, int event)
+{
+
+ switch(event) {
+ case 0: /* lamp */
+ add_objectLamp(LA_LOCAL);
+ break;
+ case 1: /* sun */
+ add_objectLamp(LA_SUN);
+ break;
+ case 2: /* spot */
+ add_objectLamp(LA_SPOT);
+ break;
+ case 3: /* hemi */
+ add_objectLamp(LA_HEMI);
+ break;
+ case 4: /* area */
+ add_objectLamp(LA_AREA);
+ break;
+ case 5: /* YafRay photon lamp */
+ if (G.scene->r.renderer==R_YAFRAY)
+ add_objectLamp(LA_YF_PHOTON);
+ break;
+ default:
+ break;
+ }
+ allqueue(REDRAWINFO, 0);
+}
+
+static uiBlock *info_add_lampmenu(void *arg_unused)
+{
+/* static short tog=0; */
+ uiBlock *block;
+ short yco= 0;
+
+ block= uiNewBlock(&curarea->uiblocks, "add_lampmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_info_add_lampmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Lamp|", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Sun|", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Spot|", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Hemi|", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 3, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Area|", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 4, "");
+ if (G.scene->r.renderer==R_YAFRAY)
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Photon|", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 5, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+static void do_info_add_groupmenu(void *arg, int event)
+{
+ Object *ob;
+
+ add_object_draw(OB_EMPTY);
+ ob= OBACT;
+
+ ob->dup_group= BLI_findlink(&G.main->group, event);
+ if(ob->dup_group) {
+ id_us_plus((ID *)ob->dup_group);
+ ob->transflag |= OB_DUPLIGROUP;
+ DAG_scene_sort(G.scene);
+ }
+}
+
+
+static uiBlock *info_add_groupmenu(void *arg_unused)
+{
+ Group *group;
+ uiBlock *block;
+ short yco= 0;
+ int a;
+
+ block= uiNewBlock(&curarea->uiblocks, "add_groupmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_info_add_groupmenu, NULL);
+
+ for(a=0, group= G.main->group.first; group; group= group->id.next, a++) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, group->id.name+2, 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, a, "");
+ }
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+void do_info_addmenu(void *arg, int event)
+{
+ switch(event) {
+ case 0:
+ /* Mesh */
+ break;
+ case 1:
+ /* Curve */
+ break;
+ case 2:
+ /* Surface */
+ break;
+ case 3:
+ /* Metaball */
+ break;
+ case 4:
+ /* Text (argument is discarded) */
+ add_primitiveFont(event);
+ break;
+ case 5:
+ /* Empty */
+ add_object_draw(OB_EMPTY);
+ break;
+ case 6:
+ /* Camera */
+ add_object_draw(OB_CAMERA);
+ break;
+ case 8:
+ /* Armature */
+ add_primitiveArmature(OB_ARMATURE);
+ break;
+ case 9:
+ /* Lattice */
+ add_object_draw(OB_LATTICE);
+ break;
+ case 10:
+ /* group instance not yet */
+ break;
+ default:
+ break;
+ }
+ allqueue(REDRAWINFO, 0);
+}
+
+
+static uiBlock *info_addmenu(void *arg_unused)
+{
+/* static short tog=0; */
+ uiBlock *block;
+ short yco= 0;
+
+ block= uiNewBlock(&curarea->uiblocks, "addmenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_info_addmenu, NULL);
+
+ uiDefIconTextBlockBut(block, info_add_meshmenu, NULL, ICON_RIGHTARROW_THIN, "Mesh", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, info_add_curvemenu, NULL, ICON_RIGHTARROW_THIN, "Curve", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, info_add_surfacemenu, NULL, ICON_RIGHTARROW_THIN, "Surface", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, info_add_metamenu, NULL, ICON_RIGHTARROW_THIN, "Meta", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Text", 0, yco-=20, 120, 19, NULL, 0.0, 0.0, 1, 4, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Empty", 0, yco-=20, 120, 19, NULL, 0.0, 0.0, 1, 5, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, 120, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBlockBut(block, info_add_groupmenu, NULL, ICON_RIGHTARROW_THIN, "Group", 0, yco-=20, 120, 19, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, 120, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Camera", 0, yco-=20, 120, 19, NULL, 0.0, 0.0, 1, 6, "");
+ uiDefIconTextBlockBut(block, info_add_lampmenu, NULL, ICON_RIGHTARROW_THIN, "Lamp", 0, yco-=20, 120, 19, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, 120, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Armature", 0, yco-=20, 120, 19, NULL, 0.0, 0.0, 1, 8, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Lattice", 0, yco-=20, 120, 19, NULL, 0.0, 0.0, 1, 9, "");
+
+ uiBlockSetDirection(block, UI_DOWN);
+ uiTextBoundsBlock(block, 80);
+
+ return block;
+}
+
+/************************** GAME *****************************/
+
+
+static void do_info_gamemenu(void *arg, int event)
+{
+ switch (event) {
+ case G_FILE_ENABLE_ALL_FRAMES:
+ case G_FILE_DIAPLAY_LISTS:
+ case G_FILE_SHOW_FRAMERATE:
+ case G_FILE_SHOW_DEBUG_PROPS:
+ case G_FILE_AUTOPLAY:
+ case G_FILE_GAME_TO_IPO:
+ case G_FILE_GAME_MAT:
+ case G_FILE_SHOW_PHYSICS:
+ G.fileflags ^= event;
+ break;
+ default:
+ ; /* ignore the rest */
+ }
+}
+
+static uiBlock *info_gamemenu(void *arg_unused)
+{
+/* static short tog=0; */
+ uiBlock *block;
+ short yco= 0;
+ short menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "gamemenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_info_gamemenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, B_STARTGAME, ICON_BLANK1, "Start Game|P", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 1, 0, "");
+
+
+ if(G.fileflags & G_FILE_ENABLE_ALL_FRAMES) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Enable All Frames", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, G_FILE_ENABLE_ALL_FRAMES, "");
+ } else {
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Enable All Frames", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, G_FILE_ENABLE_ALL_FRAMES, "");
+ }
+
+ if(G.fileflags & G_FILE_GAME_TO_IPO) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Record Game Physics to IPO", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, G_FILE_GAME_TO_IPO, "");
+ } else {
+
+ if(G.fileflags & G_FILE_DIAPLAY_LISTS) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Generate Display Lists", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, G_FILE_DIAPLAY_LISTS, "");
+ } else {
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Generate Display Lists", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, G_FILE_DIAPLAY_LISTS, "");
+ }
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Record Game Physics to IPO", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, G_FILE_GAME_TO_IPO, "");
+ }
+
+ if(G.fileflags & G_FILE_GAME_MAT) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Use Blender Materials", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, G_FILE_GAME_MAT, "");
+ } else {
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Use Blender Materials", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, G_FILE_GAME_MAT, "");
+ }
+
+
+
+ if(G.fileflags & G_FILE_SHOW_FRAMERATE) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Show Framerate and Profile", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, G_FILE_SHOW_FRAMERATE, "");
+ } else {
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Show Framerate and Profile", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, G_FILE_SHOW_FRAMERATE, "");
+ }
+
+
+ if(G.fileflags & G_FILE_SHOW_PHYSICS) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Show Physics Visualization", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, G_FILE_SHOW_PHYSICS, "");
+ } else {
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Show Physics Visualization", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, G_FILE_SHOW_PHYSICS, "");
+ }
+
+ if(G.fileflags & G_FILE_SHOW_DEBUG_PROPS) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Show Debug Properties", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, G_FILE_SHOW_DEBUG_PROPS, "");
+ } else {
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Show Debug Properties", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, G_FILE_SHOW_DEBUG_PROPS, "");
+ }
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 1, 0, "");
+
+ if(G.fileflags & G_FILE_AUTOPLAY) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Autostart", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, G_FILE_AUTOPLAY, "");
+ } else {
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Autostart", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, G_FILE_AUTOPLAY, "");
+ }
+
+ uiBlockSetDirection(block, UI_DOWN);
+ uiTextBoundsBlock(block, 70);
+
+ return block;
+}
+/************************** TIMELINE *****************************/
+
+static void do_info_timelinemenu(void *arg, int event)
+{
+ /* needed to check for valid selected objects */
+ Base *base=NULL;
+ Object *ob=NULL;
+ //char file[FILE_MAXDIR+FILE_MAXFILE];
+
+ base= BASACT;
+ if (base) ob= base->object;
+
+ switch(event) {
+ case 1:
+ /* Show Keyframes */
+ if (!ob) error("Select an object before showing its keyframes");
+ else set_ob_ipoflags();
+ break;
+ case 2:
+ /* Show and select Keyframes */
+ if (!ob) error("Select an object before showing and selecting its keyframes");
+ else select_select_keys();
+ break;
+ case 3:
+ /* select next keyframe */
+ if (!ob) error("Select an object before selecting its next keyframe");
+ else nextkey_obipo(1);
+ break;
+ case 4:
+ /* select previous keyframe */
+ if (!ob) error("Select an object before selecting its previous keyframe");
+ else nextkey_obipo(-1);
+ break;
+ case 5:
+ /* next keyframe */
+ if (!ob) error("Select an object before going to its next keyframe");
+ else movekey_obipo(1);
+ break;
+ case 6:
+ /* previous keyframe */
+ if (!ob) error("Select an object before going to its previous keyframe");
+ else movekey_obipo(-1);
+ break;
+ case 7:
+ /* next frame */
+ CFRA++;
+ update_for_newframe();
+ break;
+ case 8:
+ /* previous frame */
+ CFRA--;
+ if(CFRA<1) CFRA=1;
+ update_for_newframe();
+ break;
+ case 9:
+ /* forward 10 frames */
+ CFRA+= 10;
+ update_for_newframe();
+ break;
+ case 10:
+ /* back 10 frames */
+ CFRA-= 10;
+ if(CFRA<1) CFRA=1;
+ update_for_newframe();
+ break;
+ case 11:
+ /* end frame */
+ CFRA= EFRA;
+ update_for_newframe();
+ break;
+ case 12:
+ /* start frame */
+ CFRA= SFRA;
+ update_for_newframe();
+ break;
+ }
+ allqueue(REDRAWINFO, 0);
+}
+
+static uiBlock *info_timelinemenu(void *arg_unused)
+{
+/* static short tog=0; */
+ uiBlock *block;
+ char str[26];
+ short yco= 0;
+ short menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "timelinemenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_info_timelinemenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Show Keyframes|K", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Show and Select Keyframes|Shift K",0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select Next Keyframe|PageUp", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select Previous Keyframe|PageDown", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Next Keyframe|Ctrl PageUp", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Previous Keyframe|Ctrl PageDown", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 6, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Next Frame|RightArrow", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 7, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Previous Frame|LeftArrow", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 8, "");
+
+ sprintf(str, "Forward %d Frames|UpArrow", G.scene->jumpframe);
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, str, 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 9, "");
+ sprintf(str, "Back %d Frames|DownArrow", G.scene->jumpframe);
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, str, 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 10, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "End Frame|Shift RightArrow", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 11, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Start Frame|Shift LeftArrow", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 12, "");
+
+ uiBlockSetDirection(block, UI_DOWN);
+ uiTextBoundsBlock(block, 80);
+
+ return block;
+}
+
+/************************** RENDER *****************************/
+
+void do_info_render_bakemenu(void *arg, int event)
+{
+
+ objects_bake_render(event);
+
+ allqueue(REDRAWINFO, 0);
+}
+
+static uiBlock *info_render_bakemenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0;
+
+ block= uiNewBlock(&curarea->uiblocks, "render_bakemenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_info_render_bakemenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Full Render|Ctrl Alt B, 1", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Ambient Occlusion|Ctrl Alt B, 2", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Normals|Ctrl Alt B, 3", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 3, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Texture Only|Ctrl Alt B, 4", 0, yco-=20, 160, 19, NULL, 0.0, 0.0, 1, 4, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+static void do_info_rendermenu(void *arg, int event)
+{
+ ScrArea *sa;
+ extern void playback_anim();
+
+ /* events >=10 are registered bpython scripts */
+ if (event >= 10) {
+ if(curarea->spacetype==SPACE_INFO) {
+ sa= find_biggest_area_of_type(SPACE_SCRIPT);
+ if (!sa) sa= closest_bigger_area();
+ areawinset(sa->win);
+ }
+
+ BPY_menu_do_python(PYMENU_RENDER, event - 10);
+ BIF_undo_push("Rendering Script");
+ }
+ else {
+ switch(event) {
+
+ case 0:
+ BIF_do_render(0);
+ break;
+ case 1:
+ BIF_do_render(1);
+ break;
+
+ /* note: dont use select_area() for setting active areas for opengl render */
+ /* its hackish and instable... code here was removed */
+
+ case 4:
+ BIF_toggle_render_display();
+ break;
+ case 5:
+ playback_anim();
+ break;
+ case 6:
+ /* dodgy hack turning on SHIFT key to do a proper render border select
+ set_render_border(); only works when 3d window active
+
+ This code copied from toolbox.c, only works when 3d window is cameraview */
+
+ if(select_area(SPACE_VIEW3D)) {
+ mainqenter(LEFTSHIFTKEY, 1);
+ mainqenter(BKEY, 1);
+ mainqenter(BKEY, 0);
+ mainqenter(EXECUTE, 1);
+ mainqenter(LEFTSHIFTKEY, 0);
+ }
+
+ break;
+
+ case 7:
+ extern_set_butspace(F10KEY, 0);
+ break;
+ }
+ }
+ allqueue(REDRAWINFO, 0);
+}
+
+static uiBlock *info_rendermenu(void *arg_unused)
+{
+ uiBlock *block;
+ BPyMenu *pym;
+ short yco= 0;
+ short menuwidth=120;
+ int i=0;
+
+ block= uiNewBlock(&curarea->uiblocks, "rendermenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_info_rendermenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Render Current Frame|F12", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Render Animation|Ctrl F12", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBlockBut(block, info_render_bakemenu, NULL, ICON_RIGHTARROW_THIN, "Bake Render Meshes", 0, yco-=20, 120, 19, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Show Render Buffer|F11", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Play Back Rendered Animation|Ctrl F11", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Set Render Border|Shift B", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 6, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Render Settings|F10", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 7, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ for (pym = BPyMenuTable[PYMENU_RENDER]; pym; pym = pym->next, i++) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_PYTHON, pym->name, 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, i+10, pym->tooltip?pym->tooltip:pym->filename);
+ }
+
+ uiBlockSetDirection(block, UI_DOWN);
+ uiTextBoundsBlock(block, 80);
+
+ return block;
+}
+
+/************************** HELP *****************************/
+
+static void do_info_help_websitesmenu(void *arg, int event)
+{
+ BPY_menu_do_python(PYMENU_HELPWEBSITES, event);
+
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+
+static uiBlock *info_help_websitesmenu(void *arg_unused)
+{
+ uiBlock *block;
+ BPyMenu *pym;
+ short yco = 20, menuwidth = 120;
+ int i = 0;
+
+ block= uiNewBlock(&curarea->uiblocks, "info_help_websitesmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_info_help_websitesmenu, NULL);
+
+ for (pym = BPyMenuTable[PYMENU_HELPWEBSITES]; pym; pym = pym->next, i++) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_PYTHON, pym->name, 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, i, pym->tooltip?pym->tooltip:pym->filename);
+ }
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+
+ return block;
+}
+
+static void do_info_help_systemmenu(void *arg, int event)
+{
+ /* events >=10 are registered bpython scripts */
+ if (event >= 10) BPY_menu_do_python(PYMENU_HELPSYSTEM, event - 10);
+ else {
+ switch(event) {
+
+ case 1: /* Benchmark */
+ /* dodgy hack turning on CTRL ALT SHIFT key to do a benchmark
+ * rather than copying lines and lines of code from toets.c :(
+ */
+
+ if(select_area(SPACE_VIEW3D)) {
+ mainqenter(LEFTSHIFTKEY, 1);
+ mainqenter(LEFTCTRLKEY, 1);
+ mainqenter(LEFTALTKEY, 1);
+ mainqenter(TKEY, 1);
+ mainqenter(TKEY, 0);
+ mainqenter(EXECUTE, 1);
+ mainqenter(LEFTSHIFTKEY, 0);
+ mainqenter(LEFTCTRLKEY, 0);
+ mainqenter(LEFTALTKEY, 0);
+ }
+ break;
+ }
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+
+static uiBlock *info_help_systemmenu(void *arg_unused)
+{
+ uiBlock *block;
+ BPyMenu *pym;
+ short yco = 20, menuwidth = 120;
+ int i = 0;
+
+ block= uiNewBlock(&curarea->uiblocks, "info_help_systemmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_info_help_systemmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Benchmark", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+
+ for (pym = BPyMenuTable[PYMENU_HELPSYSTEM]; pym; pym = pym->next, i++) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_PYTHON, pym->name, 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, i+10, pym->tooltip?pym->tooltip:pym->filename);
+ }
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+
+ return block;
+}
+
+static void do_info_helpmenu(void *arg, int event)
+{
+ ScrArea *sa;
+
+ if(curarea->spacetype==SPACE_INFO) {
+ sa= find_biggest_area_of_type(SPACE_SCRIPT);
+ if (!sa) sa= closest_bigger_area();
+ areawinset(sa->win);
+ }
+
+ /* events >=10 are registered bpython scripts */
+ if (event >= 10) BPY_menu_do_python(PYMENU_HELP, event - 10);
+ else {
+ switch(event) {
+
+ case 0: /* About Blender */
+ break;
+ }
+ }
+
+ allqueue(REDRAWINFO, 0);
+}
+
+static uiBlock *info_helpmenu(void *arg_unused)
+{
+/* static short tog=0; */
+ uiBlock *block;
+ short yco= 0;
+ short menuwidth=120;
+ BPyMenu *pym;
+ int i = 0;
+
+ block= uiNewBlock(&curarea->uiblocks, "info_helpmenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_info_helpmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, B_SHOWSPLASH, ICON_BLANK1, "About Blender...", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ for (pym = BPyMenuTable[PYMENU_HELP]; pym; pym = pym->next, i++) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_PYTHON, pym->name, 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, i+10, pym->tooltip?pym->tooltip:pym->filename);
+ }
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBlockBut(block, info_help_websitesmenu, NULL, ICON_RIGHTARROW_THIN, "Websites", 0, yco-=20, 120, 19, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBlockBut(block, info_help_systemmenu, NULL, ICON_RIGHTARROW_THIN, "System", 0, yco-=20, 120, 19, "");
+
+ uiBlockSetDirection(block, UI_DOWN);
+ uiTextBoundsBlock(block, 80);
+
+ return block;
+}
+
+/************************** END MAIN MENU *****************************/
+/* ugly global yes, for renderwin.c to write to */
+char info_time_str[32]="";
+
+static void info_text(int x, int y)
+{
+ Object *ob= OBACT;
+ extern float hashvectf[];
+ extern unsigned long mem_in_use, mmap_in_use;
+ unsigned int swatch_color;
+ float fac1, fac2, fac3;
+ char infostr[300], memstr[64];
+ char *headerstr, *s;
+ int hsize;
+
+ s= memstr + sprintf(memstr," | Mem:%.2fM ", ((mem_in_use-mmap_in_use)>>10)/1024.0);
+ if(mmap_in_use)
+ sprintf(s,"(%.2fM) ", ((mmap_in_use)>>10)/1024.0);
+
+
+ if(G.obedit) {
+ s = infostr;
+
+ s+= sprintf(s, "%s", G.editModeTitleExtra);
+ if(G.obedit->type==OB_MESH) {
+ if(G.scene->selectmode & SCE_SELECT_VERTEX)
+ s+= sprintf(s,"Ve:%d-%d | Ed:%d-%d | Fa:%d-%d",
+ G.totvertsel, G.totvert, G.totedgesel, G.totedge, G.totfacesel, G.totface);
+ else if(G.scene->selectmode & SCE_SELECT_EDGE)
+ s+= sprintf(s,"Ed:%d-%d | Fa:%d-%d",
+ G.totedgesel, G.totedge, G.totfacesel, G.totface);
+ else
+ s+= sprintf(s,"Fa:%d-%d", G.totfacesel, G.totface);
+ }
+ else if(G.obedit->type==OB_ARMATURE) {
+ s+= sprintf(s,"Ve:%d-%d | Bo:%d-%d", G.totvertsel, G.totvert, G.totbonesel, G.totbone);
+ }
+ else {
+ s+= sprintf(s,"Ve:%d-%d", G.totvertsel, G.totvert);
+ }
+
+ strcat(s, memstr);
+ }
+ else if(ob && (ob->flag & OB_POSEMODE)) {
+ sprintf(infostr,"Bo:%d-%d %s",
+ G.totbonesel, G.totbone, memstr);
+ }
+ else {
+ sprintf(infostr,"Ve:%d | Fa:%d | Ob:%d-%d | La:%d %s | Time:%s | ",
+ G.totvert, G.totface, G.totobj, G.totobjsel, G.totlamp, memstr, info_time_str);
+ }
+ if(ob) {
+ strcat(infostr, ob->id.name+2);
+ }
+
+ if (g_progress_bar && g_progress_info) {
+ headerstr= g_progress_info;
+ } else {
+ headerstr= versionstr;
+ }
+
+ if (g_progress_bar) {
+ hsize = 4 + (138.0 * g_done);
+ fac1 = 0.5 * g_done; /* do some rainbow colors on progress */
+ fac2 = 1.0;
+ fac3 = 0.9;
+ } else {
+ hsize= 30+BIF_GetStringWidth(G.font, headerstr, (U.transopts & USER_TR_BUTTONS));
+
+ /* promise! Never change these lines again! (zr & ton did!) */
+ fac1= fabs(hashvectf[ 2*G.version+4]);
+ fac2= 0.5+0.1*hashvectf[ G.version+3];
+ fac3= 0.7;
+ }
+
+ swatch_color= hsv_to_cpack(fac1, fac2, fac3);
+
+ cpack( swatch_color );
+ glRecti(x-24, y-6, x-30+hsize, y+14);
+
+ glColor3ub(0, 0, 0); /* makes text black colored rect */
+
+ glRasterPos2i(x, y);
+ BIF_RasterPos(x, y);
+
+ BIF_DrawString(G.font, headerstr, (U.transopts & USER_TR_MENUS));
+ hsize= BIF_GetStringWidth(G.font, headerstr, (U.transopts & USER_TR_BUTTONS));
+
+ BIF_ThemeColor(TH_MENU_TEXT); /* makes text readable on dark theme */
+
+ glRasterPos2i(x+hsize+10, y);
+ BIF_RasterPos(x+hsize+10, y);
+
+ BIF_DrawString(G.font, infostr, (U.transopts & USER_TR_MENUS));
+}
+
+void info_buttons(void)
+{
+ uiBlock *block;
+ short xco= 42;
+ int xmax;
+
+ block= uiNewBlock(&curarea->uiblocks, "header info", UI_EMBOSSN, UI_HELV, curarea->headwin);
+
+ if(area_is_active_area(curarea)) uiBlockSetCol(block, TH_HEADER);
+ else uiBlockSetCol(block, TH_HEADERDESEL);
+
+ if(curarea->flag & HEADER_NO_PULLDOWN) {
+ uiDefIconButBitS(block, TOG, HEADER_NO_PULLDOWN, B_FLIPINFOMENU, ICON_DISCLOSURE_TRI_RIGHT,
+ xco,2,XIC,YIC-2,
+ &(curarea->flag), 0, 0, 0, 0, "Enables display of pulldown menus");
+ } else {
+ uiDefIconButBitS(block, TOG, HEADER_NO_PULLDOWN, B_FLIPINFOMENU, ICON_DISCLOSURE_TRI_DOWN,
+ xco,2,XIC,YIC-2,
+ &(curarea->flag), 0, 0, 0, 0, "Hides pulldown menus");
+ }
+ xco+=XIC;
+
+ if((curarea->flag & HEADER_NO_PULLDOWN)==0) {
+
+ uiBlockSetEmboss(block, UI_EMBOSSP);
+
+ /* the 'xmax - 3' rather than xmax is to prevent some weird flickering where the highlighted
+ * menu is drawn wider than it should be. The ypos of -1 is to make it properly fill the
+ * height of the header */
+ xmax= GetButStringLength("File");
+ uiDefPulldownBut(block, info_filemenu, NULL, "File", xco, -1, xmax-3, 22, "");
+ xco+= xmax;
+
+ xmax= GetButStringLength("Add");
+ uiDefPulldownBut(block, info_addmenu, NULL, "Add", xco, -1, xmax-3, 22, "");
+ xco+= xmax;
+
+ xmax= GetButStringLength("Timeline");
+ uiDefPulldownBut(block, info_timelinemenu, NULL, "Timeline", xco, -1, xmax-3, 22, "");
+ xco+= xmax;
+
+ xmax= GetButStringLength("Game");
+ uiDefPulldownBut(block, info_gamemenu, NULL, "Game", xco, -1, xmax-3, 22, "");
+ xco+= xmax;
+
+ xmax= GetButStringLength("Render");
+ uiDefPulldownBut(block, info_rendermenu, NULL, "Render", xco, -1, xmax-3, 22, "");
+ xco+= xmax;
+
+ xmax= GetButStringLength("Help");
+ uiDefPulldownBut(block, info_helpmenu, NULL, "Help", xco, -1, xmax-3, 22, "");
+ xco+= xmax;
+
+ }
+
+ /* pack icon indicates a packed file */
+
+ if (G.fileflags & G_AUTOPACK) {
+ uiBlockSetEmboss(block, UI_EMBOSSN);
+ uiDefIconBut(block, LABEL, 0, ICON_PACKAGE, xco, 0, XIC, YIC, &G.fileflags, 0.0, 0.0, 0, 0, "Indicates this is a Packed file. See File menu.");
+ xco += XIC;
+ }
+
+ if (curarea->full == 0) {
+ curarea->butspacetype= SPACE_INFO;
+ uiBlockSetEmboss(block, UI_EMBOSS);
+ uiDefIconTextButC(block, ICONTEXTROW,B_NEWSPACE, ICON_VIEW3D, windowtype_pup(), 8,0,XIC+10,YIC, &(curarea->butspacetype), 1.0, SPACEICONMAX, 0, 0, "Displays Current Window Type. Click for menu of available types.");
+
+ /* STD SCREEN BUTTONS */
+ xco= std_libbuttons(block, xco, 0, 0, NULL, B_INFOSCR, ID_SCR, 0, (ID *)G.curscreen, 0, &G.curscreen->screennr, 1, 1, B_INFODELSCR, 0, 0);
+
+ xco +=8;
+
+ /* STD SCENE BUTTONS */
+ xco= std_libbuttons(block, xco, 0, 0, NULL, B_INFOSCE, ID_SCE, 0, (ID *)G.scene, 0, &G.curscreen->scenenr, 1, 1, B_INFODELSCE, 0, 0);
+ }
+ else xco= 430;
+
+BIF_SetScale(block->aspect);
+ info_text(xco+24, 6);
+
+ uiBlockSetEmboss(block, UI_EMBOSSN);
+ uiDefIconBut(block, BUT, B_SHOWSPLASH, ICON_BLENDER, xco+2, 0,XIC,YIC, 0, 0, 0, 0, 0, "Click to display Splash Screen");
+
+ /* always do as last */
+ curarea->headbutlen= xco+2*XIC;
+
+#if 0
+// #ifdef _WIN32 // FULLSCREEN
+ if(U.uiflag & USER_FLIPFULLSCREEN) {
+ uiDefIconBut(block, BUT, B_FLIPFULLSCREEN, ICON_WINDOW_WINDOW,
+ (short)(curarea->winx-XIC-5), 0,XIC,YIC,
+ 0, 0, 0, 0, 0, "Toggles Blender to fullscreen mode");/* dir */
+ } else {
+ uiDefIconBut(block, BUT, B_FLIPFULLSCREEN, ICON_WINDOW_FULLSCREEN,
+ (short)(curarea->winx-XIC-5), 0,XIC,YIC,
+ 0, 0, 0, 0, 0, "Toggles Blender to fullscreen mode");/* dir */
+ }
+#endif
+
+ uiDrawBlock(block);
+}
diff --git a/source/blender/src/header_ipo.c b/source/blender/src/header_ipo.c
new file mode 100644
index 00000000000..d2b16da3b35
--- /dev/null
+++ b/source/blender/src/header_ipo.c
@@ -0,0 +1,1365 @@
+/**
+ * header_ipo.c oct-2003
+ *
+ * Functions to draw the "Ipo Curve Editor" window header
+ * and handle user events sent to it.
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "DNA_action_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_ID.h"
+#include "DNA_ipo_types.h"
+#include "DNA_key_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_material_types.h"
+#include "DNA_object_types.h"
+#include "DNA_object_fluidsim.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_space_types.h"
+#include "DNA_sequence_types.h"
+#include "DNA_sound_types.h"
+#include "DNA_world_types.h"
+
+#include "BKE_action.h"
+#include "BKE_constraint.h"
+#include "BKE_global.h"
+#include "BKE_ipo.h"
+#include "BKE_key.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
+
+#include "BLI_blenlib.h"
+
+#include "BSE_drawipo.h"
+#include "BSE_editipo_types.h"
+#include "BSE_edit.h"
+#include "BSE_editipo.h"
+#include "BSE_headerbuttons.h"
+#include "BSE_time.h"
+
+#include "BIF_editaction.h"
+#include "BIF_interface.h"
+#include "BIF_mainqueue.h"
+#include "BIF_resources.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_toolbox.h"
+
+#include "nla.h"
+
+#include "blendef.h"
+#include "mydevice.h"
+
+extern int totipo_edit, totipo_sel;
+
+/* headerbutton call, assuming full context is set */
+/* it aligns with editipo.c, verify_ipo */
+void spaceipo_assign_ipo(SpaceIpo *si, Ipo *ipo)
+{
+ if(si->from==NULL || si->from->lib) return;
+
+ if(ipo) ipo->id.us++;
+
+ /* first check action ipos */
+ if(si->actname && si->actname[0]) {
+ Object *ob= (Object *)si->from;
+ bActionChannel *achan;
+
+ if(ob->action) {
+ achan= verify_action_channel(ob->action, si->actname);
+
+ if(achan) {
+ /* constraint exception */
+ if(si->blocktype==ID_CO) {
+ bConstraintChannel *conchan= get_constraint_channel(&achan->constraintChannels, si->constname);
+ if(conchan) {
+ if(conchan->ipo)
+ conchan->ipo->id.us--;
+ conchan->ipo= ipo;
+ }
+ }
+ else {
+ if(achan->ipo)
+ achan->ipo->id.us--;
+ achan->ipo= ipo;
+ }
+ }
+ }
+ }
+ else {
+ switch(GS(si->from->name)) {
+ case ID_OB:
+ {
+ Object *ob= (Object *)si->from;
+ /* constraint exception */
+ if(si->blocktype==ID_CO) {
+ bConstraintChannel *conchan= get_constraint_channel(&ob->constraintChannels, si->constname);
+ if(conchan) {
+ if(conchan->ipo)
+ conchan->ipo->id.us--;
+ conchan->ipo= ipo;
+ }
+ }
+ else if(si->blocktype==ID_FLUIDSIM) { // NT
+ if( (ob->fluidsimSettings) &&
+ (ob->fluidsimSettings->ipo) ) {
+ // decrement users counter
+ ob->fluidsimSettings->ipo->id.us--;
+ }
+ ob->fluidsimSettings->ipo = ipo;
+ }
+ else if(si->blocktype==ID_OB) {
+ if(ob->ipo)
+ ob->ipo->id.us--;
+ ob->ipo= ipo;
+ }
+ }
+ break;
+ case ID_MA:
+ {
+ Material *ma= (Material *)si->from;
+
+ if(ma->ipo)
+ ma->ipo->id.us--;
+ ma->ipo= ipo;
+ }
+ break;
+ case ID_TE:
+ {
+ Tex *tex= (Tex *)si->from;
+
+ if(tex->ipo)
+ tex->ipo->id.us--;
+ tex->ipo= ipo;
+ }
+ break;
+ case ID_SEQ:
+ {
+ Sequence *seq= (Sequence *)si->from; /* note, sequence is mimicing Id */
+
+ if((seq->type & SEQ_EFFECT)
+ || (seq->type == SEQ_RAM_SOUND)
+ || (seq->type == SEQ_HD_SOUND)) {
+ if(seq->ipo)
+ seq->ipo->id.us--;
+ seq->ipo= ipo;
+ }
+ }
+ break;
+ case ID_CU:
+ {
+ Curve *cu= (Curve *)si->from;
+
+ if(cu->ipo)
+ cu->ipo->id.us--;
+ cu->ipo= ipo;
+ }
+ break;
+ case ID_KE:
+ {
+ Key *key= (Key *)si->from;
+
+ if(key->ipo)
+ key->ipo->id.us--;
+ key->ipo= ipo;
+ }
+ break;
+ case ID_WO:
+ {
+ World *wo= (World *)si->from;
+
+ if(wo->ipo)
+ wo->ipo->id.us--;
+ wo->ipo= ipo;
+ }
+ break;
+ case ID_LA:
+ {
+ Lamp *la= (Lamp *)si->from;
+
+ if(la->ipo)
+ la->ipo->id.us--;
+ la->ipo= ipo;
+ }
+ break;
+ case ID_CA:
+ {
+ Camera *ca= (Camera *)si->from;
+
+ if(ca->ipo)
+ ca->ipo->id.us--;
+ ca->ipo= ipo;
+ }
+ break;
+ case ID_SO:
+ {
+ bSound *snd= (bSound *)si->from;
+
+ if(snd->ipo)
+ snd->ipo->id.us--;
+ snd->ipo= ipo;
+ }
+ }
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWNLA, 0);
+ allqueue(REDRAWBUTSALL, 0);
+
+}
+
+
+static void do_ipo_editmenu_transformmenu(void *arg, int event)
+{
+ switch(event)
+ {
+ case 0: /* grab/move */
+ transform_ipo('g');
+ break;
+ case 1: /* rotate */
+ transform_ipo('r');
+ break;
+ case 2: /* scale */
+ transform_ipo('s');
+ break;
+ }
+}
+
+static uiBlock *ipo_editmenu_transformmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "ipo_editmenu_transformmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_ipo_editmenu_transformmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Grab/Move|G", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Rotate|R", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Scale|S", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+
+ return block;
+}
+
+static void do_ipo_editmenu_snapmenu(void *arg, int event)
+{
+ switch(event) {
+ case 1: /* Horizontal */
+ case 2: /* To Next */
+ case 3: /* To Frame */
+ case 4: /* To Current Frame */
+ ipo_snap(event);
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *ipo_editmenu_snapmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "ipo_editmenu_snapmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_ipo_editmenu_snapmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Horizontal|Shift S, 1", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "To Next|Shift S, 2", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "To Frame|Shift S, 3", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "To Current Frame|Shift S, 4", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+static void do_ipo_editmenu_mirrormenu(void *arg, int event)
+{
+ switch(event) {
+ case 1: /* mirror over current frame */
+ case 2: /* mirror over frame 0 */
+ case 3: /* mirror over horizontal axis */
+ ipo_mirror(event);
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *ipo_editmenu_mirrormenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "ipo_editmenu_mirrormenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_ipo_editmenu_mirrormenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Over Current Frame|Shift M, 1", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Over Vertical Axis|Shift M, 2", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Over Horizontal Axis|Shift M, 3", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+static void do_ipo_editmenu_joinmenu(void *arg, int event)
+{
+ switch(event) {
+ case 1: /* All Selected */
+ case 2: /* Selected Doubles */
+ join_ipo(event);
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *ipo_editmenu_joinmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "ipo_editmenu_joinmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_ipo_editmenu_joinmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "All Selected|Ctrl J, 1", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Selected Doubles|Ctrl J, 2", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+static void do_ipo_editmenu_keymenu(void *arg, int event)
+{
+ Key *key;
+ KeyBlock *kb;
+ Object *ob= OBACT;
+
+ if(G.sipo->blocktype==ID_KE && totipo_edit==0 && totipo_sel==0) {
+ key= ob_get_key((Object *)G.sipo->from);
+ if(key==NULL) return;
+
+ kb= BLI_findlink(&key->block, ob->shapenr-1);
+ kb->type= 0;
+ switch(event){
+ case 0:
+ kb->type= KEY_LINEAR;
+ break;
+ case 1:
+ kb->type= KEY_CARDINAL;
+ break;
+ case 2:
+ kb->type= KEY_BSPLINE;
+ break;
+ }
+ }
+}
+
+static uiBlock *ipo_editmenu_keymenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "ipo_editmenu_keymenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_ipo_editmenu_keymenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Linear|T, 1", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Cardinal|T, 2", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "BSpline|T, 3", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+
+ return block;
+
+}
+
+static void do_ipo_editmenu_handlemenu(void *arg, int event)
+{
+ switch(event){
+ case 0:
+ sethandles_ipo(HD_AUTO);
+ break;
+ case 1:
+ case 2:
+ sethandles_ipo(HD_ALIGN);
+ break;
+ case 3:
+ sethandles_ipo(HD_VECT);
+ break;
+ case 4:
+ sethandles_ipo(HD_AUTO_ANIM);
+ break;
+ }
+}
+
+static uiBlock *ipo_editmenu_handlemenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "ipo_editmenu_handlemenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_ipo_editmenu_handlemenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Auto|Shift H", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Auto Clamped|Alt H", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Aligned|H", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Free|H", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Vector|V", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+
+ return block;
+}
+
+static void do_ipo_editmenu_intpolmenu(void *arg, int event)
+{
+ EditIpo *ei;
+ int a;
+
+ get_status_editipo();
+
+ ei = G.sipo->editipo;
+
+ switch(event)
+ {
+ case 0:
+ for(a=0; a<G.sipo->totipo; a++, ei++) {
+ if ISPOIN3(ei, flag & IPO_VISIBLE, flag & IPO_SELECT, icu) {
+ ei->icu->ipo= IPO_CONST;
+ }
+ }
+ break;
+ case 1:
+ for(a=0; a<G.sipo->totipo; a++, ei++) {
+ if ISPOIN3(ei, flag & IPO_VISIBLE, flag & IPO_SELECT, icu) {
+ ei->icu->ipo= IPO_LIN;
+ }
+ }
+ break;
+ case 2:
+ for(a=0; a<G.sipo->totipo; a++, ei++) {
+ if ISPOIN3(ei, flag & IPO_VISIBLE, flag & IPO_SELECT, icu) {
+ ei->icu->ipo= IPO_BEZ;
+ }
+ }
+ break;
+ }
+
+ scrarea_queue_winredraw(curarea);
+}
+
+static uiBlock *ipo_editmenu_intpolmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "ipo_editmenu_intpolmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_ipo_editmenu_intpolmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Constant|T, 1", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Linear|T, 2", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Bezier|T, 3", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+
+ return block;
+}
+
+static void do_ipo_editmenu_extendmenu(void *arg, int event)
+{
+ switch(event)
+ {
+ case 0:
+ do_ipo_buttons(B_IPOCONT);
+ break;
+ case 1:
+ do_ipo_buttons(B_IPOEXTRAP);
+ break;
+ case 2:
+ do_ipo_buttons(B_IPOCYCLIC);
+ break;
+ case 3:
+ do_ipo_buttons(B_IPOCYCLICX);
+ break;
+ }
+}
+
+static uiBlock *ipo_editmenu_extendmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "ipo_editmenu_extendmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_ipo_editmenu_extendmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Constant", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Extrapolation", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Cyclic", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Cyclic Extrapolation", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+
+ return block;
+}
+
+
+static void do_ipo_editmenu(void *arg, int event)
+{
+ switch(event)
+ {
+ case 0:
+ del_ipo(1);
+ break;
+ case 1:
+ add_duplicate_editipo();
+ break;
+ case 2:
+ ipo_record();
+ break;
+ case 3:
+ mainqenter(IKEY, 1);
+ break;
+ case 4 :
+ add_blockhandler(curarea, IPO_HANDLER_PROPERTIES, UI_PNL_UNSTOW);
+ break;
+ case 5:
+ //join_ipo();
+ break;
+ case 6:
+ /*IPO Editmode*/
+ set_editflag_editipo();
+ break;
+ case 7:
+ sethandles_ipo(HD_AUTO_ANIM);
+ break;
+ case 8: /* clean ipo */
+ clean_ipo();
+ break;
+ case 9: /* smooth ipo */
+ smooth_ipo();
+ break;
+ }
+}
+
+static uiBlock *ipo_editmenu(void *arg_unused)
+{
+ uiBlock *block;
+ EditIpo *ei;
+ short yco= 0, menuwidth=120;
+ int a,isedit = 0;
+
+ get_status_editipo();
+
+ ei = G.sipo->editipo;
+
+ block= uiNewBlock(&curarea->uiblocks, "ipo_editmenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_ipo_editmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_MENU_PANEL, "Transform Properties|N", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
+
+ uiDefIconTextBlockBut(block, ipo_editmenu_transformmenu, NULL, ICON_RIGHTARROW_THIN, "Transform", 0, yco-=20, 120, 19, "");
+
+ uiDefIconTextBlockBut(block, ipo_editmenu_snapmenu, NULL, ICON_RIGHTARROW_THIN, "Snap", 0, yco-=20, 120, 19, "");
+
+ uiDefIconTextBlockBut(block, ipo_editmenu_mirrormenu, NULL, ICON_RIGHTARROW_THIN, "Mirror", 0, yco-=20, 120, 19, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ /*Look to see if any ipos are being edited, so there can be a check next to the menu option*/
+ for(a=0; a<G.sipo->totipo; a++, ei++) {
+ if(ei->icu) {
+ if(ei->flag & IPO_VISIBLE) {
+ if(totipo_edit && (ei->flag & IPO_EDIT)) {
+ isedit = 1;
+ break;
+ }
+ }
+ }
+ }
+ if(isedit)
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Edit Selected|TAB", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 6, "");
+ else
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Edit Selected|TAB", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 6, "");
+
+ ei = get_active_editipo();
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ if(ei && ei->icu && ei->icu->driver)
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Insert 1:1 Curve...|I", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
+ else
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Insert Keyframe...|I", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Duplicate|Shift D", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Record Mouse Movement|Ctrl R", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Clean IPO Curves|O", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 8, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Smooth IPO Curves|Shift O", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 9, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Delete|X", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBlockBut(block, ipo_editmenu_joinmenu, NULL, ICON_RIGHTARROW_THIN, "Join", 0, yco-=20, 120, 19, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Auto Clamped Handles|Alt H", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 7, "");
+
+ if (!G.sipo->showkey){
+ uiDefIconTextBlockBut(block, ipo_editmenu_extendmenu, NULL, ICON_RIGHTARROW_THIN, "Extend Mode", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, ipo_editmenu_intpolmenu, NULL, ICON_RIGHTARROW_THIN, "Interpolation Mode ", 0, yco-=20, 120, 20, "");
+ if(ei != NULL && (ei->flag & IPO_EDIT))
+ uiDefIconTextBlockBut(block, ipo_editmenu_handlemenu, NULL, ICON_RIGHTARROW_THIN, "Handle Type", 0, yco-=20, 120, 19, "");
+ if(G.sipo->blocktype==ID_KE && totipo_edit==0 && totipo_sel==0)
+ uiDefIconTextBlockBut(block, ipo_editmenu_keymenu, NULL, ICON_RIGHTARROW_THIN, "Key Type", 0, yco-=20, 120, 19, "");
+ }
+
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+static void do_ipo_viewmenu(void *arg, int event)
+{
+ extern int play_anim(int mode);
+
+ switch(event)
+ {
+ case 1:
+ do_ipo_buttons(B_IPOHOME);
+ break;
+ case 2:
+ ipo_toggle_showkey();
+ scrarea_queue_headredraw(curarea);
+ scrarea_queue_winredraw(curarea);
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+ case 3:
+ move_to_frame();
+ break;
+ case 4:
+ mainqenter(PADPLUSKEY,1);
+ break;
+ case 5:
+ mainqenter(PADMINUS,1);
+ break;
+ case 6: /* Play Animation */
+ play_anim(0);
+ break;
+ case 7: /* Play Animation in All */
+ play_anim(1);
+ break;
+ case 8:
+ add_blockhandler(curarea, IPO_HANDLER_PROPERTIES, UI_PNL_UNSTOW);
+ break;
+ case 9:
+ G.v2d->flag ^= V2D_VIEWLOCK;
+ if(G.v2d->flag & V2D_VIEWLOCK)
+ view2d_do_locks(curarea, 0);
+ break;
+ case 10: /* center view to current frame */
+ center_currframe();
+ scrarea_queue_winredraw(curarea);
+ break;
+ case 11:
+ do_ipo_buttons(B_IPOVIEWCENTER);
+ break;
+ }
+}
+
+static uiBlock *ipo_viewmenu(void *arg_unused)
+{
+ uiBlock *block;
+ EditIpo *ei;
+ short yco= 0, menuwidth=120;
+
+ ei = get_active_editipo();
+
+ block= uiNewBlock(&curarea->uiblocks, "ipo_viewmenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_ipo_viewmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_MENU_PANEL, "Channel Properties|N", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 8, "");
+
+ if (G.sipo->showkey)
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Show Keys|K", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
+ else
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Show Keys|K", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Zoom Out|NumPad -", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 5, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Zoom In|NumPad +", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Play Animation|Alt A", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, 6, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Play Animation in 3D View|Alt Shift A", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, 7, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Center on Current Frame|Shift C", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 10, "");
+ uiDefIconTextBut(block, BUTM, 1, (G.v2d->flag & V2D_VIEWLOCK)?ICON_CHECKBOX_HLT:ICON_CHECKBOX_DEHLT,
+ "Lock Time to Other Windows|", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 9, "");
+
+ if (ei != NULL && (ei->flag & IPO_EDIT)) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Move Current Frame to Selected|C", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
+ }
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "View Selected|NumPad .", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 11, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "View All|Home", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
+ if(!curarea->full) uiDefIconTextBut(block, BUTM, B_FULL, ICON_BLANK1, "Maximize Window|Ctrl UpArrow", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0,20, "");
+ else uiDefIconTextBut(block, BUTM, B_FULL, ICON_BLANK1, "Tile Window|Ctrl DownArrow", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 20, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+static void do_ipo_selectmenu(void *arg, int event)
+{
+ switch(event)
+ {
+ case 0:
+ borderselect_ipo();
+ break;
+ case 1:
+ swap_selectall_editipo();
+ break;
+ case 2:
+ borderselect_markers();
+ allqueue(REDRAWMARKER, 0);
+ break;
+ case 3:
+ deselect_markers(1, 0);
+ allqueue(REDRAWMARKER, 0);
+ break;
+ }
+}
+
+static uiBlock *ipo_selectmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "ipo_selectmenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_ipo_selectmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Border Select|B", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Border Select Markers|Ctrl B", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select/Deselect All|A", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select/Deselect All Markers|Ctrl A", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+static void do_ipo_markermenu(void *arg, int event)
+{
+ switch(event)
+ {
+ case 1:
+ add_marker(CFRA);
+ break;
+ case 2:
+ duplicate_marker();
+ break;
+ case 3:
+ remove_marker();
+ break;
+ case 4:
+ rename_marker();
+ break;
+ case 5:
+ transform_markers('g', 0);
+ break;
+ }
+
+ allqueue(REDRAWMARKER, 0);
+}
+
+static uiBlock *ipo_markermenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "ipo_markermenu",
+ UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_ipo_markermenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Add Marker|M", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Duplicate Marker|Ctrl Shift D", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Delete Marker|X", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "(Re)Name Marker|Ctrl M", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Grab/Move Marker|Ctrl G", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+static char *ipo_modeselect_pup(void)
+{
+ Object *ob= OBACT;
+ static char formatstring[] = "|%s %%x%d %%i%d";
+ static char string[1024];
+ char *str = string;
+
+ str += sprintf(str, "Ipo type: %%t");
+
+ if(ob)
+ str += sprintf(str,formatstring, "Object",ID_OB, ICON_OBJECT);
+
+ if(ob && give_current_material(ob, ob->actcol)) // check for material
+ str += sprintf(str,formatstring, "Material",ID_MA, ICON_MATERIAL);
+
+ if(G.scene->world)
+ str += sprintf(str,formatstring, "World",ID_WO, ICON_WORLD);
+
+ if(ob && ob->type==OB_CURVE)
+ str += sprintf(str,formatstring, "Path",ID_CU, ICON_CURVE);
+
+ if(ob && ob->type==OB_CAMERA)
+ str += sprintf(str,formatstring, "Camera",ID_CA, ICON_CAMERA);
+
+ if(ob && ob->type==OB_LAMP)
+ str += sprintf(str,formatstring, "Lamp",ID_LA, ICON_LAMP);
+
+ if(ob && give_current_texture(ob, ob->actcol))
+ str += sprintf(str,formatstring, "Texture",ID_TE, ICON_TEXTURE);
+
+ if(ob){
+ if ELEM4(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_LATTICE)
+ str += sprintf(str,formatstring, "Shape",ID_KE, ICON_EDIT);
+ if (ob->type==OB_ARMATURE)
+ str += sprintf(str,formatstring, "Pose",ID_PO, ICON_POSE_HLT);
+#ifdef __CON_IPO
+ str += sprintf(str,formatstring, "Constraint",ID_CO, ICON_CONSTRAINT);
+#endif
+ if(ob->fluidsimFlag & OB_FLUIDSIM_ENABLE) {
+ str += sprintf(str,formatstring,"Fluidsim",ID_FLUIDSIM, ICON_WORLD);
+ }
+ }
+
+ str += sprintf(str,formatstring, "Sequence",ID_SEQ, ICON_SEQUENCE);
+
+ return (string);
+}
+
+void do_ipo_buttons(short event)
+{
+ EditIpo *ei;
+ View2D *v2d;
+ rcti rect;
+ Object *ob= OBACT;
+ float xmin, ymin, dx, dy;
+ int a, val, first;
+ short mval[2];
+
+ if(curarea->win==0) return;
+
+ switch(event) {
+ case B_IPOVIEWCENTER:
+ case B_IPOHOME:
+
+ /* boundbox */
+
+ v2d= &(G.sipo->v2d);
+ first= 1;
+
+ ei= G.sipo->editipo;
+ if(ei==0) return;
+
+ /* map ipo-points for drawing if scaled ipo */
+ if (OBACT && OBACT->action && G.sipo->pin==0 && G.sipo->actname) {
+ actstrip_map_ipo_keys(OBACT, G.sipo->ipo, 0, 0);
+ }
+
+ for(a=0; a<G.sipo->totipo; a++, ei++) {
+ if ISPOIN(ei, flag & IPO_VISIBLE, icu) {
+
+ boundbox_ipocurve(ei->icu, (event==B_IPOVIEWCENTER));
+
+ if(first) {
+ v2d->tot= ei->icu->totrct;
+ first= 0;
+ }
+ else BLI_union_rctf(&(v2d->tot), &(ei->icu->totrct));
+ }
+ }
+
+ /* undo mapping of ipo-points for drawing if scaled ipo */
+ if (OBACT && OBACT->action && G.sipo->pin==0 && G.sipo->actname) {
+ actstrip_map_ipo_keys(OBACT, G.sipo->ipo, 1, 0);
+ }
+
+ /* speciale home */
+ if(G.qual & LR_SHIFTKEY) {
+ v2d->tot.xmin= SFRA;
+ v2d->tot.xmax= EFRA;
+ }
+
+ /* zoom out a bit */
+ dx= 0.10*(v2d->tot.xmax-v2d->tot.xmin);
+ dy= 0.10*(v2d->tot.ymax-v2d->tot.ymin);
+
+ if(dx<v2d->min[0]) dx= v2d->min[0];
+ if(dy<v2d->min[1]) dy= v2d->min[1];
+
+ v2d->cur.xmin= v2d->tot.xmin- dx;
+ v2d->cur.xmax= v2d->tot.xmax+ dx;
+ v2d->cur.ymin= v2d->tot.ymin- dy;
+ v2d->cur.ymax= v2d->tot.ymax+ dy;
+
+ test_view2d(G.v2d, curarea->winx, curarea->winy);
+ view2d_do_locks(curarea, V2D_LOCK_COPY);
+ if(G.sipo->ipo) G.sipo->ipo->cur = G.v2d->cur;
+
+ scrarea_queue_winredraw(curarea);
+ break;
+ case B_IPOBORDER:
+ val= get_border(&rect, 3);
+ if(val) {
+ mval[0]= rect.xmin;
+ mval[1]= rect.ymin;
+ areamouseco_to_ipoco(G.v2d, mval, &xmin, &ymin);
+ mval[0]= rect.xmax;
+ mval[1]= rect.ymax;
+ areamouseco_to_ipoco(G.v2d, mval, &(G.v2d->cur.xmax), &(G.v2d->cur.ymax));
+ G.v2d->cur.xmin= xmin;
+ G.v2d->cur.ymin= ymin;
+
+ test_view2d(G.v2d, curarea->winx, curarea->winy);
+ view2d_do_locks(curarea, V2D_LOCK_COPY);
+ scrarea_queue_winredraw(curarea);
+ }
+ break;
+
+ case B_IPOPIN:
+ allqueue (REDRAWIPO, 0);
+ break;
+
+ case B_IPOCOPY:
+ copy_editipo();
+ break;
+ case B_IPOPASTE:
+ paste_editipo();
+ break;
+ case B_IPOCONT:
+ set_exprap_ipo(IPO_HORIZ);
+ break;
+ case B_IPOEXTRAP:
+ set_exprap_ipo(IPO_DIR);
+ break;
+ case B_IPOCYCLIC:
+ set_exprap_ipo(IPO_CYCL);
+ break;
+ case B_IPOCYCLICX:
+ set_exprap_ipo(IPO_CYCLX);
+ break;
+ case B_IPOMAIN:
+ /* pass 1 to enforce a refresh when there's no Ipo */
+ test_editipo(1);
+ scrarea_queue_winredraw(curarea);
+ scrarea_queue_headredraw(curarea);
+ if(ob) ob->ipowin= G.sipo->blocktype;
+ break;
+ case B_IPOSHOWKEY:
+ /* reverse value because of winqread */
+ G.sipo->showkey= 1-G.sipo->showkey;
+ ipo_toggle_showkey();
+ scrarea_queue_headredraw(curarea);
+ scrarea_queue_winredraw(curarea);
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+ case B_VIEW2DZOOM:
+ view2dzoom(event);
+ scrarea_queue_headredraw(curarea);
+ break;
+ case B_IPO_ACTION_OB:
+ if(ob && G.sipo->from && G.sipo->pin==0) {
+ if(ob->ipoflag & OB_ACTION_OB) { /* check if channel exists, and flip ipo link */
+ bActionChannel *achan;
+
+ if(has_ipo_code(ob->ipo, OB_LAY))
+ notice("Note: Layer Ipo doesn't work in Actions");
+
+ if(ob->action==NULL)
+ ob->action= add_empty_action("ObAction");
+ achan= verify_action_channel(ob->action, "Object");
+ if(achan->ipo==NULL && ob->ipo) {
+ achan->ipo= ob->ipo;
+ ob->ipo= NULL;
+ }
+
+ /* object constraints */
+ if(ob->constraintChannels.first) {
+ free_constraint_channels(&achan->constraintChannels);
+ achan->constraintChannels= ob->constraintChannels;
+ ob->constraintChannels.first= ob->constraintChannels.last= NULL;
+ }
+ }
+ else if(ob->action) {
+ bActionChannel *achan= get_action_channel(ob->action, "Object");
+ if(achan) {
+
+ if(achan->ipo && ob->ipo==NULL) {
+ ob->ipo= achan->ipo;
+ achan->ipo= NULL;
+ }
+
+ /* object constraints */
+ if(achan->constraintChannels.first) {
+ free_constraint_channels(&ob->constraintChannels);
+ ob->constraintChannels= achan->constraintChannels;
+ achan->constraintChannels.first= achan->constraintChannels.last= NULL;
+ }
+ }
+ }
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWOOPS, 0);
+ allqueue(REDRAWNLA, 0);
+ }
+ break;
+
+ case B_IPO_ACTION_KEY:
+ if(ob && G.sipo->from && G.sipo->pin==0) {
+ Key *key= ob_get_key(ob);
+ if(key) {
+ if(ob->ipoflag & OB_ACTION_KEY) { /* check if channel exists, and flip ipo link */
+ bActionChannel *achan;
+
+ if(ob->action==NULL)
+ ob->action= add_empty_action("ShapeAction");
+ achan= verify_action_channel(ob->action, "Shape");
+ if(achan->ipo==NULL && key->ipo) {
+ achan->ipo= key->ipo;
+ key->ipo= NULL;
+ }
+ }
+ else if(ob->action) {
+ bActionChannel *achan= get_action_channel(ob->action, "Shape");
+ if(achan) {
+ if(achan->ipo && key->ipo==NULL) {
+ key->ipo= achan->ipo;
+ achan->ipo= NULL;
+ }
+ }
+ }
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWOOPS, 0);
+ allqueue(REDRAWNLA, 0);
+ }
+ }
+ break;
+ case B_IPOVIEWALL:
+ /* set visible active */
+ for(a=0, ei=G.sipo->editipo; a<G.sipo->totipo; a++, ei++) {
+ if (ei->icu) ei->flag |= IPO_VISIBLE;
+ else ei->flag &= ~IPO_VISIBLE;
+ }
+ break;
+ }
+}
+
+void ipo_buttons(void)
+{
+ Object *ob;
+ EditIpo *ei;
+ uiBlock *block;
+ short xco,xmax;
+ char naam[20];
+ int icon=0, allow_pin= B_IPOPIN;
+
+ sprintf(naam, "header %d", curarea->headwin);
+ block= uiNewBlock(&curarea->uiblocks, naam, UI_EMBOSS, UI_HELV, curarea->headwin);
+
+ if(area_is_active_area(curarea)) uiBlockSetCol(block, TH_HEADER);
+ else uiBlockSetCol(block, TH_HEADERDESEL);
+
+ curarea->butspacetype= SPACE_IPO;
+
+ xco = 8;
+ uiDefIconTextButC(block, ICONTEXTROW,B_NEWSPACE, ICON_VIEW3D, windowtype_pup(), xco,0,XIC+10,YIC, &(curarea->butspacetype), 1.0, SPACEICONMAX, 0, 0, "Displays Current Window Type. Click for menu of available types.");
+ xco+= XIC+14;
+
+ test_editipo(0); /* test if current editipo is OK, make_editipo sets v2d->cur */
+
+ uiBlockSetEmboss(block, UI_EMBOSSN);
+ if(curarea->flag & HEADER_NO_PULLDOWN) {
+ uiDefIconButBitS(block, TOG, HEADER_NO_PULLDOWN, B_FLIPINFOMENU, ICON_DISCLOSURE_TRI_RIGHT,
+ xco,2,XIC,YIC-2,
+ &(curarea->flag), 0, 0, 0, 0, "Enables display of pulldown menus");
+ } else {
+ uiDefIconButBitS(block, TOG, HEADER_NO_PULLDOWN, B_FLIPINFOMENU, ICON_DISCLOSURE_TRI_DOWN,
+ xco,2,XIC,YIC-2,
+ &(curarea->flag), 0, 0, 0, 0, "Hides pulldown menus");
+ }
+ uiBlockSetEmboss(block, UI_EMBOSS);
+ xco+=XIC;
+
+ /* pull down menus */
+ if((curarea->flag & HEADER_NO_PULLDOWN)==0) {
+ uiBlockSetEmboss(block, UI_EMBOSSP);
+
+ ei = get_active_editipo();
+
+ xmax= GetButStringLength("View");
+ uiDefPulldownBut(block,ipo_viewmenu, NULL, "View", xco, -2, xmax-3, 24, "");
+ xco+=xmax;
+
+ xmax= GetButStringLength("Select");
+ uiDefPulldownBut(block,ipo_selectmenu, NULL, "Select", xco, -2, xmax-3, 24, "");
+ xco+=xmax;
+
+ xmax= GetButStringLength("Marker");
+ uiDefPulldownBut(block,ipo_markermenu, NULL, "Marker", xco, -2, xmax-3, 24, "");
+ xco+=xmax;
+
+ if (G.sipo->showkey) {
+ xmax= GetButStringLength("Key");
+ uiDefPulldownBut(block,ipo_editmenu, NULL, "Key", xco, -2, xmax-3, 24, "");
+ }
+ else if(ei != NULL && (ei->flag & IPO_EDIT)) {
+ xmax= GetButStringLength("Point");
+ uiDefPulldownBut(block,ipo_editmenu, NULL, "Point", xco, -2, xmax-3, 24, "");
+ }
+ else {
+ xmax= GetButStringLength("Curve");
+ uiDefPulldownBut(block,ipo_editmenu, NULL, "Curve", xco, -2, xmax-3, 24, "");
+ }
+ xco+=xmax;
+ }
+
+ /* end of pull down menus */
+ uiBlockSetEmboss(block, UI_EMBOSS);
+
+ ob= OBACT;
+
+ /* action switch option, only when active object is there and no pin */
+ uiSetButLock(G.sipo->pin, "Can't change because of pinned data");
+
+ /* define whether ipos are on Object or on action */
+ if(ob) {
+ static short fake1= 1;
+
+ uiBlockBeginAlign(block);
+
+ if(G.sipo->blocktype==ID_OB) {
+ uiDefIconButBitS(block, TOG, OB_ACTION_OB, B_IPO_ACTION_OB, ICON_ACTION, xco,0,XIC,YIC, &(ob->ipoflag), 0, 0, 0, 0, "Sets Ipo to be included in an Action or not");
+ xco+= XIC;
+ }
+ else if(G.sipo->blocktype==ID_KE) {
+ uiDefIconButBitS(block, TOG, OB_ACTION_KEY, B_IPO_ACTION_KEY, ICON_ACTION, xco,0,XIC,YIC, &(ob->ipoflag), 0, 0, 0, 0, "Sets Ipo to be included in an Action or not");
+ xco+= XIC;
+ }
+ else if(G.sipo->blocktype==ID_CO) {
+
+ if(G.sipo->from && G.sipo->actname[0]==0)
+ uiDefIconButBitS(block, TOG, OB_ACTION_OB, B_IPO_ACTION_OB, ICON_ACTION, xco,0,XIC,YIC, &(ob->ipoflag), 0, 0, 0, 0, "Sets Ipo to be included in an Action or not");
+ else {
+ uiSetButLock(1, "Pose Constraint Ipo cannot be switched");
+ uiDefIconButS(block, TOG, 1, ICON_ACTION, xco,0,XIC,YIC, &fake1, 0, 0, 0, 0, "Ipo is connected to Pose Action");
+ }
+ xco+= XIC;
+ }
+ else if(G.sipo->blocktype==ID_PO) { /* only to indicate we have action ipos */
+ uiSetButLock(1, "Pose Action Ipo cannot be switched");
+ uiDefIconButS(block, TOG, 1, ICON_ACTION, xco,0,XIC,YIC, &fake1, 0, 0, 0, 0, "Ipo is connected to Pose Action");
+ xco+= XIC;
+ }
+ uiClearButLock();
+ }
+
+ /* ipo muting */
+ if (G.sipo->ipo) {
+ uiDefIconButS(block, ICONTOG, 1, ICON_MUTE_IPO_OFF, xco,0,XIC,YIC, &(G.sipo->ipo->muteipo), 0, 0, 0, 0, "Mute IPO-block");
+ xco += XIC;
+ }
+
+ /* mainmenu, only when data is there and no pin */
+ uiSetButLock(G.sipo->pin, "Can't change because of pinned data");
+
+ if (G.sipo->blocktype == ID_OB)
+ icon = ICON_OBJECT;
+ else if (G.sipo->blocktype == ID_MA)
+ icon = ICON_MATERIAL;
+ else if (G.sipo->blocktype == ID_WO)
+ icon = ICON_WORLD;
+ else if (G.sipo->blocktype == ID_CU)
+ icon = ICON_ANIM;
+ else if (G.sipo->blocktype == ID_CA)
+ icon = ICON_CAMERA;
+ else if (G.sipo->blocktype == ID_LA)
+ icon = ICON_LAMP;
+ else if (G.sipo->blocktype == ID_KE)
+ icon = ICON_EDIT;
+ else if (G.sipo->blocktype == ID_PO)
+ icon = ICON_POSE_HLT;
+ else if (G.sipo->blocktype == ID_CO)
+ icon = ICON_CONSTRAINT;
+ else if (G.sipo->blocktype == ID_SEQ)
+ icon = ICON_SEQUENCE;
+ else if(G.sipo->blocktype == ID_TE)
+ icon = ICON_TEXTURE;
+ else if(G.sipo->blocktype == ID_FLUIDSIM)
+ icon = ICON_WORLD;
+
+ uiDefIconTextButS(block, MENU, B_IPOMAIN, icon, ipo_modeselect_pup(), xco,0,100,20, &(G.sipo->blocktype), 0, 0, 0, 0, "Show IPO type");
+
+ xco += 85;
+
+ if(G.sipo->blocktype==ID_MA) {
+ uiDefButS(block, NUM, B_IPOMAIN, "", xco+=XIC,0,XIC-4,YIC, &G.sipo->channel, 0.0, MAX_MTEX-1.0, 0, 0, "Channel Number of the active Material texture.");
+ xco-= 4;
+ }
+ if(G.sipo->blocktype==ID_WO) {
+ uiDefButS(block, NUM, B_IPOMAIN, "", xco+=XIC,0,XIC-4,YIC, &G.sipo->channel, 0.0, MAX_MTEX-1.0, 0, 0, "Channel Number of the active World texture.");
+ xco-= 4;
+ }
+
+ if(G.sipo->blocktype==ID_LA) {
+ uiDefButS(block, NUM, B_IPOMAIN, "", xco+=XIC,0,XIC-4,YIC, &G.sipo->channel, 0.0, MAX_MTEX-1.0, 0, 0, "Channel Number of the active Lamp texture. ");
+ xco-= 4;
+ }
+
+ uiBlockEndAlign(block);
+
+ uiClearButLock();
+
+ /* if(G.sipo->blocktype==ID_SEQ)
+ allow_pin= 0; */
+ xco= std_libbuttons(block, (short)(xco+1.5*XIC), 0, allow_pin, &G.sipo->pin, B_IPOBROWSE, ID_IP,
+ G.sipo->blocktype, (ID*)G.sipo->ipo, G.sipo->from, &(G.sipo->menunr), B_IPOALONE, B_IPOLOCAL, B_IPODELETE, 0, B_KEEPDATA);
+
+ /* COPY PASTE */
+ xco-= XIC/2;
+ uiBlockBeginAlign(block);
+ if(curarea->headertype==HEADERTOP) {
+ uiDefIconBut(block, BUT, B_IPOCOPY, ICON_COPYUP, xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0, "Copies the selected curves to the buffer");
+ uiSetButLock(G.sipo->ipo && G.sipo->ipo->id.lib, ERROR_LIBDATA_MESSAGE);
+ uiDefIconBut(block, BUT, B_IPOPASTE, ICON_PASTEUP, xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0, "Pastes the curves from the buffer");
+ }
+ else {
+ uiDefIconBut(block, BUT, B_IPOCOPY, ICON_COPYDOWN, xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0, "Copies the selected curves to the buffer");
+ uiSetButLock(G.sipo->ipo && G.sipo->ipo->id.lib, ERROR_LIBDATA_MESSAGE);
+ uiDefIconBut(block, BUT, B_IPOPASTE, ICON_PASTEDOWN, xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0, "Pastes the curves from the buffer");
+ }
+ uiBlockEndAlign(block);
+ xco+=XIC/2;
+
+ uiClearButLock();
+
+ /* ZOOMBORDER */
+ uiDefIconBut(block, BUT, B_IPOBORDER, ICON_BORDERMOVE, xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0, "Zooms view to area");
+
+ xco+=XIC/2;
+
+ /* draw LOCK */
+ uiDefIconButS(block, ICONTOG, 1, ICON_UNLOCKED, xco+=XIC,0,XIC,YIC, &(G.sipo->lock), 0, 0, 0, 0, "Toggles forced redraw of other windows to reflect changes in real time");
+
+ /* always do as last */
+ curarea->headbutlen= xco+2*XIC;
+
+ uiDrawBlock(block);
+}
diff --git a/source/blender/src/header_nla.c b/source/blender/src/header_nla.c
new file mode 100644
index 00000000000..96ea6c3d792
--- /dev/null
+++ b/source/blender/src/header_nla.c
@@ -0,0 +1,562 @@
+/**
+ * header_nla.c oct-2003
+ *
+ * Functions to draw the "NLA Editor" window header
+ * and handle user events sent to it.
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "DNA_ID.h"
+#include "DNA_nla_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_interface.h"
+#include "BIF_resources.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_editnla.h"
+#include "BIF_editaction.h"
+#include "BIF_toolbox.h"
+
+#include "BSE_drawipo.h"
+#include "BSE_headerbuttons.h"
+#include "BSE_time.h"
+
+//#include "nla.h"
+
+#include "blendef.h"
+#include "mydevice.h"
+
+void do_nla_buttons(unsigned short event)
+{
+ View2D *v2d;
+
+ switch(event){
+ case B_NLAHOME:
+ // Find X extents
+ v2d= &(G.snla->v2d);
+
+ /* i tried to understand nla/action drawing to reveil a 'tot' rect, impossible code! (ton) */
+ v2d->cur.xmin = G.scene->r.sfra-5;
+ v2d->cur.xmax = G.scene->r.efra+5;
+ v2d->cur.ymin= -SCROLLB;
+ v2d->cur.ymax= 5; // at least stuff is visiable then?
+
+ test_view2d(G.v2d, curarea->winx, curarea->winy);
+ view2d_do_locks(curarea, V2D_LOCK_COPY);
+ addqueue (curarea->win, REDRAW, 1);
+ break;
+ }
+}
+
+
+static void do_nla_viewmenu(void *arg, int event)
+{
+ extern int play_anim(int mode);
+
+ switch(event) {
+ case 0: /* Update Automatically */
+ if(BTST(G.snla->lock, 0)) G.snla->lock = BCLR(G.snla->lock, 0);
+ else G.snla->lock = BSET(G.snla->lock, 0);
+ break;
+ case 1: /* Play Back Animation */
+ play_anim(0);
+ break;
+ case 2: /* Play Back Animation in 3D View */
+ play_anim(1);
+ break;
+ case 3: /* View All */
+ do_nla_buttons(B_NLAHOME);
+ break;
+ case 4: /* Maximize Window */
+ /* using event B_FULL */
+ break;
+ case 5: /* Update automatically */
+ G.v2d->flag ^= V2D_VIEWLOCK;
+ if(G.v2d->flag & V2D_VIEWLOCK)
+ view2d_do_locks(curarea, 0);
+ break;
+ case 6: /* Show all objects that have keyframes? */
+ G.snla->flag ^= SNLA_ALLKEYED;
+ break;
+ case 7: /* Show timing in Frames or Seconds */
+ G.snla->flag ^= SNLA_DRAWTIME;
+ break;
+ }
+}
+
+static uiBlock *nla_viewmenu(void *arg_unused)
+{
+/* static short tog=0; */
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "nla_viewmenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_nla_viewmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, (G.snla->flag & SNLA_ALLKEYED)?ICON_CHECKBOX_DEHLT:ICON_CHECKBOX_HLT,
+ "Only Objects On Visible Layers|", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 6, "");
+
+ if (G.snla->flag & SNLA_DRAWTIME) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Show Frames|Ctrl T", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 7, "");
+ } else {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Show Seconds|Ctrl T", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 7, "");
+ }
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ if(BTST(G.snla->lock, 0)) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Update Automatically|", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+ } else {
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Update Automatically|", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+ }
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Play Back Animation|Alt A", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Play Back Animation in 3D View|Alt Shift A", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "View All|Home", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+ uiDefIconTextBut(block, BUTM, 1, (G.v2d->flag & V2D_VIEWLOCK)?ICON_CHECKBOX_HLT:ICON_CHECKBOX_DEHLT,
+ "Lock Time to Other Windows|", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+
+ if(!curarea->full) uiDefIconTextBut(block, BUTM, B_FULL, ICON_BLANK1, "Maximize Window|Ctrl UpArrow", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
+ else uiDefIconTextBut(block, BUTM, B_FULL, ICON_BLANK1, "Tile Window|Ctrl DownArrow", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+static void do_nla_selectmenu(void *arg, int event)
+{
+
+ switch(event)
+ {
+ case 0: /* Border Select */
+ borderselect_nla();
+ break;
+ case 1: /* Select/Deselect All Keys */
+ deselect_nlachannel_keys(1);
+ allqueue (REDRAWNLA, 0);
+ allqueue (REDRAWIPO, 0);
+ break;
+ case 2: /* Select/Deselect All Channel */
+ deselect_nlachannels(1);
+ allqueue (REDRAWVIEW3D, 0);
+ allqueue (REDRAWNLA, 0);
+ allqueue (REDRAWIPO, 0);
+ break;
+ case 3: /* Select/Deselect All Markers */
+ deselect_markers(1, 0);
+ allqueue(REDRAWMARKER, 0);
+ break;
+ case 4: /* Borderselect markers */
+ borderselect_markers();
+ break;
+ }
+}
+
+static uiBlock *nla_selectmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "nla_selectmenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_nla_selectmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Border Select|B", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Border Select Markers|Ctrl B", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select/Deselect All Keys|A", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select/Deselect All Channels", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select/Deselect All Markers|Ctrl A", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+static void do_nla_strip_snapmenu(void *arg, int event)
+{
+ snap_action_strips(event);
+
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWNLA, 0);
+}
+
+static uiBlock *nla_strip_snapmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "nla_strip_snapmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_nla_strip_snapmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Nearest Frame|Shift S, 1", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Current Frame|Shift S, 2", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+static void do_nla_strip_transformmenu(void *arg, int event)
+{
+ switch(event) {
+ case 0: /* grab/move */
+ transform_nlachannel_keys('g', 0);
+ update_for_newframe_muted();
+ break;
+ case 1: /* scale */
+ transform_nlachannel_keys('s', 0);
+ update_for_newframe_muted();
+ break;
+ case 2: /* extend */
+ transform_nlachannel_keys('e', 0);
+ update_for_newframe_muted();
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *nla_strip_transformmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "nla_strip_transformmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_nla_strip_transformmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Grab/Move|G", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Grab/Extend from Frame|E", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Scale|S", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+static void do_nla_stripmenu(void *arg, int event)
+{
+ switch(event)
+ {
+ case 0: /* Strip Properties */
+ add_blockhandler(curarea, NLA_HANDLER_PROPERTIES, UI_PNL_UNSTOW);
+ break;
+ case 1: /* Add Action Strip */
+ add_nlablock();
+ break;
+ case 2: /* Duplicate */
+ duplicate_nlachannel_keys();
+ update_for_newframe_muted();
+ break;
+ case 3: /* Delete Strips */
+ if (okee("Erase selected strips and/or keys")) {
+ delete_nlachannel_keys ();
+ update_for_newframe_muted();
+ }
+ break;
+ case 5: /* Convert Action to NLA Strip */
+ convert_nla();
+ break;
+ case 6: /* Move Up */
+ shift_nlastrips_up();
+ break;
+ case 7: /* Move Down */
+ shift_nlastrips_down();
+ break;
+ case 8: /* size */
+ reset_action_strips(1);
+ break;
+ case 9: /* reset start/end of action */
+ reset_action_strips(2);
+ break;
+ case 10: /* add new action as new action strip */
+ add_empty_nlablock();
+ break;
+ }
+}
+
+static uiBlock *nla_stripmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "nla_stripmenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_nla_stripmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Strip Properties...|N", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBlockBut(block, nla_strip_transformmenu, NULL, ICON_RIGHTARROW_THIN, "Transform", 0, yco-=20, 120, 20, "");
+ uiDefIconTextBlockBut(block, nla_strip_snapmenu, NULL, ICON_RIGHTARROW_THIN, "Snap To Frame", 0, yco-=20, 120, 20, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Reset Strip Size|Alt S", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 8, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Reset Action Start/End|Alt S", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 9, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Add Action Strip|Shift A", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Add Blank Action Strip|Shift N", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 10, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Convert Action to NLA Strip|C", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 5, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Duplicate|Shift D", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Delete|X", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Move Down|Ctrl Page Down", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 7, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Move Up|Ctrl Page Up", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 6, "");
+
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+static void do_nla_markermenu(void *arg, int event)
+{
+ switch(event)
+ {
+ case 1:
+ add_marker(CFRA);
+ break;
+ case 2:
+ duplicate_marker();
+ break;
+ case 3:
+ remove_marker();
+ break;
+ case 4:
+ rename_marker();
+ break;
+ case 5:
+ transform_markers('g', 0);
+ break;
+ }
+
+ allqueue(REDRAWMARKER, 0);
+}
+
+static uiBlock *nla_markermenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "nla_markermenu",
+ UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_nla_markermenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Add Marker|M", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Duplicate Marker|Ctrl Shift D", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Delete Marker|X", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "(Re)Name Marker|Ctrl M", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Grab/Move Marker|Ctrl G", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+void nla_buttons(void)
+{
+ SpaceNla *snla;
+ short xco, xmax;
+ char naam[20];
+ uiBlock *block;
+
+ snla= curarea->spacedata.first;
+
+ sprintf(naam, "header %d", curarea->headwin);
+ block= uiNewBlock(&curarea->uiblocks, naam, UI_EMBOSS, UI_HELV, curarea->headwin);
+
+ if(area_is_active_area(curarea)) uiBlockSetCol(block, TH_HEADER);
+ else uiBlockSetCol(block, TH_HEADERDESEL);
+
+ curarea->butspacetype= SPACE_NLA;
+
+ xco = 8;
+
+ uiDefIconTextButC(block, ICONTEXTROW,B_NEWSPACE, ICON_VIEW3D, windowtype_pup(), xco,0,XIC+10,YIC, &(curarea->butspacetype), 1.0, SPACEICONMAX, 0, 0, "Displays Current Window Type. Click for menu of available types.");
+
+ xco+= XIC+14;
+
+ uiBlockSetEmboss(block, UI_EMBOSSN);
+ if(curarea->flag & HEADER_NO_PULLDOWN) {
+ uiDefIconButBitS(block, TOG, HEADER_NO_PULLDOWN, B_FLIPINFOMENU, ICON_DISCLOSURE_TRI_RIGHT,
+ xco,2,XIC,YIC-2,
+ &(curarea->flag), 0, 0, 0, 0, "Show pulldown menus");
+ } else {
+ uiDefIconButBitS(block, TOG, HEADER_NO_PULLDOWN, B_FLIPINFOMENU, ICON_DISCLOSURE_TRI_DOWN,
+ xco,2,XIC,YIC-2,
+ &(curarea->flag), 0, 0, 0, 0, "Hide pulldown menus");
+ }
+ uiBlockSetEmboss(block, UI_EMBOSS);
+ xco+=XIC;
+
+ if((curarea->flag & HEADER_NO_PULLDOWN)==0) {
+ /* pull down menus */
+ uiBlockSetEmboss(block, UI_EMBOSSP);
+
+ xmax= GetButStringLength("View");
+ uiDefPulldownBut(block, nla_viewmenu, NULL, "View", xco, -2, xmax-3, 24, "");
+ xco+= xmax;
+
+ xmax= GetButStringLength("Select");
+ uiDefPulldownBut(block, nla_selectmenu, NULL, "Select", xco, -2, xmax-3, 24, "");
+ xco+= xmax;
+
+ xmax= GetButStringLength("Marker");
+ uiDefPulldownBut(block, nla_markermenu, NULL, "Marker", xco, -2, xmax-3, 24, "");
+ xco+= xmax;
+
+ xmax= GetButStringLength("Strip");
+ uiDefPulldownBut(block, nla_stripmenu, NULL, "Strip", xco, -2, xmax-3, 24, "");
+ xco+= xmax;
+
+
+ }
+
+ uiBlockSetEmboss(block, UI_EMBOSS);
+
+
+ /* draw AUTOSNAP */
+ xco += 8;
+
+ if (G.snla->flag & SNLA_DRAWTIME) {
+ uiDefButS(block, MENU, B_REDR,
+ "Auto-Snap Strips/Keyframes %t|Off %x0|Second Step %x1|Nearest Second %x2|Nearest Marker %x3",
+ xco,0,70,YIC, &(G.snla->autosnap), 0, 1, 0, 0,
+ "Auto-snapping mode for strips and keyframes when transforming");
+ }
+ else {
+ uiDefButS(block, MENU, B_REDR,
+ "Auto-Snap Strips/Keyframes %t|Off %x0|Frame Step %x1|Nearest Frame %x2|Nearest Marker %x3",
+ xco,0,70,YIC, &(G.snla->autosnap), 0, 1, 0, 0,
+ "Auto-snapping mode for strips and keyframes when transforming");
+ }
+
+ xco += (70 + 8);
+
+ /* FULL WINDOW */
+
+
+// xco = 8;
+
+// uiDefIconTextButC(block, ICONTEXTROW,B_NEWSPACE, ICON_VIEW3D, windowtype_pup(), xco,0,XIC+10,YIC, &(curarea->butspacetype), 1.0, SPACEICONMAX, 0, 0, "Displays Current Window Type. Click for menu of available types.");
+
+// xco+= XIC+22;
+
+ /* FULL WINDOW */
+// if(curarea->full) uiDefIconBut(block, BUT,B_FULL, ICON_SPLITSCREEN, xco,0,XIC,YIC, 0, 0, 0, 0, 0, "Returns to multiple views window (CTRL+Up arrow)");
+// else uiDefIconBut(block, BUT,B_FULL, ICON_FULLSCREEN, xco,0,XIC,YIC, 0, 0, 0, 0, 0, "Makes current window full screen (CTRL+Down arrow)");
+
+ /* HOME */
+// uiDefIconBut(block, BUT, B_NLAHOME, ICON_HOME, xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0, "Zooms window to home view showing all items (HOMEKEY)");
+// xco+= XIC;
+
+ /* IMAGE */
+// uiDefIconButS(block, TOG, B_REDR, ICON_IMAGE_COL, xco+=XIC,0,XIC,YIC, &sseq->mainb, 0, 0, 0, 0, "Toggles image display");
+
+ /* ZOOM en BORDER */
+// xco+= XIC;
+// uiDefIconButI(block, TOG, B_VIEW2DZOOM, ICON_VIEWZOOM, xco+=XIC,0,XIC,YIC, &viewmovetemp, 0, 0, 0, 0, "Zoom view (CTRL+MiddleMouse)");
+// uiDefIconBut(block, BUT, B_NLABORDER, ICON_BORDERMOVE, xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0, "Zoom view to area");
+
+ /* draw LOCK */
+// xco+= XIC/2;
+
+ xco += 8;
+
+ uiDefIconButS(block, ICONTOG, 1, ICON_UNLOCKED, xco,0,XIC,YIC, &(snla->lock), 0, 0, 0, 0, "Toggles forced redraw of other windows to reflect changes in real time");
+
+ uiDrawBlock(block);
+}
diff --git a/source/blender/src/header_node.c b/source/blender/src/header_node.c
new file mode 100644
index 00000000000..83aff8bcbe1
--- /dev/null
+++ b/source/blender/src/header_node.c
@@ -0,0 +1,673 @@
+/**
+ *
+ * $Id:
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "DNA_ID.h"
+#include "DNA_material_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
+#include "DNA_view2d_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BIF_gl.h"
+#include "BIF_interface.h"
+#include "BIF_previewrender.h"
+#include "BIF_resources.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_toolbox.h"
+#include "BIF_butspace.h"
+
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_node.h"
+
+#include "BSE_drawipo.h"
+#include "BSE_headerbuttons.h"
+#include "BSE_node.h"
+
+#include "blendef.h"
+#include "butspace.h"
+#include "mydevice.h"
+
+void do_node_buttons(ScrArea *sa, unsigned short event)
+{
+ SpaceNode *snode= sa->spacedata.first;
+ Material *ma;
+
+ switch(event) {
+ case B_NODE_USEMAT:
+ ma= (Material *)snode->id;
+ if(ma) {
+ if(ma->use_nodes && ma->nodetree==NULL) {
+ node_shader_default(ma);
+ snode_set_context(snode);
+ }
+ BIF_preview_changed(ID_MA);
+ allqueue(REDRAWNODE, 0);
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWIPO, 0);
+ }
+ break;
+
+ case B_NODE_USESCENE:
+ if(G.scene->use_nodes) {
+ if(G.scene->nodetree==NULL)
+ node_composit_default(G.scene);
+ addqueue(curarea->win, UI_BUT_EVENT, B_NODE_TREE_EXEC);
+ }
+ snode_set_context(snode);
+ allqueue(REDRAWNODE, 0);
+ break;
+ }
+}
+
+static void do_node_viewmenu(void *arg, int event)
+{
+ SpaceNode *snode= curarea->spacedata.first;
+
+ switch(event) {
+ case 1: /* Zoom in */
+ snode_zoom_in(curarea);
+ break;
+ case 2: /* View all */
+ snode_zoom_out(curarea);
+ break;
+ case 3: /* View all */
+ snode_home(curarea, snode);
+ break;
+ }
+ allqueue(REDRAWNODE, 0);
+}
+
+static uiBlock *node_viewmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "node_viewmenu",
+ UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_node_viewmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Zoom In|NumPad +", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Zoom Out|NumPad -", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "View All|Home", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+
+ if (!curarea->full)
+ uiDefIconTextBut(block, BUTM, B_FULL, ICON_BLANK1, "Maximize Window|Ctrl UpArrow", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
+ else
+ uiDefIconTextBut(block, BUTM, B_FULL, ICON_BLANK1, "Tile Window|Ctrl DownArrow", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+static void do_node_selectmenu(void *arg, int event)
+{
+ SpaceNode *snode= curarea->spacedata.first;
+
+ /* functions in editnode.c assume there's a tree */
+ if(snode->nodetree==NULL)
+ return;
+
+ switch(event) {
+ case 1: /* border select */
+ node_border_select(snode);
+ break;
+ case 2: /* select/deselect all */
+ node_deselectall(snode, 1);
+ break;
+ case 3: /* select linked in */
+ node_select_linked(snode, 0);
+ break;
+ case 4: /* select linked out */
+ node_select_linked(snode, 1);
+ break;
+ }
+ allqueue(REDRAWNODE, 0);
+}
+
+static uiBlock *node_selectmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "node_selectmenu",
+ UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_node_selectmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Border Select|B", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select/Deselect All|A", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select Linked From|L", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select Linked To|Shift L", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+void do_node_addmenu(void *arg, int event)
+{
+ SpaceNode *snode= curarea->spacedata.first;
+ bNode *node;
+ float locx, locy;
+ short mval[2];
+
+ /* store selection in temp test flag */
+ for(node= snode->edittree->nodes.first; node; node= node->next) {
+ if(node->flag & NODE_SELECT) node->flag |= NODE_TEST;
+ else node->flag &= ~NODE_TEST;
+ }
+
+ getmouseco_areawin(mval);
+ areamouseco_to_ipoco(G.v2d, mval, &locx, &locy);
+ node= node_add_node(snode, event, locx, locy);
+
+ /* uses test flag */
+ snode_autoconnect(snode, node, NODE_TEST);
+
+ addqueue(curarea->win, UI_BUT_EVENT, B_NODE_TREE_EXEC);
+
+ BIF_undo_push("Add Node");
+
+}
+
+static void node_make_addmenu(SpaceNode *snode, int nodeclass, uiBlock *block)
+{
+ bNodeTree *ntree;
+ int tot= 0, a;
+ short yco= 0, menuwidth=120;
+
+ ntree = snode->nodetree;
+ if(ntree) {
+ /* mostly taken from toolbox.c, node_add_sublevel() */
+ if(ntree) {
+ if(nodeclass==NODE_CLASS_GROUP) {
+ bNodeTree *ngroup= G.main->nodetree.first;
+ for(; ngroup; ngroup= ngroup->id.next)
+ if(ngroup->type==ntree->type)
+ tot++;
+ }
+ else {
+ bNodeType *type = ntree->alltypes.first;
+ while(type) {
+ if(type->nclass == nodeclass)
+ tot++;
+ type= type->next;
+ }
+ }
+ }
+
+ if(tot==0) {
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+ return;
+ }
+
+ if(nodeclass==NODE_CLASS_GROUP) {
+ bNodeTree *ngroup= G.main->nodetree.first;
+ for(tot=0, a=0; ngroup; ngroup= ngroup->id.next, tot++) {
+ if(ngroup->type==ntree->type) {
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, (ngroup->id.name+2), 0,
+ yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, NODE_GROUP_MENU+tot, "");
+ a++;
+ }
+ }
+ }
+ else {
+ bNodeType *type;
+ for(a=0, type= ntree->alltypes.first; type; type=type->next) {
+ if( type->nclass == nodeclass ) {
+ printf("node %s\n", type->name);
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, type->name, 0,
+ yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, type->type, "");
+ a++;
+ }
+ }
+ }
+ } else {
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+ return;
+ }
+}
+
+static uiBlock *node_add_inputmenu(void *arg_unused)
+{
+ SpaceNode *snode= curarea->spacedata.first;
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "node_add_inputmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_node_addmenu, NULL);
+
+ node_make_addmenu(snode, NODE_CLASS_INPUT, block);
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+
+ return block;
+}
+static uiBlock *node_add_outputmenu(void *arg_unused)
+{
+ SpaceNode *snode= curarea->spacedata.first;
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "node_add_outputmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_node_addmenu, NULL);
+
+ node_make_addmenu(snode, NODE_CLASS_OUTPUT, block);
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+
+ return block;
+}
+static uiBlock *node_add_colormenu(void *arg_unused)
+{
+ SpaceNode *snode= curarea->spacedata.first;
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "node_add_colormenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_node_addmenu, NULL);
+
+ node_make_addmenu(snode, NODE_CLASS_OP_COLOR, block);
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+
+ return block;
+}
+static uiBlock *node_add_vectormenu(void *arg_unused)
+{
+ SpaceNode *snode= curarea->spacedata.first;
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "node_add_vectormenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_node_addmenu, NULL);
+
+ node_make_addmenu(snode, NODE_CLASS_OP_VECTOR, block);
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+
+ return block;
+}
+static uiBlock *node_add_filtermenu(void *arg_unused)
+{
+ SpaceNode *snode= curarea->spacedata.first;
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "node_add_filtermenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_node_addmenu, NULL);
+
+ node_make_addmenu(snode, NODE_CLASS_OP_FILTER, block);
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+
+ return block;
+}
+static uiBlock *node_add_convertermenu(void *arg_unused)
+{
+ SpaceNode *snode= curarea->spacedata.first;
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "node_add_convertermenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_node_addmenu, NULL);
+
+ node_make_addmenu(snode, NODE_CLASS_CONVERTOR, block);
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+
+ return block;
+}
+static uiBlock *node_add_mattemenu(void *arg_unused)
+{
+ SpaceNode *snode= curarea->spacedata.first;
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "node_add_mattemenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_node_addmenu, NULL);
+
+ node_make_addmenu(snode, NODE_CLASS_MATTE, block);
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+
+ return block;
+}
+static uiBlock *node_add_distortmenu(void *arg_unused)
+{
+ SpaceNode *snode= curarea->spacedata.first;
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "node_add_distortmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_node_addmenu, NULL);
+
+ node_make_addmenu(snode, NODE_CLASS_DISTORT, block);
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+
+ return block;
+}
+static uiBlock *node_add_groupmenu(void *arg_unused)
+{
+ SpaceNode *snode= curarea->spacedata.first;
+ uiBlock *block;
+
+ block= uiNewBlock(&curarea->uiblocks, "node_add_groupmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_node_addmenu, NULL);
+
+ node_make_addmenu(snode, NODE_CLASS_GROUP, block);
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+
+ return block;
+}
+
+static uiBlock *node_addmenu(void *arg_unused)
+{
+ SpaceNode *snode= curarea->spacedata.first;
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "node_addmenu",
+ UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_node_addmenu, NULL);
+
+ if(snode->treetype==NTREE_SHADER) {
+ uiDefIconTextBlockBut(block, node_add_inputmenu, NULL, ICON_RIGHTARROW_THIN, "Input", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, node_add_outputmenu, NULL, ICON_RIGHTARROW_THIN, "Output", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, node_add_colormenu, NULL, ICON_RIGHTARROW_THIN, "Color", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, node_add_vectormenu, NULL, ICON_RIGHTARROW_THIN, "Vector", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, node_add_convertermenu, NULL, ICON_RIGHTARROW_THIN, "Convertor", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, node_add_groupmenu, NULL, ICON_RIGHTARROW_THIN, "Group", 0, yco-=20, 120, 19, "");
+ }
+ else if(snode->treetype==NTREE_COMPOSIT) {
+ uiDefIconTextBlockBut(block, node_add_inputmenu, NULL, ICON_RIGHTARROW_THIN, "Input", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, node_add_outputmenu, NULL, ICON_RIGHTARROW_THIN, "Output", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, node_add_colormenu, NULL, ICON_RIGHTARROW_THIN, "Color", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, node_add_vectormenu, NULL, ICON_RIGHTARROW_THIN, "Vector", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, node_add_filtermenu, NULL, ICON_RIGHTARROW_THIN, "Filter", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, node_add_convertermenu, NULL, ICON_RIGHTARROW_THIN, "Convertor", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, node_add_mattemenu, NULL, ICON_RIGHTARROW_THIN, "Matte", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, node_add_distortmenu, NULL, ICON_RIGHTARROW_THIN, "Distort", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, node_add_groupmenu, NULL, ICON_RIGHTARROW_THIN, "Group", 0, yco-=20, 120, 19, "");
+
+ } else
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+static void do_node_nodemenu(void *arg, int event)
+{
+ SpaceNode *snode= curarea->spacedata.first;
+ int fromlib=0;
+
+ /* functions in editnode.c assume there's a tree */
+ if(snode->nodetree==NULL)
+ return;
+ fromlib= (snode->id && snode->id->lib);
+
+ switch(event) {
+ case 1: /* grab/move */
+ node_transform_ext(0,0);
+ break;
+ case 2: /* duplicate */
+ if(fromlib) fromlib= -1;
+ else node_adduplicate(snode);
+ break;
+ case 3: /* delete */
+ if(fromlib) fromlib= -1;
+ else node_delete(snode);
+ break;
+ case 4: /* make group */
+ node_make_group(snode);
+ break;
+ case 5: /* ungroup */
+ node_ungroup(snode);
+ break;
+ case 6: /* edit group */
+ if(fromlib) fromlib= -1;
+ else snode_make_group_editable(snode, NULL);
+ break;
+ case 7: /* hide/unhide */
+ node_hide(snode);
+ break;
+ case 8: /* read saved render layers */
+ node_read_renderlayers(snode);
+ break;
+ case 9: /* show cyclic */
+ ntreeSolveOrder(snode->edittree);
+ break;
+ case 10: /* execute */
+ addqueue(curarea->win, UI_BUT_EVENT, B_NODE_TREE_EXEC);
+ break;
+ }
+
+ if(fromlib==-1) error_libdata();
+ allqueue(REDRAWNODE, 0);
+}
+
+static uiBlock *node_nodemenu(void *arg_unused)
+{
+ SpaceNode *snode= curarea->spacedata.first;
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "node_nodemenu",
+ UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_node_nodemenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Grab/Move|G", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Duplicate|Shift D", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Delete|X", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Make Group|Ctrl G", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Ungroup|Alt G", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Edit Group|Tab", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 6, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Hide/Unhide|H", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 7, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ if(snode->treetype==NTREE_COMPOSIT) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Execute Composite|E", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 10, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Read Saved Render Results|R", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 8, "");
+ }
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Show Cyclic Dependencies|C", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 9, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+void node_buttons(ScrArea *sa)
+{
+ SpaceNode *snode= sa->spacedata.first;
+ uiBlock *block;
+ short xco, xmax;
+ char name[256];
+
+ sprintf(name, "header %d", sa->headwin);
+ block= uiNewBlock(&sa->uiblocks, name, UI_EMBOSS, UI_HELV, sa->headwin);
+
+ if(area_is_active_area(sa)) uiBlockSetCol(block, TH_HEADER);
+ else uiBlockSetCol(block, TH_HEADERDESEL);
+
+ sa->butspacetype= SPACE_NODE;
+
+ xco = 8;
+
+ uiDefIconTextButC(block, ICONTEXTROW,B_NEWSPACE, ICON_VIEW3D,
+ windowtype_pup(), xco, 0, XIC+10, YIC,
+ &(sa->butspacetype), 1.0, SPACEICONMAX, 0, 0,
+ "Displays Current Window Type");
+
+ xco += XIC + 14;
+
+ uiBlockSetEmboss(block, UI_EMBOSSN);
+ if (sa->flag & HEADER_NO_PULLDOWN) {
+ uiDefIconButBitS(block, TOG, HEADER_NO_PULLDOWN, B_FLIPINFOMENU,
+ ICON_DISCLOSURE_TRI_RIGHT, xco,2,XIC,YIC-2,
+ &(sa->flag), 0, 0, 0, 0, "Show pulldown menus");
+ }
+ else {
+ uiDefIconButBitS(block, TOG, HEADER_NO_PULLDOWN, B_FLIPINFOMENU,
+ ICON_DISCLOSURE_TRI_DOWN, xco,2,XIC,YIC-2,
+ &(sa->flag), 0, 0, 0, 0, "Hide pulldown menus");
+ }
+ xco+=XIC;
+
+ if((sa->flag & HEADER_NO_PULLDOWN)==0) {
+ /* pull down menus */
+ uiBlockSetEmboss(block, UI_EMBOSSP);
+
+ xmax= GetButStringLength("View");
+ uiDefPulldownBut(block, node_viewmenu, NULL,
+ "View", xco, -2, xmax-3, 24, "");
+ xco+= xmax;
+
+ xmax= GetButStringLength("Select");
+ uiDefPulldownBut(block, node_selectmenu, NULL,
+ "Select", xco, -2, xmax-3, 24, "");
+ xco+= xmax;
+
+ xmax= GetButStringLength("Add");
+ uiDefPulldownBut(block, node_addmenu, NULL,
+ "Add", xco, -2, xmax-3, 24, "");
+ xco+= xmax;
+
+ xmax= GetButStringLength("Node");
+ uiDefPulldownBut(block, node_nodemenu, NULL,
+ "Node", xco, -2, xmax-3, 24, "");
+ xco+= xmax;
+ }
+
+ uiBlockSetEmboss(block, UI_EMBOSS);
+
+ /* main type choosing */
+ uiBlockBeginAlign(block);
+ uiDefIconButI(block, ROW, B_REDR, ICON_MATERIAL_DEHLT, xco,2,XIC,YIC-2,
+ &(snode->treetype), 2, 0, 0, 0, "Material Nodes");
+ xco+= XIC;
+ uiDefIconButI(block, ROW, B_REDR, ICON_IMAGE_DEHLT, xco,2,XIC,YIC-2,
+ &(snode->treetype), 2, 1, 0, 0, "Composite Nodes");
+ xco+= 2*XIC;
+ uiBlockEndAlign(block);
+
+ /* find and set the context */
+ snode_set_context(snode);
+
+ if(snode->treetype==NTREE_SHADER) {
+ if(snode->from) {
+ /* 0, NULL -> pin */
+ xco= std_libbuttons(block, xco, 0, 0, NULL, B_MATBROWSE, ID_MA, 1, snode->id, snode->from, &(snode->menunr),
+ B_MATALONE, B_MATLOCAL, B_MATDELETE, B_AUTOMATNAME, B_KEEPDATA);
+
+ if(snode->id) {
+ Material *ma= (Material *)snode->id;
+ uiDefButC(block, TOG, B_NODE_USEMAT, "Use Nodes", xco+5,0,70,19, &ma->use_nodes, 0.0f, 0.0f, 0, 0, "");
+ xco+=80;
+ }
+ }
+ }
+ else if(snode->treetype==NTREE_COMPOSIT) {
+ uiDefButS(block, TOG, B_NODE_USESCENE, "Use Nodes", xco+5,0,70,19, &G.scene->use_nodes, 0.0f, 0.0f, 0, 0, "Indicate this Scene will use Nodes and execute them while editing");
+ xco+= 80;
+ uiDefButBitS(block, TOG, R_COMP_FREE, B_NOP, "Free Unused", xco+5,0,80,19, &G.scene->r.scemode, 0.0f, 0.0f, 0, 0, "Free Nodes that are not used while composite");
+ xco+= 80;
+ uiDefButBitS(block, TOG, SNODE_BACKDRAW, B_NOP, "Backdrop", xco+5,0,80,19, &snode->flag, 0.0f, 0.0f, 0, 0, "Use active Viewer Node output as backdrop");
+ xco+= 80;
+ }
+
+ /* always as last */
+ sa->headbutlen= xco+2*XIC;
+
+ uiDrawBlock(block);
+}
diff --git a/source/blender/src/header_oops.c b/source/blender/src/header_oops.c
new file mode 100644
index 00000000000..7bfbf0ee667
--- /dev/null
+++ b/source/blender/src/header_oops.c
@@ -0,0 +1,578 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: not all of this file anymore.
+ *
+ * Contributor(s): Blender Foundation.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "BMF_Api.h"
+#include "BIF_language.h"
+
+#include "DNA_ID.h"
+#include "DNA_oops_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "BKE_global.h"
+#include "BKE_main.h"
+
+#include "BIF_gl.h"
+#include "BIF_interface.h"
+#include "BIF_resources.h"
+#include "BIF_screen.h"
+#include "BIF_editoops.h"
+#include "BIF_oops.h"
+#include "BIF_outliner.h"
+#include "BIF_space.h"
+
+#include "BSE_drawipo.h"
+#include "BSE_drawoops.h"
+#include "BSE_headerbuttons.h"
+
+#include "blendef.h"
+
+#include "BKE_depsgraph.h"
+
+#include "BPY_extern.h"
+#include "BPY_menus.h"
+
+static int viewmovetemp = 0;
+
+void do_oops_buttons(short event)
+{
+ float dx, dy;
+
+ /* used for maximize hack */
+ int win_width, win_height;
+ float aspect_win, aspect_oops, oops_width, oops_height, oops_x_mid, oops_y_mid;
+
+
+ if(curarea->win==0) return;
+
+ if (event == B_NEWOOPS) {
+ scrarea_queue_winredraw(curarea);
+ scrarea_queue_headredraw(curarea);
+ G.soops->lockpoin= 0;
+ } else { /* must be either B_OOPSHOME or B_OOPSVIEWSEL */
+ init_v2d_oops(curarea, curarea->spacedata.first); // forces min/max to be reset
+ if (event == B_OOPSHOME) {
+ boundbox_oops(0); /* Test all oops blocks */
+ } else {
+ boundbox_oops(1); /* Test only selected oops blocks */
+ }
+
+
+ /* Hack to work with test_view2d in drawipo.c
+ Modify the bounding box so it is maximized to the window aspect
+ so viewing all oops blocks isnt limited to hoz/vert only.
+ Cant modify drawipo.c because many other functions use this hos/vert operation - Campbell*/
+
+ win_width= curarea->winrct.xmax - curarea->winrct.xmin;
+ win_height= curarea->winrct.ymax - curarea->winrct.ymin;
+
+ oops_width = G.v2d->tot.xmax - G.v2d->tot.xmin;
+ oops_height = G.v2d->tot.ymax - G.v2d->tot.ymin;
+
+ oops_x_mid = (G.v2d->tot.xmax + G.v2d->tot.xmin)*0.5;
+ oops_y_mid = (G.v2d->tot.ymax + G.v2d->tot.ymin)*0.5;
+ /* wide windows will be above 1, skinny below 1 */
+ aspect_win= (float)win_width / (float)win_height;
+ aspect_oops = (float)oops_width / (float)oops_height;
+ if (aspect_win>aspect_oops) {/* the window is wider then the oops bounds, increase the oops width */
+ G.v2d->tot.xmin = oops_x_mid - ((oops_x_mid-G.v2d->tot.xmin) * (aspect_win/aspect_oops) ); /* scale the min */
+ G.v2d->tot.xmax = oops_x_mid + ((G.v2d->tot.xmax-oops_x_mid) * (aspect_win/aspect_oops) );/* scale the max */
+ } else { /* the window is skinnier then the oops bounds, increase the oops height */
+ G.v2d->tot.ymin = oops_y_mid - ((oops_y_mid-G.v2d->tot.ymin) * (aspect_oops/aspect_win) ); /* scale the min */
+ G.v2d->tot.ymax = oops_y_mid + ((G.v2d->tot.ymax-oops_y_mid) * (aspect_oops/aspect_win) );/* scale the max */
+ }
+
+ /* maybe we should restore the correct values? - do next of its needed */
+ /* end hack */
+
+
+
+ G.v2d->cur= G.v2d->tot;
+ dx= 0.15*(G.v2d->cur.xmax-G.v2d->cur.xmin);
+ dy= 0.15*(G.v2d->cur.ymax-G.v2d->cur.ymin);
+ G.v2d->cur.xmin-= dx;
+ G.v2d->cur.xmax+= dx;
+ G.v2d->cur.ymin-= dy;
+ G.v2d->cur.ymax+= dy;
+ test_view2d(G.v2d, curarea->winx, curarea->winy);
+ scrarea_queue_winredraw(curarea);
+ }
+}
+
+static void do_oops_viewmenu(void *arg, int event)
+{
+ SpaceOops *soops= curarea->spacedata.first;
+
+ switch(event) {
+ case 0: /* Shuffle Selected Blocks */
+ shuffle_oops();
+ break;
+ case 1: /* Shrink Selected Blocks */
+ shrink_oops();
+ break;
+ case 2: /* View All */
+ do_oops_buttons(B_OOPSHOME);
+ break;
+ case 3: /* View All */
+ do_oops_buttons(B_OOPSVIEWSEL);
+ break;
+ case 4: /* Maximize Window */
+ /* using event B_FULL */
+ break;
+ case 5: /* show outliner */
+ if(soops->type==SO_OOPS || soops->type==SO_DEPSGRAPH) soops->type= SO_OUTLINER;
+ else soops->type= SO_OOPS;
+ init_v2d_oops(curarea, soops);
+ test_view2d(G.v2d, curarea->winx, curarea->winy);
+ scrarea_queue_winredraw(curarea);
+ break;
+ case 6:
+ outliner_toggle_visible(curarea);
+ break;
+ case 7:
+ outliner_show_hierarchy(curarea);
+ break;
+ case 8:
+ outliner_show_active(curarea);
+ break;
+ case 9:
+ outliner_one_level(curarea, 1);
+ break;
+ case 10:
+ outliner_one_level(curarea, -1);
+ break;
+#ifdef SHOWDEPGRAPH
+ case 11:
+ // show deps
+ {
+ SpaceOops *soops= curarea->spacedata.first;
+ if(soops->type==SO_OOPS) {
+ soops->type= SO_DEPSGRAPH;
+ soops->deps_flags = DAG_RL_ALL_BUT_DATA_MASK;
+ } else
+ soops->type= SO_OOPS;
+ init_v2d_oops(curarea, soops);
+ test_view2d(G.v2d, curarea->winx, curarea->winy);
+ scrarea_queue_winredraw(curarea);
+ }
+ break;
+#endif
+ case 12:
+ if (soops->flag & SO_HIDE_RESTRICTCOLS) soops->flag &= ~SO_HIDE_RESTRICTCOLS;
+ else soops->flag |= SO_HIDE_RESTRICTCOLS;
+ break;
+ }
+}
+
+static uiBlock *oops_viewmenu(void *arg_unused)
+{
+ SpaceOops *soops= curarea->spacedata.first;
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "oops_viewmenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_oops_viewmenu, NULL);
+
+ if(soops->type==SO_OOPS) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Show Outliner", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+#ifdef SHOWDEPGRAPH
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Show Dependancies", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 11, "");
+#endif
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Shuffle Selected Blocks|Shift S", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Shrink Selected Blocks|Alt S", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "View All|Home", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "View Selected|NumPad .", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+ }
+#ifdef SHOWDEPGRAPH
+ else if(soops->type==SO_DEPSGRAPH) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Show Outliner", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Show Oops Schematic", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 11, "");
+ }
+#endif
+ else {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Show Oops Schematic", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ if (soops->flag & SO_HIDE_RESTRICTCOLS)
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Show Restriction Columns", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 12, "");
+ else
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Show Restriction Columns", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 12, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Expand One Level|NumPad +", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 9, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Collapse One Level|NumPad -", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 10, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Show/Hide All", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 6, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Show Hierarchy|Home", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 7, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Show Active|NumPad .", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 8, "");
+ }
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+ if(!curarea->full) uiDefIconTextBut(block, BUTM, B_FULL, ICON_BLANK1, "Maximize Window|Ctrl UpArrow", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
+ else uiDefIconTextBut(block, BUTM, B_FULL, ICON_BLANK1, "Tile Window|Ctrl DownArrow", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+
+static void do_oops_selectmenu(void *arg, int event)
+{
+
+ switch(event)
+ {
+ case 0: /* Border Select */
+ borderselect_oops();
+ break;
+ case 1: /* Select/Deselect All */
+ swap_select_all_oops();
+ break;
+ case 2: /* Linked to Selected */
+ select_linked_oops();
+ break;
+ case 3: /* Users of Selected */
+ select_backlinked_oops();
+ break;
+ }
+}
+
+static uiBlock *oops_selectmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "oops_selectmenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_oops_selectmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Border Select|B", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select/Deselect All|A", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Linked to Selected|L", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Users of Selected|Shift L", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+static void do_oops_blockmenu(void *arg, int event)
+{
+ switch(event)
+ {
+ case 0: /* grab/move */
+ transform_oops('g', 0);
+ break;
+ case 1: /* scale */
+ transform_oops('s', 0);
+ break;
+ }
+}
+
+static uiBlock *oops_blockmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "oops_blockmenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_oops_blockmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Grab/Move|G", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Scale|S", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+static void do_oops_searchmenu(void *arg, int event)
+{
+ int search_flags = OL_FIND, again = 0;
+
+ switch(event)
+ {
+ case 0: /* plain new find */
+ search_flags = OL_FIND;
+ break;
+ case 1: /* case sensitive */
+ search_flags = OL_FIND_CASE;
+ break;
+ case 2: /* full search */
+ search_flags = OL_FIND_COMPLETE;
+ break;
+ case 3: /* full case sensitive */
+ search_flags = OL_FIND_COMPLETE_CASE;
+ break;
+ case 4: /* again */
+ again = 1;
+ break;
+ default: /* nothing valid */
+ return;
+ }
+
+ /* run search */
+ outliner_find_panel(curarea, again, search_flags);
+}
+
+static uiBlock *oops_searchmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "oops_searchmenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_oops_searchmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Find|F", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Find (Case Sensitive)|Ctrl F", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Find Complete|Alt F", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Find Complete (Case Sensitive)|Ctrl Alt F", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Find Again|Shift F", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+void oops_buttons(void)
+{
+ SpaceOops *soops;
+ Oops *oops;
+ uiBlock *block;
+ short xco, xmax;
+ char naam[256];
+
+ soops= curarea->spacedata.first;
+
+ sprintf(naam, "header %d", curarea->headwin);
+ block= uiNewBlock(&curarea->uiblocks, naam, UI_EMBOSS, UI_HELV, curarea->headwin);
+
+ if(area_is_active_area(curarea)) uiBlockSetCol(block, TH_HEADER);
+ else uiBlockSetCol(block, TH_HEADERDESEL);
+
+ curarea->butspacetype= SPACE_OOPS;
+
+ xco = 8;
+
+ uiDefIconTextButC(block, ICONTEXTROW,B_NEWSPACE, ICON_VIEW3D, windowtype_pup(), xco,0,XIC+10,YIC, &(curarea->butspacetype), 1.0, SPACEICONMAX, 0, 0, "Displays Current Window Type. Click for menu of available types.");
+
+ xco+= XIC+14;
+
+ uiBlockSetEmboss(block, UI_EMBOSSN);
+ if(curarea->flag & HEADER_NO_PULLDOWN) {
+ uiDefIconButBitS(block, TOG, HEADER_NO_PULLDOWN, B_FLIPINFOMENU, ICON_DISCLOSURE_TRI_RIGHT,
+ xco,2,XIC,YIC-2,
+ &(curarea->flag), 0, 0, 0, 0, "Show pulldown menus");
+ } else {
+ uiDefIconButBitS(block, TOG, HEADER_NO_PULLDOWN, B_FLIPINFOMENU, ICON_DISCLOSURE_TRI_DOWN,
+ xco,2,XIC,YIC-2,
+ &(curarea->flag), 0, 0, 0, 0, "Hide pulldown menus");
+ }
+ uiBlockSetEmboss(block, UI_EMBOSS);
+ xco+=XIC;
+
+ if((curarea->flag & HEADER_NO_PULLDOWN)==0) {
+ /* pull down menus */
+ uiBlockSetEmboss(block, UI_EMBOSSP);
+
+ xmax= GetButStringLength("View");
+ uiDefPulldownBut(block, oops_viewmenu, NULL, "View", xco, -2, xmax-3, 24, "");
+ xco+= xmax;
+
+ if(soops->type==SO_OOPS) {
+ xmax= GetButStringLength("Select");
+ uiDefPulldownBut(block, oops_selectmenu, NULL, "Select", xco, -2, xmax-3, 24, "");
+ xco+= xmax;
+
+ xmax= GetButStringLength("Block");
+ uiDefPulldownBut(block, oops_blockmenu, NULL, "Block", xco, -2, xmax-3, 24, "");
+ xco+= xmax;
+
+ }
+ else {
+ xmax= GetButStringLength("Search");
+ uiDefPulldownBut(block, oops_searchmenu, NULL, "Search", xco, -2, xmax-3, 24, "");
+ xco+= xmax;
+ }
+ }
+
+ uiBlockSetEmboss(block, UI_EMBOSS);
+
+ if(soops->type==SO_OOPS) {
+ /* ZOOM and BORDER */
+ uiBlockBeginAlign(block);
+ uiDefIconButI(block, TOG, B_VIEW2DZOOM, ICON_VIEWZOOM, (short)(xco),0,XIC,YIC, &viewmovetemp, 0, 0, 0, 0, "Zooms view (Ctrl MiddleMouse)");
+ uiDefIconBut(block, BUT, B_IPOBORDER, ICON_BORDERMOVE, (short)(xco+=XIC),0,XIC,YIC, 0, 0, 0, 0, 0, "Zooms view to area");
+ uiBlockEndAlign(block);
+
+ xco+= 8;
+
+ /* VISIBLE */
+ uiBlockBeginAlign(block);
+ uiDefButBitS(block, TOG, OOPS_LAY, B_NEWOOPS, "Layer", (short)(xco+=XIC),0,XIC+20,YIC, &soops->visiflag, 0, 0, 0, 0, "Only show object datablocks on visible layers");
+ xco+= 20;
+ uiDefIconButBitS(block, TOG, OOPS_SCE, B_NEWOOPS, ICON_SCENE_HLT, (short)(xco+=XIC),0,XIC,YIC, &soops->visiflag, 0, 0, 0, 0, "Displays Scene datablocks");
+ uiDefIconButBitS(block, TOG, OOPS_OB, B_NEWOOPS, ICON_OBJECT_HLT, (short)(xco+=XIC),0,XIC,YIC, &soops->visiflag, 0, 0, 0, 0, "Displays Object datablocks");
+ uiDefIconButBitS(block, TOG, OOPS_ME, B_NEWOOPS, ICON_MESH_HLT, (short)(xco+=XIC),0,XIC,YIC, &soops->visiflag, 0, 0, 0, 0, "Displays Mesh datablocks");
+ uiDefIconButBitS(block, TOG, OOPS_CU, B_NEWOOPS, ICON_CURVE_HLT, (short)(xco+=XIC),0,XIC,YIC, &soops->visiflag, 0, 0, 0, 0, "Displays Curve/Surface/Font datablocks");
+ uiDefIconButBitS(block, TOG, OOPS_MB, B_NEWOOPS, ICON_MBALL_HLT, (short)(xco+=XIC),0,XIC,YIC, &soops->visiflag, 0, 0, 0, 0, "Displays Metaball datablocks");
+ uiDefIconButBitS(block, TOG, OOPS_LT, B_NEWOOPS, ICON_LATTICE_HLT, (short)(xco+=XIC),0,XIC,YIC, &soops->visiflag, 0, 0, 0, 0, "Displays Lattice datablocks");
+ uiDefIconButBitS(block, TOG, OOPS_LA, B_NEWOOPS, ICON_LAMP_HLT, (short)(xco+=XIC),0,XIC,YIC, &soops->visiflag, 0, 0, 0, 0, "Displays Lamp datablocks");
+ uiDefIconButBitS(block, TOG, OOPS_MA, B_NEWOOPS, ICON_MATERIAL_HLT, (short)(xco+=XIC),0,XIC,YIC, &soops->visiflag, 0, 0, 0, 0, "Displays Material datablocks");
+ uiDefIconButBitS(block, TOG, OOPS_TE, B_NEWOOPS, ICON_TEXTURE_HLT, (short)(xco+=XIC),0,XIC,YIC, &soops->visiflag, 0, 0, 0, 0, "Displays Texture datablocks");
+ uiDefIconButBitS(block, TOG, OOPS_IP, B_NEWOOPS, ICON_IPO_HLT, (short)(xco+=XIC),0,XIC,YIC, &soops->visiflag, 0, 0, 0, 0, "Displays Ipo datablocks");
+ uiDefIconButBitS(block, TOG, OOPS_IM, B_NEWOOPS, ICON_IMAGE_HLT, (short)(xco+=XIC),0,XIC,YIC, &soops->visiflag, 0, 0, 0, 0, "Displays Image datablocks");
+ uiDefIconButBitS(block, TOG, OOPS_GR, B_NEWOOPS, ICON_CIRCLE_DEHLT, (short)(xco+=XIC),0,XIC,YIC, &soops->visiflag, 0, 0, 0, 0, "Displays Group datablocks");
+ uiDefIconButBitS(block, TOG, OOPS_LI, B_NEWOOPS, ICON_LIBRARY_HLT, (short)(xco+=XIC),0,XIC,YIC, &soops->visiflag, 0, 0, 0, 0, "Displays Library datablocks");
+
+
+ uiBlockEndAlign(block);
+
+ /* name */
+ if(G.soops->lockpoin) {
+ oops= G.soops->lockpoin;
+ if(oops->type==ID_LI) strcpy(naam, ((Library *)oops->id)->name);
+ else strcpy(naam, oops->id->name);
+
+ cpack(0x0);
+ BIF_ThemeColor(TH_MENU_TEXT); /* makes text readable on dark theme */
+ BIF_SetScale(1.0);
+ glRasterPos2i(xco+=XIC+10, 5);
+ BIF_RasterPos(xco+=XIC+10, 5);
+ BIF_DrawString(G.font, naam, 0);
+
+ }
+ }
+#ifdef SHOWDEPGRAPH
+ else if(soops->type==SO_DEPSGRAPH) {
+ // cpack colors : 0x00FF00 0xFF0000 0xFFFF00 0x000000 0x0000FF 0x00FFFF
+ static unsigned char colr[21] ={0x00, 0xFF, 0x00,
+ 0x00, 0x00, 0xFF,
+ 0x00, 0xFF, 0xFF,
+ 0x00, 0x00, 0x00,
+ 0xFF, 0x00, 0x00,
+ 0xFF, 0xFF, 0x00,
+ 0xFF, 0x00, 0x00};
+
+ uiDefButC( block, COL, 0, "", (short)(xco+=10),0, 5,YIC, colr, 0, 1, 0, 0, "");
+ uiDefButS( block, TOG|BIT|2, B_REDR, "parent", (short)(xco+=7),0, 50,YIC, &soops->deps_flags, 0, 1, 0, 0, "parent");
+ uiDefButC( block, COL, 0, "", (short)(xco+=60),0, 5,YIC, colr+3, 0, 1, 0, 0, "");
+ uiDefButS( block, TOG|BIT|1, B_REDR, "data", (short)(xco+=7),0, 50,YIC, &soops->deps_flags, 0, 1, 0, 0, "data");
+ uiDefButC( block, COL, 0, "", (short)(xco+=60),0, 5,YIC, colr+6, 0, 1, 0, 0, "");
+ uiDefButS( block, TOG|BIT|3, B_REDR, "track", (short)(xco+=7),0, 50,YIC, &soops->deps_flags, 0, 1, 0, 0, "track");
+ uiDefButC( block, COL, 0, "", (short)(xco+=60),0, 5,YIC, colr+9, 0, 1, 0, 0, "");
+ uiDefButS( block, TOG|BIT|4, B_REDR, "path", (short)(xco+=7),0, 50,YIC, &soops->deps_flags, 0, 1, 0, 0, "path");
+ uiDefButC( block, COL, 0, "", (short)(xco+=60),0, 5,YIC, colr+12, 0, 1, 0, 0, "");
+ uiDefButS( block, TOG|BIT|5, B_REDR, "cons.", (short)(xco+=7),0, 50,YIC, &soops->deps_flags, 0, 1, 0, 0, "constraint");
+ uiDefButC( block, COL, 0, "", (short)(xco+=60),0, 5,YIC, colr+15, 0, 1, 0, 0, "");
+ uiDefButS( block, TOG|BIT|6, B_REDR, "hook.", (short)(xco+=7),0, 50,YIC, &soops->deps_flags, 0, 1, 0, 0, "hook");
+ uiDefButC( block, COL, 0, "", (short)(xco+=60),0, 5,YIC, colr+18, 0, 1, 0, 0, "");
+ uiDefButS( block, TOG|BIT|7, B_REDR, "d cons.", (short)(xco+=7),0, 50,YIC, &soops->deps_flags, 0, 1, 0, 0, "d cons");
+ }
+#endif
+ else {
+ if(G.main->library.first)
+#ifdef WITH_VERSE
+ uiDefButS(block, MENU, B_REDR, "Outliner Display%t|Verse Servers %x9|Verse Sessions %x8|Libraries %x7|All Scenes %x0|Current Scene %x1|Visible Layers %x2|Groups %x6|Same Types %x5|Selected %x3|Active %x4", xco, 0, 100, 20, &soops->outlinevis, 0, 0, 0, 0, "");
+#else
+ uiDefButS(block, MENU, B_REDR, "Outliner Display%t|Libraries %x7|All Scenes %x0|Current Scene %x1|Visible Layers %x2|Groups %x6|Same Types %x5|Selected %x3|Active %x4", xco, 0, 100, 20, &soops->outlinevis, 0, 0, 0, 0, "");
+#endif /* WITH_VERSE */
+ else
+#ifdef WITH_VERSE
+ uiDefButS(block, MENU, B_REDR, "Outliner Display%t|Verse Servers %x9|Verse Sessions %x8|All Scenes %x0|Current Scene %x1|Visible Layers %x2|Groups %x6|Same Types %x5|Selected %x3|Active %x4", xco, 0, 100, 20, &soops->outlinevis, 0, 0, 0, 0, "");
+#else
+ uiDefButS(block, MENU, B_REDR, "Outliner Display%t|All Scenes %x0|Current Scene %x1|Visible Layers %x2|Groups %x6|Same Types %x5|Selected %x3|Active %x4", xco, 0, 100, 20, &soops->outlinevis, 0, 0, 0, 0, "");
+#endif /* WITH_VERSE */
+ }
+
+ /* always do as last */
+ curarea->headbutlen= xco+2*XIC;
+
+ uiDrawBlock(block);
+}
+
diff --git a/source/blender/src/header_script.c b/source/blender/src/header_script.c
new file mode 100644
index 00000000000..98f18c4e2ac
--- /dev/null
+++ b/source/blender/src/header_script.c
@@ -0,0 +1,280 @@
+/**
+ * header_script.c nov-2003
+ *
+ * Functions to draw the "Script Window" window header
+ * and handle user events sent to it.
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Willian P. Germano.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "BLI_blenlib.h"
+
+#include "BSE_headerbuttons.h"
+
+#include "DNA_ID.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "BIF_interface.h"
+#include "BIF_resources.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_toolbox.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_sca.h"
+#include "BSE_filesel.h"
+
+#include "BPI_script.h"
+#include "BPY_extern.h"
+#include "BPY_menus.h"
+
+#include "blendef.h"
+#include "mydevice.h"
+
+/* ********************** SCRIPT ****************************** */
+
+/* action executed after clicking in Scripts menu */
+static void do_scripts_submenus(void *int_arg, int event)
+{
+ int menutype = (long)int_arg;
+
+ BPY_menu_do_python (menutype, event);
+
+ //allqueue(REDRAWSCRIPT, 0);
+}
+
+static uiBlock *script_scripts_submenus(void *int_menutype)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+ BPyMenu *pym;
+ int i = 0, menutype = (long)int_menutype;
+
+ if ((menutype < 0) || (menutype > PYMENU_SCRIPTS_MENU_TOTAL))
+ return NULL;
+
+ block= uiNewBlock(&curarea->uiblocks, "scriptsscriptssubmenus", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_scripts_submenus, int_menutype);
+
+ for (pym = BPyMenuTable[menutype]; pym; pym = pym->next, i++) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_PYTHON, pym->name, 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, i, pym->tooltip?pym->tooltip:pym->filename);
+ }
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+
+ return block;
+}
+
+static void do_script_scriptsmenu(void *arg, int event)
+{
+ ScrArea *sa;
+
+ if(curarea->spacetype==SPACE_INFO) {
+ sa= closest_bigger_area();
+ areawinset(sa->win);
+ }
+
+ /* these are no defines, easier this way, the codes are in the function below */
+ switch(event) {
+ case 0: /* update menus */
+ BPyMenu_RemoveAllEntries();
+ if (BPyMenu_Init(1) == -1) error("Invalid scripts dir: check console");
+ break;
+ }
+
+// allqueue(REDRAWSCRIPT, 0);
+}
+
+/* Scripts menu */
+static uiBlock *script_scriptsmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 0, menuwidth = 120;
+ int i;
+
+ block= uiNewBlock(&curarea->uiblocks, "script_scriptsmenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_script_scriptsmenu, NULL);
+
+ for (i = 0; i < PYMENU_SCRIPTS_MENU_TOTAL; i++) {
+ uiDefIconTextBlockBut(block, script_scripts_submenus, (void *)(long)i, ICON_RIGHTARROW_THIN, BPyMenu_group_itoa(i), 0, yco-=20, menuwidth, 19, "");
+ }
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Update Menus", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "Use when a scripts folder or its contents are modified");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+ return block;
+}
+
+void do_script_buttons(unsigned short event)
+{
+ SpaceScript *sc= curarea->spacedata.first;
+ ID *id, *idtest;
+ int nr= 1;
+ Script *script = sc->script;
+
+ if (!sc) return;
+ if (sc->spacetype != SPACE_SCRIPT) return;
+
+ switch (event) {
+ case B_SCRIPTBROWSE:
+ if (sc->menunr==-2) {
+ activate_databrowse((ID *)script, ID_SCR, 0, B_SCRIPTBROWSE,
+ &sc->menunr, do_script_buttons);
+ break;
+ }
+
+ if(sc->menunr < 0) break;
+
+ nr = 1;
+ id = (ID *)script;
+
+ idtest= G.main->script.first;
+ while(idtest) {
+ if(nr==sc->menunr) {
+ break;
+ }
+ nr++;
+ idtest= idtest->next;
+ }
+ if(idtest!=id) {
+ sc->script= (Script *)idtest;
+
+ allqueue(REDRAWSCRIPT, 0);
+ allqueue(REDRAWHEADERS, 0);
+ }
+ break;
+ case B_SCRIPT2PREV:
+ if(sc->next) {
+ BLI_remlink(&curarea->spacedata, sc);
+ BLI_addtail(&curarea->spacedata, sc);
+ sc = curarea->spacedata.first;
+ newspace(curarea, sc->spacetype);
+ }
+ break;
+ }
+
+ return;
+}
+
+void script_buttons(void)
+{
+ uiBlock *block;
+ SpaceScript *sc= curarea->spacedata.first;
+ short xco = 8, xmax;
+ char naam[256];
+
+ if (!sc || sc->spacetype != SPACE_SCRIPT) return;
+
+ sprintf(naam, "header %d", curarea->headwin);
+ block= uiNewBlock(&curarea->uiblocks, naam, UI_EMBOSS, UI_HELV, curarea->headwin);
+
+ if(area_is_active_area(curarea)) uiBlockSetCol(block, TH_HEADER);
+ else uiBlockSetCol(block, TH_HEADERDESEL);
+
+ curarea->butspacetype= SPACE_SCRIPT;
+
+ uiDefIconTextButC(block, ICONTEXTROW,B_NEWSPACE, ICON_VIEW3D,
+ windowtype_pup(), xco,0,XIC+10,YIC, &(curarea->butspacetype), 1.0,
+ SPACEICONMAX, 0, 0, "Displays Current Window Type. Click for menu"
+ " of available types.");
+ xco += XIC+14;
+
+ uiBlockSetEmboss(block, UI_EMBOSSN);
+ if(curarea->flag & HEADER_NO_PULLDOWN) {
+ uiDefIconButBitS(block, TOG, HEADER_NO_PULLDOWN, B_FLIPINFOMENU, ICON_DISCLOSURE_TRI_RIGHT,
+ xco,2,XIC,YIC-2,
+ &(curarea->flag), 0, 0, 0, 0, "Enables display of pulldown menus");
+ } else {
+ uiDefIconButBitS(block, TOG, HEADER_NO_PULLDOWN, B_FLIPINFOMENU, ICON_DISCLOSURE_TRI_DOWN,
+ xco,2,XIC,YIC-2,
+ &(curarea->flag), 0, 0, 0, 0, "Hides pulldown menus");
+ }
+ uiBlockSetEmboss(block, UI_EMBOSS);
+ xco+=XIC;
+
+ /* pull down menus */
+ if((curarea->flag & HEADER_NO_PULLDOWN)==0) {
+ uiBlockSetEmboss(block, UI_EMBOSSP);
+
+ xmax= GetButStringLength("Scripts");
+ uiDefPulldownBut(block,script_scriptsmenu, NULL, "Scripts", xco, 0, xmax, 20, "");
+ xco+=xmax;
+ }
+
+ uiBlockSetEmboss(block, UI_EMBOSS);
+
+ uiBlockBeginAlign(block);
+ uiDefIconBut(block, BUT, B_SCRIPT2PREV, ICON_GO_LEFT, xco+=XIC, 0, XIC, YIC,
+ 0, 0, 0, 0, 0, "Returns to previous window");
+
+ /* FULL WINDOW */
+ if(curarea->full)
+ uiDefIconBut(block, BUT,B_FULL, ICON_SPLITSCREEN, xco+=XIC,0,XIC,YIC, 0, 0,
+ 0, 0, 0, "Returns to multiple views window (CTRL+Up arrow)");
+ else
+ uiDefIconBut(block, BUT,B_FULL, ICON_FULLSCREEN, xco+=XIC,0,XIC,YIC, 0, 0,
+ 0, 0, 0, "Makes current window full screen (CTRL+Down arrow)");
+ uiBlockEndAlign(block);
+
+ /* STD SCRIPT BUTTONS */
+ xco += 2*XIC;
+ xco= std_libbuttons(block, xco, 0, 0, NULL, B_SCRIPTBROWSE, ID_SCRIPT, 0, (ID*)sc->script, 0, &(sc->menunr), 0, 0, 0, 0, 0);
+
+ /* always as last */
+ curarea->headbutlen= xco+2*XIC;
+
+ uiDrawBlock(block);
+}
+
+
+/* ********************** SCRIPT ****************************** */
+
diff --git a/source/blender/src/header_seq.c b/source/blender/src/header_seq.c
new file mode 100644
index 00000000000..4075371108b
--- /dev/null
+++ b/source/blender/src/header_seq.c
@@ -0,0 +1,727 @@
+/**
+ * header_seq.c oct-2003
+ *
+ * Functions to draw the "Video Sequence Editor" window header
+ * and handle user events sent to it.
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "BMF_Api.h"
+#include "BIF_language.h"
+
+#include "DNA_ID.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_sequence_types.h"
+#include "DNA_space_types.h"
+#include "BLI_blenlib.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BIF_drawseq.h"
+#include "BIF_interface.h"
+#include "BIF_resources.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_editseq.h"
+#include "BSE_drawipo.h"
+#include "BSE_headerbuttons.h"
+#include "BSE_sequence.h"
+#include "BSE_time.h"
+#include "blendef.h"
+#include "mydevice.h"
+
+static int viewmovetemp = 0;
+
+static void do_seq_viewmenu(void *arg, int event)
+{
+ extern int play_anim(int mode);
+ Sequence * last_seq = get_last_seq();
+ SpaceSeq * sseq = curarea->spacedata.first;
+
+ switch(event)
+ {
+ case 1: /* Play Back Animation */
+ play_anim(0);
+ break;
+ case 2: /* Play Back Animation in All */
+ play_anim(1);
+ break;
+ case 3:
+ do_seq_buttons(B_SEQHOME);
+ break;
+ case 4:
+ if(last_seq) {
+ CFRA= last_seq->startdisp;
+ G.v2d->cur.xmin= last_seq->startdisp- (last_seq->len/20);
+ G.v2d->cur.xmax= last_seq->enddisp+ (last_seq->len/20);
+ update_for_newframe();
+ }
+ break;
+ case 5: /* Lock time */
+ G.v2d->flag ^= V2D_VIEWLOCK;
+ if (G.v2d->flag & V2D_VIEWLOCK) {
+ view2d_do_locks(curarea, 0);
+ }
+ break;
+ case 6: /* Draw time/frames */
+ sseq->flag ^= SEQ_DRAWFRAMES;
+ break;
+ }
+}
+
+static uiBlock *seq_viewmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+ SpaceSeq * sseq = curarea->spacedata.first;
+
+ block= uiNewBlock(&curarea->uiblocks, "seq_viewmenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_seq_viewmenu, NULL);
+
+ if (sseq->mainb == 0) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Play Back Animation "
+ "in all Sequence Areas|Alt A", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ } else {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Play Back Animation "
+ "in this window|Alt A", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ }
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Play Back Animation in all "
+ "3D Views and Sequence Areas|Alt Shift A",
+ 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "View All|Home", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "View Selected|NumPad .", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+
+ /* Lock Time */
+ uiDefIconTextBut(block, BUTM, 1, (G.v2d->flag & V2D_VIEWLOCK)?ICON_CHECKBOX_HLT:ICON_CHECKBOX_DEHLT,
+ "Lock Time to Other Windows|", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+
+ /* Draw time or frames.*/
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ if(sseq->flag & SEQ_DRAWFRAMES)
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Show Seconds|T", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 6, "");
+ else
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Show Frames|T", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 6, "");
+
+
+ if(!curarea->full) uiDefIconTextBut(block, BUTM, B_FULL, ICON_BLANK1, "Maximize Window|Ctrl UpArrow", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0,0, "");
+ else uiDefIconTextBut(block, BUTM, B_FULL, ICON_BLANK1, "Tile Window|Ctrl DownArrow", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 0, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+static void do_seq_selectmenu(void *arg, int event)
+{
+ switch(event)
+ {
+ case 0:
+ borderselect_seq();
+ break;
+ case 1:
+ swap_select_seq();
+ break;
+ case 2:
+ select_dir_from_last(1);
+ break;
+ case 3:
+ select_dir_from_last(2);
+ break;
+ case 4:
+ select_surround_from_last();
+ break;
+ case 5:
+ select_neighbor_from_last(1);
+ break;
+ case 6:
+ select_neighbor_from_last(2);
+ break;
+ case 7:
+ select_linked_seq(2);
+ break;
+ }
+}
+
+static uiBlock *seq_selectmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "seq_selectmenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_seq_selectmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Strips to the Left", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Strips to the Right", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Surrounding Handles", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Left Handles", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 5, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Right Handles", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 6, "");
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Border Select|B", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Linked|Ctrl L", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 7, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select/Deselect All|A", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+static void do_seq_addmenu_effectmenu(void *arg, int event)
+{
+ switch(event)
+ {
+ case 0:
+ add_sequence(SEQ_ADD);
+ break;
+ case 1:
+ add_sequence(SEQ_SUB);
+ break;
+ case 2:
+ add_sequence(SEQ_MUL);
+ break;
+ case 3:
+ add_sequence(SEQ_CROSS);
+ break;
+ case 4:
+ add_sequence(SEQ_GAMCROSS);
+ break;
+ case 5:
+ add_sequence(SEQ_ALPHAOVER);
+ break;
+ case 6:
+ add_sequence(SEQ_ALPHAUNDER);
+ break;
+ case 7:
+ add_sequence(SEQ_OVERDROP);
+ break;
+ case 8:
+ add_sequence(SEQ_PLUGIN);
+ break;
+ case 9:
+ add_sequence(SEQ_WIPE);
+ break;
+ case 10:
+ add_sequence(SEQ_GLOW);
+ break;
+ case 11:
+ add_sequence(SEQ_TRANSFORM);
+ break;
+ case 12:
+ add_sequence(SEQ_COLOR);
+ break;
+ case 13:
+ add_sequence(SEQ_SPEED);
+ break;
+ }
+}
+
+static uiBlock *seq_addmenu_effectmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "seq_addmenu_effectmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_seq_addmenu_effectmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Add", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Subtract", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Multiply", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Cross", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Gamma Cross", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Alpha Over", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 5, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Alpha Under", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 6, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Alpha Over Drop", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 7, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Wipe", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 9, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Glow", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 10, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Transform", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 11, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Color Generator", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 12, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Speed Control", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 13, "");
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Plugin...", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 8, "");
+
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+
+ return block;
+}
+
+
+static void do_seq_addmenu(void *arg, int event)
+{
+ switch(event)
+ {
+ case 0:
+ add_sequence(SEQ_IMAGE);
+ break;
+ case 1:
+ add_sequence(SEQ_MOVIE);
+ break;
+ case 2:
+ add_sequence(SEQ_RAM_SOUND);
+ break;
+ case 3:
+ add_sequence(SEQ_HD_SOUND);
+ break;
+ case 4:
+ add_sequence(SEQ_SCENE);
+ break;
+ case 5:
+ add_sequence(SEQ_MOVIE_AND_HD_SOUND);
+ break;
+ }
+}
+
+static uiBlock *seq_addmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "seq_addmenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_seq_addmenu, NULL);
+
+ uiDefIconTextBlockBut(block, seq_addmenu_effectmenu, NULL, ICON_RIGHTARROW_THIN, "Effect", 0, yco-=20, 120, 19, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+#ifdef WITH_FFMPEG
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Audio (RAM)", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Audio (HD)", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
+#else
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Audio (Wav)", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
+#endif
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Scene", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Images", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Movie", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
+#ifdef WITH_FFMPEG
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Movie + Audio (HD)", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 5, "");
+#endif
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ }
+
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+static void do_seq_editmenu(void *arg, int event)
+{
+ SpaceSeq *sseq;
+
+ sseq= curarea->spacedata.first;
+
+ switch(event)
+ {
+ case 1: /* Change Strip... */
+ change_sequence();
+ break;
+ case 2: /* Make Meta Strip */
+ make_meta();
+ break;
+ case 3: /* Separate Meta Strip */
+ un_meta();
+ break;
+ case 4: /* Properties... */
+ add_blockhandler(curarea, SEQ_HANDLER_PROPERTIES, UI_PNL_UNSTOW);
+ break;
+ case 5: /* Duplicate */
+ add_duplicate_seq();
+ break;
+ case 6: /* Delete */
+ del_seq();
+ break;
+ case 7: /* Grab/Extend */
+ transform_seq('e', 0);
+ break;
+ case 8:
+ set_filter_seq();
+ break;
+ case 9:
+ enter_meta();
+ break;
+ case 10:
+ exit_meta();
+ break;
+ case 11: /* grab/move */
+ transform_seq('g', 0);
+ break;
+ case 12: /* Snap to Current Frame */
+ seq_snap(event);
+ break;
+ case 13: /* Cut at Current Frame */
+ seq_cut(CFRA);
+ break;
+ case 14:
+ reassign_inputs_seq_effect();
+ break;
+ case 15:
+ seq_remap_paths();
+ break;
+ case 16:
+ seq_separate_images();
+ break;
+ case 17:
+ reload_sequence();
+ break;
+ }
+}
+
+static uiBlock *seq_editmenu(void *arg_unused)
+{
+ uiBlock *block;
+ Editing *ed;
+ short yco= 0, menuwidth=120;
+ Sequence * last_seq = get_last_seq();
+
+ ed = G.scene->ed;
+
+ block= uiNewBlock(&curarea->uiblocks, "seq_editmenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_seq_editmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_MENU_PANEL, "Strip Properties...|N", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Grab/Move|G", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 11, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Grab/Extend from frame|E", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 7, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Snap to Current Frame|Shift S, 1", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 12, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Cut at Current Frame|K", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 13, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Separate Images to Strips|Y", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 16, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Duplicate|Shift D", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 5, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Delete|X", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 6, "");
+
+ if (last_seq != NULL && last_seq->type != SEQ_MOVIE) {
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ if(last_seq->type >= SEQ_EFFECT) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Change Effect...|C", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Reassign Inputs|R", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 14, "");
+ }
+ else if(last_seq->type == SEQ_IMAGE) uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Change Image...|C", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
+ else uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Change Scene...|C", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
+
+ if(last_seq->type==SEQ_IMAGE)
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Remap Paths...|Shift R", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 15, "");
+
+ }
+
+/* if (last_seq != NULL && last_seq->type == SEQ_MOVIE) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Set Filter Y|F", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 8, "");
+ }
+*/
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Make Meta Strip...|M", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Separate Meta Strip...|Alt M", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
+ if ((ed != NULL) && (ed->metastack.first > 0)){
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Enter/Exit Meta Strip|Tab", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 10, "");
+ }
+ else {
+ if (last_seq != NULL && last_seq->type == SEQ_META) {
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Enter/Exit Meta Strip|Tab", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 9, "");
+ }
+ }
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Reload Strip Data...|Alt R", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 17, "");
+
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+static void do_seq_markermenu(void *arg, int event)
+{
+ SpaceSeq *sseq= curarea->spacedata.first;
+
+ switch(event)
+ {
+ case 1:
+ add_marker(CFRA);
+ break;
+ case 2:
+ duplicate_marker();
+ break;
+ case 3:
+ remove_marker();
+ break;
+ case 4:
+ rename_marker();
+ break;
+ case 5:
+ transform_markers('g', 0);
+ break;
+ case 6:
+ sseq->flag ^= SEQ_MARKER_TRANS;
+ break;
+
+ }
+
+ allqueue(REDRAWMARKER, 0);
+}
+
+static uiBlock *seq_markermenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ SpaceSeq *sseq= curarea->spacedata.first;
+
+ block= uiNewBlock(&curarea->uiblocks, "ipo_markermenu",
+ UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_seq_markermenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Add Marker|Ctrl Alt M", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Duplicate Marker|Ctrl Shift D", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Delete Marker", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "(Re)Name Marker|Ctrl M", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Grab/Move Marker|Ctrl G", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, (sseq->flag & SEQ_MARKER_TRANS)?ICON_CHECKBOX_HLT:ICON_CHECKBOX_DEHLT,
+ "Transform Markers", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, 6, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ } else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+void do_seq_buttons(short event)
+{
+ Editing *ed;
+ SpaceSeq *sseq= curarea->spacedata.first;
+
+ ed= G.scene->ed;
+ if(ed==0) return;
+
+ switch(event) {
+ case B_SEQHOME:
+ if(sseq->mainb)
+ seq_reset_imageofs(sseq);
+ else {
+ G.v2d->cur= G.v2d->tot;
+ test_view2d(G.v2d, curarea->winx, curarea->winy);
+ view2d_do_locks(curarea, V2D_LOCK_COPY);
+ }
+ scrarea_queue_winredraw(curarea);
+ break;
+ case B_SEQCLEAR:
+ free_imbuf_seq();
+ allqueue(REDRAWSEQ, 1);
+ break;
+ }
+}
+
+void seq_buttons()
+{
+ SpaceSeq *sseq;
+ short xco;
+ char naam[20];
+ uiBlock *block;
+ short xmax;
+
+ sseq= curarea->spacedata.first;
+
+ sprintf(naam, "header %d", curarea->headwin);
+ block= uiNewBlock(&curarea->uiblocks, naam, UI_EMBOSS, UI_HELV, curarea->headwin);
+
+ if(area_is_active_area(curarea)) uiBlockSetCol(block, TH_HEADER);
+ else uiBlockSetCol(block, TH_HEADERDESEL);
+
+ curarea->butspacetype= SPACE_SEQ;
+
+ xco = 8;
+ uiDefIconTextButC(block, ICONTEXTROW,B_NEWSPACE, ICON_VIEW3D, windowtype_pup(), xco,0,XIC+10,YIC, &(curarea->butspacetype), 1.0, SPACEICONMAX, 0, 0, "Displays Current Window Type. Click for menu of available types.");
+ xco+= XIC+14;
+
+ uiBlockSetEmboss(block, UI_EMBOSSN);
+ if(curarea->flag & HEADER_NO_PULLDOWN) {
+ uiDefIconButBitS(block, TOG, HEADER_NO_PULLDOWN, B_FLIPINFOMENU, ICON_DISCLOSURE_TRI_RIGHT,
+ xco,2,XIC,YIC-2,
+ &(curarea->flag), 0, 0, 0, 0, "Enables display of pulldown menus");
+ } else {
+ uiDefIconButBitS(block, TOG, HEADER_NO_PULLDOWN, B_FLIPINFOMENU, ICON_DISCLOSURE_TRI_DOWN,
+ xco,2,XIC,YIC-2,
+ &(curarea->flag), 0, 0, 0, 0, "Hides pulldown menus");
+ }
+ uiBlockSetEmboss(block, UI_EMBOSS);
+ xco+=XIC;
+
+
+ /* pull down menus */
+ if((curarea->flag & HEADER_NO_PULLDOWN)==0) {
+ uiBlockSetEmboss(block, UI_EMBOSSP);
+
+ xmax= GetButStringLength("View");
+ uiDefPulldownBut(block,seq_viewmenu, NULL, "View", xco, -2, xmax-3, 24, "");
+ xco+=xmax;
+
+ xmax= GetButStringLength("Select");
+ uiDefPulldownBut(block,seq_selectmenu, NULL, "Select", xco, -2, xmax-3, 24, "");
+ xco+=xmax;
+
+ xmax= GetButStringLength("Marker");
+ uiDefPulldownBut(block,seq_markermenu, NULL, "Marker", xco, -2, xmax-3, 24, "");
+ xco+=xmax;
+
+ xmax= GetButStringLength("Add");
+ uiDefPulldownBut(block, seq_addmenu, NULL, "Add", xco, -2, xmax-3, 24, "");
+ xco+= xmax;
+
+ xmax= GetButStringLength("Strip");
+ uiDefPulldownBut(block, seq_editmenu, NULL, "Strip", xco, -2, xmax-3, 24, "");
+ xco+= xmax;
+
+ /* end of pull down menus */
+ uiBlockSetEmboss(block, UI_EMBOSS);
+ }
+
+ /* IMAGE */
+ uiDefIconTextButS(block, ICONTEXTROW,B_REDR, ICON_SEQ_SEQUENCER,
+ "Image Preview: %t"
+ "|Sequence %x0"
+ "|Image Preview %x1"
+ "|Luma Waveform %x2"
+ "|Chroma Vectorscope %x3",
+ xco,0,XIC+10,YIC, &sseq->mainb, 0.0, 3.0,
+ 0, 0,
+ "Shows the sequence output image preview");
+
+ xco+= 8 + XIC+10;
+
+ /* CHANNEL shown in 3D preview */
+ if(sseq->mainb) {
+ int minchan = 0;
+
+ if (G.scene->ed && ((Editing*)G.scene->ed)->metastack.first)
+ minchan = -BLI_countlist(&((Editing*)G.scene->ed)->metastack);
+
+ uiDefButS(block, NUM, B_REDR, "Chan:",
+ xco, 0, 3.5 * XIC,YIC,
+ &sseq->chanshown, minchan, MAXSEQ, 0, 0,
+ "The channel number shown in the image preview. 0 is the result of all strips combined.");
+
+ xco+= 8 + XIC*3.5;
+ }
+
+
+ /* ZOOM and BORDER */
+ xco+= 8;
+ uiBlockBeginAlign(block);
+ uiDefIconButI(block, TOG, B_VIEW2DZOOM, ICON_VIEWZOOM, xco,0,XIC,YIC, &viewmovetemp, 0, 0, 0, 0, "Zooms view in and out (Ctrl MiddleMouse)");
+ uiDefIconBut(block, BUT, B_IPOBORDER, ICON_BORDERMOVE, xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0, "Zooms view to fit area");
+ uiBlockEndAlign(block);
+
+ /* CLEAR MEM */
+ xco+= 8;
+
+ /* CLEAR MEM */
+ xco+= 8;
+ uiDefBut(block, BUT, B_SEQCLEAR, "Refresh", xco+=XIC,0,3*XIC,YIC, 0, 0, 0, 0, 0, "Clears all buffered images in memory");
+
+ uiDrawBlock(block);
+}
diff --git a/source/blender/src/header_sound.c b/source/blender/src/header_sound.c
new file mode 100644
index 00000000000..c2fb72d7d17
--- /dev/null
+++ b/source/blender/src/header_sound.c
@@ -0,0 +1,444 @@
+/**
+ * header_sound.c oct-2003
+ *
+ * Functions to draw the "Audio Timeline" window header
+ * and handle user events sent to it.
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "BMF_Api.h"
+#include "BIF_language.h"
+
+#include "DNA_ID.h"
+#include "DNA_screen_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_sound_types.h"
+#include "DNA_space_types.h"
+#include "DNA_view2d_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BIF_editsound.h"
+#include "BIF_gl.h"
+#include "BIF_interface.h"
+#include "BIF_previewrender.h"
+#include "BIF_resources.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_toolbox.h"
+#include "BIF_butspace.h"
+
+#include "BKE_global.h"
+#include "BKE_main.h"
+
+#include "BSE_drawipo.h"
+#include "BSE_filesel.h"
+#include "BSE_headerbuttons.h"
+#include "BSE_time.h"
+
+#include "blendef.h"
+#include "mydevice.h"
+
+void do_sound_buttons(unsigned short event)
+{
+ ID *id, *idtest;
+ int nr;
+ char name[256];
+
+ switch(event) {
+
+ case B_SOUNDBROWSE:
+ if(G.ssound->sndnr== -2) {
+ activate_databrowse((ID *)G.ssound->sound, ID_SO, 0,
+ B_SOUNDBROWSE, &G.ssound->sndnr, do_sound_buttons);
+ return;
+ }
+ if (G.ssound->sndnr < 0) break;
+ if (G.ssound->sndnr == 32766) {
+ if (G.ssound && G.ssound->sound) strcpy(name, G.ssound->sound->name);
+ else strcpy(name, U.sounddir);
+ activate_fileselect(FILE_SPECIAL, "SELECT WAV FILE", name,
+ load_space_sound);
+ } else {
+ nr= 1;
+ id= (ID *)G.ssound->sound;
+
+ idtest= G.main->sound.first;
+ while(idtest) {
+ if(nr==G.ssound->sndnr) {
+ break;
+ }
+ nr++;
+ idtest= idtest->next;
+ }
+
+ if(idtest==0) { /* no new */
+ return;
+ }
+
+ if(idtest!=id) {
+ G.ssound->sound= (bSound *)idtest;
+ if(idtest->us==0) idtest->us= 1;
+ allqueue(REDRAWSOUND, 0);
+ }
+ }
+
+ break;
+ case B_SOUNDBROWSE2:
+ id = (ID *)G.buts->lockpoin;
+ if(G.buts->texnr == -2) {
+ activate_databrowse(id, ID_SO, 0, B_SOUNDBROWSE2,
+ &G.buts->texnr, do_sound_buttons);
+ return;
+ }
+ if (G.buts->texnr < 0) break;
+ if (G.buts->texnr == 32766) {
+ if (id) strcpy(name, ((bSound *)id)->name);
+ else strcpy(name, U.sounddir);
+ activate_fileselect(FILE_SPECIAL, "SELECT WAV FILE", name, load_sound_buttons);
+ }
+ else {
+ nr= 1;
+
+ idtest= G.main->sound.first;
+ while (idtest) {
+ if(nr == G.buts->texnr) {
+ break;
+ }
+ nr++;
+ idtest = idtest->next;
+ }
+
+ if (idtest == 0) { /* geen new */
+ return;
+ }
+
+ if (idtest != id) {
+ G.buts->lockpoin = (bSound *)idtest;
+ if(idtest->us==0) idtest->us= 1;
+ allqueue(REDRAWBUTSSCENE, 0);
+ }
+ }
+ break;
+
+ case B_SOUNDHOME:
+ if(G.ssound->sound==NULL) {
+ G.v2d->tot.xmin= G.scene->r.sfra;
+ G.v2d->tot.xmax= G.scene->r.efra;
+ }
+ G.v2d->cur= G.v2d->tot;
+ test_view2d(G.v2d, curarea->winx, curarea->winy);
+ view2d_do_locks(curarea, V2D_LOCK_COPY);
+ scrarea_queue_winredraw(curarea);
+ break;
+ }
+}
+
+static void do_sound_viewmenu(void *arg, int event)
+{
+ extern int play_anim(int mode);
+
+ switch(event) {
+ case 1: /* Play Back Animation */
+ play_anim(0);
+ break;
+ case 2: /* Play Back Animation in All */
+ play_anim(1);
+ break;
+ case 3: /* View All */
+ do_sound_buttons(B_SOUNDHOME);
+ break;
+ case 4: /* Maximize Window */
+ /* using event B_FULL */
+ break;
+ case 5: /* jump to next marker */
+ nextprev_marker(1);
+ break;
+ case 6: /* jump to previous marker */
+ nextprev_marker(-1);
+ break;
+ case 7:
+ G.v2d->flag ^= V2D_VIEWLOCK;
+ if(G.v2d->flag & V2D_VIEWLOCK)
+ view2d_do_locks(curarea, 0);
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *sound_viewmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "sound_viewmenu",
+ UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_sound_viewmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Jump To Next Marker|PageUp", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0, 5, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Jump To Prev Marker|PageDown", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 0, 6, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Play Back Animation|Alt A", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Play Back Animation in 3D View|Alt Shift A", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "View All|Home", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+
+ uiDefIconTextBut(block, BUTM, 1, (G.v2d->flag & V2D_VIEWLOCK)?ICON_CHECKBOX_HLT:ICON_CHECKBOX_DEHLT,
+ "Lock Time to Other Windows|", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 7, "");
+
+ if (!curarea->full)
+ uiDefIconTextBut(block, BUTM, B_FULL, ICON_BLANK1, "Maximize Window|Ctrl UpArrow", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
+ else
+ uiDefIconTextBut(block, BUTM, B_FULL, ICON_BLANK1, "Tile Window|Ctrl DownArrow", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+static void do_sound_markermenu(void *arg, int event)
+{
+ switch(event)
+ {
+ case 1:
+ add_marker(CFRA);
+ break;
+ case 2:
+ duplicate_marker();
+ break;
+ case 3:
+ remove_marker();
+ break;
+ case 4:
+ rename_marker();
+ break;
+ case 5:
+ transform_markers('g', 0);
+ break;
+ }
+
+ allqueue(REDRAWMARKER, 0);
+}
+
+static uiBlock *sound_markermenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "sound_markermenu",
+ UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_sound_markermenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Add Marker|M", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Duplicate Marker|Shift D", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Delete Marker|X", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "(Re)Name Marker|Ctrl M", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Grab/Move Marker|G", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+
+void sound_buttons(void)
+{
+ uiBlock *block;
+ short xco, xmax;
+ char naam[256];
+ char ch[20];
+
+ sprintf(naam, "header %d", curarea->headwin);
+ block= uiNewBlock(&curarea->uiblocks, naam, UI_EMBOSS, UI_HELV, curarea->headwin);
+
+ if(area_is_active_area(curarea)) uiBlockSetCol(block, TH_HEADER);
+ else uiBlockSetCol(block, TH_HEADERDESEL);
+
+ curarea->butspacetype= SPACE_SOUND;
+
+ xco = 8;
+
+ uiDefIconTextButC(block, ICONTEXTROW,B_NEWSPACE, ICON_VIEW3D,
+ windowtype_pup(), xco, 0, XIC+10, YIC,
+ &(curarea->butspacetype), 1.0, SPACEICONMAX, 0, 0,
+ "Displays Current Window Type. "
+ "Click for menu of available types.");
+
+ xco += XIC + 14;
+
+ uiBlockSetEmboss(block, UI_EMBOSSN);
+ if (curarea->flag & HEADER_NO_PULLDOWN) {
+ uiDefIconButBitS(block, TOG, HEADER_NO_PULLDOWN, B_FLIPINFOMENU,
+ ICON_DISCLOSURE_TRI_RIGHT,
+ xco,2,XIC,YIC-2,
+ &(curarea->flag), 0, 0, 0, 0,
+ "Show pulldown menus");
+ }
+ else {
+ uiDefIconButBitS(block, TOG, HEADER_NO_PULLDOWN, B_FLIPINFOMENU,
+ ICON_DISCLOSURE_TRI_DOWN,
+ xco,2,XIC,YIC-2,
+ &(curarea->flag), 0, 0, 0, 0,
+ "Hide pulldown menus");
+ }
+ uiBlockSetEmboss(block, UI_EMBOSS);
+ xco+=XIC;
+
+ if((curarea->flag & HEADER_NO_PULLDOWN)==0) {
+ /* pull down menus */
+ uiBlockSetEmboss(block, UI_EMBOSSP);
+
+ xmax= GetButStringLength("View");
+ uiDefPulldownBut(block, sound_viewmenu, NULL,
+ "View", xco, -2, xmax-3, 24, "");
+ xco+= xmax;
+
+ xmax= GetButStringLength("Marker");
+ uiDefPulldownBut(block, sound_markermenu, NULL,
+ "Marker", xco, -2, xmax-3, 24, "");
+ xco+= xmax;
+ }
+
+ uiBlockSetEmboss(block, UI_EMBOSS);
+ xco= std_libbuttons(block, xco+8, 0, 0, NULL, B_SOUNDBROWSE, ID_SO, 0, (ID *)G.ssound->sound, 0, &(G.ssound->sndnr), 1, 0, 0, 0, 0);
+
+ if(G.ssound->sound) {
+ bSound *sound= G.ssound->sound;
+
+ if (sound->sample && sound->sample->len)
+ {
+ if (sound->sample->channels == 1)
+ strcpy(ch, "Mono");
+ else if (sound->sample->channels == 2)
+ strcpy(ch, "Stereo");
+ else
+ strcpy(ch, "Unknown");
+
+ sprintf(naam, "Sample: %s, %d bit, %d Hz, %d samples", ch, sound->sample->bits, sound->sample->rate, sound->sample->len);
+ cpack(0x0);
+ glRasterPos2i(xco+10, 5);
+ BMF_DrawString(uiBlockGetCurFont(block), naam);
+ }
+ else
+ {
+ sprintf(naam, "No sample info available.");
+ cpack(0x0);
+ glRasterPos2i(xco+10, 5);
+ BMF_DrawString(uiBlockGetCurFont(block), naam);
+ }
+
+ }
+
+ /* always as last */
+ curarea->headbutlen= xco+2*XIC;
+
+ uiDrawBlock(block);
+}
+
+/* the next two functions are also called from fileselect: */
+
+void load_space_sound(char *str)
+{
+ bSound *sound;
+
+ sound= sound_new_sound(str);
+ if (sound) {
+ if (G.ssound) {
+ G.ssound->sound= sound;
+ }
+ } else {
+ error("Not a valid sample: %s", str);
+ }
+
+ allqueue(REDRAWSOUND, 0);
+ allqueue(REDRAWBUTSLOGIC, 0);
+}
+
+void load_sound_buttons(char *str)
+{
+ bSound *sound;
+
+ sound= sound_new_sound(str);
+ if (sound) {
+ if (curarea && curarea->spacetype==SPACE_BUTS) {
+ if (G.buts->mainb == CONTEXT_SCENE) {
+ if( G.buts->tab[CONTEXT_SCENE]==TAB_SCENE_SOUND )
+ G.buts->lockpoin = sound;
+ }
+ }
+ }
+ else {
+ error("Not a valid sample: %s", str);
+ }
+
+ allqueue(REDRAWBUTSSCENE, 0);
+}
diff --git a/source/blender/src/header_text.c b/source/blender/src/header_text.c
new file mode 100644
index 00000000000..04c354fb2b1
--- /dev/null
+++ b/source/blender/src/header_text.c
@@ -0,0 +1,821 @@
+/**
+ * header_text.c oct-2003
+ *
+ * Functions to draw the "Text Editor" window header
+ * and handle user events sent to it.
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "BMF_Api.h"
+#include "BIF_language.h"
+
+#include "BSE_headerbuttons.h"
+
+#include "DNA_ID.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_text_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_action_types.h"
+
+#include "BIF_drawtext.h"
+#include "BIF_interface.h"
+#include "BIF_resources.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_toolbox.h"
+
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_sca.h"
+#include "BKE_text.h"
+#include "BKE_depsgraph.h"
+
+#include "BSE_filesel.h"
+
+#include "BPY_extern.h"
+#include "BPY_menus.h"
+
+#include "blendef.h"
+#include "mydevice.h"
+
+void do_text_buttons(unsigned short event)
+{
+ SpaceText *st= curarea->spacedata.first;
+ ID *id, *idtest;
+ int nr= 1;
+ Text *text;
+
+ if (!st) return;
+ if (st->spacetype != SPACE_TEXT) return;
+
+ switch (event) {
+ case B_TEXTBROWSE:
+ if (st->menunr==-2) {
+ activate_databrowse((ID *)st->text, ID_TXT, 0, B_TEXTBROWSE,
+ &st->menunr, do_text_buttons);
+ break;
+ }
+ if(st->menunr < 0) break;
+
+ text= st->text;
+
+ nr= 1;
+ id= (ID *)text;
+
+ if (st->menunr==32767) {
+ st->text= (Text *)add_empty_text( "Text" );
+
+ st->top= 0;
+
+ allqueue(REDRAWTEXT, 0);
+ allqueue(REDRAWHEADERS, 0);
+ }
+ else if (st->menunr==32766) {
+ activate_fileselect(FILE_SPECIAL, "Open Text File", G.sce, add_text_fs);
+ return;
+ }
+ else {
+ idtest= G.main->text.first;
+ while(idtest) {
+ if(nr==st->menunr) {
+ break;
+ }
+ nr++;
+ idtest= idtest->next;
+ }
+ if(idtest==0) { /* new text */
+ activate_fileselect(FILE_SPECIAL, "Open Text File",
+ G.sce, add_text_fs);
+ return;
+ }
+ if(idtest!=id) {
+ st->text= (Text *)idtest;
+ st->top= 0;
+
+ pop_space_text(st);
+ if (st->showsyntax) get_format_string();
+ allqueue(REDRAWTEXT, 0);
+ allqueue(REDRAWHEADERS, 0);
+ }
+ }
+ break;
+
+ case B_TEXTDELETE:
+ {
+ Object *obt;
+ bConstraint *con;
+ int update;
+
+ text= st->text;
+ if (!text) return;
+
+ /* make the previous text active, if its not there make the next text active */
+ if (st->text->id.prev) {
+ st->text = st->text->id.prev;
+ pop_space_text(st);
+ } else if (st->text->id.next) {
+ st->text = st->text->id.next;
+ pop_space_text(st);
+ }
+
+ /*check all pyconstraints*/
+ for (obt=G.main->object.first; obt; obt=obt->id.next) {
+ update = 0;
+ if(obt->type==OB_ARMATURE && obt->pose) {
+ bPoseChannel *pchan;
+ for(pchan= obt->pose->chanbase.first; pchan; pchan= pchan->next) {
+ for (con = pchan->constraints.first; con; con=con->next) {
+ if (con->type==CONSTRAINT_TYPE_PYTHON) {
+ bPythonConstraint *data = con->data;
+ if (data->text==text) data->text = NULL;
+ update = 1;
+
+ }
+ }
+ }
+ }
+ for (con = obt->constraints.first; con; con=con->next) {
+ if (con->type==CONSTRAINT_TYPE_PYTHON) {
+ bPythonConstraint *data = con->data;
+ if (data->text==text) data->text = NULL;
+ update = 1;
+ }
+ }
+
+ if (update) {
+ DAG_object_flush_update(G.scene, obt, OB_RECALC_DATA);
+ }
+ }
+
+ BPY_clear_bad_scriptlinks(text);
+ free_text_controllers(text);
+
+ unlink_text(text);
+ free_libblock(&G.main->text, text);
+
+ allqueue(REDRAWTEXT, 0);
+ allqueue(REDRAWHEADERS, 0);
+
+ /*for if any object constraints were changed.*/
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSOBJECT, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+
+ BIF_undo_push("Delete Text");
+ }
+ break;
+
+/*
+ case B_TEXTSTORE:
+ st->text->flags ^= TXT_ISEXT;
+
+ allqueue(REDRAWHEADERS, 0);
+ break;
+*/
+ case B_TEXTLINENUM:
+ allqueue(REDRAWTEXT, 0);
+ allqueue(REDRAWHEADERS, 0);
+ break;
+
+ case B_TEXTFONT:
+ switch(st->font_id) {
+ case 0:
+ st->lheight= 12; break;
+ case 1:
+ st->lheight= 15;
+ break;
+ }
+
+ allqueue(REDRAWTEXT, 0);
+ allqueue(REDRAWHEADERS, 0);
+
+ break;
+ case B_TAB_NUMBERS:
+ if (st->showsyntax) get_format_string();
+ allqueue(REDRAWTEXT, 0);
+ allqueue(REDRAWHEADERS, 0);
+ break;
+ case B_SYNTAX:
+ if (st->showsyntax) {
+ get_format_string();
+ }
+ allqueue(REDRAWTEXT, 0);
+ allqueue(REDRAWHEADERS, 0);
+ break;
+ }
+}
+
+static void do_text_template_scriptsmenu(void *arg, int event)
+{
+ BPY_menu_do_python(PYMENU_SCRIPTTEMPLATE, event);
+
+ allqueue(REDRAWIMAGE, 0);
+}
+
+static uiBlock *text_template_scriptsmenu (void *args_unused)
+{
+ uiBlock *block;
+ BPyMenu *pym;
+ int i= 0;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "text_template_scriptsmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_text_template_scriptsmenu, NULL);
+
+ /* note that we acount for the N previous entries with i+20: */
+ for (pym = BPyMenuTable[PYMENU_SCRIPTTEMPLATE]; pym; pym = pym->next, i++) {
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_PYTHON, pym->name, 0, yco-=20, menuwidth, 19,
+ NULL, 0.0, 0.0, 1, i,
+ pym->tooltip?pym->tooltip:pym->filename);
+ }
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+
+ return block;
+}
+
+/* action executed after clicking in File menu */
+static void do_text_filemenu(void *arg, int event)
+{
+ SpaceText *st= curarea->spacedata.first;
+ Text *text= st->text;
+ ScrArea *sa;
+
+ switch(event) {
+ case 1:
+ st->text= add_empty_text( "Text" );
+ st->top=0;
+
+ allqueue(REDRAWTEXT, 0);
+ allqueue(REDRAWHEADERS, 0);
+ break;
+ case 2:
+ activate_fileselect(FILE_SPECIAL, "Open Text File", G.sce, add_text_fs);
+ break;
+ case 3:
+ if (text->compiled) BPY_free_compiled_text(text);
+ text->compiled = NULL;
+ if (okee("Reopen Text")) {
+ if (!reopen_text(text)) {
+ error("Could not reopen file");
+ }
+ if (st->showsyntax) get_format_string();
+ }
+ break;
+ case 5:
+ text->flags |= TXT_ISMEM;
+ case 4:
+ txt_write_file(text);
+ break;
+ case 6:
+ run_python_script(st);
+ break;
+ case 7:
+ {
+ Object *ob;
+ bConstraint *con;
+ short update;
+
+ /* check all pyconstraints */
+ for (ob= G.main->object.first; ob; ob= ob->id.next) {
+ update = 0;
+ if (ob->type==OB_ARMATURE && ob->pose) {
+ bPoseChannel *pchan;
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ for (con = pchan->constraints.first; con; con= con->next) {
+ if (con->type==CONSTRAINT_TYPE_PYTHON) {
+ bPythonConstraint *data = con->data;
+ if (data->text==text) BPY_pyconstraint_update(ob, con);
+ update = 1;
+
+ }
+ }
+ }
+ }
+ for (con = ob->constraints.first; con; con= con->next) {
+ if (con->type==CONSTRAINT_TYPE_PYTHON) {
+ bPythonConstraint *data = con->data;
+ if (data->text==text) BPY_pyconstraint_update(ob, con);
+ update = 1;
+ }
+ }
+
+ if (update) {
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
+ SpaceText *st= sa->spacedata.first;
+ if (st && st->spacetype==SPACE_TEXT) {
+ scrarea_queue_redraw(sa);
+ }
+ }
+}
+
+/* action executed after clicking in Edit menu */
+static void do_text_editmenu(void *arg, int event)
+{
+ SpaceText *st= curarea->spacedata.first;
+ Text *text= st->text;
+ ScrArea *sa;
+
+ switch(event) {
+ case 1:
+ txt_do_undo(text);
+ break;
+ case 2:
+ txt_do_redo(text);
+ break;
+ case 3:
+ txt_cut_sel(text);
+ pop_space_text(st);
+ break;
+ case 4:
+ txt_copy_sel(text);
+ break;
+ case 5:
+ txt_paste(text);
+ if (st->showsyntax) get_format_string();
+ break;
+ case 6:
+ txt_print_cutbuffer();
+ break;
+ case 7:
+ jumptoline_interactive(st);
+ break;
+ case 8:
+ txt_find_panel(st,1);
+ break;
+ case 9:
+ txt_find_panel(st,0);
+ break;
+ default:
+ break;
+ }
+
+ for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
+ SpaceText *st= sa->spacedata.first;
+ if (st && st->spacetype==SPACE_TEXT) {
+ scrarea_queue_redraw(sa);
+ }
+ }
+}
+
+/* action executed after clicking in View menu */
+static void do_text_editmenu_viewmenu(void *arg, int event)
+{
+ SpaceText *st= curarea->spacedata.first;
+ Text *text= st->text;
+ ScrArea *sa;
+
+ switch(event) {
+ case 1:
+ txt_move_bof(text, 0);
+ pop_space_text(st);
+ break;
+ case 2:
+ txt_move_eof(text, 0);
+ pop_space_text(st);
+ break;
+ default:
+ break;
+ }
+
+ for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
+ SpaceText *st= sa->spacedata.first;
+ if (st && st->spacetype==SPACE_TEXT) {
+ scrarea_queue_redraw(sa);
+ }
+ }
+}
+
+/* action executed after clicking in Select menu */
+static void do_text_editmenu_selectmenu(void *arg, int event)
+{
+ SpaceText *st= curarea->spacedata.first;
+ Text *text= st->text;
+ ScrArea *sa;
+
+ switch(event) {
+ case 1:
+ txt_sel_all(text);
+ break;
+ case 2:
+ txt_sel_line(text);
+ break;
+ default:
+ break;
+ }
+
+ for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
+ SpaceText *st= sa->spacedata.first;
+ if (st && st->spacetype==SPACE_TEXT) {
+ scrarea_queue_redraw(sa);
+ }
+ }
+}
+
+/* action executed after clicking in Format menu */
+static void do_text_formatmenu(void *arg, int event)
+{
+ SpaceText *st= curarea->spacedata.first;
+ Text *text= st->text;
+ ScrArea *sa;
+
+ switch(event) {
+ case 3:
+ if (txt_has_sel(text)) {
+ txt_order_cursors(text);
+ indent(text);
+ break;
+ }
+ else {
+ txt_add_char(text, '\t');
+ break;
+ }
+ case 4:
+ if ( txt_has_sel(text)) {
+ txt_order_cursors(text);
+ unindent(text);
+ break;
+ }
+ break;
+ case 5:
+ if ( txt_has_sel(text)) {
+ txt_order_cursors(text);
+ comment(text);
+ if (st->showsyntax) get_format_string();
+ break;
+ }
+ break;
+ case 6:
+ if ( txt_has_sel(text)) {
+ txt_order_cursors(text);
+ uncomment(text);
+ if (st->showsyntax) get_format_string();
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
+ SpaceText *st= sa->spacedata.first;
+ if (st && st->spacetype==SPACE_TEXT) {
+ scrarea_queue_redraw(sa);
+ }
+ }
+}
+
+/* View menu */
+static uiBlock *text_editmenu_viewmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "text_editmenu_viewmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_text_editmenu_viewmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Top of File", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Bottom of File", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+
+ return block;
+}
+
+/* Select menu */
+static uiBlock *text_editmenu_selectmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "text_editmenu_selectmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_text_editmenu_selectmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select All|Ctrl A", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select Line", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+
+ return block;
+}
+
+void do_text_formatmenu_convert(void *arg, int event)
+{
+ SpaceText *st= curarea->spacedata.first;
+
+ switch(event) {
+ case 1: convert_tabs(st, 0); break;
+ case 2: convert_tabs(st, 1); break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *text_formatmenu_convert(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "do_text_formatmenu_convert", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_text_formatmenu_convert, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "To Spaces", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "Converts script whitespace to spaces based on Tab:");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "To Tabs", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "Converts script whitespace to tabs based on Tab:");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+/* Format menu */
+static uiBlock *text_formatmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "text_formatmenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_text_formatmenu, NULL);
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Indent|Tab", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Unindent|Shift Tab", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Comment", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 5, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Uncomment|Ctrl Shift D", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 6, "");
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBlockBut(block, text_formatmenu_convert, NULL, ICON_RIGHTARROW_THIN, "Convert whitespace", 0, yco-=20, menuwidth, 19, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+ return block;
+}
+
+
+/* action executed after clicking in Object to 3d Sub Menu */
+void do_text_editmenu_to3dmenu(void *arg, int event)
+{
+ SpaceText *st= curarea->spacedata.first;
+ Text *text= st->text;
+
+ switch(event) {
+ case 1: txt_export_to_object(text); break;
+ case 2: txt_export_to_objects(text); break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+/* Object to 3d Sub Menu */
+static uiBlock *text_editmenu_to3dmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "do_text_editmenu_to3dmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_text_editmenu_to3dmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "One Object | Alt-M", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "One Object Per Line", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+
+/* Edit menu */
+static uiBlock *text_editmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "text_editmenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_text_editmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Undo|Ctrl Z", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Redo|Ctrl Shift Z", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Cut|Alt X", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Copy|Alt C", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Paste|Alt V", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 5, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Print Cut Buffer", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 6, "");
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBlockBut(block, text_editmenu_viewmenu, NULL, ICON_RIGHTARROW_THIN, "View|Alt Shift V ", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, text_editmenu_selectmenu, NULL, ICON_RIGHTARROW_THIN, "Select|Alt Shift S ", 0, yco-=20, 120, 19, "");
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Jump...|Alt J", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 7, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Find...|Alt Ctrl F", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 8, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Find Again|Alt F", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 9, "");
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBlockBut(block, text_editmenu_to3dmenu, NULL, ICON_RIGHTARROW_THIN, "Text to 3d Object", 0, yco-=20, 120, 19, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+ return block;
+}
+
+/* File menu */
+static uiBlock *text_filemenu(void *arg_unused)
+{
+ SpaceText *st= curarea->spacedata.first;
+ Text *text= st->text;
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "text_filemenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_text_filemenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "New|Alt N", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Open...|Alt O", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
+
+ if(text) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Reopen|Alt R", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Save|Alt S", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Save As...", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 5, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Run Python Script|Alt P", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 6, "");
+
+ if (BPY_is_pyconstraint(text))
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Refresh All PyConstraints", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 7, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+ }
+
+ uiDefIconTextBlockBut(block, text_template_scriptsmenu, NULL, ICON_RIGHTARROW_THIN, "Script Templates", 0, yco-=20, 120, 19, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+ return block;
+}
+
+/* header */
+void text_buttons(void)
+{
+ uiBlock *block;
+ SpaceText *st= curarea->spacedata.first;
+ Text *text= st->text;
+ short xco, xmax;
+ char naam[256];
+
+ if (!st || st->spacetype != SPACE_TEXT) return;
+
+ sprintf(naam, "header %d", curarea->headwin);
+ block= uiNewBlock(&curarea->uiblocks, naam, UI_EMBOSS, UI_HELV, curarea->headwin);
+
+ if(area_is_active_area(curarea)) uiBlockSetCol(block, TH_HEADER);
+ else uiBlockSetCol(block, TH_HEADERDESEL);
+
+ curarea->butspacetype= SPACE_TEXT;
+
+ xco = 8;
+ uiDefIconTextButC(block, ICONTEXTROW,B_NEWSPACE, ICON_VIEW3D, windowtype_pup(), xco,0,XIC+10,YIC, &(curarea->butspacetype), 1.0, SPACEICONMAX, 0, 0, "Displays Current Window Type. Click for menu of available types.");
+ xco+= XIC+14;
+
+ uiBlockSetEmboss(block, UI_EMBOSSN);
+ if(curarea->flag & HEADER_NO_PULLDOWN) {
+ uiDefIconButBitS(block, TOG, HEADER_NO_PULLDOWN, B_FLIPINFOMENU, ICON_DISCLOSURE_TRI_RIGHT,
+ xco,2,XIC,YIC-2,
+ &(curarea->flag), 0, 0, 0, 0, "Enables display of pulldown menus");
+ } else {
+ uiDefIconButBitS(block, TOG, HEADER_NO_PULLDOWN, B_FLIPINFOMENU, ICON_DISCLOSURE_TRI_DOWN,
+ xco,2,XIC,YIC-2,
+ &(curarea->flag), 0, 0, 0, 0, "Hides pulldown menus");
+ }
+ uiBlockSetEmboss(block, UI_EMBOSS);
+ xco+=XIC;
+
+ /* pull down menus */
+ if((curarea->flag & HEADER_NO_PULLDOWN)==0) {
+ uiBlockSetEmboss(block, UI_EMBOSSP);
+
+ xmax= GetButStringLength("File");
+ uiDefPulldownBut(block,text_filemenu, NULL, "File", xco, 0, xmax, 20, "");
+ xco+=xmax;
+
+ if(text) {
+ xmax= GetButStringLength("Edit");
+ uiDefPulldownBut(block,text_editmenu, NULL, "Edit", xco, 0, xmax, 20, "");
+ xco+=xmax;
+
+ xmax= GetButStringLength("Format");
+ uiDefPulldownBut(block,text_formatmenu, NULL, "Format", xco, 0, xmax, 20, "");
+ xco+=xmax;
+ }
+ }
+ uiBlockSetEmboss(block, UI_EMBOSS);
+ xco += 10;
+
+ /* FULL WINDOW */
+ uiBlockBeginAlign(block);
+ if(curarea->full) uiDefIconBut(block, BUT,B_FULL, ICON_SPLITSCREEN, xco,0,XIC,YIC, 0, 0, 0, 0, 0, "Returns to multiple views window (CTRL+Up arrow)");
+ else uiDefIconBut(block, BUT,B_FULL, ICON_FULLSCREEN, xco,0,XIC,YIC, 0, 0, 0, 0, 0, "Makes current window full screen (CTRL+Down arrow)");
+
+ uiDefIconButI(block, ICONTOG, B_TEXTLINENUM, ICON_LONGDISPLAY, xco+=XIC,0,XIC,YIC, &st->showlinenrs, 0, 0, 0, 0, "Displays line numbers");
+
+ uiDefIconButI(block, ICONTOG, B_SYNTAX, ICON_SYNTAX, xco+=XIC,0,XIC,YIC, &st->showsyntax, 0, 0, 0, 0, "Enables Syntax Highlighting");
+ uiBlockEndAlign(block);
+
+ /* STD TEXT BUTTONS */
+ xco+= 2*XIC;
+ xco= std_libbuttons(block, xco, 0, 0, NULL, B_TEXTBROWSE, ID_TXT, 0, (ID*)st->text, 0, &(st->menunr), 0, 0, B_TEXTDELETE, 0, 0);
+
+ /*
+ if (st->text) {
+ if (st->text->flags & TXT_ISDIRTY && (st->text->flags & TXT_ISEXT || !(st->text->flags & TXT_ISMEM)))
+ uiDefIconBut(block, BUT,0, ICON_ERROR, xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0, "The text has been changed");
+ if (st->text->flags & TXT_ISEXT)
+ uiDefBut(block, BUT,B_TEXTSTORE, ICON(), xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0, "Stores text in project file");
+ else
+ uiDefBut(block, BUT,B_TEXTSTORE, ICON(), xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0, "Disables storing of text in project file");
+ xco+=10;
+ }
+ */
+
+ xco+=XIC;
+ if(st->font_id>1) st->font_id= 0;
+ uiDefButI(block, MENU, B_TEXTFONT, "Screen 12 %x0|Screen 15%x1", xco,0,100,YIC, &st->font_id, 0, 0, 0, 0, "Displays available fonts");
+ xco+=110;
+
+ uiDefButI(block, NUM, B_TAB_NUMBERS, "Tab:", xco, 0, XIC+50, YIC, &st->tabnumber, 2, 8, 0, 0, "Set spacing of Tab");
+ xco+= XIC+50;
+
+ /* always as last */
+ curarea->headbutlen= xco+2*XIC;
+
+ uiDrawBlock(block);
+}
diff --git a/source/blender/src/header_time.c b/source/blender/src/header_time.c
new file mode 100644
index 00000000000..53b22fc4e39
--- /dev/null
+++ b/source/blender/src/header_time.c
@@ -0,0 +1,539 @@
+/**
+ *
+ * $Id:
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "DNA_ID.h"
+#include "DNA_screen_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
+#include "DNA_view2d_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BIF_gl.h"
+#include "BIF_interface.h"
+#include "BIF_resources.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_toolbox.h"
+#include "BIF_butspace.h"
+
+#include "BKE_global.h"
+#include "BKE_main.h"
+
+#include "BSE_drawipo.h"
+#include "BSE_drawview.h"
+#include "BSE_editipo.h"
+#include "BSE_filesel.h"
+#include "BSE_headerbuttons.h"
+#include "BSE_seqaudio.h"
+#include "BSE_time.h"
+
+#include "blendef.h"
+#include "butspace.h"
+#include "mydevice.h"
+
+void do_time_buttons(ScrArea *sa, unsigned short event)
+{
+ SpaceTime *stime= sa->spacedata.first;
+
+ switch(event) {
+
+ case B_TL_REW:
+ CFRA= PSFRA;
+ update_for_newframe();
+ break;
+ case B_TL_PLAY:
+ add_screenhandler(G.curscreen, SCREEN_HANDLER_ANIM, stime->redraws);
+ if(stime->redraws & TIME_WITH_SEQ_AUDIO)
+ audiostream_start( CFRA );
+
+ break;
+ case B_TL_STOP:
+ rem_screenhandler(G.curscreen, SCREEN_HANDLER_ANIM);
+ if(stime->redraws & TIME_WITH_SEQ_AUDIO)
+ audiostream_stop();
+ allqueue(REDRAWALL, 0);
+
+ break;
+ case B_TL_FF:
+ /* end frame */
+ CFRA= PEFRA;
+ update_for_newframe();
+ break;
+ case B_TL_PREVKEY:
+ /* previous keyframe */
+ nextprev_timeline_key(-1);
+ break;
+ case B_TL_NEXTKEY:
+ /* next keyframe */
+ nextprev_timeline_key(1);
+ break;
+
+ case B_TL_PREVIEWON:
+ if (G.scene->r.psfra) {
+ /* turn on preview range */
+ G.scene->r.psfra= G.scene->r.sfra;
+ G.scene->r.pefra= G.scene->r.efra;
+ }
+ else {
+ /* turn off preview range */
+ G.scene->r.psfra= 0;
+ G.scene->r.pefra= 0;
+ }
+ BIF_undo_push("Set anim-preview range");
+ allqueue(REDRAWALL, 0);
+ break;
+ }
+}
+
+static void do_time_redrawmenu(void *arg, int event)
+{
+ SpaceTime *stime= curarea->spacedata.first;
+
+ if(event < 1001) {
+
+ stime->redraws ^= event;
+ /* update handler when it's running */
+ if(has_screenhandler(G.curscreen, SCREEN_HANDLER_ANIM))
+ add_screenhandler(G.curscreen, SCREEN_HANDLER_ANIM, stime->redraws);
+ }
+ else {
+ if(event==1001) {
+ button(&G.scene->r.frs_sec,1,120,"FPS:");
+ }
+ }
+}
+
+
+static uiBlock *time_redrawmenu(void *arg_unused)
+{
+ SpaceTime *stime= curarea->spacedata.first;
+ uiBlock *block;
+ short yco= 0, menuwidth=120, icon;
+ char str[32];
+
+ block= uiNewBlock(&curarea->uiblocks, "time_redrawmenu",
+ UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_time_redrawmenu, NULL);
+
+ if(stime->redraws & TIME_LEFTMOST_3D_WIN) icon= ICON_CHECKBOX_HLT;
+ else icon= ICON_CHECKBOX_DEHLT;
+ uiDefIconTextBut(block, BUTM, 1, icon, "Top-Left 3D Window", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, TIME_LEFTMOST_3D_WIN, "");
+
+ if(stime->redraws & TIME_ALL_3D_WIN) icon= ICON_CHECKBOX_HLT;
+ else icon= ICON_CHECKBOX_DEHLT;
+ uiDefIconTextBut(block, BUTM, 1, icon, "All 3D Windows", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, TIME_ALL_3D_WIN, "");
+
+ if(stime->redraws & TIME_ALL_ANIM_WIN) icon= ICON_CHECKBOX_HLT;
+ else icon= ICON_CHECKBOX_DEHLT;
+ uiDefIconTextBut(block, BUTM, 1, icon, "Animation Windows", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, TIME_ALL_ANIM_WIN, "");
+
+ if(stime->redraws & TIME_ALL_BUTS_WIN) icon= ICON_CHECKBOX_HLT;
+ else icon= ICON_CHECKBOX_DEHLT;
+ uiDefIconTextBut(block, BUTM, 1, icon, "Buttons Windows", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, TIME_ALL_BUTS_WIN, "");
+
+ if(stime->redraws & TIME_ALL_IMAGE_WIN) icon= ICON_CHECKBOX_HLT;
+ else icon= ICON_CHECKBOX_DEHLT;
+ uiDefIconTextBut(block, BUTM, 1, icon, "Image Windows", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, TIME_ALL_IMAGE_WIN, "");
+
+ /* Add sequencer only redraw*/
+ if(stime->redraws & TIME_SEQ) icon= ICON_CHECKBOX_HLT;
+ else icon= ICON_CHECKBOX_DEHLT;
+ uiDefIconTextBut(block, BUTM, 1, icon, "Sequencer Windows", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, TIME_SEQ, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ sprintf(str, "Set Frames/Sec (%d/%f)", G.scene->r.frs_sec, G.scene->r.frs_sec_base);
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, str, 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1001, "");
+
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+static void do_time_viewmenu(void *arg, int event)
+{
+ SpaceTime *stime= curarea->spacedata.first;
+ int first;
+
+ switch(event) {
+ case 2: /* Play Back Animation */
+ add_screenhandler(G.curscreen, SCREEN_HANDLER_ANIM, stime->redraws);
+ break;
+ case 3: /* View All */
+ first= G.scene->r.sfra;
+ if(first >= G.scene->r.efra) first= G.scene->r.efra;
+ G.v2d->cur.xmin=G.v2d->tot.xmin= (float)first-2;
+ G.v2d->cur.xmax=G.v2d->tot.xmax= (float)G.scene->r.efra+2;
+
+ test_view2d(G.v2d, curarea->winx, curarea->winy);
+ scrarea_queue_winredraw(curarea);
+ break;
+ case 4: /* Maximize Window */
+ /* using event B_FULL */
+ break;
+ case 5: /* show time or frames */
+ stime->flag ^= TIME_DRAWFRAMES;
+ break;
+ case 6:
+ nextprev_marker(1);
+ break;
+ case 7:
+ nextprev_marker(-1);
+ break;
+ case 8:
+ nextprev_timeline_key(1);
+ break;
+ case 9:
+ nextprev_timeline_key(-1);
+ break;
+ case 10:
+ timeline_frame_to_center();
+ break;
+ case 11:
+ G.v2d->flag ^= V2D_VIEWLOCK;
+ if(G.v2d->flag & V2D_VIEWLOCK)
+ view2d_do_locks(curarea, 0);
+ break;
+ case 12: /* only show keyframes from selected data */
+ stime->flag ^= TIME_ONLYACTSEL;
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *time_viewmenu(void *arg_unused)
+{
+ SpaceTime *stime= curarea->spacedata.first;
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "time_viewmenu",
+ UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_time_viewmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Play Back Animation", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ if(stime->flag & TIME_DRAWFRAMES)
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Show Seconds|T", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+ else
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Show Frames|T", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+
+ uiDefIconTextBut(block, BUTM, 1, (stime->flag & TIME_ONLYACTSEL)?ICON_CHECKBOX_HLT:ICON_CHECKBOX_DEHLT,
+ "Only Selected Data Keys|", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 12, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Jump To Next Marker|PageUp", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 6, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Jump To Prev Marker|PageDown", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 7, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Jump To Next Key|Ctrl PageUp", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 8, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Jump To Prev Key|Ctrl PageDown", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 9, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Center View|C", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 10, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "View All|Home", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+ uiDefIconTextBut(block, BUTM, 1, (G.v2d->flag & V2D_VIEWLOCK)?ICON_CHECKBOX_HLT:ICON_CHECKBOX_DEHLT,
+ "Lock Time to Other Windows|", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 11, "");
+
+ if (!curarea->full)
+ uiDefIconTextBut(block, BUTM, B_FULL, ICON_BLANK1, "Maximize Window|Ctrl UpArrow", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
+ else
+ uiDefIconTextBut(block, BUTM, B_FULL, ICON_BLANK1, "Tile Window|Ctrl DownArrow", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+static void do_time_framemenu(void *arg, int event)
+{
+ switch(event) {
+ case 1: /*Set as Start */
+ if (G.scene->r.psfra) {
+ if (G.scene->r.pefra < CFRA)
+ G.scene->r.pefra= CFRA;
+ G.scene->r.psfra= CFRA;
+ }
+ else
+ G.scene->r.sfra = CFRA;
+ allqueue(REDRAWALL, 1);
+ break;
+ case 2: /* Set as End */
+ if (G.scene->r.psfra) {
+ if (CFRA < G.scene->r.psfra)
+ G.scene->r.psfra= CFRA;
+ G.scene->r.pefra= CFRA;
+ }
+ else
+ G.scene->r.efra = CFRA;
+ allqueue(REDRAWALL, 1);
+ break;
+ case 3: /* Add Marker */
+ add_marker(CFRA);
+ break;
+ case 4: /* Remove Marker */
+ remove_marker();
+ break;
+ case 5: /* Rename Marker */
+ rename_marker();
+ break;
+ case 6: /* Grab Marker */
+ transform_markers('g', 0);
+ break;
+ case 7: /* duplicate marker */
+ duplicate_marker();
+ break;
+ }
+ allqueue(REDRAWTIME, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWNLA, 0);
+ allqueue(REDRAWSOUND, 0);
+}
+
+static uiBlock *time_framemenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "time_framemenu",
+ UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_time_framemenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Add Marker|M", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Duplicate Marker|Shift D", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, 7, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Delete Marker|X", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Name Marker|Ctrl M", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Grab/Move Marker|G", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, 6, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Set as Start|S", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Set as End|E", 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+void time_buttons(ScrArea *sa)
+{
+ SpaceTime *stime= sa->spacedata.first;
+ uiBlock *block;
+ short xco, xmax;
+ char name[256];
+
+ sprintf(name, "header %d", sa->headwin);
+ block= uiNewBlock(&sa->uiblocks, name, UI_EMBOSS, UI_HELV, sa->headwin);
+
+ if(area_is_active_area(sa)) uiBlockSetCol(block, TH_HEADER);
+ else uiBlockSetCol(block, TH_HEADERDESEL);
+
+ sa->butspacetype= SPACE_TIME;
+
+ xco = 8;
+
+ uiDefIconTextButC(block, ICONTEXTROW,B_NEWSPACE, ICON_VIEW3D,
+ windowtype_pup(), xco, 0, XIC+10, YIC,
+ &(sa->butspacetype), 1.0, SPACEICONMAX, 0, 0,
+ "Displays Current Window Type. "
+ "Click for menu of available types.");
+
+ xco += XIC + 14;
+
+ uiBlockSetEmboss(block, UI_EMBOSSN);
+ if (sa->flag & HEADER_NO_PULLDOWN) {
+ uiDefIconButBitS(block, TOG, HEADER_NO_PULLDOWN, B_FLIPINFOMENU,
+ ICON_DISCLOSURE_TRI_RIGHT,
+ xco,2,XIC,YIC-2,
+ &(sa->flag), 0, 0, 0, 0,
+ "Show pulldown menus");
+ }
+ else {
+ uiDefIconButBitS(block, TOG, HEADER_NO_PULLDOWN, B_FLIPINFOMENU,
+ ICON_DISCLOSURE_TRI_DOWN,
+ xco,2,XIC,YIC-2,
+ &(sa->flag), 0, 0, 0, 0,
+ "Hide pulldown menus");
+ }
+ uiBlockSetEmboss(block, UI_EMBOSS);
+ xco+=XIC;
+
+ if((sa->flag & HEADER_NO_PULLDOWN)==0) {
+ /* pull down menus */
+ uiBlockSetEmboss(block, UI_EMBOSSP);
+
+ xmax= GetButStringLength("View");
+ uiDefPulldownBut(block, time_viewmenu, NULL,
+ "View", xco, -2, xmax-3, 24, "");
+ xco+= xmax;
+ xmax= GetButStringLength("Frame");
+ uiDefPulldownBut(block, time_framemenu, NULL,
+ "Frame", xco, -2, xmax-3, 24, "");
+ xco+= xmax;
+
+ xmax= GetButStringLength("Playback");
+ uiDefPulldownBut(block, time_redrawmenu, NULL,
+ "Playback", xco, -2, xmax-3, 24, "");
+ xco+= xmax;
+ }
+
+ uiBlockSetEmboss(block, UI_EMBOSS);
+
+ uiBlockBeginAlign(block);
+
+ uiDefButI(block, TOG, B_TL_PREVIEWON,"Preview",
+ xco,0, XIC, YIC,
+ &G.scene->r.psfra,0, 1, 0, 0,
+ "Show settings for frame range of animation preview");
+
+ xco += XIC;
+
+ if (G.scene->r.psfra) {
+ uiDefButI(block, NUM, REDRAWALL,"Start:",
+ xco,0, 4.5*XIC, YIC,
+ &G.scene->r.psfra,MINFRAMEF, MAXFRAMEF, 0, 0,
+ "The start frame of the animation preview");
+
+ xco += 4.5*XIC;
+
+ uiDefButI(block, NUM, REDRAWALL,"End:",
+ xco,0,4.5*XIC,YIC,
+ &G.scene->r.pefra,PSFRA,MAXFRAMEF, 0, 0,
+ "The end frame of the animation preview");
+ }
+ else {
+ uiDefButI(block, NUM, REDRAWALL,"Start:",
+ xco,0, 4.5*XIC, YIC,
+ &G.scene->r.sfra,MINFRAMEF, MAXFRAMEF, 0, 0,
+ "The start frame of the animation");
+
+ xco += 4.5*XIC;
+
+ uiDefButI(block, NUM, REDRAWALL,"End:",
+ xco,0,4.5*XIC,YIC,
+ &G.scene->r.efra,SFRA,MAXFRAMEF, 0, 0,
+ "The end frame of the animation");
+ }
+ uiBlockEndAlign(block);
+
+ xco += 4.5*XIC+16;
+
+ uiDefButI(block, NUM, B_NEWFRAME, "",
+ xco,0,3.5*XIC,YIC,
+ &(G.scene->r.cfra), MINFRAMEF, MAXFRAMEF, 0, 0,
+ "Displays Current Frame of animation. Click to change.");
+
+ xco += 3.5*XIC+16;
+
+ uiDefIconBut(block, BUT, B_TL_REW, ICON_REW,
+ xco, 0, XIC, YIC, 0, 0, 0, 0, 0, "Skip to Start frame (Shift DownArrow)");
+ xco+= XIC+4;
+ uiDefIconBut(block, BUT, B_TL_PREVKEY, ICON_PREV_KEYFRAME,
+ xco, 0, XIC, YIC, 0, 0, 0, 0, 0, "Skip to previous keyframe (Ctrl PageDown)");
+ xco+= XIC+4;
+
+ if(has_screenhandler(G.curscreen, SCREEN_HANDLER_ANIM))
+ uiDefIconBut(block, BUT, B_TL_STOP, ICON_PAUSE,
+ xco, 0, XIC, YIC, 0, 0, 0, 0, 0, "Stop Playing Timeline");
+ else
+ uiDefIconBut(block, BUT, B_TL_PLAY, ICON_PLAY,
+ xco, 0, XIC, YIC, 0, 0, 0, 0, 0, "Play Timeline ");
+
+ xco+= XIC+4;
+ uiDefIconBut(block, BUT, B_TL_NEXTKEY, ICON_NEXT_KEYFRAME,
+ xco, 0, XIC, YIC, 0, 0, 0, 0, 0, "Skip to next keyframe (Ctrl PageUp)");
+ xco+= XIC+4;
+ uiDefIconBut(block, BUT, B_TL_FF, ICON_FF,
+ xco, 0, XIC, YIC, 0, 0, 0, 0, 0, "Skip to End frame (Shift UpArrow)");
+ xco+= XIC+8;
+
+ uiDefIconButBitI(block, TOG, G_RECORDKEYS, REDRAWINFO, ICON_REC,
+ xco, 0, XIC, YIC, &(G.flags), 0, 0, 0, 0, "Automatically insert keyframes in Object and Action Ipo curves");
+
+ xco+= XIC+16;
+
+ uiDefIconButBitI(block, TOG, TIME_WITH_SEQ_AUDIO, B_DIFF, ICON_SPEAKER,
+ xco, 0, XIC, YIC, &(stime->redraws), 0, 0, 0, 0, "Play back and sync with audio from Sequence Editor");
+
+ /* always as last */
+ sa->headbutlen= xco+XIC+80; // +80 because the last button is not an icon
+
+ uiDrawBlock(block);
+}
diff --git a/source/blender/src/header_view3d.c b/source/blender/src/header_view3d.c
new file mode 100644
index 00000000000..099a016c698
--- /dev/null
+++ b/source/blender/src/header_view3d.c
@@ -0,0 +1,5261 @@
+/*
+ * header_view3d.c oct-2003
+ *
+ * Functions to draw the "3D Viewport" window header
+ * and handle user events sent to it.
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "BMF_Api.h"
+#include "BIF_language.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_armature_types.h"
+#include "DNA_ID.h"
+#include "DNA_image_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_text_types.h" /* for space handlers */
+#include "DNA_texture_types.h"
+#include "DNA_userdef_types.h" /* U.smooth_viewtx */
+
+#include "BKE_action.h"
+#include "BKE_curve.h"
+#include "BKE_depsgraph.h"
+#include "BKE_displist.h"
+#include "BKE_effect.h"
+#include "BKE_global.h"
+#include "BKE_image.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
+#include "BKE_utildefines.h" /* for VECCOPY */
+
+#ifdef WITH_VERSE
+#include "BKE_verse.h"
+#endif
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+#include "BLI_editVert.h"
+
+#include "BSE_edit.h"
+#include "BSE_editipo.h"
+#include "BSE_headerbuttons.h"
+#include "BSE_view.h"
+#include "BSE_drawview.h"
+
+#include "BDR_editcurve.h"
+#include "BDR_editface.h"
+#include "BDR_editmball.h"
+#include "BDR_editobject.h"
+#include "BDR_sculptmode.h"
+#include "BDR_imagepaint.h"
+#include "BDR_vpaint.h"
+
+#include "BIF_editlattice.h"
+#include "BIF_editarmature.h"
+#include "BIF_editconstraint.h"
+#include "BIF_editdeform.h"
+#include "BIF_editfont.h"
+#include "BIF_editgroup.h"
+#include "BIF_editmesh.h"
+#include "BIF_editmode_undo.h"
+#include "BIF_editview.h"
+#include "BIF_gl.h"
+#include "BIF_interface.h"
+#include "BIF_mainqueue.h"
+#include "BIF_meshtools.h"
+#include "BIF_poseobject.h"
+#include "BIF_renderwin.h"
+#include "BIF_resources.h"
+#include "BIF_retopo.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_toets.h"
+#include "BIF_toolbox.h"
+#include "BIF_transform.h"
+
+#ifdef WITH_VERSE
+#include "BIF_verse.h"
+#endif
+
+#include "BPY_extern.h"
+#include "BPY_menus.h"
+
+#include "blendef.h"
+#include "multires.h"
+#include "mydevice.h"
+#include "butspace.h"
+
+#include "BIF_poseobject.h"
+
+/* View3d->modeselect
+ * This is a bit of a dodgy hack to enable a 'mode' menu with icons+labels
+ * rather than those buttons.
+ * I know the implementation's not good - it's an experiment to see if this
+ * approach would work well
+ *
+ * This can be cleaned when I make some new 'mode' icons.
+ */
+
+#define V3D_OBJECTMODE_SEL ICON_OBJECT
+#define V3D_EDITMODE_SEL ICON_EDITMODE_HLT
+#define V3D_SCULPTMODE_SEL ICON_SCULPTMODE_HLT
+#define V3D_FACESELECT_SEL ICON_FACESEL_HLT /* this is not a mode anymore - just a switch */
+#define V3D_VERTEXPAINTMODE_SEL ICON_VPAINT_HLT
+#define V3D_TEXTUREPAINTMODE_SEL ICON_TPAINT_HLT
+#define V3D_WEIGHTPAINTMODE_SEL ICON_WPAINT_HLT
+#define V3D_POSEMODE_SEL ICON_POSE_HLT
+
+#define TEST_EDITMESH if(G.obedit==0) return; \
+ if( (G.vd->lay & G.obedit->lay)==0 ) return;
+
+void do_layer_buttons(short event)
+{
+ static int oldlay= 1;
+
+ if(G.vd==0) return;
+ if(G.vd->localview) return;
+
+ if(event==-1 && (G.qual & LR_CTRLKEY)) {
+ G.vd->scenelock= !G.vd->scenelock;
+ do_view3d_buttons(B_SCENELOCK);
+ } else if (event==-1) {
+ if(G.vd->lay== (1<<20)-1) {
+ if(G.qual & LR_SHIFTKEY) G.vd->lay= oldlay;
+ }
+ else {
+ oldlay= G.vd->lay;
+ G.vd->lay= (1<<20)-1;
+ }
+
+ if(G.vd->scenelock) handle_view3d_lock();
+ scrarea_queue_winredraw(curarea);
+
+ /* new layers might need unflushed events events */
+ DAG_scene_update_flags(G.scene, G.vd->lay); /* tags all that moves and flushes */
+ }
+ else {
+ if(G.qual & LR_ALTKEY) {
+ if(event<11) event+= 10;
+ }
+ if(G.qual & LR_SHIFTKEY) {
+ if(G.vd->lay & (1<<event)) G.vd->lay -= (1<<event);
+ else G.vd->lay += (1<<event);
+ }
+ do_view3d_buttons(event+B_LAY);
+ }
+ /* redraw seems double: but the queue nicely handles that */
+ scrarea_queue_headredraw(curarea);
+
+ if(curarea->spacetype==SPACE_OOPS) allqueue(REDRAWVIEW3D, 1); /* 1==also do headwin */
+ if(G.vd->drawtype == OB_SHADED) reshadeall_displist();
+ allqueue(REDRAWNLA, 0);
+}
+
+static void do_view3d_view_camerasmenu(void *arg, int event)
+{
+ Base *base;
+ int i=1;
+
+ if (event == 1) {
+ /* Set Active Object as Active Camera */
+ /* ugly hack alert */
+ G.qual |= LR_CTRLKEY;
+ persptoetsen(PAD0);
+ G.qual &= ~LR_CTRLKEY;
+ } else {
+ for( base = FIRSTBASE; base; base = base->next ) {
+ if (base->object->type == OB_CAMERA) {
+ i++;
+
+ if (event==i) {
+
+ if (G.vd->camera == base->object && G.vd->persp==2)
+ return;
+
+ if (U.smooth_viewtx) {
+ /* move 3d view to camera view */
+ float orig_ofs[3], orig_lens = G.vd->lens;
+ VECCOPY(orig_ofs, G.vd->ofs);
+
+ if (G.vd->camera && G.vd->persp==2)
+ view_settings_from_ob(G.vd->camera, G.vd->ofs, G.vd->viewquat, &G.vd->dist, &G.vd->lens);
+
+ G.vd->camera = base->object;
+ handle_view3d_lock();
+ G.vd->persp= 2;
+ G.vd->view= 0;
+
+ smooth_view_to_camera(G.vd);
+
+ /* restore values */
+ VECCOPY(G.vd->ofs, orig_ofs);
+ G.vd->lens = orig_lens;
+ } else {
+ G.vd->camera= base->object;
+ handle_view3d_lock();
+ G.vd->persp= 2;
+ G.vd->view= 0;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_view_camerasmenu(void *arg_unused)
+{
+ Base *base;
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+ int i=1;
+ char camname[48];
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_view_camerasmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_view_camerasmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Set Active Object as Active Camera|Ctrl NumPad 0", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, 140, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ for( base = FIRSTBASE; base; base = base->next ) {
+ if (base->object->type == OB_CAMERA) {
+ i++;
+
+ strcpy(camname, base->object->id.name+2);
+ if (base->object == G.scene->camera) strcat(camname, " (Active)");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, camname, 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, i, "");
+ }
+ }
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 50);
+ return block;
+}
+
+static void do_view3d_view_cameracontrolsmenu(void *arg, int event)
+{
+ switch(event) {
+ case 0: /* Orbit Left */
+ persptoetsen(PAD4);
+ break;
+ case 1: /* Orbit Right */
+ persptoetsen(PAD6);
+ break;
+ case 2: /* Orbit Up */
+ persptoetsen(PAD8);
+ break;
+ case 3: /* Orbit Down */
+ persptoetsen(PAD2);
+ break;
+ case 4: /* Pan left */
+ /* ugly hack alert */
+ G.qual |= LR_CTRLKEY;
+ persptoetsen(PAD4);
+ G.qual &= ~LR_CTRLKEY;
+ break;
+ case 5: /* Pan right */
+ /* ugly hack alert */
+ G.qual |= LR_CTRLKEY;
+ persptoetsen(PAD6);
+ G.qual &= ~LR_CTRLKEY;
+ break;
+ case 6: /* Pan up */
+ /* ugly hack alert */
+ G.qual |= LR_CTRLKEY;
+ persptoetsen(PAD8);
+ G.qual &= ~LR_CTRLKEY;
+ break;
+ case 7: /* Pan down */
+ /* ugly hack alert */
+ G.qual |= LR_CTRLKEY;
+ persptoetsen(PAD2);
+ G.qual &= ~LR_CTRLKEY;
+ break;
+ case 8: /* Zoom In */
+ persptoetsen(PADPLUSKEY);
+ break;
+ case 9: /* Zoom Out */
+ persptoetsen(PADMINUS);
+ break;
+ case 10: /* Reset Zoom */
+ persptoetsen(PADENTER);
+ break;
+ case 11: /* Camera Fly mode */
+ fly();
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_view_cameracontrolsmenu(void *arg_unused)
+{
+/* static short tog=0; */
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_view_cameracontrolsmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_view_cameracontrolsmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Camera Fly Mode|Shift F", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 11, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, 140, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Orbit Left|NumPad 4", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Orbit Right|NumPad 6", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Orbit Up|NumPad 8", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Orbit Down|NumPad 2", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, 140, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Pan Left|Ctrl NumPad 4", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Pan Right|Ctrl NumPad 6", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 5, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Pan Up|Ctrl NumPad 8", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 6, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Pan Down|Ctrl NumPad 2", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 7, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, 140, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Zoom In|NumPad +", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 8, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Zoom Out|NumPad -", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 9, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Reset Zoom|NumPad Enter", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 10, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 50);
+ return block;
+}
+
+static void do_view3d_view_alignviewmenu(void *arg, int event)
+{
+ View3D *v3d= curarea->spacedata.first;
+ float *curs;
+
+ switch(event) {
+
+ case 0: /* Align View to Selected (edit/faceselect mode) */
+ case 1:
+ case 2:
+ if ((G.obedit) && (G.obedit->type == OB_MESH)) {
+ editmesh_align_view_to_selected(v3d, event);
+ } else if (FACESEL_PAINT_TEST) {
+ Object *obact= OBACT;
+ if (obact && obact->type==OB_MESH) {
+ Mesh *me= obact->data;
+
+ if (me->mtface) {
+ faceselect_align_view_to_selected(v3d, me, event);
+ addqueue(v3d->area->win, REDRAW, 1);
+ }
+ }
+ }
+ break;
+ case 3: /* Center View to Cursor */
+ curs= give_cursor();
+ G.vd->ofs[0]= -curs[0];
+ G.vd->ofs[1]= -curs[1];
+ G.vd->ofs[2]= -curs[2];
+ scrarea_queue_winredraw(curarea);
+ break;
+ case 4: /* Align Active Camera to View */
+ /* This ugly hack is a symptom of the nasty persptoetsen function,
+ * but at least it works for now.
+ */
+ G.qual |= LR_CTRLKEY|LR_ALTKEY;
+ persptoetsen(PAD0);
+ G.qual &= ~(LR_CTRLKEY|LR_ALTKEY);
+ break;
+ case 5: /* Align View to Selected (object mode) */
+ mainqenter(PADASTERKEY, 1);
+ break;
+ case 6: /* Center View and Cursor to Origin */
+ view3d_home(1);
+ curs= give_cursor();
+ curs[0]=curs[1]=curs[2]= 0.0;
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_view_alignviewmenu(void *arg_unused)
+{
+/* static short tog=0; */
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_view_alignviewmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_view_alignviewmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Center View to Cursor|C", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Center Cursor and View All|Shift C", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 6, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Align Active Camera to View|Ctrl Alt NumPad 0", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
+
+ if (((G.obedit) && (G.obedit->type == OB_MESH)) || (FACESEL_PAINT_TEST)) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Align View to Selected (Top)|Shift V", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Align View to Selected (Front)|Shift V", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Align View to Selected (Side)|Shift V", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 0, "");
+ } else {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Align View to Selected|NumPad *", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 5, "");
+ }
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 50);
+ return block;
+}
+
+static void do_view3d_view_spacehandlers(void *arg, int event)
+{
+ Text *text = G.main->text.first;
+ unsigned short menu_evt_num = 0;
+
+ if (event > 0) {
+ while (text) {
+ if (++menu_evt_num == event) {
+
+ if (BPY_has_spacehandler(text, curarea))
+ BPY_del_spacehandler(text, curarea);
+ else
+ BPY_add_spacehandler(text, curarea, SPACE_VIEW3D);
+
+ break;
+ }
+ text = text->id.next;
+ }
+ }
+
+ allqueue(REDRAWVIEW3D, 1);
+}
+
+static uiBlock *view3d_view_spacehandlers(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+ Text *text = G.main->text.first;
+ ScrArea *sa = curarea;
+ unsigned short handlertype;
+ int icontype, slinks_num = 0;
+ unsigned short menu_evt_num = 0;
+ char menustr[64];
+ static char msg_tog_on[] = "Click to enable";
+ static char msg_tog_off[]= "Click to disable";
+ char *tip = NULL;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_view_spacehandlers", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_view_spacehandlers, NULL);
+
+ while (text) {
+ menu_evt_num++;
+ handlertype = BPY_is_spacehandler(text, SPACE_VIEW3D);
+
+ if (handlertype) {
+ slinks_num++;
+
+ /* mark text as script, so we can remove its link if its header
+ * becomes corrupt and it's not recognized anymore */
+ if (!(text->flags & TXT_ISSCRIPT)) text->flags |= TXT_ISSCRIPT;
+
+ if (handlertype == SPACEHANDLER_VIEW3D_EVENT)
+ BLI_strncpy(menustr, "Event: ", 8);
+ else
+ BLI_strncpy(menustr, "Draw: ", 8);
+ BLI_strncpy(menustr+7, text->id.name+2, 22);
+
+ if (BPY_has_spacehandler(text, sa)) {
+ icontype = ICON_CHECKBOX_HLT;
+ tip = msg_tog_off;
+ }
+ else {
+ icontype = ICON_CHECKBOX_DEHLT;
+ tip = msg_tog_on;
+ }
+
+ uiDefIconTextBut(block, BUTM, 1, icontype, menustr, 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, menu_evt_num, tip);
+ }
+ else if (text->flags & TXT_ISSCRIPT) {
+ /* if bit set, text was a space handler, but its header got corrupted,
+ * so we need to remove the link here */
+ BPY_del_spacehandler(text, sa);
+ text->flags &=~TXT_ISSCRIPT;
+ }
+
+ text = text->id.next;
+ }
+
+ if (slinks_num == 0) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_SCRIPT, "None Available", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, -1, "None of the texts in the Text Editor is a 3D View space handler");
+ }
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+static void do_view3d_viewmenu(void *arg, int event)
+{
+ View3D *v3d= curarea->spacedata.first;
+
+ switch(event) {
+ case 0: /* User */
+ G.vd->viewbut = 0;
+ G.vd->persp = 1;
+ break;
+ case 1: /* Camera */
+ persptoetsen(PAD0);
+ break;
+ case 2: /* Top */
+ persptoetsen(PAD7);
+ break;
+ case 3: /* Front */
+ persptoetsen(PAD1);
+ break;
+ case 4: /* Side */
+ persptoetsen(PAD3);
+ break;
+ case 5: /* Perspective */
+ G.vd->persp=1;
+ break;
+ case 6: /* Orthographic */
+ G.vd->persp=0;
+ break;
+ case 7: /* Local View */
+ G.vd->localview= 1;
+ initlocalview();
+ break;
+ case 8: /* Global View */
+ G.vd->localview= 0;
+ endlocalview(curarea);
+ break;
+ case 9: /* View All (Home) */
+ view3d_home(0);
+ break;
+ case 11: /* View Selected */
+ centerview();
+ break;
+ case 13: /* Play Back Animation */
+ play_anim(0);
+ break;
+ case 15: /* Background Image... */
+ add_blockhandler(curarea, VIEW3D_HANDLER_BACKGROUND, UI_PNL_UNSTOW);
+ break;
+ case 16: /* View Panel */
+ add_blockhandler(curarea, VIEW3D_HANDLER_PROPERTIES, UI_PNL_UNSTOW);
+ break;
+ case 17: /* Set Clipping Border */
+ view3d_edit_clipping(v3d);
+ break;
+ case 18: /* render preview */
+ toggle_blockhandler(curarea, VIEW3D_HANDLER_PREVIEW, 0);
+ break;
+ case 19: /* zoom within border */
+ view3d_border_zoom();
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 1);
+}
+
+static uiBlock *view3d_viewmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+ View3D *v3d= curarea->spacedata.first;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_viewmenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_view3d_viewmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_MENU_PANEL, "Render Preview...|Shift P", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 18, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_MENU_PANEL, "View Properties...", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 16, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_MENU_PANEL, "Background Image...", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 15, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ if ((G.vd->viewbut == 0) && !(G.vd->persp == 2)) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "User", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 0, "");
+ else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "User", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 0, "");
+ if (G.vd->persp == 2) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Camera|NumPad 0", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
+ else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Camera|NumPad 0", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 1, "");
+ if (G.vd->viewbut == 1) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Top|NumPad 7", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
+ else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Top|NumPad 7", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 2, "");
+ if (G.vd->viewbut == 2) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Front|NumPad 1", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
+ else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Front|NumPad 1", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 3, "");
+ if (G.vd->viewbut == 3) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Side|NumPad 3", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
+ else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Side|NumPad 3", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 4, "");
+
+ uiDefIconTextBlockBut(block, view3d_view_camerasmenu, NULL, ICON_RIGHTARROW_THIN, "Cameras", 0, yco-=20, 120, 19, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ if(G.vd->persp==1) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Perspective|NumPad 5", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 5, "");
+ else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Perspective|NumPad 5", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 5, "");
+ if(G.vd->persp==0) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Orthographic|NumPad 5", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 6, "");
+ else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Orthographic|NumPad 5", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 6, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ if(G.vd->localview) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Local View|NumPad /", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 7, "");
+ else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Local View|NumPad /", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 7, "");
+ if(!G.vd->localview) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Global View|NumPad /", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 8, "");
+ else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Global View|NumPad /", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 8, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBlockBut(block, view3d_view_cameracontrolsmenu, NULL, ICON_RIGHTARROW_THIN, "View Navigation", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, view3d_view_alignviewmenu, NULL, ICON_RIGHTARROW_THIN, "Align View", 0, yco-=20, 120, 19, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ if(v3d->flag & V3D_CLIPPING)
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Clear Clipping Border|Alt B", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 17, "");
+ else
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Set Clipping Border|Alt B", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 17, "");
+ if (v3d->persp==0) uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Zoom Within Border...|Shift B", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 19, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "View Selected|NumPad .", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 11, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "View All|Home", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 9, "");
+ if(!curarea->full) uiDefIconTextBut(block, BUTM, B_FULL, ICON_BLANK1, "Maximize Window|Ctrl UpArrow", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 99, "");
+ else uiDefIconTextBut(block, BUTM, B_FULL, ICON_BLANK1, "Tile Window|Ctrl DownArrow", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 99, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Play Back Animation|Alt A", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 13, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBlockBut(block, view3d_view_spacehandlers, NULL, ICON_RIGHTARROW_THIN, "Space Handler Scripts", 0, yco-=20, 120, 19, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+void do_view3d_select_object_typemenu(void *arg, int event)
+{
+
+ extern void selectall_type(short obtype);
+
+ switch(event) {
+ case 1: /* Mesh */
+ selectall_type(OB_MESH);
+ break;
+ case 2: /* Curve */
+ selectall_type(OB_CURVE);
+ break;
+ case 3: /* Surface */
+ selectall_type(OB_SURF);
+ break;
+ case 4: /* Meta */
+ selectall_type(OB_MBALL);
+ break;
+ case 5: /* Armature */
+ selectall_type(OB_ARMATURE);
+ break;
+ case 6: /* Lattice */
+ selectall_type(OB_LATTICE);
+ break;
+ case 7: /* Text */
+ selectall_type(OB_FONT);
+ break;
+ case 8: /* Empty */
+ selectall_type(OB_EMPTY);
+ break;
+ case 9: /* Camera */
+ selectall_type(OB_CAMERA);
+ break;
+ case 10: /* Lamp */
+ selectall_type(OB_LAMP);
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_select_object_typemenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_select_object_typemenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_select_object_typemenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Mesh", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Curve", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Surface", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Meta", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Armature", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Lattice", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 6, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Text", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 7, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Empty", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 8, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Camera", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 9, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Lamp", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 10, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+void do_view3d_select_object_layermenu(void *arg, int event)
+{
+ extern void selectall_layer(unsigned int layernum);
+
+ switch(event) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ case 16:
+ case 17:
+ case 18:
+ case 19:
+ case 20:
+ selectall_layer(event);
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_select_object_layermenu(void *arg_unused)
+{
+ uiBlock *block;
+ short xco= 0, yco = 20, menuwidth = 22;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_select_object_layermenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_select_object_layermenu, NULL);
+
+ uiDefBut(block, BUTM, 1, "1", xco, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefBut(block, BUTM, 1, "2", xco+=(menuwidth+1), yco, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefBut(block, BUTM, 1, "3", xco+=(menuwidth+1), yco, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+ uiDefBut(block, BUTM, 1, "4", xco+=(menuwidth+1), yco, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+ uiDefBut(block, BUTM, 1, "5", xco+=(menuwidth+1), yco, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+ xco += 6;
+ uiDefBut(block, BUTM, 1, "6", xco+=(menuwidth+1), yco, menuwidth, 19, NULL, 0.0, 0.0, 1, 6, "");
+ uiDefBut(block, BUTM, 1, "7", xco+=(menuwidth+1), yco, menuwidth, 19, NULL, 0.0, 0.0, 1, 7, "");
+ uiDefBut(block, BUTM, 1, "8", xco+=(menuwidth+1), yco, menuwidth, 19, NULL, 0.0, 0.0, 1, 8, "");
+ uiDefBut(block, BUTM, 1, "9", xco+=(menuwidth+1), yco, menuwidth, 19, NULL, 0.0, 0.0, 1, 9, "");
+ uiDefBut(block, BUTM, 1, "10", xco+=(menuwidth+1), yco, menuwidth, 19, NULL, 0.0, 0.0, 1, 10, "");
+ xco = 0;
+ uiDefBut(block, BUTM, 1, "11", xco, yco-=24, menuwidth, 19, NULL, 0.0, 0.0, 1, 11, "");
+ uiDefBut(block, BUTM, 1, "12", xco+=(menuwidth+1), yco, menuwidth, 19, NULL, 0.0, 0.0, 1, 12, "");
+ uiDefBut(block, BUTM, 1, "13", xco+=(menuwidth+1), yco, menuwidth, 19, NULL, 0.0, 0.0, 1, 13, "");
+ uiDefBut(block, BUTM, 1, "14", xco+=(menuwidth+1), yco, menuwidth, 19, NULL, 0.0, 0.0, 1, 14, "");
+ uiDefBut(block, BUTM, 1, "15", xco+=(menuwidth+1), yco, menuwidth, 19, NULL, 0.0, 0.0, 1, 15, "");
+ xco += 6;
+ uiDefBut(block, BUTM, 1, "16", xco+=(menuwidth+1), yco, menuwidth, 19, NULL, 0.0, 0.0, 1, 16, "");
+ uiDefBut(block, BUTM, 1, "17", xco+=(menuwidth+1), yco, menuwidth, 19, NULL, 0.0, 0.0, 1, 17, "");
+ uiDefBut(block, BUTM, 1, "18", xco+=(menuwidth+1), yco, menuwidth, 19, NULL, 0.0, 0.0, 1, 18, "");
+ uiDefBut(block, BUTM, 1, "19", xco+=(menuwidth+1), yco, menuwidth, 19, NULL, 0.0, 0.0, 1, 19, "");
+ uiDefBut(block, BUTM, 1, "20", xco+=(menuwidth+1), yco, menuwidth, 19, NULL, 0.0, 0.0, 1, 20, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ /*uiTextBoundsBlock(block, 100);*/
+ return block;
+}
+
+void do_view3d_select_object_linkedmenu(void *arg, int event)
+{
+ switch(event) {
+ case 1: /* Object Ipo */
+ case 2: /* ObData */
+ case 3: /* Current Material */
+ case 4: /* Current Texture */
+ selectlinks(event);
+ break;
+ }
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_select_object_linkedmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_select_object_linkedmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_select_object_linkedmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Object Ipo|Shift L, 1", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "ObData|Shift L, 2", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Material|Shift L, 3", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Texture|Shift L, 4", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+void do_view3d_select_object_groupedmenu(void *arg, int event)
+{
+ switch(event) {
+ case 1: /* Children */
+ case 2: /* Immediate Children */
+ case 3: /* Parent */
+ case 4: /* Siblings */
+ case 5: /* Type */
+ case 6: /* Objects on Shared Layers */
+ case 7: /* Objects in Same Group */
+ case 8: /* Object Hooks*/
+ case 9: /* Object PassIndex*/
+ select_object_grouped((short)event);
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_select_object_groupedmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_select_object_groupedmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_select_object_groupedmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Children|Shift G, 1", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Immediate Children|Shift G, 2", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Parent|Shift G, 3", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Siblings (Shared Parent)|Shift G, 4", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Objects of Same Type|Shift G, 5", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Objects on Shared Layers|Shift G, 6", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 6, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Objects in Same Group|Shift G, 7", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 7, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Object Hooks|Shift G, 8", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 8, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Object PassIndex|Shift G, 9", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 9, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+void do_view3d_select_objectmenu(void *arg, int event)
+{
+ switch(event) {
+
+ case 0: /* border select */
+ borderselect();
+ break;
+ case 1: /* Select/Deselect All */
+ deselectall();
+ break;
+ case 2: /* inverse */
+ selectswap();
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_select_objectmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_select_objectmenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_view3d_select_objectmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Border Select|B", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select/Deselect All|A", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Inverse", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBlockBut(block, view3d_select_object_layermenu, NULL, ICON_RIGHTARROW_THIN, "Select All by Layer", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, view3d_select_object_typemenu, NULL, ICON_RIGHTARROW_THIN, "Select All by Type", 0, yco-=20, 120, 19, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBlockBut(block, view3d_select_object_linkedmenu, NULL, ICON_RIGHTARROW_THIN, "Linked", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, view3d_select_object_groupedmenu, NULL, ICON_RIGHTARROW_THIN, "Grouped", 0, yco-=20, 120, 19, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+ return block;
+}
+
+void do_view3d_select_meshmenu(void *arg, int event)
+{
+/* extern void borderselect(void);*/
+
+ switch(event) {
+
+ case 0: /* border select */
+ borderselect();
+ break;
+ case 2: /* Select/Deselect all */
+ deselectall_mesh();
+ break;
+ case 3: /* Inverse */
+ selectswap_mesh();
+ break;
+ case 4: /* select linked vertices */
+ selectconnected_mesh_all();
+ break;
+ case 5: /* select random */
+ selectrandom_mesh();
+ break;
+ case 7: /* select more */
+ select_more();
+ break;
+ case 8: /* select less */
+ select_less();
+ break;
+ case 9: /* select non-manifold */
+ select_non_manifold();
+ break;
+ case 11: /* select triangles */
+ select_faces_by_numverts(3);
+ break;
+ case 12: /* select quads */
+ select_faces_by_numverts(4);
+ break;
+ case 13: /* select non-triangles/quads */
+ select_faces_by_numverts(5);
+ break;
+ case 14: /* select sharp edges */
+ select_sharp_edges();
+ break;
+ case 15: /* select linked flat faces */
+ select_linked_flat_faces();
+ break;
+
+ case 16: /* path select */
+ pathselect();
+ BIF_undo_push("Path Select");
+ break;
+ case 17: /* edge loop select */
+ loop_multiselect(0);
+ break;
+ case 18: /* edge ring select */
+ loop_multiselect(1);
+ break;
+ case 19: /* loop to region */
+ loop_to_region();
+ break;
+ case 20: /* region to loop */
+ region_to_loop();
+ break;
+ case 21: /* Select grouped */
+ select_mesh_group_menu();
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+
+static uiBlock *view3d_select_meshmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_select_meshmenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_view3d_select_meshmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Border Select|B", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select/Deselect All|A", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Inverse|Ctrl I", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6,
+ menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Random...", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Non-Manifold|Ctrl Alt Shift M",
+ 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 9, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Sharp Edges|Ctrl Alt Shift S",
+ 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 14, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Linked Flat Faces|Ctrl Alt Shift F",
+ 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 15, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6,
+ menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Triangles|Ctrl Alt Shift 3",
+ 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 11, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Quads|Ctrl Alt Shift 4",
+ 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 12, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Non-Triangles/Quads|Ctrl Alt Shift 5",
+ 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 13, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
+ "Similar to Selection...|Shift G",
+ 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 21, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6,
+ menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "More|Ctrl NumPad +",
+ 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 7, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Less|Ctrl NumPad -",
+ 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 8, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6,
+ menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Linked Vertices|Ctrl L", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Vertex Path|W Alt 7", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 16, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Edge Loop|Ctrl E 6", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 17, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Edge Ring|Ctrl E 7", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 18, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6,
+ menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Loop to Region|Ctrl E 8", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 19, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Region to Loop|Ctrl E 9", 0, yco-=20, menuwidth, 20, NULL, 0.0, 0.0, 1, 20, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+ return block;
+}
+
+void do_view3d_select_curvemenu(void *arg, int event)
+{
+/* extern void borderselect(void);*/
+
+ switch(event) {
+ case 0: /* border select */
+ borderselect();
+ break;
+ case 2: /* Select/Deselect all */
+ deselectall_nurb();
+ break;
+ case 3: /* Inverse */
+ selectswapNurb();
+ break;
+ /* select connected control points */
+ /*case 4:
+ G.qual |= LR_CTRLKEY;
+ select_connected_nurb();
+ G.qual &= ~LR_CTRLKEY;
+ break;*/
+ case 5: /* select row (nurb) */
+ selectrow_nurb();
+ break;
+ case 7: /* select/deselect first */
+ selectend_nurb(FIRST, 1, DESELECT);
+ break;
+ case 8: /* select/deselect last */
+ selectend_nurb(LAST, 1, DESELECT);
+ break;
+ case 9: /* select more */
+ select_more_nurb();
+ break;
+ case 10: /* select less */
+ select_less_nurb();
+ break;
+ case 11: /* select next */
+ select_next_nurb();
+ break;
+ case 12: /* select previous */
+ select_prev_nurb();
+ break;
+ case 13: /* select random */
+ select_random_nurb();
+ break;
+ case 14: /* select every nth */
+ select_every_nth_nurb();
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+
+static uiBlock *view3d_select_curvemenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_select_curvemenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_view3d_select_curvemenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Border Select|B", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select/Deselect All|A", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Inverse", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Random...", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 13, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Every Nth", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 14, "");
+
+ if (OBACT->type == OB_SURF) {
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Control Point Row|Shift R", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+ }
+ else {
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select/Deselect First", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 7, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select/Deselect Last", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 8, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select Next", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 11, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select Previous", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 12, "");
+ }
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "More|Ctrl NumPad +", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 9, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Less|Ctrl NumPad -", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 10, "");
+
+ /* commented out because it seems to only like the LKEY method - based on mouse pointer position :( */
+ /*uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Connected Control Points|Ctrl L", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");*/
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+ return block;
+}
+
+void do_view3d_select_metaballmenu(void *arg, int event)
+{
+
+ switch(event) {
+ case 0: /* border select */
+ borderselect();
+ break;
+ case 2: /* Select/Deselect all */
+ deselectall_mball();
+ break;
+ case 3: /* Inverse */
+ selectinverse_mball();
+ break;
+ case 4: /* Select Random */
+ selectrandom_mball();
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+
+static uiBlock *view3d_select_metaballmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_select_metaballmenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_view3d_select_metaballmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Border Select|B", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select/Deselect All|A", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Inverse", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Random...", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+ return block;
+}
+
+static void do_view3d_select_latticemenu(void *arg, int event)
+{
+/* extern void borderselect(void);*/
+
+ switch(event) {
+ case 0: /* border select */
+ borderselect();
+ break;
+ case 2: /* Select/Deselect all */
+ deselectall_Latt();
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_select_latticemenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_select_latticemenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_view3d_select_latticemenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Border Select|B", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select/Deselect All|A", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+ return block;
+}
+
+static void do_view3d_select_armaturemenu(void *arg, int event)
+{
+/* extern void borderselect(void);*/
+
+ switch(event) {
+ case 0: /* border select */
+ borderselect();
+ break;
+ case 2: /* Select/Deselect all */
+ deselectall_armature(1, 1);
+ break;
+ case 3: /* Select Parent(s) */
+ select_bone_parent();
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_select_armaturemenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_select_armaturemenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_view3d_select_armaturemenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Border Select|B", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select/Deselect All|A", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select Parent(s)|P", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+ return block;
+}
+
+static void do_view3d_select_pose_armaturemenu(void *arg, int event)
+{
+/* extern void borderselect(void);*/
+
+ switch(event) {
+ case 0: /* border select */
+ borderselect();
+ break;
+ case 2: /* Select/Deselect all */
+ deselectall_posearmature(OBACT, 1, 1);
+ break;
+ case 3:
+ pose_select_constraint_target();
+ break;
+ case 4:
+ select_bone_parent();
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_select_pose_armaturemenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_select_pose_armaturemenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_view3d_select_pose_armaturemenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Border Select|B", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select/Deselect All|A", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select Constraint Target|W", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select Parent(s)|P", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+ return block;
+}
+
+void do_view3d_select_faceselmenu(void *arg, int event)
+{
+ /* events >= 6 are registered bpython scripts */
+ if (event >= 6) BPY_menu_do_python(PYMENU_FACESELECT, event - 6);
+
+ switch(event) {
+ case 0: /* border select */
+ borderselect();
+ break;
+ case 2: /* Select/Deselect all */
+ deselectall_tface();
+ break;
+ case 3: /* Select Inverse */
+ selectswap_tface();
+ break;
+ case 4: /* Select Linked */
+ select_linked_tfaces(2);
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_select_faceselmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+ BPyMenu *pym;
+ int i = 0;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_select_faceselmenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_view3d_select_faceselmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Border Select|B", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select/Deselect All|A", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Inverse", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Linked Faces|Ctrl L", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ /* note that we account for the 6 previous entries with i+6: */
+ for (pym = BPyMenuTable[PYMENU_FACESELECT]; pym; pym = pym->next, i++) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_PYTHON, pym->name, 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, i+6,
+ pym->tooltip?pym->tooltip:pym->filename);
+ }
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+ return block;
+}
+
+void do_view3d_edit_snapmenu(void *arg, int event)
+{
+ switch(event) {
+ case 1: /* Selection to grid */
+ snap_sel_to_grid();
+ break;
+ case 2: /* Selection to cursor */
+ snap_sel_to_curs();
+ break;
+ case 3: /* Cursor to grid */
+ snap_curs_to_grid();
+ break;
+ case 4: /* Cursor to selection */
+ snap_curs_to_sel();
+ break;
+ case 5: /* Selection to center of selection*/
+ snap_to_center();
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_edit_snapmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_edit_snapmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_edit_snapmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Selection -> Grid|Shift S, 1", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Selection -> Cursor|Shift S, 2", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Cursor -> Grid|Shift S, 3", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Cursor -> Selection|Shift S, 4", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Selection -> Center|Shift S, 5", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+void do_view3d_transform_moveaxismenu(void *arg, int event)
+{
+ float mat[3][3];
+
+ Mat3One(mat);
+
+ switch(event)
+ {
+ case 0: /* X Global */
+ initTransform(TFM_TRANSLATION, CTX_NONE);
+ BIF_setSingleAxisConstraint(mat[0], " X");
+ Transform();
+ break;
+ case 1: /* Y Global */
+ initTransform(TFM_TRANSLATION, CTX_NONE);
+ BIF_setSingleAxisConstraint(mat[1], " Y");
+ Transform();
+ break;
+ case 2: /* Z Global */
+ initTransform(TFM_TRANSLATION, CTX_NONE);
+ BIF_setSingleAxisConstraint(mat[2], " Z");
+ Transform();
+ break;
+ case 3: /* X Local */
+ initTransform(TFM_TRANSLATION, CTX_NONE);
+ BIF_setLocalAxisConstraint('X', " X");
+ Transform();
+ break;
+ case 4: /* Y Local */
+ initTransform(TFM_TRANSLATION, CTX_NONE);
+ BIF_setLocalAxisConstraint('Y', " Y");
+ Transform();
+ break;
+ case 5: /* Z Local */
+ initTransform(TFM_TRANSLATION, CTX_NONE);
+ BIF_setLocalAxisConstraint('Z', " Z");
+ Transform();
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_transform_moveaxismenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_transform_moveaxismenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_transform_moveaxismenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "X Global|G, X", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Y Global|G, Y", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Z Global|G, Z", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "X Local|G, X, X", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Y Local|G, Y, Y", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Z Local|G, Z, Z", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+void do_view3d_transform_rotateaxismenu(void *arg, int event)
+{
+ float mat[3][3];
+
+ Mat3One(mat);
+
+ switch(event)
+ {
+ case 0: /* X Global */
+ initTransform(TFM_ROTATION, CTX_NONE);
+ BIF_setSingleAxisConstraint(mat[0], " X");
+ Transform();
+ break;
+ case 1: /* Y Global */
+ initTransform(TFM_ROTATION, CTX_NONE);
+ BIF_setSingleAxisConstraint(mat[1], " Y");
+ Transform();
+ break;
+ case 2: /* Z Global */
+ initTransform(TFM_ROTATION, CTX_NONE);
+ BIF_setSingleAxisConstraint(mat[2], " Z");
+ Transform();
+ break;
+ case 3: /* X Local */
+ initTransform(TFM_ROTATION, CTX_NONE);
+ BIF_setLocalAxisConstraint('X', " X");
+ Transform();
+ break;
+ case 4: /* Y Local */
+ initTransform(TFM_ROTATION, CTX_NONE);
+ BIF_setLocalAxisConstraint('Y', " Y");
+ Transform();
+ break;
+ case 5: /* Z Local */
+ initTransform(TFM_ROTATION, CTX_NONE);
+ BIF_setLocalAxisConstraint('Z', " Z");
+ Transform();
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_transform_rotateaxismenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_transform_rotateaxismenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_transform_rotateaxismenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "X Global|R, X", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Y Global|R, Y", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Z Global|R, Z", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "X Local|R, X, X", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Y Local|R, Y, Y", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Z Local|R, Z, Z", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+void do_view3d_transform_scaleaxismenu(void *arg, int event)
+{
+ float mat[3][3];
+
+ Mat3One(mat);
+
+ switch(event)
+ {
+ case 0: /* X Global */
+ initTransform(TFM_RESIZE, CTX_NONE);
+ BIF_setSingleAxisConstraint(mat[0], " X");
+ Transform();
+ break;
+ case 1: /* Y Global */
+ initTransform(TFM_RESIZE, CTX_NONE);
+ BIF_setSingleAxisConstraint(mat[1], " Y");
+ Transform();
+ break;
+ case 2: /* Z Global */
+ initTransform(TFM_RESIZE, CTX_NONE);
+ BIF_setSingleAxisConstraint(mat[2], " Z");
+ Transform();
+ break;
+ case 3: /* X Local */
+ initTransform(TFM_RESIZE, CTX_NONE);
+ BIF_setLocalAxisConstraint('X', " X");
+ Transform();
+ break;
+ case 4: /* Y Local */
+ initTransform(TFM_RESIZE, CTX_NONE);
+ BIF_setLocalAxisConstraint('X', " X");
+ Transform();
+ break;
+ case 5: /* Z Local */
+ initTransform(TFM_RESIZE, CTX_NONE);
+ BIF_setLocalAxisConstraint('X', " X");
+ Transform();
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_transform_scaleaxismenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_transform_scaleaxismenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_transform_scaleaxismenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "X Global|S, X", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Y Global|S, Y", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Z Global|S, Z", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "X Local|S, X, X", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Y Local|S, Y, Y", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Z Local|S, Z, Z", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+static void do_view3d_transformmenu(void *arg, int event)
+{
+ switch(event) {
+ case 1:
+ initTransform(TFM_TRANSLATION, CTX_NONE);
+ Transform();
+ break;
+ case 2:
+ initTransform(TFM_ROTATION, CTX_NONE);
+ Transform();
+ break;
+ case 3:
+ initTransform(TFM_RESIZE, CTX_NONE);
+ Transform();
+ break;
+ case 4:
+ image_aspect();
+ break;
+ case 5:
+ initTransform(TFM_TOSPHERE, CTX_NONE);
+ Transform();
+ break;
+ case 6:
+ initTransform(TFM_SHEAR, CTX_NONE);
+ Transform();
+ break;
+ case 7:
+ initTransform(TFM_WARP, CTX_NONE);
+ Transform();
+ break;
+ case 8:
+ initTransform(TFM_PUSHPULL, CTX_NONE);
+ Transform();
+ break;
+ case 9:
+ if (G.obedit) {
+ if (G.obedit->type == OB_MESH)
+ initTransform(TFM_SHRINKFATTEN, CTX_NONE);
+ Transform();
+ } else error("Only meshes can be shrinked/fattened");
+ break;
+ case 10:
+ docenter(0);
+ break;
+ case 11:
+ docenter_new();
+ break;
+ case 12:
+ docenter_cursor();
+ break;
+ case 13:
+ initTransform(TFM_TILT, CTX_NONE);
+ Transform();
+ break;
+ case 14:
+ initTransform(TFM_CURVE_SHRINKFATTEN, CTX_NONE);
+ Transform();
+ break;
+ case 15:
+ G.scene->snap_flag &= ~SCE_SNAP;
+ break;
+ case 16:
+ G.scene->snap_flag |= SCE_SNAP;
+ break;
+ case 17:
+ G.scene->snap_target = SCE_SNAP_TARGET_CLOSEST;
+ break;
+ case 18:
+ G.scene->snap_target = SCE_SNAP_TARGET_CENTER;
+ break;
+ case 19:
+ G.scene->snap_target = SCE_SNAP_TARGET_MEDIAN;
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_transformmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_transformmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_transformmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Grab/Move|G", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBlockBut(block, view3d_transform_moveaxismenu, NULL, ICON_RIGHTARROW_THIN, "Grab/Move on Axis", 0, yco-=20, 120, 19, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Rotate|R", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBlockBut(block, view3d_transform_rotateaxismenu, NULL, ICON_RIGHTARROW_THIN, "Rotate on Axis", 0, yco-=20, 120, 19, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Scale|S", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+ uiDefIconTextBlockBut(block, view3d_transform_scaleaxismenu, NULL, ICON_RIGHTARROW_THIN, "Scale on Axis", 0, yco-=20, 120, 19, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ if (G.obedit) {
+ if (G.obedit->type == OB_MESH)
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Shrink/Fatten Along Normals|Alt S", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 9, "");
+ else if (G.obedit->type == OB_CURVE) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Tilt|T", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 13, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Shrink/Fatten Radius|Alt S", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 14, "");
+ }
+ }
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "To Sphere|Ctrl Shift S", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+ if (G.obedit) uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Shear|Ctrl S", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 6, "");
+ else uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Shear|Ctrl Shift Alt S", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 6, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Warp|Shift W", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 7, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Push/Pull|Shift P", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 8, "");
+
+ if (!G.obedit) {
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Scale to Image Aspect Ratio|Alt V", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+ }
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "ObData to Center", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 10, "");
+ if (!G.obedit) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Center New", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 11, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Center Cursor", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 12, "");
+ }
+
+ if (G.obedit != NULL && G.obedit->type==OB_MESH)
+ {
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ if (G.scene->snap_flag & SCE_SNAP)
+ {
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Grid", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 15, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Snap", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 16, "");
+ }
+ else
+ {
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Grid", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 15, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Snap", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 16, "");
+ }
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ switch(G.scene->snap_target)
+ {
+ case SCE_SNAP_TARGET_CLOSEST:
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Snap Closest", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 17, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Snap Center", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 18, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Snap Median", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 19, "");
+ break;
+ case SCE_SNAP_TARGET_CENTER:
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Snap Closest", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 17, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Snap Center", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 18, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Snap Median", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 19, "");
+ break;
+ case SCE_SNAP_TARGET_MEDIAN:
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Snap Closest", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 17, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Snap Center", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 18, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Snap Median", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 19, "");
+ break;
+ }
+ }
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+void do_view3d_object_mirrormenu(void *arg, int event)
+{
+ switch(event) {
+ case 1:
+ case 2:
+ case 3:
+ Mirror(event + 3); /* + 3 because the first three modes are global*/
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_object_mirrormenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_object_mirrormenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_object_mirrormenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "X Local|Ctrl M, 1", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Y Local|Ctrl M, 2", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Z Local|Ctrl M, 3", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+static void do_view3d_edit_object_transformmenu(void *arg, int event)
+{
+ switch(event) {
+ case 0: /* clear origin */
+ clear_object('o');
+ break;
+ case 1: /* clear scale */
+ clear_object('s');
+ break;
+ case 2: /* clear rotation */
+ clear_object('r');
+ break;
+ case 3: /* clear location */
+ clear_object('g');
+ break;
+ case 4:
+ if(OBACT) object_apply_deform(OBACT);
+ break;
+ case 5: /* make duplis real */
+ make_duplilist_real();
+ break;
+ case 6: /* apply scale/rotation or deformation */
+ apply_object();
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_edit_object_transformmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_edit_object_transformmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_edit_object_transformmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Apply Scale/Rotation|Ctrl A", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 6, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Apply Deformation|Ctrl Shift A", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Make Duplicates Real|Ctrl Shift A", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Clear Location|Alt G", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Clear Rotation|Alt R", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Clear Scale|Alt S", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Clear Origin|Alt O", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+static void do_view3d_edit_object_makelocalmenu(void *arg, int event)
+{
+ switch(event) {
+ case 1:
+ case 2:
+ case 3:
+ make_local(event);
+ break;
+ }
+}
+
+static uiBlock *view3d_edit_object_makelocalmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_edit_object_makelocalmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_edit_object_makelocalmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Selected Objects|L, 1", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Selected Objects and Data|L, 2", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "All|L, 3", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+static void do_view3d_edit_object_makelinksmenu(void *arg, int event)
+{
+ switch(event) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ make_links((short)event);
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_edit_object_makelinksmenu(void *arg_unused)
+{
+ Object *ob=NULL;
+
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_edit_object_makelinksmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_edit_object_makelinksmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "To Scene...|Ctrl L, 1", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Object Ipo|Ctrl L, 2", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+
+ if ((ob=OBACT)) {
+
+ if(ob->type==OB_MESH) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Mesh Data|Ctrl L, 3", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Materials|Ctrl L, 4", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+ } else if(ob->type==OB_CURVE) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Curve Data|Ctrl L, 3", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Materials|Ctrl L, 4", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+ } else if(ob->type==OB_FONT) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Text Data|Ctrl L, 3", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Materials|Ctrl L, 4", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+ } else if(ob->type==OB_SURF) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Surface Data|Ctrl L, 3", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Materials|Ctrl L, 4", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+ } else if(ob->type==OB_MBALL) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Materials|Ctrl L, 3", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+ } else if(ob->type==OB_CAMERA) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Camera Data|Ctrl L, 3", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ } else if(ob->type==OB_LAMP) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Lamp Data|Ctrl L, 3", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ } else if(ob->type==OB_LATTICE) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Lattice Data|Ctrl L, 3", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ } else if(ob->type==OB_ARMATURE) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Armature Data|Ctrl L, 3", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ }
+ }
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+static void do_view3d_edit_object_singleusermenu(void *arg, int event)
+{
+ switch(event) {
+ case 1: /* Object */
+ single_object_users(1);
+ break;
+ case 2: /* Object & ObData */
+ single_object_users(1);
+ single_obdata_users(1);
+ break;
+ case 3: /* Object & ObData & Materials+Tex */
+ single_object_users(1);
+ single_obdata_users(1);
+ single_mat_users(1); /* also tex */
+ break;
+ case 4: /* Materials+Tex */
+ single_mat_users(1);
+ break;
+ }
+
+ clear_id_newpoins();
+ countall();
+
+ allqueue(REDRAWALL, 0);
+}
+
+static uiBlock *view3d_edit_object_singleusermenu(void *arg_unused)
+{
+
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_edit_object_singleusermenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_edit_object_singleusermenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Object|U, 1", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Object & ObData|U, 2", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Object & ObData & Materials+Tex|U, 3", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Materials+Tex|U, 4", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+static void do_view3d_edit_object_copyattrmenu(void *arg, int event)
+{
+ switch(event) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 17:
+ case 18:
+ case 19:
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ case 24:
+ case 25:
+ case 26:
+ case 29:
+ case 30:
+ copy_attr((short)event);
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_edit_object_copyattrmenu(void *arg_unused)
+{
+ Object *ob=NULL;
+
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_edit_object_copyattrmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_edit_object_copyattrmenu, NULL);
+
+ ob= OBACT;
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Location|Ctrl C, 1", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Rotation|Ctrl C, 2", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Size|Ctrl C, 3", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Drawtype|Ctrl C, 4", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Time Offset|Ctrl C, 5", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Dupli|Ctrl C, 6", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 6, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Mass|Ctrl C, 7", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 7, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Damping|Ctrl C, 8", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 8, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Properties|Ctrl C, 9", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 9, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Logic Bricks|Ctrl C, 10", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 10, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Protected Transform |Ctrl C", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 29, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Object Constraints|Ctrl C", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 22, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "NLA Strips|Ctrl C", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 26, "");
+
+ if (ob) {
+
+ if ((ob->type == OB_MESH) || (ob->type == OB_CURVE) || (ob->type == OB_SURF) ||
+ (ob->type == OB_FONT) || (ob->type == OB_MBALL)) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Texture Space|Ctrl C", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 17, "");
+ }
+
+ if(ob->type == OB_FONT) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Font Settings|Ctrl C", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 18, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Bevel Settings|Ctrl C", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 19, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Curve Resolution|Ctrl C", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 25, "");
+ }
+ if(ob->type == OB_CURVE) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Bevel Settings|Ctrl C", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 19, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Curve Resolution|Ctrl C", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 25, "");
+ }
+
+ if(ob->type==OB_MESH) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Subsurf Settings|Ctrl C", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 21, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Modifiers ...|Ctrl C", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 24, "");
+ }
+
+ if( give_parteff(ob) ) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Particle Settings|Ctrl C", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 20, "");
+ }
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Object Pass Index|Ctrl C", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 30, "");
+ }
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+
+static void do_view3d_edit_object_parentmenu(void *arg, int event)
+{
+ switch(event) {
+ case 0: /* clear parent */
+ clear_parent();
+ break;
+ case 1: /* make parent */
+ make_parent();
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_edit_object_parentmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_edit_object_parentmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_edit_object_parentmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Make Parent...|Ctrl P", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Clear Parent...|Alt P", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+static void do_view3d_edit_object_groupmenu(void *arg, int event)
+{
+ switch(event) {
+ case 1:
+ case 2:
+ case 3:
+ group_operation(event);
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_edit_object_groupmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_edit_object_groupmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_edit_object_groupmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Add to Existing Group|Ctrl G, 1", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Add to New Group|Ctrl G, 2", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Remove from All Groups|Ctrl G, 3", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+static void do_view3d_edit_object_trackmenu(void *arg, int event)
+{
+ switch(event) {
+ case 0: /* clear track */
+ clear_track();
+ break;
+ case 1: /* make track */
+ make_track();
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_edit_object_trackmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_edit_object_trackmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_edit_object_trackmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Make Track...|Ctrl T", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Clear Track...|Alt T", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+static void do_view3d_edit_object_constraintsmenu(void *arg, int event)
+{
+ switch(event) {
+ case 1: /* add constraint */
+ add_constraint(0);
+ break;
+ case 2: /* clear constraint */
+ ob_clear_constraints();
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_edit_object_constraintsmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_edit_object_constraintsmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_edit_object_constraintsmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Add Constraint...|Ctrl Alt C", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Clear Constraints", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+static void do_view3d_edit_object_showhidemenu(void *arg, int event)
+{
+
+ switch(event) {
+
+ case 0: /* show objects */
+ show_objects();
+ break;
+ case 1: /* hide selected objects */
+ hide_objects(1);
+ break;
+ case 2: /* hide deselected objects */
+ hide_objects(0);
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_edit_object_showhidemenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_edit_object_showhidemenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_edit_object_showhidemenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Show Hidden|Alt H", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Hide Selected|H", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Hide Deselected|Shift H", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+static void do_view3d_edit_object_scriptsmenu(void *arg, int event)
+{
+ BPY_menu_do_python(PYMENU_OBJECT, event);
+
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_edit_object_scriptsmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+ BPyMenu *pym;
+ int i = 0;
+
+ block= uiNewBlock(&curarea->uiblocks, "v3d_eobject_pymenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_edit_object_scriptsmenu, NULL);
+
+ for (pym = BPyMenuTable[PYMENU_OBJECT]; pym; pym = pym->next, i++) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_PYTHON, pym->name, 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, i, pym->tooltip?pym->tooltip:pym->filename);
+ }
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+
+ return block;
+}
+
+#ifdef WITH_VERSE
+extern ListBase session_list;
+#endif
+
+static void do_view3d_edit_objectmenu(void *arg, int event)
+{
+ /* needed to check for valid selected objects */
+ Base *base=NULL;
+ Object *ob=NULL;
+#ifdef WITH_VERSE
+ struct VerseSession *session=NULL;
+#endif
+
+ base= BASACT;
+ if (base) ob= base->object;
+
+ switch(event) {
+
+ case 0: /* transform properties*/
+ mainqenter(NKEY, 1);
+ break;
+ case 1: /* delete */
+ delete_context_selected();
+ break;
+ case 2: /* duplicate */
+ duplicate_context_selected();
+ break;
+ case 3: /* duplicate linked */
+ adduplicate(0, 0);
+ break;
+ case 5: /* make single user */
+ single_user();
+ break;
+ case 7: /* boolean operation */
+ special_editmenu();
+ break;
+ case 8: /* join objects */
+ join_menu();
+ break;
+ case 9: /* convert object type */
+ convertmenu();
+ break;
+ case 10: /* move to layer */
+ movetolayer();
+ break;
+ case 11: /* insert keyframe */
+ common_insertkey();
+ break;
+ case 15: /* Object Panel */
+ add_blockhandler(curarea, VIEW3D_HANDLER_OBJECT, UI_PNL_UNSTOW);
+ break;
+#ifdef WITH_VERSE
+ case 16: /* Share Object at Verse server */
+ if(session_list.first != session_list.last) session = session_menu();
+ else session = session_list.first;
+ if(session) b_verse_push_object(session, ob);
+ break;
+#endif
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_edit_objectmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_edit_objectmenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_view3d_edit_objectmenu, NULL);
+
+#ifdef WITH_VERSE
+ if(session_list.first != NULL) {
+ Base *base = BASACT;
+ Object *ob = NULL;
+ if (base) ob= base->object;
+
+ if(ob && (ob->type == OB_MESH) && (!ob->vnode)) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Share at Verse Server", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 16, "");
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+ }
+ }
+#endif
+
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_MENU_PANEL, "Transform Properties|N", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 15, "");
+ uiDefIconTextBlockBut(block, view3d_transformmenu, NULL, ICON_RIGHTARROW_THIN, "Transform", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, view3d_object_mirrormenu, NULL, ICON_RIGHTARROW_THIN, "Mirror", 0, yco-=20, menuwidth, 19, "");
+
+ uiDefIconTextBlockBut(block, view3d_edit_object_transformmenu, NULL, ICON_RIGHTARROW_THIN, "Clear/Apply", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, view3d_edit_snapmenu, NULL, ICON_RIGHTARROW_THIN, "Snap", 0, yco-=20, 120, 19, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Insert Keyframe|I", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 11, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Duplicate|Shift D", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Duplicate Linked|Alt D", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Delete|X", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBlockBut(block, view3d_edit_object_makelinksmenu, NULL, ICON_RIGHTARROW_THIN, "Make Links", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, view3d_edit_object_singleusermenu, NULL, ICON_RIGHTARROW_THIN, "Make Single User", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, view3d_edit_object_makelocalmenu, NULL, ICON_RIGHTARROW_THIN, "Make Local", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, view3d_edit_object_copyattrmenu, NULL, ICON_RIGHTARROW_THIN, "Copy Attributes", 0, yco-=20, 120, 19, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBlockBut(block, view3d_edit_object_parentmenu, NULL, ICON_RIGHTARROW_THIN, "Parent", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, view3d_edit_object_groupmenu, NULL, ICON_RIGHTARROW_THIN, "Group", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, view3d_edit_object_trackmenu, NULL, ICON_RIGHTARROW_THIN, "Track", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, view3d_edit_object_constraintsmenu, NULL, ICON_RIGHTARROW_THIN, "Constraints", 0, yco-=20, 120, 19, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ if (OBACT && OBACT->type == OB_MESH) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Boolean Operation...|W", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 7, "");
+ }
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Join Objects|Ctrl J", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 8, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Convert Object Type...|Alt C", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 9, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Move to Layer...|M", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 10, "");
+ uiDefIconTextBlockBut(block, view3d_edit_object_showhidemenu, NULL, ICON_RIGHTARROW_THIN, "Show/Hide Objects", 0, yco-=20, 120, 19, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBlockBut(block, view3d_edit_object_scriptsmenu, NULL, ICON_RIGHTARROW_THIN, "Scripts", 0, yco-=20, 120, 19, "");
+
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+ return block;
+}
+
+
+static void do_view3d_edit_propfalloffmenu(void *arg, int event)
+{
+
+ G.scene->prop_mode= event;
+
+ allqueue(REDRAWVIEW3D, 1);
+}
+
+static uiBlock *view3d_edit_propfalloffmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_edit_propfalloffmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_edit_propfalloffmenu, NULL);
+
+ if (G.scene->prop_mode==PROP_SMOOTH) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Smooth|Shift O", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, PROP_SMOOTH, "");
+ else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Smooth|Shift O", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, PROP_SMOOTH, "");
+ if (G.scene->prop_mode==PROP_SPHERE) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Sphere|Shift O", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, PROP_SPHERE, "");
+ else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Sphere|Shift O", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, PROP_SPHERE, "");
+ if (G.scene->prop_mode==PROP_ROOT) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Root|Shift O", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, PROP_ROOT, "");
+ else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Root|Shift O", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, PROP_ROOT, "");
+ if (G.scene->prop_mode==PROP_SHARP) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Sharp|Shift O", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, PROP_SHARP, "");
+ else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Sharp|Shift O", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, PROP_SHARP, "");
+ if (G.scene->prop_mode==PROP_LIN) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Linear|Shift O", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, PROP_LIN, "");
+ else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Linear|Shift O", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, PROP_LIN, "");
+ if (G.scene->prop_mode==PROP_RANDOM) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Random|Shift O", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, PROP_RANDOM, "");
+ else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Random|Shift O", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, PROP_RANDOM, "");
+ if (G.scene->prop_mode==PROP_CONST) uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Constant|Shift O", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, PROP_CONST, "");
+ else uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Constant|Shift O", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, PROP_CONST, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+
+void do_view3d_edit_mesh_verticesmenu(void *arg, int event)
+{
+
+ switch(event) {
+ int count;
+
+ case 0: /* make vertex parent */
+ make_parent();
+ break;
+ case 1: /* remove doubles */
+ count= removedoublesflag(1, 0, G.scene->toolsettings->doublimit);
+ notice("Removed: %d", count);
+ if (count) { /* only undo and redraw if an action is taken */
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ BIF_undo_push("Rem Doubles");
+ }
+ break;
+ case 2: /* smooth */
+ vertexsmooth();
+ break;
+ case 3: /* separate */
+ separate_mesh();
+ break;
+ case 4: /*split */
+ split_mesh();
+ break;
+ case 5: /*merge */
+ mergemenu();
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ break;
+ case 6: /* add hook */
+ add_hook();
+ break;
+ case 7: /* rip */
+ mesh_rip();
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_edit_mesh_verticesmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_edit_mesh_verticesmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_edit_mesh_verticesmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Merge...|Alt M", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Rip|V", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 7, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Split|Y", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Separate|P", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Smooth|W, Alt 1", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Remove Doubles|W, 6", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Make Vertex Parent|Ctrl P", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Add Hook|Ctrl H", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 6, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+extern void editmesh_mark_sharp(int set); /* declared in editmesh_mods.c */
+
+void do_view3d_edit_mesh_edgesmenu(void *arg, int event)
+{
+ float fac;
+ short randfac;
+
+ switch(event) {
+
+ case 0: /* subdivide smooth */
+ esubdivideflag(1, 0.0, G.scene->toolsettings->editbutflag | B_SMOOTH,1,0);
+ BIF_undo_push("Subdivide Smooth");
+ break;
+ case 1: /*subdivide fractal */
+ randfac= 10;
+ if(button(&randfac, 1, 100, "Rand fac:")==0) return;
+ fac= -( (float)randfac )/100;
+ esubdivideflag(1, fac, G.scene->toolsettings->editbutflag,1,0);
+ BIF_undo_push("Subdivide Fractal");
+ break;
+ case 2: /* subdivide */
+ esubdivideflag(1, 0.0, G.scene->toolsettings->editbutflag,1,0);
+ BIF_undo_push("Subdivide");
+ break;
+ case 3: /* knife subdivide */
+ KnifeSubdivide(KNIFE_PROMPT);
+ break;
+ case 4: /* Loop subdivide */
+ CutEdgeloop(1);
+ break;
+ case 5: /* Make Edge/Face */
+ addedgeface_mesh();
+ break;
+ case 6:
+ bevel_menu();
+ break;
+ case 7: /* Mark Seam */
+ editmesh_mark_seam(0);
+ break;
+ case 8: /* Clear Seam */
+ editmesh_mark_seam(1);
+ break;
+ case 9: /* Cease SubSurf */
+ if(!multires_level1_test()) {
+ initTransform(TFM_CREASE, CTX_EDGE);
+ Transform();
+ }
+ break;
+ case 10: /* Rotate Edge */
+ edge_rotate_selected(2);
+ break;
+ case 11: /* Rotate Edge */
+ edge_rotate_selected(1);
+ break;
+ case 12: /* Edgeslide */
+ EdgeSlide(0,0.0);
+ break;
+ case 13: /* Edge Loop Delete */
+ EdgeLoopDelete();
+ break;
+ case 14: /*Collapse Edges*/
+ collapseEdges();
+ BIF_undo_push("Collapse");
+ break;
+ case 15:
+ editmesh_mark_sharp(1);
+ BIF_undo_push("Mark Sharp");
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ break;
+ case 16:
+ editmesh_mark_sharp(0);
+ BIF_undo_push("Clear Sharp");
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_edit_mesh_edgesmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_edit_mesh_edgesmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_edit_mesh_edgesmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Make Edge/Face|F", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Bevel|W, Alt 2", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 6, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Loop Subdivide...|Ctrl R", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Knife Subdivide...|Shift K", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Subdivide|W, 1", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Subdivide Fractal|W, 3", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Subdivide Smooth|W, 4", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Mark Seam|Ctrl E", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 7, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Clear Seam|Ctrl E", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 8, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Mark Sharp|Ctrl E", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 15, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Clear Sharp|Ctrl E", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 16, "");
+
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Crease SubSurf|Shift E", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 9, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Rotate Edge CW|Ctrl E", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 10, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Rotate Edge CCW|Ctrl E", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 11, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Slide Edge |Ctrl E", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 12, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Delete Edge Loop|X", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 13, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Collapse", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 14, "");
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+void do_view3d_edit_mesh_facesmenu(void *arg, int event)
+{
+ switch(event) {
+ case 0: /* Fill Faces */
+ fill_mesh();
+ break;
+ case 1: /* Beauty Fill Faces */
+ beauty_fill();
+ break;
+ case 2: /* Quads to Tris */
+ convert_to_triface(0);
+ allqueue(REDRAWVIEW3D, 0);
+ countall();
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ break;
+ case 3: /* Tris to Quads */
+ join_triangles();
+ break;
+ case 4: /* Flip triangle edges */
+ edge_flip();
+ break;
+ case 5: /* Make Edge/Face */
+ addedgeface_mesh();
+ break;
+ case 6: /* Set Smooth */
+ mesh_set_smooth_faces(1);
+ break;
+ case 7: /* Set Solid */
+ mesh_set_smooth_faces(0);
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_edit_mesh_facesmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_edit_mesh_facesmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_edit_mesh_facesmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Make Edge/Face|F", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Fill|Shift F", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Beautify Fill|Alt F", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Convert Quads to Triangles|Ctrl T", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Convert Triangles to Quads|Alt J", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Flip Triangle Edges|Ctrl Shift F", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Set Smooth|W, Alt 3", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 6, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Set Solid|W, Alt 4", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 7, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+void do_view3d_edit_mesh_normalsmenu(void *arg, int event)
+{
+ switch(event) {
+ case 0: /* flip */
+ flip_editnormals();
+ break;
+ case 1: /* recalculate inside */
+ righthandfaces(2);
+ break;
+ case 2: /* recalculate outside */
+ righthandfaces(1);
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_edit_mesh_normalsmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_edit_mesh_normalsmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_edit_mesh_normalsmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Recalculate Outside|Ctrl N", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Recalculate Inside|Ctrl Shift N", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Flip|W, 0", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+void do_view3d_edit_mirrormenu(void *arg, int event)
+{
+ switch(event) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ Mirror(event);
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_edit_mirrormenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_edit_mirrormenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_edit_mirrormenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "X Global|Ctrl M, 1", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Y Global|Ctrl M, 2", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Z Global|Ctrl M, 3", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "X Local|Ctrl M, 4", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Y Local|Ctrl M, 5", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Z Local|Ctrl M, 6", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 6, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "X View|Ctrl M, 7", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 7, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Y View|Ctrl M, 8", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 8, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Z View|Ctrl M, 9", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 9, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+static void do_view3d_edit_mesh_showhidemenu(void *arg, int event)
+{
+
+ switch(event) {
+
+ case 0: /* show hidden vertices */
+ reveal_mesh();
+ break;
+ case 1: /* hide selected vertices */
+ hide_mesh(0);
+ break;
+ case 2: /* hide deselected vertices */
+ hide_mesh(1);
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_edit_mesh_showhidemenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_edit_mesh_showhidemenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_edit_mesh_showhidemenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Show Hidden|Alt H", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Hide Selected|H", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Hide Deselected|Shift H", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+static void do_view3d_edit_mesh_scriptsmenu(void *arg, int event)
+{
+ BPY_menu_do_python(PYMENU_MESH, event);
+
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_edit_mesh_scriptsmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+ BPyMenu *pym;
+ int i = 0;
+
+ block= uiNewBlock(&curarea->uiblocks, "v3d_emesh_pymenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_edit_mesh_scriptsmenu, NULL);
+
+ for (pym = BPyMenuTable[PYMENU_MESH]; pym; pym = pym->next, i++) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_PYTHON, pym->name, 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, i, pym->tooltip?pym->tooltip:pym->filename);
+ }
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+
+ return block;
+}
+
+static void do_view3d_edit_meshmenu(void *arg, int event)
+{
+#ifdef WITH_VERSE
+ struct VerseSession *session;
+#endif
+
+ switch(event) {
+
+ case 0: /* Undo Editing */
+ BIF_undo();
+ break;
+ case 1: /* Redo Editing */
+ BIF_redo();
+ break;
+ case 2: /* transform properties */
+ add_blockhandler(curarea, VIEW3D_HANDLER_OBJECT, 0);
+ break;
+ case 4: /* insert keyframe */
+ common_insertkey();
+ break;
+ case 5: /* Extrude */
+ extrude_mesh();
+ break;
+ case 6: /* duplicate */
+ duplicate_context_selected();
+ break;
+ case 7: /* make edge face */
+ addedgeface_mesh();
+ break;
+ case 8: /* delete */
+ delete_context_selected();
+ break;
+ case 9: /* Shrink/Fatten Along Normals */
+ initTransform(TFM_SHRINKFATTEN, CTX_NONE);
+ Transform();
+ break;
+ case 10: /* Shear */
+ initTransform(TFM_SHEAR, CTX_NONE);
+ Transform();
+ break;
+ case 11: /* Warp */
+ initTransform(TFM_WARP, CTX_NONE);
+ Transform();
+ break;
+ case 12: /* proportional edit (toggle) */
+ if(G.scene->proportional) G.scene->proportional= 0;
+ else G.scene->proportional= 1;
+ break;
+ case 13: /* automerge edit (toggle) */
+ if(G.scene->automerge) G.scene->automerge= 0;
+ else G.scene->automerge= 1;
+ break;
+#ifdef WITH_VERSE
+ case 14:
+ if(session_list.first != session_list.last) session = session_menu();
+ else session = session_list.first;
+ if(session) b_verse_push_object(session, G.obedit);
+ break;
+#endif
+ case 15:
+ uv_autocalc_tface();
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_edit_meshmenu(void *arg_unused)
+{
+
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_edit_meshmenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_view3d_edit_meshmenu, NULL);
+
+#ifdef WITH_VERSE
+ if((session_list.first != NULL) && (!G.obedit->vnode)) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Share at Verse Server",
+ 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 14, "");
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+ }
+#endif
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Undo Editing|Ctrl Z", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Redo Editing|Ctrl Shift Z", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBlockBut(block, editmode_undohistorymenu, NULL, ICON_RIGHTARROW_THIN, "Undo History", 0, yco-=20, 120, 19, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_MENU_PANEL, "Transform Properties...|N", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBlockBut(block, view3d_transformmenu, NULL, ICON_RIGHTARROW_THIN, "Transform", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, view3d_edit_mirrormenu, NULL, ICON_RIGHTARROW_THIN, "Mirror", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, view3d_edit_snapmenu, NULL, ICON_RIGHTARROW_THIN, "Snap", 0, yco-=20, 120, 19, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Insert Keyframe|I", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "UV Unwrap|U", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 15, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Extrude|E", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Duplicate|Shift D", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 6, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Make Edge/Face|F", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 7, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Delete...|X", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 8, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBlockBut(block, view3d_edit_mesh_verticesmenu, NULL, ICON_RIGHTARROW_THIN, "Vertices", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, view3d_edit_mesh_edgesmenu, NULL, ICON_RIGHTARROW_THIN, "Edges", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, view3d_edit_mesh_facesmenu, NULL, ICON_RIGHTARROW_THIN, "Faces", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, view3d_edit_mesh_normalsmenu, NULL, ICON_RIGHTARROW_THIN, "Normals", 0, yco-=20, 120, 19, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+
+
+ if(G.scene->proportional) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Proportional Editing|O", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 12, "");
+ } else {
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Proportional Editing|O", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 12, "");
+ }
+ uiDefIconTextBlockBut(block, view3d_edit_propfalloffmenu, NULL, ICON_RIGHTARROW_THIN, "Proportional Falloff", 0, yco-=20, 120, 19, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ if(G.scene->automerge) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "AutoMerge Editing", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 13, "");
+ } else {
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "AutoMerge Editing", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 13, "");
+ }
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBlockBut(block, view3d_edit_mesh_showhidemenu, NULL, ICON_RIGHTARROW_THIN, "Show/Hide Vertices", 0, yco-=20, 120, 19, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBlockBut(block, view3d_edit_mesh_scriptsmenu, NULL, ICON_RIGHTARROW_THIN, "Scripts", 0, yco-=20, 120, 19, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+ return block;
+}
+
+static void do_view3d_edit_curve_controlpointsmenu(void *arg, int event)
+{
+ switch(event) {
+ case 0: /* tilt */
+ initTransform(TFM_TILT, CTX_NONE);
+ Transform();
+ break;
+ case 1: /* clear tilt */
+ clear_tilt();
+ break;
+ case 2: /* Free */
+ sethandlesNurb(3);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ break;
+ case 3: /* vector */
+ sethandlesNurb(2);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ break;
+ case 4: /* smooth */
+ sethandlesNurb(1);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ break;
+ case 5: /* make vertex parent */
+ make_parent();
+ break;
+ case 6: /* add hook */
+ add_hook();
+ break;
+ case 7:
+ separate_nurb();
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_edit_curve_controlpointsmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_edit_curve_controlpointsmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_edit_curve_controlpointsmenu, NULL);
+
+ if (OBACT->type == OB_CURVE) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Tilt|T", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Clear Tilt|Alt T", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Separate|P", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 7, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Automatic|Shift H", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Toggle Free/Aligned|H", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Vector|V", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+ }
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Make Vertex Parent|Ctrl P", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Add Hook|Ctrl H", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 6, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+void do_view3d_edit_curve_segmentsmenu(void *arg, int event)
+{
+ switch(event) {
+ case 0: /* subdivide */
+ subdivideNurb();
+ break;
+ case 1: /* switch direction */
+ switchdirectionNurb2();
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_edit_curve_segmentsmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_edit_curve_segmentsmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_edit_curve_segmentsmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Subdivide", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Switch Direction", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+void do_view3d_edit_curve_showhidemenu(void *arg, int event)
+{
+ switch(event) {
+ case 10: /* show hidden control points */
+ revealNurb();
+ break;
+ case 11: /* hide selected control points */
+ hideNurb(0);
+ break;
+ case 12: /* hide deselected control points */
+ hideNurb(1);
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_edit_curve_showhidemenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_edit_curve_showhidemenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_edit_curve_showhidemenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Show Hidden|Alt H", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 10, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Hide Selected|Alt Ctrl H", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 11, "");
+ if (OBACT->type == OB_SURF) uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Hide Deselected Control Points|Alt Shift H", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 12, "");
+
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+static void do_view3d_edit_curvemenu(void *arg, int event)
+{
+ switch(event) {
+
+ case 0: /* Undo Editing */
+ remake_editNurb();
+ break;
+ case 1: /* transformation properties */
+ mainqenter(NKEY, 1);
+ break;
+ case 2: /* insert keyframe */
+ common_insertkey();
+ break;
+ case 4: /* extrude */
+ if (OBACT->type == OB_CURVE) {
+ addvert_Nurb('e');
+ } else if (OBACT->type == OB_SURF) {
+ extrude_nurb();
+ }
+ break;
+ case 5: /* duplicate */
+ duplicate_context_selected();
+ break;
+ case 6: /* make segment */
+ addsegment_nurb();
+ break;
+ case 7: /* toggle cyclic */
+ makecyclicNurb();
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ break;
+ case 8: /* delete */
+ delete_context_selected();
+ break;
+ case 9: /* proportional edit (toggle) */
+ if(G.scene->proportional) G.scene->proportional= 0;
+ else G.scene->proportional= 1;
+ break;
+ case 13: /* Shear */
+ initTransform(TFM_SHEAR, CTX_NONE);
+ Transform();
+ break;
+ case 14: /* Warp */
+ initTransform(TFM_WARP, CTX_NONE);
+ Transform();
+ break;
+ case 15:
+ uv_autocalc_tface();
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_edit_curvemenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_edit_curvemenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_view3d_edit_curvemenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Reload Original|U", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_MENU_PANEL, "Transform Properties...|N", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBlockBut(block, view3d_transformmenu, NULL, ICON_RIGHTARROW_THIN, "Transform", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, view3d_edit_mirrormenu, NULL, ICON_RIGHTARROW_THIN, "Mirror", 0, yco-=20, menuwidth, 19, "");
+ uiDefIconTextBlockBut(block, view3d_edit_snapmenu, NULL, ICON_RIGHTARROW_THIN, "Snap", 0, yco-=20, 120, 19, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Insert Keyframe|I", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "UV Unwrap|U", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 15, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Extrude|E", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Duplicate|Shift D", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Make Segment|F", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 6, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Toggle Cyclic|C", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 7, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Delete...|X", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 8, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBlockBut(block, view3d_edit_curve_controlpointsmenu, NULL, ICON_RIGHTARROW_THIN, "Control Points", 0, yco-=20, menuwidth, 19, "");
+ uiDefIconTextBlockBut(block, view3d_edit_curve_segmentsmenu, NULL, ICON_RIGHTARROW_THIN, "Segments", 0, yco-=20, menuwidth, 19, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ if(G.scene->proportional) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Proportional Editing|O", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 9, "");
+ } else {
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Proportional Editing|O", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 9, "");
+ }
+ uiDefIconTextBlockBut(block, view3d_edit_propfalloffmenu, NULL, ICON_RIGHTARROW_THIN, "Proportional Falloff", 0, yco-=20, menuwidth, 19, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBlockBut(block, view3d_edit_curve_showhidemenu, NULL, ICON_RIGHTARROW_THIN, "Show/Hide Control Points", 0, yco-=20, menuwidth, 19, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+ return block;
+}
+
+static void do_view3d_edit_mball_showhidemenu(void *arg, int event)
+{
+ switch(event) {
+ case 10: /* show hidden control points */
+ reveal_mball();
+ break;
+ case 11: /* hide selected control points */
+ hide_mball(0);
+ break;
+ case 12: /* hide deselected control points */
+ hide_mball(1);
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_edit_mball_showhidemenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_edit_mball_showhidemenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_edit_mball_showhidemenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Show Hidden|Alt H", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 10, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Hide Selected|H", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 11, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Hide Deselected|Shift H", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 12, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+static void do_view3d_edit_metaballmenu(void *arg, int event)
+{
+ switch(event) {
+ case 1: /* undo */
+ BIF_undo();
+ break;
+ case 2: /* redo */
+ BIF_redo();
+ break;
+ case 3: /* duplicate */
+ duplicate_context_selected();
+ break;
+ case 4: /* delete */
+ delete_context_selected();
+ break;
+ case 5: /* Shear */
+ initTransform(TFM_SHEAR, CTX_NONE);
+ Transform();
+ break;
+ case 6: /* Warp */
+ initTransform(TFM_WARP, CTX_NONE);
+ Transform();
+ break;
+ case 7: /* Transform Properties */
+ add_blockhandler(curarea, VIEW3D_HANDLER_OBJECT, 0);
+ break;
+ case 8:
+ uv_autocalc_tface();
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_edit_metaballmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_edit_metaballmenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_view3d_edit_metaballmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Undo Editing|Ctrl Z", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Redo Editing|Shift Ctrl Z", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBlockBut(block, editmode_undohistorymenu, NULL, ICON_RIGHTARROW_THIN, "Undo History", 0, yco-=20, 120, 19, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_MENU_PANEL, "Transform Properties|N",0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 7, "");
+ uiDefIconTextBlockBut(block, view3d_transformmenu, NULL, ICON_RIGHTARROW_THIN, "Transform", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, view3d_edit_mirrormenu, NULL, ICON_RIGHTARROW_THIN, "Mirror", 0, yco-=20, menuwidth, 19, "");
+ uiDefIconTextBlockBut(block, view3d_edit_snapmenu, NULL, ICON_RIGHTARROW_THIN, "Snap", 0, yco-=20, 120, 19, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "UV Unwrap|U", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 8, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Duplicate|Shift D", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Delete...|X", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBlockBut(block, view3d_edit_mball_showhidemenu, NULL, ICON_RIGHTARROW_THIN, "Hide MetaElems", 0, yco-=20, 120, 19, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+ return block;
+}
+
+static void do_view3d_edit_text_charsmenu(void *arg, int event)
+{
+ switch(event) {
+ case 0: /* copyright */
+ do_textedit(0,0,169);
+ break;
+ case 1: /* registered trademark */
+ do_textedit(0,0,174);
+ break;
+ case 2: /* degree sign */
+ do_textedit(0,0,176);
+ break;
+ case 3: /* Multiplication Sign */
+ do_textedit(0,0,215);
+ break;
+ case 4: /* Circle */
+ do_textedit(0,0,138);
+ break;
+ case 5: /* superscript 1 */
+ do_textedit(0,0,185);
+ break;
+ case 6: /* superscript 2 */
+ do_textedit(0,0,178);
+ break;
+ case 7: /* superscript 3 */
+ do_textedit(0,0,179);
+ break;
+ case 8: /* double >> */
+ do_textedit(0,0,187);
+ break;
+ case 9: /* double << */
+ do_textedit(0,0,171);
+ break;
+ case 10: /* Promillage */
+ do_textedit(0,0,139);
+ break;
+ case 11: /* dutch florin */
+ do_textedit(0,0,164);
+ break;
+ case 12: /* british pound */
+ do_textedit(0,0,163);
+ break;
+ case 13: /* japanese yen*/
+ do_textedit(0,0,165);
+ break;
+ case 14: /* german S */
+ do_textedit(0,0,223);
+ break;
+ case 15: /* spanish question mark */
+ do_textedit(0,0,191);
+ break;
+ case 16: /* spanish exclamation mark */
+ do_textedit(0,0,161);
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_edit_text_charsmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_edit_text_charsmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_edit_text_charsmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Copyright|Alt C", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Registered Trademark|Alt R", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Degree Sign|Alt G", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Multiplication Sign|Alt x", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Circle|Alt .", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Superscript 1|Alt 1", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Superscript 2|Alt 2", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 6, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Superscript 3|Alt 3", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 7, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Double >>|Alt >", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 8, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Double <<|Alt <", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 9, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Promillage|Alt %", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 10, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Dutch Florin|Alt F", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 11, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "British Pound|Alt L", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 12, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Japanese Yen|Alt Y", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 13, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "German S|Alt S", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 14, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Spanish Question Mark|Alt ?", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 15, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Spanish Exclamation Mark|Alt !", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 16, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+
+ return block;
+}
+
+static void do_view3d_edit_textmenu(void *arg, int event)
+{
+ switch(event) {
+
+ case 0: /* Undo Editing */
+ remake_editText();
+ break;
+ case 1: /* paste from file buffer */
+ paste_editText();
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_edit_textmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_edit_textmenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_view3d_edit_textmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Undo Editing|U", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Paste From Buffer File|Alt V", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBlockBut(block, view3d_edit_text_charsmenu, NULL, ICON_RIGHTARROW_THIN, "Special Characters", 0, yco-=20, 120, 19, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+ return block;
+}
+
+static void do_view3d_edit_latticemenu(void *arg, int event)
+{
+ switch(event) {
+
+ case 0: /* Undo Editing */
+ remake_editLatt();
+ break;
+ case 2: /* insert keyframe */
+ common_insertkey();
+ break;
+ case 3: /* Shear */
+ initTransform(TFM_SHEAR, CTX_NONE);
+ Transform();
+ break;
+ case 4: /* Warp */
+ initTransform(TFM_WARP, CTX_NONE);
+ Transform();
+ break;
+ case 5: /* proportional edit (toggle) */
+ if(G.scene->proportional) G.scene->proportional= 0;
+ else G.scene->proportional= 1;
+ break;
+ case 6:
+ uv_autocalc_tface();
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_edit_latticemenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_edit_latticemenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_view3d_edit_latticemenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Undo Editing|U", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBlockBut(block, view3d_transformmenu, NULL, ICON_RIGHTARROW_THIN, "Transform", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, view3d_edit_mirrormenu, NULL, ICON_RIGHTARROW_THIN, "Mirror", 0, yco-=20, menuwidth, 19, "");
+ uiDefIconTextBlockBut(block, view3d_edit_snapmenu, NULL, ICON_RIGHTARROW_THIN, "Snap", 0, yco-=20, 120, 19, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Insert Keyframe|I", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "UV Unwrap|U", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 6, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ if(G.scene->proportional) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_HLT, "Proportional Editing|O", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+ } else {
+ uiDefIconTextBut(block, BUTM, 1, ICON_CHECKBOX_DEHLT, "Proportional Editing|O", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+ }
+ uiDefIconTextBlockBut(block, view3d_edit_propfalloffmenu, NULL, ICON_RIGHTARROW_THIN, "Proportional Falloff", 0, yco-=20, 120, 19, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+ return block;
+}
+
+void do_view3d_edit_armature_parentmenu(void *arg, int event)
+{
+ switch(event) {
+ case 1:
+ make_bone_parent();
+ break;
+ case 2:
+ clear_bone_parent();
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_edit_armature_parentmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_edit_armature_parentmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_edit_armature_parentmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Make Parent...|Ctrl P", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Clear Parent...|Alt P", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+void do_view3d_edit_armature_rollmenu(void *arg, int event)
+{
+ if (event == 1 || event == 2)
+ /* set roll based on aligning z-axis */
+ auto_align_armature(event);
+ else if (event == 3) {
+ /* interactively set bone roll */
+ initTransform(TFM_BONE_ROLL, CTX_NONE);
+ Transform();
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_edit_armature_rollmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_edit_armature_rollmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_edit_armature_rollmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Clear Roll (Z-Axis Up)|Ctrl N, 1", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Roll to Cursor|Ctrl N, 2", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Set Roll|Ctrl R", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+static void do_view3d_edit_armaturemenu(void *arg, int event)
+{
+ static short numcuts= 2;
+
+ switch(event) {
+
+ case 0: /* Undo Editing */
+ remake_editArmature();
+ break;
+ case 1: /* transformation properties */
+ mainqenter(NKEY, 1);
+ break;
+ case 3: /* extrude */
+ extrude_armature(0);
+ break;
+ case 4: /* duplicate */
+ duplicate_context_selected();
+ break;
+ case 5: /* delete */
+ delete_context_selected();
+ break;
+ case 6: /* Shear */
+ initTransform(TFM_SHEAR, CTX_NONE);
+ Transform();
+ break;
+ case 7: /* Warp */
+ initTransform(TFM_WARP, CTX_NONE);
+ Transform();
+ case 10: /* forked! */
+ extrude_armature(1);
+ break;
+ case 12: /* subdivide */
+ subdivide_armature(1);
+ break;
+ case 13: /* flip left and right names */
+ armature_flip_names();
+ break;
+ case 15: /* subdivide multi */
+ if(button(&numcuts, 1, 128, "Number of Cuts:")==0) return;
+ waitcursor(1);
+ subdivide_armature(numcuts);
+ break;
+ case 16: /* Alt-S transform (BoneSize) */
+ initTransform(TFM_BONESIZE, CTX_NONE);
+ Transform();
+ break;
+ case 17: /* move to layer */
+ pose_movetolayer();
+ break;
+ case 18:
+ uv_autocalc_tface();
+ break;
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+
+
+static void do_view3d_scripts_armaturemenu(void *arg, int event)
+{
+ BPY_menu_do_python(PYMENU_SCRIPTTEMPLATE, event);
+
+ allqueue(REDRAWIMAGE, 0);
+}
+
+static uiBlock *view3d_scripts_armaturemenu(void *args_unused)
+{
+ uiBlock *block;
+ BPyMenu *pym;
+ int i= 0;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_scripts_armaturemenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_scripts_armaturemenu, NULL);
+
+ /* note that we acount for the N previous entries with i+20: */
+ for (pym = BPyMenuTable[PYMENU_ARMATURE]; pym; pym = pym->next, i++) {
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_PYTHON, pym->name, 0, yco-=20, menuwidth, 19,
+ NULL, 0.0, 0.0, 1, i,
+ pym->tooltip?pym->tooltip:pym->filename);
+ }
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+
+ return block;
+}
+
+
+static uiBlock *view3d_edit_armaturemenu(void *arg_unused)
+{
+ bArmature *arm= G.obedit->data;
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_edit_armaturemenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_view3d_edit_armaturemenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Undo Editing|U", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_MENU_PANEL, "Transform Properties|N", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBlockBut(block, view3d_transformmenu, NULL, ICON_RIGHTARROW_THIN, "Transform", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, view3d_edit_mirrormenu, NULL, ICON_RIGHTARROW_THIN, "Mirror", 0, yco-=20, menuwidth, 19, "");
+ uiDefIconTextBlockBut(block, view3d_edit_snapmenu, NULL, ICON_RIGHTARROW_THIN, "Snap", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, view3d_edit_armature_rollmenu, NULL, ICON_RIGHTARROW_THIN, "Bone Roll", 0, yco-=20, 120, 19, "");
+
+ if (arm->drawtype==ARM_ENVELOPE)
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Scale Envelope Distance|Alt S", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 16, "");
+ else if (arm->drawtype==ARM_B_BONE)
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Scale B-Bone Width|Alt S", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 16, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Extrude|E", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+ if(arm->flag & ARM_MIRROR_EDIT)
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Extrude Forked|Shift E", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 10, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Duplicate|Shift D", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Delete|X", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Subdivide|W, 1", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 12, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Subdivide Multi|W, 2", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 15, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Flip Left & Right Names|W, 3", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 13, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Switch Armature Layers|Shift M", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 17, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Move Bone To Layer|M", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 17, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "UV Unwrap|U", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 18, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBlockBut(block, view3d_edit_armature_parentmenu, NULL, ICON_RIGHTARROW_THIN, "Parent", 0, yco-=20, 120, 19, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBlockBut(block, view3d_scripts_armaturemenu, NULL, ICON_RIGHTARROW_THIN, "Scripts", 0, yco-=20, 120, 19, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+static void do_view3d_pose_armature_transformmenu(void *arg, int event)
+{
+ Object *ob= OBACT;
+
+ switch(event) {
+ case 0: /* clear origin */
+ clear_object('o');
+ break;
+ case 1: /* clear scale */
+ clear_object('s');
+ break;
+ case 2: /* clear rotation */
+ clear_object('r');
+ break;
+ case 3: /* clear location */
+ clear_object('g');
+ break;
+ case 4: /* clear user transform */
+ rest_pose(ob->pose);
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ BIF_undo_push("Pose, Clear User Transform");
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_pose_armature_transformmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_pose_armature_transformmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_pose_armature_transformmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Clear User Transform|W", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Clear Location|Alt G", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Clear Rotation|Alt R", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Clear Scale|Alt S", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Clear Origin|Alt O", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+static void do_view3d_pose_armature_showhidemenu(void *arg, int event)
+{
+
+ switch(event) {
+
+ case 0: /* show hidden bones */
+ show_all_pose_bones();
+ break;
+ case 1: /* hide selected bones */
+ hide_selected_pose_bones();
+ break;
+ case 2: /* hide deselected bones */
+ hide_unselected_pose_bones();
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_pose_armature_showhidemenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_pose_armature_showhidemenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_pose_armature_showhidemenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Show Hidden|Alt H", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Hide Selected|H", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Hide Deselected|Shift H", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+static void do_view3d_pose_armature_ikmenu(void *arg, int event)
+{
+
+ switch(event) {
+
+ case 1:
+ pose_add_IK();
+ break;
+ case 2:
+ pose_clear_IK();
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_pose_armature_ikmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_pose_armature_ikmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_pose_armature_ikmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Add IK to Bone...|Ctrl I", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Clear IK...|Alt I", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+static void do_view3d_pose_armature_constraintsmenu(void *arg, int event)
+{
+
+ switch(event) {
+
+ case 1:
+ add_constraint(0);
+ break;
+ case 2:
+ pose_clear_constraints();
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_pose_armature_constraintsmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_pose_armature_constraintsmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_pose_armature_constraintsmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Add Constraint to Bone...|Ctrl Alt C", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Clear Constraints...|Alt C", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+static void do_view3d_pose_armature_motionpathsmenu(void *arg, int event)
+{
+
+ switch(event) {
+
+ case 1:
+ pose_calculate_path(OBACT);
+ break;
+ case 2:
+ pose_clear_paths(OBACT);
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_pose_armature_motionpathsmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_pose_armature_motionpathsmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_pose_armature_motionpathsmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Calculate Paths|W", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Clear All Paths|W", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+static void do_view3d_pose_armaturemenu(void *arg, int event)
+{
+ Object *ob;
+ ob=OBACT;
+
+ switch(event) {
+
+ case 0: /* transform properties */
+ mainqenter(NKEY, 1);
+ break;
+ case 1: /* copy current pose */
+ copy_posebuf();
+ break;
+ case 2: /* paste pose */
+ paste_posebuf(0);
+ break;
+ case 3: /* paste flipped pose */
+ paste_posebuf(1);
+ break;
+ case 4: /* insert keyframe */
+ common_insertkey();
+ break;
+ case 5:
+ pose_copy_menu();
+ break;
+ case 9:
+ pose_flip_names();
+ break;
+ case 13:
+ if(ob && (ob->flag & OB_POSEMODE)) {
+ bArmature *arm= ob->data;
+ if( (arm->drawtype == ARM_B_BONE) || (arm->drawtype == ARM_ENVELOPE)) {
+ initTransform(TFM_BONESIZE, CTX_NONE);
+ Transform();
+ break;
+ }
+ }
+ break;
+ case 14: /* move bone to layer / change armature layer */
+ pose_movetolayer();
+ break;
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_pose_armaturemenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_pose_armaturemenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_view3d_pose_armaturemenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_MENU_PANEL, "Transform Properties|N", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefIconTextBlockBut(block, view3d_transformmenu, NULL, ICON_RIGHTARROW_THIN, "Transform", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, view3d_pose_armature_transformmenu, NULL, ICON_RIGHTARROW_THIN, "Clear Transform", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Scale Envelope Distance|Alt S", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 13, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Insert Keyframe|I", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Copy Current Pose", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Paste Pose", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Paste Flipped Pose", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBlockBut(block, view3d_pose_armature_motionpathsmenu, NULL, ICON_RIGHTARROW_THIN, "Motion Paths", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, view3d_pose_armature_ikmenu, NULL, ICON_RIGHTARROW_THIN, "Inverse Kinematics", 0, yco-=20, 120, 19, "");
+ uiDefIconTextBlockBut(block, view3d_pose_armature_constraintsmenu, NULL, ICON_RIGHTARROW_THIN, "Constraints", 0, yco-=20, 120, 19, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Flip L/R Names|W", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 9, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Copy Attributes...|Ctrl C", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Switch Armature Layers|Shift M", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 14, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Move Bone To Layer|M", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 14, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBlockBut(block, view3d_pose_armature_showhidemenu,
+ NULL, ICON_RIGHTARROW_THIN, "Show/Hide Bones", 0, yco-=20, 120, 19, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+/* vertex paint menu */
+static void do_view3d_vpaintmenu(void *arg, int event)
+{
+ /* events >= 2 are registered bpython scripts */
+ if (event >= 2) BPY_menu_do_python(PYMENU_VERTEXPAINT, event - 2);
+
+ switch(event) {
+ case 0: /* undo vertex painting */
+ BIF_undo();
+ break;
+ case 1: /* set vertex colors/weight */
+ if(FACESEL_PAINT_TEST)
+ clear_vpaint_selectedfaces();
+ else /* we know were in vertex paint mode */
+ clear_vpaint();
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_vpaintmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+ BPyMenu *pym;
+ int i=0;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_paintmenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_view3d_vpaintmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Undo Vertex Painting|U", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Set Vertex Colors|Shift K", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+
+ /* note that we account for the 2 previous entries with i+2:
+ even if the last item isnt displayed, it dosent matter */
+ for (pym = BPyMenuTable[PYMENU_VERTEXPAINT]; pym; pym = pym->next, i++) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_PYTHON, pym->name, 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, i+2,
+ pym->tooltip?pym->tooltip:pym->filename);
+ }
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+ return block;
+}
+
+
+/* texture paint menu (placeholder, no items yet??) */
+static void do_view3d_tpaintmenu(void *arg, int event)
+{
+ switch(event) {
+ case 0: /* undo image painting */
+ imagepaint_undo();
+ break;
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_tpaintmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_paintmenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_view3d_tpaintmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Undo Texture Painting|U", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+ return block;
+}
+
+
+static void do_view3d_wpaintmenu(void *arg, int event)
+{
+ Object *ob= OBACT;
+
+ /* events >= 3 are registered bpython scripts */
+ if (event >= 4) BPY_menu_do_python(PYMENU_WEIGHTPAINT, event - 4);
+
+ switch(event) {
+ case 0: /* undo weight painting */
+ BIF_undo();
+ break;
+ case 1: /* set vertex colors/weight */
+ clear_wpaint_selectedfaces();
+ break;
+ case 2: /* vgroups from envelopes */
+ pose_adds_vgroups(ob, 0);
+ break;
+ case 3: /* vgroups from bone heat */
+ pose_adds_vgroups(ob, 1);
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_wpaintmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120, menunr=1;
+ BPyMenu *pym;
+ int i=0;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_paintmenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_view3d_wpaintmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Undo Weight Painting|U", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Apply Bone Heat Weights to Vertex Groups|W, 2", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Apply Bone Envelopes to Vertex Groups|W, 1", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ if (FACESEL_PAINT_TEST) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Set Weight|Shift K", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+ menunr++;
+ }
+
+ /* note that we account for the 4 previous entries with i+4:
+ even if the last item isnt displayed, it dosent matter */
+ for (pym = BPyMenuTable[PYMENU_WEIGHTPAINT]; pym; pym = pym->next, i++) {
+ uiDefIconTextBut(block, BUTM, 1, ICON_PYTHON, pym->name, 0, yco-=20,
+ menuwidth, 19, NULL, 0.0, 0.0, 1, i+4,
+ pym->tooltip?pym->tooltip:pym->filename);
+ }
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+ return block;
+}
+
+void do_view3d_sculpt_inputmenu(void *arg, int event)
+{
+ SculptData *sd= &G.scene->sculptdata;
+ short val;
+
+ switch(event) {
+ case 0:
+ sd->flags ^= SCULPT_INPUT_SMOOTH;
+ break;
+ case 1:
+ val= sd->tablet_size;
+ if(button(&val,0,10,"Tablet Size:")==0) return;
+ sd->tablet_size= val;
+ break;
+ case 2:
+ val= sd->tablet_strength;
+ if(button(&val,0,10,"Tablet Strength:")==0) return;
+ sd->tablet_strength= val;
+ break;
+ }
+
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+void do_view3d_sculptmenu(void *arg, int event)
+{
+ SculptData *sd= &G.scene->sculptdata;
+ BrushData *br= sculptmode_brush();
+ switch(event) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ sd->brush_type= event+1;
+ break;
+ case 7:
+ br->airbrush= !br->airbrush; break;
+ case 8:
+ sd->symm ^= SYMM_X; break;
+ case 9:
+ sd->symm ^= SYMM_Y; break;
+ case 10:
+ sd->symm ^= SYMM_Z; break;
+ case 11:
+ if(G.vd)
+ G.vd->pivot_last= !G.vd->pivot_last;
+ break;
+ case 12:
+ sd->flags ^= SCULPT_DRAW_FAST;
+ break;
+ case 13:
+ sd->flags ^= SCULPT_DRAW_BRUSH;
+ break;
+ case 14:
+ add_blockhandler(curarea, VIEW3D_HANDLER_OBJECT, UI_PNL_UNSTOW);
+ break;
+ case 15:
+ sculptmode_propset_init(PropsetTexRot);
+ break;
+ case 16:
+ sculptmode_propset_init(PropsetStrength);
+ break;
+ case 17:
+ sculptmode_propset_init(PropsetSize);
+ break;
+ case 18:
+ br->dir= br->dir==1 ? 2 : 1; break;
+ }
+
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+uiBlock *view3d_sculpt_inputmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth= 120;
+ SculptData *sd= &G.scene->sculptdata;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_sculpt_inputmenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_sculpt_inputmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ((sd->flags & SCULPT_INPUT_SMOOTH) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT), "Smooth Stroke", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Tablet Size Adjust", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Tablet Strength Adjust", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 50);
+ return block;
+}
+
+uiBlock *view3d_sculptmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth= 120;
+ SculptData *sd= &G.scene->sculptdata;
+ const BrushData *br= sculptmode_brush();
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_sculptmenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_view3d_sculptmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_MENU_PANEL, "Sculpt Properties|N", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 14, "");
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBlockBut(block, view3d_sculpt_inputmenu, NULL, ICON_RIGHTARROW_THIN, "Input Settings", 0, yco-=20, 120, 19, "");
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, ((sd->flags & SCULPT_DRAW_BRUSH) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT), "Display Brush", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 13, "");
+ uiDefIconTextBut(block, BUTM, 1, ((sd->flags & SCULPT_DRAW_FAST) ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT), "Partial Redraw", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 12, "");
+ if(G.vd)
+ uiDefIconTextBut(block, BUTM, 1, (G.vd->pivot_last ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT), "Pivot Last", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 11, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Scale Brush|F", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 17, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Strengthen Brush|Shift F", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 16, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Rotate Brush|Ctrl F", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 15, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, (sd->symm & SYMM_Z ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT), "Z Symmetry|Z", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 10, "");
+ uiDefIconTextBut(block, BUTM, 1, (sd->symm & SYMM_Y ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT), "Y Symmetry|Y", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 9, "");
+ uiDefIconTextBut(block, BUTM, 1, (sd->symm & SYMM_X ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT), "X Symmetry|X", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 8, "");
+
+ if(sd->brush_type!=GRAB_BRUSH) {
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, (br->airbrush ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT), "Airbrush|A", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 7, "");
+
+ if(sd->brush_type!=SMOOTH_BRUSH && sd->brush_type!=FLATTEN_BRUSH) {
+ uiDefIconTextBut(block, BUTM, 1, (br->dir==1 ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT), "Add|V", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 18, "");
+ }
+ }
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+ uiDefIconTextBut(block, BUTM, 1, (sd->brush_type==FLATTEN_BRUSH ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT), "Flatten|T", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 6, "");
+ uiDefIconTextBut(block, BUTM, 1, (sd->brush_type==LAYER_BRUSH ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT), "Layer|L", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+ uiDefIconTextBut(block, BUTM, 1, (sd->brush_type==GRAB_BRUSH ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT), "Grab|G", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+ uiDefIconTextBut(block, BUTM, 1, (sd->brush_type==INFLATE_BRUSH ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT), "Inflate|I", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+ uiDefIconTextBut(block, BUTM, 1, (sd->brush_type==PINCH_BRUSH ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT), "Pinch|P", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, (sd->brush_type==SMOOTH_BRUSH ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT), "Smooth|S", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+ uiDefIconTextBut(block, BUTM, 1, (sd->brush_type==DRAW_BRUSH ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT), "Draw|D", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+
+ return block;
+}
+
+static void do_view3d_facesel_showhidemenu(void *arg, int event)
+{
+ switch(event) {
+ case 4: /* show hidden faces */
+ reveal_tface();
+ break;
+ case 5: /* hide selected faces */
+ hide_tface();
+ break;
+ case 6: /* hide deselected faces */
+ G.qual |= LR_SHIFTKEY;
+ hide_tface();
+ G.qual &= ~LR_SHIFTKEY;
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static uiBlock *view3d_facesel_showhidemenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco = 20, menuwidth = 120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_facesel_showhidemenu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetButmFunc(block, do_view3d_facesel_showhidemenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Show Hidden Faces|Alt H", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Hide Selected Faces|H", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Hide Deselected Faces|Shift H", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 6, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 60);
+ return block;
+}
+
+static void do_view3d_faceselmenu(void *arg, int event)
+{
+ switch(event) {
+ case 0: /* set vertex colors */
+ clear_vpaint_selectedfaces();
+ break;
+ case 1: /* mark border seam */
+ seam_mark_clear_tface(1);
+ break;
+ case 2: /* clear seam */
+ seam_mark_clear_tface(2);
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWIMAGE, 0);
+}
+
+static uiBlock *view3d_faceselmenu(void *arg_unused)
+{
+ uiBlock *block;
+ short yco= 0, menuwidth=120;
+
+ block= uiNewBlock(&curarea->uiblocks, "view3d_faceselmenu", UI_EMBOSSP, UI_HELV, curarea->headwin);
+ uiBlockSetButmFunc(block, do_view3d_faceselmenu, NULL);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Set Vertex Colors|Shift K", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Clear Seam|Ctrl E", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Mark Border Seam|Ctrl E", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBlockBut(block, view3d_facesel_showhidemenu, NULL, ICON_RIGHTARROW_THIN, "Show/Hide Faces", 0, yco-=20, 120, 19, "");
+
+ if(curarea->headertype==HEADERTOP) {
+ uiBlockSetDirection(block, UI_DOWN);
+ }
+ else {
+ uiBlockSetDirection(block, UI_TOP);
+ uiBlockFlipOrder(block);
+ }
+
+ uiTextBoundsBlock(block, 50);
+ return block;
+}
+
+
+static char *view3d_modeselect_pup(void)
+{
+ Object *ob= OBACT;
+ static char string[1024];
+ static char formatstr[] = "|%s %%x%d %%i%d";
+ char *str = string;
+
+ str += sprintf(str, "Mode: %%t");
+
+ str += sprintf(str, formatstr, "Object Mode", V3D_OBJECTMODE_SEL, ICON_OBJECT);
+
+ if(ob==NULL) return string;
+
+ /* if active object is editable */
+ if ( ((ob->type == OB_MESH) || (ob->type == OB_ARMATURE)
+ || (ob->type == OB_CURVE) || (ob->type == OB_SURF) || (ob->type == OB_FONT)
+ || (ob->type == OB_MBALL) || (ob->type == OB_LATTICE))) {
+
+ str += sprintf(str, formatstr, "Edit Mode", V3D_EDITMODE_SEL, ICON_EDITMODE_HLT);
+ }
+
+ if (ob->type == OB_MESH) {
+
+ str += sprintf(str, formatstr, "Sculpt Mode", V3D_SCULPTMODE_SEL, ICON_SCULPTMODE_HLT);
+ /*str += sprintf(str, formatstr, "Face Select", V3D_FACESELECTMODE_SEL, ICON_FACESEL_HLT);*/
+ str += sprintf(str, formatstr, "Vertex Paint", V3D_VERTEXPAINTMODE_SEL, ICON_VPAINT_HLT);
+ str += sprintf(str, formatstr, "Texture Paint", V3D_TEXTUREPAINTMODE_SEL, ICON_TPAINT_HLT);
+ str += sprintf(str, formatstr, "Weight Paint", V3D_WEIGHTPAINTMODE_SEL, ICON_WPAINT_HLT);
+ }
+
+
+ /* if active object is an armature */
+ if (ob->type==OB_ARMATURE) {
+ str += sprintf(str, formatstr, "Pose Mode", V3D_POSEMODE_SEL, ICON_POSE_HLT);
+ }
+
+ return (string);
+}
+
+
+static char *drawtype_pup(void)
+{
+ static char string[512];
+ char *str = string;
+
+ str += sprintf(str, "%s", "Draw type: %t");
+ str += sprintf(str, "%s", "|Bounding Box %x1");
+ str += sprintf(str, "%s", "|Wireframe %x2");
+ str += sprintf(str, "%s", "|Solid %x3");
+ str += sprintf(str, "%s", "|Shaded %x4");
+ str += sprintf(str, "%s", "|Textured %x5");
+ return string;
+}
+static char *around_pup(void)
+{
+ static char string[512];
+ char *str = string;
+
+ str += sprintf(str, "%s", "Pivot: %t");
+ str += sprintf(str, "%s", "|Bounding Box Center %x0");
+ str += sprintf(str, "%s", "|Median Point %x3");
+ str += sprintf(str, "%s", "|3D Cursor %x1");
+ str += sprintf(str, "%s", "|Individual Centers %x2");
+ if ((G.obedit) && (G.obedit->type == OB_MESH))
+ str += sprintf(str, "%s", "|Active Vert/Edge/Face %x4");
+ else
+ str += sprintf(str, "%s", "|Active Object %x4");
+ return string;
+}
+
+static char *propfalloff_pup(void)
+{
+ static char string[512];
+ char *str = string;
+
+ str += sprintf(str, "%s", "Falloff: %t");
+ str += sprintf(str, "%s", "|Smooth Falloff%x0");
+ str += sprintf(str, "%s", "|Sphere Falloff%x1");
+ str += sprintf(str, "%s", "|Root Falloff%x2");
+ str += sprintf(str, "%s", "|Sharp Falloff%x3");
+ str += sprintf(str, "%s", "|Linear Falloff%x4");
+ str += sprintf(str, "%s", "|Random Falloff%x6");
+ str += sprintf(str, "%s", "|Constant, No Falloff%x5");
+ return string;
+}
+
+
+void do_view3d_buttons(short event)
+{
+ Object *ob= OBACT;
+ int bit;
+
+ /* watch it: if curarea->win does not exist, check that when calling direct drawing routines */
+
+ switch(event) {
+ case B_HOME:
+ view3d_home(0);
+ break;
+ case B_SCENELOCK:
+ if(G.vd->scenelock) {
+ G.vd->lay= G.scene->lay;
+ /* seek for layact */
+ bit= 0;
+ while(bit<32) {
+ if(G.vd->lay & (1<<bit)) {
+ G.vd->layact= 1<<bit;
+ break;
+ }
+ bit++;
+ }
+ G.vd->camera= G.scene->camera;
+ scrarea_queue_winredraw(curarea);
+ scrarea_queue_headredraw(curarea);
+ }
+ break;
+
+ case B_LOCALVIEW:
+ if(G.vd->localview) initlocalview();
+ else {
+ endlocalview(curarea);
+ /* new layers might need unflushed events events */
+ DAG_scene_update_flags(G.scene, G.vd->lay); /* tags all that moves and flushes*/
+ }
+ scrarea_queue_headredraw(curarea);
+ break;
+
+ case B_VIEWBUT:
+
+ if(G.vd->viewbut==1) persptoetsen(PAD7);
+ else if(G.vd->viewbut==2) persptoetsen(PAD1);
+ else if(G.vd->viewbut==3) persptoetsen(PAD3);
+ break;
+
+ case B_PERSP:
+
+ if(G.vd->persp==2) persptoetsen(PAD0);
+ else {
+ G.vd->persp= 1-G.vd->persp;
+ persptoetsen(PAD5);
+ }
+
+ break;
+ case B_PROPTOOL:
+ allqueue(REDRAWHEADERS, 0);
+ break;
+ case B_VIEWRENDER:
+ if (curarea->spacetype==SPACE_VIEW3D) {
+ BIF_do_ogl_render(curarea->spacedata.first, G.qual!=0 );
+ }
+ break;
+ case B_STARTGAME:
+ if (select_area(SPACE_VIEW3D)) {
+ start_game();
+ }
+ break;
+ case B_MODESELECT:
+ if (G.vd->modeselect == V3D_OBJECTMODE_SEL) {
+
+ G.vd->flag &= ~V3D_MODE;
+ if(G.f & G_SCULPTMODE) set_sculptmode(); /* Switch off sculptmode */
+ if(G.f & G_VERTEXPAINT) set_vpaint(); /* Switch off vertex paint */
+ if(G.f & G_TEXTUREPAINT) set_texturepaint(); /* Switch off tex paint */
+ if(G.f & G_WEIGHTPAINT) set_wpaint(); /* Switch off weight paint */
+ if(ob) exit_posemode(); /* exit posemode for active object */
+ if(G.obedit) exit_editmode(EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR); /* exit editmode and undo */
+ }
+ else if (G.vd->modeselect == V3D_EDITMODE_SEL) {
+ if(!G.obedit) {
+ G.vd->flag &= ~V3D_MODE;
+ if(G.f & G_SCULPTMODE) set_sculptmode(); /* Switch off sculptmode */
+ if(G.f & G_VERTEXPAINT) set_vpaint(); /* Switch off vertex paint */
+ if(G.f & G_TEXTUREPAINT) set_texturepaint(); /* Switch off tex paint */
+ if(G.f & G_WEIGHTPAINT) set_wpaint(); /* Switch off weight paint */
+
+ enter_editmode(EM_WAITCURSOR);
+ BIF_undo_push("Original"); /* here, because all over code enter_editmode is abused */
+ }
+ }
+ else if (G.vd->modeselect == V3D_SCULPTMODE_SEL) {
+ if (!(G.f & G_SCULPTMODE)) {
+ G.vd->flag &= ~V3D_MODE;
+ if(G.f & G_VERTEXPAINT) set_vpaint(); /* Switch off vertex paint */
+ if(G.f & G_TEXTUREPAINT) set_texturepaint(); /* Switch off tex paint */
+ if(G.f & G_WEIGHTPAINT) set_wpaint(); /* Switch off weight paint */
+ if(G.obedit) exit_editmode(2); /* exit editmode and undo */
+
+ set_sculptmode();
+ }
+ }
+ else if (G.vd->modeselect == V3D_VERTEXPAINTMODE_SEL) {
+ if (!(G.f & G_VERTEXPAINT)) {
+ G.vd->flag &= ~V3D_MODE;
+ if(G.f & G_SCULPTMODE) set_sculptmode(); /* Switch off sculptmode */
+ if(G.f & G_TEXTUREPAINT) set_texturepaint(); /* Switch off tex paint */
+ if(G.f & G_WEIGHTPAINT) set_wpaint(); /* Switch off weight paint */
+ if(G.obedit) exit_editmode(EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR); /* exit editmode and undo */
+
+ set_vpaint();
+ }
+ }
+ else if (G.vd->modeselect == V3D_TEXTUREPAINTMODE_SEL) {
+ if (!(G.f & G_TEXTUREPAINT)) {
+ G.vd->flag &= ~V3D_MODE;
+ if(G.f & G_SCULPTMODE) set_sculptmode(); /* Switch off sculptmode */
+ if(G.f & G_VERTEXPAINT) set_vpaint(); /* Switch off vertex paint */
+ if(G.f & G_WEIGHTPAINT) set_wpaint(); /* Switch off weight paint */
+ if(G.obedit) exit_editmode(EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR); /* exit editmode and undo */
+
+ set_texturepaint();
+ }
+ }
+ else if (G.vd->modeselect == V3D_WEIGHTPAINTMODE_SEL) {
+ if (!(G.f & G_WEIGHTPAINT) && (ob && ob->type == OB_MESH) ) {
+ G.vd->flag &= ~V3D_MODE;
+ if(G.f & G_SCULPTMODE) set_sculptmode(); /* Switch off sculptmode */
+ if(G.f & G_VERTEXPAINT) set_vpaint(); /* Switch off vertex paint */
+ if(G.f & G_TEXTUREPAINT) set_texturepaint(); /* Switch off tex paint */
+ if(G.obedit) exit_editmode(EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR); /* exit editmode and undo */
+
+ set_wpaint();
+ }
+ }
+ else if (G.vd->modeselect == V3D_POSEMODE_SEL) {
+
+ if (ob) {
+ G.vd->flag &= ~V3D_MODE;
+ if(G.obedit) exit_editmode(EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR); /* exit editmode and undo */
+
+ enter_posemode();
+ }
+ }
+ allqueue(REDRAWVIEW3D, 1);
+ break;
+
+ case B_AROUND:
+ handle_view3d_around(); /* copies to other 3d windows */
+ allqueue(REDRAWVIEW3D, 1);
+ break;
+
+ case B_SEL_VERT:
+ if( (G.qual & LR_SHIFTKEY)==0 || G.scene->selectmode==0)
+ G.scene->selectmode= SCE_SELECT_VERTEX;
+ EM_selectmode_set();
+ countall();
+ BIF_undo_push("Selectmode Set: Vertex");
+ allqueue(REDRAWVIEW3D, 1);
+ allqueue(REDRAWIMAGE, 0); /* only needed in cases where mesh and UV selection are in sync */
+ break;
+ case B_SEL_EDGE:
+ if( (G.qual & LR_SHIFTKEY)==0 || G.scene->selectmode==0){
+ if( (G.scene->selectmode ^ SCE_SELECT_EDGE) == SCE_SELECT_VERTEX){
+ if(G.qual==LR_CTRLKEY) EM_convertsel(SCE_SELECT_VERTEX,SCE_SELECT_EDGE);
+ }
+ G.scene->selectmode = SCE_SELECT_EDGE;
+ }
+ EM_selectmode_set();
+ countall();
+ BIF_undo_push("Selectmode Set: Edge");
+ allqueue(REDRAWVIEW3D, 1);
+ allqueue(REDRAWIMAGE, 0); /* only needed in cases where mesh and UV selection are in sync */
+ break;
+ case B_SEL_FACE:
+ if( (G.qual & LR_SHIFTKEY)==0 || G.scene->selectmode==0){
+ if( ((G.scene->selectmode ^ SCE_SELECT_FACE) == SCE_SELECT_VERTEX) || ((G.scene->selectmode ^ SCE_SELECT_FACE) == SCE_SELECT_EDGE)){
+ if(G.qual==LR_CTRLKEY) EM_convertsel((G.scene->selectmode ^ SCE_SELECT_FACE),SCE_SELECT_FACE);
+ }
+ G.scene->selectmode = SCE_SELECT_FACE;
+ }
+ EM_selectmode_set();
+ countall();
+ BIF_undo_push("Selectmode Set: Face");
+ allqueue(REDRAWVIEW3D, 1);
+ allqueue(REDRAWIMAGE, 0); /* only needed in cases where mesh and UV selection are in sync */
+ break;
+
+ case B_MAN_TRANS:
+ if( (G.qual & LR_SHIFTKEY)==0 || G.vd->twtype==0)
+ G.vd->twtype= V3D_MANIP_TRANSLATE;
+ allqueue(REDRAWVIEW3D, 1);
+ break;
+ case B_MAN_ROT:
+ if( (G.qual & LR_SHIFTKEY)==0 || G.vd->twtype==0)
+ G.vd->twtype= V3D_MANIP_ROTATE;
+ allqueue(REDRAWVIEW3D, 1);
+ break;
+ case B_MAN_SCALE:
+ if( (G.qual & LR_SHIFTKEY)==0 || G.vd->twtype==0)
+ G.vd->twtype= V3D_MANIP_SCALE;
+ allqueue(REDRAWVIEW3D, 1);
+ break;
+
+ default:
+
+ if(event>=B_LAY && event<B_LAY+31) {
+ if(G.vd->lay!=0 && (G.qual & LR_SHIFTKEY)) {
+
+ /* but do find active layer */
+
+ bit= event-B_LAY;
+ if( G.vd->lay & (1<<bit)) G.vd->layact= 1<<bit;
+ else {
+ if( (G.vd->lay & G.vd->layact) == 0) {
+ bit= 0;
+ while(bit<32) {
+ if(G.vd->lay & (1<<bit)) {
+ G.vd->layact= 1<<bit;
+ break;
+ }
+ bit++;
+ }
+ }
+ }
+ }
+ else {
+ bit= event-B_LAY;
+ G.vd->lay= 1<<bit;
+ G.vd->layact= G.vd->lay;
+ scrarea_queue_headredraw(curarea);
+ }
+
+ if(G.vd->scenelock) handle_view3d_lock();
+
+ scrarea_queue_winredraw(curarea);
+ countall();
+
+ /* new layers might need unflushed events events */
+ DAG_scene_update_flags(G.scene, G.vd->lay); /* tags all that moves and flushes */
+
+ allqueue(REDRAWOOPS, 0);
+ allqueue(REDRAWNLA, 0);
+ }
+ break;
+ }
+}
+
+static void view3d_header_pulldowns(uiBlock *block, short *xcoord)
+{
+ Object *ob= OBACT;
+ short xmax, xco= *xcoord;
+
+ /* pull down menus */
+ uiBlockSetEmboss(block, UI_EMBOSSP);
+
+ /* compensate for local mode when setting up the viewing menu/iconrow values */
+ if(G.vd->view==7) G.vd->viewbut= 1;
+ else if(G.vd->view==1) G.vd->viewbut= 2;
+ else if(G.vd->view==3) G.vd->viewbut= 3;
+ else G.vd->viewbut= 0;
+
+
+ /* the 'xmax - 3' rather than xmax is to prevent some weird flickering where the highlighted
+ * menu is drawn wider than it should be. The ypos of -2 is to make it properly fill the
+ * height of the header */
+
+ xmax= GetButStringLength("View");
+ uiDefPulldownBut(block, view3d_viewmenu, NULL, "View", xco, -2, xmax-3, 24, "");
+ xco+= xmax;
+
+ xmax= GetButStringLength("Select");
+ if (G.obedit) {
+ if (ob && ob->type == OB_MESH) {
+ uiDefPulldownBut(block, view3d_select_meshmenu, NULL, "Select", xco,-2, xmax-3, 24, "");
+ } else if (ob && (ob->type == OB_CURVE || ob->type == OB_SURF)) {
+ uiDefPulldownBut(block, view3d_select_curvemenu, NULL, "Select", xco,-2, xmax-3, 24, "");
+ } else if (ob && ob->type == OB_FONT) {
+ uiDefPulldownBut(block, view3d_select_meshmenu, NULL, "Select", xco, -2, xmax-3, 24, "");
+ } else if (ob && ob->type == OB_MBALL) {
+ uiDefPulldownBut(block, view3d_select_metaballmenu, NULL, "Select", xco,-2, xmax-3, 24, "");
+ } else if (ob && ob->type == OB_LATTICE) {
+ uiDefPulldownBut(block, view3d_select_latticemenu, NULL, "Select", xco,-2, xmax-3, 24, "");
+ } else if (ob && ob->type == OB_ARMATURE) {
+ uiDefPulldownBut(block, view3d_select_armaturemenu, NULL, "Select", xco,-2, xmax-3, 24, "");
+ }
+ } else if (FACESEL_PAINT_TEST) {
+ if (ob && ob->type == OB_MESH) {
+ uiDefPulldownBut(block, view3d_select_faceselmenu, NULL, "Select", xco,-2, xmax-3, 24, "");
+ }
+ } else if ((G.f & G_VERTEXPAINT) || (G.f & G_TEXTUREPAINT) || (G.f & G_WEIGHTPAINT)) {
+ uiDefBut(block, LABEL,0,"", xco, 0, xmax, 20, 0, 0, 0, 0, 0, "");
+ } else {
+
+ if (ob && (ob->flag & OB_POSEMODE))
+ uiDefPulldownBut(block, view3d_select_pose_armaturemenu, NULL, "Select", xco,-2, xmax-3, 24, "");
+ else
+ uiDefPulldownBut(block, view3d_select_objectmenu, NULL, "Select", xco,-2, xmax-3, 24, "");
+ }
+ xco+= xmax;
+
+ if (G.obedit) {
+ if (ob && ob->type == OB_MESH) {
+ xmax= GetButStringLength("Mesh");
+ uiDefPulldownBut(block, view3d_edit_meshmenu, NULL, "Mesh", xco,-2, xmax-3, 24, "");
+ xco+= xmax;
+ } else if (ob && ob->type == OB_CURVE) {
+ xmax= GetButStringLength("Curve");
+ uiDefPulldownBut(block, view3d_edit_curvemenu, NULL, "Curve", xco,-2, xmax-3, 24, "");
+ xco+= xmax;
+ } else if (ob && ob->type == OB_SURF) {
+ xmax= GetButStringLength("Surface");
+ uiDefPulldownBut(block, view3d_edit_curvemenu, NULL, "Surface", xco,-2, xmax-3, 24, "");
+ xco+= xmax;
+ } else if (ob && ob->type == OB_FONT) {
+ xmax= GetButStringLength("Text");
+ uiDefPulldownBut(block, view3d_edit_textmenu, NULL, "Text", xco,-2, xmax-3, 24, "");
+ xco+= xmax;
+ } else if (ob && ob->type == OB_MBALL) {
+ xmax= GetButStringLength("Metaball");
+ uiDefPulldownBut(block, view3d_edit_metaballmenu, NULL, "Metaball", xco,-2, xmax-3, 24, "");
+ xco+= xmax;
+ } else if (ob && ob->type == OB_LATTICE) {
+ xmax= GetButStringLength("Lattice");
+ uiDefPulldownBut(block, view3d_edit_latticemenu, NULL, "Lattice", xco,-2, xmax-3, 24, "");
+ xco+= xmax;
+ } else if (ob && ob->type == OB_ARMATURE) {
+ xmax= GetButStringLength("Armature");
+ uiDefPulldownBut(block, view3d_edit_armaturemenu, NULL, "Armature", xco,-2, xmax-3, 24, "");
+ xco+= xmax;
+ }
+
+ }
+ else if (G.f & G_WEIGHTPAINT) {
+ xmax= GetButStringLength("Paint");
+ uiDefPulldownBut(block, view3d_wpaintmenu, NULL, "Paint", xco,-2, xmax-3, 24, "");
+ xco+= xmax;
+ }
+ else if (G.f & G_VERTEXPAINT) {
+ xmax= GetButStringLength("Paint");
+ uiDefPulldownBut(block, view3d_vpaintmenu, NULL, "Paint", xco,-2, xmax-3, 24, "");
+ xco+= xmax;
+ }
+ else if (G.f & G_TEXTUREPAINT) {
+ xmax= GetButStringLength("Paint");
+ uiDefPulldownBut(block, view3d_tpaintmenu, NULL, "Paint", xco,-2, xmax-3, 24, "");
+ xco+= xmax;
+ }
+ else if( G.f & G_SCULPTMODE) {
+ xmax= GetButStringLength("Sculpt");
+ uiDefPulldownBut(block, view3d_sculptmenu, NULL, "Sculpt", xco, -2, xmax-3, 24, "");
+ xco+= xmax;
+ }
+ else if (FACESEL_PAINT_TEST) {
+ if (ob && ob->type == OB_MESH) {
+ xmax= GetButStringLength("Face");
+ uiDefPulldownBut(block, view3d_faceselmenu, NULL, "Face", xco,-2, xmax-3, 24, "");
+ xco+= xmax;
+ }
+ } else {
+ if (ob && (ob->flag & OB_POSEMODE)) {
+ xmax= GetButStringLength("Pose");
+ uiDefPulldownBut(block, view3d_pose_armaturemenu, NULL, "Pose", xco,-2, xmax-3, 24, "");
+ xco+= xmax;
+ }
+ else {
+ xmax= GetButStringLength("Object");
+ uiDefPulldownBut(block, view3d_edit_objectmenu, NULL, "Object", xco,-2, xmax-3, 24, "");
+ xco+= xmax;
+ }
+ }
+
+ *xcoord= xco;
+}
+
+void view3d_buttons(void)
+{
+ uiBlock *block;
+ Object *ob= OBACT;
+ int a;
+ short xco = 0;
+
+ block= uiNewBlock(&curarea->uiblocks, "header view3d", UI_EMBOSS, UI_HELV, curarea->headwin);
+
+ if(area_is_active_area(curarea)) uiBlockSetCol(block, TH_HEADER);
+ else uiBlockSetCol(block, TH_HEADERDESEL);
+
+ curarea->butspacetype= SPACE_VIEW3D;
+
+ xco = 8;
+ uiDefIconTextButC(block, ICONTEXTROW,B_NEWSPACE, ICON_VIEW3D, windowtype_pup(), xco,0,XIC+10,YIC, &(curarea->butspacetype), 1.0, SPACEICONMAX, 0, 0, "Displays Current Window Type. Click for menu of available types.");
+ xco+= XIC+14;
+
+ uiBlockSetEmboss(block, UI_EMBOSSN);
+ if(curarea->flag & HEADER_NO_PULLDOWN) {
+ uiDefIconButBitS(block, TOG, HEADER_NO_PULLDOWN, B_FLIPINFOMENU, ICON_DISCLOSURE_TRI_RIGHT,
+ xco,2,XIC,YIC-2,
+ &(curarea->flag), 0, 0, 0, 0, "Enables display of pulldown menus");
+ } else {
+ uiDefIconButBitS(block, TOG, HEADER_NO_PULLDOWN, B_FLIPINFOMENU, ICON_DISCLOSURE_TRI_DOWN,
+ xco,2,XIC,YIC-2,
+ &(curarea->flag), 0, 0, 0, 0, "Hides pulldown menus");
+ }
+ uiBlockSetEmboss(block, UI_EMBOSS);
+ xco+=XIC;
+
+ if((curarea->flag & HEADER_NO_PULLDOWN)==0)
+ view3d_header_pulldowns(block, &xco);
+
+ /* other buttons: */
+ uiBlockSetEmboss(block, UI_EMBOSS);
+
+ /* mode */
+ G.vd->modeselect = V3D_OBJECTMODE_SEL;
+
+ if (G.obedit) G.vd->modeselect = V3D_EDITMODE_SEL;
+ else if(ob && (ob->flag & OB_POSEMODE)) G.vd->modeselect = V3D_POSEMODE_SEL;
+ else if (G.f & G_SCULPTMODE) G.vd->modeselect = V3D_SCULPTMODE_SEL;
+ else if (G.f & G_WEIGHTPAINT) G.vd->modeselect = V3D_WEIGHTPAINTMODE_SEL;
+ else if (G.f & G_VERTEXPAINT) G.vd->modeselect = V3D_VERTEXPAINTMODE_SEL;
+ else if (G.f & G_TEXTUREPAINT) G.vd->modeselect = V3D_TEXTUREPAINTMODE_SEL;
+ /*else if(G.f & G_FACESELECT) G.vd->modeselect = V3D_FACESELECTMODE_SEL;*/
+
+ G.vd->flag &= ~V3D_MODE;
+
+ /* not sure what the G.vd->flag is useful for now... modeselect is confusing */
+ if(G.obedit) G.vd->flag |= V3D_EDITMODE;
+ if(ob && (ob->flag & OB_POSEMODE)) G.vd->flag |= V3D_POSEMODE;
+ if(G.f & G_VERTEXPAINT) G.vd->flag |= V3D_VERTEXPAINT;
+ if(G.f & G_WEIGHTPAINT) G.vd->flag |= V3D_WEIGHTPAINT;
+ if (G.f & G_TEXTUREPAINT) G.vd->flag |= V3D_TEXTUREPAINT;
+ if(FACESEL_PAINT_TEST) G.vd->flag |= V3D_FACESELECT;
+
+ uiDefIconTextButS(block, MENU, B_MODESELECT, (G.vd->modeselect),view3d_modeselect_pup() ,
+ xco,0,126,20, &(G.vd->modeselect), 0, 0, 0, 0, "Mode (Hotkeys: Tab, V, Ctrl Tab)");
+
+ xco+= 126+8;
+
+ /* DRAWTYPE */
+ uiDefIconTextButS(block, ICONTEXTROW,B_REDR, ICON_BBOX, drawtype_pup(), xco,0,XIC+10,YIC, &(G.vd->drawtype), 1.0, 5.0, 0, 0, "Viewport Shading (Hotkeys: Z, Shift Z, Ctrl Z, Alt Z");
+
+ /* around */
+ xco+= XIC+18;
+
+ uiBlockBeginAlign(block);
+
+ if(retopo_mesh_paint_check()) {
+ RetopoPaintData *rpd= get_retopo_paint_data();
+ if(rpd) {
+ ToolSettings *ts= G.scene->toolsettings;
+
+ uiDefButC(block,ROW,B_REDR,"Pen",xco,0,40,20,&ts->retopo_paint_tool,6.0,RETOPO_PEN,0,0,"");
+ xco+=40;
+ uiDefButC(block,ROW,B_REDR,"Line",xco,0,40,20,&ts->retopo_paint_tool,6.0,RETOPO_LINE,0,0,"");
+ xco+=40;
+ uiDefButC(block,ROW,B_REDR,"Ellipse",xco,0,60,20,&ts->retopo_paint_tool,6.0,RETOPO_ELLIPSE,0,0,"");
+ xco+=65;
+
+ uiBlockBeginAlign(block);
+ if(ts->retopo_paint_tool == RETOPO_PEN) {
+ uiDefButC(block,TOG,B_NOP,"Hotspot",xco,0,60,20, &ts->retopo_hotspot, 0,0,0,0,"Show hotspots at line ends to allow line continuation");
+ xco+=80;
+ }
+ else if(ts->retopo_paint_tool == RETOPO_LINE) {
+ uiDefButC(block,NUM,B_NOP,"LineDiv",xco,0,80,20,&ts->line_div,1,50,0,0,"Subdivisions per retopo line");
+ xco+=80;
+ }
+ else if(ts->retopo_paint_tool == RETOPO_ELLIPSE) {
+ uiDefButC(block,NUM,B_NOP,"EllDiv",xco,0,80,20,&ts->ellipse_div,3,50,0,0,"Subdivisions per retopo ellipse");
+ xco+=80;
+ }
+ xco+=5;
+
+ uiBlockEndAlign(block);
+ }
+ } else {
+ if (G.obedit==NULL && (G.f & (G_VERTEXPAINT|G_WEIGHTPAINT|G_TEXTUREPAINT|G_SCULPTMODE))) {
+ uiDefIconButBitI(block, TOG, G_FACESELECT, B_REDR, ICON_FACESEL_HLT,xco,0,XIC,YIC, &G.f, 0, 0, 0, 0, "Painting Mask (FKey)");
+ xco+= XIC+10;
+ } else {
+ /* Manipulators arnt used in weight paint mode */
+ uiDefIconTextButS(block, ICONTEXTROW,B_AROUND, ICON_ROTATE, around_pup(), xco,0,XIC+10,YIC, &(G.vd->around), 0, 3.0, 0, 0, "Rotation/Scaling Pivot (Hotkeys: Comma, Shift Comma, Period, Ctrl Period, Alt Period)");
+
+ xco+= XIC+10;
+
+ uiDefIconButBitS(block, TOG, V3D_ALIGN, B_AROUND, ICON_ALIGN,
+ xco,0,XIC,YIC,
+ &G.vd->flag, 0, 0, 0, 0, "Move object centers only");
+ uiBlockEndAlign(block);
+
+ xco+= XIC+8;
+
+ /* Transform widget / manipulators */
+ uiBlockBeginAlign(block);
+ uiDefIconButBitS(block, TOG, V3D_USE_MANIPULATOR, B_REDR, ICON_MANIPUL,xco,0,XIC,YIC, &G.vd->twflag, 0, 0, 0, 0, "Use 3d transform manipulator (Ctrl Space)");
+ xco+= XIC;
+
+ if(G.vd->twflag & V3D_USE_MANIPULATOR) {
+ uiDefIconButBitS(block, TOG, V3D_MANIP_TRANSLATE, B_MAN_TRANS, ICON_MAN_TRANS, xco,0,XIC,YIC, &G.vd->twtype, 1.0, 0.0, 0, 0, "Translate manipulator mode (Ctrl Alt G)");
+ xco+= XIC;
+ uiDefIconButBitS(block, TOG, V3D_MANIP_ROTATE, B_MAN_ROT, ICON_MAN_ROT, xco,0,XIC,YIC, &G.vd->twtype, 1.0, 0.0, 0, 0, "Rotate manipulator mode (Ctrl Alt R)");
+ xco+= XIC;
+ uiDefIconButBitS(block, TOG, V3D_MANIP_SCALE, B_MAN_SCALE, ICON_MAN_SCALE, xco,0,XIC,YIC, &G.vd->twtype, 1.0, 0.0, 0, 0, "Scale manipulator mode (Ctrl Alt S)");
+ xco+= XIC;
+ }
+ uiDefButS(block, MENU, B_NOP, "Orientation%t|Global%x0|Local%x1|Normal%x2|View%x3",xco,0,70,YIC, &G.vd->twmode, 0, 0, 0, 0, "Transform Orientation (Alt Space)");
+ xco+= 70;
+ uiBlockEndAlign(block);
+ xco+= 8;
+ }
+
+ /* LAYERS */
+ if(G.obedit==NULL && G.vd->localview==0) {
+ uiBlockBeginAlign(block);
+ for(a=0; a<5; a++)
+ uiDefButBitI(block, TOG, 1<<a, B_LAY+a, "", (short)(xco+a*(XIC/2)), (short)(YIC/2),(short)(XIC/2),(short)(YIC/2), &(G.vd->lay), 0, 0, 0, 0, "Toggles Layer visibility (Num, Shift Num)");
+ for(a=0; a<5; a++)
+ uiDefButBitI(block, TOG, 1<<(a+10), B_LAY+10+a, "",(short)(xco+a*(XIC/2)), 0, XIC/2, (YIC)/2, &(G.vd->lay), 0, 0, 0, 0, "Toggles Layer visibility (Alt Num, Alt Shift Num)");
+
+ xco+= 5;
+ uiBlockBeginAlign(block);
+ for(a=5; a<10; a++)
+ uiDefButBitI(block, TOG, 1<<a, B_LAY+a, "", (short)(xco+a*(XIC/2)), (short)(YIC/2),(short)(XIC/2),(short)(YIC/2), &(G.vd->lay), 0, 0, 0, 0, "Toggles Layer visibility (Num, Shift Num)");
+ for(a=5; a<10; a++)
+ uiDefButBitI(block, TOG, 1<<(a+10), B_LAY+10+a, "",(short)(xco+a*(XIC/2)), 0, XIC/2, (YIC)/2, &(G.vd->lay), 0, 0, 0, 0, "Toggles Layer visibility (Alt Num, Alt Shift Num)");
+
+ uiBlockEndAlign(block);
+
+ xco+= (a-2)*(XIC/2)+3;
+
+ /* LOCK */
+ uiDefIconButS(block, ICONTOG, B_SCENELOCK, ICON_UNLOCKED, xco+=XIC,0,XIC,YIC, &(G.vd->scenelock), 0, 0, 0, 0, "Locks Active Camera and layers to Scene (Ctrl `)");
+ xco+= XIC+10;
+
+ }
+
+ /* proportional falloff */
+ if(G.obedit && (G.obedit->type == OB_MESH || G.obedit->type == OB_CURVE || G.obedit->type == OB_SURF || G.obedit->type == OB_LATTICE)) {
+
+ uiBlockBeginAlign(block);
+ uiDefIconTextButS(block, ICONTEXTROW,B_REDR, ICON_PROP_OFF, "Proportional %t|Off %x0|On %x1|Connected %x2", xco,0,XIC+10,YIC, &(G.scene->proportional), 0, 1.0, 0, 0, "Proportional Edit Falloff (Hotkeys: O, Alt O) ");
+ xco+= XIC+10;
+
+ if(G.scene->proportional) {
+ uiDefIconTextButS(block, ICONTEXTROW,B_REDR, ICON_SMOOTHCURVE, propfalloff_pup(), xco,0,XIC+10,YIC, &(G.scene->prop_mode), 0.0, 0.0, 0, 0, "Proportional Edit Falloff (Hotkey: Shift O) ");
+ xco+= XIC+10;
+ }
+ xco+= 10;
+ }
+
+ /* Snap */
+ if(G.obedit && (G.obedit->type == OB_MESH)) { // Only Mesh for now
+ uiBlockBeginAlign(block);
+
+ if (G.scene->snap_flag & SCE_SNAP) {
+ uiDefIconButBitS(block, TOG, SCE_SNAP, B_REDR, ICON_SNAP_GEO,xco,0,XIC,YIC, &G.scene->snap_flag, 0, 0, 0, 0, "Use Snap or Grid (Shift Tab)");
+ xco+= XIC;
+ uiDefButS(block, MENU, B_NOP, "Mode%t|Closest%x0|Center%x1|Median%x2",xco,0,70,YIC, &G.scene->snap_target, 0, 0, 0, 0, "Snap Target Mode");
+ xco+= 70;
+ } else {
+ uiDefIconButBitS(block, TOG, SCE_SNAP, B_REDR, ICON_SNAP_GEAR,xco,0,XIC,YIC, &G.scene->snap_flag, 0, 0, 0, 0, "Snap while Ctrl is held during transform (Shift Tab)");
+ xco+= XIC;
+ }
+
+ uiBlockEndAlign(block);
+ xco+= 10;
+ }
+
+ /* selection modus */
+ if(G.obedit && (G.obedit->type == OB_MESH)) {
+ uiBlockBeginAlign(block);
+ uiDefIconButBitS(block, TOG, SCE_SELECT_VERTEX, B_SEL_VERT, ICON_VERTEXSEL, xco,0,XIC,YIC, &G.scene->selectmode, 1.0, 0.0, 0, 0, "Vertex select mode (Ctrl Tab 1)");
+ xco+= XIC;
+ uiDefIconButBitS(block, TOG, SCE_SELECT_EDGE, B_SEL_EDGE, ICON_EDGESEL, xco,0,XIC,YIC, &G.scene->selectmode, 1.0, 0.0, 0, 0, "Edge select mode (Ctrl Tab 2)");
+ xco+= XIC;
+ uiDefIconButBitS(block, TOG, SCE_SELECT_FACE, B_SEL_FACE, ICON_FACESEL, xco,0,XIC,YIC, &G.scene->selectmode, 1.0, 0.0, 0, 0, "Face select mode (Ctrl Tab 3)");
+ xco+= XIC;
+ uiBlockEndAlign(block);
+ if(G.vd->drawtype > OB_WIRE) {
+ uiDefIconButBitS(block, TOG, V3D_ZBUF_SELECT, B_REDR, ICON_ORTHO, xco,0,XIC,YIC, &G.vd->flag, 1.0, 0.0, 0, 0, "Occlude background geometry");
+ xco+= XIC;
+ }
+ xco+= 20;
+ }
+
+ uiDefIconBut(block, BUT, B_VIEWRENDER, ICON_SCENE_DEHLT, xco,0,XIC,YIC, NULL, 0, 1.0, 0, 0, "Render this window (hold CTRL for anim)");
+
+ if (ob && (ob->flag & OB_POSEMODE)) {
+ xco+= XIC/2;
+ uiBlockBeginAlign(block);
+ if(curarea->headertype==HEADERTOP) {
+ uiDefIconBut(block, BUT, B_ACTCOPY, ICON_COPYUP,
+ xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0,
+ "Copies the current pose to the buffer");
+ uiDefIconBut(block, BUT, B_ACTPASTE, ICON_PASTEUP,
+ xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0,
+ "Pastes the pose from the buffer");
+ uiDefIconBut(block, BUT, B_ACTPASTEFLIP, ICON_PASTEFLIPUP,
+ xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0,
+ "Pastes the mirrored pose from the buffer");
+ }
+ else {
+ uiDefIconBut(block, BUT, B_ACTCOPY, ICON_COPYDOWN,
+ xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0,
+ "Copies the current pose to the buffer");
+ uiSetButLock(object_data_is_libdata(ob), ERROR_LIBDATA_MESSAGE);
+ uiDefIconBut(block, BUT, B_ACTPASTE, ICON_PASTEDOWN,
+ xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0,
+ "Pastes the pose from the buffer");
+ uiDefIconBut(block, BUT, B_ACTPASTEFLIP, ICON_PASTEFLIPDOWN,
+ xco+=XIC,0,XIC,YIC, 0, 0, 0, 0, 0,
+ "Pastes the mirrored pose from the buffer");
+ }
+ uiBlockEndAlign(block);
+ }
+ }
+
+ /* Always do this last */
+ curarea->headbutlen= xco+2*XIC;
+
+ uiDrawBlock(block);
+
+}
diff --git a/source/blender/src/headerbuttons.c b/source/blender/src/headerbuttons.c
new file mode 100644
index 00000000000..2ad1702f1f0
--- /dev/null
+++ b/source/blender/src/headerbuttons.c
@@ -0,0 +1,2080 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include <sys/types.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "BMF_Api.h"
+#include "BIF_language.h"
+#ifdef INTERNATIONAL
+#include "FTF_Api.h"
+#endif
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_storage_types.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "DNA_ID.h"
+#include "DNA_action_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_brush_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_group_types.h"
+#include "DNA_image_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_key_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_object_types.h"
+#include "DNA_oops_types.h"
+#include "DNA_packedFile_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_sequence_types.h"
+#include "DNA_sound_types.h"
+#include "DNA_space_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_text_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_view2d_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_world_types.h"
+#include "DNA_constraint_types.h"
+
+#include "BKE_utildefines.h"
+
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_blender.h"
+#include "BKE_brush.h"
+#include "BKE_constraint.h"
+#include "BKE_curve.h"
+#include "BKE_depsgraph.h"
+#include "BKE_exotic.h"
+#include "BKE_global.h"
+#include "BKE_image.h"
+#include "BKE_ipo.h"
+#include "BKE_key.h"
+#include "BKE_lattice.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_mball.h"
+#include "BKE_mesh.h"
+#include "BKE_node.h"
+#include "BKE_object.h"
+#include "BKE_packedFile.h"
+#include "BKE_sca.h"
+#include "BKE_scene.h"
+#include "BKE_texture.h"
+#include "BKE_text.h"
+#include "BKE_world.h"
+
+#include "BLO_readfile.h"
+#include "BLO_writefile.h"
+
+#include "BIF_drawimage.h"
+#include "BIF_drawoops.h"
+#include "BIF_drawscene.h"
+#include "BIF_drawtext.h"
+#include "BIF_editaction.h"
+#include "BIF_editarmature.h"
+#include "BIF_editfont.h"
+#include "BIF_editlattice.h"
+#include "BIF_editconstraint.h"
+#include "BIF_editmesh.h"
+#include "BIF_editmesh.h"
+#include "BIF_editsima.h"
+#include "BIF_editsound.h"
+#include "BIF_gl.h"
+#include "BIF_imasel.h"
+#include "BIF_interface.h"
+#include "BIF_mainqueue.h"
+#include "BIF_mywindow.h"
+#include "BIF_poseobject.h"
+#include "BIF_renderwin.h"
+#include "BIF_resources.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_toets.h"
+#include "BIF_toolbox.h"
+#include "BIF_usiblender.h"
+#include "BIF_previewrender.h"
+#include "BIF_writeimage.h"
+#include "BIF_butspace.h"
+
+#include "BPI_script.h"
+
+#include "BSE_edit.h"
+#include "BSE_filesel.h"
+#include "BSE_headerbuttons.h"
+#include "BSE_node.h"
+#include "BSE_view.h"
+#include "BSE_sequence.h"
+#include "BSE_editipo.h"
+#include "BSE_drawipo.h"
+
+#include "BDR_drawmesh.h"
+#include "BDR_vpaint.h"
+#include "BDR_editface.h"
+#include "BDR_editobject.h"
+#include "BDR_editcurve.h"
+#include "BDR_editmball.h"
+#include "BDR_sculptmode.h"
+
+#include "BPY_extern.h"
+#include "BPY_menus.h"
+
+#include "mydevice.h"
+#include "blendef.h"
+#include "interface.h"
+#include "nla.h" /* __NLA : To be removed later */
+#include "butspace.h" // test_idbutton
+
+#include "BIF_poseobject.h"
+
+#include "SYS_System.h"
+
+ /* WATCH IT: always give all headerbuttons for same window the same name
+ * event B_REDR is a standard redraw
+ *
+ */
+
+char *windowtype_pup(void)
+{
+ return(
+ "Window type:%t" //14
+ "|3D View %x1" //30
+
+ "|%l" // 33
+
+ "|Ipo Curve Editor %x2" //54
+ "|Action Editor %x12" //73
+ "|NLA Editor %x13" //94
+
+ "|%l" //97
+
+ "|UV/Image Editor %x6" //117
+
+ "|Video Sequence Editor %x8" //143
+ "|Timeline %x15" //163
+ "|Audio Window %x11" //163
+ "|Text Editor %x9" //179
+
+ "|%l" //192
+
+
+ "|User Preferences %x7" //213
+ "|Outliner %x3" //232
+ "|Buttons Window %x4" //251
+ "|Node Editor %x16"
+ "|%l" //254
+
+ "|Image Browser %x10" //273
+ "|File Browser %x5" //290
+
+ "|%l" //293
+
+ "|Scripts Window %x14"//313
+ );
+}
+
+int GetButStringLength(char *str) {
+ int rt;
+
+ rt= BIF_GetStringWidth(G.font, str, (U.transopts & USER_TR_BUTTONS));
+
+ return rt + 15;
+}
+
+/* ********************** GLOBAL ****************************** */
+
+int std_libbuttons(uiBlock *block, short xco, short yco,
+ int pin, short *pinpoin, int browse, short id_code, short special, ID *id,
+ ID *parid, short *menupoin, int users, int lib,
+ int del, int autobut, int keepbut)
+{
+ ListBase *lb;
+ uiBut *but;
+ int len, oldcol, add_addbutton=0;
+ char *str=NULL, str1[10];
+
+ uiBlockBeginAlign(block);
+ oldcol= uiBlockGetCol(block);
+
+ if(id && pin) {
+ uiDefIconButS(block, ICONTOG, pin, ICON_PIN_DEHLT, xco,yco,XIC,YIC, pinpoin, 0, 0, 0, 0, "Keeps this view displaying the current data regardless of what object is selected");
+ xco+= XIC;
+ }
+ /* browse menu */
+ if(browse) {
+ char *extrastr= NULL;
+
+ if(ELEM3(id_code, ID_MA, ID_TE, ID_BR)) add_addbutton= 1;
+
+ lb= wich_libbase(G.main, id_code);
+
+ if(id && id->us>1) uiBlockSetCol(block, TH_BUT_SETTING1);
+
+ if (pin && *pinpoin) {
+ uiBlockSetCol(block, TH_BUT_SETTING2);
+ }
+
+ if ELEM8( id_code, ID_SCE, ID_SCR, ID_MA, ID_TE, ID_WO, ID_IP, ID_AC, ID_BR) extrastr= "ADD NEW %x 32767";
+ else if (id_code==ID_TXT) extrastr= "OPEN NEW %x 32766 |ADD NEW %x 32767";
+ else if (id_code==ID_SO) extrastr= "OPEN NEW %x 32766";
+
+ uiSetButLock(G.scene->id.lib!=0, ERROR_LIBDATA_MESSAGE);
+ if( id_code==ID_SCE || id_code==ID_SCR ) uiClearButLock();
+
+ if(curarea->spacetype==SPACE_BUTS)
+ uiSetButLock(id_code!=ID_SCR && G.obedit!=0 && G.buts->mainb==CONTEXT_EDITING, "Cannot perform in EditMode");
+
+ if(parid) uiSetButLock(parid->lib!=0, ERROR_LIBDATA_MESSAGE);
+
+ if (lb) {
+ if( id_code==ID_IP)
+ IPOnames_to_pupstring(&str, NULL, extrastr, lb, id, menupoin, G.sipo->blocktype);
+ else if(browse!=B_SIMABROWSE && id_code==ID_IM )
+ IMAnames_to_pupstring(&str, NULL, extrastr, lb, id, menupoin);
+ else
+ IDnames_to_pupstring(&str, NULL, extrastr, lb, id, menupoin);
+ }
+
+ uiDefButS(block, MENU, browse, str, xco,yco,XIC,YIC, menupoin, 0, 0, 0, 0, "Browses existing choices or adds NEW");
+ xco+= XIC;
+
+ uiClearButLock();
+
+ MEM_freeN(str);
+ }
+
+ uiBlockSetCol(block, oldcol);
+
+ if(id) { /* text button with name */
+
+ /* name */
+ if(id->us>1) uiBlockSetCol(block, TH_BUT_SETTING1);
+ /* Pinned data ? */
+ if (pin && *pinpoin) {
+ uiBlockSetCol(block, TH_BUT_SETTING2);
+ }
+ /* Redalert overrides pin color */
+ if(id->us<=0) uiBlockSetCol(block, TH_REDALERT);
+
+ uiSetButLock(id->lib!=0, ERROR_LIBDATA_MESSAGE);
+
+ if(GS(id->name)==ID_SCE) strcpy(str1, "SCE:");
+ else if(GS(id->name)==ID_SCE) strcpy(str1, "SCR:");
+ else if(GS(id->name)==ID_MA) {
+ if( ((Material *)id)->use_nodes )
+ strcpy(str1, "NT:");
+ else
+ strcpy(str1, "MA:");
+ }
+ else {
+ str1[0]= id->name[0];
+ str1[1]= id->name[1];
+ str1[2]= ':';
+ str1[3]= 0;
+ }
+
+ if( GS(id->name)==ID_IP) len= 110;
+ else if(yco) len= 140; // comes from button panel
+ else len= 120;
+
+ but= uiDefBut(block, TEX, B_IDNAME, str1,xco, yco, (short)len, YIC, id->name+2, 0.0, 21.0, 0, 0, "Displays current Datablock name. Click to change.");
+ uiButSetFunc(but, test_idbutton_cb, id->name, NULL);
+
+ uiClearButLock();
+
+ xco+= len;
+
+ if(id->lib) {
+
+ if(id->flag & LIB_INDIRECT) uiDefIconBut(block, BUT, 0, ICON_DATALIB,xco,yco,XIC,YIC, 0, 0, 0, 0, 0, "Indirect Library Datablock. Cannot change.");
+ else uiDefIconBut(block, BUT, lib, ICON_PARLIB, xco,yco,XIC,YIC, 0, 0, 0, 0, 0,
+ lib?"Direct linked Library Datablock. Click to make local.":"Direct linked Library Datablock, cannot make local."
+ );
+
+ xco+= XIC;
+ }
+
+
+ if(users && id->us>1) {
+ uiSetButLock (pin && *pinpoin, "Can't make pinned data single-user");
+
+ sprintf(str1, "%d", id->us);
+ if(id->us<10) {
+
+ uiDefBut(block, BUT, users, str1, xco,yco,XIC,YIC, 0, 0, 0, 0, 0, "Displays number of users of this data. Click to make a single-user copy.");
+ xco+= XIC;
+ }
+ else {
+ uiDefBut(block, BUT, users, str1, xco, yco, XIC+10, YIC, 0, 0, 0, 0, 0, "Displays number of users of this data. Click to make a single-user copy.");
+ xco+= XIC+10;
+ }
+
+ uiClearButLock();
+
+ }
+
+ if(del) {
+
+ uiSetButLock (pin && *pinpoin, "Can't unlink pinned data");
+ if(parid && parid->lib);
+ else {
+ uiDefIconBut(block, BUT, del, ICON_X, xco,yco,XIC,YIC, 0, 0, 0, 0, 0, "Deletes link to this Datablock");
+ xco+= XIC;
+ }
+
+ uiClearButLock();
+ }
+
+ if(autobut) {
+ if(parid && parid->lib);
+ else {
+ uiDefIconBut(block, BUT, autobut, ICON_AUTO,xco,yco,XIC,YIC, 0, 0, 0, 0, 0, "Generates an automatic name");
+ xco+= XIC;
+ }
+
+
+ }
+ if(keepbut) {
+ uiDefBut(block, BUT, keepbut, "F", xco,yco,XIC,YIC, 0, 0, 0, 0, 0, "Saves this datablock even if it has no users");
+ xco+= XIC;
+ }
+ }
+ else if(add_addbutton) { /* "add new" button */
+ uiBlockSetCol(block, oldcol);
+ uiDefButS(block, TOG, browse, "Add New" ,xco, yco, 110, YIC, menupoin, (float)*menupoin, 32767.0, 0, 0, "Add new data block");
+ xco+= 110;
+ }
+ //xco+=XIC;
+
+ uiBlockSetCol(block, oldcol);
+ uiBlockEndAlign(block);
+
+ return xco;
+}
+
+
+/* results in fully updated anim system */
+static void do_update_for_newframe(int mute, int events)
+{
+ extern void audiostream_scrub(unsigned int frame); /* seqaudio.c */
+
+ if(events) {
+ allqueue(REDRAWALL, 0);
+ }
+
+ /* this function applies the changes too */
+ scene_update_for_newframe(G.scene, screen_view3d_layers()); /* BKE_scene.h */
+
+ if ( (CFRA>1) && (!mute) && (G.scene->audio.flag & AUDIO_SCRUB))
+ audiostream_scrub( CFRA );
+
+ /* 3d window, preview */
+ BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
+
+ /* all movie/sequence images */
+ BIF_image_update_frame();
+
+ /* composite */
+ if(G.scene->use_nodes && G.scene->nodetree)
+ ntreeCompositTagAnimated(G.scene->nodetree);
+}
+
+void update_for_newframe(void)
+{
+ do_update_for_newframe(0, 1);
+}
+
+void update_for_newframe_muted(void)
+{
+ do_update_for_newframe(1, 1);
+}
+
+/* used by new animated UI playback */
+void update_for_newframe_nodraw(int nosound)
+{
+ do_update_for_newframe(nosound, 0);
+}
+
+
+static void show_splash(void)
+{
+ extern char datatoc_splash_jpg[];
+ extern int datatoc_splash_jpg_size;
+ char *string = NULL;
+
+#ifdef NAN_BUILDINFO
+ char buffer[1024];
+ extern char * build_date;
+ extern char * build_time;
+ extern char * build_platform;
+ extern char * build_type;
+
+ string = &buffer[0];
+ sprintf(string,"Built on %s %s Version %s %s", build_date, build_time, build_platform, build_type);
+#endif
+
+ splash((void *)datatoc_splash_jpg, datatoc_splash_jpg_size, string);
+}
+
+
+/* Functions for user preferences fileselect windows */
+
+/* yafray: export dir select */
+static void filesel_u_yfexportdir(char *name)
+{
+ char dir[FILE_MAXDIR], file[FILE_MAXFILE];
+
+ BLI_cleanup_dir(G.sce, name);
+ BLI_split_dirfile(name, dir, file);
+
+ strcpy(U.yfexportdir, dir);
+ allqueue(REDRAWALL, 0);
+}
+
+static void filesel_u_fontdir(char *name)
+{
+ char dir[FILE_MAXDIR], file[FILE_MAXFILE];
+
+ BLI_cleanup_dir(G.sce, name);
+ BLI_split_dirfile(name, dir, file);
+
+ strcpy(U.fontdir, dir);
+ allqueue(REDRAWALL, 0);
+}
+
+static void filesel_u_textudir(char *name)
+{
+ char dir[FILE_MAXDIR], file[FILE_MAXFILE];
+
+ BLI_cleanup_dir(G.sce, name);
+ BLI_split_dirfile(name, dir, file);
+
+ strcpy(U.textudir, dir);
+ allqueue(REDRAWALL, 0);
+}
+
+static void filesel_u_plugtexdir(char *name)
+{
+ char dir[FILE_MAXDIR], file[FILE_MAXFILE];
+
+ BLI_cleanup_dir(G.sce, name);
+ BLI_split_dirfile(name, dir, file);
+
+ strcpy(U.plugtexdir, dir);
+ allqueue(REDRAWALL, 0);
+}
+
+static void filesel_u_plugseqdir(char *name)
+{
+ char dir[FILE_MAXDIR], file[FILE_MAXFILE];
+
+ BLI_cleanup_dir(G.sce, name);
+ BLI_split_dirfile(name, dir, file);
+
+ strcpy(U.plugseqdir, dir);
+ allqueue(REDRAWALL, 0);
+}
+
+static void filesel_u_renderdir(char *name)
+{
+ char dir[FILE_MAXDIR], file[FILE_MAXFILE];
+
+ BLI_cleanup_dir(G.sce, name);
+ BLI_split_dirfile(name, dir, file);
+
+ strcpy(U.renderdir, dir);
+ allqueue(REDRAWALL, 0);
+}
+
+static void filesel_u_pythondir(char *name)
+{
+ char dir[FILE_MAXDIR], file[FILE_MAXFILE];
+
+ BLI_cleanup_dir(G.sce, name);
+ BLI_split_dirfile(name, dir, file);
+
+ strcpy(U.pythondir, dir);
+ allqueue(REDRAWALL, 0);
+}
+
+static void filesel_u_sounddir(char *name)
+{
+ char dir[FILE_MAXDIR], file[FILE_MAXFILE];
+
+ BLI_cleanup_dir(G.sce, name);
+ BLI_split_dirfile(name, dir, file);
+
+ strcpy(U.sounddir, dir);
+ allqueue(REDRAWALL, 0);
+}
+
+static void filesel_u_tempdir(char *name)
+{
+ char dir[FILE_MAXDIR], file[FILE_MAXFILE];
+
+ BLI_cleanup_dir(G.sce, name);
+ BLI_split_dirfile(name, dir, file);
+
+ strcpy(U.tempdir, dir);
+ allqueue(REDRAWALL, 0);
+}
+
+/* END Functions for user preferences fileselect windows */
+
+
+void do_global_buttons(unsigned short event)
+{
+ ListBase *lb;
+ Object *ob;
+ Material *ma;
+ MTex *mtex;
+ Ipo *ipo;
+ Lamp *la;
+ World *wrld;
+ bAction *act;
+ ID *id, *idtest, *from=NULL;
+ ScrArea *sa;
+ Brush *br;
+ int nr= 1;
+
+#ifdef INTERNATIONAL
+ char buf[FILE_MAX];
+#endif
+
+ ob= OBACT;
+
+ id= NULL; /* id at null for texbrowse */
+
+
+ switch(event) {
+
+ case B_NEWFRAME:
+ scrarea_queue_winredraw(curarea);
+ scrarea_queue_headredraw(curarea);
+
+ update_for_newframe();
+ break;
+ case B_REDR:
+ scrarea_queue_winredraw(curarea);
+ scrarea_queue_headredraw(curarea);
+ break;
+ case B_REDRCURW3D:
+ allqueue(REDRAWVIEW3D, 0);
+ scrarea_queue_winredraw(curarea);
+ scrarea_queue_headredraw(curarea);
+ break;
+ case B_EDITBROWSE:
+ if(ob==NULL) return;
+ if(ob->id.lib) return;
+ id= ob->data;
+ if(id==NULL) return;
+
+ if(G.buts->menunr== -2) {
+ activate_databrowse((ID *)G.buts->lockpoin, GS(id->name), 0, B_EDITBROWSE, &G.buts->menunr, do_global_buttons);
+ return;
+ }
+ if(G.buts->menunr < 0) return;
+
+ lb= wich_libbase(G.main, GS(id->name));
+ idtest= lb->first;
+ while(idtest) {
+ if(nr==G.buts->menunr) {
+ if(idtest!=id) {
+ id->us--;
+ id_us_plus(idtest);
+
+ ob->data= idtest;
+
+ test_object_materials(idtest);
+
+ if( GS(idtest->name)==ID_CU ) {
+ test_curve_type(ob);
+ }
+ else if( ob->type==OB_ARMATURE) {
+ armature_rebuild_pose(ob, ob->data);
+ }
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWACTION,0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWNLA,0);
+ }
+ break;
+ }
+ nr++;
+ idtest= idtest->next;
+ }
+
+ break;
+ case B_MESHBROWSE:
+ if(ob==0) return;
+ if(ob->id.lib) return;
+
+ id= ob->data;
+ if(id==0) id= G.main->mesh.first;
+ if(id==0) return;
+
+ if(G.buts->menunr== -2) {
+ activate_databrowse((ID *)G.buts->lockpoin, GS(id->name), 0, B_MESHBROWSE, &G.buts->menunr, do_global_buttons);
+ return;
+ }
+ if(G.buts->menunr < 0) return;
+
+
+ idtest= G.main->mesh.first;
+ while(idtest) {
+ if(nr==G.buts->menunr) {
+ set_mesh(ob, (Mesh *)idtest);
+
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+
+ BIF_undo_push("Browse Mesh");
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWACTION,0);
+ allqueue(REDRAWIPO, 0);
+
+ break;
+ }
+ nr++;
+ idtest= idtest->next;
+ }
+
+ break;
+ case B_MATBROWSE:
+ {
+ void *lockpoin= NULL;
+ short *menunr= 0;
+
+ /* this is called now from Node editor too, buttons might not exist */
+ if(curarea->spacetype==SPACE_NODE) {
+ SpaceNode *snode= curarea->spacedata.first;
+ menunr= &snode->menunr;
+ lockpoin= snode->id;
+ }
+ else if(G.buts) {
+ menunr= &G.buts->menunr;
+ lockpoin= G.buts->lockpoin;
+ }
+ else return;
+
+ if(*menunr== -2) {
+ if(G.qual & LR_CTRLKEY) {
+ activate_databrowse_imasel((ID *)lockpoin, ID_MA, 0, B_MATBROWSE, menunr, do_global_buttons);
+ }
+ else {
+ activate_databrowse((ID *)lockpoin, ID_MA, 0, B_MATBROWSE, menunr, do_global_buttons);
+ }
+ return;
+ }
+
+ if(*menunr < 0) return;
+
+ if(0) { /* future pin */
+
+ }
+ else {
+
+ ma= give_current_material(ob, ob->actcol);
+ nr= 1;
+
+ id= (ID *)ma;
+
+ idtest= G.main->mat.first;
+ while(idtest) {
+ if(nr== *menunr) {
+ break;
+ }
+ nr++;
+ idtest= idtest->next;
+ }
+ if(idtest==0) { /* new mat */
+ if(id) idtest= (ID *)copy_material((Material *)id);
+ else {
+ idtest= (ID *)add_material("Material");
+ }
+ idtest->us--;
+ }
+ if(idtest!=id) {
+ assign_material(ob, (Material *)idtest, ob->actcol);
+
+ BIF_undo_push("Browse Material");
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWNODE, 0);
+ BIF_preview_changed(ID_MA);
+ }
+
+ }
+ }
+ break;
+ case B_MATDELETE:
+ if(0) { /* future pin */
+
+ }
+ else {
+ ma= give_current_material(ob, ob->actcol);
+ if(ma) {
+ assign_material(ob, 0, ob->actcol);
+ BIF_undo_push("Unlink Material");
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWOOPS, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ BIF_preview_changed(ID_MA);
+ }
+ }
+ break;
+ case B_TEXDELETE:
+ if(G.buts->pin) {
+
+ }
+ else {
+ if(G.buts->texfrom==0) { /* from mat */
+ ma= give_current_material(ob, ob->actcol);
+ ma= editnode_get_active_material(ma);
+ if(ma) {
+ mtex= ma->mtex[ ma->texact ];
+ if(mtex) {
+ if(mtex->tex) mtex->tex->id.us--;
+ MEM_freeN(mtex);
+ ma->mtex[ ma->texact ]= NULL;
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWIPO, 0);
+ BIF_preview_changed(ID_MA);
+ }
+ }
+ }
+ else if(G.buts->texfrom==1) { /* from world */
+ wrld= G.scene->world;
+ if(wrld) {
+ mtex= wrld->mtex[ wrld->texact ];
+ if(mtex) {
+ if(mtex->tex) mtex->tex->id.us--;
+ MEM_freeN(mtex);
+ wrld->mtex[ wrld->texact ]= NULL;
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWIPO, 0);
+ BIF_preview_changed(ID_WO);
+ }
+ }
+ }
+ else if(G.buts->texfrom==2) { /* from lamp */
+ la= ob->data;
+ if(la && ob->type==OB_LAMP) { /* to be sure */
+ mtex= la->mtex[ la->texact ];
+ if(mtex) {
+ if(mtex->tex) mtex->tex->id.us--;
+ MEM_freeN(mtex);
+ la->mtex[ la->texact ]= NULL;
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWIPO, 0);
+ BIF_preview_changed(ID_LA);
+ }
+ }
+ }
+ else { /* from brush */
+ br= G.scene->toolsettings->imapaint.brush;
+ if(G.f & G_SCULPTMODE) {
+ sculptmode_rem_tex(NULL, NULL);
+ allqueue(REDRAWBUTSSHADING, 0);
+ } else if(br) {
+ mtex= br->mtex[ br->texact ];
+ if(mtex) {
+ if(mtex->tex) mtex->tex->id.us--;
+ MEM_freeN(mtex);
+ br->mtex[ br->texact ]= NULL;
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWIMAGE, 0);
+ allqueue(REDRAWIPO, 0);
+ /*BIF_preview_changed(ID_BR);*/
+ }
+ }
+ }
+ BIF_undo_push("Unlink Texture");
+ }
+ break;
+ case B_EXTEXBROWSE:
+ case B_TEXBROWSE:
+
+ if(G.buts->texnr== -2) {
+
+ id= G.buts->lockpoin;
+ if(event==B_EXTEXBROWSE) {
+ id= NULL;
+ ma= give_current_material(ob, ob->actcol);
+ ma= editnode_get_active_material(ma);
+ if(ma) {
+ mtex= ma->mtex[ ma->texact ];
+ if(mtex) id= (ID *)mtex->tex;
+ }
+ }
+ if(G.qual & LR_CTRLKEY) {
+ activate_databrowse_imasel(id, ID_TE, 0, B_TEXBROWSE, &G.buts->texnr, do_global_buttons);
+ }
+ else {
+ activate_databrowse(id, ID_TE, 0, B_TEXBROWSE, &G.buts->texnr, do_global_buttons);
+ }
+ return;
+ }
+ if(G.buts->texnr < 0) break;
+
+ if(G.buts->pin) {
+
+ }
+ else {
+ id= NULL;
+
+ ma= give_current_material(ob, ob->actcol);
+ ma= editnode_get_active_material(ma);
+ if(ma) {
+ mtex= ma->mtex[ ma->texact ];
+ if(mtex) id= (ID *)mtex->tex;
+ }
+
+ idtest= G.main->tex.first;
+ while(idtest) {
+ if(nr==G.buts->texnr) {
+ break;
+ }
+ nr++;
+ idtest= idtest->next;
+ }
+ if(idtest==0) { /* new tex */
+ if(id) idtest= (ID *)copy_texture((Tex *)id);
+ else idtest= (ID *)add_texture("Tex");
+ idtest->us--;
+ }
+ if(idtest!=id && ma) {
+
+ if( ma->mtex[ma->texact]==0) ma->mtex[ma->texact]= add_mtex();
+
+ ma->mtex[ ma->texact ]->tex= (Tex *)idtest;
+ id_us_plus(idtest);
+ if(id) id->us--;
+
+ BIF_undo_push("Browse Texture");
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWOOPS, 0);
+ BIF_preview_changed(ID_MA);
+ }
+ }
+ break;
+ case B_ACTIONDELETE:
+ act=ob->action;
+
+ if (act)
+ act->id.us--;
+ ob->action=NULL;
+ if(ob->pose) { // clear flag, also used for draw colors
+ bPoseChannel *pchan;
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next)
+ pchan->flag= 0;
+ }
+ BIF_undo_push("Unlink Action");
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWNLA, 0);
+ allqueue(REDRAWIPO, 0);
+ break;
+ case B_ACTIONBROWSE:
+ if (!ob)
+ break;
+ act=ob->action;
+ id= (ID *)act;
+
+ if (G.saction->actnr== -2){
+ activate_databrowse((ID *)G.saction->action, ID_AC, 0, B_ACTIONBROWSE, &G.saction->actnr, do_global_buttons);
+ return;
+ }
+
+ if(G.saction->actnr < 0) break;
+
+ /* See if we have selected a valid action */
+ for (idtest= G.main->action.first; idtest; idtest= idtest->next) {
+ if(nr==G.saction->actnr) {
+ break;
+ }
+ nr++;
+
+ }
+
+ if(G.saction->pin) {
+ G.saction->action= (bAction *)idtest;
+ allqueue(REDRAWACTION, 0);
+ }
+ else {
+
+ /* Store current action */
+ if (!idtest) {
+ /* 'Add New' option:
+ * - make a copy of an exisiting action
+ * - or make a new empty action if no existing action
+ */
+ if (act) {
+ idtest= (ID *)copy_action(act);
+ }
+ else {
+ if (ID_OB==ob->type) {
+ /* for empties */
+ idtest=(ID *)add_empty_action("ObAction");
+ }
+ else if (ELEM(ob->type, OB_MESH, OB_LATTICE) && ob_get_key(ob)) {
+ /* shapekey - like if B_IPO_ACTION_KEY is triggered */
+ bActionChannel *achan;
+ Key *key= ob_get_key(ob);
+
+ ob->ipoflag |= OB_ACTION_KEY;
+
+ act = add_empty_action("ShapeAction");
+ idtest=(ID *)act;
+
+ achan= verify_action_channel(act, "Shape");
+ achan->flag = (ACHAN_HILIGHTED|ACHAN_SELECTED|ACHAN_EXPANDED|ACHAN_SHOWIPO);
+
+ if(achan->ipo==NULL && key->ipo) {
+ achan->ipo= key->ipo;
+ key->ipo= NULL;
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWOOPS, 0);
+ }
+ }
+ else {
+ /* a plain action */
+ idtest=(ID *)add_empty_action("Action");
+ }
+ }
+ idtest->us--;
+ }
+
+
+ if(idtest!=id && ob) {
+ act= (bAction *)idtest;
+
+ ob->action= act;
+ id_us_plus(idtest);
+
+ if(id) id->us--;
+
+ // Update everything
+ BIF_undo_push("Browse Action");
+ do_global_buttons (B_NEWFRAME);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWNLA, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWHEADERS, 0);
+ }
+ }
+
+ break;
+ case B_IPOBROWSE:
+
+ ipo= G.sipo->ipo;
+ from= G.sipo->from;
+ id= (ID *)ipo;
+ if(from==NULL) return;
+
+ if(G.sipo->menunr== -2) {
+ activate_databrowse((ID *)G.sipo->ipo, ID_IP, G.sipo->blocktype, B_IPOBROWSE, &G.sipo->menunr, do_global_buttons);
+ return;
+ }
+
+ if(G.sipo->menunr < 0) break;
+
+ idtest= G.main->ipo.first;
+ while(idtest) {
+ if( ((Ipo *)idtest)->blocktype == G.sipo->blocktype) {
+ if(nr==G.sipo->menunr) {
+ break;
+ }
+ nr++;
+ }
+ idtest= idtest->next;
+ }
+
+ if(G.sipo->pin) {
+ if(idtest) {
+ G.sipo->ipo= (Ipo *)idtest;
+ allspace(REMAKEIPO, 0); // in fact it should only do this one, but there is no function for it
+ }
+ }
+ else {
+ // assign the ipo to ...
+
+ if(idtest==0) {
+ if(ipo) idtest= (ID *)copy_ipo(ipo);
+ else {
+ nr= G.sipo->blocktype;
+ if(nr==ID_OB) idtest= (ID *)add_ipo("ObIpo", ID_OB);
+ else if(nr==ID_CO) idtest= (ID *)add_ipo("CoIpo", ID_CO);
+ else if(nr==ID_PO) idtest= (ID *)add_ipo("ActIpo", nr);
+ else if(nr==ID_MA) idtest= (ID *)add_ipo("MatIpo", nr);
+ else if(nr==ID_TE) idtest= (ID *)add_ipo("TexIpo", nr);
+ else if(nr==ID_SEQ) idtest= (ID *)add_ipo("MatSeq", nr);
+ else if(nr==ID_CU) idtest= (ID *)add_ipo("CuIpo", nr);
+ else if(nr==ID_KE) idtest= (ID *)add_ipo("KeyIpo", nr);
+ else if(nr==ID_WO) idtest= (ID *)add_ipo("WoIpo", nr);
+ else if(nr==ID_LA) idtest= (ID *)add_ipo("LaIpo", nr);
+ else if(nr==ID_CA) idtest= (ID *)add_ipo("CaIpo", nr);
+ else if(nr==ID_SO) idtest= (ID *)add_ipo("SndIpo", nr);
+ else if(nr==ID_FLUIDSIM) idtest= (ID *)add_ipo("FluidsimIpo", nr);
+ else error("Warn bugtracker!");
+ }
+ idtest->us--;
+ }
+ if(idtest!=id && from) {
+ spaceipo_assign_ipo(G.sipo, (Ipo *)idtest);
+
+ BIF_undo_push("Browse Ipo");
+ }
+ }
+ break;
+ case B_IPODELETE:
+ ipo= G.sipo->ipo;
+ from= G.sipo->from;
+
+ spaceipo_assign_ipo(G.sipo, NULL);
+
+ editipo_changed(G.sipo, 1); /* doredraw */
+
+ BIF_undo_push("Unlink Ipo");
+
+ break;
+ case B_WORLDBROWSE:
+
+ if(G.buts->menunr==-2) {
+ activate_databrowse((ID *)G.scene->world, ID_WO, 0, B_WORLDBROWSE, &G.buts->menunr, do_global_buttons);
+ break;
+ }
+
+ if(G.buts->menunr < 0) break;
+ /* no lock */
+
+ wrld= G.scene->world;
+ nr= 1;
+
+ id= (ID *)wrld;
+
+ idtest= G.main->world.first;
+ while(idtest) {
+ if(nr==G.buts->menunr) {
+ break;
+ }
+ nr++;
+ idtest= idtest->next;
+ }
+ if(idtest==0) { /* new world */
+ if(id) idtest= (ID *)copy_world((World *)id);
+ else idtest= (ID *)add_world("World");
+ idtest->us--;
+ }
+ if(idtest!=id) {
+ G.scene->world= (World *)idtest;
+ id_us_plus(idtest);
+ if(id) id->us--;
+
+ BIF_undo_push("Browse World");
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWOOPS, 0);
+ BIF_preview_changed(ID_WO);
+ }
+ break;
+ case B_WORLDDELETE:
+ if(G.scene->world) {
+ G.scene->world->id.us--;
+ G.scene->world= NULL;
+
+ BIF_undo_push("Unlink World");
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWIPO, 0);
+ }
+
+ break;
+ case B_WTEXBROWSE:
+
+ if(G.buts->texnr== -2) {
+ id= NULL;
+ wrld= G.scene->world;
+ if(wrld) {
+ mtex= wrld->mtex[ wrld->texact ];
+ if(mtex) id= (ID *)mtex->tex;
+ }
+
+ activate_databrowse((ID *)id, ID_TE, 0, B_WTEXBROWSE, &G.buts->texnr, do_global_buttons);
+ return;
+ }
+ if(G.buts->texnr < 0) break;
+
+ if(G.buts->pin) {
+
+ }
+ else {
+ id= NULL;
+
+ wrld= G.scene->world;
+ if(wrld) {
+ mtex= wrld->mtex[ wrld->texact ];
+ if(mtex) id= (ID *)mtex->tex;
+ }
+
+ idtest= G.main->tex.first;
+ while(idtest) {
+ if(nr==G.buts->texnr) {
+ break;
+ }
+ nr++;
+ idtest= idtest->next;
+ }
+ if(idtest==0) { /* new tex */
+ if(id) idtest= (ID *)copy_texture((Tex *)id);
+ else idtest= (ID *)add_texture("Tex");
+ idtest->us--;
+ }
+ if(idtest!=id && wrld) {
+
+ if( wrld->mtex[wrld->texact]==0) {
+ wrld->mtex[wrld->texact]= add_mtex();
+ wrld->mtex[wrld->texact]->texco= TEXCO_VIEW;
+ }
+ wrld->mtex[ wrld->texact ]->tex= (Tex *)idtest;
+ id_us_plus(idtest);
+ if(id) id->us--;
+
+ BIF_undo_push("Texture browse");
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWOOPS, 0);
+ BIF_preview_changed(ID_WO);
+ }
+ }
+ break;
+ case B_LAMPBROWSE:
+ /* no lock */
+ if(ob==0) return;
+ if(ob->type!=OB_LAMP) return;
+
+ if(G.buts->menunr== -2) {
+ activate_databrowse((ID *)G.buts->lockpoin, ID_LA, 0, B_LAMPBROWSE, &G.buts->menunr, do_global_buttons);
+ return;
+ }
+ if(G.buts->menunr < 0) break;
+
+ la= ob->data;
+ nr= 1;
+ id= (ID *)la;
+
+ idtest= G.main->lamp.first;
+ while(idtest) {
+ if(nr==G.buts->menunr) {
+ break;
+ }
+ nr++;
+ idtest= idtest->next;
+ }
+ if(idtest==0) { /* no new lamp */
+ return;
+ }
+ if(idtest!=id) {
+ ob->data= (Lamp *)idtest;
+ id_us_plus(idtest);
+ if(id) id->us--;
+
+ BIF_undo_push("Lamp browse");
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWOOPS, 0);
+ BIF_preview_changed(ID_LA);
+ }
+ break;
+
+ case B_LTEXBROWSE:
+
+ if(ob==0) return;
+ if(ob->type!=OB_LAMP) return;
+
+ if(G.buts->texnr== -2) {
+ id= NULL;
+ la= ob->data;
+ mtex= la->mtex[ la->texact ];
+ if(mtex) id= (ID *)mtex->tex;
+
+ activate_databrowse(id, ID_TE, 0, B_LTEXBROWSE, &G.buts->texnr, do_global_buttons);
+ return;
+ }
+ if(G.buts->texnr < 0) break;
+
+ if(G.buts->pin) {
+
+ }
+ else {
+ id= NULL;
+
+ la= ob->data;
+ mtex= la->mtex[ la->texact ];
+ if(mtex) id= (ID *)mtex->tex;
+
+ idtest= G.main->tex.first;
+ while(idtest) {
+ if(nr==G.buts->texnr) {
+ break;
+ }
+ nr++;
+ idtest= idtest->next;
+ }
+ if(idtest==0) { /* new tex */
+ if(id) idtest= (ID *)copy_texture((Tex *)id);
+ else idtest= (ID *)add_texture("Tex");
+ idtest->us--;
+ }
+ if(idtest!=id && la) {
+
+ if( la->mtex[la->texact]==0) {
+ la->mtex[la->texact]= add_mtex();
+ la->mtex[la->texact]->texco= TEXCO_GLOB;
+ }
+ la->mtex[ la->texact ]->tex= (Tex *)idtest;
+ id_us_plus(idtest);
+ if(id) id->us--;
+
+ BIF_undo_push("Texture Browse");
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWOOPS, 0);
+ BIF_preview_changed(ID_LA);
+ }
+ }
+ break;
+
+ case B_IMAGEDELETE:
+ if(G.sima->image && (G.sima->image->type == IMA_TYPE_R_RESULT || G.sima->image->type == IMA_TYPE_COMPOSITE)) {
+ /* Run if G.sima is render, remove the render and display the meshes image if it exists */
+ G.sima->image= NULL;
+ what_image(G.sima);
+ allqueue(REDRAWIMAGE, 0);
+ } else {
+ /* Run on non render images, unlink normally */
+ image_changed(G.sima, NULL);
+ BIF_undo_push("Unlink Image");
+ allqueue(REDRAWIMAGE, 0);
+ }
+ break;
+
+ case B_AUTOMATNAME:
+ /* this is called now from Node editor too, buttons might not exist */
+ if(curarea->spacetype==SPACE_NODE) {
+ SpaceNode *snode= curarea->spacedata.first;
+ automatname((Material *)snode->id);
+ }
+ else if(G.buts) {
+ automatname(G.buts->lockpoin);
+ }
+ else return;
+
+ BIF_undo_push("Auto name");
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWNODE, 0);
+ allqueue(REDRAWOOPS, 0);
+ break;
+ case B_AUTOTEXNAME:
+ if(G.buts->mainb==CONTEXT_SHADING) {
+ if(G.buts->tab[CONTEXT_SHADING]==TAB_SHADING_TEX) {
+ autotexname(G.buts->lockpoin);
+ }
+ else if(G.buts->tab[CONTEXT_SHADING]==TAB_SHADING_MAT) {
+ ma= G.buts->lockpoin;
+ if(ma->mtex[ ma->texact]) autotexname(ma->mtex[ma->texact]->tex);
+ }
+ else if(G.buts->tab[CONTEXT_SHADING]==TAB_SHADING_WORLD) {
+ wrld= G.buts->lockpoin;
+ if(wrld->mtex[ wrld->texact]) autotexname(wrld->mtex[wrld->texact]->tex);
+ }
+ else if(G.buts->tab[CONTEXT_SHADING]==TAB_SHADING_LAMP) {
+ la= G.buts->lockpoin;
+ if(la->mtex[ la->texact]) autotexname(la->mtex[la->texact]->tex);
+ }
+ BIF_undo_push("Auto name");
+ allqueue(REDRAWBUTSSHADING, 0);
+ allqueue(REDRAWOOPS, 0);
+ allqueue(REDRAWIMAGE, 0);
+ }
+ else if(G.buts->mainb==CONTEXT_EDITING) {
+ SculptData *sd= &G.scene->sculptdata;
+ if(sd && sd->texact != -1) {
+ if(sd->mtex[sd->texact]) autotexname(sd->mtex[sd->texact]->tex);
+
+ BIF_undo_push("Auto name");
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWOOPS, 0);
+ }
+ }
+ break;
+
+ case B_RESETAUTOSAVE:
+ reset_autosave();
+ allqueue(REDRAWINFO, 0);
+ break;
+ case B_SOUNDTOGGLE:
+ SYS_WriteCommandLineInt(SYS_GetSystem(), "noaudio", (U.gameflags & USER_DISABLE_SOUND));
+ break;
+ case B_SHOWSPLASH:
+ show_splash();
+ break;
+ case B_MIPMAPCHANGED:
+ set_mipmap(!(U.gameflags & USER_DISABLE_MIPMAP));
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+ case B_GLRESLIMITCHANGED:
+ free_all_realtime_images(); /* force reloading with new res limit */
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+ case B_NEWSPACE:
+ newspace(curarea, curarea->butspacetype);
+ break;
+ case B_LOADTEMP: /* is button from space.c */
+ BIF_read_autosavefile();
+ break;
+
+ case B_USERPREF:
+ allqueue(REDRAWINFO, 0);
+ break;
+
+ case B_DRAWINFO: /* is button from space.c *info* */
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+
+ case B_PLAINMENUS: /* is button from space.c *info* */
+ reset_toolbox();
+ break;
+
+ case B_FLIPINFOMENU: /* is button from space.c *info* */
+ scrarea_queue_headredraw(curarea);
+ break;
+
+#if 0
+//#ifdef _WIN32 // FULLSCREEN
+ case B_FLIPFULLSCREEN:
+ if(U.uiflag & USER_FLIPFULLSCREEN)
+ U.uiflag &= ~USER_FLIPFULLSCREEN;
+ else
+ U.uiflag |= USER_FLIPFULLSCREEN;
+ mainwindow_toggle_fullscreen((U.uiflag & USER_FLIPFULLSCREEN));
+ break;
+#endif
+
+ /* Fileselect windows for user preferences file paths */
+
+ /* yafray: xml export dir. select */
+ case B_YAFRAYDIRFILESEL: /* space.c */
+ if(curarea->spacetype==SPACE_INFO) {
+ sa= closest_bigger_area();
+ areawinset(sa->win);
+ }
+
+ activate_fileselect(FILE_SPECIAL, "SELECT YFEXPORT PATH", U.yfexportdir, filesel_u_yfexportdir);
+ break;
+
+ case B_FONTDIRFILESEL: /* is button from space.c *info* */
+ if(curarea->spacetype==SPACE_INFO) {
+ sa= closest_bigger_area();
+ areawinset(sa->win);
+ }
+
+ activate_fileselect(FILE_SPECIAL, "SELECT FONT PATH", U.fontdir, filesel_u_fontdir);
+ break;
+
+ case B_TEXTUDIRFILESEL: /* is button from space.c *info* */
+ if(curarea->spacetype==SPACE_INFO) {
+ sa= closest_bigger_area();
+ areawinset(sa->win);
+ }
+
+ activate_fileselect(FILE_SPECIAL, "SELECT TEXTURE PATH", U.textudir, filesel_u_textudir);
+ break;
+
+ case B_PLUGTEXDIRFILESEL: /* is button form space.c *info* */
+ if(curarea->spacetype==SPACE_INFO) {
+ sa= closest_bigger_area();
+ areawinset(sa->win);
+ }
+
+ activate_fileselect(FILE_SPECIAL, "SELECT TEX PLUGIN PATH", U.plugtexdir, filesel_u_plugtexdir);
+ break;
+
+ case B_PLUGSEQDIRFILESEL: /* is button from space.c *info* */
+ if(curarea->spacetype==SPACE_INFO) {
+ sa= closest_bigger_area();
+ areawinset(sa->win);
+ }
+
+ activate_fileselect(FILE_SPECIAL, "SELECT SEQ PLUGIN PATH", U.plugseqdir, filesel_u_plugseqdir);
+ break;
+
+ case B_RENDERDIRFILESEL: /* is button from space.c *info* */
+ if(curarea->spacetype==SPACE_INFO) {
+ sa= closest_bigger_area();
+ areawinset(sa->win);
+ }
+
+ activate_fileselect(FILE_SPECIAL, "SELECT RENDER PATH", U.renderdir, filesel_u_renderdir);
+ break;
+
+ case B_PYMENUEVAL: /* is button from space.c *info* */
+ waitcursor( 1 ); /* can take some time */
+ BPyMenu_RemoveAllEntries(); /* free old data */
+ if (BPyMenu_Init(1) == -1) { /* re-eval scripts registration in menus */
+ waitcursor( 0 );
+ error("Invalid scripts dir: check console");
+ }
+ waitcursor( 0 );
+ break;
+ case B_PYTHONDIRFILESEL: /* is button from space.c *info* */
+ if(curarea->spacetype==SPACE_INFO) {
+ sa= closest_bigger_area();
+ areawinset(sa->win);
+ }
+
+ activate_fileselect(FILE_SPECIAL, "SELECT SCRIPT PATH", U.pythondir, filesel_u_pythondir);
+ break;
+
+ case B_SOUNDDIRFILESEL: /* is button from space.c *info* */
+ if(curarea->spacetype==SPACE_INFO) {
+ sa= closest_bigger_area();
+ areawinset(sa->win);
+ }
+
+ activate_fileselect(FILE_SPECIAL, "SELECT SOUND PATH", U.sounddir, filesel_u_sounddir);
+ break;
+
+ case B_TEMPDIRFILESEL: /* is button from space.c *info* */
+ if(curarea->spacetype==SPACE_INFO) {
+ sa= closest_bigger_area();
+ areawinset(sa->win);
+ }
+
+ activate_fileselect(FILE_SPECIAL, "SELECT TEMP FILE PATH", U.tempdir, filesel_u_tempdir);
+ break;
+
+ /* END Fileselect windows for user preferences file paths */
+
+#ifdef INTERNATIONAL
+ case B_LOADUIFONT: /* is button from space.c *info* */
+ if(curarea->spacetype==SPACE_INFO) {
+ sa= closest_bigger_area();
+ areawinset(sa->win);
+ }
+ BLI_make_file_string("/", buf, U.fontdir, U.fontname);
+ activate_fileselect(FILE_SPECIAL, "LOAD UI FONT", buf, set_interface_font);
+ break;
+
+ case B_SETLANGUAGE: /* is button from space.c *info* */
+ lang_setlanguage();
+ allqueue(REDRAWALL, 0);
+ break;
+
+ case B_SETFONTSIZE: /* is button from space.c *info* */
+ refresh_interface_font();
+ FTF_SetSize(U.fontsize);
+ allqueue(REDRAWALL, 0);
+ break;
+
+ case B_SETTRANSBUTS: /* is button from space.c *info* */
+ allqueue(REDRAWALL, 0);
+ break;
+
+ case B_RESTOREFONT: /* is button from space.c *info* */
+ U.fontsize= 0;
+ start_interface_font();
+ allqueue(REDRAWALL, 0);
+ break;
+
+ case B_USETEXTUREFONT: /* is button from space.c *info* */
+ refresh_interface_font();
+ allqueue(REDRAWALL, 0);
+ break;
+
+ case B_DOLANGUIFONT: /* is button from space.c *info* */
+ if(U.transopts & USER_DOTRANSLATE)
+ start_interface_font();
+ else
+ G.ui_international = FALSE;
+ allqueue(REDRAWALL, 0);
+ break;
+#endif
+
+ case B_FULL:
+ if(curarea->spacetype!=SPACE_INFO) {
+ area_fullscreen();
+ }
+ break;
+
+ case B_IDNAME:
+ /* changing a metaballs name, sadly enough,
+ * can require it to be updated because its
+ * basis might have changed... -zr
+ */
+ if (ob && ob->type==OB_MBALL) {
+ DAG_scene_sort(G.scene);
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ }
+ /* redraw because name has changed: new pup */
+ scrarea_queue_headredraw(curarea);
+ allqueue(REDRAWINFO, 1);
+ allqueue(REDRAWOOPS, 1);
+ allqueue(REDRAWACTION, 1);
+ allqueue(REDRAWNLA, 1);
+ /* name scene also in set PUPmenu */
+ allqueue(REDRAWBUTSALL, 0);
+ allqueue(REDRAWIMAGE, 0);
+ allqueue(REDRAWHEADERS, 0);
+ break;
+
+ case B_KEEPDATA:
+ /* keep datablock. similar to pressing FKEY in a fileselect window
+ * maybe we can move that stuff to a seperate function? -- sg
+ */
+ if (curarea->spacetype==SPACE_BUTS) {
+ id= (ID *)G.buts->lockpoin;
+ } else if(curarea->spacetype==SPACE_IPO) {
+ id = (ID *)G.sipo->ipo;
+ } else if(curarea->spacetype==SPACE_NODE) {
+ id = ((SpaceNode *)curarea->spacedata.first)->id;
+ } /* similar for other spacetypes ? */
+ if (id) {
+ if( id->flag & LIB_FAKEUSER) {
+ id->flag -= LIB_FAKEUSER;
+ id->us--;
+ } else {
+ id->flag |= LIB_FAKEUSER;
+ id->us++;
+ }
+ }
+ allqueue(REDRAWHEADERS, 0);
+
+ break;
+
+ }
+}
+
+
+void do_global_buttons2(short event)
+{
+ Base *base;
+ Object *ob;
+ Material *ma;
+ MTex *mtex;
+ Mesh *me;
+ Curve *cu;
+ MetaBall *mb;
+ Ipo *ipo;
+ Lamp *la;
+ Lattice *lt;
+ World *wrld;
+ ID *idfrom;
+ bAction *act;
+ Brush *br;
+
+ /* general: Single User is allowed when from==LOCAL
+ * Make Local is allowed when (from==LOCAL && id==LIB)
+ */
+
+ if(event<B_LOCAL_ALONE) return;
+
+ ob= OBACT;
+
+ switch(event) {
+
+ case B_LAMPALONE:
+ if(ob && ob->id.lib==0) {
+ la= ob->data;
+ if(la->id.us>1) {
+ if(okee("Single user")) {
+ ob->data= copy_lamp(la);
+ la->id.us--;
+ }
+ }
+ }
+ break;
+ case B_LAMPLOCAL:
+ if(ob && ob->id.lib==0) {
+ la= ob->data;
+ if(la->id.lib) {
+ if(okee("Make local")) {
+ make_local_lamp(la);
+ }
+ }
+ }
+ break;
+
+ case B_ARMLOCAL:
+ if (ob&&ob->id.lib==0){
+ bArmature *arm=ob->data;
+ if (arm->id.lib){
+ if(okee("Make local")) {
+ make_local_armature(arm);
+ }
+ }
+ }
+ break;
+ case B_ARMALONE:
+ if(ob && ob->id.lib==0) {
+ bArmature *arm=ob->data;
+ if(arm->id.us>1) {
+ if(okee("Single user")) {
+ ob->data= copy_armature(arm);
+ armature_rebuild_pose(ob, ob->data);
+ arm->id.us--;
+ }
+ }
+ }
+ break;
+ case B_ACTLOCAL:
+ if(ob && ob->id.lib==0) {
+ act= ob->action;
+ if(act->id.lib) {
+ if(okee("Make local")) {
+ make_local_action(act);
+ allqueue(REDRAWACTION,0);
+ }
+ }
+ }
+ break;
+ case B_ACTALONE:
+ if(ob && ob->id.lib==0) {
+ act= ob->action;
+
+ if(act->id.us>1) {
+ if(okee("Single user")) {
+ ob->action=copy_action(act);
+ act->id.us--;
+ allqueue(REDRAWACTION, 0);
+ }
+ }
+ }
+ break;
+
+ case B_CAMERAALONE:
+ if(ob && ob->id.lib==0) {
+ Camera *ca= ob->data;
+ if(ca->id.us>1) {
+ if(okee("Single user")) {
+ ob->data= copy_camera(ca);
+ ca->id.us--;
+ }
+ }
+ }
+ break;
+ case B_CAMERALOCAL:
+ if(ob && ob->id.lib==0) {
+ Camera *ca= ob->data;
+ if(ca->id.lib) {
+ if(okee("Make local")) {
+ make_local_camera(ca);
+ }
+ }
+ }
+ break;
+ case B_WORLDALONE:
+ wrld= G.scene->world;
+ if(wrld->id.us>1) {
+ if(okee("Single user")) {
+ G.scene->world= copy_world(wrld);
+ wrld->id.us--;
+ }
+ }
+ break;
+ case B_WORLDLOCAL:
+ wrld= G.scene->world;
+ if(wrld && wrld->id.lib) {
+ if(okee("Make local")) {
+ make_local_world(wrld);
+ }
+ }
+ break;
+
+ case B_LATTALONE:
+ if(ob && ob->id.lib==0) {
+ lt= ob->data;
+ if(lt->id.us>1) {
+ if(okee("Single user")) {
+ ob->data= copy_lattice(lt);
+ lt->id.us--;
+ }
+ }
+ }
+ break;
+ case B_LATTLOCAL:
+ if(ob && ob->id.lib==0) {
+ lt= ob->data;
+ if(lt->id.lib) {
+ if(okee("Make local")) {
+ make_local_lattice(lt);
+ }
+ }
+ }
+ break;
+
+ case B_MATALONE:
+ if(ob==0) return;
+ ma= give_current_material(ob, ob->actcol);
+ idfrom= material_from(ob, ob->actcol);
+ if(idfrom && idfrom->lib==0) {
+ if(ma->id.us>1) {
+ if(okee("Single user")) {
+ ma= copy_material(ma);
+ ma->id.us= 0;
+ assign_material(ob, ma, ob->actcol);
+ }
+ }
+ }
+ break;
+ case B_MATLOCAL:
+ if(ob==0) return;
+ idfrom= material_from(ob, ob->actcol);
+ if(idfrom->lib==0) {
+ ma= give_current_material(ob, ob->actcol);
+ if(ma && ma->id.lib) {
+ if(okee("Make local")) {
+ make_local_material(ma);
+ }
+ }
+ }
+ break;
+
+ case B_MESHLOCAL:
+ if(ob && ob->id.lib==0) {
+ me= ob->data;
+ if(me && me->id.lib) {
+ if(okee("Make local")) {
+ make_local_mesh(me);
+ make_local_key( me->key );
+
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ }
+ }
+ }
+ break;
+
+ case B_MBALLALONE:
+ if(ob && ob->id.lib==0) {
+ mb= ob->data;
+ if(mb->id.us>1) {
+ if(okee("Single user")) {
+ ob->data= copy_mball(mb);
+ mb->id.us--;
+ if(ob==G.obedit) allqueue(REDRAWVIEW3D, 0);
+ }
+ }
+ }
+ break;
+ case B_MBALLLOCAL:
+ if(ob && ob->id.lib==0) {
+ mb= ob->data;
+ if(mb->id.lib) {
+ if(okee("Make local")) {
+ make_local_mball(mb);
+ }
+ }
+ }
+ break;
+
+ case B_CURVEALONE:
+ if(ob && ob->id.lib==0) {
+ cu= ob->data;
+ if(cu->id.us>1) {
+ if(okee("Single user")) {
+ ob->data= copy_curve(cu);
+ cu->id.us--;
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ if(ob==G.obedit) allqueue(REDRAWVIEW3D, 0);
+ }
+ }
+ }
+ break;
+ case B_CURVELOCAL:
+ if(ob && ob->id.lib==0) {
+ cu= ob->data;
+ if(cu->id.lib) {
+ if(okee("Make local")) {
+ make_local_curve(cu);
+ make_local_key( cu->key );
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ }
+ }
+ }
+ break;
+
+ case B_TEXALONE:
+ if(G.buts->texfrom==0) { /* from mat */
+ if(ob==0) return;
+ ma= give_current_material(ob, ob->actcol);
+ ma= editnode_get_active_material(ma);
+ if(ma && ma->id.lib==0) {
+ mtex= ma->mtex[ ma->texact ];
+ if(mtex->tex && mtex->tex->id.us>1) {
+ if(okee("Single user")) {
+ mtex->tex->id.us--;
+ mtex->tex= copy_texture(mtex->tex);
+ }
+ }
+ }
+ }
+ else if(G.buts->texfrom==1) { /* from world */
+ wrld= G.scene->world;
+ if(wrld->id.lib==0) {
+ mtex= wrld->mtex[ wrld->texact ];
+ if(mtex->tex && mtex->tex->id.us>1) {
+ if(okee("Single user")) {
+ mtex->tex->id.us--;
+ mtex->tex= copy_texture(mtex->tex);
+ }
+ }
+ }
+ }
+ else if(G.buts->texfrom==2) { /* from lamp */
+ if(ob==0 || ob->type!=OB_LAMP) return;
+ la= ob->data;
+ if(la->id.lib==0) {
+ mtex= la->mtex[ la->texact ];
+ if(mtex->tex && mtex->tex->id.us>1) {
+ if(okee("Single user")) {
+ mtex->tex->id.us--;
+ mtex->tex= copy_texture(mtex->tex);
+ }
+ }
+ }
+ }
+ else if(G.buts->texfrom==3) { /* from brush */
+ br= G.scene->toolsettings->imapaint.brush;
+ if(br==0) return;
+ if(br->id.lib==0) {
+ mtex= br->mtex[ br->texact ];
+ if(mtex->tex && mtex->tex->id.us>1) {
+ if(okee("Single user")) {
+ mtex->tex->id.us--;
+ mtex->tex= copy_texture(mtex->tex);
+ allqueue(REDRAWIMAGE, 0);
+ }
+ }
+ }
+ }
+ break;
+ case B_TEXLOCAL:
+ if(G.buts->texfrom==0) { /* from mat */
+ if(ob==0) return;
+ ma= give_current_material(ob, ob->actcol);
+ ma= editnode_get_active_material(ma);
+ if(ma && ma->id.lib==0) {
+ mtex= ma->mtex[ ma->texact ];
+ if(mtex->tex && mtex->tex->id.lib) {
+ if(okee("Make local")) {
+ make_local_texture(mtex->tex);
+ }
+ }
+ }
+ }
+ else if(G.buts->texfrom==1) { /* from world */
+ wrld= G.scene->world;
+ if(wrld->id.lib==0) {
+ mtex= wrld->mtex[ wrld->texact ];
+ if(mtex->tex && mtex->tex->id.lib) {
+ if(okee("Make local")) {
+ make_local_texture(mtex->tex);
+ }
+ }
+ }
+ }
+ else if(G.buts->texfrom==2) { /* from lamp */
+ if(ob==0 || ob->type!=OB_LAMP) return;
+ la= ob->data;
+ if(la->id.lib==0) {
+ mtex= la->mtex[ la->texact ];
+ if(mtex->tex && mtex->tex->id.lib) {
+ if(okee("Make local")) {
+ make_local_texture(mtex->tex);
+ }
+ }
+ }
+ }
+ else if(G.buts->texfrom==3) { /* from brush */
+ br= G.scene->toolsettings->imapaint.brush;
+ if(br==0) return;
+ if(br->id.lib==0) {
+ mtex= br->mtex[ br->texact ];
+ if(mtex->tex && mtex->tex->id.lib) {
+ if(okee("Make local")) {
+ make_local_texture(mtex->tex);
+ allqueue(REDRAWIMAGE, 0);
+ }
+ }
+ }
+ }
+ break;
+
+ case B_IPOALONE:
+ ipo= G.sipo->ipo;
+ idfrom= G.sipo->from;
+
+ if(idfrom && idfrom->lib==NULL) {
+ if(ipo->id.us>1) {
+ if(okee("Single user")) {
+ ipo= copy_ipo(ipo);
+ ipo->id.us= 0; /* assign_ipo adds users, copy_ipo sets to 1 */
+ spaceipo_assign_ipo(G.sipo, ipo);
+ allqueue(REDRAWIPO, 0);
+ }
+ }
+ }
+ break;
+ case B_IPOLOCAL:
+ ipo= G.sipo->ipo;
+ idfrom= G.sipo->from;
+
+ if(idfrom && idfrom->lib==0) {
+ if(ipo->id.lib) {
+ if(okee("Make local")) {
+ make_local_ipo(ipo);
+ allqueue(REDRAWIPO, 0);
+ }
+ }
+ }
+ break;
+
+ case B_OBALONE:
+ if(G.scene->id.lib==0) {
+ if(ob->id.us>1) {
+ if(okee("Single user")) {
+ base= FIRSTBASE;
+ while(base) {
+ if(base->object==ob) {
+ base->object= copy_object(ob);
+ ob->id.us--;
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+ }
+ base= base->next;
+ }
+ }
+ }
+ }
+ break;
+ case B_OBLOCAL:
+ if(G.scene->id.lib==0) {
+ if(ob->id.lib) {
+ if(okee("Make local")) {
+ make_local_object(ob);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ }
+ }
+ break;
+ case B_MESHALONE:
+ if(ob && ob->id.lib==0) {
+
+ me= ob->data;
+
+ if(me && me->id.us>1) {
+ if(okee("Single user")) {
+ Mesh *men= copy_mesh(me);
+ men->id.us= 0;
+
+ set_mesh(ob, men);
+
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+
+ if(ob==G.obedit) allqueue(REDRAWVIEW3D, 0);
+ }
+ }
+ }
+ break;
+ }
+
+ BIF_undo_push("Make single user or local");
+ allqueue(REDRAWBUTSALL, 0);
+ allqueue(REDRAWOOPS, 0);
+}
+
+/* ******************** GENERAL ********************** */
+
+void do_headerbuttons(short event)
+{
+
+ if(event<=50) do_global_buttons2(event);
+ else if(event<=100) do_global_buttons(event);
+ else if(event<200) do_view3d_buttons(event);
+ else if(event<250) do_ipo_buttons(event);
+ else if(event<300) do_oops_buttons(event);
+ else if(event<350) do_info_buttons(event);
+ else if(event<400) do_image_buttons(event);
+ else if(event<450) do_buts_buttons(event);
+ else if(event<500) do_imasel_buttons(event);
+ else if(event<525) do_text_buttons(event);
+ else if(event<550) do_script_buttons(event);
+ else if(event<600) do_file_buttons(event);
+ else if(event<650) do_seq_buttons(event);
+ else if(event<700) do_sound_buttons(event);
+ else if(event<750) do_action_buttons(event);
+ else if(event<800) do_time_buttons(curarea, event);
+ else if(event<850) do_nla_buttons(event);
+ else if(event<900) do_node_buttons(curarea, event);
+ else if(event>=REDRAWVIEW3D) allqueue(event, 0);
+}
+
diff --git a/source/blender/src/imagepaint.c b/source/blender/src/imagepaint.c
new file mode 100644
index 00000000000..7b8efd0ed75
--- /dev/null
+++ b/source/blender/src/imagepaint.c
@@ -0,0 +1,790 @@
+/**
+ * $Id$
+ * imagepaint.c
+ *
+ * Functions to paint images in 2D and 3D.
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Jens Ole Wund (bjornmose)
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#ifdef WIN32
+#include "BLI_winstuff.h"
+#endif
+#include "BLI_arithb.h"
+#include "PIL_time.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_image_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_brush.h"
+#include "BKE_global.h"
+#include "BKE_image.h"
+#include "BKE_mesh.h"
+#include "BKE_node.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_mywindow.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_toolbox.h"
+
+#include "BSE_drawipo.h"
+#include "BSE_node.h"
+#include "BSE_trans_types.h"
+#include "BSE_view.h"
+
+#include "BDR_drawmesh.h"
+#include "BDR_imagepaint.h"
+#include "BDR_vpaint.h"
+
+#include "GHOST_Types.h"
+
+#include "blendef.h"
+#include "butspace.h"
+#include "mydevice.h"
+
+/* Defines and Structs */
+
+#define IMAPAINT_FLOAT_TO_CHAR(f) ((char)(f*255))
+#define IMAPAINT_CHAR_TO_FLOAT(c) (c/255.0f)
+
+#define IMAPAINT_FLOAT_RGB_TO_CHAR(c, f) { c[0]=IMAPAINT_FLOAT_TO_CHAR(f[0]); \
+ c[1]=IMAPAINT_FLOAT_TO_CHAR(f[1]); c[2]=IMAPAINT_FLOAT_TO_CHAR(f[2]); }
+#define IMAPAINT_CHAR_RGB_TO_FLOAT(f, c) { f[0]=IMAPAINT_CHAR_TO_FLOAT(c[0]); \
+ f[1]=IMAPAINT_CHAR_TO_FLOAT(c[1]); f[2]=IMAPAINT_CHAR_TO_FLOAT(c[2]); }
+#define IMAPAINT_FLOAT_RGB_COPY(a, b) VECCOPY(a, b)
+
+#define IMAPAINT_TILE_BITS 6
+#define IMAPAINT_TILE_SIZE (1 << IMAPAINT_TILE_BITS)
+#define IMAPAINT_TILE_NUMBER(size) (((size)+IMAPAINT_TILE_SIZE-1) >> IMAPAINT_TILE_BITS)
+
+typedef struct ImagePaintState {
+ Brush *brush;
+ short tool, blend;
+ Image *image;
+ ImBuf *canvas;
+ ImBuf *clonecanvas;
+ short clonefreefloat;
+ char *warnpackedfile;
+ char *warnmultifile;
+
+ /* texture paint only */
+ Object *ob;
+ Mesh *me;
+ int faceindex;
+ float uv[2];
+} ImagePaintState;
+
+typedef struct ImagePaintUndo {
+ Image *image;
+ ImBuf *tilebuf;
+ void **tiles;
+ int xtiles, ytiles;
+} ImagePaintUndo;
+
+typedef struct ImagePaintPartialRedraw {
+ int x1, y1, x2, y2;
+ int enabled;
+} ImagePaintPartialRedraw;
+
+static ImagePaintUndo imapaintundo = {NULL, NULL, NULL, 0, 0};
+static ImagePaintPartialRedraw imapaintpartial = {0, 0, 0, 0, 0};
+
+static void init_imagapaint_undo(Image *ima, ImBuf *ibuf)
+{
+ int xt, yt;
+
+ imapaintundo.image = ima;
+ imapaintundo.xtiles = xt = IMAPAINT_TILE_NUMBER(ibuf->x);
+ imapaintundo.ytiles = yt = IMAPAINT_TILE_NUMBER(ibuf->y);
+ imapaintundo.tiles = MEM_callocN(sizeof(void*)*xt*yt, "ImagePaintUndoTiles");
+ imapaintundo.tilebuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE,
+ ibuf->depth, (ibuf->rect_float)? IB_rectfloat: IB_rect, 0);
+}
+
+static void imapaint_copy_tile(ImBuf *ibuf, int tile, int x, int y, int swapundo)
+{
+ IMB_rectcpy(imapaintundo.tilebuf, ibuf, 0, 0, x*IMAPAINT_TILE_SIZE,
+ y*IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE);
+
+ if (imapaintundo.tilebuf->rect_float)
+ SWAP(void*, imapaintundo.tilebuf->rect_float, imapaintundo.tiles[tile])
+ else
+ SWAP(void*, imapaintundo.tilebuf->rect, imapaintundo.tiles[tile])
+
+ if (swapundo)
+ IMB_rectcpy(ibuf, imapaintundo.tilebuf, x*IMAPAINT_TILE_SIZE,
+ y*IMAPAINT_TILE_SIZE, 0, 0, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE);
+}
+
+static void imapaint_clear_partial_redraw()
+{
+ memset(&imapaintpartial, 0, sizeof(imapaintpartial));
+}
+
+static void imapaint_dirty_region(Image *ima, ImBuf *ibuf, int x, int y, int w, int h)
+{
+ int srcx= 0, srcy= 0, origx, tile, allocsize;
+
+ IMB_rectclip(ibuf, NULL, &x, &y, &srcx, &srcy, &w, &h);
+
+ if (w == 0 || h == 0)
+ return;
+
+ if (!imapaintpartial.enabled) {
+ imapaintpartial.x1 = x;
+ imapaintpartial.y1 = y;
+ imapaintpartial.x2 = x+w;
+ imapaintpartial.y2 = y+h;
+ imapaintpartial.enabled = 1;
+ }
+ else {
+ imapaintpartial.x1 = MIN2(imapaintpartial.x1, x);
+ imapaintpartial.y1 = MIN2(imapaintpartial.y1, y);
+ imapaintpartial.x2 = MAX2(imapaintpartial.x2, x+w);
+ imapaintpartial.y2 = MAX2(imapaintpartial.y2, y+h);
+ }
+
+ w = ((x + w - 1) >> IMAPAINT_TILE_BITS);
+ h = ((y + h - 1) >> IMAPAINT_TILE_BITS);
+ origx = (x >> IMAPAINT_TILE_BITS);
+ y = (y >> IMAPAINT_TILE_BITS);
+
+ for (; y <= h; y++) {
+ for (x=origx; x <= w; x++) {
+ if (ima != imapaintundo.image) {
+ free_imagepaint();
+ init_imagapaint_undo(ima, ibuf);
+ }
+
+ tile = y*imapaintundo.xtiles + x;
+ if (!imapaintundo.tiles[tile]) {
+ allocsize= (ibuf->rect_float)? sizeof(float): sizeof(char);
+ imapaintundo.tiles[tile]= MEM_mapallocN(allocsize*4*
+ IMAPAINT_TILE_SIZE*IMAPAINT_TILE_SIZE, "ImagePaintUndoTile");
+ imapaint_copy_tile(ibuf, tile, x, y, 0);
+ }
+ }
+ }
+
+ ibuf->userflags |= IB_BITMAPDIRTY;
+}
+
+static void imapaint_image_update(Image *image, ImBuf *ibuf, short texpaint)
+{
+ if(ibuf->rect_float)
+ imb_freerectImBuf(ibuf); /* force recreate of char rect */
+ if(ibuf->mipmap[0])
+ imb_freemipmapImBuf(ibuf);
+
+ /* todo: should set_tpage create ->rect? */
+ if(texpaint || G.sima->lock) {
+ int w = imapaintpartial.x2 - imapaintpartial.x1;
+ int h = imapaintpartial.y2 - imapaintpartial.y1;
+ update_realtime_image(image, imapaintpartial.x1, imapaintpartial.y1, w, h);
+ }
+}
+
+/* note; gets called for both 2d image paint and 3d texture paint. in the
+ latter case image may be NULL and G.sima may not exist */
+static void imapaint_redraw(int final, int texpaint, Image *image)
+{
+ if(final) {
+ if(texpaint)
+ allqueue(REDRAWIMAGE, 0);
+ else if(!G.sima->lock) {
+ if(image)
+ free_realtime_image(image); /* force OpenGL reload */
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ allqueue(REDRAWHEADERS, 0);
+
+ if(!texpaint && image) {
+ /* after paint, tag Image or RenderResult nodes changed */
+ if(G.scene->nodetree) {
+ imagepaint_composite_tags(G.scene->nodetree, image, &G.sima->iuser);
+ }
+ /* signal composite (hurmf, need an allqueue?) */
+ if(G.sima->lock) {
+ ScrArea *sa;
+ for(sa=G.curscreen->areabase.first; sa; sa= sa->next) {
+ if(sa->spacetype==SPACE_NODE) {
+ if(((SpaceNode *)sa->spacedata.first)->treetype==NTREE_COMPOSIT) {
+ addqueue(sa->win, UI_BUT_EVENT, B_NODE_TREE_EXEC);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if(!texpaint && G.sima->lock)
+ force_draw_plus(SPACE_VIEW3D, 0);
+ else
+ force_draw(0);
+}
+
+void imagepaint_undo()
+{
+ Image *ima= imapaintundo.image;
+ ImBuf *ibuf= BKE_image_get_ibuf(ima, G.sima?&G.sima->iuser:NULL);
+ int x, y, tile;
+
+ if (!ima || !ibuf || !(ibuf->rect || ibuf->rect_float))
+ return;
+
+ for (tile = 0, y = 0; y < imapaintundo.ytiles; y++)
+ for (x = 0; x < imapaintundo.xtiles; x++, tile++)
+ if (imapaintundo.tiles[tile])
+ imapaint_copy_tile(ibuf, tile, x, y, 1);
+
+ free_realtime_image(ima); /* force OpenGL reload */
+ if(ibuf->rect_float)
+ imb_freerectImBuf(ibuf); /* force recreate of char rect */
+
+ allqueue(REDRAWIMAGE, 0);
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+void free_imagepaint()
+{
+ /* todo: does this need to be in the same places as editmode_undo_clear,
+ vertex paint isn't? */
+ int i, size = imapaintundo.xtiles*imapaintundo.ytiles;
+
+ if (imapaintundo.tiles) {
+ for (i = 0; i < size; i++)
+ if (imapaintundo.tiles[i])
+ MEM_freeN(imapaintundo.tiles[i]);
+ MEM_freeN(imapaintundo.tiles);
+ }
+ if (imapaintundo.tilebuf)
+ IMB_freeImBuf(imapaintundo.tilebuf);
+
+ memset(&imapaintundo, 0, sizeof(imapaintundo));
+}
+
+/* Image Paint Operations */
+
+static void imapaint_ibuf_get_set_rgb(ImBuf *ibuf, int x, int y, short torus, short set, float *rgb)
+{
+ if (torus) {
+ x %= ibuf->x;
+ if (x < 0) x += ibuf->x;
+ y %= ibuf->y;
+ if (y < 0) y += ibuf->y;
+ }
+
+ if (ibuf->rect_float) {
+ float *rrgbf = ibuf->rect_float + (ibuf->x*y + x)*4;
+
+ if (set) IMAPAINT_FLOAT_RGB_COPY(rrgbf, rgb)
+ else IMAPAINT_FLOAT_RGB_COPY(rgb, rrgbf)
+ }
+ else {
+ char *rrgb = (char*)ibuf->rect + (ibuf->x*y + x)*4;
+
+ if (set) IMAPAINT_FLOAT_RGB_TO_CHAR(rrgb, rgb)
+ else IMAPAINT_CHAR_RGB_TO_FLOAT(rgb, rrgb)
+ }
+}
+
+static int imapaint_ibuf_add_if(ImBuf *ibuf, unsigned int x, unsigned int y, float *outrgb, short torus)
+{
+ float inrgb[3];
+
+ if ((x >= ibuf->x) || (y >= ibuf->y)) {
+ if (torus) imapaint_ibuf_get_set_rgb(ibuf, x, y, 1, 0, inrgb);
+ else return 0;
+ }
+ else imapaint_ibuf_get_set_rgb(ibuf, x, y, 0, 0, inrgb);
+
+ outrgb[0] += inrgb[0];
+ outrgb[1] += inrgb[1];
+ outrgb[2] += inrgb[2];
+
+ return 1;
+}
+
+static void imapaint_lift_soften(ImBuf *ibuf, ImBuf *ibufb, int *pos, short torus)
+{
+ int x, y, count, xi, yi, xo, yo;
+ int out_off[2], in_off[2], dim[2];
+ float outrgb[3];
+
+ dim[0] = ibufb->x;
+ dim[1] = ibufb->y;
+ in_off[0] = pos[0];
+ in_off[1] = pos[1];
+ out_off[0] = out_off[1] = 0;
+
+ if (!torus) {
+ IMB_rectclip(ibuf, ibufb, &in_off[0], &in_off[1], &out_off[0],
+ &out_off[1], &dim[0], &dim[1]);
+
+ if ((dim[0] == 0) || (dim[1] == 0))
+ return;
+ }
+
+ for (y=0; y < dim[1]; y++) {
+ for (x=0; x < dim[0]; x++) {
+ /* get input pixel */
+ xi = in_off[0] + x;
+ yi = in_off[1] + y;
+
+ count = 1;
+ imapaint_ibuf_get_set_rgb(ibuf, xi, yi, torus, 0, outrgb);
+
+ count += imapaint_ibuf_add_if(ibuf, xi-1, yi-1, outrgb, torus);
+ count += imapaint_ibuf_add_if(ibuf, xi-1, yi , outrgb, torus);
+ count += imapaint_ibuf_add_if(ibuf, xi-1, yi+1, outrgb, torus);
+
+ count += imapaint_ibuf_add_if(ibuf, xi , yi-1, outrgb, torus);
+ count += imapaint_ibuf_add_if(ibuf, xi , yi+1, outrgb, torus);
+
+ count += imapaint_ibuf_add_if(ibuf, xi+1, yi-1, outrgb, torus);
+ count += imapaint_ibuf_add_if(ibuf, xi+1, yi , outrgb, torus);
+ count += imapaint_ibuf_add_if(ibuf, xi+1, yi+1, outrgb, torus);
+
+ outrgb[0] /= count;
+ outrgb[1] /= count;
+ outrgb[2] /= count;
+
+ /* write into brush buffer */
+ xo = out_off[0] + x;
+ yo = out_off[1] + y;
+ imapaint_ibuf_get_set_rgb(ibufb, xo, yo, 0, 1, outrgb);
+ }
+ }
+}
+
+static void imapaint_lift_smear(ImBuf *ibuf, ImBuf *ibufb, int *pos)
+{
+ IMB_rectblend_torus(ibufb, ibuf, 0, 0, pos[0], pos[1],
+ ibufb->x, ibufb->y, IMB_BLEND_COPY_RGB);
+}
+
+static ImBuf *imapaint_lift_clone(ImBuf *ibuf, ImBuf *ibufb, int *pos)
+{
+ /* note: allocImbuf returns zero'd memory, so regions outside image will
+ have zero alpha, and hence not be blended onto the image */
+ int w=ibufb->x, h=ibufb->y, destx=0, desty=0, srcx=pos[0], srcy=pos[1];
+ ImBuf *clonebuf= IMB_allocImBuf(w, h, ibufb->depth, ibufb->flags, 0);
+
+ IMB_rectclip(clonebuf, ibuf, &destx, &desty, &srcx, &srcy, &w, &h);
+ IMB_rectblend(clonebuf, ibuf, destx, desty, srcx, srcy, w, h,
+ IMB_BLEND_COPY_RGB);
+ IMB_rectblend(clonebuf, ibufb, destx, desty, destx, desty, w, h,
+ IMB_BLEND_COPY_ALPHA);
+
+ return clonebuf;
+}
+
+static void imapaint_convert_brushco(ImBuf *ibufb, float *pos, int *ipos)
+{
+ ipos[0]= (int)(pos[0] - ibufb->x/2);
+ ipos[1]= (int)(pos[1] - ibufb->y/2);
+}
+
+static int imapaint_paint_op(void *state, ImBuf *ibufb, float *lastpos, float *pos)
+{
+ ImagePaintState *s= ((ImagePaintState*)state);
+ ImBuf *clonebuf= NULL;
+ short torus= s->brush->flag & BRUSH_TORUS;
+ short blend= s->blend;
+ float *offset= s->brush->clone.offset;
+ float liftpos[2];
+ int bpos[2], blastpos[2], bliftpos[2];
+
+ imapaint_convert_brushco(ibufb, pos, bpos);
+
+ /* lift from canvas */
+ if(s->tool == PAINT_TOOL_SOFTEN) {
+ imapaint_lift_soften(s->canvas, ibufb, bpos, torus);
+ }
+ else if(s->tool == PAINT_TOOL_SMEAR) {
+ if (lastpos[0]==pos[0] && lastpos[1]==pos[1])
+ return 0;
+
+ imapaint_convert_brushco(ibufb, lastpos, blastpos);
+ imapaint_lift_smear(s->canvas, ibufb, blastpos);
+ }
+ else if(s->tool == PAINT_TOOL_CLONE && s->clonecanvas) {
+ liftpos[0]= pos[0] - offset[0]*s->canvas->x;
+ liftpos[1]= pos[1] - offset[1]*s->canvas->y;
+
+ imapaint_convert_brushco(ibufb, liftpos, bliftpos);
+ clonebuf= imapaint_lift_clone(s->clonecanvas, ibufb, bliftpos);
+ }
+
+ imapaint_dirty_region(s->image, s->canvas, bpos[0], bpos[1], ibufb->x, ibufb->y);
+
+ /* blend into canvas */
+ if(torus)
+ IMB_rectblend_torus(s->canvas, (clonebuf)? clonebuf: ibufb,
+ bpos[0], bpos[1], 0, 0, ibufb->x, ibufb->y, blend);
+ else
+ IMB_rectblend(s->canvas, (clonebuf)? clonebuf: ibufb,
+ bpos[0], bpos[1], 0, 0, ibufb->x, ibufb->y, blend);
+
+ if(clonebuf) IMB_freeImBuf(clonebuf);
+
+ return 1;
+}
+
+/* 2D ImagePaint */
+
+static void imapaint_compute_uvco(short *mval, float *uv)
+{
+ areamouseco_to_ipoco(G.v2d, mval, &uv[0], &uv[1]);
+}
+
+/* 3D TexturePaint */
+
+int facesel_face_pick(Mesh *me, short *mval, unsigned int *index, short rect);
+void texpaint_pick_uv(Object *ob, Mesh *mesh, unsigned int faceindex, short *xy, float *mousepos);
+
+static int texpaint_break_stroke(float *prevuv, float *fwuv, float *bkuv, float *uv)
+{
+ float d1[2], d2[2];
+ float mismatch = Vec2Lenf(fwuv, uv);
+ float len1 = Vec2Lenf(prevuv, fwuv);
+ float len2 = Vec2Lenf(bkuv, uv);
+
+ Vec2Subf(d1, fwuv, prevuv);
+ Vec2Subf(d2, uv, bkuv);
+
+ return ((Inp2f(d1, d2) < 0.0f) || (mismatch > MAX2(len1, len2)*2));
+}
+
+/* ImagePaint Common */
+
+static int imapaint_canvas_set(ImagePaintState *s, Image *ima)
+{
+ ImBuf *ibuf= BKE_image_get_ibuf(ima, G.sima?&G.sima->iuser:NULL);
+
+ /* verify that we can paint and set canvas */
+ if(ima->packedfile && ima->rr) {
+ s->warnpackedfile = ima->id.name + 2;
+ return 0;
+ }
+ else if(ibuf && ibuf->channels!=4) {
+ s->warnmultifile = ima->id.name + 2;
+ return 0;
+ }
+ else if(!ima || !ibuf || !(ibuf->rect || ibuf->rect_float))
+ return 0;
+
+ s->image= ima;
+ s->canvas= ibuf;
+
+ /* set clone canvas */
+ if(s->tool == PAINT_TOOL_CLONE) {
+ ima= s->brush->clone.image;
+ ibuf= BKE_image_get_ibuf(ima, G.sima?&G.sima->iuser:NULL);
+
+ if(!ima || !ibuf || !(ibuf->rect || ibuf->rect_float))
+ return 0;
+
+ s->clonecanvas= ibuf;
+
+ if(s->canvas->rect_float && !s->clonecanvas->rect_float) {
+ /* temporarily add float rect for cloning */
+ IMB_float_from_rect(s->clonecanvas);
+ s->clonefreefloat= 1;
+ }
+ else if(!s->canvas->rect_float && !s->clonecanvas->rect)
+ IMB_rect_from_float(s->clonecanvas);
+ }
+
+ return 1;
+}
+
+static void imapaint_canvas_free(ImagePaintState *s)
+{
+ if (s->clonefreefloat)
+ imb_freerectfloatImBuf(s->clonecanvas);
+}
+
+static int imapaint_paint_sub_stroke(ImagePaintState *s, BrushPainter *painter, Image *image, short texpaint, float *uv, double time, int update, float pressure)
+{
+ ImBuf *ibuf= BKE_image_get_ibuf(image, G.sima?&G.sima->iuser:NULL);
+ float pos[2];
+
+ if(!ibuf)
+ return 0;
+
+ pos[0] = uv[0]*ibuf->x;
+ pos[1] = uv[1]*ibuf->y;
+
+ brush_painter_require_imbuf(painter, ((ibuf->rect_float)? 1: 0), 0, 0);
+
+ if (brush_painter_paint(painter, imapaint_paint_op, pos, time, pressure, s)) {
+ if (update)
+ imapaint_image_update(image, ibuf, texpaint);
+ return 1;
+ }
+ else return 0;
+}
+
+static void imapaint_paint_stroke(ImagePaintState *s, BrushPainter *painter, short texpaint, short *prevmval, short *mval, double time, float pressure)
+{
+ Image *newimage = NULL;
+ float fwuv[2], bkuv[2], newuv[2];
+ unsigned int newfaceindex;
+ int breakstroke = 0, redraw = 0;
+
+ if (texpaint) {
+
+ /* pick new face and image */
+ if (facesel_face_pick(s->me, mval, &newfaceindex, 0)) {
+ ImBuf *ibuf;
+
+ newimage = (Image*)((s->me->mtface+newfaceindex)->tpage);
+ ibuf= BKE_image_get_ibuf(newimage, G.sima?&G.sima->iuser:NULL);
+
+ if(ibuf && ibuf->rect)
+ texpaint_pick_uv(s->ob, s->me, newfaceindex, mval, newuv);
+ else
+ newimage = NULL;
+ }
+ else
+ newuv[0] = newuv[1] = 0.0f;
+
+ /* see if stroke is broken, and if so finish painting in old position */
+ if (s->image) {
+ texpaint_pick_uv(s->ob, s->me, s->faceindex, mval, fwuv);
+ texpaint_pick_uv(s->ob, s->me, newfaceindex, prevmval, bkuv);
+
+ if (newimage == s->image)
+ breakstroke= texpaint_break_stroke(s->uv, fwuv, bkuv, newuv);
+ else
+ breakstroke= 1;
+ }
+ else
+ fwuv[0]= fwuv[1]= 0.0f;
+
+ if (breakstroke) {
+ texpaint_pick_uv(s->ob, s->me, s->faceindex, mval, fwuv);
+ redraw |= imapaint_paint_sub_stroke(s, painter, s->image, texpaint,
+ fwuv, time, 1, pressure);
+ imapaint_clear_partial_redraw();
+ brush_painter_break_stroke(painter);
+ }
+
+ /* set new canvas */
+ if (newimage && (newimage != s->image))
+ if (!imapaint_canvas_set(s, newimage))
+ newimage = NULL;
+
+ /* paint in new image */
+ if (newimage) {
+ if (breakstroke)
+ redraw|= imapaint_paint_sub_stroke(s, painter, newimage,
+ texpaint, bkuv, time, 0, pressure);
+ redraw|= imapaint_paint_sub_stroke(s, painter, newimage, texpaint,
+ newuv, time, 1, pressure);
+ }
+
+ /* update state */
+ s->image = newimage;
+ s->faceindex = newfaceindex;
+ s->uv[0] = newuv[0];
+ s->uv[1] = newuv[1];
+ }
+ else {
+ imapaint_compute_uvco(mval, newuv);
+ redraw |= imapaint_paint_sub_stroke(s, painter, s->image, texpaint, newuv,
+ time, 1, pressure);
+ }
+
+ if (redraw) {
+ imapaint_redraw(0, texpaint, NULL);
+ imapaint_clear_partial_redraw();
+ }
+}
+
+void imagepaint_paint(short mousebutton, short texpaint)
+{
+ ImagePaintState s;
+ BrushPainter *painter;
+ ToolSettings *settings= G.scene->toolsettings;
+ short prevmval[2], mval[2];
+ double time;
+ float pressure;
+
+ if(!settings->imapaint.brush)
+ return;
+
+ /* initialize state */
+ memset(&s, 0, sizeof(s));
+ s.brush = settings->imapaint.brush;
+ s.tool = settings->imapaint.tool;
+ if(texpaint && (s.tool == PAINT_TOOL_CLONE))
+ s.tool = PAINT_TOOL_DRAW;
+ s.blend = s.brush->blend;
+
+ if(texpaint) {
+ s.ob = OBACT;
+ if (!s.ob || !(s.ob->lay & G.vd->lay)) return;
+ s.me = get_mesh(s.ob);
+ if (!s.me) return;
+
+ persp(PERSP_VIEW);
+ }
+ else {
+ s.image = G.sima->image;
+
+ if(!imapaint_canvas_set(&s, G.sima->image)) {
+ if(s.warnmultifile)
+ error("Image requires 4 color channels to paint");
+ if(s.warnpackedfile)
+ error("Packed MultiLayer files cannot be painted");
+ return;
+ }
+ }
+
+ settings->imapaint.flag |= IMAGEPAINT_DRAWING;
+ free_imagepaint();
+
+ /* create painter and paint once */
+ painter= brush_painter_new(s.brush);
+
+ getmouseco_areawin(mval);
+
+ pressure = get_pressure();
+ s.blend = (get_activedevice() == 2)? BRUSH_BLEND_ERASE_ALPHA: s.brush->blend;
+
+ time= PIL_check_seconds_timer();
+ prevmval[0]= mval[0];
+ prevmval[1]= mval[1];
+
+ /* special exception here for too high pressure values on first touch in
+ windows for some tablets */
+ if (!((s.brush->flag & (BRUSH_ALPHA_PRESSURE|BRUSH_SIZE_PRESSURE|
+ BRUSH_SPACING_PRESSURE|BRUSH_RAD_PRESSURE)) && (get_activedevice() != 0) && (pressure >= 0.99f)))
+ imapaint_paint_stroke(&s, painter, texpaint, prevmval, mval, time, pressure);
+
+ /* paint loop */
+ do {
+ getmouseco_areawin(mval);
+
+ pressure = get_pressure();
+ s.blend = (get_activedevice() == 2)? BRUSH_BLEND_ERASE_ALPHA: s.brush->blend;
+
+ time= PIL_check_seconds_timer();
+
+ if((mval[0] != prevmval[0]) || (mval[1] != prevmval[1])) {
+ imapaint_paint_stroke(&s, painter, texpaint, prevmval, mval, time, pressure);
+ prevmval[0]= mval[0];
+ prevmval[1]= mval[1];
+ }
+ else if (s.brush->flag & BRUSH_AIRBRUSH)
+ imapaint_paint_stroke(&s, painter, texpaint, prevmval, mval, time, pressure);
+ else
+ BIF_wait_for_statechange();
+
+ /* do mouse checking at the end, so don't check twice, and potentially
+ miss a short tap */
+ } while(get_mbut() & mousebutton);
+
+ /* clean up */
+ settings->imapaint.flag &= ~IMAGEPAINT_DRAWING;
+ imapaint_canvas_free(&s);
+ brush_painter_free(painter);
+
+ imapaint_redraw(1, texpaint, s.image);
+
+ if (texpaint) {
+ if (s.warnmultifile)
+ error("Image requires 4 color channels to paint: %s", s.warnmultifile);
+ if(s.warnpackedfile)
+ error("Packed MultiLayer files cannot be painted %s", s.warnpackedfile);
+
+ persp(PERSP_WIN);
+ }
+}
+
+void imagepaint_pick(short mousebutton)
+{
+ ToolSettings *settings= G.scene->toolsettings;
+ Brush *brush= settings->imapaint.brush;
+
+ if(brush && (settings->imapaint.tool == PAINT_TOOL_CLONE)) {
+ if(brush->clone.image) {
+ short prevmval[2], mval[2];
+ float lastmousepos[2], mousepos[2];
+
+ getmouseco_areawin(prevmval);
+
+ while(get_mbut() & mousebutton) {
+ getmouseco_areawin(mval);
+
+ if((prevmval[0] != mval[0]) || (prevmval[1] != mval[1]) ) {
+ /* mouse moved, so move the clone image */
+ imapaint_compute_uvco(prevmval, lastmousepos);
+ imapaint_compute_uvco(mval, mousepos);
+
+ brush->clone.offset[0] += mousepos[0] - lastmousepos[0];
+ brush->clone.offset[1] += mousepos[1] - lastmousepos[1];
+
+ force_draw(0);
+
+ prevmval[0]= mval[0];
+ prevmval[1]= mval[1];
+ }
+ }
+ }
+ }
+ else if(brush)
+ sample_vpaint();
+}
+
diff --git a/source/blender/src/imasel.c b/source/blender/src/imasel.c
new file mode 100644
index 00000000000..78fc3f1be2a
--- /dev/null
+++ b/source/blender/src/imasel.c
@@ -0,0 +1,85 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef WIN32
+#include <unistd.h>
+#else
+#include "BLI_winstuff.h"
+#include <io.h>
+#include <direct.h>
+#endif
+#include <fcntl.h>
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_global.h"
+
+#include "BIF_imasel.h"
+#include "BIF_filelist.h"
+#include "BIF_space.h"
+#include "BIF_screen.h"
+
+#include "blendef.h"
+#include "mydevice.h"
+
+
+void free_imasel(SpaceImaSel *simasel)
+{
+ /* do not free imasel itself */
+ if(simasel->files) {
+ BIF_filelist_freelib(simasel->files);
+ BIF_filelist_free(simasel->files);
+ MEM_freeN(simasel->files);
+ simasel->files = NULL;
+ }
+ if (simasel->img) {
+ IMB_freeImBuf(simasel->img);
+ }
+ if(simasel->pupmenu) {
+ MEM_freeN(simasel->pupmenu);
+ simasel->pupmenu = NULL;
+ }
+}
+
diff --git a/source/blender/src/interface.c b/source/blender/src/interface.c
new file mode 100644
index 00000000000..07debe8f864
--- /dev/null
+++ b/source/blender/src/interface.c
@@ -0,0 +1,6684 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/*
+ a full doc with API notes can be found in bf-blender/blender/doc/interface_API.txt
+
+ */
+
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef WIN32
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "PIL_time.h"
+
+#include "BMF_Api.h"
+#include "BIF_language.h"
+#ifdef INTERNATIONAL
+#include "FTF_Api.h"
+#endif // INTERNATIONAL
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "DNA_color_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_vec_types.h"
+#include "DNA_object_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_vfont_types.h"
+
+#include "BKE_blender.h"
+#include "BKE_colortools.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_cursors.h"
+#include "BIF_gl.h"
+#include "BIF_graphics.h"
+#include "BIF_keyval.h"
+#include "BIF_mainqueue.h"
+#include "BIF_resources.h"
+#include "BIF_screen.h"
+#include "BIF_toolbox.h"
+#include "BIF_mywindow.h"
+#include "BIF_space.h"
+#include "BIF_glutil.h"
+#include "BIF_editfont.h"
+#include "BIF_interface.h"
+#include "BIF_interface_icons.h"
+#include "BIF_butspace.h"
+#include "BIF_previewrender.h"
+
+#include "BSE_view.h"
+
+#include "BPY_extern.h" /* for BPY_button_eval */
+
+#include "GHOST_Types.h" /* for tablet data */
+
+#include "mydevice.h"
+#include "interface.h"
+#include "blendef.h"
+#include "winlay.h"
+
+#define INSIDE_BLOCK 1
+#define INSIDE_PANEL_HEADER 2
+#define INSIDE_PANEL_SCALE 3
+
+/* naming conventions:
+ *
+ * uiBlahBlah() external function
+ * ui_blah_blah() internal function
+ */
+
+/***/
+/* ************ GLOBALS ************* */
+
+float UIwinmat[4][4];
+static int UIlock= 0, UIafterval;
+static char *UIlockstr=NULL;
+
+static void (*UIafterfunc_butm)(void *arg, int event);
+static void (*UIafterfunc_but)(void *arg1, void *arg2);
+static void *UIafterfunc_arg1, *UIafterfunc_arg2;
+
+static uiFont UIfont[UI_ARRAY]; // no init needed
+uiBut *UIbuttip;
+
+static char but_copypaste_str[256]="";
+static double but_copypaste_val=0.0;
+static float but_copypaste_rgb[3];
+
+/* ************* PROTOTYPES ***************** */
+
+static void ui_set_but_val(uiBut *but, double value);
+static void ui_do_but_tip(uiBut *buttip);
+
+/* ****************************** */
+
+static int uibut_contains_pt(uiBut *but, short *pt)
+{
+ return ((but->x1<pt[0] && but->x2>=pt[0]) &&
+ (but->y1<pt[1] && but->y2>=pt[1]));
+}
+
+static void uibut_do_func(uiBut *but)
+{
+ if (but->func) {
+ but->func(but->func_arg1, but->func_arg2);
+ }
+}
+
+/* ************* window matrix ************** */
+
+
+void ui_graphics_to_window(int win, float *x, float *y) /* for rectwrite */
+{
+ float gx, gy;
+ int sx, sy;
+ int getsizex, getsizey;
+
+ bwin_getsize(win, &getsizex, &getsizey);
+ bwin_getsuborigin(win, &sx, &sy);
+
+ gx= *x;
+ gy= *y;
+ *x= ((float)sx) + ((float)getsizex)*(0.5+ 0.5*(gx*UIwinmat[0][0]+ gy*UIwinmat[1][0]+ UIwinmat[3][0]));
+ *y= ((float)sy) + ((float)getsizey)*(0.5+ 0.5*(gx*UIwinmat[0][1]+ gy*UIwinmat[1][1]+ UIwinmat[3][1]));
+}
+
+void ui_graphics_to_window_rct(int win, rctf *graph, rcti *winr)
+{
+ float gx, gy;
+ int sx, sy;
+ int getsizex, getsizey;
+
+ bwin_getsize(win, &getsizex, &getsizey);
+ bwin_getsuborigin(win, &sx, &sy);
+
+ gx= graph->xmin;
+ gy= graph->ymin;
+ winr->xmin= (int)((float)sx) + ((float)getsizex)*(0.5+ 0.5*(gx*UIwinmat[0][0]+ gy*UIwinmat[1][0]+ UIwinmat[3][0]));
+ winr->ymin= (int)((float)sy) + ((float)getsizey)*(0.5+ 0.5*(gx*UIwinmat[0][1]+ gy*UIwinmat[1][1]+ UIwinmat[3][1]));
+ gx= graph->xmax;
+ gy= graph->ymax;
+ winr->xmax= (int)((float)sx) + ((float)getsizex)*(0.5+ 0.5*(gx*UIwinmat[0][0]+ gy*UIwinmat[1][0]+ UIwinmat[3][0]));
+ winr->ymax= (int)((float)sy) + ((float)getsizey)*(0.5+ 0.5*(gx*UIwinmat[0][1]+ gy*UIwinmat[1][1]+ UIwinmat[3][1]));
+}
+
+
+void ui_window_to_graphics(int win, float *x, float *y) /* for mouse cursor */
+{
+ float a, b, c, d, e, f, px, py;
+ int getsizex, getsizey;
+
+ bwin_getsize(win, &getsizex, &getsizey);
+
+ a= .5*((float)getsizex)*UIwinmat[0][0];
+ b= .5*((float)getsizex)*UIwinmat[1][0];
+ c= .5*((float)getsizex)*(1.0+UIwinmat[3][0]);
+
+ d= .5*((float)getsizey)*UIwinmat[0][1];
+ e= .5*((float)getsizey)*UIwinmat[1][1];
+ f= .5*((float)getsizey)*(1.0+UIwinmat[3][1]);
+
+ px= *x;
+ py= *y;
+
+ *y= (a*(py-f) + d*(c-px))/(a*e-d*b);
+ *x= (px- b*(*y)- c)/a;
+
+}
+
+
+/* ************* SAVE UNDER ************ */
+
+/* new method:
+
+OverDraw *ui_begin_overdraw(int minx, int miny, int maxx, int maxy);
+- enforces mainwindow to become active
+- grabs copy from frontbuffer, pastes in back
+
+void ui_flush_overdraw(OverDraw *od);
+- copies backbuffer to front
+
+void ui_refresh_overdraw(Overdraw *od);
+- pastes in back copy of frontbuffer again for fresh drawing
+
+void ui_end_overdraw(OverDraw *od);
+- puts back on frontbuffer saved image
+- frees copy
+- sets back active blender area
+- signals backbuffer to be corrupt (sel buffer!)
+
+*/
+
+/* frontbuffer updates now glCopyPixels too, with block->flush rect */
+
+/* new idea for frontbuffer updates:
+
+- hilites: with blended poly?
+
+- full updates... thats harder, but:
+ - copy original
+ - before draw, always paste to backbuf
+ - flush
+ - always end with redraw event for full update
+
+*/
+
+static void myglCopyPixels(int a, int b, int c, int d, int e)
+{
+ if(G.rt==2) {
+ unsigned int *buf= MEM_mallocN(4*c*d, "temp glcopypixels");
+ glReadPixels(a, b, c, d, GL_RGBA, GL_UNSIGNED_BYTE, buf);
+ glDrawPixels(c, d, GL_RGBA, GL_UNSIGNED_BYTE, buf);
+ MEM_freeN(buf);
+ }
+ else glCopyPixels(a, b, c, d, e);
+}
+
+typedef struct {
+ short x, y, sx, sy, oldwin;
+ unsigned int *rect;
+} uiOverDraw;
+
+
+static uiOverDraw *ui_begin_overdraw(int minx, int miny, int maxx, int maxy)
+{
+ uiOverDraw *od=NULL;
+
+ // dirty patch removed for sun and sgi to mywindow.c commented out
+
+ /* clip with actual window size */
+ if(minx < 0) minx= 0;
+ if(miny < 0) miny= 0;
+ if(maxx >= G.curscreen->sizex) maxx= G.curscreen->sizex-1;
+ if(maxy >= G.curscreen->sizey) maxy= G.curscreen->sizey-1;
+
+ if(minx<maxx && miny<maxy) {
+ od= MEM_callocN(sizeof(uiOverDraw), "overdraw");
+
+ od->x= minx;
+ od->y= miny;
+ od->sx= maxx-minx;
+ od->sy= maxy-miny;
+ od->rect= MEM_mallocN(od->sx*od->sy*4, "temp_frontbuffer_image");
+
+ od->oldwin= mywinget();
+ mywinset(G.curscreen->mainwin);
+ /* grab front */
+ glReadBuffer(GL_FRONT);
+ glReadPixels(od->x, od->y, od->sx, od->sy, GL_RGBA, GL_UNSIGNED_BYTE, od->rect);
+ glReadBuffer(GL_BACK);
+ /* paste in back */
+ glDisable(GL_DITHER);
+ glRasterPos2f(od->x, od->y);
+ glDrawPixels(od->sx, od->sy, GL_RGBA, GL_UNSIGNED_BYTE, od->rect);
+ glEnable(GL_DITHER);
+ }
+
+ return od;
+}
+
+static void ui_flush_overdraw(uiOverDraw *od)
+{
+
+ if(od==NULL) return;
+ glDisable(GL_DITHER);
+ glReadBuffer(GL_BACK);
+ glDrawBuffer(GL_FRONT);
+ glRasterPos2s(od->x, od->y);
+ myglCopyPixels(od->x, od->y, od->sx, od->sy, GL_COLOR);
+ glEnable(GL_DITHER);
+ bglFlush();
+ glDrawBuffer(GL_BACK);
+}
+
+/* special flush version to enable transparent menus */
+static void ui_block_flush_overdraw(uiBlock *block)
+{
+
+ if(block->flag & UI_BLOCK_LOOP) {
+ char col[4];
+
+ BIF_GetThemeColor4ubv(TH_MENU_BACK, col);
+ if(col[3]!=255) {
+ uiBut *bt;
+ uiOverDraw *od= block->overdraw;
+
+ /* completely draw all! */
+ glRasterPos2s(od->x, od->y);
+ glDrawPixels(od->sx, od->sy, GL_RGBA, GL_UNSIGNED_BYTE, od->rect);
+
+ uiDrawMenuBox(block->minx, block->miny, block->maxx, block->maxy, block->flag);
+ for (bt= block->buttons.first; bt; bt= bt->next) {
+ ui_draw_but(bt);
+ }
+ }
+ }
+
+ ui_flush_overdraw(block->overdraw);
+}
+
+static void ui_end_overdraw(uiOverDraw *od)
+{
+ if(od==NULL) return;
+
+ glDisable(GL_DITHER);
+
+ // clear in back
+ glRasterPos2s(od->x, od->y);
+ glDrawPixels(od->sx, od->sy, GL_RGBA, GL_UNSIGNED_BYTE, od->rect);
+
+ // clear in front
+ glDrawBuffer(GL_FRONT);
+ glRasterPos2s(od->x, od->y);
+ glDrawPixels(od->sx, od->sy, GL_RGBA, GL_UNSIGNED_BYTE, od->rect);
+
+ bglFlush();
+ glDrawBuffer(GL_BACK);
+ glEnable(GL_DITHER);
+
+ if(od->oldwin) mywinset(od->oldwin);
+
+ MEM_freeN(od->rect);
+ MEM_freeN(od);
+
+ markdirty_all_back(); // sets flags only
+}
+
+/* ****************** live updates for hilites and button presses *********** */
+
+void ui_block_flush_back(uiBlock *block)
+{
+ int minx, miny, sizex, sizey;
+
+ /* note; this routine also has to work for block loop */
+ if(block->needflush==0) return;
+
+ /* exception, when we cannot use backbuffer for draw... */
+ if(block->flag & UI_BLOCK_FRONTBUFFER) {
+ bglFlush();
+ glDrawBuffer(GL_BACK);
+ block->needflush= 0;
+ return;
+ }
+
+ /* copy pixels works on window coords, so we move to window space */
+
+ ui_graphics_to_window(block->win, &block->flush.xmin, &block->flush.ymin);
+ ui_graphics_to_window(block->win, &block->flush.xmax, &block->flush.ymax);
+ minx= floor(block->flush.xmin);
+ miny= floor(block->flush.ymin);
+ sizex= ceil(block->flush.xmax-block->flush.xmin);
+ sizey= ceil(block->flush.ymax-block->flush.ymin);
+
+ if(sizex>0 && sizey>0) {
+ glPushMatrix();
+ mywinset(G.curscreen->mainwin);
+
+ glDisable(GL_DITHER);
+ glReadBuffer(GL_BACK);
+ glDrawBuffer(GL_FRONT);
+ glRasterPos2i(minx, miny);
+#ifdef __sun__
+ myglCopyPixels(minx, miny+1, sizex, sizey, GL_COLOR);
+#else
+ myglCopyPixels(minx, miny, sizex, sizey, GL_COLOR);
+#endif
+ glEnable(GL_DITHER);
+ bglFlush();
+ glDrawBuffer(GL_BACK);
+
+ mywinset(block->win);
+ glPopMatrix();
+
+ markdirty_win_back(block->win);
+ }
+
+ block->needflush= 0;
+}
+
+/* merge info for live updates in frontbuf */
+void ui_block_set_flush(uiBlock *block, uiBut *but)
+{
+ /* clear signal */
+ if(but==NULL) {
+ block->needflush= 0;
+
+ block->flush.xmin= 0.0;
+ block->flush.xmax= 0.0;
+ }
+ else {
+ /* exception, when we cannot use backbuffer for draw... */
+ if(block->flag & UI_BLOCK_FRONTBUFFER) {
+ glDrawBuffer(GL_FRONT);
+ }
+ else if(block->needflush==0) {
+ /* first rect */
+ block->flush.xmin= but->x1;
+ block->flush.xmax= but->x2;
+ block->flush.ymin= but->y1;
+ block->flush.ymax= but->y2;
+
+ }
+ else {
+ /* union of rects */
+ if(block->flush.xmin > but->x1) block->flush.xmin= but->x1;
+ if(block->flush.xmax < but->x2) block->flush.xmax= but->x2;
+ if(block->flush.ymin > but->y1) block->flush.ymin= but->y1;
+ if(block->flush.ymax < but->y2) block->flush.ymax= but->y2;
+ }
+
+ block->needflush= 1;
+
+ }
+}
+
+/* ******************* copy and paste ******************** */
+
+/* c = copy, v = paste */
+/* return 1 when something changed */
+static int ui_but_copy_paste(uiBut *but, char mode)
+{
+ void *poin;
+
+ if(mode=='v' && but->lock) return 0;
+ poin= but->poin;
+
+ if ELEM3(but->type, NUM, NUMSLI, HSVSLI) {
+
+ if(poin==NULL);
+ else if(mode=='c') {
+ but_copypaste_val= ui_get_but_val(but);
+ }
+ else {
+ ui_set_but_val(but, but_copypaste_val);
+ uibut_do_func(but);
+ ui_check_but(but);
+ return 1;
+ }
+ }
+ else if(but->type==COL) {
+
+ if(poin==NULL);
+ else if(mode=='c') {
+ if(but->pointype==FLO) {
+ float *fp= (float *) poin;
+ but_copypaste_rgb[0]= fp[0];
+ but_copypaste_rgb[1]= fp[1];
+ but_copypaste_rgb[2]= fp[2];
+ }
+ else if (but->pointype==CHA) {
+ char *cp= (char *) poin;
+ but_copypaste_rgb[0]= (float)(cp[0]/255.0);
+ but_copypaste_rgb[1]= (float)(cp[1]/255.0);
+ but_copypaste_rgb[2]= (float)(cp[2]/255.0);
+ }
+
+ }
+ else {
+ if(but->pointype==FLO) {
+ float *fp= (float *) poin;
+ fp[0] = but_copypaste_rgb[0];
+ fp[1] = but_copypaste_rgb[1];
+ fp[2] = but_copypaste_rgb[2];
+ return 1;
+ }
+ else if (but->pointype==CHA) {
+ char *cp= (char *) poin;
+ cp[0] = (char)(but_copypaste_rgb[0]*255.0);
+ cp[1] = (char)(but_copypaste_rgb[1]*255.0);
+ cp[2] = (char)(but_copypaste_rgb[2]*255.0);
+
+ return 1;
+ }
+
+ }
+ }
+ else if(but->type==TEX) {
+
+ if(poin==NULL);
+ else if(mode=='c') {
+ strncpy(but_copypaste_str, but->poin, but->max);
+ }
+ else {
+ char backstr[UI_MAX_DRAW_STR];
+ /* give butfunc the original text too */
+ /* feature used for bone renaming, channels, etc */
+ if(but->func_arg2==NULL) {
+ strncpy(backstr, but->drawstr, UI_MAX_DRAW_STR);
+ but->func_arg2= backstr;
+ }
+ strncpy(but->poin, but_copypaste_str, but->max);
+ uibut_do_func(but);
+ ui_check_but(but);
+ return 1;
+ }
+ }
+ else if(but->type==IDPOIN) {
+
+ if(mode=='c') {
+ ID *id= *but->idpoin_idpp;
+ if(id) strncpy(but_copypaste_str, id->name+2, 22);
+ }
+ else {
+ but->idpoin_func(but_copypaste_str, but->idpoin_idpp);
+ ui_check_but(but);
+ return 1;
+ }
+ }
+
+
+ return 0;
+}
+
+/* ******************* block calc ************************* */
+
+/* only for pulldowns */
+void uiTextBoundsBlock(uiBlock *block, int addval)
+{
+ uiBut *bt;
+ int i = 0, j, x1addval= 0, nextcol;
+
+ bt= block->buttons.first;
+ while(bt) {
+ if(bt->type!=SEPR) {
+ int transopts= (U.transopts & USER_TR_BUTTONS);
+ if(bt->type==TEX || bt->type==IDPOIN) transopts= 0;
+ j= BIF_GetStringWidth(bt->font, bt->drawstr, transopts);
+
+ if(j > i) i = j;
+ }
+ bt= bt->next;
+ }
+
+ /* cope with multi collumns */
+ bt= block->buttons.first;
+ while(bt) {
+ if(bt->next && bt->x1 < bt->next->x1)
+ nextcol= 1;
+ else nextcol= 0;
+
+ bt->x1 = x1addval;
+ bt->x2 = bt->x1 + i + addval;
+
+ ui_check_but(bt); // clips text again
+
+ if(nextcol)
+ x1addval+= i + addval;
+
+ bt= bt->next;
+ }
+}
+
+
+void uiBoundsBlock(uiBlock *block, int addval)
+{
+ uiBut *bt;
+ int xof;
+
+ if(block->buttons.first==NULL) {
+ if(block->panel) {
+ block->minx= 0.0; block->maxx= block->panel->sizex;
+ block->miny= 0.0; block->maxy= block->panel->sizey;
+ }
+ }
+ else {
+
+ block->minx= block->miny= 10000;
+ block->maxx= block->maxy= -10000;
+
+ bt= block->buttons.first;
+ while(bt) {
+ if(bt->x1 < block->minx) block->minx= bt->x1;
+ if(bt->y1 < block->miny) block->miny= bt->y1;
+
+ if(bt->x2 > block->maxx) block->maxx= bt->x2;
+ if(bt->y2 > block->maxy) block->maxy= bt->y2;
+
+ bt= bt->next;
+ }
+
+ block->minx -= addval;
+ block->miny -= addval;
+ block->maxx += addval;
+ block->maxy += addval;
+ }
+
+ /* hardcoded exception... but that one is annoying with larger safety */
+ bt= block->buttons.first;
+ if(bt && strncmp(bt->str, "ERROR", 5)==0) xof= 10;
+ else xof= 40;
+
+ block->safety.xmin= block->minx-xof;
+ block->safety.ymin= block->miny-xof;
+ block->safety.xmax= block->maxx+xof;
+ block->safety.ymax= block->maxy+xof;
+}
+
+static void ui_positionblock(uiBlock *block, uiBut *but)
+{
+ /* position block relative to but */
+ uiBut *bt;
+ rctf butrct;
+ float aspect;
+ int xsize, ysize, xof=0, yof=0, center;
+ short dir1= 0, dir2=0;
+
+ /* first transform to screen coords, assuming matrix is stil OK */
+ /* the UIwinmat is in panelspace */
+
+ butrct.xmin= but->x1; butrct.xmax= but->x2;
+ butrct.ymin= but->y1; butrct.ymax= but->y2;
+
+ ui_graphics_to_window(block->win, &butrct.xmin, &butrct.ymin);
+ ui_graphics_to_window(block->win, &butrct.xmax, &butrct.ymax);
+ block->parentrct= butrct; // will use that for pulldowns later
+
+ /* calc block rect */
+ if(block->buttons.first) {
+ block->minx= block->miny= 10000;
+ block->maxx= block->maxy= -10000;
+
+ bt= block->buttons.first;
+ while(bt) {
+ if(bt->x1 < block->minx) block->minx= bt->x1;
+ if(bt->y1 < block->miny) block->miny= bt->y1;
+
+ if(bt->x2 > block->maxx) block->maxx= bt->x2;
+ if(bt->y2 > block->maxy) block->maxy= bt->y2;
+
+ bt= bt->next;
+ }
+ }
+ else {
+ /* we're nice and allow empty blocks too */
+ block->minx= block->miny= 0;
+ block->maxx= block->maxy= 20;
+ }
+
+ aspect= (float)(block->maxx - block->minx + 4);
+ ui_graphics_to_window(block->win, &block->minx, &block->miny);
+ ui_graphics_to_window(block->win, &block->maxx, &block->maxy);
+
+ //block->minx-= 2.0; block->miny-= 2.0;
+ //block->maxx+= 2.0; block->maxy+= 2.0;
+
+ xsize= block->maxx - block->minx+4; // 4 for shadow
+ ysize= block->maxy - block->miny+4;
+ aspect/= (float)xsize;
+
+ if(but) {
+ short left=0, right=0, top=0, down=0;
+
+ if(block->direction & UI_CENTER) center= ysize/2;
+ else center= 0;
+
+ if( butrct.xmin-xsize > 0.0) left= 1;
+ if( butrct.xmax+xsize < G.curscreen->sizex) right= 1;
+ if( butrct.ymin-ysize+center > 0.0) down= 1;
+ if( butrct.ymax+ysize-center < G.curscreen->sizey) top= 1;
+
+ dir1= block->direction & UI_DIRECTION;
+
+ /* secundary directions */
+ if(dir1 & (UI_TOP|UI_DOWN)) {
+ if(dir1 & UI_LEFT) dir2= UI_LEFT;
+ else if(dir1 & UI_RIGHT) dir2= UI_RIGHT;
+ dir1 &= (UI_TOP|UI_DOWN);
+ }
+
+ if(dir2==0) if(dir1==UI_LEFT || dir1==UI_RIGHT) dir2= UI_DOWN;
+ if(dir2==0) if(dir1==UI_TOP || dir1==UI_DOWN) dir2= UI_LEFT;
+
+ /* no space at all? dont change */
+ if(left || right) {
+ if(dir1==UI_LEFT && left==0) dir1= UI_RIGHT;
+ if(dir1==UI_RIGHT && right==0) dir1= UI_LEFT;
+ /* this is aligning, not append! */
+ if(dir2==UI_LEFT && right==0) dir2= UI_RIGHT;
+ if(dir2==UI_RIGHT && left==0) dir2= UI_LEFT;
+ }
+ if(down || top) {
+ if(dir1==UI_TOP && top==0) dir1= UI_DOWN;
+ if(dir1==UI_DOWN && down==0) dir1= UI_TOP;
+ if(dir2==UI_TOP && top==0) dir2= UI_DOWN;
+ if(dir2==UI_DOWN && down==0) dir2= UI_TOP;
+ }
+
+ if(dir1==UI_LEFT) {
+ xof= butrct.xmin - block->maxx;
+ if(dir2==UI_TOP) yof= butrct.ymin - block->miny-center;
+ else yof= butrct.ymax - block->maxy+center;
+ }
+ else if(dir1==UI_RIGHT) {
+ xof= butrct.xmax - block->minx;
+ if(dir2==UI_TOP) yof= butrct.ymin - block->miny-center;
+ else yof= butrct.ymax - block->maxy+center;
+ }
+ else if(dir1==UI_TOP) {
+ yof= butrct.ymax - block->miny;
+ if(dir2==UI_RIGHT) xof= butrct.xmax - block->maxx;
+ else xof= butrct.xmin - block->minx;
+ // changed direction?
+ if((dir1 & block->direction)==0) {
+ if(block->direction & UI_SHIFT_FLIPPED)
+ xof+= dir2==UI_LEFT?25:-25;
+ uiBlockFlipOrder(block);
+ }
+ }
+ else if(dir1==UI_DOWN) {
+ yof= butrct.ymin - block->maxy;
+ if(dir2==UI_RIGHT) xof= butrct.xmax - block->maxx;
+ else xof= butrct.xmin - block->minx;
+ // changed direction?
+ if((dir1 & block->direction)==0) {
+ if(block->direction & UI_SHIFT_FLIPPED)
+ xof+= dir2==UI_LEFT?25:-25;
+ uiBlockFlipOrder(block);
+ }
+ }
+
+ /* and now we handle the exception; no space below or to top */
+ if(top==0 && down==0) {
+ if(dir1==UI_LEFT || dir1==UI_RIGHT) {
+ // align with bottom of screen
+ yof= ysize;
+ }
+ }
+
+ /* or no space left or right */
+ if(left==0 && right==0) {
+ if(dir1==UI_TOP || dir1==UI_DOWN) {
+ // align with left size of screen
+ xof= -block->minx+5;
+ }
+ }
+
+ // apply requested offset in the block
+ xof += block->xofs/block->aspect;
+ yof += block->yofs/block->aspect;
+
+ }
+
+ /* apply */
+
+ for(bt= block->buttons.first; bt; bt= bt->next) {
+
+ ui_graphics_to_window(block->win, &bt->x1, &bt->y1);
+ ui_graphics_to_window(block->win, &bt->x2, &bt->y2);
+
+ bt->x1 += xof;
+ bt->x2 += xof;
+ bt->y1 += yof;
+ bt->y2 += yof;
+
+ bt->aspect= 1.0;
+ // ui_check_but recalculates drawstring size in pixels
+ ui_check_but(bt);
+ }
+
+ block->minx += xof;
+ block->miny += yof;
+ block->maxx += xof;
+ block->maxy += yof;
+
+ /* safety calculus */
+ if(but) {
+ float midx= (block->parentrct.xmin+block->parentrct.xmax)/2.0;
+ float midy= (block->parentrct.ymin+block->parentrct.ymax)/2.0;
+
+ /* when you are outside parent button, safety there should be smaller */
+
+ // parent button to left
+ if( midx < block->minx ) block->safety.xmin= block->minx-3;
+ else block->safety.xmin= block->minx-40;
+ // parent button to right
+ if( midx > block->maxx ) block->safety.xmax= block->maxx+3;
+ else block->safety.xmax= block->maxx+40;
+
+ // parent button on bottom
+ if( midy < block->miny ) block->safety.ymin= block->miny-3;
+ else block->safety.ymin= block->miny-40;
+ // parent button on top
+ if( midy > block->maxy ) block->safety.ymax= block->maxy+3;
+ else block->safety.ymax= block->maxy+40;
+
+ // exception for switched pulldowns...
+ if(dir1 && (dir1 & block->direction)==0) {
+ if(dir2==UI_RIGHT) block->safety.xmax= block->maxx+3;
+ if(dir2==UI_LEFT) block->safety.xmin= block->minx-3;
+ }
+ block->direction= dir1;
+ }
+ else {
+ block->safety.xmin= block->minx-40;
+ block->safety.ymin= block->miny-40;
+ block->safety.xmax= block->maxx+40;
+ block->safety.ymax= block->maxy+40;
+ }
+
+}
+
+
+void ui_autofill(uiBlock *block)
+{
+ uiBut *but;
+ float *maxw, *maxh, startx = 0, starty, height = 0;
+ float totmaxh;
+ int rows=0, /* cols=0, */ i, lasti;
+
+ /* first count rows */
+ but= block->buttons.last;
+ rows= but->x1+1;
+
+ /* calculate max width / height for each row */
+ maxw= MEM_callocN(sizeof(float)*rows, "maxw");
+ maxh= MEM_callocN(sizeof(float)*rows, "maxh");
+ but= block->buttons.first;
+ while(but) {
+ i= but->x1;
+ if( maxh[i] < but->y2) maxh[i]= but->y2;
+ maxw[i] += but->x2;
+ but= but->next;
+ }
+
+ totmaxh= 0.0;
+ for(i=0; i<rows; i++) totmaxh+= maxh[i];
+
+ /* apply widths/heights */
+ starty= block->maxy;
+ but= block->buttons.first;
+ lasti= -1;
+ while(but) {
+ // signal for aligning code
+ but->flag |= UI_BUT_ALIGN_DOWN;
+
+ i= but->x1;
+
+ if(i!=lasti) {
+ startx= block->minx;
+ height= (maxh[i]*(block->maxy-block->miny))/totmaxh;
+ starty-= height;
+ lasti= i;
+ }
+
+ but->y1= starty+but->aspect;
+ but->y2= but->y1+height-but->aspect;
+
+ but->x2= (but->x2*(block->maxx-block->minx))/maxw[i];
+ but->x1= startx+but->aspect;
+
+ startx+= but->x2;
+ but->x2+= but->x1-but->aspect;
+
+ ui_check_but(but);
+
+ but= but->next;
+ }
+
+ uiBlockEndAlign(block);
+
+ MEM_freeN(maxw); MEM_freeN(maxh);
+ block->autofill= 0;
+}
+
+/* ************** LINK LINE DRAWING ************* */
+
+/* link line drawing is not part of buttons or theme.. so we stick with it here */
+
+static void ui_draw_linkline(uiBut *but, uiLinkLine *line)
+{
+ float vec1[2], vec2[2];
+
+ if(line->from==NULL || line->to==NULL) return;
+
+ vec1[0]= (line->from->x1+line->from->x2)/2.0;
+ vec1[1]= (line->from->y1+line->from->y2)/2.0;
+ vec2[0]= (line->to->x1+line->to->x2)/2.0;
+ vec2[1]= (line->to->y1+line->to->y2)/2.0;
+
+ if(line->flag & UI_SELECT) BIF_ThemeColorShade(but->themecol, 80);
+ else glColor3ub(0,0,0);
+ fdrawline(vec1[0], vec1[1], vec2[0], vec2[1]);
+}
+
+static void ui_draw_links(uiBlock *block)
+{
+ uiBut *but;
+ uiLinkLine *line;
+
+ but= block->buttons.first;
+ while(but) {
+ if(but->type==LINK && but->link) {
+ line= but->link->lines.first;
+ while(line) {
+ ui_draw_linkline(but, line);
+ line= line->next;
+ }
+ }
+ but= but->next;
+ }
+}
+
+/* ************** BLOCK DRAWING FUNCTION ************* */
+
+
+void uiDrawBlock(uiBlock *block)
+{
+ uiBut *but;
+ short testmouse=0, mouse[2];
+
+ /* we set this only once */
+ glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
+
+ /* handle pending stuff */
+ if(block->autofill) ui_autofill(block);
+ if(block->minx==0.0 && block->maxx==0.0) uiBoundsBlock(block, 0);
+ if(block->flag & UI_BUT_ALIGN) uiBlockEndAlign(block);
+
+ /* we set active flag on a redraw again */
+ if((block->flag & UI_BLOCK_LOOP)==0) {
+ testmouse= 1;
+ Mat4CpyMat4(UIwinmat, block->winmat);
+ }
+
+ uiPanelPush(block); // panel matrix
+
+ if(block->flag & UI_BLOCK_LOOP) {
+ uiDrawMenuBox(block->minx, block->miny, block->maxx, block->maxy, block->flag);
+ }
+ else {
+ if(block->panel) ui_draw_panel(block);
+ }
+
+ if(block->drawextra) block->drawextra(curarea, block);
+
+ if(testmouse) /* do it after panel push, otherwise coords are wrong */
+ uiGetMouse(block->win, mouse);
+
+ for (but= block->buttons.first; but; but= but->next) {
+
+ if(testmouse && uibut_contains_pt(but, mouse))
+ but->flag |= UI_ACTIVE;
+
+ ui_draw_but(but);
+ }
+
+ ui_draw_links(block);
+
+ uiPanelPop(block); // matrix restored
+}
+
+/* ************* MENUBUTS *********** */
+
+typedef struct {
+ char *str;
+ int retval;
+ int icon;
+} MenuEntry;
+
+typedef struct {
+ char *instr;
+ char *title;
+ int titleicon;
+
+ MenuEntry *items;
+ int nitems, itemssize;
+} MenuData;
+
+static MenuData *menudata_new(char *instr) {
+ MenuData *md= MEM_mallocN(sizeof(*md), "MenuData");
+
+ md->instr= instr;
+ md->title= NULL;
+ md->titleicon= 0;
+ md->items= NULL;
+ md->nitems= md->itemssize= 0;
+
+ return md;
+}
+
+static void menudata_set_title(MenuData *md, char *title, int titleicon) {
+ if (!md->title)
+ md->title= title;
+ if (!md->titleicon)
+ md->titleicon= titleicon;
+}
+
+static void menudata_add_item(MenuData *md, char *str, int retval, int icon) {
+ if (md->nitems==md->itemssize) {
+ int nsize= md->itemssize?(md->itemssize<<1):1;
+ MenuEntry *oitems= md->items;
+
+ md->items= MEM_mallocN(nsize*sizeof(*md->items), "md->items");
+ if (oitems) {
+ memcpy(md->items, oitems, md->nitems*sizeof(*md->items));
+ MEM_freeN(oitems);
+ }
+
+ md->itemssize= nsize;
+ }
+
+ md->items[md->nitems].str= str;
+ md->items[md->nitems].retval= retval;
+ md->items[md->nitems].icon= icon;
+ md->nitems++;
+}
+
+static void menudata_free(MenuData *md) {
+ MEM_freeN(md->instr);
+ if (md->items)
+ MEM_freeN(md->items);
+ MEM_freeN(md);
+}
+
+ /**
+ * Parse menu description strings, string is of the
+ * form "[sss%t|]{(sss[%xNN]|), (%l|)}", ssss%t indicates the
+ * menu title, sss or sss%xNN indicates an option,
+ * if %xNN is given then NN is the return value if
+ * that option is selected otherwise the return value
+ * is the index of the option (starting with 1). %l
+ * indicates a seperator.
+ *
+ * @param str String to be parsed.
+ * @retval new menudata structure, free with menudata_free()
+ */
+static MenuData *decompose_menu_string(char *str)
+{
+ char *instr= BLI_strdup(str);
+ MenuData *md= menudata_new(instr);
+ char *nitem= NULL, *s= instr;
+ int nicon=0, nretval= 1, nitem_is_title= 0;
+
+ while (1) {
+ char c= *s;
+
+ if (c=='%') {
+ if (s[1]=='x') {
+ nretval= atoi(s+2);
+
+ *s= '\0';
+ s++;
+ } else if (s[1]=='t') {
+ nitem_is_title= 1;
+
+ *s= '\0';
+ s++;
+ } else if (s[1]=='l') {
+ nitem= "%l";
+ s++;
+ } else if (s[1]=='i') {
+ nicon= atoi(s+2);
+
+ *s= '\0';
+ s++;
+ }
+ } else if (c=='|' || c=='\0') {
+ if (nitem) {
+ *s= '\0';
+
+ if (nitem_is_title) {
+ menudata_set_title(md, nitem, nicon);
+ nitem_is_title= 0;
+ } else {
+ /* prevent separator to get a value */
+ if(nitem[0]=='%' && nitem[1]=='l')
+ menudata_add_item(md, nitem, -1, nicon);
+ else
+ menudata_add_item(md, nitem, nretval, nicon);
+ nretval= md->nitems+1;
+ }
+
+ nitem= NULL;
+ nicon= 0;
+ }
+
+ if (c=='\0')
+ break;
+ } else if (!nitem)
+ nitem= s;
+
+ s++;
+ }
+
+ return md;
+}
+
+static void ui_set_name_menu(uiBut *but, int value)
+{
+ MenuData *md;
+ int i;
+
+ md= decompose_menu_string(but->str);
+ for (i=0; i<md->nitems; i++)
+ if (md->items[i].retval==value)
+ strcpy(but->drawstr, md->items[i].str);
+
+ menudata_free(md);
+}
+
+static void ui_warp_pointer(short x, short y)
+{
+ /* OSX has very poor mousewarp support, it sends events;
+ this causes a menu being pressed immediately ... */
+ #ifndef __APPLE__
+ warp_pointer(x, y);
+ #endif
+}
+
+#define TBOXH 20
+static int ui_do_but_MENU(uiBut *but)
+{
+ uiBlock *block;
+ uiBut *bt;
+ ListBase listb={NULL, NULL}, lb;
+ double fvalue;
+ int width, height=0, a, xmax, starty;
+ short startx;
+ int columns=1, rows=0, boxh, event;
+ short x1, y1, active= -1;
+ short mval[2];
+ MenuData *md;
+
+ but->flag |= UI_SELECT;
+ ui_draw_but(but);
+ ui_block_flush_back(but->block); // flush because this button creates own blocks loop
+
+ block= uiNewBlock(&listb, "menu", UI_EMBOSSP, UI_HELV, but->win);
+ block->flag= UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_NUMSELECT;
+ block->themecol= TH_MENU_ITEM;
+
+ md= decompose_menu_string(but->str);
+
+ /* columns and row calculation */
+ columns= (md->nitems+20)/20;
+ if (columns<1) columns= 1;
+
+ if(columns>8) columns= (md->nitems+25)/25;
+
+ rows= (int) md->nitems/columns;
+ if (rows<1) rows= 1;
+
+ while (rows*columns<md->nitems) rows++;
+
+ /* prevent scaling up of pupmenu */
+ if (but->aspect < 1.0f) but->aspect = 1.0f;
+
+ /* size and location */
+ if(md->title)
+ width= 1.5*but->aspect*strlen(md->title)+BIF_GetStringWidth(block->curfont, md->title, (U.transopts & USER_TR_MENUS));
+ else
+ width= 0;
+
+ for(a=0; a<md->nitems; a++) {
+ xmax= but->aspect*BIF_GetStringWidth(block->curfont, md->items[a].str, (U.transopts & USER_TR_MENUS));
+ if ( md->items[a].icon) xmax += 20*but->aspect;
+ if(xmax>width) width= xmax;
+ }
+
+ width+= 10;
+ if (width < (but->x2 - but->x1)) width = (but->x2 - but->x1);
+ if (width<50) width=50;
+
+ boxh= TBOXH;
+
+ height= rows*boxh;
+ if (md->title) height+= boxh;
+
+ getmouseco_sc(mval);
+
+ /* find active item */
+ fvalue= ui_get_but_val(but);
+ for(active=0; active<md->nitems; active++) {
+ if( md->items[active].retval== (int)fvalue ) break;
+ }
+ /* no active item? */
+ if(active==md->nitems) {
+ if(md->title) active= -1;
+ else active= 0;
+ }
+
+ /* for now disabled... works confusing because you think it's a title or so.... */
+ active= -1;
+
+ /* here we go! */
+ startx= but->x1;
+ starty= but->y1;
+
+ if(md->title) {
+ uiBut *bt;
+ uiSetCurFont(block, block->font+1);
+ if (md->titleicon) {
+ uiDefIconTextBut(block, LABEL, 0, md->titleicon, md->title, startx, (short)(starty+rows*boxh), (short)width, (short)boxh, NULL, 0.0, 0.0, 0, 0, "");
+ } else {
+ bt= uiDefBut(block, LABEL, 0, md->title, startx, (short)(starty+rows*boxh), (short)width, (short)boxh, NULL, 0.0, 0.0, 0, 0, "");
+ bt->flag= UI_TEXT_LEFT;
+ }
+ uiSetCurFont(block, block->font);
+
+ }
+
+ for(a=0; a<md->nitems; a++) {
+
+ x1= but->x1 + width*((int)(md->nitems-a-1)/rows);
+ y1= but->y1 - boxh*(rows - ((md->nitems - a - 1)%rows)) + (rows*boxh);
+
+ if (strcmp(md->items[md->nitems-a-1].str, "%l")==0) {
+ uiDefBut(block, SEPR, B_NOP, "", x1, y1,(short)(width-(rows>1)), (short)(boxh-1), NULL, 0.0, 0.0, 0, 0, "");
+ }
+ else if(md->items[md->nitems-a-1].icon) {
+ uiBut *bt= uiDefIconTextBut(block, BUTM|but->pointype, but->retval, md->items[md->nitems-a-1].icon ,md->items[md->nitems-a-1].str, x1, y1,(short)(width-(rows>1)), (short)(boxh-1), but->poin, (float) md->items[md->nitems-a-1].retval, 0.0, 0, 0, "");
+ if(active==a) bt->flag |= UI_ACTIVE;
+ }
+ else {
+ uiBut *bt= uiDefBut(block, BUTM|but->pointype, but->retval, md->items[md->nitems-a-1].str, x1, y1,(short)(width-(rows>1)), (short)(boxh-1), but->poin, (float) md->items[md->nitems-a-1].retval, 0.0, 0, 0, "");
+ if(active==a) bt->flag |= UI_ACTIVE;
+ }
+ }
+
+ /* the code up here has flipped locations, because of change of preferred order */
+ /* thats why we have to switch list order too, to make arrowkeys work */
+
+ lb.first= lb.last= NULL;
+ bt= block->buttons.first;
+ while(bt) {
+ uiBut *next= bt->next;
+ BLI_remlink(&block->buttons, bt);
+ BLI_addhead(&lb, bt);
+ bt= next;
+ }
+ block->buttons= lb;
+
+ /* and lets go */
+ block->direction= UI_TOP;
+ ui_positionblock(block, but);
+
+ /* blocks can come (and get scaled) from a normal window, now we go to screenspace */
+ block->win= G.curscreen->mainwin;
+ for(bt= block->buttons.first; bt; bt= bt->next) bt->win= block->win;
+ bwin_getsinglematrix(block->win, block->winmat);
+
+ event= uiDoBlocks(&listb, 0);
+
+ menudata_free(md);
+
+ but->flag &= ~UI_SELECT;
+ ui_check_but(but);
+ /* no draw of button now, for floating panels the matrix now is invalid...
+ the button still is active, and will be redrawn in main loop to de-activate it */
+ /* but, if no hilites, we send redraw to queue */
+ if(but->flag & UI_NO_HILITE)
+ addqueue(but->block->winq, REDRAW, 1);
+
+ uibut_do_func(but);
+
+ /* return no existing event, because the menu sends events instead */
+ return -1;
+}
+
+/* ********************** NEXT/PREV for arrowkeys etc ************** */
+
+static uiBut *ui_but_prev(uiBut *but)
+{
+ while(but->prev) {
+ but= but->prev;
+ if(but->type!=LABEL && but->type!=SEPR && but->type!=ROUNDBOX) return but;
+ }
+ return NULL;
+}
+
+static uiBut *ui_but_next(uiBut *but)
+{
+ while(but->next) {
+ but= but->next;
+ if(but->type!=LABEL && but->type!=SEPR && but->type!=ROUNDBOX) return but;
+ }
+ return NULL;
+}
+
+static uiBut *ui_but_first(uiBlock *block)
+{
+ uiBut *but;
+
+ but= block->buttons.first;
+ while(but) {
+ if(but->type!=LABEL && but->type!=SEPR && but->type!=ROUNDBOX) return but;
+ but= but->next;
+ }
+ return NULL;
+}
+
+static uiBut *ui_but_last(uiBlock *block)
+{
+ uiBut *but;
+
+ but= block->buttons.last;
+ while(but) {
+ if(but->type!=LABEL && but->type!=SEPR && but->type!=ROUNDBOX) return but;
+ but= but->prev;
+ }
+ return NULL;
+}
+
+
+/* ************* IN-BUTTON TEXT SELECTION/EDITING ************* */
+
+static short ui_delete_selection_edittext(uiBut *but)
+{
+ int x;
+ short deletedwidth=0;
+ char *str;
+
+ str= (char *)but->poin;
+
+ deletedwidth = (but->selend - but->selsta);
+
+ for(x=0; x< strlen(str); x++) {
+ if (but->selend + x <= strlen(str) ) {
+ str[but->selsta + x]= str[but->selend + x];
+ } else {
+ str[but->selsta + x]= '\0';
+ break;
+ }
+ }
+ but->pos = but->selend = but->selsta;
+
+ return deletedwidth;
+}
+
+static void ui_set_cursor_pos_edittext(uiBut *but, short sx)
+{
+ char backstr[UI_MAX_DRAW_STR];
+
+ BLI_strncpy(backstr, but->drawstr, UI_MAX_DRAW_STR);
+ but->pos= strlen(backstr)-but->ofs;
+
+ while((but->aspect*BIF_GetStringWidth(but->font, backstr+but->ofs, 0) + but->x1) > sx) {
+ if (but->pos <= 0) break;
+ but->pos--;
+ backstr[but->pos+but->ofs] = 0;
+ }
+
+ but->pos -= strlen(but->str);
+ but->pos += but->ofs;
+ if(but->pos<0) but->pos= 0;
+}
+
+
+/* ************* EVENTS ************* */
+
+void uiGetMouse(int win, short *adr)
+{
+ int x, y;
+ float xwin, ywin;
+
+ getmouseco_sc(adr);
+ if (win == G.curscreen->mainwin) return;
+
+ bwin_getsuborigin(win, &x, &y);
+
+ adr[0]-= x;
+ adr[1]-= y;
+
+ xwin= adr[0];
+ ywin= adr[1];
+
+ ui_window_to_graphics(win, &xwin, &ywin);
+
+ adr[0]= (short)(xwin+0.5);
+ adr[1]= (short)(ywin+0.5);
+}
+
+static void ui_is_but_sel(uiBut *but)
+{
+ double value;
+ int lvalue;
+ short push=0, true=1;
+
+ value= ui_get_but_val(but);
+
+ if( but->type==TOGN || but->type==ICONTOGN) true= 0;
+
+ if( but->bit ) {
+ lvalue= (int)value;
+ if( BTST(lvalue, (but->bitnr)) ) push= true;
+ else push= !true;
+ }
+ else {
+ switch(but->type) {
+ case BUT:
+ push= 0;
+ break;
+ case KEYEVT:
+ if (value==-1) push= 1;
+ break;
+ case TOG:
+ case TOGR:
+ case TOG3:
+ case BUT_TOGDUAL:
+ case ICONTOG:
+ if(value!=but->min) push= 1;
+ break;
+ case ICONTOGN:
+ case TOGN:
+ if(value==0.0) push= 1;
+ break;
+ case ROW:
+ if(value == but->max) push= 1;
+ break;
+ case COL:
+ push= 1;
+ break;
+ default:
+ push= 2;
+ break;
+ }
+ }
+
+ if(push==2);
+ else if(push==1) but->flag |= UI_SELECT;
+ else but->flag &= ~UI_SELECT;
+}
+
+static int ui_do_but_BUT(uiBut *but)
+{
+ int activated;
+
+ do {
+ int oflag= but->flag;
+ short mval[2];
+
+ uiGetMouse(mywinget(), mval);
+
+ if (uibut_contains_pt(but, mval))
+ but->flag |= UI_SELECT;
+ else
+ but->flag &= ~UI_SELECT;
+
+ if (but->flag != oflag) {
+ ui_draw_but(but);
+ ui_block_flush_back(but->block);
+ }
+
+ PIL_sleep_ms(10);
+ } while (get_mbut() & L_MOUSE);
+
+ activated= (but->flag & UI_SELECT);
+
+ if(activated) {
+ UIafterfunc_but= but->func;
+ UIafterfunc_arg1= but->func_arg1;
+ UIafterfunc_arg2= but->func_arg2;
+ /* no more uibut_do_func(but); this button calls fileselecting windows */
+ }
+
+ but->flag &= ~UI_SELECT;
+ ui_draw_but(but);
+
+ return activated?but->retval:0;
+}
+
+static int ui_do_but_KEYEVT(uiBut *but)
+{
+ unsigned short event= 0;
+ short val;
+
+ /* flag for ui_check_but */
+ ui_set_but_val(but, -1);
+ ui_check_but(but);
+ ui_draw_but(but);
+ ui_block_flush_back(but->block);
+
+ do {
+ event= extern_qread(&val);
+ } while (!event || !val || ELEM(event, MOUSEX, MOUSEY));
+
+ if (!key_event_to_string(event)[0]) event= 0;
+
+ ui_set_but_val(but, (double) event);
+ ui_check_but(but);
+ ui_draw_but(but);
+
+ return (event!=0);
+}
+
+static int ui_do_but_TOG(uiBlock *block, uiBut *but, int qual)
+{
+ uiBut *bt;
+ double value;
+ int w, lvalue, push;
+
+ /* local hack... */
+ if(but->type==BUT_TOGDUAL && qual==LR_CTRLKEY) {
+ if(but->pointype==SHO)
+ but->poin += 2;
+ else if(but->pointype==INT)
+ but->poin += 4;
+ }
+
+ value= ui_get_but_val(but);
+ lvalue= (int)value;
+
+ if(but->bit) {
+ w= BTST(lvalue, but->bitnr);
+ if(w) lvalue = BCLR(lvalue, but->bitnr);
+ else lvalue = BSET(lvalue, but->bitnr);
+
+ if(but->type==TOGR) {
+ if( (get_qual() & LR_SHIFTKEY)==0 ) {
+ lvalue= 1<<(but->bitnr);
+
+ ui_set_but_val(but, (double)lvalue);
+
+ bt= block->buttons.first;
+ while(bt) {
+ if( bt!=but && bt->poin==but->poin ) {
+ ui_is_but_sel(bt);
+ ui_draw_but(bt);
+ }
+ bt= bt->next;
+ }
+ }
+ else {
+ if(lvalue==0) lvalue= 1<<(but->bitnr);
+ }
+ }
+
+ ui_set_but_val(but, (double)lvalue);
+ if(but->type==ICONTOG || but->type==ICONTOGN) ui_check_but(but);
+ // no frontbuffer draw for this one
+ if(but->type==BUT_TOGDUAL);
+ else if((but->flag & UI_NO_HILITE)==0) ui_draw_but(but);
+ }
+ else {
+
+ if(value==0.0) push= 1;
+ else push= 0;
+
+ if(but->type==TOGN || but->type==ICONTOGN) push= !push;
+ ui_set_but_val(but, (double)push);
+ if(but->type==ICONTOG || but->type==ICONTOGN) ui_check_but(but);
+ // no frontbuffer draw for this one
+ if((but->flag & UI_NO_HILITE)==0) ui_draw_but(but);
+ }
+
+ /* end local hack... */
+ if(but->type==BUT_TOGDUAL && qual==LR_CTRLKEY) {
+ if(but->pointype==SHO)
+ but->poin -= 2;
+ else if(but->pointype==INT)
+ but->poin -= 4;
+ }
+
+ /* no while loop...this button is used for viewmove */
+
+ uibut_do_func(but);
+
+ return but->retval;
+}
+
+static int ui_do_but_ROW(uiBlock *block, uiBut *but)
+{
+ uiBut *bt;
+
+ ui_set_but_val(but, but->max);
+ ui_draw_but(but);
+
+ bt= block->buttons.first;
+ while(bt) {
+ if( bt!=but && bt->type==ROW ) {
+ if(bt->min==but->min) {
+ ui_is_but_sel(bt);
+ ui_draw_but(bt);
+ }
+ }
+ bt= bt->next;
+ }
+ return but->retval;
+}
+
+/* return 1 if char ch is special character otherwise
+ * it returns 0 */
+static short test_special_char(char ch)
+{
+ switch(ch) {
+ case '\\':
+ case '/':
+ case '~':
+ case '!':
+ case '@':
+ case '#':
+ case '$':
+ case '%':
+ case '^':
+ case '&':
+ case '*':
+ case '(':
+ case ')':
+ case '+':
+ case '=':
+ case '{':
+ case '}':
+ case '[':
+ case ']':
+ case ':':
+ case ';':
+ case '\'':
+ case '\"':
+ case '<':
+ case '>':
+ case ',':
+ case '.':
+ case '?':
+ case '_':
+ case '-':
+ case ' ':
+ return 1;
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int ui_do_but_TEX(uiBut *but)
+{
+ unsigned short dev;
+ short x, y, mval[2], len=0, dodraw, selextend=0;
+ char *str, backstr[UI_MAX_DRAW_STR];
+ short capturing, sx, sy, prevx;
+
+ str= (char *)but->poin;
+
+ but->flag |= UI_SELECT;
+
+ uiGetMouse(mywinget(), mval);
+
+ /* set cursor pos to the end of the text */
+ but->pos = strlen(str);
+ but->selsta = 0;
+ but->selend = strlen(but->drawstr) - strlen(but->str);
+
+ /* backup */
+ BLI_strncpy(backstr, but->poin, UI_MAX_DRAW_STR);
+
+ ui_draw_but(but);
+ ui_block_flush_back(but->block);
+
+ while (get_mbut() & L_MOUSE) BIF_wait_for_statechange();
+ len= strlen(str);
+
+ but->min= 0.0;
+
+ capturing = TRUE;
+ while(capturing) {
+ char ascii;
+ short val;
+
+ dodraw= 0;
+ dev = extern_qread_ext(&val, &ascii);
+
+ if(dev==INPUTCHANGE) break;
+ else if(get_mbut() & R_MOUSE) break;
+ else if(get_mbut() & L_MOUSE) {
+ uiGetMouse(mywinget(), mval);
+ sx = mval[0]; sy = mval[1];
+
+ if ((but->y1 <= sy) && (sy <= but->y2) && (but->x1 <= sx) && (sx <= but->x2)) {
+ ui_set_cursor_pos_edittext(but, mval[0]);
+
+ but->selsta = but->selend = but->pos;
+
+ /* drag text select */
+ prevx= mval[0];
+ while (get_mbut() & L_MOUSE) {
+ uiGetMouse(mywinget(), mval);
+
+ if(prevx!=mval[0]) {
+
+ if (mval[0] > sx) selextend = EXTEND_RIGHT;
+ else if (mval[0] < sx) selextend = EXTEND_LEFT;
+
+ ui_set_cursor_pos_edittext(but, mval[0]);
+
+ if (selextend == EXTEND_RIGHT) but->selend = but->pos;
+ if (selextend == EXTEND_LEFT) but->selsta = but->pos;
+
+ ui_check_but(but);
+ ui_draw_but(but);
+ ui_block_flush_back(but->block);
+ }
+ PIL_sleep_ms(10);
+ }
+ dodraw= 1;
+ } else break;
+ }
+ else if(dev==ESCKEY) break;
+ else if(dev==MOUSEX) val= 0;
+ else if(dev==MOUSEY) val= 0;
+
+ /* cut, copy, paste selected text */
+ /* mainqread discards ascii values < 32, so can't do this cleanly within the if(ascii) block*/
+ else if ( (val) &&
+ ((G.qual & LR_COMMANDKEY) || (G.qual & LR_CTRLKEY)) &&
+ ((dev==XKEY) || (dev==CKEY) || (dev==VKEY)) ) {
+
+
+ /* paste */
+ if (dev==VKEY) {
+ /* paste over the current selection */
+ if ((but->selend - but->selsta) > 0) {
+ len -= ui_delete_selection_edittext(but);
+ }
+
+ for (y=0; y<strlen(but_copypaste_str); y++)
+ {
+ /* add contents of buffer */
+ if(len < but->max) {
+ for(x= but->max; x>but->pos; x--)
+ str[x]= str[x-1];
+ str[but->pos]= but_copypaste_str[y];
+ but->pos++;
+ len++;
+ str[len]= '\0';
+ }
+ }
+ if (strlen(but_copypaste_str) > 0) dodraw= 1;
+ }
+ /* cut & copy */
+ else if ( (dev==XKEY) || (dev==CKEY) ) {
+ /* copy the contents to the copypaste buffer */
+ for(x= but->selsta; x <= but->selend; x++) {
+ if (x==but->selend)
+ but_copypaste_str[x] = '\0';
+ else
+ but_copypaste_str[(x - but->selsta)] = str[x];
+ }
+
+ /* for cut only, delete the selection afterwards */
+ if (dev==XKEY) {
+ if ((but->selend - but->selsta) > 0) {
+ len -= ui_delete_selection_edittext(but);
+
+ if (len < 0) len = 0;
+ dodraw=1;
+ }
+ }
+ }
+ }
+ else if((ascii)){
+
+ if(len-(but->selend - but->selsta)+1 <= but->max) {
+
+ /* type over the current selection */
+ if ((but->selend - but->selsta) > 0) {
+ len -= ui_delete_selection_edittext(but);
+ }
+
+ if(len < but->max) {
+ for(x= but->max; x>but->pos; x--)
+ str[x]= str[x-1];
+ str[but->pos]= ascii;
+ but->pos++;
+ len++;
+ str[len]= '\0';
+ dodraw= 1;
+ }
+ }
+ }
+ else if(val) {
+
+ switch (dev) {
+
+ case RIGHTARROWKEY:
+ /* if there's a selection */
+ if ((but->selend - but->selsta) > 0) {
+ /* extend the selection based on the first direction taken */
+ if(G.qual & LR_SHIFTKEY) {
+ if (!selextend) {
+ selextend = EXTEND_RIGHT;
+ }
+ if (selextend == EXTEND_RIGHT) {
+ but->selend++;
+ if (but->selend > len) but->selend = len;
+ } else if (selextend == EXTEND_LEFT) {
+ but->selsta++;
+ /* if the selection start has gone past the end,
+ * flip them so they're in sync again */
+ if (but->selsta == but->selend) {
+ but->pos = but->selsta;
+ selextend = EXTEND_RIGHT;
+ }
+ }
+ } else {
+ but->selsta = but->pos = but->selend;
+ selextend = 0;
+ }
+ } else {
+ if(G.qual & LR_SHIFTKEY) {
+ /* make a selection, starting from the cursor position */
+ but->selsta = but->pos;
+
+ but->pos++;
+ if(but->pos>strlen(str)) but->pos= strlen(str);
+
+ but->selend = but->pos;
+ } else if(G.qual & LR_CTRLKEY) {
+ /* jump betweenn special characters (/,\,_,-, etc.),
+ * look at function test_special_char() for complete
+ * list of special character, ctr -> */
+ while(but->pos < len) {
+ but->pos++;
+ if(test_special_char(str[but->pos])) break;
+ }
+ } else {
+ but->pos++;
+ if(but->pos>strlen(str)) but->pos= strlen(str);
+ }
+ }
+ dodraw= 1;
+ break;
+
+ case LEFTARROWKEY:
+ /* if there's a selection */
+ if ((but->selend - but->selsta) > 0) {
+ /* extend the selection based on the first direction taken */
+ if(G.qual & LR_SHIFTKEY) {
+ if (!selextend) {
+ selextend = EXTEND_LEFT;
+ }
+ if (selextend == EXTEND_LEFT) {
+ but->selsta--;
+ if (but->selsta < 0) but->selsta = 0;
+ } else if (selextend == EXTEND_RIGHT) {
+ but->selend--;
+ /* if the selection start has gone past the end,
+ * flip them so they're in sync again */
+ if (but->selsta == but->selend) {
+ but->pos = but->selsta;
+ selextend = EXTEND_LEFT;
+ }
+ }
+ } else {
+ but->pos = but->selend = but->selsta;
+ selextend = 0;
+ }
+ } else {
+ if(G.qual & LR_SHIFTKEY) {
+ /* make a selection, starting from the cursor position */
+ but->selend = but->pos;
+
+ but->pos--;
+ if(but->pos<0) but->pos= 0;
+
+ but->selsta = but->pos;
+ } else if(G.qual & LR_CTRLKEY) {
+ /* jump betweenn special characters (/,\,_,-, etc.),
+ * look at function test_special_char() for complete
+ * list of special character, ctr -> */
+ while(but->pos > 0){
+ but->pos--;
+ if(test_special_char(str[but->pos])) break;
+ }
+ } else {
+ if(but->pos>0) but->pos--;
+ }
+ }
+ dodraw= 1;
+ break;
+
+ case DOWNARROWKEY:
+ case ENDKEY:
+ if(G.qual & LR_SHIFTKEY) {
+ but->selsta = but->pos;
+ but->selend = strlen(str);
+ selextend = EXTEND_RIGHT;
+ } else {
+ but->selsta = but->selend = but->pos= strlen(str);
+ }
+ dodraw= 1;
+ break;
+
+ case UPARROWKEY:
+ case HOMEKEY:
+ if(G.qual & LR_SHIFTKEY) {
+ but->selend = but->pos;
+ but->selsta = 0;
+ selextend = EXTEND_LEFT;
+ } else {
+ but->selsta = but->selend = but->pos= 0;
+ }
+ dodraw= 1;
+ break;
+
+ case PADENTER:
+ case RETKEY:
+ capturing = FALSE;
+ break;
+
+ case DELKEY:
+ if ((but->selend - but->selsta) > 0) {
+ len -= ui_delete_selection_edittext(but);
+
+ if (len < 0) len = 0;
+ dodraw=1;
+ }
+ else if(but->pos>=0 && but->pos<strlen(str)) {
+ for(x=but->pos; x<=strlen(str); x++)
+ str[x]= str[x+1];
+ str[--len]='\0';
+ dodraw= 1;
+ }
+ break;
+
+ case BACKSPACEKEY:
+ if(len!=0) {
+ if ((but->selend - but->selsta) > 0) {
+ len -= ui_delete_selection_edittext(but);
+
+ if (len < 0) len = 0;
+ dodraw=1;
+ }
+ else if(get_qual() & LR_SHIFTKEY) {
+ str[0]= 0;
+ but->pos= 0;
+ len= 0;
+ dodraw= 1;
+ }
+ else if(but->pos>0) {
+ for(x=but->pos; x<=strlen(str); x++)
+ str[x-1]= str[x];
+ but->pos--;
+ str[--len]='\0';
+ dodraw= 1;
+ }
+ }
+ break;
+
+ case TABKEY:
+ if(but->autocomplete_func) {
+ but->autocomplete_func(str, but->autofunc_arg);
+ but->pos= strlen(str);
+ len= but->pos;
+ dodraw= 1;
+ }
+ else capturing= FALSE;
+
+ break;
+ }
+ }
+
+
+ if(dodraw) {
+ ui_check_but(but);
+ ui_draw_but(but);
+ ui_block_flush_back(but->block);
+ }
+ }
+
+ if(dev==ESCKEY) strcpy(but->poin, backstr);
+ but->pos= -1;
+ but->flag &= ~UI_SELECT;
+
+ if(dev!=ESCKEY) {
+ /* give butfunc the original text too */
+ /* feature used for bone renaming, channels, etc */
+ if(but->func_arg2==NULL) but->func_arg2= backstr;
+ uibut_do_func(but);
+ }
+
+ ui_check_but(but);
+ ui_draw_but(but);
+
+ if(dev==TABKEY) addqueue(but->win, G.qual?BUT_PREV:BUT_NEXT, 1);
+
+ if(dev!=ESCKEY) return but->retval;
+ else return B_NOP; // prevent event to be passed on
+}
+
+
+static int ui_act_as_text_but(uiBut *but)
+{
+ void *but_func;
+ double value;
+ float min, max;
+ int temp, retval, textleft;
+ char str[UI_MAX_DRAW_STR], *point;
+
+ /* this function is abused for tab-cycling */
+ if(but->type==TEX)
+ return ui_do_but_TEX(but);
+
+ value= ui_get_but_val(but);
+ if( but->pointype==FLO ) {
+ if(but->a2) { /* amount of digits defined */
+ if(but->a2==1) sprintf(str, "%.1f", value);
+ else if(but->a2==2) sprintf(str, "%.2f", value);
+ else if(but->a2==3) sprintf(str, "%.3f", value);
+ else sprintf(str, "%.4f", value);
+ }
+ else sprintf(str, "%.3f", value);
+ }
+ else {
+ sprintf(str, "%d", (int)value);
+ }
+ /* store values before calling as text button */
+ point= but->poin;
+ but->poin= str;
+ but_func= but->func;
+ but->func= NULL;
+ min= but->min;
+ max= but->max;
+ but->min= 0.0;
+ but->max= UI_MAX_DRAW_STR - 1; /* for py strings evaluation */
+ temp= but->type;
+ but->type= TEX;
+ textleft= but->flag & UI_TEXT_LEFT;
+ but->flag |= UI_TEXT_LEFT;
+ ui_check_but(but);
+
+ retval= ui_do_but_TEX(but);
+
+ /* restore values */
+ but->type= temp;
+ but->poin= point;
+ but->func= but_func;
+ but->min= min;
+ but->max= max;
+ if(textleft==0) but->flag &= ~UI_TEXT_LEFT;
+
+ if(BPY_button_eval(str, &value)) {
+ /* Uncomment this if you want to see an error message (and annoy users) */
+ /* error("Invalid Python expression, check console");*/
+ value = 0.0f; /* Zero out value on error */
+
+ if(str[0])
+ retval = 0; /* invalidate return value if eval failed, except when string was null */
+ }
+
+ if(but->pointype!=FLO) value= (int)value;
+
+ if(value<min) value= min;
+ if(value>max) value= max;
+
+ ui_set_but_val(but, value);
+ ui_check_but(but);
+ ui_draw_but(but);
+
+ return retval;
+}
+
+static int ui_do_but_NUM(uiBut *but)
+{
+ double value;
+ float deler, fstart, f, tempf, pressure;
+ int lvalue, temp, orig_x; /* , firsttime=1; */
+ short retval=0, qual, sx, mval[2], pos=0;
+
+ but->flag |= UI_SELECT;
+ ui_draw_but(but);
+ ui_block_flush_back(but->block);
+
+ uiGetMouse(mywinget(), mval);
+ value= ui_get_but_val(but);
+
+ sx= mval[0];
+ orig_x = sx; /* Store so we can scale the rate of change by the dist the mouse is from its original xlocation */
+ fstart= (value - but->min)/(but->max-but->min);
+ f= fstart;
+
+ temp= (int)value;
+ tempf= value;
+
+ if(get_qual() & LR_SHIFTKEY) { /* make it textbut */
+ if( ui_act_as_text_but(but) ) retval= but->retval;
+ }
+ else {
+ retval= but->retval;
+ /* firsttime: this button can be approached with enter as well */
+
+ /* drag-lock - prevent unwanted scroll adjustments */
+ /* change last value (now 3) to adjust threshold in pixels */
+ while (get_mbut() & L_MOUSE & ( abs(mval[0]-sx) <= 3) ) {
+ uiGetMouse(mywinget(), mval);
+ }
+ sx = mval[0]; /* ignore mouse movement within drag-lock */
+
+ while (get_mbut() & L_MOUSE) {
+ qual= get_qual();
+ pressure = get_pressure();
+
+ uiGetMouse(mywinget(), mval);
+
+ deler= 500;
+ if( but->pointype!=FLO ) {
+
+ if( (but->max-but->min)<100 ) deler= 200.0;
+ if( (but->max-but->min)<25 ) deler= 50.0;
+ }
+
+ if(qual & LR_SHIFTKEY) deler*= 10.0;
+ if(qual & LR_ALTKEY) deler*= 20.0;
+
+ /* de-sensitise based on tablet pressure */
+ if (ELEM(get_activedevice(), DEV_STYLUS, DEV_ERASER)) deler /= pressure;
+
+ if(mval[0] != sx) {
+ if( but->pointype==FLO && but->max-but->min > 11) {
+ /* non linear change in mouse input- good for high precicsion */
+ f+= (((float)(mval[0]-sx))/deler) * (fabs(orig_x-mval[0])*0.002);
+ } else if ( but->pointype!=FLO && but->max-but->min > 129) { /* only scale large int buttons */
+ /* non linear change in mouse input- good for high precicsionm ints need less fine tuning */
+ f+= (((float)(mval[0]-sx))/deler) * (fabs(orig_x-mval[0])*0.004);
+ } else {
+ /*no scaling */
+ f+= ((float)(mval[0]-sx))/deler ;
+ }
+
+ if(f>1.0) f= 1.0;
+ if(f<0.0) f= 0.0;
+ sx= mval[0];
+ tempf= ( but->min + f*(but->max-but->min));
+
+ if( but->pointype!=FLO ) {
+
+ temp= floor(tempf+.5);
+
+ if(tempf==but->min || tempf==but->max);
+ else if(qual & LR_CTRLKEY) {
+ if(qual & LR_SHIFTKEY) temp= 100*(temp/100);
+ else temp= 10*(temp/10);
+ }
+ if( temp>=but->min && temp<=but->max) {
+
+ value= ui_get_but_val(but);
+ lvalue= (int)value;
+
+ if(temp != lvalue ) {
+ pos= 1;
+ ui_set_but_val(but, (double)temp);
+ ui_check_but(but);
+ ui_draw_but(but);
+ ui_block_flush_back(but->block);
+
+ uibut_do_func(but);
+ }
+ }
+
+ }
+ else {
+ temp= 0;
+ if(qual & LR_CTRLKEY) {
+ if(qual & LR_SHIFTKEY) {
+ if(tempf==but->min || tempf==but->max);
+ else if(but->max-but->min < 2.10) tempf= 0.01*floor(100.0*tempf);
+ else if(but->max-but->min < 21.0) tempf= 0.1*floor(10.0*tempf);
+ else tempf= floor(tempf);
+ }
+ else {
+ if(tempf==but->min || tempf==but->max);
+ else if(but->max-but->min < 2.10) tempf= 0.1*floor(10*tempf);
+ else if(but->max-but->min < 21.0) tempf= floor(tempf);
+ else tempf= 10.0*floor(tempf/10.0);
+ }
+ }
+
+ if( tempf>=but->min && tempf<=but->max) {
+ value= ui_get_but_val(but);
+
+ if(tempf != value ) {
+ pos= 1;
+ ui_set_but_val(but, tempf);
+ ui_check_but(but);
+ ui_draw_but(but);
+ ui_block_flush_back(but->block);
+ }
+ }
+
+ }
+ }
+ BIF_wait_for_statechange();
+ }
+
+ /* click on the side arrows to increment/decrement, click inside
+ * to edit the value directly */
+ if(pos==0) { /* plus 1 or minus 1 */
+ if( but->pointype!=FLO ) {
+
+ if(sx < (but->x1 + (but->x2 - but->x1)/3 - 3)) {
+ temp--;
+ if( temp>=but->min && temp<=but->max) ui_set_but_val(but, (double)temp);
+ }
+ else if(sx > (but->x1 + (2*(but->x2 - but->x1)/3) + 3)) {
+ temp++;
+ if( temp>=but->min && temp<=but->max) ui_set_but_val(but, (double)temp);
+ }
+ else {
+ if( ui_act_as_text_but(but) ); else retval= 0;
+ }
+ }
+ else {
+
+ if(sx < (but->x1 + (but->x2 - but->x1)/3 - 3)) {
+ tempf-= 0.01*but->a1;
+ if (tempf < but->min) tempf = but->min;
+ ui_set_but_val(but, tempf);
+ }
+ else if(sx > but->x1 + (2*((but->x2 - but->x1)/3) + 3)) {
+ tempf+= 0.01*but->a1;
+ if (tempf < but->min) tempf = but->min;
+ ui_set_but_val(but, tempf);
+ }
+ else {
+ if( ui_act_as_text_but(but) ); else retval= 0;
+ }
+ }
+ }
+ }
+
+ but->flag &= ~UI_SELECT;
+ ui_check_but(but);
+ ui_draw_but(but);
+ ui_block_flush_back(but->block);
+
+ uibut_do_func(but);
+
+ return retval;
+}
+
+static int ui_do_but_TOG3(uiBut *but)
+{
+
+ if( but->pointype==SHO ) {
+ short *sp= (short *)but->poin;
+
+ if( BTST(sp[1], but->bitnr)) {
+ sp[1]= BCLR(sp[1], but->bitnr);
+ sp[0]= BCLR(sp[0], but->bitnr);
+ }
+ else if( BTST(sp[0], but->bitnr)) {
+ sp[1]= BSET(sp[1], but->bitnr);
+ } else {
+ sp[0]= BSET(sp[0], but->bitnr);
+ }
+ }
+ else {
+ if( BTST(*(but->poin+2), but->bitnr)) {
+ *(but->poin+2)= BCLR(*(but->poin+2), but->bitnr);
+ *(but->poin)= BCLR(*(but->poin), but->bitnr);
+ }
+ else if( BTST(*(but->poin), but->bitnr)) {
+ *(but->poin+2)= BSET(*(but->poin+2), but->bitnr);
+ } else {
+ *(but->poin)= BSET(*(but->poin), but->bitnr);
+ }
+ }
+
+ ui_is_but_sel(but);
+ ui_draw_but(but);
+
+ return but->retval;
+}
+
+static int ui_do_but_ICONROW(uiBut *but)
+{
+ ListBase listb= {NULL, NULL};
+ uiBlock *block;
+ int a;
+
+ but->flag |= UI_SELECT;
+ ui_draw_but(but);
+ ui_block_flush_back(but->block); // flush because this button creates own blocks loop
+
+ /* here we go! */
+ block= uiNewBlock(&listb, "menu", UI_EMBOSSP, UI_HELV, but->win);
+ block->flag= UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_NUMSELECT;
+ block->themecol= TH_MENU_ITEM;
+
+ for(a=(int)but->min; a<=(int)but->max; a++) {
+ uiDefIconBut(block, BUTM|but->pointype, but->retval, but->icon+(a-but->min), 0, (short)(18*a), (short)(but->x2-but->x1-4), 18, but->poin, (float)a, 0.0, 0, 0, "");
+ }
+ block->direction= UI_TOP;
+ ui_positionblock(block, but);
+
+ /* the block is made with but-win, but is handled in mainwin space...
+ this is needs better implementation */
+ block->win= G.curscreen->mainwin;
+
+ uiDoBlocks(&listb, 0);
+
+ but->flag &= ~UI_SELECT;
+ ui_check_but(but);
+ ui_draw_but(but);
+
+ return but->retval;
+}
+
+static int ui_do_but_ICONTEXTROW(uiBut *but)
+{
+ uiBlock *block;
+ ListBase listb={NULL, NULL};
+ int width, a, xmax, ypos;
+ MenuData *md;
+
+ but->flag |= UI_SELECT;
+ ui_draw_but(but);
+ ui_block_flush_back(but->block); // flush because this button creates own blocks loop
+
+ block= uiNewBlock(&listb, "menu", UI_EMBOSSP, UI_HELV, but->win);
+ block->flag= UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_NUMSELECT;
+ block->themecol= TH_MENU_ITEM;
+
+ md= decompose_menu_string(but->str);
+
+ /* size and location */
+ /* expand menu width to fit labels */
+ if(md->title)
+ width= 2*strlen(md->title)+BIF_GetStringWidth(block->curfont, md->title, (U.transopts & USER_TR_MENUS));
+ else
+ width= 0;
+
+ for(a=0; a<md->nitems; a++) {
+ xmax= BIF_GetStringWidth(block->curfont, md->items[a].str, (U.transopts & USER_TR_MENUS));
+ if(xmax>width) width= xmax;
+ }
+
+ width+= 30;
+ if (width<50) width=50;
+
+ ypos = 1;
+
+ /* loop through the menu options and draw them out with icons & text labels */
+ for(a=0; a<md->nitems; a++) {
+
+ /* add a space if there's a separator (%l) */
+ if (strcmp(md->items[a].str, "%l")==0) {
+ ypos +=3;
+ }
+ else {
+ uiDefIconTextBut(block, BUTM|but->pointype, but->retval, (short)((but->icon)+(md->items[a].retval-but->min)), md->items[a].str, 0, ypos,(short)width, 19, but->poin, (float) md->items[a].retval, 0.0, 0, 0, "");
+ ypos += 20;
+ }
+ }
+
+ if(md->title) {
+ uiBut *bt;
+ uiSetCurFont(block, block->font+1);
+ bt= uiDefBut(block, LABEL, 0, md->title, 0, ypos, (short)width, 19, NULL, 0.0, 0.0, 0, 0, "");
+ uiSetCurFont(block, block->font);
+ bt->flag= UI_TEXT_LEFT;
+ }
+
+ block->direction= UI_TOP;
+ ui_positionblock(block, but);
+
+ /* the block is made with but-win, but is handled in mainwin space...
+ this is needs better implementation */
+ block->win= G.curscreen->mainwin;
+
+ uiBoundsBlock(block, 3);
+
+ uiDoBlocks(&listb, 0);
+
+ menudata_free(md);
+
+ but->flag &= ~UI_SELECT;
+ ui_check_but(but);
+ ui_draw_but(but);
+
+ uibut_do_func(but);
+
+ return but->retval;
+
+}
+
+static int ui_do_but_IDPOIN(uiBut *but)
+{
+ char str[UI_MAX_DRAW_STR];
+ ID *id;
+
+ id= *but->idpoin_idpp;
+ if(id) strcpy(str, id->name+2);
+ else str[0]= 0;
+
+ but->type= TEX;
+ but->poin= str;
+ but->min= 0.0;
+ but->max= 22.0;
+ ui_check_but(but);
+ ui_do_but_TEX(but);
+ but->poin= NULL;
+ but->type= IDPOIN;
+
+ but->idpoin_func(str, but->idpoin_idpp);
+ ui_check_but(but);
+ ui_draw_but(but);
+
+ return but->retval;
+}
+
+static int ui_do_but_SLI(uiBut *but)
+{
+ float f, fstart, tempf = 0.0, deler, value;
+ int sx, h, temp, pos=0, lvalue, redraw;
+ short mval[2], qual;
+
+ value= ui_get_but_val(but);
+ uiGetMouse(mywinget(), mval);
+
+ sx= mval[0];
+ h= but->y2-but->y1;
+ fstart= but->max-but->min;
+ fstart= (value - but->min)/fstart;
+ temp= 32767;
+
+ if( but->type==NUMSLI) deler= ( (but->x2-but->x1)/2 - 5.0*but->aspect);
+ else if( but->type==HSVSLI) deler= ( (but->x2-but->x1)/2 - 5.0*but->aspect);
+ else deler= (but->x2-but->x1- 5.0*but->aspect);
+
+
+ while (get_mbut() & L_MOUSE) {
+
+ qual= get_qual();
+ uiGetMouse(mywinget(), mval);
+
+ f= (float)(mval[0]-sx)/deler +fstart;
+
+ if (qual & LR_SHIFTKEY) {
+ f= (f-fstart)/10.0 + fstart;
+ }
+
+ CLAMP(f, 0.0, 1.0);
+ tempf= but->min+f*(but->max-but->min);
+ temp= floor(tempf+.5);
+
+ if(qual & LR_CTRLKEY) {
+ if(tempf==but->min || tempf==but->max);
+ else if( but->pointype==FLO ) {
+
+ if(qual & LR_SHIFTKEY) {
+ if(tempf==but->min || tempf==but->max);
+ else if(but->max-but->min < 2.10) tempf= 0.01*floor(100.0*tempf);
+ else if(but->max-but->min < 21.0) tempf= 0.1*floor(10.0*tempf);
+ else tempf= floor(tempf);
+ }
+ else {
+ if(but->max-but->min < 2.10) tempf= 0.1*floor(10*tempf);
+ else if(but->max-but->min < 21.0) tempf= floor(tempf);
+ else tempf= 10.0*floor(tempf/10.0);
+ }
+ }
+ else {
+ temp= 10*(temp/10);
+ tempf= temp;
+ }
+ }
+
+ value= ui_get_but_val(but);
+ lvalue= floor(value+0.5);
+
+ if( but->pointype!=FLO )
+ redraw= (temp != lvalue);
+ else
+ redraw= (tempf != value);
+
+ if (redraw) {
+ pos= 1;
+ ui_set_but_val(but, tempf);
+ ui_check_but(but);
+ ui_draw_but(but);
+ ui_block_flush_back(but->block);
+
+ if(but->a1) { /* color number */
+ uiBut *bt= but->prev;
+ while(bt) {
+ if(bt->a2 == but->a1) ui_draw_but(bt);
+ bt= bt->prev;
+ }
+ bt= but->next;
+ while(bt) {
+ if(bt->a2 == but->a1) ui_draw_but(bt);
+ bt= bt->next;
+ }
+ }
+ /* save current window matrix (global UIwinmat)
+ because button callback function MIGHT change it
+ - which has until now occured through the Python API
+ */
+ /* This is really not possible atm... nothing in Blender
+ supports such functionality even now. Calling function
+ callbacks while using a button screws up the UI (ton)
+ */
+ /* Mat4CpyMat4(curmatrix, UIwinmat);
+ uibut_do_func(but);
+ Mat4CpyMat4(UIwinmat, curmatrix); */
+ }
+ else BIF_wait_for_statechange();
+ }
+
+
+ if(temp!=32767 && pos==0) { /* plus 1 or minus 1 */
+
+ if( but->type==SLI) f= (float)(mval[0]-but->x1)/(but->x2-but->x1-h);
+ else f= (float)(mval[0]- (but->x1+but->x2)/2)/( (but->x2-but->x1)/2 - h);
+
+ f= but->min+f*(but->max-but->min);
+
+ if( but->pointype!=FLO ) {
+
+ if(f<temp) temp--;
+ else temp++;
+ if( temp>=but->min && temp<=but->max)
+ ui_set_but_val(but, (float)temp);
+
+ }
+ else {
+
+ if(f<tempf) tempf-=.01;
+ else tempf+=.01;
+ if( tempf>=but->min && tempf<=but->max)
+ ui_set_but_val(but, tempf);
+
+ }
+ }
+ ui_check_but(but);
+ ui_draw_but(but);
+ uibut_do_func(but);
+ ui_block_flush_back(but->block);
+
+ return but->retval;
+}
+
+static int ui_do_but_NUMSLI(uiBut *but)
+{
+ short mval[2];
+
+ /* first define if it's a slider or textbut */
+ uiGetMouse(mywinget(), mval);
+
+ if(mval[0]>= -6+(but->x1+but->x2)/2 ) { /* slider */
+ but->flag |= UI_SELECT;
+ ui_draw_but(but);
+ ui_do_but_SLI(but);
+ but->flag &= ~UI_SELECT;
+ }
+ else {
+ ui_act_as_text_but(but);
+ uibut_do_func(but); // this is done in ui_do_but_SLI() not in ui_act_as_text_but()
+ }
+
+ while(get_mbut() & L_MOUSE) BIF_wait_for_statechange();
+
+ ui_draw_but(but);
+
+ /* hsv patch */
+ if(but->type==HSVSLI) {
+
+ if(but->str[0]=='H') {
+ ui_draw_but(but->next);
+ ui_draw_but(but->next->next);
+ }
+ else if(but->str[0]=='S') {
+ ui_draw_but(but->next);
+ ui_draw_but(but->prev);
+ }
+ else if(but->str[0]=='V') {
+ ui_draw_but(but->prev);
+ ui_draw_but(but->prev->prev);
+ }
+ }
+
+ return but->retval;
+}
+
+/* event denotes if we make first item active or not */
+static uiBlock *ui_do_but_BLOCK(uiBut *but, int event)
+{
+ uiBlock *block;
+ uiBut *bt;
+
+ but->flag |= UI_SELECT;
+ ui_draw_but(but);
+
+ block= but->block_func(but->poin);
+ block->parent= but->block; /* allows checking for nested pulldowns */
+
+ block->xofs = -2; /* for proper alignment */
+
+ /* only used for automatic toolbox, so can set the shift flag */
+ if(but->flag & UI_MAKE_TOP) {
+ block->direction= UI_TOP|UI_SHIFT_FLIPPED;
+ uiBlockFlipOrder(block);
+ }
+ if(but->flag & UI_MAKE_DOWN) block->direction= UI_DOWN|UI_SHIFT_FLIPPED;
+ if(but->flag & UI_MAKE_LEFT) block->direction |= UI_LEFT;
+ if(but->flag & UI_MAKE_RIGHT) block->direction |= UI_RIGHT;
+
+ ui_positionblock(block, but);
+ block->flag |= UI_BLOCK_LOOP;
+
+ /* blocks can come (and get scaled) from a normal window, now we go to screenspace */
+ block->win= G.curscreen->mainwin;
+ for(bt= block->buttons.first; bt; bt= bt->next) bt->win= block->win;
+ bwin_getsinglematrix(block->win, block->winmat);
+
+ /* postpone draw, this will cause a new window matrix, first finish all other buttons */
+ block->flag |= UI_BLOCK_REDRAW;
+
+ if(event!=MOUSEX && event!=MOUSEY && event!=LEFTMOUSE && but->type==BLOCK) {
+ bt= ui_but_first(block);
+ if(bt) bt->flag |= UI_ACTIVE;
+ }
+
+ but->flag &= ~UI_SELECT;
+ uibut_do_func(but);
+
+ if(but->retval)
+ addqueue(curarea->win, UI_BUT_EVENT, (short)but->retval);
+
+ return block;
+}
+
+static int ui_do_but_BUTM(uiBut *but)
+{
+
+ ui_set_but_val(but, but->min);
+ UIafterfunc_butm= but->butm_func;
+ UIafterfunc_arg1= but->butm_func_arg;
+ UIafterval= but->a2;
+
+ return but->retval;
+}
+
+static int ui_do_but_LABEL(uiBut *but)
+{
+ uibut_do_func(but);
+ return but->retval;
+}
+
+static uiBut *ui_get_valid_link_button(uiBlock *block, uiBut *but, short *mval)
+{
+ uiBut *bt;
+
+ /* find button to link to */
+ for (bt= block->buttons.first; bt; bt= bt->next)
+ if(bt!=but && uibut_contains_pt(bt, mval))
+ break;
+
+ if (bt) {
+ if (but->type==LINK && bt->type==INLINK) {
+ if( but->link->tocode == (int)bt->min ) {
+ return bt;
+ }
+ }
+ else if(but->type==INLINK && bt->type==LINK) {
+ if( bt->link->tocode == (int)but->min ) {
+ return bt;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static int ui_is_a_link(uiBut *from, uiBut *to)
+{
+ uiLinkLine *line;
+ uiLink *link;
+
+ link= from->link;
+ if(link) {
+ line= link->lines.first;
+ while(line) {
+ if(line->from==from && line->to==to) return 1;
+ line= line->next;
+ }
+ }
+ return 0;
+}
+
+static uiBut *ui_find_inlink(uiBlock *block, void *poin)
+{
+ uiBut *but;
+
+ but= block->buttons.first;
+ while(but) {
+ if(but->type==INLINK) {
+ if(but->poin == poin) return but;
+ }
+ but= but->next;
+ }
+ return NULL;
+}
+
+static void ui_add_link_line(ListBase *listb, uiBut *but, uiBut *bt)
+{
+ uiLinkLine *line;
+
+ line= MEM_callocN(sizeof(uiLinkLine), "linkline");
+ BLI_addtail(listb, line);
+ line->from= but;
+ line->to= bt;
+}
+
+
+void uiComposeLinks(uiBlock *block)
+{
+ uiBut *but, *bt;
+ uiLink *link;
+ void ***ppoin;
+ int a;
+
+ but= block->buttons.first;
+ while(but) {
+ if(but->type==LINK) {
+ link= but->link;
+
+ /* for all pointers in the array */
+ if(link) {
+ if(link->ppoin) {
+ ppoin= link->ppoin;
+ for(a=0; a < *(link->totlink); a++) {
+ bt= ui_find_inlink(block, (*ppoin)[a] );
+ if(bt) {
+ ui_add_link_line(&link->lines, but, bt);
+ }
+ }
+ }
+ else if(link->poin) {
+ bt= ui_find_inlink(block, *(link->poin) );
+ if(bt) {
+ ui_add_link_line(&link->lines, but, bt);
+ }
+ }
+ }
+ }
+ but= but->next;
+ }
+}
+
+static void ui_add_link(uiBut *from, uiBut *to)
+{
+ /* in 'from' we have to add a link to 'to' */
+ uiLink *link;
+ void **oldppoin;
+ int a;
+
+ if(ui_is_a_link(from, to)) {
+ printf("already exists\n");
+ return;
+ }
+
+ link= from->link;
+
+ /* are there more pointers allowed? */
+ if(link->ppoin) {
+ oldppoin= *(link->ppoin);
+
+ (*(link->totlink))++;
+ *(link->ppoin)= MEM_callocN( *(link->totlink)*sizeof(void *), "new link");
+
+ for(a=0; a< (*(link->totlink))-1; a++) {
+ (*(link->ppoin))[a]= oldppoin[a];
+ }
+ (*(link->ppoin))[a]= to->poin;
+
+ if(oldppoin) MEM_freeN(oldppoin);
+ }
+ else {
+ *(link->poin)= to->poin;
+ }
+
+}
+
+static int ui_do_but_LINK(uiBlock *block, uiBut *but)
+{
+ /*
+ * This button only visualizes, the dobutton mode
+ * can add a new link, but then the whole system
+ * should be redrawn/initialized.
+ *
+ */
+ uiBut *bt=0, *bto=NULL;
+ short sval[2], mval[2], mvalo[2], first= 1;
+
+ uiGetMouse(curarea->win, sval);
+ mvalo[0]= sval[0];
+ mvalo[1]= sval[1];
+
+ while (get_mbut() & L_MOUSE) {
+ uiGetMouse(curarea->win, mval);
+
+ if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || first) {
+ /* clear completely, because of drawbuttons */
+ bt= ui_get_valid_link_button(block, but, mval);
+ if(bt) {
+ bt->flag |= UI_ACTIVE;
+ ui_draw_but(bt);
+ }
+ if(bto && bto!=bt) {
+ bto->flag &= ~UI_ACTIVE;
+ ui_draw_but(bto);
+ }
+ bto= bt;
+
+ if (!first) {
+ glutil_draw_front_xor_line(sval[0], sval[1], mvalo[0], mvalo[1]);
+ }
+ glutil_draw_front_xor_line(sval[0], sval[1], mval[0], mval[1]);
+
+ mvalo[0]= mval[0];
+ mvalo[1]= mval[1];
+
+ first= 0;
+ }
+ else BIF_wait_for_statechange();
+ }
+
+ if (!first) {
+ glutil_draw_front_xor_line(sval[0], sval[1], mvalo[0], mvalo[1]);
+ }
+
+ if(bt) {
+ if(but->type==LINK) ui_add_link(but, bt);
+ else ui_add_link(bt, but);
+
+ scrarea_queue_winredraw(curarea);
+ }
+
+ return 0;
+}
+
+/* picker sizes S hsize, F full size, D spacer, B button/pallette height */
+#define SPICK 110.0
+#define FPICK 180.0
+#define DPICK 6.0
+#define BPICK 24.0
+
+#define UI_PALETTE_TOT 16
+/* note; in tot+1 the old color is stored */
+static float palette[UI_PALETTE_TOT+1][3]= {
+{0.93, 0.83, 0.81}, {0.88, 0.89, 0.73}, {0.69, 0.81, 0.57}, {0.51, 0.76, 0.64},
+{0.37, 0.56, 0.61}, {0.33, 0.29, 0.55}, {0.46, 0.21, 0.51}, {0.40, 0.12, 0.18},
+{1.0, 1.0, 1.0}, {0.85, 0.85, 0.85}, {0.7, 0.7, 0.7}, {0.56, 0.56, 0.56},
+{0.42, 0.42, 0.42}, {0.28, 0.28, 0.28}, {0.14, 0.14, 0.14}, {0.0, 0.0, 0.0}
+};
+
+/* for picker, while editing hsv */
+static void ui_set_but_hsv(uiBut *but)
+{
+ float col[3];
+
+ hsv_to_rgb(but->hsv[0], but->hsv[1], but->hsv[2], col, col+1, col+2);
+ ui_set_but_vectorf(but, col);
+}
+
+static void update_picker_hex(uiBlock *block, float *rgb)
+{
+ uiBut *bt;
+ char col[16];
+
+ sprintf(col, "%02X%02X%02X", (unsigned int)(rgb[0]*255.0), (unsigned int)(rgb[1]*255.0), (unsigned int)(rgb[2]*255.0));
+
+ // this updates button strings, is hackish... but button pointers are on stack of caller function
+
+ for(bt= block->buttons.first; bt; bt= bt->next) {
+ if(strcmp(bt->str, "Hex: ")==0) {
+ strcpy(bt->poin, col);
+ ui_check_but(bt);
+ break;
+ }
+ }
+}
+
+static void update_picker_buts_hsv(uiBlock *block, float *hsv, char *poin)
+{
+ uiBut *bt;
+ float r, g, b;
+ float rgb[3];
+
+ // this updates button strings, is hackish... but button pointers are on stack of caller function
+ hsv_to_rgb(hsv[0], hsv[1], hsv[2], &r, &g, &b);
+
+ rgb[0] = r; rgb[1] = g; rgb[2] = b;
+ update_picker_hex(block, rgb);
+
+ for(bt= block->buttons.first; bt; bt= bt->next) {
+ if(bt->type==HSVCUBE) {
+ VECCOPY(bt->hsv, hsv);
+ ui_set_but_hsv(bt);
+ }
+ else if(bt->str[1]==' ') {
+ if(bt->str[0]=='R') {
+ ui_set_but_val(bt, r);
+ }
+ else if(bt->str[0]=='G') {
+ ui_set_but_val(bt, g);
+ }
+ else if(bt->str[0]=='B') {
+ ui_set_but_val(bt, b);
+ }
+ else if(bt->str[0]=='H') {
+ ui_set_but_val(bt, hsv[0]);
+ }
+ else if(bt->str[0]=='S') {
+ ui_set_but_val(bt, hsv[1]);
+ }
+ else if(bt->str[0]=='V') {
+ ui_set_but_val(bt, hsv[2]);
+ }
+ }
+ }
+}
+
+static void update_picker_buts_hex(uiBlock *block, char *hexcol)
+{
+ uiBut *bt;
+ float r=0, g=0, b=0;
+ float h, s, v;
+
+
+ // this updates button strings, is hackish... but button pointers are on stack of caller function
+ hex_to_rgb(hexcol, &r, &g, &b);
+ rgb_to_hsv(r, g, b, &h, &s, &v);
+
+ for(bt= block->buttons.first; bt; bt= bt->next) {
+ if(bt->type==HSVCUBE) {
+ bt->hsv[0] = h;
+ bt->hsv[1] = s;
+ bt->hsv[2] = v;
+ ui_set_but_hsv(bt);
+ }
+ else if(bt->str[1]==' ') {
+ if(bt->str[0]=='R') {
+ ui_set_but_val(bt, r);
+ }
+ else if(bt->str[0]=='G') {
+ ui_set_but_val(bt, g);
+ }
+ else if(bt->str[0]=='B') {
+ ui_set_but_val(bt, b);
+ }
+ else if(bt->str[0]=='H') {
+ ui_set_but_val(bt, h);
+ }
+ else if(bt->str[0]=='S') {
+ ui_set_but_val(bt, s);
+ }
+ else if(bt->str[0]=='V') {
+ ui_set_but_val(bt, v);
+ }
+ }
+ }
+}
+
+
+
+/* bt1 is palette but, col1 is original color */
+/* callback to copy from/to palette */
+static void do_palette_cb(void *bt1, void *col1)
+{
+ uiBut *but1= (uiBut *)bt1;
+ uiBut *but;
+ float *col= (float *)col1;
+ float *fp, hsv[3];
+
+ fp= (float *)but1->poin;
+
+ if( (get_qual() & LR_CTRLKEY) ) {
+ VECCOPY(fp, col);
+ }
+ else {
+ VECCOPY(col, fp);
+ }
+
+ rgb_to_hsv(col[0], col[1], col[2], hsv, hsv+1, hsv+2);
+ update_picker_buts_hsv(but1->block, hsv, but1->poin);
+ update_picker_hex(but1->block, col);
+
+ for (but= but1->block->buttons.first; but; but= but->next) {
+ ui_check_but(but);
+ ui_draw_but(but);
+ }
+ but= but1->block->buttons.first;
+ ui_block_flush_back(but->block);
+}
+
+/* bt1 is num but, hsv1 is pointer to original color in hsv space*/
+/* callback to handle changes in num-buts in picker */
+static void do_palette1_cb(void *bt1, void *hsv1)
+{
+ uiBut *but1= (uiBut *)bt1;
+ uiBut *but;
+ float *hsv= (float *)hsv1;
+ float *fp= NULL;
+
+ if(but1->str[1]==' ') {
+ if(but1->str[0]=='R') fp= (float *)but1->poin;
+ else if(but1->str[0]=='G') fp= ((float *)but1->poin)-1;
+ else if(but1->str[0]=='B') fp= ((float *)but1->poin)-2;
+ }
+ if(fp) {
+ rgb_to_hsv(fp[0], fp[1], fp[2], hsv, hsv+1, hsv+2);
+ }
+ update_picker_buts_hsv(but1->block, hsv, but1->poin);
+
+ for (but= but1->block->buttons.first; but; but= but->next) {
+ ui_check_but(but);
+ ui_draw_but(but);
+ }
+
+ but= but1->block->buttons.first;
+ ui_block_flush_back(but->block);
+
+}
+
+/* bt1 is num but, col1 is pointer to original color */
+/* callback to handle changes in num-buts in picker */
+static void do_palette2_cb(void *bt1, void *col1)
+{
+ uiBut *but1= (uiBut *)bt1;
+ uiBut *but;
+ float *rgb= (float *)col1;
+ float *fp= NULL;
+
+ if(but1->str[1]==' ') {
+ if(but1->str[0]=='H') fp= (float *)but1->poin;
+ else if(but1->str[0]=='S') fp= ((float *)but1->poin)-1;
+ else if(but1->str[0]=='V') fp= ((float *)but1->poin)-2;
+ }
+ if(fp) {
+ hsv_to_rgb(fp[0], fp[1], fp[2], rgb, rgb+1, rgb+2);
+ }
+ update_picker_buts_hsv(but1->block, fp, but1->poin);
+
+ for (but= but1->block->buttons.first; but; but= but->next) {
+ ui_check_but(but);
+ ui_draw_but(but);
+ }
+
+ but= but1->block->buttons.first;
+ ui_block_flush_back(but->block);
+
+}
+
+static void do_palette_hex_cb(void *bt1, void *hexcl)
+{
+ uiBut *but1= (uiBut *)bt1;
+ uiBut *but;
+ char *hexcol= (char *)hexcl;
+
+ update_picker_buts_hex(but1->block, hexcol);
+
+ for (but= but1->block->buttons.first; but; but= but->next) {
+ ui_check_but(but);
+ ui_draw_but(but);
+ }
+
+ but= but1->block->buttons.first;
+ ui_block_flush_back(but->block);
+}
+
+
+/* used for both 3d view and image window */
+static void do_palette_sample_cb(void *bt1, void *col1) /* frontbuf */
+{
+ uiBut *but1= (uiBut *)bt1;
+ uiBut *but;
+ float tempcol[4];
+ int x=0, y=0;
+ short mval[2];
+ float hsv[3];
+ short capturing;
+ int oldcursor;
+ Window *win;
+ unsigned short dev;
+
+ oldcursor=get_cursor();
+ win=winlay_get_active_window();
+
+ while (get_mbut() & L_MOUSE) BIF_wait_for_statechange();
+
+ SetBlenderCursor(BC_EYEDROPPER_CURSOR);
+
+ /* loop and wait for a mouse click */
+ capturing = TRUE;
+ while(capturing) {
+ char ascii;
+ short val;
+
+ dev = extern_qread_ext(&val, &ascii);
+
+ if(dev==INPUTCHANGE) break;
+ if(get_mbut() & R_MOUSE) break;
+ else if(get_mbut() & L_MOUSE) {
+ uiGetMouse(mywinget(), mval);
+ x= mval[0]; y= mval[1];
+
+ capturing = FALSE;
+ break;
+ }
+ else if(dev==ESCKEY) break;
+ }
+ window_set_cursor(win, oldcursor);
+
+ if(capturing) return;
+
+ if(x<0 || y<0) return;
+
+ /* if we've got a glick, use OpenGL to sample the color under the mouse pointer */
+ glReadBuffer(GL_FRONT);
+ glReadPixels(x, y, 1, 1, GL_RGBA, GL_FLOAT, tempcol);
+ glReadBuffer(GL_BACK);
+
+ /* and send that color back to the picker */
+ rgb_to_hsv(tempcol[0], tempcol[1], tempcol[2], hsv, hsv+1, hsv+2);
+ update_picker_buts_hsv(but1->block, hsv, but1->poin);
+ update_picker_hex(but1->block, tempcol);
+
+ for (but= but1->block->buttons.first; but; but= but->next) {
+ ui_check_but(but);
+ ui_draw_but(but);
+ }
+
+ but= but1->block->buttons.first;
+ ui_block_flush_back(but->block);
+}
+
+
+/* color picker, Gimp version. mode: 'f' = floating panel, 'p' = popup */
+/* col = read/write to, hsv/old/hexcol = memory for temporal use */
+void uiBlockPickerButtons(uiBlock *block, float *col, float *hsv, float *old, char *hexcol, char mode, short retval)
+{
+ uiBut *bt;
+ float h, offs;
+ int a;
+
+ VECCOPY(old, col); // old color stored there, for palette_cb to work
+
+ // the cube intersection
+ bt= uiDefButF(block, HSVCUBE, retval, "", 0,DPICK+BPICK,FPICK,FPICK, col, 0.0, 0.0, 2, 0, "");
+ uiButSetFlag(bt, UI_NO_HILITE);
+
+ bt= uiDefButF(block, HSVCUBE, retval, "", 0,0,FPICK,BPICK, col, 0.0, 0.0, 3, 0, "");
+ uiButSetFlag(bt, UI_NO_HILITE);
+
+ // palette
+
+ uiBlockSetEmboss(block, UI_EMBOSSP);
+
+ bt=uiDefButF(block, COL, retval, "", FPICK+DPICK, 0, BPICK,BPICK, old, 0.0, 0.0, -1, 0, "Old color, click to restore");
+ uiButSetFunc(bt, do_palette_cb, bt, col);
+ uiDefButF(block, COL, retval, "", FPICK+DPICK, BPICK+DPICK, BPICK,60-BPICK-DPICK, col, 0.0, 0.0, -1, 0, "Active color");
+
+ h= (DPICK+BPICK+FPICK-64)/(UI_PALETTE_TOT/2.0);
+ uiBlockBeginAlign(block);
+ for(a= -1+UI_PALETTE_TOT/2; a>=0; a--) {
+ bt= uiDefButF(block, COL, retval, "", FPICK+DPICK, 65.0+(float)a*h, BPICK/2, h, palette[a+UI_PALETTE_TOT/2], 0.0, 0.0, -1, 0, "Click to choose, hold CTRL to store in palette");
+ uiButSetFunc(bt, do_palette_cb, bt, col);
+ bt= uiDefButF(block, COL, retval, "", FPICK+DPICK+BPICK/2, 65.0+(float)a*h, BPICK/2, h, palette[a], 0.0, 0.0, -1, 0, "Click to choose, hold CTRL to store in palette");
+ uiButSetFunc(bt, do_palette_cb, bt, col);
+ }
+ uiBlockEndAlign(block);
+
+ uiBlockSetEmboss(block, UI_EMBOSS);
+
+ // buttons
+ rgb_to_hsv(col[0], col[1], col[2], hsv, hsv+1, hsv+2);
+ sprintf(hexcol, "%02X%02X%02X", (unsigned int)(col[0]*255.0), (unsigned int)(col[1]*255.0), (unsigned int)(col[2]*255.0));
+
+ offs= FPICK+2*DPICK+BPICK;
+
+ /* note; made this a TOG now, with NULL pointer. Is because BUT now gets handled with a afterfunc */
+ bt= uiDefIconTextBut(block, TOG, UI_RETURN_OK, ICON_EYEDROPPER, "Sample", offs+55, 170, 85, 20, NULL, 0, 0, 0, 0, "Sample the color underneath the following mouse click (ESC or RMB to cancel)");
+ uiButSetFunc(bt, do_palette_sample_cb, bt, col);
+ uiButSetFlag(bt, UI_TEXT_LEFT);
+
+ bt= uiDefBut(block, TEX, retval, "Hex: ", offs, 140, 140, 20, hexcol, 0, 8, 0, 0, "Hex triplet for color (#RRGGBB)");
+ uiButSetFunc(bt, do_palette_hex_cb, bt, hexcol);
+
+ uiBlockBeginAlign(block);
+ bt= uiDefButF(block, NUMSLI, retval, "R ", offs, 110, 140,20, col, 0.0, 1.0, 10, 3, "");
+ uiButSetFunc(bt, do_palette1_cb, bt, hsv);
+ bt= uiDefButF(block, NUMSLI, retval, "G ", offs, 90, 140,20, col+1, 0.0, 1.0, 10, 3, "");
+ uiButSetFunc(bt, do_palette1_cb, bt, hsv);
+ bt= uiDefButF(block, NUMSLI, retval, "B ", offs, 70, 140,20, col+2, 0.0, 1.0, 10, 3, "");
+ uiButSetFunc(bt, do_palette1_cb, bt, hsv);
+
+ uiBlockBeginAlign(block);
+ bt= uiDefButF(block, NUMSLI, retval, "H ", offs, 40, 140,20, hsv, 0.0, 1.0, 10, 3, "");
+ uiButSetFunc(bt, do_palette2_cb, bt, col);
+ bt= uiDefButF(block, NUMSLI, retval, "S ", offs, 20, 140,20, hsv+1, 0.0, 1.0, 10, 3, "");
+ uiButSetFunc(bt, do_palette2_cb, bt, col);
+ bt= uiDefButF(block, NUMSLI, retval, "V ", offs, 0, 140,20, hsv+2, 0.0, 1.0, 10, 3, "");
+ uiButSetFunc(bt, do_palette2_cb, bt, col);
+ uiBlockEndAlign(block);
+}
+
+static int ui_do_but_COL(uiBut *but)
+{
+ uiBlock *block;
+ uiBut *bt;
+ ListBase listb={NULL, NULL};
+ float hsv[3], old[3], *poin= NULL, colstore[3];
+ static char hexcol[128];
+ short event;
+
+ // signal to prevent calling up color picker
+ if(but->a1 == -1) {
+ uibut_do_func(but);
+ return but->retval;
+ }
+
+ // enable char button too, use temporal colstore for color
+ if(but->pointype!=FLO) {
+ if(but->pointype==CHA) {
+ ui_get_but_vectorf(but, colstore);
+ poin= colstore;
+ }
+ else return but->retval;
+ }
+ else poin= (float *)but->poin;
+
+ block= uiNewBlock(&listb, "colorpicker", UI_EMBOSS, UI_HELV, but->win);
+ block->flag= UI_BLOCK_LOOP|UI_BLOCK_REDRAW;
+ block->themecol= TH_BUT_NUM;
+
+ uiBlockPickerButtons(block, poin, hsv, old, hexcol, 'p', 0);
+
+ /* and lets go */
+ block->direction= UI_TOP;
+ ui_positionblock(block, but);
+ uiBoundsBlock(block, 3);
+
+ /* blocks can come from a normal window, but we go to screenspace */
+ block->win= G.curscreen->mainwin;
+ for(bt= block->buttons.first; bt; bt= bt->next) bt->win= block->win;
+ bwin_getsinglematrix(block->win, block->winmat);
+
+ event= uiDoBlocks(&listb, 0);
+
+ if(but->pointype==CHA) ui_set_but_vectorf(but, colstore);
+
+ uibut_do_func(but);
+ return but->retval;
+
+}
+
+static int ui_do_but_HSVCUBE(uiBut *but)
+{
+ uiBut *bt;
+ float x, y;
+ short mval[2], mvalo[2];
+
+ mvalo[0]= mvalo[1]= -32000;
+
+ /* we work on persistant hsv, to prevent it being converted back and forth all the time */
+
+ while (get_mbut() & L_MOUSE) {
+
+ uiGetMouse(mywinget(), mval);
+
+ if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1]) {
+ mvalo[0]= mval[0];
+ mvalo[1]= mval[1];
+
+ /* relative position within box */
+ x= ((float)mval[0]-but->x1)/(but->x2-but->x1);
+ y= ((float)mval[1]-but->y1)/(but->y2-but->y1);
+ CLAMP(x, 0.0, 1.0);
+ CLAMP(y, 0.0, 1.0);
+
+ if(but->a1==0) {
+ but->hsv[0]= x;
+ but->hsv[2]= y;
+ // hsv_to_rgb(x, s, y, col, col+1, col+2);
+ }
+ else if(but->a1==1) {
+ but->hsv[0]= x;
+ but->hsv[1]= y;
+ // hsv_to_rgb(x, y, v, col, col+1, col+2);
+ }
+ else if(but->a1==2) {
+ but->hsv[2]= x;
+ but->hsv[1]= y;
+ // hsv_to_rgb(h, y, x, col, col+1, col+2);
+ }
+ else {
+ but->hsv[0]= x;
+ // hsv_to_rgb(x, s, v, col, col+1, col+2);
+ }
+
+ ui_set_but_hsv(but); // converts to rgb
+
+ // update button values and strings
+ update_picker_buts_hsv(but->block, but->hsv, but->poin);
+// update_picker_buts_hex(but->block, but->hsv);
+
+ /* we redraw the entire block */
+ for (bt= but->block->buttons.first; bt; bt= bt->next) {
+ if(but->poin == bt->poin) VECCOPY(bt->hsv, but->hsv);
+ ui_draw_but(bt);
+ }
+ ui_block_flush_back(but->block);
+ }
+ else BIF_wait_for_statechange();
+ }
+
+ return but->retval;
+}
+
+#ifdef INTERNATIONAL
+
+static int ui_do_but_CHARTAB(uiBut *but)
+{
+ /* Variables */
+ short mval[2];
+ float sx, sy, ex, ey;
+ float width, height;
+ float butw, buth;
+ int x, y, cs, che;
+
+ /* Check the position */
+ uiGetMouse(mywinget(), mval);
+
+ /* Calculate the size of the button */
+ width = abs(but->x2 - but->x1);
+ height = abs(but->y2 - but->y1);
+
+ butw = floor(width / 12);
+ buth = floor(height / 6);
+
+ /* Initialize variables */
+ sx = but->x1;
+ ex = but->x1 + butw;
+ sy = but->y1 + height - buth;
+ ey = but->y1 + height;
+
+ cs = G.charstart;
+
+ /* And the character is */
+ x = (int) ((mval[0] / butw) - 0.5);
+ y = (int) (6 - ((mval[1] / buth) - 0.5));
+
+ che = cs + (y*12) + x;
+
+ if(che > G.charmax)
+ che = 0;
+
+ if(G.obedit)
+ {
+ do_textedit(0,0,che);
+ }
+
+ return but->retval;
+}
+
+#endif
+
+static int vergcband(const void *a1, const void *a2)
+{
+ const CBData *x1=a1, *x2=a2;
+
+ if( x1->pos > x2->pos ) return 1;
+ else if( x1->pos < x2->pos) return -1;
+ return 0;
+}
+
+
+static void do_colorband_evt(ColorBand *coba)
+{
+ int a;
+
+ if(coba==NULL) return;
+
+ if(coba->tot<2) return;
+
+ for(a=0; a<coba->tot; a++) coba->data[a].cur= a;
+ qsort(coba->data, coba->tot, sizeof(CBData), vergcband);
+ for(a=0; a<coba->tot; a++) {
+ if(coba->data[a].cur==coba->cur) {
+ if(coba->cur!=a) addqueue(curarea->win, REDRAW, 0); /* button cur */
+ coba->cur= a;
+ break;
+ }
+ }
+}
+
+static int ui_do_but_COLORBAND(uiBut *but)
+{
+ ColorBand *coba= (ColorBand *)but->poin;
+ CBData *cbd;
+ float dx, width= but->x2-but->x1;
+ int a;
+ int mindist= 12, xco;
+ short mval[2], mvalo[2];
+
+ uiGetMouse(mywinget(), mvalo);
+
+ if(G.qual & LR_CTRLKEY) {
+ /* insert new key on mouse location */
+ if(coba->tot < MAXCOLORBAND-1) {
+ float pos= ((float)(mvalo[0] - but->x1))/width;
+ float col[4];
+
+ do_colorband(coba, pos, col); /* executes it */
+
+ coba->tot++;
+ coba->cur= coba->tot-1;
+
+ coba->data[coba->cur].r= col[0];
+ coba->data[coba->cur].g= col[1];
+ coba->data[coba->cur].b= col[2];
+ coba->data[coba->cur].a= col[3];
+ coba->data[coba->cur].pos= pos;
+
+ do_colorband_evt(coba);
+ }
+ }
+ else {
+
+ /* first, activate new key when mouse is close */
+ for(a=0, cbd= coba->data; a<coba->tot; a++, cbd++) {
+ xco= but->x1 + (cbd->pos*width);
+ xco= ABS(xco-mvalo[0]);
+ if(a==coba->cur) xco+= 5; // selected one disadvantage
+ if(xco<mindist) {
+ coba->cur= a;
+ mindist= xco;
+ }
+ }
+
+ cbd= coba->data + coba->cur;
+
+ while(get_mbut() & L_MOUSE) {
+ uiGetMouse(mywinget(), mval);
+ if(mval[0]!=mvalo[0]) {
+ dx= mval[0]-mvalo[0];
+ dx/= width;
+ cbd->pos+= dx;
+ CLAMP(cbd->pos, 0.0, 1.0);
+
+ ui_draw_but(but);
+ ui_block_flush_back(but->block);
+
+ do_colorband_evt(coba);
+ cbd= coba->data + coba->cur; /* because qsort */
+
+ mvalo[0]= mval[0];
+ }
+ BIF_wait_for_statechange();
+ }
+ }
+
+ return but->retval;
+}
+
+/* button is presumed square */
+/* if mouse moves outside of sphere, it does negative normal */
+static int ui_do_but_NORMAL(uiBut *but)
+{
+ float dx, dy, rad, radsq, mrad, *fp= (float *)but->poin;
+ int firsttime=1;
+ short mval[2], mvalo[2], mvals[2], mvaldx, mvaldy;
+
+ rad= (but->x2 - but->x1);
+ radsq= rad*rad;
+
+ if(fp[2]>0.0f) {
+ mvaldx= (rad*fp[0]);
+ mvaldy= (rad*fp[1]);
+ }
+ else if(fp[2]> -1.0f) {
+ mrad= rad/sqrt(fp[0]*fp[0] + fp[1]*fp[1]);
+
+ mvaldx= 2.0f*mrad*fp[0] - (rad*fp[0]);
+ mvaldy= 2.0f*mrad*fp[1] - (rad*fp[1]);
+ }
+ else mvaldx= mvaldy= 0;
+
+ uiGetMouse(mywinget(), mvalo);
+ mvals[0]= mvalo[0];
+ mvals[1]= mvalo[1];
+
+ while(get_mbut() & L_MOUSE) {
+
+ uiGetMouse(mywinget(), mval);
+
+ if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || firsttime) {
+ firsttime= 0;
+
+ dx= (float)(mval[0]+mvaldx-mvals[0]);
+ dy= (float)(mval[1]+mvaldy-mvals[1]);
+
+ mrad= dx*dx+dy*dy;
+ if(mrad < radsq) { /* inner circle */
+ fp[0]= dx;
+ fp[1]= dy;
+ fp[2]= sqrt( radsq-dx*dx-dy*dy );
+ }
+ else { /* outer circle */
+
+ mrad= rad/sqrt(mrad); // veclen
+
+ dx*= (2.0f*mrad - 1.0f);
+ dy*= (2.0f*mrad - 1.0f);
+
+ mrad= dx*dx+dy*dy;
+ if(mrad < radsq) {
+ fp[0]= dx;
+ fp[1]= dy;
+ fp[2]= -sqrt( radsq-dx*dx-dy*dy );
+ }
+ }
+ Normalize(fp);
+
+ ui_draw_but(but);
+ ui_block_flush_back(but->block);
+
+ mvalo[0]= mval[0];
+ mvalo[1]= mval[1];
+ }
+ BIF_wait_for_statechange();
+ }
+
+ return but->retval;
+}
+
+static int ui_do_but_CURVE(uiBut *but)
+{
+ CurveMapping *cumap= (CurveMapping *)but->poin;
+ CurveMap *cuma= cumap->cm+cumap->cur;
+ CurveMapPoint *cmp= cuma->curve;
+ float fx, fy, zoomx, zoomy, offsx, offsy;
+ float dist, mindist= 200.0f; // 14 pixels radius
+ int a, sel= -1, retval= but->retval;
+ short mval[2], mvalo[2];
+
+ uiGetMouse(mywinget(), mval);
+
+ /* calculate offset and zoom */
+ zoomx= (but->x2-but->x1)/(cumap->curr.xmax-cumap->curr.xmin);
+ zoomy= (but->y2-but->y1)/(cumap->curr.ymax-cumap->curr.ymin);
+ offsx= cumap->curr.xmin;
+ offsy= cumap->curr.ymin;
+
+ if(G.qual & LR_CTRLKEY) {
+
+ fx= ((float)mval[0] - but->x1)/zoomx + offsx;
+ fy= ((float)mval[1] - but->y1)/zoomy + offsy;
+
+ curvemap_insert(cuma, fx, fy);
+ curvemapping_changed(cumap, 0);
+
+ ui_draw_but(but);
+ ui_block_flush_back(but->block);
+ }
+
+
+ /* check for selecting of a point */
+ cmp= cuma->curve; /* ctrl adds point, new malloc */
+ for(a=0; a<cuma->totpoint; a++) {
+ fx= but->x1 + zoomx*(cmp[a].x-offsx);
+ fy= but->y1 + zoomy*(cmp[a].y-offsy);
+ dist= (fx-mval[0])*(fx-mval[0]) + (fy-mval[1])*(fy-mval[1]);
+ if(dist < mindist) {
+ sel= a;
+ mindist= dist;
+ }
+ }
+
+ if (sel == -1) {
+ /* if the click didn't select anything, check if it's clicked on the
+ * curve itself, and if so, add a point */
+ fx= ((float)mval[0] - but->x1)/zoomx + offsx;
+ fy= ((float)mval[1] - but->y1)/zoomy + offsy;
+
+ cmp= cuma->table;
+
+ /* loop through the curve segment table and find what's near the mouse.
+ * 0.05 is kinda arbitrary, but seems to be what works nicely. */
+ for(a=0; a<=CM_TABLE; a++) {
+ if ( ( fabs(fx - cmp[a].x) < (0.05) ) && ( fabs(fy - cmp[a].y) < (0.05) ) ) {
+
+ curvemap_insert(cuma, fx, fy);
+ curvemapping_changed(cumap, 0);
+
+ ui_draw_but(but);
+ ui_block_flush_back(but->block);
+
+ /* reset cmp back to the curve points again, rather than drawing segments */
+ cmp= cuma->curve;
+
+ /* find newly added point and make it 'sel' */
+ for(a=0; a<cuma->totpoint; a++) {
+ if (cmp[a].x == fx) sel = a;
+ }
+
+ break;
+ }
+ }
+ }
+
+ /* ok, we move a point */
+ if(sel!= -1) {
+ int moved_point;
+ int moved_mouse= 0;
+
+ /* deselect all if this one is deselect. except if we hold shift */
+ if((G.qual & LR_SHIFTKEY)==0 && (cmp[sel].flag & SELECT)==0)
+ for(a=0; a<cuma->totpoint; a++)
+ cmp[a].flag &= ~SELECT;
+ cmp[sel].flag |= SELECT;
+
+ /* draw to show select updates */
+ ui_draw_but(but);
+ ui_block_flush_back(but->block);
+
+ /* while move mouse, do move points around */
+ while(get_mbut() & L_MOUSE) {
+
+ uiGetMouse(mywinget(), mvalo);
+
+ if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1]) {
+ moved_mouse= 1; /* for selection */
+ moved_point= 0; /* for ctrl grid, can't use orig coords because of sorting */
+
+ fx= (mvalo[0]-mval[0])/zoomx;
+ fy= (mvalo[1]-mval[1])/zoomy;
+ for(a=0; a<cuma->totpoint; a++) {
+ if(cmp[a].flag & SELECT) {
+ float origx= cmp[a].x, origy= cmp[a].y;
+ cmp[a].x+= fx;
+ cmp[a].y+= fy;
+ if( (get_qual() & LR_SHIFTKEY) ) {
+ cmp[a].x= 0.125f*floor(0.5f + 8.0f*cmp[a].x);
+ cmp[a].y= 0.125f*floor(0.5f + 8.0f*cmp[a].y);
+ }
+ if(cmp[a].x!=origx || cmp[a].y!=origy)
+ moved_point= 1;
+ }
+ }
+ curvemapping_changed(cumap, 0); /* no remove doubles */
+
+ ui_draw_but(but);
+ ui_block_flush_back(but->block);
+
+ if(moved_point) {
+ mval[0]= mvalo[0];
+ mval[1]= mvalo[1];
+ }
+ }
+ BIF_wait_for_statechange();
+ }
+
+ if(moved_mouse==0) {
+ /* deselect all, select one */
+ if((G.qual & LR_SHIFTKEY)==0) {
+ for(a=0; a<cuma->totpoint; a++)
+ cmp[a].flag &= ~SELECT;
+ cmp[sel].flag |= SELECT;
+ }
+ }
+ else
+ curvemapping_changed(cumap, 1); /* remove doubles */
+
+ ui_draw_but(but);
+ ui_block_flush_back(but->block);
+ }
+ else {
+ /* we move the view */
+ retval= B_NOP;
+
+ while(get_mbut() & L_MOUSE) {
+
+ uiGetMouse(mywinget(), mvalo);
+
+ if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1]) {
+ fx= (mvalo[0]-mval[0])/zoomx;
+ fy= (mvalo[1]-mval[1])/zoomy;
+
+ /* clamp for clip */
+ if(cumap->flag & CUMA_DO_CLIP) {
+ if(cumap->curr.xmin-fx < cumap->clipr.xmin)
+ fx= cumap->curr.xmin - cumap->clipr.xmin;
+ else if(cumap->curr.xmax-fx > cumap->clipr.xmax)
+ fx= cumap->curr.xmax - cumap->clipr.xmax;
+ if(cumap->curr.ymin-fy < cumap->clipr.ymin)
+ fy= cumap->curr.ymin - cumap->clipr.ymin;
+ else if(cumap->curr.ymax-fy > cumap->clipr.ymax)
+ fy= cumap->curr.ymax - cumap->clipr.ymax;
+ }
+ cumap->curr.xmin-=fx;
+ cumap->curr.ymin-=fy;
+ cumap->curr.xmax-=fx;
+ cumap->curr.ymax-=fy;
+
+ ui_draw_but(but);
+ ui_block_flush_back(but->block);
+
+ mval[0]= mvalo[0];
+ mval[1]= mvalo[1];
+ }
+ }
+ BIF_wait_for_statechange();
+ }
+
+ return retval;
+}
+
+/* ************************************************ */
+
+void uiSetButLock(int val, char *lockstr)
+{
+ UIlock |= val;
+ if (val) UIlockstr= lockstr;
+}
+
+void uiClearButLock()
+{
+ UIlock= 0;
+ UIlockstr= NULL;
+}
+
+/* *************************************************************** */
+
+static void setup_file(uiBlock *block)
+{
+ uiBut *but;
+ FILE *fp;
+
+ fp= fopen("butsetup","w");
+ if(fp==NULL);
+ else {
+ but= block->buttons.first;
+ while(but) {
+ ui_check_but(but);
+ fprintf(fp,"%d,%d,%d,%d %s %s\n", (int)but->x1, (int)but->y1, (int)( but->x2-but->x1), (int)(but->y2-but->y1), but->str, but->tip);
+ but= but->next;
+ }
+ fclose(fp);
+ }
+}
+
+
+static void edit_but(uiBlock *block, uiBut *but, uiEvent *uevent)
+{
+ short dx, dy, mval[2], mvalo[2], didit=0;
+
+ getmouseco_sc(mvalo);
+ while(TRUE) {
+ if( !(get_mbut() & L_MOUSE) ) break;
+
+ getmouseco_sc(mval);
+ dx= (mval[0]-mvalo[0]);
+ dy= (mval[1]-mvalo[1]);
+
+ if(dx!=0 || dy!=0) {
+ mvalo[0]= mval[0];
+ mvalo[1]= mval[1];
+
+ cpack(0xc0c0c0);
+ glRectf(but->x1-2, but->y1-2, but->x2+2, but->y2+2);
+
+ if((uevent->qual & LR_SHIFTKEY)==0) {
+ but->x1 += dx;
+ but->y1 += dy;
+ }
+ but->x2 += dx;
+ but->y2 += dy;
+
+ ui_draw_but(but);
+ ui_block_flush_back(but->block);
+ didit= 1;
+
+ }
+ /* idle for this poor code */
+ else PIL_sleep_ms(30);
+ }
+ if(didit) setup_file(block);
+}
+
+
+/* is called when LEFTMOUSE is pressed or released
+ * return: butval or zero
+ */
+static int ui_do_button(uiBlock *block, uiBut *but, uiEvent *uevent)
+{
+ int retval= 0;
+
+ if(but->lock) {
+ if (but->lockstr) {
+ error("%s", but->lockstr);
+ return 0;
+ }
+ }
+ else {
+ if( but->pointype ) { /* there's a pointer needed */
+ if(but->poin==0 ) {
+ printf("DoButton pointer error: %s\n",but->str);
+ return 0;
+ }
+ }
+ }
+
+ if(G.rt==1 && (uevent->qual & LR_CTRLKEY)) {
+ edit_but(block, but, uevent);
+ return 0;
+ }
+
+ block->flag |= UI_BLOCK_BUSY;
+
+ switch(but->type) {
+ case BUT:
+ if(uevent->val) retval= ui_do_but_BUT(but);
+ break;
+
+ case KEYEVT:
+ if(uevent->val) retval= ui_do_but_KEYEVT(but);
+ break;
+
+ case TOG:
+ case TOGR:
+ case ICONTOG:
+ case ICONTOGN:
+ case TOGN:
+ case BUT_TOGDUAL:
+ if(uevent->val) {
+ retval= ui_do_but_TOG(block, but, uevent->qual);
+ }
+ break;
+
+ case ROW:
+ if(uevent->val) retval= ui_do_but_ROW(block, but);
+ break;
+
+ case SCROLL:
+ /* DrawBut(b, 1); */
+ /* do_scrollbut(b); */
+ /* DrawBut(b,0); */
+ break;
+
+ case NUM:
+ if(uevent->val) retval= ui_do_but_NUM(but);
+ break;
+
+ case SLI:
+ case NUMSLI:
+ case HSVSLI:
+ if(uevent->val) retval= ui_do_but_NUMSLI(but);
+ break;
+
+ case ROUNDBOX:
+ case LABEL:
+ if(uevent->val) retval= ui_do_but_LABEL(but);
+ break;
+
+ case TOG3:
+ if(uevent->val) retval= ui_do_but_TOG3(but);
+ break;
+
+ case TEX:
+ if(uevent->val) retval= ui_do_but_TEX(but);
+ break;
+
+ case MENU:
+ if(uevent->val) retval= ui_do_but_MENU(but);
+ break;
+
+ case ICONROW:
+ if(uevent->val) retval= ui_do_but_ICONROW(but);
+ break;
+
+ case ICONTEXTROW:
+ if(uevent->val) retval= ui_do_but_ICONTEXTROW(but);
+ break;
+
+ case IDPOIN:
+ if(uevent->val) retval= ui_do_but_IDPOIN(but);
+ break;
+
+ case BLOCK:
+ case PULLDOWN:
+ if(uevent->val) {
+ ui_do_but_BLOCK(but, uevent->event);
+ retval= 0;
+ if(block->auto_open==0) block->auto_open= 1;
+ }
+ break;
+
+ case BUTM:
+ retval= ui_do_but_BUTM(but);
+ break;
+
+ case LINK:
+ case INLINK:
+ retval= ui_do_but_LINK(block, but);
+ break;
+
+ case COL:
+ if(uevent->val) retval= ui_do_but_COL(but);
+ break;
+
+ case HSVCUBE:
+ retval= ui_do_but_HSVCUBE(but);
+ break;
+ case BUT_COLORBAND:
+ retval= ui_do_but_COLORBAND(but);
+ break;
+ case BUT_NORMAL:
+ retval= ui_do_but_NORMAL(but);
+ break;
+ case BUT_CURVE:
+ retval= ui_do_but_CURVE(but);
+ break;
+
+#ifdef INTERNATIONAL
+ case CHARTAB:
+ retval= ui_do_but_CHARTAB(but);
+ break;
+#endif
+ }
+
+ block->flag &= ~UI_BLOCK_BUSY;
+
+ return retval;
+}
+
+static void ui_delete_active_linkline(uiBlock *block)
+{
+ uiBut *but;
+ uiLink *link;
+ uiLinkLine *line, *nline;
+ int a, b;
+
+ but= block->buttons.first;
+ while(but) {
+ if(but->type==LINK && but->link) {
+ line= but->link->lines.first;
+ while(line) {
+
+ nline= line->next;
+
+ if(line->flag & UI_SELECT) {
+ BLI_remlink(&but->link->lines, line);
+
+ link= line->from->link;
+
+ /* are there more pointers allowed? */
+ if(link->ppoin) {
+
+ if(*(link->totlink)==1) {
+ *(link->totlink)= 0;
+ MEM_freeN(*(link->ppoin));
+ *(link->ppoin)= NULL;
+ }
+ else {
+ b= 0;
+ for(a=0; a< (*(link->totlink)); a++) {
+
+ if( (*(link->ppoin))[a] != line->to->poin ) {
+ (*(link->ppoin))[b]= (*(link->ppoin))[a];
+ b++;
+ }
+ }
+ (*(link->totlink))--;
+ }
+ }
+ else {
+ *(link->poin)= NULL;
+ }
+
+ MEM_freeN(line);
+ }
+ line= nline;
+ }
+ }
+ but= but->next;
+ }
+
+ /* temporal! these buttons can be everywhere... */
+ allqueue(REDRAWBUTSLOGIC, 0);
+}
+
+static void ui_do_active_linklines(uiBlock *block, short *mval)
+{
+ uiBut *but;
+ uiLinkLine *line, *act= NULL;
+ float mindist= 12.0, fac, v1[2], v2[2], v3[3];
+ int foundone= 0;
+
+ if(mval) {
+ v1[0]= mval[0];
+ v1[1]= mval[1];
+
+ /* find a line close to the mouse */
+ but= block->buttons.first;
+ while(but) {
+ if(but->type==LINK && but->link) {
+ foundone= 1;
+ line= but->link->lines.first;
+ while(line) {
+ v2[0]= line->from->x2;
+ v2[1]= (line->from->y1+line->from->y2)/2.0;
+ v3[0]= line->to->x1;
+ v3[1]= (line->to->y1+line->to->y2)/2.0;
+
+ fac= PdistVL2Dfl(v1, v2, v3);
+ if(fac < mindist) {
+ mindist= fac;
+ act= line;
+ }
+ line= line->next;
+ }
+ }
+ but= but->next;
+ }
+ }
+
+ /* check for a 'found one' to prevent going to 'frontbuffer' mode.
+ this slows done gfx quite some, and at OSX the 'finish' forces a swapbuffer */
+ if(foundone) {
+ glDrawBuffer(GL_FRONT);
+
+ /* draw */
+ but= block->buttons.first;
+ while(but) {
+ if(but->type==LINK && but->link) {
+ line= but->link->lines.first;
+ while(line) {
+ if(line==act) {
+ if((line->flag & UI_SELECT)==0) {
+ line->flag |= UI_SELECT;
+ ui_draw_linkline(but, line);
+ }
+ }
+ else if(line->flag & UI_SELECT) {
+ line->flag &= ~UI_SELECT;
+ ui_draw_linkline(but, line);
+ }
+ line= line->next;
+ }
+ }
+ but= but->next;
+ }
+ bglFlush();
+ glDrawBuffer(GL_BACK);
+ }
+}
+
+
+/* only to be used to prevent an 'outside' event when using nested pulldowns */
+/* only one checks:
+ - while mouse moves in triangular area defined old mouse position and left/right side of new menu
+ - only for 1 second
+
+ return 0: check outside
+*/
+static int ui_mouse_motion_towards_block(uiBlock *block, uiEvent *uevent)
+{
+ short mvalo[2], dx, dy, domx, domy;
+ int counter=0;
+
+ if((block->direction & UI_TOP) || (block->direction & UI_DOWN)) return 0;
+ if(uevent->event!= MOUSEX && uevent->event!= MOUSEY) return 0;
+
+ /* calculate dominant direction */
+ domx= ( -uevent->mval[0] + (block->maxx+block->minx)/2 );
+ domy= ( -uevent->mval[1] + (block->maxy+block->miny)/2 );
+ /* we need some accuracy */
+ if( abs(domx)<4 ) return 0;
+
+ uiGetMouse(mywinget(), mvalo);
+
+ while(TRUE) {
+ uiGetMouse(mywinget(), uevent->mval);
+
+ /* check inside, if so return */
+ if( block->minx <= uevent->mval[0] && block->maxx >= uevent->mval[0] ) {
+ if( block->miny <= uevent->mval[1] && block->maxy >= uevent->mval[1] ) {
+ return 1;
+ }
+ }
+
+ /* check direction */
+ dx= uevent->mval[0] - mvalo[0];
+ dy= uevent->mval[1] - mvalo[1];
+
+ if( abs(dx)+abs(dy)>4 ) { // threshold
+ /* menu to right */
+ if(domx>0) {
+ int fac= (uevent->mval[0] - mvalo[0])*(mvalo[1] - (short)(block->maxy +20)) + (uevent->mval[1] - mvalo[1])*(-mvalo[0] + (short)block->minx);
+ if( (fac>0)) {
+ // printf("Left outside 1, Fac %d\n", fac);
+ return 0;
+ }
+
+ fac= (uevent->mval[0] - mvalo[0])*(mvalo[1] - (short)(block->miny-20)) + (uevent->mval[1] - mvalo[1])*(-mvalo[0] + (short)block->minx);
+ if( (fac<0)) {
+ //printf("Left outside 2, Fac %d\n", fac);
+ return 0;
+ }
+ }
+ else {
+ int fac= (uevent->mval[0] - mvalo[0])*(mvalo[1] - (short)(block->maxy+20)) + (uevent->mval[1] - mvalo[1])*(-mvalo[0] + (short)block->maxx);
+ if( (fac<0)) {
+ // printf("Left outside 1, Fac %d\n", fac);
+ return 0;
+ }
+
+ fac= (uevent->mval[0] - mvalo[0])*(mvalo[1] - (short)(block->miny-20)) + (uevent->mval[1] - mvalo[1])*(-mvalo[0] + (short)block->maxx);
+ if( (fac>0)) {
+ // printf("Left outside 2, Fac %d\n", fac);
+ return 0;
+ }
+ }
+ }
+
+ /* idle for this poor code */
+ PIL_sleep_ms(10);
+ counter++;
+ if(counter > 100) {
+ //printf("left because of timer (1 sec)\n");
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+
+static void ui_set_ftf_font(float aspect)
+{
+
+#ifdef INTERNATIONAL
+ if(aspect<1.15) {
+ FTF_SetFontSize('l');
+ }
+ else if(aspect<1.59) {
+ FTF_SetFontSize('m');
+ }
+ else {
+ FTF_SetFontSize('s');
+ }
+#endif
+}
+
+static void ui_but_next_edittext(uiBlock *block)
+{
+ uiBut *but, *actbut;
+
+ for(actbut= block->buttons.first; actbut; actbut= actbut->next) {
+ /* label and roundbox can overlap real buttons (backdrops...) */
+ if(actbut->type!=LABEL && actbut->type!=ROUNDBOX)
+ if(actbut->flag & UI_ACTIVE) break;
+ }
+ if(actbut) {
+ /* ensure all buttons are cleared, label/roundbox overlap */
+ for(but= block->buttons.first; but; but= but->next)
+ but->flag &= ~(UI_ACTIVE|UI_SELECT);
+
+ for(but= actbut->next; but; but= but->next) {
+ if(ELEM4(but->type, TEX, NUM, NUMSLI, HSVSLI)) {
+ but->flag |= UI_ACTIVE;
+ return;
+ }
+ }
+ for(but= block->buttons.first; but!=actbut; but= but->next) {
+ if(ELEM4(but->type, TEX, NUM, NUMSLI, HSVSLI)) {
+ but->flag |= UI_ACTIVE;
+ return;
+ }
+ }
+ }
+}
+
+static void ui_but_prev_edittext(uiBlock *block)
+{
+ uiBut *but, *actbut;
+
+ for(actbut= block->buttons.first; actbut; actbut= actbut->next) {
+ /* label and roundbox can overlap real buttons (backdrops...) */
+ if(actbut->type!=LABEL && actbut->type!=ROUNDBOX)
+ if(actbut->flag & UI_ACTIVE) break;
+ }
+ if(actbut) {
+ /* ensure all buttons are cleared, label/roundbox overlap */
+ for(but= block->buttons.first; but; but= but->next)
+ but->flag &= ~(UI_ACTIVE|UI_SELECT);
+
+ for(but= actbut->prev; but; but= but->prev) {
+ if(ELEM4(but->type, TEX, NUM, NUMSLI, HSVSLI)) {
+ but->flag |= UI_ACTIVE;
+ return;
+ }
+ }
+ for(but= block->buttons.last; but!=actbut; but= but->prev) {
+ if(ELEM4(but->type, TEX, NUM, NUMSLI, HSVSLI)) {
+ but->flag |= UI_ACTIVE;
+ return;
+ }
+ }
+ }
+}
+
+/* ******************************************************* */
+
+/* nasty but safe way to store screendump rect */
+static int scr_x=0, scr_y=0, scr_sizex=0, scr_sizey=0;
+
+static void ui_set_screendump_bbox(uiBlock *block)
+{
+ if(block) {
+ scr_x= block->minx;
+ scr_y= block->miny;
+ scr_sizex= block->maxx - block->minx;
+ scr_sizey= block->maxy - block->miny;
+ }
+ else {
+ scr_sizex= scr_sizey= 0;
+ }
+}
+
+/* used for making screenshots for menus, called in screendump.c */
+int uiIsMenu(int *x, int *y, int *sizex, int *sizey)
+{
+ if(scr_sizex!=0 && scr_sizey!=0) {
+ *x= scr_x;
+ *y= scr_y;
+ *sizex= scr_sizex;
+ *sizey= scr_sizey;
+ return 1;
+ }
+
+ return 0;
+}
+/* ******************************************************* */
+
+/* return:
+ * UI_NOTHING pass event to other ui's
+ * UI_CONT don't pass event to other ui's
+ * UI_RETURN something happened, return, swallow event
+ */
+static int ui_do_block(uiBlock *block, uiEvent *uevent)
+{
+ uiBut *but, *bt;
+ int butevent, event, retval=UI_NOTHING, count, act=0;
+ int inside= 0, active=0;
+
+ if(block->win != mywinget()) return UI_NOTHING;
+
+ /* filter some unwanted events */
+ /* btw: we allow event==0 for first time in menus, draws the hilited item */
+ if(uevent==0 || uevent->event==LEFTSHIFTKEY || uevent->event==RIGHTSHIFTKEY) return UI_NOTHING;
+ if(uevent->event==UI_BUT_EVENT) return UI_NOTHING;
+
+ if(block->flag & UI_BLOCK_ENTER_OK) {
+ if((uevent->event==RETKEY || uevent->event==PADENTER) && uevent->val) {
+ // printf("qual: %d %d %d\n", uevent->qual, get_qual(), G.qual);
+ if ((G.qual & LR_SHIFTKEY) == 0) {
+ return UI_RETURN_OK;
+ }
+ }
+ }
+
+ ui_set_ftf_font(block->aspect); // sets just a pointer in ftf lib... the button dont have ftf handles
+ ui_set_screendump_bbox(block);
+
+ // added this for panels in windows with buttons...
+ // maybe speed optimize should require test
+ if((block->flag & UI_BLOCK_LOOP)==0) {
+ glMatrixMode(GL_PROJECTION);
+ bwin_load_winmatrix(block->win, block->winmat);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ }
+
+ Mat4CpyMat4(UIwinmat, block->winmat);
+ uiPanelPush(block); // push matrix; no return without pop!
+
+ uiGetMouse(mywinget(), uevent->mval); /* transformed mouseco */
+
+ /* check boundbox and panel events */
+ if( block->minx <= uevent->mval[0] && block->maxx >= uevent->mval[0] ) {
+
+ // inside block
+ if( block->miny <= uevent->mval[1] && block->maxy >= uevent->mval[1] ) inside= INSIDE_BLOCK;
+
+ if(block->panel && block->panel->paneltab==NULL) {
+
+ /* clicked at panel header? */
+ if( block->panel->flag & PNL_CLOSEDX) {
+ if(block->minx <= uevent->mval[0] && block->minx+PNL_HEADER >= uevent->mval[0])
+ inside= INSIDE_PANEL_HEADER;
+ }
+ else if( (block->maxy <= uevent->mval[1]) && (block->maxy+PNL_HEADER >= uevent->mval[1]) ) {
+ inside= INSIDE_PANEL_HEADER;
+ }
+ else if( block->panel->control & UI_PNL_SCALE) {
+ if( (block->maxx-PNL_HEADER <= uevent->mval[0]))
+ if( (block->miny+PNL_HEADER >= uevent->mval[1]) && inside )
+ inside= INSIDE_PANEL_SCALE;
+ }
+
+ if (inside) { // this stuff should move to do_panel
+
+ if(uevent->event==LEFTMOUSE) {
+ if(ELEM(inside, INSIDE_PANEL_HEADER, INSIDE_PANEL_SCALE)) {
+ uiPanelPop(block); // pop matrix; no return without pop!
+ if(inside==INSIDE_PANEL_HEADER)
+ ui_do_panel(block, uevent);
+ else
+ ui_scale_panel(block);
+ return UI_EXIT_LOOP; // exit loops because of moving panels
+ }
+ }
+ else if(uevent->event==ESCKEY) {
+ if(block->handler) {
+ rem_blockhandler(curarea, block->handler);
+ addqueue(curarea->win, REDRAW, 1);
+ }
+ }
+ else if(uevent->event==PADPLUSKEY || uevent->event==PADMINUS) {
+ int zoom=0;
+
+ /* if panel is closed, only zoom if mouse is over the header */
+ if ((block->panel->flag & PNL_CLOSEDX) || (block->panel->flag & PNL_CLOSEDY)) {
+ if (inside == INSIDE_PANEL_HEADER)
+ zoom=1;
+ } else if (inside >= INSIDE_BLOCK)
+ zoom=1;
+
+ if(zoom) {
+ SpaceLink *sl= curarea->spacedata.first;
+ if(curarea->spacetype!=SPACE_BUTS) {
+ if(!(block->panel->control & UI_PNL_SCALE)) {
+ if(uevent->event==PADPLUSKEY) sl->blockscale+= 0.1;
+ else sl->blockscale-= 0.1;
+ CLAMP(sl->blockscale, 0.6, 1.0);
+ addqueue(block->winq, REDRAW, 1);
+ retval= UI_RETURN_OK;
+ }
+ }
+ }
+
+ }
+ }
+ }
+ }
+
+ /* inside menus, scrollwheel acts as arrow */
+ if(block->flag & UI_BLOCK_LOOP) {
+ if(uevent->event==WHEELUPMOUSE) uevent->event= UPARROWKEY;
+ if(uevent->event==WHEELDOWNMOUSE) uevent->event= DOWNARROWKEY;
+ }
+
+ switch(uevent->event) {
+ case LEFTARROWKEY: /* closing sublevels of pulldowns */
+ if(uevent->val && (block->flag & UI_BLOCK_LOOP) && block->parent) {
+ return UI_RETURN_OUT;
+ }
+ break;
+
+ case RIGHTARROWKEY: /* opening sublevels of pulldowns */
+ if(uevent->val && (block->flag & UI_BLOCK_LOOP)) {
+ for(but= block->buttons.first; but; but= but->next) {
+ if(but->flag & UI_ACTIVE) {
+ if(but->type==BLOCK) {
+ but->flag &= ~UI_MOUSE_OVER;
+ uevent->event= BUT_ACTIVATE;
+ }
+ break;
+ }
+ }
+ if(but==NULL) { /* no item active, we make first active */
+ if(block->direction & UI_TOP) but= ui_but_last(block);
+ else but= ui_but_first(block);
+ if(but) {
+ but->flag |= UI_ACTIVE;
+ ui_draw_but(but);
+ }
+ }
+ }
+ break;
+
+ case PAD8: case PAD2:
+ case UPARROWKEY:
+ case DOWNARROWKEY:
+ if(inside || (block->flag & UI_BLOCK_LOOP)) {
+ /* arrowkeys: only handle for block_loop blocks */
+ event= 0;
+ if(block->flag & UI_BLOCK_LOOP) {
+ event= uevent->event;
+ if(event==PAD8) event= UPARROWKEY;
+ if(event==PAD2) event= DOWNARROWKEY;
+ }
+ else {
+ if(uevent->event==PAD8) event= UPARROWKEY;
+ if(uevent->event==PAD2) event= DOWNARROWKEY;
+ }
+ if(event && uevent->val) {
+
+ for(but= block->buttons.first; but; but= but->next) {
+ but->flag &= ~UI_MOUSE_OVER;
+
+ if(but->flag & UI_ACTIVE) {
+ but->flag &= ~UI_ACTIVE;
+ ui_draw_but(but);
+
+ if(event==UPARROWKEY) {
+ if(block->direction & UI_TOP) bt= ui_but_next(but);
+ else bt= ui_but_prev(but);
+ }
+ else {
+ if(block->direction & UI_TOP) bt= ui_but_prev(but);
+ else bt= ui_but_next(but);
+ }
+
+ if(bt) {
+ bt->flag |= UI_ACTIVE;
+ ui_draw_but(bt);
+ break;
+ }
+ }
+ }
+
+ /* nothing done */
+ if(but==NULL) {
+
+ if(event==UPARROWKEY) {
+ if(block->direction & UI_TOP) but= ui_but_first(block);
+ else but= ui_but_last(block);
+ }
+ else {
+ if(block->direction & UI_TOP) but= ui_but_last(block);
+ else but= ui_but_first(block);
+ }
+ if(but) {
+ but->flag |= UI_ACTIVE;
+ ui_draw_but(but);
+ }
+ }
+ retval= UI_CONT;
+ }
+ }
+ break;
+
+ case ONEKEY: act= 1;
+ case TWOKEY: if(act==0) act= 2;
+ case THREEKEY: if(act==0) act= 3;
+ case FOURKEY: if(act==0) act= 4;
+ case FIVEKEY: if(act==0) act= 5;
+ case SIXKEY: if(act==0) act= 6;
+ case SEVENKEY: if(act==0) act= 7;
+ case EIGHTKEY: if(act==0) act= 8;
+ case NINEKEY: if(act==0) act= 9;
+ case ZEROKEY: if(act==0) act= 10;
+
+ if( block->flag & UI_BLOCK_NUMSELECT ) {
+
+ if(get_qual() & LR_ALTKEY) act+= 10;
+
+ count= 0;
+ for(but= block->buttons.first; but; but= but->next) {
+ int doit= 0;
+
+ if(but->type!=LABEL && but->type!=SEPR) count++;
+ /* exception for menus like layer buts, with button aligning they're not drawn in order */
+ if(but->type==TOGR) {
+ if(but->bitnr==act-1) doit= 1;
+ } else if(count==act) doit=1;
+
+ if(doit) {
+ but->flag |= UI_ACTIVE;
+ if(uevent->val==1) ui_draw_but(but);
+ else if(block->flag & UI_BLOCK_RET_1) { /* to make UI_BLOCK_RET_1 working */
+ uevent->event= RETKEY;
+ uevent->val= 1;
+ //addqueue(block->winq, RIGHTARROWKEY, 1); (why! (ton))
+ }
+ else {
+ uevent->event= LEFTMOUSE; /* to make sure the button is handled further on */
+ uevent->val= 1;
+ }
+ }
+ else if(but->flag & UI_ACTIVE) {
+ but->flag &= ~UI_ACTIVE;
+ ui_draw_but(but);
+ }
+ }
+ }
+ break;
+ case BUT_NEXT:
+ ui_but_next_edittext(block);
+ break;
+ case BUT_PREV:
+ ui_but_prev_edittext(block);
+ break;
+ case BUT_ACTIVATE:
+ for(but= block->buttons.first; but; but= but->next) {
+ if(but->retval==uevent->val) but->flag |= UI_ACTIVE;
+ }
+ break;
+ case VKEY:
+ case CKEY:
+ if(uevent->val && (uevent->qual & (LR_CTRLKEY|LR_COMMANDKEY))) {
+ for(but= block->buttons.first; but; but= but->next) {
+ if(but->type!=LABEL && but->type!=ROUNDBOX) {
+ if(but->flag & UI_ACTIVE) {
+ int doit=0;
+
+ if(uevent->event==VKEY) doit= ui_but_copy_paste(but, 'v');
+ else ui_but_copy_paste(but, 'c');
+
+ if(doit) {
+ ui_draw_but(but);
+
+ if(but->retval) addqueue(block->winq, UI_BUT_EVENT, (short)but->retval);
+ if((but->type==NUMSLI && but->a1) || (but->type==COL)) addqueue(block->winq, REDRAW, 1); // col button update
+
+ BIF_undo_push(but->str);
+ }
+ // but we do return, to prevent passing event through other queues */
+ if( (block->flag & UI_BLOCK_LOOP) && but->type==BLOCK);
+ else if(but->retval) retval= UI_RETURN_OK;
+ break;
+ }
+ }
+ }
+ }
+ break;
+
+
+#ifdef INTERNATIONAL
+ //HACK to let the chartab button react to the mousewheel and PGUP/PGDN keys
+ case WHEELUPMOUSE:
+ case PAGEUPKEY:
+ for(but= block->buttons.first; but; but= but->next)
+ {
+ if(but->type == CHARTAB && (but->flag & UI_MOUSE_OVER))
+ {
+ G.charstart = G.charstart - (12*6);
+ if(G.charstart < 0)
+ G.charstart = 0;
+ if(G.charstart < G.charmin)
+ G.charstart = G.charmin;
+ ui_draw_but(but);
+
+ //Really nasty... to update the num button from the same butblock
+ for(bt= block->buttons.first; bt; bt= bt->next)
+ {
+ if(bt->type == NUM) {
+ ui_check_but(bt);
+ ui_draw_but(bt);
+ }
+ }
+ retval=UI_CONT;
+ break;
+ }
+ }
+ break;
+
+ case WHEELDOWNMOUSE:
+ case PAGEDOWNKEY:
+ for(but= block->buttons.first; but; but= but->next)
+ {
+ if(but->type == CHARTAB && (but->flag & UI_MOUSE_OVER))
+ {
+ G.charstart = G.charstart + (12*6);
+ if(G.charstart > (0xffff - 12*6))
+ G.charstart = 0xffff - (12*6);
+ if(G.charstart > G.charmax - 12*6)
+ G.charstart = G.charmax - 12*6;
+ ui_draw_but(but);
+
+ for(bt= block->buttons.first; bt; bt= bt->next)
+ {
+ if(bt->type == NUM) {
+ ui_check_but(bt);
+ ui_draw_but(bt);
+ }
+ }
+
+ but->flag |= UI_ACTIVE;
+ retval=UI_RETURN_OK;
+ break;
+ }
+ }
+ break;
+#endif
+
+ case PADENTER:
+ case RETKEY: // prevent treating this as mousemove. for example when you enter at popup
+ if(block->flag & UI_BLOCK_LOOP) break;
+
+ default:
+
+ for(but= block->buttons.first; but; but= but->next) {
+
+ // active flag clear, it can have been set with number keys or arrows, prevents next loop from wrong selection on click
+ if(uevent->event==LEFTMOUSE) but->flag &= ~UI_ACTIVE;
+
+ but->flag &= ~UI_MOUSE_OVER;
+
+ /* check boundbox */
+ if (uibut_contains_pt(but, uevent->mval)) {
+ but->flag |= UI_MOUSE_OVER;
+ UIbuttip= but;
+ }
+ /* hilite case 1 */
+ if(but->flag & UI_MOUSE_OVER) {
+ if( (but->flag & UI_ACTIVE)==0) {
+ but->flag |= UI_ACTIVE;
+ if(but->type != LABEL && (but->flag & UI_NO_HILITE)==0) ui_draw_but(but);
+ }
+ }
+ /* hilite case 2 */
+ if(but->flag & UI_ACTIVE) {
+ if( (but->flag & UI_MOUSE_OVER)==0) {
+ /* we dont clear active flag until mouse move, for Menu buttons to remain showing active item when opened */
+ if (uevent->event==MOUSEY) {
+ but->flag &= ~UI_ACTIVE;
+ if(but->type != LABEL && (but->flag & UI_NO_HILITE)==0) ui_draw_but(but);
+ }
+ }
+ else if(but->type==BLOCK || but->type==MENU || but->type==PULLDOWN || but->type==ICONTEXTROW) { // automatic opens block button (pulldown)
+ int time;
+ if(uevent->event!=LEFTMOUSE ) {
+ if(block->auto_open==2) time= 1; // test for toolbox
+ else if(block->auto_open) time= 5*U.menuthreshold2;
+ else if(U.uiflag & USER_MENUOPENAUTO) time= 5*U.menuthreshold1;
+ else time= -1;
+
+ for (; time>0; time--) {
+ if (qtest()) break;
+ else PIL_sleep_ms(20);
+ }
+
+ if(time==0) {
+ uevent->val= 1; // otherwise buttons dont react
+ ui_do_button(block, but, uevent);
+ }
+ }
+ }
+ if(but->flag & UI_ACTIVE) active= 1;
+ }
+ }
+
+ /* if there are no active buttons... otherwise clear lines */
+ if(active) ui_do_active_linklines(block, 0);
+ else ui_do_active_linklines(block, uevent->mval);
+
+ }
+
+ /* middlemouse exception, not for regular blocks */
+ if( (block->flag & UI_BLOCK_LOOP) && uevent->event==MIDDLEMOUSE) uevent->event= LEFTMOUSE;
+
+ /* the final dobutton */
+ for(but= block->buttons.first; but; but= but->next) {
+ if(but->flag & UI_ACTIVE) {
+
+ /* UI_BLOCK_RET_1: not return when val==0 */
+
+ if(uevent->val || (block->flag & UI_BLOCK_RET_1)==0) {
+ if ELEM6(uevent->event, LEFTMOUSE, PADENTER, RETKEY, BUT_ACTIVATE, BUT_NEXT, BUT_PREV) {
+ /* when mouse outside, don't do button */
+ if(inside || uevent->event!=LEFTMOUSE) {
+
+ if ELEM(uevent->event, BUT_NEXT, BUT_PREV) {
+ butevent= ui_act_as_text_but(but);
+ uibut_do_func(but);
+ }
+ else
+ butevent= ui_do_button(block, but, uevent);
+
+ /* add undo pushes if... */
+ if( !(block->flag & UI_BLOCK_LOOP)) {
+ if(!G.obedit) {
+ if ELEM5(but->type, BLOCK, BUT, LABEL, PULLDOWN, ROUNDBOX);
+ else {
+ /* define which string to use for undo */
+ if ELEM(but->type, LINK, INLINK) screen_delayed_undo_push("Add button link");
+ else if ELEM(but->type, MENU, ICONTEXTROW) screen_delayed_undo_push(but->drawstr);
+ else if(but->drawstr[0]) screen_delayed_undo_push(but->drawstr);
+ else screen_delayed_undo_push(but->tip);
+ }
+ }
+ }
+
+ if(butevent) addqueue(block->winq, UI_BUT_EVENT, (short)butevent);
+
+ /* i doubt about the next line! */
+ /* if(but->func) mywinset(block->win); */
+
+ if( (block->flag & UI_BLOCK_LOOP) && but->type==BLOCK);
+ else
+ if (butevent) retval= UI_RETURN_OK;
+ }
+ }
+ }
+ }
+ }
+
+ /* flush to frontbuffer */
+ if((block->flag & UI_BLOCK_LOOP)==0) { // no loop, might need total flush in uidoblocks()
+ ui_block_flush_back(block);
+ }
+
+ uiPanelPop(block); // pop matrix; no return without pop!
+
+
+ /* the linkines... why not make buttons from it? Speed? Memory? */
+ if(uevent->val && (uevent->event==XKEY || uevent->event==DELKEY))
+ ui_delete_active_linkline(block);
+
+ /* here we check return conditions for menus */
+ if(block->flag & UI_BLOCK_LOOP) {
+
+ if(inside==0 && uevent->val==1) {
+ if ELEM3(uevent->event, LEFTMOUSE, MIDDLEMOUSE, RIGHTMOUSE) {
+ if(BLI_in_rctf(&block->parentrct, (float)uevent->mval[0], (float)uevent->mval[1]));
+ else return UI_RETURN_OUT;
+ }
+ }
+
+ if(uevent->event==ESCKEY && uevent->val==1) return UI_RETURN_CANCEL;
+
+ if((uevent->event==RETKEY || uevent->event==PADENTER) && uevent->val==1) return UI_RETURN_OK;
+
+ /* check outside */
+ if(inside==0) {
+ uiBlock *tblock= NULL;
+
+ /* check for all parent rects, enables arrowkeys to be used */
+ if(uevent->event!=MOUSEX && uevent->event!=MOUSEY) {
+ for(tblock=block->parent; tblock; tblock= tblock->parent) {
+ if( BLI_in_rctf(&tblock->parentrct, (float)uevent->mval[0], (float)uevent->mval[1]))
+ break;
+ else if( BLI_in_rctf(&tblock->safety, (float)uevent->mval[0], (float)uevent->mval[1]))
+ break;
+ }
+ }
+ /* strict check, and include the parent rect */
+ if(tblock);
+ else if( BLI_in_rctf(&block->parentrct, (float)uevent->mval[0], (float)uevent->mval[1]));
+ else if( ui_mouse_motion_towards_block(block, uevent));
+ else if( BLI_in_rctf(&block->safety, (float)uevent->mval[0], (float)uevent->mval[1]));
+ else return UI_RETURN_OUT;
+ }
+ }
+
+ return retval;
+}
+
+static uiOverDraw *ui_draw_but_tip(uiBut *but)
+{
+ uiOverDraw *od;
+ float x1, x2, y1, y2;
+ rctf tip_bbox;
+
+ BIF_GetBoundingBox(but->font, but->tip, (U.transopts & USER_TR_TOOLTIPS), &tip_bbox);
+
+ x1= (but->x1+but->x2)/2;
+ x2= x1+but->aspect*((tip_bbox.xmax-tip_bbox.xmin) + 8);
+ y2= but->y1-10;
+ y1= y2-but->aspect*((tip_bbox.ymax+(tip_bbox.ymax-tip_bbox.ymin)));
+
+
+ /* for pulldown menus it doesnt work */
+ if(mywinget()==G.curscreen->mainwin);
+ else {
+ ui_graphics_to_window(mywinget(), &x1, &y1);
+ ui_graphics_to_window(mywinget(), &x2, &y2);
+ }
+
+ if(x2 > G.curscreen->sizex) {
+ x1 -= x2-G.curscreen->sizex;
+ x2= G.curscreen->sizex;
+ }
+ if(y1 < 0) {
+ y1 += 36;
+ y2 += 36;
+ }
+
+ od= ui_begin_overdraw((int)(x1-1), (int)(y1-2), (int)(x2+4), (int)(y2+4));
+
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_BLEND);
+
+ glColor4ub(0, 0, 0, 20);
+
+ gl_round_box(GL_POLYGON, x1+3, y1-1, x2+1, y2-2, 2.0);
+ gl_round_box(GL_POLYGON, x1+3, y1-2, x2+2, y2-2, 3.0);
+
+ glColor4ub(0, 0, 0, 8);
+
+ gl_round_box(GL_POLYGON, x1+3, y1-3, x2+3, y2-3, 4.0);
+ gl_round_box(GL_POLYGON, x1+3, y1-4, x2+4, y2-3, 5.0);
+
+ glDisable(GL_BLEND);
+
+ glColor3ub(0xFF, 0xFF, 0xDD);
+ glRectf(x1, y1, x2, y2);
+
+ glColor3ub(0,0,0);
+ /* set the position for drawing text +4 in from the left edge, and leaving an equal gap between the top of the background box
+ * and the top of the string's tip_bbox, and the bottom of the background box, and the bottom of the string's tip_bbox
+ */
+ ui_rasterpos_safe(x1+4, ((y2-tip_bbox.ymax)+(y1+tip_bbox.ymin))/2 - tip_bbox.ymin, but->aspect);
+ BIF_SetScale(1.0);
+
+ BIF_DrawString(but->font, but->tip, (U.transopts & USER_TR_TOOLTIPS));
+
+ ui_flush_overdraw(od); /* to show it in the frontbuffer */
+ return od;
+}
+
+/* inside this function no global UIbuttip... qread is not safe */
+static void ui_do_but_tip(uiBut *buttip)
+{
+ uiOverDraw *od;
+ int time;
+
+ if (buttip && buttip->tip && buttip->tip[0]) {
+ /* Pause for a moment to see if we
+ * should really display the tip
+ * or if the user will keep moving
+ * the pointer.
+ */
+ for (time= 0; time<25; time++) {
+ if (anyqtest())
+ return;
+ else
+ PIL_sleep_ms(20);
+ }
+
+ /* Display the tip, and keep it displayed
+ * as long as the mouse remains on top
+ * of the button that owns it.
+ */
+ Mat4CpyMat4(UIwinmat, buttip->block->winmat); // get rid of uiwinmat once...
+ uiPanelPush(buttip->block); // panel matrix
+ od= ui_draw_but_tip(buttip);
+
+ if(od) {
+ while (1) {
+ char ascii;
+ short val;
+ unsigned short evt= extern_qread_ext(&val, &ascii);
+
+ if (evt==MOUSEX || evt==MOUSEY) {
+ short mouse[2];
+ uiGetMouse(od->oldwin, mouse);
+
+ if (!uibut_contains_pt(buttip, mouse))
+ break;
+ } else {
+ mainqpushback(evt, val, ascii);
+ break;
+ }
+ }
+
+ ui_end_overdraw(od);
+ }
+
+ uiPanelPop(buttip->block); // panel matrix
+ /* still the evil global.... */
+ UIbuttip= NULL;
+ }
+}
+
+/* returns UI_NOTHING, if nothing happened */
+int uiDoBlocks(ListBase *lb, int event)
+{
+ /* return when: firstblock != BLOCK_LOOP
+ *
+ * 'cont' is used to make sure you can press another button while a looping menu
+ * is active. otherwise you have to press twice...
+ */
+
+ uiBlock *block, *first;
+ uiEvent uevent;
+ int retval= UI_NOTHING, cont= 1;
+
+ if(lb->first==0) return UI_NOTHING;
+
+ /* for every pixel both x and y events are generated, overloads the system! */
+ if(event==MOUSEX) return UI_NOTHING;
+
+ UIbuttip= NULL;
+ UIafterfunc_butm= NULL; /* to prevent infinite loops, this shouldnt be a global! */
+ UIafterfunc_but= NULL; /* to prevent infinite loops, this shouldnt be a global! */
+ UIafterfunc_arg1= UIafterfunc_arg2= NULL;
+
+ uevent.qual= G.qual;
+ uevent.event= event;
+ uevent.val= 1;
+
+ /* this is a caching mechanism, to prevent too many calls to glFrontBuffer and glFlush, which slows down interface */
+ block= lb->first;
+ while(block) {
+ ui_block_set_flush(block, NULL); // clears all flushing info
+ block= block->next;
+ }
+
+ /* main loop, needed when you click outside a looping block (menu) then it uses that
+ event to immediately evaluate the other uiBlocks again. */
+ while(cont) {
+
+ /* first loop, for the normal blocks */
+ block= lb->first;
+ while(block) {
+
+ /* for pupmenus, the bgnpupdraw sets (and later restores) the active
+ window. Then mousecoords get transformed OK.
+ It looks double... but a call to ui_do_block otherwise doesnt get handled properly
+ */
+ if(block->flag & UI_BLOCK_REDRAW) {
+ if( block->flag & UI_BLOCK_LOOP) {
+ block->overdraw= ui_begin_overdraw((int)block->minx-1, (int)block->miny-10, (int)block->maxx+10, (int)block->maxy+1);
+ }
+ block->in_use= 1; // is always a menu
+ uiDrawBlock(block);
+ block->flag &= ~UI_BLOCK_REDRAW;
+ }
+
+ block->in_use= 1; // bit awkward, but now we can detect if frontbuf flush should be set
+ retval |= ui_do_block(block, &uevent); /* we 'or' because 2nd loop can return to here, and we we want 'out' to return */
+ block->in_use= 0;
+ if(retval & UI_EXIT_LOOP) break;
+
+ /* now a new block could be created for menus, this is
+ inserted in the beginning of a list */
+
+ /* is there a flush cached? */
+ if(block->needflush) {
+ ui_block_flush_overdraw(block);
+ block->needflush= 0;
+ }
+
+ /* to make sure the matrix of the panel works for menus too */
+ if(retval==UI_CONT || (retval & UI_RETURN)) break;
+ first= lb->first; if(first->flag & UI_BLOCK_LOOP) break;
+
+ block= block->next;
+ }
+
+ /* second loop, for menus (looping blocks). works for sub->menus too */
+ block= lb->first;
+ if(block==NULL || (block->flag & UI_BLOCK_LOOP)==0) cont= 0;
+
+ while( (block= lb->first) && (block->flag & UI_BLOCK_LOOP)) {
+ if(block->auto_open==0) block->auto_open= 1;
+
+ /* this here, for menu buts */
+ if(block->flag & UI_BLOCK_REDRAW) {
+
+ if( block->flag & UI_BLOCK_LOOP) {
+ block->overdraw= ui_begin_overdraw((int)block->minx-1, (int)block->miny-6, (int)block->maxx+6, (int)block->maxy+1);
+ }
+ uiDrawBlock(block);
+ block->flag &= ~UI_BLOCK_REDRAW;
+ ui_flush_overdraw(block->overdraw);
+ block->needflush= 0;
+ }
+
+ uevent.event= extern_qread(&uevent.val);
+ uevent.qual= G.qual;
+
+ if(uevent.event) {
+ block->in_use= 1; // bit awkward, but now we can detect if frontbuf flush should be set
+ retval= ui_do_block(block, &uevent);
+ block->in_use= 0;
+
+ if(block->needflush) { // flush (old menu) now, maybe new menu was opened
+ ui_block_flush_overdraw(block);
+ block->needflush= 0;
+ }
+
+ if(retval & UI_RETURN) {
+ ui_end_overdraw(block->overdraw);
+ BLI_remlink(lb, block);
+ uiFreeBlock(block);
+ }
+ if(retval & (UI_RETURN_OK|UI_RETURN_CANCEL)) {
+ /* free other menus */
+ while( (block= lb->first) && (block->flag & UI_BLOCK_LOOP)) {
+ ui_end_overdraw(block->overdraw);
+ BLI_remlink(lb, block);
+ uiFreeBlock(block);
+ }
+ }
+ }
+
+ /* tooltip */
+ if(retval==UI_NOTHING && (uevent.event==MOUSEX || uevent.event==MOUSEY)) {
+ if(U.flag & USER_TOOLTIPS) ui_do_but_tip(UIbuttip);
+ }
+ }
+
+ /* else it does the first part of this loop again, maybe another menu needs to be opened */
+ if(retval==UI_CONT || (retval & UI_RETURN_OK)) cont= 0;
+ }
+
+ /* clears screendump boundbox, call before afterfunc! */
+ ui_set_screendump_bbox(NULL);
+
+ /* afterfunc is used for fileloading too, so after this call, the blocks pointers are invalid */
+ if(retval & UI_RETURN_OK) {
+ if(UIafterfunc_butm) {
+ mywinset(curarea->win);
+ UIafterfunc_butm(UIafterfunc_arg1, UIafterval);
+ UIafterfunc_butm= NULL;
+ }
+ if(UIafterfunc_but) {
+ mywinset(curarea->win);
+ UIafterfunc_but(UIafterfunc_arg1, UIafterfunc_arg2);
+ UIafterfunc_but= NULL;
+ }
+ }
+
+ /* tooltip */
+ if(retval==UI_NOTHING && (uevent.event==MOUSEX || uevent.event==MOUSEY)) {
+ if(U.flag & USER_TOOLTIPS) ui_do_but_tip(UIbuttip);
+ }
+
+ return retval;
+}
+
+/* ************** DATA *************** */
+
+/* for buttons pointing to color for example */
+void ui_get_but_vectorf(uiBut *but, float *vec)
+{
+ void *poin;
+
+ poin= but->poin;
+
+ if( but->pointype == CHA ) {
+ char *cp= (char *)poin;
+ vec[0]= ((float)cp[0])/255.0;
+ vec[1]= ((float)cp[1])/255.0;
+ vec[2]= ((float)cp[2])/255.0;
+ }
+ else if( but->pointype == FLO ) {
+ float *fp= (float *)poin;
+ VECCOPY(vec, fp);
+ }
+}
+/* for buttons pointing to color for example */
+void ui_set_but_vectorf(uiBut *but, float *vec)
+{
+ void *poin;
+
+ poin= but->poin;
+
+ if( but->pointype == CHA ) {
+ char *cp= (char *)poin;
+ cp[0]= (char)(0.5 +vec[0]*255.0);
+ cp[1]= (char)(0.5 +vec[1]*255.0);
+ cp[2]= (char)(0.5 +vec[2]*255.0);
+ }
+ else if( but->pointype == FLO ) {
+ float *fp= (float *)poin;
+ VECCOPY(fp, vec);
+ }
+}
+
+double ui_get_but_val(uiBut *but)
+{
+ void *poin;
+ double value = 0.0;
+
+ if(but->poin==NULL) return 0.0;
+ poin= but->poin;
+
+ if(but->type== HSVSLI) {
+ float h, s, v, *fp= (float *) poin;
+
+ rgb_to_hsv(fp[0], fp[1], fp[2], &h, &s, &v);
+
+ switch(but->str[0]) {
+ case 'H': value= h; break;
+ case 'S': value= s; break;
+ case 'V': value= v; break;
+ }
+
+ }
+ else if( but->pointype == CHA ) {
+ value= *(char *)poin;
+ }
+ else if( but->pointype == SHO ) {
+ value= *(short *)poin;
+ }
+ else if( but->pointype == INT ) {
+ value= *(int *)poin;
+ }
+ else if( but->pointype == FLO ) {
+ value= *(float *)poin;
+ }
+
+ return value;
+}
+
+static void ui_set_but_val(uiBut *but, double value)
+{
+ void *poin;
+
+ if(but->pointype==0) return;
+ poin= but->poin;
+
+ /* value is a hsv value: convert to rgb */
+ if( but->type==HSVSLI ) {
+ float h, s, v, *fp= (float *)but->poin;
+
+ rgb_to_hsv(fp[0], fp[1], fp[2], &h, &s, &v);
+
+ switch(but->str[0]) {
+ case 'H': h= value; break;
+ case 'S': s= value; break;
+ case 'V': v= value; break;
+ }
+
+ hsv_to_rgb(h, s, v, fp, fp+1, fp+2);
+
+ }
+ else if( but->pointype==CHA )
+ *((char *)poin)= (char)floor(value+0.5);
+ else if( but->pointype==SHO ) {
+ /* gcc 3.2.1 seems to have problems
+ * casting a double like 32772.0 to
+ * a short so we cast to an int, then
+ to a short */
+ int gcckludge;
+ gcckludge = (int) floor(value+0.5);
+ *((short *)poin)= (short) gcckludge;
+ }
+ else if( but->pointype==INT )
+ *((int *)poin)= (int)floor(value+0.5);
+ else if( but->pointype==FLO ) {
+ float fval= (float)value;
+ if(fval>= -0.00001f && fval<= 0.00001f) fval= 0.0f; /* prevent negative zero */
+ *((float *)poin)= fval;
+ }
+
+ /* update select flag */
+ ui_is_but_sel(but);
+
+}
+
+void uiSetCurFont(uiBlock *block, int index)
+{
+
+ ui_set_ftf_font(block->aspect);
+
+ if(block->aspect<0.60) {
+ block->curfont= UIfont[index].xl;
+ }
+ else if(block->aspect<1.15) {
+ block->curfont= UIfont[index].large;
+ }
+ else if(block->aspect<1.59) {
+ block->curfont= UIfont[index].medium;
+ }
+ else {
+ block->curfont= UIfont[index].small;
+ }
+
+ if(block->curfont==NULL) block->curfont= UIfont[index].large;
+ if(block->curfont==NULL) block->curfont= UIfont[index].medium;
+ if(block->curfont==NULL) printf("error block no font %s\n", block->name);
+
+}
+
+/* called by node editor */
+void *uiSetCurFont_ext(float aspect)
+{
+ void *curfont;
+
+ ui_set_ftf_font(aspect);
+
+ if(aspect<0.60) {
+ curfont= UIfont[0].xl;
+ }
+ else if(aspect<1.15) {
+ curfont= UIfont[0].large;
+ }
+ else if(aspect<1.59) {
+ curfont= UIfont[0].medium;
+ }
+ else {
+ curfont= UIfont[0].small;
+ }
+
+ if(curfont==NULL) curfont= UIfont[0].large;
+ if(curfont==NULL) curfont= UIfont[0].medium;
+
+ return curfont;
+}
+
+void uiDefFont(unsigned int index, void *xl, void *large, void *medium, void *small)
+{
+ if(index>=UI_ARRAY) return;
+
+ UIfont[index].xl= xl;
+ UIfont[index].large= large;
+ UIfont[index].medium= medium;
+ UIfont[index].small= small;
+}
+
+static void ui_free_link(uiLink *link)
+{
+ if(link) {
+ BLI_freelistN(&link->lines);
+ MEM_freeN(link);
+ }
+}
+
+static void ui_free_but(uiBut *but)
+{
+ if(but->str && but->str != but->strdata) MEM_freeN(but->str);
+ ui_free_link(but->link);
+
+ MEM_freeN(but);
+}
+
+void uiFreeBlock(uiBlock *block)
+{
+ uiBut *but;
+
+ if(block->flag & UI_BLOCK_BUSY) printf("attempt to free busy buttonblock: %p\n", block);
+
+ while( (but= block->buttons.first) ) {
+ BLI_remlink(&block->buttons, but);
+ ui_free_but(but);
+ }
+
+ if(block->panel) block->panel->active= 0;
+
+
+ MEM_freeN(block);
+ UIbuttip= NULL;
+}
+
+void uiFreeBlocks(ListBase *lb)
+{
+ uiBlock *block;
+
+ while( (block= lb->first) ) {
+ BLI_remlink(lb, block);
+ uiFreeBlock(block);
+ }
+}
+
+void uiFreeBlocksWin(ListBase *lb, int win)
+{
+ uiBlock *block, *blockn;
+
+ block= lb->first;
+ while(block) {
+ blockn= block->next;
+ if(block->win==win) {
+ BLI_remlink(lb, block);
+ uiFreeBlock(block);
+ }
+ block= blockn;
+ }
+}
+
+uiBlock *uiNewBlock(ListBase *lb, char *name, short dt, short font, short win)
+{
+ uiBlock *block;
+
+ /* each listbase only has one block with this name */
+ if(lb) {
+ for (block= lb->first; block; block= block->next)
+ if (BLI_streq(block->name, name))
+ break;
+ if (block) {
+ BLI_remlink(lb, block);
+ uiFreeBlock(block);
+ }
+ }
+
+ block= MEM_callocN(sizeof(uiBlock), "uiBlock");
+ if(lb) BLI_addhead(lb, block); /* at the beginning of the list! for dynamical menus/blocks */
+
+ strcpy(block->name, name);
+ /* draw win */
+ block->win= win;
+ /* window where queue event should be added, pretty weak this way!
+ this is because the 'mainwin' pup menu's */
+ block->winq= mywinget();
+ block->dt= dt;
+ block->themecol= TH_AUTO;
+
+ /* aspect */
+ bwin_getsinglematrix(win, block->winmat);
+
+ if (win==G.curscreen->mainwin) {
+ block->aspect= 1.0;
+ block->auto_open= 2;
+ } else {
+ int getsizex, getsizey;
+
+ bwin_getsize(win, &getsizex, &getsizey);
+ block->aspect= 2.0/( (getsizex)*block->winmat[0][0]);
+ }
+
+ uiSetCurFont(block, font);
+
+ UIbuttip= NULL;
+ UIlock= 0;
+
+ return block;
+}
+
+uiBlock *uiGetBlock(char *name, ScrArea *sa)
+{
+ uiBlock *block= sa->uiblocks.first;
+
+ while(block) {
+ if( strcmp(name, block->name)==0 ) return block;
+ block= block->next;
+ }
+
+ return NULL;
+}
+
+void ui_check_but(uiBut *but)
+{
+ /* if something changed in the button */
+ ID *id;
+ double value;
+ float okwidth;
+ int transopts= (U.transopts & USER_TR_BUTTONS);
+ short pos;
+
+ ui_is_but_sel(but);
+
+ if(but->type==TEX || but->type==IDPOIN) transopts= 0;
+
+ /* test for min and max, icon sliders, etc */
+ switch( but->type ) {
+ case NUM:
+ case SLI:
+ case SCROLL:
+ case NUMSLI:
+ case HSVSLI:
+ value= ui_get_but_val(but);
+ if(value < but->min) value= but->min;
+ if(value > but->max) value= but->max;
+ ui_set_but_val(but, value);
+ break;
+
+ case ICONTOG:
+ case ICONTOGN:
+ if(but->flag & UI_SELECT) but->iconadd= 1;
+ else but->iconadd= 0;
+ break;
+
+ case ICONROW:
+ value= ui_get_but_val(but);
+ but->iconadd= (int)value- (int)(but->min);
+ break;
+
+ case ICONTEXTROW:
+ value= ui_get_but_val(but);
+ but->iconadd= (int)value- (int)(but->min);
+ break;
+ }
+
+
+ /* safety is 4 to enable small number buttons (like 'users') */
+ if(but->type==NUMSLI || but->type==HSVSLI)
+ okwidth= -4 + (but->x2 - but->x1)/2.0;
+ else
+ okwidth= -4 + (but->x2 - but->x1);
+
+ /* name: */
+ switch( but->type ) {
+
+ case MENU:
+ case ICONTEXTROW:
+
+ if(but->x2 - but->x1 > 24) {
+ value= ui_get_but_val(but);
+ ui_set_name_menu(but, (int)value);
+ }
+ break;
+
+ case NUM:
+ case NUMSLI:
+ case HSVSLI:
+
+ value= ui_get_but_val(but);
+
+ if( but->pointype==FLO ) {
+ if(but->a2) { /* amount of digits defined */
+ if(but->a2==1) sprintf(but->drawstr, "%s%.1f", but->str, value);
+ else if(but->a2==2) sprintf(but->drawstr, "%s%.2f", but->str, value);
+ else if(but->a2==3) sprintf(but->drawstr, "%s%.3f", but->str, value);
+ else sprintf(but->drawstr, "%s%.4f", but->str, value);
+ }
+ else {
+ if(but->max<10.001) sprintf(but->drawstr, "%s%.3f", but->str, value);
+ else sprintf(but->drawstr, "%s%.2f", but->str, value);
+ }
+ }
+ else {
+ sprintf(but->drawstr, "%s%d", but->str, (int)value);
+ }
+ break;
+
+ case LABEL:
+ if( but->pointype==FLO && but->poin) {
+ value= ui_get_but_val(but);
+ if(but->a2) { /* amount of digits defined */
+ if(but->a2==1) sprintf(but->drawstr, "%s%.1f", but->str, value);
+ else if(but->a2==2) sprintf(but->drawstr, "%s%.2f", but->str, value);
+ else if(but->a2==3) sprintf(but->drawstr, "%s%.3f", but->str, value);
+ else sprintf(but->drawstr, "%s%.4f", but->str, value);
+ }
+ else {
+ sprintf(but->drawstr, "%s%.2f", but->str, value);
+ }
+ }
+ else strcpy(but->drawstr, but->str);
+
+ break;
+
+ case IDPOIN:
+ id= *(but->idpoin_idpp);
+ strcpy(but->drawstr, but->str);
+ if(id) strcat(but->drawstr, id->name+2);
+ break;
+
+ case TEX:
+ strcpy(but->drawstr, but->str);
+ strcat(but->drawstr, but->poin);
+ break;
+
+ case KEYEVT:
+ strcpy(but->drawstr, but->str);
+ if (but->flag & UI_SELECT) {
+ strcat(but->drawstr, "Press a key");
+ } else {
+ strcat(but->drawstr, key_event_to_string((short) ui_get_but_val(but)));
+ }
+ break;
+ case BUT_TOGDUAL:
+ /* trying to get the dual-icon to left of text... not very nice */
+ if(but->str[0]) {
+ strcpy(but->drawstr, " ");
+ strcpy(but->drawstr+2, but->str);
+ }
+ break;
+ default:
+ strcpy(but->drawstr, but->str);
+
+ }
+
+ if(but->drawstr[0]) {
+ but->strwidth= but->aspect*BIF_GetStringWidth(but->font, but->drawstr, transopts);
+ // here should be check for less space for icon offsets...
+ if(but->type==MENU) okwidth -= 15;
+ }
+ else
+ but->strwidth= 0;
+
+ /* automatic width */
+ if(but->x2==0.0f && but->x1 > 0.0f) {
+ but->x2= (but->x1+but->strwidth+6);
+ }
+
+ if(but->strwidth==0) but->drawstr[0]= 0;
+ else if(but->type==BUTM || but->type==BLOCK); // no clip string, uiTextBoundsBlock is used (hack!)
+ else {
+
+ /* calc but->ofs, to draw the string shorter if too long */
+ but->ofs= 0;
+ while(but->strwidth > (int)okwidth ) {
+
+ if ELEM(but->type, NUM, TEX) { // only these cut off left
+ but->ofs++;
+ but->strwidth= but->aspect*BIF_GetStringWidth(but->font, but->drawstr+but->ofs, transopts);
+
+ /* textbut exception */
+ if(but->pos != -1) {
+ pos= but->pos+strlen(but->str);
+ if(pos-1 < but->ofs) {
+ pos= but->ofs-pos+1;
+ but->ofs -= pos;
+ if(but->ofs<0) {
+ but->ofs= 0;
+ pos--;
+ }
+ but->drawstr[ strlen(but->drawstr)-pos ]= 0;
+ }
+ }
+ }
+ else {
+ but->drawstr[ strlen(but->drawstr)-1 ]= 0;
+ but->strwidth= but->aspect*BIF_GetStringWidth(but->font, but->drawstr, transopts);
+ }
+
+ if(but->strwidth < 10) break;
+ }
+ }
+}
+
+static int ui_auto_themecol(uiBut *but)
+{
+
+ switch(but->type) {
+ case BUT:
+ return TH_BUT_ACTION;
+ case ROW:
+ case TOG:
+ case TOG3:
+ case TOGR:
+ case TOGN:
+ case BUT_TOGDUAL:
+ return TH_BUT_SETTING;
+ case SLI:
+ case NUM:
+ case NUMSLI:
+ case HSVSLI:
+ return TH_BUT_NUM;
+ case TEX:
+ return TH_BUT_TEXTFIELD;
+ case PULLDOWN:
+ case BLOCK:
+ case MENU:
+ case BUTM:
+ // (weak!) detect if it is a blockloop
+ if(but->block->dt == UI_EMBOSSP) return TH_MENU_ITEM;
+ return TH_BUT_POPUP;
+ default:
+ return TH_BUT_NEUTRAL;
+ }
+}
+
+void uiBlockBeginAlign(uiBlock *block)
+{
+ /* if other align was active, end it */
+ if(block->flag & UI_BUT_ALIGN) uiBlockEndAlign(block);
+
+ block->flag |= UI_BUT_ALIGN_DOWN;
+ /* buttons declared after this call will this align flag */
+}
+
+static int buts_are_horiz(uiBut *but1, uiBut *but2)
+{
+ float dx, dy;
+
+ dx= fabs( but1->x2 - but2->x1);
+ dy= fabs( but1->y1 - but2->y2);
+
+ if(dx > dy) return 0;
+ return 1;
+}
+
+void uiBlockEndAlign(uiBlock *block)
+{
+ uiBut *prev, *but=NULL, *next;
+ int flag= 0, cols=0, rows=0;
+ int theme= BIF_GetThemeValue(TH_BUT_DRAWTYPE);
+
+ if ( !(ELEM3(theme, TH_MINIMAL, TH_SHADED, TH_ROUNDED)) ) {
+ block->flag &= ~UI_BUT_ALIGN; // all 4 flags
+ return;
+ }
+
+ /* auto align:
+ - go back to first button of align start (ALIGN_DOWN)
+ - compare triples, and define flags
+ */
+ prev= block->buttons.last;
+ while(prev) {
+ if( (prev->flag & UI_BUT_ALIGN_DOWN)) but= prev;
+ else break;
+
+ if(but && but->next) {
+ if(buts_are_horiz(but, but->next)) cols++;
+ else rows++;
+ }
+
+ prev= prev->prev;
+ }
+ if(but==NULL) return;
+
+ /* rows==0: 1 row, cols==0: 1 collumn */
+
+ /* note; how it uses 'flag' in loop below (either set it, or OR it) is confusing */
+ prev= NULL;
+ while(but) {
+ next= but->next;
+
+ /* clear old flag */
+ but->flag &= ~UI_BUT_ALIGN_DOWN;
+
+ if(flag==0) { /* first case */
+ if(next) {
+ if(buts_are_horiz(but, next)) {
+ if(rows==0)
+ flag= UI_BUT_ALIGN_RIGHT;
+ else
+ flag= UI_BUT_ALIGN_DOWN|UI_BUT_ALIGN_RIGHT;
+ }
+ else {
+ flag= UI_BUT_ALIGN_DOWN;
+ }
+ }
+ }
+ else if(next==NULL) { /* last case */
+ if(prev) {
+ if(buts_are_horiz(prev, but)) {
+ if(rows==0)
+ flag= UI_BUT_ALIGN_LEFT;
+ else
+ flag= UI_BUT_ALIGN_TOP|UI_BUT_ALIGN_LEFT;
+ }
+ else flag= UI_BUT_ALIGN_TOP;
+ }
+ }
+ else if(buts_are_horiz(but, next)) {
+ /* check if this is already second row */
+ if( prev && buts_are_horiz(prev, but)==0) {
+ flag |= UI_BUT_ALIGN_TOP;
+ /* exception case: bottom row */
+ if(rows>0) {
+ uiBut *bt= but;
+ while(bt) {
+ if(bt->next && buts_are_horiz(bt, bt->next)==0 ) break;
+ bt= bt->next;
+ }
+ if(bt==0) flag= UI_BUT_ALIGN_TOP|UI_BUT_ALIGN_RIGHT;
+ }
+ }
+ else flag |= UI_BUT_ALIGN_LEFT;
+ }
+ else {
+ if(cols==0) {
+ flag |= UI_BUT_ALIGN_TOP;
+ }
+ else { /* next button switches to new row */
+ if( (flag & UI_BUT_ALIGN_TOP)==0) { /* stil top row */
+ if(prev)
+ flag= UI_BUT_ALIGN_DOWN|UI_BUT_ALIGN_LEFT;
+ else
+ flag |= UI_BUT_ALIGN_DOWN;
+ }
+ else
+ flag |= UI_BUT_ALIGN_TOP;
+ }
+ }
+
+ but->flag |= flag;
+
+ /* merge coordinates */
+ if(prev) {
+ // simple cases
+ if(rows==0) {
+ but->x1= (prev->x2+but->x1)/2.0;
+ prev->x2= but->x1;
+ }
+ else if(cols==0) {
+ but->y2= (prev->y1+but->y2)/2.0;
+ prev->y1= but->y2;
+ }
+ else {
+ if(buts_are_horiz(prev, but)) {
+ but->x1= (prev->x2+but->x1)/2.0;
+ prev->x2= but->x1;
+ /* copy height too */
+ but->y2= prev->y2;
+ }
+ else if(prev->prev && buts_are_horiz(prev->prev, prev)==0) {
+ /* the previous button is a single one in its row */
+ but->y2= (prev->y1+but->y2)/2.0;
+ prev->y1= but->y2;
+ }
+ else {
+ /* the previous button is not a single one in its row */
+ but->y2= prev->y1;
+ }
+ }
+ }
+
+ prev= but;
+ but= next;
+ }
+
+ block->flag &= ~UI_BUT_ALIGN; // all 4 flags
+}
+
+#if 0
+static void uiBlockEndAligno(uiBlock *block)
+{
+ uiBut *but;
+
+ /* correct last defined button */
+ but= block->buttons.last;
+ if(but) {
+ /* vertical align case */
+ if( (block->flag & UI_BUT_ALIGN) == (UI_BUT_ALIGN_TOP|UI_BUT_ALIGN_DOWN) ) {
+ but->flag &= ~UI_BUT_ALIGN_DOWN;
+ }
+ /* horizontal align case */
+ if( (block->flag & UI_BUT_ALIGN) == (UI_BUT_ALIGN_LEFT|UI_BUT_ALIGN_RIGHT) ) {
+ but->flag &= ~UI_BUT_ALIGN_RIGHT;
+ }
+ /* else do nothing, manually provided flags */
+ }
+ block->flag &= ~UI_BUT_ALIGN; // all 4 flags
+}
+#endif
+
+/*
+ui_def_but is the function that draws many button types
+
+for float buttons:
+ "a1" Click Step (how much to change the value each click)
+ "a2" Number of decimal point values to display. 0 defaults to 3 (0.000) 1,2,3, and a maximum of 4,
+ all greater values will be clamped to 4.
+
+*/
+static uiBut *ui_def_but(uiBlock *block, int type, int retval, char *str, short x1, short y1, short x2, short y2, void *poin, float min, float max, float a1, float a2, char *tip)
+{
+ uiBut *but;
+ short slen;
+
+ if(type & BUTPOIN) { /* a pointer is required */
+ if(poin==NULL) {
+ /* if pointer is zero, button is removed and not drawn */
+ BIF_ThemeColor(block->themecol);
+ glRects(x1, y1, x1+x2, y1+y2);
+ return NULL;
+ }
+ }
+
+ but= MEM_callocN(sizeof(uiBut), "uiBut");
+
+ but->type= type & BUTTYPE;
+ but->pointype= type & BUTPOIN;
+ but->bit= type & BIT;
+ but->bitnr= type & 31;
+ but->icon = 0;
+
+ BLI_addtail(&block->buttons, but);
+
+ but->retval= retval;
+ if( strlen(str)>=UI_MAX_NAME_STR-1 ) {
+ but->str= MEM_callocN( strlen(str)+2, "uiDefBut");
+ strcpy(but->str, str);
+ }
+ else {
+ but->str= but->strdata;
+ strcpy(but->str, str);
+ }
+ but->x1= x1;
+ but->y1= y1;
+ if(block->autofill) {
+ but->x2= x2;
+ but->y2= y2;
+ }
+ else {
+ but->x2= (x1+x2);
+ but->y2= (y1+y2);
+ }
+ but->poin= poin;
+ but->min= min;
+ but->max= max;
+ but->a1= a1;
+ but->a2= a2;
+ but->tip= tip;
+
+ but->font= block->curfont;
+
+ but->lock= UIlock;
+ but->lockstr= UIlockstr;
+
+ but->aspect= block->aspect;
+ but->win= block->win;
+ but->block= block; // pointer back, used for frontbuffer status, and picker
+
+ if(block->themecol==TH_AUTO) but->themecol= ui_auto_themecol(but);
+ else but->themecol= block->themecol;
+
+ if (but->type==BUTM) {
+ but->butm_func= block->butm_func;
+ but->butm_func_arg= block->butm_func_arg;
+ } else {
+ but->func= block->func;
+ but->func_arg1= block->func_arg1;
+ but->func_arg2= block->func_arg2;
+ }
+
+ ui_set_embossfunc(but, block->dt);
+
+ but->pos= -1; /* cursor invisible */
+
+ if(but->type==NUM) { /* add a space to name */
+ slen= strlen(but->str);
+ if(slen>0 && slen<UI_MAX_NAME_STR-2) {
+ if(but->str[slen-1]!=' ') {
+ but->str[slen]= ' ';
+ but->str[slen+1]= 0;
+ }
+ }
+ }
+
+ if(but->type==HSVCUBE) { /* hsv buttons temp storage */
+ float rgb[3];
+ ui_get_but_vectorf(but, rgb);
+ rgb_to_hsv(rgb[0], rgb[1], rgb[2], but->hsv, but->hsv+1, but->hsv+2);
+ }
+
+ if ELEM8(but->type, HSVSLI , NUMSLI, MENU, TEX, LABEL, IDPOIN, BLOCK, BUTM) {
+ but->flag |= UI_TEXT_LEFT;
+ }
+
+ if(but->type==BUT_TOGDUAL) {
+ but->flag |= UI_ICON_LEFT;
+ }
+
+ if(but->type==ROUNDBOX)
+ but->flag |= UI_NO_HILITE;
+
+ but->flag |= (block->flag & UI_BUT_ALIGN);
+ if(block->flag & UI_BLOCK_NO_HILITE)
+ but->flag |= UI_NO_HILITE;
+
+ return but;
+}
+
+uiBut *uiDefBut(uiBlock *block, int type, int retval, char *str, short x1, short y1, short x2, short y2, void *poin, float min, float max, float a1, float a2, char *tip)
+{
+ uiBut *but= ui_def_but(block, type, retval, str, x1, y1, x2, y2, poin, min, max, a1, a2, tip);
+
+ ui_check_but(but);
+
+ return but;
+}
+
+ /* if _x_ is a power of two (only one bit) return the power,
+ * otherwise return -1.
+ * (1<<findBitIndex(x))==x for powers of two.
+ */
+static int findBitIndex(unsigned int x) {
+ if (!x || (x&(x-1))!=0) { /* x&(x-1) strips lowest bit */
+ return -1;
+ } else {
+ int idx= 0;
+
+ if (x&0xFFFF0000) idx+=16, x>>=16;
+ if (x&0xFF00) idx+=8, x>>=8;
+ if (x&0xF0) idx+=4, x>>=4;
+ if (x&0xC) idx+=2, x>>=2;
+ if (x&0x2) idx+=1;
+
+ return idx;
+ }
+}
+
+/* autocomplete helper functions */
+struct AutoComplete {
+ int maxlen;
+ char *truncate;
+ char *startname;
+};
+
+AutoComplete *autocomplete_begin(char *startname, int maxlen)
+{
+ AutoComplete *autocpl;
+
+ autocpl= MEM_callocN(sizeof(AutoComplete), "AutoComplete");
+ autocpl->maxlen= maxlen;
+ autocpl->truncate= MEM_callocN(sizeof(char)*maxlen, "AutoCompleteTruncate");
+ autocpl->startname= startname;
+
+ return autocpl;
+}
+
+void autocomplete_do_name(AutoComplete *autocpl, const char *name)
+{
+ char *truncate= autocpl->truncate;
+ char *startname= autocpl->startname;
+ int a;
+
+ for(a=0; a<autocpl->maxlen-1; a++) {
+ if(startname[a]==0 || startname[a]!=name[a])
+ break;
+ }
+ /* found a match */
+ if(startname[a]==0) {
+ /* first match */
+ if(truncate[0]==0)
+ BLI_strncpy(truncate, name, autocpl->maxlen);
+ else {
+ /* remove from truncate what is not in bone->name */
+ for(a=0; a<autocpl->maxlen-1; a++) {
+ if(truncate[a]!=name[a])
+ truncate[a]= 0;
+ }
+ }
+ }
+}
+
+void autocomplete_end(AutoComplete *autocpl, char *autoname)
+{
+ if(autocpl->truncate[0])
+ BLI_strncpy(autoname, autocpl->truncate, autocpl->maxlen);
+ else
+ BLI_strncpy(autoname, autocpl->startname, autocpl->maxlen);
+
+ MEM_freeN(autocpl->truncate);
+ MEM_freeN(autocpl);
+}
+
+/* autocomplete callback for ID buttons */
+static void autocomplete_id(char *str, void *arg_v)
+{
+ int blocktype= (long)arg_v;
+ ListBase *listb= wich_libbase(G.main, blocktype);
+
+ if(listb==NULL) return;
+
+ /* search if str matches the beginning of an ID struct */
+ if(str[0]) {
+ AutoComplete *autocpl= autocomplete_begin(str, 22);
+ ID *id;
+
+ for(id= listb->first; id; id= id->next)
+ autocomplete_do_name(autocpl, id->name+2);
+
+ autocomplete_end(autocpl, str);
+ }
+}
+
+static uiBut *uiDefButBit(uiBlock *block, int type, int bit, int retval, char *str, short x1, short y1, short x2, short y2, void *poin, float min, float max, float a1, float a2, char *tip)
+{
+ int bitIdx= findBitIndex(bit);
+ if (bitIdx==-1) {
+ return NULL;
+ } else {
+ return uiDefBut(block, type|BIT|bitIdx, retval, str, x1, y1, x2, y2, poin, min, max, a1, a2, tip);
+ }
+}
+uiBut *uiDefButF(uiBlock *block, int type, int retval, char *str, short x1, short y1, short x2, short y2, float *poin, float min, float max, float a1, float a2, char *tip)
+{
+ return uiDefBut(block, type|FLO, retval, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
+}
+uiBut *uiDefButBitF(uiBlock *block, int type, int bit, int retval, char *str, short x1, short y1, short x2, short y2, float *poin, float min, float max, float a1, float a2, char *tip)
+{
+ return uiDefButBit(block, type|FLO, bit, retval, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
+}
+uiBut *uiDefButI(uiBlock *block, int type, int retval, char *str, short x1, short y1, short x2, short y2, int *poin, float min, float max, float a1, float a2, char *tip)
+{
+ return uiDefBut(block, type|INT, retval, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
+}
+uiBut *uiDefButBitI(uiBlock *block, int type, int bit, int retval, char *str, short x1, short y1, short x2, short y2, int *poin, float min, float max, float a1, float a2, char *tip)
+{
+ return uiDefButBit(block, type|INT, bit, retval, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
+}
+uiBut *uiDefButS(uiBlock *block, int type, int retval, char *str, short x1, short y1, short x2, short y2, short *poin, float min, float max, float a1, float a2, char *tip)
+{
+ return uiDefBut(block, type|SHO, retval, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
+}
+uiBut *uiDefButBitS(uiBlock *block, int type, int bit, int retval, char *str, short x1, short y1, short x2, short y2, short *poin, float min, float max, float a1, float a2, char *tip)
+{
+ return uiDefButBit(block, type|SHO, bit, retval, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
+}
+uiBut *uiDefButC(uiBlock *block, int type, int retval, char *str, short x1, short y1, short x2, short y2, char *poin, float min, float max, float a1, float a2, char *tip)
+{
+ return uiDefBut(block, type|CHA, retval, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
+}
+uiBut *uiDefButBitC(uiBlock *block, int type, int bit, int retval, char *str, short x1, short y1, short x2, short y2, char *poin, float min, float max, float a1, float a2, char *tip)
+{
+ return uiDefButBit(block, type|CHA, bit, retval, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
+}
+
+uiBut *uiDefIconBut(uiBlock *block, int type, int retval, int icon, short x1, short y1, short x2, short y2, void *poin, float min, float max, float a1, float a2, char *tip)
+{
+ uiBut *but= ui_def_but(block, type, retval, "", x1, y1, x2, y2, poin, min, max, a1, a2, tip);
+
+ but->icon= (BIFIconID) icon;
+ but->flag|= UI_HAS_ICON;
+
+ ui_check_but(but);
+
+ return but;
+}
+static uiBut *uiDefIconButBit(uiBlock *block, int type, int bit, int retval, int icon, short x1, short y1, short x2, short y2, void *poin, float min, float max, float a1, float a2, char *tip)
+{
+ int bitIdx= findBitIndex(bit);
+ if (bitIdx==-1) {
+ return NULL;
+ } else {
+ return uiDefIconBut(block, type|BIT|bitIdx, retval, icon, x1, y1, x2, y2, poin, min, max, a1, a2, tip);
+ }
+}
+
+uiBut *uiDefIconButF(uiBlock *block, int type, int retval, int icon, short x1, short y1, short x2, short y2, float *poin, float min, float max, float a1, float a2, char *tip)
+{
+ return uiDefIconBut(block, type|FLO, retval, icon, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
+}
+uiBut *uiDefIconButBitF(uiBlock *block, int type, int bit, int retval, int icon, short x1, short y1, short x2, short y2, float *poin, float min, float max, float a1, float a2, char *tip)
+{
+ return uiDefIconButBit(block, type|FLO, bit, retval, icon, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
+}
+uiBut *uiDefIconButI(uiBlock *block, int type, int retval, int icon, short x1, short y1, short x2, short y2, int *poin, float min, float max, float a1, float a2, char *tip)
+{
+ return uiDefIconBut(block, type|INT, retval, icon, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
+}
+uiBut *uiDefIconButBitI(uiBlock *block, int type, int bit, int retval, int icon, short x1, short y1, short x2, short y2, int *poin, float min, float max, float a1, float a2, char *tip)
+{
+ return uiDefIconButBit(block, type|INT, bit, retval, icon, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
+}
+uiBut *uiDefIconButS(uiBlock *block, int type, int retval, int icon, short x1, short y1, short x2, short y2, short *poin, float min, float max, float a1, float a2, char *tip)
+{
+ return uiDefIconBut(block, type|SHO, retval, icon, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
+}
+uiBut *uiDefIconButBitS(uiBlock *block, int type, int bit, int retval, int icon, short x1, short y1, short x2, short y2, short *poin, float min, float max, float a1, float a2, char *tip)
+{
+ return uiDefIconButBit(block, type|SHO, bit, retval, icon, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
+}
+uiBut *uiDefIconButC(uiBlock *block, int type, int retval, int icon, short x1, short y1, short x2, short y2, char *poin, float min, float max, float a1, float a2, char *tip)
+{
+ return uiDefIconBut(block, type|CHA, retval, icon, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
+}
+uiBut *uiDefIconButBitC(uiBlock *block, int type, int bit, int retval, int icon, short x1, short y1, short x2, short y2, char *poin, float min, float max, float a1, float a2, char *tip)
+{
+ return uiDefIconButBit(block, type|CHA, bit, retval, icon, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
+}
+
+/* Button containing both string label and icon */
+uiBut *uiDefIconTextBut(uiBlock *block, int type, int retval, int icon, char *str, short x1, short y1, short x2, short y2, void *poin, float min, float max, float a1, float a2, char *tip)
+{
+ uiBut *but= ui_def_but(block, type, retval, str, x1, y1, x2, y2, poin, min, max, a1, a2, tip);
+
+ but->icon= (BIFIconID) icon;
+ but->flag|= UI_HAS_ICON;
+
+ but->flag|= UI_ICON_LEFT;
+
+ ui_check_but(but);
+
+ return but;
+}
+static uiBut *uiDefIconTextButBit(uiBlock *block, int type, int bit, int retval, int icon, char *str, short x1, short y1, short x2, short y2, void *poin, float min, float max, float a1, float a2, char *tip)
+{
+ int bitIdx= findBitIndex(bit);
+ if (bitIdx==-1) {
+ return NULL;
+ } else {
+ return uiDefIconTextBut(block, type|BIT|bitIdx, retval, icon, str, x1, y1, x2, y2, poin, min, max, a1, a2, tip);
+ }
+}
+
+uiBut *uiDefIconTextButF(uiBlock *block, int type, int retval, int icon, char *str, short x1, short y1, short x2, short y2, float *poin, float min, float max, float a1, float a2, char *tip)
+{
+ return uiDefIconTextBut(block, type|FLO, retval, icon, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
+}
+uiBut *uiDefIconTextButBitF(uiBlock *block, int type, int bit, int retval, int icon, char *str, short x1, short y1, short x2, short y2, float *poin, float min, float max, float a1, float a2, char *tip)
+{
+ return uiDefIconTextButBit(block, type|FLO, bit, retval, icon, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
+}
+uiBut *uiDefIconTextButI(uiBlock *block, int type, int retval, int icon, char *str, short x1, short y1, short x2, short y2, int *poin, float min, float max, float a1, float a2, char *tip)
+{
+ return uiDefIconTextBut(block, type|INT, retval, icon, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
+}
+uiBut *uiDefIconTextButBitI(uiBlock *block, int type, int bit, int retval, int icon, char *str, short x1, short y1, short x2, short y2, int *poin, float min, float max, float a1, float a2, char *tip)
+{
+ return uiDefIconTextButBit(block, type|INT, bit, retval, icon, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
+}
+uiBut *uiDefIconTextButS(uiBlock *block, int type, int retval, int icon, char *str, short x1, short y1, short x2, short y2, short *poin, float min, float max, float a1, float a2, char *tip)
+{
+ return uiDefIconTextBut(block, type|SHO, retval, icon, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
+}
+uiBut *uiDefIconTextButBitS(uiBlock *block, int type, int bit, int retval, int icon, char *str, short x1, short y1, short x2, short y2, short *poin, float min, float max, float a1, float a2, char *tip)
+{
+ return uiDefIconTextButBit(block, type|SHO, bit, retval, icon, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
+}
+uiBut *uiDefIconTextButC(uiBlock *block, int type, int retval, int icon, char *str, short x1, short y1, short x2, short y2, char *poin, float min, float max, float a1, float a2, char *tip)
+{
+ return uiDefIconTextBut(block, type|CHA, retval, icon, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
+}
+uiBut *uiDefIconTextButBitC(uiBlock *block, int type, int bit, int retval, int icon, char *str, short x1, short y1, short x2, short y2, char *poin, float min, float max, float a1, float a2, char *tip)
+{
+ return uiDefIconTextButBit(block, type|CHA, bit, retval, icon, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
+}
+
+/* END Button containing both string label and icon */
+
+void uiAutoBlock(uiBlock *block, float minx, float miny, float sizex, float sizey, int flag)
+{
+ block->minx= minx;
+ block->maxx= minx+sizex;
+ block->miny= miny;
+ block->maxy= miny+sizey;
+
+ block->autofill= flag; /* also check for if it has to be done */
+
+}
+
+void uiSetButLink(uiBut *but, void **poin, void ***ppoin, short *tot, int from, int to)
+{
+ uiLink *link;
+
+ link= but->link= MEM_callocN(sizeof(uiLink), "new uilink");
+
+ link->poin= poin;
+ link->ppoin= ppoin;
+ link->totlink= tot;
+ link->fromcode= from;
+ link->tocode= to;
+}
+
+/* cruft to make uiBlock and uiBut private */
+
+int uiBlocksGetYMin(ListBase *lb)
+{
+ uiBlock *block;
+ int min= 0;
+
+ for (block= lb->first; block; block= block->next)
+ if (block==lb->first || block->miny<min)
+ min= block->miny;
+
+ return min;
+}
+
+int uiBlockGetCol(uiBlock *block)
+{
+ return block->themecol;
+}
+void uiBlockSetCol(uiBlock *block, int col)
+{
+ block->themecol= col;
+}
+void uiBlockSetEmboss(uiBlock *block, int emboss)
+{
+ block->dt= emboss;
+}
+void uiBlockSetDirection(uiBlock *block, int direction)
+{
+ block->direction= direction;
+}
+
+/* this call escapes if there's alignment flags */
+void uiBlockFlipOrder(uiBlock *block)
+{
+ ListBase lb;
+ uiBut *but, *next;
+ float centy, miny=10000, maxy= -10000;
+
+// if(U.uiflag & USER_PLAINMENUS)
+// return;
+
+ for(but= block->buttons.first; but; but= but->next) {
+ if(but->flag & UI_BUT_ALIGN) return;
+ if(but->y1 < miny) miny= but->y1;
+ if(but->y2 > maxy) maxy= but->y2;
+ }
+ /* mirror trick */
+ centy= (miny+maxy)/2.0;
+ for(but= block->buttons.first; but; but= but->next) {
+ but->y1 = centy-(but->y1-centy);
+ but->y2 = centy-(but->y2-centy);
+ SWAP(float, but->y1, but->y2);
+ }
+
+ /* also flip order in block itself, for example for arrowkey */
+ lb.first= lb.last= NULL;
+ but= block->buttons.first;
+ while(but) {
+ next= but->next;
+ BLI_remlink(&block->buttons, but);
+ BLI_addtail(&lb, but);
+ but= next;
+ }
+ block->buttons= lb;
+}
+
+
+void uiBlockSetFlag(uiBlock *block, int flag)
+{
+ block->flag= flag;
+}
+void uiBlockSetXOfs(uiBlock *block, int xofs)
+{
+ block->xofs= xofs;
+}
+void* uiBlockGetCurFont(uiBlock *block)
+{
+ return block->curfont;
+}
+
+void uiButSetFlag(uiBut *but, int flag)
+{
+ but->flag|= flag;
+}
+void uiButClearFlag(uiBut *but, int flag)
+{
+ but->flag&= ~flag;
+}
+
+int uiButGetRetVal(uiBut *but)
+{
+ return but->retval;
+}
+
+
+void uiBlockSetButmFunc(uiBlock *block, void (*menufunc)(void *arg, int event), void *arg)
+{
+ block->butm_func= menufunc;
+ block->butm_func_arg= arg;
+}
+
+void uiBlockSetFunc(uiBlock *block, void (*func)(void *arg1, void *arg2), void *arg1, void *arg2)
+{
+ block->func= func;
+ block->func_arg1= arg1;
+ block->func_arg2= arg2;
+}
+
+void uiBlockSetDrawExtraFunc(uiBlock *block, void (*func)())
+{
+ block->drawextra= func;
+}
+
+void uiButSetFunc(uiBut *but, void (*func)(void *arg1, void *arg2), void *arg1, void *arg2)
+{
+ but->func= func;
+ but->func_arg1= arg1;
+ but->func_arg2= arg2;
+}
+
+void uiButSetCompleteFunc(uiBut *but, void (*func)(char *str, void *arg), void *arg)
+{
+ but->autocomplete_func= func;
+ but->autofunc_arg= arg;
+}
+
+
+uiBut *uiDefIDPoinBut(uiBlock *block, uiIDPoinFuncFP func, short blocktype, int retval, char *str, short x1, short y1, short x2, short y2, void *idpp, char *tip)
+{
+ uiBut *but= ui_def_but(block, IDPOIN, retval, str, x1, y1, x2, y2, NULL, 0.0, 0.0, 0.0, 0.0, tip);
+ but->idpoin_func= func;
+ but->idpoin_idpp= (ID**) idpp;
+ ui_check_but(but);
+
+ if(blocktype)
+ uiButSetCompleteFunc(but, autocomplete_id, (void *)(long)blocktype);
+
+ return but;
+}
+
+uiBut *uiDefBlockBut(uiBlock *block, uiBlockFuncFP func, void *arg, char *str, short x1, short y1, short x2, short y2, char *tip)
+{
+ uiBut *but= ui_def_but(block, BLOCK, 0, str, x1, y1, x2, y2, arg, 0.0, 0.0, 0.0, 0.0, tip);
+ but->block_func= func;
+ ui_check_but(but);
+ return but;
+}
+
+uiBut *uiDefPulldownBut(uiBlock *block, uiBlockFuncFP func, void *arg, char *str, short x1, short y1, short x2, short y2, char *tip)
+{
+ uiBut *but= ui_def_but(block, PULLDOWN, 0, str, x1, y1, x2, y2, arg, 0.0, 0.0, 0.0, 0.0, tip);
+ but->block_func= func;
+ ui_check_but(but);
+ return but;
+}
+
+/* Block button containing both string label and icon */
+uiBut *uiDefIconTextBlockBut(uiBlock *block, uiBlockFuncFP func, void *arg, int icon, char *str, short x1, short y1, short x2, short y2, char *tip)
+{
+ uiBut *but= ui_def_but(block, BLOCK, 0, str, x1, y1, x2, y2, arg, 0.0, 0.0, 0.0, 0.0, tip);
+
+ but->icon= (BIFIconID) icon;
+ but->flag|= UI_HAS_ICON;
+
+ but->flag|= UI_ICON_LEFT;
+ but->flag|= UI_ICON_RIGHT;
+
+ but->block_func= func;
+ ui_check_but(but);
+
+ return but;
+}
+
+/* Block button containing icon */
+uiBut *uiDefIconBlockBut(uiBlock *block, uiBlockFuncFP func, void *arg, int retval, int icon, short x1, short y1, short x2, short y2, char *tip)
+{
+ uiBut *but= ui_def_but(block, BLOCK, retval, "", x1, y1, x2, y2, arg, 0.0, 0.0, 0.0, 0.0, tip);
+
+ but->icon= (BIFIconID) icon;
+ but->flag|= UI_HAS_ICON;
+
+ but->flag|= UI_ICON_LEFT;
+ but->flag|= UI_ICON_RIGHT;
+
+ but->block_func= func;
+ ui_check_but(but);
+
+ return but;
+}
+
+void uiDefKeyevtButS(uiBlock *block, int retval, char *str, short x1, short y1, short x2, short y2, short *spoin, char *tip)
+{
+ uiBut *but= ui_def_but(block, KEYEVT|SHO, retval, str, x1, y1, x2, y2, spoin, 0.0, 0.0, 0.0, 0.0, tip);
+ ui_check_but(but);
+}
+
+/* ******************** PUPmenu ****************** */
+
+static int pupmenu_set= 0;
+
+void pupmenu_set_active(int val)
+{
+ pupmenu_set= val;
+}
+
+/* value== -1 read, otherwise set */
+static int pupmenu_memory(char *str, int value)
+{
+ static char mem[256], first=1;
+ int val=0, nr=0;
+
+ if(first) {
+ memset(mem, 0, 256);
+ first= 0;
+ }
+ while(str[nr]) {
+ val+= str[nr];
+ nr++;
+ }
+
+ if(value >= 0) mem[ val & 255 ]= value;
+ else return mem[ val & 255 ];
+
+ return 0;
+}
+
+#define PUP_LABELH 6
+short pupmenu(char *instr)
+{
+ uiBlock *block;
+ ListBase listb= {NULL, NULL};
+ int event;
+ short lastselected, width, height=0, mousexmove = 0, mouseymove, xmax, ymax, mval[2], val= -1;
+ short a, startx, starty, endx, endy, boxh=TBOXH, x1, y1;
+ MenuData *md;
+
+ /* block stuff first, need to know the font */
+ block= uiNewBlock(&listb, "menu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetFlag(block, UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_RET_1|UI_BLOCK_NUMSELECT);
+ block->themecol= TH_MENU_ITEM;
+
+ md= decompose_menu_string(instr);
+
+ /* size and location, title slightly bigger for bold */
+ if(md->title) width= 2*strlen(md->title)+BIF_GetStringWidth(uiBlockGetCurFont(block), md->title, (U.transopts & USER_TR_BUTTONS));
+ else width= 0;
+ for(a=0; a<md->nitems; a++) {
+ char *name= md->items[a].str;
+
+ xmax= BIF_GetStringWidth(uiBlockGetCurFont(block), md->items[a].str, (U.transopts & USER_TR_BUTTONS));
+ if(xmax>width) width= xmax;
+
+ if( strcmp(name, "%l")==0) height+= PUP_LABELH;
+ else height+= boxh;
+ }
+
+ width+= 10;
+
+ xmax = G.curscreen->sizex;
+ ymax = G.curscreen->sizey;
+
+ getmouseco_sc(mval);
+
+ /* set first item */
+ lastselected= 0;
+ if(pupmenu_set) {
+ lastselected= pupmenu_set-1;
+ pupmenu_set= 0;
+ }
+ else if(md->nitems>1) {
+ lastselected= pupmenu_memory(instr, -1);
+ }
+
+ startx= mval[0]-(0.8*(width));
+ starty= mval[1]-height+boxh/2;
+ if(lastselected>=0 && lastselected<md->nitems) {
+ for(a=0; a<md->nitems; a++) {
+ if(a==lastselected) break;
+ if( strcmp(md->items[a].str, "%l")==0) starty+= PUP_LABELH;
+ else starty+=boxh;
+ }
+
+ //starty= mval[1]-height+boxh/2+lastselected*boxh;
+ }
+
+ mouseymove= 0;
+
+ if(startx<10) startx= 10;
+ if(starty<10) {
+ mouseymove= 10-starty;
+ starty= 10;
+ }
+
+ endx= startx+width;
+ endy= starty+height;
+ if(endx>xmax) {
+ endx= xmax-10;
+ startx= endx-width;
+ }
+ if(endy>ymax-20) {
+ mouseymove= ymax-endy-20;
+ endy= ymax-20;
+ starty= endy-height;
+
+ }
+
+ if(mouseymove) {
+ ui_warp_pointer(mval[0], mouseymove+mval[1]);
+ mousexmove= mval[0];
+ mouseymove= mval[1];
+ }
+
+ /* here we go! */
+ if(md->title) {
+ uiBut *bt;
+ char titlestr[256];
+ uiSetCurFont(block, UI_HELVB);
+
+ if (md->titleicon) {
+ width+= 20;
+ sprintf(titlestr, " %s", md->title);
+ uiDefIconTextBut(block, LABEL, 0, md->titleicon, titlestr, startx, (short)(starty+height), width, boxh, NULL, 0.0, 0.0, 0, 0, "");
+ } else {
+ bt= uiDefBut(block, LABEL, 0, md->title, startx, (short)(starty+height), width, boxh, NULL, 0.0, 0.0, 0, 0, "");
+ bt->flag= UI_TEXT_LEFT;
+ }
+ uiSetCurFont(block, UI_HELV);
+ }
+
+ y1= starty + height - boxh;
+ x1= startx;
+
+ for(a=0; a<md->nitems; a++) {
+ char *name= md->items[a].str;
+
+ if( strcmp(name, "%l")==0) {
+ uiDefBut(block, SEPR, B_NOP, "", x1, y1, width, PUP_LABELH, NULL, 0, 0.0, 0, 0, "");
+ y1 -= PUP_LABELH;
+ }
+ else {
+ uiDefButS(block, BUTM, B_NOP, name, x1, y1, width, boxh-1, &val, (float) md->items[a].retval, 0.0, 0, 0, "");
+ y1 -= boxh;
+ }
+ }
+
+ uiBoundsBlock(block, 1);
+
+ event= uiDoBlocks(&listb, 0);
+
+ /* calculate last selected */
+ if(event & UI_RETURN_OK) {
+ lastselected= 0;
+ for(a=0; a<md->nitems; a++) {
+ if(val==md->items[a].retval) lastselected= a;
+ }
+
+ pupmenu_memory(instr, lastselected);
+ }
+ menudata_free(md);
+
+ if(mouseymove && (event & UI_RETURN_OUT)==0) ui_warp_pointer(mousexmove, mouseymove);
+ return val;
+}
+
+short pupmenu_col(char *instr, int maxrow)
+{
+ uiBlock *block;
+ ListBase listb= {NULL, NULL};
+ int columns, rows;
+ short mousemove[2], mval[2], event;
+ int width, height, xmax, ymax, val= -1;
+ int a, startx, starty, endx, endy, boxh=TBOXH, x1, y1;
+ MenuData *md;
+
+ block= uiNewBlock(&listb, "menu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetFlag(block, UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_RET_1|UI_BLOCK_NUMSELECT);
+ block->themecol= TH_MENU_ITEM;
+
+ md= decompose_menu_string(instr);
+
+ /* collumns and row calculation */
+ columns= (md->nitems+maxrow)/maxrow;
+ if (columns<1) columns= 1;
+
+ if(columns > 8) {
+ maxrow += 5;
+ columns= (md->nitems+maxrow)/maxrow;
+ }
+
+ rows= (int) md->nitems/columns;
+ if (rows<1) rows= 1;
+
+ while (rows*columns<(md->nitems+columns) ) rows++;
+
+ /* size and location */
+ if(md->title) {
+ width= 2*strlen(md->title)+BIF_GetStringWidth(uiBlockGetCurFont(block), md->title, (U.transopts & USER_TR_BUTTONS));
+ width /= columns;
+ }
+ else width= 0;
+
+ for(a=0; a<md->nitems; a++) {
+ xmax= BIF_GetStringWidth(uiBlockGetCurFont(block), md->items[a].str, (U.transopts & USER_TR_BUTTONS));
+ if(xmax>width) width= xmax;
+ }
+
+ width+= 10;
+ if (width<50) width=50;
+
+ boxh= TBOXH;
+
+ height= rows*boxh;
+ if (md->title) height+= boxh;
+
+ xmax = G.curscreen->sizex;
+ ymax = G.curscreen->sizey;
+
+ getmouseco_sc(mval);
+
+ /* find active item */
+#if 0
+ fvalue= ui_get_but_val(but);
+ for(a=0; a<md->nitems; a++) {
+ if( md->items[a].retval== (int)fvalue ) break;
+ }
+#endif
+ /* no active item? */
+ if(a==md->nitems) {
+ if(md->title) a= -1;
+ else a= 0;
+ }
+
+ if(a>0)
+ startx = mval[0]-width/2 - ((int)(a)/rows)*width;
+ else
+ startx= mval[0]-width/2;
+ starty = mval[1]-height + boxh/2 + ((a)%rows)*boxh;
+
+ if (md->title) starty+= boxh;
+
+ mousemove[0]= mousemove[1]= 0;
+
+ if(startx<10) {
+ mousemove[0]= 10-startx;
+ startx= 10;
+ }
+ if(starty<10) {
+ mousemove[1]= 10-starty;
+ starty= 10;
+ }
+
+ endx= startx+width*columns;
+ endy= starty+height;
+
+ if(endx>xmax) {
+ mousemove[0]= xmax-endx-10;
+ endx= xmax-10;
+ startx= endx-width*columns;
+ }
+ if(endy>ymax) {
+ mousemove[1]= ymax-endy-10;
+ endy= ymax-10;
+ starty= endy-height;
+ }
+
+ ui_warp_pointer(mval[0]+mousemove[0], mval[1]+mousemove[1]);
+
+ mousemove[0]= mval[0];
+ mousemove[1]= mval[1];
+
+ /* here we go! */
+
+ if(md->title) {
+ uiBut *bt;
+ uiSetCurFont(block, UI_HELVB);
+ bt= uiDefBut(block, LABEL, 0, md->title, startx, (short)(starty+rows*boxh), columns*(short)width, (short)boxh, NULL, 0.0, 0.0, 0, 0, "");
+ uiSetCurFont(block, UI_HELV);
+ bt->flag= UI_TEXT_LEFT;
+ }
+
+ for(a=0; a<md->nitems; a++) {
+ char *name= md->items[a].str;
+
+ int icon = md->items[a].icon;
+
+ x1= startx + width*((int)a/rows);
+ y1= starty - boxh*(a%rows) + (rows-1)*boxh;
+
+ if( strcmp(name, "%l")==0){
+ uiDefBut(block, SEPR, B_NOP, "", x1, y1, width, PUP_LABELH, NULL, 0, 0.0, 0, 0, "");
+ y1 -= PUP_LABELH;
+ }
+ else if (icon) {
+ uiDefIconButI(block, BUTM, B_NOP, icon, x1, y1, width+16, boxh-1, &val, (float) md->items[a].retval, 0.0, 0, 0, "");
+ y1 -= boxh;
+ }
+ else {
+ uiDefButI(block, BUTM, B_NOP, name, x1, y1, width, boxh-1, &val, (float) md->items[a].retval, 0.0, 0, 0, "");
+ y1 -= boxh;
+ }
+ //uiDefButI(block, BUTM, B_NOP, md->items[a].str, x1, y1, (short)(width-(rows>1)), (short)(boxh-1), &val, (float)md->items[a].retval, 0.0, 0, 0, "");
+ }
+
+ uiBoundsBlock(block, 1);
+
+ event= uiDoBlocks(&listb, 0);
+
+ menudata_free(md);
+
+ if((event & UI_RETURN_OUT)==0) ui_warp_pointer(mousemove[0], mousemove[1]);
+
+ return val;
+}
+
diff --git a/source/blender/src/interface_draw.c b/source/blender/src/interface_draw.c
new file mode 100644
index 00000000000..4f1d5056111
--- /dev/null
+++ b/source/blender/src/interface_draw.c
@@ -0,0 +1,2467 @@
+
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/*
+ a full doc with API notes can be found in bf-blender/blender/doc/interface_API.txt
+
+ */
+
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifndef WIN32
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "PIL_time.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "DNA_color_types.h"
+#include "DNA_key_types.h"
+#include "DNA_packedFile_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_vec_types.h"
+#include "DNA_vfont_types.h"
+
+#include "BKE_blender.h"
+#include "BKE_colortools.h"
+#include "BKE_font.h"
+#include "BKE_global.h"
+#include "BKE_key.h"
+#include "BKE_utildefines.h"
+
+#include "datatoc.h" /* std font */
+
+#include "BIF_gl.h"
+#include "BIF_graphics.h"
+#include "BIF_keyval.h"
+#include "BIF_mainqueue.h"
+
+#include "BIF_screen.h"
+#include "BIF_toolbox.h"
+#include "BIF_mywindow.h"
+#include "BIF_space.h"
+#include "BIF_glutil.h"
+#include "BIF_interface.h"
+#include "BIF_interface_icons.h"
+#include "BIF_butspace.h"
+#include "BIF_language.h"
+
+#include "BSE_view.h"
+
+#ifdef INTERNATIONAL
+#include "FTF_Api.h"
+#endif
+
+#include "mydevice.h"
+#include "interface.h"
+#include "blendef.h"
+
+// globals
+extern float UIwinmat[4][4];
+
+
+/* ************** safe rasterpos for pixmap alignment with pixels ************* */
+
+void ui_rasterpos_safe(float x, float y, float aspect)
+{
+ float vals[4], remainder;
+ int doit=0;
+
+ glRasterPos2f(x, y);
+ glGetFloatv(GL_CURRENT_RASTER_POSITION, vals);
+
+ remainder= vals[0] - floor(vals[0]);
+ if(remainder > 0.4 && remainder < 0.6) {
+ if(remainder < 0.5) x -= 0.1*aspect;
+ else x += 0.1*aspect;
+ doit= 1;
+ }
+ remainder= vals[1] - floor(vals[1]);
+ if(remainder > 0.4 && remainder < 0.6) {
+ if(remainder < 0.5) y -= 0.1*aspect;
+ else y += 0.1*aspect;
+ doit= 1;
+ }
+
+ if(doit) glRasterPos2f(x, y);
+
+ BIF_RasterPos(x, y);
+ BIF_SetScale(aspect);
+}
+
+/* ************** generic embossed rect, for window sliders etc ************* */
+
+void uiEmboss(float x1, float y1, float x2, float y2, int sel)
+{
+
+ /* below */
+ if(sel) glColor3ub(200,200,200);
+ else glColor3ub(50,50,50);
+ fdrawline(x1, y1, x2, y1);
+
+ /* right */
+ fdrawline(x2, y1, x2, y2);
+
+ /* top */
+ if(sel) glColor3ub(50,50,50);
+ else glColor3ub(200,200,200);
+ fdrawline(x1, y2, x2, y2);
+
+ /* left */
+ fdrawline(x1, y1, x1, y2);
+
+}
+
+/* ************** GENERIC ICON DRAW, NO THEME HERE ************* */
+
+/* icons have been standardized... and this call draws in untransformed coordinates */
+#define ICON_HEIGHT 16.0f
+
+static void ui_draw_icon(uiBut *but, BIFIconID icon, int blend)
+{
+ float xs=0, ys=0, aspect, height;
+
+ /* this icon doesn't need draw... */
+ if(icon==ICON_BLANK1) return;
+
+ /* we need aspect from block, for menus... these buttons are scaled in uiPositionBlock() */
+ aspect= but->block->aspect;
+ if(aspect != but->aspect) {
+ /* prevent scaling up icon in pupmenu */
+ if (aspect < 1.0f) {
+ height= ICON_HEIGHT;
+ aspect = 1.0f;
+
+ }
+ else
+ height= ICON_HEIGHT/aspect;
+ }
+ else
+ height= ICON_HEIGHT;
+
+ if(but->flag & UI_ICON_LEFT) {
+ if (but->type==BUT_TOGDUAL && but->drawstr[0]) {
+ xs= but->x1-1.0;
+ }
+ else if (but->type==BUTM ) {
+ xs= but->x1+1.0;
+ }
+ else if ((but->type==ICONROW) || (but->type==ICONTEXTROW)) {
+ xs= but->x1+3.0;
+ }
+ else {
+ xs= but->x1+4.0;
+ }
+ ys= (but->y1+but->y2- height)/2.0;
+ }
+ if(but->flag & UI_ICON_RIGHT) {
+ xs= but->x2-17.0;
+ ys= (but->y1+but->y2- height)/2.0;
+ }
+ if (!((but->flag & UI_ICON_RIGHT) || (but->flag & UI_ICON_LEFT))) {
+ xs= (but->x1+but->x2- height)/2.0;
+ ys= (but->y1+but->y2- height)/2.0;
+ }
+
+ glEnable(GL_BLEND);
+
+ /* calculate blend color */
+ if ELEM3(but->type, TOG, ROW, TOGN) {
+ if(but->flag & UI_SELECT);
+ else if(but->flag & UI_ACTIVE);
+ else blend= -60;
+ }
+ BIF_icon_draw_aspect_blended(xs, ys, icon, aspect, blend);
+
+ glDisable(GL_BLEND);
+
+}
+
+
+/* ************** DEFAULT THEME, SHADED BUTTONS ************* */
+
+
+#define M_WHITE BIF_ThemeColorShade(colorid, 80)
+
+#define M_ACT_LIGHT BIF_ThemeColorShade(colorid, 55)
+#define M_LIGHT BIF_ThemeColorShade(colorid, 45)
+#define M_HILITE BIF_ThemeColorShade(colorid, 25)
+#define M_LMEDIUM BIF_ThemeColorShade(colorid, 10)
+#define M_MEDIUM BIF_ThemeColor(colorid)
+#define M_LGREY BIF_ThemeColorShade(colorid, -20)
+#define M_GREY BIF_ThemeColorShade(colorid, -45)
+#define M_DARK BIF_ThemeColorShade(colorid, -80)
+
+#define M_NUMTEXT BIF_ThemeColorShade(colorid, 25)
+#define M_NUMTEXT_ACT_LIGHT BIF_ThemeColorShade(colorid, 35)
+
+#define MM_WHITE BIF_ThemeColorShade(TH_BUT_NEUTRAL, 120)
+
+/* Used for the subtle sunken effect around buttons.
+ * One option is to hardcode to white, with alpha, however it causes a
+ * weird 'building up' efect, so it's commented out for now.
+ */
+
+/*
+#define MM_WHITE_OP glColor4ub(255, 255, 255, 60)
+#define MM_WHITE_TR glColor4ub(255, 255, 255, 0)
+ */
+
+#define MM_WHITE_OP BIF_ThemeColorShadeAlpha(TH_BACK, 55, -100)
+#define MM_WHITE_TR BIF_ThemeColorShadeAlpha(TH_BACK, 55, -255)
+
+#define MM_LIGHT BIF_ThemeColorShade(TH_BUT_OUTLINE, 45)
+#define MM_MEDIUM BIF_ThemeColor(TH_BUT_OUTLINE)
+#define MM_GREY BIF_ThemeColorShade(TH_BUT_OUTLINE, -45)
+#define MM_DARK BIF_ThemeColorShade(TH_BUT_OUTLINE, -80)
+
+/* base shaded button */
+static void shaded_button(float x1, float y1, float x2, float y2, float asp, int colorid, int flag, int mid)
+{
+ /* 'mid' arg determines whether the button is in the middle of
+ * an alignment group or not. 0 = not middle, 1 = is in the middle.
+ * Done to allow cleaner drawing
+ */
+
+ /* *** SHADED BUTTON BASE *** */
+ glShadeModel(GL_SMOOTH);
+ glBegin(GL_QUADS);
+
+ if(flag & UI_SELECT) {
+ if(flag & UI_ACTIVE) M_MEDIUM;
+ else M_LGREY;
+ } else {
+ if(flag & UI_ACTIVE) M_LIGHT;
+ else M_HILITE;
+ }
+
+ glVertex2f(x1,y1);
+ glVertex2f(x2,y1);
+
+ if(flag & UI_SELECT) {
+ if(flag & UI_ACTIVE) M_LGREY;
+ else M_GREY;
+ } else {
+ if(flag & UI_ACTIVE) M_ACT_LIGHT;
+ else M_LIGHT;
+ }
+
+ glVertex2f(x2,(y2-(y2-y1)/3));
+ glVertex2f(x1,(y2-(y2-y1)/3));
+ glEnd();
+
+
+ glShadeModel(GL_FLAT);
+ glBegin(GL_QUADS);
+
+ if(flag & UI_SELECT) {
+ if(flag & UI_ACTIVE) M_LGREY;
+ else M_GREY;
+ } else {
+ if(flag & UI_ACTIVE) M_ACT_LIGHT;
+ else M_LIGHT;
+ }
+
+ glVertex2f(x1,(y2-(y2-y1)/3));
+ glVertex2f(x2,(y2-(y2-y1)/3));
+ glVertex2f(x2,y2);
+ glVertex2f(x1,y2);
+
+ glEnd();
+ /* *** END SHADED BUTTON BASE *** */
+
+ /* *** INNER OUTLINE *** */
+ /* left */
+ if(!(flag & UI_SELECT)) {
+ glShadeModel(GL_SMOOTH);
+ glBegin(GL_LINES);
+ M_MEDIUM;
+ glVertex2f(x1+1,y1+2);
+ M_WHITE;
+ glVertex2f(x1+1,y2);
+ glEnd();
+ }
+
+ /* right */
+ if(!(flag & UI_SELECT)) {
+ glShadeModel(GL_SMOOTH);
+ glBegin(GL_LINES);
+ M_MEDIUM;
+ glVertex2f(x2-1,y1+2);
+ M_WHITE;
+ glVertex2f(x2-1,y2);
+ glEnd();
+ }
+
+ glShadeModel(GL_FLAT);
+
+ /* top */
+ if(flag & UI_SELECT) {
+ if(flag & UI_ACTIVE) M_LGREY;
+ else M_GREY;
+ } else {
+ if(flag & UI_ACTIVE) M_WHITE;
+ else M_WHITE;
+ }
+
+ fdrawline(x1, (y2-1), x2, (y2-1));
+
+ /* bottom */
+ if(flag & UI_SELECT) {
+ if(flag & UI_ACTIVE) M_MEDIUM;
+ else M_LGREY;
+ } else {
+ if(flag & UI_ACTIVE) M_LMEDIUM;
+ else M_MEDIUM;
+ }
+ fdrawline(x1, (y1+1), x2, (y1+1));
+ /* *** END INNER OUTLINE *** */
+
+ /* *** OUTER OUTLINE *** */
+ if (mid) {
+ // we draw full outline, its not AA, and it works better button mouse-over hilite
+ MM_DARK;
+
+ // left right
+ fdrawline(x1, y1, x1, y2);
+ fdrawline(x2, y1, x2, y2);
+
+ // top down
+ fdrawline(x1, y2, x2, y2);
+ fdrawline(x1, y1, x2, y1);
+ } else {
+ MM_DARK;
+ gl_round_box(GL_LINE_LOOP, x1, y1, x2, y2, 1.5);
+ }
+ /* END OUTER OUTLINE */
+}
+
+/* base flat button */
+static void flat_button(float x1, float y1, float x2, float y2, float asp, int colorid, int flag, int mid)
+{
+ /* 'mid' arg determines whether the button is in the middle of
+ * an alignment group or not. 0 = not middle, 1 = is in the middle.
+ * Done to allow cleaner drawing
+ */
+
+ /* *** FLAT TEXT/NUM FIELD *** */
+ glShadeModel(GL_FLAT);
+ if(flag & UI_SELECT) {
+ if(flag & UI_ACTIVE) M_LGREY;
+ else M_GREY;
+ }
+ else {
+ if(flag & UI_ACTIVE) M_NUMTEXT_ACT_LIGHT;
+ else M_NUMTEXT;
+ }
+
+ glRectf(x1, y1, x2, y2);
+ /* *** END FLAT TEXT/NUM FIELD *** */
+
+ /* *** OUTER OUTLINE *** */
+ if (mid) {
+ // we draw full outline, its not AA, and it works better button mouse-over hilite
+ MM_DARK;
+
+ // left right
+ fdrawline(x1, y1, x1, y2);
+ fdrawline(x2, y1, x2, y2);
+
+ // top down
+ fdrawline(x1, y2, x2, y2);
+ fdrawline(x1, y1, x2, y1);
+ } else {
+ MM_DARK;
+ gl_round_box(GL_LINE_LOOP, x1, y1, x2, y2, 1.5);
+ }
+ /* END OUTER OUTLINE */
+}
+
+/* small side double arrow for iconrow */
+static void ui_default_iconrow_arrows(float x1, float y1, float x2, float y2)
+{
+ glEnable( GL_POLYGON_SMOOTH );
+ glEnable( GL_BLEND );
+
+ glShadeModel(GL_FLAT);
+ glBegin(GL_TRIANGLES);
+ glVertex2f((short)x2-2,(short)(y2-(y2-y1)/2)+1);
+ glVertex2f((short)x2-6,(short)(y2-(y2-y1)/2)+1);
+ glVertex2f((short)x2-4,(short)(y2-(y2-y1)/2)+4);
+ glEnd();
+
+ glBegin(GL_TRIANGLES);
+ glVertex2f((short)x2-2,(short)(y2-(y2-y1)/2) -1);
+ glVertex2f((short)x2-6,(short)(y2-(y2-y1)/2) -1);
+ glVertex2f((short)x2-4,(short)(y2-(y2-y1)/2) -4);
+ glEnd();
+
+ glDisable( GL_BLEND );
+ glDisable( GL_POLYGON_SMOOTH );
+}
+
+/* side double arrow for menu */
+static void ui_default_menu_arrows(float x1, float y1, float x2, float y2)
+{
+ glEnable( GL_POLYGON_SMOOTH );
+ glEnable( GL_BLEND );
+
+ glShadeModel(GL_FLAT);
+ glBegin(GL_TRIANGLES);
+ glVertex2f((short)x2-4,(short)(y2-(y2-y1)/2)+1);
+ glVertex2f((short)x2-12,(short)(y2-(y2-y1)/2)+1);
+ glVertex2f((short)x2-8,(short)(y2-(y2-y1)/2)+4);
+ glEnd();
+
+ glBegin(GL_TRIANGLES);
+ glVertex2f((short)x2-4,(short)(y2-(y2-y1)/2) -1);
+ glVertex2f((short)x2-12,(short)(y2-(y2-y1)/2) -1);
+ glVertex2f((short)x2-8,(short)(y2-(y2-y1)/2) -4);
+ glEnd();
+
+ glDisable( GL_BLEND );
+ glDisable( GL_POLYGON_SMOOTH );
+}
+
+/* left/right arrows for number fields */
+static void ui_default_num_arrows(float x1, float y1, float x2, float y2)
+{
+ if( x2-x1 > 25) { // 25 is a bit arbitrary, but small buttons cant have arrows
+
+ glEnable( GL_POLYGON_SMOOTH );
+ glEnable( GL_BLEND );
+
+ glShadeModel(GL_FLAT);
+ glBegin(GL_TRIANGLES);
+
+ glVertex2f((short)x1+5,(short)(y2-(y2-y1)/2));
+ glVertex2f((short)x1+10,(short)(y2-(y2-y1)/2)+4);
+ glVertex2f((short)x1+10,(short)(y2-(y2-y1)/2)-4);
+ glEnd();
+
+ /* right */
+ glShadeModel(GL_FLAT);
+ glBegin(GL_TRIANGLES);
+
+ glVertex2f((short)x2-5,(short)(y2-(y2-y1)/2));
+ glVertex2f((short)x2-10,(short)(y2-(y2-y1)/2)-4);
+ glVertex2f((short)x2-10,(short)(y2-(y2-y1)/2)+4);
+ glEnd();
+
+ glDisable( GL_BLEND );
+ glDisable( GL_POLYGON_SMOOTH );
+ }
+}
+
+/* changing black/white for TOG3 buts */
+static void ui_tog3_invert(float x1, float y1, float x2, float y2, int seltype)
+{
+ short alpha = 30;
+
+ if (seltype == 0) {
+ glEnable(GL_BLEND);
+
+ glColor4ub(0, 0, 0, alpha);
+ glRectf(x2-6, y1, x2, (y1+(y2-y1)/2));
+
+ glColor4ub(255, 255, 255, alpha);
+ glRectf(x2-6, (y1+(y2-y1)/2), x2, y2);
+
+ glDisable(GL_BLEND);
+ } else {
+ glEnable(GL_BLEND);
+
+ glColor4ub(255, 255, 255, alpha);
+ glRectf(x2-6, y1, x2, (y1+(y2-y1)/2));
+
+ glColor4ub(0, 0, 0, alpha);
+ glRectf(x2-6, (y1+(y2-y1)/2), x2, y2);
+
+ glDisable(GL_BLEND);
+ }
+}
+
+/* button/popup menu/iconrow drawing code */
+static void ui_default_button(int type, int colorid, float asp, float x1, float y1, float x2, float y2, int flag)
+{
+ int align= (flag & UI_BUT_ALIGN);
+
+ if(align) {
+
+ /* *** BOTTOM OUTER SUNKEN EFFECT *** */
+ if (!((align == UI_BUT_ALIGN_DOWN) ||
+ (align == (UI_BUT_ALIGN_DOWN|UI_BUT_ALIGN_RIGHT)) ||
+ (align == (UI_BUT_ALIGN_DOWN|UI_BUT_ALIGN_LEFT)))) {
+ glEnable(GL_BLEND);
+ MM_WHITE_OP;
+ fdrawline(x1, y1-1, x2, y1-1);
+ glDisable(GL_BLEND);
+ }
+ /* *** END BOTTOM OUTER SUNKEN EFFECT *** */
+
+ switch(align) {
+ case UI_BUT_ALIGN_TOP:
+ uiSetRoundBox(12);
+
+ /* last arg in shaded_button() determines whether the button is in the middle of
+ * an alignment group or not. 0 = not middle, 1 = is in the middle.
+ * Done to allow cleaner drawing
+ */
+
+ shaded_button(x1, y1, x2, y2, asp, colorid, flag, 0);
+ break;
+ case UI_BUT_ALIGN_DOWN:
+ uiSetRoundBox(3);
+ shaded_button(x1, y1, x2, y2, asp, colorid, flag, 0);
+ break;
+ case UI_BUT_ALIGN_LEFT:
+
+ /* RIGHT OUTER SUNKEN EFFECT */
+ glEnable(GL_BLEND);
+ glShadeModel(GL_SMOOTH);
+ glBegin(GL_LINES);
+ MM_WHITE_OP;
+ glVertex2f(x2+1,y1);
+ MM_WHITE_TR;
+ glVertex2f(x2+1,y2);
+ glEnd();
+ glDisable(GL_BLEND);
+
+ uiSetRoundBox(6);
+ shaded_button(x1, y1, x2, y2, asp, colorid, flag, 0);
+ break;
+ case UI_BUT_ALIGN_RIGHT:
+
+ /* LEFT OUTER SUNKEN EFFECT */
+ glEnable(GL_BLEND);
+ glShadeModel(GL_SMOOTH);
+ glBegin(GL_LINES);
+ MM_WHITE_OP;
+ glVertex2f(x1-1,y1);
+ MM_WHITE_TR;
+ glVertex2f(x1-1,y2);
+ glEnd();
+ glDisable(GL_BLEND);
+
+ uiSetRoundBox(9);
+ shaded_button(x1, y1, x2, y2, asp, colorid, flag, 0);
+ break;
+
+ case UI_BUT_ALIGN_DOWN|UI_BUT_ALIGN_RIGHT:
+ uiSetRoundBox(1);
+ shaded_button(x1, y1, x2, y2, asp, colorid, flag, 0);
+ break;
+ case UI_BUT_ALIGN_DOWN|UI_BUT_ALIGN_LEFT:
+ uiSetRoundBox(2);
+ shaded_button(x1, y1, x2, y2, asp, colorid, flag, 0);
+ break;
+ case UI_BUT_ALIGN_TOP|UI_BUT_ALIGN_RIGHT:
+
+ /* LEFT OUTER SUNKEN EFFECT */
+ glEnable(GL_BLEND);
+ glShadeModel(GL_SMOOTH);
+ glBegin(GL_LINES);
+ MM_WHITE_OP;
+ glVertex2f(x1-1,y1);
+ MM_WHITE_TR;
+ glVertex2f(x1-1,y2);
+ glEnd();
+ glDisable(GL_BLEND);
+
+ uiSetRoundBox(8);
+ shaded_button(x1, y1, x2, y2, asp, colorid, flag, 0);
+ break;
+ case UI_BUT_ALIGN_TOP|UI_BUT_ALIGN_LEFT:
+
+ /* RIGHT OUTER SUNKEN EFFECT */
+ glEnable(GL_BLEND);
+ glShadeModel(GL_SMOOTH);
+ glBegin(GL_LINES);
+ MM_WHITE_OP;
+ glVertex2f(x2+1,y1);
+ MM_WHITE_TR;
+ glVertex2f(x2+1,y2);
+ glEnd();
+ glDisable(GL_BLEND);
+
+ uiSetRoundBox(4);
+ shaded_button(x1, y1, x2, y2, asp, colorid, flag, 0);
+ break;
+
+ default:
+ shaded_button(x1, y1, x2, y2, asp, colorid, flag, 1);
+ break;
+ }
+ }
+ else {
+ glEnable(GL_BLEND);
+ glShadeModel(GL_SMOOTH);
+
+ /* BOTTOM OUTER SUNKEN EFFECT */
+ MM_WHITE_OP;
+ fdrawline(x1, y1-1, x2, y1-1);
+
+ /* LEFT OUTER SUNKEN EFFECT */
+ glBegin(GL_LINES);
+ MM_WHITE_OP;
+ glVertex2f(x1-1,y1);
+ MM_WHITE_TR;
+ glVertex2f(x1-1,y2);
+ glEnd();
+
+ /* RIGHT OUTER SUNKEN EFFECT */
+ glBegin(GL_LINES);
+ MM_WHITE_OP;
+ glVertex2f(x2+1,y1);
+ MM_WHITE_TR;
+ glVertex2f(x2+1,y2);
+ glEnd();
+
+ glDisable(GL_BLEND);
+
+ uiSetRoundBox(15);
+ shaded_button(x1, y1, x2, y2, asp, colorid, flag, 0);
+ }
+
+ /* *** EXTRA DRAWING FOR SPECIFIC CONTROL TYPES *** */
+ switch(type) {
+ case ICONROW:
+ case ICONTEXTROW:
+ /* DARKENED AREA */
+ glEnable(GL_BLEND);
+
+ glColor4ub(0, 0, 0, 30);
+ glRectf(x2-9, y1, x2, y2);
+
+ glDisable(GL_BLEND);
+ /* END DARKENED AREA */
+
+ /* ICONROW DOUBLE-ARROW */
+ M_DARK;
+ ui_default_iconrow_arrows(x1, y1, x2, y2);
+ /* END ICONROW DOUBLE-ARROW */
+ break;
+ case MENU:
+ /* DARKENED AREA */
+ glEnable(GL_BLEND);
+
+ glColor4ub(0, 0, 0, 30);
+ glRectf(x2-18, y1, x2, y2);
+
+ glDisable(GL_BLEND);
+ /* END DARKENED AREA */
+
+ /* MENU DOUBLE-ARROW */
+ M_DARK;
+ ui_default_menu_arrows(x1, y1, x2, y2);
+ /* MENU DOUBLE-ARROW */
+ break;
+ }
+}
+
+
+/* number/text field drawing code */
+static void ui_default_flat(int type, int colorid, float asp, float x1, float y1, float x2, float y2, int flag)
+{
+ int align= (flag & UI_BUT_ALIGN);
+
+ if(align) {
+
+ /* *** BOTTOM OUTER SUNKEN EFFECT *** */
+ if (!((align == UI_BUT_ALIGN_DOWN) ||
+ (align == (UI_BUT_ALIGN_DOWN|UI_BUT_ALIGN_RIGHT)) ||
+ (align == (UI_BUT_ALIGN_DOWN|UI_BUT_ALIGN_LEFT)))) {
+ glEnable(GL_BLEND);
+ MM_WHITE_OP;
+ fdrawline(x1, y1-1, x2, y1-1);
+ glDisable(GL_BLEND);
+ }
+ /* *** END BOTTOM OUTER SUNKEN EFFECT *** */
+
+ switch(align) {
+ case UI_BUT_ALIGN_TOP:
+ uiSetRoundBox(12);
+
+ /* last arg in shaded_button() determines whether the button is in the middle of
+ * an alignment group or not. 0 = not middle, 1 = is in the middle.
+ * Done to allow cleaner drawing
+ */
+
+ flat_button(x1, y1, x2, y2, asp, colorid, flag, 0);
+ break;
+ case UI_BUT_ALIGN_DOWN:
+ uiSetRoundBox(3);
+ flat_button(x1, y1, x2, y2, asp, colorid, flag, 0);
+ break;
+ case UI_BUT_ALIGN_LEFT:
+
+ /* RIGHT OUTER SUNKEN EFFECT */
+ glEnable(GL_BLEND);
+ glShadeModel(GL_SMOOTH);
+ glBegin(GL_LINES);
+ MM_WHITE_OP;
+ glVertex2f(x2+1,y1);
+ MM_WHITE_TR;
+ glVertex2f(x2+1,y2);
+ glEnd();
+ glDisable(GL_BLEND);
+
+ uiSetRoundBox(6);
+ flat_button(x1, y1, x2, y2, asp, colorid, flag, 0);
+ break;
+ case UI_BUT_ALIGN_RIGHT:
+
+ /* LEFT OUTER SUNKEN EFFECT */
+ glEnable(GL_BLEND);
+ glShadeModel(GL_SMOOTH);
+ glBegin(GL_LINES);
+ MM_WHITE_OP;
+ glVertex2f(x1-1,y1);
+ MM_WHITE_TR;
+ glVertex2f(x1-1,y2);
+ glEnd();
+ glDisable(GL_BLEND);
+
+ uiSetRoundBox(9);
+ flat_button(x1, y1, x2, y2, asp, colorid, flag, 0);
+ break;
+
+ case UI_BUT_ALIGN_DOWN|UI_BUT_ALIGN_RIGHT:
+ uiSetRoundBox(1);
+ flat_button(x1, y1, x2, y2, asp, colorid, flag, 0);
+ break;
+ case UI_BUT_ALIGN_DOWN|UI_BUT_ALIGN_LEFT:
+ uiSetRoundBox(2);
+ flat_button(x1, y1, x2, y2, asp, colorid, flag, 0);
+ break;
+ case UI_BUT_ALIGN_TOP|UI_BUT_ALIGN_RIGHT:
+
+ /* LEFT OUTER SUNKEN EFFECT */
+ glEnable(GL_BLEND);
+ glShadeModel(GL_SMOOTH);
+ glBegin(GL_LINES);
+ MM_WHITE_OP;
+ glVertex2f(x1-1,y1);
+ MM_WHITE_TR;
+ glVertex2f(x1-1,y2);
+ glEnd();
+ glDisable(GL_BLEND);
+
+ uiSetRoundBox(8);
+ flat_button(x1, y1, x2, y2, asp, colorid, flag, 0);
+ break;
+ case UI_BUT_ALIGN_TOP|UI_BUT_ALIGN_LEFT:
+
+ /* RIGHT OUTER SUNKEN EFFECT */
+ glEnable(GL_BLEND);
+ glShadeModel(GL_SMOOTH);
+ glBegin(GL_LINES);
+ MM_WHITE_OP;
+ glVertex2f(x2+1,y1);
+ MM_WHITE_TR;
+ glVertex2f(x2+1,y2);
+ glEnd();
+ glDisable(GL_BLEND);
+
+ uiSetRoundBox(4);
+ flat_button(x1, y1, x2, y2, asp, colorid, flag, 0);
+ break;
+
+ default:
+ flat_button(x1, y1, x2, y2, asp, colorid, flag, 1);
+ break;
+ }
+ }
+ else {
+
+ glEnable(GL_BLEND);
+ glShadeModel(GL_SMOOTH);
+
+ /* BOTTOM OUTER SUNKEN EFFECT */
+ MM_WHITE_OP;
+ fdrawline(x1, y1-1, x2, y1-1);
+
+ /* LEFT OUTER SUNKEN EFFECT */
+ glBegin(GL_LINES);
+ MM_WHITE_OP;
+ glVertex2f(x1-1,y1);
+ MM_WHITE_TR;
+ glVertex2f(x1-1,y2);
+ glEnd();
+
+ /* RIGHT OUTER SUNKEN EFFECT */
+ glBegin(GL_LINES);
+ MM_WHITE_OP;
+ glVertex2f(x2+1,y1);
+ MM_WHITE_TR;
+ glVertex2f(x2+1,y2);
+ glEnd();
+
+ glDisable(GL_BLEND);
+
+ uiSetRoundBox(15);
+ flat_button(x1, y1, x2, y2, asp, colorid, flag, 0);
+ }
+
+ /* *** EXTRA DRAWING FOR SPECIFIC CONTROL TYPES *** */
+ switch(type) {
+ case NUM:
+ /* SIDE ARROWS */
+ /* left */
+ if(flag & UI_SELECT) {
+ if(flag & UI_ACTIVE) M_DARK;
+ else M_DARK;
+ } else {
+ if(flag & UI_ACTIVE) M_GREY;
+ else M_LGREY;
+ }
+
+ ui_default_num_arrows(x1, y1, x2, y2);
+ /* END SIDE ARROWS */
+ }
+}
+
+static void ui_default_slider(int colorid, float fac, float aspect, float x1, float y1, float x2, float y2, int flag)
+{
+ float ymid, yc;
+
+ /* the slider background line */
+ ymid= (y1+y2)/2.0;
+ //yc= 2.5*aspect; // height of center line
+ yc = 2.3; // height of center line
+
+ if(flag & UI_SELECT)
+ BIF_ThemeColorShade(TH_BUT_NUM, -5);
+ else
+ if(flag & UI_ACTIVE)
+ BIF_ThemeColorShade(TH_BUT_NUM, +35);
+ else
+ BIF_ThemeColorShade(TH_BUT_NUM, +25);
+
+ glRectf(x1, ymid-yc, x2, ymid+yc);
+
+ /* top inner bevel */
+ if(flag & UI_SELECT) BIF_ThemeColorShade(TH_BUT_NUM, -40);
+ else BIF_ThemeColorShade(TH_BUT_NUM, -5);
+ fdrawline(x1+1, ymid+yc, x2, ymid+yc);
+
+ /* bottom inner bevel */
+ if(flag & UI_SELECT) BIF_ThemeColorShade(TH_BUT_NUM, +15);
+ else BIF_ThemeColorShade(TH_BUT_NUM, +45);
+ fdrawline(x1+1, ymid-yc, x2, ymid-yc);
+
+
+ /* the movable slider */
+ if(flag & UI_SELECT) BIF_ThemeColorShade(TH_BUT_NUM, +80);
+ else BIF_ThemeColorShade(TH_BUT_NUM, -45);
+
+ glShadeModel(GL_SMOOTH);
+ glBegin(GL_QUADS);
+
+ BIF_ThemeColorShade(TH_BUT_NUM, -45);
+
+ glVertex2f(x1, y1+2.5);
+ glVertex2f(x1+fac, y1+2.5);
+
+ BIF_ThemeColor(TH_BUT_NUM);
+
+ glVertex2f(x1+fac, y2-2.5);
+ glVertex2f(x1, y2-2.5);
+
+ glEnd();
+
+
+ /* slider handle center */
+ glShadeModel(GL_SMOOTH);
+ glBegin(GL_QUADS);
+
+ BIF_ThemeColor(TH_BUT_NUM);
+ glVertex2f(x1+fac-3, y1+2);
+ glVertex2f(x1+fac, y1+4);
+ BIF_ThemeColorShade(TH_BUT_NUM, +80);
+ glVertex2f(x1+fac, y2-2);
+ glVertex2f(x1+fac-3, y2-2);
+
+ glEnd();
+
+ /* slider handle left bevel */
+ BIF_ThemeColorShade(TH_BUT_NUM, +70);
+ fdrawline(x1+fac-3, y2-2, x1+fac-3, y1+2);
+
+ /* slider handle right bevel */
+ BIF_ThemeColorShade(TH_BUT_NUM, -35);
+ fdrawline(x1+fac, y2-2, x1+fac, y1+2);
+
+ glShadeModel(GL_FLAT);
+}
+
+/* default theme callback */
+static void ui_draw_default(int type, int colorid, float aspect, float x1, float y1, float x2, float y2, int flag)
+{
+
+ switch(type) {
+ case TEX:
+ case IDPOIN:
+ case NUM:
+ ui_default_flat(type, colorid, aspect, x1, y1, x2, y2, flag);
+ break;
+ case ICONROW:
+ case ICONTEXTROW:
+ case MENU:
+ default:
+ ui_default_button(type, colorid, aspect, x1, y1, x2, y2, flag);
+ }
+
+}
+
+
+/* *************** OLDSKOOL THEME ***************** */
+
+static void ui_draw_outlineX(float x1, float y1, float x2, float y2, float asp1)
+{
+ float vec[2];
+
+ glBegin(GL_LINE_LOOP);
+ vec[0]= x1+asp1; vec[1]= y1-asp1;
+ glVertex2fv(vec);
+ vec[0]= x2-asp1;
+ glVertex2fv(vec);
+ vec[0]= x2+asp1; vec[1]= y1+asp1;
+ glVertex2fv(vec);
+ vec[1]= y2-asp1;
+ glVertex2fv(vec);
+ vec[0]= x2-asp1; vec[1]= y2+asp1;
+ glVertex2fv(vec);
+ vec[0]= x1+asp1;
+ glVertex2fv(vec);
+ vec[0]= x1-asp1; vec[1]= y2-asp1;
+ glVertex2fv(vec);
+ vec[1]= y1+asp1;
+ glVertex2fv(vec);
+ glEnd();
+
+}
+
+
+static void ui_draw_oldskool(int type, int colorid, float asp, float x1, float y1, float x2, float y2, int flag)
+{
+ /* paper */
+ if(flag & UI_SELECT) {
+ if(flag & UI_ACTIVE) BIF_ThemeColorShade(colorid, -40);
+ else BIF_ThemeColorShade(colorid, -30);
+ }
+ else {
+ if(flag & UI_ACTIVE) BIF_ThemeColorShade(colorid, +30);
+ else BIF_ThemeColorShade(colorid, +20);
+ }
+
+ glRectf(x1+1, y1+1, x2-1, y2-1);
+
+ x1+= asp;
+ x2-= asp;
+ y1+= asp;
+ y2-= asp;
+
+ /* below */
+ if(flag & UI_SELECT) BIF_ThemeColorShade(colorid, 0);
+ else BIF_ThemeColorShade(colorid, -30);
+ fdrawline(x1, y1, x2, y1);
+
+ /* right */
+ fdrawline(x2, y1, x2, y2);
+
+ /* top */
+ if(flag & UI_SELECT) BIF_ThemeColorShade(colorid, -30);
+ else BIF_ThemeColorShade(colorid, 0);
+ fdrawline(x1, y2, x2, y2);
+
+ /* left */
+ fdrawline(x1, y1, x1, y2);
+
+ /* outline */
+ glColor3ub(0,0,0);
+ ui_draw_outlineX(x1, y1, x2, y2, asp);
+
+
+ /* special type decorations */
+ switch(type) {
+ case NUM:
+ if(flag & UI_SELECT) BIF_ThemeColorShade(colorid, -60);
+ else BIF_ThemeColorShade(colorid, -30);
+ ui_default_num_arrows(x1, y1, x2, y2);
+ break;
+
+ case ICONROW:
+ case ICONTEXTROW:
+ if(flag & UI_ACTIVE) BIF_ThemeColorShade(colorid, 0);
+ else BIF_ThemeColorShade(colorid, -10);
+ glRectf(x2-9, y1+asp, x2-asp, y2-asp);
+
+ BIF_ThemeColorShade(colorid, -50);
+ ui_default_iconrow_arrows(x1, y1, x2, y2);
+ break;
+
+ case MENU:
+ if(flag & UI_ACTIVE) BIF_ThemeColorShade(colorid, 0);
+ else BIF_ThemeColorShade(colorid, -10);
+ glRectf(x2-17, y1+asp, x2-asp, y2-asp);
+
+ BIF_ThemeColorShade(colorid, -50);
+ ui_default_menu_arrows(x1, y1, x2, y2);
+ break;
+ }
+
+}
+
+/* *************** BASIC ROUNDED THEME ***************** */
+
+static void round_button(float x1, float y1, float x2, float y2, float asp,
+ int colorid, int round, int menudeco, int curshade)
+{
+ float rad;
+ char col[4];
+
+ rad= (y2-y1)/2.0;
+ if(rad>7.0) rad= 7.0;
+
+ uiSetRoundBox(round);
+ gl_round_box(GL_POLYGON, x1, y1, x2, y2, rad);
+
+ if(menudeco) {
+ uiSetRoundBox(round & ~9);
+ BIF_ThemeColorShade(colorid, curshade-20);
+ gl_round_box(GL_POLYGON, x2-menudeco, y1, x2, y2, rad);
+ }
+
+ /* fake AA */
+ uiSetRoundBox(round);
+ glEnable( GL_BLEND );
+
+ BIF_GetThemeColor3ubv(colorid, col);
+
+ if(col[0]<100) col[0]= 0; else col[0]-= 100;
+ if(col[1]<100) col[1]= 0; else col[1]-= 100;
+ if(col[2]<100) col[2]= 0; else col[2]-= 100;
+ col[3]= 80;
+ glColor4ubv((GLubyte *)col);
+ gl_round_box(GL_LINE_LOOP, x1, y1, x2, y2, rad - asp);
+ gl_round_box(GL_LINE_LOOP, x1, y1, x2, y2, rad + asp);
+ col[3]= 180;
+ glColor4ubv((GLubyte *)col);
+ gl_round_box(GL_LINE_LOOP, x1, y1, x2, y2, rad);
+
+ glDisable( GL_BLEND );
+}
+
+/* button in midst of alignment row */
+static void round_button_mid(float x1, float y1, float x2, float y2, float asp,
+ int colorid, int align, int menudeco, int curshade)
+{
+ glRectf(x1, y1, x2, y2);
+
+ if(menudeco) {
+ BIF_ThemeColorShade(colorid, curshade-20);
+ glRectf(x2-menudeco, y1, x2, y2);
+ }
+
+ BIF_ThemeColorBlendShade(colorid, TH_BACK, 0.5, -70);
+ // we draw full outline, its not AA, and it works better button mouse-over hilite
+
+ // left right
+ fdrawline(x1, y1, x1, y2);
+ fdrawline(x2, y1, x2, y2);
+
+ // top down
+ fdrawline(x1, y2, x2, y2);
+ fdrawline(x1, y1, x2, y1);
+}
+
+static void ui_draw_round(int type, int colorid, float asp, float x1, float y1, float x2, float y2, int flag)
+{
+ int align= (flag & UI_BUT_ALIGN);
+ int curshade= 0, menudeco= 0;
+
+ if(type==ICONROW || type==ICONTEXTROW) menudeco= 9;
+ else if((type==MENU || type==BLOCK) && x2-x1>24) menudeco= 16;
+
+ /* paper */
+ if(flag & UI_SELECT) {
+ if(flag & UI_ACTIVE) curshade= -40;
+ else curshade= -30;
+ }
+ else {
+ if(flag & UI_ACTIVE) curshade= 30;
+ else curshade= +20;
+ }
+
+ BIF_ThemeColorShade(colorid, curshade);
+
+ if(align) {
+ switch(align) {
+ case UI_BUT_ALIGN_TOP:
+ round_button(x1, y1, x2, y2, asp, colorid, 12, menudeco, curshade);
+ break;
+ case UI_BUT_ALIGN_DOWN:
+ round_button(x1, y1, x2, y2, asp, colorid, 3, menudeco, curshade);
+ break;
+ case UI_BUT_ALIGN_LEFT:
+ round_button(x1, y1, x2, y2, asp, colorid, 6, menudeco, curshade);
+ break;
+ case UI_BUT_ALIGN_RIGHT:
+ round_button(x1, y1, x2, y2, asp, colorid, 9, menudeco, curshade);
+ break;
+
+ case UI_BUT_ALIGN_DOWN|UI_BUT_ALIGN_RIGHT:
+ round_button(x1, y1, x2, y2, asp, colorid, 1, menudeco, curshade);
+ break;
+ case UI_BUT_ALIGN_DOWN|UI_BUT_ALIGN_LEFT:
+ round_button(x1, y1, x2, y2, asp, colorid, 2, menudeco, curshade);
+ break;
+ case UI_BUT_ALIGN_TOP|UI_BUT_ALIGN_RIGHT:
+ round_button(x1, y1, x2, y2, asp, colorid, 8, menudeco, curshade);
+ break;
+ case UI_BUT_ALIGN_TOP|UI_BUT_ALIGN_LEFT:
+ round_button(x1, y1, x2, y2, asp, colorid, 4, menudeco, curshade);
+ break;
+
+ default:
+ round_button_mid(x1, y1, x2, y2, asp, colorid, align, menudeco, curshade);
+ break;
+ }
+ }
+ else {
+ round_button(x1, y1, x2, y2, asp, colorid, 15, menudeco, curshade);
+ }
+
+ /* special type decorations */
+ switch(type) {
+ case NUM:
+ BIF_ThemeColorShade(colorid, curshade-60);
+ ui_default_num_arrows(x1, y1, x2, y2);
+ break;
+
+ case ICONROW:
+ case ICONTEXTROW:
+ BIF_ThemeColorShade(colorid, curshade-60);
+ ui_default_iconrow_arrows(x1, y1, x2, y2);
+ break;
+
+ case MENU:
+ case BLOCK:
+ BIF_ThemeColorShade(colorid, curshade-60);
+ ui_default_menu_arrows(x1, y1, x2, y2);
+ break;
+ }
+}
+
+/* *************** MINIMAL THEME ***************** */
+
+// theme can define an embosfunc and sliderfunc, text+icon drawing is standard, no theme.
+
+
+
+/* super minimal button as used in logic menu */
+static void ui_draw_minimal(int type, int colorid, float asp, float x1, float y1, float x2, float y2, int flag)
+{
+ /* too much space between buttons */
+
+ if (type==TEX || type==IDPOIN) {
+ x1+= asp;
+ x2-= (asp*2);
+ //y1+= asp;
+ y2-= asp;
+ } else {
+ /* Less space between buttons looks nicer */
+ y2-= asp;
+ x2-= asp;
+ }
+
+ /* paper */
+ if(flag & UI_SELECT) {
+ if(flag & UI_ACTIVE) BIF_ThemeColorShade(colorid, -40);
+ else BIF_ThemeColorShade(colorid, -30);
+ }
+ else {
+ if(flag & UI_ACTIVE) BIF_ThemeColorShade(colorid, +20);
+ else BIF_ThemeColorShade(colorid, +10);
+ }
+
+ glRectf(x1, y1, x2, y2);
+
+ if (type==TEX || type==IDPOIN) {
+ BIF_ThemeColorShade(colorid, -60);
+
+ /* top */
+ fdrawline(x1, y2, x2, y2);
+ /* left */
+ fdrawline(x1, y1, x1, y2);
+
+
+ /* text underline, some */
+ BIF_ThemeColorShade(colorid, +50);
+ glEnable(GL_LINE_STIPPLE);
+ glLineStipple(1, 0x8888);
+ fdrawline(x1+(asp*2), y1+(asp*3), x2-(asp*2), y1+(asp*3));
+ glDisable(GL_LINE_STIPPLE);
+
+
+ BIF_ThemeColorShade(colorid, +60);
+ /* below */
+ fdrawline(x1, y1, x2, y1);
+ /* right */
+ fdrawline(x2, y1, x2, y2);
+
+ } else {
+ if(flag & UI_SELECT) {
+ BIF_ThemeColorShade(colorid, -60);
+
+ /* top */
+ fdrawline(x1, y2, x2, y2);
+ /* left */
+ fdrawline(x1, y1, x1, y2);
+ BIF_ThemeColorShade(colorid, +40);
+
+ /* below */
+ fdrawline(x1, y1, x2, y1);
+ /* right */
+ fdrawline(x2, y1, x2, y2);
+ }
+ else {
+ BIF_ThemeColorShade(colorid, +40);
+
+ /* top */
+ fdrawline(x1, y2, x2, y2);
+ /* left */
+ fdrawline(x1, y1, x1, y2);
+
+ BIF_ThemeColorShade(colorid, -60);
+ /* below */
+ fdrawline(x1, y1, x2, y1);
+ /* right */
+ fdrawline(x2, y1, x2, y2);
+ }
+ }
+
+ /* special type decorations */
+ switch(type) {
+ case NUM:
+ if(flag & UI_SELECT) BIF_ThemeColorShade(colorid, -60);
+ else BIF_ThemeColorShade(colorid, -30);
+ ui_default_num_arrows(x1, y1, x2, y2);
+ break;
+
+ case ICONROW:
+ case ICONTEXTROW:
+ if(flag & UI_ACTIVE) BIF_ThemeColorShade(colorid, 0);
+ else BIF_ThemeColorShade(colorid, -10);
+ glRectf(x2-9, y1+asp, x2-asp, y2-asp);
+
+ BIF_ThemeColorShade(colorid, -50);
+ ui_default_iconrow_arrows(x1, y1, x2, y2);
+ break;
+
+ case MENU:
+ case BLOCK:
+ if(flag & UI_ACTIVE) BIF_ThemeColorShade(colorid, 0);
+ else BIF_ThemeColorShade(colorid, -10);
+ glRectf(x2-17, y1+asp, x2-asp, y2-asp);
+
+ BIF_ThemeColorShade(colorid, -50);
+ ui_default_menu_arrows(x1, y1, x2, y2);
+ break;
+ }
+
+
+}
+
+
+/* fac is the slider handle position between x1 and x2 */
+static void ui_draw_slider(int colorid, float fac, float aspect, float x1, float y1, float x2, float y2, int flag)
+{
+ float ymid, yc;
+
+ /* the slider background line */
+ ymid= (y1+y2)/2.0;
+ yc= 1.7*aspect;
+
+ if(flag & UI_ACTIVE)
+ BIF_ThemeColorShade(colorid, -50);
+ else
+ BIF_ThemeColorShade(colorid, -40);
+
+ /* left part */
+ glRectf(x1, ymid-2.0*yc, x1+fac, ymid+2.0*yc);
+ /* right part */
+ glRectf(x1+fac, ymid-yc, x2, ymid+yc);
+
+ /* the movable slider */
+
+ BIF_ThemeColorShade(colorid, +70);
+ glRectf(x1+fac-aspect, ymid-2.0*yc, x1+fac+aspect, ymid+2.0*yc);
+
+}
+
+/* ************** STANDARD MENU DRAWING FUNCTION ************* */
+
+
+static void ui_shadowbox(float minx, float miny, float maxx, float maxy, float shadsize, unsigned char alpha)
+{
+ glEnable(GL_BLEND);
+ glShadeModel(GL_SMOOTH);
+
+ /* right quad */
+ glBegin(GL_POLYGON);
+ glColor4ub(0, 0, 0, alpha);
+ glVertex2f(maxx, miny);
+ glVertex2f(maxx, maxy-shadsize);
+ glColor4ub(0, 0, 0, 0);
+ glVertex2f(maxx+shadsize, maxy-shadsize-shadsize);
+ glVertex2f(maxx+shadsize, miny);
+ glEnd();
+
+ /* corner shape */
+ glBegin(GL_POLYGON);
+ glColor4ub(0, 0, 0, alpha);
+ glVertex2f(maxx, miny);
+ glColor4ub(0, 0, 0, 0);
+ glVertex2f(maxx+shadsize, miny);
+ glVertex2f(maxx+0.7*shadsize, miny-0.7*shadsize);
+ glVertex2f(maxx, miny-shadsize);
+ glEnd();
+
+ /* bottom quad */
+ glBegin(GL_POLYGON);
+ glColor4ub(0, 0, 0, alpha);
+ glVertex2f(minx+shadsize, miny);
+ glVertex2f(maxx, miny);
+ glColor4ub(0, 0, 0, 0);
+ glVertex2f(maxx, miny-shadsize);
+ glVertex2f(minx+shadsize+shadsize, miny-shadsize);
+ glEnd();
+
+ glDisable(GL_BLEND);
+ glShadeModel(GL_FLAT);
+}
+
+void uiDrawBoxShadow(unsigned char alpha, float minx, float miny, float maxx, float maxy)
+{
+ /* accumulated outline boxes to make shade not linear, is more pleasant */
+ ui_shadowbox(minx, miny, maxx, maxy, 6.0, (30*alpha)>>8);
+ ui_shadowbox(minx, miny, maxx, maxy, 4.0, (70*alpha)>>8);
+ ui_shadowbox(minx, miny, maxx, maxy, 2.0, (100*alpha)>>8);
+
+}
+
+// background for pulldowns, pullups, and other drawing temporal menus....
+// has to be made themable still (now only color)
+
+void uiDrawMenuBox(float minx, float miny, float maxx, float maxy, short flag)
+{
+ char col[4];
+ BIF_GetThemeColor4ubv(TH_MENU_BACK, col);
+
+ if( (flag & UI_BLOCK_NOSHADOW)==0) {
+ /* accumulated outline boxes to make shade not linear, is more pleasant */
+ ui_shadowbox(minx, miny, maxx, maxy, 6.0, (30*col[3])>>8);
+ ui_shadowbox(minx, miny, maxx, maxy, 4.0, (70*col[3])>>8);
+ ui_shadowbox(minx, miny, maxx, maxy, 2.0, (100*col[3])>>8);
+
+ glEnable(GL_BLEND);
+ glColor4ubv((GLubyte *)col);
+ glRectf(minx-1, miny, minx, maxy); // 1 pixel on left, to distinguish sublevel menus
+ }
+ glEnable(GL_BLEND);
+ glColor4ubv((GLubyte *)col);
+ glRectf(minx, miny, maxx, maxy);
+ glDisable(GL_BLEND);
+}
+
+
+
+/* pulldown menu item */
+static void ui_draw_pulldown_item(int type, int colorid, float asp, float x1, float y1, float x2, float y2, int flag)
+{
+ char col[4];
+
+ BIF_GetThemeColor4ubv(TH_MENU_BACK, col);
+ if(col[3]!=255) {
+ glEnable(GL_BLEND);
+ }
+
+ if((flag & UI_ACTIVE) && type!=LABEL) {
+ BIF_ThemeColor4(TH_MENU_HILITE);
+ glRectf(x1, y1, x2, y2);
+
+
+ } else {
+ BIF_ThemeColor4(colorid); // is set at TH_MENU_ITEM when pulldown opened.
+ glRectf(x1, y1, x2, y2);
+ }
+
+ glDisable(GL_BLEND);
+}
+
+/* pulldown menu calling button */
+static void ui_draw_pulldown_round(int type, int colorid, float asp, float x1, float y1, float x2, float y2, int flag)
+{
+
+ if(flag & UI_ACTIVE) {
+ BIF_ThemeColor(TH_MENU_HILITE);
+
+ uiSetRoundBox(15);
+ gl_round_box(GL_POLYGON, x1, y1+3, x2, y2-3, 7.0);
+
+ glEnable( GL_LINE_SMOOTH );
+ glEnable( GL_BLEND );
+ gl_round_box(GL_LINE_LOOP, x1, y1+3, x2, y2-3, 7.0);
+ glDisable( GL_LINE_SMOOTH );
+ glDisable( GL_BLEND );
+
+ } else {
+ BIF_ThemeColor(colorid); // is set at TH_MENU_ITEM when pulldown opened.
+ glRectf(x1-1, y1+2, x2+1, y2-2);
+ }
+
+}
+
+
+/* ************** TEXT AND ICON DRAWING FUNCTIONS ************* */
+
+
+
+/* draws text and icons for buttons */
+static void ui_draw_text_icon(uiBut *but)
+{
+ float x;
+ int len;
+ char *cpoin;
+ short t, pos, ch;
+ short selsta_tmp, selend_tmp, selsta_draw, selwidth_draw;
+
+ /* check for button text label */
+ if (but->type == ICONTEXTROW) {
+ ui_draw_icon(but, (BIFIconID) (but->icon+but->iconadd), 0);
+ }
+ else {
+
+ /* text button selection and cursor */
+ if(but->pos != -1) {
+
+ if ((but->selend - but->selsta) > 0) {
+ /* text button selection */
+ selsta_tmp = but->selsta + strlen(but->str);
+ selend_tmp = but->selend + strlen(but->str);
+
+ if(but->drawstr[0]!=0) {
+ ch= but->drawstr[selsta_tmp];
+ but->drawstr[selsta_tmp]= 0;
+
+ selsta_draw = but->aspect*BIF_GetStringWidth(but->font, but->drawstr+but->ofs, (U.transopts & USER_TR_BUTTONS)) + 3;
+
+ but->drawstr[selsta_tmp]= ch;
+
+
+ ch= but->drawstr[selend_tmp];
+ but->drawstr[selend_tmp]= 0;
+
+ selwidth_draw = but->aspect*BIF_GetStringWidth(but->font, but->drawstr+but->ofs, (U.transopts & USER_TR_BUTTONS)) + 3;
+
+ but->drawstr[selend_tmp]= ch;
+
+ BIF_ThemeColor(TH_BUT_TEXTFIELD_HI);
+ glRects(but->x1+selsta_draw+1, but->y1+2, but->x1+selwidth_draw+1, but->y2-2);
+ }
+ } else {
+ /* text cursor */
+ pos= but->pos+strlen(but->str);
+ if(pos >= but->ofs) {
+ if(but->drawstr[0]!=0) {
+ ch= but->drawstr[pos];
+ but->drawstr[pos]= 0;
+
+ t= but->aspect*BIF_GetStringWidth(but->font, but->drawstr+but->ofs, (U.transopts & USER_TR_BUTTONS)) + 3;
+
+ but->drawstr[pos]= ch;
+ }
+ else t= 3;
+
+ glColor3ub(255,0,0);
+ glRects(but->x1+t, but->y1+2, but->x1+t+2, but->y2-2);
+ }
+ }
+ }
+
+ if(but->type==BUT_TOGDUAL) {
+ int dualset= 0;
+ if(but->pointype==SHO)
+ dualset= BTST( *(((short *)but->poin)+1), but->bitnr);
+ else if(but->pointype==INT)
+ dualset= BTST( *(((int *)but->poin)+1), but->bitnr);
+
+ ui_draw_icon(but, ICON_DOT, dualset?0:-100);
+ }
+
+ if(but->drawstr[0]!=0) {
+ int transopts;
+ int tog3= 0;
+
+ // cut string in 2 parts
+ cpoin= strchr(but->drawstr, '|');
+ if(cpoin) *cpoin= 0;
+
+ /* If there's an icon too (made with uiDefIconTextBut) then draw the icon
+ and offset the text label to accomodate it */
+
+ if ( (but->flag & UI_HAS_ICON) && (but->flag & UI_ICON_LEFT) ) {
+ ui_draw_icon(but, but->icon, 0);
+
+ if(but->flag & UI_TEXT_LEFT) x= but->x1 + but->aspect*BIF_icon_get_width(but->icon)+5.0;
+ else x= (but->x1+but->x2-but->strwidth+1)/2.0;
+ }
+ else {
+ if(but->flag & UI_TEXT_LEFT) x= but->x1+4.0;
+ else x= (but->x1+but->x2-but->strwidth+1)/2.0;
+ }
+
+ /* tog3 button exception; draws with glColor! */
+ if(but->type==TOG3 && (but->flag & UI_SELECT)) {
+
+ if( but->pointype==CHA ) {
+ if( BTST( *(but->poin+2), but->bitnr )) tog3= 1;
+ }
+ else if( but->pointype ==SHO ) {
+ short *sp= (short *)but->poin;
+ if( BTST( sp[1], but->bitnr )) tog3= 1;
+ }
+
+ ui_tog3_invert(but->x1,but->y1,but->x2,but->y2, tog3);
+ if (tog3) glColor3ub(255, 255, 0);
+ }
+
+ /* text color, with pulldown item exception */
+ if(tog3); // color already set
+ else if(but->dt==UI_EMBOSSP) {
+ if((but->flag & (UI_SELECT|UI_ACTIVE)) && but->type!=LABEL) { // LABEL = title in pulldowns
+ BIF_ThemeColor(TH_MENU_TEXT_HI);
+ } else {
+ BIF_ThemeColor(TH_MENU_TEXT);
+ }
+ }
+ else {
+ if(but->flag & UI_SELECT) {
+ BIF_ThemeColor(TH_BUT_TEXT_HI);
+ } else {
+ BIF_ThemeColor(TH_BUT_TEXT);
+ }
+ }
+
+ /* LABEL button exception */
+ if(but->type==LABEL && but->min!=0.0) BIF_ThemeColor(TH_BUT_TEXT_HI);
+
+ ui_rasterpos_safe(x, (but->y1+but->y2- 9.0)/2.0, but->aspect);
+ if(but->type==IDPOIN) transopts= 0; // no translation, of course!
+ else transopts= (U.transopts & USER_TR_BUTTONS);
+
+ #ifdef INTERNATIONAL
+ if (but->type == FTPREVIEW)
+ FTF_DrawNewFontString (but->drawstr+but->ofs, FTF_INPUT_UTF8);
+ else
+ BIF_DrawString(but->font, but->drawstr+but->ofs, transopts);
+ #else
+ BIF_DrawString(but->font, but->drawstr+but->ofs, transopts);
+ #endif
+
+ /* part text right aligned */
+ if(cpoin) {
+ len= BIF_GetStringWidth(but->font, cpoin+1, (U.transopts & USER_TR_BUTTONS));
+ ui_rasterpos_safe( but->x2 - len*but->aspect-3, (but->y1+but->y2- 9.0)/2.0, but->aspect);
+ BIF_DrawString(but->font, cpoin+1, (U.transopts & USER_TR_BUTTONS));
+ *cpoin= '|';
+ }
+ }
+ /* if there's no text label, then check to see if there's an icon only and draw it */
+ else if( but->flag & UI_HAS_ICON ) {
+ ui_draw_icon(but, (BIFIconID) (but->icon+but->iconadd), 0);
+ }
+ }
+}
+
+static void ui_draw_but_COL(uiBut *but)
+{
+ float *fp;
+ char colr, colg, colb;
+
+ if( but->pointype==FLO ) {
+ fp= (float *)but->poin;
+ colr= floor(255.0*fp[0]+0.5);
+ colg= floor(255.0*fp[1]+0.5);
+ colb= floor(255.0*fp[2]+0.5);
+ }
+ else {
+ char *cp= (char *)but->poin;
+ colr= cp[0];
+ colg= cp[1];
+ colb= cp[2];
+ }
+
+ /* exception... hrms, but can't simply use the emboss callback for this now. */
+ /* this button type needs review, and nice integration with rest of API here */
+ if(but->embossfunc == ui_draw_round) {
+ char *cp= BIF_ThemeGetColorPtr(U.themes.first, 0, TH_CUSTOM);
+ cp[0]= colr; cp[1]= colg; cp[2]= colb;
+ but->flag &= ~UI_SELECT;
+ but->embossfunc(but->type, TH_CUSTOM, but->aspect, but->x1, but->y1, but->x2, but->y2, but->flag);
+ }
+ else {
+
+ glColor3ub(colr, colg, colb);
+ glRectf((but->x1), (but->y1), (but->x2), (but->y2));
+ glColor3ub(0, 0, 0);
+ fdrawbox((but->x1), (but->y1), (but->x2), (but->y2));
+ }
+}
+
+/* draws in resolution of 20x4 colors */
+static void ui_draw_but_HSVCUBE(uiBut *but)
+{
+ int a;
+ float h,s,v;
+ float dx, dy, sx1, sx2, sy, x, y;
+ float col0[4][3]; // left half, rect bottom to top
+ float col1[4][3]; // right half, rect bottom to top
+
+ h= but->hsv[0];
+ s= but->hsv[1];
+ v= but->hsv[2];
+
+ /* draw series of gouraud rects */
+ glShadeModel(GL_SMOOTH);
+
+ if(but->a1==0) { // H and V vary
+ hsv_to_rgb(0.0, s, 0.0, &col1[0][0], &col1[0][1], &col1[0][2]);
+ hsv_to_rgb(0.0, s, 0.333, &col1[1][0], &col1[1][1], &col1[1][2]);
+ hsv_to_rgb(0.0, s, 0.666, &col1[2][0], &col1[2][1], &col1[2][2]);
+ hsv_to_rgb(0.0, s, 1.0, &col1[3][0], &col1[3][1], &col1[3][2]);
+ x= h; y= v;
+ }
+ else if(but->a1==1) { // H and S vary
+ hsv_to_rgb(0.0, 0.0, v, &col1[0][0], &col1[0][1], &col1[0][2]);
+ hsv_to_rgb(0.0, 0.333, v, &col1[1][0], &col1[1][1], &col1[1][2]);
+ hsv_to_rgb(0.0, 0.666, v, &col1[2][0], &col1[2][1], &col1[2][2]);
+ hsv_to_rgb(0.0, 1.0, v, &col1[3][0], &col1[3][1], &col1[3][2]);
+ x= h; y= s;
+ }
+ else if(but->a1==2) { // S and V vary
+ hsv_to_rgb(h, 0.0, 0.0, &col1[0][0], &col1[0][1], &col1[0][2]);
+ hsv_to_rgb(h, 0.333, 0.0, &col1[1][0], &col1[1][1], &col1[1][2]);
+ hsv_to_rgb(h, 0.666, 0.0, &col1[2][0], &col1[2][1], &col1[2][2]);
+ hsv_to_rgb(h, 1.0, 0.0, &col1[3][0], &col1[3][1], &col1[3][2]);
+ x= v; y= s;
+ }
+ else { // only hue slider
+ hsv_to_rgb(0.0, 1.0, 1.0, &col1[0][0], &col1[0][1], &col1[0][2]);
+ VECCOPY(col1[1], col1[0]);
+ VECCOPY(col1[2], col1[0]);
+ VECCOPY(col1[3], col1[0]);
+ x= h; y= 0.5;
+ }
+
+ for(dx=0.0; dx<1.0; dx+= 0.05) {
+ // previous color
+ VECCOPY(col0[0], col1[0]);
+ VECCOPY(col0[1], col1[1]);
+ VECCOPY(col0[2], col1[2]);
+ VECCOPY(col0[3], col1[3]);
+
+ // new color
+ if(but->a1==0) { // H and V vary
+ hsv_to_rgb(dx, s, 0.0, &col1[0][0], &col1[0][1], &col1[0][2]);
+ hsv_to_rgb(dx, s, 0.333, &col1[1][0], &col1[1][1], &col1[1][2]);
+ hsv_to_rgb(dx, s, 0.666, &col1[2][0], &col1[2][1], &col1[2][2]);
+ hsv_to_rgb(dx, s, 1.0, &col1[3][0], &col1[3][1], &col1[3][2]);
+ }
+ else if(but->a1==1) { // H and S vary
+ hsv_to_rgb(dx, 0.0, v, &col1[0][0], &col1[0][1], &col1[0][2]);
+ hsv_to_rgb(dx, 0.333, v, &col1[1][0], &col1[1][1], &col1[1][2]);
+ hsv_to_rgb(dx, 0.666, v, &col1[2][0], &col1[2][1], &col1[2][2]);
+ hsv_to_rgb(dx, 1.0, v, &col1[3][0], &col1[3][1], &col1[3][2]);
+ }
+ else if(but->a1==2) { // S and V vary
+ hsv_to_rgb(h, 0.0, dx, &col1[0][0], &col1[0][1], &col1[0][2]);
+ hsv_to_rgb(h, 0.333, dx, &col1[1][0], &col1[1][1], &col1[1][2]);
+ hsv_to_rgb(h, 0.666, dx, &col1[2][0], &col1[2][1], &col1[2][2]);
+ hsv_to_rgb(h, 1.0, dx, &col1[3][0], &col1[3][1], &col1[3][2]);
+ }
+ else { // only H
+ hsv_to_rgb(dx, 1.0, 1.0, &col1[0][0], &col1[0][1], &col1[0][2]);
+ VECCOPY(col1[1], col1[0]);
+ VECCOPY(col1[2], col1[0]);
+ VECCOPY(col1[3], col1[0]);
+ }
+
+ // rect
+ sx1= but->x1 + dx*(but->x2-but->x1);
+ sx2= but->x1 + (dx+0.05)*(but->x2-but->x1);
+ sy= but->y1;
+ dy= (but->y2-but->y1)/3.0;
+
+ glBegin(GL_QUADS);
+ for(a=0; a<3; a++, sy+=dy) {
+ glColor3fv(col0[a]);
+ glVertex2f(sx1, sy);
+
+ glColor3fv(col1[a]);
+ glVertex2f(sx2, sy);
+
+ glColor3fv(col1[a+1]);
+ glVertex2f(sx2, sy+dy);
+
+ glColor3fv(col0[a+1]);
+ glVertex2f(sx1, sy+dy);
+ }
+ glEnd();
+ }
+
+ glShadeModel(GL_FLAT);
+
+ /* cursor */
+ x= but->x1 + x*(but->x2-but->x1);
+ y= but->y1 + y*(but->y2-but->y1);
+ CLAMP(x, but->x1+3.0, but->x2-3.0);
+ CLAMP(y, but->y1+3.0, but->y2-3.0);
+
+ fdrawXORcirc(x, y, 3.1);
+
+ /* outline */
+ glColor3ub(0, 0, 0);
+ fdrawbox((but->x1), (but->y1), (but->x2), (but->y2));
+}
+
+#ifdef INTERNATIONAL
+static void ui_draw_but_CHARTAB(uiBut *but)
+{
+ /* Some local variables */
+ float sx, sy, ex, ey;
+ float width, height;
+ float butw, buth;
+ int x, y, cs;
+ wchar_t wstr[2];
+ unsigned char ustr[16];
+ PackedFile *pf;
+ int result = 0;
+ int charmax = G.charmax;
+
+ /* <builtin> font in use. There are TTF <builtin> and non-TTF <builtin> fonts */
+ if(!strcmp(G.selfont->name, "<builtin>"))
+ {
+ if(G.ui_international == TRUE)
+ {
+ charmax = 0xff;
+ }
+ else
+ {
+ charmax = 0xff;
+ }
+ }
+
+ /* Category list exited without selecting the area */
+ if(G.charmax == 0)
+ charmax = G.charmax = 0xffff;
+
+ /* Calculate the size of the button */
+ width = abs(but->x2 - but->x1);
+ height = abs(but->y2 - but->y1);
+
+ butw = floor(width / 12);
+ buth = floor(height / 6);
+
+ /* Initialize variables */
+ sx = but->x1;
+ ex = but->x1 + butw;
+ sy = but->y1 + height - buth;
+ ey = but->y1 + height;
+
+ cs = G.charstart;
+
+ /* Set the font, in case it is not <builtin> font */
+ if(G.selfont && strcmp(G.selfont->name, "<builtin>"))
+ {
+ char tmpStr[256];
+
+ // Is the font file packed, if so then use the packed file
+ if(G.selfont->packedfile)
+ {
+ pf = G.selfont->packedfile;
+ FTF_SetFont(pf->data, pf->size, 14.0);
+ }
+ else
+ {
+ int err;
+
+ strcpy(tmpStr, G.selfont->name);
+ BLI_convertstringcode(tmpStr, G.sce, 0);
+ err = FTF_SetFont((unsigned char *)tmpStr, 0, 14.0);
+ }
+ }
+ else
+ {
+ if(G.ui_international == TRUE)
+ {
+ FTF_SetFont((unsigned char *) datatoc_bfont_ttf, datatoc_bfont_ttf_size, 14.0);
+ }
+ }
+
+ /* Start drawing the button itself */
+ glShadeModel(GL_SMOOTH);
+
+ glColor3ub(200, 200, 200);
+ glRectf((but->x1), (but->y1), (but->x2), (but->y2));
+
+ glColor3ub(0, 0, 0);
+ for(y = 0; y < 6; y++)
+ {
+ // Do not draw more than the category allows
+ if(cs > charmax) break;
+
+ for(x = 0; x < 12; x++)
+ {
+ // Do not draw more than the category allows
+ if(cs > charmax) break;
+
+ // Draw one grid cell
+ glBegin(GL_LINE_LOOP);
+ glVertex2f(sx, sy);
+ glVertex2f(ex, sy);
+ glVertex2f(ex, ey);
+ glVertex2f(sx, ey);
+ glEnd();
+
+ // Draw character inside the cell
+ memset(wstr, 0, sizeof(wchar_t)*2);
+ memset(ustr, 0, 16);
+
+ // Set the font to be either unicode or <builtin>
+ wstr[0] = cs;
+ if(strcmp(G.selfont->name, "<builtin>"))
+ {
+ wcs2utf8s((char *)ustr, (wchar_t *)wstr);
+ }
+ else
+ {
+ if(G.ui_international == TRUE)
+ {
+ wcs2utf8s((char *)ustr, (wchar_t *)wstr);
+ }
+ else
+ {
+ ustr[0] = cs;
+ ustr[1] = 0;
+ }
+ }
+
+ if((G.selfont && strcmp(G.selfont->name, "<builtin>")) || (G.selfont && !strcmp(G.selfont->name, "<builtin>") && G.ui_international == TRUE))
+ {
+ float wid;
+ float llx, lly, llz, urx, ury, urz;
+ float dx, dy;
+ float px, py;
+
+ // Calculate the position
+ wid = FTF_GetStringWidth((char *) ustr, FTF_USE_GETTEXT | FTF_INPUT_UTF8);
+ FTF_GetBoundingBox((char *) ustr, &llx,&lly,&llz,&urx,&ury,&urz, FTF_USE_GETTEXT | FTF_INPUT_UTF8);
+ dx = urx-llx;
+ dy = ury-lly;
+
+ // This isn't fully functional since the but->aspect isn't working like I suspected
+ px = sx + ((butw/but->aspect)-dx)/2;
+ py = sy + ((buth/but->aspect)-dy)/2;
+
+ // Set the position and draw the character
+ ui_rasterpos_safe(px, py, but->aspect);
+ FTF_DrawString((char *) ustr, FTF_USE_GETTEXT | FTF_INPUT_UTF8);
+ }
+ else
+ {
+ ui_rasterpos_safe(sx + butw/2, sy + buth/2, but->aspect);
+ BIF_DrawString(but->font, (char *) ustr, 0);
+ }
+
+ // Calculate the next position and character
+ sx += butw; ex +=butw;
+ cs++;
+ }
+ /* Add the y position and reset x position */
+ sy -= buth;
+ ey -= buth;
+ sx = but->x1;
+ ex = but->x1 + butw;
+ }
+ glShadeModel(GL_FLAT);
+
+ /* Return Font Settings to original */
+ if(U.fontsize && U.fontname[0])
+ {
+ result = FTF_SetFont((unsigned char *)U.fontname, 0, U.fontsize);
+ }
+ else if (U.fontsize)
+ {
+ result = FTF_SetFont((unsigned char *) datatoc_bfont_ttf, datatoc_bfont_ttf_size, U.fontsize);
+ }
+
+ if (result == 0)
+ {
+ result = FTF_SetFont((unsigned char *) datatoc_bfont_ttf, datatoc_bfont_ttf_size, 11);
+ }
+
+ /* resets the font size */
+ if(G.ui_international == TRUE)
+ {
+ uiSetCurFont(but->block, UI_HELV);
+ }
+}
+
+#endif // INTERNATIONAL
+
+static void ui_draw_but_COLORBAND(uiBut *but)
+{
+ ColorBand *coba= (ColorBand *)but->poin;
+ CBData *cbd;
+ float x1, y1, sizex, sizey;
+ float dx, v3[2], v1[2], v2[2];
+ int a;
+
+ if(coba==NULL) return;
+
+ x1= but->x1;
+ y1= but->y1;
+ sizex= but->x2-x1;
+ sizey= but->y2-y1;
+
+ /* first background, to show tranparency */
+ dx= sizex/12.0;
+ v1[0]= x1;
+ for(a=0; a<12; a++) {
+ if(a & 1) glColor3f(0.3, 0.3, 0.3); else glColor3f(0.8, 0.8, 0.8);
+ glRectf(v1[0], y1, v1[0]+dx, y1+0.5*sizey);
+ if(a & 1) glColor3f(0.8, 0.8, 0.8); else glColor3f(0.3, 0.3, 0.3);
+ glRectf(v1[0], y1+0.5*sizey, v1[0]+dx, y1+sizey);
+ v1[0]+= dx;
+ }
+
+ glShadeModel(GL_SMOOTH);
+ glEnable(GL_BLEND);
+
+ cbd= coba->data;
+
+ v1[0]= v2[0]= x1;
+ v1[1]= y1;
+ v2[1]= y1+sizey;
+
+ glBegin(GL_QUAD_STRIP);
+
+ glColor4fv( &cbd->r );
+ glVertex2fv(v1); glVertex2fv(v2);
+
+ for(a=0; a<coba->tot; a++, cbd++) {
+
+ v1[0]=v2[0]= x1+ cbd->pos*sizex;
+
+ glColor4fv( &cbd->r );
+ glVertex2fv(v1); glVertex2fv(v2);
+ }
+
+ v1[0]=v2[0]= x1+ sizex;
+ glVertex2fv(v1); glVertex2fv(v2);
+
+ glEnd();
+ glShadeModel(GL_FLAT);
+ glDisable(GL_BLEND);
+
+ /* outline */
+ v1[0]= x1; v1[1]= y1;
+
+ cpack(0x0);
+ glBegin(GL_LINE_LOOP);
+ glVertex2fv(v1);
+ v1[0]+= sizex;
+ glVertex2fv(v1);
+ v1[1]+= sizey;
+ glVertex2fv(v1);
+ v1[0]-= sizex;
+ glVertex2fv(v1);
+ glEnd();
+
+
+ /* help lines */
+ v1[0]= v2[0]=v3[0]= x1;
+ v1[1]= y1;
+ v2[1]= y1+0.5*sizey;
+ v3[1]= y1+sizey;
+
+ cbd= coba->data;
+ glBegin(GL_LINES);
+ for(a=0; a<coba->tot; a++, cbd++) {
+ v1[0]=v2[0]=v3[0]= x1+ cbd->pos*sizex;
+
+ glColor3ub(0, 0, 0);
+ glVertex2fv(v1);
+ glVertex2fv(v2);
+
+ if(a==coba->cur) {
+ glVertex2f(v1[0]-1, v1[1]);
+ glVertex2f(v2[0]-1, v2[1]);
+ glVertex2f(v1[0]+1, v1[1]);
+ glVertex2f(v2[0]+1, v2[1]);
+ }
+
+ glColor3ub(255, 255, 255);
+ glVertex2fv(v2);
+ glVertex2fv(v3);
+
+ if(a==coba->cur) {
+ if(cbd->pos>0.01) {
+ glVertex2f(v2[0]-1, v2[1]);
+ glVertex2f(v3[0]-1, v3[1]);
+ }
+ if(cbd->pos<0.99) {
+ glVertex2f(v2[0]+1, v2[1]);
+ glVertex2f(v3[0]+1, v3[1]);
+ }
+ }
+ }
+ glEnd();
+}
+
+static void ui_draw_but_NORMAL(uiBut *but)
+{
+ static GLuint displist=0;
+ int a, old[8];
+ GLfloat diff[4], diffn[4]={1.0f, 1.0f, 1.0f, 1.0f};
+ float vec0[4]={0.0f, 0.0f, 0.0f, 0.0f};
+ float dir[4], size;
+
+ /* store stuff */
+ glGetMaterialfv(GL_FRONT, GL_DIFFUSE, diff);
+
+ /* backdrop */
+ BIF_ThemeColor(TH_BUT_NEUTRAL);
+ uiSetRoundBox(15);
+ gl_round_box(GL_POLYGON, but->x1, but->y1, but->x2, but->y2, 5.0f);
+
+ /* sphere color */
+ glMaterialfv(GL_FRONT, GL_DIFFUSE, diffn);
+ glCullFace(GL_BACK); glEnable(GL_CULL_FACE);
+
+ /* disable blender light */
+ for(a=0; a<8; a++) {
+ old[a]= glIsEnabled(GL_LIGHT0+a);
+ glDisable(GL_LIGHT0+a);
+ }
+
+ /* own light */
+ glEnable(GL_LIGHT7);
+ glEnable(GL_LIGHTING);
+
+ VECCOPY(dir, (float *)but->poin);
+ dir[3]= 0.0f; /* glLight needs 4 args, 0.0 is sun */
+ glLightfv(GL_LIGHT7, GL_POSITION, dir);
+ glLightfv(GL_LIGHT7, GL_DIFFUSE, diffn);
+ glLightfv(GL_LIGHT7, GL_SPECULAR, vec0);
+ glLightf(GL_LIGHT7, GL_CONSTANT_ATTENUATION, 1.0f);
+ glLightf(GL_LIGHT7, GL_LINEAR_ATTENUATION, 0.0f);
+
+ /* transform to button */
+ glPushMatrix();
+ glTranslatef(but->x1 + 0.5f*(but->x2-but->x1), but->y1+ 0.5f*(but->y2-but->y1), 0.0f);
+ size= (but->x2-but->x1)/200.f;
+ glScalef(size, size, size);
+
+ if(displist==0) {
+ GLUquadricObj *qobj;
+
+ displist= glGenLists(1);
+ glNewList(displist, GL_COMPILE_AND_EXECUTE);
+
+ qobj= gluNewQuadric();
+ gluQuadricDrawStyle(qobj, GLU_FILL);
+ glShadeModel(GL_SMOOTH);
+ gluSphere( qobj, 100.0, 32, 24);
+ glShadeModel(GL_FLAT);
+ gluDeleteQuadric(qobj);
+
+ glEndList();
+ }
+ else glCallList(displist);
+
+ /* restore */
+ glPopMatrix();
+ glDisable(GL_LIGHTING);
+ glDisable(GL_CULL_FACE);
+ glMaterialfv(GL_FRONT, GL_DIFFUSE, diff);
+
+ glDisable(GL_LIGHT7);
+
+ /* enable blender light */
+ for(a=0; a<8; a++) {
+ if(old[a])
+ glEnable(GL_LIGHT0+a);
+ }
+}
+
+static void ui_draw_but_curve_grid(uiBut *but, float zoomx, float zoomy, float offsx, float offsy, float step)
+{
+ float dx, dy, fx, fy;
+
+ glBegin(GL_LINES);
+ dx= step*zoomx;
+ fx= but->x1 + zoomx*(-offsx);
+ if(fx > but->x1) fx -= dx*( floor(fx-but->x1));
+ while(fx < but->x2) {
+ glVertex2f(fx, but->y1);
+ glVertex2f(fx, but->y2);
+ fx+= dx;
+ }
+
+ dy= step*zoomy;
+ fy= but->y1 + zoomy*(-offsy);
+ if(fy > but->y1) fy -= dy*( floor(fy-but->y1));
+ while(fy < but->y2) {
+ glVertex2f(but->x1, fy);
+ glVertex2f(but->x2, fy);
+ fy+= dy;
+ }
+ glEnd();
+
+}
+
+static void ui_draw_but_CURVE(uiBut *but)
+{
+ CurveMapping *cumap= (CurveMapping *)but->poin;
+ CurveMap *cuma= cumap->cm+cumap->cur;
+ CurveMapPoint *cmp;
+ float fx, fy, dx, dy, fac[2], zoomx, zoomy, offsx, offsy;
+ GLint scissor[4];
+ int a;
+
+ /* need scissor test, curve can draw outside of boundary */
+ glGetIntegerv(GL_VIEWPORT, scissor);
+ fx= but->x1; fy= but->y1;
+ ui_graphics_to_window(but->win, &fx, &fy);
+ dx= but->x2; dy= but->y2;
+ ui_graphics_to_window(but->win, &dx, &dy);
+ glScissor((int)floor(fx), (int)floor(fy), (int)ceil(dx-fx), (int)ceil(dy-fy));
+
+ /* calculate offset and zoom */
+ zoomx= (but->x2-but->x1-2.0*but->aspect)/(cumap->curr.xmax - cumap->curr.xmin);
+ zoomy= (but->y2-but->y1-2.0*but->aspect)/(cumap->curr.ymax - cumap->curr.ymin);
+ offsx= cumap->curr.xmin-but->aspect/zoomx;
+ offsy= cumap->curr.ymin-but->aspect/zoomy;
+
+ /* backdrop */
+ if(cumap->flag & CUMA_DO_CLIP) {
+ BIF_ThemeColorShade(TH_BUT_NEUTRAL, -20);
+ glRectf(but->x1, but->y1, but->x2, but->y2);
+ BIF_ThemeColor(TH_BUT_NEUTRAL);
+ glRectf(but->x1 + zoomx*(cumap->clipr.xmin-offsx),
+ but->y1 + zoomy*(cumap->clipr.ymin-offsy),
+ but->x1 + zoomx*(cumap->clipr.xmax-offsx),
+ but->y1 + zoomy*(cumap->clipr.ymax-offsy));
+ }
+ else {
+ BIF_ThemeColor(TH_BUT_NEUTRAL);
+ glRectf(but->x1, but->y1, but->x2, but->y2);
+ }
+
+ /* grid, every .25 step */
+ BIF_ThemeColorShade(TH_BUT_NEUTRAL, -16);
+ ui_draw_but_curve_grid(but, zoomx, zoomy, offsx, offsy, 0.25f);
+ /* grid, every 1.0 step */
+ BIF_ThemeColorShade(TH_BUT_NEUTRAL, -24);
+ ui_draw_but_curve_grid(but, zoomx, zoomy, offsx, offsy, 1.0f);
+ /* axes */
+ BIF_ThemeColorShade(TH_BUT_NEUTRAL, -50);
+ glBegin(GL_LINES);
+ glVertex2f(but->x1, but->y1 + zoomy*(-offsy));
+ glVertex2f(but->x2, but->y1 + zoomy*(-offsy));
+ glVertex2f(but->x1 + zoomx*(-offsx), but->y1);
+ glVertex2f(but->x1 + zoomx*(-offsx), but->y2);
+ glEnd();
+
+ /* cfra option */
+ if(cumap->flag & CUMA_DRAW_CFRA) {
+ glColor3ub(0x60, 0xc0, 0x40);
+ glBegin(GL_LINES);
+ glVertex2f(but->x1 + zoomx*(cumap->black[0]-offsx), but->y1);
+ glVertex2f(but->x1 + zoomx*(cumap->black[0]-offsx), but->y2);
+ glEnd();
+ }
+
+ /* the curve */
+ BIF_ThemeColorBlend(TH_TEXT, TH_BUT_NEUTRAL, 0.35);
+ glEnable(GL_LINE_SMOOTH);
+ glEnable(GL_BLEND);
+ glBegin(GL_LINE_STRIP);
+
+ if(cuma->table==NULL)
+ curvemapping_changed(cumap, 0); /* 0 = no remove doubles */
+ cmp= cuma->table;
+
+ /* first point */
+ if((cuma->flag & CUMA_EXTEND_EXTRAPOLATE)==0)
+ glVertex2f(but->x1, but->y1 + zoomy*(cmp[0].y-offsy));
+ else {
+ fx= but->x1 + zoomx*(cmp[0].x-offsx + cuma->ext_in[0]);
+ fy= but->y1 + zoomy*(cmp[0].y-offsy + cuma->ext_in[1]);
+ glVertex2f(fx, fy);
+ }
+ for(a=0; a<=CM_TABLE; a++) {
+ fx= but->x1 + zoomx*(cmp[a].x-offsx);
+ fy= but->y1 + zoomy*(cmp[a].y-offsy);
+ glVertex2f(fx, fy);
+ }
+ /* last point */
+ if((cuma->flag & CUMA_EXTEND_EXTRAPOLATE)==0)
+ glVertex2f(but->x2, but->y1 + zoomy*(cmp[CM_TABLE].y-offsy));
+ else {
+ fx= but->x1 + zoomx*(cmp[CM_TABLE].x-offsx - cuma->ext_out[0]);
+ fy= but->y1 + zoomy*(cmp[CM_TABLE].y-offsy - cuma->ext_out[1]);
+ glVertex2f(fx, fy);
+ }
+ glEnd();
+ glDisable(GL_LINE_SMOOTH);
+ glDisable(GL_BLEND);
+
+ /* the points, use aspect to make them visible on edges */
+ cmp= cuma->curve;
+ glPointSize(3.0f);
+ bglBegin(GL_POINTS);
+ for(a=0; a<cuma->totpoint; a++) {
+ if(cmp[a].flag & SELECT)
+ BIF_ThemeColor(TH_TEXT_HI);
+ else
+ BIF_ThemeColor(TH_TEXT);
+ fac[0]= but->x1 + zoomx*(cmp[a].x-offsx);
+ fac[1]= but->y1 + zoomy*(cmp[a].y-offsy);
+ bglVertex2fv(fac);
+ }
+ bglEnd();
+ glPointSize(1.0f);
+
+ /* restore scissortest */
+ glScissor(scissor[0], scissor[1], scissor[2], scissor[3]);
+
+ /* outline */
+ BIF_ThemeColor(TH_BUT_OUTLINE);
+ fdrawbox(but->x1, but->y1, but->x2, but->y2);
+
+}
+
+static void ui_draw_roundbox(uiBut *but)
+{
+ glEnable(GL_BLEND);
+
+ BIF_ThemeColorShadeAlpha(TH_PANEL, but->a2, but->a2);
+
+ uiSetRoundBox(but->a1);
+ gl_round_box(GL_POLYGON, but->x1, but->y1, but->x2, but->y2, but->min);
+
+ glDisable(GL_BLEND);
+}
+
+
+/* nothing! */
+static void ui_draw_nothing(int type, int colorid, float asp, float x1, float y1, float x2, float y2, int flag)
+{
+}
+
+
+/* ************** EXTERN, called from interface.c ************* */
+/* ************** MAIN CALLBACK FUNCTION ************* */
+
+void ui_set_embossfunc(uiBut *but, int drawtype)
+{
+ // this aded for evaluating textcolor for example
+ but->dt= drawtype;
+
+ // not really part of standard minimal themes, just make sure it is set
+ but->sliderfunc= ui_draw_slider;
+
+ // standard builtin first:
+ if(but->type==LABEL || but->type==ROUNDBOX) but->embossfunc= ui_draw_nothing;
+ else if(but->type==PULLDOWN) but->embossfunc= ui_draw_pulldown_round;
+ else if(drawtype==UI_EMBOSSM) but->embossfunc= ui_draw_minimal;
+ else if(drawtype==UI_EMBOSSN) but->embossfunc= ui_draw_nothing;
+ else if(drawtype==UI_EMBOSSP) but->embossfunc= ui_draw_pulldown_item;
+ else if(drawtype==UI_EMBOSSR) but->embossfunc= ui_draw_round;
+ else {
+ int theme= BIF_GetThemeValue(TH_BUT_DRAWTYPE);
+
+ switch(theme) {
+
+ case TH_ROUNDED:
+ but->embossfunc= ui_draw_round;
+ break;
+ case TH_OLDSKOOL:
+ but->embossfunc= ui_draw_oldskool;
+ break;
+ case TH_MINIMAL:
+ but->embossfunc= ui_draw_minimal;
+ break;
+ case TH_SHADED:
+ default:
+ but->embossfunc= ui_draw_default;
+ but->sliderfunc= ui_default_slider;
+ break;
+ }
+ }
+
+ // note: if you want aligning, adapt the call uiBlockEndAlign in interface.c
+}
+
+void ui_draw_but(uiBut *but)
+{
+ double value;
+ float x1, x2, y1, y2, fac;
+
+ if(but==NULL) return;
+
+ /* signal for frontbuf flush buttons and menus, not when normal drawing */
+ if(but->block->in_use) ui_block_set_flush(but->block, but);
+
+ switch (but->type) {
+
+ case NUMSLI:
+ case HSVSLI:
+
+ but->embossfunc(but->type, but->themecol, but->aspect, but->x1, but->y1, but->x2, but->y2, but->flag);
+ ui_draw_text_icon(but);
+
+ x1= (but->x1+but->x2)/2;
+ x2= but->x2 - 5.0*but->aspect;
+ y1= but->y1 + 2.0*but->aspect;
+ y2= but->y2 - 2.0*but->aspect;
+
+ value= ui_get_but_val(but);
+ fac= (value-but->min)*(x2-x1)/(but->max - but->min);
+
+ but->sliderfunc(but->themecol, fac, but->aspect, x1, y1, x2, y2, but->flag);
+ break;
+
+ case SEPR:
+ // only background
+ break;
+
+ case COL:
+ ui_draw_but_COL(but); // black box with color
+ break;
+
+ case HSVCUBE:
+ ui_draw_but_HSVCUBE(but); // box for colorpicker, three types
+ break;
+
+#ifdef INTERNATIONAL
+ case CHARTAB:
+ value= ui_get_but_val(but);
+ ui_draw_but_CHARTAB(but);
+ break;
+#endif
+
+ case LINK:
+ case INLINK:
+ ui_draw_icon(but, but->icon, 0);
+ break;
+
+ case ROUNDBOX:
+ ui_draw_roundbox(but);
+ break;
+
+ case BUT_COLORBAND:
+ ui_draw_but_COLORBAND(but);
+ break;
+ case BUT_NORMAL:
+ ui_draw_but_NORMAL(but);
+ break;
+ case BUT_CURVE:
+ ui_draw_but_CURVE(but);
+ break;
+
+ default:
+ but->embossfunc(but->type, but->themecol, but->aspect, but->x1, but->y1, but->x2, but->y2, but->flag);
+ ui_draw_text_icon(but);
+
+ }
+}
+
+void ui_dropshadow(rctf *rct, float radius, float aspect, int select)
+{
+ float rad;
+ float a;
+ char alpha= 2;
+
+ glEnable(GL_BLEND);
+
+ if(radius > (rct->ymax-rct->ymin-10.0f)/2.0f)
+ rad= (rct->ymax-rct->ymin-10.0f)/2.0f;
+ else
+ rad= radius;
+
+ if(select) a= 12.0f*aspect; else a= 12.0f*aspect;
+ for(; a>0.0f; a-=aspect) {
+ /* alpha ranges from 2 to 20 or so */
+ glColor4ub(0, 0, 0, alpha);
+ alpha+= 2;
+
+ gl_round_box(GL_POLYGON, rct->xmin - a, rct->ymin - a, rct->xmax + a, rct->ymax-10.0f + a, rad+a);
+ }
+
+ /* outline emphasis */
+ glEnable( GL_LINE_SMOOTH );
+ glColor4ub(0, 0, 0, 100);
+ gl_round_box(GL_LINE_LOOP, rct->xmin-0.5f, rct->ymin-0.5f, rct->xmax+0.5f, rct->ymax+0.5f, radius);
+ glDisable( GL_LINE_SMOOTH );
+
+ glDisable(GL_BLEND);
+}
diff --git a/source/blender/src/interface_icons.c b/source/blender/src/interface_icons.c
new file mode 100644
index 00000000000..d93834d8d8a
--- /dev/null
+++ b/source/blender/src/interface_icons.c
@@ -0,0 +1,1074 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef WIN32
+#include <unistd.h>
+#else
+#include <io.h>
+#include <direct.h>
+#endif
+#include "MEM_guardedalloc.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+#include "BLI_storage_types.h"
+
+#include "DNA_material_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_world_types.h"
+#include "DNA_object_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_image_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_world_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_image_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BKE_global.h"
+#include "BKE_material.h"
+#include "BKE_texture.h"
+#include "BKE_world.h"
+#include "BKE_image.h"
+#include "BKE_object.h"
+#include "BKE_utildefines.h"
+#include "BKE_icons.h"
+#include "BKE_packedFile.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+#include "BIF_interface.h"
+#include "BIF_interface_icons.h"
+#include "BIF_previewrender.h"
+#include "BIF_screen.h"
+#include "BIF_resources.h" /* elubie: should be removed once the enum for the ICONS is in BIF_preview_icons.h */
+
+#include "interface.h"
+
+#include "PIL_time.h"
+
+#include "blendef.h" // CLAMP
+#include "datatoc.h"
+#include "mydevice.h"
+
+#define ICON_IMAGE_W 512
+#define ICON_IMAGE_H 256
+
+#define ICON_GRID_COLS 25
+#define ICON_GRID_ROWS 12
+
+#define ICON_GRID_MARGIN 5
+#define ICON_GRID_W 15
+#define ICON_GRID_H 16
+
+typedef struct IconImage {
+ int w;
+ int h;
+ unsigned int *rect;
+} IconImage;
+
+typedef struct DrawInfo {
+ int w;
+ int h;
+ float aspect;
+ VectorDrawFunc drawFunc; /* If drawFunc is defined then it is a vector icon, otherwise use rect */
+ IconImage* icon;
+} DrawInfo;
+
+/* ******************* STATIC LOCAL VARS ******************* */
+/* static here to cache results of icon directory scan, so it's not
+ * scanning the filesystem each time the menu is drawn */
+static struct ListBase iconfilelist = {0, 0};
+
+
+static int preview_render_size(int miplevel);
+
+/* **************************************************** */
+
+static void def_internal_icon(ImBuf *bbuf, int icon_id, int xofs, int yofs)
+{
+ Icon *new_icon = NULL;
+ IconImage *iimg = NULL;
+ DrawInfo *di;
+ int y = 0;
+
+ new_icon = MEM_callocN(sizeof(Icon), "texicon");
+
+ new_icon->obj = 0; /* icon is not for library object */
+ new_icon->type = 0;
+
+ di = MEM_callocN(sizeof(DrawInfo), "drawinfo");
+ di->drawFunc = 0;
+ di->w = ICON_DEFAULT_HEIGHT;
+ di->h = ICON_DEFAULT_HEIGHT;
+ di->aspect = 1.0f;
+
+ iimg = MEM_mallocN(sizeof(IconImage), "icon_img");
+ iimg->rect = MEM_mallocN(ICON_DEFAULT_HEIGHT*ICON_DEFAULT_HEIGHT*sizeof(unsigned int), "icon_rect");
+ iimg->w = ICON_DEFAULT_HEIGHT;
+ iimg->h = ICON_DEFAULT_HEIGHT;
+
+ /* Here we store the rect in the icon - same as before */
+ for (y=0; y<ICON_DEFAULT_HEIGHT; y++) {
+ memcpy(&iimg->rect[y*ICON_DEFAULT_HEIGHT], &bbuf->rect[(y+yofs)*512+xofs], ICON_DEFAULT_HEIGHT*sizeof(int));
+ }
+
+ di->icon = iimg;
+
+ new_icon->drawinfo_free = BIF_icons_free_drawinfo;
+ new_icon->drawinfo = di;
+
+ BKE_icon_set(icon_id, new_icon);
+}
+
+static void def_internal_vicon( int icon_id, VectorDrawFunc drawFunc)
+{
+ Icon *new_icon = NULL;
+ DrawInfo* di;
+
+ new_icon = MEM_callocN(sizeof(Icon), "texicon");
+
+ new_icon->obj = 0; /* icon is not for library object */
+ new_icon->type = 0;
+
+ di = MEM_callocN(sizeof(DrawInfo), "drawinfo");
+ di->drawFunc =drawFunc;
+ di->w = ICON_DEFAULT_HEIGHT;
+ di->h = ICON_DEFAULT_HEIGHT;
+ di->aspect = 1.0f;
+ di->icon = NULL;
+
+ new_icon->drawinfo_free = 0;
+ new_icon->drawinfo = di;
+
+ BKE_icon_set(icon_id, new_icon);
+}
+
+/* Vector Icon Drawing Routines */
+
+ /* Utilities */
+
+static void viconutil_set_point(GLint pt[2], int x, int y)
+{
+ pt[0] = x;
+ pt[1] = y;
+}
+
+static void viconutil_draw_tri(GLint (*pts)[2])
+{
+ glBegin(GL_TRIANGLES);
+ glVertex2iv(pts[0]);
+ glVertex2iv(pts[1]);
+ glVertex2iv(pts[2]);
+ glEnd();
+}
+
+#if 0
+static void viconutil_draw_quad(GLint (*pts)[2])
+{
+ glBegin(GL_QUADS);
+ glVertex2iv(pts[0]);
+ glVertex2iv(pts[1]);
+ glVertex2iv(pts[2]);
+ glVertex2iv(pts[3]);
+ glEnd();
+}
+#endif
+
+static void viconutil_draw_lineloop(GLint (*pts)[2], int numPoints)
+{
+ int i;
+
+ glBegin(GL_LINE_LOOP);
+ for (i=0; i<numPoints; i++) {
+ glVertex2iv(pts[i]);
+ }
+ glEnd();
+}
+
+static void viconutil_draw_lineloop_smooth(GLint (*pts)[2], int numPoints)
+{
+ glEnable(GL_LINE_SMOOTH);
+ viconutil_draw_lineloop(pts, numPoints);
+ glDisable(GL_LINE_SMOOTH);
+}
+
+static void viconutil_draw_points(GLint (*pts)[2], int numPoints, int pointSize)
+{
+ int i;
+
+ glBegin(GL_QUADS);
+ for (i=0; i<numPoints; i++) {
+ int x = pts[i][0], y = pts[i][1];
+
+ glVertex2i(x-pointSize,y-pointSize);
+ glVertex2i(x+pointSize,y-pointSize);
+ glVertex2i(x+pointSize,y+pointSize);
+ glVertex2i(x-pointSize,y+pointSize);
+ }
+ glEnd();
+}
+
+ /* Drawing functions */
+
+static void vicon_x_draw(int x, int y, int w, int h, float alpha)
+{
+ x += 3;
+ y += 3;
+ w -= 6;
+ h -= 6;
+
+ glEnable( GL_LINE_SMOOTH );
+
+ glLineWidth(2.5);
+
+ glColor4f(0.0, 0.0, 0.0, alpha);
+ glBegin(GL_LINES);
+ glVertex2i(x ,y );
+ glVertex2i(x+w,y+h);
+ glVertex2i(x+w,y );
+ glVertex2i(x ,y+h);
+ glEnd();
+
+ glLineWidth(1.0);
+
+ glDisable( GL_LINE_SMOOTH );
+}
+
+static void vicon_view3d_draw(int x, int y, int w, int h, float alpha)
+{
+ int cx = x + w/2;
+ int cy = y + h/2;
+ int d = MAX2(2, h/3);
+
+ glColor4f(0.5, 0.5, 0.5, alpha);
+ glBegin(GL_LINES);
+ glVertex2i(x , cy-d);
+ glVertex2i(x+w, cy-d);
+ glVertex2i(x , cy+d);
+ glVertex2i(x+w, cy+d);
+
+ glVertex2i(cx-d, y );
+ glVertex2i(cx-d, y+h);
+ glVertex2i(cx+d, y );
+ glVertex2i(cx+d, y+h);
+ glEnd();
+
+ glColor4f(0.0, 0.0, 0.0, alpha);
+ glBegin(GL_LINES);
+ glVertex2i(x , cy);
+ glVertex2i(x+w, cy);
+ glVertex2i(cx, y );
+ glVertex2i(cx, y+h);
+ glEnd();
+}
+
+static void vicon_edit_draw(int x, int y, int w, int h, float alpha)
+{
+ GLint pts[4][2];
+
+ viconutil_set_point(pts[0], x+3 , y+3 );
+ viconutil_set_point(pts[1], x+w-3, y+3 );
+ viconutil_set_point(pts[2], x+w-3, y+h-3);
+ viconutil_set_point(pts[3], x+3 , y+h-3);
+
+ glColor4f(0.0, 0.0, 0.0, alpha);
+ viconutil_draw_lineloop(pts, 4);
+
+ glColor3f(1, 1, 0.0);
+ viconutil_draw_points(pts, 4, 1);
+}
+
+static void vicon_editmode_hlt_draw(int x, int y, int w, int h, float alpha)
+{
+ GLint pts[3][2];
+
+ viconutil_set_point(pts[0], x+w/2, y+h-2);
+ viconutil_set_point(pts[1], x+3, y+4);
+ viconutil_set_point(pts[2], x+w-3, y+4);
+
+ glColor4f(0.5, 0.5, 0.5, alpha);
+ viconutil_draw_tri(pts);
+
+ glColor4f(0.0, 0.0, 0.0, 1);
+ viconutil_draw_lineloop_smooth(pts, 3);
+
+ glColor3f(1, 1, 0.0);
+ viconutil_draw_points(pts, 3, 1);
+}
+
+static void vicon_editmode_dehlt_draw(int x, int y, int w, int h, float alpha)
+{
+ GLint pts[3][2];
+
+ viconutil_set_point(pts[0], x+w/2, y+h-2);
+ viconutil_set_point(pts[1], x+3, y+4);
+ viconutil_set_point(pts[2], x+w-3, y+4);
+
+ glColor4f(0.0, 0.0, 0.0, 1);
+ viconutil_draw_lineloop_smooth(pts, 3);
+
+ glColor3f(.9, .9, .9);
+ viconutil_draw_points(pts, 3, 1);
+}
+
+static void vicon_disclosure_tri_right_draw(int x, int y, int w, int h, float alpha)
+{
+ GLint pts[3][2];
+ int cx = x+w/2;
+ int cy = y+w/2;
+ int d = w/3, d2 = w/5;
+
+ viconutil_set_point(pts[0], cx-d2, cy+d);
+ viconutil_set_point(pts[1], cx-d2, cy-d);
+ viconutil_set_point(pts[2], cx+d2, cy);
+
+ glShadeModel(GL_SMOOTH);
+ glBegin(GL_TRIANGLES);
+ glColor4f(0.8, 0.8, 0.8, alpha);
+ glVertex2iv(pts[0]);
+ glVertex2iv(pts[1]);
+ glColor4f(0.3, 0.3, 0.3, alpha);
+ glVertex2iv(pts[2]);
+ glEnd();
+ glShadeModel(GL_FLAT);
+
+ glColor4f(0.0, 0.0, 0.0, 1);
+ viconutil_draw_lineloop_smooth(pts, 3);
+}
+
+static void vicon_disclosure_tri_down_draw(int x, int y, int w, int h, float alpha)
+{
+ GLint pts[3][2];
+ int cx = x+w/2;
+ int cy = y+w/2;
+ int d = w/3, d2 = w/5;
+
+ viconutil_set_point(pts[0], cx+d, cy+d2);
+ viconutil_set_point(pts[1], cx-d, cy+d2);
+ viconutil_set_point(pts[2], cx, cy-d2);
+
+ glShadeModel(GL_SMOOTH);
+ glBegin(GL_TRIANGLES);
+ glColor4f(0.8, 0.8, 0.8, alpha);
+ glVertex2iv(pts[0]);
+ glVertex2iv(pts[1]);
+ glColor4f(0.3, 0.3, 0.3, alpha);
+ glVertex2iv(pts[2]);
+ glEnd();
+ glShadeModel(GL_FLAT);
+
+ glColor4f(0.0, 0.0, 0.0, 1);
+ viconutil_draw_lineloop_smooth(pts, 3);
+}
+
+static void vicon_move_up_draw(int x, int y, int w, int h, float alpha)
+{
+ int d=-2;
+
+ glEnable(GL_LINE_SMOOTH);
+ glLineWidth(1);
+ glColor3f(0.0, 0.0, 0.0);
+
+ glBegin(GL_LINE_STRIP);
+ glVertex2i(x+w/2-d*2, y+h/2+d);
+ glVertex2i(x+w/2, y+h/2-d + 1);
+ glVertex2i(x+w/2+d*2, y+h/2+d);
+ glEnd();
+
+ glLineWidth(1.0);
+ glDisable(GL_LINE_SMOOTH);
+}
+
+static void vicon_move_down_draw(int x, int y, int w, int h, float alpha)
+{
+ int d=2;
+
+ glEnable(GL_LINE_SMOOTH);
+ glLineWidth(1);
+ glColor3f(0.0, 0.0, 0.0);
+
+ glBegin(GL_LINE_STRIP);
+ glVertex2i(x+w/2-d*2, y+h/2+d);
+ glVertex2i(x+w/2, y+h/2-d - 1);
+ glVertex2i(x+w/2+d*2, y+h/2+d);
+ glEnd();
+
+ glLineWidth(1.0);
+ glDisable(GL_LINE_SMOOTH);
+}
+
+/***/
+
+
+/* this only works for the hardcoded buttons image, turning the grey AA pixels to alpha, and slight off-grey to half alpha */
+#if 0
+static void clear_transp_rect_soft(unsigned char *transp, unsigned char *rect, int w, int h, int rowstride)
+{
+ int x, y, val;
+
+ for (y=1; y<h-1; y++) {
+ unsigned char *row0= &rect[(y-1)*rowstride];
+ unsigned char *row= &rect[y*rowstride];
+ unsigned char *row1= &rect[(y+1)*rowstride];
+ for (x=1; x<w-1; x++) {
+ unsigned char *pxl0= &row0[x*4];
+ unsigned char *pxl= &row[x*4];
+ unsigned char *pxl1= &row1[x*4];
+
+ if(pxl[3]!=0) {
+ val= (abs(pxl[0]-transp[0]) + abs(pxl[1]-transp[1]) + abs(pxl[2]-transp[2]))/3;
+ if(val<20) {
+ pxl[3]= 128;
+ }
+ else if(val<50) {
+ // one of pixels surrounding has alpha null?
+ if(pxl[3-4]==0 || pxl[3+4]==0 || pxl0[3]==0 || pxl1[3]==0) {
+
+ if(pxl[0]>val) pxl[0]-= val; else pxl[0]= 0;
+ if(pxl[1]>val) pxl[1]-= val; else pxl[1]= 0;
+ if(pxl[2]>val) pxl[2]-= val; else pxl[2]= 0;
+
+ pxl[3]= 128;
+ }
+ }
+ }
+ }
+ }
+}
+#endif
+
+static void clear_icon_grid_margins(unsigned char *rect, int w, int h)
+{
+ int x, y;
+ int xoffs=ICON_GRID_W+ICON_GRID_MARGIN;
+ int yoffs=ICON_GRID_H+ICON_GRID_MARGIN;
+
+ for (y=0; y<h; y++) {
+ unsigned char *row= &rect[y*w*4];
+
+ for (x=0; x<w; x++) {
+ unsigned char *pxl= &row[x*4];
+
+ if ((x % xoffs < ICON_GRID_MARGIN-2) || (x % xoffs > ICON_GRID_W+2))
+ pxl[3] = 0; //alpha channel == x+3
+ else if ((y % yoffs < ICON_GRID_MARGIN-2) || (y % yoffs > ICON_GRID_H+2))
+ pxl[3] = 0;
+ }
+ }
+}
+
+static void prepare_internal_icons(ImBuf *bbuf)
+{
+
+ unsigned char *back= (unsigned char *)bbuf->rect;
+
+ /* this sets the icon grid margin area outside of icon to zero alpha */
+ clear_icon_grid_margins(back, bbuf->x, bbuf->y);
+
+ /* hack! */
+#if 0
+ for (y=0; y<12; y++) {
+ for (x=0; x<21; x++) {
+ unsigned char *start= ((unsigned char*) bbuf->rect) + (y*21 + 3)*rowstride + (x*20 + 3)*4;
+ /* this sets backdrop of icon to zero alpha */
+ transp[0]= start[0];
+ transp[1]= start[1];
+ transp[2]= start[2];
+ transp[3]= start[3];
+ clear_transp_rect(transp, start, 20, 21, rowstride);
+ clear_transp_rect_soft(transp, start, 20, 21, rowstride);
+
+ }
+ }
+#endif
+}
+
+
+static void init_internal_icons()
+{
+ bTheme *btheme= U.themes.first;
+ ImBuf *bbuf;
+ int x, y;
+ char iconfilestr[FILE_MAXDIR+FILE_MAXFILE];
+ char filenamestr[FILE_MAXFILE+16]; // 16 == strlen(".blender/icons/")+1
+
+ if ((btheme!=NULL) && (strlen(btheme->tui.iconfile) > 0)) {
+
+#ifdef WIN32
+ sprintf(filenamestr, "icons/%s", btheme->tui.iconfile);
+#else
+ sprintf(filenamestr, ".blender/icons/%s", btheme->tui.iconfile);
+#endif
+
+ BLI_make_file_string("/", iconfilestr, BLI_gethome(), filenamestr);
+
+ if (BLI_exists(iconfilestr)) {
+ bbuf = IMB_loadiffname(iconfilestr, IB_rect);
+ } else {
+ bbuf = IMB_ibImageFromMemory((int *)datatoc_blenderbuttons, datatoc_blenderbuttons_size, IB_rect);
+ }
+ } else {
+ bbuf = IMB_ibImageFromMemory((int *)datatoc_blenderbuttons, datatoc_blenderbuttons_size, IB_rect);
+ }
+
+ prepare_internal_icons(bbuf);
+
+ for (y=0; y<ICON_GRID_ROWS; y++) {
+ for (x=0; x<ICON_GRID_COLS; x++) {
+ def_internal_icon(bbuf, BIFICONID_FIRST + y*ICON_GRID_COLS + x,
+ x*(ICON_GRID_W+ICON_GRID_MARGIN)+3,
+ y*(ICON_GRID_H+ICON_GRID_MARGIN)+3);
+ }
+ }
+
+ def_internal_vicon(VICON_VIEW3D, vicon_view3d_draw);
+ def_internal_vicon(VICON_EDIT, vicon_edit_draw);
+ def_internal_vicon(VICON_EDITMODE_DEHLT, vicon_editmode_dehlt_draw);
+ def_internal_vicon(VICON_EDITMODE_HLT, vicon_editmode_hlt_draw);
+ def_internal_vicon(VICON_DISCLOSURE_TRI_RIGHT, vicon_disclosure_tri_right_draw);
+ def_internal_vicon(VICON_DISCLOSURE_TRI_DOWN, vicon_disclosure_tri_down_draw);
+ def_internal_vicon(VICON_MOVE_UP, vicon_move_up_draw);
+ def_internal_vicon(VICON_MOVE_DOWN, vicon_move_down_draw);
+ def_internal_vicon(VICON_X, vicon_x_draw);
+
+ IMB_freeImBuf(bbuf);
+}
+
+
+static void init_iconfile_list(struct ListBase *list)
+{
+ IconFile *ifile;
+ ImBuf *bbuf= NULL;
+ struct direntry *dir;
+ int restoredir = 1; /* restore to current directory */
+ int totfile, i, index=1;
+ int ifilex, ifiley;
+ char icondirstr[FILE_MAX];
+ char iconfilestr[FILE_MAX+16]; /* allow 256 chars for file+dir */
+ char olddir[FILE_MAX];
+
+ list->first = list->last = NULL;
+
+#ifdef WIN32
+ BLI_make_file_string("/", icondirstr, BLI_gethome(), "icons");
+#else
+ BLI_make_file_string("/", icondirstr, BLI_gethome(), ".blender/icons");
+#endif
+
+ if(BLI_exists(icondirstr)==0)
+ return;
+
+ /* since BLI_getdir changes the current working directory, restore it
+ back to old value afterwards */
+ if(!BLI_getwdN(olddir))
+ restoredir = 0;
+ totfile = BLI_getdir(icondirstr, &dir);
+ if (restoredir)
+ chdir(olddir);
+
+ for(i=0; i<totfile; i++) {
+ if( (dir[i].type & S_IFREG) ) {
+ char *filename = dir[i].relname;
+
+ if(BLI_testextensie(filename, ".png")) {
+
+ /* check to see if the image is the right size, continue if not */
+ /* copying strings here should go ok, assuming that we never get back
+ a complete path to file longer than 256 chars */
+ sprintf(iconfilestr, "%s/%s", icondirstr, filename);
+ if(BLI_exists(iconfilestr)) bbuf = IMB_loadiffname(iconfilestr, IB_rect);
+
+ ifilex = bbuf->x;
+ ifiley = bbuf->y;
+ IMB_freeImBuf(bbuf);
+
+ if ((ifilex != ICON_IMAGE_W) || (ifiley != ICON_IMAGE_H))
+ continue;
+
+ /* found a potential icon file, so make an entry for it in the cache list */
+ ifile = MEM_callocN(sizeof(IconFile), "IconFile");
+
+ BLI_strncpy(ifile->filename, filename, sizeof(ifile->filename));
+ ifile->index = index;
+
+ BLI_addtail(list, ifile);
+
+ index++;
+ }
+ }
+ }
+
+ /* free temporary direntry structure that's been created by BLI_getdir() */
+ i= totfile-1;
+
+ for(; i>=0; i--){
+ MEM_freeN(dir[i].relname);
+ if (dir[i].string) MEM_freeN(dir[i].string);
+ }
+ free(dir);
+ dir= 0;
+}
+
+static void free_iconfile_list(struct ListBase *list)
+{
+ IconFile *ifile=NULL, *next_ifile=NULL;
+
+ for(ifile=list->first; ifile; ifile=next_ifile) {
+ next_ifile = ifile->next;
+ BLI_freelinkN(list, ifile);
+ }
+}
+
+int BIF_iconfile_get_index(char *filename)
+{
+ IconFile *ifile;
+ ListBase *list=&(iconfilelist);
+
+ for(ifile=list->first; ifile; ifile=ifile->next) {
+ if ( BLI_streq(filename, ifile->filename)) {
+ return ifile->index;
+ }
+ }
+
+ return 0;
+}
+
+ListBase *BIF_iconfile_list(void)
+{
+ ListBase *list=&(iconfilelist);
+
+ return list;
+}
+
+
+void BIF_icons_free()
+{
+ free_iconfile_list(&iconfilelist);
+ BKE_icons_free();
+}
+
+void BIF_icons_free_drawinfo(void *drawinfo)
+{
+ DrawInfo *di = drawinfo;
+
+ if (di)
+ {
+ if (di->icon) {
+ MEM_freeN(di->icon->rect);
+ MEM_freeN(di->icon);
+ }
+ MEM_freeN(di);
+ }
+}
+
+static DrawInfo *icon_create_drawinfo()
+{
+ DrawInfo *di = NULL;
+
+ di = MEM_callocN(sizeof(DrawInfo), "di_icon");
+
+ di->drawFunc = 0;
+ di->w = ICON_DEFAULT_HEIGHT;
+ di->h = ICON_DEFAULT_HEIGHT;
+ di->icon = NULL;
+ di->aspect = 1.0f;
+
+ return di;
+}
+
+int BIF_icon_get_width(int icon_id)
+{
+ Icon *icon = NULL;
+ DrawInfo *di = NULL;
+
+ icon = BKE_icon_get(icon_id);
+
+ if (!icon) {
+ printf("BIF_icon_get_width: Internal error, no icon for icon ID: %d\n", icon_id);
+ return 0;
+ }
+
+ di = (DrawInfo *)icon->drawinfo;
+ if (!di) {
+ di = icon_create_drawinfo();
+ icon->drawinfo = di;
+ }
+
+ if (di)
+ return di->w;
+
+ return 0;
+}
+
+int BIF_icon_get_height(int icon_id)
+{
+ Icon *icon = NULL;
+ DrawInfo *di = NULL;
+
+ icon = BKE_icon_get(icon_id);
+
+ if (!icon) {
+ printf("BIF_icon_get_width: Internal error, no icon for icon ID: %d\n", icon_id);
+ return 0;
+ }
+
+ di = (DrawInfo*)icon->drawinfo;
+
+ if (!di) {
+ di = icon_create_drawinfo();
+ icon->drawinfo = di;
+ }
+
+ if (di)
+ return di->h;
+
+ return 0;
+}
+
+void BIF_icons_init(int first_dyn_id)
+{
+ init_iconfile_list(&iconfilelist);
+ BKE_icons_init(first_dyn_id);
+ init_internal_icons();
+}
+
+static void icon_copy_rect(ImBuf *ibuf, unsigned int w, unsigned int h, unsigned int *rect)
+{
+ struct ImBuf *ima;
+ unsigned int *drect, *srect;
+ float scaledx, scaledy;
+ short ex, ey, dx, dy;
+
+ /* paranoia test */
+ if(ibuf==NULL || (ibuf->rect==NULL && ibuf->rect_float==NULL))
+ return;
+
+ /* waste of cpu cyles... but the imbuf API has no other way to scale fast (ton) */
+ ima = IMB_dupImBuf(ibuf);
+
+ if (!ima)
+ return;
+
+ if (ima->x > ima->y) {
+ scaledx = (float)w;
+ scaledy = ( (float)ima->y/(float)ima->x )*(float)w;
+ }
+ else {
+ scaledx = ( (float)ima->x/(float)ima->y )*(float)h;
+ scaledy = (float)h;
+ }
+
+ ex = (short)scaledx;
+ ey = (short)scaledy;
+
+ dx = (w - ex) / 2;
+ dy = (h - ey) / 2;
+
+ IMB_scalefastImBuf(ima, ex, ey);
+
+ /* if needed, convert to 32 bits */
+ if(ima->rect==NULL)
+ IMB_rect_from_float(ima);
+
+ srect = ima->rect;
+ drect = rect;
+
+ drect+= dy*w+dx;
+ for (;ey > 0; ey--){
+ memcpy(drect,srect, ex * sizeof(int));
+ drect += w;
+ srect += ima->x;
+ }
+ IMB_freeImBuf(ima);
+}
+
+static void icon_create_mipmap(struct PreviewImage* prv_img, int miplevel)
+{
+ unsigned int size = preview_render_size(miplevel);
+
+ if (!prv_img) {
+ printf("Error: requested preview image does not exist");
+ }
+ if (!prv_img->rect[miplevel]) {
+ prv_img->w[miplevel] = size;
+ prv_img->h[miplevel] = size;
+ prv_img->changed[miplevel] = 1;
+ prv_img->rect[miplevel] = MEM_callocN(size*size*sizeof(unsigned int), "prv_rect");
+ }
+}
+
+/* create single icon from jpg, png etc. */
+static void icon_from_image(Image *img, int miplevel)
+{
+ unsigned int pr_size;
+ short image_loaded = 0;
+ struct ImBuf* ibuf=NULL;
+ PreviewImage* pi;
+
+ /* img->ok is zero when Image cannot load */
+ if (img==NULL || img->ok==0)
+ return;
+
+ /* elubie: this needs to be changed: here image is always loaded if not
+ already there. Very expensive for large images. Need to find a way to
+ only get existing ibuf */
+ ibuf = BKE_image_get_ibuf(img, NULL);
+ if(ibuf==NULL || ibuf->rect==NULL) {
+ return;
+ }
+
+ pi = BKE_previewimg_get((ID*)img);
+
+ if(!pi) {
+ printf("preview image could'nt be allocated");
+ return;
+ }
+ /* we can only create the preview rect here, since loading possibly deallocated
+ old preview */
+ icon_create_mipmap(pi, miplevel);
+
+ pr_size = img->preview->w[miplevel]*img->preview->h[miplevel]*sizeof(unsigned int);
+
+ image_loaded = 1;
+ icon_copy_rect(ibuf, img->preview->w[miplevel], img->preview->h[miplevel], img->preview->rect[miplevel]);
+}
+
+static void set_alpha(char* cp, int sizex, int sizey, char alpha)
+{
+ int x,y;
+ for(y=0; y<sizey; y++) {
+ for(x=0; x<sizex; x++, cp+=4) {
+ cp[3]= alpha;
+ }
+ }
+}
+
+/* only called when icon has changed */
+/* only call with valid pointer from BIF_icon_draw */
+static void icon_set_image(ID *id, DrawInfo *di, PreviewImage* prv_img, int miplevel)
+{
+ RenderInfo ri;
+ unsigned int pr_size = 0;
+
+ if (!di) return;
+
+ if (!prv_img) {
+ printf("No preview image for this ID: %s\n", id->name);
+ return;
+ }
+
+ /* no drawing (see last parameter doDraw, just calculate preview image
+ - hopefully small enough to be fast */
+ if (GS(id->name) == ID_IM)
+ icon_from_image((struct Image*)id, miplevel);
+ else {
+ /* create the preview rect */
+ icon_create_mipmap(prv_img, miplevel);
+
+ ri.curtile= 0;
+ ri.tottile= 0;
+ ri.rect = NULL;
+ ri.pr_rectx = prv_img->w[miplevel];
+ ri.pr_recty = prv_img->h[miplevel];
+
+ pr_size = ri.pr_rectx*ri.pr_recty*sizeof(unsigned int);
+
+ BIF_previewrender(id, &ri, NULL, PR_ICON_RENDER);
+
+ /* world is rendered with alpha=0, so it wasn't displayed
+ this could be render option for sky to, for later */
+ if (GS(id->name) == ID_WO) {
+ set_alpha( (char*) ri.rect, ri.pr_rectx, ri.pr_recty, 255);
+ }
+ else if (GS(id->name) == ID_MA) {
+ Material* mat = (Material*)id;
+ if (mat->mode & MA_HALO) {
+ set_alpha( (char*) ri.rect, ri.pr_rectx, ri.pr_recty, 255);
+ }
+ }
+
+ if (ri.rect) {
+ memcpy(prv_img->rect[miplevel], ri.rect, pr_size);
+
+ /* and clean up */
+ MEM_freeN(ri.rect);
+ ri.rect = 0;
+ }
+ }
+}
+
+static void icon_draw_rect(float x, float y, int w, int h, float aspect, int rw, int rh, unsigned int *rect)
+{
+ ui_rasterpos_safe(x, y, aspect);
+
+ if(w<1 || h<1) {
+ printf("what the heck!\n");
+ }
+ /* rect contains image in 'rendersize', we only scale if needed */
+ else if(rw!=w && rh!=h) {
+ ImBuf *ima;
+ if(w>2000 || h>2000) { /* something has gone wrong! */
+ printf("insane icon size w=%d h=%d\n",w,h);
+ return;
+ }
+ /* first allocate imbuf for scaling and copy preview into it */
+ ima = IMB_allocImBuf(rw, rh, 32, IB_rect, 0);
+ memcpy(ima->rect, rect, rw*rh*sizeof(unsigned int));
+
+ /* scale it */
+ IMB_scaleImBuf(ima, w, h);
+ glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, ima->rect);
+
+ IMB_freeImBuf(ima);
+ }
+ else
+ glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, rect);
+}
+
+/* Render size for preview images at level miplevel */
+static int preview_render_size(int miplevel)
+{
+ switch (miplevel) {
+ case 0: return 32;
+ case 1: return PREVIEW_DEFAULT_HEIGHT;
+ }
+ return 0;
+}
+
+/* Drawing size for preview images at level miplevel */
+static int preview_size(int miplevel)
+{
+ switch (miplevel) {
+ case 0: return ICON_DEFAULT_HEIGHT;
+ case 1: return PREVIEW_DEFAULT_HEIGHT;
+ }
+ return 0;
+}
+
+
+static void icon_draw_mipmap(float x, float y, int icon_id, float aspect, int miplevel, int nocreate)
+{
+ Icon *icon = NULL;
+ DrawInfo *di = NULL;
+ int draw_size = preview_size(miplevel);
+
+ icon = BKE_icon_get(icon_id);
+
+ if (!icon) {
+ printf("BIF_icon_set_aspect: Internal error, no icon for icon ID: %d\n", icon_id);
+ return;
+ }
+
+ di = (DrawInfo*)icon->drawinfo;
+
+ if (!di) {
+ di = icon_create_drawinfo();
+
+ icon->drawinfo = di;
+ icon->drawinfo_free = BIF_icons_free_drawinfo;
+ }
+
+ di->aspect = aspect;
+ /* scale width and height according to aspect */
+ di->w = (int)(draw_size/di->aspect + 0.5f);
+ di->h = (int)(draw_size/di->aspect + 0.5f);
+
+ if (di->drawFunc) {
+ /* vector icons use the uiBlock transformation, they are not drawn
+ with untransformed coordinates like the other icons */
+ di->drawFunc(x, y, ICON_DEFAULT_HEIGHT, ICON_DEFAULT_HEIGHT, 1.0f);
+ }
+ else if (di->icon) {
+ /* it is a builtin icon */
+ if (!di->icon->rect) return; /* something has gone wrong! */
+
+ icon_draw_rect(x,y,di->w, di->h, di->aspect, di->icon->w, di->icon->h, di->icon->rect);
+ }
+ else {
+ PreviewImage* pi = BKE_previewimg_get((ID*)icon->obj);
+
+ if (pi) {
+ if (!nocreate && (pi->changed[miplevel] ||!pi->rect[miplevel])) /* changed only ever set by dynamic icons */
+ {
+ waitcursor(1);
+ /* create the preview rect if necessary */
+ icon_set_image((ID*)icon->obj, icon->drawinfo, pi, miplevel);
+ pi->changed[miplevel] = 0;
+ waitcursor(0);
+ }
+
+ if (!pi->rect[miplevel]) return; /* something has gone wrong! */
+
+ icon_draw_rect(x,y,di->w, di->h, di->aspect, pi->w[miplevel], pi->h[miplevel], pi->rect[miplevel]);
+ }
+ }
+}
+
+void BIF_icon_draw_aspect(float x, float y, int icon_id, float aspect)
+{
+ icon_draw_mipmap(x,y,icon_id, aspect, PREVIEW_MIPMAP_ZERO, 0);
+}
+
+void BIF_icon_draw(float x, float y, int icon_id)
+{
+ BIF_icon_draw_aspect(x, y, icon_id, 1.0f);
+}
+
+void BIF_icon_draw_preview(float x, float y, int icon_id, int nocreate)
+{
+ icon_draw_mipmap(x,y,icon_id, 1.0f, PREVIEW_MIPMAP_LARGE, nocreate);
+}
+
+void BIF_icon_draw_aspect_blended(float x, float y, int icon_id, float aspect, int shade)
+{
+
+ if(shade < 0) {
+ float r= (128+shade)/128.0f;
+ glPixelTransferf(GL_ALPHA_SCALE, r);
+ }
+
+ BIF_icon_draw_aspect(x, y, icon_id, aspect);
+
+ if(shade < 0)
+ glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
+}
diff --git a/source/blender/src/interface_panel.c b/source/blender/src/interface_panel.c
new file mode 100644
index 00000000000..bafc544daa7
--- /dev/null
+++ b/source/blender/src/interface_panel.c
@@ -0,0 +1,1950 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/*
+ a full doc with API notes can be found in bf-blender/blender/doc/interface_API.txt
+
+ */
+
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef WIN32
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "PIL_time.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_vec_types.h"
+
+#include "BKE_blender.h"
+#include "BKE_utildefines.h"
+#include "BKE_global.h"
+
+#include "BIF_gl.h"
+#include "BIF_graphics.h"
+#include "BIF_keyval.h"
+#include "BIF_mainqueue.h"
+
+#include "BIF_drawimage.h"
+#include "BIF_previewrender.h"
+#include "BIF_screen.h"
+#include "BIF_toolbox.h"
+#include "BIF_mywindow.h"
+#include "BIF_space.h"
+#include "BIF_glutil.h"
+#include "BIF_interface.h"
+#include "BIF_butspace.h"
+#include "BIF_language.h"
+
+#include "BSE_view.h"
+
+#include "mydevice.h"
+#include "interface.h"
+#include "blendef.h"
+
+// globals
+extern float UIwinmat[4][4];
+
+
+
+/* --------- generic helper drawng calls ---------------- */
+
+
+#define UI_RB_ALPHA 16
+static int roundboxtype= 15;
+
+void uiSetRoundBox(int type)
+{
+ /* Not sure the roundbox function is the best place to change this
+ * if this is undone, its not that big a deal, only makes curves edges
+ * square for the */
+ if (BIF_GetThemeValue(TH_BUT_DRAWTYPE) == TH_MINIMAL)
+ roundboxtype= 0;
+ else
+ roundboxtype= type;
+
+ /* flags to set which corners will become rounded:
+
+ 1------2
+ | |
+ 8------4
+ */
+
+}
+
+void gl_round_box(int mode, float minx, float miny, float maxx, float maxy, float rad)
+{
+ float vec[7][2]= {{0.195, 0.02}, {0.383, 0.067}, {0.55, 0.169}, {0.707, 0.293},
+ {0.831, 0.45}, {0.924, 0.617}, {0.98, 0.805}};
+ int a;
+
+ /* mult */
+ for(a=0; a<7; a++) {
+ vec[a][0]*= rad; vec[a][1]*= rad;
+ }
+
+ glBegin(mode);
+
+ /* start with corner right-bottom */
+ if(roundboxtype & 4) {
+ glVertex2f( maxx-rad, miny);
+ for(a=0; a<7; a++) {
+ glVertex2f( maxx-rad+vec[a][0], miny+vec[a][1]);
+ }
+ glVertex2f( maxx, miny+rad);
+ }
+ else glVertex2f( maxx, miny);
+
+ /* corner right-top */
+ if(roundboxtype & 2) {
+ glVertex2f( maxx, maxy-rad);
+ for(a=0; a<7; a++) {
+ glVertex2f( maxx-vec[a][1], maxy-rad+vec[a][0]);
+ }
+ glVertex2f( maxx-rad, maxy);
+ }
+ else glVertex2f( maxx, maxy);
+
+ /* corner left-top */
+ if(roundboxtype & 1) {
+ glVertex2f( minx+rad, maxy);
+ for(a=0; a<7; a++) {
+ glVertex2f( minx+rad-vec[a][0], maxy-vec[a][1]);
+ }
+ glVertex2f( minx, maxy-rad);
+ }
+ else glVertex2f( minx, maxy);
+
+ /* corner left-bottom */
+ if(roundboxtype & 8) {
+ glVertex2f( minx, miny+rad);
+ for(a=0; a<7; a++) {
+ glVertex2f( minx+vec[a][1], miny+rad-vec[a][0]);
+ }
+ glVertex2f( minx+rad, miny);
+ }
+ else glVertex2f( minx, miny);
+
+ glEnd();
+}
+
+static void round_box_shade_col(float *col1, float *col2, float fac)
+{
+ float col[3];
+
+ col[0]= (fac*col1[0] + (1.0-fac)*col2[0]);
+ col[1]= (fac*col1[1] + (1.0-fac)*col2[1]);
+ col[2]= (fac*col1[2] + (1.0-fac)*col2[2]);
+
+ glColor3fv(col);
+}
+
+/* linear horizontal shade within button or in outline */
+void gl_round_box_shade(int mode, float minx, float miny, float maxx, float maxy, float rad, float shadetop, float shadedown)
+{
+ float vec[7][2]= {{0.195, 0.02}, {0.383, 0.067}, {0.55, 0.169}, {0.707, 0.293},
+ {0.831, 0.45}, {0.924, 0.617}, {0.98, 0.805}};
+ float div= maxy-miny;
+ float coltop[3], coldown[3], color[4];
+ int a;
+
+ /* mult */
+ for(a=0; a<7; a++) {
+ vec[a][0]*= rad; vec[a][1]*= rad;
+ }
+ /* get current color, needs to be outside of glBegin/End */
+ glGetFloatv(GL_CURRENT_COLOR, color);
+
+ /* 'shade' defines strength of shading */
+ coltop[0]= color[0]+shadetop; if(coltop[0]>1.0) coltop[0]= 1.0;
+ coltop[1]= color[1]+shadetop; if(coltop[1]>1.0) coltop[1]= 1.0;
+ coltop[2]= color[2]+shadetop; if(coltop[2]>1.0) coltop[2]= 1.0;
+ coldown[0]= color[0]+shadedown; if(coldown[0]<0.0) coldown[0]= 0.0;
+ coldown[1]= color[1]+shadedown; if(coldown[1]<0.0) coldown[1]= 0.0;
+ coldown[2]= color[2]+shadedown; if(coldown[2]<0.0) coldown[2]= 0.0;
+
+ if (BIF_GetThemeValue(TH_BUT_DRAWTYPE) != TH_MINIMAL) {
+ glShadeModel(GL_SMOOTH);
+ glBegin(mode);
+ }
+
+ /* start with corner right-bottom */
+ if(roundboxtype & 4) {
+
+ round_box_shade_col(coltop, coldown, 0.0);
+ glVertex2f( maxx-rad, miny);
+
+ for(a=0; a<7; a++) {
+ round_box_shade_col(coltop, coldown, vec[a][1]/div);
+ glVertex2f( maxx-rad+vec[a][0], miny+vec[a][1]);
+ }
+
+ round_box_shade_col(coltop, coldown, rad/div);
+ glVertex2f( maxx, miny+rad);
+ }
+ else {
+ round_box_shade_col(coltop, coldown, 0.0);
+ glVertex2f( maxx, miny);
+ }
+
+ /* corner right-top */
+ if(roundboxtype & 2) {
+
+ round_box_shade_col(coltop, coldown, (div-rad)/div);
+ glVertex2f( maxx, maxy-rad);
+
+ for(a=0; a<7; a++) {
+ round_box_shade_col(coltop, coldown, (div-rad+vec[a][1])/div);
+ glVertex2f( maxx-vec[a][1], maxy-rad+vec[a][0]);
+ }
+ round_box_shade_col(coltop, coldown, 1.0);
+ glVertex2f( maxx-rad, maxy);
+ }
+ else {
+ round_box_shade_col(coltop, coldown, 1.0);
+ glVertex2f( maxx, maxy);
+ }
+
+ /* corner left-top */
+ if(roundboxtype & 1) {
+
+ round_box_shade_col(coltop, coldown, 1.0);
+ glVertex2f( minx+rad, maxy);
+
+ for(a=0; a<7; a++) {
+ round_box_shade_col(coltop, coldown, (div-vec[a][1])/div);
+ glVertex2f( minx+rad-vec[a][0], maxy-vec[a][1]);
+ }
+
+ round_box_shade_col(coltop, coldown, (div-rad)/div);
+ glVertex2f( minx, maxy-rad);
+ }
+ else {
+ round_box_shade_col(coltop, coldown, 1.0);
+ glVertex2f( minx, maxy);
+ }
+
+ /* corner left-bottom */
+ if(roundboxtype & 8) {
+
+ round_box_shade_col(coltop, coldown, rad/div);
+ glVertex2f( minx, miny+rad);
+
+ for(a=0; a<7; a++) {
+ round_box_shade_col(coltop, coldown, (rad-vec[a][1])/div);
+ glVertex2f( minx+vec[a][1], miny+rad-vec[a][0]);
+ }
+
+ round_box_shade_col(coltop, coldown, 0.0);
+ glVertex2f( minx+rad, miny);
+ }
+ else {
+ round_box_shade_col(coltop, coldown, 0.0);
+ glVertex2f( minx, miny);
+ }
+
+ glEnd();
+ glShadeModel(GL_FLAT);
+}
+
+/* only for headers */
+static void gl_round_box_topshade(float minx, float miny, float maxx, float maxy, float rad)
+{
+ float vec[7][2]= {{0.195, 0.02}, {0.383, 0.067}, {0.55, 0.169}, {0.707, 0.293},
+ {0.831, 0.45}, {0.924, 0.617}, {0.98, 0.805}};
+ char col[7]= {140, 165, 195, 210, 230, 245, 255};
+ int a;
+ char alpha=255;
+
+ if(roundboxtype & UI_RB_ALPHA) alpha= 128;
+
+ /* mult */
+ for(a=0; a<7; a++) {
+ vec[a][0]*= rad; vec[a][1]*= rad;
+ }
+
+ /* shades from grey->white->grey */
+ glBegin(GL_LINE_STRIP);
+
+ if(roundboxtype & 3) {
+ /* corner right-top */
+ glColor4ub(140, 140, 140, alpha);
+ glVertex2f( maxx, maxy-rad);
+ for(a=0; a<7; a++) {
+ glColor4ub(col[a], col[a], col[a], alpha);
+ glVertex2f( maxx-vec[a][1], maxy-rad+vec[a][0]);
+ }
+ glColor4ub(225, 225, 225, alpha);
+ glVertex2f( maxx-rad, maxy);
+
+
+ /* corner left-top */
+ glVertex2f( minx+rad, maxy);
+ for(a=0; a<7; a++) {
+ glColor4ub(col[6-a], col[6-a], col[6-a], alpha);
+ glVertex2f( minx+rad-vec[a][0], maxy-vec[a][1]);
+ }
+ glVertex2f( minx, maxy-rad);
+ }
+ else {
+ glColor4ub(225, 225, 225, alpha);
+ glVertex2f( minx, maxy);
+ glVertex2f( maxx, maxy);
+ }
+
+ glEnd();
+}
+
+/* for headers and floating panels */
+void uiRoundBoxEmboss(float minx, float miny, float maxx, float maxy, float rad, int active)
+{
+ float color[4];
+
+ if(roundboxtype & UI_RB_ALPHA) {
+ glGetFloatv(GL_CURRENT_COLOR, color);
+ color[3]= 0.5;
+ glColor4fv(color);
+ glEnable( GL_BLEND );
+ }
+
+ /* solid part */
+ //if(active)
+ // gl_round_box_shade(GL_POLYGON, minx, miny, maxx, maxy, rad, 0.10, -0.05);
+ // else
+ /* shading doesnt work for certain buttons yet (pulldown) need smarter buffer caching (ton) */
+ gl_round_box(GL_POLYGON, minx, miny, maxx, maxy, rad);
+
+ /* set antialias line */
+ if (BIF_GetThemeValue(TH_BUT_DRAWTYPE) != TH_MINIMAL) {
+ glEnable( GL_LINE_SMOOTH );
+ glEnable( GL_BLEND );
+ }
+
+ /* top shade */
+ gl_round_box_topshade(minx+1, miny+1, maxx-1, maxy-1, rad);
+
+ /* total outline */
+ if(roundboxtype & UI_RB_ALPHA) glColor4ub(0,0,0, 128); else glColor4ub(0,0,0, 200);
+ gl_round_box(GL_LINE_LOOP, minx, miny, maxx, maxy, rad);
+
+ glDisable( GL_LINE_SMOOTH );
+
+ /* bottom shade for header down */
+ if((roundboxtype & 12)==12) {
+ glColor4ub(0,0,0, 80);
+ fdrawline(minx+rad-1.0, miny+1.0, maxx-rad+1.0, miny+1.0);
+ }
+ glDisable( GL_BLEND );
+}
+
+
+/* plain antialiased unfilled rectangle */
+void uiRoundRect(float minx, float miny, float maxx, float maxy, float rad)
+{
+ float color[4];
+
+ if(roundboxtype & UI_RB_ALPHA) {
+ glGetFloatv(GL_CURRENT_COLOR, color);
+ color[3]= 0.5;
+ glColor4fv(color);
+ glEnable( GL_BLEND );
+ }
+
+ /* set antialias line */
+ if (BIF_GetThemeValue(TH_BUT_DRAWTYPE) != TH_MINIMAL) {
+ glEnable( GL_LINE_SMOOTH );
+ glEnable( GL_BLEND );
+ }
+
+ gl_round_box(GL_LINE_LOOP, minx, miny, maxx, maxy, rad);
+
+ glDisable( GL_BLEND );
+ glDisable( GL_LINE_SMOOTH );
+}
+
+
+
+/* plain antialiased filled box */
+void uiRoundBox(float minx, float miny, float maxx, float maxy, float rad)
+{
+ float color[4];
+
+ if(roundboxtype & UI_RB_ALPHA) {
+ glGetFloatv(GL_CURRENT_COLOR, color);
+ color[3]= 0.5;
+ glColor4fv(color);
+ glEnable( GL_BLEND );
+ }
+
+ /* solid part */
+ gl_round_box(GL_POLYGON, minx, miny, maxx, maxy, rad);
+
+ /* set antialias line */
+ if (BIF_GetThemeValue(TH_BUT_DRAWTYPE) != TH_MINIMAL) {
+ glEnable( GL_LINE_SMOOTH );
+ glEnable( GL_BLEND );
+ }
+
+ gl_round_box(GL_LINE_LOOP, minx, miny, maxx, maxy, rad);
+
+ glDisable( GL_BLEND );
+ glDisable( GL_LINE_SMOOTH );
+}
+
+
+/* ************** panels ************* */
+
+static void copy_panel_offset(Panel *pa, Panel *papar)
+{
+ /* with respect to sizes... papar is parent */
+
+ pa->ofsx= papar->ofsx;
+ pa->ofsy= papar->ofsy + papar->sizey-pa->sizey;
+}
+
+
+
+/* global... but will be NULLed after each 'newPanel' call */
+static char *panel_tabbed=NULL, *group_tabbed=NULL;
+
+void uiNewPanelTabbed(char *panelname, char *groupname)
+{
+ panel_tabbed= panelname;
+ group_tabbed= groupname;
+}
+
+/* another global... */
+static int pnl_control= UI_PNL_TRANSP;
+
+void uiPanelControl(int control)
+{
+ pnl_control= control;
+}
+
+/* another global... */
+static int pnl_handler= 0;
+
+void uiSetPanelHandler(int handler)
+{
+ pnl_handler= handler;
+}
+
+
+/* ofsx/ofsy only used for new panel definitions */
+/* return 1 if visible (create buttons!) */
+int uiNewPanel(ScrArea *sa, uiBlock *block, char *panelname, char *tabname, int ofsx, int ofsy, int sizex, int sizey)
+{
+ Panel *pa;
+
+ /* check if Panel exists, then use that one */
+ pa= sa->panels.first;
+ while(pa) {
+ if( strncmp(pa->panelname, panelname, UI_MAX_NAME_STR)==0) {
+ if( strncmp(pa->tabname, tabname, UI_MAX_NAME_STR)==0) {
+ break;
+ }
+ }
+ pa= pa->next;
+ }
+
+ if(pa) {
+ /* scale correction */
+ if(pa->control & UI_PNL_SCALE);
+ else {
+ pa->sizex= sizex;
+ if(pa->sizey != sizey) {
+ pa->ofsy+= (pa->sizey - sizey); // check uiNewPanelHeight()
+ pa->sizey= sizey;
+ }
+ }
+ }
+ else {
+
+ /* new panel */
+ pa= MEM_callocN(sizeof(Panel), "new panel");
+ BLI_addtail(&sa->panels, pa);
+ strncpy(pa->panelname, panelname, UI_MAX_NAME_STR);
+ strncpy(pa->tabname, tabname, UI_MAX_NAME_STR);
+
+ pa->ofsx= ofsx & ~(PNL_GRID-1);
+ pa->ofsy= ofsy & ~(PNL_GRID-1);
+ pa->sizex= sizex;
+ pa->sizey= sizey;
+
+ /* make new Panel tabbed? */
+ if(panel_tabbed && group_tabbed) {
+ Panel *papar;
+ for(papar= sa->panels.first; papar; papar= papar->next) {
+ if(papar->active && papar->paneltab==NULL) {
+ if( strncmp(panel_tabbed, papar->panelname, UI_MAX_NAME_STR)==0) {
+ if( strncmp(group_tabbed, papar->tabname, UI_MAX_NAME_STR)==0) {
+ pa->paneltab= papar;
+ copy_panel_offset(pa, papar);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ block->panel= pa;
+ block->handler= pnl_handler;
+ pa->active= 1;
+ pa->control= pnl_control;
+
+ /* global control over this feature; UI_PNL_TO_MOUSE only called for hotkey panels */
+ if(U.uiflag & USER_PANELPINNED);
+ else if(pnl_control & UI_PNL_TO_MOUSE) {
+ short mval[2];
+
+ Mat4CpyMat4(UIwinmat, block->winmat); // can be first event here
+ uiGetMouse(block->win, mval);
+ pa->ofsx= mval[0]-pa->sizex/2;
+ pa->ofsy= mval[1]-pa->sizey/2;
+
+ if(pa->flag & PNL_CLOSED) pa->flag &= ~PNL_CLOSED;
+ }
+
+ if(pnl_control & UI_PNL_UNSTOW) {
+ if(pa->flag & PNL_CLOSEDY) {
+ pa->flag &= ~PNL_CLOSED;
+ }
+ }
+
+ /* clear ugly globals */
+ panel_tabbed= group_tabbed= NULL;
+ pnl_handler= 0;
+ pnl_control= UI_PNL_TRANSP; // back to default
+
+ if(block->panel->paneltab) return 0;
+ if(block->panel->flag & PNL_CLOSED) return 0;
+
+ /* the 'return 0' above makes this to be in end. otherwise closes panels show wrong title */
+ pa->drawname[0]= 0;
+
+ return 1;
+}
+
+void uiFreePanels(ListBase *lb)
+{
+ Panel *panel;
+
+ while( (panel= lb->first) ) {
+ BLI_remlink(lb, panel);
+ MEM_freeN(panel);
+ }
+}
+
+void uiNewPanelHeight(uiBlock *block, int sizey)
+{
+ if(sizey<64) sizey= 64;
+
+ if(block->panel) {
+ block->panel->ofsy+= (block->panel->sizey - sizey);
+ block->panel->sizey= sizey;
+ }
+}
+
+void uiNewPanelTitle(uiBlock *block, char *str)
+{
+ if(block->panel)
+ BLI_strncpy(block->panel->drawname, str, UI_MAX_NAME_STR);
+}
+
+static int panel_has_tabs(Panel *panel)
+{
+ Panel *pa= curarea->panels.first;
+
+ if(panel==NULL) return 0;
+
+ while(pa) {
+ if(pa->paneltab==panel) return 1;
+ pa= pa->next;
+ }
+ return 0;
+}
+
+static void ui_scale_panel_block(uiBlock *block)
+{
+ uiBut *but;
+ float facx= 1.0, facy= 1.0;
+ int centerx= 0, topy=0, tabsy=0;
+
+ if(block->panel==NULL) return;
+
+ if(block->autofill) ui_autofill(block);
+ /* buttons min/max centered, offset calculated */
+ uiBoundsBlock(block, 0);
+
+ if( block->maxx-block->minx > block->panel->sizex - 2*PNL_SAFETY ) {
+ facx= (block->panel->sizex - (2*PNL_SAFETY))/( block->maxx-block->minx );
+ }
+ else centerx= (block->panel->sizex-( block->maxx-block->minx ) - 2*PNL_SAFETY)/2;
+
+ // tabsy= PNL_HEADER*panel_has_tabs(block->panel);
+ if( (block->maxy-block->miny) > block->panel->sizey - 2*PNL_SAFETY - tabsy) {
+ facy= (block->panel->sizey - (2*PNL_SAFETY) - tabsy)/( block->maxy-block->miny );
+ }
+ else topy= (block->panel->sizey- 2*PNL_SAFETY - tabsy) - ( block->maxy-block->miny ) ;
+
+ but= block->buttons.first;
+ while(but) {
+ but->x1= PNL_SAFETY+centerx+ facx*(but->x1-block->minx);
+ but->y1= PNL_SAFETY+topy + facy*(but->y1-block->miny);
+ but->x2= PNL_SAFETY+centerx+ facx*(but->x2-block->minx);
+ but->y2= PNL_SAFETY+topy + facy*(but->y2-block->miny);
+ if(facx!=1.0) ui_check_but(but); /* for strlen */
+ but= but->next;
+ }
+
+ block->maxx= block->panel->sizex;
+ block->maxy= block->panel->sizey;
+ block->minx= block->miny= 0.0;
+
+}
+
+// for 'home' key
+void uiSetPanel_view2d(ScrArea *sa)
+{
+ Panel *pa;
+ float minx=10000, maxx= -10000, miny=10000, maxy= -10000;
+ int done=0;
+
+ pa= sa->panels.first;
+ while(pa) {
+ if(pa->active && pa->paneltab==NULL) {
+ done= 1;
+ if(pa->ofsx < minx) minx= pa->ofsx;
+ if(pa->ofsx+pa->sizex > maxx) maxx= pa->ofsx+pa->sizex;
+ if(pa->ofsy < miny) miny= pa->ofsy;
+ if(pa->ofsy+pa->sizey+PNL_HEADER > maxy) maxy= pa->ofsy+pa->sizey+PNL_HEADER;
+ }
+ pa= pa->next;
+ }
+ if(done) {
+ G.v2d->tot.xmin= minx-PNL_DIST;
+ G.v2d->tot.xmax= maxx+PNL_DIST;
+ G.v2d->tot.ymin= miny-PNL_DIST;
+ G.v2d->tot.ymax= maxy+PNL_DIST;
+ }
+ else {
+ uiBlock *block;
+
+ G.v2d->tot.xmin= 0;
+ G.v2d->tot.xmax= 1280;
+ G.v2d->tot.ymin= 0;
+ G.v2d->tot.ymax= 228;
+
+ /* no panels, but old 'loose' buttons, as in old logic editor */
+ for(block= sa->uiblocks.first; block; block= block->next) {
+ if(block->win==sa->win) {
+ if(block->minx < G.v2d->tot.xmin) G.v2d->tot.xmin= block->minx;
+ if(block->maxx > G.v2d->tot.xmax) G.v2d->tot.xmax= block->maxx;
+ if(block->miny < G.v2d->tot.ymin) G.v2d->tot.ymin= block->miny;
+ if(block->maxy > G.v2d->tot.ymax) G.v2d->tot.ymax= block->maxy;
+ }
+ }
+ }
+
+}
+
+// make sure the panels are not outside 'tot' area
+void uiMatchPanel_view2d(ScrArea *sa)
+{
+ Panel *pa;
+ int done=0;
+
+ pa= sa->panels.first;
+ while(pa) {
+ if(pa->active && pa->paneltab==NULL) {
+ done= 1;
+ if(pa->ofsx < G.v2d->tot.xmin) G.v2d->tot.xmin= pa->ofsx;
+ if(pa->ofsx+pa->sizex > G.v2d->tot.xmax)
+ G.v2d->tot.xmax= pa->ofsx+pa->sizex;
+ if(pa->ofsy < G.v2d->tot.ymin) G.v2d->tot.ymin= pa->ofsy;
+ if(pa->ofsy+pa->sizey+PNL_HEADER > G.v2d->tot.ymax)
+ G.v2d->tot.ymax= pa->ofsy+pa->sizey+PNL_HEADER;
+ }
+ pa= pa->next;
+ }
+ if(done==0) {
+ uiBlock *block;
+ /* no panels, but old 'loose' buttons, as in old logic editor */
+ for(block= sa->uiblocks.first; block; block= block->next) {
+ if(block->win==sa->win) {
+ if(block->minx < G.v2d->tot.xmin) G.v2d->tot.xmin= block->minx;
+ if(block->maxx > G.v2d->tot.xmax) G.v2d->tot.xmax= block->maxx;
+ if(block->miny < G.v2d->tot.ymin) G.v2d->tot.ymin= block->miny;
+ if(block->maxy > G.v2d->tot.ymax) G.v2d->tot.ymax= block->maxy;
+ }
+ }
+ }
+}
+
+/* extern used by previewrender */
+void uiPanelPush(uiBlock *block)
+{
+ glPushMatrix();
+ if(block->panel) {
+ glTranslatef((float)block->panel->ofsx, (float)block->panel->ofsy, 0.0);
+ i_translate((float)block->panel->ofsx, (float)block->panel->ofsy, 0.0, UIwinmat);
+ }
+}
+
+void uiPanelPop(uiBlock *block)
+{
+ glPopMatrix();
+ Mat4CpyMat4(UIwinmat, block->winmat);
+}
+
+uiBlock *uiFindOpenPanelBlockName(ListBase *lb, char *name)
+{
+ uiBlock *block;
+
+ for(block= lb->first; block; block= block->next) {
+ if(block->panel && block->panel->active && block->panel->paneltab==NULL) {
+ if(block->panel->flag & PNL_CLOSED);
+ else if(strncmp(name, block->panel->panelname, UI_MAX_NAME_STR)==0) break;
+ }
+ }
+ return block;
+}
+
+static void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3)
+{
+ // we draw twice, anti polygons not widely supported...
+ glBegin(GL_POLYGON);
+ glVertex2f(x1, y1);
+ glVertex2f(x2, y2);
+ glVertex2f(x3, y3);
+ glEnd();
+
+ /* set antialias line */
+ glEnable( GL_LINE_SMOOTH );
+ glEnable( GL_BLEND );
+
+ glBegin(GL_LINE_LOOP);
+ glVertex2f(x1, y1);
+ glVertex2f(x2, y2);
+ glVertex2f(x3, y3);
+ glEnd();
+
+ glDisable( GL_LINE_SMOOTH );
+ glDisable( GL_BLEND );
+}
+
+/* triangle 'icon' for panel header */
+void ui_draw_tria_icon(float x, float y, float aspect, char dir)
+{
+ if(dir=='h') {
+ ui_draw_anti_tria( x, y+1, x, y+10.0, x+8, y+6.25);
+ }
+ else {
+ ui_draw_anti_tria( x-2, y+9, x+8-2, y+9, x+4.25-2, y+1);
+ }
+}
+
+void ui_draw_anti_x(float x1, float y1, float x2, float y2)
+{
+
+ /* set antialias line */
+ glEnable( GL_LINE_SMOOTH );
+ glEnable( GL_BLEND );
+
+ glLineWidth(2.0);
+
+ fdrawline(x1, y1, x2, y2);
+ fdrawline(x1, y2, x2, y1);
+
+ glLineWidth(1.0);
+
+ glDisable( GL_LINE_SMOOTH );
+ glDisable( GL_BLEND );
+
+}
+
+/* x 'icon' for panel header */
+static void ui_draw_x_icon(float x, float y)
+{
+ BIF_ThemeColor(TH_TEXT_HI);
+
+ ui_draw_anti_x( x, y, x+9.375, y+9.375);
+
+}
+
+#if 0
+static void ui_set_panel_pattern(char dir)
+{
+ static int firsttime= 1;
+ static GLubyte path[4*32], patv[4*32];
+ int a,b,i=0;
+
+ if(firsttime) {
+ firsttime= 0;
+ for(a=0; a<128; a++) patv[a]= 0x33;
+ for(a=0; a<8; a++) {
+ for(b=0; b<4; b++) path[i++]= 0xff; /* 1 scanlines */
+ for(b=0; b<12; b++) path[i++]= 0x0; /* 3 lines */
+ }
+ }
+ glEnable(GL_POLYGON_STIPPLE);
+ if(dir=='h') glPolygonStipple(path);
+ else glPolygonStipple(patv);
+}
+#endif
+
+static char *ui_block_cut_str(uiBlock *block, char *str, short okwidth)
+{
+ short width, ofs=strlen(str);
+ static char str1[128];
+
+ if(ofs>127) return str;
+
+ width= block->aspect*BIF_GetStringWidth(block->curfont, str, (U.transopts & USER_TR_BUTTONS));
+
+ if(width <= okwidth) return str;
+ strcpy(str1, str);
+
+ while(width > okwidth && ofs>0) {
+ ofs--;
+ str1[ofs]= 0;
+
+ width= block->aspect*BIF_GetStringWidth(block->curfont, str1, 0);
+
+ if(width < 10) break;
+ }
+ return str1;
+}
+
+
+#define PNL_ICON 20
+#define PNL_DRAGGER 20
+
+
+static void ui_draw_panel_header(uiBlock *block)
+{
+ Panel *pa, *panel= block->panel;
+ float width;
+ int a, nr= 1, pnl_icons;
+ char *panelname= panel->drawname[0]?panel->drawname:panel->panelname;
+ char *str;
+
+ /* count */
+ pa= curarea->panels.first;
+ while(pa) {
+ if(pa->active) {
+ if(pa->paneltab==panel) nr++;
+ }
+ pa= pa->next;
+ }
+
+ pnl_icons= PNL_ICON+8;
+ if(panel->control & UI_PNL_CLOSE) pnl_icons+= PNL_ICON;
+
+ if(nr==1) {
+ // full header
+ BIF_ThemeColorShade(TH_HEADER, -30);
+ uiSetRoundBox(3);
+ uiRoundBox(block->minx, block->maxy, block->maxx, block->maxy+PNL_HEADER, 8);
+
+ /* active tab */
+ /* draw text label */
+ BIF_ThemeColor(TH_TEXT_HI);
+ ui_rasterpos_safe(4.0f+block->minx+pnl_icons, block->maxy+5.0f, block->aspect);
+ BIF_DrawString(block->curfont, panelname, (U.transopts & USER_TR_BUTTONS));
+ return;
+ }
+
+ // tabbed, full header brighter
+ //BIF_ThemeColorShade(TH_HEADER, 0);
+ //uiSetRoundBox(3);
+ //uiRoundBox(block->minx, block->maxy, block->maxx, block->maxy+PNL_HEADER, 8);
+
+ a= 0;
+ width= (panel->sizex - 3 - pnl_icons - PNL_ICON)/nr;
+ pa= curarea->panels.first;
+ while(pa) {
+ panelname= pa->drawname[0]?pa->drawname:pa->panelname;
+
+ if(pa->active==0);
+ else if(pa==panel) {
+ /* active tab */
+
+ /* draw the active tab */
+ uiSetRoundBox(3);
+ BIF_ThemeColorShade(TH_HEADER, -3);
+ uiRoundBox(2+pnl_icons+a*width, panel->sizey-1, pnl_icons+(a+1)*width, panel->sizey+PNL_HEADER-3, 8);
+
+ /* draw the active text label */
+ BIF_ThemeColor(TH_TEXT);
+ ui_rasterpos_safe(16+pnl_icons+a*width, panel->sizey+4, block->aspect);
+ str= ui_block_cut_str(block, panelname, (short)(width-10));
+ BIF_DrawString(block->curfont, str, (U.transopts & USER_TR_BUTTONS));
+
+ a++;
+ }
+ else if(pa->paneltab==panel) {
+ /* draw an inactive tab */
+ uiSetRoundBox(3);
+ BIF_ThemeColorShade(TH_HEADER, -60);
+ uiRoundBox(2+pnl_icons+a*width, panel->sizey, pnl_icons+(a+1)*width, panel->sizey+PNL_HEADER-3, 8);
+
+ /* draw an inactive tab label */
+ BIF_ThemeColorShade(TH_TEXT_HI, -40);
+ ui_rasterpos_safe(16+pnl_icons+a*width, panel->sizey+4, block->aspect);
+ str= ui_block_cut_str(block, panelname, (short)(width-10));
+ BIF_DrawString(block->curfont, str, (U.transopts & USER_TR_BUTTONS));
+
+ a++;
+ }
+ pa= pa->next;
+ }
+
+ // dragger
+ /*
+ uiSetRoundBox(15);
+ BIF_ThemeColorShade(TH_HEADER, -70);
+ uiRoundBox(panel->sizex-PNL_ICON+5, panel->sizey+5, panel->sizex-5, panel->sizey+PNL_HEADER-5, 5);
+ */
+
+}
+
+static void ui_draw_panel_scalewidget(uiBlock *block)
+{
+ float xmin, xmax, dx;
+ float ymin, ymax, dy;
+
+ xmin= block->maxx-PNL_HEADER+2;
+ xmax= block->maxx-3;
+ ymin= block->miny+3;
+ ymax= block->miny+PNL_HEADER-2;
+
+ dx= 0.5f*(xmax-xmin);
+ dy= 0.5f*(ymax-ymin);
+
+ glEnable(GL_BLEND);
+ glColor4ub(255, 255, 255, 50);
+ fdrawline(xmin, ymin, xmax, ymax);
+ fdrawline(xmin+dx, ymin, xmax, ymax-dy);
+
+ glColor4ub(0, 0, 0, 50);
+ fdrawline(xmin, ymin+block->aspect, xmax, ymax+block->aspect);
+ fdrawline(xmin+dx, ymin+block->aspect, xmax, ymax-dy+block->aspect);
+ glDisable(GL_BLEND);
+}
+
+void ui_draw_panel(uiBlock *block)
+{
+ Panel *panel= block->panel;
+ int ofsx;
+ char *panelname= panel->drawname[0]?panel->drawname:panel->panelname;
+
+ if(panel->paneltab) return;
+
+ /* if the panel is minimized vertically:
+ * (------)
+ */
+ if(panel->flag & PNL_CLOSEDY) {
+ /* draw a little rounded box, the size of the header */
+ uiSetRoundBox(15);
+ BIF_ThemeColorShade(TH_HEADER, -30);
+ uiRoundBox(block->minx, block->maxy, block->maxx, block->maxy+PNL_HEADER, 8);
+
+ /* title */
+ ofsx= PNL_ICON+8;
+ if(panel->control & UI_PNL_CLOSE) ofsx+= PNL_ICON;
+ BIF_ThemeColor(TH_TEXT_HI);
+ ui_rasterpos_safe(4+block->minx+ofsx, block->maxy+5, block->aspect);
+ BIF_DrawString(block->curfont, panelname, (U.transopts & USER_TR_BUTTONS));
+
+ /* border */
+ if(panel->flag & PNL_SELECT) {
+ BIF_ThemeColorShade(TH_HEADER, -120);
+ uiRoundRect(block->minx, block->maxy, block->maxx, block->maxy+PNL_HEADER, 8);
+ }
+ /* if it's being overlapped by a panel being dragged */
+ if(panel->flag & PNL_OVERLAP) {
+ BIF_ThemeColor(TH_TEXT_HI);
+ uiRoundRect(block->minx, block->maxy, block->maxx, block->maxy+PNL_HEADER, 8);
+ }
+
+ }
+ /* if the panel is minimized horizontally:
+ * /-\
+ * |
+ * |
+ * |
+ * \_/
+ */
+ else if(panel->flag & PNL_CLOSEDX) {
+ char str[4];
+ int a, end, ofs;
+
+ /* draw a little rounded box, the size of the header, rotated 90 deg */
+ uiSetRoundBox(15);
+ BIF_ThemeColorShade(TH_HEADER, -30);
+ uiRoundBox(block->minx, block->miny, block->minx+PNL_HEADER, block->maxy+PNL_HEADER, 8);
+
+ /* title, only the initial character for now */
+ BIF_ThemeColor(TH_TEXT_HI);
+ str[1]= 0;
+ end= strlen(panelname);
+ ofs= 20;
+ for(a=0; a<end; a++) {
+ str[0]= panelname[a];
+ if( isupper(str[0]) ) {
+ ui_rasterpos_safe(block->minx+5, block->maxy-ofs, block->aspect);
+ BIF_DrawString(block->curfont, str, 0);
+ ofs+= 15;
+ }
+ }
+
+ /* border */
+ if(panel->flag & PNL_SELECT) {
+ BIF_ThemeColorShade(TH_HEADER, -120);
+ uiRoundRect(block->minx, block->miny, block->minx+PNL_HEADER, block->maxy+PNL_HEADER, 8);
+ }
+ if(panel->flag & PNL_OVERLAP) {
+ BIF_ThemeColor(TH_TEXT_HI);
+ uiRoundRect(block->minx, block->miny, block->minx+PNL_HEADER, block->maxy+PNL_HEADER, 8);
+ }
+
+ }
+ /* an open panel */
+ else {
+ /* all panels now... */
+ if(panel->control & UI_PNL_SOLID) {
+ BIF_ThemeColorShade(TH_HEADER, -30);
+
+ uiSetRoundBox(3);
+ uiRoundBox(block->minx, block->maxy, block->maxx, block->maxy+PNL_HEADER, 8);
+
+ glEnable(GL_BLEND);
+ BIF_ThemeColor4(TH_PANEL);
+
+ uiSetRoundBox(12);
+ /* bad code... but its late :) */
+ if(strcmp(block->name, "image_panel_preview")==0)
+ uiRoundRect(block->minx, block->miny, block->maxx, block->maxy, 8);
+ else
+ uiRoundBox(block->minx, block->miny, block->maxx, block->maxy, 8);
+
+ // glRectf(block->minx, block->miny, block->maxx, block->maxy);
+
+ /* shadow */
+ /*
+ glColor4ub(0, 0, 0, 40);
+
+ fdrawline(block->minx+2, block->miny-1, block->maxx+1, block->miny-1);
+ fdrawline(block->maxx+1, block->miny-1, block->maxx+1, block->maxy+7);
+
+ glColor4ub(0, 0, 0, 10);
+
+ fdrawline(block->minx+3, block->miny-2, block->maxx+2, block->miny-2);
+ fdrawline(block->maxx+2, block->miny-2, block->maxx+2, block->maxy+6);
+
+ */
+
+ glDisable(GL_BLEND);
+ }
+ /* floating panel */
+ else if(panel->control & UI_PNL_TRANSP) {
+ BIF_ThemeColorShade(TH_HEADER, -30);
+ uiSetRoundBox(3);
+ uiRoundBox(block->minx, block->maxy, block->maxx, block->maxy+PNL_HEADER, 8);
+
+ glEnable(GL_BLEND);
+ BIF_ThemeColor4(TH_PANEL);
+ glRectf(block->minx, block->miny, block->maxx, block->maxy);
+
+ glDisable(GL_BLEND);
+ }
+
+ /* draw the title, tabs, etc in the header */
+ ui_draw_panel_header(block);
+
+ /* in some occasions, draw a border */
+ if(panel->flag & PNL_SELECT) {
+ if(panel->control & UI_PNL_SOLID) uiSetRoundBox(15);
+ else uiSetRoundBox(3);
+
+ BIF_ThemeColorShade(TH_HEADER, -120);
+ uiRoundRect(block->minx, block->miny, block->maxx, block->maxy+PNL_HEADER, 8);
+ }
+ if(panel->flag & PNL_OVERLAP) {
+ if(panel->control & UI_PNL_SOLID) uiSetRoundBox(15);
+ else uiSetRoundBox(3);
+
+ BIF_ThemeColor(TH_TEXT_HI);
+ uiRoundRect(block->minx, block->miny, block->maxx, block->maxy+PNL_HEADER, 8);
+ }
+
+ if(panel->control & UI_PNL_SCALE)
+ ui_draw_panel_scalewidget(block);
+
+ /* and a soft shadow-line for now */
+ /*
+ glEnable( GL_BLEND );
+ glColor4ub(0, 0, 0, 50);
+ fdrawline(block->maxx, block->miny, block->maxx, block->maxy+PNL_HEADER/2);
+ fdrawline(block->minx, block->miny, block->maxx, block->miny);
+ glDisable(GL_BLEND);
+ */
+
+ }
+
+ /* draw optional close icon */
+
+ ofsx= 6;
+ if(panel->control & UI_PNL_CLOSE) {
+
+ ui_draw_x_icon(block->minx+2+ofsx, block->maxy+5);
+ ofsx= 22;
+ }
+
+ /* draw collapse icon */
+
+ BIF_ThemeColor(TH_TEXT_HI);
+
+ if(panel->flag & PNL_CLOSEDY)
+ ui_draw_tria_icon(block->minx+6+ofsx, block->maxy+5, block->aspect, 'h');
+ else if(panel->flag & PNL_CLOSEDX)
+ ui_draw_tria_icon(block->minx+7, block->maxy+2, block->aspect, 'h');
+ else
+ ui_draw_tria_icon(block->minx+6+ofsx, block->maxy+5, block->aspect, 'v');
+
+
+}
+
+static void ui_redraw_select_panel(ScrArea *sa)
+{
+ /* only for beauty, make sure the panel thats moved is on top */
+ /* better solution later? */
+ uiBlock *block;
+
+ for(block= sa->uiblocks.first; block; block= block->next) {
+ if(block->panel && (block->panel->flag & PNL_SELECT)) {
+ uiDrawBlock(block);
+ }
+ }
+
+}
+
+
+/* ------------ panel alignment ---------------- */
+
+
+/* this function is needed because uiBlock and Panel itself dont
+change sizey or location when closed */
+static int get_panel_real_ofsy(Panel *pa)
+{
+ if(pa->flag & PNL_CLOSEDY) return pa->ofsy+pa->sizey;
+ else if(pa->paneltab && (pa->paneltab->flag & PNL_CLOSEDY)) return pa->ofsy+pa->sizey;
+ else return pa->ofsy;
+}
+
+static int get_panel_real_ofsx(Panel *pa)
+{
+ if(pa->flag & PNL_CLOSEDX) return pa->ofsx+PNL_HEADER;
+ else if(pa->paneltab && (pa->paneltab->flag & PNL_CLOSEDX)) return pa->ofsx+PNL_HEADER;
+ else return pa->ofsx+pa->sizex;
+}
+
+
+typedef struct PanelSort {
+ Panel *pa, *orig;
+} PanelSort;
+
+/* note about sorting;
+ the sortcounter has a lower value for new panels being added.
+ however, that only works to insert a single panel, when more new panels get
+ added the coordinates of existing panels and the previously stored to-be-insterted
+ panels do not match for sorting */
+
+static int find_leftmost_panel(const void *a1, const void *a2)
+{
+ const PanelSort *ps1=a1, *ps2=a2;
+
+ if( ps1->pa->ofsx > ps2->pa->ofsx) return 1;
+ else if( ps1->pa->ofsx < ps2->pa->ofsx) return -1;
+ else if( ps1->pa->sortcounter > ps2->pa->sortcounter) return 1;
+ else if( ps1->pa->sortcounter < ps2->pa->sortcounter) return -1;
+
+ return 0;
+}
+
+
+static int find_highest_panel(const void *a1, const void *a2)
+{
+ const PanelSort *ps1=a1, *ps2=a2;
+
+ if( ps1->pa->ofsy < ps2->pa->ofsy) return 1;
+ else if( ps1->pa->ofsy > ps2->pa->ofsy) return -1;
+ else if( ps1->pa->sortcounter > ps2->pa->sortcounter) return 1;
+ else if( ps1->pa->sortcounter < ps2->pa->sortcounter) return -1;
+
+ return 0;
+}
+
+/* this doesnt draw */
+/* returns 1 when it did something */
+int uiAlignPanelStep(ScrArea *sa, float fac)
+{
+ SpaceButs *sbuts= sa->spacedata.first;
+ Panel *pa;
+ PanelSort *ps, *panelsort, *psnext;
+ static int sortcounter= 0;
+ int a, tot=0, done;
+
+ if(sa->spacetype!=SPACE_BUTS) {
+ return 0;
+ }
+
+ /* count active, not tabbed Panels */
+ for(pa= sa->panels.first; pa; pa= pa->next) {
+ if(pa->active && pa->paneltab==NULL) tot++;
+ }
+
+ if(tot==0) return 0;
+
+ /* extra; change close direction? */
+ for(pa= sa->panels.first; pa; pa= pa->next) {
+ if(pa->active && pa->paneltab==NULL) {
+ if( (pa->flag & PNL_CLOSEDX) && (sbuts->align==BUT_VERTICAL) )
+ pa->flag ^= PNL_CLOSED;
+
+ else if( (pa->flag & PNL_CLOSEDY) && (sbuts->align==BUT_HORIZONTAL) )
+ pa->flag ^= PNL_CLOSED;
+
+ }
+ }
+
+ panelsort= MEM_callocN( tot*sizeof(PanelSort), "panelsort");
+
+ /* fill panelsort array */
+ ps= panelsort;
+ for(pa= sa->panels.first; pa; pa= pa->next) {
+ if(pa->active && pa->paneltab==NULL) {
+ ps->pa= MEM_dupallocN(pa);
+ ps->orig= pa;
+ ps++;
+ }
+ }
+
+ if(sbuts->align==BUT_VERTICAL)
+ qsort(panelsort, tot, sizeof(PanelSort), find_highest_panel);
+ else
+ qsort(panelsort, tot, sizeof(PanelSort), find_leftmost_panel);
+
+
+ /* no smart other default start loc! this keeps switching f5/f6/etc compatible */
+ ps= panelsort;
+ ps->pa->ofsx= 0;
+ ps->pa->ofsy= 0;
+
+ for(a=0 ; a<tot-1; a++, ps++) {
+ psnext= ps+1;
+
+ if(sbuts->align==BUT_VERTICAL) {
+ psnext->pa->ofsx = ps->pa->ofsx;
+ psnext->pa->ofsy = get_panel_real_ofsy(ps->pa) - psnext->pa->sizey-PNL_HEADER-PNL_DIST;
+ }
+ else {
+ psnext->pa->ofsx = get_panel_real_ofsx(ps->pa)+PNL_DIST;
+ psnext->pa->ofsy = ps->pa->ofsy + ps->pa->sizey - psnext->pa->sizey;
+ }
+ }
+
+ /* we interpolate */
+ done= 0;
+ ps= panelsort;
+ for(a=0; a<tot; a++, ps++) {
+ if( (ps->pa->flag & PNL_SELECT)==0) {
+ if( (ps->orig->ofsx != ps->pa->ofsx) || (ps->orig->ofsy != ps->pa->ofsy)) {
+ ps->orig->ofsx= floor(0.5 + fac*ps->pa->ofsx + (1.0-fac)*ps->orig->ofsx);
+ ps->orig->ofsy= floor(0.5 + fac*ps->pa->ofsy + (1.0-fac)*ps->orig->ofsy);
+ done= 1;
+ }
+ }
+ }
+
+ /* copy locations to tabs */
+ for(pa= sa->panels.first; pa; pa= pa->next) {
+ if(pa->paneltab && pa->active) {
+ copy_panel_offset(pa, pa->paneltab);
+ }
+ }
+
+ /* set counter, used for sorting with newly added panels */
+ sortcounter++;
+ for(pa= sa->panels.first; pa; pa= pa->next) {
+ if(pa->active) pa->sortcounter= sortcounter;
+ }
+
+ /* free panelsort array */
+ ps= panelsort;
+ for(a=0; a<tot; a++, ps++) {
+ MEM_freeN(ps->pa);
+ }
+ MEM_freeN(panelsort);
+
+ return done;
+}
+
+
+static void ui_animate_panels(ScrArea *sa)
+{
+ double time=0, ltime;
+ float result= 0.0, fac= 0.2;
+
+ ltime = PIL_check_seconds_timer();
+
+ /* for max 1 second, interpolate positions */
+ while(TRUE) {
+
+ if( uiAlignPanelStep(sa, fac) ) {
+ /* warn: this re-allocs uiblocks! */
+ scrarea_do_windraw(curarea);
+ ui_redraw_select_panel(curarea);
+ screen_swapbuffers();
+ }
+ else {
+ addqueue(curarea->win, REDRAW,1 ); // because 'Animate' is also called as redraw
+ break;
+ }
+
+ if(result >= 1.0) break;
+
+ if(result==0.0) { // firsttime
+ time = PIL_check_seconds_timer()-ltime;
+ if(time > 0.5) fac= 0.7;
+ else if(time > 0.2) fac= 0.5;
+ else if(time > 0.1) fac= 0.4;
+ else if(time > 0.05) fac= 0.3; // 11 steps
+ }
+
+ result= fac + (1.0-fac)*result;
+
+ if(result > 0.98) {
+ result= 1.0;
+ fac= 1.0;
+ }
+ }
+}
+
+/* only draws blocks with panels */
+void uiDrawBlocksPanels(ScrArea *sa, int re_align)
+{
+ uiBlock *block;
+ Panel *panot, *panew, *patest;
+
+ /* scaling contents */
+ block= sa->uiblocks.first;
+ while(block) {
+ if(block->panel) ui_scale_panel_block(block);
+ block= block->next;
+ }
+
+ /* consistancy; are panels not made, whilst they have tabs */
+ for(panot= sa->panels.first; panot; panot= panot->next) {
+ if(panot->active==0) { // not made
+
+ for(panew= sa->panels.first; panew; panew= panew->next) {
+ if(panew->active) {
+ if(panew->paneltab==panot) { // panew is tab in notmade pa
+ break;
+ }
+ }
+ }
+ /* now panew can become the new parent, check all other tabs */
+ if(panew) {
+ for(patest= sa->panels.first; patest; patest= patest->next) {
+ if(patest->paneltab == panot) {
+ patest->paneltab= panew;
+ }
+ }
+ panot->paneltab= panew;
+ panew->paneltab= NULL;
+ addqueue(sa->win, REDRAW, 1); // the buttons panew were not made
+ }
+ }
+ }
+
+ /* re-align */
+ if(re_align) uiAlignPanelStep(sa, 1.0);
+
+ if(sa->spacetype!=SPACE_BUTS) {
+ SpaceLink *sl= sa->spacedata.first;
+ for(block= sa->uiblocks.first; block; block= block->next) {
+ if(block->panel && block->panel->active && block->panel->paneltab == NULL) {
+ float dx=0.0, dy=0.0, minx, miny, maxx, maxy, miny_panel;
+
+ minx= sl->blockscale*block->panel->ofsx;
+ maxx= sl->blockscale*(block->panel->ofsx+block->panel->sizex);
+ miny= sl->blockscale*(block->panel->ofsy+block->panel->sizey);
+ maxy= sl->blockscale*(block->panel->ofsy+block->panel->sizey+PNL_HEADER);
+ miny_panel= sl->blockscale*(block->panel->ofsy);
+
+ /* check to see if snapped panels have been left out in the open by resizing a window
+ * and if so, offset them back to where they belong */
+ if (block->panel->snap) {
+ if (((block->panel->snap) & PNL_SNAP_RIGHT) &&
+ (maxx < (float)sa->winx)) {
+
+ dx = sa->winx-maxx;
+ block->panel->ofsx+= dx/sl->blockscale;
+ }
+ if (((block->panel->snap) & PNL_SNAP_TOP) &&
+ (maxy < (float)sa->winy)) {
+
+ dy = sa->winy-maxy;
+ block->panel->ofsy+= dy/sl->blockscale;
+ }
+
+ /* reset these vars with updated panel offset distances */
+ minx= sl->blockscale*block->panel->ofsx;
+ maxx= sl->blockscale*(block->panel->ofsx+block->panel->sizex);
+ miny= sl->blockscale*(block->panel->ofsy+block->panel->sizey);
+ maxy= sl->blockscale*(block->panel->ofsy+block->panel->sizey+PNL_HEADER);
+ miny_panel= sl->blockscale*(block->panel->ofsy);
+ } else
+ /* reset to no snapping */
+ block->panel->snap = PNL_SNAP_NONE;
+
+
+ /* clip panels (headers) for non-butspace situations (maybe make optimized event later) */
+
+ /* check left and right edges */
+ if (minx < PNL_SNAP_DIST) {
+ dx = -minx;
+ block->panel->snap |= PNL_SNAP_LEFT;
+ }
+ else if (maxx > ((float)sa->winx - PNL_SNAP_DIST)) {
+ dx= sa->winx-maxx;
+ block->panel->snap |= PNL_SNAP_RIGHT;
+ }
+ if( minx + dx < 0.0) dx= -minx; // when panel cant fit, put it fixed here
+
+ /* check top and bottom edges */
+ if ((miny_panel < PNL_SNAP_DIST) && (miny_panel > -PNL_SNAP_DIST)) {
+ dy= -miny_panel;
+ block->panel->snap |= PNL_SNAP_BOTTOM;
+ }
+ if(miny < PNL_SNAP_DIST) {
+ dy= -miny;
+ block->panel->snap |= PNL_SNAP_BOTTOM;
+ }
+ else if(maxy > ((float)sa->winy - PNL_SNAP_DIST)) {
+ dy= sa->winy-maxy;
+ block->panel->snap |= PNL_SNAP_TOP;
+ }
+ if( miny + dy < 0.0) dy= -miny; // when panel cant fit, put it fixed here
+
+
+ block->panel->ofsx+= dx/sl->blockscale;
+ block->panel->ofsy+= dy/sl->blockscale;
+
+ /* copy locations */
+ for(patest= sa->panels.first; patest; patest= patest->next) {
+ if(patest->paneltab==block->panel) copy_panel_offset(patest, block->panel);
+ }
+
+ }
+ }
+ }
+
+ /* draw */
+ block= sa->uiblocks.first;
+ while(block) {
+ if(block->panel) uiDrawBlock(block);
+ block= block->next;
+ }
+
+}
+
+
+
+/* ------------ panel merging ---------------- */
+
+static void check_panel_overlap(ScrArea *sa, Panel *panel)
+{
+ Panel *pa= sa->panels.first;
+
+ /* also called with panel==NULL for clear */
+
+ while(pa) {
+ pa->flag &= ~PNL_OVERLAP;
+ if(panel && (pa != panel)) {
+ if(pa->paneltab==NULL && pa->active) {
+ float safex= 0.2, safey= 0.2;
+
+ if( pa->flag & PNL_CLOSEDX) safex= 0.05;
+ else if(pa->flag & PNL_CLOSEDY) safey= 0.05;
+ else if( panel->flag & PNL_CLOSEDX) safex= 0.05;
+ else if(panel->flag & PNL_CLOSEDY) safey= 0.05;
+
+ if( pa->ofsx > panel->ofsx- safex*panel->sizex)
+ if( pa->ofsx+pa->sizex < panel->ofsx+ (1.0+safex)*panel->sizex)
+ if( pa->ofsy > panel->ofsy- safey*panel->sizey)
+ if( pa->ofsy+pa->sizey < panel->ofsy+ (1.0+safey)*panel->sizey)
+ pa->flag |= PNL_OVERLAP;
+ }
+ }
+
+ pa= pa->next;
+ }
+}
+
+static void test_add_new_tabs(ScrArea *sa)
+{
+ Panel *pa, *pasel=NULL, *palap=NULL;
+ /* search selected and overlapped panel */
+
+ pa= sa->panels.first;
+ while(pa) {
+ if(pa->active) {
+ if(pa->flag & PNL_SELECT) pasel= pa;
+ if(pa->flag & PNL_OVERLAP) palap= pa;
+ }
+ pa= pa->next;
+ }
+
+ if(pasel && palap==NULL) {
+
+ /* copy locations */
+ pa= sa->panels.first;
+ while(pa) {
+ if(pa->paneltab==pasel) {
+ copy_panel_offset(pa, pasel);
+ }
+ pa= pa->next;
+ }
+ }
+
+ if(pasel==NULL || palap==NULL) return;
+
+ /* the overlapped panel becomes a tab */
+ palap->paneltab= pasel;
+
+ /* the selected panel gets coords of overlapped one */
+ copy_panel_offset(pasel, palap);
+
+ /* and its tabs */
+ pa= sa->panels.first;
+ while(pa) {
+ if(pa->paneltab == pasel) {
+ copy_panel_offset(pa, palap);
+ }
+ pa= pa->next;
+ }
+
+ /* but, the overlapped panel already can have tabs too! */
+ pa= sa->panels.first;
+ while(pa) {
+ if(pa->paneltab == palap) {
+ pa->paneltab = pasel;
+ }
+ pa= pa->next;
+ }
+}
+
+/* ------------ panel drag ---------------- */
+
+
+static void ui_drag_panel(uiBlock *block, int doscale)
+{
+ Panel *panel= block->panel;
+ short align=0, first=1, dx=0, dy=0, dxo=0, dyo=0, mval[2], mvalo[2];
+ short ofsx, ofsy, sizex, sizey;
+
+ if(curarea->spacetype==SPACE_BUTS) {
+ SpaceButs *sbuts= curarea->spacedata.first;
+ align= sbuts->align;
+ }
+
+ uiGetMouse(block->win, mvalo);
+ ofsx= block->panel->ofsx;
+ ofsy= block->panel->ofsy;
+ sizex= block->panel->sizex;
+ sizey= block->panel->sizey;
+
+ panel->flag |= PNL_SELECT;
+
+ /* exception handling, 3d window preview panel */
+ if(block->drawextra==BIF_view3d_previewdraw)
+ BIF_view3d_previewrender_clear(curarea);
+
+ while(TRUE) {
+
+ if( !(get_mbut() & L_MOUSE) ) break;
+
+ /* first clip for window, no dragging outside */
+ getmouseco_areawin(mval);
+ if( mval[0]>0 && mval[0]<curarea->winx && mval[1]>0 && mval[1]<curarea->winy) {
+ uiGetMouse(mywinget(), mval);
+ dx= (mval[0]-mvalo[0]) & ~(PNL_GRID-1);
+ dy= (mval[1]-mvalo[1]) & ~(PNL_GRID-1);
+ }
+
+ if(dx!=dxo || dy!=dyo || first || align) {
+ dxo= dx; dyo= dy;
+ first= 0;
+
+ if(doscale) {
+ panel->sizex = MAX2(sizex+dx, UI_PANEL_MINX);
+
+ if(sizey-dy < UI_PANEL_MINY) {
+ dy= -UI_PANEL_MINY+sizey;
+ }
+ panel->sizey = sizey-dy;
+
+ panel->ofsy= ofsy+dy;
+
+ }
+ else {
+ /* reset the panel snapping, to allow dragging away from snapped edges */
+ panel->snap = PNL_SNAP_NONE;
+
+ panel->ofsx = ofsx+dx;
+ panel->ofsy = ofsy+dy;
+ check_panel_overlap(curarea, panel);
+
+ if(align) uiAlignPanelStep(curarea, 0.2);
+ }
+
+ /* warn: this re-allocs blocks! */
+ scrarea_do_windraw(curarea);
+ ui_redraw_select_panel(curarea);
+ screen_swapbuffers();
+
+ /* so, we find the new block */
+ block= curarea->uiblocks.first;
+ while(block) {
+ if(block->panel == panel) break;
+ block= block->next;
+ }
+ // temporal debug
+ if(block==NULL) {
+ printf("block null while panel drag, should not happen\n");
+ }
+
+ /* restore */
+ Mat4CpyMat4(UIwinmat, block->winmat);
+
+ /* idle for align */
+ if(dx==dxo && dy==dyo) PIL_sleep_ms(30);
+ }
+ /* idle for this poor code */
+ else PIL_sleep_ms(30);
+ }
+
+ test_add_new_tabs(curarea); // also copies locations of tabs in dragged panel
+
+ panel->flag &= ~PNL_SELECT;
+ check_panel_overlap(curarea, NULL); // clears
+
+ if(align==0) addqueue(block->win, REDRAW, 1);
+ else ui_animate_panels(curarea);
+
+ /* exception handling, 3d window preview panel */
+ if(block->drawextra==BIF_view3d_previewdraw)
+ BIF_view3d_previewrender_signal(curarea, PR_DISPRECT);
+ else if(strcmp(block->name, "image_panel_preview")==0)
+ image_preview_event(2);
+}
+
+
+static void ui_panel_untab(uiBlock *block)
+{
+ Panel *panel= block->panel, *pa, *panew=NULL;
+ short nr, mval[2], mvalo[2];
+
+ /* while hold mouse, check for movement, then untab */
+
+ uiGetMouse(block->win, mvalo);
+ while(TRUE) {
+
+ if( !(get_mbut() & L_MOUSE) ) break;
+ uiGetMouse(mywinget(), mval);
+
+ if( abs(mval[0]-mvalo[0]) + abs(mval[1]-mvalo[1]) > 6 ) {
+ /* find new parent panel */
+ nr= 0;
+ pa= curarea->panels.first;
+ while(pa) {
+ if(pa->paneltab==panel) {
+ panew= pa;
+ nr++;
+ }
+ pa= pa->next;
+ }
+
+ /* make old tabs point to panew */
+ if(panew==NULL) printf("panel untab: shouldnt happen\n");
+ panew->paneltab= NULL;
+
+ pa= curarea->panels.first;
+ while(pa) {
+ if(pa->paneltab==panel) {
+ pa->paneltab= panew;
+ }
+ pa= pa->next;
+ }
+
+ ui_drag_panel(block, 0);
+ break;
+
+ }
+ /* idle for this poor code */
+ else PIL_sleep_ms(50);
+
+ }
+
+}
+
+/* ------------ panel events ---------------- */
+
+
+static void panel_clicked_tabs(uiBlock *block, int mousex)
+{
+ Panel *pa, *tabsel=NULL, *panel= block->panel;
+ int nr= 1, a, width, ofsx;
+
+ ofsx= PNL_ICON;
+ if(block->panel->control & UI_PNL_CLOSE) ofsx+= PNL_ICON;
+
+
+ /* count */
+ pa= curarea->panels.first;
+ while(pa) {
+ if(pa!=panel) {
+ if(pa->paneltab==panel) nr++;
+ }
+ pa= pa->next;
+ }
+
+ if(nr==1) return;
+
+ /* find clicked tab, mouse in panel coords */
+ a= 0;
+ width= (int)((float)(panel->sizex - ofsx-10)/nr);
+ pa= curarea->panels.first;
+ while(pa) {
+ if(pa==panel || pa->paneltab==panel) {
+ if( (mousex > ofsx+a*width) && (mousex < ofsx+(a+1)*width) ) {
+ tabsel= pa;
+ break;
+ }
+ a++;
+ }
+ pa= pa->next;
+ }
+
+ if(tabsel) {
+
+ if(tabsel == panel) {
+ ui_panel_untab(block);
+ }
+ else {
+ /* tabsel now becomes parent for all others */
+ panel->paneltab= tabsel;
+ tabsel->paneltab= NULL;
+
+ pa= curarea->panels.first;
+ while(pa) {
+ if(pa->paneltab == panel) pa->paneltab = tabsel;
+ pa= pa->next;
+ }
+
+ addqueue(curarea->win, REDRAW, 1);
+ }
+ }
+
+}
+
+/* disabled /deprecated now, panels minimise in place */
+#if 0
+static void stow_unstow(uiBlock *block)
+{
+ SpaceLink *sl= curarea->spacedata.first;
+ Panel *pa;
+ int ok=0, x, y, width;
+
+ if(block->panel->flag & PNL_CLOSEDY) { // flag has been set how it should become!
+
+ width= (curarea->winx-320)/sl->blockscale;
+ if(width<5) width= 5;
+
+ /* find empty spot in bottom */
+ for(y=4; y<100; y+= PNL_HEADER+4) {
+ for(x=4; x<width; x+= 324) {
+ ok= 1;
+ /* check overlap with other panels */
+ for(pa=curarea->panels.first; pa; pa=pa->next) {
+ if(pa!=block->panel && pa->active && pa->paneltab==NULL) {
+ if( abs(pa->ofsx-x)<320 ) {
+ if( abs(pa->ofsy+pa->sizey-y)<PNL_HEADER+4) ok= 0;
+ }
+ }
+ }
+
+ if(ok) break;
+ }
+ if(ok) break;
+ }
+ if(ok==0) printf("still primitive code... fix!\n");
+
+ block->panel->old_ofsx= block->panel->ofsx;
+ block->panel->old_ofsy= block->panel->ofsy;
+
+ block->panel->ofsx= x;
+ block->panel->ofsy= y-block->panel->sizey;
+
+ }
+ else {
+ block->panel->ofsx= block->panel->old_ofsx;
+ block->panel->ofsy= block->panel->old_ofsy;
+
+ }
+ /* copy locations */
+ for(pa= curarea->panels.first; pa; pa= pa->next) {
+ if(pa->paneltab==block->panel) copy_panel_offset(pa, block->panel);
+ }
+
+}
+#endif
+
+
+/* this function is supposed to call general window drawing too */
+/* also it supposes a block has panel, and isnt a menu */
+void ui_do_panel(uiBlock *block, uiEvent *uevent)
+{
+ Panel *pa;
+ int align= 0;
+
+ if(curarea->spacetype==SPACE_BUTS) {
+ SpaceButs *sbuts= curarea->spacedata.first;
+ align= sbuts->align;
+ }
+
+ /* mouse coordinates in panel space! */
+
+ if(uevent->event==LEFTMOUSE && block->panel->paneltab==NULL) {
+ int button= 0;
+
+ /* check open/collapsed button */
+ if(block->panel->flag & PNL_CLOSEDX) {
+ if(uevent->mval[1] >= block->maxy) button= 1;
+ }
+ else if(block->panel->control & UI_PNL_CLOSE) {
+ if(uevent->mval[0] <= block->minx+PNL_ICON-2) button= 2;
+ else if(uevent->mval[0] <= block->minx+2*PNL_ICON+2) button= 1;
+ }
+ else if(uevent->mval[0] <= block->minx+PNL_ICON+2) {
+ button= 1;
+ }
+
+ if(button) {
+
+ if(button==2) { // close
+ rem_blockhandler(curarea, block->handler);
+ addqueue(curarea->win, REDRAW, 1);
+ }
+ else { // collapse
+
+ if(block->panel->flag & PNL_CLOSED) {
+ block->panel->flag &= ~PNL_CLOSED;
+ /* snap back up so full panel aligns with screen edge */
+ if (block->panel->snap & PNL_SNAP_BOTTOM)
+ block->panel->ofsy= 0;
+ }
+ else if(align==BUT_HORIZONTAL) block->panel->flag |= PNL_CLOSEDX;
+ else {
+ /* snap down to bottom screen edge*/
+ block->panel->flag |= PNL_CLOSEDY;
+ if (block->panel->snap & PNL_SNAP_BOTTOM)
+ block->panel->ofsy= -block->panel->sizey;
+ }
+
+ for(pa= curarea->panels.first; pa; pa= pa->next) {
+ if(pa->paneltab==block->panel) {
+ if(block->panel->flag & PNL_CLOSED) pa->flag |= PNL_CLOSED;
+ else pa->flag &= ~PNL_CLOSED;
+ }
+ }
+ }
+ if(align==0) addqueue(block->win, REDRAW, 1);
+ else ui_animate_panels(curarea);
+
+ }
+ else if(block->panel->flag & PNL_CLOSED) {
+ ui_drag_panel(block, 0);
+ }
+ /* check if clicked in tabbed area */
+ else if(uevent->mval[0] < block->maxx-PNL_ICON-3 && panel_has_tabs(block->panel)) {
+ panel_clicked_tabs(block, uevent->mval[0]);
+ }
+ else {
+ ui_drag_panel(block, 0);
+ }
+ }
+}
+
+/* panel with scaling widget */
+void ui_scale_panel(uiBlock *block)
+{
+ if(block->panel->flag & PNL_CLOSED)
+ return;
+
+ ui_drag_panel(block, 1);
+}
+
+
diff --git a/source/blender/src/keyval.c b/source/blender/src/keyval.c
new file mode 100644
index 00000000000..79445fa7aa2
--- /dev/null
+++ b/source/blender/src/keyval.c
@@ -0,0 +1,354 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BIF_keyval.h"
+#include "blendef.h"
+#include "mydevice.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+char *key_event_to_string(unsigned short event)
+{
+
+ switch(event) {
+ case AKEY:
+ return "A";
+ break;
+ case BKEY:
+ return "B";
+ break;
+ case CKEY:
+ return "C";
+ break;
+ case DKEY:
+ return "D";
+ break;
+ case EKEY:
+ return "E";
+ break;
+ case FKEY:
+ return "F";
+ break;
+ case GKEY:
+ return "G";
+ break;
+ case HKEY:
+ return "H";
+ break;
+ case IKEY:
+ return "I";
+ break;
+ case JKEY:
+ return "J";
+ break;
+ case KKEY:
+ return "K";
+ break;
+ case LKEY:
+ return "L";
+ break;
+ case MKEY:
+ return "M";
+ break;
+ case NKEY:
+ return "N";
+ break;
+ case OKEY:
+ return "O";
+ break;
+ case PKEY:
+ return "P";
+ break;
+ case QKEY:
+ return "Q";
+ break;
+ case RKEY:
+ return "R";
+ break;
+ case SKEY:
+ return "S";
+ break;
+ case TKEY:
+ return "T";
+ break;
+ case UKEY:
+ return "U";
+ break;
+ case VKEY:
+ return "V";
+ break;
+ case WKEY:
+ return "W";
+ break;
+ case XKEY:
+ return "X";
+ break;
+ case YKEY:
+ return "Y";
+ break;
+ case ZKEY:
+ return "Z";
+ break;
+
+ case ZEROKEY:
+ return "Zero";
+ break;
+ case ONEKEY:
+ return "One";
+ break;
+ case TWOKEY:
+ return "Two";
+ break;
+ case THREEKEY:
+ return "Three";
+ break;
+ case FOURKEY:
+ return "Four";
+ break;
+ case FIVEKEY:
+ return "Five";
+ break;
+ case SIXKEY:
+ return "Six";
+ break;
+ case SEVENKEY:
+ return "Seven";
+ break;
+ case EIGHTKEY:
+ return "Eight";
+ break;
+ case NINEKEY:
+ return "Nine";
+ break;
+
+ case LEFTCTRLKEY:
+ return "Leftctrl";
+ break;
+ case LEFTALTKEY:
+ return "Leftalt";
+ break;
+ case RIGHTALTKEY:
+ return "Rightalt";
+ break;
+ case RIGHTCTRLKEY:
+ return "Rightctrl";
+ break;
+ case RIGHTSHIFTKEY:
+ return "Rightshift";
+ break;
+ case LEFTSHIFTKEY:
+ return "Leftshift";
+ break;
+
+ case ESCKEY:
+ return "Esc";
+ break;
+ case TABKEY:
+ return "Tab";
+ break;
+ case RETKEY:
+ return "Ret";
+ break;
+ case SPACEKEY:
+ return "Space";
+ break;
+ case LINEFEEDKEY:
+ return "Linefeed";
+ break;
+ case BACKSPACEKEY:
+ return "Backspace";
+ break;
+ case DELKEY:
+ return "Del";
+ break;
+ case SEMICOLONKEY:
+ return "Semicolon";
+ break;
+ case PERIODKEY:
+ return "Period";
+ break;
+ case COMMAKEY:
+ return "Comma";
+ break;
+ case QUOTEKEY:
+ return "Quote";
+ break;
+ case ACCENTGRAVEKEY:
+ return "Accentgrave";
+ break;
+ case MINUSKEY:
+ return "Minus";
+ break;
+ case SLASHKEY:
+ return "Slash";
+ break;
+ case BACKSLASHKEY:
+ return "Backslash";
+ break;
+ case EQUALKEY:
+ return "Equal";
+ break;
+ case LEFTBRACKETKEY:
+ return "Leftbracket";
+ break;
+ case RIGHTBRACKETKEY:
+ return "Rightbracket";
+ break;
+
+ case LEFTARROWKEY:
+ return "Leftarrow";
+ break;
+ case DOWNARROWKEY:
+ return "Downarrow";
+ break;
+ case RIGHTARROWKEY:
+ return "Rightarrow";
+ break;
+ case UPARROWKEY:
+ return "Uparrow";
+ break;
+
+ case PAD2:
+ return "Pad2";
+ break;
+ case PAD4:
+ return "Pad4";
+ break;
+ case PAD6:
+ return "Pad6";
+ break;
+ case PAD8:
+ return "Pad8";
+ break;
+ case PAD1:
+ return "Pad1";
+ break;
+ case PAD3:
+ return "Pad3";
+ break;
+ case PAD5:
+ return "Pad5";
+ break;
+ case PAD7:
+ return "Pad7";
+ break;
+ case PAD9:
+ return "Pad9";
+ break;
+
+ case PADPERIOD:
+ return "Padperiod";
+ break;
+ case PADSLASHKEY:
+ return "Padslash";
+ break;
+ case PADASTERKEY:
+ return "Padaster";
+ break;
+
+ case PAD0:
+ return "Pad0";
+ break;
+ case PADMINUS:
+ return "Padminus";
+ break;
+ case PADENTER:
+ return "Padenter";
+ break;
+ case PADPLUSKEY:
+ return "Padplus";
+ break;
+
+ case F1KEY:
+ return "F1";
+ break;
+ case F2KEY:
+ return "F2";
+ break;
+ case F3KEY:
+ return "F3";
+ break;
+ case F4KEY:
+ return "F4";
+ break;
+ case F5KEY:
+ return "F5";
+ break;
+ case F6KEY:
+ return "F6";
+ break;
+ case F7KEY:
+ return "F7";
+ break;
+ case F8KEY:
+ return "F8";
+ break;
+ case F9KEY:
+ return "F9";
+ break;
+ case F10KEY:
+ return "F10";
+ break;
+ case F11KEY:
+ return "F11";
+ break;
+ case F12KEY:
+ return "F12";
+ break;
+
+ case PAUSEKEY:
+ return "Pause";
+ break;
+ case INSERTKEY:
+ return "Insert";
+ break;
+ case HOMEKEY:
+ return "Home";
+ break;
+ case PAGEUPKEY:
+ return "Pageup";
+ break;
+ case PAGEDOWNKEY:
+ return "Pagedown";
+ break;
+ case ENDKEY:
+ return "End";
+ break;
+ }
+
+ return "";
+}
diff --git a/source/blender/src/language.c b/source/blender/src/language.c
new file mode 100644
index 00000000000..c289d75f88b
--- /dev/null
+++ b/source/blender/src/language.c
@@ -0,0 +1,453 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is written by Rob Haarsma (phase)
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "DNA_listBase.h"
+#include "DNA_userdef_types.h"
+#include "DNA_vec_types.h"
+
+#include "BKE_global.h" /* G */
+#include "BKE_utildefines.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_linklist.h" /* linknode */
+
+#include "BIF_gl.h"
+#include "BIF_language.h"
+#include "BIF_space.h" /* allqueue() */
+#include "BIF_toolbox.h" /* error() */
+#include "datatoc.h" /* std font */
+
+#include "MEM_guardedalloc.h" /* vprintf, etc ??? */
+
+#include "mydevice.h" /* REDRAWALL */
+
+#include "BMF_Api.h"
+
+#ifdef WITH_ICONV
+#include "iconv.h"
+
+void string_to_utf8(char *original, char *utf_8, char *code)
+{
+ size_t inbytesleft=strlen(original);
+ size_t outbytesleft=512;
+ size_t rv=0;
+ iconv_t cd;
+
+ cd=iconv_open("UTF-8", code);
+
+ if (cd == (iconv_t)(-1)) {
+ printf("iconv_open Error");
+ *utf_8='\0';
+ return ;
+ }
+ rv=iconv(cd, &original, &inbytesleft, &utf_8, &outbytesleft);
+ if (rv == (size_t) -1) {
+ printf("iconv Error\n");
+ return ;
+ }
+ *utf_8 = '\0';
+ iconv_close(cd);
+}
+#endif // WITH_ICONV
+
+#ifdef INTERNATIONAL
+#include "FTF_Api.h"
+
+static struct LANGMenuEntry *langmenu= 0;
+static int tot_lang = 0;
+
+#endif // INTERNATIONAL
+
+void BIF_RasterPos(float x, float y)
+{
+#ifdef INTERNATIONAL
+ FTF_SetPosition(x, y);
+#endif // INTERNATIONAL
+}
+
+void BIF_SetScale(float aspect)
+{
+#ifdef INTERNATIONAL
+ FTF_SetScale(aspect);
+#endif // INTERNATIONAL
+}
+
+void refresh_interface_font(void)
+{
+#ifdef INTERNATIONAL
+ if(U.transopts & USER_DOTRANSLATE)
+ start_interface_font();
+ else
+ G.ui_international = FALSE;
+#else // INTERNATIONAL
+ G.ui_international = FALSE;
+#endif
+}
+
+int BIF_DrawString(BMF_Font* font, char *str, int translate)
+{
+
+#ifdef INTERNATIONAL
+ if(G.ui_international == TRUE) {
+ if(translate)
+ {
+#ifdef WITH_ICONV
+ if(translate & CONVERT_TO_UTF8) {
+ char utf_8[512];
+
+ struct LANGMenuEntry *lme;
+ lme = find_language(U.language);
+
+ if (lme !=NULL) {
+ if (!strcmp(lme->code, "ja_JP"))
+ string_to_utf8(str, utf_8, "Shift_JIS"); /* Japanese */
+ else if (!strcmp(lme->code, "zh_CN"))
+ string_to_utf8(str, utf_8, "GB2312"); /* Chinese */
+ }
+
+ return FTF_DrawString(utf_8, FTF_INPUT_UTF8);
+ }
+ else
+#endif // WITH_ICONV
+ return FTF_DrawString(str, FTF_USE_GETTEXT | FTF_INPUT_UTF8);
+ }
+ else
+ return FTF_DrawString(str, FTF_NO_TRANSCONV | FTF_INPUT_UTF8);
+ } else {
+ return BMF_DrawString(font, str);
+ }
+#else // INTERNATIONAL
+ return BMF_DrawString(font, str);
+#endif
+
+}
+
+
+float BIF_GetStringWidth(BMF_Font* font, char *str, int translate)
+{
+ float rt;
+
+#ifdef INTERNATIONAL
+ if(G.ui_international == TRUE)
+ if(translate && (U.transopts & USER_TR_BUTTONS))
+ rt= FTF_GetStringWidth(str, FTF_USE_GETTEXT | FTF_INPUT_UTF8);
+ else
+ rt= FTF_GetStringWidth(str, FTF_NO_TRANSCONV | FTF_INPUT_UTF8);
+ else
+ rt= BMF_GetStringWidth(font, str);
+#else
+ rt= BMF_GetStringWidth(font, str);
+#endif
+
+ return rt;
+}
+
+void BIF_GetBoundingBox(struct BMF_Font* font, char* str, int translate, rctf *bbox){
+ float dummy;
+#ifdef INTERNATIONAL
+ if(G.ui_international == TRUE)
+ if(translate && (U.transopts & USER_TR_BUTTONS))
+ FTF_GetBoundingBox(str, &bbox->xmin, &bbox->ymin, &dummy, &bbox->xmax, &bbox->ymax, &dummy, FTF_USE_GETTEXT | FTF_INPUT_UTF8);
+ else
+ FTF_GetBoundingBox(str, &bbox->xmin, &bbox->ymin, &dummy, &bbox->xmax, &bbox->ymax, &dummy, FTF_NO_TRANSCONV | FTF_INPUT_UTF8);
+ else
+ BMF_GetStringBoundingBox(font, str, &bbox->xmin, &bbox->ymin, &bbox->xmax, &bbox->ymax);
+#else
+ BMF_GetStringBoundingBox(font, str, &bbox->xmin, &bbox->ymin, &bbox->xmax, &bbox->ymax);
+#endif
+}
+
+
+#ifdef INTERNATIONAL
+
+char *fontsize_pup(void)
+{
+ static char string[1024];
+ char formatstring[1024];
+
+ strcpy(formatstring, "Choose Font Size: %%t|%s %%x%d|%s %%x%d|%s %%x%d|%s %%x%d|%s %%x%d|%s %%x%d|%s %%x%d|%s %%x%d|%s %%x%d");
+
+ sprintf(string, formatstring,
+ "Font Size: 8", 8,
+ "Font Size: 9", 9,
+ "Font Size: 10", 10,
+ "Font Size: 11", 11,
+ "Font Size: 12", 12,
+ "Font Size: 13", 13,
+ "Font Size: 14", 14,
+ "Font Size: 15", 15,
+ "Font Size: 16", 16
+ );
+
+ return (string);
+}
+
+
+char *language_pup(void)
+{
+ struct LANGMenuEntry *lme = langmenu;
+ static char string[1024];
+ static char tmp[1024];
+
+ if(tot_lang == 0)
+ sprintf(string, "Choose Language: %%t|Language: English %%x0");
+ else {
+ sprintf(string, "Choose Language: %%t");
+ while(lme) {
+ sprintf(tmp, "|Language: %s %%x%d", lme->language, lme->id);
+ strcat(string, tmp);
+ lme= lme->next;
+ }
+ }
+
+ return string;
+}
+
+
+struct LANGMenuEntry *find_language(short langid)
+{
+ struct LANGMenuEntry *lme = langmenu;
+
+ while(lme) {
+ if(lme->id == langid)
+ return lme;
+
+ lme=lme->next;
+ }
+ return NULL;
+}
+
+
+void lang_setlanguage(void)
+{
+ struct LANGMenuEntry *lme;
+
+ lme = find_language(U.language);
+ if(lme) FTF_SetLanguage(lme->code);
+ else FTF_SetLanguage("en_US");
+}
+
+/* called from fileselector */
+void set_interface_font(char *str)
+{
+
+ /* this test needed because fileselect callback can happen after disable AA fonts */
+ if(U.transopts & USER_DOTRANSLATE) {
+ if(FTF_SetFont((unsigned char*)str, 0, U.fontsize)) {
+ lang_setlanguage();
+
+ if(strlen(str) < FILE_MAXDIR) strcpy(U.fontname, str);
+ G.ui_international = TRUE;
+ }
+ else {
+ U.fontname[0]= 0;
+ FTF_SetFont((unsigned char*)datatoc_bfont_ttf, datatoc_bfont_ttf_size, U.fontsize);
+ G.ui_international = TRUE; // this case will switch to standard font
+ okee("Invalid font selection - reverting to built-in font.");
+ }
+ allqueue(REDRAWALL, 0);
+ }
+}
+
+
+void start_interface_font(void)
+{
+ int result = 0;
+
+ if(U.transopts & USER_USETEXTUREFONT)
+ FTF_SetMode(FTF_TEXTUREFONT);
+ else
+ FTF_SetMode(FTF_PIXMAPFONT);
+
+ if(U.fontsize && U.fontname[0] ) { // we have saved user settings + fontpath
+
+ // try loading font from U.fontname = full path to font in usersettings
+ result = FTF_SetFont((unsigned char*)U.fontname, 0, U.fontsize);
+ }
+ else if(U.fontsize) { // user settings, default
+ result = FTF_SetFont((unsigned char*)datatoc_bfont_ttf, datatoc_bfont_ttf_size, U.fontsize);
+ }
+
+ if(result==0) { // use default
+ U.language= 0;
+ U.fontsize= 11;
+ U.encoding= 0;
+ U.fontname[0]= 0;
+ result = FTF_SetFont((unsigned char*)datatoc_bfont_ttf, datatoc_bfont_ttf_size, U.fontsize);
+ }
+
+ if(result) {
+
+ lang_setlanguage();
+
+ G.ui_international = TRUE;
+ }
+ else {
+ printf("no font found for international support\n");
+ G.ui_international = FALSE;
+ U.transopts &= ~USER_DOTRANSLATE;
+ U.fontsize = 0;
+ }
+
+ allqueue(REDRAWALL, 0);
+}
+
+
+static char *first_dpointchar(char *string)
+{
+ char *dpointchar;
+
+ dpointchar= strchr(string, ':');
+
+ return dpointchar;
+}
+
+
+static void splitlangline(char *line, struct LANGMenuEntry *lme)
+{
+ char *dpointchar= first_dpointchar(line);
+
+ if (dpointchar) {
+ lme->code= BLI_strdup(dpointchar+1);
+ *(dpointchar)=0;
+ lme->language= BLI_strdup(line);
+ } else {
+ error("Invalid language file");
+ }
+}
+
+
+static void puplang_insert_entry(char *line)
+{
+ struct LANGMenuEntry *lme, *prev;
+ int sorted = 0;
+
+ prev= NULL;
+ lme= langmenu;
+
+ for (; lme; prev= lme, lme= lme->next) {
+ if (lme->line) {
+ if (BLI_streq(line, lme->line)) {
+ return;
+ } else if (sorted && strcmp(line, lme->line)<0) {
+ break;
+ }
+ }
+ }
+
+ lme= MEM_mallocN(sizeof(*lme), "lme");
+ lme->line = BLI_strdup(line);
+ splitlangline(line, lme);
+ lme->id = tot_lang;
+ tot_lang++;
+
+ if (prev) {
+ lme->next= prev->next;
+ prev->next= lme;
+ } else {
+ lme->next= langmenu;
+ langmenu= lme;
+ }
+}
+
+
+int read_languagefile(void)
+{
+ char name[FILE_MAXDIR+FILE_MAXFILE];
+ LinkNode *l, *lines;
+
+ /* .Blanguages, http://www.blender3d.org/cms/Installation_Policy.352.0.html*/
+#if defined (__APPLE__) || (WIN32)
+ BLI_make_file_string("/", name, BLI_gethome(), ".Blanguages");
+#else
+ BLI_make_file_string("/", name, BLI_gethome(), ".blender/.Blanguages");
+#endif
+
+ lines= BLI_read_file_as_lines(name);
+
+ if(lines == NULL) {
+ /* If not found in home, try current dir
+ * (Resources folder of app bundle on OS X) */
+#if defined (__APPLE__)
+ char *bundlePath = BLI_getbundle();
+ strcpy(name, bundlePath);
+ strcat(name, "/Contents/Resources/.Blanguages");
+#else
+ /* Check the CWD. Takes care of the case where users
+ * unpack blender tarball; cd blender-dir; ./blender */
+ strcpy(name, ".blender/.Blanguages");
+#endif
+ lines= BLI_read_file_as_lines(name);
+
+ if(lines == NULL) {
+ /* If not found in .blender, try current dir */
+ strcpy(name, ".Blanguages");
+ lines= BLI_read_file_as_lines(name);
+ if(lines == NULL) {
+ if(G.f & G_DEBUG) printf("File .Blanguages not found\n");
+ return 0;
+ }
+ }
+ }
+
+ for (l= lines; l; l= l->next) {
+ char *line= l->link;
+
+ if (!BLI_streq(line, "")) {
+ puplang_insert_entry(line);
+ }
+ }
+
+ BLI_free_file_lines(lines);
+
+ return 1;
+}
+
+
+void free_languagemenu(void)
+{
+ struct LANGMenuEntry *lme= langmenu;
+
+ while (lme) {
+ struct LANGMenuEntry *n= lme->next;
+
+ if (lme->line) MEM_freeN(lme->line);
+ if (lme->language) MEM_freeN(lme->language);
+ if (lme->code) MEM_freeN(lme->code);
+ MEM_freeN(lme);
+
+ lme= n;
+ }
+}
+
+#endif /* INTERNATIONAL */
diff --git a/source/blender/src/lorem.c b/source/blender/src/lorem.c
new file mode 100644
index 00000000000..6b3a00f2cc3
--- /dev/null
+++ b/source/blender/src/lorem.c
@@ -0,0 +1,516 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "BIF_editfont.h"
+
+char *BIF_lorem =
+"Lorem ipsum dolor sit amet, consectetuer adipiscing elit. "
+"Aliquam tristique interdum sem. "
+"Nullam pretium, tortor non euismod varius, nulla odio sodales nulla, at bibendum lorem metus sed nulla. "
+"Vestibulum in lectus at pede blandit viverra. "
+"Fusce scelerisque ipsum nec enim. "
+"Fusce euismod nunc id enim. "
+"In venenatis cursus arcu. "
+"Aenean quis dui. "
+"Maecenas laoreet. "
+"Nulla tempor, arcu pulvinar pretium suscipit, tortor wisi dapibus libero, id ornare felis ipsum suscipit purus. "
+"Maecenas ipsum. "
+"Morbi cursus. "
+"Vestibulum diam purus, commodo et, convallis eu, posuere at, ligula. "
+"Nulla aliquam aliquet lorem. "
+"Nunc et mauris hendrerit est bibendum suscipit. "
+"Donec pellentesque libero eu nisl. "
+"Pellentesque eget libero. "
+"Donec tempus ipsum sed quam. "
+"Sed blandit nunc quis enim. "
+"Quisque lectus diam, adipiscing hendrerit, placerat non, pulvinar id, felis. "
+"In congue magna sit amet urna. "
+"Nunc non augue sed nisl dictum laoreet. "
+"Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. "
+"In venenatis dapibus massa. "
+"Nulla hendrerit sapien et quam. "
+"Nunc ac magna lobortis tellus tincidunt posuere. "
+"Cras augue mauris, mattis lobortis, fermentum at, semper ac, tellus. "
+"Cras vitae ligula sit amet sem posuere iaculis. "
+"Aliquam condimentum eleifend felis. "
+"Ut sit amet sapien. "
+"Suspendisse potenti. "
+"Mauris urna. "
+"Ut eu enim eu ante porta vestibulum. "
+"Aenean scelerisque est ac felis. "
+"Suspendisse auctor. "
+"Nunc pellentesque. "
+"Morbi laoreet ante et nibh. "
+"Donec feugiat arcu eget enim. "
+"Morbi vehicula tortor ac ipsum. "
+"Quisque lacus arcu, elementum ac, faucibus vel, posuere id, est. "
+"Proin commodo gravida sem. "
+"Vivamus tincidunt vehicula libero. "
+"Phasellus wisi. "
+"Maecenas pretium tellus eu sapien. "
+"Nunc sit amet nunc. "
+"In hac habitasse platea dictumst. "
+"Aenean dictum neque sed tortor. "
+"Donec et erat. "
+"Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Sed justo turpis, scelerisque ut, mattis sit amet, ornare rutrum, massa. "
+"Vestibulum bibendum enim sit amet velit. "
+"Vivamus tellus ipsum, luctus ut, consectetuer vitae, dignissim non, ligula. "
+"Phasellus lacinia wisi at est. "
+"Donec elit wisi, commodo non, placerat in, convallis id, elit. "
+"Nunc dolor dolor, vestibulum id, bibendum vitae, lacinia id, erat. "
+"Cras sit amet eros. "
+"Suspendisse suscipit lobortis lectus. "
+"Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. "
+"Cras orci. "
+"Praesent massa urna, lobortis semper, auctor a, pretium vitae, tellus. "
+"Curabitur at purus. "
+"Morbi tortor quam, imperdiet venenatis, egestas a, cursus eu, est. "
+"Nunc interdum lectus sit amet libero. "
+"Quisque dignissim placerat ligula. "
+"Nunc porttitor posuere arcu. "
+"Mauris faucibus quam at massa. "
+"Vivamus sodales aliquet mauris. "
+"In id ante. "
+"Pellentesque varius ipsum in arcu. "
+"Fusce mauris lacus, tristique ac, lobortis quis, lobortis luctus, pede. "
+"Sed wisi. "
+"Vestibulum mattis. "
+"Maecenas hendrerit sem nec purus. "
+"Proin id quam. "
+"Cras nec mauris. "
+"Integer orci. "
+"Nullam dui sem, molestie sed, egestas quis, cursus in, magna. "
+"Mauris neque lacus, consectetuer nec, sagittis eu, porttitor eget, dui. "
+"Fusce consectetuer. "
+"Donec nec tellus quis leo lobortis ullamcorper. "
+"Etiam metus urna, aliquet pretium, ultrices eu, cursus ut, turpis. "
+"Morbi bibendum vehicula lectus. "
+"Sed non ante vitae arcu pellentesque tempor. "
+"Fusce sed ligula in sem tempor imperdiet. "
+"Aliquam vel est. "
+"Phasellus sollicitudin sollicitudin nibh. "
+"Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. "
+"Sed vel leo nec eros blandit imperdiet. "
+"Nulla facilisi. "
+"Suspendisse lobortis, dui ut fringilla hendrerit, justo purus ullamcorper ligula, ultricies ultrices dolor enim in libero. "
+"Sed elementum, pede eget porta convallis, dui nulla dignissim pede, eget vehicula odio ante at sem. "
+"Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. "
+"Sed ullamcorper tincidunt ipsum. "
+"Fusce risus nibh, accumsan sit amet, tempus eget, tristique ac, neque. "
+"Sed quis lorem ut tortor facilisis fermentum. "
+"Fusce pulvinar quam sit amet ipsum. "
+"Morbi ac elit quis tellus malesuada blandit. "
+"Maecenas suscipit sollicitudin sem. "
+"Nam sed eros vel lacus lobortis congue. "
+"Proin interdum nunc lobortis orci. "
+"Donec egestas enim eu odio. "
+"Vestibulum id metus. "
+"Pellentesque auctor, sem varius luctus tempus, libero magna cursus neque, et porttitor diam diam quis purus. "
+"Vestibulum sit amet dolor. "
+"Nulla in magna. "
+"Cras id diam at lectus faucibus placerat. "
+"Nunc porta posuere sapien. "
+"Etiam scelerisque. "
+"Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. "
+"Aliquam pellentesque mi sed tortor. "
+"Maecenas eleifend diam non urna. "
+"Donec luctus pharetra tellus. "
+"Proin ac ipsum eget libero bibendum volutpat. "
+"Cras id tellus. "
+"Nulla non risus. "
+"In dolor. "
+"Fusce scelerisque quam in massa ultrices porta. "
+"Morbi ut dolor eu massa egestas condimentum. "
+"Mauris vulputate. "
+"In hac habitasse platea dictumst. "
+"Suspendisse potenti. "
+"Mauris vehicula leo in tortor. "
+"Mauris vel erat a urna laoreet semper. "
+"Pellentesque ut metus ac tellus commodo eleifend. "
+"Suspendisse quis urna. "
+"Curabitur lacinia dignissim dui. "
+"Nam nec ante. "
+"In id enim. "
+"Aenean mattis enim. "
+"In ut neque porttitor risus hendrerit tincidunt. "
+"Suspendisse potenti. "
+"Ut vestibulum lectus vitae tortor. "
+"Duis velit. "
+"Nulla facilisi. "
+"Integer sit amet urna. "
+"Cras varius tortor in pede. "
+"Sed facilisis. "
+"Praesent lacinia libero nec nibh. "
+"Donec aliquam risus non nisl. "
+"Nam a nunc et felis tempor feugiat. "
+"Nunc metus. "
+"Vestibulum euismod, metus in semper laoreet, urna ipsum pharetra lorem, sed ultricies magna lorem sit amet wisi. "
+"Sed wisi. "
+"Nullam facilisis elit sed nisl. "
+"Phasellus mattis leo nec massa. "
+"Aenean malesuada. "
+"Cras wisi erat, lobortis nec, cursus eget, lobortis at, libero. "
+"In massa nisl, rutrum non, cursus nec, faucibus sed, lacus. "
+"Pellentesque malesuada. "
+"Cras euismod, neque ac suscipit tempus, velit lorem luctus elit, dapibus rhoncus wisi est ut sem. "
+"Proin vulputate enim in eros elementum accumsan. "
+"Ut lorem nisl, hendrerit et, interdum nec, lacinia in, dolor. "
+"Duis nec quam. "
+"Praesent velit felis, posuere id, luctus quis, laoreet ut, ipsum. "
+"Praesent eget arcu. "
+"Mauris massa felis, ornare non, ultrices id, tristique in, elit. "
+"Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. "
+"Phasellus vulputate, mi ac bibendum facilisis, libero enim suscipit leo, non nonummy pede diam eget nibh. "
+"Sed tempus. "
+"Aenean interdum suscipit dui. "
+"Aliquam erat volutpat. "
+"Ut malesuada. "
+"Nam commodo, nulla ut fringilla rutrum, orci elit viverra diam, vitae mollis odio odio et purus. "
+"Aliquam erat volutpat. "
+"Sed aliquet lobortis ipsum. "
+"In ut est. "
+"Etiam condimentum. "
+"Vestibulum pellentesque tortor pulvinar lacus. "
+"Aenean orci. "
+"Suspendisse lacus nulla, nonummy a, dictum vitae, egestas quis, eros. "
+"Donec auctor gravida nisl. "
+"Cras ac est rutrum augue pulvinar ornare. "
+"Phasellus mauris nibh, vulputate in, rhoncus imperdiet, dapibus eget, lacus. "
+"Nam nunc mauris, suscipit at, ultricies a, facilisis at, tellus. "
+"Nam accumsan mollis libero. "
+"Vivamus condimentum mattis est. "
+"Donec lacus. "
+"Nullam ac sapien id massa lobortis molestie. "
+"Pellentesque elementum. "
+"Proin ut purus. "
+"Integer et sapien quis turpis commodo mollis. "
+"Nulla consequat. "
+"Proin a wisi ut tellus blandit elementum. "
+"Aliquam nulla lorem, bibendum ac, malesuada vel, elementum et, metus. "
+"Phasellus egestas nibh et ligula. "
+"Vivamus diam odio, lacinia quis, malesuada quis, sollicitudin ut, eros. "
+"Phasellus aliquet lorem ac ipsum. "
+"Sed cursus tellus ac orci. "
+"Phasellus at nulla. "
+"Donec porta sodales ante. "
+"Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. "
+"Sed id lectus at massa ullamcorper tristique. "
+"Suspendisse porttitor lacus. "
+"In hac habitasse platea dictumst. "
+"Nunc non turpis. "
+"Sed sagittis. "
+"Morbi laoreet scelerisque dui. "
+"Nam arcu tellus, tempor vitae, vestibulum et, imperdiet ut, velit. "
+"In sit amet augue a arcu volutpat suscipit. "
+"Donec dictum ultrices lectus. "
+"Phasellus a purus et orci dictum lacinia. "
+"Ut leo. "
+"Cras semper, lorem sit amet tincidunt congue, justo eros varius pede, in bibendum turpis lectus non eros. "
+"Phasellus quam. "
+"Suspendisse mattis sollicitudin magna. "
+"Aenean facilisis diam vel nisl nonummy condimentum. "
+"Suspendisse vel dolor. "
+"Vestibulum nonummy. "
+"Mauris imperdiet semper ante. "
+"Maecenas vulputate eros. "
+"Vestibulum ac dolor. "
+"Fusce risus metus, aliquet eget, facilisis et, feugiat vel, orci. "
+"Ut at nunc id ante sodales vulputate. "
+"Duis tristique mattis ante. "
+"Vestibulum neque mauris, laoreet id, congue interdum, aliquet ut, diam. "
+"Nulla volutpat blandit magna. "
+"Donec accumsan congue diam. "
+"Etiam vel dui eget nisl tempor varius. "
+"Cras dictum massa sed enim. "
+"Cras urna tortor, fringilla ac, ullamcorper in, euismod vel, arcu. "
+"Morbi posuere luctus augue. "
+"Aliquam dui dui, adipiscing in, lobortis eu, luctus eu, nulla. "
+"Cras velit pede, ullamcorper sit amet, feugiat in, auctor vitae, ante. "
+"Suspendisse dictum fringilla mauris. "
+"In a nibh. "
+"Donec ac ligula. "
+"In quam. "
+"Praesent vitae urna ultricies sem aliquam placerat. "
+"Aliquam erat volutpat. "
+"Nam est. "
+"Donec faucibus sodales metus. "
+"Ut congue. "
+"Donec arcu tellus, pharetra ac, vulputate ac, mollis sed, lectus. "
+"Nulla facilisi. "
+"Nullam volutpat nunc et felis. "
+"Sed pede odio, tincidunt in, volutpat malesuada, feugiat gravida, nulla. "
+"Nulla aliquam pede vitae arcu. "
+"Proin velit elit, nonummy sit amet, elementum vitae, varius vitae, dolor. "
+"Donec rutrum ipsum eu mi. "
+"Aliquam et sem. "
+"In adipiscing rhoncus velit. "
+"Nam viverra scelerisque arcu. "
+"Aliquam sem. "
+"Sed tincidunt nulla quis massa. "
+"Mauris faucibus tempus nunc. "
+"Phasellus condimentum. "
+"Curabitur aliquet iaculis sapien. "
+"Nunc rhoncus, odio vitae bibendum dignissim, tellus libero commodo ipsum, ut sollicitudin nisl nisl vel justo. "
+"Nulla facilisi. "
+"Praesent blandit enim ut justo. "
+"Proin elementum, elit eget accumsan pulvinar, orci quam auctor neque, sed convallis diam purus vel felis. "
+"Sed orci leo, eleifend vel, blandit non, semper eu, purus. "
+"Proin bibendum, libero ac consectetuer commodo, eros sapien blandit nisl, eu eleifend nibh nibh vel lectus. "
+"Vivamus placerat. "
+"Integer odio dolor, pharetra non, sodales id, viverra eget, diam. "
+"Nunc mauris magna, egestas quis, feugiat id, fermentum viverra, mi. "
+"Aenean suscipit nisl non nunc. "
+"Proin quis lectus ac tellus nonummy commodo. "
+"Nunc eget diam ac elit vestibulum auctor. "
+"Etiam vulputate, odio sed lacinia consequat, justo mi vulputate purus, sit amet euismod libero metus sed tortor. "
+"Maecenas ac elit sed lorem vulputate gravida. "
+"Proin lectus eros, ullamcorper id, volutpat quis, condimentum tincidunt, sapien. "
+"Sed et massa eget lorem aliquet tempus. "
+"Duis porttitor nisl non risus. "
+"Nam id quam. "
+"Nullam est. "
+"Proin orci diam, posuere et, pharetra commodo, dictum vel, enim. "
+"Proin eget erat. "
+"Donec nisl. "
+"Maecenas auctor velit ut pede. "
+"Nunc vitae lectus nec libero tincidunt hendrerit. "
+"Quisque varius, erat ultrices ultrices euismod, purus lacus dictum eros, at condimentum enim dui nec magna. "
+"Morbi diam. "
+"Phasellus sed est. "
+"Phasellus nec libero in arcu fringilla sollicitudin. "
+"In rutrum nisl at arcu. "
+"Nulla facilisi. "
+"Mauris dignissim. "
+"Etiam est mauris, pharetra sed, viverra et, tincidunt sed, neque. "
+"Ut at lectus id nibh luctus ornare. "
+"Mauris varius porttitor risus. "
+"Ut vulputate aliquet risus. "
+"Vestibulum luctus neque sit amet nunc. "
+"Duis fermentum nibh. "
+"Pellentesque dapibus. "
+"Proin eros libero, aliquam non, condimentum a, sodales ut, turpis. "
+"Integer accumsan mi sed lorem. "
+"Vestibulum pellentesque sodales nisl. "
+"Nulla eu justo quis dui pretium rhoncus. "
+"Praesent viverra commodo mi. "
+"Maecenas dolor libero, viverra a, elementum vitae, aliquet vitae, dui. "
+"Mauris convallis lectus et mi. "
+"Mauris sagittis. "
+"Sed arcu. "
+"Pellentesque auctor. "
+"Donec pellentesque purus non tellus. "
+"Ut leo wisi, ultrices sit amet, ultrices eu, gravida ac, libero. "
+"Mauris fermentum dapibus diam. "
+"Integer quis lacus dapibus odio pellentesque varius. "
+"Fusce pede quam, vehicula ut, pulvinar et, tincidunt sed, felis. "
+"Curabitur eros enim, vulputate sed, aliquam ac, euismod ac, erat. "
+"Ut dignissim, lacus a interdum iaculis, enim orci posuere nunc, nec ultricies lectus risus in odio. "
+"Etiam et massa id dui commodo vehicula. "
+"Nunc blandit tortor quis dui. "
+"Quisque nisl. "
+"Sed venenatis blandit ligula. "
+"Fusce viverra imperdiet magna. "
+"Donec eget nunc quis est pharetra lobortis. "
+"Vestibulum quis lectus. "
+"Mauris vel orci lobortis nunc fermentum bibendum. "
+"Pellentesque eget leo. "
+"Morbi vel urna sit amet erat fermentum facilisis. "
+"Sed vulputate, libero et sollicitudin congue, wisi lectus sodales dolor, eget molestie magna orci vel tellus. "
+"Sed tempor ante et enim. "
+"Mauris elit. "
+"Curabitur ullamcorper vehicula massa. "
+"Sed viverra. "
+"Duis nulla. "
+"Nam bibendum. "
+"Nam tortor lorem, ullamcorper vitae, dictum sed, posuere eu, justo. "
+"Aliquam adipiscing arcu vitae turpis. "
+"Donec malesuada posuere libero. "
+"Ut sed tellus. "
+"Fusce sed nunc eget nisl dapibus malesuada. "
+"Suspendisse potenti. "
+"Integer tristique libero et metus. "
+"Vivamus posuere. "
+"Maecenas non sem non quam fermentum blandit. "
+"Duis risus tellus, rutrum vitae, imperdiet nec, malesuada nec, ipsum. "
+"Nunc quam dolor, luctus eget, placerat non, rhoncus at, tellus. "
+"Duis pede lectus, mattis adipiscing, tempor ut, porta at, mi. "
+"Pellentesque risus nulla, sodales sed, interdum id, nonummy vitae, ligula. "
+"Morbi pulvinar pede ut massa. "
+"Nunc risus mauris, tincidunt et, faucibus eu, suscipit vel, orci. "
+"In faucibus felis in arcu. "
+"Nulla sit amet elit. "
+"Nulla erat sapien, sagittis eget, dignissim eget, viverra eu, felis. "
+"Nam ac ipsum. "
+"Suspendisse vulputate turpis vel sem lacinia ullamcorper. "
+"Mauris ornare ipsum sed ligula. "
+"Duis facilisis neque quis orci. "
+"Nullam et erat et orci lacinia pellentesque. "
+"Donec ac ipsum. "
+"Duis molestie ipsum ac arcu. "
+"Aenean congue accumsan ante. "
+"Integer bibendum, leo ut ornare aliquam, nunc erat condimentum arcu, ut pulvinar mi augue et nulla. "
+"Quisque lacinia aliquet wisi. "
+"Vivamus nec dui. "
+"Etiam wisi leo, euismod vitae, vulputate a, dictum vitae, quam. "
+"Quisque quis tortor. "
+"Etiam interdum. "
+"In massa erat, porttitor sed, tincidunt vel, vehicula fringilla, augue. "
+"Nulla vel urna. "
+"In libero mi, pretium sed, mattis tempus, sagittis sed, massa. "
+"Suspendisse quam wisi, fermentum quis, sagittis at, consequat eget, odio. "
+"Nullam imperdiet, purus quis aliquam cursus, turpis odio egestas justo, placerat gravida turpis wisi vel tortor. "
+"Nunc ultricies porta purus. "
+"Proin elementum erat ac orci. "
+"Ut vel magna nec mi feugiat tincidunt. "
+"Ut ligula. "
+"Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Donec et magna in diam porta nonummy. "
+"Maecenas ut sem in turpis fermentum viverra. "
+"Suspendisse at orci. "
+"Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. "
+"Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Pellentesque rutrum eleifend justo. "
+"Nullam vitae pede. "
+"Donec condimentum nibh et odio. "
+"Sed et metus. "
+"Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. "
+"Nam tempus. "
+"Sed ac wisi. "
+"In hac habitasse platea dictumst. "
+"Sed sed wisi. "
+"Ut facilisis tellus non ligula. "
+"Integer metus. "
+"In lacinia dui. "
+"Curabitur ornare. "
+"Mauris vel urna. "
+"Nam consectetuer dignissim urna. "
+"Nunc elementum porttitor erat. "
+"Sed blandit, risus non commodo nonummy, ligula erat fermentum nibh, eu facilisis ante neque sed sem. "
+"Etiam scelerisque justo eget wisi. "
+"Nunc dignissim. "
+"Proin pulvinar quam non lectus. "
+"Proin ut turpis quis augue pellentesque dictum. "
+"Fusce et lorem. "
+"Aliquam urna lacus, blandit sed, vestibulum sit amet, placerat et, dolor. "
+"Curabitur auctor erat nec lorem. "
+"Phasellus urna wisi, lacinia ut, molestie tincidunt, condimentum id, odio. "
+"Curabitur convallis ullamcorper justo. "
+"Donec vestibulum est ac quam. "
+"Nullam vitae elit eu massa varius vulputate. "
+"Nulla facilisi. "
+"Suspendisse potenti. "
+"Praesent non libero. "
+"Nullam tristique massa id magna viverra commodo. "
+"Vestibulum libero tortor, luctus ac, viverra congue, consectetuer vel, libero. "
+"Aenean arcu augue, luctus id, laoreet pulvinar, dictum sed, lectus. "
+"Donec vestibulum volutpat dolor. "
+"Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. "
+"Pellentesque augue turpis, laoreet nec, malesuada at, nonummy vitae, nibh. "
+"Etiam orci sapien, congue in, porttitor sit amet, rutrum vel, nibh. "
+"Integer eu lorem. "
+"Mauris pretium leo et elit. "
+"In nonummy ultricies sapien. "
+"Mauris varius. "
+"Mauris sed libero. "
+"Curabitur ullamcorper elit eu purus. "
+"Vestibulum velit pede, semper sit amet, lobortis vitae, tincidunt vel, dui. "
+"Nulla neque ante, sagittis eu, vestibulum et, lacinia a, libero. "
+"Morbi sit amet wisi. "
+"Pellentesque non felis quis arcu bibendum ornare. "
+"Aenean enim metus, commodo eu, hendrerit nonummy, euismod ut, quam. "
+"Nulla eleifend nisl quis dolor. "
+"Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. "
+"Maecenas pellentesque massa in erat molestie molestie. "
+"Mauris dignissim dapibus libero. "
+"Sed sed risus id neque dictum ornare. "
+"Sed eu ligula at felis sodales accumsan. "
+"Sed interdum, urna non pharetra hendrerit, quam mi ornare libero, id fringilla tortor orci non velit. "
+"Aliquam nec risus. "
+"Donec at nunc vitae tellus molestie vestibulum. "
+"Pellentesque vel justo. "
+"Duis ligula libero, vulputate quis, adipiscing bibendum, feugiat vitae, velit. "
+"Vivamus et arcu. "
+"Fusce eget quam. "
+"Ut ante. "
+"Suspendisse feugiat metus non ipsum. "
+"Nulla tempus leo ut mi. "
+"Curabitur vitae nisl. "
+"Vivamus elementum. "
+"Etiam a orci. "
+"Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Vivamus urna quam, tincidunt at, ultrices vel, feugiat eget, nulla. "
+"Maecenas lacus magna, nonummy eu, iaculis sed, consectetuer quis, enim. "
+"Praesent a eros. "
+"Aliquam nonummy dignissim neque. "
+"Nulla enim. "
+"Praesent molestie, orci quis tristique volutpat, lacus metus luctus sapien, et facilisis eros neque id sapien. "
+"Nunc condimentum dolor vel orci. "
+"Integer wisi diam, porttitor sit amet, feugiat in, dapibus in, lectus. "
+"Aliquam erat volutpat. "
+"Quisque mollis turpis vitae tortor. "
+"Mauris turpis mi, pretium ut, ultrices sed, porta in, justo. "
+"Suspendisse posuere. "
+"Quisque ultricies lacus vitae enim. "
+"Donec lacus. "
+"Suspendisse potenti. "
+"Donec molestie, magna sed euismod dictum, magna magna interdum diam, vitae sagittis leo lorem ac neque. "
+"Cras metus. "
+"Quisque nunc. "
+"Duis consectetuer. "
+"Vestibulum gravida sollicitudin urna. "
+"Integer volutpat, massa quis ultrices pulvinar, eros purus dignissim nunc, eget rhoncus enim lectus quis tortor. "
+"Integer lacinia quam quis erat convallis mattis. "
+"Suspendisse iaculis posuere velit. "
+"Etiam tellus enim, aliquet nec, laoreet a, molestie non, velit. "
+"Quisque lacus velit, eleifend imperdiet, fringilla id, dapibus scelerisque, lectus. "
+"Nulla quis lorem. "
+"Nulla malesuada neque et dui. "
+"Phasellus malesuada ultricies odio. "
+"Phasellus vitae ligula. "
+"Pellentesque feugiat arcu at erat. "
+"Vivamus ut eros ut lorem pulvinar iaculis. "
+"Proin lobortis ipsum id nunc. "
+"Curabitur vel massa. "
+"Suspendisse nulla ipsum, malesuada vel, posuere eget, mollis at, risus. "
+"Vestibulum sed diam id est dapibus ultrices. "
+"Proin tempus, eros a scelerisque vestibulum, ipsum arcu aliquam mi, ut feugiat libero odio in nisl. "
+"Quisque et massa a mauris luctus congue. "
+"Ut id eros. "
+"Fusce ante eros, pharetra non, molestie tristique, bibendum sit amet, wisi. "
+"Phasellus rutrum, dolor et semper elementum, eros ante malesuada massa, sed sollicitudin lectus velit et massa. "
+"In auctor. "
+"Aliquam erat volutpat. "
+"Etiam risus leo, vulputate suscipit, sollicitudin et, sodales eget, nisl. "
+"Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Curabitur lobortis, libero ac laoreet mollis, ligula leo porta wisi, ut euismod felis ligula id elit. "
+"Vivamus malesuada nulla eu enim. "
+"Donec accumsan faucibus orci. "
+"Nulla lacinia ante. "
+"Praesent at nibh. "
+"Mauris porta dignissim wisi. "
+"Ut lacinia tortor nec nunc. "
+"Phasellus et augue. "
+"Integer rhoncus, libero a pellentesque rhoncus, tortor sapien lobortis pede, eget condimentum sapien risus vitae elit. "
+"Suspendisse sed turpis ut dolor placerat dignissim. "
+"Quisque quis leo. "
+"Cras ultrices. "
+"Maecenas hendrerit auctor tortor. "
+"Etiam sit amet arcu. ";
diff --git a/source/blender/src/mainqueue.c b/source/blender/src/mainqueue.c
new file mode 100644
index 00000000000..30ee825a23a
--- /dev/null
+++ b/source/blender/src/mainqueue.c
@@ -0,0 +1,102 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * Just the functions to maintain a central event
+ * queue.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "BIF_mainqueue.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+typedef struct {
+ unsigned short event;
+ short val;
+ char ascii;
+} QEvent;
+
+static QEvent mainqueue[MAXQUEUE];
+static unsigned int nevents= 0;
+
+unsigned short mainqread(short *val, char *ascii)
+{
+ if (nevents) {
+ nevents--;
+
+ *val= mainqueue[nevents].val;
+ *ascii= mainqueue[nevents].ascii;
+ if((*ascii<32)||(*ascii==127)) *ascii=0;
+ return mainqueue[nevents].event;
+ } else
+ return 0;
+}
+
+void mainqenter(unsigned short event, short val)
+{
+ mainqenter_ext(event, val, 0);
+}
+
+void mainqenter_ext(unsigned short event, short val, char ascii)
+{
+ if (!event)
+ return;
+
+ if (nevents<MAXQUEUE) {
+ memmove(mainqueue+1, mainqueue, sizeof(*mainqueue)*nevents);
+ mainqueue[0].event= event;
+ mainqueue[0].val= val;
+ mainqueue[0].ascii= ascii;
+
+ nevents++;
+ }
+}
+
+void mainqpushback(unsigned short event, short val, char ascii)
+{
+ if (nevents<MAXQUEUE) {
+ mainqueue[nevents].event= event;
+ mainqueue[nevents].val= val;
+ mainqueue[nevents].ascii= ascii;
+ nevents++;
+ }
+}
+
+unsigned short mainqtest()
+{
+ if (nevents)
+ return mainqueue[nevents-1].event;
+ else
+ return 0;
+}
diff --git a/source/blender/src/meshlaplacian.c b/source/blender/src/meshlaplacian.c
new file mode 100644
index 00000000000..c27694ae51e
--- /dev/null
+++ b/source/blender/src/meshlaplacian.c
@@ -0,0 +1,1777 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * meshlaplacian.c: Algorithms using the mesh laplacian.
+ */
+
+#include <math.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+
+#include "BLI_arithb.h"
+#include "BLI_edgehash.h"
+#include "BLI_memarena.h"
+
+#include "BKE_DerivedMesh.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_editdeform.h"
+#include "BIF_meshlaplacian.h"
+#include "BIF_meshtools.h"
+#include "BIF_screen.h"
+#include "BIF_toolbox.h"
+
+#include "BSE_headerbuttons.h"
+
+#ifdef RIGID_DEFORM
+#include "BLI_editVert.h"
+#include "BLI_polardecomp.h"
+#endif
+
+#include "RE_raytrace.h"
+
+#include "ONL_opennl.h"
+
+/************************** Laplacian System *****************************/
+
+struct LaplacianSystem {
+ NLContext context; /* opennl context */
+
+ int totvert, totface;
+
+ float **verts; /* vertex coordinates */
+ float *varea; /* vertex weights for laplacian computation */
+ char *vpinned; /* vertex pinning */
+ int (*faces)[3]; /* face vertex indices */
+ float (*fweights)[3]; /* cotangent weights per face */
+
+ int areaweights; /* use area in cotangent weights? */
+ int storeweights; /* store cotangent weights in fweights */
+ int nlbegun; /* nlBegin(NL_SYSTEM/NL_MATRIX) done */
+
+ EdgeHash *edgehash; /* edge hash for construction */
+
+ struct HeatWeighting {
+ Mesh *mesh;
+ float (*verts)[3]; /* vertex coordinates */
+ float (*vnors)[3]; /* vertex normals */
+
+ float (*root)[3]; /* bone root */
+ float (*tip)[3]; /* bone tip */
+ int numbones;
+
+ float *H; /* diagonal H matrix */
+ float *p; /* values from all p vectors */
+ float *mindist; /* minimum distance to a bone for all vertices */
+
+ RayTree *raytree; /* ray tracing acceleration structure */
+ MFace **vface; /* a face that the vertex belongs to */
+ } heat;
+
+#ifdef RIGID_DEFORM
+ struct RigidDeformation {
+ EditMesh *mesh;
+
+ float (*R)[3][3];
+ float (*rhs)[3];
+ float (*origco)[3];
+ int thrownerror;
+ } rigid;
+#endif
+};
+
+/* Laplacian matrix construction */
+
+/* Computation of these weights for the laplacian is based on:
+ "Discrete Differential-Geometry Operators for Triangulated 2-Manifolds",
+ Meyer et al, 2002. Section 3.5, formula (8).
+
+ We do it a bit different by going over faces instead of going over each
+ vertex and adjacent faces, since we don't store this adjacency. Also, the
+ formulas are tweaked a bit to work for non-manifold meshes. */
+
+static void laplacian_increase_edge_count(EdgeHash *edgehash, int v1, int v2)
+{
+ void **p = BLI_edgehash_lookup_p(edgehash, v1, v2);
+
+ if(p)
+ *p = (void*)((long)*p + (long)1);
+ else
+ BLI_edgehash_insert(edgehash, v1, v2, (void*)(long)1);
+}
+
+static int laplacian_edge_count(EdgeHash *edgehash, int v1, int v2)
+{
+ return (int)(long)BLI_edgehash_lookup(edgehash, v1, v2);
+}
+
+static float cotan_weight(float *v1, float *v2, float *v3)
+{
+ float a[3], b[3], c[3], clen;
+
+ VecSubf(a, v2, v1);
+ VecSubf(b, v3, v1);
+ Crossf(c, a, b);
+
+ clen = VecLength(c);
+
+ if (clen == 0.0f)
+ return 0.0f;
+
+ return Inpf(a, b)/clen;
+}
+
+static void laplacian_triangle_area(LaplacianSystem *sys, int i1, int i2, int i3)
+{
+ float t1, t2, t3, len1, len2, len3, area;
+ float *varea= sys->varea, *v1, *v2, *v3;
+ int obtuse = 0;
+
+ v1= sys->verts[i1];
+ v2= sys->verts[i2];
+ v3= sys->verts[i3];
+
+ t1= cotan_weight(v1, v2, v3);
+ t2= cotan_weight(v2, v3, v1);
+ t3= cotan_weight(v3, v1, v2);
+
+ if(VecAngle3(v2, v1, v3) > 90) obtuse= 1;
+ else if(VecAngle3(v1, v2, v3) > 90) obtuse= 2;
+ else if(VecAngle3(v1, v3, v2) > 90) obtuse= 3;
+
+ if (obtuse > 0) {
+ area= AreaT3Dfl(v1, v2, v3);
+
+ varea[i1] += (obtuse == 1)? area: area*0.5;
+ varea[i2] += (obtuse == 2)? area: area*0.5;
+ varea[i3] += (obtuse == 3)? area: area*0.5;
+ }
+ else {
+ len1= VecLenf(v2, v3);
+ len2= VecLenf(v1, v3);
+ len3= VecLenf(v1, v2);
+
+ t1 *= len1*len1;
+ t2 *= len2*len2;
+ t3 *= len3*len3;
+
+ varea[i1] += (t2 + t3)*0.25f;
+ varea[i2] += (t1 + t3)*0.25f;
+ varea[i3] += (t1 + t2)*0.25f;
+ }
+}
+
+static void laplacian_triangle_weights(LaplacianSystem *sys, int f, int i1, int i2, int i3)
+{
+ float t1, t2, t3;
+ float *varea= sys->varea, *v1, *v2, *v3;
+
+ v1= sys->verts[i1];
+ v2= sys->verts[i2];
+ v3= sys->verts[i3];
+
+ /* instead of *0.5 we divided by the number of faces of the edge, it still
+ needs to be varified that this is indeed the correct thing to do! */
+ t1= cotan_weight(v1, v2, v3)/laplacian_edge_count(sys->edgehash, i2, i3);
+ t2= cotan_weight(v2, v3, v1)/laplacian_edge_count(sys->edgehash, i3, i1);
+ t3= cotan_weight(v3, v1, v2)/laplacian_edge_count(sys->edgehash, i1, i2);
+
+ nlMatrixAdd(i1, i1, (t2+t3)*varea[i1]);
+ nlMatrixAdd(i2, i2, (t1+t3)*varea[i2]);
+ nlMatrixAdd(i3, i3, (t1+t2)*varea[i3]);
+
+ nlMatrixAdd(i1, i2, -t3*varea[i1]);
+ nlMatrixAdd(i2, i1, -t3*varea[i2]);
+
+ nlMatrixAdd(i2, i3, -t1*varea[i2]);
+ nlMatrixAdd(i3, i2, -t1*varea[i3]);
+
+ nlMatrixAdd(i3, i1, -t2*varea[i3]);
+ nlMatrixAdd(i1, i3, -t2*varea[i1]);
+
+ if(sys->storeweights) {
+ sys->fweights[f][0]= t1*varea[i1];
+ sys->fweights[f][1]= t2*varea[i2];
+ sys->fweights[f][2]= t3*varea[i3];
+ }
+}
+
+LaplacianSystem *laplacian_system_construct_begin(int totvert, int totface)
+{
+ LaplacianSystem *sys;
+
+ sys= MEM_callocN(sizeof(LaplacianSystem), "LaplacianSystem");
+
+ sys->verts= MEM_callocN(sizeof(float*)*totvert, "LaplacianSystemVerts");
+ sys->vpinned= MEM_callocN(sizeof(char)*totvert, "LaplacianSystemVpinned");
+ sys->faces= MEM_callocN(sizeof(int)*3*totface, "LaplacianSystemFaces");
+
+ sys->totvert= 0;
+ sys->totface= 0;
+
+ sys->areaweights= 1;
+ sys->storeweights= 0;
+
+ /* create opennl context */
+ nlNewContext();
+ nlSolverParameteri(NL_NB_VARIABLES, totvert);
+
+ sys->context= nlGetCurrent();
+
+ return sys;
+}
+
+void laplacian_add_vertex(LaplacianSystem *sys, float *co, int pinned)
+{
+ sys->verts[sys->totvert]= co;
+ sys->vpinned[sys->totvert]= pinned;
+ sys->totvert++;
+}
+
+void laplacian_add_triangle(LaplacianSystem *sys, int v1, int v2, int v3)
+{
+ sys->faces[sys->totface][0]= v1;
+ sys->faces[sys->totface][1]= v2;
+ sys->faces[sys->totface][2]= v3;
+ sys->totface++;
+}
+
+void laplacian_system_construct_end(LaplacianSystem *sys)
+{
+ int (*face)[3];
+ int a, totvert=sys->totvert, totface=sys->totface;
+
+ laplacian_begin_solve(sys, 0);
+
+ sys->varea= MEM_callocN(sizeof(float)*totvert, "LaplacianSystemVarea");
+
+ sys->edgehash= BLI_edgehash_new();
+ for(a=0, face=sys->faces; a<sys->totface; a++, face++) {
+ laplacian_increase_edge_count(sys->edgehash, (*face)[0], (*face)[1]);
+ laplacian_increase_edge_count(sys->edgehash, (*face)[1], (*face)[2]);
+ laplacian_increase_edge_count(sys->edgehash, (*face)[2], (*face)[0]);
+ }
+
+ if(sys->areaweights)
+ for(a=0, face=sys->faces; a<sys->totface; a++, face++)
+ laplacian_triangle_area(sys, (*face)[0], (*face)[1], (*face)[2]);
+
+ for(a=0; a<totvert; a++) {
+ if(sys->areaweights) {
+ if(sys->varea[a] != 0.0f)
+ sys->varea[a]= 0.5f/sys->varea[a];
+ }
+ else
+ sys->varea[a]= 1.0f;
+
+ /* for heat weighting */
+ if(sys->heat.H)
+ nlMatrixAdd(a, a, sys->heat.H[a]);
+ }
+
+ if(sys->storeweights)
+ sys->fweights= MEM_callocN(sizeof(float)*3*totface, "LaplacianFWeight");
+
+ for(a=0, face=sys->faces; a<totface; a++, face++)
+ laplacian_triangle_weights(sys, a, (*face)[0], (*face)[1], (*face)[2]);
+
+ MEM_freeN(sys->faces);
+ sys->faces= NULL;
+
+ if(sys->varea) {
+ MEM_freeN(sys->varea);
+ sys->varea= NULL;
+ }
+
+ BLI_edgehash_free(sys->edgehash, NULL);
+ sys->edgehash= NULL;
+}
+
+void laplacian_system_delete(LaplacianSystem *sys)
+{
+ if(sys->verts) MEM_freeN(sys->verts);
+ if(sys->varea) MEM_freeN(sys->varea);
+ if(sys->vpinned) MEM_freeN(sys->vpinned);
+ if(sys->faces) MEM_freeN(sys->faces);
+ if(sys->fweights) MEM_freeN(sys->fweights);
+
+ nlDeleteContext(sys->context);
+ MEM_freeN(sys);
+}
+
+void laplacian_begin_solve(LaplacianSystem *sys, int index)
+{
+ int a;
+
+ if (!sys->nlbegun) {
+ nlBegin(NL_SYSTEM);
+
+ if(index >= 0) {
+ for(a=0; a<sys->totvert; a++) {
+ if(sys->vpinned[a]) {
+ nlSetVariable(0, a, sys->verts[a][index]);
+ nlLockVariable(a);
+ }
+ }
+ }
+
+ nlBegin(NL_MATRIX);
+ sys->nlbegun = 1;
+ }
+}
+
+void laplacian_add_right_hand_side(LaplacianSystem *sys, int v, float value)
+{
+ nlRightHandSideAdd(0, v, value);
+}
+
+int laplacian_system_solve(LaplacianSystem *sys)
+{
+ nlEnd(NL_MATRIX);
+ nlEnd(NL_SYSTEM);
+ sys->nlbegun = 0;
+
+ //nlPrintMatrix();
+
+ return nlSolveAdvanced(NULL, NL_TRUE);
+}
+
+float laplacian_system_get_solution(int v)
+{
+ return nlGetVariable(0, v);
+}
+
+/************************* Heat Bone Weighting ******************************/
+/* From "Automatic Rigging and Animation of 3D Characters"
+ Ilya Baran and Jovan Popovic, SIGGRAPH 2007 */
+
+#define C_WEIGHT 1.0f
+#define WEIGHT_LIMIT 0.05f
+#define DISTANCE_EPSILON 1e-4f
+
+/* Raytracing for vertex to bone visibility */
+
+static LaplacianSystem *HeatSys = NULL;
+
+static void heat_ray_coords_func(RayFace *face, float **v1, float **v2, float **v3, float **v4)
+{
+ MFace *mface= (MFace*)face;
+ float (*verts)[3]= HeatSys->heat.verts;
+
+ *v1= verts[mface->v1];
+ *v2= verts[mface->v2];
+ *v3= verts[mface->v3];
+ *v4= (mface->v4)? verts[mface->v4]: NULL;
+}
+
+static int heat_ray_check_func(Isect *is, RayFace *face)
+{
+ float *v1, *v2, *v3, *v4, nor[3];
+
+ /* don't intersect if the ray faces along the face normal */
+ heat_ray_coords_func(face, &v1, &v2, &v3, &v4);
+
+ if(v4) CalcNormFloat4(v1, v2, v3, v4, nor);
+ else CalcNormFloat(v1, v2, v3, nor);
+
+ return (INPR(nor, is->vec) < 0);
+}
+
+static void heat_ray_tree_create(LaplacianSystem *sys)
+{
+ Mesh *me = sys->heat.mesh;
+ RayTree *tree;
+ MFace *mface;
+ float min[3], max[3];
+ int a;
+
+ /* create a raytrace tree from the mesh */
+ INIT_MINMAX(min, max);
+
+ for(a=0; a<me->totvert; a++)
+ DO_MINMAX(sys->heat.verts[a], min, max);
+
+ tree= RE_ray_tree_create(64, me->totface, min, max,
+ heat_ray_coords_func, heat_ray_check_func);
+
+ sys->heat.vface= MEM_callocN(sizeof(MFace*)*me->totvert, "HeatVFaces");
+
+ HeatSys= sys;
+
+ for(a=0, mface=me->mface; a<me->totface; a++, mface++) {
+ RE_ray_tree_add_face(tree, mface);
+
+ sys->heat.vface[mface->v1]= mface;
+ sys->heat.vface[mface->v2]= mface;
+ sys->heat.vface[mface->v3]= mface;
+ if(mface->v4) sys->heat.vface[mface->v4]= mface;
+ }
+
+ HeatSys= NULL;
+
+ RE_ray_tree_done(tree);
+
+ sys->heat.raytree= tree;
+}
+
+static int heat_ray_bone_visible(LaplacianSystem *sys, int vertex, int bone)
+{
+ Isect isec;
+ MFace *mface;
+ float dir[3];
+ int visible;
+
+ mface= sys->heat.vface[vertex];
+ if(!mface)
+ return 1;
+
+ /* setup isec */
+ memset(&isec, 0, sizeof(isec));
+ isec.mode= RE_RAY_SHADOW;
+ isec.lay= -1;
+ isec.face_last= NULL;
+ isec.faceorig= mface;
+
+ VECCOPY(isec.start, sys->heat.verts[vertex]);
+ PclosestVL3Dfl(isec.end, isec.start,
+ sys->heat.root[bone], sys->heat.tip[bone]);
+
+ /* add an extra offset to the start position to avoid self intersection */
+ VECSUB(dir, isec.end, isec.start);
+ Normalize(dir);
+ VecMulf(dir, 1e-5);
+ VecAddf(isec.start, isec.start, dir);
+
+ HeatSys= sys;
+ visible= !RE_ray_tree_intersect(sys->heat.raytree, &isec);
+ HeatSys= NULL;
+
+ return visible;
+}
+
+static float heat_bone_distance(LaplacianSystem *sys, int vertex, int bone)
+{
+ float closest[3], d[3], dist, cosine;
+
+ /* compute euclidian distance */
+ PclosestVL3Dfl(closest, sys->heat.verts[vertex],
+ sys->heat.root[bone], sys->heat.tip[bone]);
+
+ VecSubf(d, sys->heat.verts[vertex], closest);
+ dist= Normalize(d);
+
+ /* if the vertex normal does not point along the bone, increase distance */
+ cosine= INPR(d, sys->heat.vnors[vertex]);
+
+ return dist/(0.5f*(cosine + 1.001f));
+}
+
+static int heat_bone_closest(LaplacianSystem *sys, int vertex, int bone)
+{
+ float dist;
+
+ dist= heat_bone_distance(sys, vertex, bone);
+
+ if(dist <= sys->heat.mindist[vertex]*(1.0f + DISTANCE_EPSILON))
+ if(heat_ray_bone_visible(sys, vertex, bone))
+ return 1;
+
+ return 0;
+}
+
+static void heat_set_H(LaplacianSystem *sys, int vertex)
+{
+ float dist, mindist, h;
+ int j, numclosest = 0;
+
+ mindist= 1e10;
+
+ /* compute minimum distance */
+ for(j=0; j<sys->heat.numbones; j++) {
+ dist= heat_bone_distance(sys, vertex, j);
+
+ if(dist < mindist)
+ mindist= dist;
+ }
+
+ sys->heat.mindist[vertex]= mindist;
+
+ /* count number of bones with approximately this minimum distance */
+ for(j=0; j<sys->heat.numbones; j++)
+ if(heat_bone_closest(sys, vertex, j))
+ numclosest++;
+
+ sys->heat.p[vertex]= (numclosest > 0)? 1.0f/numclosest: 0.0f;
+
+ /* compute H entry */
+ if(numclosest > 0) {
+ if(mindist > 1e-5)
+ h= numclosest*C_WEIGHT/(mindist*mindist);
+ else
+ h= 1e10f;
+ }
+ else
+ h= 0.0f;
+
+ sys->heat.H[vertex]= h;
+}
+
+void heat_calc_vnormals(LaplacianSystem *sys)
+{
+ float fnor[3];
+ int a, v1, v2, v3, (*face)[3];
+
+ sys->heat.vnors= MEM_callocN(sizeof(float)*3*sys->totvert, "HeatVNors");
+
+ for(a=0, face=sys->faces; a<sys->totface; a++, face++) {
+ v1= (*face)[0];
+ v2= (*face)[1];
+ v3= (*face)[2];
+
+ CalcNormFloat(sys->verts[v1], sys->verts[v2], sys->verts[v3], fnor);
+
+ VecAddf(sys->heat.vnors[v1], sys->heat.vnors[v1], fnor);
+ VecAddf(sys->heat.vnors[v2], sys->heat.vnors[v2], fnor);
+ VecAddf(sys->heat.vnors[v3], sys->heat.vnors[v3], fnor);
+ }
+
+ for(a=0; a<sys->totvert; a++)
+ Normalize(sys->heat.vnors[a]);
+}
+
+static void heat_laplacian_create(LaplacianSystem *sys)
+{
+ Mesh *me = sys->heat.mesh;
+ MFace *mface;
+ int a;
+
+ /* heat specific definitions */
+ sys->heat.mindist= MEM_callocN(sizeof(float)*me->totvert, "HeatMinDist");
+ sys->heat.H= MEM_callocN(sizeof(float)*me->totvert, "HeatH");
+ sys->heat.p= MEM_callocN(sizeof(float)*me->totvert, "HeatP");
+
+ /* add verts and faces to laplacian */
+ for(a=0; a<me->totvert; a++)
+ laplacian_add_vertex(sys, sys->heat.verts[a], 0);
+
+ for(a=0, mface=me->mface; a<me->totface; a++, mface++) {
+ laplacian_add_triangle(sys, mface->v1, mface->v2, mface->v3);
+ if(mface->v4)
+ laplacian_add_triangle(sys, mface->v1, mface->v3, mface->v4);
+ }
+
+ /* for distance computation in set_H */
+ heat_calc_vnormals(sys);
+
+ for(a=0; a<me->totvert; a++)
+ heat_set_H(sys, a);
+}
+
+void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numbones, bDeformGroup **dgrouplist, bDeformGroup **dgroupflip, float (*root)[3], float (*tip)[3], int *selected)
+{
+ LaplacianSystem *sys;
+ MFace *mface;
+ float solution;
+ int a, aflip, totface, j, thrownerror = 0;
+
+ /* count triangles */
+ for(totface=0, a=0, mface=me->mface; a<me->totface; a++, mface++) {
+ totface++;
+ if(mface->v4) totface++;
+ }
+
+ /* create laplacian */
+ sys = laplacian_system_construct_begin(me->totvert, totface);
+
+ sys->heat.mesh= me;
+ sys->heat.verts= verts;
+ sys->heat.root= root;
+ sys->heat.tip= tip;
+ sys->heat.numbones= numbones;
+
+ heat_ray_tree_create(sys);
+ heat_laplacian_create(sys);
+
+ laplacian_system_construct_end(sys);
+
+ /* compute weights per bone */
+ for(j=0; j<numbones; j++) {
+ if(!selected[j])
+ continue;
+
+ laplacian_begin_solve(sys, -1);
+
+ for(a=0; a<me->totvert; a++)
+ if(heat_bone_closest(sys, a, j))
+ laplacian_add_right_hand_side(sys, a,
+ sys->heat.H[a]*sys->heat.p[a]);
+
+ if(laplacian_system_solve(sys)) {
+ for(a=0; a<me->totvert; a++) {
+ solution= laplacian_system_get_solution(a);
+
+ if(solution > WEIGHT_LIMIT)
+ add_vert_to_defgroup(ob, dgrouplist[j], a, solution,
+ WEIGHT_REPLACE);
+ else
+ remove_vert_defgroup(ob, dgrouplist[j], a);
+
+ /* do same for mirror */
+ aflip = (dgroupflip)? mesh_get_x_mirror_vert(ob, a): 0;
+ if (dgroupflip && dgroupflip[j] && aflip >= 0) {
+ if(solution > WEIGHT_LIMIT)
+ add_vert_to_defgroup(ob, dgroupflip[j], aflip,
+ solution, WEIGHT_REPLACE);
+ else
+ remove_vert_defgroup(ob, dgroupflip[j], aflip);
+ }
+ }
+ }
+ else if(!thrownerror) {
+ error("Bone Heat Weighting:"
+ " failed to find solution for one or more bones");
+ thrownerror= 1;
+ break;
+ }
+ }
+
+ /* free */
+ RE_ray_tree_free(sys->heat.raytree);
+ MEM_freeN(sys->heat.vface);
+
+ MEM_freeN(sys->heat.mindist);
+ MEM_freeN(sys->heat.H);
+ MEM_freeN(sys->heat.p);
+ MEM_freeN(sys->heat.vnors);
+
+ laplacian_system_delete(sys);
+}
+
+#ifdef RIGID_DEFORM
+/********************** As-Rigid-As-Possible Deformation ******************/
+/* From "As-Rigid-As-Possible Surface Modeling",
+ Olga Sorkine and Marc Alexa, ESGP 2007. */
+
+/* investigate:
+ - transpose R in orthogonal
+ - flipped normals and per face adding
+ - move cancelling to transform, make origco pointer
+*/
+
+static LaplacianSystem *RigidDeformSystem = NULL;
+
+static void rigid_add_half_edge_to_R(LaplacianSystem *sys, EditVert *v1, EditVert *v2, float w)
+{
+ float e[3], e_[3];
+ int i;
+
+ VecSubf(e, sys->rigid.origco[v1->tmp.l], sys->rigid.origco[v2->tmp.l]);
+ VecSubf(e_, v1->co, v2->co);
+
+ /* formula (5) */
+ for (i=0; i<3; i++) {
+ sys->rigid.R[v1->tmp.l][i][0] += w*e[0]*e_[i];
+ sys->rigid.R[v1->tmp.l][i][1] += w*e[1]*e_[i];
+ sys->rigid.R[v1->tmp.l][i][2] += w*e[2]*e_[i];
+ }
+}
+
+static void rigid_add_edge_to_R(LaplacianSystem *sys, EditVert *v1, EditVert *v2, float w)
+{
+ rigid_add_half_edge_to_R(sys, v1, v2, w);
+ rigid_add_half_edge_to_R(sys, v2, v1, w);
+}
+
+static void rigid_orthogonalize_R(float R[][3])
+{
+ HMatrix M, Q, S;
+
+ Mat4CpyMat3(M, R);
+ polar_decomp(M, Q, S);
+ Mat3CpyMat4(R, Q);
+}
+
+static void rigid_add_half_edge_to_rhs(LaplacianSystem *sys, EditVert *v1, EditVert *v2, float w)
+{
+ /* formula (8) */
+ float Rsum[3][3], rhs[3];
+
+ if (sys->vpinned[v1->tmp.l])
+ return;
+
+ Mat3AddMat3(Rsum, sys->rigid.R[v1->tmp.l], sys->rigid.R[v2->tmp.l]);
+ Mat3Transp(Rsum);
+
+ VecSubf(rhs, sys->rigid.origco[v1->tmp.l], sys->rigid.origco[v2->tmp.l]);
+ Mat3MulVecfl(Rsum, rhs);
+ VecMulf(rhs, 0.5f);
+ VecMulf(rhs, w);
+
+ VecAddf(sys->rigid.rhs[v1->tmp.l], sys->rigid.rhs[v1->tmp.l], rhs);
+}
+
+static void rigid_add_edge_to_rhs(LaplacianSystem *sys, EditVert *v1, EditVert *v2, float w)
+{
+ rigid_add_half_edge_to_rhs(sys, v1, v2, w);
+ rigid_add_half_edge_to_rhs(sys, v2, v1, w);
+}
+
+void rigid_deform_iteration()
+{
+ LaplacianSystem *sys= RigidDeformSystem;
+ EditMesh *em;
+ EditVert *eve;
+ EditFace *efa;
+ int a, i;
+
+ if(!sys)
+ return;
+
+ nlMakeCurrent(sys->context);
+ em= sys->rigid.mesh;
+
+ /* compute R */
+ memset(sys->rigid.R, 0, sizeof(float)*3*3*sys->totvert);
+ memset(sys->rigid.rhs, 0, sizeof(float)*3*sys->totvert);
+
+ for(a=0, efa=em->faces.first; efa; efa=efa->next, a++) {
+ rigid_add_edge_to_R(sys, efa->v1, efa->v2, sys->fweights[a][2]);
+ rigid_add_edge_to_R(sys, efa->v2, efa->v3, sys->fweights[a][0]);
+ rigid_add_edge_to_R(sys, efa->v3, efa->v1, sys->fweights[a][1]);
+
+ if(efa->v4) {
+ a++;
+ rigid_add_edge_to_R(sys, efa->v1, efa->v3, sys->fweights[a][2]);
+ rigid_add_edge_to_R(sys, efa->v3, efa->v4, sys->fweights[a][0]);
+ rigid_add_edge_to_R(sys, efa->v4, efa->v1, sys->fweights[a][1]);
+ }
+ }
+
+ for(a=0, eve=em->verts.first; eve; eve=eve->next, a++) {
+ rigid_orthogonalize_R(sys->rigid.R[a]);
+ eve->tmp.l= a;
+ }
+
+ /* compute right hand sides for solving */
+ for(a=0, efa=em->faces.first; efa; efa=efa->next, a++) {
+ rigid_add_edge_to_rhs(sys, efa->v1, efa->v2, sys->fweights[a][2]);
+ rigid_add_edge_to_rhs(sys, efa->v2, efa->v3, sys->fweights[a][0]);
+ rigid_add_edge_to_rhs(sys, efa->v3, efa->v1, sys->fweights[a][1]);
+
+ if(efa->v4) {
+ a++;
+ rigid_add_edge_to_rhs(sys, efa->v1, efa->v3, sys->fweights[a][2]);
+ rigid_add_edge_to_rhs(sys, efa->v3, efa->v4, sys->fweights[a][0]);
+ rigid_add_edge_to_rhs(sys, efa->v4, efa->v1, sys->fweights[a][1]);
+ }
+ }
+
+ /* solve for positions, for X,Y and Z separately */
+ for(i=0; i<3; i++) {
+ laplacian_begin_solve(sys, i);
+
+ for(a=0; a<sys->totvert; a++)
+ if(!sys->vpinned[a]) {
+ /*if (i==0)
+ printf("rhs %f\n", sys->rigid.rhs[a][0]);*/
+ laplacian_add_right_hand_side(sys, a, sys->rigid.rhs[a][i]);
+ }
+
+ if(laplacian_system_solve(sys)) {
+ for(a=0, eve=em->verts.first; eve; eve=eve->next, a++)
+ eve->co[i]= laplacian_system_get_solution(a);
+ }
+ else {
+ if(!sys->rigid.thrownerror) {
+ error("RigidDeform: failed to find solution.");
+ sys->rigid.thrownerror= 1;
+ }
+ break;
+ }
+ }
+
+ /*printf("\n--------------------------------------------\n\n");*/
+}
+
+static void rigid_laplacian_create(LaplacianSystem *sys)
+{
+ EditMesh *em = sys->rigid.mesh;
+ EditVert *eve;
+ EditFace *efa;
+ int a;
+
+ /* add verts and faces to laplacian */
+ for(a=0, eve=em->verts.first; eve; eve=eve->next, a++) {
+ laplacian_add_vertex(sys, eve->co, eve->pinned);
+ eve->tmp.l= a;
+ }
+
+ for(efa=em->faces.first; efa; efa=efa->next) {
+ laplacian_add_triangle(sys,
+ efa->v1->tmp.l, efa->v2->tmp.l, efa->v3->tmp.l);
+ if(efa->v4)
+ laplacian_add_triangle(sys,
+ efa->v1->tmp.l, efa->v3->tmp.l, efa->v4->tmp.l);
+ }
+}
+
+void rigid_deform_begin(EditMesh *em)
+{
+ LaplacianSystem *sys;
+ EditVert *eve;
+ EditFace *efa;
+ int a, totvert, totface;
+
+ /* count vertices, triangles */
+ for(totvert=0, eve=em->verts.first; eve; eve=eve->next)
+ totvert++;
+
+ for(totface=0, efa=em->faces.first; efa; efa=efa->next) {
+ totface++;
+ if(efa->v4) totface++;
+ }
+
+ /* create laplacian */
+ sys = laplacian_system_construct_begin(totvert, totface);
+
+ sys->rigid.mesh= em;
+ sys->rigid.R = MEM_callocN(sizeof(float)*3*3*totvert, "RigidDeformR");
+ sys->rigid.rhs = MEM_callocN(sizeof(float)*3*totvert, "RigidDeformRHS");
+ sys->rigid.origco = MEM_callocN(sizeof(float)*3*totvert, "RigidDeformCo");
+
+ for(a=0, eve=em->verts.first; eve; eve=eve->next, a++)
+ VecCopyf(sys->rigid.origco[a], eve->co);
+
+ sys->areaweights= 0;
+ sys->storeweights= 1;
+
+ rigid_laplacian_create(sys);
+
+ laplacian_system_construct_end(sys);
+
+ RigidDeformSystem = sys;
+}
+
+void rigid_deform_end(int cancel)
+{
+ LaplacianSystem *sys = RigidDeformSystem;
+
+ if(sys) {
+ EditMesh *em = sys->rigid.mesh;
+ EditVert *eve;
+ int a;
+
+ if(cancel)
+ for(a=0, eve=em->verts.first; eve; eve=eve->next, a++)
+ if(!eve->pinned)
+ VecCopyf(eve->co, sys->rigid.origco[a]);
+
+ if(sys->rigid.R) MEM_freeN(sys->rigid.R);
+ if(sys->rigid.rhs) MEM_freeN(sys->rigid.rhs);
+ if(sys->rigid.origco) MEM_freeN(sys->rigid.origco);
+
+ /* free */
+ laplacian_system_delete(sys);
+ }
+
+ RigidDeformSystem = NULL;
+}
+#endif
+
+/************************** Harmonic Coordinates ****************************/
+/* From "Harmonic Coordinates for Character Articulation",
+ Pushkar Joshi, Mark Meyer, Tony DeRose, Brian Green and Tom Sanocki,
+ SIGGRAPH 2007. */
+
+#define EPSILON 0.0001f
+
+#define MESHDEFORM_TAG_UNTYPED 0
+#define MESHDEFORM_TAG_BOUNDARY 1
+#define MESHDEFORM_TAG_INTERIOR 2
+#define MESHDEFORM_TAG_EXTERIOR 3
+
+#define MESHDEFORM_LEN_THRESHOLD 1e-6
+
+static int MESHDEFORM_OFFSET[7][3] =
+ {{0,0,0}, {1,0,0}, {-1,0,0}, {0,1,0}, {0,-1,0}, {0,0,1}, {0,0,-1}};
+
+typedef struct MDefBoundIsect {
+ float co[3], uvw[4];
+ int nvert, v[4], facing;
+ float len;
+} MDefBoundIsect;
+
+typedef struct MeshDeformBind {
+ /* grid dimensions */
+ float min[3], max[3];
+ float width[3], halfwidth[3];
+ int size, size3;
+
+ /* meshes */
+ DerivedMesh *cagedm;
+ float (*cagecos)[3];
+ float (*vertexcos)[3];
+ int totvert, totcagevert;
+
+ /* grids */
+ MemArena *memarena;
+ MDefBoundIsect *(*boundisect)[6];
+ int *semibound;
+ int *tag;
+ float *phi, *totalphi;
+
+ /* mesh stuff */
+ int *inside;
+ float *weights;
+ float cagemat[4][4];
+
+ /* direct solver */
+ int *varidx;
+
+ /* raytrace */
+ RayTree *raytree;
+} MeshDeformBind;
+
+/* ray intersection */
+
+/* our own triangle intersection, so we can fully control the epsilons and
+ * prevent corner case from going wrong*/
+static int meshdeform_tri_intersect(float orig[3], float end[3], float vert0[3],
+ float vert1[3], float vert2[3], float *isectco, float *uvw)
+{
+ float edge1[3], edge2[3], tvec[3], pvec[3], qvec[3];
+ float det,inv_det, u, v, dir[3], isectdir[3];
+
+ VECSUB(dir, end, orig);
+
+ /* find vectors for two edges sharing vert0 */
+ VECSUB(edge1, vert1, vert0);
+ VECSUB(edge2, vert2, vert0);
+
+ /* begin calculating determinant - also used to calculate U parameter */
+ Crossf(pvec, dir, edge2);
+
+ /* if determinant is near zero, ray lies in plane of triangle */
+ det = INPR(edge1, pvec);
+
+ if (det == 0.0f)
+ return 0;
+ inv_det = 1.0f / det;
+
+ /* calculate distance from vert0 to ray origin */
+ VECSUB(tvec, orig, vert0);
+
+ /* calculate U parameter and test bounds */
+ u = INPR(tvec, pvec) * inv_det;
+ if (u < -EPSILON || u > 1.0f+EPSILON)
+ return 0;
+
+ /* prepare to test V parameter */
+ Crossf(qvec, tvec, edge1);
+
+ /* calculate V parameter and test bounds */
+ v = INPR(dir, qvec) * inv_det;
+ if (v < -EPSILON || u + v > 1.0f+EPSILON)
+ return 0;
+
+ isectco[0]= (1.0f - u - v)*vert0[0] + u*vert1[0] + v*vert2[0];
+ isectco[1]= (1.0f - u - v)*vert0[1] + u*vert1[1] + v*vert2[1];
+ isectco[2]= (1.0f - u - v)*vert0[2] + u*vert1[2] + v*vert2[2];
+
+ uvw[0]= 1.0 - u - v;
+ uvw[1]= u;
+ uvw[2]= v;
+
+ /* check if it is within the length of the line segment */
+ VECSUB(isectdir, isectco, orig);
+
+ if(INPR(dir, isectdir) < -EPSILON)
+ return 0;
+
+ if(INPR(dir, dir) + EPSILON < INPR(isectdir, isectdir))
+ return 0;
+
+ return 1;
+}
+
+/* blender's raytracer is not use now, even though it is much faster. it can
+ * give problems with rays falling through, so we use our own intersection
+ * function above with tweaked epsilons */
+
+#if 0
+static MeshDeformBind *MESHDEFORM_BIND = NULL;
+
+static void meshdeform_ray_coords_func(RayFace *face, float **v1, float **v2, float **v3, float **v4)
+{
+ MFace *mface= (MFace*)face;
+ float (*cagecos)[3]= MESHDEFORM_BIND->cagecos;
+
+ *v1= cagecos[mface->v1];
+ *v2= cagecos[mface->v2];
+ *v3= cagecos[mface->v3];
+ *v4= (mface->v4)? cagecos[mface->v4]: NULL;
+}
+
+static int meshdeform_ray_check_func(Isect *is, RayFace *face)
+{
+ return 1;
+}
+
+static void meshdeform_ray_tree_create(MeshDeformBind *mdb)
+{
+ MFace *mface;
+ float min[3], max[3];
+ int a, totface;
+
+ /* create a raytrace tree from the mesh */
+ INIT_MINMAX(min, max);
+
+ for(a=0; a<mdb->totcagevert; a++)
+ DO_MINMAX(mdb->cagecos[a], min, max)
+
+ MESHDEFORM_BIND= mdb;
+
+ mface= mdb->cagedm->getFaceArray(mdb->cagedm);
+ totface= mdb->cagedm->getNumFaces(mdb->cagedm);
+
+ mdb->raytree= RE_ray_tree_create(64, totface, min, max,
+ meshdeform_ray_coords_func, meshdeform_ray_check_func);
+
+ for(a=0; a<totface; a++, mface++)
+ RE_ray_tree_add_face(mdb->raytree, mface);
+
+ RE_ray_tree_done(mdb->raytree);
+}
+
+static void meshdeform_ray_tree_free(MeshDeformBind *mdb)
+{
+ MESHDEFORM_BIND= NULL;
+ RE_ray_tree_free(mdb->raytree);
+}
+#endif
+
+static int meshdeform_intersect(MeshDeformBind *mdb, Isect *isec)
+{
+ MFace *mface;
+ float face[4][3], co[3], uvw[3], len, nor[3];
+ int f, hit, is= 0, totface;
+
+ isec->labda= 1e10;
+
+ mface= mdb->cagedm->getFaceArray(mdb->cagedm);
+ totface= mdb->cagedm->getNumFaces(mdb->cagedm);
+
+ for(f=0; f<totface; f++, mface++) {
+ VECCOPY(face[0], mdb->cagecos[mface->v1]);
+ VECCOPY(face[1], mdb->cagecos[mface->v2]);
+ VECCOPY(face[2], mdb->cagecos[mface->v3]);
+
+ if(mface->v4) {
+ VECCOPY(face[3], mdb->cagecos[mface->v4]);
+ hit= meshdeform_tri_intersect(isec->start, isec->end, face[0], face[1], face[2], co, uvw);
+
+ if(hit) {
+ CalcNormFloat(face[0], face[1], face[2], nor);
+ }
+ else {
+ hit= meshdeform_tri_intersect(isec->start, isec->end, face[0], face[2], face[3], co, uvw);
+ CalcNormFloat(face[0], face[2], face[3], nor);
+ }
+ }
+ else {
+ hit= meshdeform_tri_intersect(isec->start, isec->end, face[0], face[1], face[2], co, uvw);
+ CalcNormFloat(face[0], face[1], face[2], nor);
+ }
+
+ if(hit) {
+ len= VecLenf(isec->start, co)/VecLenf(isec->start, isec->end);
+ if(len < isec->labda) {
+ isec->labda= len;
+ isec->face= mface;
+ isec->isect= (INPR(isec->vec, nor) <= 0.0f);
+ is= 1;
+ }
+ }
+ }
+
+ return is;
+}
+
+static MDefBoundIsect *meshdeform_ray_tree_intersect(MeshDeformBind *mdb, float *co1, float *co2)
+{
+ MDefBoundIsect *isect;
+ Isect isec;
+ float (*cagecos)[3];
+ MFace *mface;
+ float vert[4][3], len;
+ static float epsilon[3]= {0, 0, 0}; //1e-4, 1e-4, 1e-4};
+
+ /* setup isec */
+ memset(&isec, 0, sizeof(isec));
+ isec.mode= RE_RAY_MIRROR; /* we want the closest intersection */
+ isec.lay= -1;
+ isec.face_last= NULL;
+ isec.faceorig= NULL;
+ isec.labda= 1e10f;
+
+ VECADD(isec.start, co1, epsilon);
+ VECADD(isec.end, co2, epsilon);
+ VECSUB(isec.vec, isec.end, isec.start);
+
+#if 0
+ /*if(RE_ray_tree_intersect(mdb->raytree, &isec)) {*/
+#endif
+
+ if(meshdeform_intersect(mdb, &isec)) {
+ len= isec.labda;
+ mface= isec.face;
+
+ /* create MDefBoundIsect */
+ isect= BLI_memarena_alloc(mdb->memarena, sizeof(*isect));
+
+ /* compute intersection coordinate */
+ isect->co[0]= co1[0] + isec.vec[0]*len;
+ isect->co[1]= co1[1] + isec.vec[1]*len;
+ isect->co[2]= co1[2] + isec.vec[2]*len;
+
+ isect->len= VecLenf(co1, isect->co);
+ if(isect->len < MESHDEFORM_LEN_THRESHOLD)
+ isect->len= MESHDEFORM_LEN_THRESHOLD;
+
+ isect->v[0]= mface->v1;
+ isect->v[1]= mface->v2;
+ isect->v[2]= mface->v3;
+ isect->v[3]= mface->v4;
+ isect->nvert= (mface->v4)? 4: 3;
+
+ isect->facing= isec.isect;
+
+ /* compute mean value coordinates for interpolation */
+ cagecos= mdb->cagecos;
+ VECCOPY(vert[0], cagecos[mface->v1]);
+ VECCOPY(vert[1], cagecos[mface->v2]);
+ VECCOPY(vert[2], cagecos[mface->v3]);
+ if(mface->v4) VECCOPY(vert[3], cagecos[mface->v4]);
+ MeanValueWeights(vert, isect->nvert, isect->co, isect->uvw);
+
+ return isect;
+ }
+
+ return NULL;
+}
+
+static int meshdeform_inside_cage(MeshDeformBind *mdb, float *co)
+{
+ MDefBoundIsect *isect;
+ float outside[3], start[3], dir[3];
+ int i, counter;
+
+ for(i=1; i<=6; i++) {
+ counter = 0;
+
+ outside[0] = co[0] + (mdb->max[0] - mdb->min[0] + 1.0f)*MESHDEFORM_OFFSET[i][0];
+ outside[1] = co[1] + (mdb->max[1] - mdb->min[1] + 1.0f)*MESHDEFORM_OFFSET[i][1];
+ outside[2] = co[2] + (mdb->max[2] - mdb->min[2] + 1.0f)*MESHDEFORM_OFFSET[i][2];
+
+ VECSUB(dir, outside, start);
+ Normalize(dir);
+ VECCOPY(start, co);
+
+ isect = meshdeform_ray_tree_intersect(mdb, start, outside);
+ if(isect && !isect->facing)
+ return 1;
+ }
+
+ return 0;
+}
+
+/* solving */
+
+static int meshdeform_index(MeshDeformBind *mdb, int x, int y, int z, int n)
+{
+ int size= mdb->size;
+
+ x += MESHDEFORM_OFFSET[n][0];
+ y += MESHDEFORM_OFFSET[n][1];
+ z += MESHDEFORM_OFFSET[n][2];
+
+ if(x < 0 || x >= mdb->size)
+ return -1;
+ if(y < 0 || y >= mdb->size)
+ return -1;
+ if(z < 0 || z >= mdb->size)
+ return -1;
+
+ return x + y*size + z*size*size;
+}
+
+static void meshdeform_cell_center(MeshDeformBind *mdb, int x, int y, int z, int n, float *center)
+{
+ x += MESHDEFORM_OFFSET[n][0];
+ y += MESHDEFORM_OFFSET[n][1];
+ z += MESHDEFORM_OFFSET[n][2];
+
+ center[0]= mdb->min[0] + x*mdb->width[0] + mdb->halfwidth[0];
+ center[1]= mdb->min[1] + y*mdb->width[1] + mdb->halfwidth[1];
+ center[2]= mdb->min[2] + z*mdb->width[2] + mdb->halfwidth[2];
+}
+
+static void meshdeform_add_intersections(MeshDeformBind *mdb, int x, int y, int z)
+{
+ MDefBoundIsect *isect;
+ float center[3], ncenter[3];
+ int i, a;
+
+ a= meshdeform_index(mdb, x, y, z, 0);
+ meshdeform_cell_center(mdb, x, y, z, 0, center);
+
+ /* check each outgoing edge for intersection */
+ for(i=1; i<=6; i++) {
+ if(meshdeform_index(mdb, x, y, z, i) == -1)
+ continue;
+
+ meshdeform_cell_center(mdb, x, y, z, i, ncenter);
+
+ isect= meshdeform_ray_tree_intersect(mdb, center, ncenter);
+ if(isect) {
+ mdb->boundisect[a][i-1]= isect;
+ mdb->tag[a]= MESHDEFORM_TAG_BOUNDARY;
+ }
+ }
+}
+
+static void meshdeform_bind_floodfill(MeshDeformBind *mdb)
+{
+ int *stack, *tag= mdb->tag;
+ int a, b, i, xyz[3], stacksize, size= mdb->size;
+
+ stack= MEM_callocN(sizeof(int)*mdb->size3, "MeshDeformBindStack");
+
+ /* we know lower left corner is EXTERIOR because of padding */
+ tag[0]= MESHDEFORM_TAG_EXTERIOR;
+ stack[0]= 0;
+ stacksize= 1;
+
+ /* floodfill exterior tag */
+ while(stacksize > 0) {
+ a= stack[--stacksize];
+
+ xyz[2]= a/(size*size);
+ xyz[1]= (a - xyz[2]*size*size)/size;
+ xyz[0]= a - xyz[1]*size - xyz[2]*size*size;
+
+ for(i=1; i<=6; i++) {
+ b= meshdeform_index(mdb, xyz[0], xyz[1], xyz[2], i);
+
+ if(b != -1) {
+ if(tag[b] == MESHDEFORM_TAG_UNTYPED ||
+ (tag[b] == MESHDEFORM_TAG_BOUNDARY && !mdb->boundisect[a][i-1])) {
+ tag[b]= MESHDEFORM_TAG_EXTERIOR;
+ stack[stacksize++]= b;
+ }
+ }
+ }
+ }
+
+ /* other cells are interior */
+ for(a=0; a<size*size*size; a++)
+ if(tag[a]==MESHDEFORM_TAG_UNTYPED)
+ tag[a]= MESHDEFORM_TAG_INTERIOR;
+
+#if 0
+ {
+ int tb, ti, te, ts;
+ tb= ti= te= ts= 0;
+ for(a=0; a<size*size*size; a++)
+ if(tag[a]==MESHDEFORM_TAG_BOUNDARY)
+ tb++;
+ else if(tag[a]==MESHDEFORM_TAG_INTERIOR)
+ ti++;
+ else if(tag[a]==MESHDEFORM_TAG_EXTERIOR) {
+ te++;
+
+ if(mdb->semibound[a])
+ ts++;
+ }
+
+ printf("interior %d exterior %d boundary %d semi-boundary %d\n", ti, te, tb, ts);
+ }
+#endif
+
+ MEM_freeN(stack);
+}
+
+static float meshdeform_boundary_phi(MeshDeformBind *mdb, MDefBoundIsect *isect, int cagevert)
+{
+ int a;
+
+ for(a=0; a<isect->nvert; a++)
+ if(isect->v[a] == cagevert)
+ return isect->uvw[a];
+
+ return 0.0f;
+}
+
+static float meshdeform_interp_w(MeshDeformBind *mdb, float *gridvec, float *vec, int cagevert)
+{
+ float dvec[3], ivec[3], wx, wy, wz, result=0.0f;
+ float weight, totweight= 0.0f;
+ int i, a, x, y, z;
+
+ for(i=0; i<3; i++) {
+ ivec[i]= (int)gridvec[i];
+ dvec[i]= gridvec[i] - ivec[i];
+ }
+
+ for(i=0; i<8; i++) {
+ if(i & 1) { x= ivec[0]+1; wx= dvec[0]; }
+ else { x= ivec[0]; wx= 1.0f-dvec[0]; }
+
+ if(i & 2) { y= ivec[1]+1; wy= dvec[1]; }
+ else { y= ivec[1]; wy= 1.0f-dvec[1]; }
+
+ if(i & 4) { z= ivec[2]+1; wz= dvec[2]; }
+ else { z= ivec[2]; wz= 1.0f-dvec[2]; }
+
+ CLAMP(x, 0, mdb->size-1);
+ CLAMP(y, 0, mdb->size-1);
+ CLAMP(z, 0, mdb->size-1);
+
+ a= meshdeform_index(mdb, x, y, z, 0);
+ weight= wx*wy*wz;
+ result += weight*mdb->phi[a];
+ totweight += weight;
+ }
+
+ if(totweight > 0.0f)
+ result /= totweight;
+
+ return result;
+}
+
+static void meshdeform_check_semibound(MeshDeformBind *mdb, int x, int y, int z)
+{
+ int i, a;
+
+ a= meshdeform_index(mdb, x, y, z, 0);
+ if(mdb->tag[a] != MESHDEFORM_TAG_EXTERIOR)
+ return;
+
+ for(i=1; i<=6; i++)
+ if(mdb->boundisect[a][i-1])
+ mdb->semibound[a]= 1;
+}
+
+static float meshdeform_boundary_total_weight(MeshDeformBind *mdb, int x, int y, int z)
+{
+ float weight, totweight= 0.0f;
+ int i, a;
+
+ a= meshdeform_index(mdb, x, y, z, 0);
+
+ /* count weight for neighbour cells */
+ for(i=1; i<=6; i++) {
+ if(meshdeform_index(mdb, x, y, z, i) == -1)
+ continue;
+
+ if(mdb->boundisect[a][i-1])
+ weight= 1.0f/mdb->boundisect[a][i-1]->len;
+ else if(!mdb->semibound[a])
+ weight= 1.0f/mdb->width[0];
+ else
+ weight= 0.0f;
+
+ totweight += weight;
+ }
+
+ return totweight;
+}
+
+static void meshdeform_matrix_add_cell(MeshDeformBind *mdb, int x, int y, int z)
+{
+ MDefBoundIsect *isect;
+ float weight, totweight;
+ int i, a, acenter;
+
+ acenter= meshdeform_index(mdb, x, y, z, 0);
+ if(mdb->tag[acenter] == MESHDEFORM_TAG_EXTERIOR)
+ return;
+
+ nlMatrixAdd(mdb->varidx[acenter], mdb->varidx[acenter], 1.0f);
+
+ totweight= meshdeform_boundary_total_weight(mdb, x, y, z);
+ for(i=1; i<=6; i++) {
+ a= meshdeform_index(mdb, x, y, z, i);
+ if(a == -1 || mdb->tag[a] == MESHDEFORM_TAG_EXTERIOR)
+ continue;
+
+ isect= mdb->boundisect[acenter][i-1];
+ if (!isect) {
+ weight= (1.0f/mdb->width[0])/totweight;
+ nlMatrixAdd(mdb->varidx[acenter], mdb->varidx[a], -weight);
+ }
+ }
+}
+
+static void meshdeform_matrix_add_rhs(MeshDeformBind *mdb, int x, int y, int z, int cagevert)
+{
+ MDefBoundIsect *isect;
+ float rhs, weight, totweight;
+ int i, a, acenter;
+
+ acenter= meshdeform_index(mdb, x, y, z, 0);
+ if(mdb->tag[acenter] == MESHDEFORM_TAG_EXTERIOR)
+ return;
+
+ totweight= meshdeform_boundary_total_weight(mdb, x, y, z);
+ for(i=1; i<=6; i++) {
+ a= meshdeform_index(mdb, x, y, z, i);
+ if(a == -1)
+ continue;
+
+ isect= mdb->boundisect[acenter][i-1];
+
+ if (isect) {
+ weight= (1.0f/isect->len)/totweight;
+ rhs= weight*meshdeform_boundary_phi(mdb, isect, cagevert);
+ nlRightHandSideAdd(0, mdb->varidx[acenter], rhs);
+ }
+ }
+}
+
+static void meshdeform_matrix_add_semibound_phi(MeshDeformBind *mdb, int x, int y, int z, int cagevert)
+{
+ MDefBoundIsect *isect;
+ float rhs, weight, totweight;
+ int i, a;
+
+ a= meshdeform_index(mdb, x, y, z, 0);
+ if(!mdb->semibound[a])
+ return;
+
+ mdb->phi[a]= 0.0f;
+
+ totweight= meshdeform_boundary_total_weight(mdb, x, y, z);
+ for(i=1; i<=6; i++) {
+ isect= mdb->boundisect[a][i-1];
+
+ if (isect) {
+ weight= (1.0f/isect->len)/totweight;
+ rhs= weight*meshdeform_boundary_phi(mdb, isect, cagevert);
+ mdb->phi[a] += rhs;
+ }
+ }
+}
+
+static void meshdeform_matrix_add_exterior_phi(MeshDeformBind *mdb, int x, int y, int z, int cagevert)
+{
+ float phi, totweight;
+ int i, a, acenter;
+
+ acenter= meshdeform_index(mdb, x, y, z, 0);
+ if(mdb->tag[acenter] != MESHDEFORM_TAG_EXTERIOR || mdb->semibound[acenter])
+ return;
+
+ phi= 0.0f;
+ totweight= 0.0f;
+ for(i=1; i<=6; i++) {
+ a= meshdeform_index(mdb, x, y, z, i);
+
+ if(a != -1 && mdb->semibound[a]) {
+ phi += mdb->phi[a];
+ totweight += 1.0f;
+ }
+ }
+
+ if(totweight != 0.0f)
+ mdb->phi[acenter]= phi/totweight;
+}
+
+static void meshdeform_matrix_solve(MeshDeformBind *mdb)
+{
+ NLContext *context;
+ float vec[3], gridvec[3];
+ int a, b, x, y, z, totvar;
+ char message[1024];
+
+ /* setup variable indices */
+ mdb->varidx= MEM_callocN(sizeof(int)*mdb->size3, "MeshDeformDSvaridx");
+ for(a=0, totvar=0; a<mdb->size3; a++)
+ mdb->varidx[a]= (mdb->tag[a] == MESHDEFORM_TAG_EXTERIOR)? -1: totvar++;
+
+ if(totvar == 0) {
+ MEM_freeN(mdb->varidx);
+ return;
+ }
+
+ progress_bar(0, "Starting mesh deform solve");
+
+ /* setup opennl solver */
+ nlNewContext();
+ context= nlGetCurrent();
+
+ nlSolverParameteri(NL_NB_VARIABLES, totvar);
+ nlSolverParameteri(NL_NB_ROWS, totvar);
+ nlSolverParameteri(NL_NB_RIGHT_HAND_SIDES, 1);
+
+ nlBegin(NL_SYSTEM);
+ nlBegin(NL_MATRIX);
+
+ /* build matrix */
+ for(z=0; z<mdb->size; z++)
+ for(y=0; y<mdb->size; y++)
+ for(x=0; x<mdb->size; x++)
+ meshdeform_matrix_add_cell(mdb, x, y, z);
+
+ /* solve for each cage vert */
+ for(a=0; a<mdb->totcagevert; a++) {
+ if(a != 0) {
+ nlBegin(NL_SYSTEM);
+ nlBegin(NL_MATRIX);
+ }
+
+ /* fill in right hand side and solve */
+ for(z=0; z<mdb->size; z++)
+ for(y=0; y<mdb->size; y++)
+ for(x=0; x<mdb->size; x++)
+ meshdeform_matrix_add_rhs(mdb, x, y, z, a);
+
+ nlEnd(NL_MATRIX);
+ nlEnd(NL_SYSTEM);
+
+#if 0
+ nlPrintMatrix();
+#endif
+
+ if(nlSolveAdvanced(NULL, NL_TRUE)) {
+ for(z=0; z<mdb->size; z++)
+ for(y=0; y<mdb->size; y++)
+ for(x=0; x<mdb->size; x++)
+ meshdeform_matrix_add_semibound_phi(mdb, x, y, z, a);
+
+ for(z=0; z<mdb->size; z++)
+ for(y=0; y<mdb->size; y++)
+ for(x=0; x<mdb->size; x++)
+ meshdeform_matrix_add_exterior_phi(mdb, x, y, z, a);
+
+ for(b=0; b<mdb->size3; b++) {
+ if(mdb->tag[b] != MESHDEFORM_TAG_EXTERIOR)
+ mdb->phi[b]= nlGetVariable(0, mdb->varidx[b]);
+ mdb->totalphi[b] += mdb->phi[b];
+ }
+
+ /* compute weights for each vertex */
+ for(b=0; b<mdb->totvert; b++) {
+ if(mdb->inside[b]) {
+ VECCOPY(vec, mdb->vertexcos[b]);
+ Mat4MulVecfl(mdb->cagemat, vec);
+ gridvec[0]= (vec[0] - mdb->min[0] - mdb->halfwidth[0])/mdb->width[0];
+ gridvec[1]= (vec[1] - mdb->min[1] - mdb->halfwidth[1])/mdb->width[1];
+ gridvec[2]= (vec[2] - mdb->min[2] - mdb->halfwidth[2])/mdb->width[2];
+
+ mdb->weights[b*mdb->totcagevert + a]= meshdeform_interp_w(mdb, gridvec, vec, a);
+ }
+ }
+ }
+ else {
+ error("Mesh Deform: failed to find solution.");
+ break;
+ }
+
+ sprintf(message, "Mesh deform solve %d / %d |||", a+1, mdb->totcagevert);
+ progress_bar((float)(a+1)/(float)(mdb->totcagevert), message);
+ }
+
+#if 0
+ /* sanity check */
+ for(b=0; b<mdb->size3; b++)
+ if(mdb->tag[b] != MESHDEFORM_TAG_EXTERIOR)
+ if(fabs(mdb->totalphi[b] - 1.0f) > 1e-4)
+ printf("totalphi deficiency [%s|%d] %d: %.10f\n",
+ (mdb->tag[b] == MESHDEFORM_TAG_INTERIOR)? "interior": "boundary", mdb->semibound[b], mdb->varidx[b], mdb->totalphi[b]);
+#endif
+
+ /* free */
+ MEM_freeN(mdb->varidx);
+
+ nlDeleteContext(context);
+}
+
+void harmonic_coordinates_bind(MeshDeformModifierData *mmd, float (*vertexcos)[3], int totvert, float cagemat[][4])
+{
+ MeshDeformBind mdb;
+ MVert *mvert;
+ float center[3], vec[3], maxwidth;
+ int a, x, y, z, totinside;
+
+ waitcursor(1);
+ start_progress_bar();
+
+ /* free exisiting weights */
+ if(mmd->bindweights) {
+ MEM_freeN(mmd->bindweights);
+ MEM_freeN(mmd->bindcos);
+ mmd->bindweights= NULL;
+ mmd->bindcos= NULL;
+ }
+
+ memset(&mdb, 0, sizeof(MeshDeformBind));
+
+ /* get mesh and cage mesh */
+ mdb.vertexcos= vertexcos;
+ mdb.totvert= totvert;
+
+ mdb.cagedm= mesh_create_derived_no_deform(mmd->object, NULL, CD_MASK_BAREMESH);
+ mdb.totcagevert= mdb.cagedm->getNumVerts(mdb.cagedm);
+ mdb.cagecos= MEM_callocN(sizeof(*mdb.cagecos)*mdb.totcagevert, "MeshDeformBindCos");
+ Mat4CpyMat4(mdb.cagemat, cagemat);
+
+ mvert= mdb.cagedm->getVertArray(mdb.cagedm);
+ for(a=0; a<mdb.totcagevert; a++)
+ VECCOPY(mdb.cagecos[a], mvert[a].co)
+
+ /* compute bounding box of the cage mesh */
+ INIT_MINMAX(mdb.min, mdb.max);
+
+ for(a=0; a<mdb.totcagevert; a++)
+ DO_MINMAX(mdb.cagecos[a], mdb.min, mdb.max);
+
+ /* allocate memory */
+ mdb.size= (2<<(mmd->gridsize-1)) + 2;
+ mdb.size3= mdb.size*mdb.size*mdb.size;
+ mdb.tag= MEM_callocN(sizeof(int)*mdb.size3, "MeshDeformBindTag");
+ mdb.phi= MEM_callocN(sizeof(float)*mdb.size3, "MeshDeformBindPhi");
+ mdb.totalphi= MEM_callocN(sizeof(float)*mdb.size3, "MeshDeformBindTotalPhi");
+ mdb.boundisect= MEM_callocN(sizeof(*mdb.boundisect)*mdb.size3, "MDefBoundIsect");
+ mdb.semibound= MEM_callocN(sizeof(int)*mdb.size3, "MDefSemiBound");
+
+ mdb.weights= MEM_callocN(sizeof(float)*mdb.totvert*mdb.totcagevert, "MDefWeights");
+ mdb.inside= MEM_callocN(sizeof(int)*mdb.totvert, "MDefInside");
+
+ mdb.memarena= BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE);
+ BLI_memarena_use_calloc(mdb.memarena);
+
+ /* make bounding box equal size in all directions, add padding, and compute
+ * width of the cells */
+ maxwidth = -1.0f;
+ for(a=0; a<3; a++)
+ if(mdb.max[a]-mdb.min[a] > maxwidth)
+ maxwidth= mdb.max[a]-mdb.min[a];
+
+ for(a=0; a<3; a++) {
+ center[a]= (mdb.min[a]+mdb.max[a])*0.5f;
+ mdb.min[a]= center[a] - maxwidth*0.5f;
+ mdb.max[a]= center[a] + maxwidth*0.5f;
+
+ mdb.width[a]= (mdb.max[a]-mdb.min[a])/(mdb.size-4);
+ mdb.min[a] -= 2.1f*mdb.width[a];
+ mdb.max[a] += 2.1f*mdb.width[a];
+
+ mdb.width[a]= (mdb.max[a]-mdb.min[a])/mdb.size;
+ mdb.halfwidth[a]= mdb.width[a]*0.5f;
+ }
+
+ progress_bar(0, "Setting up mesh deform system");
+
+#if 0
+ /* create ray tree */
+ meshdeform_ray_tree_create(&mdb);
+#endif
+
+ totinside= 0;
+ for(a=0; a<mdb.totvert; a++) {
+ VECCOPY(vec, mdb.vertexcos[a]);
+ Mat4MulVecfl(mdb.cagemat, vec);
+ mdb.inside[a]= meshdeform_inside_cage(&mdb, vec);
+ if(mdb.inside[a])
+ totinside++;
+ }
+
+ /* free temporary MDefBoundIsects */
+ BLI_memarena_free(mdb.memarena);
+ mdb.memarena= BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE);
+
+ /* start with all cells untyped */
+ for(a=0; a<mdb.size3; a++)
+ mdb.tag[a]= MESHDEFORM_TAG_UNTYPED;
+
+ /* detect intersections and tag boundary cells */
+ for(z=0; z<mdb.size; z++)
+ for(y=0; y<mdb.size; y++)
+ for(x=0; x<mdb.size; x++)
+ meshdeform_add_intersections(&mdb, x, y, z);
+
+#if 0
+ /* free ray tree */
+ meshdeform_ray_tree_free(&mdb);
+#endif
+
+ /* compute exterior and interior tags */
+ meshdeform_bind_floodfill(&mdb);
+
+ for(z=0; z<mdb.size; z++)
+ for(y=0; y<mdb.size; y++)
+ for(x=0; x<mdb.size; x++)
+ meshdeform_check_semibound(&mdb, x, y, z);
+
+ /* solve */
+ meshdeform_matrix_solve(&mdb);
+
+ /* assign results */
+ mmd->bindweights= mdb.weights;
+ mmd->bindcos= (float*)mdb.cagecos;
+ mmd->totvert= mdb.totvert;
+ mmd->totcagevert= mdb.totcagevert;
+
+ /* transform bindcos to world space */
+ for(a=0; a<mdb.totcagevert; a++)
+ Mat4MulVecfl(mmd->object->obmat, mmd->bindcos+a*3);
+
+ /* free */
+ mdb.cagedm->release(mdb.cagedm);
+ MEM_freeN(mdb.tag);
+ MEM_freeN(mdb.phi);
+ MEM_freeN(mdb.totalphi);
+ MEM_freeN(mdb.boundisect);
+ MEM_freeN(mdb.semibound);
+ MEM_freeN(mdb.inside);
+ BLI_memarena_free(mdb.memarena);
+
+ end_progress_bar();
+ waitcursor(0);
+}
+
diff --git a/source/blender/src/meshtools.c b/source/blender/src/meshtools.c
new file mode 100644
index 00000000000..41a9bece61a
--- /dev/null
+++ b/source/blender/src/meshtools.c
@@ -0,0 +1,980 @@
+/**
+ * $Id:
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/*
+
+meshtools.c: no editmode, tools operating on meshes
+
+int join_mesh(void);
+
+void fasterdraw(void);
+void slowerdraw(void);
+
+void sort_faces(void);
+
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_image_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_material_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_world_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "BKE_depsgraph.h"
+#include "BKE_customdata.h"
+#include "BKE_global.h"
+#include "BKE_image.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_mesh.h"
+#include "BKE_material.h"
+#include "BKE_object.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_editmesh.h"
+#include "BIF_graphics.h"
+#include "BIF_interface.h"
+#include "BIF_mywindow.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_toolbox.h"
+#include "BIF_editconstraint.h"
+
+#include "BDR_drawmesh.h"
+#include "BDR_editobject.h"
+#include "BDR_editface.h"
+#include "BDR_sculptmode.h"
+
+#include "BLI_editVert.h"
+#include "BLI_threads.h"
+#include "BLI_rand.h" /* for randome face sorting */
+
+#include "mydevice.h"
+#include "blendef.h"
+
+#include "BIF_meshtools.h" /* include ourself for prototypes */
+
+#include "RE_pipeline.h"
+#include "RE_shader_ext.h"
+
+#include "PIL_time.h"
+
+#include "IMB_imbuf_types.h"
+
+/* from rendercode.c */
+#define VECMUL(dest, f) dest[0]*= f; dest[1]*= f; dest[2]*= f
+
+/* * ********************** no editmode!!! *********** */
+
+/* join selected meshes into the active mesh, context sensitive
+return 0 if no join is made (error) and 1 of the join is done */
+int join_mesh(void)
+{
+ Base *base, *nextb;
+ Object *ob;
+ Material **matar, *ma;
+ Mesh *me;
+ MVert *mvert, *mvertmain;
+ MEdge *medge = NULL, *medgemain;
+ MFace *mface = NULL, *mfacemain;
+ float imat[4][4], cmat[4][4];
+ int a, b, totcol, totedge=0, totvert=0, totface=0, ok=0, vertofs, map[MAXMAT];
+ int i, j, index, haskey=0, hasmulti=0, edgeofs, faceofs;
+ bDeformGroup *dg, *odg;
+ MDeformVert *dvert;
+ CustomData vdata, edata, fdata;
+
+ if(G.obedit) return 0;
+
+ ob= OBACT;
+ if(!ob || ob->type!=OB_MESH) return 0;
+
+ if (object_data_is_libdata(ob)) {
+ error_libdata();
+ return 0;
+ }
+
+#ifdef WITH_VERSE
+ /* it isn't allowed to join shared object at verse server
+ * this function will be implemented as soon as possible */
+ base= FIRSTBASE;
+ while(base) {
+ if TESTBASELIB(base) {
+ if(base->object->type==OB_MESH) {
+ if(base->object->vnode) {
+ haskey= 1;
+ break;
+ }
+ }
+ }
+ base= base->next;
+ }
+ if(haskey) {
+ error("Can't join meshes shared at verse server");
+ return 0;
+ }
+#endif
+
+ /* count & check */
+ base= FIRSTBASE;
+ while(base) {
+ if TESTBASELIB(base) {
+ if(base->object->type==OB_MESH) {
+ me= base->object->data;
+ totvert+= me->totvert;
+ totface+= me->totface;
+
+ if(base->object == ob) ok= 1;
+
+ if(me->key) {
+ haskey= 1;
+ break;
+ }
+ if(me->mr) {
+ hasmulti= 1;
+ break;
+ }
+ }
+ }
+ base= base->next;
+ }
+
+ if(haskey) {
+ error("Can't join meshes with vertex keys");
+ return 0;
+ }
+ if(hasmulti) {
+ error("Can't join meshes with Multires");
+ return 0;
+ }
+ /* that way the active object is always selected */
+ if(ok==0) return 0;
+
+ if(totvert==0 || totvert>MESH_MAX_VERTS) return 0;
+
+ /* if needed add edges to other meshes */
+ for(base= FIRSTBASE; base; base= base->next) {
+ if TESTBASELIB(base) {
+ if(base->object->type==OB_MESH) {
+ me= base->object->data;
+ totedge += me->totedge;
+ }
+ }
+ }
+
+ /* new material indices and material array */
+ matar= MEM_callocN(sizeof(void *)*MAXMAT, "join_mesh");
+ totcol= ob->totcol;
+
+ /* obact materials in new main array, is nicer start! */
+ for(a=1; a<=ob->totcol; a++) {
+ matar[a-1]= give_current_material(ob, a);
+ id_us_plus((ID *)matar[a-1]);
+ /* increase id->us : will be lowered later */
+ }
+
+ base= FIRSTBASE;
+ while(base) {
+ if TESTBASELIB(base) {
+ if(ob!=base->object && base->object->type==OB_MESH) {
+ me= base->object->data;
+
+ // Join this object's vertex groups to the base one's
+ for (dg=base->object->defbase.first; dg; dg=dg->next){
+ /* See if this group exists in the object */
+ for (odg=ob->defbase.first; odg; odg=odg->next){
+ if (!strcmp(odg->name, dg->name)){
+ break;
+ }
+ }
+ if (!odg){
+ odg = MEM_callocN (sizeof(bDeformGroup), "join deformGroup");
+ memcpy (odg, dg, sizeof(bDeformGroup));
+ BLI_addtail(&ob->defbase, odg);
+ }
+
+ }
+ if (ob->defbase.first && ob->actdef==0)
+ ob->actdef=1;
+
+ if(me->totvert) {
+ for(a=1; a<=base->object->totcol; a++) {
+ ma= give_current_material(base->object, a);
+ if(ma) {
+ for(b=0; b<totcol; b++) {
+ if(ma == matar[b]) break;
+ }
+ if(b==totcol) {
+ matar[b]= ma;
+ ma->id.us++;
+ totcol++;
+ }
+ if(totcol>=MAXMAT-1) break;
+ }
+ }
+ }
+ }
+ if(totcol>=MAXMAT-1) break;
+ }
+ base= base->next;
+ }
+
+ me= ob->data;
+
+ memset(&vdata, 0, sizeof(vdata));
+ memset(&edata, 0, sizeof(edata));
+ memset(&fdata, 0, sizeof(fdata));
+
+ mvert= CustomData_add_layer(&vdata, CD_MVERT, CD_CALLOC, NULL, totvert);
+ medge= CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, NULL, totedge);
+ mface= CustomData_add_layer(&fdata, CD_MFACE, CD_CALLOC, NULL, totface);
+
+ mvertmain= mvert;
+ medgemain= medge;
+ mfacemain= mface;
+
+ /* inverse transorm all selected meshes in this object */
+ Mat4Invert(imat, ob->obmat);
+
+ vertofs= 0;
+ edgeofs= 0;
+ faceofs= 0;
+ base= FIRSTBASE;
+ while(base) {
+ nextb= base->next;
+ if TESTBASELIB(base) {
+ if(base->object->type==OB_MESH) {
+
+ me= base->object->data;
+
+ if(me->totvert) {
+ CustomData_merge(&me->vdata, &vdata, CD_MASK_MESH, CD_DEFAULT, totvert);
+ CustomData_copy_data(&me->vdata, &vdata, 0, vertofs, me->totvert);
+
+ dvert= CustomData_get(&vdata, vertofs, CD_MDEFORMVERT);
+
+ /* NEW VERSION */
+ if (dvert){
+ for (i=0; i<me->totvert; i++){
+ for (j=0; j<dvert[i].totweight; j++){
+ // Find the old vertex group
+ odg = BLI_findlink (&base->object->defbase, dvert[i].dw[j].def_nr);
+ if(odg) {
+ // Search for a match in the new object
+ for (dg=ob->defbase.first, index=0; dg; dg=dg->next, index++){
+ if (!strcmp(dg->name, odg->name)){
+ dvert[i].dw[j].def_nr = index;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if(base->object != ob) {
+ /* watch this: switch matmul order really goes wrong */
+ Mat4MulMat4(cmat, base->object->obmat, imat);
+
+ a= me->totvert;
+ while(a--) {
+ Mat4MulVecfl(cmat, mvert->co);
+ mvert++;
+ }
+ }
+ else mvert+= me->totvert;
+ }
+ if(me->totface) {
+
+ /* make mapping for materials */
+ memset(map, 0, 4*MAXMAT);
+ for(a=1; a<=base->object->totcol; a++) {
+ ma= give_current_material(base->object, a);
+ if(ma) {
+ for(b=0; b<totcol; b++) {
+ if(ma == matar[b]) {
+ map[a-1]= b;
+ break;
+ }
+ }
+ }
+ }
+
+ CustomData_merge(&me->fdata, &fdata, CD_MASK_MESH, CD_DEFAULT, totface);
+ CustomData_copy_data(&me->fdata, &fdata, 0, faceofs, me->totface);
+
+ for(a=0; a<me->totface; a++, mface++) {
+ mface->v1+= vertofs;
+ mface->v2+= vertofs;
+ mface->v3+= vertofs;
+ if(mface->v4) mface->v4+= vertofs;
+
+ mface->mat_nr= map[(int)mface->mat_nr];
+ }
+
+ faceofs += me->totface;
+ }
+
+ if(me->totedge) {
+ CustomData_merge(&me->edata, &edata, CD_MASK_MESH, CD_DEFAULT, totedge);
+ CustomData_copy_data(&me->edata, &edata, 0, edgeofs, me->totedge);
+
+ for(a=0; a<me->totedge; a++, medge++) {
+ medge->v1+= vertofs;
+ medge->v2+= vertofs;
+ }
+
+ edgeofs += me->totedge;
+ }
+
+ vertofs += me->totvert;
+
+ if(base->object!=ob)
+ free_and_unlink_base(base);
+ }
+ }
+ base= nextb;
+ }
+
+ me= ob->data;
+
+ CustomData_free(&me->vdata, me->totvert);
+ CustomData_free(&me->edata, me->totedge);
+ CustomData_free(&me->fdata, me->totface);
+
+ me->totvert= totvert;
+ me->totedge= totedge;
+ me->totface= totface;
+
+ me->vdata= vdata;
+ me->edata= edata;
+ me->fdata= fdata;
+
+ mesh_update_customdata_pointers(me);
+
+ /* old material array */
+ for(a=1; a<=ob->totcol; a++) {
+ ma= ob->mat[a-1];
+ if(ma) ma->id.us--;
+ }
+ for(a=1; a<=me->totcol; a++) {
+ ma= me->mat[a-1];
+ if(ma) ma->id.us--;
+ }
+ if(ob->mat) MEM_freeN(ob->mat);
+ if(me->mat) MEM_freeN(me->mat);
+ ob->mat= me->mat= 0;
+
+ if(totcol) {
+ me->mat= matar;
+ ob->mat= MEM_callocN(sizeof(void *)*totcol, "join obmatar");
+ }
+ else MEM_freeN(matar);
+
+ ob->totcol= me->totcol= totcol;
+ ob->colbits= 0;
+
+ /* other mesh users */
+ test_object_materials((ID *)me);
+
+ DAG_scene_sort(G.scene); // removed objects, need to rebuild dag before editmode call
+
+ enter_editmode(EM_WAITCURSOR);
+ exit_editmode(EM_FREEDATA|EM_WAITCURSOR); // freedata, but no undo
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSSHADING, 0);
+
+ BIF_undo_push("Join Mesh");
+ return 1;
+}
+
+
+/* ********************** SORT FACES ******************* */
+
+static void permutate(void *list, int num, int size, int *index)
+{
+ void *buf;
+ int len;
+ int i;
+
+ len = num * size;
+
+ buf = MEM_mallocN(len, "permutate");
+ memcpy(buf, list, len);
+
+ for (i = 0; i < num; i++) {
+ memcpy((char *)list + (i * size), (char *)buf + (index[i] * size), size);
+ }
+ MEM_freeN(buf);
+}
+
+/* sort faces on view axis */
+static float *face_sort_floats;
+static int float_sort(const void *v1, const void *v2)
+{
+ float x1, x2;
+
+ x1 = face_sort_floats[((int *) v1)[0]];
+ x2 = face_sort_floats[((int *) v2)[0]];
+
+ if( x1 > x2 ) return 1;
+ else if( x1 < x2 ) return -1;
+ return 0;
+}
+
+
+void sort_faces(void)
+{
+ Object *ob= OBACT;
+ Mesh *me;
+ CustomDataLayer *layer;
+ int i, *index;
+ short event;
+ float reverse = 1;
+
+ if(!ob) return;
+ if(G.obedit) return;
+ if(ob->type!=OB_MESH) return;
+ if (!G.vd) return;
+
+ me= ob->data;
+ if(me->totface==0) return;
+
+ event = pupmenu(
+ "Sort Faces (Ctrl to reverse)%t|"
+ "View Axis%x1|"
+ "Cursor Distance%x2|"
+ "Material%x3|"
+ "Selection%x4|"
+ "Randomize%x5");
+
+ if (event==-1) return;
+
+ if(G.qual & LR_CTRLKEY)
+ reverse = -1;
+
+/* create index list */
+ index = (int *) MEM_mallocN(sizeof(int) * me->totface, "sort faces");
+ for (i = 0; i < me->totface; i++) {
+ index[i] = i;
+ }
+
+ face_sort_floats = (float *) MEM_mallocN(sizeof(float) * me->totface, "sort faces float");
+
+/* sort index list instead of faces itself
+ and apply this permutation to all face layers */
+
+ if (event == 5) {
+ /* Random */
+ for(i=0; i<me->totface; i++) {
+ face_sort_floats[i] = BLI_frand();
+ }
+ qsort(index, me->totface, sizeof(int), float_sort);
+ } else {
+ MFace *mf;
+ float vec[3];
+ float mat[4][4];
+ float cur[3];
+
+ if (event == 1)
+ Mat4MulMat4(mat, OBACT->obmat, G.vd->viewmat); /* apply the view matrix to the object matrix */
+ else if (event == 2) { /* sort from cursor */
+ if( G.vd && G.vd->localview ) {
+ VECCOPY(cur, G.vd->cursor);
+ } else {
+ VECCOPY(cur, G.scene->cursor);
+ }
+ Mat4Invert(mat, OBACT->obmat);
+ Mat4MulVecfl(mat, cur);
+ }
+
+ mf= me->mface;
+ for(i=0; i<me->totface; i++, mf++) {
+
+ if (event==3) {
+ face_sort_floats[i] = ((float)mf->mat_nr)*reverse;
+ } else if (event==4) {
+ /*selected first*/
+ if (mf->flag & ME_FACE_SEL) face_sort_floats[i] = 0.0;
+ else face_sort_floats[i] = reverse;
+ } else {
+ /* find the faces center */
+ VECADD(vec, (me->mvert+mf->v1)->co, (me->mvert+mf->v2)->co);
+ if (mf->v4) {
+ VECADD(vec, vec, (me->mvert+mf->v3)->co);
+ VECADD(vec, vec, (me->mvert+mf->v4)->co);
+ VECMUL(vec, 0.25f);
+ } else {
+ VECADD(vec, vec, (me->mvert+mf->v3)->co);
+ VECMUL(vec, 1.0f/3.0f);
+ } /* done */
+
+ if (event == 1) { /* sort on view axis */
+ Mat4MulVecfl(mat, vec);
+ face_sort_floats[i] = vec[2] * reverse;
+ } else { /* distance from cursor*/
+ face_sort_floats[i] = VecLenf(cur, vec) * reverse; /* back to front */
+ }
+ }
+ }
+ qsort(index, me->totface, sizeof(int), float_sort);
+ }
+
+ MEM_freeN(face_sort_floats);
+
+ for(i = 0; i < me->fdata.totlayer; i++) {
+ layer = &me->fdata.layers[i];
+ permutate(layer->data, me->totface, CustomData_sizeof(layer->type), index);
+ }
+
+ MEM_freeN(index);
+
+ allqueue(REDRAWVIEW3D, 0);
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+}
+
+
+
+/* ********************* MESH VERTEX OCTREE LOOKUP ************* */
+
+/* important note; this is unfinished, needs better API for editmode, and custom threshold */
+
+#define MOC_RES 8
+#define MOC_NODE_RES 8
+#define MOC_THRESH 0.0002f
+
+typedef struct MocNode {
+ struct MocNode *next;
+ long index[MOC_NODE_RES];
+} MocNode;
+
+static int mesh_octree_get_base_offs(float *co, float *offs, float *div)
+{
+ int vx, vy, vz;
+
+ vx= floor( (co[0]-offs[0])/div[0] );
+ vy= floor( (co[1]-offs[1])/div[1] );
+ vz= floor( (co[2]-offs[2])/div[2] );
+
+ CLAMP(vx, 0, MOC_RES-1);
+ CLAMP(vy, 0, MOC_RES-1);
+ CLAMP(vz, 0, MOC_RES-1);
+
+ return (vx*MOC_RES*MOC_RES) + vy*MOC_RES + vz;
+}
+
+static void mesh_octree_add_node(MocNode **bt, long index)
+{
+ if(*bt==NULL) {
+ *bt= MEM_callocN(sizeof(MocNode), "MocNode");
+ (*bt)->index[0]= index;
+ }
+ else {
+ int a;
+ for(a=0; a<MOC_NODE_RES; a++) {
+ if((*bt)->index[a]==index)
+ return;
+ else if((*bt)->index[a]==0) {
+ (*bt)->index[a]= index;
+ return;
+ }
+ }
+ mesh_octree_add_node(&(*bt)->next, index);
+ }
+}
+
+static void mesh_octree_free_node(MocNode **bt)
+{
+ if( (*bt)->next ) {
+ mesh_octree_free_node(&(*bt)->next);
+ }
+ MEM_freeN(*bt);
+}
+
+
+/* temporal define, just to make nicer code below */
+#define MOC_ADDNODE(vx, vy, vz) mesh_octree_add_node(basetable + ((vx)*MOC_RES*MOC_RES) + (vy)*MOC_RES + (vz), index)
+
+static void mesh_octree_add_nodes(MocNode **basetable, float *co, float *offs, float *div, long index)
+{
+ float fx, fy, fz;
+ int vx, vy, vz;
+
+ fx= (co[0]-offs[0])/div[0];
+ fy= (co[1]-offs[1])/div[1];
+ fz= (co[2]-offs[2])/div[2];
+ CLAMP(fx, 0.0f, MOC_RES-MOC_THRESH);
+ CLAMP(fy, 0.0f, MOC_RES-MOC_THRESH);
+ CLAMP(fz, 0.0f, MOC_RES-MOC_THRESH);
+
+ vx= floor(fx);
+ vy= floor(fy);
+ vz= floor(fz);
+
+ MOC_ADDNODE(vx, vy, vz);
+
+ if( vx>0 )
+ if( fx-((float)vx)-MOC_THRESH < 0.0f)
+ MOC_ADDNODE(vx-1, vy, vz);
+ if( vx<MOC_RES-2 )
+ if( fx-((float)vx)+MOC_THRESH > 1.0f)
+ MOC_ADDNODE(vx+1, vy, vz);
+
+ if( vy>0 )
+ if( fy-((float)vy)-MOC_THRESH < 0.0f)
+ MOC_ADDNODE(vx, vy-1, vz);
+ if( vy<MOC_RES-2 )
+ if( fy-((float)vy)+MOC_THRESH > 1.0f)
+ MOC_ADDNODE(vx, vy+1, vz);
+
+ if( vz>0 )
+ if( fz-((float)vz)-MOC_THRESH < 0.0f)
+ MOC_ADDNODE(vx, vy, vz-1);
+ if( vz<MOC_RES-2 )
+ if( fz-((float)vz)+MOC_THRESH > 1.0f)
+ MOC_ADDNODE(vx, vy, vz+1);
+
+}
+
+static long mesh_octree_find_index(MocNode **bt, MVert *mvert, float *co)
+{
+ float *vec;
+ int a;
+
+ if(*bt==NULL)
+ return -1;
+
+ for(a=0; a<MOC_NODE_RES; a++) {
+ if((*bt)->index[a]) {
+ /* does mesh verts and editmode, code looks potential dangerous, octree should really be filled OK! */
+ if(mvert) {
+ vec= (mvert+(*bt)->index[a]-1)->co;
+ if(FloatCompare(vec, co, MOC_THRESH))
+ return (*bt)->index[a]-1;
+ }
+ else {
+ EditVert *eve= (EditVert *)((*bt)->index[a]);
+ if(FloatCompare(eve->co, co, MOC_THRESH))
+ return (*bt)->index[a];
+ }
+ }
+ else return -1;
+ }
+ if( (*bt)->next)
+ return mesh_octree_find_index(&(*bt)->next, mvert, co);
+
+ return -1;
+}
+
+
+/* mode is 's' start, or 'e' end, or 'u' use */
+/* if end, ob can be NULL */
+long mesh_octree_table(Object *ob, float *co, char mode)
+{
+ MocNode **bt;
+ static MocNode **basetable= NULL;
+ static float offs[3], div[3];
+
+ if(mode=='u') { /* use table */
+ if(basetable==NULL)
+ mesh_octree_table(ob, NULL, 's');
+
+ if(basetable) {
+ Mesh *me= ob->data;
+ bt= basetable + mesh_octree_get_base_offs(co, offs, div);
+ if(ob==G.obedit)
+ return mesh_octree_find_index(bt, NULL, co);
+ else
+ return mesh_octree_find_index(bt, me->mvert, co);
+ }
+ return -1;
+ }
+ else if(mode=='s') { /* start table */
+ Mesh *me= ob->data;
+ BoundBox *bb = mesh_get_bb(me);
+
+ /* for quick unit coordinate calculus */
+ VECCOPY(offs, bb->vec[0]);
+ offs[0]-= MOC_THRESH; /* we offset it 1 threshold unit extra */
+ offs[1]-= MOC_THRESH;
+ offs[2]-= MOC_THRESH;
+
+ VecSubf(div, bb->vec[6], bb->vec[0]);
+ div[0]+= 2*MOC_THRESH; /* and divide with 2 threshold unit more extra (try 8x8 unit grid on paint) */
+ div[1]+= 2*MOC_THRESH;
+ div[2]+= 2*MOC_THRESH;
+
+ VecMulf(div, 1.0f/MOC_RES);
+ if(div[0]==0.0f) div[0]= 1.0f;
+ if(div[1]==0.0f) div[1]= 1.0f;
+ if(div[2]==0.0f) div[2]= 1.0f;
+
+ if(basetable) /* happens when entering this call without ending it */
+ mesh_octree_table(ob, co, 'e');
+
+ basetable= MEM_callocN(MOC_RES*MOC_RES*MOC_RES*sizeof(void *), "sym table");
+
+ if(ob==G.obedit) {
+ EditVert *eve;
+
+ for(eve= G.editMesh->verts.first; eve; eve= eve->next) {
+ mesh_octree_add_nodes(basetable, eve->co, offs, div, (long)(eve));
+ }
+ }
+ else {
+ MVert *mvert;
+ long a;
+
+ for(a=1, mvert= me->mvert; a<=me->totvert; a++, mvert++) {
+ mesh_octree_add_nodes(basetable, mvert->co, offs, div, a);
+ }
+ }
+ }
+ else if(mode=='e') { /* end table */
+ if(basetable) {
+ int a;
+
+ for(a=0, bt=basetable; a<MOC_RES*MOC_RES*MOC_RES; a++, bt++) {
+ if(*bt) mesh_octree_free_node(bt);
+ }
+ MEM_freeN(basetable);
+ basetable= NULL;
+ }
+ }
+ return 0;
+}
+
+int mesh_get_x_mirror_vert(Object *ob, int index)
+{
+ Mesh *me= ob->data;
+ MVert *mvert= me->mvert+index;
+ float vec[3];
+
+ vec[0]= -mvert->co[0];
+ vec[1]= mvert->co[1];
+ vec[2]= mvert->co[2];
+
+ return mesh_octree_table(ob, vec, 'u');
+}
+
+EditVert *editmesh_get_x_mirror_vert(Object *ob, float *co)
+{
+ float vec[3];
+ long poinval;
+
+ vec[0]= -co[0];
+ vec[1]= co[1];
+ vec[2]= co[2];
+
+ poinval= mesh_octree_table(ob, vec, 'u');
+ if(poinval != -1)
+ return (EditVert *)(poinval);
+ return NULL;
+}
+
+
+/* ****************** render BAKING ********************** */
+
+/* threaded break test */
+static volatile int g_break= 0;
+static int thread_break(void)
+{
+ return g_break;
+}
+
+static ScrArea *biggest_image_area(void)
+{
+ ScrArea *sa, *big= NULL;
+ int size, maxsize= 0;
+
+ for(sa= G.curscreen->areabase.first; sa; sa= sa->next) {
+ if(sa->spacetype==SPACE_IMAGE) {
+ size= sa->winx*sa->winy;
+ if(sa->winx > 10 && sa->winy > 10 && size > maxsize) {
+ maxsize= size;
+ big= sa;
+ }
+ }
+ }
+ return big;
+}
+
+
+typedef struct BakeRender {
+ Render *re;
+ int event, tot, ready;
+} BakeRender;
+
+static void *do_bake_render(void *bake_v)
+{
+ BakeRender *bkr= bake_v;
+
+ bkr->tot= RE_bake_shade_all_selected(bkr->re, bkr->event);
+ bkr->ready= 1;
+
+ return NULL;
+}
+
+
+void objects_bake_render_menu(void)
+{
+ short event;
+
+ event= pupmenu("Bake Selected Meshes %t|Full Render %x1|Ambient Occlusion %x2|Normals %x3|Texture Only %x4");
+
+ objects_bake_render(event);
+}
+
+/* all selected meshes with UV maps are rendered for current scene visibility */
+void objects_bake_render(short event)
+{
+ short prev_r_raytrace= 0, prev_wo_amb_occ= 0;
+
+ if(event==0) event= G.scene->r.bake_mode;
+
+ if(G.scene->r.renderer!=R_INTERN) {
+ error("Bake only supported for Internal Renderer");
+ return;
+ }
+
+ if(event>0) {
+ Render *re= RE_NewRender("_Bake View_");
+ ScrArea *area= biggest_image_area();
+ ListBase threads;
+ BakeRender bkr;
+ int timer=0, tot, sculptmode= G.f & G_SCULPTMODE;
+
+ if(sculptmode) set_sculptmode();
+
+ if(event==1) event= RE_BAKE_ALL;
+ else if(event==2) event= RE_BAKE_AO;
+ else if(event==3) event= RE_BAKE_NORMALS;
+ else event= RE_BAKE_TEXTURE;
+
+ if(event==RE_BAKE_AO) {
+ if(G.scene->world==NULL) {
+ error("No world set up");
+ return;
+ }
+
+ /* If raytracing or AO is disabled, switch it on temporarily for baking. */
+ prev_r_raytrace = (G.scene->r.mode & R_RAYTRACE) != 0;
+ prev_wo_amb_occ = (G.scene->world->mode & WO_AMB_OCC) != 0;
+
+ G.scene->r.mode |= R_RAYTRACE;
+ G.scene->world->mode |= WO_AMB_OCC;
+ }
+
+ waitcursor(1);
+ RE_test_break_cb(re, thread_break);
+ g_break= 0;
+ G.afbreek= 0; /* blender_test_break uses this global */
+
+ RE_Database_Baking(re, G.scene, event);
+
+ /* baking itself is threaded, cannot use test_break in threads. we also update optional imagewindow */
+
+ BLI_init_threads(&threads, do_bake_render, 1);
+ bkr.re= re;
+ bkr.event= event;
+ bkr.ready= 0;
+ BLI_insert_thread(&threads, &bkr);
+
+ while(bkr.ready==0) {
+ PIL_sleep_ms(50);
+ if(bkr.ready)
+ break;
+
+ g_break= blender_test_break();
+
+ timer++;
+ if(area && timer==20) {
+ Image *ima= RE_bake_shade_get_image();
+ if(ima) ((SpaceImage *)area->spacedata.first)->image= ima;
+ scrarea_do_windraw(area);
+ myswapbuffers();
+ timer= 0;
+ }
+ }
+ BLI_end_threads(&threads);
+ tot= bkr.tot;
+
+ RE_Database_Free(re);
+ waitcursor(0);
+
+ if(tot==0) error("No Images found to bake to");
+ else {
+ Image *ima;
+ /* force OpenGL reload */
+ for(ima= G.main->image.first; ima; ima= ima->id.next) {
+ if(ima->ok==IMA_OK_LOADED) {
+ ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL);
+ if(ibuf && (ibuf->userflags & IB_BITMAPDIRTY))
+ free_realtime_image(ima);
+ }
+ }
+ }
+
+ /* restore raytrace and AO */
+ if(event==RE_BAKE_AO) {
+ if( prev_wo_amb_occ == 0) G.scene->world->mode &= ~WO_AMB_OCC;
+ if( prev_r_raytrace == 0) G.scene->r.mode &= ~R_RAYTRACE;
+ }
+
+ allqueue(REDRAWIMAGE, 0);
+ allqueue(REDRAWVIEW3D, 0);
+
+ if(sculptmode) set_sculptmode();
+
+ }
+}
+
+
diff --git a/source/blender/src/multires-firstlevel.c b/source/blender/src/multires-firstlevel.c
new file mode 100644
index 00000000000..2be867b5db0
--- /dev/null
+++ b/source/blender/src/multires-firstlevel.c
@@ -0,0 +1,410 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 by Nicholas Bishop
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Deals with the first-level data in multires (edge flags, weights, and UVs)
+ *
+ * multires.h
+ *
+ */
+
+#include "DNA_customdata_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BIF_editmesh.h"
+
+#include "BKE_customdata.h"
+#include "BKE_global.h"
+#include "BKE_mesh.h"
+
+#include "BLI_editVert.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "blendef.h"
+#include "multires.h"
+
+#include <string.h>
+
+MDeformVert *subdivide_dverts(MDeformVert *src, MultiresLevel *lvl);
+MTFace *subdivide_mtfaces(MTFace *src, MultiresLevel *lvl);
+void multires_update_edge_flags(Mesh *me, EditMesh *em);
+void eed_to_medge_flag(EditEdge *eed, short *flag, char *crease);
+
+/*********** Generic ***********/
+
+CustomDataMask cdmask(const int type)
+{
+ if(type == CD_MDEFORMVERT)
+ return CD_MASK_MDEFORMVERT;
+ else if(type == CD_MTFACE)
+ return CD_MASK_MTFACE;
+ return -1;
+}
+
+char type_ok(const int type)
+{
+ return (type == CD_MDEFORMVERT) || (type == CD_MTFACE);
+}
+
+/* Copy vdata or fdata from Mesh or EditMesh to Multires. */
+void multires_update_customdata(MultiresLevel *lvl1, CustomData *src, CustomData *dst, const int type)
+{
+ if(src && dst && type_ok(type)) {
+ const int tot= (type == CD_MDEFORMVERT ? lvl1->totvert : lvl1->totface);
+ int i;
+
+ CustomData_free(dst, tot);
+
+ if(CustomData_has_layer(src, type)) {
+ if(G.obedit) {
+ EditVert *eve= G.editMesh->verts.first;
+ EditFace *efa= G.editMesh->faces.first;
+ CustomData_copy(src, dst, cdmask(type), CD_CALLOC, tot);
+ for(i=0; i<tot; ++i) {
+ if(type == CD_MDEFORMVERT) {
+ CustomData_from_em_block(&G.editMesh->vdata, dst, eve->data, i);
+ eve= eve->next;
+ }
+ else if(type == CD_MTFACE) {
+ CustomData_from_em_block(&G.editMesh->fdata, dst, efa->data, i);
+ efa= efa->next;
+ }
+ }
+ }
+ else
+ CustomData_copy(src, dst, cdmask(type), CD_DUPLICATE, tot);
+ }
+ }
+}
+
+/* Uses subdivide_dverts or subdivide_mtfaces to subdivide src to match lvl_end. Does not free src. */
+void *subdivide_customdata_to_level(void *src, MultiresLevel *lvl_start,
+ MultiresLevel *lvl_end, const int type)
+{
+ if(src && lvl_start && lvl_end && type_ok(type)) {
+ MultiresLevel *lvl;
+ void *cr_data= NULL, *pr_data= NULL;
+
+ pr_data= src;
+ for(lvl= lvl_start; lvl && lvl != lvl_end; lvl= lvl->next) {
+ if(type == CD_MDEFORMVERT)
+ cr_data= subdivide_dverts(pr_data, lvl);
+ else if(type == CD_MTFACE)
+ cr_data= subdivide_mtfaces(pr_data, lvl);
+
+ /* Free previous subdivision level's data */
+ if(lvl != lvl_start) {
+ if(type == CD_MDEFORMVERT)
+ free_dverts(pr_data, lvl->totvert);
+ else if(type == CD_MTFACE)
+ MEM_freeN(pr_data);
+ }
+
+ pr_data= cr_data;
+ cr_data= NULL;
+ }
+
+ return pr_data;
+ }
+
+ return NULL;
+}
+
+/* Directly copy src into dst (handles both Mesh and EditMesh) */
+void customdata_to_mesh(Mesh *me, EditMesh *em, CustomData *src, CustomData *dst, const int tot, const int type)
+{
+ if(me && me->mr && src && dst && type_ok(type)) {
+ if(em) {
+ int i;
+ EditVert *eve= em->verts.first;
+ EditFace *efa= em->faces.first;
+ CustomData_copy(src, dst, cdmask(type), CD_CALLOC, 0);
+
+ for(i=0; i<tot; ++i) {
+ if(type == CD_MDEFORMVERT) {
+ CustomData_to_em_block(src, dst, i, &eve->data);
+ eve= eve->next;
+ }
+ else if(type == CD_MTFACE) {
+ CustomData_to_em_block(src, dst, i, &efa->data);
+ efa= efa->next;
+ }
+ }
+ } else {
+ CustomData_merge(src, dst, cdmask(type), CD_DUPLICATE, tot);
+ }
+ }
+}
+
+/* Subdivide vdata or fdata from Multires into either Mesh or EditMesh. */
+void multires_customdata_to_mesh(Mesh *me, EditMesh *em, MultiresLevel *lvl, CustomData *src,
+ CustomData *dst, const int type)
+{
+ if(me && me->mr && lvl && src && dst && type_ok(type) &&
+ CustomData_has_layer(src, type)) {
+ const int tot= (type == CD_MDEFORMVERT ? lvl->totvert : lvl->totface);
+ if(lvl == me->mr->levels.first) {
+ customdata_to_mesh(me, em, src, dst, tot, type);
+ }
+ else {
+ CustomData cdf;
+ const int count = CustomData_number_of_layers(src, type);
+ int i;
+
+ /* Construct a new CustomData containing the subdivided data */
+ CustomData_copy(src, &cdf, cdmask(type), CD_ASSIGN, tot);
+ for(i=0; i<count; ++i) {
+ void *layer= CustomData_get_layer_n(&cdf, type, i);
+ CustomData_set_layer_n(&cdf, type, i,
+ subdivide_customdata_to_level(layer, me->mr->levels.first, lvl, type));
+ }
+
+ customdata_to_mesh(me, em, &cdf, dst, tot, type);
+ CustomData_free(&cdf, tot);
+ }
+ }
+}
+
+/* Subdivide the first-level customdata up to cr_lvl, then delete the original data */
+void multires_del_lower_customdata(Multires *mr, MultiresLevel *cr_lvl)
+{
+ MultiresLevel *lvl1= mr->levels.first;
+ MDeformVert *dverts= NULL;
+ CustomData cdf;
+ int i;
+
+ /* dverts */
+ dverts= subdivide_customdata_to_level(CustomData_get(&mr->vdata, 0, CD_MDEFORMVERT),
+ lvl1, cr_lvl, CD_MDEFORMVERT);
+ if(dverts) {
+ CustomData_free_layers(&mr->vdata, CD_MDEFORMVERT, lvl1->totvert);
+ CustomData_add_layer(&mr->vdata, CD_MDEFORMVERT, CD_ASSIGN, dverts, cr_lvl->totvert);
+ }
+
+ /* mtfaces */
+ CustomData_copy(&mr->fdata, &cdf, CD_MASK_MTFACE, CD_ASSIGN, cr_lvl->totface);
+ for(i=0; i<CustomData_number_of_layers(&mr->fdata, CD_MTFACE); ++i) {
+ MTFace *mtfaces=
+ subdivide_customdata_to_level(CustomData_get_layer_n(&mr->fdata, CD_MTFACE, i),
+ lvl1, cr_lvl, CD_MTFACE);
+ if(mtfaces)
+ CustomData_set_layer_n(&cdf, CD_MTFACE, i, mtfaces);
+ }
+
+ CustomData_free(&mr->fdata, lvl1->totface);
+ mr->fdata= cdf;
+}
+
+/* Update all special first-level data, if the first-level is active */
+void multires_update_first_level(Mesh *me, EditMesh *em)
+{
+ if(me && me->mr && me->mr->current == 1) {
+ multires_update_customdata(me->mr->levels.first, em ? &em->vdata : &me->vdata,
+ &me->mr->vdata, CD_MDEFORMVERT);
+ multires_update_customdata(me->mr->levels.first, em ? &em->fdata : &me->fdata,
+ &me->mr->fdata, CD_MTFACE);
+ multires_update_edge_flags(me, em);
+ }
+}
+
+/*********** Multires.edge_flags ***********/
+void multires_update_edge_flags(Mesh *me, EditMesh *em)
+{
+ MultiresLevel *lvl= me->mr->levels.first;
+ EditEdge *eed= NULL;
+ int i;
+
+ if(em) eed= em->edges.first;
+ for(i=0; i<lvl->totedge; ++i) {
+ if(em) {
+ me->mr->edge_flags[i]= 0;
+ eed_to_medge_flag(eed, &me->mr->edge_flags[i], &me->mr->edge_creases[i]);
+ eed= eed->next;
+ }
+ else {
+ me->mr->edge_flags[i]= me->medge[i].flag;
+ me->mr->edge_creases[i]= me->medge[i].crease;
+ }
+ }
+}
+
+
+
+/*********** Multires.vdata ***********/
+
+/* MDeformVert */
+
+/* Add each weight from in to out. Scale each weight by w. */
+void multires_add_dvert(MDeformVert *out, const MDeformVert *in, const float w)
+{
+ if(out && in) {
+ int i, j;
+ char found;
+
+ for(i=0; i<in->totweight; ++i) {
+ found= 0;
+ for(j=0; j<out->totweight; ++j) {
+ if(out->dw[j].def_nr==in->dw[i].def_nr) {
+ out->dw[j].weight += in->dw[i].weight * w;
+ found= 1;
+ }
+ }
+ if(!found) {
+ MDeformWeight *newdw= MEM_callocN(sizeof(MDeformWeight)*(out->totweight+1),
+ "multires dvert");
+ if(out->dw) {
+ memcpy(newdw, out->dw, sizeof(MDeformWeight)*out->totweight);
+ MEM_freeN(out->dw);
+ }
+
+ out->dw= newdw;
+ out->dw[out->totweight].weight= in->dw[i].weight * w;
+ out->dw[out->totweight].def_nr= in->dw[i].def_nr;
+
+ ++out->totweight;
+ }
+ }
+ }
+}
+
+/* Takes an input array of dverts and subdivides them (linear) using the topology of lvl */
+MDeformVert *subdivide_dverts(MDeformVert *src, MultiresLevel *lvl)
+{
+ if(lvl && lvl->next) {
+ MDeformVert *out = MEM_callocN(sizeof(MDeformVert)*lvl->next->totvert, "dvert prop array");
+ int i, j;
+
+ /* Copy lower level */
+ for(i=0; i<lvl->totvert; ++i)
+ multires_add_dvert(&out[i], &src[i], 1);
+ /* Edge verts */
+ for(i=0; i<lvl->totedge; ++i) {
+ for(j=0; j<2; ++j)
+ multires_add_dvert(&out[lvl->totvert+i], &src[lvl->edges[i].v[j]],0.5);
+ }
+
+ /* Face verts */
+ for(i=0; i<lvl->totface; ++i) {
+ for(j=0; j<(lvl->faces[i].v[3]?4:3); ++j)
+ multires_add_dvert(&out[lvl->totvert + lvl->totedge + i],
+ &src[lvl->faces[i].v[j]],
+ lvl->faces[i].v[3]?0.25:(1.0f/3.0f));
+ }
+
+ return out;
+ }
+
+ return NULL;
+}
+
+
+
+/*********** Multires.fdata ***********/
+
+/* MTFace */
+
+void multires_uv_avg2(float out[2], const float a[2], const float b[2])
+{
+ int i;
+ for(i=0; i<2; ++i)
+ out[i] = (a[i] + b[i]) / 2.0f;
+}
+
+/* Takes an input array of mtfaces and subdivides them (linear) using the topology of lvl */
+MTFace *subdivide_mtfaces(MTFace *src, MultiresLevel *lvl)
+{
+ if(lvl && lvl->next) {
+ MTFace *out= MEM_callocN(sizeof(MultiresColFace)*lvl->next->totface,"Multirescolfaces");
+ int i, j, curf;
+
+ for(i=0, curf=0; i<lvl->totface; ++i) {
+ const char sides= lvl->faces[i].v[3]?4:3;
+ float cntr[2]= {0, 0};
+
+ /* Find average uv coord of the current face */
+ for(j=0; j<sides; ++j) {
+ cntr[0]+= src[i].uv[j][0];
+ cntr[1]+= src[i].uv[j][1];
+ }
+ cntr[0]/= sides;
+ cntr[1]/= sides;
+
+ for(j=0; j<sides; ++j, ++curf) {
+ out[curf]= src[i];
+
+ multires_uv_avg2(out[curf].uv[0], src[i].uv[j], src[i].uv[j==0?sides-1:j-1]);
+
+ out[curf].uv[1][0]= src[i].uv[j][0];
+ out[curf].uv[1][1]= src[i].uv[j][1];
+
+ multires_uv_avg2(out[curf].uv[2], src[i].uv[j], src[i].uv[j==sides-1?0:j+1]);
+
+ out[curf].uv[3][0]= cntr[0];
+ out[curf].uv[3][1]= cntr[1];
+ }
+ }
+
+ return out;
+ }
+
+ return NULL;
+}
+
+void multires_delete_layer(Mesh *me, CustomData *cd, const int type, int n)
+{
+ if(me && me->mr && cd) {
+ MultiresLevel *lvl1= me->mr->levels.first;
+
+ multires_update_levels(me, 0);
+
+ CustomData_set_layer_active(cd, type, n);
+ CustomData_free_layer_active(cd, type, lvl1->totface);
+
+ multires_level_to_mesh(OBACT, me, 0);
+ }
+}
+
+MultiresLevel *current_level(Multires *mr);
+void multires_add_layer(Mesh *me, CustomData *cd, const int type, const int n)
+{
+ if(me && me->mr && cd) {
+ multires_update_levels(me, 0);
+
+ if(CustomData_has_layer(cd, type))
+ CustomData_add_layer(cd, type, CD_DUPLICATE, CustomData_get_layer(cd, type),
+ current_level(me->mr)->totface);
+ else
+ CustomData_add_layer(cd, type, CD_DEFAULT, NULL, current_level(me->mr)->totface);
+
+ CustomData_set_layer_active(cd, type, n);
+ multires_level_to_mesh(OBACT, me, 0);
+ }
+}
diff --git a/source/blender/src/multires.c b/source/blender/src/multires.c
new file mode 100644
index 00000000000..8704f9abfa4
--- /dev/null
+++ b/source/blender/src/multires.c
@@ -0,0 +1,1650 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 by Nicholas Bishop
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Implements the multiresolution modeling tools.
+ *
+ * multires.h
+ *
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "DNA_key_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_vec_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_customdata.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_key.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+
+#include "BIF_editmesh.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_toolbox.h"
+
+#include "BDR_editobject.h"
+#include "BDR_sculptmode.h"
+
+#include "BLI_editVert.h"
+
+#include "BSE_edit.h"
+#include "BSE_view.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "blendef.h"
+#include "editmesh.h"
+#include "multires.h"
+#include "mydevice.h"
+#include "parametrizer.h"
+
+#include <math.h>
+
+const CustomDataMask vdata_mask= CD_MASK_MDEFORMVERT;
+
+void multires_calc_temp_data(struct MultiresLevel *lvl);
+
+int multires_test()
+{
+ Mesh *me= get_mesh(OBACT);
+ if(me && me->mr) {
+ error("Unable to complete action with multires enabled.");
+ return 1;
+ }
+ return 0;
+}
+int multires_level1_test()
+{
+ Mesh *me= get_mesh(OBACT);
+ if(me && me->mr && me->mr->current != 1) {
+ error("Operation only available for multires level 1.");
+ return 1;
+ }
+ return 0;
+}
+
+/* Sculptmode */
+
+void multires_check_state()
+{
+ if(G.f & G_SCULPTMODE && !G.obedit)
+ sculptmode_correct_state();
+}
+
+typedef struct MultiresMapNode {
+ struct MultiresMapNode *next, *prev;
+ unsigned Index;
+} MultiresMapNode;
+
+MultiresLevel *current_level(Multires *mr)
+{
+ return BLI_findlink(&mr->levels, mr->current - 1);
+}
+
+MultiresLevel *multires_level_n(Multires *mr, int n)
+{
+ if(mr)
+ return BLI_findlink(&mr->levels, n - 1);
+ else
+ return NULL;
+}
+
+void Vec3fAvg3(float *out, float *v1, float *v2, float *v3)
+{
+ out[0]= (v1[0]+v2[0]+v3[0])/3;
+ out[1]= (v1[1]+v2[1]+v3[1])/3;
+ out[2]= (v1[2]+v2[2]+v3[2])/3;
+}
+void Vec3fAvg4(float *out, float *v1, float *v2, float *v3, float *v4)
+{
+ out[0]= (v1[0]+v2[0]+v3[0]+v4[0])/4;
+ out[1]= (v1[1]+v2[1]+v3[1]+v4[1])/4;
+ out[2]= (v1[2]+v2[2]+v3[2]+v4[2])/4;
+}
+
+short multires_vert_is_boundary(MultiresLevel *lvl, unsigned v)
+{
+ MultiresMapNode *node= lvl->vert_edge_map[v].first;
+ while(node) {
+ if(lvl->edge_boundary_states[node->Index])
+ return 1;
+ node= node->next;
+ }
+ return 0;
+}
+
+typedef struct MultiApplyData {
+ /* Smooth faces */
+ float *corner1, *corner2, *corner3, *corner4;
+ char quad;
+
+ /* Smooth edges */
+ char boundary;
+ float edge_face_neighbor_midpoints_accum[3];
+ unsigned edge_face_neighbor_midpoints_total;
+ float *endpoint1, *endpoint2;
+
+ /* Smooth verts */
+ /* uses 'char boundary' */
+ float *original;
+ int edge_count;
+ float vert_face_neighbor_midpoints_average[3];
+ float vert_edge_neighbor_midpoints_average[3];
+ float boundary_edges_average[3];
+} MultiApplyData;
+
+/* CATMULL-CLARK
+ ============= */
+
+/* Simply averages the four corners of a polygon. */
+float catmullclark_smooth_face(MultiApplyData *data, const unsigned i)
+{
+ const float total= data->corner1[i]+data->corner2[i]+data->corner3[i];
+ return data->quad ? (total+data->corner4[i])/4 : total/3;
+}
+
+float catmullclark_smooth_edge(MultiApplyData *data, const unsigned i)
+{
+ float accum= 0;
+ unsigned count= 2;
+
+ accum+= data->endpoint1[i] + data->endpoint2[i];
+
+ if(!data->boundary) {
+ accum+= data->edge_face_neighbor_midpoints_accum[i];
+ count+= data->edge_face_neighbor_midpoints_total;
+ }
+
+ return accum / count;
+}
+float catmullclark_smooth_vert(MultiApplyData *data, const unsigned i)
+{
+ if(data->boundary) {
+ return data->original[i]*0.75 + data->boundary_edges_average[i]*0.25;
+ } else {
+ return (data->vert_face_neighbor_midpoints_average[i] +
+ 2*data->vert_edge_neighbor_midpoints_average[i] +
+ data->original[i]*(data->edge_count-3))/data->edge_count;
+ }
+}
+
+
+
+/* Call func count times, passing in[i] as the input and storing the output in out[i] */
+void multi_apply(float *out, MultiApplyData *data,
+ const unsigned count, float (*func)(MultiApplyData *, const unsigned))
+{
+ unsigned i;
+ for(i=0; i<count; ++i)
+ out[i]= func(data,i);
+}
+
+#define GET_FLOAT(array, i, j, stride) (((float*)((char*)(array)+((i)*(stride))))[(j)])
+
+void edge_face_neighbor_midpoints_accum(MultiApplyData *data, MultiresLevel *lvl,
+ void *array, const char stride, const MultiresEdge *e)
+{
+ ListBase *neighbors1= &lvl->vert_face_map[e->v[0]];
+ ListBase *neighbors2= &lvl->vert_face_map[e->v[1]];
+ MultiresMapNode *n1, *n2;
+ unsigned j,count= 0;
+ float *out= data->edge_face_neighbor_midpoints_accum;
+
+ out[0]=out[1]=out[2]= 0;
+
+ for(n1= neighbors1->first; n1; n1= n1->next) {
+ for(n2= neighbors2->first; n2; n2= n2->next) {
+ if(n1->Index == n2->Index) {
+ for(j=0; j<3; ++j)
+ out[j]+= GET_FLOAT(array,lvl->faces[n1->Index].mid,j,stride);
+ ++count;
+ }
+ }
+ }
+
+ data->edge_face_neighbor_midpoints_total= count;
+}
+void vert_face_neighbor_midpoints_average(MultiApplyData *data, MultiresLevel *lvl,
+ void *array, const char stride, const unsigned i)
+{
+ ListBase *neighbors= &lvl->vert_face_map[i];
+ MultiresMapNode *n1;
+ unsigned j,count= 0;
+ float *out= data->vert_face_neighbor_midpoints_average;
+
+ out[0]=out[1]=out[2]= 0;
+
+ for(n1= neighbors->first; n1; n1= n1->next) {
+ for(j=0; j<3; ++j)
+ out[j]+= GET_FLOAT(array,lvl->faces[n1->Index].mid,j,stride);
+ ++count;
+ }
+ for(j=0; j<3; ++j) out[j]/= count;
+}
+void vert_edge_neighbor_midpoints_average(MultiApplyData *data, MultiresLevel *lvl,
+ void *array, const char stride, const unsigned i)
+{
+ ListBase *neighbors= &lvl->vert_edge_map[i];
+ MultiresMapNode *n1;
+ unsigned j,count= 0;
+ float *out= data->vert_edge_neighbor_midpoints_average;
+
+ out[0]=out[1]=out[2]= 0;
+
+ for(n1= neighbors->first; n1; n1= n1->next) {
+ for(j=0; j<3; ++j)
+ out[j]+= (GET_FLOAT(array,lvl->edges[n1->Index].v[0],j,stride) +
+ GET_FLOAT(array,lvl->edges[n1->Index].v[1],j,stride)) / 2;
+ ++count;
+ }
+ for(j=0; j<3; ++j) out[j]/= count;
+}
+void boundary_edges_average(MultiApplyData *data, MultiresLevel *lvl,
+ void *array, const char stride, const unsigned i)
+{
+ ListBase *neighbors= &lvl->vert_edge_map[i];
+ MultiresMapNode *n1;
+ unsigned j,count= 0;
+ float *out= data->boundary_edges_average;
+
+ out[0]=out[1]=out[2]= 0;
+
+ for(n1= neighbors->first; n1; n1= n1->next) {
+ const MultiresEdge *e= &lvl->edges[n1->Index];
+ const unsigned end= e->v[0]==i ? e->v[1] : e->v[0];
+
+ if(lvl->edge_boundary_states[n1->Index]) {
+ for(j=0; j<3; ++j)
+ out[j]+= GET_FLOAT(array,end,j,stride);
+ ++count;
+ }
+ }
+ for(j=0; j<3; ++j) out[j]/= count;
+}
+
+/* For manipulating vertex colors / uvs */
+void mcol_to_multires(MultiresColFace *mrf, MCol *mcol)
+{
+ char i;
+ for(i=0; i<4; ++i) {
+ mrf->col[i].a= mcol[i].a;
+ mrf->col[i].r= mcol[i].r;
+ mrf->col[i].g= mcol[i].g;
+ mrf->col[i].b= mcol[i].b;
+ }
+}
+
+float clamp_component(const float c)
+{
+ if(c<0) return 0;
+ else if(c>255) return 255;
+ else return c;
+}
+
+void multires_to_mcol(MultiresColFace *f, MCol mcol[4])
+{
+ unsigned char j;
+ for(j=0; j<4; ++j) {
+ mcol->a= clamp_component(f->col[j].a);
+ mcol->r= clamp_component(f->col[j].r);
+ mcol->g= clamp_component(f->col[j].g);
+ mcol->b= clamp_component(f->col[j].b);
+ ++mcol;
+ }
+}
+
+/* 1 <= count <= 4 */
+void multires_col_avg(MultiresCol *avg, MultiresCol cols[4], char count)
+{
+ unsigned i;
+ avg->a= avg->r= avg->g= avg->b= 0;
+ for(i=0; i<count; ++i) {
+ avg->a+= cols[i].a;
+ avg->r+= cols[i].r;
+ avg->g+= cols[i].g;
+ avg->b+= cols[i].b;
+ }
+ avg->a/= count;
+ avg->r/= count;
+ avg->g/= count;
+ avg->b/= count;
+}
+
+void multires_col_avg2(MultiresCol *avg, MultiresCol *c1, MultiresCol *c2)
+{
+ MultiresCol in[2];
+ in[0]= *c1;
+ in[1]= *c2;
+ multires_col_avg(avg,in,2);
+}
+
+void multires_load_cols(Mesh *me)
+{
+ MultiresLevel *lvl= BLI_findlink(&me->mr->levels,me->mr->current-1), *cur;
+ EditMesh *em= G.obedit ? G.editMesh : NULL;
+ CustomData *src= em ? &em->fdata : &me->fdata;
+ EditFace *efa= NULL;
+ unsigned i,j;
+
+ if(!CustomData_has_layer(src, CD_MCOL) && !CustomData_has_layer(src, CD_MTFACE)) return;
+
+ /* Add texcol data */
+ for(cur= me->mr->levels.first; cur; cur= cur->next)
+ if(!cur->colfaces)
+ cur->colfaces= MEM_callocN(sizeof(MultiresColFace)*cur->totface,"ColFaces");
+
+ me->mr->use_col= CustomData_has_layer(src, CD_MCOL);
+
+ if(em) efa= em->faces.first;
+ for(i=0; i<lvl->totface; ++i) {
+ MultiresColFace *f= &lvl->colfaces[i];
+
+ if(me->mr->use_col)
+ mcol_to_multires(f, em ? CustomData_em_get(src, efa->data, CD_MCOL) : &me->mcol[i*4]);
+
+ if(em) efa= efa->next;
+ }
+
+ /* Update higher levels */
+ lvl= lvl->next;
+ while(lvl) {
+ MultiresColFace *cf= lvl->colfaces;
+ for(i=0; i<lvl->prev->totface; ++i) {
+ const char sides= lvl->prev->faces[i].v[3]?4:3;
+ MultiresCol cntr;
+
+ /* Find average color of 4 (or 3 for triangle) verts */
+ multires_col_avg(&cntr,lvl->prev->colfaces[i].col,sides);
+
+ for(j=0; j<sides; ++j) {
+ MultiresColFace *pf= &lvl->prev->colfaces[i];
+
+ multires_col_avg2(&cf->col[0],
+ &pf->col[j],
+ &pf->col[j==0?sides-1:j-1]);
+ cf->col[1]= pf->col[j];
+ multires_col_avg2(&cf->col[2],
+ &pf->col[j],
+ &pf->col[j==sides-1?0:j+1]);
+ cf->col[3]= cntr;
+
+ ++cf;
+ }
+ }
+ lvl= lvl->next;
+ }
+
+ /* Update lower levels */
+ lvl= me->mr->levels.last;
+ lvl= lvl->prev;
+ while(lvl) {
+ unsigned curf= 0;
+ for(i=0; i<lvl->totface; ++i) {
+ MultiresFace *f= &lvl->faces[i];
+ for(j=0; j<(f->v[3]?4:3); ++j) {
+ lvl->colfaces[i].col[j]= lvl->next->colfaces[curf].col[1];
+ ++curf;
+ }
+ }
+ lvl= lvl->prev;
+ }
+}
+
+void multires_get_vert(MVert *out, EditVert *eve, MVert *m, int i)
+{
+ if(eve) {
+ VecCopyf(out->co, eve->co);
+ out->flag= 0;
+ if(eve->f & SELECT) out->flag |= 1;
+ if(eve->h) out->flag |= ME_HIDE;
+ eve->tmp.l= i;
+ }
+ else
+ *out= *m;
+}
+
+void multires_get_face(MultiresFace *f, EditFace *efa, MFace *m)
+{
+ if(efa) {
+ MFace tmp;
+ int j;
+ tmp.v1= efa->v1->tmp.l;
+ tmp.v2= efa->v2->tmp.l;
+ tmp.v3= efa->v3->tmp.l;
+ tmp.v4= 0;
+ if(efa->v4) tmp.v4= efa->v4->tmp.l;
+ test_index_face(&tmp, NULL, 0, efa->v4?4:3);
+ for(j=0; j<4; ++j) f->v[j]= (&tmp.v1)[j];
+
+ /* Flags */
+ f->flag= efa->flag;
+ if(efa->f & 1) f->flag |= ME_FACE_SEL;
+ else f->flag &= ~ME_FACE_SEL;
+ if(efa->h) f->flag |= ME_HIDE;
+ f->mat_nr= efa->mat_nr;
+ } else {
+ f->v[0]= m->v1;
+ f->v[1]= m->v2;
+ f->v[2]= m->v3;
+ f->v[3]= m->v4;
+ f->flag= m->flag;
+ f->mat_nr= m->mat_nr;
+ }
+}
+
+void eed_to_medge_flag(EditEdge *eed, short *flag, char *crease)
+{
+ if(!eed || !flag) return;
+
+ /* Would be nice if EditMesh edge flags could be unified with Mesh flags! */
+ *flag= (eed->f & SELECT) | ME_EDGERENDER;
+ if(eed->f2<2) *flag |= ME_EDGEDRAW;
+ if(eed->f2==0) *flag |= ME_LOOSEEDGE;
+ if(eed->sharp) *flag |= ME_SHARP;
+ if(eed->seam) *flag |= ME_SEAM;
+ if(eed->h & EM_FGON) *flag |= ME_FGON;
+ if(eed->h & 1) *flag |= ME_HIDE;
+
+ *crease= (char)(255.0*eed->crease);
+}
+
+void multires_get_edge(MultiresEdge *e, EditEdge *eed, MEdge *m, short *flag, char *crease)
+{
+ if(eed) {
+ e->v[0]= eed->v1->tmp.l;
+ e->v[1]= eed->v2->tmp.l;
+ eed_to_medge_flag(eed, flag, crease);
+ } else {
+ e->v[0]= m->v1;
+ e->v[1]= m->v2;
+ *flag= m->flag;
+ *crease= m->crease;
+ }
+}
+
+void multires_make(void *ob, void *me_v)
+{
+ Mesh *me= me_v;
+ MultiresLevel *lvl;
+ EditMesh *em= G.obedit ? G.editMesh : NULL;
+ EditVert *eve= NULL;
+ EditFace *efa= NULL;
+ EditEdge *eed= NULL;
+ Key *key;
+ int i;
+
+ /* Check for shape keys */
+ key= me->key;
+ if(key) {
+ int ret= okee("Adding multires will delete all shape keys, proceed?");
+ if(ret) {
+ free_key(key);
+ me->key= NULL;
+ } else
+ return;
+ }
+
+ lvl= MEM_callocN(sizeof(MultiresLevel), "multires level");
+
+ waitcursor(1);
+
+ multires_check_state();
+
+ if(me->pv) sculptmode_pmv_off(me);
+
+ me->mr= MEM_callocN(sizeof(Multires), "multires data");
+
+ BLI_addtail(&me->mr->levels,lvl);
+ me->mr->current= 1;
+ me->mr->level_count= 1;
+ me->mr->edgelvl= 1;
+ me->mr->pinlvl= 1;
+ me->mr->renderlvl= 1;
+
+ /* Load mesh (or editmesh) into multires data */
+
+ /* Load vertices and vdata (MDeformVerts) */
+ lvl->totvert= em ? BLI_countlist(&em->verts) : me->totvert;
+ me->mr->verts= MEM_callocN(sizeof(MVert)*lvl->totvert,"multires verts");
+ multires_update_customdata(me->mr->levels.first, em ? &em->vdata : &me->vdata,
+ &me->mr->vdata, CD_MDEFORMVERT);
+ if(em) eve= em->verts.first;
+ for(i=0; i<lvl->totvert; ++i) {
+ multires_get_vert(&me->mr->verts[i], eve, &me->mvert[i], i);
+ if(em) eve= eve->next;
+ }
+
+ /* Load faces and fdata (MTFaces) */
+ lvl->totface= em ? BLI_countlist(&em->faces) : me->totface;
+ lvl->faces= MEM_callocN(sizeof(MultiresFace)*lvl->totface,"multires faces");
+ multires_update_customdata(me->mr->levels.first, em ? &em->fdata : &me->fdata,
+ &me->mr->fdata, CD_MTFACE);
+ if(em) efa= em->faces.first;
+ for(i=0; i<lvl->totface; ++i) {
+ multires_get_face(&lvl->faces[i], efa, &me->mface[i]);
+ if(em) efa= efa->next;
+ }
+
+ /* Load edges and edge_flags */
+ lvl->totedge= em ? BLI_countlist(&em->edges) : me->totedge;
+ lvl->edges= MEM_callocN(sizeof(MultiresEdge)*lvl->totedge,"multires edges");
+ me->mr->edge_flags= MEM_callocN(sizeof(short)*lvl->totedge, "multires edge flags");
+ me->mr->edge_creases= MEM_callocN(sizeof(short)*lvl->totedge, "multires edge creases");
+ if(em) eed= em->edges.first;
+ for(i=0; i<lvl->totedge; ++i) {
+ multires_get_edge(&lvl->edges[i], eed, &me->medge[i], &me->mr->edge_flags[i], &me->mr->edge_creases[i]);
+ if(em) eed= eed->next;
+ }
+
+ multires_load_cols(me);
+
+ allqueue(REDRAWBUTSEDIT, 0);
+
+ BIF_undo_push("Make multires");
+
+ waitcursor(0);
+}
+
+void multires_delete(void *ob, void *me_v)
+{
+ Mesh *me= me_v;
+ multires_free(me->mr);
+ me->mr= NULL;
+
+ multires_check_state();
+
+ allqueue(REDRAWBUTSEDIT, 0);
+
+ BIF_undo_push("Apply multires");
+}
+
+MultiresLevel *multires_level_copy(MultiresLevel *orig)
+{
+ if(orig) {
+ MultiresLevel *lvl= MEM_dupallocN(orig);
+
+ lvl->next= lvl->prev= NULL;
+ lvl->faces= MEM_dupallocN(orig->faces);
+ lvl->colfaces= MEM_dupallocN(orig->colfaces);
+ lvl->edges= MEM_dupallocN(orig->edges);
+ lvl->edge_boundary_states = NULL;
+ lvl->vert_edge_map= lvl->vert_face_map= NULL;
+ lvl->map_mem= NULL;
+
+ return lvl;
+ }
+ return NULL;
+}
+
+Multires *multires_copy(Multires *orig)
+{
+ if(orig) {
+ Multires *mr= MEM_dupallocN(orig);
+ MultiresLevel *lvl;
+
+ mr->levels.first= mr->levels.last= NULL;
+
+ for(lvl= orig->levels.first; lvl; lvl= lvl->next)
+ BLI_addtail(&mr->levels, multires_level_copy(lvl));
+
+ mr->verts= MEM_dupallocN(orig->verts);
+
+ lvl= mr->levels.first;
+ if(lvl) {
+ CustomData_copy(&orig->vdata, &mr->vdata, vdata_mask, CD_DUPLICATE, lvl->totvert);
+ CustomData_copy(&orig->fdata, &mr->fdata, CD_MASK_MTFACE, CD_DUPLICATE, lvl->totface);
+ mr->edge_flags= MEM_dupallocN(orig->edge_flags);
+ mr->edge_creases= MEM_dupallocN(orig->edge_creases);
+ }
+
+ return mr;
+ }
+ return NULL;
+}
+
+void multires_free(Multires *mr)
+{
+ if(mr) {
+ MultiresLevel* lvl= mr->levels.first;
+
+ /* Free the first-level data */
+ if(lvl) {
+ CustomData_free(&mr->vdata, lvl->totvert);
+ CustomData_free(&mr->fdata, lvl->totface);
+ MEM_freeN(mr->edge_flags);
+ MEM_freeN(mr->edge_creases);
+ }
+
+ while(lvl) {
+ multires_free_level(lvl);
+ lvl= lvl->next;
+ }
+
+ MEM_freeN(mr->verts);
+
+ BLI_freelistN(&mr->levels);
+
+ MEM_freeN(mr);
+ }
+}
+
+/* Free and clear the temporary connectivity data */
+void multires_free_temp_data(MultiresLevel *lvl)
+{
+ if(lvl) {
+ if(lvl->edge_boundary_states) MEM_freeN(lvl->edge_boundary_states);
+ if(lvl->vert_edge_map) MEM_freeN(lvl->vert_edge_map);
+ if(lvl->vert_face_map) MEM_freeN(lvl->vert_face_map);
+ if(lvl->map_mem) MEM_freeN(lvl->map_mem);
+
+ lvl->edge_boundary_states = NULL;
+ lvl->vert_edge_map = lvl->vert_face_map = NULL;
+ lvl->map_mem = NULL;
+ }
+}
+
+/* Does not actually free lvl itself! */
+void multires_free_level(MultiresLevel *lvl)
+{
+ if(lvl) {
+ if(lvl->faces) MEM_freeN(lvl->faces);
+ if(lvl->edges) MEM_freeN(lvl->edges);
+ if(lvl->colfaces) MEM_freeN(lvl->colfaces);
+
+ multires_free_temp_data(lvl);
+ }
+}
+
+/* Make sure that all level indices are clipped to [1, mr->level_count] */
+void multires_clip_levels(Multires *mr)
+{
+ if(mr) {
+ const int cnt = mr->level_count;
+
+ if(mr->current < 1) mr->current = 1;
+ if(mr->edgelvl < 1) mr->edgelvl = 1;
+ if(mr->pinlvl < 1) mr->pinlvl = 1;
+ if(mr->renderlvl < 1) mr->renderlvl = 1;
+
+ if(mr->current > cnt) mr->current = cnt;
+ if(mr->edgelvl > cnt) mr->edgelvl = cnt;
+ if(mr->pinlvl > cnt) mr->pinlvl = cnt;
+ if(mr->renderlvl > cnt) mr->renderlvl = cnt;
+ }
+}
+
+/* Delete all multires levels beneath current level. Subdivide special
+ first-level data up to the new lowest level. */
+void multires_del_lower(void *ob, void *me)
+{
+ Multires *mr= ((Mesh*)me)->mr;
+ MultiresLevel *lvl1= mr->levels.first, *cr_lvl= current_level(mr);
+ MultiresLevel *lvl= NULL, *lvlprev= NULL;
+ short *edgeflags= NULL;
+ char *edgecreases= NULL;
+ int i, last;
+
+ if(cr_lvl == lvl1) return;
+
+ multires_check_state();
+
+ /* Subdivide the edge flags to the current level */
+ edgeflags= MEM_callocN(sizeof(short)*current_level(mr)->totedge, "Multires Edge Flags");
+ edgecreases= MEM_callocN(sizeof(char)*current_level(mr)->totedge, "Multires Edge Creases");
+ last= lvl1->totedge * pow(2, mr->current-1);
+ for(i=0; i<last; ++i) {
+ edgeflags[i] = mr->edge_flags[(int)(i / pow(2, mr->current-1))];
+ edgecreases[i] = mr->edge_creases[(int)(i / pow(2, mr->current-1))];
+ }
+ MEM_freeN(mr->edge_flags);
+ MEM_freeN(mr->edge_creases);
+ mr->edge_flags= edgeflags;
+ mr->edge_creases= edgecreases;
+
+ multires_del_lower_customdata(mr, cr_lvl);
+
+ lvl= cr_lvl->prev;
+ while(lvl) {
+ lvlprev= lvl->prev;
+
+ multires_free_level(lvl);
+ BLI_freelinkN(&mr->levels, lvl);
+
+ mr->current-= 1;
+ mr->level_count-= 1;
+
+ lvl= lvlprev;
+ }
+ mr->newlvl= mr->current;
+
+ multires_clip_levels(mr);
+
+ allqueue(REDRAWBUTSEDIT, 0);
+
+ BIF_undo_push("Multires delete lower");
+}
+
+void multires_del_higher(void *ob, void *me)
+{
+ Multires *mr= ((Mesh*)me)->mr;
+ MultiresLevel *lvl= BLI_findlink(&mr->levels,mr->current-1);
+ MultiresLevel *lvlnext;
+
+ multires_check_state();
+
+ lvl= lvl->next;
+ while(lvl) {
+ lvlnext= lvl->next;
+
+ multires_free_level(lvl);
+ BLI_freelinkN(&mr->levels,lvl);
+
+ mr->level_count-= 1;
+
+ lvl= lvlnext;
+ }
+
+ multires_clip_levels(mr);
+
+ allqueue(REDRAWBUTSEDIT, 0);
+
+ BIF_undo_push("Multires delete higher");
+}
+
+unsigned int find_mid_edge(ListBase *vert_edge_map,
+ MultiresLevel *lvl,
+ const unsigned int v1,
+ const unsigned int v2 )
+{
+ MultiresMapNode *n= vert_edge_map[v1].first;
+ while(n) {
+ if(lvl->edges[n->Index].v[0]==v2 ||
+ lvl->edges[n->Index].v[1]==v2)
+ return lvl->edges[n->Index].mid;
+
+ n= n->next;
+ }
+ return -1;
+}
+
+void check_colors(Mesh *me)
+{
+ CustomData *src= G.obedit ? &G.editMesh->fdata : &me->fdata;
+ const char col= CustomData_has_layer(src, CD_MCOL);
+
+ /* Check if vertex colors have been deleted or added */
+ if(me->mr->use_col && !col)
+ me->mr->use_col= 0;
+ else if(!me->mr->use_col && col) {
+ me->mr->use_col= 1;
+ multires_load_cols(me);
+ }
+}
+
+void multires_add_level(void *ob, void *me_v)
+{
+ int i,j, curf, cure;
+ Mesh *me= me_v;
+ MultiresLevel *lvl= NULL;
+ MultiApplyData data;
+ MVert *oldverts= NULL;
+
+ multires_check_state();
+
+ if(CustomData_number_of_layers(G.obedit ? &G.editMesh->fdata : &me->fdata, CD_MCOL) > 1) {
+ int ret= okee("Adding a level will delete all but the active vertex color layer, proceed?");
+ if(!ret)
+ return;
+ }
+
+ waitcursor(1);
+
+ lvl= MEM_callocN(sizeof(MultiresLevel), "multireslevel");
+ if(me->pv) sculptmode_pmv_off(me);
+
+ check_colors(me);
+ multires_update_levels(me, 0);
+
+ ++me->mr->level_count;
+ BLI_addtail(&me->mr->levels,lvl);
+
+ /* Create vertices
+ =============== */
+ lvl->totvert= lvl->prev->totvert + lvl->prev->totedge + lvl->prev->totface;
+ oldverts= me->mr->verts;
+ me->mr->verts= MEM_callocN(sizeof(MVert)*lvl->totvert, "multitres verts");
+ /* Copy old verts */
+ for(i=0; i<lvl->prev->totvert; ++i)
+ me->mr->verts[i]= oldverts[i];
+ /* Create new edge verts */
+ for(i=0; i<lvl->prev->totedge; ++i) {
+ VecMidf(me->mr->verts[lvl->prev->totvert + i].co,
+ oldverts[lvl->prev->edges[i].v[0]].co,
+ oldverts[lvl->prev->edges[i].v[1]].co);
+ lvl->prev->edges[i].mid= lvl->prev->totvert + i;
+ }
+ /* Create new face verts */
+ for(i=0; i<lvl->prev->totface; ++i) {
+ lvl->prev->faces[i].mid= lvl->prev->totvert + lvl->prev->totedge + i;
+ }
+
+ multires_calc_temp_data(lvl->prev);
+
+ /* Create faces
+ ============ */
+ /* Allocate all the new faces (each triangle creates three, and
+ each quad creates four */
+ lvl->totface= 0;
+ for(i=0; i<lvl->prev->totface; ++i)
+ lvl->totface+= lvl->prev->faces[i].v[3] ? 4 : 3;
+ lvl->faces= MEM_callocN(sizeof(MultiresFace)*lvl->totface,"multires faces");
+
+ curf= 0;
+ for(i=0; i<lvl->prev->totface; ++i) {
+ const int max= lvl->prev->faces[i].v[3] ? 3 : 2;
+
+ for(j=0; j<max+1; ++j) {
+ lvl->faces[curf].v[0]= find_mid_edge(lvl->prev->vert_edge_map,lvl->prev,
+ lvl->prev->faces[i].v[j],
+ lvl->prev->faces[i].v[j==0?max:j-1]);
+ lvl->faces[curf].v[1]= lvl->prev->faces[i].v[j];
+ lvl->faces[curf].v[2]= find_mid_edge(lvl->prev->vert_edge_map,lvl->prev,
+ lvl->prev->faces[i].v[j],
+ lvl->prev->faces[i].v[j==max?0:j+1]);
+ lvl->faces[curf].v[3]= lvl->prev->totvert + lvl->prev->totedge + i;
+ lvl->faces[curf].flag= lvl->prev->faces[i].flag;
+ lvl->faces[curf].mat_nr= lvl->prev->faces[i].mat_nr;
+
+ ++curf;
+ }
+ }
+
+ /* Create edges
+ ============ */
+ /* Figure out how many edges to allocate */
+ lvl->totedge= lvl->prev->totedge*2;
+ for(i=0; i<lvl->prev->totface; ++i)
+ lvl->totedge+= lvl->prev->faces[i].v[3]?4:3;
+ lvl->edges= MEM_callocN(sizeof(MultiresEdge)*lvl->totedge,"multires edges");
+
+ for(i=0; i<lvl->prev->totedge; ++i) {
+ lvl->edges[i*2].v[0]= lvl->prev->edges[i].v[0];
+ lvl->edges[i*2].v[1]= lvl->prev->edges[i].mid;
+ lvl->edges[i*2+1].v[0]= lvl->prev->edges[i].mid;
+ lvl->edges[i*2+1].v[1]= lvl->prev->edges[i].v[1];
+ }
+ /* Add edges inside of old polygons */
+ curf= 0;
+ cure= lvl->prev->totedge*2;
+ for(i=0; i<lvl->prev->totface; ++i) {
+ for(j=0; j<(lvl->prev->faces[i].v[3]?4:3); ++j) {
+ lvl->edges[cure].v[0]= lvl->faces[curf].v[2];
+ lvl->edges[cure].v[1]= lvl->faces[curf].v[3];
+ ++cure;
+ ++curf;
+ }
+ }
+
+ /* Smooth vertices
+ =============== */
+ for(i=0; i<lvl->prev->totface; ++i) {
+ const MultiresFace *f= &lvl->prev->faces[i];
+ data.corner1= oldverts[f->v[0]].co;
+ data.corner2= oldverts[f->v[1]].co;
+ data.corner3= oldverts[f->v[2]].co;
+ data.corner4= oldverts[f->v[3]].co;
+ data.quad= f->v[3] ? 1 : 0;
+ multi_apply(me->mr->verts[f->mid].co, &data, 3, catmullclark_smooth_face);
+ }
+
+ if(G.scene->toolsettings->multires_subdiv_type == 0) {
+ for(i=0; i<lvl->prev->totedge; ++i) {
+ const MultiresEdge *e= &lvl->prev->edges[i];
+ data.boundary= lvl->prev->edge_boundary_states[i];
+ edge_face_neighbor_midpoints_accum(&data,lvl->prev, me->mr->verts, sizeof(MVert),e);
+ data.endpoint1= oldverts[e->v[0]].co;
+ data.endpoint2= oldverts[e->v[1]].co;
+ multi_apply(me->mr->verts[e->mid].co, &data, 3, catmullclark_smooth_edge);
+ }
+
+ for(i=0; i<lvl->prev->totvert; ++i) {
+ data.boundary= multires_vert_is_boundary(lvl->prev,i);
+ data.original= oldverts[i].co;
+ data.edge_count= BLI_countlist(&lvl->prev->vert_edge_map[i]);
+ if(data.boundary)
+ boundary_edges_average(&data,lvl->prev, oldverts, sizeof(MVert),i);
+ else {
+ vert_face_neighbor_midpoints_average(&data,lvl->prev, me->mr->verts,
+ sizeof(MVert),i);
+ vert_edge_neighbor_midpoints_average(&data,lvl->prev, oldverts,
+ sizeof(MVert),i);
+ }
+ multi_apply(me->mr->verts[i].co, &data, 3, catmullclark_smooth_vert);
+ }
+ }
+
+ multires_free_temp_data(lvl->prev);
+ MEM_freeN(oldverts);
+
+ /* Vertex Colors
+ ============= */
+ curf= 0;
+ if(me->mr->use_col) {
+ MultiresColFace *cf= MEM_callocN(sizeof(MultiresColFace)*lvl->totface,"Multirescolfaces");
+ lvl->colfaces= cf;
+ for(i=0; i<lvl->prev->totface; ++i) {
+ const char sides= lvl->prev->faces[i].v[3]?4:3;
+ MultiresCol cntr;
+
+ /* Find average color of 4 (or 3 for triangle) verts */
+ multires_col_avg(&cntr,lvl->prev->colfaces[i].col,sides);
+
+ for(j=0; j<sides; ++j) {
+ multires_col_avg2(&cf->col[0],
+ &lvl->prev->colfaces[i].col[j],
+ &lvl->prev->colfaces[i].col[j==0?sides-1:j-1]);
+ cf->col[1]= lvl->prev->colfaces[i].col[j];
+ multires_col_avg2(&cf->col[2],
+ &lvl->prev->colfaces[i].col[j],
+ &lvl->prev->colfaces[i].col[j==sides-1?0:j+1]);
+ cf->col[3]= cntr;
+
+ ++cf;
+ }
+ }
+ }
+
+ me->mr->newlvl= me->mr->level_count;
+ me->mr->current= me->mr->newlvl;
+ /* Unless the render level has been set to something other than the
+ highest level (by the user), increment the render level to match
+ the highest available level */
+ if(me->mr->renderlvl == me->mr->level_count - 1) me->mr->renderlvl= me->mr->level_count;
+
+ multires_level_to_mesh(ob, me, 0);
+
+ allqueue(REDRAWBUTSEDIT, 0);
+
+ BIF_undo_push("Add multires level");
+
+ waitcursor(0);
+}
+
+void multires_set_level_cb(void *ob, void *me)
+{
+ multires_set_level(ob, me, 0);
+}
+
+void multires_set_level(struct Object *ob, struct Mesh *me, const int render)
+{
+ waitcursor(1);
+
+ multires_check_state();
+
+ if(me->pv) sculptmode_pmv_off(me);
+
+ check_colors(me);
+ multires_update_levels(me, render);
+
+ me->mr->current= me->mr->newlvl;
+ if(me->mr->current<1) me->mr->current= 1;
+ else if(me->mr->current>me->mr->level_count) me->mr->current= me->mr->level_count;
+
+ multires_level_to_mesh(ob, me, render);
+
+ if(!render && (G.obedit || G.f & G_SCULPTMODE))
+ BIF_undo_push("Multires set level");
+
+ allqueue(REDRAWBUTSEDIT, 0);
+
+ waitcursor(0);
+}
+
+
+void medge_flag_to_eed(const short flag, const char crease, EditEdge *eed)
+{
+ if(!eed) return;
+
+ if(flag & ME_SEAM) eed->seam= 1;
+ if(flag & ME_SHARP) eed->sharp = 1;
+ if(flag & SELECT) eed->f |= SELECT;
+ if(flag & ME_FGON) eed->h= EM_FGON;
+ if(flag & ME_HIDE) eed->h |= 1;
+
+ eed->crease= ((float)crease)/255.0;
+}
+
+/* note, function is called in background render too, without UI */
+void multires_level_to_mesh(Object *ob, Mesh *me, const int render)
+{
+ MultiresLevel *lvl= BLI_findlink(&me->mr->levels,me->mr->current-1);
+ int i;
+ EditMesh *em= (!render && G.obedit) ? G.editMesh : NULL;
+ EditVert **eves= NULL;
+ EditEdge *eed= NULL;
+
+ if(em) {
+ /* Remove editmesh elements */
+ free_editMesh(em);
+
+ eves= MEM_callocN(sizeof(EditVert*)*lvl->totvert, "editvert pointers");
+ } else {
+ CustomData_free_layer_active(&me->vdata, CD_MVERT, me->totvert);
+ CustomData_free_layer_active(&me->edata, CD_MEDGE, me->totedge);
+ CustomData_free_layer_active(&me->fdata, CD_MFACE, me->totface);
+ CustomData_free_layer_active(&me->vdata, CD_MDEFORMVERT, me->totvert);
+ CustomData_free_layers(&me->fdata, CD_MTFACE, me->totface);
+ CustomData_free_layers(&me->fdata, CD_MCOL, me->totface);
+
+ me->totvert= lvl->totvert;
+ me->totface= lvl->totface;
+ me->totedge= lvl->totedge;
+
+ CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, me->totvert);
+ CustomData_add_layer(&me->edata, CD_MEDGE, CD_CALLOC, NULL, me->totedge);
+ CustomData_add_layer(&me->fdata, CD_MFACE, CD_CALLOC, NULL, me->totface);
+ mesh_update_customdata_pointers(me);
+ }
+
+ /* Vertices/Edges/Faces */
+
+ for(i=0; i<lvl->totvert; ++i) {
+ if(em) {
+ eves[i]= addvertlist(me->mr->verts[i].co, NULL);
+ if(me->mr->verts[i].flag & 1) eves[i]->f |= SELECT;
+ if(me->mr->verts[i].flag & ME_HIDE) eves[i]->h= 1;
+ eves[i]->data= NULL;
+ }
+ else
+ me->mvert[i]= me->mr->verts[i];
+ }
+ for(i=0; i<lvl->totedge; ++i) {
+ if(em) {
+ addedgelist(eves[lvl->edges[i].v[0]], eves[lvl->edges[i].v[1]], NULL);
+ } else {
+ me->medge[i].v1= lvl->edges[i].v[0];
+ me->medge[i].v2= lvl->edges[i].v[1];
+ me->medge[i].flag &= ~ME_HIDE;
+ }
+ }
+ for(i=0; i<lvl->totface; ++i) {
+ if(em) {
+ EditVert *eve4= lvl->faces[i].v[3] ? eves[lvl->faces[i].v[3]] : NULL;
+ EditFace *efa= addfacelist(eves[lvl->faces[i].v[0]], eves[lvl->faces[i].v[1]],
+ eves[lvl->faces[i].v[2]], eve4, NULL, NULL);
+ efa->flag= lvl->faces[i].flag & ~ME_HIDE;
+ efa->mat_nr= lvl->faces[i].mat_nr;
+ if(lvl->faces[i].flag & ME_FACE_SEL)
+ efa->f |= SELECT;
+ if(lvl->faces[i].flag & ME_HIDE) efa->h= 1;
+ efa->data= NULL;
+ }
+ else {
+ me->mface[i].v1= lvl->faces[i].v[0];
+ me->mface[i].v2= lvl->faces[i].v[1];
+ me->mface[i].v3= lvl->faces[i].v[2];
+ me->mface[i].v4= lvl->faces[i].v[3];
+ me->mface[i].flag= lvl->faces[i].flag;
+ me->mface[i].flag &= ~ME_HIDE;
+ me->mface[i].mat_nr= lvl->faces[i].mat_nr;
+ }
+ }
+
+ /* Edge flags */
+ if(em) eed= em->edges.first;
+ if(lvl==me->mr->levels.first) {
+ for(i=0; i<lvl->totedge; ++i) {
+ if(em) {
+ medge_flag_to_eed(me->mr->edge_flags[i], me->mr->edge_creases[i], eed);
+ eed= eed->next;
+ }
+ else {
+ me->medge[i].flag= me->mr->edge_flags[i];
+ me->medge[i].crease= me->mr->edge_creases[i];
+ }
+ }
+ } else {
+ MultiresLevel *lvl1= me->mr->levels.first;
+ const int last= lvl1->totedge * pow(2, me->mr->current-1);
+ for(i=0; i<last; ++i) {
+ const int ndx= i / pow(2, me->mr->current-1);
+
+ if(em) {
+ medge_flag_to_eed(me->mr->edge_flags[ndx], me->mr->edge_creases[ndx], eed);
+ eed= eed->next;
+ }
+ else {
+ me->medge[i].flag= me->mr->edge_flags[ndx];
+ me->medge[i].crease= me->mr->edge_creases[ndx];
+ }
+ }
+ }
+
+ if(em) {
+ eed= em->edges.first;
+ for(i=0, eed= em->edges.first; i<lvl->totedge; ++i, eed= eed->next) {
+ eed->h= me->mr->verts[lvl->edges[i].v[0]].flag & ME_HIDE ||
+ me->mr->verts[lvl->edges[i].v[1]].flag & ME_HIDE;
+ }
+ }
+
+ EM_select_flush();
+
+ multires_customdata_to_mesh(me, em, lvl, &me->mr->vdata, em ? &em->vdata : &me->vdata, CD_MDEFORMVERT);
+ multires_customdata_to_mesh(me, em, lvl, &me->mr->fdata, em ? &em->fdata : &me->fdata, CD_MTFACE);
+
+ /* Colors */
+ if(me->mr->use_col) {
+ MCol c[4];
+ EditFace *efa= NULL;
+ CustomData *src= em ? &em->fdata : &me->fdata;
+ if(em) {
+ if(me->mr->use_col) EM_add_data_layer(src, CD_MCOL);
+ efa= em->faces.first;
+ }
+ else {
+ if(me->mr->use_col) me->mcol= CustomData_add_layer(src, CD_MCOL, CD_CALLOC, NULL, me->totface);
+ }
+
+ for(i=0; i<lvl->totface; ++i) {
+ if(em) {
+ if(me->mr->use_col) {
+ multires_to_mcol(&lvl->colfaces[i], c);
+ CustomData_em_set(src, efa->data, CD_MCOL, c);
+ }
+ efa= efa->next;
+ }
+ else if(me->mr->use_col) multires_to_mcol(&lvl->colfaces[i], &me->mcol[i*4]);
+ }
+
+ }
+
+ mesh_update_customdata_pointers(me);
+
+ if(em) {
+ MEM_freeN(eves);
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ recalc_editnormals();
+ } else {
+ multires_edge_level_update(ob,me);
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
+ }
+
+ /* friendly check for background render */
+ if(G.background==0) {
+ object_handle_update(ob);
+ countall();
+
+ if(G.vd && G.vd->depths) G.vd->depths->damaged= 1;
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWIMAGE, 0);
+ }
+}
+
+void multires_update_colors(Mesh *me)
+{
+ MultiresLevel *lvl= BLI_findlink(&me->mr->levels,me->mr->current-1);
+ MultiresCol *pr_deltas= NULL, *cr_deltas= NULL;
+ EditMesh *em= G.obedit ? G.editMesh : NULL;
+ CustomData *src= em ? &em->fdata : &me->fdata;
+ EditFace *efa= NULL;
+ unsigned i,j,curf= 0;
+
+ if(me->mr->use_col) {
+ /* Calc initial deltas */
+ cr_deltas= MEM_callocN(sizeof(MultiresCol)*lvl->totface*4,"initial color/uv deltas");
+
+ if(em) efa= em->faces.first;
+ for(i=0; i<lvl->totface; ++i) {
+ MCol *col= em ? CustomData_em_get(src, efa->data, CD_MCOL) : &me->mcol[i*4];
+ for(j=0; j<4; ++j) {
+ if(me->mr->use_col) {
+ cr_deltas[i*4+j].a= col[j].a - lvl->colfaces[i].col[j].a;
+ cr_deltas[i*4+j].r= col[j].r - lvl->colfaces[i].col[j].r;
+ cr_deltas[i*4+j].g= col[j].g - lvl->colfaces[i].col[j].g;
+ cr_deltas[i*4+j].b= col[j].b - lvl->colfaces[i].col[j].b;
+ }
+ }
+ if(em) efa= efa->next;
+ }
+
+ /* Update current level */
+ if(em) efa= em->faces.first;
+ for(i=0; i<lvl->totface; ++i) {
+ MultiresColFace *f= &lvl->colfaces[i];
+
+ if(me->mr->use_col)
+ mcol_to_multires(f, em ? CustomData_em_get(src, efa->data, CD_MCOL) : &me->mcol[i*4]);
+
+ if(em) efa= efa->next;
+ }
+
+ /* Update higher levels */
+ lvl= lvl->next;
+ while(lvl) {
+ /* Set up new deltas, but keep the ones from the previous level */
+ if(pr_deltas) MEM_freeN(pr_deltas);
+ pr_deltas= cr_deltas;
+ cr_deltas= MEM_callocN(sizeof(MultiresCol)*lvl->totface*4,"color deltas");
+
+ curf= 0;
+ for(i=0; i<lvl->prev->totface; ++i) {
+ const char sides= lvl->prev->faces[i].v[3]?4:3;
+ MultiresCol cntr;
+
+ /* Find average color of 4 (or 3 for triangle) verts */
+ multires_col_avg(&cntr,&pr_deltas[i*4],sides);
+
+ for(j=0; j<sides; ++j) {
+ multires_col_avg2(&cr_deltas[curf*4],
+ &pr_deltas[i*4+j],
+ &pr_deltas[i*4+(j==0?sides-1:j-1)]);
+ cr_deltas[curf*4+1]= pr_deltas[i*4+j];
+ multires_col_avg2(&cr_deltas[curf*4+2],
+ &pr_deltas[i*4+j],
+ &pr_deltas[i*4+(j==sides-1?0:j+1)]);
+ cr_deltas[curf*4+3]= cntr;
+ ++curf;
+ }
+ }
+
+ for(i=0; i<lvl->totface; ++i) {
+ for(j=0; j<4; ++j) {
+ lvl->colfaces[i].col[j].a+= cr_deltas[i*4+j].a;
+ lvl->colfaces[i].col[j].r+= cr_deltas[i*4+j].r;
+ lvl->colfaces[i].col[j].g+= cr_deltas[i*4+j].g;
+ lvl->colfaces[i].col[j].b+= cr_deltas[i*4+j].b;
+ }
+ }
+
+ lvl= lvl->next;
+ }
+ if(pr_deltas) MEM_freeN(pr_deltas);
+ if(cr_deltas) MEM_freeN(cr_deltas);
+
+ /* Update lower levels */
+ lvl= me->mr->levels.last;
+ lvl= lvl->prev;
+ while(lvl) {
+ MultiresColFace *nf= lvl->next->colfaces;
+ for(i=0; i<lvl->totface; ++i) {
+ MultiresFace *f= &lvl->faces[i];
+ for(j=0; j<(f->v[3]?4:3); ++j) {
+ lvl->colfaces[i].col[j]= nf->col[1];
+ ++nf;
+ }
+ }
+ lvl= lvl->prev;
+ }
+ }
+}
+
+/* Update vertex locations and vertex flags */
+void multires_update_vertices(Mesh *me, EditMesh *em)
+{
+ MultiresLevel *cr_lvl= current_level(me->mr), *pr_lvl= NULL,
+ *last_lvl= me->mr->levels.last;
+ vec3f *pr_deltas= NULL, *cr_deltas= NULL, *swap_deltas= NULL;
+ EditVert *eve= NULL;
+ MultiApplyData data;
+ int i, j;
+
+ /* Prepare deltas */
+ pr_deltas= MEM_callocN(sizeof(vec3f)*last_lvl->totvert, "multires deltas 1");
+ cr_deltas= MEM_callocN(sizeof(vec3f)*last_lvl->totvert, "multires deltas 2");
+
+ /* Calculate initial deltas -- current mesh subtracted from current level*/
+ if(em) eve= em->verts.first;
+ for(i=0; i<cr_lvl->totvert; ++i) {
+ if(em) {
+ VecSubf(&cr_deltas[i].x, eve->co, me->mr->verts[i].co);
+ eve= eve->next;
+ } else
+ VecSubf(&cr_deltas[i].x, me->mvert[i].co, me->mr->verts[i].co);
+ }
+
+
+ /* Copy current level's vertex flags and clear the rest */
+ if(em) eve= em->verts.first;
+ for(i=0; i < last_lvl->totvert; ++i) {
+ if(i < cr_lvl->totvert) {
+ MVert mvflag;
+ multires_get_vert(&mvflag, eve, &me->mvert[i], i);
+ if(em) eve= eve->next;
+ me->mr->verts[i].flag= mvflag.flag;
+ }
+ else
+ me->mr->verts[i].flag= 0;
+ }
+
+ /* If already on the highest level, copy current verts (including flags) into current level */
+ if(cr_lvl == last_lvl) {
+ if(em)
+ eve= em->verts.first;
+ for(i=0; i<cr_lvl->totvert; ++i) {
+ multires_get_vert(&me->mr->verts[i], eve, &me->mvert[i], i);
+ if(em) eve= eve->next;
+ }
+ }
+
+ /* Update higher levels */
+ pr_lvl= BLI_findlink(&me->mr->levels,me->mr->current-1);
+ cr_lvl= pr_lvl->next;
+ while(cr_lvl) {
+ multires_calc_temp_data(pr_lvl);
+
+ /* Swap the old/new deltas */
+ swap_deltas= pr_deltas;
+ pr_deltas= cr_deltas;
+ cr_deltas= swap_deltas;
+
+ /* Calculate and add new deltas
+ ============================ */
+ for(i=0; i<pr_lvl->totface; ++i) {
+ const MultiresFace *f= &pr_lvl->faces[i];
+ data.corner1= &pr_deltas[f->v[0]].x;
+ data.corner2= &pr_deltas[f->v[1]].x;
+ data.corner3= &pr_deltas[f->v[2]].x;
+ data.corner4= &pr_deltas[f->v[3]].x;
+ data.quad= f->v[3] ? 1 : 0;
+ multi_apply(&cr_deltas[f->mid].x, &data, 3, catmullclark_smooth_face);
+
+ for(j=0; j<(data.quad?4:3); ++j)
+ me->mr->verts[f->mid].flag |= me->mr->verts[f->v[j]].flag;
+ }
+
+ for(i=0; i<pr_lvl->totedge; ++i) {
+ const MultiresEdge *e= &pr_lvl->edges[i];
+ data.boundary= pr_lvl->edge_boundary_states[i];
+ edge_face_neighbor_midpoints_accum(&data,pr_lvl,cr_deltas,sizeof(vec3f),e);
+ data.endpoint1= &pr_deltas[e->v[0]].x;
+ data.endpoint2= &pr_deltas[e->v[1]].x;
+ multi_apply(&cr_deltas[e->mid].x, &data, 3, catmullclark_smooth_edge);
+
+ for(j=0; j<2; ++j)
+ me->mr->verts[e->mid].flag |= me->mr->verts[e->v[j]].flag;
+ }
+
+ for(i=0; i<pr_lvl->totvert; ++i) {
+ data.boundary= multires_vert_is_boundary(pr_lvl,i);
+ data.original= &pr_deltas[i].x;
+ data.edge_count= BLI_countlist(&pr_lvl->vert_edge_map[i]);
+ if(data.boundary)
+ boundary_edges_average(&data,pr_lvl,pr_deltas,sizeof(vec3f),i);
+ else {
+ vert_face_neighbor_midpoints_average(&data,pr_lvl,cr_deltas,sizeof(vec3f),i);
+ vert_edge_neighbor_midpoints_average(&data,pr_lvl,pr_deltas,sizeof(vec3f),i);
+ }
+ multi_apply(&cr_deltas[i].x, &data, 3, catmullclark_smooth_vert);
+ }
+
+ /* Apply deltas to vertex locations */
+ for(i=0; (cr_lvl == last_lvl) && (i < cr_lvl->totvert); ++i) {
+ VecAddf(me->mr->verts[i].co,
+ me->mr->verts[i].co,
+ &cr_deltas[i].x);
+ }
+
+ multires_free_temp_data(pr_lvl);
+
+ pr_lvl= pr_lvl->next;
+ cr_lvl= cr_lvl->next;
+ }
+ if(pr_deltas) MEM_freeN(pr_deltas);
+ if(cr_deltas) MEM_freeN(cr_deltas);
+
+}
+
+void multires_update_faces(Mesh *me, EditMesh *em)
+{
+ MultiresLevel *cr_lvl= current_level(me->mr), *pr_lvl= NULL,
+ *last_lvl= me->mr->levels.last;
+ char *pr_flag_damaged= NULL, *cr_flag_damaged= NULL, *or_flag_damaged= NULL,
+ *pr_mat_damaged= NULL, *cr_mat_damaged= NULL, *or_mat_damaged= NULL, *swap= NULL;
+ EditFace *efa= NULL;
+ unsigned i,j,curf;
+
+ /* Find for each face whether flag/mat has changed */
+ pr_flag_damaged= MEM_callocN(sizeof(char) * last_lvl->totface, "flag_damaged 1");
+ cr_flag_damaged= MEM_callocN(sizeof(char) * last_lvl->totface, "flag_damaged 1");
+ pr_mat_damaged= MEM_callocN(sizeof(char) * last_lvl->totface, "mat_damaged 1");
+ cr_mat_damaged= MEM_callocN(sizeof(char) * last_lvl->totface, "mat_damaged 1");
+ if(em) efa= em->faces.first;
+ for(i=0; i<cr_lvl->totface; ++i) {
+ MultiresFace mftmp;
+ multires_get_face(&mftmp, efa, &me->mface[i]);
+ if(cr_lvl->faces[i].flag != mftmp.flag)
+ cr_flag_damaged[i]= 1;
+ if(cr_lvl->faces[i].mat_nr != mftmp.mat_nr)
+ cr_mat_damaged[i]= 1;
+
+ /* Update current level */
+ cr_lvl->faces[i].flag= mftmp.flag;
+ cr_lvl->faces[i].mat_nr= mftmp.mat_nr;
+
+ if(em) efa= efa->next;
+ }
+ or_flag_damaged= MEM_dupallocN(cr_flag_damaged);
+ or_mat_damaged= MEM_dupallocN(cr_mat_damaged);
+
+ /* Update lower levels */
+ cr_lvl= cr_lvl->prev;
+ while(cr_lvl) {
+ swap= pr_flag_damaged;
+ pr_flag_damaged= cr_flag_damaged;
+ cr_flag_damaged= swap;
+
+ swap= pr_mat_damaged;
+ pr_mat_damaged= cr_mat_damaged;
+ cr_mat_damaged= swap;
+
+ curf= 0;
+ for(i=0; i<cr_lvl->totface; ++i) {
+ const int sides= cr_lvl->faces[i].v[3] ? 4 : 3;
+
+ /* Check damages */
+ for(j=0; j<sides; ++j, ++curf) {
+ if(pr_flag_damaged[curf]) {
+ cr_lvl->faces[i].flag= cr_lvl->next->faces[curf].flag;
+ cr_flag_damaged[i]= 1;
+ }
+ if(pr_mat_damaged[curf]) {
+ cr_lvl->faces[i].mat_nr= cr_lvl->next->faces[curf].mat_nr;
+ cr_mat_damaged[i]= 1;
+ }
+ }
+ }
+
+ cr_lvl= cr_lvl->prev;
+ }
+
+ /* Clear to original damages */
+ if(cr_flag_damaged) MEM_freeN(cr_flag_damaged);
+ if(cr_mat_damaged) MEM_freeN(cr_mat_damaged);
+ cr_flag_damaged= or_flag_damaged;
+ cr_mat_damaged= or_mat_damaged;
+
+ /* Update higher levels */
+ pr_lvl= current_level(me->mr);
+ cr_lvl= pr_lvl->next;
+ while(cr_lvl) {
+ swap= pr_flag_damaged;
+ pr_flag_damaged= cr_flag_damaged;
+ cr_flag_damaged= swap;
+
+ swap= pr_mat_damaged;
+ pr_mat_damaged= cr_mat_damaged;
+ cr_mat_damaged= swap;
+
+ /* Update faces */
+ for(i=0, curf= 0; i<pr_lvl->totface; ++i) {
+ const int sides= cr_lvl->prev->faces[i].v[3] ? 4 : 3;
+ for(j=0; j<sides; ++j, ++curf) {
+ if(pr_flag_damaged[i]) {
+ cr_lvl->faces[curf].flag= pr_lvl->faces[i].flag;
+ cr_flag_damaged[curf]= 1;
+ }
+ if(pr_mat_damaged[i]) {
+ cr_lvl->faces[curf].mat_nr= pr_lvl->faces[i].mat_nr;
+ cr_mat_damaged[curf]= 1;
+ }
+ }
+ }
+
+ pr_lvl= pr_lvl->next;
+ cr_lvl= cr_lvl->next;
+ }
+
+ if(pr_flag_damaged) MEM_freeN(pr_flag_damaged);
+ if(cr_flag_damaged) MEM_freeN(cr_flag_damaged);
+ if(pr_mat_damaged) MEM_freeN(pr_mat_damaged);
+ if(cr_mat_damaged) MEM_freeN(cr_mat_damaged);
+}
+
+void multires_update_levels(Mesh *me, const int render)
+{
+ EditMesh *em= (!render && G.obedit) ? G.editMesh : NULL;
+
+ multires_update_first_level(me, em);
+ multires_update_vertices(me, em);
+ multires_update_faces(me, em);
+ multires_update_colors(me);
+}
+
+void multires_calc_temp_data(MultiresLevel *lvl)
+{
+ unsigned i, j, emax;
+ MultiresMapNode *indexnode= NULL;
+
+ lvl->map_mem= MEM_mallocN(sizeof(MultiresMapNode)*(lvl->totedge*2 + lvl->totface*4), "map_mem");
+ indexnode= lvl->map_mem;
+
+ /* edge map */
+ lvl->vert_edge_map= MEM_callocN(sizeof(ListBase)*lvl->totvert,"vert_edge_map");
+ for(i=0; i<lvl->totedge; ++i) {
+ for(j=0; j<2; ++j, ++indexnode) {
+ indexnode->Index= i;
+ BLI_addtail(&lvl->vert_edge_map[lvl->edges[i].v[j]], indexnode);
+ }
+ }
+
+ /* face map */
+ lvl->vert_face_map= MEM_callocN(sizeof(ListBase)*lvl->totvert,"vert_face_map");
+ for(i=0; i<lvl->totface; ++i){
+ for(j=0; j<(lvl->faces[i].v[3]?4:3); ++j, ++indexnode) {
+ indexnode->Index= i;
+ BLI_addtail(&lvl->vert_face_map[lvl->faces[i].v[j]], indexnode);
+ }
+ }
+
+ /* edge boundaries */
+ emax = (lvl->prev ? (lvl->prev->totedge * 2) : lvl->totedge);
+ lvl->edge_boundary_states= MEM_callocN(sizeof(char)*lvl->totedge, "edge_boundary_states");
+ for(i=0; i<emax; ++i) {
+ MultiresMapNode *n1= lvl->vert_face_map[lvl->edges[i].v[0]].first;
+ unsigned total= 0;
+
+ lvl->edge_boundary_states[i] = 1;
+ while(n1 && lvl->edge_boundary_states[i] == 1) {
+ MultiresMapNode *n2= lvl->vert_face_map[lvl->edges[i].v[1]].first;
+ while(n2) {
+ if(n1->Index == n2->Index) {
+ ++total;
+
+ if(total > 1) {
+ lvl->edge_boundary_states[i] = 0;
+ break;
+ }
+ }
+
+ n2= n2->next;
+ }
+ n1= n1->next;
+ }
+ }
+}
+
+void multires_edge_level_update(void *ob, void *me_v)
+{
+ if(!G.obedit) {
+ Mesh *me= me_v;
+ MultiresLevel *cr_lvl= BLI_findlink(&me->mr->levels,me->mr->current-1);
+ MultiresLevel *edge_lvl= BLI_findlink(&me->mr->levels,me->mr->edgelvl-1);
+ const int threshold= edge_lvl->totedge * powf(2, me->mr->current - me->mr->edgelvl);
+ unsigned i;
+
+ for(i=0; i<cr_lvl->totedge; ++i) {
+ const int ndx= me->pv ? me->pv->edge_map[i] : i;
+ if(ndx != -1) { /* -1= hidden edge */
+ if(me->mr->edgelvl >= me->mr->current || i<threshold)
+ me->medge[ndx].flag |= ME_EDGEDRAW | ME_EDGERENDER;
+ else
+ me->medge[ndx].flag &= ~ME_EDGEDRAW & ~ME_EDGERENDER;
+ }
+ }
+
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+}
+
+int multires_modifier_warning()
+{
+ ModifierData *md;
+
+ for(md= modifiers_getVirtualModifierList(OBACT); md; md= md->next) {
+ if(md->mode & eModifierMode_Render) {
+ switch(md->type) {
+ case eModifierType_Subsurf:
+ case eModifierType_Build:
+ case eModifierType_Mirror:
+ case eModifierType_Decimate:
+ case eModifierType_Boolean:
+ case eModifierType_Array:
+ case eModifierType_EdgeSplit:
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/source/blender/src/mywindow.c b/source/blender/src/mywindow.c
new file mode 100644
index 00000000000..56ef28d3a6e
--- /dev/null
+++ b/source/blender/src/mywindow.c
@@ -0,0 +1,744 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ *
+ *
+ * for compatibility with old iris code, replacement of swinopen, winset, etc
+ * btw: subwindows in X are way too slow, tried it, and choose for my own system... (ton)
+ *
+ */
+
+#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_gsqueue.h"
+
+#include "DNA_screen_types.h"
+
+#include "BKE_global.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+#include "BIF_mywindow.h"
+#include "BIF_screen.h"
+
+#include "mydevice.h"
+#include "blendef.h"
+
+#include "winlay.h"
+
+typedef struct {
+ struct bWindow *next, *prev;
+ int id, pad;
+
+ int xmin, xmax, ymin, ymax;
+ float viewmat[4][4], winmat[4][4];
+
+ GSQueue *qevents;
+} bWindow;
+
+/* globals */
+static Window *winlay_mainwindow;
+static int curswin=0;
+static bWindow *swinarray[MAXWIN]= {NULL};
+static bWindow mainwindow, renderwindow;
+static int mainwin_color_depth;
+
+/* prototypes --------------- */
+void mywindow_init_mainwin(Window *, int , int , int , int );
+void mywindow_build_and_set_renderwin( int , int , int , int);
+
+void mywindow_init_mainwin(Window *win, int orx, int ory, int sizex, int sizey)
+{
+ GLint r, g, b;
+
+ winlay_mainwindow= win;
+
+ swinarray[1]= &mainwindow;
+ curswin= 1;
+
+ mainwindow.xmin= orx;
+ mainwindow.ymin= ory;
+ mainwindow.xmax= orx+sizex-1;
+ mainwindow.ymax= ory+sizey-1;
+ mainwindow.qevents= NULL;
+
+ myortho2(-0.375, (float)sizex-0.375, -0.375, (float)sizey-0.375);
+ glLoadIdentity();
+
+ glGetFloatv(GL_PROJECTION_MATRIX, (float *)mainwindow.winmat);
+ glGetFloatv(GL_MODELVIEW_MATRIX, (float *)mainwindow.viewmat);
+
+ glGetIntegerv(GL_RED_BITS, &r);
+ glGetIntegerv(GL_GREEN_BITS, &g);
+ glGetIntegerv(GL_BLUE_BITS, &b);
+
+ mainwin_color_depth= r + g + b;
+ if(G.f & G_DEBUG) {
+ printf("Color depth r %d g %d b %d\n", (int)r, (int)g, (int)b);
+ glGetIntegerv(GL_AUX_BUFFERS, &r);
+ printf("Aux buffers: %d\n", (int)r);
+ }
+}
+
+/* XXXXXXXXXXXXXXXX very hacky, because of blenderwindows vs ghostwindows vs renderwindow
+ this routine sets up a blenderwin (a mywin)
+ */
+void mywindow_build_and_set_renderwin( int orx, int ory, int sizex, int sizey)
+{
+
+ swinarray[2]= &renderwindow;
+ curswin= 2; /* myortho2 needs this to be set */
+
+ renderwindow.xmin= orx;
+ renderwindow.ymin= ory;
+ renderwindow.xmax= orx+sizex-1;
+ renderwindow.ymax= ory+sizey-1;
+ renderwindow.qevents= NULL;
+
+ myortho2(-0.375, (float)sizex-0.375, -0.375, (float)sizey-0.375);
+ glLoadIdentity();
+
+ glGetFloatv(GL_PROJECTION_MATRIX, (float *)renderwindow.winmat);
+ glGetFloatv(GL_MODELVIEW_MATRIX, (float *)renderwindow.viewmat);
+ mywinset(2);
+
+}
+
+/* ------------------------------------------------------------------------- */
+
+ /* XXXXX, remove later */
+static bWindow *bwin_from_winid(int winid)
+{
+ bWindow *bwin= swinarray[winid];
+ if (!bwin) {
+ printf("bwin_from_winid: Internal error, bad winid: %d\n", winid);
+ }
+ return bwin;
+}
+
+int bwin_qtest(int winid)
+{
+ return !BLI_gsqueue_is_empty(bwin_from_winid(winid)->qevents);
+}
+int bwin_qread(int winid, BWinEvent *evt_r)
+{
+ if (bwin_qtest(winid)) {
+ BLI_gsqueue_pop(bwin_from_winid(winid)->qevents, evt_r);
+ return 1;
+ } else {
+ return 0;
+ }
+}
+void bwin_qadd(int winid, BWinEvent *evt)
+{
+ BLI_gsqueue_push(bwin_from_winid(winid)->qevents, evt);
+}
+
+/* ------------------------------------------------------------------------- */
+
+void bwin_get_rect(int winid, rcti *rect_r)
+{
+ bWindow *win= bwin_from_winid(winid);
+ if(win) {
+ rect_r->xmin= win->xmin;
+ rect_r->ymin= win->ymin;
+ rect_r->xmax= win->xmax;
+ rect_r->ymax= win->ymax;
+ }
+}
+
+void bwin_getsize(int win, int *x, int *y)
+{
+ if(win<4) {
+ if (win==1) {
+ window_get_size(winlay_mainwindow, x, y);
+ } else {
+ printf("bwin_getsize: Internal error, bad winid: %d\n", win);
+ *x= *y= 0;
+ }
+ } else {
+ bWindow *bwin= swinarray[win];
+ if (bwin) {
+ *x= bwin->xmax-bwin->xmin+1;
+ *y= bwin->ymax-bwin->ymin+1;
+ }
+ }
+}
+
+void bwin_getsuborigin(int win, int *x, int *y)
+{
+ if(win<4) {
+ *x= *y= 0;
+ } else {
+ bWindow *bwin= swinarray[win];
+ if (bwin) {
+ *x= bwin->xmin;
+ *y= bwin->ymin;
+ }
+ }
+}
+
+void bwin_getsinglematrix(int winid, float mat[][4])
+{
+ bWindow *win;
+ float matview[4][4], matproj[4][4];
+
+ win= swinarray[winid];
+ if(win==NULL) {
+ glGetFloatv(GL_PROJECTION_MATRIX, (float *)matproj);
+ glGetFloatv(GL_MODELVIEW_MATRIX, (float *)matview);
+ Mat4MulMat4(mat, matview, matproj);
+ }
+ else {
+ Mat4MulMat4(mat, win->viewmat, win->winmat);
+ }
+}
+
+/* ------------------------------------------------------------------------- */
+
+void bwin_load_viewmatrix(int winid, float mat[][4])
+{
+ bWindow *win= bwin_from_winid(winid);
+ if(win) {
+ glLoadMatrixf(mat);
+ Mat4CpyMat4(win->viewmat, mat);
+ }
+}
+void bwin_load_winmatrix(int winid, float mat[][4])
+{
+ bWindow *win= bwin_from_winid(winid);
+ if(win) {
+ glLoadMatrixf(mat);
+ Mat4CpyMat4(win->winmat, mat);
+ }
+}
+
+void bwin_get_viewmatrix(int winid, float mat[][4])
+{
+ bWindow *win= bwin_from_winid(winid);
+ if(win)
+ Mat4CpyMat4(mat, win->viewmat);
+}
+void bwin_get_winmatrix(int winid, float mat[][4])
+{
+ bWindow *win= bwin_from_winid(winid);
+ if(win)
+ Mat4CpyMat4(mat, win->winmat);
+}
+
+void bwin_multmatrix(int winid, float mat[][4])
+{
+ bWindow *win= bwin_from_winid(winid);
+
+ if(win) {
+ glMultMatrixf((float*) mat);
+ glGetFloatv(GL_MODELVIEW_MATRIX, (float *)win->viewmat);
+ }
+}
+
+void bwin_scalematrix(int winid, float x, float y, float z)
+{
+ bWindow *win= bwin_from_winid(winid);
+ if(win) {
+ glScalef(x, y, z);
+ glGetFloatv(GL_MODELVIEW_MATRIX, (float *)win->viewmat);
+ }
+}
+
+void bwin_clear_viewmat(int swin)
+{
+ bWindow *win;
+
+ win= swinarray[swin];
+ if(win==NULL) return;
+
+ memset(win->viewmat, 0, sizeof(win->viewmat));
+ win->viewmat[0][0]= 1.0;
+ win->viewmat[1][1]= 1.0;
+ win->viewmat[2][2]= 1.0;
+ win->viewmat[3][3]= 1.0;
+}
+
+
+void myloadmatrix(float mat[][4])
+{
+ if (glaGetOneInteger(GL_MATRIX_MODE)==GL_MODELVIEW) {
+ bwin_load_viewmatrix(curswin, mat);
+ } else {
+ bwin_load_winmatrix(curswin, mat);
+ }
+}
+
+void mygetmatrix(float mat[][4])
+{
+ if (glaGetOneInteger(GL_MATRIX_MODE)==GL_MODELVIEW) {
+ bwin_get_viewmatrix(curswin, mat);
+ } else {
+ bwin_get_winmatrix(curswin, mat);
+ }
+}
+
+void mymultmatrix(float mat[][4])
+{
+ bwin_multmatrix(curswin, mat);
+}
+
+void mygetsingmatrix(float mat[][4])
+{
+ bwin_getsinglematrix(curswin, mat);
+}
+
+int mywinget(void)
+{
+ return curswin;
+}
+
+void mywinset(int wid)
+{
+ bWindow *win;
+
+ win= swinarray[wid];
+ if(win==NULL) {
+ printf("mywinset %d: doesn't exist\n", wid);
+ return;
+ }
+ if (wid == 1 || wid == 2) { /* main window or renderwindow*/
+ glViewport(0, 0, ( win->xmax-win->xmin)+1, ( win->ymax-win->ymin)+1);
+ glScissor(0, 0, ( win->xmax-win->xmin)+1, ( win->ymax-win->ymin)+1);
+ }
+ else {
+ int width= (win->xmax - win->xmin)+1;
+ int height= (win->ymax - win->ymin)+1;
+
+ /* CRITICAL, this clamping ensures that
+ * the viewport never goes outside the screen
+ * edges (assuming the x, y coords aren't
+ * outside). This causes a hardware lock
+ * on Matrox cards if it happens.
+ *
+ * Really Blender should never _ever_ try
+ * to do such a thing, but just to be safe
+ * clamp it anyway (or fix the bScreen
+ * scaling routine, and be damn sure you
+ * fixed it). - zr
+ */
+ if (win->xmin + width>G.curscreen->sizex)
+ width= G.curscreen->sizex - win->xmin;
+ if (win->ymin + height>G.curscreen->sizey)
+ height= G.curscreen->sizey - win->ymin;
+
+ glViewport(win->xmin, win->ymin, width, height);
+ glScissor(win->xmin, win->ymin, width, height);
+ }
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadMatrixf(&win->winmat[0][0]);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadMatrixf(&win->viewmat[0][0]);
+
+ glFlush();
+
+ curswin= wid;
+}
+
+int myswinopen(int parentid, int xmin, int xmax, int ymin, int ymax)
+{
+ bWindow *win= NULL;
+ int freewinid;
+
+ for (freewinid= 4; freewinid<MAXWIN; freewinid++)
+ if (!swinarray[freewinid])
+ break;
+
+ /* this case is not handled in Blender, so will crash. use myswinopen_allowed() first to check */
+ if (freewinid==MAXWIN) {
+ printf("too many windows\n");
+
+ return 0;
+ }
+ else {
+ win= MEM_callocN(sizeof(*win), "winopen");
+
+ win->id= freewinid;
+ swinarray[win->id]= win;
+
+ win->xmin= xmin;
+ win->ymin= ymin;
+ win->xmax= xmax;
+ win->ymax= ymax;
+
+ win->qevents= BLI_gsqueue_new(sizeof(BWinEvent));
+
+ Mat4One(win->viewmat);
+ Mat4One(win->winmat);
+
+ mywinset(win->id);
+
+ return win->id;
+ }
+}
+
+int myswinopen_allowed(void)
+{
+ int totfree=0;
+ int freewinid;
+
+ for (freewinid= 4; freewinid<MAXWIN; freewinid++)
+ if (swinarray[freewinid]==NULL)
+ totfree++;
+ if(totfree<2)
+ return 0;
+ return 1;
+}
+
+void mywinclose(int winid)
+{
+ if (winid<4) {
+ if (winid==1) {
+ window_destroy(winlay_mainwindow);
+ winlay_mainwindow= NULL;
+ } else {
+ printf("mwinclose: Internal error, bad winid: %d\n", winid);
+ }
+ } else {
+ bWindow *win= swinarray[winid];
+
+ if (win) {
+ BLI_gsqueue_free(win->qevents);
+ MEM_freeN(win);
+ } else {
+ printf("mwinclose: Internal error, bad winid: %d\n", winid);
+ }
+ }
+
+ swinarray[winid]= NULL;
+ if (curswin==winid) curswin= 0;
+}
+
+void mywinposition(int winid, int xmin, int xmax, int ymin, int ymax) /* watch: syntax differs from iris */
+{
+ bWindow *win= bwin_from_winid(winid);
+ if(win) {
+ win->xmin= xmin;
+ win->ymin= ymin;
+ win->xmax= xmax;
+ win->ymax= ymax;
+ }
+}
+
+
+void bwin_ortho(int winid, float x1, float x2, float y1, float y2, float n, float f)
+{
+ bWindow *bwin= bwin_from_winid(winid);
+ if(bwin) {
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+
+ glOrtho(x1, x2, y1, y2, n, f);
+
+ glGetFloatv(GL_PROJECTION_MATRIX, (float *)bwin->winmat);
+ glMatrixMode(GL_MODELVIEW);
+ }
+}
+
+void bwin_ortho2(int win, float x1, float x2, float y1, float y2)
+{
+ bwin_ortho(win, x1, x2, y1, y2, -1, 1);
+}
+
+void bwin_frustum(int winid, float x1, float x2, float y1, float y2, float n, float f)
+{
+ bWindow *win= bwin_from_winid(winid);
+ if(win) {
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glFrustum(x1, x2, y1, y2, n, f);
+
+ glGetFloatv(GL_PROJECTION_MATRIX, (float *)win->winmat);
+ glMatrixMode(GL_MODELVIEW);
+ }
+}
+
+void myortho(float x1, float x2, float y1, float y2, float n, float f)
+{
+ bwin_ortho(curswin, x1, x2, y1, y2, n, f);
+}
+
+void myortho2(float x1, float x2, float y1, float y2)
+{
+ /* prevent opengl from generating errors */
+ if(x1==x2) x2+=1.0;
+ if(y1==y2) y2+=1.0;
+ bwin_ortho(curswin, x1, x2, y1, y2, -100, 100);
+}
+
+void mywindow(float x1, float x2, float y1, float y2, float n, float f)
+{
+ bwin_frustum(curswin, x1, x2, y1, y2, n, f);
+}
+
+#ifdef __APPLE__
+
+/* apple seems to round colors to below and up on some configs */
+
+static unsigned int index_to_framebuffer(int index)
+{
+ unsigned int i= index;
+
+ switch(mainwin_color_depth) {
+ case 12:
+ i= ((i & 0xF00)<<12) + ((i & 0xF0)<<8) + ((i & 0xF)<<4);
+ /* sometimes dithering subtracts! */
+ i |= 0x070707;
+ break;
+ case 15:
+ case 16:
+ i= ((i & 0x7C00)<<9) + ((i & 0x3E0)<<6) + ((i & 0x1F)<<3);
+ i |= 0x030303;
+ break;
+ case 24:
+ break;
+ default: // 18 bits...
+ i= ((i & 0x3F000)<<6) + ((i & 0xFC0)<<4) + ((i & 0x3F)<<2);
+ i |= 0x010101;
+ break;
+ }
+
+ return i;
+}
+
+#else
+
+/* this is the old method as being in use for ages.... seems to work? colors are rounded to lower values */
+
+static unsigned int index_to_framebuffer(int index)
+{
+ unsigned int i= index;
+
+ switch(mainwin_color_depth) {
+ case 8:
+ i= ((i & 48)<<18) + ((i & 12)<<12) + ((i & 3)<<6);
+ i |= 0x3F3F3F;
+ break;
+ case 12:
+ i= ((i & 0xF00)<<12) + ((i & 0xF0)<<8) + ((i & 0xF)<<4);
+ /* sometimes dithering subtracts! */
+ i |= 0x0F0F0F;
+ break;
+ case 15:
+ case 16:
+ i= ((i & 0x7C00)<<9) + ((i & 0x3E0)<<6) + ((i & 0x1F)<<3);
+ i |= 0x070707;
+ break;
+ case 24:
+ break;
+ default: // 18 bits...
+ i= ((i & 0x3F000)<<6) + ((i & 0xFC0)<<4) + ((i & 0x3F)<<2);
+ i |= 0x030303;
+ break;
+ }
+
+ return i;
+}
+
+#endif
+
+void set_framebuffer_index_color(int index)
+{
+ cpack(index_to_framebuffer(index));
+}
+
+int framebuffer_to_index(unsigned int col)
+{
+ if (col==0) return 0;
+
+ switch(mainwin_color_depth) {
+ case 8:
+ return ((col & 0xC00000)>>18) + ((col & 0xC000)>>12) + ((col & 0xC0)>>6);
+ case 12:
+ return ((col & 0xF00000)>>12) + ((col & 0xF000)>>8) + ((col & 0xF0)>>4);
+ case 15:
+ case 16:
+ return ((col & 0xF80000)>>9) + ((col & 0xF800)>>6) + ((col & 0xF8)>>3);
+ case 24:
+ return col & 0xFFFFFF;
+ default: // 18 bits...
+ return ((col & 0xFC0000)>>6) + ((col & 0xFC00)>>4) + ((col & 0xFC)>>2);
+ }
+}
+
+
+/* ********** END MY WINDOW ************** */
+
+#ifdef WIN32
+static int is_a_really_crappy_nvidia_card(void) {
+ static int well_is_it= -1;
+
+ /* Do you understand the implication? Do you? */
+ if (well_is_it==-1)
+ well_is_it= (strcmp((char*) glGetString(GL_VENDOR), "NVIDIA Corporation") == 0);
+
+ return well_is_it;
+}
+#endif
+
+void myswapbuffers(void)
+{
+ ScrArea *sa;
+
+ sa= G.curscreen->areabase.first;
+ while(sa) {
+ if(sa->win_swap==WIN_BACK_OK) sa->win_swap= WIN_FRONT_OK;
+ if(sa->head_swap==WIN_BACK_OK) sa->head_swap= WIN_FRONT_OK;
+
+ sa= sa->next;
+ }
+
+ /* HACK, some windows drivers feel they should honor the scissor
+ * test when swapping buffers, disable the test while swapping
+ * on WIN32. (namely Matrox and NVidia's new drivers around Oct 1 2001)
+ * - zr
+ */
+
+#ifdef WIN32
+ /* HACK, in some NVidia driver release some kind of
+ * fancy optimiziation (I presume) was put in which for
+ * some reason causes parts of the buffer not to be
+ * swapped. One way to defeat it is the following wierd
+ * code (which we only do for nvidia cards). This should
+ * be removed if NVidia fixes their drivers. - zr
+ */
+ if (is_a_really_crappy_nvidia_card()) {
+ glDrawBuffer(GL_FRONT);
+
+ glBegin(GL_LINES);
+ glEnd();
+
+ glDrawBuffer(GL_BACK);
+ }
+
+ glDisable(GL_SCISSOR_TEST);
+ window_swap_buffers(winlay_mainwindow);
+ glEnable(GL_SCISSOR_TEST);
+#else
+ window_swap_buffers(winlay_mainwindow);
+#endif
+}
+
+
+/* *********************** PATTERNS ETC ***************** */
+
+void setlinestyle(int nr)
+{
+ if(nr==0) {
+ glDisable(GL_LINE_STIPPLE);
+ }
+ else {
+
+ glEnable(GL_LINE_STIPPLE);
+ glLineStipple(nr, 0xAAAA);
+ }
+}
+
+/*******************/
+/*******************/
+/* Menu utilities */
+
+static int *frontbuffer_save= NULL;
+static int ov_x, ov_y, ov_sx, ov_sy;
+
+/*
+#if defined(__sgi) || defined(__sun) || defined(__sun__) || defined (__sparc) || defined (__sparc__)
+*/
+/* this is a dirty patch: gets sometimes the backbuffer */
+/* my_get_frontbuffer_image(0, 0, 1, 1);
+my_put_frontbuffer_image();
+#endif
+*/
+
+void my_put_frontbuffer_image(void)
+{
+ if (frontbuffer_save) {
+ glRasterPos2f( (float)ov_x -0.5, (float)ov_y - 0.5 );
+ glDrawPixels(ov_sx, ov_sy, GL_RGBA, GL_UNSIGNED_BYTE, frontbuffer_save);
+ MEM_freeN(frontbuffer_save);
+ frontbuffer_save= NULL;
+ }
+}
+
+void my_get_frontbuffer_image(int x, int y, int sx, int sy)
+{
+ if(frontbuffer_save) return;
+
+ ov_x= x;
+ ov_y= y;
+ ov_sx= sx;
+ ov_sy= sy;
+
+ if(sx>1 && sy>1) {
+ frontbuffer_save= MEM_mallocN(sx*sy*4, "temp_frontbuffer_image");
+ glReadPixels(x, y, sx, sy, GL_RGBA, GL_UNSIGNED_BYTE, frontbuffer_save);
+ }
+
+ #ifdef WIN32
+ /* different coord system! */
+ y= (G.curscreen->sizey-y);
+
+ if(curswin>3) {
+ y -= curarea->winrct.ymin;
+ }
+ #endif
+}
+
+int mywin_inmenu(void) {
+ return frontbuffer_save?1:0;
+}
+
+void mywin_getmenu_rect(int *x, int *y, int *sx, int *sy) {
+ *x= ov_x;
+ *sx= ov_sx;
+ *sy= ov_sy;
+
+#if defined(WIN32) || defined (__BeOS)
+ *y= ov_y;
+#else
+ *y= (G.curscreen->sizey - ov_y) - ov_sy;
+#endif
+}
diff --git a/source/blender/src/oops.c b/source/blender/src/oops.c
new file mode 100644
index 00000000000..7def4ca615e
--- /dev/null
+++ b/source/blender/src/oops.c
@@ -0,0 +1,1104 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <math.h>
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "DNA_curve_types.h"
+#include "DNA_image_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_object_types.h"
+#include "DNA_oops_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_key_types.h"
+#include "DNA_group_types.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_toolbox.h"
+#include "BIF_oops.h"
+#include "BIF_drawoops.h"
+#include "BIF_outliner.h"
+
+#include "blendef.h"
+#include "mydevice.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+static int correct_oops_y(Oops *oops);
+
+
+Oops *add_oops(void *id)
+{
+ Oops *oops;
+
+ if(G.soops==0) return NULL;
+ oops= MEM_callocN(sizeof(Oops), "oops");
+
+ BLI_addtail(&G.soops->oops, oops);
+
+ oops->id= id;
+ oops->type= GS(oops->id->name);
+
+ return oops;
+}
+
+
+Oops *find_oops(ID *id)
+{
+ Oops *oops;
+
+ /* searching for an oops with this ID */
+ oops= G.soops->oops.first;
+ while(oops) {
+ if(oops->id == id) {
+ /* this error once happened. securing it doesnt harm */
+ if(oops->type != GS(id->name)) oops->id= 0;
+ else break;
+ }
+ oops= oops->next;
+ }
+ return oops;
+}
+
+/* never even called! (ton) */
+int test_oops(Oops *oops)
+{
+ /* test if own ID block still exists */
+ ListBase *lb;
+ ID *id;
+
+ if(G.soops==0) return 0;
+
+ lb= wich_libbase(G.main, oops->type);
+ id= lb->first;
+ while(id) {
+ if(id==oops->id) break;
+ id= id->next;
+ }
+
+ if(id==0) return 0;
+
+
+ return 1;
+}
+
+void test_oopslinko(OopsLink *ol)
+{
+ /* test if links exist */
+ Oops *oops;
+ ListBase *lb;
+ ID *id, *from;
+
+ if(G.soops==0) return;
+
+ ol->to= 0;
+ from= *ol->idfrom;
+
+ if(from==0) return;
+
+ lb= wich_libbase(G.main, ol->type);
+ id= lb->first;
+ while(id) {
+ if(id==from) break;
+ id= id->next;
+ }
+
+ if(id==0) {
+ /* ID does not exist anymore */
+ *ol->idfrom= 0;
+ }
+ else {
+ /* search for oops with this ID */
+ oops= G.soops->oops.first;
+ while(oops) {
+ if(oops->id == id) break;
+ oops= oops->next;
+ }
+
+ ol->to= oops;
+ }
+}
+
+void test_oopslink(OopsLink *ol)
+{
+ /* test if links exist */
+ Oops *oops;
+ ID *from;
+
+ if(G.soops==0) return;
+
+ ol->to= 0;
+ from= *ol->idfrom;
+
+ if(from==0) return;
+
+ /* search for oops with this ID */
+ oops= G.soops->oops.first;
+ while(oops) {
+ if(oops->id == from) break;
+ oops= oops->next;
+ }
+
+ ol->to= oops;
+ if(oops) oops->flag |= OOPS_REFER;
+}
+
+
+OopsLink *add_oopslink(char *name, Oops *oops, short type, void *from, float xof, float yof)
+{
+ OopsLink *ol;
+
+ if(G.soops==0) return NULL;
+
+ /* testing if it exsists: */
+ /* ol= oops->link.first; */
+ /* while(ol) { */
+ /* if(ol->idfrom == from) { */
+ /* strncpy(ol->name, name, 11); */
+ /* ol->type= type; */
+ /* ol->xof= xof; */
+ /* ol->yof= yof; */
+ /* return ol; */
+ /* } */
+ /* ol= ol->next; */
+ /* } */
+
+ if(* ((int *)from) == 0) return NULL;
+
+ /* make new */
+ ol= MEM_callocN(sizeof(OopsLink), "oopslink");
+
+ BLI_addtail(&oops->link, ol);
+
+ ol->type= type;
+ ol->idfrom= from;
+ ol->xof= xof;
+ ol->yof= yof;
+ BLI_strncpy(ol->name, name, sizeof(ol->name));
+
+ return ol;
+}
+
+int oops_test_overlap(Oops *test)
+{
+ Oops *oops;
+ rctf rt, ro;
+
+ rt.xmin= test->x;
+ rt.xmax= (float)(test->x+OOPSX);
+ rt.ymin= test->y;
+ rt.ymax= (float)(test->y+OOPSY);
+
+ oops= G.soops->oops.first;
+ while(oops) {
+ if(oops!=test) { /* do net test for hide: is only a temporal flag */
+
+ ro.xmin= oops->x;
+ ro.xmax= (float)(oops->x+OOPSX);
+ ro.ymin= oops->y;
+ ro.ymax= (float)(oops->y+OOPSY);
+
+ if( BLI_isect_rctf(&rt, &ro, 0) ) return 1;
+
+ }
+ oops= oops->next;
+ }
+
+ return 0;
+}
+
+int oops_test_overlaphide(Oops *test)
+{
+ Oops *oops;
+ rctf rt, ro;
+
+ rt.xmin= (float)(test->x);
+ rt.xmax= (float)(test->x+OOPSX);
+ rt.ymin= (float)(test->y);
+ rt.ymax= (float)(test->y+OOPSY);
+
+ oops= G.soops->oops.first;
+ while(oops) {
+ if(oops->hide==0 && oops!=test) { /* do test for hide, but not use it during build_oops */
+
+ ro.xmin= oops->x;
+ ro.xmax= (float)(oops->x+OOPSX);
+ ro.ymin= oops->y;
+ ro.ymax= (float)(oops->y+OOPSY);
+
+ if( BLI_isect_rctf(&rt, &ro, 0) ) return 1;
+
+ }
+ oops= oops->next;
+ }
+
+ return 0;
+}
+
+float oopslink_totlen(Oops *oops)
+{
+ OopsLink *ol;
+ float vec[4], dx, dy, len= 0.0;
+
+
+ ol= oops->link.first;
+ while(ol) {
+ if(ol->to) {
+ give_oopslink_line(oops, ol, vec, vec+2);
+
+ dx= vec[0]-vec[2];
+ dy= vec[1]-vec[3];
+
+ len+= (float)sqrt( dx*dx + dy*dy );
+ }
+ ol= ol->next;
+ }
+ return len;
+}
+
+
+void add_from_link(Oops *from, Oops *oops)
+{
+ OopsLink *ol;
+
+ ol= MEM_callocN(sizeof(OopsLink), "oopslinktemp");
+ BLI_addtail(&oops->link, ol);
+ ol->from= from;
+
+}
+
+void shuffle_oops()
+{
+ Oops *o2, *oops;
+ OopsLink *ol, *oln;
+ float olen, len1, f1, f2;
+ int go= 1, tot=0, dir=1, type1, type2;
+
+
+ /* we take two oopses, calc the 'beauty' and the exchanged beauty */
+
+ if(G.soops==0) return;
+
+ waitcursor(1);
+
+ /* to make it 100% OK and fast: temporal insert
+ * to the ooplinklist - per oops - the 'from' links.
+ * Don't forget to free!
+ */
+
+ oops= G.soops->oops.first;
+ while(oops) {
+ if(oops->hide==0) {
+ ol= oops->link.first;
+ while(ol) {
+ if(ol->to && ol->to->hide==0) {
+ if(ol->to->flag & SELECT) {
+ add_from_link(oops, ol->to);
+ }
+ }
+ ol= ol->next;
+ }
+ }
+ oops= oops->next;
+ }
+
+ while(go) {
+
+ go= 0;
+ dir= 1-dir;
+ tot++;
+
+ if(dir) oops= G.soops->oops.last;
+ else oops= G.soops->oops.first;
+ while(oops) {
+
+ if(oops->link.first && oops->hide==0 && (oops->flag & SELECT)) {
+ /* find a good exchangable pair */
+ olen= oopslink_totlen(oops);
+
+ if(dir) o2= oops->prev;
+ else o2= oops->next;
+
+ if ELEM3(oops->type, ID_OB, ID_LI, ID_SCE) type1= 1; else type1= 0;
+
+
+ while(o2) {
+ if(o2->hide==0 && (o2->flag & SELECT)) {
+
+ if ELEM3(o2->type, ID_OB, ID_LI, ID_SCE) type2= 1; else type2= 0;
+
+ if(type1==type2) {
+
+ len1= oopslink_totlen(o2);
+
+ SWAP(float, oops->x, o2->x);
+ SWAP(float, oops->y, o2->y);
+
+ f1= oopslink_totlen(oops);
+ f2= oopslink_totlen(o2);
+
+ if( f1<=olen && f2<len1) { /* 1 x <= !!! */
+ olen= oopslink_totlen(oops);
+ go= 1;
+ }
+ else {
+ SWAP(float, oops->x, o2->x);
+ SWAP(float, oops->y, o2->y);
+ }
+ }
+ }
+ if(dir) o2= o2->prev;
+ else o2= o2->next;
+ }
+ }
+ if(dir) oops= oops->prev;
+ else oops= oops->next;
+
+
+ }
+ if(tot>5) break;
+ }
+ waitcursor(0);
+
+ /* free the from links */
+ oops= G.soops->oops.first;
+ while(oops) {
+ if(oops->hide==0) {
+ ol= oops->link.first;
+ while(ol) {
+ oln= ol->next;
+ if(ol->from) {
+ BLI_remlink(&oops->link, ol);
+ MEM_freeN(ol);
+ }
+ ol= oln;
+ }
+ }
+ oops= oops->next;
+ }
+
+ allqueue(REDRAWOOPS, 1);
+}
+
+void shrink_oops()
+{
+ Oops *oops;
+ OopsLink *ol;
+ float vec[4];
+ int /* go= 1, */tot=4;
+
+
+ if(G.soops==0) return;
+
+ if(okee("Shrink oops")==0) return;
+
+ waitcursor(1);
+
+ /* clear */
+ oops= G.soops->oops.first;
+ while(oops) {
+ oops->dx= oops->dy= 0.0;
+ oops= oops->next;
+ }
+
+ while(tot) {
+ tot--;
+
+ /* shrink */
+ oops= G.soops->oops.first;
+ while(oops) {
+ if(oops->link.first && oops->hide==0 && (oops->flag & SELECT)) {
+
+ ol= oops->link.first;
+ while(ol) {
+ if(ol->to && ol->to->hide==0) {
+
+ give_oopslink_line(oops, ol, vec, vec+2);
+
+ oops->dx= (float)(.8*oops->dx + .2*( vec[2]-vec[0]));
+ oops->dy= (float)(.8*oops->dy + .2*( vec[3]-vec[1]));
+
+ if(ol->to->flag & SELECT) {
+ ol->to->dx= (float)(.8*ol->to->dx + .2*( vec[0]-vec[2]));
+ ol->to->dy= (float)(.8*ol->to->dy + .2*( vec[1]-vec[3]));
+ }
+ }
+
+ ol= ol->next;
+ }
+ }
+ oops= oops->next;
+ }
+
+ /* apply */
+ oops= G.soops->oops.first;
+ while(oops) {
+ if(oops->hide==0 && (oops->flag & SELECT)) {
+
+ /* shrink */
+ oops->x+= oops->dx;
+ oops->y+= oops->dy;
+
+ if(oops_test_overlaphide(oops)) {
+ oops->x-= oops->dx;
+ oops->y-= oops->dy;
+ }
+
+ oops->dx= oops->dy= 0.0;
+ }
+ oops= oops->next;
+ }
+ }
+ waitcursor(0);
+
+ allqueue(REDRAWOOPS, 1);
+}
+
+#define LIMSCE -20.0
+#define LIMOB 14.0
+#define LIMDATA 24.0
+
+static int correct_oops_y(Oops *oops)
+{
+ float y;
+
+ y= oops->y;
+
+ switch(oops->type) {
+ case ID_SCE:
+ case ID_LI:
+ if(oops->y > LIMSCE-OOPSY) oops->y= (float)(LIMSCE-OOPSY);
+ break;
+ case ID_OB:
+ CLAMP(oops->y, LIMSCE, LIMOB);
+ break;
+ case ID_IP:
+ case ID_MA:
+ case ID_TE:
+ if(oops->y < LIMDATA+OOPSY) oops->y= (float)(LIMDATA+OOPSY);
+ break;
+ default:
+ CLAMP(oops->y, (float)(LIMOB+OOPSY), LIMDATA);
+ break;
+ }
+
+ if(y==oops->y) return 0;
+ else return 1;
+}
+
+float oopslastx=0.0, oopslasty= 0.0;
+
+void new_oops_location(Oops *new)
+{
+ float dirvec[4][2];
+ static int cnt=0;
+ int a, b, rc= 1, tel=1, ok=0;
+
+ if(G.soops==0) return;
+
+ if(G.soops->oops.first==G.soops->oops.last) {
+ oopslastx= oopslasty= 0.0;
+ }
+
+ cnt++;
+
+ new->x= oopslastx;
+ new->y= oopslasty;
+
+ correct_oops_y(new);
+
+ /* find from center free location */
+ dirvec[cnt & 3][0]= 1.2*OOPSX;
+ dirvec[cnt & 3][1]= 0;
+ cnt++;
+ dirvec[cnt & 3][0]= 0;
+ dirvec[cnt & 3][1]= (float)(-1.2*OOPSY);
+ cnt++;
+ dirvec[cnt & 3][0]= -1.2*OOPSX;
+ dirvec[cnt & 3][1]= 0;
+ cnt++;
+ dirvec[cnt & 3][0]= 0;
+ dirvec[cnt & 3][1]= (float)(1.2*OOPSY);
+ cnt++;
+
+
+ new->x+= dirvec[ (rc-2) & 3][0];
+ new->y+= dirvec[ (rc-2) & 3][1];
+ rc+= correct_oops_y(new);
+
+ if( oops_test_overlap(new)==0 ) {
+ ok= 1;
+ }
+
+ rc++;
+
+ if(ok==0) {
+ new->x+= dirvec[ (rc-1) & 3][0];
+ new->y+= dirvec[ (rc-1) & 3][1];
+ rc+= correct_oops_y(new);
+
+ if(oops_test_overlap(new)==0 ) {
+ ok= 1;
+ }
+ rc++;
+ }
+
+
+ while(ok==0) {
+
+ for(a=0;a<2;a++) {
+ for(b=0;b<tel;b++) {
+
+ if( oops_test_overlap(new)==0 ) {
+ ok= 1;
+ break;
+ }
+
+ rc &= 3;
+ new->x += dirvec[rc][0];
+ new->y += dirvec[rc][1];
+ rc+= correct_oops_y(new);
+ }
+ rc++;
+
+
+
+ if(ok) break;
+ }
+ if(ok || tel>100) break;
+ tel++;
+ }
+ oopslastx= new->x;
+ oopslasty= new->y;
+
+}
+
+
+void free_oops(Oops *oops) /* also oops itself */
+{
+ BLI_freelistN(&oops->link);
+ MEM_freeN(oops);
+}
+
+void free_oopspace(SpaceOops *so)
+{
+ Oops *oops;
+
+ while( (oops= so->oops.first) ) {
+ BLI_remlink(&so->oops, oops);
+ free_oops(oops);
+ }
+
+ outliner_free_tree(&so->tree);
+ if(so->treestore) {
+ if(so->treestore->data) MEM_freeN(so->treestore->data);
+ MEM_freeN(so->treestore);
+ }
+}
+
+void add_material_oopslinks(Material *ma, Oops *oops, short flag)
+{
+ int a;
+
+ if(flag & OOPS_TE) {
+ for(a=0; a<MAX_MTEX; a++) {
+ if(ma->mtex[a]) add_oopslink("tex", oops, ID_TE, &(ma->mtex[a]->tex), (float)(0.5*OOPSX), (float)OOPSY);
+ }
+ }
+ if(flag & OOPS_OB) {
+ for(a=0; a<MAX_MTEX; a++) {
+ if(ma->mtex[a]) add_oopslink("ob", oops, ID_OB, &(ma->mtex[a]->object), 0.0, (float)(0.2*OOPSY));
+ }
+ }
+ if(flag & OOPS_IP)
+ if(ma->ipo) add_oopslink("ipo", oops, ID_IP, &(ma->ipo), OOPSX, (float)(0.5*OOPSY));
+
+ if (ma->group)
+ add_oopslink("group", oops, ID_GR, &(ma->group), OOPSX, (float)(0.5*OOPSY));
+}
+
+
+void add_group_oopslinks(Group *gp, Oops *oops, short flag)
+{
+ GroupObject *gob;
+ if(flag & OOPS_GR) {
+ for(gob=gp->gobject.first; gob; gob= gob->next) {
+ add_oopslink("group", oops, ID_GR, &(gob->ob), (float)(0.5*OOPSX), (float)OOPSY);
+ }
+ }
+}
+
+
+void add_object_oopslinks(Object *ob, Oops *oops, short flag)
+{
+ ID *id;
+
+ if(ob->parent) add_oopslink("parent", oops, ID_OB, &ob->parent, (float)(.6*OOPSX), (float)OOPSY);
+ if(ob->track) add_oopslink("parent", oops, ID_OB, &ob->track, (float)(.4*OOPSX), (float)OOPSY);
+
+ id= ob->data;
+ if(id) {
+ switch( GS(id->name) ) {
+ case ID_ME:
+ if(flag & OOPS_ME) add_oopslink("data", oops, ID_ME, &ob->data, (float)(.5*OOPSX), (float)OOPSY);
+ break;
+ case ID_CU:
+ if(flag & OOPS_CU) add_oopslink("data", oops, ID_CU, &ob->data, (float)(.5*OOPSX), (float)OOPSY);
+ break;
+ case ID_MB:
+ if(flag & OOPS_MB) add_oopslink("data", oops, ID_MB, &ob->data, (float)(.5*OOPSX), (float)OOPSY);
+ break;
+ case ID_LT:
+ if(flag & OOPS_LT) add_oopslink("data", oops, ID_LT, &ob->data, (float)(.5*OOPSX), (float)OOPSY);
+ break;
+ case ID_LA:
+ if(flag & OOPS_LA) add_oopslink("data", oops, ID_LA, &ob->data, (float)(.5*OOPSX), (float)OOPSY);
+ break;
+ }
+ }
+
+ if(flag & OOPS_MA) {
+ short a;
+
+ for(a=0; a<ob->totcol; a++) {
+ if(ob->mat[a]) {
+ add_oopslink("mat", oops, ID_MA, ob->mat+a, 0, (float)(0.5*OOPSY));
+ }
+ }
+ }
+
+ if(flag & OOPS_IP) add_oopslink("ipo", oops, ID_IP, &ob->ipo, OOPSX, (float)(0.5*OOPSY));
+
+ if (ob->dup_group && (ob->transflag & OB_DUPLIGROUP))
+ add_oopslink("group", oops, ID_GR, &ob->dup_group, OOPSX, (float)(0.5*OOPSY));
+}
+
+void add_mesh_oopslinks(Mesh *me, Oops *oops, short flag)
+{
+ int a;
+
+ if(flag & OOPS_MA) {
+ for(a=0; a<me->totcol; a++) {
+ if(me->mat[a]) {
+ add_oopslink("ma", oops, ID_MA, me->mat+a, 0.0, (float)(0.5*OOPSY));
+ }
+ }
+ }
+ if(flag & OOPS_IP) {
+ if(me->key) add_oopslink("ipo", oops, ID_IP, &me->key->ipo, OOPSX, (float)(0.5*OOPSY));
+ }
+}
+
+void add_curve_oopslinks(Curve *cu, Oops *oops, short flag)
+{
+ int a;
+
+ if(flag & OOPS_MA) {
+ for(a=0; a<cu->totcol; a++) {
+ if(cu->mat[a]) {
+ add_oopslink("ma", oops, ID_MA, cu->mat+a, 0.0, (float)(0.5*OOPSY));
+ }
+ }
+ }
+ if(flag & OOPS_IP) {
+ add_oopslink("speed", oops, ID_IP, &cu->ipo, OOPSX, (float)(0.5*OOPSY));
+ if(cu->key) add_oopslink("ipo", oops, ID_IP, &cu->key->ipo, OOPSX, (float)(0.5*OOPSY));
+ }
+
+}
+
+void add_mball_oopslinks(MetaBall *mb, Oops *oops, short flag)
+{
+ int a;
+
+ if(flag & OOPS_MA) {
+ for(a=0; a<mb->totcol; a++) {
+ if(mb->mat[a]) {
+ add_oopslink("ma", oops, ID_MA, mb->mat+a, 0.0, (float)(0.5*OOPSY));
+ }
+ }
+ }
+}
+
+void add_lamp_oopslinks(Lamp *la, Oops *oops, short flag)
+{
+ int a;
+
+ if(flag & OOPS_TE) {
+ for(a=0; a<MAX_MTEX; a++) {
+ if(la->mtex[a]) {
+ add_oopslink("tex", oops, ID_TE, &(la->mtex[a]->tex), 0.0, (float)(0.5*OOPSY));
+ }
+ }
+ }
+}
+
+
+Oops *add_test_oops(void *id) /* incl links */
+{
+ Oops *oops;
+ Object *ob;
+ Lamp *la;
+ Tex *tex;
+
+ if(id==0) return NULL;
+
+ /* test if it exists */
+ oops= find_oops(id);
+
+ if(oops) {
+ oops->hide= 0;
+ }
+ else {
+ oops= add_oops(id);
+ new_oops_location(oops);
+ if(G.soops->flag & SO_NEWSELECTED) {
+ oops->flag |= SELECT;
+ }
+ }
+
+ switch( GS( ((ID *)id)->name)) {
+ case ID_SCE:
+ add_oopslink("set", oops, ID_SCE, &((Scene *)id)->set, (float)(.5*OOPSX), (float)OOPSY);
+ break;
+ case ID_OB:
+ ob= (Object *)id;
+ if(ob->flag & SELECT) oops->flag |= SELECT;
+ else oops->flag &= ~SELECT;
+ add_object_oopslinks(ob, oops, G.soops->visiflag);
+ break;
+ case ID_ME:
+ add_mesh_oopslinks((Mesh *)id, oops, G.soops->visiflag);
+ break;
+ case ID_CU:
+ add_curve_oopslinks((Curve *)id, oops, G.soops->visiflag);
+ break;
+ case ID_MB:
+ add_mball_oopslinks((MetaBall *)id, oops, G.soops->visiflag);
+ break;
+ case ID_LA:
+ la= (Lamp *)id;
+ add_lamp_oopslinks(la, oops, G.soops->visiflag);
+ if(la->ipo) if(G.soops->visiflag & OOPS_IP) add_oopslink("ipo", oops, ID_IP, &la->ipo, OOPSX, (float)(0.3*OOPSY));
+ break;
+ case ID_IP:
+
+ break;
+ case ID_MA:
+ add_material_oopslinks((Material *)id, oops, G.soops->visiflag);
+ break;
+ case ID_GR:
+ add_group_oopslinks((Group *)id, oops, G.soops->visiflag);
+ break;
+ case ID_TE:
+ tex= (Tex *)id;
+ if(tex->ima) if(G.soops->visiflag & OOPS_IM) add_oopslink("image", oops, ID_IM, &tex->ima, OOPSX, (float)(0.3*OOPSY));
+ }
+
+ return oops;
+}
+
+void add_texture_oops(Material *ma)
+{
+ int a;
+
+ for(a=0; a<MAX_MTEX; a++) {
+ if(ma->mtex[a]) {
+ add_test_oops(ma->mtex[a]->tex);
+ if(ma->mtex[a]->tex) if(G.soops->visiflag & OOPS_IM) add_test_oops(ma->mtex[a]->tex->ima);
+ }
+ }
+}
+
+void build_oops()
+{
+ Oops *oops;
+ OopsLink *ol;
+ ID *id;
+ Base *base;
+ Object *ob;
+ short a, type;
+
+ /* always build it all! */
+
+ if(G.soops==0) return;
+
+ /* set hide flags */
+ oops= G.soops->oops.first;
+ while(oops) {
+ oops->hide= 1;
+ oops->flag &= ~OOPS_REFER;
+
+ BLI_freelistN(&oops->link); /* much safer */
+
+ oops= oops->next;
+ }
+
+ /* make oops, includes testing for existance */
+
+ /* always */
+ if(G.soops->visiflag & OOPS_LI) {
+ Library *li= G.main->library.first;
+ while(li) {
+ oops= add_test_oops(li);
+ li= li->id.next;
+ }
+ }
+
+ /* the rest in 2 ways: or everything (OOPS_SCE) or only the ones in this scene */
+
+ if(G.soops->visiflag & OOPS_SCE) {
+ Scene *sce= G.main->scene.first;
+
+ while(sce) {
+
+ oops= add_test_oops(sce);
+
+ if(G.soops->visiflag & OOPS_OB) {
+ base= sce->base.first;
+ while(base) {
+
+ add_oopslink("object", oops, ID_OB, &base->object, (float)(.5*OOPSX), (float)OOPSY);
+ base= base->next;
+ }
+ }
+
+ sce= sce->id.next;
+ }
+
+ if(G.soops->visiflag & OOPS_OB) {
+ Object *ob= G.main->object.first;
+
+ while(ob) {
+ oops= add_test_oops(ob);
+ ob= ob->id.next;
+ }
+ }
+ if(G.soops->visiflag & OOPS_ME) {
+ Mesh *me= G.main->mesh.first;
+ while(me) {
+ oops= add_test_oops(me);
+ me= me->id.next;
+ }
+ }
+
+ if(G.soops->visiflag & OOPS_CU) {
+ Curve *cu= G.main->curve.first;
+ while(cu) {
+ oops= add_test_oops(cu);
+ cu= cu->id.next;
+ }
+ }
+
+ if(G.soops->visiflag & OOPS_MB) {
+ MetaBall *mb= G.main->mball.first;
+ while(mb) {
+ oops= add_test_oops(mb);
+ mb= mb->id.next;
+ }
+ }
+
+ if(G.soops->visiflag & OOPS_LA) {
+ Lamp *la= G.main->lamp.first;
+ while(la) {
+ oops= add_test_oops(la);
+ la= la->id.next;
+ }
+ }
+
+ if(G.soops->visiflag & OOPS_IP) {
+ Ipo *ipo= G.main->ipo.first;
+ while(ipo) {
+ oops= add_test_oops(ipo);
+ ipo= ipo->id.next;
+ }
+ }
+
+ if(G.soops->visiflag & OOPS_MA) {
+ Material *ma= G.main->mat.first;
+ while(ma) {
+ oops= add_test_oops(ma);
+ ma= ma->id.next;
+ }
+ }
+ if(G.soops->visiflag & OOPS_TE) {
+ Tex *tex= G.main->tex.first;
+ while(tex) {
+ oops= add_test_oops(tex);
+ tex= tex->id.next;
+ }
+ }
+ if(G.soops->visiflag & OOPS_IM) {
+ Image *ima= G.main->image.first;
+ while(ima) {
+ oops= add_test_oops(ima);
+ ima= ima->id.next;
+ }
+ }
+ if(G.soops->visiflag & OOPS_GR) {
+ Group *gp= G.main->group.first;
+ while(gp) {
+ oops= add_test_oops(gp);
+ gp= gp->id.next;
+ }
+ }
+ }
+ else {
+
+ /* only blocks from this scene */
+
+ base= FIRSTBASE;
+ while(base) {
+
+ /* layer? */
+ if( (G.soops->visiflag & OOPS_LAY)==0 || (base->lay & G.scene->lay)) {
+ ob= base->object;
+
+ if(G.soops->visiflag & OOPS_OB) {
+ oops= add_test_oops(ob);
+ }
+ if(G.soops->visiflag & OOPS_MA) {
+ for(a=0; a<ob->totcol; a++) {
+ if(ob->mat[a]) {
+ oops= add_test_oops(ob->mat[a]);
+ if(G.soops->visiflag & OOPS_TE) add_texture_oops(ob->mat[a]);
+ if(G.soops->visiflag & OOPS_IP) add_test_oops(ob->mat[a]->ipo);
+ }
+ }
+ }
+ if(G.soops->visiflag & OOPS_IP) oops= add_test_oops(ob->ipo);
+
+ id= ob->data;
+ if(id) {
+ type= GS(id->name);
+
+ if(type==ID_ME && G.soops->visiflag & OOPS_ME) {
+ Mesh *me= ob->data;
+ oops= add_test_oops(ob->data);
+
+ if(G.soops->visiflag & OOPS_MA) {
+ for(a=0; a<me->totcol; a++) {
+ if(me->mat[a]) {
+ oops= add_test_oops(me->mat[a]);
+ if(G.soops->visiflag & OOPS_TE) add_texture_oops(me->mat[a]);
+ if(G.soops->visiflag & OOPS_IP) add_test_oops(me->mat[a]->ipo);
+ }
+ }
+ }
+ if(G.soops->visiflag & OOPS_IP) {
+ if(me->key) oops= add_test_oops(me->key->ipo);
+ }
+ }
+ else if(type==ID_CU && G.soops->visiflag & OOPS_CU) {
+ Curve *cu= ob->data;
+ oops= add_test_oops(ob->data);
+
+ if(G.soops->visiflag & OOPS_MA) {
+ for(a=0; a<cu->totcol; a++) {
+ if(cu->mat[a]) {
+ oops= add_test_oops(cu->mat[a]);
+ if(G.soops->visiflag & OOPS_TE) add_texture_oops(cu->mat[a]);
+ if(G.soops->visiflag & OOPS_IP) add_test_oops(cu->mat[a]->ipo);
+ }
+ }
+ }
+ if(G.soops->visiflag & OOPS_IP) {
+ if(cu->ipo) oops= add_test_oops(cu->ipo);
+ if(cu->key) oops= add_test_oops(cu->key->ipo);
+ }
+ }
+ else if(type==ID_MB && G.soops->visiflag & OOPS_MB) {
+ oops= add_test_oops(ob->data);
+
+ if(G.soops->visiflag & OOPS_MA) {
+ MetaBall *mb= ob->data;
+ for(a=0; a<mb->totcol; a++) {
+ if(mb->mat[a]) {
+ oops= add_test_oops(mb->mat[a]);
+ if(G.soops->visiflag & OOPS_TE) add_texture_oops(mb->mat[a]);
+ if(G.soops->visiflag & OOPS_IP) add_test_oops(mb->mat[a]->ipo);
+ }
+ }
+ }
+ }
+ else if(type==ID_LA && G.soops->visiflag & OOPS_LA) {
+ Lamp *la= ob->data;
+ oops= add_test_oops(ob->data);
+ if(G.soops->visiflag & OOPS_IP) add_test_oops(la->ipo);
+ if(G.soops->visiflag & OOPS_TE) {
+ for(a=0; a<MAX_MTEX; a++) {
+ if(la->mtex[a]) add_test_oops(la->mtex[a]->tex);
+ }
+ }
+ }
+ }
+ }
+ base= base->next;
+ }
+ }
+
+
+
+
+ /* test links */
+ oops= G.soops->oops.first;
+ while(oops) {
+ if(oops->hide==0) {
+ ol= oops->link.first;
+ while(ol) {
+ test_oopslink(ol);
+ ol= ol->next;
+ }
+ }
+ oops= oops->next;
+ }
+
+ G.soops->flag &= ~SO_NEWSELECTED;
+}
diff --git a/source/blender/src/outliner.c b/source/blender/src/outliner.c
new file mode 100644
index 00000000000..aa5fd0d409b
--- /dev/null
+++ b/source/blender/src/outliner.c
@@ -0,0 +1,3640 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_action_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_image_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_group_types.h"
+#include "DNA_key_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_nla_types.h"
+#include "DNA_object_types.h"
+#include "DNA_oops_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_text_types.h"
+#include "DNA_world_types.h"
+
+#include "BLI_blenlib.h"
+
+#include "BKE_constraint.h"
+#include "BKE_deform.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_group.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_modifier.h"
+#include "BKE_screen.h"
+#include "BKE_scene.h"
+#include "BKE_utildefines.h"
+
+#ifdef WITH_VERSE
+#include "BKE_verse.h"
+#endif
+
+#include "BIF_butspace.h"
+#include "BIF_drawscene.h"
+#include "BIF_drawtext.h"
+#include "BIF_editaction.h"
+#include "BIF_editarmature.h"
+#include "BIF_editdeform.h"
+#include "BIF_editnla.h"
+#include "BIF_editview.h"
+#include "BIF_editconstraint.h"
+#include "BIF_gl.h"
+#include "BIF_graphics.h"
+#include "BIF_interface.h"
+#include "BIF_interface_icons.h"
+#include "BIF_mywindow.h"
+#include "BIF_outliner.h"
+#include "BIF_language.h"
+#include "BIF_mainqueue.h"
+#include "BIF_poseobject.h"
+#include "BIF_previewrender.h"
+#include "BIF_resources.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_toolbox.h"
+
+#ifdef WITH_VERSE
+#include "BIF_verse.h"
+#endif
+
+#ifdef INTERNATIONAL
+#include "FTF_Api.h"
+#endif
+
+#include "BDR_editobject.h"
+#include "BSE_drawipo.h"
+#include "BSE_edit.h"
+#include "BSE_view.h"
+
+#include "PIL_time.h"
+
+#include "blendef.h"
+#include "mydevice.h"
+
+#define OL_H 19
+#define OL_X 18
+
+#define OL_TOG_RESTRICT_VIEWX 54
+#define OL_TOG_RESTRICT_SELECTX 36
+#define OL_TOG_RESTRICT_RENDERX 18
+
+#define OL_TOGW OL_TOG_RESTRICT_VIEWX
+
+#define TS_CHUNK 128
+
+#define TREESTORE(a) ((a)?soops->treestore->data+(a)->store_index:NULL)
+
+#ifdef WITH_VERSE
+extern ListBase session_list;
+extern ListBase server_list;
+#endif
+
+
+/* ******************** PROTOTYPES ***************** */
+static void outliner_draw_tree_element(SpaceOops *soops, TreeElement *te, int startx, int *starty);
+
+
+/* ******************** PERSISTANT DATA ***************** */
+
+static void outliner_storage_cleanup(SpaceOops *soops)
+{
+ TreeStore *ts= soops->treestore;
+
+ if(ts) {
+ TreeStoreElem *tselem;
+ int a, unused= 0;
+
+ /* each element used once, for ID blocks with more users to have each a treestore */
+ for(a=0, tselem= ts->data; a<ts->usedelem; a++, tselem++) tselem->used= 0;
+
+ /* cleanup only after reading file or undo step */
+ if(soops->storeflag & SO_TREESTORE_CLEANUP) {
+
+ for(a=0, tselem= ts->data; a<ts->usedelem; a++, tselem++) {
+ if(tselem->id==NULL) unused++;
+ }
+
+ if(unused) {
+ if(ts->usedelem == unused) {
+ MEM_freeN(ts->data);
+ ts->data= NULL;
+ ts->usedelem= ts->totelem= 0;
+ }
+ else {
+ TreeStoreElem *tsnewar, *tsnew;
+
+ tsnew=tsnewar= MEM_mallocN((ts->usedelem-unused)*sizeof(TreeStoreElem), "new tselem");
+ for(a=0, tselem= ts->data; a<ts->usedelem; a++, tselem++) {
+ if(tselem->id) {
+ *tsnew= *tselem;
+ tsnew++;
+ }
+ }
+ MEM_freeN(ts->data);
+ ts->data= tsnewar;
+ ts->usedelem-= unused;
+ ts->totelem= ts->usedelem;
+ }
+ }
+ }
+ }
+}
+
+static void check_persistant(SpaceOops *soops, TreeElement *te, ID *id, short type, short nr)
+{
+ TreeStore *ts;
+ TreeStoreElem *tselem;
+ int a;
+
+ /* case 1; no TreeStore */
+ if(soops->treestore==NULL) {
+ ts= soops->treestore= MEM_callocN(sizeof(TreeStore), "treestore");
+ }
+ ts= soops->treestore;
+
+ /* check if 'te' is in treestore */
+ tselem= ts->data;
+ for(a=0; a<ts->usedelem; a++, tselem++) {
+ if(tselem->id==id && tselem->used==0) {
+ if((type==0 && tselem->type==0) ||(tselem->type==type && tselem->nr==nr)) {
+ te->store_index= a;
+ tselem->used= 1;
+ return;
+ }
+ }
+ }
+
+ /* add 1 element to treestore */
+ if(ts->usedelem==ts->totelem) {
+ TreeStoreElem *tsnew;
+
+ tsnew= MEM_mallocN((ts->totelem+TS_CHUNK)*sizeof(TreeStoreElem), "treestore data");
+ if(ts->data) {
+ memcpy(tsnew, ts->data, ts->totelem*sizeof(TreeStoreElem));
+ MEM_freeN(ts->data);
+ }
+ ts->data= tsnew;
+ ts->totelem+= TS_CHUNK;
+ }
+
+ tselem= ts->data+ts->usedelem;
+
+ tselem->type= type;
+ if(type) tselem->nr= nr; // we're picky! :)
+ else tselem->nr= 0;
+ tselem->id= id;
+ tselem->flag= TSE_CLOSED;
+ te->store_index= ts->usedelem;
+
+ ts->usedelem++;
+}
+
+/* ******************** TREE MANAGEMENT ****************** */
+
+void outliner_free_tree(ListBase *lb)
+{
+
+ while(lb->first) {
+ TreeElement *te= lb->first;
+
+ outliner_free_tree(&te->subtree);
+ BLI_remlink(lb, te);
+ MEM_freeN(te);
+ }
+}
+
+static void outliner_height(SpaceOops *soops, ListBase *lb, int *h)
+{
+ TreeElement *te= lb->first;
+ while(te) {
+ TreeStoreElem *tselem= TREESTORE(te);
+ if((tselem->flag & TSE_CLOSED)==0)
+ outliner_height(soops, &te->subtree, h);
+ (*h)++;
+ te= te->next;
+ }
+}
+
+static void outliner_width(SpaceOops *soops, ListBase *lb, int *w)
+{
+ TreeElement *te= lb->first;
+ while(te) {
+ TreeStoreElem *tselem= TREESTORE(te);
+ if(tselem->flag & TSE_CLOSED) {
+ if (te->xend > *w)
+ *w = te->xend;
+ }
+ outliner_width(soops, &te->subtree, w);
+ te= te->next;
+ }
+}
+
+static TreeElement *outliner_find_tree_element(ListBase *lb, int store_index)
+{
+ TreeElement *te= lb->first, *tes;
+ while(te) {
+ if(te->store_index==store_index) return te;
+ tes= outliner_find_tree_element(&te->subtree, store_index);
+ if(tes) return tes;
+ te= te->next;
+ }
+ return NULL;
+}
+
+
+
+static ID *outliner_search_back(SpaceOops *soops, TreeElement *te, short idcode)
+{
+ TreeStoreElem *tselem;
+ te= te->parent;
+
+ while(te) {
+ tselem= TREESTORE(te);
+ if(te->idcode==idcode && tselem->type==0) return tselem->id;
+ te= te->parent;
+ }
+ return NULL;
+}
+
+struct treesort {
+ TreeElement *te;
+ ID *id;
+ char *name;
+ short idcode;
+};
+
+static int treesort_alpha(const void *v1, const void *v2)
+{
+ const struct treesort *x1= v1, *x2= v2;
+ int comp;
+
+ /* first put objects last (hierarchy) */
+ comp= (x1->idcode==ID_OB);
+ if(x2->idcode==ID_OB) comp+=2;
+
+ if(comp==1) return 1;
+ else if(comp==2) return -1;
+ else if(comp==3) {
+ int comp= strcmp(x1->name, x2->name);
+
+ if( comp>0 ) return 1;
+ else if( comp<0) return -1;
+ return 0;
+ }
+ return 0;
+}
+
+/* this is nice option for later? doesnt look too useful... */
+#if 0
+static int treesort_obtype_alpha(const void *v1, const void *v2)
+{
+ const struct treesort *x1= v1, *x2= v2;
+
+ /* first put objects last (hierarchy) */
+ if(x1->idcode==ID_OB && x2->idcode!=ID_OB) return 1;
+ else if(x2->idcode==ID_OB && x1->idcode!=ID_OB) return -1;
+ else {
+ /* 2nd we check ob type */
+ if(x1->idcode==ID_OB && x2->idcode==ID_OB) {
+ if( ((Object *)x1->id)->type > ((Object *)x2->id)->type) return 1;
+ else if( ((Object *)x1->id)->type > ((Object *)x2->id)->type) return -1;
+ else return 0;
+ }
+ else {
+ int comp= strcmp(x1->name, x2->name);
+
+ if( comp>0 ) return 1;
+ else if( comp<0) return -1;
+ return 0;
+ }
+ }
+}
+#endif
+
+/* sort happens on each subtree individual */
+static void outliner_sort(SpaceOops *soops, ListBase *lb)
+{
+ TreeElement *te;
+ TreeStoreElem *tselem;
+ int totelem=0;
+
+ te= lb->last;
+ if(te==NULL) return;
+ tselem= TREESTORE(te);
+
+ /* sorting rules; only object lists or deformgroups */
+ if( (tselem->type==TSE_DEFGROUP) || (tselem->type==0 && te->idcode==ID_OB)) {
+
+ /* count first */
+ for(te= lb->first; te; te= te->next) totelem++;
+
+ if(totelem>1) {
+ struct treesort *tear= MEM_mallocN(totelem*sizeof(struct treesort), "tree sort array");
+ struct treesort *tp=tear;
+ int skip= 0;
+
+ for(te= lb->first; te; te= te->next, tp++) {
+ tselem= TREESTORE(te);
+ tp->te= te;
+ tp->name= te->name;
+ tp->idcode= te->idcode;
+ if(tselem->type && tselem->type!=TSE_DEFGROUP) tp->idcode= 0; // dont sort this
+ tp->id= tselem->id;
+ }
+ /* keep beginning of list */
+ for(tp= tear, skip=0; skip<totelem; skip++, tp++)
+ if(tp->idcode) break;
+
+ if(skip<totelem)
+ qsort(tear+skip, totelem-skip, sizeof(struct treesort), treesort_alpha);
+
+ lb->first=lb->last= NULL;
+ tp= tear;
+ while(totelem--) {
+ BLI_addtail(lb, tp->te);
+ tp++;
+ }
+ MEM_freeN(tear);
+ }
+ }
+
+ for(te= lb->first; te; te= te->next) {
+ outliner_sort(soops, &te->subtree);
+ }
+}
+
+/* Prototype, see functions below */
+static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *idv,
+ TreeElement *parent, short type, short index);
+
+
+static void outliner_add_passes(SpaceOops *soops, TreeElement *tenla, ID *id, SceneRenderLayer *srl)
+{
+ TreeStoreElem *tselem= TREESTORE(tenla);
+ TreeElement *te;
+
+ te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, SCE_PASS_COMBINED);
+ te->name= "Combined";
+ te->directdata= &srl->passflag;
+
+ /* save cpu cycles, but we add the first to invoke an open/close triangle */
+ if(tselem->flag & TSE_CLOSED)
+ return;
+
+ te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, SCE_PASS_Z);
+ te->name= "Z";
+ te->directdata= &srl->passflag;
+
+ te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, SCE_PASS_VECTOR);
+ te->name= "Vector";
+ te->directdata= &srl->passflag;
+
+ te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, SCE_PASS_NORMAL);
+ te->name= "Normal";
+ te->directdata= &srl->passflag;
+
+ te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, SCE_PASS_UV);
+ te->name= "UV";
+ te->directdata= &srl->passflag;
+
+ te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, SCE_PASS_INDEXOB);
+ te->name= "Index Object";
+ te->directdata= &srl->passflag;
+
+ te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, SCE_PASS_RGBA);
+ te->name= "Color";
+ te->directdata= &srl->passflag;
+
+ te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, SCE_PASS_DIFFUSE);
+ te->name= "Diffuse";
+ te->directdata= &srl->passflag;
+
+ te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, SCE_PASS_SPEC);
+ te->name= "Specular";
+ te->directdata= &srl->passflag;
+
+ te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, SCE_PASS_SHADOW);
+ te->name= "Shadow";
+ te->directdata= &srl->passflag;
+
+ te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, SCE_PASS_AO);
+ te->name= "AO";
+ te->directdata= &srl->passflag;
+
+ te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, SCE_PASS_REFLECT);
+ te->name= "Reflection";
+ te->directdata= &srl->passflag;
+
+ te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, SCE_PASS_REFRACT);
+ te->name= "Refraction";
+ te->directdata= &srl->passflag;
+
+ te= outliner_add_element(soops, &tenla->subtree, id, tenla, TSE_R_PASS, SCE_PASS_RADIO);
+ te->name= "Radiosity";
+ te->directdata= &srl->passflag;
+
+}
+
+
+/* special handling of hierarchical non-lib data */
+static void outliner_add_bone(SpaceOops *soops, ListBase *lb, ID *id, Bone *curBone,
+ TreeElement *parent, int *a)
+{
+ TreeElement *te= outliner_add_element(soops, lb, id, parent, TSE_BONE, *a);
+
+ (*a)++;
+ te->name= curBone->name;
+ te->directdata= curBone;
+
+ for(curBone= curBone->childbase.first; curBone; curBone=curBone->next) {
+ outliner_add_bone(soops, &te->subtree, id, curBone, te, a);
+ }
+}
+
+static void outliner_add_scene_contents(SpaceOops *soops, ListBase *lb, Scene *sce, TreeElement *te)
+{
+ SceneRenderLayer *srl;
+ TreeElement *tenla= outliner_add_element(soops, lb, sce, te, TSE_R_LAYER_BASE, 0);
+ int a;
+
+ tenla->name= "RenderLayers";
+ for(a=0, srl= sce->r.layers.first; srl; srl= srl->next, a++) {
+ TreeElement *tenlay= outliner_add_element(soops, &tenla->subtree, sce, te, TSE_R_LAYER, a);
+ tenlay->name= srl->name;
+ tenlay->directdata= &srl->passflag;
+
+ if(srl->light_override)
+ outliner_add_element(soops, &tenlay->subtree, srl->light_override, tenlay, TSE_LINKED_LAMP, 0);
+ if(srl->mat_override)
+ outliner_add_element(soops, &tenlay->subtree, srl->mat_override, tenlay, TSE_LINKED_MAT, 0);
+
+ outliner_add_passes(soops, tenlay, &sce->id, srl);
+ }
+
+ outliner_add_element(soops, lb, sce->world, te, 0, 0);
+
+ if(sce->scriptlink.scripts) {
+ int a= 0;
+ tenla= outliner_add_element(soops, lb, sce, te, TSE_SCRIPT_BASE, 0);
+ tenla->name= "Scripts";
+ for (a=0; a<sce->scriptlink.totscript; a++) {
+ outliner_add_element(soops, &tenla->subtree, sce->scriptlink.scripts[a], tenla, 0, 0);
+ }
+ }
+
+}
+
+static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *idv,
+ TreeElement *parent, short type, short index)
+{
+ TreeElement *te;
+ TreeStoreElem *tselem;
+ ID *id= idv;
+ int a;
+
+ if(id==NULL) return NULL;
+
+ te= MEM_callocN(sizeof(TreeElement), "tree elem");
+ /* add to the visual tree */
+ BLI_addtail(lb, te);
+ /* add to the storage */
+ check_persistant(soops, te, id, type, index);
+ tselem= TREESTORE(te);
+
+ te->parent= parent;
+ te->index= index; // for data arays
+ te->name= id->name+2; // default, can be overridden by Library or non-ID data
+ te->idcode= GS(id->name);
+
+ if(type==0) {
+
+ /* tuck pointer back in object, to construct hierarchy */
+ if(GS(id->name)==ID_OB) id->newid= (ID *)te;
+
+ /* expand specific data always */
+ switch(GS(id->name)) {
+ case ID_LI:
+ te->name= ((Library *)id)->name;
+ break;
+ case ID_SCE:
+ outliner_add_scene_contents(soops, &te->subtree, (Scene *)id, te);
+ break;
+ case ID_OB:
+ {
+ Object *ob= (Object *)id;
+
+ if(ob->proxy && ob->id.lib==NULL)
+ outliner_add_element(soops, &te->subtree, ob->proxy, te, TSE_PROXY, 0);
+
+ outliner_add_element(soops, &te->subtree, ob->data, te, 0, 0);
+
+ if(ob->pose) {
+ bPoseChannel *pchan;
+ TreeElement *ten;
+ TreeElement *tenla= outliner_add_element(soops, &te->subtree, ob, te, TSE_POSE_BASE, 0);
+
+ tenla->name= "Pose";
+
+ if(ob!=G.obedit && (ob->flag & OB_POSEMODE)) { // channels undefined in editmode, but we want the 'tenla' pose icon itself
+ int a= 0, const_index= 1000; /* ensure unique id for bone constraints */
+
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next, a++) {
+ ten= outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_POSE_CHANNEL, a);
+ ten->name= pchan->name;
+ ten->directdata= pchan;
+ pchan->prev= (bPoseChannel *)ten;
+
+ if(pchan->constraints.first) {
+ //Object *target;
+ bConstraint *con;
+ TreeElement *ten1;
+ TreeElement *tenla1= outliner_add_element(soops, &ten->subtree, ob, ten, TSE_CONSTRAINT_BASE, 0);
+ //char *str;
+
+ tenla1->name= "Constraints";
+ for(con= pchan->constraints.first; con; con= con->next, const_index++) {
+ ten1= outliner_add_element(soops, &tenla1->subtree, ob, tenla1, TSE_CONSTRAINT, const_index);
+#if 0 /* disabled as it needs to be reworked for recoded constraints system */
+ target= get_constraint_target(con, &str);
+ if(str && str[0]) ten1->name= str;
+ else if(target) ten1->name= target->id.name+2;
+ else ten1->name= con->name;
+#endif
+ ten1->name= con->name;
+ ten1->directdata= con;
+ /* possible add all other types links? */
+ }
+ }
+ }
+ /* make hierarchy */
+ ten= tenla->subtree.first;
+ while(ten) {
+ TreeElement *nten= ten->next, *par;
+ tselem= TREESTORE(ten);
+ if(tselem->type==TSE_POSE_CHANNEL) {
+ pchan= (bPoseChannel *)ten->directdata;
+ if(pchan->parent) {
+ BLI_remlink(&tenla->subtree, ten);
+ par= (TreeElement *)pchan->parent->prev;
+ BLI_addtail(&par->subtree, ten);
+ ten->parent= par;
+ }
+ }
+ ten= nten;
+ }
+ /* restore prev pointers */
+ pchan= ob->pose->chanbase.first;
+ if(pchan) pchan->prev= NULL;
+ for(; pchan; pchan= pchan->next) {
+ if(pchan->next) pchan->next->prev= pchan;
+ }
+ }
+ }
+
+ outliner_add_element(soops, &te->subtree, ob->ipo, te, 0, 0);
+ outliner_add_element(soops, &te->subtree, ob->action, te, 0, 0);
+
+ for(a=0; a<ob->totcol; a++)
+ outliner_add_element(soops, &te->subtree, ob->mat[a], te, 0, a);
+
+ if(ob->constraints.first) {
+ //Object *target;
+ bConstraint *con;
+ TreeElement *ten;
+ TreeElement *tenla= outliner_add_element(soops, &te->subtree, ob, te, TSE_CONSTRAINT_BASE, 0);
+ int a= 0;
+ //char *str;
+
+ tenla->name= "Constraints";
+ for(con= ob->constraints.first; con; con= con->next, a++) {
+ ten= outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_CONSTRAINT, a);
+#if 0 /* disabled due to constraints system targets recode... code here needs review */
+ target= get_constraint_target(con, &str);
+ if(str && str[0]) ten->name= str;
+ else if(target) ten->name= target->id.name+2;
+ else ten->name= con->name;
+#endif
+ ten->name= con->name;
+ ten->directdata= con;
+ /* possible add all other types links? */
+ }
+ }
+
+ if(ob->modifiers.first) {
+ ModifierData *md;
+ TreeElement *temod = outliner_add_element(soops, &te->subtree, ob, te, TSE_MODIFIER_BASE, 0);
+ int index;
+
+ temod->name = "Modifiers";
+ for (index=0,md=ob->modifiers.first; md; index++,md=md->next) {
+ TreeElement *te = outliner_add_element(soops, &temod->subtree, ob, temod, TSE_MODIFIER, index);
+ te->name= md->name;
+
+ if (md->type==eModifierType_Lattice) {
+ outliner_add_element(soops, &te->subtree, ((LatticeModifierData*) md)->object, te, TSE_LINKED_OB, 0);
+ } else if (md->type==eModifierType_Curve) {
+ outliner_add_element(soops, &te->subtree, ((CurveModifierData*) md)->object, te, TSE_LINKED_OB, 0);
+ } else if (md->type==eModifierType_Armature) {
+ outliner_add_element(soops, &te->subtree, ((ArmatureModifierData*) md)->object, te, TSE_LINKED_OB, 0);
+ } else if (md->type==eModifierType_Hook) {
+ outliner_add_element(soops, &te->subtree, ((HookModifierData*) md)->object, te, TSE_LINKED_OB, 0);
+ }
+ }
+ }
+ if(ob->defbase.first) {
+ bDeformGroup *defgroup;
+ TreeElement *ten;
+ TreeElement *tenla= outliner_add_element(soops, &te->subtree, ob, te, TSE_DEFGROUP_BASE, 0);
+ int a= 0;
+
+ tenla->name= "Vertex Groups";
+ for (defgroup=ob->defbase.first; defgroup; defgroup=defgroup->next, a++) {
+ ten= outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_DEFGROUP, a);
+ ten->name= defgroup->name;
+ ten->directdata= defgroup;
+ }
+ }
+ if(ob->scriptlink.scripts) {
+ TreeElement *tenla= outliner_add_element(soops, &te->subtree, ob, te, TSE_SCRIPT_BASE, 0);
+ int a= 0;
+
+ tenla->name= "Scripts";
+ for (a=0; a<ob->scriptlink.totscript; a++) { /* ** */
+ outliner_add_element(soops, &tenla->subtree, ob->scriptlink.scripts[a], te, 0, 0);
+ }
+ }
+
+ if(ob->dup_group)
+ outliner_add_element(soops, &te->subtree, ob->dup_group, te, 0, 0);
+
+ if(ob->nlastrips.first) {
+ bActionStrip *strip;
+ TreeElement *ten;
+ TreeElement *tenla= outliner_add_element(soops, &te->subtree, ob, te, TSE_NLA, 0);
+ int a= 0;
+
+ tenla->name= "NLA strips";
+ for (strip=ob->nlastrips.first; strip; strip=strip->next, a++) {
+ ten= outliner_add_element(soops, &tenla->subtree, strip->act, tenla, TSE_NLA_ACTION, a);
+ if(ten) ten->directdata= strip;
+ }
+ }
+
+ }
+ break;
+ case ID_ME:
+ {
+ Mesh *me= (Mesh *)id;
+ outliner_add_element(soops, &te->subtree, me->ipo, te, 0, 0);
+ outliner_add_element(soops, &te->subtree, me->key, te, 0, 0);
+ for(a=0; a<me->totcol; a++)
+ outliner_add_element(soops, &te->subtree, me->mat[a], te, 0, a);
+ /* could do tfaces with image links, but the images are not grouped nicely.
+ would require going over all tfaces, sort images in use. etc... */
+ }
+ break;
+ case ID_CU:
+ {
+ Curve *cu= (Curve *)id;
+ for(a=0; a<cu->totcol; a++)
+ outliner_add_element(soops, &te->subtree, cu->mat[a], te, 0, a);
+ }
+ break;
+ case ID_MB:
+ {
+ MetaBall *mb= (MetaBall *)id;
+ for(a=0; a<mb->totcol; a++)
+ outliner_add_element(soops, &te->subtree, mb->mat[a], te, 0, a);
+ }
+ break;
+ case ID_MA:
+ {
+ Material *ma= (Material *)id;
+
+ outliner_add_element(soops, &te->subtree, ma->ipo, te, 0, 0);
+ for(a=0; a<MAX_MTEX; a++) {
+ if(ma->mtex[a]) outliner_add_element(soops, &te->subtree, ma->mtex[a]->tex, te, 0, a);
+ }
+ }
+ break;
+ case ID_TE:
+ {
+ Tex *tex= (Tex *)id;
+
+ outliner_add_element(soops, &te->subtree, tex->ipo, te, 0, 0);
+ outliner_add_element(soops, &te->subtree, tex->ima, te, 0, 0);
+ }
+ break;
+ case ID_CA:
+ {
+ Camera *ca= (Camera *)id;
+ outliner_add_element(soops, &te->subtree, ca->ipo, te, 0, 0);
+ }
+ break;
+ case ID_LA:
+ {
+ Lamp *la= (Lamp *)id;
+ outliner_add_element(soops, &te->subtree, la->ipo, te, 0, 0);
+ for(a=0; a<MAX_MTEX; a++) {
+ if(la->mtex[a]) outliner_add_element(soops, &te->subtree, la->mtex[a]->tex, te, 0, a);
+ }
+ }
+ break;
+ case ID_WO:
+ {
+ World *wrld= (World *)id;
+ outliner_add_element(soops, &te->subtree, wrld->ipo, te, 0, 0);
+ for(a=0; a<MAX_MTEX; a++) {
+ if(wrld->mtex[a]) outliner_add_element(soops, &te->subtree, wrld->mtex[a]->tex, te, 0, a);
+ }
+ }
+ break;
+ case ID_KE:
+ {
+ Key *key= (Key *)id;
+ outliner_add_element(soops, &te->subtree, key->ipo, te, 0, 0);
+ }
+ break;
+ case ID_IP:
+ {
+ Ipo *ipo= (Ipo *)id;
+ IpoCurve *icu;
+ Object *lastadded= NULL;
+
+ for(icu= ipo->curve.first; icu; icu= icu->next) {
+ if(icu->driver && icu->driver->ob) {
+ if(lastadded!=icu->driver->ob) {
+ outliner_add_element(soops, &te->subtree, icu->driver->ob, te, TSE_LINKED_OB, 0);
+ lastadded= icu->driver->ob;
+ }
+ }
+ }
+ }
+ case ID_AC:
+ {
+ bAction *act= (bAction *)id;
+ bActionChannel *chan;
+ int a= 0;
+
+ tselem= TREESTORE(parent);
+ for (chan=act->chanbase.first; chan; chan=chan->next, a++) {
+ outliner_add_element(soops, &te->subtree, chan->ipo, te, 0, a);
+ }
+ }
+ break;
+ case ID_AR:
+ {
+ bArmature *arm= (bArmature *)id;
+ int a= 0;
+
+ if(G.obedit && G.obedit->data==arm) {
+ EditBone *ebone;
+ TreeElement *ten;
+
+ for (ebone = G.edbo.first; ebone; ebone=ebone->next, a++) {
+ ten= outliner_add_element(soops, &te->subtree, id, te, TSE_EBONE, a);
+ ten->directdata= ebone;
+ ten->name= ebone->name;
+ ebone->temp= ten;
+ }
+ /* make hierarchy */
+ ten= te->subtree.first;
+ while(ten) {
+ TreeElement *nten= ten->next, *par;
+ ebone= (EditBone *)ten->directdata;
+ if(ebone->parent) {
+ BLI_remlink(&te->subtree, ten);
+ par= ebone->parent->temp;
+ BLI_addtail(&par->subtree, ten);
+ ten->parent= par;
+ }
+ ten= nten;
+ }
+ }
+ else {
+ /* do not extend Armature when we have posemode */
+ tselem= TREESTORE(te->parent);
+ if( GS(tselem->id->name)==ID_OB && ((Object *)tselem->id)->flag & OB_POSEMODE);
+ else {
+ Bone *curBone;
+ for (curBone=arm->bonebase.first; curBone; curBone=curBone->next){
+ outliner_add_bone(soops, &te->subtree, id, curBone, te, &a);
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+#ifdef WITH_VERSE
+ else if(type==ID_VS) {
+ struct VerseSession *session = (VerseSession*)idv;
+ te->name = session->address;
+ te->directdata = (void*)session;
+ te->idcode = ID_VS;
+ }
+ else if(type==ID_MS) {
+ te->name = "Available Verse Servers";
+ te->idcode = ID_MS;
+ }
+ else if(type==ID_SS) {
+ struct VerseServer *server = (VerseServer *)idv;
+ te->name = server->name;
+ te->directdata = (void *)server;
+ te->idcode = ID_SS;
+ }
+ else if(type==ID_VN) {
+ struct VNode *vnode = (VNode*)idv;
+ te->name = vnode->name;
+ te->idcode = ID_VN;
+ if(vnode->type==V_NT_OBJECT) {
+ struct TreeElement *ten;
+ struct VNode *child_node;
+ struct VLink *vlink;
+
+ vlink = ((VObjectData*)vnode->data)->links.lb.first;
+ while(vlink) {
+ child_node = vlink->target;
+ if(child_node && child_node->type==V_NT_GEOMETRY) {
+ ten = outliner_add_element(soops, &te->subtree, child_node, te, ID_VN, 0);
+ ten->directdata = child_node;
+ }
+ vlink = vlink->next;
+ }
+ }
+ }
+#endif
+ return te;
+}
+
+static void outliner_make_hierarchy(SpaceOops *soops, ListBase *lb)
+{
+ TreeElement *te, *ten, *tep;
+ TreeStoreElem *tselem;
+
+ /* build hierarchy */
+ te= lb->first;
+ while(te) {
+ ten= te->next;
+ tselem= TREESTORE(te);
+
+ if(tselem->type==0 && te->idcode==ID_OB) {
+ Object *ob= (Object *)tselem->id;
+ if(ob->parent && ob->parent->id.newid) {
+ BLI_remlink(lb, te);
+ tep= (TreeElement *)ob->parent->id.newid;
+ BLI_addtail(&tep->subtree, te);
+ // set correct parent pointers
+ for(te=tep->subtree.first; te; te= te->next) te->parent= tep;
+ }
+ }
+ te= ten;
+ }
+}
+
+static void outliner_build_tree(SpaceOops *soops)
+{
+ Base *base;
+ Object *ob;
+ TreeElement *te, *ten;
+ TreeStoreElem *tselem;
+ int show_opened= soops->treestore==NULL; /* on first view, we open scenes */
+#ifdef WITH_VERSE
+ struct VerseSession *session;
+#endif
+
+ if(soops->tree.first && (soops->storeflag & SO_TREESTORE_REDRAW))
+ return;
+
+ outliner_free_tree(&soops->tree);
+ outliner_storage_cleanup(soops);
+
+ /* clear ob id.new flags */
+ for(ob= G.main->object.first; ob; ob= ob->id.next) ob->id.newid= NULL;
+
+ /* options */
+ if(soops->outlinevis == SO_LIBRARIES) {
+ Library *lib;
+
+ for(lib= G.main->library.first; lib; lib= lib->id.next) {
+ ten= outliner_add_element(soops, &soops->tree, lib, NULL, 0, 0);
+ lib->id.newid= (ID *)ten;
+ }
+ /* make hierarchy */
+ ten= soops->tree.first;
+ while(ten) {
+ TreeElement *nten= ten->next, *par;
+ tselem= TREESTORE(ten);
+ lib= (Library *)tselem->id;
+ if(lib->parent) {
+ BLI_remlink(&soops->tree, ten);
+ par= (TreeElement *)lib->parent->id.newid;
+ BLI_addtail(&par->subtree, ten);
+ ten->parent= par;
+ }
+ ten= nten;
+ }
+ /* restore newid pointers */
+ for(lib= G.main->library.first; lib; lib= lib->id.next)
+ lib->id.newid= NULL;
+
+ }
+ else if(soops->outlinevis == SO_ALL_SCENES) {
+ Scene *sce;
+ for(sce= G.main->scene.first; sce; sce= sce->id.next) {
+ te= outliner_add_element(soops, &soops->tree, sce, NULL, 0, 0);
+ tselem= TREESTORE(te);
+ if(sce==G.scene && show_opened)
+ tselem->flag &= ~TSE_CLOSED;
+
+ for(base= sce->base.first; base; base= base->next) {
+ ten= outliner_add_element(soops, &te->subtree, base->object, te, 0, 0);
+ ten->directdata= base;
+ }
+ outliner_make_hierarchy(soops, &te->subtree);
+ /* clear id.newid, to prevent objects be inserted in wrong scenes (parent in other scene) */
+ for(base= sce->base.first; base; base= base->next) base->object->id.newid= NULL;
+ }
+ }
+ else if(soops->outlinevis == SO_CUR_SCENE) {
+
+ outliner_add_scene_contents(soops, &soops->tree, G.scene, NULL);
+
+ for(base= G.scene->base.first; base; base= base->next) {
+ ten= outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
+ ten->directdata= base;
+ }
+ outliner_make_hierarchy(soops, &soops->tree);
+ }
+ else if(soops->outlinevis == SO_VISIBLE) {
+ for(base= G.scene->base.first; base; base= base->next) {
+ if(base->lay & G.scene->lay)
+ outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
+ }
+ outliner_make_hierarchy(soops, &soops->tree);
+ }
+ else if(soops->outlinevis == SO_GROUPS) {
+ Group *group;
+ GroupObject *go;
+
+ for(group= G.main->group.first; group; group= group->id.next) {
+ if(group->id.us) {
+ te= outliner_add_element(soops, &soops->tree, group, NULL, 0, 0);
+ tselem= TREESTORE(te);
+
+ for(go= group->gobject.first; go; go= go->next) {
+ ten= outliner_add_element(soops, &te->subtree, go->ob, te, 0, 0);
+ ten->directdata= NULL; /* eh, why? */
+ }
+ outliner_make_hierarchy(soops, &te->subtree);
+ /* clear id.newid, to prevent objects be inserted in wrong scenes (parent in other scene) */
+ for(go= group->gobject.first; go; go= go->next) go->ob->id.newid= NULL;
+ }
+ }
+ }
+ else if(soops->outlinevis == SO_SAME_TYPE) {
+ Object *ob= OBACT;
+ if(ob) {
+ for(base= G.scene->base.first; base; base= base->next) {
+ if(base->object->type==ob->type) {
+ ten= outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
+ ten->directdata= base;
+ }
+ }
+ outliner_make_hierarchy(soops, &soops->tree);
+ }
+ }
+ else if(soops->outlinevis == SO_SELECTED) {
+ for(base= G.scene->base.first; base; base= base->next) {
+ if(base->lay & G.scene->lay) {
+ if(base==BASACT || (base->flag & SELECT)) {
+ ten= outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0);
+ ten->directdata= base;
+ }
+ }
+ }
+ outliner_make_hierarchy(soops, &soops->tree);
+ }
+#ifdef WITH_VERSE
+ else if(soops->outlinevis == SO_VERSE_SESSION) {
+ /* add all session to the "root" of hierarchy */
+ for(session=session_list.first; session; session = session->next) {
+ struct VNode *vnode;
+ if(session->flag & VERSE_CONNECTED) {
+ te= outliner_add_element(soops, &soops->tree, session, NULL, ID_VS, 0);
+ /* add all object nodes as childreen of session */
+ for(vnode=session->nodes.lb.first; vnode; vnode=vnode->next) {
+ if(vnode->type==V_NT_OBJECT) {
+ ten= outliner_add_element(soops, &te->subtree, vnode, te, ID_VN, 0);
+ ten->directdata= vnode;
+ }
+ else if(vnode->type==V_NT_BITMAP) {
+ ten= outliner_add_element(soops, &te->subtree, vnode, te, ID_VN, 0);
+ ten->directdata= vnode;
+ }
+ }
+ }
+ }
+ }
+ else if(soops->outlinevis == SO_VERSE_MS) {
+ te= outliner_add_element(soops, &soops->tree, "MS", NULL, ID_MS, 0);
+ if(server_list.first!=NULL) {
+ struct VerseServer *server;
+ /* add one main entry to root of hierarchy */
+ for(server=server_list.first; server; server=server->next) {
+ ten= outliner_add_element(soops, &te->subtree, server, te, ID_SS, 0);
+ ten->directdata= server;
+ }
+ }
+ }
+#endif
+ else {
+ ten= outliner_add_element(soops, &soops->tree, OBACT, NULL, 0, 0);
+ if(ten) ten->directdata= BASACT;
+ }
+
+
+ outliner_sort(soops, &soops->tree);
+}
+
+/* **************** INTERACTIVE ************* */
+
+static int outliner_count_levels(SpaceOops *soops, ListBase *lb, int curlevel)
+{
+ TreeElement *te;
+ int level=curlevel, lev;
+
+ for(te= lb->first; te; te= te->next) {
+
+ lev= outliner_count_levels(soops, &te->subtree, curlevel+1);
+ if(lev>level) level= lev;
+ }
+ return level;
+}
+
+static int outliner_has_one_flag(SpaceOops *soops, ListBase *lb, short flag, short curlevel)
+{
+ TreeElement *te;
+ TreeStoreElem *tselem;
+ int level;
+
+ for(te= lb->first; te; te= te->next) {
+ tselem= TREESTORE(te);
+ if(tselem->flag & flag) return curlevel;
+
+ level= outliner_has_one_flag(soops, &te->subtree, flag, curlevel+1);
+ if(level) return level;
+ }
+ return 0;
+}
+
+static void outliner_set_flag(SpaceOops *soops, ListBase *lb, short flag, short set)
+{
+ TreeElement *te;
+ TreeStoreElem *tselem;
+
+ for(te= lb->first; te; te= te->next) {
+ tselem= TREESTORE(te);
+ if(set==0) tselem->flag &= ~flag;
+ else tselem->flag |= flag;
+ outliner_set_flag(soops, &te->subtree, flag, set);
+ }
+}
+
+void outliner_toggle_visible(struct ScrArea *sa)
+{
+ SpaceOops *soops= sa->spacedata.first;
+
+ if( outliner_has_one_flag(soops, &soops->tree, TSE_CLOSED, 1))
+ outliner_set_flag(soops, &soops->tree, TSE_CLOSED, 0);
+ else
+ outliner_set_flag(soops, &soops->tree, TSE_CLOSED, 1);
+
+ BIF_undo_push("Outliner toggle visible");
+ scrarea_queue_redraw(sa);
+}
+
+void outliner_toggle_selected(struct ScrArea *sa)
+{
+ SpaceOops *soops= sa->spacedata.first;
+
+ if( outliner_has_one_flag(soops, &soops->tree, TSE_SELECTED, 1))
+ outliner_set_flag(soops, &soops->tree, TSE_SELECTED, 0);
+ else
+ outliner_set_flag(soops, &soops->tree, TSE_SELECTED, 1);
+
+ BIF_undo_push("Outliner toggle selected");
+ soops->storeflag |= SO_TREESTORE_REDRAW;
+ scrarea_queue_redraw(sa);
+}
+
+
+static void outliner_openclose_level(SpaceOops *soops, ListBase *lb, int curlevel, int level, int open)
+{
+ TreeElement *te;
+ TreeStoreElem *tselem;
+
+ for(te= lb->first; te; te= te->next) {
+ tselem= TREESTORE(te);
+
+ if(open) {
+ if(curlevel<=level) tselem->flag &= ~TSE_CLOSED;
+ }
+ else {
+ if(curlevel>=level) tselem->flag |= TSE_CLOSED;
+ }
+
+ outliner_openclose_level(soops, &te->subtree, curlevel+1, level, open);
+ }
+}
+
+/* return 1 when levels were opened */
+static int outliner_open_back(SpaceOops *soops, TreeElement *te)
+{
+ TreeStoreElem *tselem;
+ int retval= 0;
+
+ for (te= te->parent; te; te= te->parent) {
+ tselem= TREESTORE(te);
+ if (tselem->flag & TSE_CLOSED) {
+ tselem->flag &= ~TSE_CLOSED;
+ retval= 1;
+ }
+ }
+ return retval;
+}
+
+static void outliner_open_reveal(SpaceOops *soops, ListBase *lb, TreeElement *teFind, int *found)
+{
+ TreeElement *te;
+ TreeStoreElem *tselem;
+
+ for (te= lb->first; te; te= te->next) {
+ /* check if this tree-element was the one we're seeking */
+ if (te == teFind) {
+ *found= 1;
+ return;
+ }
+
+ /* try to see if sub-tree contains it then */
+ outliner_open_reveal(soops, &te->subtree, teFind, found);
+ if (*found) {
+ tselem= TREESTORE(te);
+ if (tselem->flag & TSE_CLOSED)
+ tselem->flag &= ~TSE_CLOSED;
+ return;
+ }
+ }
+}
+
+
+void outliner_one_level(struct ScrArea *sa, int add)
+{
+ SpaceOops *soops= sa->spacedata.first;
+ int level;
+
+ level= outliner_has_one_flag(soops, &soops->tree, TSE_CLOSED, 1);
+ if(add==1) {
+ if(level) outliner_openclose_level(soops, &soops->tree, 1, level, 1);
+ }
+ else {
+ if(level==0) level= outliner_count_levels(soops, &soops->tree, 0);
+ if(level) outliner_openclose_level(soops, &soops->tree, 1, level-1, 0);
+ }
+
+ BIF_undo_push("Outliner show/hide one level");
+ scrarea_queue_redraw(sa);
+}
+
+void outliner_page_up_down(ScrArea *sa, int up)
+{
+ SpaceOops *soops= sa->spacedata.first;
+ int dy= soops->v2d.mask.ymax-soops->v2d.mask.ymin;
+
+ if(up == -1) dy= -dy;
+ soops->v2d.cur.ymin+= dy;
+ soops->v2d.cur.ymax+= dy;
+
+ soops->storeflag |= SO_TREESTORE_REDRAW;
+ scrarea_queue_redraw(sa);
+}
+
+/* **** do clicks on items ******* */
+
+static int tree_element_active_renderlayer(TreeElement *te, TreeStoreElem *tselem, int set)
+{
+ Scene *sce;
+
+ /* paranoia check */
+ if(te->idcode!=ID_SCE)
+ return 0;
+ sce= (Scene *)tselem->id;
+
+ if(set) {
+ sce->r.actlay= tselem->nr;
+ allqueue(REDRAWBUTSSCENE, 0);
+ }
+ else {
+ return sce->r.actlay==tselem->nr;
+ }
+ return 0;
+}
+
+static void tree_element_active_object(SpaceOops *soops, TreeElement *te)
+{
+ TreeStoreElem *tselem= TREESTORE(te);
+ Scene *sce;
+ Base *base;
+ Object *ob= NULL;
+
+ /* if id is not object, we search back */
+ if(te->idcode==ID_OB) ob= (Object *)tselem->id;
+ else {
+ ob= (Object *)outliner_search_back(soops, te, ID_OB);
+ if(ob==OBACT) return;
+ }
+ if(ob==NULL) return;
+
+ sce= (Scene *)outliner_search_back(soops, te, ID_SCE);
+ if(sce && G.scene != sce) {
+ if(G.obedit) exit_editmode(EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR);
+ set_scene(sce);
+ }
+
+ /* find associated base in current scene */
+ for(base= FIRSTBASE; base; base= base->next)
+ if(base->object==ob) break;
+ if(base) {
+ if(G.qual & LR_SHIFTKEY) {
+ /* swap select */
+ if(base->flag & SELECT) base->flag &= ~SELECT;
+ else if ((base->object->restrictflag & OB_RESTRICT_VIEW)==0) base->flag |= SELECT;
+ base->object->flag= base->flag;
+ }
+ else {
+ Base *b;
+ /* deleselect all */
+ for(b= FIRSTBASE; b; b= b->next) {
+ b->flag &= ~SELECT;
+ b->object->flag= b->flag;
+ }
+ if ((base->object->restrictflag & OB_RESTRICT_VIEW)==0) {
+ base->flag |= SELECT;
+ base->object->flag |= SELECT;
+ }
+ }
+ set_active_base(base); /* editview.c */
+
+ allqueue(REDRAWVIEW3D, 1);
+ allqueue(REDRAWOOPS, 0);
+ allqueue(REDRAWINFO, 1);
+ }
+
+ if(ob!=G.obedit) exit_editmode(EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR);
+}
+
+static int tree_element_active_material(SpaceOops *soops, TreeElement *te, int set)
+{
+ TreeElement *tes;
+ Object *ob;
+
+ /* we search for the object parent */
+ ob= (Object *)outliner_search_back(soops, te, ID_OB);
+ if(ob==NULL || ob!=OBACT) return 0; // just paranoia
+
+ /* searching in ob mat array? */
+ tes= te->parent;
+ if(tes->idcode==ID_OB) {
+ if(set) {
+ ob->actcol= te->index+1;
+ ob->colbits |= (1<<te->index); // make ob material active too
+ }
+ else {
+ if(ob->actcol == te->index+1)
+ if(ob->colbits & (1<<te->index)) return 1;
+ }
+ }
+ /* or we search for obdata material */
+ else {
+ if(set) {
+ ob->actcol= te->index+1;
+ ob->colbits &= ~(1<<te->index); // make obdata material active too
+ }
+ else {
+ if(ob->actcol == te->index+1)
+ if( (ob->colbits & (1<<te->index))==0 ) return 1;
+ }
+ }
+ if(set) {
+ extern_set_butspace(F5KEY, 0); // force shading buttons
+ BIF_preview_changed(ID_MA);
+ allqueue(REDRAWBUTSSHADING, 1);
+ allqueue(REDRAWNODE, 0);
+ allqueue(REDRAWOOPS, 0);
+ allqueue(REDRAWIPO, 0);
+ }
+ return 0;
+}
+
+static int tree_element_active_texture(SpaceOops *soops, TreeElement *te, int set)
+{
+ TreeElement *tep;
+ TreeStoreElem *tselem, *tselemp;
+ Object *ob=OBACT;
+ ScrArea *sa;
+ SpaceButs *sbuts=NULL;
+
+ if(ob==NULL) return 0; // no active object
+
+ tselem= TREESTORE(te);
+
+ /* find buttons area (note, this is undefined really still, needs recode in blender) */
+ sa= G.curscreen->areabase.first;
+ while(sa) {
+ if(sa->spacetype==SPACE_BUTS) break;
+ sa= sa->next;
+ }
+ if(sa) sbuts= sa->spacedata.first;
+
+ /* where is texture linked to? */
+ tep= te->parent;
+ tselemp= TREESTORE(tep);
+
+ if(tep->idcode==ID_WO) {
+ World *wrld= (World *)tselemp->id;
+
+ if(set) {
+ if(sbuts) {
+ sbuts->tabo= TAB_SHADING_TEX; // hack from header_buttonswin.c
+ sbuts->texfrom= 1;
+ }
+ extern_set_butspace(F6KEY, 0); // force shading buttons texture
+ wrld->texact= te->index;
+ }
+ else if(tselemp->id == (ID *)(G.scene->world)) {
+ if(wrld->texact==te->index) return 1;
+ }
+ }
+ else if(tep->idcode==ID_LA) {
+ Lamp *la= (Lamp *)tselemp->id;
+ if(set) {
+ if(sbuts) {
+ sbuts->tabo= TAB_SHADING_TEX; // hack from header_buttonswin.c
+ sbuts->texfrom= 2;
+ }
+ extern_set_butspace(F6KEY, 0); // force shading buttons texture
+ la->texact= te->index;
+ }
+ else {
+ if(tselemp->id == ob->data) {
+ if(la->texact==te->index) return 1;
+ }
+ }
+ }
+ else if(tep->idcode==ID_MA) {
+ Material *ma= (Material *)tselemp->id;
+ if(set) {
+ if(sbuts) {
+ //sbuts->tabo= TAB_SHADING_TEX; // hack from header_buttonswin.c
+ sbuts->texfrom= 0;
+ }
+ extern_set_butspace(F6KEY, 0); // force shading buttons texture
+ ma->texact= te->index;
+
+ /* also set active material */
+ ob->actcol= tep->index+1;
+ }
+ else if(tep->flag & TE_ACTIVE) { // this is active material
+ if(ma->texact==te->index) return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+static int tree_element_active_lamp(SpaceOops *soops, TreeElement *te, int set)
+{
+ Object *ob;
+
+ /* we search for the object parent */
+ ob= (Object *)outliner_search_back(soops, te, ID_OB);
+ if(ob==NULL || ob!=OBACT) return 0; // just paranoia
+
+ if(set) {
+ extern_set_butspace(F5KEY, 0);
+ BIF_preview_changed(ID_LA);
+ allqueue(REDRAWBUTSSHADING, 1);
+ allqueue(REDRAWOOPS, 0);
+ allqueue(REDRAWIPO, 0);
+ }
+ else return 1;
+
+ return 0;
+}
+
+static int tree_element_active_world(SpaceOops *soops, TreeElement *te, int set)
+{
+ TreeElement *tep;
+ TreeStoreElem *tselem=NULL;
+ Scene *sce=NULL;
+
+ tep= te->parent;
+ if(tep) {
+ tselem= TREESTORE(tep);
+ sce= (Scene *)tselem->id;
+ }
+
+ if(set) { // make new scene active
+ if(sce && G.scene != sce) {
+ if(G.obedit) exit_editmode(EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR);
+ set_scene(sce);
+ }
+ }
+
+ if(tep==NULL || tselem->id == (ID *)G.scene) {
+ if(set) {
+ extern_set_butspace(F8KEY, 0);
+ }
+ else {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int tree_element_active_ipo(SpaceOops *soops, TreeElement *te, int set)
+{
+ TreeElement *tes;
+ TreeStoreElem *tselems=NULL;
+ Object *ob;
+
+ /* we search for the object parent */
+ ob= (Object *)outliner_search_back(soops, te, ID_OB);
+ if(ob==NULL || ob!=OBACT) return 0; // just paranoia
+
+ /* the parent of ipo */
+ tes= te->parent;
+ tselems= TREESTORE(tes);
+
+ if(set) {
+ if(tes->idcode==ID_AC) {
+ if(ob->ipoflag & OB_ACTION_OB)
+ ob->ipowin= ID_OB;
+ else if(ob->ipoflag & OB_ACTION_KEY)
+ ob->ipowin= ID_KE;
+ else
+ ob->ipowin= ID_PO;
+ }
+ else ob->ipowin= tes->idcode;
+
+ if(ob->ipowin==ID_MA) tree_element_active_material(soops, tes, 1);
+ else if(ob->ipowin==ID_AC) {
+ bActionChannel *chan;
+ short a=0;
+ for(chan=ob->action->chanbase.first; chan; chan= chan->next) {
+ if(a==te->index) break;
+ if(chan->ipo) a++;
+ }
+ deselect_actionchannels(ob->action, 0);
+ select_channel(ob->action, chan, SELECT_ADD);
+ allqueue(REDRAWACTION, ob->ipowin);
+ allqueue(REDRAWVIEW3D, ob->ipowin);
+ }
+
+ allqueue(REDRAWIPO, ob->ipowin);
+ }
+ else {
+ if(tes->idcode==ID_AC) {
+ if(ob->ipoflag & OB_ACTION_OB)
+ return ob->ipowin==ID_OB;
+ else if(ob->ipoflag & OB_ACTION_KEY)
+ return ob->ipowin==ID_KE;
+ else if(ob->ipowin==ID_AC) {
+ bActionChannel *chan;
+ short a=0;
+ for(chan=ob->action->chanbase.first; chan; chan= chan->next) {
+ if(a==te->index) break;
+ if(chan->ipo) a++;
+ }
+ if(chan==get_hilighted_action_channel(ob->action)) return 1;
+ }
+ }
+ else if(ob->ipowin==tes->idcode) {
+ if(ob->ipowin==ID_MA) {
+ Material *ma= give_current_material(ob, ob->actcol);
+ if(ma==(Material *)tselems->id) return 1;
+ }
+ else return 1;
+ }
+ }
+ return 0;
+}
+
+static int tree_element_active_defgroup(TreeElement *te, TreeStoreElem *tselem, int set)
+{
+ Object *ob;
+
+ /* id in tselem is object */
+ ob= (Object *)tselem->id;
+ if(set) {
+ ob->actdef= te->index+1;
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, ob->ipowin);
+ }
+ else {
+ if(ob==OBACT)
+ if(ob->actdef== te->index+1) return 1;
+ }
+ return 0;
+}
+
+static int tree_element_active_nla_action(TreeElement *te, TreeStoreElem *tselem, int set)
+{
+ if(set) {
+ bActionStrip *strip= te->directdata;
+ if(strip) {
+ deselect_nlachannel_keys(0);
+ strip->flag |= ACTSTRIP_SELECT;
+ allqueue(REDRAWNLA, 0);
+ }
+ }
+ else {
+ /* id in tselem is action */
+ bActionStrip *strip= te->directdata;
+ if(strip) {
+ if(strip->flag & ACTSTRIP_SELECT) return 1;
+ }
+ }
+ return 0;
+}
+
+static int tree_element_active_posechannel(TreeElement *te, TreeStoreElem *tselem, int set)
+{
+ Object *ob= (Object *)tselem->id;
+ bPoseChannel *pchan= te->directdata;
+
+ if(set) {
+ if(!(pchan->bone->flag & BONE_HIDDEN_P)) {
+
+ if(G.qual & LR_SHIFTKEY) deselectall_posearmature(ob, 2, 0); // 2 = clear active tag
+ else deselectall_posearmature(ob, 0, 0); // 0 = deselect
+ pchan->bone->flag |= BONE_SELECTED|BONE_ACTIVE;
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWOOPS, 0);
+ allqueue(REDRAWACTION, 0);
+ }
+ }
+ else {
+ if(ob==OBACT && ob->pose) {
+ if (pchan->bone->flag & BONE_SELECTED) return 1;
+ }
+ }
+ return 0;
+}
+
+static int tree_element_active_bone(TreeElement *te, TreeStoreElem *tselem, int set)
+{
+ bArmature *arm= (bArmature *)tselem->id;
+ Bone *bone= te->directdata;
+
+ if(set) {
+ if(!(bone->flag & BONE_HIDDEN_P)) {
+ if(G.qual & LR_SHIFTKEY) deselectall_posearmature(OBACT, 2, 0); // 2 is clear active tag
+ else deselectall_posearmature(OBACT, 0, 0);
+ bone->flag |= BONE_SELECTED|BONE_ACTIVE;
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWOOPS, 0);
+ allqueue(REDRAWACTION, 0);
+ }
+ }
+ else {
+ Object *ob= OBACT;
+
+ if(ob && ob->data==arm) {
+ if (bone->flag & BONE_SELECTED) return 1;
+ }
+ }
+ return 0;
+}
+
+
+/* ebones only draw in editmode armature */
+static int tree_element_active_ebone(TreeElement *te, TreeStoreElem *tselem, int set)
+{
+ EditBone *ebone= te->directdata;
+
+ if(set) {
+ if(!(ebone->flag & BONE_HIDDEN_A)) {
+
+ if(G.qual & LR_SHIFTKEY) deselectall_armature(2, 0); // only clear active tag
+ else deselectall_armature(0, 0); // deselect
+
+ ebone->flag |= BONE_SELECTED|BONE_ROOTSEL|BONE_TIPSEL|BONE_ACTIVE;
+ // flush to parent?
+ if(ebone->parent && (ebone->flag & BONE_CONNECTED)) ebone->parent->flag |= BONE_TIPSEL;
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWOOPS, 0);
+ allqueue(REDRAWACTION, 0);
+ }
+ }
+ else {
+ if (ebone->flag & BONE_SELECTED) return 1;
+ }
+ return 0;
+}
+
+static int tree_element_active_modifier(TreeElement *te, TreeStoreElem *tselem, int set)
+{
+ if(set) {
+ extern_set_butspace(F9KEY, 0);
+ }
+
+ return 0;
+}
+
+static int tree_element_active_constraint(TreeElement *te, TreeStoreElem *tselem, int set)
+{
+ if(set) {
+ extern_set_butspace(F7KEY, 0);
+ }
+
+ return 0;
+}
+
+static int tree_element_active_text(SpaceOops *soops, TreeElement *te, int set)
+{
+ ScrArea *sa=NULL;
+
+ for(sa= G.curscreen->areabase.first; sa; sa= sa->next) {
+ if(sa->spacetype==SPACE_TEXT) break;
+ }
+ if(sa) {
+ SpaceText *st= sa->spacedata.first;
+ TreeStoreElem *tselem= TREESTORE(te);
+
+ if(set) {
+ st->text= (Text *)tselem->id;
+ st->top= 0;
+ scrarea_queue_redraw(sa);
+ }
+ else if(st->text==(Text *)tselem->id) return 1;
+ }
+ return 0;
+}
+
+/* generic call for ID data check or make/check active in UI */
+static int tree_element_active(SpaceOops *soops, TreeElement *te, int set)
+{
+
+ switch(te->idcode) {
+ case ID_MA:
+ return tree_element_active_material(soops, te, set);
+ case ID_WO:
+ return tree_element_active_world(soops, te, set);
+ case ID_LA:
+ return tree_element_active_lamp(soops, te, set);
+ case ID_IP:
+ return tree_element_active_ipo(soops, te, set);
+ case ID_TE:
+ return tree_element_active_texture(soops, te, set);
+ case ID_TXT:
+ return tree_element_active_text(soops, te, set);
+ }
+ return 0;
+}
+
+static int tree_element_active_pose(TreeElement *te, TreeStoreElem *tselem, int set)
+{
+ Object *ob= (Object *)tselem->id;
+
+ if(set) {
+ if(G.obedit) exit_editmode(EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR);
+ if(ob->flag & OB_POSEMODE) exit_posemode();
+ else enter_posemode();
+ }
+ else {
+ if(ob->flag & OB_POSEMODE) return 1;
+ }
+ return 0;
+}
+
+/* generic call for non-id data to make/check active in UI */
+static int tree_element_type_active(SpaceOops *soops, TreeElement *te, TreeStoreElem *tselem, int set)
+{
+
+ switch(tselem->type) {
+ case TSE_NLA_ACTION:
+ return tree_element_active_nla_action(te, tselem, set);
+ case TSE_DEFGROUP:
+ return tree_element_active_defgroup(te, tselem, set);
+ case TSE_BONE:
+ return tree_element_active_bone(te, tselem, set);
+ case TSE_EBONE:
+ return tree_element_active_ebone(te, tselem, set);
+ case TSE_MODIFIER:
+ return tree_element_active_modifier(te, tselem, set);
+ case TSE_LINKED_OB:
+ if(set) tree_element_active_object(soops, te);
+ else if(tselem->id==(ID *)OBACT) return 1;
+ break;
+ case TSE_POSE_BASE:
+ return tree_element_active_pose(te, tselem, set);
+ break;
+ case TSE_POSE_CHANNEL:
+ return tree_element_active_posechannel(te, tselem, set);
+ case TSE_CONSTRAINT:
+ return tree_element_active_constraint(te, tselem, set);
+ case TSE_R_LAYER:
+ return tree_element_active_renderlayer(te, tselem, set);
+ }
+ return 0;
+}
+
+#ifdef WITH_VERSE
+static void verse_operation_menu(TreeElement *te)
+{
+ short event=0;
+ if(te->idcode==ID_VS) {
+ struct VerseSession *session = (VerseSession*)te->directdata;
+ struct VNode *vnode;
+ if(!(session->flag & VERSE_AUTOSUBSCRIBE)) {
+ event = pupmenu("VerseSession %t| End Session %x1| Subscribe to All Nodes %x2| Start Autosubscribe %x3");
+ }
+ else {
+ event = pupmenu("VerseSession %t| End Session %x1| Subscribe to All Nodes %x2| Stop Autosubscribe %x4");
+ }
+ switch(event) {
+ case 1:
+ end_verse_session(session);
+ break;
+ case 2:
+ vnode = session->nodes.lb.first;
+ while(vnode) {
+ b_verse_pop_node(vnode);
+ vnode = vnode->next;
+ }
+ break;
+ case 3:
+ vnode = session->nodes.lb.first;
+ while(vnode) {
+ b_verse_pop_node(vnode);
+ vnode = vnode->next;
+ }
+ session->flag |= VERSE_AUTOSUBSCRIBE;
+ break;
+ case 4:
+ session->flag &= ~VERSE_AUTOSUBSCRIBE;
+ break;
+ }
+ }
+ else if(te->idcode==ID_VN) {
+ struct VNode *vnode = (VNode*)te->directdata;
+ event = pupmenu("VerseNode %t| Subscribe %x1| Unsubscribe %x2");
+ switch(event) {
+ case 1:
+ b_verse_pop_node(vnode);
+ break;
+ case 2:
+ /* Global */
+ b_verse_unsubscribe(vnode);
+ break;
+ }
+ }
+ else if(te->idcode==ID_MS) {
+ event = pupmenu("Verse Master Server %t| Refresh %x1");
+ b_verse_ms_get();
+ }
+ else if(te->idcode==ID_SS) {
+ struct VerseServer *vserver = (VerseServer*)te->directdata;
+
+ if(!(vserver->flag & VERSE_CONNECTING) && !(vserver->flag & VERSE_CONNECTED)) {
+ event = pupmenu("VerseServer %t| Connect %x1");
+ } else if((vserver->flag & VERSE_CONNECTING) && !(vserver->flag & VERSE_CONNECTED)) {
+ event = pupmenu("VerseServer %t| Connecting %x2");
+ } else if(!(vserver->flag & VERSE_CONNECTING) && (vserver->flag & VERSE_CONNECTED)) {
+ event = pupmenu("VerseServer %t| Disconnect %x3");
+ }
+ switch(event) {
+ case 1:
+ b_verse_connect(vserver->ip);
+ vserver->flag |= VERSE_CONNECTING;
+ break;
+ case 2:
+ break;
+ case 3:
+ end_verse_session(vserver->session);
+ break;
+ }
+ }
+}
+#endif
+
+
+static int do_outliner_mouse_event(SpaceOops *soops, TreeElement *te, short event, float *mval)
+{
+
+ if(mval[1]>te->ys && mval[1]<te->ys+OL_H) {
+ TreeStoreElem *tselem= TREESTORE(te);
+ int openclose= 0;
+
+ /* open close icon, three things to check */
+ if(event==RETKEY || event==PADENTER) openclose= 1; // enter opens/closes always
+ else if((te->flag & TE_ICONROW)==0) { // hidden icon, no open/close
+ if( mval[0]>te->xs && mval[0]<te->xs+OL_X) openclose= 1;
+ }
+
+ if(openclose) {
+
+ /* all below close/open? */
+ if( (G.qual & LR_SHIFTKEY) ) {
+ tselem->flag &= ~TSE_CLOSED;
+ outliner_set_flag(soops, &te->subtree, TSE_CLOSED, !outliner_has_one_flag(soops, &te->subtree, TSE_CLOSED, 1));
+ }
+ else {
+ if(tselem->flag & TSE_CLOSED) tselem->flag &= ~TSE_CLOSED;
+ else tselem->flag |= TSE_CLOSED;
+
+ }
+
+ return 1;
+ }
+ /* name and first icon */
+ else if(mval[0]>te->xs && mval[0]<te->xend) {
+
+ /* activate a name button? */
+ if(event==LEFTMOUSE) {
+
+ if (G.qual & LR_CTRLKEY) {
+ if(ELEM8(tselem->type, TSE_NLA, TSE_DEFGROUP_BASE, TSE_CONSTRAINT_BASE, TSE_MODIFIER_BASE, TSE_SCRIPT_BASE, TSE_POSE_BASE, TSE_R_LAYER_BASE, TSE_R_PASS))
+ error("Cannot edit builtin name");
+ else if(tselem->id->lib)
+ error_libdata();
+ else {
+ tselem->flag |= TSE_TEXTBUT;
+ }
+ } else {
+
+ if (G.qual & LR_SHIFTKEY) {
+ if(tselem->id->lib && tselem->type==0) {
+ notice(tselem->id->lib->name);
+ }
+ }
+ /* always makes active object */
+ tree_element_active_object(soops, te);
+
+ if(tselem->type==0) { // the lib blocks
+ /* editmode? */
+ if(te->idcode==ID_SCE) {
+ if(G.scene!=(Scene *)tselem->id) {
+ if(G.obedit) exit_editmode(EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR);
+ set_scene((Scene *)tselem->id);
+ }
+ }
+ else if(ELEM5(te->idcode, ID_ME, ID_CU, ID_MB, ID_LT, ID_AR)) {
+ if(G.obedit) exit_editmode(EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR);
+ else {
+ enter_editmode(EM_WAITCURSOR);
+ extern_set_butspace(F9KEY, 0);
+ }
+ } else { // rest of types
+ tree_element_active(soops, te, 1);
+ }
+
+ }
+ else tree_element_type_active(soops, te, tselem, 1);
+ }
+ }
+ else if(event==RIGHTMOUSE) {
+#ifdef WITH_VERSE
+ if(ELEM4(te->idcode, ID_VS, ID_VN, ID_MS, ID_SS))
+ verse_operation_menu(te);
+ else
+#endif
+ /* select object that's clicked on and popup context menu */
+ if (!(tselem->flag & TSE_SELECTED)) {
+
+ if ( outliner_has_one_flag(soops, &soops->tree, TSE_SELECTED, 1) )
+ outliner_set_flag(soops, &soops->tree, TSE_SELECTED, 0);
+
+ tselem->flag |= TSE_SELECTED;
+ /* redraw, same as outliner_select function */
+ soops->storeflag |= SO_TREESTORE_REDRAW;
+ scrarea_do_windraw(soops->area);
+ screen_swapbuffers();
+ }
+
+ outliner_operation_menu(soops->area);
+ }
+ return 1;
+ }
+ }
+
+ for(te= te->subtree.first; te; te= te->next) {
+ if(do_outliner_mouse_event(soops, te, event, mval)) return 1;
+ }
+ return 0;
+}
+
+/* event can enterkey, then it opens/closes */
+void outliner_mouse_event(ScrArea *sa, short event)
+{
+ SpaceOops *soops= sa->spacedata.first;
+ TreeElement *te;
+ float fmval[2];
+ short mval[2];
+
+ getmouseco_areawin(mval);
+ areamouseco_to_ipoco(&soops->v2d, mval, fmval, fmval+1);
+
+ for(te= soops->tree.first; te; te= te->next) {
+ if(do_outliner_mouse_event(soops, te, event, fmval)) break;
+ }
+
+ if(te) {
+ BIF_undo_push("Outliner click event");
+ allqueue(REDRAWOOPS, 0);
+ }
+ else
+ outliner_select(sa);
+
+}
+/* recursive helper for function below */
+static void outliner_set_coordinates_element(SpaceOops *soops, TreeElement *te, int startx, int *starty)
+{
+ TreeStoreElem *tselem= TREESTORE(te);
+
+ /* store coord and continue, we need coordinates for elements outside view too */
+ te->xs= startx;
+ te->ys= *starty;
+ *starty-= OL_H;
+
+ if((tselem->flag & TSE_CLOSED)==0) {
+ TreeElement *ten;
+ for(ten= te->subtree.first; ten; ten= ten->next) {
+ outliner_set_coordinates_element(soops, ten, startx+OL_X, starty);
+ }
+ }
+
+}
+
+/* to retrieve coordinates with redrawing the entire tree */
+static void outliner_set_coordinates(SpaceOops *soops)
+{
+ TreeElement *te;
+ int starty= soops->v2d.tot.ymax-OL_H;
+ int startx= 0;
+
+ for(te= soops->tree.first; te; te= te->next) {
+ outliner_set_coordinates_element(soops, te, startx, &starty);
+ }
+}
+
+static TreeElement *outliner_find_id(SpaceOops *soops, ListBase *lb, ID *id)
+{
+ TreeElement *te, *tes;
+ TreeStoreElem *tselem;
+
+ for(te= lb->first; te; te= te->next) {
+ tselem= TREESTORE(te);
+ if(tselem->type==0) {
+ if(tselem->id==id) return te;
+ /* only deeper on scene or object */
+ if( te->idcode==ID_OB || te->idcode==ID_SCE) {
+ tes= outliner_find_id(soops, &te->subtree, id);
+ if(tes) return tes;
+ }
+ }
+ }
+ return NULL;
+}
+
+void outliner_show_active(struct ScrArea *sa)
+{
+ SpaceOops *so= sa->spacedata.first;
+ TreeElement *te;
+ int xdelta, ytop;
+
+ if(OBACT == NULL) return;
+
+ te= outliner_find_id(so, &so->tree, (ID *)OBACT);
+ if(te) {
+ /* make te->ys center of view */
+ ytop= te->ys + (so->v2d.mask.ymax-so->v2d.mask.ymin)/2;
+ if(ytop>0) ytop= 0;
+ so->v2d.cur.ymax= ytop;
+ so->v2d.cur.ymin= ytop-(so->v2d.mask.ymax-so->v2d.mask.ymin);
+
+ /* make te->xs ==> te->xend center of view */
+ xdelta = te->xs - so->v2d.cur.xmin;
+ so->v2d.cur.xmin += xdelta;
+ so->v2d.cur.xmax += xdelta;
+
+ so->storeflag |= SO_TREESTORE_REDRAW;
+ scrarea_queue_redraw(sa);
+ }
+}
+
+void outliner_show_selected(struct ScrArea *sa)
+{
+ SpaceOops *so= sa->spacedata.first;
+ TreeElement *te;
+ int xdelta, ytop;
+
+ te= outliner_find_id(so, &so->tree, (ID *)OBACT);
+ if(te) {
+ /* make te->ys center of view */
+ ytop= te->ys + (so->v2d.mask.ymax-so->v2d.mask.ymin)/2;
+ if(ytop>0) ytop= 0;
+ so->v2d.cur.ymax= ytop;
+ so->v2d.cur.ymin= ytop-(so->v2d.mask.ymax-so->v2d.mask.ymin);
+
+ /* make te->xs ==> te->xend center of view */
+ xdelta = te->xs - so->v2d.cur.xmin;
+ so->v2d.cur.xmin += xdelta;
+ so->v2d.cur.xmax += xdelta;
+
+ so->storeflag |= SO_TREESTORE_REDRAW;
+ scrarea_queue_redraw(sa);
+ }
+}
+
+
+/* find next element that has this name */
+static TreeElement *outliner_find_named(SpaceOops *soops, ListBase *lb, char *name, int flags, TreeElement *prev, int *prevFound)
+{
+ TreeElement *te, *tes;
+
+ for (te= lb->first; te; te= te->next) {
+ int found;
+
+ /* determine if match */
+ if(flags==OL_FIND)
+ found= BLI_strcasestr(te->name, name)!=NULL;
+ else if(flags==OL_FIND_CASE)
+ found= strstr(te->name, name)!=NULL;
+ else if(flags==OL_FIND_COMPLETE)
+ found= BLI_strcasecmp(te->name, name)==0;
+ else
+ found= strcmp(te->name, name)==0;
+
+ if(found) {
+ /* name is right, but is element the previous one? */
+ if (prev) {
+ if ((te != prev) && (*prevFound))
+ return te;
+ if (te == prev) {
+ *prevFound = 1;
+ }
+ }
+ else
+ return te;
+ }
+
+ tes= outliner_find_named(soops, &te->subtree, name, flags, prev, prevFound);
+ if(tes) return tes;
+ }
+
+ /* nothing valid found */
+ return NULL;
+}
+
+/* tse is not in the treestore, we use its contents to find a match */
+static TreeElement *outliner_find_tse(SpaceOops *soops, TreeStoreElem *tse)
+{
+ TreeStore *ts= soops->treestore;
+ TreeStoreElem *tselem;
+ int a;
+
+ if(tse->id==NULL) return NULL;
+
+ /* check if 'tse' is in treestore */
+ tselem= ts->data;
+ for(a=0; a<ts->usedelem; a++, tselem++) {
+ if(tselem->id==tse->id) {
+ if((tse->type==0 && tselem->type==0) || (tselem->type==tse->type && tselem->nr==tse->nr)) {
+ break;
+ }
+ }
+ }
+ if(tselem)
+ return outliner_find_tree_element(&soops->tree, a);
+
+ return NULL;
+}
+
+
+/* Called to find an item based on name.
+ */
+void outliner_find_panel(struct ScrArea *sa, int again, int flags)
+{
+ SpaceOops *soops= sa->spacedata.first;
+ TreeElement *te= NULL;
+ TreeElement *last_find;
+ TreeStoreElem *tselem;
+ int ytop, xdelta, prevFound=0;
+ char name[33];
+
+ /* get last found tree-element based on stored search_tse */
+ last_find= outliner_find_tse(soops, &soops->search_tse);
+
+ /* determine which type of search to do */
+ if (again && last_find) {
+ /* no popup panel - previous + user wanted to search for next after previous */
+ BLI_strncpy(name, soops->search_string, 33);
+ flags= soops->search_flags;
+
+ /* try to find matching element */
+ te= outliner_find_named(soops, &soops->tree, name, flags, last_find, &prevFound);
+ if (te==NULL) {
+ /* no more matches after previous, start from beginning again */
+ prevFound= 1;
+ te= outliner_find_named(soops, &soops->tree, name, flags, last_find, &prevFound);
+ }
+ }
+ else {
+ /* pop up panel - no previous, or user didn't want search after previous */
+ strcpy(name, "");
+ if (sbutton(name, 0, sizeof(name)-1, "Find: ") && name[0]) {
+ te= outliner_find_named(soops, &soops->tree, name, flags, NULL, &prevFound);
+ }
+ else return; /* XXX RETURN! XXX */
+ }
+
+ /* do selection and reveil */
+ if (te) {
+ tselem= TREESTORE(te);
+ if (tselem) {
+ /* expand branches so that it will be visible, we need to get correct coordinates */
+ if( outliner_open_back(soops, te))
+ outliner_set_coordinates(soops);
+
+ /* deselect all visible, and select found element */
+ outliner_set_flag(soops, &soops->tree, TSE_SELECTED, 0);
+ tselem->flag |= TSE_SELECTED;
+
+ /* make te->ys center of view */
+ ytop= te->ys + (soops->v2d.mask.ymax-soops->v2d.mask.ymin)/2;
+ if(ytop>0) ytop= 0;
+ soops->v2d.cur.ymax= ytop;
+ soops->v2d.cur.ymin= ytop-(soops->v2d.mask.ymax-soops->v2d.mask.ymin);
+
+ /* make te->xs ==> te->xend center of view */
+ xdelta = te->xs - soops->v2d.cur.xmin;
+ soops->v2d.cur.xmin += xdelta;
+ soops->v2d.cur.xmax += xdelta;
+
+ /* store selection */
+ soops->search_tse= *tselem;
+
+ BLI_strncpy(soops->search_string, name, 33);
+ soops->search_flags= flags;
+
+ /* redraw */
+ soops->storeflag |= SO_TREESTORE_REDRAW;
+ scrarea_queue_redraw(sa);
+ }
+ }
+ else {
+ /* no tree-element found */
+ error("Not found: %s", name);
+ }
+}
+
+static int subtree_has_objects(SpaceOops *soops, ListBase *lb)
+{
+ TreeElement *te;
+ TreeStoreElem *tselem;
+
+ for(te= lb->first; te; te= te->next) {
+ tselem= TREESTORE(te);
+ if(tselem->type==0 && te->idcode==ID_OB) return 1;
+ if( subtree_has_objects(soops, &te->subtree)) return 1;
+ }
+ return 0;
+}
+
+static void tree_element_show_hierarchy(SpaceOops *soops, ListBase *lb)
+{
+ TreeElement *te;
+ TreeStoreElem *tselem;
+
+ /* open all object elems, close others */
+ for(te= lb->first; te; te= te->next) {
+ tselem= TREESTORE(te);
+
+ if(tselem->type==0) {
+ if(te->idcode==ID_SCE) {
+ if(tselem->id!=(ID *)G.scene) tselem->flag |= TSE_CLOSED;
+ else tselem->flag &= ~TSE_CLOSED;
+ }
+ else if(te->idcode==ID_OB) {
+ if(subtree_has_objects(soops, &te->subtree)) tselem->flag &= ~TSE_CLOSED;
+ else tselem->flag |= TSE_CLOSED;
+ }
+ }
+ else tselem->flag |= TSE_CLOSED;
+
+ if(tselem->flag & TSE_CLOSED); else tree_element_show_hierarchy(soops, &te->subtree);
+ }
+
+}
+
+/* show entire object level hierarchy */
+void outliner_show_hierarchy(struct ScrArea *sa)
+{
+ SpaceOops *so= sa->spacedata.first;
+
+ tree_element_show_hierarchy(so, &so->tree);
+ scrarea_queue_redraw(sa);
+
+ BIF_undo_push("Outliner show hierarchy");
+}
+
+static void do_outliner_select(SpaceOops *soops, ListBase *lb, float y1, float y2, short *selecting)
+{
+ TreeElement *te;
+ TreeStoreElem *tselem;
+
+ if(y1>y2) SWAP(float, y1, y2);
+
+ for(te= lb->first; te; te= te->next) {
+ tselem= TREESTORE(te);
+
+ if(te->ys + OL_H < y1) return;
+ if(te->ys < y2) {
+ if((te->flag & TE_ICONROW)==0) {
+ if(*selecting == -1) {
+ if( tselem->flag & TSE_SELECTED) *selecting= 0;
+ else *selecting= 1;
+ }
+ if(*selecting) tselem->flag |= TSE_SELECTED;
+ else tselem->flag &= ~TSE_SELECTED;
+ }
+ }
+ if((tselem->flag & TSE_CLOSED)==0) do_outliner_select(soops, &te->subtree, y1, y2, selecting);
+ }
+}
+
+/* its own redraw loop... urm */
+void outliner_select(struct ScrArea *sa )
+{
+ SpaceOops *so= sa->spacedata.first;
+ float fmval[2], y1, y2;
+ short mval[2], yo=-1, selecting= -1;
+
+ getmouseco_areawin(mval);
+ areamouseco_to_ipoco(&so->v2d, mval, fmval, fmval+1);
+ y1= fmval[1];
+
+ while (get_mbut() & (L_MOUSE|R_MOUSE)) {
+ getmouseco_areawin(mval);
+ areamouseco_to_ipoco(&so->v2d, mval, fmval, fmval+1);
+ y2= fmval[1];
+
+ if(yo!=mval[1]) {
+ /* select the 'ouliner row' */
+ do_outliner_select(so, &so->tree, y1, y2, &selecting);
+ yo= mval[1];
+
+ so->storeflag |= SO_TREESTORE_REDRAW;
+ scrarea_do_windraw(sa);
+ screen_swapbuffers();
+
+ y1= y2;
+ }
+ else PIL_sleep_ms(30);
+ }
+
+ BIF_undo_push("Outliner selection");
+
+}
+
+/* ************ SELECTION OPERATIONS ********* */
+
+static int scenelevel=0, objectlevel=0, idlevel=0, datalevel=0; // globals, euh... you can do better
+
+static void set_operation_types(SpaceOops *soops, ListBase *lb)
+{
+ TreeElement *te;
+ TreeStoreElem *tselem;
+
+ for(te= lb->first; te; te= te->next) {
+ tselem= TREESTORE(te);
+ if(tselem->flag & TSE_SELECTED) {
+ if(tselem->type) {
+#ifdef WITH_VERSE
+ if(te->idcode==ID_VS) datalevel= TSE_VERSE_SESSION;
+ else if(te->idcode==ID_VN) datalevel= TSE_VERSE_OBJ_NODE;
+ else if(datalevel==0) datalevel= tselem->type;
+#else
+ if(datalevel==0) datalevel= tselem->type;
+#endif
+ else if(datalevel!=tselem->type) datalevel= -1;
+ }
+ else {
+ int idcode= GS(tselem->id->name);
+ switch(idcode) {
+ case ID_SCE:
+ scenelevel= 1;
+ break;
+ case ID_OB:
+ objectlevel= 1;
+ break;
+
+ case ID_ME: case ID_CU: case ID_MB: case ID_LT:
+ case ID_LA: case ID_AR: case ID_CA:
+ case ID_MA: case ID_TE: case ID_IP: case ID_IM:
+ case ID_SO: case ID_KE: case ID_WO: case ID_AC:
+ case ID_NLA: case ID_TXT: case ID_GR:
+ if(idlevel==0) idlevel= idcode;
+ else if(idlevel!=idcode) idlevel= -1;
+ break;
+ }
+ }
+ }
+ if((tselem->flag & TSE_CLOSED)==0) set_operation_types(soops, &te->subtree);
+ }
+}
+
+static void unlink_material_cb(TreeElement *te, TreeStoreElem *tsep, TreeStoreElem *tselem)
+{
+ Material **matar=NULL;
+ int a, totcol=0;
+
+ if( GS(tsep->id->name)==ID_OB) {
+ Object *ob= (Object *)tsep->id;
+ totcol= ob->totcol;
+ matar= ob->mat;
+ }
+ else if( GS(tsep->id->name)==ID_ME) {
+ Mesh *me= (Mesh *)tsep->id;
+ totcol= me->totcol;
+ matar= me->mat;
+ }
+ else if( GS(tsep->id->name)==ID_CU) {
+ Curve *cu= (Curve *)tsep->id;
+ totcol= cu->totcol;
+ matar= cu->mat;
+ }
+ else if( GS(tsep->id->name)==ID_MB) {
+ MetaBall *mb= (MetaBall *)tsep->id;
+ totcol= mb->totcol;
+ matar= mb->mat;
+ }
+
+ for(a=0; a<totcol; a++) {
+ if(a==te->index && matar[a]) {
+ matar[a]->id.us--;
+ matar[a]= NULL;
+ }
+ }
+}
+
+static void unlink_texture_cb(TreeElement *te, TreeStoreElem *tsep, TreeStoreElem *tselem)
+{
+ MTex **mtex= NULL;
+ int a;
+
+ if( GS(tsep->id->name)==ID_MA) {
+ Material *ma= (Material *)tsep->id;
+ mtex= ma->mtex;
+ }
+ else if( GS(tsep->id->name)==ID_LA) {
+ Lamp *la= (Lamp *)tsep->id;
+ mtex= la->mtex;
+ }
+ else if( GS(tsep->id->name)==ID_WO) {
+ World *wrld= (World *)tsep->id;
+ mtex= wrld->mtex;
+ }
+ else return;
+
+ for(a=0; a<MAX_MTEX; a++) {
+ if(a==te->index && mtex[a]) {
+ if(mtex[a]->tex) {
+ mtex[a]->tex->id.us--;
+ mtex[a]->tex= NULL;
+ }
+ }
+ }
+}
+
+static void unlink_group_cb(TreeElement *te, TreeStoreElem *tsep, TreeStoreElem *tselem)
+{
+ Group *group= (Group *)tselem->id;
+
+ if(tsep) {
+ if( GS(tsep->id->name)==ID_OB) {
+ Object *ob= (Object *)tsep->id;
+ ob->dup_group= NULL;
+ group->id.us--;
+ }
+ }
+ else {
+ unlink_group(group);
+ }
+}
+
+static void outliner_do_libdata_operation(SpaceOops *soops, ListBase *lb,
+ void (*operation_cb)(TreeElement *, TreeStoreElem *, TreeStoreElem *))
+{
+ TreeElement *te;
+ TreeStoreElem *tselem;
+
+ for(te=lb->first; te; te= te->next) {
+ tselem= TREESTORE(te);
+ if(tselem->flag & TSE_SELECTED) {
+ if(tselem->type==0) {
+ TreeStoreElem *tsep= TREESTORE(te->parent);
+ operation_cb(te, tsep, tselem);
+ }
+ }
+ if((tselem->flag & TSE_CLOSED)==0) {
+ outliner_do_libdata_operation(soops, &te->subtree, operation_cb);
+ }
+ }
+}
+
+/* */
+
+static void object_select_cb(TreeElement *te, TreeStoreElem *tsep, TreeStoreElem *tselem)
+{
+ Base *base= (Base *)te->directdata;
+
+ if(base==NULL) base= object_in_scene((Object *)tselem->id, G.scene);
+ if(base && ((base->object->restrictflag & OB_RESTRICT_VIEW)==0)) {
+ base->flag |= SELECT;
+ base->object->flag |= SELECT;
+ }
+}
+
+static void object_deselect_cb(TreeElement *te, TreeStoreElem *tsep, TreeStoreElem *tselem)
+{
+ Base *base= (Base *)te->directdata;
+
+ if(base==NULL) base= object_in_scene((Object *)tselem->id, G.scene);
+ if(base) {
+ base->flag &= ~SELECT;
+ base->object->flag &= ~SELECT;
+ }
+}
+
+static void object_delete_cb(TreeElement *te, TreeStoreElem *tsep, TreeStoreElem *tselem)
+{
+ Base *base= (Base *)te->directdata;
+
+ if(base==NULL) base= object_in_scene((Object *)tselem->id, G.scene);
+ if(base) {
+ // check also library later
+ if(G.obedit==base->object) exit_editmode(EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR);
+
+ if(base==BASACT) {
+ G.f &= ~(G_VERTEXPAINT+G_TEXTUREPAINT+G_WEIGHTPAINT);
+ setcursor_space(SPACE_VIEW3D, CURSOR_STD);
+ }
+
+ free_and_unlink_base(base);
+ te->directdata= NULL;
+ tselem->id= NULL;
+ }
+}
+
+static void id_local_cb(TreeElement *te, TreeStoreElem *tsep, TreeStoreElem *tselem)
+{
+ if(tselem->id->lib && (tselem->id->flag & LIB_EXTERN)) {
+ tselem->id->lib= NULL;
+ tselem->id->flag= LIB_LOCAL;
+ new_id(0, tselem->id, 0);
+ }
+}
+
+static void outliner_do_object_operation(SpaceOops *soops, ListBase *lb,
+ void (*operation_cb)(TreeElement *, TreeStoreElem *, TreeStoreElem *))
+{
+ TreeElement *te;
+ TreeStoreElem *tselem;
+
+ for(te=lb->first; te; te= te->next) {
+ tselem= TREESTORE(te);
+ if(tselem->flag & TSE_SELECTED) {
+ if(tselem->type==0 && te->idcode==ID_OB) {
+ // when objects selected in other scenes... dunno if that should be allowed
+ Scene *sce= (Scene *)outliner_search_back(soops, te, ID_SCE);
+ if(sce && G.scene != sce) set_scene(sce);
+
+ operation_cb(te, NULL, tselem);
+ }
+ }
+ if((tselem->flag & TSE_CLOSED)==0) {
+ outliner_do_object_operation(soops, &te->subtree, operation_cb);
+ }
+ }
+}
+
+static void pchan_cb(int event, TreeElement *te, TreeStoreElem *tselem)
+{
+ bPoseChannel *pchan= (bPoseChannel *)te->directdata;
+
+ if(event==1)
+ pchan->bone->flag |= BONE_SELECTED;
+ else if(event==2)
+ pchan->bone->flag &= ~BONE_SELECTED;
+ else if(event==3) {
+ pchan->bone->flag |= BONE_HIDDEN_P;
+ pchan->bone->flag &= ~BONE_SELECTED;
+ }
+ else if(event==4)
+ pchan->bone->flag &= ~BONE_HIDDEN_P;
+}
+
+static void bone_cb(int event, TreeElement *te, TreeStoreElem *tselem)
+{
+ Bone *bone= (Bone *)te->directdata;
+
+ if(event==1)
+ bone->flag |= BONE_SELECTED;
+ else if(event==2)
+ bone->flag &= ~BONE_SELECTED;
+ else if(event==3) {
+ bone->flag |= BONE_HIDDEN_P;
+ bone->flag &= ~BONE_SELECTED;
+ }
+ else if(event==4)
+ bone->flag &= ~BONE_HIDDEN_P;
+}
+
+static void ebone_cb(int event, TreeElement *te, TreeStoreElem *tselem)
+{
+ EditBone *ebone= (EditBone *)te->directdata;
+
+ if(event==1)
+ ebone->flag |= BONE_SELECTED;
+ else if(event==2)
+ ebone->flag &= ~BONE_SELECTED;
+ else if(event==3) {
+ ebone->flag |= BONE_HIDDEN_A;
+ ebone->flag &= ~BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
+ }
+ else if(event==4)
+ ebone->flag &= ~BONE_HIDDEN_A;
+}
+
+#ifdef WITH_VERSE
+static void vsession_cb(int event, TreeElement *te, TreeStoreElem *tselem)
+{
+/* struct VerseSession *vsession =(VerseSession*)te->directdata;*/
+
+ if(event==1) {
+ printf("\tending verse session\n");
+ }
+}
+#endif
+
+static void outliner_do_data_operation(SpaceOops *soops, int type, int event, ListBase *lb,
+ void (*operation_cb)(int, TreeElement *, TreeStoreElem *))
+{
+ TreeElement *te;
+ TreeStoreElem *tselem;
+
+ for(te=lb->first; te; te= te->next) {
+ tselem= TREESTORE(te);
+ if(tselem->flag & TSE_SELECTED) {
+ if(tselem->type==type) {
+ operation_cb(event, te, tselem);
+ }
+ }
+ if((tselem->flag & TSE_CLOSED)==0) {
+ outliner_do_data_operation(soops, type, event, &te->subtree, operation_cb);
+ }
+ }
+}
+
+void outliner_del(ScrArea *sa)
+{
+ SpaceOops *soops= sa->spacedata.first;
+ outliner_do_object_operation(soops, &soops->tree, object_delete_cb);
+ DAG_scene_sort(G.scene);
+ countall();
+ BIF_undo_push("Delete Objects");
+ allqueue(REDRAWALL, 0);
+}
+
+
+void outliner_operation_menu(ScrArea *sa)
+{
+ SpaceOops *soops= sa->spacedata.first;
+
+ // bad globals
+ scenelevel= objectlevel= idlevel= datalevel=0;
+
+ set_operation_types(soops, &soops->tree);
+
+ if(scenelevel) {
+ if(objectlevel || datalevel || idlevel) error("Mixed selection");
+ //else pupmenu("Scene Operations%t|Delete");
+ }
+ else if(objectlevel) {
+ short event= pupmenu("Select%x1|Deselect%x2|Delete%x4"); /* make local: does not work... it doesn't set lib_extern flags... so data gets lost */
+ if(event>0) {
+ char *str="";
+
+ if(event==1) {
+ Scene *sce= G.scene; // to be able to delete, scenes are set...
+ outliner_do_object_operation(soops, &soops->tree, object_select_cb);
+ if(G.scene != sce) set_scene(sce);
+
+ str= "Select Objects";
+ }
+ else if(event==2) {
+ outliner_do_object_operation(soops, &soops->tree, object_deselect_cb);
+ str= "Deselect Objects";
+ }
+ else if(event==4) {
+ outliner_do_object_operation(soops, &soops->tree, object_delete_cb);
+ DAG_scene_sort(G.scene);
+ str= "Delete Objects";
+ }
+ else if(event==5) { /* disabled, see above (ton) */
+ outliner_do_object_operation(soops, &soops->tree, id_local_cb);
+ str= "Localized Objects";
+ }
+
+ countall();
+
+ BIF_undo_push(str);
+ allqueue(REDRAWALL, 0);
+ }
+ }
+ else if(idlevel) {
+ if(idlevel==-1 || datalevel) error("Mixed selection");
+ else {
+ short event= pupmenu("Unlink %x1|Make Local %x2");
+
+ if(event==1) {
+ switch(idlevel) {
+ case ID_MA:
+ outliner_do_libdata_operation(soops, &soops->tree, unlink_material_cb);
+ BIF_undo_push("Unlink material");
+ allqueue(REDRAWBUTSSHADING, 1);
+ break;
+ case ID_TE:
+ outliner_do_libdata_operation(soops, &soops->tree, unlink_texture_cb);
+ allqueue(REDRAWBUTSSHADING, 1);
+ BIF_undo_push("Unlink texture");
+ break;
+ case ID_GR:
+ outliner_do_libdata_operation(soops, &soops->tree, unlink_group_cb);
+ BIF_undo_push("Unlink group");
+ break;
+ default:
+ error("Not yet...");
+ }
+ allqueue(REDRAWALL, 0);
+ }
+ else if(event==2) {
+ outliner_do_libdata_operation(soops, &soops->tree, id_local_cb);
+ BIF_undo_push("Localized Data");
+ allqueue(REDRAWALL, 0);
+ }
+ }
+ }
+ else if(datalevel) {
+ if(datalevel==-1) error("Mixed selection");
+ else {
+ if(datalevel==TSE_POSE_CHANNEL) {
+ short event= pupmenu("PoseChannel Operations%t|Select%x1|Deselect%x2|Hide%x3|Unhide%x4");
+ if(event>0) {
+ outliner_do_data_operation(soops, datalevel, event, &soops->tree, pchan_cb);
+ BIF_undo_push("PoseChannel operation");
+ }
+ }
+ else if(datalevel==TSE_BONE) {
+ short event= pupmenu("Bone Operations%t|Select%x1|Deselect%x2|Hide%x3|Unhide%x4");
+ if(event>0) {
+ outliner_do_data_operation(soops, datalevel, event, &soops->tree, bone_cb);
+ BIF_undo_push("Bone operation");
+ }
+ }
+ else if(datalevel==TSE_EBONE) {
+ short event= pupmenu("EditBone Operations%t|Select%x1|Deselect%x2|Hide%x3|Unhide%x4");
+ if(event>0) {
+ outliner_do_data_operation(soops, datalevel, event, &soops->tree, ebone_cb);
+ BIF_undo_push("EditBone operation");
+ }
+ }
+#ifdef WITH_VERSE
+ else if(datalevel==TSE_VERSE_SESSION) {
+ short event= pupmenu("VerseSession %t| End %x1");
+ if(event>0) {
+ outliner_do_data_operation(soops, datalevel, event, &soops->tree, vsession_cb);
+ }
+ }
+#endif
+
+ allqueue(REDRAWOOPS, 0);
+ allqueue(REDRAWBUTSALL, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ }
+}
+
+
+/* ***************** DRAW *************** */
+
+static void tselem_draw_icon(float x, float y, TreeStoreElem *tselem, TreeElement *te)
+{
+ if(tselem->type) {
+ switch( tselem->type) {
+ case TSE_NLA:
+ BIF_icon_draw(x, y, ICON_NLA); break;
+ case TSE_NLA_ACTION:
+ BIF_icon_draw(x, y, ICON_ACTION); break;
+ case TSE_DEFGROUP_BASE:
+ BIF_icon_draw(x, y, ICON_VERTEXSEL); break;
+ case TSE_BONE:
+ case TSE_EBONE:
+ BIF_icon_draw(x, y, ICON_WPAINT_DEHLT); break;
+ case TSE_CONSTRAINT_BASE:
+ BIF_icon_draw(x, y, ICON_CONSTRAINT); break;
+ case TSE_MODIFIER_BASE:
+ BIF_icon_draw(x, y, ICON_MODIFIER); break;
+ case TSE_LINKED_OB:
+ BIF_icon_draw(x, y, ICON_OBJECT); break;
+ case TSE_MODIFIER:
+ {
+ Object *ob= (Object *)tselem->id;
+ ModifierData *md= BLI_findlink(&ob->modifiers, tselem->nr);
+ switch(md->type) {
+ case eModifierType_Subsurf:
+ BIF_icon_draw(x, y, ICON_MOD_SUBSURF); break;
+ case eModifierType_Armature:
+ BIF_icon_draw(x, y, ICON_ARMATURE); break;
+ case eModifierType_Lattice:
+ BIF_icon_draw(x, y, ICON_LATTICE); break;
+ case eModifierType_Curve:
+ BIF_icon_draw(x, y, ICON_CURVE); break;
+ case eModifierType_Build:
+ BIF_icon_draw(x, y, ICON_MOD_BUILD); break;
+ case eModifierType_Mirror:
+ BIF_icon_draw(x, y, ICON_MOD_MIRROR); break;
+ case eModifierType_Decimate:
+ BIF_icon_draw(x, y, ICON_MOD_DECIM); break;
+ case eModifierType_Wave:
+ BIF_icon_draw(x, y, ICON_MOD_WAVE); break;
+ case eModifierType_Hook:
+ BIF_icon_draw(x, y, ICON_HOOK); break;
+ case eModifierType_Softbody:
+ BIF_icon_draw(x, y, ICON_MOD_SOFT); break;
+ case eModifierType_Boolean:
+ BIF_icon_draw(x, y, ICON_MOD_BOOLEAN); break;
+ default:
+ BIF_icon_draw(x, y, ICON_DOT); break;
+ }
+ break;
+ }
+ case TSE_SCRIPT_BASE:
+ BIF_icon_draw(x, y, ICON_TEXT); break;
+ case TSE_POSE_BASE:
+ BIF_icon_draw(x, y, ICON_ARMATURE_DEHLT); break;
+ case TSE_POSE_CHANNEL:
+ BIF_icon_draw(x, y, ICON_WPAINT_DEHLT); break;
+ case TSE_PROXY:
+ BIF_icon_draw(x, y, ICON_GHOST); break;
+ case TSE_R_LAYER_BASE:
+ BIF_icon_draw(x, y, ICON_RESTRICT_RENDER_OFF); break;
+ case TSE_R_LAYER:
+ BIF_icon_draw(x, y, ICON_IMAGE_DEHLT); break;
+ case TSE_LINKED_LAMP:
+ BIF_icon_draw(x, y, ICON_LAMP_DEHLT); break;
+ case TSE_LINKED_MAT:
+ BIF_icon_draw(x, y, ICON_MATERIAL_DEHLT); break;
+
+#ifdef WITH_VERSE
+ case ID_VS:
+ case ID_MS:
+ case ID_SS:
+ BIF_icon_draw(x, y, ICON_VERSE); break;
+ case ID_VN:
+ BIF_icon_draw(x, y, ICON_VERSE); break;
+#endif
+ default:
+ BIF_icon_draw(x, y, ICON_DOT); break;
+ }
+ }
+ else {
+ switch( GS(tselem->id->name)) {
+ case ID_SCE:
+ BIF_icon_draw(x, y, ICON_SCENE_DEHLT); break;
+ case ID_OB:
+ BIF_icon_draw(x, y, ICON_OBJECT); break;
+ case ID_ME:
+ BIF_icon_draw(x, y, ICON_MESH); break;
+ case ID_CU:
+ BIF_icon_draw(x, y, ICON_CURVE); break;
+ case ID_MB:
+ BIF_icon_draw(x, y, ICON_MBALL); break;
+ case ID_LT:
+ BIF_icon_draw(x, y, ICON_LATTICE); break;
+ case ID_LA:
+ BIF_icon_draw(x, y, ICON_LAMP_DEHLT); break;
+ case ID_MA:
+ BIF_icon_draw(x, y, ICON_MATERIAL_DEHLT); break;
+ case ID_TE:
+ BIF_icon_draw(x, y, ICON_TEXTURE_DEHLT); break;
+ case ID_IP:
+ BIF_icon_draw(x, y, ICON_IPO_DEHLT); break;
+ case ID_IM:
+ BIF_icon_draw(x, y, ICON_IMAGE_DEHLT); break;
+ case ID_SO:
+ BIF_icon_draw(x, y, ICON_SPEAKER); break;
+ case ID_AR:
+ BIF_icon_draw(x, y, ICON_ARMATURE); break;
+ case ID_CA:
+ BIF_icon_draw(x, y, ICON_CAMERA_DEHLT); break;
+ case ID_KE:
+ BIF_icon_draw(x, y, ICON_EDIT_DEHLT); break;
+ case ID_WO:
+ BIF_icon_draw(x, y, ICON_WORLD_DEHLT); break;
+ case ID_AC:
+ BIF_icon_draw(x, y, ICON_ACTION); break;
+ case ID_NLA:
+ BIF_icon_draw(x, y, ICON_NLA); break;
+ case ID_TXT:
+ BIF_icon_draw(x, y, ICON_SCRIPT); break;
+ case ID_GR:
+ BIF_icon_draw(x, y, ICON_CIRCLE_DEHLT); break;
+ case ID_LI:
+ BIF_icon_draw(x, y, ICON_LIBRARY_DEHLT); break;
+ }
+ }
+}
+
+static void outliner_draw_iconrow(SpaceOops *soops, ListBase *lb, int level, int *offsx, int ys)
+{
+ TreeElement *te;
+ TreeStoreElem *tselem;
+ int active;
+
+ for(te= lb->first; te; te= te->next) {
+ tselem= TREESTORE(te);
+
+ /* object hierarchy always, further constrained on level */
+ if(level<1 || (tselem->type==0 && te->idcode==ID_OB)) {
+
+ /* active blocks get white circle */
+ active= 0;
+ if(tselem->type==0) {
+ if(te->idcode==ID_OB) active= (OBACT==(Object *)tselem->id);
+ else if(G.obedit && G.obedit->data==tselem->id) active= 1;
+ else active= tree_element_active(soops, te, 0);
+ }
+ else active= tree_element_type_active(soops, te, tselem, 0);
+
+ if(active) {
+ uiSetRoundBox(15);
+ glColor4ub(255, 255, 255, 100);
+ uiRoundBox( (float)*offsx-0.5, (float)ys-1.0, (float)*offsx+OL_H-3.0, (float)ys+OL_H-3.0, OL_H/2.0-2.0);
+ glEnable(GL_BLEND);
+ }
+
+ tselem_draw_icon(*offsx, ys, tselem, te);
+ te->xs= *offsx;
+ te->ys= ys;
+ te->xend= *offsx+OL_X;
+ te->flag |= TE_ICONROW; // for click
+
+ (*offsx) += OL_X;
+ }
+
+ /* this tree element always has same amount of branches, so dont draw */
+ if(tselem->type!=TSE_R_LAYER)
+ outliner_draw_iconrow(soops, &te->subtree, level+1, offsx, ys);
+ }
+
+}
+
+static void outliner_draw_tree_element(SpaceOops *soops, TreeElement *te, int startx, int *starty)
+{
+ TreeElement *ten;
+ TreeStoreElem *tselem;
+ int offsx= 0, active=0; // active=1 active obj, else active data
+
+ tselem= TREESTORE(te);
+
+ if(*starty >= soops->v2d.cur.ymin && *starty<= soops->v2d.cur.ymax) {
+
+ glEnable(GL_BLEND);
+
+ /* colors for active/selected data */
+ if(tselem->type==0) {
+ if(te->idcode==ID_SCE) {
+ if(tselem->id == (ID *)G.scene) {
+ glColor4ub(255, 255, 255, 100);
+ active= 2;
+ }
+ }
+ else if(te->idcode==ID_OB) {
+ Object *ob= (Object *)tselem->id;
+
+ if(ob==OBACT || (ob->flag & SELECT)) {
+ char col[4];
+
+ active= 2;
+ if(ob==OBACT) {
+ BIF_GetThemeColorType4ubv(TH_ACTIVE, SPACE_VIEW3D, col);
+ /* so black text is drawn when active and not selected */
+ if (ob->flag & SELECT) active= 1;
+ }
+ else BIF_GetThemeColorType4ubv(TH_SELECT, SPACE_VIEW3D, col);
+ col[3]= 100;
+ glColor4ubv((GLubyte *)col);
+ }
+
+#ifdef WITH_VERSE
+ if(ob->vnode) {
+ if (active==0) active=2;
+ if (ob==OBACT)
+ glColor4ub(0,255,0,100);
+ else
+ glColor4ub(0,128,0,100);
+ }
+#endif
+ }
+ else if(G.obedit && G.obedit->data==tselem->id) {
+ glColor4ub(255, 255, 255, 100);
+ active= 2;
+ }
+ else {
+ if(tree_element_active(soops, te, 0)) {
+ glColor4ub(220, 220, 255, 100);
+ active= 2;
+ }
+ }
+ } else if (tselem->type==ID_SS) {
+#ifdef WITH_VERSE
+ /* draw colored circle behind verse server icon */
+ struct VerseServer *server = (VerseServer *)te->directdata;
+ if(server->flag & VERSE_CONNECTING) {
+ glColor4ub(255,128,64,100);
+ active = 2;
+ } else if(server->flag & VERSE_CONNECTED) {
+ glColor4ub(0,128,0,100);
+ active = 2;
+ }
+#endif
+ }
+ else if (tselem->type==ID_VN) {
+#ifdef WITH_VERSE
+ struct VNode *vnode = (VNode *)te->directdata;
+ if(vnode->type==V_NT_OBJECT) {
+ if(((VObjectData*)vnode->data)->object) {
+ glColor4ub(0,128,0,100);
+ active = 2;
+ }
+ }
+ else if(vnode->type==V_NT_GEOMETRY) {
+ if(((VGeomData*)vnode->data)->mesh || ((VGeomData*)vnode->data)->editmesh) {
+ glColor4ub(0,128,0,100);
+ active = 2;
+ }
+ }
+ if(vnode->type==V_NT_BITMAP) {
+ if(((VBitmapData*)vnode->data)->image) {
+ glColor4ub(0,128,0,100);
+ active = 2;
+ }
+ }
+#endif
+ }
+ else {
+ if( tree_element_type_active(soops, te, tselem, 0) ) active= 2;
+ glColor4ub(220, 220, 255, 100);
+ }
+
+ /* active circle */
+ if(active) {
+ uiSetRoundBox(15);
+ uiRoundBox( (float)startx+OL_H-1.5, (float)*starty+2.0, (float)startx+2*OL_H-4.0, (float)*starty+OL_H-1.0, OL_H/2.0-2.0);
+ glEnable(GL_BLEND); /* roundbox disables it */
+
+ te->flag |= TE_ACTIVE; // for lookup in display hierarchies
+ }
+
+ /* open/close icon, only when sublevels, except for scene */
+ if(te->subtree.first || (te->idcode==ID_SCE && tselem->type==0)) {
+ int icon_x;
+ if((tselem->type==0 && ELEM(te->idcode, ID_OB, ID_SCE)) || ELEM4(te->idcode,ID_VN,ID_VS, ID_MS, ID_SS))
+ icon_x = startx;
+ else
+ icon_x = startx+5;
+
+ // icons a bit higher
+ if(tselem->flag & TSE_CLOSED)
+ BIF_icon_draw(icon_x, *starty+2, ICON_TRIA_RIGHT);
+ else
+ BIF_icon_draw(icon_x, *starty+2, ICON_TRIA_DOWN);
+ }
+ offsx+= OL_X;
+
+ /* datatype icon */
+
+ // icons a bit higher
+ tselem_draw_icon(startx+offsx, *starty+2, tselem, te);
+ offsx+= OL_X;
+
+ if(tselem->id->lib && tselem->type==0) {
+ glPixelTransferf(GL_ALPHA_SCALE, 0.5);
+ if(tselem->id->flag & LIB_INDIRECT)
+ BIF_icon_draw(startx+offsx, *starty+2, ICON_DATALIB);
+ else
+ BIF_icon_draw(startx+offsx, *starty+2, ICON_PARLIB);
+ glPixelTransferf(GL_ALPHA_SCALE, 1.0);
+ offsx+= OL_X;
+ }
+ glDisable(GL_BLEND);
+
+ /* name */
+ if(active==1) BIF_ThemeColor(TH_TEXT_HI);
+ else BIF_ThemeColor(TH_TEXT);
+ glRasterPos2i(startx+offsx, *starty+5);
+ BIF_RasterPos(startx+offsx, *starty+5);
+#ifdef WITH_VERSE
+ if(te->name) {
+#endif
+ BIF_DrawString(G.font, te->name, 0);
+ offsx+= OL_X + BIF_GetStringWidth(G.font, te->name, 0);
+#ifdef WITH_VERSE
+ }
+#endif
+
+ /* closed item, we draw the icons, not when it's a scene, or master-server list though */
+ if(tselem->flag & TSE_CLOSED) {
+ if(te->subtree.first) {
+ if(tselem->type==0 && te->idcode==ID_SCE);
+#ifdef WITH_VERSE
+ else if(tselem->type==ID_MS) {
+ char server_buf[50];
+ int nr_servers = 0;
+ struct VerseServer *server = server_list.first;
+ while (server) {
+ nr_servers++;
+ server = server->next;
+ }
+ sprintf(server_buf, "(%d server%s", nr_servers, nr_servers==1?")":"s)");
+ glRasterPos2i(startx+offsx-10, *starty+5);
+ BIF_RasterPos(startx+offsx-10, *starty+5);
+ BIF_DrawString(G.font, server_buf, 0);
+ offsx+= OL_X + BIF_GetStringWidth(G.font, server_buf, 0);
+ }
+#endif
+ else if(tselem->type!=TSE_R_LAYER) { /* this tree element always has same amount of branches, so dont draw */
+ int tempx= startx+offsx;
+ // divider
+ BIF_ThemeColorShade(TH_BACK, -40);
+ glRecti(tempx -10, *starty+4, tempx -8, *starty+OL_H-4);
+
+ glEnable(GL_BLEND);
+ glPixelTransferf(GL_ALPHA_SCALE, 0.5);
+
+ outliner_draw_iconrow(soops, &te->subtree, 0, &tempx, *starty+2);
+
+ glPixelTransferf(GL_ALPHA_SCALE, 1.0);
+ glDisable(GL_BLEND);
+ }
+ }
+ }
+ }
+ /* store coord and continue, we need coordinates for elements outside view too */
+ te->xs= startx;
+ te->ys= *starty;
+ te->xend= startx+offsx;
+
+ *starty-= OL_H;
+
+ if((tselem->flag & TSE_CLOSED)==0) {
+ for(ten= te->subtree.first; ten; ten= ten->next) {
+ outliner_draw_tree_element(soops, ten, startx+OL_X, starty);
+ }
+ }
+}
+
+static void outliner_draw_hierarchy(SpaceOops *soops, ListBase *lb, int startx, int *starty)
+{
+ TreeElement *te;
+ TreeStoreElem *tselem;
+ int y1, y2;
+
+ if(lb->first==NULL) return;
+
+ y1=y2= *starty; /* for vertical lines between objects */
+ for(te=lb->first; te; te= te->next) {
+ y2= *starty;
+ tselem= TREESTORE(te);
+
+ /* horizontal line? */
+ if((tselem->type==0 && (te->idcode==ID_OB || te->idcode==ID_SCE)) || ELEM4(te->idcode,ID_VS,ID_VN,ID_MS,ID_SS))
+ glRecti(startx, *starty, startx+OL_X, *starty-1);
+
+ *starty-= OL_H;
+
+ if((tselem->flag & TSE_CLOSED)==0)
+ outliner_draw_hierarchy(soops, &te->subtree, startx+OL_X, starty);
+ }
+
+ /* vertical line */
+ te= lb->last;
+ if(te->parent || lb->first!=lb->last) {
+ tselem= TREESTORE(te);
+ if((tselem->type==0 && te->idcode==ID_OB) || ELEM4(te->idcode,ID_VS,ID_VN,ID_MS,ID_SS)) {
+
+ glRecti(startx, y1+OL_H, startx+1, y2);
+ }
+ }
+}
+
+static void outliner_draw_selection(SpaceOops *soops, ListBase *lb, int *starty)
+{
+ TreeElement *te;
+ TreeStoreElem *tselem;
+
+ for(te= lb->first; te; te= te->next) {
+ tselem= TREESTORE(te);
+
+ /* selection status */
+ if(tselem->flag & TSE_SELECTED) {
+ glRecti(0, *starty+1, (int)soops->v2d.cur.xmax, *starty+OL_H-1);
+ }
+ *starty-= OL_H;
+ if((tselem->flag & TSE_CLOSED)==0) outliner_draw_selection(soops, &te->subtree, starty);
+ }
+}
+
+
+static void outliner_draw_tree(SpaceOops *soops)
+{
+ TreeElement *te;
+ int starty, startx;
+ float col[4];
+
+#ifdef INTERNATIONAL
+ FTF_SetFontSize('l');
+ BIF_SetScale(1.0);
+#endif
+
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // only once
+
+ // selection first
+ BIF_GetThemeColor3fv(TH_BACK, col);
+ glColor3f(col[0]+0.06f, col[1]+0.08f, col[2]+0.10f);
+ starty= soops->v2d.tot.ymax-OL_H;
+ outliner_draw_selection(soops, &soops->tree, &starty);
+
+ // grey hierarchy lines
+ BIF_ThemeColorBlend(TH_BACK, TH_TEXT, 0.2);
+ starty= soops->v2d.tot.ymax-OL_H/2;
+ startx= 6;
+ outliner_draw_hierarchy(soops, &soops->tree, startx, &starty);
+
+ // items themselves
+ starty= soops->v2d.tot.ymax-OL_H;
+ startx= 0;
+ for(te= soops->tree.first; te; te= te->next) {
+ outliner_draw_tree_element(soops, te, startx, &starty);
+ }
+}
+
+
+static void outliner_back(SpaceOops *soops)
+{
+ int ystart;
+
+ BIF_ThemeColorShade(TH_BACK, 6);
+ ystart= soops->v2d.tot.ymax;
+ ystart= OL_H*(ystart/(OL_H));
+
+ while(ystart > soops->v2d.cur.ymin) {
+ glRecti(0, ystart, (int)soops->v2d.cur.xmax, ystart+OL_H);
+ ystart-= 2*OL_H;
+ }
+}
+
+static void outliner_draw_restrictcols(SpaceOops *soops)
+{
+ int ystart;
+
+ /* background underneath */
+ BIF_ThemeColor(TH_BACK);
+ glRecti((int)soops->v2d.cur.xmax-OL_TOGW, soops->v2d.cur.ymin, (int)soops->v2d.cur.xmax, soops->v2d.cur.ymax);
+
+ BIF_ThemeColorShade(TH_BACK, 6);
+ ystart= soops->v2d.tot.ymax;
+ ystart= OL_H*(ystart/(OL_H));
+
+ while(ystart > soops->v2d.cur.ymin) {
+ glRecti((int)soops->v2d.cur.xmax-OL_TOGW, ystart, (int)soops->v2d.cur.xmax, ystart+OL_H);
+ ystart-= 2*OL_H;
+ }
+
+ BIF_ThemeColorShadeAlpha(TH_BACK, -15, -200);
+
+ /* view */
+ fdrawline(soops->v2d.cur.xmax-OL_TOG_RESTRICT_VIEWX,
+ soops->v2d.cur.ymax,
+ soops->v2d.cur.xmax-OL_TOG_RESTRICT_VIEWX,
+ soops->v2d.cur.ymin);
+
+ /* render */
+ fdrawline(soops->v2d.cur.xmax-OL_TOG_RESTRICT_SELECTX,
+ soops->v2d.cur.ymax,
+ soops->v2d.cur.xmax-OL_TOG_RESTRICT_SELECTX,
+ soops->v2d.cur.ymin);
+
+ /* render */
+ fdrawline(soops->v2d.cur.xmax-OL_TOG_RESTRICT_RENDERX,
+ soops->v2d.cur.ymax,
+ soops->v2d.cur.xmax-OL_TOG_RESTRICT_RENDERX,
+ soops->v2d.cur.ymin);
+}
+
+static void restrictbutton_view_cb(void *poin, void *poin2)
+{
+ Base *base;
+ Object *ob = (Object *)poin;
+
+ /* deselect objects that are invisible */
+ if (ob->restrictflag & OB_RESTRICT_VIEW) {
+
+ /* Ouch! There is no backwards pointer from Object to Base,
+ * so have to do loop to find it. */
+ for(base= FIRSTBASE; base; base= base->next) {
+ if(base->object==ob) {
+ base->flag &= ~SELECT;
+ base->object->flag= base->flag;
+ }
+ }
+ }
+
+ allqueue(REDRAWOOPS, 0);
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static void restrictbutton_sel_cb(void *poin, void *poin2)
+{
+ Base *base;
+ Object *ob = (Object *)poin;
+
+ /* if select restriction has just been turned on */
+ if (ob->restrictflag & OB_RESTRICT_SELECT) {
+
+ /* Ouch! There is no backwards pointer from Object to Base,
+ * so have to do loop to find it. */
+ for(base= FIRSTBASE; base; base= base->next) {
+ if(base->object==ob) {
+ base->flag &= ~SELECT;
+ base->object->flag= base->flag;
+ }
+ }
+ }
+
+ allqueue(REDRAWOOPS, 0);
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static void restrictbutton_rend_cb(void *poin, void *poin2)
+{
+ allqueue(REDRAWOOPS, 0);
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static void restrictbutton_r_lay_cb(void *poin, void *poin2)
+{
+ allqueue(REDRAWOOPS, 0);
+ allqueue(REDRAWNODE, 0);
+ allqueue(REDRAWBUTSSCENE, 0);
+}
+
+static void namebutton_cb(void *tep, void *oldnamep)
+{
+ SpaceOops *soops= curarea->spacedata.first;
+ TreeStore *ts= soops->treestore;
+ TreeElement *te= tep;
+
+ if(ts && te) {
+ TreeStoreElem *tselem= TREESTORE(te);
+
+ if(tselem->type==0) {
+ test_idbutton(tselem->id->name+2); // library.c, unique name and alpha sort
+
+ /* Check the library target exists */
+ if (te->idcode == ID_LI) {
+ char expanded[FILE_MAXDIR + FILE_MAXFILE];
+ BLI_strncpy(expanded, ((Library *)tselem->id)->name, FILE_MAXDIR + FILE_MAXFILE);
+
+ if (!BLI_exists(expanded)) {
+ error("This path does not exist, correct this before saving");
+ }
+ }
+ }
+ else {
+ switch(tselem->type) {
+ case TSE_DEFGROUP:
+ unique_vertexgroup_name(te->directdata, (Object *)tselem->id); // id = object
+ allqueue(REDRAWBUTSEDIT, 0);
+ break;
+ case TSE_NLA_ACTION:
+ test_idbutton(tselem->id->name+2);
+ break;
+ case TSE_EBONE:
+ if(G.obedit && G.obedit->data==(ID *)tselem->id) {
+ EditBone *ebone= te->directdata;
+ char newname[32];
+
+ /* restore bone name */
+ BLI_strncpy(newname, ebone->name, 32);
+ BLI_strncpy(ebone->name, oldnamep, 32);
+ armature_bone_rename(G.obedit->data, oldnamep, newname);
+ }
+ allqueue(REDRAWOOPS, 0);
+ allqueue(REDRAWVIEW3D, 1);
+ allqueue(REDRAWBUTSEDIT, 0);
+ break;
+
+ case TSE_BONE:
+ {
+ Bone *bone= te->directdata;
+ Object *ob;
+ char newname[32];
+
+ // always make current object active
+ tree_element_active_object(soops, te);
+ ob= OBACT;
+
+ /* restore bone name */
+ BLI_strncpy(newname, bone->name, 32);
+ BLI_strncpy(bone->name, oldnamep, 32);
+ armature_bone_rename(ob->data, oldnamep, newname);
+ }
+ allqueue(REDRAWOOPS, 0);
+ allqueue(REDRAWVIEW3D, 1);
+ allqueue(REDRAWBUTSEDIT, 0);
+ break;
+ case TSE_POSE_CHANNEL:
+ {
+ bPoseChannel *pchan= te->directdata;
+ Object *ob;
+ char newname[32];
+
+ // always make current object active
+ tree_element_active_object(soops, te);
+ ob= OBACT;
+
+ /* restore bone name */
+ BLI_strncpy(newname, pchan->name, 32);
+ BLI_strncpy(pchan->name, oldnamep, 32);
+ armature_bone_rename(ob->data, oldnamep, newname);
+ }
+ allqueue(REDRAWOOPS, 0);
+ allqueue(REDRAWVIEW3D, 1);
+ allqueue(REDRAWBUTSEDIT, 0);
+ break;
+ case TSE_R_LAYER:
+ allqueue(REDRAWOOPS, 0);
+ allqueue(REDRAWBUTSSCENE, 0);
+ break;
+ }
+ }
+ }
+ scrarea_queue_redraw(curarea);
+}
+
+static void outliner_draw_restrictbuts(uiBlock *block, SpaceOops *soops, ListBase *lb)
+{
+ uiBut *bt;
+ TreeElement *te;
+ TreeStoreElem *tselem;
+ Object *ob;
+
+ for(te= lb->first; te; te= te->next) {
+ tselem= TREESTORE(te);
+ if(te->ys >= soops->v2d.cur.ymin && te->ys <= soops->v2d.cur.ymax) {
+ /* objects have toggle-able restriction flags */
+ if(tselem->type==0 && te->idcode==ID_OB) {
+ ob = (Object *)tselem->id;
+
+ uiBlockSetEmboss(block, UI_EMBOSSN);
+ bt= uiDefIconButBitS(block, ICONTOG, OB_RESTRICT_VIEW, REDRAWALL, ICON_RESTRICT_VIEW_OFF,
+ (int)soops->v2d.cur.xmax-OL_TOG_RESTRICT_VIEWX, te->ys, 17, OL_H-1, &(ob->restrictflag), 0, 0, 0, 0, "Restrict/Allow visibility in the 3D View");
+ uiButSetFunc(bt, restrictbutton_view_cb, ob, NULL);
+ uiButSetFlag(bt, UI_NO_HILITE);
+
+ bt= uiDefIconButBitS(block, ICONTOG, OB_RESTRICT_SELECT, REDRAWALL, ICON_RESTRICT_SELECT_OFF,
+ (int)soops->v2d.cur.xmax-OL_TOG_RESTRICT_SELECTX, te->ys, 17, OL_H-1, &(ob->restrictflag), 0, 0, 0, 0, "Restrict/Allow selection in the 3D View");
+ uiButSetFunc(bt, restrictbutton_sel_cb, ob, NULL);
+ uiButSetFlag(bt, UI_NO_HILITE);
+
+ bt= uiDefIconButBitS(block, ICONTOG, OB_RESTRICT_RENDER, REDRAWALL, ICON_RESTRICT_RENDER_OFF,
+ (int)soops->v2d.cur.xmax-OL_TOG_RESTRICT_RENDERX, te->ys, 17, OL_H-1, &(ob->restrictflag), 0, 0, 0, 0, "Restrict/Allow renderability");
+ uiButSetFunc(bt, restrictbutton_rend_cb, NULL, NULL);
+ uiButSetFlag(bt, UI_NO_HILITE);
+
+ uiBlockSetEmboss(block, UI_EMBOSS);
+ }
+ /* scene render layers and passes have toggle-able flags too! */
+ else if(tselem->type==TSE_R_LAYER) {
+ uiBlockSetEmboss(block, UI_EMBOSSN);
+
+ bt= uiDefIconButBitI(block, ICONTOGN, SCE_LAY_DISABLE, REDRAWBUTSSCENE, ICON_CHECKBOX_HLT-1,
+ (int)soops->v2d.cur.xmax-OL_TOG_RESTRICT_VIEWX, te->ys, 17, OL_H-1, te->directdata, 0, 0, 0, 0, "Render this RenderLayer");
+ uiButSetFunc(bt, restrictbutton_r_lay_cb, NULL, NULL);
+
+ uiBlockSetEmboss(block, UI_EMBOSS);
+ }
+ else if(tselem->type==TSE_R_PASS) {
+ int *layflag= te->directdata;
+ uiBlockSetEmboss(block, UI_EMBOSSN);
+
+ /* NOTE: tselem->nr is short! */
+ bt= uiDefIconButBitI(block, ICONTOG, tselem->nr, REDRAWBUTSSCENE, ICON_CHECKBOX_HLT-1,
+ (int)soops->v2d.cur.xmax-OL_TOG_RESTRICT_VIEWX, te->ys, 17, OL_H-1, layflag, 0, 0, 0, 0, "Render this Pass");
+ uiButSetFunc(bt, restrictbutton_r_lay_cb, NULL, NULL);
+
+ layflag++; /* is lay_xor */
+ if(ELEM6(tselem->nr, SCE_PASS_SPEC, SCE_PASS_SHADOW, SCE_PASS_AO, SCE_PASS_REFLECT, SCE_PASS_REFRACT, SCE_PASS_RADIO))
+ bt= uiDefIconButBitI(block, TOG, tselem->nr, REDRAWBUTSSCENE, (*layflag & tselem->nr)?ICON_DOT:ICON_BLANK1,
+ (int)soops->v2d.cur.xmax-OL_TOG_RESTRICT_SELECTX, te->ys, 17, OL_H-1, layflag, 0, 0, 0, 0, "Exclude this Pass from Combined");
+ uiButSetFunc(bt, restrictbutton_r_lay_cb, NULL, NULL);
+
+ uiBlockSetEmboss(block, UI_EMBOSS);
+ }
+ }
+
+ if((tselem->flag & TSE_CLOSED)==0) outliner_draw_restrictbuts(block, soops, &te->subtree);
+ }
+}
+
+static void outliner_buttons(uiBlock *block, SpaceOops *soops, ListBase *lb)
+{
+ uiBut *bt;
+ TreeElement *te;
+ TreeStoreElem *tselem;
+ int dx, len;
+
+ for(te= lb->first; te; te= te->next) {
+ tselem= TREESTORE(te);
+ if(te->ys >= soops->v2d.cur.ymin && te->ys <= soops->v2d.cur.ymax) {
+
+ if(tselem->flag & TSE_TEXTBUT) {
+ if(tselem->type == TSE_POSE_BASE) continue; // prevent crash when trying to rename 'pose' entry of armature
+
+ if(tselem->type==TSE_EBONE) len = sizeof(((EditBone*) 0)->name);
+ else if (tselem->type==TSE_MODIFIER) len = sizeof(((ModifierData*) 0)->name);
+ else if(tselem->id && GS(tselem->id->name)==ID_LI) len = sizeof(((Library*) 0)->name);
+ else len= sizeof(((ID*) 0)->name)-2;
+
+ dx= BIF_GetStringWidth(G.font, te->name, 0);
+ if(dx<50) dx= 50;
+
+ bt= uiDefBut(block, TEX, OL_NAMEBUTTON, "", te->xs+2*OL_X-4, te->ys, dx+10, OL_H-1, te->name, 1.0, (float)len-1, 0, 0, "");
+ uiButSetFunc(bt, namebutton_cb, te, NULL);
+
+ // signal for button to open
+ addqueue(curarea->win, BUT_ACTIVATE, OL_NAMEBUTTON);
+
+ /* otherwise keeps open on ESC */
+ tselem->flag &= ~TSE_TEXTBUT;
+ }
+ }
+
+ if((tselem->flag & TSE_CLOSED)==0) outliner_buttons(block, soops, &te->subtree);
+ }
+}
+
+void draw_outliner(ScrArea *sa, SpaceOops *soops)
+{
+ uiBlock *block;
+ int sizey, sizex;
+ short ofsx, ofsy;
+
+ /* version patch for old outliners here - do_versions patch doesn't work */
+ if (G.v2d->scroll != L_SCROLL+B_SCROLLO) {
+ init_v2d_oops(curarea, soops);
+ test_view2d(G.v2d, curarea->winx, curarea->winy);
+ calc_scrollrcts(sa, G.v2d, sa->winx, sa->winy);
+ }
+ else
+ calc_scrollrcts(sa, G.v2d, sa->winx, sa->winy);
+
+ if(sa->winx>SCROLLB+10 && sa->winy>SCROLLH+10) {
+ if(G.v2d->scroll) {
+ ofsx= sa->winrct.xmin; /* because mywin */
+ ofsy= sa->winrct.ymin;
+ glViewport(ofsx+G.v2d->mask.xmin, ofsy+G.v2d->mask.ymin, ( ofsx+G.v2d->mask.xmax-1)-(ofsx+G.v2d->mask.xmin)+1, ( ofsy+G.v2d->mask.ymax-1)-( ofsy+G.v2d->mask.ymin)+1);
+ glScissor(ofsx+G.v2d->mask.xmin, ofsy+G.v2d->mask.ymin, ( ofsx+G.v2d->mask.xmax-1)-(ofsx+G.v2d->mask.xmin)+1, ( ofsy+G.v2d->mask.ymax-1)-( ofsy+G.v2d->mask.ymin)+1);
+ }
+ }
+
+ outliner_build_tree(soops); // always
+ sizey = sizex = 0;
+ outliner_height(soops, &soops->tree, &sizey);
+ outliner_width(soops, &soops->tree, &sizex);
+
+ /* we init all tot rect vars, only really needed on window size change though */
+ G.v2d->tot.xmin= 0.0;
+ G.v2d->tot.xmax= (G.v2d->mask.xmax-G.v2d->mask.xmin);
+ if(soops->flag & SO_HIDE_RESTRICTCOLS) {
+ if(G.v2d->tot.xmax <= sizex)
+ G.v2d->tot.xmax= 2*sizex;
+ }
+ else {
+ if(G.v2d->tot.xmax-OL_TOGW <= sizex)
+ G.v2d->tot.xmax= 2*sizex;
+ }
+ G.v2d->tot.ymax= 0.0;
+ G.v2d->tot.ymin= -sizey*OL_H;
+ test_view2d(G.v2d, sa->winx, sa->winy);
+
+ // align on top window if cur bigger than tot
+ if(G.v2d->cur.ymax-G.v2d->cur.ymin > sizey*OL_H) {
+ G.v2d->cur.ymax= 0.0;
+ G.v2d->cur.ymin= -(G.v2d->mask.ymax-G.v2d->mask.ymin);
+ }
+
+ myortho2(G.v2d->cur.xmin-0.375, G.v2d->cur.xmax-0.375, G.v2d->cur.ymin-0.375, G.v2d->cur.ymax-0.375);
+
+ /* draw outliner stuff (background and hierachy lines) */
+ outliner_back(soops);
+ outliner_draw_tree(soops);
+
+ /* restore viewport */
+ mywinset(sa->win);
+
+ /* ortho corrected - 'pixel space' */
+ myortho2(G.v2d->cur.xmin-SCROLLB-0.375, G.v2d->cur.xmax-0.375, G.v2d->cur.ymin-SCROLLH-0.375, G.v2d->cur.ymax-0.375);
+
+ /* draw icons and names */
+ block= uiNewBlock(&sa->uiblocks, "outliner buttons", UI_EMBOSS, UI_HELV, sa->win);
+ outliner_buttons(block, soops, &soops->tree);
+
+ /* draw restriction columns */
+ if (!(soops->flag & SO_HIDE_RESTRICTCOLS)) {
+ outliner_draw_restrictcols(soops);
+ outliner_draw_restrictbuts(block, soops, &soops->tree);
+ }
+
+ uiDrawBlock(block);
+
+ /* clear flag that allows quick redraws */
+ soops->storeflag &= ~SO_TREESTORE_REDRAW;
+
+ /* drawoopsspace handles sliders */
+}
diff --git a/source/blender/src/parametrizer.c b/source/blender/src/parametrizer.c
new file mode 100644
index 00000000000..d0a51027ad3
--- /dev/null
+++ b/source/blender/src/parametrizer.c
@@ -0,0 +1,4203 @@
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_memarena.h"
+#include "BLI_arithb.h"
+#include "BLI_rand.h"
+#include "BLI_heap.h"
+#include "BLI_boxpack2d.h"
+
+#include "BKE_utildefines.h"
+
+#include "BIF_editsima.h"
+#include "BIF_toolbox.h"
+
+#include "ONL_opennl.h"
+
+#include "parametrizer.h"
+#include "parametrizer_intern.h"
+
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#if defined(_WIN32)
+#define M_PI 3.14159265358979323846
+#endif
+
+/* PHash
+ - special purpose hash that keeps all its elements in a single linked list.
+ - after construction, this hash is thrown away, and the list remains.
+ - removing elements is not possible efficiently.
+*/
+
+static int PHashSizes[] = {
+ 1, 3, 5, 11, 17, 37, 67, 131, 257, 521, 1031, 2053, 4099, 8209,
+ 16411, 32771, 65537, 131101, 262147, 524309, 1048583, 2097169,
+ 4194319, 8388617, 16777259, 33554467, 67108879, 134217757, 268435459
+};
+
+#define PHASH_hash(ph, item) (((unsigned long) (item))%((unsigned int) (ph)->cursize))
+#define PHASH_edge(v1, v2) ((v1)^(v2))
+
+static PHash *phash_new(PHashLink **list, int sizehint)
+{
+ PHash *ph = (PHash*)MEM_callocN(sizeof(PHash), "PHash");
+ ph->size = 0;
+ ph->cursize_id = 0;
+ ph->list = list;
+
+ while (PHashSizes[ph->cursize_id] < sizehint)
+ ph->cursize_id++;
+
+ ph->cursize = PHashSizes[ph->cursize_id];
+ ph->buckets = (PHashLink**)MEM_callocN(ph->cursize*sizeof(*ph->buckets), "PHashBuckets");
+
+ return ph;
+}
+
+static void phash_delete(PHash *ph)
+{
+ MEM_freeN(ph->buckets);
+ MEM_freeN(ph);
+}
+
+static int phash_size(PHash *ph)
+{
+ return ph->size;
+}
+
+static void phash_insert(PHash *ph, PHashLink *link)
+{
+ int size = ph->cursize;
+ int hash = PHASH_hash(ph, link->key);
+ PHashLink *lookup = ph->buckets[hash];
+
+ if (lookup == NULL) {
+ /* insert in front of the list */
+ ph->buckets[hash] = link;
+ link->next = *(ph->list);
+ *(ph->list) = link;
+ }
+ else {
+ /* insert after existing element */
+ link->next = lookup->next;
+ lookup->next = link;
+ }
+
+ ph->size++;
+
+ if (ph->size > (size*3)) {
+ PHashLink *next = NULL, *first = *(ph->list);
+
+ ph->cursize = PHashSizes[++ph->cursize_id];
+ MEM_freeN(ph->buckets);
+ ph->buckets = (PHashLink**)MEM_callocN(ph->cursize*sizeof(*ph->buckets), "PHashBuckets");
+ ph->size = 0;
+ *(ph->list) = NULL;
+
+ for (link = first; link; link = next) {
+ next = link->next;
+ phash_insert(ph, link);
+ }
+ }
+}
+
+static PHashLink *phash_lookup(PHash *ph, PHashKey key)
+{
+ PHashLink *link;
+ int hash = PHASH_hash(ph, key);
+
+ for (link = ph->buckets[hash]; link; link = link->next)
+ if (link->key == key)
+ return link;
+ else if (PHASH_hash(ph, link->key) != hash)
+ return NULL;
+
+ return link;
+}
+
+static PHashLink *phash_next(PHash *ph, PHashKey key, PHashLink *link)
+{
+ int hash = PHASH_hash(ph, key);
+
+ for (link = link->next; link; link = link->next)
+ if (link->key == key)
+ return link;
+ else if (PHASH_hash(ph, link->key) != hash)
+ return NULL;
+
+ return link;
+}
+
+/* Geometry */
+
+static float p_vec_angle_cos(float *v1, float *v2, float *v3)
+{
+ float d1[3], d2[3];
+
+ d1[0] = v1[0] - v2[0];
+ d1[1] = v1[1] - v2[1];
+ d1[2] = v1[2] - v2[2];
+
+ d2[0] = v3[0] - v2[0];
+ d2[1] = v3[1] - v2[1];
+ d2[2] = v3[2] - v2[2];
+
+ Normalize(d1);
+ Normalize(d2);
+
+ return d1[0]*d2[0] + d1[1]*d2[1] + d1[2]*d2[2];
+}
+
+static float p_vec_angle(float *v1, float *v2, float *v3)
+{
+ float dot = p_vec_angle_cos(v1, v2, v3);
+
+ if (dot <= -1.0f)
+ return (float)M_PI;
+ else if (dot >= 1.0f)
+ return 0.0f;
+ else
+ return (float)acos(dot);
+}
+
+static float p_vec2_angle(float *v1, float *v2, float *v3)
+{
+ float u1[3], u2[3], u3[3];
+
+ u1[0] = v1[0]; u1[1] = v1[1]; u1[2] = 0.0f;
+ u2[0] = v2[0]; u2[1] = v2[1]; u2[2] = 0.0f;
+ u3[0] = v3[0]; u3[1] = v3[1]; u3[2] = 0.0f;
+
+ return p_vec_angle(u1, u2, u3);
+}
+
+static void p_triangle_angles(float *v1, float *v2, float *v3, float *a1, float *a2, float *a3)
+{
+ *a1 = p_vec_angle(v3, v1, v2);
+ *a2 = p_vec_angle(v1, v2, v3);
+ *a3 = M_PI - *a2 - *a1;
+}
+
+static void p_face_angles(PFace *f, float *a1, float *a2, float *a3)
+{
+ PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
+ PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
+
+ p_triangle_angles(v1->co, v2->co, v3->co, a1, a2, a3);
+}
+
+static float p_face_area(PFace *f)
+{
+ PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
+ PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
+
+ return AreaT3Dfl(v1->co, v2->co, v3->co);
+}
+
+static float p_area_signed(float *v1, float *v2, float *v3)
+{
+ return 0.5f*(((v2[0] - v1[0])*(v3[1] - v1[1])) -
+ ((v3[0] - v1[0])*(v2[1] - v1[1])));
+}
+
+static float p_face_uv_area_signed(PFace *f)
+{
+ PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
+ PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
+
+ return 0.5f*(((v2->uv[0] - v1->uv[0])*(v3->uv[1] - v1->uv[1])) -
+ ((v3->uv[0] - v1->uv[0])*(v2->uv[1] - v1->uv[1])));
+}
+
+static float p_edge_length(PEdge *e)
+{
+ PVert *v1 = e->vert, *v2 = e->next->vert;
+ float d[3];
+
+ d[0] = v2->co[0] - v1->co[0];
+ d[1] = v2->co[1] - v1->co[1];
+ d[2] = v2->co[2] - v1->co[2];
+
+ return sqrt(d[0]*d[0] + d[1]*d[1] + d[2]*d[2]);
+}
+
+static float p_edge_uv_length(PEdge *e)
+{
+ PVert *v1 = e->vert, *v2 = e->next->vert;
+ float d[3];
+
+ d[0] = v2->uv[0] - v1->uv[0];
+ d[1] = v2->uv[1] - v1->uv[1];
+
+ return sqrt(d[0]*d[0] + d[1]*d[1]);
+}
+
+static void p_chart_uv_bbox(PChart *chart, float *minv, float *maxv)
+{
+ PVert *v;
+
+ INIT_MINMAX2(minv, maxv);
+
+ for (v=chart->verts; v; v=v->nextlink) {
+ DO_MINMAX2(v->uv, minv, maxv);
+ }
+}
+
+static void p_chart_uv_scale(PChart *chart, float scale)
+{
+ PVert *v;
+
+ for (v=chart->verts; v; v=v->nextlink) {
+ v->uv[0] *= scale;
+ v->uv[1] *= scale;
+ }
+}
+
+static void p_chart_uv_translate(PChart *chart, float trans[2])
+{
+ PVert *v;
+
+ for (v=chart->verts; v; v=v->nextlink) {
+ v->uv[0] += trans[0];
+ v->uv[1] += trans[1];
+ }
+}
+
+static PBool p_intersect_line_2d_dir(float *v1, float *dir1, float *v2, float *dir2, float *isect)
+{
+ float lmbda, div;
+
+ div= dir2[0]*dir1[1] - dir2[1]*dir1[0];
+
+ if (div == 0.0f)
+ return P_FALSE;
+
+ lmbda= ((v1[1]-v2[1])*dir1[0]-(v1[0]-v2[0])*dir1[1])/div;
+ isect[0] = v1[0] + lmbda*dir2[0];
+ isect[1] = v1[1] + lmbda*dir2[1];
+
+ return P_TRUE;
+}
+
+#if 0
+static PBool p_intersect_line_2d(float *v1, float *v2, float *v3, float *v4, float *isect)
+{
+ float dir1[2], dir2[2];
+
+ dir1[0] = v4[0] - v3[0];
+ dir1[1] = v4[1] - v3[1];
+
+ dir2[0] = v2[0] - v1[0];
+ dir2[1] = v2[1] - v1[1];
+
+ if (!p_intersect_line_2d_dir(v1, dir1, v2, dir2, isect)) {
+ /* parallel - should never happen in theory for polygon kernel, but
+ let's give a point nearby in case things go wrong */
+ isect[0] = (v1[0] + v2[0])*0.5f;
+ isect[1] = (v1[1] + v2[1])*0.5f;
+ return P_FALSE;
+ }
+
+ return P_TRUE;
+}
+#endif
+
+/* Topological Utilities */
+
+static PEdge *p_wheel_edge_next(PEdge *e)
+{
+ return e->next->next->pair;
+}
+
+static PEdge *p_wheel_edge_prev(PEdge *e)
+{
+ return (e->pair)? e->pair->next: NULL;
+}
+
+static PEdge *p_boundary_edge_next(PEdge *e)
+{
+ return e->next->vert->edge;
+}
+
+static PEdge *p_boundary_edge_prev(PEdge *e)
+{
+ PEdge *we = e, *last;
+
+ do {
+ last = we;
+ we = p_wheel_edge_next(we);
+ } while (we && (we != e));
+
+ return last->next->next;
+}
+
+static PBool p_vert_interior(PVert *v)
+{
+ return (v->edge->pair != NULL);
+}
+
+static void p_face_flip(PFace *f)
+{
+ PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
+ PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
+ int f1 = e1->flag, f2 = e2->flag, f3 = e3->flag;
+
+ e1->vert = v2;
+ e1->next = e3;
+ e1->flag = (f1 & ~PEDGE_VERTEX_FLAGS) | (f2 & PEDGE_VERTEX_FLAGS);
+
+ e2->vert = v3;
+ e2->next = e1;
+ e2->flag = (f2 & ~PEDGE_VERTEX_FLAGS) | (f3 & PEDGE_VERTEX_FLAGS);
+
+ e3->vert = v1;
+ e3->next = e2;
+ e3->flag = (f3 & ~PEDGE_VERTEX_FLAGS) | (f1 & PEDGE_VERTEX_FLAGS);
+}
+
+#if 0
+static void p_chart_topological_sanity_check(PChart *chart)
+{
+ PVert *v;
+ PEdge *e;
+
+ for (v=chart->verts; v; v=v->nextlink)
+ param_test_equals_ptr("v->edge->vert", v, v->edge->vert);
+
+ for (e=chart->edges; e; e=e->nextlink) {
+ if (e->pair) {
+ param_test_equals_ptr("e->pair->pair", e, e->pair->pair);
+ param_test_equals_ptr("pair->vert", e->vert, e->pair->next->vert);
+ param_test_equals_ptr("pair->next->vert", e->next->vert, e->pair->vert);
+ }
+ }
+}
+#endif
+
+/* Loading / Flushing */
+
+static void p_vert_load_pin_select_uvs(PVert *v)
+{
+ PEdge *e;
+ int nedges = 0, npins = 0;
+ float pinuv[2];
+
+ v->uv[0] = v->uv[1] = 0.0f;
+ pinuv[0] = pinuv[1] = 0.0f;
+ e = v->edge;
+ do {
+ if (e->orig_uv) {
+ if (e->flag & PEDGE_SELECT)
+ v->flag |= PVERT_SELECT;
+
+ if (e->flag & PEDGE_PIN) {
+ pinuv[0] += e->orig_uv[0];
+ pinuv[1] += e->orig_uv[1];
+ npins++;
+ }
+ else {
+ v->uv[0] += e->orig_uv[0];
+ v->uv[1] += e->orig_uv[1];
+ }
+
+ nedges++;
+ }
+
+ e = p_wheel_edge_next(e);
+ } while (e && e != (v->edge));
+
+ if (npins > 0) {
+ v->uv[0] = pinuv[0]/npins;
+ v->uv[1] = pinuv[1]/npins;
+ v->flag |= PVERT_PIN;
+ }
+ else if (nedges > 0) {
+ v->uv[0] /= nedges;
+ v->uv[1] /= nedges;
+ }
+}
+
+static void p_flush_uvs(PChart *chart)
+{
+ PEdge *e;
+
+ for (e=chart->edges; e; e=e->nextlink) {
+ if (e->orig_uv) {
+ e->orig_uv[0] = e->vert->uv[0];
+ e->orig_uv[1] = e->vert->uv[1];
+ }
+ }
+}
+
+static void p_flush_uvs_blend(PChart *chart, float blend)
+{
+ PEdge *e;
+ float invblend = 1.0f - blend;
+
+ for (e=chart->edges; e; e=e->nextlink) {
+ if (e->orig_uv) {
+ e->orig_uv[0] = blend*e->old_uv[0] + invblend*e->vert->uv[0];
+ e->orig_uv[1] = blend*e->old_uv[1] + invblend*e->vert->uv[1];
+ }
+ }
+}
+
+static void p_face_backup_uvs(PFace *f)
+{
+ PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
+
+ if (e1->orig_uv && e2->orig_uv && e3->orig_uv) {
+ e1->old_uv[0] = e1->orig_uv[0];
+ e1->old_uv[1] = e1->orig_uv[1];
+ e2->old_uv[0] = e2->orig_uv[0];
+ e2->old_uv[1] = e2->orig_uv[1];
+ e3->old_uv[0] = e3->orig_uv[0];
+ e3->old_uv[1] = e3->orig_uv[1];
+ }
+}
+
+static void p_face_restore_uvs(PFace *f)
+{
+ PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
+
+ if (e1->orig_uv && e2->orig_uv && e3->orig_uv) {
+ e1->orig_uv[0] = e1->old_uv[0];
+ e1->orig_uv[1] = e1->old_uv[1];
+ e2->orig_uv[0] = e2->old_uv[0];
+ e2->orig_uv[1] = e2->old_uv[1];
+ e3->orig_uv[0] = e3->old_uv[0];
+ e3->orig_uv[1] = e3->old_uv[1];
+ }
+}
+
+/* Construction (use only during construction, relies on u.key being set */
+
+static PVert *p_vert_add(PHandle *handle, PHashKey key, float *co, PEdge *e)
+{
+ PVert *v = (PVert*)BLI_memarena_alloc(handle->arena, sizeof *v);
+ v->co = co;
+ v->u.key = key;
+ v->edge = e;
+ v->flag = 0;
+
+ phash_insert(handle->hash_verts, (PHashLink*)v);
+
+ return v;
+}
+
+static PVert *p_vert_lookup(PHandle *handle, PHashKey key, float *co, PEdge *e)
+{
+ PVert *v = (PVert*)phash_lookup(handle->hash_verts, key);
+
+ if (v)
+ return v;
+ else
+ return p_vert_add(handle, key, co, e);
+}
+
+static PVert *p_vert_copy(PChart *chart, PVert *v)
+{
+ PVert *nv = (PVert*)BLI_memarena_alloc(chart->handle->arena, sizeof *nv);
+
+ nv->co = v->co;
+ nv->uv[0] = v->uv[0];
+ nv->uv[1] = v->uv[1];
+ nv->u.key = v->u.key;
+ nv->edge = v->edge;
+ nv->flag = v->flag;
+
+ return nv;
+}
+
+static PEdge *p_edge_lookup(PHandle *handle, PHashKey *vkeys)
+{
+ PHashKey key = PHASH_edge(vkeys[0], vkeys[1]);
+ PEdge *e = (PEdge*)phash_lookup(handle->hash_edges, key);
+
+ while (e) {
+ if ((e->vert->u.key == vkeys[0]) && (e->next->vert->u.key == vkeys[1]))
+ return e;
+ else if ((e->vert->u.key == vkeys[1]) && (e->next->vert->u.key == vkeys[0]))
+ return e;
+
+ e = (PEdge*)phash_next(handle->hash_edges, key, (PHashLink*)e);
+ }
+
+ return NULL;
+}
+
+static PBool p_face_exists(PHandle *handle, PHashKey *vkeys, int i1, int i2, int i3)
+{
+ PHashKey key = PHASH_edge(vkeys[i1], vkeys[i2]);
+ PEdge *e = (PEdge*)phash_lookup(handle->hash_edges, key);
+
+ while (e) {
+ if ((e->vert->u.key == vkeys[i1]) && (e->next->vert->u.key == vkeys[i2])) {
+ if (e->next->next->vert->u.key == vkeys[i3])
+ return P_TRUE;
+ }
+ else if ((e->vert->u.key == vkeys[i2]) && (e->next->vert->u.key == vkeys[i1])) {
+ if (e->next->next->vert->u.key == vkeys[i3])
+ return P_TRUE;
+ }
+
+ e = (PEdge*)phash_next(handle->hash_edges, key, (PHashLink*)e);
+ }
+
+ return P_FALSE;
+}
+
+static PChart *p_chart_new(PHandle *handle)
+{
+ PChart *chart = (PChart*)MEM_callocN(sizeof*chart, "PChart");
+ chart->handle = handle;
+
+ return chart;
+}
+
+static void p_chart_delete(PChart *chart)
+{
+ /* the actual links are free by memarena */
+ MEM_freeN(chart);
+}
+
+static PBool p_edge_implicit_seam(PEdge *e, PEdge *ep)
+{
+ float *uv1, *uv2, *uvp1, *uvp2;
+ float limit[2];
+
+ limit[0] = 0.00001;
+ limit[1] = 0.00001;
+
+ uv1 = e->orig_uv;
+ uv2 = e->next->orig_uv;
+
+ if (e->vert->u.key == ep->vert->u.key) {
+ uvp1 = ep->orig_uv;
+ uvp2 = ep->next->orig_uv;
+ }
+ else {
+ uvp1 = ep->next->orig_uv;
+ uvp2 = ep->orig_uv;
+ }
+
+ if((fabs(uv1[0]-uvp1[0]) > limit[0]) || (fabs(uv1[1]-uvp1[1]) > limit[1])) {
+ e->flag |= PEDGE_SEAM;
+ ep->flag |= PEDGE_SEAM;
+ return P_TRUE;
+ }
+ if((fabs(uv2[0]-uvp2[0]) > limit[0]) || (fabs(uv2[1]-uvp2[1]) > limit[1])) {
+ e->flag |= PEDGE_SEAM;
+ ep->flag |= PEDGE_SEAM;
+ return P_TRUE;
+ }
+
+ return P_FALSE;
+}
+
+static PBool p_edge_has_pair(PHandle *handle, PEdge *e, PEdge **pair, PBool impl)
+{
+ PHashKey key;
+ PEdge *pe;
+ PVert *v1, *v2;
+ PHashKey key1 = e->vert->u.key;
+ PHashKey key2 = e->next->vert->u.key;
+
+ if (e->flag & PEDGE_SEAM)
+ return P_FALSE;
+
+ key = PHASH_edge(key1, key2);
+ pe = (PEdge*)phash_lookup(handle->hash_edges, key);
+ *pair = NULL;
+
+ while (pe) {
+ if (pe != e) {
+ v1 = pe->vert;
+ v2 = pe->next->vert;
+
+ if (((v1->u.key == key1) && (v2->u.key == key2)) ||
+ ((v1->u.key == key2) && (v2->u.key == key1))) {
+
+ /* don't connect seams and t-junctions */
+ if ((pe->flag & PEDGE_SEAM) || *pair ||
+ (impl && p_edge_implicit_seam(e, pe))) {
+ *pair = NULL;
+ return P_FALSE;
+ }
+
+ *pair = pe;
+ }
+ }
+
+ pe = (PEdge*)phash_next(handle->hash_edges, key, (PHashLink*)pe);
+ }
+
+ if (*pair && (e->vert == (*pair)->vert)) {
+ if ((*pair)->next->pair || (*pair)->next->next->pair) {
+ /* non unfoldable, maybe mobius ring or klein bottle */
+ *pair = NULL;
+ return P_FALSE;
+ }
+ }
+
+ return (*pair != NULL);
+}
+
+static PBool p_edge_connect_pair(PHandle *handle, PEdge *e, PEdge ***stack, PBool impl)
+{
+ PEdge *pair = NULL;
+
+ if(!e->pair && p_edge_has_pair(handle, e, &pair, impl)) {
+ if (e->vert == pair->vert)
+ p_face_flip(pair->face);
+
+ e->pair = pair;
+ pair->pair = e;
+
+ if (!(pair->face->flag & PFACE_CONNECTED)) {
+ **stack = pair;
+ (*stack)++;
+ }
+ }
+
+ return (e->pair != NULL);
+}
+
+static int p_connect_pairs(PHandle *handle, PBool impl)
+{
+ PEdge **stackbase = MEM_mallocN(sizeof*stackbase*phash_size(handle->hash_faces), "Pstackbase");
+ PEdge **stack = stackbase;
+ PFace *f, *first;
+ PEdge *e, *e1, *e2;
+ PChart *chart = handle->construction_chart;
+ int ncharts = 0;
+
+ /* connect pairs, count edges, set vertex-edge pointer to a pairless edge */
+ for (first=chart->faces; first; first=first->nextlink) {
+ if (first->flag & PFACE_CONNECTED)
+ continue;
+
+ *stack = first->edge;
+ stack++;
+
+ while (stack != stackbase) {
+ stack--;
+ e = *stack;
+ e1 = e->next;
+ e2 = e1->next;
+
+ f = e->face;
+ f->flag |= PFACE_CONNECTED;
+
+ /* assign verts to charts so we can sort them later */
+ f->u.chart = ncharts;
+
+ if (!p_edge_connect_pair(handle, e, &stack, impl))
+ e->vert->edge = e;
+ if (!p_edge_connect_pair(handle, e1, &stack, impl))
+ e1->vert->edge = e1;
+ if (!p_edge_connect_pair(handle, e2, &stack, impl))
+ e2->vert->edge = e2;
+ }
+
+ ncharts++;
+ }
+
+ MEM_freeN(stackbase);
+
+ return ncharts;
+}
+
+static void p_split_vert(PChart *chart, PEdge *e)
+{
+ PEdge *we, *lastwe = NULL;
+ PVert *v = e->vert;
+ PBool copy = P_TRUE;
+
+ if (e->flag & PEDGE_VERTEX_SPLIT)
+ return;
+
+ /* rewind to start */
+ lastwe = e;
+ for (we = p_wheel_edge_prev(e); we && (we != e); we = p_wheel_edge_prev(we))
+ lastwe = we;
+
+ /* go over all edges in wheel */
+ for (we = lastwe; we; we = p_wheel_edge_next(we)) {
+ if (we->flag & PEDGE_VERTEX_SPLIT)
+ break;
+
+ we->flag |= PEDGE_VERTEX_SPLIT;
+
+ if (we == v->edge) {
+ /* found it, no need to copy */
+ copy = P_FALSE;
+ v->nextlink = chart->verts;
+ chart->verts = v;
+ chart->nverts++;
+ }
+ }
+
+ if (copy) {
+ /* not found, copying */
+ v->flag |= PVERT_SPLIT;
+ v = p_vert_copy(chart, v);
+ v->flag |= PVERT_SPLIT;
+
+ v->nextlink = chart->verts;
+ chart->verts = v;
+ chart->nverts++;
+
+ v->edge = lastwe;
+
+ we = lastwe;
+ do {
+ we->vert = v;
+ we = p_wheel_edge_next(we);
+ } while (we && (we != lastwe));
+ }
+}
+
+static PChart **p_split_charts(PHandle *handle, PChart *chart, int ncharts)
+{
+ PChart **charts = MEM_mallocN(sizeof*charts * ncharts, "PCharts"), *nchart;
+ PFace *f, *nextf;
+ int i;
+
+ for (i = 0; i < ncharts; i++)
+ charts[i] = p_chart_new(handle);
+
+ f = chart->faces;
+ while (f) {
+ PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
+ nextf = f->nextlink;
+
+ nchart = charts[f->u.chart];
+
+ f->nextlink = nchart->faces;
+ nchart->faces = f;
+ e1->nextlink = nchart->edges;
+ nchart->edges = e1;
+ e2->nextlink = nchart->edges;
+ nchart->edges = e2;
+ e3->nextlink = nchart->edges;
+ nchart->edges = e3;
+
+ nchart->nfaces++;
+ nchart->nedges += 3;
+
+ p_split_vert(nchart, e1);
+ p_split_vert(nchart, e2);
+ p_split_vert(nchart, e3);
+
+ f = nextf;
+ }
+
+ return charts;
+}
+
+static PFace *p_face_add(PHandle *handle)
+{
+ PFace *f;
+ PEdge *e1, *e2, *e3;
+
+ /* allocate */
+ f = (PFace*)BLI_memarena_alloc(handle->arena, sizeof *f);
+ f->flag=0; // init !
+
+ e1 = (PEdge*)BLI_memarena_alloc(handle->arena, sizeof *e1);
+ e2 = (PEdge*)BLI_memarena_alloc(handle->arena, sizeof *e2);
+ e3 = (PEdge*)BLI_memarena_alloc(handle->arena, sizeof *e3);
+
+ /* set up edges */
+ f->edge = e1;
+ e1->face = e2->face = e3->face = f;
+
+ e1->next = e2;
+ e2->next = e3;
+ e3->next = e1;
+
+ e1->pair = NULL;
+ e2->pair = NULL;
+ e3->pair = NULL;
+
+ e1->flag =0;
+ e2->flag =0;
+ e3->flag =0;
+
+ return f;
+}
+
+static PFace *p_face_add_construct(PHandle *handle, ParamKey key, ParamKey *vkeys,
+ float *co[3], float *uv[3], int i1, int i2, int i3,
+ ParamBool *pin, ParamBool *select)
+{
+ PFace *f = p_face_add(handle);
+ PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
+
+ e1->vert = p_vert_lookup(handle, vkeys[i1], co[i1], e1);
+ e2->vert = p_vert_lookup(handle, vkeys[i2], co[i2], e2);
+ e3->vert = p_vert_lookup(handle, vkeys[i3], co[i3], e3);
+
+ e1->orig_uv = uv[i1];
+ e2->orig_uv = uv[i2];
+ e3->orig_uv = uv[i3];
+
+ if (pin) {
+ if (pin[i1]) e1->flag |= PEDGE_PIN;
+ if (pin[i2]) e2->flag |= PEDGE_PIN;
+ if (pin[i3]) e3->flag |= PEDGE_PIN;
+ }
+
+ if (select) {
+ if (select[i1]) e1->flag |= PEDGE_SELECT;
+ if (select[i2]) e2->flag |= PEDGE_SELECT;
+ if (select[i3]) e3->flag |= PEDGE_SELECT;
+ }
+
+ /* insert into hash */
+ f->u.key = key;
+ phash_insert(handle->hash_faces, (PHashLink*)f);
+
+ e1->u.key = PHASH_edge(vkeys[i1], vkeys[i2]);
+ e2->u.key = PHASH_edge(vkeys[i2], vkeys[i3]);
+ e3->u.key = PHASH_edge(vkeys[i3], vkeys[i1]);
+
+ phash_insert(handle->hash_edges, (PHashLink*)e1);
+ phash_insert(handle->hash_edges, (PHashLink*)e2);
+ phash_insert(handle->hash_edges, (PHashLink*)e3);
+
+ return f;
+}
+
+static PFace *p_face_add_fill(PChart *chart, PVert *v1, PVert *v2, PVert *v3)
+{
+ PFace *f = p_face_add(chart->handle);
+ PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
+
+ e1->vert = v1;
+ e2->vert = v2;
+ e3->vert = v3;
+
+ e1->orig_uv = e2->orig_uv = e3->orig_uv = NULL;
+
+ f->nextlink = chart->faces;
+ chart->faces = f;
+ e1->nextlink = chart->edges;
+ chart->edges = e1;
+ e2->nextlink = chart->edges;
+ chart->edges = e2;
+ e3->nextlink = chart->edges;
+ chart->edges = e3;
+
+ chart->nfaces++;
+ chart->nedges += 3;
+
+ return f;
+}
+
+static PBool p_quad_split_direction(PHandle *handle, float **co, PHashKey *vkeys)
+{
+ float fac= VecLenf(co[0], co[2]) - VecLenf(co[1], co[3]);
+ PBool dir = (fac <= 0.0f);
+
+ /* the face exists check is there because of a special case: when
+ two quads share three vertices, they can each be split into two
+ triangles, resulting in two identical triangles. for example in
+ suzanne's nose. */
+ if (dir) {
+ if (p_face_exists(handle,vkeys,0,1,2) || p_face_exists(handle,vkeys,0,2,3))
+ return !dir;
+ }
+ else {
+ if (p_face_exists(handle,vkeys,0,1,3) || p_face_exists(handle,vkeys,1,2,3))
+ return !dir;
+ }
+
+ return dir;
+}
+
+/* Construction: boundary filling */
+
+static void p_chart_boundaries(PChart *chart, int *nboundaries, PEdge **outer)
+{
+ PEdge *e, *be;
+ float len, maxlen = -1.0;
+
+ if (nboundaries)
+ *nboundaries = 0;
+ if (outer)
+ *outer = NULL;
+
+ for (e=chart->edges; e; e=e->nextlink) {
+ if (e->pair || (e->flag & PEDGE_DONE))
+ continue;
+
+ if (nboundaries)
+ (*nboundaries)++;
+
+ len = 0.0f;
+
+ be = e;
+ do {
+ be->flag |= PEDGE_DONE;
+ len += p_edge_length(be);
+ be = be->next->vert->edge;
+ } while(be != e);
+
+ if (outer && (len > maxlen)) {
+ *outer = e;
+ maxlen = len;
+ }
+ }
+
+ for (e=chart->edges; e; e=e->nextlink)
+ e->flag &= ~PEDGE_DONE;
+}
+
+static float p_edge_boundary_angle(PEdge *e)
+{
+ PEdge *we;
+ PVert *v, *v1, *v2;
+ float angle;
+ int n = 0;
+
+ v = e->vert;
+
+ /* concave angle check -- could be better */
+ angle = M_PI;
+
+ we = v->edge;
+ do {
+ v1 = we->next->vert;
+ v2 = we->next->next->vert;
+ angle -= p_vec_angle(v1->co, v->co, v2->co);
+
+ we = we->next->next->pair;
+ n++;
+ } while (we && (we != v->edge));
+
+ return angle;
+}
+
+static void p_chart_fill_boundary(PChart *chart, PEdge *be, int nedges)
+{
+ PEdge *e, *e1, *e2;
+ PHashKey vkeys[3];
+ PFace *f;
+ struct Heap *heap = BLI_heap_new();
+ float angle;
+
+ e = be;
+ do {
+ angle = p_edge_boundary_angle(e);
+ e->u.heaplink = BLI_heap_insert(heap, angle, e);
+
+ e = p_boundary_edge_next(e);
+ } while(e != be);
+
+ if (nedges == 2) {
+ /* no real boundary, but an isolated seam */
+ e = be->next->vert->edge;
+ e->pair = be;
+ be->pair = e;
+
+ BLI_heap_remove(heap, e->u.heaplink);
+ BLI_heap_remove(heap, be->u.heaplink);
+ }
+ else {
+ while (nedges > 2) {
+ PEdge *ne, *ne1, *ne2;
+
+ e = (PEdge*)BLI_heap_popmin(heap);
+
+ e1 = p_boundary_edge_prev(e);
+ e2 = p_boundary_edge_next(e);
+
+ BLI_heap_remove(heap, e1->u.heaplink);
+ BLI_heap_remove(heap, e2->u.heaplink);
+ e->u.heaplink = e1->u.heaplink = e2->u.heaplink = NULL;
+
+ e->flag |= PEDGE_FILLED;
+ e1->flag |= PEDGE_FILLED;
+
+ vkeys[0] = e->vert->u.key;
+ vkeys[1] = e1->vert->u.key;
+ vkeys[2] = e2->vert->u.key;
+
+ f = p_face_add_fill(chart, e->vert, e1->vert, e2->vert);
+ f->flag |= PFACE_FILLED;
+
+ ne = f->edge->next->next;
+ ne1 = f->edge;
+ ne2 = f->edge->next;
+
+ ne->flag = ne1->flag = ne2->flag = PEDGE_FILLED;
+
+ e->pair = ne;
+ ne->pair = e;
+ e1->pair = ne1;
+ ne1->pair = e1;
+
+ ne->vert = e2->vert;
+ ne1->vert = e->vert;
+ ne2->vert = e1->vert;
+
+ if (nedges == 3) {
+ e2->pair = ne2;
+ ne2->pair = e2;
+ }
+ else {
+ ne2->vert->edge = ne2;
+
+ ne2->u.heaplink = BLI_heap_insert(heap, p_edge_boundary_angle(ne2), ne2);
+ e2->u.heaplink = BLI_heap_insert(heap, p_edge_boundary_angle(e2), e2);
+ }
+
+ nedges--;
+ }
+ }
+
+ BLI_heap_free(heap, NULL);
+}
+
+static void p_chart_fill_boundaries(PChart *chart, PEdge *outer)
+{
+ PEdge *e, *enext, *be;
+ int nedges;
+
+ for (e=chart->edges; e; e=e->nextlink) {
+ enext = e->nextlink;
+
+ if (e->pair || (e->flag & PEDGE_FILLED))
+ continue;
+
+ nedges = 0;
+ be = e;
+ do {
+ be->flag |= PEDGE_FILLED;
+ be = be->next->vert->edge;
+ nedges++;
+ } while(be != e);
+
+ if (e != outer)
+ p_chart_fill_boundary(chart, e, nedges);
+ }
+}
+
+#if 0
+/* Polygon kernel for inserting uv's non overlapping */
+
+static int p_polygon_point_in(float *cp1, float *cp2, float *p)
+{
+ if ((cp1[0] == p[0]) && (cp1[1] == p[1]))
+ return 2;
+ else if ((cp2[0] == p[0]) && (cp2[1] == p[1]))
+ return 3;
+ else
+ return (p_area_signed(cp1, cp2, p) >= 0.0f);
+}
+
+static void p_polygon_kernel_clip(float (*oldpoints)[2], int noldpoints, float (*newpoints)[2], int *nnewpoints, float *cp1, float *cp2)
+{
+ float *p2, *p1, isect[2];
+ int i, p2in, p1in;
+
+ p1 = oldpoints[noldpoints-1];
+ p1in = p_polygon_point_in(cp1, cp2, p1);
+ *nnewpoints = 0;
+
+ for (i = 0; i < noldpoints; i++) {
+ p2 = oldpoints[i];
+ p2in = p_polygon_point_in(cp1, cp2, p2);
+
+ if ((p2in >= 2) || (p1in && p2in)) {
+ newpoints[*nnewpoints][0] = p2[0];
+ newpoints[*nnewpoints][1] = p2[1];
+ (*nnewpoints)++;
+ }
+ else if (p1in && !p2in) {
+ if (p1in != 3) {
+ p_intersect_line_2d(p1, p2, cp1, cp2, isect);
+ newpoints[*nnewpoints][0] = isect[0];
+ newpoints[*nnewpoints][1] = isect[1];
+ (*nnewpoints)++;
+ }
+ }
+ else if (!p1in && p2in) {
+ p_intersect_line_2d(p1, p2, cp1, cp2, isect);
+ newpoints[*nnewpoints][0] = isect[0];
+ newpoints[*nnewpoints][1] = isect[1];
+ (*nnewpoints)++;
+
+ newpoints[*nnewpoints][0] = p2[0];
+ newpoints[*nnewpoints][1] = p2[1];
+ (*nnewpoints)++;
+ }
+
+ p1in = p2in;
+ p1 = p2;
+ }
+}
+
+static void p_polygon_kernel_center(float (*points)[2], int npoints, float *center)
+{
+ int i, size, nnewpoints = npoints;
+ float (*oldpoints)[2], (*newpoints)[2], *p1, *p2;
+
+ size = npoints*3;
+ oldpoints = MEM_mallocN(sizeof(float)*2*size, "PPolygonOldPoints");
+ newpoints = MEM_mallocN(sizeof(float)*2*size, "PPolygonNewPoints");
+
+ memcpy(oldpoints, points, sizeof(float)*2*npoints);
+
+ for (i = 0; i < npoints; i++) {
+ p1 = points[i];
+ p2 = points[(i+1)%npoints];
+ p_polygon_kernel_clip(oldpoints, nnewpoints, newpoints, &nnewpoints, p1, p2);
+
+ if (nnewpoints == 0) {
+ /* degenerate case, use center of original polygon */
+ memcpy(oldpoints, points, sizeof(float)*2*npoints);
+ nnewpoints = npoints;
+ break;
+ }
+ else if (nnewpoints == 1) {
+ /* degenerate case, use remaining point */
+ center[0] = newpoints[0][0];
+ center[1] = newpoints[0][1];
+
+ MEM_freeN(oldpoints);
+ MEM_freeN(newpoints);
+
+ return;
+ }
+
+ if (nnewpoints*2 > size) {
+ size *= 2;
+ free(oldpoints);
+ oldpoints = malloc(sizeof(float)*2*size);
+ memcpy(oldpoints, newpoints, sizeof(float)*2*nnewpoints);
+ free(newpoints);
+ newpoints = malloc(sizeof(float)*2*size);
+ }
+ else {
+ float (*sw_points)[2] = oldpoints;
+ oldpoints = newpoints;
+ newpoints = sw_points;
+ }
+ }
+
+ center[0] = center[1] = 0.0f;
+
+ for (i = 0; i < nnewpoints; i++) {
+ center[0] += oldpoints[i][0];
+ center[1] += oldpoints[i][1];
+ }
+
+ center[0] /= nnewpoints;
+ center[1] /= nnewpoints;
+
+ MEM_freeN(oldpoints);
+ MEM_freeN(newpoints);
+}
+#endif
+
+#if 0
+/* Edge Collapser */
+
+int NCOLLAPSE = 1;
+int NCOLLAPSEX = 0;
+
+static float p_vert_cotan(float *v1, float *v2, float *v3)
+{
+ float a[3], b[3], c[3], clen;
+
+ VecSubf(a, v2, v1);
+ VecSubf(b, v3, v1);
+ Crossf(c, a, b);
+
+ clen = VecLength(c);
+
+ if (clen == 0.0f)
+ return 0.0f;
+
+ return Inpf(a, b)/clen;
+}
+
+static PBool p_vert_flipped_wheel_triangle(PVert *v)
+{
+ PEdge *e = v->edge;
+
+ do {
+ if (p_face_uv_area_signed(e->face) < 0.0f)
+ return P_TRUE;
+
+ e = p_wheel_edge_next(e);
+ } while (e && (e != v->edge));
+
+ return P_FALSE;
+}
+
+static PBool p_vert_map_harmonic_weights(PVert *v)
+{
+ float weightsum, positionsum[2], olduv[2];
+
+ weightsum = 0.0f;
+ positionsum[0] = positionsum[1] = 0.0f;
+
+ if (p_vert_interior(v)) {
+ PEdge *e = v->edge;
+
+ do {
+ float t1, t2, weight;
+ PVert *v1, *v2;
+
+ v1 = e->next->vert;
+ v2 = e->next->next->vert;
+ t1 = p_vert_cotan(v2->co, e->vert->co, v1->co);
+
+ v1 = e->pair->next->vert;
+ v2 = e->pair->next->next->vert;
+ t2 = p_vert_cotan(v2->co, e->pair->vert->co, v1->co);
+
+ weight = 0.5f*(t1 + t2);
+ weightsum += weight;
+ positionsum[0] += weight*e->pair->vert->uv[0];
+ positionsum[1] += weight*e->pair->vert->uv[1];
+
+ e = p_wheel_edge_next(e);
+ } while (e && (e != v->edge));
+ }
+ else {
+ PEdge *e = v->edge;
+
+ do {
+ float t1, t2;
+ PVert *v1, *v2;
+
+ v2 = e->next->vert;
+ v1 = e->next->next->vert;
+
+ t1 = p_vert_cotan(v1->co, v->co, v2->co);
+ t2 = p_vert_cotan(v2->co, v->co, v1->co);
+
+ weightsum += t1 + t2;
+ positionsum[0] += (v2->uv[1] - v1->uv[1]) + (t1*v2->uv[0] + t2*v1->uv[0]);
+ positionsum[1] += (v1->uv[0] - v2->uv[0]) + (t1*v2->uv[1] + t2*v1->uv[1]);
+
+ e = p_wheel_edge_next(e);
+ } while (e && (e != v->edge));
+ }
+
+ if (weightsum != 0.0f) {
+ weightsum = 1.0f/weightsum;
+ positionsum[0] *= weightsum;
+ positionsum[1] *= weightsum;
+ }
+
+ olduv[0] = v->uv[0];
+ olduv[1] = v->uv[1];
+ v->uv[0] = positionsum[0];
+ v->uv[1] = positionsum[1];
+
+ if (p_vert_flipped_wheel_triangle(v)) {
+ v->uv[0] = olduv[0];
+ v->uv[1] = olduv[1];
+
+ return P_FALSE;
+ }
+
+ return P_TRUE;
+}
+
+static void p_vert_harmonic_insert(PVert *v)
+{
+ PEdge *e;
+
+ if (!p_vert_map_harmonic_weights(v)) {
+ /* do polygon kernel center insertion: this is quite slow, but should
+ only be needed for 0.01 % of verts or so, when insert with harmonic
+ weights fails */
+
+ int npoints = 0, i;
+ float (*points)[2];
+
+ e = v->edge;
+ do {
+ npoints++;
+ e = p_wheel_edge_next(e);
+ } while (e && (e != v->edge));
+
+ if (e == NULL)
+ npoints++;
+
+ points = MEM_mallocN(sizeof(float)*2*npoints, "PHarmonicPoints");
+
+ e = v->edge;
+ i = 0;
+ do {
+ PEdge *nexte = p_wheel_edge_next(e);
+
+ points[i][0] = e->next->vert->uv[0];
+ points[i][1] = e->next->vert->uv[1];
+
+ if (nexte == NULL) {
+ i++;
+ points[i][0] = e->next->next->vert->uv[0];
+ points[i][1] = e->next->next->vert->uv[1];
+ break;
+ }
+
+ e = nexte;
+ i++;
+ } while (e != v->edge);
+
+ p_polygon_kernel_center(points, npoints, v->uv);
+
+ MEM_freeN(points);
+ }
+
+ e = v->edge;
+ do {
+ if (!(e->next->vert->flag & PVERT_PIN))
+ p_vert_map_harmonic_weights(e->next->vert);
+ e = p_wheel_edge_next(e);
+ } while (e && (e != v->edge));
+
+ p_vert_map_harmonic_weights(v);
+}
+
+static void p_vert_fix_edge_pointer(PVert *v)
+{
+ PEdge *start = v->edge;
+
+ /* set v->edge pointer to the edge with no pair, if there is one */
+ while (v->edge->pair) {
+ v->edge = p_wheel_edge_prev(v->edge);
+
+ if (v->edge == start)
+ break;
+ }
+}
+
+static void p_collapsing_verts(PEdge *edge, PEdge *pair, PVert **newv, PVert **keepv)
+{
+ /* the two vertices that are involved in the collapse */
+ if (edge) {
+ *newv = edge->vert;
+ *keepv = edge->next->vert;
+ }
+ else {
+ *newv = pair->next->vert;
+ *keepv = pair->vert;
+ }
+}
+
+static void p_collapse_edge(PEdge *edge, PEdge *pair)
+{
+ PVert *oldv, *keepv;
+ PEdge *e;
+
+ p_collapsing_verts(edge, pair, &oldv, &keepv);
+
+ /* change e->vert pointers from old vertex to the target vertex */
+ e = oldv->edge;
+ do {
+ if ((e != edge) && !(pair && pair->next == e))
+ e->vert = keepv;
+
+ e = p_wheel_edge_next(e);
+ } while (e && (e != oldv->edge));
+
+ /* set keepv->edge pointer */
+ if ((edge && (keepv->edge == edge->next)) || (keepv->edge == pair)) {
+ if (edge && edge->next->pair)
+ keepv->edge = edge->next->pair->next;
+ else if (pair && pair->next->next->pair)
+ keepv->edge = pair->next->next->pair;
+ else if (edge && edge->next->next->pair)
+ keepv->edge = edge->next->next->pair;
+ else
+ keepv->edge = pair->next->pair->next;
+ }
+
+ /* update pairs and v->edge pointers */
+ if (edge) {
+ PEdge *e1 = edge->next, *e2 = e1->next;
+
+ if (e1->pair)
+ e1->pair->pair = e2->pair;
+
+ if (e2->pair) {
+ e2->pair->pair = e1->pair;
+ e2->vert->edge = p_wheel_edge_prev(e2);
+ }
+ else
+ e2->vert->edge = p_wheel_edge_next(e2);
+
+ p_vert_fix_edge_pointer(e2->vert);
+ }
+
+ if (pair) {
+ PEdge *e1 = pair->next, *e2 = e1->next;
+
+ if (e1->pair)
+ e1->pair->pair = e2->pair;
+
+ if (e2->pair) {
+ e2->pair->pair = e1->pair;
+ e2->vert->edge = p_wheel_edge_prev(e2);
+ }
+ else
+ e2->vert->edge = p_wheel_edge_next(e2);
+
+ p_vert_fix_edge_pointer(e2->vert);
+ }
+
+ p_vert_fix_edge_pointer(keepv);
+
+ /* mark for move to collapsed list later */
+ oldv->flag |= PVERT_COLLAPSE;
+
+ if (edge) {
+ PFace *f = edge->face;
+ PEdge *e1 = edge->next, *e2 = e1->next;
+
+ f->flag |= PFACE_COLLAPSE;
+ edge->flag |= PEDGE_COLLAPSE;
+ e1->flag |= PEDGE_COLLAPSE;
+ e2->flag |= PEDGE_COLLAPSE;
+ }
+
+ if (pair) {
+ PFace *f = pair->face;
+ PEdge *e1 = pair->next, *e2 = e1->next;
+
+ f->flag |= PFACE_COLLAPSE;
+ pair->flag |= PEDGE_COLLAPSE;
+ e1->flag |= PEDGE_COLLAPSE;
+ e2->flag |= PEDGE_COLLAPSE;
+ }
+}
+
+static void p_split_vertex(PEdge *edge, PEdge *pair)
+{
+ PVert *newv, *keepv;
+ PEdge *e;
+
+ p_collapsing_verts(edge, pair, &newv, &keepv);
+
+ /* update edge pairs */
+ if (edge) {
+ PEdge *e1 = edge->next, *e2 = e1->next;
+
+ if (e1->pair)
+ e1->pair->pair = e1;
+ if (e2->pair)
+ e2->pair->pair = e2;
+
+ e2->vert->edge = e2;
+ p_vert_fix_edge_pointer(e2->vert);
+ keepv->edge = e1;
+ }
+
+ if (pair) {
+ PEdge *e1 = pair->next, *e2 = e1->next;
+
+ if (e1->pair)
+ e1->pair->pair = e1;
+ if (e2->pair)
+ e2->pair->pair = e2;
+
+ e2->vert->edge = e2;
+ p_vert_fix_edge_pointer(e2->vert);
+ keepv->edge = pair;
+ }
+
+ p_vert_fix_edge_pointer(keepv);
+
+ /* set e->vert pointers to restored vertex */
+ e = newv->edge;
+ do {
+ e->vert = newv;
+ e = p_wheel_edge_next(e);
+ } while (e && (e != newv->edge));
+}
+
+static PBool p_collapse_allowed_topologic(PEdge *edge, PEdge *pair)
+{
+ PVert *oldv, *keepv;
+
+ p_collapsing_verts(edge, pair, &oldv, &keepv);
+
+ /* boundary edges */
+ if (!edge || !pair) {
+ /* avoid collapsing chart into an edge */
+ if (edge && !edge->next->pair && !edge->next->next->pair)
+ return P_FALSE;
+ else if (pair && !pair->next->pair && !pair->next->next->pair)
+ return P_FALSE;
+ }
+ /* avoid merging two boundaries (oldv and keepv are on the 'other side' of
+ the chart) */
+ else if (!p_vert_interior(oldv) && !p_vert_interior(keepv))
+ return P_FALSE;
+
+ return P_TRUE;
+}
+
+static PBool p_collapse_normal_flipped(float *v1, float *v2, float *vold, float *vnew)
+{
+ float nold[3], nnew[3], sub1[3], sub2[3];
+
+ VecSubf(sub1, vold, v1);
+ VecSubf(sub2, vold, v2);
+ Crossf(nold, sub1, sub2);
+
+ VecSubf(sub1, vnew, v1);
+ VecSubf(sub2, vnew, v2);
+ Crossf(nnew, sub1, sub2);
+
+ return (Inpf(nold, nnew) <= 0.0f);
+}
+
+static PBool p_collapse_allowed_geometric(PEdge *edge, PEdge *pair)
+{
+ PVert *oldv, *keepv;
+ PEdge *e;
+ float angulardefect, angle;
+
+ p_collapsing_verts(edge, pair, &oldv, &keepv);
+
+ angulardefect = 2*M_PI;
+
+ e = oldv->edge;
+ do {
+ float a[3], b[3], minangle, maxangle;
+ PEdge *e1 = e->next, *e2 = e1->next;
+ PVert *v1 = e1->vert, *v2 = e2->vert;
+ int i;
+
+ angle = p_vec_angle(v1->co, oldv->co, v2->co);
+ angulardefect -= angle;
+
+ /* skip collapsing faces */
+ if (v1 == keepv || v2 == keepv) {
+ e = p_wheel_edge_next(e);
+ continue;
+ }
+
+ if (p_collapse_normal_flipped(v1->co, v2->co, oldv->co, keepv->co))
+ return P_FALSE;
+
+ a[0] = angle;
+ a[1] = p_vec_angle(v2->co, v1->co, oldv->co);
+ a[2] = M_PI - a[0] - a[1];
+
+ b[0] = p_vec_angle(v1->co, keepv->co, v2->co);
+ b[1] = p_vec_angle(v2->co, v1->co, keepv->co);
+ b[2] = M_PI - b[0] - b[1];
+
+ /* abf criterion 1: avoid sharp and obtuse angles */
+ minangle = 15.0f*M_PI/180.0f;
+ maxangle = M_PI - minangle;
+
+ for (i = 0; i < 3; i++) {
+ if ((b[i] < a[i]) && (b[i] < minangle))
+ return P_FALSE;
+ else if ((b[i] > a[i]) && (b[i] > maxangle))
+ return P_FALSE;
+ }
+
+ e = p_wheel_edge_next(e);
+ } while (e && (e != oldv->edge));
+
+ if (p_vert_interior(oldv)) {
+ /* hlscm criterion: angular defect smaller than threshold */
+ if (fabs(angulardefect) > (M_PI*30.0/180.0))
+ return P_FALSE;
+ }
+ else {
+ PVert *v1 = p_boundary_edge_next(oldv->edge)->vert;
+ PVert *v2 = p_boundary_edge_prev(oldv->edge)->vert;
+
+ /* abf++ criterion 2: avoid collapsing verts inwards */
+ if (p_vert_interior(keepv))
+ return P_FALSE;
+
+ /* don't collapse significant boundary changes */
+ angle = p_vec_angle(v1->co, oldv->co, v2->co);
+ if (angle < (M_PI*160.0/180.0))
+ return P_FALSE;
+ }
+
+ return P_TRUE;
+}
+
+static PBool p_collapse_allowed(PEdge *edge, PEdge *pair)
+{
+ PVert *oldv, *keepv;
+
+ p_collapsing_verts(edge, pair, &oldv, &keepv);
+
+ if (oldv->flag & PVERT_PIN)
+ return P_FALSE;
+
+ return (p_collapse_allowed_topologic(edge, pair) &&
+ p_collapse_allowed_geometric(edge, pair));
+}
+
+static float p_collapse_cost(PEdge *edge, PEdge *pair)
+{
+ /* based on volume and boundary optimization from:
+ "Fast and Memory Efficient Polygonal Simplification" P. Lindstrom, G. Turk */
+
+ PVert *oldv, *keepv;
+ PEdge *e;
+ PFace *oldf1, *oldf2;
+ float volumecost = 0.0f, areacost = 0.0f, edgevec[3], cost, weight, elen;
+ float shapecost = 0.0f;
+ float shapeold = 0.0f, shapenew = 0.0f;
+ int nshapeold = 0, nshapenew = 0;
+
+ p_collapsing_verts(edge, pair, &oldv, &keepv);
+ oldf1 = (edge)? edge->face: NULL;
+ oldf2 = (pair)? pair->face: NULL;
+
+ VecSubf(edgevec, keepv->co, oldv->co);
+
+ e = oldv->edge;
+ do {
+ float a1, a2, a3;
+ float *co1 = e->next->vert->co;
+ float *co2 = e->next->next->vert->co;
+
+ if ((e->face != oldf1) && (e->face != oldf2)) {
+ float tetrav2[3], tetrav3[3], c[3];
+
+ /* tetrahedron volume = (1/3!)*|a.(b x c)| */
+ VecSubf(tetrav2, co1, oldv->co);
+ VecSubf(tetrav3, co2, oldv->co);
+ Crossf(c, tetrav2, tetrav3);
+
+ volumecost += fabs(Inpf(edgevec, c)/6.0f);
+#if 0
+ shapecost += Inpf(co1, keepv->co);
+
+ if (p_wheel_edge_next(e) == NULL)
+ shapecost += Inpf(co2, keepv->co);
+#endif
+
+ p_triangle_angles(oldv->co, co1, co2, &a1, &a2, &a3);
+ a1 = a1 - M_PI/3.0;
+ a2 = a2 - M_PI/3.0;
+ a3 = a3 - M_PI/3.0;
+ shapeold = (a1*a1 + a2*a2 + a3*a3)/((M_PI/2)*(M_PI/2));
+
+ nshapeold++;
+ }
+ else {
+ p_triangle_angles(keepv->co, co1, co2, &a1, &a2, &a3);
+ a1 = a1 - M_PI/3.0;
+ a2 = a2 - M_PI/3.0;
+ a3 = a3 - M_PI/3.0;
+ shapenew = (a1*a1 + a2*a2 + a3*a3)/((M_PI/2)*(M_PI/2));
+
+ nshapenew++;
+ }
+
+ e = p_wheel_edge_next(e);
+ } while (e && (e != oldv->edge));
+
+ if (!p_vert_interior(oldv)) {
+ PVert *v1 = p_boundary_edge_prev(oldv->edge)->vert;
+ PVert *v2 = p_boundary_edge_next(oldv->edge)->vert;
+
+ areacost = AreaT3Dfl(oldv->co, v1->co, v2->co);
+ }
+
+ elen = VecLength(edgevec);
+ weight = 1.0f; /* 0.2f */
+ cost = weight*volumecost*volumecost + elen*elen*areacost*areacost;
+#if 0
+ cost += shapecost;
+#else
+ shapeold /= nshapeold;
+ shapenew /= nshapenew;
+ shapecost = (shapeold + 0.00001)/(shapenew + 0.00001);
+
+ cost *= shapecost;
+#endif
+
+ return cost;
+}
+
+static void p_collapse_cost_vertex(PVert *vert, float *mincost, PEdge **mine)
+{
+ PEdge *e, *enext, *pair;
+
+ *mine = NULL;
+ *mincost = 0.0f;
+ e = vert->edge;
+ do {
+ if (p_collapse_allowed(e, e->pair)) {
+ float cost = p_collapse_cost(e, e->pair);
+
+ if ((*mine == NULL) || (cost < *mincost)) {
+ *mincost = cost;
+ *mine = e;
+ }
+ }
+
+ enext = p_wheel_edge_next(e);
+
+ if (enext == NULL) {
+ /* the other boundary edge, where we only have the pair halfedge */
+ pair = e->next->next;
+
+ if (p_collapse_allowed(NULL, pair)) {
+ float cost = p_collapse_cost(NULL, pair);
+
+ if ((*mine == NULL) || (cost < *mincost)) {
+ *mincost = cost;
+ *mine = pair;
+ }
+ }
+
+ break;
+ }
+
+ e = enext;
+ } while (e != vert->edge);
+}
+
+static void p_chart_post_collapse_flush(PChart *chart, PEdge *collapsed)
+{
+ /* move to collapsed_ */
+
+ PVert *v, *nextv = NULL, *verts = chart->verts;
+ PEdge *e, *nexte = NULL, *edges = chart->edges, *laste = NULL;
+ PFace *f, *nextf = NULL, *faces = chart->faces;
+
+ chart->verts = chart->collapsed_verts = NULL;
+ chart->edges = chart->collapsed_edges = NULL;
+ chart->faces = chart->collapsed_faces = NULL;
+
+ chart->nverts = chart->nedges = chart->nfaces = 0;
+
+ for (v=verts; v; v=nextv) {
+ nextv = v->nextlink;
+
+ if (v->flag & PVERT_COLLAPSE) {
+ v->nextlink = chart->collapsed_verts;
+ chart->collapsed_verts = v;
+ }
+ else {
+ v->nextlink = chart->verts;
+ chart->verts = v;
+ chart->nverts++;
+ }
+ }
+
+ for (e=edges; e; e=nexte) {
+ nexte = e->nextlink;
+
+ if (!collapsed || !(e->flag & PEDGE_COLLAPSE_EDGE)) {
+ if (e->flag & PEDGE_COLLAPSE) {
+ e->nextlink = chart->collapsed_edges;
+ chart->collapsed_edges = e;
+ }
+ else {
+ e->nextlink = chart->edges;
+ chart->edges = e;
+ chart->nedges++;
+ }
+ }
+ }
+
+ /* these are added last so they can be popped of in the right order
+ for splitting */
+ for (e=collapsed; e; e=e->nextlink) {
+ e->nextlink = e->u.nextcollapse;
+ laste = e;
+ }
+ if (laste) {
+ laste->nextlink = chart->collapsed_edges;
+ chart->collapsed_edges = collapsed;
+ }
+
+ for (f=faces; f; f=nextf) {
+ nextf = f->nextlink;
+
+ if (f->flag & PFACE_COLLAPSE) {
+ f->nextlink = chart->collapsed_faces;
+ chart->collapsed_faces = f;
+ }
+ else {
+ f->nextlink = chart->faces;
+ chart->faces = f;
+ chart->nfaces++;
+ }
+ }
+}
+
+static void p_chart_post_split_flush(PChart *chart)
+{
+ /* move from collapsed_ */
+
+ PVert *v, *nextv = NULL;
+ PEdge *e, *nexte = NULL;
+ PFace *f, *nextf = NULL;
+
+ for (v=chart->collapsed_verts; v; v=nextv) {
+ nextv = v->nextlink;
+ v->nextlink = chart->verts;
+ chart->verts = v;
+ chart->nverts++;
+ }
+
+ for (e=chart->collapsed_edges; e; e=nexte) {
+ nexte = e->nextlink;
+ e->nextlink = chart->edges;
+ chart->edges = e;
+ chart->nedges++;
+ }
+
+ for (f=chart->collapsed_faces; f; f=nextf) {
+ nextf = f->nextlink;
+ f->nextlink = chart->faces;
+ chart->faces = f;
+ chart->nfaces++;
+ }
+
+ chart->collapsed_verts = NULL;
+ chart->collapsed_edges = NULL;
+ chart->collapsed_faces = NULL;
+}
+
+static void p_chart_simplify_compute(PChart *chart)
+{
+ /* Computes a list of edge collapses / vertex splits. The collapsed
+ simplices go in the chart->collapsed_* lists, The original and
+ collapsed may then be view as stacks, where the next collapse/split
+ is at the top of the respective lists. */
+
+ Heap *heap = BLI_heap_new();
+ PVert *v, **wheelverts;
+ PEdge *collapsededges = NULL, *e;
+ int nwheelverts, i, ncollapsed = 0;
+
+ wheelverts = MEM_mallocN(sizeof(PVert*)*chart->nverts, "PChartWheelVerts");
+
+ /* insert all potential collapses into heap */
+ for (v=chart->verts; v; v=v->nextlink) {
+ float cost;
+ PEdge *e = NULL;
+
+ p_collapse_cost_vertex(v, &cost, &e);
+
+ if (e)
+ v->u.heaplink = BLI_heap_insert(heap, cost, e);
+ else
+ v->u.heaplink = NULL;
+ }
+
+ for (e=chart->edges; e; e=e->nextlink)
+ e->u.nextcollapse = NULL;
+
+ /* pop edge collapse out of heap one by one */
+ while (!BLI_heap_empty(heap)) {
+ if (ncollapsed == NCOLLAPSE)
+ break;
+
+ HeapNode *link = BLI_heap_top(heap);
+ PEdge *edge = (PEdge*)BLI_heap_popmin(heap), *pair = edge->pair;
+ PVert *oldv, *keepv;
+ PEdge *wheele, *nexte;
+
+ /* remember the edges we collapsed */
+ edge->u.nextcollapse = collapsededges;
+ collapsededges = edge;
+
+ if (edge->vert->u.heaplink != link) {
+ edge->flag |= (PEDGE_COLLAPSE_EDGE|PEDGE_COLLAPSE_PAIR);
+ edge->next->vert->u.heaplink = NULL;
+ SWAP(PEdge*, edge, pair);
+ }
+ else {
+ edge->flag |= PEDGE_COLLAPSE_EDGE;
+ edge->vert->u.heaplink = NULL;
+ }
+
+ p_collapsing_verts(edge, pair, &oldv, &keepv);
+
+ /* gather all wheel verts and remember them before collapse */
+ nwheelverts = 0;
+ wheele = oldv->edge;
+
+ do {
+ wheelverts[nwheelverts++] = wheele->next->vert;
+ nexte = p_wheel_edge_next(wheele);
+
+ if (nexte == NULL)
+ wheelverts[nwheelverts++] = wheele->next->next->vert;
+
+ wheele = nexte;
+ } while (wheele && (wheele != oldv->edge));
+
+ /* collapse */
+ p_collapse_edge(edge, pair);
+
+ for (i = 0; i < nwheelverts; i++) {
+ float cost;
+ PEdge *collapse = NULL;
+
+ v = wheelverts[i];
+
+ if (v->u.heaplink) {
+ BLI_heap_remove(heap, v->u.heaplink);
+ v->u.heaplink = NULL;
+ }
+
+ p_collapse_cost_vertex(v, &cost, &collapse);
+
+ if (collapse)
+ v->u.heaplink = BLI_heap_insert(heap, cost, collapse);
+ }
+
+ ncollapsed++;
+ }
+
+ MEM_freeN(wheelverts);
+ BLI_heap_free(heap, NULL);
+
+ p_chart_post_collapse_flush(chart, collapsededges);
+}
+
+static void p_chart_complexify(PChart *chart)
+{
+ PEdge *e, *pair, *edge;
+ PVert *newv, *keepv;
+ int x = 0;
+
+ for (e=chart->collapsed_edges; e; e=e->nextlink) {
+ if (!(e->flag & PEDGE_COLLAPSE_EDGE))
+ break;
+
+ edge = e;
+ pair = e->pair;
+
+ if (edge->flag & PEDGE_COLLAPSE_PAIR) {
+ SWAP(PEdge*, edge, pair);
+ }
+
+ p_split_vertex(edge, pair);
+ p_collapsing_verts(edge, pair, &newv, &keepv);
+
+ if (x >= NCOLLAPSEX) {
+ newv->uv[0] = keepv->uv[0];
+ newv->uv[1] = keepv->uv[1];
+ }
+ else {
+ p_vert_harmonic_insert(newv);
+ x++;
+ }
+ }
+
+ p_chart_post_split_flush(chart);
+}
+
+#if 0
+static void p_chart_simplify(PChart *chart)
+{
+ /* Not implemented, needs proper reordering in split_flush. */
+}
+#endif
+#endif
+
+/* ABF */
+
+#define ABF_MAX_ITER 20
+
+typedef struct PAbfSystem {
+ int ninterior, nfaces, nangles;
+ float *alpha, *beta, *sine, *cosine, *weight;
+ float *bAlpha, *bTriangle, *bInterior;
+ float *lambdaTriangle, *lambdaPlanar, *lambdaLength;
+ float (*J2dt)[3], *bstar, *dstar;
+ float minangle, maxangle;
+} PAbfSystem;
+
+static void p_abf_setup_system(PAbfSystem *sys)
+{
+ int i;
+
+ sys->alpha = (float*)MEM_mallocN(sizeof(float)*sys->nangles, "ABFalpha");
+ sys->beta = (float*)MEM_mallocN(sizeof(float)*sys->nangles, "ABFbeta");
+ sys->sine = (float*)MEM_mallocN(sizeof(float)*sys->nangles, "ABFsine");
+ sys->cosine = (float*)MEM_mallocN(sizeof(float)*sys->nangles, "ABFcosine");
+ sys->weight = (float*)MEM_mallocN(sizeof(float)*sys->nangles, "ABFweight");
+
+ sys->bAlpha = (float*)MEM_mallocN(sizeof(float)*sys->nangles, "ABFbalpha");
+ sys->bTriangle = (float*)MEM_mallocN(sizeof(float)*sys->nfaces, "ABFbtriangle");
+ sys->bInterior = (float*)MEM_mallocN(sizeof(float)*2*sys->ninterior, "ABFbinterior");
+
+ sys->lambdaTriangle = (float*)MEM_callocN(sizeof(float)*sys->nfaces, "ABFlambdatri");
+ sys->lambdaPlanar = (float*)MEM_callocN(sizeof(float)*sys->ninterior, "ABFlamdaplane");
+ sys->lambdaLength = (float*)MEM_mallocN(sizeof(float)*sys->ninterior, "ABFlambdalen");
+
+ sys->J2dt = MEM_mallocN(sizeof(float)*sys->nangles*3, "ABFj2dt");
+ sys->bstar = (float*)MEM_mallocN(sizeof(float)*sys->nfaces, "ABFbstar");
+ sys->dstar = (float*)MEM_mallocN(sizeof(float)*sys->nfaces, "ABFdstar");
+
+ for (i = 0; i < sys->ninterior; i++)
+ sys->lambdaLength[i] = 1.0;
+
+ sys->minangle = 7.5f*M_PI/180.0f;
+ sys->maxangle = M_PI - sys->minangle;
+}
+
+static void p_abf_free_system(PAbfSystem *sys)
+{
+ MEM_freeN(sys->alpha);
+ MEM_freeN(sys->beta);
+ MEM_freeN(sys->sine);
+ MEM_freeN(sys->cosine);
+ MEM_freeN(sys->weight);
+ MEM_freeN(sys->bAlpha);
+ MEM_freeN(sys->bTriangle);
+ MEM_freeN(sys->bInterior);
+ MEM_freeN(sys->lambdaTriangle);
+ MEM_freeN(sys->lambdaPlanar);
+ MEM_freeN(sys->lambdaLength);
+ MEM_freeN(sys->J2dt);
+ MEM_freeN(sys->bstar);
+ MEM_freeN(sys->dstar);
+}
+
+static void p_abf_compute_sines(PAbfSystem *sys)
+{
+ int i;
+ float *sine = sys->sine, *cosine = sys->cosine, *alpha = sys->alpha;
+
+ for (i = 0; i < sys->nangles; i++, sine++, cosine++, alpha++) {
+ *sine = sin(*alpha);
+ *cosine = cos(*alpha);
+ }
+}
+
+static float p_abf_compute_sin_product(PAbfSystem *sys, PVert *v, int aid)
+{
+ PEdge *e, *e1, *e2;
+ float sin1, sin2;
+
+ sin1 = sin2 = 1.0;
+
+ e = v->edge;
+ do {
+ e1 = e->next;
+ e2 = e->next->next;
+
+ if (aid == e1->u.id) {
+ /* we are computing a derivative for this angle,
+ so we use cos and drop the other part */
+ sin1 *= sys->cosine[e1->u.id];
+ sin2 = 0.0;
+ }
+ else
+ sin1 *= sys->sine[e1->u.id];
+
+ if (aid == e2->u.id) {
+ /* see above */
+ sin1 = 0.0;
+ sin2 *= sys->cosine[e2->u.id];
+ }
+ else
+ sin2 *= sys->sine[e2->u.id];
+
+ e = e->next->next->pair;
+ } while (e && (e != v->edge));
+
+ return (sin1 - sin2);
+}
+
+static float p_abf_compute_grad_alpha(PAbfSystem *sys, PFace *f, PEdge *e)
+{
+ PVert *v = e->vert, *v1 = e->next->vert, *v2 = e->next->next->vert;
+ float deriv;
+
+ deriv = (sys->alpha[e->u.id] - sys->beta[e->u.id])*sys->weight[e->u.id];
+ deriv += sys->lambdaTriangle[f->u.id];
+
+ if (v->flag & PVERT_INTERIOR) {
+ deriv += sys->lambdaPlanar[v->u.id];
+ }
+
+ if (v1->flag & PVERT_INTERIOR) {
+ float product = p_abf_compute_sin_product(sys, v1, e->u.id);
+ deriv += sys->lambdaLength[v1->u.id]*product;
+ }
+
+ if (v2->flag & PVERT_INTERIOR) {
+ float product = p_abf_compute_sin_product(sys, v2, e->u.id);
+ deriv += sys->lambdaLength[v2->u.id]*product;
+ }
+
+ return deriv;
+}
+
+static float p_abf_compute_gradient(PAbfSystem *sys, PChart *chart)
+{
+ PFace *f;
+ PEdge *e;
+ PVert *v;
+ float norm = 0.0;
+
+ for (f=chart->faces; f; f=f->nextlink) {
+ PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
+ float gtriangle, galpha1, galpha2, galpha3;
+
+ galpha1 = p_abf_compute_grad_alpha(sys, f, e1);
+ galpha2 = p_abf_compute_grad_alpha(sys, f, e2);
+ galpha3 = p_abf_compute_grad_alpha(sys, f, e3);
+
+ sys->bAlpha[e1->u.id] = -galpha1;
+ sys->bAlpha[e2->u.id] = -galpha2;
+ sys->bAlpha[e3->u.id] = -galpha3;
+
+ norm += galpha1*galpha1 + galpha2*galpha2 + galpha3*galpha3;
+
+ gtriangle = sys->alpha[e1->u.id] + sys->alpha[e2->u.id] + sys->alpha[e3->u.id] - M_PI;
+ sys->bTriangle[f->u.id] = -gtriangle;
+ norm += gtriangle*gtriangle;
+ }
+
+ for (v=chart->verts; v; v=v->nextlink) {
+ if (v->flag & PVERT_INTERIOR) {
+ float gplanar = -2*M_PI, glength;
+
+ e = v->edge;
+ do {
+ gplanar += sys->alpha[e->u.id];
+ e = e->next->next->pair;
+ } while (e && (e != v->edge));
+
+ sys->bInterior[v->u.id] = -gplanar;
+ norm += gplanar*gplanar;
+
+ glength = p_abf_compute_sin_product(sys, v, -1);
+ sys->bInterior[sys->ninterior + v->u.id] = -glength;
+ norm += glength*glength;
+ }
+ }
+
+ return norm;
+}
+
+static PBool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart)
+{
+ PFace *f;
+ PEdge *e;
+ int i, j, ninterior = sys->ninterior, nvar = 2*sys->ninterior;
+ PBool success;
+
+ nlNewContext();
+ nlSolverParameteri(NL_NB_VARIABLES, nvar);
+
+ nlBegin(NL_SYSTEM);
+
+ nlBegin(NL_MATRIX);
+
+ for (i = 0; i < nvar; i++)
+ nlRightHandSideAdd(0, i, sys->bInterior[i]);
+
+ for (f=chart->faces; f; f=f->nextlink) {
+ float wi1, wi2, wi3, b, si, beta[3], j2[3][3], W[3][3];
+ float row1[6], row2[6], row3[6];
+ int vid[6];
+ PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
+ PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
+
+ wi1 = 1.0/sys->weight[e1->u.id];
+ wi2 = 1.0/sys->weight[e2->u.id];
+ wi3 = 1.0/sys->weight[e3->u.id];
+
+ /* bstar1 = (J1*dInv*bAlpha - bTriangle) */
+ b = sys->bAlpha[e1->u.id]*wi1;
+ b += sys->bAlpha[e2->u.id]*wi2;
+ b += sys->bAlpha[e3->u.id]*wi3;
+ b -= sys->bTriangle[f->u.id];
+
+ /* si = J1*d*J1t */
+ si = 1.0/(wi1 + wi2 + wi3);
+
+ /* J1t*si*bstar1 - bAlpha */
+ beta[0] = b*si - sys->bAlpha[e1->u.id];
+ beta[1] = b*si - sys->bAlpha[e2->u.id];
+ beta[2] = b*si - sys->bAlpha[e3->u.id];
+
+ /* use this later for computing other lambda's */
+ sys->bstar[f->u.id] = b;
+ sys->dstar[f->u.id] = si;
+
+ /* set matrix */
+ W[0][0] = si - sys->weight[e1->u.id]; W[0][1] = si; W[0][2] = si;
+ W[1][0] = si; W[1][1] = si - sys->weight[e2->u.id]; W[1][2] = si;
+ W[2][0] = si; W[2][1] = si; W[2][2] = si - sys->weight[e3->u.id];
+
+ vid[0] = vid[1] = vid[2] = vid[3] = vid[4] = vid[5] = -1;
+
+ if (v1->flag & PVERT_INTERIOR) {
+ vid[0] = v1->u.id;
+ vid[3] = ninterior + v1->u.id;
+
+ sys->J2dt[e1->u.id][0] = j2[0][0] = 1.0*wi1;
+ sys->J2dt[e2->u.id][0] = j2[1][0] = p_abf_compute_sin_product(sys, v1, e2->u.id)*wi2;
+ sys->J2dt[e3->u.id][0] = j2[2][0] = p_abf_compute_sin_product(sys, v1, e3->u.id)*wi3;
+
+ nlRightHandSideAdd(0, v1->u.id, j2[0][0]*beta[0]);
+ nlRightHandSideAdd(0, ninterior + v1->u.id, j2[1][0]*beta[1] + j2[2][0]*beta[2]);
+
+ row1[0] = j2[0][0]*W[0][0];
+ row2[0] = j2[0][0]*W[1][0];
+ row3[0] = j2[0][0]*W[2][0];
+
+ row1[3] = j2[1][0]*W[0][1] + j2[2][0]*W[0][2];
+ row2[3] = j2[1][0]*W[1][1] + j2[2][0]*W[1][2];
+ row3[3] = j2[1][0]*W[2][1] + j2[2][0]*W[2][2];
+ }
+
+ if (v2->flag & PVERT_INTERIOR) {
+ vid[1] = v2->u.id;
+ vid[4] = ninterior + v2->u.id;
+
+ sys->J2dt[e1->u.id][1] = j2[0][1] = p_abf_compute_sin_product(sys, v2, e1->u.id)*wi1;
+ sys->J2dt[e2->u.id][1] = j2[1][1] = 1.0*wi2;
+ sys->J2dt[e3->u.id][1] = j2[2][1] = p_abf_compute_sin_product(sys, v2, e3->u.id)*wi3;
+
+ nlRightHandSideAdd(0, v2->u.id, j2[1][1]*beta[1]);
+ nlRightHandSideAdd(0, ninterior + v2->u.id, j2[0][1]*beta[0] + j2[2][1]*beta[2]);
+
+ row1[1] = j2[1][1]*W[0][1];
+ row2[1] = j2[1][1]*W[1][1];
+ row3[1] = j2[1][1]*W[2][1];
+
+ row1[4] = j2[0][1]*W[0][0] + j2[2][1]*W[0][2];
+ row2[4] = j2[0][1]*W[1][0] + j2[2][1]*W[1][2];
+ row3[4] = j2[0][1]*W[2][0] + j2[2][1]*W[2][2];
+ }
+
+ if (v3->flag & PVERT_INTERIOR) {
+ vid[2] = v3->u.id;
+ vid[5] = ninterior + v3->u.id;
+
+ sys->J2dt[e1->u.id][2] = j2[0][2] = p_abf_compute_sin_product(sys, v3, e1->u.id)*wi1;
+ sys->J2dt[e2->u.id][2] = j2[1][2] = p_abf_compute_sin_product(sys, v3, e2->u.id)*wi2;
+ sys->J2dt[e3->u.id][2] = j2[2][2] = 1.0*wi3;
+
+ nlRightHandSideAdd(0, v3->u.id, j2[2][2]*beta[2]);
+ nlRightHandSideAdd(0, ninterior + v3->u.id, j2[0][2]*beta[0] + j2[1][2]*beta[1]);
+
+ row1[2] = j2[2][2]*W[0][2];
+ row2[2] = j2[2][2]*W[1][2];
+ row3[2] = j2[2][2]*W[2][2];
+
+ row1[5] = j2[0][2]*W[0][0] + j2[1][2]*W[0][1];
+ row2[5] = j2[0][2]*W[1][0] + j2[1][2]*W[1][1];
+ row3[5] = j2[0][2]*W[2][0] + j2[1][2]*W[2][1];
+ }
+
+ for (i = 0; i < 3; i++) {
+ int r = vid[i];
+
+ if (r == -1)
+ continue;
+
+ for (j = 0; j < 6; j++) {
+ int c = vid[j];
+
+ if (c == -1)
+ continue;
+
+ if (i == 0)
+ nlMatrixAdd(r, c, j2[0][i]*row1[j]);
+ else
+ nlMatrixAdd(r + ninterior, c, j2[0][i]*row1[j]);
+
+ if (i == 1)
+ nlMatrixAdd(r, c, j2[1][i]*row2[j]);
+ else
+ nlMatrixAdd(r + ninterior, c, j2[1][i]*row2[j]);
+
+
+ if (i == 2)
+ nlMatrixAdd(r, c, j2[2][i]*row3[j]);
+ else
+ nlMatrixAdd(r + ninterior, c, j2[2][i]*row3[j]);
+ }
+ }
+ }
+
+ nlEnd(NL_MATRIX);
+
+ nlEnd(NL_SYSTEM);
+
+ success = nlSolve();
+
+ if (success) {
+ for (f=chart->faces; f; f=f->nextlink) {
+ float dlambda1, pre[3], dalpha;
+ PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
+ PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
+
+ pre[0] = pre[1] = pre[2] = 0.0;
+
+ if (v1->flag & PVERT_INTERIOR) {
+ float x = nlGetVariable(0, v1->u.id);
+ float x2 = nlGetVariable(0, ninterior + v1->u.id);
+ pre[0] += sys->J2dt[e1->u.id][0]*x;
+ pre[1] += sys->J2dt[e2->u.id][0]*x2;
+ pre[2] += sys->J2dt[e3->u.id][0]*x2;
+ }
+
+ if (v2->flag & PVERT_INTERIOR) {
+ float x = nlGetVariable(0, v2->u.id);
+ float x2 = nlGetVariable(0, ninterior + v2->u.id);
+ pre[0] += sys->J2dt[e1->u.id][1]*x2;
+ pre[1] += sys->J2dt[e2->u.id][1]*x;
+ pre[2] += sys->J2dt[e3->u.id][1]*x2;
+ }
+
+ if (v3->flag & PVERT_INTERIOR) {
+ float x = nlGetVariable(0, v3->u.id);
+ float x2 = nlGetVariable(0, ninterior + v3->u.id);
+ pre[0] += sys->J2dt[e1->u.id][2]*x2;
+ pre[1] += sys->J2dt[e2->u.id][2]*x2;
+ pre[2] += sys->J2dt[e3->u.id][2]*x;
+ }
+
+ dlambda1 = pre[0] + pre[1] + pre[2];
+ dlambda1 = sys->dstar[f->u.id]*(sys->bstar[f->u.id] - dlambda1);
+
+ sys->lambdaTriangle[f->u.id] += dlambda1;
+
+ dalpha = (sys->bAlpha[e1->u.id] - dlambda1);
+ sys->alpha[e1->u.id] += dalpha/sys->weight[e1->u.id] - pre[0];
+
+ dalpha = (sys->bAlpha[e2->u.id] - dlambda1);
+ sys->alpha[e2->u.id] += dalpha/sys->weight[e2->u.id] - pre[1];
+
+ dalpha = (sys->bAlpha[e3->u.id] - dlambda1);
+ sys->alpha[e3->u.id] += dalpha/sys->weight[e3->u.id] - pre[2];
+
+ /* clamp */
+ e = f->edge;
+ do {
+ if (sys->alpha[e->u.id] > M_PI)
+ sys->alpha[e->u.id] = M_PI;
+ else if (sys->alpha[e->u.id] < 0.0f)
+ sys->alpha[e->u.id] = 0.0f;
+ } while (e != f->edge);
+ }
+
+ for (i = 0; i < ninterior; i++) {
+ sys->lambdaPlanar[i] += nlGetVariable(0, i);
+ sys->lambdaLength[i] += nlGetVariable(0, ninterior + i);
+ }
+ }
+
+ nlDeleteContext(nlGetCurrent());
+
+ return success;
+}
+
+static PBool p_chart_abf_solve(PChart *chart)
+{
+ PVert *v;
+ PFace *f;
+ PEdge *e, *e1, *e2, *e3;
+ PAbfSystem sys;
+ int i;
+ float lastnorm, limit = (chart->nfaces > 100)? 1.0f: 0.001f;
+
+ /* setup id's */
+ sys.ninterior = sys.nfaces = sys.nangles = 0;
+
+ for (v=chart->verts; v; v=v->nextlink) {
+ if (p_vert_interior(v)) {
+ v->flag |= PVERT_INTERIOR;
+ v->u.id = sys.ninterior++;
+ }
+ else
+ v->flag &= ~PVERT_INTERIOR;
+ }
+
+ for (f=chart->faces; f; f=f->nextlink) {
+ e1 = f->edge; e2 = e1->next; e3 = e2->next;
+ f->u.id = sys.nfaces++;
+
+ /* angle id's are conveniently stored in half edges */
+ e1->u.id = sys.nangles++;
+ e2->u.id = sys.nangles++;
+ e3->u.id = sys.nangles++;
+ }
+
+ p_abf_setup_system(&sys);
+
+ /* compute initial angles */
+ for (f=chart->faces; f; f=f->nextlink) {
+ float a1, a2, a3;
+
+ e1 = f->edge; e2 = e1->next; e3 = e2->next;
+ p_face_angles(f, &a1, &a2, &a3);
+
+ if (a1 < sys.minangle)
+ a1 = sys.minangle;
+ else if (a1 > sys.maxangle)
+ a1 = sys.maxangle;
+ if (a2 < sys.minangle)
+ a2 = sys.minangle;
+ else if (a2 > sys.maxangle)
+ a2 = sys.maxangle;
+ if (a3 < sys.minangle)
+ a3 = sys.minangle;
+ else if (a3 > sys.maxangle)
+ a3 = sys.maxangle;
+
+ sys.alpha[e1->u.id] = sys.beta[e1->u.id] = a1;
+ sys.alpha[e2->u.id] = sys.beta[e2->u.id] = a2;
+ sys.alpha[e3->u.id] = sys.beta[e3->u.id] = a3;
+
+ sys.weight[e1->u.id] = 2.0/(a1*a1);
+ sys.weight[e2->u.id] = 2.0/(a2*a2);
+ sys.weight[e3->u.id] = 2.0/(a3*a3);
+ }
+
+ for (v=chart->verts; v; v=v->nextlink) {
+ if (v->flag & PVERT_INTERIOR) {
+ float anglesum = 0.0, scale;
+
+ e = v->edge;
+ do {
+ anglesum += sys.beta[e->u.id];
+ e = e->next->next->pair;
+ } while (e && (e != v->edge));
+
+ scale = (anglesum == 0.0f)? 0.0f: 2*M_PI/anglesum;
+
+ e = v->edge;
+ do {
+ sys.beta[e->u.id] = sys.alpha[e->u.id] = sys.beta[e->u.id]*scale;
+ e = e->next->next->pair;
+ } while (e && (e != v->edge));
+ }
+ }
+
+ if (sys.ninterior > 0) {
+ p_abf_compute_sines(&sys);
+
+ /* iteration */
+ lastnorm = 1e10;
+
+ for (i = 0; i < ABF_MAX_ITER; i++) {
+ float norm = p_abf_compute_gradient(&sys, chart);
+
+ lastnorm = norm;
+
+ if (norm < limit)
+ break;
+
+ if (!p_abf_matrix_invert(&sys, chart)) {
+ param_warning("ABF failed to invert matrix.");
+ p_abf_free_system(&sys);
+ return P_FALSE;
+ }
+
+ p_abf_compute_sines(&sys);
+ }
+
+ if (i == ABF_MAX_ITER) {
+ param_warning("ABF maximum iterations reached.");
+ p_abf_free_system(&sys);
+ return P_FALSE;
+ }
+ }
+
+ chart->u.lscm.abf_alpha = MEM_dupallocN(sys.alpha);
+ p_abf_free_system(&sys);
+
+ return P_TRUE;
+}
+
+/* Least Squares Conformal Maps */
+
+static void p_chart_pin_positions(PChart *chart, PVert **pin1, PVert **pin2)
+{
+ if (pin1 == pin2) {
+ /* degenerate case */
+ PFace *f = chart->faces;
+ *pin1 = f->edge->vert;
+ *pin2 = f->edge->next->vert;
+
+ (*pin1)->uv[0] = 0.0f;
+ (*pin1)->uv[1] = 0.5f;
+ (*pin2)->uv[0] = 1.0f;
+ (*pin2)->uv[1] = 0.5f;
+ }
+ else {
+ int diru, dirv, dirx, diry;
+ float sub[3];
+
+ VecSubf(sub, (*pin1)->co, (*pin2)->co);
+ sub[0] = fabs(sub[0]);
+ sub[1] = fabs(sub[1]);
+ sub[2] = fabs(sub[2]);
+
+ if ((sub[0] > sub[1]) && (sub[0] > sub[2])) {
+ dirx = 0;
+ diry = (sub[1] > sub[2])? 1: 2;
+ }
+ else if ((sub[1] > sub[0]) && (sub[1] > sub[2])) {
+ dirx = 1;
+ diry = (sub[0] > sub[2])? 0: 2;
+ }
+ else {
+ dirx = 2;
+ diry = (sub[0] > sub[1])? 0: 1;
+ }
+
+ if (dirx == 2) {
+ diru = 1;
+ dirv = 0;
+ }
+ else {
+ diru = 0;
+ dirv = 1;
+ }
+
+ (*pin1)->uv[diru] = (*pin1)->co[dirx];
+ (*pin1)->uv[dirv] = (*pin1)->co[diry];
+ (*pin2)->uv[diru] = (*pin2)->co[dirx];
+ (*pin2)->uv[dirv] = (*pin2)->co[diry];
+ }
+}
+
+static PBool p_chart_symmetry_pins(PChart *chart, PEdge *outer, PVert **pin1, PVert **pin2)
+{
+ PEdge *be, *lastbe = NULL, *maxe1 = NULL, *maxe2 = NULL, *be1, *be2;
+ PEdge *cure = NULL, *firste1 = NULL, *firste2 = NULL, *nextbe;
+ float maxlen = 0.0f, curlen = 0.0f, totlen = 0.0f, firstlen = 0.0f;
+ float len1, len2;
+
+ /* find longest series of verts split in the chart itself, these are
+ marked during construction */
+ be = outer;
+ lastbe = p_boundary_edge_prev(be);
+ do {
+ float len = p_edge_length(be);
+ totlen += len;
+
+ nextbe = p_boundary_edge_next(be);
+
+ if ((be->vert->flag & PVERT_SPLIT) ||
+ (lastbe->vert->flag & nextbe->vert->flag & PVERT_SPLIT)) {
+ if (!cure) {
+ if (be == outer)
+ firste1 = be;
+ cure = be;
+ }
+ else
+ curlen += p_edge_length(lastbe);
+ }
+ else if (cure) {
+ if (curlen > maxlen) {
+ maxlen = curlen;
+ maxe1 = cure;
+ maxe2 = lastbe;
+ }
+
+ if (firste1 == cure) {
+ firstlen = curlen;
+ firste2 = lastbe;
+ }
+
+ curlen = 0.0f;
+ cure = NULL;
+ }
+
+ lastbe = be;
+ be = nextbe;
+ } while(be != outer);
+
+ /* make sure we also count a series of splits over the starting point */
+ if (cure && (cure != outer)) {
+ firstlen += curlen + p_edge_length(be);
+
+ if (firstlen > maxlen) {
+ maxlen = firstlen;
+ maxe1 = cure;
+ maxe2 = firste2;
+ }
+ }
+
+ if (!maxe1 || !maxe2 || (maxlen < 0.5f*totlen))
+ return P_FALSE;
+
+ /* find pin1 in the split vertices */
+ be1 = maxe1;
+ be2 = maxe2;
+ len1 = 0.0f;
+ len2 = 0.0f;
+
+ do {
+ if (len1 < len2) {
+ len1 += p_edge_length(be1);
+ be1 = p_boundary_edge_next(be1);
+ }
+ else {
+ be2 = p_boundary_edge_prev(be2);
+ len2 += p_edge_length(be2);
+ }
+ } while (be1 != be2);
+
+ *pin1 = be1->vert;
+
+ /* find pin2 outside the split vertices */
+ be1 = maxe1;
+ be2 = maxe2;
+ len1 = 0.0f;
+ len2 = 0.0f;
+
+ do {
+ if (len1 < len2) {
+ be1 = p_boundary_edge_prev(be1);
+ len1 += p_edge_length(be1);
+ }
+ else {
+ len2 += p_edge_length(be2);
+ be2 = p_boundary_edge_next(be2);
+ }
+ } while (be1 != be2);
+
+ *pin2 = be1->vert;
+
+ p_chart_pin_positions(chart, pin1, pin2);
+
+ return P_TRUE;
+}
+
+static void p_chart_extrema_verts(PChart *chart, PVert **pin1, PVert **pin2)
+{
+ float minv[3], maxv[3], dirlen;
+ PVert *v, *minvert[3], *maxvert[3];
+ int i, dir;
+
+ /* find minimum and maximum verts over x/y/z axes */
+ minv[0] = minv[1] = minv[2] = 1e20;
+ maxv[0] = maxv[1] = maxv[2] = -1e20;
+
+ minvert[0] = minvert[1] = minvert[2] = NULL;
+ maxvert[0] = maxvert[1] = maxvert[2] = NULL;
+
+ for (v = chart->verts; v; v=v->nextlink) {
+ for (i = 0; i < 3; i++) {
+ if (v->co[i] < minv[i]) {
+ minv[i] = v->co[i];
+ minvert[i] = v;
+ }
+ if (v->co[i] > maxv[i]) {
+ maxv[i] = v->co[i];
+ maxvert[i] = v;
+ }
+ }
+ }
+
+ /* find axes with longest distance */
+ dir = 0;
+ dirlen = -1.0;
+
+ for (i = 0; i < 3; i++) {
+ if (maxv[i] - minv[i] > dirlen) {
+ dir = i;
+ dirlen = maxv[i] - minv[i];
+ }
+ }
+
+ *pin1 = minvert[dir];
+ *pin2 = maxvert[dir];
+
+ p_chart_pin_positions(chart, pin1, pin2);
+}
+
+static void p_chart_lscm_load_solution(PChart *chart)
+{
+ PVert *v;
+
+ for (v=chart->verts; v; v=v->nextlink) {
+ v->uv[0] = nlGetVariable(0, 2*v->u.id);
+ v->uv[1] = nlGetVariable(0, 2*v->u.id + 1);
+ }
+}
+
+static void p_chart_lscm_begin(PChart *chart, PBool live, PBool abf)
+{
+ PVert *v, *pin1, *pin2;
+ PBool select = P_FALSE, deselect = P_FALSE;
+ int npins = 0, id = 0;
+
+ /* give vertices matrix indices and count pins */
+ for (v=chart->verts; v; v=v->nextlink) {
+ if (v->flag & PVERT_PIN) {
+ npins++;
+ if (v->flag & PVERT_SELECT)
+ select = P_TRUE;
+ }
+
+ if (!(v->flag & PVERT_SELECT))
+ deselect = P_TRUE;
+ }
+
+ if ((live && (!select || !deselect)) || (npins == 1)) {
+ chart->u.lscm.context = NULL;
+ }
+ else {
+#if 0
+ p_chart_simplify_compute(chart);
+ p_chart_topological_sanity_check(chart);
+#endif
+
+ if (abf) {
+ if (!p_chart_abf_solve(chart))
+ param_warning("ABF solving failed: falling back to LSCM.\n");
+ }
+
+ if (npins <= 1) {
+ /* not enough pins, lets find some ourself */
+ PEdge *outer;
+
+ p_chart_boundaries(chart, NULL, &outer);
+
+ if (!p_chart_symmetry_pins(chart, outer, &pin1, &pin2))
+ p_chart_extrema_verts(chart, &pin1, &pin2);
+
+ chart->u.lscm.pin1 = pin1;
+ chart->u.lscm.pin2 = pin2;
+ }
+ else {
+ chart->flag |= PCHART_NOPACK;
+ }
+
+ for (v=chart->verts; v; v=v->nextlink)
+ v->u.id = id++;
+
+ nlNewContext();
+ nlSolverParameteri(NL_NB_VARIABLES, 2*chart->nverts);
+ nlSolverParameteri(NL_NB_ROWS, 2*chart->nfaces);
+ nlSolverParameteri(NL_LEAST_SQUARES, NL_TRUE);
+
+ chart->u.lscm.context = nlGetCurrent();
+ }
+}
+
+static PBool p_chart_lscm_solve(PChart *chart)
+{
+ PVert *v, *pin1 = chart->u.lscm.pin1, *pin2 = chart->u.lscm.pin2;
+ PFace *f;
+ float *alpha = chart->u.lscm.abf_alpha;
+ int row;
+
+ nlMakeCurrent(chart->u.lscm.context);
+
+ nlBegin(NL_SYSTEM);
+
+#if 0
+ /* TODO: make loading pins work for simplify/complexify. */
+#endif
+
+ for (v=chart->verts; v; v=v->nextlink)
+ if (v->flag & PVERT_PIN)
+ p_vert_load_pin_select_uvs(v); /* reload for live */
+
+ if (chart->u.lscm.pin1) {
+ nlLockVariable(2*pin1->u.id);
+ nlLockVariable(2*pin1->u.id + 1);
+ nlLockVariable(2*pin2->u.id);
+ nlLockVariable(2*pin2->u.id + 1);
+
+ nlSetVariable(0, 2*pin1->u.id, pin1->uv[0]);
+ nlSetVariable(0, 2*pin1->u.id + 1, pin1->uv[1]);
+ nlSetVariable(0, 2*pin2->u.id, pin2->uv[0]);
+ nlSetVariable(0, 2*pin2->u.id + 1, pin2->uv[1]);
+ }
+ else {
+ /* set and lock the pins */
+ for (v=chart->verts; v; v=v->nextlink) {
+ if (v->flag & PVERT_PIN) {
+ nlLockVariable(2*v->u.id);
+ nlLockVariable(2*v->u.id + 1);
+
+ nlSetVariable(0, 2*v->u.id, v->uv[0]);
+ nlSetVariable(0, 2*v->u.id + 1, v->uv[1]);
+ }
+ }
+ }
+
+ /* construct matrix */
+
+ nlBegin(NL_MATRIX);
+
+ row = 0;
+ for (f=chart->faces; f; f=f->nextlink) {
+ PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
+ PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
+ float a1, a2, a3, ratio, cosine, sine;
+ float sina1, sina2, sina3, sinmax;
+
+ if (alpha) {
+ /* use abf angles if passed on */
+ a1 = *(alpha++);
+ a2 = *(alpha++);
+ a3 = *(alpha++);
+ }
+ else
+ p_face_angles(f, &a1, &a2, &a3);
+
+ sina1 = sin(a1);
+ sina2 = sin(a2);
+ sina3 = sin(a3);
+
+ sinmax = MAX3(sina1, sina2, sina3);
+
+ /* shift vertices to find most stable order */
+ #define SHIFT3(type, a, b, c) \
+ { type tmp; tmp = a; a = c; c = b; b = tmp; }
+
+ if (sina3 != sinmax) {
+ SHIFT3(PVert*, v1, v2, v3);
+ SHIFT3(float, a1, a2, a3);
+ SHIFT3(float, sina1, sina2, sina3);
+
+ if (sina2 == sinmax) {
+ SHIFT3(PVert*, v1, v2, v3);
+ SHIFT3(float, a1, a2, a3);
+ SHIFT3(float, sina1, sina2, sina3);
+ }
+ }
+
+ /* angle based lscm formulation */
+ ratio = (sina3 == 0.0f)? 1.0f: sina2/sina3;
+ cosine = cos(a1)*ratio;
+ sine = sina1*ratio;
+
+#if 0
+ nlBegin(NL_ROW);
+ nlCoefficient(2*v1->u.id, cosine - 1.0);
+ nlCoefficient(2*v1->u.id+1, -sine);
+ nlCoefficient(2*v2->u.id, -cosine);
+ nlCoefficient(2*v2->u.id+1, sine);
+ nlCoefficient(2*v3->u.id, 1.0);
+ nlEnd(NL_ROW);
+
+ nlBegin(NL_ROW);
+ nlCoefficient(2*v1->u.id, sine);
+ nlCoefficient(2*v1->u.id+1, cosine - 1.0);
+ nlCoefficient(2*v2->u.id, -sine);
+ nlCoefficient(2*v2->u.id+1, -cosine);
+ nlCoefficient(2*v3->u.id+1, 1.0);
+ nlEnd(NL_ROW);
+#else
+ nlMatrixAdd(row, 2*v1->u.id, cosine - 1.0);
+ nlMatrixAdd(row, 2*v1->u.id+1, -sine);
+ nlMatrixAdd(row, 2*v2->u.id, -cosine);
+ nlMatrixAdd(row, 2*v2->u.id+1, sine);
+ nlMatrixAdd(row, 2*v3->u.id, 1.0);
+ row++;
+
+ nlMatrixAdd(row, 2*v1->u.id, sine);
+ nlMatrixAdd(row, 2*v1->u.id+1, cosine - 1.0);
+ nlMatrixAdd(row, 2*v2->u.id, -sine);
+ nlMatrixAdd(row, 2*v2->u.id+1, -cosine);
+ nlMatrixAdd(row, 2*v3->u.id+1, 1.0);
+ row++;
+#endif
+ }
+
+ nlEnd(NL_MATRIX);
+
+ nlEnd(NL_SYSTEM);
+
+ if (nlSolveAdvanced(NULL, NL_TRUE)) {
+ p_chart_lscm_load_solution(chart);
+ return P_TRUE;
+ }
+ else {
+ for (v=chart->verts; v; v=v->nextlink) {
+ v->uv[0] = 0.0f;
+ v->uv[1] = 0.0f;
+ }
+ }
+
+ return P_FALSE;
+}
+
+static void p_chart_lscm_end(PChart *chart)
+{
+ if (chart->u.lscm.context)
+ nlDeleteContext(chart->u.lscm.context);
+
+ if (chart->u.lscm.abf_alpha) {
+ MEM_freeN(chart->u.lscm.abf_alpha);
+ chart->u.lscm.abf_alpha = NULL;
+ }
+
+ chart->u.lscm.context = NULL;
+ chart->u.lscm.pin1 = NULL;
+ chart->u.lscm.pin2 = NULL;
+}
+
+/* Stretch */
+
+#define P_STRETCH_ITER 20
+
+static void p_stretch_pin_boundary(PChart *chart)
+{
+ PVert *v;
+
+ for(v=chart->verts; v; v=v->nextlink)
+ if (v->edge->pair == NULL)
+ v->flag |= PVERT_PIN;
+ else
+ v->flag &= ~PVERT_PIN;
+}
+
+static float p_face_stretch(PFace *f)
+{
+ float T, w, tmp[3];
+ float Ps[3], Pt[3];
+ float a, c, area;
+ PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
+ PVert *v1 = e1->vert, *v2 = e2->vert, *v3 = e3->vert;
+
+ area = p_face_uv_area_signed(f);
+
+ if (area <= 0.0f) /* flipped face -> infinite stretch */
+ return 1e10f;
+
+ w= 1.0f/(2.0f*area);
+
+ /* compute derivatives */
+ VecCopyf(Ps, v1->co);
+ VecMulf(Ps, (v2->uv[1] - v3->uv[1]));
+
+ VecCopyf(tmp, v2->co);
+ VecMulf(tmp, (v3->uv[1] - v1->uv[1]));
+ VecAddf(Ps, Ps, tmp);
+
+ VecCopyf(tmp, v3->co);
+ VecMulf(tmp, (v1->uv[1] - v2->uv[1]));
+ VecAddf(Ps, Ps, tmp);
+
+ VecMulf(Ps, w);
+
+ VecCopyf(Pt, v1->co);
+ VecMulf(Pt, (v3->uv[0] - v2->uv[0]));
+
+ VecCopyf(tmp, v2->co);
+ VecMulf(tmp, (v1->uv[0] - v3->uv[0]));
+ VecAddf(Pt, Pt, tmp);
+
+ VecCopyf(tmp, v3->co);
+ VecMulf(tmp, (v2->uv[0] - v1->uv[0]));
+ VecAddf(Pt, Pt, tmp);
+
+ VecMulf(Pt, w);
+
+ /* Sander Tensor */
+ a= Inpf(Ps, Ps);
+ c= Inpf(Pt, Pt);
+
+ T = sqrt(0.5f*(a + c));
+ if (f->flag & PFACE_FILLED)
+ T *= 0.2;
+
+ return T;
+}
+
+static float p_stretch_compute_vertex(PVert *v)
+{
+ PEdge *e = v->edge;
+ float sum = 0.0f;
+
+ do {
+ sum += p_face_stretch(e->face);
+ e = p_wheel_edge_next(e);
+ } while (e && e != (v->edge));
+
+ return sum;
+}
+
+static void p_chart_stretch_minimize(PChart *chart, RNG *rng)
+{
+ PVert *v;
+ PEdge *e;
+ int j, nedges;
+ float orig_stretch, low, stretch_low, high, stretch_high, mid, stretch;
+ float orig_uv[2], dir[2], random_angle, trusted_radius;
+
+ for(v=chart->verts; v; v=v->nextlink) {
+ if((v->flag & PVERT_PIN) || !(v->flag & PVERT_SELECT))
+ continue;
+
+ orig_stretch = p_stretch_compute_vertex(v);
+ orig_uv[0] = v->uv[0];
+ orig_uv[1] = v->uv[1];
+
+ /* move vertex in a random direction */
+ trusted_radius = 0.0f;
+ nedges = 0;
+ e = v->edge;
+
+ do {
+ trusted_radius += p_edge_uv_length(e);
+ nedges++;
+
+ e = p_wheel_edge_next(e);
+ } while (e && e != (v->edge));
+
+ trusted_radius /= 2 * nedges;
+
+ random_angle = rng_getFloat(rng) * 2.0 * M_PI;
+ dir[0] = trusted_radius * cos(random_angle);
+ dir[1] = trusted_radius * sin(random_angle);
+
+ /* calculate old and new stretch */
+ low = 0;
+ stretch_low = orig_stretch;
+
+ Vec2Addf(v->uv, orig_uv, dir);
+ high = 1;
+ stretch = stretch_high = p_stretch_compute_vertex(v);
+
+ /* binary search for lowest stretch position */
+ for (j = 0; j < P_STRETCH_ITER; j++) {
+ mid = 0.5 * (low + high);
+ v->uv[0]= orig_uv[0] + mid*dir[0];
+ v->uv[1]= orig_uv[1] + mid*dir[1];
+ stretch = p_stretch_compute_vertex(v);
+
+ if (stretch_low < stretch_high) {
+ high = mid;
+ stretch_high = stretch;
+ }
+ else {
+ low = mid;
+ stretch_low = stretch;
+ }
+ }
+
+ /* no luck, stretch has increased, reset to old values */
+ if(stretch >= orig_stretch)
+ Vec2Copyf(v->uv, orig_uv);
+ }
+}
+
+/* Minimum area enclosing rectangle for packing */
+
+static int p_compare_geometric_uv(const void *a, const void *b)
+{
+ PVert *v1 = *(PVert**)a;
+ PVert *v2 = *(PVert**)b;
+
+ if (v1->uv[0] < v2->uv[0])
+ return -1;
+ else if (v1->uv[0] == v2->uv[0]) {
+ if (v1->uv[1] < v2->uv[1])
+ return -1;
+ else if (v1->uv[1] == v2->uv[1])
+ return 0;
+ else
+ return 1;
+ }
+ else
+ return 1;
+}
+
+static PBool p_chart_convex_hull(PChart *chart, PVert ***verts, int *nverts, int *right)
+{
+ /* Graham algorithm, taken from:
+ * http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/117225 */
+
+ PEdge *be, *e;
+ int npoints = 0, i, ulen, llen;
+ PVert **U, **L, **points, **p;
+
+ p_chart_boundaries(chart, NULL, &be);
+
+ if (!be)
+ return P_FALSE;
+
+ e = be;
+ do {
+ npoints++;
+ e = p_boundary_edge_next(e);
+ } while(e != be);
+
+ p = points = (PVert**)MEM_mallocN(sizeof(PVert*)*npoints*2, "PCHullpoints");
+ U = (PVert**)MEM_mallocN(sizeof(PVert*)*npoints, "PCHullU");
+ L = (PVert**)MEM_mallocN(sizeof(PVert*)*npoints, "PCHullL");
+
+ e = be;
+ do {
+ *p = e->vert;
+ p++;
+ e = p_boundary_edge_next(e);
+ } while(e != be);
+
+ qsort(points, npoints, sizeof(PVert*), p_compare_geometric_uv);
+
+ ulen = llen = 0;
+ for (p=points, i = 0; i < npoints; i++, p++) {
+ while ((ulen > 1) && (p_area_signed(U[ulen-2]->uv, (*p)->uv, U[ulen-1]->uv) <= 0))
+ ulen--;
+ while ((llen > 1) && (p_area_signed(L[llen-2]->uv, (*p)->uv, L[llen-1]->uv) >= 0))
+ llen--;
+
+ U[ulen] = *p;
+ ulen++;
+ L[llen] = *p;
+ llen++;
+ }
+
+ npoints = 0;
+ for (p=points, i = 0; i < ulen; i++, p++, npoints++)
+ *p = U[i];
+
+ /* the first and last point in L are left out, since they are also in U */
+ for (i = llen-2; i > 0; i--, p++, npoints++)
+ *p = L[i];
+
+ *verts = points;
+ *nverts = npoints;
+ *right = ulen - 1;
+
+ MEM_freeN(U);
+ MEM_freeN(L);
+
+ return P_TRUE;
+}
+
+float p_rectangle_area(float *p1, float *dir, float *p2, float *p3, float *p4)
+{
+ /* given 4 points on the rectangle edges and the direction of on edge,
+ compute the area of the rectangle */
+
+ float orthodir[2], corner1[2], corner2[2], corner3[2];
+
+ orthodir[0] = dir[1];
+ orthodir[1] = -dir[0];
+
+ if (!p_intersect_line_2d_dir(p1, dir, p2, orthodir, corner1))
+ return 1e10;
+
+ if (!p_intersect_line_2d_dir(p1, dir, p4, orthodir, corner2))
+ return 1e10;
+
+ if (!p_intersect_line_2d_dir(p3, dir, p4, orthodir, corner3))
+ return 1e10;
+
+ return Vec2Lenf(corner1, corner2)*Vec2Lenf(corner2, corner3);
+}
+
+static float p_chart_minimum_area_angle(PChart *chart)
+{
+ /* minimum area enclosing rectangle with rotating calipers, info:
+ * http://cgm.cs.mcgill.ca/~orm/maer.html */
+
+ float rotated, minarea, minangle, area, len;
+ float *angles, miny, maxy, v[2], a[4], mina;
+ int npoints, right, mini, maxi, i, idx[4], nextidx;
+ PVert **points, *p1, *p2, *p3, *p4, *p1n;
+
+ /* compute convex hull */
+ if (!p_chart_convex_hull(chart, &points, &npoints, &right))
+ return 0.0;
+
+ /* find left/top/right/bottom points, and compute angle for each point */
+ angles = MEM_mallocN(sizeof(float)*npoints, "PMinAreaAngles");
+
+ mini = maxi = 0;
+ miny = 1e10;
+ maxy = -1e10;
+
+ for (i = 0; i < npoints; i++) {
+ p1 = (i == 0)? points[npoints-1]: points[i-1];
+ p2 = points[i];
+ p3 = (i == npoints-1)? points[0]: points[i+1];
+
+ angles[i] = M_PI - p_vec2_angle(p1->uv, p2->uv, p3->uv);
+
+ if (points[i]->uv[1] < miny) {
+ miny = points[i]->uv[1];
+ mini = i;
+ }
+ if (points[i]->uv[1] > maxy) {
+ maxy = points[i]->uv[1];
+ maxi = i;
+ }
+ }
+
+ /* left, top, right, bottom */
+ idx[0] = 0;
+ idx[1] = maxi;
+ idx[2] = right;
+ idx[3] = mini;
+
+ v[0] = points[idx[0]]->uv[0];
+ v[1] = points[idx[0]]->uv[1] + 1.0f;
+ a[0] = p_vec2_angle(points[(idx[0]+1)%npoints]->uv, points[idx[0]]->uv, v);
+
+ v[0] = points[idx[1]]->uv[0] + 1.0f;
+ v[1] = points[idx[1]]->uv[1];
+ a[1] = p_vec2_angle(points[(idx[1]+1)%npoints]->uv, points[idx[1]]->uv, v);
+
+ v[0] = points[idx[2]]->uv[0];
+ v[1] = points[idx[2]]->uv[1] - 1.0f;
+ a[2] = p_vec2_angle(points[(idx[2]+1)%npoints]->uv, points[idx[2]]->uv, v);
+
+ v[0] = points[idx[3]]->uv[0] - 1.0f;
+ v[1] = points[idx[3]]->uv[1];
+ a[3] = p_vec2_angle(points[(idx[3]+1)%npoints]->uv, points[idx[3]]->uv, v);
+
+ /* 4 rotating calipers */
+
+ rotated = 0.0;
+ minarea = 1e10;
+ minangle = 0.0;
+
+ while (rotated <= M_PI/2) { /* INVESTIGATE: how far to rotate? */
+ /* rotate with the smallest angle */
+ mini = 0;
+ mina = 1e10;
+
+ for (i = 0; i < 4; i++)
+ if (a[i] < mina) {
+ mina = a[i];
+ mini = i;
+ }
+
+ rotated += mina;
+ nextidx = (idx[mini]+1)%npoints;
+
+ a[mini] = angles[nextidx];
+ a[(mini+1)%4] = a[(mini+1)%4] - mina;
+ a[(mini+2)%4] = a[(mini+2)%4] - mina;
+ a[(mini+3)%4] = a[(mini+3)%4] - mina;
+
+ /* compute area */
+ p1 = points[idx[mini]];
+ p1n = points[nextidx];
+ p2 = points[idx[(mini+1)%4]];
+ p3 = points[idx[(mini+2)%4]];
+ p4 = points[idx[(mini+3)%4]];
+
+ len = Vec2Lenf(p1->uv, p1n->uv);
+
+ if (len > 0.0f) {
+ len = 1.0/len;
+ v[0] = (p1n->uv[0] - p1->uv[0])*len;
+ v[1] = (p1n->uv[1] - p1->uv[1])*len;
+
+ area = p_rectangle_area(p1->uv, v, p2->uv, p3->uv, p4->uv);
+
+ /* remember smallest area */
+ if (area < minarea) {
+ minarea = area;
+ minangle = rotated;
+ }
+ }
+
+ idx[mini] = nextidx;
+ }
+
+ /* try keeping rotation as small as possible */
+ if (minangle > M_PI/4)
+ minangle -= M_PI/2;
+
+ MEM_freeN(angles);
+ MEM_freeN(points);
+
+ return minangle;
+}
+
+void p_chart_rotate_minimum_area(PChart *chart)
+{
+ float angle = p_chart_minimum_area_angle(chart);
+ float sine = sin(angle);
+ float cosine = cos(angle);
+ PVert *v;
+
+ for (v = chart->verts; v; v=v->nextlink) {
+ float oldu = v->uv[0], oldv = v->uv[1];
+ v->uv[0] = cosine*oldu - sine*oldv;
+ v->uv[1] = sine*oldu + cosine*oldv;
+ }
+}
+
+/* Area Smoothing */
+
+/* 2d bsp tree for inverse mapping - that's a bit silly */
+
+typedef struct SmoothTriangle {
+ float co1[2], co2[2], co3[2];
+ float oco1[2], oco2[2], oco3[2];
+} SmoothTriangle;
+
+typedef struct SmoothNode {
+ struct SmoothNode *c1, *c2;
+ SmoothTriangle **tri;
+ float split;
+ int axis, ntri;
+} SmoothNode;
+
+static void p_barycentric_2d(float *v1, float *v2, float *v3, float *p, float *b)
+{
+ float a[2], c[2], h[2], div;
+
+ a[0] = v2[0] - v1[0];
+ a[1] = v2[1] - v1[1];
+ c[0] = v3[0] - v1[0];
+ c[1] = v3[1] - v1[1];
+
+ div = a[0]*c[1] - a[1]*c[0];
+
+ if (div == 0.0f) {
+ b[0] = 1.0f/3.0f;
+ b[1] = 1.0f/3.0f;
+ b[2] = 1.0f/3.0f;
+ }
+ else {
+ h[0] = p[0] - v1[0];
+ h[1] = p[1] - v1[1];
+
+ div = 1.0f/div;
+
+ b[1] = (h[0]*c[1] - h[1]*c[0])*div;
+ b[2] = (a[0]*h[1] - a[1]*h[0])*div;
+ b[0] = 1.0 - b[1] - b[2];
+ }
+}
+
+static PBool p_triangle_inside(SmoothTriangle *t, float *co)
+{
+ float b[3];
+
+ p_barycentric_2d(t->co1, t->co2, t->co3, co, b);
+
+ if ((b[0] >= 0.0) && (b[1] >= 0.0) && (b[2] >= 0.0f)) {
+ co[0] = t->oco1[0]*b[0] + t->oco2[0]*b[1] + t->oco3[0]*b[2];
+ co[1] = t->oco1[1]*b[0] + t->oco2[1]*b[1] + t->oco3[1]*b[2];
+ return P_TRUE;
+ }
+
+ return P_FALSE;
+}
+
+static SmoothNode *p_node_new(MemArena *arena, SmoothTriangle **tri, int ntri, float *bmin, float *bmax, int depth)
+{
+ SmoothNode *node = BLI_memarena_alloc(arena, sizeof *node);
+ int axis, i, t1size = 0, t2size = 0;
+ float split, mi, mx;
+ SmoothTriangle **t1, **t2, *t;
+
+ node->tri = tri;
+ node->ntri = ntri;
+
+ if (ntri <= 10 || depth >= 15)
+ return node;
+
+ t1 = MEM_mallocN(sizeof(SmoothTriangle)*ntri, "PNodeTri1");
+ t2 = MEM_mallocN(sizeof(SmoothTriangle)*ntri, "PNodeTri1");
+
+ axis = (bmax[0] - bmin[0] > bmax[1] - bmin[1])? 0: 1;
+ split = 0.5f*(bmin[axis] + bmax[axis]);
+
+ for (i = 0; i < ntri; i++) {
+ t = tri[i];
+
+ if ((t->co1[axis] <= split) || (t->co2[axis] <= split) || (t->co3[axis] <= split)) {
+ t1[t1size] = t;
+ t1size++;
+ }
+ if ((t->co1[axis] >= split) || (t->co2[axis] >= split) || (t->co3[axis] >= split)) {
+ t2[t2size] = t;
+ t2size++;
+ }
+ }
+
+ if ((t1size == t2size) && (t1size == ntri)) {
+ MEM_freeN(t1);
+ MEM_freeN(t2);
+ return node;
+ }
+
+ node->tri = NULL;
+ node->ntri = 0;
+ MEM_freeN(tri);
+
+ node->axis = axis;
+ node->split = split;
+
+ mi = bmin[axis];
+ mx = bmax[axis];
+ bmax[axis] = split;
+ node->c1 = p_node_new(arena, t1, t1size, bmin, bmax, depth+1);
+
+ bmin[axis] = bmax[axis];
+ bmax[axis] = mx;
+ node->c2 = p_node_new(arena, t2, t2size, bmin, bmax, depth+1);
+
+ return node;
+}
+
+static void p_node_delete(SmoothNode *node)
+{
+ if (node->c1)
+ p_node_delete(node->c1);
+ if (node->c2)
+ p_node_delete(node->c2);
+ if (node->tri)
+ MEM_freeN(node->tri);
+}
+
+static PBool p_node_intersect(SmoothNode *node, float *co)
+{
+ int i;
+
+ if (node->tri) {
+ for (i = 0; i < node->ntri; i++)
+ if (p_triangle_inside(node->tri[i], co))
+ return P_TRUE;
+
+ return P_FALSE;
+ }
+ else {
+ if (co[node->axis] < node->split)
+ return p_node_intersect(node->c1, co);
+ else
+ return p_node_intersect(node->c2, co);
+ }
+
+}
+
+/* smooothing */
+
+static int p_compare_float(const void *a, const void *b)
+{
+ if (*((float*)a) < *((float*)b))
+ return -1;
+ else if (*((float*)a) == *((float*)b))
+ return 0;
+ else
+ return 1;
+}
+
+static float p_smooth_median_edge_length(PChart *chart)
+{
+ PEdge *e;
+ float *lengths = MEM_mallocN(sizeof(chart->edges)*chart->nedges, "PMedianLength");
+ float median;
+ int i;
+
+ /* ok, so i'm lazy */
+ for (i=0, e=chart->edges; e; e=e->nextlink, i++)
+ lengths[i] = p_edge_length(e);
+
+ qsort(lengths, i, sizeof(float), p_compare_float);
+
+ median = lengths[i/2];
+ MEM_freeN(lengths);
+
+ return median;
+}
+
+static float p_smooth_distortion(PEdge *e, float avg2d, float avg3d)
+{
+ float len2d = p_edge_uv_length(e)*avg3d;
+ float len3d = p_edge_length(e)*avg2d;
+
+ return (len3d == 0.0f)? 0.0f: len2d/len3d;
+}
+
+void p_smooth(PChart *chart)
+{
+ PEdge *e;
+ PVert *v;
+ PFace *f;
+ int j, it2, maxiter2, it;
+ int nedges = chart->nedges, nwheel, gridx, gridy;
+ int edgesx, edgesy, nsize, esize, i, x, y, maxiter, totiter;
+ float minv[2], maxv[2], median, invmedian, distortion, avglen2d, avglen3d;
+ float center[2], dx, dy, *nodes, dlimit, d, *oldnodesx, *oldnodesy;
+ float *nodesx, *nodesy, *hedges, *vedges, climit, moved, padding;
+ SmoothTriangle *triangles, *t, *t2, **tri, **trip;
+ SmoothNode *root;
+ MemArena *arena;
+
+ if (nedges == 0)
+ return;
+
+ p_chart_uv_bbox(chart, minv, maxv);
+ median = p_smooth_median_edge_length(chart)*0.10f;
+
+ if (median == 0.0)
+ return;
+
+ invmedian = 1.0/median;
+
+ /* compute edge distortion */
+ distortion = 0.0;
+ avglen2d = avglen3d = 0.0;
+
+ for (e=chart->edges; e; e=e->nextlink) {
+ avglen2d += p_edge_uv_length(e);
+ avglen3d += p_edge_length(e);
+ }
+
+ avglen2d /= nedges;
+ avglen3d /= nedges;
+
+ for (v=chart->verts; v; v=v->nextlink) {
+ v->u.distortion = 0.0;
+ nwheel = 0;
+
+ e = v->edge;
+ do {
+ v->u.distortion += p_smooth_distortion(e, avglen2d, avglen3d);
+ nwheel++;
+
+ e = e->next->next->pair;
+ } while(e && (e != v->edge));
+
+ v->u.distortion /= nwheel;
+ }
+
+ /* need to do excessive grid size checking still */
+ center[0] = 0.5f*(minv[0] + maxv[0]);
+ center[1] = 0.5f*(minv[1] + maxv[1]);
+
+ dx = 0.5f*(maxv[0] - minv[0]);
+ dy = 0.5f*(maxv[1] - minv[1]);
+
+ padding = 0.15f;
+ dx += padding*dx + 2.0f*median;
+ dy += padding*dy + 2.0f*median;
+
+ gridx = (int)(dx*invmedian);
+ gridy = (int)(dy*invmedian);
+
+ minv[0] = center[0] - median*gridx;
+ minv[1] = center[1] - median*gridy;
+ maxv[0] = center[0] + median*gridx;
+ maxv[1] = center[1] + median*gridy;
+
+ /* create grid */
+ gridx = gridx*2 + 1;
+ gridy = gridy*2 + 1;
+
+ if ((gridx <= 2) || (gridy <= 2))
+ return;
+
+ edgesx = gridx-1;
+ edgesy = gridy-1;
+ nsize = gridx*gridy;
+ esize = edgesx*edgesy;
+
+ nodes = MEM_mallocN(sizeof(float)*nsize, "PSmoothNodes");
+ nodesx = MEM_mallocN(sizeof(float)*nsize, "PSmoothNodesX");
+ nodesy = MEM_mallocN(sizeof(float)*nsize, "PSmoothNodesY");
+ oldnodesx = MEM_mallocN(sizeof(float)*nsize, "PSmoothOldNodesX");
+ oldnodesy = MEM_mallocN(sizeof(float)*nsize, "PSmoothOldNodesY");
+ hedges = MEM_mallocN(sizeof(float)*esize, "PSmoothHEdges");
+ vedges = MEM_mallocN(sizeof(float)*esize, "PSmoothVEdges");
+
+ if (!nodes || !nodesx || !nodesy || !oldnodesx || !oldnodesy || !hedges || !vedges) {
+ if (nodes) MEM_freeN(nodes);
+ if (nodesx) MEM_freeN(nodesx);
+ if (nodesy) MEM_freeN(nodesy);
+ if (oldnodesx) MEM_freeN(oldnodesx);
+ if (oldnodesy) MEM_freeN(oldnodesy);
+ if (hedges) MEM_freeN(hedges);
+ if (vedges) MEM_freeN(vedges);
+
+ error("Not enough memory for area smoothing grid.");
+ return;
+ }
+
+ for (x = 0; x < gridx; x++) {
+ for (y = 0; y < gridy; y++) {
+ i = x + y*gridx;
+
+ nodesx[i] = minv[0] + median*x;
+ nodesy[i] = minv[1] + median*y;
+
+ nodes[i] = 1.0f;
+ }
+ }
+
+ /* embed in grid */
+ for (f=chart->faces; f; f=f->nextlink) {
+ PEdge *e1 = f->edge, *e2 = e1->next, *e3 = e2->next;
+ float fmin[2], fmax[2];
+ int bx1, by1, bx2, by2;
+
+ INIT_MINMAX2(fmin, fmax);
+
+ DO_MINMAX2(e1->vert->uv, fmin, fmax);
+ DO_MINMAX2(e2->vert->uv, fmin, fmax);
+ DO_MINMAX2(e3->vert->uv, fmin, fmax);
+
+ bx1 = (int)((fmin[0] - minv[0])*invmedian);
+ by1 = (int)((fmin[1] - minv[1])*invmedian);
+ bx2 = (int)((fmax[0] - minv[0])*invmedian + 2);
+ by2 = (int)((fmax[1] - minv[1])*invmedian + 2);
+
+ for (x = bx1; x < bx2; x++) {
+ for (y = by1; y < by2; y++) {
+ float p[2], b[3];
+
+ i = x + y*gridx;
+
+ p[0] = nodesx[i];
+ p[1] = nodesy[i];
+
+ p_barycentric_2d(e1->vert->uv, e2->vert->uv, e3->vert->uv, p, b);
+
+ if ((b[0] > 0.0) && (b[1] > 0.0) && (b[2] > 0.0)) {
+ nodes[i] = e1->vert->u.distortion*b[0];
+ nodes[i] += e2->vert->u.distortion*b[1];
+ nodes[i] += e3->vert->u.distortion*b[2];
+ }
+ }
+ }
+ }
+
+ /* smooth the grid */
+ maxiter = 10;
+ totiter = 0;
+ climit = 0.00001f*nsize;
+
+ for (it = 0; it < maxiter; it++) {
+ moved = 0.0f;
+
+ for (x = 0; x < edgesx; x++) {
+ for (y = 0; y < edgesy; y++) {
+ i = x + y*gridx;
+ j = x + y*edgesx;
+
+ hedges[j] = (nodes[i] + nodes[i+1])*0.5f;
+ vedges[j] = (nodes[i] + nodes[i+gridx])*0.5f;
+
+ /* we do *inverse* mapping */
+ hedges[j] = 1.0f/hedges[j];
+ vedges[j] = 1.0f/vedges[j];
+ }
+ }
+
+ maxiter2 = 50;
+ dlimit = 0.0001f;
+
+ for (it2 = 0; it2 < maxiter2; it2++) {
+ d = 0.0f;
+ totiter += 1;
+
+ memcpy(oldnodesx, nodesx, sizeof(float)*nsize);
+ memcpy(oldnodesy, nodesy, sizeof(float)*nsize);
+
+ for (x=1; x < gridx-1; x++) {
+ for (y=1; y < gridy-1; y++) {
+ float p[2], oldp[2], sum1, sum2, diff[2], length;
+
+ i = x + gridx*y;
+ j = x + edgesx*y;
+
+ oldp[0] = oldnodesx[i];
+ oldp[1] = oldnodesy[i];
+
+ sum1 = hedges[j-1]*oldnodesx[i-1];
+ sum1 += hedges[j]*oldnodesx[i+1];
+ sum1 += vedges[j-edgesx]*oldnodesx[i-gridx];
+ sum1 += vedges[j]*oldnodesx[i+gridx];
+
+ sum2 = hedges[j-1];
+ sum2 += hedges[j];
+ sum2 += vedges[j-edgesx];
+ sum2 += vedges[j];
+
+ nodesx[i] = sum1/sum2;
+
+ sum1 = hedges[j-1]*oldnodesy[i-1];
+ sum1 += hedges[j]*oldnodesy[i+1];
+ sum1 += vedges[j-edgesx]*oldnodesy[i-gridx];
+ sum1 += vedges[j]*oldnodesy[i+gridx];
+
+ nodesy[i] = sum1/sum2;
+
+ p[0] = nodesx[i];
+ p[1] = nodesy[i];
+
+ diff[0] = p[0] - oldp[0];
+ diff[1] = p[1] - oldp[1];
+
+ length = sqrt(diff[0]*diff[0] + diff[1]*diff[1]);
+ d = MAX2(d, length);
+ moved += length;
+ }
+ }
+
+ if (d < dlimit)
+ break;
+ }
+
+ if (moved < climit)
+ break;
+ }
+
+ MEM_freeN(oldnodesx);
+ MEM_freeN(oldnodesy);
+ MEM_freeN(hedges);
+ MEM_freeN(vedges);
+
+ /* create bsp */
+ t = triangles = MEM_mallocN(sizeof(SmoothTriangle)*esize*2, "PSmoothTris");
+ trip = tri = MEM_mallocN(sizeof(SmoothTriangle*)*esize*2, "PSmoothTriP");
+
+ if (!triangles || !tri) {
+ MEM_freeN(nodes);
+ MEM_freeN(nodesx);
+ MEM_freeN(nodesy);
+
+ if (triangles) MEM_freeN(triangles);
+ if (tri) MEM_freeN(tri);
+
+ error("Not enough memory for area smoothing grid.");
+ return;
+ }
+
+ for (x = 0; x < edgesx; x++) {
+ for (y = 0; y < edgesy; y++) {
+ i = x + y*gridx;
+
+ t->co1[0] = nodesx[i];
+ t->co1[1] = nodesy[i];
+
+ t->co2[0] = nodesx[i+1];
+ t->co2[1] = nodesy[i+1];
+
+ t->co3[0] = nodesx[i+gridx];
+ t->co3[1] = nodesy[i+gridx];
+
+ t->oco1[0] = minv[0] + x*median;
+ t->oco1[1] = minv[1] + y*median;
+
+ t->oco2[0] = minv[0] + (x+1)*median;
+ t->oco2[1] = minv[1] + y*median;
+
+ t->oco3[0] = minv[0] + x*median;
+ t->oco3[1] = minv[1] + (y+1)*median;
+
+ t2 = t+1;
+
+ t2->co1[0] = nodesx[i+gridx+1];
+ t2->co1[1] = nodesy[i+gridx+1];
+
+ t2->oco1[0] = minv[0] + (x+1)*median;
+ t2->oco1[1] = minv[1] + (y+1)*median;
+
+ t2->co2[0] = t->co2[0]; t2->co2[1] = t->co2[1];
+ t2->oco2[0] = t->oco2[0]; t2->oco2[1] = t->oco2[1];
+
+ t2->co3[0] = t->co3[0]; t2->co3[1] = t->co3[1];
+ t2->oco3[0] = t->oco3[0]; t2->oco3[1] = t->oco3[1];
+
+ *trip = t; trip++; t++;
+ *trip = t; trip++; t++;
+ }
+ }
+
+ MEM_freeN(nodes);
+ MEM_freeN(nodesx);
+ MEM_freeN(nodesy);
+
+ arena = BLI_memarena_new(1<<16);
+ root = p_node_new(arena, tri, esize*2, minv, maxv, 0);
+
+ for (v=chart->verts; v; v=v->nextlink)
+ if (!p_node_intersect(root, v->uv))
+ param_warning("area smoothing error: couldn't find mapping triangle\n");
+
+ p_node_delete(root);
+ BLI_memarena_free(arena);
+
+ MEM_freeN(triangles);
+}
+
+/* Exported */
+
+ParamHandle *param_construct_begin()
+{
+ PHandle *handle = MEM_callocN(sizeof*handle, "PHandle");
+ handle->construction_chart = p_chart_new(handle);
+ handle->state = PHANDLE_STATE_ALLOCATED;
+ handle->arena = BLI_memarena_new((1<<16));
+
+ handle->hash_verts = phash_new((PHashLink**)&handle->construction_chart->verts, 1);
+ handle->hash_edges = phash_new((PHashLink**)&handle->construction_chart->edges, 1);
+ handle->hash_faces = phash_new((PHashLink**)&handle->construction_chart->faces, 1);
+
+ return (ParamHandle*)handle;
+}
+
+void param_delete(ParamHandle *handle)
+{
+ PHandle *phandle = (PHandle*)handle;
+ int i;
+
+ param_assert((phandle->state == PHANDLE_STATE_ALLOCATED) ||
+ (phandle->state == PHANDLE_STATE_CONSTRUCTED));
+
+ for (i = 0; i < phandle->ncharts; i++)
+ p_chart_delete(phandle->charts[i]);
+
+ if (phandle->charts)
+ MEM_freeN(phandle->charts);
+
+ if (phandle->construction_chart) {
+ p_chart_delete(phandle->construction_chart);
+
+ phash_delete(phandle->hash_verts);
+ phash_delete(phandle->hash_edges);
+ phash_delete(phandle->hash_faces);
+ }
+
+ BLI_memarena_free(phandle->arena);
+ MEM_freeN(phandle);
+}
+
+void param_face_add(ParamHandle *handle, ParamKey key, int nverts,
+ ParamKey *vkeys, float **co, float **uv,
+ ParamBool *pin, ParamBool *select)
+{
+ PHandle *phandle = (PHandle*)handle;
+
+ param_assert(phash_lookup(phandle->hash_faces, key) == NULL);
+ param_assert(phandle->state == PHANDLE_STATE_ALLOCATED);
+ param_assert((nverts == 3) || (nverts == 4));
+
+ if (nverts == 4) {
+ if (p_quad_split_direction(phandle, co, vkeys)) {
+ p_face_add_construct(phandle, key, vkeys, co, uv, 0, 1, 2, pin, select);
+ p_face_add_construct(phandle, key, vkeys, co, uv, 0, 2, 3, pin, select);
+ }
+ else {
+ p_face_add_construct(phandle, key, vkeys, co, uv, 0, 1, 3, pin, select);
+ p_face_add_construct(phandle, key, vkeys, co, uv, 1, 2, 3, pin, select);
+ }
+ }
+ else
+ p_face_add_construct(phandle, key, vkeys, co, uv, 0, 1, 2, pin, select);
+}
+
+void param_edge_set_seam(ParamHandle *handle, ParamKey *vkeys)
+{
+ PHandle *phandle = (PHandle*)handle;
+ PEdge *e;
+
+ param_assert(phandle->state == PHANDLE_STATE_ALLOCATED);
+
+ e = p_edge_lookup(phandle, vkeys);
+ if (e)
+ e->flag |= PEDGE_SEAM;
+}
+
+void param_construct_end(ParamHandle *handle, ParamBool fill, ParamBool impl)
+{
+ PHandle *phandle = (PHandle*)handle;
+ PChart *chart = phandle->construction_chart;
+ int i, j, nboundaries = 0;
+ PEdge *outer;
+
+ param_assert(phandle->state == PHANDLE_STATE_ALLOCATED);
+
+ phandle->ncharts = p_connect_pairs(phandle, impl);
+ phandle->charts = p_split_charts(phandle, chart, phandle->ncharts);
+
+ p_chart_delete(phandle->construction_chart);
+ phandle->construction_chart = NULL;
+
+ phash_delete(phandle->hash_verts);
+ phash_delete(phandle->hash_edges);
+ phash_delete(phandle->hash_faces);
+ phandle->hash_verts = phandle->hash_edges = phandle->hash_faces = NULL;
+
+ for (i = j = 0; i < phandle->ncharts; i++) {
+ PVert *v;
+ PChart *chart = phandle->charts[i];
+
+ p_chart_boundaries(chart, &nboundaries, &outer);
+
+ if (nboundaries == 0) {
+ p_chart_delete(chart);
+ continue;
+ }
+
+ phandle->charts[j] = chart;
+ j++;
+
+ if (fill && (nboundaries > 1))
+ p_chart_fill_boundaries(chart, outer);
+
+ for (v=chart->verts; v; v=v->nextlink)
+ p_vert_load_pin_select_uvs(v);
+ }
+
+ phandle->ncharts = j;
+
+ phandle->state = PHANDLE_STATE_CONSTRUCTED;
+}
+
+void param_lscm_begin(ParamHandle *handle, ParamBool live, ParamBool abf)
+{
+ PHandle *phandle = (PHandle*)handle;
+ PFace *f;
+ int i;
+
+ param_assert(phandle->state == PHANDLE_STATE_CONSTRUCTED);
+ phandle->state = PHANDLE_STATE_LSCM;
+
+ for (i = 0; i < phandle->ncharts; i++) {
+ for (f=phandle->charts[i]->faces; f; f=f->nextlink)
+ p_face_backup_uvs(f);
+ p_chart_lscm_begin(phandle->charts[i], live, abf);
+ }
+}
+
+void param_lscm_solve(ParamHandle *handle)
+{
+ PHandle *phandle = (PHandle*)handle;
+ PChart *chart;
+ int i;
+ PBool result;
+
+ param_assert(phandle->state == PHANDLE_STATE_LSCM);
+
+ for (i = 0; i < phandle->ncharts; i++) {
+ chart = phandle->charts[i];
+
+ if (chart->u.lscm.context) {
+ result = p_chart_lscm_solve(chart);
+
+ if (result && !(chart->flag & PCHART_NOPACK))
+ p_chart_rotate_minimum_area(chart);
+
+ if (!result || (chart->u.lscm.pin1))
+ p_chart_lscm_end(chart);
+ }
+ }
+}
+
+void param_lscm_end(ParamHandle *handle)
+{
+ PHandle *phandle = (PHandle*)handle;
+ int i;
+
+ param_assert(phandle->state == PHANDLE_STATE_LSCM);
+
+ for (i = 0; i < phandle->ncharts; i++) {
+ p_chart_lscm_end(phandle->charts[i]);
+#if 0
+ p_chart_complexify(phandle->charts[i]);
+#endif
+ }
+
+ phandle->state = PHANDLE_STATE_CONSTRUCTED;
+}
+
+void param_stretch_begin(ParamHandle *handle)
+{
+ PHandle *phandle = (PHandle*)handle;
+ PChart *chart;
+ PVert *v;
+ PFace *f;
+ int i;
+
+ param_assert(phandle->state == PHANDLE_STATE_CONSTRUCTED);
+ phandle->state = PHANDLE_STATE_STRETCH;
+
+ phandle->rng = rng_new(31415926);
+ phandle->blend = 0.0f;
+
+ for (i = 0; i < phandle->ncharts; i++) {
+ chart = phandle->charts[i];
+
+ for (v=chart->verts; v; v=v->nextlink)
+ v->flag &= ~PVERT_PIN; /* don't use user-defined pins */
+
+ p_stretch_pin_boundary(chart);
+
+ for (f=chart->faces; f; f=f->nextlink) {
+ p_face_backup_uvs(f);
+ f->u.area3d = p_face_area(f);
+ }
+ }
+}
+
+void param_stretch_blend(ParamHandle *handle, float blend)
+{
+ PHandle *phandle = (PHandle*)handle;
+
+ param_assert(phandle->state == PHANDLE_STATE_STRETCH);
+ phandle->blend = blend;
+}
+
+void param_stretch_iter(ParamHandle *handle)
+{
+ PHandle *phandle = (PHandle*)handle;
+ PChart *chart;
+ int i;
+
+ param_assert(phandle->state == PHANDLE_STATE_STRETCH);
+
+ for (i = 0; i < phandle->ncharts; i++) {
+ chart = phandle->charts[i];
+ p_chart_stretch_minimize(chart, phandle->rng);
+ }
+}
+
+void param_stretch_end(ParamHandle *handle)
+{
+ PHandle *phandle = (PHandle*)handle;
+
+ param_assert(phandle->state == PHANDLE_STATE_STRETCH);
+ phandle->state = PHANDLE_STATE_CONSTRUCTED;
+
+ rng_free(phandle->rng);
+ phandle->rng = NULL;
+}
+
+void param_smooth_area(ParamHandle *handle)
+{
+ PHandle *phandle = (PHandle*)handle;
+ int i;
+
+ param_assert(phandle->state == PHANDLE_STATE_CONSTRUCTED);
+
+ for (i = 0; i < phandle->ncharts; i++) {
+ PChart *chart = phandle->charts[i];
+ PVert *v;
+
+ for (v=chart->verts; v; v=v->nextlink)
+ v->flag &= ~PVERT_PIN;
+
+ p_smooth(chart);
+ }
+}
+
+void param_pack(ParamHandle *handle)
+{
+ /* box packing variables */
+ boxPack *boxarray, *box;
+ float tot_width, tot_height, scale;
+
+ PChart *chart;
+ int i, unpacked=0;
+ float trans[2];
+
+ PHandle *phandle = (PHandle*)handle;
+
+
+ if (phandle->ncharts == 0)
+ return;
+
+ /* we may not use all these boxes */
+ boxarray = MEM_mallocN( phandle->ncharts*sizeof(boxPack), "boxPack box");
+
+ for (i = 0; i < phandle->ncharts; i++) {
+ chart = phandle->charts[i];
+
+
+ if (chart->flag & PCHART_NOPACK) {
+ unpacked++;
+ continue;
+ }
+
+ box = boxarray+(i-unpacked);
+
+ p_chart_uv_bbox(chart, trans, chart->u.pack.size);
+
+ trans[0] = -trans[0];
+ trans[1] = -trans[1];
+
+ p_chart_uv_translate(chart, trans);
+
+ box->w = chart->u.pack.size[0] + trans[0];
+ box->h = chart->u.pack.size[1] + trans[1];
+ box->index = i; /* warning this index skips PCHART_NOPACK boxes */
+ }
+
+ boxPack2D(boxarray, phandle->ncharts-unpacked, &tot_width, &tot_height);
+
+ if (tot_height>tot_width)
+ scale = 1.0/tot_height;
+ else
+ scale = 1.0/tot_width;
+
+ for (i = 0; i < phandle->ncharts-unpacked; i++) {
+ box = boxarray+i;
+ trans[0] = box->x;
+ trans[1] = box->y;
+
+ chart = phandle->charts[box->index];
+ p_chart_uv_translate(chart, trans);
+ p_chart_uv_scale(chart, scale);
+ }
+ MEM_freeN(boxarray);
+}
+
+void param_flush(ParamHandle *handle)
+{
+ PHandle *phandle = (PHandle*)handle;
+ PChart *chart;
+ int i;
+
+ for (i = 0; i < phandle->ncharts; i++) {
+ chart = phandle->charts[i];
+
+ if ((phandle->state == PHANDLE_STATE_LSCM) && !chart->u.lscm.context)
+ continue;
+
+ if (phandle->blend == 0.0f)
+ p_flush_uvs(chart);
+ else
+ p_flush_uvs_blend(chart, phandle->blend);
+ }
+}
+
+void param_flush_restore(ParamHandle *handle)
+{
+ PHandle *phandle = (PHandle*)handle;
+ PChart *chart;
+ PFace *f;
+ int i;
+
+ for (i = 0; i < phandle->ncharts; i++) {
+ chart = phandle->charts[i];
+
+ for (f=chart->faces; f; f=f->nextlink)
+ p_face_restore_uvs(f);
+ }
+}
+
diff --git a/source/blender/src/parametrizer.h b/source/blender/src/parametrizer.h
new file mode 100644
index 00000000000..fcda5fc6164
--- /dev/null
+++ b/source/blender/src/parametrizer.h
@@ -0,0 +1,85 @@
+
+#ifndef __PARAMETRIZER_H__
+#define __PARAMETRIZER_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void ParamHandle; /* handle to a set of charts */
+typedef long ParamKey; /* (hash) key for identifying verts and faces */
+typedef enum ParamBool {
+ PARAM_TRUE = 1,
+ PARAM_FALSE = 0
+} ParamBool;
+
+/* Chart construction:
+ -------------------
+ - faces and seams may only be added between construct_{begin|end}
+ - the pointers to co and uv are stored, rather than being copied
+ - vertices are implicitly created
+ - in construct_end the mesh will be split up according to the seams
+ - the resulting charts must be:
+ - manifold, connected, open (at least one boundary loop)
+ - output will be written to the uv pointers
+*/
+
+ParamHandle *param_construct_begin();
+
+void param_face_add(ParamHandle *handle,
+ ParamKey key,
+ int nverts,
+ ParamKey *vkeys,
+ float **co,
+ float **uv,
+ ParamBool *pin,
+ ParamBool *select);
+
+void param_edge_set_seam(ParamHandle *handle,
+ ParamKey *vkeys);
+
+void param_construct_end(ParamHandle *handle, ParamBool fill, ParamBool impl);
+void param_delete(ParamHandle *chart);
+
+/* Least Squares Conformal Maps:
+ -----------------------------
+ - charts with less than two pinned vertices are assigned 2 pins
+ - lscm is divided in three steps:
+ - begin: compute matrix and it's factorization (expensive)
+ - solve using pinned coordinates (cheap)
+ - end: clean up
+ - uv coordinates are allowed to change within begin/end, for
+ quick re-solving
+*/
+
+void param_lscm_begin(ParamHandle *handle, ParamBool live, ParamBool abf);
+void param_lscm_solve(ParamHandle *handle);
+void param_lscm_end(ParamHandle *handle);
+
+/* Stretch */
+
+void param_stretch_begin(ParamHandle *handle);
+void param_stretch_blend(ParamHandle *handle, float blend);
+void param_stretch_iter(ParamHandle *handle);
+void param_stretch_end(ParamHandle *handle);
+
+/* Area Smooth */
+
+void param_smooth_area(ParamHandle *handle);
+
+/* Packing */
+
+void param_pack(ParamHandle *handle);
+
+/* Flushing */
+
+void param_flush(ParamHandle *handle);
+void param_flush_restore(ParamHandle *handle);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*__PARAMETRIZER_H__*/
+
diff --git a/source/blender/src/parametrizer_intern.h b/source/blender/src/parametrizer_intern.h
new file mode 100644
index 00000000000..6114ecc8696
--- /dev/null
+++ b/source/blender/src/parametrizer_intern.h
@@ -0,0 +1,192 @@
+
+#ifndef __PARAMETRIZER_INTERN_H__
+#define __PARAMETRIZER_INTERN_H__
+
+/* Utils */
+
+#if 0
+ #define param_assert(condition);
+ #define param_warning(message);
+ #define param_test_equals_ptr(condition);
+ #define param_test_equals_int(condition);
+#else
+ #define param_assert(condition) \
+ if (!(condition)) \
+ { /*printf("Assertion %s:%d\n", __FILE__, __LINE__); abort();*/ }
+ #define param_warning(message) \
+ { /*printf("Warning %s:%d: %s\n", __FILE__, __LINE__, message);*/ }
+ #define param_test_equals_ptr(str, a, b) \
+ if (a != b) \
+ { /*printf("Equals %s => %p != %p\n", str, a, b);*/ };
+ #define param_test_equals_int(str, a, b) \
+ if (a != b) \
+ { /*printf("Equals %s => %d != %d\n", str, a, b);*/ };
+#endif
+
+typedef enum PBool {
+ P_TRUE = 1,
+ P_FALSE = 0
+} PBool;
+
+/* Special Purpose Hash */
+
+typedef long PHashKey;
+
+typedef struct PHashLink {
+ struct PHashLink *next;
+ PHashKey key;
+} PHashLink;
+
+typedef struct PHash {
+ PHashLink **list;
+ PHashLink **buckets;
+ int size, cursize, cursize_id;
+} PHash;
+
+
+
+struct PVert;
+struct PEdge;
+struct PFace;
+struct PChart;
+struct PHandle;
+
+/* Simplices */
+
+typedef struct PVert {
+ struct PVert *nextlink;
+
+ union PVertUnion {
+ PHashKey key; /* construct */
+ int id; /* abf/lscm matrix index */
+ float distortion; /* area smoothing */
+ HeapNode *heaplink; /* edge collapsing */
+ } u;
+
+ struct PEdge *edge;
+ float *co;
+ float uv[2];
+ unsigned char flag;
+
+} PVert;
+
+typedef struct PEdge {
+ struct PEdge *nextlink;
+
+ union PEdgeUnion {
+ PHashKey key; /* construct */
+ int id; /* abf matrix index */
+ HeapNode *heaplink; /* fill holes */
+ struct PEdge *nextcollapse; /* simplification */
+ } u;
+
+ struct PVert *vert;
+ struct PEdge *pair;
+ struct PEdge *next;
+ struct PFace *face;
+ float *orig_uv, old_uv[2];
+ unsigned short flag;
+
+} PEdge;
+
+typedef struct PFace {
+ struct PFace *nextlink;
+
+ union PFaceUnion {
+ PHashKey key; /* construct */
+ int chart; /* construct splitting*/
+ float area3d; /* stretch */
+ int id; /* abf matrix index */
+ } u;
+
+ struct PEdge *edge;
+ unsigned char flag;
+
+} PFace;
+
+enum PVertFlag {
+ PVERT_PIN = 1,
+ PVERT_SELECT = 2,
+ PVERT_INTERIOR = 4,
+ PVERT_COLLAPSE = 8,
+ PVERT_SPLIT = 16
+};
+
+enum PEdgeFlag {
+ PEDGE_SEAM = 1,
+ PEDGE_VERTEX_SPLIT = 2,
+ PEDGE_PIN = 4,
+ PEDGE_SELECT = 8,
+ PEDGE_DONE = 16,
+ PEDGE_FILLED = 32,
+ PEDGE_COLLAPSE = 64,
+ PEDGE_COLLAPSE_EDGE = 128,
+ PEDGE_COLLAPSE_PAIR = 256
+};
+
+/* for flipping faces */
+#define PEDGE_VERTEX_FLAGS (PEDGE_PIN)
+
+enum PFaceFlag {
+ PFACE_CONNECTED = 1,
+ PFACE_FILLED = 2,
+ PFACE_COLLAPSE = 4
+};
+
+/* Chart */
+
+typedef struct PChart {
+ PVert *verts;
+ PEdge *edges;
+ PFace *faces;
+ int nverts, nedges, nfaces;
+
+ PVert *collapsed_verts;
+ PEdge *collapsed_edges;
+ PFace *collapsed_faces;
+
+ union PChartUnion {
+ struct PChartLscm {
+ NLContext context;
+ float *abf_alpha;
+ PVert *pin1, *pin2;
+ } lscm;
+ struct PChartPack {
+ float rescale, area;
+ float size[2], trans[2];
+ } pack;
+ } u;
+
+ unsigned char flag;
+ struct PHandle *handle;
+} PChart;
+
+enum PChartFlag {
+ PCHART_NOPACK = 1
+};
+
+enum PHandleState {
+ PHANDLE_STATE_ALLOCATED,
+ PHANDLE_STATE_CONSTRUCTED,
+ PHANDLE_STATE_LSCM,
+ PHANDLE_STATE_STRETCH
+};
+
+typedef struct PHandle {
+ enum PHandleState state;
+ MemArena *arena;
+
+ PChart *construction_chart;
+ PHash *hash_verts;
+ PHash *hash_edges;
+ PHash *hash_faces;
+
+ PChart **charts;
+ int ncharts;
+
+ RNG *rng;
+ float blend;
+} PHandle;
+
+#endif /*__PARAMETRIZER_INTERN_H__*/
+
diff --git a/source/blender/src/playanim.c b/source/blender/src/playanim.c
new file mode 100644
index 00000000000..65853a841d6
--- /dev/null
+++ b/source/blender/src/playanim.c
@@ -0,0 +1,794 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef WIN32
+#include <unistd.h>
+#include <sys/times.h>
+#include <sys/wait.h>
+#else
+#include <io.h>
+#endif
+#include "MEM_guardedalloc.h"
+
+#ifdef WITH_QUICKTIME
+#ifdef _WIN32
+#include <QTML.h>
+#include <Movies.h>
+#elif defined(__APPLE__)
+#include <QuickTime/Movies.h>
+#endif /* __APPLE__ */
+#endif /* WITH_QUICKTIME */
+
+#include "PIL_time.h"
+
+#include <math.h>
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "BDR_editcurve.h"
+
+#include "BKE_blender.h"
+#include "BKE_global.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+#include "BIF_screen.h"
+#include "BIF_mywindow.h"
+
+#include "BMF_Api.h"
+
+#include "playanim_ext.h"
+#include "mydevice.h"
+#include "blendef.h"
+#include "winlay.h"
+
+/* ***************** gl_util.c ****************** */
+
+static Window *g_window = NULL;
+static int qualN = 0;
+
+#define LSHIFT (1<<0)
+#define RSHIFT (1<<1)
+#define SHIFT (LSHIFT | RSHIFT)
+#define LALT (1<<2)
+#define RALT (1<<3)
+#define ALT (LALT | RALT)
+#define LCTRL (1<<4)
+#define RCTRL (1<<5)
+#define LMOUSE (1<<16)
+#define MMOUSE (1<<17)
+#define RMOUSE (1<<18)
+#define MOUSE (LMOUSE | MMOUSE | RMOUSE)
+
+unsigned short screen_qread(short *val, char *ascii);
+
+/* implementation */
+static int qreadN(short *val)
+{
+ char ascii;
+ int event = screen_qread(val, &ascii);
+
+ switch(event){
+ case LEFTMOUSE:
+ if (*val) qualN |= LMOUSE;
+ else qualN &= ~LMOUSE;
+ break;
+ case MIDDLEMOUSE:
+ if (*val) qualN |= MMOUSE;
+ else qualN &= ~MMOUSE;
+ break;
+ case RIGHTMOUSE:
+ if (*val) qualN |= RMOUSE;
+ else qualN &= ~RMOUSE;
+ break;
+ case LEFTSHIFTKEY:
+ if (*val) qualN |= LSHIFT;
+ else qualN &= ~LSHIFT;
+ break;
+ case RIGHTSHIFTKEY:
+ if (*val) qualN |= RSHIFT;
+ else qualN &= ~RSHIFT;
+ break;
+ case LEFTCTRLKEY:
+ if (*val) qualN |= LCTRL;
+ else qualN &= ~LCTRL;
+ break;
+ case RIGHTCTRLKEY:
+ if (*val) qualN |= RCTRL;
+ else qualN &= ~RCTRL;
+ break;
+ case LEFTALTKEY:
+ if (*val) qualN |= LALT;
+ else qualN &= ~LALT;
+ break;
+ case RIGHTALTKEY:
+ if (*val) qualN |= RALT;
+ else qualN &= ~RALT;
+ break;
+ }
+
+ return(event);
+}
+
+/* ***************** gl_util.c ****************** */
+
+
+
+
+typedef struct pict{
+ struct pict *next, *prev;
+ char *mem;
+ int size;
+ char *name;
+ struct ImBuf *ibuf;
+ struct anim *anim;
+ int frame;
+ int IB_flags;
+}Pict;
+
+static struct ListBase _picsbase = {0,0};
+static struct ListBase *picsbase = &_picsbase;
+static int fromdisk = FALSE;
+static float zoomx = 1.0 , zoomy = 1.0;
+static double ptottime = 0.0, swaptime = 0.04;
+
+static int pupdate_time(void)
+{
+ static double ltime;
+ double time;
+
+ time = PIL_check_seconds_timer();
+
+ ptottime += (time - ltime);
+ ltime = time;
+ return (ptottime < 0);
+}
+
+static void toscreen(Pict *picture, struct ImBuf *ibuf)
+{
+
+ if (ibuf == 0){
+ printf("no ibuf !\n");
+ return;
+ }
+
+ glRasterPos2f(0.0f, 0.0f);
+
+ glDrawPixels(ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
+
+ pupdate_time();
+
+ if(picture && (qualN & LMOUSE)) {
+ char str[256];
+ cpack(-1);
+ glRasterPos2f(0.02f, 0.03f);
+ sprintf(str, "%s", picture->name);
+ BMF_DrawString(G.fonts, str);
+ }
+
+ window_swap_buffers(g_window);
+}
+
+static void build_pict_list(char * first)
+{
+ int size,pic,file;
+ char *mem, name[256];
+ short val;
+ struct pict * picture = 0;
+ struct ImBuf *ibuf = 0;
+ int count = 0;
+ char str[100];
+ struct anim * anim;
+
+ if (IMB_isanim(first)) {
+ anim = IMB_open_anim(first, IB_rect);
+ if (anim) {
+ ibuf = IMB_anim_absolute(anim, 0);
+ if (ibuf) {
+ toscreen(NULL, ibuf);
+ IMB_freeImBuf(ibuf);
+ }
+
+ for (pic = 0; pic < IMB_anim_get_duration(anim); pic ++) {
+ picture = (Pict*)MEM_callocN(sizeof(Pict),"Pict");
+ picture->anim = anim;
+ picture->frame = pic;
+ picture->IB_flags = IB_rect;
+ sprintf(str, "%s : %d", first, pic + 1);
+ picture->name = strdup(str);
+ BLI_addtail(picsbase, picture);
+ }
+ }
+ else printf("couldn't open anim %s\n", first);
+ }
+ else {
+
+ strcpy(name,first);
+
+ pupdate_time();
+ ptottime = 1.0;
+
+/*
+ O_DIRECT
+ If set, all reads and writes on the resulting file descriptor will
+ be performed directly to or from the user program buffer, provided
+ appropriate size and alignment restrictions are met. Refer to the
+ F_SETFL and F_DIOINFO commands in the fcntl(2) manual entry for
+ information about how to determine the alignment constraints.
+ O_DIRECT is a Silicon Graphics extension and is only supported on
+ local EFS and XFS file systems.
+*/
+ while(IMB_ispic(name)){
+ file = open(name, O_BINARY|O_RDONLY, 0);
+ if (file < 0) return;
+ picture = (struct pict*)MEM_callocN(sizeof(struct pict), "picture");
+ if (picture == 0){
+ printf("Not enough memory for pict struct \n");
+ close(file);
+ return;
+ }
+ size = BLI_filesize(file);
+
+ if (size < 1) {
+ close(file);
+ MEM_freeN(picture);
+ return;
+ }
+
+ picture->size = size;
+ picture->IB_flags = IB_rect;
+
+ if (fromdisk == FALSE) {
+ mem=(char *)MEM_mallocN(size, "build pic list");
+ if (mem==0){
+ printf("Couldn't get memory\n");
+ close(file);
+ MEM_freeN(picture);
+ return;
+ }
+
+ if (read(file,mem,size) != size){
+ printf("Error while reading %s\n",name);
+ close(file);
+ MEM_freeN(picture);
+ MEM_freeN(mem);
+ return;
+ }
+ } else mem = 0;
+
+ picture->mem = mem;
+ picture->name = strdup(name);
+ close(file);
+ BLI_addtail(picsbase,picture);
+ count++;
+
+ pupdate_time();
+
+ if (ptottime > 1.0) {
+ if (picture->mem) ibuf = IMB_ibImageFromMemory((int *) picture->mem, picture->size, picture->IB_flags);
+ else ibuf = IMB_loadiffname(picture->name, picture->IB_flags);
+ if (ibuf) {
+ toscreen(picture, ibuf);
+ IMB_freeImBuf(ibuf);
+ }
+ pupdate_time();
+ ptottime = 0.0;
+ }
+
+ BLI_newname(name, +1);
+
+ while(qtest()){
+ switch(qreadN(&val)){
+ case ESCKEY:
+ if (val) return;
+ break;
+ }
+ }
+ }
+ }
+ return;
+}
+
+void playanim(int argc, char **argv)
+{
+ struct ImBuf *ibuf = 0;
+ struct pict *picture = 0;
+ char name[256];
+ short val = 0, go = TRUE, ibufx = 0, ibufy = 0;
+ int event, stopped = FALSE, maxwinx, maxwiny;
+ short /* c233 = FALSE, */ /* yuvx = FALSE, */ once = FALSE, sstep = FALSE, wait2 = FALSE, /* resetmap = FALSE, */ pause = 0;
+ short pingpong = FALSE, direction = 1, next = 1, turbo = FALSE, /* doubleb = TRUE, */ noskip = FALSE;
+ int sizex, sizey, ofsx, ofsy, i;
+ /* This was done to disambiguate the name for use under c++. */
+ struct anim * anim = 0;
+ int start_x= 0, start_y= 0;
+
+ while (argc > 1) {
+ if (argv[1][0] == '-'){
+ switch(argv[1][1]) {
+ case 'm':
+ fromdisk = TRUE;
+ break;
+ case 'p':
+ if (argc>3) {
+ start_x= atoi(argv[2]);
+ start_y= atoi(argv[3]);
+ argc-= 2;
+ argv+= 2;
+ } else {
+ printf("too few arguments for -p (need 2): skipping\n");
+ }
+ break;
+ default:
+ printf("unknown option '%c': skipping\n", argv[1][1]);
+ break;
+ }
+ argc--;
+ argv++;
+ } else break;
+ }
+
+#ifdef WITH_QUICKTIME
+#if defined (_WIN32) || defined (__APPLE__)
+ /* Initialize QuickTime */
+#ifndef noErr
+#define noErr 0
+#endif
+
+#ifdef _WIN32
+ if (InitializeQTML(0) != noErr)
+ G.have_quicktime = FALSE;
+ else
+ G.have_quicktime = TRUE;
+#endif /* _WIN32 */
+ if (EnterMovies() != noErr)
+ G.have_quicktime = FALSE;
+ else
+#endif /* _WIN32 || __APPLE__ */
+ G.have_quicktime = TRUE;
+#endif /* WITH_QUICKTIME */
+
+ if (argc > 1) strcpy(name,argv[1]);
+ else {
+ BLI_getwdN(name);
+ if (name[strlen(name)-1] != '/') strcat(name,"/");
+ }
+
+ if (IMB_isanim(name)) {
+ anim = IMB_open_anim(name, IB_rect);
+ if (anim) {
+ ibuf = IMB_anim_absolute(anim, 0);
+ IMB_close_anim(anim);
+ anim = NULL;
+ }
+ } else if (!IMB_ispic(name)) {
+ exit(1);
+ }
+
+ if (ibuf == 0) ibuf = IMB_loadiffname(name, IB_rect);
+ if (ibuf == 0){
+ printf("couldn't open %s\n",name);
+ exit(1);
+ }
+
+ #if !defined(WIN32) && !defined(__APPLE__)
+ if (fork()) exit(0);
+ #endif
+
+ winlay_get_screensize(&maxwinx, &maxwiny);
+
+ /* XXX, fixme zr */
+ {
+ extern void add_to_mainqueue(Window *win, void *user_data, short evt, short val, char ascii);
+
+ g_window = window_open("Blender:Anim", start_x, start_y, ibuf->x, ibuf->y, 0);
+ window_set_handler(g_window, add_to_mainqueue, NULL);
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f);
+ glMatrixMode(GL_MODELVIEW);
+ }
+
+ G.fonts= BMF_GetFont(BMF_kHelvetica10);
+
+ ibufx = ibuf->x;
+ ibufy = ibuf->y;
+
+ if (maxwinx % ibuf->x) maxwinx = ibuf->x * (1 + (maxwinx / ibuf->x));
+ if (maxwiny % ibuf->y) maxwiny = ibuf->y * (1 + (maxwiny / ibuf->y));
+
+ glClearColor(0.0, 0.0, 0.0, 0.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ window_swap_buffers(g_window);
+
+ build_pict_list(name);
+
+ for (i = 2; i < argc; i++){
+ strcpy(name, argv[i]);
+ build_pict_list(name);
+ }
+
+ IMB_freeImBuf(ibuf);
+ ibuf = 0;
+
+ pupdate_time();
+ ptottime = 0;
+
+ while (go){
+ if (pingpong) direction = -direction;
+
+ if (direction == 1) picture = picsbase->first;
+ else picture = picsbase->last;
+
+ if (picture == 0){
+ printf("couldn't find pictures\n");
+ go = FALSE;
+ }
+ if (pingpong){
+ if (direction == 1) picture = picture->next;
+ else picture = picture->prev;
+ }
+ if (ptottime > 0.0) ptottime = 0.0;
+
+ while (picture){
+ if (ibuf != 0 && ibuf->type == 0) IMB_freeImBuf(ibuf);
+
+ if (picture->ibuf) ibuf = picture->ibuf;
+ else if (picture->anim) ibuf = IMB_anim_absolute(picture->anim, picture->frame);
+ else if (picture->mem) ibuf = IMB_ibImageFromMemory((int *) picture->mem, picture->size, picture->IB_flags);
+ else ibuf = IMB_loadiffname(picture->name, picture->IB_flags);
+
+ if (ibuf){
+ strcpy(ibuf->name, picture->name);
+
+#ifdef _WIN32
+ window_set_title(g_window, picture->name);
+#endif
+
+ while (pupdate_time()) PIL_sleep_ms(1);
+ ptottime -= swaptime;
+ toscreen(picture, ibuf);
+ } /* else deleten */
+ else {
+ printf("error: can't play this image type\n");
+ exit(0);
+ }
+
+ if (once){
+ if (picture->next == 0) wait2 = TRUE;
+ else if (picture->prev == 0) wait2 = TRUE;
+ }
+
+ next = direction;
+
+ while ((qtest() != 0 ) || ( wait2 != 0)){
+ if (wait2 && stopped) {
+ stopped = FALSE;
+ }
+
+ event = qreadN(&val);
+ /* printf("%d %d\n", event, val); */
+
+ if (wait2){
+ pupdate_time();
+ ptottime = 0;
+ }
+ switch (event){
+ case AKEY:
+ if (val)
+ noskip = !noskip;
+ break;
+ case PKEY:
+ if (val)
+ pingpong = !pingpong;
+ break;
+ case SLASHKEY:
+ if (val) {
+ if (qualN & SHIFT) {
+ if (ibuf)
+ printf(" Name: %s | Speed: %.2f frames/s\n", ibuf->name, 1.0 / swaptime);
+ } else {
+ swaptime = 1.0 / 5.0;
+ }
+ }
+ break;
+ case LEFTARROWKEY:
+ if (val){
+ sstep = TRUE;
+ wait2 = FALSE;
+ if (qualN & SHIFT) {
+ picture = picsbase->first;
+ next = 0;
+ } else {
+ next = -1;
+ }
+ }
+ break;
+ case DOWNARROWKEY:
+ if (val){
+ wait2 = FALSE;
+ if (qualN & SHIFT) {
+ next = direction = -1;
+ } else {
+ next = -10;
+ sstep = TRUE;
+ }
+ }
+ break;
+ case RIGHTARROWKEY:
+ if (val){
+ sstep = TRUE;
+ wait2 = FALSE;
+ if (qualN & SHIFT) {
+ picture = picsbase->last;
+ next = 0;
+ } else {
+ next = 1;
+ }
+ }
+ break;
+ case UPARROWKEY:
+ if (val){
+ wait2 = FALSE;
+ if (qualN & SHIFT) {
+ next = direction = 1;
+ } else {
+ next = 10;
+ sstep = TRUE;
+ }
+ }
+ break;
+ case LEFTMOUSE:
+ case MOUSEX:
+ if (qualN & LMOUSE) {
+ window_get_size(g_window,&sizex,&sizey);
+ picture = picsbase->first;
+ i = 0;
+ while (picture){
+ i ++;
+ picture = picture->next;
+ }
+ i = (i * val) / sizex;
+ picture = picsbase->first;
+ for (; i > 0; i--){
+ if (picture->next == 0) break;
+ picture = picture->next;
+ }
+ sstep = TRUE;
+ wait2 = FALSE;
+ next = 0;
+ }
+ break;
+ go= FALSE;
+ break;
+ case EQUALKEY:
+ if (val) {
+ if (qualN & SHIFT) {
+ pause ++;
+ printf("pause:%d\n", pause);
+ } else swaptime /= 1.1;
+ }
+ break;
+ case MINUSKEY:
+ if (val) {
+ if (qualN & SHIFT) {
+ pause --;
+ printf("pause:%d\n", pause);
+ } else swaptime *= 1.1;
+ }
+ break;
+ case PAD0:
+ if (val){
+ if (once) once = wait2 = FALSE;
+ else {
+ picture = 0;
+ once = TRUE;
+ wait2 = FALSE;
+ }
+ }
+ break;
+ case RETKEY:
+ case PADENTER:
+ if (val){
+ wait2 = sstep = FALSE;
+ }
+ break;
+ case PADPERIOD:
+ if (val){
+ if (sstep) wait2 = FALSE;
+ else {
+ sstep = TRUE;
+ wait2 = !wait2;
+ }
+ }
+ break;
+ case PAD1:
+ swaptime = 1.0 / 60.0;
+ break;
+ case PAD2:
+ swaptime = 1.0 / 50.0;
+ break;
+ case PAD3:
+ swaptime = 1.0 / 30.0;
+ break;
+ case PAD4:
+ swaptime = 1.0 / 25.0;
+ break;
+ case PAD5:
+ swaptime = 1.0 / 20.0;
+ break;
+ case PAD6:
+ swaptime = 1.0 / 15.0;
+ break;
+ case PAD7:
+ swaptime = 1.0 / 12.0;
+ break;
+ case PAD8:
+ swaptime = 1.0 / 10.0;
+ break;
+ case PAD9:
+ swaptime = 1.0 / 6.0;
+ break;
+ case PADPLUSKEY:
+ if (val == 0) break;
+ zoomx += 2.0;
+ zoomy += 2.0;
+ case PADMINUS:
+ if (val == 0) break;
+ if (zoomx > 1.0) zoomx -= 1.0;
+ if (zoomy > 1.0) zoomy -= 1.0;
+ window_get_position(g_window,&ofsx,&ofsy);
+ window_get_size(g_window,&sizex,&sizey);
+ ofsx += sizex/2;
+ ofsy += sizey/2;
+ sizex = zoomx * ibufx;
+ sizey = zoomy * ibufy;
+ ofsx -= sizex/2;
+ ofsy -= sizey/2;
+/* window_set_position(g_window,sizex,sizey); */
+ window_set_size(g_window,sizex,sizey);
+ break;
+ case RESHAPE:
+ case REDRAW:
+ window_get_size(g_window,&sizex,&sizey);
+ window_make_active(g_window);
+
+ glViewport(0, 0, sizex, sizey);
+ glScissor(0, 0, sizex, sizey);
+
+ zoomx = (float) sizex / ibufx;
+ zoomy = (float) sizey / ibufy;
+ zoomx = floor(zoomx + 0.5);
+ zoomy = floor(zoomy + 0.5);
+ if (zoomx < 1.0) zoomx = 1.0;
+ if (zoomy < 1.0) zoomy = 1.0;
+
+ sizex = zoomx * ibufx;
+ sizey = zoomy * ibufy;
+
+ glPixelZoom(zoomx, zoomy);
+ glEnable(GL_DITHER);
+ ptottime = 0.0;
+ toscreen(picture, ibuf);
+ while (qtest()) qreadN(&val);
+
+ break;
+ case ESCKEY:
+ case WINCLOSE:
+ case WINQUIT:
+ go = FALSE;
+ break;
+ }
+ if (go == FALSE) break;
+ }
+
+ wait2 = sstep;
+
+ if (wait2 == 0 && stopped == 0) {
+ stopped = TRUE;
+ }
+
+ pupdate_time();
+
+ if (picture && next) {
+ /* always at least set one step */
+ while (picture){
+ if (next < 0) picture = picture->prev;
+ else picture = picture->next;
+
+ if (once && picture != 0){
+ if (picture->next == 0) wait2 = TRUE;
+ else if (picture->prev == 0) wait2 = TRUE;
+ }
+
+ if (wait2 || ptottime < swaptime || turbo || noskip) break;
+ ptottime -= swaptime;
+ }
+ if (picture == 0 && sstep) {
+ if (next < 0) picture = picsbase->last;
+ else if (next > 0) picture = picsbase->first;
+ }
+ }
+ if (go == FALSE) break;
+ }
+ }
+ picture = picsbase->first;
+ anim = NULL;
+ while (picture) {
+ if (picture && picture->anim && (anim != picture->anim)) {
+ // to prevent divx crashes
+ anim = picture->anim;
+ IMB_close_anim(anim);
+ }
+ if(picture->ibuf) IMB_freeImBuf(picture->ibuf);
+ if(picture->mem) MEM_freeN(picture->mem);
+
+ picture = picture->next;
+ }
+#ifdef WITH_QUICKTIME
+#if defined (_WIN32) || defined (__APPLE__)
+ if(G.have_quicktime) {
+ ExitMovies();
+#ifdef _WIN32
+ TerminateQTML();
+#endif /* _WIN32 */
+ }
+#endif /* _WIN32 || __APPLE__ */
+#endif /* WITH_QUICKTIME */
+
+ /* cleanup */
+ if(ibuf) IMB_freeImBuf(ibuf);
+ BLI_freelistN(picsbase);
+ free_blender();
+ window_destroy(g_window);
+
+ if(totblock!=0) {
+ printf("Error Totblock: %d\n",totblock);
+ MEM_printmemlist();
+ }
+}
diff --git a/source/blender/src/poseobject.c b/source/blender/src/poseobject.c
new file mode 100644
index 00000000000..faae6bd0da4
--- /dev/null
+++ b/source/blender/src/poseobject.c
@@ -0,0 +1,963 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Ton Roosendaal, Blender Foundation '05, full recode.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ * support for animation modes - Reevan McKay
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+
+#include "DNA_action_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_blender.h"
+#include "BKE_constraint.h"
+#include "BKE_deform.h"
+#include "BKE_depsgraph.h"
+#include "BKE_displist.h"
+#include "BKE_global.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_editarmature.h"
+#include "BIF_editaction.h"
+#include "BIF_editconstraint.h"
+#include "BIF_editdeform.h"
+#include "BIF_gl.h"
+#include "BIF_graphics.h"
+#include "BIF_interface.h"
+#include "BIF_poseobject.h"
+#include "BIF_space.h"
+#include "BIF_toolbox.h"
+#include "BIF_screen.h"
+
+#include "BDR_editobject.h"
+
+#include "BSE_edit.h"
+#include "BSE_editipo.h"
+#include "BSE_trans_types.h"
+
+#include "mydevice.h"
+#include "blendef.h"
+
+void enter_posemode(void)
+{
+ Base *base;
+ Object *ob;
+ bArmature *arm;
+
+ if(G.scene->id.lib) return;
+ base= BASACT;
+ if(base==NULL) return;
+
+ ob= base->object;
+
+ if (ob->id.lib){
+ error ("Can't pose libdata");
+ return;
+ }
+
+ switch (ob->type){
+ case OB_ARMATURE:
+ arm= get_armature(ob);
+ if( arm==NULL ) return;
+
+ ob->flag |= OB_POSEMODE;
+ base->flag= ob->flag;
+
+ allqueue(REDRAWHEADERS, 0);
+ allqueue(REDRAWBUTSALL, 0);
+ allqueue(REDRAWOOPS, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+ default:
+ return;
+ }
+
+ if (G.obedit) exit_editmode(EM_FREEDATA|EM_WAITCURSOR);
+ G.f &= ~(G_VERTEXPAINT | G_TEXTUREPAINT | G_WEIGHTPAINT);
+}
+
+void set_pose_keys (Object *ob)
+{
+ bArmature *arm= ob->data;
+ bPoseChannel *chan;
+
+ if (ob->pose){
+ for (chan=ob->pose->chanbase.first; chan; chan=chan->next){
+ Bone *bone= chan->bone;
+ if(bone && (bone->flag & BONE_SELECTED) && (arm->layer & bone->layer)) {
+ chan->flag |= POSE_KEY;
+ }
+ else {
+ chan->flag &= ~POSE_KEY;
+ }
+ }
+ }
+}
+
+
+void exit_posemode(void)
+{
+ Object *ob= OBACT;
+ Base *base= BASACT;
+
+ if(ob==NULL) return;
+
+ ob->flag &= ~OB_POSEMODE;
+ base->flag= ob->flag;
+
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWOOPS, 0);
+ allqueue(REDRAWHEADERS, 0);
+ allqueue(REDRAWBUTSALL, 0);
+
+ scrarea_queue_headredraw(curarea);
+}
+
+/* called by buttons to find a bone to display/edit values for */
+bPoseChannel *get_active_posechannel (Object *ob)
+{
+ bArmature *arm= ob->data;
+ bPoseChannel *pchan;
+
+ /* find active */
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ if(pchan->bone && (pchan->bone->flag & BONE_ACTIVE) && (pchan->bone->layer & arm->layer))
+ return pchan;
+ }
+
+ return NULL;
+}
+
+/* if a selected or active bone is protected, throw error and return 1 */
+/* only_selected==1 : the active bone is allowed to be protected */
+static int pose_has_protected_selected(Object *ob, int only_selected)
+{
+
+ /* check protection */
+ if(ob->proxy) {
+ bPoseChannel *pchan;
+ bArmature *arm= ob->data;
+
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ if(pchan->bone && (pchan->bone->layer & arm->layer)) {
+ if(pchan->bone->layer & arm->layer_protected) {
+ if(only_selected && (pchan->bone->flag & BONE_ACTIVE));
+ else if(pchan->bone->flag & (BONE_ACTIVE|BONE_SELECTED))
+ break;
+ }
+ }
+ }
+ if(pchan) {
+ error("Cannot change Proxy protected bones");
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* only for real IK, not for auto-IK */
+int pose_channel_in_IK_chain(Object *ob, bPoseChannel *pchan)
+{
+ bConstraint *con;
+ Bone *bone;
+
+ for(con= pchan->constraints.first; con; con= con->next) {
+ if(con->type==CONSTRAINT_TYPE_KINEMATIC) {
+ bKinematicConstraint *data= con->data;
+ if((data->flag & CONSTRAINT_IK_AUTO)==0)
+ return 1;
+ }
+ }
+ for(bone= pchan->bone->childbase.first; bone; bone= bone->next) {
+ pchan= get_pose_channel(ob->pose, bone->name);
+ if(pchan && pose_channel_in_IK_chain(ob, pchan))
+ return 1;
+ }
+ return 0;
+}
+
+/* ********************************************** */
+
+/* for the object with pose/action: create path curves for selected bones */
+void pose_calculate_path(Object *ob)
+{
+ bArmature *arm;
+ bPoseChannel *pchan;
+ Base *base;
+ float *fp;
+ int cfra;
+ int sfra, efra;
+
+ if(ob==NULL || ob->pose==NULL)
+ return;
+ arm= ob->data;
+
+ /* version patch for older files here (do_versions patch too complicated) */
+ if ((arm->pathsf == 0) || (arm->pathef == 0)) {
+ arm->pathsf = SFRA;
+ arm->pathef = EFRA;
+ }
+ if (arm->pathsize == 0) {
+ arm->pathsize = 1;
+ }
+
+ /* set frame values */
+ cfra= CFRA;
+ sfra = arm->pathsf;
+ efra = arm->pathef;
+ if (efra<=sfra) return;
+
+ DAG_object_update_flags(G.scene, ob, screen_view3d_layers());
+
+ /* malloc the path blocks */
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ if(pchan->bone && (pchan->bone->flag & BONE_SELECTED)) {
+ if(arm->layer & pchan->bone->layer) {
+ pchan->pathlen= efra-sfra+1;
+ pchan->pathsf= sfra;
+ pchan->pathef= efra+1;
+ if(pchan->path)
+ MEM_freeN(pchan->path);
+ pchan->path= MEM_callocN(3*pchan->pathlen*sizeof(float), "pchan path");
+ }
+ }
+ }
+
+ for(CFRA=sfra; CFRA<=efra; CFRA++) {
+ /* do all updates */
+ for(base= FIRSTBASE; base; base= base->next) {
+ if(base->object->recalc) {
+ int temp= base->object->recalc;
+ object_handle_update(base->object);
+ base->object->recalc= temp;
+ }
+ }
+
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ if(pchan->bone && (pchan->bone->flag & BONE_SELECTED)) {
+ if(arm->layer & pchan->bone->layer) {
+ if(pchan->path) {
+ fp= pchan->path+3*(CFRA-sfra);
+
+ if (arm->pathflag & ARM_PATH_HEADS) {
+ VECCOPY(fp, pchan->pose_head);
+ }
+ else {
+ VECCOPY(fp, pchan->pose_tail);
+ }
+
+ Mat4MulVecfl(ob->obmat, fp);
+ }
+ }
+ }
+ }
+ }
+
+ CFRA= cfra;
+ allqueue(REDRAWVIEW3D, 0); /* recalc tags are still there */
+ allqueue(REDRAWBUTSEDIT, 0);
+}
+
+
+/* for the object with pose/action: clear all path curves */
+void pose_clear_paths(Object *ob)
+{
+ bPoseChannel *pchan;
+
+ if(ob==NULL || ob->pose==NULL)
+ return;
+
+ /* free the path blocks */
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ if(pchan->path) {
+ MEM_freeN(pchan->path);
+ pchan->path= NULL;
+ }
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+
+
+void pose_select_constraint_target(void)
+{
+ Object *ob= OBACT;
+ bArmature *arm= ob->data;
+ bPoseChannel *pchan;
+ bConstraint *con;
+
+ /* paranoia checks */
+ if (!ob && !ob->pose) return;
+ if (ob==G.obedit || (ob->flag & OB_POSEMODE)==0) return;
+
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ if (arm->layer & pchan->bone->layer) {
+ if (pchan->bone->flag & (BONE_ACTIVE|BONE_SELECTED)) {
+ for (con= pchan->constraints.first; con; con= con->next) {
+ bConstraintTypeInfo *cti= constraint_get_typeinfo(con);
+ ListBase targets = {NULL, NULL};
+ bConstraintTarget *ct;
+
+ if (cti && cti->get_constraint_targets) {
+ cti->get_constraint_targets(con, &targets);
+
+ for (ct= targets.first; ct; ct= ct->next) {
+ if ((ct->tar == ob) && (ct->subtarget[0])) {
+ bPoseChannel *pchanc= get_pose_channel(ob->pose, ct->subtarget);
+ if(pchanc)
+ pchanc->bone->flag |= BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL;
+ }
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(con, &targets, 1);
+ }
+ }
+ }
+ }
+ }
+
+ allqueue (REDRAWVIEW3D, 0);
+ allqueue (REDRAWBUTSOBJECT, 0);
+ allqueue (REDRAWOOPS, 0);
+
+ BIF_undo_push("Select constraint target");
+
+}
+
+/* context: active channel */
+void pose_special_editmenu(void)
+{
+ Object *ob= OBACT;
+ short nr;
+
+ /* paranoia checks */
+ if(!ob && !ob->pose) return;
+ if(ob==G.obedit || (ob->flag & OB_POSEMODE)==0) return;
+
+ nr= pupmenu("Specials%t|Select Constraint Target%x1|Flip Left-Right Names%x2|Calculate Paths%x3|Clear All Paths%x4|Clear User Transform %x5");
+ if(nr==1) {
+ pose_select_constraint_target();
+ }
+ else if(nr==2) {
+ pose_flip_names();
+ }
+ else if(nr==3) {
+ pose_calculate_path(ob);
+ }
+ else if(nr==4) {
+ pose_clear_paths(ob);
+ }
+ else if(nr==5) {
+ rest_pose(ob->pose);
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ BIF_undo_push("Clear User Transform Pose");
+ }
+}
+
+void pose_add_IK(void)
+{
+ Object *ob= OBACT;
+
+ /* paranoia checks */
+ if(!ob && !ob->pose) return;
+ if(ob==G.obedit || (ob->flag & OB_POSEMODE)==0) return;
+
+ add_constraint(1); /* 1 means only IK */
+}
+
+/* context: all selected channels */
+void pose_clear_IK(void)
+{
+ Object *ob= OBACT;
+ bArmature *arm= ob->data;
+ bPoseChannel *pchan;
+ bConstraint *con;
+ bConstraint *next;
+
+ /* paranoia checks */
+ if(!ob && !ob->pose) return;
+ if(ob==G.obedit || (ob->flag & OB_POSEMODE)==0) return;
+
+ if(pose_has_protected_selected(ob, 0))
+ return;
+
+ if(okee("Remove IK constraint(s)")==0) return;
+
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ if(arm->layer & pchan->bone->layer) {
+ if(pchan->bone->flag & (BONE_ACTIVE|BONE_SELECTED)) {
+
+ for(con= pchan->constraints.first; con; con= next) {
+ next= con->next;
+ if(con->type==CONSTRAINT_TYPE_KINEMATIC) {
+ BLI_remlink(&pchan->constraints, con);
+ free_constraint_data(con);
+ MEM_freeN(con);
+ }
+ }
+ pchan->constflag &= ~(PCHAN_HAS_IK|PCHAN_HAS_TARGET);
+ }
+ }
+ }
+
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); // and all its relations
+
+ allqueue (REDRAWVIEW3D, 0);
+ allqueue (REDRAWBUTSOBJECT, 0);
+ allqueue (REDRAWOOPS, 0);
+
+ BIF_undo_push("Remove IK constraint(s)");
+}
+
+void pose_clear_constraints(void)
+{
+ Object *ob= OBACT;
+ bArmature *arm= ob->data;
+ bPoseChannel *pchan;
+
+ /* paranoia checks */
+ if(!ob && !ob->pose) return;
+ if(ob==G.obedit || (ob->flag & OB_POSEMODE)==0) return;
+
+ if(pose_has_protected_selected(ob, 0))
+ return;
+
+ if(okee("Remove Constraints")==0) return;
+
+ /* find active */
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ if(arm->layer & pchan->bone->layer) {
+ if(pchan->bone->flag & (BONE_ACTIVE|BONE_SELECTED)) {
+ free_constraints(&pchan->constraints);
+ pchan->constflag= 0;
+ }
+ }
+ }
+
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); // and all its relations
+
+ allqueue (REDRAWVIEW3D, 0);
+ allqueue (REDRAWBUTSOBJECT, 0);
+ allqueue (REDRAWOOPS, 0);
+
+ BIF_undo_push("Remove Constraint(s)");
+
+}
+
+
+void pose_copy_menu(void)
+{
+ Object *ob= OBACT;
+ bArmature *arm= ob->data;
+ bPoseChannel *pchan, *pchanact;
+ short nr;
+ int i=0;
+
+ /* paranoia checks */
+ if(!ob && !ob->pose) return;
+ if(ob==G.obedit || (ob->flag & OB_POSEMODE)==0) return;
+
+ /* find active */
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ if(pchan->bone->flag & BONE_ACTIVE) break;
+ }
+
+ if(pchan==NULL) return;
+
+ if(pose_has_protected_selected(ob, 1))
+ return;
+
+ pchanact= pchan;
+
+ i= BLI_countlist(&(pchanact->constraints)); /* if there are 24 or less, allow for the user to select constraints */
+ if (i<25)
+ nr= pupmenu("Copy Pose Attributes %t|Local Location%x1|Local Rotation%x2|Local Size%x3|%l|Visual Location %x9|Visual Rotation%x10|Visual Size%x11|%l|Constraints (All)%x4|Constraints...%x5|%l|Transform Locks%x6|IK Limits%x7|Bone Shape%x8");
+ else
+ nr= pupmenu("Copy Pose Attributes %t|Local Location%x1|Local Rotation%x2|Local Size%x3|%l|Visual Location %x9|Visual Rotation%x10|Visual Size%x11|%l|Constraints (All)%x4|%l|Transform Locks%x6|IK Limits%x7|Bone Shape%x8");
+
+ if(nr==-1) return;
+ if(nr!=5) {
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ if( (arm->layer & pchan->bone->layer) &&
+ (pchan->bone->flag & BONE_SELECTED) &&
+ (pchan!=pchanact)
+ ) {
+ switch (nr) {
+ case 1: /* Local Location */
+ VECCOPY(pchan->loc, pchanact->loc);
+ break;
+ case 2: /* Local Rotation */
+ QUATCOPY(pchan->quat, pchanact->quat);
+ break;
+ case 3: /* Local Size */
+ VECCOPY(pchan->size, pchanact->size);
+ break;
+ case 4: /* All Constraints */
+ {
+ free_constraints(&pchan->constraints);
+ copy_constraints(&pchan->constraints, &pchanact->constraints);
+ pchan->constflag = pchanact->constflag;
+ }
+ break;
+ case 6: /* Transform Locks */
+ pchan->protectflag = pchanact->protectflag;
+ break;
+ case 7: /* IK (DOF) settings */
+ {
+ pchan->ikflag = pchanact->ikflag;
+ VECCOPY(pchan->limitmin, pchanact->limitmin);
+ VECCOPY(pchan->limitmax, pchanact->limitmax);
+ VECCOPY(pchan->stiffness, pchanact->stiffness);
+ pchan->ikstretch= pchanact->ikstretch;
+ }
+ break;
+ case 8: /* Custom Bone Shape */
+ pchan->custom = pchanact->custom;
+ break;
+ case 9: /* Visual Location */
+ armature_loc_pose_to_bone(pchan, pchanact->pose_mat[3], pchan->loc);
+ break;
+ case 10: /* Visual Rotation */
+ {
+ float delta_mat[4][4], quat[4];
+
+ armature_mat_pose_to_bone(pchan, pchanact->pose_mat, delta_mat);
+ Mat4ToQuat(delta_mat, quat);
+ QUATCOPY(pchan->quat, quat);
+ }
+ break;
+ case 11: /* Visual Size */
+ {
+ float delta_mat[4][4], size[4];
+
+ armature_mat_pose_to_bone(pchan, pchanact->pose_mat, delta_mat);
+ Mat4ToSize(delta_mat, size);
+ VECCOPY(pchan->size, size);
+ }
+ }
+ }
+ }
+ } else { /* constraints, optional */
+ bConstraint *con, *con_back;
+ int const_toggle[24];
+ ListBase const_copy={0, 0};
+
+ duplicatelist (&const_copy, &(pchanact->constraints));
+
+ /* build the puplist of constraints */
+ for (con = pchanact->constraints.first, i=0; con; con=con->next, i++){
+ const_toggle[i]= 1;
+ add_numbut(i, TOG|INT, con->name, 0, 0, &(const_toggle[i]), "");
+ }
+
+ if (!do_clever_numbuts("Select Constraints", i, REDRAW)) {
+ BLI_freelistN(&const_copy);
+ return;
+ }
+
+ /* now build a new listbase from the options selected */
+ for (i=0, con=const_copy.first; con; i++) {
+ if (!const_toggle[i]) {
+ con_back= con->next;
+ BLI_freelinkN(&const_copy, con);
+ con= con_back;
+ } else {
+ con= con->next;
+ }
+ }
+
+ /* Copy the temo listbase to the selected posebones */
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ if( (arm->layer & pchan->bone->layer) &&
+ (pchan->bone->flag & BONE_SELECTED) &&
+ (pchan!=pchanact)
+ ) {
+ free_constraints(&pchan->constraints);
+ copy_constraints(&pchan->constraints, &const_copy);
+ pchan->constflag = pchanact->constflag;
+ }
+ }
+ BLI_freelistN(&const_copy);
+ update_pose_constraint_flags(ob->pose); /* we could work out the flags but its simpler to do this */
+ }
+
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); // and all its relations
+
+ allqueue (REDRAWVIEW3D, 0);
+ allqueue (REDRAWBUTSOBJECT, 0);
+ allqueue (REDRAWOOPS, 0);
+
+ BIF_undo_push("Copy Pose Attributes");
+
+}
+
+/* ******************** copy/paste pose ********************** */
+
+static bPose *g_posebuf=NULL;
+
+void free_posebuf(void)
+{
+ if (g_posebuf) {
+ // was copied without constraints
+ BLI_freelistN (&g_posebuf->chanbase);
+ MEM_freeN (g_posebuf);
+ }
+ g_posebuf=NULL;
+}
+
+void copy_posebuf (void)
+{
+ Object *ob= OBACT;
+
+ if (!ob || !ob->pose){
+ error ("No Pose");
+ return;
+ }
+
+ free_posebuf();
+
+ set_pose_keys(ob); // sets chan->flag to POSE_KEY if bone selected
+ copy_pose(&g_posebuf, ob->pose, 0);
+
+}
+
+void paste_posebuf (int flip)
+{
+ Object *ob= OBACT;
+ bPoseChannel *chan, *pchan;
+ float eul[4];
+ char name[32];
+
+ if (!ob || !ob->pose)
+ return;
+
+ if (!g_posebuf){
+ error ("Copy buffer is empty");
+ return;
+ }
+
+ /*
+ // disabled until protected bones in proxies follow the rules everywhere else!
+ if(pose_has_protected_selected(ob, 1))
+ return;
+ */
+
+ /* Safely merge all of the channels in this pose into
+ any existing pose */
+ for (chan=g_posebuf->chanbase.first; chan; chan=chan->next) {
+ if (chan->flag & POSE_KEY) {
+ BLI_strncpy(name, chan->name, sizeof(name));
+ if (flip)
+ bone_flip_name (name, 0); // 0 = don't strip off number extensions
+
+ /* only copy when channel exists, poses are not meant to add random channels to anymore */
+ pchan= get_pose_channel(ob->pose, name);
+
+ if (pchan) {
+ /* only loc rot size */
+ /* only copies transform info for the pose */
+ VECCOPY(pchan->loc, chan->loc);
+ VECCOPY(pchan->size, chan->size);
+ QUATCOPY(pchan->quat, chan->quat);
+ pchan->flag= chan->flag;
+
+ if (flip) {
+ pchan->loc[0]*= -1;
+
+ QuatToEul(pchan->quat, eul);
+ eul[1]*= -1;
+ eul[2]*= -1;
+ EulToQuat(eul, pchan->quat);
+ }
+
+ if (G.flags & G_RECORDKEYS) {
+ ID *id= &ob->id;
+
+ /* Set keys on pose */
+ if (chan->flag & POSE_ROT) {
+ insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_X, 0);
+ insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_Y, 0);
+ insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_Z, 0);
+ insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_W, 0);
+ }
+ if (chan->flag & POSE_SIZE) {
+ insertkey(id, ID_PO, pchan->name, NULL, AC_SIZE_X, 0);
+ insertkey(id, ID_PO, pchan->name, NULL, AC_SIZE_Y, 0);
+ insertkey(id, ID_PO, pchan->name, NULL, AC_SIZE_Z, 0);
+ }
+ if (chan->flag & POSE_LOC) {
+ insertkey(id, ID_PO, pchan->name, NULL, AC_LOC_X, 0);
+ insertkey(id, ID_PO, pchan->name, NULL, AC_LOC_Y, 0);
+ insertkey(id, ID_PO, pchan->name, NULL, AC_LOC_Z, 0);
+ }
+
+ /* clear any unkeyed tags */
+ if (chan->bone)
+ chan->bone->flag &= ~BONE_UNKEYED;
+ }
+ else {
+ /* add unkeyed tags */
+ if (chan->bone)
+ chan->bone->flag |= BONE_UNKEYED;
+ }
+ }
+ }
+ }
+
+ /* Update event for pose and deformation children */
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+
+ if (G.flags & G_RECORDKEYS) {
+ remake_action_ipos(ob->action);
+ allqueue (REDRAWIPO, 0);
+ allqueue (REDRAWVIEW3D, 0);
+ allqueue (REDRAWACTION, 0);
+ allqueue(REDRAWNLA, 0);
+ }
+ else {
+ /* need to trick depgraph, action is not allowed to execute on pose */
+ where_is_pose(ob);
+ ob->recalc= 0;
+ }
+
+ BIF_undo_push("Paste Action Pose");
+}
+
+/* ********************************************** */
+
+/* context weightpaint and deformer in posemode */
+void pose_adds_vgroups(Object *meshobj, int heatweights)
+{
+ extern VPaint Gwp; /* from vpaint */
+ Object *poseobj= modifiers_isDeformedByArmature(meshobj);
+
+ if(poseobj==NULL || (poseobj->flag & OB_POSEMODE)==0) {
+ error("The active object must have a deforming armature in pose mode");
+ return;
+ }
+
+ add_verts_to_dgroups(meshobj, poseobj, heatweights, (Gwp.flag & VP_MIRROR_X));
+
+ if(heatweights)
+ BIF_undo_push("Apply Bone Heat Weights to Vertex Groups");
+ else
+ BIF_undo_push("Apply Bone Envelopes to Vertex Groups");
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+
+ // and all its relations
+ DAG_object_flush_update(G.scene, meshobj, OB_RECALC_DATA);
+}
+
+/* ********************************************** */
+
+/* context active object */
+void pose_flip_names(void)
+{
+ Object *ob= OBACT;
+ bArmature *arm= ob->data;
+ bPoseChannel *pchan;
+ char newname[32];
+
+ /* paranoia checks */
+ if(!ob && !ob->pose) return;
+ if(ob==G.obedit || (ob->flag & OB_POSEMODE)==0) return;
+
+ if(pose_has_protected_selected(ob, 0))
+ return;
+
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ if(arm->layer & pchan->bone->layer) {
+ if(pchan->bone->flag & (BONE_ACTIVE|BONE_SELECTED)) {
+ BLI_strncpy(newname, pchan->name, sizeof(newname));
+ bone_flip_name(newname, 1); // 1 = do strip off number extensions
+ armature_bone_rename(ob->data, pchan->name, newname);
+ }
+ }
+ }
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWBUTSOBJECT, 0);
+ allqueue (REDRAWACTION, 0);
+ allqueue(REDRAWOOPS, 0);
+ BIF_undo_push("Flip names");
+
+}
+
+/* context active object, or weightpainted object with armature in posemode */
+void pose_activate_flipped_bone(void)
+{
+ Object *ob= OBACT;
+ bArmature *arm= ob->data;
+
+ if(ob==NULL) return;
+
+ if(G.f & G_WEIGHTPAINT) {
+ ob= modifiers_isDeformedByArmature(ob);
+ }
+ if(ob && (ob->flag & OB_POSEMODE)) {
+ bPoseChannel *pchan, *pchanf;
+
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ if(arm->layer & pchan->bone->layer) {
+ if(pchan->bone->flag & BONE_ACTIVE)
+ break;
+ }
+ }
+ if(pchan) {
+ char name[32];
+
+ BLI_strncpy(name, pchan->name, 32);
+ bone_flip_name(name, 1); // 0 = do not strip off number extensions
+
+ pchanf= get_pose_channel(ob->pose, name);
+ if(pchanf && pchanf!=pchan) {
+ pchan->bone->flag &= ~(BONE_SELECTED|BONE_ACTIVE);
+ pchanf->bone->flag |= (BONE_SELECTED|BONE_ACTIVE);
+
+ /* in weightpaint we select the associated vertex group too */
+ if(G.f & G_WEIGHTPAINT) {
+ vertexgroup_select_by_name(OBACT, name);
+ DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA);
+ }
+
+ select_actionchannel_by_name(ob->action, name, 1);
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWIPO, 0); /* To force action/constraint ipo update */
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWBUTSOBJECT, 0);
+ allqueue(REDRAWOOPS, 0);
+ }
+ }
+ }
+}
+
+/* This function pops up the move-to-layer popup widgets when the user
+ * presses either SHIFT-MKEY or MKEY in PoseMode OR EditMode (for Armatures)
+ */
+void pose_movetolayer(void)
+{
+ Object *ob= OBACT;
+ bArmature *arm;
+ short lay= 0;
+
+ if (ob==NULL) return;
+ arm= ob->data;
+
+ if (G.qual & LR_SHIFTKEY) {
+ /* armature layers */
+ lay= arm->layer;
+ if ( movetolayer_short_buts(&lay, "Armature Layers")==0 ) return;
+ if (lay==0) return;
+ arm->layer= lay;
+ if(ob->pose)
+ ob->pose->proxy_layer= lay;
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ }
+ else if (G.obedit) {
+ /* the check for editbone layer moving needs to occur before posemode one to work */
+ EditBone *ebo;
+
+ for (ebo= G.edbo.first; ebo; ebo= ebo->next) {
+ if (arm->layer & ebo->layer) {
+ if (ebo->flag & BONE_SELECTED)
+ lay |= ebo->layer;
+ }
+ }
+ if (lay==0) return;
+
+ if ( movetolayer_short_buts(&lay, "Bone Layers")==0 ) return;
+ if (lay==0) return;
+
+ for (ebo= G.edbo.first; ebo; ebo= ebo->next) {
+ if (arm->layer & ebo->layer) {
+ if (ebo->flag & BONE_SELECTED)
+ ebo->layer= lay;
+ }
+ }
+
+ BIF_undo_push("Move Bone Layer");
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ }
+ else if (ob->flag & OB_POSEMODE) {
+ /* pose-channel layers */
+ bPoseChannel *pchan;
+
+ if (pose_has_protected_selected(ob, 0))
+ return;
+
+ for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ if (arm->layer & pchan->bone->layer) {
+ if (pchan->bone->flag & BONE_SELECTED)
+ lay |= pchan->bone->layer;
+ }
+ }
+ if (lay==0) return;
+
+ if ( movetolayer_short_buts(&lay, "Bone Layers")==0 ) return;
+ if (lay==0) return;
+
+ for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ if (arm->layer & pchan->bone->layer) {
+ if (pchan->bone->flag & BONE_SELECTED)
+ pchan->bone->layer= lay;
+ }
+ }
+
+ BIF_undo_push("Move Bone Layer");
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ }
+}
diff --git a/source/blender/src/preview.blend.c b/source/blender/src/preview.blend.c
new file mode 100644
index 00000000000..b88d16c5699
--- /dev/null
+++ b/source/blender/src/preview.blend.c
@@ -0,0 +1,14367 @@
+/* DataToC output of file <preview_blend> */
+
+int datatoc_preview_blend_size= 459544;
+char datatoc_preview_blend[]= {
+ 66, 76, 69, 78, 68, 69, 82, 95, 86, 50, 52, 50, 82, 69, 78, 68, 0, 0, 0, 32,191,255,236,148,
+ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 20,112,114,101,118,105,101,119, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 71, 76, 79, 66, 0, 0, 0, 32,191,255,235,240, 0, 0, 0,139, 0, 0, 0, 1, 32, 32, 32, 52,
+ 0, 4, 0, 0, 0,240, 0, 0, 0, 1, 1, 0, 2,236, 30,176, 5, 30,236, 32, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 83, 82,
+ 0, 0, 0,120, 2,236, 30,176, 0, 0, 0,134, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 83, 82,115, 99,114,101,101,110, 0, 45, 83, 99,114,105,112,116,105,110,103, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 2,235, 18,144, 2,236, 32, 16, 2,236, 32, 80, 2,236, 34,208, 2,236, 35, 16, 2,236,136,160, 5, 30,236, 32,
+ 0, 0, 4,198, 0, 49, 3, 84, 4,199, 3, 36, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 20, 2,235, 18,144, 0, 0, 0,135, 0, 0, 0, 1, 2,235,137,224,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 20, 2,235,137,224, 0, 0, 0,135,
+ 0, 0, 0, 1, 2,235, 63,144, 2,235, 18,144, 0, 0, 0, 0, 0, 0, 3, 36, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 20,
+ 2,235, 63,144, 0, 0, 0,135, 0, 0, 0, 1, 2,228,196,160, 2,235,137,224, 0, 0, 0, 0, 4,199, 3, 36, 0, 0, 0, 0,
+ 68, 65, 84, 65, 0, 0, 0, 20, 2,228,196,160, 0, 0, 0,135, 0, 0, 0, 1, 2,236, 31, 80, 2,235, 63,144, 0, 0, 0, 0,
+ 4,199, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 20, 2,236, 31, 80, 0, 0, 0,135, 0, 0, 0, 1, 2,236, 31,144,
+ 2,228,196,160, 0, 0, 0, 0, 0, 0, 3, 10, 0, 0, 0, 1, 68, 65, 84, 65, 0, 0, 0, 20, 2,236, 31,144, 0, 0, 0,135,
+ 0, 0, 0, 1, 2,236, 31,208, 2,236, 31, 80, 0, 0, 0, 0, 4,199, 3, 10, 0, 0, 0, 1, 68, 65, 84, 65, 0, 0, 0, 20,
+ 2,236, 31,208, 0, 0, 0,135, 0, 0, 0, 1, 2,236, 32, 16, 2,236, 31,144, 0, 0, 0, 0, 3,208, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65, 0, 0, 0, 20, 2,236, 32, 16, 0, 0, 0,135, 0, 0, 0, 1, 0, 0, 0, 0, 2,236, 31,208, 0, 0, 0, 0,
+ 3,208, 3, 10, 0, 0, 0, 1, 68, 65, 84, 65, 0, 0, 0, 24, 2,236, 32, 80, 0, 0, 0,136, 0, 0, 0, 1, 2,236, 32,144,
+ 0, 0, 0, 0, 2,235, 63,144, 2,235,137,224, 0, 1, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 24, 2,236, 32,144,
+ 0, 0, 0,136, 0, 0, 0, 1, 2,236, 32,208, 2,236, 32, 80, 2,235,137,224, 2,236, 31, 80, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65, 0, 0, 0, 24, 2,236, 32,208, 0, 0, 0,136, 0, 0, 0, 1, 2,236, 33, 16, 2,236, 32,144, 2,235, 63,144,
+ 2,236, 31,144, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 24, 2,236, 33, 16, 0, 0, 0,136, 0, 0, 0, 1,
+ 2,236, 33, 80, 2,236, 32,208, 2,236, 31, 80, 2,236, 31,144, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 24,
+ 2,236, 33, 80, 0, 0, 0,136, 0, 0, 0, 1, 2,236, 33,144, 2,236, 33, 16, 2,228,196,160, 2,236, 31,208, 0, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 24, 2,236, 33,144, 0, 0, 0,136, 0, 0, 0, 1, 2,236, 33,208, 2,236, 33, 80,
+ 2,236, 31,144, 2,236, 32, 16, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 24, 2,236, 33,208, 0, 0, 0,136,
+ 0, 0, 0, 1, 2,236, 34, 16, 2,236, 33,144, 2,236, 31,208, 2,236, 32, 16, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+ 0, 0, 0, 24, 2,236, 34, 16, 0, 0, 0,136, 0, 0, 0, 1, 2,236, 34, 80, 2,236, 33,208, 2,228,196,160, 2,236, 31,144,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 24, 2,236, 34, 80, 0, 0, 0,136, 0, 0, 0, 1, 2,236, 34,144,
+ 2,236, 34, 16, 2,235, 18,144, 2,236, 31, 80, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 24, 2,236, 34,144,
+ 0, 0, 0,136, 0, 0, 0, 1, 2,236, 34,208, 2,236, 34, 80, 2,236, 31, 80, 2,236, 32, 16, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65, 0, 0, 0, 24, 2,236, 34,208, 0, 0, 0,136, 0, 0, 0, 1, 0, 0, 0, 0, 2,236, 34,144, 2,235, 18,144,
+ 2,236, 31,208, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,204, 2,236, 35, 16, 0, 0, 0,138, 0, 0, 0, 1,
+ 2,236, 79,160, 0, 0, 0, 0, 2,236, 31, 80, 2,235,137,224, 2,235, 63,144, 2,236, 31,144, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 4,199, 0, 0, 3, 11, 0, 0, 3, 36, 0, 0, 0, 0, 0, 0, 4,199, 0, 0, 3, 11, 0, 0, 3, 37, 0, 0, 0, 0,
+ 0, 0, 4,199, 0, 0, 3, 36, 0, 0, 3, 36, 0, 5, 0, 4, 0, 1, 7, 7, 4,200, 0, 1, 1, 0, 1, 0, 2,189, 0, 0,
+ 0, 7, 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, 2,237, 23,112,
+ 2,237, 23,112, 2,236, 36, 16, 2,236, 78,144, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 36, 16, 0, 0, 0,137, 0, 0, 0, 1,
+ 2,236, 37, 32, 0, 0, 0, 0, 79,117,116,112,117,116, 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, 82,101,110,100,101,114, 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, 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, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 37, 32, 0, 0, 0,137, 0, 0, 0, 1, 2,236, 38, 48, 2,236, 36, 16,
+ 82,101,110,100,101,114, 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,
+ 82,101,110,100,101,114, 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, 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,
+ 1, 70, 0, 0, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+ 0, 0, 0,228, 2,236, 38, 48, 0, 0, 0,137, 0, 0, 0, 1, 2,236, 39, 64, 2,236, 37, 32, 65,110,105,109, 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, 82,101,110,100,101,114, 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, 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, 2,140, 0, 0, 1, 62, 0,204,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 39, 64,
+ 0, 0, 0,137, 0, 0, 0, 1, 2,236, 40, 80, 2,236, 38, 48, 70,111,114,109, 97,116, 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, 82,101,110,100,101,114, 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, 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, 3,210, 0, 0, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 40, 80, 0, 0, 0,137, 0, 0, 0, 1,
+ 2,236, 41, 96, 2,236, 39, 64, 80,114,101,118,105,101,119, 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, 76, 97,109,112, 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, 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, 0, 0, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 41, 96, 0, 0, 0,137, 0, 0, 0, 1, 2,236, 42,112, 2,236, 40, 80,
+ 76, 97,109,112, 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,
+ 76, 97,109,112, 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, 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,
+ 1, 70, 0, 0, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+ 0, 0, 0,228, 2,236, 42,112, 0, 0, 0,137, 0, 0, 0, 1, 2,236, 43,128, 2,236, 41, 96, 83,104, 97,100,111,119, 32, 97,
+110,100, 32, 83,112,111,116, 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, 76, 97,109,112, 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, 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, 2,140, 0, 0, 1, 62, 0,204,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 43,128,
+ 0, 0, 0,137, 0, 0, 0, 1, 2,236, 44,144, 2,236, 42,112, 84,101,120,116,117,114,101, 32, 97,110,100, 32, 73,110,112,117,
+116, 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, 76, 97,109,112, 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, 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, 3,210, 0, 0, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 44,144, 0, 0, 0,137, 0, 0, 0, 1,
+ 2,236, 45,160, 2,236, 43,128, 77, 97,112, 32, 84,111, 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, 76, 97,109,112, 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, 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, 3,210, 0, 0, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 2,236, 43,128, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 45,160, 0, 0, 0,137, 0, 0, 0, 1, 2,236, 46,176, 2,236, 44,144,
+ 80,114,101,118,105,101,119, 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,
+ 77, 97,116,101,114,105, 97,108, 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, 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, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+ 0, 0, 0,228, 2,236, 46,176, 0, 0, 0,137, 0, 0, 0, 1, 2,236, 47,192, 2,236, 45,160, 76,105,110,107,115, 32, 97,110,
+100, 32, 80,105,112,101,108,105,110,101, 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, 77, 97,116,101,114,105, 97,108,
+ 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, 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, 1, 70, 0, 0, 1, 62, 0,204,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 47,192,
+ 0, 0, 0,137, 0, 0, 0, 1, 2,236, 48,208, 2,236, 46,176, 77, 97,116,101,114,105, 97,108, 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, 77, 97,116,101,114,105, 97,108, 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, 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, 2,140, 0, 0, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 48,208, 0, 0, 0,137, 0, 0, 0, 1,
+ 2,236, 49,224, 2,236, 47,192, 82, 97,109,112,115, 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, 77, 97,116,101,114,105, 97,108, 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, 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, 2,140, 0, 0, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 2,236, 47,192, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 49,224, 0, 0, 0,137, 0, 0, 0, 1, 2,236, 50,240, 2,236, 48,208,
+ 83,104, 97,100,101,114,115, 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,
+ 77, 97,116,101,114,105, 97,108, 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, 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,
+ 3,210, 0, 0, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,236, 50,240, 68, 65, 84, 65,
+ 0, 0, 0,228, 2,236, 50,240, 0, 0, 0,137, 0, 0, 0, 1, 2,236, 52, 0, 2,236, 49,224, 77,105,114,114,111,114, 32, 84,
+114, 97,110,115,112, 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, 77, 97,116,101,114,105, 97,108,
+ 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, 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, 3,210, 0, 0, 1, 62, 0,204,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 52, 0,
+ 0, 0, 0,137, 0, 0, 0, 1, 2,236, 53, 16, 2,236, 50,240, 84,101,120,116,117,114,101, 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, 77, 97,116,101,114,105, 97,108, 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, 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, 5, 24, 0, 0, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 53, 16, 0, 0, 0,137, 0, 0, 0, 1,
+ 2,236, 54, 32, 2,236, 52, 0, 77, 97,112, 32, 73,110,112,117,116, 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, 77, 97,116,101,114,105, 97,108, 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, 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, 5, 24, 0, 0, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 2,236, 52, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 54, 32, 0, 0, 0,137, 0, 0, 0, 1, 2,236, 55, 48, 2,236, 53, 16,
+ 77, 97,112, 32, 84,111, 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,
+ 77, 97,116,101,114,105, 97,108, 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, 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,
+ 5, 24, 0, 0, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,236, 52, 0, 68, 65, 84, 65,
+ 0, 0, 0,228, 2,236, 55, 48, 0, 0, 0,137, 0, 0, 0, 1, 2,236, 56, 64, 2,236, 54, 32, 76,105,110,107, 32, 97,110,100,
+ 32, 77, 97,116,101,114,105, 97,108,115, 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, 69,100,105,116,105,110,103, 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, 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, 1, 62, 0,204,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 56, 64,
+ 0, 0, 0,137, 0, 0, 0, 1, 2,236, 57, 80, 2,236, 55, 48, 77,101,115,104, 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, 69,100,105,116,105,110,103, 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, 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, 1, 70, 0, 0, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 57, 80, 0, 0, 0,137, 0, 0, 0, 1,
+ 2,236, 58, 96, 2,236, 56, 64, 77,111,100,105,102,105,101,114,115, 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, 69,100,105,116,105,110,103, 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, 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, 2,140, 0, 0, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 58, 96, 0, 0, 0,137, 0, 0, 0, 1, 2,236, 59,112, 2,236, 57, 80,
+ 83,104, 97,112,101,115, 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,
+ 69,100,105,116,105,110,103, 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, 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,
+ 2,140, 0, 0, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,236, 57, 80, 68, 65, 84, 65,
+ 0, 0, 0,228, 2,236, 59,112, 0, 0, 0,137, 0, 0, 0, 1, 2,236, 60,128, 2,236, 58, 96, 77,101,115,104, 32, 84,111,111,
+108,115, 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, 69,100,105,116,105,110,103, 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, 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, 3,210, 0, 0, 1, 62, 0,204,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 60,128,
+ 0, 0, 0,137, 0, 0, 0, 1, 2,236, 61,144, 2,236, 59,112, 77,101,115,104, 32, 84,111,111,108,115, 32, 49, 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, 69,100,105,116,105,110,103, 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, 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, 5, 24, 0, 0, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 61,144, 0, 0, 0,137, 0, 0, 0, 1,
+ 2,236, 62,160, 2,236, 60,128, 80,114,101,118,105,101,119, 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, 87,111,114,108,100, 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, 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, 0, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 62,160, 0, 0, 0,137, 0, 0, 0, 1, 2,236, 63,176, 2,236, 61,144,
+ 87,111,114,108,100, 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,
+ 87,111,114,108,100, 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, 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,
+ 1, 70, 0, 0, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+ 0, 0, 0,228, 2,236, 63,176, 0, 0, 0,137, 0, 0, 0, 1, 2,236, 64,192, 2,236, 62,160, 77,105,115,116, 32, 47, 32, 83,
+116, 97,114,115, 32, 47, 32, 80,104,121,115,105, 99,115, 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, 87,111,114,108,100, 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, 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, 2,140, 0, 0, 1, 62, 0,204,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 64,192,
+ 0, 0, 0,137, 0, 0, 0, 1, 2,236, 65,208, 2,236, 63,176, 65,109, 98, 32, 79, 99, 99, 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, 87,111,114,108,100, 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, 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, 2,140, 0, 0, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 2,236, 63,176, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 65,208, 0, 0, 0,137, 0, 0, 0, 1,
+ 2,236, 66,224, 2,236, 64,192, 84,101,120,116,117,114,101, 32, 97,110,100, 32, 73,110,112,117,116, 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, 87,111,114,108,100, 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, 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, 3,210, 0, 0, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 66,224, 0, 0, 0,137, 0, 0, 0, 1, 2,236, 67,240, 2,236, 65,208,
+ 77, 97,112, 32, 84,111, 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,
+ 87,111,114,108,100, 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, 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,
+ 3,210, 0, 0, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,236, 65,208, 68, 65, 84, 65,
+ 0, 0, 0,228, 2,236, 67,240, 0, 0, 0,137, 0, 0, 0, 1, 2,236, 69, 0, 2,236, 66,224, 80,114,101,118,105,101,119, 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, 84,101,120,116,117,114,101, 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, 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, 1, 62, 0,204,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 69, 0,
+ 0, 0, 0,137, 0, 0, 0, 1, 2,236, 70, 16, 2,236, 67,240, 84,101,120,116,117,114,101, 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, 84,101,120,116,117,114,101, 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, 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, 1, 70, 0, 0, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 70, 16, 0, 0, 0,137, 0, 0, 0, 1,
+ 2,236, 71, 32, 2,236, 69, 0, 67,111,108,111,114,115, 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, 84,101,120,116,117,114,101, 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, 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, 1, 70, 0, 0, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 2,236, 69, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 71, 32, 0, 0, 0,137, 0, 0, 0, 1, 2,236, 72, 48, 2,236, 70, 16,
+ 79, 98,106,101, 99,116, 32, 97,110,100, 32, 76,105,110,107,115, 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,
+ 79, 98,106,101, 99,116, 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, 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, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+ 0, 0, 0,228, 2,236, 72, 48, 0, 0, 0,137, 0, 0, 0, 1, 2,236, 73, 64, 2,236, 71, 32, 65,110,105,109, 32,115,101,116,
+116,105,110,103,115, 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, 79, 98,106,101, 99,116, 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, 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, 1, 70, 0, 0, 1, 62, 0,204,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 73, 64,
+ 0, 0, 0,137, 0, 0, 0, 1, 2,236, 74, 80, 2,236, 72, 48, 68,114, 97,119, 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, 79, 98,106,101, 99,116, 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, 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, 2,140, 0, 0, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 74, 80, 0, 0, 0,137, 0, 0, 0, 1,
+ 2,236, 75, 96, 2,236, 73, 64, 67,111,110,115,116,114, 97,105,110,116,115, 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, 79, 98,106,101, 99,116, 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, 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, 3,210, 0, 0, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 75, 96, 0, 0, 0,137, 0, 0, 0, 1, 2,236, 76,112, 2,236, 74, 80,
+ 67,108,111,117,100,115, 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,
+ 84,101,120,116,117,114,101, 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, 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,
+ 2,140, 0, 0, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+ 0, 0, 0,228, 2,236, 76,112, 0, 0, 0,137, 0, 0, 0, 1, 2,236, 77,128, 2,236, 75, 96, 83,116,117, 99, 99,105, 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, 84,101,120,116,117,114,101, 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, 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, 2,140, 0, 0, 1, 62, 0,204,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 77,128,
+ 0, 0, 0,137, 0, 0, 0, 1, 2,236, 78,144, 2,236, 76,112, 87,111,111,100, 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, 84,101,120,116,117,114,101, 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, 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, 2,140, 0, 0, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 78,144, 0, 0, 0,137, 0, 0, 0, 1,
+ 0, 0, 0, 0, 2,236, 77,128, 82,101,110,100,101,114, 32, 76, 97,121,101,114,115, 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, 82,101,110,100,101,114, 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, 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, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 2,236, 36, 16, 68, 65, 84, 65, 0, 0, 0,204, 2,236, 79,160, 0, 0, 0,138, 0, 0, 0, 1, 2,236,136,160, 2,236, 35, 16,
+ 2,236, 31,208, 2,236, 32, 16, 2,236, 31,144, 2,228,196,160, 0, 0, 0, 0, 63,140, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 65, 45, 68,171, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,191,128, 1, 80,
+191,128, 0, 0,128, 0, 0, 0,128, 0, 0, 0,188,163,215,226,128, 0, 0, 0, 0, 0, 3,209, 0, 0, 4,199, 0, 0, 0, 0,
+ 0, 0, 3, 9, 0, 0, 3,209, 0, 0, 4,199, 0, 0, 2,239, 0, 0, 3, 9, 0, 0, 3,209, 0, 0, 4,199, 0, 0, 0, 0,
+ 0, 0, 2,238, 0, 7, 0, 6, 0, 2, 4, 4, 0,247, 2,239, 1, 0, 1, 0, 1,136, 0, 68, 0, 7, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,236,127, 96, 2,236,135, 16, 2,232,159,176, 2,232,206,176, 2,236, 80,160,
+ 2,232,193, 80, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 80,160, 0, 0, 0,137, 0, 0, 0, 1, 2,236, 81,176, 0, 0, 0, 0,
+ 84,114, 97,110,115,102,111,114,109, 32, 80,114,111,112,101,114,116,105,101,115, 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,
+ 73,112,111, 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, 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, 33, 0,167, 1, 62, 0,204, 0, 0, 0, 0, 0,162, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+ 0, 0, 0,228, 2,236, 81,176, 0, 0, 0,137, 0, 0, 0, 1, 2,236, 82,192, 2,236, 80,160, 79,117,116,112,117,116, 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, 82,101,110,100,101,114, 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, 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, 1, 62, 0,204,
+ 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 2,236,114,160, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 82,192,
+ 0, 0, 0,137, 0, 0, 0, 1, 2,236, 83,208, 2,236, 81,176, 82,101,110,100,101,114, 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, 82,101,110,100,101,114, 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, 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,255, 24, 1, 62, 0,204, 0, 0, 0, 1, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 83,208, 0, 0, 0,137, 0, 0, 0, 1,
+ 2,236, 84,224, 2,236, 82,192, 65,110,105,109, 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, 82,101,110,100,101,114, 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, 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,254, 48, 1, 62, 0,204, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13,
+ 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 84,224, 0, 0, 0,137, 0, 0, 0, 1, 2,236, 85,240, 2,236, 83,208,
+ 70,111,114,109, 97,116, 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,
+ 82,101,110,100,101,114, 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, 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,253, 72, 1, 62, 0,204, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 68, 65, 84, 65,
+ 0, 0, 0,228, 2,236, 85,240, 0, 0, 0,137, 0, 0, 0, 1, 2,236, 87, 0, 2,236, 84,224, 76,105,110,107, 32, 97,110,100,
+ 32, 77, 97,116,101,114,105, 97,108,115, 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, 69,100,105,116,105,110,103, 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, 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, 1, 62, 0,204,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 87, 0,
+ 0, 0, 0,137, 0, 0, 0, 1, 2,236, 88, 16, 2,236, 85,240, 67, 97,109,101,114, 97, 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, 69,100,105,116,105,110,103, 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, 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, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 88, 16, 0, 0, 0,137, 0, 0, 0, 1,
+ 2,236, 89, 32, 2,236, 87, 0, 80,114,101,118,105,101,119, 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, 76, 97,109,112, 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, 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, 0, 0, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 89, 32, 0, 0, 0,137, 0, 0, 0, 1, 2,236, 90, 48, 2,236, 88, 16,
+ 76, 97,109,112, 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,
+ 76, 97,109,112, 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, 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,255, 24, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+ 0, 0, 0,228, 2,236, 90, 48, 0, 0, 0,137, 0, 0, 0, 1, 2,236, 91, 64, 2,236, 89, 32, 83,104, 97,100,111,119, 32, 97,
+110,100, 32, 83,112,111,116, 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, 76, 97,109,112, 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, 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,254, 48, 1, 62, 0,204,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 91, 64,
+ 0, 0, 0,137, 0, 0, 0, 1, 2,236, 92, 80, 2,236, 90, 48, 84,101,120,116,117,114,101, 32, 97,110,100, 32, 73,110,112,117,
+116, 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, 76, 97,109,112, 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, 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,253, 72, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 92, 80, 0, 0, 0,137, 0, 0, 0, 1,
+ 2,236, 93, 96, 2,236, 91, 64, 77, 97,112, 32, 84,111, 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, 76, 97,109,112, 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, 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,253, 72, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 2,236, 91, 64, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 93, 96, 0, 0, 0,137, 0, 0, 0, 1, 2,236, 94,112, 2,236, 92, 80,
+ 77,101,115,104, 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,
+ 69,100,105,116,105,110,103, 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, 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,255, 24, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 68, 65, 84, 65,
+ 0, 0, 0,228, 2,236, 94,112, 0, 0, 0,137, 0, 0, 0, 1, 2,236, 95,128, 2,236, 93, 96, 77,111,100,105,102,105,101,114,
+115, 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, 69,100,105,116,105,110,103, 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, 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,253, 72, 1, 62, 0,204,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 95,128,
+ 0, 0, 0,137, 0, 0, 0, 1, 2,236, 96,144, 2,236, 94,112, 83,104, 97,112,101,115, 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, 69,100,105,116,105,110,103, 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, 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,253, 72, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 12, 2,236, 94,112, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 96,144, 0, 0, 0,137, 0, 0, 0, 1,
+ 2,236, 97,160, 2,236, 95,128, 77,101,115,104, 32, 84,111,111,108,115, 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, 69,100,105,116,105,110,103, 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, 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,253, 72, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 97,160, 0, 0, 0,137, 0, 0, 0, 1, 2,236, 98,176, 2,236, 96,144,
+ 77,101,115,104, 32, 84,111,111,108,115, 32, 49, 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,
+ 69,100,105,116,105,110,103, 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, 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,252, 96, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+ 0, 0, 0,228, 2,236, 98,176, 0, 0, 0,137, 0, 0, 0, 1, 2,236, 99,192, 2,236, 97,160, 84,101,120,116,117,114,101, 32,
+102, 97, 99,101, 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, 69,100,105,116,105,110,103, 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, 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, 1, 62, 0,204,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,236, 99,192, 68, 65, 84, 65, 0, 0, 0,228, 2,236, 99,192,
+ 0, 0, 0,137, 0, 0, 0, 1, 2,236,100,208, 2,236, 98,176, 85, 86, 32, 67, 97,108, 99,117,108, 97,116,105,111,110, 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, 69,100,105,116,105,110,103, 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, 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, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236,100,208, 0, 0, 0,137, 0, 0, 0, 1,
+ 2,236,101,224, 2,236, 99,192, 80, 97,105,110,116, 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, 69,100,105,116,105,110,103, 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, 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,254, 48, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10,
+ 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236,101,224, 0, 0, 0,137, 0, 0, 0, 1, 2,236,102,240, 2,236,100,208,
+ 67,117,114,118,101, 32, 97,110,100, 32, 83,117,114,102, 97, 99,101, 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,
+ 69,100,105,116,105,110,103, 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, 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, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+ 0, 0, 0,228, 2,236,102,240, 0, 0, 0,137, 0, 0, 0, 1, 2,236,104, 0, 2,236,101,224, 67,117,114,118,101, 32, 84,111,
+111,108,115, 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, 69,100,105,116,105,110,103, 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, 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,255, 24, 1, 62, 0,204,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236,104, 0,
+ 0, 0, 0,137, 0, 0, 0, 1, 2,236,105, 16, 2,236,102,240, 67,117,114,118,101, 32, 84,111,111,108,115, 49, 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, 69,100,105,116,105,110,103, 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, 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,253, 72, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236,105, 16, 0, 0, 0,137, 0, 0, 0, 1,
+ 2,236,106, 32, 2,236,104, 0, 80,114,101,118,105,101,119, 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, 77, 97,116,101,114,105, 97,108, 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, 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, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236,106, 32, 0, 0, 0,137, 0, 0, 0, 1, 2,236,107, 48, 2,236,105, 16,
+ 76,105,110,107,115, 32, 97,110,100, 32, 80,105,112,101,108,105,110,101, 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,
+ 77, 97,116,101,114,105, 97,108, 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, 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,255, 24, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+ 0, 0, 0,228, 2,236,107, 48, 0, 0, 0,137, 0, 0, 0, 1, 2,236,108, 64, 2,236,106, 32, 77, 97,116,101,114,105, 97,108,
+ 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, 77, 97,116,101,114,105, 97,108,
+ 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, 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,254, 48, 1, 62, 0,204,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236,108, 64,
+ 0, 0, 0,137, 0, 0, 0, 1, 2,236,109, 80, 2,236,107, 48, 82, 97,109,112,115, 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, 77, 97,116,101,114,105, 97,108, 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, 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,254, 48, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 2,236,107, 48, 68, 65, 84, 65, 0, 0, 0,228, 2,236,109, 80, 0, 0, 0,137, 0, 0, 0, 1,
+ 2,236,110, 96, 2,236,108, 64, 83,104, 97,100,101,114,115, 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, 77, 97,116,101,114,105, 97,108, 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, 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,253, 72, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 2,236,110, 96, 68, 65, 84, 65, 0, 0, 0,228, 2,236,110, 96, 0, 0, 0,137, 0, 0, 0, 1, 2,236,111,112, 2,236,109, 80,
+ 77,105,114,114,111,114, 32, 84,114, 97,110,115,112, 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,
+ 77, 97,116,101,114,105, 97,108, 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, 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,253, 72, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+ 0, 0, 0,228, 2,236,111,112, 0, 0, 0,137, 0, 0, 0, 1, 2,236,112,128, 2,236,110, 96, 84,101,120,116,117,114,101, 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, 77, 97,116,101,114,105, 97,108,
+ 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, 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,252, 96, 1, 62, 0,204,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236,112,128,
+ 0, 0, 0,137, 0, 0, 0, 1, 2,236,113,144, 2,236,111,112, 77, 97,112, 32, 73,110,112,117,116, 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, 77, 97,116,101,114,105, 97,108, 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, 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,252, 96, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 2,236,111,112, 68, 65, 84, 65, 0, 0, 0,228, 2,236,113,144, 0, 0, 0,137, 0, 0, 0, 1,
+ 2,236,114,160, 2,236,112,128, 77, 97,112, 32, 84,111, 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, 77, 97,116,101,114,105, 97,108, 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, 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,252, 96, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 2,236,111,112, 68, 65, 84, 65, 0, 0, 0,228, 2,236,114,160, 0, 0, 0,137, 0, 0, 0, 1, 2,236,115,176, 2,236,113,144,
+ 82,101,110,100,101,114, 32, 76, 97,121,101,114,115, 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,
+ 82,101,110,100,101,114, 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, 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, 1, 62, 0,204, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 68, 65, 84, 65,
+ 0, 0, 0,228, 2,236,115,176, 0, 0, 0,137, 0, 0, 0, 1, 2,236,116,192, 2,236,114,160, 80,114,101,118,105,101,119, 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, 87,111,114,108,100, 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, 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,254, 48, 1, 62, 0,204,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236,116,192,
+ 0, 0, 0,137, 0, 0, 0, 1, 2,236,117,208, 2,236,115,176, 87,111,114,108,100, 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, 87,111,114,108,100, 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, 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,253, 72, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236,117,208, 0, 0, 0,137, 0, 0, 0, 1,
+ 2,236,118,224, 2,236,116,192, 77,105,115,116, 32, 47, 32, 83,116, 97,114,115, 32, 47, 32, 80,104,121,115,105, 99,115, 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, 87,111,114,108,100, 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, 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, 0, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236,118,224, 0, 0, 0,137, 0, 0, 0, 1, 2,236,119,240, 2,236,117,208,
+ 65,109, 98, 32, 79, 99, 99, 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,
+ 87,111,114,108,100, 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, 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, 0, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,236,117,208, 68, 65, 84, 65,
+ 0, 0, 0,228, 2,236,119,240, 0, 0, 0,137, 0, 0, 0, 1, 2,236,121, 0, 2,236,118,224, 84,101,120,116,117,114,101, 32,
+ 97,110,100, 32, 73,110,112,117,116, 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, 87,111,114,108,100, 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, 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,255, 24, 1, 62, 0,204,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236,121, 0,
+ 0, 0, 0,137, 0, 0, 0, 1, 2,236,122, 16, 2,236,119,240, 77, 97,112, 32, 84,111, 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, 87,111,114,108,100, 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, 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,255, 24, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 2,236,119,240, 68, 65, 84, 65, 0, 0, 0,228, 2,236,122, 16, 0, 0, 0,137, 0, 0, 0, 1,
+ 2,236,123, 32, 2,236,121, 0, 77,117,108,116,105,114,101,115, 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, 69,100,105,116,105,110,103, 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, 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,254, 48, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12,
+ 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236,123, 32, 0, 0, 0,137, 0, 0, 0, 1, 2,236,124, 48, 2,236,122, 16,
+ 79, 98,106,101, 99,116, 32, 97,110,100, 32, 76,105,110,107,115, 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,
+ 79, 98,106,101, 99,116, 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, 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, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+ 0, 0, 0,228, 2,236,124, 48, 0, 0, 0,137, 0, 0, 0, 1, 2,236,125, 64, 2,236,123, 32, 65,110,105,109, 32,115,101,116,
+116,105,110,103,115, 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, 79, 98,106,101, 99,116, 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, 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,255, 24, 1, 62, 0,204,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236,125, 64,
+ 0, 0, 0,137, 0, 0, 0, 1, 2,236,126, 80, 2,236,124, 48, 68,114, 97,119, 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, 79, 98,106,101, 99,116, 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, 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,254, 48, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236,126, 80, 0, 0, 0,137, 0, 0, 0, 1,
+ 2,232,193, 80, 2,236,125, 64, 67,111,110,115,116,114, 97,105,110,116,115, 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, 79, 98,106,101, 99,116, 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, 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,253, 72, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,232,193, 80, 0, 0, 0,137, 0, 0, 0, 1, 0, 0, 0, 0, 2,236,126, 80,
+ 66, 97,107,101, 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,
+ 82,101,110,100,101,114, 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, 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,254, 48, 1, 62, 0,204, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 2,236, 83,208, 68, 65, 84, 65,
+ 0, 0, 0,204, 2,236,127, 96, 0, 0, 0,118, 0, 0, 0, 1, 5, 30,228, 32, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0,
+ 2,236, 79,160, 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, 2, 0, 0,
+193, 0, 0, 0, 67,163, 0, 0,196,106, 0, 0, 67,104, 0, 0,194,173, 94,108, 67,202, 87,155,196,148,152,252, 67,152,156, 15,
+ 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, 67,128, 0, 0, 66, 40, 0, 0, 69, 0, 0, 0, 67,225, 0, 0,
+ 63, 0, 0, 0, 63,154,225, 72, 0, 0, 0, 1, 0, 1, 0, 1, 0,247, 2,239, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0,
+ 5, 30,236, 32,255,255, 0, 0, 0, 0, 0, 0, 1,150, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+ 0, 0, 3, 0, 5, 30,228, 32, 0, 0, 0,113, 0, 0, 0, 1, 2,236,128, 96, 2,236,127, 96, 0, 0, 0, 1, 63, 51, 51, 51,
+ 2,236, 79,160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,127,198, 52,188,166, 29,146, 61, 22,153, 97,
+ 0, 0, 0, 0, 61, 43,252, 13, 62,247, 11, 89,191, 95,248, 90, 0, 0, 0, 0, 52, 67,176,196, 63, 96, 42,246, 62,247, 67, 44,
+ 0, 0, 0, 0, 64, 78, 45, 74, 62,172, 87,201,194, 41,171, 79, 63,128, 0, 0, 63,127,198, 53, 61, 43,251,248, 52, 80, 0, 0,
+ 0, 0, 0, 0,188,166, 29,186, 62,247, 11,119, 63, 96, 43, 16, 0, 0, 0, 0, 61, 22,153, 99,191, 95,248,117, 62,247, 67, 75,
+ 0, 0, 0, 0,191,211,125,192,194, 21,161,185, 65,161,133, 59, 63,128, 0, 0, 63,139,224,100,190, 96,221, 21,189, 22,154,236,
+189, 22,153, 97, 61, 60, 27,174, 64,167, 52,239, 63, 95,250,166, 63, 95,248, 90, 52, 86, 9, 86, 65, 23,185, 41,190,247, 69,181,
+190,247, 67, 44, 64, 97,129,137, 64,105, 75, 27, 66, 41,152,145, 66, 41,171, 79, 63,105,225, 95, 61, 39,247, 84,186,185, 46,176,
+184,146,196,144,186,245,126,178, 61, 54,117, 48, 61,165,157, 23, 52,153,160, 0, 66,165, 56,225, 68,233,202,192,196,124, 94, 18,
+194, 71,254, 87,194,165, 77,102,196,233,177, 39, 68,124, 65,193, 66, 72, 0,101, 63,140, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 65, 45, 68,171, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,191,128, 1, 80,
+191,128, 0, 0,128, 0, 0, 0,128, 0, 0, 0,188,163,215,226,128, 0, 0, 0, 63,127,198, 52,188,166, 29,146, 61, 22,153, 97,
+ 0, 0, 0, 0, 61, 43,252, 13, 62,247, 11, 89,191, 95,248, 90, 0, 0, 0, 0, 52, 67,176,196, 63, 96, 42,246, 62,247, 67, 44,
+ 0, 0, 0, 0, 64, 78, 45, 74, 62,172, 87,201,194, 41,171, 79, 63,128, 0, 0, 63, 92, 99,141,191, 2, 35, 43,188, 46,238,188,
+188,148, 32, 94, 66, 25,240, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 5, 30,248, 32, 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, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0,
+255,226, 0, 0, 66, 12, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 58,124, 56, 68, 60, 35,215, 10, 67,250, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 64, 68, 77,201, 64,111, 66,228,191,205, 97,230, 60,149,191,128,191, 77,109,116, 63,230,165,248, 0, 20, 0, 0,
+ 0, 7, 0, 99, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,255,255, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 24, 24, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 1, 40, 2,236,128, 96, 0, 0, 0,117,
+ 0, 0, 0, 1, 2,236,129,176, 5, 30,228, 32, 0, 0, 0, 2, 63, 51, 51, 51, 2,236, 79,160, 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, 67,122, 0, 0,189,204,204,205, 63,140,204,205,
+ 63,128, 0, 0, 67,122, 0, 0,192,160, 0, 0, 64,160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 2,235,
+ 0, 0, 0, 16, 0, 0, 3,168, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 3,168, 0, 0, 0, 16, 0, 0, 2,235,
+ 60, 35,215, 10, 60, 35,215, 10, 70,106, 96, 0, 68,122, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 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, 5, 31, 16, 32, 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, 0, 0, 29, 0, 0,
+ 0, 0, 0, 0, 0, 0, 79, 66, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 67,122, 0, 0,189,204,204,205, 63,140,204,205, 68, 65, 84, 65, 0, 0, 0,120, 2,236,129,176, 0, 0, 0,124, 0, 0, 0, 1,
+ 2,236,130, 80, 2,236,128, 96, 0, 0, 0, 9, 63, 51, 51, 51, 2,236, 79,160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 2,236,183,112, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61,204,204,205, 0, 0, 0, 5, 0, 0, 0, 17,
+ 0, 0, 2,225, 0, 0, 2,227, 0, 0, 0, 5, 0, 0, 0, 17, 0, 0, 2,207, 0, 0, 2,227, 68, 65, 84, 65, 0, 0, 0,248,
+ 2,236,130, 80, 0, 0, 0,122, 0, 0, 0, 1, 2,236,131,112, 2,236,129,176, 0, 0, 0, 6, 63, 51, 51, 51, 2,236, 79,160,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67,128, 0, 0, 0, 0, 0, 0, 67,128, 0, 0,
+190,120, 0, 0, 63,159, 0, 0,190,242, 0, 0, 63,188,128, 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, 1,124, 0, 0, 0, 0, 0, 0, 1,242,
+ 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, 2, 0, 0,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,128, 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, 68, 65, 84, 65, 0, 0, 0,248, 2,236,131,112, 0, 0, 0,121, 0, 0, 0, 1, 2,236,132,144, 2,236,130, 80,
+ 0, 0, 0, 3, 63, 51, 51, 51, 2,236, 79,160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 67,182, 0, 0,195,209, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67,182, 0, 0,195,190, 0, 0,181, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 1,124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16,
+ 0, 0, 1,124, 0, 0, 0, 0, 0, 0, 1,124,195,190, 0, 0,195,190, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1,108, 1,124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,142,
+ 0, 1, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,160, 2,236,132,144, 0, 0, 0,194,
+ 0, 0, 0, 1, 2,236,133, 96, 2,236,131,112, 0, 0, 0, 11, 63, 51, 51, 51, 2,236, 79,160,192,128, 0, 0, 67,122, 0, 0,
+192,128, 0, 0, 67,127, 0, 0,192,128, 0, 0, 66, 72, 0, 0,192,128, 0, 0, 67,127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,124, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 1,124,
+ 0, 0, 0, 16, 0, 0, 1,124, 63,128, 0, 0, 67,129,128, 0, 70,250, 0, 0, 67,129,128, 0, 61,204,204,205, 65, 32, 0, 0,
+ 0, 8, 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, 68, 65, 84, 65, 0, 0, 0,164, 2,236,133, 96, 0, 0, 0,123, 0, 0, 0, 1, 2,236,134, 48, 2,236,132,144,
+ 0, 0, 0, 13, 63, 51, 51, 51, 2,236, 79,160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,128, 0, 0, 68,122, 0, 0, 0, 0, 0, 0, 68,122, 0, 0,192,160, 0, 0, 66,130, 0, 0, 0, 0, 0, 0,
+ 67,182, 0, 0, 0, 0, 1,108, 0, 0, 1,124, 0, 0, 0, 0, 0, 0, 1,124, 0, 0, 0,196, 0, 0, 1,108, 0, 0, 0, 0,
+ 0, 0, 0, 16, 0, 0, 0,196, 0, 0, 1,108, 0, 0, 0, 16, 0, 0, 1,124, 0, 0, 0, 0, 0, 0, 0, 0, 68,122, 0, 0,
+ 68,122, 0, 0, 61,204,204,205, 66, 72, 0, 0, 0, 10, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+ 0, 0, 0,176, 2,236,134, 48, 0, 0, 0,203, 0, 0, 0, 1, 2,236,135, 16, 2,236,133, 96, 0, 0, 0, 12, 63, 51, 51, 51,
+ 2,236, 79,160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,191, 0, 0, 0, 66, 2, 0, 0,193,128, 0, 0,
+ 67,247, 0, 0,191, 0, 0, 0, 66, 2, 0, 0,193,128, 0, 0, 67,247, 0, 0, 0, 0, 1,108, 0, 0, 1,124, 0, 0, 0, 0,
+ 0, 0, 2, 14, 0, 0, 0,128, 0, 0, 1,108, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0,128, 0, 0, 1,108, 0, 0, 0, 16,
+ 0, 0, 2, 14, 0, 0, 0, 0, 0, 0, 0, 0, 70,250, 0, 0, 68,122, 0, 0, 60, 35,215, 10, 66, 72, 0, 0, 0, 10, 0, 0,
+ 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65, 0, 0, 1,104, 2,236,135, 16, 0, 0, 0,120, 0, 0, 0, 1, 0, 0, 0, 0, 2,236,134, 48, 0, 0, 0, 5,
+ 63, 51, 51, 51, 2,236, 79,160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,150,
+ 83, 97,118,101, 32, 70,105,108,101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 85,115,101,114,115, 47,116,
+111,110, 47, 68,101,115,107,116,111,112, 47, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,112,114,101,118,105,101,119, 46,
+ 98,108,101,110,100, 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, 0, 0, 0, 0, 0, 8, 0, 82, 0, 0, 0, 0, 1, 76, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,255,255, 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, 68, 65, 84, 65,
+ 0, 0, 0,204, 2,236,136,160, 0, 0, 0,138, 0, 0, 0, 1, 0, 0, 0, 0, 2,236, 79,160, 2,235, 18,144, 2,236, 31, 80,
+ 2,236, 32, 16, 2,236, 31,208, 0, 0, 0, 0, 63, 79, 65,254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,134,173, 25, 0, 0, 0, 0, 0, 0, 0, 0,189, 60, 82,171,188,131, 1,211,191,153,211,206,191,128, 0, 0,128, 0, 0, 0,
+128, 0, 0, 0,193, 65,236,225,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,207, 0, 0, 0, 0, 0, 0, 3, 9, 0, 0, 0, 0,
+ 0, 0, 3,207, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 3,207, 0, 0, 0, 27, 0, 0, 3, 9, 0, 9, 0, 8,
+ 0, 1, 1, 1, 3,208, 2,239, 1, 0, 1, 0, 2,195, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 5, 30,232, 32, 2,236,159, 32, 2,232,189,144, 2,232,189,144, 2,236,137,160, 2,236,150, 96, 68, 65, 84, 65,
+ 0, 0, 0,228, 2,236,137,160, 0, 0, 0,137, 0, 0, 0, 1, 2,236,138,176, 0, 0, 0, 0, 84,114, 97,110,115,102,111,114,
+109, 32, 80,114,111,112,101,114,116,105,101,115, 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, 73,112,111, 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, 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, 33, 0,167, 1, 62, 0,204,
+ 0, 0, 0, 0, 0,162, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236,138,176,
+ 0, 0, 0,137, 0, 0, 0, 1, 2,236,139,192, 2,236,137,160, 79,117,116,112,117,116, 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, 82,101,110,100,101,114, 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, 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, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236,139,192, 0, 0, 0,137, 0, 0, 0, 1,
+ 2,236,140,208, 2,236,138,176, 82,101,110,100,101,114, 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, 82,101,110,100,101,114, 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, 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, 1, 64, 0, 0, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236,140,208, 0, 0, 0,137, 0, 0, 0, 1, 2,236,141,224, 2,236,139,192,
+ 65,110,105,109, 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,
+ 82,101,110,100,101,114, 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, 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,
+ 2,128, 0, 0, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+ 0, 0, 0,228, 2,236,141,224, 0, 0, 0,137, 0, 0, 0, 1, 2,236,142,240, 2,236,140,208, 70,111,114,109, 97,116, 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, 82,101,110,100,101,114, 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, 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, 3,192, 0, 0, 1, 62, 0,204,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236,142,240,
+ 0, 0, 0,137, 0, 0, 0, 1, 2,236,144, 0, 2,236,141,224, 76,105,110,107, 32, 97,110,100, 32, 77, 97,116,101,114,105, 97,
+108,115, 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, 69,100,105,116,105,110,103, 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, 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, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236,144, 0, 0, 0, 0,137, 0, 0, 0, 1,
+ 2,236,145, 16, 2,236,142,240, 67, 97,109,101,114, 97, 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, 69,100,105,116,105,110,103, 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, 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, 1, 64, 0, 0, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236,145, 16, 0, 0, 0,137, 0, 0, 0, 1, 2,236,146, 32, 2,236,144, 0,
+ 80,114,101,118,105,101,119, 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,
+ 76, 97,109,112, 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, 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, 0, 0, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+ 0, 0, 0,228, 2,236,146, 32, 0, 0, 0,137, 0, 0, 0, 1, 2,236,147, 48, 2,236,145, 16, 76, 97,109,112, 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, 76, 97,109,112, 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, 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,255, 24, 1, 62, 0,204,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236,147, 48,
+ 0, 0, 0,137, 0, 0, 0, 1, 2,236,148, 64, 2,236,146, 32, 83,104, 97,100,111,119, 32, 97,110,100, 32, 83,112,111,116, 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, 76, 97,109,112, 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, 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,254, 48, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236,148, 64, 0, 0, 0,137, 0, 0, 0, 1,
+ 2,236,149, 80, 2,236,147, 48, 84,101,120,116,117,114,101, 32, 97,110,100, 32, 73,110,112,117,116, 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, 76, 97,109,112, 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, 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,253, 72, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,228, 2,236,149, 80, 0, 0, 0,137, 0, 0, 0, 1, 2,236,150, 96, 2,236,148, 64,
+ 77, 97,112, 32, 84,111, 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,
+ 76, 97,109,112, 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, 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,253, 72, 1, 62, 0,204, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,236,148, 64, 68, 65, 84, 65,
+ 0, 0, 0,228, 2,236,150, 96, 0, 0, 0,137, 0, 0, 0, 1, 0, 0, 0, 0, 2,236,149, 80, 84,114, 97,110,115,102,111,114,
+109, 32, 80,114,111,112,101,114,116,105,101,115, 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, 86,105,101,119, 51,100, 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, 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,228, 1, 62, 0,204,
+ 0, 0, 0, 0, 0,162, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 3, 0, 5, 30,232, 32,
+ 0, 0, 0,113, 0, 0, 0, 1, 2,236,151,112, 0, 0, 0, 0, 0, 0, 0, 1, 63, 51, 51, 51, 2,236,136,160, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 37,127,255,255, 37,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 51,160, 0, 0,191,128, 0, 0, 0, 0, 0, 0,165,128, 0, 0, 63,128, 0, 0, 51,162, 33,104, 0, 0, 0, 0, 60, 41,199, 78,
+191,230,129,210,193, 30,230,225, 63,128, 0, 0, 63,128, 0, 0, 37,127,255,254,165,127,255,255, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,127,255,255, 0, 0, 0, 0, 0, 0, 0, 0,191,128, 0, 1, 51,160, 0, 0, 0, 0, 0, 0,188, 41,199, 79,
+193, 30,230,226, 63,230,129,216, 63,128, 0, 0, 63, 79, 65,254, 37,132,161, 17,165,153,211,206,165,128, 0, 0, 61, 60, 82,171,
+ 60,131, 1,253, 63,153,211,206, 63,128, 0, 0,177,110,137,200, 63,134,173, 25,179,194,216, 54,179,162, 33,104, 62,238, 21, 90,
+191,222, 51, 78,190, 61,126, 0, 65, 30,230,225, 63,158, 26, 70, 37,158, 26, 69,165,158, 26, 71,153,128, 0, 0, 0, 0, 0, 0,
+ 51,144, 0, 0, 63,115, 79, 65, 0, 0, 0, 0, 58, 96, 32, 0, 63, 81,196, 5,190, 24, 37, 84,189,168,248,231,189,108,210, 23,
+ 60,122, 37,233, 62, 39, 71,242, 61,203, 17, 30, 63, 79, 65,254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,134,173, 25, 0, 0, 0, 0, 0, 0, 0, 0,189, 60, 82,171,188,131, 1,211,191,153,211,206,191,128, 0, 0,128, 0, 0, 0,
+128, 0, 0, 0,193, 65,236,225,128, 0, 0, 0, 63,128, 0, 0, 37,127,255,255, 37,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 51,160, 0, 0,191,128, 0, 0, 0, 0, 0, 0,165,128, 0, 0, 63,128, 0, 0, 51,162, 33,104, 0, 0, 0, 0, 60, 41,199, 78,
+191,230,129,210,193, 30,230,225, 63,128, 0, 0, 63, 53, 4,244,191, 53, 4,243,165, 53, 4,243, 36,181, 4,242, 65, 98,160,147,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 5, 30,248, 32, 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, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0,255,251, 0, 0, 66, 12, 0, 0,
+ 63,128, 0, 0, 63,128, 0, 0, 59, 37,224,208, 60, 35,215, 10, 67,250, 0, 0,188,218, 18,228,188, 23,180, 37, 62, 24, 35, 81,
+190, 55, 52, 64,191,230,153,244, 54,224, 0, 0, 63, 88,146, 56, 64, 71, 37,198, 0, 20, 0, 0, 0, 7, 0,207, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0,255,255, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,128, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 8, 0, 0, 0, 10,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,204, 2,236,151,112, 0, 0, 0,118, 0, 0, 0, 1, 2,236,152,112,
+ 5, 30,232, 32, 0, 0, 0, 4, 0, 0, 0, 0, 2,236,136,160, 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, 2, 0, 4, 0, 0, 0, 0, 68,160, 0, 0,196, 46, 0, 0, 67,100, 0, 0, 55,136,197,197,
+ 68, 78,209,118,195,231,222, 40, 67, 25,158,172, 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, 67,128, 0, 0,
+ 66, 40, 0, 0, 69, 0, 0, 0, 67,225, 0, 0, 63, 0, 0, 0, 63,154,225, 72, 0, 0, 0, 1, 0, 1, 0, 1, 3,233, 2,235,
+ 0, 0, 0, 0, 0, 3, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0,255,255, 0, 0, 0, 0, 0, 0, 1,150, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 4, 0, 0, 0, 68, 65, 84, 65, 0, 0, 1, 40, 2,236,152,112, 0, 0, 0,117, 0, 0, 0, 1, 2,236,153,192,
+ 2,236,151,112, 0, 0, 0, 2, 63, 51, 51, 51, 2,236,136,160, 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, 67,122, 0, 0,189,204,204,205, 63,140,204,205, 63,128, 0, 0, 67,122, 0, 0,
+192,160, 0, 0, 64,160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 2,235, 0, 0, 0, 16, 0, 0, 3,168,
+ 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 3,168, 0, 0, 0, 16, 0, 0, 2,235, 60, 35,215, 10, 60, 35,215, 10,
+ 70,106, 96, 0, 68,122, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 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, 5, 31, 16, 32, 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, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 79, 66,
+ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67,122, 0, 0,189,204,204,205,
+ 63,140,204,205, 68, 65, 84, 65, 0, 0, 0,120, 2,236,153,192, 0, 0, 0,124, 0, 0, 0, 1, 2,236,154, 96, 2,236,152,112,
+ 0, 0, 0, 9, 63, 51, 51, 51, 2,236,136,160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,236,183,112,
+ 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61,204,204,205, 0, 0, 0, 5, 0, 0, 0, 17, 0, 0, 2,225, 0, 0, 2,227,
+ 0, 0, 0, 5, 0, 0, 0, 17, 0, 0, 2,207, 0, 0, 2,227, 68, 65, 84, 65, 0, 0, 0,248, 2,236,154, 96, 0, 0, 0,122,
+ 0, 0, 0, 1, 2,236,155,128, 2,236,153,192, 0, 0, 0, 6, 63, 51, 51, 51, 2,236,136,160, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67,128, 0, 0, 0, 0, 0, 0, 67,128, 0, 0,190,120, 0, 0, 63,159, 0, 0,
+190,242, 0, 0, 63,188,128, 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, 1,124, 0, 0, 0, 0, 0, 0, 1,242, 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, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 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, 68, 65, 84, 65,
+ 0, 0, 0,248, 2,236,155,128, 0, 0, 0,121, 0, 0, 0, 1, 2,236,156,160, 2,236,154, 96, 0, 0, 0, 3, 63, 51, 51, 51,
+ 2,236,136,160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67,182, 0, 0,195,209, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 67,182, 0, 0,195,190, 0, 0,181, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0,
+ 0, 0, 1,124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 1,124, 0, 0, 0, 0,
+ 0, 0, 1,124,195,190, 0, 0,195,190, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 1, 0, 1,
+ 0, 1, 0, 1, 1,108, 1,124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,142, 0, 1, 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, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,160, 2,236,156,160, 0, 0, 0,194, 0, 0, 0, 1, 2,236,157,112,
+ 2,236,155,128, 0, 0, 0, 11, 63, 51, 51, 51, 2,236,136,160,192,128, 0, 0, 67,122, 0, 0,192,128, 0, 0, 67,127, 0, 0,
+192,128, 0, 0, 66, 72, 0, 0,192,128, 0, 0, 67,127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1,124, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 1,124, 0, 0, 0, 16, 0, 0, 1,124,
+ 63,128, 0, 0, 67,129,128, 0, 70,250, 0, 0, 67,129,128, 0, 61,204,204,205, 65, 32, 0, 0, 0, 8, 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, 68, 65, 84, 65,
+ 0, 0, 0,164, 2,236,157,112, 0, 0, 0,123, 0, 0, 0, 1, 2,236,158, 64, 2,236,156,160, 0, 0, 0, 13, 63, 51, 51, 51,
+ 2,236,136,160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0,
+ 68,122, 0, 0, 0, 0, 0, 0, 68,122, 0, 0,192,160, 0, 0, 66,130, 0, 0, 0, 0, 0, 0, 67,182, 0, 0, 0, 0, 1,108,
+ 0, 0, 1,124, 0, 0, 0, 0, 0, 0, 1,124, 0, 0, 0,196, 0, 0, 1,108, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0,196,
+ 0, 0, 1,108, 0, 0, 0, 16, 0, 0, 1,124, 0, 0, 0, 0, 0, 0, 0, 0, 68,122, 0, 0, 68,122, 0, 0, 61,204,204,205,
+ 66, 72, 0, 0, 0, 10, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,176, 2,236,158, 64,
+ 0, 0, 0,203, 0, 0, 0, 1, 2,236,159, 32, 2,236,157,112, 0, 0, 0, 12, 63, 51, 51, 51, 2,236,136,160, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,191, 0, 0, 0, 66, 2, 0, 0,193,128, 0, 0, 67,247, 0, 0,191, 0, 0, 0,
+ 66, 2, 0, 0,193,128, 0, 0, 67,247, 0, 0, 0, 0, 1,108, 0, 0, 1,124, 0, 0, 0, 0, 0, 0, 2, 14, 0, 0, 0,128,
+ 0, 0, 1,108, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0,128, 0, 0, 1,108, 0, 0, 0, 16, 0, 0, 2, 14, 0, 0, 0, 0,
+ 0, 0, 0, 0, 70,250, 0, 0, 68,122, 0, 0, 60, 35,215, 10, 66, 72, 0, 0, 0, 10, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 1,104,
+ 2,236,159, 32, 0, 0, 0,120, 0, 0, 0, 1, 0, 0, 0, 0, 2,236,158, 64, 0, 0, 0, 5, 63, 51, 51, 51, 2,236,136,160,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 86, 83, 97,118,101, 32, 70,105,108,
+101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 85,115,101,114,115, 47,116,111,110, 47, 68,101,115,107,116,
+111,112, 47, 0,114, 47,114,101,108,101, 97,115,101, 47,100, 97,116, 97,102,105,108,101,115, 47, 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, 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,112,114,101,118,105,101,119, 46, 98,108,101,110,100, 0, 0, 0,
+ 98,108,101,110,100, 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, 8, 0, 46, 0, 0, 0, 0, 1, 85, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 72, 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, 83, 67, 0, 0, 4,156, 5, 30,236, 32,
+ 0, 0, 0,111, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 67,112,114,101,118,105,101,
+119, 0, 0, 99,101,110,101, 46, 48, 48, 49, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 30,248, 32,
+ 2,236,182, 32, 0, 0, 0, 0, 0, 0, 0, 0, 2,236,160,176, 2,236,167,144, 2,236,165,176, 63,149,213, 84,193, 7,238,126,
+ 63,142,109, 36, 55,142, 84, 52,192,188, 12,194, 64, 71, 38, 28, 55,142, 84, 52,192,188, 12,194, 64, 71, 38, 28, 55,142, 84, 52,
+192,188, 12,194, 64, 71, 38, 28, 0, 0, 0, 1, 62,214,245, 65, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 2,236,167,224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,236,168, 48, 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, 2, 0, 0, 0, 1, 0, 0, 0, 20,
+ 0, 0, 0,100, 0, 0, 0,100, 0, 0, 0, 1, 0, 0, 0, 0, 63,128, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 2,128, 1,224, 0, 60, 0, 32, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 25, 0,141, 2, 88,
+ 2, 88, 0,100, 0,100, 0, 2, 0, 2, 0, 0, 0, 24, 0, 4, 0, 0, 0, 0, 0, 90, 0, 16, 0, 0, 0, 0, 0, 0, 0, 64,
+ 0, 0, 0, 0, 0, 0, 0, 5, 0, 25, 0, 10, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 63,128, 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, 2,236,168,176,
+ 2,236,168,176, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 5, 0, 2, 0, 1, 0, 1, 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, 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, 47, 47, 98, 97,
+ 99,107, 98,117,102, 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, 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, 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, 47,116,109,112,
+ 47, 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,
+ 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, 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, 47, 47,102,116,
+121,112,101, 0, 64, 38, 35, 0, 0, 0, 0, 0, 64, 94, 0, 0, 64, 38, 94, 0, 0, 0, 35, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0,172, 68,
+ 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, 10, 0, 0, 0, 0, 0, 0, 2,233, 81,160, 0, 1, 0, 0, 0, 0, 0, 1, 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, 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, 68, 65, 84, 65, 0, 0, 0, 28, 2,236,160,176, 0, 0, 0, 98, 0, 0, 0, 1, 2,236,161, 0, 0, 0, 0, 0,
+ 0, 0, 0, 33, 0, 0, 0, 1, 0, 0, 0, 0, 1,255, 1,124, 5, 31, 4, 32, 68, 65, 84, 65, 0, 0, 0, 28, 2,236,161, 0,
+ 0, 0, 0, 98, 0, 0, 0, 1, 2,236,161, 80, 2,236,160,176, 0, 0, 4, 14, 0, 0, 0, 1, 0, 0, 0, 0, 1,255, 1,252,
+ 5, 31, 0, 32, 68, 65, 84, 65, 0, 0, 0, 28, 2,236,161, 80, 0, 0, 0, 98, 0, 0, 0, 1, 2,236,161,160, 2,236,161, 0,
+ 0, 0, 4, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1,203, 1, 72, 5, 31, 76, 32, 68, 65, 84, 65, 0, 0, 0, 28, 2,236,161,160,
+ 0, 0, 0, 98, 0, 0, 0, 1, 2,236,161,240, 2,236,161, 80, 0, 0, 0, 32, 0, 0, 0, 4, 0, 0, 16, 0, 46,224, 1, 49,
+ 5, 31, 40, 32, 68, 65, 84, 65, 0, 0, 0, 28, 2,236,161,240, 0, 0, 0, 98, 0, 0, 0, 1, 2,236,162, 64, 2,236,161,160,
+ 0, 0, 0, 33, 0, 0, 0, 2, 0, 0, 0, 0, 1,255, 1,124, 5, 31, 44, 32, 68, 65, 84, 65, 0, 0, 0, 28, 2,236,162, 64,
+ 0, 0, 0, 98, 0, 0, 0, 1, 2,236,162,144, 2,236,161,240, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 20, 0, 46,224, 0, 52,
+ 5, 31, 36, 32, 68, 65, 84, 65, 0, 0, 0, 28, 2,236,162,144, 0, 0, 0, 98, 0, 0, 0, 1, 2,236,162,224, 2,236,162, 64,
+ 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 20, 0, 46,224, 0, 47, 5, 31, 32, 32, 68, 65, 84, 65, 0, 0, 0, 28, 2,236,162,224,
+ 0, 0, 0, 98, 0, 0, 0, 1, 2,236,163, 48, 2,236,162,144, 0, 0, 0, 2, 0, 0, 0, 4, 0, 0, 20, 0, 46,224, 1, 85,
+ 5, 31, 28, 32, 68, 65, 84, 65, 0, 0, 0, 28, 2,236,163, 48, 0, 0, 0, 98, 0, 0, 0, 1, 2,236,163,128, 2,236,162,224,
+ 0, 0, 0, 1, 0, 0, 0, 3, 0, 0, 20, 0, 46,224, 0,158, 5, 31, 24, 32, 68, 65, 84, 65, 0, 0, 0, 28, 2,236,163,128,
+ 0, 0, 0, 98, 0, 0, 0, 1, 2,236,163,208, 2,236,163, 48, 0, 0, 0, 1, 0, 0, 0, 4, 0, 0, 20, 0, 46,224, 0,100,
+ 5, 31, 20, 32, 68, 65, 84, 65, 0, 0, 0, 28, 2,236,163,208, 0, 0, 0, 98, 0, 0, 0, 1, 2,236,164, 32, 2,236,163,128,
+ 0, 0, 0, 4, 0, 0, 0, 11, 0, 0, 0, 0, 1,254, 1,152, 5, 31, 72, 32, 68, 65, 84, 65, 0, 0, 0, 28, 2,236,164, 32,
+ 0, 0, 0, 98, 0, 0, 0, 1, 2,236,164,112, 2,236,163,208, 0, 0, 4, 14, 0, 0, 0, 5, 0, 0, 0, 0, 1,255, 1,252,
+ 5, 30,252, 32, 68, 65, 84, 65, 0, 0, 0, 28, 2,236,164,112, 0, 0, 0, 98, 0, 0, 0, 1, 2,236,164,192, 2,236,164, 32,
+ 0, 0, 0, 64, 0, 0, 0, 13, 0, 0, 16, 0, 1,252, 2,162, 5, 31, 64, 32, 68, 65, 84, 65, 0, 0, 0, 28, 2,236,164,192,
+ 0, 0, 0, 98, 0, 0, 0, 1, 2,236,165, 16, 2,236,164,112, 0, 0, 0, 64, 0, 0, 0, 14, 0, 0, 0, 0, 1,249, 1,199,
+ 5, 31, 68, 32, 68, 65, 84, 65, 0, 0, 0, 28, 2,236,165, 16, 0, 0, 0, 98, 0, 0, 0, 1, 2,236,165, 96, 2,236,164,192,
+ 0, 0, 0, 32, 0, 0, 0, 15, 0, 0, 0, 0, 1,253, 1,124, 5, 31, 80, 32, 68, 65, 84, 65, 0, 0, 0, 28, 2,236,165, 96,
+ 0, 0, 0, 98, 0, 0, 0, 1, 2,236,165,176, 2,236,165, 16, 0, 0, 0, 16, 0, 0, 0, 1, 0, 0, 0, 0, 1,254, 1,125,
+ 5, 31, 60, 32, 68, 65, 84, 65, 0, 0, 0, 28, 2,236,165,176, 0, 0, 0, 98, 0, 0, 0, 1, 2,236,166, 0, 2,236,165, 96,
+ 0, 0, 0, 1, 0, 0, 0, 5, 0, 0, 0, 1, 1,253, 1,125, 5, 31, 48, 32, 68, 65, 84, 65, 0, 0, 0, 28, 2,236,166, 0,
+ 0, 0, 0, 98, 0, 0, 0, 1, 2,236,166, 80, 2,236,165,176, 0, 0, 4, 28, 0, 0, 0, 2, 0, 0, 20, 0, 46,224, 1,152,
+ 5, 31, 8, 32, 68, 65, 84, 65, 0, 0, 0, 28, 2,236,166, 80, 0, 0, 0, 98, 0, 0, 0, 1, 2,236,166,160, 2,236,166, 0,
+ 0, 0, 0, 2, 0, 0, 0, 6, 0, 0, 0, 0, 1,254, 1,125, 5, 31, 56, 32, 68, 65, 84, 65, 0, 0, 0, 28, 2,236,166,160,
+ 0, 0, 0, 98, 0, 0, 0, 1, 2,236,166,240, 2,236,166, 80, 0, 0, 4, 28, 0, 0, 0, 3, 0, 0, 20, 0, 46,224, 0, 44,
+ 5, 31, 16, 32, 68, 65, 84, 65, 0, 0, 0, 28, 2,236,166,240, 0, 0, 0, 98, 0, 0, 0, 1, 2,236,167, 64, 2,236,166,160,
+ 0, 0, 0, 8, 0, 0, 0, 21, 0, 0, 0, 0, 1,194, 1,152, 5, 31, 52, 32, 68, 65, 84, 65, 0, 0, 0, 28, 2,236,167, 64,
+ 0, 0, 0, 98, 0, 0, 0, 1, 2,236,167,144, 2,236,166,240, 0, 0, 4, 28, 0, 0, 0, 4, 0, 0, 20, 0, 46,224, 0, 20,
+ 5, 31, 12, 32, 68, 65, 84, 65, 0, 0, 0, 28, 2,236,167,144, 0, 0, 0, 98, 0, 0, 0, 1, 0, 0, 0, 0, 2,236,167, 64,
+ 0, 0, 5,223, 0, 0, 0, 6, 0, 0, 4, 0, 46,224, 0, 62, 5, 30,248, 32, 68, 65, 84, 65, 0, 0, 0, 40, 2,236,167,224,
+ 0, 0, 0, 97, 0, 0, 0, 1, 1, 44, 0, 0, 0, 1, 0, 2, 0, 1, 0, 2, 0, 0, 0, 1, 1,244, 0,200, 0,100, 0, 20,
+ 0, 0, 39, 16, 61,204,204,205, 65,240, 0, 0, 64, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 76, 2,236,168, 48, 0, 0, 0,108,
+ 0, 0, 0, 1, 0, 1, 0, 1, 63, 76,204,205, 66,180, 0, 0, 0, 9, 0, 1, 63,128, 0, 0, 58,131, 18,111, 0, 32, 0, 32,
+ 0, 32, 0, 1, 63,128, 0, 0, 63,128, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 56,209,183, 23, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 61,204,204,205, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 64, 2,236,168,176, 0, 0, 0,103,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 49, 32, 82,101,110,100,101,114, 76, 97,121,101,114, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,236,184, 64, 0, 15,255,255, 0, 0,127,255, 0, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 73, 77, 0, 0, 1,116, 2,236,169, 32, 0, 0, 0, 28, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 73, 77, 73,109, 97,103,101, 46, 48, 48, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85,110,116,105,116,108,101,100, 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, 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, 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, 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, 1, 0, 0, 0, 1, 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, 68,134,110,108,
+ 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 67, 65, 0, 0, 0,128, 2,236,170,192, 0, 0, 0, 25, 0, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 65, 67, 97,109,101,114, 97, 46, 48, 48, 49, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 62, 76,204,205, 0, 0, 0, 0,
+ 64,176, 39, 76, 66,112, 69,210, 65,240, 0, 0, 64,234, 14,161, 63, 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, 76, 65, 0, 0, 1, 0, 2,236,171,112, 0, 0, 0, 36, 0, 0, 0, 1, 2,236,172,160, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 76, 65, 76, 97,109,112, 46, 48, 48, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 1, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+ 63,128, 0, 0, 65,160, 0, 0, 66,143,152,182, 62, 25,153,154, 63,128, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63, 0, 0, 0,
+ 66, 32, 0, 0, 66, 52, 0, 0, 63,128, 0, 0, 64, 64, 0, 0, 2, 0, 0, 3, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1,
+ 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 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, 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, 76, 65, 0, 0, 1, 0, 2,236,172,160,
+ 0, 0, 0, 36, 0, 0, 0, 1, 2,236,173,208, 2,236,171,112, 0, 0, 0, 0, 0, 0, 0, 0, 76, 65, 83,112,111,116, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 8,
+ 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 64, 12,204,205, 65,239,255,247, 66,150, 0, 0,
+ 62, 25,153,154, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 26, 46, 65,240, 4, 25, 66, 52, 0, 0, 63,128, 0, 0,
+ 64, 64, 0, 0, 11, 64, 0, 3, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+ 63,128, 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, 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, 76, 65, 0, 0, 1, 0, 2,236,173,208, 0, 0, 0, 36, 0, 0, 0, 1, 2,236,175, 0,
+ 2,236,172,160, 0, 0, 0, 0, 0, 0, 0, 0, 76, 65, 83,112,111,116, 46, 48, 48, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+ 63,128, 0, 0, 63,128, 0, 0, 63,102,102,102, 65,239,255,247, 66,150, 0, 0, 62, 25,153,154, 63,128, 0, 0, 0, 0, 0, 0,
+ 63,128, 0, 0, 63,128, 26, 46, 65,240, 4, 25, 66, 52, 0, 0, 63,128, 0, 0, 64, 64, 0, 0, 11, 64, 0, 3, 0, 1, 0, 0,
+ 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 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, 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, 76, 65,
+ 0, 0, 1, 0, 2,236,175, 0, 0, 0, 0, 36, 0, 0, 0, 1, 2,236,176, 48, 2,236,173,208, 0, 0, 0, 0, 0, 0, 0, 0,
+ 76, 65, 83,112,111,116, 46, 48, 48, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+ 65,239,255,247, 66,150, 0, 0, 62, 25,153,154, 63,128, 0, 0, 63, 27,182,200, 63,128, 0, 0, 63,128, 26, 46, 65,240, 4, 25,
+ 66, 52, 0, 0, 63,128, 0, 0, 64, 64, 0, 0, 11, 64, 0, 3, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0,
+ 63,128, 0, 0, 63,128, 0, 0, 63,128, 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, 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, 76, 65, 0, 0, 1, 0, 2,236,176, 48, 0, 0, 0, 36,
+ 0, 0, 0, 1, 2,236,177, 96, 2,236,175, 0, 0, 0, 0, 0, 0, 0, 0, 0, 76, 65, 83,112,111,116, 46, 48, 48, 52, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0,
+ 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 62,204,204,205, 65,239,255,247, 66,150, 0, 0, 62, 25,153,154,
+ 63,128, 0, 0, 63, 27,182,200, 63,128, 0, 0, 63,128, 26, 46, 65,240, 4, 25, 66, 52, 0, 0, 63,128, 0, 0, 64, 64, 0, 0,
+ 11, 64, 0, 3, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 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, 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, 76, 65, 0, 0, 1, 0, 2,236,177, 96, 0, 0, 0, 36, 0, 0, 0, 1, 2,236,178,144, 2,236,176, 48,
+ 0, 0, 0, 0, 0, 0, 0, 0, 76, 65, 83,112,111,116, 46, 48, 48, 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 8, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+ 63,128, 0, 0, 63, 83, 78, 80, 65,239,255,247, 66,150, 0, 0, 62, 25,153,154, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+ 63,128, 26, 46, 65,240, 4, 25, 66, 52, 0, 0, 63,128, 0, 0, 64, 64, 0, 0, 11, 64, 0, 3, 0, 1, 0, 0, 0, 0, 0, 1,
+ 0, 1, 0, 1, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 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, 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, 76, 65, 0, 0, 1, 0,
+ 2,236,178,144, 0, 0, 0, 36, 0, 0, 0, 1, 2,236,179,192, 2,236,177, 96, 0, 0, 0, 0, 0, 0, 0, 0, 76, 65, 83,112,
+111,116, 46, 48, 48, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 2, 0, 8, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,179, 51, 51, 65,239,255,247,
+ 66, 72, 0, 0, 63, 8,156,171, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 65, 68,207, 78, 65,240, 4, 25, 66, 52, 0, 0,
+ 63,128, 0, 0, 64, 64, 0, 0, 2, 0, 0, 3, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 63,128, 0, 0,
+ 63,128, 0, 0, 63,128, 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, 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, 76, 65, 0, 0, 1, 0, 2,236,179,192, 0, 0, 0, 36, 0, 0, 0, 1,
+ 2,236,180,240, 2,236,178,144, 0, 0, 0, 0, 0, 0, 0, 0, 76, 65, 83,112,111,116, 46, 48, 48, 55, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 63,128, 0, 0,
+ 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 65,239,255,247, 66,150, 0, 0, 62, 25,153,154, 63,128, 0, 0,
+ 0, 0, 0, 0, 63,128, 0, 0, 63,128, 26, 46, 65,240, 4, 25, 66, 52, 0, 0, 63,128, 0, 0, 64, 64, 0, 0, 11, 64, 0, 3,
+ 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 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, 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, 76, 65, 0, 0, 1, 0, 2,236,180,240, 0, 0, 0, 36, 0, 0, 0, 1, 0, 0, 0, 0, 2,236,179,192, 0, 0, 0, 0,
+ 0, 0, 0, 0, 76, 65, 76, 97,109,112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+ 63,192, 0, 0, 65,160, 0, 0, 66, 52, 0, 0, 62, 25,153,154, 63,128, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63, 0, 0, 0,
+ 66, 32, 0, 0, 66, 52, 0, 0, 63,128, 0, 0, 64, 64, 0, 0, 2, 0, 0, 3, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1,
+ 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 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, 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, 87, 79, 0, 0, 1, 40, 2,236,182, 32,
+ 0, 0, 0, 96, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 87, 79, 87,111,114,108,100, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62, 79, 47,141, 62,209, 19, 64, 63, 14, 23, 73, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 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, 63,128, 0, 0, 0, 0, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 28,204,205, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 5, 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, 64, 0, 0, 0,
+ 0, 0, 0, 0, 65,112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 32, 0, 0, 0, 0, 0, 0, 63,128, 0, 0,
+ 61, 76,204,205, 0, 0, 0, 5, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 88, 0, 0, 0,104, 2,236,183,112, 0, 0, 0, 23,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 88, 84,101,120,116, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,
+ 0, 0, 0, 1, 2,236,184, 0, 2,236,184, 0, 2,236,184, 0, 2,236,184, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 30,242, 32,
+255,255,255,255, 0, 0, 4, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 24, 2,236,184, 0, 0, 0, 0, 22, 0, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 2,233, 30,112, 0, 0, 0, 0, 0, 0, 0, 0, 70, 82, 69, 69, 68, 65, 84, 65, 0, 0, 0, 4,
+ 2,233, 30,112, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 71, 82, 0, 0, 0, 68, 2,236,184, 64, 0, 0, 0,196,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 71, 82, 79,118,101,114,114,105,100,101, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,236,184,176, 2,236,186,240,
+ 0, 15,255,255, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 24, 2,236,184,176, 0, 0, 0,195, 0, 0, 0, 1, 2,236,184,240,
+ 0, 0, 0, 0, 5, 31, 40, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 24, 2,236,184,240,
+ 0, 0, 0,195, 0, 0, 0, 1, 2,236,185, 48, 2,236,184,176, 5, 31, 36, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65, 0, 0, 0, 24, 2,236,185, 48, 0, 0, 0,195, 0, 0, 0, 1, 2,236,185,112, 2,236,184,240, 5, 31, 32, 32,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 24, 2,236,185,112, 0, 0, 0,195, 0, 0, 0, 1,
+ 2,236,185,176, 2,236,185, 48, 5, 31, 28, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 24,
+ 2,236,185,176, 0, 0, 0,195, 0, 0, 0, 1, 2,236,185,240, 2,236,185,112, 5, 31, 24, 32, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 24, 2,236,185,240, 0, 0, 0,195, 0, 0, 0, 1, 2,236,186, 48, 2,236,185,176,
+ 5, 31, 20, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 24, 2,236,186, 48, 0, 0, 0,195,
+ 0, 0, 0, 1, 2,236,186,112, 2,236,185,240, 5, 31, 64, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+ 0, 0, 0, 24, 2,236,186,112, 0, 0, 0,195, 0, 0, 0, 1, 2,236,186,176, 2,236,186, 48, 5, 31, 8, 32, 5,157,146, 32,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 24, 2,236,186,176, 0, 0, 0,195, 0, 0, 0, 1, 2,236,186,240,
+ 2,236,186,112, 5, 31, 16, 32, 5,157,150, 32, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 24, 2,236,186,240,
+ 0, 0, 0,195, 0, 0, 0, 1, 0, 0, 0, 0, 2,236,186,176, 5, 31, 12, 32, 5,157,154, 32, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 79, 66, 0, 0, 3, 16, 5, 30,248, 32, 0, 0, 0, 90, 0, 0, 0, 1, 5, 30,252, 32, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 79, 66, 67, 97,109,101,114, 97, 46, 48, 48, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 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, 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, 2,236,170,192, 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,188, 41,199, 78,
+193, 30,230,225, 63,230,129,216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,201, 15,218, 37,128, 0, 0,
+ 37,127,255,255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 37,127,255,255,165,128, 0, 0, 0, 0, 0, 0,
+ 37,127,255,255, 51,162, 33,105, 63,128, 0, 0, 0, 0, 0, 0, 37,128, 0, 0,191,128, 0, 0, 51,162, 33,105, 0, 0, 0, 0,
+188, 41,199, 78,193, 30,230,225, 63,230,129,216, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,137,145,110, 60, 24,136,133,160, 0, 0, 0, 0,
+ 25,127,255,254, 63,128, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0,165,127,255,255,176,136, 90, 64, 63,128, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 5,223, 4, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 1,
+ 0, 0, 0, 0, 79, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,100, 0, 0, 0, 0,
+ 64, 0, 0, 0, 63,128, 0, 0, 63,100, 41, 6, 63,128, 0, 0, 62,204,204,205, 0, 0, 0, 0, 63,100, 41, 6, 0, 0, 0, 0,
+ 2, 0, 0, 0, 1, 0, 0, 0, 63,128, 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, 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, 63,128, 0, 0, 63,128, 0, 0, 63,128, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 79, 66, 0, 0, 3, 16, 5, 30,252, 32, 0, 0, 0, 90, 0, 0, 0, 1, 5, 31, 0, 32, 5, 30,248, 32,
+ 0, 0, 0, 0, 0, 0, 0, 0, 79, 66, 99,104,101, 99,107,101,114,115, 46, 48, 48, 49, 0, 46, 48, 48, 49, 0, 0, 0, 0, 0,
+ 0, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 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, 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, 2,236,213, 64, 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, 2,235, 92,144,
+ 55,142, 84, 52,192,188, 12,194, 64, 71, 38, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 64,190, 36, 69, 64,190, 36, 69, 64,190, 36, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+128, 0, 0, 0, 63, 73, 15,218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64,134,115, 83, 64,134,115, 82, 0, 0, 0, 0,
+ 0, 0, 0, 0,192,134,115, 82, 64,134,115, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64,190, 36, 68,
+ 0, 0, 0, 0, 55,142, 84, 52,192,188, 12,194, 64, 71, 38, 28, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 61,243,183,207,189,243,183,205, 37,162, 83,160,
+ 0, 0, 0, 0, 50, 26, 90, 29, 50, 26, 90, 31, 62, 44, 85,173, 0, 0, 0, 0,189,243,183,205,189,243,183,207, 50, 87,107, 24,
+ 0, 0, 0, 0,190,247,176,158,190,246,108,212,190, 97,232, 64, 63,128, 0, 0, 0, 0, 4, 14, 0, 0, 0, 1, 0, 0, 0, 68,
+ 0, 1, 0, 2, 0, 0, 0, 0, 79, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,100,
+ 0, 0, 0, 0,201,150,180, 56, 63,128, 0, 0, 61, 35,215, 10, 63,128, 0, 0, 62,204,204,205, 0, 0, 0, 0, 61,204,204,205,
+ 0, 0, 0, 0, 4, 0, 1, 1, 1, 0, 0, 0, 63,128, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,128, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 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, 2,235,190, 48, 2,235,196, 48, 0, 0, 0, 89,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 4, 2,235, 92,144, 0, 0, 0, 0, 0, 0, 0, 1, 2,236,191,224,
+ 0, 0, 79, 66, 0, 0, 3, 16, 5, 31, 0, 32, 0, 0, 0, 90, 0, 0, 0, 1, 5, 31, 4, 32, 5, 30,252, 32, 0, 0, 0, 0,
+ 0, 0, 0, 0, 79, 66, 99,104,101, 99,107,101,114,115, 46, 48, 48, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 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, 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, 2,236,208,112, 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, 2,235,151,176, 55,142, 84, 52,
+192,188, 12,194, 64, 71, 38, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 64,190, 36, 69, 64,190, 36, 69, 64,190, 36, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 0, 0, 0,
+ 63, 73, 15,218, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64,134,115, 83, 64,134,115, 82, 0, 0, 0, 0, 0, 0, 0, 0,
+192,134,115, 82, 64,134,115, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64,190, 36, 68, 0, 0, 0, 0,
+ 55,142, 84, 52,192,188, 12,194, 64, 71, 38, 28, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 61,243,183,207,189,243,183,205, 37,162, 83,160, 0, 0, 0, 0,
+ 50, 26, 90, 29, 50, 26, 90, 31, 62, 44, 85,173, 0, 0, 0, 0,189,243,183,205,189,243,183,207, 50, 87,107, 24, 0, 0, 0, 0,
+190,247,176,158,190,246,108,212,190, 97,232, 64, 63,128, 0, 0, 0, 0, 4, 14, 0, 0, 0, 1, 0, 0, 0, 68, 0, 1, 0, 2,
+ 0, 0, 0, 0, 79, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,100, 0, 0, 0, 0,
+201,150,180, 56, 63,128, 0, 0, 61, 35,215, 10, 63,128, 0, 0, 62,204,204,205, 0, 0, 0, 0, 61,204,204,205, 0, 0, 0, 0,
+ 4, 0, 1, 1, 1, 0, 0, 0, 63,128, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0,
+ 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 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, 2,235,177,128, 2,235,183,144, 0, 0, 0, 89, 0, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 4, 2,235,151,176, 0, 0, 0, 0, 0, 0, 0, 1, 2,236,189, 96, 0, 0, 79, 66,
+ 0, 0, 3, 16, 5, 31, 4, 32, 0, 0, 0, 90, 0, 0, 0, 1, 5, 31, 8, 32, 5, 31, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0,
+ 79, 66, 99,104,101, 99,107,101,114,115, 46, 48, 48, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 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, 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,
+ 2,236,218, 64, 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, 2,230, 6, 0, 60,102,131, 0, 64,164,112, 14,
+ 63,229,211, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 34,159,178,
+ 65, 34,159,178, 65, 34,159,177, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 0, 0, 0,178, 89,250,166,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 34,159,178,180, 10,120,151, 0, 0, 0, 0, 0, 0, 0, 0, 52, 10,120,151,
+ 65, 34,159,178, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 34,159,177, 0, 0, 0, 0, 60,102,131, 0,
+ 64,164,112, 14, 63,229,211, 24, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 61,201,126,231, 48,171,145,219,163,201, 66, 34, 0, 0, 0, 0,164,167,209, 65,
+ 49,255, 57, 51, 61,201,126,232, 0, 0, 0, 0, 48,172, 66,235,189,201,126,231, 49,251,201, 70, 0, 0, 0, 0,187, 29,136, 18,
+191,189,200,203, 58, 9,139,180, 63,128, 0, 0, 0, 0, 0, 33, 0, 0, 0, 1, 0, 0, 0, 68, 0, 1, 0, 2, 0, 0, 0, 0,
+ 79, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,100, 0, 0, 0, 0,201,150,180, 56,
+ 63,128, 0, 0, 61, 35,215, 10, 63,128, 0, 0, 62,204,204,205, 0, 0, 0, 0, 61,204,204,205, 0, 0, 0, 0, 4, 0, 1, 1,
+ 1, 0, 0, 0, 63,128, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 64, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 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, 2,229,237, 0, 2,229,242,240, 0, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65, 0, 0, 0, 4, 2,230, 6, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2,236,191,224, 0, 0, 79, 66, 0, 0, 3, 16,
+ 5, 31, 8, 32, 0, 0, 0, 90, 0, 0, 0, 1, 5, 31, 12, 32, 5, 31, 4, 32, 0, 0, 0, 0, 0, 0, 0, 0, 79, 66, 76, 97,
+109,112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 10, 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, 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, 2,236,172,160,
+ 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, 65,110, 57, 42, 64, 11,114,237, 64,121, 99,120,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,103, 90, 85,190,186, 45,254, 63,128,209,115, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,255,247,136, 63, 74, 39, 37, 62,182, 26,138, 0, 0, 0, 0,191, 44, 21,164, 61,194, 67, 28,
+ 63, 59,248,176, 0, 0, 0, 0, 63, 11,203,251,191, 27, 45,217, 63, 20, 7, 47, 0, 0, 0, 0, 65,110, 57, 42, 64, 11,114,237,
+ 64,121, 99,120, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,128, 0, 0, 62,255,247,138,191, 44, 21,164, 63, 11,203,251, 0, 0, 0, 0, 62,182, 26,141, 63, 59,248,176,
+ 63, 20, 7, 45, 0, 0, 0, 0,191, 74, 39, 37,189,194, 67, 9, 63, 27, 45,217, 0, 0, 0, 0,193,142, 14,147, 64,234,125, 35,
+192, 0,119, 85, 63,128, 0, 0, 0, 0, 4, 28, 20, 0, 0, 0, 0, 0, 0, 68, 0, 5, 0, 1, 0, 0, 0, 0, 79, 66, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,100, 0, 0, 0, 0,201,150,180, 56, 63,128, 0, 0,
+ 61, 35,215, 10, 63,128, 0, 0, 62,204,204,205, 0, 0, 0, 0, 61,204,204,205, 0, 0, 0, 0, 4, 0, 0, 0, 1, 0, 0, 0,
+ 63,128, 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, 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, 64, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 79, 66,
+ 0, 0, 3, 16, 5, 31, 12, 32, 0, 0, 0, 90, 0, 0, 0, 1, 5, 31, 16, 32, 5, 31, 8, 32, 0, 0, 0, 0, 0, 0, 0, 0,
+ 79, 66, 76, 97,109,112, 46, 48, 48, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 10, 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, 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,
+ 2,236,173,208, 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,191,210, 76, 84,193, 71,162,178,
+ 64,178,186,210, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,103, 90, 85,190,186, 45,254, 63,128,209,115,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62,255,247,136, 63, 74, 39, 37, 62,182, 26,138, 0, 0, 0, 0,191, 44, 21,164,
+ 61,194, 67, 28, 63, 59,248,176, 0, 0, 0, 0, 63, 11,203,251,191, 27, 45,217, 63, 20, 7, 47, 0, 0, 0, 0,191,210, 76, 84,
+193, 71,162,178, 64,178,186,210, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 62,255,247,136,191, 44, 21,164, 63, 11,203,251, 0, 0, 0, 0, 62,182, 26,139,
+ 63, 59,248,173, 63, 20, 7, 44, 0, 0, 0, 0,191, 74, 39, 36,189,194, 67, 17, 63, 27, 45,217, 0, 0, 0, 0, 63,189,129,191,
+192,104,159,176,192, 53,194,132, 63,128, 0, 0, 0, 0, 4, 28, 20, 0, 0, 0, 0, 0, 0, 68, 0, 5, 0, 1, 0, 0, 0, 0,
+ 79, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,100, 0, 0, 0, 0,201,150,180, 56,
+ 63,128, 0, 0, 61, 35,215, 10, 63,128, 0, 0, 62,204,204,205, 0, 0, 0, 0, 61,204,204,205, 0, 0, 0, 0, 4, 0, 0, 0,
+ 1, 0, 0, 0, 63,128, 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, 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, 64, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 79, 66, 0, 0, 3, 16, 5, 31, 16, 32, 0, 0, 0, 90, 0, 0, 0, 1, 5, 31, 20, 32, 5, 31, 12, 32, 0, 0, 0, 0,
+ 0, 0, 0, 0, 79, 66, 76, 97,109,112, 46, 48, 48, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 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, 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, 2,236,178,144, 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,193, 16,188,238,
+193, 57,119,229, 65,141,218, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,191, 15, 79,202,191, 12,100,179,
+ 63,234, 92,112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,190, 96,197,171, 63, 83, 27,149, 63, 5,118, 10, 0, 0, 0, 0,
+191, 99,218,142, 61, 75, 4,109,190,232, 3,179, 0, 0, 0, 0,190,204,142,233,191, 16, 64,104, 63, 57, 28,174, 0, 0, 0, 0,
+193, 16,188,238,193, 57,119,229, 65,141,218, 17, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0,190, 96,197,175,191, 99,218,143,190,204,142,235, 0, 0, 0, 0,
+ 63, 5,118, 11,190,232, 3,179, 63, 57, 28,172, 0, 0, 0, 0,191, 83, 27,150,189, 75, 4,119, 63, 16, 64,105, 0, 0, 0, 0,
+193, 14,181,128,191, 61,177,214,193,128,133, 29, 63,128, 0, 0, 0, 0, 4, 28, 20, 0, 0, 0, 0, 0, 0, 68, 0, 5, 0, 1,
+ 0, 0, 0, 0, 79, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,100, 0, 0, 0, 0,
+201,150,180, 56, 63,128, 0, 0, 61, 35,215, 10, 63,128, 0, 0, 62,204,204,205, 0, 0, 0, 0, 61,204,204,205, 0, 0, 0, 0,
+ 4, 0, 0, 0, 1, 0, 0, 0, 63,128, 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, 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, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 79, 66, 0, 0, 3, 16, 5, 31, 20, 32, 0, 0, 0, 90, 0, 0, 0, 1, 5, 31, 24, 32, 5, 31, 16, 32,
+ 0, 0, 0, 0, 0, 0, 0, 0, 79, 66, 76, 97,109,112, 46, 48, 48, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 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, 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, 2,236,175, 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,
+ 64,104,147,176,193, 23, 84, 42, 64,171, 77,116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,103, 90, 85,
+190,186, 45,254, 63,128,209,115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62,255,247,136, 63, 74, 39, 37, 62,182, 26,138,
+ 0, 0, 0, 0,191, 44, 21,164, 61,194, 67, 28, 63, 59,248,176, 0, 0, 0, 0, 63, 11,203,251,191, 27, 45,217, 63, 20, 7, 47,
+ 0, 0, 0, 0, 64,104,147,176,193, 23, 84, 42, 64,171, 77,116, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 62,255,247,137,191, 44, 21,165, 63, 11,203,251,
+ 0, 0, 0, 0, 62,182, 26,141, 63, 59,248,176, 63, 20, 7, 46, 0, 0, 0, 0,191, 74, 39, 37,189,194, 67, 20, 63, 27, 45,217,
+ 0, 0, 0, 0,192, 93, 99, 91,190, 80, 98,136,192,112,119,223, 63,128, 0, 0, 0, 0, 0, 1, 20, 0, 0, 0, 0, 0, 0, 68,
+ 0, 5, 0, 1, 0, 0, 0, 0, 79, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,100,
+ 0, 0, 0, 0,201,150,180, 56, 63,128, 0, 0, 61, 35,215, 10, 63,128, 0, 0, 62,204,204,205, 0, 0, 0, 0, 61,204,204,205,
+ 0, 0, 0, 0, 4, 0, 0, 0, 1, 0, 0, 0, 63,128, 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, 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, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 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, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 79, 66, 0, 0, 3, 16, 5, 31, 24, 32, 0, 0, 0, 90, 0, 0, 0, 1, 5, 31, 28, 32,
+ 5, 31, 20, 32, 0, 0, 0, 0, 0, 0, 0, 0, 79, 66, 76, 97,109,112, 46, 48, 48, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 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, 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, 2,236,176, 48, 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,192,251,147,249,193, 24, 0,206,192,104,131, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,103, 90, 85,190,186, 45,254, 63,128,209,115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62,255,247,136, 63, 74, 39, 37,
+ 62,182, 26,138, 0, 0, 0, 0,191, 44, 21,164, 61,194, 67, 28, 63, 59,248,176, 0, 0, 0, 0, 63, 11,203,251,191, 27, 45,217,
+ 63, 20, 7, 47, 0, 0, 0, 0,192,251,147,249,193, 24, 0,206,192,104,131, 67, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 62,255,247,137,191, 44, 21,165,
+ 63, 11,203,251, 0, 0, 0, 0, 62,182, 26,139, 63, 59,248,176, 63, 20, 7, 45, 0, 0, 0, 0,191, 74, 39, 36,189,194, 67, 19,
+ 63, 27, 45,217, 0, 0, 0, 0, 64,176,142,147,191,170, 22, 97, 64,246, 28, 27, 63,128, 0, 0, 0, 0, 0, 1, 20, 0, 0, 0,
+ 0, 0, 0, 68, 0, 5, 0, 1, 0, 0, 0, 0, 79, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1,
+ 0, 0, 0,100, 0, 0, 0, 0,201,150,180, 56, 63,128, 0, 0, 61, 35,215, 10, 63,128, 0, 0, 62,204,204,205, 0, 0, 0, 0,
+ 61,204,204,205, 0, 0, 0, 0, 4, 0, 0, 0, 1, 0, 0, 0, 63,128, 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, 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, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 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, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 79, 66, 0, 0, 3, 16, 5, 31, 28, 32, 0, 0, 0, 90, 0, 0, 0, 1,
+ 5, 31, 32, 32, 5, 31, 24, 32, 0, 0, 0, 0, 0, 0, 0, 0, 79, 66, 76, 97,109,112, 46, 48, 48, 53, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 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, 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, 2,236,177, 96, 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, 65, 54, 41,142,191,115,124, 24,192, 58,215,162, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,103, 90, 85,190,186, 45,254, 63,128,209,115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62,255,247,136,
+ 63, 74, 39, 37, 62,182, 26,138, 0, 0, 0, 0,191, 44, 21,164, 61,194, 67, 28, 63, 59,248,176, 0, 0, 0, 0, 63, 11,203,251,
+191, 27, 45,217, 63, 20, 7, 47, 0, 0, 0, 0, 65, 54, 41,142,191,115,124, 24,192, 58,215,162, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 62,255,247,136,
+191, 44, 21,164, 63, 11,203,251, 0, 0, 0, 0, 62,182, 26,139, 63, 59,248,175, 63, 20, 7, 46, 0, 0, 0, 0,191, 74, 39, 36,
+189,194, 67, 25, 63, 27, 45,217, 0, 0, 0, 0,193, 49,192,139, 65, 36, 99, 40, 63,249,156, 89, 63,128, 0, 0, 0, 0, 0, 2,
+ 20, 0, 0, 0, 0, 0, 0, 68, 0, 5, 0, 1, 0, 0, 0, 0, 79, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 0,100, 0, 0, 0, 0,201,150,180, 56, 63,128, 0, 0, 61, 35,215, 10, 63,128, 0, 0, 62,204,204,205,
+ 0, 0, 0, 0, 61,204,204,205, 0, 0, 0, 0, 4, 0, 0, 0, 1, 0, 0, 0, 63,128, 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, 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, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+ 63,128, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 79, 66, 0, 0, 3, 16, 5, 31, 32, 32, 0, 0, 0, 90,
+ 0, 0, 0, 1, 5, 31, 36, 32, 5, 31, 28, 32, 0, 0, 0, 0, 0, 0, 0, 0, 79, 66, 76, 97,109,112, 46, 48, 48, 54, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 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, 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, 2,236,178,144, 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,193, 19,239,220,193, 54,239,215, 65, 60, 9, 42, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,191,103,251, 67,191, 24, 27,164, 64, 3,136, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+190,197,143, 31, 63, 59,184,209, 63, 15, 80,138, 0, 0, 0, 0,191, 64, 66, 57, 61,210,119,132,191, 38,249,118, 0, 0, 0, 0,
+191, 9, 43, 37,191, 44, 15, 35, 63, 2,212,114, 0, 0, 0, 0,193, 19,239,220,193, 54,239,215, 65, 60, 9, 42, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0,
+190,197,143, 31,191, 64, 66, 56,191, 9, 43, 35, 0, 0, 0, 0, 63, 15, 80,139,191, 38,249,117, 63, 2,212,112, 0, 0, 0, 0,
+191, 59,184,208,189,210,119,142, 63, 44, 15, 35, 0, 0, 0, 0,193, 0,135,195,190,148,252,127,193, 48,180, 8, 63,128, 0, 0,
+ 0, 0, 0, 2, 20, 0, 0, 0, 0, 0, 0, 68, 0, 5, 0, 1, 0, 0, 0, 0, 79, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,100, 0, 0, 0, 0,201,150,180, 56, 63,128, 0, 0, 61, 35,215, 10, 63,128, 0, 0,
+ 62,204,204,205, 0, 0, 0, 0, 61,204,204,205, 0, 0, 0, 0, 4, 0, 0, 0, 1, 0, 0, 0, 63,128, 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, 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, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0,
+ 63,128, 0, 0, 63,128, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 79, 66, 0, 0, 3, 16, 5, 31, 36, 32,
+ 0, 0, 0, 90, 0, 0, 0, 1, 5, 31, 40, 32, 5, 31, 32, 32, 0, 0, 0, 0, 0, 0, 0, 0, 79, 66, 76, 97,109,112, 46, 48,
+ 48, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 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, 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, 2,236,179,192, 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,192,164, 99,104,193, 51,244,239, 64, 19,110,188, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,103, 90, 85,190,186, 45,254, 63,128,209,115, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,255,247,136, 63, 74, 39, 37, 62,182, 26,138, 0, 0, 0, 0,191, 44, 21,164, 61,194, 67, 28, 63, 59,248,176,
+ 0, 0, 0, 0, 63, 11,203,251,191, 27, 45,217, 63, 20, 7, 47, 0, 0, 0, 0,192,164, 99,104,193, 51,244,239, 64, 19,110,188,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,128, 0, 0, 62,255,247,137,191, 44, 21,165, 63, 11,203,251, 0, 0, 0, 0, 62,182, 26,139, 63, 59,248,178, 63, 20, 7, 45,
+ 0, 0, 0, 0,191, 74, 39, 36,189,194, 67, 18, 63, 27, 45,217, 0, 0, 0, 0, 64, 91, 24, 96,192,108, 50,226, 63,219, 9,101,
+ 63,128, 0, 0, 0, 0, 0, 2, 20, 0, 0, 0, 0, 0, 0, 68, 0, 5, 0, 1, 0, 0, 0, 0, 79, 66, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,100, 0, 0, 0, 0,201,150,180, 56, 63,128, 0, 0, 61, 35,215, 10,
+ 63,128, 0, 0, 62,204,204,205, 0, 0, 0, 0, 61,204,204,205, 0, 0, 0, 0, 4, 0, 0, 0, 1, 0, 0, 0, 63,128, 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, 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, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,128, 0, 0, 63,128, 0, 0, 63,128, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 79, 66, 0, 0, 3, 16,
+ 5, 31, 40, 32, 0, 0, 0, 90, 0, 0, 0, 1, 5, 31, 44, 32, 5, 31, 36, 32, 0, 0, 0, 0, 0, 0, 0, 0, 79, 66, 76, 97,
+109,112, 46, 48, 48, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 10, 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, 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, 2,236,180,240,
+ 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, 63,188, 75,145,193,107,197, 44, 64, 81,147, 5,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,201, 15,218, 37,128, 0, 0, 37,127,255,255, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 37,127,255,255,165,128, 0, 0, 0, 0, 0, 0, 37,127,255,255, 51,162, 33,105,
+ 63,128, 0, 0, 0, 0, 0, 0, 37,128, 0, 0,191,128, 0, 0, 51,162, 33,105, 0, 0, 0, 0, 63,188, 75,145,193,107,197, 44,
+ 64, 81,147, 5, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,178, 23, 25, 45,179, 75,199,107, 0, 0, 0, 0,153,236,127, 0, 63,128, 0, 0,
+ 40, 0, 0, 0, 0, 0, 0, 0,177,108,127, 0, 50, 29, 9,206, 63,128, 0, 0, 0, 0, 0, 0,191,189,159, 32,191,188,164, 47,
+192,153,188,150, 63,128, 0, 0, 0, 0, 0, 32, 16, 0, 0, 0, 0, 0, 0, 68, 0, 5, 0, 1, 0, 0, 0, 0, 79, 66, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,100, 0, 0, 0, 0,201,150,180, 56, 63,128, 0, 0,
+ 61, 35,215, 10, 63,128, 0, 0, 62,204,204,205, 0, 0, 0, 0, 61,204,204,205, 0, 0, 0, 0, 4, 0, 0, 0, 1, 0, 0, 0,
+ 63,128, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 79, 66,
+ 0, 0, 3, 16, 5, 31, 44, 32, 0, 0, 0, 90, 0, 0, 0, 1, 5, 31, 48, 32, 5, 31, 40, 32, 0, 0, 0, 0, 0, 0, 0, 0,
+ 79, 66, 99,104,101, 99,107,101,114,115, 0, 0,108, 97,110,101, 46, 48, 48, 51, 0, 0, 0, 0, 0, 1, 4, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 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, 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,
+ 2,236,228, 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, 2,233, 65, 80, 60,102,131, 0, 64,164,112, 14,
+ 63,229,211, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 34,159,178,
+ 65, 34,159,178, 65, 34,159,177, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 0, 0, 0,178, 89,250,166,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 34,159,178,180, 10,120,151, 0, 0, 0, 0, 0, 0, 0, 0, 52, 10,120,151,
+ 65, 34,159,178, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 34,159,177, 0, 0, 0, 0, 60,102,131, 0,
+ 64,164,112, 14, 63,229,211, 24, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 61,201,126,231, 48,171,145,219,163,201, 66, 34, 0, 0, 0, 0,164,167,209, 65,
+ 49,255, 57, 51, 61,201,126,232, 0, 0, 0, 0, 48,172, 66,235,189,201,126,231, 49,251,201, 70, 0, 0, 0, 0,187, 29,136, 18,
+191,189,200,203, 58, 9,139,180, 63,128, 0, 0, 0, 0, 0, 33, 0, 0, 0, 1, 0, 0, 0, 68, 0, 1, 0, 2, 0, 0, 0, 0,
+ 79, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,100, 0, 0, 0, 0,201,150,180, 56,
+ 63,128, 0, 0, 61, 35,215, 10, 63,128, 0, 0, 62,204,204,205, 0, 0, 0, 0, 61,204,204,205, 0, 0, 0, 0, 4, 0, 1, 1,
+ 1, 0, 0, 0, 63,128, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 64, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 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, 2,232,181,208, 2,233, 28, 32, 0, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65, 0, 0, 0, 4, 2,233, 65, 80, 0, 0, 0, 0, 0, 0, 0, 1, 2,236,189, 96, 0, 0, 79, 66, 0, 0, 3, 16,
+ 5, 31, 48, 32, 0, 0, 0, 90, 0, 0, 0, 1, 5, 31, 52, 32, 5, 31, 44, 32, 0, 0, 0, 0, 0, 0, 0, 0, 79, 66,112,114,
+101,118,105,101,119, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 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, 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, 2,236,248,224,
+ 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, 2,230, 32,176,189, 7, 82,100,191,103,204, 21, 63,230,165,241,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64,155, 39,153, 64,155, 39,153,
+ 64,155, 39,153, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,201, 15,218, 37,192, 0, 0, 36,255,255,255, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 64,155, 39,153, 38, 27, 39,152,166,232,187,102, 0, 0, 0, 0, 38,232,187,102, 52,196,134,157,
+ 64,155, 39,153, 0, 0, 0, 0, 38, 27, 39,154,192,155, 39,153, 52,196,134,157, 0, 0, 0, 0,189, 7, 82,100,191,103,204, 21,
+ 63,230,165,241, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,128, 0, 0, 62, 83, 50, 25, 35,211, 50, 28,163,211, 50, 23, 0, 0, 0, 0,163,211, 50, 27, 62, 83, 50, 25,
+ 38,174, 59,158, 0, 0, 0, 0,173,204, 94, 0,175, 96, 79,158, 62, 83, 50, 25, 0, 0, 0, 0, 59,153, 62,135,185,110, 94,217,
+ 63,238, 71,118, 63,128, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 68, 0, 1, 0, 2, 0, 0, 0, 0, 79, 66, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,100, 0, 0, 0, 0,201,150,180, 56, 63,128, 0, 0,
+ 61, 35,215, 10, 63,128, 0, 0, 62,204,204,205, 0, 0, 0, 0, 61,204,204,205, 0, 0, 0, 0, 4, 0, 1, 1, 1, 0, 0, 0,
+ 63,128, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 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, 2,235,168, 32, 2,235,172,208, 0, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+ 0, 0, 0, 4, 2,230, 32,176, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 79, 66, 0, 0, 3, 16, 5, 31, 52, 32,
+ 0, 0, 0, 90, 0, 0, 0, 1, 5, 31, 56, 32, 5, 31, 48, 32, 0, 0, 0, 0, 0, 0, 0, 0, 79, 66,112,114,101,118,105,101,
+119, 46, 48, 48, 50, 0, 46, 48, 48, 49, 0, 0, 0, 0, 0, 0, 0, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 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, 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, 2,236,203,160, 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, 2,236,187, 48, 2,236,187, 48, 2,233, 41,192,191,213,187,242, 63,134,145,194, 64, 35,100,254, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 28, 0,243, 65, 28, 0,246, 65, 28, 0,243,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,135,110, 48, 62, 59,169,180,191, 1,115,138, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 65, 6, 49,198,192,148,154,115,191,227,113, 3, 0, 0, 0, 0, 64,106,250,159, 64, 91,207,189, 65, 5,170, 80,
+ 0, 0, 0, 0,192, 86,151, 46,192,251, 94,125, 64,150,127,188, 0, 0, 0, 0,191,213,187,242, 63,134,145,194, 64, 35,100,254,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,128, 0, 0, 61,180,174,143, 61, 30, 48,160,189, 16,118,223, 0, 0, 0, 0,188,153, 29,162, 61,179,248, 38, 61, 74,162,115,
+ 0, 0, 0, 0, 61, 72, 21, 15,189, 19,250,160, 61,169, 57, 88, 0, 0, 0, 0, 63, 50,107, 4,190,204, 46, 88, 63, 79,206,177,
+ 63,128, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 68, 0, 1, 0, 2, 0, 0, 0, 0, 79, 66, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,100, 0, 0, 0, 0,201,150,180, 56, 63,128, 0, 0, 61, 35,215, 10,
+ 63,128, 0, 0, 62,204,204,205, 0, 0, 0, 0, 61,204,204,205, 0, 0, 0, 0, 4, 0, 1, 1, 1, 0, 0, 0, 63,128, 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, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 1, 0, 0, 0,
+ 63,128, 0, 0, 63,128, 0, 0, 63,128, 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, 2,230, 90, 96, 2,235, 93,240, 0, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 4,
+ 2,233, 41,192, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 68, 2,236,187, 48, 0, 0, 0, 69,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 31, 83,117, 98,115,117,114,102, 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, 1, 0, 1, 0, 8,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 79, 66, 0, 0, 3, 16, 5, 31, 56, 32, 0, 0, 0, 90, 0, 0, 0, 1, 5, 31, 60, 32,
+ 5, 31, 52, 32, 0, 0, 0, 0, 0, 0, 0, 0, 79, 66,112,114,101,118,105,101,119, 46, 48, 48, 51, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 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, 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, 2,236,243,224, 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,
+ 2,230, 42, 80,187,203,194, 16, 63, 45, 89,155, 63,230,153,244, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 72,135, 56, 63, 72,135, 56, 63, 72,135, 56, 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, 63,128, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 72,135, 56, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 72,135, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 72,135, 56, 0, 0, 0, 0,187,203,194, 16, 63, 45, 89,155, 63,230,153,244, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,163,104,144, 37,163,104,143,
+165,163,104,143, 0, 0, 0, 0, 37,165,104, 66, 51,206,250,252, 63,163,104,144, 0, 0, 0, 0,173,202,240, 60,191,163,104,144,
+ 51,204, 63,183, 0, 0, 0, 0,187,173, 93,105,193, 88,176,172,186,118, 52, 95, 63,128, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0,
+ 0, 0, 0, 68, 0, 1, 0, 2, 0, 0, 0, 0, 79, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1,
+ 0, 0, 0,100, 0, 0, 0, 0,201,150,180, 56, 63,128, 0, 0, 61, 35,215, 10, 63,128, 0, 0, 62,204,204,205, 0, 0, 0, 0,
+ 61,204,204,205, 0, 0, 0, 0, 4, 0, 1, 1, 1, 0, 0, 0, 63,128, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 32, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 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, 2,236, 8,208, 2,236, 13,128,
+ 0, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 4, 2,230, 42, 80, 0, 0, 0, 0, 0, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 79, 66, 0, 0, 3, 16, 5, 31, 60, 32, 0, 0, 0, 90, 0, 0, 0, 1, 5, 31, 64, 32, 5, 31, 56, 32,
+ 0, 0, 0, 0, 0, 0, 0, 0, 79, 66,112,114,101,118,105,101,119, 46, 48, 48, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 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, 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, 2,236,243,224, 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, 2,233,103, 32,
+ 58, 10, 31, 0, 63,236, 94, 59, 63,231, 84,236, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,110,188, 91, 63,110,188, 91, 63,110,188, 91, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,201, 15,218,
+128, 0, 0, 0,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,110,188, 91, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 51,151, 50, 90, 63,110,188, 91, 0, 0, 0, 0, 0, 0, 0, 0,191,110,188, 91, 51,151, 50, 90,
+ 0, 0, 0, 0, 58, 10, 31, 0, 63,236, 94, 59, 63,231, 84,236, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,137, 65,160,165,137, 65,159,165,137, 65,161,
+ 0, 0, 0, 0, 37,137, 65,160, 63,137, 65,160, 40, 19, 46,157, 0, 0, 0, 0, 45, 14,127,248,176,150,195,159, 63,137, 65,161,
+ 0, 0, 0, 0,188, 63, 80, 29,187,226, 95, 62, 65, 74, 19, 87, 63,128, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 68,
+ 0, 1, 0, 2, 0, 0, 0, 0, 79, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,100,
+ 0, 0, 0, 0,201,150,180, 56, 63,128, 0, 0, 61, 35,215, 10, 63,128, 0, 0, 62,204,204,205, 0, 0, 0, 0, 61,204,204,205,
+ 0, 0, 0, 0, 4, 0, 1, 1, 1, 0, 0, 0, 63,128, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,128, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 32, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 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, 2,235,222, 64, 2,235,117, 16, 0, 0, 0, 25,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 4, 2,233,103, 32, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 79, 66, 0, 0, 3, 16, 5, 31, 64, 32, 0, 0, 0, 90, 0, 0, 0, 1, 5, 31, 68, 32, 5, 31, 60, 32, 0, 0, 0, 0,
+ 0, 0, 0, 0, 79, 66,112,114,101,118,105,101,119, 46, 48, 48, 53, 0, 48, 48, 51, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 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, 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, 2,236,171,112, 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,189,195,155,128,
+ 64,188,145, 20, 65, 88,220, 94, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,134,180,221, 37,141,190, 48,
+ 35, 57, 55,253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 35, 57, 55,253,165,141,190, 48, 0, 0, 0, 0,
+ 37,112,128,219, 62,253,177, 52, 63, 94, 93, 94, 0, 0, 0, 0, 37, 22,133, 52,191, 94, 93, 94, 62,253,177, 52, 0, 0, 0, 0,
+189,195,155,128, 64,188,145, 20, 65, 88,220, 94, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 37, 16,252, 23,165, 70,176,196, 0, 0, 0, 0,
+174,231, 90, 80, 63, 94, 93, 94, 62,253,177, 52, 0, 0, 0, 0,172,239, 68, 0,190,253,177, 50, 63, 94, 93, 95, 0, 0, 0, 0,
+ 61,174, 98,150,193,144,101, 85, 64,253,124,196, 63,128, 0, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 0, 0, 68, 0, 5, 0, 1,
+ 0, 0, 0, 0, 79, 66, 0, 0, 0, 7, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,100, 0, 0, 0, 0,
+201,150,180, 56, 63,128, 0, 0, 61, 35,215, 10, 63,128, 0, 0, 62,204,204,205, 0, 0, 0, 0, 61,204,204,205, 0, 0, 0, 0,
+ 4, 0, 0, 0, 1, 0, 0, 0, 63,128, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0,
+ 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 79, 66, 0, 0, 3, 16, 5, 31, 68, 32, 0, 0, 0, 90, 0, 0, 0, 1, 5, 31, 72, 32, 5, 31, 64, 32,
+ 0, 0, 0, 0, 0, 0, 0, 0, 79, 66,112,114,101,118,105,101,119, 46, 48, 48, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 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, 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, 2,237, 7, 80, 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, 2,228, 97, 96,
+190,252, 52, 94, 65,228,101,174, 65, 17,116,141, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 66, 30,239,235, 66, 30,239,236, 66, 30,239,235, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 95,174,138,
+ 37,123,132, 98,165, 87, 56, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66, 30,239,235,168, 5,158,105,168, 28, 39,108,
+ 0, 0, 0, 0, 40, 77,129,212, 65,204, 15, 66, 65,243,186,158, 0, 0, 0, 0,165, 13, 89, 55,193,243,186,156, 65,204, 15, 65,
+ 0, 0, 0, 0,190,252, 52, 94, 65,228,101,174, 65, 17,116,141, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 60,206, 43,101, 34,240,217,143,163, 18,165,201,
+ 0, 0, 0, 0, 31,231, 14,226, 60,158, 20,101, 60,132, 89,193, 0, 0, 0, 0, 34,173, 83,190,188,132, 89,192, 60,158, 20,103,
+ 0, 0, 0, 0, 60, 70,215, 11,191, 67, 43, 61, 63, 31,241,185, 63,128, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 68,
+ 0, 1, 0, 2, 0, 0, 0, 0, 79, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,100,
+ 0, 0, 0, 0,201,150,180, 56, 63,128, 0, 0, 61, 35,215, 10, 63,128, 0, 0, 62,204,204,205, 0, 0, 0, 0, 61,204,204,205,
+ 0, 0, 0, 0, 4, 0, 1, 1, 1, 0, 0, 0, 63,128, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,128, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 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, 2,235,205,112, 2,235,242,224, 0, 0, 0, 25,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 4, 2,228, 97, 96, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 79, 66, 0, 0, 3, 16, 5, 31, 72, 32, 0, 0, 0, 90, 0, 0, 0, 1, 5, 31, 76, 32, 5, 31, 68, 32, 0, 0, 0, 0,
+ 0, 0, 0, 0, 79, 66,112,114,101,118,105,101,119, 99,117, 98,101, 0,117, 98,101, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 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, 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, 2,237, 14,128, 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, 2,233,120, 16, 59, 88,253,128,
+ 63,160,118,220, 64, 37, 15, 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,
+ 64, 68, 88, 84, 64, 68, 88, 84, 64, 68, 88, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62,237,190, 1,190,217,230,108,
+ 63, 52,151, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 8, 38, 67, 63,231,228,191, 63,162, 31,186, 0, 0, 0, 0,
+192, 13,118, 35, 63,220, 61, 2, 63,160, 44, 31, 0, 0, 0, 0, 60,234, 52,166,191,227,223,102, 64, 31,229, 55, 0, 0, 0, 0,
+ 59, 88,253,128, 63,160,118,220, 64, 37, 15, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 62,103,115, 10,190,112,122,201, 59, 71, 17,255, 0, 0, 0, 0,
+ 62, 9,205,116, 62, 8, 36,205, 62,135,232,136, 0, 0, 0, 0,190, 69, 27, 1,190, 59, 50,224, 62, 65,176, 25, 0, 0, 0, 0,
+192, 16,176,110,192, 9, 71,158, 63,244, 90,115, 63,128, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 68, 0, 1, 0, 2,
+ 0, 0, 0, 0, 79, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,100, 0, 0, 0, 0,
+201,150,180, 56, 63,128, 0, 0, 61, 35,215, 10, 63,128, 0, 0, 62,204,204,205, 0, 0, 0, 0, 61,204,204,205, 0, 0, 0, 0,
+ 4, 0, 1, 1, 1, 0, 0, 0, 63,128, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0,
+ 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 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, 2,235,226, 64, 2,235,211, 0, 0, 0, 0, 25, 0, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 4, 2,233,120, 16, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 79, 66,
+ 0, 0, 3, 16, 5, 31, 76, 32, 0, 0, 0, 90, 0, 0, 0, 1, 5, 31, 80, 32, 5, 31, 72, 32, 0, 0, 0, 0, 0, 0, 0, 0,
+ 79, 66,112,114,101,118,105,101,119,104, 97,105,114, 0,108, 97,110,101, 0, 0, 0, 0, 0, 0, 0, 1, 4, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 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, 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,
+ 2,236,237,192, 0, 0, 0, 0, 0, 0, 0, 0, 2,236,187,160, 2,236,187,160, 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, 2,228, 54, 96, 63,200, 92, 86, 63,227,205, 7,
+189, 9,199,149, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 47,126,234,
+ 64, 47,126,234, 64, 47,126,236, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 2, 80,225,191, 15,211, 5, 62, 18,219, 92,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 18,254,224, 62,169,209, 23, 63,186,251, 27, 0, 0, 0, 0,191,133,254, 71,
+ 64, 17, 40,207, 63,144,194,229, 0, 0, 0, 0,191,137, 38, 78,191,192,162, 48, 64, 1,176,125, 0, 0, 0, 0, 63,200, 92, 86,
+ 63,227,205, 7,189, 9,199,149, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 62,156,100,244,190, 14,143,135,190, 17,235, 52, 0, 0, 0, 0, 62, 70,239,175,
+ 62, 26, 4,102, 62,137,251, 72, 0, 0, 0, 0,189, 52,172,174,190,154,112,211, 62, 76,243, 67, 0, 0, 0, 0,191, 36, 56,149,
+192, 66, 98,139, 64, 68, 5,168, 63,128, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 68, 0, 1, 0, 2, 0, 0, 0, 0,
+ 79, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,100, 0, 0, 0, 0,201,150,180, 56,
+ 63,128, 0, 0, 61, 35,215, 10, 63,128, 0, 0, 62,204,204,205, 0, 0, 0, 0, 61,204,204,205, 0, 0, 0, 0, 4, 0, 1, 1,
+ 1, 0, 0, 0, 63,128, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 64, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 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, 2,236,189, 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, 25, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65, 0, 0, 0, 4, 2,228, 54, 96, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 1, 56,
+ 2,236,187,160, 0, 0, 0,153, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 13, 0, 1, 0, 1, 0, 0, 0, 0,
+ 63,128, 0, 0, 66,200, 0, 0, 66, 72, 0, 0, 0, 0, 0,150, 0, 0, 0, 8, 0, 0, 0, 0, 61,125,243, 64, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,189, 35,214,240, 0, 0, 0, 0,189,196,155,184, 0, 0, 0, 0, 61, 76,204,205,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 66, 72, 0, 0, 66, 72, 0, 0, 66, 72, 0, 0, 66, 72, 0, 0, 0, 4, 0, 4, 0, 4, 0, 4,
+ 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 5, 0, 1, 0, 1, 0, 8, 0, 0, 0, 0, 0,100, 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, 0, 0, 0, 62,156,100,244,
+190, 14,143,134,190, 17,235, 52, 0, 0, 0, 0, 61, 52,172,172, 62,154,112,211,190, 76,243, 69, 0, 0, 0, 0, 62, 70,239,176,
+ 62, 26, 4,102, 62,137,251, 73, 0, 0, 0, 0,191, 12,211,188,190,160,176,198, 63, 22,156, 56, 63,128, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 44, 2,236,189, 0, 0, 0, 0, 92, 0, 0, 0, 1, 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, 61,204,204,205, 62, 76,204,205,
+ 60,163,215, 10, 0, 0, 79, 66, 0, 0, 3, 16, 5, 31, 80, 32, 0, 0, 0, 90, 0, 0, 0, 1, 0, 0, 0, 0, 5, 31, 76, 32,
+ 0, 0, 0, 0, 0, 0, 0, 0, 79, 66,116,101,120,116,117,114,101, 0,114,101,118,105,101,119, 46, 48, 48, 53, 0, 0, 0, 0,
+ 0, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 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, 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, 2,237, 0, 32, 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, 2,228,195, 96,
+188,183, 16, 61,191,103,204, 21, 63,228,234, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 64,155, 39,153, 64,155, 39,153, 64,155, 39,153, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,201, 15,218,
+ 37,192, 0, 0, 36,255,255,255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64,155, 39,153, 38, 27, 39,152,166,232,187,102,
+ 0, 0, 0, 0, 38,232,187,102, 52,196,134,157, 64,155, 39,153, 0, 0, 0, 0, 38, 27, 39,154,192,155, 39,153, 52,196,134,157,
+ 0, 0, 0, 0,188,183, 16, 61,191,103,204, 21, 63,228,234, 48, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 62, 83, 50, 25, 35,211, 50, 28,163,211, 50, 23,
+ 0, 0, 0, 0,163,211, 50, 27, 62, 83, 50, 25, 38,174, 59,158, 0, 0, 0, 0,173, 44, 24, 0,175, 94,165,224, 62, 83, 50, 25,
+ 0, 0, 0, 0, 59, 33,251,236, 59, 40, 37,135, 63,238, 71,118, 63,128, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 68,
+ 0, 1, 0, 2, 0, 0, 0, 0, 79, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,100,
+ 0, 0, 0, 0,201,150,180, 56, 63,128, 0, 0, 61, 35,215, 10, 63,128, 0, 0, 62,204,204,205, 0, 0, 0, 0, 61,204,204,205,
+ 0, 0, 0, 0, 4, 0, 1, 1, 1, 0, 0, 0, 63,128, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,128, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 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, 2,235, 92,192, 2,235,104,176, 0, 0, 0, 25,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 4, 2,228,195, 96, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 77, 65, 0, 0, 1,184, 2,236,189, 96, 0, 0, 0, 38, 0, 0, 0, 1, 2,236,191,224, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 77, 65, 99,104,101, 99,107,101,114,100, 97,114,107, 0, 0, 0, 97,116,101,114,105, 97, 0, 0, 0, 2, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 1, 61,221, 1,116, 61,220,251,200, 61,220,251,200, 63,128, 0, 0, 63,128, 0, 0,
+ 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0,
+ 63, 89,153,154, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63, 76,204,205, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,160, 0, 0, 0, 0, 0, 0, 63,160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,128, 0, 0, 0, 2, 0, 2, 0, 1, 0, 6, 1, 64, 0, 3, 1, 64, 0, 3, 0, 1, 0, 4, 0, 12, 0, 4, 63, 0, 0, 0,
+ 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 64,128, 0, 0, 63, 0, 0, 0,
+ 61,204,204,205, 63, 0, 0, 0, 61,204,204,205, 61,204,204,205, 63,128, 0, 0, 8, 16, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 2,236,191, 64, 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, 63, 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, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,120, 2,236,191, 64, 0, 0, 0, 29, 0, 0, 0, 1,
+ 0, 16, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2,236,202,112, 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, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,192, 0, 1, 63,192, 0, 1, 63,192, 0, 1, 0, 0, 0, 0, 56,209,183, 23, 56,209,177,184, 56,209,177,184, 63,128, 0, 0,
+ 63,128, 0, 0, 63,128, 0, 0, 63, 0, 0, 0, 63,128, 0, 0, 62, 76,204,205, 0, 0, 0, 0, 0, 0, 77, 65, 0, 0, 1,184,
+ 2,236,191,224, 0, 0, 0, 38, 0, 0, 0, 1, 2,236,194, 96, 2,236,189, 96, 0, 0, 0, 0, 0, 0, 0, 0, 77, 65, 99,104,
+101, 99,107,101,114,108,105,103,104,116, 0, 0, 0, 97,116,101,114,105, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 3, 0, 1, 62,157, 65,188, 62,157, 61,178, 62,157, 61,178, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 63, 89,153,154, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63, 76,204,205, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,160, 0, 0, 0, 0, 0, 0, 63,160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61,204,204,205, 0, 2, 0, 2,
+ 0, 1, 0, 6, 1, 64, 0, 3, 1, 64, 0, 3, 0, 1, 0, 4, 0, 12, 0, 4, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+ 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0,
+ 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 64,128, 0, 0, 63, 0, 0, 0, 61,204,204,205, 63, 0, 0, 0,
+ 61,204,204,205, 61,204,204,205, 63,128, 0, 0, 8, 16, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,128, 0, 0, 63,128, 0, 0, 2,236,193,192, 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, 63, 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, 0, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,120, 2,236,193,192, 0, 0, 0, 29, 0, 0, 0, 1, 0, 16, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 2,236,202,112, 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, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 56,209,183, 23, 56,209,177,184, 56,209,177,184, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+ 63, 0, 0, 0, 63,128, 0, 0, 62, 76,204,205, 0, 0, 0, 0, 0, 0, 77, 65, 0, 0, 1,184, 2,236,194, 96, 0, 0, 0, 38,
+ 0, 0, 0, 1, 2,236,196,224, 2,236,191,224, 0, 0, 0, 0, 0, 0, 0, 0, 77, 65,112,114,101,118,105,101,119, 0, 0, 97,
+116,101,114,105, 97,108, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 63,128, 0, 0,
+ 63, 54,232, 61, 63, 23,161,184, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 62, 68,248,188,
+ 63,128, 0, 0, 63, 76,204,205, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,130,121,198, 63,160, 0, 0,
+ 0, 0, 0, 0, 63,160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61,204,204,205, 0, 2, 0, 2, 0, 50, 0, 6, 3, 17, 0, 3,
+ 3, 17, 0, 3, 0, 1, 0, 4, 0, 12, 0, 4, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 2,
+ 0, 0, 0, 0, 63, 0, 0, 0, 64,128, 0, 0, 63, 0, 0, 0, 61,204,204,205, 63, 0, 0, 0, 61,204,204,205, 61,204,204,205,
+ 63,128, 0, 0, 8, 1, 0, 1, 5, 31, 84, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+ 2,236,196, 64, 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, 63, 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, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+ 0, 0, 0,120, 2,236,196, 64, 0, 0, 0, 29, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2,236,201, 64,
+ 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,
+ 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 16, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63, 0, 0, 0, 63,128, 0, 0,
+ 62, 76,204,205, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 3, 8, 5, 31, 84, 32, 0, 0, 0, 32, 0, 0, 0, 1, 0, 0, 0, 2,
+ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62,220, 40,245, 0, 0, 0, 0, 63,125,112,164,
+ 63,128, 0, 0, 63, 24,214,106, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 1, 63, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0,
+ 63,128, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63,128, 0, 0, 63, 0, 0, 0,
+ 0, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63,128, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0,
+ 63, 0, 0, 0, 63, 0, 0, 0, 63,128, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0,
+ 63,128, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63,128, 0, 0, 63, 0, 0, 0,
+ 0, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63,128, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0,
+ 63, 0, 0, 0, 63, 0, 0, 0, 63,128, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0,
+ 63,128, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63,128, 0, 0, 63, 0, 0, 0,
+ 0, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63,128, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0,
+ 63, 0, 0, 0, 63, 0, 0, 0, 63,128, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0,
+ 63,128, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63,128, 0, 0, 63, 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, 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, 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, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 77, 65, 0, 0, 1,184, 2,236,196,224, 0, 0, 0, 38, 0, 0, 0, 1, 2,236,199, 96, 2,236,194, 96,
+ 0, 0, 0, 0, 0, 0, 0, 0, 77, 65,116,101,120,116,117,114,101, 0,114,101,118,105,101,119, 46, 48, 48, 49, 0, 0, 0, 0,
+ 0, 1, 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, 63,128, 0, 0,
+ 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 76,204,205, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,160, 0, 0, 0, 0, 0, 0, 63,160, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 61,204,204,205, 0, 2, 0, 2, 0, 50, 0, 6, 3, 1, 0, 71, 3, 1, 0, 67, 0, 1, 0, 4, 0, 12, 0, 4,
+ 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 2, 0, 0, 0, 0, 63, 0, 0, 0, 64,128, 0, 0,
+ 63, 0, 0, 0, 61,204,204,205, 63, 0, 0, 0, 61,204,204,205, 61,204,204,205, 63,128, 0, 0, 8, 1, 0,129, 5, 31, 88, 32,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 2,236,198,192, 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, 63, 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, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,120, 2,236,198,192, 0, 0, 0, 29,
+ 0, 0, 0, 1, 0, 1, 0,129, 0, 0, 0, 0, 0, 0, 0, 0, 2,236,201, 64, 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, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 16, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+ 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63, 0, 0, 0, 63,128, 0, 0, 62, 76,204,205, 0, 0, 0, 0, 68, 65, 84, 65,
+ 0, 0, 3, 8, 5, 31, 88, 32, 0, 0, 0, 32, 0, 0, 0, 1, 0, 0, 0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,220, 40,245, 0, 0, 0, 0, 63,125,112,164, 63,128, 0, 0, 63, 24,214,106, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 1, 63, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63,128, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0,
+ 63, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63,128, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0,
+ 63, 0, 0, 0, 63,128, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63,128, 0, 0,
+ 63, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63,128, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0,
+ 63, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63,128, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0,
+ 63, 0, 0, 0, 63,128, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63,128, 0, 0,
+ 63, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63,128, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0,
+ 63, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63,128, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0,
+ 63, 0, 0, 0, 63,128, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63,128, 0, 0,
+ 63, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63,128, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0,
+ 63, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63,128, 0, 0, 63, 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, 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, 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, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 77, 65, 0, 0, 1,184,
+ 2,236,199, 96, 0, 0, 0, 38, 0, 0, 0, 1, 0, 0, 0, 0, 2,236,196,224, 0, 0, 0, 0, 0, 0, 0, 0, 77, 65,116,101,
+120,116,117,114,101, 46, 48, 48, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63, 76,204,205, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,160, 0, 0, 0, 0, 0, 0, 63,160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 2, 0, 2,
+ 0, 50, 0, 6, 3, 1, 0, 3, 3, 1, 0, 3, 0, 1, 0, 4, 0, 12, 0, 4, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+ 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0,
+ 0, 0, 0, 3, 0, 0, 0, 2, 0, 0, 0, 0, 63, 0, 0, 0, 64,128, 0, 0, 63, 0, 0, 0, 61,204,204,205, 63, 0, 0, 0,
+ 61,204,204,205, 61,204,204,205, 63,128, 0, 0, 0, 0, 0, 0, 5, 31, 92, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,128, 0, 0, 63,128, 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, 63, 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, 0, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 3, 8, 5, 31, 92, 32, 0, 0, 0, 32, 0, 0, 0, 1, 0, 0, 0, 2, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62,220, 40,245, 0, 0, 0, 0, 63,125,112,164, 63,128, 0, 0,
+ 63, 24,214,106, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 1, 63, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63,128, 0, 0,
+ 63, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63,128, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0,
+ 63, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63,128, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0,
+ 63, 0, 0, 0, 63,128, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63,128, 0, 0,
+ 63, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63,128, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0,
+ 63, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63,128, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0,
+ 63, 0, 0, 0, 63,128, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63,128, 0, 0,
+ 63, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63,128, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0,
+ 63, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63,128, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0,
+ 63, 0, 0, 0, 63,128, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63,128, 0, 0,
+ 63, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63,128, 0, 0, 63, 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, 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, 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, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 84, 69, 0, 0, 1, 0, 2,236,201, 64, 0, 0, 0, 34, 0, 0, 0, 1, 2,236,202,112, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 84, 69,112,114,101,118,105,101,119, 0,101,120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,128, 0, 0, 64,160, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+ 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 64, 0, 0, 0, 64, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 32, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0,
+ 0, 0, 0, 0, 0, 5, 0, 8, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 1, 0, 1,
+ 0, 3, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 60,204,204,205, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0, 1, 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, 84, 69, 0, 0, 1, 0, 2,236,202,112,
+ 0, 0, 0, 34, 0, 0, 0, 1, 0, 0, 0, 0, 2,236,201, 64, 0, 0, 0, 0, 0, 0, 0, 0, 84, 69,102, 97,107,101,115,104,
+ 97,100,111,119, 0, 0, 76,101,110,100, 0,101,120, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62,128, 0, 0,
+ 64,160, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+ 64, 0, 0, 0, 64, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 64, 32, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 5, 0, 40, 0, 5, 0, 4,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 1, 0, 1, 0, 3, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 60,204,204,205, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0, 1, 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, 77, 69, 0, 0, 1, 20, 2,236,203,160, 0, 0, 0, 50, 0, 0, 0, 1, 2,236,208,112,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 77, 69, 67,117, 98,101, 46, 48, 48, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,235,160,224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 2,233, 45, 16, 5, 31,184, 32, 8,102,176, 32, 8,170,144, 32, 5, 31, 96, 32, 5, 31,136, 32, 0, 0, 0, 0,
+ 5, 31,232, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,236,204,224, 0, 0, 0, 1,
+ 0, 0, 0, 5, 0, 0, 0, 20, 0, 0, 0, 0, 2,236,206, 16, 0, 0, 0, 1, 0, 0, 0, 5, 0, 0, 0, 12, 0, 0, 0, 0,
+ 2,236,207, 64, 0, 0, 0, 3, 0, 0, 0, 5, 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, 1,249, 0, 0, 3,237, 0, 0, 1,244,
+ 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 1, 61, 88,133,192,189, 85, 45,184,190, 24,181,196, 63, 35, 71,185, 62,235, 31,153,
+ 62,203,102,130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 4, 0, 1, 0, 1,
+ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 4, 2,233, 45, 16, 0, 0, 0, 0,
+ 0, 0, 0, 1, 2,236,194, 96, 68, 65, 84, 65, 0, 0, 1, 4, 2,236,204,224, 0, 0, 0,242, 0, 0, 0, 5, 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, 5, 31, 96, 32, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65, 0, 0, 39,116, 5, 31, 96, 32, 0, 0, 0, 56, 0, 0, 1,249, 62,131,144,140, 60,200,163,119, 62, 85, 9,156,
+ 92,125,170, 70, 21,228, 0,255,190, 26,222, 50, 60,200,163,119, 62, 85, 9,156,163,131,170, 70, 21,228, 0,255, 62,146,126, 61,
+188, 8, 37,223, 62, 47,183, 99, 76,247,194,191, 81,228, 2,255,190, 56,185,147,188, 8, 37,223, 62, 47,183, 99,179, 9,194,191,
+ 81,228, 2,255, 62,157,176,129,188,217, 91,211, 61,246,238,244, 84, 31,181,226, 61,191, 2,255,190, 79, 30, 28,188,217, 91,211,
+ 61,246,238,244,171,225,181,226, 61,191, 2,255, 62, 94, 19,115,189,128,251,103, 62, 14, 32,150, 9,241,144,155, 62, 64, 2,255,
+189,227,161, 26,189,128,251,103, 62, 14, 32,150,246, 15,144,155, 62, 64, 2,255, 62, 94, 19,115,189, 25,118,251, 62, 62,165, 20,
+ 14,184,163,144, 87, 76, 2,255,189,227,161, 26,189, 25,118,251, 62, 62,165, 20,241, 72,163,144, 87, 76, 2,255, 62, 94, 19,115,
+ 60, 34,107,232, 62, 92,128,116, 3, 3,131,121, 29,110, 0,255,189,227,161, 26, 60, 34,107,232, 62, 92,128,116,252,253,131,121,
+ 29,110, 0,255, 62, 56,193, 58, 60,200,163,119, 62, 99,247, 77,171, 56,167,117, 36,206, 0,255,189,152,252,168, 60,200,163,119,
+ 62, 99,247, 77, 84,200,167,117, 36,206, 0,255, 62, 23, 42,109,188, 8, 37,223, 62, 73,215, 88,217,152,203,122,110, 56, 0,255,
+ 62, 0,197,229,188,217, 91,211, 62, 29, 14, 71,184,179,175, 93, 69, 66, 2,255,188,164, 23,249,188,217, 91,211, 62, 29, 14, 71,
+ 71, 77,175, 93, 69, 66, 2,255, 61,182,231, 88, 61,121,154,159, 62, 32,201,179,151,181,255,104, 74, 51, 2,255, 60,134,121,207,
+ 61,121,154,159, 62, 32,201,179,104, 75,255,104, 74, 51, 2,255, 61,242,158, 25, 61,121,154,159, 62, 73,215, 88,171, 78,255,150,
+ 95,246, 2,255,188, 80,194,110, 61,121,154,159, 62, 73,215, 88, 84,178,255,150, 95,246, 2,255, 62, 41,211,138, 61,121,154,159,
+ 62, 99,247, 77,133,152,254,153, 37, 98, 0,255,189,118, 66,143, 61,121,154,159, 62, 99,247, 77,122,104,254,153, 37, 98, 0,255,
+ 62, 56,193, 58, 61,206,232,154, 62, 99,247, 77,170, 24, 88, 13, 35, 89, 0,255,189,152,252,168, 61,206,232,154, 62, 99,247, 77,
+ 85,232, 88, 13, 35, 89, 0,255, 62, 23, 42,109, 62, 5, 79,173, 62, 73,215, 88,200,249, 65,221, 94,244, 2,255,189, 43,158, 31,
+ 62, 5, 79,173, 62, 73,215, 88, 55, 7, 65,221, 94,244, 2,255, 62, 0,197,229, 62, 27,180, 54, 62, 29, 14, 71,186, 51, 78, 86,
+ 73, 78, 2,255,188,164, 23,249, 62, 27,180, 54, 62, 29, 14, 71, 69,205, 78, 86, 73, 78, 2,255, 62, 94, 19,115, 62, 65, 6,111,
+ 62, 14, 32,150, 11, 2,107,152, 68,114, 2,255,189,227,161, 26, 62, 65, 6,111, 62, 14, 32,150,244,254,107,152, 68,114, 2,255,
+ 62, 94, 19,115, 62, 35, 43, 14, 62, 62,165, 20, 14,201, 91,180, 88, 14, 2,255,189,227,161, 26, 62, 35, 43, 14, 62, 62,165, 20,
+241, 55, 91,180, 88, 14, 2,255, 62, 94, 19,115, 61,236,195,250, 62, 92,128,116, 2,134,125, 29, 26,228, 0,255,189,227,161, 26,
+ 61,236,195,250, 62, 92,128,116,253,122,125, 29, 26,228, 0,255, 62,131,144,140, 61,206,232,154, 62, 85, 9,156, 93, 54, 85, 67,
+ 20,154, 0,255,190, 26,222, 50, 61,206,232,154, 62, 85, 9,156,162,202, 85, 67, 20,154, 0,255, 62,146,126, 61, 62, 5, 79,173,
+ 62, 47,183, 99, 76,241, 60,161, 82, 97, 2,255,190, 56,185,147, 62, 5, 79,173, 62, 47,183, 99,179, 15, 60,161, 82, 97, 2,255,
+ 62,157,176,129, 62, 27,180, 54, 61,246,238,244, 83,179, 71,157, 65, 45, 2,255,190, 79, 30, 28, 62, 27,180, 54, 61,246,238,244,
+172, 77, 71,157, 65, 45, 2,255, 62,176, 89,157, 61,121,154,159, 61,232, 1, 67,111, 40,255,113, 63,117, 2,255,190,116,112, 84,
+ 61,121,154,159, 61,232, 1, 67,144,216,255,113, 63,117, 2,255, 62,161,107,237, 61,121,154,159, 62, 40, 64,139,100, 48,255,154,
+ 79,167, 2,255,190, 86,148,244, 61,121,154,159, 62, 40, 64,139,155,208,255,154, 79,167, 2,255, 62,139, 7,100, 61,121,154,159,
+ 62, 81, 78, 48,126,117,254,181, 19,185, 0,255,190, 41,203,227, 61,121,154,159, 62, 81, 78, 48,129,139,254,181, 19,185, 0,255,
+ 62,140,229, 26, 61,121,154,159, 62, 88,197, 8,120,160,254,106, 42,198, 2,255,190, 45,135, 79, 61,121,154,159, 62, 88,197, 8,
+135, 96,254,106, 42,198, 2,255, 62,133,110, 66, 61,214, 95,114, 62, 92,128,116, 93,173, 74,126, 45, 93, 2,255,190, 30,153,158,
+ 61,214, 95,114, 62, 92,128,116,162, 83, 74,126, 45, 93, 2,255, 62, 94, 19,115, 61,251,177,170, 62,103,178,185, 11, 9,115, 31,
+ 54,216, 2,255,189,227,161, 26, 61,251,177,170, 62,103,178,185,244,247,115, 31, 54,216, 2,255, 62, 53, 5,206, 61,214, 95,114,
+ 62,111, 41,145,181, 9, 80,184, 65, 43, 2,255,189,145,133,208, 61,214, 95,114, 62,111, 41,145, 74,247, 80,184, 65, 43, 2,255,
+ 62, 34, 92,178, 61,121,154,159, 62,111, 41,145,146,116,254, 57, 66, 43, 2,255,189, 88,103, 48, 61,121,154,159, 62,111, 41,145,
+109,140,254, 57, 66, 43, 2,255, 62, 53, 5,206, 60,170,200, 22, 62,111, 41,145,182, 34,173,181, 64,115, 2,255,189,145,133,208,
+ 60,170,200, 22, 62,111, 41,145, 73,222,173,181, 64,115, 2,255, 62, 94, 19,115, 61,121,154,159, 62,114,228,253, 24, 74,255,139,
+125,171, 2,255,189,227,161, 26, 61,121,154,159, 62,114,228,253,231,182,255,139,125,171, 2,255, 62, 94, 19,115, 59, 43,249,149,
+ 62,103,178,185, 10,218,140,140, 54, 45, 2,255,189,227,161, 26, 59, 43,249,149, 62,103,178,185,245, 38,140,140, 54, 45, 2,255,
+ 62,133,110, 66, 60,170,200, 22, 62, 92,128,116, 92,141,179,203, 44,210, 2,255,190, 30,153,158, 60,170,200, 22, 62, 92,128,116,
+163,115,179,203, 44,210, 2,255, 61, 88,133,203, 62, 23,248,202, 62, 73,215, 88, 0, 0,124, 43, 31, 17, 0,255, 61, 88,133,203,
+ 61,229, 77, 34, 62,111, 41,145, 0, 0,249, 63,127,209, 0,255, 61, 88,133,203,190,188,254,150, 62, 70, 27,236, 0, 0,251,204,
+127,237, 0,255, 61, 88,133,203,190, 78, 79,191, 62, 92,128,116, 0, 0,150, 33, 71,238, 2,255, 61, 88,133,203,190, 14,221,146,
+ 62, 99,247, 77, 0, 0,100, 28, 79,192, 0,255, 61, 88,133,203,190,211, 99, 30, 62, 62,165, 20, 0, 0,142,184, 59,147, 2,255,
+ 61, 88,133,203, 62, 12,198,133, 62, 6,169,190, 0, 0,103,143, 75, 57, 0,255, 61, 88,133,203, 62, 91, 38, 99, 61,239,120, 28,
+ 0, 0, 78,115,101, 34, 0,255, 61, 88,133,203, 62,187,243, 16,190,206,250,170, 0, 0,110,190,191,212, 2,255, 61, 88,133,203,
+ 62, 87,106,247,191, 11,224,178, 0, 0, 35,144,133, 12, 3,255, 61, 88,133,203,188,157,165, 18,191, 9, 20, 33, 0, 0,214,194,
+134,213, 2,255, 61, 88,133,203,190,108, 43, 32,190,160, 83,227, 0, 0,134,154,215,113, 2,255, 62, 23, 42,109,190, 14,221,146,
+ 61,232, 1, 67,113,144,198,122, 13, 79, 0,255,189, 43,158, 31,190, 14,221,146, 61,232, 1, 67,142,112,198,122, 13, 79, 0,255,
+ 62, 75,106, 87,190,131, 37,138, 61,239,120, 28,122,196, 31, 19, 18,152, 2,255,189,190, 78,225,190,131, 37,138, 61,239,120, 28,
+133, 60, 31, 19, 18,152, 2,255, 62, 94, 19,115,190,192,186, 2, 61,239,120, 28,125,167, 12,146, 20,226, 0,255,189,227,161, 26,
+190,192,186, 2, 61,239,120, 28,130, 89, 12,146, 20,226, 0,255, 62,101,138, 75,190,239, 96,200, 61,202, 37,227,124,113,242,142,
+ 26,196, 2,255,189,242,142,203,190,239, 96,200, 61,202, 37,227,131,143,242,142, 26,196, 2,255, 62, 82,225, 47,190,252,112,195,
+ 61,194,175, 10, 79,159,159, 44, 25,210, 2,255,189,205, 60,146,190,252,112,195, 61,194,175, 10,176, 97,159, 44, 25,210, 2,255,
+ 62, 11,248, 41,191, 1, 4,242, 61,224,138,107, 19,143,131, 13, 19,178, 2,255,188,253,170, 27,191, 1, 4,242, 61,224,138,107,
+236,113,131, 13, 19,178, 2,255, 61, 88,133,203,191, 2,226,168, 61,246,238,244, 0, 0,130, 75, 24, 21, 2,255, 62,131,144,140,
+189,240,242, 18, 61,202, 37,227, 47,114,137,117, 8,232, 2,255,190, 26,222, 50,189,240,242, 18, 61,202, 37,227,208,142,137,117,
+ 8,232, 2,255, 62,178, 55, 83,189,143,233, 23, 61,209,156,187, 77, 25,154,198, 13,214, 2,255,190,120, 43,193,189,143,233, 23,
+ 61,209,156,187,178,231,154,198, 13,214, 2,255, 62,224,222, 26, 60,140,236,182, 61,112, 21, 49,113,216,198,247, 12,255, 2,255,
+190,170,188,167, 60,140,236,182, 61,112, 21, 49,142, 40,198,247, 12,255, 2,255, 62,232, 84,243, 62, 23,248,202, 62, 2,238, 82,
+113,104, 51, 31, 30, 32, 2,255,190,178, 51,128, 62, 23,248,202, 62, 2,238, 82,142,152, 51, 31, 30, 32, 2,255, 62,196,224,112,
+ 62, 50, 24,190, 62, 17,220, 2, 64,216,106,225, 27,121, 0,255,190,142,190,253, 62, 50, 24,190, 62, 17,220, 2,191, 40,106,225,
+ 27,121, 0,255, 62,144,160,134, 62,106, 20, 20, 62, 47,183, 99, 75,137,101, 82, 20, 70, 0,255,190, 52,254, 39, 62,106, 20, 20,
+ 62, 47,183, 99,180,119,101, 82, 20, 70, 0,255, 62, 79, 37,195, 62,154, 92, 67, 62, 70, 27,236, 38,241,119, 19, 26, 54, 2,255,
+189,197,197,186, 62,154, 92, 67, 62, 70, 27,236,217, 15,119, 19, 26, 54, 2,255, 62, 0,197,229, 62,145, 7,181, 62, 81, 78, 48,
+175, 21, 96, 54, 24, 12, 2,255,188,164, 23,249, 62,145, 7,181, 62, 81, 78, 48, 80,235, 96, 54, 24, 12, 2,255, 61,167,249,168,
+ 62, 53,212, 42, 62, 77,146,196,155,174, 76,128, 21,151, 0,255, 60,194, 48,144, 62, 53,212, 42, 62, 77,146,196,100, 82, 76,128,
+ 21,151, 0,255, 62, 4,129, 81, 62, 16,129,241, 62, 88,197, 8, 25, 0,237, 4,124, 22, 0,255,188,193,243, 89, 62, 16,129,241,
+ 62, 88,197, 8,231, 0,237, 4,124, 22, 0,255, 61,227,176,105, 61,184,132, 17, 62, 85, 9,156,255,160,232,126,125,209, 0,255,
+187,178,169,214, 61,184,132, 17, 62, 85, 9,156, 0, 96,232,126,125,209, 0,255,189, 43,158, 31,188, 8, 37,223, 62, 73,215, 88,
+ 38,104,203,122,110, 56, 0,255, 62,105, 69,184,189, 55, 82, 92, 62, 55, 46, 59, 34,106,200,119,110, 16, 0,255,189,250, 5,163,
+189, 55, 82, 92, 62, 55, 46, 59,221,150,200,119,110, 16, 0,255, 62,144,160,134,188,187,128,115, 62, 40, 64,139, 55,161,207, 60,
+104,115, 0,255,190, 52,254, 39,188,187,128,115, 62, 40, 64,139,200, 95,207, 60,104,115, 0,255, 62,176, 89,157, 61, 17, 26,205,
+ 62, 29, 14, 71, 58,181,226,123,109,214, 0,255,190,116,112, 84, 61, 17, 26,205, 62, 29, 14, 71,197, 75,226,123,109,214, 0,255,
+ 62,180, 21, 9, 61,177, 13, 57, 62, 29, 14, 71, 49,157,230, 61,115, 36, 0,255,190,123,231, 45, 61,177, 13, 57, 62, 29, 14, 71,
+206, 99,230, 61,115, 36, 0,255, 62,170,192,123, 61,251,177,170, 62, 36,133, 31, 39,206,234,175,119,196, 0,255,190,105, 62, 16,
+ 61,251,177,170, 62, 36,133, 31,216, 50,234,175,119,196, 0,255, 62,129,178,214, 62, 27,180, 54, 62, 62,165, 20, 24, 62,255, 85,
+125,173, 0,255,190, 23, 34,198, 62, 27,180, 54, 62, 62,165, 20,231,194,255, 85,125,173, 0,255, 62, 45,142,246, 62, 42,161,230,
+ 62, 81, 78, 48, 31,251,247, 40,123,158, 0,255,189,130,152, 32, 62, 42,161,230, 62, 81, 78, 48,224, 5,247, 40,123,158, 0,255,
+ 61, 88,133,203,190,209,133,104, 62, 70, 27,236, 0, 0,210,148,119,170, 0,255, 61,212,194,185,190,198, 83, 36, 62, 70, 27,236,
+ 19, 39,222, 65,121,248, 0,255, 58,240,196,191,190,198, 83, 36, 62, 70, 27,236,236,217,222, 65,121,248, 0,255, 61,220, 57,145,
+190,226, 80,207, 62, 58,233,167, 2,134,217,132,122, 12, 0,255,186,236,241, 77,190,226, 80,207, 62, 58,233,167,253,122,217,132,
+122, 12, 0,255, 61,167,249,168,190,237,131, 19, 62, 51,114,207,252, 13,214,169,121, 18, 0,255, 60,194, 48,144,190,237,131, 19,
+ 62, 51,114,207, 3,243,214,169,121, 18, 0,255, 61, 88,133,203,190,239, 96,200, 62, 47,183, 99, 0, 0,219,150,122,180, 0,255,
+ 61, 88,133,203,190, 18,152,254, 62, 77,146,196, 0, 0, 97, 46, 83, 76, 0,255, 61, 88,133,203,189,240,242, 18, 62, 73,215, 88,
+ 0, 0,104,197, 73,134, 0,255, 61,205, 75,225,189,248,104,235, 62, 73,215, 88, 36, 52, 53, 2,110,187, 0,255, 59,179,158,179,
+189,248,104,235, 62, 73,215, 88,219,204, 53, 2,110,187, 0,255, 61,227,176,105,190, 33,134,174, 62, 77,146,196, 95,187,212, 14,
+ 72,182, 0,255,187,178,169,214,190, 33,134,174, 62, 77,146,196,160, 69,212, 14, 72,182, 0,255, 61,190, 94, 48,190, 63, 98, 15,
+ 62, 73,215, 88, 64,117,207,117, 99, 90, 0,255, 60, 81, 60,220,190, 63, 98, 15, 62, 73,215, 88,191,139,207,117, 99, 90, 0,255,
+ 62,116,119,252,189,151, 95,239, 62, 40, 64,139, 49,103,196,157,102, 13, 0,255,190, 8, 53, 22,189,151, 95,239, 62, 40, 64,139,
+206,153,196,157,102, 13, 0,255, 62,174,123,231,188,217, 91,211, 62, 17,220, 2, 59,142,204,107,100,223, 2,255,190,112,180,232,
+188,217, 91,211, 62, 17,220, 2,196,114,204,107,100,223, 2,255, 62,200,155,220, 61, 46,246, 45, 62, 6,169,190, 66,102,217, 11,
+102, 65, 0,255,190,146,122,105, 61, 46,246, 45, 62, 6,169,190,189,154,217, 11,102, 65, 0,255, 62,204, 87, 72, 61,251,177,170,
+ 62, 32,201,179, 54, 87,228,142,112,151, 0,255,190,150, 53,213, 61,251,177,170, 62, 32,201,179,201,169,228,142,112,151, 0,255,
+ 62,191, 71, 78, 62, 16,129,241, 62, 66, 96,128, 42, 82,247, 97,120,125, 2,255,190,137, 37,219, 62, 16,129,241, 62, 66, 96,128,
+213,174,247, 97,120,125, 2,255, 62,131,144,140, 62, 79,244, 31, 62, 99,247, 77, 41,192,254,216,120,253, 0,255,190, 26,222, 50,
+ 62, 79,244, 31, 62, 99,247, 77,214, 64,254,216,120,253, 0,255, 62, 75,106, 87, 62,124,189, 48, 62,118,160,105, 28,217, 7, 53,
+124,126, 0,255,189,190, 78,225, 62,124,189, 48, 62,118,160,105,227, 39, 7, 53,124,126, 0,255, 62, 23, 42,109, 62,113,138,236,
+ 62,126, 23, 65,255,125, 5, 44,127,227, 0,255,189, 43,158, 31, 62,113,138,236, 62,126, 23, 65, 0,131, 5, 44,127,227, 0,255,
+ 61,205, 75,225, 62, 23,248,202, 62,122, 91,213,238,130, 2, 89,126,197, 0,255, 59,179,158,179, 62, 23,248,202, 62,122, 91,213,
+ 17,126, 2, 89,126,197, 0,255, 61,227,176,105,189,203,159,217, 62,107,110, 37, 23,115,230, 27,123, 34, 0,255,187,178,169,214,
+189,203,159,217, 62,107,110, 37,232,141,230, 27,123, 34, 0,255, 62, 26,229,218,190,133, 3, 64, 62, 58,233,167, 74,212, 14, 28,
+102,225, 2,255,189, 58,139,207,190,133, 3, 64, 62, 58,233,167,181, 44, 14, 28,102,225, 2,255, 62, 45,142,246,190,194,151,184,
+ 62, 47,183, 99, 72,235,252, 17,105, 31, 2,255,189,130,152, 32,190,194,151,184, 62, 47,183, 99,183, 21,252, 17,105, 31, 2,255,
+ 62, 53, 5,206,190,222,149, 99, 62, 36,133, 31, 66,179,225,197,104,249, 2,255,189,145,133,208,190,222,149, 99, 62, 36,133, 31,
+189, 77,225,197,104,249, 2,255, 62, 38, 24, 30,190,244,249,234, 62, 21,151,111, 44, 62,183, 4, 95, 98, 2,255,189,103, 84,224,
+190,244,249,234, 62, 21,151,111,211,194,183, 4, 95, 98, 2,255, 62, 4,129, 81,190,248,181, 86, 62, 21,151,111, 19,155,158, 52,
+ 80, 54, 2,255,188,193,243, 89,190,248,181, 86, 62, 21,151,111,236,101,158, 52, 80, 54, 2,255, 61, 88,133,203,190,252,112,195,
+ 62, 25, 82,219, 0, 0,154,201, 78, 88, 2,255, 61, 88,133,203,188,247, 55, 52, 62, 66, 96,128, 0, 0,252, 2,127,239, 0,255,
+ 61, 88,133,203, 61, 61,227,222, 62, 85, 9,156, 0, 0,227,112,124,196, 0,255, 62, 82,225, 47, 62, 46, 93, 82, 62, 73,215, 88,
+ 21, 58,254,234,126, 56, 0,255,189,205, 60,146, 62, 46, 93, 82, 62, 73,215, 88,234,198,254,234,126, 56, 0,255, 62, 4,129, 81,
+ 60, 94, 34,170, 62, 77,146,196,214, 37,232,110,118,163, 0,255,188,193,243, 89, 60, 94, 34,170, 62, 77,146,196, 41,219,232,110,
+118,163, 0,255, 61,235, 39, 65, 61, 61,227,222, 62, 81, 78, 48,232,150,230,127,123, 57, 0,255,188, 21, 11,173, 61, 61,227,222,
+ 62, 81, 78, 48, 23,106,230,127,123, 57, 0,255, 61,220, 57,145,190,190,220, 76, 62, 70, 27,236, 20,117,248,197,126, 36, 0,255,
+186,236,241, 77,190,190,220, 76, 62, 70, 27,236,235,139,248,197,126, 36, 0,255, 61,182,231, 88,190,133, 3, 64, 62, 77,146,196,
+ 19, 43, 0,128,126,141, 2,255, 60,134,121,207,190,133, 3, 64, 62, 77,146,196,236,213, 0,128,126,141, 2,255, 61, 88,133,203,
+190,133, 3, 64, 62, 77,146,196, 0, 0,255,122,127,254, 0,255, 61, 88,133,203,190, 82, 11, 43, 62, 73,215, 88, 0, 0,184,121,
+106, 36, 0,255, 61,197,213, 8,190, 55,235, 55, 62, 92,128,116, 66,167,160,139, 53, 45, 2,255, 60, 21,134, 27,190, 55,235, 55,
+ 62, 92,128,116,189, 89,160,139, 53, 45, 2,255, 61,235, 39, 65,190, 33,134,174, 62, 99,247, 77,118,133,224,215, 36,239, 2,255,
+188, 21, 11,173,190, 33,134,174, 62, 99,247, 77,137,123,224,215, 36,239, 2,255, 61,212,194,185,189,233,123, 57, 62, 92,128,116,
+ 81,167, 95,141, 24, 49, 2,255, 58,240,196,191,189,233,123, 57, 62, 92,128,116,174, 89, 95,141, 24, 49, 2,255, 61,145,149, 31,
+189,226, 4, 97, 62, 92,128,116,200,189,108,160, 39, 26, 2,255, 61, 13,225, 89,189,226, 4, 97, 62, 92,128,116, 55, 67,108,160,
+ 39, 26, 2,255, 61, 88,133,203,190, 22, 84,106, 62,114,228,253, 0, 0, 23, 42,125,225, 0,255, 61,153, 11,247,189,248,104,235,
+ 62,107,110, 37,231,186, 78, 89, 98, 66, 2,255, 60,253,231, 82,189,248,104,235, 62,107,110, 37, 24, 70, 78, 89, 98, 66, 2,255,
+ 61,197,213, 8,189,255,223,195, 62,107,110, 37, 43, 88, 62,134,102,237, 2,255, 60, 21,134, 27,189,255,223,195, 62,107,110, 37,
+212,168, 62,134,102,237, 2,255, 61,212,194,185,190, 33,134,174, 62,114,228,253, 46,247,233, 89,116,228, 2,255, 58,240,196,191,
+190, 33,134,174, 62,114,228,253,209, 9,233, 89,116,228, 2,255, 61,182,231, 88,190, 44,184,243, 62,103,178,185, 31, 46,181,198,
+ 99,128, 2,255, 60,134,121,207,190, 44,184,243, 62,103,178,185,224,210,181,198, 99,128, 2,255, 61, 88,133,203,190, 63, 98, 15,
+ 62,103,178,185, 0, 0,191,185,110,175, 2,255, 62, 49, 74, 98,190, 74,148, 83, 61,224,138,107,120, 23, 41, 34, 16, 99, 0,255,
+189,138, 14,248,190, 74,148, 83, 61,224,138,107,135,233, 41, 34, 16, 99, 0,255, 62, 4,129, 81,190, 40,253,134, 62, 58,233,167,
+ 80,251,250, 26, 98,241, 0,255,188,193,243, 89,190, 40,253,134, 62, 58,233,167,175, 5,250, 26, 98,241, 0,255, 62, 11,248, 41,
+190, 74,148, 83, 62, 58,233,167, 83,215, 16,153, 95, 71, 0,255,188,253,170, 27,190, 74,148, 83, 62, 58,233,167,172, 41, 16,153,
+ 95, 71, 0,255, 62, 38, 24, 30,190, 44,184,243, 61,224,138,107,122, 24, 35, 67, 15, 64, 0,255,189,103, 84,224,190, 44,184,243,
+ 61,224,138,107,133,232, 35, 67, 15, 64, 0,255, 61, 88,133,203,190,235,165, 93, 62, 47,183, 99, 0, 0, 86,139, 94, 77, 0,255,
+ 61,153, 11,247,190,233,199,167, 62, 47,183, 99,206,144, 70,200, 94,125, 0,255, 60,253,231, 82,190,233,199,167, 62, 47,183, 99,
+ 49,112, 70,200, 94,125, 0,255, 61,197,213, 8,190,222,149, 99, 62, 58,233,167,164,253, 17,109, 88, 75, 0,255, 60, 21,134, 27,
+190,222,149, 99, 62, 58,233,167, 91, 3, 17,109, 88, 75, 0,255, 61,197,213, 8,190,203,236, 70, 62, 66, 96,128,225,141,168, 87,
+ 88, 39, 0,255, 60, 21,134, 27,190,203,236, 70, 62, 66, 96,128, 30,115,168, 87, 88, 39, 0,255, 61, 88,133,203,190,213, 64,212,
+ 62, 32,201,179, 0, 0,159, 20, 83,153, 0,255, 61,197,213, 8,190,205,201,252, 62, 36,133, 31,230, 5,177,250, 98, 20, 0,255,
+ 60, 21,134, 27,190,205,201,252, 62, 36,133, 31, 25,251,177,250, 98, 20, 0,255, 61,197,213, 8,190,220,183,173, 62, 25, 82,219,
+152, 18, 24, 8, 70,188, 0,255, 60, 21,134, 27,190,220,183,173, 62, 25, 82,219,103,238, 24, 8, 70,188, 0,255, 61,153, 11,247,
+190,230, 12, 59, 62, 21,151,111,222, 26, 49,242,112,221, 0,255, 60,253,231, 82,190,230, 12, 59, 62, 21,151,111, 33,230, 49,242,
+112,221, 0,255, 61, 88,133,203,190,231,233,241, 62, 21,151,111, 0, 0, 60, 18,113, 5, 0,255, 62, 8, 60,189, 61, 76,209,142,
+ 62, 92,128,116, 30, 4,244, 93,123,225, 0,255,188,223,206,186, 61, 76,209,142, 62, 92,128,116,225,252,244, 93,123,225, 0,255,
+ 62, 15,179,149, 60,170,200, 22, 62, 88,197, 8, 9, 71,251, 34,127,144, 0,255,189, 13,194,190, 60,170,200, 22, 62, 88,197, 8,
+246,185,251, 34,127,144, 0,255, 62, 86,156,155, 62, 23,248,202, 62, 81, 78, 48, 17, 81, 2, 74,126,204, 0,255,189,212,179,106,
+ 62, 23,248,202, 62, 81, 78, 48,238,175, 2, 74,126,204, 0,255, 62, 56,193, 58, 62, 20, 61, 94, 62, 88,197, 8, 25,218,253,177,
+125, 86, 2,255,189,152,252,168, 62, 20, 61, 94, 62, 88,197, 8,230, 38,253,177,125, 86, 2,255, 62,127,170, 64, 62, 9, 11, 25,
+ 62, 88,197, 8, 21,182,240,210,125, 57, 2,255,190, 19,103, 90, 62, 9, 11, 25, 62, 88,197, 8,234, 74,240,210,125, 57, 2,255,
+ 62,161,107,237, 61,229, 77, 34, 62, 51,114,207, 28,143,237,249,123,117, 0,255,190, 86,148,244, 61,229, 77, 34, 62, 51,114,207,
+227,113,237,249,123,117, 0,255, 62,167, 5, 15, 61,169,150, 97, 62, 47,183, 99, 15,209,246,217,126,175, 0,255,190, 97,199, 56,
+ 61,169,150, 97, 62, 47,183, 99,240, 47,246,217,126,175, 0,255, 62,165, 39, 89, 61, 32, 8,125, 62, 43,251,247, 24,177,253,190,
+125,146, 0,255,190, 94, 11,204, 61, 32, 8,125, 62, 43,251,247,231, 79,253,190,125,146, 0,255, 62,140,229, 26,187,152,222, 60,
+ 62, 62,165, 20, 33, 20, 2, 75,123,160, 0,255,190, 45,135, 79,187,152,222, 60, 62, 62,165, 20,222,236, 2, 75,123,160, 0,255,
+ 62,105, 69,184,188,187,128,115, 62, 73,215, 88, 26, 85,248,238,125, 14, 0,255,189,250, 5,163,188,187,128,115, 62, 73,215, 88,
+229,171,248,238,125, 14, 0,255, 62, 34, 92,178,186,133,194,226, 62, 92,128,116, 7, 8,250,142,127,175, 0,255,189, 88,103, 48,
+186,133,194,226, 62, 92,128,116,248,248,250,142,127,175, 0,255, 62, 11,248, 41, 61,177, 13, 57, 62, 92,128,116, 34,169,240, 2,
+122, 43, 0,255,188,253,170, 27, 61,177, 13, 57, 62, 92,128,116,221, 87,240, 2,122, 43, 0,255, 62, 26,229,218, 61,251,177,170,
+ 62, 92,128,116, 27,126,239,108,123,231, 0,255,189, 58,139,207, 61,251,177,170, 62, 92,128,116,228,130,239,108,123,231, 0,255,
+ 62, 38, 24, 30, 61,236,195,250, 62, 81, 78, 48, 64,226,207, 13, 98,224, 0,255,189,103, 84,224, 61,236,195,250, 62, 81, 78, 48,
+191, 30,207, 13, 98,224, 0,255, 62, 19,111, 1, 61,177, 13, 57, 62, 81, 78, 48, 96, 29,229,169, 80, 81, 0,255,189, 28,176,110,
+ 61,177, 13, 57, 62, 81, 78, 48,159,227,229,169, 80, 81, 0,255, 62, 41,211,138, 59,205,106, 77, 62, 81, 78, 48, 55, 36, 71,122,
+ 90,188, 0,255,189,118, 66,143, 59,205,106, 77, 62, 81, 78, 48,200,220, 71,122, 90,188, 0,255, 62,105, 69,184,188, 67,220,161,
+ 62, 66, 96,128, 21, 76, 78, 90, 98,241, 0,255,189,250, 5,163,188, 67,220,161, 62, 66, 96,128,234,180, 78, 90, 98,241, 0,255,
+ 62,137, 41,174, 59, 43,249,149, 62, 55, 46, 59,245, 85, 69, 69,107, 25, 0,255,190, 38, 16,118, 59, 43,249,149, 62, 55, 46, 59,
+ 10,171, 69, 69,107, 25, 0,255, 62,157,176,129, 61, 61,227,222, 62, 40, 64,139,223,232, 29,211,120, 67, 0,255,190, 79, 30, 28,
+ 61, 61,227,222, 62, 40, 64,139, 32, 24, 29,211,120, 67, 0,255, 62,159,142, 55, 61,162, 31,137, 62, 40, 64,139,210,148,238,123,
+118, 95, 0,255,190, 82,217,136, 61,162, 31,137, 62, 40, 64,139, 45,108,238,123,118, 95, 0,255, 62,153,245, 21, 61,214, 95,114,
+ 62, 43,251,247,229,216,179,108, 99, 43, 0,255,190, 71,167, 67, 61,214, 95,114, 62, 43,251,247, 26, 40,179,108, 99, 43, 0,255,
+ 62,123,238,212, 62, 5, 79,173, 62, 77,146,196,237,202,158,179, 81, 35, 2,255,190, 15,171,238, 62, 5, 79,173, 62, 77,146,196,
+ 18, 54,158,179, 81, 35, 2,255, 62, 60,124,166, 62, 9, 11, 25, 62, 85, 9,156, 39, 24,212,118,113,214, 2,255,189,160,115,129,
+ 62, 9, 11, 25, 62, 85, 9,156,216,232,212,118,113,214, 2,255, 62, 86,156,155, 62, 12,198,133, 62, 77,146,196, 1,213,193,189,
+111,208, 0,255,189,212,179,106, 62, 12,198,133, 62, 77,146,196,254, 43,193,189,111,208, 0,255, 62, 23, 42,109, 60,230,126,216,
+ 62, 77,146,196, 84,226, 42,192, 85,187, 0,255,189, 43,158, 31, 60,230,126,216, 62, 77,146,196,171, 30, 42,192, 85,187, 0,255,
+ 62, 19,111, 1, 61, 91,191, 63, 62, 77,146,196,102,235, 2,196, 76, 11, 0,255,189, 28,176,110, 61, 91,191, 63, 62, 77,146,196,
+153, 21, 2,196, 76, 11, 0,255, 61,212,194,185, 62, 38,230,122, 62, 10,101, 42,182,183,104,118,246, 5, 0,255, 58,240,196,191,
+ 62, 38,230,122, 62, 10,101, 42, 73, 73,104,118,246, 5, 0,255, 62, 19,111, 1, 62,131,247,186, 62, 14, 32,150,192,208, 66,221,
+167, 3, 2,255,189, 28,176,110, 62,131,247,186, 62, 14, 32,150, 63, 48, 66,221,167, 3, 2,255, 62, 86,156,155, 62,137,144,220,
+ 62, 2,238, 82, 9, 59, 90, 89,165,208, 2,255,189,212,179,106, 62,137,144,220, 62, 2,238, 82,246,197, 90, 89,165,208, 2,255,
+ 62,142,194,208, 62, 83,175,139, 61,224,138,107, 37,165,114,104,212,176, 0,255,190, 49, 66,187, 62, 83,175,139, 61,224,138,107,
+218, 91,114,104,212,176, 0,255, 62,189,105,152, 62, 35, 43, 14, 61,164,211,170, 45, 67,116, 40,227, 1, 0,255,190,135, 72, 37,
+ 62, 35, 43, 14, 61,164,211,170,210,189,116, 40,227, 1, 0,255, 62,217,103, 66, 62, 12,198,133, 61,134,248, 73, 94,100, 79,237,
+223, 18, 0,255,190,163, 69,207, 62, 12,198,133, 61,134,248, 73,161,156, 79,237,223, 18, 0,255, 62,211,206, 32, 60,200,163,119,
+ 60,211,115,252,120,247,221,255,231,165, 0,255,190,157,172,173, 60,200,163,119, 60,211,115,252,135, 9,221,255,231,165, 0,255,
+ 62,170,192,123,189, 85, 45,188, 61, 52, 94,112, 76,155,154,106,242, 19, 0,255,190,105, 62, 16,189, 85, 45,188, 61, 52, 94,112,
+179,101,154,106,242, 19, 0,255, 62,131,144,140,189,196, 41, 0, 61,142,111, 33, 56,204,142, 26, 13,138, 0,255,190, 26,222, 50,
+189,196, 41, 0, 61,142,111, 33,199, 52,142, 26, 13,138, 0,255, 61, 88,133,203, 62,187,243, 16,188,105,242, 89, 0, 0,106,155,
+ 70,214, 2,255, 61, 88,133,203, 62,208,121,226,190, 62, 7,254, 0, 0,127,243, 3, 82, 2,255, 61, 88,133,203,190, 18,152,254,
+190,236,214, 11, 0, 0,164, 54,166,204, 3,255, 61, 88,133,203,190,136,190,173,189,124,142,139, 0, 0,129,179,235, 65, 0,255,
+ 61, 88,133,203,191, 1,243,205, 61,134,248, 73, 0, 0,151,182,181,204, 2,255, 61, 88,133,203,190,218,217,247, 60, 56, 12,241,
+ 0, 0,221,231,132,162, 2,255, 61, 88,133,203,190,162,222,161, 57,157, 21,147, 0, 0,212, 16,135,201, 0,255, 61, 88,133,203,
+190,142, 87,207,188,146,212,141, 0, 0,147,245,187, 97, 0,255, 62,230,119, 61, 61,106,172,239,189,253, 43,161,125,164,235,181,
+ 13,156, 0,255,190,176, 85,202, 61,106,172,239,189,253, 43,161,130, 92,235,181, 13,156, 0,255, 62,232, 84,243, 61,199,113,194,
+190, 47, 26, 78,126,174,238, 23,252, 66, 0,255,190,178, 51,128, 61,199,113,194,190, 47, 26, 78,129, 82,238, 23,252, 66, 0,255,
+ 62,211,206, 32, 61,147, 49,216,190,180,218,181, 81, 70, 13,148,158, 15, 1,255,190,157,172,173, 61,147, 49,216,190,180,218,181,
+174,186, 13,148,158, 15, 1,255, 62,137, 41,174, 62, 27,180, 54,190,244, 76,226, 58,123, 21,228,144, 70, 3,255,190, 38, 16,118,
+ 62, 27,180, 54,190,244, 76,226,197,133, 21,228,144, 70, 3,255, 62,202,121,146,189,151, 95,239,189,238, 61,240, 89, 76,164,139,
+ 6,161, 2,255,190,148, 88, 31,189,151, 95,239,189,238, 61,240,166,180,164,139, 6,161, 2,255, 62,168,226,197,189,226, 4, 97,
+190,103, 21,163, 38, 93,134, 34, 7,182, 0,255,190,101,130,164,189,226, 4, 97,190,103, 21,163,217,163,134, 34, 7,182, 0,255,
+ 62,180, 21, 9,189,100, 27,109,190,178,252,255, 43,106,170,219,170,222, 1,255,190,123,231, 45,189,100, 27,109,190,178,252,255,
+212,150,170,219,170,222, 1,255, 62, 86,156,155,188,217, 91,211,190,234,248, 85, 55,168,213,109,148,229, 2,255,189,212,179,106,
+188,217, 91,211,190,234,248, 85,200, 88,213,109,148,229, 2,255, 62, 38, 24, 30,190, 93, 61,112, 61, 37,112,191,120,197,255, 36,
+213,158, 0,255,189,103, 84,224,190, 93, 61,112, 61, 37,112,191,135, 59,255, 36,213,158, 0,255, 62, 11,248, 41,190,123, 24,209,
+188,236,102,176, 84,188,181, 20,196, 24, 0,255,188,253,170, 27,190,123, 24,209,188,236,102,176,171, 68,181, 20,196, 24, 0,255,
+ 62, 64, 56, 19,190,196,117,110, 60,241, 79, 92, 79,131,254, 86,155,183, 2,255,189,167,234, 89,190,196,117,110, 60,241, 79, 92,
+176,125,254, 86,155,183, 2,255, 62, 45,142,246,190,146, 19, 59, 61, 7,149, 95, 99, 5, 1, 8,174,231, 0,255,189,130,152, 32,
+190,146, 19, 59, 61, 7,149, 95,156,251, 1, 8,174,231, 0,255, 62, 82,225, 47,190,244,249,234, 61, 22,131, 15, 62, 65,185,227,
+168,224, 2,255,189,205, 60,146,190,244,249,234, 61, 22,131, 15,193,191,185,227,168,224, 2,255, 61,242,158, 25,190,207,167,178,
+ 60,181,152,155, 16,133,232,208,131, 55, 0,255,188, 80,194,110,190,207,167,178, 60,181,152,155,239,123,232,208,131, 55, 0,255,
+ 61,227,176,105,190,155,103,201, 60,151,189, 58, 48, 7,224,163,141,149, 0,255,187,178,169,214,190,155,103,201, 60,151,189, 58,
+207,249,224,163,141,149, 0,255, 62, 4,129, 81,190,252,112,195, 61, 97, 39,129, 12, 68,158,218,173,147, 0,255,188,193,243, 89,
+190,252,112,195, 61, 97, 39,129,243,188,158,218,173,147, 0,255, 62, 30,161, 70,190, 59,166,163, 61, 82, 57,208,124,195,227,106,
+255,203, 0,255,189, 73,121,127,190, 59,166,163, 61, 82, 57,208,131, 61,227,106,255,203, 0,255, 62, 26,229,218,190, 33,134,174,
+ 61,142,111, 33,120, 29,231,105, 36,193, 0,255,189, 58,139,207,190, 33,134,174, 61,142,111, 33,135,227,231,105, 36,193, 0,255,
+ 62, 23, 42,109,190, 7,102,186, 61,172, 74,130,101,160,182,164, 25,240, 0,255,189, 43,158, 31,190, 7,102,186, 61,172, 74,130,
+154, 96,182,164, 25,240, 0,255, 62, 26,229,218,190,111,230,140,189,148,171,206, 84,120,159,221,253,198, 0,255,189, 58,139,207,
+190,111,230,140,189,148,171,206,171,136,159,221,253,198, 0,255, 62, 67,243,127,190, 74,148, 83,190,139,205, 16, 67,255,151, 42,
+228, 73, 2,255,189,175, 97, 49,190, 74,148, 83,190,139,205, 16,188, 1,151, 42,228, 73, 2,255, 62, 90, 88, 7,189,248,104,235,
+190,205, 28,244, 63,201,176, 25,179, 0, 3,255,189,220, 42, 66,189,248,104,235,190,205, 28,244,192, 55,176, 25,179, 0, 3,255,
+ 62,135, 75,248, 62,180,124, 55,190,167,202,187, 56, 34, 95,160,192, 17, 2,255,190, 34, 85, 10, 62,180,124, 55,190,167,202,187,
+199,222, 95,160,192, 17, 2,255, 62,135, 75,248, 62,195,105,232,190, 58, 76,146, 55, 54,115,120, 0,239, 2,255,190, 34, 85, 10,
+ 62,195,105,232,190, 58, 76,146,200,202,115,120, 0,239, 2,255, 62,135, 75,248, 62,176,192,203,189, 34,252,105, 63,239, 92,164,
+ 60,238, 2,255,190, 34, 85, 10, 62,176,192,203,189, 34,252,105,192, 17, 92,164, 60,238, 2,255, 62,137, 41,174, 62, 68,193,219,
+ 61, 82, 57,208, 49,123,102,255, 57,170, 0,255,190, 38, 16,118, 62, 68,193,219, 61, 82, 57,208,206,133,102,255, 57,170, 0,255,
+ 62,200,155,220, 62, 12,198,133, 59,248,172, 95, 98,142, 73,198, 35, 6, 0,255,190,146,122,105, 62, 12,198,133, 59,248,172, 95,
+157,114, 73,198, 35, 6, 0,255, 62,178, 55, 83, 62, 35, 43, 14,188,146,212,141, 61,129,106,254, 33,241, 0,255,190,120, 43,193,
+ 62, 35, 43, 14,188,146,212,141,194,127,106,254, 33,241, 0,255, 62,180, 21, 9, 62,141, 76, 72,189,253, 43,161, 76,234, 87,151,
+ 52,221, 0,255,190,123,231, 45, 62,141, 76, 72,189,253, 43,161,179, 22, 87,151, 52,221, 0,255, 62,217,103, 66, 62, 87,106,247,
+189,185,254, 7,101,187, 66, 28, 40,199, 2,255,190,163, 69,207, 62, 87,106,247,189,185,254, 7,154, 69, 66, 28, 40,199, 2,255,
+ 62,217,103, 66, 62,113,138,236,190, 80,177, 26,113,183, 58, 68,248,119, 2,255,190,163, 69,207, 62,113,138,236,190, 80,177, 26,
+142, 73, 58, 68,248,119, 2,255, 62,180, 21, 9, 62,152,126,141,190,118, 3, 83, 86,235, 93,238,253,205, 0,255,190,123,231, 45,
+ 62,152,126,141,190,118, 3, 83,169, 21, 93,238,253,205, 0,255, 62,180, 21, 9, 62,135,179, 38,190,182,184,107, 85,232, 70,154,
+192,157, 2,255,190,123,231, 45, 62,135,179, 38,190,182,184,107,170, 24, 70,154,192,157, 2,255, 62,217,103, 66, 62, 76, 56,179,
+190,162, 49,153,110,166, 42,177,207,222, 2,255,190,163, 69,207, 62, 76, 56,179,190,162, 49,153,145, 90, 42,177,207,222, 2,255,
+ 62,174,123,231, 61,206,232,154,190,216, 79, 56, 75, 58, 1, 57,152,116, 3,255,190,112,180,232, 61,206,232,154,190,216, 79, 56,
+180,198, 1, 57,152,116, 3,255, 62,142,194,208,189, 40,100,171,190,206,250,170, 70, 73,187,147,173,200, 1,255,190, 49, 66,187,
+189, 40,100,171,190,206,250,170,185,183,187,147,173,200, 0,255, 62,223, 0,100, 61,206,232,154,190,121,190,191,114,194, 41, 80,
+ 38,207, 0,255,190,168,222,241, 61,206,232,154,190,121,190,191,141, 62, 41, 80, 38,207, 0,255, 62,120, 51,104,190, 7,102,186,
+189,163,153,127, 74,232,154,153, 22, 28, 0,255,190, 11,240,130,190, 7,102,186,189,163,153,127,181, 24,154,153, 22, 28, 0,255,
+ 62,129,178,214,190, 18,152,254,190,125,122, 44, 71, 89,151,115,237, 1, 0,255,190, 23, 34,198,190, 18,152,254,190,125,122, 44,
+184,167,151,115,237, 1, 0,255, 62,239,203,202, 62, 12,198,133,190,132, 86, 56,220, 72, 93,207, 79,106, 2,255,190,185,170, 88,
+ 62, 12,198,133,190,132, 86, 56, 35,184, 93,207, 79,106, 2,255, 62,211,206, 32,189,240,242, 18,190, 84,108,135, 15, 30,150, 34,
+ 70, 84, 2,255,190,157,172,173,189,240,242, 18,190, 84,108,135,240,226,150, 34, 70, 84, 2,255, 63, 9,160, 38,189,203,159,217,
+190,154,186,192, 67,164,166,138, 61,172, 0,255,190,221, 30,219,189,203,159,217,190,154,186,192,188, 92,166,138, 61,172, 0,255,
+ 63, 38,140,172,188,217, 91,211,190,178,252,255, 83,179,206,223, 83,114, 0,255,191, 11,123,244,188,217, 91,211,190,178,252,255,
+172, 77,206,223, 83,114, 0,255, 63, 46,242, 95, 61,199,113,194,190,177, 31, 73, 92, 54, 12,232, 87,210, 2,255,191, 19,225,167,
+ 61,199,113,194,190,177, 31, 73,163,202, 12,232, 87,210, 2,255, 63, 32,243,138, 62, 61, 75, 3,190,177, 31, 73, 62,247, 83,221,
+ 73, 97, 0,255,191, 5,226,209, 62, 61, 75, 3,190,177, 31, 73,193, 9, 83,221, 73, 97, 0,255, 63, 7,194,112, 62, 46, 93, 82,
+190,150,255, 84, 5,181,111, 80, 62,236, 0,255,190,217, 99,111, 62, 46, 93, 82,190,150,255, 84,250, 75,111, 80, 62,236, 0,255,
+ 63, 6,211,149, 62, 16,129,241,190,145,102, 50, 69,236,239,117,105,236, 0,255,190,215,133,185, 62, 16,129,241,190,145,102, 50,
+186, 20,239,117,105,236, 0,255, 63, 27, 90,104, 62, 27,180, 54,190,169,168,113, 24, 34,231,205,123, 89, 0,255,191, 0, 73,175,
+ 62, 27,180, 54,190,169,168,113,231,222,231,205,123, 89, 0,255, 63, 36,174,246, 61,169,150, 97,190,173, 99,221,223, 69,252, 16,
+123,173, 0,255,191, 9,158, 62, 61,169,150, 97,190,173, 99,221, 32,187,252, 16,123,173, 0,255, 63, 30, 38,249,188,127,147, 98,
+190,173, 99,221,239,171, 39, 0,120,207, 0,255,191, 3, 22, 64,188,127,147, 98,190,173, 99,221, 16, 85, 39, 0,120,207, 0,255,
+ 63, 8,177, 75,189,143,233, 23,190,149, 33,158, 51, 9, 45, 56,108, 82, 0,255,190,219, 65, 37,189,143,233, 23,190,149, 33,158,
+204,247, 45, 56,108, 82, 0,255, 62,224,222, 26,189,173,196,120,190, 88, 39,243, 38,147, 62,224,104,153, 2,255,190,170,188,167,
+189,173,196,120,190, 88, 39,243,217,109, 62,224,104,153, 2,255, 62,247, 66,162, 61,236,195,250,190,128,154,204, 62,218,243,152,
+110,206, 2,255,190,193, 33, 48, 61,236,195,250,190,128,154,204,193, 38,243,152,110,206, 2,255, 62,252,219,196, 61,184,132, 17,
+190,145,102, 50, 87, 10,182, 73, 58, 19, 0,255,190,198,186, 82, 61,184,132, 17,190,145,102, 50,168,246,182, 73, 58, 19, 0,255,
+ 62,237,238, 21,189,128,251,103,190,125,122, 44, 15,232,121,106, 37, 64, 0,255,190,183,204,162,189,128,251,103,190,125,122, 44,
+240, 24,121,106, 37, 64, 0,255, 63, 9,160, 38,189, 85, 45,188,190,164, 15, 79,239,157,122, 89, 33,212, 0,255,190,221, 30,219,
+189, 85, 45,188,190,164, 15, 79, 16, 99,122, 89, 33,212, 0,255, 63, 27, 90,104,188, 8, 37,223,190,182,184,107,158, 8, 81,202,
+ 9,185, 0,255,191, 0, 73,175,188, 8, 37,223,190,182,184,107, 97,248, 81,202, 9,185, 0,255, 63, 32,243,138, 61,132, 68, 40,
+190,182,184,107,131, 60,239,145, 23, 95, 0,255,191, 5,226,209, 61,132, 68, 40,190,182,184,107,124,196,239,145, 23, 95, 0,255,
+ 63, 25,124,178, 61,236,195,250,190,180,218,181,228, 27,153, 22, 70,206, 0,255,190,252,215,242, 61,236,195,250,190,180,218,181,
+ 27,229,153, 22, 70,206, 0,255, 63, 7,194,112, 61,221,214, 74,190,162, 49,153, 68, 65,168,253, 64,113, 0,255,190,217, 99,111,
+ 61,221,214, 74,190,162, 49,153,187,191,168,253, 64,113, 0,255, 62,228,153,135, 61,169,150, 97,190,125,122, 44, 86,113,222,190,
+ 88, 87, 0,255,190,174,120, 20, 61,169,150, 97,190,125,122, 44,169,143,222,190, 88, 87, 0,255, 62,226,187,209, 60,230,126,216,
+190,141,170,198, 95,196,182,107, 42,100, 0,255,190,172,154, 93, 60,230,126,216,190,141,170,198,160, 60,182,107, 42,100, 0,255,
+ 62,208, 18,180,188, 8, 37,223,190,141,170,198,111, 42, 14, 21, 61,220, 0,255,190,153,241, 65,188, 8, 37,223,190,141,170,198,
+144,214, 14, 21, 61,220, 0,255, 62,223, 0,100,188, 67,220,161,190,141,170,198, 79, 3, 91, 4, 43, 19, 2,255,190,168,222,241,
+188, 67,220,161,190,141,170,198,176,253, 91, 4, 43, 19, 2,255, 62,228,153,135,189, 55, 82, 92,190,141,170,198,107,207,254,198,
+ 68,250, 2,255,190,174,120, 20,189, 55, 82, 92,190,141,170,198,148, 49,254,198, 68,250, 2,255, 62,221, 34,174,189,115, 9, 29,
+190,141,170,198, 82, 7, 64,225, 73,200, 0,255,190,167, 1, 59,189,115, 9, 29,190,141,170,198,173,249, 64,225, 73,200, 0,255,
+ 62,200,155,220,189, 85, 45,188,190, 58, 76,146,117, 38,207, 66,239, 47, 0,255,190,146,122,105,189, 85, 45,188,190, 58, 76,146,
+138,218,207, 66,239, 47, 0,255, 62,198,190, 38,189,128,251,103,190,106,209, 15, 97,150, 18,139, 80,184, 0,255,190,144,156,179,
+189,128,251,103,190,106,209, 15,158,106, 18,139, 80,184, 0,255, 62,198,190, 38,189, 10,137, 74,190,114, 71,231,116, 17,240, 66,
+ 51,154, 0,255,190,144,156,179,189, 10,137, 74,190,114, 71,231,139,239,240, 66, 51,154, 0,255, 62,217,103, 66, 61, 46,246, 45,
+190,125,122, 44,113,112,204,245, 30, 39, 0,255,190,163, 69,207, 61, 46,246, 45,190,125,122, 44,142,144,204,245, 30, 39, 0,255,
+ 62,239,203,202, 61,121,154,159,190,139,205, 16, 90,105,185, 61, 56,146, 0,255,190,185,170, 88, 61,121,154,159,190,139,205, 16,
+165,151,185, 61, 56,146, 0,255, 62,239,203,202, 61,106,172,239,190,152,221, 10, 82,191,204,102, 82,230, 0,255,190,185,170, 88,
+ 61,106,172,239,190,152,221, 10,173, 65,204,102, 82,230, 0,255, 62,221, 34,174,189,115, 9, 29,190,152,221, 10, 29,246, 98, 64,
+ 76, 94, 0,255,190,167, 1, 59,189,115, 9, 29,190,152,221, 10,226, 10, 98, 64, 76, 94, 0,255, 62,230,119, 61,189, 55, 82, 92,
+190,152,221, 10, 77,150, 17,111,100, 75, 0,255,190,176, 85,202,189, 55, 82, 92,190,152,221, 10,178,106, 17,111,100, 75, 0,255,
+ 62,224,222, 26,188,127,147, 98,190,152,221, 10, 60,239, 60,190, 94,195, 0,255,190,170,188,167,188,127,147, 98,190,152,221, 10,
+195, 17, 60,190, 94,195, 0,255, 62,209,240,106,188, 8, 37,223,190,152,221, 10, 83,199, 23,178, 93,209, 0,255,190,155,206,247,
+188, 8, 37,223,190,152,221, 10,172, 57, 23,178, 93,209, 0,255, 62,228,153,135, 60,230,126,216,190,152,221, 10, 73, 98,200, 1,
+ 88,170, 0,255,190,174,120, 20, 60,230,126,216,190,152,221, 10,182,158,200, 1, 88,170, 0,255, 63, 9,160, 38, 61,206,232,154,
+190,175, 65,147, 68, 23,223,166,103,112, 0,255,190,221, 30,219, 61,206,232,154,190,175, 65,147,187,233,223,166,103,112, 0,255,
+ 63, 27, 90,104, 61,221,214, 74,190,192, 12,249, 18,165,216,156,120, 89, 0,255,191, 0, 73,175, 61,221,214, 74,190,192, 12,249,
+237, 91,216,156,120, 89, 0,255, 63, 35,192, 27, 61,121,154,159,190,193,234,175,185, 25,231, 29,103,157, 0,255,191, 8,175, 98,
+ 61,121,154,159,190,193,234,175, 70,231,231, 29,103,157, 0,255, 63, 30, 38,249,188, 67,220,161,190,192, 12,249,209, 43, 64, 0,
+100,119, 0,255,191, 3, 22, 64,188, 67,220,161,190,192, 12,249, 46,213, 64, 0,100,119, 0,255, 63, 10,143, 1,189, 85, 45,188,
+190,177, 31, 73, 26, 52, 92,240, 84, 3, 0,255,190,222,252,145,189, 85, 45,188,190,177, 31, 73,229,204, 92,240, 84, 3, 0,255,
+ 62,237,238, 21,189,115, 9, 29,190,139,205, 16, 8, 58,111,116, 62,101, 0,255,190,183,204,162,189,115, 9, 29,190,139,205, 16,
+247,198,111,116, 62,101, 0,255, 62,254,185,122, 61,169,150, 97,190,158,118, 45, 80,198,213,102, 89,175, 0,255,190,200,152, 8,
+ 61,169,150, 97,190,158,118, 45,175, 58,213,102, 89,175, 0,255, 62,239,203,202,186,133,194,226,190,154,186,192, 25,136, 0,130,
+125,108, 0,255,190,185,170, 88,186,133,194,226,190,154,186,192,230,120, 0,130,125,108, 0,255, 62,250,254, 14,188,187,128,115,
+190,156,152,119, 27, 2, 30, 58,121,104, 0,255,190,196,220,156,188,187,128,115,190,156,152,119,228,254, 30, 58,121,104, 0,255,
+ 63, 4,245,223, 59,205,106, 77,190,164, 15, 79, 55,218,253,126,115, 35, 0,255,190,211,202, 76, 59,205,106, 77,190,164, 15, 79,
+200, 38,253,126,115, 35, 0,255, 63, 0, 75,152, 60,230,126,216,190,160, 83,227, 41,164,255,199,121, 8, 0,255,190,202,117,190,
+ 60,230,126,216,190,160, 83,227,214, 92,255,199,121, 8, 0,255, 63, 6,211,149, 61,106,172,239,190,165,237, 5, 39,237, 9,191,
+121, 55, 0,255,190,215,133,185, 61,106,172,239,190,165,237, 5,216, 19, 9,191,121, 55, 0,255, 63, 11,125,220, 61, 17, 26,205,
+190,167,202,187, 46,208,244, 41,118,137, 0,255,190,224,218, 71, 61, 17, 26,205,190,167,202,187,209, 48,244, 41,118,137, 0,255,
+ 63, 18, 5,218, 61, 61,227,222,190,169,168,113, 53, 70, 3, 84,116, 85, 2,255,190,237,234, 65, 61, 61,227,222,190,169,168,113,
+202,186, 3, 84,116, 85, 2,255, 63, 15, 57, 73, 61,154,168,176,190,169,168,113, 44, 99, 38, 36,113,212, 2,255,190,232, 81, 31,
+ 61,154,168,176,190,169,168,113,211,157, 38, 36,113,212, 2,255, 63, 7,194,112, 62, 27,180, 54,190,192, 12,249,198,249, 72, 3,
+166,222, 3,255,190,217, 99,111, 62, 27,180, 54,190,192, 12,249, 57, 7, 72, 3,166,222, 3,255, 63, 34,209, 64, 62, 42,161,230,
+190,206,250,170, 37,198, 68,123,154,174, 3,255,191, 7,192,135, 62, 42,161,230,190,206,250,170,218, 58, 68,123,154,174, 3,255,
+ 63, 48,208, 21, 61,177, 13, 57,190,195,200,102,121, 3, 17,201,218, 73, 3,255,191, 21,191, 93, 61,177, 13, 57,190,195,200,102,
+134,253, 17,201,218, 73, 3,255, 63, 42, 72, 24,188,217, 91,211,190,203, 63, 62, 82, 59,200, 75,175, 70, 3,255,191, 15, 55, 96,
+188,217, 91,211,190,203, 63, 62,173,197,200, 75,175, 70, 3,255, 63, 9,160, 38,189,188,178, 40,190,193,234,175,249,134,165,184,
+165,129, 3,255,190,221, 30,219,189,188,178, 40,190,193,234,175, 6,122,165,184,165,129, 3,255, 62,215,137,140,189,226, 4, 97,
+190,154,186,192,249,126,163,122,167,205, 1,255,190,161,104, 25,189,226, 4, 97,190,154,186,192, 6,130,163,122,167,205, 1,255,
+ 62,232, 84,243, 62, 1,148, 65,190,167,202,187,193, 93, 65,224,165,229, 1,255,190,178, 51,128, 62, 1,148, 65,190,167,202,187,
+ 62,163, 65,224,165,229, 1,255, 68, 65, 84, 65, 0, 0, 1, 4, 2,236,206, 16, 0, 0, 0,242, 0, 0, 0, 5, 0, 0, 0, 3,
+ 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, 5, 31,136, 32, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65, 0, 0, 47, 28, 5, 31,136, 32, 0, 0, 0, 53, 0, 0, 3,237, 0, 0, 0, 0, 0, 0, 0, 45, 0, 0, 0, 34,
+ 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 34, 0, 0, 0, 2, 0, 0, 0, 43, 0, 0, 0, 34, 0, 0, 0, 43, 0, 0, 0, 45,
+ 0, 0, 0, 34, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0, 0, 34, 0, 0, 0, 1, 0, 0, 0, 46, 0, 0, 0, 34, 0, 0, 0, 44,
+ 0, 0, 0, 46, 0, 0, 0, 34, 0, 0, 0, 3, 0, 0, 0, 44, 0, 0, 0, 34, 0, 0, 0, 2, 0, 0, 0, 4, 0, 0, 0, 34,
+ 0, 0, 0, 4, 0, 0, 0, 41, 0, 0, 0, 34, 0, 0, 0, 41, 0, 0, 0, 43, 0, 0, 0, 34, 0, 0, 0, 3, 0, 0, 0, 5,
+ 0, 0, 0, 34, 0, 0, 0, 42, 0, 0, 0, 44, 0, 0, 0, 34, 0, 0, 0, 5, 0, 0, 0, 42, 0, 0, 0, 34, 0, 0, 0, 2,
+ 0, 0, 0, 8, 0, 0, 0, 34, 0, 0, 0, 6, 0, 0, 0, 8, 0, 0, 0, 34, 0, 0, 0, 4, 0, 0, 0, 6, 0, 0, 0, 34,
+ 0, 0, 0, 7, 0, 0, 0, 9, 0, 0, 0, 34, 0, 0, 0, 3, 0, 0, 0, 9, 0, 0, 0, 34, 0, 0, 0, 5, 0, 0, 0, 7,
+ 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 34, 0, 0, 0, 8, 0, 0, 0, 10, 0, 0, 0, 34, 0, 0, 0, 9,
+ 0, 0, 0, 11, 0, 0, 0, 34, 0, 0, 0, 1, 0, 0, 0, 11, 0, 0, 0, 34, 0, 0, 0, 10, 0, 0, 0, 12, 0, 0, 0, 34,
+ 0, 0, 0, 12, 0, 0, 0, 14, 0, 0, 0, 34, 0, 0, 0, 8, 0, 0, 0, 14, 0, 0, 0, 34, 0, 0, 0, 11, 0, 0, 0, 13,
+ 0, 0, 0, 34, 0, 0, 0, 14, 0, 0, 0, 15, 0, 0, 0, 34, 0, 0, 0, 6, 0, 0, 0, 15, 0, 0, 0, 34, 0, 0, 0, 7,
+ 0, 0, 0, 16, 0, 0, 0, 34, 0, 0, 0, 14, 0, 0, 0, 19, 0, 0, 0, 34, 0, 0, 0, 17, 0, 0, 0, 19, 0, 0, 0, 34,
+ 0, 0, 0, 15, 0, 0, 0, 17, 0, 0, 0, 34, 0, 0, 0, 18, 0, 0, 0, 20, 0, 0, 0, 34, 0, 0, 0, 16, 0, 0, 0, 18,
+ 0, 0, 0, 34, 0, 0, 0, 12, 0, 0, 0, 21, 0, 0, 0, 34, 0, 0, 0, 19, 0, 0, 0, 21, 0, 0, 0, 34, 0, 0, 0, 20,
+ 0, 0, 0, 22, 0, 0, 0, 34, 0, 0, 0, 13, 0, 0, 0, 22, 0, 0, 0, 34, 0, 0, 0, 21, 0, 0, 0, 23, 0, 0, 0, 34,
+ 0, 0, 0, 23, 0, 0, 0, 25, 0, 0, 0, 34, 0, 0, 0, 19, 0, 0, 0, 25, 0, 0, 0, 34, 0, 0, 0, 24, 0, 0, 0, 26,
+ 0, 0, 0, 34, 0, 0, 0, 22, 0, 0, 0, 24, 0, 0, 0, 34, 0, 0, 0, 20, 0, 0, 0, 26, 0, 0, 0, 34, 0, 0, 0, 25,
+ 0, 0, 0, 27, 0, 0, 0, 34, 0, 0, 0, 17, 0, 0, 0, 27, 0, 0, 0, 34, 0, 0, 0, 26, 0, 0, 0, 28, 0, 0, 0, 34,
+ 0, 0, 0, 18, 0, 0, 0, 28, 0, 0, 0, 34, 0, 0, 0, 25, 0, 0, 0, 31, 0, 0, 0, 34, 0, 0, 0, 29, 0, 0, 0, 31,
+ 0, 0, 0, 34, 0, 0, 0, 27, 0, 0, 0, 29, 0, 0, 0, 34, 0, 0, 0, 30, 0, 0, 0, 32, 0, 0, 0, 34, 0, 0, 0, 26,
+ 0, 0, 0, 32, 0, 0, 0, 34, 0, 0, 0, 28, 0, 0, 0, 30, 0, 0, 0, 34, 0, 0, 0, 23, 0, 0, 0, 33, 0, 0, 0, 34,
+ 0, 0, 0, 31, 0, 0, 0, 33, 0, 0, 0, 34, 0, 0, 0, 32, 0, 0, 0, 34, 0, 0, 0, 34, 0, 0, 0, 24, 0, 0, 0, 34,
+ 0, 0, 0, 34, 0, 0, 0, 33, 0, 0, 0, 35, 0, 0, 0, 34, 0, 0, 0, 35, 0, 0, 0, 37, 0, 0, 0, 34, 0, 0, 0, 31,
+ 0, 0, 0, 37, 0, 0, 0, 34, 0, 0, 0, 36, 0, 0, 0, 38, 0, 0, 0, 34, 0, 0, 0, 34, 0, 0, 0, 36, 0, 0, 0, 34,
+ 0, 0, 0, 32, 0, 0, 0, 38, 0, 0, 0, 34, 0, 0, 0, 37, 0, 0, 0, 39, 0, 0, 0, 34, 0, 0, 0, 29, 0, 0, 0, 39,
+ 0, 0, 0, 34, 0, 0, 0, 38, 0, 0, 0, 40, 0, 0, 0, 34, 0, 0, 0, 30, 0, 0, 0, 40, 0, 0, 0, 34, 0, 0, 0, 37,
+ 0, 0, 0, 43, 0, 0, 0, 34, 0, 0, 0, 39, 0, 0, 0, 41, 0, 0, 0, 34, 0, 0, 0, 38, 0, 0, 0, 44, 0, 0, 0, 34,
+ 0, 0, 0, 40, 0, 0, 0, 42, 0, 0, 0, 34, 0, 0, 0, 35, 0, 0, 0, 45, 0, 0, 0, 34, 0, 0, 0, 36, 0, 0, 0, 46,
+ 0, 0, 0, 34, 0, 0, 0, 35, 0, 0, 0, 49, 0, 0, 0, 34, 0, 0, 0, 47, 0, 0, 0, 49, 0, 0, 0, 34, 0, 0, 0, 45,
+ 0, 0, 0, 47, 0, 0, 0, 34, 0, 0, 0, 36, 0, 0, 0, 50, 0, 0, 0, 34, 0, 0, 0, 46, 0, 0, 0, 48, 0, 0, 0, 34,
+ 0, 0, 0, 48, 0, 0, 0, 50, 0, 0, 0, 34, 0, 0, 0, 33, 0, 0, 0, 51, 0, 0, 0, 34, 0, 0, 0, 49, 0, 0, 0, 51,
+ 0, 0, 0, 34, 0, 0, 0, 34, 0, 0, 0, 52, 0, 0, 0, 34, 0, 0, 0, 50, 0, 0, 0, 52, 0, 0, 0, 34, 0, 0, 0, 23,
+ 0, 0, 0, 53, 0, 0, 0, 34, 0, 0, 0, 51, 0, 0, 0, 53, 0, 0, 0, 34, 0, 0, 0, 24, 0, 0, 0, 54, 0, 0, 0, 34,
+ 0, 0, 0, 52, 0, 0, 0, 54, 0, 0, 0, 34, 0, 0, 0, 21, 0, 0, 0, 55, 0, 0, 0, 34, 0, 0, 0, 53, 0, 0, 0, 55,
+ 0, 0, 0, 34, 0, 0, 0, 22, 0, 0, 0, 56, 0, 0, 0, 34, 0, 0, 0, 54, 0, 0, 0, 56, 0, 0, 0, 34, 0, 0, 0, 12,
+ 0, 0, 0, 57, 0, 0, 0, 34, 0, 0, 0, 55, 0, 0, 0, 57, 0, 0, 0, 34, 0, 0, 0, 13, 0, 0, 0, 58, 0, 0, 0, 34,
+ 0, 0, 0, 56, 0, 0, 0, 58, 0, 0, 0, 34, 0, 0, 0, 10, 0, 0, 0, 61, 0, 0, 0, 34, 0, 0, 0, 57, 0, 0, 0, 61,
+ 0, 0, 0, 34, 0, 0, 0, 11, 0, 0, 0, 62, 0, 0, 0, 34, 0, 0, 0, 58, 0, 0, 0, 62, 0, 0, 0, 34, 0, 0, 0, 0,
+ 0, 0, 0, 63, 0, 0, 0, 34, 0, 0, 0, 61, 0, 0, 0, 63, 0, 0, 0, 34, 0, 0, 0, 1, 0, 0, 0, 64, 0, 0, 0, 34,
+ 0, 0, 0, 62, 0, 0, 0, 64, 0, 0, 0, 34, 0, 0, 0, 47, 0, 0, 0, 63, 0, 0, 0, 34, 0, 0, 0, 48, 0, 0, 0, 64,
+ 0, 0, 0, 34, 0, 0, 0, 59, 0, 0, 0, 63, 0, 0, 0, 34, 0, 0, 0, 47, 0, 0, 0, 59, 0, 0, 0, 34, 0, 0, 0, 60,
+ 0, 0, 0, 64, 0, 0, 0, 34, 0, 0, 0, 48, 0, 0, 0, 60, 0, 0, 0, 34, 0, 0, 0, 59, 0, 0, 0, 61, 0, 0, 0, 34,
+ 0, 0, 0, 60, 0, 0, 0, 62, 0, 0, 0, 34, 0, 0, 0, 57, 0, 0, 0, 59, 0, 0, 0, 34, 0, 0, 0, 58, 0, 0, 0, 60,
+ 0, 0, 0, 34, 0, 0, 0, 55, 0, 0, 0, 59, 0, 0, 0, 34, 0, 0, 0, 56, 0, 0, 0, 60, 0, 0, 0, 34, 0, 0, 0, 53,
+ 0, 0, 0, 59, 0, 0, 0, 34, 0, 0, 0, 54, 0, 0, 0, 60, 0, 0, 0, 34, 0, 0, 0, 51, 0, 0, 0, 59, 0, 0, 0, 34,
+ 0, 0, 0, 52, 0, 0, 0, 60, 0, 0, 0, 34, 0, 0, 0, 49, 0, 0, 0, 59, 0, 0, 0, 34, 0, 0, 0, 50, 0, 0, 0, 60,
+ 0, 0, 0, 34, 0, 0, 0, 87, 0, 0, 0,171, 0, 0, 0, 34, 0, 0, 0,171, 0, 0, 0,173, 0, 0, 0, 34, 0, 0, 0, 89,
+ 0, 0, 0,173, 0, 0, 0, 34, 0, 0, 0, 87, 0, 0, 0, 89, 0, 0, 0, 34, 0, 0, 0,172, 0, 0, 0,173, 0, 0, 0, 34,
+ 0, 0, 0, 88, 0, 0, 0,172, 0, 0, 0, 34, 0, 0, 0, 88, 0, 0, 0, 89, 0, 0, 0, 34, 0, 0, 0, 85, 0, 0, 0,169,
+ 0, 0, 0, 34, 0, 0, 0,169, 0, 0, 0,171, 0, 0, 0, 34, 0, 0, 0, 85, 0, 0, 0, 87, 0, 0, 0, 34, 0, 0, 0,170,
+ 0, 0, 0,172, 0, 0, 0, 34, 0, 0, 0, 86, 0, 0, 0,170, 0, 0, 0, 34, 0, 0, 0, 86, 0, 0, 0, 88, 0, 0, 0, 34,
+ 0, 0, 0, 83, 0, 0, 0,167, 0, 0, 0, 34, 0, 0, 0,167, 0, 0, 0,169, 0, 0, 0, 34, 0, 0, 0, 83, 0, 0, 0, 85,
+ 0, 0, 0, 34, 0, 0, 0,168, 0, 0, 0,170, 0, 0, 0, 34, 0, 0, 0, 84, 0, 0, 0,168, 0, 0, 0, 34, 0, 0, 0, 84,
+ 0, 0, 0, 86, 0, 0, 0, 34, 0, 0, 0, 81, 0, 0, 0,165, 0, 0, 0, 34, 0, 0, 0,165, 0, 0, 0,167, 0, 0, 0, 34,
+ 0, 0, 0, 81, 0, 0, 0, 83, 0, 0, 0, 34, 0, 0, 0,166, 0, 0, 0,168, 0, 0, 0, 34, 0, 0, 0, 82, 0, 0, 0,166,
+ 0, 0, 0, 34, 0, 0, 0, 82, 0, 0, 0, 84, 0, 0, 0, 34, 0, 0, 0, 79, 0, 0, 0,163, 0, 0, 0, 34, 0, 0, 0,163,
+ 0, 0, 0,165, 0, 0, 0, 34, 0, 0, 0, 79, 0, 0, 0, 81, 0, 0, 0, 34, 0, 0, 0,164, 0, 0, 0,166, 0, 0, 0, 34,
+ 0, 0, 0, 80, 0, 0, 0,164, 0, 0, 0, 34, 0, 0, 0, 80, 0, 0, 0, 82, 0, 0, 0, 34, 0, 0, 0, 77, 0, 0, 0, 90,
+ 0, 0, 0, 34, 0, 0, 0, 90, 0, 0, 0,143, 0, 0, 0, 34, 0, 0, 0,143, 0, 0, 0,161, 0, 0, 0, 34, 0, 0, 0, 77,
+ 0, 0, 0,161, 0, 0, 0, 34, 0, 0, 0, 91, 0, 0, 0,144, 0, 0, 0, 34, 0, 0, 0, 78, 0, 0, 0, 91, 0, 0, 0, 34,
+ 0, 0, 0, 78, 0, 0, 0,162, 0, 0, 0, 34, 0, 0, 0,144, 0, 0, 0,162, 0, 0, 0, 34, 0, 0, 0, 90, 0, 0, 0, 92,
+ 0, 0, 0, 34, 0, 0, 0, 92, 0, 0, 0,145, 0, 0, 0, 34, 0, 0, 0,143, 0, 0, 0,145, 0, 0, 0, 34, 0, 0, 0, 93,
+ 0, 0, 0,146, 0, 0, 0, 34, 0, 0, 0, 91, 0, 0, 0, 93, 0, 0, 0, 34, 0, 0, 0,144, 0, 0, 0,146, 0, 0, 0, 34,
+ 0, 0, 0, 92, 0, 0, 0, 94, 0, 0, 0, 34, 0, 0, 0, 94, 0, 0, 0,147, 0, 0, 0, 34, 0, 0, 0,145, 0, 0, 0,147,
+ 0, 0, 0, 34, 0, 0, 0, 95, 0, 0, 0,148, 0, 0, 0, 34, 0, 0, 0, 93, 0, 0, 0, 95, 0, 0, 0, 34, 0, 0, 0,146,
+ 0, 0, 0,148, 0, 0, 0, 34, 0, 0, 0, 94, 0, 0, 0, 96, 0, 0, 0, 34, 0, 0, 0, 96, 0, 0, 0,149, 0, 0, 0, 34,
+ 0, 0, 0,147, 0, 0, 0,149, 0, 0, 0, 34, 0, 0, 0, 97, 0, 0, 0,150, 0, 0, 0, 34, 0, 0, 0, 95, 0, 0, 0, 97,
+ 0, 0, 0, 34, 0, 0, 0,148, 0, 0, 0,150, 0, 0, 0, 34, 0, 0, 0, 96, 0, 0, 0, 98, 0, 0, 0, 34, 0, 0, 0, 98,
+ 0, 0, 0,151, 0, 0, 0, 34, 0, 0, 0,149, 0, 0, 0,151, 0, 0, 0, 34, 0, 0, 0, 99, 0, 0, 0,152, 0, 0, 0, 34,
+ 0, 0, 0, 97, 0, 0, 0, 99, 0, 0, 0, 34, 0, 0, 0,150, 0, 0, 0,152, 0, 0, 0, 34, 0, 0, 0, 98, 0, 0, 0,100,
+ 0, 0, 0, 34, 0, 0, 0,100, 0, 0, 0,153, 0, 0, 0, 34, 0, 0, 0,151, 0, 0, 0,153, 0, 0, 0, 34, 0, 0, 0,101,
+ 0, 0, 0,154, 0, 0, 0, 34, 0, 0, 0, 99, 0, 0, 0,101, 0, 0, 0, 34, 0, 0, 0,152, 0, 0, 0,154, 0, 0, 0, 34,
+ 0, 0, 0,100, 0, 0, 0,102, 0, 0, 0, 34, 0, 0, 0,102, 0, 0, 0,155, 0, 0, 0, 34, 0, 0, 0,153, 0, 0, 0,155,
+ 0, 0, 0, 34, 0, 0, 0,103, 0, 0, 0,156, 0, 0, 0, 34, 0, 0, 0,101, 0, 0, 0,103, 0, 0, 0, 34, 0, 0, 0,154,
+ 0, 0, 0,156, 0, 0, 0, 34, 0, 0, 0,102, 0, 0, 0,104, 0, 0, 0, 34, 0, 0, 0,104, 0, 0, 0,157, 0, 0, 0, 34,
+ 0, 0, 0,155, 0, 0, 0,157, 0, 0, 0, 34, 0, 0, 0,105, 0, 0, 0,158, 0, 0, 0, 34, 0, 0, 0,103, 0, 0, 0,105,
+ 0, 0, 0, 34, 0, 0, 0,156, 0, 0, 0,158, 0, 0, 0, 34, 0, 0, 0,104, 0, 0, 0,106, 0, 0, 0, 34, 0, 0, 0,106,
+ 0, 0, 0,159, 0, 0, 0, 34, 0, 0, 0,157, 0, 0, 0,159, 0, 0, 0, 34, 0, 0, 0,107, 0, 0, 0,160, 0, 0, 0, 34,
+ 0, 0, 0,105, 0, 0, 0,107, 0, 0, 0, 34, 0, 0, 0,158, 0, 0, 0,160, 0, 0, 0, 34, 0, 0, 0, 65, 0, 0, 0,106,
+ 0, 0, 0, 34, 0, 0, 0, 65, 0, 0, 0, 66, 0, 0, 0, 34, 0, 0, 0, 66, 0, 0, 0,159, 0, 0, 0, 34, 0, 0, 0, 65,
+ 0, 0, 0,107, 0, 0, 0, 34, 0, 0, 0, 66, 0, 0, 0,160, 0, 0, 0, 34, 0, 0, 0,108, 0, 0, 0,125, 0, 0, 0, 34,
+ 0, 0, 0,125, 0, 0, 0,157, 0, 0, 0, 34, 0, 0, 0,108, 0, 0, 0,159, 0, 0, 0, 34, 0, 0, 0,126, 0, 0, 0,158,
+ 0, 0, 0, 34, 0, 0, 0,109, 0, 0, 0,126, 0, 0, 0, 34, 0, 0, 0,109, 0, 0, 0,160, 0, 0, 0, 34, 0, 0, 0,125,
+ 0, 0, 0,176, 0, 0, 0, 34, 0, 0, 0,155, 0, 0, 0,176, 0, 0, 0, 34, 0, 0, 0,156, 0, 0, 0,177, 0, 0, 0, 34,
+ 0, 0, 0,126, 0, 0, 0,177, 0, 0, 0, 34, 0, 0, 0,123, 0, 0, 0,153, 0, 0, 0, 34, 0, 0, 0,123, 0, 0, 0,176,
+ 0, 0, 0, 34, 0, 0, 0,124, 0, 0, 0,154, 0, 0, 0, 34, 0, 0, 0,124, 0, 0, 0,177, 0, 0, 0, 34, 0, 0, 0,121,
+ 0, 0, 0,151, 0, 0, 0, 34, 0, 0, 0,121, 0, 0, 0,123, 0, 0, 0, 34, 0, 0, 0,122, 0, 0, 0,152, 0, 0, 0, 34,
+ 0, 0, 0,122, 0, 0, 0,124, 0, 0, 0, 34, 0, 0, 0,119, 0, 0, 0,149, 0, 0, 0, 34, 0, 0, 0,119, 0, 0, 0,121,
+ 0, 0, 0, 34, 0, 0, 0,120, 0, 0, 0,150, 0, 0, 0, 34, 0, 0, 0,120, 0, 0, 0,122, 0, 0, 0, 34, 0, 0, 0,117,
+ 0, 0, 0,147, 0, 0, 0, 34, 0, 0, 0,117, 0, 0, 0,119, 0, 0, 0, 34, 0, 0, 0,118, 0, 0, 0,148, 0, 0, 0, 34,
+ 0, 0, 0,118, 0, 0, 0,120, 0, 0, 0, 34, 0, 0, 0,115, 0, 0, 0,145, 0, 0, 0, 34, 0, 0, 0,115, 0, 0, 0,117,
+ 0, 0, 0, 34, 0, 0, 0,116, 0, 0, 0,146, 0, 0, 0, 34, 0, 0, 0,116, 0, 0, 0,118, 0, 0, 0, 34, 0, 0, 0,113,
+ 0, 0, 0,143, 0, 0, 0, 34, 0, 0, 0,113, 0, 0, 0,115, 0, 0, 0, 34, 0, 0, 0,114, 0, 0, 0,144, 0, 0, 0, 34,
+ 0, 0, 0,114, 0, 0, 0,116, 0, 0, 0, 34, 0, 0, 0,112, 0, 0, 0,162, 0, 0, 0, 34, 0, 0, 0,112, 0, 0, 0,114,
+ 0, 0, 0, 34, 0, 0, 0,174, 0, 0, 0,178, 0, 0, 0, 34, 0, 0, 0,161, 0, 0, 0,174, 0, 0, 0, 34, 0, 0, 0,174,
+ 0, 0, 0,179, 0, 0, 0, 34, 0, 0, 0,112, 0, 0, 0,179, 0, 0, 0, 34, 0, 0, 0,162, 0, 0, 0,174, 0, 0, 0, 34,
+ 0, 0, 0, 66, 0, 0, 0,110, 0, 0, 0, 34, 0, 0, 0,108, 0, 0, 0,110, 0, 0, 0, 34, 0, 0, 0,109, 0, 0, 0,111,
+ 0, 0, 0, 34, 0, 0, 0, 66, 0, 0, 0,111, 0, 0, 0, 34, 0, 0, 0, 66, 0, 0, 0,175, 0, 0, 0, 34, 0, 0, 0,175,
+ 0, 0, 0,180, 0, 0, 0, 34, 0, 0, 0,110, 0, 0, 0,180, 0, 0, 0, 34, 0, 0, 0,111, 0, 0, 0,181, 0, 0, 0, 34,
+ 0, 0, 0,175, 0, 0, 0,181, 0, 0, 0, 34, 0, 0, 0,178, 0, 0, 0,180, 0, 0, 0, 34, 0, 0, 0,174, 0, 0, 0,175,
+ 0, 0, 0, 32, 0, 0, 0,179, 0, 0, 0,181, 0, 0, 0, 34, 0, 0, 0,132, 0, 0, 0,134, 0, 0, 0, 34, 0, 0, 0,134,
+ 0, 0, 0,173, 0, 0, 0, 34, 0, 0, 0,132, 0, 0, 0,171, 0, 0, 0, 34, 0, 0, 0,133, 0, 0, 0,134, 0, 0, 0, 34,
+ 0, 0, 0,133, 0, 0, 0,172, 0, 0, 0, 34, 0, 0, 0,130, 0, 0, 0,132, 0, 0, 0, 34, 0, 0, 0,130, 0, 0, 0,169,
+ 0, 0, 0, 34, 0, 0, 0,131, 0, 0, 0,133, 0, 0, 0, 34, 0, 0, 0,131, 0, 0, 0,170, 0, 0, 0, 34, 0, 0, 0,128,
+ 0, 0, 0,130, 0, 0, 0, 34, 0, 0, 0,128, 0, 0, 0,167, 0, 0, 0, 34, 0, 0, 0,129, 0, 0, 0,131, 0, 0, 0, 34,
+ 0, 0, 0,129, 0, 0, 0,168, 0, 0, 0, 34, 0, 0, 0,163, 0, 0, 0,184, 0, 0, 0, 34, 0, 0, 0,182, 0, 0, 0,184,
+ 0, 0, 0, 34, 0, 0, 0,165, 0, 0, 0,182, 0, 0, 0, 34, 0, 0, 0,183, 0, 0, 0,185, 0, 0, 0, 34, 0, 0, 0,164,
+ 0, 0, 0,185, 0, 0, 0, 34, 0, 0, 0,166, 0, 0, 0,183, 0, 0, 0, 34, 0, 0, 0,128, 0, 0, 0,182, 0, 0, 0, 34,
+ 0, 0, 0,129, 0, 0, 0,183, 0, 0, 0, 34, 0, 0, 0,141, 0, 0, 0,187, 0, 0, 0, 34, 0, 0, 0,186, 0, 0, 0,187,
+ 0, 0, 0, 32, 0, 0, 0,184, 0, 0, 0,186, 0, 0, 0, 34, 0, 0, 0,141, 0, 0, 0,184, 0, 0, 0, 34, 0, 0, 0,142,
+ 0, 0, 0,187, 0, 0, 0, 34, 0, 0, 0,142, 0, 0, 0,185, 0, 0, 0, 34, 0, 0, 0,185, 0, 0, 0,186, 0, 0, 0, 34,
+ 0, 0, 0, 67, 0, 0, 0,186, 0, 0, 0, 32, 0, 0, 0, 67, 0, 0, 0,182, 0, 0, 0, 34, 0, 0, 0, 67, 0, 0, 0,183,
+ 0, 0, 0, 34, 0, 0, 0,127, 0, 0, 0,128, 0, 0, 0, 34, 0, 0, 0, 67, 0, 0, 0,127, 0, 0, 0, 32, 0, 0, 0,127,
+ 0, 0, 0,129, 0, 0, 0, 34, 0, 0, 0,139, 0, 0, 0,190, 0, 0, 0, 34, 0, 0, 0,188, 0, 0, 0,190, 0, 0, 0, 34,
+ 0, 0, 0,141, 0, 0, 0,188, 0, 0, 0, 34, 0, 0, 0,139, 0, 0, 0,141, 0, 0, 0, 34, 0, 0, 0,189, 0, 0, 0,191,
+ 0, 0, 0, 34, 0, 0, 0,140, 0, 0, 0,191, 0, 0, 0, 34, 0, 0, 0,140, 0, 0, 0,142, 0, 0, 0, 34, 0, 0, 0,142,
+ 0, 0, 0,189, 0, 0, 0, 34, 0, 0, 0,137, 0, 0, 0,192, 0, 0, 0, 34, 0, 0, 0,190, 0, 0, 0,192, 0, 0, 0, 34,
+ 0, 0, 0,137, 0, 0, 0,139, 0, 0, 0, 34, 0, 0, 0,191, 0, 0, 0,193, 0, 0, 0, 34, 0, 0, 0,138, 0, 0, 0,193,
+ 0, 0, 0, 34, 0, 0, 0,138, 0, 0, 0,140, 0, 0, 0, 34, 0, 0, 0,136, 0, 0, 0,194, 0, 0, 0, 34, 0, 0, 0,192,
+ 0, 0, 0,194, 0, 0, 0, 34, 0, 0, 0,136, 0, 0, 0,137, 0, 0, 0, 34, 0, 0, 0,193, 0, 0, 0,195, 0, 0, 0, 34,
+ 0, 0, 0,136, 0, 0, 0,195, 0, 0, 0, 34, 0, 0, 0,136, 0, 0, 0,138, 0, 0, 0, 34, 0, 0, 0, 69, 0, 0, 0,135,
+ 0, 0, 0, 34, 0, 0, 0, 69, 0, 0, 0,194, 0, 0, 0, 34, 0, 0, 0,135, 0, 0, 0,136, 0, 0, 0, 34, 0, 0, 0, 69,
+ 0, 0, 0,195, 0, 0, 0, 34, 0, 0, 0, 68, 0, 0, 0,188, 0, 0, 0, 34, 0, 0, 0, 68, 0, 0, 0,187, 0, 0, 0, 34,
+ 0, 0, 0, 68, 0, 0, 0,189, 0, 0, 0, 34, 0, 0, 0,188, 0, 0, 0,203, 0, 0, 0, 34, 0, 0, 0,203, 0, 0, 0,205,
+ 0, 0, 0, 34, 0, 0, 0, 68, 0, 0, 0,205, 0, 0, 0, 34, 0, 0, 0,189, 0, 0, 0,204, 0, 0, 0, 34, 0, 0, 0,204,
+ 0, 0, 0,205, 0, 0, 0, 34, 0, 0, 0, 69, 0, 0, 0,196, 0, 0, 0, 34, 0, 0, 0,196, 0, 0, 0,197, 0, 0, 0, 34,
+ 0, 0, 0,194, 0, 0, 0,197, 0, 0, 0, 34, 0, 0, 0,196, 0, 0, 0,198, 0, 0, 0, 34, 0, 0, 0,195, 0, 0, 0,198,
+ 0, 0, 0, 34, 0, 0, 0,197, 0, 0, 0,199, 0, 0, 0, 34, 0, 0, 0,192, 0, 0, 0,199, 0, 0, 0, 34, 0, 0, 0,198,
+ 0, 0, 0,200, 0, 0, 0, 34, 0, 0, 0,193, 0, 0, 0,200, 0, 0, 0, 34, 0, 0, 0,199, 0, 0, 0,201, 0, 0, 0, 34,
+ 0, 0, 0,190, 0, 0, 0,201, 0, 0, 0, 34, 0, 0, 0,200, 0, 0, 0,202, 0, 0, 0, 34, 0, 0, 0,191, 0, 0, 0,202,
+ 0, 0, 0, 34, 0, 0, 0,201, 0, 0, 0,203, 0, 0, 0, 34, 0, 0, 0,202, 0, 0, 0,204, 0, 0, 0, 34, 0, 0, 0,196,
+ 0, 0, 0,201, 0, 0, 0, 34, 0, 0, 0,196, 0, 0, 0,202, 0, 0, 0, 34, 0, 0, 0,196, 0, 0, 0,205, 0, 0, 0, 34,
+ 0, 0, 0,137, 0, 0, 0,161, 0, 0, 0, 34, 0, 0, 0,136, 0, 0, 0,174, 0, 0, 0, 34, 0, 0, 0,138, 0, 0, 0,162,
+ 0, 0, 0, 34, 0, 0, 0,139, 0, 0, 0,208, 0, 0, 0, 34, 0, 0, 0,161, 0, 0, 0,208, 0, 0, 0, 34, 0, 0, 0,140,
+ 0, 0, 0,209, 0, 0, 0, 34, 0, 0, 0,162, 0, 0, 0,209, 0, 0, 0, 34, 0, 0, 0,141, 0, 0, 0,210, 0, 0, 0, 34,
+ 0, 0, 0,208, 0, 0, 0,210, 0, 0, 0, 34, 0, 0, 0,142, 0, 0, 0,211, 0, 0, 0, 34, 0, 0, 0,209, 0, 0, 0,211,
+ 0, 0, 0, 34, 0, 0, 0,163, 0, 0, 0,210, 0, 0, 0, 34, 0, 0, 0,164, 0, 0, 0,211, 0, 0, 0, 34, 0, 0, 0, 79,
+ 0, 0, 0,206, 0, 0, 0, 34, 0, 0, 0,206, 0, 0, 0,210, 0, 0, 0, 34, 0, 0, 0,207, 0, 0, 0,211, 0, 0, 0, 34,
+ 0, 0, 0, 80, 0, 0, 0,207, 0, 0, 0, 34, 0, 0, 0,206, 0, 0, 0,212, 0, 0, 0, 34, 0, 0, 0,208, 0, 0, 0,212,
+ 0, 0, 0, 34, 0, 0, 0,209, 0, 0, 0,213, 0, 0, 0, 34, 0, 0, 0,207, 0, 0, 0,213, 0, 0, 0, 34, 0, 0, 0, 77,
+ 0, 0, 0,212, 0, 0, 0, 34, 0, 0, 0, 78, 0, 0, 0,213, 0, 0, 0, 34, 0, 0, 0, 70, 0, 0, 0,127, 0, 0, 0, 34,
+ 0, 0, 0, 70, 0, 0, 0,219, 0, 0, 0, 34, 0, 0, 0,128, 0, 0, 0,219, 0, 0, 0, 34, 0, 0, 0,129, 0, 0, 0,220,
+ 0, 0, 0, 34, 0, 0, 0, 70, 0, 0, 0,220, 0, 0, 0, 34, 0, 0, 0,217, 0, 0, 0,219, 0, 0, 0, 34, 0, 0, 0,130,
+ 0, 0, 0,217, 0, 0, 0, 34, 0, 0, 0,131, 0, 0, 0,218, 0, 0, 0, 34, 0, 0, 0,218, 0, 0, 0,220, 0, 0, 0, 34,
+ 0, 0, 0,215, 0, 0, 0,217, 0, 0, 0, 34, 0, 0, 0,132, 0, 0, 0,215, 0, 0, 0, 34, 0, 0, 0,133, 0, 0, 0,216,
+ 0, 0, 0, 34, 0, 0, 0,216, 0, 0, 0,218, 0, 0, 0, 34, 0, 0, 0,214, 0, 0, 0,215, 0, 0, 0, 34, 0, 0, 0,134,
+ 0, 0, 0,214, 0, 0, 0, 34, 0, 0, 0,214, 0, 0, 0,216, 0, 0, 0, 34, 0, 0, 0,215, 0, 0, 0,226, 0, 0, 0, 34,
+ 0, 0, 0,226, 0, 0, 0,228, 0, 0, 0, 34, 0, 0, 0,214, 0, 0, 0,228, 0, 0, 0, 34, 0, 0, 0,216, 0, 0, 0,227,
+ 0, 0, 0, 34, 0, 0, 0,227, 0, 0, 0,228, 0, 0, 0, 34, 0, 0, 0,217, 0, 0, 0,224, 0, 0, 0, 34, 0, 0, 0,224,
+ 0, 0, 0,226, 0, 0, 0, 34, 0, 0, 0,218, 0, 0, 0,225, 0, 0, 0, 34, 0, 0, 0,225, 0, 0, 0,227, 0, 0, 0, 34,
+ 0, 0, 0,219, 0, 0, 0,222, 0, 0, 0, 34, 0, 0, 0,222, 0, 0, 0,224, 0, 0, 0, 34, 0, 0, 0,220, 0, 0, 0,223,
+ 0, 0, 0, 34, 0, 0, 0,223, 0, 0, 0,225, 0, 0, 0, 34, 0, 0, 0, 70, 0, 0, 0,221, 0, 0, 0, 34, 0, 0, 0,221,
+ 0, 0, 0,222, 0, 0, 0, 34, 0, 0, 0,221, 0, 0, 0,223, 0, 0, 0, 34, 0, 0, 0,221, 0, 0, 0,228, 0, 0, 0, 34,
+ 0, 0, 0,222, 0, 0, 0,226, 0, 0, 0, 34, 0, 0, 0,223, 0, 0, 0,227, 0, 0, 0, 34, 0, 0, 0,178, 0, 0, 0,231,
+ 0, 0, 0, 34, 0, 0, 0,229, 0, 0, 0,231, 0, 0, 0, 34, 0, 0, 0,180, 0, 0, 0,229, 0, 0, 0, 34, 0, 0, 0,179,
+ 0, 0, 0,232, 0, 0, 0, 34, 0, 0, 0,181, 0, 0, 0,230, 0, 0, 0, 34, 0, 0, 0,230, 0, 0, 0,232, 0, 0, 0, 34,
+ 0, 0, 0,229, 0, 0, 0,251, 0, 0, 0, 34, 0, 0, 0,110, 0, 0, 0,251, 0, 0, 0, 34, 0, 0, 0,111, 0, 0, 0,252,
+ 0, 0, 0, 34, 0, 0, 0,230, 0, 0, 0,252, 0, 0, 0, 34, 0, 0, 0,251, 0, 0, 0,253, 0, 0, 0, 34, 0, 0, 0,108,
+ 0, 0, 0,253, 0, 0, 0, 34, 0, 0, 0,109, 0, 0, 0,254, 0, 0, 0, 34, 0, 0, 0,252, 0, 0, 0,254, 0, 0, 0, 34,
+ 0, 0, 0,231, 0, 0, 0,249, 0, 0, 0, 34, 0, 0, 0,112, 0, 0, 0,250, 0, 0, 0, 34, 0, 0, 0,232, 0, 0, 0,250,
+ 0, 0, 0, 34, 0, 0, 0,113, 0, 0, 0,247, 0, 0, 0, 34, 0, 0, 0,247, 0, 0, 0,249, 0, 0, 0, 34, 0, 0, 0,114,
+ 0, 0, 0,248, 0, 0, 0, 34, 0, 0, 0,248, 0, 0, 0,250, 0, 0, 0, 34, 0, 0, 0,115, 0, 0, 0,245, 0, 0, 0, 34,
+ 0, 0, 0,245, 0, 0, 0,247, 0, 0, 0, 34, 0, 0, 0,116, 0, 0, 0,246, 0, 0, 0, 34, 0, 0, 0,246, 0, 0, 0,248,
+ 0, 0, 0, 34, 0, 0, 0,117, 0, 0, 0,243, 0, 0, 0, 34, 0, 0, 0,243, 0, 0, 0,245, 0, 0, 0, 34, 0, 0, 0,118,
+ 0, 0, 0,244, 0, 0, 0, 34, 0, 0, 0,244, 0, 0, 0,246, 0, 0, 0, 34, 0, 0, 0,119, 0, 0, 0,241, 0, 0, 0, 34,
+ 0, 0, 0,241, 0, 0, 0,243, 0, 0, 0, 34, 0, 0, 0,120, 0, 0, 0,242, 0, 0, 0, 34, 0, 0, 0,242, 0, 0, 0,244,
+ 0, 0, 0, 34, 0, 0, 0,121, 0, 0, 0,239, 0, 0, 0, 34, 0, 0, 0,239, 0, 0, 0,241, 0, 0, 0, 34, 0, 0, 0,122,
+ 0, 0, 0,240, 0, 0, 0, 34, 0, 0, 0,240, 0, 0, 0,242, 0, 0, 0, 34, 0, 0, 0,123, 0, 0, 0,237, 0, 0, 0, 34,
+ 0, 0, 0,237, 0, 0, 0,239, 0, 0, 0, 34, 0, 0, 0,124, 0, 0, 0,238, 0, 0, 0, 34, 0, 0, 0,238, 0, 0, 0,240,
+ 0, 0, 0, 34, 0, 0, 0,176, 0, 0, 0,233, 0, 0, 0, 34, 0, 0, 0,233, 0, 0, 0,237, 0, 0, 0, 34, 0, 0, 0,177,
+ 0, 0, 0,234, 0, 0, 0, 34, 0, 0, 0,234, 0, 0, 0,238, 0, 0, 0, 34, 0, 0, 0,125, 0, 0, 0,235, 0, 0, 0, 34,
+ 0, 0, 0,233, 0, 0, 0,235, 0, 0, 0, 34, 0, 0, 0,126, 0, 0, 0,236, 0, 0, 0, 34, 0, 0, 0,234, 0, 0, 0,236,
+ 0, 0, 0, 34, 0, 0, 0,235, 0, 0, 0,253, 0, 0, 0, 34, 0, 0, 0,236, 0, 0, 0,254, 0, 0, 0, 34, 0, 0, 0,253,
+ 0, 0, 0,255, 0, 0, 0, 34, 0, 0, 0,255, 0, 0, 1, 17, 0, 0, 0, 34, 0, 0, 0,235, 0, 0, 1, 17, 0, 0, 0, 34,
+ 0, 0, 0,254, 0, 0, 1, 0, 0, 0, 0, 34, 0, 0, 0,236, 0, 0, 1, 18, 0, 0, 0, 34, 0, 0, 1, 0, 0, 0, 1, 18,
+ 0, 0, 0, 34, 0, 0, 1, 17, 0, 0, 1, 19, 0, 0, 0, 34, 0, 0, 0,233, 0, 0, 1, 19, 0, 0, 0, 34, 0, 0, 0,234,
+ 0, 0, 1, 20, 0, 0, 0, 34, 0, 0, 1, 18, 0, 0, 1, 20, 0, 0, 0, 34, 0, 0, 1, 15, 0, 0, 1, 19, 0, 0, 0, 34,
+ 0, 0, 0,237, 0, 0, 1, 15, 0, 0, 0, 34, 0, 0, 0,238, 0, 0, 1, 16, 0, 0, 0, 34, 0, 0, 1, 16, 0, 0, 1, 20,
+ 0, 0, 0, 34, 0, 0, 1, 13, 0, 0, 1, 15, 0, 0, 0, 34, 0, 0, 0,239, 0, 0, 1, 13, 0, 0, 0, 34, 0, 0, 0,240,
+ 0, 0, 1, 14, 0, 0, 0, 34, 0, 0, 1, 14, 0, 0, 1, 16, 0, 0, 0, 34, 0, 0, 1, 11, 0, 0, 1, 13, 0, 0, 0, 34,
+ 0, 0, 0,241, 0, 0, 1, 11, 0, 0, 0, 34, 0, 0, 0,242, 0, 0, 1, 12, 0, 0, 0, 34, 0, 0, 1, 12, 0, 0, 1, 14,
+ 0, 0, 0, 34, 0, 0, 1, 9, 0, 0, 1, 11, 0, 0, 0, 34, 0, 0, 0,243, 0, 0, 1, 9, 0, 0, 0, 34, 0, 0, 0,244,
+ 0, 0, 1, 10, 0, 0, 0, 34, 0, 0, 1, 10, 0, 0, 1, 12, 0, 0, 0, 34, 0, 0, 1, 7, 0, 0, 1, 9, 0, 0, 0, 34,
+ 0, 0, 0,245, 0, 0, 1, 7, 0, 0, 0, 34, 0, 0, 0,246, 0, 0, 1, 8, 0, 0, 0, 34, 0, 0, 1, 8, 0, 0, 1, 10,
+ 0, 0, 0, 34, 0, 0, 1, 5, 0, 0, 1, 7, 0, 0, 0, 34, 0, 0, 0,247, 0, 0, 1, 5, 0, 0, 0, 34, 0, 0, 0,248,
+ 0, 0, 1, 6, 0, 0, 0, 34, 0, 0, 1, 6, 0, 0, 1, 8, 0, 0, 0, 34, 0, 0, 1, 3, 0, 0, 1, 5, 0, 0, 0, 34,
+ 0, 0, 0,249, 0, 0, 1, 3, 0, 0, 0, 34, 0, 0, 0,250, 0, 0, 1, 4, 0, 0, 0, 34, 0, 0, 1, 4, 0, 0, 1, 6,
+ 0, 0, 0, 34, 0, 0, 1, 3, 0, 0, 1, 21, 0, 0, 0, 34, 0, 0, 0,231, 0, 0, 1, 21, 0, 0, 0, 34, 0, 0, 0,232,
+ 0, 0, 1, 22, 0, 0, 0, 34, 0, 0, 1, 4, 0, 0, 1, 22, 0, 0, 0, 34, 0, 0, 0,251, 0, 0, 1, 1, 0, 0, 0, 34,
+ 0, 0, 0,255, 0, 0, 1, 1, 0, 0, 0, 34, 0, 0, 0,252, 0, 0, 1, 2, 0, 0, 0, 34, 0, 0, 1, 0, 0, 0, 1, 2,
+ 0, 0, 0, 34, 0, 0, 0,229, 0, 0, 1, 23, 0, 0, 0, 34, 0, 0, 1, 1, 0, 0, 1, 23, 0, 0, 0, 34, 0, 0, 0,230,
+ 0, 0, 1, 24, 0, 0, 0, 34, 0, 0, 1, 2, 0, 0, 1, 24, 0, 0, 0, 34, 0, 0, 1, 21, 0, 0, 1, 23, 0, 0, 0, 34,
+ 0, 0, 1, 22, 0, 0, 1, 24, 0, 0, 0, 34, 0, 0, 0,106, 0, 0, 1, 25, 0, 0, 0, 34, 0, 0, 0, 71, 0, 0, 1, 25,
+ 0, 0, 0, 38, 0, 0, 0, 65, 0, 0, 0, 71, 0, 0, 0, 34, 0, 0, 0,107, 0, 0, 1, 26, 0, 0, 0, 34, 0, 0, 0, 71,
+ 0, 0, 1, 26, 0, 0, 0, 38, 0, 0, 0,104, 0, 0, 1, 27, 0, 0, 0, 34, 0, 0, 1, 25, 0, 0, 1, 27, 0, 0, 0, 34,
+ 0, 0, 0,105, 0, 0, 1, 28, 0, 0, 0, 34, 0, 0, 1, 26, 0, 0, 1, 28, 0, 0, 0, 34, 0, 0, 0,102, 0, 0, 1, 29,
+ 0, 0, 0, 34, 0, 0, 1, 27, 0, 0, 1, 29, 0, 0, 0, 34, 0, 0, 0,103, 0, 0, 1, 30, 0, 0, 0, 34, 0, 0, 1, 28,
+ 0, 0, 1, 30, 0, 0, 0, 34, 0, 0, 0,100, 0, 0, 1, 31, 0, 0, 0, 34, 0, 0, 1, 29, 0, 0, 1, 31, 0, 0, 0, 34,
+ 0, 0, 0,101, 0, 0, 1, 32, 0, 0, 0, 34, 0, 0, 1, 30, 0, 0, 1, 32, 0, 0, 0, 34, 0, 0, 0, 98, 0, 0, 1, 33,
+ 0, 0, 0, 34, 0, 0, 1, 31, 0, 0, 1, 33, 0, 0, 0, 38, 0, 0, 0, 99, 0, 0, 1, 34, 0, 0, 0, 34, 0, 0, 1, 32,
+ 0, 0, 1, 34, 0, 0, 0, 38, 0, 0, 0, 96, 0, 0, 1, 35, 0, 0, 0, 34, 0, 0, 1, 33, 0, 0, 1, 35, 0, 0, 0, 34,
+ 0, 0, 0, 97, 0, 0, 1, 36, 0, 0, 0, 34, 0, 0, 1, 34, 0, 0, 1, 36, 0, 0, 0, 34, 0, 0, 0, 94, 0, 0, 1, 37,
+ 0, 0, 0, 34, 0, 0, 1, 35, 0, 0, 1, 37, 0, 0, 0, 34, 0, 0, 0, 95, 0, 0, 1, 38, 0, 0, 0, 34, 0, 0, 1, 36,
+ 0, 0, 1, 38, 0, 0, 0, 34, 0, 0, 0, 92, 0, 0, 1, 39, 0, 0, 0, 34, 0, 0, 1, 37, 0, 0, 1, 39, 0, 0, 0, 34,
+ 0, 0, 0, 93, 0, 0, 1, 40, 0, 0, 0, 34, 0, 0, 1, 38, 0, 0, 1, 40, 0, 0, 0, 34, 0, 0, 0, 90, 0, 0, 1, 41,
+ 0, 0, 0, 34, 0, 0, 1, 39, 0, 0, 1, 41, 0, 0, 0, 34, 0, 0, 0, 91, 0, 0, 1, 42, 0, 0, 0, 34, 0, 0, 1, 40,
+ 0, 0, 1, 42, 0, 0, 0, 34, 0, 0, 1, 49, 0, 0, 1, 50, 0, 0, 0, 38, 0, 0, 1, 50, 0, 0, 1, 69, 0, 0, 0, 34,
+ 0, 0, 1, 69, 0, 0, 1, 79, 0, 0, 0, 34, 0, 0, 1, 49, 0, 0, 1, 79, 0, 0, 0, 34, 0, 0, 1, 50, 0, 0, 1, 70,
+ 0, 0, 0, 34, 0, 0, 1, 49, 0, 0, 1, 80, 0, 0, 0, 34, 0, 0, 1, 70, 0, 0, 1, 80, 0, 0, 0, 34, 0, 0, 1, 48,
+ 0, 0, 1, 49, 0, 0, 0, 38, 0, 0, 1, 77, 0, 0, 1, 79, 0, 0, 0, 34, 0, 0, 1, 48, 0, 0, 1, 77, 0, 0, 0, 34,
+ 0, 0, 1, 48, 0, 0, 1, 78, 0, 0, 0, 34, 0, 0, 1, 78, 0, 0, 1, 80, 0, 0, 0, 34, 0, 0, 1, 47, 0, 0, 1, 48,
+ 0, 0, 0, 38, 0, 0, 1, 77, 0, 0, 1, 81, 0, 0, 0, 34, 0, 0, 1, 47, 0, 0, 1, 81, 0, 0, 0, 34, 0, 0, 1, 47,
+ 0, 0, 1, 82, 0, 0, 0, 34, 0, 0, 1, 78, 0, 0, 1, 82, 0, 0, 0, 34, 0, 0, 0, 89, 0, 0, 1, 47, 0, 0, 0, 38,
+ 0, 0, 0, 87, 0, 0, 1, 81, 0, 0, 0, 34, 0, 0, 0, 88, 0, 0, 1, 82, 0, 0, 0, 34, 0, 0, 1, 75, 0, 0, 1, 81,
+ 0, 0, 0, 34, 0, 0, 0, 85, 0, 0, 1, 75, 0, 0, 0, 34, 0, 0, 0, 86, 0, 0, 1, 76, 0, 0, 0, 34, 0, 0, 1, 76,
+ 0, 0, 1, 82, 0, 0, 0, 34, 0, 0, 1, 71, 0, 0, 1, 75, 0, 0, 0, 34, 0, 0, 0, 83, 0, 0, 1, 71, 0, 0, 0, 34,
+ 0, 0, 0, 84, 0, 0, 1, 72, 0, 0, 0, 34, 0, 0, 1, 72, 0, 0, 1, 76, 0, 0, 0, 34, 0, 0, 1, 71, 0, 0, 1, 73,
+ 0, 0, 0, 34, 0, 0, 0, 81, 0, 0, 1, 73, 0, 0, 0, 34, 0, 0, 0, 82, 0, 0, 1, 74, 0, 0, 0, 34, 0, 0, 1, 72,
+ 0, 0, 1, 74, 0, 0, 0, 34, 0, 0, 1, 71, 0, 0, 1, 77, 0, 0, 0, 34, 0, 0, 1, 73, 0, 0, 1, 79, 0, 0, 0, 34,
+ 0, 0, 1, 72, 0, 0, 1, 78, 0, 0, 0, 34, 0, 0, 1, 74, 0, 0, 1, 80, 0, 0, 0, 34, 0, 0, 1, 67, 0, 0, 1, 73,
+ 0, 0, 0, 34, 0, 0, 1, 67, 0, 0, 1, 69, 0, 0, 0, 34, 0, 0, 1, 68, 0, 0, 1, 74, 0, 0, 0, 34, 0, 0, 1, 68,
+ 0, 0, 1, 70, 0, 0, 0, 34, 0, 0, 0, 79, 0, 0, 1, 67, 0, 0, 0, 34, 0, 0, 0, 80, 0, 0, 1, 68, 0, 0, 0, 34,
+ 0, 0, 0,206, 0, 0, 1, 83, 0, 0, 0, 34, 0, 0, 1, 83, 0, 0, 1, 85, 0, 0, 0, 34, 0, 0, 0,212, 0, 0, 1, 85,
+ 0, 0, 0, 34, 0, 0, 1, 84, 0, 0, 1, 86, 0, 0, 0, 34, 0, 0, 0,207, 0, 0, 1, 84, 0, 0, 0, 34, 0, 0, 0,213,
+ 0, 0, 1, 86, 0, 0, 0, 34, 0, 0, 1, 67, 0, 0, 1, 83, 0, 0, 0, 34, 0, 0, 1, 68, 0, 0, 1, 84, 0, 0, 0, 34,
+ 0, 0, 1, 85, 0, 0, 1, 87, 0, 0, 0, 34, 0, 0, 0, 77, 0, 0, 1, 87, 0, 0, 0, 34, 0, 0, 0, 78, 0, 0, 1, 88,
+ 0, 0, 0, 34, 0, 0, 1, 86, 0, 0, 1, 88, 0, 0, 0, 34, 0, 0, 1, 41, 0, 0, 1, 87, 0, 0, 0, 34, 0, 0, 1, 42,
+ 0, 0, 1, 88, 0, 0, 0, 34, 0, 0, 0, 75, 0, 0, 1, 65, 0, 0, 0, 34, 0, 0, 1, 65, 0, 0, 1, 93, 0, 0, 0, 34,
+ 0, 0, 1, 45, 0, 0, 1, 93, 0, 0, 0, 39, 0, 0, 0, 75, 0, 0, 1, 45, 0, 0, 0, 38, 0, 0, 1, 66, 0, 0, 1, 94,
+ 0, 0, 0, 34, 0, 0, 0, 75, 0, 0, 1, 66, 0, 0, 0, 34, 0, 0, 1, 45, 0, 0, 1, 94, 0, 0, 0, 39, 0, 0, 1, 91,
+ 0, 0, 1, 93, 0, 0, 0, 34, 0, 0, 0, 76, 0, 0, 1, 91, 0, 0, 0, 34, 0, 0, 0, 76, 0, 0, 1, 45, 0, 0, 0, 38,
+ 0, 0, 1, 92, 0, 0, 1, 94, 0, 0, 0, 34, 0, 0, 0, 76, 0, 0, 1, 92, 0, 0, 0, 34, 0, 0, 1, 89, 0, 0, 1, 91,
+ 0, 0, 0, 34, 0, 0, 1, 46, 0, 0, 1, 89, 0, 0, 0, 34, 0, 0, 0, 76, 0, 0, 1, 46, 0, 0, 0, 38, 0, 0, 1, 90,
+ 0, 0, 1, 92, 0, 0, 0, 34, 0, 0, 1, 46, 0, 0, 1, 90, 0, 0, 0, 34, 0, 0, 1, 69, 0, 0, 1, 89, 0, 0, 0, 34,
+ 0, 0, 1, 46, 0, 0, 1, 50, 0, 0, 0, 38, 0, 0, 1, 70, 0, 0, 1, 90, 0, 0, 0, 34, 0, 0, 1, 83, 0, 0, 1, 89,
+ 0, 0, 0, 34, 0, 0, 1, 84, 0, 0, 1, 90, 0, 0, 0, 34, 0, 0, 1, 39, 0, 0, 1, 59, 0, 0, 0, 34, 0, 0, 1, 51,
+ 0, 0, 1, 59, 0, 0, 0, 34, 0, 0, 1, 37, 0, 0, 1, 51, 0, 0, 0, 34, 0, 0, 1, 40, 0, 0, 1, 60, 0, 0, 0, 34,
+ 0, 0, 1, 38, 0, 0, 1, 52, 0, 0, 0, 34, 0, 0, 1, 52, 0, 0, 1, 60, 0, 0, 0, 34, 0, 0, 0, 74, 0, 0, 1, 57,
+ 0, 0, 0, 39, 0, 0, 1, 57, 0, 0, 1, 65, 0, 0, 0, 34, 0, 0, 0, 74, 0, 0, 0, 75, 0, 0, 0, 38, 0, 0, 1, 58,
+ 0, 0, 1, 66, 0, 0, 0, 34, 0, 0, 0, 74, 0, 0, 1, 58, 0, 0, 0, 39, 0, 0, 1, 43, 0, 0, 1, 99, 0, 0, 0, 34,
+ 0, 0, 1, 97, 0, 0, 1, 99, 0, 0, 0, 34, 0, 0, 1, 44, 0, 0, 1, 97, 0, 0, 0, 34, 0, 0, 1, 43, 0, 0, 1, 44,
+ 0, 0, 0, 38, 0, 0, 1, 98, 0, 0, 1,100, 0, 0, 0, 34, 0, 0, 1, 43, 0, 0, 1,100, 0, 0, 0, 34, 0, 0, 1, 44,
+ 0, 0, 1, 98, 0, 0, 0, 34, 0, 0, 1, 95, 0, 0, 1, 97, 0, 0, 0, 34, 0, 0, 0, 73, 0, 0, 1, 95, 0, 0, 0, 34,
+ 0, 0, 0, 73, 0, 0, 1, 44, 0, 0, 0, 38, 0, 0, 1, 96, 0, 0, 1, 98, 0, 0, 0, 34, 0, 0, 0, 73, 0, 0, 1, 96,
+ 0, 0, 0, 34, 0, 0, 1, 57, 0, 0, 1, 95, 0, 0, 0, 34, 0, 0, 0, 73, 0, 0, 0, 74, 0, 0, 0, 38, 0, 0, 1, 58,
+ 0, 0, 1, 96, 0, 0, 0, 34, 0, 0, 1, 35, 0, 0, 1,103, 0, 0, 0, 34, 0, 0, 1,103, 0, 0, 1,105, 0, 0, 0, 34,
+ 0, 0, 1, 33, 0, 0, 1,105, 0, 0, 0, 34, 0, 0, 1, 36, 0, 0, 1,104, 0, 0, 0, 34, 0, 0, 1, 34, 0, 0, 1,106,
+ 0, 0, 0, 34, 0, 0, 1,104, 0, 0, 1,106, 0, 0, 0, 34, 0, 0, 1,103, 0, 0, 1,109, 0, 0, 0, 34, 0, 0, 1,107,
+ 0, 0, 1,109, 0, 0, 0, 34, 0, 0, 1,105, 0, 0, 1,107, 0, 0, 0, 34, 0, 0, 1,104, 0, 0, 1,110, 0, 0, 0, 34,
+ 0, 0, 1,106, 0, 0, 1,108, 0, 0, 0, 34, 0, 0, 1,108, 0, 0, 1,110, 0, 0, 0, 34, 0, 0, 1,109, 0, 0, 1,111,
+ 0, 0, 0, 34, 0, 0, 1,111, 0, 0, 1,113, 0, 0, 0, 34, 0, 0, 1,107, 0, 0, 1,113, 0, 0, 0, 34, 0, 0, 1,110,
+ 0, 0, 1,112, 0, 0, 0, 34, 0, 0, 1,108, 0, 0, 1,114, 0, 0, 0, 34, 0, 0, 1,112, 0, 0, 1,114, 0, 0, 0, 34,
+ 0, 0, 1,111, 0, 0, 1,117, 0, 0, 0, 34, 0, 0, 1,115, 0, 0, 1,117, 0, 0, 0, 34, 0, 0, 1,113, 0, 0, 1,115,
+ 0, 0, 0, 34, 0, 0, 1,112, 0, 0, 1,118, 0, 0, 0, 34, 0, 0, 1,114, 0, 0, 1,116, 0, 0, 0, 34, 0, 0, 1,116,
+ 0, 0, 1,118, 0, 0, 0, 34, 0, 0, 1, 55, 0, 0, 1,119, 0, 0, 0, 39, 0, 0, 1,115, 0, 0, 1,119, 0, 0, 0, 34,
+ 0, 0, 1, 55, 0, 0, 1,117, 0, 0, 0, 34, 0, 0, 1,116, 0, 0, 1,120, 0, 0, 0, 34, 0, 0, 1, 56, 0, 0, 1,120,
+ 0, 0, 0, 39, 0, 0, 1, 56, 0, 0, 1,118, 0, 0, 0, 34, 0, 0, 1, 95, 0, 0, 1,115, 0, 0, 0, 34, 0, 0, 1, 57,
+ 0, 0, 1,119, 0, 0, 0, 39, 0, 0, 1, 96, 0, 0, 1,116, 0, 0, 0, 34, 0, 0, 1, 58, 0, 0, 1,120, 0, 0, 0, 39,
+ 0, 0, 1, 97, 0, 0, 1,113, 0, 0, 0, 34, 0, 0, 1, 98, 0, 0, 1,114, 0, 0, 0, 34, 0, 0, 1, 99, 0, 0, 1,107,
+ 0, 0, 0, 34, 0, 0, 1,100, 0, 0, 1,108, 0, 0, 0, 34, 0, 0, 1, 99, 0, 0, 1,101, 0, 0, 0, 34, 0, 0, 1,101,
+ 0, 0, 1,105, 0, 0, 0, 34, 0, 0, 1,102, 0, 0, 1,106, 0, 0, 0, 34, 0, 0, 1,100, 0, 0, 1,102, 0, 0, 0, 34,
+ 0, 0, 1, 31, 0, 0, 1,101, 0, 0, 0, 34, 0, 0, 1, 32, 0, 0, 1,102, 0, 0, 0, 34, 0, 0, 0, 72, 0, 0, 1,101,
+ 0, 0, 0, 34, 0, 0, 0, 72, 0, 0, 1, 43, 0, 0, 0, 38, 0, 0, 0, 72, 0, 0, 1,102, 0, 0, 0, 34, 0, 0, 1, 25,
+ 0, 0, 1, 31, 0, 0, 0, 38, 0, 0, 1, 26, 0, 0, 1, 32, 0, 0, 0, 38, 0, 0, 0, 72, 0, 0, 1, 25, 0, 0, 0, 34,
+ 0, 0, 0, 72, 0, 0, 1, 26, 0, 0, 0, 34, 0, 0, 0, 71, 0, 0, 0, 72, 0, 0, 0, 38, 0, 0, 1, 51, 0, 0, 1,103,
+ 0, 0, 0, 34, 0, 0, 1, 52, 0, 0, 1,104, 0, 0, 0, 34, 0, 0, 1, 51, 0, 0, 1, 53, 0, 0, 0, 34, 0, 0, 1, 53,
+ 0, 0, 1,109, 0, 0, 0, 34, 0, 0, 1, 54, 0, 0, 1,110, 0, 0, 0, 34, 0, 0, 1, 52, 0, 0, 1, 54, 0, 0, 0, 34,
+ 0, 0, 1, 53, 0, 0, 1,123, 0, 0, 0, 34, 0, 0, 1,111, 0, 0, 1,123, 0, 0, 0, 34, 0, 0, 1,112, 0, 0, 1,124,
+ 0, 0, 0, 34, 0, 0, 1, 54, 0, 0, 1,124, 0, 0, 0, 34, 0, 0, 1, 55, 0, 0, 1,123, 0, 0, 0, 34, 0, 0, 1, 56,
+ 0, 0, 1,124, 0, 0, 0, 34, 0, 0, 1, 91, 0, 0, 1,127, 0, 0, 0, 34, 0, 0, 1,125, 0, 0, 1,127, 0, 0, 0, 34,
+ 0, 0, 1, 89, 0, 0, 1,125, 0, 0, 0, 34, 0, 0, 1, 92, 0, 0, 1,128, 0, 0, 0, 34, 0, 0, 1, 90, 0, 0, 1,126,
+ 0, 0, 0, 34, 0, 0, 1,126, 0, 0, 1,128, 0, 0, 0, 34, 0, 0, 1, 59, 0, 0, 1,125, 0, 0, 0, 34, 0, 0, 1, 61,
+ 0, 0, 1,127, 0, 0, 0, 34, 0, 0, 1, 59, 0, 0, 1, 61, 0, 0, 0, 34, 0, 0, 1, 60, 0, 0, 1,126, 0, 0, 0, 34,
+ 0, 0, 1, 60, 0, 0, 1, 62, 0, 0, 0, 34, 0, 0, 1, 62, 0, 0, 1,128, 0, 0, 0, 34, 0, 0, 1, 41, 0, 0, 1,125,
+ 0, 0, 0, 34, 0, 0, 1, 42, 0, 0, 1,126, 0, 0, 0, 34, 0, 0, 1, 41, 0, 0, 1, 85, 0, 0, 0, 34, 0, 0, 1, 83,
+ 0, 0, 1,125, 0, 0, 0, 34, 0, 0, 1, 42, 0, 0, 1, 86, 0, 0, 0, 34, 0, 0, 1, 84, 0, 0, 1,126, 0, 0, 0, 34,
+ 0, 0, 1, 55, 0, 0, 1, 63, 0, 0, 0, 34, 0, 0, 1, 63, 0, 0, 1,121, 0, 0, 0, 39, 0, 0, 1,119, 0, 0, 1,121,
+ 0, 0, 0, 34, 0, 0, 1, 64, 0, 0, 1,122, 0, 0, 0, 39, 0, 0, 1, 56, 0, 0, 1, 64, 0, 0, 0, 34, 0, 0, 1,120,
+ 0, 0, 1,122, 0, 0, 0, 34, 0, 0, 1, 65, 0, 0, 1,121, 0, 0, 0, 34, 0, 0, 1, 66, 0, 0, 1,122, 0, 0, 0, 34,
+ 0, 0, 1,121, 0, 0, 1,127, 0, 0, 0, 34, 0, 0, 1, 61, 0, 0, 1, 63, 0, 0, 0, 34, 0, 0, 1,122, 0, 0, 1,128,
+ 0, 0, 0, 34, 0, 0, 1, 62, 0, 0, 1, 64, 0, 0, 0, 34, 0, 0, 1, 93, 0, 0, 1,121, 0, 0, 0, 39, 0, 0, 1, 94,
+ 0, 0, 1,122, 0, 0, 0, 39, 0, 0, 1,129, 0, 0, 1,141, 0, 0, 0, 34, 0, 0, 1,129, 0, 0, 1,155, 0, 0, 0, 34,
+ 0, 0, 1,143, 0, 0, 1,155, 0, 0, 0, 34, 0, 0, 1,141, 0, 0, 1,143, 0, 0, 0, 34, 0, 0, 1,130, 0, 0, 1,156,
+ 0, 0, 0, 34, 0, 0, 1,130, 0, 0, 1,142, 0, 0, 0, 34, 0, 0, 1,142, 0, 0, 1,144, 0, 0, 0, 34, 0, 0, 1,144,
+ 0, 0, 1,156, 0, 0, 0, 34, 0, 0, 1,143, 0, 0, 1,145, 0, 0, 0, 34, 0, 0, 1,139, 0, 0, 1,145, 0, 0, 0, 34,
+ 0, 0, 1,139, 0, 0, 1,141, 0, 0, 0, 34, 0, 0, 1,144, 0, 0, 1,146, 0, 0, 0, 34, 0, 0, 1,140, 0, 0, 1,142,
+ 0, 0, 0, 34, 0, 0, 1,140, 0, 0, 1,146, 0, 0, 0, 34, 0, 0, 1,145, 0, 0, 1,147, 0, 0, 0, 34, 0, 0, 1,137,
+ 0, 0, 1,147, 0, 0, 0, 34, 0, 0, 1,137, 0, 0, 1,139, 0, 0, 0, 34, 0, 0, 1,146, 0, 0, 1,148, 0, 0, 0, 34,
+ 0, 0, 1,138, 0, 0, 1,140, 0, 0, 0, 34, 0, 0, 1,138, 0, 0, 1,148, 0, 0, 0, 34, 0, 0, 1,147, 0, 0, 1,149,
+ 0, 0, 0, 34, 0, 0, 1,135, 0, 0, 1,149, 0, 0, 0, 34, 0, 0, 1,135, 0, 0, 1,137, 0, 0, 0, 34, 0, 0, 1,148,
+ 0, 0, 1,150, 0, 0, 0, 34, 0, 0, 1,136, 0, 0, 1,138, 0, 0, 0, 34, 0, 0, 1,136, 0, 0, 1,150, 0, 0, 0, 34,
+ 0, 0, 1,149, 0, 0, 1,151, 0, 0, 0, 34, 0, 0, 1,133, 0, 0, 1,151, 0, 0, 0, 34, 0, 0, 1,133, 0, 0, 1,135,
+ 0, 0, 0, 34, 0, 0, 1,150, 0, 0, 1,152, 0, 0, 0, 34, 0, 0, 1,134, 0, 0, 1,136, 0, 0, 0, 34, 0, 0, 1,134,
+ 0, 0, 1,152, 0, 0, 0, 34, 0, 0, 1,151, 0, 0, 1,153, 0, 0, 0, 34, 0, 0, 1,131, 0, 0, 1,153, 0, 0, 0, 34,
+ 0, 0, 1,131, 0, 0, 1,133, 0, 0, 0, 34, 0, 0, 1,152, 0, 0, 1,154, 0, 0, 0, 34, 0, 0, 1,132, 0, 0, 1,134,
+ 0, 0, 0, 34, 0, 0, 1,132, 0, 0, 1,154, 0, 0, 0, 34, 0, 0, 1,151, 0, 0, 1,161, 0, 0, 0, 34, 0, 0, 1,159,
+ 0, 0, 1,161, 0, 0, 0, 34, 0, 0, 1,153, 0, 0, 1,159, 0, 0, 0, 34, 0, 0, 1,160, 0, 0, 1,162, 0, 0, 0, 34,
+ 0, 0, 1,152, 0, 0, 1,162, 0, 0, 0, 34, 0, 0, 1,154, 0, 0, 1,160, 0, 0, 0, 34, 0, 0, 1,149, 0, 0, 1,163,
+ 0, 0, 0, 34, 0, 0, 1,161, 0, 0, 1,163, 0, 0, 0, 34, 0, 0, 1,162, 0, 0, 1,164, 0, 0, 0, 34, 0, 0, 1,150,
+ 0, 0, 1,164, 0, 0, 0, 34, 0, 0, 1,147, 0, 0, 1,165, 0, 0, 0, 34, 0, 0, 1,163, 0, 0, 1,165, 0, 0, 0, 34,
+ 0, 0, 1,164, 0, 0, 1,166, 0, 0, 0, 34, 0, 0, 1,148, 0, 0, 1,166, 0, 0, 0, 34, 0, 0, 1,145, 0, 0, 1,167,
+ 0, 0, 0, 34, 0, 0, 1,165, 0, 0, 1,167, 0, 0, 0, 34, 0, 0, 1,166, 0, 0, 1,168, 0, 0, 0, 34, 0, 0, 1,146,
+ 0, 0, 1,168, 0, 0, 0, 34, 0, 0, 1,143, 0, 0, 1,169, 0, 0, 0, 34, 0, 0, 1,167, 0, 0, 1,169, 0, 0, 0, 34,
+ 0, 0, 1,168, 0, 0, 1,170, 0, 0, 0, 34, 0, 0, 1,144, 0, 0, 1,170, 0, 0, 0, 34, 0, 0, 1,155, 0, 0, 1,157,
+ 0, 0, 0, 34, 0, 0, 1,157, 0, 0, 1,169, 0, 0, 0, 34, 0, 0, 1,156, 0, 0, 1,158, 0, 0, 0, 34, 0, 0, 1,158,
+ 0, 0, 1,170, 0, 0, 0, 34, 0, 0, 1, 61, 0, 0, 1,185, 0, 0, 0, 34, 0, 0, 1,183, 0, 0, 1,185, 0, 0, 0, 34,
+ 0, 0, 1, 59, 0, 0, 1,183, 0, 0, 0, 34, 0, 0, 1, 62, 0, 0, 1,186, 0, 0, 0, 34, 0, 0, 1, 60, 0, 0, 1,184,
+ 0, 0, 0, 34, 0, 0, 1,184, 0, 0, 1,186, 0, 0, 0, 34, 0, 0, 1, 61, 0, 0, 1,131, 0, 0, 0, 34, 0, 0, 1,153,
+ 0, 0, 1,185, 0, 0, 0, 34, 0, 0, 1, 62, 0, 0, 1,132, 0, 0, 0, 34, 0, 0, 1,154, 0, 0, 1,186, 0, 0, 0, 34,
+ 0, 0, 1, 53, 0, 0, 1,183, 0, 0, 0, 34, 0, 0, 1, 54, 0, 0, 1,184, 0, 0, 0, 34, 0, 0, 1,123, 0, 0, 1,171,
+ 0, 0, 0, 34, 0, 0, 1,155, 0, 0, 1,171, 0, 0, 0, 34, 0, 0, 1,123, 0, 0, 1,129, 0, 0, 0, 34, 0, 0, 1,156,
+ 0, 0, 1,172, 0, 0, 0, 34, 0, 0, 1,124, 0, 0, 1,172, 0, 0, 0, 34, 0, 0, 1,124, 0, 0, 1,130, 0, 0, 0, 34,
+ 0, 0, 1,159, 0, 0, 1,181, 0, 0, 0, 34, 0, 0, 1,181, 0, 0, 1,185, 0, 0, 0, 34, 0, 0, 1,160, 0, 0, 1,182,
+ 0, 0, 0, 34, 0, 0, 1,182, 0, 0, 1,186, 0, 0, 0, 34, 0, 0, 1,179, 0, 0, 1,187, 0, 0, 0, 34, 0, 0, 1,185,
+ 0, 0, 1,187, 0, 0, 0, 34, 0, 0, 1,179, 0, 0, 1,181, 0, 0, 0, 34, 0, 0, 1,186, 0, 0, 1,188, 0, 0, 0, 34,
+ 0, 0, 1,180, 0, 0, 1,188, 0, 0, 0, 34, 0, 0, 1,180, 0, 0, 1,182, 0, 0, 0, 34, 0, 0, 1,175, 0, 0, 1,187,
+ 0, 0, 0, 34, 0, 0, 1,177, 0, 0, 1,179, 0, 0, 0, 34, 0, 0, 1,175, 0, 0, 1,177, 0, 0, 0, 34, 0, 0, 1,176,
+ 0, 0, 1,188, 0, 0, 0, 34, 0, 0, 1,176, 0, 0, 1,178, 0, 0, 0, 34, 0, 0, 1,178, 0, 0, 1,180, 0, 0, 0, 34,
+ 0, 0, 1,173, 0, 0, 1,189, 0, 0, 0, 34, 0, 0, 1,187, 0, 0, 1,189, 0, 0, 0, 34, 0, 0, 1,173, 0, 0, 1,175,
+ 0, 0, 0, 34, 0, 0, 1,188, 0, 0, 1,190, 0, 0, 0, 34, 0, 0, 1,174, 0, 0, 1,190, 0, 0, 0, 34, 0, 0, 1,174,
+ 0, 0, 1,176, 0, 0, 0, 34, 0, 0, 1,171, 0, 0, 1,189, 0, 0, 0, 34, 0, 0, 1,173, 0, 0, 1,191, 0, 0, 0, 34,
+ 0, 0, 1,171, 0, 0, 1,191, 0, 0, 0, 32, 0, 0, 1,172, 0, 0, 1,190, 0, 0, 0, 34, 0, 0, 1,172, 0, 0, 1,192,
+ 0, 0, 0, 32, 0, 0, 1,174, 0, 0, 1,192, 0, 0, 0, 34, 0, 0, 1,157, 0, 0, 1,191, 0, 0, 0, 34, 0, 0, 1,158,
+ 0, 0, 1,192, 0, 0, 0, 34, 0, 0, 1, 53, 0, 0, 1,189, 0, 0, 0, 34, 0, 0, 1, 54, 0, 0, 1,190, 0, 0, 0, 34,
+ 0, 0, 1,183, 0, 0, 1,187, 0, 0, 0, 34, 0, 0, 1,184, 0, 0, 1,188, 0, 0, 0, 34, 0, 0, 1,191, 0, 0, 1,193,
+ 0, 0, 0, 34, 0, 0, 1,193, 0, 0, 1,217, 0, 0, 0, 34, 0, 0, 1,157, 0, 0, 1,217, 0, 0, 0, 34, 0, 0, 1,192,
+ 0, 0, 1,194, 0, 0, 0, 34, 0, 0, 1,158, 0, 0, 1,218, 0, 0, 0, 34, 0, 0, 1,194, 0, 0, 1,218, 0, 0, 0, 34,
+ 0, 0, 1,173, 0, 0, 1,203, 0, 0, 0, 34, 0, 0, 1,193, 0, 0, 1,203, 0, 0, 0, 34, 0, 0, 1,174, 0, 0, 1,204,
+ 0, 0, 0, 34, 0, 0, 1,194, 0, 0, 1,204, 0, 0, 0, 34, 0, 0, 1,175, 0, 0, 1,201, 0, 0, 0, 34, 0, 0, 1,201,
+ 0, 0, 1,203, 0, 0, 0, 34, 0, 0, 1,176, 0, 0, 1,202, 0, 0, 0, 34, 0, 0, 1,202, 0, 0, 1,204, 0, 0, 0, 34,
+ 0, 0, 1,177, 0, 0, 1,199, 0, 0, 0, 34, 0, 0, 1,199, 0, 0, 1,201, 0, 0, 0, 34, 0, 0, 1,178, 0, 0, 1,200,
+ 0, 0, 0, 34, 0, 0, 1,200, 0, 0, 1,202, 0, 0, 0, 34, 0, 0, 1,179, 0, 0, 1,197, 0, 0, 0, 34, 0, 0, 1,197,
+ 0, 0, 1,199, 0, 0, 0, 34, 0, 0, 1,180, 0, 0, 1,198, 0, 0, 0, 34, 0, 0, 1,198, 0, 0, 1,200, 0, 0, 0, 34,
+ 0, 0, 1,181, 0, 0, 1,195, 0, 0, 0, 34, 0, 0, 1,195, 0, 0, 1,197, 0, 0, 0, 34, 0, 0, 1,182, 0, 0, 1,196,
+ 0, 0, 0, 34, 0, 0, 1,196, 0, 0, 1,198, 0, 0, 0, 34, 0, 0, 1,159, 0, 0, 1,215, 0, 0, 0, 34, 0, 0, 1,195,
+ 0, 0, 1,215, 0, 0, 0, 34, 0, 0, 1,160, 0, 0, 1,216, 0, 0, 0, 34, 0, 0, 1,196, 0, 0, 1,216, 0, 0, 0, 34,
+ 0, 0, 1,205, 0, 0, 1,217, 0, 0, 0, 34, 0, 0, 1,169, 0, 0, 1,205, 0, 0, 0, 34, 0, 0, 1,170, 0, 0, 1,206,
+ 0, 0, 0, 34, 0, 0, 1,206, 0, 0, 1,218, 0, 0, 0, 34, 0, 0, 1,205, 0, 0, 1,207, 0, 0, 0, 34, 0, 0, 1,167,
+ 0, 0, 1,207, 0, 0, 0, 34, 0, 0, 1,168, 0, 0, 1,208, 0, 0, 0, 34, 0, 0, 1,206, 0, 0, 1,208, 0, 0, 0, 34,
+ 0, 0, 1,207, 0, 0, 1,209, 0, 0, 0, 34, 0, 0, 1,165, 0, 0, 1,209, 0, 0, 0, 34, 0, 0, 1,166, 0, 0, 1,210,
+ 0, 0, 0, 34, 0, 0, 1,208, 0, 0, 1,210, 0, 0, 0, 34, 0, 0, 1,209, 0, 0, 1,211, 0, 0, 0, 34, 0, 0, 1,163,
+ 0, 0, 1,211, 0, 0, 0, 34, 0, 0, 1,164, 0, 0, 1,212, 0, 0, 0, 34, 0, 0, 1,210, 0, 0, 1,212, 0, 0, 0, 34,
+ 0, 0, 1,211, 0, 0, 1,213, 0, 0, 0, 34, 0, 0, 1,161, 0, 0, 1,213, 0, 0, 0, 34, 0, 0, 1,162, 0, 0, 1,214,
+ 0, 0, 0, 34, 0, 0, 1,212, 0, 0, 1,214, 0, 0, 0, 34, 0, 0, 1,213, 0, 0, 1,215, 0, 0, 0, 34, 0, 0, 1,214,
+ 0, 0, 1,216, 0, 0, 0, 34, 0, 0, 1,197, 0, 0, 1,221, 0, 0, 0, 34, 0, 0, 1,219, 0, 0, 1,221, 0, 0, 0, 34,
+ 0, 0, 1,199, 0, 0, 1,219, 0, 0, 0, 34, 0, 0, 1,198, 0, 0, 1,222, 0, 0, 0, 34, 0, 0, 1,200, 0, 0, 1,220,
+ 0, 0, 0, 34, 0, 0, 1,220, 0, 0, 1,222, 0, 0, 0, 34, 0, 0, 1,221, 0, 0, 1,223, 0, 0, 0, 34, 0, 0, 1,223,
+ 0, 0, 1,225, 0, 0, 0, 32, 0, 0, 1,219, 0, 0, 1,225, 0, 0, 0, 34, 0, 0, 1,222, 0, 0, 1,224, 0, 0, 0, 34,
+ 0, 0, 1,220, 0, 0, 1,226, 0, 0, 0, 34, 0, 0, 1,224, 0, 0, 1,226, 0, 0, 0, 32, 0, 0, 1,223, 0, 0, 1,229,
+ 0, 0, 0, 34, 0, 0, 1,227, 0, 0, 1,229, 0, 0, 0, 34, 0, 0, 1,225, 0, 0, 1,227, 0, 0, 0, 34, 0, 0, 1,224,
+ 0, 0, 1,230, 0, 0, 0, 34, 0, 0, 1,226, 0, 0, 1,228, 0, 0, 0, 34, 0, 0, 1,228, 0, 0, 1,230, 0, 0, 0, 34,
+ 0, 0, 1,229, 0, 0, 1,231, 0, 0, 0, 34, 0, 0, 1,231, 0, 0, 1,233, 0, 0, 0, 34, 0, 0, 1,227, 0, 0, 1,233,
+ 0, 0, 0, 34, 0, 0, 1,230, 0, 0, 1,232, 0, 0, 0, 34, 0, 0, 1,228, 0, 0, 1,234, 0, 0, 0, 34, 0, 0, 1,232,
+ 0, 0, 1,234, 0, 0, 0, 34, 0, 0, 1,217, 0, 0, 1,227, 0, 0, 0, 34, 0, 0, 1,205, 0, 0, 1,233, 0, 0, 0, 34,
+ 0, 0, 1,218, 0, 0, 1,228, 0, 0, 0, 34, 0, 0, 1,206, 0, 0, 1,234, 0, 0, 0, 34, 0, 0, 1,193, 0, 0, 1,225,
+ 0, 0, 0, 34, 0, 0, 1,194, 0, 0, 1,226, 0, 0, 0, 34, 0, 0, 1,203, 0, 0, 1,219, 0, 0, 0, 34, 0, 0, 1,204,
+ 0, 0, 1,220, 0, 0, 0, 34, 0, 0, 1,215, 0, 0, 1,221, 0, 0, 0, 34, 0, 0, 1,216, 0, 0, 1,222, 0, 0, 0, 34,
+ 0, 0, 1,213, 0, 0, 1,223, 0, 0, 0, 34, 0, 0, 1,214, 0, 0, 1,224, 0, 0, 0, 34, 0, 0, 1,211, 0, 0, 1,229,
+ 0, 0, 0, 34, 0, 0, 1,212, 0, 0, 1,230, 0, 0, 0, 34, 0, 0, 1,209, 0, 0, 1,231, 0, 0, 0, 34, 0, 0, 1,210,
+ 0, 0, 1,232, 0, 0, 0, 34, 0, 0, 1,207, 0, 0, 1,233, 0, 0, 0, 34, 0, 0, 1,208, 0, 0, 1,234, 0, 0, 0, 34,
+ 0, 0, 1,131, 0, 0, 1,245, 0, 0, 0, 34, 0, 0, 1,243, 0, 0, 1,245, 0, 0, 0, 39, 0, 0, 1,133, 0, 0, 1,243,
+ 0, 0, 0, 34, 0, 0, 1,132, 0, 0, 1,246, 0, 0, 0, 34, 0, 0, 1,134, 0, 0, 1,244, 0, 0, 0, 34, 0, 0, 1,244,
+ 0, 0, 1,246, 0, 0, 0, 39, 0, 0, 1,241, 0, 0, 1,243, 0, 0, 0, 39, 0, 0, 1,135, 0, 0, 1,241, 0, 0, 0, 34,
+ 0, 0, 1,136, 0, 0, 1,242, 0, 0, 0, 34, 0, 0, 1,242, 0, 0, 1,244, 0, 0, 0, 39, 0, 0, 1,239, 0, 0, 1,241,
+ 0, 0, 0, 39, 0, 0, 1,137, 0, 0, 1,239, 0, 0, 0, 34, 0, 0, 1,138, 0, 0, 1,240, 0, 0, 0, 34, 0, 0, 1,240,
+ 0, 0, 1,242, 0, 0, 0, 39, 0, 0, 1,237, 0, 0, 1,239, 0, 0, 0, 39, 0, 0, 1,139, 0, 0, 1,237, 0, 0, 0, 34,
+ 0, 0, 1,140, 0, 0, 1,238, 0, 0, 0, 34, 0, 0, 1,238, 0, 0, 1,240, 0, 0, 0, 39, 0, 0, 1,235, 0, 0, 1,237,
+ 0, 0, 0, 39, 0, 0, 1,141, 0, 0, 1,235, 0, 0, 0, 34, 0, 0, 1,142, 0, 0, 1,236, 0, 0, 0, 34, 0, 0, 1,236,
+ 0, 0, 1,238, 0, 0, 0, 39, 0, 0, 1,235, 0, 0, 1,247, 0, 0, 0, 39, 0, 0, 1,129, 0, 0, 1,247, 0, 0, 0, 34,
+ 0, 0, 1,130, 0, 0, 1,248, 0, 0, 0, 34, 0, 0, 1,236, 0, 0, 1,248, 0, 0, 0, 39, 0, 0, 1,235, 0, 0, 1,243,
+ 0, 0, 0, 34, 0, 0, 1,245, 0, 0, 1,247, 0, 0, 0, 34, 0, 0, 1,236, 0, 0, 1,244, 0, 0, 0, 34, 0, 0, 1,246,
+ 0, 0, 1,248, 0, 0, 0, 34, 0, 0, 1,237, 0, 0, 1,241, 0, 0, 0, 34, 0, 0, 1,238, 0, 0, 1,242, 0, 0, 0, 34,
+ 0, 0, 1, 55, 0, 0, 1,247, 0, 0, 0, 39, 0, 0, 1, 56, 0, 0, 1,248, 0, 0, 0, 39, 0, 0, 1, 63, 0, 0, 1,245,
+ 0, 0, 0, 39, 0, 0, 1, 64, 0, 0, 1,246, 0, 0, 0, 39, 0, 0, 0, 14, 0, 0, 0,249, 0, 0, 0, 34, 0, 0, 0, 14,
+ 0, 0, 0,178, 0, 0, 0, 34, 0, 0, 0, 14, 0, 0, 0,113, 0, 0, 0, 34, 0, 0, 0, 14, 0, 0, 0,161, 0, 0, 0, 34,
+ 0, 0, 0, 20, 0, 0, 0,112, 0, 0, 0, 34, 0, 0, 0, 16, 0, 0, 0,112, 0, 0, 0, 34, 0, 0, 0, 9, 0, 0, 0,112,
+ 0, 0, 0, 34, 0, 0, 0, 13, 0, 0, 0,112, 0, 0, 0, 34, 68, 65, 84, 65, 0, 0, 1, 4, 2,236,207, 64, 0, 0, 0,242,
+ 0, 0, 0, 5, 0, 0, 0, 4, 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, 5, 31,184, 32, 0, 0, 0, 5, 0, 0, 0, 20,
+ 0, 0, 0, 0, 0, 0, 0, 0, 85, 86, 84,101,120, 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, 8,102,176, 32, 0, 0, 0, 6, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 67,111,108, 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, 5, 31,232, 32,
+ 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, 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, 68, 65, 84, 65, 0, 0, 39, 16, 5, 31,184, 32, 0, 0, 0, 52, 0, 0, 1,244, 0, 0, 0, 45,
+ 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 43, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 46, 0, 0, 0, 44,
+ 0, 0, 0, 1, 0, 0, 0, 43, 0, 0, 0, 2, 0, 0, 0, 4, 0, 0, 0, 41, 0, 0, 0, 1, 0, 0, 0, 5, 0, 0, 0, 3,
+ 0, 0, 0, 44, 0, 0, 0, 42, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 8, 0, 0, 0, 6, 0, 0, 0, 4, 0, 0, 0, 1,
+ 0, 0, 0, 7, 0, 0, 0, 9, 0, 0, 0, 3, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 8,
+ 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 9, 0, 0, 0, 11, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 10,
+ 0, 0, 0, 12, 0, 0, 0, 14, 0, 0, 0, 8, 0, 0, 0, 1, 0, 0, 0,112, 0, 0, 0, 13, 0, 0, 0, 11, 0, 0, 0, 9,
+ 0, 0, 0, 1, 0, 0, 0, 8, 0, 0, 0, 14, 0, 0, 0, 15, 0, 0, 0, 6, 0, 0, 0, 1, 0, 0, 0, 16, 0, 0, 0,112,
+ 0, 0, 0, 9, 0, 0, 0, 7, 0, 0, 0, 1, 0, 0, 0, 14, 0, 0, 0, 19, 0, 0, 0, 17, 0, 0, 0, 15, 0, 0, 0, 1,
+ 0, 0, 0, 18, 0, 0, 0, 20, 0, 0, 0,112, 0, 0, 0, 16, 0, 0, 0, 1, 0, 0, 0, 12, 0, 0, 0, 21, 0, 0, 0, 19,
+ 0, 0, 0, 14, 0, 0, 0, 1, 0, 0, 0, 20, 0, 0, 0, 22, 0, 0, 0, 13, 0, 0, 0,112, 0, 0, 0, 1, 0, 0, 0, 21,
+ 0, 0, 0, 23, 0, 0, 0, 25, 0, 0, 0, 19, 0, 0, 0, 1, 0, 0, 0, 26, 0, 0, 0, 24, 0, 0, 0, 22, 0, 0, 0, 20,
+ 0, 0, 0, 1, 0, 0, 0, 19, 0, 0, 0, 25, 0, 0, 0, 27, 0, 0, 0, 17, 0, 0, 0, 1, 0, 0, 0, 28, 0, 0, 0, 26,
+ 0, 0, 0, 20, 0, 0, 0, 18, 0, 0, 0, 1, 0, 0, 0, 25, 0, 0, 0, 31, 0, 0, 0, 29, 0, 0, 0, 27, 0, 0, 0, 1,
+ 0, 0, 0, 30, 0, 0, 0, 32, 0, 0, 0, 26, 0, 0, 0, 28, 0, 0, 0, 1, 0, 0, 0, 23, 0, 0, 0, 33, 0, 0, 0, 31,
+ 0, 0, 0, 25, 0, 0, 0, 1, 0, 0, 0, 32, 0, 0, 0, 34, 0, 0, 0, 24, 0, 0, 0, 26, 0, 0, 0, 1, 0, 0, 0, 33,
+ 0, 0, 0, 35, 0, 0, 0, 37, 0, 0, 0, 31, 0, 0, 0, 1, 0, 0, 0, 38, 0, 0, 0, 36, 0, 0, 0, 34, 0, 0, 0, 32,
+ 0, 0, 0, 1, 0, 0, 0, 31, 0, 0, 0, 37, 0, 0, 0, 39, 0, 0, 0, 29, 0, 0, 0, 1, 0, 0, 0, 40, 0, 0, 0, 38,
+ 0, 0, 0, 32, 0, 0, 0, 30, 0, 0, 0, 1, 0, 0, 0, 37, 0, 0, 0, 43, 0, 0, 0, 41, 0, 0, 0, 39, 0, 0, 0, 1,
+ 0, 0, 0, 42, 0, 0, 0, 44, 0, 0, 0, 38, 0, 0, 0, 40, 0, 0, 0, 1, 0, 0, 0, 35, 0, 0, 0, 45, 0, 0, 0, 43,
+ 0, 0, 0, 37, 0, 0, 0, 1, 0, 0, 0, 44, 0, 0, 0, 46, 0, 0, 0, 36, 0, 0, 0, 38, 0, 0, 0, 1, 0, 0, 0, 45,
+ 0, 0, 0, 35, 0, 0, 0, 49, 0, 0, 0, 47, 0, 0, 0, 1, 0, 0, 0, 50, 0, 0, 0, 36, 0, 0, 0, 46, 0, 0, 0, 48,
+ 0, 0, 0, 1, 0, 0, 0, 35, 0, 0, 0, 33, 0, 0, 0, 51, 0, 0, 0, 49, 0, 0, 0, 1, 0, 0, 0, 52, 0, 0, 0, 34,
+ 0, 0, 0, 36, 0, 0, 0, 50, 0, 0, 0, 1, 0, 0, 0, 33, 0, 0, 0, 23, 0, 0, 0, 53, 0, 0, 0, 51, 0, 0, 0, 1,
+ 0, 0, 0, 54, 0, 0, 0, 24, 0, 0, 0, 34, 0, 0, 0, 52, 0, 0, 0, 1, 0, 0, 0, 23, 0, 0, 0, 21, 0, 0, 0, 55,
+ 0, 0, 0, 53, 0, 0, 0, 1, 0, 0, 0, 56, 0, 0, 0, 22, 0, 0, 0, 24, 0, 0, 0, 54, 0, 0, 0, 1, 0, 0, 0, 21,
+ 0, 0, 0, 12, 0, 0, 0, 57, 0, 0, 0, 55, 0, 0, 0, 1, 0, 0, 0, 58, 0, 0, 0, 13, 0, 0, 0, 22, 0, 0, 0, 56,
+ 0, 0, 0, 1, 0, 0, 0, 12, 0, 0, 0, 10, 0, 0, 0, 61, 0, 0, 0, 57, 0, 0, 0, 1, 0, 0, 0, 62, 0, 0, 0, 11,
+ 0, 0, 0, 13, 0, 0, 0, 58, 0, 0, 0, 1, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 61, 0, 0, 0, 1,
+ 0, 0, 0, 64, 0, 0, 0, 1, 0, 0, 0, 11, 0, 0, 0, 62, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 45, 0, 0, 0, 47,
+ 0, 0, 0, 63, 0, 0, 0, 1, 0, 0, 0, 48, 0, 0, 0, 46, 0, 0, 0, 1, 0, 0, 0, 64, 0, 0, 0, 1, 0, 0, 0, 59,
+ 0, 0, 0, 63, 0, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 48, 0, 0, 0, 64, 0, 0, 0, 60, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 0, 61, 0, 0, 0, 63, 0, 0, 0, 59, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 60, 0, 0, 0, 64,
+ 0, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 59, 0, 0, 0, 57, 0, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 1,
+ 0, 0, 0, 62, 0, 0, 0, 58, 0, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 59, 0, 0, 0, 55, 0, 0, 0, 57,
+ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 58, 0, 0, 0, 56, 0, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 59,
+ 0, 0, 0, 53, 0, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 56, 0, 0, 0, 54, 0, 0, 0, 60, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 0, 59, 0, 0, 0, 51, 0, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 54, 0, 0, 0, 52,
+ 0, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 59, 0, 0, 0, 49, 0, 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 1,
+ 0, 0, 0, 52, 0, 0, 0, 50, 0, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 59, 0, 0, 0, 47, 0, 0, 0, 49,
+ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 50, 0, 0, 0, 48, 0, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 87,
+ 0, 0, 0,171, 0, 0, 0,173, 0, 0, 0, 89, 0, 0, 0, 1, 0, 0, 0,173, 0, 0, 0,172, 0, 0, 0, 88, 0, 0, 0, 89,
+ 0, 0, 0, 1, 0, 0, 0, 85, 0, 0, 0,169, 0, 0, 0,171, 0, 0, 0, 87, 0, 0, 0, 1, 0, 0, 0,172, 0, 0, 0,170,
+ 0, 0, 0, 86, 0, 0, 0, 88, 0, 0, 0, 1, 0, 0, 0, 83, 0, 0, 0,167, 0, 0, 0,169, 0, 0, 0, 85, 0, 0, 0, 1,
+ 0, 0, 0,170, 0, 0, 0,168, 0, 0, 0, 84, 0, 0, 0, 86, 0, 0, 0, 1, 0, 0, 0, 81, 0, 0, 0,165, 0, 0, 0,167,
+ 0, 0, 0, 83, 0, 0, 0, 1, 0, 0, 0,168, 0, 0, 0,166, 0, 0, 0, 82, 0, 0, 0, 84, 0, 0, 0, 1, 0, 0, 0, 79,
+ 0, 0, 0,163, 0, 0, 0,165, 0, 0, 0, 81, 0, 0, 0, 1, 0, 0, 0,166, 0, 0, 0,164, 0, 0, 0, 80, 0, 0, 0, 82,
+ 0, 0, 0, 1, 0, 0, 0, 77, 0, 0, 0, 90, 0, 0, 0,143, 0, 0, 0,161, 0, 0, 0, 1, 0, 0, 0,144, 0, 0, 0, 91,
+ 0, 0, 0, 78, 0, 0, 0,162, 0, 0, 0, 1, 0, 0, 0, 90, 0, 0, 0, 92, 0, 0, 0,145, 0, 0, 0,143, 0, 0, 0, 1,
+ 0, 0, 0,146, 0, 0, 0, 93, 0, 0, 0, 91, 0, 0, 0,144, 0, 0, 0, 1, 0, 0, 0, 92, 0, 0, 0, 94, 0, 0, 0,147,
+ 0, 0, 0,145, 0, 0, 0, 1, 0, 0, 0,148, 0, 0, 0, 95, 0, 0, 0, 93, 0, 0, 0,146, 0, 0, 0, 1, 0, 0, 0, 94,
+ 0, 0, 0, 96, 0, 0, 0,149, 0, 0, 0,147, 0, 0, 0, 1, 0, 0, 0,150, 0, 0, 0, 97, 0, 0, 0, 95, 0, 0, 0,148,
+ 0, 0, 0, 1, 0, 0, 0, 96, 0, 0, 0, 98, 0, 0, 0,151, 0, 0, 0,149, 0, 0, 0, 1, 0, 0, 0,152, 0, 0, 0, 99,
+ 0, 0, 0, 97, 0, 0, 0,150, 0, 0, 0, 1, 0, 0, 0, 98, 0, 0, 0,100, 0, 0, 0,153, 0, 0, 0,151, 0, 0, 0, 1,
+ 0, 0, 0,154, 0, 0, 0,101, 0, 0, 0, 99, 0, 0, 0,152, 0, 0, 0, 1, 0, 0, 0,100, 0, 0, 0,102, 0, 0, 0,155,
+ 0, 0, 0,153, 0, 0, 0, 1, 0, 0, 0,156, 0, 0, 0,103, 0, 0, 0,101, 0, 0, 0,154, 0, 0, 0, 1, 0, 0, 0,102,
+ 0, 0, 0,104, 0, 0, 0,157, 0, 0, 0,155, 0, 0, 0, 1, 0, 0, 0,158, 0, 0, 0,105, 0, 0, 0,103, 0, 0, 0,156,
+ 0, 0, 0, 1, 0, 0, 0,104, 0, 0, 0,106, 0, 0, 0,159, 0, 0, 0,157, 0, 0, 0, 1, 0, 0, 0,160, 0, 0, 0,107,
+ 0, 0, 0,105, 0, 0, 0,158, 0, 0, 0, 1, 0, 0, 0,106, 0, 0, 0, 65, 0, 0, 0, 66, 0, 0, 0,159, 0, 0, 0, 1,
+ 0, 0, 0, 66, 0, 0, 0, 65, 0, 0, 0,107, 0, 0, 0,160, 0, 0, 0, 1, 0, 0, 0,108, 0, 0, 0,125, 0, 0, 0,157,
+ 0, 0, 0,159, 0, 0, 0, 1, 0, 0, 0,158, 0, 0, 0,126, 0, 0, 0,109, 0, 0, 0,160, 0, 0, 0, 1, 0, 0, 0,125,
+ 0, 0, 0,176, 0, 0, 0,155, 0, 0, 0,157, 0, 0, 0, 1, 0, 0, 0,156, 0, 0, 0,177, 0, 0, 0,126, 0, 0, 0,158,
+ 0, 0, 0, 1, 0, 0, 0,123, 0, 0, 0,153, 0, 0, 0,155, 0, 0, 0,176, 0, 0, 0, 1, 0, 0, 0,156, 0, 0, 0,154,
+ 0, 0, 0,124, 0, 0, 0,177, 0, 0, 0, 1, 0, 0, 0,121, 0, 0, 0,151, 0, 0, 0,153, 0, 0, 0,123, 0, 0, 0, 1,
+ 0, 0, 0,154, 0, 0, 0,152, 0, 0, 0,122, 0, 0, 0,124, 0, 0, 0, 1, 0, 0, 0,119, 0, 0, 0,149, 0, 0, 0,151,
+ 0, 0, 0,121, 0, 0, 0, 1, 0, 0, 0,152, 0, 0, 0,150, 0, 0, 0,120, 0, 0, 0,122, 0, 0, 0, 1, 0, 0, 0,117,
+ 0, 0, 0,147, 0, 0, 0,149, 0, 0, 0,119, 0, 0, 0, 1, 0, 0, 0,150, 0, 0, 0,148, 0, 0, 0,118, 0, 0, 0,120,
+ 0, 0, 0, 1, 0, 0, 0,115, 0, 0, 0,145, 0, 0, 0,147, 0, 0, 0,117, 0, 0, 0, 1, 0, 0, 0,148, 0, 0, 0,146,
+ 0, 0, 0,116, 0, 0, 0,118, 0, 0, 0, 1, 0, 0, 0,113, 0, 0, 0,143, 0, 0, 0,145, 0, 0, 0,115, 0, 0, 0, 1,
+ 0, 0, 0,146, 0, 0, 0,144, 0, 0, 0,114, 0, 0, 0,116, 0, 0, 0, 1, 0, 0, 0, 14, 0, 0, 0,161, 0, 0, 0,143,
+ 0, 0, 0,113, 0, 0, 0, 1, 0, 0, 0,144, 0, 0, 0,162, 0, 0, 0,112, 0, 0, 0,114, 0, 0, 0, 1, 0, 0, 0, 14,
+ 0, 0, 0,178, 0, 0, 0,174, 0, 0, 0,161, 0, 0, 0, 1, 0, 0, 0,174, 0, 0, 0,179, 0, 0, 0,112, 0, 0, 0,162,
+ 0, 0, 0, 1, 0, 0, 0,108, 0, 0, 0,159, 0, 0, 0, 66, 0, 0, 0,110, 0, 0, 0, 1, 0, 0, 0, 66, 0, 0, 0,160,
+ 0, 0, 0,109, 0, 0, 0,111, 0, 0, 0, 1, 0, 0, 0,110, 0, 0, 0, 66, 0, 0, 0,175, 0, 0, 0,180, 0, 0, 0, 1,
+ 0, 0, 0,175, 0, 0, 0, 66, 0, 0, 0,111, 0, 0, 0,181, 0, 0, 0, 1, 0, 0, 0,174, 0, 0, 0,178, 0, 0, 0,180,
+ 0, 0, 0,175, 0, 0, 0, 1, 0, 0, 0,181, 0, 0, 0,179, 0, 0, 0,174, 0, 0, 0,175, 0, 0, 0, 1, 0, 0, 0,132,
+ 0, 0, 0,134, 0, 0, 0,173, 0, 0, 0,171, 0, 0, 0, 1, 0, 0, 0,173, 0, 0, 0,134, 0, 0, 0,133, 0, 0, 0,172,
+ 0, 0, 0, 1, 0, 0, 0,130, 0, 0, 0,132, 0, 0, 0,171, 0, 0, 0,169, 0, 0, 0, 1, 0, 0, 0,172, 0, 0, 0,133,
+ 0, 0, 0,131, 0, 0, 0,170, 0, 0, 0, 1, 0, 0, 0,128, 0, 0, 0,130, 0, 0, 0,169, 0, 0, 0,167, 0, 0, 0, 1,
+ 0, 0, 0,170, 0, 0, 0,131, 0, 0, 0,129, 0, 0, 0,168, 0, 0, 0, 1, 0, 0, 0,163, 0, 0, 0,184, 0, 0, 0,182,
+ 0, 0, 0,165, 0, 0, 0, 1, 0, 0, 0,183, 0, 0, 0,185, 0, 0, 0,164, 0, 0, 0,166, 0, 0, 0, 1, 0, 0, 0,128,
+ 0, 0, 0,167, 0, 0, 0,165, 0, 0, 0,182, 0, 0, 0, 1, 0, 0, 0,166, 0, 0, 0,168, 0, 0, 0,129, 0, 0, 0,183,
+ 0, 0, 0, 1, 0, 0, 0,141, 0, 0, 0,187, 0, 0, 0,186, 0, 0, 0,184, 0, 0, 0, 1, 0, 0, 0,186, 0, 0, 0,187,
+ 0, 0, 0,142, 0, 0, 0,185, 0, 0, 0, 1, 0, 0, 0,182, 0, 0, 0,184, 0, 0, 0,186, 0, 0, 0, 67, 0, 0, 0, 1,
+ 0, 0, 0,186, 0, 0, 0,185, 0, 0, 0,183, 0, 0, 0, 67, 0, 0, 0, 1, 0, 0, 0,127, 0, 0, 0,128, 0, 0, 0,182,
+ 0, 0, 0, 67, 0, 0, 0, 1, 0, 0, 0,183, 0, 0, 0,129, 0, 0, 0,127, 0, 0, 0, 67, 0, 0, 0, 1, 0, 0, 0,139,
+ 0, 0, 0,190, 0, 0, 0,188, 0, 0, 0,141, 0, 0, 0, 1, 0, 0, 0,189, 0, 0, 0,191, 0, 0, 0,140, 0, 0, 0,142,
+ 0, 0, 0, 1, 0, 0, 0,137, 0, 0, 0,192, 0, 0, 0,190, 0, 0, 0,139, 0, 0, 0, 1, 0, 0, 0,191, 0, 0, 0,193,
+ 0, 0, 0,138, 0, 0, 0,140, 0, 0, 0, 1, 0, 0, 0,136, 0, 0, 0,194, 0, 0, 0,192, 0, 0, 0,137, 0, 0, 0, 1,
+ 0, 0, 0,193, 0, 0, 0,195, 0, 0, 0,136, 0, 0, 0,138, 0, 0, 0, 1, 0, 0, 0,135, 0, 0, 0, 69, 0, 0, 0,194,
+ 0, 0, 0,136, 0, 0, 0, 1, 0, 0, 0,195, 0, 0, 0, 69, 0, 0, 0,135, 0, 0, 0,136, 0, 0, 0, 1, 0, 0, 0,187,
+ 0, 0, 0,141, 0, 0, 0,188, 0, 0, 0, 68, 0, 0, 0, 1, 0, 0, 0,189, 0, 0, 0,142, 0, 0, 0,187, 0, 0, 0, 68,
+ 0, 0, 0, 1, 0, 0, 0, 68, 0, 0, 0,188, 0, 0, 0,203, 0, 0, 0,205, 0, 0, 0, 1, 0, 0, 0,204, 0, 0, 0,189,
+ 0, 0, 0, 68, 0, 0, 0,205, 0, 0, 0, 1, 0, 0, 0, 69, 0, 0, 0,196, 0, 0, 0,197, 0, 0, 0,194, 0, 0, 0, 1,
+ 0, 0, 0,198, 0, 0, 0,196, 0, 0, 0, 69, 0, 0, 0,195, 0, 0, 0, 1, 0, 0, 0,194, 0, 0, 0,197, 0, 0, 0,199,
+ 0, 0, 0,192, 0, 0, 0, 1, 0, 0, 0,200, 0, 0, 0,198, 0, 0, 0,195, 0, 0, 0,193, 0, 0, 0, 1, 0, 0, 0,192,
+ 0, 0, 0,199, 0, 0, 0,201, 0, 0, 0,190, 0, 0, 0, 1, 0, 0, 0,202, 0, 0, 0,200, 0, 0, 0,193, 0, 0, 0,191,
+ 0, 0, 0, 1, 0, 0, 0,190, 0, 0, 0,201, 0, 0, 0,203, 0, 0, 0,188, 0, 0, 0, 1, 0, 0, 0,204, 0, 0, 0,202,
+ 0, 0, 0,191, 0, 0, 0,189, 0, 0, 0, 1, 0, 0, 0,196, 0, 0, 0,201, 0, 0, 0,199, 0, 0, 0,197, 0, 0, 0, 1,
+ 0, 0, 0,200, 0, 0, 0,202, 0, 0, 0,196, 0, 0, 0,198, 0, 0, 0, 1, 0, 0, 0,196, 0, 0, 0,205, 0, 0, 0,203,
+ 0, 0, 0,201, 0, 0, 0, 1, 0, 0, 0,204, 0, 0, 0,205, 0, 0, 0,196, 0, 0, 0,202, 0, 0, 0, 1, 0, 0, 0,136,
+ 0, 0, 0,137, 0, 0, 0,161, 0, 0, 0,174, 0, 0, 0, 1, 0, 0, 0,162, 0, 0, 0,138, 0, 0, 0,136, 0, 0, 0,174,
+ 0, 0, 0, 1, 0, 0, 0,137, 0, 0, 0,139, 0, 0, 0,208, 0, 0, 0,161, 0, 0, 0, 1, 0, 0, 0,209, 0, 0, 0,140,
+ 0, 0, 0,138, 0, 0, 0,162, 0, 0, 0, 1, 0, 0, 0,139, 0, 0, 0,141, 0, 0, 0,210, 0, 0, 0,208, 0, 0, 0, 1,
+ 0, 0, 0,211, 0, 0, 0,142, 0, 0, 0,140, 0, 0, 0,209, 0, 0, 0, 1, 0, 0, 0,141, 0, 0, 0,184, 0, 0, 0,163,
+ 0, 0, 0,210, 0, 0, 0, 1, 0, 0, 0,164, 0, 0, 0,185, 0, 0, 0,142, 0, 0, 0,211, 0, 0, 0, 1, 0, 0, 0, 79,
+ 0, 0, 0,206, 0, 0, 0,210, 0, 0, 0,163, 0, 0, 0, 1, 0, 0, 0,211, 0, 0, 0,207, 0, 0, 0, 80, 0, 0, 0,164,
+ 0, 0, 0, 1, 0, 0, 0,206, 0, 0, 0,212, 0, 0, 0,208, 0, 0, 0,210, 0, 0, 0, 1, 0, 0, 0,209, 0, 0, 0,213,
+ 0, 0, 0,207, 0, 0, 0,211, 0, 0, 0, 1, 0, 0, 0, 77, 0, 0, 0,161, 0, 0, 0,208, 0, 0, 0,212, 0, 0, 0, 1,
+ 0, 0, 0,209, 0, 0, 0,162, 0, 0, 0, 78, 0, 0, 0,213, 0, 0, 0, 1, 0, 0, 0,128, 0, 0, 0,127, 0, 0, 0, 70,
+ 0, 0, 0,219, 0, 0, 0, 1, 0, 0, 0, 70, 0, 0, 0,127, 0, 0, 0,129, 0, 0, 0,220, 0, 0, 0, 1, 0, 0, 0,130,
+ 0, 0, 0,128, 0, 0, 0,219, 0, 0, 0,217, 0, 0, 0, 1, 0, 0, 0,220, 0, 0, 0,129, 0, 0, 0,131, 0, 0, 0,218,
+ 0, 0, 0, 1, 0, 0, 0,132, 0, 0, 0,130, 0, 0, 0,217, 0, 0, 0,215, 0, 0, 0, 1, 0, 0, 0,218, 0, 0, 0,131,
+ 0, 0, 0,133, 0, 0, 0,216, 0, 0, 0, 1, 0, 0, 0,134, 0, 0, 0,132, 0, 0, 0,215, 0, 0, 0,214, 0, 0, 0, 1,
+ 0, 0, 0,216, 0, 0, 0,133, 0, 0, 0,134, 0, 0, 0,214, 0, 0, 0, 1, 0, 0, 0,214, 0, 0, 0,215, 0, 0, 0,226,
+ 0, 0, 0,228, 0, 0, 0, 1, 0, 0, 0,227, 0, 0, 0,216, 0, 0, 0,214, 0, 0, 0,228, 0, 0, 0, 1, 0, 0, 0,215,
+ 0, 0, 0,217, 0, 0, 0,224, 0, 0, 0,226, 0, 0, 0, 1, 0, 0, 0,225, 0, 0, 0,218, 0, 0, 0,216, 0, 0, 0,227,
+ 0, 0, 0, 1, 0, 0, 0,217, 0, 0, 0,219, 0, 0, 0,222, 0, 0, 0,224, 0, 0, 0, 1, 0, 0, 0,223, 0, 0, 0,220,
+ 0, 0, 0,218, 0, 0, 0,225, 0, 0, 0, 1, 0, 0, 0,219, 0, 0, 0, 70, 0, 0, 0,221, 0, 0, 0,222, 0, 0, 0, 1,
+ 0, 0, 0,221, 0, 0, 0, 70, 0, 0, 0,220, 0, 0, 0,223, 0, 0, 0, 1, 0, 0, 0,221, 0, 0, 0,228, 0, 0, 0,226,
+ 0, 0, 0,222, 0, 0, 0, 1, 0, 0, 0,227, 0, 0, 0,228, 0, 0, 0,221, 0, 0, 0,223, 0, 0, 0, 1, 0, 0, 0,222,
+ 0, 0, 0,226, 0, 0, 0,224, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,225, 0, 0, 0,227, 0, 0, 0,223, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 0,180, 0, 0, 0,178, 0, 0, 0,231, 0, 0, 0,229, 0, 0, 0, 1, 0, 0, 0,232, 0, 0, 0,179,
+ 0, 0, 0,181, 0, 0, 0,230, 0, 0, 0, 1, 0, 0, 0,110, 0, 0, 0,180, 0, 0, 0,229, 0, 0, 0,251, 0, 0, 0, 1,
+ 0, 0, 0,230, 0, 0, 0,181, 0, 0, 0,111, 0, 0, 0,252, 0, 0, 0, 1, 0, 0, 0,108, 0, 0, 0,110, 0, 0, 0,251,
+ 0, 0, 0,253, 0, 0, 0, 1, 0, 0, 0,252, 0, 0, 0,111, 0, 0, 0,109, 0, 0, 0,254, 0, 0, 0, 1, 0, 0, 0,178,
+ 0, 0, 0, 14, 0, 0, 0,249, 0, 0, 0,231, 0, 0, 0, 1, 0, 0, 0,250, 0, 0, 0,112, 0, 0, 0,179, 0, 0, 0,232,
+ 0, 0, 0, 1, 0, 0, 0, 14, 0, 0, 0,113, 0, 0, 0,247, 0, 0, 0,249, 0, 0, 0, 1, 0, 0, 0,248, 0, 0, 0,114,
+ 0, 0, 0,112, 0, 0, 0,250, 0, 0, 0, 1, 0, 0, 0,113, 0, 0, 0,115, 0, 0, 0,245, 0, 0, 0,247, 0, 0, 0, 1,
+ 0, 0, 0,246, 0, 0, 0,116, 0, 0, 0,114, 0, 0, 0,248, 0, 0, 0, 1, 0, 0, 0,115, 0, 0, 0,117, 0, 0, 0,243,
+ 0, 0, 0,245, 0, 0, 0, 1, 0, 0, 0,244, 0, 0, 0,118, 0, 0, 0,116, 0, 0, 0,246, 0, 0, 0, 1, 0, 0, 0,117,
+ 0, 0, 0,119, 0, 0, 0,241, 0, 0, 0,243, 0, 0, 0, 1, 0, 0, 0,242, 0, 0, 0,120, 0, 0, 0,118, 0, 0, 0,244,
+ 0, 0, 0, 1, 0, 0, 0,119, 0, 0, 0,121, 0, 0, 0,239, 0, 0, 0,241, 0, 0, 0, 1, 0, 0, 0,240, 0, 0, 0,122,
+ 0, 0, 0,120, 0, 0, 0,242, 0, 0, 0, 1, 0, 0, 0,121, 0, 0, 0,123, 0, 0, 0,237, 0, 0, 0,239, 0, 0, 0, 1,
+ 0, 0, 0,238, 0, 0, 0,124, 0, 0, 0,122, 0, 0, 0,240, 0, 0, 0, 1, 0, 0, 0,123, 0, 0, 0,176, 0, 0, 0,233,
+ 0, 0, 0,237, 0, 0, 0, 1, 0, 0, 0,234, 0, 0, 0,177, 0, 0, 0,124, 0, 0, 0,238, 0, 0, 0, 1, 0, 0, 0,176,
+ 0, 0, 0,125, 0, 0, 0,235, 0, 0, 0,233, 0, 0, 0, 1, 0, 0, 0,236, 0, 0, 0,126, 0, 0, 0,177, 0, 0, 0,234,
+ 0, 0, 0, 1, 0, 0, 0,125, 0, 0, 0,108, 0, 0, 0,253, 0, 0, 0,235, 0, 0, 0, 1, 0, 0, 0,254, 0, 0, 0,109,
+ 0, 0, 0,126, 0, 0, 0,236, 0, 0, 0, 1, 0, 0, 0,235, 0, 0, 0,253, 0, 0, 0,255, 0, 0, 1, 17, 0, 0, 0, 1,
+ 0, 0, 1, 0, 0, 0, 0,254, 0, 0, 0,236, 0, 0, 1, 18, 0, 0, 0, 1, 0, 0, 0,233, 0, 0, 0,235, 0, 0, 1, 17,
+ 0, 0, 1, 19, 0, 0, 0, 1, 0, 0, 1, 18, 0, 0, 0,236, 0, 0, 0,234, 0, 0, 1, 20, 0, 0, 0, 1, 0, 0, 0,237,
+ 0, 0, 0,233, 0, 0, 1, 19, 0, 0, 1, 15, 0, 0, 0, 1, 0, 0, 1, 20, 0, 0, 0,234, 0, 0, 0,238, 0, 0, 1, 16,
+ 0, 0, 0, 1, 0, 0, 0,239, 0, 0, 0,237, 0, 0, 1, 15, 0, 0, 1, 13, 0, 0, 0, 1, 0, 0, 1, 16, 0, 0, 0,238,
+ 0, 0, 0,240, 0, 0, 1, 14, 0, 0, 0, 1, 0, 0, 0,241, 0, 0, 0,239, 0, 0, 1, 13, 0, 0, 1, 11, 0, 0, 0, 1,
+ 0, 0, 1, 14, 0, 0, 0,240, 0, 0, 0,242, 0, 0, 1, 12, 0, 0, 0, 1, 0, 0, 0,243, 0, 0, 0,241, 0, 0, 1, 11,
+ 0, 0, 1, 9, 0, 0, 0, 1, 0, 0, 1, 12, 0, 0, 0,242, 0, 0, 0,244, 0, 0, 1, 10, 0, 0, 0, 1, 0, 0, 0,245,
+ 0, 0, 0,243, 0, 0, 1, 9, 0, 0, 1, 7, 0, 0, 0, 1, 0, 0, 1, 10, 0, 0, 0,244, 0, 0, 0,246, 0, 0, 1, 8,
+ 0, 0, 0, 1, 0, 0, 0,247, 0, 0, 0,245, 0, 0, 1, 7, 0, 0, 1, 5, 0, 0, 0, 1, 0, 0, 1, 8, 0, 0, 0,246,
+ 0, 0, 0,248, 0, 0, 1, 6, 0, 0, 0, 1, 0, 0, 0,249, 0, 0, 0,247, 0, 0, 1, 5, 0, 0, 1, 3, 0, 0, 0, 1,
+ 0, 0, 1, 6, 0, 0, 0,248, 0, 0, 0,250, 0, 0, 1, 4, 0, 0, 0, 1, 0, 0, 0,231, 0, 0, 0,249, 0, 0, 1, 3,
+ 0, 0, 1, 21, 0, 0, 0, 1, 0, 0, 1, 4, 0, 0, 0,250, 0, 0, 0,232, 0, 0, 1, 22, 0, 0, 0, 1, 0, 0, 0,253,
+ 0, 0, 0,251, 0, 0, 1, 1, 0, 0, 0,255, 0, 0, 0, 1, 0, 0, 1, 2, 0, 0, 0,252, 0, 0, 0,254, 0, 0, 1, 0,
+ 0, 0, 0, 1, 0, 0, 0,251, 0, 0, 0,229, 0, 0, 1, 23, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 24, 0, 0, 0,230,
+ 0, 0, 0,252, 0, 0, 1, 2, 0, 0, 0, 1, 0, 0, 0,229, 0, 0, 0,231, 0, 0, 1, 21, 0, 0, 1, 23, 0, 0, 0, 1,
+ 0, 0, 1, 22, 0, 0, 0,232, 0, 0, 0,230, 0, 0, 1, 24, 0, 0, 0, 1, 0, 0, 0, 65, 0, 0, 0,106, 0, 0, 1, 25,
+ 0, 0, 0, 71, 0, 0, 0, 1, 0, 0, 1, 26, 0, 0, 0,107, 0, 0, 0, 65, 0, 0, 0, 71, 0, 0, 0, 1, 0, 0, 0,106,
+ 0, 0, 0,104, 0, 0, 1, 27, 0, 0, 1, 25, 0, 0, 0, 1, 0, 0, 1, 28, 0, 0, 0,105, 0, 0, 0,107, 0, 0, 1, 26,
+ 0, 0, 0, 1, 0, 0, 0,104, 0, 0, 0,102, 0, 0, 1, 29, 0, 0, 1, 27, 0, 0, 0, 1, 0, 0, 1, 30, 0, 0, 0,103,
+ 0, 0, 0,105, 0, 0, 1, 28, 0, 0, 0, 1, 0, 0, 0,102, 0, 0, 0,100, 0, 0, 1, 31, 0, 0, 1, 29, 0, 0, 0, 1,
+ 0, 0, 1, 32, 0, 0, 0,101, 0, 0, 0,103, 0, 0, 1, 30, 0, 0, 0, 1, 0, 0, 0,100, 0, 0, 0, 98, 0, 0, 1, 33,
+ 0, 0, 1, 31, 0, 0, 0, 1, 0, 0, 1, 34, 0, 0, 0, 99, 0, 0, 0,101, 0, 0, 1, 32, 0, 0, 0, 1, 0, 0, 0, 98,
+ 0, 0, 0, 96, 0, 0, 1, 35, 0, 0, 1, 33, 0, 0, 0, 1, 0, 0, 1, 36, 0, 0, 0, 97, 0, 0, 0, 99, 0, 0, 1, 34,
+ 0, 0, 0, 1, 0, 0, 0, 96, 0, 0, 0, 94, 0, 0, 1, 37, 0, 0, 1, 35, 0, 0, 0, 1, 0, 0, 1, 38, 0, 0, 0, 95,
+ 0, 0, 0, 97, 0, 0, 1, 36, 0, 0, 0, 1, 0, 0, 0, 94, 0, 0, 0, 92, 0, 0, 1, 39, 0, 0, 1, 37, 0, 0, 0, 1,
+ 0, 0, 1, 40, 0, 0, 0, 93, 0, 0, 0, 95, 0, 0, 1, 38, 0, 0, 0, 1, 0, 0, 0, 92, 0, 0, 0, 90, 0, 0, 1, 41,
+ 0, 0, 1, 39, 0, 0, 0, 1, 0, 0, 1, 42, 0, 0, 0, 91, 0, 0, 0, 93, 0, 0, 1, 40, 0, 0, 0, 1, 0, 0, 1, 49,
+ 0, 0, 1, 50, 0, 0, 1, 69, 0, 0, 1, 79, 0, 0, 0, 1, 0, 0, 1, 70, 0, 0, 1, 50, 0, 0, 1, 49, 0, 0, 1, 80,
+ 0, 0, 0, 1, 0, 0, 1, 48, 0, 0, 1, 49, 0, 0, 1, 79, 0, 0, 1, 77, 0, 0, 0, 1, 0, 0, 1, 80, 0, 0, 1, 49,
+ 0, 0, 1, 48, 0, 0, 1, 78, 0, 0, 0, 1, 0, 0, 1, 47, 0, 0, 1, 48, 0, 0, 1, 77, 0, 0, 1, 81, 0, 0, 0, 1,
+ 0, 0, 1, 78, 0, 0, 1, 48, 0, 0, 1, 47, 0, 0, 1, 82, 0, 0, 0, 1, 0, 0, 0, 87, 0, 0, 0, 89, 0, 0, 1, 47,
+ 0, 0, 1, 81, 0, 0, 0, 1, 0, 0, 1, 47, 0, 0, 0, 89, 0, 0, 0, 88, 0, 0, 1, 82, 0, 0, 0, 1, 0, 0, 0, 85,
+ 0, 0, 0, 87, 0, 0, 1, 81, 0, 0, 1, 75, 0, 0, 0, 1, 0, 0, 1, 82, 0, 0, 0, 88, 0, 0, 0, 86, 0, 0, 1, 76,
+ 0, 0, 0, 1, 0, 0, 0, 83, 0, 0, 0, 85, 0, 0, 1, 75, 0, 0, 1, 71, 0, 0, 0, 1, 0, 0, 1, 76, 0, 0, 0, 86,
+ 0, 0, 0, 84, 0, 0, 1, 72, 0, 0, 0, 1, 0, 0, 0, 81, 0, 0, 0, 83, 0, 0, 1, 71, 0, 0, 1, 73, 0, 0, 0, 1,
+ 0, 0, 1, 72, 0, 0, 0, 84, 0, 0, 0, 82, 0, 0, 1, 74, 0, 0, 0, 1, 0, 0, 1, 71, 0, 0, 1, 77, 0, 0, 1, 79,
+ 0, 0, 1, 73, 0, 0, 0, 1, 0, 0, 1, 80, 0, 0, 1, 78, 0, 0, 1, 72, 0, 0, 1, 74, 0, 0, 0, 1, 0, 0, 1, 71,
+ 0, 0, 1, 75, 0, 0, 1, 81, 0, 0, 1, 77, 0, 0, 0, 1, 0, 0, 1, 82, 0, 0, 1, 76, 0, 0, 1, 72, 0, 0, 1, 78,
+ 0, 0, 0, 1, 0, 0, 1, 67, 0, 0, 1, 73, 0, 0, 1, 79, 0, 0, 1, 69, 0, 0, 0, 1, 0, 0, 1, 80, 0, 0, 1, 74,
+ 0, 0, 1, 68, 0, 0, 1, 70, 0, 0, 0, 1, 0, 0, 0, 79, 0, 0, 0, 81, 0, 0, 1, 73, 0, 0, 1, 67, 0, 0, 0, 1,
+ 0, 0, 1, 74, 0, 0, 0, 82, 0, 0, 0, 80, 0, 0, 1, 68, 0, 0, 0, 1, 0, 0, 0,206, 0, 0, 1, 83, 0, 0, 1, 85,
+ 0, 0, 0,212, 0, 0, 0, 1, 0, 0, 1, 86, 0, 0, 1, 84, 0, 0, 0,207, 0, 0, 0,213, 0, 0, 0, 1, 0, 0, 0, 79,
+ 0, 0, 1, 67, 0, 0, 1, 83, 0, 0, 0,206, 0, 0, 0, 1, 0, 0, 1, 84, 0, 0, 1, 68, 0, 0, 0, 80, 0, 0, 0,207,
+ 0, 0, 0, 1, 0, 0, 0, 77, 0, 0, 0,212, 0, 0, 1, 85, 0, 0, 1, 87, 0, 0, 0, 1, 0, 0, 1, 86, 0, 0, 0,213,
+ 0, 0, 0, 78, 0, 0, 1, 88, 0, 0, 0, 1, 0, 0, 0, 77, 0, 0, 1, 87, 0, 0, 1, 41, 0, 0, 0, 90, 0, 0, 0, 1,
+ 0, 0, 1, 42, 0, 0, 1, 88, 0, 0, 0, 78, 0, 0, 0, 91, 0, 0, 0, 1, 0, 0, 0, 75, 0, 0, 1, 65, 0, 0, 1, 93,
+ 0, 0, 1, 45, 0, 0, 0, 1, 0, 0, 1, 94, 0, 0, 1, 66, 0, 0, 0, 75, 0, 0, 1, 45, 0, 0, 0, 1, 0, 0, 1, 45,
+ 0, 0, 1, 93, 0, 0, 1, 91, 0, 0, 0, 76, 0, 0, 0, 1, 0, 0, 1, 92, 0, 0, 1, 94, 0, 0, 1, 45, 0, 0, 0, 76,
+ 0, 0, 0, 1, 0, 0, 0, 76, 0, 0, 1, 91, 0, 0, 1, 89, 0, 0, 1, 46, 0, 0, 0, 1, 0, 0, 1, 90, 0, 0, 1, 92,
+ 0, 0, 0, 76, 0, 0, 1, 46, 0, 0, 0, 1, 0, 0, 1, 46, 0, 0, 1, 89, 0, 0, 1, 69, 0, 0, 1, 50, 0, 0, 0, 1,
+ 0, 0, 1, 70, 0, 0, 1, 90, 0, 0, 1, 46, 0, 0, 1, 50, 0, 0, 0, 1, 0, 0, 1, 67, 0, 0, 1, 69, 0, 0, 1, 89,
+ 0, 0, 1, 83, 0, 0, 0, 1, 0, 0, 1, 90, 0, 0, 1, 70, 0, 0, 1, 68, 0, 0, 1, 84, 0, 0, 0, 1, 0, 0, 1, 37,
+ 0, 0, 1, 39, 0, 0, 1, 59, 0, 0, 1, 51, 0, 0, 0, 1, 0, 0, 1, 60, 0, 0, 1, 40, 0, 0, 1, 38, 0, 0, 1, 52,
+ 0, 0, 0, 1, 0, 0, 0, 74, 0, 0, 1, 57, 0, 0, 1, 65, 0, 0, 0, 75, 0, 0, 0, 1, 0, 0, 1, 66, 0, 0, 1, 58,
+ 0, 0, 0, 74, 0, 0, 0, 75, 0, 0, 0, 1, 0, 0, 1, 43, 0, 0, 1, 99, 0, 0, 1, 97, 0, 0, 1, 44, 0, 0, 0, 1,
+ 0, 0, 1, 98, 0, 0, 1,100, 0, 0, 1, 43, 0, 0, 1, 44, 0, 0, 0, 1, 0, 0, 1, 44, 0, 0, 1, 97, 0, 0, 1, 95,
+ 0, 0, 0, 73, 0, 0, 0, 1, 0, 0, 1, 96, 0, 0, 1, 98, 0, 0, 1, 44, 0, 0, 0, 73, 0, 0, 0, 1, 0, 0, 0, 73,
+ 0, 0, 1, 95, 0, 0, 1, 57, 0, 0, 0, 74, 0, 0, 0, 1, 0, 0, 1, 58, 0, 0, 1, 96, 0, 0, 0, 73, 0, 0, 0, 74,
+ 0, 0, 0, 1, 0, 0, 1, 33, 0, 0, 1, 35, 0, 0, 1,103, 0, 0, 1,105, 0, 0, 0, 1, 0, 0, 1,104, 0, 0, 1, 36,
+ 0, 0, 1, 34, 0, 0, 1,106, 0, 0, 0, 1, 0, 0, 1,105, 0, 0, 1,103, 0, 0, 1,109, 0, 0, 1,107, 0, 0, 0, 1,
+ 0, 0, 1,110, 0, 0, 1,104, 0, 0, 1,106, 0, 0, 1,108, 0, 0, 0, 1, 0, 0, 1,107, 0, 0, 1,109, 0, 0, 1,111,
+ 0, 0, 1,113, 0, 0, 0, 1, 0, 0, 1,112, 0, 0, 1,110, 0, 0, 1,108, 0, 0, 1,114, 0, 0, 0, 1, 0, 0, 1,113,
+ 0, 0, 1,111, 0, 0, 1,117, 0, 0, 1,115, 0, 0, 0, 1, 0, 0, 1,118, 0, 0, 1,112, 0, 0, 1,114, 0, 0, 1,116,
+ 0, 0, 0, 1, 0, 0, 1, 55, 0, 0, 1,119, 0, 0, 1,115, 0, 0, 1,117, 0, 0, 0, 1, 0, 0, 1,116, 0, 0, 1,120,
+ 0, 0, 1, 56, 0, 0, 1,118, 0, 0, 0, 1, 0, 0, 1, 57, 0, 0, 1, 95, 0, 0, 1,115, 0, 0, 1,119, 0, 0, 0, 1,
+ 0, 0, 1,116, 0, 0, 1, 96, 0, 0, 1, 58, 0, 0, 1,120, 0, 0, 0, 1, 0, 0, 1, 95, 0, 0, 1, 97, 0, 0, 1,113,
+ 0, 0, 1,115, 0, 0, 0, 1, 0, 0, 1,114, 0, 0, 1, 98, 0, 0, 1, 96, 0, 0, 1,116, 0, 0, 0, 1, 0, 0, 1, 97,
+ 0, 0, 1, 99, 0, 0, 1,107, 0, 0, 1,113, 0, 0, 0, 1, 0, 0, 1,108, 0, 0, 1,100, 0, 0, 1, 98, 0, 0, 1,114,
+ 0, 0, 0, 1, 0, 0, 1, 99, 0, 0, 1,101, 0, 0, 1,105, 0, 0, 1,107, 0, 0, 0, 1, 0, 0, 1,106, 0, 0, 1,102,
+ 0, 0, 1,100, 0, 0, 1,108, 0, 0, 0, 1, 0, 0, 1, 31, 0, 0, 1, 33, 0, 0, 1,105, 0, 0, 1,101, 0, 0, 0, 1,
+ 0, 0, 1,106, 0, 0, 1, 34, 0, 0, 1, 32, 0, 0, 1,102, 0, 0, 0, 1, 0, 0, 0, 72, 0, 0, 1,101, 0, 0, 1, 99,
+ 0, 0, 1, 43, 0, 0, 0, 1, 0, 0, 1,100, 0, 0, 1,102, 0, 0, 0, 72, 0, 0, 1, 43, 0, 0, 0, 1, 0, 0, 1, 25,
+ 0, 0, 1, 27, 0, 0, 1, 29, 0, 0, 1, 31, 0, 0, 0, 1, 0, 0, 1, 30, 0, 0, 1, 28, 0, 0, 1, 26, 0, 0, 1, 32,
+ 0, 0, 0, 1, 0, 0, 1, 25, 0, 0, 1, 31, 0, 0, 1,101, 0, 0, 0, 72, 0, 0, 0, 1, 0, 0, 1,102, 0, 0, 1, 32,
+ 0, 0, 1, 26, 0, 0, 0, 72, 0, 0, 0, 1, 0, 0, 0, 71, 0, 0, 1, 25, 0, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 1,
+ 0, 0, 0, 72, 0, 0, 1, 26, 0, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 35, 0, 0, 1, 37, 0, 0, 1, 51,
+ 0, 0, 1,103, 0, 0, 0, 1, 0, 0, 1, 52, 0, 0, 1, 38, 0, 0, 1, 36, 0, 0, 1,104, 0, 0, 0, 1, 0, 0, 1, 51,
+ 0, 0, 1, 53, 0, 0, 1,109, 0, 0, 1,103, 0, 0, 0, 1, 0, 0, 1,110, 0, 0, 1, 54, 0, 0, 1, 52, 0, 0, 1,104,
+ 0, 0, 0, 1, 0, 0, 1, 53, 0, 0, 1,123, 0, 0, 1,111, 0, 0, 1,109, 0, 0, 0, 1, 0, 0, 1,112, 0, 0, 1,124,
+ 0, 0, 1, 54, 0, 0, 1,110, 0, 0, 0, 1, 0, 0, 1, 55, 0, 0, 1,117, 0, 0, 1,111, 0, 0, 1,123, 0, 0, 0, 1,
+ 0, 0, 1,112, 0, 0, 1,118, 0, 0, 1, 56, 0, 0, 1,124, 0, 0, 0, 1, 0, 0, 1, 89, 0, 0, 1, 91, 0, 0, 1,127,
+ 0, 0, 1,125, 0, 0, 0, 1, 0, 0, 1,128, 0, 0, 1, 92, 0, 0, 1, 90, 0, 0, 1,126, 0, 0, 0, 1, 0, 0, 1, 59,
+ 0, 0, 1,125, 0, 0, 1,127, 0, 0, 1, 61, 0, 0, 0, 1, 0, 0, 1,128, 0, 0, 1,126, 0, 0, 1, 60, 0, 0, 1, 62,
+ 0, 0, 0, 1, 0, 0, 1, 39, 0, 0, 1, 41, 0, 0, 1,125, 0, 0, 1, 59, 0, 0, 0, 1, 0, 0, 1,126, 0, 0, 1, 42,
+ 0, 0, 1, 40, 0, 0, 1, 60, 0, 0, 0, 1, 0, 0, 1, 41, 0, 0, 1, 85, 0, 0, 1, 83, 0, 0, 1,125, 0, 0, 0, 1,
+ 0, 0, 1, 84, 0, 0, 1, 86, 0, 0, 1, 42, 0, 0, 1,126, 0, 0, 0, 1, 0, 0, 1, 83, 0, 0, 1, 89, 0, 0, 1,125,
+ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,126, 0, 0, 1, 90, 0, 0, 1, 84, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 41,
+ 0, 0, 1, 87, 0, 0, 1, 85, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 86, 0, 0, 1, 88, 0, 0, 1, 42, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 1, 55, 0, 0, 1, 63, 0, 0, 1,121, 0, 0, 1,119, 0, 0, 0, 1, 0, 0, 1,122, 0, 0, 1, 64,
+ 0, 0, 1, 56, 0, 0, 1,120, 0, 0, 0, 1, 0, 0, 1, 57, 0, 0, 1,119, 0, 0, 1,121, 0, 0, 1, 65, 0, 0, 0, 1,
+ 0, 0, 1,122, 0, 0, 1,120, 0, 0, 1, 58, 0, 0, 1, 66, 0, 0, 0, 1, 0, 0, 1, 61, 0, 0, 1,127, 0, 0, 1,121,
+ 0, 0, 1, 63, 0, 0, 0, 1, 0, 0, 1,122, 0, 0, 1,128, 0, 0, 1, 62, 0, 0, 1, 64, 0, 0, 0, 1, 0, 0, 1, 91,
+ 0, 0, 1, 93, 0, 0, 1,121, 0, 0, 1,127, 0, 0, 0, 1, 0, 0, 1,122, 0, 0, 1, 94, 0, 0, 1, 92, 0, 0, 1,128,
+ 0, 0, 0, 1, 0, 0, 1, 65, 0, 0, 1,121, 0, 0, 1, 93, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 94, 0, 0, 1,122,
+ 0, 0, 1, 66, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,141, 0, 0, 1,129, 0, 0, 1,155, 0, 0, 1,143, 0, 0, 0, 1,
+ 0, 0, 1,156, 0, 0, 1,130, 0, 0, 1,142, 0, 0, 1,144, 0, 0, 0, 1, 0, 0, 1,141, 0, 0, 1,143, 0, 0, 1,145,
+ 0, 0, 1,139, 0, 0, 0, 1, 0, 0, 1,146, 0, 0, 1,144, 0, 0, 1,142, 0, 0, 1,140, 0, 0, 0, 1, 0, 0, 1,139,
+ 0, 0, 1,145, 0, 0, 1,147, 0, 0, 1,137, 0, 0, 0, 1, 0, 0, 1,148, 0, 0, 1,146, 0, 0, 1,140, 0, 0, 1,138,
+ 0, 0, 0, 1, 0, 0, 1,137, 0, 0, 1,147, 0, 0, 1,149, 0, 0, 1,135, 0, 0, 0, 1, 0, 0, 1,150, 0, 0, 1,148,
+ 0, 0, 1,138, 0, 0, 1,136, 0, 0, 0, 1, 0, 0, 1,135, 0, 0, 1,149, 0, 0, 1,151, 0, 0, 1,133, 0, 0, 0, 1,
+ 0, 0, 1,152, 0, 0, 1,150, 0, 0, 1,136, 0, 0, 1,134, 0, 0, 0, 1, 0, 0, 1,133, 0, 0, 1,151, 0, 0, 1,153,
+ 0, 0, 1,131, 0, 0, 0, 1, 0, 0, 1,154, 0, 0, 1,152, 0, 0, 1,134, 0, 0, 1,132, 0, 0, 0, 1, 0, 0, 1,151,
+ 0, 0, 1,161, 0, 0, 1,159, 0, 0, 1,153, 0, 0, 0, 1, 0, 0, 1,160, 0, 0, 1,162, 0, 0, 1,152, 0, 0, 1,154,
+ 0, 0, 0, 1, 0, 0, 1,149, 0, 0, 1,163, 0, 0, 1,161, 0, 0, 1,151, 0, 0, 0, 1, 0, 0, 1,162, 0, 0, 1,164,
+ 0, 0, 1,150, 0, 0, 1,152, 0, 0, 0, 1, 0, 0, 1,147, 0, 0, 1,165, 0, 0, 1,163, 0, 0, 1,149, 0, 0, 0, 1,
+ 0, 0, 1,164, 0, 0, 1,166, 0, 0, 1,148, 0, 0, 1,150, 0, 0, 0, 1, 0, 0, 1,145, 0, 0, 1,167, 0, 0, 1,165,
+ 0, 0, 1,147, 0, 0, 0, 1, 0, 0, 1,166, 0, 0, 1,168, 0, 0, 1,146, 0, 0, 1,148, 0, 0, 0, 1, 0, 0, 1,143,
+ 0, 0, 1,169, 0, 0, 1,167, 0, 0, 1,145, 0, 0, 0, 1, 0, 0, 1,168, 0, 0, 1,170, 0, 0, 1,144, 0, 0, 1,146,
+ 0, 0, 0, 1, 0, 0, 1,143, 0, 0, 1,155, 0, 0, 1,157, 0, 0, 1,169, 0, 0, 0, 1, 0, 0, 1,158, 0, 0, 1,156,
+ 0, 0, 1,144, 0, 0, 1,170, 0, 0, 0, 1, 0, 0, 1, 59, 0, 0, 1, 61, 0, 0, 1,185, 0, 0, 1,183, 0, 0, 0, 1,
+ 0, 0, 1,186, 0, 0, 1, 62, 0, 0, 1, 60, 0, 0, 1,184, 0, 0, 0, 1, 0, 0, 1, 61, 0, 0, 1,131, 0, 0, 1,153,
+ 0, 0, 1,185, 0, 0, 0, 1, 0, 0, 1,154, 0, 0, 1,132, 0, 0, 1, 62, 0, 0, 1,186, 0, 0, 0, 1, 0, 0, 1, 51,
+ 0, 0, 1, 59, 0, 0, 1,183, 0, 0, 1, 53, 0, 0, 0, 1, 0, 0, 1,184, 0, 0, 1, 60, 0, 0, 1, 52, 0, 0, 1, 54,
+ 0, 0, 0, 1, 0, 0, 1,123, 0, 0, 1,171, 0, 0, 1,155, 0, 0, 1,129, 0, 0, 0, 1, 0, 0, 1,156, 0, 0, 1,172,
+ 0, 0, 1,124, 0, 0, 1,130, 0, 0, 0, 1, 0, 0, 1,153, 0, 0, 1,159, 0, 0, 1,181, 0, 0, 1,185, 0, 0, 0, 1,
+ 0, 0, 1,182, 0, 0, 1,160, 0, 0, 1,154, 0, 0, 1,186, 0, 0, 0, 1, 0, 0, 1,179, 0, 0, 1,187, 0, 0, 1,185,
+ 0, 0, 1,181, 0, 0, 0, 1, 0, 0, 1,186, 0, 0, 1,188, 0, 0, 1,180, 0, 0, 1,182, 0, 0, 0, 1, 0, 0, 1,175,
+ 0, 0, 1,187, 0, 0, 1,179, 0, 0, 1,177, 0, 0, 0, 1, 0, 0, 1,180, 0, 0, 1,188, 0, 0, 1,176, 0, 0, 1,178,
+ 0, 0, 0, 1, 0, 0, 1,173, 0, 0, 1,189, 0, 0, 1,187, 0, 0, 1,175, 0, 0, 0, 1, 0, 0, 1,188, 0, 0, 1,190,
+ 0, 0, 1,174, 0, 0, 1,176, 0, 0, 0, 1, 0, 0, 1,171, 0, 0, 1,189, 0, 0, 1,173, 0, 0, 1,191, 0, 0, 0, 1,
+ 0, 0, 1,174, 0, 0, 1,190, 0, 0, 1,172, 0, 0, 1,192, 0, 0, 0, 1, 0, 0, 1,155, 0, 0, 1,171, 0, 0, 1,191,
+ 0, 0, 1,157, 0, 0, 0, 1, 0, 0, 1,192, 0, 0, 1,172, 0, 0, 1,156, 0, 0, 1,158, 0, 0, 0, 1, 0, 0, 1, 53,
+ 0, 0, 1,189, 0, 0, 1,171, 0, 0, 1,123, 0, 0, 0, 1, 0, 0, 1,172, 0, 0, 1,190, 0, 0, 1, 54, 0, 0, 1,124,
+ 0, 0, 0, 1, 0, 0, 1, 53, 0, 0, 1,183, 0, 0, 1,187, 0, 0, 1,189, 0, 0, 0, 1, 0, 0, 1,188, 0, 0, 1,184,
+ 0, 0, 1, 54, 0, 0, 1,190, 0, 0, 0, 1, 0, 0, 1,183, 0, 0, 1,185, 0, 0, 1,187, 0, 0, 0, 0, 0, 0, 0, 1,
+ 0, 0, 1,188, 0, 0, 1,186, 0, 0, 1,184, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,157, 0, 0, 1,191, 0, 0, 1,193,
+ 0, 0, 1,217, 0, 0, 0, 1, 0, 0, 1,194, 0, 0, 1,192, 0, 0, 1,158, 0, 0, 1,218, 0, 0, 0, 1, 0, 0, 1,191,
+ 0, 0, 1,173, 0, 0, 1,203, 0, 0, 1,193, 0, 0, 0, 1, 0, 0, 1,204, 0, 0, 1,174, 0, 0, 1,192, 0, 0, 1,194,
+ 0, 0, 0, 1, 0, 0, 1,173, 0, 0, 1,175, 0, 0, 1,201, 0, 0, 1,203, 0, 0, 0, 1, 0, 0, 1,202, 0, 0, 1,176,
+ 0, 0, 1,174, 0, 0, 1,204, 0, 0, 0, 1, 0, 0, 1,175, 0, 0, 1,177, 0, 0, 1,199, 0, 0, 1,201, 0, 0, 0, 1,
+ 0, 0, 1,200, 0, 0, 1,178, 0, 0, 1,176, 0, 0, 1,202, 0, 0, 0, 1, 0, 0, 1,177, 0, 0, 1,179, 0, 0, 1,197,
+ 0, 0, 1,199, 0, 0, 0, 1, 0, 0, 1,198, 0, 0, 1,180, 0, 0, 1,178, 0, 0, 1,200, 0, 0, 0, 1, 0, 0, 1,179,
+ 0, 0, 1,181, 0, 0, 1,195, 0, 0, 1,197, 0, 0, 0, 1, 0, 0, 1,196, 0, 0, 1,182, 0, 0, 1,180, 0, 0, 1,198,
+ 0, 0, 0, 1, 0, 0, 1,181, 0, 0, 1,159, 0, 0, 1,215, 0, 0, 1,195, 0, 0, 0, 1, 0, 0, 1,216, 0, 0, 1,160,
+ 0, 0, 1,182, 0, 0, 1,196, 0, 0, 0, 1, 0, 0, 1,169, 0, 0, 1,157, 0, 0, 1,217, 0, 0, 1,205, 0, 0, 0, 1,
+ 0, 0, 1,218, 0, 0, 1,158, 0, 0, 1,170, 0, 0, 1,206, 0, 0, 0, 1, 0, 0, 1,167, 0, 0, 1,169, 0, 0, 1,205,
+ 0, 0, 1,207, 0, 0, 0, 1, 0, 0, 1,206, 0, 0, 1,170, 0, 0, 1,168, 0, 0, 1,208, 0, 0, 0, 1, 0, 0, 1,165,
+ 0, 0, 1,167, 0, 0, 1,207, 0, 0, 1,209, 0, 0, 0, 1, 0, 0, 1,208, 0, 0, 1,168, 0, 0, 1,166, 0, 0, 1,210,
+ 0, 0, 0, 1, 0, 0, 1,163, 0, 0, 1,165, 0, 0, 1,209, 0, 0, 1,211, 0, 0, 0, 1, 0, 0, 1,210, 0, 0, 1,166,
+ 0, 0, 1,164, 0, 0, 1,212, 0, 0, 0, 1, 0, 0, 1,161, 0, 0, 1,163, 0, 0, 1,211, 0, 0, 1,213, 0, 0, 0, 1,
+ 0, 0, 1,212, 0, 0, 1,164, 0, 0, 1,162, 0, 0, 1,214, 0, 0, 0, 1, 0, 0, 1,159, 0, 0, 1,161, 0, 0, 1,213,
+ 0, 0, 1,215, 0, 0, 0, 1, 0, 0, 1,214, 0, 0, 1,162, 0, 0, 1,160, 0, 0, 1,216, 0, 0, 0, 1, 0, 0, 1,199,
+ 0, 0, 1,197, 0, 0, 1,221, 0, 0, 1,219, 0, 0, 0, 1, 0, 0, 1,222, 0, 0, 1,198, 0, 0, 1,200, 0, 0, 1,220,
+ 0, 0, 0, 1, 0, 0, 1,219, 0, 0, 1,221, 0, 0, 1,223, 0, 0, 1,225, 0, 0, 0, 1, 0, 0, 1,224, 0, 0, 1,222,
+ 0, 0, 1,220, 0, 0, 1,226, 0, 0, 0, 1, 0, 0, 1,225, 0, 0, 1,223, 0, 0, 1,229, 0, 0, 1,227, 0, 0, 0, 1,
+ 0, 0, 1,230, 0, 0, 1,224, 0, 0, 1,226, 0, 0, 1,228, 0, 0, 0, 1, 0, 0, 1,227, 0, 0, 1,229, 0, 0, 1,231,
+ 0, 0, 1,233, 0, 0, 0, 1, 0, 0, 1,232, 0, 0, 1,230, 0, 0, 1,228, 0, 0, 1,234, 0, 0, 0, 1, 0, 0, 1,205,
+ 0, 0, 1,217, 0, 0, 1,227, 0, 0, 1,233, 0, 0, 0, 1, 0, 0, 1,228, 0, 0, 1,218, 0, 0, 1,206, 0, 0, 1,234,
+ 0, 0, 0, 1, 0, 0, 1,193, 0, 0, 1,225, 0, 0, 1,227, 0, 0, 1,217, 0, 0, 0, 1, 0, 0, 1,228, 0, 0, 1,226,
+ 0, 0, 1,194, 0, 0, 1,218, 0, 0, 0, 1, 0, 0, 1,193, 0, 0, 1,203, 0, 0, 1,219, 0, 0, 1,225, 0, 0, 0, 1,
+ 0, 0, 1,220, 0, 0, 1,204, 0, 0, 1,194, 0, 0, 1,226, 0, 0, 0, 1, 0, 0, 1,199, 0, 0, 1,219, 0, 0, 1,203,
+ 0, 0, 1,201, 0, 0, 0, 1, 0, 0, 1,204, 0, 0, 1,220, 0, 0, 1,200, 0, 0, 1,202, 0, 0, 0, 1, 0, 0, 1,195,
+ 0, 0, 1,215, 0, 0, 1,221, 0, 0, 1,197, 0, 0, 0, 1, 0, 0, 1,222, 0, 0, 1,216, 0, 0, 1,196, 0, 0, 1,198,
+ 0, 0, 0, 1, 0, 0, 1,213, 0, 0, 1,223, 0, 0, 1,221, 0, 0, 1,215, 0, 0, 0, 1, 0, 0, 1,222, 0, 0, 1,224,
+ 0, 0, 1,214, 0, 0, 1,216, 0, 0, 0, 1, 0, 0, 1,211, 0, 0, 1,229, 0, 0, 1,223, 0, 0, 1,213, 0, 0, 0, 1,
+ 0, 0, 1,224, 0, 0, 1,230, 0, 0, 1,212, 0, 0, 1,214, 0, 0, 0, 1, 0, 0, 1,209, 0, 0, 1,231, 0, 0, 1,229,
+ 0, 0, 1,211, 0, 0, 0, 1, 0, 0, 1,230, 0, 0, 1,232, 0, 0, 1,210, 0, 0, 1,212, 0, 0, 0, 1, 0, 0, 1,207,
+ 0, 0, 1,233, 0, 0, 1,231, 0, 0, 1,209, 0, 0, 0, 1, 0, 0, 1,232, 0, 0, 1,234, 0, 0, 1,208, 0, 0, 1,210,
+ 0, 0, 0, 1, 0, 0, 1,205, 0, 0, 1,233, 0, 0, 1,207, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,208, 0, 0, 1,234,
+ 0, 0, 1,206, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,133, 0, 0, 1,131, 0, 0, 1,245, 0, 0, 1,243, 0, 0, 0, 1,
+ 0, 0, 1,246, 0, 0, 1,132, 0, 0, 1,134, 0, 0, 1,244, 0, 0, 0, 1, 0, 0, 1,135, 0, 0, 1,133, 0, 0, 1,243,
+ 0, 0, 1,241, 0, 0, 0, 1, 0, 0, 1,244, 0, 0, 1,134, 0, 0, 1,136, 0, 0, 1,242, 0, 0, 0, 1, 0, 0, 1,137,
+ 0, 0, 1,135, 0, 0, 1,241, 0, 0, 1,239, 0, 0, 0, 1, 0, 0, 1,242, 0, 0, 1,136, 0, 0, 1,138, 0, 0, 1,240,
+ 0, 0, 0, 1, 0, 0, 1,139, 0, 0, 1,137, 0, 0, 1,239, 0, 0, 1,237, 0, 0, 0, 1, 0, 0, 1,240, 0, 0, 1,138,
+ 0, 0, 1,140, 0, 0, 1,238, 0, 0, 0, 1, 0, 0, 1,141, 0, 0, 1,139, 0, 0, 1,237, 0, 0, 1,235, 0, 0, 0, 1,
+ 0, 0, 1,238, 0, 0, 1,140, 0, 0, 1,142, 0, 0, 1,236, 0, 0, 0, 1, 0, 0, 1,129, 0, 0, 1,141, 0, 0, 1,235,
+ 0, 0, 1,247, 0, 0, 0, 1, 0, 0, 1,236, 0, 0, 1,142, 0, 0, 1,130, 0, 0, 1,248, 0, 0, 0, 1, 0, 0, 1,235,
+ 0, 0, 1,243, 0, 0, 1,245, 0, 0, 1,247, 0, 0, 0, 1, 0, 0, 1,246, 0, 0, 1,244, 0, 0, 1,236, 0, 0, 1,248,
+ 0, 0, 0, 1, 0, 0, 1,235, 0, 0, 1,237, 0, 0, 1,241, 0, 0, 1,243, 0, 0, 0, 1, 0, 0, 1,242, 0, 0, 1,238,
+ 0, 0, 1,236, 0, 0, 1,244, 0, 0, 0, 1, 0, 0, 1,237, 0, 0, 1,239, 0, 0, 1,241, 0, 0, 0, 0, 0, 0, 0, 1,
+ 0, 0, 1,242, 0, 0, 1,240, 0, 0, 1,238, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 55, 0, 0, 1,123, 0, 0, 1,129,
+ 0, 0, 1,247, 0, 0, 0, 1, 0, 0, 1,130, 0, 0, 1,124, 0, 0, 1, 56, 0, 0, 1,248, 0, 0, 0, 1, 0, 0, 1, 55,
+ 0, 0, 1,247, 0, 0, 1,245, 0, 0, 1, 63, 0, 0, 0, 1, 0, 0, 1,246, 0, 0, 1,248, 0, 0, 1, 56, 0, 0, 1, 64,
+ 0, 0, 0, 1, 0, 0, 1, 61, 0, 0, 1, 63, 0, 0, 1,245, 0, 0, 1,131, 0, 0, 0, 1, 0, 0, 1,246, 0, 0, 1, 64,
+ 0, 0, 1, 62, 0, 0, 1,132, 0, 0, 0, 1, 68, 65, 84, 65, 0, 0, 85,240, 8,102,176, 32, 0, 0, 0, 60, 0, 0, 1,244,
+ 63, 28,112, 3, 62,236,178,185, 63, 27,124,224, 62,232, 65,235, 63, 30, 63,144, 62,226,195,233, 63, 32,152,118, 62,236,167, 37,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,240, 62,209,232, 2, 62,226, 21,222, 62,215,109,102, 62,231,147,222, 62,213,135, 28,
+ 62,236, 4,172, 62,205, 54, 56, 62,235,249, 22, 2,236,169, 32, 61, 0, 0, 5, 0, 0, 0,240, 63, 32,152,118, 62,236,167, 37,
+ 63, 30, 63,144, 62,226,195,233, 63, 33,235,108, 62,220,235,197, 63, 37,151,209, 62,236,161, 89, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0,240, 62,202,144, 76, 62,220, 61,186, 62,209,232, 2, 62,226, 21,222, 62,205, 54, 56, 62,235,249, 22, 62,195, 55,128,
+ 62,235,243, 70, 2,236,169, 32, 61, 0, 0, 5, 0, 0, 0,240, 63, 30, 63,144, 62,226,195,233, 63, 25, 55, 20, 62,223, 35, 1,
+ 63, 25,178,200, 62,214,233, 77, 63, 33,235,108, 62,220,235,197, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,240, 62,219, 1,146,
+ 62,214, 59, 66, 62,219,248,248, 62,222,116,246, 62,209,232, 2, 62,226, 21,222, 62,202,144, 76, 62,220, 61,186, 2,236,169, 32,
+ 61, 0, 0, 5, 0, 0, 0,240, 63, 27,124,224, 62,232, 65,235, 63, 24,252, 87, 62,230,111, 93, 63, 25, 55, 20, 62,223, 35, 1,
+ 63, 30, 63,144, 62,226,195,233, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,240, 62,219,248,248, 62,222,116,246, 62,220,110,118,
+ 62,229,193, 78, 62,215,109,102, 62,231,147,222, 62,209,232, 2, 62,226, 21,222, 2,236,169, 32, 61, 0, 0, 5, 0, 0, 0,240,
+ 63, 24,252, 87, 62,230,111, 93, 63, 22,195, 22, 62,232, 90,195, 63, 20, 91,191, 62,227, 18,193, 63, 25, 55, 20, 62,223, 35, 1,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,240, 62,229,175,162, 62,226,100,178, 62,224,224,248, 62,231,172,182, 62,220,110,118,
+ 62,229,193, 78, 62,219,248,248, 62,222,116,246, 2,236,169, 32, 61, 0, 0, 5, 0, 0, 0,240, 63, 25, 55, 20, 62,223, 35, 1,
+ 63, 20, 91,191, 62,227, 18,193, 63, 17,165,187, 62,221, 6,225, 63, 25,178,200, 62,214,233, 77, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0,240, 62,235, 27,170, 62,220, 88,214, 62,229,175,162, 62,226,100,178, 62,219,248,248, 62,222,116,246, 62,219, 1,146,
+ 62,214, 59, 66, 2,236,169, 32, 61, 0, 0, 5, 0, 0, 0,240, 63, 20, 91,191, 62,227, 18,193, 63, 18, 18,164, 62,236,201,173,
+ 63, 13,231,157, 62,236,161, 89, 63, 17,165,187, 62,221, 6,225, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,240, 62,242,151,232,
+ 62,235,243, 70, 62,234, 65,216, 62,236, 27,158, 62,229,175,162, 62,226,100,178, 62,235, 27,170, 62,220, 88,214, 2,236,169, 32,
+ 61, 0, 0, 5, 0, 0, 0,240, 63, 22,195, 22, 62,232, 90,195, 63, 21,202, 11, 62,236,189, 1, 63, 18, 18,164, 62,236,201,173,
+ 63, 20, 91,191, 62,227, 18,193, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,240, 62,234, 65,216, 62,236, 27,158, 62,226,211, 12,
+ 62,236, 14,246, 62,224,224,248, 62,231,172,182, 62,229,175,162, 62,226,100,178, 2,236,169, 32, 61, 0, 0, 5, 0, 0, 0,240,
+ 63, 21,202, 11, 62,236,189, 1, 63, 22,202,215, 62,241,124,237, 63, 20,105,125, 62,246, 71, 1, 63, 18, 18,164, 62,236,201,173,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,240, 62,229,148, 42, 62,245,152,246, 62,224,209,112, 62,240,206,226, 62,226,211, 12,
+ 62,236, 14,246, 62,234, 65,216, 62,236, 27,158, 2,236,169, 32, 61, 0, 0, 5, 0, 0, 0,240, 63, 18, 18,164, 62,236,201,173,
+ 63, 20,105,125, 62,246, 71, 1, 63, 17,173, 44, 62,252,149,231, 63, 13,231,157, 62,236,161, 89, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0,240, 62,235, 12,206, 62,251,231,218, 62,229,148, 42, 62,245,152,246, 62,234, 65,216, 62,236, 27,158, 62,242,151,232,
+ 62,235,243, 70, 2,236,169, 32, 61, 0, 0, 5, 0, 0, 0,240, 63, 20,105,125, 62,246, 71, 1, 63, 25, 59, 37, 62,250, 73, 49,
+ 63, 25,178,108, 63, 1,108,218, 63, 17,173, 44, 62,252,149,231, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,240, 62,219, 2, 76,
+ 63, 1, 21,213, 62,219,240,216, 62,249,155, 38, 62,229,148, 42, 62,245,152,246, 62,235, 12,206, 62,251,231,218, 2,236,169, 32,
+ 61, 0, 0, 5, 0, 0, 0,240, 63, 22,202,215, 62,241,124,237, 63, 25, 1,195, 62,243,102,169, 63, 25, 59, 37, 62,250, 73, 49,
+ 63, 20,105,125, 62,246, 71, 1, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,240, 62,219,240,216, 62,249,155, 38, 62,220, 99,156,
+ 62,242,184,154, 62,224,209,112, 62,240,206,226, 62,229,148, 42, 62,245,152,246, 2,236,169, 32, 61, 0, 0, 5, 0, 0, 0,240,
+ 63, 25, 1,195, 62,243,102,169, 63, 27,125,176, 62,241,145,149, 63, 30, 74,167, 62,246,153, 3, 63, 25, 59, 37, 62,250, 73, 49,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,240, 62,209,209,212, 62,245,234,246, 62,215,107,192, 62,240,227,138, 62,220, 99,156,
+ 62,242,184,154, 62,219,240,216, 62,249,155, 38, 2,236,169, 32, 61, 0, 0, 5, 0, 0, 0,240, 63, 25, 59, 37, 62,250, 73, 49,
+ 63, 30, 74,167, 62,246,153, 3, 63, 33,230,204, 62,252,232,107, 63, 25,178,108, 63, 1,108,218, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0,240, 62,202,153,132, 62,252, 58, 94, 62,209,209,212, 62,245,234,246, 62,219,240,216, 62,249,155, 38, 62,219, 2, 76,
+ 63, 1, 21,213, 2,236,169, 32, 61, 0, 0, 5, 0, 0, 0,240, 63, 30, 74,167, 62,246,153, 3, 63, 32,152,118, 62,236,167, 37,
+ 63, 37,151,209, 62,236,161, 89, 63, 33,230,204, 62,252,232,107, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,240, 62,195, 55,128,
+ 62,235,243, 70, 62,205, 54, 56, 62,235,249, 22, 62,209,209,212, 62,245,234,246, 62,202,153,132, 62,252, 58, 94, 2,236,169, 32,
+ 61, 0, 0, 5, 0, 0, 0,240, 63, 27,125,176, 62,241,145,149, 63, 28,112, 3, 62,236,178,185, 63, 32,152,118, 62,236,167, 37,
+ 63, 30, 74,167, 62,246,153, 3, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,240, 62,205, 54, 56, 62,235,249, 22, 62,213,135, 28,
+ 62,236, 4,172, 62,215,107,192, 62,240,227,138, 62,209,209,212, 62,245,234,246, 2,236,169, 32, 61, 0, 0, 5, 0, 0, 0,240,
+ 63, 28,112, 3, 62,236,178,185, 63, 27,125,176, 62,241,145,149, 63, 27, 39, 42, 62,241, 1, 57, 63, 27,249,140, 62,236,186,115,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,240, 62,216, 24,206, 62,240, 83, 46, 62,215,107,192, 62,240,227,138, 62,213,135, 28,
+ 62,236, 4,172, 62,214,116, 8, 62,236, 12,102, 2,236,169, 32, 61, 0, 0, 5, 0, 0, 0,240, 63, 27,125,176, 62,241,145,149,
+ 63, 25, 1,195, 62,243,102,169, 63, 24,248, 6, 62,242, 91,185, 63, 27, 39, 42, 62,241, 1, 57, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0,240, 62,220,119, 22, 62,241,173,174, 62,220, 99,156, 62,242,184,154, 62,215,107,192, 62,240,227,138, 62,216, 24,206,
+ 62,240, 83, 46, 2,236,169, 32, 61, 0, 0, 5, 0, 0, 0,240, 63, 25, 1,195, 62,243,102,169, 63, 22,202,215, 62,241,124,237,
+ 63, 23, 38,157, 62,240,173,225, 63, 24,248, 6, 62,242, 91,185, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,240, 62,224, 25,234,
+ 62,239,255,214, 62,224,209,112, 62,240,206,226, 62,220, 99,156, 62,242,184,154, 62,220,119, 22, 62,241,173,174, 2,236,169, 32,
+ 61, 0, 0, 5, 0, 0, 0,240, 63, 22,202,215, 62,241,124,237, 63, 21,202, 11, 62,236,189, 1, 63, 22, 89, 13, 62,236,196,247,
+ 63, 23, 38,157, 62,240,173,225, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,240, 62,225,181, 8, 62,236, 22,234, 62,226,211, 12,
+ 62,236, 14,246, 62,224,209,112, 62,240,206,226, 62,224, 25,234, 62,239,255,214, 2,236,169, 32, 61, 0, 0, 5, 0, 0, 0,240,
+ 63, 21,202, 11, 62,236,189, 1, 63, 22,195, 22, 62,232, 90,195, 63, 23, 33, 88, 62,233, 47, 69, 63, 22, 89, 13, 62,236,196,247,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,240, 62,224, 36,112, 62,232,129, 58, 62,224,224,248, 62,231,172,182, 62,226,211, 12,
+ 62,236, 14,246, 62,225,181, 8, 62,236, 22,234, 2,236,169, 32, 61, 0, 0, 5, 0, 0, 0,240, 63, 22,195, 22, 62,232, 90,195,
+ 63, 24,252, 87, 62,230,111, 93, 63, 24,243,100, 62,231,123, 5, 63, 23, 33, 88, 62,233, 47, 69, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0,240, 62,220,128, 90, 62,230,204,248, 62,220,110,118, 62,229,193, 78, 62,224,224,248, 62,231,172,182, 62,224, 36,112,
+ 62,232,129, 58, 2,236,169, 32, 61, 0, 0, 5, 0, 0, 0,240, 63, 24,252, 87, 62,230,111, 93, 63, 27,124,224, 62,232, 65,235,
+ 63, 27, 37,169, 62,232,211, 35, 63, 24,243,100, 62,231,123, 5, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,240, 62,216, 27,206,
+ 62,232, 37, 22, 62,215,109,102, 62,231,147,222, 62,220,110,118, 62,229,193, 78, 62,220,128, 90, 62,230,204,248, 2,236,169, 32,
+ 61, 0, 0, 5, 0, 0, 0,240, 63, 27,124,224, 62,232, 65,235, 63, 28,112, 3, 62,236,178,185, 63, 27,249,140, 62,236,186,115,
+ 63, 27, 37,169, 62,232,211, 35, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,240, 62,214,116, 8, 62,236, 12,102, 62,213,135, 28,
+ 62,236, 4,172, 62,215,109,102, 62,231,147,222, 62,216, 27,206, 62,232, 37, 22, 2,236,169, 32, 61, 0, 0, 5, 0, 0, 0,240,
+ 63, 24,242,138, 62,236,194, 21, 63, 27, 37,169, 62,232,211, 35, 63, 27,249,140, 62,236,186,115, 63,128, 0, 0, 63,128, 0, 0,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,112, 62,214,116, 8, 62,236, 12,102, 62,216, 27,206, 62,232, 37, 22, 62,220,130, 16,
+ 62,236, 20, 6, 63,128, 0, 0, 63,128, 0, 0, 2,236,169, 32, 61, 0, 0, 5, 0, 0, 0,112, 63, 24,243,100, 62,231,123, 5,
+ 63, 27, 37,169, 62,232,211, 35, 63, 24,242,138, 62,236,194, 21, 63,128, 0, 0, 63,128, 0, 0, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0,112, 62,220,130, 16, 62,236, 20, 6, 62,216, 27,206, 62,232, 37, 22, 62,220,128, 90, 62,230,204,248, 63,128, 0, 0,
+ 63,128, 0, 0, 2,236,169, 32, 61, 0, 0, 5, 0, 0, 0,112, 63, 24,242,138, 62,236,194, 21, 63, 23, 33, 88, 62,233, 47, 69,
+ 63, 24,243,100, 62,231,123, 5, 63,128, 0, 0, 63,128, 0, 0, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,112, 62,220,128, 90,
+ 62,230,204,248, 62,224, 36,112, 62,232,129, 58, 62,220,130, 16, 62,236, 20, 6, 63,128, 0, 0, 63,128, 0, 0, 2,236,169, 32,
+ 61, 0, 0, 5, 0, 0, 0,112, 63, 24,242,138, 62,236,194, 21, 63, 22, 89, 13, 62,236,196,247, 63, 23, 33, 88, 62,233, 47, 69,
+ 63,128, 0, 0, 63,128, 0, 0, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,112, 62,224, 36,112, 62,232,129, 58, 62,225,181, 8,
+ 62,236, 22,234, 62,220,130, 16, 62,236, 20, 6, 63,128, 0, 0, 63,128, 0, 0, 2,236,169, 32, 61, 0, 0, 5, 0, 0, 0,112,
+ 63, 24,242,138, 62,236,194, 21, 63, 23, 38,157, 62,240,173,225, 63, 22, 89, 13, 62,236,196,247, 63,128, 0, 0, 63,128, 0, 0,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,112, 62,225,181, 8, 62,236, 22,234, 62,224, 25,234, 62,239,255,214, 62,220,130, 16,
+ 62,236, 20, 6, 63,128, 0, 0, 63,128, 0, 0, 2,236,169, 32, 61, 0, 0, 5, 0, 0, 0,112, 63, 24,242,138, 62,236,194, 21,
+ 63, 24,248, 6, 62,242, 91,185, 63, 23, 38,157, 62,240,173,225, 63,128, 0, 0, 63,128, 0, 0, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0,112, 62,224, 25,234, 62,239,255,214, 62,220,119, 22, 62,241,173,174, 62,220,130, 16, 62,236, 20, 6, 63,128, 0, 0,
+ 63,128, 0, 0, 2,236,169, 32, 61, 0, 0, 5, 0, 0, 0,112, 63, 24,242,138, 62,236,194, 21, 63, 27, 39, 42, 62,241, 1, 57,
+ 63, 24,248, 6, 62,242, 91,185, 63,128, 0, 0, 63,128, 0, 0, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,112, 62,220,119, 22,
+ 62,241,173,174, 62,216, 24,206, 62,240, 83, 46, 62,220,130, 16, 62,236, 20, 6, 63,128, 0, 0, 63,128, 0, 0, 2,236,169, 32,
+ 61, 0, 0, 5, 0, 0, 0,112, 63, 24,242,138, 62,236,194, 21, 63, 27,249,140, 62,236,186,115, 63, 27, 39, 42, 62,241, 1, 57,
+ 63,128, 0, 0, 63,128, 0, 0, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,112, 62,216, 24,206, 62,240, 83, 46, 62,214,116, 8,
+ 62,236, 12,102, 62,220,130, 16, 62,236, 20, 6, 63,128, 0, 0, 63,128, 0, 0, 2,236,169, 32, 61, 0, 0, 5, 0, 0, 0,112,
+ 63, 16,254,174, 62, 34, 45, 94, 63, 13,190, 79, 62, 46,193,160, 63, 3,199,220, 62, 24,219, 89, 63, 3,199,219, 61,229, 28, 18,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 16, 63, 3,199,220, 62, 24,219, 89, 62,243,150, 14, 62, 47, 79,204, 62,236,248,140,
+ 62, 34,202,182, 63, 3,199,219, 61,229, 28, 18, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 64, 63, 21,152,184, 62, 53, 47,182,
+ 63, 16,104,250, 62, 55,113, 16, 63, 13,190, 79, 62, 46,193,160, 63, 16,254,174, 62, 34, 45, 94, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0,128, 62,243,150, 14, 62, 47, 79,204, 62,238, 68,200, 62, 56, 62, 76, 62,227,207,183, 62, 54, 75,250, 62,236,248,140,
+ 62, 34,202,182, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,128, 63, 22, 57,137, 62, 61, 93, 81, 63, 16,186,206, 62, 72,129, 85,
+ 63, 16,104,250, 62, 55,113, 16, 63, 21,152,184, 62, 53, 47,182, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,238, 68,200,
+ 62, 56, 62, 76, 62,237,187,192, 62, 73,118,194, 62,226,152,122, 62, 62,166,190, 62,227,207,183, 62, 54, 75,250, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63, 22,249,250, 62, 88,251,160, 63, 16, 32,222, 62, 93,106, 34, 63, 16,186,206, 62, 72,129, 85,
+ 63, 22, 57,137, 62, 61, 93, 81, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,237,187,192, 62, 73,118,194, 62,239, 19, 21,
+ 62, 94,110,121, 62,225, 83, 90, 62, 90,153, 21, 62,226,152,122, 62, 62,166,190, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63, 25, 81, 20, 62,132, 56, 17, 63, 15,243,206, 62,136,207,182, 63, 16, 32,222, 62, 93,106, 34, 63, 22,249,250, 62, 88,251,160,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,239, 19, 21, 62, 94,110,121, 62,239,193, 92, 62,137, 61,113, 62,221, 42, 54,
+ 62,133, 25,209, 62,225, 83, 90, 62, 90,153, 21, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 27,239,111, 62,166, 77,159,
+ 63, 37, 94, 91, 62,187,120,107, 63, 30, 21, 66, 62,200,139,178, 63, 12,237,158, 62,187,241, 38, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 62,211,125,139, 62,200,171,170, 62,197, 28,156, 62,187,130,166, 62,216, 21,115, 62,166,177, 14, 62,245,175, 15,
+ 62,188, 14,188, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 37, 94, 91, 62,187,120,107, 63, 43, 57, 87, 62,206, 58,222,
+ 63, 39,163, 24, 62,216, 95,174, 63, 30, 21, 66, 62,200,139,178, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,191,194, 98,
+ 62,216, 94, 42, 62,184,207,130, 62,206, 27, 42, 62,197, 28,156, 62,187,130,166, 62,211,125,139, 62,200,171,170, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63, 43, 57, 87, 62,206, 58,222, 63, 50,229, 38, 62,226, 32,169, 63, 43, 79,177, 62,231,194,202,
+ 63, 39,163, 24, 62,216, 95,174, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,183,201, 60, 62,231,218, 82, 62,168, 39,196,
+ 62,226, 11,206, 62,184,207,130, 62,206, 27, 42, 62,191,194, 98, 62,216, 94, 42, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63, 50,229, 38, 62,226, 32,169, 63, 48,134, 62, 62,249,107, 37, 63, 43,190,154, 62,249, 0,192, 63, 43, 79,177, 62,231,194,202,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,182,190,138, 62,249, 49, 35, 62,172,229,172, 62,249,127,116, 62,168, 39,196,
+ 62,226, 11,206, 62,183,201, 60, 62,231,218, 82, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 48,134, 62, 62,249,107, 37,
+ 63, 46, 88,238, 63, 2,223,146, 63, 40,207,123, 62,254,175,218, 63, 43,190,154, 62,249, 0,192, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 62,188,184, 2, 62,255, 0,140, 62,177, 87,173, 63, 3, 9,102, 62,172,229,172, 62,249,127,116, 62,182,190,138,
+ 62,249, 49, 35, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 46, 88,238, 63, 2,223,146, 63, 34,158,220, 63, 10, 23,175,
+ 63, 30, 77,126, 63, 5, 88,156, 63, 40,207,123, 62,254,175,218, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,210, 65, 89,
+ 63, 5,158, 56, 62,201,109,124, 63, 10,121, 72, 62,177, 87,173, 63, 3, 9,102, 62,188,184, 2, 62,255, 0,140, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63, 34,158,220, 63, 10, 23,175, 63, 26,105, 28, 63, 11,194,242, 63, 25,120,244, 63, 7,242, 78,
+ 63, 30, 77,126, 63, 5, 88,156, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,220, 39, 0, 63, 8, 58,252, 62,218, 73,220,
+ 63, 12, 31,169, 62,201,109,124, 63, 10,121, 72, 62,210, 65, 89, 63, 5,158, 56, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63, 26,105, 28, 63, 11,194,242, 63, 22,244,173, 63, 11,215,236, 63, 22, 47,202, 63, 8, 60,156, 63, 25,120,244, 63, 7,242, 78,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,226,221, 11, 63, 8,125, 90, 62,225, 89,220, 63, 12, 42, 77, 62,218, 73,220,
+ 63, 12, 31,169, 62,220, 39, 0, 63, 8, 58,252, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 22,244,173, 63, 11,215,236,
+ 63, 11,169, 67, 63, 11,197, 18, 63, 12,252,106, 63, 3,173,180, 63, 22, 47,202, 63, 8, 60,156, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 62,245,114, 35, 63, 3,196,233, 62,248, 72, 55, 63, 11,232, 91, 62,225, 89,220, 63, 12, 42, 77, 62,226,221, 11,
+ 63, 8,125, 90, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 11,169, 67, 63, 11,197, 18, 63, 3,232,148, 63, 11, 17,164,
+ 63, 3,220,162, 63, 0, 88, 45, 63, 12,252,106, 63, 3,173,180, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 3,220,162,
+ 63, 0, 88, 45, 63, 3,232,148, 63, 11, 17,164, 62,248, 72, 55, 63, 11,232, 91, 62,245,114, 35, 63, 3,196,233, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63, 17, 59,103, 62,255,195,120, 63, 22, 81,240, 63, 1, 70,114, 63, 22, 47,202, 63, 8, 60,156,
+ 63, 12,252,106, 63, 3,173,180, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,226,221, 11, 63, 8,125, 90, 62,226,128,106,
+ 63, 1,111,198, 62,236,213,209, 62,255,250, 4, 62,245,114, 35, 63, 3,196,233, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63, 22, 81,240, 63, 1, 70,114, 63, 25,182,151, 63, 1, 9,130, 63, 25,120,244, 63, 7,242, 78, 63, 22, 47,202, 63, 8, 60,156,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,220, 39, 0, 63, 8, 58,252, 62,219,150,213, 63, 1, 55, 50, 62,226,128,106,
+ 63, 1,111,198, 62,226,221, 11, 63, 8,125, 90, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 30, 49, 96, 62,254,229,121,
+ 63, 30, 77,126, 63, 5, 88,156, 63, 25,120,244, 63, 7,242, 78, 63, 25,182,151, 63, 1, 9,130, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 62,220, 39, 0, 63, 8, 58,252, 62,210, 65, 89, 63, 5,158, 56, 62,210,116,176, 62,255, 62,227, 62,219,150,213,
+ 63, 1, 55, 50, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 37,113, 25, 62,247,157, 35, 63, 40,207,123, 62,254,175,218,
+ 63, 30, 77,126, 63, 5, 88,156, 63, 30, 49, 96, 62,254,229,121, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,210, 65, 89,
+ 63, 5,158, 56, 62,188,184, 2, 62,255, 0,140, 62,195,165,189, 62,247,232,139, 62,210,116,176, 62,255, 62,227, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63, 39, 62, 92, 62,240, 75,121, 63, 43,190,154, 62,249, 0,192, 63, 40,207,123, 62,254,175,218,
+ 63, 37,113, 25, 62,247,157, 35, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,188,184, 2, 62,255, 0,140, 62,182,190,138,
+ 62,249, 49, 35, 62,192, 10,222, 62,240,128,163, 62,195,165,189, 62,247,232,139, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63, 38,149,140, 62,229, 95, 38, 63, 43, 79,177, 62,231,194,202, 63, 43,190,154, 62,249, 0,192, 63, 39, 62, 92, 62,240, 75,121,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,182,190,138, 62,249, 49, 35, 62,183,201, 60, 62,231,218, 82, 62,193,140,168,
+ 62,229,129, 94, 62,192, 10,222, 62,240,128,163, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 33,120, 14, 62,214,238,166,
+ 63, 39,163, 24, 62,216, 95,174, 63, 43, 79,177, 62,231,194,202, 63, 38,149,140, 62,229, 95, 38, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 62,183,201, 60, 62,231,218, 82, 62,191,194, 98, 62,216, 94, 42, 62,204, 75,168, 62,215, 7, 62, 62,193,140,168,
+ 62,229,129, 94, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 27,178,165, 62,208, 17,128, 63, 30, 21, 66, 62,200,139,178,
+ 63, 39,163, 24, 62,216, 95,174, 63, 33,120, 14, 62,214,238,166, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,191,194, 98,
+ 62,216, 94, 42, 62,211,125,139, 62,200,171,170, 62,216, 24, 6, 62,208, 57,128, 62,204, 75,168, 62,215, 7, 62, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63, 17, 97, 15, 62,214, 34,220, 63, 12,237,158, 62,187,241, 38, 63, 30, 21, 66, 62,200,139,178,
+ 63, 27,178,165, 62,208, 17,128, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,211,125,139, 62,200,171,170, 62,245,175, 15,
+ 62,188, 14,188, 62,236,200,217, 62,214, 49,134, 62,216, 24, 6, 62,208, 57,128, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63, 17, 97, 15, 62,214, 34,220, 63, 14,244,149, 62,221, 42, 4, 63, 3,230,147, 62,208, 47, 78, 63, 12,237,158, 62,187,241, 38,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 3,230,147, 62,208, 47, 78, 62,241,144,141, 62,221, 52,244, 62,236,200,217,
+ 62,214, 49,134, 62,245,175, 15, 62,188, 14,188, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 17, 59,103, 62,255,195,120,
+ 63, 12,252,106, 63, 3,173,180, 63, 3,220,162, 63, 0, 88, 45, 63, 13, 25, 71, 62,243,163,116, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 63, 3,220,162, 63, 0, 88, 45, 62,245,114, 35, 63, 3,196,233, 62,236,213,209, 62,255,250, 4, 62,245, 45, 0,
+ 62,243,185,206, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 13, 25, 71, 62,243,163,116, 63, 3,220,162, 63, 0, 88, 45,
+ 63, 3,220,215, 62,231,189,148, 63, 13, 2, 64, 62,230,215, 52, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 3,220,215,
+ 62,231,189,148, 63, 3,220,162, 63, 0, 88, 45, 62,245, 45, 0, 62,243,185,206, 62,245,100,219, 62,230,230,184, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63, 3,230,147, 62,208, 47, 78, 63, 14,244,149, 62,221, 42, 4, 63, 13, 2, 64, 62,230,215, 52,
+ 63, 3,220,215, 62,231,189,148, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,245,100,219, 62,230,230,184, 62,241,144,141,
+ 62,221, 52,244, 63, 3,230,147, 62,208, 47, 78, 63, 3,220,215, 62,231,189,148, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63, 7, 61,250, 62, 54, 31,148, 63, 3,202,193, 62, 49,174,214, 63, 3,199,220, 62, 24,219, 89, 63, 13,190, 79, 62, 46,193,160,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 3,199,220, 62, 24,219, 89, 63, 3,202,193, 62, 49,174,214, 63, 0, 87,175,
+ 62, 54, 90,251, 62,243,150, 14, 62, 47, 79,204, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 9,214, 68, 62, 66,237,246,
+ 63, 7, 61,250, 62, 54, 31,148, 63, 13,190, 79, 62, 46,193,160, 63, 16,104,250, 62, 55,113, 16, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 62,243,150, 14, 62, 47, 79,204, 63, 0, 87,175, 62, 54, 90,251, 62,251,137,104, 62, 67, 92,179, 62,238, 68,200,
+ 62, 56, 62, 76, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 8,221,237, 62, 91, 90,218, 63, 9,214, 68, 62, 66,237,246,
+ 63, 16,104,250, 62, 55,113, 16, 63, 16,186,206, 62, 72,129, 85, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,238, 68,200,
+ 62, 56, 62, 76, 62,251,137,104, 62, 67, 92,179, 62,253,153, 39, 62, 91,195, 27, 62,237,187,192, 62, 73,118,194, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63, 15,243,206, 62,136,207,182, 63, 8, 32, 77, 62,139, 39, 10, 63, 9,117, 22, 62, 97,203,146,
+ 63, 16, 32,222, 62, 93,106, 34, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,252,110,192, 62, 98, 68, 79, 62,255, 89,219,
+ 62,139, 79,116, 62,239,193, 92, 62,137, 61,113, 62,239, 19, 21, 62, 94,110,121, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63, 8,221,237, 62, 91, 90,218, 63, 16,186,206, 62, 72,129, 85, 63, 16, 32,222, 62, 93,106, 34, 63, 9,117, 22, 62, 97,203,146,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,239, 19, 21, 62, 94,110,121, 62,237,187,192, 62, 73,118,194, 62,253,153, 39,
+ 62, 91,195, 27, 62,252,110,192, 62, 98, 68, 79, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 9,125,119, 62,158,112, 7,
+ 63, 3,233, 70, 62,154, 27, 88, 63, 3,229,235, 62,139,108, 97, 63, 8, 32, 77, 62,139, 39, 10, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 63, 3,229,235, 62,139,108, 97, 63, 3,233, 70, 62,154, 27, 88, 62,252,179,165, 62,158,140,163, 62,255, 89,219,
+ 62,139, 79,116, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 9,117, 22, 62, 97,203,146, 63, 8, 32, 77, 62,139, 39, 10,
+ 63, 3,229,235, 62,139,108, 97, 63, 3,215,246, 62,101, 56,143, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 3,229,235,
+ 62,139,108, 97, 62,255, 89,219, 62,139, 79,116, 62,252,110,192, 62, 98, 68, 79, 63, 3,215,246, 62,101, 56,143, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63, 3,210,147, 62, 86, 95,221, 63, 8,221,237, 62, 91, 90,218, 63, 9,117, 22, 62, 97,203,146,
+ 63, 3,215,246, 62,101, 56,143, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,252,110,192, 62, 98, 68, 79, 62,253,153, 39,
+ 62, 91,195, 27, 63, 3,210,147, 62, 86, 95,221, 63, 3,215,246, 62,101, 56,143, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63, 12, 54, 5, 62,167,183,188, 63, 9, 61,250, 62,168,214,252, 63, 8,143,152, 62,163,107, 45, 63, 9,125,119, 62,158,112, 7,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,254,136,100, 62,163,123, 38, 62,253, 39,110, 62,168,224,103, 62,247, 68, 98,
+ 62,167,206,146, 62,252,179,165, 62,158,140,163, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 10,196,135, 62,178,208, 52,
+ 63, 8,233, 25, 62,175,110,116, 63, 9, 61,250, 62,168,214,252, 63, 12, 54, 5, 62,167,183,188, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 62,253, 39,110, 62,168,224,103, 62,253,195,102, 62,175,102,184, 62,250, 14, 98, 62,178,202,149, 62,247, 68, 98,
+ 62,167,206,146, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 4, 17, 69, 62,182,176,105, 63, 6,138, 69, 62,177,180, 80,
+ 63, 8,233, 25, 62,175,110,116, 63, 10,196,135, 62,178,208, 52, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,253,195,102,
+ 62,175,102,184, 63, 1, 49, 14, 62,177,150, 62, 63, 4, 17, 69, 62,182,176,105, 62,250, 14, 98, 62,178,202,149, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63, 3,124,209, 62,177, 0, 70, 63, 3,232, 11, 62,174, 4,140, 63, 6,138, 69, 62,177,180, 80,
+ 63, 4, 17, 69, 62,182,176,105, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 1, 49, 14, 62,177,150, 62, 63, 3,232, 11,
+ 62,174, 4,140, 63, 3,124,209, 62,177, 0, 70, 63, 4, 17, 69, 62,182,176,105, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63, 3,233, 70, 62,154, 27, 88, 63, 9,125,119, 62,158,112, 7, 63, 8,143,152, 62,163,107, 45, 63, 3,232,212, 62,158,152, 58,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,254,136,100, 62,163,123, 38, 62,252,179,165, 62,158,140,163, 63, 3,233, 70,
+ 62,154, 27, 88, 63, 3,232,212, 62,158,152, 58, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 3,232,212, 62,158,152, 58,
+ 63, 8,143,152, 62,163,107, 45, 63, 7, 91,121, 62,166, 51,134, 63, 3,231,205, 62,162,149, 58, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 63, 0,116, 44, 62,166, 56,255, 62,254,136,100, 62,163,123, 38, 63, 3,232,212, 62,158,152, 58, 63, 3,231,205,
+ 62,162,149, 58, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 3,232, 11, 62,174, 4,140, 63, 3,233,214, 62,170,154,198,
+ 63, 6,110,233, 62,174,152, 94, 63, 6,138, 69, 62,177,180, 80, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 1, 82,228,
+ 62,174,140, 95, 63, 3,233,214, 62,170,154,198, 63, 3,232, 11, 62,174, 4,140, 63, 1, 49, 14, 62,177,150, 62, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63, 6,138, 69, 62,177,180, 80, 63, 6,110,233, 62,174,152, 94, 63, 7,236, 59, 62,173,123, 19,
+ 63, 8,233, 25, 62,175,110,116, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,255,185,217, 62,173,116, 92, 63, 1, 82,228,
+ 62,174,140, 95, 63, 1, 49, 14, 62,177,150, 62, 62,253,195,102, 62,175,102,184, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63, 8,233, 25, 62,175,110,116, 63, 7,236, 59, 62,173,123, 19, 63, 7,249, 85, 62,169, 52, 92, 63, 9, 61,250, 62,168,214,252,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,255,169,160, 62,169, 57, 6, 62,255,185,217, 62,173,116, 92, 62,253,195,102,
+ 62,175,102,184, 62,253, 39,110, 62,168,224,103, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 9, 61,250, 62,168,214,252,
+ 63, 7,249, 85, 62,169, 52, 92, 63, 7, 91,121, 62,166, 51,134, 63, 8,143,152, 62,163,107, 45, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 63, 0,116, 44, 62,166, 56,255, 62,255,169,160, 62,169, 57, 6, 62,253, 39,110, 62,168,224,103, 62,254,136,100,
+ 62,163,123, 38, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 3,233,214, 62,170,154,198, 63, 7,249, 85, 62,169, 52, 92,
+ 63, 7,236, 59, 62,173,123, 19, 63, 6,110,233, 62,174,152, 94, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,255,185,217,
+ 62,173,116, 92, 62,255,169,160, 62,169, 57, 6, 63, 3,233,214, 62,170,154,198, 63, 1, 82,228, 62,174,140, 95, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63, 3,233,214, 62,170,154,198, 63, 3,231,205, 62,162,149, 58, 63, 7, 91,121, 62,166, 51,134,
+ 63, 7,249, 85, 62,169, 52, 92, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 0,116, 44, 62,166, 56,255, 63, 3,231,205,
+ 62,162,149, 58, 63, 3,233,214, 62,170,154,198, 62,255,169,160, 62,169, 57, 6, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63, 4, 17, 69, 62,182,176,105, 63, 10,196,135, 62,178,208, 52, 63, 12,237,158, 62,187,241, 38, 63, 3,230,147, 62,208, 47, 78,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,245,175, 15, 62,188, 14,188, 62,250, 14, 98, 62,178,202,149, 63, 4, 17, 69,
+ 62,182,176,105, 63, 3,230,147, 62,208, 47, 78, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 10,196,135, 62,178,208, 52,
+ 63, 12, 54, 5, 62,167,183,188, 63, 16, 0,112, 62,164,246,254, 63, 12,237,158, 62,187,241, 38, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 62,239,187,207, 62,165, 42, 19, 62,247, 68, 98, 62,167,206,146, 62,250, 14, 98, 62,178,202,149, 62,245,175, 15,
+ 62,188, 14,188, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 12, 54, 5, 62,167,183,188, 63, 9,125,119, 62,158,112, 7,
+ 63, 15,250, 44, 62,154, 0,109, 63, 16, 0,112, 62,164,246,254, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,239,205, 56,
+ 62,154, 71, 8, 62,252,179,165, 62,158,140,163, 62,247, 68, 98, 62,167,206,146, 62,239,187,207, 62,165, 42, 19, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63, 9,125,119, 62,158,112, 7, 63, 8, 32, 77, 62,139, 39, 10, 63, 15,243,206, 62,136,207,182,
+ 63, 15,250, 44, 62,154, 0,109, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,239,193, 92, 62,137, 61,113, 62,255, 89,219,
+ 62,139, 79,116, 62,252,179,165, 62,158,140,163, 62,239,205, 56, 62,154, 71, 8, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63, 25, 81, 20, 62,132, 56, 17, 63, 27, 46,208, 62,148, 35,149, 63, 15,250, 44, 62,154, 0,109, 63, 15,243,206, 62,136,207,182,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,239,205, 56, 62,154, 71, 8, 62,217,166,238, 62,148,221,229, 62,221, 42, 54,
+ 62,133, 25,209, 62,239,193, 92, 62,137, 61,113, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 27, 46,208, 62,148, 35,149,
+ 63, 27,177, 36, 62,156,151,158, 63, 16, 0,112, 62,164,246,254, 63, 15,250, 44, 62,154, 0,109, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 62,239,187,207, 62,165, 42, 19, 62,216,160, 0, 62,157, 44,127, 62,217,166,238, 62,148,221,229, 62,239,205, 56,
+ 62,154, 71, 8, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 27,239,111, 62,166, 77,159, 63, 12,237,158, 62,187,241, 38,
+ 63, 16, 0,112, 62,164,246,254, 63, 27,177, 36, 62,156,151,158, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,239,187,207,
+ 62,165, 42, 19, 62,245,175, 15, 62,188, 14,188, 62,216, 21,115, 62,166,177, 14, 62,216,160, 0, 62,157, 44,127, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63, 8,221,237, 62, 91, 90,218, 63, 3,210,147, 62, 86, 95,221, 63, 3,211,129, 62, 83,168,248,
+ 63, 8, 33,170, 62, 86,149,254, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 3,211,129, 62, 83,168,248, 63, 3,210,147,
+ 62, 86, 95,221, 62,253,153, 39, 62, 91,195, 27, 62,255, 14, 8, 62, 86,232, 58, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63, 9,214, 68, 62, 66,237,246, 63, 8,221,237, 62, 91, 90,218, 63, 8, 33,170, 62, 86,149,254, 63, 8,180, 20, 62, 69, 29, 94,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,255, 14, 8, 62, 86,232, 58, 62,253,153, 39, 62, 91,195, 27, 62,251,137,104,
+ 62, 67, 92,179, 62,253,210, 19, 62, 69,114, 55, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 7, 61,250, 62, 54, 31,148,
+ 63, 9,214, 68, 62, 66,237,246, 63, 8,180, 20, 62, 69, 29, 94, 63, 6, 82,168, 62, 57, 43, 80, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 62,253,210, 19, 62, 69,114, 55, 62,251,137,104, 62, 67, 92,179, 63, 0, 87,175, 62, 54, 90,251, 63, 1, 68, 48,
+ 62, 57, 84,166, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 3,202,193, 62, 49,174,214, 63, 7, 61,250, 62, 54, 31,148,
+ 63, 6, 82,168, 62, 57, 43, 80, 63, 3,202,205, 62, 54, 22, 8, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 1, 68, 48,
+ 62, 57, 84,166, 63, 0, 87,175, 62, 54, 90,251, 63, 3,202,193, 62, 49,174,214, 63, 3,202,205, 62, 54, 22, 8, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63, 3,202,205, 62, 54, 22, 8, 63, 6, 82,168, 62, 57, 43, 80, 63, 5, 24,246, 62, 66,150, 26,
+ 63, 3,205,213, 62, 64,232,220, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 2,131, 29, 62, 66,172, 22, 63, 1, 68, 48,
+ 62, 57, 84,166, 63, 3,202,205, 62, 54, 22, 8, 63, 3,205,213, 62, 64,232,220, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63, 6, 82,168, 62, 57, 43, 80, 63, 8,180, 20, 62, 69, 29, 94, 63, 6, 83, 39, 62, 70,114,191, 63, 5, 24,246, 62, 66,150, 26,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 1, 75,185, 62, 70,160,222, 62,253,210, 19, 62, 69,114, 55, 63, 1, 68, 48,
+ 62, 57, 84,166, 63, 2,131, 29, 62, 66,172, 22, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 8,180, 20, 62, 69, 29, 94,
+ 63, 8, 33,170, 62, 86,149,254, 63, 6,111, 4, 62, 76,172, 40, 63, 6, 83, 39, 62, 70,114,191, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 63, 1, 51,157, 62, 76,218,158, 62,255, 14, 8, 62, 86,232, 58, 62,253,210, 19, 62, 69,114, 55, 63, 1, 75,185,
+ 62, 70,160,222, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 8, 33,170, 62, 86,149,254, 63, 3,211,129, 62, 83,168,248,
+ 63, 3,208,234, 62, 75, 43,146, 63, 6,111, 4, 62, 76,172, 40, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 3,208,234,
+ 62, 75, 43,146, 63, 3,211,129, 62, 83,168,248, 62,255, 14, 8, 62, 86,232, 58, 63, 1, 51,157, 62, 76,218,158, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63, 3,208,234, 62, 75, 43,146, 63, 3,205,213, 62, 64,232,220, 63, 5, 24,246, 62, 66,150, 26,
+ 63, 6,111, 4, 62, 76,172, 40, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 2,131, 29, 62, 66,172, 22, 63, 3,205,213,
+ 62, 64,232,220, 63, 3,208,234, 62, 75, 43,146, 63, 1, 51,157, 62, 76,218,158, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63, 6,111, 4, 62, 76,172, 40, 63, 5, 24,246, 62, 66,150, 26, 63, 6, 83, 39, 62, 70,114,191, 63,128, 0, 0, 63,128, 0, 0,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 1, 75,185, 62, 70,160,222, 63, 2,131, 29, 62, 66,172, 22, 63, 1, 51,157,
+ 62, 76,218,158, 63,128, 0, 0, 63,128, 0, 0, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 13, 2, 64, 62,230,215, 52,
+ 63, 14,244,149, 62,221, 42, 4, 63, 16,216, 4, 62,224, 24,160, 63, 15,200,120, 62,231,255, 84, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 62,237,193,119, 62,224, 38,190, 62,241,144,141, 62,221, 52,244, 62,245,100,219, 62,230,230,184, 62,239,211, 21,
+ 62,232, 18,185, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 13, 25, 71, 62,243,163,116, 63, 13, 2, 64, 62,230,215, 52,
+ 63, 15,200,120, 62,231,255, 84, 63, 16,171,184, 62,241,133, 40, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,239,211, 21,
+ 62,232, 18,185, 62,245,100,219, 62,230,230,184, 62,245, 45, 0, 62,243,185,206, 62,237,252,218, 62,241,160, 62, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63, 17, 59,103, 62,255,195,120, 63, 13, 25, 71, 62,243,163,116, 63, 16,171,184, 62,241,133, 40,
+ 63, 19, 44, 55, 62,250, 21, 86, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,237,252,218, 62,241,160, 62, 62,245, 45, 0,
+ 62,243,185,206, 62,236,213,209, 62,255,250, 4, 62,232,228,153, 62,250, 67,154, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63, 14,244,149, 62,221, 42, 4, 63, 17, 97, 15, 62,214, 34,220, 63, 19, 53,217, 62,218,211, 16, 63, 16,216, 4, 62,224, 24,160,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,233, 14, 8, 62,218,226, 66, 62,236,200,217, 62,214, 49,134, 62,241,144,141,
+ 62,221, 52,244, 62,237,193,119, 62,224, 38,190, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 17, 97, 15, 62,214, 34,220,
+ 63, 27,178,165, 62,208, 17,128, 63, 26,198,205, 62,214,184,124, 63, 19, 53,217, 62,218,211, 16, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 62,217,214,216, 62,214,224,218, 62,216, 24, 6, 62,208, 57,128, 62,236,200,217, 62,214, 49,134, 62,233, 14, 8,
+ 62,218,226, 66, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 27,178,165, 62,208, 17,128, 63, 33,120, 14, 62,214,238,166,
+ 63, 31,136,156, 62,219,138,194, 63, 26,198,205, 62,214,184,124, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,208, 30,254,
+ 62,219,177,204, 62,204, 75,168, 62,215, 7, 62, 62,216, 24, 6, 62,208, 57,128, 62,217,214,216, 62,214,224,218, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63, 33,120, 14, 62,214,238,166, 63, 38,149,140, 62,229, 95, 38, 63, 36, 9, 79, 62,229,224, 94,
+ 63, 31,136,156, 62,219,138,194, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,198,192,148, 62,230, 11,182, 62,193,140,168,
+ 62,229,129, 94, 62,204, 75,168, 62,215, 7, 62, 62,208, 30,254, 62,219,177,204, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63, 38,149,140, 62,229, 95, 38, 63, 39, 62, 92, 62,240, 75,121, 63, 36, 49, 14, 62,239, 88,253, 63, 36, 9, 79, 62,229,224, 94,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,198, 71, 97, 62,239,149,192, 62,192, 10,222, 62,240,128,163, 62,193,140,168,
+ 62,229,129, 94, 62,198,192,148, 62,230, 11,182, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 39, 62, 92, 62,240, 75,121,
+ 63, 37,113, 25, 62,247,157, 35, 63, 35, 33,243, 62,245,143, 80, 63, 36, 49, 14, 62,239, 88,253, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 62,200, 99, 87, 62,245,217,172, 62,195,165,189, 62,247,232,139, 62,192, 10,222, 62,240,128,163, 62,198, 71, 97,
+ 62,239,149,192, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 37,113, 25, 62,247,157, 35, 63, 30, 49, 96, 62,254,229,121,
+ 63, 29, 49,223, 62,250,140,199, 63, 35, 33,243, 62,245,143, 80, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,212,124,147,
+ 62,250,215,146, 62,210,116,176, 62,255, 62,227, 62,195,165,189, 62,247,232,139, 62,200, 99, 87, 62,245,217,172, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63, 30, 49, 96, 62,254,229,121, 63, 25,182,151, 63, 1, 9,130, 63, 25,181, 50, 62,253,111,118,
+ 63, 29, 49,223, 62,250,140,199, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,219,151, 52, 62,253,186, 68, 62,219,150,213,
+ 63, 1, 55, 50, 62,210,116,176, 62,255, 62,227, 62,212,124,147, 62,250,215,146, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63, 25,182,151, 63, 1, 9,130, 63, 22, 81,240, 63, 1, 70,114, 63, 22,188,241, 62,253,149, 28, 63, 25,181, 50, 62,253,111,118,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,225,163,212, 62,253,215, 91, 62,226,128,106, 63, 1,111,198, 62,219,150,213,
+ 63, 1, 55, 50, 62,219,151, 52, 62,253,186, 68, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 22, 81,240, 63, 1, 70,114,
+ 63, 17, 59,103, 62,255,195,120, 63, 19, 44, 55, 62,250, 21, 86, 63, 22,188,241, 62,253,149, 28, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 62,232,228,153, 62,250, 67,154, 62,236,213,209, 62,255,250, 4, 62,226,128,106, 63, 1,111,198, 62,225,163,212,
+ 62,253,215, 91, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 22,188,241, 62,253,149, 28, 63, 19, 44, 55, 62,250, 21, 86,
+ 63, 20,165, 9, 62,247, 99,248, 63, 23, 0, 20, 62,251, 57, 6, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,229,232,232,
+ 62,247,142, 74, 62,232,228,153, 62,250, 67,154, 62,225,163,212, 62,253,215, 91, 62,225, 26,145, 62,251,116,114, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63, 25,181, 50, 62,253,111,118, 63, 22,188,241, 62,253,149, 28, 63, 23, 0, 20, 62,251, 57, 6,
+ 63, 25,144,130, 62,251, 7,128, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,225, 26,145, 62,251,116,114, 62,225,163,212,
+ 62,253,215, 91, 62,219,151, 52, 62,253,186, 68, 62,219,225,177, 62,251, 75, 67, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63, 29, 49,223, 62,250,140,199, 63, 25,181, 50, 62,253,111,118, 63, 25,144,130, 62,251, 7,128, 63, 28,195, 80, 62,248,166, 55,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,219,225,177, 62,251, 75, 67, 62,219,151, 52, 62,253,186, 68, 62,212,124,147,
+ 62,250,215,146, 62,213, 95,233, 62,248,237, 20, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 35, 33,243, 62,245,143, 80,
+ 63, 29, 49,223, 62,250,140,199, 63, 28,195, 80, 62,248,166, 55, 63, 33,164, 22, 62,243, 75,102, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 62,213, 95,233, 62,248,237, 20, 62,212,124,147, 62,250,215,146, 62,200, 99, 87, 62,245,217,172, 62,203,114, 65,
+ 62,243,143,159, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 36, 49, 14, 62,239, 88,253, 63, 35, 33,243, 62,245,143, 80,
+ 63, 33,164, 22, 62,243, 75,102, 63, 34,160, 30, 62,238, 47,169, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,203,114, 65,
+ 62,243,143,159, 62,200, 99, 87, 62,245,217,172, 62,198, 71, 97, 62,239,149,192, 62,201,128,188, 62,238,110,126, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63, 36, 9, 79, 62,229,224, 94, 63, 36, 49, 14, 62,239, 88,253, 63, 34,160, 30, 62,238, 47,169,
+ 63, 34,144,131, 62,231, 87,253, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,201,128,188, 62,238,110,126, 62,198, 71, 97,
+ 62,239,149,192, 62,198,192,148, 62,230, 11,182, 62,201,190,141, 62,231,140,124, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63, 31,136,156, 62,219,138,194, 63, 36, 9, 79, 62,229,224, 94, 63, 34,144,131, 62,231, 87,253, 63, 30,208, 21, 62,221,182,174,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,201,190,141, 62,231,140,124, 62,198,192,148, 62,230, 11,182, 62,208, 30,254,
+ 62,219,177,204, 62,209,133,168, 62,221,221, 51, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 26,198,205, 62,214,184,124,
+ 63, 31,136,156, 62,219,138,194, 63, 30,208, 21, 62,221,182,174, 63, 26,218,128, 62,217,206, 68, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 62,209,133,168, 62,221,221, 51, 62,208, 30,254, 62,219,177,204, 62,217,214,216, 62,214,224,218, 62,217,157, 11,
+ 62,217,243, 64, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 19, 53,217, 62,218,211, 16, 63, 26,198,205, 62,214,184,124,
+ 63, 26,218,128, 62,217,206, 68, 63, 20, 53,103, 62,221, 84,236, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,217,157, 11,
+ 62,217,243, 64, 62,217,214,216, 62,214,224,218, 62,233, 14, 8, 62,218,226, 66, 62,231, 5, 68, 62,221,101,234, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63, 16,216, 4, 62,224, 24,160, 63, 19, 53,217, 62,218,211, 16, 63, 20, 53,103, 62,221, 84,236,
+ 63, 18, 87, 81, 62,226,175, 33, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,231, 5, 68, 62,221,101,234, 62,233, 14, 8,
+ 62,218,226, 66, 62,237,193,119, 62,224, 38,190, 62,234,187,180, 62,226,190,249, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63, 19, 44, 55, 62,250, 21, 86, 63, 16,171,184, 62,241,133, 40, 63, 18, 68, 98, 62,240,197,150, 63, 20,165, 9, 62,247, 99,248,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,234,197, 35, 62,240,226,215, 62,237,252,218, 62,241,160, 62, 62,232,228,153,
+ 62,250, 67,154, 62,229,232,232, 62,247,142, 74, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 16,171,184, 62,241,133, 40,
+ 63, 15,200,120, 62,231,255, 84, 63, 18, 4,161, 62,232,184,138, 63, 18, 68, 98, 62,240,197,150, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 62,235, 85,154, 62,232,206, 92, 62,239,211, 21, 62,232, 18,185, 62,237,252,218, 62,241,160, 62, 62,234,197, 35,
+ 62,240,226,215, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 15,200,120, 62,231,255, 84, 63, 16,216, 4, 62,224, 24,160,
+ 63, 18, 87, 81, 62,226,175, 33, 63, 18, 4,161, 62,232,184,138, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,234,187,180,
+ 62,226,190,249, 62,237,193,119, 62,224, 38,190, 62,239,211, 21, 62,232, 18,185, 62,235, 85,154, 62,232,206, 92, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63, 3,232,148, 63, 11, 17,164, 63, 11,169, 67, 63, 11,197, 18, 63, 13,120,216, 63, 23, 81,160,
+ 63, 4, 15,147, 63, 23,248,227, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,245, 27, 64, 63, 23,166,100, 62,248, 72, 55,
+ 63, 11,232, 91, 63, 3,232,148, 63, 11, 17,164, 63, 4, 15,147, 63, 23,248,227, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63, 11,169, 67, 63, 11,197, 18, 63, 22,244,173, 63, 11,215,236, 63, 23,233, 94, 63, 16, 60,186, 63, 13,120,216, 63, 23, 81,160,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,223,130,109, 63, 16,165,118, 62,225, 89,220, 63, 12, 42, 77, 62,248, 72, 55,
+ 63, 11,232, 91, 62,245, 27, 64, 63, 23,166,100, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 22,244,173, 63, 11,215,236,
+ 63, 26,105, 28, 63, 11,194,242, 63, 28, 56,220, 63, 14,250, 66, 63, 23,233, 94, 63, 16, 60,186, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 62,214,161,157, 63, 15,110,219, 62,218, 73,220, 63, 12, 31,169, 62,225, 89,220, 63, 12, 42, 77, 62,223,130,109,
+ 63, 16,165,118, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 26,105, 28, 63, 11,194,242, 63, 34,158,220, 63, 10, 23,175,
+ 63, 39, 44,109, 63, 19,221,107, 63, 28, 56,220, 63, 14,250, 66, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,192, 26,156,
+ 63, 20,139, 31, 62,201,109,124, 63, 10,121, 72, 62,218, 73,220, 63, 12, 31,169, 62,214,161,157, 63, 15,110,219, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63, 34,158,220, 63, 10, 23,175, 63, 46, 88,238, 63, 2,223,146, 63, 56, 80,242, 63, 6,244, 44,
+ 63, 39, 44,109, 63, 19,221,107, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 64, 62,156,208, 61, 63, 7, 16,204, 62,177, 87,173,
+ 63, 3, 9,102, 62,201,109,124, 63, 10,121, 72, 62,192, 26,156, 63, 20,139, 31, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 16,
+ 63, 46, 88,238, 63, 2,223,146, 63, 48,134, 62, 62,249,107, 37, 63, 54,173,195, 62,252,106,239, 63, 56, 80,242, 63, 6,244, 44,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,128, 62,160, 36,202, 62,252, 51, 94, 62,172,229,172, 62,249,127,116, 62,177, 87,173,
+ 63, 3, 9,102, 62,156,208, 61, 63, 7, 16,204, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,128, 63, 48,134, 62, 62,249,107, 37,
+ 63, 50,229, 38, 62,226, 32,169, 63, 53, 88,154, 62,221,146,240, 63, 54,173,195, 62,252,106,239, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 64, 62,162,172,128, 62,221,169, 17, 62,168, 39,196, 62,226, 11,206, 62,172,229,172, 62,249,127,116, 62,160, 36,202,
+ 62,252, 51, 94, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 16, 63, 50,229, 38, 62,226, 32,169, 63, 43, 57, 87, 62,206, 58,222,
+ 63, 49,117,240, 62,198,138,164, 63, 53, 88,154, 62,221,146,240, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,128, 62,172,137,147,
+ 62,198, 19,148, 62,184,207,130, 62,206, 27, 42, 62,168, 39,196, 62,226, 11,206, 62,162,172,128, 62,221,169, 17, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0,128, 63, 43, 57, 87, 62,206, 58,222, 63, 37, 94, 91, 62,187,120,107, 63, 41,160,156, 62,182,175, 56,
+ 63, 49,117,240, 62,198,138,164, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,188,212,202, 62,182,163,245, 62,197, 28,156,
+ 62,187,130,166, 62,184,207,130, 62,206, 27, 42, 62,172,137,147, 62,198, 19,148, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63, 48,252,165, 62, 85, 33,133, 63, 48, 54,112, 62, 96, 19, 20, 63, 46, 36,172, 62,129, 7,208, 63, 42, 17,240, 62, 97, 84,129,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,181, 71, 76, 62,131,200,204, 62,175,121,117, 62,106,185,183, 62,172, 24,217,
+ 62, 92,237, 21, 62,187, 81,138, 62,103, 40, 59, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 48, 89,204, 62, 4,194,134,
+ 63, 48,252,165, 62, 85, 33,133, 63, 42, 17,240, 62, 97, 84,129, 63, 37,125,160, 62, 46,211, 50, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 16, 62,187, 81,138, 62,103, 40, 59, 62,172, 24,217, 62, 92,237, 21, 62,172,197, 94, 62, 4,200,109, 62,195,121, 25,
+ 62, 48,253, 46, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 64, 63, 20, 44, 11, 61,163, 26, 20, 63, 48, 89,204, 62, 4,194,134,
+ 63, 37,125,160, 62, 46,211, 50, 63, 24, 92, 40, 62, 21,184,214, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 32, 62,195,121, 25,
+ 62, 48,253, 46, 62,172,197, 94, 62, 4,200,109, 62,230,122,140, 61,161,248,202, 62,222, 13,216, 62, 22,116,222, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 32, 63, 16,254,174, 62, 34, 45, 94, 63, 3,199,219, 61,229, 28, 18, 63, 20, 44, 11, 61,163, 26, 20,
+ 63, 24, 92, 40, 62, 21,184,214, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 16, 62,230,122,140, 61,161,248,202, 63, 3,199,219,
+ 61,229, 28, 18, 62,236,248,140, 62, 34,202,182, 62,222, 13,216, 62, 22,116,222, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 64,
+ 63, 21,152,184, 62, 53, 47,182, 63, 16,254,174, 62, 34, 45, 94, 63, 24, 92, 40, 62, 21,184,214, 63, 25, 52,209, 62, 51,140, 76,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 32, 62,222, 13,216, 62, 22,116,222, 62,236,248,140, 62, 34,202,182, 62,227,207,183,
+ 62, 54, 75,250, 62,220,137,229, 62, 52,228,185, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 32, 63, 22, 57,137, 62, 61, 93, 81,
+ 63, 21,152,184, 62, 53, 47,182, 63, 25, 52,209, 62, 51,140, 76, 63, 30,166,193, 62, 73,168,114, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 62,220,137,229, 62, 52,228,185, 62,227,207,183, 62, 54, 75,250, 62,226,152,122, 62, 62,166,190, 62,209,198, 54,
+ 62, 75,240, 18, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 22,249,250, 62, 88,251,160, 63, 22, 57,137, 62, 61, 93, 81,
+ 63, 30,166,193, 62, 73,168,114, 63, 36, 0, 75, 62,116, 47,229, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,209,198, 54,
+ 62, 75,240, 18, 62,226,152,122, 62, 62,166,190, 62,225, 83, 90, 62, 90,153, 21, 62,199,231,211, 62,119,237,216, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63, 30,166,193, 62, 73,168,114, 63, 37,125,160, 62, 46,211, 50, 63, 42, 17,240, 62, 97, 84,129,
+ 63, 36, 0, 75, 62,116, 47,229, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,187, 81,138, 62,103, 40, 59, 62,195,121, 25,
+ 62, 48,253, 46, 62,209,198, 54, 62, 75,240, 18, 62,199,231,211, 62,119,237,216, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63, 30,166,193, 62, 73,168,114, 63, 25, 52,209, 62, 51,140, 76, 63, 24, 92, 40, 62, 21,184,214, 63, 37,125,160, 62, 46,211, 50,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,222, 13,216, 62, 22,116,222, 62,220,137,229, 62, 52,228,185, 62,209,198, 54,
+ 62, 75,240, 18, 62,195,121, 25, 62, 48,253, 46, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 36,163, 37, 62,140,168,191,
+ 63, 36, 0, 75, 62,116, 47,229, 63, 42, 17,240, 62, 97, 84,129, 63, 46, 36,172, 62,129, 7,208, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 62,187, 81,138, 62,103, 40, 59, 62,199,231,211, 62,119,237,216, 62,199, 64, 6, 62,142, 6,105, 62,181, 71, 76,
+ 62,131,200,204, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 25, 81, 20, 62,132, 56, 17, 63, 22,249,250, 62, 88,251,160,
+ 63, 36, 0, 75, 62,116, 47,229, 63, 36,163, 37, 62,140,168,191, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,199,231,211,
+ 62,119,237,216, 62,225, 83, 90, 62, 90,153, 21, 62,221, 42, 54, 62,133, 25,209, 62,199, 64, 6, 62,142, 6,105, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63, 27, 46,208, 62,148, 35,149, 63, 36, 60, 91, 62,150,222,221, 63, 33,170,222, 62,158,126, 74,
+ 63, 27,177, 36, 62,156,151,158, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,204,234, 72, 62,159, 63, 56, 62,199,245,150,
+ 62,152, 15, 85, 62,217,166,238, 62,148,221,229, 62,216,160, 0, 62,157, 44,127, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63, 25, 81, 20, 62,132, 56, 17, 63, 36,163, 37, 62,140,168,191, 63, 36, 60, 91, 62,150,222,221, 63, 27, 46,208, 62,148, 35,149,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,199,245,150, 62,152, 15, 85, 62,199, 64, 6, 62,142, 6,105, 62,221, 42, 54,
+ 62,133, 25,209, 62,217,166,238, 62,148,221,229, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 27,239,111, 62,166, 77,159,
+ 63, 27,177, 36, 62,156,151,158, 63, 33,170,222, 62,158,126, 74, 63, 31,212,102, 62,164,192,144, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 62,204,234, 72, 62,159, 63, 56, 62,216,160, 0, 62,157, 44,127, 62,216, 21,115, 62,166,177, 14, 62,208,119, 17,
+ 62,165, 65,201, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 27,239,111, 62,166, 77,159, 63, 31,212,102, 62,164,192,144,
+ 63, 41,160,156, 62,182,175, 56, 63, 37, 94, 91, 62,187,120,107, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,188,212,202,
+ 62,182,163,245, 62,208,119, 17, 62,165, 65,201, 62,216, 21,115, 62,166,177, 14, 62,197, 28,156, 62,187,130,166, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 62,194,119,104, 63, 82,189,164, 62,212, 73, 23, 63, 90,239,152, 62,205,192,100, 63, 97,238, 46,
+ 62,185, 56, 38, 63, 91,154, 72, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,240, 62,141, 94,228, 63,100,234, 86, 62,150, 66, 84,
+ 63, 94,154,114, 62,173, 86,230, 63, 98, 66, 79, 62,162,143, 20, 63,106,173, 44, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,240,
+ 63, 87,122, 72, 62, 62, 8,216, 63, 84,106,202, 62,113,185,137, 63, 72, 77,226, 62,121, 21,204, 63, 71,225,158, 62, 68, 34,113,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 16, 62,137, 32,132, 62,121, 65,181, 62,107,179,168, 62,103,127,139, 62,114,147,210,
+ 62, 61,116,212, 62,142,125,248, 62, 80, 4, 30, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 64, 63, 71,225,158, 62, 68, 34,113,
+ 63, 72, 77,226, 62,121, 21,204, 63, 51, 7, 8, 62,130,186, 5, 63, 49,166, 3, 62, 96, 57,232, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 62,172,197, 18, 62,133,112, 41, 62,137, 32,132, 62,121, 65,181, 62,142,125,248, 62, 80, 4, 30, 62,174,228,121,
+ 62,109, 79, 52, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 49,166, 3, 62, 96, 57,232, 63, 51, 7, 8, 62,130,186, 5,
+ 63, 46, 36,172, 62,129, 7,208, 63, 48, 54,112, 62, 96, 19, 20, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,181, 71, 76,
+ 62,131,200,204, 62,172,197, 18, 62,133,112, 41, 62,174,228,121, 62,109, 79, 52, 62,175,121,117, 62,106,185,183, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63, 36,163, 37, 62,140,168,191, 63, 46, 36,172, 62,129, 7,208, 63, 51, 7, 8, 62,130,186, 5,
+ 63, 36, 60, 91, 62,150,222,221, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,172,197, 18, 62,133,112, 41, 62,181, 71, 76,
+ 62,131,200,204, 62,199, 64, 6, 62,142, 6,105, 62,199,245,150, 62,152, 15, 85, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63, 53, 88,154, 62,221,146,240, 63, 49,117,240, 62,198,138,164, 63, 69, 19,224, 62,190, 68, 24, 63, 74, 64, 53, 62,224, 31,171,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 16, 62,134, 78,250, 62,186,213,148, 62,172,137,147, 62,198, 19,148, 62,162,172,128,
+ 62,221,169, 17, 62,114,112,184, 62,220,169,248, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 64, 62,214, 74, 54, 63, 70, 55, 20,
+ 62,233,130, 48, 63, 83, 69,188, 62,212, 73, 23, 63, 90,239,152, 62,194,119,104, 63, 82,189,164, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0,240, 62,150, 66, 84, 63, 94,154,114, 62,153, 1, 66, 63, 81,149,245, 62,185, 56, 38, 63, 83,110,102, 62,173, 86,230,
+ 63, 98, 66, 79, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,240, 63, 66,242,106, 63, 25, 94,202, 63, 70,100,190, 63, 15,234,222,
+ 63, 77,189, 90, 63, 17, 88,233, 63, 74,206, 8, 63, 27,118, 88, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62, 96, 32, 22,
+ 63, 16, 60, 66, 62,125, 87, 86, 63, 15, 5,174, 62,132,187, 78, 63, 24, 44,180, 62,108, 79, 26, 63, 26, 1,124, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63, 74,206, 8, 63, 27,118, 88, 63, 77,189, 90, 63, 17, 88,233, 63, 85,139, 72, 63, 19, 51,103,
+ 63, 85,119,220, 63, 31, 71, 77, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62, 64,199, 64, 63, 18, 40, 26, 62, 96, 32, 22,
+ 63, 16, 60, 66, 62,108, 79, 26, 63, 26, 1,124, 62, 67,191, 44, 63, 30, 89, 90, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63, 85,119,220, 63, 31, 71, 77, 63, 85,139, 72, 63, 19, 51,103, 63,100,213,228, 63, 20,156, 72, 63, 96, 82, 18, 63, 34,133,128,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,128, 62, 1, 50,226, 63, 20, 68,184, 62, 64,199, 64, 63, 18, 40, 26, 62, 67,191, 44,
+ 63, 30, 89, 90, 62, 24,204,194, 63, 34,186, 32, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,128, 63, 56, 80,242, 63, 6,244, 44,
+ 63, 54,173,195, 62,252,106,239, 63, 60,205,115, 62,253,150,213, 63, 64, 14,166, 63, 4, 80, 81, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 16, 62,147, 85,190, 62,252,176, 91, 62,160, 36,202, 62,252, 51, 94, 62,156,208, 61, 63, 7, 16,204, 62,140,121,160,
+ 63, 3,197, 74, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 64, 63, 64, 14,166, 63, 4, 80, 81, 63, 60,205,115, 62,253,150,213,
+ 63, 73,103, 68, 63, 0,248,233, 63, 75, 12,248, 63, 8,206, 64, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,115, 59,144,
+ 62,255,143,102, 62,147, 85,190, 62,252,176, 91, 62,140,121,160, 63, 3,197, 74, 62,107,135, 78, 63, 7,182, 88, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63, 75, 12,248, 63, 8,206, 64, 63, 73,103, 68, 63, 0,248,233, 63, 82,151,239, 63, 3,223, 86,
+ 63, 82,227,181, 63, 11,102,189, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62, 77, 17, 82, 63, 2, 98,162, 62,115, 59,144,
+ 62,255,143,102, 62,107,135, 78, 63, 7,182, 88, 62, 75, 98,202, 63, 10, 43,108, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63, 82,227,181, 63, 11,102,189, 63, 82,151,239, 63, 3,223, 86, 63, 91,224, 92, 63, 5,144,239, 63, 90,148,161, 63, 13, 95,146,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62, 38, 40,178, 63, 3,230, 14, 62, 77, 17, 82, 63, 2, 98,162, 62, 75, 98,202,
+ 63, 10, 43,108, 62, 43,162, 10, 63, 12, 50, 8, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63,103, 89,120, 63, 2, 76,105,
+ 63,103,179,170, 63, 12,105,142, 63, 90,148,161, 63, 13, 95,146, 63, 91,224, 92, 63, 5,144,239, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 62, 43,162, 10, 63, 12, 50, 8, 61,231, 41,168, 63, 11, 83,158, 61,234,128,116, 63, 0, 39,200, 62, 38, 40,178,
+ 63, 3,230, 14, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63,100,213,228, 63, 20,156, 72, 63, 85,139, 72, 63, 19, 51,103,
+ 63, 90,148,161, 63, 13, 95,146, 63,103,179,170, 63, 12,105,142, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62, 43,162, 10,
+ 63, 12, 50, 8, 62, 64,199, 64, 63, 18, 40, 26, 62, 1, 50,226, 63, 20, 68,184, 61,231, 41,168, 63, 11, 83,158, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63, 85,139, 72, 63, 19, 51,103, 63, 77,189, 90, 63, 17, 88,233, 63, 82,227,181, 63, 11,102,189,
+ 63, 90,148,161, 63, 13, 95,146, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62, 75, 98,202, 63, 10, 43,108, 62, 96, 32, 22,
+ 63, 16, 60, 66, 62, 64,199, 64, 63, 18, 40, 26, 62, 43,162, 10, 63, 12, 50, 8, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63, 77,189, 90, 63, 17, 88,233, 63, 70,100,190, 63, 15,234,222, 63, 75, 12,248, 63, 8,206, 64, 63, 82,227,181, 63, 11,102,189,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,107,135, 78, 63, 7,182, 88, 62,125, 87, 86, 63, 15, 5,174, 62, 96, 32, 22,
+ 63, 16, 60, 66, 62, 75, 98,202, 63, 10, 43,108, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 70,100,190, 63, 15,234,222,
+ 63, 60,235, 82, 63, 12, 12, 27, 63, 64, 14,166, 63, 4, 80, 81, 63, 75, 12,248, 63, 8,206, 64, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 62,140,121,160, 63, 3,197, 74, 62,145,230, 78, 63, 11,225,148, 62,125, 87, 86, 63, 15, 5,174, 62,107,135, 78,
+ 63, 7,182, 88, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 57,118, 31, 63, 12, 79,230, 63, 56, 80,242, 63, 6,244, 44,
+ 63, 64, 14,166, 63, 4, 80, 81, 63, 60,235, 82, 63, 12, 12, 27, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 32, 62,140,121,160,
+ 63, 3,197, 74, 62,156,208, 61, 63, 7, 16,204, 62,152,199, 0, 63, 12,133, 13, 62,145,230, 78, 63, 11,225,148, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 32, 63, 57,240,195, 63, 23,138, 10, 63, 60,235, 82, 63, 12, 12, 27, 63, 70,100,190, 63, 15,234,222,
+ 63, 66,242,106, 63, 25, 94,202, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,125, 87, 86, 63, 15, 5,174, 62,145,230, 78,
+ 63, 11,225,148, 62,150, 7,247, 63, 23, 12, 96, 62,132,187, 78, 63, 24, 44,180, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63, 13,120,216, 63, 23, 81,160, 63, 23,233, 94, 63, 16, 60,186, 63, 28, 56,220, 63, 14,250, 66, 63, 39, 44,109, 63, 19,221,107,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,214,161,157, 63, 15,110,219, 62,223,130,109, 63, 16,165,118, 62,245, 27, 64,
+ 63, 23,166,100, 62,192, 26,156, 63, 20,139, 31, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 56, 29,176, 63, 20,206, 88,
+ 63, 57,118, 31, 63, 12, 79,230, 63, 60,235, 82, 63, 12, 12, 27, 63, 57,240,195, 63, 23,138, 10, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 62,145,230, 78, 63, 11,225,148, 62,152,199, 0, 63, 12,133, 13, 62,153,211,239, 63, 20,159,220, 62,150, 7,247,
+ 63, 23, 12, 96, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 54,148, 48, 63, 22,206,220, 63, 56, 29,176, 63, 20,206, 88,
+ 63, 57,240,195, 63, 23,138, 10, 63,128, 0, 0, 63,128, 0, 0, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,150, 7,247,
+ 63, 23, 12, 96, 62,153,211,239, 63, 20,159,220, 62,156,106,108, 63, 22,154,146, 63,128, 0, 0, 63,128, 0, 0, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63, 54,173,195, 62,252,106,239, 63, 53, 88,154, 62,221,146,240, 63, 74, 64, 53, 62,224, 31,171,
+ 63, 60,205,115, 62,253,150,213, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 32, 62,114,112,184, 62,220,169,248, 62,162,172,128,
+ 62,221,169, 17, 62,160, 36,202, 62,252, 51, 94, 62,147, 85,190, 62,252,176, 91, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 32,
+ 63, 74, 64, 53, 62,224, 31,171, 63, 81,106,217, 62,232,214, 14, 63, 73,103, 68, 63, 0,248,233, 63, 60,205,115, 62,253,150,213,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,115, 59,144, 62,255,143,102, 62, 84, 93, 88, 62,228,105, 50, 62,114,112,184,
+ 62,220,169,248, 62,147, 85,190, 62,252,176, 91, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 81,106,217, 62,232,214, 14,
+ 63, 93,154,106, 62,233, 26,226, 63, 82,151,239, 63, 3,223, 86, 63, 73,103, 68, 63, 0,248,233, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 62, 77, 17, 82, 63, 2, 98,162, 62, 33, 1,128, 62,226,210, 70, 62, 84, 93, 88, 62,228,105, 50, 62,115, 59,144,
+ 62,255,143,102, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63,103, 89,120, 63, 2, 76,105, 63, 91,224, 92, 63, 5,144,239,
+ 63, 82,151,239, 63, 3,223, 86, 63, 93,154,106, 62,233, 26,226, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62, 77, 17, 82,
+ 63, 2, 98,162, 62, 38, 40,178, 63, 3,230, 14, 61,234,128,116, 63, 0, 39,200, 62, 33, 1,128, 62,226,210, 70, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63, 51, 7, 8, 62,130,186, 5, 63, 72, 77,226, 62,121, 21,204, 63, 73,254,154, 62,140, 82,178,
+ 63, 56,188, 90, 62,159,207,103, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,130,249,249, 62,137,175,246, 62,137, 32,132,
+ 62,121, 65,181, 62,172,197, 18, 62,133,112, 41, 62,161, 5,192, 62,159, 40,228, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63, 69, 19,224, 62,190, 68, 24, 63, 56,188, 90, 62,159,207,103, 63, 73,254,154, 62,140, 82,178, 63, 77,217,216, 62,157,228, 7,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,128, 62,130,249,249, 62,137,175,246, 62,161, 5,192, 62,159, 40,228, 62,134, 78,250,
+ 62,186,213,148, 62,111,118,154, 62,152,108,120, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,128, 63, 49,117,240, 62,198,138,164,
+ 63, 41,160,156, 62,182,175, 56, 63, 56,188, 90, 62,159,207,103, 63, 69, 19,224, 62,190, 68, 24, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 62,161, 5,192, 62,159, 40,228, 62,188,212,202, 62,182,163,245, 62,172,137,147, 62,198, 19,148, 62,134, 78,250,
+ 62,186,213,148, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 41,160,156, 62,182,175, 56, 63, 33,170,222, 62,158,126, 74,
+ 63, 36, 60, 91, 62,150,222,221, 63, 56,188, 90, 62,159,207,103, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,199,245,150,
+ 62,152, 15, 85, 62,204,234, 72, 62,159, 63, 56, 62,188,212,202, 62,182,163,245, 62,161, 5,192, 62,159, 40,228, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63, 36, 60, 91, 62,150,222,221, 63, 51, 7, 8, 62,130,186, 5, 63, 56,188, 90, 62,159,207,103,
+ 63,128, 0, 0, 63,128, 0, 0, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,161, 5,192, 62,159, 40,228, 62,172,197, 18,
+ 62,133,112, 41, 62,199,245,150, 62,152, 15, 85, 63,128, 0, 0, 63,128, 0, 0, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63, 41,160,156, 62,182,175, 56, 63, 31,212,102, 62,164,192,144, 63, 33,170,222, 62,158,126, 74, 63,128, 0, 0, 63,128, 0, 0,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,204,234, 72, 62,159, 63, 56, 62,208,119, 17, 62,165, 65,201, 62,188,212,202,
+ 62,182,163,245, 63,128, 0, 0, 63,128, 0, 0, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,245, 44,226, 63, 96,140,129,
+ 62,227,135, 42, 63,101, 2, 58, 62,219,168,136, 63, 95,236, 30, 62,238, 30,135, 63, 90, 41,200, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0,240, 62,137,240,216, 63, 93,226, 90, 62,122,103,110, 63, 92,255,236, 62,120, 84, 74, 63, 83, 32,104, 62,138,193, 32,
+ 63, 83, 3, 16, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,240, 62,233,130, 48, 63, 83, 69,188, 62,238, 30,135, 63, 90, 41,200,
+ 62,219,168,136, 63, 95,236, 30, 62,212, 73, 23, 63, 90,239,152, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,240, 62,137,240,216,
+ 63, 93,226, 90, 62,138,193, 32, 63, 83, 3, 16, 62,153, 1, 66, 63, 81,149,245, 62,150, 66, 84, 63, 94,154,114, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0,240, 63, 77,217,216, 62,157,228, 7, 63, 73,254,154, 62,140, 82,178, 63, 90, 61, 33, 62,124,207,195,
+ 63, 90,225,160, 62,137,121,110, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 16, 62, 81,207, 98, 62,110, 1,109, 62,130,249,249,
+ 62,137,175,246, 62,111,118,154, 62,152,108,120, 62, 74,125,166, 62,130, 30,252, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 64,
+ 63, 72, 77,226, 62,121, 21,204, 63, 84,106,202, 62,113,185,137, 63, 90, 61, 33, 62,124,207,195, 63, 73,254,154, 62,140, 82,178,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62, 81,207, 98, 62,110, 1,109, 62,107,179,168, 62,103,127,139, 62,137, 32,132,
+ 62,121, 65,181, 62,130,249,249, 62,137,175,246, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,212, 73, 23, 63, 90,239,152,
+ 62,219,168,136, 63, 95,236, 30, 62,205,192,100, 63, 97,238, 46, 63,128, 0, 0, 63,128, 0, 0, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0,112, 62,141, 94,228, 63,100,234, 86, 62,137,240,216, 63, 93,226, 90, 62,150, 66, 84, 63, 94,154,114, 63,128, 0, 0,
+ 63,128, 0, 0, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,112, 63,109,178, 31, 62,228, 68,224, 63,102,178, 46, 62,232,184,100,
+ 63,101,251,100, 62,227,198,238, 63,107,173, 94, 62,225,130,168, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 61,249,209, 68,
+ 62,219,134, 70, 61,242,216,120, 62,225, 40,124, 61,177, 27, 28, 62,219,240, 42, 61,196,131, 76, 62,216, 97,196, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63,109,178, 31, 62,228, 68,224, 63,107,173, 94, 62,225,130,168, 63,114,102,144, 62,220, 23,198,
+ 63,116, 76, 41, 62,222,153,139, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 61,120,163, 56, 62,208,252, 58, 61,196,131, 76,
+ 62,216, 97,196, 61,177, 27, 28, 62,219,240, 42, 61, 73,183,128, 62,213,108, 84, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63,116, 76, 41, 62,222,153,139, 63,114,102,144, 62,220, 23,198, 63,117, 87, 84, 62,211,255,221, 63,119,115,183, 62,215, 49,140,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 61, 55, 29,144, 62,194,183,207, 61,120,163, 56, 62,208,252, 58, 61, 73,183,128,
+ 62,213,108, 84, 60,231,111,224, 62,198,142,100, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63,119,115,183, 62,215, 49,140,
+ 63,117, 87, 84, 62,211,255,221, 63,118, 20,150, 62,196,110, 60, 63,122, 12, 49, 62,197, 8,246, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 61,103,197, 96, 62,170,206, 15, 61, 55, 29,144, 62,194,183,207, 60,231,111,224, 62,198,142,100, 61, 16, 54,240,
+ 62,167, 4,120, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63,122, 12, 49, 62,197, 8,246, 63,118, 20,150, 62,196,110, 60,
+ 63,108,155, 17, 62,178,201,130, 63,110,190, 84, 62,172, 77,223, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 61,246,252,148,
+ 62,160,116,164, 61,103,197, 96, 62,170,206, 15, 61, 16, 54,240, 62,167, 4,120, 61,246, 66, 8, 62,152,161, 28, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63,110,190, 84, 62,172, 77,223, 63,108,155, 17, 62,178,201,130, 63, 92,180, 21, 62,173, 95,202,
+ 63, 90, 5,151, 62,167, 61,138, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62, 54,216,144, 62,163, 76, 35, 61,246,252,148,
+ 62,160,116,164, 61,246, 66, 8, 62,152,161, 28, 62, 66,251,194, 62,158,102,163, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63,108,155, 17, 62,178,201,130, 63,109,132,198, 62,186,157,182, 63, 97, 32, 68, 62,178, 12,192, 63, 92,180, 21, 62,173, 95,202,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62, 36,185, 48, 62,166, 7, 16, 61,221, 91, 40, 62,167,194, 4, 61,246,252,148,
+ 62,160,116,164, 62, 54,216,144, 62,163, 76, 35, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63,118, 20,150, 62,196,110, 60,
+ 63,115,225, 84, 62,198, 85,208, 63,109,132,198, 62,186,157,182, 63,108,155, 17, 62,178,201,130, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 61,221, 91, 40, 62,167,194, 4, 61,134,221,244, 62,175,164,121, 61,103,197, 96, 62,170,206, 15, 61,246,252,148,
+ 62,160,116,164, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63,117, 87, 84, 62,211,255,221, 63,116, 48,222, 62,209, 8,169,
+ 63,115,225, 84, 62,198, 85,208, 63,118, 20,150, 62,196,110, 60, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 61,134,221,244,
+ 62,175,164,121, 61, 93,108,160, 62,190,207, 17, 61, 55, 29,144, 62,194,183,207, 61,103,197, 96, 62,170,206, 15, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63,114,102,144, 62,220, 23,198, 63,113,151,174, 62,214,229, 26, 63,116, 48,222, 62,209, 8,169,
+ 63,117, 87, 84, 62,211,255,221, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 61, 93,108,160, 62,190,207, 17, 61,135,155, 12,
+ 62,201, 39,166, 61,120,163, 56, 62,208,252, 58, 61, 55, 29,144, 62,194,183,207, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63,107,173, 94, 62,225,130,168, 63,107,239,228, 62,218, 59, 62, 63,113,151,174, 62,214,229, 26, 63,114,102,144, 62,220, 23,198,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 61,135,155, 12, 62,201, 39,166, 61,195, 47,128, 62,207, 11, 6, 61,196,131, 76,
+ 62,216, 97,196, 61,120,163, 56, 62,208,252, 58, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63,107,173, 94, 62,225,130,168,
+ 63,101,251,100, 62,227,198,238, 63,102,205, 71, 62,219, 94,132, 63,107,239,228, 62,218, 59, 62, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 61,244,157,192, 62,209,137,157, 61,249,209, 68, 62,219,134, 70, 61,196,131, 76, 62,216, 97,196, 61,195, 47,128,
+ 62,207, 11, 6, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 69, 19,224, 62,190, 68, 24, 63, 77,217,216, 62,157,228, 7,
+ 63, 85, 35,236, 62,181,201,164, 63, 78, 92, 56, 62,188,114,177, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 32, 62, 80, 91,122,
+ 62,174, 18, 72, 62,111,118,154, 62,152,108,120, 62,134, 78,250, 62,186,213,148, 62,104,163,162, 62,182,180,150, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 32, 63, 77,217,216, 62,157,228, 7, 63, 90, 5,151, 62,167, 61,138, 63, 92,180, 21, 62,173, 95,202,
+ 63, 85, 35,236, 62,181,201,164, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 16, 62, 54,216,144, 62,163, 76, 35, 62, 66,251,194,
+ 62,158,102,163, 62,111,118,154, 62,152,108,120, 62, 80, 91,122, 62,174, 18, 72, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 64,
+ 63, 74, 64, 53, 62,224, 31,171, 63, 69, 19,224, 62,190, 68, 24, 63, 78, 92, 56, 62,188,114,177, 63, 81,106,217, 62,232,214, 14,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62,104,163,162, 62,182,180,150, 62,134, 78,250, 62,186,213,148, 62,114,112,184,
+ 62,220,169,248, 62, 84, 93, 88, 62,228,105, 50, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 93,154,106, 62,233, 26,226,
+ 63, 94,229,196, 62,224,195,128, 63,101,251,100, 62,227,198,238, 63,102,178, 46, 62,232,184,100, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 61,249,209, 68, 62,219,134, 70, 62, 28,187,108, 62,217, 86, 48, 62, 33, 1,128, 62,226,210, 70, 61,242,216,120,
+ 62,225, 40,124, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 92,180, 21, 62,173, 95,202, 63, 97, 32, 68, 62,178, 12,192,
+ 63, 94,215, 9, 62,186, 54, 4, 63, 85, 35,236, 62,181,201,164, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62, 41,122, 60,
+ 62,175, 58, 16, 62, 36,185, 48, 62,166, 7, 16, 62, 54,216,144, 62,163, 76, 35, 62, 80, 91,122, 62,174, 18, 72, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63, 95, 78,230, 62,189,233, 4, 63, 86,188, 32, 62,190, 62, 44, 63, 85, 35,236, 62,181,201,164,
+ 63, 94,215, 9, 62,186, 54, 4, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62, 80, 91,122, 62,174, 18, 72, 62, 71,118, 78,
+ 62,182, 49, 27, 62, 37,225, 52, 62,179, 12, 40, 62, 41,122, 60, 62,175, 58, 16, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63, 92,166, 70, 62,197,166, 0, 63, 86,188, 32, 62,190, 62, 44, 63, 95, 78,230, 62,189,233, 4, 63, 95, 13,226, 62,194,152, 37,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62, 37,225, 52, 62,179, 12, 40, 62, 71,118, 78, 62,182, 49, 27, 62, 45,143,142,
+ 62,188, 37,237, 62, 36,230,106, 62,184, 27,222, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 95, 90,248, 62,207,122,100,
+ 63, 90,249,108, 62,212,199, 58, 63, 86,188, 32, 62,190, 62, 44, 63, 92,166, 70, 62,197,166, 0, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 62, 71,118, 78, 62,182, 49, 27, 62, 48, 56,110, 62,205, 43,230, 62, 30,250,174, 62,198, 12, 26, 62, 45,143,142,
+ 62,188, 37,237, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 94,229,196, 62,224,195,128, 63, 90,249,108, 62,212,199, 58,
+ 63, 95, 90,248, 62,207,122,100, 63, 98,104, 92, 62,215,136,197, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62, 30,250,174,
+ 62,198, 12, 26, 62, 48, 56,110, 62,205, 43,230, 62, 28,187,108, 62,217, 86, 48, 62, 15, 59,212, 62,206, 50,224, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63,101,251,100, 62,227,198,238, 63, 94,229,196, 62,224,195,128, 63, 98,104, 92, 62,215,136,197,
+ 63,102,205, 71, 62,219, 94,132, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62, 15, 59,212, 62,206, 50,224, 62, 28,187,108,
+ 62,217, 86, 48, 61,249,209, 68, 62,219,134, 70, 61,244,157,192, 62,209,137,157, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63, 81,106,217, 62,232,214, 14, 63, 90,249,108, 62,212,199, 58, 63, 94,229,196, 62,224,195,128, 63, 93,154,106, 62,233, 26,226,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62, 28,187,108, 62,217, 86, 48, 62, 48, 56,110, 62,205, 43,230, 62, 84, 93, 88,
+ 62,228,105, 50, 62, 33, 1,128, 62,226,210, 70, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 81,106,217, 62,232,214, 14,
+ 63, 78, 92, 56, 62,188,114,177, 63, 86,188, 32, 62,190, 62, 44, 63, 90,249,108, 62,212,199, 58, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 62, 71,118, 78, 62,182, 49, 27, 62,104,163,162, 62,182,180,150, 62, 84, 93, 88, 62,228,105, 50, 62, 48, 56,110,
+ 62,205, 43,230, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 78, 92, 56, 62,188,114,177, 63, 85, 35,236, 62,181,201,164,
+ 63, 86,188, 32, 62,190, 62, 44, 63,128, 0, 0, 63,128, 0, 0, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62, 71,118, 78,
+ 62,182, 49, 27, 62, 80, 91,122, 62,174, 18, 72, 62,104,163,162, 62,182,180,150, 63,128, 0, 0, 63,128, 0, 0, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63,102,205, 71, 62,219, 94,132, 63, 98,104, 92, 62,215,136,197, 63,100,109,182, 62,210,255,149,
+ 63,104, 86, 54, 62,214,241,209, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62, 7,107,160, 62,200,103, 34, 62, 15, 59,212,
+ 62,206, 50,224, 61,244,157,192, 62,209,137,157, 61,232, 2, 8, 62,203,214, 20, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63, 98,104, 92, 62,215,136,197, 63, 95, 90,248, 62,207,122,100, 63, 97,206,112, 62,204,202, 10, 63,100,109,182, 62,210,255,149,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62, 21, 68, 64, 62,194, 55,107, 62, 30,250,174, 62,198, 12, 26, 62, 15, 59,212,
+ 62,206, 50,224, 62, 7,107,160, 62,200,103, 34, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 95, 90,248, 62,207,122,100,
+ 63, 92,166, 70, 62,197,166, 0, 63, 94,241, 82, 62,198,103, 40, 63, 97,206,112, 62,204,202, 10, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 62, 35,225, 20, 62,188, 50, 39, 62, 45,143,142, 62,188, 37,237, 62, 30,250,174, 62,198, 12, 26, 62, 21, 68, 64,
+ 62,194, 55,107, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 92,166, 70, 62,197,166, 0, 63, 95, 13,226, 62,194,152, 37,
+ 63, 97, 1,118, 62,195,226, 47, 63, 94,241, 82, 62,198,103, 40, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62, 28, 43, 12,
+ 62,184,177,186, 62, 36,230,106, 62,184, 27,222, 62, 45,143,142, 62,188, 37,237, 62, 35,225, 20, 62,188, 50, 39, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63, 95, 13,226, 62,194,152, 37, 63, 95, 78,230, 62,189,233, 4, 63, 97,113, 51, 62,189,151, 92,
+ 63, 97, 1,118, 62,195,226, 47, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62, 29, 67,104, 62,177,199, 58, 62, 37,225, 52,
+ 62,179, 12, 40, 62, 36,230,106, 62,184, 27,222, 62, 28, 43, 12, 62,184,177,186, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63, 95, 78,230, 62,189,233, 4, 63, 94,215, 9, 62,186, 54, 4, 63, 96, 69, 96, 62,187,133,152, 63, 97,113, 51, 62,189,151, 92,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62, 35, 14,140, 62,176, 19, 33, 62, 41,122, 60, 62,175, 58, 16, 62, 37,225, 52,
+ 62,179, 12, 40, 62, 29, 67,104, 62,177,199, 58, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63, 94,215, 9, 62,186, 54, 4,
+ 63, 97, 32, 68, 62,178, 12,192, 63, 98, 91,112, 62,182,128,149, 63, 96, 69, 96, 62,187,133,152, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 62, 29,107,228, 62,169,230, 95, 62, 36,185, 48, 62,166, 7, 16, 62, 41,122, 60, 62,175, 58, 16, 62, 35, 14,140,
+ 62,176, 19, 33, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63,107,239,228, 62,218, 59, 62, 63,102,205, 71, 62,219, 94,132,
+ 63,104, 86, 54, 62,214,241,209, 63,109, 27, 34, 62,214,254,155, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 61,232, 2, 8,
+ 62,203,214, 20, 61,244,157,192, 62,209,137,157, 61,195, 47,128, 62,207, 11, 6, 61,184,174, 36, 62,202,130,216, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63,113,151,174, 62,214,229, 26, 63,107,239,228, 62,218, 59, 62, 63,109, 27, 34, 62,214,254,155,
+ 63,113,134, 69, 62,212, 82,156, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 61,184,174, 36, 62,202,130,216, 61,195, 47,128,
+ 62,207, 11, 6, 61,135,155, 12, 62,201, 39,166, 61,138,114, 60, 62,197, 61, 28, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63,116, 48,222, 62,209, 8,169, 63,113,151,174, 62,214,229, 26, 63,113,134, 69, 62,212, 82,156, 63,114,143, 42, 62,207,168, 24,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 61,138,114, 60, 62,197, 61, 28, 61,135,155, 12, 62,201, 39,166, 61, 93,108,160,
+ 62,190,207, 17, 61,132, 85,184, 62,189,211, 22, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63,115,225, 84, 62,198, 85,208,
+ 63,116, 48,222, 62,209, 8,169, 63,114,143, 42, 62,207,168, 24, 63,114,125,203, 62,200,114, 96, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 61,132, 85,184, 62,189,211, 22, 61, 93,108,160, 62,190,207, 17, 61,134,221,244, 62,175,164,121, 61,145,152, 16,
+ 62,179,214, 84, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63,109,132,198, 62,186,157,182, 63,115,225, 84, 62,198, 85,208,
+ 63,114,125,203, 62,200,114, 96, 63,109,192,177, 62,190,240,152, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 61,145,152, 16,
+ 62,179,214, 84, 61,134,221,244, 62,175,164,121, 61,221, 91, 40, 62,167,194, 4, 61,208,226, 64, 62,172, 58,232, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63, 97, 32, 68, 62,178, 12,192, 63,109,132,198, 62,186,157,182, 63,109,192,177, 62,190,240,152,
+ 63, 98, 91,112, 62,182,128,149, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 61,208,226, 64, 62,172, 58,232, 61,221, 91, 40,
+ 62,167,194, 4, 62, 36,185, 48, 62,166, 7, 16, 62, 29,107,228, 62,169,230, 95, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63, 97, 1,118, 62,195,226, 47, 63, 97,113, 51, 62,189,151, 92, 63,102,139,215, 62,193,109, 15, 63,100, 47, 54, 62,198,115,186,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62, 5,169, 92, 62,179,115,168, 62, 29, 67,104, 62,177,199, 58, 62, 28, 43, 12,
+ 62,184,177,186, 62, 13, 97, 50, 62,186, 42, 50, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63,100, 47, 54, 62,198,115,186,
+ 63,102,139,215, 62,193,109, 15, 63,105,241,174, 62,200, 8,204, 63,103,233, 71, 62,204, 42,178, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 61,229,171,228, 62,185, 42, 41, 62, 5,169, 92, 62,179,115,168, 62, 13, 97, 50, 62,186, 42, 50, 61,243,248, 92,
+ 62,191, 22, 96, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63,103,233, 71, 62,204, 42,178, 63,105,241,174, 62,200, 8,204,
+ 63,108, 37, 51, 62,205, 3,249, 63,106,212, 56, 62,208,238, 96, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 61,202, 99,120,
+ 62,190, 49,192, 61,229,171,228, 62,185, 42, 41, 61,243,248, 92, 62,191, 22, 96, 61,211,209,160, 62,195,159,108, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63,106,212, 56, 62,208,238, 96, 63,108, 37, 51, 62,205, 3,249, 63,110, 73, 56, 62,206,119,186,
+ 63,109,191, 46, 62,210, 64, 92, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 61,179,234,244, 62,190,219,240, 61,202, 99,120,
+ 62,190, 49,192, 61,211,209,160, 62,195,159,108, 61,181,129,196, 62,196, 14,204, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63,109, 27, 34, 62,214,254,155, 63,104, 86, 54, 62,214,241,209, 63,106,212, 56, 62,208,238, 96, 63,109,191, 46, 62,210, 64, 92,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 61,211,209,160, 62,195,159,108, 61,232, 2, 8, 62,203,214, 20, 61,184,174, 36,
+ 62,202,130,216, 61,181,129,196, 62,196, 14,204, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63,100,109,182, 62,210,255,149,
+ 63,103,233, 71, 62,204, 42,178, 63,106,212, 56, 62,208,238, 96, 63,104, 86, 54, 62,214,241,209, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 61,211,209,160, 62,195,159,108, 61,243,248, 92, 62,191, 22, 96, 62, 7,107,160, 62,200,103, 34, 61,232, 2, 8,
+ 62,203,214, 20, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63,100,109,182, 62,210,255,149, 63, 97,206,112, 62,204,202, 10,
+ 63,100, 47, 54, 62,198,115,186, 63,103,233, 71, 62,204, 42,178, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62, 13, 97, 50,
+ 62,186, 42, 50, 62, 21, 68, 64, 62,194, 55,107, 62, 7,107,160, 62,200,103, 34, 61,243,248, 92, 62,191, 22, 96, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63, 97, 1,118, 62,195,226, 47, 63,100, 47, 54, 62,198,115,186, 63, 97,206,112, 62,204,202, 10,
+ 63, 94,241, 82, 62,198,103, 40, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62, 21, 68, 64, 62,194, 55,107, 62, 13, 97, 50,
+ 62,186, 42, 50, 62, 28, 43, 12, 62,184,177,186, 62, 35,225, 20, 62,188, 50, 39, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63, 96, 69, 96, 62,187,133,152, 63, 98, 91,112, 62,182,128,149, 63,102,139,215, 62,193,109, 15, 63, 97,113, 51, 62,189,151, 92,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 62, 5,169, 92, 62,179,115,168, 62, 29,107,228, 62,169,230, 95, 62, 35, 14,140,
+ 62,176, 19, 33, 62, 29, 67,104, 62,177,199, 58, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63,109,192,177, 62,190,240,152,
+ 63,105,241,174, 62,200, 8,204, 63,102,139,215, 62,193,109, 15, 63, 98, 91,112, 62,182,128,149, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 62, 5,169, 92, 62,179,115,168, 61,229,171,228, 62,185, 42, 41, 61,208,226, 64, 62,172, 58,232, 62, 29,107,228,
+ 62,169,230, 95, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63,114,125,203, 62,200,114, 96, 63,108, 37, 51, 62,205, 3,249,
+ 63,105,241,174, 62,200, 8,204, 63,109,192,177, 62,190,240,152, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 61,229,171,228,
+ 62,185, 42, 41, 61,202, 99,120, 62,190, 49,192, 61,145,152, 16, 62,179,214, 84, 61,208,226, 64, 62,172, 58,232, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63,114,143, 42, 62,207,168, 24, 63,110, 73, 56, 62,206,119,186, 63,108, 37, 51, 62,205, 3,249,
+ 63,114,125,203, 62,200,114, 96, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 61,202, 99,120, 62,190, 49,192, 61,179,234,244,
+ 62,190,219,240, 61,132, 85,184, 62,189,211, 22, 61,145,152, 16, 62,179,214, 84, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 63,113,134, 69, 62,212, 82,156, 63,109,191, 46, 62,210, 64, 92, 63,110, 73, 56, 62,206,119,186, 63,114,143, 42, 62,207,168, 24,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 61,179,234,244, 62,190,219,240, 61,181,129,196, 62,196, 14,204, 61,138,114, 60,
+ 62,197, 61, 28, 61,132, 85,184, 62,189,211, 22, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63,109, 27, 34, 62,214,254,155,
+ 63,109,191, 46, 62,210, 64, 92, 63,113,134, 69, 62,212, 82,156, 63,128, 0, 0, 63,128, 0, 0, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 61,138,114, 60, 62,197, 61, 28, 61,181,129,196, 62,196, 14,204, 61,184,174, 36, 62,202,130,216, 63,128, 0, 0,
+ 63,128, 0, 0, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63,110,190, 84, 62,172, 77,223, 63, 90, 5,151, 62,167, 61,138,
+ 63, 96, 25, 22, 62,149,248,246, 63,122,176,162, 62,161,215,145, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,128, 62, 54,234, 64,
+ 62,140,219,146, 62, 66,251,194, 62,158,102,163, 61,246, 66, 8, 62,152,161, 28, 61,189,241,172, 62,132,107, 13, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0, 0, 63,122, 12, 49, 62,197, 8,246, 63,110,190, 84, 62,172, 77,223, 63,122,176,162, 62,161,215,145,
+ 63,126,255,188, 62,198,248,115, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 64, 61,189,241,172, 62,132,107, 13, 61,246, 66, 8,
+ 62,152,161, 28, 61, 16, 54,240, 62,167, 4,120, 58,163, 8, 0, 62,162, 69, 39, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,128,
+ 63,119,115,183, 62,215, 49,140, 63,122, 12, 49, 62,197, 8,246, 63,126,255,188, 62,198,248,115, 63,122, 6, 47, 62,216,157,248,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 58,163, 8, 0, 62,162, 69, 39, 61, 16, 54,240, 62,167, 4,120, 60,231,111,224,
+ 62,198,142,100, 60, 14,248,224, 62,198,141, 70, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 16, 63,116, 76, 41, 62,222,153,139,
+ 63,119,115,183, 62,215, 49,140, 63,122, 6, 47, 62,216,157,248, 63,119, 98,134, 62,225, 37,204, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 0, 60, 14,248,224, 62,198,141, 70, 60,231,111,224, 62,198,142,100, 61, 73,183,128, 62,213,108, 84, 60,229,210, 80,
+ 62,218,239, 32, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 63,109,178, 31, 62,228, 68,224, 63,116, 76, 41, 62,222,153,139,
+ 63,119, 98,134, 62,225, 37,204, 63,115,185, 46, 62,234,157, 90, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,128, 60,229,210, 80,
+ 62,218,239, 32, 61, 73,183,128, 62,213,108, 84, 61,177, 27, 28, 62,219,240, 42, 61,122,103, 56, 62,230, 10, 30, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0,128, 63,102,178, 46, 62,232,184,100, 63,109,178, 31, 62,228, 68,224, 63,115,185, 46, 62,234,157, 90,
+ 63,106,134,244, 62,246, 64,234, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 64, 61,122,103, 56, 62,230, 10, 30, 61,177, 27, 28,
+ 62,219,240, 42, 61,242,216,120, 62,225, 40,124, 61,209,222,212, 62,240,123,238, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 16,
+ 63, 5,188,235, 63, 98, 74,252, 62,248,111,200, 63,112,105,197, 62,231, 49, 0, 63,107,190,118, 62,255, 57,150, 63, 96, 14, 53,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,240, 62, 95, 99, 80, 63, 94,194,149, 62, 62, 8, 58, 63, 89,154, 10, 62, 92, 24, 40,
+ 63, 74, 82, 14, 62,112, 11,112, 63, 78,133,157, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,240, 63, 5,188,235, 63, 98, 74,252,
+ 63, 12,139,136, 63,101,233,138, 63, 6, 45,116, 63,113,245,112, 62,248,111,200, 63,112,105,197, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0,240, 62, 36,219, 68, 63, 81,186,249, 62, 65,254, 28, 63, 70, 55, 20, 62, 92, 24, 40, 63, 74, 82, 14, 62, 62, 8, 58,
+ 63, 89,154, 10, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,240, 63, 12,139,136, 63,101,233,138, 63, 12,130, 5, 63,108,216,149,
+ 63, 6, 45,116, 63,113,245,112, 63,128, 0, 0, 63,128, 0, 0, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,112, 62, 36,219, 68,
+ 63, 81,186,249, 62, 42, 1, 76, 63, 73,178, 39, 62, 65,254, 28, 63, 70, 55, 20, 63,128, 0, 0, 63,128, 0, 0, 2,236,169, 32,
+ 1, 0, 0, 5, 0, 0, 0,112, 63,103, 89,120, 63, 2, 76,105, 63, 93,154,106, 62,233, 26,226, 63,102,178, 46, 62,232,184,100,
+ 63,106,134,244, 62,246, 64,234, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0, 61,242,216,120, 62,225, 40,124, 62, 33, 1,128,
+ 62,226,210, 70, 61,234,128,116, 63, 0, 39,200, 61,209,222,212, 62,240,123,238, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 0,
+ 62,245, 44,226, 63, 96,140,129, 62,255, 57,150, 63, 96, 14, 53, 62,231, 49, 0, 63,107,190,118, 62,227,135, 42, 63,101, 2, 58,
+ 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,240, 62, 95, 99, 80, 63, 94,194,149, 62,112, 11,112, 63, 78,133,157, 62,120, 84, 74,
+ 63, 83, 32,104, 62,122,103,110, 63, 92,255,236, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0,240, 63, 77,217,216, 62,157,228, 7,
+ 63, 90,225,160, 62,137,121,110, 63, 96, 25, 22, 62,149,248,246, 63, 90, 5,151, 62,167, 61,138, 2,236,169, 32, 1, 0, 0, 5,
+ 0, 0, 0, 16, 62, 54,234, 64, 62,140,219,146, 62, 74,125,166, 62,130, 30,252, 62,111,118,154, 62,152,108,120, 62, 66,251,194,
+ 62,158,102,163, 2,236,169, 32, 1, 0, 0, 5, 0, 0, 0, 64, 68, 65, 84, 65, 0, 0, 31, 64, 5, 31,232, 32, 0, 0, 0, 57,
+ 0, 0, 7,208,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 68, 65, 84, 65, 0, 0,117, 48, 8,170,144, 32, 0, 0, 0, 51, 0, 0, 1,244, 2,236,169, 32, 63, 28,112, 3,
+ 62,236,178,185, 63, 27,124,224, 62,232, 65,235, 63, 30, 63,144, 62,226,195,233, 63, 32,152,118, 62,236,167, 37,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32, 62,209,232, 2, 62,226, 21,222,
+ 62,215,109,102, 62,231,147,222, 62,213,135, 28, 62,236, 4,172, 62,205, 54, 56, 62,235,249, 22,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 61, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32, 63, 32,152,118, 62,236,167, 37, 63, 30, 63,144,
+ 62,226,195,233, 63, 33,235,108, 62,220,235,197, 63, 37,151,209, 62,236,161, 89,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32, 62,202,144, 76, 62,220, 61,186, 62,209,232, 2, 62,226, 21,222,
+ 62,205, 54, 56, 62,235,249, 22, 62,195, 55,128, 62,235,243, 70,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 61, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32, 63, 30, 63,144, 62,226,195,233, 63, 25, 55, 20, 62,223, 35, 1, 63, 25,178,200,
+ 62,214,233, 77, 63, 33,235,108, 62,220,235,197,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0,240, 2,236,169, 32, 62,219, 1,146, 62,214, 59, 66, 62,219,248,248, 62,222,116,246, 62,209,232, 2, 62,226, 21,222,
+ 62,202,144, 76, 62,220, 61,186,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 61, 0, 0, 5, 0, 0, 0,240,
+ 2,236,169, 32, 63, 27,124,224, 62,232, 65,235, 63, 24,252, 87, 62,230,111, 93, 63, 25, 55, 20, 62,223, 35, 1, 63, 30, 63,144,
+ 62,226,195,233,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32,
+ 62,219,248,248, 62,222,116,246, 62,220,110,118, 62,229,193, 78, 62,215,109,102, 62,231,147,222, 62,209,232, 2, 62,226, 21,222,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 61, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32, 63, 24,252, 87,
+ 62,230,111, 93, 63, 22,195, 22, 62,232, 90,195, 63, 20, 91,191, 62,227, 18,193, 63, 25, 55, 20, 62,223, 35, 1,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32, 62,229,175,162, 62,226,100,178,
+ 62,224,224,248, 62,231,172,182, 62,220,110,118, 62,229,193, 78, 62,219,248,248, 62,222,116,246,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 61, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32, 63, 25, 55, 20, 62,223, 35, 1, 63, 20, 91,191,
+ 62,227, 18,193, 63, 17,165,187, 62,221, 6,225, 63, 25,178,200, 62,214,233, 77,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32, 62,235, 27,170, 62,220, 88,214, 62,229,175,162, 62,226,100,178,
+ 62,219,248,248, 62,222,116,246, 62,219, 1,146, 62,214, 59, 66,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 61, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32, 63, 20, 91,191, 62,227, 18,193, 63, 18, 18,164, 62,236,201,173, 63, 13,231,157,
+ 62,236,161, 89, 63, 17,165,187, 62,221, 6,225,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0,240, 2,236,169, 32, 62,242,151,232, 62,235,243, 70, 62,234, 65,216, 62,236, 27,158, 62,229,175,162, 62,226,100,178,
+ 62,235, 27,170, 62,220, 88,214,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 61, 0, 0, 5, 0, 0, 0,240,
+ 2,236,169, 32, 63, 22,195, 22, 62,232, 90,195, 63, 21,202, 11, 62,236,189, 1, 63, 18, 18,164, 62,236,201,173, 63, 20, 91,191,
+ 62,227, 18,193,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32,
+ 62,234, 65,216, 62,236, 27,158, 62,226,211, 12, 62,236, 14,246, 62,224,224,248, 62,231,172,182, 62,229,175,162, 62,226,100,178,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 61, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32, 63, 21,202, 11,
+ 62,236,189, 1, 63, 22,202,215, 62,241,124,237, 63, 20,105,125, 62,246, 71, 1, 63, 18, 18,164, 62,236,201,173,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32, 62,229,148, 42, 62,245,152,246,
+ 62,224,209,112, 62,240,206,226, 62,226,211, 12, 62,236, 14,246, 62,234, 65,216, 62,236, 27,158,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 61, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32, 63, 18, 18,164, 62,236,201,173, 63, 20,105,125,
+ 62,246, 71, 1, 63, 17,173, 44, 62,252,149,231, 63, 13,231,157, 62,236,161, 89,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32, 62,235, 12,206, 62,251,231,218, 62,229,148, 42, 62,245,152,246,
+ 62,234, 65,216, 62,236, 27,158, 62,242,151,232, 62,235,243, 70,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 61, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32, 63, 20,105,125, 62,246, 71, 1, 63, 25, 59, 37, 62,250, 73, 49, 63, 25,178,108,
+ 63, 1,108,218, 63, 17,173, 44, 62,252,149,231,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0,240, 2,236,169, 32, 62,219, 2, 76, 63, 1, 21,213, 62,219,240,216, 62,249,155, 38, 62,229,148, 42, 62,245,152,246,
+ 62,235, 12,206, 62,251,231,218,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 61, 0, 0, 5, 0, 0, 0,240,
+ 2,236,169, 32, 63, 22,202,215, 62,241,124,237, 63, 25, 1,195, 62,243,102,169, 63, 25, 59, 37, 62,250, 73, 49, 63, 20,105,125,
+ 62,246, 71, 1,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32,
+ 62,219,240,216, 62,249,155, 38, 62,220, 99,156, 62,242,184,154, 62,224,209,112, 62,240,206,226, 62,229,148, 42, 62,245,152,246,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 61, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32, 63, 25, 1,195,
+ 62,243,102,169, 63, 27,125,176, 62,241,145,149, 63, 30, 74,167, 62,246,153, 3, 63, 25, 59, 37, 62,250, 73, 49,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32, 62,209,209,212, 62,245,234,246,
+ 62,215,107,192, 62,240,227,138, 62,220, 99,156, 62,242,184,154, 62,219,240,216, 62,249,155, 38,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 61, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32, 63, 25, 59, 37, 62,250, 73, 49, 63, 30, 74,167,
+ 62,246,153, 3, 63, 33,230,204, 62,252,232,107, 63, 25,178,108, 63, 1,108,218,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32, 62,202,153,132, 62,252, 58, 94, 62,209,209,212, 62,245,234,246,
+ 62,219,240,216, 62,249,155, 38, 62,219, 2, 76, 63, 1, 21,213,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 61, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32, 63, 30, 74,167, 62,246,153, 3, 63, 32,152,118, 62,236,167, 37, 63, 37,151,209,
+ 62,236,161, 89, 63, 33,230,204, 62,252,232,107,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0,240, 2,236,169, 32, 62,195, 55,128, 62,235,243, 70, 62,205, 54, 56, 62,235,249, 22, 62,209,209,212, 62,245,234,246,
+ 62,202,153,132, 62,252, 58, 94,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 61, 0, 0, 5, 0, 0, 0,240,
+ 2,236,169, 32, 63, 27,125,176, 62,241,145,149, 63, 28,112, 3, 62,236,178,185, 63, 32,152,118, 62,236,167, 37, 63, 30, 74,167,
+ 62,246,153, 3,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32,
+ 62,205, 54, 56, 62,235,249, 22, 62,213,135, 28, 62,236, 4,172, 62,215,107,192, 62,240,227,138, 62,209,209,212, 62,245,234,246,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 61, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32, 63, 28,112, 3,
+ 62,236,178,185, 63, 27,125,176, 62,241,145,149, 63, 27, 39, 42, 62,241, 1, 57, 63, 27,249,140, 62,236,186,115,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32, 62,216, 24,206, 62,240, 83, 46,
+ 62,215,107,192, 62,240,227,138, 62,213,135, 28, 62,236, 4,172, 62,214,116, 8, 62,236, 12,102,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 61, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32, 63, 27,125,176, 62,241,145,149, 63, 25, 1,195,
+ 62,243,102,169, 63, 24,248, 6, 62,242, 91,185, 63, 27, 39, 42, 62,241, 1, 57,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32, 62,220,119, 22, 62,241,173,174, 62,220, 99,156, 62,242,184,154,
+ 62,215,107,192, 62,240,227,138, 62,216, 24,206, 62,240, 83, 46,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 61, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32, 63, 25, 1,195, 62,243,102,169, 63, 22,202,215, 62,241,124,237, 63, 23, 38,157,
+ 62,240,173,225, 63, 24,248, 6, 62,242, 91,185,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0,240, 2,236,169, 32, 62,224, 25,234, 62,239,255,214, 62,224,209,112, 62,240,206,226, 62,220, 99,156, 62,242,184,154,
+ 62,220,119, 22, 62,241,173,174,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 61, 0, 0, 5, 0, 0, 0,240,
+ 2,236,169, 32, 63, 22,202,215, 62,241,124,237, 63, 21,202, 11, 62,236,189, 1, 63, 22, 89, 13, 62,236,196,247, 63, 23, 38,157,
+ 62,240,173,225,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32,
+ 62,225,181, 8, 62,236, 22,234, 62,226,211, 12, 62,236, 14,246, 62,224,209,112, 62,240,206,226, 62,224, 25,234, 62,239,255,214,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 61, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32, 63, 21,202, 11,
+ 62,236,189, 1, 63, 22,195, 22, 62,232, 90,195, 63, 23, 33, 88, 62,233, 47, 69, 63, 22, 89, 13, 62,236,196,247,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32, 62,224, 36,112, 62,232,129, 58,
+ 62,224,224,248, 62,231,172,182, 62,226,211, 12, 62,236, 14,246, 62,225,181, 8, 62,236, 22,234,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 61, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32, 63, 22,195, 22, 62,232, 90,195, 63, 24,252, 87,
+ 62,230,111, 93, 63, 24,243,100, 62,231,123, 5, 63, 23, 33, 88, 62,233, 47, 69,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32, 62,220,128, 90, 62,230,204,248, 62,220,110,118, 62,229,193, 78,
+ 62,224,224,248, 62,231,172,182, 62,224, 36,112, 62,232,129, 58,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 61, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32, 63, 24,252, 87, 62,230,111, 93, 63, 27,124,224, 62,232, 65,235, 63, 27, 37,169,
+ 62,232,211, 35, 63, 24,243,100, 62,231,123, 5,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0,240, 2,236,169, 32, 62,216, 27,206, 62,232, 37, 22, 62,215,109,102, 62,231,147,222, 62,220,110,118, 62,229,193, 78,
+ 62,220,128, 90, 62,230,204,248,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 61, 0, 0, 5, 0, 0, 0,240,
+ 2,236,169, 32, 63, 27,124,224, 62,232, 65,235, 63, 28,112, 3, 62,236,178,185, 63, 27,249,140, 62,236,186,115, 63, 27, 37,169,
+ 62,232,211, 35,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32,
+ 62,214,116, 8, 62,236, 12,102, 62,213,135, 28, 62,236, 4,172, 62,215,109,102, 62,231,147,222, 62,216, 27,206, 62,232, 37, 22,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 61, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32, 63, 24,242,138,
+ 62,236,194, 21, 63, 27, 37,169, 62,232,211, 35, 63, 27,249,140, 62,236,186,115, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0,112, 2,236,169, 32, 62,214,116, 8, 62,236, 12,102,
+ 62,216, 27,206, 62,232, 37, 22, 62,220,130, 16, 62,236, 20, 6, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 61, 0, 0, 5, 0, 0, 0,112, 2,236,169, 32, 63, 24,243,100, 62,231,123, 5, 63, 27, 37,169,
+ 62,232,211, 35, 63, 24,242,138, 62,236,194, 21, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0,112, 2,236,169, 32, 62,220,130, 16, 62,236, 20, 6, 62,216, 27,206, 62,232, 37, 22,
+ 62,220,128, 90, 62,230,204,248, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 61, 0, 0, 5, 0, 0, 0,112, 2,236,169, 32, 63, 24,242,138, 62,236,194, 21, 63, 23, 33, 88, 62,233, 47, 69, 63, 24,243,100,
+ 62,231,123, 5, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0,112, 2,236,169, 32, 62,220,128, 90, 62,230,204,248, 62,224, 36,112, 62,232,129, 58, 62,220,130, 16, 62,236, 20, 6,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 61, 0, 0, 5, 0, 0, 0,112,
+ 2,236,169, 32, 63, 24,242,138, 62,236,194, 21, 63, 22, 89, 13, 62,236,196,247, 63, 23, 33, 88, 62,233, 47, 69, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0,112, 2,236,169, 32,
+ 62,224, 36,112, 62,232,129, 58, 62,225,181, 8, 62,236, 22,234, 62,220,130, 16, 62,236, 20, 6, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 61, 0, 0, 5, 0, 0, 0,112, 2,236,169, 32, 63, 24,242,138,
+ 62,236,194, 21, 63, 23, 38,157, 62,240,173,225, 63, 22, 89, 13, 62,236,196,247, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0,112, 2,236,169, 32, 62,225,181, 8, 62,236, 22,234,
+ 62,224, 25,234, 62,239,255,214, 62,220,130, 16, 62,236, 20, 6, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 61, 0, 0, 5, 0, 0, 0,112, 2,236,169, 32, 63, 24,242,138, 62,236,194, 21, 63, 24,248, 6,
+ 62,242, 91,185, 63, 23, 38,157, 62,240,173,225, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0,112, 2,236,169, 32, 62,224, 25,234, 62,239,255,214, 62,220,119, 22, 62,241,173,174,
+ 62,220,130, 16, 62,236, 20, 6, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 61, 0, 0, 5, 0, 0, 0,112, 2,236,169, 32, 63, 24,242,138, 62,236,194, 21, 63, 27, 39, 42, 62,241, 1, 57, 63, 24,248, 6,
+ 62,242, 91,185, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0,112, 2,236,169, 32, 62,220,119, 22, 62,241,173,174, 62,216, 24,206, 62,240, 83, 46, 62,220,130, 16, 62,236, 20, 6,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 61, 0, 0, 5, 0, 0, 0,112,
+ 2,236,169, 32, 63, 24,242,138, 62,236,194, 21, 63, 27,249,140, 62,236,186,115, 63, 27, 39, 42, 62,241, 1, 57, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0,112, 2,236,169, 32,
+ 62,216, 24,206, 62,240, 83, 46, 62,214,116, 8, 62,236, 12,102, 62,220,130, 16, 62,236, 20, 6, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 61, 0, 0, 5, 0, 0, 0,112, 2,236,169, 32, 63, 16,254,174,
+ 62, 34, 45, 94, 63, 13,190, 79, 62, 46,193,160, 63, 3,199,220, 62, 24,219, 89, 63, 3,199,219, 61,229, 28, 18,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 16, 2,236,169, 32, 63, 3,199,220, 62, 24,219, 89,
+ 62,243,150, 14, 62, 47, 79,204, 62,236,248,140, 62, 34,202,182, 63, 3,199,219, 61,229, 28, 18,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 64, 2,236,169, 32, 63, 21,152,184, 62, 53, 47,182, 63, 16,104,250,
+ 62, 55,113, 16, 63, 13,190, 79, 62, 46,193,160, 63, 16,254,174, 62, 34, 45, 94,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0,128, 2,236,169, 32, 62,243,150, 14, 62, 47, 79,204, 62,238, 68,200, 62, 56, 62, 76,
+ 62,227,207,183, 62, 54, 75,250, 62,236,248,140, 62, 34,202,182,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0,128, 2,236,169, 32, 63, 22, 57,137, 62, 61, 93, 81, 63, 16,186,206, 62, 72,129, 85, 63, 16,104,250,
+ 62, 55,113, 16, 63, 21,152,184, 62, 53, 47,182,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 62,238, 68,200, 62, 56, 62, 76, 62,237,187,192, 62, 73,118,194, 62,226,152,122, 62, 62,166,190,
+ 62,227,207,183, 62, 54, 75,250,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63, 22,249,250, 62, 88,251,160, 63, 16, 32,222, 62, 93,106, 34, 63, 16,186,206, 62, 72,129, 85, 63, 22, 57,137,
+ 62, 61, 93, 81,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 62,237,187,192, 62, 73,118,194, 62,239, 19, 21, 62, 94,110,121, 62,225, 83, 90, 62, 90,153, 21, 62,226,152,122, 62, 62,166,190,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 25, 81, 20,
+ 62,132, 56, 17, 63, 15,243,206, 62,136,207,182, 63, 16, 32,222, 62, 93,106, 34, 63, 22,249,250, 62, 88,251,160,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,239, 19, 21, 62, 94,110,121,
+ 62,239,193, 92, 62,137, 61,113, 62,221, 42, 54, 62,133, 25,209, 62,225, 83, 90, 62, 90,153, 21,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 27,239,111, 62,166, 77,159, 63, 37, 94, 91,
+ 62,187,120,107, 63, 30, 21, 66, 62,200,139,178, 63, 12,237,158, 62,187,241, 38,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,211,125,139, 62,200,171,170, 62,197, 28,156, 62,187,130,166,
+ 62,216, 21,115, 62,166,177, 14, 62,245,175, 15, 62,188, 14,188,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 37, 94, 91, 62,187,120,107, 63, 43, 57, 87, 62,206, 58,222, 63, 39,163, 24,
+ 62,216, 95,174, 63, 30, 21, 66, 62,200,139,178,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 62,191,194, 98, 62,216, 94, 42, 62,184,207,130, 62,206, 27, 42, 62,197, 28,156, 62,187,130,166,
+ 62,211,125,139, 62,200,171,170,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63, 43, 57, 87, 62,206, 58,222, 63, 50,229, 38, 62,226, 32,169, 63, 43, 79,177, 62,231,194,202, 63, 39,163, 24,
+ 62,216, 95,174,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 62,183,201, 60, 62,231,218, 82, 62,168, 39,196, 62,226, 11,206, 62,184,207,130, 62,206, 27, 42, 62,191,194, 98, 62,216, 94, 42,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 50,229, 38,
+ 62,226, 32,169, 63, 48,134, 62, 62,249,107, 37, 63, 43,190,154, 62,249, 0,192, 63, 43, 79,177, 62,231,194,202,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,182,190,138, 62,249, 49, 35,
+ 62,172,229,172, 62,249,127,116, 62,168, 39,196, 62,226, 11,206, 62,183,201, 60, 62,231,218, 82,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 48,134, 62, 62,249,107, 37, 63, 46, 88,238,
+ 63, 2,223,146, 63, 40,207,123, 62,254,175,218, 63, 43,190,154, 62,249, 0,192,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,188,184, 2, 62,255, 0,140, 62,177, 87,173, 63, 3, 9,102,
+ 62,172,229,172, 62,249,127,116, 62,182,190,138, 62,249, 49, 35,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 46, 88,238, 63, 2,223,146, 63, 34,158,220, 63, 10, 23,175, 63, 30, 77,126,
+ 63, 5, 88,156, 63, 40,207,123, 62,254,175,218,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 62,210, 65, 89, 63, 5,158, 56, 62,201,109,124, 63, 10,121, 72, 62,177, 87,173, 63, 3, 9,102,
+ 62,188,184, 2, 62,255, 0,140,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63, 34,158,220, 63, 10, 23,175, 63, 26,105, 28, 63, 11,194,242, 63, 25,120,244, 63, 7,242, 78, 63, 30, 77,126,
+ 63, 5, 88,156,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 62,220, 39, 0, 63, 8, 58,252, 62,218, 73,220, 63, 12, 31,169, 62,201,109,124, 63, 10,121, 72, 62,210, 65, 89, 63, 5,158, 56,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 26,105, 28,
+ 63, 11,194,242, 63, 22,244,173, 63, 11,215,236, 63, 22, 47,202, 63, 8, 60,156, 63, 25,120,244, 63, 7,242, 78,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,226,221, 11, 63, 8,125, 90,
+ 62,225, 89,220, 63, 12, 42, 77, 62,218, 73,220, 63, 12, 31,169, 62,220, 39, 0, 63, 8, 58,252,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 22,244,173, 63, 11,215,236, 63, 11,169, 67,
+ 63, 11,197, 18, 63, 12,252,106, 63, 3,173,180, 63, 22, 47,202, 63, 8, 60,156,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,245,114, 35, 63, 3,196,233, 62,248, 72, 55, 63, 11,232, 91,
+ 62,225, 89,220, 63, 12, 42, 77, 62,226,221, 11, 63, 8,125, 90,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 11,169, 67, 63, 11,197, 18, 63, 3,232,148, 63, 11, 17,164, 63, 3,220,162,
+ 63, 0, 88, 45, 63, 12,252,106, 63, 3,173,180,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 63, 3,220,162, 63, 0, 88, 45, 63, 3,232,148, 63, 11, 17,164, 62,248, 72, 55, 63, 11,232, 91,
+ 62,245,114, 35, 63, 3,196,233,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63, 17, 59,103, 62,255,195,120, 63, 22, 81,240, 63, 1, 70,114, 63, 22, 47,202, 63, 8, 60,156, 63, 12,252,106,
+ 63, 3,173,180,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 62,226,221, 11, 63, 8,125, 90, 62,226,128,106, 63, 1,111,198, 62,236,213,209, 62,255,250, 4, 62,245,114, 35, 63, 3,196,233,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 22, 81,240,
+ 63, 1, 70,114, 63, 25,182,151, 63, 1, 9,130, 63, 25,120,244, 63, 7,242, 78, 63, 22, 47,202, 63, 8, 60,156,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,220, 39, 0, 63, 8, 58,252,
+ 62,219,150,213, 63, 1, 55, 50, 62,226,128,106, 63, 1,111,198, 62,226,221, 11, 63, 8,125, 90,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 30, 49, 96, 62,254,229,121, 63, 30, 77,126,
+ 63, 5, 88,156, 63, 25,120,244, 63, 7,242, 78, 63, 25,182,151, 63, 1, 9,130,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,220, 39, 0, 63, 8, 58,252, 62,210, 65, 89, 63, 5,158, 56,
+ 62,210,116,176, 62,255, 62,227, 62,219,150,213, 63, 1, 55, 50,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 37,113, 25, 62,247,157, 35, 63, 40,207,123, 62,254,175,218, 63, 30, 77,126,
+ 63, 5, 88,156, 63, 30, 49, 96, 62,254,229,121,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 62,210, 65, 89, 63, 5,158, 56, 62,188,184, 2, 62,255, 0,140, 62,195,165,189, 62,247,232,139,
+ 62,210,116,176, 62,255, 62,227,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63, 39, 62, 92, 62,240, 75,121, 63, 43,190,154, 62,249, 0,192, 63, 40,207,123, 62,254,175,218, 63, 37,113, 25,
+ 62,247,157, 35,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 62,188,184, 2, 62,255, 0,140, 62,182,190,138, 62,249, 49, 35, 62,192, 10,222, 62,240,128,163, 62,195,165,189, 62,247,232,139,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 38,149,140,
+ 62,229, 95, 38, 63, 43, 79,177, 62,231,194,202, 63, 43,190,154, 62,249, 0,192, 63, 39, 62, 92, 62,240, 75,121,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,182,190,138, 62,249, 49, 35,
+ 62,183,201, 60, 62,231,218, 82, 62,193,140,168, 62,229,129, 94, 62,192, 10,222, 62,240,128,163,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 33,120, 14, 62,214,238,166, 63, 39,163, 24,
+ 62,216, 95,174, 63, 43, 79,177, 62,231,194,202, 63, 38,149,140, 62,229, 95, 38,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,183,201, 60, 62,231,218, 82, 62,191,194, 98, 62,216, 94, 42,
+ 62,204, 75,168, 62,215, 7, 62, 62,193,140,168, 62,229,129, 94,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 27,178,165, 62,208, 17,128, 63, 30, 21, 66, 62,200,139,178, 63, 39,163, 24,
+ 62,216, 95,174, 63, 33,120, 14, 62,214,238,166,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 62,191,194, 98, 62,216, 94, 42, 62,211,125,139, 62,200,171,170, 62,216, 24, 6, 62,208, 57,128,
+ 62,204, 75,168, 62,215, 7, 62,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63, 17, 97, 15, 62,214, 34,220, 63, 12,237,158, 62,187,241, 38, 63, 30, 21, 66, 62,200,139,178, 63, 27,178,165,
+ 62,208, 17,128,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 62,211,125,139, 62,200,171,170, 62,245,175, 15, 62,188, 14,188, 62,236,200,217, 62,214, 49,134, 62,216, 24, 6, 62,208, 57,128,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 17, 97, 15,
+ 62,214, 34,220, 63, 14,244,149, 62,221, 42, 4, 63, 3,230,147, 62,208, 47, 78, 63, 12,237,158, 62,187,241, 38,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 3,230,147, 62,208, 47, 78,
+ 62,241,144,141, 62,221, 52,244, 62,236,200,217, 62,214, 49,134, 62,245,175, 15, 62,188, 14,188,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 17, 59,103, 62,255,195,120, 63, 12,252,106,
+ 63, 3,173,180, 63, 3,220,162, 63, 0, 88, 45, 63, 13, 25, 71, 62,243,163,116,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 3,220,162, 63, 0, 88, 45, 62,245,114, 35, 63, 3,196,233,
+ 62,236,213,209, 62,255,250, 4, 62,245, 45, 0, 62,243,185,206,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 13, 25, 71, 62,243,163,116, 63, 3,220,162, 63, 0, 88, 45, 63, 3,220,215,
+ 62,231,189,148, 63, 13, 2, 64, 62,230,215, 52,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 63, 3,220,215, 62,231,189,148, 63, 3,220,162, 63, 0, 88, 45, 62,245, 45, 0, 62,243,185,206,
+ 62,245,100,219, 62,230,230,184,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63, 3,230,147, 62,208, 47, 78, 63, 14,244,149, 62,221, 42, 4, 63, 13, 2, 64, 62,230,215, 52, 63, 3,220,215,
+ 62,231,189,148,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 62,245,100,219, 62,230,230,184, 62,241,144,141, 62,221, 52,244, 63, 3,230,147, 62,208, 47, 78, 63, 3,220,215, 62,231,189,148,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 7, 61,250,
+ 62, 54, 31,148, 63, 3,202,193, 62, 49,174,214, 63, 3,199,220, 62, 24,219, 89, 63, 13,190, 79, 62, 46,193,160,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 3,199,220, 62, 24,219, 89,
+ 63, 3,202,193, 62, 49,174,214, 63, 0, 87,175, 62, 54, 90,251, 62,243,150, 14, 62, 47, 79,204,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 9,214, 68, 62, 66,237,246, 63, 7, 61,250,
+ 62, 54, 31,148, 63, 13,190, 79, 62, 46,193,160, 63, 16,104,250, 62, 55,113, 16,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,243,150, 14, 62, 47, 79,204, 63, 0, 87,175, 62, 54, 90,251,
+ 62,251,137,104, 62, 67, 92,179, 62,238, 68,200, 62, 56, 62, 76,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 8,221,237, 62, 91, 90,218, 63, 9,214, 68, 62, 66,237,246, 63, 16,104,250,
+ 62, 55,113, 16, 63, 16,186,206, 62, 72,129, 85,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 62,238, 68,200, 62, 56, 62, 76, 62,251,137,104, 62, 67, 92,179, 62,253,153, 39, 62, 91,195, 27,
+ 62,237,187,192, 62, 73,118,194,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63, 15,243,206, 62,136,207,182, 63, 8, 32, 77, 62,139, 39, 10, 63, 9,117, 22, 62, 97,203,146, 63, 16, 32,222,
+ 62, 93,106, 34,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 62,252,110,192, 62, 98, 68, 79, 62,255, 89,219, 62,139, 79,116, 62,239,193, 92, 62,137, 61,113, 62,239, 19, 21, 62, 94,110,121,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 8,221,237,
+ 62, 91, 90,218, 63, 16,186,206, 62, 72,129, 85, 63, 16, 32,222, 62, 93,106, 34, 63, 9,117, 22, 62, 97,203,146,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,239, 19, 21, 62, 94,110,121,
+ 62,237,187,192, 62, 73,118,194, 62,253,153, 39, 62, 91,195, 27, 62,252,110,192, 62, 98, 68, 79,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 9,125,119, 62,158,112, 7, 63, 3,233, 70,
+ 62,154, 27, 88, 63, 3,229,235, 62,139,108, 97, 63, 8, 32, 77, 62,139, 39, 10,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 3,229,235, 62,139,108, 97, 63, 3,233, 70, 62,154, 27, 88,
+ 62,252,179,165, 62,158,140,163, 62,255, 89,219, 62,139, 79,116,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 9,117, 22, 62, 97,203,146, 63, 8, 32, 77, 62,139, 39, 10, 63, 3,229,235,
+ 62,139,108, 97, 63, 3,215,246, 62,101, 56,143,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 63, 3,229,235, 62,139,108, 97, 62,255, 89,219, 62,139, 79,116, 62,252,110,192, 62, 98, 68, 79,
+ 63, 3,215,246, 62,101, 56,143,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63, 3,210,147, 62, 86, 95,221, 63, 8,221,237, 62, 91, 90,218, 63, 9,117, 22, 62, 97,203,146, 63, 3,215,246,
+ 62,101, 56,143,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 62,252,110,192, 62, 98, 68, 79, 62,253,153, 39, 62, 91,195, 27, 63, 3,210,147, 62, 86, 95,221, 63, 3,215,246, 62,101, 56,143,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 12, 54, 5,
+ 62,167,183,188, 63, 9, 61,250, 62,168,214,252, 63, 8,143,152, 62,163,107, 45, 63, 9,125,119, 62,158,112, 7,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,254,136,100, 62,163,123, 38,
+ 62,253, 39,110, 62,168,224,103, 62,247, 68, 98, 62,167,206,146, 62,252,179,165, 62,158,140,163,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 10,196,135, 62,178,208, 52, 63, 8,233, 25,
+ 62,175,110,116, 63, 9, 61,250, 62,168,214,252, 63, 12, 54, 5, 62,167,183,188,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,253, 39,110, 62,168,224,103, 62,253,195,102, 62,175,102,184,
+ 62,250, 14, 98, 62,178,202,149, 62,247, 68, 98, 62,167,206,146,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 4, 17, 69, 62,182,176,105, 63, 6,138, 69, 62,177,180, 80, 63, 8,233, 25,
+ 62,175,110,116, 63, 10,196,135, 62,178,208, 52,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 62,253,195,102, 62,175,102,184, 63, 1, 49, 14, 62,177,150, 62, 63, 4, 17, 69, 62,182,176,105,
+ 62,250, 14, 98, 62,178,202,149,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63, 3,124,209, 62,177, 0, 70, 63, 3,232, 11, 62,174, 4,140, 63, 6,138, 69, 62,177,180, 80, 63, 4, 17, 69,
+ 62,182,176,105,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 63, 1, 49, 14, 62,177,150, 62, 63, 3,232, 11, 62,174, 4,140, 63, 3,124,209, 62,177, 0, 70, 63, 4, 17, 69, 62,182,176,105,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 3,233, 70,
+ 62,154, 27, 88, 63, 9,125,119, 62,158,112, 7, 63, 8,143,152, 62,163,107, 45, 63, 3,232,212, 62,158,152, 58,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,254,136,100, 62,163,123, 38,
+ 62,252,179,165, 62,158,140,163, 63, 3,233, 70, 62,154, 27, 88, 63, 3,232,212, 62,158,152, 58,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 3,232,212, 62,158,152, 58, 63, 8,143,152,
+ 62,163,107, 45, 63, 7, 91,121, 62,166, 51,134, 63, 3,231,205, 62,162,149, 58,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 0,116, 44, 62,166, 56,255, 62,254,136,100, 62,163,123, 38,
+ 63, 3,232,212, 62,158,152, 58, 63, 3,231,205, 62,162,149, 58,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 3,232, 11, 62,174, 4,140, 63, 3,233,214, 62,170,154,198, 63, 6,110,233,
+ 62,174,152, 94, 63, 6,138, 69, 62,177,180, 80,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 63, 1, 82,228, 62,174,140, 95, 63, 3,233,214, 62,170,154,198, 63, 3,232, 11, 62,174, 4,140,
+ 63, 1, 49, 14, 62,177,150, 62,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63, 6,138, 69, 62,177,180, 80, 63, 6,110,233, 62,174,152, 94, 63, 7,236, 59, 62,173,123, 19, 63, 8,233, 25,
+ 62,175,110,116,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 62,255,185,217, 62,173,116, 92, 63, 1, 82,228, 62,174,140, 95, 63, 1, 49, 14, 62,177,150, 62, 62,253,195,102, 62,175,102,184,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 8,233, 25,
+ 62,175,110,116, 63, 7,236, 59, 62,173,123, 19, 63, 7,249, 85, 62,169, 52, 92, 63, 9, 61,250, 62,168,214,252,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,255,169,160, 62,169, 57, 6,
+ 62,255,185,217, 62,173,116, 92, 62,253,195,102, 62,175,102,184, 62,253, 39,110, 62,168,224,103,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 9, 61,250, 62,168,214,252, 63, 7,249, 85,
+ 62,169, 52, 92, 63, 7, 91,121, 62,166, 51,134, 63, 8,143,152, 62,163,107, 45,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 0,116, 44, 62,166, 56,255, 62,255,169,160, 62,169, 57, 6,
+ 62,253, 39,110, 62,168,224,103, 62,254,136,100, 62,163,123, 38,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 3,233,214, 62,170,154,198, 63, 7,249, 85, 62,169, 52, 92, 63, 7,236, 59,
+ 62,173,123, 19, 63, 6,110,233, 62,174,152, 94,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 62,255,185,217, 62,173,116, 92, 62,255,169,160, 62,169, 57, 6, 63, 3,233,214, 62,170,154,198,
+ 63, 1, 82,228, 62,174,140, 95,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63, 3,233,214, 62,170,154,198, 63, 3,231,205, 62,162,149, 58, 63, 7, 91,121, 62,166, 51,134, 63, 7,249, 85,
+ 62,169, 52, 92,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 63, 0,116, 44, 62,166, 56,255, 63, 3,231,205, 62,162,149, 58, 63, 3,233,214, 62,170,154,198, 62,255,169,160, 62,169, 57, 6,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 4, 17, 69,
+ 62,182,176,105, 63, 10,196,135, 62,178,208, 52, 63, 12,237,158, 62,187,241, 38, 63, 3,230,147, 62,208, 47, 78,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,245,175, 15, 62,188, 14,188,
+ 62,250, 14, 98, 62,178,202,149, 63, 4, 17, 69, 62,182,176,105, 63, 3,230,147, 62,208, 47, 78,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 10,196,135, 62,178,208, 52, 63, 12, 54, 5,
+ 62,167,183,188, 63, 16, 0,112, 62,164,246,254, 63, 12,237,158, 62,187,241, 38,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,239,187,207, 62,165, 42, 19, 62,247, 68, 98, 62,167,206,146,
+ 62,250, 14, 98, 62,178,202,149, 62,245,175, 15, 62,188, 14,188,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 12, 54, 5, 62,167,183,188, 63, 9,125,119, 62,158,112, 7, 63, 15,250, 44,
+ 62,154, 0,109, 63, 16, 0,112, 62,164,246,254,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 62,239,205, 56, 62,154, 71, 8, 62,252,179,165, 62,158,140,163, 62,247, 68, 98, 62,167,206,146,
+ 62,239,187,207, 62,165, 42, 19,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63, 9,125,119, 62,158,112, 7, 63, 8, 32, 77, 62,139, 39, 10, 63, 15,243,206, 62,136,207,182, 63, 15,250, 44,
+ 62,154, 0,109,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 62,239,193, 92, 62,137, 61,113, 62,255, 89,219, 62,139, 79,116, 62,252,179,165, 62,158,140,163, 62,239,205, 56, 62,154, 71, 8,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 25, 81, 20,
+ 62,132, 56, 17, 63, 27, 46,208, 62,148, 35,149, 63, 15,250, 44, 62,154, 0,109, 63, 15,243,206, 62,136,207,182,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,239,205, 56, 62,154, 71, 8,
+ 62,217,166,238, 62,148,221,229, 62,221, 42, 54, 62,133, 25,209, 62,239,193, 92, 62,137, 61,113,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 27, 46,208, 62,148, 35,149, 63, 27,177, 36,
+ 62,156,151,158, 63, 16, 0,112, 62,164,246,254, 63, 15,250, 44, 62,154, 0,109,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,239,187,207, 62,165, 42, 19, 62,216,160, 0, 62,157, 44,127,
+ 62,217,166,238, 62,148,221,229, 62,239,205, 56, 62,154, 71, 8,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 27,239,111, 62,166, 77,159, 63, 12,237,158, 62,187,241, 38, 63, 16, 0,112,
+ 62,164,246,254, 63, 27,177, 36, 62,156,151,158,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 62,239,187,207, 62,165, 42, 19, 62,245,175, 15, 62,188, 14,188, 62,216, 21,115, 62,166,177, 14,
+ 62,216,160, 0, 62,157, 44,127,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63, 8,221,237, 62, 91, 90,218, 63, 3,210,147, 62, 86, 95,221, 63, 3,211,129, 62, 83,168,248, 63, 8, 33,170,
+ 62, 86,149,254,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 63, 3,211,129, 62, 83,168,248, 63, 3,210,147, 62, 86, 95,221, 62,253,153, 39, 62, 91,195, 27, 62,255, 14, 8, 62, 86,232, 58,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 9,214, 68,
+ 62, 66,237,246, 63, 8,221,237, 62, 91, 90,218, 63, 8, 33,170, 62, 86,149,254, 63, 8,180, 20, 62, 69, 29, 94,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,255, 14, 8, 62, 86,232, 58,
+ 62,253,153, 39, 62, 91,195, 27, 62,251,137,104, 62, 67, 92,179, 62,253,210, 19, 62, 69,114, 55,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 7, 61,250, 62, 54, 31,148, 63, 9,214, 68,
+ 62, 66,237,246, 63, 8,180, 20, 62, 69, 29, 94, 63, 6, 82,168, 62, 57, 43, 80,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,253,210, 19, 62, 69,114, 55, 62,251,137,104, 62, 67, 92,179,
+ 63, 0, 87,175, 62, 54, 90,251, 63, 1, 68, 48, 62, 57, 84,166,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 3,202,193, 62, 49,174,214, 63, 7, 61,250, 62, 54, 31,148, 63, 6, 82,168,
+ 62, 57, 43, 80, 63, 3,202,205, 62, 54, 22, 8,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 63, 1, 68, 48, 62, 57, 84,166, 63, 0, 87,175, 62, 54, 90,251, 63, 3,202,193, 62, 49,174,214,
+ 63, 3,202,205, 62, 54, 22, 8,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63, 3,202,205, 62, 54, 22, 8, 63, 6, 82,168, 62, 57, 43, 80, 63, 5, 24,246, 62, 66,150, 26, 63, 3,205,213,
+ 62, 64,232,220,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 63, 2,131, 29, 62, 66,172, 22, 63, 1, 68, 48, 62, 57, 84,166, 63, 3,202,205, 62, 54, 22, 8, 63, 3,205,213, 62, 64,232,220,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 6, 82,168,
+ 62, 57, 43, 80, 63, 8,180, 20, 62, 69, 29, 94, 63, 6, 83, 39, 62, 70,114,191, 63, 5, 24,246, 62, 66,150, 26,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 1, 75,185, 62, 70,160,222,
+ 62,253,210, 19, 62, 69,114, 55, 63, 1, 68, 48, 62, 57, 84,166, 63, 2,131, 29, 62, 66,172, 22,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 8,180, 20, 62, 69, 29, 94, 63, 8, 33,170,
+ 62, 86,149,254, 63, 6,111, 4, 62, 76,172, 40, 63, 6, 83, 39, 62, 70,114,191,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 1, 51,157, 62, 76,218,158, 62,255, 14, 8, 62, 86,232, 58,
+ 62,253,210, 19, 62, 69,114, 55, 63, 1, 75,185, 62, 70,160,222,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 8, 33,170, 62, 86,149,254, 63, 3,211,129, 62, 83,168,248, 63, 3,208,234,
+ 62, 75, 43,146, 63, 6,111, 4, 62, 76,172, 40,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 63, 3,208,234, 62, 75, 43,146, 63, 3,211,129, 62, 83,168,248, 62,255, 14, 8, 62, 86,232, 58,
+ 63, 1, 51,157, 62, 76,218,158,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63, 3,208,234, 62, 75, 43,146, 63, 3,205,213, 62, 64,232,220, 63, 5, 24,246, 62, 66,150, 26, 63, 6,111, 4,
+ 62, 76,172, 40,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 63, 2,131, 29, 62, 66,172, 22, 63, 3,205,213, 62, 64,232,220, 63, 3,208,234, 62, 75, 43,146, 63, 1, 51,157, 62, 76,218,158,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 6,111, 4,
+ 62, 76,172, 40, 63, 5, 24,246, 62, 66,150, 26, 63, 6, 83, 39, 62, 70,114,191, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 1, 75,185, 62, 70,160,222,
+ 63, 2,131, 29, 62, 66,172, 22, 63, 1, 51,157, 62, 76,218,158, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 13, 2, 64, 62,230,215, 52, 63, 14,244,149,
+ 62,221, 42, 4, 63, 16,216, 4, 62,224, 24,160, 63, 15,200,120, 62,231,255, 84,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,237,193,119, 62,224, 38,190, 62,241,144,141, 62,221, 52,244,
+ 62,245,100,219, 62,230,230,184, 62,239,211, 21, 62,232, 18,185,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 13, 25, 71, 62,243,163,116, 63, 13, 2, 64, 62,230,215, 52, 63, 15,200,120,
+ 62,231,255, 84, 63, 16,171,184, 62,241,133, 40,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 62,239,211, 21, 62,232, 18,185, 62,245,100,219, 62,230,230,184, 62,245, 45, 0, 62,243,185,206,
+ 62,237,252,218, 62,241,160, 62,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63, 17, 59,103, 62,255,195,120, 63, 13, 25, 71, 62,243,163,116, 63, 16,171,184, 62,241,133, 40, 63, 19, 44, 55,
+ 62,250, 21, 86,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 62,237,252,218, 62,241,160, 62, 62,245, 45, 0, 62,243,185,206, 62,236,213,209, 62,255,250, 4, 62,232,228,153, 62,250, 67,154,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 14,244,149,
+ 62,221, 42, 4, 63, 17, 97, 15, 62,214, 34,220, 63, 19, 53,217, 62,218,211, 16, 63, 16,216, 4, 62,224, 24,160,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,233, 14, 8, 62,218,226, 66,
+ 62,236,200,217, 62,214, 49,134, 62,241,144,141, 62,221, 52,244, 62,237,193,119, 62,224, 38,190,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 17, 97, 15, 62,214, 34,220, 63, 27,178,165,
+ 62,208, 17,128, 63, 26,198,205, 62,214,184,124, 63, 19, 53,217, 62,218,211, 16,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,217,214,216, 62,214,224,218, 62,216, 24, 6, 62,208, 57,128,
+ 62,236,200,217, 62,214, 49,134, 62,233, 14, 8, 62,218,226, 66,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 27,178,165, 62,208, 17,128, 63, 33,120, 14, 62,214,238,166, 63, 31,136,156,
+ 62,219,138,194, 63, 26,198,205, 62,214,184,124,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 62,208, 30,254, 62,219,177,204, 62,204, 75,168, 62,215, 7, 62, 62,216, 24, 6, 62,208, 57,128,
+ 62,217,214,216, 62,214,224,218,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63, 33,120, 14, 62,214,238,166, 63, 38,149,140, 62,229, 95, 38, 63, 36, 9, 79, 62,229,224, 94, 63, 31,136,156,
+ 62,219,138,194,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 62,198,192,148, 62,230, 11,182, 62,193,140,168, 62,229,129, 94, 62,204, 75,168, 62,215, 7, 62, 62,208, 30,254, 62,219,177,204,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 38,149,140,
+ 62,229, 95, 38, 63, 39, 62, 92, 62,240, 75,121, 63, 36, 49, 14, 62,239, 88,253, 63, 36, 9, 79, 62,229,224, 94,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,198, 71, 97, 62,239,149,192,
+ 62,192, 10,222, 62,240,128,163, 62,193,140,168, 62,229,129, 94, 62,198,192,148, 62,230, 11,182,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 39, 62, 92, 62,240, 75,121, 63, 37,113, 25,
+ 62,247,157, 35, 63, 35, 33,243, 62,245,143, 80, 63, 36, 49, 14, 62,239, 88,253,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,200, 99, 87, 62,245,217,172, 62,195,165,189, 62,247,232,139,
+ 62,192, 10,222, 62,240,128,163, 62,198, 71, 97, 62,239,149,192,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 37,113, 25, 62,247,157, 35, 63, 30, 49, 96, 62,254,229,121, 63, 29, 49,223,
+ 62,250,140,199, 63, 35, 33,243, 62,245,143, 80,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 62,212,124,147, 62,250,215,146, 62,210,116,176, 62,255, 62,227, 62,195,165,189, 62,247,232,139,
+ 62,200, 99, 87, 62,245,217,172,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63, 30, 49, 96, 62,254,229,121, 63, 25,182,151, 63, 1, 9,130, 63, 25,181, 50, 62,253,111,118, 63, 29, 49,223,
+ 62,250,140,199,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 62,219,151, 52, 62,253,186, 68, 62,219,150,213, 63, 1, 55, 50, 62,210,116,176, 62,255, 62,227, 62,212,124,147, 62,250,215,146,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 25,182,151,
+ 63, 1, 9,130, 63, 22, 81,240, 63, 1, 70,114, 63, 22,188,241, 62,253,149, 28, 63, 25,181, 50, 62,253,111,118,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,225,163,212, 62,253,215, 91,
+ 62,226,128,106, 63, 1,111,198, 62,219,150,213, 63, 1, 55, 50, 62,219,151, 52, 62,253,186, 68,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 22, 81,240, 63, 1, 70,114, 63, 17, 59,103,
+ 62,255,195,120, 63, 19, 44, 55, 62,250, 21, 86, 63, 22,188,241, 62,253,149, 28,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,232,228,153, 62,250, 67,154, 62,236,213,209, 62,255,250, 4,
+ 62,226,128,106, 63, 1,111,198, 62,225,163,212, 62,253,215, 91,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 22,188,241, 62,253,149, 28, 63, 19, 44, 55, 62,250, 21, 86, 63, 20,165, 9,
+ 62,247, 99,248, 63, 23, 0, 20, 62,251, 57, 6,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 62,229,232,232, 62,247,142, 74, 62,232,228,153, 62,250, 67,154, 62,225,163,212, 62,253,215, 91,
+ 62,225, 26,145, 62,251,116,114,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63, 25,181, 50, 62,253,111,118, 63, 22,188,241, 62,253,149, 28, 63, 23, 0, 20, 62,251, 57, 6, 63, 25,144,130,
+ 62,251, 7,128,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 62,225, 26,145, 62,251,116,114, 62,225,163,212, 62,253,215, 91, 62,219,151, 52, 62,253,186, 68, 62,219,225,177, 62,251, 75, 67,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 29, 49,223,
+ 62,250,140,199, 63, 25,181, 50, 62,253,111,118, 63, 25,144,130, 62,251, 7,128, 63, 28,195, 80, 62,248,166, 55,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,219,225,177, 62,251, 75, 67,
+ 62,219,151, 52, 62,253,186, 68, 62,212,124,147, 62,250,215,146, 62,213, 95,233, 62,248,237, 20,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 35, 33,243, 62,245,143, 80, 63, 29, 49,223,
+ 62,250,140,199, 63, 28,195, 80, 62,248,166, 55, 63, 33,164, 22, 62,243, 75,102,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,213, 95,233, 62,248,237, 20, 62,212,124,147, 62,250,215,146,
+ 62,200, 99, 87, 62,245,217,172, 62,203,114, 65, 62,243,143,159,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 36, 49, 14, 62,239, 88,253, 63, 35, 33,243, 62,245,143, 80, 63, 33,164, 22,
+ 62,243, 75,102, 63, 34,160, 30, 62,238, 47,169,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 62,203,114, 65, 62,243,143,159, 62,200, 99, 87, 62,245,217,172, 62,198, 71, 97, 62,239,149,192,
+ 62,201,128,188, 62,238,110,126,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63, 36, 9, 79, 62,229,224, 94, 63, 36, 49, 14, 62,239, 88,253, 63, 34,160, 30, 62,238, 47,169, 63, 34,144,131,
+ 62,231, 87,253,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 62,201,128,188, 62,238,110,126, 62,198, 71, 97, 62,239,149,192, 62,198,192,148, 62,230, 11,182, 62,201,190,141, 62,231,140,124,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 31,136,156,
+ 62,219,138,194, 63, 36, 9, 79, 62,229,224, 94, 63, 34,144,131, 62,231, 87,253, 63, 30,208, 21, 62,221,182,174,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,201,190,141, 62,231,140,124,
+ 62,198,192,148, 62,230, 11,182, 62,208, 30,254, 62,219,177,204, 62,209,133,168, 62,221,221, 51,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 26,198,205, 62,214,184,124, 63, 31,136,156,
+ 62,219,138,194, 63, 30,208, 21, 62,221,182,174, 63, 26,218,128, 62,217,206, 68,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,209,133,168, 62,221,221, 51, 62,208, 30,254, 62,219,177,204,
+ 62,217,214,216, 62,214,224,218, 62,217,157, 11, 62,217,243, 64,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 19, 53,217, 62,218,211, 16, 63, 26,198,205, 62,214,184,124, 63, 26,218,128,
+ 62,217,206, 68, 63, 20, 53,103, 62,221, 84,236,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 62,217,157, 11, 62,217,243, 64, 62,217,214,216, 62,214,224,218, 62,233, 14, 8, 62,218,226, 66,
+ 62,231, 5, 68, 62,221,101,234,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63, 16,216, 4, 62,224, 24,160, 63, 19, 53,217, 62,218,211, 16, 63, 20, 53,103, 62,221, 84,236, 63, 18, 87, 81,
+ 62,226,175, 33,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 62,231, 5, 68, 62,221,101,234, 62,233, 14, 8, 62,218,226, 66, 62,237,193,119, 62,224, 38,190, 62,234,187,180, 62,226,190,249,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 19, 44, 55,
+ 62,250, 21, 86, 63, 16,171,184, 62,241,133, 40, 63, 18, 68, 98, 62,240,197,150, 63, 20,165, 9, 62,247, 99,248,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,234,197, 35, 62,240,226,215,
+ 62,237,252,218, 62,241,160, 62, 62,232,228,153, 62,250, 67,154, 62,229,232,232, 62,247,142, 74,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 16,171,184, 62,241,133, 40, 63, 15,200,120,
+ 62,231,255, 84, 63, 18, 4,161, 62,232,184,138, 63, 18, 68, 98, 62,240,197,150,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,235, 85,154, 62,232,206, 92, 62,239,211, 21, 62,232, 18,185,
+ 62,237,252,218, 62,241,160, 62, 62,234,197, 35, 62,240,226,215,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 15,200,120, 62,231,255, 84, 63, 16,216, 4, 62,224, 24,160, 63, 18, 87, 81,
+ 62,226,175, 33, 63, 18, 4,161, 62,232,184,138,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 62,234,187,180, 62,226,190,249, 62,237,193,119, 62,224, 38,190, 62,239,211, 21, 62,232, 18,185,
+ 62,235, 85,154, 62,232,206, 92,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63, 3,232,148, 63, 11, 17,164, 63, 11,169, 67, 63, 11,197, 18, 63, 13,120,216, 63, 23, 81,160, 63, 4, 15,147,
+ 63, 23,248,227,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 62,245, 27, 64, 63, 23,166,100, 62,248, 72, 55, 63, 11,232, 91, 63, 3,232,148, 63, 11, 17,164, 63, 4, 15,147, 63, 23,248,227,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 11,169, 67,
+ 63, 11,197, 18, 63, 22,244,173, 63, 11,215,236, 63, 23,233, 94, 63, 16, 60,186, 63, 13,120,216, 63, 23, 81,160,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,223,130,109, 63, 16,165,118,
+ 62,225, 89,220, 63, 12, 42, 77, 62,248, 72, 55, 63, 11,232, 91, 62,245, 27, 64, 63, 23,166,100,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 22,244,173, 63, 11,215,236, 63, 26,105, 28,
+ 63, 11,194,242, 63, 28, 56,220, 63, 14,250, 66, 63, 23,233, 94, 63, 16, 60,186,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,214,161,157, 63, 15,110,219, 62,218, 73,220, 63, 12, 31,169,
+ 62,225, 89,220, 63, 12, 42, 77, 62,223,130,109, 63, 16,165,118,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 26,105, 28, 63, 11,194,242, 63, 34,158,220, 63, 10, 23,175, 63, 39, 44,109,
+ 63, 19,221,107, 63, 28, 56,220, 63, 14,250, 66,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 62,192, 26,156, 63, 20,139, 31, 62,201,109,124, 63, 10,121, 72, 62,218, 73,220, 63, 12, 31,169,
+ 62,214,161,157, 63, 15,110,219,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63, 34,158,220, 63, 10, 23,175, 63, 46, 88,238, 63, 2,223,146, 63, 56, 80,242, 63, 6,244, 44, 63, 39, 44,109,
+ 63, 19,221,107,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 64, 2,236,169, 32,
+ 62,156,208, 61, 63, 7, 16,204, 62,177, 87,173, 63, 3, 9,102, 62,201,109,124, 63, 10,121, 72, 62,192, 26,156, 63, 20,139, 31,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 16, 2,236,169, 32, 63, 46, 88,238,
+ 63, 2,223,146, 63, 48,134, 62, 62,249,107, 37, 63, 54,173,195, 62,252,106,239, 63, 56, 80,242, 63, 6,244, 44,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0,128, 2,236,169, 32, 62,160, 36,202, 62,252, 51, 94,
+ 62,172,229,172, 62,249,127,116, 62,177, 87,173, 63, 3, 9,102, 62,156,208, 61, 63, 7, 16,204,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0,128, 2,236,169, 32, 63, 48,134, 62, 62,249,107, 37, 63, 50,229, 38,
+ 62,226, 32,169, 63, 53, 88,154, 62,221,146,240, 63, 54,173,195, 62,252,106,239,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 64, 2,236,169, 32, 62,162,172,128, 62,221,169, 17, 62,168, 39,196, 62,226, 11,206,
+ 62,172,229,172, 62,249,127,116, 62,160, 36,202, 62,252, 51, 94,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 16, 2,236,169, 32, 63, 50,229, 38, 62,226, 32,169, 63, 43, 57, 87, 62,206, 58,222, 63, 49,117,240,
+ 62,198,138,164, 63, 53, 88,154, 62,221,146,240,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0,128, 2,236,169, 32, 62,172,137,147, 62,198, 19,148, 62,184,207,130, 62,206, 27, 42, 62,168, 39,196, 62,226, 11,206,
+ 62,162,172,128, 62,221,169, 17,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0,128,
+ 2,236,169, 32, 63, 43, 57, 87, 62,206, 58,222, 63, 37, 94, 91, 62,187,120,107, 63, 41,160,156, 62,182,175, 56, 63, 49,117,240,
+ 62,198,138,164,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 62,188,212,202, 62,182,163,245, 62,197, 28,156, 62,187,130,166, 62,184,207,130, 62,206, 27, 42, 62,172,137,147, 62,198, 19,148,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 48,252,165,
+ 62, 85, 33,133, 63, 48, 54,112, 62, 96, 19, 20, 63, 46, 36,172, 62,129, 7,208, 63, 42, 17,240, 62, 97, 84,129,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,181, 71, 76, 62,131,200,204,
+ 62,175,121,117, 62,106,185,183, 62,172, 24,217, 62, 92,237, 21, 62,187, 81,138, 62,103, 40, 59,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 48, 89,204, 62, 4,194,134, 63, 48,252,165,
+ 62, 85, 33,133, 63, 42, 17,240, 62, 97, 84,129, 63, 37,125,160, 62, 46,211, 50,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 16, 2,236,169, 32, 62,187, 81,138, 62,103, 40, 59, 62,172, 24,217, 62, 92,237, 21,
+ 62,172,197, 94, 62, 4,200,109, 62,195,121, 25, 62, 48,253, 46,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 64, 2,236,169, 32, 63, 20, 44, 11, 61,163, 26, 20, 63, 48, 89,204, 62, 4,194,134, 63, 37,125,160,
+ 62, 46,211, 50, 63, 24, 92, 40, 62, 21,184,214,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 32, 2,236,169, 32, 62,195,121, 25, 62, 48,253, 46, 62,172,197, 94, 62, 4,200,109, 62,230,122,140, 61,161,248,202,
+ 62,222, 13,216, 62, 22,116,222,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 32,
+ 2,236,169, 32, 63, 16,254,174, 62, 34, 45, 94, 63, 3,199,219, 61,229, 28, 18, 63, 20, 44, 11, 61,163, 26, 20, 63, 24, 92, 40,
+ 62, 21,184,214,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 16, 2,236,169, 32,
+ 62,230,122,140, 61,161,248,202, 63, 3,199,219, 61,229, 28, 18, 62,236,248,140, 62, 34,202,182, 62,222, 13,216, 62, 22,116,222,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 64, 2,236,169, 32, 63, 21,152,184,
+ 62, 53, 47,182, 63, 16,254,174, 62, 34, 45, 94, 63, 24, 92, 40, 62, 21,184,214, 63, 25, 52,209, 62, 51,140, 76,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 32, 2,236,169, 32, 62,222, 13,216, 62, 22,116,222,
+ 62,236,248,140, 62, 34,202,182, 62,227,207,183, 62, 54, 75,250, 62,220,137,229, 62, 52,228,185,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 32, 2,236,169, 32, 63, 22, 57,137, 62, 61, 93, 81, 63, 21,152,184,
+ 62, 53, 47,182, 63, 25, 52,209, 62, 51,140, 76, 63, 30,166,193, 62, 73,168,114,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,220,137,229, 62, 52,228,185, 62,227,207,183, 62, 54, 75,250,
+ 62,226,152,122, 62, 62,166,190, 62,209,198, 54, 62, 75,240, 18,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 22,249,250, 62, 88,251,160, 63, 22, 57,137, 62, 61, 93, 81, 63, 30,166,193,
+ 62, 73,168,114, 63, 36, 0, 75, 62,116, 47,229,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 62,209,198, 54, 62, 75,240, 18, 62,226,152,122, 62, 62,166,190, 62,225, 83, 90, 62, 90,153, 21,
+ 62,199,231,211, 62,119,237,216,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63, 30,166,193, 62, 73,168,114, 63, 37,125,160, 62, 46,211, 50, 63, 42, 17,240, 62, 97, 84,129, 63, 36, 0, 75,
+ 62,116, 47,229,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 62,187, 81,138, 62,103, 40, 59, 62,195,121, 25, 62, 48,253, 46, 62,209,198, 54, 62, 75,240, 18, 62,199,231,211, 62,119,237,216,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 30,166,193,
+ 62, 73,168,114, 63, 25, 52,209, 62, 51,140, 76, 63, 24, 92, 40, 62, 21,184,214, 63, 37,125,160, 62, 46,211, 50,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,222, 13,216, 62, 22,116,222,
+ 62,220,137,229, 62, 52,228,185, 62,209,198, 54, 62, 75,240, 18, 62,195,121, 25, 62, 48,253, 46,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 36,163, 37, 62,140,168,191, 63, 36, 0, 75,
+ 62,116, 47,229, 63, 42, 17,240, 62, 97, 84,129, 63, 46, 36,172, 62,129, 7,208,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,187, 81,138, 62,103, 40, 59, 62,199,231,211, 62,119,237,216,
+ 62,199, 64, 6, 62,142, 6,105, 62,181, 71, 76, 62,131,200,204,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 25, 81, 20, 62,132, 56, 17, 63, 22,249,250, 62, 88,251,160, 63, 36, 0, 75,
+ 62,116, 47,229, 63, 36,163, 37, 62,140,168,191,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 62,199,231,211, 62,119,237,216, 62,225, 83, 90, 62, 90,153, 21, 62,221, 42, 54, 62,133, 25,209,
+ 62,199, 64, 6, 62,142, 6,105,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63, 27, 46,208, 62,148, 35,149, 63, 36, 60, 91, 62,150,222,221, 63, 33,170,222, 62,158,126, 74, 63, 27,177, 36,
+ 62,156,151,158,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 62,204,234, 72, 62,159, 63, 56, 62,199,245,150, 62,152, 15, 85, 62,217,166,238, 62,148,221,229, 62,216,160, 0, 62,157, 44,127,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 25, 81, 20,
+ 62,132, 56, 17, 63, 36,163, 37, 62,140,168,191, 63, 36, 60, 91, 62,150,222,221, 63, 27, 46,208, 62,148, 35,149,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,199,245,150, 62,152, 15, 85,
+ 62,199, 64, 6, 62,142, 6,105, 62,221, 42, 54, 62,133, 25,209, 62,217,166,238, 62,148,221,229,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 27,239,111, 62,166, 77,159, 63, 27,177, 36,
+ 62,156,151,158, 63, 33,170,222, 62,158,126, 74, 63, 31,212,102, 62,164,192,144,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,204,234, 72, 62,159, 63, 56, 62,216,160, 0, 62,157, 44,127,
+ 62,216, 21,115, 62,166,177, 14, 62,208,119, 17, 62,165, 65,201,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 27,239,111, 62,166, 77,159, 63, 31,212,102, 62,164,192,144, 63, 41,160,156,
+ 62,182,175, 56, 63, 37, 94, 91, 62,187,120,107,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 62,188,212,202, 62,182,163,245, 62,208,119, 17, 62,165, 65,201, 62,216, 21,115, 62,166,177, 14,
+ 62,197, 28,156, 62,187,130,166,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 62,194,119,104, 63, 82,189,164, 62,212, 73, 23, 63, 90,239,152, 62,205,192,100, 63, 97,238, 46, 62,185, 56, 38,
+ 63, 91,154, 72,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32,
+ 62,141, 94,228, 63,100,234, 86, 62,150, 66, 84, 63, 94,154,114, 62,173, 86,230, 63, 98, 66, 79, 62,162,143, 20, 63,106,173, 44,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32, 63, 87,122, 72,
+ 62, 62, 8,216, 63, 84,106,202, 62,113,185,137, 63, 72, 77,226, 62,121, 21,204, 63, 71,225,158, 62, 68, 34,113,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 16, 2,236,169, 32, 62,137, 32,132, 62,121, 65,181,
+ 62,107,179,168, 62,103,127,139, 62,114,147,210, 62, 61,116,212, 62,142,125,248, 62, 80, 4, 30,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 64, 2,236,169, 32, 63, 71,225,158, 62, 68, 34,113, 63, 72, 77,226,
+ 62,121, 21,204, 63, 51, 7, 8, 62,130,186, 5, 63, 49,166, 3, 62, 96, 57,232,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,172,197, 18, 62,133,112, 41, 62,137, 32,132, 62,121, 65,181,
+ 62,142,125,248, 62, 80, 4, 30, 62,174,228,121, 62,109, 79, 52,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 49,166, 3, 62, 96, 57,232, 63, 51, 7, 8, 62,130,186, 5, 63, 46, 36,172,
+ 62,129, 7,208, 63, 48, 54,112, 62, 96, 19, 20,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 62,181, 71, 76, 62,131,200,204, 62,172,197, 18, 62,133,112, 41, 62,174,228,121, 62,109, 79, 52,
+ 62,175,121,117, 62,106,185,183,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63, 36,163, 37, 62,140,168,191, 63, 46, 36,172, 62,129, 7,208, 63, 51, 7, 8, 62,130,186, 5, 63, 36, 60, 91,
+ 62,150,222,221,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 62,172,197, 18, 62,133,112, 41, 62,181, 71, 76, 62,131,200,204, 62,199, 64, 6, 62,142, 6,105, 62,199,245,150, 62,152, 15, 85,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 53, 88,154,
+ 62,221,146,240, 63, 49,117,240, 62,198,138,164, 63, 69, 19,224, 62,190, 68, 24, 63, 74, 64, 53, 62,224, 31,171,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 16, 2,236,169, 32, 62,134, 78,250, 62,186,213,148,
+ 62,172,137,147, 62,198, 19,148, 62,162,172,128, 62,221,169, 17, 62,114,112,184, 62,220,169,248,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 64, 2,236,169, 32, 62,214, 74, 54, 63, 70, 55, 20, 62,233,130, 48,
+ 63, 83, 69,188, 62,212, 73, 23, 63, 90,239,152, 62,194,119,104, 63, 82,189,164,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32, 62,150, 66, 84, 63, 94,154,114, 62,153, 1, 66, 63, 81,149,245,
+ 62,185, 56, 38, 63, 83,110,102, 62,173, 86,230, 63, 98, 66, 79,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32, 63, 66,242,106, 63, 25, 94,202, 63, 70,100,190, 63, 15,234,222, 63, 77,189, 90,
+ 63, 17, 88,233, 63, 74,206, 8, 63, 27,118, 88,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 62, 96, 32, 22, 63, 16, 60, 66, 62,125, 87, 86, 63, 15, 5,174, 62,132,187, 78, 63, 24, 44,180,
+ 62,108, 79, 26, 63, 26, 1,124,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63, 74,206, 8, 63, 27,118, 88, 63, 77,189, 90, 63, 17, 88,233, 63, 85,139, 72, 63, 19, 51,103, 63, 85,119,220,
+ 63, 31, 71, 77,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 62, 64,199, 64, 63, 18, 40, 26, 62, 96, 32, 22, 63, 16, 60, 66, 62,108, 79, 26, 63, 26, 1,124, 62, 67,191, 44, 63, 30, 89, 90,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 85,119,220,
+ 63, 31, 71, 77, 63, 85,139, 72, 63, 19, 51,103, 63,100,213,228, 63, 20,156, 72, 63, 96, 82, 18, 63, 34,133,128,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0,128, 2,236,169, 32, 62, 1, 50,226, 63, 20, 68,184,
+ 62, 64,199, 64, 63, 18, 40, 26, 62, 67,191, 44, 63, 30, 89, 90, 62, 24,204,194, 63, 34,186, 32,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0,128, 2,236,169, 32, 63, 56, 80,242, 63, 6,244, 44, 63, 54,173,195,
+ 62,252,106,239, 63, 60,205,115, 62,253,150,213, 63, 64, 14,166, 63, 4, 80, 81,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 16, 2,236,169, 32, 62,147, 85,190, 62,252,176, 91, 62,160, 36,202, 62,252, 51, 94,
+ 62,156,208, 61, 63, 7, 16,204, 62,140,121,160, 63, 3,197, 74,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 64, 2,236,169, 32, 63, 64, 14,166, 63, 4, 80, 81, 63, 60,205,115, 62,253,150,213, 63, 73,103, 68,
+ 63, 0,248,233, 63, 75, 12,248, 63, 8,206, 64,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 62,115, 59,144, 62,255,143,102, 62,147, 85,190, 62,252,176, 91, 62,140,121,160, 63, 3,197, 74,
+ 62,107,135, 78, 63, 7,182, 88,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63, 75, 12,248, 63, 8,206, 64, 63, 73,103, 68, 63, 0,248,233, 63, 82,151,239, 63, 3,223, 86, 63, 82,227,181,
+ 63, 11,102,189,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 62, 77, 17, 82, 63, 2, 98,162, 62,115, 59,144, 62,255,143,102, 62,107,135, 78, 63, 7,182, 88, 62, 75, 98,202, 63, 10, 43,108,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 82,227,181,
+ 63, 11,102,189, 63, 82,151,239, 63, 3,223, 86, 63, 91,224, 92, 63, 5,144,239, 63, 90,148,161, 63, 13, 95,146,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62, 38, 40,178, 63, 3,230, 14,
+ 62, 77, 17, 82, 63, 2, 98,162, 62, 75, 98,202, 63, 10, 43,108, 62, 43,162, 10, 63, 12, 50, 8,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63,103, 89,120, 63, 2, 76,105, 63,103,179,170,
+ 63, 12,105,142, 63, 90,148,161, 63, 13, 95,146, 63, 91,224, 92, 63, 5,144,239,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62, 43,162, 10, 63, 12, 50, 8, 61,231, 41,168, 63, 11, 83,158,
+ 61,234,128,116, 63, 0, 39,200, 62, 38, 40,178, 63, 3,230, 14,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63,100,213,228, 63, 20,156, 72, 63, 85,139, 72, 63, 19, 51,103, 63, 90,148,161,
+ 63, 13, 95,146, 63,103,179,170, 63, 12,105,142,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 62, 43,162, 10, 63, 12, 50, 8, 62, 64,199, 64, 63, 18, 40, 26, 62, 1, 50,226, 63, 20, 68,184,
+ 61,231, 41,168, 63, 11, 83,158,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63, 85,139, 72, 63, 19, 51,103, 63, 77,189, 90, 63, 17, 88,233, 63, 82,227,181, 63, 11,102,189, 63, 90,148,161,
+ 63, 13, 95,146,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 62, 75, 98,202, 63, 10, 43,108, 62, 96, 32, 22, 63, 16, 60, 66, 62, 64,199, 64, 63, 18, 40, 26, 62, 43,162, 10, 63, 12, 50, 8,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 77,189, 90,
+ 63, 17, 88,233, 63, 70,100,190, 63, 15,234,222, 63, 75, 12,248, 63, 8,206, 64, 63, 82,227,181, 63, 11,102,189,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,107,135, 78, 63, 7,182, 88,
+ 62,125, 87, 86, 63, 15, 5,174, 62, 96, 32, 22, 63, 16, 60, 66, 62, 75, 98,202, 63, 10, 43,108,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 70,100,190, 63, 15,234,222, 63, 60,235, 82,
+ 63, 12, 12, 27, 63, 64, 14,166, 63, 4, 80, 81, 63, 75, 12,248, 63, 8,206, 64,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,140,121,160, 63, 3,197, 74, 62,145,230, 78, 63, 11,225,148,
+ 62,125, 87, 86, 63, 15, 5,174, 62,107,135, 78, 63, 7,182, 88,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 57,118, 31, 63, 12, 79,230, 63, 56, 80,242, 63, 6,244, 44, 63, 64, 14,166,
+ 63, 4, 80, 81, 63, 60,235, 82, 63, 12, 12, 27,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 32, 2,236,169, 32, 62,140,121,160, 63, 3,197, 74, 62,156,208, 61, 63, 7, 16,204, 62,152,199, 0, 63, 12,133, 13,
+ 62,145,230, 78, 63, 11,225,148,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 32,
+ 2,236,169, 32, 63, 57,240,195, 63, 23,138, 10, 63, 60,235, 82, 63, 12, 12, 27, 63, 70,100,190, 63, 15,234,222, 63, 66,242,106,
+ 63, 25, 94,202,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 62,125, 87, 86, 63, 15, 5,174, 62,145,230, 78, 63, 11,225,148, 62,150, 7,247, 63, 23, 12, 96, 62,132,187, 78, 63, 24, 44,180,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 13,120,216,
+ 63, 23, 81,160, 63, 23,233, 94, 63, 16, 60,186, 63, 28, 56,220, 63, 14,250, 66, 63, 39, 44,109, 63, 19,221,107,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,214,161,157, 63, 15,110,219,
+ 62,223,130,109, 63, 16,165,118, 62,245, 27, 64, 63, 23,166,100, 62,192, 26,156, 63, 20,139, 31,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 56, 29,176, 63, 20,206, 88, 63, 57,118, 31,
+ 63, 12, 79,230, 63, 60,235, 82, 63, 12, 12, 27, 63, 57,240,195, 63, 23,138, 10,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,145,230, 78, 63, 11,225,148, 62,152,199, 0, 63, 12,133, 13,
+ 62,153,211,239, 63, 20,159,220, 62,150, 7,247, 63, 23, 12, 96,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 54,148, 48, 63, 22,206,220, 63, 56, 29,176, 63, 20,206, 88, 63, 57,240,195,
+ 63, 23,138, 10, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 62,150, 7,247, 63, 23, 12, 96, 62,153,211,239, 63, 20,159,220, 62,156,106,108, 63, 22,154,146,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63, 54,173,195, 62,252,106,239, 63, 53, 88,154, 62,221,146,240, 63, 74, 64, 53, 62,224, 31,171, 63, 60,205,115,
+ 62,253,150,213,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 32, 2,236,169, 32,
+ 62,114,112,184, 62,220,169,248, 62,162,172,128, 62,221,169, 17, 62,160, 36,202, 62,252, 51, 94, 62,147, 85,190, 62,252,176, 91,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 32, 2,236,169, 32, 63, 74, 64, 53,
+ 62,224, 31,171, 63, 81,106,217, 62,232,214, 14, 63, 73,103, 68, 63, 0,248,233, 63, 60,205,115, 62,253,150,213,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,115, 59,144, 62,255,143,102,
+ 62, 84, 93, 88, 62,228,105, 50, 62,114,112,184, 62,220,169,248, 62,147, 85,190, 62,252,176, 91,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 81,106,217, 62,232,214, 14, 63, 93,154,106,
+ 62,233, 26,226, 63, 82,151,239, 63, 3,223, 86, 63, 73,103, 68, 63, 0,248,233,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62, 77, 17, 82, 63, 2, 98,162, 62, 33, 1,128, 62,226,210, 70,
+ 62, 84, 93, 88, 62,228,105, 50, 62,115, 59,144, 62,255,143,102,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63,103, 89,120, 63, 2, 76,105, 63, 91,224, 92, 63, 5,144,239, 63, 82,151,239,
+ 63, 3,223, 86, 63, 93,154,106, 62,233, 26,226,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 62, 77, 17, 82, 63, 2, 98,162, 62, 38, 40,178, 63, 3,230, 14, 61,234,128,116, 63, 0, 39,200,
+ 62, 33, 1,128, 62,226,210, 70,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63, 51, 7, 8, 62,130,186, 5, 63, 72, 77,226, 62,121, 21,204, 63, 73,254,154, 62,140, 82,178, 63, 56,188, 90,
+ 62,159,207,103,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 62,130,249,249, 62,137,175,246, 62,137, 32,132, 62,121, 65,181, 62,172,197, 18, 62,133,112, 41, 62,161, 5,192, 62,159, 40,228,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 69, 19,224,
+ 62,190, 68, 24, 63, 56,188, 90, 62,159,207,103, 63, 73,254,154, 62,140, 82,178, 63, 77,217,216, 62,157,228, 7,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0,128, 2,236,169, 32, 62,130,249,249, 62,137,175,246,
+ 62,161, 5,192, 62,159, 40,228, 62,134, 78,250, 62,186,213,148, 62,111,118,154, 62,152,108,120,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0,128, 2,236,169, 32, 63, 49,117,240, 62,198,138,164, 63, 41,160,156,
+ 62,182,175, 56, 63, 56,188, 90, 62,159,207,103, 63, 69, 19,224, 62,190, 68, 24,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,161, 5,192, 62,159, 40,228, 62,188,212,202, 62,182,163,245,
+ 62,172,137,147, 62,198, 19,148, 62,134, 78,250, 62,186,213,148,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 41,160,156, 62,182,175, 56, 63, 33,170,222, 62,158,126, 74, 63, 36, 60, 91,
+ 62,150,222,221, 63, 56,188, 90, 62,159,207,103,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 62,199,245,150, 62,152, 15, 85, 62,204,234, 72, 62,159, 63, 56, 62,188,212,202, 62,182,163,245,
+ 62,161, 5,192, 62,159, 40,228,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63, 36, 60, 91, 62,150,222,221, 63, 51, 7, 8, 62,130,186, 5, 63, 56,188, 90, 62,159,207,103, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 62,161, 5,192, 62,159, 40,228, 62,172,197, 18, 62,133,112, 41, 62,199,245,150, 62,152, 15, 85, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 41,160,156,
+ 62,182,175, 56, 63, 31,212,102, 62,164,192,144, 63, 33,170,222, 62,158,126, 74, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,204,234, 72, 62,159, 63, 56,
+ 62,208,119, 17, 62,165, 65,201, 62,188,212,202, 62,182,163,245, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,245, 44,226, 63, 96,140,129, 62,227,135, 42,
+ 63,101, 2, 58, 62,219,168,136, 63, 95,236, 30, 62,238, 30,135, 63, 90, 41,200,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32, 62,137,240,216, 63, 93,226, 90, 62,122,103,110, 63, 92,255,236,
+ 62,120, 84, 74, 63, 83, 32,104, 62,138,193, 32, 63, 83, 3, 16,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32, 62,233,130, 48, 63, 83, 69,188, 62,238, 30,135, 63, 90, 41,200, 62,219,168,136,
+ 63, 95,236, 30, 62,212, 73, 23, 63, 90,239,152,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0,240, 2,236,169, 32, 62,137,240,216, 63, 93,226, 90, 62,138,193, 32, 63, 83, 3, 16, 62,153, 1, 66, 63, 81,149,245,
+ 62,150, 66, 84, 63, 94,154,114,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0,240,
+ 2,236,169, 32, 63, 77,217,216, 62,157,228, 7, 63, 73,254,154, 62,140, 82,178, 63, 90, 61, 33, 62,124,207,195, 63, 90,225,160,
+ 62,137,121,110,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 16, 2,236,169, 32,
+ 62, 81,207, 98, 62,110, 1,109, 62,130,249,249, 62,137,175,246, 62,111,118,154, 62,152,108,120, 62, 74,125,166, 62,130, 30,252,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 64, 2,236,169, 32, 63, 72, 77,226,
+ 62,121, 21,204, 63, 84,106,202, 62,113,185,137, 63, 90, 61, 33, 62,124,207,195, 63, 73,254,154, 62,140, 82,178,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62, 81,207, 98, 62,110, 1,109,
+ 62,107,179,168, 62,103,127,139, 62,137, 32,132, 62,121, 65,181, 62,130,249,249, 62,137,175,246,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,212, 73, 23, 63, 90,239,152, 62,219,168,136,
+ 63, 95,236, 30, 62,205,192,100, 63, 97,238, 46, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0,112, 2,236,169, 32, 62,141, 94,228, 63,100,234, 86, 62,137,240,216, 63, 93,226, 90,
+ 62,150, 66, 84, 63, 94,154,114, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0,112, 2,236,169, 32, 63,109,178, 31, 62,228, 68,224, 63,102,178, 46, 62,232,184,100, 63,101,251,100,
+ 62,227,198,238, 63,107,173, 94, 62,225,130,168,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 61,249,209, 68, 62,219,134, 70, 61,242,216,120, 62,225, 40,124, 61,177, 27, 28, 62,219,240, 42,
+ 61,196,131, 76, 62,216, 97,196,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63,109,178, 31, 62,228, 68,224, 63,107,173, 94, 62,225,130,168, 63,114,102,144, 62,220, 23,198, 63,116, 76, 41,
+ 62,222,153,139,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 61,120,163, 56, 62,208,252, 58, 61,196,131, 76, 62,216, 97,196, 61,177, 27, 28, 62,219,240, 42, 61, 73,183,128, 62,213,108, 84,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63,116, 76, 41,
+ 62,222,153,139, 63,114,102,144, 62,220, 23,198, 63,117, 87, 84, 62,211,255,221, 63,119,115,183, 62,215, 49,140,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 61, 55, 29,144, 62,194,183,207,
+ 61,120,163, 56, 62,208,252, 58, 61, 73,183,128, 62,213,108, 84, 60,231,111,224, 62,198,142,100,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63,119,115,183, 62,215, 49,140, 63,117, 87, 84,
+ 62,211,255,221, 63,118, 20,150, 62,196,110, 60, 63,122, 12, 49, 62,197, 8,246,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 61,103,197, 96, 62,170,206, 15, 61, 55, 29,144, 62,194,183,207,
+ 60,231,111,224, 62,198,142,100, 61, 16, 54,240, 62,167, 4,120,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63,122, 12, 49, 62,197, 8,246, 63,118, 20,150, 62,196,110, 60, 63,108,155, 17,
+ 62,178,201,130, 63,110,190, 84, 62,172, 77,223,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 61,246,252,148, 62,160,116,164, 61,103,197, 96, 62,170,206, 15, 61, 16, 54,240, 62,167, 4,120,
+ 61,246, 66, 8, 62,152,161, 28,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63,110,190, 84, 62,172, 77,223, 63,108,155, 17, 62,178,201,130, 63, 92,180, 21, 62,173, 95,202, 63, 90, 5,151,
+ 62,167, 61,138,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 62, 54,216,144, 62,163, 76, 35, 61,246,252,148, 62,160,116,164, 61,246, 66, 8, 62,152,161, 28, 62, 66,251,194, 62,158,102,163,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63,108,155, 17,
+ 62,178,201,130, 63,109,132,198, 62,186,157,182, 63, 97, 32, 68, 62,178, 12,192, 63, 92,180, 21, 62,173, 95,202,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62, 36,185, 48, 62,166, 7, 16,
+ 61,221, 91, 40, 62,167,194, 4, 61,246,252,148, 62,160,116,164, 62, 54,216,144, 62,163, 76, 35,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63,118, 20,150, 62,196,110, 60, 63,115,225, 84,
+ 62,198, 85,208, 63,109,132,198, 62,186,157,182, 63,108,155, 17, 62,178,201,130,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 61,221, 91, 40, 62,167,194, 4, 61,134,221,244, 62,175,164,121,
+ 61,103,197, 96, 62,170,206, 15, 61,246,252,148, 62,160,116,164,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63,117, 87, 84, 62,211,255,221, 63,116, 48,222, 62,209, 8,169, 63,115,225, 84,
+ 62,198, 85,208, 63,118, 20,150, 62,196,110, 60,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 61,134,221,244, 62,175,164,121, 61, 93,108,160, 62,190,207, 17, 61, 55, 29,144, 62,194,183,207,
+ 61,103,197, 96, 62,170,206, 15,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63,114,102,144, 62,220, 23,198, 63,113,151,174, 62,214,229, 26, 63,116, 48,222, 62,209, 8,169, 63,117, 87, 84,
+ 62,211,255,221,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 61, 93,108,160, 62,190,207, 17, 61,135,155, 12, 62,201, 39,166, 61,120,163, 56, 62,208,252, 58, 61, 55, 29,144, 62,194,183,207,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63,107,173, 94,
+ 62,225,130,168, 63,107,239,228, 62,218, 59, 62, 63,113,151,174, 62,214,229, 26, 63,114,102,144, 62,220, 23,198,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 61,135,155, 12, 62,201, 39,166,
+ 61,195, 47,128, 62,207, 11, 6, 61,196,131, 76, 62,216, 97,196, 61,120,163, 56, 62,208,252, 58,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63,107,173, 94, 62,225,130,168, 63,101,251,100,
+ 62,227,198,238, 63,102,205, 71, 62,219, 94,132, 63,107,239,228, 62,218, 59, 62,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 61,244,157,192, 62,209,137,157, 61,249,209, 68, 62,219,134, 70,
+ 61,196,131, 76, 62,216, 97,196, 61,195, 47,128, 62,207, 11, 6,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 69, 19,224, 62,190, 68, 24, 63, 77,217,216, 62,157,228, 7, 63, 85, 35,236,
+ 62,181,201,164, 63, 78, 92, 56, 62,188,114,177,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 32, 2,236,169, 32, 62, 80, 91,122, 62,174, 18, 72, 62,111,118,154, 62,152,108,120, 62,134, 78,250, 62,186,213,148,
+ 62,104,163,162, 62,182,180,150,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 32,
+ 2,236,169, 32, 63, 77,217,216, 62,157,228, 7, 63, 90, 5,151, 62,167, 61,138, 63, 92,180, 21, 62,173, 95,202, 63, 85, 35,236,
+ 62,181,201,164,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 16, 2,236,169, 32,
+ 62, 54,216,144, 62,163, 76, 35, 62, 66,251,194, 62,158,102,163, 62,111,118,154, 62,152,108,120, 62, 80, 91,122, 62,174, 18, 72,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 64, 2,236,169, 32, 63, 74, 64, 53,
+ 62,224, 31,171, 63, 69, 19,224, 62,190, 68, 24, 63, 78, 92, 56, 62,188,114,177, 63, 81,106,217, 62,232,214, 14,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,104,163,162, 62,182,180,150,
+ 62,134, 78,250, 62,186,213,148, 62,114,112,184, 62,220,169,248, 62, 84, 93, 88, 62,228,105, 50,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 93,154,106, 62,233, 26,226, 63, 94,229,196,
+ 62,224,195,128, 63,101,251,100, 62,227,198,238, 63,102,178, 46, 62,232,184,100,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 61,249,209, 68, 62,219,134, 70, 62, 28,187,108, 62,217, 86, 48,
+ 62, 33, 1,128, 62,226,210, 70, 61,242,216,120, 62,225, 40,124,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 92,180, 21, 62,173, 95,202, 63, 97, 32, 68, 62,178, 12,192, 63, 94,215, 9,
+ 62,186, 54, 4, 63, 85, 35,236, 62,181,201,164,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 62, 41,122, 60, 62,175, 58, 16, 62, 36,185, 48, 62,166, 7, 16, 62, 54,216,144, 62,163, 76, 35,
+ 62, 80, 91,122, 62,174, 18, 72,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63, 95, 78,230, 62,189,233, 4, 63, 86,188, 32, 62,190, 62, 44, 63, 85, 35,236, 62,181,201,164, 63, 94,215, 9,
+ 62,186, 54, 4,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 62, 80, 91,122, 62,174, 18, 72, 62, 71,118, 78, 62,182, 49, 27, 62, 37,225, 52, 62,179, 12, 40, 62, 41,122, 60, 62,175, 58, 16,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 92,166, 70,
+ 62,197,166, 0, 63, 86,188, 32, 62,190, 62, 44, 63, 95, 78,230, 62,189,233, 4, 63, 95, 13,226, 62,194,152, 37,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62, 37,225, 52, 62,179, 12, 40,
+ 62, 71,118, 78, 62,182, 49, 27, 62, 45,143,142, 62,188, 37,237, 62, 36,230,106, 62,184, 27,222,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 95, 90,248, 62,207,122,100, 63, 90,249,108,
+ 62,212,199, 58, 63, 86,188, 32, 62,190, 62, 44, 63, 92,166, 70, 62,197,166, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62, 71,118, 78, 62,182, 49, 27, 62, 48, 56,110, 62,205, 43,230,
+ 62, 30,250,174, 62,198, 12, 26, 62, 45,143,142, 62,188, 37,237,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 94,229,196, 62,224,195,128, 63, 90,249,108, 62,212,199, 58, 63, 95, 90,248,
+ 62,207,122,100, 63, 98,104, 92, 62,215,136,197,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 62, 30,250,174, 62,198, 12, 26, 62, 48, 56,110, 62,205, 43,230, 62, 28,187,108, 62,217, 86, 48,
+ 62, 15, 59,212, 62,206, 50,224,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63,101,251,100, 62,227,198,238, 63, 94,229,196, 62,224,195,128, 63, 98,104, 92, 62,215,136,197, 63,102,205, 71,
+ 62,219, 94,132,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 62, 15, 59,212, 62,206, 50,224, 62, 28,187,108, 62,217, 86, 48, 61,249,209, 68, 62,219,134, 70, 61,244,157,192, 62,209,137,157,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 81,106,217,
+ 62,232,214, 14, 63, 90,249,108, 62,212,199, 58, 63, 94,229,196, 62,224,195,128, 63, 93,154,106, 62,233, 26,226,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62, 28,187,108, 62,217, 86, 48,
+ 62, 48, 56,110, 62,205, 43,230, 62, 84, 93, 88, 62,228,105, 50, 62, 33, 1,128, 62,226,210, 70,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 81,106,217, 62,232,214, 14, 63, 78, 92, 56,
+ 62,188,114,177, 63, 86,188, 32, 62,190, 62, 44, 63, 90,249,108, 62,212,199, 58,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62, 71,118, 78, 62,182, 49, 27, 62,104,163,162, 62,182,180,150,
+ 62, 84, 93, 88, 62,228,105, 50, 62, 48, 56,110, 62,205, 43,230,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 78, 92, 56, 62,188,114,177, 63, 85, 35,236, 62,181,201,164, 63, 86,188, 32,
+ 62,190, 62, 44, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 62, 71,118, 78, 62,182, 49, 27, 62, 80, 91,122, 62,174, 18, 72, 62,104,163,162, 62,182,180,150,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63,102,205, 71, 62,219, 94,132, 63, 98,104, 92, 62,215,136,197, 63,100,109,182, 62,210,255,149, 63,104, 86, 54,
+ 62,214,241,209,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 62, 7,107,160, 62,200,103, 34, 62, 15, 59,212, 62,206, 50,224, 61,244,157,192, 62,209,137,157, 61,232, 2, 8, 62,203,214, 20,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 98,104, 92,
+ 62,215,136,197, 63, 95, 90,248, 62,207,122,100, 63, 97,206,112, 62,204,202, 10, 63,100,109,182, 62,210,255,149,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62, 21, 68, 64, 62,194, 55,107,
+ 62, 30,250,174, 62,198, 12, 26, 62, 15, 59,212, 62,206, 50,224, 62, 7,107,160, 62,200,103, 34,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 95, 90,248, 62,207,122,100, 63, 92,166, 70,
+ 62,197,166, 0, 63, 94,241, 82, 62,198,103, 40, 63, 97,206,112, 62,204,202, 10,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62, 35,225, 20, 62,188, 50, 39, 62, 45,143,142, 62,188, 37,237,
+ 62, 30,250,174, 62,198, 12, 26, 62, 21, 68, 64, 62,194, 55,107,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 92,166, 70, 62,197,166, 0, 63, 95, 13,226, 62,194,152, 37, 63, 97, 1,118,
+ 62,195,226, 47, 63, 94,241, 82, 62,198,103, 40,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 62, 28, 43, 12, 62,184,177,186, 62, 36,230,106, 62,184, 27,222, 62, 45,143,142, 62,188, 37,237,
+ 62, 35,225, 20, 62,188, 50, 39,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63, 95, 13,226, 62,194,152, 37, 63, 95, 78,230, 62,189,233, 4, 63, 97,113, 51, 62,189,151, 92, 63, 97, 1,118,
+ 62,195,226, 47,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 62, 29, 67,104, 62,177,199, 58, 62, 37,225, 52, 62,179, 12, 40, 62, 36,230,106, 62,184, 27,222, 62, 28, 43, 12, 62,184,177,186,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 95, 78,230,
+ 62,189,233, 4, 63, 94,215, 9, 62,186, 54, 4, 63, 96, 69, 96, 62,187,133,152, 63, 97,113, 51, 62,189,151, 92,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62, 35, 14,140, 62,176, 19, 33,
+ 62, 41,122, 60, 62,175, 58, 16, 62, 37,225, 52, 62,179, 12, 40, 62, 29, 67,104, 62,177,199, 58,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 94,215, 9, 62,186, 54, 4, 63, 97, 32, 68,
+ 62,178, 12,192, 63, 98, 91,112, 62,182,128,149, 63, 96, 69, 96, 62,187,133,152,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62, 29,107,228, 62,169,230, 95, 62, 36,185, 48, 62,166, 7, 16,
+ 62, 41,122, 60, 62,175, 58, 16, 62, 35, 14,140, 62,176, 19, 33,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63,107,239,228, 62,218, 59, 62, 63,102,205, 71, 62,219, 94,132, 63,104, 86, 54,
+ 62,214,241,209, 63,109, 27, 34, 62,214,254,155,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 61,232, 2, 8, 62,203,214, 20, 61,244,157,192, 62,209,137,157, 61,195, 47,128, 62,207, 11, 6,
+ 61,184,174, 36, 62,202,130,216,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63,113,151,174, 62,214,229, 26, 63,107,239,228, 62,218, 59, 62, 63,109, 27, 34, 62,214,254,155, 63,113,134, 69,
+ 62,212, 82,156,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 61,184,174, 36, 62,202,130,216, 61,195, 47,128, 62,207, 11, 6, 61,135,155, 12, 62,201, 39,166, 61,138,114, 60, 62,197, 61, 28,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63,116, 48,222,
+ 62,209, 8,169, 63,113,151,174, 62,214,229, 26, 63,113,134, 69, 62,212, 82,156, 63,114,143, 42, 62,207,168, 24,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 61,138,114, 60, 62,197, 61, 28,
+ 61,135,155, 12, 62,201, 39,166, 61, 93,108,160, 62,190,207, 17, 61,132, 85,184, 62,189,211, 22,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63,115,225, 84, 62,198, 85,208, 63,116, 48,222,
+ 62,209, 8,169, 63,114,143, 42, 62,207,168, 24, 63,114,125,203, 62,200,114, 96,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 61,132, 85,184, 62,189,211, 22, 61, 93,108,160, 62,190,207, 17,
+ 61,134,221,244, 62,175,164,121, 61,145,152, 16, 62,179,214, 84,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63,109,132,198, 62,186,157,182, 63,115,225, 84, 62,198, 85,208, 63,114,125,203,
+ 62,200,114, 96, 63,109,192,177, 62,190,240,152,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 61,145,152, 16, 62,179,214, 84, 61,134,221,244, 62,175,164,121, 61,221, 91, 40, 62,167,194, 4,
+ 61,208,226, 64, 62,172, 58,232,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63, 97, 32, 68, 62,178, 12,192, 63,109,132,198, 62,186,157,182, 63,109,192,177, 62,190,240,152, 63, 98, 91,112,
+ 62,182,128,149,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 61,208,226, 64, 62,172, 58,232, 61,221, 91, 40, 62,167,194, 4, 62, 36,185, 48, 62,166, 7, 16, 62, 29,107,228, 62,169,230, 95,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 97, 1,118,
+ 62,195,226, 47, 63, 97,113, 51, 62,189,151, 92, 63,102,139,215, 62,193,109, 15, 63,100, 47, 54, 62,198,115,186,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62, 5,169, 92, 62,179,115,168,
+ 62, 29, 67,104, 62,177,199, 58, 62, 28, 43, 12, 62,184,177,186, 62, 13, 97, 50, 62,186, 42, 50,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63,100, 47, 54, 62,198,115,186, 63,102,139,215,
+ 62,193,109, 15, 63,105,241,174, 62,200, 8,204, 63,103,233, 71, 62,204, 42,178,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 61,229,171,228, 62,185, 42, 41, 62, 5,169, 92, 62,179,115,168,
+ 62, 13, 97, 50, 62,186, 42, 50, 61,243,248, 92, 62,191, 22, 96,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63,103,233, 71, 62,204, 42,178, 63,105,241,174, 62,200, 8,204, 63,108, 37, 51,
+ 62,205, 3,249, 63,106,212, 56, 62,208,238, 96,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 61,202, 99,120, 62,190, 49,192, 61,229,171,228, 62,185, 42, 41, 61,243,248, 92, 62,191, 22, 96,
+ 61,211,209,160, 62,195,159,108,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63,106,212, 56, 62,208,238, 96, 63,108, 37, 51, 62,205, 3,249, 63,110, 73, 56, 62,206,119,186, 63,109,191, 46,
+ 62,210, 64, 92,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 61,179,234,244, 62,190,219,240, 61,202, 99,120, 62,190, 49,192, 61,211,209,160, 62,195,159,108, 61,181,129,196, 62,196, 14,204,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63,109, 27, 34,
+ 62,214,254,155, 63,104, 86, 54, 62,214,241,209, 63,106,212, 56, 62,208,238, 96, 63,109,191, 46, 62,210, 64, 92,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 61,211,209,160, 62,195,159,108,
+ 61,232, 2, 8, 62,203,214, 20, 61,184,174, 36, 62,202,130,216, 61,181,129,196, 62,196, 14,204,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63,100,109,182, 62,210,255,149, 63,103,233, 71,
+ 62,204, 42,178, 63,106,212, 56, 62,208,238, 96, 63,104, 86, 54, 62,214,241,209,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 61,211,209,160, 62,195,159,108, 61,243,248, 92, 62,191, 22, 96,
+ 62, 7,107,160, 62,200,103, 34, 61,232, 2, 8, 62,203,214, 20,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63,100,109,182, 62,210,255,149, 63, 97,206,112, 62,204,202, 10, 63,100, 47, 54,
+ 62,198,115,186, 63,103,233, 71, 62,204, 42,178,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 62, 13, 97, 50, 62,186, 42, 50, 62, 21, 68, 64, 62,194, 55,107, 62, 7,107,160, 62,200,103, 34,
+ 61,243,248, 92, 62,191, 22, 96,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63, 97, 1,118, 62,195,226, 47, 63,100, 47, 54, 62,198,115,186, 63, 97,206,112, 62,204,202, 10, 63, 94,241, 82,
+ 62,198,103, 40,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 62, 21, 68, 64, 62,194, 55,107, 62, 13, 97, 50, 62,186, 42, 50, 62, 28, 43, 12, 62,184,177,186, 62, 35,225, 20, 62,188, 50, 39,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63, 96, 69, 96,
+ 62,187,133,152, 63, 98, 91,112, 62,182,128,149, 63,102,139,215, 62,193,109, 15, 63, 97,113, 51, 62,189,151, 92,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62, 5,169, 92, 62,179,115,168,
+ 62, 29,107,228, 62,169,230, 95, 62, 35, 14,140, 62,176, 19, 33, 62, 29, 67,104, 62,177,199, 58,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63,109,192,177, 62,190,240,152, 63,105,241,174,
+ 62,200, 8,204, 63,102,139,215, 62,193,109, 15, 63, 98, 91,112, 62,182,128,149,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62, 5,169, 92, 62,179,115,168, 61,229,171,228, 62,185, 42, 41,
+ 61,208,226, 64, 62,172, 58,232, 62, 29,107,228, 62,169,230, 95,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63,114,125,203, 62,200,114, 96, 63,108, 37, 51, 62,205, 3,249, 63,105,241,174,
+ 62,200, 8,204, 63,109,192,177, 62,190,240,152,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0, 0, 2,236,169, 32, 61,229,171,228, 62,185, 42, 41, 61,202, 99,120, 62,190, 49,192, 61,145,152, 16, 62,179,214, 84,
+ 61,208,226, 64, 62,172, 58,232,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63,114,143, 42, 62,207,168, 24, 63,110, 73, 56, 62,206,119,186, 63,108, 37, 51, 62,205, 3,249, 63,114,125,203,
+ 62,200,114, 96,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 61,202, 99,120, 62,190, 49,192, 61,179,234,244, 62,190,219,240, 61,132, 85,184, 62,189,211, 22, 61,145,152, 16, 62,179,214, 84,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63,113,134, 69,
+ 62,212, 82,156, 63,109,191, 46, 62,210, 64, 92, 63,110, 73, 56, 62,206,119,186, 63,114,143, 42, 62,207,168, 24,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 61,179,234,244, 62,190,219,240,
+ 61,181,129,196, 62,196, 14,204, 61,138,114, 60, 62,197, 61, 28, 61,132, 85,184, 62,189,211, 22,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63,109, 27, 34, 62,214,254,155, 63,109,191, 46,
+ 62,210, 64, 92, 63,113,134, 69, 62,212, 82,156, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 61,138,114, 60, 62,197, 61, 28, 61,181,129,196, 62,196, 14,204,
+ 61,184,174, 36, 62,202,130,216, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63,110,190, 84, 62,172, 77,223, 63, 90, 5,151, 62,167, 61,138, 63, 96, 25, 22,
+ 62,149,248,246, 63,122,176,162, 62,161,215,145,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0,128, 2,236,169, 32, 62, 54,234, 64, 62,140,219,146, 62, 66,251,194, 62,158,102,163, 61,246, 66, 8, 62,152,161, 28,
+ 61,189,241,172, 62,132,107, 13,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0,
+ 2,236,169, 32, 63,122, 12, 49, 62,197, 8,246, 63,110,190, 84, 62,172, 77,223, 63,122,176,162, 62,161,215,145, 63,126,255,188,
+ 62,198,248,115,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 64, 2,236,169, 32,
+ 61,189,241,172, 62,132,107, 13, 61,246, 66, 8, 62,152,161, 28, 61, 16, 54,240, 62,167, 4,120, 58,163, 8, 0, 62,162, 69, 39,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0,128, 2,236,169, 32, 63,119,115,183,
+ 62,215, 49,140, 63,122, 12, 49, 62,197, 8,246, 63,126,255,188, 62,198,248,115, 63,122, 6, 47, 62,216,157,248,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 58,163, 8, 0, 62,162, 69, 39,
+ 61, 16, 54,240, 62,167, 4,120, 60,231,111,224, 62,198,142,100, 60, 14,248,224, 62,198,141, 70,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 16, 2,236,169, 32, 63,116, 76, 41, 62,222,153,139, 63,119,115,183,
+ 62,215, 49,140, 63,122, 6, 47, 62,216,157,248, 63,119, 98,134, 62,225, 37,204,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 60, 14,248,224, 62,198,141, 70, 60,231,111,224, 62,198,142,100,
+ 61, 73,183,128, 62,213,108, 84, 60,229,210, 80, 62,218,239, 32,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 63,109,178, 31, 62,228, 68,224, 63,116, 76, 41, 62,222,153,139, 63,119, 98,134,
+ 62,225, 37,204, 63,115,185, 46, 62,234,157, 90,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0,128, 2,236,169, 32, 60,229,210, 80, 62,218,239, 32, 61, 73,183,128, 62,213,108, 84, 61,177, 27, 28, 62,219,240, 42,
+ 61,122,103, 56, 62,230, 10, 30,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0,128,
+ 2,236,169, 32, 63,102,178, 46, 62,232,184,100, 63,109,178, 31, 62,228, 68,224, 63,115,185, 46, 62,234,157, 90, 63,106,134,244,
+ 62,246, 64,234,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 64, 2,236,169, 32,
+ 61,122,103, 56, 62,230, 10, 30, 61,177, 27, 28, 62,219,240, 42, 61,242,216,120, 62,225, 40,124, 61,209,222,212, 62,240,123,238,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 16, 2,236,169, 32, 63, 5,188,235,
+ 63, 98, 74,252, 62,248,111,200, 63,112,105,197, 62,231, 49, 0, 63,107,190,118, 62,255, 57,150, 63, 96, 14, 53,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32, 62, 95, 99, 80, 63, 94,194,149,
+ 62, 62, 8, 58, 63, 89,154, 10, 62, 92, 24, 40, 63, 74, 82, 14, 62,112, 11,112, 63, 78,133,157,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32, 63, 5,188,235, 63, 98, 74,252, 63, 12,139,136,
+ 63,101,233,138, 63, 6, 45,116, 63,113,245,112, 62,248,111,200, 63,112,105,197,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32, 62, 36,219, 68, 63, 81,186,249, 62, 65,254, 28, 63, 70, 55, 20,
+ 62, 92, 24, 40, 63, 74, 82, 14, 62, 62, 8, 58, 63, 89,154, 10,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32, 63, 12,139,136, 63,101,233,138, 63, 12,130, 5, 63,108,216,149, 63, 6, 45,116,
+ 63,113,245,112, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5,
+ 0, 0, 0,112, 2,236,169, 32, 62, 36,219, 68, 63, 81,186,249, 62, 42, 1, 76, 63, 73,178, 39, 62, 65,254, 28, 63, 70, 55, 20,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0,112,
+ 2,236,169, 32, 63,103, 89,120, 63, 2, 76,105, 63, 93,154,106, 62,233, 26,226, 63,102,178, 46, 62,232,184,100, 63,106,134,244,
+ 62,246, 64,234,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32,
+ 61,242,216,120, 62,225, 40,124, 62, 33, 1,128, 62,226,210, 70, 61,234,128,116, 63, 0, 39,200, 61,209,222,212, 62,240,123,238,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 0, 2,236,169, 32, 62,245, 44,226,
+ 63, 96,140,129, 62,255, 57,150, 63, 96, 14, 53, 62,231, 49, 0, 63,107,190,118, 62,227,135, 42, 63,101, 2, 58,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32, 62, 95, 99, 80, 63, 94,194,149,
+ 62,112, 11,112, 63, 78,133,157, 62,120, 84, 74, 63, 83, 32,104, 62,122,103,110, 63, 92,255,236,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 5, 0, 0, 0,240, 2,236,169, 32, 63, 77,217,216, 62,157,228, 7, 63, 90,225,160,
+ 62,137,121,110, 63, 96, 25, 22, 62,149,248,246, 63, 90, 5,151, 62,167, 61,138,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 5, 0, 0, 0, 16, 2,236,169, 32, 62, 54,234, 64, 62,140,219,146, 62, 74,125,166, 62,130, 30,252,
+ 62,111,118,154, 62,152,108,120, 62, 66,251,194, 62,158,102,163,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 5, 0, 0, 0, 64, 0, 0, 77, 69, 0, 0, 1, 20, 2,236,208,112, 0, 0, 0, 50, 0, 0, 0, 1, 2,236,213, 64,
+ 2,236,203,160, 0, 0, 0, 0, 0, 0, 0, 0, 77, 69, 80,108, 97,110,101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,235,189,160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 2,230, 87, 96, 5, 32, 40, 32, 5, 32, 48, 32, 5, 30, 70, 32, 5, 32, 8, 32, 5, 32, 24, 32, 0, 0, 0, 0,
+ 5, 32, 62, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,236,209,176, 0, 0, 0, 1,
+ 0, 0, 0, 5, 0, 0, 0, 20, 0, 0, 0, 0, 2,236,210,224, 0, 0, 0, 1, 0, 0, 0, 5, 0, 0, 0, 12, 0, 0, 0, 0,
+ 2,236,212, 16, 0, 0, 0, 3, 0, 0, 0, 5, 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0,188, 0, 0, 1, 53, 0, 0, 0, 76,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 63, 76,204,213, 63, 76,204,255,182,104, 0, 0, 63,128, 0, 30, 63,128, 0,140,
+ 63,127,255,214, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 4, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 4, 2,230, 87, 96, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 1, 4, 2,236,209,176, 0, 0, 0,242, 0, 0, 0, 5, 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, 5, 32, 8, 32, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65, 0, 0, 14,176, 5, 32, 8, 32, 0, 0, 0, 56, 0, 0, 0,188, 63,230,102,133, 63,179, 51,208, 63,127,255,146,
+165,127, 0, 0, 90,129, 2,255, 63,230,102,133, 63, 25,154,206, 63,127,255,146,165,127, 0, 0, 90,129, 2,255, 63,179, 51, 81,
+ 63,179, 51,210, 63,127,255,148, 0, 0, 0, 0,127,255, 2,255, 63,128, 0, 28, 63,179, 51,212, 63,127,255,152, 0, 0, 0, 0,
+127,255, 2,255, 63, 25,153,207, 63,179, 51,214, 63,127,255,154, 0, 0, 0, 0,127,255, 2,255, 62, 76,205,152, 63,179, 51,216,
+ 63,127,255,156, 0, 0, 0, 0,127,255, 2,255, 63,179, 51, 80, 63,128, 0,158, 63,127,255,148, 0, 0, 0, 0,127,255, 2,255,
+ 63,128, 0, 27, 63,128, 0,160, 63,127,255,150, 0, 0, 0, 0,127,255, 2,255, 63, 25,153,204, 63,128, 0,162, 63,127,255,154,
+ 0, 0, 0, 0,127,255, 2,255, 62, 76,205,140, 63,128, 0,163, 63,127,255,156, 0, 0, 0, 0,127,255, 2,255, 63,179, 51, 80,
+ 63, 25,154,209, 63,127,255,148, 0, 0, 0, 0,127,255, 2,255, 63,128, 0, 27, 63, 25,154,213, 63,127,255,150, 0, 0, 0, 0,
+127,255, 2,255, 63, 25,153,204, 63, 25,154,217, 63,127,255,154, 0, 0, 0, 0,127,255, 2,255, 62, 76,205,140, 63, 25,154,221,
+ 63,127,255,156, 0, 0, 0, 0,127,255, 2,255, 63,179, 51, 80, 62, 76,209,160, 63,127,255,148, 0, 0, 0, 0,127,255, 2,255,
+ 63,128, 0, 27, 62, 76,209,176, 63,127,255,150, 0, 0, 0, 0,127,255, 2,255, 63, 25,153,204, 62, 76,209,188, 63,127,255,152,
+ 0, 0, 0, 0,127,255, 2,255, 62, 76,205,140, 62, 76,209,204, 63,127,255,154, 0, 0, 0, 0,127,255, 2,255, 62, 76,205,140,
+ 63,230,103, 8, 63,127,255,148, 0, 0,165,127, 90,129, 0,255, 63, 25,153,204, 63,230,103, 10, 63,127,255,146, 0, 0,165,127,
+ 90,129, 0,255, 63,128, 0, 27, 63,230,103, 10, 63,127,255,142, 0, 0,165,127, 90,129, 0,255, 63,179, 51, 80, 63,230,103, 12,
+ 63,127,255,140, 0, 0,165,127, 90,129, 0,255,190, 76,205,152, 63,230,103, 12, 63,127,255,140, 0, 0,165,127, 90,129, 0,255,
+190, 76,205,152, 62, 76,209,160, 63,127,255,148, 0, 0, 0, 0,127,255, 2,255,190, 76,205,152, 63, 25,154,209, 63,127,255,148,
+ 0, 0, 0, 0,127,255, 2,255,190, 76,205,152, 63,128, 0,158, 63,127,255,148, 0, 0, 0, 0,127,255, 2,255,190, 76,205,144,
+ 63,179, 51,210, 63,127,255,148, 0, 0, 0, 0,127,255, 2,255, 63,230,102,131, 63,230,103, 7, 63,127,255,148, 0, 0,165,127,
+ 90,129, 0,255, 63,230,102,131, 63,128, 0,160, 63,127,255,142,165,127, 0, 0, 90,129, 2,255, 63,230,102,127, 62, 76,208, 28,
+ 63,127,255,148,165,127, 0, 0, 90,129, 2,255,190, 76,205,146,190, 76,208, 72, 63,127,255,148, 0, 0, 0, 0,127,255, 2,255,
+ 62, 76,205,150,190, 76,208, 24, 63,127,255,156, 0, 0, 0, 0,127,255, 2,255, 63, 25,153,207,190, 76,208, 40, 63,127,255,154,
+ 0, 0, 0, 0,127,255, 2,255, 63,128, 0, 28,190, 76,208, 56, 63,127,255,152, 0, 0, 0, 0,127,255, 2,255, 63,179, 51, 81,
+190, 76,208, 72, 63,127,255,148, 0, 0, 0, 0,127,255, 2,255, 63,230,102,133,190, 76,208, 88, 63,127,255,146, 0, 0, 0, 0,
+127,255, 2,255, 63,230,102,133,190, 76,208, 88,191,128, 0, 4, 0, 0, 0, 0,127,255, 2,255, 63,179, 51, 81,190, 76,208, 72,
+191,128, 0, 3, 0, 0, 0, 0,127,255, 2,255, 63,128, 0, 28,190, 76,208, 56,191,128, 0, 1, 0, 0, 0, 0,127,255, 2,255,
+ 63, 25,153,207,190, 76,208, 40,191,128, 0, 0, 0, 0, 0, 0,127,255, 2,255, 62, 76,205,150,190, 76,208, 24,191,127,255,254,
+ 0, 0, 0, 0,127,255, 2,255,190, 76,205,146,190, 76,208, 72,191,128, 0, 3, 0, 0, 0, 0,127,255, 2,255, 63,230,102,127,
+ 62, 76,208, 28,191, 25,153,155,128, 1, 0, 0, 0, 0, 2,255, 63,230,102,131,190, 76,201,136,191, 25,153,159,128, 1, 0, 0,
+ 0, 0, 2,255, 63,230,102,127, 62, 76,208, 28,190, 76,204,193,128, 1, 0, 0, 0, 0, 2,255, 63,230,102,131,190, 76,201,136,
+190, 76,204,209,128, 1, 0, 0, 0, 0, 2,255, 63,230,102,127, 62, 76,208, 28, 62, 76,204,219,128, 1, 0, 0, 0, 0, 2,255,
+ 63,230,102,131,190, 76,201,136, 62, 76,204,203,128, 1, 0, 0, 0, 0, 2,255, 63,230,102,127, 62, 76,208, 28, 63, 25,153,159,
+128, 1, 0, 0, 0, 0, 2,255, 63,230,102,131,190, 76,201,136, 63, 25,153,155,128, 1, 0, 0, 0, 0, 2,255, 63,230,102,127,
+ 62, 76,208, 28,191,128, 0, 3,165,127, 0, 0, 90,129, 2,255, 63,230,102,131, 63,128, 0,160,191,128, 0, 6,165,127, 0, 0,
+ 90,129, 2,255, 63,230,102,131, 63,230,103, 7,191,128, 0, 3, 0, 0,165,127, 90,129, 0,255, 63,230,102,135, 63, 25,154,207,
+ 63, 25,153,151,128, 1, 0, 0, 0, 0, 2,255, 63,230,102,131, 63,128, 0,156, 63, 25,153,151,128, 1, 0, 0, 0, 0, 2,255,
+ 63,230,102,131, 63,179, 51,212, 63, 25,153,155,128, 1, 0, 0, 0, 0, 2,255, 63,230,102,131, 63,230,103, 7, 63, 25,153,159,
+165,127,165,127, 0, 0, 2,255, 63,230,102,135, 63, 25,154,207, 62, 76,204,171,128, 1, 0, 0, 0, 0, 2,255, 63,230,102,131,
+ 63,128, 0,160, 62, 76,204,187,128, 1, 0, 0, 0, 0, 2,255, 63,230,102,131, 63,179, 51,212, 62, 76,204,203,128, 1, 0, 0,
+ 0, 0, 2,255, 63,230,102,131, 63,230,103, 7, 62, 76,204,219,165,127,165,127, 0, 0, 2,255, 63,230,102,135, 63, 25,154,207,
+190, 76,204,241,128, 1, 0, 0, 0, 0, 2,255, 63,230,102,131, 63,128, 0,160,190, 76,204,225,128, 1, 0, 0, 0, 0, 2,255,
+ 63,230,102,131, 63,179, 51,212,190, 76,204,209,128, 1, 0, 0, 0, 0, 2,255, 63,230,102,131, 63,230,103, 7,190, 76,204,193,
+165,127,165,127, 0, 0, 2,255, 63,230,102,135, 63, 25,154,207,191, 25,153,167,128, 1, 0, 0, 0, 0, 2,255, 63,230,102,131,
+ 63,128, 0,160,191, 25,153,163,128, 1, 0, 0, 0, 0, 2,255, 63,230,102,131, 63,179, 51,212,191, 25,153,159,128, 1, 0, 0,
+ 0, 0, 2,255, 63,230,102,131, 63,230,103, 7,191, 25,153,155,165,127,165,127, 0, 0, 2,255,190, 76,205,144, 63,179, 51,210,
+191,128, 0, 3, 0, 0, 0, 0,127,255, 2,255,190, 76,205,152, 63,128, 0,158,191,128, 0, 3, 0, 0, 0, 0,127,255, 2,255,
+190, 76,205,152, 63, 25,154,209,191,128, 0, 3, 0, 0, 0, 0,127,255, 2,255,190, 76,205,152, 62, 76,209,160,191,128, 0, 3,
+ 0, 0, 0, 0,127,255, 2,255,190, 76,205,152, 63,230,103, 12,191, 25,153,168, 0, 0,128, 1, 0, 0, 2,255,190, 76,205,152,
+ 63,230,103, 12,190, 76,204,244, 0, 0,128, 1, 0, 0, 2,255,190, 76,205,152, 63,230,103, 12, 62, 76,204,168, 0, 0,128, 1,
+ 0, 0, 2,255,190, 76,205,144, 63,230,103, 12, 63, 25,153,150, 0, 0,128, 1, 0, 0, 2,255,190, 76,205,152, 63,230,103, 12,
+191,128, 0, 7, 0, 0,165,127, 90,129, 0,255, 63,179, 51, 80, 63,230,103, 12,191,128, 0, 7, 0, 0,165,127, 90,129, 0,255,
+ 63,128, 0, 27, 63,230,103, 10,191,128, 0, 6, 0, 0,165,127, 90,129, 0,255, 63, 25,153,204, 63,230,103, 10,191,128, 0, 4,
+ 0, 0,165,127, 90,129, 0,255, 62, 76,205,140, 63,230,103, 8,191,128, 0, 3, 0, 0,165,127, 90,129, 0,255, 63,179, 51, 81,
+ 63,230,103, 12, 63, 25,153,150, 0, 0,128, 1, 0, 0, 2,255, 63,128, 0, 28, 63,230,103, 10, 63, 25,153,150, 0, 0,128, 1,
+ 0, 0, 2,255, 63, 25,153,207, 63,230,103, 10, 63, 25,153,154, 0, 0,128, 1, 0, 0, 2,255, 62, 76,205,152, 63,230,103, 8,
+ 63, 25,153,158, 0, 0,128, 1, 0, 0, 2,255, 63,179, 51, 80, 63,230,103, 12, 62, 76,204,168, 0, 0,128, 1, 0, 0, 2,255,
+ 63,128, 0, 27, 63,230,103, 10, 62, 76,204,184, 0, 0,128, 1, 0, 0, 2,255, 63, 25,153,204, 63,230,103, 10, 62, 76,204,200,
+ 0, 0,128, 1, 0, 0, 2,255, 62, 76,205,140, 63,230,103, 8, 62, 76,204,216, 0, 0,128, 1, 0, 0, 2,255, 63,179, 51, 80,
+ 63,230,103, 12,190, 76,204,244, 0, 0,128, 1, 0, 0, 2,255, 63,128, 0, 27, 63,230,103, 10,190, 76,204,228, 0, 0,128, 1,
+ 0, 0, 2,255, 63, 25,153,204, 63,230,103, 10,190, 76,204,212, 0, 0,128, 1, 0, 0, 2,255, 62, 76,205,140, 63,230,103, 8,
+190, 76,204,196, 0, 0,128, 1, 0, 0, 2,255, 63,179, 51, 80, 63,230,103, 12,191, 25,153,168, 0, 0,128, 1, 0, 0, 2,255,
+ 63,128, 0, 27, 63,230,103, 10,191, 25,153,164, 0, 0,128, 1, 0, 0, 2,255, 63, 25,153,204, 63,230,103, 10,191, 25,153,160,
+ 0, 0,128, 1, 0, 0, 2,255, 62, 76,205,140, 63,230,103, 8,191, 25,153,156, 0, 0,128, 1, 0, 0, 2,255, 62, 76,205,140,
+ 62, 76,209,204,191,127,255,255, 0, 0, 0, 0,127,255, 2,255, 63, 25,153,204, 62, 76,209,188,191,128, 0, 1, 0, 0, 0, 0,
+127,255, 2,255, 63,128, 0, 27, 62, 76,209,176,191,128, 0, 2, 0, 0, 0, 0,127,255, 2,255, 63,179, 51, 80, 62, 76,209,160,
+191,128, 0, 3, 0, 0, 0, 0,127,255, 2,255, 62, 76,205,140, 63, 25,154,221,191,127,255,254, 0, 0, 0, 0,127,255, 2,255,
+ 63, 25,153,204, 63, 25,154,217,191,128, 0, 0, 0, 0, 0, 0,127,255, 2,255, 63,128, 0, 27, 63, 25,154,213,191,128, 0, 2,
+ 0, 0, 0, 0,127,255, 2,255, 63,179, 51, 80, 63, 25,154,209,191,128, 0, 3, 0, 0, 0, 0,127,255, 2,255, 62, 76,205,140,
+ 63,128, 0,163,191,127,255,254, 0, 0, 0, 0,127,255, 2,255, 63, 25,153,204, 63,128, 0,162,191,128, 0, 0, 0, 0, 0, 0,
+127,255, 2,255, 63,128, 0, 27, 63,128, 0,160,191,128, 0, 2, 0, 0, 0, 0,127,255, 2,255, 63,179, 51, 80, 63,128, 0,158,
+191,128, 0, 3, 0, 0, 0, 0,127,255, 2,255, 62, 76,205,152, 63,179, 51,216,191,127,255,254, 0, 0, 0, 0,127,255, 2,255,
+ 63, 25,153,207, 63,179, 51,214,191,128, 0, 0, 0, 0, 0, 0,127,255, 2,255, 63,128, 0, 28, 63,179, 51,212,191,128, 0, 1,
+ 0, 0, 0, 0,127,255, 2,255, 63,179, 51, 81, 63,179, 51,210,191,128, 0, 3, 0, 0, 0, 0,127,255, 2,255, 63,230,102,133,
+ 63, 25,154,206,191,128, 0, 4,165,127, 0, 0, 90,129, 2,255, 63,230,102,133, 63,179, 51,208,191,128, 0, 4,165,127, 0, 0,
+ 90,129, 2,255,190, 76,205,128, 62, 76,201,116,191,128, 0, 5,127,255, 0, 0, 0, 0, 16,255,190, 76,205,136, 63,127,255, 48,
+191,128, 0, 5,127,255, 0, 0, 0, 0, 16,255,190, 76,205,112,190, 76,208, 64,191, 25,153,156,127,255, 0, 0, 0, 0, 16,255,
+190, 76,205,112, 62, 76,201, 84,191, 25,153,160,127,255, 0, 0, 0, 0, 18,255,190, 76,205,120, 63, 25,152,190,191, 25,153,164,
+127,255, 0, 0, 0, 0, 18,255,190, 76,205,152, 63,127,255, 46,191, 25,153,168,127,255, 0, 0, 0, 0, 18,255,190, 76,205,112,
+190, 76,208, 64,190, 76,204,195,127,255, 0, 0, 0, 0, 16,255,190, 76,205,112, 62, 76,201, 84,190, 76,204,211,127,255, 0, 0,
+ 0, 0, 18,255,190, 76,205,120, 63, 25,152,190,190, 76,204,227,127,255, 0, 0, 0, 0, 18,255,190, 76,205,152, 63,127,255, 46,
+190, 76,204,243,127,255, 0, 0, 0, 0, 18,255,190, 76,205,112,190, 76,208, 64, 62, 76,204,221,127,255, 0, 0, 0, 0, 16,255,
+190, 76,205,112, 62, 76,201, 84, 62, 76,204,205,127,255, 0, 0, 0, 0, 18,255,190, 76,205,120, 63, 25,152,190, 62, 76,204,189,
+127,255, 0, 0, 0, 0, 18,255,190, 76,205,152, 63,127,255, 46, 62, 76,204,173,127,255, 0, 0, 0, 0, 18,255,190, 76,205,112,
+190, 76,208, 64, 63, 25,153,160,127,255, 0, 0, 0, 0, 16,255,190, 76,205,112, 62, 76,201, 84, 63, 25,153,156,127,255, 0, 0,
+ 0, 0, 18,255,190, 76,205,120, 63, 25,152,198, 63, 25,153,152,127,255, 0, 0, 0, 0, 18,255,190, 76,205,152, 63,127,255, 46,
+ 63, 25,153,152,127,255, 0, 0, 0, 0, 18,255,190, 76,205,112,190, 76,208, 64,191,128, 0, 4,231, 94,231, 94,132,215, 16,255,
+190, 76,205,120, 63, 25,152,190,191,128, 0, 7,127,255, 0, 0, 0, 0, 16,255,190, 76,205, 96, 63,179, 50,251,191,128, 0, 4,
+127,255, 0, 0, 0, 0, 16,255,190, 76,205,128, 63,230,102, 48, 63, 25,153,156,127,255, 0, 0, 0, 0, 18,255,190, 76,205, 96,
+ 63,179, 50,251, 63, 25,153,160,127,255, 0, 0, 0, 0, 18,255,190, 76,205,128, 63,230,102, 48, 62, 76,204,205,127,255, 0, 0,
+ 0, 0, 18,255,190, 76,205, 96, 63,179, 50,251, 62, 76,204,221,127,255, 0, 0, 0, 0, 18,255,190, 76,205,128, 63,230,102, 48,
+190, 76,204,211,127,255, 0, 0, 0, 0, 18,255,190, 76,205, 96, 63,179, 50,251,190, 76,204,195,127,255, 0, 0, 0, 0, 18,255,
+190, 76,205,128, 63,230,102, 48,191, 25,153,160,127,255, 0, 0, 0, 0, 18,255,190, 76,205, 96, 63,179, 50,251,191, 25,153,156,
+127,255, 0, 0, 0, 0, 18,255,190, 76,205,144, 63,230,103, 10,191,128, 0, 5,243,161,111, 93,194, 34, 16,255,190, 76,205,144,
+ 63,230,103, 10, 63,127,255,148,243,161,111, 93, 61,222, 16,255,190, 76,205, 96, 63,179, 50,251, 63,127,255,150,127,255, 0, 0,
+ 0, 0, 16,255,190, 76,205,120, 63, 25,152,190, 63,127,255,144,127,255, 0, 0, 0, 0, 16,255,190, 76,205,112,190, 76,208, 64,
+ 63,127,255,150,231, 94,231, 94,123, 41, 16,255,190, 76,205,136, 63,127,255, 48, 63,127,255,148,127,255, 0, 0, 0, 0, 16,255,
+190, 76,205,128, 62, 76,201,116, 63,127,255,148,127,255, 0, 0, 0, 0, 16,255, 63,179, 51, 36,190, 76,208, 56,191, 25,153,157,
+ 0, 0,127,255, 0, 0, 3,255, 63,127,255,222,190, 76,208, 80,191, 25,153,161, 0, 0,127,255, 0, 0, 3,255, 63, 25,153,116,
+190, 76,208, 80,191, 25,153,165, 0, 0,127,255, 0, 0, 3,255, 62, 76,204, 44,190, 76,208,104,191, 25,153,169, 0, 0,127,255,
+ 0, 0, 3,255, 63,179, 51, 36,190, 76,208, 56,190, 76,204,198, 0, 0,127,255, 0, 0, 3,255, 63,127,255,222,190, 76,208, 80,
+190, 76,204,214, 0, 0,127,255, 0, 0, 3,255, 63, 25,153,116,190, 76,208, 80,190, 76,204,230, 0, 0,127,255, 0, 0, 3,255,
+ 62, 76,204, 44,190, 76,208,104,190, 76,204,246, 0, 0,127,255, 0, 0, 3,255, 63,179, 51, 36,190, 76,208, 56, 62, 76,204,218,
+ 0, 0,127,255, 0, 0, 3,255, 63,127,255,222,190, 76,208, 80, 62, 76,204,202, 0, 0,127,255, 0, 0, 3,255, 63, 25,153,116,
+190, 76,208, 80, 62, 76,204,186, 0, 0,127,255, 0, 0, 3,255, 62, 76,204, 44,190, 76,208,104, 62, 76,204,170, 0, 0,127,255,
+ 0, 0, 3,255, 63,179, 51, 34,190, 76,208, 56, 63, 25,153,159, 0, 0,127,255, 0, 0, 3,255, 63,127,255,220,190, 76,208, 80,
+ 63, 25,153,155, 0, 0,127,255, 0, 0, 3,255, 63, 25,153,114,190, 76,208, 80, 63, 25,153,151, 0, 0,127,255, 0, 0, 3,255,
+ 62, 76,204, 36,190, 76,208,104, 63, 25,153,151, 0, 0,127,255, 0, 0, 3,255, 63,179, 51, 36,190, 76,208, 56,191,128, 0, 4,
+ 0, 0,127,255, 0, 0, 3,255, 63,127,255,222,190, 76,208, 80,191,128, 0, 5, 0, 0,127,255, 0, 0, 3,255, 63, 25,153,116,
+190, 76,208, 80,191,128, 0, 7, 0, 0,127,255, 0, 0, 3,255, 62, 76,204, 44,190, 76,208,104,191,128, 0, 8, 0, 0,127,255,
+ 0, 0, 3,255, 63,230,102,136,190, 76,208, 88,191,128, 0, 8, 0, 0,127,255, 0, 0, 3,255, 63,230,102,135,190, 76,208, 88,
+ 63, 25,153,151, 0, 0,127,255, 0, 0, 3,255, 63,230,102,136,190, 76,208, 88, 62, 76,204,170, 0, 0,127,255, 0, 0, 3,255,
+ 63,230,102,136,190, 76,208, 88,190, 76,204,246, 0, 0,127,255, 0, 0, 3,255, 63,230,102,136,190, 76,208, 88,191, 25,153,169,
+ 0, 0,127,255, 0, 0, 3,255,190, 76,205,112,190, 76,208, 64,191, 25,153,156, 0, 0,127,255, 0, 0, 1,255,190, 76,205,112,
+190, 76,208, 64,190, 76,204,195, 0, 0,127,255, 0, 0, 1,255,190, 76,205,112,190, 76,208, 64, 62, 76,204,221, 0, 0,127,255,
+ 0, 0, 1,255,190, 76,205,112,190, 76,208, 64, 63, 25,153,160, 0, 0,127,255, 0, 0, 1,255,190, 76,205,112,190, 76,208, 64,
+191,128, 0, 4, 0, 0,127,255, 0, 0, 3,255,190, 76,205,112,190, 76,208, 64, 63,127,255,150, 0, 0,127,255, 0, 0, 3,255,
+ 63,230,102,136,190, 76,208, 88, 63,127,255,142, 0, 0,127,255, 0, 0, 3,255, 62, 76,204, 44,190, 76,208,104, 63,127,255,142,
+ 0, 0,127,255, 0, 0, 3,255, 63, 25,153,116,190, 76,208, 80, 63,127,255,144, 0, 0,127,255, 0, 0, 3,255, 63,127,255,222,
+190, 76,208, 80, 63,127,255,148, 0, 0,127,255, 0, 0, 3,255, 63,179, 51, 36,190, 76,208, 56, 63,127,255,150, 0, 0,127,255,
+ 0, 0, 3,255, 68, 65, 84, 65, 0, 0, 1, 4, 2,236,210,224, 0, 0, 0,242, 0, 0, 0, 5, 0, 0, 0, 3, 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, 5, 32, 24, 32, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+ 0, 0, 14,124, 5, 32, 24, 32, 0, 0, 0, 53, 0, 0, 1, 53, 0, 0, 0, 21, 0, 0, 0, 82, 0, 0, 0, 34, 0, 0, 0, 20,
+ 0, 0, 0, 83, 0, 0, 0, 34, 0, 0, 0, 19, 0, 0, 0, 84, 0, 0, 0, 34, 0, 0, 0, 18, 0, 0, 0, 85, 0, 0, 0, 34,
+ 0, 0, 0, 22, 0, 0, 0, 76, 0, 0, 0, 34, 0, 0, 0, 1, 0, 0, 0, 53, 0, 0, 0, 34, 0, 0, 0, 28, 0, 0, 0, 54,
+ 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, 34, 0, 0, 0, 27, 0, 0, 0, 56, 0, 0, 0, 34, 0, 0, 0, 29,
+ 0, 0, 0, 48, 0, 0, 0, 34, 0, 0, 0, 4, 0, 0, 0, 5, 0, 0, 0, 34, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, 34,
+ 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 34, 0, 0, 0, 5, 0, 0, 0, 9,
+ 0, 0, 0, 34, 0, 0, 0, 8, 0, 0, 0, 9, 0, 0, 0, 34, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 34, 0, 0, 0, 7,
+ 0, 0, 0, 8, 0, 0, 0, 34, 0, 0, 0, 3, 0, 0, 0, 7, 0, 0, 0, 34, 0, 0, 0, 6, 0, 0, 0, 7, 0, 0, 0, 34,
+ 0, 0, 0, 2, 0, 0, 0, 6, 0, 0, 0, 34, 0, 0, 0, 9, 0, 0, 0, 13, 0, 0, 0, 34, 0, 0, 0, 12, 0, 0, 0, 13,
+ 0, 0, 0, 34, 0, 0, 0, 8, 0, 0, 0, 12, 0, 0, 0, 34, 0, 0, 0, 11, 0, 0, 0, 12, 0, 0, 0, 34, 0, 0, 0, 7,
+ 0, 0, 0, 11, 0, 0, 0, 34, 0, 0, 0, 10, 0, 0, 0, 11, 0, 0, 0, 34, 0, 0, 0, 6, 0, 0, 0, 10, 0, 0, 0, 34,
+ 0, 0, 0, 1, 0, 0, 0, 10, 0, 0, 0, 34, 0, 0, 0, 13, 0, 0, 0, 17, 0, 0, 0, 34, 0, 0, 0, 16, 0, 0, 0, 17,
+ 0, 0, 0, 34, 0, 0, 0, 12, 0, 0, 0, 16, 0, 0, 0, 34, 0, 0, 0, 15, 0, 0, 0, 16, 0, 0, 0, 34, 0, 0, 0, 11,
+ 0, 0, 0, 15, 0, 0, 0, 34, 0, 0, 0, 14, 0, 0, 0, 15, 0, 0, 0, 34, 0, 0, 0, 10, 0, 0, 0, 14, 0, 0, 0, 34,
+ 0, 0, 0, 19, 0, 0, 0, 20, 0, 0, 0, 34, 0, 0, 0, 2, 0, 0, 0, 21, 0, 0, 0, 34, 0, 0, 0, 3, 0, 0, 0, 20,
+ 0, 0, 0, 34, 0, 0, 0, 4, 0, 0, 0, 19, 0, 0, 0, 34, 0, 0, 0, 5, 0, 0, 0, 18, 0, 0, 0, 34, 0, 0, 0, 22,
+ 0, 0, 0, 26, 0, 0, 0, 34, 0, 0, 0, 24, 0, 0, 0, 25, 0, 0, 0, 34, 0, 0, 0, 18, 0, 0, 0, 22, 0, 0, 0, 34,
+ 0, 0, 0, 17, 0, 0, 0, 23, 0, 0, 0, 34, 0, 0, 0, 13, 0, 0, 0, 24, 0, 0, 0, 34, 0, 0, 0, 9, 0, 0, 0, 25,
+ 0, 0, 0, 34, 0, 0, 0, 5, 0, 0, 0, 26, 0, 0, 0, 34, 0, 0, 0, 1, 0, 0, 0, 28, 0, 0, 0, 34, 0, 0, 0, 0,
+ 0, 0, 0, 28, 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 34, 0, 0, 0, 1, 0, 0, 0, 29, 0, 0, 0, 34,
+ 0, 0, 0, 21, 0, 0, 0, 27, 0, 0, 0, 34, 0, 0, 0, 14, 0, 0, 0, 29, 0, 0, 0, 34, 0, 0, 0, 6, 0, 0, 0, 28,
+ 0, 0, 0, 34, 0, 0, 0, 30, 0, 0, 0, 31, 0, 0, 0, 34, 0, 0, 0, 34, 0, 0, 0, 35, 0, 0, 0, 34, 0, 0, 0, 32,
+ 0, 0, 0, 33, 0, 0, 0, 34, 0, 0, 0, 29, 0, 0, 0, 35, 0, 0, 0, 34, 0, 0, 0, 23, 0, 0, 0, 30, 0, 0, 0, 34,
+ 0, 0, 0, 14, 0, 0, 0, 34, 0, 0, 0, 34, 0, 0, 0, 15, 0, 0, 0, 33, 0, 0, 0, 34, 0, 0, 0, 16, 0, 0, 0, 32,
+ 0, 0, 0, 34, 0, 0, 0, 17, 0, 0, 0, 31, 0, 0, 0, 34, 0, 0, 0, 40, 0, 0, 0, 98, 0, 0, 0, 34, 0, 0, 0, 39,
+ 0, 0, 0, 99, 0, 0, 0, 34, 0, 0, 0, 38, 0, 0, 0,100, 0, 0, 0, 34, 0, 0, 0, 37, 0, 0, 0,101, 0, 0, 0, 34,
+ 0, 0, 0, 41, 0, 0, 0, 72, 0, 0, 0, 34, 0, 0, 0, 36, 0, 0, 0, 50, 0, 0, 0, 34, 0, 0, 0, 38, 0, 0, 0, 39,
+ 0, 0, 0, 34, 0, 0, 0, 36, 0, 0, 0, 37, 0, 0, 0, 34, 0, 0, 0, 40, 0, 0, 0, 41, 0, 0, 0, 34, 0, 0, 0, 51,
+ 0, 0, 0,109, 0, 0, 0, 34, 0, 0, 0, 50, 0, 0, 0,101, 0, 0, 0, 34, 0, 0, 0, 68, 0, 0, 0, 94, 0, 0, 0, 34,
+ 0, 0, 0, 64, 0, 0, 0, 90, 0, 0, 0, 34, 0, 0, 0, 60, 0, 0, 0, 86, 0, 0, 0, 34, 0, 0, 0, 56, 0, 0, 0, 82,
+ 0, 0, 0, 34, 0, 0, 0, 52, 0, 0, 0, 78, 0, 0, 0, 34, 0, 0, 0, 50, 0, 0, 0,114, 0, 0, 0, 34, 0, 0, 0, 65,
+ 0, 0, 0,114, 0, 0, 0, 34, 0, 0, 0, 67, 0, 0, 0,115, 0, 0, 0, 34, 0, 0, 0, 52, 0, 0, 0,115, 0, 0, 0, 34,
+ 0, 0, 0, 51, 0, 0, 0,115, 0, 0, 0, 34, 0, 0, 0, 51, 0, 0, 0,114, 0, 0, 0, 34, 0, 0, 0, 42, 0, 0, 0, 50,
+ 0, 0, 0, 34, 0, 0, 0, 43, 0, 0, 0, 45, 0, 0, 0, 34, 0, 0, 0, 42, 0, 0, 0, 43, 0, 0, 0, 34, 0, 0, 0, 42,
+ 0, 0, 0, 44, 0, 0, 0, 34, 0, 0, 0, 44, 0, 0, 0, 45, 0, 0, 0, 34, 0, 0, 0, 44, 0, 0, 0, 46, 0, 0, 0, 34,
+ 0, 0, 0, 47, 0, 0, 0, 49, 0, 0, 0, 34, 0, 0, 0, 46, 0, 0, 0, 47, 0, 0, 0, 34, 0, 0, 0, 46, 0, 0, 0, 48,
+ 0, 0, 0, 34, 0, 0, 0, 48, 0, 0, 0, 49, 0, 0, 0, 34, 0, 0, 0, 55, 0, 0, 0, 56, 0, 0, 0, 34, 0, 0, 0, 54,
+ 0, 0, 0, 55, 0, 0, 0, 34, 0, 0, 0, 53, 0, 0, 0, 54, 0, 0, 0, 34, 0, 0, 0, 56, 0, 0, 0, 60, 0, 0, 0, 34,
+ 0, 0, 0, 59, 0, 0, 0, 60, 0, 0, 0, 34, 0, 0, 0, 55, 0, 0, 0, 59, 0, 0, 0, 34, 0, 0, 0, 58, 0, 0, 0, 59,
+ 0, 0, 0, 34, 0, 0, 0, 54, 0, 0, 0, 58, 0, 0, 0, 34, 0, 0, 0, 57, 0, 0, 0, 58, 0, 0, 0, 34, 0, 0, 0, 53,
+ 0, 0, 0, 57, 0, 0, 0, 34, 0, 0, 0, 60, 0, 0, 0, 64, 0, 0, 0, 34, 0, 0, 0, 63, 0, 0, 0, 64, 0, 0, 0, 34,
+ 0, 0, 0, 59, 0, 0, 0, 63, 0, 0, 0, 34, 0, 0, 0, 62, 0, 0, 0, 63, 0, 0, 0, 34, 0, 0, 0, 58, 0, 0, 0, 62,
+ 0, 0, 0, 34, 0, 0, 0, 61, 0, 0, 0, 62, 0, 0, 0, 34, 0, 0, 0, 57, 0, 0, 0, 61, 0, 0, 0, 34, 0, 0, 0, 64,
+ 0, 0, 0, 68, 0, 0, 0, 34, 0, 0, 0, 67, 0, 0, 0, 68, 0, 0, 0, 34, 0, 0, 0, 63, 0, 0, 0, 67, 0, 0, 0, 34,
+ 0, 0, 0, 66, 0, 0, 0, 67, 0, 0, 0, 34, 0, 0, 0, 62, 0, 0, 0, 66, 0, 0, 0, 34, 0, 0, 0, 65, 0, 0, 0, 66,
+ 0, 0, 0, 34, 0, 0, 0, 61, 0, 0, 0, 65, 0, 0, 0, 34, 0, 0, 0, 52, 0, 0, 0, 68, 0, 0, 0, 34, 0, 0, 0, 51,
+ 0, 0, 0, 66, 0, 0, 0, 34, 0, 0, 0, 48, 0, 0, 0, 53, 0, 0, 0, 34, 0, 0, 0, 46, 0, 0, 0, 57, 0, 0, 0, 34,
+ 0, 0, 0, 44, 0, 0, 0, 61, 0, 0, 0, 34, 0, 0, 0, 42, 0, 0, 0, 65, 0, 0, 0, 34, 0, 0, 0, 69, 0, 0, 0,110,
+ 0, 0, 0, 34, 0, 0, 0, 70, 0, 0, 0,106, 0, 0, 0, 34, 0, 0, 0, 71, 0, 0, 0,102, 0, 0, 0, 34, 0, 0, 0, 72,
+ 0, 0, 0, 98, 0, 0, 0, 34, 0, 0, 0, 73, 0, 0, 0, 97, 0, 0, 0, 34, 0, 0, 0, 74, 0, 0, 0, 93, 0, 0, 0, 34,
+ 0, 0, 0, 75, 0, 0, 0, 89, 0, 0, 0, 34, 0, 0, 0, 76, 0, 0, 0, 85, 0, 0, 0, 34, 0, 0, 0, 77, 0, 0, 0, 81,
+ 0, 0, 0, 34, 0, 0, 0, 70, 0, 0, 0, 71, 0, 0, 0, 34, 0, 0, 0, 73, 0, 0, 0, 77, 0, 0, 0, 34, 0, 0, 0, 74,
+ 0, 0, 0, 75, 0, 0, 0, 34, 0, 0, 0, 69, 0, 0, 0, 77, 0, 0, 0, 34, 0, 0, 0, 81, 0, 0, 0,110, 0, 0, 0, 34,
+ 0, 0, 0, 80, 0, 0, 0,111, 0, 0, 0, 34, 0, 0, 0, 79, 0, 0, 0,112, 0, 0, 0, 34, 0, 0, 0, 78, 0, 0, 0,113,
+ 0, 0, 0, 34, 0, 0, 0, 79, 0, 0, 0, 80, 0, 0, 0, 34, 0, 0, 0, 84, 0, 0, 0, 85, 0, 0, 0, 34, 0, 0, 0, 83,
+ 0, 0, 0, 84, 0, 0, 0, 34, 0, 0, 0, 82, 0, 0, 0, 83, 0, 0, 0, 34, 0, 0, 0, 85, 0, 0, 0, 89, 0, 0, 0, 34,
+ 0, 0, 0, 88, 0, 0, 0, 89, 0, 0, 0, 34, 0, 0, 0, 84, 0, 0, 0, 88, 0, 0, 0, 34, 0, 0, 0, 87, 0, 0, 0, 88,
+ 0, 0, 0, 34, 0, 0, 0, 83, 0, 0, 0, 87, 0, 0, 0, 34, 0, 0, 0, 86, 0, 0, 0, 87, 0, 0, 0, 34, 0, 0, 0, 82,
+ 0, 0, 0, 86, 0, 0, 0, 34, 0, 0, 0, 89, 0, 0, 0, 93, 0, 0, 0, 34, 0, 0, 0, 92, 0, 0, 0, 93, 0, 0, 0, 34,
+ 0, 0, 0, 88, 0, 0, 0, 92, 0, 0, 0, 34, 0, 0, 0, 91, 0, 0, 0, 92, 0, 0, 0, 34, 0, 0, 0, 87, 0, 0, 0, 91,
+ 0, 0, 0, 34, 0, 0, 0, 90, 0, 0, 0, 91, 0, 0, 0, 34, 0, 0, 0, 86, 0, 0, 0, 90, 0, 0, 0, 34, 0, 0, 0, 93,
+ 0, 0, 0, 97, 0, 0, 0, 34, 0, 0, 0, 96, 0, 0, 0, 97, 0, 0, 0, 34, 0, 0, 0, 92, 0, 0, 0, 96, 0, 0, 0, 34,
+ 0, 0, 0, 95, 0, 0, 0, 96, 0, 0, 0, 34, 0, 0, 0, 91, 0, 0, 0, 95, 0, 0, 0, 34, 0, 0, 0, 94, 0, 0, 0, 95,
+ 0, 0, 0, 34, 0, 0, 0, 90, 0, 0, 0, 94, 0, 0, 0, 34, 0, 0, 0, 81, 0, 0, 0, 97, 0, 0, 0, 34, 0, 0, 0, 80,
+ 0, 0, 0, 96, 0, 0, 0, 34, 0, 0, 0, 79, 0, 0, 0, 95, 0, 0, 0, 34, 0, 0, 0, 78, 0, 0, 0, 94, 0, 0, 0, 34,
+ 0, 0, 0,101, 0, 0, 0,105, 0, 0, 0, 34, 0, 0, 0,100, 0, 0, 0,101, 0, 0, 0, 34, 0, 0, 0,100, 0, 0, 0,104,
+ 0, 0, 0, 34, 0, 0, 0, 99, 0, 0, 0,100, 0, 0, 0, 34, 0, 0, 0, 99, 0, 0, 0,103, 0, 0, 0, 34, 0, 0, 0, 98,
+ 0, 0, 0, 99, 0, 0, 0, 34, 0, 0, 0, 98, 0, 0, 0,102, 0, 0, 0, 34, 0, 0, 0,105, 0, 0, 0,114, 0, 0, 0, 34,
+ 0, 0, 0,105, 0, 0, 0,109, 0, 0, 0, 34, 0, 0, 0,104, 0, 0, 0,105, 0, 0, 0, 34, 0, 0, 0,104, 0, 0, 0,108,
+ 0, 0, 0, 34, 0, 0, 0,103, 0, 0, 0,104, 0, 0, 0, 34, 0, 0, 0,103, 0, 0, 0,107, 0, 0, 0, 34, 0, 0, 0,102,
+ 0, 0, 0,103, 0, 0, 0, 34, 0, 0, 0,102, 0, 0, 0,106, 0, 0, 0, 34, 0, 0, 0,109, 0, 0, 0,113, 0, 0, 0, 34,
+ 0, 0, 0,108, 0, 0, 0,109, 0, 0, 0, 34, 0, 0, 0,108, 0, 0, 0,112, 0, 0, 0, 34, 0, 0, 0,107, 0, 0, 0,108,
+ 0, 0, 0, 34, 0, 0, 0,107, 0, 0, 0,111, 0, 0, 0, 34, 0, 0, 0,106, 0, 0, 0,107, 0, 0, 0, 34, 0, 0, 0,106,
+ 0, 0, 0,110, 0, 0, 0, 34, 0, 0, 0,113, 0, 0, 0,115, 0, 0, 0, 34, 0, 0, 0,112, 0, 0, 0,113, 0, 0, 0, 34,
+ 0, 0, 0,111, 0, 0, 0,112, 0, 0, 0, 34, 0, 0, 0,110, 0, 0, 0,111, 0, 0, 0, 34, 0, 0, 0,121, 0, 0, 0,144,
+ 0, 0, 0, 50, 0, 0, 0,125, 0, 0, 0,142, 0, 0, 0, 50, 0, 0, 0,129, 0, 0, 0,140, 0, 0, 0, 50, 0, 0, 0,133,
+ 0, 0, 0,138, 0, 0, 0, 50, 0, 0, 0,120, 0, 0, 0,135, 0, 0, 0, 50, 0, 0, 0,118, 0, 0, 0,134, 0, 0, 0,178,
+ 0, 0, 0,121, 0, 0, 0,125, 0, 0, 0, 50, 0, 0, 0,120, 0, 0, 0,121, 0, 0, 0, 50, 0, 0, 0,120, 0, 0, 0,124,
+ 0, 0, 0, 50, 0, 0, 0,120, 0, 0, 0,119, 0, 0, 0, 50, 0, 0, 0,119, 0, 0, 0,123, 0, 0, 0, 50, 0, 0, 0,118,
+ 0, 0, 0,119, 0, 0, 0, 50, 0, 0, 0,118, 0, 0, 0,122, 0, 0, 0, 50, 0, 0, 0,125, 0, 0, 0,129, 0, 0, 0, 50,
+ 0, 0, 0,124, 0, 0, 0,125, 0, 0, 0, 50, 0, 0, 0,124, 0, 0, 0,128, 0, 0, 0, 50, 0, 0, 0,123, 0, 0, 0,124,
+ 0, 0, 0, 50, 0, 0, 0,123, 0, 0, 0,127, 0, 0, 0, 50, 0, 0, 0,122, 0, 0, 0,123, 0, 0, 0, 50, 0, 0, 0,122,
+ 0, 0, 0,126, 0, 0, 0,178, 0, 0, 0,129, 0, 0, 0,133, 0, 0, 0, 50, 0, 0, 0,128, 0, 0, 0,129, 0, 0, 0, 50,
+ 0, 0, 0,128, 0, 0, 0,132, 0, 0, 0, 50, 0, 0, 0,127, 0, 0, 0,128, 0, 0, 0, 50, 0, 0, 0,127, 0, 0, 0,131,
+ 0, 0, 0, 50, 0, 0, 0,126, 0, 0, 0,127, 0, 0, 0, 50, 0, 0, 0,126, 0, 0, 0,130, 0, 0, 0, 50, 0, 0, 0,132,
+ 0, 0, 0,133, 0, 0, 0, 50, 0, 0, 0,131, 0, 0, 0,132, 0, 0, 0, 50, 0, 0, 0,130, 0, 0, 0,131, 0, 0, 0, 50,
+ 0, 0, 0,137, 0, 0, 0,138, 0, 0, 0, 50, 0, 0, 0,138, 0, 0, 0,140, 0, 0, 0, 50, 0, 0, 0,139, 0, 0, 0,140,
+ 0, 0, 0, 50, 0, 0, 0,137, 0, 0, 0,139, 0, 0, 0, 50, 0, 0, 0,140, 0, 0, 0,142, 0, 0, 0, 50, 0, 0, 0,141,
+ 0, 0, 0,142, 0, 0, 0, 50, 0, 0, 0,142, 0, 0, 0,144, 0, 0, 0, 50, 0, 0, 0,143, 0, 0, 0,144, 0, 0, 0, 50,
+ 0, 0, 0,141, 0, 0, 0,143, 0, 0, 0, 50, 0, 0, 0,136, 0, 0, 0,144, 0, 0, 0, 50, 0, 0, 0,117, 0, 0, 0,135,
+ 0, 0, 0,178, 0, 0, 0,116, 0, 0, 0,135, 0, 0, 0, 50, 0, 0, 0,116, 0, 0, 0,134, 0, 0, 0,178, 0, 0, 0,119,
+ 0, 0, 0,116, 0, 0, 0, 50, 0, 0, 0,117, 0, 0, 0,121, 0, 0, 0, 50, 0, 0, 0,117, 0, 0, 0,136, 0, 0, 0, 50,
+ 0, 0, 0,136, 0, 0, 0,145, 0, 0, 0,178, 0, 0, 0,146, 0, 0, 0,147, 0, 0, 0,178, 0, 0, 0,147, 0, 0, 0,150,
+ 0, 0, 0, 50, 0, 0, 0,149, 0, 0, 0,151, 0, 0, 0,178, 0, 0, 0,148, 0, 0, 0,151, 0, 0, 0, 50, 0, 0, 0,148,
+ 0, 0, 0,150, 0, 0, 0,178, 0, 0, 0,138, 0, 0, 0,147, 0, 0, 0, 50, 0, 0, 0,130, 0, 0, 0,149, 0, 0, 0,178,
+ 0, 0, 0,131, 0, 0, 0,151, 0, 0, 0, 50, 0, 0, 0,132, 0, 0, 0,148, 0, 0, 0, 50, 0, 0, 0,133, 0, 0, 0,150,
+ 0, 0, 0, 50, 0, 0, 0,155, 0, 0, 0,171, 0, 0, 0, 35, 0, 0, 0,154, 0, 0, 0,170, 0, 0, 0, 35, 0, 0, 0,153,
+ 0, 0, 0,169, 0, 0, 0, 35, 0, 0, 0,152, 0, 0, 0,168, 0, 0, 0, 35, 0, 0, 0,155, 0, 0, 0,159, 0, 0, 0, 35,
+ 0, 0, 0,154, 0, 0, 0,155, 0, 0, 0, 35, 0, 0, 0,154, 0, 0, 0,158, 0, 0, 0, 35, 0, 0, 0,153, 0, 0, 0,154,
+ 0, 0, 0, 35, 0, 0, 0,153, 0, 0, 0,157, 0, 0, 0, 35, 0, 0, 0,152, 0, 0, 0,153, 0, 0, 0, 35, 0, 0, 0,152,
+ 0, 0, 0,156, 0, 0, 0, 35, 0, 0, 0,159, 0, 0, 0,163, 0, 0, 0, 35, 0, 0, 0,158, 0, 0, 0,159, 0, 0, 0, 35,
+ 0, 0, 0,158, 0, 0, 0,162, 0, 0, 0, 35, 0, 0, 0,157, 0, 0, 0,158, 0, 0, 0, 35, 0, 0, 0,157, 0, 0, 0,161,
+ 0, 0, 0, 35, 0, 0, 0,156, 0, 0, 0,157, 0, 0, 0, 35, 0, 0, 0,156, 0, 0, 0,160, 0, 0, 0, 35, 0, 0, 0,163,
+ 0, 0, 0,167, 0, 0, 0, 35, 0, 0, 0,162, 0, 0, 0,163, 0, 0, 0, 35, 0, 0, 0,162, 0, 0, 0,166, 0, 0, 0, 35,
+ 0, 0, 0,161, 0, 0, 0,162, 0, 0, 0, 35, 0, 0, 0,161, 0, 0, 0,165, 0, 0, 0, 35, 0, 0, 0,160, 0, 0, 0,161,
+ 0, 0, 0, 35, 0, 0, 0,160, 0, 0, 0,164, 0, 0, 0, 35, 0, 0, 0,166, 0, 0, 0,167, 0, 0, 0, 35, 0, 0, 0,165,
+ 0, 0, 0,166, 0, 0, 0, 35, 0, 0, 0,164, 0, 0, 0,165, 0, 0, 0, 35, 0, 0, 0,169, 0, 0, 0,170, 0, 0, 0, 35,
+ 0, 0, 0,174, 0, 0, 0,175, 0, 0, 0, 35, 0, 0, 0,172, 0, 0, 0,176, 0, 0, 0, 35, 0, 0, 0,168, 0, 0, 0,172,
+ 0, 0, 0, 35, 0, 0, 0,164, 0, 0, 0,173, 0, 0, 0, 35, 0, 0, 0,160, 0, 0, 0,174, 0, 0, 0, 35, 0, 0, 0,156,
+ 0, 0, 0,175, 0, 0, 0, 35, 0, 0, 0,152, 0, 0, 0,176, 0, 0, 0, 35, 0, 0, 0,177, 0, 0, 0,181, 0, 0, 0, 35,
+ 0, 0, 0,177, 0, 0, 0,178, 0, 0, 0,163, 0, 0, 0,178, 0, 0, 0,179, 0, 0, 0, 35, 0, 0, 0,179, 0, 0, 0,180,
+ 0, 0, 0,163, 0, 0, 0,171, 0, 0, 0,181, 0, 0, 0, 35, 0, 0, 0,167, 0, 0, 0,180, 0, 0, 0, 35, 0, 0, 0,163,
+ 0, 0, 0,179, 0, 0, 0, 35, 0, 0, 0,159, 0, 0, 0,178, 0, 0, 0, 35, 0, 0, 0,155, 0, 0, 0,177, 0, 0, 0, 35,
+ 0, 0, 0,182, 0, 0, 0,184, 0, 0, 0, 35, 0, 0, 0,183, 0, 0, 0,187, 0, 0, 0, 35, 0, 0, 0,185, 0, 0, 0,186,
+ 0, 0, 0, 35, 0, 0, 0,180, 0, 0, 0,182, 0, 0, 0, 35, 0, 0, 0,173, 0, 0, 0,183, 0, 0, 0, 35, 0, 0, 0,164,
+ 0, 0, 0,187, 0, 0, 0, 35, 0, 0, 0,165, 0, 0, 0,186, 0, 0, 0, 35, 0, 0, 0,166, 0, 0, 0,185, 0, 0, 0, 35,
+ 0, 0, 0,167, 0, 0, 0,184, 0, 0, 0, 35, 68, 65, 84, 65, 0, 0, 1, 4, 2,236,212, 16, 0, 0, 0,242, 0, 0, 0, 5,
+ 0, 0, 0, 4, 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, 5, 32, 40, 32, 0, 0, 0, 5, 0, 0, 0, 20, 0, 0, 0, 0,
+ 0, 0, 0, 0, 85, 86, 84,101,120, 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, 5, 32, 48, 32, 0, 0, 0, 6, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 67,111,108, 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, 5, 32, 62, 32, 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, 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, 68, 65, 84, 65, 0, 0, 5,240, 5, 32, 40, 32, 0, 0, 0, 52, 0, 0, 0, 76, 0, 0, 0, 18, 0, 0, 0, 22,
+ 0, 0, 0, 26, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 19, 0, 0, 0, 4, 0, 0, 0, 3, 0, 0, 0, 0,
+ 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 5, 0, 0, 0, 9,
+ 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 7, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 9,
+ 0, 0, 0, 25, 0, 0, 0, 24, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 8, 0, 0, 0, 12, 0, 0, 0, 11,
+ 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 0, 6, 0, 0, 0, 10, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 13,
+ 0, 0, 0, 17, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 11, 0, 0, 0, 15, 0, 0, 0, 14, 0, 0, 0, 0,
+ 0, 0, 0, 17, 0, 0, 0, 23, 0, 0, 0, 30, 0, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 16, 0, 0, 0, 32,
+ 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 34, 0, 0, 0, 35, 0, 0, 0, 29, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 42,
+ 0, 0, 0, 65, 0, 0, 0,114, 0, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 45, 0, 0, 0, 44, 0, 0, 0, 42, 0, 0, 0, 43,
+ 0, 0, 0, 0, 0, 0, 0, 46, 0, 0, 0, 57, 0, 0, 0, 61, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 48,
+ 0, 0, 0, 46, 0, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0, 1, 0, 0, 0, 53, 0, 0, 0, 48, 0, 0, 0, 0,
+ 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, 56, 0, 0, 0, 60,
+ 0, 0, 0, 59, 0, 0, 0, 0, 0, 0, 0, 53, 0, 0, 0, 54, 0, 0, 0, 58, 0, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 58,
+ 0, 0, 0, 59, 0, 0, 0, 63, 0, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 64, 0, 0, 0, 68, 0, 0, 0, 67,
+ 0, 0, 0, 0, 0, 0, 0, 61, 0, 0, 0, 62, 0, 0, 0, 66, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0,115, 0, 0, 0, 51,
+ 0, 0, 0, 66, 0, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 22, 0, 0, 0, 76, 0, 0, 0, 85, 0, 0, 0, 0,
+ 0, 0, 0, 20, 0, 0, 0, 19, 0, 0, 0, 84, 0, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 21, 0, 0, 0, 82,
+ 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 85, 0, 0, 0, 89, 0, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 82,
+ 0, 0, 0, 83, 0, 0, 0, 87, 0, 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, 89, 0, 0, 0, 75, 0, 0, 0, 74, 0, 0, 0, 93,
+ 0, 0, 0, 0, 0, 0, 0, 87, 0, 0, 0, 88, 0, 0, 0, 92, 0, 0, 0, 91, 0, 0, 0, 0, 0, 0, 0, 60, 0, 0, 0, 86,
+ 0, 0, 0, 90, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 92, 0, 0, 0, 93, 0, 0, 0, 97, 0, 0, 0, 96, 0, 0, 0, 0,
+ 0, 0, 0, 90, 0, 0, 0, 91, 0, 0, 0, 95, 0, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 97, 0, 0, 0, 73, 0, 0, 0, 77,
+ 0, 0, 0, 81, 0, 0, 0, 0, 0, 0, 0, 95, 0, 0, 0, 96, 0, 0, 0, 80, 0, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 78,
+ 0, 0, 0, 52, 0, 0, 0, 68, 0, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 37, 0, 0, 0, 36, 0, 0, 0, 50, 0, 0, 0,101,
+ 0, 0, 0, 0, 0, 0, 0,100, 0, 0, 0, 99, 0, 0, 0, 39, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 98, 0, 0, 0, 72,
+ 0, 0, 0, 41, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0,105, 0, 0, 0,104, 0, 0, 0,100, 0, 0, 0,101, 0, 0, 0, 0,
+ 0, 0, 0,103, 0, 0, 0,102, 0, 0, 0, 98, 0, 0, 0, 99, 0, 0, 0, 0, 0, 0, 0, 51, 0, 0, 0,109, 0, 0, 0,105,
+ 0, 0, 0,114, 0, 0, 0, 0, 0, 0, 0,108, 0, 0, 0,107, 0, 0, 0,103, 0, 0, 0,104, 0, 0, 0, 0, 0, 0, 0,106,
+ 0, 0, 0, 70, 0, 0, 0, 71, 0, 0, 0,102, 0, 0, 0, 0, 0, 0, 0,113, 0, 0, 0,112, 0, 0, 0,108, 0, 0, 0,109,
+ 0, 0, 0, 0, 0, 0, 0,111, 0, 0, 0,110, 0, 0, 0,106, 0, 0, 0,107, 0, 0, 0, 0, 0, 0, 0,113, 0, 0, 0,115,
+ 0, 0, 0, 52, 0, 0, 0, 78, 0, 0, 0, 0, 0, 0, 0, 79, 0, 0, 0, 80, 0, 0, 0,111, 0, 0, 0,112, 0, 0, 0, 0,
+ 0, 0, 0, 81, 0, 0, 0, 77, 0, 0, 0, 69, 0, 0, 0,110, 0, 0, 0, 0, 0, 0, 0,116, 0, 0, 0,135, 0, 0, 0,120,
+ 0, 0, 0,119, 0, 0, 0, 16, 0, 0, 0,125, 0, 0, 0,124, 0, 0, 0,120, 0, 0, 0,121, 0, 0, 0, 16, 0, 0, 0,123,
+ 0, 0, 0,122, 0, 0, 0,118, 0, 0, 0,119, 0, 0, 0, 16, 0, 0, 0,128, 0, 0, 0,127, 0, 0, 0,123, 0, 0, 0,124,
+ 0, 0, 0, 16, 0, 0, 0,133, 0, 0, 0,132, 0, 0, 0,128, 0, 0, 0,129, 0, 0, 0, 16, 0, 0, 0,131, 0, 0, 0,130,
+ 0, 0, 0,126, 0, 0, 0,127, 0, 0, 0, 16, 0, 0, 0,148, 0, 0, 0,151, 0, 0, 0,131, 0, 0, 0,132, 0, 0, 0, 16,
+ 0, 0, 0,147, 0, 0, 0,150, 0, 0, 0,133, 0, 0, 0,138, 0, 0, 0, 16, 0, 0, 0,137, 0, 0, 0,138, 0, 0, 0,140,
+ 0, 0, 0,139, 0, 0, 0, 16, 0, 0, 0,140, 0, 0, 0,129, 0, 0, 0,125, 0, 0, 0,142, 0, 0, 0, 16, 0, 0, 0,141,
+ 0, 0, 0,142, 0, 0, 0,144, 0, 0, 0,143, 0, 0, 0, 16, 0, 0, 0,144, 0, 0, 0,121, 0, 0, 0,117, 0, 0, 0,136,
+ 0, 0, 0, 16, 0, 0, 0,171, 0, 0, 0,181, 0, 0, 0,177, 0, 0, 0,155, 0, 0, 0, 2, 0, 0, 0,154, 0, 0, 0,153,
+ 0, 0, 0,169, 0, 0, 0,170, 0, 0, 0, 2, 0, 0, 0,152, 0, 0, 0,176, 0, 0, 0,172, 0, 0, 0,168, 0, 0, 0, 2,
+ 0, 0, 0,159, 0, 0, 0,158, 0, 0, 0,154, 0, 0, 0,155, 0, 0, 0, 2, 0, 0, 0,157, 0, 0, 0,156, 0, 0, 0,152,
+ 0, 0, 0,153, 0, 0, 0, 2, 0, 0, 0,179, 0, 0, 0,163, 0, 0, 0,159, 0, 0, 0,178, 0, 0, 0, 2, 0, 0, 0,162,
+ 0, 0, 0,161, 0, 0, 0,157, 0, 0, 0,158, 0, 0, 0, 2, 0, 0, 0,160, 0, 0, 0,174, 0, 0, 0,175, 0, 0, 0,156,
+ 0, 0, 0, 2, 0, 0, 0,167, 0, 0, 0,166, 0, 0, 0,162, 0, 0, 0,163, 0, 0, 0, 2, 0, 0, 0,165, 0, 0, 0,164,
+ 0, 0, 0,160, 0, 0, 0,161, 0, 0, 0, 2, 0, 0, 0,182, 0, 0, 0,184, 0, 0, 0,167, 0, 0, 0,180, 0, 0, 0, 2,
+ 0, 0, 0,185, 0, 0, 0,186, 0, 0, 0,165, 0, 0, 0,166, 0, 0, 0, 2, 0, 0, 0,187, 0, 0, 0,183, 0, 0, 0,173,
+ 0, 0, 0,164, 0, 0, 0, 2, 68, 65, 84, 65, 0, 0, 13, 16, 5, 32, 48, 32, 0, 0, 0, 60, 0, 0, 0, 76, 63, 27,168,250,
+ 59, 93,211, 96, 62,203,162, 84, 59, 93,211, 96, 62,203,162, 84, 59, 93,211, 96, 63, 27,168,251, 59, 93,211, 96, 0, 0, 0, 0,
+ 61, 0, 0, 1, 0, 0, 0, 0, 63,131,172, 21, 59, 93,211, 96, 63, 81,128,146, 59, 93,211, 96, 63, 81,128,149, 59, 93,211, 96,
+ 63,131,172, 22, 59, 93,211, 96, 0, 0, 0, 0, 61, 0, 0, 1, 0, 0, 0, 0, 63,158,151,227, 59, 93,211, 96, 63,185,131,174,
+ 59, 93,211, 96, 63,185,131,174, 59, 93,211, 96, 63,158,151,225, 59, 93,211, 96, 0, 0, 0, 0, 61, 0, 0, 1, 0, 0, 0, 0,
+ 63, 81,128,149, 59, 93,211, 96, 63, 27,168,251, 59, 93,211, 96, 63, 27,168,246, 59, 93,211, 96, 63, 81,128,142, 59, 93,211, 96,
+ 0, 0, 0, 0, 61, 0, 0, 1, 0, 0, 0, 0, 63,158,151,227, 59, 93,211, 96, 63,131,172, 22, 59, 93,211, 96, 63,131,172, 24,
+ 59, 93,211, 96, 63,158,151,226, 59, 93,211, 96, 0, 0, 0, 0, 61, 0, 0, 1, 0, 0, 0, 0, 63, 27,168,246, 59, 93,211, 96,
+ 62,203,162, 86, 59, 93,211, 96, 62,203,162, 85, 59, 93,211, 96, 63, 27,168,247, 59, 93,211, 96, 0, 0, 0, 0, 61, 0, 0, 1,
+ 0, 0, 0, 0, 63,131,172, 24, 59, 93,211, 96, 63, 81,128,142, 59, 93,211, 96, 63, 81,128,144, 59, 93,211, 96, 63,131,172, 21,
+ 59, 93,211, 96, 0, 0, 0, 0, 61, 0, 0, 1, 0, 0, 0, 0, 63,185,131,174, 59, 93,211, 96, 63,158,151,226, 59, 93,211, 96,
+ 63,158,151,226, 59, 93,211, 96, 63,185,131,176, 59, 93,211, 96, 0, 0, 0, 0, 61, 0, 0, 1, 0, 0, 0, 0, 63, 81,128,144,
+ 59, 93,211, 96, 63, 27,168,247, 59, 93,211, 96, 63, 27,168,247, 59, 93,211, 96, 63, 81,128,144, 59, 93,211, 96, 0, 0, 0, 0,
+ 61, 0, 0, 1, 0, 0, 0, 0, 63,158,151,226, 59, 93,211, 96, 63,131,172, 21, 59, 93,211, 96, 63,131,172, 22, 59, 93,211, 96,
+ 63,158,151,224, 59, 93,211, 96, 0, 0, 0, 0, 61, 0, 0, 1, 0, 0, 0, 0, 63, 27,168,247, 59, 93,211, 96, 62,203,162, 85,
+ 59, 93,211, 96, 62,203,162, 86, 59, 93,211, 96, 63, 27,168,248, 59, 93,211, 96, 0, 0, 0, 0, 61, 0, 0, 1, 0, 0, 0, 0,
+ 63,131,172, 22, 59, 93,211, 96, 63, 81,128,144, 59, 93,211, 96, 63, 81,128,144, 59, 93,211, 96, 63,131,172, 22, 59, 93,211, 96,
+ 0, 0, 0, 0, 61, 0, 0, 1, 0, 0, 0, 0, 63,158,151,226, 59, 93,211, 96, 63,185,131,176, 59, 93,211, 96, 63,185,131,174,
+ 59, 93,211, 96, 63,158,151,224, 59, 93,211, 96, 0, 0, 0, 0, 61, 0, 0, 1, 0, 0, 0, 0, 63,140,131, 99, 63, 41, 47, 76,
+ 63,114,244, 44, 63, 79, 65,236, 63,114,244, 44, 63, 79, 65,236, 63,140,131, 99, 63, 41, 47, 76, 0, 0, 0, 0, 60, 0, 0, 1,
+ 0, 0, 0, 0, 63,159,140,161, 63, 3, 28,210, 63,140,131, 99, 63, 41, 47, 76, 63,140,131, 99, 63, 41, 47, 76, 63,159,140,161,
+ 63, 3, 28,210, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 63,140,131, 99, 63, 41, 47, 76, 63,114,244, 44, 63, 79, 65,236,
+ 63,114,244, 44, 63, 79, 65,236, 63,140,131, 99, 63, 41, 47, 76, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 63,159,140,161,
+ 63, 3, 28,210, 63,140,131, 99, 63, 41, 47, 76, 63,140,131, 99, 63, 41, 47, 76, 63,159,140,161, 63, 3, 28,210, 0, 0, 0, 0,
+ 60, 0, 0, 1, 0, 0, 0, 0, 63,140,131, 99, 63, 41, 47, 72, 63,114,244, 44, 63, 79, 65,236, 63,114,244, 44, 63, 79, 65,236,
+ 63,140,131, 99, 63, 41, 47, 76, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 63, 76,225,174, 63,117, 84,102, 63, 38,207, 52,
+ 63,141,179,111, 63, 38,207, 52, 63,141,179,111, 63, 76,225,174, 63,117, 84,102, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0,
+ 63, 38,207, 52, 63,141,179,111, 63, 0,188,188, 63,160,188,173, 63, 0,188,188, 63,160,188,173, 63, 38,207, 52, 63,141,179,111,
+ 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 63,114,244, 44, 63, 79, 65,236, 63, 76,225,174, 63,117, 84,102, 63, 76,225,172,
+ 63,117, 84,102, 63,114,244, 44, 63, 79, 65,236, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 63, 76,225,172, 63,117, 84,102,
+ 63, 38,207, 52, 63,141,179,111, 63, 38,207, 52, 63,141,179,111, 63, 76,225,172, 63,117, 84,102, 0, 0, 0, 0, 60, 0, 0, 1,
+ 0, 0, 0, 0, 63, 38,207, 52, 63,141,179,111, 63, 0,188,188, 63,160,188,173, 63, 0,188,188, 63,160,188,173, 63, 38,207, 52,
+ 63,141,179,111, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 63,114,244, 44, 63, 79, 65,236, 63, 76,225,172, 63,117, 84,102,
+ 63, 76,225,172, 63,117, 84,102, 63,114,244, 44, 63, 79, 65,236, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 63, 38,207, 56,
+ 63,141,179,111, 63, 76,225,172, 63,117, 84,102, 63, 76,225,172, 63,117, 84,102, 63, 38,207, 52, 63,141,179,111, 0, 0, 0, 0,
+ 60, 0, 0, 1, 0, 0, 0, 0,189,188,105, 96, 63, 41, 47,120,190,118,127, 56, 63, 3, 28,220,190,118,127, 56, 63, 3, 28,220,
+189,188,105, 96, 63, 41, 47,120, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 62, 82, 95, 26, 63,117, 84,102, 61,104, 84,200,
+ 63, 79, 65,244, 61,104, 84,200, 63, 79, 65,242, 62, 82, 95, 26, 63,117, 84,102, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0,
+ 63, 0,188,190, 63,160,188,171, 62,181, 84,122, 63,141,179,113, 62,181, 84,122, 63,141,179,113, 63, 0,188,188, 63,160,188,173,
+ 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 61,104, 84,200, 63, 79, 65,242,189,188,105, 96, 63, 41, 47,120,189,188,105,128,
+ 63, 41, 47,120, 61,104, 84,160, 63, 79, 65,242, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 62,181, 84,122, 63,141,179,113,
+ 62, 82, 95, 26, 63,117, 84,102, 62, 82, 95, 26, 63,117, 84,102, 62,181, 84,122, 63,141,179,113, 0, 0, 0, 0, 60, 0, 0, 1,
+ 0, 0, 0, 0,189,188,105,128, 63, 41, 47,120,190,118,127, 64, 63, 3, 28,216,190,118,127, 64, 63, 3, 28,216,189,188,105,128,
+ 63, 41, 47,120, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 62, 82, 95, 26, 63,117, 84,102, 61,104, 84,160, 63, 79, 65,242,
+ 61,104, 84,160, 63, 79, 65,242, 62, 82, 95, 26, 63,117, 84,102, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 63, 0,188,188,
+ 63,160,188,173, 62,181, 84,122, 63,141,179,113, 62,181, 84,122, 63,141,179,113, 63, 0,188,188, 63,160,188,173, 0, 0, 0, 0,
+ 60, 0, 0, 1, 0, 0, 0, 0, 61,104, 84,160, 63, 79, 65,242,189,188,105,128, 63, 41, 47,120,189,188,105,128, 63, 41, 47,120,
+ 61,104, 84,160, 63, 79, 65,242, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 62,181, 84,122, 63,141,179,113, 62, 82, 95, 26,
+ 63,117, 84,102, 62, 82, 95, 26, 63,117, 84,102, 62,181, 84,122, 63,141,179,113, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0,
+189,188,105,128, 63, 41, 47,120,190,118,127, 64, 63, 3, 28,216,190,118,127, 64, 63, 3, 28,216,189,188,105,128, 63, 41, 47,120,
+ 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 62, 82, 95, 26, 63,117, 84,102, 61,104, 84,160, 63, 79, 65,242, 61,104, 84,160,
+ 63, 79, 65,242, 62, 82, 95, 26, 63,117, 84,102, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 62,181, 84,122, 63,141,179,113,
+ 63, 0,188,188, 63,160,188,173, 63, 0,188,188, 63,160,188,173, 62,181, 84,122, 63,141,179,113, 0, 0, 0, 0, 60, 0, 0, 1,
+ 0, 0, 0, 0, 63,140,131,180, 62,186, 19,116, 63,159,140,244, 63, 3, 28, 50, 63,140,131, 99, 63, 41, 47, 76, 63,114,244, 42,
+ 63, 3, 28,244, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 63, 76,225,174, 62,186, 21, 0, 63, 38,207, 51, 62, 91,224, 24,
+ 63, 76,226,112, 61,135, 38, 64, 63,114,244,240, 62, 91,221, 4, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 63, 0,188,185,
+ 61,135, 44, 96, 62,181, 84, 61,189,169,104,176, 63, 0,189, 93,190,109, 1, 80, 63, 38,207,248,189,169,109,144, 0, 0, 0, 0,
+ 60, 0, 0, 1, 0, 0, 0, 0, 63, 76,225,174, 63, 41, 47,116, 63, 38,207, 52, 63, 3, 28,248, 63, 76,225,174, 62,186, 21, 0,
+ 63,114,244, 42, 63, 3, 28,244, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 63, 0,188,185, 62,186, 21, 0, 62,181, 84,122,
+ 62, 91,224, 32, 63, 0,188,185, 61,135, 44, 96, 63, 38,207, 51, 62, 91,224, 24, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0,
+ 63, 76,225,172, 63,117, 84,102, 63, 38,207, 52, 63, 79, 65,236, 63, 76,225,174, 63, 41, 47,116, 63,114,244, 44, 63, 79, 65,236,
+ 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 63, 0,188,188, 63, 41, 47,120, 62,181, 84,122, 63, 3, 28,248, 63, 0,188,185,
+ 62,186, 21, 0, 63, 38,207, 52, 63, 3, 28,248, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 62, 82, 95, 14, 62,186, 21, 0,
+ 61,104, 82,144, 62, 91,223,128, 62, 82, 94,138, 61,135, 43, 48, 62,181, 84,122, 62, 91,224, 32, 0, 0, 0, 0, 60, 0, 0, 1,
+ 0, 0, 0, 0, 63, 0,188,190, 63,117, 84,102, 62,181, 84,127, 63, 79, 65,242, 63, 0,188,188, 63, 41, 47,120, 63, 38,207, 52,
+ 63, 79, 65,236, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 62, 82, 95, 26, 63, 41, 47,120, 61,104, 84,160, 63, 3, 29, 0,
+ 62, 82, 95, 14, 62,186, 21, 0, 62,181, 84,122, 63, 3, 28,248, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 63, 0,188,190,
+ 63,117, 84,102, 63, 38,207, 56, 63,141,179,111, 63, 0,188,188, 63,160,188,173, 62,181, 84,122, 63,141,179,113, 0, 0, 0, 0,
+ 60, 0, 0, 1, 0, 0, 0, 0, 62, 82, 95, 26, 63,117, 84,102, 61,104, 84,160, 63, 79, 65,242, 62, 82, 95, 26, 63, 41, 47,120,
+ 62,181, 84,127, 63, 79, 65,242, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0,189,188,105,128, 63, 41, 47,120,190,118,127, 64,
+ 63, 3, 28,216,189,188,106,128, 62,186, 20,176, 61,104, 84,160, 63, 3, 29, 0, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0,
+ 63, 38,207, 56, 63,141,179,111, 63, 76,225,172, 63,117, 84,102, 63, 76,225,172, 63,117, 84,102, 63, 38,207, 52, 63,141,179,111,
+ 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 63,114,244, 44, 63, 79, 65,236, 63, 76,225,172, 63,117, 84,102, 63, 76,225,172,
+ 63,117, 84,102, 63,114,244, 44, 63, 79, 65,236, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 63, 38,207, 52, 63,141,179,111,
+ 63, 0,188,188, 63,160,188,173, 63, 0,188,188, 63,160,188,173, 63, 38,207, 52, 63,141,179,111, 0, 0, 0, 0, 60, 0, 0, 1,
+ 0, 0, 0, 0, 63, 76,225,172, 63,117, 84,102, 63, 38,207, 52, 63,141,179,111, 63, 38,207, 52, 63,141,179,111, 63, 76,225,172,
+ 63,117, 84,102, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 63,114,244, 44, 63, 79, 65,236, 63, 76,225,174, 63,117, 84,102,
+ 63, 76,225,172, 63,117, 84,102, 63,114,244, 44, 63, 79, 65,236, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 63, 38,207, 52,
+ 63,141,179,111, 63, 0,188,188, 63,160,188,173, 63, 0,188,188, 63,160,188,173, 63, 38,207, 52, 63,141,179,111, 0, 0, 0, 0,
+ 60, 0, 0, 1, 0, 0, 0, 0, 63, 76,225,174, 63,117, 84,102, 63, 38,207, 52, 63,141,179,111, 63, 38,207, 52, 63,141,179,111,
+ 63, 76,225,174, 63,117, 84,102, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 63,140,131, 99, 63, 41, 47, 72, 63,114,244, 44,
+ 63, 79, 65,236, 63,114,244, 44, 63, 79, 65,236, 63,140,131, 99, 63, 41, 47, 76, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0,
+ 63,159,140,161, 63, 3, 28,210, 63,140,131, 99, 63, 41, 47, 76, 63,140,131, 99, 63, 41, 47, 76, 63,159,140,161, 63, 3, 28,210,
+ 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 63,140,131, 99, 63, 41, 47, 76, 63,114,244, 44, 63, 79, 65,236, 63,114,244, 44,
+ 63, 79, 65,236, 63,140,131, 99, 63, 41, 47, 76, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 63,159,140,161, 63, 3, 28,210,
+ 63,140,131, 99, 63, 41, 47, 76, 63,140,131, 99, 63, 41, 47, 76, 63,159,140,161, 63, 3, 28,210, 0, 0, 0, 0, 60, 0, 0, 1,
+ 0, 0, 0, 0, 63,140,131, 99, 63, 41, 47, 76, 63,114,244, 44, 63, 79, 65,236, 63,114,244, 44, 63, 79, 65,236, 63,140,131, 99,
+ 63, 41, 47, 76, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 62,181, 84,122, 63,141,179,113, 63, 0,188,188, 63,160,188,173,
+ 63, 0,188,188, 63,160,188,173, 62,181, 84,122, 63,141,179,113, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 62, 82, 95, 26,
+ 63,117, 84,102, 61,104, 84,160, 63, 79, 65,242, 61,104, 84,160, 63, 79, 65,242, 62, 82, 95, 26, 63,117, 84,102, 0, 0, 0, 0,
+ 60, 0, 0, 1, 0, 0, 0, 0,189,188,105,128, 63, 41, 47,120,190,118,127, 64, 63, 3, 28,216,190,118,127, 64, 63, 3, 28,216,
+189,188,105,128, 63, 41, 47,120, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 62,181, 84,122, 63,141,179,113, 62, 82, 95, 26,
+ 63,117, 84,102, 62, 82, 95, 26, 63,117, 84,102, 62,181, 84,122, 63,141,179,113, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0,
+ 61,104, 84,160, 63, 79, 65,242,189,188,105,128, 63, 41, 47,120,189,188,105,128, 63, 41, 47,120, 61,104, 84,160, 63, 79, 65,242,
+ 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 63, 0,188,188, 63,160,188,173, 62,181, 84,122, 63,141,179,113, 62,181, 84,122,
+ 63,141,179,113, 63, 0,188,188, 63,160,188,173, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 62, 82, 95, 26, 63,117, 84,102,
+ 61,104, 84,160, 63, 79, 65,242, 61,104, 84,160, 63, 79, 65,242, 62, 82, 95, 26, 63,117, 84,102, 0, 0, 0, 0, 60, 0, 0, 1,
+ 0, 0, 0, 0,189,188,105,128, 63, 41, 47,120,190,118,127, 64, 63, 3, 28,216,190,118,127, 64, 63, 3, 28,216,189,188,105,128,
+ 63, 41, 47,120, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 62,181, 84,122, 63,141,179,113, 62, 82, 95, 26, 63,117, 84,102,
+ 62, 82, 95, 26, 63,117, 84,102, 62,181, 84,122, 63,141,179,113, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 61,104, 84,200,
+ 63, 79, 65,242,189,188,105, 96, 63, 41, 47,120,189,188,105,128, 63, 41, 47,120, 61,104, 84,160, 63, 79, 65,242, 0, 0, 0, 0,
+ 60, 0, 0, 1, 0, 0, 0, 0, 63, 0,188,190, 63,160,188,171, 62,181, 84,122, 63,141,179,113, 62,181, 84,122, 63,141,179,113,
+ 63, 0,188,188, 63,160,188,173, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 62, 82, 95, 26, 63,117, 84,102, 61,104, 84,200,
+ 63, 79, 65,244, 61,104, 84,200, 63, 79, 65,242, 62, 82, 95, 26, 63,117, 84,102, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0,
+189,188,105, 96, 63, 41, 47,120,190,118,127, 56, 63, 3, 28,220,190,118,127, 56, 63, 3, 28,220,189,188,105, 96, 63, 41, 47,120,
+ 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 4,192, 5, 32, 62, 32, 0, 0, 0, 57, 0, 0, 1, 48,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 68, 65, 84, 65, 0, 0, 17,208, 5, 30, 70, 32, 0, 0, 0, 51, 0, 0, 0, 76, 0, 0, 0, 0, 63, 27,168,250, 59, 93,211, 96,
+ 62,203,162, 84, 59, 93,211, 96, 62,203,162, 84, 59, 93,211, 96, 63, 27,168,251, 59, 93,211, 96,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 61, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,131,172, 21, 59, 93,211, 96, 63, 81,128,146,
+ 59, 93,211, 96, 63, 81,128,149, 59, 93,211, 96, 63,131,172, 22, 59, 93,211, 96,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 61, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,158,151,227, 59, 93,211, 96, 63,185,131,174, 59, 93,211, 96,
+ 63,185,131,174, 59, 93,211, 96, 63,158,151,225, 59, 93,211, 96,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 61, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 81,128,149, 59, 93,211, 96, 63, 27,168,251, 59, 93,211, 96, 63, 27,168,246,
+ 59, 93,211, 96, 63, 81,128,142, 59, 93,211, 96,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 61, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,158,151,227, 59, 93,211, 96, 63,131,172, 22, 59, 93,211, 96, 63,131,172, 24, 59, 93,211, 96,
+ 63,158,151,226, 59, 93,211, 96,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 61, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 27,168,246, 59, 93,211, 96, 62,203,162, 86, 59, 93,211, 96, 62,203,162, 85, 59, 93,211, 96, 63, 27,168,247,
+ 59, 93,211, 96,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 61, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,131,172, 24, 59, 93,211, 96, 63, 81,128,142, 59, 93,211, 96, 63, 81,128,144, 59, 93,211, 96, 63,131,172, 21, 59, 93,211, 96,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 61, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,185,131,174,
+ 59, 93,211, 96, 63,158,151,226, 59, 93,211, 96, 63,158,151,226, 59, 93,211, 96, 63,185,131,176, 59, 93,211, 96,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 61, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 81,128,144, 59, 93,211, 96,
+ 63, 27,168,247, 59, 93,211, 96, 63, 27,168,247, 59, 93,211, 96, 63, 81,128,144, 59, 93,211, 96,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 61, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,158,151,226, 59, 93,211, 96, 63,131,172, 21,
+ 59, 93,211, 96, 63,131,172, 22, 59, 93,211, 96, 63,158,151,224, 59, 93,211, 96,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 61, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 27,168,247, 59, 93,211, 96, 62,203,162, 85, 59, 93,211, 96,
+ 62,203,162, 86, 59, 93,211, 96, 63, 27,168,248, 59, 93,211, 96,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 61, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,131,172, 22, 59, 93,211, 96, 63, 81,128,144, 59, 93,211, 96, 63, 81,128,144,
+ 59, 93,211, 96, 63,131,172, 22, 59, 93,211, 96,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 61, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,158,151,226, 59, 93,211, 96, 63,185,131,176, 59, 93,211, 96, 63,185,131,174, 59, 93,211, 96,
+ 63,158,151,224, 59, 93,211, 96,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 61, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,140,131, 99, 63, 41, 47, 76, 63,114,244, 44, 63, 79, 65,236, 63,114,244, 44, 63, 79, 65,236, 63,140,131, 99,
+ 63, 41, 47, 76,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,159,140,161, 63, 3, 28,210, 63,140,131, 99, 63, 41, 47, 76, 63,140,131, 99, 63, 41, 47, 76, 63,159,140,161, 63, 3, 28,210,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,140,131, 99,
+ 63, 41, 47, 76, 63,114,244, 44, 63, 79, 65,236, 63,114,244, 44, 63, 79, 65,236, 63,140,131, 99, 63, 41, 47, 76,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,159,140,161, 63, 3, 28,210,
+ 63,140,131, 99, 63, 41, 47, 76, 63,140,131, 99, 63, 41, 47, 76, 63,159,140,161, 63, 3, 28,210,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,140,131, 99, 63, 41, 47, 72, 63,114,244, 44,
+ 63, 79, 65,236, 63,114,244, 44, 63, 79, 65,236, 63,140,131, 99, 63, 41, 47, 76,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 76,225,174, 63,117, 84,102, 63, 38,207, 52, 63,141,179,111,
+ 63, 38,207, 52, 63,141,179,111, 63, 76,225,174, 63,117, 84,102,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 38,207, 52, 63,141,179,111, 63, 0,188,188, 63,160,188,173, 63, 0,188,188,
+ 63,160,188,173, 63, 38,207, 52, 63,141,179,111,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,114,244, 44, 63, 79, 65,236, 63, 76,225,174, 63,117, 84,102, 63, 76,225,172, 63,117, 84,102,
+ 63,114,244, 44, 63, 79, 65,236,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 76,225,172, 63,117, 84,102, 63, 38,207, 52, 63,141,179,111, 63, 38,207, 52, 63,141,179,111, 63, 76,225,172,
+ 63,117, 84,102,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 38,207, 52, 63,141,179,111, 63, 0,188,188, 63,160,188,173, 63, 0,188,188, 63,160,188,173, 63, 38,207, 52, 63,141,179,111,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,114,244, 44,
+ 63, 79, 65,236, 63, 76,225,172, 63,117, 84,102, 63, 76,225,172, 63,117, 84,102, 63,114,244, 44, 63, 79, 65,236,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 38,207, 56, 63,141,179,111,
+ 63, 76,225,172, 63,117, 84,102, 63, 76,225,172, 63,117, 84,102, 63, 38,207, 52, 63,141,179,111,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,189,188,105, 96, 63, 41, 47,120,190,118,127, 56,
+ 63, 3, 28,220,190,118,127, 56, 63, 3, 28,220,189,188,105, 96, 63, 41, 47,120,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 82, 95, 26, 63,117, 84,102, 61,104, 84,200, 63, 79, 65,244,
+ 61,104, 84,200, 63, 79, 65,242, 62, 82, 95, 26, 63,117, 84,102,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0,188,190, 63,160,188,171, 62,181, 84,122, 63,141,179,113, 62,181, 84,122,
+ 63,141,179,113, 63, 0,188,188, 63,160,188,173,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 61,104, 84,200, 63, 79, 65,242,189,188,105, 96, 63, 41, 47,120,189,188,105,128, 63, 41, 47,120,
+ 61,104, 84,160, 63, 79, 65,242,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,181, 84,122, 63,141,179,113, 62, 82, 95, 26, 63,117, 84,102, 62, 82, 95, 26, 63,117, 84,102, 62,181, 84,122,
+ 63,141,179,113,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+189,188,105,128, 63, 41, 47,120,190,118,127, 64, 63, 3, 28,216,190,118,127, 64, 63, 3, 28,216,189,188,105,128, 63, 41, 47,120,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 82, 95, 26,
+ 63,117, 84,102, 61,104, 84,160, 63, 79, 65,242, 61,104, 84,160, 63, 79, 65,242, 62, 82, 95, 26, 63,117, 84,102,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0,188,188, 63,160,188,173,
+ 62,181, 84,122, 63,141,179,113, 62,181, 84,122, 63,141,179,113, 63, 0,188,188, 63,160,188,173,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,104, 84,160, 63, 79, 65,242,189,188,105,128,
+ 63, 41, 47,120,189,188,105,128, 63, 41, 47,120, 61,104, 84,160, 63, 79, 65,242,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,181, 84,122, 63,141,179,113, 62, 82, 95, 26, 63,117, 84,102,
+ 62, 82, 95, 26, 63,117, 84,102, 62,181, 84,122, 63,141,179,113,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,189,188,105,128, 63, 41, 47,120,190,118,127, 64, 63, 3, 28,216,190,118,127, 64,
+ 63, 3, 28,216,189,188,105,128, 63, 41, 47,120,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62, 82, 95, 26, 63,117, 84,102, 61,104, 84,160, 63, 79, 65,242, 61,104, 84,160, 63, 79, 65,242,
+ 62, 82, 95, 26, 63,117, 84,102,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,181, 84,122, 63,141,179,113, 63, 0,188,188, 63,160,188,173, 63, 0,188,188, 63,160,188,173, 62,181, 84,122,
+ 63,141,179,113,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,140,131,180, 62,186, 19,116, 63,159,140,244, 63, 3, 28, 50, 63,140,131, 99, 63, 41, 47, 76, 63,114,244, 42, 63, 3, 28,244,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 76,225,174,
+ 62,186, 21, 0, 63, 38,207, 51, 62, 91,224, 24, 63, 76,226,112, 61,135, 38, 64, 63,114,244,240, 62, 91,221, 4,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0,188,185, 61,135, 44, 96,
+ 62,181, 84, 61,189,169,104,176, 63, 0,189, 93,190,109, 1, 80, 63, 38,207,248,189,169,109,144,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 76,225,174, 63, 41, 47,116, 63, 38,207, 52,
+ 63, 3, 28,248, 63, 76,225,174, 62,186, 21, 0, 63,114,244, 42, 63, 3, 28,244,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0,188,185, 62,186, 21, 0, 62,181, 84,122, 62, 91,224, 32,
+ 63, 0,188,185, 61,135, 44, 96, 63, 38,207, 51, 62, 91,224, 24,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 76,225,172, 63,117, 84,102, 63, 38,207, 52, 63, 79, 65,236, 63, 76,225,174,
+ 63, 41, 47,116, 63,114,244, 44, 63, 79, 65,236,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 0,188,188, 63, 41, 47,120, 62,181, 84,122, 63, 3, 28,248, 63, 0,188,185, 62,186, 21, 0,
+ 63, 38,207, 52, 63, 3, 28,248,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62, 82, 95, 14, 62,186, 21, 0, 61,104, 82,144, 62, 91,223,128, 62, 82, 94,138, 61,135, 43, 48, 62,181, 84,122,
+ 62, 91,224, 32,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 0,188,190, 63,117, 84,102, 62,181, 84,127, 63, 79, 65,242, 63, 0,188,188, 63, 41, 47,120, 63, 38,207, 52, 63, 79, 65,236,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 82, 95, 26,
+ 63, 41, 47,120, 61,104, 84,160, 63, 3, 29, 0, 62, 82, 95, 14, 62,186, 21, 0, 62,181, 84,122, 63, 3, 28,248,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0,188,190, 63,117, 84,102,
+ 63, 38,207, 56, 63,141,179,111, 63, 0,188,188, 63,160,188,173, 62,181, 84,122, 63,141,179,113,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 82, 95, 26, 63,117, 84,102, 61,104, 84,160,
+ 63, 79, 65,242, 62, 82, 95, 26, 63, 41, 47,120, 62,181, 84,127, 63, 79, 65,242,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,189,188,105,128, 63, 41, 47,120,190,118,127, 64, 63, 3, 28,216,
+189,188,106,128, 62,186, 20,176, 61,104, 84,160, 63, 3, 29, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 38,207, 56, 63,141,179,111, 63, 76,225,172, 63,117, 84,102, 63, 76,225,172,
+ 63,117, 84,102, 63, 38,207, 52, 63,141,179,111,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,114,244, 44, 63, 79, 65,236, 63, 76,225,172, 63,117, 84,102, 63, 76,225,172, 63,117, 84,102,
+ 63,114,244, 44, 63, 79, 65,236,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 38,207, 52, 63,141,179,111, 63, 0,188,188, 63,160,188,173, 63, 0,188,188, 63,160,188,173, 63, 38,207, 52,
+ 63,141,179,111,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 76,225,172, 63,117, 84,102, 63, 38,207, 52, 63,141,179,111, 63, 38,207, 52, 63,141,179,111, 63, 76,225,172, 63,117, 84,102,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,114,244, 44,
+ 63, 79, 65,236, 63, 76,225,174, 63,117, 84,102, 63, 76,225,172, 63,117, 84,102, 63,114,244, 44, 63, 79, 65,236,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 38,207, 52, 63,141,179,111,
+ 63, 0,188,188, 63,160,188,173, 63, 0,188,188, 63,160,188,173, 63, 38,207, 52, 63,141,179,111,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 76,225,174, 63,117, 84,102, 63, 38,207, 52,
+ 63,141,179,111, 63, 38,207, 52, 63,141,179,111, 63, 76,225,174, 63,117, 84,102,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,140,131, 99, 63, 41, 47, 72, 63,114,244, 44, 63, 79, 65,236,
+ 63,114,244, 44, 63, 79, 65,236, 63,140,131, 99, 63, 41, 47, 76,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,159,140,161, 63, 3, 28,210, 63,140,131, 99, 63, 41, 47, 76, 63,140,131, 99,
+ 63, 41, 47, 76, 63,159,140,161, 63, 3, 28,210,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,140,131, 99, 63, 41, 47, 76, 63,114,244, 44, 63, 79, 65,236, 63,114,244, 44, 63, 79, 65,236,
+ 63,140,131, 99, 63, 41, 47, 76,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,159,140,161, 63, 3, 28,210, 63,140,131, 99, 63, 41, 47, 76, 63,140,131, 99, 63, 41, 47, 76, 63,159,140,161,
+ 63, 3, 28,210,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,140,131, 99, 63, 41, 47, 76, 63,114,244, 44, 63, 79, 65,236, 63,114,244, 44, 63, 79, 65,236, 63,140,131, 99, 63, 41, 47, 76,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,181, 84,122,
+ 63,141,179,113, 63, 0,188,188, 63,160,188,173, 63, 0,188,188, 63,160,188,173, 62,181, 84,122, 63,141,179,113,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 82, 95, 26, 63,117, 84,102,
+ 61,104, 84,160, 63, 79, 65,242, 61,104, 84,160, 63, 79, 65,242, 62, 82, 95, 26, 63,117, 84,102,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,189,188,105,128, 63, 41, 47,120,190,118,127, 64,
+ 63, 3, 28,216,190,118,127, 64, 63, 3, 28,216,189,188,105,128, 63, 41, 47,120,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,181, 84,122, 63,141,179,113, 62, 82, 95, 26, 63,117, 84,102,
+ 62, 82, 95, 26, 63,117, 84,102, 62,181, 84,122, 63,141,179,113,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,104, 84,160, 63, 79, 65,242,189,188,105,128, 63, 41, 47,120,189,188,105,128,
+ 63, 41, 47,120, 61,104, 84,160, 63, 79, 65,242,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 0,188,188, 63,160,188,173, 62,181, 84,122, 63,141,179,113, 62,181, 84,122, 63,141,179,113,
+ 63, 0,188,188, 63,160,188,173,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62, 82, 95, 26, 63,117, 84,102, 61,104, 84,160, 63, 79, 65,242, 61,104, 84,160, 63, 79, 65,242, 62, 82, 95, 26,
+ 63,117, 84,102,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+189,188,105,128, 63, 41, 47,120,190,118,127, 64, 63, 3, 28,216,190,118,127, 64, 63, 3, 28,216,189,188,105,128, 63, 41, 47,120,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,181, 84,122,
+ 63,141,179,113, 62, 82, 95, 26, 63,117, 84,102, 62, 82, 95, 26, 63,117, 84,102, 62,181, 84,122, 63,141,179,113,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,104, 84,200, 63, 79, 65,242,
+189,188,105, 96, 63, 41, 47,120,189,188,105,128, 63, 41, 47,120, 61,104, 84,160, 63, 79, 65,242,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0,188,190, 63,160,188,171, 62,181, 84,122,
+ 63,141,179,113, 62,181, 84,122, 63,141,179,113, 63, 0,188,188, 63,160,188,173,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 82, 95, 26, 63,117, 84,102, 61,104, 84,200, 63, 79, 65,244,
+ 61,104, 84,200, 63, 79, 65,242, 62, 82, 95, 26, 63,117, 84,102,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,189,188,105, 96, 63, 41, 47,120,190,118,127, 56, 63, 3, 28,220,190,118,127, 56,
+ 63, 3, 28,220,189,188,105, 96, 63, 41, 47,120,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 77, 69, 0, 0, 1, 20, 2,236,213, 64, 0, 0, 0, 50, 0, 0, 0, 1, 2,236,218, 64, 2,236,208,112,
+ 0, 0, 0, 0, 0, 0, 0, 0, 77, 69, 80,108, 97,110,101, 46, 48, 48, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,235,202, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 2,236,214,128, 5, 32,118, 32, 5, 32,124, 32, 5, 30, 70, 32, 5, 32, 86, 32, 5, 32,102, 32, 0, 0, 0, 0, 5, 32,138, 32,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,236,214,176, 0, 0, 0, 1, 0, 0, 0, 5,
+ 0, 0, 0, 20, 0, 0, 0, 0, 2,236,215,224, 0, 0, 0, 1, 0, 0, 0, 5, 0, 0, 0, 12, 0, 0, 0, 0, 2,236,217, 16,
+ 0, 0, 0, 3, 0, 0, 0, 5, 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0,182, 0, 0, 1, 45, 0, 0, 0, 74, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1, 63, 76,204,213, 63, 76,204,255,182,104, 0, 0, 63,128, 0, 30, 63,128, 0,140, 63,127,255,214,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 4, 0, 0, 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 4, 2,236,214,128, 0, 0, 0, 0, 0, 0, 0, 1,
+ 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 1, 4, 2,236,214,176, 0, 0, 0,242, 0, 0, 0, 5, 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, 5, 32, 86, 32, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+ 0, 0, 14, 56, 5, 32, 86, 32, 0, 0, 0, 56, 0, 0, 0,182, 63,230,102,133, 63,179, 51,208,191,128, 0, 4,165,127, 0, 0,
+ 90,129, 2,255, 63,230,102,133, 63, 25,154,206,191,128, 0, 4,165,127, 0, 0, 90,129, 2,255, 63,179, 51, 81, 63,179, 51,210,
+191,128, 0, 3, 0, 0, 0, 0,127,255, 2,255, 63,128, 0, 28, 63,179, 51,212,191,128, 0, 1, 0, 0, 0, 0,127,255, 2,255,
+ 63, 25,153,207, 63,179, 51,214,191,128, 0, 0, 0, 0, 0, 0,127,255, 2,255, 62, 76,205,152, 63,179, 51,216,191,127,255,254,
+ 0, 0, 0, 0,127,255, 2,255, 63,179, 51, 80, 63,128, 0,158,191,128, 0, 3, 0, 0, 0, 0,127,255, 2,255, 63,128, 0, 27,
+ 63,128, 0,160,191,128, 0, 2, 0, 0, 0, 0,127,255, 2,255, 63, 25,153,204, 63,128, 0,162,191,128, 0, 0, 0, 0, 0, 0,
+127,255, 2,255, 62, 76,205,140, 63,128, 0,163,191,127,255,254, 0, 0, 0, 0,127,255, 2,255, 63,179, 51, 80, 63, 25,154,209,
+191,128, 0, 3, 0, 0, 0, 0,127,255, 2,255, 63,128, 0, 27, 63, 25,154,213,191,128, 0, 2, 0, 0, 0, 0,127,255, 2,255,
+ 63, 25,153,204, 63, 25,154,217,191,128, 0, 0, 0, 0, 0, 0,127,255, 2,255, 62, 76,205,140, 63, 25,154,221,191,127,255,254,
+ 0, 0, 0, 0,127,255, 2,255, 63,179, 51, 80, 62, 76,209,160,191,128, 0, 3, 0, 0, 0, 0,127,255, 2,255, 63,128, 0, 27,
+ 62, 76,209,176,191,128, 0, 2, 0, 0, 0, 0,127,255, 2,255, 63, 25,153,204, 62, 76,209,188,191,128, 0, 1, 0, 0, 0, 0,
+127,255, 2,255, 62, 76,205,140, 62, 76,209,204,191,127,255,255, 0, 0, 0, 0,127,255, 2,255, 62, 76,205,140, 63,230,103, 8,
+191, 25,153,156, 0, 0,128, 1, 0, 0, 2,255, 63, 25,153,204, 63,230,103, 10,191, 25,153,160, 0, 0,128, 1, 0, 0, 2,255,
+ 63,128, 0, 27, 63,230,103, 10,191, 25,153,164, 0, 0,128, 1, 0, 0, 2,255, 63,179, 51, 80, 63,230,103, 12,191, 25,153,168,
+ 0, 0,128, 1, 0, 0, 2,255, 62, 76,205,140, 63,230,103, 8,190, 76,204,196, 0, 0,128, 1, 0, 0, 2,255, 63, 25,153,204,
+ 63,230,103, 10,190, 76,204,212, 0, 0,128, 1, 0, 0, 2,255, 63,128, 0, 27, 63,230,103, 10,190, 76,204,228, 0, 0,128, 1,
+ 0, 0, 2,255, 63,179, 51, 80, 63,230,103, 12,190, 76,204,244, 0, 0,128, 1, 0, 0, 2,255, 62, 76,205,140, 63,230,103, 8,
+ 62, 76,204,216, 0, 0,128, 1, 0, 0, 2,255, 63, 25,153,204, 63,230,103, 10, 62, 76,204,200, 0, 0,128, 1, 0, 0, 2,255,
+ 63,128, 0, 27, 63,230,103, 10, 62, 76,204,184, 0, 0,128, 1, 0, 0, 2,255, 63,179, 51, 80, 63,230,103, 12, 62, 76,204,168,
+ 0, 0,128, 1, 0, 0, 2,255, 62, 76,205,152, 63,230,103, 8, 63, 25,153,158, 0, 0,128, 1, 0, 0, 2,255, 63, 25,153,207,
+ 63,230,103, 10, 63, 25,153,154, 0, 0,128, 1, 0, 0, 2,255, 63,128, 0, 28, 63,230,103, 10, 63, 25,153,150, 0, 0,128, 1,
+ 0, 0, 2,255, 63,179, 51, 81, 63,230,103, 12, 63, 25,153,150, 0, 0,128, 1, 0, 0, 2,255, 62, 76,205,140, 63,230,103, 8,
+191,128, 0, 3, 0, 0,165,127, 90,129, 0,255, 63, 25,153,204, 63,230,103, 10,191,128, 0, 4, 0, 0,165,127, 90,129, 0,255,
+ 63,128, 0, 27, 63,230,103, 10,191,128, 0, 6, 0, 0,165,127, 90,129, 0,255, 63,179, 51, 80, 63,230,103, 12,191,128, 0, 7,
+ 0, 0,165,127, 90,129, 0,255,190, 76,205,144, 63,230,103, 12, 63, 25,153,150, 0, 0,128, 1, 0, 0, 2,255,190, 76,205,152,
+ 63,230,103, 12, 62, 76,204,168, 0, 0,128, 1, 0, 0, 2,255,190, 76,205,152, 63,230,103, 12,190, 76,204,244, 0, 0,128, 1,
+ 0, 0, 2,255,190, 76,205,152, 63,230,103, 12,191, 25,153,168, 0, 0,128, 1, 0, 0, 2,255,190, 76,205,152, 62, 76,209,160,
+191,128, 0, 3, 0, 0, 0, 0,127,255, 2,255,190, 76,205,152, 63, 25,154,209,191,128, 0, 3, 0, 0, 0, 0,127,255, 2,255,
+190, 76,205,152, 63,128, 0,158,191,128, 0, 3, 0, 0, 0, 0,127,255, 2,255,190, 76,205,144, 63,179, 51,210,191,128, 0, 3,
+ 0, 0, 0, 0,127,255, 2,255, 63,230,102,131, 63,230,103, 7,191, 25,153,155,165,127,165,127, 0, 0, 2,255, 63,230,102,131,
+ 63,179, 51,212,191, 25,153,159,128, 1, 0, 0, 0, 0, 2,255, 63,230,102,131, 63,128, 0,160,191, 25,153,163,128, 1, 0, 0,
+ 0, 0, 2,255, 63,230,102,135, 63, 25,154,207,191, 25,153,167,128, 1, 0, 0, 0, 0, 2,255, 63,230,102,131, 63,230,103, 7,
+190, 76,204,193,165,127,165,127, 0, 0, 2,255, 63,230,102,131, 63,179, 51,212,190, 76,204,209,128, 1, 0, 0, 0, 0, 2,255,
+ 63,230,102,131, 63,128, 0,160,190, 76,204,225,128, 1, 0, 0, 0, 0, 2,255, 63,230,102,135, 63, 25,154,207,190, 76,204,241,
+128, 1, 0, 0, 0, 0, 2,255, 63,230,102,131, 63,230,103, 7, 62, 76,204,219,165,127,165,127, 0, 0, 2,255, 63,230,102,131,
+ 63,179, 51,212, 62, 76,204,203,128, 1, 0, 0, 0, 0, 2,255, 63,230,102,131, 63,128, 0,160, 62, 76,204,187,128, 1, 0, 0,
+ 0, 0, 2,255, 63,230,102,135, 63, 25,154,207, 62, 76,204,171,128, 1, 0, 0, 0, 0, 2,255, 63,230,102,131, 63,230,103, 7,
+ 63, 25,153,159,165,127,165,127, 0, 0, 2,255, 63,230,102,131, 63,179, 51,212, 63, 25,153,155,128, 1, 0, 0, 0, 0, 2,255,
+ 63,230,102,131, 63,128, 0,156, 63, 25,153,151,128, 1, 0, 0, 0, 0, 2,255, 63,230,102,135, 63, 25,154,207, 63, 25,153,151,
+128, 1, 0, 0, 0, 0, 2,255, 63,230,102,131, 63,230,103, 7,191,128, 0, 3,128, 1, 0, 0, 0, 0, 2,255, 63,230,102,131,
+ 63,128, 0,160,191,128, 0, 6,165,127, 0, 0, 90,129, 2,255, 63,230,102,127, 62, 76,208, 28,191,128, 0, 3,165,127, 0, 0,
+ 90,129, 2,255, 63,230,102,131,190, 76,201,136, 63, 25,153,155,128, 1, 0, 0, 0, 0, 2,255, 63,230,102,127, 62, 76,208, 28,
+ 63, 25,153,159,128, 1, 0, 0, 0, 0, 2,255, 63,230,102,131,190, 76,201,136, 62, 76,204,203,128, 1, 0, 0, 0, 0, 2,255,
+ 63,230,102,127, 62, 76,208, 28, 62, 76,204,219,128, 1, 0, 0, 0, 0, 2,255, 63,230,102,131,190, 76,201,136,190, 76,204,209,
+128, 1, 0, 0, 0, 0, 2,255, 63,230,102,127, 62, 76,208, 28,190, 76,204,193,128, 1, 0, 0, 0, 0, 2,255, 63,230,102,131,
+190, 76,201,136,191, 25,153,159,128, 1, 0, 0, 0, 0, 2,255, 63,230,102,127, 62, 76,208, 28,191, 25,153,155,128, 1, 0, 0,
+ 0, 0, 2,255, 62, 76,205,150,190, 76,208, 24,191,127,255,254, 0, 0, 0, 0,127,255, 2,255, 63, 25,153,207,190, 76,208, 40,
+191,128, 0, 0, 0, 0, 0, 0,127,255, 2,255, 63,128, 0, 28,190, 76,208, 56,191,128, 0, 1, 0, 0, 0, 0,127,255, 2,255,
+ 63,179, 51, 81,190, 76,208, 72,191,128, 0, 3, 0, 0, 0, 0,127,255, 2,255, 63,230,102,133,190, 76,208, 88,191,128, 0, 4,
+128, 1, 0, 0, 0, 0, 2,255, 63,230,102,133,190, 76,208, 88, 63,127,255,146,128, 1, 0, 0, 0, 0, 2,255, 63,179, 51, 81,
+190, 76,208, 72, 63,127,255,148, 0, 0, 0, 0,127,255, 2,255, 63,128, 0, 28,190, 76,208, 56, 63,127,255,152, 0, 0, 0, 0,
+127,255, 2,255, 63, 25,153,207,190, 76,208, 40, 63,127,255,154, 0, 0, 0, 0,127,255, 2,255, 62, 76,205,150,190, 76,208, 24,
+ 63,127,255,156, 0, 0, 0, 0,127,255, 2,255, 63,230,102,127, 62, 76,208, 28, 63,127,255,148,165,127, 0, 0, 90,129, 2,255,
+ 63,230,102,131, 63,128, 0,160, 63,127,255,142,165,127, 0, 0, 90,129, 2,255, 63,230,102,131, 63,230,103, 7, 63,127,255,148,
+128, 1, 0, 0, 0, 0, 2,255,190, 76,205,144, 63,179, 51,210, 63,127,255,148, 0, 0, 0, 0,127,255, 2,255,190, 76,205,152,
+ 63,128, 0,158, 63,127,255,148, 0, 0, 0, 0,127,255, 2,255,190, 76,205,152, 63, 25,154,209, 63,127,255,148, 0, 0, 0, 0,
+127,255, 2,255,190, 76,205,152, 62, 76,209,160, 63,127,255,148, 0, 0, 0, 0,127,255, 2,255, 63,179, 51, 80, 63,230,103, 12,
+ 63,127,255,140, 0, 0,165,127, 90,129, 2,255, 63,128, 0, 27, 63,230,103, 10, 63,127,255,142, 0, 0,165,127, 90,129, 2,255,
+ 63, 25,153,204, 63,230,103, 10, 63,127,255,146, 0, 0,165,127, 90,129, 2,255, 62, 76,205,140, 63,230,103, 8, 63,127,255,148,
+ 0, 0,165,127, 90,129, 2,255, 62, 76,205,140, 62, 76,209,204, 63,127,255,154, 0, 0, 0, 0,127,255, 2,255, 63, 25,153,204,
+ 62, 76,209,188, 63,127,255,152, 0, 0, 0, 0,127,255, 2,255, 63,128, 0, 27, 62, 76,209,176, 63,127,255,150, 0, 0, 0, 0,
+127,255, 2,255, 63,179, 51, 80, 62, 76,209,160, 63,127,255,148, 0, 0, 0, 0,127,255, 2,255, 62, 76,205,140, 63, 25,154,221,
+ 63,127,255,156, 0, 0, 0, 0,127,255, 2,255, 63, 25,153,204, 63, 25,154,217, 63,127,255,154, 0, 0, 0, 0,127,255, 2,255,
+ 63,128, 0, 27, 63, 25,154,213, 63,127,255,150, 0, 0, 0, 0,127,255, 2,255, 63,179, 51, 80, 63, 25,154,209, 63,127,255,148,
+ 0, 0, 0, 0,127,255, 2,255, 62, 76,205,140, 63,128, 0,163, 63,127,255,156, 0, 0, 0, 0,127,255, 2,255, 63, 25,153,204,
+ 63,128, 0,162, 63,127,255,154, 0, 0, 0, 0,127,255, 2,255, 63,128, 0, 27, 63,128, 0,160, 63,127,255,150, 0, 0, 0, 0,
+127,255, 2,255, 63,179, 51, 80, 63,128, 0,158, 63,127,255,148, 0, 0, 0, 0,127,255, 2,255, 62, 76,205,152, 63,179, 51,216,
+ 63,127,255,156, 0, 0, 0, 0,127,255, 2,255, 63, 25,153,207, 63,179, 51,214, 63,127,255,154, 0, 0, 0, 0,127,255, 2,255,
+ 63,128, 0, 28, 63,179, 51,212, 63,127,255,152, 0, 0, 0, 0,127,255, 2,255, 63,179, 51, 81, 63,179, 51,210, 63,127,255,148,
+ 0, 0, 0, 0,127,255, 2,255, 63,230,102,133, 63, 25,154,206, 63,127,255,146,165,127, 0, 0, 90,129, 2,255, 63,230,102,133,
+ 63,179, 51,208, 63,127,255,146,165,127, 0, 0, 90,129, 2,255,190, 76,205,144, 62, 76,201,140, 63,127,255,148,127,255, 0, 0,
+ 0, 0, 1,255,190, 76,205,136, 63,127,255, 52, 63,127,255,148,127,255, 0, 0, 0, 0, 1,255,190, 76,205,128,190, 76,208, 48,
+ 63,127,255,150,127,255, 0, 0, 0, 0, 3,255,190, 76,205,120, 63, 25,152,194, 63,127,255,144,127,255, 0, 0, 0, 0, 1,255,
+190, 76,205, 80, 63,179, 50,254, 63,127,255,150,127,255, 0, 0, 0, 0, 1,255,190, 76,205,128, 63,230,103, 12, 63,127,255,148,
+127,255, 0, 0, 0, 0, 3,255,190, 76,205,128, 63,230,103, 12,191,128, 0, 5,127,255, 0, 0, 0, 0, 3,255,190, 76,205, 80,
+ 63,179, 50,254,191, 25,153,156,127,255, 0, 0, 0, 0, 3,255,190, 76,205,112, 63,230,102, 50,191, 25,153,160,127,255, 0, 0,
+ 0, 0, 3,255,190, 76,205, 80, 63,179, 50,254,190, 76,204,195,127,255, 0, 0, 0, 0, 3,255,190, 76,205,112, 63,230,102, 50,
+190, 76,204,211,127,255, 0, 0, 0, 0, 3,255,190, 76,205, 80, 63,179, 50,254, 62, 76,204,221,127,255, 0, 0, 0, 0, 3,255,
+190, 76,205,112, 63,230,102, 50, 62, 76,204,205,127,255, 0, 0, 0, 0, 3,255,190, 76,205, 80, 63,179, 50,254, 63, 25,153,160,
+127,255, 0, 0, 0, 0, 3,255,190, 76,205,112, 63,230,102, 50, 63, 25,153,156,127,255, 0, 0, 0, 0, 3,255,190, 76,205, 80,
+ 63,179, 50,254,191,128, 0, 4,127,255, 0, 0, 0, 0, 1,255,190, 76,205,120, 63, 25,152,194,191,128, 0, 7,127,255, 0, 0,
+ 0, 0, 1,255,190, 76,205,128,190, 76,208, 48,191,128, 0, 4,127,255, 0, 0, 0, 0, 3,255,190, 76,205,152, 63,127,255, 52,
+ 63, 25,153,152,127,255, 0, 0, 0, 0, 3,255,190, 76,205,120, 63, 25,152,202, 63, 25,153,152,127,255, 0, 0, 0, 0, 3,255,
+190, 76,205,128, 62, 76,201,108, 63, 25,153,156,127,255, 0, 0, 0, 0, 3,255,190, 76,205,128,190, 76,208, 48, 63, 25,153,160,
+127,255, 0, 0, 0, 0, 1,255,190, 76,205,152, 63,127,255, 52, 62, 76,204,173,127,255, 0, 0, 0, 0, 3,255,190, 76,205,120,
+ 63, 25,152,194, 62, 76,204,189,127,255, 0, 0, 0, 0, 3,255,190, 76,205,128, 62, 76,201,108, 62, 76,204,205,127,255, 0, 0,
+ 0, 0, 3,255,190, 76,205,128,190, 76,208, 48, 62, 76,204,221,127,255, 0, 0, 0, 0, 1,255,190, 76,205,152, 63,127,255, 52,
+190, 76,204,243,127,255, 0, 0, 0, 0, 3,255,190, 76,205,120, 63, 25,152,194,190, 76,204,227,127,255, 0, 0, 0, 0, 3,255,
+190, 76,205,128, 62, 76,201,108,190, 76,204,211,127,255, 0, 0, 0, 0, 3,255,190, 76,205,128,190, 76,208, 48,190, 76,204,195,
+127,255, 0, 0, 0, 0, 1,255,190, 76,205,152, 63,127,255, 52,191, 25,153,168,127,255, 0, 0, 0, 0, 3,255,190, 76,205,120,
+ 63, 25,152,194,191, 25,153,164,127,255, 0, 0, 0, 0, 3,255,190, 76,205,128, 62, 76,201,108,191, 25,153,160,127,255, 0, 0,
+ 0, 0, 3,255,190, 76,205,128,190, 76,208, 48,191, 25,153,156,127,255, 0, 0, 0, 0, 1,255,190, 76,205,136, 63,127,255, 52,
+191,128, 0, 5,127,255, 0, 0, 0, 0, 1,255,190, 76,205,144, 62, 76,201,140,191,128, 0, 5,127,255, 0, 0, 0, 0, 1,255,
+ 63,179, 51, 36,190, 76,208, 56, 63,127,255,150, 0, 0,127,255, 0, 0, 3,255, 63,127,255,222,190, 76,208, 80, 63,127,255,148,
+ 0, 0,127,255, 0, 0, 3,255, 63, 25,153,116,190, 76,208, 80, 63,127,255,144, 0, 0,127,255, 0, 0, 3,255, 62, 76,204, 44,
+190, 76,208,104, 63,127,255,142, 0, 0,127,255, 0, 0, 3,255,190, 76,205,112,190, 76,208, 64, 63,127,255,150,231, 94,231, 94,
+123, 41, 1,255,190, 76,205,112,190, 76,208, 64,191,128, 0, 4,231, 94,231, 94,132,215, 1,255,190, 76,205,112,190, 76,208, 64,
+ 63, 25,153,160, 0, 0,127,255, 0, 0, 1,255,190, 76,205,112,190, 76,208, 64, 62, 76,204,221, 0, 0,127,255, 0, 0, 1,255,
+190, 76,205,112,190, 76,208, 64,190, 76,204,195, 0, 0,127,255, 0, 0, 1,255,190, 76,205,112,190, 76,208, 64,191, 25,153,156,
+ 0, 0,127,255, 0, 0, 1,255, 63,230,102,136,190, 76,208, 88,191, 25,153,169, 0, 0,127,255, 0, 0, 3,255, 63,230,102,136,
+190, 76,208, 88,190, 76,204,246, 0, 0,127,255, 0, 0, 3,255, 63,230,102,136,190, 76,208, 88, 62, 76,204,170, 0, 0,127,255,
+ 0, 0, 3,255, 63,230,102,135,190, 76,208, 88, 63, 25,153,151, 0, 0,127,255, 0, 0, 3,255, 62, 76,204, 44,190, 76,208,104,
+191,128, 0, 8, 0, 0,127,255, 0, 0, 3,255, 63, 25,153,116,190, 76,208, 80,191,128, 0, 7, 0, 0,127,255, 0, 0, 3,255,
+ 63,127,255,222,190, 76,208, 80,191,128, 0, 5, 0, 0,127,255, 0, 0, 3,255, 63,179, 51, 36,190, 76,208, 56,191,128, 0, 4,
+ 0, 0,127,255, 0, 0, 3,255, 62, 76,204, 36,190, 76,208,104, 63, 25,153,151, 0, 0,127,255, 0, 0, 3,255, 63, 25,153,114,
+190, 76,208, 80, 63, 25,153,151, 0, 0,127,255, 0, 0, 3,255, 63,127,255,220,190, 76,208, 80, 63, 25,153,155, 0, 0,127,255,
+ 0, 0, 3,255, 63,179, 51, 34,190, 76,208, 56, 63, 25,153,159, 0, 0,127,255, 0, 0, 3,255, 62, 76,204, 44,190, 76,208,104,
+ 62, 76,204,170, 0, 0,127,255, 0, 0, 3,255, 63, 25,153,116,190, 76,208, 80, 62, 76,204,186, 0, 0,127,255, 0, 0, 3,255,
+ 63,127,255,222,190, 76,208, 80, 62, 76,204,202, 0, 0,127,255, 0, 0, 3,255, 63,179, 51, 36,190, 76,208, 56, 62, 76,204,218,
+ 0, 0,127,255, 0, 0, 3,255, 62, 76,204, 44,190, 76,208,104,190, 76,204,246, 0, 0,127,255, 0, 0, 3,255, 63, 25,153,116,
+190, 76,208, 80,190, 76,204,230, 0, 0,127,255, 0, 0, 3,255, 63,127,255,222,190, 76,208, 80,190, 76,204,214, 0, 0,127,255,
+ 0, 0, 3,255, 63,179, 51, 36,190, 76,208, 56,190, 76,204,198, 0, 0,127,255, 0, 0, 3,255, 62, 76,204, 44,190, 76,208,104,
+191, 25,153,169, 0, 0,127,255, 0, 0, 3,255, 63, 25,153,116,190, 76,208, 80,191, 25,153,165, 0, 0,127,255, 0, 0, 3,255,
+ 63,127,255,222,190, 76,208, 80,191, 25,153,161, 0, 0,127,255, 0, 0, 3,255, 63,179, 51, 36,190, 76,208, 56,191, 25,153,157,
+ 0, 0,127,255, 0, 0, 3,255, 68, 65, 84, 65, 0, 0, 1, 4, 2,236,215,224, 0, 0, 0,242, 0, 0, 0, 5, 0, 0, 0, 3,
+ 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, 5, 32,102, 32, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65, 0, 0, 14, 28, 5, 32,102, 32, 0, 0, 0, 53, 0, 0, 1, 45, 0, 0, 0, 4, 0, 0, 0, 5, 0, 0, 0, 34,
+ 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, 34, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 2,
+ 0, 0, 0, 34, 0, 0, 0, 5, 0, 0, 0, 9, 0, 0, 0, 34, 0, 0, 0, 8, 0, 0, 0, 9, 0, 0, 0, 34, 0, 0, 0, 4,
+ 0, 0, 0, 8, 0, 0, 0, 34, 0, 0, 0, 7, 0, 0, 0, 8, 0, 0, 0, 34, 0, 0, 0, 3, 0, 0, 0, 7, 0, 0, 0, 34,
+ 0, 0, 0, 6, 0, 0, 0, 7, 0, 0, 0, 34, 0, 0, 0, 2, 0, 0, 0, 6, 0, 0, 0, 34, 0, 0, 0, 9, 0, 0, 0, 13,
+ 0, 0, 0, 34, 0, 0, 0, 12, 0, 0, 0, 13, 0, 0, 0, 34, 0, 0, 0, 8, 0, 0, 0, 12, 0, 0, 0, 34, 0, 0, 0, 11,
+ 0, 0, 0, 12, 0, 0, 0, 34, 0, 0, 0, 7, 0, 0, 0, 11, 0, 0, 0, 34, 0, 0, 0, 10, 0, 0, 0, 11, 0, 0, 0, 34,
+ 0, 0, 0, 6, 0, 0, 0, 10, 0, 0, 0, 34, 0, 0, 0, 1, 0, 0, 0, 10, 0, 0, 0, 34, 0, 0, 0, 13, 0, 0, 0, 17,
+ 0, 0, 0, 34, 0, 0, 0, 16, 0, 0, 0, 17, 0, 0, 0, 34, 0, 0, 0, 12, 0, 0, 0, 16, 0, 0, 0, 34, 0, 0, 0, 15,
+ 0, 0, 0, 16, 0, 0, 0, 34, 0, 0, 0, 11, 0, 0, 0, 15, 0, 0, 0, 34, 0, 0, 0, 14, 0, 0, 0, 15, 0, 0, 0, 34,
+ 0, 0, 0, 10, 0, 0, 0, 14, 0, 0, 0, 34, 0, 0, 0, 21, 0, 0, 0, 37, 0, 0, 0, 34, 0, 0, 0, 20, 0, 0, 0, 36,
+ 0, 0, 0, 34, 0, 0, 0, 19, 0, 0, 0, 35, 0, 0, 0, 34, 0, 0, 0, 18, 0, 0, 0, 34, 0, 0, 0, 34, 0, 0, 0, 21,
+ 0, 0, 0, 25, 0, 0, 0, 34, 0, 0, 0, 20, 0, 0, 0, 21, 0, 0, 0, 34, 0, 0, 0, 20, 0, 0, 0, 24, 0, 0, 0, 34,
+ 0, 0, 0, 19, 0, 0, 0, 20, 0, 0, 0, 34, 0, 0, 0, 19, 0, 0, 0, 23, 0, 0, 0, 34, 0, 0, 0, 18, 0, 0, 0, 19,
+ 0, 0, 0, 34, 0, 0, 0, 18, 0, 0, 0, 22, 0, 0, 0, 34, 0, 0, 0, 25, 0, 0, 0, 29, 0, 0, 0, 34, 0, 0, 0, 24,
+ 0, 0, 0, 25, 0, 0, 0, 34, 0, 0, 0, 24, 0, 0, 0, 28, 0, 0, 0, 34, 0, 0, 0, 23, 0, 0, 0, 24, 0, 0, 0, 34,
+ 0, 0, 0, 23, 0, 0, 0, 27, 0, 0, 0, 34, 0, 0, 0, 22, 0, 0, 0, 23, 0, 0, 0, 34, 0, 0, 0, 22, 0, 0, 0, 26,
+ 0, 0, 0, 34, 0, 0, 0, 29, 0, 0, 0, 33, 0, 0, 0, 34, 0, 0, 0, 28, 0, 0, 0, 29, 0, 0, 0, 34, 0, 0, 0, 28,
+ 0, 0, 0, 32, 0, 0, 0, 34, 0, 0, 0, 27, 0, 0, 0, 28, 0, 0, 0, 34, 0, 0, 0, 27, 0, 0, 0, 31, 0, 0, 0, 34,
+ 0, 0, 0, 26, 0, 0, 0, 27, 0, 0, 0, 34, 0, 0, 0, 26, 0, 0, 0, 30, 0, 0, 0, 34, 0, 0, 0, 32, 0, 0, 0, 33,
+ 0, 0, 0, 34, 0, 0, 0, 31, 0, 0, 0, 32, 0, 0, 0, 34, 0, 0, 0, 30, 0, 0, 0, 31, 0, 0, 0, 34, 0, 0, 0, 34,
+ 0, 0, 0, 35, 0, 0, 0, 34, 0, 0, 0, 36, 0, 0, 0, 37, 0, 0, 0, 34, 0, 0, 0, 2, 0, 0, 0, 37, 0, 0, 0, 34,
+ 0, 0, 0, 3, 0, 0, 0, 36, 0, 0, 0, 34, 0, 0, 0, 4, 0, 0, 0, 35, 0, 0, 0, 34, 0, 0, 0, 5, 0, 0, 0, 34,
+ 0, 0, 0, 34, 0, 0, 0, 38, 0, 0, 0, 39, 0, 0, 0, 34, 0, 0, 0, 40, 0, 0, 0, 41, 0, 0, 0, 34, 0, 0, 0, 42,
+ 0, 0, 0, 43, 0, 0, 0, 34, 0, 0, 0, 44, 0, 0, 0, 45, 0, 0, 0, 34, 0, 0, 0, 30, 0, 0, 0, 38, 0, 0, 0, 34,
+ 0, 0, 0, 26, 0, 0, 0, 39, 0, 0, 0, 34, 0, 0, 0, 22, 0, 0, 0, 40, 0, 0, 0, 34, 0, 0, 0, 18, 0, 0, 0, 41,
+ 0, 0, 0, 34, 0, 0, 0, 17, 0, 0, 0, 42, 0, 0, 0, 34, 0, 0, 0, 13, 0, 0, 0, 43, 0, 0, 0, 34, 0, 0, 0, 9,
+ 0, 0, 0, 44, 0, 0, 0, 34, 0, 0, 0, 5, 0, 0, 0, 45, 0, 0, 0, 34, 0, 0, 0, 49, 0, 0, 0, 72, 0, 0, 0, 34,
+ 0, 0, 0, 53, 0, 0, 0, 70, 0, 0, 0, 34, 0, 0, 0, 57, 0, 0, 0, 68, 0, 0, 0, 34, 0, 0, 0, 61, 0, 0, 0, 66,
+ 0, 0, 0, 34, 0, 0, 0, 48, 0, 0, 0, 63, 0, 0, 0, 34, 0, 0, 0, 46, 0, 0, 0, 62, 0, 0, 0, 34, 0, 0, 0, 49,
+ 0, 0, 0, 53, 0, 0, 0, 34, 0, 0, 0, 48, 0, 0, 0, 49, 0, 0, 0, 34, 0, 0, 0, 48, 0, 0, 0, 52, 0, 0, 0, 34,
+ 0, 0, 0, 47, 0, 0, 0, 48, 0, 0, 0, 34, 0, 0, 0, 47, 0, 0, 0, 51, 0, 0, 0, 34, 0, 0, 0, 46, 0, 0, 0, 47,
+ 0, 0, 0, 34, 0, 0, 0, 46, 0, 0, 0, 50, 0, 0, 0, 34, 0, 0, 0, 53, 0, 0, 0, 57, 0, 0, 0, 34, 0, 0, 0, 52,
+ 0, 0, 0, 53, 0, 0, 0, 34, 0, 0, 0, 52, 0, 0, 0, 56, 0, 0, 0, 34, 0, 0, 0, 51, 0, 0, 0, 52, 0, 0, 0, 34,
+ 0, 0, 0, 51, 0, 0, 0, 55, 0, 0, 0, 34, 0, 0, 0, 50, 0, 0, 0, 51, 0, 0, 0, 34, 0, 0, 0, 50, 0, 0, 0, 54,
+ 0, 0, 0, 34, 0, 0, 0, 57, 0, 0, 0, 61, 0, 0, 0, 34, 0, 0, 0, 56, 0, 0, 0, 57, 0, 0, 0, 34, 0, 0, 0, 56,
+ 0, 0, 0, 60, 0, 0, 0, 34, 0, 0, 0, 55, 0, 0, 0, 56, 0, 0, 0, 34, 0, 0, 0, 55, 0, 0, 0, 59, 0, 0, 0, 34,
+ 0, 0, 0, 54, 0, 0, 0, 55, 0, 0, 0, 34, 0, 0, 0, 54, 0, 0, 0, 58, 0, 0, 0, 34, 0, 0, 0, 60, 0, 0, 0, 61,
+ 0, 0, 0, 34, 0, 0, 0, 59, 0, 0, 0, 60, 0, 0, 0, 34, 0, 0, 0, 58, 0, 0, 0, 59, 0, 0, 0, 34, 0, 0, 0, 65,
+ 0, 0, 0, 66, 0, 0, 0, 34, 0, 0, 0, 66, 0, 0, 0, 68, 0, 0, 0, 34, 0, 0, 0, 67, 0, 0, 0, 68, 0, 0, 0, 34,
+ 0, 0, 0, 68, 0, 0, 0, 70, 0, 0, 0, 34, 0, 0, 0, 69, 0, 0, 0, 70, 0, 0, 0, 34, 0, 0, 0, 67, 0, 0, 0, 69,
+ 0, 0, 0, 34, 0, 0, 0, 70, 0, 0, 0, 72, 0, 0, 0, 34, 0, 0, 0, 71, 0, 0, 0, 72, 0, 0, 0, 34, 0, 0, 0, 64,
+ 0, 0, 0, 72, 0, 0, 0, 34, 0, 0, 0, 1, 0, 0, 0, 63, 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 34,
+ 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 47, 0, 0, 0, 34, 0, 0, 0, 1, 0, 0, 0, 49,
+ 0, 0, 0, 34, 0, 0, 0, 1, 0, 0, 0, 64, 0, 0, 0, 34, 0, 0, 0, 33, 0, 0, 0, 58, 0, 0, 0, 34, 0, 0, 0, 29,
+ 0, 0, 0, 54, 0, 0, 0, 34, 0, 0, 0, 25, 0, 0, 0, 50, 0, 0, 0, 34, 0, 0, 0, 21, 0, 0, 0, 46, 0, 0, 0, 34,
+ 0, 0, 0, 14, 0, 0, 0, 64, 0, 0, 0, 34, 0, 0, 0, 6, 0, 0, 0, 63, 0, 0, 0, 34, 0, 0, 0, 75, 0, 0, 0, 76,
+ 0, 0, 0, 34, 0, 0, 0, 73, 0, 0, 0, 74, 0, 0, 0, 34, 0, 0, 0, 71, 0, 0, 0, 77, 0, 0, 0, 34, 0, 0, 0, 64,
+ 0, 0, 0, 77, 0, 0, 0, 34, 0, 0, 0, 14, 0, 0, 0, 76, 0, 0, 0, 34, 0, 0, 0, 15, 0, 0, 0, 75, 0, 0, 0, 34,
+ 0, 0, 0, 16, 0, 0, 0, 74, 0, 0, 0, 34, 0, 0, 0, 17, 0, 0, 0, 73, 0, 0, 0, 34, 0, 0, 0, 82, 0, 0, 0, 94,
+ 0, 0, 0, 34, 0, 0, 0, 81, 0, 0, 0, 95, 0, 0, 0, 34, 0, 0, 0, 80, 0, 0, 0, 96, 0, 0, 0, 34, 0, 0, 0, 79,
+ 0, 0, 0, 97, 0, 0, 0, 34, 0, 0, 0, 78, 0, 0, 0, 83, 0, 0, 0, 34, 0, 0, 0, 81, 0, 0, 0, 82, 0, 0, 0, 34,
+ 0, 0, 0, 79, 0, 0, 0, 80, 0, 0, 0, 34, 0, 0, 0, 84, 0, 0, 0,105, 0, 0, 0, 34, 0, 0, 0, 83, 0, 0, 0, 97,
+ 0, 0, 0, 34, 0, 0, 0, 83, 0, 0, 0,110, 0, 0, 0, 34, 0, 0, 0, 85, 0, 0, 0,111, 0, 0, 0, 34, 0, 0, 0, 84,
+ 0, 0, 0,111, 0, 0, 0, 34, 0, 0, 0, 84, 0, 0, 0,110, 0, 0, 0, 34, 0, 0, 0, 86, 0, 0, 0,106, 0, 0, 0, 34,
+ 0, 0, 0, 87, 0, 0, 0,102, 0, 0, 0, 34, 0, 0, 0, 88, 0, 0, 0, 98, 0, 0, 0, 34, 0, 0, 0, 89, 0, 0, 0, 94,
+ 0, 0, 0, 34, 0, 0, 0, 86, 0, 0, 0, 87, 0, 0, 0, 34, 0, 0, 0, 88, 0, 0, 0, 89, 0, 0, 0, 34, 0, 0, 0, 93,
+ 0, 0, 0,106, 0, 0, 0, 34, 0, 0, 0, 92, 0, 0, 0,107, 0, 0, 0, 34, 0, 0, 0, 91, 0, 0, 0,108, 0, 0, 0, 34,
+ 0, 0, 0, 90, 0, 0, 0,109, 0, 0, 0, 34, 0, 0, 0, 90, 0, 0, 0, 91, 0, 0, 0, 34, 0, 0, 0, 92, 0, 0, 0, 93,
+ 0, 0, 0, 34, 0, 0, 0, 97, 0, 0, 0,101, 0, 0, 0, 34, 0, 0, 0, 96, 0, 0, 0, 97, 0, 0, 0, 34, 0, 0, 0, 96,
+ 0, 0, 0,100, 0, 0, 0, 34, 0, 0, 0, 95, 0, 0, 0, 96, 0, 0, 0, 34, 0, 0, 0, 95, 0, 0, 0, 99, 0, 0, 0, 34,
+ 0, 0, 0, 94, 0, 0, 0, 95, 0, 0, 0, 34, 0, 0, 0, 94, 0, 0, 0, 98, 0, 0, 0, 34, 0, 0, 0,101, 0, 0, 0,110,
+ 0, 0, 0, 34, 0, 0, 0,101, 0, 0, 0,105, 0, 0, 0, 34, 0, 0, 0,100, 0, 0, 0,101, 0, 0, 0, 34, 0, 0, 0,100,
+ 0, 0, 0,104, 0, 0, 0, 34, 0, 0, 0, 99, 0, 0, 0,100, 0, 0, 0, 34, 0, 0, 0, 99, 0, 0, 0,103, 0, 0, 0, 34,
+ 0, 0, 0, 98, 0, 0, 0, 99, 0, 0, 0, 34, 0, 0, 0, 98, 0, 0, 0,102, 0, 0, 0, 34, 0, 0, 0,105, 0, 0, 0,109,
+ 0, 0, 0, 34, 0, 0, 0,104, 0, 0, 0,105, 0, 0, 0, 34, 0, 0, 0,104, 0, 0, 0,108, 0, 0, 0, 34, 0, 0, 0,103,
+ 0, 0, 0,104, 0, 0, 0, 34, 0, 0, 0,103, 0, 0, 0,107, 0, 0, 0, 34, 0, 0, 0,102, 0, 0, 0,103, 0, 0, 0, 34,
+ 0, 0, 0,102, 0, 0, 0,106, 0, 0, 0, 34, 0, 0, 0,109, 0, 0, 0,111, 0, 0, 0, 34, 0, 0, 0,108, 0, 0, 0,109,
+ 0, 0, 0, 34, 0, 0, 0,107, 0, 0, 0,108, 0, 0, 0, 34, 0, 0, 0,106, 0, 0, 0,107, 0, 0, 0, 34, 0, 0, 0, 65,
+ 0, 0, 0, 78, 0, 0, 0, 34, 0, 0, 0, 66, 0, 0, 0, 83, 0, 0, 0, 34, 0, 0, 0, 58, 0, 0, 0, 85, 0, 0, 0, 34,
+ 0, 0, 0, 59, 0, 0, 0,111, 0, 0, 0, 34, 0, 0, 0, 60, 0, 0, 0, 84, 0, 0, 0, 34, 0, 0, 0, 61, 0, 0, 0,110,
+ 0, 0, 0, 34, 0, 0, 0, 30, 0, 0, 0, 93, 0, 0, 0, 34, 0, 0, 0, 31, 0, 0, 0, 92, 0, 0, 0, 34, 0, 0, 0, 32,
+ 0, 0, 0, 91, 0, 0, 0, 34, 0, 0, 0, 33, 0, 0, 0, 90, 0, 0, 0, 34, 0, 0, 0,113, 0, 0, 0,130, 0, 0, 0, 35,
+ 0, 0, 0,115, 0, 0, 0,131, 0, 0, 0, 35, 0, 0, 0,112, 0, 0, 0,132, 0, 0, 0, 35, 0, 0, 0,114, 0, 0, 0,133,
+ 0, 0, 0, 35, 0, 0, 0,116, 0, 0, 0,125, 0, 0, 0, 35, 0, 0, 0,117, 0, 0, 0,126, 0, 0, 0, 35, 0, 0, 0,113,
+ 0, 0, 0,115, 0, 0, 0, 35, 0, 0, 0,112, 0, 0, 0,115, 0, 0, 0,163, 0, 0, 0,112, 0, 0, 0,114, 0, 0, 0, 35,
+ 0, 0, 0,113, 0, 0, 0,116, 0, 0, 0,163, 0, 0, 0,116, 0, 0, 0,117, 0, 0, 0, 35, 0, 0, 0,118, 0, 0, 0,127,
+ 0, 0, 0, 35, 0, 0, 0,118, 0, 0, 0,120, 0, 0, 0, 35, 0, 0, 0,127, 0, 0, 0,146, 0, 0, 0,163, 0, 0, 0,142,
+ 0, 0, 0,146, 0, 0, 0, 35, 0, 0, 0,144, 0, 0, 0,147, 0, 0, 0, 35, 0, 0, 0,129, 0, 0, 0,147, 0, 0, 0, 35,
+ 0, 0, 0,128, 0, 0, 0,147, 0, 0, 0,163, 0, 0, 0,128, 0, 0, 0,146, 0, 0, 0, 35, 0, 0, 0,119, 0, 0, 0,127,
+ 0, 0, 0, 35, 0, 0, 0,119, 0, 0, 0,120, 0, 0, 0, 35, 0, 0, 0,119, 0, 0, 0,121, 0, 0, 0, 35, 0, 0, 0,122,
+ 0, 0, 0,124, 0, 0, 0, 35, 0, 0, 0,121, 0, 0, 0,122, 0, 0, 0, 35, 0, 0, 0,121, 0, 0, 0,123, 0, 0, 0, 35,
+ 0, 0, 0,123, 0, 0, 0,124, 0, 0, 0, 35, 0, 0, 0,123, 0, 0, 0,125, 0, 0, 0, 35, 0, 0, 0,125, 0, 0, 0,126,
+ 0, 0, 0, 35, 0, 0, 0,132, 0, 0, 0,133, 0, 0, 0, 35, 0, 0, 0,131, 0, 0, 0,132, 0, 0, 0, 35, 0, 0, 0,130,
+ 0, 0, 0,131, 0, 0, 0, 35, 0, 0, 0,133, 0, 0, 0,137, 0, 0, 0,163, 0, 0, 0,136, 0, 0, 0,137, 0, 0, 0, 35,
+ 0, 0, 0,132, 0, 0, 0,136, 0, 0, 0, 35, 0, 0, 0,135, 0, 0, 0,136, 0, 0, 0, 35, 0, 0, 0,131, 0, 0, 0,135,
+ 0, 0, 0, 35, 0, 0, 0,134, 0, 0, 0,135, 0, 0, 0, 35, 0, 0, 0,130, 0, 0, 0,134, 0, 0, 0, 35, 0, 0, 0,137,
+ 0, 0, 0,141, 0, 0, 0, 35, 0, 0, 0,140, 0, 0, 0,141, 0, 0, 0, 35, 0, 0, 0,136, 0, 0, 0,140, 0, 0, 0, 35,
+ 0, 0, 0,139, 0, 0, 0,140, 0, 0, 0, 35, 0, 0, 0,135, 0, 0, 0,139, 0, 0, 0, 35, 0, 0, 0,138, 0, 0, 0,139,
+ 0, 0, 0, 35, 0, 0, 0,134, 0, 0, 0,138, 0, 0, 0, 35, 0, 0, 0,141, 0, 0, 0,145, 0, 0, 0,163, 0, 0, 0,144,
+ 0, 0, 0,145, 0, 0, 0, 35, 0, 0, 0,140, 0, 0, 0,144, 0, 0, 0, 35, 0, 0, 0,143, 0, 0, 0,144, 0, 0, 0, 35,
+ 0, 0, 0,139, 0, 0, 0,143, 0, 0, 0, 35, 0, 0, 0,142, 0, 0, 0,143, 0, 0, 0, 35, 0, 0, 0,138, 0, 0, 0,142,
+ 0, 0, 0, 35, 0, 0, 0,129, 0, 0, 0,145, 0, 0, 0, 35, 0, 0, 0,128, 0, 0, 0,143, 0, 0, 0, 35, 0, 0, 0,125,
+ 0, 0, 0,130, 0, 0, 0, 35, 0, 0, 0,123, 0, 0, 0,134, 0, 0, 0, 35, 0, 0, 0,121, 0, 0, 0,138, 0, 0, 0, 35,
+ 0, 0, 0,119, 0, 0, 0,142, 0, 0, 0, 35, 0, 0, 0,151, 0, 0, 0,166, 0, 0, 0, 35, 0, 0, 0,150, 0, 0, 0,167,
+ 0, 0, 0, 35, 0, 0, 0,149, 0, 0, 0,168, 0, 0, 0, 35, 0, 0, 0,148, 0, 0, 0,169, 0, 0, 0, 35, 0, 0, 0,152,
+ 0, 0, 0,154, 0, 0, 0,163, 0, 0, 0,148, 0, 0, 0,149, 0, 0, 0, 35, 0, 0, 0,150, 0, 0, 0,151, 0, 0, 0, 35,
+ 0, 0, 0,157, 0, 0, 0,178, 0, 0, 0, 35, 0, 0, 0,156, 0, 0, 0,174, 0, 0, 0, 35, 0, 0, 0,155, 0, 0, 0,170,
+ 0, 0, 0, 35, 0, 0, 0,154, 0, 0, 0,166, 0, 0, 0, 35, 0, 0, 0,154, 0, 0, 0,155, 0, 0, 0, 35, 0, 0, 0,155,
+ 0, 0, 0,156, 0, 0, 0,163, 0, 0, 0,156, 0, 0, 0,157, 0, 0, 0, 35, 0, 0, 0,153, 0, 0, 0,157, 0, 0, 0,163,
+ 0, 0, 0,158, 0, 0, 0,181, 0, 0, 0, 35, 0, 0, 0,159, 0, 0, 0,177, 0, 0, 0, 35, 0, 0, 0,160, 0, 0, 0,173,
+ 0, 0, 0, 35, 0, 0, 0,161, 0, 0, 0,169, 0, 0, 0, 35, 0, 0, 0,158, 0, 0, 0,159, 0, 0, 0, 35, 0, 0, 0,160,
+ 0, 0, 0,161, 0, 0, 0, 35, 0, 0, 0,162, 0, 0, 0,163, 0, 0, 0, 35, 0, 0, 0,164, 0, 0, 0,165, 0, 0, 0, 35,
+ 0, 0, 0,168, 0, 0, 0,169, 0, 0, 0, 35, 0, 0, 0,167, 0, 0, 0,168, 0, 0, 0, 35, 0, 0, 0,166, 0, 0, 0,167,
+ 0, 0, 0, 35, 0, 0, 0,169, 0, 0, 0,173, 0, 0, 0, 35, 0, 0, 0,172, 0, 0, 0,173, 0, 0, 0, 35, 0, 0, 0,168,
+ 0, 0, 0,172, 0, 0, 0, 35, 0, 0, 0,171, 0, 0, 0,172, 0, 0, 0, 35, 0, 0, 0,167, 0, 0, 0,171, 0, 0, 0, 35,
+ 0, 0, 0,170, 0, 0, 0,171, 0, 0, 0, 35, 0, 0, 0,166, 0, 0, 0,170, 0, 0, 0, 35, 0, 0, 0,173, 0, 0, 0,177,
+ 0, 0, 0, 35, 0, 0, 0,176, 0, 0, 0,177, 0, 0, 0, 35, 0, 0, 0,172, 0, 0, 0,176, 0, 0, 0, 35, 0, 0, 0,175,
+ 0, 0, 0,176, 0, 0, 0, 35, 0, 0, 0,171, 0, 0, 0,175, 0, 0, 0, 35, 0, 0, 0,174, 0, 0, 0,175, 0, 0, 0, 35,
+ 0, 0, 0,170, 0, 0, 0,174, 0, 0, 0, 35, 0, 0, 0,177, 0, 0, 0,181, 0, 0, 0, 35, 0, 0, 0,180, 0, 0, 0,181,
+ 0, 0, 0, 35, 0, 0, 0,176, 0, 0, 0,180, 0, 0, 0, 35, 0, 0, 0,179, 0, 0, 0,180, 0, 0, 0, 35, 0, 0, 0,175,
+ 0, 0, 0,179, 0, 0, 0, 35, 0, 0, 0,178, 0, 0, 0,179, 0, 0, 0, 35, 0, 0, 0,174, 0, 0, 0,178, 0, 0, 0, 35,
+ 0, 0, 0,165, 0, 0, 0,181, 0, 0, 0, 35, 0, 0, 0,164, 0, 0, 0,180, 0, 0, 0, 35, 0, 0, 0,163, 0, 0, 0,179,
+ 0, 0, 0, 35, 0, 0, 0,162, 0, 0, 0,178, 0, 0, 0, 35, 68, 65, 84, 65, 0, 0, 1, 4, 2,236,217, 16, 0, 0, 0,242,
+ 0, 0, 0, 5, 0, 0, 0, 4, 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, 5, 32,118, 32, 0, 0, 0, 5, 0, 0, 0, 20,
+ 0, 0, 0, 0, 0, 0, 0, 0, 85, 86, 84,101,120, 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, 5, 32,124, 32, 0, 0, 0, 6, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 67,111,108, 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, 5, 32,138, 32,
+ 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, 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, 68, 65, 84, 65, 0, 0, 5,200, 5, 32,118, 32, 0, 0, 0, 52, 0, 0, 0, 74, 0, 0, 0, 35,
+ 0, 0, 0, 34, 0, 0, 0, 5, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 37, 0, 0, 0, 36, 0, 0, 0, 3, 0, 0, 0, 2,
+ 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 45, 0, 0, 0, 44, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 4,
+ 0, 0, 0, 8, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 6, 0, 0, 0, 63, 0, 0, 0, 0,
+ 0, 0, 0, 8, 0, 0, 0, 9, 0, 0, 0, 13, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 7, 0, 0, 0, 11,
+ 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 43, 0, 0, 0, 42, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 11,
+ 0, 0, 0, 12, 0, 0, 0, 16, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 10, 0, 0, 0, 14, 0, 0, 0, 64,
+ 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 17, 0, 0, 0, 73, 0, 0, 0, 74, 0, 0, 0, 0, 0, 0, 0, 75, 0, 0, 0, 76,
+ 0, 0, 0, 14, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 20, 0, 0, 0, 36, 0, 0, 0, 37, 0, 0, 0, 0,
+ 0, 0, 0, 19, 0, 0, 0, 18, 0, 0, 0, 34, 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 50, 0, 0, 0, 25, 0, 0, 0, 21,
+ 0, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 23, 0, 0, 0, 19, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 22,
+ 0, 0, 0, 40, 0, 0, 0, 41, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0, 0, 28, 0, 0, 0, 24, 0, 0, 0, 25,
+ 0, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 26, 0, 0, 0, 22, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 58, 0, 0, 0, 33,
+ 0, 0, 0, 29, 0, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 31, 0, 0, 0, 27, 0, 0, 0, 28, 0, 0, 0, 0,
+ 0, 0, 0, 30, 0, 0, 0, 38, 0, 0, 0, 39, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 90, 0, 0, 0, 91, 0, 0, 0, 32,
+ 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 92, 0, 0, 0, 93, 0, 0, 0, 30, 0, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 49,
+ 0, 0, 0, 48, 0, 0, 0, 63, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 47, 0, 0, 0, 46,
+ 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 51, 0, 0, 0, 47, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 57, 0, 0, 0, 56,
+ 0, 0, 0, 52, 0, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, 54, 0, 0, 0, 50, 0, 0, 0, 51, 0, 0, 0, 0,
+ 0, 0, 0, 60, 0, 0, 0, 59, 0, 0, 0, 55, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0,110, 0, 0, 0, 84, 0, 0, 0, 60,
+ 0, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0,111, 0, 0, 0, 85, 0, 0, 0, 58, 0, 0, 0, 59, 0, 0, 0, 0, 0, 0, 0, 78,
+ 0, 0, 0, 83, 0, 0, 0, 66, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 66, 0, 0, 0, 61, 0, 0, 0, 57, 0, 0, 0, 68,
+ 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, 0, 68, 0, 0, 0, 70, 0, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, 70, 0, 0, 0, 53,
+ 0, 0, 0, 49, 0, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 71, 0, 0, 0, 72, 0, 0, 0, 64, 0, 0, 0, 77, 0, 0, 0, 0,
+ 0, 0, 0, 80, 0, 0, 0, 79, 0, 0, 0, 97, 0, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 95, 0, 0, 0, 94, 0, 0, 0, 82,
+ 0, 0, 0, 81, 0, 0, 0, 0, 0, 0, 0,110, 0, 0, 0,101, 0, 0, 0, 97, 0, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0,100,
+ 0, 0, 0, 99, 0, 0, 0, 95, 0, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 98, 0, 0, 0, 88, 0, 0, 0, 89, 0, 0, 0, 94,
+ 0, 0, 0, 0, 0, 0, 0,105, 0, 0, 0,104, 0, 0, 0,100, 0, 0, 0,101, 0, 0, 0, 0, 0, 0, 0,103, 0, 0, 0,102,
+ 0, 0, 0, 98, 0, 0, 0, 99, 0, 0, 0, 0, 0, 0, 0,111, 0, 0, 0,109, 0, 0, 0,105, 0, 0, 0, 84, 0, 0, 0, 0,
+ 0, 0, 0,108, 0, 0, 0,107, 0, 0, 0,103, 0, 0, 0,104, 0, 0, 0, 0, 0, 0, 0,106, 0, 0, 0, 86, 0, 0, 0, 87,
+ 0, 0, 0,102, 0, 0, 0, 0, 0, 0, 0, 90, 0, 0, 0, 91, 0, 0, 0,108, 0, 0, 0,109, 0, 0, 0, 0, 0, 0, 0, 92,
+ 0, 0, 0, 93, 0, 0, 0,106, 0, 0, 0,107, 0, 0, 0, 0, 0, 0, 0,120, 0, 0, 0,119, 0, 0, 0,127, 0, 0, 0,118,
+ 0, 0, 0, 2, 0, 0, 0,121, 0, 0, 0,138, 0, 0, 0,142, 0, 0, 0,119, 0, 0, 0, 2, 0, 0, 0,124, 0, 0, 0,123,
+ 0, 0, 0,121, 0, 0, 0,122, 0, 0, 0, 2, 0, 0, 0,125, 0, 0, 0,130, 0, 0, 0,134, 0, 0, 0,123, 0, 0, 0, 2,
+ 0, 0, 0,117, 0, 0, 0,116, 0, 0, 0,125, 0, 0, 0,126, 0, 0, 0, 2, 0, 0, 0,112, 0, 0, 0,114, 0, 0, 0,133,
+ 0, 0, 0,132, 0, 0, 0, 2, 0, 0, 0,113, 0, 0, 0,115, 0, 0, 0,131, 0, 0, 0,130, 0, 0, 0, 2, 0, 0, 0,131,
+ 0, 0, 0,132, 0, 0, 0,136, 0, 0, 0,135, 0, 0, 0, 2, 0, 0, 0,136, 0, 0, 0,137, 0, 0, 0,141, 0, 0, 0,140,
+ 0, 0, 0, 2, 0, 0, 0,134, 0, 0, 0,135, 0, 0, 0,139, 0, 0, 0,138, 0, 0, 0, 2, 0, 0, 0,139, 0, 0, 0,140,
+ 0, 0, 0,144, 0, 0, 0,143, 0, 0, 0, 2, 0, 0, 0,129, 0, 0, 0,147, 0, 0, 0,144, 0, 0, 0,145, 0, 0, 0, 2,
+ 0, 0, 0,142, 0, 0, 0,143, 0, 0, 0,128, 0, 0, 0,146, 0, 0, 0, 2, 0, 0, 0,149, 0, 0, 0,148, 0, 0, 0,169,
+ 0, 0, 0,168, 0, 0, 0, 2, 0, 0, 0,151, 0, 0, 0,150, 0, 0, 0,167, 0, 0, 0,166, 0, 0, 0, 2, 0, 0, 0,169,
+ 0, 0, 0,161, 0, 0, 0,160, 0, 0, 0,173, 0, 0, 0, 2, 0, 0, 0,167, 0, 0, 0,168, 0, 0, 0,172, 0, 0, 0,171,
+ 0, 0, 0, 2, 0, 0, 0,154, 0, 0, 0,166, 0, 0, 0,170, 0, 0, 0,155, 0, 0, 0, 2, 0, 0, 0,172, 0, 0, 0,173,
+ 0, 0, 0,177, 0, 0, 0,176, 0, 0, 0, 2, 0, 0, 0,170, 0, 0, 0,171, 0, 0, 0,175, 0, 0, 0,174, 0, 0, 0, 2,
+ 0, 0, 0,177, 0, 0, 0,159, 0, 0, 0,158, 0, 0, 0,181, 0, 0, 0, 2, 0, 0, 0,175, 0, 0, 0,176, 0, 0, 0,180,
+ 0, 0, 0,179, 0, 0, 0, 2, 0, 0, 0,156, 0, 0, 0,174, 0, 0, 0,178, 0, 0, 0,157, 0, 0, 0, 2, 0, 0, 0,180,
+ 0, 0, 0,181, 0, 0, 0,165, 0, 0, 0,164, 0, 0, 0, 2, 0, 0, 0,178, 0, 0, 0,179, 0, 0, 0,163, 0, 0, 0,162,
+ 0, 0, 0, 2, 68, 65, 84, 65, 0, 0, 12,184, 5, 32,124, 32, 0, 0, 0, 60, 0, 0, 0, 74, 61,104, 84,160, 63, 79, 65,242,
+189,188,105,128, 63, 41, 47,120, 61,104, 84,160, 63, 3, 29, 0, 62, 82, 95, 26, 63, 41, 47,120, 0, 0, 0, 0, 60, 0, 0, 1,
+ 0, 0, 0, 0, 62,181, 84,122, 63,141,179,113, 62, 82, 95, 26, 63,117, 84,102, 62,181, 84,127, 63, 79, 65,242, 63, 0,188,190,
+ 63,117, 84,102, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 61,104, 84,160, 63, 3, 29, 0,189,188,106,128, 62,186, 20,176,
+ 61,104, 82,144, 62, 91,223,128, 62, 82, 95, 14, 62,186, 21, 0, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 62,181, 84,127,
+ 63, 79, 65,242, 62, 82, 95, 26, 63, 41, 47,120, 62,181, 84,122, 63, 3, 28,248, 63, 0,188,188, 63, 41, 47,120, 0, 0, 0, 0,
+ 60, 0, 0, 1, 0, 0, 0, 0, 63, 38,207, 56, 63,141,179,111, 63, 0,188,190, 63,117, 84,102, 63, 38,207, 52, 63, 79, 65,236,
+ 63, 76,225,172, 63,117, 84,102, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 62,181, 84,122, 63, 3, 28,248, 62, 82, 95, 14,
+ 62,186, 21, 0, 62,181, 84,122, 62, 91,224, 32, 63, 0,188,185, 62,186, 21, 0, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0,
+ 63, 38,207, 52, 63, 79, 65,236, 63, 0,188,188, 63, 41, 47,120, 63, 38,207, 52, 63, 3, 28,248, 63, 76,225,174, 63, 41, 47,116,
+ 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 62,181, 84,122, 62, 91,224, 32, 62, 82, 94,138, 61,135, 43, 48, 62,181, 84, 61,
+189,169,104,176, 63, 0,188,185, 61,135, 44, 96, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 63, 38,207, 52, 63, 3, 28,248,
+ 63, 0,188,185, 62,186, 21, 0, 63, 38,207, 51, 62, 91,224, 24, 63, 76,225,174, 62,186, 21, 0, 0, 0, 0, 0, 60, 0, 0, 1,
+ 0, 0, 0, 0, 63,114,244, 44, 63, 79, 65,236, 63, 76,225,174, 63, 41, 47,116, 63,114,244, 42, 63, 3, 28,244, 63,140,131, 99,
+ 63, 41, 47, 76, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 63, 38,207, 51, 62, 91,224, 24, 63, 0,188,185, 61,135, 44, 96,
+ 63, 38,207,248,189,169,109,144, 63, 76,226,112, 61,135, 38, 64, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 63,114,244,240,
+ 62, 91,221, 4, 63,140,131,180, 62,186, 19,116, 63,114,244, 42, 63, 3, 28,244, 63, 76,225,174, 62,186, 21, 0, 0, 0, 0, 0,
+ 60, 0, 0, 1, 0, 0, 0, 0, 62,181, 84,122, 63,141,179,113, 62, 82, 95, 26, 63,117, 84,102, 62, 82, 95, 26, 63,117, 84,102,
+ 62,181, 84,122, 63,141,179,113, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 61,104, 84,160, 63, 79, 65,242,189,188,105,128,
+ 63, 41, 47,120,189,188,105,128, 63, 41, 47,120, 61,104, 84,160, 63, 79, 65,242, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0,
+ 63, 0,188,188, 63,160,188,173, 62,181, 84,122, 63,141,179,113, 62,181, 84,122, 63,141,179,113, 63, 0,188,188, 63,160,188,173,
+ 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 62, 82, 95, 26, 63,117, 84,102, 61,104, 84,160, 63, 79, 65,242, 61,104, 84,160,
+ 63, 79, 65,242, 62, 82, 95, 26, 63,117, 84,102, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0,189,188,105,128, 63, 41, 47,120,
+190,118,127, 64, 63, 3, 28,216,190,118,127, 64, 63, 3, 28,216,189,188,105,128, 63, 41, 47,120, 0, 0, 0, 0, 60, 0, 0, 1,
+ 0, 0, 0, 0, 62,181, 84,122, 63,141,179,113, 62, 82, 95, 26, 63,117, 84,102, 62, 82, 95, 26, 63,117, 84,102, 62,181, 84,122,
+ 63,141,179,113, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 61,104, 84,160, 63, 79, 65,242,189,188,105,128, 63, 41, 47,120,
+189,188,105,128, 63, 41, 47,120, 61,104, 84,160, 63, 79, 65,242, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 63, 0,188,188,
+ 63,160,188,173, 62,181, 84,122, 63,141,179,113, 62,181, 84,122, 63,141,179,113, 63, 0,188,188, 63,160,188,173, 0, 0, 0, 0,
+ 60, 0, 0, 1, 0, 0, 0, 0, 62, 82, 95, 26, 63,117, 84,102, 61,104, 84,200, 63, 79, 65,242, 61,104, 84,160, 63, 79, 65,242,
+ 62, 82, 95, 26, 63,117, 84,102, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0,189,188,105, 96, 63, 41, 47,120,190,118,127, 56,
+ 63, 3, 28,220,190,118,127, 64, 63, 3, 28,216,189,188,105,128, 63, 41, 47,120, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0,
+ 62,181, 84,122, 63,141,179,113, 62, 82, 95, 26, 63,117, 84,102, 62, 82, 95, 26, 63,117, 84,102, 62,181, 84,122, 63,141,179,113,
+ 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 61,104, 84,200, 63, 79, 65,244,189,188,105, 96, 63, 41, 47,120,189,188,105, 96,
+ 63, 41, 47,120, 61,104, 84,200, 63, 79, 65,242, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 63,114,244, 44, 63, 79, 65,236,
+ 63, 76,225,172, 63,117, 84,102, 63, 76,225,172, 63,117, 84,102, 63,114,244, 44, 63, 79, 65,236, 0, 0, 0, 0, 60, 0, 0, 1,
+ 0, 0, 0, 0, 63, 0,188,188, 63,160,188,173, 63, 38,207, 56, 63,141,179,111, 63, 38,207, 52, 63,141,179,111, 63, 0,188,188,
+ 63,160,188,173, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 63, 76,225,172, 63,117, 84,102, 63, 38,207, 52, 63,141,179,111,
+ 63, 38,207, 52, 63,141,179,111, 63, 76,225,172, 63,117, 84,102, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 63,114,244, 44,
+ 63, 79, 65,236, 63, 76,225,172, 63,117, 84,102, 63, 76,225,172, 63,117, 84,102, 63,114,244, 44, 63, 79, 65,236, 0, 0, 0, 0,
+ 60, 0, 0, 1, 0, 0, 0, 0, 63, 38,207, 52, 63,141,179,111, 63, 0,188,188, 63,160,188,173, 63, 0,188,188, 63,160,188,173,
+ 63, 38,207, 52, 63,141,179,111, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 63, 76,225,174, 63,117, 84,102, 63, 38,207, 52,
+ 63,141,179,111, 63, 38,207, 52, 63,141,179,111, 63, 76,225,172, 63,117, 84,102, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0,
+ 63,114,244, 44, 63, 79, 65,236, 63, 76,225,174, 63,117, 84,102, 63, 76,225,174, 63,117, 84,102, 63,114,244, 44, 63, 79, 65,236,
+ 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 63, 38,207, 52, 63,141,179,111, 63, 0,188,190, 63,160,188,171, 63, 0,188,188,
+ 63,160,188,173, 63, 38,207, 52, 63,141,179,111, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 63,159,140,162, 63, 3, 28,210,
+ 63,140,131, 99, 63, 41, 47, 72, 63,140,131, 99, 63, 41, 47, 76, 63,159,140,161, 63, 3, 28,210, 0, 0, 0, 0, 60, 0, 0, 1,
+ 0, 0, 0, 0, 63,140,131, 99, 63, 41, 47, 76, 63,114,244, 44, 63, 79, 65,236, 63,114,244, 44, 63, 79, 65,236, 63,140,131, 99,
+ 63, 41, 47, 76, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 63,159,140,161, 63, 3, 28,210, 63,140,131, 99, 63, 41, 47, 76,
+ 63,140,131, 99, 63, 41, 47, 76, 63,159,140,161, 63, 3, 28,210, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 63,140,131, 99,
+ 63, 41, 47, 76, 63,114,244, 44, 63, 79, 65,236, 63,114,244, 44, 63, 79, 65,236, 63,140,131, 99, 63, 41, 47, 76, 0, 0, 0, 0,
+ 60, 0, 0, 1, 0, 0, 0, 0, 63,159,140,161, 63, 3, 28,210, 63,140,131, 99, 63, 41, 47, 76, 63,140,131, 99, 63, 41, 47, 76,
+ 63,159,140,244, 63, 3, 28, 50, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 63,131,172, 22, 59, 93,211, 96, 63,158,151,226,
+ 59, 93,211, 96, 63,158,151,224, 59, 93,211, 96, 63,131,172, 22, 59, 93,211, 96, 0, 0, 0, 0, 61, 0, 0, 1, 0, 0, 0, 0,
+ 63, 81,128,144, 59, 93,211, 96, 63, 27,168,247, 59, 93,211, 96, 63, 27,168,248, 59, 93,211, 96, 63, 81,128,144, 59, 93,211, 96,
+ 0, 0, 0, 0, 61, 0, 0, 1, 0, 0, 0, 0, 63,185,131,176, 59, 93,211, 96, 63,158,151,226, 59, 93,211, 96, 63,158,151,224,
+ 59, 93,211, 96, 63,185,131,174, 59, 93,211, 96, 0, 0, 0, 0, 61, 0, 0, 1, 0, 0, 0, 0, 63,131,172, 21, 59, 93,211, 96,
+ 63, 81,128,144, 59, 93,211, 96, 63, 81,128,144, 59, 93,211, 96, 63,131,172, 22, 59, 93,211, 96, 0, 0, 0, 0, 61, 0, 0, 1,
+ 0, 0, 0, 0, 63, 27,168,247, 59, 93,211, 96, 62,203,162, 85, 59, 93,211, 96, 62,203,162, 85, 59, 93,211, 96, 63, 27,168,247,
+ 59, 93,211, 96, 0, 0, 0, 0, 61, 0, 0, 1, 0, 0, 0, 0, 63,158,151,226, 59, 93,211, 96, 63,131,172, 24, 59, 93,211, 96,
+ 63,131,172, 21, 59, 93,211, 96, 63,158,151,226, 59, 93,211, 96, 0, 0, 0, 0, 61, 0, 0, 1, 0, 0, 0, 0, 63, 81,128,142,
+ 59, 93,211, 96, 63, 27,168,246, 59, 93,211, 96, 63, 27,168,247, 59, 93,211, 96, 63, 81,128,144, 59, 93,211, 96, 0, 0, 0, 0,
+ 61, 0, 0, 1, 0, 0, 0, 0, 63,185,131,174, 59, 93,211, 96, 63,158,151,227, 59, 93,211, 96, 63,158,151,226, 59, 93,211, 96,
+ 63,185,131,174, 59, 93,211, 96, 0, 0, 0, 0, 61, 0, 0, 1, 0, 0, 0, 0, 63,131,172, 22, 59, 93,211, 96, 63, 81,128,149,
+ 59, 93,211, 96, 63, 81,128,142, 59, 93,211, 96, 63,131,172, 24, 59, 93,211, 96, 0, 0, 0, 0, 61, 0, 0, 1, 0, 0, 0, 0,
+ 63, 27,168,251, 59, 93,211, 96, 62,203,162, 84, 59, 93,211, 96, 62,203,162, 86, 59, 93,211, 96, 63, 27,168,246, 59, 93,211, 96,
+ 0, 0, 0, 0, 61, 0, 0, 1, 0, 0, 0, 0, 63,158,151,225, 59, 93,211, 96, 63,131,172, 21, 59, 93,211, 96, 63,131,172, 22,
+ 59, 93,211, 96, 63,158,151,227, 59, 93,211, 96, 0, 0, 0, 0, 61, 0, 0, 1, 0, 0, 0, 0, 63, 81,128,146, 59, 93,211, 96,
+ 63, 27,168,250, 59, 93,211, 96, 63, 27,168,251, 59, 93,211, 96, 63, 81,128,149, 59, 93,211, 96, 0, 0, 0, 0, 61, 0, 0, 1,
+ 0, 0, 0, 0, 63,159,140,161, 63, 3, 28,210, 63,140,131, 99, 63, 41, 47, 76, 63,140,131, 99, 63, 41, 47, 76, 63,159,140,244,
+ 63, 3, 28, 50, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 63,140,131, 99, 63, 41, 47, 76, 63,114,244, 44, 63, 79, 65,236,
+ 63,114,244, 44, 63, 79, 65,236, 63,140,131, 99, 63, 41, 47, 76, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 63,159,140,161,
+ 63, 3, 28,210, 63,140,131, 99, 63, 41, 47, 76, 63,140,131, 99, 63, 41, 47, 76, 63,159,140,161, 63, 3, 28,210, 0, 0, 0, 0,
+ 60, 0, 0, 1, 0, 0, 0, 0, 63,140,131, 99, 63, 41, 47, 76, 63,114,244, 44, 63, 79, 65,236, 63,114,244, 44, 63, 79, 65,236,
+ 63,140,131, 99, 63, 41, 47, 76, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 63,159,140,162, 63, 3, 28,210, 63,140,131, 99,
+ 63, 41, 47, 72, 63,140,131, 99, 63, 41, 47, 76, 63,159,140,161, 63, 3, 28,210, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0,
+ 63, 38,207, 52, 63,141,179,111, 63, 0,188,190, 63,160,188,171, 63, 0,188,188, 63,160,188,173, 63, 38,207, 52, 63,141,179,111,
+ 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 63,114,244, 44, 63, 79, 65,236, 63, 76,225,174, 63,117, 84,102, 63, 76,225,174,
+ 63,117, 84,102, 63,114,244, 44, 63, 79, 65,236, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 63, 76,225,174, 63,117, 84,102,
+ 63, 38,207, 52, 63,141,179,111, 63, 38,207, 52, 63,141,179,111, 63, 76,225,172, 63,117, 84,102, 0, 0, 0, 0, 60, 0, 0, 1,
+ 0, 0, 0, 0, 63, 38,207, 52, 63,141,179,111, 63, 0,188,188, 63,160,188,173, 63, 0,188,188, 63,160,188,173, 63, 38,207, 52,
+ 63,141,179,111, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 63,114,244, 44, 63, 79, 65,236, 63, 76,225,172, 63,117, 84,102,
+ 63, 76,225,172, 63,117, 84,102, 63,114,244, 44, 63, 79, 65,236, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 63, 76,225,172,
+ 63,117, 84,102, 63, 38,207, 52, 63,141,179,111, 63, 38,207, 52, 63,141,179,111, 63, 76,225,172, 63,117, 84,102, 0, 0, 0, 0,
+ 60, 0, 0, 1, 0, 0, 0, 0, 63, 0,188,188, 63,160,188,173, 63, 38,207, 56, 63,141,179,111, 63, 38,207, 52, 63,141,179,111,
+ 63, 0,188,188, 63,160,188,173, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 63,114,244, 44, 63, 79, 65,236, 63, 76,225,172,
+ 63,117, 84,102, 63, 76,225,172, 63,117, 84,102, 63,114,244, 44, 63, 79, 65,236, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0,
+ 61,104, 84,200, 63, 79, 65,244,189,188,105, 96, 63, 41, 47,120,189,188,105, 96, 63, 41, 47,120, 61,104, 84,200, 63, 79, 65,242,
+ 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 62,181, 84,122, 63,141,179,113, 62, 82, 95, 26, 63,117, 84,102, 62, 82, 95, 26,
+ 63,117, 84,102, 62,181, 84,122, 63,141,179,113, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0,189,188,105, 96, 63, 41, 47,120,
+190,118,127, 56, 63, 3, 28,220,190,118,127, 64, 63, 3, 28,216,189,188,105,128, 63, 41, 47,120, 0, 0, 0, 0, 60, 0, 0, 1,
+ 0, 0, 0, 0, 62, 82, 95, 26, 63,117, 84,102, 61,104, 84,200, 63, 79, 65,242, 61,104, 84,160, 63, 79, 65,242, 62, 82, 95, 26,
+ 63,117, 84,102, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 63, 0,188,188, 63,160,188,173, 62,181, 84,122, 63,141,179,113,
+ 62,181, 84,122, 63,141,179,113, 63, 0,188,188, 63,160,188,173, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 61,104, 84,160,
+ 63, 79, 65,242,189,188,105,128, 63, 41, 47,120,189,188,105,128, 63, 41, 47,120, 61,104, 84,160, 63, 79, 65,242, 0, 0, 0, 0,
+ 60, 0, 0, 1, 0, 0, 0, 0, 62,181, 84,122, 63,141,179,113, 62, 82, 95, 26, 63,117, 84,102, 62, 82, 95, 26, 63,117, 84,102,
+ 62,181, 84,122, 63,141,179,113, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0,189,188,105,128, 63, 41, 47,120,190,118,127, 64,
+ 63, 3, 28,216,190,118,127, 64, 63, 3, 28,216,189,188,105,128, 63, 41, 47,120, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0,
+ 62, 82, 95, 26, 63,117, 84,102, 61,104, 84,160, 63, 79, 65,242, 61,104, 84,160, 63, 79, 65,242, 62, 82, 95, 26, 63,117, 84,102,
+ 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 63, 0,188,188, 63,160,188,173, 62,181, 84,122, 63,141,179,113, 62,181, 84,122,
+ 63,141,179,113, 63, 0,188,188, 63,160,188,173, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 61,104, 84,160, 63, 79, 65,242,
+189,188,105,128, 63, 41, 47,120,189,188,105,128, 63, 41, 47,120, 61,104, 84,160, 63, 79, 65,242, 0, 0, 0, 0, 60, 0, 0, 1,
+ 0, 0, 0, 0, 62,181, 84,122, 63,141,179,113, 62, 82, 95, 26, 63,117, 84,102, 62, 82, 95, 26, 63,117, 84,102, 62,181, 84,122,
+ 63,141,179,113, 0, 0, 0, 0, 60, 0, 0, 1, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 4,160, 5, 32,138, 32, 0, 0, 0, 57,
+ 0, 0, 1, 40,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 68, 65, 84, 65, 0, 0, 17, 88, 5, 30, 70, 32, 0, 0, 0, 51, 0, 0, 0, 74, 0, 0, 0, 0, 61,104, 84,160,
+ 63, 79, 65,242,189,188,105,128, 63, 41, 47,120, 61,104, 84,160, 63, 3, 29, 0, 62, 82, 95, 26, 63, 41, 47,120,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,181, 84,122, 63,141,179,113,
+ 62, 82, 95, 26, 63,117, 84,102, 62,181, 84,127, 63, 79, 65,242, 63, 0,188,190, 63,117, 84,102,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,104, 84,160, 63, 3, 29, 0,189,188,106,128,
+ 62,186, 20,176, 61,104, 82,144, 62, 91,223,128, 62, 82, 95, 14, 62,186, 21, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,181, 84,127, 63, 79, 65,242, 62, 82, 95, 26, 63, 41, 47,120,
+ 62,181, 84,122, 63, 3, 28,248, 63, 0,188,188, 63, 41, 47,120,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 38,207, 56, 63,141,179,111, 63, 0,188,190, 63,117, 84,102, 63, 38,207, 52,
+ 63, 79, 65,236, 63, 76,225,172, 63,117, 84,102,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,181, 84,122, 63, 3, 28,248, 62, 82, 95, 14, 62,186, 21, 0, 62,181, 84,122, 62, 91,224, 32,
+ 63, 0,188,185, 62,186, 21, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 38,207, 52, 63, 79, 65,236, 63, 0,188,188, 63, 41, 47,120, 63, 38,207, 52, 63, 3, 28,248, 63, 76,225,174,
+ 63, 41, 47,116,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,181, 84,122, 62, 91,224, 32, 62, 82, 94,138, 61,135, 43, 48, 62,181, 84, 61,189,169,104,176, 63, 0,188,185, 61,135, 44, 96,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 38,207, 52,
+ 63, 3, 28,248, 63, 0,188,185, 62,186, 21, 0, 63, 38,207, 51, 62, 91,224, 24, 63, 76,225,174, 62,186, 21, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,114,244, 44, 63, 79, 65,236,
+ 63, 76,225,174, 63, 41, 47,116, 63,114,244, 42, 63, 3, 28,244, 63,140,131, 99, 63, 41, 47, 76,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 38,207, 51, 62, 91,224, 24, 63, 0,188,185,
+ 61,135, 44, 96, 63, 38,207,248,189,169,109,144, 63, 76,226,112, 61,135, 38, 64,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,114,244,240, 62, 91,221, 4, 63,140,131,180, 62,186, 19,116,
+ 63,114,244, 42, 63, 3, 28,244, 63, 76,225,174, 62,186, 21, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,181, 84,122, 63,141,179,113, 62, 82, 95, 26, 63,117, 84,102, 62, 82, 95, 26,
+ 63,117, 84,102, 62,181, 84,122, 63,141,179,113,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 61,104, 84,160, 63, 79, 65,242,189,188,105,128, 63, 41, 47,120,189,188,105,128, 63, 41, 47,120,
+ 61,104, 84,160, 63, 79, 65,242,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 0,188,188, 63,160,188,173, 62,181, 84,122, 63,141,179,113, 62,181, 84,122, 63,141,179,113, 63, 0,188,188,
+ 63,160,188,173,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62, 82, 95, 26, 63,117, 84,102, 61,104, 84,160, 63, 79, 65,242, 61,104, 84,160, 63, 79, 65,242, 62, 82, 95, 26, 63,117, 84,102,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,189,188,105,128,
+ 63, 41, 47,120,190,118,127, 64, 63, 3, 28,216,190,118,127, 64, 63, 3, 28,216,189,188,105,128, 63, 41, 47,120,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,181, 84,122, 63,141,179,113,
+ 62, 82, 95, 26, 63,117, 84,102, 62, 82, 95, 26, 63,117, 84,102, 62,181, 84,122, 63,141,179,113,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,104, 84,160, 63, 79, 65,242,189,188,105,128,
+ 63, 41, 47,120,189,188,105,128, 63, 41, 47,120, 61,104, 84,160, 63, 79, 65,242,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0,188,188, 63,160,188,173, 62,181, 84,122, 63,141,179,113,
+ 62,181, 84,122, 63,141,179,113, 63, 0,188,188, 63,160,188,173,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 82, 95, 26, 63,117, 84,102, 61,104, 84,200, 63, 79, 65,242, 61,104, 84,160,
+ 63, 79, 65,242, 62, 82, 95, 26, 63,117, 84,102,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0,189,188,105, 96, 63, 41, 47,120,190,118,127, 56, 63, 3, 28,220,190,118,127, 64, 63, 3, 28,216,
+189,188,105,128, 63, 41, 47,120,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,181, 84,122, 63,141,179,113, 62, 82, 95, 26, 63,117, 84,102, 62, 82, 95, 26, 63,117, 84,102, 62,181, 84,122,
+ 63,141,179,113,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 61,104, 84,200, 63, 79, 65,244,189,188,105, 96, 63, 41, 47,120,189,188,105, 96, 63, 41, 47,120, 61,104, 84,200, 63, 79, 65,242,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,114,244, 44,
+ 63, 79, 65,236, 63, 76,225,172, 63,117, 84,102, 63, 76,225,172, 63,117, 84,102, 63,114,244, 44, 63, 79, 65,236,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0,188,188, 63,160,188,173,
+ 63, 38,207, 56, 63,141,179,111, 63, 38,207, 52, 63,141,179,111, 63, 0,188,188, 63,160,188,173,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 76,225,172, 63,117, 84,102, 63, 38,207, 52,
+ 63,141,179,111, 63, 38,207, 52, 63,141,179,111, 63, 76,225,172, 63,117, 84,102,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,114,244, 44, 63, 79, 65,236, 63, 76,225,172, 63,117, 84,102,
+ 63, 76,225,172, 63,117, 84,102, 63,114,244, 44, 63, 79, 65,236,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 38,207, 52, 63,141,179,111, 63, 0,188,188, 63,160,188,173, 63, 0,188,188,
+ 63,160,188,173, 63, 38,207, 52, 63,141,179,111,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 76,225,174, 63,117, 84,102, 63, 38,207, 52, 63,141,179,111, 63, 38,207, 52, 63,141,179,111,
+ 63, 76,225,172, 63,117, 84,102,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,114,244, 44, 63, 79, 65,236, 63, 76,225,174, 63,117, 84,102, 63, 76,225,174, 63,117, 84,102, 63,114,244, 44,
+ 63, 79, 65,236,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 38,207, 52, 63,141,179,111, 63, 0,188,190, 63,160,188,171, 63, 0,188,188, 63,160,188,173, 63, 38,207, 52, 63,141,179,111,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,159,140,162,
+ 63, 3, 28,210, 63,140,131, 99, 63, 41, 47, 72, 63,140,131, 99, 63, 41, 47, 76, 63,159,140,161, 63, 3, 28,210,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,140,131, 99, 63, 41, 47, 76,
+ 63,114,244, 44, 63, 79, 65,236, 63,114,244, 44, 63, 79, 65,236, 63,140,131, 99, 63, 41, 47, 76,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,159,140,161, 63, 3, 28,210, 63,140,131, 99,
+ 63, 41, 47, 76, 63,140,131, 99, 63, 41, 47, 76, 63,159,140,161, 63, 3, 28,210,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,140,131, 99, 63, 41, 47, 76, 63,114,244, 44, 63, 79, 65,236,
+ 63,114,244, 44, 63, 79, 65,236, 63,140,131, 99, 63, 41, 47, 76,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,159,140,161, 63, 3, 28,210, 63,140,131, 99, 63, 41, 47, 76, 63,140,131, 99,
+ 63, 41, 47, 76, 63,159,140,244, 63, 3, 28, 50,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,131,172, 22, 59, 93,211, 96, 63,158,151,226, 59, 93,211, 96, 63,158,151,224, 59, 93,211, 96,
+ 63,131,172, 22, 59, 93,211, 96,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 61, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 81,128,144, 59, 93,211, 96, 63, 27,168,247, 59, 93,211, 96, 63, 27,168,248, 59, 93,211, 96, 63, 81,128,144,
+ 59, 93,211, 96,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 61, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,185,131,176, 59, 93,211, 96, 63,158,151,226, 59, 93,211, 96, 63,158,151,224, 59, 93,211, 96, 63,185,131,174, 59, 93,211, 96,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 61, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,131,172, 21,
+ 59, 93,211, 96, 63, 81,128,144, 59, 93,211, 96, 63, 81,128,144, 59, 93,211, 96, 63,131,172, 22, 59, 93,211, 96,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 61, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 27,168,247, 59, 93,211, 96,
+ 62,203,162, 85, 59, 93,211, 96, 62,203,162, 85, 59, 93,211, 96, 63, 27,168,247, 59, 93,211, 96,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 61, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,158,151,226, 59, 93,211, 96, 63,131,172, 24,
+ 59, 93,211, 96, 63,131,172, 21, 59, 93,211, 96, 63,158,151,226, 59, 93,211, 96,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 61, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 81,128,142, 59, 93,211, 96, 63, 27,168,246, 59, 93,211, 96,
+ 63, 27,168,247, 59, 93,211, 96, 63, 81,128,144, 59, 93,211, 96,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 61, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,185,131,174, 59, 93,211, 96, 63,158,151,227, 59, 93,211, 96, 63,158,151,226,
+ 59, 93,211, 96, 63,185,131,174, 59, 93,211, 96,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 61, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,131,172, 22, 59, 93,211, 96, 63, 81,128,149, 59, 93,211, 96, 63, 81,128,142, 59, 93,211, 96,
+ 63,131,172, 24, 59, 93,211, 96,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 61, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 27,168,251, 59, 93,211, 96, 62,203,162, 84, 59, 93,211, 96, 62,203,162, 86, 59, 93,211, 96, 63, 27,168,246,
+ 59, 93,211, 96,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 61, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,158,151,225, 59, 93,211, 96, 63,131,172, 21, 59, 93,211, 96, 63,131,172, 22, 59, 93,211, 96, 63,158,151,227, 59, 93,211, 96,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 61, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 81,128,146,
+ 59, 93,211, 96, 63, 27,168,250, 59, 93,211, 96, 63, 27,168,251, 59, 93,211, 96, 63, 81,128,149, 59, 93,211, 96,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 61, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,159,140,161, 63, 3, 28,210,
+ 63,140,131, 99, 63, 41, 47, 76, 63,140,131, 99, 63, 41, 47, 76, 63,159,140,244, 63, 3, 28, 50,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,140,131, 99, 63, 41, 47, 76, 63,114,244, 44,
+ 63, 79, 65,236, 63,114,244, 44, 63, 79, 65,236, 63,140,131, 99, 63, 41, 47, 76,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,159,140,161, 63, 3, 28,210, 63,140,131, 99, 63, 41, 47, 76,
+ 63,140,131, 99, 63, 41, 47, 76, 63,159,140,161, 63, 3, 28,210,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,140,131, 99, 63, 41, 47, 76, 63,114,244, 44, 63, 79, 65,236, 63,114,244, 44,
+ 63, 79, 65,236, 63,140,131, 99, 63, 41, 47, 76,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,159,140,162, 63, 3, 28,210, 63,140,131, 99, 63, 41, 47, 72, 63,140,131, 99, 63, 41, 47, 76,
+ 63,159,140,161, 63, 3, 28,210,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 38,207, 52, 63,141,179,111, 63, 0,188,190, 63,160,188,171, 63, 0,188,188, 63,160,188,173, 63, 38,207, 52,
+ 63,141,179,111,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,114,244, 44, 63, 79, 65,236, 63, 76,225,174, 63,117, 84,102, 63, 76,225,174, 63,117, 84,102, 63,114,244, 44, 63, 79, 65,236,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 76,225,174,
+ 63,117, 84,102, 63, 38,207, 52, 63,141,179,111, 63, 38,207, 52, 63,141,179,111, 63, 76,225,172, 63,117, 84,102,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 38,207, 52, 63,141,179,111,
+ 63, 0,188,188, 63,160,188,173, 63, 0,188,188, 63,160,188,173, 63, 38,207, 52, 63,141,179,111,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,114,244, 44, 63, 79, 65,236, 63, 76,225,172,
+ 63,117, 84,102, 63, 76,225,172, 63,117, 84,102, 63,114,244, 44, 63, 79, 65,236,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 76,225,172, 63,117, 84,102, 63, 38,207, 52, 63,141,179,111,
+ 63, 38,207, 52, 63,141,179,111, 63, 76,225,172, 63,117, 84,102,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0,188,188, 63,160,188,173, 63, 38,207, 56, 63,141,179,111, 63, 38,207, 52,
+ 63,141,179,111, 63, 0,188,188, 63,160,188,173,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,114,244, 44, 63, 79, 65,236, 63, 76,225,172, 63,117, 84,102, 63, 76,225,172, 63,117, 84,102,
+ 63,114,244, 44, 63, 79, 65,236,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 61,104, 84,200, 63, 79, 65,244,189,188,105, 96, 63, 41, 47,120,189,188,105, 96, 63, 41, 47,120, 61,104, 84,200,
+ 63, 79, 65,242,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,181, 84,122, 63,141,179,113, 62, 82, 95, 26, 63,117, 84,102, 62, 82, 95, 26, 63,117, 84,102, 62,181, 84,122, 63,141,179,113,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,189,188,105, 96,
+ 63, 41, 47,120,190,118,127, 56, 63, 3, 28,220,190,118,127, 64, 63, 3, 28,216,189,188,105,128, 63, 41, 47,120,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 82, 95, 26, 63,117, 84,102,
+ 61,104, 84,200, 63, 79, 65,242, 61,104, 84,160, 63, 79, 65,242, 62, 82, 95, 26, 63,117, 84,102,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0,188,188, 63,160,188,173, 62,181, 84,122,
+ 63,141,179,113, 62,181, 84,122, 63,141,179,113, 63, 0,188,188, 63,160,188,173,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,104, 84,160, 63, 79, 65,242,189,188,105,128, 63, 41, 47,120,
+189,188,105,128, 63, 41, 47,120, 61,104, 84,160, 63, 79, 65,242,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,181, 84,122, 63,141,179,113, 62, 82, 95, 26, 63,117, 84,102, 62, 82, 95, 26,
+ 63,117, 84,102, 62,181, 84,122, 63,141,179,113,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0,189,188,105,128, 63, 41, 47,120,190,118,127, 64, 63, 3, 28,216,190,118,127, 64, 63, 3, 28,216,
+189,188,105,128, 63, 41, 47,120,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62, 82, 95, 26, 63,117, 84,102, 61,104, 84,160, 63, 79, 65,242, 61,104, 84,160, 63, 79, 65,242, 62, 82, 95, 26,
+ 63,117, 84,102,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 0,188,188, 63,160,188,173, 62,181, 84,122, 63,141,179,113, 62,181, 84,122, 63,141,179,113, 63, 0,188,188, 63,160,188,173,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,104, 84,160,
+ 63, 79, 65,242,189,188,105,128, 63, 41, 47,120,189,188,105,128, 63, 41, 47,120, 61,104, 84,160, 63, 79, 65,242,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,181, 84,122, 63,141,179,113,
+ 62, 82, 95, 26, 63,117, 84,102, 62, 82, 95, 26, 63,117, 84,102, 62,181, 84,122, 63,141,179,113,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 60, 0, 0, 1, 0, 0, 0, 0, 0, 0, 77, 69, 0, 0, 1, 20, 2,236,218, 64, 0, 0, 0, 50,
+ 0, 0, 0, 1, 2,236,228, 0, 2,236,213, 64, 0, 0, 0, 0, 0, 0, 0, 0, 77, 69, 80,108, 97,110,101, 46, 48, 48, 50, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,232,181, 64, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,236,219,128, 2,236,224,240, 2,236,225,192, 5, 30, 54, 32, 5, 15,188, 32,
+ 2,236,222, 16, 0, 0, 0, 0, 2,236,227, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 2,236,219,176, 0, 0, 0, 1, 0, 0, 0, 5, 0, 0, 0, 20, 0, 0, 0, 0, 2,236,220,224, 0, 0, 0, 1, 0, 0, 0, 5,
+ 0, 0, 0, 12, 0, 0, 0, 0, 2,236,223,192, 0, 0, 0, 3, 0, 0, 0, 5, 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 23,
+ 0, 0, 0, 32, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 76,205, 4, 55, 39,197,172, 63, 76,204,214, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 30, 0, 5, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 4,
+ 2,236,219,128, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 1, 4, 2,236,219,176, 0, 0, 0,242,
+ 0, 0, 0, 5, 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, 5, 15,188, 32, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 1,204, 5, 15,188, 32, 0, 0, 0, 56, 0, 0, 0, 23,191, 76,205, 4,
+ 0, 0, 0, 0,190,204,204,208, 0, 0,128, 1, 0, 0, 3, 1,190,204,205, 55, 0, 0, 0, 0,190,204,204,216, 0, 0,128, 1,
+ 0, 0, 3, 1,182, 70, 0, 0, 52,128, 0, 0,190,204,204,224, 0, 0,128, 1, 0, 0, 3, 1,191, 76,205, 4, 0, 0, 0, 0,
+ 52, 96, 0, 0, 0, 0,128, 1, 0, 0, 3, 1,190,204,205, 55, 0, 0, 0, 0,179, 0, 0, 0, 0, 0,128, 1, 0, 0, 3, 1,
+182, 70, 0, 0, 52,128, 0, 0,180,144, 0, 0, 0, 0,128, 1, 0, 0, 3, 1,191, 76,205, 4, 0, 0, 0, 0, 62,204,204,213,
+ 0, 0,128, 1, 0, 0, 3, 1,190,204,205, 55, 0, 0, 0, 0, 62,204,204,205, 0, 0,128, 1, 0, 0, 3, 1,182, 70, 0, 0,
+ 52,128, 0, 0, 62,204,204,197, 0, 0,128, 1, 0, 0, 3, 1,190,204,205, 47, 0, 0, 0, 0, 63, 76,204,206, 0, 0,128, 1,
+ 0, 0, 3, 1,182, 62, 0, 0, 52,128, 0, 0, 63, 76,204,206, 0, 0,128, 1, 0, 0, 3, 1,191, 76,205, 4, 0, 0, 0, 0,
+191, 76,204,208, 0, 0,128, 1, 0, 0, 3, 1,190,204,205, 55, 0, 0, 0, 0,191, 76,204,212, 0, 0,128, 1, 0, 0, 3, 1,
+182, 70, 0, 0, 52,128, 0, 0,191, 76,204,214, 0, 0,128, 1, 0, 0, 3, 1, 62,204,205, 47,180,128, 0, 0,191, 76,204,206,
+ 0, 0,128, 1, 0, 0, 3, 1, 63, 76,205, 4, 0, 0, 0, 0, 63, 76,204,210, 0, 0,128, 1, 0, 0, 3, 1, 62,204,205, 53,
+180,128, 0, 0, 63, 76,204,214, 0, 0,128, 1, 0, 0, 3, 1, 63, 76,205, 0, 0, 0, 0, 0, 62,204,204,213, 0, 0,128, 1,
+ 0, 0, 3, 1, 62,204,205, 47,180,128, 0, 0, 62,204,204,221, 0, 0,128, 1, 0, 0, 3, 1, 63, 76,205, 0, 0, 0, 0, 0,
+ 52, 96, 0, 0, 0, 0,128, 1, 0, 0, 3, 1, 62,204,205, 47,180,128, 0, 0, 52,240, 0, 0, 0, 0,128, 1, 0, 0, 3, 1,
+ 63, 76,205, 0, 0, 0, 0, 0,190,204,204,208, 0, 0,128, 1, 0, 0, 3, 1, 62,204,205, 47,180,128, 0, 0,190,204,204,200,
+ 0, 0,128, 1, 0, 0, 3, 1, 68, 65, 84, 65, 0, 0, 1, 4, 2,236,220,224, 0, 0, 0,242, 0, 0, 0, 5, 0, 0, 0, 3,
+ 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, 2,236,222, 16, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65, 0, 0, 1,128, 2,236,222, 16, 0, 0, 0, 53, 0, 0, 0, 32, 0, 0, 0, 2, 0, 0, 0, 22, 0, 0, 0, 35,
+ 0, 0, 0, 5, 0, 0, 0, 20, 0, 0, 0, 35, 0, 0, 0, 8, 0, 0, 0, 18, 0, 0, 0, 35, 0, 0, 0, 14, 0, 0, 0, 13,
+ 0, 0, 0, 35, 0, 0, 0, 2, 0, 0, 0, 13, 0, 0, 0, 35, 0, 0, 0, 1, 0, 0, 0, 12, 0, 0, 0, 35, 0, 0, 0, 0,
+ 0, 0, 0, 11, 0, 0, 0, 35, 0, 0, 0, 5, 0, 0, 0, 2, 0, 0, 0, 35, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 35,
+ 0, 0, 0, 4, 0, 0, 0, 1, 0, 0, 0, 35, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, 5, 0, 0, 0, 8,
+ 0, 0, 0, 35, 0, 0, 0, 5, 0, 0, 0, 4, 0, 0, 0, 35, 0, 0, 0, 4, 0, 0, 0, 7, 0, 0, 0, 35, 0, 0, 0, 4,
+ 0, 0, 0, 3, 0, 0, 0, 35, 0, 0, 0, 6, 0, 0, 0, 3, 0, 0, 0, 35, 0, 0, 0, 8, 0, 0, 0, 10, 0, 0, 0, 35,
+ 0, 0, 0, 8, 0, 0, 0, 7, 0, 0, 0, 35, 0, 0, 0, 7, 0, 0, 0, 9, 0, 0, 0, 35, 0, 0, 0, 6, 0, 0, 0, 7,
+ 0, 0, 0, 35, 0, 0, 0, 9, 0, 0, 0, 10, 0, 0, 0, 35, 0, 0, 0, 11, 0, 0, 0, 12, 0, 0, 0, 35, 0, 0, 0, 15,
+ 0, 0, 0, 16, 0, 0, 0, 35, 0, 0, 0, 16, 0, 0, 0, 18, 0, 0, 0, 35, 0, 0, 0, 17, 0, 0, 0, 18, 0, 0, 0, 35,
+ 0, 0, 0, 15, 0, 0, 0, 17, 0, 0, 0, 35, 0, 0, 0, 18, 0, 0, 0, 20, 0, 0, 0, 35, 0, 0, 0, 19, 0, 0, 0, 20,
+ 0, 0, 0, 35, 0, 0, 0, 20, 0, 0, 0, 22, 0, 0, 0, 35, 0, 0, 0, 21, 0, 0, 0, 22, 0, 0, 0, 35, 0, 0, 0, 19,
+ 0, 0, 0, 21, 0, 0, 0, 35, 0, 0, 0, 14, 0, 0, 0, 22, 0, 0, 0, 35, 68, 65, 84, 65, 0, 0, 1, 4, 2,236,223,192,
+ 0, 0, 0,242, 0, 0, 0, 5, 0, 0, 0, 4, 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, 2,236,224,240, 0, 0, 0, 5,
+ 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 85, 86, 84,101,120, 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, 2,236,225,192, 0, 0, 0, 6, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0,
+ 67,111,108, 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,
+ 2,236,227, 80, 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, 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, 68, 65, 84, 65, 0, 0, 0,160, 2,236,224,240, 0, 0, 0, 52, 0, 0, 0, 8,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 12, 0, 0, 0, 2, 0, 0, 0, 5, 0, 0, 0, 4, 0, 0, 0, 1,
+ 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 7, 0, 0, 0, 6, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0, 10,
+ 0, 0, 0, 9, 0, 0, 0, 7, 0, 0, 0, 8, 0, 0, 0, 2, 0, 0, 0, 15, 0, 0, 0, 16, 0, 0, 0, 18, 0, 0, 0, 17,
+ 0, 0, 0, 2, 0, 0, 0, 18, 0, 0, 0, 8, 0, 0, 0, 5, 0, 0, 0, 20, 0, 0, 0, 2, 0, 0, 0, 22, 0, 0, 0, 21,
+ 0, 0, 0, 19, 0, 0, 0, 20, 0, 0, 0, 2, 0, 0, 0, 22, 0, 0, 0, 2, 0, 0, 0, 13, 0, 0, 0, 14, 0, 0, 0, 2,
+ 68, 65, 84, 65, 0, 0, 1, 96, 2,236,225,192, 0, 0, 0, 60, 0, 0, 0, 8, 62,137,192, 12, 63,125,226,162, 61,246,108,144,
+ 63,125,226,162, 61,246,108,144, 63,125,226,162, 62,137,192, 12, 63,125,226,162, 0, 0, 0, 0, 61, 0, 0, 1, 0, 0, 0, 0,
+ 62,213,228,252, 63,125,226,162, 62,137,192, 12, 63,125,226,162, 62,137,192, 12, 63,125,226,162, 62,213,228,252, 63,125,226,162,
+ 0, 0, 0, 0, 61, 0, 0, 1, 0, 0, 0, 0, 62,137,192, 12, 63,125,226,162, 61,246,108,144, 63,125,226,162, 61,246,108,144,
+ 63,125,226,162, 62,137,192, 12, 63,125,226,162, 0, 0, 0, 0, 61, 0, 0, 1, 0, 0, 0, 0, 62,213,229, 0, 63,125,226,162,
+ 62,137,192, 18, 63,125,226,162, 62,137,192, 12, 63,125,226,162, 62,213,228,252, 63,125,226,162, 0, 0, 0, 0, 61, 0, 0, 1,
+ 0, 0, 0, 0, 63, 55, 23,154, 63,125,226,162, 63, 17, 5, 34, 63,125,226,162, 63, 17, 5, 30, 63,125,226,162, 63, 55, 23,152,
+ 63,125,226,162, 0, 0, 0, 0, 61, 0, 0, 1, 0, 0, 0, 0, 63, 17, 5, 30, 63,125,226,162, 62,213,228,252, 63,125,226,162,
+ 62,213,228,252, 63,125,226,162, 63, 17, 5, 30, 63,125,226,162, 0, 0, 0, 0, 61, 0, 0, 1, 0, 0, 0, 0, 63, 17, 5, 30,
+ 63,125,226,162, 63, 55, 23,152, 63,125,226,162, 63, 55, 23,152, 63,125,226,162, 63, 17, 5, 30, 63,125,226,162, 0, 0, 0, 0,
+ 61, 0, 0, 1, 0, 0, 0, 0, 63, 17, 5, 30, 63,125,226,162, 62,213,228,252, 63,125,226,162, 62,213,228,252, 63,125,226,162,
+ 63, 17, 5, 30, 63,125,226,162, 0, 0, 0, 0, 61, 0, 0, 1, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,128, 2,236,227, 80,
+ 0, 0, 0, 57, 0, 0, 0, 32,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 68, 65, 84, 65, 0, 0, 1,224, 5, 30, 54, 32, 0, 0, 0, 51, 0, 0, 0, 8, 0, 0, 0, 0,
+ 62,137,192, 12, 63,125,226,162, 61,246,108,144, 63,125,226,162, 61,246,108,144, 63,125,226,162, 62,137,192, 12, 63,125,226,162,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 61, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,213,228,252,
+ 63,125,226,162, 62,137,192, 12, 63,125,226,162, 62,137,192, 12, 63,125,226,162, 62,213,228,252, 63,125,226,162,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 61, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,137,192, 12, 63,125,226,162,
+ 61,246,108,144, 63,125,226,162, 61,246,108,144, 63,125,226,162, 62,137,192, 12, 63,125,226,162,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 61, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,213,229, 0, 63,125,226,162, 62,137,192, 18,
+ 63,125,226,162, 62,137,192, 12, 63,125,226,162, 62,213,228,252, 63,125,226,162,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 61, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 55, 23,154, 63,125,226,162, 63, 17, 5, 34, 63,125,226,162,
+ 63, 17, 5, 30, 63,125,226,162, 63, 55, 23,152, 63,125,226,162,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 61, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 17, 5, 30, 63,125,226,162, 62,213,228,252, 63,125,226,162, 62,213,228,252,
+ 63,125,226,162, 63, 17, 5, 30, 63,125,226,162,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 61, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 17, 5, 30, 63,125,226,162, 63, 55, 23,152, 63,125,226,162, 63, 55, 23,152, 63,125,226,162,
+ 63, 17, 5, 30, 63,125,226,162,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 61, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 17, 5, 30, 63,125,226,162, 62,213,228,252, 63,125,226,162, 62,213,228,252, 63,125,226,162, 63, 17, 5, 30,
+ 63,125,226,162,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 61, 0, 0, 1, 0, 0, 0, 0, 0, 0, 77, 69,
+ 0, 0, 1, 20, 2,236,228, 0, 0, 0, 0, 50, 0, 0, 0, 1, 2,236,237,192, 2,236,218, 64, 1, 94, 44, 64, 0, 0, 0, 0,
+ 77, 69, 80,108, 97,110,101, 46, 48, 48, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 2,231, 0,192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,236,229, 64, 2,236,234,176,
+ 2,236,235,128, 5, 30, 54, 32, 5, 15,190, 32, 2,236,231,208, 0, 0, 0, 0, 2,236,237, 16, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,236,229,112, 0, 0, 0, 1, 0, 0, 0, 5, 0, 0, 0, 20, 0, 0, 0, 0,
+ 2,236,230,160, 0, 0, 0, 1, 0, 0, 0, 5, 0, 0, 0, 12, 0, 0, 0, 0, 2,236,233,128, 0, 0, 0, 3, 0, 0, 0, 5,
+ 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 23, 0, 0, 0, 32, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+180, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 76,205, 2, 55, 39,197,172, 63, 76,204,214, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 5, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 4, 2,236,229, 64, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 68, 65, 84, 65,
+ 0, 0, 1, 4, 2,236,229,112, 0, 0, 0,242, 0, 0, 0, 5, 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,
+ 5, 15,190, 32, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 1,204, 5, 15,190, 32,
+ 0, 0, 0, 56, 0, 0, 0, 23, 62,204,205, 47,180,128, 0, 0,190,204,204,200, 0, 0,128, 1, 0, 0, 2, 0, 63, 76,205, 0,
+ 0, 0, 0, 0,190,204,204,208, 0, 0,128, 1, 0, 0, 2, 0, 62,204,205, 47,180,128, 0, 0, 52,240, 0, 0, 0, 0,128, 1,
+ 0, 0, 2, 0, 63, 76,205, 0, 0, 0, 0, 0, 52, 96, 0, 0, 0, 0,128, 1, 0, 0, 2, 0, 62,204,205, 47,180,128, 0, 0,
+ 62,204,204,221, 0, 0,128, 1, 0, 0, 2, 0, 63, 76,205, 0, 0, 0, 0, 0, 62,204,204,213, 0, 0,128, 1, 0, 0, 2, 0,
+ 62,204,205, 53,180,128, 0, 0, 63, 76,204,214, 0, 0,128, 1, 0, 0, 2, 0, 62,204,205, 47,180,128, 0, 0,191, 76,204,206,
+ 0, 0,128, 1, 0, 0, 2, 0, 63, 76,205, 0, 0, 0, 0, 0,191, 76,204,208, 0, 0,128, 1, 0, 0, 2, 0,182, 70, 0, 0,
+ 52,128, 0, 0,191, 76,204,214, 0, 0,128, 1, 0, 0, 2, 0,190,204,205, 55, 0, 0, 0, 0,191, 76,204,212, 0, 0,128, 1,
+ 0, 0, 2, 0,182, 62, 0, 0, 52,128, 0, 0, 63, 76,204,206, 0, 0,128, 1, 0, 0, 2, 0,190,204,205, 47, 0, 0, 0, 0,
+ 63, 76,204,206, 0, 0,128, 1, 0, 0, 2, 0,191, 76,205, 4, 0, 0, 0, 0, 63, 76,204,210, 0, 0,128, 1, 0, 0, 2, 0,
+182, 70, 0, 0, 52,128, 0, 0, 62,204,204,197, 0, 0,128, 1, 0, 0, 2, 0,190,204,205, 55, 0, 0, 0, 0, 62,204,204,205,
+ 0, 0,128, 1, 0, 0, 2, 0,191, 76,205, 4, 0, 0, 0, 0, 62,204,204,213, 0, 0,128, 1, 0, 0, 2, 0,182, 70, 0, 0,
+ 52,128, 0, 0,180,144, 0, 0, 0, 0,128, 1, 0, 0, 2, 0,190,204,205, 55, 0, 0, 0, 0,179, 0, 0, 0, 0, 0,128, 1,
+ 0, 0, 2, 0,191, 76,205, 4, 0, 0, 0, 0, 52, 96, 0, 0, 0, 0,128, 1, 0, 0, 2, 0,182, 70, 0, 0, 52,128, 0, 0,
+190,204,204,224, 0, 0,128, 1, 0, 0, 2, 0,190,204,205, 55, 0, 0, 0, 0,190,204,204,216, 0, 0,128, 1, 0, 0, 2, 0,
+191, 76,205, 4, 0, 0, 0, 0,190,204,204,208, 0, 0,128, 1, 0, 0, 2, 0, 68, 65, 84, 65, 0, 0, 1, 4, 2,236,230,160,
+ 0, 0, 0,242, 0, 0, 0, 5, 0, 0, 0, 3, 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, 2,236,231,208, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 1,128, 2,236,231,208, 0, 0, 0, 53, 0, 0, 0, 32,
+ 0, 0, 0, 1, 0, 0, 0, 8, 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 1,
+ 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 34, 0, 0, 0, 3, 0, 0, 0, 5, 0, 0, 0, 34, 0, 0, 0, 2,
+ 0, 0, 0, 3, 0, 0, 0, 34, 0, 0, 0, 2, 0, 0, 0, 4, 0, 0, 0, 34, 0, 0, 0, 4, 0, 0, 0, 5, 0, 0, 0, 34,
+ 0, 0, 0, 4, 0, 0, 0, 6, 0, 0, 0, 34, 0, 0, 0, 7, 0, 0, 0, 8, 0, 0, 0, 34, 0, 0, 0, 9, 0, 0, 0, 10,
+ 0, 0, 0, 34, 0, 0, 0, 12, 0, 0, 0, 13, 0, 0, 0, 34, 0, 0, 0, 13, 0, 0, 0, 16, 0, 0, 0, 34, 0, 0, 0, 15,
+ 0, 0, 0, 16, 0, 0, 0, 34, 0, 0, 0, 12, 0, 0, 0, 15, 0, 0, 0, 34, 0, 0, 0, 14, 0, 0, 0, 15, 0, 0, 0, 34,
+ 0, 0, 0, 11, 0, 0, 0, 14, 0, 0, 0, 34, 0, 0, 0, 18, 0, 0, 0, 19, 0, 0, 0, 34, 0, 0, 0, 15, 0, 0, 0, 18,
+ 0, 0, 0, 34, 0, 0, 0, 17, 0, 0, 0, 18, 0, 0, 0, 34, 0, 0, 0, 14, 0, 0, 0, 17, 0, 0, 0, 34, 0, 0, 0, 19,
+ 0, 0, 0, 22, 0, 0, 0, 34, 0, 0, 0, 21, 0, 0, 0, 22, 0, 0, 0, 34, 0, 0, 0, 18, 0, 0, 0, 21, 0, 0, 0, 34,
+ 0, 0, 0, 20, 0, 0, 0, 21, 0, 0, 0, 34, 0, 0, 0, 17, 0, 0, 0, 20, 0, 0, 0, 34, 0, 0, 0, 10, 0, 0, 0, 21,
+ 0, 0, 0, 34, 0, 0, 0, 9, 0, 0, 0, 20, 0, 0, 0, 34, 0, 0, 0, 6, 0, 0, 0, 11, 0, 0, 0, 34, 0, 0, 0, 4,
+ 0, 0, 0, 14, 0, 0, 0, 34, 0, 0, 0, 2, 0, 0, 0, 17, 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 34,
+ 68, 65, 84, 65, 0, 0, 1, 4, 2,236,233,128, 0, 0, 0,242, 0, 0, 0, 5, 0, 0, 0, 4, 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, 2,236,234,176, 0, 0, 0, 5, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 85, 86, 84,101,120, 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, 2,236,235,128, 0, 0, 0, 6,
+ 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 67,111,108, 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, 2,236,237, 16, 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, 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, 68, 65, 84, 65, 0, 0, 0,160,
+ 2,236,234,176, 0, 0, 0, 52, 0, 0, 0, 8, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 8, 0, 0, 0, 0,
+ 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 4, 0, 0, 0, 2,
+ 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 11, 0, 0, 0, 14, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 12,
+ 0, 0, 0, 13, 0, 0, 0, 16, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 15, 0, 0, 0, 18, 0, 0, 0, 17,
+ 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 19, 0, 0, 0, 22, 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 21,
+ 0, 0, 0, 10, 0, 0, 0, 9, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 1, 96, 2,236,235,128, 0, 0, 0, 60, 0, 0, 0, 8,
+ 63, 55, 23,152, 63,125,226,162, 63, 17, 5, 30, 63,125,226,162, 63, 17, 5, 30, 63,125,226,162, 63, 55, 23,152, 63,125,226,162,
+ 0, 0, 0, 0, 61, 0, 0, 1, 0, 0, 0, 0, 62,213,228,252, 63,125,226,162, 63, 17, 5, 30, 63,125,226,162, 63, 17, 5, 30,
+ 63,125,226,162, 62,213,228,252, 63,125,226,162, 0, 0, 0, 0, 61, 0, 0, 1, 0, 0, 0, 0, 63, 55, 23,152, 63,125,226,162,
+ 63, 17, 5, 30, 63,125,226,162, 63, 17, 5, 30, 63,125,226,162, 63, 55, 23,152, 63,125,226,162, 0, 0, 0, 0, 61, 0, 0, 1,
+ 0, 0, 0, 0, 63, 17, 5, 34, 63,125,226,162, 62,213,229, 0, 63,125,226,162, 62,213,228,252, 63,125,226,162, 63, 17, 5, 30,
+ 63,125,226,162, 0, 0, 0, 0, 61, 0, 0, 1, 0, 0, 0, 0, 62,137,192, 18, 63,125,226,162, 61,246,108,144, 63,125,226,162,
+ 61,246,108,144, 63,125,226,162, 62,137,192, 12, 63,125,226,162, 0, 0, 0, 0, 61, 0, 0, 1, 0, 0, 0, 0, 62,213,228,252,
+ 63,125,226,162, 62,137,192, 12, 63,125,226,162, 62,137,192, 12, 63,125,226,162, 62,213,228,252, 63,125,226,162, 0, 0, 0, 0,
+ 61, 0, 0, 1, 0, 0, 0, 0, 62,137,192, 12, 63,125,226,162, 61,246,108,144, 63,125,226,162, 61,246,108,144, 63,125,226,162,
+ 62,137,192, 12, 63,125,226,162, 0, 0, 0, 0, 61, 0, 0, 1, 0, 0, 0, 0, 62,213,228,252, 63,125,226,162, 62,137,192, 12,
+ 63,125,226,162, 62,137,192, 12, 63,125,226,162, 62,213,228,252, 63,125,226,162, 0, 0, 0, 0, 61, 0, 0, 1, 0, 0, 0, 0,
+ 68, 65, 84, 65, 0, 0, 0,128, 2,236,237, 16, 0, 0, 0, 57, 0, 0, 0, 32,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 68, 65, 84, 65, 0, 0, 1,224, 5, 30, 54, 32,
+ 0, 0, 0, 51, 0, 0, 0, 8, 0, 0, 0, 0, 63, 55, 23,152, 63,125,226,162, 63, 17, 5, 30, 63,125,226,162, 63, 17, 5, 30,
+ 63,125,226,162, 63, 55, 23,152, 63,125,226,162,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 61, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,213,228,252, 63,125,226,162, 63, 17, 5, 30, 63,125,226,162, 63, 17, 5, 30, 63,125,226,162,
+ 62,213,228,252, 63,125,226,162,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 61, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 55, 23,152, 63,125,226,162, 63, 17, 5, 30, 63,125,226,162, 63, 17, 5, 30, 63,125,226,162, 63, 55, 23,152,
+ 63,125,226,162,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 61, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 17, 5, 34, 63,125,226,162, 62,213,229, 0, 63,125,226,162, 62,213,228,252, 63,125,226,162, 63, 17, 5, 30, 63,125,226,162,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 61, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,137,192, 18,
+ 63,125,226,162, 61,246,108,144, 63,125,226,162, 61,246,108,144, 63,125,226,162, 62,137,192, 12, 63,125,226,162,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 61, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,213,228,252, 63,125,226,162,
+ 62,137,192, 12, 63,125,226,162, 62,137,192, 12, 63,125,226,162, 62,213,228,252, 63,125,226,162,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 61, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,137,192, 12, 63,125,226,162, 61,246,108,144,
+ 63,125,226,162, 61,246,108,144, 63,125,226,162, 62,137,192, 12, 63,125,226,162,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 61, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,213,228,252, 63,125,226,162, 62,137,192, 12, 63,125,226,162,
+ 62,137,192, 12, 63,125,226,162, 62,213,228,252, 63,125,226,162,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 61, 0, 0, 1, 0, 0, 0, 0, 0, 0, 77, 69, 0, 0, 1, 20, 2,236,237,192, 0, 0, 0, 50, 0, 0, 0, 1, 2,236,243,224,
+ 2,236,228, 0, 0, 0, 0, 0, 0, 0, 0, 0, 77, 69, 80,108, 97,110,101, 46, 48, 48, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 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, 2,236,239, 0, 2,236,243,160, 0, 0, 0, 0, 0, 0, 0, 0, 2,236,240, 96, 2,236,242, 16, 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, 2,236,239, 48, 0, 0, 0, 1,
+ 0, 0, 0, 5, 0, 0, 0, 20, 0, 0, 0, 0, 2,236,240,224, 0, 0, 0, 1, 0, 0, 0, 5, 0, 0, 0, 12, 0, 0, 0, 0,
+ 2,236,242,112, 0, 0, 0, 1, 0, 0, 0, 5, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,179,128, 0, 0, 52, 64, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 2,
+ 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 4, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 4, 2,236,239, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 2,236,194, 96, 68, 65, 84, 65, 0, 0, 1, 4, 2,236,239, 48, 0, 0, 0,242, 0, 0, 0, 5, 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, 2,236,240, 96, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65, 0, 0, 0, 80, 2,236,240, 96, 0, 0, 0, 56, 0, 0, 0, 4, 63,128, 0, 0, 63,127,255,255, 0, 0, 0, 0,
+ 0, 0, 0, 0,127,255, 3,255, 63,128, 0, 0,191,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127,255, 3,255,191,128, 0, 1,
+191,127,255,253, 0, 0, 0, 0, 0, 0, 0, 0,127,255, 3,255,191,127,255,250, 63,128, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0,
+127,255, 3,255, 68, 65, 84, 65, 0, 0, 1, 4, 2,236,240,224, 0, 0, 0,242, 0, 0, 0, 5, 0, 0, 0, 3, 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, 2,236,242, 16, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+ 0, 0, 0, 48, 2,236,242, 16, 0, 0, 0, 53, 0, 0, 0, 4, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 35, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 0, 35, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, 3, 0, 0, 0, 2, 0, 0, 0, 35,
+ 68, 65, 84, 65, 0, 0, 1, 4, 2,236,242,112, 0, 0, 0,242, 0, 0, 0, 5, 0, 0, 0, 4, 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, 2,236,243,160, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 20,
+ 2,236,243,160, 0, 0, 0, 52, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 2,
+ 0, 0, 77, 69, 0, 0, 1, 20, 2,236,243,224, 0, 0, 0, 50, 0, 0, 0, 1, 2,236,248,224, 2,236,237,192, 0, 0, 0, 0,
+ 0, 0, 0, 0, 77, 69,112,114,101,118,105,101,119, 0, 0, 0, 0,112,104,101,114,101, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 2,235,212, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,236,245, 32,
+ 8,108, 16, 32, 8,108,128, 32, 8,172, 96, 32, 5, 32,170, 32, 8,107,176, 32, 0, 0, 0, 0, 8,109, 96, 32, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,236,245, 80, 0, 0, 0, 1, 0, 0, 0, 5, 0, 0, 0, 20,
+ 0, 0, 0, 0, 2,236,246,128, 0, 0, 0, 1, 0, 0, 0, 5, 0, 0, 0, 12, 0, 0, 0, 0, 2,236,247,176, 0, 0, 0, 3,
+ 0, 0, 0, 5, 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, 2,130, 0, 0, 7,128, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64,186,224,117, 64,187, 13, 91, 64,186,240,160, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 4, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 4, 2,236,245, 32, 0, 0, 0, 0, 0, 0, 0, 1, 2,236,194, 96,
+ 68, 65, 84, 65, 0, 0, 1, 4, 2,236,245, 80, 0, 0, 0,242, 0, 0, 0, 5, 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, 5, 32,170, 32, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 50, 40,
+ 5, 32,170, 32, 0, 0, 0, 56, 0, 0, 2,130,191,141,136, 28, 62,244,243, 12,192,183, 86,198,231,212, 10,117,130,191, 3,255,
+192,131,102,240, 64,119,183, 30,191,199,169,109,166, 58, 84,158,221,230, 3,255, 63,239,108,119, 64,156, 85,213,192, 40, 58,188,
+ 40,228,106,207,198,137, 3,255, 64,146,135, 95,191, 14, 54, 63,192,102,194,241,100, 27,243,219,177, 45, 3,255, 62,141, 84,239,
+192,157,220, 16,192, 73, 2, 14, 6, 8,148, 39,187, 86, 3,255,192,162,239,132,192, 12,165,206,191,240, 45,150,144,175,207,245,
+214,251, 3,255,190,141, 84,239, 64,157,220, 16, 64, 73, 2, 14,249,248,107,217, 68,170, 3,255, 64,162,239,132, 64, 12,165,206,
+ 63,240, 45,150,111, 81, 48, 11, 41, 5, 3,255, 64,131,102,240,192,119,183, 30, 63,199,169,109, 89,198,171, 98, 34, 26, 3,255,
+191,239,108,119,192,156, 85,213, 64, 40, 58,188,215, 28,149, 49, 57,119, 3,255,192,146,135, 95, 63, 14, 54, 63, 64,102,194,241,
+155,229, 12, 37, 78,211, 3,255, 63,141,136, 28,190,244,243, 12, 64,183, 86,198, 24, 44,245,139,125, 65, 3,255,192, 68, 17,114,
+ 64, 35,153,226,192,137, 26,154,189, 6, 55,226,162, 85, 3,255, 62,230, 40,155, 64, 73,199,239,192,157, 52,176, 9,211, 68,237,
+148,153, 3,255,191,168, 55,124, 64,164,177,224,192, 29,144, 58,227, 69,112,132,202, 46, 3,255,192,105, 35, 94,191,129, 88,230,
+192,143, 14,195,176, 93,233,233,158, 68, 3,255,192,173, 2, 37, 63,123,187,137,192, 1, 68, 56,137,206, 21,127,211,216, 3,255,
+ 64, 2,168,234,189, 57,158,231,192,175,149, 65, 44,162,255, 3,136, 11, 3,255, 64,114,159, 19, 64, 34,226,254,192,106,133,196,
+ 82,225, 55,164,175,228, 3,255,190,249,176,105,192, 39,148, 21,192,166,214,217,245, 87,198,194,142, 5, 3,255, 64, 54,163,227,
+192, 78,121, 86,192,125,202, 22, 62, 99,185,120,169, 79, 3,255,192, 53, 40,241,192,134, 31,200,192, 60,188,229,194, 30,164, 94,
+191,136, 3,255,192,181,230, 96,191,119, 24, 33, 63,130, 26,174,131,186,234,231, 22, 56, 3,255,192,163, 93,103, 64, 38,128,136,
+ 63,153,235, 83,144,100, 56,224, 26, 74, 3,255,192, 36,219,238, 64,165,151,132, 63,109,226,165,199,176,113, 33, 20, 80, 3,255,
+ 63,111,237, 24, 64,184,174,118, 62,154, 34,212, 20,125,126, 44, 6,148, 3,255, 64,130,244,163, 64,133, 58,157,190,226, 95,125,
+ 89,119, 91, 5,246, 86, 3,255, 64,181,230, 96, 63,119, 24, 33,191,130, 26,174,124, 70, 21, 25,233,200, 3,255, 64,163, 93,103,
+192, 38,128,136,191,153,235, 83,111,156,199, 32,229,182, 3,255, 64, 36,219,238,192,165,151,132,191,109,226,165, 56, 80,142,223,
+235,176, 3,255,191,111,237, 24,192,184,174,118,190,154, 34,212,235,131,129,212,249,108, 3,255,192,130,244,163,192,133, 58,157,
+ 62,226, 95,125,166,137,164,251, 9,170, 3,255,192, 54,163,227, 64, 78,121, 86, 64,125,202, 22,193,157, 70,136, 86,177, 3,255,
+ 64, 53, 40,241, 64,134, 31,200, 64, 60,188,229, 61,226, 91,162, 64,120, 3,255, 64,173, 2, 37,191,123,187,137, 64, 1, 68, 56,
+118, 50,234,129, 44, 40, 3,255, 63,168, 55,124,192,164,177,224, 64, 29,144, 58, 28,187,143,124, 53,210, 3,255,192,114,159, 19,
+192, 34,226,254, 64,106,133,196,173, 31,200, 92, 80, 28, 3,255,192, 2,168,234, 61, 57,158,231, 64,175,149, 65,211, 94, 0,253,
+119,245, 3,255, 62,249,176,105, 64, 39,148, 21, 64,166,214,217, 10,169, 57, 62,113,251, 3,255, 64,105, 35, 94, 63,129, 88,230,
+ 64,143, 14,195, 79,163, 22, 23, 97,188, 3,255, 64, 68, 17,114,192, 35,153,226, 64,137, 26,154, 66,250,200, 30, 93,171, 3,255,
+190,230, 40,155,192, 73,199,239, 64,157, 52,176,246, 45,187, 19,107,103, 3,255,192, 10,178, 37, 63,201,231,138,192,166,143,149,
+209,129, 33,140,141,145, 3,255,192,110,132, 3, 64, 85,203,243,192, 66,107,151,174, 16, 73,158,190,209, 3,255,190,174,161,116,
+ 63,241,152, 81,192,177, 2,110,247,217, 40, 15,134,182, 3,255, 63,154, 91,138, 64,133,179,218,192,122,222,209, 27, 0, 92, 30,
+171, 86, 3,255,192, 52, 82, 7, 64,149,252, 82,192, 5,202, 64,193, 39,101,227,210,181, 3,255, 62,148, 12,179, 64,166,221,251,
+192, 41, 87,188, 7,192,113,224,198, 21, 3,255,192, 29,246,216,190,141,156, 17,192,169,167,209,203, 47,250,160,139,137, 3,255,
+192,145, 72, 99,191,213,114, 79,192, 83, 35,183,156, 26,219, 3,185, 12, 3,255,192,158, 58,115, 64, 33,120,129,191,238, 41,198,
+148,126, 56,116,215,137, 3,255,192,174,158,118,191, 33,148,103,192, 1,156,140,136,218,240,198,211,203, 3,255, 62,249, 14, 55,
+ 62,102,133, 95,192,186,143,210, 9, 56, 5, 40,128,113, 3,255, 64, 92, 61,220,190,159,230, 56,192,151, 61, 6, 76, 94,248,242,
+153,135, 3,255, 64, 60, 86, 7, 64,119, 48, 60,192, 81, 88, 93, 63,119, 85,124,184,246, 3,255, 64,139, 55,252, 63,132, 95, 62,
+192,113,216,225, 95,118, 21, 54,173,107, 3,255,191, 84, 6, 18,191,142, 96,251,192,182, 4, 76,237,158,233, 20,131,109, 3,255,
+189,225, 74,109,192,123, 54, 51,192,138,246, 34,253,241,169, 39,162, 1, 3,255, 64,119, 66,153,191,251,154,127,192,123,220,161,
+ 85, 59,214, 59,170, 34, 3,255, 63,208, 59,201,192,135,182,241,192,108,101,212, 34,103,162,133,175,160, 3,255,191,169,246,161,
+192,151,196,235,192, 74,149,170,228, 95,151,253,186,184, 3,255,192,131,198, 33,192, 84,137,218,192, 32,134, 37,164,247,184, 77,
+201,167, 3,255,192,179, 61,176,191,210,110,138,190,228,220, 24,133,210,219,130,244,238, 3,255,192,170,182, 73,190, 90, 16,136,
+ 64, 25,194, 90,139,224,252, 8, 53,174, 3,255,192,153, 55, 75, 64, 87, 78, 4,190, 62, 54, 12,151,200, 74, 29,250,179, 3,255,
+192,161, 19,235, 63,210, 12,207, 64, 31,242,210,146, 50, 34,244, 55,182, 3,255,192, 94, 75, 60, 64,150,115,189,190,167,211,186,
+179, 98,102, 49,247,183, 3,255,191,189,191,186, 64,168, 32, 63, 64, 7,100,213,224,161,114,191, 47, 61, 3,255, 63,186,205,242,
+ 64,177, 65,141,191,154,219,127, 32, 82,120,177,228, 61, 3,255, 62,175,245, 99, 64,178, 12, 97, 63,228,253,255, 6,247,121, 65,
+ 40, 98, 3,255, 64, 70, 92,226, 64,150,131, 8,191,204, 77,182, 66,193,103, 37,220, 32, 3,255, 64,152,194,200, 64, 83,155,180,
+ 63, 62,217,154,104,207, 71,101, 17, 87, 3,255, 64,170,182, 73, 62, 90, 16,136,192, 25,194, 90,116, 32, 3,248,202, 82, 3,255,
+ 64,179, 61,176, 63,210,110,138, 62,228,220, 24,122, 46, 36,126, 11, 18, 3,255, 64,161, 19,235,191,210, 12,207,192, 31,242,210,
+109,206,221, 12,200, 74, 3,255, 64,153, 55, 75,192, 87, 78, 4, 62, 62, 54, 12,104, 56,181,227, 5, 77, 3,255, 63,189,191,186,
+192,168, 32, 63,192, 7,100,213, 31, 95,141, 65,208,195, 3,255, 64, 94, 75, 60,192,150,115,189, 62,167,211,186, 76,158,153,207,
+ 8, 73, 3,255,190,175,245, 99,192,178, 12, 97,191,228,253,255,249, 9,134,191,215,158, 3,255,191,186,205,242,192,177, 65,141,
+ 63,154,219,127,223,174,135, 79, 27,195, 3,255,192,152,194,200,192, 83,155,180,191, 62,217,154,151, 49,184,155,238,169, 3,255,
+192, 70, 92,226,192,150,131, 8, 63,204, 77,182,189, 63,152,219, 35,224, 3,255,191,208, 59,201, 64,135,182,241, 64,108,101,212,
+221,153, 93,123, 80, 96, 3,255,192,119, 66,153, 63,251,154,127, 64,123,220,161,170,197, 41,197, 85,222, 3,255, 63,169,246,161,
+ 64,151,196,235, 64, 74,149,170, 27,161,104, 3, 69, 72, 3,255, 64,131,198, 33, 64, 84,137,218, 64, 32,134, 37, 91, 9, 71,179,
+ 54, 89, 3,255, 64,174,158,118, 63, 33,148,103, 64, 1,156,140,119, 38, 15, 58, 44, 53, 3,255, 64,158, 58,115,192, 33,120,129,
+ 63,238, 41,198,107,130,199,140, 40,119, 3,255, 64, 52, 82, 7,192,149,252, 82, 64, 5,202, 64, 62,217,154, 29, 45, 75, 3,255,
+190,148, 12,179,192,166,221,251, 64, 41, 87,188,248, 64,142, 32, 57,235, 3,255,192, 60, 86, 7,192,119, 48, 60, 64, 81, 88, 93,
+192,137,170,132, 71, 10, 3,255,192,139, 55,252,191,132, 95, 62, 64,113,216,225,160,138,234,202, 82,149, 3,255,192, 92, 61,220,
+ 62,159,230, 56, 64,151, 61, 6,179,162, 7, 14,102,121, 3,255,190,249, 14, 55,190,102,133, 95, 64,186,143,210,246,200,250,216,
+127,143, 3,255, 61,225, 74,109, 64,123, 54, 51, 64,138,246, 34, 2, 15, 86,217, 93,255, 3,255, 63, 84, 6, 18, 63,142, 96,251,
+ 64,182, 4, 76, 18, 98, 22,236,124,147, 3,255, 64,145, 72, 99, 63,213,114, 79, 64, 83, 35,183, 99,230, 36,253, 70,244, 3,255,
+ 64, 29,246,216, 62,141,156, 17, 64,169,167,209, 52,209, 5, 96,116,119, 3,255, 64,110,132, 3,192, 85,203,243, 64, 66,107,151,
+ 81,240,182, 98, 65, 47, 3,255, 64, 10,178, 37,191,201,231,138, 64,166,143,149, 46,127,222,116,114,111, 3,255,191,154, 91,138,
+192,133,179,218, 64,122,222,209,229, 0,163,226, 84,170, 3,255, 62,174,161,116,191,241,152, 81, 64,177, 2,110, 8, 39,215,241,
+121, 74, 3,255,192, 19, 76, 36, 64,129,151, 25,192, 98,254,212,206,231, 88, 97,177,131, 3,255,191,175,232, 93, 64, 64, 23,177,
+192,154,186, 69,225,227, 66,235,151, 34, 3,255,190,232,190,208, 64,139,160, 93,192,120, 33,191,244,183, 94,205,170,192, 3,255,
+192,142,126,210, 63,238, 49, 43,192, 84, 30,112,158,187, 39, 95,182,183, 3,255,192, 97,165,138, 63, 80, 9, 92,192,147, 74, 20,
+177,183, 17,233,156, 86, 3,255,192,152, 61, 98,188,106, 63, 87,192, 90, 97, 6,152,127, 0,251,180,183, 3,255, 64, 14,173,200,
+ 64, 63,183,155,192,144, 75,192, 48,206, 64, 45,156,152, 3,255, 63,167,162, 95, 63,209, 29,144,192,174,245, 25, 29,250, 36, 75,
+136,250, 3,255, 64, 68, 62,211, 63,168, 56, 51,192,153,245, 13, 65,241, 29,192,150,106, 3,255, 64, 36,182, 33,191,220, 38, 34,
+192,159, 5,150, 54,233,217,211,146,223, 3,255, 63, 81, 34, 16,191,179, 64,129,192,180, 5,162, 18,242,224, 93,133,111, 3,255,
+ 63,159, 56,212,192, 68,166,172,192,154,108,212, 27,176,190, 32,149,208, 3,255,191,223, 76,204,192,101, 32,170,192,137, 83, 65,
+216,199,178,195,161,198, 3,255,192, 10,249,249,191,244, 52, 62,192,162,236, 25,208, 9,213, 0,145,102, 3,255,192, 89,207, 42,
+192, 47, 6,251,192,121,165, 27,182,209,196, 18,169,198, 3,255,192,176,215,137, 63,241, 62, 25,190,219,254,179,134,179, 39,232,
+247, 78, 3,255,192,186,150, 28, 60, 28, 16,150,191, 7, 9,191,128,118, 1,131,245, 77, 3,255,192,181,132, 34, 63, 92, 60, 99,
+ 63,149, 81,217,131,181, 18,238, 23,252, 3,255,190, 74,242,175, 64,183,173,164,191,145,105,227,250,117,125,160,232, 31, 3,255,
+192, 2,227,219, 64,173,164, 96,191, 78, 71,200,212,164,119, 52,238,226, 3,255,191, 92,140,181, 64,184, 38, 75, 63, 37,148,176,
+236,224,125,237, 12,159, 3,255, 64,159,104, 75, 63,236, 56,212,192, 29,126,240,108,211, 41,166,203, 9, 3,255, 64,132,159,215,
+ 64, 97,184, 84,192, 10, 44, 30, 91,176, 76, 19,209, 56, 3,255, 64,164,122, 95, 64, 44,143,199,191, 68, 78, 53,112, 17, 59, 17,
+237,185, 3,255, 64, 54,176,255,192,141, 84,243,192, 36,176,237, 63,192,160, 9,200, 63, 3,255, 64,133,229, 93,192, 68, 21,217,
+192, 45,226,157, 90,249,187,187,197, 78, 3,255, 64,129, 56,203,192,130,211, 21,191,143,115,187, 87,252,166,194,229,252, 3,255,
+192,104,239,189,192,140,142, 82,191,168,178,178,177,134,158,245,227,155, 3,255,191,253,141, 50,192,167,155, 52,191,218,181,170,
+211,125,141,166,219,155, 3,255,192, 41, 58,164,192,167, 34,172, 61,151,232,206,197,232,141,243, 0, 26, 3,255,192,133,229, 93,
+ 64, 68, 21,217, 64, 45,226,157,165, 7, 68, 69, 58,178, 3,255,192,129, 56,203, 64,130,211, 21, 63,143,115,187,168, 4, 89, 62,
+ 26, 4, 3,255,192, 54,176,255, 64,141, 84,243, 64, 36,176,237,192, 64, 95,247, 55,193, 3,255, 63,253,141, 50, 64,167,155, 52,
+ 63,218,181,170, 44,131,114, 90, 36,101, 3,255, 64, 41, 58,164, 64,167, 34,172,189,151,232,206, 58, 24,114, 13,255,230, 3,255,
+ 64,104,239,189, 64,140,142, 82, 63,168,178,178, 78,122, 97, 11, 28,101, 3,255, 64,186,150, 28,188, 28, 16,150, 63, 7, 9,191,
+127,138,254,125, 10,179, 3,255, 64,181,132, 34,191, 92, 60, 99,191,149, 81,217,124, 75,237, 18,232, 4, 3,255, 64,176,215,137,
+191,241, 62, 25, 62,219,254,179,121, 77,216, 24, 8,178, 3,255, 64, 2,227,219,192,173,164, 96, 63, 78, 71,200, 43, 92,136,204,
+ 17, 30, 3,255, 63, 92,140,181,192,184, 38, 75,191, 37,148,176, 19, 32,130, 19,243, 97, 3,255, 62, 74,242,175,192,183,173,164,
+ 63,145,105,227, 5,139,130, 96, 23,225, 3,255,192,132,159,215,192, 97,184, 84, 64, 10, 44, 30,164, 80,179,237, 46,200, 3,255,
+192,164,122, 95,192, 44,143,199, 63, 68, 78, 53,143,239,196,239, 18, 71, 3,255,192,159,104, 75,191,236, 56,212, 64, 29,126,240,
+147, 45,214, 90, 52,247, 3,255,191,159, 56,212, 64, 68,166,172, 64,154,108,212,228, 80, 65,224,106, 48, 3,255,192, 36,182, 33,
+ 63,220, 38, 34, 64,159, 5,150,201, 23, 38, 45,109, 33, 3,255,191, 81, 34, 16, 63,179, 64,129, 64,180, 5,162,237, 14, 31,163,
+122,145, 3,255, 64, 89,207, 42, 64, 47, 6,251, 64,121,165, 27, 73, 47, 59,238, 86, 58, 3,255, 63,223, 76,208, 64,101, 32,170,
+ 64,137, 83, 65, 39, 57, 77, 61, 94, 58, 3,255, 64, 10,249,249, 63,244, 52, 62, 64,162,236, 25, 47,247, 43, 0,110,154, 3,255,
+ 64,142,126,210,191,238, 49, 43, 64, 84, 30,112, 97, 69,216,161, 73, 73, 3,255, 64,152, 61, 98, 60,106, 63, 87, 64, 90, 97, 6,
+103,129,255, 5, 75, 73, 3,255, 64, 97,165,138,191, 80, 9, 92, 64,147, 74, 20, 78, 73,238, 23, 99,170, 3,255, 62,232,190,208,
+192,139,160, 93, 64,120, 33,191, 11, 73,161, 51, 85, 64, 3,255, 64, 19, 76, 36,192,129,151, 25, 64, 98,254,212, 49, 25,167,159,
+ 78,125, 3,255, 63,175,232, 93,192, 64, 23,177, 64,154,186, 69, 30, 29,189, 21,104,222, 3,255,192, 68, 62,211,191,168, 56, 51,
+ 64,153,245, 13,190, 15,226, 64,105,150, 3,255,192, 14,173,200,192, 63,183,155, 64,144, 75,192,207, 50,191,211, 99,104, 3,255,
+191,167,162, 95,191,209, 29,144, 64,174,245, 25,226, 6,219,181,119, 6, 3,255,191,211,156,158, 63,132,228,185,192,176,207,190,
+220,164, 21,231,134,244, 3,255,192, 41, 76, 0, 64, 5,199,190,192,153,157, 83,198,146, 45, 75,150,246, 3,255,192,125, 83,204,
+ 64,105, 55,169,192, 20,162,244,169, 72, 79,246,206, 82, 3,255,192, 91,215,178, 64, 62,235,222,192,108,254,190,180,215, 65, 87,
+175,155, 3,255,191, 59, 63,242, 63,152,237,210,192,182, 21,251,239,125, 25, 26,131,149, 3,255, 61, 94,230, 86, 64, 35, 30,198,
+192,169, 15,233, 0,238, 55, 52,140,135, 3,255, 63,199, 4,220, 64,146,145, 7,192, 83,186,104, 34,109,100,137,184,168, 3,255,
+ 63, 86,120, 9, 64,109, 91,149,192,142,242, 79, 18,133, 81, 64,158,218, 3,255,192, 95,243,103, 64,138, 91,221,191,236, 15,186,
+178,170, 93,219,216, 25, 3,255,192, 5,206, 46, 64,159, 41,121,192, 19, 91,154,209,230,108, 96,205,226, 3,255, 63,139,200,169,
+ 64,163, 78,198,192, 42,146,201, 24,247,111, 59,197,206, 3,255,191, 4,128,187, 64,167,181,206,192, 37, 92, 74,245, 57,114, 96,
+199,145, 3,255,191,231, 16,151, 61,209,166,160,192,178, 95,167,217,136, 2,196,133,245, 3,255,192, 69,200,163,191, 38,143,178,
+192,158, 48,148,188,243,242, 11,147,223, 3,255,192,155,192, 43,191,250, 6,151,192, 39, 82,170,149, 79,212,247,199,231, 3,255,
+192,132,118,233,191,173,111,217,192,123,122, 67,165,100,226, 58,170,165, 3,255,192,146, 85,238, 64, 78,205,178,191,221, 54, 70,
+156,183, 71,134,218,120, 3,255,192,167,137, 76, 63,227, 31,111,191,251, 57,158,141,234, 39, 54,213, 59, 3,255,192,170,143, 39,
+191,183, 15,167,191,252, 85,251,139,217,223,169,213, 13, 3,255,192,175,214, 8, 62, 53,124,177,192, 2,241,206,136, 23, 3, 89,
+211, 92, 3,255,190,160,160, 77, 62,182, 20, 9,192,186,232,108,248, 8, 7,241,128,128, 3,255, 63,163,144, 33, 61,186,144,151,
+192,183, 47, 50, 27, 97, 2, 19,130,252, 3,255, 64,129,179,222,190,224,147,234,192,134,180, 38, 89, 83,246, 64,164,218, 3,255,
+ 64, 49,138,114,190, 57, 97,246,192,165, 76, 57, 60,250,251,247,143,138, 3,255, 64, 27,158,249, 64,141,118,197,192, 62,196, 58,
+ 52, 90, 97, 70,191, 90, 3,255, 64, 89,244, 98, 64, 79,120, 8,192, 96,128, 65, 74, 8, 71, 39,179,151, 3,255, 64,144,100, 13,
+ 62,118,214,200,192,110,205, 64, 98,182, 4, 37,174,161, 3,255, 64,131,202, 42, 63,231,161, 60,192,112,245,142, 90, 10, 38,255,
+173,209, 3,255,191,122, 51,149,190,163,151, 52,192,184,157, 15,234,118,250, 36,129,248, 3,255,191, 42,113, 5,191,241,112, 31,
+192,176,119, 15,241, 93,215, 84,135,135, 3,255, 61,172, 55, 60,192,143, 64, 22,192,113,246,164, 2, 27,157,132,174, 71, 3,255,
+190,154,173,167,192, 83,224,111,192,154,169,198,249,136,183, 89,150,211, 3,255, 64,136,133,151,191,162,249, 9,192,115,219,106,
+ 93,175,229, 47,173, 3, 3,255, 64, 89,124,110,192, 40, 6,135,192,127,195,223, 74,120,199, 31,168,208, 3,255, 63,117,248,244,
+192,148, 90,109,192, 93, 0,123, 20, 8,154, 66,180,249, 3,255, 64, 17, 0,162,192,113,196, 63,192,119,239, 52, 49, 10,173, 64,
+171,144, 3,255,191, 7,217,162,192,156,117, 21,192, 75,238,222,245,139,149, 20,186,108, 3,255,192, 6,144,171,192,144,158,112,
+192, 69,241,198,210,156,157, 55,188,115, 3,255,192,148,238,110,192, 50,109,115,192, 13,197,187,153,170,195,231,208, 17, 3,255,
+192, 96,252, 79,192,115, 40,140,192, 48,165,116,178,226,173, 98,195,236, 3,255,192,172,228,100,191,248,128,217,191,150, 93, 8,
+138, 91,213, 53,229, 86, 3,255,192,182,171, 82,191,168,250,216, 62,147, 15, 15,131,122,226,250, 5,203, 3,255,192,160, 73,215,
+ 62, 49,165,124, 64, 66, 85,232,147, 33, 4, 84, 67, 42, 3,255,192,178, 89,171,191, 24,115,192, 63,221,116, 78,134,129,243, 64,
+ 38, 50, 3,255,192,143,206, 51, 64,105,250,133,191, 97,251,119,158, 85, 80, 53,235,193, 3,255,192,160, 32, 62, 64, 65, 38,163,
+ 63, 3,117,164,146,236, 66, 24, 10,193, 3,255,192,155,108,216, 63,141,255, 59, 64, 69,117,189,150, 61, 23,119, 68, 42, 3,255,
+192,164, 27, 85, 64, 9, 78,244, 63,239,193, 87,144, 33, 46,128, 41, 73, 3,255,192,117, 35,134, 64,138,152, 39,191,116, 86, 73,
+171,230, 94, 2,234, 73, 3,255,192, 67,220, 35, 64,159,218, 6, 62,155,103,242,188,240,108,215, 6, 55, 3,255,191, 99, 79,130,
+ 64,164,182,215, 64, 42, 4, 10,237,118,112, 50, 58,190, 3,255,192, 3, 86,161, 64,168,205, 14, 63,197, 55, 60,211,148,115, 31,
+ 33,255, 3,255, 63,215,101,229, 64,168,141, 84,191,248, 90, 16, 37, 11,114,148,212,159, 3,255, 63,155, 52, 99, 64,183, 17,198,
+190,235,199,232, 26,159,124,192,245,120, 3,255, 61, 10,179,105, 64,169,185, 25, 64, 31,119,120, 0, 77,115,101, 55, 96, 3,255,
+ 63, 37,198,143, 64,183,120,123, 63,135,108,160, 13,240,125, 8, 23,144, 3,255, 64, 32,174,180, 64,155, 13, 65,192, 8,167,238,
+ 53,247,105,245,208,163, 3,255, 64,104,199, 69, 64,143,135,177,191,132, 12, 41, 79, 10, 98, 10,233, 31, 3,255, 64,159,134,121,
+ 64, 49,245, 49, 63,169,166,210,109, 27, 59,242, 29,190, 3,255, 64,143,133, 52, 64,113,200,119, 62, 29,206,186, 98, 20, 82, 39,
+ 3,190, 3,255, 64,160, 73,215,190, 49,165,124,192, 66, 85,232,108,223,251,172,188,214, 3,255, 64,178, 89,171, 63, 24,115,192,
+191,221,116, 78,121,127, 12,192,217,206, 3,255, 64,172,228,100, 63,248,128,217, 63,150, 93, 8,117,165, 42,203, 26,170, 3,255,
+ 64,182,171, 82, 63,168,250,216,190,147, 15, 15,124,134, 29, 6,250, 53, 3,255, 64,155,108,216,191,141,255, 59,192, 69,117,189,
+105,195,232,137,187,214, 3,255, 64,164, 27, 85,192, 9, 78,244,191,239,193, 87,111,223,209,128,214,183, 3,255, 64,143,206, 51,
+192,105,250,133, 63, 97,251,119, 97,171,175,203, 20, 63, 3,255, 64,160, 32, 62,192, 65, 38,163,191, 3,117,164,109, 20,189,232,
+245, 63, 3,255, 63, 99, 79,130,192,164,182,215,192, 42, 4, 10, 18,138,143,206,197, 66, 3,255, 64, 3, 86,161,192,168,205, 14,
+191,197, 55, 60, 44,108,140,225,222, 1, 3,255, 64,117, 35,134,192,138,152, 39, 63,116, 86, 73, 84, 26,161,254, 21,183, 3,255,
+ 64, 67,220, 35,192,159,218, 6,190,155,103,242, 67, 16,147, 41,249,201, 3,255,189, 10,179,105,192,169,185, 25,192, 31,119,120,
+255,179,140,155,200,160, 3,255,191, 37,198,143,192,183,120,123,191,135,108,160,242, 16,130,248,232,112, 3,255,191,215,101,229,
+192,168,141, 84, 63,248, 90, 16,218,245,141,108, 43, 97, 3,255,191,155, 52, 99,192,183, 17,198, 62,235,199,232,229, 97,131, 64,
+ 10,136, 3,255,192,159,134,121,192, 49,245, 49,191,169,166,210,146,229,196, 14,226, 66, 3,255,192,143,133, 52,192,113,200,119,
+190, 29,206,186,157,236,173,217,252, 66, 3,255,192, 32,174,180,192,155, 13, 65, 64, 8,167,238,202, 9,150, 11, 47, 93, 3,255,
+192,104,199, 69,192,143,135,177, 63,132, 12, 41,176,246,157,246, 22,225, 3,255,191,117,248,244, 64,148, 90,109, 64, 93, 0,123,
+235,248,101,190, 75, 7, 3,255,192, 17, 0,162, 64,113,196, 63, 64,119,239, 52,206,246, 82,192, 84,112, 3,255,192,136,133,151,
+ 63,162,249, 9, 64,115,219,106,162, 81, 26,209, 82,253, 3,255,192, 89,124,110, 64, 40, 6,135, 64,127,195,223,181,136, 56,225,
+ 87, 48, 3,255, 63, 7,217,162, 64,156,117, 21, 64, 75,238,222, 10,117,106,236, 69,148, 3,255, 64, 6,144,171, 64,144,158,112,
+ 64, 69,241,198, 45,100, 98,201, 67,141, 3,255, 64,148,238,110, 64, 50,109,115, 64, 13,197,187,102, 86, 60, 25, 47,239, 3,255,
+ 64, 96,252, 79, 64,115, 40,140, 64, 48,165,116, 77, 30, 82,158, 60, 20, 3,255, 64,170,143, 39, 63,183, 15,167, 63,252, 85,251,
+116, 39, 32, 87, 42,243, 3,255, 64,175,214, 8,190, 53,124,177, 64, 2,241,206,119,233,252,167, 44,164, 3,255, 64,146, 85,238,
+192, 78,205,178, 63,221, 54, 70, 99, 73,184,122, 37,136, 3,255, 64,167,137, 76,191,227, 31,111, 63,251, 57,158,114, 22,216,202,
+ 42,197, 3,255, 64, 95,243,103,192,138, 91,221, 63,236, 15,186, 77, 86,162, 37, 39,231, 3,255, 64, 5,206, 46,192,159, 41,121,
+ 64, 19, 91,154, 46, 26,147,160, 50, 30, 3,255,191,139,200,169,192,163, 78,198, 64, 42,146,201,231, 9,144,197, 58, 50, 3,255,
+ 63, 4,128,187,192,167,181,206, 64, 37, 92, 74, 10,199,141,160, 56,111, 3,255,192, 27,158,249,192,141,118,197, 64, 62,196, 58,
+203,166,158,186, 64,166, 3,255,192, 89,244, 98,192, 79,120, 8, 64, 96,128, 65,181,248,184,217, 76,105, 3,255,192,144,100, 13,
+190,118,214,200, 64,110,205, 64,157, 74,251,219, 81, 95, 3,255,192,131,202, 42,191,231,161, 60, 64,112,245,142,165,246,217, 1,
+ 82, 47, 3,255,192,129,179,222, 62,224,147,234, 64,134,180, 38,166,173, 9,192, 91, 38, 3,255,192, 49,138,114, 62, 57, 97,246,
+ 64,165, 76, 57,195, 6, 4, 9,112,118, 3,255, 62,160,160, 77,190,182, 20, 9, 64,186,232,108, 7,248,248, 15,127,128, 3,255,
+191,163,144, 33,189,186,144,151, 64,183, 47, 50,228,159,253,237,125, 4, 3,255,189,172, 55, 60, 64,143, 64, 22, 64,113,246,164,
+253,229, 98,124, 81,185, 3,255, 62,154,173,167, 64, 83,224,111, 64,154,169,198, 6,120, 72,167,105, 45, 3,255, 63,122, 51,149,
+ 62,163,151, 52, 64,184,157, 15, 21,138, 5,220,126, 8, 3,255, 63, 42,113, 5, 63,241,112, 31, 64,176,119, 15, 14,163, 40,172,
+120,121, 3,255, 64,155,192, 43, 63,250, 6,151, 64, 39, 82,170,106,177, 43, 9, 56, 25, 3,255, 64,132,118,233, 63,173,111,217,
+ 64,123,122, 67, 90,156, 29,198, 85, 91, 3,255, 63,231, 16,151,189,209,166,160, 64,178, 95,167, 38,120,253, 60,122, 11, 3,255,
+ 64, 69,200,163, 63, 38,143,178, 64,158, 48,148, 67, 13, 13,245,108, 33, 3,255, 64,125, 83,204,192,105, 55,169, 64, 20,162,244,
+ 86,184,176, 10, 49,174, 3,255, 64, 91,215,178,192, 62,235,222, 64,108,254,190, 75, 41,190,169, 80,101, 3,255, 63,211,156,158,
+191,132,228,185, 64,176,207,190, 35, 92,234, 25,121, 12, 3,255, 64, 41, 76, 0,192, 5,199,190, 64,153,157, 83, 57,110,210,181,
+105, 10, 3,255,191,199, 4,220,192,146,145, 7, 64, 83,186,104,221,147,155,119, 71, 88, 3,255,191, 86,120, 9,192,109, 91,149,
+ 64,142,242, 79,237,123,174,192, 97, 38, 3,255, 63, 59, 63,242,191,152,237,210, 64,182, 21,251, 16,131,230,230,124,107, 3,255,
+189, 94,230, 86,192, 35, 30,198, 64,169, 15,233,255, 18,200,204,115,121, 3,255,192, 46, 27,208, 64, 86,104,124,192,126, 52, 85,
+197,137, 72,226,168,134, 3,255,191,234,168, 82, 64,149, 62, 87,192, 67, 12,118,217, 5,101,188,188,210, 3,255,192, 16, 10,186,
+ 64, 52,106,249,192,147,253,210,206,182, 62,131,155,198, 3,255,190,240, 33, 93, 64, 71,199,191,192,158, 47,142,245,214, 69, 40,
+148,199, 3,255,187, 71, 46, 19, 64,115,240,194,192,142,166,175,254,240, 82,161,158, 66, 3,255,191,101,194,188, 64,154, 84, 17,
+192, 77,193,240,235, 76,104,214,185,142, 3,255,192,115,246,246, 64, 15, 86,183,192,118,168, 51,172,249, 47,229,171, 45, 3,255,
+192,160, 1,101, 63,184,146, 47,192, 45, 38,153,146,225, 30, 96,196,102, 3,255,192, 85,229,215, 63,218,178,166,192,144, 55,183,
+182, 38, 37,133,158,110, 3,255,192,104,178,151,189,205,107,245,192,147, 60,175,175,178,253,205,156, 91, 3,255,192,136, 81,192,
+191, 4,239, 55,192,127,222, 24,163,130,245,158,168, 35, 3,255,192,164,241, 70, 62,251,218,102,192, 48, 82,143,143,222, 11,210,
+195,110, 3,255, 63,173,230,209, 64, 71,135,231,192,152,234, 27, 29,148, 67, 4,151, 11, 3,255, 64, 67,103,158, 64, 51,206, 82,
+192,132,168, 39, 66,203, 60, 63,164,242, 3,255, 63,100,131,136, 64, 27, 95, 16,192,168,115, 4, 20,122, 53,138,141,143, 3,255,
+ 63,217,154, 77, 63, 78, 69,185,192,177,196,221, 38, 53, 17,236,135, 42, 3,255, 64, 37,195,107, 63, 36,213, 4,192,167, 33, 20,
+ 55,151, 14,194,141,168, 3,255, 64, 94,139,103, 63,250,146,153,192,137,141, 72, 75, 19, 43,156,161,245, 3,255, 64, 21,195,231,
+191,101, 58,236,192,169,178,218, 49,247,236, 31,139,218, 3,255, 64, 48, 32,142,192, 32,140,155,192,145, 1,195, 59, 3,200,178,
+156,204, 3,255, 63,185,155, 70,191, 59,202, 12,192,180, 86,163, 32,149,239, 73,133, 91, 3,255, 62, 43, 97, 29,192, 2,118,144,
+192,175,231,125, 4,106,210,160,136,103, 3,255, 62,196,116, 97,192, 56,176, 10,192,162,239,120, 8,164,194, 20,144, 81, 3,255,
+ 64, 5, 2,185,192, 76,105,217,192,142,173,135, 45,218,187, 79,158, 56, 3,255,191,144,243,163,192, 73, 41,252,192,154, 66,148,
+230,134,188, 73,150,107, 3,255,192, 20,133,147,192,124, 55,234,192,107, 3,176,204,110,170,196,175,164, 3,255,192, 60,186, 42,
+191,189,128,219,192,155, 43, 23,191, 41,222,189,150,199, 3,255,191,172,164, 52,192, 18,240,106,192,167, 58,141,226, 76,204,213,
+142,128, 3,255,192,100,171, 12,191,243, 33,249,192,135,221,106,178,248,214,143,162,143, 3,255,192, 74, 78,195,192, 96,206,241,
+192, 94, 88, 98,188, 4,179, 34,179,129, 3,255,192,177,110, 41, 63,186, 30, 81,191,158,249,105,134,160, 30,165,229, 86, 3,255,
+192,172,138, 45, 64, 17,149,114, 62,200,203,127,137,251, 48,171, 9, 56, 3,255,192,182, 94, 10, 63, 1, 5, 48,191,165, 81, 86,
+131,156, 12, 24,228, 94, 3,255,192,186,224,117,190,247,234, 37, 62,126, 56,147,128,132,246,101, 6, 46, 3,255,192,184, 78,204,
+189, 89,193, 19, 63,141,163,187,130, 22,254,208, 22,241, 3,255,192,174,232,105, 63,224,187,151, 63,153,183,156,136,137, 38,137,
+ 25, 3, 3,255,191, 68,118, 42, 64,176,173,101,191,233,132,114,238, 57,120,142,216,217, 3,255, 62,191,172, 81, 64,186,208, 67,
+190,216,163,195, 7, 75,127,131,247,159, 3,255,191,218, 2,113, 64,171,151,172,191,212, 25,114,219,243,117,116,220, 30, 3,255,
+192, 21,244,251, 64,172, 12, 28, 61,128,151, 13,205,229,117,196, 1,226, 3,255,191,223, 39, 51, 64,177, 94,248, 63, 76,122,104,
+217,155,121, 3, 16, 65, 3,255, 61, 28,208, 72, 64,187, 13, 91, 62,245,215, 64, 0,187,127,168, 9, 66, 3,255, 64,142, 93, 45,
+ 64, 14,137, 70,192, 70,202,147, 96,241, 49,173,188,202, 3,255, 64,173, 23,106, 63,182,131,157,191,225,176,175,118, 7, 32, 20,
+218, 72, 3,255, 64,128,203, 78, 64, 69, 14,124,192, 61, 0, 55, 88,168, 66, 80,191,199, 3,255, 64,133,175,133, 64,121,149, 28,
+191,168,212, 51, 92, 4, 84, 86,227,170, 3,255, 64,149,211, 8, 64, 94,166, 84,191, 29, 24, 68,101,221, 76, 30,241,113, 3,255,
+ 64,175,169, 31, 63,237,176,138,191,103,168, 15,119,152, 40,128,235, 11, 3,255, 64, 57, 78,122,192,120, 12,224,192, 84, 56, 7,
+ 64, 62,171,247,183,239, 3,255, 64, 48, 74, 0,192,155,165,245,191,227, 87,208, 61, 38,150, 68,217,192, 3,255, 64,100,108, 85,
+192, 76, 47,115,192, 88,224,149, 77,102,185, 90,182,131, 3,255, 64,150,191,173,192, 55,233,227,191,254,101,198,102,121,192, 79,
+213, 73, 3,255, 64,148, 97,119,192, 89, 33,200,191,150,225, 24,101, 7,182, 44,229, 20, 3,255, 64, 86,171, 75,192,150, 83, 36,
+191,133, 36, 22, 72,220,153,131,232, 32, 3,255,192, 81,251,116,192,139, 80,115,192, 10,124, 57,185, 81,160, 53,208,254, 3,255,
+192,122,239, 70,192,138,220, 53,190,227, 86,113,171, 68,160,132,246,195, 3,255,192, 28, 50, 14,192,153, 4,245,192, 23, 39,141,
+201,187,151,215,205, 33, 3,255,191,189,123, 34,192,178,168,203,191,130,106,149,222,209,134, 63,234,158, 3,255,191,232,127,176,
+192,178,107,177,189,236,189, 47,216, 65,134,100,252, 66, 3,255,192, 90,168, 53,192,152, 83,169, 62,133,201,227,181, 29,152, 77,
+ 4,136, 3,255,192,150,191,173, 64, 55,233,227, 63,254,101,198,153,135, 63,177, 42,183, 3,255,192,100,108, 85, 64, 76, 47,115,
+ 64, 88,224,149,178,154, 70,166, 73,125, 3,255,192,148, 97,119, 64, 89, 33,200, 63,150,225, 24,154,249, 73,212, 26,236, 3,255,
+192, 86,171, 75, 64,150, 83, 36, 63,133, 36, 22,183, 36,102,125, 23,224, 3,255,192, 48, 74, 0, 64,155,165,245, 63,227, 87,208,
+194,218,105,188, 38, 64, 3,255,192, 57, 78,122, 64,120, 12,224, 64, 84, 56, 7,191,194, 84, 9, 72, 17, 3,255, 63,189,123, 34,
+ 64,178,168,203, 63,130,106,149, 33, 47,121,193, 21, 98, 3,255, 64, 28, 50, 14, 64,153, 4,245, 64, 23, 39,141, 54, 69,104, 41,
+ 50,223, 3,255, 63,232,127,176, 64,178,107,177, 61,236,189, 47, 39,191,121,156, 3,190, 3,255, 64, 90,168, 53, 64,152, 83,169,
+190,133,201,227, 74,227,103,179,251,120, 3,255, 64,122,239, 70, 64,138,220, 53, 62,227, 86,113, 84,188, 95,124, 9, 61, 3,255,
+ 64, 81,251,116, 64,139, 80,115, 64, 10,124, 57, 70,175, 95,203, 47, 2, 3,255, 64,186,224,117, 62,247,234, 37,190,126, 56,147,
+127,124, 9,155,249,210, 3,255, 64,182, 94, 10,191, 1, 5, 48, 63,165, 81, 86,124,100,243,232, 27,162, 3,255, 64,184, 78,204,
+ 61, 89,193, 19,191,141,163,187,125,234, 1, 48,233, 15, 3,255, 64,174,232,105,191,224,187,151,191,153,183,156,119,119,217,119,
+230,253, 3,255, 64,172,138, 45,192, 17,149,114,190,200,203,127,118, 5,207, 85,246,200, 3,255, 64,177,110, 41,191,186, 30, 81,
+ 63,158,249,105,121, 96,225, 91, 26,170, 3,255, 64, 21,244,251,192,172, 12, 28,189,128,151, 13, 50, 27,138, 60,254, 30, 3,255,
+ 63,218, 2,113,192,171,151,172, 63,212, 25,114, 36, 13,138,140, 35,226, 3,255, 63,223, 39, 51,192,177, 94,248,191, 76,122,104,
+ 38,101,134,253,239,191, 3,255,189, 28,208, 72,192,187, 13, 91,190,245,215, 64,255, 69,128, 88,246,190, 3,255,190,191,172, 81,
+192,186,208, 67, 62,216,163,195,248,181,128,125, 8, 97, 3,255, 63, 68,118, 42,192,176,173,101, 63,233,132,114, 17,199,135,114,
+ 39, 39, 3,255,192,133,175,133,192,121,149, 28, 63,168,212, 51,163,252,171,170, 28, 86, 3,255,192,128,203, 78,192, 69, 14,124,
+ 64, 61, 0, 55,167, 88,189,176, 64, 57, 3,255,192,175,169, 31,191,237,176,138, 63,103,168, 15,136,104,215,128, 20,245, 3,255,
+192,149,211, 8,192, 94,166, 84, 63, 29, 24, 68,154, 35,179,226, 14,143, 3,255,192,173, 23,106,191,182,131,157, 63,225,176,175,
+137,249,223,236, 37,184, 3,255,192,142, 93, 45,192, 14,137, 70, 64, 70,202,147,159, 15,206, 83, 67, 54, 3,255,192, 5, 2,185,
+ 64, 76,105,217, 64,142,173,135,210, 38, 68,177, 97,200, 3,255,190,196,116, 97, 64, 56,176, 10, 64,162,239,120,247, 92, 61,236,
+111,175, 3,255,192, 48, 32,142, 64, 32,140,155, 64,145, 1,195,196,253, 55, 78, 99, 52, 3,255,192, 21,195,231, 63,101, 58,236,
+ 64,169,178,218,206, 9, 19,225,116, 38, 3,255,191,185,155, 70, 63, 59,202, 12, 64,180, 86,163,223,107, 16,183,122,165, 3,255,
+190, 43, 97, 29, 64, 2,118,144, 64,175,231,125,251,150, 45, 96,119,153, 3,255, 64, 74, 78,195, 64, 96,206,241, 64, 94, 88, 98,
+ 67,252, 76,222, 76,127, 3,255, 64,100,171, 12, 63,243, 33,249, 64,135,221,106, 77, 8, 41,113, 93,113, 3,255, 64, 20,133,147,
+ 64,124, 55,234, 64,107, 3,176, 51,146, 85, 60, 80, 92, 3,255, 63,144,243,164, 64, 73, 41,252, 64,154, 66,148, 25,122, 67,183,
+105,149, 3,255, 63,172,164, 52, 64, 18,240,106, 64,167, 58,141, 29,180, 51, 43,113,128, 3,255, 64, 60,186, 42, 63,189,128,219,
+ 64,155, 43, 23, 64,215, 33, 67,105, 57, 3,255, 64,160, 1,101,191,184,146, 47, 64, 45, 38,153,109, 31,225,160, 59,154, 3,255,
+ 64,115,246,246,192, 15, 86,183, 64,118,168, 51, 83, 7,208, 27, 84,211, 3,255, 64,164,241, 70,190,251,218,102, 64, 48, 82,143,
+112, 34,244, 46, 60,146, 3,255, 64,136, 81,192, 63, 4,239, 55, 64,127,222, 24, 92,126, 10, 98, 87,221, 3,255, 64,104,178,151,
+ 61,205,107,245, 64,147, 60,175, 80, 78, 2, 51, 99,165, 3,255, 64, 85,229,215,191,218,178,166, 64,144, 55,183, 73,218,218,123,
+ 97,146, 3,255, 63,101,194,188,192,154, 84, 17, 64, 77,193,240, 20,180,151, 42, 70,114, 3,255, 59, 71, 46, 19,192,115,240,194,
+ 64,142,166,175, 1, 16,173, 95, 97,190, 3,255, 63,234,168, 82,192,149, 62, 87, 64, 67, 12,118, 38,251,154, 68, 67, 46, 3,255,
+ 64, 46, 27,208,192, 86,104,124, 64,126, 52, 85, 58,119,183, 30, 87,122, 3,255, 64, 16, 10,186,192, 52,106,249, 64,147,253,210,
+ 49, 74,193,125,100, 58, 3,255, 62,240, 33, 93,192, 71,199,191, 64,158, 47,142, 10, 42,186,216,107, 57, 3,255,192, 94,139,103,
+191,250,146,153, 64,137,141, 72,180,237,212,100, 94, 11, 3,255,192, 37,195,107,191, 36,213, 4, 64,167, 33, 20,200,105,241, 62,
+114, 88, 3,255,192, 67,103,158,192, 51,206, 82, 64,132,168, 39,189, 53,195,193, 91, 14, 3,255,191,173,230,209,192, 71,135,231,
+ 64,152,234, 27,226,108,188,252,104,245, 3,255,191,217,154, 77,191, 78, 69,185, 64,177,196,221,217,203,238, 20,120,214, 3,255,
+191,100,131,136,192, 27, 95, 16, 64,168,115, 4,235,134,202,118,114,113, 3,255,192, 37,220,139, 64,141,135,245,192, 54,173,114,
+199, 45, 96, 95,193,211, 3,255,192, 84,119,204, 64,130, 73, 93,192, 38,107,212,183, 58, 88,223,199,137, 3,255,192, 67, 76,208,
+ 64,111,120, 62,192, 85, 89, 14,189, 80, 81,196,183,140, 3,255,191,238,147, 68, 64,100,230,166,192,136, 9,234,215,216, 78,130,
+163, 59, 3,255,191,109,149, 30, 64,111, 18, 40,192,141,100,171,235, 37, 81,201,159,199, 3,255,191,178,237,144, 64,136,136, 25,
+192,113, 1,121,225,117, 92,189,173, 62, 3,255, 63, 66, 82,214, 64,152,115,128,192, 85, 25,164, 16,241,104, 27,183,126, 3,255,
+189,171,155,119, 64,155, 40,138,192, 83, 96,113,254,128,105,196,183,238, 3,255, 62,194,138, 67, 64,138, 97,177,192,124,158, 75,
+ 8,112, 94,134,170, 29, 3,255,191, 94,106,158, 64, 30,106,167,192,167,240,254,236,229, 53,187,141,105, 3,255,191,229,114, 22,
+ 64, 20, 96,193,192,162,167,253,217, 22, 50, 93,144,244, 3,255,191,162,210, 45, 63,224,211,233,192,174, 67,184,228, 69, 37,245,
+136,244, 3,255,192,152, 61, 37, 64, 14, 9,230,192, 39,179,137,152, 85, 48,183,198,226, 3,255,192,140,187,232, 64, 62, 96, 6,
+192, 30,247,107,160, 7, 65, 68,202, 11, 3,255,192,132,134,116, 64, 40,130, 40,192, 77,207,237,165,139, 57,149,186, 30, 3,255,
+192,129,129, 12, 63,173,129,231,192,128,125,159,167, 62, 29, 15,168,123, 3,255,192,134,112,254, 62,207,146,126,192,130, 19,159,
+164, 15, 9,119,167,117, 3,255,192,149,121,189, 63,111,192,142,192, 90, 95, 76,154, 95, 20,107,180,236, 3,255,192,162, 65, 12,
+191,149, 84, 11,192, 44,202,172,145, 60,230, 47,197, 75, 3,255,192,165,120, 74,190,167, 78, 95,192, 48, 51,139,143, 54,248,140,
+195,244, 3,255,192,150,161, 61,191, 89,221,107,192, 89,113,118,153, 40,237, 79,182, 35, 3,255,192, 66, 56, 52, 62,139, 40,206,
+192,160,116, 21,190, 13, 6, 19,146,121, 3,255,192, 56,120,245, 63,154,213,118,192,158,227, 81,193, 81, 26, 47,147,133, 3,255,
+192, 22,104,220, 63, 40,221,204,192,170,137,115,205, 16, 14, 89,139,117, 3,255, 64, 39,143,145, 64, 94, 49,190,192,124, 27,165,
+ 56,238, 75,252,170, 43, 3,255, 64, 6,168,130, 64,130,132,190,192,105, 96, 12, 45,226, 89, 91,176,173, 3,255, 63,222,169, 76,
+ 64,104,107,205,192,136,142,150, 38, 23, 79,105,163, 33, 3,255, 63,229,207,137, 64, 22, 63, 30,192,161,235,207, 39,198, 50,227,
+145,127, 3,255, 64, 14, 11,239, 63,191,114,175,192,166,208,254, 48,133, 33, 81,142, 87, 3,255, 64, 43,222,239, 64, 11,226,212,
+192,151, 71,227, 58, 33, 47,140,152, 91, 3,255, 64,124,245, 0, 62,187, 32, 27,192,138, 6, 57, 86,138, 7,176,162, 2, 3,255,
+ 64,112, 75, 42, 63,152, 42,228,192,139, 44, 25, 82, 0, 25,159,161, 31, 3,255, 64, 82,218,178, 63, 1,247,178,192,154,129,211,
+ 72, 35, 11, 4,150,217, 3,255, 63,104,203,208, 63,113, 6,146,192,183, 5,108, 19,132, 20,150,131, 49, 3,255, 62,251, 68, 26,
+ 63,228, 38,111,192,178, 48,114, 10,139, 38,158,134,109, 3,255, 61,149, 78,163, 63,137, 25, 65,192,184,102,234, 1, 54, 23, 52,
+130, 34, 3,255, 64, 80,140, 98,191,238,205,169,192,144, 69, 83, 71, 70,215,145,157,173, 3,255, 64,109, 39,177,191,147,213,155,
+192,140,143,238, 81, 57,230,247,160, 77, 3,255, 64, 66,225,100,191,131,191,146,192,157, 18,152, 66,178,233,128,149, 25, 3,255,
+ 63,220, 24,190,191,202,163,163,192,171,244,160, 37, 99,220,199,138,196, 3,255, 63,133,219,227,192, 17, 47,172,192,169,160, 93,
+ 23,126,206,164,140, 68, 3,255, 63,247,202, 46,192, 27,140, 23,192,158,252,116, 41,217,203, 77,147, 32, 3,255, 63, 68,220, 36,
+192,132,143, 24,192,130,105, 20, 16,163,165, 66,167, 72, 3,255, 63,185,255, 60,192,108,244,215,192,138, 7,129, 31,113,175, 11,
+161,251, 3,255, 63, 19, 18,220,192, 98,186,168,192,148,136, 66, 12,155,178,121,154,241, 3,255,187,172,119,131,191,162,209,182,
+192,183, 73,170,255,209,228,144,130,251, 3,255, 63, 40,230,165,191, 24,111,246,192,185,150, 50, 14, 19,243, 18,129,113, 3,255,
+190, 50, 45,123,190,230, 16,213,192,186,240,160,251,231,246,124,128,109, 3,255,191,199, 22,221,192,134,211, 71,192,113,161, 37,
+222, 98,163,255,173,157, 3,255,191, 58,131,171,192,140,178, 57,192,115,174,214,240,105,159,201,173, 11, 3,255,191,112,119,228,
+192,115, 46, 49,192,139,222,186,235,152,172,221,160,217, 3,255,191,254, 75,122,192, 50, 36, 18,192,152, 70, 84,211,253,195, 46,
+152, 87, 3,255,192, 52,239,190,192, 22,186,193,192,145,240,166,194,167,204, 3,156,108, 3,255,192, 39, 23, 51,192, 76,245, 14,
+192,132,248,105,199, 29,186,137,164,200, 3,255,192,140,137,202,192, 33,234, 4,192, 60,117,152,159,215,200,216,192, 6, 3,255,
+192,115,176, 68,192, 68, 49, 85,192, 79,173, 65,172,178,189, 81,185, 81, 3,255,192,128,173,131,192, 14,170, 50,192,105, 71,247,
+168, 30,207, 64,176,189, 3,255,192, 22, 80,230,191,141,155, 50,192,168, 95,108,205, 3,232, 6,141, 19, 3,255,191,194,113, 96,
+191,195,184,166,192,174,160, 31,222,205,222,245,136,227, 3,255,191,213,244,249,191, 52, 33, 10,192,178, 94,248,219,172,241, 3,
+134, 48, 3,255,192,167, 26, 30, 64, 42, 11, 62,190,159,163,199,142, 45, 58, 26,248,236, 3,255,192,157,242, 15, 64, 63, 35,177,
+191,132,230,242,148,115, 65,134,233, 39, 3,255,192,169,163, 58, 64, 14,207,184,191,148, 92, 43,140,122, 48,250,230,193, 3,255,
+192,184, 83,241, 63,117,241, 33,190,248, 69,204,130, 32, 20,245,246, 22, 3,255,192,186,178, 88, 62,226, 33,180, 62,165,211, 69,
+128,153, 10, 65, 6,196, 3,255,192,181,194,100, 63,178, 37,227, 62,191, 51, 65,131,199, 29,217, 7,201, 3,255,192,168, 68,140,
+ 63, 57,100,162, 64, 31, 41, 90,141, 91, 15,195, 54,175, 3,255,192,173,114,185, 63,162, 11,147, 63,237,131,136,137,204, 27,106,
+ 40,187, 3,255,192,178, 82, 90, 62,168, 0,181, 63,231, 64,125,134,136, 7, 78, 39,175, 3,255,192,185, 52,235,191, 83,185,191,
+190,252,176, 39,129,201,237,211,244,241, 3,255,192,182,222, 95,190,161, 32,178,191,165, 92, 48,131, 90,248,208,227,211, 3,255,
+192,179,119, 52,191,147,204,223,191,160,141,116,133,169,230,113,228,103, 3,255, 63, 35, 88,109, 64,182,186,129,191,152, 8,207,
+ 14, 5,124,127,229,202, 3,255, 63, 99, 54,226, 64,174,134,172,191,250, 98, 96, 19,180,118,244,213, 14, 3,255, 61, 60,195,150,
+ 64,177,121, 46,191,245, 6,174, 1, 84,120,249,214, 55, 3,255,191,145,160,228, 64,181, 59,121,191,123,252,246,231, 63,123,214,
+235, 42, 3,255,191,188,166, 29, 64,181,120,167,189,165,224, 4,224, 81,123,253,253,203, 3,255,191, 9,186, 26, 64,186,142,104,
+190,126, 74,128,243,158,127, 69,250, 88, 3,255,191, 19,205,179, 64,175,145, 33, 63,253,151,102,243,125,119,171, 43,167, 3,255,
+190,134,114,163, 64,183, 94, 81, 63,157,210, 73,250, 40,124,240, 27, 49, 3,255,191,151,217,253, 64,178, 89, 90, 63,178,246,210,
+230, 89,121,146, 30,187, 3,255,192, 50,200,107, 64,164, 21, 4,191, 18,252,143,194,229,111,189,243, 58, 3,255,192, 29,140,219,
+ 64,163,216,164,191,187,160,163,202, 2,111,148,224, 27, 3,255,192, 76, 63, 8, 64,152, 92,149,191,157, 6,201,185,254,103,184,
+229, 25, 3,255, 64,167, 31,102, 63,133,113, 18,192, 29,150,122,113,214, 22,149,202, 5, 3,255, 64,157, 48,115, 63, 33,183, 74,
+192, 72,172, 21,107, 50, 13,106,187, 91, 3,255, 64,151, 48,250, 63,186,157,117,192, 74, 37,236,103, 41, 31,126,187, 23, 3,255,
+ 64,148, 31,118, 64, 46, 99,144,192, 21,237, 95,101,101, 59,141,205,115, 3,255, 64,150,177, 40, 64, 73,250,101,191,189,252,104,
+103, 13, 68,113,223, 39, 3,255, 64,164, 67, 59, 64, 19,116,106,191,209,145, 96,111,204, 50,223,219,255, 3,255, 64,168, 99, 9,
+ 64, 32,173,184, 63, 27, 16,129,114,228, 54,189, 13,164, 3,255, 64,174, 1,225, 64, 12,167, 65,190, 38, 1,199,118,149, 48, 17,
+252,195, 3,255, 64,160,156,172, 64, 66,121, 23,188, 53,253,220,109,155, 66, 25, 0, 0, 3,255, 64,106,184,230, 64,133, 83,117,
+191,243, 95, 76, 79,202, 90,251,214, 77, 3,255, 64,101,166,116, 64,111,107, 67,192, 47,233, 69, 78, 23, 81,219,196, 34, 3,255,
+ 64, 68, 20,109, 64,139, 9,202,192, 29,255,124, 66,138, 95, 22,202, 6, 3,255, 64, 12,138, 46,192,156,168,195,192, 23,240, 99,
+ 47,172,149, 54,203,252, 3,255, 63,201,189,110,192,154, 28, 48,192, 60,148,180, 34, 2,150,195,191,147, 3,255, 64, 17, 55, 21,
+192,140, 67,125,192, 75, 8,118, 49, 61,160, 50,186,221, 3,255, 64,100,126, 85,192,114,211,103,192, 43,176,187, 78, 60,172,241,
+198, 2, 3,255, 64,133,112, 29,192,104, 45,168,191,249, 44, 95, 90,154,176, 96,213, 48, 3,255, 64, 95,193,192,192,138, 5,221,
+191,239,219, 42, 76,181,162, 61,214,177, 3,255, 64,134, 21, 28,192,130,231,185, 62,133,210,175, 91,128,166,182, 6, 33, 3,255,
+ 64,115,101,128,192,142,100,106,190,205,174,214, 83, 32,159, 12,247,127, 3,255, 64,142,250,187,192,113,123,178,190,242,120, 90,
+ 97, 99,173,142,245,244, 3,255, 64,149, 83,115,192, 24,118, 25,192, 41, 5, 96,101,195,204, 61,198, 36, 3,255, 64,130, 97,236,
+192, 34,248,181,192, 87,132, 49, 89, 17,200,184,182,144, 3,255, 64,144,103,186,191,234, 9, 91,192, 80,226,150, 98,152,216,121,
+184,152, 3,255,192,136, 74,208,192,121,117,231,191,133,193, 32,162,248,171, 42,232,249, 3,255,192,144, 84, 31,192, 87, 19, 24,
+191,211, 65, 53,157, 74,182,248,219,224, 3,255,192,123, 90, 7,192,121,238,107,191,247,227,115,170, 22,171, 1,213,218, 3,255,
+192, 54,112,161,192,156, 77, 94,191,196,107,207,193,198,149, 23,223, 32, 3,255,192, 22, 41, 24,192,169,197, 1,191, 84, 68,191,
+204, 45,140,105,237,172, 3,255,192, 75,243, 73,192,156, 16, 86,191, 33,150,180,186,216,149, 63,241,194, 3,255,192, 19,246,140,
+192,166, 60,148, 63,182, 70, 11,205,164,142,159, 31,127, 3,255,192, 58, 21, 17,192,160,209,224, 63, 88,100,103,192,202,146, 72,
+ 18,171, 3,255,192, 4,252,151,192,174, 89, 71, 63, 38, 93,215,210,148,137, 55, 14,122, 3,255,191,150,176, 53,192,174,252,238,
+191,226,172, 37,230,114,136,199,217, 20, 3,255,191,214,105,225,192,161,177,211,192, 29,229,160,219,197,145,175,202, 38, 3,255,
+191, 88,213, 62,192,167, 70,193,192, 32,217,212,237,221,141,232,200,230, 3,255,192,130, 97,236, 64, 34,248,181, 64, 87,132, 49,
+166,239, 55, 72, 73,112, 3,255,192,144,103,186, 63,234, 9, 91, 64, 80,226,150,157,104, 39,135, 71,104, 3,255,192,149, 83,115,
+ 64, 24,118, 25, 64, 41, 5, 96,154, 61, 51,195, 57,220, 3,255,192,133,112, 29, 64,104, 45,168, 63,249, 44, 95,165,102, 79,160,
+ 42,208, 3,255,192, 95,193,192, 64,138, 5,221, 63,239,219, 42,179, 75, 93,195, 41, 79, 3,255,192,100,126, 85, 64,114,211,103,
+ 64, 43,176,187,177,196, 83, 15, 57,254, 3,255,191,201,189,110, 64,154, 28, 48, 64, 60,148,180,221,254,105, 61, 64,109, 3,255,
+192, 17, 55, 21, 64,140, 67,125, 64, 75, 8,118,206,195, 95,206, 69, 35, 3,255,192, 12,138, 46, 64,156,168,195, 64, 23,240, 99,
+208, 84,106,202, 52, 4, 3,255,192,115,101,128, 64,142,100,106, 62,205,174,214,172,224, 96,244, 8,129, 3,255,192,142,250,187,
+ 64,113,123,178, 62,242,120, 90,158,157, 82,114, 10, 12, 3,255,192,134, 21, 28, 64,130,231,185,190,133,210,175,164,128, 89, 74,
+249,223, 3,255, 63,214,105,225, 64,161,177,211, 64, 29,229,160, 36, 59,110, 81, 53,218, 3,255, 63, 88,213, 62, 64,167, 70,193,
+ 64, 32,217,212, 18, 35,114, 24, 55, 26, 3,255, 63,150,176, 53, 64,174,252,238, 63,226,172, 37, 25,142,119, 57, 38,236, 3,255,
+ 64, 22, 41, 24, 64,169,197, 1, 63, 84, 68,191, 51,211,115,151, 18, 84, 3,255, 64, 75,243, 73, 64,156, 16, 86, 63, 33,150,180,
+ 69, 40,106,193, 14, 62, 3,255, 64, 54,112,161, 64,156, 77, 94, 63,196,107,208, 62, 58,106,233, 32,224, 3,255, 64,144, 84, 31,
+ 64, 87, 19, 24, 63,211, 65, 53, 98,182, 73, 8, 36, 32, 3,255, 64,123, 90, 7, 64,121,238,107, 63,247,227,115, 85,234, 84,255,
+ 42, 38, 3,255, 64,136, 74,208, 64,121,117,231, 63,133,193, 32, 93, 8, 84,214, 23, 7, 3,255, 64, 58, 21, 17, 64,160,209,224,
+191, 88,100,103, 63, 54,109,184,237, 85, 3,255, 64, 4,252,151, 64,174, 89, 71,191, 38, 93,215, 45,108,118,201,241,134, 3,255,
+ 64, 19,246,140, 64,166, 60,148,191,182, 70, 11, 50, 92,113, 97,224,129, 3,255, 64,182,222, 95, 62,161, 32,178, 63,165, 92, 48,
+124,166, 7, 48, 28, 45, 3,255, 64,179,119, 52, 63,147,204,223, 63,160,141,116,122, 87, 25,143, 27,153, 3,255, 64,185, 52,235,
+ 63, 83,185,191, 62,252,176, 39,126, 55, 18, 45, 11, 15, 3,255, 64,186,178, 88,190,226, 33,180,190,165,211, 69,127,103,245,191,
+249, 60, 3,255, 64,181,194,100,191,178, 37,227,190,191, 51, 65,124, 57,226, 39,248, 55, 3,255, 64,184, 83,241,191,117,241, 33,
+ 62,248, 69,204,125,224,235, 11, 9,234, 3,255, 64,157,242, 15,192, 63, 35,177, 63,132,230,242,107,141,190,122, 22,217, 3,255,
+ 64,169,163, 58,192, 14,207,184, 63,148, 92, 43,115,134,207, 6, 25, 63, 3,255, 64,167, 26, 30,192, 42, 11, 62, 62,159,163,199,
+113,211,197,230, 7, 20, 3,255, 64,173,114,185,191,162, 11,147,191,237,131,136,118, 52,228,150,215, 69, 3,255, 64,178, 82, 90,
+190,168, 0,181,191,231, 64,125,121,120,248,178,216, 81, 3,255, 64,168, 68,140,191, 57,100,162,192, 31, 41, 90,114,165,240, 61,
+201, 81, 3,255, 64, 29,140,219,192,163,216,164, 63,187,160,163, 53,254,144,108, 31,229, 3,255, 64, 76, 63, 8,192,152, 92,149,
+ 63,157, 6,201, 70, 2,152, 72, 26,231, 3,255, 64, 50,200,107,192,164, 21, 4, 63, 18,252,143, 61, 27,144, 67, 12,198, 3,255,
+ 63,188,166, 29,192,181,120,167, 61,165,224, 4, 31,175,132, 3, 2, 53, 3,255, 63, 9,186, 26,192,186,142,104, 62,126, 74,128,
+ 12, 98,128,187, 5,168, 3,255, 63,145,160,228,192,181, 59,121, 63,123,252,246, 24,193,132, 42, 20,214, 3,255,191, 99, 54,226,
+192,174,134,172, 63,250, 98, 96,236, 76,137, 12, 42,242, 3,255,189, 60,195,150,192,177,121, 46, 63,245, 6,174,254,172,135, 7,
+ 41,201, 3,255,191, 35, 88,109,192,182,186,129, 63,152, 8,207,241,251,131,129, 26, 54, 3,255, 62,134,114,163,192,183, 94, 81,
+191,157,210, 73, 5,216,131, 16,228,207, 3,255, 63,151,217,253,192,178, 89, 90,191,178,246,210, 25,167,134,110,225, 69, 3,255,
+ 63, 19,205,179,192,175,145, 33,191,253,151,102, 12,131,136, 85,212, 89, 3,255,192,101,166,116,192,111,107, 67, 64, 47,233, 69,
+177,233,174, 37, 59,222, 3,255,192, 68, 20,109,192,139, 9,202, 64, 29,255,124,189,118,160,234, 53,250, 3,255,192,106,184,230,
+192,133, 83,117, 63,243, 95, 76,176, 54,165, 5, 41,179, 3,255,192,150,177, 40,192, 73,250,101, 63,189,252,104,152,243,187,143,
+ 32,217, 3,255,192,164, 67, 59,192, 19,116,106, 63,209,145, 96,144, 52,205, 33, 36, 1, 3,255,192,148, 31,118,192, 46, 99,144,
+ 64, 21,237, 95,154,155,196,115, 50,141, 3,255,192,157, 48,115,191, 33,183, 74, 64, 72,172, 21,148,206,242,150, 68,165, 3,255,
+192,151, 48,250,191,186,157,117, 64, 74, 37,236,152,215,224,130, 68,233, 3,255,192,167, 31,102,191,133,113, 18, 64, 29,150,122,
+142, 42,233,107, 53,251, 3,255,192,174, 1,225,192, 12,167, 65, 62, 38, 1,199,137,107,207,239, 3, 61, 3,255,192,160,156,172,
+192, 66,121, 23, 60, 53,253,220,146,101,189,231, 0, 0, 3,255,192,168, 99, 9,192, 32,173,184,191, 27, 16,129,141, 28,201, 67,
+242, 92, 3,255,191, 19, 18,220, 64, 98,186,168, 64,148,136, 66,243,101, 77,135,101, 15, 3,255,191, 68,220, 36, 64,132,143, 24,
+ 64,130,105, 20,239, 93, 90,190, 88,184, 3,255,191,185,255, 60, 64,108,244,215, 64,138, 7,129,224,143, 80,245, 94, 5, 3,255,
+191,247,202, 46, 64, 27,140, 23, 64,158,252,116,214, 39, 52,179,108,224, 3,255,191,220, 24,190, 63,202,163,163, 64,171,244,160,
+218,157, 35, 57,117, 60, 3,255,191,133,219,227, 64, 17, 47,172, 64,169,160, 93,232,130, 49, 92,115,188, 3,255, 62, 50, 45,123,
+ 62,230, 16,213, 64,186,240,160, 4, 25, 9,132,127,147, 3,255, 59,172,119,131, 63,162,209,182, 64,183, 73,170, 0, 47, 27,112,
+125, 5, 3,255,191, 40,230,165, 63, 24,111,246, 64,185,150, 50,241,237, 12,238,126,143, 3,255,192, 66,225,100, 63,131,191,146,
+ 64,157, 18,152,189, 78, 22,128,106,231, 3,255,192, 80,140, 98, 63,238,205,169, 64,144, 69, 83,184,186, 40,111, 98, 83, 3,255,
+192,109, 39,177, 63,147,213,154, 64,140,143,239,174,199, 25, 9, 95,179, 3,255, 64,128,173,131, 64, 14,170, 50, 64,105, 71,247,
+ 87,226, 48,192, 79, 67, 3,255, 64,140,137,202, 64, 33,234, 4, 64, 60,117,152, 96, 41, 55, 40, 63,250, 3,255, 64,115,176, 68,
+ 64, 68, 49, 85, 64, 79,173, 65, 83, 78, 66,175, 70,175, 3,255, 64, 39, 23, 51, 64, 76,245, 14, 64,132,248,105, 56,227, 69,119,
+ 91, 56, 3,255, 63,254, 75,122, 64, 50, 36, 17, 64,152, 70, 83, 44, 3, 60,210,103,169, 3,255, 64, 52,239,190, 64, 22,186,193,
+ 64,145,240,166, 61, 89, 51,253, 99,148, 3,255, 63,213,244,249, 63, 52, 33, 10, 64,178, 94,248, 36, 84, 14,253,121,208, 3,255,
+ 64, 22, 80,230, 63,141,155, 50, 64,168, 95,108, 50,253, 23,250,114,237, 3,255, 63,194,113, 96, 63,195,184,166, 64,174,160, 31,
+ 33, 51, 33, 11,119, 29, 3,255, 63,112,119,228, 64,115, 46, 49, 64,139,222,186, 20,104, 83, 35, 95, 40, 3,255, 63,199, 22,221,
+ 64,134,211, 71, 64,113,161, 37, 33,158, 92, 1, 82, 99, 3,255, 63, 58,131,170, 64,140,178, 58, 64,115,174,213, 15,151, 96, 55,
+ 82,245, 3,255, 64,132,134,116,192, 40,130, 40, 64, 77,207,237, 90,117,198,107, 69,226, 3,255, 64,140,187,232,192, 62, 96, 6,
+ 64, 30,247,107, 95,249,190,188, 53,245, 3,255, 64,152, 61, 37,192, 14, 9,230, 64, 39,179,137,103,171,207, 73, 57, 30, 3,255,
+ 64,149,121,189,191,111,192,142, 64, 90, 95, 76,101,161,235,149, 75, 20, 3,255, 64,134,112,254,190,207,146,126, 64,130, 19,159,
+ 91,241,246,137, 88,139, 3,255, 64,129,129, 12,191,173,129,231, 64,128,125,159, 88,194,226,241, 87,133, 3,255, 64, 22,104,220,
+191, 40,221,204, 64,170,137,115, 50,240,241,167,116,139, 3,255, 64, 56,120,245,191,154,213,118, 64,158,227, 81, 62,175,229,209,
+108,123, 3,255, 64, 66, 56, 52,190,139, 40,206, 64,160,116, 21, 65,243,249,237,109,135, 3,255, 64,150,161, 61, 63, 89,221,107,
+ 64, 89,113,118,102,216, 18,177, 73,221, 3,255, 64,165,120, 74, 62,167, 78, 95, 64, 48, 51,139,112,202, 7,116, 60, 12, 3,255,
+ 64,162, 65, 12, 63,149, 84, 11, 64, 44,202,172,110,196, 25,209, 58,181, 3,255,190,194,138, 67,192,138, 97,177, 64,124,158, 75,
+247,144,161,122, 85,227, 3,255,191, 66, 82,214,192,152,115,128, 64, 85, 25,164,239, 15,151,229, 72,130, 3,255, 61,171,155,119,
+192,155, 40,138, 64, 83, 96,113, 1,128,150, 60, 72, 18, 3,255, 63,178,237,144,192,136,136, 25, 64,113, 1,121, 30,139,163, 67,
+ 82,194, 3,255, 63,238,147, 68,192,100,230,166, 64,136, 9,234, 40, 40,177,126, 92,197, 3,255, 63,109,149, 30,192,111, 18, 40,
+ 64,141,100,171, 20,219,174, 55, 96, 57, 3,255, 63,162,210, 45,191,224,211,233, 64,174, 67,184, 27,187,218, 11,119, 12, 3,255,
+ 63, 94,106,158,192, 30,106,167, 64,167,240,254, 19, 27,202, 69,114,151, 3,255, 63,229,114, 22,192, 20, 96,193, 64,162,167,253,
+ 38,234,205,163,111, 12, 3,255, 64, 67, 76,208,192,111,120, 62, 64, 85, 89, 14, 66,176,174, 60, 72,116, 3,255, 64, 37,220,139,
+192,141,135,245, 64, 54,173,114, 56,211,159,161, 62, 45, 3,255, 64, 84,119,204,192,130, 73, 93, 64, 38,107,212, 72,198,167, 33,
+ 56,119, 3,255,192, 82,218,178,191, 1,247,178, 64,154,129,211,183,221,244,252,105, 39, 3,255,192,124,245, 0,190,187, 32, 27,
+ 64,138, 6, 57,169,118,248, 80, 93,254, 3,255,192,112, 75, 42,191,152, 42,228, 64,139, 44, 25,174, 0,230, 97, 94,225, 3,255,
+192, 43,222,239,192, 11,226,212, 64,151, 71,227,197,223,208,116,103,165, 3,255,191,229,207,137,192, 22, 63, 30, 64,161,235,207,
+216, 58,205, 29,110,129, 3,255,192, 14, 11,239,191,191,114,175, 64,166,208,254,207,123,222,175,113,169, 3,255,189,149, 78,163,
+191,137, 25, 65, 64,184,102,234,254,202,232,204,125,222, 3,255,191,104,203,208,191,113, 6,146, 64,183, 5,108,236,124,235,106,
+124,207, 3,255,190,251, 68, 26,191,228, 38,111, 64,178, 48,114,245,117,217, 98,121,147, 3,255,191,222,169, 76,192,104,107,205,
+ 64,136,142,150,217,233,176,151, 92,223, 3,255,192, 39,143,145,192, 94, 49,190, 64,124, 27,165,199, 18,180, 4, 85,213, 3,255,
+192, 6,168,130,192,130,132,190, 64,105, 96, 12,210, 30,166,165, 79, 83, 3,255, 68, 65, 84, 65, 0, 0, 1, 4, 2,236,246,128,
+ 0, 0, 0,242, 0, 0, 0, 5, 0, 0, 0, 3, 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, 8,107,176, 32, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 90, 0, 8,107,176, 32, 0, 0, 0, 53, 0, 0, 7,128,
+ 0, 0, 0, 0, 0, 0, 0,162, 0, 0, 0, 35, 0, 0, 0, 42, 0, 0, 0,162, 0, 0, 0, 35, 0, 0, 0, 12, 0, 0, 0,163,
+ 0, 0, 0, 35, 0, 0, 0, 42, 0, 0, 0,163, 0, 0, 0, 35, 0, 0, 0, 1, 0, 0, 0,164, 0, 0, 0, 35, 0, 0, 0, 43,
+ 0, 0, 0,164, 0, 0, 0, 35, 0, 0, 0, 12, 0, 0, 0,165, 0, 0, 0, 35, 0, 0, 0, 43, 0, 0, 0,165, 0, 0, 0, 35,
+ 0, 0, 0, 0, 0, 0, 0,166, 0, 0, 0, 35, 0, 0, 0, 44, 0, 0, 0,166, 0, 0, 0, 35, 0, 0, 0, 13, 0, 0, 0,167,
+ 0, 0, 0, 35, 0, 0, 0, 44, 0, 0, 0,167, 0, 0, 0, 35, 0, 0, 0, 2, 0, 0, 0,168, 0, 0, 0, 35, 0, 0, 0, 45,
+ 0, 0, 0,168, 0, 0, 0, 35, 0, 0, 0, 13, 0, 0, 0,169, 0, 0, 0, 35, 0, 0, 0, 45, 0, 0, 0,169, 0, 0, 0, 35,
+ 0, 0, 0, 1, 0, 0, 0,170, 0, 0, 0, 35, 0, 0, 0, 46, 0, 0, 0,170, 0, 0, 0, 35, 0, 0, 0, 14, 0, 0, 0,171,
+ 0, 0, 0, 35, 0, 0, 0, 46, 0, 0, 0,171, 0, 0, 0, 35, 0, 0, 0, 2, 0, 0, 0,172, 0, 0, 0, 35, 0, 0, 0, 47,
+ 0, 0, 0,172, 0, 0, 0, 35, 0, 0, 0, 14, 0, 0, 0,173, 0, 0, 0, 35, 0, 0, 0, 47, 0, 0, 0,173, 0, 0, 0, 35,
+ 0, 0, 0, 0, 0, 0, 0,174, 0, 0, 0, 35, 0, 0, 0, 48, 0, 0, 0,174, 0, 0, 0, 35, 0, 0, 0, 15, 0, 0, 0,175,
+ 0, 0, 0, 35, 0, 0, 0, 48, 0, 0, 0,175, 0, 0, 0, 35, 0, 0, 0, 5, 0, 0, 0,176, 0, 0, 0, 35, 0, 0, 0, 49,
+ 0, 0, 0,176, 0, 0, 0, 35, 0, 0, 0, 15, 0, 0, 0,177, 0, 0, 0, 35, 0, 0, 0, 49, 0, 0, 0,177, 0, 0, 0, 35,
+ 0, 0, 0, 1, 0, 0, 0,178, 0, 0, 0, 35, 0, 0, 0, 50, 0, 0, 0,178, 0, 0, 0, 35, 0, 0, 0, 16, 0, 0, 0,179,
+ 0, 0, 0, 35, 0, 0, 0, 50, 0, 0, 0,179, 0, 0, 0, 35, 0, 0, 0, 5, 0, 0, 0,180, 0, 0, 0, 35, 0, 0, 0, 51,
+ 0, 0, 0,180, 0, 0, 0, 35, 0, 0, 0, 16, 0, 0, 0,181, 0, 0, 0, 35, 0, 0, 0, 51, 0, 0, 0,181, 0, 0, 0, 35,
+ 0, 0, 0, 0, 0, 0, 0,182, 0, 0, 0, 35, 0, 0, 0, 52, 0, 0, 0,182, 0, 0, 0, 35, 0, 0, 0, 17, 0, 0, 0,183,
+ 0, 0, 0, 35, 0, 0, 0, 52, 0, 0, 0,183, 0, 0, 0, 35, 0, 0, 0, 3, 0, 0, 0,184, 0, 0, 0, 35, 0, 0, 0, 53,
+ 0, 0, 0,184, 0, 0, 0, 35, 0, 0, 0, 17, 0, 0, 0,185, 0, 0, 0, 35, 0, 0, 0, 53, 0, 0, 0,185, 0, 0, 0, 35,
+ 0, 0, 0, 2, 0, 0, 0,186, 0, 0, 0, 35, 0, 0, 0, 54, 0, 0, 0,186, 0, 0, 0, 35, 0, 0, 0, 18, 0, 0, 0,187,
+ 0, 0, 0, 35, 0, 0, 0, 54, 0, 0, 0,187, 0, 0, 0, 35, 0, 0, 0, 3, 0, 0, 0,188, 0, 0, 0, 35, 0, 0, 0, 55,
+ 0, 0, 0,188, 0, 0, 0, 35, 0, 0, 0, 18, 0, 0, 0,189, 0, 0, 0, 35, 0, 0, 0, 55, 0, 0, 0,189, 0, 0, 0, 35,
+ 0, 0, 0, 0, 0, 0, 0,190, 0, 0, 0, 35, 0, 0, 0, 56, 0, 0, 0,190, 0, 0, 0, 35, 0, 0, 0, 19, 0, 0, 0,191,
+ 0, 0, 0, 35, 0, 0, 0, 56, 0, 0, 0,191, 0, 0, 0, 35, 0, 0, 0, 4, 0, 0, 0,192, 0, 0, 0, 35, 0, 0, 0, 57,
+ 0, 0, 0,192, 0, 0, 0, 35, 0, 0, 0, 19, 0, 0, 0,193, 0, 0, 0, 35, 0, 0, 0, 57, 0, 0, 0,193, 0, 0, 0, 35,
+ 0, 0, 0, 3, 0, 0, 0,194, 0, 0, 0, 35, 0, 0, 0, 58, 0, 0, 0,194, 0, 0, 0, 35, 0, 0, 0, 20, 0, 0, 0,195,
+ 0, 0, 0, 35, 0, 0, 0, 58, 0, 0, 0,195, 0, 0, 0, 35, 0, 0, 0, 4, 0, 0, 0,196, 0, 0, 0, 35, 0, 0, 0, 59,
+ 0, 0, 0,196, 0, 0, 0, 35, 0, 0, 0, 20, 0, 0, 0,197, 0, 0, 0, 35, 0, 0, 0, 59, 0, 0, 0,197, 0, 0, 0, 35,
+ 0, 0, 0, 4, 0, 0, 0,198, 0, 0, 0, 35, 0, 0, 0, 60, 0, 0, 0,198, 0, 0, 0, 35, 0, 0, 0, 21, 0, 0, 0,199,
+ 0, 0, 0, 35, 0, 0, 0, 60, 0, 0, 0,199, 0, 0, 0, 35, 0, 0, 0, 5, 0, 0, 0,200, 0, 0, 0, 35, 0, 0, 0, 61,
+ 0, 0, 0,200, 0, 0, 0, 35, 0, 0, 0, 21, 0, 0, 0,201, 0, 0, 0, 35, 0, 0, 0, 61, 0, 0, 0,201, 0, 0, 0, 35,
+ 0, 0, 0, 5, 0, 0, 0,202, 0, 0, 0, 35, 0, 0, 0, 62, 0, 0, 0,202, 0, 0, 0, 35, 0, 0, 0, 22, 0, 0, 0,203,
+ 0, 0, 0, 35, 0, 0, 0, 62, 0, 0, 0,203, 0, 0, 0, 35, 0, 0, 0, 10, 0, 0, 0,204, 0, 0, 0, 35, 0, 0, 0, 63,
+ 0, 0, 0,204, 0, 0, 0, 35, 0, 0, 0, 22, 0, 0, 0,205, 0, 0, 0, 35, 0, 0, 0, 63, 0, 0, 0,205, 0, 0, 0, 35,
+ 0, 0, 0, 1, 0, 0, 0,206, 0, 0, 0, 35, 0, 0, 0, 64, 0, 0, 0,206, 0, 0, 0, 35, 0, 0, 0, 23, 0, 0, 0,207,
+ 0, 0, 0, 35, 0, 0, 0, 64, 0, 0, 0,207, 0, 0, 0, 35, 0, 0, 0, 10, 0, 0, 0,208, 0, 0, 0, 35, 0, 0, 0, 65,
+ 0, 0, 0,208, 0, 0, 0, 35, 0, 0, 0, 23, 0, 0, 0,209, 0, 0, 0, 35, 0, 0, 0, 65, 0, 0, 0,209, 0, 0, 0, 35,
+ 0, 0, 0, 1, 0, 0, 0,210, 0, 0, 0, 35, 0, 0, 0, 66, 0, 0, 0,210, 0, 0, 0, 35, 0, 0, 0, 24, 0, 0, 0,211,
+ 0, 0, 0, 35, 0, 0, 0, 66, 0, 0, 0,211, 0, 0, 0, 35, 0, 0, 0, 6, 0, 0, 0,212, 0, 0, 0, 35, 0, 0, 0, 67,
+ 0, 0, 0,212, 0, 0, 0, 35, 0, 0, 0, 24, 0, 0, 0,213, 0, 0, 0, 35, 0, 0, 0, 67, 0, 0, 0,213, 0, 0, 0, 35,
+ 0, 0, 0, 2, 0, 0, 0,214, 0, 0, 0, 35, 0, 0, 0, 68, 0, 0, 0,214, 0, 0, 0, 35, 0, 0, 0, 25, 0, 0, 0,215,
+ 0, 0, 0, 35, 0, 0, 0, 68, 0, 0, 0,215, 0, 0, 0, 35, 0, 0, 0, 6, 0, 0, 0,216, 0, 0, 0, 35, 0, 0, 0, 69,
+ 0, 0, 0,216, 0, 0, 0, 35, 0, 0, 0, 25, 0, 0, 0,217, 0, 0, 0, 35, 0, 0, 0, 69, 0, 0, 0,217, 0, 0, 0, 35,
+ 0, 0, 0, 2, 0, 0, 0,218, 0, 0, 0, 35, 0, 0, 0, 70, 0, 0, 0,218, 0, 0, 0, 35, 0, 0, 0, 26, 0, 0, 0,219,
+ 0, 0, 0, 35, 0, 0, 0, 70, 0, 0, 0,219, 0, 0, 0, 35, 0, 0, 0, 7, 0, 0, 0,220, 0, 0, 0, 35, 0, 0, 0, 71,
+ 0, 0, 0,220, 0, 0, 0, 35, 0, 0, 0, 26, 0, 0, 0,221, 0, 0, 0, 35, 0, 0, 0, 71, 0, 0, 0,221, 0, 0, 0, 35,
+ 0, 0, 0, 3, 0, 0, 0,222, 0, 0, 0, 35, 0, 0, 0, 72, 0, 0, 0,222, 0, 0, 0, 35, 0, 0, 0, 27, 0, 0, 0,223,
+ 0, 0, 0, 35, 0, 0, 0, 72, 0, 0, 0,223, 0, 0, 0, 35, 0, 0, 0, 7, 0, 0, 0,224, 0, 0, 0, 35, 0, 0, 0, 73,
+ 0, 0, 0,224, 0, 0, 0, 35, 0, 0, 0, 27, 0, 0, 0,225, 0, 0, 0, 35, 0, 0, 0, 73, 0, 0, 0,225, 0, 0, 0, 35,
+ 0, 0, 0, 3, 0, 0, 0,226, 0, 0, 0, 35, 0, 0, 0, 74, 0, 0, 0,226, 0, 0, 0, 35, 0, 0, 0, 28, 0, 0, 0,227,
+ 0, 0, 0, 35, 0, 0, 0, 74, 0, 0, 0,227, 0, 0, 0, 35, 0, 0, 0, 8, 0, 0, 0,228, 0, 0, 0, 35, 0, 0, 0, 75,
+ 0, 0, 0,228, 0, 0, 0, 35, 0, 0, 0, 28, 0, 0, 0,229, 0, 0, 0, 35, 0, 0, 0, 75, 0, 0, 0,229, 0, 0, 0, 35,
+ 0, 0, 0, 4, 0, 0, 0,230, 0, 0, 0, 35, 0, 0, 0, 76, 0, 0, 0,230, 0, 0, 0, 35, 0, 0, 0, 29, 0, 0, 0,231,
+ 0, 0, 0, 35, 0, 0, 0, 76, 0, 0, 0,231, 0, 0, 0, 35, 0, 0, 0, 8, 0, 0, 0,232, 0, 0, 0, 35, 0, 0, 0, 77,
+ 0, 0, 0,232, 0, 0, 0, 35, 0, 0, 0, 29, 0, 0, 0,233, 0, 0, 0, 35, 0, 0, 0, 77, 0, 0, 0,233, 0, 0, 0, 35,
+ 0, 0, 0, 4, 0, 0, 0,234, 0, 0, 0, 35, 0, 0, 0, 78, 0, 0, 0,234, 0, 0, 0, 35, 0, 0, 0, 30, 0, 0, 0,235,
+ 0, 0, 0, 35, 0, 0, 0, 78, 0, 0, 0,235, 0, 0, 0, 35, 0, 0, 0, 9, 0, 0, 0,236, 0, 0, 0, 35, 0, 0, 0, 79,
+ 0, 0, 0,236, 0, 0, 0, 35, 0, 0, 0, 30, 0, 0, 0,237, 0, 0, 0, 35, 0, 0, 0, 79, 0, 0, 0,237, 0, 0, 0, 35,
+ 0, 0, 0, 5, 0, 0, 0,238, 0, 0, 0, 35, 0, 0, 0, 80, 0, 0, 0,238, 0, 0, 0, 35, 0, 0, 0, 31, 0, 0, 0,239,
+ 0, 0, 0, 35, 0, 0, 0, 80, 0, 0, 0,239, 0, 0, 0, 35, 0, 0, 0, 9, 0, 0, 0,240, 0, 0, 0, 35, 0, 0, 0, 81,
+ 0, 0, 0,240, 0, 0, 0, 35, 0, 0, 0, 31, 0, 0, 0,241, 0, 0, 0, 35, 0, 0, 0, 81, 0, 0, 0,241, 0, 0, 0, 35,
+ 0, 0, 0, 6, 0, 0, 0,242, 0, 0, 0, 35, 0, 0, 0, 82, 0, 0, 0,242, 0, 0, 0, 35, 0, 0, 0, 32, 0, 0, 0,243,
+ 0, 0, 0, 35, 0, 0, 0, 82, 0, 0, 0,243, 0, 0, 0, 35, 0, 0, 0, 10, 0, 0, 0,244, 0, 0, 0, 35, 0, 0, 0, 83,
+ 0, 0, 0,244, 0, 0, 0, 35, 0, 0, 0, 32, 0, 0, 0,245, 0, 0, 0, 35, 0, 0, 0, 83, 0, 0, 0,245, 0, 0, 0, 35,
+ 0, 0, 0, 6, 0, 0, 0,246, 0, 0, 0, 35, 0, 0, 0, 84, 0, 0, 0,246, 0, 0, 0, 35, 0, 0, 0, 33, 0, 0, 0,247,
+ 0, 0, 0, 35, 0, 0, 0, 84, 0, 0, 0,247, 0, 0, 0, 35, 0, 0, 0, 7, 0, 0, 0,248, 0, 0, 0, 35, 0, 0, 0, 85,
+ 0, 0, 0,248, 0, 0, 0, 35, 0, 0, 0, 33, 0, 0, 0,249, 0, 0, 0, 35, 0, 0, 0, 85, 0, 0, 0,249, 0, 0, 0, 35,
+ 0, 0, 0, 7, 0, 0, 0,250, 0, 0, 0, 35, 0, 0, 0, 86, 0, 0, 0,250, 0, 0, 0, 35, 0, 0, 0, 34, 0, 0, 0,251,
+ 0, 0, 0, 35, 0, 0, 0, 86, 0, 0, 0,251, 0, 0, 0, 35, 0, 0, 0, 8, 0, 0, 0,252, 0, 0, 0, 35, 0, 0, 0, 87,
+ 0, 0, 0,252, 0, 0, 0, 35, 0, 0, 0, 34, 0, 0, 0,253, 0, 0, 0, 35, 0, 0, 0, 87, 0, 0, 0,253, 0, 0, 0, 35,
+ 0, 0, 0, 8, 0, 0, 0,254, 0, 0, 0, 35, 0, 0, 0, 88, 0, 0, 0,254, 0, 0, 0, 35, 0, 0, 0, 35, 0, 0, 0,255,
+ 0, 0, 0, 35, 0, 0, 0, 88, 0, 0, 0,255, 0, 0, 0, 35, 0, 0, 0, 9, 0, 0, 1, 0, 0, 0, 0, 35, 0, 0, 0, 89,
+ 0, 0, 1, 0, 0, 0, 0, 35, 0, 0, 0, 35, 0, 0, 1, 1, 0, 0, 0, 35, 0, 0, 0, 89, 0, 0, 1, 1, 0, 0, 0, 35,
+ 0, 0, 0, 9, 0, 0, 1, 2, 0, 0, 0, 35, 0, 0, 0, 90, 0, 0, 1, 2, 0, 0, 0, 35, 0, 0, 0, 36, 0, 0, 1, 3,
+ 0, 0, 0, 35, 0, 0, 0, 90, 0, 0, 1, 3, 0, 0, 0, 35, 0, 0, 0, 10, 0, 0, 1, 4, 0, 0, 0, 35, 0, 0, 0, 91,
+ 0, 0, 1, 4, 0, 0, 0, 35, 0, 0, 0, 36, 0, 0, 1, 5, 0, 0, 0, 35, 0, 0, 0, 91, 0, 0, 1, 5, 0, 0, 0, 35,
+ 0, 0, 0, 10, 0, 0, 1, 6, 0, 0, 0, 35, 0, 0, 0, 92, 0, 0, 1, 6, 0, 0, 0, 35, 0, 0, 0, 37, 0, 0, 1, 7,
+ 0, 0, 0, 35, 0, 0, 0, 92, 0, 0, 1, 7, 0, 0, 0, 35, 0, 0, 0, 11, 0, 0, 1, 8, 0, 0, 0, 35, 0, 0, 0, 93,
+ 0, 0, 1, 8, 0, 0, 0, 35, 0, 0, 0, 37, 0, 0, 1, 9, 0, 0, 0, 35, 0, 0, 0, 93, 0, 0, 1, 9, 0, 0, 0, 35,
+ 0, 0, 0, 6, 0, 0, 1, 10, 0, 0, 0, 35, 0, 0, 0, 94, 0, 0, 1, 10, 0, 0, 0, 35, 0, 0, 0, 38, 0, 0, 1, 11,
+ 0, 0, 0, 35, 0, 0, 0, 94, 0, 0, 1, 11, 0, 0, 0, 35, 0, 0, 0, 11, 0, 0, 1, 12, 0, 0, 0, 35, 0, 0, 0, 95,
+ 0, 0, 1, 12, 0, 0, 0, 35, 0, 0, 0, 38, 0, 0, 1, 13, 0, 0, 0, 35, 0, 0, 0, 95, 0, 0, 1, 13, 0, 0, 0, 35,
+ 0, 0, 0, 7, 0, 0, 1, 14, 0, 0, 0, 35, 0, 0, 0, 96, 0, 0, 1, 14, 0, 0, 0, 35, 0, 0, 0, 39, 0, 0, 1, 15,
+ 0, 0, 0, 35, 0, 0, 0, 96, 0, 0, 1, 15, 0, 0, 0, 35, 0, 0, 0, 11, 0, 0, 1, 16, 0, 0, 0, 35, 0, 0, 0, 97,
+ 0, 0, 1, 16, 0, 0, 0, 35, 0, 0, 0, 39, 0, 0, 1, 17, 0, 0, 0, 35, 0, 0, 0, 97, 0, 0, 1, 17, 0, 0, 0, 35,
+ 0, 0, 0, 8, 0, 0, 1, 18, 0, 0, 0, 35, 0, 0, 0, 98, 0, 0, 1, 18, 0, 0, 0, 35, 0, 0, 0, 40, 0, 0, 1, 19,
+ 0, 0, 0, 35, 0, 0, 0, 98, 0, 0, 1, 19, 0, 0, 0, 35, 0, 0, 0, 11, 0, 0, 1, 20, 0, 0, 0, 35, 0, 0, 0, 99,
+ 0, 0, 1, 20, 0, 0, 0, 35, 0, 0, 0, 40, 0, 0, 1, 21, 0, 0, 0, 35, 0, 0, 0, 99, 0, 0, 1, 21, 0, 0, 0, 35,
+ 0, 0, 0, 9, 0, 0, 1, 22, 0, 0, 0, 35, 0, 0, 0,100, 0, 0, 1, 22, 0, 0, 0, 35, 0, 0, 0, 41, 0, 0, 1, 23,
+ 0, 0, 0, 35, 0, 0, 0,100, 0, 0, 1, 23, 0, 0, 0, 35, 0, 0, 0, 11, 0, 0, 1, 24, 0, 0, 0, 35, 0, 0, 0,101,
+ 0, 0, 1, 24, 0, 0, 0, 35, 0, 0, 0, 41, 0, 0, 1, 25, 0, 0, 0, 35, 0, 0, 0,101, 0, 0, 1, 25, 0, 0, 0, 35,
+ 0, 0, 0, 12, 0, 0, 1, 26, 0, 0, 0, 35, 0, 0, 0,102, 0, 0, 1, 26, 0, 0, 0, 35, 0, 0, 0, 14, 0, 0, 1, 27,
+ 0, 0, 0, 35, 0, 0, 0,102, 0, 0, 1, 27, 0, 0, 0, 35, 0, 0, 0, 12, 0, 0, 1, 28, 0, 0, 0, 35, 0, 0, 0,103,
+ 0, 0, 1, 28, 0, 0, 0, 35, 0, 0, 0, 13, 0, 0, 1, 29, 0, 0, 0, 35, 0, 0, 0,103, 0, 0, 1, 29, 0, 0, 0, 35,
+ 0, 0, 0, 13, 0, 0, 1, 30, 0, 0, 0, 35, 0, 0, 0,104, 0, 0, 1, 30, 0, 0, 0, 35, 0, 0, 0, 14, 0, 0, 1, 31,
+ 0, 0, 0, 35, 0, 0, 0,104, 0, 0, 1, 31, 0, 0, 0, 35, 0, 0, 0, 12, 0, 0, 1, 32, 0, 0, 0, 35, 0, 0, 0,105,
+ 0, 0, 1, 32, 0, 0, 0, 35, 0, 0, 0, 16, 0, 0, 1, 33, 0, 0, 0, 35, 0, 0, 0,105, 0, 0, 1, 33, 0, 0, 0, 35,
+ 0, 0, 0, 12, 0, 0, 1, 34, 0, 0, 0, 35, 0, 0, 0,106, 0, 0, 1, 34, 0, 0, 0, 35, 0, 0, 0, 15, 0, 0, 1, 35,
+ 0, 0, 0, 35, 0, 0, 0,106, 0, 0, 1, 35, 0, 0, 0, 35, 0, 0, 0, 15, 0, 0, 1, 36, 0, 0, 0, 35, 0, 0, 0,107,
+ 0, 0, 1, 36, 0, 0, 0, 35, 0, 0, 0, 16, 0, 0, 1, 37, 0, 0, 0, 35, 0, 0, 0,107, 0, 0, 1, 37, 0, 0, 0, 35,
+ 0, 0, 0, 13, 0, 0, 1, 38, 0, 0, 0, 35, 0, 0, 0,108, 0, 0, 1, 38, 0, 0, 0, 35, 0, 0, 0, 18, 0, 0, 1, 39,
+ 0, 0, 0, 35, 0, 0, 0,108, 0, 0, 1, 39, 0, 0, 0, 35, 0, 0, 0, 13, 0, 0, 1, 40, 0, 0, 0, 35, 0, 0, 0,109,
+ 0, 0, 1, 40, 0, 0, 0, 35, 0, 0, 0, 17, 0, 0, 1, 41, 0, 0, 0, 35, 0, 0, 0,109, 0, 0, 1, 41, 0, 0, 0, 35,
+ 0, 0, 0, 17, 0, 0, 1, 42, 0, 0, 0, 35, 0, 0, 0,110, 0, 0, 1, 42, 0, 0, 0, 35, 0, 0, 0, 18, 0, 0, 1, 43,
+ 0, 0, 0, 35, 0, 0, 0,110, 0, 0, 1, 43, 0, 0, 0, 35, 0, 0, 0, 17, 0, 0, 1, 44, 0, 0, 0, 35, 0, 0, 0,111,
+ 0, 0, 1, 44, 0, 0, 0, 35, 0, 0, 0, 20, 0, 0, 1, 45, 0, 0, 0, 35, 0, 0, 0,111, 0, 0, 1, 45, 0, 0, 0, 35,
+ 0, 0, 0, 17, 0, 0, 1, 46, 0, 0, 0, 35, 0, 0, 0,112, 0, 0, 1, 46, 0, 0, 0, 35, 0, 0, 0, 19, 0, 0, 1, 47,
+ 0, 0, 0, 35, 0, 0, 0,112, 0, 0, 1, 47, 0, 0, 0, 35, 0, 0, 0, 19, 0, 0, 1, 48, 0, 0, 0, 35, 0, 0, 0,113,
+ 0, 0, 1, 48, 0, 0, 0, 35, 0, 0, 0, 20, 0, 0, 1, 49, 0, 0, 0, 35, 0, 0, 0,113, 0, 0, 1, 49, 0, 0, 0, 35,
+ 0, 0, 0, 19, 0, 0, 1, 50, 0, 0, 0, 35, 0, 0, 0,114, 0, 0, 1, 50, 0, 0, 0, 35, 0, 0, 0, 21, 0, 0, 1, 51,
+ 0, 0, 0, 35, 0, 0, 0,114, 0, 0, 1, 51, 0, 0, 0, 35, 0, 0, 0, 15, 0, 0, 1, 52, 0, 0, 0, 35, 0, 0, 0,115,
+ 0, 0, 1, 52, 0, 0, 0, 35, 0, 0, 0, 19, 0, 0, 1, 53, 0, 0, 0, 35, 0, 0, 0,115, 0, 0, 1, 53, 0, 0, 0, 35,
+ 0, 0, 0, 15, 0, 0, 1, 54, 0, 0, 0, 35, 0, 0, 0,116, 0, 0, 1, 54, 0, 0, 0, 35, 0, 0, 0, 21, 0, 0, 1, 55,
+ 0, 0, 0, 35, 0, 0, 0,116, 0, 0, 1, 55, 0, 0, 0, 35, 0, 0, 0, 16, 0, 0, 1, 56, 0, 0, 0, 35, 0, 0, 0,117,
+ 0, 0, 1, 56, 0, 0, 0, 35, 0, 0, 0, 23, 0, 0, 1, 57, 0, 0, 0, 35, 0, 0, 0,117, 0, 0, 1, 57, 0, 0, 0, 35,
+ 0, 0, 0, 16, 0, 0, 1, 58, 0, 0, 0, 35, 0, 0, 0,118, 0, 0, 1, 58, 0, 0, 0, 35, 0, 0, 0, 22, 0, 0, 1, 59,
+ 0, 0, 0, 35, 0, 0, 0,118, 0, 0, 1, 59, 0, 0, 0, 35, 0, 0, 0, 22, 0, 0, 1, 60, 0, 0, 0, 35, 0, 0, 0,119,
+ 0, 0, 1, 60, 0, 0, 0, 35, 0, 0, 0, 23, 0, 0, 1, 61, 0, 0, 0, 35, 0, 0, 0,119, 0, 0, 1, 61, 0, 0, 0, 35,
+ 0, 0, 0, 14, 0, 0, 1, 62, 0, 0, 0, 35, 0, 0, 0,120, 0, 0, 1, 62, 0, 0, 0, 35, 0, 0, 0, 25, 0, 0, 1, 63,
+ 0, 0, 0, 35, 0, 0, 0,120, 0, 0, 1, 63, 0, 0, 0, 35, 0, 0, 0, 14, 0, 0, 1, 64, 0, 0, 0, 35, 0, 0, 0,121,
+ 0, 0, 1, 64, 0, 0, 0, 35, 0, 0, 0, 24, 0, 0, 1, 65, 0, 0, 0, 35, 0, 0, 0,121, 0, 0, 1, 65, 0, 0, 0, 35,
+ 0, 0, 0, 24, 0, 0, 1, 66, 0, 0, 0, 35, 0, 0, 0,122, 0, 0, 1, 66, 0, 0, 0, 35, 0, 0, 0, 25, 0, 0, 1, 67,
+ 0, 0, 0, 35, 0, 0, 0,122, 0, 0, 1, 67, 0, 0, 0, 35, 0, 0, 0, 18, 0, 0, 1, 68, 0, 0, 0, 35, 0, 0, 0,123,
+ 0, 0, 1, 68, 0, 0, 0, 35, 0, 0, 0, 27, 0, 0, 1, 69, 0, 0, 0, 35, 0, 0, 0,123, 0, 0, 1, 69, 0, 0, 0, 35,
+ 0, 0, 0, 18, 0, 0, 1, 70, 0, 0, 0, 35, 0, 0, 0,124, 0, 0, 1, 70, 0, 0, 0, 35, 0, 0, 0, 26, 0, 0, 1, 71,
+ 0, 0, 0, 35, 0, 0, 0,124, 0, 0, 1, 71, 0, 0, 0, 35, 0, 0, 0, 26, 0, 0, 1, 72, 0, 0, 0, 35, 0, 0, 0,125,
+ 0, 0, 1, 72, 0, 0, 0, 35, 0, 0, 0, 27, 0, 0, 1, 73, 0, 0, 0, 35, 0, 0, 0,125, 0, 0, 1, 73, 0, 0, 0, 35,
+ 0, 0, 0, 20, 0, 0, 1, 74, 0, 0, 0, 35, 0, 0, 0,126, 0, 0, 1, 74, 0, 0, 0, 35, 0, 0, 0, 29, 0, 0, 1, 75,
+ 0, 0, 0, 35, 0, 0, 0,126, 0, 0, 1, 75, 0, 0, 0, 35, 0, 0, 0, 20, 0, 0, 1, 76, 0, 0, 0, 35, 0, 0, 0,127,
+ 0, 0, 1, 76, 0, 0, 0, 35, 0, 0, 0, 28, 0, 0, 1, 77, 0, 0, 0, 35, 0, 0, 0,127, 0, 0, 1, 77, 0, 0, 0, 35,
+ 0, 0, 0, 28, 0, 0, 1, 78, 0, 0, 0, 35, 0, 0, 0,128, 0, 0, 1, 78, 0, 0, 0, 35, 0, 0, 0, 29, 0, 0, 1, 79,
+ 0, 0, 0, 35, 0, 0, 0,128, 0, 0, 1, 79, 0, 0, 0, 35, 0, 0, 0, 21, 0, 0, 1, 80, 0, 0, 0, 35, 0, 0, 0,129,
+ 0, 0, 1, 80, 0, 0, 0, 35, 0, 0, 0, 31, 0, 0, 1, 81, 0, 0, 0, 35, 0, 0, 0,129, 0, 0, 1, 81, 0, 0, 0, 35,
+ 0, 0, 0, 21, 0, 0, 1, 82, 0, 0, 0, 35, 0, 0, 0,130, 0, 0, 1, 82, 0, 0, 0, 35, 0, 0, 0, 30, 0, 0, 1, 83,
+ 0, 0, 0, 35, 0, 0, 0,130, 0, 0, 1, 83, 0, 0, 0, 35, 0, 0, 0, 30, 0, 0, 1, 84, 0, 0, 0, 35, 0, 0, 0,131,
+ 0, 0, 1, 84, 0, 0, 0, 35, 0, 0, 0, 31, 0, 0, 1, 85, 0, 0, 0, 35, 0, 0, 0,131, 0, 0, 1, 85, 0, 0, 0, 35,
+ 0, 0, 0, 23, 0, 0, 1, 86, 0, 0, 0, 35, 0, 0, 0,132, 0, 0, 1, 86, 0, 0, 0, 35, 0, 0, 0, 32, 0, 0, 1, 87,
+ 0, 0, 0, 35, 0, 0, 0,132, 0, 0, 1, 87, 0, 0, 0, 35, 0, 0, 0, 23, 0, 0, 1, 88, 0, 0, 0, 35, 0, 0, 0,133,
+ 0, 0, 1, 88, 0, 0, 0, 35, 0, 0, 0, 24, 0, 0, 1, 89, 0, 0, 0, 35, 0, 0, 0,133, 0, 0, 1, 89, 0, 0, 0, 35,
+ 0, 0, 0, 24, 0, 0, 1, 90, 0, 0, 0, 35, 0, 0, 0,134, 0, 0, 1, 90, 0, 0, 0, 35, 0, 0, 0, 32, 0, 0, 1, 91,
+ 0, 0, 0, 35, 0, 0, 0,134, 0, 0, 1, 91, 0, 0, 0, 35, 0, 0, 0, 25, 0, 0, 1, 92, 0, 0, 0, 35, 0, 0, 0,135,
+ 0, 0, 1, 92, 0, 0, 0, 35, 0, 0, 0, 33, 0, 0, 1, 93, 0, 0, 0, 35, 0, 0, 0,135, 0, 0, 1, 93, 0, 0, 0, 35,
+ 0, 0, 0, 25, 0, 0, 1, 94, 0, 0, 0, 35, 0, 0, 0,136, 0, 0, 1, 94, 0, 0, 0, 35, 0, 0, 0, 26, 0, 0, 1, 95,
+ 0, 0, 0, 35, 0, 0, 0,136, 0, 0, 1, 95, 0, 0, 0, 35, 0, 0, 0, 26, 0, 0, 1, 96, 0, 0, 0, 35, 0, 0, 0,137,
+ 0, 0, 1, 96, 0, 0, 0, 35, 0, 0, 0, 33, 0, 0, 1, 97, 0, 0, 0, 35, 0, 0, 0,137, 0, 0, 1, 97, 0, 0, 0, 35,
+ 0, 0, 0, 27, 0, 0, 1, 98, 0, 0, 0, 35, 0, 0, 0,138, 0, 0, 1, 98, 0, 0, 0, 35, 0, 0, 0, 34, 0, 0, 1, 99,
+ 0, 0, 0, 35, 0, 0, 0,138, 0, 0, 1, 99, 0, 0, 0, 35, 0, 0, 0, 27, 0, 0, 1,100, 0, 0, 0, 35, 0, 0, 0,139,
+ 0, 0, 1,100, 0, 0, 0, 35, 0, 0, 0, 28, 0, 0, 1,101, 0, 0, 0, 35, 0, 0, 0,139, 0, 0, 1,101, 0, 0, 0, 35,
+ 0, 0, 0, 28, 0, 0, 1,102, 0, 0, 0, 35, 0, 0, 0,140, 0, 0, 1,102, 0, 0, 0, 35, 0, 0, 0, 34, 0, 0, 1,103,
+ 0, 0, 0, 35, 0, 0, 0,140, 0, 0, 1,103, 0, 0, 0, 35, 0, 0, 0, 29, 0, 0, 1,104, 0, 0, 0, 35, 0, 0, 0,141,
+ 0, 0, 1,104, 0, 0, 0, 35, 0, 0, 0, 35, 0, 0, 1,105, 0, 0, 0, 35, 0, 0, 0,141, 0, 0, 1,105, 0, 0, 0, 35,
+ 0, 0, 0, 29, 0, 0, 1,106, 0, 0, 0, 35, 0, 0, 0,142, 0, 0, 1,106, 0, 0, 0, 35, 0, 0, 0, 30, 0, 0, 1,107,
+ 0, 0, 0, 35, 0, 0, 0,142, 0, 0, 1,107, 0, 0, 0, 35, 0, 0, 0, 30, 0, 0, 1,108, 0, 0, 0, 35, 0, 0, 0,143,
+ 0, 0, 1,108, 0, 0, 0, 35, 0, 0, 0, 35, 0, 0, 1,109, 0, 0, 0, 35, 0, 0, 0,143, 0, 0, 1,109, 0, 0, 0, 35,
+ 0, 0, 0, 31, 0, 0, 1,110, 0, 0, 0, 35, 0, 0, 0,144, 0, 0, 1,110, 0, 0, 0, 35, 0, 0, 0, 36, 0, 0, 1,111,
+ 0, 0, 0, 35, 0, 0, 0,144, 0, 0, 1,111, 0, 0, 0, 35, 0, 0, 0, 22, 0, 0, 1,112, 0, 0, 0, 35, 0, 0, 0,145,
+ 0, 0, 1,112, 0, 0, 0, 35, 0, 0, 0, 31, 0, 0, 1,113, 0, 0, 0, 35, 0, 0, 0,145, 0, 0, 1,113, 0, 0, 0, 35,
+ 0, 0, 0, 22, 0, 0, 1,114, 0, 0, 0, 35, 0, 0, 0,146, 0, 0, 1,114, 0, 0, 0, 35, 0, 0, 0, 36, 0, 0, 1,115,
+ 0, 0, 0, 35, 0, 0, 0,146, 0, 0, 1,115, 0, 0, 0, 35, 0, 0, 0, 32, 0, 0, 1,116, 0, 0, 0, 35, 0, 0, 0,147,
+ 0, 0, 1,116, 0, 0, 0, 35, 0, 0, 0, 38, 0, 0, 1,117, 0, 0, 0, 35, 0, 0, 0,147, 0, 0, 1,117, 0, 0, 0, 35,
+ 0, 0, 0, 32, 0, 0, 1,118, 0, 0, 0, 35, 0, 0, 0,148, 0, 0, 1,118, 0, 0, 0, 35, 0, 0, 0, 37, 0, 0, 1,119,
+ 0, 0, 0, 35, 0, 0, 0,148, 0, 0, 1,119, 0, 0, 0, 35, 0, 0, 0, 37, 0, 0, 1,120, 0, 0, 0, 35, 0, 0, 0,149,
+ 0, 0, 1,120, 0, 0, 0, 35, 0, 0, 0, 38, 0, 0, 1,121, 0, 0, 0, 35, 0, 0, 0,149, 0, 0, 1,121, 0, 0, 0, 35,
+ 0, 0, 0, 33, 0, 0, 1,122, 0, 0, 0, 35, 0, 0, 0,150, 0, 0, 1,122, 0, 0, 0, 35, 0, 0, 0, 39, 0, 0, 1,123,
+ 0, 0, 0, 35, 0, 0, 0,150, 0, 0, 1,123, 0, 0, 0, 35, 0, 0, 0, 33, 0, 0, 1,124, 0, 0, 0, 35, 0, 0, 0,151,
+ 0, 0, 1,124, 0, 0, 0, 35, 0, 0, 0, 38, 0, 0, 1,125, 0, 0, 0, 35, 0, 0, 0,151, 0, 0, 1,125, 0, 0, 0, 35,
+ 0, 0, 0, 38, 0, 0, 1,126, 0, 0, 0, 35, 0, 0, 0,152, 0, 0, 1,126, 0, 0, 0, 35, 0, 0, 0, 39, 0, 0, 1,127,
+ 0, 0, 0, 35, 0, 0, 0,152, 0, 0, 1,127, 0, 0, 0, 35, 0, 0, 0, 34, 0, 0, 1,128, 0, 0, 0, 35, 0, 0, 0,153,
+ 0, 0, 1,128, 0, 0, 0, 35, 0, 0, 0, 40, 0, 0, 1,129, 0, 0, 0, 35, 0, 0, 0,153, 0, 0, 1,129, 0, 0, 0, 35,
+ 0, 0, 0, 34, 0, 0, 1,130, 0, 0, 0, 35, 0, 0, 0,154, 0, 0, 1,130, 0, 0, 0, 35, 0, 0, 0, 39, 0, 0, 1,131,
+ 0, 0, 0, 35, 0, 0, 0,154, 0, 0, 1,131, 0, 0, 0, 35, 0, 0, 0, 39, 0, 0, 1,132, 0, 0, 0, 35, 0, 0, 0,155,
+ 0, 0, 1,132, 0, 0, 0, 35, 0, 0, 0, 40, 0, 0, 1,133, 0, 0, 0, 35, 0, 0, 0,155, 0, 0, 1,133, 0, 0, 0, 35,
+ 0, 0, 0, 35, 0, 0, 1,134, 0, 0, 0, 35, 0, 0, 0,156, 0, 0, 1,134, 0, 0, 0, 35, 0, 0, 0, 41, 0, 0, 1,135,
+ 0, 0, 0, 35, 0, 0, 0,156, 0, 0, 1,135, 0, 0, 0, 35, 0, 0, 0, 35, 0, 0, 1,136, 0, 0, 0, 35, 0, 0, 0,157,
+ 0, 0, 1,136, 0, 0, 0, 35, 0, 0, 0, 40, 0, 0, 1,137, 0, 0, 0, 35, 0, 0, 0,157, 0, 0, 1,137, 0, 0, 0, 35,
+ 0, 0, 0, 40, 0, 0, 1,138, 0, 0, 0, 35, 0, 0, 0,158, 0, 0, 1,138, 0, 0, 0, 35, 0, 0, 0, 41, 0, 0, 1,139,
+ 0, 0, 0, 35, 0, 0, 0,158, 0, 0, 1,139, 0, 0, 0, 35, 0, 0, 0, 36, 0, 0, 1,140, 0, 0, 0, 35, 0, 0, 0,159,
+ 0, 0, 1,140, 0, 0, 0, 35, 0, 0, 0, 37, 0, 0, 1,141, 0, 0, 0, 35, 0, 0, 0,159, 0, 0, 1,141, 0, 0, 0, 35,
+ 0, 0, 0, 36, 0, 0, 1,142, 0, 0, 0, 35, 0, 0, 0,160, 0, 0, 1,142, 0, 0, 0, 35, 0, 0, 0, 41, 0, 0, 1,143,
+ 0, 0, 0, 35, 0, 0, 0,160, 0, 0, 1,143, 0, 0, 0, 35, 0, 0, 0, 37, 0, 0, 1,144, 0, 0, 0, 35, 0, 0, 0,161,
+ 0, 0, 1,144, 0, 0, 0, 35, 0, 0, 0, 41, 0, 0, 1,145, 0, 0, 0, 35, 0, 0, 0,161, 0, 0, 1,145, 0, 0, 0, 35,
+ 0, 0, 0, 46, 0, 0, 1,146, 0, 0, 0, 35, 0, 0, 0,102, 0, 0, 1,146, 0, 0, 0, 35, 0, 0, 0, 43, 0, 0, 1,147,
+ 0, 0, 0, 33, 0, 0, 0, 46, 0, 0, 1,147, 0, 0, 0, 33, 0, 0, 0, 43, 0, 0, 1,148, 0, 0, 0, 35, 0, 0, 0,102,
+ 0, 0, 1,148, 0, 0, 0, 35, 0, 0, 0,102, 0, 0, 1,149, 0, 0, 0, 35, 0, 0, 0,103, 0, 0, 1,149, 0, 0, 0, 35,
+ 0, 0, 0,103, 0, 0, 1,150, 0, 0, 0, 35, 0, 0, 0,104, 0, 0, 1,150, 0, 0, 0, 35, 0, 0, 0,102, 0, 0, 1,151,
+ 0, 0, 0, 35, 0, 0, 0,104, 0, 0, 1,151, 0, 0, 0, 35, 0, 0, 0, 45, 0, 0, 1,152, 0, 0, 0, 33, 0, 0, 0, 47,
+ 0, 0, 1,152, 0, 0, 0, 33, 0, 0, 0, 47, 0, 0, 1,153, 0, 0, 0, 35, 0, 0, 0,104, 0, 0, 1,153, 0, 0, 0, 35,
+ 0, 0, 0, 45, 0, 0, 1,154, 0, 0, 0, 35, 0, 0, 0,104, 0, 0, 1,154, 0, 0, 0, 35, 0, 0, 0, 44, 0, 0, 1,155,
+ 0, 0, 0, 35, 0, 0, 0,103, 0, 0, 1,155, 0, 0, 0, 35, 0, 0, 0, 42, 0, 0, 1,156, 0, 0, 0, 35, 0, 0, 0,103,
+ 0, 0, 1,156, 0, 0, 0, 35, 0, 0, 0, 42, 0, 0, 1,157, 0, 0, 0, 33, 0, 0, 0, 44, 0, 0, 1,157, 0, 0, 0, 33,
+ 0, 0, 0, 50, 0, 0, 1,158, 0, 0, 0, 35, 0, 0, 0,105, 0, 0, 1,158, 0, 0, 0, 35, 0, 0, 0, 43, 0, 0, 1,159,
+ 0, 0, 0, 33, 0, 0, 0, 50, 0, 0, 1,159, 0, 0, 0, 33, 0, 0, 0, 43, 0, 0, 1,160, 0, 0, 0, 35, 0, 0, 0,105,
+ 0, 0, 1,160, 0, 0, 0, 35, 0, 0, 0,105, 0, 0, 1,161, 0, 0, 0, 35, 0, 0, 0,106, 0, 0, 1,161, 0, 0, 0, 35,
+ 0, 0, 0,106, 0, 0, 1,162, 0, 0, 0, 35, 0, 0, 0,107, 0, 0, 1,162, 0, 0, 0, 35, 0, 0, 0,105, 0, 0, 1,163,
+ 0, 0, 0, 35, 0, 0, 0,107, 0, 0, 1,163, 0, 0, 0, 35, 0, 0, 0, 49, 0, 0, 1,164, 0, 0, 0, 33, 0, 0, 0, 51,
+ 0, 0, 1,164, 0, 0, 0, 33, 0, 0, 0, 51, 0, 0, 1,165, 0, 0, 0, 35, 0, 0, 0,107, 0, 0, 1,165, 0, 0, 0, 35,
+ 0, 0, 0, 49, 0, 0, 1,166, 0, 0, 0, 35, 0, 0, 0,107, 0, 0, 1,166, 0, 0, 0, 35, 0, 0, 0, 48, 0, 0, 1,167,
+ 0, 0, 0, 35, 0, 0, 0,106, 0, 0, 1,167, 0, 0, 0, 35, 0, 0, 0, 42, 0, 0, 1,168, 0, 0, 0, 35, 0, 0, 0,106,
+ 0, 0, 1,168, 0, 0, 0, 35, 0, 0, 0, 42, 0, 0, 1,169, 0, 0, 0, 33, 0, 0, 0, 48, 0, 0, 1,169, 0, 0, 0, 33,
+ 0, 0, 0, 54, 0, 0, 1,170, 0, 0, 0, 35, 0, 0, 0,108, 0, 0, 1,170, 0, 0, 0, 35, 0, 0, 0, 45, 0, 0, 1,171,
+ 0, 0, 0, 33, 0, 0, 0, 54, 0, 0, 1,171, 0, 0, 0, 33, 0, 0, 0, 45, 0, 0, 1,172, 0, 0, 0, 35, 0, 0, 0,108,
+ 0, 0, 1,172, 0, 0, 0, 35, 0, 0, 0,108, 0, 0, 1,173, 0, 0, 0, 35, 0, 0, 0,109, 0, 0, 1,173, 0, 0, 0, 35,
+ 0, 0, 0,109, 0, 0, 1,174, 0, 0, 0, 35, 0, 0, 0,110, 0, 0, 1,174, 0, 0, 0, 35, 0, 0, 0,108, 0, 0, 1,175,
+ 0, 0, 0, 35, 0, 0, 0,110, 0, 0, 1,175, 0, 0, 0, 35, 0, 0, 0, 53, 0, 0, 1,176, 0, 0, 0, 33, 0, 0, 0, 55,
+ 0, 0, 1,176, 0, 0, 0, 33, 0, 0, 0, 55, 0, 0, 1,177, 0, 0, 0, 35, 0, 0, 0,110, 0, 0, 1,177, 0, 0, 0, 35,
+ 0, 0, 0, 53, 0, 0, 1,178, 0, 0, 0, 35, 0, 0, 0,110, 0, 0, 1,178, 0, 0, 0, 35, 0, 0, 0, 52, 0, 0, 1,179,
+ 0, 0, 0, 35, 0, 0, 0,109, 0, 0, 1,179, 0, 0, 0, 35, 0, 0, 0, 44, 0, 0, 1,180, 0, 0, 0, 35, 0, 0, 0,109,
+ 0, 0, 1,180, 0, 0, 0, 35, 0, 0, 0, 44, 0, 0, 1,181, 0, 0, 0, 33, 0, 0, 0, 52, 0, 0, 1,181, 0, 0, 0, 33,
+ 0, 0, 0, 58, 0, 0, 1,182, 0, 0, 0, 35, 0, 0, 0,111, 0, 0, 1,182, 0, 0, 0, 35, 0, 0, 0, 53, 0, 0, 1,183,
+ 0, 0, 0, 33, 0, 0, 0, 58, 0, 0, 1,183, 0, 0, 0, 33, 0, 0, 0, 53, 0, 0, 1,184, 0, 0, 0, 35, 0, 0, 0,111,
+ 0, 0, 1,184, 0, 0, 0, 35, 0, 0, 0,111, 0, 0, 1,185, 0, 0, 0, 35, 0, 0, 0,112, 0, 0, 1,185, 0, 0, 0, 35,
+ 0, 0, 0,112, 0, 0, 1,186, 0, 0, 0, 35, 0, 0, 0,113, 0, 0, 1,186, 0, 0, 0, 35, 0, 0, 0,111, 0, 0, 1,187,
+ 0, 0, 0, 35, 0, 0, 0,113, 0, 0, 1,187, 0, 0, 0, 35, 0, 0, 0, 57, 0, 0, 1,188, 0, 0, 0, 33, 0, 0, 0, 59,
+ 0, 0, 1,188, 0, 0, 0, 33, 0, 0, 0, 59, 0, 0, 1,189, 0, 0, 0, 35, 0, 0, 0,113, 0, 0, 1,189, 0, 0, 0, 35,
+ 0, 0, 0, 57, 0, 0, 1,190, 0, 0, 0, 35, 0, 0, 0,113, 0, 0, 1,190, 0, 0, 0, 35, 0, 0, 0, 56, 0, 0, 1,191,
+ 0, 0, 0, 35, 0, 0, 0,112, 0, 0, 1,191, 0, 0, 0, 35, 0, 0, 0, 52, 0, 0, 1,192, 0, 0, 0, 35, 0, 0, 0,112,
+ 0, 0, 1,192, 0, 0, 0, 35, 0, 0, 0, 52, 0, 0, 1,193, 0, 0, 0, 33, 0, 0, 0, 56, 0, 0, 1,193, 0, 0, 0, 33,
+ 0, 0, 0, 60, 0, 0, 1,194, 0, 0, 0, 35, 0, 0, 0,114, 0, 0, 1,194, 0, 0, 0, 35, 0, 0, 0, 57, 0, 0, 1,195,
+ 0, 0, 0, 33, 0, 0, 0, 60, 0, 0, 1,195, 0, 0, 0, 33, 0, 0, 0, 57, 0, 0, 1,196, 0, 0, 0, 35, 0, 0, 0,114,
+ 0, 0, 1,196, 0, 0, 0, 35, 0, 0, 0,114, 0, 0, 1,197, 0, 0, 0, 35, 0, 0, 0,115, 0, 0, 1,197, 0, 0, 0, 35,
+ 0, 0, 0,115, 0, 0, 1,198, 0, 0, 0, 35, 0, 0, 0,116, 0, 0, 1,198, 0, 0, 0, 35, 0, 0, 0,114, 0, 0, 1,199,
+ 0, 0, 0, 35, 0, 0, 0,116, 0, 0, 1,199, 0, 0, 0, 35, 0, 0, 0, 49, 0, 0, 1,200, 0, 0, 0, 33, 0, 0, 0, 61,
+ 0, 0, 1,200, 0, 0, 0, 33, 0, 0, 0, 61, 0, 0, 1,201, 0, 0, 0, 35, 0, 0, 0,116, 0, 0, 1,201, 0, 0, 0, 35,
+ 0, 0, 0, 49, 0, 0, 1,202, 0, 0, 0, 35, 0, 0, 0,116, 0, 0, 1,202, 0, 0, 0, 35, 0, 0, 0, 48, 0, 0, 1,203,
+ 0, 0, 0, 35, 0, 0, 0,115, 0, 0, 1,203, 0, 0, 0, 35, 0, 0, 0, 56, 0, 0, 1,204, 0, 0, 0, 35, 0, 0, 0,115,
+ 0, 0, 1,204, 0, 0, 0, 35, 0, 0, 0, 48, 0, 0, 1,205, 0, 0, 0, 33, 0, 0, 0, 56, 0, 0, 1,205, 0, 0, 0, 33,
+ 0, 0, 0, 64, 0, 0, 1,206, 0, 0, 0, 35, 0, 0, 0,117, 0, 0, 1,206, 0, 0, 0, 35, 0, 0, 0, 50, 0, 0, 1,207,
+ 0, 0, 0, 33, 0, 0, 0, 64, 0, 0, 1,207, 0, 0, 0, 33, 0, 0, 0, 50, 0, 0, 1,208, 0, 0, 0, 35, 0, 0, 0,117,
+ 0, 0, 1,208, 0, 0, 0, 35, 0, 0, 0,117, 0, 0, 1,209, 0, 0, 0, 35, 0, 0, 0,118, 0, 0, 1,209, 0, 0, 0, 35,
+ 0, 0, 0,118, 0, 0, 1,210, 0, 0, 0, 35, 0, 0, 0,119, 0, 0, 1,210, 0, 0, 0, 35, 0, 0, 0,117, 0, 0, 1,211,
+ 0, 0, 0, 35, 0, 0, 0,119, 0, 0, 1,211, 0, 0, 0, 35, 0, 0, 0, 63, 0, 0, 1,212, 0, 0, 0, 33, 0, 0, 0, 65,
+ 0, 0, 1,212, 0, 0, 0, 33, 0, 0, 0, 65, 0, 0, 1,213, 0, 0, 0, 35, 0, 0, 0,119, 0, 0, 1,213, 0, 0, 0, 35,
+ 0, 0, 0, 63, 0, 0, 1,214, 0, 0, 0, 35, 0, 0, 0,119, 0, 0, 1,214, 0, 0, 0, 35, 0, 0, 0, 62, 0, 0, 1,215,
+ 0, 0, 0, 35, 0, 0, 0,118, 0, 0, 1,215, 0, 0, 0, 35, 0, 0, 0, 51, 0, 0, 1,216, 0, 0, 0, 35, 0, 0, 0,118,
+ 0, 0, 1,216, 0, 0, 0, 35, 0, 0, 0, 51, 0, 0, 1,217, 0, 0, 0, 33, 0, 0, 0, 62, 0, 0, 1,217, 0, 0, 0, 33,
+ 0, 0, 0, 68, 0, 0, 1,218, 0, 0, 0, 35, 0, 0, 0,120, 0, 0, 1,218, 0, 0, 0, 35, 0, 0, 0, 47, 0, 0, 1,219,
+ 0, 0, 0, 33, 0, 0, 0, 68, 0, 0, 1,219, 0, 0, 0, 33, 0, 0, 0, 47, 0, 0, 1,220, 0, 0, 0, 35, 0, 0, 0,120,
+ 0, 0, 1,220, 0, 0, 0, 35, 0, 0, 0,120, 0, 0, 1,221, 0, 0, 0, 35, 0, 0, 0,121, 0, 0, 1,221, 0, 0, 0, 35,
+ 0, 0, 0,121, 0, 0, 1,222, 0, 0, 0, 35, 0, 0, 0,122, 0, 0, 1,222, 0, 0, 0, 35, 0, 0, 0,120, 0, 0, 1,223,
+ 0, 0, 0, 35, 0, 0, 0,122, 0, 0, 1,223, 0, 0, 0, 35, 0, 0, 0, 67, 0, 0, 1,224, 0, 0, 0, 33, 0, 0, 0, 69,
+ 0, 0, 1,224, 0, 0, 0, 33, 0, 0, 0, 69, 0, 0, 1,225, 0, 0, 0, 35, 0, 0, 0,122, 0, 0, 1,225, 0, 0, 0, 35,
+ 0, 0, 0, 67, 0, 0, 1,226, 0, 0, 0, 35, 0, 0, 0,122, 0, 0, 1,226, 0, 0, 0, 35, 0, 0, 0, 66, 0, 0, 1,227,
+ 0, 0, 0, 35, 0, 0, 0,121, 0, 0, 1,227, 0, 0, 0, 35, 0, 0, 0, 46, 0, 0, 1,228, 0, 0, 0, 35, 0, 0, 0,121,
+ 0, 0, 1,228, 0, 0, 0, 35, 0, 0, 0, 46, 0, 0, 1,229, 0, 0, 0, 33, 0, 0, 0, 66, 0, 0, 1,229, 0, 0, 0, 33,
+ 0, 0, 0, 72, 0, 0, 1,230, 0, 0, 0, 35, 0, 0, 0,123, 0, 0, 1,230, 0, 0, 0, 35, 0, 0, 0, 55, 0, 0, 1,231,
+ 0, 0, 0, 33, 0, 0, 0, 72, 0, 0, 1,231, 0, 0, 0, 33, 0, 0, 0, 55, 0, 0, 1,232, 0, 0, 0, 35, 0, 0, 0,123,
+ 0, 0, 1,232, 0, 0, 0, 35, 0, 0, 0,123, 0, 0, 1,233, 0, 0, 0, 35, 0, 0, 0,124, 0, 0, 1,233, 0, 0, 0, 35,
+ 0, 0, 0,124, 0, 0, 1,234, 0, 0, 0, 35, 0, 0, 0,125, 0, 0, 1,234, 0, 0, 0, 35, 0, 0, 0,123, 0, 0, 1,235,
+ 0, 0, 0, 35, 0, 0, 0,125, 0, 0, 1,235, 0, 0, 0, 35, 0, 0, 0, 71, 0, 0, 1,236, 0, 0, 0, 33, 0, 0, 0, 73,
+ 0, 0, 1,236, 0, 0, 0, 33, 0, 0, 0, 73, 0, 0, 1,237, 0, 0, 0, 35, 0, 0, 0,125, 0, 0, 1,237, 0, 0, 0, 35,
+ 0, 0, 0, 71, 0, 0, 1,238, 0, 0, 0, 35, 0, 0, 0,125, 0, 0, 1,238, 0, 0, 0, 35, 0, 0, 0, 70, 0, 0, 1,239,
+ 0, 0, 0, 35, 0, 0, 0,124, 0, 0, 1,239, 0, 0, 0, 35, 0, 0, 0, 54, 0, 0, 1,240, 0, 0, 0, 35, 0, 0, 0,124,
+ 0, 0, 1,240, 0, 0, 0, 35, 0, 0, 0, 54, 0, 0, 1,241, 0, 0, 0, 33, 0, 0, 0, 70, 0, 0, 1,241, 0, 0, 0, 33,
+ 0, 0, 0, 76, 0, 0, 1,242, 0, 0, 0, 35, 0, 0, 0,126, 0, 0, 1,242, 0, 0, 0, 35, 0, 0, 0, 59, 0, 0, 1,243,
+ 0, 0, 0, 33, 0, 0, 0, 76, 0, 0, 1,243, 0, 0, 0, 33, 0, 0, 0, 59, 0, 0, 1,244, 0, 0, 0, 35, 0, 0, 0,126,
+ 0, 0, 1,244, 0, 0, 0, 35, 0, 0, 0,126, 0, 0, 1,245, 0, 0, 0, 35, 0, 0, 0,127, 0, 0, 1,245, 0, 0, 0, 35,
+ 0, 0, 0,127, 0, 0, 1,246, 0, 0, 0, 35, 0, 0, 0,128, 0, 0, 1,246, 0, 0, 0, 35, 0, 0, 0,126, 0, 0, 1,247,
+ 0, 0, 0, 35, 0, 0, 0,128, 0, 0, 1,247, 0, 0, 0, 35, 0, 0, 0, 75, 0, 0, 1,248, 0, 0, 0, 33, 0, 0, 0, 77,
+ 0, 0, 1,248, 0, 0, 0, 33, 0, 0, 0, 77, 0, 0, 1,249, 0, 0, 0, 35, 0, 0, 0,128, 0, 0, 1,249, 0, 0, 0, 35,
+ 0, 0, 0, 75, 0, 0, 1,250, 0, 0, 0, 35, 0, 0, 0,128, 0, 0, 1,250, 0, 0, 0, 35, 0, 0, 0, 74, 0, 0, 1,251,
+ 0, 0, 0, 35, 0, 0, 0,127, 0, 0, 1,251, 0, 0, 0, 35, 0, 0, 0, 58, 0, 0, 1,252, 0, 0, 0, 35, 0, 0, 0,127,
+ 0, 0, 1,252, 0, 0, 0, 35, 0, 0, 0, 58, 0, 0, 1,253, 0, 0, 0, 33, 0, 0, 0, 74, 0, 0, 1,253, 0, 0, 0, 33,
+ 0, 0, 0, 80, 0, 0, 1,254, 0, 0, 0, 35, 0, 0, 0,129, 0, 0, 1,254, 0, 0, 0, 35, 0, 0, 0, 61, 0, 0, 1,255,
+ 0, 0, 0, 33, 0, 0, 0, 80, 0, 0, 1,255, 0, 0, 0, 33, 0, 0, 0, 61, 0, 0, 2, 0, 0, 0, 0, 35, 0, 0, 0,129,
+ 0, 0, 2, 0, 0, 0, 0, 35, 0, 0, 0,129, 0, 0, 2, 1, 0, 0, 0, 35, 0, 0, 0,130, 0, 0, 2, 1, 0, 0, 0, 35,
+ 0, 0, 0,130, 0, 0, 2, 2, 0, 0, 0, 35, 0, 0, 0,131, 0, 0, 2, 2, 0, 0, 0, 35, 0, 0, 0,129, 0, 0, 2, 3,
+ 0, 0, 0, 35, 0, 0, 0,131, 0, 0, 2, 3, 0, 0, 0, 35, 0, 0, 0, 79, 0, 0, 2, 4, 0, 0, 0, 33, 0, 0, 0, 81,
+ 0, 0, 2, 4, 0, 0, 0, 33, 0, 0, 0, 81, 0, 0, 2, 5, 0, 0, 0, 35, 0, 0, 0,131, 0, 0, 2, 5, 0, 0, 0, 35,
+ 0, 0, 0, 79, 0, 0, 2, 6, 0, 0, 0, 35, 0, 0, 0,131, 0, 0, 2, 6, 0, 0, 0, 35, 0, 0, 0, 78, 0, 0, 2, 7,
+ 0, 0, 0, 35, 0, 0, 0,130, 0, 0, 2, 7, 0, 0, 0, 35, 0, 0, 0, 60, 0, 0, 2, 8, 0, 0, 0, 35, 0, 0, 0,130,
+ 0, 0, 2, 8, 0, 0, 0, 35, 0, 0, 0, 60, 0, 0, 2, 9, 0, 0, 0, 33, 0, 0, 0, 78, 0, 0, 2, 9, 0, 0, 0, 33,
+ 0, 0, 0, 83, 0, 0, 2, 10, 0, 0, 0, 35, 0, 0, 0,132, 0, 0, 2, 10, 0, 0, 0, 35, 0, 0, 0, 65, 0, 0, 2, 11,
+ 0, 0, 0, 33, 0, 0, 0, 83, 0, 0, 2, 11, 0, 0, 0, 33, 0, 0, 0, 65, 0, 0, 2, 12, 0, 0, 0, 35, 0, 0, 0,132,
+ 0, 0, 2, 12, 0, 0, 0, 35, 0, 0, 0,132, 0, 0, 2, 13, 0, 0, 0, 35, 0, 0, 0,133, 0, 0, 2, 13, 0, 0, 0, 35,
+ 0, 0, 0,133, 0, 0, 2, 14, 0, 0, 0, 35, 0, 0, 0,134, 0, 0, 2, 14, 0, 0, 0, 35, 0, 0, 0,132, 0, 0, 2, 15,
+ 0, 0, 0, 35, 0, 0, 0,134, 0, 0, 2, 15, 0, 0, 0, 35, 0, 0, 0, 67, 0, 0, 2, 16, 0, 0, 0, 33, 0, 0, 0, 82,
+ 0, 0, 2, 16, 0, 0, 0, 33, 0, 0, 0, 82, 0, 0, 2, 17, 0, 0, 0, 35, 0, 0, 0,134, 0, 0, 2, 17, 0, 0, 0, 35,
+ 0, 0, 0, 67, 0, 0, 2, 18, 0, 0, 0, 35, 0, 0, 0,134, 0, 0, 2, 18, 0, 0, 0, 35, 0, 0, 0, 66, 0, 0, 2, 19,
+ 0, 0, 0, 35, 0, 0, 0,133, 0, 0, 2, 19, 0, 0, 0, 35, 0, 0, 0, 64, 0, 0, 2, 20, 0, 0, 0, 35, 0, 0, 0,133,
+ 0, 0, 2, 20, 0, 0, 0, 35, 0, 0, 0, 64, 0, 0, 2, 21, 0, 0, 0, 33, 0, 0, 0, 66, 0, 0, 2, 21, 0, 0, 0, 33,
+ 0, 0, 0, 84, 0, 0, 2, 22, 0, 0, 0, 35, 0, 0, 0,135, 0, 0, 2, 22, 0, 0, 0, 35, 0, 0, 0, 69, 0, 0, 2, 23,
+ 0, 0, 0, 33, 0, 0, 0, 84, 0, 0, 2, 23, 0, 0, 0, 33, 0, 0, 0, 69, 0, 0, 2, 24, 0, 0, 0, 35, 0, 0, 0,135,
+ 0, 0, 2, 24, 0, 0, 0, 35, 0, 0, 0,135, 0, 0, 2, 25, 0, 0, 0, 35, 0, 0, 0,136, 0, 0, 2, 25, 0, 0, 0, 35,
+ 0, 0, 0,136, 0, 0, 2, 26, 0, 0, 0, 35, 0, 0, 0,137, 0, 0, 2, 26, 0, 0, 0, 35, 0, 0, 0,135, 0, 0, 2, 27,
+ 0, 0, 0, 35, 0, 0, 0,137, 0, 0, 2, 27, 0, 0, 0, 35, 0, 0, 0, 71, 0, 0, 2, 28, 0, 0, 0, 33, 0, 0, 0, 85,
+ 0, 0, 2, 28, 0, 0, 0, 33, 0, 0, 0, 85, 0, 0, 2, 29, 0, 0, 0, 35, 0, 0, 0,137, 0, 0, 2, 29, 0, 0, 0, 35,
+ 0, 0, 0, 71, 0, 0, 2, 30, 0, 0, 0, 35, 0, 0, 0,137, 0, 0, 2, 30, 0, 0, 0, 35, 0, 0, 0, 70, 0, 0, 2, 31,
+ 0, 0, 0, 35, 0, 0, 0,136, 0, 0, 2, 31, 0, 0, 0, 35, 0, 0, 0, 68, 0, 0, 2, 32, 0, 0, 0, 35, 0, 0, 0,136,
+ 0, 0, 2, 32, 0, 0, 0, 35, 0, 0, 0, 68, 0, 0, 2, 33, 0, 0, 0, 33, 0, 0, 0, 70, 0, 0, 2, 33, 0, 0, 0, 33,
+ 0, 0, 0, 86, 0, 0, 2, 34, 0, 0, 0, 35, 0, 0, 0,138, 0, 0, 2, 34, 0, 0, 0, 35, 0, 0, 0, 73, 0, 0, 2, 35,
+ 0, 0, 0, 33, 0, 0, 0, 86, 0, 0, 2, 35, 0, 0, 0, 33, 0, 0, 0, 73, 0, 0, 2, 36, 0, 0, 0, 35, 0, 0, 0,138,
+ 0, 0, 2, 36, 0, 0, 0, 35, 0, 0, 0,138, 0, 0, 2, 37, 0, 0, 0, 35, 0, 0, 0,139, 0, 0, 2, 37, 0, 0, 0, 35,
+ 0, 0, 0,139, 0, 0, 2, 38, 0, 0, 0, 35, 0, 0, 0,140, 0, 0, 2, 38, 0, 0, 0, 35, 0, 0, 0,138, 0, 0, 2, 39,
+ 0, 0, 0, 35, 0, 0, 0,140, 0, 0, 2, 39, 0, 0, 0, 35, 0, 0, 0, 75, 0, 0, 2, 40, 0, 0, 0, 33, 0, 0, 0, 87,
+ 0, 0, 2, 40, 0, 0, 0, 33, 0, 0, 0, 87, 0, 0, 2, 41, 0, 0, 0, 35, 0, 0, 0,140, 0, 0, 2, 41, 0, 0, 0, 35,
+ 0, 0, 0, 75, 0, 0, 2, 42, 0, 0, 0, 35, 0, 0, 0,140, 0, 0, 2, 42, 0, 0, 0, 35, 0, 0, 0, 74, 0, 0, 2, 43,
+ 0, 0, 0, 35, 0, 0, 0,139, 0, 0, 2, 43, 0, 0, 0, 35, 0, 0, 0, 72, 0, 0, 2, 44, 0, 0, 0, 35, 0, 0, 0,139,
+ 0, 0, 2, 44, 0, 0, 0, 35, 0, 0, 0, 72, 0, 0, 2, 45, 0, 0, 0, 33, 0, 0, 0, 74, 0, 0, 2, 45, 0, 0, 0, 33,
+ 0, 0, 0, 88, 0, 0, 2, 46, 0, 0, 0, 35, 0, 0, 0,141, 0, 0, 2, 46, 0, 0, 0, 35, 0, 0, 0, 77, 0, 0, 2, 47,
+ 0, 0, 0, 33, 0, 0, 0, 88, 0, 0, 2, 47, 0, 0, 0, 33, 0, 0, 0, 77, 0, 0, 2, 48, 0, 0, 0, 35, 0, 0, 0,141,
+ 0, 0, 2, 48, 0, 0, 0, 35, 0, 0, 0,141, 0, 0, 2, 49, 0, 0, 0, 35, 0, 0, 0,142, 0, 0, 2, 49, 0, 0, 0, 35,
+ 0, 0, 0,142, 0, 0, 2, 50, 0, 0, 0, 35, 0, 0, 0,143, 0, 0, 2, 50, 0, 0, 0, 35, 0, 0, 0,141, 0, 0, 2, 51,
+ 0, 0, 0, 35, 0, 0, 0,143, 0, 0, 2, 51, 0, 0, 0, 35, 0, 0, 0, 79, 0, 0, 2, 52, 0, 0, 0, 33, 0, 0, 0, 89,
+ 0, 0, 2, 52, 0, 0, 0, 33, 0, 0, 0, 89, 0, 0, 2, 53, 0, 0, 0, 35, 0, 0, 0,143, 0, 0, 2, 53, 0, 0, 0, 35,
+ 0, 0, 0, 79, 0, 0, 2, 54, 0, 0, 0, 35, 0, 0, 0,143, 0, 0, 2, 54, 0, 0, 0, 35, 0, 0, 0, 78, 0, 0, 2, 55,
+ 0, 0, 0, 35, 0, 0, 0,142, 0, 0, 2, 55, 0, 0, 0, 35, 0, 0, 0, 76, 0, 0, 2, 56, 0, 0, 0, 35, 0, 0, 0,142,
+ 0, 0, 2, 56, 0, 0, 0, 35, 0, 0, 0, 76, 0, 0, 2, 57, 0, 0, 0, 33, 0, 0, 0, 78, 0, 0, 2, 57, 0, 0, 0, 33,
+ 0, 0, 0, 90, 0, 0, 2, 58, 0, 0, 0, 35, 0, 0, 0,144, 0, 0, 2, 58, 0, 0, 0, 35, 0, 0, 0, 81, 0, 0, 2, 59,
+ 0, 0, 0, 33, 0, 0, 0, 90, 0, 0, 2, 59, 0, 0, 0, 33, 0, 0, 0, 81, 0, 0, 2, 60, 0, 0, 0, 35, 0, 0, 0,144,
+ 0, 0, 2, 60, 0, 0, 0, 35, 0, 0, 0,144, 0, 0, 2, 61, 0, 0, 0, 35, 0, 0, 0,145, 0, 0, 2, 61, 0, 0, 0, 35,
+ 0, 0, 0,145, 0, 0, 2, 62, 0, 0, 0, 35, 0, 0, 0,146, 0, 0, 2, 62, 0, 0, 0, 35, 0, 0, 0,144, 0, 0, 2, 63,
+ 0, 0, 0, 35, 0, 0, 0,146, 0, 0, 2, 63, 0, 0, 0, 35, 0, 0, 0, 63, 0, 0, 2, 64, 0, 0, 0, 33, 0, 0, 0, 91,
+ 0, 0, 2, 64, 0, 0, 0, 33, 0, 0, 0, 91, 0, 0, 2, 65, 0, 0, 0, 35, 0, 0, 0,146, 0, 0, 2, 65, 0, 0, 0, 35,
+ 0, 0, 0, 63, 0, 0, 2, 66, 0, 0, 0, 35, 0, 0, 0,146, 0, 0, 2, 66, 0, 0, 0, 35, 0, 0, 0, 62, 0, 0, 2, 67,
+ 0, 0, 0, 35, 0, 0, 0,145, 0, 0, 2, 67, 0, 0, 0, 35, 0, 0, 0, 80, 0, 0, 2, 68, 0, 0, 0, 35, 0, 0, 0,145,
+ 0, 0, 2, 68, 0, 0, 0, 35, 0, 0, 0, 62, 0, 0, 2, 69, 0, 0, 0, 33, 0, 0, 0, 80, 0, 0, 2, 69, 0, 0, 0, 33,
+ 0, 0, 0, 94, 0, 0, 2, 70, 0, 0, 0, 35, 0, 0, 0,147, 0, 0, 2, 70, 0, 0, 0, 35, 0, 0, 0, 82, 0, 0, 2, 71,
+ 0, 0, 0, 33, 0, 0, 0, 94, 0, 0, 2, 71, 0, 0, 0, 33, 0, 0, 0, 82, 0, 0, 2, 72, 0, 0, 0, 35, 0, 0, 0,147,
+ 0, 0, 2, 72, 0, 0, 0, 35, 0, 0, 0,147, 0, 0, 2, 73, 0, 0, 0, 35, 0, 0, 0,148, 0, 0, 2, 73, 0, 0, 0, 35,
+ 0, 0, 0,148, 0, 0, 2, 74, 0, 0, 0, 35, 0, 0, 0,149, 0, 0, 2, 74, 0, 0, 0, 35, 0, 0, 0,147, 0, 0, 2, 75,
+ 0, 0, 0, 35, 0, 0, 0,149, 0, 0, 2, 75, 0, 0, 0, 35, 0, 0, 0, 93, 0, 0, 2, 76, 0, 0, 0, 33, 0, 0, 0, 95,
+ 0, 0, 2, 76, 0, 0, 0, 33, 0, 0, 0, 95, 0, 0, 2, 77, 0, 0, 0, 35, 0, 0, 0,149, 0, 0, 2, 77, 0, 0, 0, 35,
+ 0, 0, 0, 93, 0, 0, 2, 78, 0, 0, 0, 35, 0, 0, 0,149, 0, 0, 2, 78, 0, 0, 0, 35, 0, 0, 0, 92, 0, 0, 2, 79,
+ 0, 0, 0, 35, 0, 0, 0,148, 0, 0, 2, 79, 0, 0, 0, 35, 0, 0, 0, 83, 0, 0, 2, 80, 0, 0, 0, 35, 0, 0, 0,148,
+ 0, 0, 2, 80, 0, 0, 0, 35, 0, 0, 0, 83, 0, 0, 2, 81, 0, 0, 0, 33, 0, 0, 0, 92, 0, 0, 2, 81, 0, 0, 0, 33,
+ 0, 0, 0, 96, 0, 0, 2, 82, 0, 0, 0, 35, 0, 0, 0,150, 0, 0, 2, 82, 0, 0, 0, 35, 0, 0, 0, 85, 0, 0, 2, 83,
+ 0, 0, 0, 33, 0, 0, 0, 96, 0, 0, 2, 83, 0, 0, 0, 33, 0, 0, 0, 85, 0, 0, 2, 84, 0, 0, 0, 35, 0, 0, 0,150,
+ 0, 0, 2, 84, 0, 0, 0, 35, 0, 0, 0,150, 0, 0, 2, 85, 0, 0, 0, 35, 0, 0, 0,151, 0, 0, 2, 85, 0, 0, 0, 35,
+ 0, 0, 0,151, 0, 0, 2, 86, 0, 0, 0, 35, 0, 0, 0,152, 0, 0, 2, 86, 0, 0, 0, 35, 0, 0, 0,150, 0, 0, 2, 87,
+ 0, 0, 0, 35, 0, 0, 0,152, 0, 0, 2, 87, 0, 0, 0, 35, 0, 0, 0, 95, 0, 0, 2, 88, 0, 0, 0, 33, 0, 0, 0, 97,
+ 0, 0, 2, 88, 0, 0, 0, 33, 0, 0, 0, 97, 0, 0, 2, 89, 0, 0, 0, 35, 0, 0, 0,152, 0, 0, 2, 89, 0, 0, 0, 35,
+ 0, 0, 0, 95, 0, 0, 2, 90, 0, 0, 0, 35, 0, 0, 0,152, 0, 0, 2, 90, 0, 0, 0, 35, 0, 0, 0, 94, 0, 0, 2, 91,
+ 0, 0, 0, 35, 0, 0, 0,151, 0, 0, 2, 91, 0, 0, 0, 35, 0, 0, 0, 84, 0, 0, 2, 92, 0, 0, 0, 35, 0, 0, 0,151,
+ 0, 0, 2, 92, 0, 0, 0, 35, 0, 0, 0, 84, 0, 0, 2, 93, 0, 0, 0, 33, 0, 0, 0, 94, 0, 0, 2, 93, 0, 0, 0, 33,
+ 0, 0, 0, 98, 0, 0, 2, 94, 0, 0, 0, 35, 0, 0, 0,153, 0, 0, 2, 94, 0, 0, 0, 35, 0, 0, 0, 87, 0, 0, 2, 95,
+ 0, 0, 0, 33, 0, 0, 0, 98, 0, 0, 2, 95, 0, 0, 0, 33, 0, 0, 0, 87, 0, 0, 2, 96, 0, 0, 0, 35, 0, 0, 0,153,
+ 0, 0, 2, 96, 0, 0, 0, 35, 0, 0, 0,153, 0, 0, 2, 97, 0, 0, 0, 35, 0, 0, 0,154, 0, 0, 2, 97, 0, 0, 0, 35,
+ 0, 0, 0,154, 0, 0, 2, 98, 0, 0, 0, 35, 0, 0, 0,155, 0, 0, 2, 98, 0, 0, 0, 35, 0, 0, 0,153, 0, 0, 2, 99,
+ 0, 0, 0, 35, 0, 0, 0,155, 0, 0, 2, 99, 0, 0, 0, 35, 0, 0, 0, 97, 0, 0, 2,100, 0, 0, 0, 33, 0, 0, 0, 99,
+ 0, 0, 2,100, 0, 0, 0, 33, 0, 0, 0, 99, 0, 0, 2,101, 0, 0, 0, 35, 0, 0, 0,155, 0, 0, 2,101, 0, 0, 0, 35,
+ 0, 0, 0, 97, 0, 0, 2,102, 0, 0, 0, 35, 0, 0, 0,155, 0, 0, 2,102, 0, 0, 0, 35, 0, 0, 0, 96, 0, 0, 2,103,
+ 0, 0, 0, 35, 0, 0, 0,154, 0, 0, 2,103, 0, 0, 0, 35, 0, 0, 0, 86, 0, 0, 2,104, 0, 0, 0, 35, 0, 0, 0,154,
+ 0, 0, 2,104, 0, 0, 0, 35, 0, 0, 0, 86, 0, 0, 2,105, 0, 0, 0, 33, 0, 0, 0, 96, 0, 0, 2,105, 0, 0, 0, 33,
+ 0, 0, 0,100, 0, 0, 2,106, 0, 0, 0, 35, 0, 0, 0,156, 0, 0, 2,106, 0, 0, 0, 35, 0, 0, 0, 89, 0, 0, 2,107,
+ 0, 0, 0, 33, 0, 0, 0,100, 0, 0, 2,107, 0, 0, 0, 33, 0, 0, 0, 89, 0, 0, 2,108, 0, 0, 0, 35, 0, 0, 0,156,
+ 0, 0, 2,108, 0, 0, 0, 35, 0, 0, 0,156, 0, 0, 2,109, 0, 0, 0, 35, 0, 0, 0,157, 0, 0, 2,109, 0, 0, 0, 35,
+ 0, 0, 0,157, 0, 0, 2,110, 0, 0, 0, 35, 0, 0, 0,158, 0, 0, 2,110, 0, 0, 0, 35, 0, 0, 0,156, 0, 0, 2,111,
+ 0, 0, 0, 35, 0, 0, 0,158, 0, 0, 2,111, 0, 0, 0, 35, 0, 0, 0, 99, 0, 0, 2,112, 0, 0, 0, 33, 0, 0, 0,101,
+ 0, 0, 2,112, 0, 0, 0, 33, 0, 0, 0,101, 0, 0, 2,113, 0, 0, 0, 35, 0, 0, 0,158, 0, 0, 2,113, 0, 0, 0, 35,
+ 0, 0, 0, 99, 0, 0, 2,114, 0, 0, 0, 35, 0, 0, 0,158, 0, 0, 2,114, 0, 0, 0, 35, 0, 0, 0, 98, 0, 0, 2,115,
+ 0, 0, 0, 35, 0, 0, 0,157, 0, 0, 2,115, 0, 0, 0, 35, 0, 0, 0, 88, 0, 0, 2,116, 0, 0, 0, 35, 0, 0, 0,157,
+ 0, 0, 2,116, 0, 0, 0, 35, 0, 0, 0, 88, 0, 0, 2,117, 0, 0, 0, 33, 0, 0, 0, 98, 0, 0, 2,117, 0, 0, 0, 33,
+ 0, 0, 0, 92, 0, 0, 2,118, 0, 0, 0, 35, 0, 0, 0,159, 0, 0, 2,118, 0, 0, 0, 35, 0, 0, 0, 91, 0, 0, 2,119,
+ 0, 0, 0, 33, 0, 0, 0, 92, 0, 0, 2,119, 0, 0, 0, 33, 0, 0, 0, 91, 0, 0, 2,120, 0, 0, 0, 35, 0, 0, 0,159,
+ 0, 0, 2,120, 0, 0, 0, 35, 0, 0, 0,159, 0, 0, 2,121, 0, 0, 0, 35, 0, 0, 0,160, 0, 0, 2,121, 0, 0, 0, 35,
+ 0, 0, 0,160, 0, 0, 2,122, 0, 0, 0, 35, 0, 0, 0,161, 0, 0, 2,122, 0, 0, 0, 35, 0, 0, 0,159, 0, 0, 2,123,
+ 0, 0, 0, 35, 0, 0, 0,161, 0, 0, 2,123, 0, 0, 0, 35, 0, 0, 0, 93, 0, 0, 2,124, 0, 0, 0, 33, 0, 0, 0,101,
+ 0, 0, 2,124, 0, 0, 0, 33, 0, 0, 0, 93, 0, 0, 2,125, 0, 0, 0, 35, 0, 0, 0,161, 0, 0, 2,125, 0, 0, 0, 35,
+ 0, 0, 0,101, 0, 0, 2,126, 0, 0, 0, 35, 0, 0, 0,161, 0, 0, 2,126, 0, 0, 0, 35, 0, 0, 0,100, 0, 0, 2,127,
+ 0, 0, 0, 35, 0, 0, 0,160, 0, 0, 2,127, 0, 0, 0, 35, 0, 0, 0, 90, 0, 0, 2,128, 0, 0, 0, 35, 0, 0, 0,160,
+ 0, 0, 2,128, 0, 0, 0, 35, 0, 0, 0, 90, 0, 0, 2,129, 0, 0, 0, 33, 0, 0, 0,100, 0, 0, 2,129, 0, 0, 0, 33,
+ 0, 0, 1, 27, 0, 0, 1,146, 0, 0, 0, 35, 0, 0, 0,171, 0, 0, 1,146, 0, 0, 0, 35, 0, 0, 0,171, 0, 0, 1, 27,
+ 0, 0, 0, 35, 0, 0, 1,146, 0, 0, 1,147, 0, 0, 0, 35, 0, 0, 1,146, 0, 0, 1,148, 0, 0, 0, 35, 0, 0, 1,147,
+ 0, 0, 1,148, 0, 0, 0, 35, 0, 0, 0,165, 0, 0, 1, 26, 0, 0, 0, 35, 0, 0, 0,165, 0, 0, 1,148, 0, 0, 0, 35,
+ 0, 0, 1, 26, 0, 0, 1,148, 0, 0, 0, 35, 0, 0, 0,164, 0, 0, 1,147, 0, 0, 0, 35, 0, 0, 0,164, 0, 0, 0,170,
+ 0, 0, 0, 35, 0, 0, 0,170, 0, 0, 1,147, 0, 0, 0, 35, 0, 0, 1, 26, 0, 0, 1,149, 0, 0, 0, 35, 0, 0, 1, 28,
+ 0, 0, 1,149, 0, 0, 0, 35, 0, 0, 1, 26, 0, 0, 1, 28, 0, 0, 0, 35, 0, 0, 1,149, 0, 0, 1,150, 0, 0, 0, 35,
+ 0, 0, 1,149, 0, 0, 1,151, 0, 0, 0, 35, 0, 0, 1,150, 0, 0, 1,151, 0, 0, 0, 35, 0, 0, 1, 27, 0, 0, 1, 31,
+ 0, 0, 0, 35, 0, 0, 1, 31, 0, 0, 1,151, 0, 0, 0, 35, 0, 0, 1, 27, 0, 0, 1,151, 0, 0, 0, 35, 0, 0, 1, 30,
+ 0, 0, 1,150, 0, 0, 0, 35, 0, 0, 1, 29, 0, 0, 1, 30, 0, 0, 0, 35, 0, 0, 1, 29, 0, 0, 1,150, 0, 0, 0, 35,
+ 0, 0, 0,168, 0, 0, 1,152, 0, 0, 0, 35, 0, 0, 0,172, 0, 0, 1,152, 0, 0, 0, 35, 0, 0, 0,168, 0, 0, 0,172,
+ 0, 0, 0, 35, 0, 0, 1,152, 0, 0, 1,153, 0, 0, 0, 35, 0, 0, 1,152, 0, 0, 1,154, 0, 0, 0, 35, 0, 0, 1,153,
+ 0, 0, 1,154, 0, 0, 0, 35, 0, 0, 0,169, 0, 0, 1, 30, 0, 0, 0, 35, 0, 0, 1, 30, 0, 0, 1,154, 0, 0, 0, 35,
+ 0, 0, 0,169, 0, 0, 1,154, 0, 0, 0, 35, 0, 0, 1, 31, 0, 0, 1,153, 0, 0, 0, 35, 0, 0, 0,173, 0, 0, 1, 31,
+ 0, 0, 0, 35, 0, 0, 0,173, 0, 0, 1,153, 0, 0, 0, 35, 0, 0, 0,167, 0, 0, 1,155, 0, 0, 0, 35, 0, 0, 1, 29,
+ 0, 0, 1,155, 0, 0, 0, 35, 0, 0, 0,167, 0, 0, 1, 29, 0, 0, 0, 35, 0, 0, 1,155, 0, 0, 1,156, 0, 0, 0, 35,
+ 0, 0, 1,155, 0, 0, 1,157, 0, 0, 0, 35, 0, 0, 1,156, 0, 0, 1,157, 0, 0, 0, 35, 0, 0, 0,162, 0, 0, 0,166,
+ 0, 0, 0, 35, 0, 0, 0,162, 0, 0, 1,157, 0, 0, 0, 35, 0, 0, 0,166, 0, 0, 1,157, 0, 0, 0, 35, 0, 0, 0,163,
+ 0, 0, 1,156, 0, 0, 0, 35, 0, 0, 0,163, 0, 0, 1, 28, 0, 0, 0, 35, 0, 0, 1, 28, 0, 0, 1,156, 0, 0, 0, 35,
+ 0, 0, 1, 33, 0, 0, 1,158, 0, 0, 0, 35, 0, 0, 0,179, 0, 0, 1, 33, 0, 0, 0, 35, 0, 0, 0,179, 0, 0, 1,158,
+ 0, 0, 0, 35, 0, 0, 1,158, 0, 0, 1,159, 0, 0, 0, 35, 0, 0, 1,159, 0, 0, 1,160, 0, 0, 0, 35, 0, 0, 1,158,
+ 0, 0, 1,160, 0, 0, 0, 35, 0, 0, 0,165, 0, 0, 1, 32, 0, 0, 0, 35, 0, 0, 1, 32, 0, 0, 1,160, 0, 0, 0, 35,
+ 0, 0, 0,165, 0, 0, 1,160, 0, 0, 0, 35, 0, 0, 0,164, 0, 0, 1,159, 0, 0, 0, 35, 0, 0, 0,178, 0, 0, 1,159,
+ 0, 0, 0, 35, 0, 0, 0,164, 0, 0, 0,178, 0, 0, 0, 35, 0, 0, 1, 32, 0, 0, 1,161, 0, 0, 0, 35, 0, 0, 1, 32,
+ 0, 0, 1, 34, 0, 0, 0, 35, 0, 0, 1, 34, 0, 0, 1,161, 0, 0, 0, 35, 0, 0, 1,161, 0, 0, 1,162, 0, 0, 0, 35,
+ 0, 0, 1,162, 0, 0, 1,163, 0, 0, 0, 35, 0, 0, 1,161, 0, 0, 1,163, 0, 0, 0, 35, 0, 0, 1, 33, 0, 0, 1, 37,
+ 0, 0, 0, 35, 0, 0, 1, 33, 0, 0, 1,163, 0, 0, 0, 35, 0, 0, 1, 37, 0, 0, 1,163, 0, 0, 0, 35, 0, 0, 1, 36,
+ 0, 0, 1,162, 0, 0, 0, 35, 0, 0, 1, 35, 0, 0, 1,162, 0, 0, 0, 35, 0, 0, 1, 35, 0, 0, 1, 36, 0, 0, 0, 35,
+ 0, 0, 0,176, 0, 0, 1,164, 0, 0, 0, 35, 0, 0, 0,176, 0, 0, 0,180, 0, 0, 0, 35, 0, 0, 0,180, 0, 0, 1,164,
+ 0, 0, 0, 35, 0, 0, 1,164, 0, 0, 1,165, 0, 0, 0, 35, 0, 0, 1,165, 0, 0, 1,166, 0, 0, 0, 35, 0, 0, 1,164,
+ 0, 0, 1,166, 0, 0, 0, 35, 0, 0, 0,177, 0, 0, 1, 36, 0, 0, 0, 35, 0, 0, 0,177, 0, 0, 1,166, 0, 0, 0, 35,
+ 0, 0, 1, 36, 0, 0, 1,166, 0, 0, 0, 35, 0, 0, 1, 37, 0, 0, 1,165, 0, 0, 0, 35, 0, 0, 0,181, 0, 0, 1,165,
+ 0, 0, 0, 35, 0, 0, 0,181, 0, 0, 1, 37, 0, 0, 0, 35, 0, 0, 0,175, 0, 0, 1,167, 0, 0, 0, 35, 0, 0, 0,175,
+ 0, 0, 1, 35, 0, 0, 0, 35, 0, 0, 1, 35, 0, 0, 1,167, 0, 0, 0, 35, 0, 0, 1,167, 0, 0, 1,168, 0, 0, 0, 35,
+ 0, 0, 1,168, 0, 0, 1,169, 0, 0, 0, 35, 0, 0, 1,167, 0, 0, 1,169, 0, 0, 0, 35, 0, 0, 0,162, 0, 0, 0,174,
+ 0, 0, 0, 35, 0, 0, 0,174, 0, 0, 1,169, 0, 0, 0, 35, 0, 0, 0,162, 0, 0, 1,169, 0, 0, 0, 35, 0, 0, 0,163,
+ 0, 0, 1,168, 0, 0, 0, 35, 0, 0, 1, 34, 0, 0, 1,168, 0, 0, 0, 35, 0, 0, 0,163, 0, 0, 1, 34, 0, 0, 0, 35,
+ 0, 0, 1, 39, 0, 0, 1,170, 0, 0, 0, 35, 0, 0, 0,187, 0, 0, 1,170, 0, 0, 0, 35, 0, 0, 0,187, 0, 0, 1, 39,
+ 0, 0, 0, 35, 0, 0, 1,170, 0, 0, 1,171, 0, 0, 0, 35, 0, 0, 1,170, 0, 0, 1,172, 0, 0, 0, 35, 0, 0, 1,171,
+ 0, 0, 1,172, 0, 0, 0, 35, 0, 0, 0,169, 0, 0, 1, 38, 0, 0, 0, 35, 0, 0, 0,169, 0, 0, 1,172, 0, 0, 0, 35,
+ 0, 0, 1, 38, 0, 0, 1,172, 0, 0, 0, 35, 0, 0, 0,168, 0, 0, 1,171, 0, 0, 0, 35, 0, 0, 0,168, 0, 0, 0,186,
+ 0, 0, 0, 35, 0, 0, 0,186, 0, 0, 1,171, 0, 0, 0, 35, 0, 0, 1, 38, 0, 0, 1,173, 0, 0, 0, 35, 0, 0, 1, 40,
+ 0, 0, 1,173, 0, 0, 0, 35, 0, 0, 1, 38, 0, 0, 1, 40, 0, 0, 0, 35, 0, 0, 1,173, 0, 0, 1,174, 0, 0, 0, 35,
+ 0, 0, 1,173, 0, 0, 1,175, 0, 0, 0, 35, 0, 0, 1,174, 0, 0, 1,175, 0, 0, 0, 35, 0, 0, 1, 39, 0, 0, 1, 43,
+ 0, 0, 0, 35, 0, 0, 1, 43, 0, 0, 1,175, 0, 0, 0, 35, 0, 0, 1, 39, 0, 0, 1,175, 0, 0, 0, 35, 0, 0, 1, 42,
+ 0, 0, 1,174, 0, 0, 0, 35, 0, 0, 1, 41, 0, 0, 1, 42, 0, 0, 0, 35, 0, 0, 1, 41, 0, 0, 1,174, 0, 0, 0, 35,
+ 0, 0, 0,184, 0, 0, 1,176, 0, 0, 0, 35, 0, 0, 0,188, 0, 0, 1,176, 0, 0, 0, 35, 0, 0, 0,184, 0, 0, 0,188,
+ 0, 0, 0, 35, 0, 0, 1,176, 0, 0, 1,177, 0, 0, 0, 35, 0, 0, 1,176, 0, 0, 1,178, 0, 0, 0, 35, 0, 0, 1,177,
+ 0, 0, 1,178, 0, 0, 0, 35, 0, 0, 0,185, 0, 0, 1, 42, 0, 0, 0, 35, 0, 0, 1, 42, 0, 0, 1,178, 0, 0, 0, 35,
+ 0, 0, 0,185, 0, 0, 1,178, 0, 0, 0, 35, 0, 0, 1, 43, 0, 0, 1,177, 0, 0, 0, 35, 0, 0, 0,189, 0, 0, 1, 43,
+ 0, 0, 0, 35, 0, 0, 0,189, 0, 0, 1,177, 0, 0, 0, 35, 0, 0, 0,183, 0, 0, 1,179, 0, 0, 0, 35, 0, 0, 1, 41,
+ 0, 0, 1,179, 0, 0, 0, 35, 0, 0, 0,183, 0, 0, 1, 41, 0, 0, 0, 35, 0, 0, 1,179, 0, 0, 1,180, 0, 0, 0, 35,
+ 0, 0, 1,179, 0, 0, 1,181, 0, 0, 0, 35, 0, 0, 1,180, 0, 0, 1,181, 0, 0, 0, 35, 0, 0, 0,166, 0, 0, 0,182,
+ 0, 0, 0, 35, 0, 0, 0,166, 0, 0, 1,181, 0, 0, 0, 35, 0, 0, 0,182, 0, 0, 1,181, 0, 0, 0, 35, 0, 0, 0,167,
+ 0, 0, 1,180, 0, 0, 0, 35, 0, 0, 0,167, 0, 0, 1, 40, 0, 0, 0, 35, 0, 0, 1, 40, 0, 0, 1,180, 0, 0, 0, 35,
+ 0, 0, 1, 45, 0, 0, 1,182, 0, 0, 0, 35, 0, 0, 0,195, 0, 0, 1,182, 0, 0, 0, 35, 0, 0, 0,195, 0, 0, 1, 45,
+ 0, 0, 0, 35, 0, 0, 1,182, 0, 0, 1,183, 0, 0, 0, 35, 0, 0, 1,182, 0, 0, 1,184, 0, 0, 0, 35, 0, 0, 1,183,
+ 0, 0, 1,184, 0, 0, 0, 35, 0, 0, 0,185, 0, 0, 1, 44, 0, 0, 0, 35, 0, 0, 0,185, 0, 0, 1,184, 0, 0, 0, 35,
+ 0, 0, 1, 44, 0, 0, 1,184, 0, 0, 0, 35, 0, 0, 0,184, 0, 0, 1,183, 0, 0, 0, 35, 0, 0, 0,184, 0, 0, 0,194,
+ 0, 0, 0, 35, 0, 0, 0,194, 0, 0, 1,183, 0, 0, 0, 35, 0, 0, 1, 44, 0, 0, 1,185, 0, 0, 0, 35, 0, 0, 1, 46,
+ 0, 0, 1,185, 0, 0, 0, 35, 0, 0, 1, 44, 0, 0, 1, 46, 0, 0, 0, 35, 0, 0, 1,185, 0, 0, 1,186, 0, 0, 0, 35,
+ 0, 0, 1,185, 0, 0, 1,187, 0, 0, 0, 35, 0, 0, 1,186, 0, 0, 1,187, 0, 0, 0, 35, 0, 0, 1, 45, 0, 0, 1, 49,
+ 0, 0, 0, 35, 0, 0, 1, 49, 0, 0, 1,187, 0, 0, 0, 35, 0, 0, 1, 45, 0, 0, 1,187, 0, 0, 0, 35, 0, 0, 1, 48,
+ 0, 0, 1,186, 0, 0, 0, 35, 0, 0, 1, 47, 0, 0, 1, 48, 0, 0, 0, 35, 0, 0, 1, 47, 0, 0, 1,186, 0, 0, 0, 35,
+ 0, 0, 0,192, 0, 0, 1,188, 0, 0, 0, 35, 0, 0, 0,196, 0, 0, 1,188, 0, 0, 0, 35, 0, 0, 0,192, 0, 0, 0,196,
+ 0, 0, 0, 35, 0, 0, 1,188, 0, 0, 1,189, 0, 0, 0, 35, 0, 0, 1,188, 0, 0, 1,190, 0, 0, 0, 35, 0, 0, 1,189,
+ 0, 0, 1,190, 0, 0, 0, 35, 0, 0, 0,193, 0, 0, 1, 48, 0, 0, 0, 35, 0, 0, 1, 48, 0, 0, 1,190, 0, 0, 0, 35,
+ 0, 0, 0,193, 0, 0, 1,190, 0, 0, 0, 35, 0, 0, 1, 49, 0, 0, 1,189, 0, 0, 0, 35, 0, 0, 0,197, 0, 0, 1, 49,
+ 0, 0, 0, 35, 0, 0, 0,197, 0, 0, 1,189, 0, 0, 0, 35, 0, 0, 0,191, 0, 0, 1,191, 0, 0, 0, 35, 0, 0, 1, 47,
+ 0, 0, 1,191, 0, 0, 0, 35, 0, 0, 0,191, 0, 0, 1, 47, 0, 0, 0, 35, 0, 0, 1,191, 0, 0, 1,192, 0, 0, 0, 35,
+ 0, 0, 1,191, 0, 0, 1,193, 0, 0, 0, 35, 0, 0, 1,192, 0, 0, 1,193, 0, 0, 0, 35, 0, 0, 0,182, 0, 0, 0,190,
+ 0, 0, 0, 35, 0, 0, 0,182, 0, 0, 1,193, 0, 0, 0, 35, 0, 0, 0,190, 0, 0, 1,193, 0, 0, 0, 35, 0, 0, 0,183,
+ 0, 0, 1,192, 0, 0, 0, 35, 0, 0, 0,183, 0, 0, 1, 46, 0, 0, 0, 35, 0, 0, 1, 46, 0, 0, 1,192, 0, 0, 0, 35,
+ 0, 0, 1, 51, 0, 0, 1,194, 0, 0, 0, 35, 0, 0, 0,199, 0, 0, 1,194, 0, 0, 0, 35, 0, 0, 0,199, 0, 0, 1, 51,
+ 0, 0, 0, 35, 0, 0, 1,194, 0, 0, 1,195, 0, 0, 0, 35, 0, 0, 1,194, 0, 0, 1,196, 0, 0, 0, 35, 0, 0, 1,195,
+ 0, 0, 1,196, 0, 0, 0, 35, 0, 0, 0,193, 0, 0, 1, 50, 0, 0, 0, 35, 0, 0, 0,193, 0, 0, 1,196, 0, 0, 0, 35,
+ 0, 0, 1, 50, 0, 0, 1,196, 0, 0, 0, 35, 0, 0, 0,192, 0, 0, 1,195, 0, 0, 0, 35, 0, 0, 0,192, 0, 0, 0,198,
+ 0, 0, 0, 35, 0, 0, 0,198, 0, 0, 1,195, 0, 0, 0, 35, 0, 0, 1, 50, 0, 0, 1,197, 0, 0, 0, 35, 0, 0, 1, 53,
+ 0, 0, 1,197, 0, 0, 0, 35, 0, 0, 1, 50, 0, 0, 1, 53, 0, 0, 0, 35, 0, 0, 1,197, 0, 0, 1,198, 0, 0, 0, 35,
+ 0, 0, 1,197, 0, 0, 1,199, 0, 0, 0, 35, 0, 0, 1,198, 0, 0, 1,199, 0, 0, 0, 35, 0, 0, 1, 51, 0, 0, 1, 55,
+ 0, 0, 0, 35, 0, 0, 1, 55, 0, 0, 1,199, 0, 0, 0, 35, 0, 0, 1, 51, 0, 0, 1,199, 0, 0, 0, 35, 0, 0, 1, 54,
+ 0, 0, 1,198, 0, 0, 0, 35, 0, 0, 1, 52, 0, 0, 1, 54, 0, 0, 0, 35, 0, 0, 1, 52, 0, 0, 1,198, 0, 0, 0, 35,
+ 0, 0, 0,176, 0, 0, 1,200, 0, 0, 0, 35, 0, 0, 0,200, 0, 0, 1,200, 0, 0, 0, 35, 0, 0, 0,176, 0, 0, 0,200,
+ 0, 0, 0, 35, 0, 0, 1,200, 0, 0, 1,201, 0, 0, 0, 35, 0, 0, 1,200, 0, 0, 1,202, 0, 0, 0, 35, 0, 0, 1,201,
+ 0, 0, 1,202, 0, 0, 0, 35, 0, 0, 0,177, 0, 0, 1, 54, 0, 0, 0, 35, 0, 0, 1, 54, 0, 0, 1,202, 0, 0, 0, 35,
+ 0, 0, 0,177, 0, 0, 1,202, 0, 0, 0, 35, 0, 0, 1, 55, 0, 0, 1,201, 0, 0, 0, 35, 0, 0, 0,201, 0, 0, 1, 55,
+ 0, 0, 0, 35, 0, 0, 0,201, 0, 0, 1,201, 0, 0, 0, 35, 0, 0, 0,175, 0, 0, 1,203, 0, 0, 0, 35, 0, 0, 1, 52,
+ 0, 0, 1,203, 0, 0, 0, 35, 0, 0, 0,175, 0, 0, 1, 52, 0, 0, 0, 35, 0, 0, 1,203, 0, 0, 1,204, 0, 0, 0, 35,
+ 0, 0, 1,203, 0, 0, 1,205, 0, 0, 0, 35, 0, 0, 1,204, 0, 0, 1,205, 0, 0, 0, 35, 0, 0, 0,174, 0, 0, 0,190,
+ 0, 0, 0, 35, 0, 0, 0,190, 0, 0, 1,205, 0, 0, 0, 35, 0, 0, 0,174, 0, 0, 1,205, 0, 0, 0, 35, 0, 0, 0,191,
+ 0, 0, 1,204, 0, 0, 0, 35, 0, 0, 0,191, 0, 0, 1, 53, 0, 0, 0, 35, 0, 0, 1, 53, 0, 0, 1,204, 0, 0, 0, 35,
+ 0, 0, 1, 57, 0, 0, 1,206, 0, 0, 0, 35, 0, 0, 0,207, 0, 0, 1, 57, 0, 0, 0, 35, 0, 0, 0,207, 0, 0, 1,206,
+ 0, 0, 0, 35, 0, 0, 1,206, 0, 0, 1,207, 0, 0, 0, 35, 0, 0, 1,207, 0, 0, 1,208, 0, 0, 0, 35, 0, 0, 1,206,
+ 0, 0, 1,208, 0, 0, 0, 35, 0, 0, 0,179, 0, 0, 1, 56, 0, 0, 0, 35, 0, 0, 1, 56, 0, 0, 1,208, 0, 0, 0, 35,
+ 0, 0, 0,179, 0, 0, 1,208, 0, 0, 0, 35, 0, 0, 0,178, 0, 0, 1,207, 0, 0, 0, 35, 0, 0, 0,206, 0, 0, 1,207,
+ 0, 0, 0, 35, 0, 0, 0,178, 0, 0, 0,206, 0, 0, 0, 35, 0, 0, 1, 56, 0, 0, 1,209, 0, 0, 0, 35, 0, 0, 1, 56,
+ 0, 0, 1, 58, 0, 0, 0, 35, 0, 0, 1, 58, 0, 0, 1,209, 0, 0, 0, 35, 0, 0, 1,209, 0, 0, 1,210, 0, 0, 0, 35,
+ 0, 0, 1,210, 0, 0, 1,211, 0, 0, 0, 35, 0, 0, 1,209, 0, 0, 1,211, 0, 0, 0, 35, 0, 0, 1, 57, 0, 0, 1, 61,
+ 0, 0, 0, 35, 0, 0, 1, 57, 0, 0, 1,211, 0, 0, 0, 35, 0, 0, 1, 61, 0, 0, 1,211, 0, 0, 0, 35, 0, 0, 1, 60,
+ 0, 0, 1,210, 0, 0, 0, 35, 0, 0, 1, 59, 0, 0, 1,210, 0, 0, 0, 35, 0, 0, 1, 59, 0, 0, 1, 60, 0, 0, 0, 35,
+ 0, 0, 0,204, 0, 0, 1,212, 0, 0, 0, 35, 0, 0, 0,204, 0, 0, 0,208, 0, 0, 0, 35, 0, 0, 0,208, 0, 0, 1,212,
+ 0, 0, 0, 35, 0, 0, 1,212, 0, 0, 1,213, 0, 0, 0, 35, 0, 0, 1,213, 0, 0, 1,214, 0, 0, 0, 35, 0, 0, 1,212,
+ 0, 0, 1,214, 0, 0, 0, 35, 0, 0, 0,205, 0, 0, 1, 60, 0, 0, 0, 35, 0, 0, 0,205, 0, 0, 1,214, 0, 0, 0, 35,
+ 0, 0, 1, 60, 0, 0, 1,214, 0, 0, 0, 35, 0, 0, 1, 61, 0, 0, 1,213, 0, 0, 0, 35, 0, 0, 0,209, 0, 0, 1,213,
+ 0, 0, 0, 35, 0, 0, 0,209, 0, 0, 1, 61, 0, 0, 0, 35, 0, 0, 0,203, 0, 0, 1,215, 0, 0, 0, 35, 0, 0, 0,203,
+ 0, 0, 1, 59, 0, 0, 0, 35, 0, 0, 1, 59, 0, 0, 1,215, 0, 0, 0, 35, 0, 0, 1,215, 0, 0, 1,216, 0, 0, 0, 35,
+ 0, 0, 1,216, 0, 0, 1,217, 0, 0, 0, 35, 0, 0, 1,215, 0, 0, 1,217, 0, 0, 0, 35, 0, 0, 0,180, 0, 0, 0,202,
+ 0, 0, 0, 35, 0, 0, 0,202, 0, 0, 1,217, 0, 0, 0, 35, 0, 0, 0,180, 0, 0, 1,217, 0, 0, 0, 35, 0, 0, 0,181,
+ 0, 0, 1,216, 0, 0, 0, 35, 0, 0, 1, 58, 0, 0, 1,216, 0, 0, 0, 35, 0, 0, 0,181, 0, 0, 1, 58, 0, 0, 0, 35,
+ 0, 0, 1, 63, 0, 0, 1,218, 0, 0, 0, 35, 0, 0, 0,215, 0, 0, 1, 63, 0, 0, 0, 35, 0, 0, 0,215, 0, 0, 1,218,
+ 0, 0, 0, 35, 0, 0, 1,218, 0, 0, 1,219, 0, 0, 0, 35, 0, 0, 1,219, 0, 0, 1,220, 0, 0, 0, 35, 0, 0, 1,218,
+ 0, 0, 1,220, 0, 0, 0, 35, 0, 0, 0,173, 0, 0, 1, 62, 0, 0, 0, 35, 0, 0, 1, 62, 0, 0, 1,220, 0, 0, 0, 35,
+ 0, 0, 0,173, 0, 0, 1,220, 0, 0, 0, 35, 0, 0, 0,172, 0, 0, 1,219, 0, 0, 0, 35, 0, 0, 0,214, 0, 0, 1,219,
+ 0, 0, 0, 35, 0, 0, 0,172, 0, 0, 0,214, 0, 0, 0, 35, 0, 0, 1, 62, 0, 0, 1,221, 0, 0, 0, 35, 0, 0, 1, 62,
+ 0, 0, 1, 64, 0, 0, 0, 35, 0, 0, 1, 64, 0, 0, 1,221, 0, 0, 0, 35, 0, 0, 1,221, 0, 0, 1,222, 0, 0, 0, 35,
+ 0, 0, 1,222, 0, 0, 1,223, 0, 0, 0, 35, 0, 0, 1,221, 0, 0, 1,223, 0, 0, 0, 35, 0, 0, 1, 63, 0, 0, 1, 67,
+ 0, 0, 0, 35, 0, 0, 1, 63, 0, 0, 1,223, 0, 0, 0, 35, 0, 0, 1, 67, 0, 0, 1,223, 0, 0, 0, 35, 0, 0, 1, 66,
+ 0, 0, 1,222, 0, 0, 0, 35, 0, 0, 1, 65, 0, 0, 1,222, 0, 0, 0, 35, 0, 0, 1, 65, 0, 0, 1, 66, 0, 0, 0, 35,
+ 0, 0, 0,212, 0, 0, 1,224, 0, 0, 0, 35, 0, 0, 0,212, 0, 0, 0,216, 0, 0, 0, 35, 0, 0, 0,216, 0, 0, 1,224,
+ 0, 0, 0, 35, 0, 0, 1,224, 0, 0, 1,225, 0, 0, 0, 35, 0, 0, 1,225, 0, 0, 1,226, 0, 0, 0, 35, 0, 0, 1,224,
+ 0, 0, 1,226, 0, 0, 0, 35, 0, 0, 0,213, 0, 0, 1, 66, 0, 0, 0, 35, 0, 0, 0,213, 0, 0, 1,226, 0, 0, 0, 35,
+ 0, 0, 1, 66, 0, 0, 1,226, 0, 0, 0, 35, 0, 0, 1, 67, 0, 0, 1,225, 0, 0, 0, 35, 0, 0, 0,217, 0, 0, 1,225,
+ 0, 0, 0, 35, 0, 0, 0,217, 0, 0, 1, 67, 0, 0, 0, 35, 0, 0, 0,211, 0, 0, 1,227, 0, 0, 0, 35, 0, 0, 0,211,
+ 0, 0, 1, 65, 0, 0, 0, 35, 0, 0, 1, 65, 0, 0, 1,227, 0, 0, 0, 35, 0, 0, 1,227, 0, 0, 1,228, 0, 0, 0, 35,
+ 0, 0, 1,228, 0, 0, 1,229, 0, 0, 0, 35, 0, 0, 1,227, 0, 0, 1,229, 0, 0, 0, 35, 0, 0, 0,170, 0, 0, 0,210,
+ 0, 0, 0, 35, 0, 0, 0,210, 0, 0, 1,229, 0, 0, 0, 35, 0, 0, 0,170, 0, 0, 1,229, 0, 0, 0, 35, 0, 0, 0,171,
+ 0, 0, 1,228, 0, 0, 0, 35, 0, 0, 1, 64, 0, 0, 1,228, 0, 0, 0, 35, 0, 0, 0,171, 0, 0, 1, 64, 0, 0, 0, 35,
+ 0, 0, 1, 69, 0, 0, 1,230, 0, 0, 0, 35, 0, 0, 0,223, 0, 0, 1, 69, 0, 0, 0, 35, 0, 0, 0,223, 0, 0, 1,230,
+ 0, 0, 0, 35, 0, 0, 1,230, 0, 0, 1,231, 0, 0, 0, 35, 0, 0, 1,231, 0, 0, 1,232, 0, 0, 0, 35, 0, 0, 1,230,
+ 0, 0, 1,232, 0, 0, 0, 35, 0, 0, 0,189, 0, 0, 1, 68, 0, 0, 0, 35, 0, 0, 1, 68, 0, 0, 1,232, 0, 0, 0, 35,
+ 0, 0, 0,189, 0, 0, 1,232, 0, 0, 0, 35, 0, 0, 0,188, 0, 0, 1,231, 0, 0, 0, 35, 0, 0, 0,222, 0, 0, 1,231,
+ 0, 0, 0, 35, 0, 0, 0,188, 0, 0, 0,222, 0, 0, 0, 35, 0, 0, 1, 68, 0, 0, 1,233, 0, 0, 0, 35, 0, 0, 1, 68,
+ 0, 0, 1, 70, 0, 0, 0, 35, 0, 0, 1, 70, 0, 0, 1,233, 0, 0, 0, 35, 0, 0, 1,233, 0, 0, 1,234, 0, 0, 0, 35,
+ 0, 0, 1,234, 0, 0, 1,235, 0, 0, 0, 35, 0, 0, 1,233, 0, 0, 1,235, 0, 0, 0, 35, 0, 0, 1, 69, 0, 0, 1, 73,
+ 0, 0, 0, 35, 0, 0, 1, 69, 0, 0, 1,235, 0, 0, 0, 35, 0, 0, 1, 73, 0, 0, 1,235, 0, 0, 0, 35, 0, 0, 1, 72,
+ 0, 0, 1,234, 0, 0, 0, 35, 0, 0, 1, 71, 0, 0, 1,234, 0, 0, 0, 35, 0, 0, 1, 71, 0, 0, 1, 72, 0, 0, 0, 35,
+ 0, 0, 0,220, 0, 0, 1,236, 0, 0, 0, 35, 0, 0, 0,220, 0, 0, 0,224, 0, 0, 0, 35, 0, 0, 0,224, 0, 0, 1,236,
+ 0, 0, 0, 35, 0, 0, 1,236, 0, 0, 1,237, 0, 0, 0, 35, 0, 0, 1,237, 0, 0, 1,238, 0, 0, 0, 35, 0, 0, 1,236,
+ 0, 0, 1,238, 0, 0, 0, 35, 0, 0, 0,221, 0, 0, 1, 72, 0, 0, 0, 35, 0, 0, 0,221, 0, 0, 1,238, 0, 0, 0, 35,
+ 0, 0, 1, 72, 0, 0, 1,238, 0, 0, 0, 35, 0, 0, 1, 73, 0, 0, 1,237, 0, 0, 0, 35, 0, 0, 0,225, 0, 0, 1,237,
+ 0, 0, 0, 35, 0, 0, 0,225, 0, 0, 1, 73, 0, 0, 0, 35, 0, 0, 0,219, 0, 0, 1,239, 0, 0, 0, 35, 0, 0, 0,219,
+ 0, 0, 1, 71, 0, 0, 0, 35, 0, 0, 1, 71, 0, 0, 1,239, 0, 0, 0, 35, 0, 0, 1,239, 0, 0, 1,240, 0, 0, 0, 35,
+ 0, 0, 1,240, 0, 0, 1,241, 0, 0, 0, 35, 0, 0, 1,239, 0, 0, 1,241, 0, 0, 0, 35, 0, 0, 0,186, 0, 0, 0,218,
+ 0, 0, 0, 35, 0, 0, 0,218, 0, 0, 1,241, 0, 0, 0, 35, 0, 0, 0,186, 0, 0, 1,241, 0, 0, 0, 35, 0, 0, 0,187,
+ 0, 0, 1,240, 0, 0, 0, 35, 0, 0, 1, 70, 0, 0, 1,240, 0, 0, 0, 35, 0, 0, 0,187, 0, 0, 1, 70, 0, 0, 0, 35,
+ 0, 0, 1, 75, 0, 0, 1,242, 0, 0, 0, 35, 0, 0, 0,231, 0, 0, 1, 75, 0, 0, 0, 35, 0, 0, 0,231, 0, 0, 1,242,
+ 0, 0, 0, 35, 0, 0, 1,242, 0, 0, 1,243, 0, 0, 0, 35, 0, 0, 1,243, 0, 0, 1,244, 0, 0, 0, 35, 0, 0, 1,242,
+ 0, 0, 1,244, 0, 0, 0, 35, 0, 0, 0,197, 0, 0, 1, 74, 0, 0, 0, 35, 0, 0, 1, 74, 0, 0, 1,244, 0, 0, 0, 35,
+ 0, 0, 0,197, 0, 0, 1,244, 0, 0, 0, 35, 0, 0, 0,196, 0, 0, 1,243, 0, 0, 0, 35, 0, 0, 0,230, 0, 0, 1,243,
+ 0, 0, 0, 35, 0, 0, 0,196, 0, 0, 0,230, 0, 0, 0, 35, 0, 0, 1, 74, 0, 0, 1,245, 0, 0, 0, 35, 0, 0, 1, 74,
+ 0, 0, 1, 76, 0, 0, 0, 35, 0, 0, 1, 76, 0, 0, 1,245, 0, 0, 0, 35, 0, 0, 1,245, 0, 0, 1,246, 0, 0, 0, 35,
+ 0, 0, 1,246, 0, 0, 1,247, 0, 0, 0, 35, 0, 0, 1,245, 0, 0, 1,247, 0, 0, 0, 35, 0, 0, 1, 75, 0, 0, 1, 79,
+ 0, 0, 0, 35, 0, 0, 1, 75, 0, 0, 1,247, 0, 0, 0, 35, 0, 0, 1, 79, 0, 0, 1,247, 0, 0, 0, 35, 0, 0, 1, 78,
+ 0, 0, 1,246, 0, 0, 0, 35, 0, 0, 1, 77, 0, 0, 1,246, 0, 0, 0, 35, 0, 0, 1, 77, 0, 0, 1, 78, 0, 0, 0, 35,
+ 0, 0, 0,228, 0, 0, 1,248, 0, 0, 0, 35, 0, 0, 0,228, 0, 0, 0,232, 0, 0, 0, 35, 0, 0, 0,232, 0, 0, 1,248,
+ 0, 0, 0, 35, 0, 0, 1,248, 0, 0, 1,249, 0, 0, 0, 35, 0, 0, 1,249, 0, 0, 1,250, 0, 0, 0, 35, 0, 0, 1,248,
+ 0, 0, 1,250, 0, 0, 0, 35, 0, 0, 0,229, 0, 0, 1, 78, 0, 0, 0, 35, 0, 0, 0,229, 0, 0, 1,250, 0, 0, 0, 35,
+ 0, 0, 1, 78, 0, 0, 1,250, 0, 0, 0, 35, 0, 0, 1, 79, 0, 0, 1,249, 0, 0, 0, 35, 0, 0, 0,233, 0, 0, 1,249,
+ 0, 0, 0, 35, 0, 0, 0,233, 0, 0, 1, 79, 0, 0, 0, 35, 0, 0, 0,227, 0, 0, 1,251, 0, 0, 0, 35, 0, 0, 0,227,
+ 0, 0, 1, 77, 0, 0, 0, 35, 0, 0, 1, 77, 0, 0, 1,251, 0, 0, 0, 35, 0, 0, 1,251, 0, 0, 1,252, 0, 0, 0, 35,
+ 0, 0, 1,252, 0, 0, 1,253, 0, 0, 0, 35, 0, 0, 1,251, 0, 0, 1,253, 0, 0, 0, 35, 0, 0, 0,194, 0, 0, 0,226,
+ 0, 0, 0, 35, 0, 0, 0,226, 0, 0, 1,253, 0, 0, 0, 35, 0, 0, 0,194, 0, 0, 1,253, 0, 0, 0, 35, 0, 0, 0,195,
+ 0, 0, 1,252, 0, 0, 0, 35, 0, 0, 1, 76, 0, 0, 1,252, 0, 0, 0, 35, 0, 0, 0,195, 0, 0, 1, 76, 0, 0, 0, 35,
+ 0, 0, 1, 81, 0, 0, 1,254, 0, 0, 0, 35, 0, 0, 0,239, 0, 0, 1, 81, 0, 0, 0, 35, 0, 0, 0,239, 0, 0, 1,254,
+ 0, 0, 0, 35, 0, 0, 1,254, 0, 0, 1,255, 0, 0, 0, 35, 0, 0, 1,255, 0, 0, 2, 0, 0, 0, 0, 35, 0, 0, 1,254,
+ 0, 0, 2, 0, 0, 0, 0, 35, 0, 0, 0,201, 0, 0, 1, 80, 0, 0, 0, 35, 0, 0, 1, 80, 0, 0, 2, 0, 0, 0, 0, 35,
+ 0, 0, 0,201, 0, 0, 2, 0, 0, 0, 0, 35, 0, 0, 0,200, 0, 0, 1,255, 0, 0, 0, 35, 0, 0, 0,238, 0, 0, 1,255,
+ 0, 0, 0, 35, 0, 0, 0,200, 0, 0, 0,238, 0, 0, 0, 35, 0, 0, 1, 80, 0, 0, 2, 1, 0, 0, 0, 35, 0, 0, 1, 80,
+ 0, 0, 1, 82, 0, 0, 0, 35, 0, 0, 1, 82, 0, 0, 2, 1, 0, 0, 0, 35, 0, 0, 2, 1, 0, 0, 2, 2, 0, 0, 0, 35,
+ 0, 0, 2, 2, 0, 0, 2, 3, 0, 0, 0, 35, 0, 0, 2, 1, 0, 0, 2, 3, 0, 0, 0, 35, 0, 0, 1, 81, 0, 0, 1, 85,
+ 0, 0, 0, 35, 0, 0, 1, 81, 0, 0, 2, 3, 0, 0, 0, 35, 0, 0, 1, 85, 0, 0, 2, 3, 0, 0, 0, 35, 0, 0, 1, 84,
+ 0, 0, 2, 2, 0, 0, 0, 35, 0, 0, 1, 83, 0, 0, 2, 2, 0, 0, 0, 35, 0, 0, 1, 83, 0, 0, 1, 84, 0, 0, 0, 35,
+ 0, 0, 0,236, 0, 0, 2, 4, 0, 0, 0, 35, 0, 0, 0,236, 0, 0, 0,240, 0, 0, 0, 35, 0, 0, 0,240, 0, 0, 2, 4,
+ 0, 0, 0, 35, 0, 0, 2, 4, 0, 0, 2, 5, 0, 0, 0, 35, 0, 0, 2, 5, 0, 0, 2, 6, 0, 0, 0, 35, 0, 0, 2, 4,
+ 0, 0, 2, 6, 0, 0, 0, 35, 0, 0, 0,237, 0, 0, 1, 84, 0, 0, 0, 35, 0, 0, 0,237, 0, 0, 2, 6, 0, 0, 0, 35,
+ 0, 0, 1, 84, 0, 0, 2, 6, 0, 0, 0, 35, 0, 0, 1, 85, 0, 0, 2, 5, 0, 0, 0, 35, 0, 0, 0,241, 0, 0, 2, 5,
+ 0, 0, 0, 35, 0, 0, 0,241, 0, 0, 1, 85, 0, 0, 0, 35, 0, 0, 0,235, 0, 0, 2, 7, 0, 0, 0, 35, 0, 0, 0,235,
+ 0, 0, 1, 83, 0, 0, 0, 35, 0, 0, 1, 83, 0, 0, 2, 7, 0, 0, 0, 35, 0, 0, 2, 7, 0, 0, 2, 8, 0, 0, 0, 35,
+ 0, 0, 2, 8, 0, 0, 2, 9, 0, 0, 0, 35, 0, 0, 2, 7, 0, 0, 2, 9, 0, 0, 0, 35, 0, 0, 0,198, 0, 0, 0,234,
+ 0, 0, 0, 35, 0, 0, 0,234, 0, 0, 2, 9, 0, 0, 0, 35, 0, 0, 0,198, 0, 0, 2, 9, 0, 0, 0, 35, 0, 0, 0,199,
+ 0, 0, 2, 8, 0, 0, 0, 35, 0, 0, 1, 82, 0, 0, 2, 8, 0, 0, 0, 35, 0, 0, 0,199, 0, 0, 1, 82, 0, 0, 0, 35,
+ 0, 0, 1, 87, 0, 0, 2, 10, 0, 0, 0, 35, 0, 0, 0,245, 0, 0, 2, 10, 0, 0, 0, 35, 0, 0, 0,245, 0, 0, 1, 87,
+ 0, 0, 0, 35, 0, 0, 2, 10, 0, 0, 2, 11, 0, 0, 0, 35, 0, 0, 2, 10, 0, 0, 2, 12, 0, 0, 0, 35, 0, 0, 2, 11,
+ 0, 0, 2, 12, 0, 0, 0, 35, 0, 0, 0,209, 0, 0, 1, 86, 0, 0, 0, 35, 0, 0, 0,209, 0, 0, 2, 12, 0, 0, 0, 35,
+ 0, 0, 1, 86, 0, 0, 2, 12, 0, 0, 0, 35, 0, 0, 0,208, 0, 0, 2, 11, 0, 0, 0, 35, 0, 0, 0,208, 0, 0, 0,244,
+ 0, 0, 0, 35, 0, 0, 0,244, 0, 0, 2, 11, 0, 0, 0, 35, 0, 0, 1, 86, 0, 0, 2, 13, 0, 0, 0, 35, 0, 0, 1, 88,
+ 0, 0, 2, 13, 0, 0, 0, 35, 0, 0, 1, 86, 0, 0, 1, 88, 0, 0, 0, 35, 0, 0, 2, 13, 0, 0, 2, 14, 0, 0, 0, 35,
+ 0, 0, 2, 13, 0, 0, 2, 15, 0, 0, 0, 35, 0, 0, 2, 14, 0, 0, 2, 15, 0, 0, 0, 35, 0, 0, 1, 87, 0, 0, 1, 91,
+ 0, 0, 0, 35, 0, 0, 1, 91, 0, 0, 2, 15, 0, 0, 0, 35, 0, 0, 1, 87, 0, 0, 2, 15, 0, 0, 0, 35, 0, 0, 1, 90,
+ 0, 0, 2, 14, 0, 0, 0, 35, 0, 0, 1, 89, 0, 0, 1, 90, 0, 0, 0, 35, 0, 0, 1, 89, 0, 0, 2, 14, 0, 0, 0, 35,
+ 0, 0, 0,212, 0, 0, 2, 16, 0, 0, 0, 35, 0, 0, 0,242, 0, 0, 2, 16, 0, 0, 0, 35, 0, 0, 0,212, 0, 0, 0,242,
+ 0, 0, 0, 35, 0, 0, 2, 16, 0, 0, 2, 17, 0, 0, 0, 35, 0, 0, 2, 16, 0, 0, 2, 18, 0, 0, 0, 35, 0, 0, 2, 17,
+ 0, 0, 2, 18, 0, 0, 0, 35, 0, 0, 0,213, 0, 0, 1, 90, 0, 0, 0, 35, 0, 0, 1, 90, 0, 0, 2, 18, 0, 0, 0, 35,
+ 0, 0, 0,213, 0, 0, 2, 18, 0, 0, 0, 35, 0, 0, 1, 91, 0, 0, 2, 17, 0, 0, 0, 35, 0, 0, 0,243, 0, 0, 1, 91,
+ 0, 0, 0, 35, 0, 0, 0,243, 0, 0, 2, 17, 0, 0, 0, 35, 0, 0, 0,211, 0, 0, 2, 19, 0, 0, 0, 35, 0, 0, 1, 89,
+ 0, 0, 2, 19, 0, 0, 0, 35, 0, 0, 0,211, 0, 0, 1, 89, 0, 0, 0, 35, 0, 0, 2, 19, 0, 0, 2, 20, 0, 0, 0, 35,
+ 0, 0, 2, 19, 0, 0, 2, 21, 0, 0, 0, 35, 0, 0, 2, 20, 0, 0, 2, 21, 0, 0, 0, 35, 0, 0, 0,206, 0, 0, 0,210,
+ 0, 0, 0, 35, 0, 0, 0,206, 0, 0, 2, 21, 0, 0, 0, 35, 0, 0, 0,210, 0, 0, 2, 21, 0, 0, 0, 35, 0, 0, 0,207,
+ 0, 0, 2, 20, 0, 0, 0, 35, 0, 0, 0,207, 0, 0, 1, 88, 0, 0, 0, 35, 0, 0, 1, 88, 0, 0, 2, 20, 0, 0, 0, 35,
+ 0, 0, 1, 93, 0, 0, 2, 22, 0, 0, 0, 35, 0, 0, 0,247, 0, 0, 2, 22, 0, 0, 0, 35, 0, 0, 0,247, 0, 0, 1, 93,
+ 0, 0, 0, 35, 0, 0, 2, 22, 0, 0, 2, 23, 0, 0, 0, 35, 0, 0, 2, 22, 0, 0, 2, 24, 0, 0, 0, 35, 0, 0, 2, 23,
+ 0, 0, 2, 24, 0, 0, 0, 35, 0, 0, 0,217, 0, 0, 1, 92, 0, 0, 0, 35, 0, 0, 0,217, 0, 0, 2, 24, 0, 0, 0, 35,
+ 0, 0, 1, 92, 0, 0, 2, 24, 0, 0, 0, 35, 0, 0, 0,216, 0, 0, 2, 23, 0, 0, 0, 35, 0, 0, 0,216, 0, 0, 0,246,
+ 0, 0, 0, 35, 0, 0, 0,246, 0, 0, 2, 23, 0, 0, 0, 35, 0, 0, 1, 92, 0, 0, 2, 25, 0, 0, 0, 35, 0, 0, 1, 94,
+ 0, 0, 2, 25, 0, 0, 0, 35, 0, 0, 1, 92, 0, 0, 1, 94, 0, 0, 0, 35, 0, 0, 2, 25, 0, 0, 2, 26, 0, 0, 0, 35,
+ 0, 0, 2, 25, 0, 0, 2, 27, 0, 0, 0, 35, 0, 0, 2, 26, 0, 0, 2, 27, 0, 0, 0, 35, 0, 0, 1, 93, 0, 0, 1, 97,
+ 0, 0, 0, 35, 0, 0, 1, 97, 0, 0, 2, 27, 0, 0, 0, 35, 0, 0, 1, 93, 0, 0, 2, 27, 0, 0, 0, 35, 0, 0, 1, 96,
+ 0, 0, 2, 26, 0, 0, 0, 35, 0, 0, 1, 95, 0, 0, 1, 96, 0, 0, 0, 35, 0, 0, 1, 95, 0, 0, 2, 26, 0, 0, 0, 35,
+ 0, 0, 0,220, 0, 0, 2, 28, 0, 0, 0, 35, 0, 0, 0,248, 0, 0, 2, 28, 0, 0, 0, 35, 0, 0, 0,220, 0, 0, 0,248,
+ 0, 0, 0, 35, 0, 0, 2, 28, 0, 0, 2, 29, 0, 0, 0, 35, 0, 0, 2, 28, 0, 0, 2, 30, 0, 0, 0, 35, 0, 0, 2, 29,
+ 0, 0, 2, 30, 0, 0, 0, 35, 0, 0, 0,221, 0, 0, 1, 96, 0, 0, 0, 35, 0, 0, 1, 96, 0, 0, 2, 30, 0, 0, 0, 35,
+ 0, 0, 0,221, 0, 0, 2, 30, 0, 0, 0, 35, 0, 0, 1, 97, 0, 0, 2, 29, 0, 0, 0, 35, 0, 0, 0,249, 0, 0, 1, 97,
+ 0, 0, 0, 35, 0, 0, 0,249, 0, 0, 2, 29, 0, 0, 0, 35, 0, 0, 0,219, 0, 0, 2, 31, 0, 0, 0, 35, 0, 0, 1, 95,
+ 0, 0, 2, 31, 0, 0, 0, 35, 0, 0, 0,219, 0, 0, 1, 95, 0, 0, 0, 35, 0, 0, 2, 31, 0, 0, 2, 32, 0, 0, 0, 35,
+ 0, 0, 2, 31, 0, 0, 2, 33, 0, 0, 0, 35, 0, 0, 2, 32, 0, 0, 2, 33, 0, 0, 0, 35, 0, 0, 0,214, 0, 0, 0,218,
+ 0, 0, 0, 35, 0, 0, 0,214, 0, 0, 2, 33, 0, 0, 0, 35, 0, 0, 0,218, 0, 0, 2, 33, 0, 0, 0, 35, 0, 0, 0,215,
+ 0, 0, 2, 32, 0, 0, 0, 35, 0, 0, 0,215, 0, 0, 1, 94, 0, 0, 0, 35, 0, 0, 1, 94, 0, 0, 2, 32, 0, 0, 0, 35,
+ 0, 0, 1, 99, 0, 0, 2, 34, 0, 0, 0, 35, 0, 0, 0,251, 0, 0, 2, 34, 0, 0, 0, 35, 0, 0, 0,251, 0, 0, 1, 99,
+ 0, 0, 0, 35, 0, 0, 2, 34, 0, 0, 2, 35, 0, 0, 0, 35, 0, 0, 2, 34, 0, 0, 2, 36, 0, 0, 0, 35, 0, 0, 2, 35,
+ 0, 0, 2, 36, 0, 0, 0, 35, 0, 0, 0,225, 0, 0, 1, 98, 0, 0, 0, 35, 0, 0, 0,225, 0, 0, 2, 36, 0, 0, 0, 35,
+ 0, 0, 1, 98, 0, 0, 2, 36, 0, 0, 0, 35, 0, 0, 0,224, 0, 0, 2, 35, 0, 0, 0, 35, 0, 0, 0,224, 0, 0, 0,250,
+ 0, 0, 0, 35, 0, 0, 0,250, 0, 0, 2, 35, 0, 0, 0, 35, 0, 0, 1, 98, 0, 0, 2, 37, 0, 0, 0, 35, 0, 0, 1,100,
+ 0, 0, 2, 37, 0, 0, 0, 35, 0, 0, 1, 98, 0, 0, 1,100, 0, 0, 0, 35, 0, 0, 2, 37, 0, 0, 2, 38, 0, 0, 0, 35,
+ 0, 0, 2, 37, 0, 0, 2, 39, 0, 0, 0, 35, 0, 0, 2, 38, 0, 0, 2, 39, 0, 0, 0, 35, 0, 0, 1, 99, 0, 0, 1,103,
+ 0, 0, 0, 35, 0, 0, 1,103, 0, 0, 2, 39, 0, 0, 0, 35, 0, 0, 1, 99, 0, 0, 2, 39, 0, 0, 0, 35, 0, 0, 1,102,
+ 0, 0, 2, 38, 0, 0, 0, 35, 0, 0, 1,101, 0, 0, 1,102, 0, 0, 0, 35, 0, 0, 1,101, 0, 0, 2, 38, 0, 0, 0, 35,
+ 0, 0, 0,228, 0, 0, 2, 40, 0, 0, 0, 35, 0, 0, 0,252, 0, 0, 2, 40, 0, 0, 0, 35, 0, 0, 0,228, 0, 0, 0,252,
+ 0, 0, 0, 35, 0, 0, 2, 40, 0, 0, 2, 41, 0, 0, 0, 35, 0, 0, 2, 40, 0, 0, 2, 42, 0, 0, 0, 35, 0, 0, 2, 41,
+ 0, 0, 2, 42, 0, 0, 0, 35, 0, 0, 0,229, 0, 0, 1,102, 0, 0, 0, 35, 0, 0, 1,102, 0, 0, 2, 42, 0, 0, 0, 35,
+ 0, 0, 0,229, 0, 0, 2, 42, 0, 0, 0, 35, 0, 0, 1,103, 0, 0, 2, 41, 0, 0, 0, 35, 0, 0, 0,253, 0, 0, 1,103,
+ 0, 0, 0, 35, 0, 0, 0,253, 0, 0, 2, 41, 0, 0, 0, 35, 0, 0, 0,227, 0, 0, 2, 43, 0, 0, 0, 35, 0, 0, 1,101,
+ 0, 0, 2, 43, 0, 0, 0, 35, 0, 0, 0,227, 0, 0, 1,101, 0, 0, 0, 35, 0, 0, 2, 43, 0, 0, 2, 44, 0, 0, 0, 35,
+ 0, 0, 2, 43, 0, 0, 2, 45, 0, 0, 0, 35, 0, 0, 2, 44, 0, 0, 2, 45, 0, 0, 0, 35, 0, 0, 0,222, 0, 0, 0,226,
+ 0, 0, 0, 35, 0, 0, 0,222, 0, 0, 2, 45, 0, 0, 0, 35, 0, 0, 0,226, 0, 0, 2, 45, 0, 0, 0, 35, 0, 0, 0,223,
+ 0, 0, 2, 44, 0, 0, 0, 35, 0, 0, 0,223, 0, 0, 1,100, 0, 0, 0, 35, 0, 0, 1,100, 0, 0, 2, 44, 0, 0, 0, 35,
+ 0, 0, 1,105, 0, 0, 2, 46, 0, 0, 0, 35, 0, 0, 0,255, 0, 0, 2, 46, 0, 0, 0, 35, 0, 0, 0,255, 0, 0, 1,105,
+ 0, 0, 0, 35, 0, 0, 2, 46, 0, 0, 2, 47, 0, 0, 0, 35, 0, 0, 2, 46, 0, 0, 2, 48, 0, 0, 0, 35, 0, 0, 2, 47,
+ 0, 0, 2, 48, 0, 0, 0, 35, 0, 0, 0,233, 0, 0, 1,104, 0, 0, 0, 35, 0, 0, 0,233, 0, 0, 2, 48, 0, 0, 0, 35,
+ 0, 0, 1,104, 0, 0, 2, 48, 0, 0, 0, 35, 0, 0, 0,232, 0, 0, 2, 47, 0, 0, 0, 35, 0, 0, 0,232, 0, 0, 0,254,
+ 0, 0, 0, 35, 0, 0, 0,254, 0, 0, 2, 47, 0, 0, 0, 35, 0, 0, 1,104, 0, 0, 2, 49, 0, 0, 0, 35, 0, 0, 1,106,
+ 0, 0, 2, 49, 0, 0, 0, 35, 0, 0, 1,104, 0, 0, 1,106, 0, 0, 0, 35, 0, 0, 2, 49, 0, 0, 2, 50, 0, 0, 0, 35,
+ 0, 0, 2, 49, 0, 0, 2, 51, 0, 0, 0, 35, 0, 0, 2, 50, 0, 0, 2, 51, 0, 0, 0, 35, 0, 0, 1,105, 0, 0, 1,109,
+ 0, 0, 0, 35, 0, 0, 1,109, 0, 0, 2, 51, 0, 0, 0, 35, 0, 0, 1,105, 0, 0, 2, 51, 0, 0, 0, 35, 0, 0, 1,108,
+ 0, 0, 2, 50, 0, 0, 0, 35, 0, 0, 1,107, 0, 0, 1,108, 0, 0, 0, 35, 0, 0, 1,107, 0, 0, 2, 50, 0, 0, 0, 35,
+ 0, 0, 0,236, 0, 0, 2, 52, 0, 0, 0, 35, 0, 0, 1, 0, 0, 0, 2, 52, 0, 0, 0, 35, 0, 0, 0,236, 0, 0, 1, 0,
+ 0, 0, 0, 35, 0, 0, 2, 52, 0, 0, 2, 53, 0, 0, 0, 35, 0, 0, 2, 52, 0, 0, 2, 54, 0, 0, 0, 35, 0, 0, 2, 53,
+ 0, 0, 2, 54, 0, 0, 0, 35, 0, 0, 0,237, 0, 0, 1,108, 0, 0, 0, 35, 0, 0, 1,108, 0, 0, 2, 54, 0, 0, 0, 35,
+ 0, 0, 0,237, 0, 0, 2, 54, 0, 0, 0, 35, 0, 0, 1,109, 0, 0, 2, 53, 0, 0, 0, 35, 0, 0, 1, 1, 0, 0, 1,109,
+ 0, 0, 0, 35, 0, 0, 1, 1, 0, 0, 2, 53, 0, 0, 0, 35, 0, 0, 0,235, 0, 0, 2, 55, 0, 0, 0, 35, 0, 0, 1,107,
+ 0, 0, 2, 55, 0, 0, 0, 35, 0, 0, 0,235, 0, 0, 1,107, 0, 0, 0, 35, 0, 0, 2, 55, 0, 0, 2, 56, 0, 0, 0, 35,
+ 0, 0, 2, 55, 0, 0, 2, 57, 0, 0, 0, 35, 0, 0, 2, 56, 0, 0, 2, 57, 0, 0, 0, 35, 0, 0, 0,230, 0, 0, 0,234,
+ 0, 0, 0, 35, 0, 0, 0,230, 0, 0, 2, 57, 0, 0, 0, 35, 0, 0, 0,234, 0, 0, 2, 57, 0, 0, 0, 35, 0, 0, 0,231,
+ 0, 0, 2, 56, 0, 0, 0, 35, 0, 0, 0,231, 0, 0, 1,106, 0, 0, 0, 35, 0, 0, 1,106, 0, 0, 2, 56, 0, 0, 0, 35,
+ 0, 0, 1,111, 0, 0, 2, 58, 0, 0, 0, 35, 0, 0, 1, 3, 0, 0, 2, 58, 0, 0, 0, 35, 0, 0, 1, 3, 0, 0, 1,111,
+ 0, 0, 0, 35, 0, 0, 2, 58, 0, 0, 2, 59, 0, 0, 0, 35, 0, 0, 2, 58, 0, 0, 2, 60, 0, 0, 0, 35, 0, 0, 2, 59,
+ 0, 0, 2, 60, 0, 0, 0, 35, 0, 0, 0,241, 0, 0, 1,110, 0, 0, 0, 35, 0, 0, 0,241, 0, 0, 2, 60, 0, 0, 0, 35,
+ 0, 0, 1,110, 0, 0, 2, 60, 0, 0, 0, 35, 0, 0, 0,240, 0, 0, 2, 59, 0, 0, 0, 35, 0, 0, 0,240, 0, 0, 1, 2,
+ 0, 0, 0, 35, 0, 0, 1, 2, 0, 0, 2, 59, 0, 0, 0, 35, 0, 0, 1,110, 0, 0, 2, 61, 0, 0, 0, 35, 0, 0, 1,113,
+ 0, 0, 2, 61, 0, 0, 0, 35, 0, 0, 1,110, 0, 0, 1,113, 0, 0, 0, 35, 0, 0, 2, 61, 0, 0, 2, 62, 0, 0, 0, 35,
+ 0, 0, 2, 61, 0, 0, 2, 63, 0, 0, 0, 35, 0, 0, 2, 62, 0, 0, 2, 63, 0, 0, 0, 35, 0, 0, 1,111, 0, 0, 1,115,
+ 0, 0, 0, 35, 0, 0, 1,115, 0, 0, 2, 63, 0, 0, 0, 35, 0, 0, 1,111, 0, 0, 2, 63, 0, 0, 0, 35, 0, 0, 1,114,
+ 0, 0, 2, 62, 0, 0, 0, 35, 0, 0, 1,112, 0, 0, 1,114, 0, 0, 0, 35, 0, 0, 1,112, 0, 0, 2, 62, 0, 0, 0, 35,
+ 0, 0, 0,204, 0, 0, 2, 64, 0, 0, 0, 35, 0, 0, 1, 4, 0, 0, 2, 64, 0, 0, 0, 35, 0, 0, 0,204, 0, 0, 1, 4,
+ 0, 0, 0, 35, 0, 0, 2, 64, 0, 0, 2, 65, 0, 0, 0, 35, 0, 0, 2, 64, 0, 0, 2, 66, 0, 0, 0, 35, 0, 0, 2, 65,
+ 0, 0, 2, 66, 0, 0, 0, 35, 0, 0, 0,205, 0, 0, 1,114, 0, 0, 0, 35, 0, 0, 1,114, 0, 0, 2, 66, 0, 0, 0, 35,
+ 0, 0, 0,205, 0, 0, 2, 66, 0, 0, 0, 35, 0, 0, 1,115, 0, 0, 2, 65, 0, 0, 0, 35, 0, 0, 1, 5, 0, 0, 1,115,
+ 0, 0, 0, 35, 0, 0, 1, 5, 0, 0, 2, 65, 0, 0, 0, 35, 0, 0, 0,203, 0, 0, 2, 67, 0, 0, 0, 35, 0, 0, 1,112,
+ 0, 0, 2, 67, 0, 0, 0, 35, 0, 0, 0,203, 0, 0, 1,112, 0, 0, 0, 35, 0, 0, 2, 67, 0, 0, 2, 68, 0, 0, 0, 35,
+ 0, 0, 2, 67, 0, 0, 2, 69, 0, 0, 0, 35, 0, 0, 2, 68, 0, 0, 2, 69, 0, 0, 0, 35, 0, 0, 0,202, 0, 0, 0,238,
+ 0, 0, 0, 35, 0, 0, 0,238, 0, 0, 2, 69, 0, 0, 0, 35, 0, 0, 0,202, 0, 0, 2, 69, 0, 0, 0, 35, 0, 0, 0,239,
+ 0, 0, 2, 68, 0, 0, 0, 35, 0, 0, 0,239, 0, 0, 1,113, 0, 0, 0, 35, 0, 0, 1,113, 0, 0, 2, 68, 0, 0, 0, 35,
+ 0, 0, 1,117, 0, 0, 2, 70, 0, 0, 0, 35, 0, 0, 1, 11, 0, 0, 1,117, 0, 0, 0, 35, 0, 0, 1, 11, 0, 0, 2, 70,
+ 0, 0, 0, 35, 0, 0, 2, 70, 0, 0, 2, 71, 0, 0, 0, 35, 0, 0, 2, 71, 0, 0, 2, 72, 0, 0, 0, 35, 0, 0, 2, 70,
+ 0, 0, 2, 72, 0, 0, 0, 35, 0, 0, 0,243, 0, 0, 1,116, 0, 0, 0, 35, 0, 0, 1,116, 0, 0, 2, 72, 0, 0, 0, 35,
+ 0, 0, 0,243, 0, 0, 2, 72, 0, 0, 0, 35, 0, 0, 0,242, 0, 0, 2, 71, 0, 0, 0, 35, 0, 0, 1, 10, 0, 0, 2, 71,
+ 0, 0, 0, 35, 0, 0, 0,242, 0, 0, 1, 10, 0, 0, 0, 35, 0, 0, 1,116, 0, 0, 2, 73, 0, 0, 0, 35, 0, 0, 1,116,
+ 0, 0, 1,118, 0, 0, 0, 35, 0, 0, 1,118, 0, 0, 2, 73, 0, 0, 0, 35, 0, 0, 2, 73, 0, 0, 2, 74, 0, 0, 0, 35,
+ 0, 0, 2, 74, 0, 0, 2, 75, 0, 0, 0, 35, 0, 0, 2, 73, 0, 0, 2, 75, 0, 0, 0, 35, 0, 0, 1,117, 0, 0, 1,121,
+ 0, 0, 0, 35, 0, 0, 1,117, 0, 0, 2, 75, 0, 0, 0, 35, 0, 0, 1,121, 0, 0, 2, 75, 0, 0, 0, 35, 0, 0, 1,120,
+ 0, 0, 2, 74, 0, 0, 0, 35, 0, 0, 1,119, 0, 0, 2, 74, 0, 0, 0, 35, 0, 0, 1,119, 0, 0, 1,120, 0, 0, 0, 35,
+ 0, 0, 1, 8, 0, 0, 2, 76, 0, 0, 0, 35, 0, 0, 1, 8, 0, 0, 1, 12, 0, 0, 0, 35, 0, 0, 1, 12, 0, 0, 2, 76,
+ 0, 0, 0, 35, 0, 0, 2, 76, 0, 0, 2, 77, 0, 0, 0, 35, 0, 0, 2, 77, 0, 0, 2, 78, 0, 0, 0, 35, 0, 0, 2, 76,
+ 0, 0, 2, 78, 0, 0, 0, 35, 0, 0, 1, 9, 0, 0, 1,120, 0, 0, 0, 35, 0, 0, 1, 9, 0, 0, 2, 78, 0, 0, 0, 35,
+ 0, 0, 1,120, 0, 0, 2, 78, 0, 0, 0, 35, 0, 0, 1,121, 0, 0, 2, 77, 0, 0, 0, 35, 0, 0, 1, 13, 0, 0, 2, 77,
+ 0, 0, 0, 35, 0, 0, 1, 13, 0, 0, 1,121, 0, 0, 0, 35, 0, 0, 1, 7, 0, 0, 2, 79, 0, 0, 0, 35, 0, 0, 1, 7,
+ 0, 0, 1,119, 0, 0, 0, 35, 0, 0, 1,119, 0, 0, 2, 79, 0, 0, 0, 35, 0, 0, 2, 79, 0, 0, 2, 80, 0, 0, 0, 35,
+ 0, 0, 2, 80, 0, 0, 2, 81, 0, 0, 0, 35, 0, 0, 2, 79, 0, 0, 2, 81, 0, 0, 0, 35, 0, 0, 0,244, 0, 0, 1, 6,
+ 0, 0, 0, 35, 0, 0, 1, 6, 0, 0, 2, 81, 0, 0, 0, 35, 0, 0, 0,244, 0, 0, 2, 81, 0, 0, 0, 35, 0, 0, 0,245,
+ 0, 0, 2, 80, 0, 0, 0, 35, 0, 0, 1,118, 0, 0, 2, 80, 0, 0, 0, 35, 0, 0, 0,245, 0, 0, 1,118, 0, 0, 0, 35,
+ 0, 0, 1,123, 0, 0, 2, 82, 0, 0, 0, 35, 0, 0, 1, 15, 0, 0, 1,123, 0, 0, 0, 35, 0, 0, 1, 15, 0, 0, 2, 82,
+ 0, 0, 0, 35, 0, 0, 2, 82, 0, 0, 2, 83, 0, 0, 0, 35, 0, 0, 2, 83, 0, 0, 2, 84, 0, 0, 0, 35, 0, 0, 2, 82,
+ 0, 0, 2, 84, 0, 0, 0, 35, 0, 0, 0,249, 0, 0, 1,122, 0, 0, 0, 35, 0, 0, 1,122, 0, 0, 2, 84, 0, 0, 0, 35,
+ 0, 0, 0,249, 0, 0, 2, 84, 0, 0, 0, 35, 0, 0, 0,248, 0, 0, 2, 83, 0, 0, 0, 35, 0, 0, 1, 14, 0, 0, 2, 83,
+ 0, 0, 0, 35, 0, 0, 0,248, 0, 0, 1, 14, 0, 0, 0, 35, 0, 0, 1,122, 0, 0, 2, 85, 0, 0, 0, 35, 0, 0, 1,122,
+ 0, 0, 1,124, 0, 0, 0, 35, 0, 0, 1,124, 0, 0, 2, 85, 0, 0, 0, 35, 0, 0, 2, 85, 0, 0, 2, 86, 0, 0, 0, 35,
+ 0, 0, 2, 86, 0, 0, 2, 87, 0, 0, 0, 35, 0, 0, 2, 85, 0, 0, 2, 87, 0, 0, 0, 35, 0, 0, 1,123, 0, 0, 1,127,
+ 0, 0, 0, 35, 0, 0, 1,123, 0, 0, 2, 87, 0, 0, 0, 35, 0, 0, 1,127, 0, 0, 2, 87, 0, 0, 0, 35, 0, 0, 1,126,
+ 0, 0, 2, 86, 0, 0, 0, 35, 0, 0, 1,125, 0, 0, 2, 86, 0, 0, 0, 35, 0, 0, 1,125, 0, 0, 1,126, 0, 0, 0, 35,
+ 0, 0, 1, 12, 0, 0, 2, 88, 0, 0, 0, 35, 0, 0, 1, 12, 0, 0, 1, 16, 0, 0, 0, 35, 0, 0, 1, 16, 0, 0, 2, 88,
+ 0, 0, 0, 35, 0, 0, 2, 88, 0, 0, 2, 89, 0, 0, 0, 35, 0, 0, 2, 89, 0, 0, 2, 90, 0, 0, 0, 35, 0, 0, 2, 88,
+ 0, 0, 2, 90, 0, 0, 0, 35, 0, 0, 1, 13, 0, 0, 1,126, 0, 0, 0, 35, 0, 0, 1, 13, 0, 0, 2, 90, 0, 0, 0, 35,
+ 0, 0, 1,126, 0, 0, 2, 90, 0, 0, 0, 35, 0, 0, 1,127, 0, 0, 2, 89, 0, 0, 0, 35, 0, 0, 1, 17, 0, 0, 2, 89,
+ 0, 0, 0, 35, 0, 0, 1, 17, 0, 0, 1,127, 0, 0, 0, 35, 0, 0, 1, 11, 0, 0, 2, 91, 0, 0, 0, 35, 0, 0, 1, 11,
+ 0, 0, 1,125, 0, 0, 0, 35, 0, 0, 1,125, 0, 0, 2, 91, 0, 0, 0, 35, 0, 0, 2, 91, 0, 0, 2, 92, 0, 0, 0, 35,
+ 0, 0, 2, 92, 0, 0, 2, 93, 0, 0, 0, 35, 0, 0, 2, 91, 0, 0, 2, 93, 0, 0, 0, 35, 0, 0, 0,246, 0, 0, 1, 10,
+ 0, 0, 0, 35, 0, 0, 1, 10, 0, 0, 2, 93, 0, 0, 0, 35, 0, 0, 0,246, 0, 0, 2, 93, 0, 0, 0, 35, 0, 0, 0,247,
+ 0, 0, 2, 92, 0, 0, 0, 35, 0, 0, 1,124, 0, 0, 2, 92, 0, 0, 0, 35, 0, 0, 0,247, 0, 0, 1,124, 0, 0, 0, 35,
+ 0, 0, 1,129, 0, 0, 2, 94, 0, 0, 0, 35, 0, 0, 1, 19, 0, 0, 1,129, 0, 0, 0, 35, 0, 0, 1, 19, 0, 0, 2, 94,
+ 0, 0, 0, 35, 0, 0, 2, 94, 0, 0, 2, 95, 0, 0, 0, 35, 0, 0, 2, 95, 0, 0, 2, 96, 0, 0, 0, 35, 0, 0, 2, 94,
+ 0, 0, 2, 96, 0, 0, 0, 35, 0, 0, 0,253, 0, 0, 1,128, 0, 0, 0, 35, 0, 0, 1,128, 0, 0, 2, 96, 0, 0, 0, 35,
+ 0, 0, 0,253, 0, 0, 2, 96, 0, 0, 0, 35, 0, 0, 0,252, 0, 0, 2, 95, 0, 0, 0, 35, 0, 0, 1, 18, 0, 0, 2, 95,
+ 0, 0, 0, 35, 0, 0, 0,252, 0, 0, 1, 18, 0, 0, 0, 35, 0, 0, 1,128, 0, 0, 2, 97, 0, 0, 0, 35, 0, 0, 1,128,
+ 0, 0, 1,130, 0, 0, 0, 35, 0, 0, 1,130, 0, 0, 2, 97, 0, 0, 0, 35, 0, 0, 2, 97, 0, 0, 2, 98, 0, 0, 0, 35,
+ 0, 0, 2, 98, 0, 0, 2, 99, 0, 0, 0, 35, 0, 0, 2, 97, 0, 0, 2, 99, 0, 0, 0, 35, 0, 0, 1,129, 0, 0, 1,133,
+ 0, 0, 0, 35, 0, 0, 1,129, 0, 0, 2, 99, 0, 0, 0, 35, 0, 0, 1,133, 0, 0, 2, 99, 0, 0, 0, 35, 0, 0, 1,132,
+ 0, 0, 2, 98, 0, 0, 0, 35, 0, 0, 1,131, 0, 0, 2, 98, 0, 0, 0, 35, 0, 0, 1,131, 0, 0, 1,132, 0, 0, 0, 35,
+ 0, 0, 1, 16, 0, 0, 2,100, 0, 0, 0, 35, 0, 0, 1, 16, 0, 0, 1, 20, 0, 0, 0, 35, 0, 0, 1, 20, 0, 0, 2,100,
+ 0, 0, 0, 35, 0, 0, 2,100, 0, 0, 2,101, 0, 0, 0, 35, 0, 0, 2,101, 0, 0, 2,102, 0, 0, 0, 35, 0, 0, 2,100,
+ 0, 0, 2,102, 0, 0, 0, 35, 0, 0, 1, 17, 0, 0, 1,132, 0, 0, 0, 35, 0, 0, 1, 17, 0, 0, 2,102, 0, 0, 0, 35,
+ 0, 0, 1,132, 0, 0, 2,102, 0, 0, 0, 35, 0, 0, 1,133, 0, 0, 2,101, 0, 0, 0, 35, 0, 0, 1, 21, 0, 0, 2,101,
+ 0, 0, 0, 35, 0, 0, 1, 21, 0, 0, 1,133, 0, 0, 0, 35, 0, 0, 1, 15, 0, 0, 2,103, 0, 0, 0, 35, 0, 0, 1, 15,
+ 0, 0, 1,131, 0, 0, 0, 35, 0, 0, 1,131, 0, 0, 2,103, 0, 0, 0, 35, 0, 0, 2,103, 0, 0, 2,104, 0, 0, 0, 35,
+ 0, 0, 2,104, 0, 0, 2,105, 0, 0, 0, 35, 0, 0, 2,103, 0, 0, 2,105, 0, 0, 0, 35, 0, 0, 0,250, 0, 0, 1, 14,
+ 0, 0, 0, 35, 0, 0, 1, 14, 0, 0, 2,105, 0, 0, 0, 35, 0, 0, 0,250, 0, 0, 2,105, 0, 0, 0, 35, 0, 0, 0,251,
+ 0, 0, 2,104, 0, 0, 0, 35, 0, 0, 1,130, 0, 0, 2,104, 0, 0, 0, 35, 0, 0, 0,251, 0, 0, 1,130, 0, 0, 0, 35,
+ 0, 0, 1,135, 0, 0, 2,106, 0, 0, 0, 35, 0, 0, 1, 23, 0, 0, 1,135, 0, 0, 0, 35, 0, 0, 1, 23, 0, 0, 2,106,
+ 0, 0, 0, 35, 0, 0, 2,106, 0, 0, 2,107, 0, 0, 0, 35, 0, 0, 2,107, 0, 0, 2,108, 0, 0, 0, 35, 0, 0, 2,106,
+ 0, 0, 2,108, 0, 0, 0, 35, 0, 0, 1, 1, 0, 0, 1,134, 0, 0, 0, 35, 0, 0, 1,134, 0, 0, 2,108, 0, 0, 0, 35,
+ 0, 0, 1, 1, 0, 0, 2,108, 0, 0, 0, 35, 0, 0, 1, 0, 0, 0, 2,107, 0, 0, 0, 35, 0, 0, 1, 22, 0, 0, 2,107,
+ 0, 0, 0, 35, 0, 0, 1, 0, 0, 0, 1, 22, 0, 0, 0, 35, 0, 0, 1,134, 0, 0, 2,109, 0, 0, 0, 35, 0, 0, 1,134,
+ 0, 0, 1,136, 0, 0, 0, 35, 0, 0, 1,136, 0, 0, 2,109, 0, 0, 0, 35, 0, 0, 2,109, 0, 0, 2,110, 0, 0, 0, 35,
+ 0, 0, 2,110, 0, 0, 2,111, 0, 0, 0, 35, 0, 0, 2,109, 0, 0, 2,111, 0, 0, 0, 35, 0, 0, 1,135, 0, 0, 1,139,
+ 0, 0, 0, 35, 0, 0, 1,135, 0, 0, 2,111, 0, 0, 0, 35, 0, 0, 1,139, 0, 0, 2,111, 0, 0, 0, 35, 0, 0, 1,138,
+ 0, 0, 2,110, 0, 0, 0, 35, 0, 0, 1,137, 0, 0, 2,110, 0, 0, 0, 35, 0, 0, 1,137, 0, 0, 1,138, 0, 0, 0, 35,
+ 0, 0, 1, 20, 0, 0, 2,112, 0, 0, 0, 35, 0, 0, 1, 20, 0, 0, 1, 24, 0, 0, 0, 35, 0, 0, 1, 24, 0, 0, 2,112,
+ 0, 0, 0, 35, 0, 0, 2,112, 0, 0, 2,113, 0, 0, 0, 35, 0, 0, 2,113, 0, 0, 2,114, 0, 0, 0, 35, 0, 0, 2,112,
+ 0, 0, 2,114, 0, 0, 0, 35, 0, 0, 1, 21, 0, 0, 1,138, 0, 0, 0, 35, 0, 0, 1, 21, 0, 0, 2,114, 0, 0, 0, 35,
+ 0, 0, 1,138, 0, 0, 2,114, 0, 0, 0, 35, 0, 0, 1,139, 0, 0, 2,113, 0, 0, 0, 35, 0, 0, 1, 25, 0, 0, 2,113,
+ 0, 0, 0, 35, 0, 0, 1, 25, 0, 0, 1,139, 0, 0, 0, 35, 0, 0, 1, 19, 0, 0, 2,115, 0, 0, 0, 35, 0, 0, 1, 19,
+ 0, 0, 1,137, 0, 0, 0, 35, 0, 0, 1,137, 0, 0, 2,115, 0, 0, 0, 35, 0, 0, 2,115, 0, 0, 2,116, 0, 0, 0, 35,
+ 0, 0, 2,116, 0, 0, 2,117, 0, 0, 0, 35, 0, 0, 2,115, 0, 0, 2,117, 0, 0, 0, 35, 0, 0, 0,254, 0, 0, 1, 18,
+ 0, 0, 0, 35, 0, 0, 1, 18, 0, 0, 2,117, 0, 0, 0, 35, 0, 0, 0,254, 0, 0, 2,117, 0, 0, 0, 35, 0, 0, 0,255,
+ 0, 0, 2,116, 0, 0, 0, 35, 0, 0, 1,136, 0, 0, 2,116, 0, 0, 0, 35, 0, 0, 0,255, 0, 0, 1,136, 0, 0, 0, 35,
+ 0, 0, 1,141, 0, 0, 2,118, 0, 0, 0, 35, 0, 0, 1, 7, 0, 0, 1,141, 0, 0, 0, 35, 0, 0, 1, 7, 0, 0, 2,118,
+ 0, 0, 0, 35, 0, 0, 2,118, 0, 0, 2,119, 0, 0, 0, 35, 0, 0, 2,119, 0, 0, 2,120, 0, 0, 0, 35, 0, 0, 2,118,
+ 0, 0, 2,120, 0, 0, 0, 35, 0, 0, 1, 5, 0, 0, 1,140, 0, 0, 0, 35, 0, 0, 1,140, 0, 0, 2,120, 0, 0, 0, 35,
+ 0, 0, 1, 5, 0, 0, 2,120, 0, 0, 0, 35, 0, 0, 1, 4, 0, 0, 2,119, 0, 0, 0, 35, 0, 0, 1, 6, 0, 0, 2,119,
+ 0, 0, 0, 35, 0, 0, 1, 4, 0, 0, 1, 6, 0, 0, 0, 35, 0, 0, 1,140, 0, 0, 2,121, 0, 0, 0, 35, 0, 0, 1,140,
+ 0, 0, 1,142, 0, 0, 0, 35, 0, 0, 1,142, 0, 0, 2,121, 0, 0, 0, 35, 0, 0, 2,121, 0, 0, 2,122, 0, 0, 0, 35,
+ 0, 0, 2,122, 0, 0, 2,123, 0, 0, 0, 35, 0, 0, 2,121, 0, 0, 2,123, 0, 0, 0, 35, 0, 0, 1,141, 0, 0, 1,144,
+ 0, 0, 0, 35, 0, 0, 1,141, 0, 0, 2,123, 0, 0, 0, 35, 0, 0, 1,144, 0, 0, 2,123, 0, 0, 0, 35, 0, 0, 1,145,
+ 0, 0, 2,122, 0, 0, 0, 35, 0, 0, 1,143, 0, 0, 2,122, 0, 0, 0, 35, 0, 0, 1,143, 0, 0, 1,145, 0, 0, 0, 35,
+ 0, 0, 1, 24, 0, 0, 2,124, 0, 0, 0, 35, 0, 0, 1, 8, 0, 0, 1, 24, 0, 0, 0, 35, 0, 0, 1, 8, 0, 0, 2,124,
+ 0, 0, 0, 35, 0, 0, 2,124, 0, 0, 2,125, 0, 0, 0, 35, 0, 0, 2,125, 0, 0, 2,126, 0, 0, 0, 35, 0, 0, 2,124,
+ 0, 0, 2,126, 0, 0, 0, 35, 0, 0, 1, 25, 0, 0, 1,145, 0, 0, 0, 35, 0, 0, 1, 25, 0, 0, 2,126, 0, 0, 0, 35,
+ 0, 0, 1,145, 0, 0, 2,126, 0, 0, 0, 35, 0, 0, 1,144, 0, 0, 2,125, 0, 0, 0, 35, 0, 0, 1, 9, 0, 0, 2,125,
+ 0, 0, 0, 35, 0, 0, 1, 9, 0, 0, 1,144, 0, 0, 0, 35, 0, 0, 1, 23, 0, 0, 2,127, 0, 0, 0, 35, 0, 0, 1, 23,
+ 0, 0, 1,143, 0, 0, 0, 35, 0, 0, 1,143, 0, 0, 2,127, 0, 0, 0, 35, 0, 0, 2,127, 0, 0, 2,128, 0, 0, 0, 35,
+ 0, 0, 2,128, 0, 0, 2,129, 0, 0, 0, 35, 0, 0, 2,127, 0, 0, 2,129, 0, 0, 0, 35, 0, 0, 1, 2, 0, 0, 1, 22,
+ 0, 0, 0, 35, 0, 0, 1, 22, 0, 0, 2,129, 0, 0, 0, 35, 0, 0, 1, 2, 0, 0, 2,129, 0, 0, 0, 35, 0, 0, 1, 3,
+ 0, 0, 2,128, 0, 0, 0, 35, 0, 0, 1,142, 0, 0, 2,128, 0, 0, 0, 35, 0, 0, 1, 3, 0, 0, 1,142, 0, 0, 0, 35,
+ 68, 65, 84, 65, 0, 0, 1, 4, 2,236,247,176, 0, 0, 0,242, 0, 0, 0, 5, 0, 0, 0, 4, 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, 8,108, 16, 32, 0, 0, 0, 5, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 85, 86, 84,101,120, 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, 8,108,128, 32, 0, 0, 0, 6,
+ 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 67,111,108, 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, 8,109, 96, 32, 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, 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, 68, 65, 84, 65, 0, 0,100, 0,
+ 8,108, 16, 32, 0, 0, 0, 52, 0, 0, 5, 0, 0, 0, 1, 27, 0, 0, 0,102, 0, 0, 1,146, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1,146, 0, 0, 0,171, 0, 0, 1, 27, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 14, 0, 0, 1, 27, 0, 0, 0,171,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,171, 0, 0, 1,146, 0, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,147,
+ 0, 0, 0, 46, 0, 0, 1,146, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,146, 0, 0, 1,148, 0, 0, 1,147, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 43, 0, 0, 1,147, 0, 0, 1,148, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,148, 0, 0, 1,146,
+ 0, 0, 0,102, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 26, 0, 0, 0, 12, 0, 0, 0,165, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0,165, 0, 0, 1,148, 0, 0, 1, 26, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,102, 0, 0, 1, 26, 0, 0, 1,148,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,148, 0, 0, 0,165, 0, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,147,
+ 0, 0, 0, 43, 0, 0, 0,164, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,164, 0, 0, 0,170, 0, 0, 1,147, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 46, 0, 0, 1,147, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,170, 0, 0, 0,164,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 26, 0, 0, 0,102, 0, 0, 1,149, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1,149, 0, 0, 1, 28, 0, 0, 1, 26, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 12, 0, 0, 1, 26, 0, 0, 1, 28,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 28, 0, 0, 1,149, 0, 0, 0,103, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,150,
+ 0, 0, 0,103, 0, 0, 1,149, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,149, 0, 0, 1,151, 0, 0, 1,150, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,104, 0, 0, 1,150, 0, 0, 1,151, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,151, 0, 0, 1,149,
+ 0, 0, 0,102, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 27, 0, 0, 0, 14, 0, 0, 1, 31, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 31, 0, 0, 1,151, 0, 0, 1, 27, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,102, 0, 0, 1, 27, 0, 0, 1,151,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,151, 0, 0, 1, 31, 0, 0, 0,104, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,150,
+ 0, 0, 0,104, 0, 0, 1, 30, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 30, 0, 0, 1, 29, 0, 0, 1,150, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,103, 0, 0, 1,150, 0, 0, 1, 29, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 29, 0, 0, 1, 30,
+ 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,168, 0, 0, 0, 45, 0, 0, 1,152, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1,152, 0, 0, 0,172, 0, 0, 0,168, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 2, 0, 0, 0,168, 0, 0, 0,172,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,172, 0, 0, 1,152, 0, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,153,
+ 0, 0, 0, 47, 0, 0, 1,152, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,152, 0, 0, 1,154, 0, 0, 1,153, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,104, 0, 0, 1,153, 0, 0, 1,154, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,154, 0, 0, 1,152,
+ 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,169, 0, 0, 0, 13, 0, 0, 1, 30, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 30, 0, 0, 1,154, 0, 0, 0,169, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 45, 0, 0, 0,169, 0, 0, 1,154,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,154, 0, 0, 1, 30, 0, 0, 0,104, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,153,
+ 0, 0, 0,104, 0, 0, 1, 31, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 31, 0, 0, 0,173, 0, 0, 1,153, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 47, 0, 0, 1,153, 0, 0, 0,173, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,173, 0, 0, 1, 31,
+ 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,167, 0, 0, 0, 44, 0, 0, 1,155, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1,155, 0, 0, 1, 29, 0, 0, 0,167, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 13, 0, 0, 0,167, 0, 0, 1, 29,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 29, 0, 0, 1,155, 0, 0, 0,103, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,156,
+ 0, 0, 0,103, 0, 0, 1,155, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,155, 0, 0, 1,157, 0, 0, 1,156, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 42, 0, 0, 1,156, 0, 0, 1,157, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,157, 0, 0, 1,155,
+ 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,166, 0, 0, 0, 0, 0, 0, 0,162, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0,162, 0, 0, 1,157, 0, 0, 0,166, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 44, 0, 0, 0,166, 0, 0, 1,157,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,157, 0, 0, 0,162, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,156,
+ 0, 0, 0, 42, 0, 0, 0,163, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,163, 0, 0, 1, 28, 0, 0, 1,156, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,103, 0, 0, 1,156, 0, 0, 1, 28, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 28, 0, 0, 0,163,
+ 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,158, 0, 0, 0,105, 0, 0, 1, 33, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 33, 0, 0, 0,179, 0, 0, 1,158, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 50, 0, 0, 1,158, 0, 0, 0,179,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,179, 0, 0, 1, 33, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,158,
+ 0, 0, 0, 50, 0, 0, 1,159, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,159, 0, 0, 1,160, 0, 0, 1,158, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,105, 0, 0, 1,158, 0, 0, 1,160, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,160, 0, 0, 1,159,
+ 0, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,165, 0, 0, 0, 12, 0, 0, 1, 32, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 32, 0, 0, 1,160, 0, 0, 0,165, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 43, 0, 0, 0,165, 0, 0, 1,160,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,160, 0, 0, 1, 32, 0, 0, 0,105, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,164,
+ 0, 0, 0, 43, 0, 0, 1,159, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,159, 0, 0, 0,178, 0, 0, 0,164, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0,164, 0, 0, 0,178, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,178, 0, 0, 1,159,
+ 0, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,161, 0, 0, 0,105, 0, 0, 1, 32, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 32, 0, 0, 1, 34, 0, 0, 1,161, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,106, 0, 0, 1,161, 0, 0, 1, 34,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 34, 0, 0, 1, 32, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,161,
+ 0, 0, 0,106, 0, 0, 1,162, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,162, 0, 0, 1,163, 0, 0, 1,161, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,105, 0, 0, 1,161, 0, 0, 1,163, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,163, 0, 0, 1,162,
+ 0, 0, 0,107, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 37, 0, 0, 0, 16, 0, 0, 1, 33, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 33, 0, 0, 1,163, 0, 0, 1, 37, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,107, 0, 0, 1, 37, 0, 0, 1,163,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,163, 0, 0, 1, 33, 0, 0, 0,105, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 36,
+ 0, 0, 0,107, 0, 0, 1,162, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,162, 0, 0, 1, 35, 0, 0, 1, 36, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 15, 0, 0, 1, 36, 0, 0, 1, 35, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 35, 0, 0, 1,162,
+ 0, 0, 0,106, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,164, 0, 0, 0, 49, 0, 0, 0,176, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0,176, 0, 0, 0,180, 0, 0, 1,164, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 51, 0, 0, 1,164, 0, 0, 0,180,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,180, 0, 0, 0,176, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,164,
+ 0, 0, 0, 51, 0, 0, 1,165, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,165, 0, 0, 1,166, 0, 0, 1,164, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 49, 0, 0, 1,164, 0, 0, 1,166, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,166, 0, 0, 1,165,
+ 0, 0, 0,107, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 36, 0, 0, 0, 15, 0, 0, 0,177, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0,177, 0, 0, 1,166, 0, 0, 1, 36, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,107, 0, 0, 1, 36, 0, 0, 1,166,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,166, 0, 0, 0,177, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 37,
+ 0, 0, 0,107, 0, 0, 1,165, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,165, 0, 0, 0,181, 0, 0, 1, 37, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 16, 0, 0, 1, 37, 0, 0, 0,181, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,181, 0, 0, 1,165,
+ 0, 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,167, 0, 0, 0, 48, 0, 0, 0,175, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0,175, 0, 0, 1, 35, 0, 0, 1,167, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,106, 0, 0, 1,167, 0, 0, 1, 35,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 35, 0, 0, 0,175, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,167,
+ 0, 0, 0,106, 0, 0, 1,168, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,168, 0, 0, 1,169, 0, 0, 1,167, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 48, 0, 0, 1,167, 0, 0, 1,169, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,169, 0, 0, 1,168,
+ 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,162, 0, 0, 0, 0, 0, 0, 0,174, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0,174, 0, 0, 1,169, 0, 0, 0,162, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 42, 0, 0, 0,162, 0, 0, 1,169,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,169, 0, 0, 0,174, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,163,
+ 0, 0, 0, 42, 0, 0, 1,168, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,168, 0, 0, 1, 34, 0, 0, 0,163, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 12, 0, 0, 0,163, 0, 0, 1, 34, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 34, 0, 0, 1,168,
+ 0, 0, 0,106, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 39, 0, 0, 0,108, 0, 0, 1,170, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1,170, 0, 0, 0,187, 0, 0, 1, 39, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 18, 0, 0, 1, 39, 0, 0, 0,187,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,187, 0, 0, 1,170, 0, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,171,
+ 0, 0, 0, 54, 0, 0, 1,170, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,170, 0, 0, 1,172, 0, 0, 1,171, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 45, 0, 0, 1,171, 0, 0, 1,172, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,172, 0, 0, 1,170,
+ 0, 0, 0,108, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 38, 0, 0, 0, 13, 0, 0, 0,169, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0,169, 0, 0, 1,172, 0, 0, 1, 38, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,108, 0, 0, 1, 38, 0, 0, 1,172,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,172, 0, 0, 0,169, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,171,
+ 0, 0, 0, 45, 0, 0, 0,168, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,168, 0, 0, 0,186, 0, 0, 1,171, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 54, 0, 0, 1,171, 0, 0, 0,186, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,186, 0, 0, 0,168,
+ 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 38, 0, 0, 0,108, 0, 0, 1,173, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1,173, 0, 0, 1, 40, 0, 0, 1, 38, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 13, 0, 0, 1, 38, 0, 0, 1, 40,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 40, 0, 0, 1,173, 0, 0, 0,109, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,174,
+ 0, 0, 0,109, 0, 0, 1,173, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,173, 0, 0, 1,175, 0, 0, 1,174, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,110, 0, 0, 1,174, 0, 0, 1,175, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,175, 0, 0, 1,173,
+ 0, 0, 0,108, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 39, 0, 0, 0, 18, 0, 0, 1, 43, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 43, 0, 0, 1,175, 0, 0, 1, 39, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,108, 0, 0, 1, 39, 0, 0, 1,175,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,175, 0, 0, 1, 43, 0, 0, 0,110, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,174,
+ 0, 0, 0,110, 0, 0, 1, 42, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 42, 0, 0, 1, 41, 0, 0, 1,174, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,109, 0, 0, 1,174, 0, 0, 1, 41, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 41, 0, 0, 1, 42,
+ 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,184, 0, 0, 0, 53, 0, 0, 1,176, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1,176, 0, 0, 0,188, 0, 0, 0,184, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0,184, 0, 0, 0,188,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,188, 0, 0, 1,176, 0, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,177,
+ 0, 0, 0, 55, 0, 0, 1,176, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,176, 0, 0, 1,178, 0, 0, 1,177, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,110, 0, 0, 1,177, 0, 0, 1,178, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,178, 0, 0, 1,176,
+ 0, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,185, 0, 0, 0, 17, 0, 0, 1, 42, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 42, 0, 0, 1,178, 0, 0, 0,185, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 53, 0, 0, 0,185, 0, 0, 1,178,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,178, 0, 0, 1, 42, 0, 0, 0,110, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,177,
+ 0, 0, 0,110, 0, 0, 1, 43, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 43, 0, 0, 0,189, 0, 0, 1,177, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 55, 0, 0, 1,177, 0, 0, 0,189, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,189, 0, 0, 1, 43,
+ 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,183, 0, 0, 0, 52, 0, 0, 1,179, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1,179, 0, 0, 1, 41, 0, 0, 0,183, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 17, 0, 0, 0,183, 0, 0, 1, 41,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 41, 0, 0, 1,179, 0, 0, 0,109, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,180,
+ 0, 0, 0,109, 0, 0, 1,179, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,179, 0, 0, 1,181, 0, 0, 1,180, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 44, 0, 0, 1,180, 0, 0, 1,181, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,181, 0, 0, 1,179,
+ 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,182, 0, 0, 0, 0, 0, 0, 0,166, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0,166, 0, 0, 1,181, 0, 0, 0,182, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 52, 0, 0, 0,182, 0, 0, 1,181,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,181, 0, 0, 0,166, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,180,
+ 0, 0, 0, 44, 0, 0, 0,167, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,167, 0, 0, 1, 40, 0, 0, 1,180, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,109, 0, 0, 1,180, 0, 0, 1, 40, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 40, 0, 0, 0,167,
+ 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 45, 0, 0, 0,111, 0, 0, 1,182, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1,182, 0, 0, 0,195, 0, 0, 1, 45, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 20, 0, 0, 1, 45, 0, 0, 0,195,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,195, 0, 0, 1,182, 0, 0, 0, 58, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,183,
+ 0, 0, 0, 58, 0, 0, 1,182, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,182, 0, 0, 1,184, 0, 0, 1,183, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 53, 0, 0, 1,183, 0, 0, 1,184, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,184, 0, 0, 1,182,
+ 0, 0, 0,111, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 44, 0, 0, 0, 17, 0, 0, 0,185, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0,185, 0, 0, 1,184, 0, 0, 1, 44, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,111, 0, 0, 1, 44, 0, 0, 1,184,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,184, 0, 0, 0,185, 0, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,183,
+ 0, 0, 0, 53, 0, 0, 0,184, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,184, 0, 0, 0,194, 0, 0, 1,183, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 58, 0, 0, 1,183, 0, 0, 0,194, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,194, 0, 0, 0,184,
+ 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 44, 0, 0, 0,111, 0, 0, 1,185, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1,185, 0, 0, 1, 46, 0, 0, 1, 44, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 17, 0, 0, 1, 44, 0, 0, 1, 46,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 46, 0, 0, 1,185, 0, 0, 0,112, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,186,
+ 0, 0, 0,112, 0, 0, 1,185, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,185, 0, 0, 1,187, 0, 0, 1,186, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,113, 0, 0, 1,186, 0, 0, 1,187, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,187, 0, 0, 1,185,
+ 0, 0, 0,111, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 45, 0, 0, 0, 20, 0, 0, 1, 49, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 49, 0, 0, 1,187, 0, 0, 1, 45, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,111, 0, 0, 1, 45, 0, 0, 1,187,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,187, 0, 0, 1, 49, 0, 0, 0,113, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,186,
+ 0, 0, 0,113, 0, 0, 1, 48, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 48, 0, 0, 1, 47, 0, 0, 1,186, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,112, 0, 0, 1,186, 0, 0, 1, 47, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 47, 0, 0, 1, 48,
+ 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,192, 0, 0, 0, 57, 0, 0, 1,188, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1,188, 0, 0, 0,196, 0, 0, 0,192, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0,192, 0, 0, 0,196,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,196, 0, 0, 1,188, 0, 0, 0, 59, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,189,
+ 0, 0, 0, 59, 0, 0, 1,188, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,188, 0, 0, 1,190, 0, 0, 1,189, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,113, 0, 0, 1,189, 0, 0, 1,190, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,190, 0, 0, 1,188,
+ 0, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,193, 0, 0, 0, 19, 0, 0, 1, 48, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 48, 0, 0, 1,190, 0, 0, 0,193, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 57, 0, 0, 0,193, 0, 0, 1,190,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,190, 0, 0, 1, 48, 0, 0, 0,113, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,189,
+ 0, 0, 0,113, 0, 0, 1, 49, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 49, 0, 0, 0,197, 0, 0, 1,189, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 59, 0, 0, 1,189, 0, 0, 0,197, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,197, 0, 0, 1, 49,
+ 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,191, 0, 0, 0, 56, 0, 0, 1,191, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1,191, 0, 0, 1, 47, 0, 0, 0,191, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 19, 0, 0, 0,191, 0, 0, 1, 47,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 47, 0, 0, 1,191, 0, 0, 0,112, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,192,
+ 0, 0, 0,112, 0, 0, 1,191, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,191, 0, 0, 1,193, 0, 0, 1,192, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 52, 0, 0, 1,192, 0, 0, 1,193, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,193, 0, 0, 1,191,
+ 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,190, 0, 0, 0, 0, 0, 0, 0,182, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0,182, 0, 0, 1,193, 0, 0, 0,190, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 56, 0, 0, 0,190, 0, 0, 1,193,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,193, 0, 0, 0,182, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,192,
+ 0, 0, 0, 52, 0, 0, 0,183, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,183, 0, 0, 1, 46, 0, 0, 1,192, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,112, 0, 0, 1,192, 0, 0, 1, 46, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 46, 0, 0, 0,183,
+ 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 51, 0, 0, 0,114, 0, 0, 1,194, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1,194, 0, 0, 0,199, 0, 0, 1, 51, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 21, 0, 0, 1, 51, 0, 0, 0,199,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,199, 0, 0, 1,194, 0, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,195,
+ 0, 0, 0, 60, 0, 0, 1,194, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,194, 0, 0, 1,196, 0, 0, 1,195, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 57, 0, 0, 1,195, 0, 0, 1,196, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,196, 0, 0, 1,194,
+ 0, 0, 0,114, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 50, 0, 0, 0, 19, 0, 0, 0,193, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0,193, 0, 0, 1,196, 0, 0, 1, 50, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,114, 0, 0, 1, 50, 0, 0, 1,196,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,196, 0, 0, 0,193, 0, 0, 0, 57, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,195,
+ 0, 0, 0, 57, 0, 0, 0,192, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,192, 0, 0, 0,198, 0, 0, 1,195, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 60, 0, 0, 1,195, 0, 0, 0,198, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,198, 0, 0, 0,192,
+ 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 50, 0, 0, 0,114, 0, 0, 1,197, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1,197, 0, 0, 1, 53, 0, 0, 1, 50, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 19, 0, 0, 1, 50, 0, 0, 1, 53,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 53, 0, 0, 1,197, 0, 0, 0,115, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,198,
+ 0, 0, 0,115, 0, 0, 1,197, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,197, 0, 0, 1,199, 0, 0, 1,198, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,116, 0, 0, 1,198, 0, 0, 1,199, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,199, 0, 0, 1,197,
+ 0, 0, 0,114, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 51, 0, 0, 0, 21, 0, 0, 1, 55, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 55, 0, 0, 1,199, 0, 0, 1, 51, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,114, 0, 0, 1, 51, 0, 0, 1,199,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,199, 0, 0, 1, 55, 0, 0, 0,116, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,198,
+ 0, 0, 0,116, 0, 0, 1, 54, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 54, 0, 0, 1, 52, 0, 0, 1,198, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,115, 0, 0, 1,198, 0, 0, 1, 52, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 52, 0, 0, 1, 54,
+ 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,176, 0, 0, 0, 49, 0, 0, 1,200, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1,200, 0, 0, 0,200, 0, 0, 0,176, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 5, 0, 0, 0,176, 0, 0, 0,200,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,200, 0, 0, 1,200, 0, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,201,
+ 0, 0, 0, 61, 0, 0, 1,200, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,200, 0, 0, 1,202, 0, 0, 1,201, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,116, 0, 0, 1,201, 0, 0, 1,202, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,202, 0, 0, 1,200,
+ 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,177, 0, 0, 0, 15, 0, 0, 1, 54, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 54, 0, 0, 1,202, 0, 0, 0,177, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 49, 0, 0, 0,177, 0, 0, 1,202,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,202, 0, 0, 1, 54, 0, 0, 0,116, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,201,
+ 0, 0, 0,116, 0, 0, 1, 55, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 55, 0, 0, 0,201, 0, 0, 1,201, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 61, 0, 0, 1,201, 0, 0, 0,201, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,201, 0, 0, 1, 55,
+ 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,175, 0, 0, 0, 48, 0, 0, 1,203, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1,203, 0, 0, 1, 52, 0, 0, 0,175, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 15, 0, 0, 0,175, 0, 0, 1, 52,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 52, 0, 0, 1,203, 0, 0, 0,115, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,204,
+ 0, 0, 0,115, 0, 0, 1,203, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,203, 0, 0, 1,205, 0, 0, 1,204, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 56, 0, 0, 1,204, 0, 0, 1,205, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,205, 0, 0, 1,203,
+ 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,174, 0, 0, 0, 0, 0, 0, 0,190, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0,190, 0, 0, 1,205, 0, 0, 0,174, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 48, 0, 0, 0,174, 0, 0, 1,205,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,205, 0, 0, 0,190, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,204,
+ 0, 0, 0, 56, 0, 0, 0,191, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,191, 0, 0, 1, 53, 0, 0, 1,204, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,115, 0, 0, 1,204, 0, 0, 1, 53, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 53, 0, 0, 0,191,
+ 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,206, 0, 0, 0,117, 0, 0, 1, 57, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 57, 0, 0, 0,207, 0, 0, 1,206, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 64, 0, 0, 1,206, 0, 0, 0,207,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,207, 0, 0, 1, 57, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,206,
+ 0, 0, 0, 64, 0, 0, 1,207, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,207, 0, 0, 1,208, 0, 0, 1,206, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,117, 0, 0, 1,206, 0, 0, 1,208, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,208, 0, 0, 1,207,
+ 0, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,179, 0, 0, 0, 16, 0, 0, 1, 56, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 56, 0, 0, 1,208, 0, 0, 0,179, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 50, 0, 0, 0,179, 0, 0, 1,208,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,208, 0, 0, 1, 56, 0, 0, 0,117, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,178,
+ 0, 0, 0, 50, 0, 0, 1,207, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,207, 0, 0, 0,206, 0, 0, 0,178, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0,178, 0, 0, 0,206, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,206, 0, 0, 1,207,
+ 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,209, 0, 0, 0,117, 0, 0, 1, 56, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 56, 0, 0, 1, 58, 0, 0, 1,209, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,118, 0, 0, 1,209, 0, 0, 1, 58,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 58, 0, 0, 1, 56, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,209,
+ 0, 0, 0,118, 0, 0, 1,210, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,210, 0, 0, 1,211, 0, 0, 1,209, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,117, 0, 0, 1,209, 0, 0, 1,211, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,211, 0, 0, 1,210,
+ 0, 0, 0,119, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 61, 0, 0, 0, 23, 0, 0, 1, 57, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 57, 0, 0, 1,211, 0, 0, 1, 61, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,119, 0, 0, 1, 61, 0, 0, 1,211,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,211, 0, 0, 1, 57, 0, 0, 0,117, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 60,
+ 0, 0, 0,119, 0, 0, 1,210, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,210, 0, 0, 1, 59, 0, 0, 1, 60, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 22, 0, 0, 1, 60, 0, 0, 1, 59, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 59, 0, 0, 1,210,
+ 0, 0, 0,118, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,212, 0, 0, 0, 63, 0, 0, 0,204, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0,204, 0, 0, 0,208, 0, 0, 1,212, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 65, 0, 0, 1,212, 0, 0, 0,208,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,208, 0, 0, 0,204, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,212,
+ 0, 0, 0, 65, 0, 0, 1,213, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,213, 0, 0, 1,214, 0, 0, 1,212, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 63, 0, 0, 1,212, 0, 0, 1,214, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,214, 0, 0, 1,213,
+ 0, 0, 0,119, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 60, 0, 0, 0, 22, 0, 0, 0,205, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0,205, 0, 0, 1,214, 0, 0, 1, 60, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,119, 0, 0, 1, 60, 0, 0, 1,214,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,214, 0, 0, 0,205, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 61,
+ 0, 0, 0,119, 0, 0, 1,213, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,213, 0, 0, 0,209, 0, 0, 1, 61, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 23, 0, 0, 1, 61, 0, 0, 0,209, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,209, 0, 0, 1,213,
+ 0, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,215, 0, 0, 0, 62, 0, 0, 0,203, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0,203, 0, 0, 1, 59, 0, 0, 1,215, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,118, 0, 0, 1,215, 0, 0, 1, 59,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 59, 0, 0, 0,203, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,215,
+ 0, 0, 0,118, 0, 0, 1,216, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,216, 0, 0, 1,217, 0, 0, 1,215, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 62, 0, 0, 1,215, 0, 0, 1,217, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,217, 0, 0, 1,216,
+ 0, 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,180, 0, 0, 0, 5, 0, 0, 0,202, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0,202, 0, 0, 1,217, 0, 0, 0,180, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 51, 0, 0, 0,180, 0, 0, 1,217,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,217, 0, 0, 0,202, 0, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,181,
+ 0, 0, 0, 51, 0, 0, 1,216, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,216, 0, 0, 1, 58, 0, 0, 0,181, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 16, 0, 0, 0,181, 0, 0, 1, 58, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 58, 0, 0, 1,216,
+ 0, 0, 0,118, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,218, 0, 0, 0,120, 0, 0, 1, 63, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 63, 0, 0, 0,215, 0, 0, 1,218, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 68, 0, 0, 1,218, 0, 0, 0,215,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,215, 0, 0, 1, 63, 0, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,218,
+ 0, 0, 0, 68, 0, 0, 1,219, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,219, 0, 0, 1,220, 0, 0, 1,218, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,120, 0, 0, 1,218, 0, 0, 1,220, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,220, 0, 0, 1,219,
+ 0, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,173, 0, 0, 0, 14, 0, 0, 1, 62, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 62, 0, 0, 1,220, 0, 0, 0,173, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 47, 0, 0, 0,173, 0, 0, 1,220,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,220, 0, 0, 1, 62, 0, 0, 0,120, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,172,
+ 0, 0, 0, 47, 0, 0, 1,219, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,219, 0, 0, 0,214, 0, 0, 0,172, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 2, 0, 0, 0,172, 0, 0, 0,214, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,214, 0, 0, 1,219,
+ 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,221, 0, 0, 0,120, 0, 0, 1, 62, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 62, 0, 0, 1, 64, 0, 0, 1,221, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,121, 0, 0, 1,221, 0, 0, 1, 64,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 64, 0, 0, 1, 62, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,221,
+ 0, 0, 0,121, 0, 0, 1,222, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,222, 0, 0, 1,223, 0, 0, 1,221, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,120, 0, 0, 1,221, 0, 0, 1,223, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,223, 0, 0, 1,222,
+ 0, 0, 0,122, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 67, 0, 0, 0, 25, 0, 0, 1, 63, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 63, 0, 0, 1,223, 0, 0, 1, 67, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,122, 0, 0, 1, 67, 0, 0, 1,223,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,223, 0, 0, 1, 63, 0, 0, 0,120, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 66,
+ 0, 0, 0,122, 0, 0, 1,222, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,222, 0, 0, 1, 65, 0, 0, 1, 66, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 24, 0, 0, 1, 66, 0, 0, 1, 65, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 65, 0, 0, 1,222,
+ 0, 0, 0,121, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,224, 0, 0, 0, 67, 0, 0, 0,212, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0,212, 0, 0, 0,216, 0, 0, 1,224, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 69, 0, 0, 1,224, 0, 0, 0,216,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,216, 0, 0, 0,212, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,224,
+ 0, 0, 0, 69, 0, 0, 1,225, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,225, 0, 0, 1,226, 0, 0, 1,224, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 67, 0, 0, 1,224, 0, 0, 1,226, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,226, 0, 0, 1,225,
+ 0, 0, 0,122, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 66, 0, 0, 0, 24, 0, 0, 0,213, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0,213, 0, 0, 1,226, 0, 0, 1, 66, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,122, 0, 0, 1, 66, 0, 0, 1,226,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,226, 0, 0, 0,213, 0, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 67,
+ 0, 0, 0,122, 0, 0, 1,225, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,225, 0, 0, 0,217, 0, 0, 1, 67, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 25, 0, 0, 1, 67, 0, 0, 0,217, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,217, 0, 0, 1,225,
+ 0, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,227, 0, 0, 0, 66, 0, 0, 0,211, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0,211, 0, 0, 1, 65, 0, 0, 1,227, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,121, 0, 0, 1,227, 0, 0, 1, 65,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 65, 0, 0, 0,211, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,227,
+ 0, 0, 0,121, 0, 0, 1,228, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,228, 0, 0, 1,229, 0, 0, 1,227, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 66, 0, 0, 1,227, 0, 0, 1,229, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,229, 0, 0, 1,228,
+ 0, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,170, 0, 0, 0, 1, 0, 0, 0,210, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0,210, 0, 0, 1,229, 0, 0, 0,170, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 46, 0, 0, 0,170, 0, 0, 1,229,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,229, 0, 0, 0,210, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,171,
+ 0, 0, 0, 46, 0, 0, 1,228, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,228, 0, 0, 1, 64, 0, 0, 0,171, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 14, 0, 0, 0,171, 0, 0, 1, 64, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 64, 0, 0, 1,228,
+ 0, 0, 0,121, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,230, 0, 0, 0,123, 0, 0, 1, 69, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 69, 0, 0, 0,223, 0, 0, 1,230, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 72, 0, 0, 1,230, 0, 0, 0,223,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,223, 0, 0, 1, 69, 0, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,230,
+ 0, 0, 0, 72, 0, 0, 1,231, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,231, 0, 0, 1,232, 0, 0, 1,230, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,123, 0, 0, 1,230, 0, 0, 1,232, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,232, 0, 0, 1,231,
+ 0, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,189, 0, 0, 0, 18, 0, 0, 1, 68, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 68, 0, 0, 1,232, 0, 0, 0,189, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 55, 0, 0, 0,189, 0, 0, 1,232,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,232, 0, 0, 1, 68, 0, 0, 0,123, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,188,
+ 0, 0, 0, 55, 0, 0, 1,231, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,231, 0, 0, 0,222, 0, 0, 0,188, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0,188, 0, 0, 0,222, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,222, 0, 0, 1,231,
+ 0, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,233, 0, 0, 0,123, 0, 0, 1, 68, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 68, 0, 0, 1, 70, 0, 0, 1,233, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,124, 0, 0, 1,233, 0, 0, 1, 70,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 70, 0, 0, 1, 68, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,233,
+ 0, 0, 0,124, 0, 0, 1,234, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,234, 0, 0, 1,235, 0, 0, 1,233, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,123, 0, 0, 1,233, 0, 0, 1,235, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,235, 0, 0, 1,234,
+ 0, 0, 0,125, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 73, 0, 0, 0, 27, 0, 0, 1, 69, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 69, 0, 0, 1,235, 0, 0, 1, 73, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,125, 0, 0, 1, 73, 0, 0, 1,235,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,235, 0, 0, 1, 69, 0, 0, 0,123, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 72,
+ 0, 0, 0,125, 0, 0, 1,234, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,234, 0, 0, 1, 71, 0, 0, 1, 72, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 26, 0, 0, 1, 72, 0, 0, 1, 71, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 71, 0, 0, 1,234,
+ 0, 0, 0,124, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,236, 0, 0, 0, 71, 0, 0, 0,220, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0,220, 0, 0, 0,224, 0, 0, 1,236, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 73, 0, 0, 1,236, 0, 0, 0,224,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,224, 0, 0, 0,220, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,236,
+ 0, 0, 0, 73, 0, 0, 1,237, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,237, 0, 0, 1,238, 0, 0, 1,236, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 71, 0, 0, 1,236, 0, 0, 1,238, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,238, 0, 0, 1,237,
+ 0, 0, 0,125, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 72, 0, 0, 0, 26, 0, 0, 0,221, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0,221, 0, 0, 1,238, 0, 0, 1, 72, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,125, 0, 0, 1, 72, 0, 0, 1,238,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,238, 0, 0, 0,221, 0, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 73,
+ 0, 0, 0,125, 0, 0, 1,237, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,237, 0, 0, 0,225, 0, 0, 1, 73, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 27, 0, 0, 1, 73, 0, 0, 0,225, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,225, 0, 0, 1,237,
+ 0, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,239, 0, 0, 0, 70, 0, 0, 0,219, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0,219, 0, 0, 1, 71, 0, 0, 1,239, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,124, 0, 0, 1,239, 0, 0, 1, 71,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 71, 0, 0, 0,219, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,239,
+ 0, 0, 0,124, 0, 0, 1,240, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,240, 0, 0, 1,241, 0, 0, 1,239, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 70, 0, 0, 1,239, 0, 0, 1,241, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,241, 0, 0, 1,240,
+ 0, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,186, 0, 0, 0, 2, 0, 0, 0,218, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0,218, 0, 0, 1,241, 0, 0, 0,186, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 54, 0, 0, 0,186, 0, 0, 1,241,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,241, 0, 0, 0,218, 0, 0, 0, 70, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,187,
+ 0, 0, 0, 54, 0, 0, 1,240, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,240, 0, 0, 1, 70, 0, 0, 0,187, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 18, 0, 0, 0,187, 0, 0, 1, 70, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 70, 0, 0, 1,240,
+ 0, 0, 0,124, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,242, 0, 0, 0,126, 0, 0, 1, 75, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 75, 0, 0, 0,231, 0, 0, 1,242, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 76, 0, 0, 1,242, 0, 0, 0,231,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,231, 0, 0, 1, 75, 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,242,
+ 0, 0, 0, 76, 0, 0, 1,243, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,243, 0, 0, 1,244, 0, 0, 1,242, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,126, 0, 0, 1,242, 0, 0, 1,244, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,244, 0, 0, 1,243,
+ 0, 0, 0, 59, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,197, 0, 0, 0, 20, 0, 0, 1, 74, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 74, 0, 0, 1,244, 0, 0, 0,197, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 59, 0, 0, 0,197, 0, 0, 1,244,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,244, 0, 0, 1, 74, 0, 0, 0,126, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,196,
+ 0, 0, 0, 59, 0, 0, 1,243, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,243, 0, 0, 0,230, 0, 0, 0,196, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0,196, 0, 0, 0,230, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,230, 0, 0, 1,243,
+ 0, 0, 0, 76, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,245, 0, 0, 0,126, 0, 0, 1, 74, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 74, 0, 0, 1, 76, 0, 0, 1,245, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,127, 0, 0, 1,245, 0, 0, 1, 76,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 76, 0, 0, 1, 74, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,245,
+ 0, 0, 0,127, 0, 0, 1,246, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,246, 0, 0, 1,247, 0, 0, 1,245, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,126, 0, 0, 1,245, 0, 0, 1,247, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,247, 0, 0, 1,246,
+ 0, 0, 0,128, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 79, 0, 0, 0, 29, 0, 0, 1, 75, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 75, 0, 0, 1,247, 0, 0, 1, 79, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,128, 0, 0, 1, 79, 0, 0, 1,247,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,247, 0, 0, 1, 75, 0, 0, 0,126, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 78,
+ 0, 0, 0,128, 0, 0, 1,246, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,246, 0, 0, 1, 77, 0, 0, 1, 78, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 28, 0, 0, 1, 78, 0, 0, 1, 77, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 77, 0, 0, 1,246,
+ 0, 0, 0,127, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,248, 0, 0, 0, 75, 0, 0, 0,228, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0,228, 0, 0, 0,232, 0, 0, 1,248, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 77, 0, 0, 1,248, 0, 0, 0,232,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,232, 0, 0, 0,228, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,248,
+ 0, 0, 0, 77, 0, 0, 1,249, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,249, 0, 0, 1,250, 0, 0, 1,248, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 75, 0, 0, 1,248, 0, 0, 1,250, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,250, 0, 0, 1,249,
+ 0, 0, 0,128, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 78, 0, 0, 0, 28, 0, 0, 0,229, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0,229, 0, 0, 1,250, 0, 0, 1, 78, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,128, 0, 0, 1, 78, 0, 0, 1,250,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,250, 0, 0, 0,229, 0, 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 79,
+ 0, 0, 0,128, 0, 0, 1,249, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,249, 0, 0, 0,233, 0, 0, 1, 79, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 29, 0, 0, 1, 79, 0, 0, 0,233, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,233, 0, 0, 1,249,
+ 0, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,251, 0, 0, 0, 74, 0, 0, 0,227, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0,227, 0, 0, 1, 77, 0, 0, 1,251, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,127, 0, 0, 1,251, 0, 0, 1, 77,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 77, 0, 0, 0,227, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,251,
+ 0, 0, 0,127, 0, 0, 1,252, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,252, 0, 0, 1,253, 0, 0, 1,251, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 74, 0, 0, 1,251, 0, 0, 1,253, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,253, 0, 0, 1,252,
+ 0, 0, 0, 58, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,194, 0, 0, 0, 3, 0, 0, 0,226, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0,226, 0, 0, 1,253, 0, 0, 0,194, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 58, 0, 0, 0,194, 0, 0, 1,253,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,253, 0, 0, 0,226, 0, 0, 0, 74, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,195,
+ 0, 0, 0, 58, 0, 0, 1,252, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,252, 0, 0, 1, 76, 0, 0, 0,195, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 20, 0, 0, 0,195, 0, 0, 1, 76, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 76, 0, 0, 1,252,
+ 0, 0, 0,127, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,254, 0, 0, 0,129, 0, 0, 1, 81, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 81, 0, 0, 0,239, 0, 0, 1,254, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 80, 0, 0, 1,254, 0, 0, 0,239,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,239, 0, 0, 1, 81, 0, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,254,
+ 0, 0, 0, 80, 0, 0, 1,255, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,255, 0, 0, 2, 0, 0, 0, 1,254, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,129, 0, 0, 1,254, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 0, 0, 0, 1,255,
+ 0, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,201, 0, 0, 0, 21, 0, 0, 1, 80, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 80, 0, 0, 2, 0, 0, 0, 0,201, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 61, 0, 0, 0,201, 0, 0, 2, 0,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 0, 0, 0, 1, 80, 0, 0, 0,129, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,200,
+ 0, 0, 0, 61, 0, 0, 1,255, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,255, 0, 0, 0,238, 0, 0, 0,200, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 5, 0, 0, 0,200, 0, 0, 0,238, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,238, 0, 0, 1,255,
+ 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 1, 0, 0, 0,129, 0, 0, 1, 80, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 80, 0, 0, 1, 82, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,130, 0, 0, 2, 1, 0, 0, 1, 82,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 82, 0, 0, 1, 80, 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 1,
+ 0, 0, 0,130, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 2, 0, 0, 2, 3, 0, 0, 2, 1, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,129, 0, 0, 2, 1, 0, 0, 2, 3, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 3, 0, 0, 2, 2,
+ 0, 0, 0,131, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 85, 0, 0, 0, 31, 0, 0, 1, 81, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 81, 0, 0, 2, 3, 0, 0, 1, 85, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,131, 0, 0, 1, 85, 0, 0, 2, 3,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 3, 0, 0, 1, 81, 0, 0, 0,129, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 84,
+ 0, 0, 0,131, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 2, 0, 0, 1, 83, 0, 0, 1, 84, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 30, 0, 0, 1, 84, 0, 0, 1, 83, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 83, 0, 0, 2, 2,
+ 0, 0, 0,130, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 4, 0, 0, 0, 79, 0, 0, 0,236, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0,236, 0, 0, 0,240, 0, 0, 2, 4, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 81, 0, 0, 2, 4, 0, 0, 0,240,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,240, 0, 0, 0,236, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 4,
+ 0, 0, 0, 81, 0, 0, 2, 5, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 5, 0, 0, 2, 6, 0, 0, 2, 4, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 79, 0, 0, 2, 4, 0, 0, 2, 6, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 6, 0, 0, 2, 5,
+ 0, 0, 0,131, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 84, 0, 0, 0, 30, 0, 0, 0,237, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0,237, 0, 0, 2, 6, 0, 0, 1, 84, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,131, 0, 0, 1, 84, 0, 0, 2, 6,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 6, 0, 0, 0,237, 0, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 85,
+ 0, 0, 0,131, 0, 0, 2, 5, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 5, 0, 0, 0,241, 0, 0, 1, 85, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 31, 0, 0, 1, 85, 0, 0, 0,241, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,241, 0, 0, 2, 5,
+ 0, 0, 0, 81, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 7, 0, 0, 0, 78, 0, 0, 0,235, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0,235, 0, 0, 1, 83, 0, 0, 2, 7, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,130, 0, 0, 2, 7, 0, 0, 1, 83,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 83, 0, 0, 0,235, 0, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 7,
+ 0, 0, 0,130, 0, 0, 2, 8, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 8, 0, 0, 2, 9, 0, 0, 2, 7, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 78, 0, 0, 2, 7, 0, 0, 2, 9, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 9, 0, 0, 2, 8,
+ 0, 0, 0, 60, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,198, 0, 0, 0, 4, 0, 0, 0,234, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0,234, 0, 0, 2, 9, 0, 0, 0,198, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 60, 0, 0, 0,198, 0, 0, 2, 9,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 9, 0, 0, 0,234, 0, 0, 0, 78, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,199,
+ 0, 0, 0, 60, 0, 0, 2, 8, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 8, 0, 0, 1, 82, 0, 0, 0,199, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 21, 0, 0, 0,199, 0, 0, 1, 82, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 82, 0, 0, 2, 8,
+ 0, 0, 0,130, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 87, 0, 0, 0,132, 0, 0, 2, 10, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 2, 10, 0, 0, 0,245, 0, 0, 1, 87, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 32, 0, 0, 1, 87, 0, 0, 0,245,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,245, 0, 0, 2, 10, 0, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 11,
+ 0, 0, 0, 83, 0, 0, 2, 10, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 10, 0, 0, 2, 12, 0, 0, 2, 11, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 65, 0, 0, 2, 11, 0, 0, 2, 12, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 12, 0, 0, 2, 10,
+ 0, 0, 0,132, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 86, 0, 0, 0, 23, 0, 0, 0,209, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0,209, 0, 0, 2, 12, 0, 0, 1, 86, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,132, 0, 0, 1, 86, 0, 0, 2, 12,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 12, 0, 0, 0,209, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 11,
+ 0, 0, 0, 65, 0, 0, 0,208, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,208, 0, 0, 0,244, 0, 0, 2, 11, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 83, 0, 0, 2, 11, 0, 0, 0,244, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,244, 0, 0, 0,208,
+ 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 86, 0, 0, 0,132, 0, 0, 2, 13, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 2, 13, 0, 0, 1, 88, 0, 0, 1, 86, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 23, 0, 0, 1, 86, 0, 0, 1, 88,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 88, 0, 0, 2, 13, 0, 0, 0,133, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 14,
+ 0, 0, 0,133, 0, 0, 2, 13, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 13, 0, 0, 2, 15, 0, 0, 2, 14, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,134, 0, 0, 2, 14, 0, 0, 2, 15, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 15, 0, 0, 2, 13,
+ 0, 0, 0,132, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 87, 0, 0, 0, 32, 0, 0, 1, 91, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 91, 0, 0, 2, 15, 0, 0, 1, 87, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,132, 0, 0, 1, 87, 0, 0, 2, 15,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 15, 0, 0, 1, 91, 0, 0, 0,134, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 14,
+ 0, 0, 0,134, 0, 0, 1, 90, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 90, 0, 0, 1, 89, 0, 0, 2, 14, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,133, 0, 0, 2, 14, 0, 0, 1, 89, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 89, 0, 0, 1, 90,
+ 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,212, 0, 0, 0, 67, 0, 0, 2, 16, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 2, 16, 0, 0, 0,242, 0, 0, 0,212, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 6, 0, 0, 0,212, 0, 0, 0,242,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,242, 0, 0, 2, 16, 0, 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 17,
+ 0, 0, 0, 82, 0, 0, 2, 16, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 16, 0, 0, 2, 18, 0, 0, 2, 17, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,134, 0, 0, 2, 17, 0, 0, 2, 18, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 18, 0, 0, 2, 16,
+ 0, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,213, 0, 0, 0, 24, 0, 0, 1, 90, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 90, 0, 0, 2, 18, 0, 0, 0,213, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 67, 0, 0, 0,213, 0, 0, 2, 18,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 18, 0, 0, 1, 90, 0, 0, 0,134, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 17,
+ 0, 0, 0,134, 0, 0, 1, 91, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 91, 0, 0, 0,243, 0, 0, 2, 17, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 82, 0, 0, 2, 17, 0, 0, 0,243, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,243, 0, 0, 1, 91,
+ 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,211, 0, 0, 0, 66, 0, 0, 2, 19, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 2, 19, 0, 0, 1, 89, 0, 0, 0,211, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 24, 0, 0, 0,211, 0, 0, 1, 89,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 89, 0, 0, 2, 19, 0, 0, 0,133, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 20,
+ 0, 0, 0,133, 0, 0, 2, 19, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 19, 0, 0, 2, 21, 0, 0, 2, 20, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 64, 0, 0, 2, 20, 0, 0, 2, 21, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 21, 0, 0, 2, 19,
+ 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,210, 0, 0, 0, 1, 0, 0, 0,206, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0,206, 0, 0, 2, 21, 0, 0, 0,210, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 66, 0, 0, 0,210, 0, 0, 2, 21,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 21, 0, 0, 0,206, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 20,
+ 0, 0, 0, 64, 0, 0, 0,207, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,207, 0, 0, 1, 88, 0, 0, 2, 20, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,133, 0, 0, 2, 20, 0, 0, 1, 88, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 88, 0, 0, 0,207,
+ 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 93, 0, 0, 0,135, 0, 0, 2, 22, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 2, 22, 0, 0, 0,247, 0, 0, 1, 93, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 33, 0, 0, 1, 93, 0, 0, 0,247,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,247, 0, 0, 2, 22, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 23,
+ 0, 0, 0, 84, 0, 0, 2, 22, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 22, 0, 0, 2, 24, 0, 0, 2, 23, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 69, 0, 0, 2, 23, 0, 0, 2, 24, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 24, 0, 0, 2, 22,
+ 0, 0, 0,135, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 92, 0, 0, 0, 25, 0, 0, 0,217, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0,217, 0, 0, 2, 24, 0, 0, 1, 92, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,135, 0, 0, 1, 92, 0, 0, 2, 24,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 24, 0, 0, 0,217, 0, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 23,
+ 0, 0, 0, 69, 0, 0, 0,216, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,216, 0, 0, 0,246, 0, 0, 2, 23, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 84, 0, 0, 2, 23, 0, 0, 0,246, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,246, 0, 0, 0,216,
+ 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 92, 0, 0, 0,135, 0, 0, 2, 25, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 2, 25, 0, 0, 1, 94, 0, 0, 1, 92, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 25, 0, 0, 1, 92, 0, 0, 1, 94,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 94, 0, 0, 2, 25, 0, 0, 0,136, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 26,
+ 0, 0, 0,136, 0, 0, 2, 25, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 25, 0, 0, 2, 27, 0, 0, 2, 26, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,137, 0, 0, 2, 26, 0, 0, 2, 27, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 27, 0, 0, 2, 25,
+ 0, 0, 0,135, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 93, 0, 0, 0, 33, 0, 0, 1, 97, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 97, 0, 0, 2, 27, 0, 0, 1, 93, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,135, 0, 0, 1, 93, 0, 0, 2, 27,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 27, 0, 0, 1, 97, 0, 0, 0,137, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 26,
+ 0, 0, 0,137, 0, 0, 1, 96, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 96, 0, 0, 1, 95, 0, 0, 2, 26, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,136, 0, 0, 2, 26, 0, 0, 1, 95, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 95, 0, 0, 1, 96,
+ 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,220, 0, 0, 0, 71, 0, 0, 2, 28, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 2, 28, 0, 0, 0,248, 0, 0, 0,220, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 7, 0, 0, 0,220, 0, 0, 0,248,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,248, 0, 0, 2, 28, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 29,
+ 0, 0, 0, 85, 0, 0, 2, 28, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 28, 0, 0, 2, 30, 0, 0, 2, 29, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,137, 0, 0, 2, 29, 0, 0, 2, 30, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 30, 0, 0, 2, 28,
+ 0, 0, 0, 71, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,221, 0, 0, 0, 26, 0, 0, 1, 96, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 96, 0, 0, 2, 30, 0, 0, 0,221, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 71, 0, 0, 0,221, 0, 0, 2, 30,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 30, 0, 0, 1, 96, 0, 0, 0,137, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 29,
+ 0, 0, 0,137, 0, 0, 1, 97, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 97, 0, 0, 0,249, 0, 0, 2, 29, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 85, 0, 0, 2, 29, 0, 0, 0,249, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,249, 0, 0, 1, 97,
+ 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,219, 0, 0, 0, 70, 0, 0, 2, 31, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 2, 31, 0, 0, 1, 95, 0, 0, 0,219, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 26, 0, 0, 0,219, 0, 0, 1, 95,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 95, 0, 0, 2, 31, 0, 0, 0,136, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 32,
+ 0, 0, 0,136, 0, 0, 2, 31, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 31, 0, 0, 2, 33, 0, 0, 2, 32, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 68, 0, 0, 2, 32, 0, 0, 2, 33, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 33, 0, 0, 2, 31,
+ 0, 0, 0, 70, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,218, 0, 0, 0, 2, 0, 0, 0,214, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0,214, 0, 0, 2, 33, 0, 0, 0,218, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 70, 0, 0, 0,218, 0, 0, 2, 33,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 33, 0, 0, 0,214, 0, 0, 0, 68, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 32,
+ 0, 0, 0, 68, 0, 0, 0,215, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,215, 0, 0, 1, 94, 0, 0, 2, 32, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,136, 0, 0, 2, 32, 0, 0, 1, 94, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 94, 0, 0, 0,215,
+ 0, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 99, 0, 0, 0,138, 0, 0, 2, 34, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 2, 34, 0, 0, 0,251, 0, 0, 1, 99, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 34, 0, 0, 1, 99, 0, 0, 0,251,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,251, 0, 0, 2, 34, 0, 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 35,
+ 0, 0, 0, 86, 0, 0, 2, 34, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 34, 0, 0, 2, 36, 0, 0, 2, 35, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 73, 0, 0, 2, 35, 0, 0, 2, 36, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 36, 0, 0, 2, 34,
+ 0, 0, 0,138, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 98, 0, 0, 0, 27, 0, 0, 0,225, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0,225, 0, 0, 2, 36, 0, 0, 1, 98, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,138, 0, 0, 1, 98, 0, 0, 2, 36,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 36, 0, 0, 0,225, 0, 0, 0, 73, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 35,
+ 0, 0, 0, 73, 0, 0, 0,224, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,224, 0, 0, 0,250, 0, 0, 2, 35, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 86, 0, 0, 2, 35, 0, 0, 0,250, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,250, 0, 0, 0,224,
+ 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 98, 0, 0, 0,138, 0, 0, 2, 37, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 2, 37, 0, 0, 1,100, 0, 0, 1, 98, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 27, 0, 0, 1, 98, 0, 0, 1,100,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,100, 0, 0, 2, 37, 0, 0, 0,139, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 38,
+ 0, 0, 0,139, 0, 0, 2, 37, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 37, 0, 0, 2, 39, 0, 0, 2, 38, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,140, 0, 0, 2, 38, 0, 0, 2, 39, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 39, 0, 0, 2, 37,
+ 0, 0, 0,138, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 99, 0, 0, 0, 34, 0, 0, 1,103, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1,103, 0, 0, 2, 39, 0, 0, 1, 99, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,138, 0, 0, 1, 99, 0, 0, 2, 39,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 39, 0, 0, 1,103, 0, 0, 0,140, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 38,
+ 0, 0, 0,140, 0, 0, 1,102, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,102, 0, 0, 1,101, 0, 0, 2, 38, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,139, 0, 0, 2, 38, 0, 0, 1,101, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,101, 0, 0, 1,102,
+ 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,228, 0, 0, 0, 75, 0, 0, 2, 40, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 2, 40, 0, 0, 0,252, 0, 0, 0,228, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 8, 0, 0, 0,228, 0, 0, 0,252,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,252, 0, 0, 2, 40, 0, 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 41,
+ 0, 0, 0, 87, 0, 0, 2, 40, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 40, 0, 0, 2, 42, 0, 0, 2, 41, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,140, 0, 0, 2, 41, 0, 0, 2, 42, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 42, 0, 0, 2, 40,
+ 0, 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,229, 0, 0, 0, 28, 0, 0, 1,102, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1,102, 0, 0, 2, 42, 0, 0, 0,229, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 75, 0, 0, 0,229, 0, 0, 2, 42,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 42, 0, 0, 1,102, 0, 0, 0,140, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 41,
+ 0, 0, 0,140, 0, 0, 1,103, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,103, 0, 0, 0,253, 0, 0, 2, 41, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 87, 0, 0, 2, 41, 0, 0, 0,253, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,253, 0, 0, 1,103,
+ 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,227, 0, 0, 0, 74, 0, 0, 2, 43, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 2, 43, 0, 0, 1,101, 0, 0, 0,227, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 28, 0, 0, 0,227, 0, 0, 1,101,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,101, 0, 0, 2, 43, 0, 0, 0,139, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 44,
+ 0, 0, 0,139, 0, 0, 2, 43, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 43, 0, 0, 2, 45, 0, 0, 2, 44, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 72, 0, 0, 2, 44, 0, 0, 2, 45, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 45, 0, 0, 2, 43,
+ 0, 0, 0, 74, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,226, 0, 0, 0, 3, 0, 0, 0,222, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0,222, 0, 0, 2, 45, 0, 0, 0,226, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 74, 0, 0, 0,226, 0, 0, 2, 45,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 45, 0, 0, 0,222, 0, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 44,
+ 0, 0, 0, 72, 0, 0, 0,223, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,223, 0, 0, 1,100, 0, 0, 2, 44, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,139, 0, 0, 2, 44, 0, 0, 1,100, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,100, 0, 0, 0,223,
+ 0, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,105, 0, 0, 0,141, 0, 0, 2, 46, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 2, 46, 0, 0, 0,255, 0, 0, 1,105, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 35, 0, 0, 1,105, 0, 0, 0,255,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,255, 0, 0, 2, 46, 0, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 47,
+ 0, 0, 0, 88, 0, 0, 2, 46, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 46, 0, 0, 2, 48, 0, 0, 2, 47, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 77, 0, 0, 2, 47, 0, 0, 2, 48, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 48, 0, 0, 2, 46,
+ 0, 0, 0,141, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,104, 0, 0, 0, 29, 0, 0, 0,233, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0,233, 0, 0, 2, 48, 0, 0, 1,104, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,141, 0, 0, 1,104, 0, 0, 2, 48,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 48, 0, 0, 0,233, 0, 0, 0, 77, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 47,
+ 0, 0, 0, 77, 0, 0, 0,232, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,232, 0, 0, 0,254, 0, 0, 2, 47, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 88, 0, 0, 2, 47, 0, 0, 0,254, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,254, 0, 0, 0,232,
+ 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,104, 0, 0, 0,141, 0, 0, 2, 49, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 2, 49, 0, 0, 1,106, 0, 0, 1,104, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 29, 0, 0, 1,104, 0, 0, 1,106,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,106, 0, 0, 2, 49, 0, 0, 0,142, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 50,
+ 0, 0, 0,142, 0, 0, 2, 49, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 49, 0, 0, 2, 51, 0, 0, 2, 50, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,143, 0, 0, 2, 50, 0, 0, 2, 51, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 51, 0, 0, 2, 49,
+ 0, 0, 0,141, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,105, 0, 0, 0, 35, 0, 0, 1,109, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1,109, 0, 0, 2, 51, 0, 0, 1,105, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,141, 0, 0, 1,105, 0, 0, 2, 51,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 51, 0, 0, 1,109, 0, 0, 0,143, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 50,
+ 0, 0, 0,143, 0, 0, 1,108, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,108, 0, 0, 1,107, 0, 0, 2, 50, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,142, 0, 0, 2, 50, 0, 0, 1,107, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,107, 0, 0, 1,108,
+ 0, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,236, 0, 0, 0, 79, 0, 0, 2, 52, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 2, 52, 0, 0, 1, 0, 0, 0, 0,236, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 9, 0, 0, 0,236, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 0, 0, 0, 2, 52, 0, 0, 0, 89, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 53,
+ 0, 0, 0, 89, 0, 0, 2, 52, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 52, 0, 0, 2, 54, 0, 0, 2, 53, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,143, 0, 0, 2, 53, 0, 0, 2, 54, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 54, 0, 0, 2, 52,
+ 0, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,237, 0, 0, 0, 30, 0, 0, 1,108, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1,108, 0, 0, 2, 54, 0, 0, 0,237, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 79, 0, 0, 0,237, 0, 0, 2, 54,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 54, 0, 0, 1,108, 0, 0, 0,143, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 53,
+ 0, 0, 0,143, 0, 0, 1,109, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,109, 0, 0, 1, 1, 0, 0, 2, 53, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 89, 0, 0, 2, 53, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 1, 0, 0, 1,109,
+ 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,235, 0, 0, 0, 78, 0, 0, 2, 55, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 2, 55, 0, 0, 1,107, 0, 0, 0,235, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 30, 0, 0, 0,235, 0, 0, 1,107,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,107, 0, 0, 2, 55, 0, 0, 0,142, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 56,
+ 0, 0, 0,142, 0, 0, 2, 55, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 55, 0, 0, 2, 57, 0, 0, 2, 56, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 76, 0, 0, 2, 56, 0, 0, 2, 57, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 57, 0, 0, 2, 55,
+ 0, 0, 0, 78, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,234, 0, 0, 0, 4, 0, 0, 0,230, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0,230, 0, 0, 2, 57, 0, 0, 0,234, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 78, 0, 0, 0,234, 0, 0, 2, 57,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 57, 0, 0, 0,230, 0, 0, 0, 76, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 56,
+ 0, 0, 0, 76, 0, 0, 0,231, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,231, 0, 0, 1,106, 0, 0, 2, 56, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,142, 0, 0, 2, 56, 0, 0, 1,106, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,106, 0, 0, 0,231,
+ 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,111, 0, 0, 0,144, 0, 0, 2, 58, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 2, 58, 0, 0, 1, 3, 0, 0, 1,111, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 36, 0, 0, 1,111, 0, 0, 1, 3,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 3, 0, 0, 2, 58, 0, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 59,
+ 0, 0, 0, 90, 0, 0, 2, 58, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 58, 0, 0, 2, 60, 0, 0, 2, 59, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 81, 0, 0, 2, 59, 0, 0, 2, 60, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 60, 0, 0, 2, 58,
+ 0, 0, 0,144, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,110, 0, 0, 0, 31, 0, 0, 0,241, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0,241, 0, 0, 2, 60, 0, 0, 1,110, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,144, 0, 0, 1,110, 0, 0, 2, 60,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 60, 0, 0, 0,241, 0, 0, 0, 81, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 59,
+ 0, 0, 0, 81, 0, 0, 0,240, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,240, 0, 0, 1, 2, 0, 0, 2, 59, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 90, 0, 0, 2, 59, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 2, 0, 0, 0,240,
+ 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,110, 0, 0, 0,144, 0, 0, 2, 61, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 2, 61, 0, 0, 1,113, 0, 0, 1,110, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 31, 0, 0, 1,110, 0, 0, 1,113,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,113, 0, 0, 2, 61, 0, 0, 0,145, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 62,
+ 0, 0, 0,145, 0, 0, 2, 61, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 61, 0, 0, 2, 63, 0, 0, 2, 62, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,146, 0, 0, 2, 62, 0, 0, 2, 63, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 63, 0, 0, 2, 61,
+ 0, 0, 0,144, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,111, 0, 0, 0, 36, 0, 0, 1,115, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1,115, 0, 0, 2, 63, 0, 0, 1,111, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,144, 0, 0, 1,111, 0, 0, 2, 63,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 63, 0, 0, 1,115, 0, 0, 0,146, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 62,
+ 0, 0, 0,146, 0, 0, 1,114, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,114, 0, 0, 1,112, 0, 0, 2, 62, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,145, 0, 0, 2, 62, 0, 0, 1,112, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,112, 0, 0, 1,114,
+ 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,204, 0, 0, 0, 63, 0, 0, 2, 64, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 2, 64, 0, 0, 1, 4, 0, 0, 0,204, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 10, 0, 0, 0,204, 0, 0, 1, 4,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 4, 0, 0, 2, 64, 0, 0, 0, 91, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 65,
+ 0, 0, 0, 91, 0, 0, 2, 64, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 64, 0, 0, 2, 66, 0, 0, 2, 65, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,146, 0, 0, 2, 65, 0, 0, 2, 66, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 66, 0, 0, 2, 64,
+ 0, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,205, 0, 0, 0, 22, 0, 0, 1,114, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1,114, 0, 0, 2, 66, 0, 0, 0,205, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 63, 0, 0, 0,205, 0, 0, 2, 66,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 66, 0, 0, 1,114, 0, 0, 0,146, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 65,
+ 0, 0, 0,146, 0, 0, 1,115, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,115, 0, 0, 1, 5, 0, 0, 2, 65, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 91, 0, 0, 2, 65, 0, 0, 1, 5, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 5, 0, 0, 1,115,
+ 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,203, 0, 0, 0, 62, 0, 0, 2, 67, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 2, 67, 0, 0, 1,112, 0, 0, 0,203, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 22, 0, 0, 0,203, 0, 0, 1,112,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,112, 0, 0, 2, 67, 0, 0, 0,145, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 68,
+ 0, 0, 0,145, 0, 0, 2, 67, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 67, 0, 0, 2, 69, 0, 0, 2, 68, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 80, 0, 0, 2, 68, 0, 0, 2, 69, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 69, 0, 0, 2, 67,
+ 0, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,202, 0, 0, 0, 5, 0, 0, 0,238, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0,238, 0, 0, 2, 69, 0, 0, 0,202, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 62, 0, 0, 0,202, 0, 0, 2, 69,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 69, 0, 0, 0,238, 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 68,
+ 0, 0, 0, 80, 0, 0, 0,239, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,239, 0, 0, 1,113, 0, 0, 2, 68, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,145, 0, 0, 2, 68, 0, 0, 1,113, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,113, 0, 0, 0,239,
+ 0, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 70, 0, 0, 0,147, 0, 0, 1,117, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1,117, 0, 0, 1, 11, 0, 0, 2, 70, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 94, 0, 0, 2, 70, 0, 0, 1, 11,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 11, 0, 0, 1,117, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 70,
+ 0, 0, 0, 94, 0, 0, 2, 71, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 71, 0, 0, 2, 72, 0, 0, 2, 70, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,147, 0, 0, 2, 70, 0, 0, 2, 72, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 72, 0, 0, 2, 71,
+ 0, 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,243, 0, 0, 0, 32, 0, 0, 1,116, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1,116, 0, 0, 2, 72, 0, 0, 0,243, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 82, 0, 0, 0,243, 0, 0, 2, 72,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 72, 0, 0, 1,116, 0, 0, 0,147, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,242,
+ 0, 0, 0, 82, 0, 0, 2, 71, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 71, 0, 0, 1, 10, 0, 0, 0,242, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 6, 0, 0, 0,242, 0, 0, 1, 10, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 10, 0, 0, 2, 71,
+ 0, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 73, 0, 0, 0,147, 0, 0, 1,116, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1,116, 0, 0, 1,118, 0, 0, 2, 73, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,148, 0, 0, 2, 73, 0, 0, 1,118,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,118, 0, 0, 1,116, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 73,
+ 0, 0, 0,148, 0, 0, 2, 74, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 74, 0, 0, 2, 75, 0, 0, 2, 73, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,147, 0, 0, 2, 73, 0, 0, 2, 75, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 75, 0, 0, 2, 74,
+ 0, 0, 0,149, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,121, 0, 0, 0, 38, 0, 0, 1,117, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1,117, 0, 0, 2, 75, 0, 0, 1,121, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,149, 0, 0, 1,121, 0, 0, 2, 75,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 75, 0, 0, 1,117, 0, 0, 0,147, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,120,
+ 0, 0, 0,149, 0, 0, 2, 74, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 74, 0, 0, 1,119, 0, 0, 1,120, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 37, 0, 0, 1,120, 0, 0, 1,119, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,119, 0, 0, 2, 74,
+ 0, 0, 0,148, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 76, 0, 0, 0, 93, 0, 0, 1, 8, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 8, 0, 0, 1, 12, 0, 0, 2, 76, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 95, 0, 0, 2, 76, 0, 0, 1, 12,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 12, 0, 0, 1, 8, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 76,
+ 0, 0, 0, 95, 0, 0, 2, 77, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 77, 0, 0, 2, 78, 0, 0, 2, 76, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 93, 0, 0, 2, 76, 0, 0, 2, 78, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 78, 0, 0, 2, 77,
+ 0, 0, 0,149, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,120, 0, 0, 0, 37, 0, 0, 1, 9, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 9, 0, 0, 2, 78, 0, 0, 1,120, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,149, 0, 0, 1,120, 0, 0, 2, 78,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 78, 0, 0, 1, 9, 0, 0, 0, 93, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,121,
+ 0, 0, 0,149, 0, 0, 2, 77, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 77, 0, 0, 1, 13, 0, 0, 1,121, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 38, 0, 0, 1,121, 0, 0, 1, 13, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 13, 0, 0, 2, 77,
+ 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 79, 0, 0, 0, 92, 0, 0, 1, 7, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 7, 0, 0, 1,119, 0, 0, 2, 79, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,148, 0, 0, 2, 79, 0, 0, 1,119,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,119, 0, 0, 1, 7, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 79,
+ 0, 0, 0,148, 0, 0, 2, 80, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 80, 0, 0, 2, 81, 0, 0, 2, 79, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 92, 0, 0, 2, 79, 0, 0, 2, 81, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 81, 0, 0, 2, 80,
+ 0, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,244, 0, 0, 0, 10, 0, 0, 1, 6, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 6, 0, 0, 2, 81, 0, 0, 0,244, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 83, 0, 0, 0,244, 0, 0, 2, 81,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 81, 0, 0, 1, 6, 0, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,245,
+ 0, 0, 0, 83, 0, 0, 2, 80, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 80, 0, 0, 1,118, 0, 0, 0,245, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 32, 0, 0, 0,245, 0, 0, 1,118, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,118, 0, 0, 2, 80,
+ 0, 0, 0,148, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 82, 0, 0, 0,150, 0, 0, 1,123, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1,123, 0, 0, 1, 15, 0, 0, 2, 82, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 96, 0, 0, 2, 82, 0, 0, 1, 15,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 15, 0, 0, 1,123, 0, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 82,
+ 0, 0, 0, 96, 0, 0, 2, 83, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 83, 0, 0, 2, 84, 0, 0, 2, 82, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,150, 0, 0, 2, 82, 0, 0, 2, 84, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 84, 0, 0, 2, 83,
+ 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,249, 0, 0, 0, 33, 0, 0, 1,122, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1,122, 0, 0, 2, 84, 0, 0, 0,249, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 85, 0, 0, 0,249, 0, 0, 2, 84,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 84, 0, 0, 1,122, 0, 0, 0,150, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,248,
+ 0, 0, 0, 85, 0, 0, 2, 83, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 83, 0, 0, 1, 14, 0, 0, 0,248, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 7, 0, 0, 0,248, 0, 0, 1, 14, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 14, 0, 0, 2, 83,
+ 0, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 85, 0, 0, 0,150, 0, 0, 1,122, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1,122, 0, 0, 1,124, 0, 0, 2, 85, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,151, 0, 0, 2, 85, 0, 0, 1,124,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,124, 0, 0, 1,122, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 85,
+ 0, 0, 0,151, 0, 0, 2, 86, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 86, 0, 0, 2, 87, 0, 0, 2, 85, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,150, 0, 0, 2, 85, 0, 0, 2, 87, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 87, 0, 0, 2, 86,
+ 0, 0, 0,152, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,127, 0, 0, 0, 39, 0, 0, 1,123, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1,123, 0, 0, 2, 87, 0, 0, 1,127, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,152, 0, 0, 1,127, 0, 0, 2, 87,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 87, 0, 0, 1,123, 0, 0, 0,150, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,126,
+ 0, 0, 0,152, 0, 0, 2, 86, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 86, 0, 0, 1,125, 0, 0, 1,126, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 38, 0, 0, 1,126, 0, 0, 1,125, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,125, 0, 0, 2, 86,
+ 0, 0, 0,151, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 88, 0, 0, 0, 95, 0, 0, 1, 12, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 12, 0, 0, 1, 16, 0, 0, 2, 88, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 97, 0, 0, 2, 88, 0, 0, 1, 16,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 16, 0, 0, 1, 12, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 88,
+ 0, 0, 0, 97, 0, 0, 2, 89, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 89, 0, 0, 2, 90, 0, 0, 2, 88, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 95, 0, 0, 2, 88, 0, 0, 2, 90, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 90, 0, 0, 2, 89,
+ 0, 0, 0,152, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,126, 0, 0, 0, 38, 0, 0, 1, 13, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 13, 0, 0, 2, 90, 0, 0, 1,126, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,152, 0, 0, 1,126, 0, 0, 2, 90,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 90, 0, 0, 1, 13, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,127,
+ 0, 0, 0,152, 0, 0, 2, 89, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 89, 0, 0, 1, 17, 0, 0, 1,127, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 39, 0, 0, 1,127, 0, 0, 1, 17, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 17, 0, 0, 2, 89,
+ 0, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 91, 0, 0, 0, 94, 0, 0, 1, 11, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 11, 0, 0, 1,125, 0, 0, 2, 91, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,151, 0, 0, 2, 91, 0, 0, 1,125,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,125, 0, 0, 1, 11, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 91,
+ 0, 0, 0,151, 0, 0, 2, 92, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 92, 0, 0, 2, 93, 0, 0, 2, 91, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 94, 0, 0, 2, 91, 0, 0, 2, 93, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 93, 0, 0, 2, 92,
+ 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,246, 0, 0, 0, 6, 0, 0, 1, 10, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 10, 0, 0, 2, 93, 0, 0, 0,246, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 84, 0, 0, 0,246, 0, 0, 2, 93,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 93, 0, 0, 1, 10, 0, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,247,
+ 0, 0, 0, 84, 0, 0, 2, 92, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 92, 0, 0, 1,124, 0, 0, 0,247, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 33, 0, 0, 0,247, 0, 0, 1,124, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,124, 0, 0, 2, 92,
+ 0, 0, 0,151, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 94, 0, 0, 0,153, 0, 0, 1,129, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1,129, 0, 0, 1, 19, 0, 0, 2, 94, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 98, 0, 0, 2, 94, 0, 0, 1, 19,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 19, 0, 0, 1,129, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 94,
+ 0, 0, 0, 98, 0, 0, 2, 95, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 95, 0, 0, 2, 96, 0, 0, 2, 94, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,153, 0, 0, 2, 94, 0, 0, 2, 96, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 96, 0, 0, 2, 95,
+ 0, 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,253, 0, 0, 0, 34, 0, 0, 1,128, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1,128, 0, 0, 2, 96, 0, 0, 0,253, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 87, 0, 0, 0,253, 0, 0, 2, 96,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 96, 0, 0, 1,128, 0, 0, 0,153, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,252,
+ 0, 0, 0, 87, 0, 0, 2, 95, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 95, 0, 0, 1, 18, 0, 0, 0,252, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 8, 0, 0, 0,252, 0, 0, 1, 18, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 18, 0, 0, 2, 95,
+ 0, 0, 0, 98, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 97, 0, 0, 0,153, 0, 0, 1,128, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1,128, 0, 0, 1,130, 0, 0, 2, 97, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,154, 0, 0, 2, 97, 0, 0, 1,130,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,130, 0, 0, 1,128, 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 97,
+ 0, 0, 0,154, 0, 0, 2, 98, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 98, 0, 0, 2, 99, 0, 0, 2, 97, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,153, 0, 0, 2, 97, 0, 0, 2, 99, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 99, 0, 0, 2, 98,
+ 0, 0, 0,155, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,133, 0, 0, 0, 40, 0, 0, 1,129, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1,129, 0, 0, 2, 99, 0, 0, 1,133, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,155, 0, 0, 1,133, 0, 0, 2, 99,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 99, 0, 0, 1,129, 0, 0, 0,153, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,132,
+ 0, 0, 0,155, 0, 0, 2, 98, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, 98, 0, 0, 1,131, 0, 0, 1,132, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 39, 0, 0, 1,132, 0, 0, 1,131, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,131, 0, 0, 2, 98,
+ 0, 0, 0,154, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,100, 0, 0, 0, 97, 0, 0, 1, 16, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 16, 0, 0, 1, 20, 0, 0, 2,100, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 99, 0, 0, 2,100, 0, 0, 1, 20,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 20, 0, 0, 1, 16, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,100,
+ 0, 0, 0, 99, 0, 0, 2,101, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,101, 0, 0, 2,102, 0, 0, 2,100, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 97, 0, 0, 2,100, 0, 0, 2,102, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,102, 0, 0, 2,101,
+ 0, 0, 0,155, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,132, 0, 0, 0, 39, 0, 0, 1, 17, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 17, 0, 0, 2,102, 0, 0, 1,132, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,155, 0, 0, 1,132, 0, 0, 2,102,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,102, 0, 0, 1, 17, 0, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,133,
+ 0, 0, 0,155, 0, 0, 2,101, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,101, 0, 0, 1, 21, 0, 0, 1,133, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 40, 0, 0, 1,133, 0, 0, 1, 21, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 21, 0, 0, 2,101,
+ 0, 0, 0, 99, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,103, 0, 0, 0, 96, 0, 0, 1, 15, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 15, 0, 0, 1,131, 0, 0, 2,103, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,154, 0, 0, 2,103, 0, 0, 1,131,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,131, 0, 0, 1, 15, 0, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,103,
+ 0, 0, 0,154, 0, 0, 2,104, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,104, 0, 0, 2,105, 0, 0, 2,103, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 96, 0, 0, 2,103, 0, 0, 2,105, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,105, 0, 0, 2,104,
+ 0, 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,250, 0, 0, 0, 7, 0, 0, 1, 14, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 14, 0, 0, 2,105, 0, 0, 0,250, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 86, 0, 0, 0,250, 0, 0, 2,105,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,105, 0, 0, 1, 14, 0, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,251,
+ 0, 0, 0, 86, 0, 0, 2,104, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,104, 0, 0, 1,130, 0, 0, 0,251, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 34, 0, 0, 0,251, 0, 0, 1,130, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,130, 0, 0, 2,104,
+ 0, 0, 0,154, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,106, 0, 0, 0,156, 0, 0, 1,135, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1,135, 0, 0, 1, 23, 0, 0, 2,106, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,100, 0, 0, 2,106, 0, 0, 1, 23,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 23, 0, 0, 1,135, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,106,
+ 0, 0, 0,100, 0, 0, 2,107, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,107, 0, 0, 2,108, 0, 0, 2,106, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,156, 0, 0, 2,106, 0, 0, 2,108, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,108, 0, 0, 2,107,
+ 0, 0, 0, 89, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 1, 0, 0, 0, 35, 0, 0, 1,134, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1,134, 0, 0, 2,108, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 89, 0, 0, 1, 1, 0, 0, 2,108,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,108, 0, 0, 1,134, 0, 0, 0,156, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 0,
+ 0, 0, 0, 89, 0, 0, 2,107, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,107, 0, 0, 1, 22, 0, 0, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 9, 0, 0, 1, 0, 0, 0, 1, 22, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 22, 0, 0, 2,107,
+ 0, 0, 0,100, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,109, 0, 0, 0,156, 0, 0, 1,134, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1,134, 0, 0, 1,136, 0, 0, 2,109, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,157, 0, 0, 2,109, 0, 0, 1,136,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,136, 0, 0, 1,134, 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,109,
+ 0, 0, 0,157, 0, 0, 2,110, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,110, 0, 0, 2,111, 0, 0, 2,109, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,156, 0, 0, 2,109, 0, 0, 2,111, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,111, 0, 0, 2,110,
+ 0, 0, 0,158, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,139, 0, 0, 0, 41, 0, 0, 1,135, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1,135, 0, 0, 2,111, 0, 0, 1,139, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,158, 0, 0, 1,139, 0, 0, 2,111,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,111, 0, 0, 1,135, 0, 0, 0,156, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,138,
+ 0, 0, 0,158, 0, 0, 2,110, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,110, 0, 0, 1,137, 0, 0, 1,138, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 40, 0, 0, 1,138, 0, 0, 1,137, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,137, 0, 0, 2,110,
+ 0, 0, 0,157, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,112, 0, 0, 0, 99, 0, 0, 1, 20, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 20, 0, 0, 1, 24, 0, 0, 2,112, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,101, 0, 0, 2,112, 0, 0, 1, 24,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 24, 0, 0, 1, 20, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,112,
+ 0, 0, 0,101, 0, 0, 2,113, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,113, 0, 0, 2,114, 0, 0, 2,112, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 99, 0, 0, 2,112, 0, 0, 2,114, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,114, 0, 0, 2,113,
+ 0, 0, 0,158, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,138, 0, 0, 0, 40, 0, 0, 1, 21, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 21, 0, 0, 2,114, 0, 0, 1,138, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,158, 0, 0, 1,138, 0, 0, 2,114,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,114, 0, 0, 1, 21, 0, 0, 0, 99, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,139,
+ 0, 0, 0,158, 0, 0, 2,113, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,113, 0, 0, 1, 25, 0, 0, 1,139, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 41, 0, 0, 1,139, 0, 0, 1, 25, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 25, 0, 0, 2,113,
+ 0, 0, 0,101, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,115, 0, 0, 0, 98, 0, 0, 1, 19, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 19, 0, 0, 1,137, 0, 0, 2,115, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,157, 0, 0, 2,115, 0, 0, 1,137,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,137, 0, 0, 1, 19, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,115,
+ 0, 0, 0,157, 0, 0, 2,116, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,116, 0, 0, 2,117, 0, 0, 2,115, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 98, 0, 0, 2,115, 0, 0, 2,117, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,117, 0, 0, 2,116,
+ 0, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,254, 0, 0, 0, 8, 0, 0, 1, 18, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 18, 0, 0, 2,117, 0, 0, 0,254, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 88, 0, 0, 0,254, 0, 0, 2,117,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,117, 0, 0, 1, 18, 0, 0, 0, 98, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,255,
+ 0, 0, 0, 88, 0, 0, 2,116, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,116, 0, 0, 1,136, 0, 0, 0,255, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 35, 0, 0, 0,255, 0, 0, 1,136, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,136, 0, 0, 2,116,
+ 0, 0, 0,157, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,118, 0, 0, 0,159, 0, 0, 1,141, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1,141, 0, 0, 1, 7, 0, 0, 2,118, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 92, 0, 0, 2,118, 0, 0, 1, 7,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 7, 0, 0, 1,141, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,118,
+ 0, 0, 0, 92, 0, 0, 2,119, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,119, 0, 0, 2,120, 0, 0, 2,118, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,159, 0, 0, 2,118, 0, 0, 2,120, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,120, 0, 0, 2,119,
+ 0, 0, 0, 91, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 5, 0, 0, 0, 36, 0, 0, 1,140, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1,140, 0, 0, 2,120, 0, 0, 1, 5, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 91, 0, 0, 1, 5, 0, 0, 2,120,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,120, 0, 0, 1,140, 0, 0, 0,159, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 4,
+ 0, 0, 0, 91, 0, 0, 2,119, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,119, 0, 0, 1, 6, 0, 0, 1, 4, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 10, 0, 0, 1, 4, 0, 0, 1, 6, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 6, 0, 0, 2,119,
+ 0, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,121, 0, 0, 0,159, 0, 0, 1,140, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1,140, 0, 0, 1,142, 0, 0, 2,121, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,160, 0, 0, 2,121, 0, 0, 1,142,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,142, 0, 0, 1,140, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,121,
+ 0, 0, 0,160, 0, 0, 2,122, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,122, 0, 0, 2,123, 0, 0, 2,121, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,159, 0, 0, 2,121, 0, 0, 2,123, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,123, 0, 0, 2,122,
+ 0, 0, 0,161, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,144, 0, 0, 0, 37, 0, 0, 1,141, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1,141, 0, 0, 2,123, 0, 0, 1,144, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,161, 0, 0, 1,144, 0, 0, 2,123,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,123, 0, 0, 1,141, 0, 0, 0,159, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,145,
+ 0, 0, 0,161, 0, 0, 2,122, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,122, 0, 0, 1,143, 0, 0, 1,145, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 41, 0, 0, 1,145, 0, 0, 1,143, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,143, 0, 0, 2,122,
+ 0, 0, 0,160, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,124, 0, 0, 0,101, 0, 0, 1, 24, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 24, 0, 0, 1, 8, 0, 0, 2,124, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 93, 0, 0, 2,124, 0, 0, 1, 8,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 8, 0, 0, 1, 24, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,124,
+ 0, 0, 0, 93, 0, 0, 2,125, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,125, 0, 0, 2,126, 0, 0, 2,124, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,101, 0, 0, 2,124, 0, 0, 2,126, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,126, 0, 0, 2,125,
+ 0, 0, 0,161, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,145, 0, 0, 0, 41, 0, 0, 1, 25, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 25, 0, 0, 2,126, 0, 0, 1,145, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,161, 0, 0, 1,145, 0, 0, 2,126,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,126, 0, 0, 1, 25, 0, 0, 0,101, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,144,
+ 0, 0, 0,161, 0, 0, 2,125, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,125, 0, 0, 1, 9, 0, 0, 1,144, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 37, 0, 0, 1,144, 0, 0, 1, 9, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 9, 0, 0, 2,125,
+ 0, 0, 0, 93, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,127, 0, 0, 0,100, 0, 0, 1, 23, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 23, 0, 0, 1,143, 0, 0, 2,127, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0,160, 0, 0, 2,127, 0, 0, 1,143,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,143, 0, 0, 1, 23, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,127,
+ 0, 0, 0,160, 0, 0, 2,128, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,128, 0, 0, 2,129, 0, 0, 2,127, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0,100, 0, 0, 2,127, 0, 0, 2,129, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,129, 0, 0, 2,128,
+ 0, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 2, 0, 0, 0, 9, 0, 0, 1, 22, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 1, 22, 0, 0, 2,129, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 90, 0, 0, 1, 2, 0, 0, 2,129,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,129, 0, 0, 1, 22, 0, 0, 0,100, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 3,
+ 0, 0, 0, 90, 0, 0, 2,128, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2,128, 0, 0, 1,142, 0, 0, 1, 3, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 36, 0, 0, 1, 3, 0, 0, 1,142, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1,142, 0, 0, 2,128,
+ 0, 0, 0,160, 0, 0, 0, 0, 0, 0, 0, 3, 68, 65, 84, 65, 0, 0,220, 0, 8,108,128, 32, 0, 0, 0, 60, 0, 0, 5, 0,
+ 63,110,222,166, 63, 55,205, 9, 63,105,132,212, 63, 65,236,201, 63,103,153,218, 63, 54,155,119, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,103,153,218, 63, 54,155,119, 63,108,148,118, 63, 44,160,211, 63,110,222,166,
+ 63, 55,205, 9, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,115, 51, 36, 63, 45, 28, 36,
+ 63,110,222,166, 63, 55,205, 9, 63,108,148,118, 63, 44,160,211, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63,108,148,118, 63, 44,160,211, 63,103,153,218, 63, 54,155,119, 63,102, 17, 87, 63, 43, 52,229, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 96, 81, 56, 63, 52, 55,170, 63,102, 17, 87, 63, 43, 52,229,
+ 63,103,153,218, 63, 54,155,119, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,103,153,218,
+ 63, 54,155,119, 63, 97, 75, 9, 63, 63,233, 92, 63, 96, 81, 56, 63, 52, 55,170, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 89,153,138, 63, 60, 86, 49, 63, 96, 81, 56, 63, 52, 55,170, 63, 97, 75, 9, 63, 63,233, 92,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 97, 75, 9, 63, 63,233, 92, 63,103,153,218,
+ 63, 54,155,119, 63,105,132,212, 63, 65,236,201, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 98,167,103, 63, 75, 39,168, 63, 89,153,138, 63, 82,228, 39, 63, 89,153,139, 63, 71,153,255, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 89,153,139, 63, 71,153,255, 63, 97, 75, 9, 63, 63,233, 92, 63, 98,167,103,
+ 63, 75, 39,168, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,105,132,212, 63, 65,236,201,
+ 63, 98,167,103, 63, 75, 39,168, 63, 97, 75, 9, 63, 63,233, 92, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 97, 75, 9, 63, 63,233, 92, 63, 89,153,139, 63, 71,153,255, 63, 89,153,138, 63, 60, 86, 49, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 96, 81, 56, 63, 52, 55,170, 63, 89,153,138, 63, 60, 86, 49,
+ 63, 89,153,139, 63, 49, 12, 79, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 89,153,139,
+ 63, 49, 12, 79, 63, 95,182,205, 63, 40,228,222, 63, 96, 81, 56, 63, 52, 55,170, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63,102, 17, 87, 63, 43, 52,229, 63, 96, 81, 56, 63, 52, 55,170, 63, 95,182,205, 63, 40,228,222,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 95,182,205, 63, 40,228,222, 63, 89,153,139,
+ 63, 49, 12, 79, 63, 89,153,139, 63, 37,200, 45, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 98,167,103, 63, 75, 39,168, 63,105,132,212, 63, 65,236,201, 63,109, 83,168, 63, 78, 83,207, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,109, 83,168, 63, 78, 83,207, 63,101, 85,135, 63, 88, 64,148, 63, 98,167,103,
+ 63, 75, 39,168, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 89,153,138, 63, 82,228, 39,
+ 63, 98,167,103, 63, 75, 39,168, 63,101, 85,135, 63, 88, 64,148, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63,101, 85,135, 63, 88, 64,148, 63,109, 83,168, 63, 78, 83,207, 63,115, 51, 36, 63, 90, 56, 22, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,121, 18,162, 63, 78, 83,207, 63,115, 51, 36, 63, 90, 56, 22,
+ 63,109, 83,168, 63, 78, 83,207, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,109, 83,168,
+ 63, 78, 83,207, 63,115, 51, 36, 63, 67, 23,115, 63,121, 18,162, 63, 78, 83,207, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63,124,225,116, 63, 65,236,202, 63,121, 18,162, 63, 78, 83,207, 63,115, 51, 36, 63, 67, 23,115,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,115, 51, 36, 63, 67, 23,115, 63,109, 83,168,
+ 63, 78, 83,207, 63,105,132,212, 63, 65,236,201, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63,110,222,166, 63, 55,205, 9, 63,115, 51, 36, 63, 45, 28, 36, 63,119,135,163, 63, 55,205, 11, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,119,135,163, 63, 55,205, 11, 63,115, 51, 36, 63, 67, 23,115, 63,110,222,166,
+ 63, 55,205, 9, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,105,132,212, 63, 65,236,201,
+ 63,110,222,166, 63, 55,205, 9, 63,115, 51, 36, 63, 67, 23,115, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63,115, 51, 36, 63, 67, 23,115, 63,119,135,163, 63, 55,205, 11, 63,124,225,116, 63, 65,236,202, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,121, 18,162, 63, 78, 83,207, 63,124,225,116, 63, 65,236,202,
+ 63,129,223,113, 63, 75, 39,170, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,129,223,113,
+ 63, 75, 39,170, 63,128,136, 98, 63, 88, 64,148, 63,121, 18,162, 63, 78, 83,207, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63,115, 51, 36, 63, 90, 56, 22, 63,121, 18,162, 63, 78, 83,207, 63,128,136, 98, 63, 88, 64,148,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 59,136, 98, 95, 63, 88, 64,148, 60,111,184,160,
+ 63, 75, 39,170, 61, 76,203,243, 63, 82,228, 41, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 61, 76,203,243, 63, 49, 12, 82, 61, 76,203,246, 63, 60, 86, 53, 60,194,162, 31, 63, 52, 55,172, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 60,194,162, 31, 63, 52, 55,172, 60,213,239,111, 63, 40,228,223, 61, 76,203,243,
+ 63, 49, 12, 82, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61, 76,203,246, 63, 37,200, 48,
+ 61, 76,203,243, 63, 49, 12, 82, 60,213,239,111, 63, 40,228,223, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 60,213,239,111, 63, 40,228,223, 60,194,162, 31, 63, 52, 55,172, 58,169,226,120, 63, 43, 52,230, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,126,204,111, 63, 54,155,121, 63,128, 42,121, 63, 43, 52,230,
+ 63,131, 10,136, 63, 52, 55,172, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,131, 10,136,
+ 63, 52, 55,172, 63,130,141,160, 63, 63,233, 95, 63,126,204,111, 63, 54,155,121, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63,124,225,116, 63, 65,236,202, 63,126,204,111, 63, 54,155,121, 63,130,141,160, 63, 63,233, 95,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 60,163,104, 11, 63, 63,233, 95, 60,194,162, 31,
+ 63, 52, 55,172, 61, 76,203,246, 63, 60, 86, 53, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 61, 76,203,244, 63, 71,154, 2, 61, 76,203,243, 63, 82,228, 41, 60,111,184,160, 63, 75, 39,170, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 60,111,184,160, 63, 75, 39,170, 60,163,104, 11, 63, 63,233, 95, 61, 76,203,244,
+ 63, 71,154, 2, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61, 76,203,246, 63, 60, 86, 53,
+ 61, 76,203,244, 63, 71,154, 2, 60,163,104, 11, 63, 63,233, 95, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63,130,141,160, 63, 63,233, 95, 63,129,223,113, 63, 75, 39,170, 63,124,225,116, 63, 65,236,202, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,126,204,111, 63, 54,155,121, 63,124,225,116, 63, 65,236,202,
+ 63,119,135,163, 63, 55,205, 11, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,119,135,163,
+ 63, 55,205, 11, 63,121,209,210, 63, 44,160,212, 63,126,204,111, 63, 54,155,121, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63,128, 42,121, 63, 43, 52,230, 63,126,204,111, 63, 54,155,121, 63,121,209,210, 63, 44,160,212,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,121,209,210, 63, 44,160,212, 63,119,135,163,
+ 63, 55,205, 11, 63,115, 51, 36, 63, 45, 28, 36, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63,134,102, 95, 63, 94, 46, 79, 63,134,102, 95, 63,105,114, 22, 63,124,205, 52, 63, 99, 26, 58, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,124,205, 52, 63, 99, 26, 58, 63,128,136, 98, 63, 88, 64,148, 63,134,102, 95,
+ 63, 94, 46, 79, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61, 76,203,243, 63, 82,228, 41,
+ 61, 76,203,234, 63, 94, 46, 79, 59,136, 98, 95, 63, 88, 64,148, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63,128,136, 98, 63, 88, 64,148, 63,124,205, 52, 63, 99, 26, 58, 63,115, 51, 36, 63, 90, 56, 22, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,105,153, 21, 63, 99, 26, 58, 63,115, 51, 36, 63, 90, 56, 22,
+ 63,124,205, 52, 63, 99, 26, 58, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,124,205, 52,
+ 63, 99, 26, 58, 63,115, 51, 32, 63,109,154,212, 63,105,153, 21, 63, 99, 26, 58, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 89,153,138, 63,105,114, 19, 63,105,153, 21, 63, 99, 26, 58, 63,115, 51, 32, 63,109,154,212,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,115, 51, 32, 63,109,154,212, 63,124,205, 52,
+ 63, 99, 26, 58, 63,134,102, 95, 63,105,114, 22, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63,134,102, 95, 63,116,187,242, 63, 59,153, 3, 63,128, 0, 0, 63, 89,153,136, 63,116,187,242, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 89,153,136, 63,116,187,242, 63,115, 51, 32, 63,109,154,212, 63,134,102, 95,
+ 63,116,187,242, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,134,102, 95, 63,105,114, 22,
+ 63,134,102, 95, 63,116,187,242, 63,115, 51, 32, 63,109,154,212, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63,115, 51, 32, 63,109,154,212, 63, 89,153,136, 63,116,187,242, 63, 89,153,138, 63,105,114, 19, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,105,153, 21, 63, 99, 26, 58, 63, 89,153,138, 63,105,114, 19,
+ 63, 89,153,138, 63, 94, 46, 77, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 89,153,138,
+ 63, 94, 46, 77, 63,101, 85,135, 63, 88, 64,148, 63,105,153, 21, 63, 99, 26, 58, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63,115, 51, 36, 63, 90, 56, 22, 63,105,153, 21, 63, 99, 26, 58, 63,101, 85,135, 63, 88, 64,148,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,101, 85,135, 63, 88, 64,148, 63, 89,153,138,
+ 63, 94, 46, 77, 63, 89,153,138, 63, 82,228, 39, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 75,153, 67, 63, 54,155,113, 63, 73,174, 74, 63, 65,236,193, 63, 68, 84,124, 63, 55,204,255, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 68, 84,124, 63, 55,204,255, 63, 70,158,169, 63, 44,160,200, 63, 75,153, 67,
+ 63, 54,155,113, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 77, 33,196, 63, 43, 52,221,
+ 63, 75,153, 67, 63, 54,155,113, 63, 70,158,169, 63, 44,160,200, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 70,158,169, 63, 44,160,200, 63, 68, 84,124, 63, 55,204,255, 63, 64, 0, 0, 63, 45, 28, 24, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 75,153, 67, 63, 54,155,113, 63, 77, 33,196, 63, 43, 52,221,
+ 63, 82,225,225, 63, 52, 55,165, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 82,225,225,
+ 63, 52, 55,165, 63, 81,232, 16, 63, 63,233, 89, 63, 75,153, 67, 63, 54,155,113, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 73,174, 74, 63, 65,236,193, 63, 75,153, 67, 63, 54,155,113, 63, 81,232, 16, 63, 63,233, 89,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 81,232, 16, 63, 63,233, 89, 63, 82,225,225,
+ 63, 52, 55,165, 63, 89,153,138, 63, 60, 86, 49, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 89,153,139, 63, 71,153,255, 63, 89,153,138, 63, 82,228, 39, 63, 80,139,179, 63, 75, 39,164, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 80,139,179, 63, 75, 39,164, 63, 81,232, 16, 63, 63,233, 89, 63, 89,153,139,
+ 63, 71,153,255, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 89,153,138, 63, 60, 86, 49,
+ 63, 89,153,139, 63, 71,153,255, 63, 81,232, 16, 63, 63,233, 89, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 81,232, 16, 63, 63,233, 89, 63, 80,139,179, 63, 75, 39,164, 63, 73,174, 74, 63, 65,236,193, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 89,153,139, 63, 49, 12, 79, 63, 89,153,138, 63, 60, 86, 49,
+ 63, 82,225,225, 63, 52, 55,165, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 82,225,225,
+ 63, 52, 55,165, 63, 83,124, 75, 63, 40,228,217, 63, 89,153,139, 63, 49, 12, 79, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 89,153,139, 63, 37,200, 45, 63, 89,153,139, 63, 49, 12, 79, 63, 83,124, 75, 63, 40,228,217,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 83,124, 75, 63, 40,228,217, 63, 82,225,225,
+ 63, 52, 55,165, 63, 77, 33,196, 63, 43, 52,221, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 69,223,120, 63, 78, 83,198, 63, 73,174, 74, 63, 65,236,193, 63, 80,139,179, 63, 75, 39,164, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 80,139,179, 63, 75, 39,164, 63, 77,221,148, 63, 88, 64,140, 63, 69,223,120,
+ 63, 78, 83,198, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 64, 0, 0, 63, 90, 56, 12,
+ 63, 69,223,120, 63, 78, 83,198, 63, 77,221,148, 63, 88, 64,140, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 77,221,148, 63, 88, 64,140, 63, 80,139,179, 63, 75, 39,164, 63, 89,153,138, 63, 82,228, 39, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 69,223,120, 63, 78, 83,198, 63, 64, 0, 0, 63, 90, 56, 12,
+ 63, 58, 32,136, 63, 78, 83,198, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 58, 32,136,
+ 63, 78, 83,198, 63, 64, 0, 0, 63, 67, 23,106, 63, 69,223,120, 63, 78, 83,198, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 73,174, 74, 63, 65,236,193, 63, 69,223,120, 63, 78, 83,198, 63, 64, 0, 0, 63, 67, 23,106,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 64, 0, 0, 63, 67, 23,106, 63, 58, 32,136,
+ 63, 78, 83,198, 63, 54, 81,182, 63, 65,236,193, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 59,171,132, 63, 55,204,255, 63, 64, 0, 0, 63, 45, 28, 24, 63, 68, 84,124, 63, 55,204,255, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 68, 84,124, 63, 55,204,255, 63, 64, 0, 0, 63, 67, 23,106, 63, 59,171,132,
+ 63, 55,204,255, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 54, 81,182, 63, 65,236,193,
+ 63, 59,171,132, 63, 55,204,255, 63, 64, 0, 0, 63, 67, 23,106, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 64, 0, 0, 63, 67, 23,106, 63, 68, 84,124, 63, 55,204,255, 63, 73,174, 74, 63, 65,236,193, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 47,116, 77, 63, 75, 39,164, 63, 54, 81,182, 63, 65,236,193,
+ 63, 58, 32,136, 63, 78, 83,198, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 58, 32,136,
+ 63, 78, 83,198, 63, 50, 34,108, 63, 88, 64,140, 63, 47,116, 77, 63, 75, 39,164, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 38,102,118, 63, 82,228, 38, 63, 47,116, 77, 63, 75, 39,164, 63, 50, 34,108, 63, 88, 64,140,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 50, 34,108, 63, 88, 64,140, 63, 58, 32,136,
+ 63, 78, 83,198, 63, 64, 0, 0, 63, 90, 56, 12, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 45, 30, 31, 63, 52, 55,165, 63, 38,102,117, 63, 60, 86, 50, 63, 38,102,117, 63, 49, 12, 78, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 38,102,117, 63, 49, 12, 78, 63, 44,131,181, 63, 40,228,216, 63, 45, 30, 31,
+ 63, 52, 55,165, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 50,222, 60, 63, 43, 52,221,
+ 63, 45, 30, 31, 63, 52, 55,165, 63, 44,131,181, 63, 40,228,216, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 44,131,181, 63, 40,228,216, 63, 38,102,117, 63, 49, 12, 78, 63, 38,102,117, 63, 37,200, 45, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 45, 30, 31, 63, 52, 55,165, 63, 50,222, 60, 63, 43, 52,221,
+ 63, 52,102,189, 63, 54,155,113, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 52,102,189,
+ 63, 54,155,113, 63, 46, 23,240, 63, 63,233, 89, 63, 45, 30, 31, 63, 52, 55,165, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 38,102,117, 63, 60, 86, 50, 63, 45, 30, 31, 63, 52, 55,165, 63, 46, 23,240, 63, 63,233, 89,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 46, 23,240, 63, 63,233, 89, 63, 52,102,189,
+ 63, 54,155,113, 63, 54, 81,182, 63, 65,236,193, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 47,116, 77, 63, 75, 39,164, 63, 38,102,118, 63, 82,228, 38, 63, 38,102,117, 63, 71,153,255, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 38,102,117, 63, 71,153,255, 63, 46, 23,240, 63, 63,233, 89, 63, 47,116, 77,
+ 63, 75, 39,164, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 54, 81,182, 63, 65,236,193,
+ 63, 47,116, 77, 63, 75, 39,164, 63, 46, 23,240, 63, 63,233, 89, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 46, 23,240, 63, 63,233, 89, 63, 38,102,117, 63, 71,153,255, 63, 38,102,117, 63, 60, 86, 50, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 59,171,132, 63, 55,204,255, 63, 54, 81,182, 63, 65,236,193,
+ 63, 52,102,189, 63, 54,155,113, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 52,102,189,
+ 63, 54,155,113, 63, 57, 97, 87, 63, 44,160,200, 63, 59,171,132, 63, 55,204,255, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 64, 0, 0, 63, 45, 28, 24, 63, 59,171,132, 63, 55,204,255, 63, 57, 97, 87, 63, 44,160,200,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 57, 97, 87, 63, 44,160,200, 63, 52,102,189,
+ 63, 54,155,113, 63, 50,222, 60, 63, 43, 52,221, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 54,101,250, 63, 99, 26, 51, 63, 38,102,118, 63,105,114, 19, 63, 38,102,118, 63, 94, 46, 77, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 38,102,118, 63, 94, 46, 77, 63, 50, 34,108, 63, 88, 64,140, 63, 54,101,250,
+ 63, 99, 26, 51, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 64, 0, 0, 63, 90, 56, 12,
+ 63, 54,101,250, 63, 99, 26, 51, 63, 50, 34,108, 63, 88, 64,140, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 50, 34,108, 63, 88, 64,140, 63, 38,102,118, 63, 94, 46, 77, 63, 38,102,118, 63, 82,228, 38, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 54,101,250, 63, 99, 26, 51, 63, 64, 0, 0, 63, 90, 56, 12,
+ 63, 73,154, 6, 63, 99, 26, 51, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 73,154, 6,
+ 63, 99, 26, 51, 63, 64, 0, 0, 63,109,154,206, 63, 54,101,250, 63, 99, 26, 51, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 38,102,118, 63,105,114, 19, 63, 54,101,250, 63, 99, 26, 51, 63, 64, 0, 0, 63,109,154,206,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 64, 0, 0, 63,109,154,206, 63, 73,154, 6,
+ 63, 99, 26, 51, 63, 89,153,138, 63,105,114, 19, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 89,153,136, 63,116,187,242, 63, 59,153, 3, 63,128, 0, 0, 63, 38,102,120, 63,116,187,242, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 38,102,120, 63,116,187,242, 63, 64, 0, 0, 63,109,154,206, 63, 89,153,136,
+ 63,116,187,242, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 89,153,138, 63,105,114, 19,
+ 63, 89,153,136, 63,116,187,242, 63, 64, 0, 0, 63,109,154,206, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 64, 0, 0, 63,109,154,206, 63, 38,102,120, 63,116,187,242, 63, 38,102,118, 63,105,114, 19, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 89,153,138, 63, 94, 46, 77, 63, 89,153,138, 63,105,114, 19,
+ 63, 73,154, 6, 63, 99, 26, 51, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 73,154, 6,
+ 63, 99, 26, 51, 63, 77,221,148, 63, 88, 64,140, 63, 89,153,138, 63, 94, 46, 77, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 89,153,138, 63, 82,228, 39, 63, 89,153,138, 63, 94, 46, 77, 63, 77,221,148, 63, 88, 64,140,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 77,221,148, 63, 88, 64,140, 63, 73,154, 6,
+ 63, 99, 26, 51, 63, 64, 0, 0, 63, 90, 56, 12, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62, 8, 71,167, 63, 55,205, 7, 61,229,192,170, 63, 65,236,200, 61,214,104,203, 63, 54,155,120, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,214,104,203, 63, 54,155,120, 61,254, 61,201, 63, 44,160,207, 62, 8, 71,167,
+ 63, 55,205, 7, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 25,153,173, 63, 45, 28, 27,
+ 62, 8, 71,167, 63, 55,205, 7, 61,254, 61,201, 63, 44,160,207, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 61,254, 61,201, 63, 44,160,207, 61,214,104,203, 63, 54,155,120, 61,202, 36,175, 63, 43, 52,228, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,156, 35,145, 63, 52, 55,172, 61,202, 36,175, 63, 43, 52,228,
+ 61,214,104,203, 63, 54,155,120, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,214,104,203,
+ 63, 54,155,120, 61,163,242, 32, 63, 63,233, 96, 61,156, 35,145, 63, 52, 55,172, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 61, 76,203,246, 63, 60, 86, 53, 61,156, 35,145, 63, 52, 55,172, 61,163,242, 32, 63, 63,233, 96,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,163,242, 32, 63, 63,233, 96, 61,214,104,203,
+ 63, 54,155,120, 61,229,192,170, 63, 65,236,200, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 61,174,213, 17, 63, 75, 39,171, 61, 76,203,243, 63, 82,228, 41, 61, 76,203,244, 63, 71,154, 2, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61, 76,203,244, 63, 71,154, 2, 61,163,242, 32, 63, 63,233, 96, 61,174,213, 17,
+ 63, 75, 39,171, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,229,192,170, 63, 65,236,200,
+ 61,174,213, 17, 63, 75, 39,171, 61,163,242, 32, 63, 63,233, 96, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 61,163,242, 32, 63, 63,233, 96, 61, 76,203,244, 63, 71,154, 2, 61, 76,203,246, 63, 60, 86, 53, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,156, 35,145, 63, 52, 55,172, 61, 76,203,246, 63, 60, 86, 53,
+ 61, 76,203,243, 63, 49, 12, 82, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61, 76,203,243,
+ 63, 49, 12, 82, 61,151, 80, 53, 63, 40,228,223, 61,156, 35,145, 63, 52, 55,172, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 61,202, 36,175, 63, 43, 52,228, 61,156, 35,145, 63, 52, 55,172, 61,151, 80, 53, 63, 40,228,223,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,151, 80, 53, 63, 40,228,223, 61, 76,203,243,
+ 63, 49, 12, 82, 61, 76,203,246, 63, 37,200, 48, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 61,174,213, 17, 63, 75, 39,171, 61,229,192,170, 63, 65,236,200, 62, 2, 27,169, 63, 78, 83,204, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 2, 27,169, 63, 78, 83,204, 61,196, 70, 23, 63, 88, 64,147, 61,174,213, 17,
+ 63, 75, 39,171, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61, 76,203,243, 63, 82,228, 41,
+ 61,174,213, 17, 63, 75, 39,171, 61,196, 70, 23, 63, 88, 64,147, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 61,196, 70, 23, 63, 88, 64,147, 62, 2, 27,169, 63, 78, 83,204, 62, 25,153,160, 63, 90, 56, 14, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 49, 23,162, 63, 78, 83,195, 62, 25,153,160, 63, 90, 56, 14,
+ 62, 2, 27,169, 63, 78, 83,204, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 2, 27,169,
+ 63, 78, 83,204, 62, 25,153,172, 63, 67, 23,108, 62, 49, 23,162, 63, 78, 83,195, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62, 64, 82,240, 63, 65,236,183, 62, 49, 23,162, 63, 78, 83,195, 62, 25,153,172, 63, 67, 23,108,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 25,153,172, 63, 67, 23,108, 62, 2, 27,169,
+ 63, 78, 83,204, 61,229,192,170, 63, 65,236,200, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62, 8, 71,167, 63, 55,205, 7, 62, 25,153,173, 63, 45, 28, 27, 62, 42,235,173, 63, 55,204,254, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 42,235,173, 63, 55,204,254, 62, 25,153,172, 63, 67, 23,108, 62, 8, 71,167,
+ 63, 55,205, 7, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,229,192,170, 63, 65,236,200,
+ 62, 8, 71,167, 63, 55,205, 7, 62, 25,153,172, 63, 67, 23,108, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62, 25,153,172, 63, 67, 23,108, 62, 42,235,173, 63, 55,204,254, 62, 64, 82,240, 63, 65,236,183, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 49, 23,162, 63, 78, 83,195, 62, 64, 82,240, 63, 65,236,183,
+ 62, 91,200,166, 63, 75, 39,147, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 91,200,166,
+ 63, 75, 39,147, 62, 81, 16, 34, 63, 88, 64,131, 62, 49, 23,162, 63, 78, 83,195, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62, 25,153,160, 63, 90, 56, 14, 62, 49, 23,162, 63, 78, 83,195, 62, 81, 16, 34, 63, 88, 64,131,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 81, 16, 34, 63, 88, 64,131, 62, 91,200,166,
+ 63, 75, 39,147, 62,128, 0, 0, 63, 82,228, 13, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,128, 0, 0, 63, 49, 12, 47, 62,128, 0, 0, 63, 60, 86, 19, 62,101, 33, 92, 63, 52, 55,146, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,101, 33, 92, 63, 52, 55,146, 62,103,139, 14, 63, 40,228,199, 62,128, 0, 0,
+ 63, 49, 12, 47, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,128, 0, 0, 63, 37,200, 23,
+ 62,128, 0, 0, 63, 49, 12, 47, 62,103,139, 14, 63, 40,228,199, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62,103,139, 14, 63, 40,228,199, 62,101, 33, 92, 63, 52, 55,146, 62, 78, 32,230, 63, 43, 52,211, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 71,254,223, 63, 54,155,102, 62, 78, 32,230, 63, 43, 52,211,
+ 62,101, 33, 92, 63, 52, 55,146, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,101, 33, 92,
+ 63, 52, 55,146, 62, 97, 58, 23, 63, 63,233, 69, 62, 71,254,223, 63, 54,155,102, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62, 64, 82,240, 63, 65,236,183, 62, 71,254,223, 63, 54,155,102, 62, 97, 58, 23, 63, 63,233, 69,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 97, 58, 23, 63, 63,233, 69, 62,101, 33, 92,
+ 63, 52, 55,146, 62,128, 0, 0, 63, 60, 86, 19, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,128, 0, 0, 63, 71,153,228, 62,128, 0, 0, 63, 82,228, 13, 62, 91,200,166, 63, 75, 39,147, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 91,200,166, 63, 75, 39,147, 62, 97, 58, 23, 63, 63,233, 69, 62,128, 0, 0,
+ 63, 71,153,228, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,128, 0, 0, 63, 60, 86, 19,
+ 62,128, 0, 0, 63, 71,153,228, 62, 97, 58, 23, 63, 63,233, 69, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62, 97, 58, 23, 63, 63,233, 69, 62, 91,200,166, 63, 75, 39,147, 62, 64, 82,240, 63, 65,236,183, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 71,254,223, 63, 54,155,102, 62, 64, 82,240, 63, 65,236,183,
+ 62, 42,235,173, 63, 55,204,254, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 42,235,173,
+ 63, 55,204,254, 62, 52, 20,105, 63, 44,160,198, 62, 71,254,223, 63, 54,155,102, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62, 78, 32,230, 63, 43, 52,211, 62, 71,254,223, 63, 54,155,102, 62, 52, 20,105, 63, 44,160,198,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 52, 20,105, 63, 44,160,198, 62, 42,235,173,
+ 63, 55,204,254, 62, 25,153,173, 63, 45, 28, 27, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,128, 0, 0, 63, 94, 46, 58, 62,128, 0, 0, 63,105,114, 8, 62, 64, 1,230, 63, 99, 26, 49, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 64, 1,230, 63, 99, 26, 49, 62, 81, 16, 34, 63, 88, 64,131, 62,128, 0, 0,
+ 63, 94, 46, 58, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,128, 0, 0, 63, 82,228, 13,
+ 62,128, 0, 0, 63, 94, 46, 58, 62, 81, 16, 34, 63, 88, 64,131, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62, 81, 16, 34, 63, 88, 64,131, 62, 64, 1,230, 63, 99, 26, 49, 62, 25,153,160, 63, 90, 56, 14, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,230, 98,164, 63, 99, 26, 58, 62, 25,153,160, 63, 90, 56, 14,
+ 62, 64, 1,230, 63, 99, 26, 49, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 64, 1,230,
+ 63, 99, 26, 49, 62, 25,153,159, 63,109,154,210, 61,230, 98,164, 63, 99, 26, 58, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 61, 76,203,237, 63,105,114, 22, 61,230, 98,164, 63, 99, 26, 58, 62, 25,153,159, 63,109,154,210,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 25,153,159, 63,109,154,210, 62, 64, 1,230,
+ 63, 99, 26, 49, 62,128, 0, 0, 63,105,114, 8, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,128, 0, 0, 63,116,187,232, 63, 59,153, 3, 63,128, 0, 0, 63,134,102, 95, 63,116,187,242, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61, 76,203,210, 63,116,187,242, 62, 25,153,159, 63,109,154,210, 62,128, 0, 0,
+ 63,116,187,232, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,128, 0, 0, 63,105,114, 8,
+ 62,128, 0, 0, 63,116,187,232, 62, 25,153,159, 63,109,154,210, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62, 25,153,159, 63,109,154,210, 61, 76,203,210, 63,116,187,242, 61, 76,203,237, 63,105,114, 22, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,230, 98,164, 63, 99, 26, 58, 61, 76,203,237, 63,105,114, 22,
+ 61, 76,203,234, 63, 94, 46, 79, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61, 76,203,234,
+ 63, 94, 46, 79, 61,196, 70, 23, 63, 88, 64,147, 61,230, 98,164, 63, 99, 26, 58, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62, 25,153,160, 63, 90, 56, 14, 61,230, 98,164, 63, 99, 26, 58, 61,196, 70, 23, 63, 88, 64,147,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,196, 70, 23, 63, 88, 64,147, 61, 76,203,234,
+ 63, 94, 46, 79, 61, 76,203,243, 63, 82,228, 41, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,170,138, 42, 63, 55,204,254, 62,159,214,136, 63, 65,236,183, 62,156, 0,145, 63, 54,155,102, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,156, 0,145, 63, 54,155,102, 62,165,245,204, 63, 44,160,198, 62,170,138, 42,
+ 63, 55,204,254, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,179, 51, 42, 63, 45, 28, 28,
+ 62,170,138, 42, 63, 55,204,254, 62,165,245,204, 63, 44,160,198, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62,165,245,204, 63, 44,160,198, 62,156, 0,145, 63, 54,155,102, 62,152,239,141, 63, 43, 52,211, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,141,111, 82, 63, 52, 55,146, 62,152,239,141, 63, 43, 52,211,
+ 62,156, 0,145, 63, 54,155,102, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,156, 0,145,
+ 63, 54,155,102, 62,143, 98,245, 63, 63,233, 68, 62,141,111, 82, 63, 52, 55,146, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,128, 0, 0, 63, 60, 86, 19, 62,141,111, 82, 63, 52, 55,146, 62,143, 98,245, 63, 63,233, 68,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,143, 98,245, 63, 63,233, 68, 62,156, 0,145,
+ 63, 54,155,102, 62,159,214,136, 63, 65,236,183, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,146, 27,173, 63, 75, 39,147, 62,128, 0, 0, 63, 82,228, 13, 62,128, 0, 0, 63, 71,153,228, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,128, 0, 0, 63, 71,153,228, 62,143, 98,245, 63, 63,233, 68, 62,146, 27,173,
+ 63, 75, 39,147, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,159,214,136, 63, 65,236,183,
+ 62,146, 27,173, 63, 75, 39,147, 62,143, 98,245, 63, 63,233, 68, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62,143, 98,245, 63, 63,233, 68, 62,128, 0, 0, 63, 71,153,228, 62,128, 0, 0, 63, 60, 86, 19, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,141,111, 82, 63, 52, 55,146, 62,128, 0, 0, 63, 60, 86, 19,
+ 62,128, 0, 0, 63, 49, 12, 47, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,128, 0, 0,
+ 63, 49, 12, 47, 62,140, 58,121, 63, 40,228,199, 62,141,111, 82, 63, 52, 55,146, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,152,239,141, 63, 43, 52,211, 62,141,111, 82, 63, 52, 55,146, 62,140, 58,121, 63, 40,228,199,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,140, 58,121, 63, 40,228,199, 62,128, 0, 0,
+ 63, 49, 12, 47, 62,128, 0, 0, 63, 37,200, 23, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,146, 27,173, 63, 75, 39,147, 62,159,214,136, 63, 65,236,183, 62,167,116, 47, 63, 78, 83,195, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,167,116, 47, 63, 78, 83,195, 62,151,119,239, 63, 88, 64,131, 62,146, 27,173,
+ 63, 75, 39,147, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,128, 0, 0, 63, 82,228, 13,
+ 62,146, 27,173, 63, 75, 39,147, 62,151,119,239, 63, 88, 64,131, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62,151,119,239, 63, 88, 64,131, 62,167,116, 47, 63, 78, 83,195, 62,179, 51, 49, 63, 90, 56, 14, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,190,242, 44, 63, 78, 83,205, 62,179, 51, 49, 63, 90, 56, 14,
+ 62,167,116, 47, 63, 78, 83,195, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,167,116, 47,
+ 63, 78, 83,195, 62,179, 51, 42, 63, 67, 23,108, 62,190,242, 44, 63, 78, 83,205, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,198,143,214, 63, 65,236,200, 62,190,242, 44, 63, 78, 83,205, 62,179, 51, 42, 63, 67, 23,108,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,179, 51, 42, 63, 67, 23,108, 62,167,116, 47,
+ 63, 78, 83,195, 62,159,214,136, 63, 65,236,183, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,170,138, 42, 63, 55,204,254, 62,179, 51, 42, 63, 45, 28, 28, 62,187,220, 45, 63, 55,205, 7, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,187,220, 45, 63, 55,205, 7, 62,179, 51, 42, 63, 67, 23,108, 62,170,138, 42,
+ 63, 55,204,254, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,159,214,136, 63, 65,236,183,
+ 62,170,138, 42, 63, 55,204,254, 62,179, 51, 42, 63, 67, 23,108, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62,179, 51, 42, 63, 67, 23,108, 62,187,220, 45, 63, 55,205, 7, 62,198,143,214, 63, 65,236,200, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,190,242, 44, 63, 78, 83,205, 62,198,143,214, 63, 65,236,200,
+ 62,212, 74,188, 63, 75, 39,171, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,212, 74,188,
+ 63, 75, 39,171, 62,206,238,122, 63, 88, 64,147, 62,190,242, 44, 63, 78, 83,205, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,179, 51, 49, 63, 90, 56, 14, 62,190,242, 44, 63, 78, 83,205, 62,206,238,122, 63, 88, 64,147,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,206,238,122, 63, 88, 64,147, 62,212, 74,188,
+ 63, 75, 39,171, 62,230,102,130, 63, 82,228, 41, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,230,102,130, 63, 49, 12, 82, 62,230,102,129, 63, 60, 86, 53, 62,216,247, 28, 63, 52, 55,172, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,216,247, 28, 63, 52, 55,172, 62,218, 43,243, 63, 40,228,223, 62,230,102,130,
+ 63, 49, 12, 82, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,230,102,129, 63, 37,200, 48,
+ 62,230,102,130, 63, 49, 12, 82, 62,218, 43,243, 63, 40,228,223, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62,218, 43,243, 63, 40,228,223, 62,216,247, 28, 63, 52, 55,172, 62,205,118,212, 63, 43, 52,228, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,202,101,206, 63, 54,155,120, 62,205,118,212, 63, 43, 52,228,
+ 62,216,247, 28, 63, 52, 55,172, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,216,247, 28,
+ 63, 52, 55,172, 62,215, 3,120, 63, 63,233, 95, 62,202,101,206, 63, 54,155,120, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,198,143,214, 63, 65,236,200, 62,202,101,206, 63, 54,155,120, 62,215, 3,120, 63, 63,233, 95,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,215, 3,120, 63, 63,233, 95, 62,216,247, 28,
+ 63, 52, 55,172, 62,230,102,129, 63, 60, 86, 53, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,230,102,130, 63, 71,154, 1, 62,230,102,130, 63, 82,228, 41, 62,212, 74,188, 63, 75, 39,171, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,212, 74,188, 63, 75, 39,171, 62,215, 3,120, 63, 63,233, 95, 62,230,102,130,
+ 63, 71,154, 1, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,230,102,129, 63, 60, 86, 53,
+ 62,230,102,130, 63, 71,154, 1, 62,215, 3,120, 63, 63,233, 95, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62,215, 3,120, 63, 63,233, 95, 62,212, 74,188, 63, 75, 39,171, 62,198,143,214, 63, 65,236,200, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,202,101,206, 63, 54,155,120, 62,198,143,214, 63, 65,236,200,
+ 62,187,220, 45, 63, 55,205, 7, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,187,220, 45,
+ 63, 55,205, 7, 62,192,112,142, 63, 44,160,207, 62,202,101,206, 63, 54,155,120, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,205,118,212, 63, 43, 52,228, 62,202,101,206, 63, 54,155,120, 62,192,112,142, 63, 44,160,207,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,192,112,142, 63, 44,160,207, 62,187,220, 45,
+ 63, 55,205, 7, 62,179, 51, 42, 63, 45, 28, 28, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,230,102,131, 63, 94, 46, 79, 62,230,102,131, 63,105,114, 22, 62,198,103, 87, 63, 99, 26, 58, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,198,103, 87, 63, 99, 26, 58, 62,206,238,122, 63, 88, 64,147, 62,230,102,131,
+ 63, 94, 46, 79, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,230,102,130, 63, 82,228, 41,
+ 62,230,102,131, 63, 94, 46, 79, 62,206,238,122, 63, 88, 64,147, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62,206,238,122, 63, 88, 64,147, 62,198,103, 87, 63, 99, 26, 58, 62,179, 51, 49, 63, 90, 56, 14, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,159,255, 14, 63, 99, 26, 49, 62,179, 51, 49, 63, 90, 56, 14,
+ 62,198,103, 87, 63, 99, 26, 58, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,198,103, 87,
+ 63, 99, 26, 58, 62,179, 51, 49, 63,109,154,210, 62,159,255, 14, 63, 99, 26, 49, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,128, 0, 0, 63,105,114, 8, 62,159,255, 14, 63, 99, 26, 49, 62,179, 51, 49, 63,109,154,210,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,179, 51, 49, 63,109,154,210, 62,198,103, 87,
+ 63, 99, 26, 58, 62,230,102,131, 63,105,114, 22, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,230,102,134, 63,116,187,242, 63, 59,153, 3, 63,128, 0, 0, 62,128, 0, 0, 63,116,187,232, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,128, 0, 0, 63,116,187,232, 62,179, 51, 49, 63,109,154,210, 62,230,102,134,
+ 63,116,187,242, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,230,102,131, 63,105,114, 22,
+ 62,230,102,134, 63,116,187,242, 62,179, 51, 49, 63,109,154,210, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62,179, 51, 49, 63,109,154,210, 62,128, 0, 0, 63,116,187,232, 62,128, 0, 0, 63,105,114, 8, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,159,255, 14, 63, 99, 26, 49, 62,128, 0, 0, 63,105,114, 8,
+ 62,128, 0, 0, 63, 94, 46, 58, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,128, 0, 0,
+ 63, 94, 46, 58, 62,151,119,239, 63, 88, 64,131, 62,159,255, 14, 63, 99, 26, 49, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,179, 51, 49, 63, 90, 56, 14, 62,159,255, 14, 63, 99, 26, 49, 62,151,119,239, 63, 88, 64,131,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,151,119,239, 63, 88, 64,131, 62,128, 0, 0,
+ 63, 94, 46, 58, 62,128, 0, 0, 63, 82,228, 13, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 8,120, 93, 63, 55,205, 11, 63, 3, 30,140, 63, 65,236,201, 63, 1, 51,145, 63, 54,155,121, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 1, 51,145, 63, 54,155,121, 63, 6, 46, 46, 63, 44,160,211, 63, 8,120, 93,
+ 63, 55,205, 11, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 12,204,220, 63, 45, 28, 35,
+ 63, 8,120, 93, 63, 55,205, 11, 63, 6, 46, 46, 63, 44,160,211, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 6, 46, 46, 63, 44,160,211, 63, 1, 51,145, 63, 54,155,121, 62,255, 86, 30, 63, 43, 52,230, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,243,213,222, 63, 52, 55,172, 62,255, 86, 30, 63, 43, 52,230,
+ 63, 1, 51,145, 63, 54,155,121, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 1, 51,145,
+ 63, 54,155,121, 62,245,201,128, 63, 63,233, 94, 62,243,213,222, 63, 52, 55,172, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,230,102,129, 63, 60, 86, 53, 62,243,213,222, 63, 52, 55,172, 62,245,201,128, 63, 63,233, 94,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,245,201,128, 63, 63,233, 94, 63, 1, 51,145,
+ 63, 54,155,121, 63, 3, 30,140, 63, 65,236,201, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,248,130, 59, 63, 75, 39,169, 62,230,102,130, 63, 82,228, 41, 62,230,102,130, 63, 71,154, 1, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,230,102,130, 63, 71,154, 1, 62,245,201,128, 63, 63,233, 94, 62,248,130, 59,
+ 63, 75, 39,169, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 3, 30,140, 63, 65,236,201,
+ 62,248,130, 59, 63, 75, 39,169, 62,245,201,128, 63, 63,233, 94, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62,245,201,128, 63, 63,233, 94, 62,230,102,130, 63, 71,154, 1, 62,230,102,129, 63, 60, 86, 53, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,243,213,222, 63, 52, 55,172, 62,230,102,129, 63, 60, 86, 53,
+ 62,230,102,130, 63, 49, 12, 82, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,230,102,130,
+ 63, 49, 12, 82, 62,242,161, 9, 63, 40,228,223, 62,243,213,222, 63, 52, 55,172, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,255, 86, 30, 63, 43, 52,230, 62,243,213,222, 63, 52, 55,172, 62,242,161, 9, 63, 40,228,223,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,242,161, 9, 63, 40,228,223, 62,230,102,130,
+ 63, 49, 12, 82, 62,230,102,129, 63, 37,200, 48, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,248,130, 59, 63, 75, 39,169, 63, 3, 30,140, 63, 65,236,201, 63, 6,237, 94, 63, 78, 83,207, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 6,237, 94, 63, 78, 83,207, 62,253,222,118, 63, 88, 64,148, 62,248,130, 59,
+ 63, 75, 39,169, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,230,102,130, 63, 82,228, 41,
+ 62,248,130, 59, 63, 75, 39,169, 62,253,222,118, 63, 88, 64,148, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62,253,222,118, 63, 88, 64,148, 63, 6,237, 94, 63, 78, 83,207, 63, 12,204,220, 63, 90, 56, 22, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 18,172, 88, 63, 78, 83,207, 63, 12,204,220, 63, 90, 56, 22,
+ 63, 6,237, 94, 63, 78, 83,207, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 6,237, 94,
+ 63, 78, 83,207, 63, 12,204,220, 63, 67, 23,115, 63, 18,172, 88, 63, 78, 83,207, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 22,123, 44, 63, 65,236,201, 63, 18,172, 88, 63, 78, 83,207, 63, 12,204,220, 63, 67, 23,115,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 12,204,220, 63, 67, 23,115, 63, 6,237, 94,
+ 63, 78, 83,207, 63, 3, 30,140, 63, 65,236,201, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 8,120, 93, 63, 55,205, 11, 63, 12,204,220, 63, 45, 28, 35, 63, 17, 33, 91, 63, 55,205, 9, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 17, 33, 91, 63, 55,205, 9, 63, 12,204,220, 63, 67, 23,115, 63, 8,120, 93,
+ 63, 55,205, 11, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 3, 30,140, 63, 65,236,201,
+ 63, 8,120, 93, 63, 55,205, 11, 63, 12,204,220, 63, 67, 23,115, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 12,204,220, 63, 67, 23,115, 63, 17, 33, 91, 63, 55,205, 9, 63, 22,123, 44, 63, 65,236,201, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 18,172, 88, 63, 78, 83,207, 63, 22,123, 44, 63, 65,236,201,
+ 63, 29, 88,153, 63, 75, 39,167, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 29, 88,153,
+ 63, 75, 39,167, 63, 26,170,121, 63, 88, 64,147, 63, 18,172, 88, 63, 78, 83,207, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 12,204,220, 63, 90, 56, 22, 63, 18,172, 88, 63, 78, 83,207, 63, 26,170,121, 63, 88, 64,147,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 26,170,121, 63, 88, 64,147, 63, 29, 88,153,
+ 63, 75, 39,167, 63, 38,102,118, 63, 82,228, 38, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 38,102,117, 63, 49, 12, 78, 63, 38,102,117, 63, 60, 86, 50, 63, 31,174,200, 63, 52, 55,169, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 31,174,200, 63, 52, 55,169, 63, 32, 73, 51, 63, 40,228,221, 63, 38,102,117,
+ 63, 49, 12, 78, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 38,102,117, 63, 37,200, 45,
+ 63, 38,102,117, 63, 49, 12, 78, 63, 32, 73, 51, 63, 40,228,221, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 32, 73, 51, 63, 40,228,221, 63, 31,174,200, 63, 52, 55,169, 63, 25,238,169, 63, 43, 52,229, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 24,102, 39, 63, 54,155,119, 63, 25,238,169, 63, 43, 52,229,
+ 63, 31,174,200, 63, 52, 55,169, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 31,174,200,
+ 63, 52, 55,169, 63, 30,180,246, 63, 63,233, 92, 63, 24,102, 39, 63, 54,155,119, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 22,123, 44, 63, 65,236,201, 63, 24,102, 39, 63, 54,155,119, 63, 30,180,246, 63, 63,233, 92,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 30,180,246, 63, 63,233, 92, 63, 31,174,200,
+ 63, 52, 55,169, 63, 38,102,117, 63, 60, 86, 50, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 38,102,117, 63, 71,153,255, 63, 38,102,118, 63, 82,228, 38, 63, 29, 88,153, 63, 75, 39,167, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 29, 88,153, 63, 75, 39,167, 63, 30,180,246, 63, 63,233, 92, 63, 38,102,117,
+ 63, 71,153,255, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 38,102,117, 63, 60, 86, 50,
+ 63, 38,102,117, 63, 71,153,255, 63, 30,180,246, 63, 63,233, 92, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 30,180,246, 63, 63,233, 92, 63, 29, 88,153, 63, 75, 39,167, 63, 22,123, 44, 63, 65,236,201, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 24,102, 39, 63, 54,155,119, 63, 22,123, 44, 63, 65,236,201,
+ 63, 17, 33, 91, 63, 55,205, 9, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 17, 33, 91,
+ 63, 55,205, 9, 63, 19,107,138, 63, 44,160,211, 63, 24,102, 39, 63, 54,155,119, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 25,238,169, 63, 43, 52,229, 63, 24,102, 39, 63, 54,155,119, 63, 19,107,138, 63, 44,160,211,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 19,107,138, 63, 44,160,211, 63, 17, 33, 91,
+ 63, 55,205, 9, 63, 12,204,220, 63, 45, 28, 35, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 38,102,118, 63, 94, 46, 77, 63, 38,102,118, 63,105,114, 19, 63, 22,102,235, 63, 99, 26, 59, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 22,102,235, 63, 99, 26, 59, 63, 26,170,121, 63, 88, 64,147, 63, 38,102,118,
+ 63, 94, 46, 77, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 38,102,118, 63, 82,228, 38,
+ 63, 38,102,118, 63, 94, 46, 77, 63, 26,170,121, 63, 88, 64,147, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 26,170,121, 63, 88, 64,147, 63, 22,102,235, 63, 99, 26, 59, 63, 12,204,220, 63, 90, 56, 22, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 3, 50,204, 63, 99, 26, 58, 63, 12,204,220, 63, 90, 56, 22,
+ 63, 22,102,235, 63, 99, 26, 59, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 22,102,235,
+ 63, 99, 26, 59, 63, 12,204,224, 63,109,154,212, 63, 3, 50,204, 63, 99, 26, 58, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,230,102,131, 63,105,114, 22, 63, 3, 50,204, 63, 99, 26, 58, 63, 12,204,224, 63,109,154,212,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 12,204,224, 63,109,154,212, 63, 22,102,235,
+ 63, 99, 26, 59, 63, 38,102,118, 63,105,114, 19, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 38,102,120, 63,116,187,242, 63, 59,153, 3, 63,128, 0, 0, 62,230,102,134, 63,116,187,242, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,230,102,134, 63,116,187,242, 63, 12,204,224, 63,109,154,212, 63, 38,102,120,
+ 63,116,187,242, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 38,102,118, 63,105,114, 19,
+ 63, 38,102,120, 63,116,187,242, 63, 12,204,224, 63,109,154,212, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 12,204,224, 63,109,154,212, 62,230,102,134, 63,116,187,242, 62,230,102,131, 63,105,114, 22, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 3, 50,204, 63, 99, 26, 58, 62,230,102,131, 63,105,114, 22,
+ 62,230,102,131, 63, 94, 46, 79, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,230,102,131,
+ 63, 94, 46, 79, 62,253,222,118, 63, 88, 64,148, 63, 3, 50,204, 63, 99, 26, 58, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 12,204,220, 63, 90, 56, 22, 63, 3, 50,204, 63, 99, 26, 58, 62,253,222,118, 63, 88, 64,148,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,253,222,118, 63, 88, 64,148, 62,230,102,131,
+ 63, 94, 46, 79, 62,230,102,130, 63, 82,228, 41, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 76,233,213, 63, 21, 48, 35, 63, 70,235,176, 63, 22,209,226, 63, 73,234, 80, 63, 11,111,146, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 73,234, 80, 63, 11,111,146, 63, 79,200, 1, 63, 9,152, 94, 63, 76,233,213,
+ 63, 21, 48, 35, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 82,215, 19, 63, 19, 29,252,
+ 63, 76,233,213, 63, 21, 48, 35, 63, 79,200, 1, 63, 9,152, 94, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 79,200, 1, 63, 9,152, 94, 63, 73,234, 80, 63, 11,111,146, 63, 76,204,193, 63, 0, 0, 0, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 76,233,213, 63, 21, 48, 35, 63, 82,215, 19, 63, 19, 29,252,
+ 63, 80, 41,220, 63, 31, 60,105, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 80, 41,220,
+ 63, 31, 60,105, 63, 73,219,164, 63, 33, 23,173, 63, 76,233,213, 63, 21, 48, 35, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 70,235,176, 63, 22,209,226, 63, 76,233,213, 63, 21, 48, 35, 63, 73,219,164, 63, 33, 23,173,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 73,219,164, 63, 33, 23,173, 63, 80, 41,220,
+ 63, 31, 60,105, 63, 77, 33,196, 63, 43, 52,221, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 70,158,169, 63, 44,160,200, 63, 64, 0, 0, 63, 45, 28, 24, 63, 67,171, 5, 63, 34, 17,216, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 67,171, 5, 63, 34, 17,216, 63, 73,219,164, 63, 33, 23,173, 63, 70,158,169,
+ 63, 44,160,200, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 77, 33,196, 63, 43, 52,221,
+ 63, 70,158,169, 63, 44,160,200, 63, 73,219,164, 63, 33, 23,173, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 73,219,164, 63, 33, 23,173, 63, 67,171, 5, 63, 34, 17,216, 63, 70,235,176, 63, 22,209,226, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 83,124, 75, 63, 40,228,217, 63, 77, 33,196, 63, 43, 52,221,
+ 63, 80, 41,220, 63, 31, 60,105, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 80, 41,220,
+ 63, 31, 60,105, 63, 86, 20,218, 63, 28,140,143, 63, 83,124, 75, 63, 40,228,217, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 89,153,139, 63, 37,200, 45, 63, 83,124, 75, 63, 40,228,217, 63, 86, 20,218, 63, 28,140,143,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 86, 20,218, 63, 28,140,143, 63, 80, 41,220,
+ 63, 31, 60,105, 63, 82,215, 19, 63, 19, 29,252, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 64, 0, 0, 63, 23, 32,182, 63, 70,235,176, 63, 22,209,226, 63, 67,171, 5, 63, 34, 17,216, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 67,171, 5, 63, 34, 17,216, 63, 60, 84,251, 63, 34, 17,216, 63, 64, 0, 0,
+ 63, 23, 32,182, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 57, 20, 80, 63, 22,209,226,
+ 63, 64, 0, 0, 63, 23, 32,182, 63, 60, 84,251, 63, 34, 17,216, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 60, 84,251, 63, 34, 17,216, 63, 67,171, 5, 63, 34, 17,216, 63, 64, 0, 0, 63, 45, 28, 24, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 64, 0, 0, 63, 23, 32,182, 63, 57, 20, 80, 63, 22,209,226,
+ 63, 60,156,169, 63, 11,116, 96, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 60,156,169,
+ 63, 11,116, 96, 63, 67, 99, 87, 63, 11,116, 96, 63, 64, 0, 0, 63, 23, 32,182, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 70,235,176, 63, 22,209,226, 63, 64, 0, 0, 63, 23, 32,182, 63, 67, 99, 87, 63, 11,116, 96,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 67, 99, 87, 63, 11,116, 96, 63, 60,156,169,
+ 63, 11,116, 96, 63, 64, 0, 0, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 70,102, 96, 63, 0, 1,244, 63, 76,204,193, 63, 0, 0, 0, 63, 73,234, 80, 63, 11,111,146, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 73,234, 80, 63, 11,111,146, 63, 67, 99, 87, 63, 11,116, 96, 63, 70,102, 96,
+ 63, 0, 1,244, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 64, 0, 0, 63, 0, 0, 0,
+ 63, 70,102, 96, 63, 0, 1,244, 63, 67, 99, 87, 63, 11,116, 96, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 67, 99, 87, 63, 11,116, 96, 63, 73,234, 80, 63, 11,111,146, 63, 70,235,176, 63, 22,209,226, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 57,153,160, 63, 0, 1,244, 63, 64, 0, 0, 63, 0, 0, 0,
+ 63, 60,156,169, 63, 11,116, 96, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 60,156,169,
+ 63, 11,116, 96, 63, 54, 21,176, 63, 11,111,146, 63, 57,153,160, 63, 0, 1,244, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 51, 51, 63, 63, 0, 0, 0, 63, 57,153,160, 63, 0, 1,244, 63, 54, 21,176, 63, 11,111,146,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 54, 21,176, 63, 11,111,146, 63, 60,156,169,
+ 63, 11,116, 96, 63, 57, 20, 80, 63, 22,209,226, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 64, 0, 0, 62,217, 58, 93, 63, 57, 61,144, 62,217,196, 19, 63, 60,123, 85, 62,198,230,253, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 60,123, 85, 62,198,230,253, 63, 67,132,171, 62,198,230,253, 63, 64, 0, 0,
+ 62,217, 58, 93, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 70,194,112, 62,217,196, 19,
+ 63, 64, 0, 0, 62,217, 58, 93, 63, 67,132,171, 62,198,230,253, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 67,132,171, 62,198,230,253, 63, 60,123, 85, 62,198,230,253, 63, 64, 0, 0, 62,180,111,211, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 64, 0, 0, 62,217, 58, 93, 63, 70,194,112, 62,217,196, 19,
+ 63, 67, 84,125, 62,236,211, 42, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 67, 84,125,
+ 62,236,211, 42, 63, 60,171,131, 62,236,211, 42, 63, 64, 0, 0, 62,217, 58, 93, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 57, 61,144, 62,217,196, 19, 63, 64, 0, 0, 62,217, 58, 93, 63, 60,171,131, 62,236,211, 42,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 60,171,131, 62,236,211, 42, 63, 67, 84,125,
+ 62,236,211, 42, 63, 64, 0, 0, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 57,153,160, 63, 0, 1,244, 63, 51, 51, 63, 63, 0, 0, 0, 63, 54, 46,128, 62,236,207, 75, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 54, 46,128, 62,236,207, 75, 63, 60,171,131, 62,236,211, 42, 63, 57,153,160,
+ 63, 0, 1,244, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 64, 0, 0, 63, 0, 0, 0,
+ 63, 57,153,160, 63, 0, 1,244, 63, 60,171,131, 62,236,211, 42, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 60,171,131, 62,236,211, 42, 63, 54, 46,128, 62,236,207, 75, 63, 57, 61,144, 62,217,196, 19, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 70,102, 96, 63, 0, 1,244, 63, 64, 0, 0, 63, 0, 0, 0,
+ 63, 67, 84,125, 62,236,211, 42, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 67, 84,125,
+ 62,236,211, 42, 63, 73,209,128, 62,236,207, 75, 63, 70,102, 96, 63, 0, 1,244, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 76,204,193, 63, 0, 0, 0, 63, 70,102, 96, 63, 0, 1,244, 63, 73,209,128, 62,236,207, 75,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 73,209,128, 62,236,207, 75, 63, 67, 84,125,
+ 62,236,211, 42, 63, 70,194,112, 62,217,196, 19, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 51, 22, 43, 63, 21, 48, 35, 63, 45, 40,237, 63, 19, 29,252, 63, 48, 55,255, 63, 9,152, 94, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 48, 55,255, 63, 9,152, 94, 63, 54, 21,176, 63, 11,111,146, 63, 51, 22, 43,
+ 63, 21, 48, 35, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 57, 20, 80, 63, 22,209,226,
+ 63, 51, 22, 43, 63, 21, 48, 35, 63, 54, 21,176, 63, 11,111,146, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 54, 21,176, 63, 11,111,146, 63, 48, 55,255, 63, 9,152, 94, 63, 51, 51, 63, 63, 0, 0, 0, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 51, 22, 43, 63, 21, 48, 35, 63, 57, 20, 80, 63, 22,209,226,
+ 63, 54, 36, 91, 63, 33, 23,173, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 54, 36, 91,
+ 63, 33, 23,173, 63, 47,214, 36, 63, 31, 60,105, 63, 51, 22, 43, 63, 21, 48, 35, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 45, 40,237, 63, 19, 29,252, 63, 51, 22, 43, 63, 21, 48, 35, 63, 47,214, 36, 63, 31, 60,105,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 47,214, 36, 63, 31, 60,105, 63, 54, 36, 91,
+ 63, 33, 23,173, 63, 50,222, 60, 63, 43, 52,221, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 44,131,181, 63, 40,228,216, 63, 38,102,117, 63, 37,200, 45, 63, 41,235, 38, 63, 28,140,141, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 41,235, 38, 63, 28,140,141, 63, 47,214, 36, 63, 31, 60,105, 63, 44,131,181,
+ 63, 40,228,216, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 50,222, 60, 63, 43, 52,221,
+ 63, 44,131,181, 63, 40,228,216, 63, 47,214, 36, 63, 31, 60,105, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 47,214, 36, 63, 31, 60,105, 63, 41,235, 38, 63, 28,140,141, 63, 45, 40,237, 63, 19, 29,252, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 57, 97, 87, 63, 44,160,200, 63, 50,222, 60, 63, 43, 52,221,
+ 63, 54, 36, 91, 63, 33, 23,173, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 54, 36, 91,
+ 63, 33, 23,173, 63, 60, 84,251, 63, 34, 17,216, 63, 57, 97, 87, 63, 44,160,200, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 64, 0, 0, 63, 45, 28, 24, 63, 57, 97, 87, 63, 44,160,200, 63, 60, 84,251, 63, 34, 17,216,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 60, 84,251, 63, 34, 17,216, 63, 54, 36, 91,
+ 63, 33, 23,173, 63, 57, 20, 80, 63, 22,209,226, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63,128, 14,134, 63, 21, 48, 39, 63,122, 30,227, 63, 22,209,233, 63,125, 29,138, 63, 11,111,150, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,125, 29,138, 63, 11,111,150, 63,129,125,159, 63, 9,152, 94, 63,128, 14,134,
+ 63, 21, 48, 39, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 60,193, 73,174, 63, 19, 29,253,
+ 57,232, 92,209, 63, 21, 48, 39, 60, 62,207,114, 63, 9,152, 94, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63,129,125,159, 63, 9,152, 94, 63,125, 29,138, 63, 11,111,150, 63,128, 0, 0, 63, 0, 0, 0, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 57,232, 92,209, 63, 21, 48, 39, 60,193, 73,174, 63, 19, 29,253,
+ 60, 87, 67,214, 63, 31, 60,110, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,129,174,136,
+ 63, 31, 60,110, 63,125, 14,213, 63, 33, 23,180, 63,128, 14,134, 63, 21, 48, 39, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63,122, 30,227, 63, 22,209,233, 63,128, 14,134, 63, 21, 48, 39, 63,125, 14,213, 63, 33, 23,180,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,125, 14,213, 63, 33, 23,180, 63,129,174,136,
+ 63, 31, 60,110, 63,128, 42,121, 63, 43, 52,230, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63,121,209,210, 63, 44,160,212, 63,115, 51, 36, 63, 45, 28, 36, 63,118,222, 49, 63, 34, 17,226, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,118,222, 49, 63, 34, 17,226, 63,125, 14,213, 63, 33, 23,180, 63,121,209,210,
+ 63, 44,160,212, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,128, 42,121, 63, 43, 52,230,
+ 63,121,209,210, 63, 44,160,212, 63,125, 14,213, 63, 33, 23,180, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63,125, 14,213, 63, 33, 23,180, 63,118,222, 49, 63, 34, 17,226, 63,122, 30,227, 63, 22,209,233, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 60,213,239,111, 63, 40,228,223, 58,169,226,120, 63, 43, 52,230,
+ 60, 87, 67,214, 63, 31, 60,110, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 60, 87, 67,214,
+ 63, 31, 60,110, 61, 20,129, 13, 63, 28,140,143, 60,213,239,111, 63, 40,228,223, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 61, 76,203,246, 63, 37,200, 48, 60,213,239,111, 63, 40,228,223, 61, 20,129, 13, 63, 28,140,143,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61, 20,129, 13, 63, 28,140,143, 60, 87, 67,214,
+ 63, 31, 60,110, 60,193, 73,174, 63, 19, 29,253, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63,115, 51, 44, 63, 23, 32,188, 63,122, 30,227, 63, 22,209,233, 63,118,222, 49, 63, 34, 17,226, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,118,222, 49, 63, 34, 17,226, 63,111,136, 31, 63, 34, 17,225, 63,115, 51, 44,
+ 63, 23, 32,188, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,108, 71,116, 63, 22,209,232,
+ 63,115, 51, 44, 63, 23, 32,188, 63,111,136, 31, 63, 34, 17,225, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63,111,136, 31, 63, 34, 17,225, 63,118,222, 49, 63, 34, 17,226, 63,115, 51, 36, 63, 45, 28, 36, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,115, 51, 44, 63, 23, 32,188, 63,108, 71,116, 63, 22,209,232,
+ 63,111,207,213, 63, 11,116,100, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,111,207,213,
+ 63, 11,116,100, 63,118,150,138, 63, 11,116,101, 63,115, 51, 44, 63, 23, 32,188, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63,122, 30,227, 63, 22,209,233, 63,115, 51, 44, 63, 23, 32,188, 63,118,150,138, 63, 11,116,101,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,118,150,138, 63, 11,116,101, 63,111,207,213,
+ 63, 11,116,100, 63,115, 51, 51, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63,121,153,154, 63, 0, 1,244, 63,128, 0, 0, 63, 0, 0, 0, 63,125, 29,138, 63, 11,111,150, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,125, 29,138, 63, 11,111,150, 63,118,150,138, 63, 11,116,101, 63,121,153,154,
+ 63, 0, 1,244, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,115, 51, 51, 63, 0, 0, 0,
+ 63,121,153,154, 63, 0, 1,244, 63,118,150,138, 63, 11,116,101, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63,118,150,138, 63, 11,116,101, 63,125, 29,138, 63, 11,111,150, 63,122, 30,227, 63, 22,209,233, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,108,204,205, 63, 0, 1,244, 63,115, 51, 51, 63, 0, 0, 0,
+ 63,111,207,213, 63, 11,116,100, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,111,207,213,
+ 63, 11,116,100, 63,105, 72,213, 63, 11,111,149, 63,108,204,205, 63, 0, 1,244, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63,102,102,101, 63, 0, 0, 0, 63,108,204,205, 63, 0, 1,244, 63,105, 72,213, 63, 11,111,149,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,105, 72,213, 63, 11,111,149, 63,111,207,213,
+ 63, 11,116,100, 63,108, 71,116, 63, 22,209,232, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63,115, 51, 58, 62,217, 58, 73, 63,108,112,192, 62,217,196, 4, 63,111,174,139, 62,198,230,223, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,111,174,139, 62,198,230,223, 63,118,183,239, 62,198,230,227, 63,115, 51, 58,
+ 62,217, 58, 73, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,121,245,179, 62,217,196, 6,
+ 63,115, 51, 58, 62,217, 58, 73, 63,118,183,239, 62,198,230,227, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63,118,183,239, 62,198,230,227, 63,111,174,139, 62,198,230,223, 63,115, 51, 65, 62,180,111,160, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,115, 51, 58, 62,217, 58, 73, 63,121,245,179, 62,217,196, 6,
+ 63,118,135,185, 62,236,211, 30, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,118,135,185,
+ 62,236,211, 30, 63,111,222,180, 62,236,211, 30, 63,115, 51, 58, 62,217, 58, 73, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63,108,112,192, 62,217,196, 4, 63,115, 51, 58, 62,217, 58, 73, 63,111,222,180, 62,236,211, 30,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,111,222,180, 62,236,211, 30, 63,118,135,185,
+ 62,236,211, 30, 63,115, 51, 51, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63,108,204,205, 63, 0, 1,244, 63,102,102,101, 63, 0, 0, 0, 63,105, 97,170, 62,236,207, 65, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,105, 97,170, 62,236,207, 65, 63,111,222,180, 62,236,211, 30, 63,108,204,205,
+ 63, 0, 1,244, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,115, 51, 51, 63, 0, 0, 0,
+ 63,108,204,205, 63, 0, 1,244, 63,111,222,180, 62,236,211, 30, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63,111,222,180, 62,236,211, 30, 63,105, 97,170, 62,236,207, 65, 63,108,112,192, 62,217,196, 4, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,121,153,154, 63, 0, 1,244, 63,115, 51, 51, 63, 0, 0, 0,
+ 63,118,135,185, 62,236,211, 30, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,118,135,185,
+ 62,236,211, 30, 63,125, 4,194, 62,236,207, 67, 63,121,153,154, 63, 0, 1,244, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63,128, 0, 0, 63, 0, 0, 0, 63,121,153,154, 63, 0, 1,244, 63,125, 4,194, 62,236,207, 67,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,125, 4,194, 62,236,207, 67, 63,118,135,185,
+ 62,236,211, 30, 63,121,245,179, 62,217,196, 6, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63,102, 73, 76, 63, 21, 48, 38, 63, 96, 92, 11, 63, 19, 29,253, 63, 99,107, 33, 63, 9,152, 94, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 99,107, 33, 63, 9,152, 94, 63,105, 72,213, 63, 11,111,149, 63,102, 73, 76,
+ 63, 21, 48, 38, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,108, 71,116, 63, 22,209,232,
+ 63,102, 73, 76, 63, 21, 48, 38, 63,105, 72,213, 63, 11,111,149, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63,105, 72,213, 63, 11,111,149, 63, 99,107, 33, 63, 9,152, 94, 63,102,102,101, 63, 0, 0, 0, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,102, 73, 76, 63, 21, 48, 38, 63,108, 71,116, 63, 22,209,232,
+ 63,105, 87,124, 63, 33, 23,180, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,105, 87,124,
+ 63, 33, 23,180, 63, 99, 9, 65, 63, 31, 60,109, 63,102, 73, 76, 63, 21, 48, 38, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 96, 92, 11, 63, 19, 29,253, 63,102, 73, 76, 63, 21, 48, 38, 63, 99, 9, 65, 63, 31, 60,109,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 99, 9, 65, 63, 31, 60,109, 63,105, 87,124,
+ 63, 33, 23,180, 63,102, 17, 87, 63, 43, 52,229, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 95,182,205, 63, 40,228,222, 63, 89,153,139, 63, 37,200, 45, 63, 93, 30, 63, 63, 28,140,143, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 93, 30, 63, 63, 28,140,143, 63, 99, 9, 65, 63, 31, 60,109, 63, 95,182,205,
+ 63, 40,228,222, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,102, 17, 87, 63, 43, 52,229,
+ 63, 95,182,205, 63, 40,228,222, 63, 99, 9, 65, 63, 31, 60,109, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 99, 9, 65, 63, 31, 60,109, 63, 93, 30, 63, 63, 28,140,143, 63, 96, 92, 11, 63, 19, 29,253, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,108,148,118, 63, 44,160,211, 63,102, 17, 87, 63, 43, 52,229,
+ 63,105, 87,124, 63, 33, 23,180, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,105, 87,124,
+ 63, 33, 23,180, 63,111,136, 31, 63, 34, 17,225, 63,108,148,118, 63, 44,160,211, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63,115, 51, 36, 63, 45, 28, 36, 63,108,148,118, 63, 44,160,211, 63,111,136, 31, 63, 34, 17,225,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,111,136, 31, 63, 34, 17,225, 63,105, 87,124,
+ 63, 33, 23,180, 63,108, 71,116, 63, 22,209,232, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62, 77, 65, 65, 63, 21, 48, 32, 62, 53, 72,152, 63, 22,209,229, 62, 65, 67, 47, 63, 11,111,147, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 65, 67, 47, 63, 11,111,147, 62, 88,185,255, 63, 9,152, 90, 62, 77, 65, 65,
+ 63, 21, 48, 32, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,100,246, 64, 63, 19, 29,246,
+ 62, 77, 65, 65, 63, 21, 48, 32, 62, 88,185,255, 63, 9,152, 90, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62, 88,185,255, 63, 9,152, 90, 62, 65, 67, 47, 63, 11,111,147, 62, 76,204,254, 63, 0, 0, 0, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 77, 65, 65, 63, 21, 48, 32, 62,100,246, 64, 63, 19, 29,246,
+ 62, 90, 65, 89, 63, 31, 60, 94, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 90, 65, 89,
+ 63, 31, 60, 94, 62, 65, 8,107, 63, 33, 23,170, 62, 77, 65, 65, 63, 21, 48, 32, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62, 53, 72,152, 63, 22,209,229, 62, 77, 65, 65, 63, 21, 48, 32, 62, 65, 8,107, 63, 33, 23,170,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 65, 8,107, 63, 33, 23,170, 62, 90, 65, 89,
+ 63, 31, 60, 94, 62, 78, 32,230, 63, 43, 52,211, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62, 52, 20,105, 63, 44,160,198, 62, 25,153,173, 63, 45, 28, 27, 62, 40, 69,216, 63, 34, 17,220, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 40, 69,216, 63, 34, 17,220, 62, 65, 8,107, 63, 33, 23,170, 62, 52, 20,105,
+ 63, 44,160,198, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 78, 32,230, 63, 43, 52,211,
+ 62, 52, 20,105, 63, 44,160,198, 62, 65, 8,107, 63, 33, 23,170, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62, 65, 8,107, 63, 33, 23,170, 62, 40, 69,216, 63, 34, 17,220, 62, 53, 72,152, 63, 22,209,229, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,103,139, 14, 63, 40,228,199, 62, 78, 32,230, 63, 43, 52,211,
+ 62, 90, 65, 89, 63, 31, 60, 94, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 90, 65, 89,
+ 63, 31, 60, 94, 62,113,237, 83, 63, 28,140,130, 62,103,139, 14, 63, 40,228,199, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,128, 0, 0, 63, 37,200, 23, 62,103,139, 14, 63, 40,228,199, 62,113,237, 83, 63, 28,140,130,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,113,237, 83, 63, 28,140,130, 62, 90, 65, 89,
+ 63, 31, 60, 94, 62,100,246, 64, 63, 19, 29,246, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62, 25,153,180, 63, 23, 32,185, 62, 53, 72,152, 63, 22,209,229, 62, 40, 69,216, 63, 34, 17,220, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 40, 69,216, 63, 34, 17,220, 62, 10,237,133, 63, 34, 17,219, 62, 25,153,180,
+ 63, 23, 32,185, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,251,213,147, 63, 22,209,228,
+ 62, 25,153,180, 63, 23, 32,185, 62, 10,237,133, 63, 34, 17,219, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62, 10,237,133, 63, 34, 17,219, 62, 40, 69,216, 63, 34, 17,220, 62, 25,153,173, 63, 45, 28, 27, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 25,153,180, 63, 23, 32,185, 61,251,213,147, 63, 22,209,228,
+ 62, 12, 12, 67, 63, 11,116, 98, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 12, 12, 67,
+ 63, 11,116, 98, 62, 39, 39, 34, 63, 11,116, 98, 62, 25,153,180, 63, 23, 32,185, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62, 53, 72,152, 63, 22,209,229, 62, 25,153,180, 63, 23, 32,185, 62, 39, 39, 34, 63, 11,116, 98,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 39, 39, 34, 63, 11,116, 98, 62, 12, 12, 67,
+ 63, 11,116, 98, 62, 25,153,181, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62, 51, 51, 92, 63, 0, 1,244, 62, 76,204,254, 63, 0, 0, 0, 62, 65, 67, 47, 63, 11,111,147, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 65, 67, 47, 63, 11,111,147, 62, 39, 39, 34, 63, 11,116, 98, 62, 51, 51, 92,
+ 63, 0, 1,244, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 25,153,181, 63, 0, 0, 0,
+ 62, 51, 51, 92, 63, 0, 1,244, 62, 39, 39, 34, 63, 11,116, 98, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62, 39, 39, 34, 63, 11,116, 98, 62, 65, 67, 47, 63, 11,111,147, 62, 53, 72,152, 63, 22,209,229, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 0, 0, 8, 63, 0, 1,244, 62, 25,153,181, 63, 0, 0, 0,
+ 62, 12, 12, 67, 63, 11,116, 98, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 12, 12, 67,
+ 63, 11,116, 98, 61,227,224,109, 63, 11,111,147, 62, 0, 0, 8, 63, 0, 1,244, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 61,204,204,215, 63, 0, 0, 0, 62, 0, 0, 8, 63, 0, 1,244, 61,227,224,109, 63, 11,111,147,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,227,224,109, 63, 11,111,147, 62, 12, 12, 67,
+ 63, 11,116, 98, 61,251,213,147, 63, 22,209,228, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62, 25,153,196, 62,217, 58, 73, 61,253, 31,171, 62,217,196, 6, 62, 11,135, 1, 62,198,230,228, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 11,135, 1, 62,198,230,228, 62, 39,172,153, 62,198,230,230, 62, 25,153,196,
+ 62,217, 58, 73, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 52,163,179, 62,217,196, 7,
+ 62, 25,153,196, 62,217, 58, 73, 62, 39,172,153, 62,198,230,230, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62, 39,172,153, 62,198,230,230, 62, 11,135, 1, 62,198,230,228, 62, 25,153,214, 62,180,111,165, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 25,153,196, 62,217, 58, 73, 62, 52,163,179, 62,217,196, 7,
+ 62, 38,235,202, 62,236,211, 33, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 38,235,202,
+ 62,236,211, 33, 62, 12, 71,173, 62,236,211, 31, 62, 25,153,196, 62,217, 58, 73, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 61,253, 31,171, 62,217,196, 6, 62, 25,153,196, 62,217, 58, 73, 62, 12, 71,173, 62,236,211, 31,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 12, 71,173, 62,236,211, 31, 62, 38,235,202,
+ 62,236,211, 33, 62, 25,153,181, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62, 0, 0, 8, 63, 0, 1,244, 61,204,204,215, 63, 0, 0, 0, 61,228,166,251, 62,236,207, 67, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,228,166,251, 62,236,207, 67, 62, 12, 71,173, 62,236,211, 31, 62, 0, 0, 8,
+ 63, 0, 1,244, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 25,153,181, 63, 0, 0, 0,
+ 62, 0, 0, 8, 63, 0, 1,244, 62, 12, 71,173, 62,236,211, 31, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62, 12, 71,173, 62,236,211, 31, 61,228,166,251, 62,236,207, 67, 61,253, 31,171, 62,217,196, 6, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 51, 51, 92, 63, 0, 1,244, 62, 25,153,181, 63, 0, 0, 0,
+ 62, 38,235,202, 62,236,211, 33, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 38,235,202,
+ 62,236,211, 33, 62, 64,223,251, 62,236,207, 67, 62, 51, 51, 92, 63, 0, 1,244, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62, 76,204,254, 63, 0, 0, 0, 62, 51, 51, 92, 63, 0, 1,244, 62, 64,223,251, 62,236,207, 67,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 64,223,251, 62,236,207, 67, 62, 38,235,202,
+ 62,236,211, 33, 62, 52,163,179, 62,217,196, 7, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 61,203,228, 42, 63, 21, 48, 37, 61,156,122, 1, 63, 19, 29,254, 61,180,242,172, 63, 9,152, 96, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,180,242,172, 63, 9,152, 96, 61,227,224,109, 63, 11,111,147, 61,203,228, 42,
+ 63, 21, 48, 37, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,251,213,147, 63, 22,209,228,
+ 61,203,228, 42, 63, 21, 48, 37, 61,227,224,109, 63, 11,111,147, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 61,227,224,109, 63, 11,111,147, 61,180,242,172, 63, 9,152, 96, 61,204,204,215, 63, 0, 0, 0, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,203,228, 42, 63, 21, 48, 37, 61,251,213,147, 63, 22,209,228,
+ 61,228, 85,208, 63, 33, 23,179, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,228, 85,208,
+ 63, 33, 23,179, 61,177,227,212, 63, 31, 60,110, 61,203,228, 42, 63, 21, 48, 37, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 61,156,122, 1, 63, 19, 29,254, 61,203,228, 42, 63, 21, 48, 37, 61,177,227,212, 63, 31, 60,110,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,177,227,212, 63, 31, 60,110, 61,228, 85,208,
+ 63, 33, 23,179, 61,202, 36,175, 63, 43, 52,228, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 61,151, 80, 53, 63, 40,228,223, 61, 76,203,246, 63, 37,200, 48, 61,130,139,166, 63, 28,140,145, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,130,139,166, 63, 28,140,145, 61,177,227,212, 63, 31, 60,110, 61,151, 80, 53,
+ 63, 40,228,223, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,202, 36,175, 63, 43, 52,228,
+ 61,151, 80, 53, 63, 40,228,223, 61,177,227,212, 63, 31, 60,110, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 61,177,227,212, 63, 31, 60,110, 61,130,139,166, 63, 28,140,145, 61,156,122, 1, 63, 19, 29,254, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,254, 61,201, 63, 44,160,207, 61,202, 36,175, 63, 43, 52,228,
+ 61,228, 85,208, 63, 33, 23,179, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,228, 85,208,
+ 63, 33, 23,179, 62, 10,237,133, 63, 34, 17,219, 61,254, 61,201, 63, 44,160,207, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62, 25,153,173, 63, 45, 28, 27, 61,254, 61,201, 63, 44,160,207, 62, 10,237,133, 63, 34, 17,219,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 10,237,133, 63, 34, 17,219, 61,228, 85,208,
+ 63, 33, 23,179, 61,251,213,147, 63, 22,209,228, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,205, 6,245, 63, 21, 48, 37, 62,193, 10,155, 63, 22,209,229, 62,199, 7,229, 63, 11,111,147, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,199, 7,229, 63, 11,111,147, 62,210,195, 85, 63, 9,152, 96, 62,205, 6,245,
+ 63, 21, 48, 37, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,216,225,128, 63, 19, 29,254,
+ 62,205, 6,245, 63, 21, 48, 37, 62,210,195, 85, 63, 9,152, 96, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62,210,195, 85, 63, 9,152, 96, 62,199, 7,229, 63, 11,111,147, 62,204,204,202, 63, 0, 0, 0, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,205, 6,245, 63, 21, 48, 37, 62,216,225,128, 63, 19, 29,254,
+ 62,211,135, 11, 63, 31, 60,110, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,211,135, 11,
+ 63, 31, 60,110, 62,198,234,140, 63, 33, 23,179, 62,205, 6,245, 63, 21, 48, 37, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,193, 10,155, 63, 22,209,229, 62,205, 6,245, 63, 21, 48, 37, 62,198,234,140, 63, 33, 23,179,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,198,234,140, 63, 33, 23,179, 62,211,135, 11,
+ 63, 31, 60,110, 62,205,118,212, 63, 43, 52,228, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,192,112,142, 63, 44,160,207, 62,179, 51, 42, 63, 45, 28, 28, 62,186,137, 61, 63, 34, 17,219, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,186,137, 61, 63, 34, 17,219, 62,198,234,140, 63, 33, 23,179, 62,192,112,142,
+ 63, 44,160,207, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,205,118,212, 63, 43, 52,228,
+ 62,192,112,142, 63, 44,160,207, 62,198,234,140, 63, 33, 23,179, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62,198,234,140, 63, 33, 23,179, 62,186,137, 61, 63, 34, 17,219, 62,193, 10,155, 63, 22,209,229, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,218, 43,243, 63, 40,228,223, 62,205,118,212, 63, 43, 52,228,
+ 62,211,135, 11, 63, 31, 60,110, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,211,135, 11,
+ 63, 31, 60,110, 62,223, 93, 22, 63, 28,140,145, 62,218, 43,243, 63, 40,228,223, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,230,102,129, 63, 37,200, 48, 62,218, 43,243, 63, 40,228,223, 62,223, 93, 22, 63, 28,140,145,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,223, 93, 22, 63, 28,140,145, 62,211,135, 11,
+ 63, 31, 60,110, 62,216,225,128, 63, 19, 29,254, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,179, 51, 38, 63, 23, 32,185, 62,193, 10,155, 63, 22,209,229, 62,186,137, 61, 63, 34, 17,219, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,186,137, 61, 63, 34, 17,219, 62,171,221, 20, 63, 34, 17,219, 62,179, 51, 38,
+ 63, 23, 32,185, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,165, 91,180, 63, 22,209,229,
+ 62,179, 51, 38, 63, 23, 32,185, 62,171,221, 20, 63, 34, 17,219, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62,171,221, 20, 63, 34, 17,219, 62,186,137, 61, 63, 34, 17,219, 62,179, 51, 42, 63, 45, 28, 28, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,179, 51, 38, 63, 23, 32,185, 62,165, 91,180, 63, 22,209,229,
+ 62,172,108,111, 63, 11,116, 98, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,172,108,111,
+ 63, 11,116, 98, 62,185,249,222, 63, 11,116, 98, 62,179, 51, 38, 63, 23, 32,185, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,193, 10,155, 63, 22,209,229, 62,179, 51, 38, 63, 23, 32,185, 62,185,249,222, 63, 11,116, 98,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,185,249,222, 63, 11,116, 98, 62,172,108,111,
+ 63, 11,116, 98, 62,179, 51, 38, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,191,255,252, 63, 0, 1,244, 62,204,204,202, 63, 0, 0, 0, 62,199, 7,229, 63, 11,111,147, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,199, 7,229, 63, 11,111,147, 62,185,249,222, 63, 11,116, 98, 62,191,255,252,
+ 63, 0, 1,244, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,179, 51, 38, 63, 0, 0, 0,
+ 62,191,255,252, 63, 0, 1,244, 62,185,249,222, 63, 11,116, 98, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62,185,249,222, 63, 11,116, 98, 62,199, 7,229, 63, 11,111,147, 62,193, 10,155, 63, 22,209,229, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,166,102, 82, 63, 0, 1,244, 62,179, 51, 38, 63, 0, 0, 0,
+ 62,172,108,111, 63, 11,116, 98, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,172,108,111,
+ 63, 11,116, 98, 62,159, 94,104, 63, 11,111,147, 62,166,102, 82, 63, 0, 1,244, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,153,153,129, 63, 0, 0, 0, 62,166,102, 82, 63, 0, 1,244, 62,159, 94,104, 63, 11,111,147,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,159, 94,104, 63, 11,111,147, 62,172,108,111,
+ 63, 11,116, 98, 62,165, 91,180, 63, 22,209,229, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,179, 51, 30, 62,217, 58, 73, 62,165,174, 39, 62,217,196, 7, 62,172, 41,180, 62,198,230,227, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,172, 41,180, 62,198,230,227, 62,186, 60,127, 62,198,230,225, 62,179, 51, 30,
+ 62,217, 58, 73, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,192,184, 21, 62,217,196, 6,
+ 62,179, 51, 30, 62,217, 58, 73, 62,186, 60,127, 62,198,230,225, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62,186, 60,127, 62,198,230,225, 62,172, 41,180, 62,198,230,227, 62,179, 51, 21, 62,180,111,165, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,179, 51, 30, 62,217, 58, 73, 62,192,184, 21, 62,217,196, 6,
+ 62,185,220, 42, 62,236,211, 31, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,185,220, 42,
+ 62,236,211, 31, 62,172,138, 27, 62,236,211, 33, 62,179, 51, 30, 62,217, 58, 73, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,165,174, 39, 62,217,196, 7, 62,179, 51, 30, 62,217, 58, 73, 62,172,138, 27, 62,236,211, 33,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,172,138, 27, 62,236,211, 33, 62,185,220, 42,
+ 62,236,211, 31, 62,179, 51, 38, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,166,102, 82, 63, 0, 1,244, 62,153,153,129, 63, 0, 0, 0, 62,159,144, 3, 62,236,207, 67, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,159,144, 3, 62,236,207, 67, 62,172,138, 27, 62,236,211, 33, 62,166,102, 82,
+ 63, 0, 1,244, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,179, 51, 38, 63, 0, 0, 0,
+ 62,166,102, 82, 63, 0, 1,244, 62,172,138, 27, 62,236,211, 33, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62,172,138, 27, 62,236,211, 33, 62,159,144, 3, 62,236,207, 67, 62,165,174, 39, 62,217,196, 7, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,191,255,252, 63, 0, 1,244, 62,179, 51, 38, 63, 0, 0, 0,
+ 62,185,220, 42, 62,236,211, 31, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,185,220, 42,
+ 62,236,211, 31, 62,198,214, 65, 62,236,207, 67, 62,191,255,252, 63, 0, 1,244, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,204,204,202, 63, 0, 0, 0, 62,191,255,252, 63, 0, 1,244, 62,198,214, 65, 62,236,207, 67,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,198,214, 65, 62,236,207, 67, 62,185,220, 42,
+ 62,236,211, 31, 62,192,184, 21, 62,217,196, 6, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,153, 95, 95, 63, 21, 48, 32, 62,141,132,224, 63, 19, 29,246, 62,147,163, 1, 63, 9,152, 91, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,147,163, 1, 63, 9,152, 91, 62,159, 94,104, 63, 11,111,147, 62,153, 95, 95,
+ 63, 21, 48, 32, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,165, 91,180, 63, 22,209,229,
+ 62,153, 95, 95, 63, 21, 48, 32, 62,159, 94,104, 63, 11,111,147, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62,159, 94,104, 63, 11,111,147, 62,147,163, 1, 63, 9,152, 91, 62,153,153,129, 63, 0, 0, 0, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,153, 95, 95, 63, 21, 48, 32, 62,165, 91,180, 63, 22,209,229,
+ 62,159,123,203, 63, 33, 23,170, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,159,123,203,
+ 63, 33, 23,170, 62,146,223, 84, 63, 31, 60, 94, 62,153, 95, 95, 63, 21, 48, 32, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,141,132,224, 63, 19, 29,246, 62,153, 95, 95, 63, 21, 48, 32, 62,146,223, 84, 63, 31, 60, 94,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,146,223, 84, 63, 31, 60, 94, 62,159,123,203,
+ 63, 33, 23,170, 62,152,239,141, 63, 43, 52,211, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,140, 58,121, 63, 40,228,199, 62,128, 0, 0, 63, 37,200, 23, 62,135, 9, 86, 63, 28,140,130, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,135, 9, 86, 63, 28,140,130, 62,146,223, 84, 63, 31, 60, 94, 62,140, 58,121,
+ 63, 40,228,199, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,152,239,141, 63, 43, 52,211,
+ 62,140, 58,121, 63, 40,228,199, 62,146,223, 84, 63, 31, 60, 94, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62,146,223, 84, 63, 31, 60, 94, 62,135, 9, 86, 63, 28,140,130, 62,141,132,224, 63, 19, 29,246, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,165,245,204, 63, 44,160,198, 62,152,239,141, 63, 43, 52,211,
+ 62,159,123,203, 63, 33, 23,170, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,159,123,203,
+ 63, 33, 23,170, 62,171,221, 20, 63, 34, 17,219, 62,165,245,204, 63, 44,160,198, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,179, 51, 42, 63, 45, 28, 28, 62,165,245,204, 63, 44,160,198, 62,171,221, 20, 63, 34, 17,219,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,171,221, 20, 63, 34, 17,219, 62,159,123,203,
+ 63, 33, 23,170, 62,165, 91,180, 63, 22,209,229, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 25,182,180, 63, 21, 48, 38, 63, 19,184,140, 63, 22,209,232, 63, 22,183, 43, 63, 11,111,149, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 22,183, 43, 63, 11,111,149, 63, 28,148,223, 63, 9,152, 94, 63, 25,182,180,
+ 63, 21, 48, 38, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 31,163,245, 63, 19, 29,253,
+ 63, 25,182,180, 63, 21, 48, 38, 63, 28,148,223, 63, 9,152, 94, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 28,148,223, 63, 9,152, 94, 63, 22,183, 43, 63, 11,111,149, 63, 25,153,155, 63, 0, 0, 0, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 25,182,180, 63, 21, 48, 38, 63, 31,163,245, 63, 19, 29,253,
+ 63, 28,246,191, 63, 31, 60,109, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 28,246,191,
+ 63, 31, 60,109, 63, 22,168,132, 63, 33, 23,180, 63, 25,182,180, 63, 21, 48, 38, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 19,184,140, 63, 22,209,232, 63, 25,182,180, 63, 21, 48, 38, 63, 22,168,132, 63, 33, 23,180,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 22,168,132, 63, 33, 23,180, 63, 28,246,191,
+ 63, 31, 60,109, 63, 25,238,169, 63, 43, 52,229, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 19,107,138, 63, 44,160,211, 63, 12,204,220, 63, 45, 28, 35, 63, 16,119,225, 63, 34, 17,225, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 16,119,225, 63, 34, 17,225, 63, 22,168,132, 63, 33, 23,180, 63, 19,107,138,
+ 63, 44,160,211, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 25,238,169, 63, 43, 52,229,
+ 63, 19,107,138, 63, 44,160,211, 63, 22,168,132, 63, 33, 23,180, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 22,168,132, 63, 33, 23,180, 63, 16,119,225, 63, 34, 17,225, 63, 19,184,140, 63, 22,209,232, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 32, 73, 51, 63, 40,228,221, 63, 25,238,169, 63, 43, 52,229,
+ 63, 28,246,191, 63, 31, 60,109, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 28,246,191,
+ 63, 31, 60,109, 63, 34,225,192, 63, 28,140,142, 63, 32, 73, 51, 63, 40,228,221, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 38,102,117, 63, 37,200, 45, 63, 32, 73, 51, 63, 40,228,221, 63, 34,225,192, 63, 28,140,142,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 34,225,192, 63, 28,140,142, 63, 28,246,191,
+ 63, 31, 60,109, 63, 31,163,245, 63, 19, 29,253, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 12,204,212, 63, 23, 32,188, 63, 19,184,140, 63, 22,209,232, 63, 16,119,225, 63, 34, 17,225, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 16,119,225, 63, 34, 17,225, 63, 9, 33,207, 63, 34, 17,226, 63, 12,204,212,
+ 63, 23, 32,188, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 5,225, 29, 63, 22,209,233,
+ 63, 12,204,212, 63, 23, 32,188, 63, 9, 33,207, 63, 34, 17,226, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 9, 33,207, 63, 34, 17,226, 63, 16,119,225, 63, 34, 17,225, 63, 12,204,220, 63, 45, 28, 35, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 12,204,212, 63, 23, 32,188, 63, 5,225, 29, 63, 22,209,233,
+ 63, 9,105,118, 63, 11,116,101, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 9,105,118,
+ 63, 11,116,101, 63, 16, 48, 43, 63, 11,116,100, 63, 12,204,212, 63, 23, 32,188, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 19,184,140, 63, 22,209,232, 63, 12,204,212, 63, 23, 32,188, 63, 16, 48, 43, 63, 11,116,100,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 16, 48, 43, 63, 11,116,100, 63, 9,105,118,
+ 63, 11,116,101, 63, 12,204,205, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 19, 51, 51, 63, 0, 1,244, 63, 25,153,155, 63, 0, 0, 0, 63, 22,183, 43, 63, 11,111,149, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 22,183, 43, 63, 11,111,149, 63, 16, 48, 43, 63, 11,116,100, 63, 19, 51, 51,
+ 63, 0, 1,244, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 12,204,205, 63, 0, 0, 0,
+ 63, 19, 51, 51, 63, 0, 1,244, 63, 16, 48, 43, 63, 11,116,100, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 16, 48, 43, 63, 11,116,100, 63, 22,183, 43, 63, 11,111,149, 63, 19,184,140, 63, 22,209,232, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 6,102,102, 63, 0, 1,244, 63, 12,204,205, 63, 0, 0, 0,
+ 63, 9,105,118, 63, 11,116,101, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 9,105,118,
+ 63, 11,116,101, 63, 2,226,118, 63, 11,111,149, 63, 6,102,102, 63, 0, 1,244, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63, 6,102,102, 63, 0, 1,244, 63, 2,226,118, 63, 11,111,149,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 2,226,118, 63, 11,111,149, 63, 9,105,118,
+ 63, 11,116,101, 63, 5,225, 29, 63, 22,209,233, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 12,204,198, 62,217, 58, 72, 63, 6, 10, 77, 62,217,196, 6, 63, 9, 72, 17, 62,198,230,227, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 9, 72, 17, 62,198,230,227, 63, 16, 81,117, 62,198,230,223, 63, 12,204,198,
+ 62,217, 58, 72, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 19,143, 64, 62,217,196, 4,
+ 63, 12,204,198, 62,217, 58, 72, 63, 16, 81,117, 62,198,230,223, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 16, 81,117, 62,198,230,223, 63, 9, 72, 17, 62,198,230,227, 63, 12,204,191, 62,180,111,160, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 12,204,198, 62,217, 58, 72, 63, 19,143, 64, 62,217,196, 4,
+ 63, 16, 33, 76, 62,236,211, 30, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 16, 33, 76,
+ 62,236,211, 30, 63, 9,120, 71, 62,236,211, 30, 63, 12,204,198, 62,217, 58, 72, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 6, 10, 77, 62,217,196, 6, 63, 12,204,198, 62,217, 58, 72, 63, 9,120, 71, 62,236,211, 30,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 9,120, 71, 62,236,211, 30, 63, 16, 33, 76,
+ 62,236,211, 30, 63, 12,204,205, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 6,102,102, 63, 0, 1,244, 63, 0, 0, 0, 63, 0, 0, 0, 63, 2,251, 62, 62,236,207, 67, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 2,251, 62, 62,236,207, 67, 63, 9,120, 71, 62,236,211, 30, 63, 6,102,102,
+ 63, 0, 1,244, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 12,204,205, 63, 0, 0, 0,
+ 63, 6,102,102, 63, 0, 1,244, 63, 9,120, 71, 62,236,211, 30, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 9,120, 71, 62,236,211, 30, 63, 2,251, 62, 62,236,207, 67, 63, 6, 10, 77, 62,217,196, 6, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 19, 51, 51, 63, 0, 1,244, 63, 12,204,205, 63, 0, 0, 0,
+ 63, 16, 33, 76, 62,236,211, 30, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 16, 33, 76,
+ 62,236,211, 30, 63, 22,158, 86, 62,236,207, 65, 63, 19, 51, 51, 63, 0, 1,244, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 25,153,155, 63, 0, 0, 0, 63, 19, 51, 51, 63, 0, 1,244, 63, 22,158, 86, 62,236,207, 65,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 22,158, 86, 62,236,207, 65, 63, 16, 33, 76,
+ 62,236,211, 30, 63, 19,143, 64, 62,217,196, 4, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,255,197,233, 63, 21, 48, 39, 62,243,235,101, 63, 19, 29,252, 62,250, 9,132, 63, 9,152, 94, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,250, 9,132, 63, 9,152, 94, 63, 2,226,118, 63, 11,111,149, 62,255,197,233,
+ 63, 21, 48, 39, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 5,225, 29, 63, 22,209,233,
+ 62,255,197,233, 63, 21, 48, 39, 63, 2,226,118, 63, 11,111,149, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 2,226,118, 63, 11,111,149, 62,250, 9,132, 63, 9,152, 94, 63, 0, 0, 0, 63, 0, 0, 0, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,255,197,233, 63, 21, 48, 39, 63, 5,225, 29, 63, 22,209,233,
+ 63, 2,241, 43, 63, 33, 23,181, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 2,241, 43,
+ 63, 33, 23,181, 62,249, 69,225, 63, 31, 60,110, 62,255,197,233, 63, 21, 48, 39, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,243,235,101, 63, 19, 29,252, 62,255,197,233, 63, 21, 48, 39, 62,249, 69,225, 63, 31, 60,110,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,249, 69,225, 63, 31, 60,110, 63, 2,241, 43,
+ 63, 33, 23,181, 62,255, 86, 30, 63, 43, 52,230, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,242,161, 9, 63, 40,228,223, 62,230,102,129, 63, 37,200, 48, 62,237,111,222, 63, 28,140,143, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,237,111,222, 63, 28,140,143, 62,249, 69,225, 63, 31, 60,110, 62,242,161, 9,
+ 63, 40,228,223, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,255, 86, 30, 63, 43, 52,230,
+ 62,242,161, 9, 63, 40,228,223, 62,249, 69,225, 63, 31, 60,110, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62,249, 69,225, 63, 31, 60,110, 62,237,111,222, 63, 28,140,143, 62,243,235,101, 63, 19, 29,252, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 6, 46, 46, 63, 44,160,211, 62,255, 86, 30, 63, 43, 52,230,
+ 63, 2,241, 43, 63, 33, 23,181, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 2,241, 43,
+ 63, 33, 23,181, 63, 9, 33,207, 63, 34, 17,226, 63, 6, 46, 46, 63, 44,160,211, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 12,204,220, 63, 45, 28, 35, 63, 6, 46, 46, 63, 44,160,211, 63, 9, 33,207, 63, 34, 17,226,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 9, 33,207, 63, 34, 17,226, 63, 2,241, 43,
+ 63, 33, 23,181, 63, 5,225, 29, 63, 22,209,233, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 85,238,138, 62,187,220, 72, 63, 82,173,218, 62,210, 92, 55, 63, 79,189,229, 62,189,208,173, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 79,189,229, 62,189,208,173, 63, 82,250,230, 62,166,190,117, 63, 85,238,138,
+ 62,187,220, 72, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 89,153,149, 62,165,199,201,
+ 63, 85,238,138, 62,187,220, 72, 63, 82,250,230, 62,166,190,117, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 82,250,230, 62,166,190,117, 63, 79,189,229, 62,189,208,173, 63, 76,119,198, 62,169,150, 90, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 73,111,170, 62,193,135, 68, 63, 76,119,198, 62,169,150, 90,
+ 63, 79,189,229, 62,189,208,173, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 79,189,229,
+ 62,189,208,173, 63, 76,175,176, 62,213,159,192, 63, 73,111,170, 62,193,135, 68, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 70,194,112, 62,217,196, 19, 63, 73,111,170, 62,193,135, 68, 63, 76,175,176, 62,213,159,192,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 76,175,176, 62,213,159,192, 63, 79,189,229,
+ 62,189,208,173, 63, 82,173,218, 62,210, 92, 55, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 79,175, 52, 62,233, 32,218, 63, 76,204,193, 63, 0, 0, 0, 63, 73,209,128, 62,236,207, 75, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 73,209,128, 62,236,207, 75, 63, 76,175,176, 62,213,159,192, 63, 79,175, 52,
+ 62,233, 32,218, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 82,173,218, 62,210, 92, 55,
+ 63, 79,175, 52, 62,233, 32,218, 63, 76,175,176, 62,213,159,192, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 76,175,176, 62,213,159,192, 63, 73,209,128, 62,236,207, 75, 63, 70,194,112, 62,217,196, 19, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 73,111,170, 62,193,135, 68, 63, 70,194,112, 62,217,196, 19,
+ 63, 67,132,171, 62,198,230,253, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 67,132,171,
+ 62,198,230,253, 63, 70, 29, 61, 62,174, 54,114, 63, 73,111,170, 62,193,135, 68, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 76,119,198, 62,169,150, 90, 63, 73,111,170, 62,193,135, 68, 63, 70, 29, 61, 62,174, 54,114,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 70, 29, 61, 62,174, 54,114, 63, 67,132,171,
+ 62,198,230,253, 63, 64, 0, 0, 62,180,111,211, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 79,175, 52, 62,233, 32,218, 63, 82,173,218, 62,210, 92, 55, 63, 86, 54, 56, 62,233, 23, 58, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 86, 54, 56, 62,233, 23, 58, 63, 83, 51, 41, 62,255,252, 24, 63, 79,175, 52,
+ 62,233, 32,218, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 76,204,193, 63, 0, 0, 0,
+ 63, 79,175, 52, 62,233, 32,218, 63, 83, 51, 41, 62,255,252, 24, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 83, 51, 41, 62,255,252, 24, 63, 86, 54, 56, 62,233, 23, 58, 63, 89,153,147, 63, 0, 0, 0, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 92,252,239, 62,233, 23, 58, 63, 89,153,147, 63, 0, 0, 0,
+ 63, 86, 54, 56, 62,233, 23, 58, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 86, 54, 56,
+ 62,233, 23, 58, 63, 89,153,147, 62,209,190,143, 63, 92,252,239, 62,233, 23, 58, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 96,133, 78, 62,210, 92, 55, 63, 92,252,239, 62,233, 23, 58, 63, 89,153,147, 62,209,190,143,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 89,153,147, 62,209,190,143, 63, 86, 54, 56,
+ 62,233, 23, 58, 63, 82,173,218, 62,210, 92, 55, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 85,238,138, 62,187,220, 72, 63, 89,153,149, 62,165,199,201, 63, 93, 68,159, 62,187,220, 72, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 93, 68,159, 62,187,220, 72, 63, 89,153,147, 62,209,190,143, 63, 85,238,138,
+ 62,187,220, 72, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 82,173,218, 62,210, 92, 55,
+ 63, 85,238,138, 62,187,220, 72, 63, 89,153,147, 62,209,190,143, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 89,153,147, 62,209,190,143, 63, 93, 68,159, 62,187,220, 72, 63, 96,133, 78, 62,210, 92, 55, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 92,252,239, 62,233, 23, 58, 63, 96,133, 78, 62,210, 92, 55,
+ 63, 99,131,242, 62,233, 32,218, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 99,131,242,
+ 62,233, 32,218, 63, 95,255,254, 62,255,252, 24, 63, 92,252,239, 62,233, 23, 58, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 89,153,147, 63, 0, 0, 0, 63, 92,252,239, 62,233, 23, 58, 63, 95,255,254, 62,255,252, 24,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 95,255,254, 62,255,252, 24, 63, 99,131,242,
+ 62,233, 32,218, 63,102,102,101, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63,111,174,139, 62,198,230,223, 63,108,112,192, 62,217,196, 4, 63,105,195,133, 62,193,135, 37, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,105,195,133, 62,193,135, 37, 63,109, 21,249, 62,174, 54, 65, 63,111,174,139,
+ 62,198,230,223, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,115, 51, 65, 62,180,111,160,
+ 63,111,174,139, 62,198,230,223, 63,109, 21,249, 62,174, 54, 65, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63,109, 21,249, 62,174, 54, 65, 63,105,195,133, 62,193,135, 37, 63,102,187,106, 62,169,150, 54, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 99,117, 70, 62,189,208,155, 63,102,187,106, 62,169,150, 54,
+ 63,105,195,133, 62,193,135, 37, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,105,195,133,
+ 62,193,135, 37, 63,102,131,123, 62,213,159,181, 63, 99,117, 70, 62,189,208,155, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 96,133, 78, 62,210, 92, 55, 63, 99,117, 70, 62,189,208,155, 63,102,131,123, 62,213,159,181,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,102,131,123, 62,213,159,181, 63,105,195,133,
+ 62,193,135, 37, 63,108,112,192, 62,217,196, 4, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63,105, 97,170, 62,236,207, 65, 63,102,102,101, 63, 0, 0, 0, 63, 99,131,242, 62,233, 32,218, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 99,131,242, 62,233, 32,218, 63,102,131,123, 62,213,159,181, 63,105, 97,170,
+ 62,236,207, 65, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,108,112,192, 62,217,196, 4,
+ 63,105, 97,170, 62,236,207, 65, 63,102,131,123, 62,213,159,181, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63,102,131,123, 62,213,159,181, 63, 99,131,242, 62,233, 32,218, 63, 96,133, 78, 62,210, 92, 55, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 99,117, 70, 62,189,208,155, 63, 96,133, 78, 62,210, 92, 55,
+ 63, 93, 68,159, 62,187,220, 72, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 93, 68,159,
+ 62,187,220, 72, 63, 96, 56, 71, 62,166,190, 99, 63, 99,117, 70, 62,189,208,155, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63,102,187,106, 62,169,150, 54, 63, 99,117, 70, 62,189,208,155, 63, 96, 56, 71, 62,166,190, 99,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 96, 56, 71, 62,166,190, 99, 63, 93, 68,159,
+ 62,187,220, 72, 63, 89,153,149, 62,165,199,201, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 99,107, 33, 63, 9,152, 94, 63, 96, 92, 11, 63, 19, 29,253, 63, 92,238, 21, 63, 9,150,112, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 92,238, 21, 63, 9,150,112, 63, 95,255,254, 62,255,252, 24, 63, 99,107, 33,
+ 63, 9,152, 94, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,102,102,101, 63, 0, 0, 0,
+ 63, 99,107, 33, 63, 9,152, 94, 63, 95,255,254, 62,255,252, 24, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 95,255,254, 62,255,252, 24, 63, 92,238, 21, 63, 9,150,112, 63, 89,153,147, 63, 0, 0, 0, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 86, 69, 14, 63, 9,150,112, 63, 89,153,147, 63, 0, 0, 0,
+ 63, 92,238, 21, 63, 9,150,112, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 92,238, 21,
+ 63, 9,150,112, 63, 89,153,143, 63, 19, 98,219, 63, 86, 69, 14, 63, 9,150,112, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 82,215, 19, 63, 19, 29,252, 63, 86, 69, 14, 63, 9,150,112, 63, 89,153,143, 63, 19, 98,219,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 89,153,143, 63, 19, 98,219, 63, 92,238, 21,
+ 63, 9,150,112, 63, 96, 92, 11, 63, 19, 29,253, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 93, 30, 63, 63, 28,140,143, 63, 89,153,139, 63, 37,200, 45, 63, 86, 20,218, 63, 28,140,143, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 86, 20,218, 63, 28,140,143, 63, 89,153,143, 63, 19, 98,219, 63, 93, 30, 63,
+ 63, 28,140,143, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 96, 92, 11, 63, 19, 29,253,
+ 63, 93, 30, 63, 63, 28,140,143, 63, 89,153,143, 63, 19, 98,219, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 89,153,143, 63, 19, 98,219, 63, 86, 20,218, 63, 28,140,143, 63, 82,215, 19, 63, 19, 29,252, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 86, 69, 14, 63, 9,150,112, 63, 82,215, 19, 63, 19, 29,252,
+ 63, 79,200, 1, 63, 9,152, 94, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 79,200, 1,
+ 63, 9,152, 94, 63, 83, 51, 41, 62,255,252, 24, 63, 86, 69, 14, 63, 9,150,112, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 89,153,147, 63, 0, 0, 0, 63, 86, 69, 14, 63, 9,150,112, 63, 83, 51, 41, 62,255,252, 24,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 83, 51, 41, 62,255,252, 24, 63, 79,200, 1,
+ 63, 9,152, 94, 63, 76,204,193, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 61, 18, 28,237, 62,187,220, 60, 60,188, 35,151, 62,210, 92, 46, 60, 60, 74,218, 62,189,208,150, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 60, 60, 74,218, 62,189,208,150, 60,197,197,195, 62,166,190, 89, 61, 18, 28,237,
+ 62,187,220, 60, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61, 76,205,194, 62,165,199,186,
+ 61, 18, 28,237, 62,187,220, 60, 60,197,197,195, 62,166,190, 89, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63,131, 23, 23, 62,166,190, 89, 63,129,120,150, 62,189,208,150, 63,127,171, 15, 62,169,150, 52, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,124,162,241, 62,193,135, 36, 63,127,171, 15, 62,169,150, 52,
+ 63,129,120,150, 62,189,208,150, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,129,120,150,
+ 62,189,208,150, 63,127,226,244, 62,213,159,179, 63,124,162,241, 62,193,135, 36, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63,121,245,179, 62,217,196, 6, 63,124,162,241, 62,193,135, 36, 63,127,226,244, 62,213,159,179,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,127,226,244, 62,213,159,179, 63,129,120,150,
+ 62,189,208,150, 63,130,240,142, 62,210, 92, 46, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63,129,113, 59, 62,233, 32,214, 63,128, 0, 0, 63, 0, 0, 0, 63,125, 4,194, 62,236,207, 67, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,125, 4,194, 62,236,207, 67, 63,127,226,244, 62,213,159,179, 63,129,113, 59,
+ 62,233, 32,214, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,130,240,142, 62,210, 92, 46,
+ 63,129,113, 59, 62,233, 32,214, 63,127,226,244, 62,213,159,179, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63,127,226,244, 62,213,159,179, 63,125, 4,194, 62,236,207, 67, 63,121,245,179, 62,217,196, 6, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,124,162,241, 62,193,135, 36, 63,121,245,179, 62,217,196, 6,
+ 63,118,183,239, 62,198,230,227, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,118,183,239,
+ 62,198,230,227, 63,121, 80,133, 62,174, 54, 65, 63,124,162,241, 62,193,135, 36, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63,127,171, 15, 62,169,150, 52, 63,124,162,241, 62,193,135, 36, 63,121, 80,133, 62,174, 54, 65,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,121, 80,133, 62,174, 54, 65, 63,118,183,239,
+ 62,198,230,227, 63,115, 51, 65, 62,180,111,160, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 60, 56,157,110, 62,233, 32,214, 60,188, 35,151, 62,210, 92, 46, 61, 22,151, 95, 62,233, 23, 55, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61, 22,151, 95, 62,233, 23, 55, 60,204,204,176, 62,255,252, 24, 60, 56,157,110,
+ 62,233, 32,214, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 38, 11, 79,167, 63, 0, 0, 0,
+ 60, 56,157,110, 62,233, 32,214, 60,204,204,176, 62,255,252, 24, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 60,204,204,176, 62,255,252, 24, 61, 22,151, 95, 62,233, 23, 55, 61, 76,204,215, 63, 0, 0, 0, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,129,129, 87, 62,233, 23, 57, 61, 76,204,215, 63, 0, 0, 0,
+ 61, 22,151, 95, 62,233, 23, 55, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61, 22,151, 95,
+ 62,233, 23, 55, 61, 76,205, 68, 62,209,190,135, 61,129,129, 87, 62,233, 23, 57, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 61,157,196, 92, 62,210, 92, 49, 61,129,129, 87, 62,233, 23, 57, 61, 76,205, 68, 62,209,190,135,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61, 76,205, 68, 62,209,190,135, 61, 22,151, 95,
+ 62,233, 23, 55, 60,188, 35,151, 62,210, 92, 46, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 61, 18, 28,237, 62,187,220, 60, 61, 76,205,194, 62,165,199,186, 61,131,191, 7, 62,187,220, 62, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,131,191, 7, 62,187,220, 62, 61, 76,205, 68, 62,209,190,135, 61, 18, 28,237,
+ 62,187,220, 60, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 60,188, 35,151, 62,210, 92, 46,
+ 61, 18, 28,237, 62,187,220, 60, 61, 76,205, 68, 62,209,190,135, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 61, 76,205, 68, 62,209,190,135, 61,131,191, 7, 62,187,220, 62, 61,157,196, 92, 62,210, 92, 49, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,129,129, 87, 62,233, 23, 57, 61,157,196, 92, 62,210, 92, 49,
+ 61,181,185, 89, 62,233, 32,214, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,181,185, 89,
+ 62,233, 32,214, 61,153,153,154, 62,255,252, 25, 61,129,129, 87, 62,233, 23, 57, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 61, 76,204,215, 63, 0, 0, 0, 61,129,129, 87, 62,233, 23, 57, 61,153,153,154, 62,255,252, 25,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,153,153,154, 62,255,252, 25, 61,181,185, 89,
+ 62,233, 32,214, 61,204,204,215, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62, 11,135, 1, 62,198,230,228, 61,253, 31,171, 62,217,196, 6, 61,231,181,251, 62,193,135, 38, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,231,181,251, 62,193,135, 38, 62, 1, 36,204, 62,174, 54, 70, 62, 11,135, 1,
+ 62,198,230,228, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 25,153,214, 62,180,111,165,
+ 62, 11,135, 1, 62,198,230,228, 62, 1, 36,204, 62,174, 54, 70, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62, 1, 36,204, 62,174, 54, 70, 61,231,181,251, 62,193,135, 38, 61,207,117, 70, 62,169,150, 54, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,181, 68, 35, 62,189,208,153, 61,207,117, 70, 62,169,150, 54,
+ 61,231,181,251, 62,193,135, 38, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,231,181,251,
+ 62,193,135, 38, 61,205,181,164, 62,213,159,180, 61,181, 68, 35, 62,189,208,153, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 61,157,196, 92, 62,210, 92, 49, 61,181, 68, 35, 62,189,208,153, 61,205,181,164, 62,213,159,180,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,205,181,164, 62,213,159,180, 61,231,181,251,
+ 62,193,135, 38, 61,253, 31,171, 62,217,196, 6, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 61,228,166,251, 62,236,207, 67, 61,204,204,215, 63, 0, 0, 0, 61,181,185, 89, 62,233, 32,214, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,181,185, 89, 62,233, 32,214, 61,205,181,164, 62,213,159,180, 61,228,166,251,
+ 62,236,207, 67, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,253, 31,171, 62,217,196, 6,
+ 61,228,166,251, 62,236,207, 67, 61,205,181,164, 62,213,159,180, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 61,205,181,164, 62,213,159,180, 61,181,185, 89, 62,233, 32,214, 61,157,196, 92, 62,210, 92, 49, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,181, 68, 35, 62,189,208,153, 61,157,196, 92, 62,210, 92, 49,
+ 61,131,191, 7, 62,187,220, 62, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,131,191, 7,
+ 62,187,220, 62, 61,155, 92, 79, 62,166,190, 91, 61,181, 68, 35, 62,189,208,153, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 61,207,117, 70, 62,169,150, 54, 61,181, 68, 35, 62,189,208,153, 61,155, 92, 79, 62,166,190, 91,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,155, 92, 79, 62,166,190, 91, 61,131,191, 7,
+ 62,187,220, 62, 61, 76,205,194, 62,165,199,186, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 61,180,242,172, 63, 9,152, 96, 61,156,122, 1, 63, 19, 29,254, 61,129, 10,100, 63, 9,150,113, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,129, 10,100, 63, 9,150,113, 61,153,153,154, 62,255,252, 25, 61,180,242,172,
+ 63, 9,152, 96, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,204,204,215, 63, 0, 0, 0,
+ 61,180,242,172, 63, 9,152, 96, 61,153,153,154, 62,255,252, 25, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 61,153,153,154, 62,255,252, 25, 61,129, 10,100, 63, 9,150,113, 61, 76,204,215, 63, 0, 0, 0, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61, 23,132,109, 63, 9,150,113, 61, 76,204,215, 63, 0, 0, 0,
+ 61,129, 10,100, 63, 9,150,113, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,129, 10,100,
+ 63, 9,150,113, 61, 76,204, 91, 63, 19, 98,220, 61, 23,132,109, 63, 9,150,113, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 60,193, 73,174, 63, 19, 29,253, 61, 23,132,109, 63, 9,150,113, 61, 76,204, 91, 63, 19, 98,220,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61, 76,204, 91, 63, 19, 98,220, 61,129, 10,100,
+ 63, 9,150,113, 61,156,122, 1, 63, 19, 29,254, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 61,130,139,166, 63, 28,140,145, 61, 76,203,246, 63, 37,200, 48, 61, 20,129, 13, 63, 28,140,143, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61, 20,129, 13, 63, 28,140,143, 61, 76,204, 91, 63, 19, 98,220, 61,130,139,166,
+ 63, 28,140,145, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,156,122, 1, 63, 19, 29,254,
+ 61,130,139,166, 63, 28,140,145, 61, 76,204, 91, 63, 19, 98,220, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 61, 76,204, 91, 63, 19, 98,220, 61, 20,129, 13, 63, 28,140,143, 60,193, 73,174, 63, 19, 29,253, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61, 23,132,109, 63, 9,150,113, 60,193, 73,174, 63, 19, 29,253,
+ 60, 62,207,114, 63, 9,152, 94, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 60, 62,207,114,
+ 63, 9,152, 94, 60,204,204,176, 62,255,252, 24, 61, 23,132,109, 63, 9,150,113, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 61, 76,204,215, 63, 0, 0, 0, 61, 23,132,109, 63, 9,150,113, 60,204,204,176, 62,255,252, 24,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 60,204,204,176, 62,255,252, 24, 60, 62,207,114,
+ 63, 9,152, 94, 38, 11, 79,167, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,113, 83,237, 62,187,220, 79, 62,100, 81, 63, 62,210, 92, 60, 62, 88,145,110, 62,189,208,167, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 88,145,110, 62,189,208,167, 62,101,133, 91, 62,166,190,112, 62,113, 83,237,
+ 62,187,220, 79, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,128, 0, 0, 62,165,199,206,
+ 62,113, 83,237, 62,187,220, 79, 62,101,133, 91, 62,166,190,112, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62,101,133, 91, 62,166,190,112, 62, 88,145,110, 62,189,208,167, 62, 75,120,239, 62,169,150, 70, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 63, 88,144, 62,193,135, 46, 62, 75,120,239, 62,169,150, 70,
+ 62, 88,145,110, 62,189,208,167, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 88,145,110,
+ 62,189,208,167, 62, 76, 88,170, 62,213,159,187, 62, 63, 88,144, 62,193,135, 46, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62, 52,163,179, 62,217,196, 7, 62, 63, 88,144, 62,193,135, 46, 62, 76, 88,170, 62,213,159,187,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 76, 88,170, 62,213,159,187, 62, 88,145,110,
+ 62,189,208,167, 62,100, 81, 63, 62,210, 92, 60, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62, 88, 86,190, 62,233, 32,221, 62, 76,204,254, 63, 0, 0, 0, 62, 64,223,251, 62,236,207, 67, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 64,223,251, 62,236,207, 67, 62, 76, 88,170, 62,213,159,187, 62, 88, 86,190,
+ 62,233, 32,221, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,100, 81, 63, 62,210, 92, 60,
+ 62, 88, 86,190, 62,233, 32,221, 62, 76, 88,170, 62,213,159,187, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62, 76, 88,170, 62,213,159,187, 62, 64,223,251, 62,236,207, 67, 62, 52,163,179, 62,217,196, 7, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 63, 88,144, 62,193,135, 46, 62, 52,163,179, 62,217,196, 7,
+ 62, 39,172,153, 62,198,230,230, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 39,172,153,
+ 62,198,230,230, 62, 50, 14,213, 62,174, 54, 78, 62, 63, 88,144, 62,193,135, 46, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62, 75,120,239, 62,169,150, 70, 62, 63, 88,144, 62,193,135, 46, 62, 50, 14,213, 62,174, 54, 78,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 50, 14,213, 62,174, 54, 78, 62, 39,172,153,
+ 62,198,230,230, 62, 25,153,214, 62,180,111,165, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62, 88, 86,190, 62,233, 32,221, 62,100, 81, 63, 62,210, 92, 60, 62,114,114,166, 62,233, 23, 63, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,114,114,166, 62,233, 23, 63, 62,102,102,126, 62,255,252, 25, 62, 88, 86,190,
+ 62,233, 32,221, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 76,204,254, 63, 0, 0, 0,
+ 62, 88, 86,190, 62,233, 32,221, 62,102,102,126, 62,255,252, 25, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62,102,102,126, 62,255,252, 25, 62,114,114,166, 62,233, 23, 63, 62,128, 0, 0, 63, 0, 0, 0, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,134,198,173, 62,233, 23, 63, 62,128, 0, 0, 63, 0, 0, 0,
+ 62,114,114,166, 62,233, 23, 63, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,114,114,166,
+ 62,233, 23, 63, 62,128, 0, 0, 62,209,190,149, 62,134,198,173, 62,233, 23, 63, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,141,215, 97, 62,210, 92, 60, 62,134,198,173, 62,233, 23, 63, 62,128, 0, 0, 62,209,190,149,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,128, 0, 0, 62,209,190,149, 62,114,114,166,
+ 62,233, 23, 63, 62,100, 81, 63, 62,210, 92, 60, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,113, 83,237, 62,187,220, 79, 62,128, 0, 0, 62,165,199,206, 62,135, 86, 9, 62,187,220, 79, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,135, 86, 9, 62,187,220, 79, 62,128, 0, 0, 62,209,190,149, 62,113, 83,237,
+ 62,187,220, 79, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,100, 81, 63, 62,210, 92, 60,
+ 62,113, 83,237, 62,187,220, 79, 62,128, 0, 0, 62,209,190,149, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62,128, 0, 0, 62,209,190,149, 62,135, 86, 9, 62,187,220, 79, 62,141,215, 97, 62,210, 92, 60, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,134,198,173, 62,233, 23, 63, 62,141,215, 97, 62,210, 92, 60,
+ 62,147,212,161, 62,233, 32,221, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,147,212,161,
+ 62,233, 32,221, 62,140,204,193, 62,255,252, 25, 62,134,198,173, 62,233, 23, 63, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,128, 0, 0, 63, 0, 0, 0, 62,134,198,173, 62,233, 23, 63, 62,140,204,193, 62,255,252, 25,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,140,204,193, 62,255,252, 25, 62,147,212,161,
+ 62,233, 32,221, 62,153,153,129, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,172, 41,180, 62,198,230,227, 62,165,174, 39, 62,217,196, 7, 62,160, 83,184, 62,193,135, 46, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,160, 83,184, 62,193,135, 46, 62,166,248,150, 62,174, 54, 78, 62,172, 41,180,
+ 62,198,230,227, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,179, 51, 21, 62,180,111,165,
+ 62,172, 41,180, 62,198,230,227, 62,166,248,150, 62,174, 54, 78, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62,166,248,150, 62,174, 54, 78, 62,160, 83,184, 62,193,135, 46, 62,154, 67,137, 62,169,150, 70, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,147,183, 73, 62,189,208,167, 62,154, 67,137, 62,169,150, 70,
+ 62,160, 83,184, 62,193,135, 46, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,160, 83,184,
+ 62,193,135, 46, 62,153,211,171, 62,213,159,187, 62,147,183, 73, 62,189,208,167, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,141,215, 97, 62,210, 92, 60, 62,147,183, 73, 62,189,208,167, 62,153,211,171, 62,213,159,187,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,153,211,171, 62,213,159,187, 62,160, 83,184,
+ 62,193,135, 46, 62,165,174, 39, 62,217,196, 7, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,159,144, 3, 62,236,207, 67, 62,153,153,129, 63, 0, 0, 0, 62,147,212,161, 62,233, 32,221, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,147,212,161, 62,233, 32,221, 62,153,211,171, 62,213,159,187, 62,159,144, 3,
+ 62,236,207, 67, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,165,174, 39, 62,217,196, 7,
+ 62,159,144, 3, 62,236,207, 67, 62,153,211,171, 62,213,159,187, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62,153,211,171, 62,213,159,187, 62,147,212,161, 62,233, 32,221, 62,141,215, 97, 62,210, 92, 60, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,147,183, 73, 62,189,208,167, 62,141,215, 97, 62,210, 92, 60,
+ 62,135, 86, 9, 62,187,220, 79, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,135, 86, 9,
+ 62,187,220, 79, 62,141, 61, 82, 62,166,190,112, 62,147,183, 73, 62,189,208,167, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,154, 67,137, 62,169,150, 70, 62,147,183, 73, 62,189,208,167, 62,141, 61, 82, 62,166,190,112,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,141, 61, 82, 62,166,190,112, 62,135, 86, 9,
+ 62,187,220, 79, 62,128, 0, 0, 62,165,199,206, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,147,163, 1, 63, 9,152, 91, 62,141,132,224, 63, 19, 29,246, 62,134,168,251, 63, 9,150,107, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,134,168,251, 63, 9,150,107, 62,140,204,193, 62,255,252, 25, 62,147,163, 1,
+ 63, 9,152, 91, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,153,153,129, 63, 0, 0, 0,
+ 62,147,163, 1, 63, 9,152, 91, 62,140,204,193, 62,255,252, 25, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62,140,204,193, 62,255,252, 25, 62,134,168,251, 63, 9,150,107, 62,128, 0, 0, 63, 0, 0, 0, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,114,174, 11, 63, 9,150,107, 62,128, 0, 0, 63, 0, 0, 0,
+ 62,134,168,251, 63, 9,150,107, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,134,168,251,
+ 63, 9,150,107, 62,128, 0, 0, 63, 19, 98,209, 62,114,174, 11, 63, 9,150,107, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,100,246, 64, 63, 19, 29,246, 62,114,174, 11, 63, 9,150,107, 62,128, 0, 0, 63, 19, 98,209,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,128, 0, 0, 63, 19, 98,209, 62,134,168,251,
+ 63, 9,150,107, 62,141,132,224, 63, 19, 29,246, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,135, 9, 86, 63, 28,140,130, 62,128, 0, 0, 63, 37,200, 23, 62,113,237, 83, 63, 28,140,130, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,113,237, 83, 63, 28,140,130, 62,128, 0, 0, 63, 19, 98,209, 62,135, 9, 86,
+ 63, 28,140,130, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,141,132,224, 63, 19, 29,246,
+ 62,135, 9, 86, 63, 28,140,130, 62,128, 0, 0, 63, 19, 98,209, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62,128, 0, 0, 63, 19, 98,209, 62,113,237, 83, 63, 28,140,130, 62,100,246, 64, 63, 19, 29,246, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,114,174, 11, 63, 9,150,107, 62,100,246, 64, 63, 19, 29,246,
+ 62, 88,185,255, 63, 9,152, 90, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 88,185,255,
+ 63, 9,152, 90, 62,102,102,126, 62,255,252, 25, 62,114,174, 11, 63, 9,150,107, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,128, 0, 0, 63, 0, 0, 0, 62,114,174, 11, 63, 9,150,107, 62,102,102,126, 62,255,252, 25,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,102,102,126, 62,255,252, 25, 62, 88,185,255,
+ 63, 9,152, 90, 62, 76,204,254, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,223, 16, 63, 62,187,220, 62, 62,216,142,233, 62,210, 92, 49, 62,210,174,248, 62,189,208,153, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,210,174,248, 62,189,208,153, 62,217, 40,237, 62,166,190, 91, 62,223, 16, 63,
+ 62,187,220, 62, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,230,102, 72, 62,165,199,183,
+ 62,223, 16, 63, 62,187,220, 62, 62,217, 40,237, 62,166,190, 91, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62,217, 40,237, 62,166,190, 91, 62,210,174,248, 62,189,208,153, 62,204, 34,175, 62,169,150, 54, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,198, 18,129, 62,193,135, 37, 62,204, 34,175, 62,169,150, 54,
+ 62,210,174,248, 62,189,208,153, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,210,174,248,
+ 62,189,208,153, 62,204,146,151, 62,213,159,180, 62,198, 18,129, 62,193,135, 37, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,192,184, 21, 62,217,196, 6, 62,198, 18,129, 62,193,135, 37, 62,204,146,151, 62,213,159,180,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,204,146,151, 62,213,159,180, 62,210,174,248,
+ 62,189,208,153, 62,216,142,233, 62,210, 92, 49, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,210,145,170, 62,233, 32,214, 62,204,204,202, 63, 0, 0, 0, 62,198,214, 65, 62,236,207, 67, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,198,214, 65, 62,236,207, 67, 62,204,146,151, 62,213,159,180, 62,210,145,170,
+ 62,233, 32,214, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,216,142,233, 62,210, 92, 49,
+ 62,210,145,170, 62,233, 32,214, 62,204,146,151, 62,213,159,180, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62,204,146,151, 62,213,159,180, 62,198,214, 65, 62,236,207, 67, 62,192,184, 21, 62,217,196, 6, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,198, 18,129, 62,193,135, 37, 62,192,184, 21, 62,217,196, 6,
+ 62,186, 60,127, 62,198,230,225, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,186, 60,127,
+ 62,198,230,225, 62,191,109,154, 62,174, 54, 68, 62,198, 18,129, 62,193,135, 37, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,204, 34,175, 62,169,150, 54, 62,198, 18,129, 62,193,135, 37, 62,191,109,154, 62,174, 54, 68,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,191,109,154, 62,174, 54, 68, 62,186, 60,127,
+ 62,198,230,225, 62,179, 51, 21, 62,180,111,165, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,210,145,170, 62,233, 32,214, 62,216,142,233, 62,210, 92, 49, 62,223,159,171, 62,233, 23, 57, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,223,159,171, 62,233, 23, 57, 62,217,153,154, 62,255,252, 24, 62,210,145,170,
+ 62,233, 32,214, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,204,204,202, 63, 0, 0, 0,
+ 62,210,145,170, 62,233, 32,214, 62,217,153,154, 62,255,252, 24, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62,217,153,154, 62,255,252, 24, 62,223,159,171, 62,233, 23, 57, 62,230,102,101, 63, 0, 0, 0, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,237, 45, 20, 62,233, 23, 55, 62,230,102,101, 63, 0, 0, 0,
+ 62,223,159,171, 62,233, 23, 57, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,223,159,171,
+ 62,233, 23, 57, 62,230,102, 88, 62,209,190,135, 62,237, 45, 20, 62,233, 23, 55, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,244, 61,199, 62,210, 92, 46, 62,237, 45, 20, 62,233, 23, 55, 62,230,102, 88, 62,209,190,135,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,230,102, 88, 62,209,190,135, 62,223,159,171,
+ 62,233, 23, 57, 62,216,142,233, 62,210, 92, 49, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,223, 16, 63, 62,187,220, 62, 62,230,102, 72, 62,165,199,183, 62,237,188, 99, 62,187,220, 60, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,237,188, 99, 62,187,220, 60, 62,230,102, 88, 62,209,190,135, 62,223, 16, 63,
+ 62,187,220, 62, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,216,142,233, 62,210, 92, 49,
+ 62,223, 16, 63, 62,187,220, 62, 62,230,102, 88, 62,209,190,135, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62,230,102, 88, 62,209,190,135, 62,237,188, 99, 62,187,220, 60, 62,244, 61,199, 62,210, 92, 46, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,237, 45, 20, 62,233, 23, 55, 62,244, 61,199, 62,210, 92, 46,
+ 62,250, 59, 21, 62,233, 32,213, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,250, 59, 21,
+ 62,233, 32,213, 62,243, 51, 53, 62,255,252, 24, 62,237, 45, 20, 62,233, 23, 55, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,230,102,101, 63, 0, 0, 0, 62,237, 45, 20, 62,233, 23, 55, 62,243, 51, 53, 62,255,252, 24,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,243, 51, 53, 62,255,252, 24, 62,250, 59, 21,
+ 62,233, 32,213, 63, 0, 0, 0, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 9, 72, 17, 62,198,230,227, 63, 6, 10, 77, 62,217,196, 6, 63, 3, 93, 15, 62,193,135, 36, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 3, 93, 15, 62,193,135, 36, 63, 6,175,123, 62,174, 54, 65, 63, 9, 72, 17,
+ 62,198,230,227, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 12,204,191, 62,180,111,160,
+ 63, 9, 72, 17, 62,198,230,227, 63, 6,175,123, 62,174, 54, 65, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 6,175,123, 62,174, 54, 65, 63, 3, 93, 15, 62,193,135, 36, 63, 0, 84,241, 62,169,150, 52, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,250, 29,169, 62,189,208,150, 63, 0, 84,241, 62,169,150, 52,
+ 63, 3, 93, 15, 62,193,135, 36, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 3, 93, 15,
+ 62,193,135, 36, 63, 0, 29, 12, 62,213,159,179, 62,250, 29,169, 62,189,208,150, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,244, 61,199, 62,210, 92, 46, 62,250, 29,169, 62,189,208,150, 63, 0, 29, 12, 62,213,159,179,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 0, 29, 12, 62,213,159,179, 63, 3, 93, 15,
+ 62,193,135, 36, 63, 6, 10, 77, 62,217,196, 6, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 2,251, 62, 62,236,207, 67, 63, 0, 0, 0, 63, 0, 0, 0, 62,250, 59, 21, 62,233, 32,213, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,250, 59, 21, 62,233, 32,213, 63, 0, 29, 12, 62,213,159,179, 63, 2,251, 62,
+ 62,236,207, 67, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 6, 10, 77, 62,217,196, 6,
+ 63, 2,251, 62, 62,236,207, 67, 63, 0, 29, 12, 62,213,159,179, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 0, 29, 12, 62,213,159,179, 62,250, 59, 21, 62,233, 32,213, 62,244, 61,199, 62,210, 92, 46, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,250, 29,169, 62,189,208,150, 62,244, 61,199, 62,210, 92, 46,
+ 62,237,188, 99, 62,187,220, 60, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,237,188, 99,
+ 62,187,220, 60, 62,243,163,164, 62,166,190, 89, 62,250, 29,169, 62,189,208,150, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 0, 84,241, 62,169,150, 52, 62,250, 29,169, 62,189,208,150, 62,243,163,164, 62,166,190, 89,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,243,163,164, 62,166,190, 89, 62,237,188, 99,
+ 62,187,220, 60, 62,230,102, 72, 62,165,199,183, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,250, 9,132, 63, 9,152, 94, 62,243,235,101, 63, 19, 29,252, 62,237, 15,114, 63, 9,150,113, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,237, 15,114, 63, 9,150,113, 62,243, 51, 53, 62,255,252, 24, 62,250, 9,132,
+ 63, 9,152, 94, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0,
+ 62,250, 9,132, 63, 9,152, 94, 62,243, 51, 53, 62,255,252, 24, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62,243, 51, 53, 62,255,252, 24, 62,237, 15,114, 63, 9,150,113, 62,230,102,101, 63, 0, 0, 0, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,223,189,103, 63, 9,150,112, 62,230,102,101, 63, 0, 0, 0,
+ 62,237, 15,114, 63, 9,150,113, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,237, 15,114,
+ 63, 9,150,113, 62,230,102,117, 63, 19, 98,220, 62,223,189,103, 63, 9,150,112, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,216,225,128, 63, 19, 29,254, 62,223,189,103, 63, 9,150,112, 62,230,102,117, 63, 19, 98,220,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,230,102,117, 63, 19, 98,220, 62,237, 15,114,
+ 63, 9,150,113, 62,243,235,101, 63, 19, 29,252, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,237,111,222, 63, 28,140,143, 62,230,102,129, 63, 37,200, 48, 62,223, 93, 22, 63, 28,140,145, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,223, 93, 22, 63, 28,140,145, 62,230,102,117, 63, 19, 98,220, 62,237,111,222,
+ 63, 28,140,143, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,243,235,101, 63, 19, 29,252,
+ 62,237,111,222, 63, 28,140,143, 62,230,102,117, 63, 19, 98,220, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62,230,102,117, 63, 19, 98,220, 62,223, 93, 22, 63, 28,140,145, 62,216,225,128, 63, 19, 29,254, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,223,189,103, 63, 9,150,112, 62,216,225,128, 63, 19, 29,254,
+ 62,210,195, 85, 63, 9,152, 96, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,210,195, 85,
+ 63, 9,152, 96, 62,217,153,154, 62,255,252, 24, 62,223,189,103, 63, 9,150,112, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,230,102,101, 63, 0, 0, 0, 62,223,189,103, 63, 9,150,112, 62,217,153,154, 62,255,252, 24,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,217,153,154, 62,255,252, 24, 62,210,195, 85,
+ 63, 9,152, 96, 62,204,204,202, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 34,187, 97, 62,187,220, 72, 63, 31,122,178, 62,210, 92, 55, 63, 28,138,186, 62,189,208,155, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 28,138,186, 62,189,208,155, 63, 31,199,185, 62,166,190, 96, 63, 34,187, 97,
+ 62,187,220, 72, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 38,102,107, 62,165,199,201,
+ 63, 34,187, 97, 62,187,220, 72, 63, 31,199,185, 62,166,190, 96, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 31,199,185, 62,166,190, 96, 63, 28,138,186, 62,189,208,155, 63, 25, 68,150, 62,169,150, 54, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 22, 60,123, 62,193,135, 36, 63, 25, 68,150, 62,169,150, 54,
+ 63, 28,138,186, 62,189,208,155, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 28,138,186,
+ 62,189,208,155, 63, 25,124,133, 62,213,159,181, 63, 22, 60,123, 62,193,135, 36, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 19,143, 64, 62,217,196, 4, 63, 22, 60,123, 62,193,135, 36, 63, 25,124,133, 62,213,159,181,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 25,124,133, 62,213,159,181, 63, 28,138,186,
+ 62,189,208,155, 63, 31,122,178, 62,210, 92, 55, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 28,124, 14, 62,233, 32,218, 63, 25,153,155, 63, 0, 0, 0, 63, 22,158, 86, 62,236,207, 65, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 22,158, 86, 62,236,207, 65, 63, 25,124,133, 62,213,159,181, 63, 28,124, 14,
+ 62,233, 32,218, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 31,122,178, 62,210, 92, 55,
+ 63, 28,124, 14, 62,233, 32,218, 63, 25,124,133, 62,213,159,181, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 25,124,133, 62,213,159,181, 63, 22,158, 86, 62,236,207, 65, 63, 19,143, 64, 62,217,196, 4, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 22, 60,123, 62,193,135, 36, 63, 19,143, 64, 62,217,196, 4,
+ 63, 16, 81,117, 62,198,230,223, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 16, 81,117,
+ 62,198,230,223, 63, 18,234, 7, 62,174, 54, 65, 63, 22, 60,123, 62,193,135, 36, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 25, 68,150, 62,169,150, 54, 63, 22, 60,123, 62,193,135, 36, 63, 18,234, 7, 62,174, 54, 65,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 18,234, 7, 62,174, 54, 65, 63, 16, 81,117,
+ 62,198,230,223, 63, 12,204,191, 62,180,111,160, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 28,124, 14, 62,233, 32,218, 63, 31,122,178, 62,210, 92, 55, 63, 35, 3, 17, 62,233, 23, 58, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 35, 3, 17, 62,233, 23, 58, 63, 32, 0, 2, 62,255,252, 24, 63, 28,124, 14,
+ 62,233, 32,218, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 25,153,155, 63, 0, 0, 0,
+ 63, 28,124, 14, 62,233, 32,218, 63, 32, 0, 2, 62,255,252, 24, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 32, 0, 2, 62,255,252, 24, 63, 35, 3, 17, 62,233, 23, 58, 63, 38,102,109, 63, 0, 0, 0, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 41,201,200, 62,233, 23, 58, 63, 38,102,109, 63, 0, 0, 0,
+ 63, 35, 3, 17, 62,233, 23, 58, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 35, 3, 17,
+ 62,233, 23, 58, 63, 38,102,109, 62,209,190,143, 63, 41,201,200, 62,233, 23, 58, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 45, 82, 38, 62,210, 92, 55, 63, 41,201,200, 62,233, 23, 58, 63, 38,102,109, 62,209,190,143,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 38,102,109, 62,209,190,143, 63, 35, 3, 17,
+ 62,233, 23, 58, 63, 31,122,178, 62,210, 92, 55, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 34,187, 97, 62,187,220, 72, 63, 38,102,107, 62,165,199,201, 63, 42, 17,118, 62,187,220, 72, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 42, 17,118, 62,187,220, 72, 63, 38,102,109, 62,209,190,143, 63, 34,187, 97,
+ 62,187,220, 72, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 31,122,178, 62,210, 92, 55,
+ 63, 34,187, 97, 62,187,220, 72, 63, 38,102,109, 62,209,190,143, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 38,102,109, 62,209,190,143, 63, 42, 17,118, 62,187,220, 72, 63, 45, 82, 38, 62,210, 92, 55, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 41,201,200, 62,233, 23, 58, 63, 45, 82, 38, 62,210, 92, 55,
+ 63, 48, 80,204, 62,233, 32,218, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 48, 80,204,
+ 62,233, 32,218, 63, 44,204,215, 62,255,252, 23, 63, 41,201,200, 62,233, 23, 58, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 38,102,109, 63, 0, 0, 0, 63, 41,201,200, 62,233, 23, 58, 63, 44,204,215, 62,255,252, 23,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 44,204,215, 62,255,252, 23, 63, 48, 80,204,
+ 62,233, 32,218, 63, 51, 51, 63, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 60,123, 85, 62,198,230,253, 63, 57, 61,144, 62,217,196, 19, 63, 54,144, 86, 62,193,135, 68, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 54,144, 86, 62,193,135, 68, 63, 57,226,196, 62,174, 54,114, 63, 60,123, 85,
+ 62,198,230,253, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 64, 0, 0, 62,180,111,211,
+ 63, 60,123, 85, 62,198,230,253, 63, 57,226,196, 62,174, 54,114, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 57,226,196, 62,174, 54,114, 63, 54,144, 86, 62,193,135, 68, 63, 51,136, 58, 62,169,150, 90, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 48, 66, 27, 62,189,208,173, 63, 51,136, 58, 62,169,150, 90,
+ 63, 54,144, 86, 62,193,135, 68, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 54,144, 86,
+ 62,193,135, 68, 63, 51, 80, 80, 62,213,159,192, 63, 48, 66, 27, 62,189,208,173, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 45, 82, 38, 62,210, 92, 55, 63, 48, 66, 27, 62,189,208,173, 63, 51, 80, 80, 62,213,159,192,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 51, 80, 80, 62,213,159,192, 63, 54,144, 86,
+ 62,193,135, 68, 63, 57, 61,144, 62,217,196, 19, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 54, 46,128, 62,236,207, 75, 63, 51, 51, 63, 63, 0, 0, 0, 63, 48, 80,204, 62,233, 32,218, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 48, 80,204, 62,233, 32,218, 63, 51, 80, 80, 62,213,159,192, 63, 54, 46,128,
+ 62,236,207, 75, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 57, 61,144, 62,217,196, 19,
+ 63, 54, 46,128, 62,236,207, 75, 63, 51, 80, 80, 62,213,159,192, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 51, 80, 80, 62,213,159,192, 63, 48, 80,204, 62,233, 32,218, 63, 45, 82, 38, 62,210, 92, 55, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 48, 66, 27, 62,189,208,173, 63, 45, 82, 38, 62,210, 92, 55,
+ 63, 42, 17,118, 62,187,220, 72, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 42, 17,118,
+ 62,187,220, 72, 63, 45, 5, 26, 62,166,190,117, 63, 48, 66, 27, 62,189,208,173, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 51,136, 58, 62,169,150, 90, 63, 48, 66, 27, 62,189,208,173, 63, 45, 5, 26, 62,166,190,117,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 45, 5, 26, 62,166,190,117, 63, 42, 17,118,
+ 62,187,220, 72, 63, 38,102,107, 62,165,199,201, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 48, 55,255, 63, 9,152, 94, 63, 45, 40,237, 63, 19, 29,252, 63, 41,186,242, 63, 9,150,112, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 41,186,242, 63, 9,150,112, 63, 44,204,215, 62,255,252, 23, 63, 48, 55,255,
+ 63, 9,152, 94, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 51, 51, 63, 63, 0, 0, 0,
+ 63, 48, 55,255, 63, 9,152, 94, 63, 44,204,215, 62,255,252, 23, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 44,204,215, 62,255,252, 23, 63, 41,186,242, 63, 9,150,112, 63, 38,102,109, 63, 0, 0, 0, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 35, 17,235, 63, 9,150,112, 63, 38,102,109, 63, 0, 0, 0,
+ 63, 41,186,242, 63, 9,150,112, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 41,186,242,
+ 63, 9,150,112, 63, 38,102,113, 63, 19, 98,219, 63, 35, 17,235, 63, 9,150,112, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 31,163,245, 63, 19, 29,253, 63, 35, 17,235, 63, 9,150,112, 63, 38,102,113, 63, 19, 98,219,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 38,102,113, 63, 19, 98,219, 63, 41,186,242,
+ 63, 9,150,112, 63, 45, 40,237, 63, 19, 29,252, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 41,235, 38, 63, 28,140,141, 63, 38,102,117, 63, 37,200, 45, 63, 34,225,192, 63, 28,140,142, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 34,225,192, 63, 28,140,142, 63, 38,102,113, 63, 19, 98,219, 63, 41,235, 38,
+ 63, 28,140,141, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 45, 40,237, 63, 19, 29,252,
+ 63, 41,235, 38, 63, 28,140,141, 63, 38,102,113, 63, 19, 98,219, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 38,102,113, 63, 19, 98,219, 63, 34,225,192, 63, 28,140,142, 63, 31,163,245, 63, 19, 29,253, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 35, 17,235, 63, 9,150,112, 63, 31,163,245, 63, 19, 29,253,
+ 63, 28,148,223, 63, 9,152, 94, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 28,148,223,
+ 63, 9,152, 94, 63, 32, 0, 2, 62,255,252, 24, 63, 35, 17,235, 63, 9,150,112, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 38,102,109, 63, 0, 0, 0, 63, 35, 17,235, 63, 9,150,112, 63, 32, 0, 2, 62,255,252, 24,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 32, 0, 2, 62,255,252, 24, 63, 28,148,223,
+ 63, 9,152, 94, 63, 25,153,155, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63,107,129,188, 62,128, 45, 66, 63, 99, 71,235, 62,120, 76,222, 63,106, 37, 94, 62, 83, 97, 84, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,106, 37, 94, 62, 83, 97, 84, 63,115, 51, 65, 62, 97,151,248, 63,107,129,188,
+ 62,128, 45, 66, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,115, 51, 65, 62,135, 83,151,
+ 63,107,129,188, 62,128, 45, 66, 63,115, 51, 65, 62, 97,151,248, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63,115, 51, 65, 62, 97,151,248, 63,106, 37, 94, 62, 83, 97, 84, 63,115, 51, 65, 62, 52,111, 90, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,107,129,188, 62,128, 45, 66, 63,115, 51, 65, 62,135, 83,151,
+ 63,108,123,142, 62,151,144,169, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,108,123,142,
+ 62,151,144,169, 63,101, 50,231, 62,146,201, 17, 63,107,129,188, 62,128, 45, 66, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 99, 71,235, 62,120, 76,222, 63,107,129,188, 62,128, 45, 66, 63,101, 50,231, 62,146,201, 17,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,101, 50,231, 62,146,201, 17, 63,108,123,142,
+ 62,151,144,169, 63,102,187,106, 62,169,150, 54, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 96, 56, 71, 62,166,190, 99, 63, 89,153,149, 62,165,199,201, 63, 93,238, 22, 62,144,101,243, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 93,238, 22, 62,144,101,243, 63,101, 50,231, 62,146,201, 17, 63, 96, 56, 71,
+ 62,166,190, 99, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,102,187,106, 62,169,150, 54,
+ 63, 96, 56, 71, 62,166,190, 99, 63,101, 50,231, 62,146,201, 17, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63,101, 50,231, 62,146,201, 17, 63, 93,238, 22, 62,144,101,243, 63, 99, 71,235, 62,120, 76,222, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,109, 21,249, 62,174, 54, 65, 63,102,187,106, 62,169,150, 54,
+ 63,108,123,142, 62,151,144,169, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,108,123,142,
+ 62,151,144,169, 63,115, 51, 65, 62,157,231, 93, 63,109, 21,249, 62,174, 54, 65, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63,115, 51, 65, 62,180,111,160, 63,109, 21,249, 62,174, 54, 65, 63,115, 51, 65, 62,157,231, 93,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,115, 51, 65, 62,157,231, 93, 63,108,123,142,
+ 62,151,144,169, 63,115, 51, 65, 62,135, 83,151, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 89,153,149, 62,115,162, 79, 63, 99, 71,235, 62,120, 76,222, 63, 93,238, 22, 62,144,101,243, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 93,238, 22, 62,144,101,243, 63, 85, 69, 21, 62,144,102, 3, 63, 89,153,149,
+ 62,115,162, 79, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 79,235, 68, 62,120, 77, 37,
+ 63, 89,153,149, 62,115,162, 79, 63, 85, 69, 21, 62,144,102, 3, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 85, 69, 21, 62,144,102, 3, 63, 93,238, 22, 62,144,101,243, 63, 89,153,149, 62,165,199,201, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 89,153,149, 62,115,162, 79, 63, 79,235, 68, 62,120, 77, 37,
+ 63, 83,186, 24, 62, 70,176,245, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 83,186, 24,
+ 62, 70,176,245, 63, 95,121, 22, 62, 70,176,204, 63, 89,153,149, 62,115,162, 79, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 99, 71,235, 62,120, 76,222, 63, 89,153,149, 62,115,162, 79, 63, 95,121, 22, 62, 70,176,204,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 95,121, 22, 62, 70,176,204, 63, 83,186, 24,
+ 62, 70,176,245, 63, 89,153,152, 62, 23, 31,198, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63,103,119, 61, 62, 30,253,179, 63,115, 51, 65, 62, 52,111, 90, 63,106, 37, 94, 62, 83, 97, 84, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,106, 37, 94, 62, 83, 97, 84, 63, 95,121, 22, 62, 70,176,204, 63,103,119, 61,
+ 62, 30,253,179, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 89,153,152, 62, 23, 31,198,
+ 63,103,119, 61, 62, 30,253,179, 63, 95,121, 22, 62, 70,176,204, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 95,121, 22, 62, 70,176,204, 63,106, 37, 94, 62, 83, 97, 84, 63, 99, 71,235, 62,120, 76,222, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 75,187,248, 62, 30,253,241, 63, 89,153,152, 62, 23, 31,198,
+ 63, 83,186, 24, 62, 70,176,245, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 83,186, 24,
+ 62, 70,176,245, 63, 73, 13,214, 62, 83, 97,181, 63, 75,187,248, 62, 30,253,241, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 64, 0, 0, 62, 52,111,202, 63, 75,187,248, 62, 30,253,241, 63, 73, 13,214, 62, 83, 97,181,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 73, 13,214, 62, 83, 97,181, 63, 83,186, 24,
+ 62, 70,176,245, 63, 79,235, 68, 62,120, 77, 37, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 89,153,152, 61,147, 41,111, 63, 64, 0, 0, 61,180,111,195, 63, 64, 0, 0, 61, 52, 65,111, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 64, 0, 0, 61, 52, 65,111, 63,117, 49, 38, 61, 52, 64,225, 63, 89,153,152,
+ 61,147, 41,111, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,115, 51, 65, 61,180,111, 83,
+ 63, 89,153,152, 61,147, 41,111, 63,117, 49, 38, 61, 52, 64,225, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63,117, 49, 38, 61, 52, 64,225, 63, 64, 0, 0, 61, 52, 65,111, 63,121,222,208,178,239, 9,102, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 89,153,152, 61,147, 41,111, 63,115, 51, 65, 61,180,111, 83,
+ 63, 99, 51,172, 61,231, 46, 48, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 99, 51,172,
+ 61,231, 46, 48, 63, 79,255,135, 61,231, 46,120, 63, 89,153,152, 61,147, 41,111, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 64, 0, 0, 61,180,111,195, 63, 89,153,152, 61,147, 41,111, 63, 79,255,135, 61,231, 46,120,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 79,255,135, 61,231, 46,120, 63, 99, 51,172,
+ 61,231, 46, 48, 63, 89,153,152, 62, 23, 31,198, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 75,187,248, 62, 30,253,241, 63, 64, 0, 0, 62, 52,111,202, 63, 64, 0, 0, 62, 7, 71, 24, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 64, 0, 0, 62, 7, 71, 24, 63, 79,255,135, 61,231, 46,120, 63, 75,187,248,
+ 62, 30,253,241, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 89,153,152, 62, 23, 31,198,
+ 63, 75,187,248, 62, 30,253,241, 63, 79,255,135, 61,231, 46,120, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 79,255,135, 61,231, 46,120, 63, 64, 0, 0, 62, 7, 71, 24, 63, 64, 0, 0, 61,180,111,195, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,103,119, 61, 62, 30,253,179, 63, 89,153,152, 62, 23, 31,198,
+ 63, 99, 51,172, 61,231, 46, 48, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 99, 51,172,
+ 61,231, 46, 48, 63,115, 51, 66, 62, 7, 70,199, 63,103,119, 61, 62, 30,253,179, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63,115, 51, 65, 62, 52,111, 90, 63,103,119, 61, 62, 30,253,179, 63,115, 51, 66, 62, 7, 70,199,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,115, 51, 66, 62, 7, 70,199, 63, 99, 51,172,
+ 61,231, 46, 48, 63,115, 51, 65, 61,180,111, 83, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 71,177,122, 62,128, 45,120, 63, 64, 0, 0, 62,135, 83,218, 63, 64, 0, 0, 62, 97,152,115, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 64, 0, 0, 62, 97,152,115, 63, 73, 13,214, 62, 83, 97,181, 63, 71,177,122,
+ 62,128, 45,120, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 79,235, 68, 62,120, 77, 37,
+ 63, 71,177,122, 62,128, 45,120, 63, 73, 13,214, 62, 83, 97,181, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 73, 13,214, 62, 83, 97,181, 63, 64, 0, 0, 62, 97,152,115, 63, 64, 0, 0, 62, 52,111,202, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 71,177,122, 62,128, 45,120, 63, 79,235, 68, 62,120, 77, 37,
+ 63, 78, 0, 72, 62,146,201, 52, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 78, 0, 72,
+ 62,146,201, 52, 63, 70,183,169, 62,151,144,219, 63, 71,177,122, 62,128, 45,120, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 64, 0, 0, 62,135, 83,218, 63, 71,177,122, 62,128, 45,120, 63, 70,183,169, 62,151,144,219,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 70,183,169, 62,151,144,219, 63, 78, 0, 72,
+ 62,146,201, 52, 63, 76,119,198, 62,169,150, 90, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 70, 29, 61, 62,174, 54,114, 63, 64, 0, 0, 62,180,111,211, 63, 64, 0, 0, 62,157,231,162, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 64, 0, 0, 62,157,231,162, 63, 70,183,169, 62,151,144,219, 63, 70, 29, 61,
+ 62,174, 54,114, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 76,119,198, 62,169,150, 90,
+ 63, 70, 29, 61, 62,174, 54,114, 63, 70,183,169, 62,151,144,219, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 70,183,169, 62,151,144,219, 63, 64, 0, 0, 62,157,231,162, 63, 64, 0, 0, 62,135, 83,218, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 82,250,230, 62,166,190,117, 63, 76,119,198, 62,169,150, 90,
+ 63, 78, 0, 72, 62,146,201, 52, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 78, 0, 72,
+ 62,146,201, 52, 63, 85, 69, 21, 62,144,102, 3, 63, 82,250,230, 62,166,190,117, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 89,153,149, 62,165,199,201, 63, 82,250,230, 62,166,190,117, 63, 85, 69, 21, 62,144,102, 3,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 85, 69, 21, 62,144,102, 3, 63, 78, 0, 72,
+ 62,146,201, 52, 63, 79,235, 68, 62,120, 77, 37, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 61,245,167,179, 62,128, 45, 72, 61,179,217, 94, 62,120, 76,222, 61,234,196,202, 62, 83, 97,100, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,234,196,202, 62, 83, 97,100, 62, 25,153,212, 62, 97,152, 2, 61,245,167,179,
+ 62,128, 45, 72, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 25,153,214, 62,135, 83,156,
+ 61,245,167,179, 62,128, 45, 72, 62, 25,153,212, 62, 97,152, 2, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62, 25,153,212, 62, 97,152, 2, 61,234,196,202, 62, 83, 97,100, 62, 25,153,214, 62, 52,111,106, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,245,167,179, 62,128, 45, 72, 62, 25,153,214, 62,135, 83,156,
+ 61,253,118, 62, 62,151,144,174, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,253,118, 62,
+ 62,151,144,174, 61,195, 49, 53, 62,146,201, 17, 61,245,167,179, 62,128, 45, 72, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 61,179,217, 94, 62,120, 76,222, 61,245,167,179, 62,128, 45, 72, 61,195, 49, 53, 62,146,201, 17,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,195, 49, 53, 62,146,201, 17, 61,253,118, 62,
+ 62,151,144,174, 61,207,117, 70, 62,169,150, 54, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 61,155, 92, 79, 62,166,190, 91, 61, 76,205,194, 62,165,199,186, 61,137, 10,212, 62,144,101,238, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,137, 10,212, 62,144,101,238, 61,195, 49, 53, 62,146,201, 17, 61,155, 92, 79,
+ 62,166,190, 91, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,207,117, 70, 62,169,150, 54,
+ 61,155, 92, 79, 62,166,190, 91, 61,195, 49, 53, 62,146,201, 17, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 61,195, 49, 53, 62,146,201, 17, 61,137, 10,212, 62,144,101,238, 61,179,217, 94, 62,120, 76,222, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 1, 36,204, 62,174, 54, 70, 61,207,117, 70, 62,169,150, 54,
+ 61,253,118, 62, 62,151,144,174, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,253,118, 62,
+ 62,151,144,174, 62, 25,153,213, 62,157,231,100, 62, 1, 36,204, 62,174, 54, 70, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62, 25,153,214, 62,180,111,165, 62, 1, 36,204, 62,174, 54, 70, 62, 25,153,213, 62,157,231,100,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 25,153,213, 62,157,231,100, 61,253,118, 62,
+ 62,151,144,174, 62, 25,153,214, 62,135, 83,156, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 61, 76,205,188, 62,115,162, 53, 61,179,217, 94, 62,120, 76,222, 61,137, 10,212, 62,144,101,238, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,137, 10,212, 62,144,101,238, 61, 7,133,207, 62,144,101,236, 61, 76,205,188,
+ 62,115,162, 53, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 60, 71,162,255, 62,120, 76,216,
+ 61, 76,205,188, 62,115,162, 53, 61, 7,133,207, 62,144,101,236, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 61, 7,133,207, 62,144,101,236, 61,137, 10,212, 62,144,101,238, 61, 76,205,194, 62,165,199,186, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61, 76,205,188, 62,115,162, 53, 60, 71,162,255, 62,120, 76,216,
+ 60,221,171,190, 62, 70,176,194, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 60,221,171,190,
+ 62, 70,176,194, 61,149, 98,194, 62, 70,176,194, 61, 76,205,188, 62,115,162, 53, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 61,179,217, 94, 62,120, 76,222, 61, 76,205,188, 62,115,162, 53, 61,149, 98,194, 62, 70,176,194,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,149, 98,194, 62, 70,176,194, 60,221,171,190,
+ 62, 70,176,194, 61, 76,205,193, 62, 23, 31,168, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 61,213, 83,198, 62, 30,253,179, 62, 25,153,214, 62, 52,111,106, 61,234,196,202, 62, 83, 97,100, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,234,196,202, 62, 83, 97,100, 61,149, 98,194, 62, 70,176,194, 61,213, 83,198,
+ 62, 30,253,179, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61, 76,205,193, 62, 23, 31,168,
+ 61,213, 83,198, 62, 30,253,179, 61,149, 98,194, 62, 70,176,194, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 61,149, 98,194, 62, 70,176,194, 61,234,196,202, 62, 83, 97,100, 61,179,217, 94, 62,120, 76,222, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,126,239, 59, 62, 30,253,174, 63,131,105,154, 62, 23, 31,168,
+ 63,131,118,175, 62, 70,176,194, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,131,118,175,
+ 62, 70,176,194, 63,124, 65, 30, 62, 83, 97, 90, 63,126,239, 59, 62, 30,253,174, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63,115, 51, 65, 62, 52,111, 90, 63,126,239, 59, 62, 30,253,174, 63,124, 65, 30, 62, 83, 97, 90,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,124, 65, 30, 62, 83, 97, 90, 63,131,118,175,
+ 62, 70,176,194, 63,129,143, 70, 62,120, 76,216, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63,131,105,156, 61,147, 41,101, 63,115, 51, 65, 61,180,111, 83, 63,117, 49, 38, 61, 52, 64,225, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,117, 49, 38, 61, 52, 64,225, 63,135,148,232, 60,125,158,144, 63,131,105,156,
+ 61,147, 41,101, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 25,153,215, 61,180,111,104,
+ 61,128,245,122, 61,147, 41,101, 62, 25,153,224, 61, 52, 64,225, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63,135,148,232, 60,125,158,144, 63,117, 49, 38, 61, 52, 64,225, 63,121,222,208,178,239, 9,102, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,128,245,122, 61,147, 41,101, 62, 25,153,215, 61,180,111,104,
+ 61,179, 55, 89, 61,231, 46, 38, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,179, 55, 89,
+ 61,231, 46, 38, 60,208,147, 96, 61,231, 46, 48, 61,128,245,122, 61,147, 41,101, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63,115, 51, 65, 61,180,111, 83, 63,131,105,156, 61,147, 41,101, 63,129,153,102, 61,231, 46, 48,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 60,208,147, 96, 61,231, 46, 48, 61,179, 55, 89,
+ 61,231, 46, 38, 61, 76,205,193, 62, 23, 31,168, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63,126,239, 59, 62, 30,253,174, 63,115, 51, 65, 62, 52,111, 90, 63,115, 51, 66, 62, 7, 70,199, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,115, 51, 66, 62, 7, 70,199, 63,129,153,102, 61,231, 46, 48, 63,126,239, 59,
+ 62, 30,253,174, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,131,105,154, 62, 23, 31,168,
+ 63,126,239, 59, 62, 30,253,174, 63,129,153,102, 61,231, 46, 48, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63,129,153,102, 61,231, 46, 48, 63,115, 51, 66, 62, 7, 70,199, 63,115, 51, 65, 61,180,111, 83, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,213, 83,198, 62, 30,253,179, 61, 76,205,193, 62, 23, 31,168,
+ 61,179, 55, 89, 61,231, 46, 38, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61,179, 55, 89,
+ 61,231, 46, 38, 62, 25,153,217, 62, 7, 70,204, 61,213, 83,198, 62, 30,253,179, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62, 25,153,214, 62, 52,111,106, 61,213, 83,198, 62, 30,253,179, 62, 25,153,217, 62, 7, 70,204,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 25,153,217, 62, 7, 70,204, 61,179, 55, 89,
+ 61,231, 46, 38, 62, 25,153,215, 61,180,111,104, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63,122,228,192, 62,128, 45, 66, 63,115, 51, 65, 62,135, 83,151, 63,115, 51, 65, 62, 97,151,248, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,115, 51, 65, 62, 97,151,248, 63,124, 65, 30, 62, 83, 97, 90, 63,122,228,192,
+ 62,128, 45, 66, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,129,143, 70, 62,120, 76,216,
+ 63,122,228,192, 62,128, 45, 66, 63,124, 65, 30, 62, 83, 97, 90, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63,124, 65, 30, 62, 83, 97, 90, 63,115, 51, 65, 62, 97,151,248, 63,115, 51, 65, 62, 52,111, 90, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,122,228,192, 62,128, 45, 66, 63,129,143, 70, 62,120, 76,216,
+ 63,128,153,201, 62,146,201, 14, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,128,153,201,
+ 62,146,201, 14, 63,121,234,239, 62,151,144,169, 63,122,228,192, 62,128, 45, 66, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63,115, 51, 65, 62,135, 83,151, 63,122,228,192, 62,128, 45, 66, 63,121,234,239, 62,151,144,169,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,121,234,239, 62,151,144,169, 63,128,153,201,
+ 62,146,201, 14, 63,127,171, 15, 62,169,150, 52, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63,121, 80,133, 62,174, 54, 65, 63,115, 51, 65, 62,180,111,160, 63,115, 51, 65, 62,157,231, 93, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,115, 51, 65, 62,157,231, 93, 63,121,234,239, 62,151,144,169, 63,121, 80,133,
+ 62,174, 54, 65, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,127,171, 15, 62,169,150, 52,
+ 63,121, 80,133, 62,174, 54, 65, 63,121,234,239, 62,151,144,169, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63,121,234,239, 62,151,144,169, 63,115, 51, 65, 62,157,231, 93, 63,115, 51, 65, 62,135, 83,151, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63,131, 23, 23, 62,166,190, 89, 63,127,171, 15, 62,169,150, 52,
+ 63,128,153,201, 62,146,201, 14, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 59,153,200,136,
+ 62,146,201, 14, 61, 7,133,207, 62,144,101,236, 60,197,197,195, 62,166,190, 89, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 61, 76,205,194, 62,165,199,186, 60,197,197,195, 62,166,190, 89, 61, 7,133,207, 62,144,101,236,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 61, 7,133,207, 62,144,101,236, 59,153,200,136,
+ 62,146,201, 14, 60, 71,162,255, 62,120, 76,216, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,163,208, 32, 62,128, 45, 79, 62,147, 92,147, 62,120, 76,252, 62,161, 23,102, 62, 83, 97,115, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,161, 23,102, 62, 83, 97,115, 62,179, 51, 22, 62, 97,152, 2, 62,163,208, 32,
+ 62,128, 45, 79, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,179, 51, 21, 62,135, 83,156,
+ 62,163,208, 32, 62,128, 45, 79, 62,179, 51, 22, 62, 97,152, 2, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62,179, 51, 22, 62, 97,152, 2, 62,161, 23,102, 62, 83, 97,115, 62,179, 51, 21, 62, 52,111,101, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,163,208, 32, 62,128, 45, 79, 62,179, 51, 21, 62,135, 83,156,
+ 62,165,195,194, 62,151,144,181, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,165,195,194,
+ 62,151,144,181, 62,151, 50,134, 62,146,201, 29, 62,163,208, 32, 62,128, 45, 79, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,147, 92,147, 62,120, 76,252, 62,163,208, 32, 62,128, 45, 79, 62,151, 50,134, 62,146,201, 29,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,151, 50,134, 62,146,201, 29, 62,165,195,194,
+ 62,151,144,181, 62,154, 67,137, 62,169,150, 70, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,141, 61, 82, 62,166,190,112, 62,128, 0, 0, 62,165,199,206, 62,136,168,247, 62,144,102, 3, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,136,168,247, 62,144,102, 3, 62,151, 50,134, 62,146,201, 29, 62,141, 61, 82,
+ 62,166,190,112, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,154, 67,137, 62,169,150, 70,
+ 62,141, 61, 82, 62,166,190,112, 62,151, 50,134, 62,146,201, 29, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62,151, 50,134, 62,146,201, 29, 62,136,168,247, 62,144,102, 3, 62,147, 92,147, 62,120, 76,252, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,166,248,150, 62,174, 54, 78, 62,154, 67,137, 62,169,150, 70,
+ 62,165,195,194, 62,151,144,181, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,165,195,194,
+ 62,151,144,181, 62,179, 51, 21, 62,157,231, 98, 62,166,248,150, 62,174, 54, 78, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,179, 51, 21, 62,180,111,165, 62,166,248,150, 62,174, 54, 78, 62,179, 51, 21, 62,157,231, 98,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,179, 51, 21, 62,157,231, 98, 62,165,195,194,
+ 62,151,144,181, 62,179, 51, 21, 62,135, 83,156, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,128, 0, 0, 62,115,162, 89, 62,147, 92,147, 62,120, 76,252, 62,136,168,247, 62,144,102, 3, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,136,168,247, 62,144,102, 3, 62,110,174, 18, 62,144,102, 3, 62,128, 0, 0,
+ 62,115,162, 89, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 89, 70,217, 62,120, 76,252,
+ 62,128, 0, 0, 62,115,162, 89, 62,110,174, 18, 62,144,102, 3, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62,110,174, 18, 62,144,102, 3, 62,136,168,247, 62,144,102, 3, 62,128, 0, 0, 62,165,199,206, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,128, 0, 0, 62,115,162, 89, 62, 89, 70,217, 62,120, 76,252,
+ 62,104,130, 30, 62, 70,176,230, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,104,130, 30,
+ 62, 70,176,230, 62,139,190,241, 62, 70,176,230, 62,128, 0, 0, 62,115,162, 89, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,147, 92,147, 62,120, 76,252, 62,128, 0, 0, 62,115,162, 89, 62,139,190,241, 62, 70,176,230,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,139,190,241, 62, 70,176,230, 62,104,130, 30,
+ 62, 70,176,230, 62,128, 0, 0, 62, 23, 31,208, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,155,187, 41, 62, 30,253,205, 62,179, 51, 21, 62, 52,111,101, 62,161, 23,102, 62, 83, 97,115, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,161, 23,102, 62, 83, 97,115, 62,139,190,241, 62, 70,176,230, 62,155,187, 41,
+ 62, 30,253,205, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,128, 0, 0, 62, 23, 31,208,
+ 62,155,187, 41, 62, 30,253,205, 62,139,190,241, 62, 70,176,230, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62,139,190,241, 62, 70,176,230, 62,161, 23,102, 62, 83, 97,115, 62,147, 92,147, 62,120, 76,252, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 72,137,174, 62, 30,253,205, 62,128, 0, 0, 62, 23, 31,208,
+ 62,104,130, 30, 62, 70,176,230, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,104,130, 30,
+ 62, 70,176,230, 62, 61,209, 51, 62, 83, 97,115, 62, 72,137,174, 62, 30,253,205, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62, 25,153,214, 62, 52,111,106, 62, 72,137,174, 62, 30,253,205, 62, 61,209, 51, 62, 83, 97,115,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 61,209, 51, 62, 83, 97,115, 62,104,130, 30,
+ 62, 70,176,230, 62, 89, 70,217, 62,120, 76,252, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,127,255,255, 61,147, 41,141, 62, 25,153,215, 61,180,111,104, 62, 25,153,224, 61, 52, 64,225, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 25,153,224, 61, 52, 64,225, 62,179, 51, 15, 61, 52, 64,225, 62,127,255,255,
+ 61,147, 41,141, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,179, 51, 20, 61,180,111,104,
+ 62,127,255,255, 61,147, 41,141, 62,179, 51, 15, 61, 52, 64,225, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62,179, 51, 15, 61, 52, 64,225, 62, 25,153,224, 61, 52, 64,225, 62,161,175,144,178,239, 9,102, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,127,255,255, 61,147, 41,141, 62,179, 51, 20, 61,180,111,104,
+ 62,147, 52, 12, 61,231, 46,109, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,147, 52, 12,
+ 61,231, 46,109, 62, 89,151,231, 61,231, 46,109, 62,127,255,255, 61,147, 41,141, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62, 25,153,215, 61,180,111,104, 62,127,255,255, 61,147, 41,141, 62, 89,151,231, 61,231, 46,109,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 89,151,231, 61,231, 46,109, 62,147, 52, 12,
+ 61,231, 46,109, 62,128, 0, 0, 62, 23, 31,208, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62, 72,137,174, 62, 30,253,205, 62, 25,153,214, 62, 52,111,106, 62, 25,153,217, 62, 7, 70,204, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 25,153,217, 62, 7, 70,204, 62, 89,151,231, 61,231, 46,109, 62, 72,137,174,
+ 62, 30,253,205, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,128, 0, 0, 62, 23, 31,208,
+ 62, 72,137,174, 62, 30,253,205, 62, 89,151,231, 61,231, 46,109, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62, 89,151,231, 61,231, 46,109, 62, 25,153,217, 62, 7, 70,204, 62, 25,153,215, 61,180,111,104, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,155,187, 41, 62, 30,253,205, 62,128, 0, 0, 62, 23, 31,208,
+ 62,147, 52, 12, 61,231, 46,109, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,147, 52, 12,
+ 61,231, 46,109, 62,179, 51, 19, 62, 7, 70,204, 62,155,187, 41, 62, 30,253,205, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,179, 51, 21, 62, 52,111,101, 62,155,187, 41, 62, 30,253,205, 62,179, 51, 19, 62, 7, 70,204,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,179, 51, 19, 62, 7, 70,204, 62,147, 52, 12,
+ 61,231, 46,109, 62,179, 51, 20, 61,180,111,104, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62, 56, 95,192, 62,128, 45, 79, 62, 25,153,214, 62,135, 83,156, 62, 25,153,212, 62, 97,152, 2, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 25,153,212, 62, 97,152, 2, 62, 61,209, 51, 62, 83, 97,115, 62, 56, 95,192,
+ 62,128, 45, 79, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 89, 70,217, 62,120, 76,252,
+ 62, 56, 95,192, 62,128, 45, 79, 62, 61,209, 51, 62, 83, 97,115, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62, 61,209, 51, 62, 83, 97,115, 62, 25,153,212, 62, 97,152, 2, 62, 25,153,214, 62, 52,111,106, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 56, 95,192, 62,128, 45, 79, 62, 89, 70,217, 62,120, 76,252,
+ 62, 81,154,245, 62,146,201, 29, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 81,154,245,
+ 62,146,201, 29, 62, 52,120,125, 62,151,144,181, 62, 56, 95,192, 62,128, 45, 79, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62, 25,153,214, 62,135, 83,156, 62, 56, 95,192, 62,128, 45, 79, 62, 52,120,125, 62,151,144,181,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 52,120,125, 62,151,144,181, 62, 81,154,245,
+ 62,146,201, 29, 62, 75,120,239, 62,169,150, 70, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62, 50, 14,213, 62,174, 54, 78, 62, 25,153,214, 62,180,111,165, 62, 25,153,213, 62,157,231,100, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 25,153,213, 62,157,231,100, 62, 52,120,125, 62,151,144,181, 62, 50, 14,213,
+ 62,174, 54, 78, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 75,120,239, 62,169,150, 70,
+ 62, 50, 14,213, 62,174, 54, 78, 62, 52,120,125, 62,151,144,181, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62, 52,120,125, 62,151,144,181, 62, 25,153,213, 62,157,231,100, 62, 25,153,214, 62,135, 83,156, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,101,133, 91, 62,166,190,112, 62, 75,120,239, 62,169,150, 70,
+ 62, 81,154,245, 62,146,201, 29, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62, 81,154,245,
+ 62,146,201, 29, 62,110,174, 18, 62,144,102, 3, 62,101,133, 91, 62,166,190,112, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,128, 0, 0, 62,165,199,206, 62,101,133, 91, 62,166,190,112, 62,110,174, 18, 62,144,102, 3,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,110,174, 18, 62,144,102, 3, 62, 81,154,245,
+ 62,146,201, 29, 62, 89, 70,217, 62,120, 76,252, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 5, 27, 64, 62,128, 45, 66, 62,249,194,232, 62,120, 76,216, 63, 3,190,226, 62, 83, 97, 90, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 3,190,226, 62, 83, 97, 90, 63, 12,204,191, 62, 97,151,248, 63, 5, 27, 64,
+ 62,128, 45, 66, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 12,204,191, 62,135, 83,149,
+ 63, 5, 27, 64, 62,128, 45, 66, 63, 12,204,191, 62, 97,151,248, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 12,204,191, 62, 97,151,248, 63, 3,190,226, 62, 83, 97, 90, 63, 12,204,191, 62, 52,111, 90, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 5, 27, 64, 62,128, 45, 66, 63, 12,204,191, 62,135, 83,149,
+ 63, 6, 21, 17, 62,151,144,169, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 6, 21, 17,
+ 62,151,144,169, 62,253,152,222, 62,146,201, 14, 63, 5, 27, 64, 62,128, 45, 66, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,249,194,232, 62,120, 76,216, 63, 5, 27, 64, 62,128, 45, 66, 62,253,152,222, 62,146,201, 14,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,253,152,222, 62,146,201, 14, 63, 6, 21, 17,
+ 62,151,144,169, 63, 0, 84,241, 62,169,150, 52, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,243,163,164, 62,166,190, 89, 62,230,102, 72, 62,165,199,183, 62,239, 15, 70, 62,144,101,233, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,239, 15, 70, 62,144,101,233, 62,253,152,222, 62,146,201, 14, 62,243,163,164,
+ 62,166,190, 89, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 0, 84,241, 62,169,150, 52,
+ 62,243,163,164, 62,166,190, 89, 62,253,152,222, 62,146,201, 14, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62,253,152,222, 62,146,201, 14, 62,239, 15, 70, 62,144,101,233, 62,249,194,232, 62,120, 76,216, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 6,175,123, 62,174, 54, 65, 63, 0, 84,241, 62,169,150, 52,
+ 63, 6, 21, 17, 62,151,144,169, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 6, 21, 17,
+ 62,151,144,169, 63, 12,204,191, 62,157,231, 90, 63, 6,175,123, 62,174, 54, 65, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 12,204,191, 62,180,111,160, 63, 6,175,123, 62,174, 54, 65, 63, 12,204,191, 62,157,231, 90,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 12,204,191, 62,157,231, 90, 63, 6, 21, 17,
+ 62,151,144,169, 63, 12,204,191, 62,135, 83,149, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,230,102, 72, 62,115,162, 53, 62,249,194,232, 62,120, 76,216, 62,239, 15, 70, 62,144,101,233, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,239, 15, 70, 62,144,101,233, 62,221,189, 75, 62,144,101,238, 62,230,102, 72,
+ 62,115,162, 53, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,211, 9,168, 62,120, 76,222,
+ 62,230,102, 72, 62,115,162, 53, 62,221,189, 75, 62,144,101,238, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62,221,189, 75, 62,144,101,238, 62,239, 15, 70, 62,144,101,233, 62,230,102, 72, 62,165,199,183, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,230,102, 72, 62,115,162, 53, 62,211, 9,168, 62,120, 76,222,
+ 62,218,167, 80, 62, 70,176,194, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,218,167, 80,
+ 62, 70,176,194, 62,242, 37, 68, 62, 70,176,194, 62,230,102, 72, 62,115,162, 53, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,249,194,232, 62,120, 76,216, 62,230,102, 72, 62,115,162, 53, 62,242, 37, 68, 62, 70,176,194,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,242, 37, 68, 62, 70,176,194, 62,218,167, 80,
+ 62, 70,176,194, 62,230,102, 72, 62, 23, 31,168, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 1, 16,197, 62, 30,253,174, 63, 12,204,191, 62, 52,111, 90, 63, 3,190,226, 62, 83, 97, 90, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 3,190,226, 62, 83, 97, 90, 62,242, 37, 68, 62, 70,176,194, 63, 1, 16,197,
+ 62, 30,253,174, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,230,102, 72, 62, 23, 31,168,
+ 63, 1, 16,197, 62, 30,253,174, 62,242, 37, 68, 62, 70,176,194, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62,242, 37, 68, 62, 70,176,194, 63, 3,190,226, 62, 83, 97, 90, 62,249,194,232, 62,120, 76,216, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,202,171, 14, 62, 30,253,179, 62,230,102, 72, 62, 23, 31,168,
+ 62,218,167, 80, 62, 70,176,194, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,218,167, 80,
+ 62, 70,176,194, 62,197, 78,205, 62, 83, 97, 95, 62,202,171, 14, 62, 30,253,179, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,179, 51, 21, 62, 52,111,101, 62,202,171, 14, 62, 30,253,179, 62,197, 78,205, 62, 83, 97, 95,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,197, 78,205, 62, 83, 97, 95, 62,218,167, 80,
+ 62, 70,176,194, 62,211, 9,168, 62,120, 76,222, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,230,102, 63, 61,147, 41,101, 62,179, 51, 20, 61,180,111,104, 62,179, 51, 15, 61, 52, 64,225, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,179, 51, 15, 61, 52, 64,225, 63, 12,204,189, 61, 52, 64,225, 62,230,102, 63,
+ 61,147, 41,101, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 12,204,191, 61,180,111, 83,
+ 62,230,102, 63, 61,147, 41,101, 63, 12,204,189, 61, 52, 64,225, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 12,204,189, 61, 52, 64,225, 62,179, 51, 15, 61, 52, 64,225, 62,161,175,144,178,239, 9,102, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,230,102, 63, 61,147, 41,101, 63, 12,204,191, 61,180,111, 83,
+ 62,249,154,104, 61,231, 46, 48, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,249,154,104,
+ 61,231, 46, 48, 62,211, 50, 42, 61,231, 46, 48, 62,230,102, 63, 61,147, 41,101, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,179, 51, 20, 61,180,111,104, 62,230,102, 63, 61,147, 41,101, 62,211, 50, 42, 61,231, 46, 48,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,211, 50, 42, 61,231, 46, 48, 62,249,154,104,
+ 61,231, 46, 48, 62,230,102, 72, 62, 23, 31,168, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,202,171, 14, 62, 30,253,179, 62,179, 51, 21, 62, 52,111,101, 62,179, 51, 19, 62, 7, 70,204, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,179, 51, 19, 62, 7, 70,204, 62,211, 50, 42, 61,231, 46, 48, 62,202,171, 14,
+ 62, 30,253,179, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,230,102, 72, 62, 23, 31,168,
+ 62,202,171, 14, 62, 30,253,179, 62,211, 50, 42, 61,231, 46, 48, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62,211, 50, 42, 61,231, 46, 48, 62,179, 51, 19, 62, 7, 70,204, 62,179, 51, 20, 61,180,111,104, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 1, 16,197, 62, 30,253,174, 62,230,102, 72, 62, 23, 31,168,
+ 62,249,154,104, 61,231, 46, 48, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,249,154,104,
+ 61,231, 46, 48, 63, 12,204,191, 62, 7, 70,199, 63, 1, 16,197, 62, 30,253,174, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 12,204,191, 62, 52,111, 90, 63, 1, 16,197, 62, 30,253,174, 63, 12,204,191, 62, 7, 70,199,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 12,204,191, 62, 7, 70,199, 62,249,154,104,
+ 61,231, 46, 48, 63, 12,204,191, 61,180,111, 83, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,194,150, 19, 62,128, 45, 72, 62,179, 51, 21, 62,135, 83,156, 62,179, 51, 22, 62, 97,152, 2, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,179, 51, 22, 62, 97,152, 2, 62,197, 78,205, 62, 83, 97, 95, 62,194,150, 19,
+ 62,128, 45, 72, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,211, 9,168, 62,120, 76,222,
+ 62,194,150, 19, 62,128, 45, 72, 62,197, 78,205, 62, 83, 97, 95, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62,197, 78,205, 62, 83, 97, 95, 62,179, 51, 22, 62, 97,152, 2, 62,179, 51, 21, 62, 52,111,101, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,194,150, 19, 62,128, 45, 72, 62,211, 9,168, 62,120, 76,222,
+ 62,207, 51,179, 62,146,201, 17, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,207, 51,179,
+ 62,146,201, 17, 62,192,162,113, 62,151,144,174, 62,194,150, 19, 62,128, 45, 72, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,179, 51, 21, 62,135, 83,156, 62,194,150, 19, 62,128, 45, 72, 62,192,162,113, 62,151,144,174,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,192,162,113, 62,151,144,174, 62,207, 51,179,
+ 62,146,201, 17, 62,204, 34,175, 62,169,150, 54, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 62,191,109,154, 62,174, 54, 68, 62,179, 51, 21, 62,180,111,165, 62,179, 51, 21, 62,157,231, 98, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,179, 51, 21, 62,157,231, 98, 62,192,162,113, 62,151,144,174, 62,191,109,154,
+ 62,174, 54, 68, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,204, 34,175, 62,169,150, 54,
+ 62,191,109,154, 62,174, 54, 68, 62,192,162,113, 62,151,144,174, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 62,192,162,113, 62,151,144,174, 62,179, 51, 21, 62,157,231, 98, 62,179, 51, 21, 62,135, 83,156, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,217, 40,237, 62,166,190, 91, 62,204, 34,175, 62,169,150, 54,
+ 62,207, 51,179, 62,146,201, 17, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,207, 51,179,
+ 62,146,201, 17, 62,221,189, 75, 62,144,101,238, 62,217, 40,237, 62,166,190, 91, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 62,230,102, 72, 62,165,199,183, 62,217, 40,237, 62,166,190, 91, 62,221,189, 75, 62,144,101,238,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 62,221,189, 75, 62,144,101,238, 62,207, 51,179,
+ 62,146,201, 17, 62,211, 9,168, 62,120, 76,222, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 56, 78,134, 62,128, 45,117, 63, 48, 20,188, 62,120, 77, 37, 63, 54,242, 42, 62, 83, 97,181, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 54,242, 42, 62, 83, 97,181, 63, 64, 0, 0, 62, 97,152,115, 63, 56, 78,134,
+ 62,128, 45,117, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 64, 0, 0, 62,135, 83,218,
+ 63, 56, 78,134, 62,128, 45,117, 63, 64, 0, 0, 62, 97,152,115, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 64, 0, 0, 62, 97,152,115, 63, 54,242, 42, 62, 83, 97,181, 63, 64, 0, 0, 62, 52,111,202, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 56, 78,134, 62,128, 45,117, 63, 64, 0, 0, 62,135, 83,218,
+ 63, 57, 72, 87, 62,151,144,219, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 57, 72, 87,
+ 62,151,144,219, 63, 49,255,184, 62,146,201, 52, 63, 56, 78,134, 62,128, 45,117, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 48, 20,188, 62,120, 77, 37, 63, 56, 78,134, 62,128, 45,117, 63, 49,255,184, 62,146,201, 52,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 49,255,184, 62,146,201, 52, 63, 57, 72, 87,
+ 62,151,144,219, 63, 51,136, 58, 62,169,150, 90, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 45, 5, 26, 62,166,190,117, 63, 38,102,107, 62,165,199,201, 63, 42,186,235, 62,144,102, 5, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 42,186,235, 62,144,102, 5, 63, 49,255,184, 62,146,201, 52, 63, 45, 5, 26,
+ 62,166,190,117, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 51,136, 58, 62,169,150, 90,
+ 63, 45, 5, 26, 62,166,190,117, 63, 49,255,184, 62,146,201, 52, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 49,255,184, 62,146,201, 52, 63, 42,186,235, 62,144,102, 5, 63, 48, 20,188, 62,120, 77, 37, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 57,226,196, 62,174, 54,114, 63, 51,136, 58, 62,169,150, 90,
+ 63, 57, 72, 87, 62,151,144,219, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 57, 72, 87,
+ 62,151,144,219, 63, 64, 0, 0, 62,157,231,162, 63, 57,226,196, 62,174, 54,114, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 64, 0, 0, 62,180,111,211, 63, 57,226,196, 62,174, 54,114, 63, 64, 0, 0, 62,157,231,162,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 64, 0, 0, 62,157,231,162, 63, 57, 72, 87,
+ 62,151,144,219, 63, 64, 0, 0, 62,135, 83,218, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 38,102,107, 62,115,162, 79, 63, 48, 20,188, 62,120, 77, 37, 63, 42,186,235, 62,144,102, 5, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 42,186,235, 62,144,102, 5, 63, 34, 17,234, 62,144,101,243, 63, 38,102,107,
+ 62,115,162, 79, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 28,184, 21, 62,120, 76,222,
+ 63, 38,102,107, 62,115,162, 79, 63, 34, 17,234, 62,144,101,243, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 34, 17,234, 62,144,101,243, 63, 42,186,235, 62,144,102, 5, 63, 38,102,107, 62,165,199,201, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 38,102,107, 62,115,162, 79, 63, 28,184, 21, 62,120, 76,222,
+ 63, 32,134,234, 62, 70,176,204, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 32,134,234,
+ 62, 70,176,204, 63, 44, 69,233, 62, 70,176,245, 63, 38,102,107, 62,115,162, 79, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 48, 20,188, 62,120, 77, 37, 63, 38,102,107, 62,115,162, 79, 63, 44, 69,233, 62, 70,176,245,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 44, 69,233, 62, 70,176,245, 63, 32,134,234,
+ 62, 70,176,204, 63, 38,102,104, 62, 23, 31,198, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 52, 68, 9, 62, 30,253,241, 63, 64, 0, 0, 62, 52,111,202, 63, 54,242, 42, 62, 83, 97,181, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 54,242, 42, 62, 83, 97,181, 63, 44, 69,233, 62, 70,176,245, 63, 52, 68, 9,
+ 62, 30,253,241, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 38,102,104, 62, 23, 31,198,
+ 63, 52, 68, 9, 62, 30,253,241, 63, 44, 69,233, 62, 70,176,245, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 44, 69,233, 62, 70,176,245, 63, 54,242, 42, 62, 83, 97,181, 63, 48, 20,188, 62,120, 77, 37, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 24,136,195, 62, 30,253,179, 63, 38,102,104, 62, 23, 31,198,
+ 63, 32,134,234, 62, 70,176,204, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 32,134,234,
+ 62, 70,176,204, 63, 21,218,162, 62, 83, 97, 84, 63, 24,136,195, 62, 30,253,179, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 12,204,191, 62, 52,111, 90, 63, 24,136,195, 62, 30,253,179, 63, 21,218,162, 62, 83, 97, 84,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 21,218,162, 62, 83, 97, 84, 63, 32,134,234,
+ 62, 70,176,204, 63, 28,184, 21, 62,120, 76,222, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 38,102,104, 61,147, 41,111, 63, 12,204,191, 61,180,111, 83, 63, 12,204,189, 61, 52, 64,225, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 12,204,189, 61, 52, 64,225, 63, 64, 0, 0, 61, 52, 65,111, 63, 38,102,104,
+ 61,147, 41,111, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 64, 0, 0, 61,180,111,195,
+ 63, 38,102,104, 61,147, 41,111, 63, 64, 0, 0, 61, 52, 65,111, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 64, 0, 0, 61, 52, 65,111, 63, 12,204,189, 61, 52, 64,225, 63,121,222,208,178,239, 9,102, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 38,102,104, 61,147, 41,111, 63, 64, 0, 0, 61,180,111,195,
+ 63, 48, 0,122, 61,231, 46,120, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 48, 0,122,
+ 61,231, 46,120, 63, 28,204, 85, 61,231, 46, 48, 63, 38,102,104, 61,147, 41,111, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 12,204,191, 61,180,111, 83, 63, 38,102,104, 61,147, 41,111, 63, 28,204, 85, 61,231, 46, 48,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 28,204, 85, 61,231, 46, 48, 63, 48, 0,122,
+ 61,231, 46,120, 63, 38,102,104, 62, 23, 31,198, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 24,136,195, 62, 30,253,179, 63, 12,204,191, 62, 52,111, 90, 63, 12,204,191, 62, 7, 70,199, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 12,204,191, 62, 7, 70,199, 63, 28,204, 85, 61,231, 46, 48, 63, 24,136,195,
+ 62, 30,253,179, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 38,102,104, 62, 23, 31,198,
+ 63, 24,136,195, 62, 30,253,179, 63, 28,204, 85, 61,231, 46, 48, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 28,204, 85, 61,231, 46, 48, 63, 12,204,191, 62, 7, 70,199, 63, 12,204,191, 61,180,111, 83, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 52, 68, 9, 62, 30,253,241, 63, 38,102,104, 62, 23, 31,198,
+ 63, 48, 0,122, 61,231, 46,120, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 48, 0,122,
+ 61,231, 46,120, 63, 64, 0, 0, 62, 7, 71, 24, 63, 52, 68, 9, 62, 30,253,241, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 64, 0, 0, 62, 52,111,202, 63, 52, 68, 9, 62, 30,253,241, 63, 64, 0, 0, 62, 7, 71, 24,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 64, 0, 0, 62, 7, 71, 24, 63, 48, 0,122,
+ 61,231, 46,120, 63, 64, 0, 0, 61,180,111,195, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 20,126, 68, 62,128, 45, 64, 63, 12,204,191, 62,135, 83,149, 63, 12,204,191, 62, 97,151,248, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 12,204,191, 62, 97,151,248, 63, 21,218,162, 62, 83, 97, 84, 63, 20,126, 68,
+ 62,128, 45, 64, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 28,184, 21, 62,120, 76,222,
+ 63, 20,126, 68, 62,128, 45, 64, 63, 21,218,162, 62, 83, 97, 84, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 21,218,162, 62, 83, 97, 84, 63, 12,204,191, 62, 97,151,248, 63, 12,204,191, 62, 52,111, 90, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 20,126, 68, 62,128, 45, 64, 63, 28,184, 21, 62,120, 76,222,
+ 63, 26,205, 25, 62,146,201, 14, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 26,205, 25,
+ 62,146,201, 14, 63, 19,132,114, 62,151,144,169, 63, 20,126, 68, 62,128, 45, 64, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 12,204,191, 62,135, 83,149, 63, 20,126, 68, 62,128, 45, 64, 63, 19,132,114, 62,151,144,169,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 19,132,114, 62,151,144,169, 63, 26,205, 25,
+ 62,146,201, 14, 63, 25, 68,150, 62,169,150, 54, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 63, 18,234, 7, 62,174, 54, 65, 63, 12,204,191, 62,180,111,160, 63, 12,204,191, 62,157,231, 90, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 12,204,191, 62,157,231, 90, 63, 19,132,114, 62,151,144,169, 63, 18,234, 7,
+ 62,174, 54, 65, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 25, 68,150, 62,169,150, 54,
+ 63, 18,234, 7, 62,174, 54, 65, 63, 19,132,114, 62,151,144,169, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 63, 19,132,114, 62,151,144,169, 63, 12,204,191, 62,157,231, 90, 63, 12,204,191, 62,135, 83,149, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 31,199,185, 62,166,190, 96, 63, 25, 68,150, 62,169,150, 54,
+ 63, 26,205, 25, 62,146,201, 14, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 26,205, 25,
+ 62,146,201, 14, 63, 34, 17,234, 62,144,101,243, 63, 31,199,185, 62,166,190, 96, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 63, 38,102,107, 62,165,199,201, 63, 31,199,185, 62,166,190, 96, 63, 34, 17,234, 62,144,101,243,
+ 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 63, 34, 17,234, 62,144,101,243, 63, 26,205, 25,
+ 62,146,201, 14, 63, 28,184, 21, 62,120, 76,222, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 68, 65, 84, 65, 0, 0, 80, 0, 8,109, 96, 32, 0, 0, 0, 57, 0, 0, 20, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 68, 65, 84, 65, 0, 1, 44, 0, 8,172, 96, 32,
+ 0, 0, 0, 51, 0, 0, 5, 0, 0, 0, 0, 0, 63,110,222,166, 63, 55,205, 9, 63,105,132,212, 63, 65,236,201, 63,103,153,218,
+ 63, 54,155,119, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,103,153,218, 63, 54,155,119, 63,108,148,118, 63, 44,160,211, 63,110,222,166, 63, 55,205, 9,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,115, 51, 36, 63, 45, 28, 36, 63,110,222,166, 63, 55,205, 9, 63,108,148,118, 63, 44,160,211, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,108,148,118, 63, 44,160,211, 63,103,153,218, 63, 54,155,119, 63,102, 17, 87, 63, 43, 52,229, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 96, 81, 56,
+ 63, 52, 55,170, 63,102, 17, 87, 63, 43, 52,229, 63,103,153,218, 63, 54,155,119, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,103,153,218, 63, 54,155,119,
+ 63, 97, 75, 9, 63, 63,233, 92, 63, 96, 81, 56, 63, 52, 55,170, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 89,153,138, 63, 60, 86, 49, 63, 96, 81, 56,
+ 63, 52, 55,170, 63, 97, 75, 9, 63, 63,233, 92, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 97, 75, 9, 63, 63,233, 92, 63,103,153,218, 63, 54,155,119,
+ 63,105,132,212, 63, 65,236,201, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 98,167,103, 63, 75, 39,168, 63, 89,153,138, 63, 82,228, 39, 63, 89,153,139,
+ 63, 71,153,255, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 89,153,139, 63, 71,153,255, 63, 97, 75, 9, 63, 63,233, 92, 63, 98,167,103, 63, 75, 39,168,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,105,132,212, 63, 65,236,201, 63, 98,167,103, 63, 75, 39,168, 63, 97, 75, 9, 63, 63,233, 92, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 97, 75, 9, 63, 63,233, 92, 63, 89,153,139, 63, 71,153,255, 63, 89,153,138, 63, 60, 86, 49, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 96, 81, 56,
+ 63, 52, 55,170, 63, 89,153,138, 63, 60, 86, 49, 63, 89,153,139, 63, 49, 12, 79, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 89,153,139, 63, 49, 12, 79,
+ 63, 95,182,205, 63, 40,228,222, 63, 96, 81, 56, 63, 52, 55,170, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,102, 17, 87, 63, 43, 52,229, 63, 96, 81, 56,
+ 63, 52, 55,170, 63, 95,182,205, 63, 40,228,222, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 95,182,205, 63, 40,228,222, 63, 89,153,139, 63, 49, 12, 79,
+ 63, 89,153,139, 63, 37,200, 45, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 98,167,103, 63, 75, 39,168, 63,105,132,212, 63, 65,236,201, 63,109, 83,168,
+ 63, 78, 83,207, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,109, 83,168, 63, 78, 83,207, 63,101, 85,135, 63, 88, 64,148, 63, 98,167,103, 63, 75, 39,168,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 89,153,138, 63, 82,228, 39, 63, 98,167,103, 63, 75, 39,168, 63,101, 85,135, 63, 88, 64,148, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,101, 85,135, 63, 88, 64,148, 63,109, 83,168, 63, 78, 83,207, 63,115, 51, 36, 63, 90, 56, 22, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,121, 18,162,
+ 63, 78, 83,207, 63,115, 51, 36, 63, 90, 56, 22, 63,109, 83,168, 63, 78, 83,207, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,109, 83,168, 63, 78, 83,207,
+ 63,115, 51, 36, 63, 67, 23,115, 63,121, 18,162, 63, 78, 83,207, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,124,225,116, 63, 65,236,202, 63,121, 18,162,
+ 63, 78, 83,207, 63,115, 51, 36, 63, 67, 23,115, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,115, 51, 36, 63, 67, 23,115, 63,109, 83,168, 63, 78, 83,207,
+ 63,105,132,212, 63, 65,236,201, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,110,222,166, 63, 55,205, 9, 63,115, 51, 36, 63, 45, 28, 36, 63,119,135,163,
+ 63, 55,205, 11, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,119,135,163, 63, 55,205, 11, 63,115, 51, 36, 63, 67, 23,115, 63,110,222,166, 63, 55,205, 9,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,105,132,212, 63, 65,236,201, 63,110,222,166, 63, 55,205, 9, 63,115, 51, 36, 63, 67, 23,115, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,115, 51, 36, 63, 67, 23,115, 63,119,135,163, 63, 55,205, 11, 63,124,225,116, 63, 65,236,202, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,121, 18,162,
+ 63, 78, 83,207, 63,124,225,116, 63, 65,236,202, 63,129,223,113, 63, 75, 39,170, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,129,223,113, 63, 75, 39,170,
+ 63,128,136, 98, 63, 88, 64,148, 63,121, 18,162, 63, 78, 83,207, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,115, 51, 36, 63, 90, 56, 22, 63,121, 18,162,
+ 63, 78, 83,207, 63,128,136, 98, 63, 88, 64,148, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 59,136, 98, 95, 63, 88, 64,148, 60,111,184,160, 63, 75, 39,170,
+ 61, 76,203,243, 63, 82,228, 41, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61, 76,203,243, 63, 49, 12, 82, 61, 76,203,246, 63, 60, 86, 53, 60,194,162, 31,
+ 63, 52, 55,172, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 60,194,162, 31, 63, 52, 55,172, 60,213,239,111, 63, 40,228,223, 61, 76,203,243, 63, 49, 12, 82,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 61, 76,203,246, 63, 37,200, 48, 61, 76,203,243, 63, 49, 12, 82, 60,213,239,111, 63, 40,228,223, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 60,213,239,111, 63, 40,228,223, 60,194,162, 31, 63, 52, 55,172, 58,169,226,120, 63, 43, 52,230, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,126,204,111,
+ 63, 54,155,121, 63,128, 42,121, 63, 43, 52,230, 63,131, 10,136, 63, 52, 55,172, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,131, 10,136, 63, 52, 55,172,
+ 63,130,141,160, 63, 63,233, 95, 63,126,204,111, 63, 54,155,121, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,124,225,116, 63, 65,236,202, 63,126,204,111,
+ 63, 54,155,121, 63,130,141,160, 63, 63,233, 95, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 60,163,104, 11, 63, 63,233, 95, 60,194,162, 31, 63, 52, 55,172,
+ 61, 76,203,246, 63, 60, 86, 53, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61, 76,203,244, 63, 71,154, 2, 61, 76,203,243, 63, 82,228, 41, 60,111,184,160,
+ 63, 75, 39,170, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 60,111,184,160, 63, 75, 39,170, 60,163,104, 11, 63, 63,233, 95, 61, 76,203,244, 63, 71,154, 2,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 61, 76,203,246, 63, 60, 86, 53, 61, 76,203,244, 63, 71,154, 2, 60,163,104, 11, 63, 63,233, 95, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,130,141,160, 63, 63,233, 95, 63,129,223,113, 63, 75, 39,170, 63,124,225,116, 63, 65,236,202, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,126,204,111,
+ 63, 54,155,121, 63,124,225,116, 63, 65,236,202, 63,119,135,163, 63, 55,205, 11, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,119,135,163, 63, 55,205, 11,
+ 63,121,209,210, 63, 44,160,212, 63,126,204,111, 63, 54,155,121, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 42,121, 63, 43, 52,230, 63,126,204,111,
+ 63, 54,155,121, 63,121,209,210, 63, 44,160,212, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,121,209,210, 63, 44,160,212, 63,119,135,163, 63, 55,205, 11,
+ 63,115, 51, 36, 63, 45, 28, 36, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,134,102, 95, 63, 94, 46, 79, 63,134,102, 95, 63,105,114, 22, 63,124,205, 52,
+ 63, 99, 26, 58, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,124,205, 52, 63, 99, 26, 58, 63,128,136, 98, 63, 88, 64,148, 63,134,102, 95, 63, 94, 46, 79,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 61, 76,203,243, 63, 82,228, 41, 61, 76,203,234, 63, 94, 46, 79, 59,136, 98, 95, 63, 88, 64,148, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,128,136, 98, 63, 88, 64,148, 63,124,205, 52, 63, 99, 26, 58, 63,115, 51, 36, 63, 90, 56, 22, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,105,153, 21,
+ 63, 99, 26, 58, 63,115, 51, 36, 63, 90, 56, 22, 63,124,205, 52, 63, 99, 26, 58, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,124,205, 52, 63, 99, 26, 58,
+ 63,115, 51, 32, 63,109,154,212, 63,105,153, 21, 63, 99, 26, 58, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 89,153,138, 63,105,114, 19, 63,105,153, 21,
+ 63, 99, 26, 58, 63,115, 51, 32, 63,109,154,212, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,115, 51, 32, 63,109,154,212, 63,124,205, 52, 63, 99, 26, 58,
+ 63,134,102, 95, 63,105,114, 22, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,134,102, 95, 63,116,187,242, 63, 59,153, 3, 63,128, 0, 0, 63, 89,153,136,
+ 63,116,187,242, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 89,153,136, 63,116,187,242, 63,115, 51, 32, 63,109,154,212, 63,134,102, 95, 63,116,187,242,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,134,102, 95, 63,105,114, 22, 63,134,102, 95, 63,116,187,242, 63,115, 51, 32, 63,109,154,212, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,115, 51, 32, 63,109,154,212, 63, 89,153,136, 63,116,187,242, 63, 89,153,138, 63,105,114, 19, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,105,153, 21,
+ 63, 99, 26, 58, 63, 89,153,138, 63,105,114, 19, 63, 89,153,138, 63, 94, 46, 77, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 89,153,138, 63, 94, 46, 77,
+ 63,101, 85,135, 63, 88, 64,148, 63,105,153, 21, 63, 99, 26, 58, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,115, 51, 36, 63, 90, 56, 22, 63,105,153, 21,
+ 63, 99, 26, 58, 63,101, 85,135, 63, 88, 64,148, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,101, 85,135, 63, 88, 64,148, 63, 89,153,138, 63, 94, 46, 77,
+ 63, 89,153,138, 63, 82,228, 39, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 75,153, 67, 63, 54,155,113, 63, 73,174, 74, 63, 65,236,193, 63, 68, 84,124,
+ 63, 55,204,255, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 68, 84,124, 63, 55,204,255, 63, 70,158,169, 63, 44,160,200, 63, 75,153, 67, 63, 54,155,113,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 77, 33,196, 63, 43, 52,221, 63, 75,153, 67, 63, 54,155,113, 63, 70,158,169, 63, 44,160,200, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 70,158,169, 63, 44,160,200, 63, 68, 84,124, 63, 55,204,255, 63, 64, 0, 0, 63, 45, 28, 24, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 75,153, 67,
+ 63, 54,155,113, 63, 77, 33,196, 63, 43, 52,221, 63, 82,225,225, 63, 52, 55,165, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 82,225,225, 63, 52, 55,165,
+ 63, 81,232, 16, 63, 63,233, 89, 63, 75,153, 67, 63, 54,155,113, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 73,174, 74, 63, 65,236,193, 63, 75,153, 67,
+ 63, 54,155,113, 63, 81,232, 16, 63, 63,233, 89, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 81,232, 16, 63, 63,233, 89, 63, 82,225,225, 63, 52, 55,165,
+ 63, 89,153,138, 63, 60, 86, 49, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 89,153,139, 63, 71,153,255, 63, 89,153,138, 63, 82,228, 39, 63, 80,139,179,
+ 63, 75, 39,164, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 80,139,179, 63, 75, 39,164, 63, 81,232, 16, 63, 63,233, 89, 63, 89,153,139, 63, 71,153,255,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 89,153,138, 63, 60, 86, 49, 63, 89,153,139, 63, 71,153,255, 63, 81,232, 16, 63, 63,233, 89, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 81,232, 16, 63, 63,233, 89, 63, 80,139,179, 63, 75, 39,164, 63, 73,174, 74, 63, 65,236,193, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 89,153,139,
+ 63, 49, 12, 79, 63, 89,153,138, 63, 60, 86, 49, 63, 82,225,225, 63, 52, 55,165, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 82,225,225, 63, 52, 55,165,
+ 63, 83,124, 75, 63, 40,228,217, 63, 89,153,139, 63, 49, 12, 79, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 89,153,139, 63, 37,200, 45, 63, 89,153,139,
+ 63, 49, 12, 79, 63, 83,124, 75, 63, 40,228,217, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 83,124, 75, 63, 40,228,217, 63, 82,225,225, 63, 52, 55,165,
+ 63, 77, 33,196, 63, 43, 52,221, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 69,223,120, 63, 78, 83,198, 63, 73,174, 74, 63, 65,236,193, 63, 80,139,179,
+ 63, 75, 39,164, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 80,139,179, 63, 75, 39,164, 63, 77,221,148, 63, 88, 64,140, 63, 69,223,120, 63, 78, 83,198,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 64, 0, 0, 63, 90, 56, 12, 63, 69,223,120, 63, 78, 83,198, 63, 77,221,148, 63, 88, 64,140, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 77,221,148, 63, 88, 64,140, 63, 80,139,179, 63, 75, 39,164, 63, 89,153,138, 63, 82,228, 39, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 69,223,120,
+ 63, 78, 83,198, 63, 64, 0, 0, 63, 90, 56, 12, 63, 58, 32,136, 63, 78, 83,198, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 58, 32,136, 63, 78, 83,198,
+ 63, 64, 0, 0, 63, 67, 23,106, 63, 69,223,120, 63, 78, 83,198, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 73,174, 74, 63, 65,236,193, 63, 69,223,120,
+ 63, 78, 83,198, 63, 64, 0, 0, 63, 67, 23,106, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 64, 0, 0, 63, 67, 23,106, 63, 58, 32,136, 63, 78, 83,198,
+ 63, 54, 81,182, 63, 65,236,193, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 59,171,132, 63, 55,204,255, 63, 64, 0, 0, 63, 45, 28, 24, 63, 68, 84,124,
+ 63, 55,204,255, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 68, 84,124, 63, 55,204,255, 63, 64, 0, 0, 63, 67, 23,106, 63, 59,171,132, 63, 55,204,255,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 54, 81,182, 63, 65,236,193, 63, 59,171,132, 63, 55,204,255, 63, 64, 0, 0, 63, 67, 23,106, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 64, 0, 0, 63, 67, 23,106, 63, 68, 84,124, 63, 55,204,255, 63, 73,174, 74, 63, 65,236,193, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 47,116, 77,
+ 63, 75, 39,164, 63, 54, 81,182, 63, 65,236,193, 63, 58, 32,136, 63, 78, 83,198, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 58, 32,136, 63, 78, 83,198,
+ 63, 50, 34,108, 63, 88, 64,140, 63, 47,116, 77, 63, 75, 39,164, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 38,102,118, 63, 82,228, 38, 63, 47,116, 77,
+ 63, 75, 39,164, 63, 50, 34,108, 63, 88, 64,140, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 50, 34,108, 63, 88, 64,140, 63, 58, 32,136, 63, 78, 83,198,
+ 63, 64, 0, 0, 63, 90, 56, 12, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 45, 30, 31, 63, 52, 55,165, 63, 38,102,117, 63, 60, 86, 50, 63, 38,102,117,
+ 63, 49, 12, 78, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 38,102,117, 63, 49, 12, 78, 63, 44,131,181, 63, 40,228,216, 63, 45, 30, 31, 63, 52, 55,165,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 50,222, 60, 63, 43, 52,221, 63, 45, 30, 31, 63, 52, 55,165, 63, 44,131,181, 63, 40,228,216, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 44,131,181, 63, 40,228,216, 63, 38,102,117, 63, 49, 12, 78, 63, 38,102,117, 63, 37,200, 45, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 45, 30, 31,
+ 63, 52, 55,165, 63, 50,222, 60, 63, 43, 52,221, 63, 52,102,189, 63, 54,155,113, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 52,102,189, 63, 54,155,113,
+ 63, 46, 23,240, 63, 63,233, 89, 63, 45, 30, 31, 63, 52, 55,165, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 38,102,117, 63, 60, 86, 50, 63, 45, 30, 31,
+ 63, 52, 55,165, 63, 46, 23,240, 63, 63,233, 89, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 46, 23,240, 63, 63,233, 89, 63, 52,102,189, 63, 54,155,113,
+ 63, 54, 81,182, 63, 65,236,193, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 47,116, 77, 63, 75, 39,164, 63, 38,102,118, 63, 82,228, 38, 63, 38,102,117,
+ 63, 71,153,255, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 38,102,117, 63, 71,153,255, 63, 46, 23,240, 63, 63,233, 89, 63, 47,116, 77, 63, 75, 39,164,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 54, 81,182, 63, 65,236,193, 63, 47,116, 77, 63, 75, 39,164, 63, 46, 23,240, 63, 63,233, 89, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 46, 23,240, 63, 63,233, 89, 63, 38,102,117, 63, 71,153,255, 63, 38,102,117, 63, 60, 86, 50, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 59,171,132,
+ 63, 55,204,255, 63, 54, 81,182, 63, 65,236,193, 63, 52,102,189, 63, 54,155,113, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 52,102,189, 63, 54,155,113,
+ 63, 57, 97, 87, 63, 44,160,200, 63, 59,171,132, 63, 55,204,255, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 64, 0, 0, 63, 45, 28, 24, 63, 59,171,132,
+ 63, 55,204,255, 63, 57, 97, 87, 63, 44,160,200, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 57, 97, 87, 63, 44,160,200, 63, 52,102,189, 63, 54,155,113,
+ 63, 50,222, 60, 63, 43, 52,221, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 54,101,250, 63, 99, 26, 51, 63, 38,102,118, 63,105,114, 19, 63, 38,102,118,
+ 63, 94, 46, 77, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 38,102,118, 63, 94, 46, 77, 63, 50, 34,108, 63, 88, 64,140, 63, 54,101,250, 63, 99, 26, 51,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 64, 0, 0, 63, 90, 56, 12, 63, 54,101,250, 63, 99, 26, 51, 63, 50, 34,108, 63, 88, 64,140, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 50, 34,108, 63, 88, 64,140, 63, 38,102,118, 63, 94, 46, 77, 63, 38,102,118, 63, 82,228, 38, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 54,101,250,
+ 63, 99, 26, 51, 63, 64, 0, 0, 63, 90, 56, 12, 63, 73,154, 6, 63, 99, 26, 51, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 73,154, 6, 63, 99, 26, 51,
+ 63, 64, 0, 0, 63,109,154,206, 63, 54,101,250, 63, 99, 26, 51, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 38,102,118, 63,105,114, 19, 63, 54,101,250,
+ 63, 99, 26, 51, 63, 64, 0, 0, 63,109,154,206, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 64, 0, 0, 63,109,154,206, 63, 73,154, 6, 63, 99, 26, 51,
+ 63, 89,153,138, 63,105,114, 19, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 89,153,136, 63,116,187,242, 63, 59,153, 3, 63,128, 0, 0, 63, 38,102,120,
+ 63,116,187,242, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 38,102,120, 63,116,187,242, 63, 64, 0, 0, 63,109,154,206, 63, 89,153,136, 63,116,187,242,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 89,153,138, 63,105,114, 19, 63, 89,153,136, 63,116,187,242, 63, 64, 0, 0, 63,109,154,206, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 64, 0, 0, 63,109,154,206, 63, 38,102,120, 63,116,187,242, 63, 38,102,118, 63,105,114, 19, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 89,153,138,
+ 63, 94, 46, 77, 63, 89,153,138, 63,105,114, 19, 63, 73,154, 6, 63, 99, 26, 51, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 73,154, 6, 63, 99, 26, 51,
+ 63, 77,221,148, 63, 88, 64,140, 63, 89,153,138, 63, 94, 46, 77, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 89,153,138, 63, 82,228, 39, 63, 89,153,138,
+ 63, 94, 46, 77, 63, 77,221,148, 63, 88, 64,140, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 77,221,148, 63, 88, 64,140, 63, 73,154, 6, 63, 99, 26, 51,
+ 63, 64, 0, 0, 63, 90, 56, 12, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 8, 71,167, 63, 55,205, 7, 61,229,192,170, 63, 65,236,200, 61,214,104,203,
+ 63, 54,155,120, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 61,214,104,203, 63, 54,155,120, 61,254, 61,201, 63, 44,160,207, 62, 8, 71,167, 63, 55,205, 7,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62, 25,153,173, 63, 45, 28, 27, 62, 8, 71,167, 63, 55,205, 7, 61,254, 61,201, 63, 44,160,207, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 61,254, 61,201, 63, 44,160,207, 61,214,104,203, 63, 54,155,120, 61,202, 36,175, 63, 43, 52,228, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,156, 35,145,
+ 63, 52, 55,172, 61,202, 36,175, 63, 43, 52,228, 61,214,104,203, 63, 54,155,120, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,214,104,203, 63, 54,155,120,
+ 61,163,242, 32, 63, 63,233, 96, 61,156, 35,145, 63, 52, 55,172, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61, 76,203,246, 63, 60, 86, 53, 61,156, 35,145,
+ 63, 52, 55,172, 61,163,242, 32, 63, 63,233, 96, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,163,242, 32, 63, 63,233, 96, 61,214,104,203, 63, 54,155,120,
+ 61,229,192,170, 63, 65,236,200, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,174,213, 17, 63, 75, 39,171, 61, 76,203,243, 63, 82,228, 41, 61, 76,203,244,
+ 63, 71,154, 2, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 61, 76,203,244, 63, 71,154, 2, 61,163,242, 32, 63, 63,233, 96, 61,174,213, 17, 63, 75, 39,171,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 61,229,192,170, 63, 65,236,200, 61,174,213, 17, 63, 75, 39,171, 61,163,242, 32, 63, 63,233, 96, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 61,163,242, 32, 63, 63,233, 96, 61, 76,203,244, 63, 71,154, 2, 61, 76,203,246, 63, 60, 86, 53, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,156, 35,145,
+ 63, 52, 55,172, 61, 76,203,246, 63, 60, 86, 53, 61, 76,203,243, 63, 49, 12, 82, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61, 76,203,243, 63, 49, 12, 82,
+ 61,151, 80, 53, 63, 40,228,223, 61,156, 35,145, 63, 52, 55,172, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,202, 36,175, 63, 43, 52,228, 61,156, 35,145,
+ 63, 52, 55,172, 61,151, 80, 53, 63, 40,228,223, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,151, 80, 53, 63, 40,228,223, 61, 76,203,243, 63, 49, 12, 82,
+ 61, 76,203,246, 63, 37,200, 48, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,174,213, 17, 63, 75, 39,171, 61,229,192,170, 63, 65,236,200, 62, 2, 27,169,
+ 63, 78, 83,204, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62, 2, 27,169, 63, 78, 83,204, 61,196, 70, 23, 63, 88, 64,147, 61,174,213, 17, 63, 75, 39,171,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 61, 76,203,243, 63, 82,228, 41, 61,174,213, 17, 63, 75, 39,171, 61,196, 70, 23, 63, 88, 64,147, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 61,196, 70, 23, 63, 88, 64,147, 62, 2, 27,169, 63, 78, 83,204, 62, 25,153,160, 63, 90, 56, 14, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 49, 23,162,
+ 63, 78, 83,195, 62, 25,153,160, 63, 90, 56, 14, 62, 2, 27,169, 63, 78, 83,204, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 2, 27,169, 63, 78, 83,204,
+ 62, 25,153,172, 63, 67, 23,108, 62, 49, 23,162, 63, 78, 83,195, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 64, 82,240, 63, 65,236,183, 62, 49, 23,162,
+ 63, 78, 83,195, 62, 25,153,172, 63, 67, 23,108, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 25,153,172, 63, 67, 23,108, 62, 2, 27,169, 63, 78, 83,204,
+ 61,229,192,170, 63, 65,236,200, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 8, 71,167, 63, 55,205, 7, 62, 25,153,173, 63, 45, 28, 27, 62, 42,235,173,
+ 63, 55,204,254, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62, 42,235,173, 63, 55,204,254, 62, 25,153,172, 63, 67, 23,108, 62, 8, 71,167, 63, 55,205, 7,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 61,229,192,170, 63, 65,236,200, 62, 8, 71,167, 63, 55,205, 7, 62, 25,153,172, 63, 67, 23,108, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62, 25,153,172, 63, 67, 23,108, 62, 42,235,173, 63, 55,204,254, 62, 64, 82,240, 63, 65,236,183, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 49, 23,162,
+ 63, 78, 83,195, 62, 64, 82,240, 63, 65,236,183, 62, 91,200,166, 63, 75, 39,147, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 91,200,166, 63, 75, 39,147,
+ 62, 81, 16, 34, 63, 88, 64,131, 62, 49, 23,162, 63, 78, 83,195, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 25,153,160, 63, 90, 56, 14, 62, 49, 23,162,
+ 63, 78, 83,195, 62, 81, 16, 34, 63, 88, 64,131, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 81, 16, 34, 63, 88, 64,131, 62, 91,200,166, 63, 75, 39,147,
+ 62,128, 0, 0, 63, 82,228, 13, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,128, 0, 0, 63, 49, 12, 47, 62,128, 0, 0, 63, 60, 86, 19, 62,101, 33, 92,
+ 63, 52, 55,146, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,101, 33, 92, 63, 52, 55,146, 62,103,139, 14, 63, 40,228,199, 62,128, 0, 0, 63, 49, 12, 47,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,128, 0, 0, 63, 37,200, 23, 62,128, 0, 0, 63, 49, 12, 47, 62,103,139, 14, 63, 40,228,199, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,103,139, 14, 63, 40,228,199, 62,101, 33, 92, 63, 52, 55,146, 62, 78, 32,230, 63, 43, 52,211, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 71,254,223,
+ 63, 54,155,102, 62, 78, 32,230, 63, 43, 52,211, 62,101, 33, 92, 63, 52, 55,146, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,101, 33, 92, 63, 52, 55,146,
+ 62, 97, 58, 23, 63, 63,233, 69, 62, 71,254,223, 63, 54,155,102, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 64, 82,240, 63, 65,236,183, 62, 71,254,223,
+ 63, 54,155,102, 62, 97, 58, 23, 63, 63,233, 69, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 97, 58, 23, 63, 63,233, 69, 62,101, 33, 92, 63, 52, 55,146,
+ 62,128, 0, 0, 63, 60, 86, 19, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,128, 0, 0, 63, 71,153,228, 62,128, 0, 0, 63, 82,228, 13, 62, 91,200,166,
+ 63, 75, 39,147, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62, 91,200,166, 63, 75, 39,147, 62, 97, 58, 23, 63, 63,233, 69, 62,128, 0, 0, 63, 71,153,228,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,128, 0, 0, 63, 60, 86, 19, 62,128, 0, 0, 63, 71,153,228, 62, 97, 58, 23, 63, 63,233, 69, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62, 97, 58, 23, 63, 63,233, 69, 62, 91,200,166, 63, 75, 39,147, 62, 64, 82,240, 63, 65,236,183, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 71,254,223,
+ 63, 54,155,102, 62, 64, 82,240, 63, 65,236,183, 62, 42,235,173, 63, 55,204,254, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 42,235,173, 63, 55,204,254,
+ 62, 52, 20,105, 63, 44,160,198, 62, 71,254,223, 63, 54,155,102, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 78, 32,230, 63, 43, 52,211, 62, 71,254,223,
+ 63, 54,155,102, 62, 52, 20,105, 63, 44,160,198, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 52, 20,105, 63, 44,160,198, 62, 42,235,173, 63, 55,204,254,
+ 62, 25,153,173, 63, 45, 28, 27, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,128, 0, 0, 63, 94, 46, 58, 62,128, 0, 0, 63,105,114, 8, 62, 64, 1,230,
+ 63, 99, 26, 49, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62, 64, 1,230, 63, 99, 26, 49, 62, 81, 16, 34, 63, 88, 64,131, 62,128, 0, 0, 63, 94, 46, 58,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,128, 0, 0, 63, 82,228, 13, 62,128, 0, 0, 63, 94, 46, 58, 62, 81, 16, 34, 63, 88, 64,131, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62, 81, 16, 34, 63, 88, 64,131, 62, 64, 1,230, 63, 99, 26, 49, 62, 25,153,160, 63, 90, 56, 14, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,230, 98,164,
+ 63, 99, 26, 58, 62, 25,153,160, 63, 90, 56, 14, 62, 64, 1,230, 63, 99, 26, 49, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 64, 1,230, 63, 99, 26, 49,
+ 62, 25,153,159, 63,109,154,210, 61,230, 98,164, 63, 99, 26, 58, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61, 76,203,237, 63,105,114, 22, 61,230, 98,164,
+ 63, 99, 26, 58, 62, 25,153,159, 63,109,154,210, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 25,153,159, 63,109,154,210, 62, 64, 1,230, 63, 99, 26, 49,
+ 62,128, 0, 0, 63,105,114, 8, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,128, 0, 0, 63,116,187,232, 63, 59,153, 3, 63,128, 0, 0, 63,134,102, 95,
+ 63,116,187,242, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 61, 76,203,210, 63,116,187,242, 62, 25,153,159, 63,109,154,210, 62,128, 0, 0, 63,116,187,232,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,128, 0, 0, 63,105,114, 8, 62,128, 0, 0, 63,116,187,232, 62, 25,153,159, 63,109,154,210, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62, 25,153,159, 63,109,154,210, 61, 76,203,210, 63,116,187,242, 61, 76,203,237, 63,105,114, 22, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,230, 98,164,
+ 63, 99, 26, 58, 61, 76,203,237, 63,105,114, 22, 61, 76,203,234, 63, 94, 46, 79, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61, 76,203,234, 63, 94, 46, 79,
+ 61,196, 70, 23, 63, 88, 64,147, 61,230, 98,164, 63, 99, 26, 58, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 25,153,160, 63, 90, 56, 14, 61,230, 98,164,
+ 63, 99, 26, 58, 61,196, 70, 23, 63, 88, 64,147, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,196, 70, 23, 63, 88, 64,147, 61, 76,203,234, 63, 94, 46, 79,
+ 61, 76,203,243, 63, 82,228, 41, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,170,138, 42, 63, 55,204,254, 62,159,214,136, 63, 65,236,183, 62,156, 0,145,
+ 63, 54,155,102, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,156, 0,145, 63, 54,155,102, 62,165,245,204, 63, 44,160,198, 62,170,138, 42, 63, 55,204,254,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,179, 51, 42, 63, 45, 28, 28, 62,170,138, 42, 63, 55,204,254, 62,165,245,204, 63, 44,160,198, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,165,245,204, 63, 44,160,198, 62,156, 0,145, 63, 54,155,102, 62,152,239,141, 63, 43, 52,211, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,141,111, 82,
+ 63, 52, 55,146, 62,152,239,141, 63, 43, 52,211, 62,156, 0,145, 63, 54,155,102, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,156, 0,145, 63, 54,155,102,
+ 62,143, 98,245, 63, 63,233, 68, 62,141,111, 82, 63, 52, 55,146, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,128, 0, 0, 63, 60, 86, 19, 62,141,111, 82,
+ 63, 52, 55,146, 62,143, 98,245, 63, 63,233, 68, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,143, 98,245, 63, 63,233, 68, 62,156, 0,145, 63, 54,155,102,
+ 62,159,214,136, 63, 65,236,183, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,146, 27,173, 63, 75, 39,147, 62,128, 0, 0, 63, 82,228, 13, 62,128, 0, 0,
+ 63, 71,153,228, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,128, 0, 0, 63, 71,153,228, 62,143, 98,245, 63, 63,233, 68, 62,146, 27,173, 63, 75, 39,147,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,159,214,136, 63, 65,236,183, 62,146, 27,173, 63, 75, 39,147, 62,143, 98,245, 63, 63,233, 68, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,143, 98,245, 63, 63,233, 68, 62,128, 0, 0, 63, 71,153,228, 62,128, 0, 0, 63, 60, 86, 19, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,141,111, 82,
+ 63, 52, 55,146, 62,128, 0, 0, 63, 60, 86, 19, 62,128, 0, 0, 63, 49, 12, 47, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,128, 0, 0, 63, 49, 12, 47,
+ 62,140, 58,121, 63, 40,228,199, 62,141,111, 82, 63, 52, 55,146, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,152,239,141, 63, 43, 52,211, 62,141,111, 82,
+ 63, 52, 55,146, 62,140, 58,121, 63, 40,228,199, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,140, 58,121, 63, 40,228,199, 62,128, 0, 0, 63, 49, 12, 47,
+ 62,128, 0, 0, 63, 37,200, 23, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,146, 27,173, 63, 75, 39,147, 62,159,214,136, 63, 65,236,183, 62,167,116, 47,
+ 63, 78, 83,195, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,167,116, 47, 63, 78, 83,195, 62,151,119,239, 63, 88, 64,131, 62,146, 27,173, 63, 75, 39,147,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,128, 0, 0, 63, 82,228, 13, 62,146, 27,173, 63, 75, 39,147, 62,151,119,239, 63, 88, 64,131, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,151,119,239, 63, 88, 64,131, 62,167,116, 47, 63, 78, 83,195, 62,179, 51, 49, 63, 90, 56, 14, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,190,242, 44,
+ 63, 78, 83,205, 62,179, 51, 49, 63, 90, 56, 14, 62,167,116, 47, 63, 78, 83,195, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,167,116, 47, 63, 78, 83,195,
+ 62,179, 51, 42, 63, 67, 23,108, 62,190,242, 44, 63, 78, 83,205, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,198,143,214, 63, 65,236,200, 62,190,242, 44,
+ 63, 78, 83,205, 62,179, 51, 42, 63, 67, 23,108, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,179, 51, 42, 63, 67, 23,108, 62,167,116, 47, 63, 78, 83,195,
+ 62,159,214,136, 63, 65,236,183, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,170,138, 42, 63, 55,204,254, 62,179, 51, 42, 63, 45, 28, 28, 62,187,220, 45,
+ 63, 55,205, 7, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,187,220, 45, 63, 55,205, 7, 62,179, 51, 42, 63, 67, 23,108, 62,170,138, 42, 63, 55,204,254,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,159,214,136, 63, 65,236,183, 62,170,138, 42, 63, 55,204,254, 62,179, 51, 42, 63, 67, 23,108, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,179, 51, 42, 63, 67, 23,108, 62,187,220, 45, 63, 55,205, 7, 62,198,143,214, 63, 65,236,200, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,190,242, 44,
+ 63, 78, 83,205, 62,198,143,214, 63, 65,236,200, 62,212, 74,188, 63, 75, 39,171, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,212, 74,188, 63, 75, 39,171,
+ 62,206,238,122, 63, 88, 64,147, 62,190,242, 44, 63, 78, 83,205, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,179, 51, 49, 63, 90, 56, 14, 62,190,242, 44,
+ 63, 78, 83,205, 62,206,238,122, 63, 88, 64,147, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,206,238,122, 63, 88, 64,147, 62,212, 74,188, 63, 75, 39,171,
+ 62,230,102,130, 63, 82,228, 41, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,230,102,130, 63, 49, 12, 82, 62,230,102,129, 63, 60, 86, 53, 62,216,247, 28,
+ 63, 52, 55,172, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,216,247, 28, 63, 52, 55,172, 62,218, 43,243, 63, 40,228,223, 62,230,102,130, 63, 49, 12, 82,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,230,102,129, 63, 37,200, 48, 62,230,102,130, 63, 49, 12, 82, 62,218, 43,243, 63, 40,228,223, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,218, 43,243, 63, 40,228,223, 62,216,247, 28, 63, 52, 55,172, 62,205,118,212, 63, 43, 52,228, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,202,101,206,
+ 63, 54,155,120, 62,205,118,212, 63, 43, 52,228, 62,216,247, 28, 63, 52, 55,172, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,216,247, 28, 63, 52, 55,172,
+ 62,215, 3,120, 63, 63,233, 95, 62,202,101,206, 63, 54,155,120, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,198,143,214, 63, 65,236,200, 62,202,101,206,
+ 63, 54,155,120, 62,215, 3,120, 63, 63,233, 95, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,215, 3,120, 63, 63,233, 95, 62,216,247, 28, 63, 52, 55,172,
+ 62,230,102,129, 63, 60, 86, 53, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,230,102,130, 63, 71,154, 1, 62,230,102,130, 63, 82,228, 41, 62,212, 74,188,
+ 63, 75, 39,171, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,212, 74,188, 63, 75, 39,171, 62,215, 3,120, 63, 63,233, 95, 62,230,102,130, 63, 71,154, 1,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,230,102,129, 63, 60, 86, 53, 62,230,102,130, 63, 71,154, 1, 62,215, 3,120, 63, 63,233, 95, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,215, 3,120, 63, 63,233, 95, 62,212, 74,188, 63, 75, 39,171, 62,198,143,214, 63, 65,236,200, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,202,101,206,
+ 63, 54,155,120, 62,198,143,214, 63, 65,236,200, 62,187,220, 45, 63, 55,205, 7, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,187,220, 45, 63, 55,205, 7,
+ 62,192,112,142, 63, 44,160,207, 62,202,101,206, 63, 54,155,120, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,205,118,212, 63, 43, 52,228, 62,202,101,206,
+ 63, 54,155,120, 62,192,112,142, 63, 44,160,207, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,192,112,142, 63, 44,160,207, 62,187,220, 45, 63, 55,205, 7,
+ 62,179, 51, 42, 63, 45, 28, 28, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,230,102,131, 63, 94, 46, 79, 62,230,102,131, 63,105,114, 22, 62,198,103, 87,
+ 63, 99, 26, 58, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,198,103, 87, 63, 99, 26, 58, 62,206,238,122, 63, 88, 64,147, 62,230,102,131, 63, 94, 46, 79,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,230,102,130, 63, 82,228, 41, 62,230,102,131, 63, 94, 46, 79, 62,206,238,122, 63, 88, 64,147, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,206,238,122, 63, 88, 64,147, 62,198,103, 87, 63, 99, 26, 58, 62,179, 51, 49, 63, 90, 56, 14, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,159,255, 14,
+ 63, 99, 26, 49, 62,179, 51, 49, 63, 90, 56, 14, 62,198,103, 87, 63, 99, 26, 58, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,198,103, 87, 63, 99, 26, 58,
+ 62,179, 51, 49, 63,109,154,210, 62,159,255, 14, 63, 99, 26, 49, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,128, 0, 0, 63,105,114, 8, 62,159,255, 14,
+ 63, 99, 26, 49, 62,179, 51, 49, 63,109,154,210, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,179, 51, 49, 63,109,154,210, 62,198,103, 87, 63, 99, 26, 58,
+ 62,230,102,131, 63,105,114, 22, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,230,102,134, 63,116,187,242, 63, 59,153, 3, 63,128, 0, 0, 62,128, 0, 0,
+ 63,116,187,232, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,128, 0, 0, 63,116,187,232, 62,179, 51, 49, 63,109,154,210, 62,230,102,134, 63,116,187,242,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,230,102,131, 63,105,114, 22, 62,230,102,134, 63,116,187,242, 62,179, 51, 49, 63,109,154,210, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,179, 51, 49, 63,109,154,210, 62,128, 0, 0, 63,116,187,232, 62,128, 0, 0, 63,105,114, 8, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,159,255, 14,
+ 63, 99, 26, 49, 62,128, 0, 0, 63,105,114, 8, 62,128, 0, 0, 63, 94, 46, 58, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,128, 0, 0, 63, 94, 46, 58,
+ 62,151,119,239, 63, 88, 64,131, 62,159,255, 14, 63, 99, 26, 49, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,179, 51, 49, 63, 90, 56, 14, 62,159,255, 14,
+ 63, 99, 26, 49, 62,151,119,239, 63, 88, 64,131, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,151,119,239, 63, 88, 64,131, 62,128, 0, 0, 63, 94, 46, 58,
+ 62,128, 0, 0, 63, 82,228, 13, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 8,120, 93, 63, 55,205, 11, 63, 3, 30,140, 63, 65,236,201, 63, 1, 51,145,
+ 63, 54,155,121, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 1, 51,145, 63, 54,155,121, 63, 6, 46, 46, 63, 44,160,211, 63, 8,120, 93, 63, 55,205, 11,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 12,204,220, 63, 45, 28, 35, 63, 8,120, 93, 63, 55,205, 11, 63, 6, 46, 46, 63, 44,160,211, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 6, 46, 46, 63, 44,160,211, 63, 1, 51,145, 63, 54,155,121, 62,255, 86, 30, 63, 43, 52,230, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,243,213,222,
+ 63, 52, 55,172, 62,255, 86, 30, 63, 43, 52,230, 63, 1, 51,145, 63, 54,155,121, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 1, 51,145, 63, 54,155,121,
+ 62,245,201,128, 63, 63,233, 94, 62,243,213,222, 63, 52, 55,172, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,230,102,129, 63, 60, 86, 53, 62,243,213,222,
+ 63, 52, 55,172, 62,245,201,128, 63, 63,233, 94, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,245,201,128, 63, 63,233, 94, 63, 1, 51,145, 63, 54,155,121,
+ 63, 3, 30,140, 63, 65,236,201, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,248,130, 59, 63, 75, 39,169, 62,230,102,130, 63, 82,228, 41, 62,230,102,130,
+ 63, 71,154, 1, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,230,102,130, 63, 71,154, 1, 62,245,201,128, 63, 63,233, 94, 62,248,130, 59, 63, 75, 39,169,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 3, 30,140, 63, 65,236,201, 62,248,130, 59, 63, 75, 39,169, 62,245,201,128, 63, 63,233, 94, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,245,201,128, 63, 63,233, 94, 62,230,102,130, 63, 71,154, 1, 62,230,102,129, 63, 60, 86, 53, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,243,213,222,
+ 63, 52, 55,172, 62,230,102,129, 63, 60, 86, 53, 62,230,102,130, 63, 49, 12, 82, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,230,102,130, 63, 49, 12, 82,
+ 62,242,161, 9, 63, 40,228,223, 62,243,213,222, 63, 52, 55,172, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,255, 86, 30, 63, 43, 52,230, 62,243,213,222,
+ 63, 52, 55,172, 62,242,161, 9, 63, 40,228,223, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,242,161, 9, 63, 40,228,223, 62,230,102,130, 63, 49, 12, 82,
+ 62,230,102,129, 63, 37,200, 48, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,248,130, 59, 63, 75, 39,169, 63, 3, 30,140, 63, 65,236,201, 63, 6,237, 94,
+ 63, 78, 83,207, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 6,237, 94, 63, 78, 83,207, 62,253,222,118, 63, 88, 64,148, 62,248,130, 59, 63, 75, 39,169,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,230,102,130, 63, 82,228, 41, 62,248,130, 59, 63, 75, 39,169, 62,253,222,118, 63, 88, 64,148, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,253,222,118, 63, 88, 64,148, 63, 6,237, 94, 63, 78, 83,207, 63, 12,204,220, 63, 90, 56, 22, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 18,172, 88,
+ 63, 78, 83,207, 63, 12,204,220, 63, 90, 56, 22, 63, 6,237, 94, 63, 78, 83,207, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 6,237, 94, 63, 78, 83,207,
+ 63, 12,204,220, 63, 67, 23,115, 63, 18,172, 88, 63, 78, 83,207, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 22,123, 44, 63, 65,236,201, 63, 18,172, 88,
+ 63, 78, 83,207, 63, 12,204,220, 63, 67, 23,115, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 12,204,220, 63, 67, 23,115, 63, 6,237, 94, 63, 78, 83,207,
+ 63, 3, 30,140, 63, 65,236,201, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 8,120, 93, 63, 55,205, 11, 63, 12,204,220, 63, 45, 28, 35, 63, 17, 33, 91,
+ 63, 55,205, 9, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 17, 33, 91, 63, 55,205, 9, 63, 12,204,220, 63, 67, 23,115, 63, 8,120, 93, 63, 55,205, 11,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 3, 30,140, 63, 65,236,201, 63, 8,120, 93, 63, 55,205, 11, 63, 12,204,220, 63, 67, 23,115, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 12,204,220, 63, 67, 23,115, 63, 17, 33, 91, 63, 55,205, 9, 63, 22,123, 44, 63, 65,236,201, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 18,172, 88,
+ 63, 78, 83,207, 63, 22,123, 44, 63, 65,236,201, 63, 29, 88,153, 63, 75, 39,167, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 29, 88,153, 63, 75, 39,167,
+ 63, 26,170,121, 63, 88, 64,147, 63, 18,172, 88, 63, 78, 83,207, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 12,204,220, 63, 90, 56, 22, 63, 18,172, 88,
+ 63, 78, 83,207, 63, 26,170,121, 63, 88, 64,147, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 26,170,121, 63, 88, 64,147, 63, 29, 88,153, 63, 75, 39,167,
+ 63, 38,102,118, 63, 82,228, 38, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 38,102,117, 63, 49, 12, 78, 63, 38,102,117, 63, 60, 86, 50, 63, 31,174,200,
+ 63, 52, 55,169, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 31,174,200, 63, 52, 55,169, 63, 32, 73, 51, 63, 40,228,221, 63, 38,102,117, 63, 49, 12, 78,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 38,102,117, 63, 37,200, 45, 63, 38,102,117, 63, 49, 12, 78, 63, 32, 73, 51, 63, 40,228,221, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 32, 73, 51, 63, 40,228,221, 63, 31,174,200, 63, 52, 55,169, 63, 25,238,169, 63, 43, 52,229, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 24,102, 39,
+ 63, 54,155,119, 63, 25,238,169, 63, 43, 52,229, 63, 31,174,200, 63, 52, 55,169, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 31,174,200, 63, 52, 55,169,
+ 63, 30,180,246, 63, 63,233, 92, 63, 24,102, 39, 63, 54,155,119, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 22,123, 44, 63, 65,236,201, 63, 24,102, 39,
+ 63, 54,155,119, 63, 30,180,246, 63, 63,233, 92, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 30,180,246, 63, 63,233, 92, 63, 31,174,200, 63, 52, 55,169,
+ 63, 38,102,117, 63, 60, 86, 50, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 38,102,117, 63, 71,153,255, 63, 38,102,118, 63, 82,228, 38, 63, 29, 88,153,
+ 63, 75, 39,167, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 29, 88,153, 63, 75, 39,167, 63, 30,180,246, 63, 63,233, 92, 63, 38,102,117, 63, 71,153,255,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 38,102,117, 63, 60, 86, 50, 63, 38,102,117, 63, 71,153,255, 63, 30,180,246, 63, 63,233, 92, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 30,180,246, 63, 63,233, 92, 63, 29, 88,153, 63, 75, 39,167, 63, 22,123, 44, 63, 65,236,201, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 24,102, 39,
+ 63, 54,155,119, 63, 22,123, 44, 63, 65,236,201, 63, 17, 33, 91, 63, 55,205, 9, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 17, 33, 91, 63, 55,205, 9,
+ 63, 19,107,138, 63, 44,160,211, 63, 24,102, 39, 63, 54,155,119, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 25,238,169, 63, 43, 52,229, 63, 24,102, 39,
+ 63, 54,155,119, 63, 19,107,138, 63, 44,160,211, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 19,107,138, 63, 44,160,211, 63, 17, 33, 91, 63, 55,205, 9,
+ 63, 12,204,220, 63, 45, 28, 35, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 38,102,118, 63, 94, 46, 77, 63, 38,102,118, 63,105,114, 19, 63, 22,102,235,
+ 63, 99, 26, 59, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 22,102,235, 63, 99, 26, 59, 63, 26,170,121, 63, 88, 64,147, 63, 38,102,118, 63, 94, 46, 77,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 38,102,118, 63, 82,228, 38, 63, 38,102,118, 63, 94, 46, 77, 63, 26,170,121, 63, 88, 64,147, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 26,170,121, 63, 88, 64,147, 63, 22,102,235, 63, 99, 26, 59, 63, 12,204,220, 63, 90, 56, 22, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 3, 50,204,
+ 63, 99, 26, 58, 63, 12,204,220, 63, 90, 56, 22, 63, 22,102,235, 63, 99, 26, 59, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 22,102,235, 63, 99, 26, 59,
+ 63, 12,204,224, 63,109,154,212, 63, 3, 50,204, 63, 99, 26, 58, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,230,102,131, 63,105,114, 22, 63, 3, 50,204,
+ 63, 99, 26, 58, 63, 12,204,224, 63,109,154,212, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 12,204,224, 63,109,154,212, 63, 22,102,235, 63, 99, 26, 59,
+ 63, 38,102,118, 63,105,114, 19, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 38,102,120, 63,116,187,242, 63, 59,153, 3, 63,128, 0, 0, 62,230,102,134,
+ 63,116,187,242, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,230,102,134, 63,116,187,242, 63, 12,204,224, 63,109,154,212, 63, 38,102,120, 63,116,187,242,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 38,102,118, 63,105,114, 19, 63, 38,102,120, 63,116,187,242, 63, 12,204,224, 63,109,154,212, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 12,204,224, 63,109,154,212, 62,230,102,134, 63,116,187,242, 62,230,102,131, 63,105,114, 22, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 3, 50,204,
+ 63, 99, 26, 58, 62,230,102,131, 63,105,114, 22, 62,230,102,131, 63, 94, 46, 79, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,230,102,131, 63, 94, 46, 79,
+ 62,253,222,118, 63, 88, 64,148, 63, 3, 50,204, 63, 99, 26, 58, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 12,204,220, 63, 90, 56, 22, 63, 3, 50,204,
+ 63, 99, 26, 58, 62,253,222,118, 63, 88, 64,148, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,253,222,118, 63, 88, 64,148, 62,230,102,131, 63, 94, 46, 79,
+ 62,230,102,130, 63, 82,228, 41, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 76,233,213, 63, 21, 48, 35, 63, 70,235,176, 63, 22,209,226, 63, 73,234, 80,
+ 63, 11,111,146, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 73,234, 80, 63, 11,111,146, 63, 79,200, 1, 63, 9,152, 94, 63, 76,233,213, 63, 21, 48, 35,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 82,215, 19, 63, 19, 29,252, 63, 76,233,213, 63, 21, 48, 35, 63, 79,200, 1, 63, 9,152, 94, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 79,200, 1, 63, 9,152, 94, 63, 73,234, 80, 63, 11,111,146, 63, 76,204,193, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 76,233,213,
+ 63, 21, 48, 35, 63, 82,215, 19, 63, 19, 29,252, 63, 80, 41,220, 63, 31, 60,105, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 80, 41,220, 63, 31, 60,105,
+ 63, 73,219,164, 63, 33, 23,173, 63, 76,233,213, 63, 21, 48, 35, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 70,235,176, 63, 22,209,226, 63, 76,233,213,
+ 63, 21, 48, 35, 63, 73,219,164, 63, 33, 23,173, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 73,219,164, 63, 33, 23,173, 63, 80, 41,220, 63, 31, 60,105,
+ 63, 77, 33,196, 63, 43, 52,221, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 70,158,169, 63, 44,160,200, 63, 64, 0, 0, 63, 45, 28, 24, 63, 67,171, 5,
+ 63, 34, 17,216, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 67,171, 5, 63, 34, 17,216, 63, 73,219,164, 63, 33, 23,173, 63, 70,158,169, 63, 44,160,200,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 77, 33,196, 63, 43, 52,221, 63, 70,158,169, 63, 44,160,200, 63, 73,219,164, 63, 33, 23,173, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 73,219,164, 63, 33, 23,173, 63, 67,171, 5, 63, 34, 17,216, 63, 70,235,176, 63, 22,209,226, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 83,124, 75,
+ 63, 40,228,217, 63, 77, 33,196, 63, 43, 52,221, 63, 80, 41,220, 63, 31, 60,105, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 80, 41,220, 63, 31, 60,105,
+ 63, 86, 20,218, 63, 28,140,143, 63, 83,124, 75, 63, 40,228,217, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 89,153,139, 63, 37,200, 45, 63, 83,124, 75,
+ 63, 40,228,217, 63, 86, 20,218, 63, 28,140,143, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 86, 20,218, 63, 28,140,143, 63, 80, 41,220, 63, 31, 60,105,
+ 63, 82,215, 19, 63, 19, 29,252, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 64, 0, 0, 63, 23, 32,182, 63, 70,235,176, 63, 22,209,226, 63, 67,171, 5,
+ 63, 34, 17,216, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 67,171, 5, 63, 34, 17,216, 63, 60, 84,251, 63, 34, 17,216, 63, 64, 0, 0, 63, 23, 32,182,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 57, 20, 80, 63, 22,209,226, 63, 64, 0, 0, 63, 23, 32,182, 63, 60, 84,251, 63, 34, 17,216, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 60, 84,251, 63, 34, 17,216, 63, 67,171, 5, 63, 34, 17,216, 63, 64, 0, 0, 63, 45, 28, 24, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 64, 0, 0,
+ 63, 23, 32,182, 63, 57, 20, 80, 63, 22,209,226, 63, 60,156,169, 63, 11,116, 96, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 60,156,169, 63, 11,116, 96,
+ 63, 67, 99, 87, 63, 11,116, 96, 63, 64, 0, 0, 63, 23, 32,182, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 70,235,176, 63, 22,209,226, 63, 64, 0, 0,
+ 63, 23, 32,182, 63, 67, 99, 87, 63, 11,116, 96, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 67, 99, 87, 63, 11,116, 96, 63, 60,156,169, 63, 11,116, 96,
+ 63, 64, 0, 0, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 70,102, 96, 63, 0, 1,244, 63, 76,204,193, 63, 0, 0, 0, 63, 73,234, 80,
+ 63, 11,111,146, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 73,234, 80, 63, 11,111,146, 63, 67, 99, 87, 63, 11,116, 96, 63, 70,102, 96, 63, 0, 1,244,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 64, 0, 0, 63, 0, 0, 0, 63, 70,102, 96, 63, 0, 1,244, 63, 67, 99, 87, 63, 11,116, 96, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 67, 99, 87, 63, 11,116, 96, 63, 73,234, 80, 63, 11,111,146, 63, 70,235,176, 63, 22,209,226, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 57,153,160,
+ 63, 0, 1,244, 63, 64, 0, 0, 63, 0, 0, 0, 63, 60,156,169, 63, 11,116, 96, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 60,156,169, 63, 11,116, 96,
+ 63, 54, 21,176, 63, 11,111,146, 63, 57,153,160, 63, 0, 1,244, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 51, 51, 63, 63, 0, 0, 0, 63, 57,153,160,
+ 63, 0, 1,244, 63, 54, 21,176, 63, 11,111,146, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 54, 21,176, 63, 11,111,146, 63, 60,156,169, 63, 11,116, 96,
+ 63, 57, 20, 80, 63, 22,209,226, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 64, 0, 0, 62,217, 58, 93, 63, 57, 61,144, 62,217,196, 19, 63, 60,123, 85,
+ 62,198,230,253, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 60,123, 85, 62,198,230,253, 63, 67,132,171, 62,198,230,253, 63, 64, 0, 0, 62,217, 58, 93,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 70,194,112, 62,217,196, 19, 63, 64, 0, 0, 62,217, 58, 93, 63, 67,132,171, 62,198,230,253, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 67,132,171, 62,198,230,253, 63, 60,123, 85, 62,198,230,253, 63, 64, 0, 0, 62,180,111,211, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 64, 0, 0,
+ 62,217, 58, 93, 63, 70,194,112, 62,217,196, 19, 63, 67, 84,125, 62,236,211, 42, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 67, 84,125, 62,236,211, 42,
+ 63, 60,171,131, 62,236,211, 42, 63, 64, 0, 0, 62,217, 58, 93, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 57, 61,144, 62,217,196, 19, 63, 64, 0, 0,
+ 62,217, 58, 93, 63, 60,171,131, 62,236,211, 42, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 60,171,131, 62,236,211, 42, 63, 67, 84,125, 62,236,211, 42,
+ 63, 64, 0, 0, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 57,153,160, 63, 0, 1,244, 63, 51, 51, 63, 63, 0, 0, 0, 63, 54, 46,128,
+ 62,236,207, 75, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 54, 46,128, 62,236,207, 75, 63, 60,171,131, 62,236,211, 42, 63, 57,153,160, 63, 0, 1,244,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 64, 0, 0, 63, 0, 0, 0, 63, 57,153,160, 63, 0, 1,244, 63, 60,171,131, 62,236,211, 42, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 60,171,131, 62,236,211, 42, 63, 54, 46,128, 62,236,207, 75, 63, 57, 61,144, 62,217,196, 19, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 70,102, 96,
+ 63, 0, 1,244, 63, 64, 0, 0, 63, 0, 0, 0, 63, 67, 84,125, 62,236,211, 42, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 67, 84,125, 62,236,211, 42,
+ 63, 73,209,128, 62,236,207, 75, 63, 70,102, 96, 63, 0, 1,244, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 76,204,193, 63, 0, 0, 0, 63, 70,102, 96,
+ 63, 0, 1,244, 63, 73,209,128, 62,236,207, 75, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 73,209,128, 62,236,207, 75, 63, 67, 84,125, 62,236,211, 42,
+ 63, 70,194,112, 62,217,196, 19, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 51, 22, 43, 63, 21, 48, 35, 63, 45, 40,237, 63, 19, 29,252, 63, 48, 55,255,
+ 63, 9,152, 94, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 48, 55,255, 63, 9,152, 94, 63, 54, 21,176, 63, 11,111,146, 63, 51, 22, 43, 63, 21, 48, 35,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 57, 20, 80, 63, 22,209,226, 63, 51, 22, 43, 63, 21, 48, 35, 63, 54, 21,176, 63, 11,111,146, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 54, 21,176, 63, 11,111,146, 63, 48, 55,255, 63, 9,152, 94, 63, 51, 51, 63, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 51, 22, 43,
+ 63, 21, 48, 35, 63, 57, 20, 80, 63, 22,209,226, 63, 54, 36, 91, 63, 33, 23,173, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 54, 36, 91, 63, 33, 23,173,
+ 63, 47,214, 36, 63, 31, 60,105, 63, 51, 22, 43, 63, 21, 48, 35, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 45, 40,237, 63, 19, 29,252, 63, 51, 22, 43,
+ 63, 21, 48, 35, 63, 47,214, 36, 63, 31, 60,105, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 47,214, 36, 63, 31, 60,105, 63, 54, 36, 91, 63, 33, 23,173,
+ 63, 50,222, 60, 63, 43, 52,221, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 44,131,181, 63, 40,228,216, 63, 38,102,117, 63, 37,200, 45, 63, 41,235, 38,
+ 63, 28,140,141, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 41,235, 38, 63, 28,140,141, 63, 47,214, 36, 63, 31, 60,105, 63, 44,131,181, 63, 40,228,216,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 50,222, 60, 63, 43, 52,221, 63, 44,131,181, 63, 40,228,216, 63, 47,214, 36, 63, 31, 60,105, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 47,214, 36, 63, 31, 60,105, 63, 41,235, 38, 63, 28,140,141, 63, 45, 40,237, 63, 19, 29,252, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 57, 97, 87,
+ 63, 44,160,200, 63, 50,222, 60, 63, 43, 52,221, 63, 54, 36, 91, 63, 33, 23,173, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 54, 36, 91, 63, 33, 23,173,
+ 63, 60, 84,251, 63, 34, 17,216, 63, 57, 97, 87, 63, 44,160,200, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 64, 0, 0, 63, 45, 28, 24, 63, 57, 97, 87,
+ 63, 44,160,200, 63, 60, 84,251, 63, 34, 17,216, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 60, 84,251, 63, 34, 17,216, 63, 54, 36, 91, 63, 33, 23,173,
+ 63, 57, 20, 80, 63, 22,209,226, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 14,134, 63, 21, 48, 39, 63,122, 30,227, 63, 22,209,233, 63,125, 29,138,
+ 63, 11,111,150, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,125, 29,138, 63, 11,111,150, 63,129,125,159, 63, 9,152, 94, 63,128, 14,134, 63, 21, 48, 39,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 60,193, 73,174, 63, 19, 29,253, 57,232, 92,209, 63, 21, 48, 39, 60, 62,207,114, 63, 9,152, 94, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,129,125,159, 63, 9,152, 94, 63,125, 29,138, 63, 11,111,150, 63,128, 0, 0, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 57,232, 92,209,
+ 63, 21, 48, 39, 60,193, 73,174, 63, 19, 29,253, 60, 87, 67,214, 63, 31, 60,110, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,129,174,136, 63, 31, 60,110,
+ 63,125, 14,213, 63, 33, 23,180, 63,128, 14,134, 63, 21, 48, 39, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,122, 30,227, 63, 22,209,233, 63,128, 14,134,
+ 63, 21, 48, 39, 63,125, 14,213, 63, 33, 23,180, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,125, 14,213, 63, 33, 23,180, 63,129,174,136, 63, 31, 60,110,
+ 63,128, 42,121, 63, 43, 52,230, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,121,209,210, 63, 44,160,212, 63,115, 51, 36, 63, 45, 28, 36, 63,118,222, 49,
+ 63, 34, 17,226, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,118,222, 49, 63, 34, 17,226, 63,125, 14,213, 63, 33, 23,180, 63,121,209,210, 63, 44,160,212,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,128, 42,121, 63, 43, 52,230, 63,121,209,210, 63, 44,160,212, 63,125, 14,213, 63, 33, 23,180, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,125, 14,213, 63, 33, 23,180, 63,118,222, 49, 63, 34, 17,226, 63,122, 30,227, 63, 22,209,233, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 60,213,239,111,
+ 63, 40,228,223, 58,169,226,120, 63, 43, 52,230, 60, 87, 67,214, 63, 31, 60,110, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 60, 87, 67,214, 63, 31, 60,110,
+ 61, 20,129, 13, 63, 28,140,143, 60,213,239,111, 63, 40,228,223, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61, 76,203,246, 63, 37,200, 48, 60,213,239,111,
+ 63, 40,228,223, 61, 20,129, 13, 63, 28,140,143, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61, 20,129, 13, 63, 28,140,143, 60, 87, 67,214, 63, 31, 60,110,
+ 60,193, 73,174, 63, 19, 29,253, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,115, 51, 44, 63, 23, 32,188, 63,122, 30,227, 63, 22,209,233, 63,118,222, 49,
+ 63, 34, 17,226, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,118,222, 49, 63, 34, 17,226, 63,111,136, 31, 63, 34, 17,225, 63,115, 51, 44, 63, 23, 32,188,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,108, 71,116, 63, 22,209,232, 63,115, 51, 44, 63, 23, 32,188, 63,111,136, 31, 63, 34, 17,225, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,111,136, 31, 63, 34, 17,225, 63,118,222, 49, 63, 34, 17,226, 63,115, 51, 36, 63, 45, 28, 36, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,115, 51, 44,
+ 63, 23, 32,188, 63,108, 71,116, 63, 22,209,232, 63,111,207,213, 63, 11,116,100, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,111,207,213, 63, 11,116,100,
+ 63,118,150,138, 63, 11,116,101, 63,115, 51, 44, 63, 23, 32,188, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,122, 30,227, 63, 22,209,233, 63,115, 51, 44,
+ 63, 23, 32,188, 63,118,150,138, 63, 11,116,101, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,118,150,138, 63, 11,116,101, 63,111,207,213, 63, 11,116,100,
+ 63,115, 51, 51, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,121,153,154, 63, 0, 1,244, 63,128, 0, 0, 63, 0, 0, 0, 63,125, 29,138,
+ 63, 11,111,150, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,125, 29,138, 63, 11,111,150, 63,118,150,138, 63, 11,116,101, 63,121,153,154, 63, 0, 1,244,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,115, 51, 51, 63, 0, 0, 0, 63,121,153,154, 63, 0, 1,244, 63,118,150,138, 63, 11,116,101, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,118,150,138, 63, 11,116,101, 63,125, 29,138, 63, 11,111,150, 63,122, 30,227, 63, 22,209,233, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,108,204,205,
+ 63, 0, 1,244, 63,115, 51, 51, 63, 0, 0, 0, 63,111,207,213, 63, 11,116,100, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,111,207,213, 63, 11,116,100,
+ 63,105, 72,213, 63, 11,111,149, 63,108,204,205, 63, 0, 1,244, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,102,102,101, 63, 0, 0, 0, 63,108,204,205,
+ 63, 0, 1,244, 63,105, 72,213, 63, 11,111,149, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,105, 72,213, 63, 11,111,149, 63,111,207,213, 63, 11,116,100,
+ 63,108, 71,116, 63, 22,209,232, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,115, 51, 58, 62,217, 58, 73, 63,108,112,192, 62,217,196, 4, 63,111,174,139,
+ 62,198,230,223, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,111,174,139, 62,198,230,223, 63,118,183,239, 62,198,230,227, 63,115, 51, 58, 62,217, 58, 73,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,121,245,179, 62,217,196, 6, 63,115, 51, 58, 62,217, 58, 73, 63,118,183,239, 62,198,230,227, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,118,183,239, 62,198,230,227, 63,111,174,139, 62,198,230,223, 63,115, 51, 65, 62,180,111,160, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,115, 51, 58,
+ 62,217, 58, 73, 63,121,245,179, 62,217,196, 6, 63,118,135,185, 62,236,211, 30, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,118,135,185, 62,236,211, 30,
+ 63,111,222,180, 62,236,211, 30, 63,115, 51, 58, 62,217, 58, 73, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,108,112,192, 62,217,196, 4, 63,115, 51, 58,
+ 62,217, 58, 73, 63,111,222,180, 62,236,211, 30, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,111,222,180, 62,236,211, 30, 63,118,135,185, 62,236,211, 30,
+ 63,115, 51, 51, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,108,204,205, 63, 0, 1,244, 63,102,102,101, 63, 0, 0, 0, 63,105, 97,170,
+ 62,236,207, 65, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,105, 97,170, 62,236,207, 65, 63,111,222,180, 62,236,211, 30, 63,108,204,205, 63, 0, 1,244,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,115, 51, 51, 63, 0, 0, 0, 63,108,204,205, 63, 0, 1,244, 63,111,222,180, 62,236,211, 30, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,111,222,180, 62,236,211, 30, 63,105, 97,170, 62,236,207, 65, 63,108,112,192, 62,217,196, 4, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,121,153,154,
+ 63, 0, 1,244, 63,115, 51, 51, 63, 0, 0, 0, 63,118,135,185, 62,236,211, 30, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,118,135,185, 62,236,211, 30,
+ 63,125, 4,194, 62,236,207, 67, 63,121,153,154, 63, 0, 1,244, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63, 0, 0, 0, 63,121,153,154,
+ 63, 0, 1,244, 63,125, 4,194, 62,236,207, 67, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,125, 4,194, 62,236,207, 67, 63,118,135,185, 62,236,211, 30,
+ 63,121,245,179, 62,217,196, 6, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,102, 73, 76, 63, 21, 48, 38, 63, 96, 92, 11, 63, 19, 29,253, 63, 99,107, 33,
+ 63, 9,152, 94, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 99,107, 33, 63, 9,152, 94, 63,105, 72,213, 63, 11,111,149, 63,102, 73, 76, 63, 21, 48, 38,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,108, 71,116, 63, 22,209,232, 63,102, 73, 76, 63, 21, 48, 38, 63,105, 72,213, 63, 11,111,149, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,105, 72,213, 63, 11,111,149, 63, 99,107, 33, 63, 9,152, 94, 63,102,102,101, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,102, 73, 76,
+ 63, 21, 48, 38, 63,108, 71,116, 63, 22,209,232, 63,105, 87,124, 63, 33, 23,180, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,105, 87,124, 63, 33, 23,180,
+ 63, 99, 9, 65, 63, 31, 60,109, 63,102, 73, 76, 63, 21, 48, 38, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 96, 92, 11, 63, 19, 29,253, 63,102, 73, 76,
+ 63, 21, 48, 38, 63, 99, 9, 65, 63, 31, 60,109, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 99, 9, 65, 63, 31, 60,109, 63,105, 87,124, 63, 33, 23,180,
+ 63,102, 17, 87, 63, 43, 52,229, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 95,182,205, 63, 40,228,222, 63, 89,153,139, 63, 37,200, 45, 63, 93, 30, 63,
+ 63, 28,140,143, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 93, 30, 63, 63, 28,140,143, 63, 99, 9, 65, 63, 31, 60,109, 63, 95,182,205, 63, 40,228,222,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,102, 17, 87, 63, 43, 52,229, 63, 95,182,205, 63, 40,228,222, 63, 99, 9, 65, 63, 31, 60,109, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 99, 9, 65, 63, 31, 60,109, 63, 93, 30, 63, 63, 28,140,143, 63, 96, 92, 11, 63, 19, 29,253, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,108,148,118,
+ 63, 44,160,211, 63,102, 17, 87, 63, 43, 52,229, 63,105, 87,124, 63, 33, 23,180, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,105, 87,124, 63, 33, 23,180,
+ 63,111,136, 31, 63, 34, 17,225, 63,108,148,118, 63, 44,160,211, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,115, 51, 36, 63, 45, 28, 36, 63,108,148,118,
+ 63, 44,160,211, 63,111,136, 31, 63, 34, 17,225, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,111,136, 31, 63, 34, 17,225, 63,105, 87,124, 63, 33, 23,180,
+ 63,108, 71,116, 63, 22,209,232, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 77, 65, 65, 63, 21, 48, 32, 62, 53, 72,152, 63, 22,209,229, 62, 65, 67, 47,
+ 63, 11,111,147, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62, 65, 67, 47, 63, 11,111,147, 62, 88,185,255, 63, 9,152, 90, 62, 77, 65, 65, 63, 21, 48, 32,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,100,246, 64, 63, 19, 29,246, 62, 77, 65, 65, 63, 21, 48, 32, 62, 88,185,255, 63, 9,152, 90, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62, 88,185,255, 63, 9,152, 90, 62, 65, 67, 47, 63, 11,111,147, 62, 76,204,254, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 77, 65, 65,
+ 63, 21, 48, 32, 62,100,246, 64, 63, 19, 29,246, 62, 90, 65, 89, 63, 31, 60, 94, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 90, 65, 89, 63, 31, 60, 94,
+ 62, 65, 8,107, 63, 33, 23,170, 62, 77, 65, 65, 63, 21, 48, 32, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 53, 72,152, 63, 22,209,229, 62, 77, 65, 65,
+ 63, 21, 48, 32, 62, 65, 8,107, 63, 33, 23,170, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 65, 8,107, 63, 33, 23,170, 62, 90, 65, 89, 63, 31, 60, 94,
+ 62, 78, 32,230, 63, 43, 52,211, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 52, 20,105, 63, 44,160,198, 62, 25,153,173, 63, 45, 28, 27, 62, 40, 69,216,
+ 63, 34, 17,220, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62, 40, 69,216, 63, 34, 17,220, 62, 65, 8,107, 63, 33, 23,170, 62, 52, 20,105, 63, 44,160,198,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62, 78, 32,230, 63, 43, 52,211, 62, 52, 20,105, 63, 44,160,198, 62, 65, 8,107, 63, 33, 23,170, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62, 65, 8,107, 63, 33, 23,170, 62, 40, 69,216, 63, 34, 17,220, 62, 53, 72,152, 63, 22,209,229, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,103,139, 14,
+ 63, 40,228,199, 62, 78, 32,230, 63, 43, 52,211, 62, 90, 65, 89, 63, 31, 60, 94, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 90, 65, 89, 63, 31, 60, 94,
+ 62,113,237, 83, 63, 28,140,130, 62,103,139, 14, 63, 40,228,199, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,128, 0, 0, 63, 37,200, 23, 62,103,139, 14,
+ 63, 40,228,199, 62,113,237, 83, 63, 28,140,130, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,113,237, 83, 63, 28,140,130, 62, 90, 65, 89, 63, 31, 60, 94,
+ 62,100,246, 64, 63, 19, 29,246, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 25,153,180, 63, 23, 32,185, 62, 53, 72,152, 63, 22,209,229, 62, 40, 69,216,
+ 63, 34, 17,220, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62, 40, 69,216, 63, 34, 17,220, 62, 10,237,133, 63, 34, 17,219, 62, 25,153,180, 63, 23, 32,185,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 61,251,213,147, 63, 22,209,228, 62, 25,153,180, 63, 23, 32,185, 62, 10,237,133, 63, 34, 17,219, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62, 10,237,133, 63, 34, 17,219, 62, 40, 69,216, 63, 34, 17,220, 62, 25,153,173, 63, 45, 28, 27, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 25,153,180,
+ 63, 23, 32,185, 61,251,213,147, 63, 22,209,228, 62, 12, 12, 67, 63, 11,116, 98, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 12, 12, 67, 63, 11,116, 98,
+ 62, 39, 39, 34, 63, 11,116, 98, 62, 25,153,180, 63, 23, 32,185, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 53, 72,152, 63, 22,209,229, 62, 25,153,180,
+ 63, 23, 32,185, 62, 39, 39, 34, 63, 11,116, 98, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 39, 39, 34, 63, 11,116, 98, 62, 12, 12, 67, 63, 11,116, 98,
+ 62, 25,153,181, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 51, 51, 92, 63, 0, 1,244, 62, 76,204,254, 63, 0, 0, 0, 62, 65, 67, 47,
+ 63, 11,111,147, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62, 65, 67, 47, 63, 11,111,147, 62, 39, 39, 34, 63, 11,116, 98, 62, 51, 51, 92, 63, 0, 1,244,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62, 25,153,181, 63, 0, 0, 0, 62, 51, 51, 92, 63, 0, 1,244, 62, 39, 39, 34, 63, 11,116, 98, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62, 39, 39, 34, 63, 11,116, 98, 62, 65, 67, 47, 63, 11,111,147, 62, 53, 72,152, 63, 22,209,229, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 8,
+ 63, 0, 1,244, 62, 25,153,181, 63, 0, 0, 0, 62, 12, 12, 67, 63, 11,116, 98, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 12, 12, 67, 63, 11,116, 98,
+ 61,227,224,109, 63, 11,111,147, 62, 0, 0, 8, 63, 0, 1,244, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,204,204,215, 63, 0, 0, 0, 62, 0, 0, 8,
+ 63, 0, 1,244, 61,227,224,109, 63, 11,111,147, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,227,224,109, 63, 11,111,147, 62, 12, 12, 67, 63, 11,116, 98,
+ 61,251,213,147, 63, 22,209,228, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 25,153,196, 62,217, 58, 73, 61,253, 31,171, 62,217,196, 6, 62, 11,135, 1,
+ 62,198,230,228, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62, 11,135, 1, 62,198,230,228, 62, 39,172,153, 62,198,230,230, 62, 25,153,196, 62,217, 58, 73,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62, 52,163,179, 62,217,196, 7, 62, 25,153,196, 62,217, 58, 73, 62, 39,172,153, 62,198,230,230, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62, 39,172,153, 62,198,230,230, 62, 11,135, 1, 62,198,230,228, 62, 25,153,214, 62,180,111,165, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 25,153,196,
+ 62,217, 58, 73, 62, 52,163,179, 62,217,196, 7, 62, 38,235,202, 62,236,211, 33, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 38,235,202, 62,236,211, 33,
+ 62, 12, 71,173, 62,236,211, 31, 62, 25,153,196, 62,217, 58, 73, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,253, 31,171, 62,217,196, 6, 62, 25,153,196,
+ 62,217, 58, 73, 62, 12, 71,173, 62,236,211, 31, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 12, 71,173, 62,236,211, 31, 62, 38,235,202, 62,236,211, 33,
+ 62, 25,153,181, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 8, 63, 0, 1,244, 61,204,204,215, 63, 0, 0, 0, 61,228,166,251,
+ 62,236,207, 67, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 61,228,166,251, 62,236,207, 67, 62, 12, 71,173, 62,236,211, 31, 62, 0, 0, 8, 63, 0, 1,244,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62, 25,153,181, 63, 0, 0, 0, 62, 0, 0, 8, 63, 0, 1,244, 62, 12, 71,173, 62,236,211, 31, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62, 12, 71,173, 62,236,211, 31, 61,228,166,251, 62,236,207, 67, 61,253, 31,171, 62,217,196, 6, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 51, 51, 92,
+ 63, 0, 1,244, 62, 25,153,181, 63, 0, 0, 0, 62, 38,235,202, 62,236,211, 33, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 38,235,202, 62,236,211, 33,
+ 62, 64,223,251, 62,236,207, 67, 62, 51, 51, 92, 63, 0, 1,244, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 76,204,254, 63, 0, 0, 0, 62, 51, 51, 92,
+ 63, 0, 1,244, 62, 64,223,251, 62,236,207, 67, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 64,223,251, 62,236,207, 67, 62, 38,235,202, 62,236,211, 33,
+ 62, 52,163,179, 62,217,196, 7, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,203,228, 42, 63, 21, 48, 37, 61,156,122, 1, 63, 19, 29,254, 61,180,242,172,
+ 63, 9,152, 96, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 61,180,242,172, 63, 9,152, 96, 61,227,224,109, 63, 11,111,147, 61,203,228, 42, 63, 21, 48, 37,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 61,251,213,147, 63, 22,209,228, 61,203,228, 42, 63, 21, 48, 37, 61,227,224,109, 63, 11,111,147, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 61,227,224,109, 63, 11,111,147, 61,180,242,172, 63, 9,152, 96, 61,204,204,215, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,203,228, 42,
+ 63, 21, 48, 37, 61,251,213,147, 63, 22,209,228, 61,228, 85,208, 63, 33, 23,179, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,228, 85,208, 63, 33, 23,179,
+ 61,177,227,212, 63, 31, 60,110, 61,203,228, 42, 63, 21, 48, 37, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,156,122, 1, 63, 19, 29,254, 61,203,228, 42,
+ 63, 21, 48, 37, 61,177,227,212, 63, 31, 60,110, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,177,227,212, 63, 31, 60,110, 61,228, 85,208, 63, 33, 23,179,
+ 61,202, 36,175, 63, 43, 52,228, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,151, 80, 53, 63, 40,228,223, 61, 76,203,246, 63, 37,200, 48, 61,130,139,166,
+ 63, 28,140,145, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 61,130,139,166, 63, 28,140,145, 61,177,227,212, 63, 31, 60,110, 61,151, 80, 53, 63, 40,228,223,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 61,202, 36,175, 63, 43, 52,228, 61,151, 80, 53, 63, 40,228,223, 61,177,227,212, 63, 31, 60,110, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 61,177,227,212, 63, 31, 60,110, 61,130,139,166, 63, 28,140,145, 61,156,122, 1, 63, 19, 29,254, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,254, 61,201,
+ 63, 44,160,207, 61,202, 36,175, 63, 43, 52,228, 61,228, 85,208, 63, 33, 23,179, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,228, 85,208, 63, 33, 23,179,
+ 62, 10,237,133, 63, 34, 17,219, 61,254, 61,201, 63, 44,160,207, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 25,153,173, 63, 45, 28, 27, 61,254, 61,201,
+ 63, 44,160,207, 62, 10,237,133, 63, 34, 17,219, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 10,237,133, 63, 34, 17,219, 61,228, 85,208, 63, 33, 23,179,
+ 61,251,213,147, 63, 22,209,228, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,205, 6,245, 63, 21, 48, 37, 62,193, 10,155, 63, 22,209,229, 62,199, 7,229,
+ 63, 11,111,147, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,199, 7,229, 63, 11,111,147, 62,210,195, 85, 63, 9,152, 96, 62,205, 6,245, 63, 21, 48, 37,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,216,225,128, 63, 19, 29,254, 62,205, 6,245, 63, 21, 48, 37, 62,210,195, 85, 63, 9,152, 96, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,210,195, 85, 63, 9,152, 96, 62,199, 7,229, 63, 11,111,147, 62,204,204,202, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,205, 6,245,
+ 63, 21, 48, 37, 62,216,225,128, 63, 19, 29,254, 62,211,135, 11, 63, 31, 60,110, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,211,135, 11, 63, 31, 60,110,
+ 62,198,234,140, 63, 33, 23,179, 62,205, 6,245, 63, 21, 48, 37, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,193, 10,155, 63, 22,209,229, 62,205, 6,245,
+ 63, 21, 48, 37, 62,198,234,140, 63, 33, 23,179, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,198,234,140, 63, 33, 23,179, 62,211,135, 11, 63, 31, 60,110,
+ 62,205,118,212, 63, 43, 52,228, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,192,112,142, 63, 44,160,207, 62,179, 51, 42, 63, 45, 28, 28, 62,186,137, 61,
+ 63, 34, 17,219, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,186,137, 61, 63, 34, 17,219, 62,198,234,140, 63, 33, 23,179, 62,192,112,142, 63, 44,160,207,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,205,118,212, 63, 43, 52,228, 62,192,112,142, 63, 44,160,207, 62,198,234,140, 63, 33, 23,179, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,198,234,140, 63, 33, 23,179, 62,186,137, 61, 63, 34, 17,219, 62,193, 10,155, 63, 22,209,229, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,218, 43,243,
+ 63, 40,228,223, 62,205,118,212, 63, 43, 52,228, 62,211,135, 11, 63, 31, 60,110, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,211,135, 11, 63, 31, 60,110,
+ 62,223, 93, 22, 63, 28,140,145, 62,218, 43,243, 63, 40,228,223, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,230,102,129, 63, 37,200, 48, 62,218, 43,243,
+ 63, 40,228,223, 62,223, 93, 22, 63, 28,140,145, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,223, 93, 22, 63, 28,140,145, 62,211,135, 11, 63, 31, 60,110,
+ 62,216,225,128, 63, 19, 29,254, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,179, 51, 38, 63, 23, 32,185, 62,193, 10,155, 63, 22,209,229, 62,186,137, 61,
+ 63, 34, 17,219, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,186,137, 61, 63, 34, 17,219, 62,171,221, 20, 63, 34, 17,219, 62,179, 51, 38, 63, 23, 32,185,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,165, 91,180, 63, 22,209,229, 62,179, 51, 38, 63, 23, 32,185, 62,171,221, 20, 63, 34, 17,219, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,171,221, 20, 63, 34, 17,219, 62,186,137, 61, 63, 34, 17,219, 62,179, 51, 42, 63, 45, 28, 28, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,179, 51, 38,
+ 63, 23, 32,185, 62,165, 91,180, 63, 22,209,229, 62,172,108,111, 63, 11,116, 98, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,172,108,111, 63, 11,116, 98,
+ 62,185,249,222, 63, 11,116, 98, 62,179, 51, 38, 63, 23, 32,185, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,193, 10,155, 63, 22,209,229, 62,179, 51, 38,
+ 63, 23, 32,185, 62,185,249,222, 63, 11,116, 98, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,185,249,222, 63, 11,116, 98, 62,172,108,111, 63, 11,116, 98,
+ 62,179, 51, 38, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,191,255,252, 63, 0, 1,244, 62,204,204,202, 63, 0, 0, 0, 62,199, 7,229,
+ 63, 11,111,147, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,199, 7,229, 63, 11,111,147, 62,185,249,222, 63, 11,116, 98, 62,191,255,252, 63, 0, 1,244,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,179, 51, 38, 63, 0, 0, 0, 62,191,255,252, 63, 0, 1,244, 62,185,249,222, 63, 11,116, 98, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,185,249,222, 63, 11,116, 98, 62,199, 7,229, 63, 11,111,147, 62,193, 10,155, 63, 22,209,229, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,166,102, 82,
+ 63, 0, 1,244, 62,179, 51, 38, 63, 0, 0, 0, 62,172,108,111, 63, 11,116, 98, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,172,108,111, 63, 11,116, 98,
+ 62,159, 94,104, 63, 11,111,147, 62,166,102, 82, 63, 0, 1,244, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,153,153,129, 63, 0, 0, 0, 62,166,102, 82,
+ 63, 0, 1,244, 62,159, 94,104, 63, 11,111,147, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,159, 94,104, 63, 11,111,147, 62,172,108,111, 63, 11,116, 98,
+ 62,165, 91,180, 63, 22,209,229, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,179, 51, 30, 62,217, 58, 73, 62,165,174, 39, 62,217,196, 7, 62,172, 41,180,
+ 62,198,230,227, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,172, 41,180, 62,198,230,227, 62,186, 60,127, 62,198,230,225, 62,179, 51, 30, 62,217, 58, 73,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,192,184, 21, 62,217,196, 6, 62,179, 51, 30, 62,217, 58, 73, 62,186, 60,127, 62,198,230,225, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,186, 60,127, 62,198,230,225, 62,172, 41,180, 62,198,230,227, 62,179, 51, 21, 62,180,111,165, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,179, 51, 30,
+ 62,217, 58, 73, 62,192,184, 21, 62,217,196, 6, 62,185,220, 42, 62,236,211, 31, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,185,220, 42, 62,236,211, 31,
+ 62,172,138, 27, 62,236,211, 33, 62,179, 51, 30, 62,217, 58, 73, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,165,174, 39, 62,217,196, 7, 62,179, 51, 30,
+ 62,217, 58, 73, 62,172,138, 27, 62,236,211, 33, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,172,138, 27, 62,236,211, 33, 62,185,220, 42, 62,236,211, 31,
+ 62,179, 51, 38, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,166,102, 82, 63, 0, 1,244, 62,153,153,129, 63, 0, 0, 0, 62,159,144, 3,
+ 62,236,207, 67, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,159,144, 3, 62,236,207, 67, 62,172,138, 27, 62,236,211, 33, 62,166,102, 82, 63, 0, 1,244,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,179, 51, 38, 63, 0, 0, 0, 62,166,102, 82, 63, 0, 1,244, 62,172,138, 27, 62,236,211, 33, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,172,138, 27, 62,236,211, 33, 62,159,144, 3, 62,236,207, 67, 62,165,174, 39, 62,217,196, 7, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,191,255,252,
+ 63, 0, 1,244, 62,179, 51, 38, 63, 0, 0, 0, 62,185,220, 42, 62,236,211, 31, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,185,220, 42, 62,236,211, 31,
+ 62,198,214, 65, 62,236,207, 67, 62,191,255,252, 63, 0, 1,244, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,204,204,202, 63, 0, 0, 0, 62,191,255,252,
+ 63, 0, 1,244, 62,198,214, 65, 62,236,207, 67, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,198,214, 65, 62,236,207, 67, 62,185,220, 42, 62,236,211, 31,
+ 62,192,184, 21, 62,217,196, 6, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,153, 95, 95, 63, 21, 48, 32, 62,141,132,224, 63, 19, 29,246, 62,147,163, 1,
+ 63, 9,152, 91, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,147,163, 1, 63, 9,152, 91, 62,159, 94,104, 63, 11,111,147, 62,153, 95, 95, 63, 21, 48, 32,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,165, 91,180, 63, 22,209,229, 62,153, 95, 95, 63, 21, 48, 32, 62,159, 94,104, 63, 11,111,147, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,159, 94,104, 63, 11,111,147, 62,147,163, 1, 63, 9,152, 91, 62,153,153,129, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,153, 95, 95,
+ 63, 21, 48, 32, 62,165, 91,180, 63, 22,209,229, 62,159,123,203, 63, 33, 23,170, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,159,123,203, 63, 33, 23,170,
+ 62,146,223, 84, 63, 31, 60, 94, 62,153, 95, 95, 63, 21, 48, 32, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,141,132,224, 63, 19, 29,246, 62,153, 95, 95,
+ 63, 21, 48, 32, 62,146,223, 84, 63, 31, 60, 94, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,146,223, 84, 63, 31, 60, 94, 62,159,123,203, 63, 33, 23,170,
+ 62,152,239,141, 63, 43, 52,211, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,140, 58,121, 63, 40,228,199, 62,128, 0, 0, 63, 37,200, 23, 62,135, 9, 86,
+ 63, 28,140,130, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,135, 9, 86, 63, 28,140,130, 62,146,223, 84, 63, 31, 60, 94, 62,140, 58,121, 63, 40,228,199,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,152,239,141, 63, 43, 52,211, 62,140, 58,121, 63, 40,228,199, 62,146,223, 84, 63, 31, 60, 94, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,146,223, 84, 63, 31, 60, 94, 62,135, 9, 86, 63, 28,140,130, 62,141,132,224, 63, 19, 29,246, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,165,245,204,
+ 63, 44,160,198, 62,152,239,141, 63, 43, 52,211, 62,159,123,203, 63, 33, 23,170, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,159,123,203, 63, 33, 23,170,
+ 62,171,221, 20, 63, 34, 17,219, 62,165,245,204, 63, 44,160,198, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,179, 51, 42, 63, 45, 28, 28, 62,165,245,204,
+ 63, 44,160,198, 62,171,221, 20, 63, 34, 17,219, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,171,221, 20, 63, 34, 17,219, 62,159,123,203, 63, 33, 23,170,
+ 62,165, 91,180, 63, 22,209,229, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 25,182,180, 63, 21, 48, 38, 63, 19,184,140, 63, 22,209,232, 63, 22,183, 43,
+ 63, 11,111,149, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 22,183, 43, 63, 11,111,149, 63, 28,148,223, 63, 9,152, 94, 63, 25,182,180, 63, 21, 48, 38,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 31,163,245, 63, 19, 29,253, 63, 25,182,180, 63, 21, 48, 38, 63, 28,148,223, 63, 9,152, 94, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 28,148,223, 63, 9,152, 94, 63, 22,183, 43, 63, 11,111,149, 63, 25,153,155, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 25,182,180,
+ 63, 21, 48, 38, 63, 31,163,245, 63, 19, 29,253, 63, 28,246,191, 63, 31, 60,109, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 28,246,191, 63, 31, 60,109,
+ 63, 22,168,132, 63, 33, 23,180, 63, 25,182,180, 63, 21, 48, 38, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 19,184,140, 63, 22,209,232, 63, 25,182,180,
+ 63, 21, 48, 38, 63, 22,168,132, 63, 33, 23,180, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 22,168,132, 63, 33, 23,180, 63, 28,246,191, 63, 31, 60,109,
+ 63, 25,238,169, 63, 43, 52,229, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 19,107,138, 63, 44,160,211, 63, 12,204,220, 63, 45, 28, 35, 63, 16,119,225,
+ 63, 34, 17,225, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 16,119,225, 63, 34, 17,225, 63, 22,168,132, 63, 33, 23,180, 63, 19,107,138, 63, 44,160,211,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 25,238,169, 63, 43, 52,229, 63, 19,107,138, 63, 44,160,211, 63, 22,168,132, 63, 33, 23,180, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 22,168,132, 63, 33, 23,180, 63, 16,119,225, 63, 34, 17,225, 63, 19,184,140, 63, 22,209,232, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 32, 73, 51,
+ 63, 40,228,221, 63, 25,238,169, 63, 43, 52,229, 63, 28,246,191, 63, 31, 60,109, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 28,246,191, 63, 31, 60,109,
+ 63, 34,225,192, 63, 28,140,142, 63, 32, 73, 51, 63, 40,228,221, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 38,102,117, 63, 37,200, 45, 63, 32, 73, 51,
+ 63, 40,228,221, 63, 34,225,192, 63, 28,140,142, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 34,225,192, 63, 28,140,142, 63, 28,246,191, 63, 31, 60,109,
+ 63, 31,163,245, 63, 19, 29,253, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 12,204,212, 63, 23, 32,188, 63, 19,184,140, 63, 22,209,232, 63, 16,119,225,
+ 63, 34, 17,225, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 16,119,225, 63, 34, 17,225, 63, 9, 33,207, 63, 34, 17,226, 63, 12,204,212, 63, 23, 32,188,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 5,225, 29, 63, 22,209,233, 63, 12,204,212, 63, 23, 32,188, 63, 9, 33,207, 63, 34, 17,226, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 9, 33,207, 63, 34, 17,226, 63, 16,119,225, 63, 34, 17,225, 63, 12,204,220, 63, 45, 28, 35, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 12,204,212,
+ 63, 23, 32,188, 63, 5,225, 29, 63, 22,209,233, 63, 9,105,118, 63, 11,116,101, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 9,105,118, 63, 11,116,101,
+ 63, 16, 48, 43, 63, 11,116,100, 63, 12,204,212, 63, 23, 32,188, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 19,184,140, 63, 22,209,232, 63, 12,204,212,
+ 63, 23, 32,188, 63, 16, 48, 43, 63, 11,116,100, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 16, 48, 43, 63, 11,116,100, 63, 9,105,118, 63, 11,116,101,
+ 63, 12,204,205, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 19, 51, 51, 63, 0, 1,244, 63, 25,153,155, 63, 0, 0, 0, 63, 22,183, 43,
+ 63, 11,111,149, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 22,183, 43, 63, 11,111,149, 63, 16, 48, 43, 63, 11,116,100, 63, 19, 51, 51, 63, 0, 1,244,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 12,204,205, 63, 0, 0, 0, 63, 19, 51, 51, 63, 0, 1,244, 63, 16, 48, 43, 63, 11,116,100, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 16, 48, 43, 63, 11,116,100, 63, 22,183, 43, 63, 11,111,149, 63, 19,184,140, 63, 22,209,232, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 6,102,102,
+ 63, 0, 1,244, 63, 12,204,205, 63, 0, 0, 0, 63, 9,105,118, 63, 11,116,101, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 9,105,118, 63, 11,116,101,
+ 63, 2,226,118, 63, 11,111,149, 63, 6,102,102, 63, 0, 1,244, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 63, 6,102,102,
+ 63, 0, 1,244, 63, 2,226,118, 63, 11,111,149, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 2,226,118, 63, 11,111,149, 63, 9,105,118, 63, 11,116,101,
+ 63, 5,225, 29, 63, 22,209,233, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 12,204,198, 62,217, 58, 72, 63, 6, 10, 77, 62,217,196, 6, 63, 9, 72, 17,
+ 62,198,230,227, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 9, 72, 17, 62,198,230,227, 63, 16, 81,117, 62,198,230,223, 63, 12,204,198, 62,217, 58, 72,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 19,143, 64, 62,217,196, 4, 63, 12,204,198, 62,217, 58, 72, 63, 16, 81,117, 62,198,230,223, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 16, 81,117, 62,198,230,223, 63, 9, 72, 17, 62,198,230,227, 63, 12,204,191, 62,180,111,160, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 12,204,198,
+ 62,217, 58, 72, 63, 19,143, 64, 62,217,196, 4, 63, 16, 33, 76, 62,236,211, 30, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 16, 33, 76, 62,236,211, 30,
+ 63, 9,120, 71, 62,236,211, 30, 63, 12,204,198, 62,217, 58, 72, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 6, 10, 77, 62,217,196, 6, 63, 12,204,198,
+ 62,217, 58, 72, 63, 9,120, 71, 62,236,211, 30, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 9,120, 71, 62,236,211, 30, 63, 16, 33, 76, 62,236,211, 30,
+ 63, 12,204,205, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 6,102,102, 63, 0, 1,244, 63, 0, 0, 0, 63, 0, 0, 0, 63, 2,251, 62,
+ 62,236,207, 67, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 2,251, 62, 62,236,207, 67, 63, 9,120, 71, 62,236,211, 30, 63, 6,102,102, 63, 0, 1,244,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 12,204,205, 63, 0, 0, 0, 63, 6,102,102, 63, 0, 1,244, 63, 9,120, 71, 62,236,211, 30, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 9,120, 71, 62,236,211, 30, 63, 2,251, 62, 62,236,207, 67, 63, 6, 10, 77, 62,217,196, 6, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 19, 51, 51,
+ 63, 0, 1,244, 63, 12,204,205, 63, 0, 0, 0, 63, 16, 33, 76, 62,236,211, 30, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 16, 33, 76, 62,236,211, 30,
+ 63, 22,158, 86, 62,236,207, 65, 63, 19, 51, 51, 63, 0, 1,244, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 25,153,155, 63, 0, 0, 0, 63, 19, 51, 51,
+ 63, 0, 1,244, 63, 22,158, 86, 62,236,207, 65, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 22,158, 86, 62,236,207, 65, 63, 16, 33, 76, 62,236,211, 30,
+ 63, 19,143, 64, 62,217,196, 4, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,255,197,233, 63, 21, 48, 39, 62,243,235,101, 63, 19, 29,252, 62,250, 9,132,
+ 63, 9,152, 94, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,250, 9,132, 63, 9,152, 94, 63, 2,226,118, 63, 11,111,149, 62,255,197,233, 63, 21, 48, 39,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 5,225, 29, 63, 22,209,233, 62,255,197,233, 63, 21, 48, 39, 63, 2,226,118, 63, 11,111,149, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 2,226,118, 63, 11,111,149, 62,250, 9,132, 63, 9,152, 94, 63, 0, 0, 0, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,255,197,233,
+ 63, 21, 48, 39, 63, 5,225, 29, 63, 22,209,233, 63, 2,241, 43, 63, 33, 23,181, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 2,241, 43, 63, 33, 23,181,
+ 62,249, 69,225, 63, 31, 60,110, 62,255,197,233, 63, 21, 48, 39, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,243,235,101, 63, 19, 29,252, 62,255,197,233,
+ 63, 21, 48, 39, 62,249, 69,225, 63, 31, 60,110, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,249, 69,225, 63, 31, 60,110, 63, 2,241, 43, 63, 33, 23,181,
+ 62,255, 86, 30, 63, 43, 52,230, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,242,161, 9, 63, 40,228,223, 62,230,102,129, 63, 37,200, 48, 62,237,111,222,
+ 63, 28,140,143, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,237,111,222, 63, 28,140,143, 62,249, 69,225, 63, 31, 60,110, 62,242,161, 9, 63, 40,228,223,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,255, 86, 30, 63, 43, 52,230, 62,242,161, 9, 63, 40,228,223, 62,249, 69,225, 63, 31, 60,110, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,249, 69,225, 63, 31, 60,110, 62,237,111,222, 63, 28,140,143, 62,243,235,101, 63, 19, 29,252, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 6, 46, 46,
+ 63, 44,160,211, 62,255, 86, 30, 63, 43, 52,230, 63, 2,241, 43, 63, 33, 23,181, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 2,241, 43, 63, 33, 23,181,
+ 63, 9, 33,207, 63, 34, 17,226, 63, 6, 46, 46, 63, 44,160,211, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 12,204,220, 63, 45, 28, 35, 63, 6, 46, 46,
+ 63, 44,160,211, 63, 9, 33,207, 63, 34, 17,226, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 9, 33,207, 63, 34, 17,226, 63, 2,241, 43, 63, 33, 23,181,
+ 63, 5,225, 29, 63, 22,209,233, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 85,238,138, 62,187,220, 72, 63, 82,173,218, 62,210, 92, 55, 63, 79,189,229,
+ 62,189,208,173, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 79,189,229, 62,189,208,173, 63, 82,250,230, 62,166,190,117, 63, 85,238,138, 62,187,220, 72,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 89,153,149, 62,165,199,201, 63, 85,238,138, 62,187,220, 72, 63, 82,250,230, 62,166,190,117, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 82,250,230, 62,166,190,117, 63, 79,189,229, 62,189,208,173, 63, 76,119,198, 62,169,150, 90, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 73,111,170,
+ 62,193,135, 68, 63, 76,119,198, 62,169,150, 90, 63, 79,189,229, 62,189,208,173, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 79,189,229, 62,189,208,173,
+ 63, 76,175,176, 62,213,159,192, 63, 73,111,170, 62,193,135, 68, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 70,194,112, 62,217,196, 19, 63, 73,111,170,
+ 62,193,135, 68, 63, 76,175,176, 62,213,159,192, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 76,175,176, 62,213,159,192, 63, 79,189,229, 62,189,208,173,
+ 63, 82,173,218, 62,210, 92, 55, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 79,175, 52, 62,233, 32,218, 63, 76,204,193, 63, 0, 0, 0, 63, 73,209,128,
+ 62,236,207, 75, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 73,209,128, 62,236,207, 75, 63, 76,175,176, 62,213,159,192, 63, 79,175, 52, 62,233, 32,218,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 82,173,218, 62,210, 92, 55, 63, 79,175, 52, 62,233, 32,218, 63, 76,175,176, 62,213,159,192, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 76,175,176, 62,213,159,192, 63, 73,209,128, 62,236,207, 75, 63, 70,194,112, 62,217,196, 19, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 73,111,170,
+ 62,193,135, 68, 63, 70,194,112, 62,217,196, 19, 63, 67,132,171, 62,198,230,253, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 67,132,171, 62,198,230,253,
+ 63, 70, 29, 61, 62,174, 54,114, 63, 73,111,170, 62,193,135, 68, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 76,119,198, 62,169,150, 90, 63, 73,111,170,
+ 62,193,135, 68, 63, 70, 29, 61, 62,174, 54,114, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 70, 29, 61, 62,174, 54,114, 63, 67,132,171, 62,198,230,253,
+ 63, 64, 0, 0, 62,180,111,211, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 79,175, 52, 62,233, 32,218, 63, 82,173,218, 62,210, 92, 55, 63, 86, 54, 56,
+ 62,233, 23, 58, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 86, 54, 56, 62,233, 23, 58, 63, 83, 51, 41, 62,255,252, 24, 63, 79,175, 52, 62,233, 32,218,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 76,204,193, 63, 0, 0, 0, 63, 79,175, 52, 62,233, 32,218, 63, 83, 51, 41, 62,255,252, 24, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 83, 51, 41, 62,255,252, 24, 63, 86, 54, 56, 62,233, 23, 58, 63, 89,153,147, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 92,252,239,
+ 62,233, 23, 58, 63, 89,153,147, 63, 0, 0, 0, 63, 86, 54, 56, 62,233, 23, 58, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 86, 54, 56, 62,233, 23, 58,
+ 63, 89,153,147, 62,209,190,143, 63, 92,252,239, 62,233, 23, 58, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 96,133, 78, 62,210, 92, 55, 63, 92,252,239,
+ 62,233, 23, 58, 63, 89,153,147, 62,209,190,143, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 89,153,147, 62,209,190,143, 63, 86, 54, 56, 62,233, 23, 58,
+ 63, 82,173,218, 62,210, 92, 55, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 85,238,138, 62,187,220, 72, 63, 89,153,149, 62,165,199,201, 63, 93, 68,159,
+ 62,187,220, 72, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 93, 68,159, 62,187,220, 72, 63, 89,153,147, 62,209,190,143, 63, 85,238,138, 62,187,220, 72,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 82,173,218, 62,210, 92, 55, 63, 85,238,138, 62,187,220, 72, 63, 89,153,147, 62,209,190,143, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 89,153,147, 62,209,190,143, 63, 93, 68,159, 62,187,220, 72, 63, 96,133, 78, 62,210, 92, 55, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 92,252,239,
+ 62,233, 23, 58, 63, 96,133, 78, 62,210, 92, 55, 63, 99,131,242, 62,233, 32,218, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 99,131,242, 62,233, 32,218,
+ 63, 95,255,254, 62,255,252, 24, 63, 92,252,239, 62,233, 23, 58, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 89,153,147, 63, 0, 0, 0, 63, 92,252,239,
+ 62,233, 23, 58, 63, 95,255,254, 62,255,252, 24, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 95,255,254, 62,255,252, 24, 63, 99,131,242, 62,233, 32,218,
+ 63,102,102,101, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,111,174,139, 62,198,230,223, 63,108,112,192, 62,217,196, 4, 63,105,195,133,
+ 62,193,135, 37, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,105,195,133, 62,193,135, 37, 63,109, 21,249, 62,174, 54, 65, 63,111,174,139, 62,198,230,223,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,115, 51, 65, 62,180,111,160, 63,111,174,139, 62,198,230,223, 63,109, 21,249, 62,174, 54, 65, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,109, 21,249, 62,174, 54, 65, 63,105,195,133, 62,193,135, 37, 63,102,187,106, 62,169,150, 54, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 99,117, 70,
+ 62,189,208,155, 63,102,187,106, 62,169,150, 54, 63,105,195,133, 62,193,135, 37, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,105,195,133, 62,193,135, 37,
+ 63,102,131,123, 62,213,159,181, 63, 99,117, 70, 62,189,208,155, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 96,133, 78, 62,210, 92, 55, 63, 99,117, 70,
+ 62,189,208,155, 63,102,131,123, 62,213,159,181, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,102,131,123, 62,213,159,181, 63,105,195,133, 62,193,135, 37,
+ 63,108,112,192, 62,217,196, 4, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,105, 97,170, 62,236,207, 65, 63,102,102,101, 63, 0, 0, 0, 63, 99,131,242,
+ 62,233, 32,218, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 99,131,242, 62,233, 32,218, 63,102,131,123, 62,213,159,181, 63,105, 97,170, 62,236,207, 65,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,108,112,192, 62,217,196, 4, 63,105, 97,170, 62,236,207, 65, 63,102,131,123, 62,213,159,181, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,102,131,123, 62,213,159,181, 63, 99,131,242, 62,233, 32,218, 63, 96,133, 78, 62,210, 92, 55, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 99,117, 70,
+ 62,189,208,155, 63, 96,133, 78, 62,210, 92, 55, 63, 93, 68,159, 62,187,220, 72, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 93, 68,159, 62,187,220, 72,
+ 63, 96, 56, 71, 62,166,190, 99, 63, 99,117, 70, 62,189,208,155, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,102,187,106, 62,169,150, 54, 63, 99,117, 70,
+ 62,189,208,155, 63, 96, 56, 71, 62,166,190, 99, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 96, 56, 71, 62,166,190, 99, 63, 93, 68,159, 62,187,220, 72,
+ 63, 89,153,149, 62,165,199,201, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 99,107, 33, 63, 9,152, 94, 63, 96, 92, 11, 63, 19, 29,253, 63, 92,238, 21,
+ 63, 9,150,112, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 92,238, 21, 63, 9,150,112, 63, 95,255,254, 62,255,252, 24, 63, 99,107, 33, 63, 9,152, 94,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,102,102,101, 63, 0, 0, 0, 63, 99,107, 33, 63, 9,152, 94, 63, 95,255,254, 62,255,252, 24, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 95,255,254, 62,255,252, 24, 63, 92,238, 21, 63, 9,150,112, 63, 89,153,147, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 86, 69, 14,
+ 63, 9,150,112, 63, 89,153,147, 63, 0, 0, 0, 63, 92,238, 21, 63, 9,150,112, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 92,238, 21, 63, 9,150,112,
+ 63, 89,153,143, 63, 19, 98,219, 63, 86, 69, 14, 63, 9,150,112, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 82,215, 19, 63, 19, 29,252, 63, 86, 69, 14,
+ 63, 9,150,112, 63, 89,153,143, 63, 19, 98,219, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 89,153,143, 63, 19, 98,219, 63, 92,238, 21, 63, 9,150,112,
+ 63, 96, 92, 11, 63, 19, 29,253, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 93, 30, 63, 63, 28,140,143, 63, 89,153,139, 63, 37,200, 45, 63, 86, 20,218,
+ 63, 28,140,143, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 86, 20,218, 63, 28,140,143, 63, 89,153,143, 63, 19, 98,219, 63, 93, 30, 63, 63, 28,140,143,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 96, 92, 11, 63, 19, 29,253, 63, 93, 30, 63, 63, 28,140,143, 63, 89,153,143, 63, 19, 98,219, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 89,153,143, 63, 19, 98,219, 63, 86, 20,218, 63, 28,140,143, 63, 82,215, 19, 63, 19, 29,252, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 86, 69, 14,
+ 63, 9,150,112, 63, 82,215, 19, 63, 19, 29,252, 63, 79,200, 1, 63, 9,152, 94, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 79,200, 1, 63, 9,152, 94,
+ 63, 83, 51, 41, 62,255,252, 24, 63, 86, 69, 14, 63, 9,150,112, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 89,153,147, 63, 0, 0, 0, 63, 86, 69, 14,
+ 63, 9,150,112, 63, 83, 51, 41, 62,255,252, 24, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 83, 51, 41, 62,255,252, 24, 63, 79,200, 1, 63, 9,152, 94,
+ 63, 76,204,193, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61, 18, 28,237, 62,187,220, 60, 60,188, 35,151, 62,210, 92, 46, 60, 60, 74,218,
+ 62,189,208,150, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 60, 60, 74,218, 62,189,208,150, 60,197,197,195, 62,166,190, 89, 61, 18, 28,237, 62,187,220, 60,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 61, 76,205,194, 62,165,199,186, 61, 18, 28,237, 62,187,220, 60, 60,197,197,195, 62,166,190, 89, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,131, 23, 23, 62,166,190, 89, 63,129,120,150, 62,189,208,150, 63,127,171, 15, 62,169,150, 52, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,124,162,241,
+ 62,193,135, 36, 63,127,171, 15, 62,169,150, 52, 63,129,120,150, 62,189,208,150, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,129,120,150, 62,189,208,150,
+ 63,127,226,244, 62,213,159,179, 63,124,162,241, 62,193,135, 36, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,121,245,179, 62,217,196, 6, 63,124,162,241,
+ 62,193,135, 36, 63,127,226,244, 62,213,159,179, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,127,226,244, 62,213,159,179, 63,129,120,150, 62,189,208,150,
+ 63,130,240,142, 62,210, 92, 46, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,129,113, 59, 62,233, 32,214, 63,128, 0, 0, 63, 0, 0, 0, 63,125, 4,194,
+ 62,236,207, 67, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,125, 4,194, 62,236,207, 67, 63,127,226,244, 62,213,159,179, 63,129,113, 59, 62,233, 32,214,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,130,240,142, 62,210, 92, 46, 63,129,113, 59, 62,233, 32,214, 63,127,226,244, 62,213,159,179, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,127,226,244, 62,213,159,179, 63,125, 4,194, 62,236,207, 67, 63,121,245,179, 62,217,196, 6, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,124,162,241,
+ 62,193,135, 36, 63,121,245,179, 62,217,196, 6, 63,118,183,239, 62,198,230,227, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,118,183,239, 62,198,230,227,
+ 63,121, 80,133, 62,174, 54, 65, 63,124,162,241, 62,193,135, 36, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,127,171, 15, 62,169,150, 52, 63,124,162,241,
+ 62,193,135, 36, 63,121, 80,133, 62,174, 54, 65, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,121, 80,133, 62,174, 54, 65, 63,118,183,239, 62,198,230,227,
+ 63,115, 51, 65, 62,180,111,160, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 60, 56,157,110, 62,233, 32,214, 60,188, 35,151, 62,210, 92, 46, 61, 22,151, 95,
+ 62,233, 23, 55, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 61, 22,151, 95, 62,233, 23, 55, 60,204,204,176, 62,255,252, 24, 60, 56,157,110, 62,233, 32,214,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 38, 11, 79,167, 63, 0, 0, 0, 60, 56,157,110, 62,233, 32,214, 60,204,204,176, 62,255,252, 24, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 60,204,204,176, 62,255,252, 24, 61, 22,151, 95, 62,233, 23, 55, 61, 76,204,215, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,129,129, 87,
+ 62,233, 23, 57, 61, 76,204,215, 63, 0, 0, 0, 61, 22,151, 95, 62,233, 23, 55, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61, 22,151, 95, 62,233, 23, 55,
+ 61, 76,205, 68, 62,209,190,135, 61,129,129, 87, 62,233, 23, 57, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,157,196, 92, 62,210, 92, 49, 61,129,129, 87,
+ 62,233, 23, 57, 61, 76,205, 68, 62,209,190,135, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61, 76,205, 68, 62,209,190,135, 61, 22,151, 95, 62,233, 23, 55,
+ 60,188, 35,151, 62,210, 92, 46, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61, 18, 28,237, 62,187,220, 60, 61, 76,205,194, 62,165,199,186, 61,131,191, 7,
+ 62,187,220, 62, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 61,131,191, 7, 62,187,220, 62, 61, 76,205, 68, 62,209,190,135, 61, 18, 28,237, 62,187,220, 60,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 60,188, 35,151, 62,210, 92, 46, 61, 18, 28,237, 62,187,220, 60, 61, 76,205, 68, 62,209,190,135, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 61, 76,205, 68, 62,209,190,135, 61,131,191, 7, 62,187,220, 62, 61,157,196, 92, 62,210, 92, 49, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,129,129, 87,
+ 62,233, 23, 57, 61,157,196, 92, 62,210, 92, 49, 61,181,185, 89, 62,233, 32,214, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,181,185, 89, 62,233, 32,214,
+ 61,153,153,154, 62,255,252, 25, 61,129,129, 87, 62,233, 23, 57, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61, 76,204,215, 63, 0, 0, 0, 61,129,129, 87,
+ 62,233, 23, 57, 61,153,153,154, 62,255,252, 25, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,153,153,154, 62,255,252, 25, 61,181,185, 89, 62,233, 32,214,
+ 61,204,204,215, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 11,135, 1, 62,198,230,228, 61,253, 31,171, 62,217,196, 6, 61,231,181,251,
+ 62,193,135, 38, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 61,231,181,251, 62,193,135, 38, 62, 1, 36,204, 62,174, 54, 70, 62, 11,135, 1, 62,198,230,228,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62, 25,153,214, 62,180,111,165, 62, 11,135, 1, 62,198,230,228, 62, 1, 36,204, 62,174, 54, 70, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62, 1, 36,204, 62,174, 54, 70, 61,231,181,251, 62,193,135, 38, 61,207,117, 70, 62,169,150, 54, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,181, 68, 35,
+ 62,189,208,153, 61,207,117, 70, 62,169,150, 54, 61,231,181,251, 62,193,135, 38, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,231,181,251, 62,193,135, 38,
+ 61,205,181,164, 62,213,159,180, 61,181, 68, 35, 62,189,208,153, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,157,196, 92, 62,210, 92, 49, 61,181, 68, 35,
+ 62,189,208,153, 61,205,181,164, 62,213,159,180, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,205,181,164, 62,213,159,180, 61,231,181,251, 62,193,135, 38,
+ 61,253, 31,171, 62,217,196, 6, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,228,166,251, 62,236,207, 67, 61,204,204,215, 63, 0, 0, 0, 61,181,185, 89,
+ 62,233, 32,214, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 61,181,185, 89, 62,233, 32,214, 61,205,181,164, 62,213,159,180, 61,228,166,251, 62,236,207, 67,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 61,253, 31,171, 62,217,196, 6, 61,228,166,251, 62,236,207, 67, 61,205,181,164, 62,213,159,180, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 61,205,181,164, 62,213,159,180, 61,181,185, 89, 62,233, 32,214, 61,157,196, 92, 62,210, 92, 49, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,181, 68, 35,
+ 62,189,208,153, 61,157,196, 92, 62,210, 92, 49, 61,131,191, 7, 62,187,220, 62, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,131,191, 7, 62,187,220, 62,
+ 61,155, 92, 79, 62,166,190, 91, 61,181, 68, 35, 62,189,208,153, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,207,117, 70, 62,169,150, 54, 61,181, 68, 35,
+ 62,189,208,153, 61,155, 92, 79, 62,166,190, 91, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,155, 92, 79, 62,166,190, 91, 61,131,191, 7, 62,187,220, 62,
+ 61, 76,205,194, 62,165,199,186, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,180,242,172, 63, 9,152, 96, 61,156,122, 1, 63, 19, 29,254, 61,129, 10,100,
+ 63, 9,150,113, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 61,129, 10,100, 63, 9,150,113, 61,153,153,154, 62,255,252, 25, 61,180,242,172, 63, 9,152, 96,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 61,204,204,215, 63, 0, 0, 0, 61,180,242,172, 63, 9,152, 96, 61,153,153,154, 62,255,252, 25, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 61,153,153,154, 62,255,252, 25, 61,129, 10,100, 63, 9,150,113, 61, 76,204,215, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61, 23,132,109,
+ 63, 9,150,113, 61, 76,204,215, 63, 0, 0, 0, 61,129, 10,100, 63, 9,150,113, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,129, 10,100, 63, 9,150,113,
+ 61, 76,204, 91, 63, 19, 98,220, 61, 23,132,109, 63, 9,150,113, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 60,193, 73,174, 63, 19, 29,253, 61, 23,132,109,
+ 63, 9,150,113, 61, 76,204, 91, 63, 19, 98,220, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61, 76,204, 91, 63, 19, 98,220, 61,129, 10,100, 63, 9,150,113,
+ 61,156,122, 1, 63, 19, 29,254, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,130,139,166, 63, 28,140,145, 61, 76,203,246, 63, 37,200, 48, 61, 20,129, 13,
+ 63, 28,140,143, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 61, 20,129, 13, 63, 28,140,143, 61, 76,204, 91, 63, 19, 98,220, 61,130,139,166, 63, 28,140,145,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 61,156,122, 1, 63, 19, 29,254, 61,130,139,166, 63, 28,140,145, 61, 76,204, 91, 63, 19, 98,220, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 61, 76,204, 91, 63, 19, 98,220, 61, 20,129, 13, 63, 28,140,143, 60,193, 73,174, 63, 19, 29,253, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61, 23,132,109,
+ 63, 9,150,113, 60,193, 73,174, 63, 19, 29,253, 60, 62,207,114, 63, 9,152, 94, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 60, 62,207,114, 63, 9,152, 94,
+ 60,204,204,176, 62,255,252, 24, 61, 23,132,109, 63, 9,150,113, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61, 76,204,215, 63, 0, 0, 0, 61, 23,132,109,
+ 63, 9,150,113, 60,204,204,176, 62,255,252, 24, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 60,204,204,176, 62,255,252, 24, 60, 62,207,114, 63, 9,152, 94,
+ 38, 11, 79,167, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,113, 83,237, 62,187,220, 79, 62,100, 81, 63, 62,210, 92, 60, 62, 88,145,110,
+ 62,189,208,167, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62, 88,145,110, 62,189,208,167, 62,101,133, 91, 62,166,190,112, 62,113, 83,237, 62,187,220, 79,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,128, 0, 0, 62,165,199,206, 62,113, 83,237, 62,187,220, 79, 62,101,133, 91, 62,166,190,112, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,101,133, 91, 62,166,190,112, 62, 88,145,110, 62,189,208,167, 62, 75,120,239, 62,169,150, 70, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 63, 88,144,
+ 62,193,135, 46, 62, 75,120,239, 62,169,150, 70, 62, 88,145,110, 62,189,208,167, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 88,145,110, 62,189,208,167,
+ 62, 76, 88,170, 62,213,159,187, 62, 63, 88,144, 62,193,135, 46, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 52,163,179, 62,217,196, 7, 62, 63, 88,144,
+ 62,193,135, 46, 62, 76, 88,170, 62,213,159,187, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 76, 88,170, 62,213,159,187, 62, 88,145,110, 62,189,208,167,
+ 62,100, 81, 63, 62,210, 92, 60, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 88, 86,190, 62,233, 32,221, 62, 76,204,254, 63, 0, 0, 0, 62, 64,223,251,
+ 62,236,207, 67, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62, 64,223,251, 62,236,207, 67, 62, 76, 88,170, 62,213,159,187, 62, 88, 86,190, 62,233, 32,221,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,100, 81, 63, 62,210, 92, 60, 62, 88, 86,190, 62,233, 32,221, 62, 76, 88,170, 62,213,159,187, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62, 76, 88,170, 62,213,159,187, 62, 64,223,251, 62,236,207, 67, 62, 52,163,179, 62,217,196, 7, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 63, 88,144,
+ 62,193,135, 46, 62, 52,163,179, 62,217,196, 7, 62, 39,172,153, 62,198,230,230, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 39,172,153, 62,198,230,230,
+ 62, 50, 14,213, 62,174, 54, 78, 62, 63, 88,144, 62,193,135, 46, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 75,120,239, 62,169,150, 70, 62, 63, 88,144,
+ 62,193,135, 46, 62, 50, 14,213, 62,174, 54, 78, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 50, 14,213, 62,174, 54, 78, 62, 39,172,153, 62,198,230,230,
+ 62, 25,153,214, 62,180,111,165, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 88, 86,190, 62,233, 32,221, 62,100, 81, 63, 62,210, 92, 60, 62,114,114,166,
+ 62,233, 23, 63, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,114,114,166, 62,233, 23, 63, 62,102,102,126, 62,255,252, 25, 62, 88, 86,190, 62,233, 32,221,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62, 76,204,254, 63, 0, 0, 0, 62, 88, 86,190, 62,233, 32,221, 62,102,102,126, 62,255,252, 25, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,102,102,126, 62,255,252, 25, 62,114,114,166, 62,233, 23, 63, 62,128, 0, 0, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,134,198,173,
+ 62,233, 23, 63, 62,128, 0, 0, 63, 0, 0, 0, 62,114,114,166, 62,233, 23, 63, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,114,114,166, 62,233, 23, 63,
+ 62,128, 0, 0, 62,209,190,149, 62,134,198,173, 62,233, 23, 63, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,141,215, 97, 62,210, 92, 60, 62,134,198,173,
+ 62,233, 23, 63, 62,128, 0, 0, 62,209,190,149, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,128, 0, 0, 62,209,190,149, 62,114,114,166, 62,233, 23, 63,
+ 62,100, 81, 63, 62,210, 92, 60, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,113, 83,237, 62,187,220, 79, 62,128, 0, 0, 62,165,199,206, 62,135, 86, 9,
+ 62,187,220, 79, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,135, 86, 9, 62,187,220, 79, 62,128, 0, 0, 62,209,190,149, 62,113, 83,237, 62,187,220, 79,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,100, 81, 63, 62,210, 92, 60, 62,113, 83,237, 62,187,220, 79, 62,128, 0, 0, 62,209,190,149, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,128, 0, 0, 62,209,190,149, 62,135, 86, 9, 62,187,220, 79, 62,141,215, 97, 62,210, 92, 60, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,134,198,173,
+ 62,233, 23, 63, 62,141,215, 97, 62,210, 92, 60, 62,147,212,161, 62,233, 32,221, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,147,212,161, 62,233, 32,221,
+ 62,140,204,193, 62,255,252, 25, 62,134,198,173, 62,233, 23, 63, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,128, 0, 0, 63, 0, 0, 0, 62,134,198,173,
+ 62,233, 23, 63, 62,140,204,193, 62,255,252, 25, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,140,204,193, 62,255,252, 25, 62,147,212,161, 62,233, 32,221,
+ 62,153,153,129, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,172, 41,180, 62,198,230,227, 62,165,174, 39, 62,217,196, 7, 62,160, 83,184,
+ 62,193,135, 46, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,160, 83,184, 62,193,135, 46, 62,166,248,150, 62,174, 54, 78, 62,172, 41,180, 62,198,230,227,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,179, 51, 21, 62,180,111,165, 62,172, 41,180, 62,198,230,227, 62,166,248,150, 62,174, 54, 78, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,166,248,150, 62,174, 54, 78, 62,160, 83,184, 62,193,135, 46, 62,154, 67,137, 62,169,150, 70, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,147,183, 73,
+ 62,189,208,167, 62,154, 67,137, 62,169,150, 70, 62,160, 83,184, 62,193,135, 46, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,160, 83,184, 62,193,135, 46,
+ 62,153,211,171, 62,213,159,187, 62,147,183, 73, 62,189,208,167, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,141,215, 97, 62,210, 92, 60, 62,147,183, 73,
+ 62,189,208,167, 62,153,211,171, 62,213,159,187, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,153,211,171, 62,213,159,187, 62,160, 83,184, 62,193,135, 46,
+ 62,165,174, 39, 62,217,196, 7, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,159,144, 3, 62,236,207, 67, 62,153,153,129, 63, 0, 0, 0, 62,147,212,161,
+ 62,233, 32,221, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,147,212,161, 62,233, 32,221, 62,153,211,171, 62,213,159,187, 62,159,144, 3, 62,236,207, 67,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,165,174, 39, 62,217,196, 7, 62,159,144, 3, 62,236,207, 67, 62,153,211,171, 62,213,159,187, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,153,211,171, 62,213,159,187, 62,147,212,161, 62,233, 32,221, 62,141,215, 97, 62,210, 92, 60, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,147,183, 73,
+ 62,189,208,167, 62,141,215, 97, 62,210, 92, 60, 62,135, 86, 9, 62,187,220, 79, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,135, 86, 9, 62,187,220, 79,
+ 62,141, 61, 82, 62,166,190,112, 62,147,183, 73, 62,189,208,167, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,154, 67,137, 62,169,150, 70, 62,147,183, 73,
+ 62,189,208,167, 62,141, 61, 82, 62,166,190,112, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,141, 61, 82, 62,166,190,112, 62,135, 86, 9, 62,187,220, 79,
+ 62,128, 0, 0, 62,165,199,206, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,147,163, 1, 63, 9,152, 91, 62,141,132,224, 63, 19, 29,246, 62,134,168,251,
+ 63, 9,150,107, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,134,168,251, 63, 9,150,107, 62,140,204,193, 62,255,252, 25, 62,147,163, 1, 63, 9,152, 91,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,153,153,129, 63, 0, 0, 0, 62,147,163, 1, 63, 9,152, 91, 62,140,204,193, 62,255,252, 25, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,140,204,193, 62,255,252, 25, 62,134,168,251, 63, 9,150,107, 62,128, 0, 0, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,114,174, 11,
+ 63, 9,150,107, 62,128, 0, 0, 63, 0, 0, 0, 62,134,168,251, 63, 9,150,107, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,134,168,251, 63, 9,150,107,
+ 62,128, 0, 0, 63, 19, 98,209, 62,114,174, 11, 63, 9,150,107, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,100,246, 64, 63, 19, 29,246, 62,114,174, 11,
+ 63, 9,150,107, 62,128, 0, 0, 63, 19, 98,209, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,128, 0, 0, 63, 19, 98,209, 62,134,168,251, 63, 9,150,107,
+ 62,141,132,224, 63, 19, 29,246, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,135, 9, 86, 63, 28,140,130, 62,128, 0, 0, 63, 37,200, 23, 62,113,237, 83,
+ 63, 28,140,130, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,113,237, 83, 63, 28,140,130, 62,128, 0, 0, 63, 19, 98,209, 62,135, 9, 86, 63, 28,140,130,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,141,132,224, 63, 19, 29,246, 62,135, 9, 86, 63, 28,140,130, 62,128, 0, 0, 63, 19, 98,209, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,128, 0, 0, 63, 19, 98,209, 62,113,237, 83, 63, 28,140,130, 62,100,246, 64, 63, 19, 29,246, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,114,174, 11,
+ 63, 9,150,107, 62,100,246, 64, 63, 19, 29,246, 62, 88,185,255, 63, 9,152, 90, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 88,185,255, 63, 9,152, 90,
+ 62,102,102,126, 62,255,252, 25, 62,114,174, 11, 63, 9,150,107, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,128, 0, 0, 63, 0, 0, 0, 62,114,174, 11,
+ 63, 9,150,107, 62,102,102,126, 62,255,252, 25, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,102,102,126, 62,255,252, 25, 62, 88,185,255, 63, 9,152, 90,
+ 62, 76,204,254, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,223, 16, 63, 62,187,220, 62, 62,216,142,233, 62,210, 92, 49, 62,210,174,248,
+ 62,189,208,153, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,210,174,248, 62,189,208,153, 62,217, 40,237, 62,166,190, 91, 62,223, 16, 63, 62,187,220, 62,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,230,102, 72, 62,165,199,183, 62,223, 16, 63, 62,187,220, 62, 62,217, 40,237, 62,166,190, 91, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,217, 40,237, 62,166,190, 91, 62,210,174,248, 62,189,208,153, 62,204, 34,175, 62,169,150, 54, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,198, 18,129,
+ 62,193,135, 37, 62,204, 34,175, 62,169,150, 54, 62,210,174,248, 62,189,208,153, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,210,174,248, 62,189,208,153,
+ 62,204,146,151, 62,213,159,180, 62,198, 18,129, 62,193,135, 37, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,192,184, 21, 62,217,196, 6, 62,198, 18,129,
+ 62,193,135, 37, 62,204,146,151, 62,213,159,180, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,204,146,151, 62,213,159,180, 62,210,174,248, 62,189,208,153,
+ 62,216,142,233, 62,210, 92, 49, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,210,145,170, 62,233, 32,214, 62,204,204,202, 63, 0, 0, 0, 62,198,214, 65,
+ 62,236,207, 67, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,198,214, 65, 62,236,207, 67, 62,204,146,151, 62,213,159,180, 62,210,145,170, 62,233, 32,214,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,216,142,233, 62,210, 92, 49, 62,210,145,170, 62,233, 32,214, 62,204,146,151, 62,213,159,180, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,204,146,151, 62,213,159,180, 62,198,214, 65, 62,236,207, 67, 62,192,184, 21, 62,217,196, 6, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,198, 18,129,
+ 62,193,135, 37, 62,192,184, 21, 62,217,196, 6, 62,186, 60,127, 62,198,230,225, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,186, 60,127, 62,198,230,225,
+ 62,191,109,154, 62,174, 54, 68, 62,198, 18,129, 62,193,135, 37, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,204, 34,175, 62,169,150, 54, 62,198, 18,129,
+ 62,193,135, 37, 62,191,109,154, 62,174, 54, 68, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,191,109,154, 62,174, 54, 68, 62,186, 60,127, 62,198,230,225,
+ 62,179, 51, 21, 62,180,111,165, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,210,145,170, 62,233, 32,214, 62,216,142,233, 62,210, 92, 49, 62,223,159,171,
+ 62,233, 23, 57, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,223,159,171, 62,233, 23, 57, 62,217,153,154, 62,255,252, 24, 62,210,145,170, 62,233, 32,214,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,204,204,202, 63, 0, 0, 0, 62,210,145,170, 62,233, 32,214, 62,217,153,154, 62,255,252, 24, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,217,153,154, 62,255,252, 24, 62,223,159,171, 62,233, 23, 57, 62,230,102,101, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,237, 45, 20,
+ 62,233, 23, 55, 62,230,102,101, 63, 0, 0, 0, 62,223,159,171, 62,233, 23, 57, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,223,159,171, 62,233, 23, 57,
+ 62,230,102, 88, 62,209,190,135, 62,237, 45, 20, 62,233, 23, 55, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,244, 61,199, 62,210, 92, 46, 62,237, 45, 20,
+ 62,233, 23, 55, 62,230,102, 88, 62,209,190,135, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,230,102, 88, 62,209,190,135, 62,223,159,171, 62,233, 23, 57,
+ 62,216,142,233, 62,210, 92, 49, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,223, 16, 63, 62,187,220, 62, 62,230,102, 72, 62,165,199,183, 62,237,188, 99,
+ 62,187,220, 60, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,237,188, 99, 62,187,220, 60, 62,230,102, 88, 62,209,190,135, 62,223, 16, 63, 62,187,220, 62,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,216,142,233, 62,210, 92, 49, 62,223, 16, 63, 62,187,220, 62, 62,230,102, 88, 62,209,190,135, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,230,102, 88, 62,209,190,135, 62,237,188, 99, 62,187,220, 60, 62,244, 61,199, 62,210, 92, 46, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,237, 45, 20,
+ 62,233, 23, 55, 62,244, 61,199, 62,210, 92, 46, 62,250, 59, 21, 62,233, 32,213, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,250, 59, 21, 62,233, 32,213,
+ 62,243, 51, 53, 62,255,252, 24, 62,237, 45, 20, 62,233, 23, 55, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,230,102,101, 63, 0, 0, 0, 62,237, 45, 20,
+ 62,233, 23, 55, 62,243, 51, 53, 62,255,252, 24, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,243, 51, 53, 62,255,252, 24, 62,250, 59, 21, 62,233, 32,213,
+ 63, 0, 0, 0, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 9, 72, 17, 62,198,230,227, 63, 6, 10, 77, 62,217,196, 6, 63, 3, 93, 15,
+ 62,193,135, 36, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 3, 93, 15, 62,193,135, 36, 63, 6,175,123, 62,174, 54, 65, 63, 9, 72, 17, 62,198,230,227,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 12,204,191, 62,180,111,160, 63, 9, 72, 17, 62,198,230,227, 63, 6,175,123, 62,174, 54, 65, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 6,175,123, 62,174, 54, 65, 63, 3, 93, 15, 62,193,135, 36, 63, 0, 84,241, 62,169,150, 52, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,250, 29,169,
+ 62,189,208,150, 63, 0, 84,241, 62,169,150, 52, 63, 3, 93, 15, 62,193,135, 36, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 3, 93, 15, 62,193,135, 36,
+ 63, 0, 29, 12, 62,213,159,179, 62,250, 29,169, 62,189,208,150, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,244, 61,199, 62,210, 92, 46, 62,250, 29,169,
+ 62,189,208,150, 63, 0, 29, 12, 62,213,159,179, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0, 29, 12, 62,213,159,179, 63, 3, 93, 15, 62,193,135, 36,
+ 63, 6, 10, 77, 62,217,196, 6, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 2,251, 62, 62,236,207, 67, 63, 0, 0, 0, 63, 0, 0, 0, 62,250, 59, 21,
+ 62,233, 32,213, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,250, 59, 21, 62,233, 32,213, 63, 0, 29, 12, 62,213,159,179, 63, 2,251, 62, 62,236,207, 67,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 6, 10, 77, 62,217,196, 6, 63, 2,251, 62, 62,236,207, 67, 63, 0, 29, 12, 62,213,159,179, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 0, 29, 12, 62,213,159,179, 62,250, 59, 21, 62,233, 32,213, 62,244, 61,199, 62,210, 92, 46, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,250, 29,169,
+ 62,189,208,150, 62,244, 61,199, 62,210, 92, 46, 62,237,188, 99, 62,187,220, 60, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,237,188, 99, 62,187,220, 60,
+ 62,243,163,164, 62,166,190, 89, 62,250, 29,169, 62,189,208,150, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0, 84,241, 62,169,150, 52, 62,250, 29,169,
+ 62,189,208,150, 62,243,163,164, 62,166,190, 89, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,243,163,164, 62,166,190, 89, 62,237,188, 99, 62,187,220, 60,
+ 62,230,102, 72, 62,165,199,183, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,250, 9,132, 63, 9,152, 94, 62,243,235,101, 63, 19, 29,252, 62,237, 15,114,
+ 63, 9,150,113, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,237, 15,114, 63, 9,150,113, 62,243, 51, 53, 62,255,252, 24, 62,250, 9,132, 63, 9,152, 94,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 0, 0, 0, 63, 0, 0, 0, 62,250, 9,132, 63, 9,152, 94, 62,243, 51, 53, 62,255,252, 24, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,243, 51, 53, 62,255,252, 24, 62,237, 15,114, 63, 9,150,113, 62,230,102,101, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,223,189,103,
+ 63, 9,150,112, 62,230,102,101, 63, 0, 0, 0, 62,237, 15,114, 63, 9,150,113, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,237, 15,114, 63, 9,150,113,
+ 62,230,102,117, 63, 19, 98,220, 62,223,189,103, 63, 9,150,112, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,216,225,128, 63, 19, 29,254, 62,223,189,103,
+ 63, 9,150,112, 62,230,102,117, 63, 19, 98,220, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,230,102,117, 63, 19, 98,220, 62,237, 15,114, 63, 9,150,113,
+ 62,243,235,101, 63, 19, 29,252, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,237,111,222, 63, 28,140,143, 62,230,102,129, 63, 37,200, 48, 62,223, 93, 22,
+ 63, 28,140,145, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,223, 93, 22, 63, 28,140,145, 62,230,102,117, 63, 19, 98,220, 62,237,111,222, 63, 28,140,143,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,243,235,101, 63, 19, 29,252, 62,237,111,222, 63, 28,140,143, 62,230,102,117, 63, 19, 98,220, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,230,102,117, 63, 19, 98,220, 62,223, 93, 22, 63, 28,140,145, 62,216,225,128, 63, 19, 29,254, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,223,189,103,
+ 63, 9,150,112, 62,216,225,128, 63, 19, 29,254, 62,210,195, 85, 63, 9,152, 96, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,210,195, 85, 63, 9,152, 96,
+ 62,217,153,154, 62,255,252, 24, 62,223,189,103, 63, 9,150,112, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,230,102,101, 63, 0, 0, 0, 62,223,189,103,
+ 63, 9,150,112, 62,217,153,154, 62,255,252, 24, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,217,153,154, 62,255,252, 24, 62,210,195, 85, 63, 9,152, 96,
+ 62,204,204,202, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 34,187, 97, 62,187,220, 72, 63, 31,122,178, 62,210, 92, 55, 63, 28,138,186,
+ 62,189,208,155, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 28,138,186, 62,189,208,155, 63, 31,199,185, 62,166,190, 96, 63, 34,187, 97, 62,187,220, 72,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 38,102,107, 62,165,199,201, 63, 34,187, 97, 62,187,220, 72, 63, 31,199,185, 62,166,190, 96, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 31,199,185, 62,166,190, 96, 63, 28,138,186, 62,189,208,155, 63, 25, 68,150, 62,169,150, 54, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 22, 60,123,
+ 62,193,135, 36, 63, 25, 68,150, 62,169,150, 54, 63, 28,138,186, 62,189,208,155, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 28,138,186, 62,189,208,155,
+ 63, 25,124,133, 62,213,159,181, 63, 22, 60,123, 62,193,135, 36, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 19,143, 64, 62,217,196, 4, 63, 22, 60,123,
+ 62,193,135, 36, 63, 25,124,133, 62,213,159,181, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 25,124,133, 62,213,159,181, 63, 28,138,186, 62,189,208,155,
+ 63, 31,122,178, 62,210, 92, 55, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 28,124, 14, 62,233, 32,218, 63, 25,153,155, 63, 0, 0, 0, 63, 22,158, 86,
+ 62,236,207, 65, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 22,158, 86, 62,236,207, 65, 63, 25,124,133, 62,213,159,181, 63, 28,124, 14, 62,233, 32,218,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 31,122,178, 62,210, 92, 55, 63, 28,124, 14, 62,233, 32,218, 63, 25,124,133, 62,213,159,181, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 25,124,133, 62,213,159,181, 63, 22,158, 86, 62,236,207, 65, 63, 19,143, 64, 62,217,196, 4, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 22, 60,123,
+ 62,193,135, 36, 63, 19,143, 64, 62,217,196, 4, 63, 16, 81,117, 62,198,230,223, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 16, 81,117, 62,198,230,223,
+ 63, 18,234, 7, 62,174, 54, 65, 63, 22, 60,123, 62,193,135, 36, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 25, 68,150, 62,169,150, 54, 63, 22, 60,123,
+ 62,193,135, 36, 63, 18,234, 7, 62,174, 54, 65, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 18,234, 7, 62,174, 54, 65, 63, 16, 81,117, 62,198,230,223,
+ 63, 12,204,191, 62,180,111,160, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 28,124, 14, 62,233, 32,218, 63, 31,122,178, 62,210, 92, 55, 63, 35, 3, 17,
+ 62,233, 23, 58, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 35, 3, 17, 62,233, 23, 58, 63, 32, 0, 2, 62,255,252, 24, 63, 28,124, 14, 62,233, 32,218,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 25,153,155, 63, 0, 0, 0, 63, 28,124, 14, 62,233, 32,218, 63, 32, 0, 2, 62,255,252, 24, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 32, 0, 2, 62,255,252, 24, 63, 35, 3, 17, 62,233, 23, 58, 63, 38,102,109, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 41,201,200,
+ 62,233, 23, 58, 63, 38,102,109, 63, 0, 0, 0, 63, 35, 3, 17, 62,233, 23, 58, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 35, 3, 17, 62,233, 23, 58,
+ 63, 38,102,109, 62,209,190,143, 63, 41,201,200, 62,233, 23, 58, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 45, 82, 38, 62,210, 92, 55, 63, 41,201,200,
+ 62,233, 23, 58, 63, 38,102,109, 62,209,190,143, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 38,102,109, 62,209,190,143, 63, 35, 3, 17, 62,233, 23, 58,
+ 63, 31,122,178, 62,210, 92, 55, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 34,187, 97, 62,187,220, 72, 63, 38,102,107, 62,165,199,201, 63, 42, 17,118,
+ 62,187,220, 72, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 42, 17,118, 62,187,220, 72, 63, 38,102,109, 62,209,190,143, 63, 34,187, 97, 62,187,220, 72,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 31,122,178, 62,210, 92, 55, 63, 34,187, 97, 62,187,220, 72, 63, 38,102,109, 62,209,190,143, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 38,102,109, 62,209,190,143, 63, 42, 17,118, 62,187,220, 72, 63, 45, 82, 38, 62,210, 92, 55, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 41,201,200,
+ 62,233, 23, 58, 63, 45, 82, 38, 62,210, 92, 55, 63, 48, 80,204, 62,233, 32,218, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 48, 80,204, 62,233, 32,218,
+ 63, 44,204,215, 62,255,252, 23, 63, 41,201,200, 62,233, 23, 58, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 38,102,109, 63, 0, 0, 0, 63, 41,201,200,
+ 62,233, 23, 58, 63, 44,204,215, 62,255,252, 23, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 44,204,215, 62,255,252, 23, 63, 48, 80,204, 62,233, 32,218,
+ 63, 51, 51, 63, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 60,123, 85, 62,198,230,253, 63, 57, 61,144, 62,217,196, 19, 63, 54,144, 86,
+ 62,193,135, 68, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 54,144, 86, 62,193,135, 68, 63, 57,226,196, 62,174, 54,114, 63, 60,123, 85, 62,198,230,253,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 64, 0, 0, 62,180,111,211, 63, 60,123, 85, 62,198,230,253, 63, 57,226,196, 62,174, 54,114, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 57,226,196, 62,174, 54,114, 63, 54,144, 86, 62,193,135, 68, 63, 51,136, 58, 62,169,150, 90, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 48, 66, 27,
+ 62,189,208,173, 63, 51,136, 58, 62,169,150, 90, 63, 54,144, 86, 62,193,135, 68, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 54,144, 86, 62,193,135, 68,
+ 63, 51, 80, 80, 62,213,159,192, 63, 48, 66, 27, 62,189,208,173, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 45, 82, 38, 62,210, 92, 55, 63, 48, 66, 27,
+ 62,189,208,173, 63, 51, 80, 80, 62,213,159,192, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 51, 80, 80, 62,213,159,192, 63, 54,144, 86, 62,193,135, 68,
+ 63, 57, 61,144, 62,217,196, 19, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 54, 46,128, 62,236,207, 75, 63, 51, 51, 63, 63, 0, 0, 0, 63, 48, 80,204,
+ 62,233, 32,218, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 48, 80,204, 62,233, 32,218, 63, 51, 80, 80, 62,213,159,192, 63, 54, 46,128, 62,236,207, 75,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 57, 61,144, 62,217,196, 19, 63, 54, 46,128, 62,236,207, 75, 63, 51, 80, 80, 62,213,159,192, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 51, 80, 80, 62,213,159,192, 63, 48, 80,204, 62,233, 32,218, 63, 45, 82, 38, 62,210, 92, 55, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 48, 66, 27,
+ 62,189,208,173, 63, 45, 82, 38, 62,210, 92, 55, 63, 42, 17,118, 62,187,220, 72, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 42, 17,118, 62,187,220, 72,
+ 63, 45, 5, 26, 62,166,190,117, 63, 48, 66, 27, 62,189,208,173, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 51,136, 58, 62,169,150, 90, 63, 48, 66, 27,
+ 62,189,208,173, 63, 45, 5, 26, 62,166,190,117, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 45, 5, 26, 62,166,190,117, 63, 42, 17,118, 62,187,220, 72,
+ 63, 38,102,107, 62,165,199,201, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 48, 55,255, 63, 9,152, 94, 63, 45, 40,237, 63, 19, 29,252, 63, 41,186,242,
+ 63, 9,150,112, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 41,186,242, 63, 9,150,112, 63, 44,204,215, 62,255,252, 23, 63, 48, 55,255, 63, 9,152, 94,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 51, 51, 63, 63, 0, 0, 0, 63, 48, 55,255, 63, 9,152, 94, 63, 44,204,215, 62,255,252, 23, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 44,204,215, 62,255,252, 23, 63, 41,186,242, 63, 9,150,112, 63, 38,102,109, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 35, 17,235,
+ 63, 9,150,112, 63, 38,102,109, 63, 0, 0, 0, 63, 41,186,242, 63, 9,150,112, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 41,186,242, 63, 9,150,112,
+ 63, 38,102,113, 63, 19, 98,219, 63, 35, 17,235, 63, 9,150,112, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 31,163,245, 63, 19, 29,253, 63, 35, 17,235,
+ 63, 9,150,112, 63, 38,102,113, 63, 19, 98,219, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 38,102,113, 63, 19, 98,219, 63, 41,186,242, 63, 9,150,112,
+ 63, 45, 40,237, 63, 19, 29,252, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 41,235, 38, 63, 28,140,141, 63, 38,102,117, 63, 37,200, 45, 63, 34,225,192,
+ 63, 28,140,142, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 34,225,192, 63, 28,140,142, 63, 38,102,113, 63, 19, 98,219, 63, 41,235, 38, 63, 28,140,141,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 45, 40,237, 63, 19, 29,252, 63, 41,235, 38, 63, 28,140,141, 63, 38,102,113, 63, 19, 98,219, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 38,102,113, 63, 19, 98,219, 63, 34,225,192, 63, 28,140,142, 63, 31,163,245, 63, 19, 29,253, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 35, 17,235,
+ 63, 9,150,112, 63, 31,163,245, 63, 19, 29,253, 63, 28,148,223, 63, 9,152, 94, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 28,148,223, 63, 9,152, 94,
+ 63, 32, 0, 2, 62,255,252, 24, 63, 35, 17,235, 63, 9,150,112, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 38,102,109, 63, 0, 0, 0, 63, 35, 17,235,
+ 63, 9,150,112, 63, 32, 0, 2, 62,255,252, 24, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 32, 0, 2, 62,255,252, 24, 63, 28,148,223, 63, 9,152, 94,
+ 63, 25,153,155, 63, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,107,129,188, 62,128, 45, 66, 63, 99, 71,235, 62,120, 76,222, 63,106, 37, 94,
+ 62, 83, 97, 84, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,106, 37, 94, 62, 83, 97, 84, 63,115, 51, 65, 62, 97,151,248, 63,107,129,188, 62,128, 45, 66,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,115, 51, 65, 62,135, 83,151, 63,107,129,188, 62,128, 45, 66, 63,115, 51, 65, 62, 97,151,248, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,115, 51, 65, 62, 97,151,248, 63,106, 37, 94, 62, 83, 97, 84, 63,115, 51, 65, 62, 52,111, 90, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,107,129,188,
+ 62,128, 45, 66, 63,115, 51, 65, 62,135, 83,151, 63,108,123,142, 62,151,144,169, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,108,123,142, 62,151,144,169,
+ 63,101, 50,231, 62,146,201, 17, 63,107,129,188, 62,128, 45, 66, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 99, 71,235, 62,120, 76,222, 63,107,129,188,
+ 62,128, 45, 66, 63,101, 50,231, 62,146,201, 17, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,101, 50,231, 62,146,201, 17, 63,108,123,142, 62,151,144,169,
+ 63,102,187,106, 62,169,150, 54, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 96, 56, 71, 62,166,190, 99, 63, 89,153,149, 62,165,199,201, 63, 93,238, 22,
+ 62,144,101,243, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 93,238, 22, 62,144,101,243, 63,101, 50,231, 62,146,201, 17, 63, 96, 56, 71, 62,166,190, 99,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,102,187,106, 62,169,150, 54, 63, 96, 56, 71, 62,166,190, 99, 63,101, 50,231, 62,146,201, 17, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,101, 50,231, 62,146,201, 17, 63, 93,238, 22, 62,144,101,243, 63, 99, 71,235, 62,120, 76,222, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,109, 21,249,
+ 62,174, 54, 65, 63,102,187,106, 62,169,150, 54, 63,108,123,142, 62,151,144,169, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,108,123,142, 62,151,144,169,
+ 63,115, 51, 65, 62,157,231, 93, 63,109, 21,249, 62,174, 54, 65, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,115, 51, 65, 62,180,111,160, 63,109, 21,249,
+ 62,174, 54, 65, 63,115, 51, 65, 62,157,231, 93, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,115, 51, 65, 62,157,231, 93, 63,108,123,142, 62,151,144,169,
+ 63,115, 51, 65, 62,135, 83,151, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 89,153,149, 62,115,162, 79, 63, 99, 71,235, 62,120, 76,222, 63, 93,238, 22,
+ 62,144,101,243, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 93,238, 22, 62,144,101,243, 63, 85, 69, 21, 62,144,102, 3, 63, 89,153,149, 62,115,162, 79,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 79,235, 68, 62,120, 77, 37, 63, 89,153,149, 62,115,162, 79, 63, 85, 69, 21, 62,144,102, 3, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 85, 69, 21, 62,144,102, 3, 63, 93,238, 22, 62,144,101,243, 63, 89,153,149, 62,165,199,201, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 89,153,149,
+ 62,115,162, 79, 63, 79,235, 68, 62,120, 77, 37, 63, 83,186, 24, 62, 70,176,245, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 83,186, 24, 62, 70,176,245,
+ 63, 95,121, 22, 62, 70,176,204, 63, 89,153,149, 62,115,162, 79, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 99, 71,235, 62,120, 76,222, 63, 89,153,149,
+ 62,115,162, 79, 63, 95,121, 22, 62, 70,176,204, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 95,121, 22, 62, 70,176,204, 63, 83,186, 24, 62, 70,176,245,
+ 63, 89,153,152, 62, 23, 31,198, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,103,119, 61, 62, 30,253,179, 63,115, 51, 65, 62, 52,111, 90, 63,106, 37, 94,
+ 62, 83, 97, 84, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,106, 37, 94, 62, 83, 97, 84, 63, 95,121, 22, 62, 70,176,204, 63,103,119, 61, 62, 30,253,179,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 89,153,152, 62, 23, 31,198, 63,103,119, 61, 62, 30,253,179, 63, 95,121, 22, 62, 70,176,204, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 95,121, 22, 62, 70,176,204, 63,106, 37, 94, 62, 83, 97, 84, 63, 99, 71,235, 62,120, 76,222, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 75,187,248,
+ 62, 30,253,241, 63, 89,153,152, 62, 23, 31,198, 63, 83,186, 24, 62, 70,176,245, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 83,186, 24, 62, 70,176,245,
+ 63, 73, 13,214, 62, 83, 97,181, 63, 75,187,248, 62, 30,253,241, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 64, 0, 0, 62, 52,111,202, 63, 75,187,248,
+ 62, 30,253,241, 63, 73, 13,214, 62, 83, 97,181, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 73, 13,214, 62, 83, 97,181, 63, 83,186, 24, 62, 70,176,245,
+ 63, 79,235, 68, 62,120, 77, 37, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 89,153,152, 61,147, 41,111, 63, 64, 0, 0, 61,180,111,195, 63, 64, 0, 0,
+ 61, 52, 65,111, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 64, 0, 0, 61, 52, 65,111, 63,117, 49, 38, 61, 52, 64,225, 63, 89,153,152, 61,147, 41,111,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,115, 51, 65, 61,180,111, 83, 63, 89,153,152, 61,147, 41,111, 63,117, 49, 38, 61, 52, 64,225, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,117, 49, 38, 61, 52, 64,225, 63, 64, 0, 0, 61, 52, 65,111, 63,121,222,208,178,239, 9,102, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 89,153,152,
+ 61,147, 41,111, 63,115, 51, 65, 61,180,111, 83, 63, 99, 51,172, 61,231, 46, 48, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 99, 51,172, 61,231, 46, 48,
+ 63, 79,255,135, 61,231, 46,120, 63, 89,153,152, 61,147, 41,111, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 64, 0, 0, 61,180,111,195, 63, 89,153,152,
+ 61,147, 41,111, 63, 79,255,135, 61,231, 46,120, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 79,255,135, 61,231, 46,120, 63, 99, 51,172, 61,231, 46, 48,
+ 63, 89,153,152, 62, 23, 31,198, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 75,187,248, 62, 30,253,241, 63, 64, 0, 0, 62, 52,111,202, 63, 64, 0, 0,
+ 62, 7, 71, 24, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 64, 0, 0, 62, 7, 71, 24, 63, 79,255,135, 61,231, 46,120, 63, 75,187,248, 62, 30,253,241,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 89,153,152, 62, 23, 31,198, 63, 75,187,248, 62, 30,253,241, 63, 79,255,135, 61,231, 46,120, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 79,255,135, 61,231, 46,120, 63, 64, 0, 0, 62, 7, 71, 24, 63, 64, 0, 0, 61,180,111,195, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,103,119, 61,
+ 62, 30,253,179, 63, 89,153,152, 62, 23, 31,198, 63, 99, 51,172, 61,231, 46, 48, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 99, 51,172, 61,231, 46, 48,
+ 63,115, 51, 66, 62, 7, 70,199, 63,103,119, 61, 62, 30,253,179, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,115, 51, 65, 62, 52,111, 90, 63,103,119, 61,
+ 62, 30,253,179, 63,115, 51, 66, 62, 7, 70,199, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,115, 51, 66, 62, 7, 70,199, 63, 99, 51,172, 61,231, 46, 48,
+ 63,115, 51, 65, 61,180,111, 83, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 71,177,122, 62,128, 45,120, 63, 64, 0, 0, 62,135, 83,218, 63, 64, 0, 0,
+ 62, 97,152,115, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 64, 0, 0, 62, 97,152,115, 63, 73, 13,214, 62, 83, 97,181, 63, 71,177,122, 62,128, 45,120,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 79,235, 68, 62,120, 77, 37, 63, 71,177,122, 62,128, 45,120, 63, 73, 13,214, 62, 83, 97,181, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 73, 13,214, 62, 83, 97,181, 63, 64, 0, 0, 62, 97,152,115, 63, 64, 0, 0, 62, 52,111,202, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 71,177,122,
+ 62,128, 45,120, 63, 79,235, 68, 62,120, 77, 37, 63, 78, 0, 72, 62,146,201, 52, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 78, 0, 72, 62,146,201, 52,
+ 63, 70,183,169, 62,151,144,219, 63, 71,177,122, 62,128, 45,120, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 64, 0, 0, 62,135, 83,218, 63, 71,177,122,
+ 62,128, 45,120, 63, 70,183,169, 62,151,144,219, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 70,183,169, 62,151,144,219, 63, 78, 0, 72, 62,146,201, 52,
+ 63, 76,119,198, 62,169,150, 90, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 70, 29, 61, 62,174, 54,114, 63, 64, 0, 0, 62,180,111,211, 63, 64, 0, 0,
+ 62,157,231,162, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 64, 0, 0, 62,157,231,162, 63, 70,183,169, 62,151,144,219, 63, 70, 29, 61, 62,174, 54,114,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 76,119,198, 62,169,150, 90, 63, 70, 29, 61, 62,174, 54,114, 63, 70,183,169, 62,151,144,219, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 70,183,169, 62,151,144,219, 63, 64, 0, 0, 62,157,231,162, 63, 64, 0, 0, 62,135, 83,218, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 82,250,230,
+ 62,166,190,117, 63, 76,119,198, 62,169,150, 90, 63, 78, 0, 72, 62,146,201, 52, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 78, 0, 72, 62,146,201, 52,
+ 63, 85, 69, 21, 62,144,102, 3, 63, 82,250,230, 62,166,190,117, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 89,153,149, 62,165,199,201, 63, 82,250,230,
+ 62,166,190,117, 63, 85, 69, 21, 62,144,102, 3, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 85, 69, 21, 62,144,102, 3, 63, 78, 0, 72, 62,146,201, 52,
+ 63, 79,235, 68, 62,120, 77, 37, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,245,167,179, 62,128, 45, 72, 61,179,217, 94, 62,120, 76,222, 61,234,196,202,
+ 62, 83, 97,100, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 61,234,196,202, 62, 83, 97,100, 62, 25,153,212, 62, 97,152, 2, 61,245,167,179, 62,128, 45, 72,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62, 25,153,214, 62,135, 83,156, 61,245,167,179, 62,128, 45, 72, 62, 25,153,212, 62, 97,152, 2, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62, 25,153,212, 62, 97,152, 2, 61,234,196,202, 62, 83, 97,100, 62, 25,153,214, 62, 52,111,106, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,245,167,179,
+ 62,128, 45, 72, 62, 25,153,214, 62,135, 83,156, 61,253,118, 62, 62,151,144,174, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,253,118, 62, 62,151,144,174,
+ 61,195, 49, 53, 62,146,201, 17, 61,245,167,179, 62,128, 45, 72, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,179,217, 94, 62,120, 76,222, 61,245,167,179,
+ 62,128, 45, 72, 61,195, 49, 53, 62,146,201, 17, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,195, 49, 53, 62,146,201, 17, 61,253,118, 62, 62,151,144,174,
+ 61,207,117, 70, 62,169,150, 54, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,155, 92, 79, 62,166,190, 91, 61, 76,205,194, 62,165,199,186, 61,137, 10,212,
+ 62,144,101,238, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 61,137, 10,212, 62,144,101,238, 61,195, 49, 53, 62,146,201, 17, 61,155, 92, 79, 62,166,190, 91,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 61,207,117, 70, 62,169,150, 54, 61,155, 92, 79, 62,166,190, 91, 61,195, 49, 53, 62,146,201, 17, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 61,195, 49, 53, 62,146,201, 17, 61,137, 10,212, 62,144,101,238, 61,179,217, 94, 62,120, 76,222, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 1, 36,204,
+ 62,174, 54, 70, 61,207,117, 70, 62,169,150, 54, 61,253,118, 62, 62,151,144,174, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,253,118, 62, 62,151,144,174,
+ 62, 25,153,213, 62,157,231,100, 62, 1, 36,204, 62,174, 54, 70, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 25,153,214, 62,180,111,165, 62, 1, 36,204,
+ 62,174, 54, 70, 62, 25,153,213, 62,157,231,100, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 25,153,213, 62,157,231,100, 61,253,118, 62, 62,151,144,174,
+ 62, 25,153,214, 62,135, 83,156, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61, 76,205,188, 62,115,162, 53, 61,179,217, 94, 62,120, 76,222, 61,137, 10,212,
+ 62,144,101,238, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 61,137, 10,212, 62,144,101,238, 61, 7,133,207, 62,144,101,236, 61, 76,205,188, 62,115,162, 53,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 60, 71,162,255, 62,120, 76,216, 61, 76,205,188, 62,115,162, 53, 61, 7,133,207, 62,144,101,236, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 61, 7,133,207, 62,144,101,236, 61,137, 10,212, 62,144,101,238, 61, 76,205,194, 62,165,199,186, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61, 76,205,188,
+ 62,115,162, 53, 60, 71,162,255, 62,120, 76,216, 60,221,171,190, 62, 70,176,194, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 60,221,171,190, 62, 70,176,194,
+ 61,149, 98,194, 62, 70,176,194, 61, 76,205,188, 62,115,162, 53, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,179,217, 94, 62,120, 76,222, 61, 76,205,188,
+ 62,115,162, 53, 61,149, 98,194, 62, 70,176,194, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,149, 98,194, 62, 70,176,194, 60,221,171,190, 62, 70,176,194,
+ 61, 76,205,193, 62, 23, 31,168, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,213, 83,198, 62, 30,253,179, 62, 25,153,214, 62, 52,111,106, 61,234,196,202,
+ 62, 83, 97,100, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 61,234,196,202, 62, 83, 97,100, 61,149, 98,194, 62, 70,176,194, 61,213, 83,198, 62, 30,253,179,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 61, 76,205,193, 62, 23, 31,168, 61,213, 83,198, 62, 30,253,179, 61,149, 98,194, 62, 70,176,194, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 61,149, 98,194, 62, 70,176,194, 61,234,196,202, 62, 83, 97,100, 61,179,217, 94, 62,120, 76,222, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,126,239, 59,
+ 62, 30,253,174, 63,131,105,154, 62, 23, 31,168, 63,131,118,175, 62, 70,176,194, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,131,118,175, 62, 70,176,194,
+ 63,124, 65, 30, 62, 83, 97, 90, 63,126,239, 59, 62, 30,253,174, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,115, 51, 65, 62, 52,111, 90, 63,126,239, 59,
+ 62, 30,253,174, 63,124, 65, 30, 62, 83, 97, 90, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,124, 65, 30, 62, 83, 97, 90, 63,131,118,175, 62, 70,176,194,
+ 63,129,143, 70, 62,120, 76,216, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,131,105,156, 61,147, 41,101, 63,115, 51, 65, 61,180,111, 83, 63,117, 49, 38,
+ 61, 52, 64,225, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,117, 49, 38, 61, 52, 64,225, 63,135,148,232, 60,125,158,144, 63,131,105,156, 61,147, 41,101,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62, 25,153,215, 61,180,111,104, 61,128,245,122, 61,147, 41,101, 62, 25,153,224, 61, 52, 64,225, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,135,148,232, 60,125,158,144, 63,117, 49, 38, 61, 52, 64,225, 63,121,222,208,178,239, 9,102, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,128,245,122,
+ 61,147, 41,101, 62, 25,153,215, 61,180,111,104, 61,179, 55, 89, 61,231, 46, 38, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,179, 55, 89, 61,231, 46, 38,
+ 60,208,147, 96, 61,231, 46, 48, 61,128,245,122, 61,147, 41,101, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,115, 51, 65, 61,180,111, 83, 63,131,105,156,
+ 61,147, 41,101, 63,129,153,102, 61,231, 46, 48, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 60,208,147, 96, 61,231, 46, 48, 61,179, 55, 89, 61,231, 46, 38,
+ 61, 76,205,193, 62, 23, 31,168, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,126,239, 59, 62, 30,253,174, 63,115, 51, 65, 62, 52,111, 90, 63,115, 51, 66,
+ 62, 7, 70,199, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,115, 51, 66, 62, 7, 70,199, 63,129,153,102, 61,231, 46, 48, 63,126,239, 59, 62, 30,253,174,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,131,105,154, 62, 23, 31,168, 63,126,239, 59, 62, 30,253,174, 63,129,153,102, 61,231, 46, 48, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,129,153,102, 61,231, 46, 48, 63,115, 51, 66, 62, 7, 70,199, 63,115, 51, 65, 61,180,111, 83, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,213, 83,198,
+ 62, 30,253,179, 61, 76,205,193, 62, 23, 31,168, 61,179, 55, 89, 61,231, 46, 38, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61,179, 55, 89, 61,231, 46, 38,
+ 62, 25,153,217, 62, 7, 70,204, 61,213, 83,198, 62, 30,253,179, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 25,153,214, 62, 52,111,106, 61,213, 83,198,
+ 62, 30,253,179, 62, 25,153,217, 62, 7, 70,204, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 25,153,217, 62, 7, 70,204, 61,179, 55, 89, 61,231, 46, 38,
+ 62, 25,153,215, 61,180,111,104, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,122,228,192, 62,128, 45, 66, 63,115, 51, 65, 62,135, 83,151, 63,115, 51, 65,
+ 62, 97,151,248, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,115, 51, 65, 62, 97,151,248, 63,124, 65, 30, 62, 83, 97, 90, 63,122,228,192, 62,128, 45, 66,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,129,143, 70, 62,120, 76,216, 63,122,228,192, 62,128, 45, 66, 63,124, 65, 30, 62, 83, 97, 90, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,124, 65, 30, 62, 83, 97, 90, 63,115, 51, 65, 62, 97,151,248, 63,115, 51, 65, 62, 52,111, 90, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,122,228,192,
+ 62,128, 45, 66, 63,129,143, 70, 62,120, 76,216, 63,128,153,201, 62,146,201, 14, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,128,153,201, 62,146,201, 14,
+ 63,121,234,239, 62,151,144,169, 63,122,228,192, 62,128, 45, 66, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,115, 51, 65, 62,135, 83,151, 63,122,228,192,
+ 62,128, 45, 66, 63,121,234,239, 62,151,144,169, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,121,234,239, 62,151,144,169, 63,128,153,201, 62,146,201, 14,
+ 63,127,171, 15, 62,169,150, 52, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,121, 80,133, 62,174, 54, 65, 63,115, 51, 65, 62,180,111,160, 63,115, 51, 65,
+ 62,157,231, 93, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,115, 51, 65, 62,157,231, 93, 63,121,234,239, 62,151,144,169, 63,121, 80,133, 62,174, 54, 65,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,127,171, 15, 62,169,150, 52, 63,121, 80,133, 62,174, 54, 65, 63,121,234,239, 62,151,144,169, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,121,234,239, 62,151,144,169, 63,115, 51, 65, 62,157,231, 93, 63,115, 51, 65, 62,135, 83,151, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,131, 23, 23,
+ 62,166,190, 89, 63,127,171, 15, 62,169,150, 52, 63,128,153,201, 62,146,201, 14, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 59,153,200,136, 62,146,201, 14,
+ 61, 7,133,207, 62,144,101,236, 60,197,197,195, 62,166,190, 89, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61, 76,205,194, 62,165,199,186, 60,197,197,195,
+ 62,166,190, 89, 61, 7,133,207, 62,144,101,236, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 61, 7,133,207, 62,144,101,236, 59,153,200,136, 62,146,201, 14,
+ 60, 71,162,255, 62,120, 76,216, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,163,208, 32, 62,128, 45, 79, 62,147, 92,147, 62,120, 76,252, 62,161, 23,102,
+ 62, 83, 97,115, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,161, 23,102, 62, 83, 97,115, 62,179, 51, 22, 62, 97,152, 2, 62,163,208, 32, 62,128, 45, 79,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,179, 51, 21, 62,135, 83,156, 62,163,208, 32, 62,128, 45, 79, 62,179, 51, 22, 62, 97,152, 2, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,179, 51, 22, 62, 97,152, 2, 62,161, 23,102, 62, 83, 97,115, 62,179, 51, 21, 62, 52,111,101, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,163,208, 32,
+ 62,128, 45, 79, 62,179, 51, 21, 62,135, 83,156, 62,165,195,194, 62,151,144,181, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,165,195,194, 62,151,144,181,
+ 62,151, 50,134, 62,146,201, 29, 62,163,208, 32, 62,128, 45, 79, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,147, 92,147, 62,120, 76,252, 62,163,208, 32,
+ 62,128, 45, 79, 62,151, 50,134, 62,146,201, 29, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,151, 50,134, 62,146,201, 29, 62,165,195,194, 62,151,144,181,
+ 62,154, 67,137, 62,169,150, 70, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,141, 61, 82, 62,166,190,112, 62,128, 0, 0, 62,165,199,206, 62,136,168,247,
+ 62,144,102, 3, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,136,168,247, 62,144,102, 3, 62,151, 50,134, 62,146,201, 29, 62,141, 61, 82, 62,166,190,112,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,154, 67,137, 62,169,150, 70, 62,141, 61, 82, 62,166,190,112, 62,151, 50,134, 62,146,201, 29, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,151, 50,134, 62,146,201, 29, 62,136,168,247, 62,144,102, 3, 62,147, 92,147, 62,120, 76,252, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,166,248,150,
+ 62,174, 54, 78, 62,154, 67,137, 62,169,150, 70, 62,165,195,194, 62,151,144,181, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,165,195,194, 62,151,144,181,
+ 62,179, 51, 21, 62,157,231, 98, 62,166,248,150, 62,174, 54, 78, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,179, 51, 21, 62,180,111,165, 62,166,248,150,
+ 62,174, 54, 78, 62,179, 51, 21, 62,157,231, 98, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,179, 51, 21, 62,157,231, 98, 62,165,195,194, 62,151,144,181,
+ 62,179, 51, 21, 62,135, 83,156, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,128, 0, 0, 62,115,162, 89, 62,147, 92,147, 62,120, 76,252, 62,136,168,247,
+ 62,144,102, 3, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,136,168,247, 62,144,102, 3, 62,110,174, 18, 62,144,102, 3, 62,128, 0, 0, 62,115,162, 89,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62, 89, 70,217, 62,120, 76,252, 62,128, 0, 0, 62,115,162, 89, 62,110,174, 18, 62,144,102, 3, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,110,174, 18, 62,144,102, 3, 62,136,168,247, 62,144,102, 3, 62,128, 0, 0, 62,165,199,206, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,128, 0, 0,
+ 62,115,162, 89, 62, 89, 70,217, 62,120, 76,252, 62,104,130, 30, 62, 70,176,230, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,104,130, 30, 62, 70,176,230,
+ 62,139,190,241, 62, 70,176,230, 62,128, 0, 0, 62,115,162, 89, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,147, 92,147, 62,120, 76,252, 62,128, 0, 0,
+ 62,115,162, 89, 62,139,190,241, 62, 70,176,230, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,139,190,241, 62, 70,176,230, 62,104,130, 30, 62, 70,176,230,
+ 62,128, 0, 0, 62, 23, 31,208, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,155,187, 41, 62, 30,253,205, 62,179, 51, 21, 62, 52,111,101, 62,161, 23,102,
+ 62, 83, 97,115, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,161, 23,102, 62, 83, 97,115, 62,139,190,241, 62, 70,176,230, 62,155,187, 41, 62, 30,253,205,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,128, 0, 0, 62, 23, 31,208, 62,155,187, 41, 62, 30,253,205, 62,139,190,241, 62, 70,176,230, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,139,190,241, 62, 70,176,230, 62,161, 23,102, 62, 83, 97,115, 62,147, 92,147, 62,120, 76,252, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 72,137,174,
+ 62, 30,253,205, 62,128, 0, 0, 62, 23, 31,208, 62,104,130, 30, 62, 70,176,230, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,104,130, 30, 62, 70,176,230,
+ 62, 61,209, 51, 62, 83, 97,115, 62, 72,137,174, 62, 30,253,205, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 25,153,214, 62, 52,111,106, 62, 72,137,174,
+ 62, 30,253,205, 62, 61,209, 51, 62, 83, 97,115, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 61,209, 51, 62, 83, 97,115, 62,104,130, 30, 62, 70,176,230,
+ 62, 89, 70,217, 62,120, 76,252, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,127,255,255, 61,147, 41,141, 62, 25,153,215, 61,180,111,104, 62, 25,153,224,
+ 61, 52, 64,225, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62, 25,153,224, 61, 52, 64,225, 62,179, 51, 15, 61, 52, 64,225, 62,127,255,255, 61,147, 41,141,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,179, 51, 20, 61,180,111,104, 62,127,255,255, 61,147, 41,141, 62,179, 51, 15, 61, 52, 64,225, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,179, 51, 15, 61, 52, 64,225, 62, 25,153,224, 61, 52, 64,225, 62,161,175,144,178,239, 9,102, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,127,255,255,
+ 61,147, 41,141, 62,179, 51, 20, 61,180,111,104, 62,147, 52, 12, 61,231, 46,109, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,147, 52, 12, 61,231, 46,109,
+ 62, 89,151,231, 61,231, 46,109, 62,127,255,255, 61,147, 41,141, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 25,153,215, 61,180,111,104, 62,127,255,255,
+ 61,147, 41,141, 62, 89,151,231, 61,231, 46,109, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 89,151,231, 61,231, 46,109, 62,147, 52, 12, 61,231, 46,109,
+ 62,128, 0, 0, 62, 23, 31,208, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 72,137,174, 62, 30,253,205, 62, 25,153,214, 62, 52,111,106, 62, 25,153,217,
+ 62, 7, 70,204, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62, 25,153,217, 62, 7, 70,204, 62, 89,151,231, 61,231, 46,109, 62, 72,137,174, 62, 30,253,205,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,128, 0, 0, 62, 23, 31,208, 62, 72,137,174, 62, 30,253,205, 62, 89,151,231, 61,231, 46,109, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62, 89,151,231, 61,231, 46,109, 62, 25,153,217, 62, 7, 70,204, 62, 25,153,215, 61,180,111,104, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,155,187, 41,
+ 62, 30,253,205, 62,128, 0, 0, 62, 23, 31,208, 62,147, 52, 12, 61,231, 46,109, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,147, 52, 12, 61,231, 46,109,
+ 62,179, 51, 19, 62, 7, 70,204, 62,155,187, 41, 62, 30,253,205, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,179, 51, 21, 62, 52,111,101, 62,155,187, 41,
+ 62, 30,253,205, 62,179, 51, 19, 62, 7, 70,204, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,179, 51, 19, 62, 7, 70,204, 62,147, 52, 12, 61,231, 46,109,
+ 62,179, 51, 20, 61,180,111,104, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 56, 95,192, 62,128, 45, 79, 62, 25,153,214, 62,135, 83,156, 62, 25,153,212,
+ 62, 97,152, 2, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62, 25,153,212, 62, 97,152, 2, 62, 61,209, 51, 62, 83, 97,115, 62, 56, 95,192, 62,128, 45, 79,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62, 89, 70,217, 62,120, 76,252, 62, 56, 95,192, 62,128, 45, 79, 62, 61,209, 51, 62, 83, 97,115, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62, 61,209, 51, 62, 83, 97,115, 62, 25,153,212, 62, 97,152, 2, 62, 25,153,214, 62, 52,111,106, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 56, 95,192,
+ 62,128, 45, 79, 62, 89, 70,217, 62,120, 76,252, 62, 81,154,245, 62,146,201, 29, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 81,154,245, 62,146,201, 29,
+ 62, 52,120,125, 62,151,144,181, 62, 56, 95,192, 62,128, 45, 79, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 25,153,214, 62,135, 83,156, 62, 56, 95,192,
+ 62,128, 45, 79, 62, 52,120,125, 62,151,144,181, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 52,120,125, 62,151,144,181, 62, 81,154,245, 62,146,201, 29,
+ 62, 75,120,239, 62,169,150, 70, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 50, 14,213, 62,174, 54, 78, 62, 25,153,214, 62,180,111,165, 62, 25,153,213,
+ 62,157,231,100, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62, 25,153,213, 62,157,231,100, 62, 52,120,125, 62,151,144,181, 62, 50, 14,213, 62,174, 54, 78,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62, 75,120,239, 62,169,150, 70, 62, 50, 14,213, 62,174, 54, 78, 62, 52,120,125, 62,151,144,181, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62, 52,120,125, 62,151,144,181, 62, 25,153,213, 62,157,231,100, 62, 25,153,214, 62,135, 83,156, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,101,133, 91,
+ 62,166,190,112, 62, 75,120,239, 62,169,150, 70, 62, 81,154,245, 62,146,201, 29, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62, 81,154,245, 62,146,201, 29,
+ 62,110,174, 18, 62,144,102, 3, 62,101,133, 91, 62,166,190,112, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,128, 0, 0, 62,165,199,206, 62,101,133, 91,
+ 62,166,190,112, 62,110,174, 18, 62,144,102, 3, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,110,174, 18, 62,144,102, 3, 62, 81,154,245, 62,146,201, 29,
+ 62, 89, 70,217, 62,120, 76,252, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 5, 27, 64, 62,128, 45, 66, 62,249,194,232, 62,120, 76,216, 63, 3,190,226,
+ 62, 83, 97, 90, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 3,190,226, 62, 83, 97, 90, 63, 12,204,191, 62, 97,151,248, 63, 5, 27, 64, 62,128, 45, 66,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 12,204,191, 62,135, 83,149, 63, 5, 27, 64, 62,128, 45, 66, 63, 12,204,191, 62, 97,151,248, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 12,204,191, 62, 97,151,248, 63, 3,190,226, 62, 83, 97, 90, 63, 12,204,191, 62, 52,111, 90, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 5, 27, 64,
+ 62,128, 45, 66, 63, 12,204,191, 62,135, 83,149, 63, 6, 21, 17, 62,151,144,169, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 6, 21, 17, 62,151,144,169,
+ 62,253,152,222, 62,146,201, 14, 63, 5, 27, 64, 62,128, 45, 66, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,249,194,232, 62,120, 76,216, 63, 5, 27, 64,
+ 62,128, 45, 66, 62,253,152,222, 62,146,201, 14, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,253,152,222, 62,146,201, 14, 63, 6, 21, 17, 62,151,144,169,
+ 63, 0, 84,241, 62,169,150, 52, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,243,163,164, 62,166,190, 89, 62,230,102, 72, 62,165,199,183, 62,239, 15, 70,
+ 62,144,101,233, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,239, 15, 70, 62,144,101,233, 62,253,152,222, 62,146,201, 14, 62,243,163,164, 62,166,190, 89,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 0, 84,241, 62,169,150, 52, 62,243,163,164, 62,166,190, 89, 62,253,152,222, 62,146,201, 14, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,253,152,222, 62,146,201, 14, 62,239, 15, 70, 62,144,101,233, 62,249,194,232, 62,120, 76,216, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 6,175,123,
+ 62,174, 54, 65, 63, 0, 84,241, 62,169,150, 52, 63, 6, 21, 17, 62,151,144,169, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 6, 21, 17, 62,151,144,169,
+ 63, 12,204,191, 62,157,231, 90, 63, 6,175,123, 62,174, 54, 65, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 12,204,191, 62,180,111,160, 63, 6,175,123,
+ 62,174, 54, 65, 63, 12,204,191, 62,157,231, 90, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 12,204,191, 62,157,231, 90, 63, 6, 21, 17, 62,151,144,169,
+ 63, 12,204,191, 62,135, 83,149, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,230,102, 72, 62,115,162, 53, 62,249,194,232, 62,120, 76,216, 62,239, 15, 70,
+ 62,144,101,233, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,239, 15, 70, 62,144,101,233, 62,221,189, 75, 62,144,101,238, 62,230,102, 72, 62,115,162, 53,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,211, 9,168, 62,120, 76,222, 62,230,102, 72, 62,115,162, 53, 62,221,189, 75, 62,144,101,238, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,221,189, 75, 62,144,101,238, 62,239, 15, 70, 62,144,101,233, 62,230,102, 72, 62,165,199,183, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,230,102, 72,
+ 62,115,162, 53, 62,211, 9,168, 62,120, 76,222, 62,218,167, 80, 62, 70,176,194, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,218,167, 80, 62, 70,176,194,
+ 62,242, 37, 68, 62, 70,176,194, 62,230,102, 72, 62,115,162, 53, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,249,194,232, 62,120, 76,216, 62,230,102, 72,
+ 62,115,162, 53, 62,242, 37, 68, 62, 70,176,194, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,242, 37, 68, 62, 70,176,194, 62,218,167, 80, 62, 70,176,194,
+ 62,230,102, 72, 62, 23, 31,168, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 1, 16,197, 62, 30,253,174, 63, 12,204,191, 62, 52,111, 90, 63, 3,190,226,
+ 62, 83, 97, 90, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 3,190,226, 62, 83, 97, 90, 62,242, 37, 68, 62, 70,176,194, 63, 1, 16,197, 62, 30,253,174,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,230,102, 72, 62, 23, 31,168, 63, 1, 16,197, 62, 30,253,174, 62,242, 37, 68, 62, 70,176,194, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,242, 37, 68, 62, 70,176,194, 63, 3,190,226, 62, 83, 97, 90, 62,249,194,232, 62,120, 76,216, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,202,171, 14,
+ 62, 30,253,179, 62,230,102, 72, 62, 23, 31,168, 62,218,167, 80, 62, 70,176,194, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,218,167, 80, 62, 70,176,194,
+ 62,197, 78,205, 62, 83, 97, 95, 62,202,171, 14, 62, 30,253,179, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,179, 51, 21, 62, 52,111,101, 62,202,171, 14,
+ 62, 30,253,179, 62,197, 78,205, 62, 83, 97, 95, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,197, 78,205, 62, 83, 97, 95, 62,218,167, 80, 62, 70,176,194,
+ 62,211, 9,168, 62,120, 76,222, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,230,102, 63, 61,147, 41,101, 62,179, 51, 20, 61,180,111,104, 62,179, 51, 15,
+ 61, 52, 64,225, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,179, 51, 15, 61, 52, 64,225, 63, 12,204,189, 61, 52, 64,225, 62,230,102, 63, 61,147, 41,101,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 12,204,191, 61,180,111, 83, 62,230,102, 63, 61,147, 41,101, 63, 12,204,189, 61, 52, 64,225, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 12,204,189, 61, 52, 64,225, 62,179, 51, 15, 61, 52, 64,225, 62,161,175,144,178,239, 9,102, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,230,102, 63,
+ 61,147, 41,101, 63, 12,204,191, 61,180,111, 83, 62,249,154,104, 61,231, 46, 48, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,249,154,104, 61,231, 46, 48,
+ 62,211, 50, 42, 61,231, 46, 48, 62,230,102, 63, 61,147, 41,101, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,179, 51, 20, 61,180,111,104, 62,230,102, 63,
+ 61,147, 41,101, 62,211, 50, 42, 61,231, 46, 48, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,211, 50, 42, 61,231, 46, 48, 62,249,154,104, 61,231, 46, 48,
+ 62,230,102, 72, 62, 23, 31,168, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,202,171, 14, 62, 30,253,179, 62,179, 51, 21, 62, 52,111,101, 62,179, 51, 19,
+ 62, 7, 70,204, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,179, 51, 19, 62, 7, 70,204, 62,211, 50, 42, 61,231, 46, 48, 62,202,171, 14, 62, 30,253,179,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,230,102, 72, 62, 23, 31,168, 62,202,171, 14, 62, 30,253,179, 62,211, 50, 42, 61,231, 46, 48, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,211, 50, 42, 61,231, 46, 48, 62,179, 51, 19, 62, 7, 70,204, 62,179, 51, 20, 61,180,111,104, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 1, 16,197,
+ 62, 30,253,174, 62,230,102, 72, 62, 23, 31,168, 62,249,154,104, 61,231, 46, 48, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,249,154,104, 61,231, 46, 48,
+ 63, 12,204,191, 62, 7, 70,199, 63, 1, 16,197, 62, 30,253,174, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 12,204,191, 62, 52,111, 90, 63, 1, 16,197,
+ 62, 30,253,174, 63, 12,204,191, 62, 7, 70,199, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 12,204,191, 62, 7, 70,199, 62,249,154,104, 61,231, 46, 48,
+ 63, 12,204,191, 61,180,111, 83, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,194,150, 19, 62,128, 45, 72, 62,179, 51, 21, 62,135, 83,156, 62,179, 51, 22,
+ 62, 97,152, 2, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,179, 51, 22, 62, 97,152, 2, 62,197, 78,205, 62, 83, 97, 95, 62,194,150, 19, 62,128, 45, 72,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,211, 9,168, 62,120, 76,222, 62,194,150, 19, 62,128, 45, 72, 62,197, 78,205, 62, 83, 97, 95, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,197, 78,205, 62, 83, 97, 95, 62,179, 51, 22, 62, 97,152, 2, 62,179, 51, 21, 62, 52,111,101, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,194,150, 19,
+ 62,128, 45, 72, 62,211, 9,168, 62,120, 76,222, 62,207, 51,179, 62,146,201, 17, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,207, 51,179, 62,146,201, 17,
+ 62,192,162,113, 62,151,144,174, 62,194,150, 19, 62,128, 45, 72, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,179, 51, 21, 62,135, 83,156, 62,194,150, 19,
+ 62,128, 45, 72, 62,192,162,113, 62,151,144,174, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,192,162,113, 62,151,144,174, 62,207, 51,179, 62,146,201, 17,
+ 62,204, 34,175, 62,169,150, 54, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,191,109,154, 62,174, 54, 68, 62,179, 51, 21, 62,180,111,165, 62,179, 51, 21,
+ 62,157,231, 98, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 62,179, 51, 21, 62,157,231, 98, 62,192,162,113, 62,151,144,174, 62,191,109,154, 62,174, 54, 68,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 62,204, 34,175, 62,169,150, 54, 62,191,109,154, 62,174, 54, 68, 62,192,162,113, 62,151,144,174, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 62,192,162,113, 62,151,144,174, 62,179, 51, 21, 62,157,231, 98, 62,179, 51, 21, 62,135, 83,156, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,217, 40,237,
+ 62,166,190, 91, 62,204, 34,175, 62,169,150, 54, 62,207, 51,179, 62,146,201, 17, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,207, 51,179, 62,146,201, 17,
+ 62,221,189, 75, 62,144,101,238, 62,217, 40,237, 62,166,190, 91, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,230,102, 72, 62,165,199,183, 62,217, 40,237,
+ 62,166,190, 91, 62,221,189, 75, 62,144,101,238, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 62,221,189, 75, 62,144,101,238, 62,207, 51,179, 62,146,201, 17,
+ 62,211, 9,168, 62,120, 76,222, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 56, 78,134, 62,128, 45,117, 63, 48, 20,188, 62,120, 77, 37, 63, 54,242, 42,
+ 62, 83, 97,181, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 54,242, 42, 62, 83, 97,181, 63, 64, 0, 0, 62, 97,152,115, 63, 56, 78,134, 62,128, 45,117,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 64, 0, 0, 62,135, 83,218, 63, 56, 78,134, 62,128, 45,117, 63, 64, 0, 0, 62, 97,152,115, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 64, 0, 0, 62, 97,152,115, 63, 54,242, 42, 62, 83, 97,181, 63, 64, 0, 0, 62, 52,111,202, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 56, 78,134,
+ 62,128, 45,117, 63, 64, 0, 0, 62,135, 83,218, 63, 57, 72, 87, 62,151,144,219, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 57, 72, 87, 62,151,144,219,
+ 63, 49,255,184, 62,146,201, 52, 63, 56, 78,134, 62,128, 45,117, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 48, 20,188, 62,120, 77, 37, 63, 56, 78,134,
+ 62,128, 45,117, 63, 49,255,184, 62,146,201, 52, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 49,255,184, 62,146,201, 52, 63, 57, 72, 87, 62,151,144,219,
+ 63, 51,136, 58, 62,169,150, 90, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 45, 5, 26, 62,166,190,117, 63, 38,102,107, 62,165,199,201, 63, 42,186,235,
+ 62,144,102, 5, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 42,186,235, 62,144,102, 5, 63, 49,255,184, 62,146,201, 52, 63, 45, 5, 26, 62,166,190,117,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 51,136, 58, 62,169,150, 90, 63, 45, 5, 26, 62,166,190,117, 63, 49,255,184, 62,146,201, 52, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 49,255,184, 62,146,201, 52, 63, 42,186,235, 62,144,102, 5, 63, 48, 20,188, 62,120, 77, 37, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 57,226,196,
+ 62,174, 54,114, 63, 51,136, 58, 62,169,150, 90, 63, 57, 72, 87, 62,151,144,219, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 57, 72, 87, 62,151,144,219,
+ 63, 64, 0, 0, 62,157,231,162, 63, 57,226,196, 62,174, 54,114, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 64, 0, 0, 62,180,111,211, 63, 57,226,196,
+ 62,174, 54,114, 63, 64, 0, 0, 62,157,231,162, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 64, 0, 0, 62,157,231,162, 63, 57, 72, 87, 62,151,144,219,
+ 63, 64, 0, 0, 62,135, 83,218, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 38,102,107, 62,115,162, 79, 63, 48, 20,188, 62,120, 77, 37, 63, 42,186,235,
+ 62,144,102, 5, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 42,186,235, 62,144,102, 5, 63, 34, 17,234, 62,144,101,243, 63, 38,102,107, 62,115,162, 79,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 28,184, 21, 62,120, 76,222, 63, 38,102,107, 62,115,162, 79, 63, 34, 17,234, 62,144,101,243, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 34, 17,234, 62,144,101,243, 63, 42,186,235, 62,144,102, 5, 63, 38,102,107, 62,165,199,201, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 38,102,107,
+ 62,115,162, 79, 63, 28,184, 21, 62,120, 76,222, 63, 32,134,234, 62, 70,176,204, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 32,134,234, 62, 70,176,204,
+ 63, 44, 69,233, 62, 70,176,245, 63, 38,102,107, 62,115,162, 79, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 48, 20,188, 62,120, 77, 37, 63, 38,102,107,
+ 62,115,162, 79, 63, 44, 69,233, 62, 70,176,245, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 44, 69,233, 62, 70,176,245, 63, 32,134,234, 62, 70,176,204,
+ 63, 38,102,104, 62, 23, 31,198, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 52, 68, 9, 62, 30,253,241, 63, 64, 0, 0, 62, 52,111,202, 63, 54,242, 42,
+ 62, 83, 97,181, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 54,242, 42, 62, 83, 97,181, 63, 44, 69,233, 62, 70,176,245, 63, 52, 68, 9, 62, 30,253,241,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 38,102,104, 62, 23, 31,198, 63, 52, 68, 9, 62, 30,253,241, 63, 44, 69,233, 62, 70,176,245, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 44, 69,233, 62, 70,176,245, 63, 54,242, 42, 62, 83, 97,181, 63, 48, 20,188, 62,120, 77, 37, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 24,136,195,
+ 62, 30,253,179, 63, 38,102,104, 62, 23, 31,198, 63, 32,134,234, 62, 70,176,204, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 32,134,234, 62, 70,176,204,
+ 63, 21,218,162, 62, 83, 97, 84, 63, 24,136,195, 62, 30,253,179, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 12,204,191, 62, 52,111, 90, 63, 24,136,195,
+ 62, 30,253,179, 63, 21,218,162, 62, 83, 97, 84, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 21,218,162, 62, 83, 97, 84, 63, 32,134,234, 62, 70,176,204,
+ 63, 28,184, 21, 62,120, 76,222, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 38,102,104, 61,147, 41,111, 63, 12,204,191, 61,180,111, 83, 63, 12,204,189,
+ 61, 52, 64,225, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 12,204,189, 61, 52, 64,225, 63, 64, 0, 0, 61, 52, 65,111, 63, 38,102,104, 61,147, 41,111,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 64, 0, 0, 61,180,111,195, 63, 38,102,104, 61,147, 41,111, 63, 64, 0, 0, 61, 52, 65,111, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 64, 0, 0, 61, 52, 65,111, 63, 12,204,189, 61, 52, 64,225, 63,121,222,208,178,239, 9,102, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 38,102,104,
+ 61,147, 41,111, 63, 64, 0, 0, 61,180,111,195, 63, 48, 0,122, 61,231, 46,120, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 48, 0,122, 61,231, 46,120,
+ 63, 28,204, 85, 61,231, 46, 48, 63, 38,102,104, 61,147, 41,111, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 12,204,191, 61,180,111, 83, 63, 38,102,104,
+ 61,147, 41,111, 63, 28,204, 85, 61,231, 46, 48, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 28,204, 85, 61,231, 46, 48, 63, 48, 0,122, 61,231, 46,120,
+ 63, 38,102,104, 62, 23, 31,198, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 24,136,195, 62, 30,253,179, 63, 12,204,191, 62, 52,111, 90, 63, 12,204,191,
+ 62, 7, 70,199, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 12,204,191, 62, 7, 70,199, 63, 28,204, 85, 61,231, 46, 48, 63, 24,136,195, 62, 30,253,179,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 38,102,104, 62, 23, 31,198, 63, 24,136,195, 62, 30,253,179, 63, 28,204, 85, 61,231, 46, 48, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 28,204, 85, 61,231, 46, 48, 63, 12,204,191, 62, 7, 70,199, 63, 12,204,191, 61,180,111, 83, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 52, 68, 9,
+ 62, 30,253,241, 63, 38,102,104, 62, 23, 31,198, 63, 48, 0,122, 61,231, 46,120, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 48, 0,122, 61,231, 46,120,
+ 63, 64, 0, 0, 62, 7, 71, 24, 63, 52, 68, 9, 62, 30,253,241, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 64, 0, 0, 62, 52,111,202, 63, 52, 68, 9,
+ 62, 30,253,241, 63, 64, 0, 0, 62, 7, 71, 24, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 64, 0, 0, 62, 7, 71, 24, 63, 48, 0,122, 61,231, 46,120,
+ 63, 64, 0, 0, 61,180,111,195, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 20,126, 68, 62,128, 45, 64, 63, 12,204,191, 62,135, 83,149, 63, 12,204,191,
+ 62, 97,151,248, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 12,204,191, 62, 97,151,248, 63, 21,218,162, 62, 83, 97, 84, 63, 20,126, 68, 62,128, 45, 64,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 28,184, 21, 62,120, 76,222, 63, 20,126, 68, 62,128, 45, 64, 63, 21,218,162, 62, 83, 97, 84, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 21,218,162, 62, 83, 97, 84, 63, 12,204,191, 62, 97,151,248, 63, 12,204,191, 62, 52,111, 90, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 20,126, 68,
+ 62,128, 45, 64, 63, 28,184, 21, 62,120, 76,222, 63, 26,205, 25, 62,146,201, 14, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 26,205, 25, 62,146,201, 14,
+ 63, 19,132,114, 62,151,144,169, 63, 20,126, 68, 62,128, 45, 64, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 12,204,191, 62,135, 83,149, 63, 20,126, 68,
+ 62,128, 45, 64, 63, 19,132,114, 62,151,144,169, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 19,132,114, 62,151,144,169, 63, 26,205, 25, 62,146,201, 14,
+ 63, 25, 68,150, 62,169,150, 54, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 18,234, 7, 62,174, 54, 65, 63, 12,204,191, 62,180,111,160, 63, 12,204,191,
+ 62,157,231, 90, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63, 12,204,191, 62,157,231, 90, 63, 19,132,114, 62,151,144,169, 63, 18,234, 7, 62,174, 54, 65,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63, 25, 68,150, 62,169,150, 54, 63, 18,234, 7, 62,174, 54, 65, 63, 19,132,114, 62,151,144,169, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63, 19,132,114, 62,151,144,169, 63, 12,204,191, 62,157,231, 90, 63, 12,204,191, 62,135, 83,149, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 31,199,185,
+ 62,166,190, 96, 63, 25, 68,150, 62,169,150, 54, 63, 26,205, 25, 62,146,201, 14, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 26,205, 25, 62,146,201, 14,
+ 63, 34, 17,234, 62,144,101,243, 63, 31,199,185, 62,166,190, 96, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 38,102,107, 62,165,199,201, 63, 31,199,185,
+ 62,166,190, 96, 63, 34, 17,234, 62,144,101,243, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63, 34, 17,234, 62,144,101,243, 63, 26,205, 25, 62,146,201, 14,
+ 63, 28,184, 21, 62,120, 76,222, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 77, 69, 0, 0, 1, 20, 2,236,248,224, 0, 0, 0, 50, 0, 0, 0, 1, 2,237, 0, 32,
+ 2,236,243,224, 0, 0, 0, 0, 0, 0, 0, 0, 77, 69,112,114,101,118,105,101,119, 46, 48, 48, 50, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,231, 1, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 2,236,250, 32, 2,236,254,208, 2,236,255, 16, 2,234,114, 96, 2,236,251,128, 2,236,253, 64, 0, 0, 0, 0,
+ 2,236,255,112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,236,250, 80, 0, 0, 0, 1,
+ 0, 0, 0, 5, 0, 0, 0, 20, 0, 0, 0, 0, 2,236,252, 16, 0, 0, 0, 1, 0, 0, 0, 5, 0, 0, 0, 12, 0, 0, 0, 0,
+ 2,236,253,160, 0, 0, 0, 3, 0, 0, 0, 5, 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 4, 0, 0, 0, 1,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1,179,128, 0, 0, 52, 64, 0, 0,188,142, 92,235, 63,128, 0, 0, 63,128, 0, 2,
+ 60,142, 92,235, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 4, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 4, 2,236,250, 32, 0, 0, 0, 0,
+ 0, 0, 0, 1, 2,236,194, 96, 68, 65, 84, 65, 0, 0, 1, 4, 2,236,250, 80, 0, 0, 0,242, 0, 0, 0, 5, 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, 2,236,251,128, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65, 0, 0, 0,100, 2,236,251,128, 0, 0, 0, 56, 0, 0, 0, 5, 63,128, 0, 0, 63,127,255,255, 39,251,255,255,
+ 0, 0, 0, 0,127,255, 2,255, 63,128, 0, 0,191,128, 0, 0,168, 2, 0, 0, 0, 0, 0, 0,127,255, 2,255,191,128, 0, 1,
+191,127,255,253,167,251,255,253, 0, 0, 0, 0,127,255, 2,255,191,127,255,250, 63,128, 0, 3, 40, 2, 0, 3, 0, 0, 0, 0,
+127,255, 2,255, 59,110,239, 0, 60, 26,164,131,189, 14, 92,235, 12,228, 33, 95,133, 28, 3,255, 68, 65, 84, 65, 0, 0, 1, 4,
+ 2,236,252, 16, 0, 0, 0,242, 0, 0, 0, 5, 0, 0, 0, 3, 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, 2,236,253, 64,
+ 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, 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, 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, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 48, 2,236,253, 64, 0, 0, 0, 53,
+ 0, 0, 0, 4, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 34, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 34, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 34, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 34, 68, 65, 84, 65, 0, 0, 1, 4, 2,236,253,160,
+ 0, 0, 0,242, 0, 0, 0, 5, 0, 0, 0, 4, 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, 2,236,254,208, 0, 0, 0, 5,
+ 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 85, 86, 84,101,120, 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, 2,236,255, 16, 0, 0, 0, 6, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0,
+ 67,111,108, 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,
+ 2,236,255,112, 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, 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, 68, 65, 84, 65, 0, 0, 0, 20, 2,236,254,208, 0, 0, 0, 52, 0, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 44, 2,236,255, 16,
+ 0, 0, 0, 60, 0, 0, 0, 1, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 16, 2,236,255,112,
+ 0, 0, 0, 57, 0, 0, 0, 4,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 68, 65, 84, 65, 0, 0, 0, 60,
+ 2,234,114, 96, 0, 0, 0, 51, 0, 0, 0, 1, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 77, 69, 0, 0, 1, 20, 2,237, 0, 32, 0, 0, 0, 50, 0, 0, 0, 1, 2,237, 7, 80,
+ 2,236,248,224, 0, 0, 0, 0, 0, 0, 0, 0, 77, 69,112,114,101,118,105,101,119, 46, 48, 48, 51, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,235,154, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 2,237, 1, 96, 2,237, 6, 0, 2,237, 6, 64, 2,234,114, 96, 2,237, 2,192, 2,237, 4,112, 0, 0, 0, 0,
+ 2,237, 6,160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,237, 1,144, 0, 0, 0, 1,
+ 0, 0, 0, 5, 0, 0, 0, 20, 0, 0, 0, 0, 2,237, 3, 64, 0, 0, 0, 1, 0, 0, 0, 5, 0, 0, 0, 12, 0, 0, 0, 0,
+ 2,237, 4,208, 0, 0, 0, 3, 0, 0, 0, 5, 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,179,128, 0, 0, 52, 64, 0, 0, 28,192, 0, 0, 63,128, 0, 0, 63,128, 0, 2,
+ 55, 39,197,172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 4, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 4, 2,237, 1, 96, 0, 0, 0, 0,
+ 0, 0, 0, 1, 2,236,196,224, 68, 65, 84, 65, 0, 0, 1, 4, 2,237, 1,144, 0, 0, 0,242, 0, 0, 0, 5, 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, 2,237, 2,192, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 68, 65, 84, 65, 0, 0, 0, 80, 2,237, 2,192, 0, 0, 0, 56, 0, 0, 0, 4, 63,128, 0, 0, 63,127,255,255, 39,251,255,255,
+ 0, 0, 0, 0,127,255, 3,255, 63,128, 0, 0,191,128, 0, 0,168, 2, 0, 0, 0, 0, 0, 0,127,255, 3,255,191,128, 0, 1,
+191,127,255,253,167,251,255,253, 0, 0, 0, 0,127,255, 3,255,191,127,255,250, 63,128, 0, 3, 40, 2, 0, 3, 0, 0, 0, 0,
+127,255, 3,255, 68, 65, 84, 65, 0, 0, 1, 4, 2,237, 3, 64, 0, 0, 0,242, 0, 0, 0, 5, 0, 0, 0, 3, 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, 2,237, 4,112, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+ 0, 0, 0, 48, 2,237, 4,112, 0, 0, 0, 53, 0, 0, 0, 4, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 35, 0, 0, 0, 0,
+ 0, 0, 0, 1, 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 35, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 35,
+ 68, 65, 84, 65, 0, 0, 1, 4, 2,237, 4,208, 0, 0, 0,242, 0, 0, 0, 5, 0, 0, 0, 4, 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, 2,237, 6, 0, 0, 0, 0, 5, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 85, 86, 84,101,120, 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, 2,237, 6, 64, 0, 0, 0, 6,
+ 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 67,111,108, 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, 2,237, 6,160, 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, 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, 68, 65, 84, 65, 0, 0, 0, 20,
+ 2,237, 6, 0, 0, 0, 0, 52, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 2,
+ 68, 65, 84, 65, 0, 0, 0, 44, 2,237, 6, 64, 0, 0, 0, 60, 0, 0, 0, 1, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+ 68, 65, 84, 65, 0, 0, 0, 16, 2,237, 6,160, 0, 0, 0, 57, 0, 0, 0, 4,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 68, 65, 84, 65, 0, 0, 0, 60, 2,234,114, 96, 0, 0, 0, 51, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 77, 69, 0, 0, 1, 20, 2,237, 7, 80,
+ 0, 0, 0, 50, 0, 0, 0, 1, 2,237, 14,128, 2,237, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 77, 69,112,114,101,118,105,101,
+119, 46, 48, 48, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,235,206,144,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,237, 8,144, 2,237, 13, 48, 2,237, 13,112, 2,234,114, 96,
+ 2,237, 9,240, 2,237, 11,160, 0, 0, 0, 0, 2,237, 13,208, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 2,237, 8,192, 0, 0, 0, 1, 0, 0, 0, 5, 0, 0, 0, 20, 0, 0, 0, 0, 2,237, 10,112, 0, 0, 0, 1,
+ 0, 0, 0, 5, 0, 0, 0, 12, 0, 0, 0, 0, 2,237, 12, 0, 0, 0, 0, 3, 0, 0, 0, 5, 0, 0, 0, 80, 0, 0, 0, 0,
+ 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,179,128, 0, 0, 52, 64, 0, 0,
+ 28,192, 0, 0, 63,128, 0, 0, 63,128, 0, 2, 55, 39,197,172, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 30, 0, 4, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65,
+ 0, 0, 0, 4, 2,237, 8,144, 0, 0, 0, 0, 0, 0, 0, 1, 2,236,199, 96, 68, 65, 84, 65, 0, 0, 1, 4, 2,237, 8,192,
+ 0, 0, 0,242, 0, 0, 0, 5, 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, 2,237, 9,240, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 80, 2,237, 9,240, 0, 0, 0, 56, 0, 0, 0, 4,
+ 63,128, 0, 0, 63,127,255,255, 39,251,255,255, 0, 0, 0, 0,127,255, 3,255, 63,128, 0, 0,191,128, 0, 0,168, 2, 0, 0,
+ 0, 0, 0, 0,127,255, 3,255,191,128, 0, 1,191,127,255,253,167,251,255,253, 0, 0, 0, 0,127,255, 3,255,191,127,255,250,
+ 63,128, 0, 3, 40, 2, 0, 3, 0, 0, 0, 0,127,255, 3,255, 68, 65, 84, 65, 0, 0, 1, 4, 2,237, 10,112, 0, 0, 0,242,
+ 0, 0, 0, 5, 0, 0, 0, 3, 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, 2,237, 11,160, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 48, 2,237, 11,160, 0, 0, 0, 53, 0, 0, 0, 4, 0, 0, 0, 1,
+ 0, 0, 0, 2, 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 35,
+ 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 35, 68, 65, 84, 65, 0, 0, 1, 4, 2,237, 12, 0, 0, 0, 0,242, 0, 0, 0, 5,
+ 0, 0, 0, 4, 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, 2,237, 13, 48, 0, 0, 0, 5, 0, 0, 0, 20, 0, 0, 0, 0,
+ 0, 0, 0, 0, 85, 86, 84,101,120, 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, 2,237, 13,112, 0, 0, 0, 6, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 67,111,108, 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, 2,237, 13,208, 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, 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, 68, 65, 84, 65, 0, 0, 0, 20, 2,237, 13, 48, 0, 0, 0, 52, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 3,
+ 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 2, 68, 65, 84, 65, 0, 0, 0, 44, 2,237, 13,112, 0, 0, 0, 60, 0, 0, 0, 1,
+ 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 16, 2,237, 13,208, 0, 0, 0, 57, 0, 0, 0, 4,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 68, 65, 84, 65, 0, 0, 0, 60, 2,234,114, 96, 0, 0, 0, 51,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 77, 69, 0, 0, 1, 20, 2,237, 14,128, 0, 0, 0, 50, 0, 0, 0, 1, 0, 0, 0, 0, 2,237, 7, 80, 0, 0, 0, 0,
+ 0, 0, 0, 0, 77, 69, 67,117, 98,101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 2,230, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,237, 15,192,
+ 2,237, 21, 16, 2,237, 21,176, 2,234,116,128, 2,237, 17, 32, 2,237, 19, 32, 0, 0, 0, 0, 2,237, 22,224, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,237, 15,240, 0, 0, 0, 1, 0, 0, 0, 5, 0, 0, 0, 20,
+ 0, 0, 0, 0, 2,237, 17,240, 0, 0, 0, 1, 0, 0, 0, 5, 0, 0, 0, 12, 0, 0, 0, 0, 2,237, 19,224, 0, 0, 0, 3,
+ 0, 0, 0, 5, 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 12, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 51,128, 0, 0,180, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 4, 63,128, 0, 4, 63,128, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 4, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 4, 2,237, 15,192, 0, 0, 0, 0, 0, 0, 0, 1, 2,236,194, 96,
+ 68, 65, 84, 65, 0, 0, 1, 4, 2,237, 15,240, 0, 0, 0,242, 0, 0, 0, 5, 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, 2,237, 17, 32, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,160,
+ 2,237, 17, 32, 0, 0, 0, 56, 0, 0, 0, 8, 63,128, 0, 0, 63,127,255,255,191,128, 0, 0, 73,230, 73,230,182, 26, 3,255,
+ 63,128, 0, 0,191,128, 0, 0,191,128, 0, 0, 73,230,182, 26,182, 26, 3,255,191,128, 0, 1,191,127,255,253,191,128, 0, 0,
+182, 26,182, 26,182, 26, 3,255,191,127,255,250, 63,128, 0, 3,191,128, 0, 0,182, 26, 73,230,182, 26, 3,255, 63,128, 0, 4,
+ 63,127,255,247, 63,128, 0, 0, 73,230, 73,230, 73,230, 3,255, 63,127,255,245,191,128, 0, 5, 63,128, 0, 0, 73,230,182, 26,
+ 73,230, 3,255,191,128, 0, 3,191,127,255,250, 63,128, 0, 0,182, 26,182, 26, 73,230, 3,255,191,127,255,255, 63,128, 0, 0,
+ 63,128, 0, 0,182, 26, 73,230, 73,230, 3,255, 68, 65, 84, 65, 0, 0, 1, 4, 2,237, 17,240, 0, 0, 0,242, 0, 0, 0, 5,
+ 0, 0, 0, 3, 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, 2,237, 19, 32, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0,144, 2,237, 19, 32, 0, 0, 0, 53, 0, 0, 0, 12, 0, 0, 0, 1, 0, 0, 0, 2,
+ 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 35, 0, 0, 0, 2,
+ 0, 0, 0, 3, 0, 0, 0, 35, 0, 0, 0, 4, 0, 0, 0, 5, 0, 0, 0, 35, 0, 0, 0, 5, 0, 0, 0, 6, 0, 0, 0, 35,
+ 0, 0, 0, 6, 0, 0, 0, 7, 0, 0, 0, 35, 0, 0, 0, 4, 0, 0, 0, 7, 0, 0, 0, 35, 0, 0, 0, 1, 0, 0, 0, 5,
+ 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 35, 0, 0, 0, 2, 0, 0, 0, 6, 0, 0, 0, 35, 0, 0, 0, 3,
+ 0, 0, 0, 7, 0, 0, 0, 35, 68, 65, 84, 65, 0, 0, 1, 4, 2,237, 19,224, 0, 0, 0,242, 0, 0, 0, 5, 0, 0, 0, 4,
+ 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, 2,237, 21, 16, 0, 0, 0, 5, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0,
+ 85, 86, 84,101,120, 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,
+ 2,237, 21,176, 0, 0, 0, 6, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 67,111,108, 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, 2,237, 22,224, 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, 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,
+ 68, 65, 84, 65, 0, 0, 0,120, 2,237, 21, 16, 0, 0, 0, 52, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2,
+ 0, 0, 0, 3, 0, 0, 0, 2, 0, 0, 0, 4, 0, 0, 0, 7, 0, 0, 0, 6, 0, 0, 0, 5, 0, 0, 0, 2, 0, 0, 0, 0,
+ 0, 0, 0, 4, 0, 0, 0, 5, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 5, 0, 0, 0, 6, 0, 0, 0, 2,
+ 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 6, 0, 0, 0, 7, 0, 0, 0, 3, 0, 0, 0, 2, 0, 0, 0, 4, 0, 0, 0, 0,
+ 0, 0, 0, 3, 0, 0, 0, 7, 0, 0, 0, 2, 68, 65, 84, 65, 0, 0, 1, 8, 2,237, 21,176, 0, 0, 0, 60, 0, 0, 0, 6,
+ 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 63,128, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 1, 0, 0, 0, 0, 68, 65, 84, 65, 0, 0, 0, 96, 2,237, 22,224, 0, 0, 0, 57, 0, 0, 0, 24,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 68, 65, 84, 65,
+ 0, 0, 1,104, 2,234,116,128, 0, 0, 0, 51, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,
+255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 63,128, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+ 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0,
+ 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0,
+ 63,128, 0, 0, 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 63,128, 0, 0,
+ 63,128, 0, 0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 0, 0, 0, 0, 63,128, 0, 0, 63,128, 0, 0,
+255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 1, 0, 0, 1, 0, 0, 0, 0, 68, 78, 65, 49, 0, 0,127,128,
+ 7, 91, 64, 32, 0, 0, 0, 0, 0, 0, 0, 1, 83, 68, 78, 65, 78, 65, 77, 69, 0, 0, 7, 39, 42,110,101,120,116, 0, 42,112,
+114,101,118, 0, 42,102,105,114,115,116, 0, 42,108, 97,115,116, 0,120, 0,121, 0,122, 0,119, 0,120,109,105,110, 0,120,109,
+ 97,120, 0,121,109,105,110, 0,121,109, 97,120, 0, 42,112,111,105,110,116,101,114, 0,103,114,111,117,112, 0,118, 97,108, 0,
+112, 97,100, 0,110, 97,109,101, 91, 51, 50, 93, 0,116,121,112,101, 0,115,117, 98,116,121,112,101, 0,102,108, 97,103, 0,100,
+ 97,116, 97, 0,108,101,110, 0,116,111,116, 97,108,108,101,110, 0,115, 97,118,101,100, 0, 42,110,101,119,105,100, 0, 42,108,
+105, 98, 0,110, 97,109,101, 91, 50, 52, 93, 0,117,115, 0,105, 99,111,110, 95,105,100, 0, 42,112,114,111,112,101,114,116,105,
+101,115, 0,105,100, 0, 42,105,100, 98,108,111, 99,107, 0, 42,102,105,108,101,100, 97,116, 97, 0,110, 97,109,101, 91, 50, 52,
+ 48, 93, 0,102,105,108,101,110, 97,109,101, 91, 50, 52, 48, 93, 0,116,111,116, 0, 42,112, 97,114,101,110,116, 0, 99,117,114,
+118,101, 0, 99,117,114, 0, 98,108,111, 99,107,116,121,112,101, 0,115,104,111,119,107,101,121, 0,112,111,115, 0, 99,117,114,
+118, 97,108, 0, 97,100,114, 99,111,100,101, 0,116,111,116,101,108,101,109, 0, 42,100, 97,116, 97, 0, 42,119,101,105,103,104,
+116,115, 0,118,103,114,111,117,112, 91, 51, 50, 93, 0,115,108,105,100,101,114,109,105,110, 0,115,108,105,100,101,114,109, 97,
+120, 0, 42,114,101,102,107,101,121, 0,101,108,101,109,115,116,114, 91, 51, 50, 93, 0,101,108,101,109,115,105,122,101, 0, 98,
+108,111, 99,107, 0, 42,105,112,111, 0, 42,102,114,111,109, 0,116,111,116,107,101,121, 0,115,108,117,114,112,104, 0, 42, 42,
+115, 99,114,105,112,116,115, 0, 42,102,108, 97,103, 0, 97, 99,116,115, 99,114,105,112,116, 0,116,111,116,115, 99,114,105,112,
+116, 0, 42,108,105,110,101, 0, 42,102,111,114,109, 97,116, 0, 98,108,101,110, 0, 42,110, 97,109,101, 0,102,108, 97,103,115,
+ 0,110,108,105,110,101,115, 0,108,105,110,101,115, 0, 42, 99,117,114,108, 0, 42,115,101,108,108, 0, 99,117,114, 99, 0,115,
+101,108, 99, 0, 42,117,110,100,111, 95, 98,117,102, 0,117,110,100,111, 95,112,111,115, 0,117,110,100,111, 95,108,101,110, 0,
+ 42, 99,111,109,112,105,108,101,100, 0,115,105,122,101, 0,115,101,101,107, 0,112, 97,115,115,101,112, 97,114,116, 97,108,112,
+104, 97, 0,112, 97,100, 49, 0, 99,108,105,112,115,116, 97, 0, 99,108,105,112,101,110,100, 0,108,101,110,115, 0,111,114,116,
+104,111, 95,115, 99, 97,108,101, 0,100,114, 97,119,115,105,122,101, 0,115,104,105,102,116,120, 0,115,104,105,102,116,121, 0,
+ 89, 70, 95,100,111,102,100,105,115,116, 0, 89, 70, 95, 97,112,101,114,116,117,114,101, 0, 89, 70, 95, 98,107,104,116,121,112,
+101, 0, 89, 70, 95, 98,107,104, 98,105, 97,115, 0, 89, 70, 95, 98,107,104,114,111,116, 0,115, 99,114,105,112,116,108,105,110,
+107, 0,104, 0, 42,114,101, 99,116, 0,102,114, 97,109,101,110,114, 0,102,114, 97,109,101,115, 0,111,102,102,115,101,116, 0,
+115,102,114, 97, 0,102,105,101, 95,105,109, 97, 0, 99,121, 99,108, 0,111,107, 0,109,117,108,116,105, 95,105,110,100,101,120,
+ 0,108, 97,121,101,114, 0,112, 97,115,115, 0,109,101,110,117,110,114, 0,105, 98,117,102,115, 0, 42, 97,110,105,109, 0, 42,
+114,114, 0,115,111,117,114, 99,101, 0,108, 97,115,116,102,114, 97,109,101, 0,116,112, 97,103,101,102,108, 97,103, 0,116,111,
+116, 98,105,110,100, 0,120,114,101,112, 0,121,114,101,112, 0,116,119,115,116, 97, 0,116,119,101,110,100, 0, 98,105,110,100,
+ 99,111,100,101, 0, 42,114,101,112, 98,105,110,100, 0, 42,112, 97, 99,107,101,100,102,105,108,101, 0, 42,112,114,101,118,105,
+101,119, 0,108, 97,115,116,117,112,100, 97,116,101, 0,108, 97,115,116,117,115,101,100, 0, 97,110,105,109,115,112,101,101,100,
+ 0,103,101,110, 95,120, 0,103,101,110, 95,121, 0,103,101,110, 95,116,121,112,101, 0, 42,118,110,111,100,101, 0,116,101,120,
+ 99,111, 0,109, 97,112,116,111, 0,109, 97,112,116,111,110,101,103, 0, 98,108,101,110,100,116,121,112,101, 0, 42,111, 98,106,
+101, 99,116, 0, 42,116,101,120, 0,117,118,110, 97,109,101, 91, 51, 50, 93, 0,112,114,111,106,120, 0,112,114,111,106,121, 0,
+112,114,111,106,122, 0,109, 97,112,112,105,110,103, 0,111,102,115, 91, 51, 93, 0,115,105,122,101, 91, 51, 93, 0,116,101,120,
+102,108, 97,103, 0, 99,111,108,111,114,109,111,100,101,108, 0,114, 0,103, 0, 98, 0,107, 0,100,101,102, 95,118, 97,114, 0,
+ 99,111,108,102, 97, 99, 0,110,111,114,102, 97, 99, 0,118, 97,114,102, 97, 99, 0,100,105,115,112,102, 97, 99, 0,119, 97,114,
+112,102, 97, 99, 0,110, 97,109,101, 91, 49, 54, 48, 93, 0, 42,104, 97,110,100,108,101, 0, 42,112,110, 97,109,101, 0, 42,115,
+116,110, 97,109,101,115, 0,115,116,121,112,101,115, 0,118, 97,114,115, 0, 42,118, 97,114,115,116,114, 0, 42,114,101,115,117,
+108,116, 0, 42, 99,102,114, 97, 0,100, 97,116, 97, 91, 51, 50, 93, 0, 40, 42,100,111,105,116, 41, 40, 41, 0, 40, 42,105,110,
+115,116, 97,110, 99,101, 95,105,110,105,116, 41, 40, 41, 0, 40, 42, 99, 97,108,108, 98, 97, 99,107, 41, 40, 41, 0,118,101,114,
+115,105,111,110, 0, 97, 0,105,112,111,116,121,112,101, 0, 42,105,109, 97, 0, 42, 99,117, 98,101, 91, 54, 93, 0,105,109, 97,
+116, 91, 52, 93, 91, 52, 93, 0,111, 98,105,109, 97,116, 91, 51, 93, 91, 51, 93, 0,115,116,121,112,101, 0,118,105,101,119,115,
+ 99, 97,108,101, 0,110,111,116,108, 97,121, 0, 99,117, 98,101,114,101,115, 0,100,101,112,116,104, 0,114,101, 99, 97,108, 99,
+ 0,108, 97,115,116,115,105,122,101, 0,110,111,105,115,101,115,105,122,101, 0,116,117,114, 98,117,108, 0, 98,114,105,103,104,
+116, 0, 99,111,110,116,114, 97,115,116, 0,114,102, 97, 99, 0,103,102, 97, 99, 0, 98,102, 97, 99, 0,102,105,108,116,101,114,
+115,105,122,101, 0,109,103, 95, 72, 0,109,103, 95,108, 97, 99,117,110, 97,114,105,116,121, 0,109,103, 95,111, 99,116, 97,118,
+101,115, 0,109,103, 95,111,102,102,115,101,116, 0,109,103, 95,103, 97,105,110, 0,100,105,115,116, 95, 97,109,111,117,110,116,
+ 0,110,115, 95,111,117,116,115, 99, 97,108,101, 0,118,110, 95,119, 49, 0,118,110, 95,119, 50, 0,118,110, 95,119, 51, 0,118,
+110, 95,119, 52, 0,118,110, 95,109,101,120,112, 0,118,110, 95,100,105,115,116,109, 0,118,110, 95, 99,111,108,116,121,112,101,
+ 0,110,111,105,115,101,100,101,112,116,104, 0,110,111,105,115,101,116,121,112,101, 0,110,111,105,115,101, 98, 97,115,105,115,
+ 0,110,111,105,115,101, 98, 97,115,105,115, 50, 0,105,109, 97,102,108, 97,103, 0, 99,114,111,112,120,109,105,110, 0, 99,114,
+111,112,121,109,105,110, 0, 99,114,111,112,120,109, 97,120, 0, 99,114,111,112,121,109, 97,120, 0,120,114,101,112,101, 97,116,
+ 0,121,114,101,112,101, 97,116, 0,101,120,116,101,110,100, 0, 99,104,101, 99,107,101,114,100,105,115,116, 0,110, 97, 98,108,
+ 97, 0,105,117,115,101,114, 0, 42,112,108,117,103,105,110, 0, 42, 99,111, 98, 97, 0, 42,101,110,118, 0,108,111, 99, 91, 51,
+ 93, 0,114,111,116, 91, 51, 93, 0,109, 97,116, 91, 52, 93, 91, 52, 93, 0,109,105,110, 91, 51, 93, 0,109, 97,120, 91, 51, 93,
+ 0, 42,111, 98, 0,109,111,100,101, 0,116,111,116,101,120, 0,101,110,101,114,103,121, 0,100,105,115,116, 0,115,112,111,116,
+115,105,122,101, 0,115,112,111,116, 98,108,101,110,100, 0,104, 97,105,110,116, 0, 97,116,116, 49, 0, 97,116,116, 50, 0,115,
+104, 97,100,115,112,111,116,115,105,122,101, 0, 98,105, 97,115, 0,115,111,102,116, 0, 98,117,102,115,105,122,101, 0,115, 97,
+109,112, 0, 98,117,102,102,101,114,115, 0,102,105,108,116,101,114,116,121,112,101, 0, 98,117,102,102,108, 97,103, 0, 98,117,
+102,116,121,112,101, 0,114, 97,121, 95,115, 97,109,112, 0,114, 97,121, 95,115, 97,109,112,121, 0,114, 97,121, 95,115, 97,109,
+112,122, 0,114, 97,121, 95,115, 97,109,112, 95,116,121,112,101, 0, 97,114,101, 97, 95,115,104, 97,112,101, 0, 97,114,101, 97,
+ 95,115,105,122,101, 0, 97,114,101, 97, 95,115,105,122,101,121, 0, 97,114,101, 97, 95,115,105,122,101,122, 0,116,101,120, 97,
+ 99,116, 0,115,104, 97,100,104, 97,108,111,115,116,101,112, 0, 89, 70, 95,110,117,109,112,104,111,116,111,110,115, 0, 89, 70,
+ 95,110,117,109,115,101, 97,114, 99,104, 0, 89, 70, 95,112,104,100,101,112,116,104, 0, 89, 70, 95,117,115,101,113,109, 99, 0,
+ 89, 70, 95, 98,117,102,115,105,122,101, 0, 89, 70, 95,112, 97,100, 0, 89, 70, 95, 99, 97,117,115,116,105, 99, 98,108,117,114,
+ 0, 89, 70, 95,108,116,114, 97,100,105,117,115, 0, 89, 70, 95,103,108,111,119,105,110,116, 0, 89, 70, 95,103,108,111,119,111,
+102,115, 0, 89, 70, 95,103,108,111,119,116,121,112,101, 0, 89, 70, 95,112, 97,100, 50, 0, 42,109,116,101,120, 91, 49, 48, 93,
+ 0,115,112,101, 99,114, 0,115,112,101, 99,103, 0,115,112,101, 99, 98, 0,109,105,114,114, 0,109,105,114,103, 0,109,105,114,
+ 98, 0, 97,109, 98,114, 0, 97,109, 98, 98, 0, 97,109, 98,103, 0, 97,109, 98, 0,101,109,105,116, 0, 97,110,103, 0,115,112,
+101, 99,116,114, 97, 0,114, 97,121, 95,109,105,114,114,111,114, 0, 97,108,112,104, 97, 0,114,101,102, 0,115,112,101, 99, 0,
+122,111,102,102,115, 0, 97,100,100, 0,116,114, 97,110,115,108,117, 99,101,110, 99,121, 0,102,114,101,115,110,101,108, 95,109,
+105,114, 0,102,114,101,115,110,101,108, 95,109,105,114, 95,105, 0,102,114,101,115,110,101,108, 95,116,114, 97, 0,102,114,101,
+115,110,101,108, 95,116,114, 97, 95,105, 0,102,105,108,116,101,114, 0,116,120, 95,108,105,109,105,116, 0,116,120, 95,102, 97,
+108,108,111,102,102, 0,114, 97,121, 95,100,101,112,116,104, 0,114, 97,121, 95,100,101,112,116,104, 95,116,114, 97, 0,104, 97,
+114, 0,115,101,101,100, 49, 0,115,101,101,100, 50, 0,109,111,100,101, 95,108, 0,102,108, 97,114,101, 99, 0,115,116, 97,114,
+ 99, 0,108,105,110,101, 99, 0,114,105,110,103, 99, 0,104, 97,115,105,122,101, 0,102,108, 97,114,101,115,105,122,101, 0,115,
+117, 98,115,105,122,101, 0,102,108, 97,114,101, 98,111,111,115,116, 0,115,116,114, 97,110,100, 95,115,116, 97, 0,115,116,114,
+ 97,110,100, 95,101,110,100, 0,115,116,114, 97,110,100, 95,101, 97,115,101, 0,115, 98,105, 97,115, 0,115,104, 97,100, 95, 97,
+108,112,104, 97, 0,112, 97,100,102, 0,114,103, 98,115,101,108, 0,112,114, 95,116,121,112,101, 0,117,115,101, 95,110,111,100,
+101,115, 0,112,114, 95, 98, 97, 99,107, 0,112,114, 95,108, 97,109,112, 0,115,101,112,116,101,120, 0,109,108, 95,102,108, 97,
+103, 0,100,105,102,102, 95,115,104, 97,100,101,114, 0,115,112,101, 99, 95,115,104, 97,100,101,114, 0,114,111,117,103,104,110,
+101,115,115, 0,114,101,102,114, 97, 99, 0,112, 97,114, 97,109, 91, 52, 93, 0,114,109,115, 0,100, 97,114,107,110,101,115,115,
+ 0, 42,114, 97,109,112, 95, 99,111,108, 0, 42,114, 97,109,112, 95,115,112,101, 99, 0,114, 97,109,112,105,110, 95, 99,111,108,
+ 0,114, 97,109,112,105,110, 95,115,112,101, 99, 0,114, 97,109,112, 98,108,101,110,100, 95, 99,111,108, 0,114, 97,109,112, 98,
+108,101,110,100, 95,115,112,101, 99, 0,114, 97,109,112, 95,115,104,111,119, 0,112, 97,100, 51, 0,114, 97,109,112,102, 97, 99,
+ 95, 99,111,108, 0,114, 97,109,112,102, 97, 99, 95,115,112,101, 99, 0, 42,110,111,100,101,116,114,101,101, 0, 42,103,114,111,
+117,112, 0,102,114,105, 99,116,105,111,110, 0,102,104, 0,114,101,102,108,101, 99,116, 0,102,104,100,105,115,116, 0,120,121,
+102,114,105, 99,116, 0,100,121,110, 97,109,111,100,101, 0,112, 97,100, 50, 0, 89, 70, 95, 97,114, 0, 89, 70, 95, 97,103, 0,
+ 89, 70, 95, 97, 98, 0, 89, 70, 95,100,115, 99, 97,108,101, 0, 89, 70, 95,100,112,119,114, 0, 89, 70, 95,100,115,109,112, 0,
+ 89, 70, 95,112,114,101,115,101,116, 0, 89, 70, 95,100,106,105,116, 0,110, 97,109,101, 91, 50, 53, 54, 93, 0,115, 99, 97,108,
+101, 0, 42, 98, 98, 0,105, 49, 0,106, 49, 0,107, 49, 0,105, 50, 0,106, 50, 0,107, 50, 0,115,101,108, 99,111,108, 49, 0,
+115,101,108, 99,111,108, 50, 0,113,117, 97,116, 91, 52, 93, 0,101,120,112,120, 0,101,120,112,121, 0,101,120,112,122, 0,114,
+ 97,100, 0,114, 97,100, 50, 0,115, 0, 42,109, 97,116, 0, 42,105,109, 97,116, 0,101,108,101,109,115, 0,100,105,115,112, 0,
+ 42, 42,109, 97,116, 0,116,111,116, 99,111,108, 0,119,105,114,101,115,105,122,101, 0,114,101,110,100,101,114,115,105,122,101,
+ 0,116,104,114,101,115,104, 0,118,101, 99, 91, 51, 93, 91, 51, 93, 0, 97,108,102, 97, 0,119,101,105,103,104,116, 0,114, 97,
+100,105,117,115, 0,104, 49, 0,104, 50, 0,102, 49, 0,102, 50, 0,102, 51, 0,104,105,100,101, 0,118,101, 99, 91, 52, 93, 0,
+109, 97,116, 95,110,114, 0,112,110,116,115,117, 0,112,110,116,115,118, 0,114,101,115,111,108,117, 0,114,101,115,111,108,118,
+ 0,111,114,100,101,114,117, 0,111,114,100,101,114,118, 0,102,108, 97,103,117, 0,102,108, 97,103,118, 0, 42,107,110,111,116,
+115,117, 0, 42,107,110,111,116,115,118, 0, 42, 98,112, 0, 42, 98,101,122,116, 0, 99,104, 97,114,105,100,120, 0,107,101,114,
+110, 0,110,117,114, 98, 0, 42, 98,101,118,111, 98,106, 0, 42,116, 97,112,101,114,111, 98,106, 0, 42,116,101,120,116,111,110,
+ 99,117,114,118,101, 0, 42,112, 97,116,104, 0, 42,107,101,121, 0, 98,101,118, 0,112, 97,116,104,108,101,110, 0, 98,101,118,
+114,101,115,111,108, 0,119,105,100,116,104, 0,101,120,116, 49, 0,101,120,116, 50, 0,114,101,115,111,108,117, 95,114,101,110,
+ 0,114,101,115,111,108,118, 95,114,101,110, 0,115,112, 97, 99,101,109,111,100,101, 0,115,112, 97, 99,105,110,103, 0,108,105,
+110,101,100,105,115,116, 0,115,104,101, 97,114, 0,102,115,105,122,101, 0,119,111,114,100,115,112, 97, 99,101, 0,117,108,112,
+111,115, 0,117,108,104,101,105,103,104,116, 0,120,111,102, 0,121,111,102, 0,108,105,110,101,119,105,100,116,104, 0, 42,115,
+116,114, 0,102, 97,109,105,108,121, 91, 50, 52, 93, 0, 42,118,102,111,110,116, 0, 42,118,102,111,110,116, 98, 0, 42,118,102,
+111,110,116,105, 0, 42,118,102,111,110,116, 98,105, 0,115,101,112, 99,104, 97,114, 0,116,111,116, 98,111,120, 0, 97, 99,116,
+ 98,111,120, 0, 42,116, 98, 0,115,101,108,115,116, 97,114,116, 0,115,101,108,101,110,100, 0, 42,115,116,114,105,110,102,111,
+ 0, 99,117,114,105,110,102,111, 0,110, 97,109,101, 91, 49, 50, 56, 93, 0,109, 97,120,114, 99,116, 0,116,111,116,114, 99,116,
+ 0,118, 97,114,116,121,112,101, 0,116,111,116,118,101,114,116, 0,105,112,111, 0,101,120,116,114, 97,112, 0,114,116, 0, 98,
+105,116,109, 97,115,107, 0, 42,100,114,105,118,101,114, 0,101,102,102,101, 99,116, 0, 42,109,102, 97, 99,101, 0, 42,109,116,
+102, 97, 99,101, 0, 42,116,102, 97, 99,101, 0, 42,109,118,101,114,116, 0, 42,109,101,100,103,101, 0, 42,100,118,101,114,116,
+ 0, 42,109, 99,111,108, 0, 42,109,115,116,105, 99,107,121, 0, 42,116,101,120, 99,111,109,101,115,104, 0, 42,109,115,101,108,
+101, 99,116, 0, 42,111, 99, 0, 42,115,117,109,111,104, 97,110,100,108,101, 0,118,100, 97,116, 97, 0,101,100, 97,116, 97, 0,
+102,100, 97,116, 97, 0,116,111,116,101,100,103,101, 0,116,111,116,102, 97, 99,101, 0,116,111,116,115,101,108,101, 99,116, 0,
+ 99,117, 98,101,109, 97,112,115,105,122,101, 0,115,109,111,111,116,104,114,101,115,104, 0,115,117, 98,100,105,118, 0,115,117,
+ 98,100,105,118,114, 0,115,117, 98,115,117,114,102,116,121,112,101, 0, 42,109,114, 0, 42,112,118, 0, 42,116,112, 97,103,101,
+ 0,117,118, 91, 52, 93, 91, 50, 93, 0, 99,111,108, 91, 52, 93, 0,116,114, 97,110,115,112, 0,116,105,108,101, 0,117,110,119,
+114, 97,112, 0,118, 49, 0,118, 50, 0,118, 51, 0,118, 52, 0,101,100, 99,111,100,101, 0, 99,114,101, 97,115,101, 0,100,101,
+102, 95,110,114, 0, 42,100,119, 0,116,111,116,119,101,105,103,104,116, 0, 99,111, 91, 51, 93, 0,110,111, 91, 51, 93, 0, 99,
+111, 91, 50, 93, 0,105,110,100,101,120, 0,118, 91, 52, 93, 0,109,105,100, 0, 99,104,105,108,100,114,101,110,115,116, 97,114,
+116, 0,112, 97,100, 91, 50, 93, 0,118, 91, 50, 93, 0, 42,118,101,114,116,115, 0, 42,102, 97, 99,101,115, 0, 42, 99,111,108,
+102, 97, 99,101,115, 0, 42,101,100,103,101,115, 0, 42,118,101,114,116, 95,101,100,103,101, 95,109, 97,112, 0, 42,118,101,114,
+116, 95,102, 97, 99,101, 95,109, 97,112, 0, 42,109, 97,112, 95,109,101,109, 0,108,101,118,101,108,115, 0,108,101,118,101,108,
+ 95, 99,111,117,110,116, 0, 99,117,114,114,101,110,116, 0,110,101,119,108,118,108, 0,101,100,103,101,108,118,108, 0,112,105,
+110,108,118,108, 0,114,101,110,100,101,114,108,118,108, 0,117,115,101, 95, 99,111,108, 0, 42,101,100,103,101, 95,102,108, 97,
+103,115, 0, 42,118,101,114,116, 95,109, 97,112, 0, 42,101,100,103,101, 95,109, 97,112, 0, 42,111,108,100, 95,102, 97, 99,101,
+115, 0, 42,111,108,100, 95,101,100,103,101,115, 0, 42,101,114,114,111,114, 0,109,111,100,105,102,105,101,114, 0,115,117, 98,
+100,105,118, 84,121,112,101, 0,114,101,110,100,101,114, 76,101,118,101,108,115, 0, 42,101,109, 67, 97, 99,104,101, 0, 42,109,
+ 67, 97, 99,104,101, 0,100,101,102, 97,120,105,115, 0,112, 97,100, 91, 54, 93, 0,115,116, 97,114,116, 0,108,101,110,103,116,
+104, 0,114, 97,110,100,111,109,105,122,101, 0,115,101,101,100, 0, 42, 99,117,114,118,101, 95,111, 98, 0, 42,111,102,102,115,
+101,116, 95,111, 98, 0,111,102,102,115,101,116, 91, 51, 93, 0,115, 99, 97,108,101, 91, 51, 93, 0,109,101,114,103,101, 95,100,
+105,115,116, 0,102,105,116, 95,116,121,112,101, 0,111,102,102,115,101,116, 95,116,121,112,101, 0, 99,111,117,110,116, 0, 97,
+120,105,115, 0,116,111,108,101,114, 97,110, 99,101, 0,115,112,108,105,116, 95, 97,110,103,108,101, 0, 42,116,101,120,116,117,
+114,101, 0,115,116,114,101,110,103,116,104, 0,100,105,114,101, 99,116,105,111,110, 0,100,101,102,103,114,112, 95,110, 97,109,
+101, 91, 51, 50, 93, 0,109,105,100,108,101,118,101,108, 0,116,101,120,109, 97,112,112,105,110,103, 0, 42,109, 97,112, 95,111,
+ 98,106,101, 99,116, 0, 42,112,114,111,106,101, 99,116,111,114,115, 91, 49, 48, 93, 0, 42,105,109, 97,103,101, 0,110,117,109,
+ 95,112,114,111,106,101, 99,116,111,114,115, 0, 97,115,112,101, 99,116,120, 0, 97,115,112,101, 99,116,121, 0,112,101,114, 99,
+101,110,116, 0,102, 97, 99,101, 67,111,117,110,116, 0, 42,111, 98,106,101, 99,116, 99,101,110,116,101,114, 0,115,116, 97,114,
+116,120, 0,115,116, 97,114,116,121, 0,104,101,105,103,104,116, 0,110, 97,114,114,111,119, 0,115,112,101,101,100, 0,100, 97,
+109,112, 0,116,105,109,101,111,102,102,115, 0,108,105,102,101,116,105,109,101, 0,100,101,102,111,114,109,102,108, 97,103, 0,
+112, 97,114,101,110,116,105,110,118, 91, 52, 93, 91, 52, 93, 0, 99,101,110,116, 91, 51, 93, 0,102, 97,108,108,111,102,102, 0,
+ 42,105,110,100,101,120, 97,114, 0,116,111,116,105,110,100,101,120, 0,102,111,114, 99,101, 0,111,112,101,114, 97,116,105,111,
+110, 0,112, 97,115,115,101,115, 0,102, 97, 99,116,111,114, 0,112,110,116,115,119, 0,111,112,110,116,115,117, 0,111,112,110,
+116,115,118, 0,111,112,110,116,115,119, 0,116,121,112,101,117, 0,116,121,112,101,118, 0,116,121,112,101,119, 0,102,117, 0,
+102,118, 0,102,119, 0,100,117, 0,100,118, 0,100,119, 0, 42,100,101,102, 0,118,101, 99, 91, 56, 93, 91, 51, 93, 0,100,118,
+101, 99, 91, 51, 93, 0,109, 97,120, 0, 42, 42,111, 98, 0,112, 97,114,116,121,112,101, 0,112, 97,114, 49, 0,112, 97,114, 50,
+ 0,112, 97,114, 51, 0,112, 97,114,115,117, 98,115,116,114, 91, 51, 50, 93, 0, 42,112, 97,114,100, 97,116, 97, 0, 42,116,114,
+ 97, 99,107, 0, 42,112,114,111,120,121, 0, 42,112,114,111,120,121, 95,103,114,111,117,112, 0, 42,112,114,111,120,121, 95,102,
+114,111,109, 0, 42, 97, 99,116,105,111,110, 0, 42,112,111,115,101, 0, 99,111,110,115,116,114, 97,105,110,116, 67,104, 97,110,
+110,101,108,115, 0,110,101,116,119,111,114,107, 0,100,101,102, 98, 97,115,101, 0,109,111,100,105,102,105,101,114,115, 0,100,
+108,111, 99, 91, 51, 93, 0,111,114,105,103, 91, 51, 93, 0,100,115,105,122,101, 91, 51, 93, 0,100,114,111,116, 91, 51, 93, 0,
+100,113,117, 97,116, 91, 52, 93, 0,111, 98,109, 97,116, 91, 52, 93, 91, 52, 93, 0,108, 97,121, 0, 99,111,108, 98,105,116,115,
+ 0,116,114, 97,110,115,102,108, 97,103, 0,105,112,111,102,108, 97,103, 0,116,114, 97, 99,107,102,108, 97,103, 0,117,112,102,
+108, 97,103, 0,110,108, 97,102,108, 97,103, 0,112,114,111,116,101, 99,116,102,108, 97,103, 0,105,112,111,119,105,110, 0,115,
+ 99, 97,102,108, 97,103, 0,115, 99, 97,118,105,115,102,108, 97,103, 0, 98,111,117,110,100,116,121,112,101, 0,100,117,112,111,
+110, 0,100,117,112,111,102,102, 0,100,117,112,115,116, 97, 0,100,117,112,101,110,100, 0,115,102, 0, 99,116,105,109,101, 0,
+109, 97,115,115, 0,100, 97,109,112,105,110,103, 0,105,110,101,114,116,105, 97, 0,102,111,114,109,102, 97, 99,116,111,114, 0,
+115,111,102,116,116,105,109,101, 0,114,100, 97,109,112,105,110,103, 0,115,105,122,101,102, 97, 99, 0,100,116, 0,100,116,120,
+ 0, 97, 99,116, 99,111,108, 0,101,109,112,116,121, 95,100,114, 97,119,116,121,112,101, 0,112, 97,100, 49, 91, 51, 93, 0,101,
+109,112,116,121, 95,100,114, 97,119,115,105,122,101, 0,112,114,111,112, 0,115,101,110,115,111,114,115, 0, 99,111,110,116,114,
+111,108,108,101,114,115, 0, 97, 99,116,117, 97,116,111,114,115, 0, 98, 98,115,105,122,101, 91, 51, 93, 0, 97, 99,116,100,101,
+102, 0,103, 97,109,101,102,108, 97,103, 0,103, 97,109,101,102,108, 97,103, 50, 0,115,111,102,116,102,108, 97,103, 0, 97,110,
+105,115,111,116,114,111,112,105, 99, 70,114,105, 99,116,105,111,110, 91, 51, 93, 0, 99,111,110,115,116,114, 97,105,110,116,115,
+ 0,110,108, 97,115,116,114,105,112,115, 0,104,111,111,107,115, 0, 42,112,100, 0, 42,115,111,102,116, 0, 42,100,117,112, 95,
+103,114,111,117,112, 0,102,108,117,105,100,115,105,109, 70,108, 97,103, 0,114,101,115,116,114,105, 99,116,102,108, 97,103, 0,
+115,104, 97,112,101,110,114, 0,115,104, 97,112,101,102,108, 97,103, 0,112, 97,100, 52, 0, 42,102,108,117,105,100,115,105,109,
+ 83,101,116,116,105,110,103,115, 0, 42,100,101,114,105,118,101,100, 68,101,102,111,114,109, 0, 42,100,101,114,105,118,101,100,
+ 70,105,110, 97,108, 0,108, 97,115,116, 68, 97,116, 97, 77, 97,115,107, 0, 99,117,114,105,110,100,101,120, 0, 97, 99,116,105,
+118,101, 0,100,101,102,108,101, 99,116, 0,102,111,114, 99,101,102,105,101,108,100, 0,112,100,101,102, 95,100, 97,109,112, 0,
+112,100,101,102, 95,114,100, 97,109,112, 0,112,100,101,102, 95,112,101,114,109, 0,102, 95,115,116,114,101,110,103,116,104, 0,
+102, 95,112,111,119,101,114, 0,109, 97,120,100,105,115,116, 0,112,100,101,102, 95,115, 98,100, 97,109,112, 0,112,100,101,102,
+ 95,115, 98,105,102,116, 0,112,100,101,102, 95,115, 98,111,102,116, 0,116,111,116,112,111,105,110,116, 0,116,111,116,115,112,
+114,105,110,103, 0, 42, 98,112,111,105,110,116, 0, 42, 98,115,112,114,105,110,103, 0,110,111,100,101,109, 97,115,115, 0,103,
+114, 97,118, 0,109,101,100,105, 97,102,114,105, 99,116, 0,114,107,108,105,109,105,116, 0,112,104,121,115,105, 99,115, 95,115,
+112,101,101,100, 0,103,111, 97,108,115,112,114,105,110,103, 0,103,111, 97,108,102,114,105, 99,116, 0,109,105,110,103,111, 97,
+108, 0,109, 97,120,103,111, 97,108, 0,100,101,102,103,111, 97,108, 0,118,101,114,116,103,114,111,117,112, 0,102,117,122,122,
+121,110,101,115,115, 0,105,110,115,112,114,105,110,103, 0,105,110,102,114,105, 99,116, 0,101,102,114, 97, 0,105,110,116,101,
+114,118, 97,108, 0,108,111, 99, 97,108, 0,115,111,108,118,101,114,102,108, 97,103,115, 0, 42, 42,107,101,121,115, 0,116,111,
+116,112,111,105,110,116,107,101,121, 0,115,101, 99,111,110,100,115,112,114,105,110,103, 0, 99,111,108, 98, 97,108,108, 0, 98,
+ 97,108,108,100, 97,109,112, 0, 98, 97,108,108,115,116,105,102,102, 0,115, 98, 99, 95,109,111,100,101, 0, 97,101,114,111,101,
+100,103,101, 0,109,105,110,108,111,111,112,115, 0,109, 97,120,108,111,111,112,115, 0, 99,104,111,107,101, 0,112, 97,100, 53,
+ 0, 42,115, 99,114, 97,116, 99,104, 0,115,104,111,119, 95, 97,100,118, 97,110, 99,101,100,111,112,116,105,111,110,115, 0,114,
+101,115,111,108,117,116,105,111,110,120,121,122, 0,112,114,101,118,105,101,119,114,101,115,120,121,122, 0,114,101, 97,108,115,
+105,122,101, 0,103,117,105, 68,105,115,112,108, 97,121, 77,111,100,101, 0,114,101,110,100,101,114, 68,105,115,112,108, 97,121,
+ 77,111,100,101, 0,118,105,115, 99,111,115,105,116,121, 86, 97,108,117,101, 0,118,105,115, 99,111,115,105,116,121, 77,111,100,
+101, 0,118,105,115, 99,111,115,105,116,121, 69,120,112,111,110,101,110,116, 0,103,114, 97,118,120, 0,103,114, 97,118,121, 0,
+103,114, 97,118,122, 0, 97,110,105,109, 83,116, 97,114,116, 0, 97,110,105,109, 69,110,100, 0,103,115,116, 97,114, 0,109, 97,
+120, 82,101,102,105,110,101, 0,105,110,105, 86,101,108,120, 0,105,110,105, 86,101,108,121, 0,105,110,105, 86,101,108,122, 0,
+ 42,111,114,103, 77,101,115,104, 0, 42,109,101,115,104, 83,117,114,102, 97, 99,101, 0, 42,109,101,115,104, 66, 66, 0,115,117,
+114,102,100, 97,116, 97, 80, 97,116,104, 91, 50, 52, 48, 93, 0, 98, 98, 83,116, 97,114,116, 91, 51, 93, 0, 98, 98, 83,105,122,
+101, 91, 51, 93, 0,116,121,112,101, 70,108, 97,103,115, 0,100,111,109, 97,105,110, 78,111,118,101, 99,103,101,110, 0,118,111,
+108,117,109,101, 73,110,105,116, 84,121,112,101, 0,112, 97,114,116, 83,108,105,112, 86, 97,108,117,101, 0,103,101,110,101,114,
+ 97,116,101, 84,114, 97, 99,101,114,115, 0,103,101,110,101,114, 97,116,101, 80, 97,114,116,105, 99,108,101,115, 0,115,117,114,
+102, 97, 99,101, 83,109,111,111,116,104,105,110,103, 0,115,117,114,102, 97, 99,101, 83,117, 98,100,105,118,115, 0,117,110,117,
+115,101,100, 68, 78, 65, 68,117,109,109,121, 0,112, 97,114,116,105, 99,108,101, 73,110,102, 83,105,122,101, 0,112, 97,114,116,
+105, 99,108,101, 73,110,102, 65,108,112,104, 97, 0,102, 97,114, 70,105,101,108,100, 83,105,122,101, 0, 42,109,101,115,104, 83,
+117,114,102, 78,111,114,109, 97,108,115, 0,109,105,115,116,121,112,101, 0,104,111,114,114, 0,104,111,114,103, 0,104,111,114,
+ 98, 0,104,111,114,107, 0,122,101,110,114, 0,122,101,110,103, 0,122,101,110, 98, 0,122,101,110,107, 0, 97,109, 98,107, 0,
+102, 97,115,116, 99,111,108, 0,101,120,112,111,115,117,114,101, 0,101,120,112, 0,114, 97,110,103,101, 0,108,105,110,102, 97,
+ 99, 0,108,111,103,102, 97, 99, 0,103,114, 97,118,105,116,121, 0, 97, 99,116,105,118,105,116,121, 66,111,120, 82, 97,100,105,
+117,115, 0,115,107,121,116,121,112,101, 0,112,104,121,115,105, 99,115, 69,110,103,105,110,101, 0,109,105,115,105, 0,109,105,
+115,116,115,116, 97, 0,109,105,115,116,100,105,115,116, 0,109,105,115,116,104,105, 0,115,116, 97,114,114, 0,115,116, 97,114,
+103, 0,115,116, 97,114, 98, 0,115,116, 97,114,107, 0,115,116, 97,114,115,105,122,101, 0,115,116, 97,114,109,105,110,100,105,
+115,116, 0,115,116, 97,114,100,105,115,116, 0,115,116, 97,114, 99,111,108,110,111,105,115,101, 0,100,111,102,115,116, 97, 0,
+100,111,102,101,110,100, 0,100,111,102,109,105,110, 0,100,111,102,109, 97,120, 0, 97,111,100,105,115,116, 0, 97,111,100,105,
+115,116,102, 97, 99, 0, 97,111,101,110,101,114,103,121, 0, 97,111, 98,105, 97,115, 0, 97,111,109,111,100,101, 0, 97,111,115,
+ 97,109,112, 0, 97,111,109,105,120, 0, 97,111, 99,111,108,111,114, 0, 42, 97,111,115,112,104,101,114,101, 0, 42, 97,111,116,
+ 97, 98,108,101,115, 0,104,101,109,105,114,101,115, 0,109, 97,120,105,116,101,114, 0,100,114, 97,119,116,121,112,101, 0,115,
+117, 98,115,104,111,111,116,112, 0,115,117, 98,115,104,111,111,116,101, 0,110,111,100,101,108,105,109, 0,109, 97,120,115,117,
+ 98,108, 97,109,112, 0,112, 97,109, 97, 0,112, 97,109,105, 0,101,108,109, 97, 0,101,108,109,105, 0,109, 97,120,110,111,100,
+101, 0, 99,111,110,118,101,114,103,101,110, 99,101, 0,114, 97,100,102, 97, 99, 0,103, 97,109,109, 97, 0,115,101,108, 99,111,
+108, 0,115,120, 0,115,121, 0, 42,108,112, 70,111,114,109, 97,116, 0, 42,108,112, 80, 97,114,109,115, 0, 99, 98, 70,111,114,
+109, 97,116, 0, 99, 98, 80, 97,114,109,115, 0,102, 99, 99, 84,121,112,101, 0,102, 99, 99, 72, 97,110,100,108,101,114, 0,100,
+119, 75,101,121, 70,114, 97,109,101, 69,118,101,114,121, 0,100,119, 81,117, 97,108,105,116,121, 0,100,119, 66,121,116,101,115,
+ 80,101,114, 83,101, 99,111,110,100, 0,100,119, 70,108, 97,103,115, 0,100,119, 73,110,116,101,114,108,101, 97,118,101, 69,118,
+101,114,121, 0, 97,118,105, 99,111,100,101, 99,110, 97,109,101, 91, 49, 50, 56, 93, 0, 42, 99,100, 80, 97,114,109,115, 0, 42,
+112, 97,100, 0, 99,100, 83,105,122,101, 0,113,116, 99,111,100,101, 99,110, 97,109,101, 91, 49, 50, 56, 93, 0, 99,111,100,101,
+ 99, 0, 97,117,100,105,111, 95, 99,111,100,101, 99, 0,118,105,100,101,111, 95, 98,105,116,114, 97,116,101, 0, 97,117,100,105,
+111, 95, 98,105,116,114, 97,116,101, 0,103,111,112, 95,115,105,122,101, 0,114, 99, 95,109,105,110, 95,114, 97,116,101, 0,114,
+ 99, 95,109, 97,120, 95,114, 97,116,101, 0,114, 99, 95, 98,117,102,102,101,114, 95,115,105,122,101, 0,109,117,120, 95,112, 97,
+ 99,107,101,116, 95,115,105,122,101, 0,109,117,120, 95,114, 97,116,101, 0,109,105,120,114, 97,116,101, 0,109, 97,105,110, 0,
+112, 97,100, 91, 51, 93, 0, 42,109, 97,116, 95,111,118,101,114,114,105,100,101, 0, 42,108,105,103,104,116, 95,111,118,101,114,
+114,105,100,101, 0,108, 97,121,102,108, 97,103, 0,112, 97,115,115,102,108, 97,103, 0,112, 97,115,115, 95,120,111,114, 0, 42,
+ 97,118,105, 99,111,100,101, 99,100, 97,116, 97, 0, 42,113,116, 99,111,100,101, 99,100, 97,116, 97, 0,102,102, 99,111,100,101,
+ 99,100, 97,116, 97, 0, 99,102,114, 97, 0,105,109, 97,103,101,115, 0,102,114, 97,109, 97,112,116,111, 0,116,104,114,101, 97,
+100,115, 0,102,114, 97,109,101,108,101,110, 0, 98,108,117,114,102, 97, 99, 0,101,100,103,101, 82, 0,101,100,103,101, 71, 0,
+101,100,103,101, 66, 0,102,117,108,108,115, 99,114,101,101,110, 0,120,112,108, 97,121, 0,121,112,108, 97,121, 0,102,114,101,
+113,112,108, 97,121, 0, 97,116,116,114,105, 98, 0,114,116, 49, 0,114,116, 50, 0,115,116,101,114,101,111,109,111,100,101, 0,
+100,105,109,101,110,115,105,111,110,115,112,114,101,115,101,116, 0,109, 97,120,105,109,115,105,122,101, 0,120,115, 99,104, 0,
+121,115, 99,104, 0,120, 97,115,112, 0,121, 97,115,112, 0,120,112, 97,114,116,115, 0,121,112, 97,114,116,115, 0,119,105,110,
+112,111,115, 0,112,108, 97,110,101,115, 0,105,109,116,121,112,101, 0,115,117, 98,105,109,116,121,112,101, 0,113,117, 97,108,
+105,116,121, 0,115, 99,101,109,111,100,101, 0,114,101,110,100,101,114,101,114, 0,111, 99,114,101,115, 0,114,112, 97,100, 91,
+ 50, 93, 0, 97,108,112,104, 97,109,111,100,101, 0,111,115, 97, 0,102,114,115, 95,115,101, 99, 0,101,100,103,101,105,110,116,
+ 0,115, 97,102,101,116,121, 0, 98,111,114,100,101,114, 0,100,105,115,112,114,101, 99,116, 0,108, 97,121,101,114,115, 0, 97,
+ 99,116,108, 97,121, 0,103, 97,117,115,115, 0,100,105,116,104,101,114, 95,105,110,116,101,110,115,105,116,121, 0, 98, 97,107,
+101, 95,111,115, 97, 0, 98, 97,107,101, 95,102,105,108,116,101,114, 0, 98, 97,107,101, 95,109,111,100,101, 0, 98, 97,107,101,
+ 95,102,108, 97,103, 0, 71, 73,113,117, 97,108,105,116,121, 0, 71, 73, 99, 97, 99,104,101, 0, 71, 73,109,101,116,104,111,100,
+ 0, 71, 73,112,104,111,116,111,110,115, 0, 71, 73,100,105,114,101, 99,116, 0, 89, 70, 95, 65, 65, 0, 89, 70,101,120,112,111,
+114,116,120,109,108, 0, 89, 70, 95,110,111, 98,117,109,112, 0, 89, 70, 95, 99,108, 97,109,112,114,103, 98, 0,121,102,112, 97,
+100, 49, 0, 71, 73,100,101,112,116,104, 0, 71, 73, 99, 97,117,115,100,101,112,116,104, 0, 71, 73,112,105,120,101,108,115,112,
+101,114,115, 97,109,112,108,101, 0, 71, 73,112,104,111,116,111,110, 99,111,117,110,116, 0, 71, 73,109,105,120,112,104,111,116,
+111,110,115, 0, 71, 73,112,104,111,116,111,110,114, 97,100,105,117,115, 0, 89, 70, 95,110,117,109,112,114,111, 99,115, 0, 89,
+ 70, 95,114, 97,121,100,101,112,116,104, 0, 89, 70, 95, 65, 65,112, 97,115,115,101,115, 0, 89, 70, 95, 65, 65,115, 97,109,112,
+108,101,115, 0, 71, 73,115,104, 97,100,111,119,113,117, 97,108,105,116,121, 0, 71, 73,114,101,102,105,110,101,109,101,110,116,
+ 0, 71, 73,112,111,119,101,114, 0, 71, 73,105,110,100,105,114,112,111,119,101,114, 0, 89, 70, 95,103, 97,109,109, 97, 0, 89,
+ 70, 95,101,120,112,111,115,117,114,101, 0, 89, 70, 95,114, 97,121, 98,105, 97,115, 0, 89, 70, 95, 65, 65,112,105,120,101,108,
+115,105,122,101, 0, 89, 70, 95, 65, 65,116,104,114,101,115,104,111,108,100, 0, 98, 97, 99,107, 98,117,102, 91, 49, 54, 48, 93,
+ 0,112,105, 99, 91, 49, 54, 48, 93, 0,102,116,121,112,101, 91, 49, 54, 48, 93, 0, 99,111,108, 91, 51, 93, 0,102,114, 97,109,
+101, 0,110, 97,109,101, 91, 54, 52, 93, 0, 42, 98,114,117,115,104, 0,116,111,111,108, 0, 99,111,114,110,101,114,116,121,112,
+101, 0,101,100,105,116, 98,117,116,102,108, 97,103, 0,106,111,105,110,116,114,105,108,105,109,105,116, 0,100,101,103,114, 0,
+115,116,101,112, 0,116,117,114,110, 0,101,120,116,114, 95,111,102,102,115, 0,100,111,117, 98,108,105,109,105,116, 0,115,101,
+103,109,101,110,116,115, 0,114,105,110,103,115, 0,118,101,114,116,105, 99,101,115, 0,117,110,119,114, 97,112,112,101,114, 0,
+117,118, 99, 97,108, 99, 95,114, 97,100,105,117,115, 0,117,118, 99, 97,108, 99, 95, 99,117, 98,101,115,105,122,101, 0,117,118,
+ 99, 97,108, 99, 95,109, 97,112,100,105,114, 0,117,118, 99, 97,108, 99, 95,109, 97,112, 97,108,105,103,110, 0,117,118, 99, 97,
+108, 99, 95,102,108, 97,103, 0,115,101,108,101, 99,116, 95,116,104,114,101,115,104, 0,105,109, 97,112, 97,105,110,116, 0, 99,
+108,101, 97,110, 95,116,104,114,101,115,104, 0,114,101,116,111,112,111, 95,109,111,100,101, 0,108,105,110,101, 95,100,105,118,
+ 0,101,108,108,105,112,115,101, 95,100,105,118, 0,100,105,114, 0, 97,105,114, 98,114,117,115,104, 0,118,105,101,119, 0, 42,
+115,101,115,115,105,111,110, 0,100,114, 97,119, 98,114,117,115,104, 0,115,109,111,111,116,104, 98,114,117,115,104, 0,112,105,
+110, 99,104, 98,114,117,115,104, 0,105,110,102,108, 97,116,101, 98,114,117,115,104, 0,103,114, 97, 98, 98,114,117,115,104, 0,
+108, 97,121,101,114, 98,114,117,115,104, 0, 98,114,117,115,104, 95,116,121,112,101, 0,116,101,120,110,114, 0,116,101,120,114,
+101,112,116, 0,116,101,120,102, 97,100,101, 0,116,101,120,115,101,112, 0, 97,118,101,114, 97,103,105,110,103, 0,100,114, 97,
+119, 95,102,108, 97,103, 0,116, 97, 98,108,101,116, 95,115,105,122,101, 0,116, 97, 98,108,101,116, 95,115,116,114,101,110,103,
+116,104, 0,115,121,109,109, 0, 42, 99, 97,109,101,114, 97, 0, 42,119,111,114,108,100, 0, 42,115,101,116, 0, 98, 97,115,101,
+ 0, 42, 98, 97,115, 97, 99,116, 0, 99,117,114,115,111,114, 91, 51, 93, 0,116,119, 99,101,110,116, 91, 51, 93, 0,116,119,109,
+105,110, 91, 51, 93, 0,116,119,109, 97,120, 91, 51, 93, 0,101,100,105,116, 98,117,116,115,105,122,101, 0,115,101,108,101, 99,
+116,109,111,100,101, 0,112,114,111,112,111,114,116,105,111,110, 97,108, 0,112,114,111,112, 95,109,111,100,101, 0, 42,101,100,
+ 0, 42,114, 97,100,105,111, 0,102,114, 97,109,105,110,103, 0, 42,116,111,111,108,115,101,116,116,105,110,103,115, 0, 97,117,
+100,105,111, 0,109, 97,114,107,101,114,115, 0,106,117,109,112,102,114, 97,109,101, 0, 42,116,104,101, 68, 97,103, 0,100, 97,
+103,105,115,118, 97,108,105,100, 0,100, 97,103,102,108, 97,103,115, 0,115, 99,117,108,112,116,100, 97,116, 97, 0,122,111,111,
+109, 0, 98,108,101,110,100, 0,120,105,109, 0,121,105,109, 0,115,112, 97, 99,101,116,121,112,101, 0, 98,108,111, 99,107,115,
+ 99, 97,108,101, 0, 42, 97,114,101, 97, 0, 98,108,111, 99,107,104, 97,110,100,108,101,114, 91, 56, 93, 0,118,105,101,119,109,
+ 97,116, 91, 52, 93, 91, 52, 93, 0,118,105,101,119,105,110,118, 91, 52, 93, 91, 52, 93, 0,112,101,114,115,109, 97,116, 91, 52,
+ 93, 91, 52, 93, 0,112,101,114,115,105,110,118, 91, 52, 93, 91, 52, 93, 0,119,105,110,109, 97,116, 49, 91, 52, 93, 91, 52, 93,
+ 0,118,105,101,119,109, 97,116, 49, 91, 52, 93, 91, 52, 93, 0,118,105,101,119,113,117, 97,116, 91, 52, 93, 0,122,102, 97, 99,
+ 0,112, 97,100, 48, 0,112,101,114,115,112, 0, 42,111, 98, 95, 99,101,110,116,114,101, 0, 42, 98,103,112,105, 99, 0, 42,108,
+111, 99, 97,108,118,100, 0, 42,114,105, 0, 42,114,101,116,111,112,111, 95,118,105,101,119, 95,100, 97,116, 97, 0, 42,100,101,
+112,116,104,115, 0,111, 98, 95, 99,101,110,116,114,101, 95, 98,111,110,101, 91, 51, 50, 93, 0,108,111, 99, 97,108,118,105,101,
+119, 0,108, 97,121, 97, 99,116, 0,115, 99,101,110,101,108,111, 99,107, 0, 97,114,111,117,110,100, 0, 99, 97,109,122,111,111,
+109, 0,112,105,118,111,116, 95,108, 97,115,116, 0,103,114,105,100, 0,103,114,105,100,118,105,101,119, 0,112,105,120,115,105,
+122,101, 0,110,101, 97,114, 0,102, 97,114, 0, 99, 97,109,100,120, 0, 99, 97,109,100,121, 0,103,114,105,100,108,105,110,101,
+115, 0,118,105,101,119, 98,117,116, 0,103,114,105,100,102,108, 97,103, 0,109,111,100,101,115,101,108,101, 99,116, 0,116,119,
+116,121,112,101, 0,116,119,109,111,100,101, 0,116,119,102,108, 97,103, 0,116,119,100,114, 97,119,102,108, 97,103, 0,116,119,
+109, 97,116, 91, 52, 93, 91, 52, 93, 0, 99,108,105,112, 91, 52, 93, 91, 52, 93, 0, 42, 99,108,105,112, 98, 98, 0, 97,102,116,
+101,114,100,114, 97,119, 0,122, 98,117,102, 0,120,114, 97,121, 0,102,108, 97,103, 50, 0,103,114,105,100,115,117, 98,100,105,
+118, 0,115,110, 97,112, 95,116, 97,114,103,101,116, 0, 42,112,114,111,112,101,114,116,105,101,115, 95,115,116,111,114, 97,103,
+101, 0,118,101,114,116, 0,104,111,114, 0,109, 97,115,107, 0,109,105,110, 91, 50, 93, 0,109, 97,120, 91, 50, 93, 0,109,105,
+110,122,111,111,109, 0,109, 97,120,122,111,111,109, 0,115, 99,114,111,108,108, 0,107,101,101,112,116,111,116, 0,107,101,101,
+112, 97,115,112,101, 99,116, 0,107,101,101,112,122,111,111,109, 0,111,108,100,119,105,110,120, 0,111,108,100,119,105,110,121,
+ 0,114,111,119, 98,117,116, 0,118, 50,100, 0, 42,101,100,105,116,105,112,111, 0,105,112,111,107,101,121, 0, 97, 99,116,110,
+ 97,109,101, 91, 51, 50, 93, 0, 99,111,110,115,116,110, 97,109,101, 91, 51, 50, 93, 0,116,111,116,105,112,111, 0,112,105,110,
+ 0, 98,117,116,111,102,115, 0, 99,104, 97,110,110,101,108, 0,108,111, 99,107, 0,109,101,100,105, 97,110, 91, 51, 93, 0, 99,
+117,114,115,101,110,115, 0, 99,117,114, 97, 99,116, 0, 97,108,105,103,110, 0,116, 97, 98,111, 0,109, 97,105,110, 98, 0,109,
+ 97,105,110, 98,111, 0, 42,108,111, 99,107,112,111,105,110, 0,116,101,120,102,114,111,109, 0,115,104,111,119,103,114,111,117,
+112, 0,109,111,100,101,108,116,121,112,101, 0,115, 99,114,105,112,116, 98,108,111, 99,107, 0,114,101, 95, 97,108,105,103,110,
+ 0,111,108,100,107,101,121,112,114,101,115,115, 0,116, 97, 98, 91, 55, 93, 0, 99,104, 97,110,115,104,111,119,110, 0, 42,102,
+105,108,101,108,105,115,116, 0,116,111,116,102,105,108,101, 0,116,105,116,108,101, 91, 50, 52, 93, 0,100,105,114, 91, 49, 54,
+ 48, 93, 0,102,105,108,101, 91, 56, 48, 93, 0,111,102,115, 0,115,111,114,116, 0,109, 97,120,110, 97,109,101,108,101,110, 0,
+ 99,111,108,108,117,109,115, 0, 42,108,105, 98,102,105,108,101,100, 97,116, 97, 0,114,101,116,118, 97,108, 0,109,101,110,117,
+ 0, 97, 99,116, 0, 40, 42,114,101,116,117,114,110,102,117,110, 99, 41, 40, 41, 0, 40, 42,114,101,116,117,114,110,102,117,110,
+ 99, 95,101,118,101,110,116, 41, 40, 41, 0, 40, 42,114,101,116,117,114,110,102,117,110, 99, 95, 97,114,103,115, 41, 40, 41, 0,
+ 42, 97,114,103, 49, 0, 42, 97,114,103, 50, 0, 42,109,101,110,117,112, 0, 42,112,117,112,109,101,110,117, 0,111,111,112,115,
+ 0,118,105,115,105,102,108, 97,103, 0,116,114,101,101, 0, 42,116,114,101,101,115,116,111,114,101, 0,115,101, 97,114, 99,104,
+ 95,115,116,114,105,110,103, 91, 51, 50, 93, 0,115,101, 97,114, 99,104, 95,116,115,101, 0,115,101, 97,114, 99,104, 95,102,108,
+ 97,103,115, 0,100,111, 95, 0,111,117,116,108,105,110,101,118,105,115, 0,115,116,111,114,101,102,108, 97,103, 0,100,101,112,
+115, 95,102,108, 97,103,115, 0, 42, 99,117,109, 97,112, 0,105,109, 97,110,114, 0, 99,117,114,116,105,108,101, 0,105,109,116,
+121,112,101,110,114, 0,115,104,111,119,115,112, 97,114,101, 0, 99,101,110,116,120, 0, 99,101,110,116,121, 0, 42,105,110,102,
+111, 95,115,116,114, 0, 42,105,110,102,111, 95,115,112, 97,114,101, 0, 42,115,112, 97,114,101, 0, 42,116,101,120,116, 0,116,
+111,112, 0,118,105,101,119,108,105,110,101,115, 0,102,111,110,116, 95,105,100, 0,108,104,101,105,103,104,116, 0,108,101,102,
+116, 0,115,104,111,119,108,105,110,101,110,114,115, 0,116, 97, 98,110,117,109, 98,101,114, 0, 99,117,114,114,116, 97, 98, 95,
+115,101,116, 0,115,104,111,119,115,121,110,116, 97,120, 0,117,110,117,115,101,100, 95,112, 97,100,100, 0,112,105,120, 95,112,
+101,114, 95,108,105,110,101, 0,116,120,116,115, 99,114,111,108,108, 0,116,120,116, 98, 97,114, 0, 42,115, 99,114,105,112,116,
+ 0,114,101,100,114, 97,119,115, 0, 42,105,100, 0, 97,115,112,101, 99,116, 0, 42, 99,117,114,102,111,110,116, 0, 42,101,100,
+105,116,116,114,101,101, 0,116,114,101,101,116,121,112,101, 0,116,105,116,108,101, 91, 50, 56, 93, 0,102, 97,115,101, 0,115,
+117, 98,102, 97,115,101, 0,109,111,117,115,101, 95,109,111,118,101, 95,114,101,100,114, 97,119, 0,105,109, 97,102, 97,115,101,
+ 0,109,120, 0,109,121, 0,100,105,114,115,108,105, 0,100,105,114,115,108,105, 95,108,105,110,101,115, 0,100,105,114,115,108,
+105, 95,115,120, 0,100,105,114,115,108,105, 95,101,121, 0,100,105,114,115,108,105, 95,101,120, 0,100,105,114,115,108,105, 95,
+104, 0,105,109, 97,115,108,105, 0,102,105,108,101,115,101,108,109,101,110,117,105,116,101,109, 0,105,109, 97,115,108,105, 95,
+115,120, 0,105,109, 97,115,108,105, 95,101,121, 0,105,109, 97,115,108,105, 95,101,120, 0,105,109, 97,115,108,105, 95,104, 0,
+100,115,115,120, 0,100,115,115,121, 0,100,115,101,120, 0,100,115,101,121, 0,100,101,115,120, 0,100,101,115,121, 0,100,101,
+101,120, 0,100,101,101,121, 0,102,115,115,120, 0,102,115,115,121, 0,102,115,101,120, 0,102,115,101,121, 0,100,115,100,104,
+ 0,102,115,100,104, 0,102,101,115,120, 0,102,101,115,121, 0,102,101,101,120, 0,102,101,101,121, 0,105,110,102,115,120, 0,
+105,110,102,115,121, 0,105,110,102,101,120, 0,105,110,102,101,121, 0,100,110,115,120, 0,100,110,115,121, 0,100,110,119, 0,
+100,110,104, 0,102,110,115,120, 0,102,110,115,121, 0,102,110,119, 0,102,110,104, 0,102,111,108,101, 91, 49, 50, 56, 93, 0,
+100,111,114, 91, 49, 50, 56, 93, 0,102,105,108,101, 91, 49, 50, 56, 93, 0,100,105,114, 91, 49, 50, 56, 93, 0, 42,102,105,114,
+115,116,100,105,114, 0, 42,102,105,114,115,116,102,105,108,101, 0,116,111,112,100,105,114, 0,116,111,116, 97,108,100,105,114,
+115, 0,104,105,108,105,116,101, 0,116,111,112,102,105,108,101, 0,116,111,116, 97,108,102,105,108,101,115, 0,105,109, 97,103,
+101, 95,115,108,105,100,101,114, 0,115,108,105,100,101,114, 95,104,101,105,103,104,116, 0,115,108,105,100,101,114, 95,115,112,
+ 97, 99,101, 0,116,111,112,105,109, 97, 0,116,111,116, 97,108,105,109, 97, 0, 99,117,114,105,109, 97,120, 0, 99,117,114,105,
+109, 97,121, 0, 42,102,105,114,115,116, 95,115,101,108, 95,105,109, 97, 0, 42,104,105,108,105,116,101, 95,105,109, 97, 0,116,
+111,116, 97,108, 95,115,101,108,101, 99,116,101,100, 0,105,109, 97, 95,114,101,100,114, 97,119, 0, 42, 99,109, 97,112, 0,111,
+117,116,108,105,110,101, 91, 52, 93, 0,110,101,117,116,114, 97,108, 91, 52, 93, 0, 97, 99,116,105,111,110, 91, 52, 93, 0,115,
+101,116,116,105,110,103, 91, 52, 93, 0,115,101,116,116,105,110,103, 49, 91, 52, 93, 0,115,101,116,116,105,110,103, 50, 91, 52,
+ 93, 0,110,117,109, 91, 52, 93, 0,116,101,120,116,102,105,101,108,100, 91, 52, 93, 0,116,101,120,116,102,105,101,108,100, 95,
+104,105, 91, 52, 93, 0,112,111,112,117,112, 91, 52, 93, 0,116,101,120,116, 91, 52, 93, 0,116,101,120,116, 95,104,105, 91, 52,
+ 93, 0,109,101,110,117, 95, 98, 97, 99,107, 91, 52, 93, 0,109,101,110,117, 95,105,116,101,109, 91, 52, 93, 0,109,101,110,117,
+ 95,104,105,108,105,116,101, 91, 52, 93, 0,109,101,110,117, 95,116,101,120,116, 91, 52, 93, 0,109,101,110,117, 95,116,101,120,
+116, 95,104,105, 91, 52, 93, 0, 98,117,116, 95,100,114, 97,119,116,121,112,101, 0,105, 99,111,110,102,105,108,101, 91, 56, 48,
+ 93, 0, 98, 97, 99,107, 91, 52, 93, 0,104,101, 97,100,101,114, 91, 52, 93, 0,112, 97,110,101,108, 91, 52, 93, 0,115,104, 97,
+100,101, 49, 91, 52, 93, 0,115,104, 97,100,101, 50, 91, 52, 93, 0,104,105,108,105,116,101, 91, 52, 93, 0,103,114,105,100, 91,
+ 52, 93, 0,119,105,114,101, 91, 52, 93, 0,115,101,108,101, 99,116, 91, 52, 93, 0,108, 97,109,112, 91, 52, 93, 0, 97, 99,116,
+105,118,101, 91, 52, 93, 0,103,114,111,117,112, 91, 52, 93, 0,103,114,111,117,112, 95, 97, 99,116,105,118,101, 91, 52, 93, 0,
+116,114, 97,110,115,102,111,114,109, 91, 52, 93, 0,118,101,114,116,101,120, 91, 52, 93, 0,118,101,114,116,101,120, 95,115,101,
+108,101, 99,116, 91, 52, 93, 0,101,100,103,101, 91, 52, 93, 0,101,100,103,101, 95,115,101,108,101, 99,116, 91, 52, 93, 0,101,
+100,103,101, 95,115,101, 97,109, 91, 52, 93, 0,101,100,103,101, 95,115,104, 97,114,112, 91, 52, 93, 0,101,100,103,101, 95,102,
+ 97, 99,101,115,101,108, 91, 52, 93, 0,102, 97, 99,101, 91, 52, 93, 0,102, 97, 99,101, 95,115,101,108,101, 99,116, 91, 52, 93,
+ 0,102, 97, 99,101, 95,100,111,116, 91, 52, 93, 0,110,111,114,109, 97,108, 91, 52, 93, 0, 98,111,110,101, 95,115,111,108,105,
+100, 91, 52, 93, 0, 98,111,110,101, 95,112,111,115,101, 91, 52, 93, 0,115,116,114,105,112, 91, 52, 93, 0,115,116,114,105,112,
+ 95,115,101,108,101, 99,116, 91, 52, 93, 0,118,101,114,116,101,120, 95,115,105,122,101, 0,102, 97, 99,101,100,111,116, 95,115,
+105,122,101, 0, 98,112, 97,100, 91, 50, 93, 0,115,121,110,116, 97,120,108, 91, 52, 93, 0,115,121,110,116, 97,120,110, 91, 52,
+ 93, 0,115,121,110,116, 97,120, 98, 91, 52, 93, 0,115,121,110,116, 97,120,118, 91, 52, 93, 0,115,121,110,116, 97,120, 99, 91,
+ 52, 93, 0,109,111,118,105,101, 91, 52, 93, 0,105,109, 97,103,101, 91, 52, 93, 0,115, 99,101,110,101, 91, 52, 93, 0, 97,117,
+100,105,111, 91, 52, 93, 0,101,102,102,101, 99,116, 91, 52, 93, 0,112,108,117,103,105,110, 91, 52, 93, 0,116,114, 97,110,115,
+105,116,105,111,110, 91, 52, 93, 0,109,101,116, 97, 91, 52, 93, 0, 98,112, 97,100, 49, 91, 52, 93, 0,116,117,105, 0,116, 98,
+117,116,115, 0,116,118, 51,100, 0,116,102,105,108,101, 0,116,105,112,111, 0,116,105,110,102,111, 0,116,115,110,100, 0,116,
+ 97, 99,116, 0,116,110,108, 97, 0,116,115,101,113, 0,116,105,109, 97, 0,116,105,109, 97,115,101,108, 0,116,101,120,116, 0,
+116,111,111,112,115, 0,116,116,105,109,101, 0,116,110,111,100,101, 0, 98,112, 97,100, 91, 52, 93, 0,115,112,101, 99, 91, 52,
+ 93, 0,100,117,112,102,108, 97,103, 0,115, 97,118,101,116,105,109,101, 0,116,101,109,112,100,105,114, 91, 49, 54, 48, 93, 0,
+102,111,110,116,100,105,114, 91, 49, 54, 48, 93, 0,114,101,110,100,101,114,100,105,114, 91, 49, 54, 48, 93, 0,116,101,120,116,
+117,100,105,114, 91, 49, 54, 48, 93, 0,112,108,117,103,116,101,120,100,105,114, 91, 49, 54, 48, 93, 0,112,108,117,103,115,101,
+113,100,105,114, 91, 49, 54, 48, 93, 0,112,121,116,104,111,110,100,105,114, 91, 49, 54, 48, 93, 0,115,111,117,110,100,100,105,
+114, 91, 49, 54, 48, 93, 0,121,102,101,120,112,111,114,116,100,105,114, 91, 49, 54, 48, 93, 0,118,101,114,115,105,111,110,115,
+ 0,118,114,109,108,102,108, 97,103, 0,103, 97,109,101,102,108, 97,103,115, 0,119,104,101,101,108,108,105,110,101,115, 99,114,
+111,108,108, 0,117,105,102,108, 97,103, 0,108, 97,110,103,117, 97,103,101, 0,117,115,101,114,112,114,101,102, 0,118,105,101,
+119,122,111,111,109, 0, 99,111,110,115,111,108,101, 95, 98,117,102,102,101,114, 0, 99,111,110,115,111,108,101, 95,111,117,116,
+ 0,109,105,120, 98,117,102,115,105,122,101, 0,102,111,110,116,115,105,122,101, 0,101,110, 99,111,100,105,110,103, 0,116,114,
+ 97,110,115,111,112,116,115, 0,109,101,110,117,116,104,114,101,115,104,111,108,100, 49, 0,109,101,110,117,116,104,114,101,115,
+104,111,108,100, 50, 0,102,111,110,116,110, 97,109,101, 91, 50, 53, 54, 93, 0,116,104,101,109,101,115, 0,117,110,100,111,115,
+116,101,112,115, 0, 99,117,114,115,115,105,122,101, 0,116, 98, 95,108,101,102,116,109,111,117,115,101, 0,116, 98, 95,114,105,
+103,104,116,109,111,117,115,101, 0,108,105,103,104,116, 91, 51, 93, 0,116,119, 95,104,111,116,115,112,111,116, 0,116,119, 95,
+102,108, 97,103, 0,116,119, 95,104, 97,110,100,108,101,115,105,122,101, 0,116,119, 95,115,105,122,101, 0,116,101,120,116,105,
+109,101,111,117,116, 0,116,101,120, 99,111,108,108,101, 99,116,114, 97,116,101, 0,109,101,109, 99, 97, 99,104,101,108,105,109,
+105,116, 0,102,114, 97,109,101,115,101,114,118,101,114,112,111,114,116, 0,112, 97,100, 95,114,111,116, 95, 97,110,103,108,101,
+ 0,111, 98, 99,101,110,116,101,114, 95,100,105, 97, 0,114,118,105,115,105,122,101, 0,114,118,105, 98,114,105,103,104,116, 0,
+118,101,114,115,101,109, 97,115,116,101,114, 91, 49, 54, 48, 93, 0,118,101,114,115,101,117,115,101,114, 91, 49, 54, 48, 93, 0,
+118,101,114,116, 98, 97,115,101, 0,101,100,103,101, 98, 97,115,101, 0, 97,114,101, 97, 98, 97,115,101, 0, 42,115, 99,101,110,
+101, 0,101,110,100,120, 0,101,110,100,121, 0,115,105,122,101,120, 0,115,105,122,101,121, 0,115, 99,101,110,101,110,114, 0,
+115, 99,114,101,101,110,110,114, 0,102,117,108,108, 0,109, 97,105,110,119,105,110, 0,119,105,110, 97,107,116, 0,104, 97,110,
+100,108,101,114, 91, 56, 93, 0, 42,110,101,119,118, 0,118,101, 99, 0, 42,118, 49, 0, 42,118, 50, 0,112, 97,110,101,108,110,
+ 97,109,101, 91, 54, 52, 93, 0,116, 97, 98,110, 97,109,101, 91, 54, 52, 93, 0,100,114, 97,119,110, 97,109,101, 91, 54, 52, 93,
+ 0,111,102,115,120, 0,111,102,115,121, 0, 99,111,110,116,114,111,108, 0,115,110, 97,112, 0,111,108,100, 95,111,102,115,120,
+ 0,111,108,100, 95,111,102,115,121, 0,115,111,114,116, 99,111,117,110,116,101,114, 0, 42,112, 97,110,101,108,116, 97, 98, 0,
+ 42,118, 51, 0, 42,118, 52, 0, 42,102,117,108,108, 0,119,105,110,109, 97,116, 91, 52, 93, 91, 52, 93, 0,104,101, 97,100,114,
+ 99,116, 0,119,105,110,114, 99,116, 0,104,101, 97,100,119,105,110, 0,119,105,110, 0,104,101, 97,100,101,114,116,121,112,101,
+ 0, 98,117,116,115,112, 97, 99,101,116,121,112,101, 0,119,105,110,120, 0,119,105,110,121, 0,104,101, 97,100, 95,115,119, 97,
+112, 0,104,101, 97,100, 95,101,113,117, 97,108, 0,119,105,110, 95,115,119, 97,112, 0,119,105,110, 95,101,113,117, 97,108, 0,
+104,101, 97,100, 98,117,116,108,101,110, 0,104,101, 97,100, 98,117,116,111,102,115, 0, 99,117,114,115,111,114, 0,115,112, 97,
+ 99,101,100, 97,116, 97, 0,117,105, 98,108,111, 99,107,115, 0,112, 97,110,101,108,115, 0,115,117, 98,118,115,116,114, 91, 52,
+ 93, 0,115,117, 98,118,101,114,115,105,111,110, 0,112, 97,100,115, 0,109,105,110,118,101,114,115,105,111,110, 0,109,105,110,
+115,117, 98,118,101,114,115,105,111,110, 0,100,105,115,112,108, 97,121,109,111,100,101, 0, 42, 99,117,114,115, 99,114,101,101,
+110, 0, 42, 99,117,114,115, 99,101,110,101, 0,102,105,108,101,102,108, 97,103,115, 0,103,108,111, 98, 97,108,102, 0,110, 97,
+109,101, 91, 56, 48, 93, 0, 42,105, 98,117,102, 0, 42,115,101, 49, 0, 42,115,101, 50, 0, 42,115,101, 51, 0,110,114, 0,100,
+111,110,101, 0, 42,115,116,114,105,112,100, 97,116, 97, 0,111,114,120, 0,111,114,121, 0, 42,105,110,115,116, 97,110, 99,101,
+ 95,112,114,105,118, 97,116,101, 95,100, 97,116, 97, 0, 42, 42, 99,117,114,114,101,110,116, 95,112,114,105,118, 97,116,101, 95,
+100, 97,116, 97, 0, 42,110,101,119,115,101,113, 0,115,116, 97,114,116,111,102,115, 0,101,110,100,111,102,115, 0,115,116, 97,
+114,116,115,116,105,108,108, 0,101,110,100,115,116,105,108,108, 0,109, 97, 99,104,105,110,101, 0,115,116, 97,114,116,100,105,
+115,112, 0,101,110,100,100,105,115,112, 0,109,117,108, 0,104, 97,110,100,115,105,122,101, 0, 42,115,116,114,105,112, 0, 42,
+ 99,117,114,101,108,101,109, 0,102, 97, 99,102, 48, 0,102, 97, 99,102, 49, 0, 42,115,101,113, 49, 0, 42,115,101,113, 50, 0,
+ 42,115,101,113, 51, 0,115,101,113, 98, 97,115,101, 0, 42,115,111,117,110,100, 0, 42,104,100, 97,117,100,105,111, 0,108,101,
+118,101,108, 0,112, 97,110, 0, 99,117,114,112,111,115, 0,115,116,114,111, 98,101, 0, 42,101,102,102,101, 99,116,100, 97,116,
+ 97, 0, 97,110,105,109, 95,112,114,101,115,101,101,107, 0, 42,111,108,100, 98, 97,115,101,112, 0, 42,112, 97,114,115,101,113,
+ 0, 42,115,101,113, 98, 97,115,101,112, 0,109,101,116, 97,115,116, 97, 99,107, 0,101,100,103,101, 87,105,100,116,104, 0, 97,
+110,103,108,101, 0,102,111,114,119, 97,114,100, 0,119,105,112,101,116,121,112,101, 0,102, 77,105,110,105, 0,102, 67,108, 97,
+109,112, 0,102, 66,111,111,115,116, 0,100, 68,105,115,116, 0,100, 81,117, 97,108,105,116,121, 0, 98, 78,111, 67,111,109,112,
+ 0, 83, 99, 97,108,101,120, 73,110,105, 0, 83, 99, 97,108,101,121, 73,110,105, 0, 83, 99, 97,108,101,120, 70,105,110, 0, 83,
+ 99, 97,108,101,121, 70,105,110, 0,120, 73,110,105, 0,120, 70,105,110, 0,121, 73,110,105, 0,121, 70,105,110, 0,114,111,116,
+ 73,110,105, 0,114,111,116, 70,105,110, 0, 42,102,114, 97,109,101, 77, 97,112, 0,103,108,111, 98, 97,108, 83,112,101,101,100,
+ 0, 98,117,116,116,121,112,101, 0,117,115,101,114,106,105,116, 0,115,116, 97, 0,101,110,100, 0,116,111,116,112, 97,114,116,
+ 0,110,111,114,109,102, 97, 99, 0,111, 98,102, 97, 99, 0,114, 97,110,100,102, 97, 99, 0,116,101,120,102, 97, 99, 0,114, 97,
+110,100,108,105,102,101, 0,102,111,114, 99,101, 91, 51, 93, 0,118,101, 99,116,115,105,122,101, 0,109, 97,120,108,101,110, 0,
+100,101,102,118,101, 99, 91, 51, 93, 0,109,117,108,116, 91, 52, 93, 0,108,105,102,101, 91, 52, 93, 0, 99,104,105,108,100, 91,
+ 52, 93, 0,109, 97,116, 91, 52, 93, 0,116,101,120,109, 97,112, 0, 99,117,114,109,117,108,116, 0,115,116, 97,116,105, 99,115,
+116,101,112, 0,111,109, 97,116, 0,116,105,109,101,116,101,120, 0,115,112,101,101,100,116,101,120, 0,102,108, 97,103, 50,110,
+101,103, 0,118,101,114,116,103,114,111,117,112, 95,118, 0,118,103,114,111,117,112,110, 97,109,101, 91, 51, 50, 93, 0,118,103,
+114,111,117,112,110, 97,109,101, 95,118, 91, 51, 50, 93, 0, 42,107,101,121,115, 0,109,105,110,102, 97, 99, 0,117,115,101,100,
+ 0,117,115,101,100,101,108,101,109, 0,100,120, 0,100,121, 0,108,105,110,107, 0,111,116,121,112,101, 0,111,108,100, 0, 42,
+112,111,105,110, 0, 42,111,108,100,112,111,105,110, 0,114,101,115,101,116,100,105,115,116, 0,108, 97,115,116,118, 97,108, 0,
+ 42,109, 97, 0,107,101,121, 0,113,117, 97,108, 0,113,117, 97,108, 50, 0,116, 97,114,103,101,116, 78, 97,109,101, 91, 51, 50,
+ 93, 0,116,111,103,103,108,101, 78, 97,109,101, 91, 51, 50, 93, 0,118, 97,108,117,101, 91, 51, 50, 93, 0,109, 97,120,118, 97,
+108,117,101, 91, 51, 50, 93, 0,109, 97,116,101,114,105, 97,108, 78, 97,109,101, 91, 51, 50, 93, 0,100, 97,109,112,116,105,109,
+101,114, 0,100,101,108, 97,121, 0,112,114,111,112,110, 97,109,101, 91, 51, 50, 93, 0,109, 97,116,110, 97,109,101, 91, 51, 50,
+ 93, 0, 97,120,105,115,102,108, 97,103, 0, 42,102,114,111,109, 79, 98,106,101, 99,116, 0,115,117, 98,106,101, 99,116, 91, 51,
+ 50, 93, 0, 98,111,100,121, 91, 51, 50, 93, 0,112,117,108,115,101, 0,102,114,101,113, 0,116,111,116,108,105,110,107,115, 0,
+ 42, 42,108,105,110,107,115, 0,105,110,118,101,114,116, 0,102,114,101,113, 50, 0, 97,120,105,115,102, 0, 98,117,116,116,111,
+110, 0, 98,117,116,116,111,110,102, 0,104, 97,116, 0,104, 97,116,102, 0,112,114,101, 99,105,115,105,111,110, 0,115,116,114,
+ 91, 49, 50, 56, 93, 0, 42,109,121,110,101,119, 0,105,110,112,117,116,115, 0,116,111,116,115,108,105,110,107,115, 0, 42, 42,
+115,108,105,110,107,115, 0,118, 97,108,111, 0,116,105,109,101, 0, 42, 97, 99,116, 0, 98,108,101,110,100,105,110, 0,112,114,
+105,111,114,105,116,121, 0,115,116,114,105,100,101, 97,120,105,115, 0,115,116,114,105,100,101,108,101,110,103,116,104, 0,115,
+110,100,110,114, 0,112, 97,100, 49, 91, 50, 93, 0,109, 97,107,101, 99,111,112,121, 0, 99,111,112,121,109, 97,100,101, 0,112,
+ 97,100, 50, 91, 49, 93, 0,116,114, 97, 99,107, 0,118,111,108,117,109,101, 0, 42,109,101, 0,108,105,110, 86,101,108,111, 99,
+105,116,121, 91, 51, 93, 0,108,111, 99, 97,108,102,108, 97,103, 0,102,111,114, 99,101,108,111, 99, 91, 51, 93, 0,102,111,114,
+ 99,101,114,111,116, 91, 51, 93, 0,108,105,110,101, 97,114,118,101,108,111, 99,105,116,121, 91, 51, 93, 0, 97,110,103,117,108,
+ 97,114,118,101,108,111, 99,105,116,121, 91, 51, 93, 0, 98,117,116,115,116, 97, 0, 98,117,116,101,110,100, 0,109,105,110, 0,
+102, 97, 99, 0,118,105,115,105,102, 97, 99, 0,115,108,111,119, 0,109,105,110,108,111, 99, 91, 51, 93, 0,109, 97,120,108,111,
+ 99, 91, 51, 93, 0,109,105,110,114,111,116, 91, 51, 93, 0,109, 97,120,114,111,116, 91, 51, 93, 0,100,105,115,116,114,105, 98,
+117,116,105,111,110, 0,105,110,116, 95, 97,114,103, 95, 49, 0,105,110,116, 95, 97,114,103, 95, 50, 0,102,108,111, 97,116, 95,
+ 97,114,103, 95, 49, 0,102,108,111, 97,116, 95, 97,114,103, 95, 50, 0,116,111, 80,114,111,112, 78, 97,109,101, 91, 51, 50, 93,
+ 0, 42,116,111, 79, 98,106,101, 99,116, 0, 98,111,100,121, 84,121,112,101, 0,102,105,108,101,110, 97,109,101, 91, 54, 52, 93,
+ 0,108,111, 97,100, 97,110,105,110, 97,109,101, 91, 54, 52, 93, 0,103,111, 0, 97, 99, 99,101,108,108,101,114, 97,116,105,111,
+110, 0,109, 97,120,115,112,101,101,100, 0,109, 97,120,114,111,116,115,112,101,101,100, 0,109, 97,120,116,105,108,116,115,112,
+101,101,100, 0,114,111,116,100, 97,109,112, 0,116,105,108,116,100, 97,109,112, 0,115,112,101,101,100,100, 97,109,112, 0, 42,
+115, 97,109,112,108,101, 0, 42,115,116,114,101, 97,109, 0, 42,110,101,119,112, 97, 99,107,101,100,102,105,108,101, 0, 42,115,
+110,100, 95,115,111,117,110,100, 0,112, 97,110,110,105,110,103, 0, 97,116,116,101,110,117, 97,116,105,111,110, 0,112,105,116,
+ 99,104, 0,109,105,110, 95,103, 97,105,110, 0,109, 97,120, 95,103, 97,105,110, 0,100,105,115,116, 97,110, 99,101, 0,115,116,
+114,101, 97,109,108,101,110, 0, 99,104, 97,110,110,101,108,115, 0,104,105,103,104,112,114,105,111, 0,112, 97,100, 91, 49, 48,
+ 93, 0,103, 97,105,110, 0,100,111,112,112,108,101,114,102, 97, 99,116,111,114, 0,100,111,112,112,108,101,114,118,101,108,111,
+ 99,105,116,121, 0,110,117,109,115,111,117,110,100,115, 98,108,101,110,100,101,114, 0,110,117,109,115,111,117,110,100,115,103,
+ 97,109,101,101,110,103,105,110,101, 0, 42,108, 97,109,112,114,101,110, 0,103,111, 98,106,101, 99,116, 0, 99,104,105,108,100,
+ 98, 97,115,101, 0,114,111,108,108, 0,104,101, 97,100, 91, 51, 93, 0,116, 97,105,108, 91, 51, 93, 0, 98,111,110,101, 95,109,
+ 97,116, 91, 51, 93, 91, 51, 93, 0, 97,114,109, 95,104,101, 97,100, 91, 51, 93, 0, 97,114,109, 95,116, 97,105,108, 91, 51, 93,
+ 0, 97,114,109, 95,109, 97,116, 91, 52, 93, 91, 52, 93, 0,120,119,105,100,116,104, 0,122,119,105,100,116,104, 0,101, 97,115,
+101, 49, 0,101, 97,115,101, 50, 0,114, 97,100, 95,104,101, 97,100, 0,114, 97,100, 95,116, 97,105,108, 0, 98,111,110,101, 98,
+ 97,115,101, 0, 99,104, 97,105,110, 98, 97,115,101, 0,112, 97,116,104,102,108, 97,103, 0,108, 97,121,101,114, 95,112,114,111,
+116,101, 99,116,101,100, 0,103,104,111,115,116,101,112, 0,103,104,111,115,116,115,105,122,101, 0,103,104,111,115,116,116,121,
+112,101, 0,112, 97,116,104,115,105,122,101, 0,103,104,111,115,116,115,102, 0,103,104,111,115,116,101,102, 0,112, 97,116,104,
+115,102, 0,112, 97,116,104,101,102, 0, 99,111,110,115,116,102,108, 97,103, 0,105,107,102,108, 97,103, 0,115,101,108,101, 99,
+116,102,108, 97,103, 0, 42, 98,111,110,101, 0, 42, 99,104,105,108,100, 0,105,107,116,114,101,101, 0, 42, 98, 95, 98,111,110,
+101, 95,109, 97,116,115, 0, 99,104, 97,110, 95,109, 97,116, 91, 52, 93, 91, 52, 93, 0,112,111,115,101, 95,109, 97,116, 91, 52,
+ 93, 91, 52, 93, 0,112,111,115,101, 95,104,101, 97,100, 91, 51, 93, 0,112,111,115,101, 95,116, 97,105,108, 91, 51, 93, 0,108,
+105,109,105,116,109,105,110, 91, 51, 93, 0,108,105,109,105,116,109, 97,120, 91, 51, 93, 0,115,116,105,102,102,110,101,115,115,
+ 91, 51, 93, 0,105,107,115,116,114,101,116, 99,104, 0, 42, 99,117,115,116,111,109, 0, 99,104, 97,110, 98, 97,115,101, 0,112,
+114,111,120,121, 95,108, 97,121,101,114, 0,115,116,114,105,100,101, 95,111,102,102,115,101,116, 91, 51, 93, 0, 99,121, 99,108,
+105, 99, 95,111,102,102,115,101,116, 91, 51, 93, 0,114,101,115,101,114,118,101,100, 49, 0, 97,117,116,111,115,110, 97,112, 0,
+ 97, 99,116,110,114, 0, 97, 99,116,119,105,100,116,104, 0,116,105,109,101,115,108,105,100,101, 0,110, 97,109,101, 91, 51, 48,
+ 93, 0,101,110,102,111,114, 99,101, 0, 42,116, 97,114, 0,105,116,101,114, 97,116,105,111,110,115, 0,114,111,111,116, 98,111,
+110,101, 0,115,117, 98,116, 97,114,103,101,116, 91, 51, 50, 93, 0,111,114,105,101,110,116,119,101,105,103,104,116, 0,103,114,
+ 97, 98,116, 97,114,103,101,116, 91, 51, 93, 0,114,101,115,101,114,118,101,100, 50, 0,109,105,110,109, 97,120,102,108, 97,103,
+ 0,115,116,105, 99,107,121, 0,115,116,117, 99,107, 0, 99, 97, 99,104,101, 91, 51, 93, 0,108,111, 99,107,102,108, 97,103, 0,
+102,111,108,108,111,119,102,108, 97,103, 0,122,109,105,110, 0,122,109, 97,120, 0,118,111,108,109,111,100,101, 0,112,108, 97,
+110,101, 0,111,114,103,108,101,110,103,116,104, 0, 98,117,108,103,101, 0,112,105,118, 88, 0,112,105,118, 89, 0,112,105,118,
+ 90, 0, 97,120, 88, 0, 97,120, 89, 0, 97,120, 90, 0,109,105,110, 76,105,109,105,116, 91, 54, 93, 0,109, 97,120, 76,105,109,
+105,116, 91, 54, 93, 0,101,120,116,114, 97, 70,122, 0, 99,104, 97,110,110,101,108, 91, 51, 50, 93, 0,110,111, 95,114,111,116,
+ 95, 97,120,105,115, 0,115,116,114,105,100,101, 95, 97,120,105,115, 0, 99,117,114,109,111,100, 0, 97, 99,116,115,116, 97,114,
+116, 0, 97, 99,116,101,110,100, 0, 97, 99,116,111,102,102,115, 0,115,116,114,105,100,101,108,101,110, 0,114,101,112,101, 97,
+116, 0, 98,108,101,110,100,111,117,116, 0,115,116,114,105,100,101, 99,104, 97,110,110,101,108, 91, 51, 50, 93, 0,111,102,102,
+115, 95, 98,111,110,101, 91, 51, 50, 93, 0,104, 97,115,105,110,112,117,116, 0,104, 97,115,111,117,116,112,117,116, 0,100, 97,
+116, 97,116,121,112,101, 0,115,111, 99,107,101,116,116,121,112,101, 0,110,115, 0,108,105,109,105,116, 0,115,116, 97, 99,107,
+ 95,105,110,100,101,120, 0,105,110,116,101,114,110, 0,115,116, 97, 99,107, 95,105,110,100,101,120, 95,101,120,116, 0,108,111,
+ 99,120, 0,108,111, 99,121, 0,111,119,110, 95,105,110,100,101,120, 0,116,111, 95,105,110,100,101,120, 0, 42,116,111,115,111,
+ 99,107, 0, 42,108,105,110,107, 0, 42,110,101,119, 95,110,111,100,101, 0,108, 97,115,116,121, 0,111,117,116,112,117,116,115,
+ 0, 42,115,116,111,114, 97,103,101, 0,109,105,110,105,119,105,100,116,104, 0, 99,117,115,116,111,109, 49, 0, 99,117,115,116,
+111,109, 50, 0,110,101,101,100, 95,101,120,101, 99, 0,101,120,101, 99, 0,116,111,116,114, 0, 98,117,116,114, 0,112,114,118,
+114, 0, 42,116,121,112,101,105,110,102,111, 0, 42,102,114,111,109,110,111,100,101, 0, 42,116,111,110,111,100,101, 0, 42,102,
+114,111,109,115,111, 99,107, 0,110,111,100,101,115, 0,108,105,110,107,115, 0, 42, 42,115,116, 97, 99,107, 0,105,110,105,116,
+ 0,115,116, 97, 99,107,115,105,122,101, 0, 99,117,114, 95,105,110,100,101,120, 0, 42, 42, 97,108,108,116,121,112,101,115, 0,
+ 42,111,119,110,116,121,112,101, 0, 40, 42,116,105,109,101, 99,117,114,115,111,114, 41, 40, 41, 0, 40, 42,115,116, 97,116,115,
+ 95,100,114, 97,119, 41, 40, 41, 0, 40, 42,116,101,115,116, 95, 98,114,101, 97,107, 41, 40, 41, 0, 99,121, 99,108,105, 99, 0,
+109,111,118,105,101, 0,115, 97,109,112,108,101,115, 0,109,105,110,115,112,101,101,100, 0, 98,111,107,101,104, 0,104,117,101,
+ 0,115, 97,116, 0,116, 49, 0,116, 50, 0,116, 51, 0,102,115,116,114,101,110,103,116,104, 0,102, 97,108,112,104, 97, 0,107,
+101,121, 91, 52, 93, 0, 99,111,108,110, 97,109,101, 91, 51, 50, 93, 0, 98,107,116,121,112,101, 0,114,111,116, 97,116,105,111,
+110, 0,112,114,101,118,105,101,119, 0,103, 97,109, 99,111, 0,110,111, 95,122, 98,117,102, 0,102,115,116,111,112, 0,109, 97,
+120, 98,108,117,114, 0, 98,116,104,114,101,115,104, 0,115,104,111,114,116,121, 0,109,105,110,116, 97, 98,108,101, 0,109, 97,
+120,116, 97, 98,108,101, 0,101,120,116, 95,105,110, 91, 50, 93, 0,101,120,116, 95,111,117,116, 91, 50, 93, 0, 42, 99,117,114,
+118,101, 0, 42,116, 97, 98,108,101, 0, 42,112,114,101,109,117,108,116, 97, 98,108,101, 0, 99,117,114,114, 0, 99,108,105,112,
+114, 0, 99,109, 91, 52, 93, 0, 98,108, 97, 99,107, 91, 51, 93, 0,119,104,105,116,101, 91, 51, 93, 0, 98,119,109,117,108, 91,
+ 51, 93, 0,111,102,102,115,101,116, 91, 50, 93, 0,105,110,110,101,114,114, 97,100,105,117,115, 0,114, 97,116,101, 0,114,103,
+ 98, 91, 51, 93, 0, 99,108,111,110,101, 0, 42,108, 97,121,101,114,115, 0,116,111,116,108, 97,121,101,114, 0,109, 97,120,108,
+ 97,121,101,114, 0,116,111,116,115,105,122,101, 0, 0, 0, 0, 84, 89, 80, 69, 0, 0, 1, 24, 99,104, 97,114, 0,117, 99,104,
+ 97,114, 0,115,104,111,114,116, 0,117,115,104,111,114,116, 0,105,110,116, 0,108,111,110,103, 0,117,108,111,110,103, 0,102,
+108,111, 97,116, 0,100,111,117, 98,108,101, 0,118,111,105,100, 0, 76,105,110,107, 0, 76,105,115,116, 66, 97,115,101, 0,118,
+101, 99, 50,115, 0,118,101, 99, 50,105, 0,118,101, 99, 50,102, 0,118,101, 99, 50,100, 0,118,101, 99, 51,105, 0,118,101, 99,
+ 51,102, 0,118,101, 99, 51,100, 0,118,101, 99, 52,105, 0,118,101, 99, 52,102, 0,118,101, 99, 52,100, 0,114, 99,116,105, 0,
+114, 99,116,102, 0, 73, 68, 80,114,111,112,101,114,116,121, 68, 97,116, 97, 0, 73, 68, 80,114,111,112,101,114,116,121, 0, 73,
+ 68, 0, 76,105, 98,114, 97,114,121, 0, 70,105,108,101, 68, 97,116, 97, 0, 73,112,111, 0, 75,101,121, 66,108,111, 99,107, 0,
+ 75,101,121, 0, 83, 99,114,105,112,116, 76,105,110,107, 0, 84,101,120,116, 76,105,110,101, 0, 84,101,120,116, 0, 80, 97, 99,
+107,101,100, 70,105,108,101, 0, 67, 97,109,101,114, 97, 0, 80,114,101,118,105,101,119, 73,109, 97,103,101, 0, 73,109, 97,103,
+101, 85,115,101,114, 0, 73,109, 97,103,101, 0, 97,110,105,109, 0, 82,101,110,100,101,114, 82,101,115,117,108,116, 0, 77, 84,
+101,120, 0, 79, 98,106,101, 99,116, 0, 84,101,120, 0, 80,108,117,103,105,110, 84,101,120, 0, 67, 66, 68, 97,116, 97, 0, 67,
+111,108,111,114, 66, 97,110,100, 0, 69,110,118, 77, 97,112, 0, 73,109, 66,117,102, 0, 84,101,120, 77, 97,112,112,105,110,103,
+ 0, 76, 97,109,112, 0, 87, 97,118,101, 0, 77, 97,116,101,114,105, 97,108, 0, 98, 78,111,100,101, 84,114,101,101, 0, 71,114,
+111,117,112, 0, 86, 70,111,110,116, 0, 86, 70,111,110,116, 68, 97,116, 97, 0, 77,101,116, 97, 69,108,101,109, 0, 66,111,117,
+110,100, 66,111,120, 0, 77,101,116, 97, 66, 97,108,108, 0, 66,101,122, 84,114,105,112,108,101, 0, 66, 80,111,105,110,116, 0,
+ 78,117,114, 98, 0, 67,104, 97,114, 73,110,102,111, 0, 84,101,120,116, 66,111,120, 0, 67,117,114,118,101, 0, 80, 97,116,104,
+ 0, 73,112,111, 68,114,105,118,101,114, 0, 73,112,111, 67,117,114,118,101, 0, 77,101,115,104, 0, 77, 70, 97, 99,101, 0, 77,
+ 84, 70, 97, 99,101, 0, 84, 70, 97, 99,101, 0, 77, 86,101,114,116, 0, 77, 69,100,103,101, 0, 77, 68,101,102,111,114,109, 86,
+101,114,116, 0, 77, 67,111,108, 0, 77, 83,116,105, 99,107,121, 0, 77, 83,101,108,101, 99,116, 0, 79, 99, 73,110,102,111, 0,
+ 67,117,115,116,111,109, 68, 97,116, 97, 0, 77,117,108,116,105,114,101,115, 0, 80, 97,114,116,105, 97,108, 86,105,115,105, 98,
+105,108,105,116,121, 0, 77, 68,101,102,111,114,109, 87,101,105,103,104,116, 0, 77,117,108,116,105,114,101,115, 67,111,108, 0,
+ 77,117,108,116,105,114,101,115, 67,111,108, 70, 97, 99,101, 0, 77,117,108,116,105,114,101,115, 70, 97, 99,101, 0, 77,117,108,
+116,105,114,101,115, 69,100,103,101, 0, 77,117,108,116,105,114,101,115, 76,101,118,101,108, 0, 77,117,108,116,105,114,101,115,
+ 77, 97,112, 78,111,100,101, 0, 77,111,100,105,102,105,101,114, 68, 97,116, 97, 0, 83,117, 98,115,117,114,102, 77,111,100,105,
+102,105,101,114, 68, 97,116, 97, 0, 76, 97,116,116,105, 99,101, 77,111,100,105,102,105,101,114, 68, 97,116, 97, 0, 67,117,114,
+118,101, 77,111,100,105,102,105,101,114, 68, 97,116, 97, 0, 66,117,105,108,100, 77,111,100,105,102,105,101,114, 68, 97,116, 97,
+ 0, 65,114,114, 97,121, 77,111,100,105,102,105,101,114, 68, 97,116, 97, 0, 77,105,114,114,111,114, 77,111,100,105,102,105,101,
+114, 68, 97,116, 97, 0, 69,100,103,101, 83,112,108,105,116, 77,111,100,105,102,105,101,114, 68, 97,116, 97, 0, 68,105,115,112,
+108, 97, 99,101, 77,111,100,105,102,105,101,114, 68, 97,116, 97, 0, 85, 86, 80,114,111,106,101, 99,116, 77,111,100,105,102,105,
+101,114, 68, 97,116, 97, 0, 68,101, 99,105,109, 97,116,101, 77,111,100,105,102,105,101,114, 68, 97,116, 97, 0, 87, 97,118,101,
+ 77,111,100,105,102,105,101,114, 68, 97,116, 97, 0, 65,114,109, 97,116,117,114,101, 77,111,100,105,102,105,101,114, 68, 97,116,
+ 97, 0, 72,111,111,107, 77,111,100,105,102,105,101,114, 68, 97,116, 97, 0, 83,111,102,116, 98,111,100,121, 77,111,100,105,102,
+105,101,114, 68, 97,116, 97, 0, 66,111,111,108,101, 97,110, 77,111,100,105,102,105,101,114, 68, 97,116, 97, 0, 68,105,115,107,
+ 65, 79, 77,111,100,105,102,105,101,114, 68, 97,116, 97, 0, 76, 97,116,116,105, 99,101, 0, 98, 68,101,102,111,114,109, 71,114,
+111,117,112, 0, 76, 66,117,102, 0, 98, 65, 99,116,105,111,110, 0, 98, 80,111,115,101, 0, 80, 97,114,116, 68,101,102,108,101,
+ 99,116, 0, 83,111,102,116, 66,111,100,121, 0, 70,108,117,105,100,115,105,109, 83,101,116,116,105,110,103,115, 0, 68,101,114,
+105,118,101,100, 77,101,115,104, 0, 79, 98, 72,111,111,107, 0, 83, 66, 86,101,114,116,101,120, 0, 66,111,100,121, 80,111,105,
+110,116, 0, 66,111,100,121, 83,112,114,105,110,103, 0, 83, 66, 83, 99,114, 97,116, 99,104, 0, 87,111,114,108,100, 0, 82, 97,
+100,105,111, 0, 66, 97,115,101, 0, 65,118,105, 67,111,100,101, 99, 68, 97,116, 97, 0, 81,117,105, 99,107,116,105,109,101, 67,
+111,100,101, 99, 68, 97,116, 97, 0, 70, 70, 77,112,101,103, 67,111,100,101, 99, 68, 97,116, 97, 0, 65,117,100,105,111, 68, 97,
+116, 97, 0, 83, 99,101,110,101, 82,101,110,100,101,114, 76, 97,121,101,114, 0, 82,101,110,100,101,114, 68, 97,116, 97, 0, 71,
+ 97,109,101, 70,114, 97,109,105,110,103, 0, 84,105,109,101, 77, 97,114,107,101,114, 0, 73,109, 97,103,101, 80, 97,105,110,116,
+ 83,101,116,116,105,110,103,115, 0, 66,114,117,115,104, 0, 84,111,111,108, 83,101,116,116,105,110,103,115, 0, 66,114,117,115,
+104, 68, 97,116, 97, 0, 83, 99,117,108,112,116, 68, 97,116, 97, 0, 83, 99,117,108,112,116, 83,101,115,115,105,111,110, 0, 83,
+ 99,101,110,101, 0, 68, 97,103, 70,111,114,101,115,116, 0, 66, 71,112,105, 99, 0, 86,105,101,119, 51, 68, 0, 83,112, 97, 99,
+101, 76,105,110,107, 0, 83, 99,114, 65,114,101, 97, 0, 82,101,110,100,101,114, 73,110,102,111, 0, 82,101,116,111,112,111, 86,
+105,101,119, 68, 97,116, 97, 0, 86,105,101,119, 68,101,112,116,104,115, 0, 86,105,101,119, 50, 68, 0, 83,112, 97, 99,101, 73,
+110,102,111, 0, 83,112, 97, 99,101, 73,112,111, 0, 83,112, 97, 99,101, 66,117,116,115, 0, 83,112, 97, 99,101, 83,101,113, 0,
+ 83,112, 97, 99,101, 70,105,108,101, 0,100,105,114,101,110,116,114,121, 0, 66,108,101,110,100, 72, 97,110,100,108,101, 0, 83,
+112, 97, 99,101, 79,111,112,115, 0, 84,114,101,101, 83,116,111,114,101, 0, 84,114,101,101, 83,116,111,114,101, 69,108,101,109,
+ 0, 83,112, 97, 99,101, 73,109, 97,103,101, 0, 67,117,114,118,101, 77, 97,112,112,105,110,103, 0, 83,112, 97, 99,101, 78,108,
+ 97, 0, 83,112, 97, 99,101, 84,101,120,116, 0, 83,112, 97, 99,101, 83, 99,114,105,112,116, 0, 83, 99,114,105,112,116, 0, 83,
+112, 97, 99,101, 84,105,109,101, 0, 83,112, 97, 99,101, 78,111,100,101, 0, 83,112, 97, 99,101, 73,109, 97, 83,101,108, 0, 73,
+109, 97, 68,105,114, 0, 79,110,101, 83,101,108,101, 99,116, 97, 98,108,101, 73,109, 97, 0, 84,104,101,109,101, 85, 73, 0, 84,
+104,101,109,101, 83,112, 97, 99,101, 0, 98, 84,104,101,109,101, 0, 83,111,108,105,100, 76,105,103,104,116, 0, 85,115,101,114,
+ 68,101,102, 0, 98, 83, 99,114,101,101,110, 0, 83, 99,114, 86,101,114,116, 0, 83, 99,114, 69,100,103,101, 0, 80, 97,110,101,
+108, 0, 70,105,108,101, 71,108,111, 98, 97,108, 0, 83,116,114,105,112, 69,108,101,109, 0, 83,116,114,105,112, 0, 80,108,117,
+103,105,110, 83,101,113, 0, 83,101,113,117,101,110, 99,101, 0, 98, 83,111,117,110,100, 0,104,100, 97,117,100,105,111, 0, 77,
+101,116, 97, 83,116, 97, 99,107, 0, 69,100,105,116,105,110,103, 0, 87,105,112,101, 86, 97,114,115, 0, 71,108,111,119, 86, 97,
+114,115, 0, 84,114, 97,110,115,102,111,114,109, 86, 97,114,115, 0, 83,111,108,105,100, 67,111,108,111,114, 86, 97,114,115, 0,
+ 83,112,101,101,100, 67,111,110,116,114,111,108, 86, 97,114,115, 0, 69,102,102,101, 99,116, 0, 66,117,105,108,100, 69,102,102,
+ 0, 80, 97,114,116, 69,102,102, 0, 80, 97,114,116,105, 99,108,101, 0, 87, 97,118,101, 69,102,102, 0, 79,111,112,115, 0, 98,
+ 80,114,111,112,101,114,116,121, 0, 98, 78,101, 97,114, 83,101,110,115,111,114, 0, 98, 77,111,117,115,101, 83,101,110,115,111,
+114, 0, 98, 84,111,117, 99,104, 83,101,110,115,111,114, 0, 98, 75,101,121, 98,111, 97,114,100, 83,101,110,115,111,114, 0, 98,
+ 80,114,111,112,101,114,116,121, 83,101,110,115,111,114, 0, 98, 67,111,108,108,105,115,105,111,110, 83,101,110,115,111,114, 0,
+ 98, 82, 97,100, 97,114, 83,101,110,115,111,114, 0, 98, 82, 97,110,100,111,109, 83,101,110,115,111,114, 0, 98, 82, 97,121, 83,
+101,110,115,111,114, 0, 98, 77,101,115,115, 97,103,101, 83,101,110,115,111,114, 0, 98, 83,101,110,115,111,114, 0, 98, 67,111,
+110,116,114,111,108,108,101,114, 0, 98, 74,111,121,115,116,105, 99,107, 83,101,110,115,111,114, 0, 98, 69,120,112,114,101,115,
+115,105,111,110, 67,111,110,116, 0, 98, 80,121,116,104,111,110, 67,111,110,116, 0, 98, 65, 99,116,117, 97,116,111,114, 0, 98,
+ 65,100,100, 79, 98,106,101, 99,116, 65, 99,116,117, 97,116,111,114, 0, 98, 65, 99,116,105,111,110, 65, 99,116,117, 97,116,111,
+114, 0, 98, 83,111,117,110,100, 65, 99,116,117, 97,116,111,114, 0, 98, 67, 68, 65, 99,116,117, 97,116,111,114, 0, 98, 69,100,
+105,116, 79, 98,106,101, 99,116, 65, 99,116,117, 97,116,111,114, 0, 98, 83, 99,101,110,101, 65, 99,116,117, 97,116,111,114, 0,
+ 98, 80,114,111,112,101,114,116,121, 65, 99,116,117, 97,116,111,114, 0, 98, 79, 98,106,101, 99,116, 65, 99,116,117, 97,116,111,
+114, 0, 98, 73,112,111, 65, 99,116,117, 97,116,111,114, 0, 98, 67, 97,109,101,114, 97, 65, 99,116,117, 97,116,111,114, 0, 98,
+ 67,111,110,115,116,114, 97,105,110,116, 65, 99,116,117, 97,116,111,114, 0, 98, 71,114,111,117,112, 65, 99,116,117, 97,116,111,
+114, 0, 98, 82, 97,110,100,111,109, 65, 99,116,117, 97,116,111,114, 0, 98, 77,101,115,115, 97,103,101, 65, 99,116,117, 97,116,
+111,114, 0, 98, 71, 97,109,101, 65, 99,116,117, 97,116,111,114, 0, 98, 86,105,115,105, 98,105,108,105,116,121, 65, 99,116,117,
+ 97,116,111,114, 0, 70,114,101,101, 67, 97,109,101,114, 97, 0, 98, 83, 97,109,112,108,101, 0, 98, 83,111,117,110,100, 76,105,
+115,116,101,110,101,114, 0, 83,112, 97, 99,101, 83,111,117,110,100, 0, 71,114,111,117,112, 79, 98,106,101, 99,116, 0, 66,111,
+110,101, 0, 98, 65,114,109, 97,116,117,114,101, 0, 98, 80,111,115,101, 67,104, 97,110,110,101,108, 0, 98, 65, 99,116,105,111,
+110, 67,104, 97,110,110,101,108, 0, 83,112, 97, 99,101, 65, 99,116,105,111,110, 0, 98, 67,111,110,115,116,114, 97,105,110,116,
+ 67,104, 97,110,110,101,108, 0, 98, 67,111,110,115,116,114, 97,105,110,116, 0, 98, 75,105,110,101,109, 97,116,105, 99, 67,111,
+110,115,116,114, 97,105,110,116, 0, 98, 84,114, 97, 99,107, 84,111, 67,111,110,115,116,114, 97,105,110,116, 0, 98, 82,111,116,
+ 97,116,101, 76,105,107,101, 67,111,110,115,116,114, 97,105,110,116, 0, 98, 76,111, 99, 97,116,101, 76,105,107,101, 67,111,110,
+115,116,114, 97,105,110,116, 0, 98, 77,105,110, 77, 97,120, 67,111,110,115,116,114, 97,105,110,116, 0, 98, 83,105,122,101, 76,
+105,107,101, 67,111,110,115,116,114, 97,105,110,116, 0, 98, 65, 99,116,105,111,110, 67,111,110,115,116,114, 97,105,110,116, 0,
+ 98, 76,111, 99,107, 84,114, 97, 99,107, 67,111,110,115,116,114, 97,105,110,116, 0, 98, 70,111,108,108,111,119, 80, 97,116,104,
+ 67,111,110,115,116,114, 97,105,110,116, 0, 98, 68,105,115,116, 97,110, 99,101, 76,105,109,105,116, 67,111,110,115,116,114, 97,
+105,110,116, 0, 98, 82,111,116, 97,116,105,111,110, 67,111,110,115,116,114, 97,105,110,116, 0, 98, 83,116,114,101,116, 99,104,
+ 84,111, 67,111,110,115,116,114, 97,105,110,116, 0, 98, 76,111, 99, 76,105,109,105,116, 67,111,110,115,116,114, 97,105,110,116,
+ 0, 98, 82,111,116, 76,105,109,105,116, 67,111,110,115,116,114, 97,105,110,116, 0, 98, 83,105,122,101, 76,105,109,105,116, 67,
+111,110,115,116,114, 97,105,110,116, 0, 98, 82,105,103,105,100, 66,111,100,121, 74,111,105,110,116, 67,111,110,115,116,114, 97,
+105,110,116, 0, 98, 65, 99,116,105,111,110, 77,111,100,105,102,105,101,114, 0, 98, 65, 99,116,105,111,110, 83,116,114,105,112,
+ 0, 98, 78,111,100,101, 83,116, 97, 99,107, 0, 98, 78,111,100,101, 83,111, 99,107,101,116, 0, 98, 78,111,100,101, 76,105,110,
+107, 0, 98, 78,111,100,101, 0, 98, 78,111,100,101, 80,114,101,118,105,101,119, 0, 98, 78,111,100,101, 84,121,112,101, 0, 78,
+111,100,101, 73,109, 97,103,101, 65,110,105,109, 0, 78,111,100,101, 66,108,117,114, 68, 97,116, 97, 0, 78,111,100,101, 72,117,
+101, 83, 97,116, 0, 78,111,100,101, 73,109, 97,103,101, 70,105,108,101, 0, 78,111,100,101, 67,104,114,111,109, 97, 0, 78,111,
+100,101, 71,101,111,109,101,116,114,121, 0, 78,111,100,101, 86,101,114,116,101,120, 67,111,108, 0, 78,111,100,101, 68,101,102,
+111, 99,117,115, 0, 67,117,114,118,101, 77, 97,112, 80,111,105,110,116, 0, 67,117,114,118,101, 77, 97,112, 0, 66,114,117,115,
+104, 67,108,111,110,101, 0, 67,117,115,116,111,109, 68, 97,116, 97, 76, 97,121,101,114, 0, 0, 84, 76, 69, 78, 0, 1, 0, 1,
+ 0, 2, 0, 2, 0, 4, 0, 4, 0, 4, 0, 4, 0, 8, 0, 0, 0, 8, 0, 8, 0, 4, 0, 8, 0, 8, 0, 16, 0, 12, 0, 12,
+ 0, 24, 0, 16, 0, 16, 0, 32, 0, 16, 0, 16, 0, 20, 0, 76, 0, 52, 2, 40, 0, 0, 0, 84, 0,104, 0,120, 0, 16, 0, 24,
+ 0,104, 0, 20, 0,128, 0, 12, 0, 32, 1,116, 0, 0, 0, 0, 0,120, 3, 16, 1, 0, 1, 84, 0, 24, 3, 8, 0,168, 0, 0,
+ 0,132, 1, 0, 0, 56, 1,184, 0,108, 0, 68, 1, 68, 0, 0, 0,108, 0,104, 0,136, 0, 56, 0, 36, 0, 56, 0, 8, 0, 16,
+ 1, 56, 0, 0, 0,140, 0, 84, 1, 20, 0, 20, 0, 44, 0, 60, 0, 20, 0, 12, 0, 12, 0, 4, 0, 8, 0, 8, 0, 24, 0, 20,
+ 0, 60, 0, 32, 0, 8, 0, 16, 0, 64, 0, 28, 0, 12, 0, 52, 0, 0, 0, 52, 0, 68, 0, 88, 0, 96, 0, 68, 0,108, 0, 60,
+ 0, 60, 0,108, 0,112, 0, 60, 0, 96, 0, 96, 0,180, 0, 52, 0, 64, 0, 60, 0,116, 0, 40, 0, 12, 0, 60, 0, 40, 0, 44,
+ 0,136, 1,132, 0, 0, 0,208, 0, 16, 0, 0, 0, 0, 0, 0, 1, 40, 0, 40, 0, 28, 0,176, 0,144, 0, 48, 0, 16, 0, 64,
+ 3, 64, 0, 16, 0, 80, 0, 12, 0,152, 0, 76, 0, 8, 0,108, 0, 0, 4,156, 0, 0, 0, 60, 3, 0, 0, 36, 0,204, 0, 0,
+ 0, 0, 0, 0, 0,120, 0, 36, 1, 40, 0,204, 0,180, 1,104, 0, 0, 0, 0, 0,248, 0, 12, 0, 12, 0,248, 1, 0, 0,164,
+ 0,120, 0, 32, 0, 0, 0,148, 0,184, 2,224, 0, 0, 0, 0, 0,152, 0,184, 11,144, 0, 56, 8,240, 0,120, 0, 20, 0, 24,
+ 0,228, 0, 32, 0,104, 0,196, 1,168, 0,184, 1, 28, 0, 0, 0, 16, 0, 28, 0, 12, 0, 24, 0, 40, 0, 16, 0, 20, 0, 16,
+ 0, 24, 1, 56, 0, 0, 0, 56, 0, 44, 0, 64, 0, 48, 0, 8, 0, 44, 0, 72, 0,104, 0, 72, 0, 44, 0, 40, 0,108, 0, 68,
+ 0, 76, 0, 80, 0, 64, 0,128, 0, 4, 0, 60, 0, 12, 0, 60, 0, 28, 0, 20, 0, 64, 0, 16, 0, 76, 0,104, 0, 52, 0, 28,
+ 0, 56, 0, 60, 0, 56, 0,108, 0,140, 0, 4, 0, 40, 0, 0, 0, 68, 0,160, 0, 24, 1, 4, 0,108, 1, 80, 0, 60, 0,176,
+ 0, 44, 0, 52, 0, 68, 0, 52, 0, 44, 0, 44, 0, 68, 0, 44, 0, 64, 0, 44, 0, 20, 0, 60, 0, 24, 0, 52, 0, 28, 0, 28,
+ 0, 28, 0, 96, 0, 52, 0,140, 0, 36, 0,116, 0, 24, 0,164, 0, 0, 0, 0, 0, 16, 0, 24, 0, 12, 1, 16, 0, 40, 0, 64,
+ 0, 32, 0, 24, 0, 12, 0, 44, 0, 20, 0, 52, 83, 84, 82, 67, 0, 0, 0,244, 0, 10, 0, 2, 0, 10, 0, 0, 0, 10, 0, 1,
+ 0, 11, 0, 2, 0, 9, 0, 2, 0, 9, 0, 3, 0, 12, 0, 2, 0, 2, 0, 4, 0, 2, 0, 5, 0, 13, 0, 2, 0, 4, 0, 4,
+ 0, 4, 0, 5, 0, 14, 0, 2, 0, 7, 0, 4, 0, 7, 0, 5, 0, 15, 0, 2, 0, 8, 0, 4, 0, 8, 0, 5, 0, 16, 0, 3,
+ 0, 4, 0, 4, 0, 4, 0, 5, 0, 4, 0, 6, 0, 17, 0, 3, 0, 7, 0, 4, 0, 7, 0, 5, 0, 7, 0, 6, 0, 18, 0, 3,
+ 0, 8, 0, 4, 0, 8, 0, 5, 0, 8, 0, 6, 0, 19, 0, 4, 0, 4, 0, 4, 0, 4, 0, 5, 0, 4, 0, 6, 0, 4, 0, 7,
+ 0, 20, 0, 4, 0, 7, 0, 4, 0, 7, 0, 5, 0, 7, 0, 6, 0, 7, 0, 7, 0, 21, 0, 4, 0, 8, 0, 4, 0, 8, 0, 5,
+ 0, 8, 0, 6, 0, 8, 0, 7, 0, 22, 0, 4, 0, 4, 0, 8, 0, 4, 0, 9, 0, 4, 0, 10, 0, 4, 0, 11, 0, 23, 0, 4,
+ 0, 7, 0, 8, 0, 7, 0, 9, 0, 7, 0, 10, 0, 7, 0, 11, 0, 24, 0, 4, 0, 9, 0, 12, 0, 11, 0, 13, 0, 4, 0, 14,
+ 0, 4, 0, 15, 0, 25, 0, 10, 0, 25, 0, 0, 0, 25, 0, 1, 0, 0, 0, 16, 0, 0, 0, 17, 0, 0, 0, 18, 0, 2, 0, 19,
+ 0, 24, 0, 20, 0, 4, 0, 21, 0, 4, 0, 22, 0, 4, 0, 23, 0, 26, 0, 9, 0, 9, 0, 0, 0, 9, 0, 1, 0, 26, 0, 24,
+ 0, 27, 0, 25, 0, 0, 0, 26, 0, 2, 0, 27, 0, 2, 0, 19, 0, 4, 0, 28, 0, 25, 0, 29, 0, 27, 0, 8, 0, 26, 0, 30,
+ 0, 26, 0, 31, 0, 28, 0, 32, 0, 0, 0, 33, 0, 0, 0, 34, 0, 4, 0, 35, 0, 4, 0, 15, 0, 27, 0, 36, 0, 29, 0, 6,
+ 0, 26, 0, 30, 0, 11, 0, 37, 0, 23, 0, 38, 0, 2, 0, 39, 0, 2, 0, 40, 0, 4, 0, 15, 0, 30, 0, 13, 0, 30, 0, 0,
+ 0, 30, 0, 1, 0, 7, 0, 41, 0, 7, 0, 42, 0, 2, 0, 17, 0, 2, 0, 43, 0, 4, 0, 44, 0, 9, 0, 45, 0, 7, 0, 46,
+ 0, 0, 0, 16, 0, 0, 0, 47, 0, 7, 0, 48, 0, 7, 0, 49, 0, 31, 0, 12, 0, 26, 0, 30, 0, 30, 0, 50, 0, 0, 0, 51,
+ 0, 4, 0, 52, 0, 7, 0, 42, 0, 11, 0, 53, 0, 29, 0, 54, 0, 26, 0, 55, 0, 2, 0, 17, 0, 2, 0, 56, 0, 2, 0, 57,
+ 0, 2, 0, 19, 0, 32, 0, 5, 0, 26, 0, 58, 0, 2, 0, 59, 0, 2, 0, 60, 0, 2, 0, 61, 0, 4, 0, 15, 0, 33, 0, 6,
+ 0, 33, 0, 0, 0, 33, 0, 1, 0, 0, 0, 62, 0, 0, 0, 63, 0, 4, 0, 21, 0, 4, 0, 64, 0, 34, 0, 13, 0, 26, 0, 30,
+ 0, 0, 0, 65, 0, 4, 0, 66, 0, 4, 0, 67, 0, 11, 0, 68, 0, 33, 0, 69, 0, 33, 0, 70, 0, 4, 0, 71, 0, 4, 0, 72,
+ 0, 0, 0, 73, 0, 4, 0, 74, 0, 4, 0, 75, 0, 9, 0, 76, 0, 35, 0, 5, 0, 4, 0, 77, 0, 4, 0, 78, 0, 4, 0, 66,
+ 0, 4, 0, 15, 0, 9, 0, 45, 0, 36, 0, 19, 0, 26, 0, 30, 0, 2, 0, 17, 0, 2, 0, 19, 0, 7, 0, 79, 0, 7, 0, 80,
+ 0, 7, 0, 81, 0, 7, 0, 82, 0, 7, 0, 83, 0, 7, 0, 84, 0, 7, 0, 85, 0, 7, 0, 86, 0, 7, 0, 87, 0, 7, 0, 88,
+ 0, 7, 0, 89, 0, 2, 0, 90, 0, 2, 0, 91, 0, 7, 0, 92, 0, 29, 0, 54, 0, 32, 0, 93, 0, 37, 0, 3, 0, 4, 0, 7,
+ 0, 4, 0, 94, 0, 4, 0, 95, 0, 38, 0, 12, 0, 4, 0, 96, 0, 4, 0, 97, 0, 4, 0, 98, 0, 4, 0, 99, 0, 2, 0,100,
+ 0, 2, 0,101, 0, 2, 0, 19, 0, 2, 0,102, 0, 2, 0,103, 0, 2, 0,104, 0, 2, 0,105, 0, 2, 0,106, 0, 39, 0, 29,
+ 0, 26, 0, 30, 0, 0, 0, 33, 0, 11, 0,107, 0, 40, 0,108, 0, 41, 0,109, 0, 2, 0,102, 0, 2, 0, 19, 0, 2, 0,110,
+ 0, 2, 0, 17, 0, 2, 0, 15, 0, 2, 0, 80, 0, 4, 0,111, 0, 2, 0,112, 0, 2, 0,113, 0, 2, 0,114, 0, 2, 0,115,
+ 0, 2, 0,116, 0, 2, 0,117, 0, 4, 0,118, 0, 4, 0,119, 0, 35, 0,120, 0, 37, 0,121, 0, 7, 0,122, 0, 4, 0,123,
+ 0, 2, 0,124, 0, 2, 0,125, 0, 2, 0,126, 0, 2, 0,127, 0, 9, 0,128, 0, 42, 0, 25, 0, 2, 0,129, 0, 2, 0,130,
+ 0, 2, 0,131, 0, 2, 0,132, 0, 43, 0,133, 0, 44, 0,134, 0, 0, 0,135, 0, 0, 0,136, 0, 0, 0,137, 0, 0, 0,138,
+ 0, 0, 0,139, 0, 7, 0,140, 0, 7, 0,141, 0, 2, 0,142, 0, 2, 0,143, 0, 7, 0,144, 0, 7, 0,145, 0, 7, 0,146,
+ 0, 7, 0,147, 0, 7, 0,148, 0, 7, 0,149, 0, 7, 0,150, 0, 7, 0,151, 0, 7, 0,152, 0, 7, 0,153, 0, 45, 0, 15,
+ 0, 0, 0,154, 0, 9, 0,155, 0, 0, 0,156, 0, 0, 0,157, 0, 4, 0,158, 0, 4, 0,159, 0, 9, 0,160, 0, 7, 0,161,
+ 0, 7, 0,162, 0, 7, 0,163, 0, 4, 0,164, 0, 9, 0,165, 0, 9, 0,166, 0, 4, 0,167, 0, 4, 0, 15, 0, 46, 0, 6,
+ 0, 7, 0,144, 0, 7, 0,145, 0, 7, 0,146, 0, 7, 0,168, 0, 7, 0, 41, 0, 4, 0, 38, 0, 47, 0, 5, 0, 2, 0, 19,
+ 0, 2, 0, 35, 0, 2, 0, 38, 0, 2, 0,169, 0, 46, 0,163, 0, 48, 0, 17, 0, 43, 0,133, 0, 39, 0,170, 0, 49, 0,171,
+ 0, 7, 0,172, 0, 7, 0,173, 0, 2, 0, 17, 0, 2, 0,174, 0, 7, 0, 81, 0, 7, 0, 82, 0, 7, 0,175, 0, 4, 0,176,
+ 0, 2, 0,177, 0, 2, 0,178, 0, 4, 0,102, 0, 4, 0,111, 0, 2, 0,179, 0, 2, 0,180, 0, 44, 0, 52, 0, 26, 0, 30,
+ 0, 7, 0,181, 0, 7, 0,182, 0, 7, 0,183, 0, 7, 0,184, 0, 7, 0,185, 0, 7, 0,186, 0, 7, 0,187, 0, 7, 0,188,
+ 0, 7, 0,189, 0, 7, 0,190, 0, 7, 0,191, 0, 7, 0,192, 0, 7, 0,193, 0, 7, 0,194, 0, 7, 0,195, 0, 7, 0,196,
+ 0, 7, 0,197, 0, 7, 0,198, 0, 7, 0,199, 0, 7, 0,200, 0, 2, 0,201, 0, 2, 0,202, 0, 2, 0,203, 0, 2, 0,204,
+ 0, 2, 0,205, 0, 2, 0,206, 0, 2, 0,207, 0, 2, 0, 19, 0, 2, 0, 17, 0, 2, 0,174, 0, 7, 0,208, 0, 7, 0,209,
+ 0, 7, 0,210, 0, 7, 0,211, 0, 2, 0,212, 0, 2, 0,213, 0, 2, 0,214, 0, 2, 0,100, 0, 4, 0, 21, 0, 4, 0, 97,
+ 0, 4, 0, 98, 0, 4, 0, 99, 0, 7, 0,215, 0, 7, 0,216, 0, 7, 0,150, 0, 38, 0,217, 0, 29, 0, 54, 0, 39, 0,170,
+ 0, 45, 0,218, 0, 47, 0,219, 0, 48, 0,220, 0, 50, 0, 8, 0, 7, 0,221, 0, 7, 0,222, 0, 7, 0,141, 0, 4, 0, 19,
+ 0, 7, 0,223, 0, 7, 0,224, 0, 7, 0,225, 0, 43, 0,226, 0, 51, 0, 52, 0, 26, 0, 30, 0, 2, 0, 17, 0, 2, 0,227,
+ 0, 2, 0,143, 0, 2, 0,228, 0, 7, 0,144, 0, 7, 0,145, 0, 7, 0,146, 0, 7, 0,147, 0, 7, 0,229, 0, 7, 0,230,
+ 0, 7, 0,231, 0, 7, 0,232, 0, 7, 0,233, 0, 7, 0,234, 0, 7, 0,235, 0, 7, 0, 81, 0, 7, 0, 82, 0, 7, 0,236,
+ 0, 7, 0,237, 0, 7, 0,238, 0, 2, 0,239, 0, 2, 0,240, 0, 2, 0,241, 0, 2, 0,242, 0, 0, 0,243, 0, 0, 0,244,
+ 0, 2, 0,245, 0, 2, 0,246, 0, 2, 0,247, 0, 2, 0,248, 0, 2, 0,249, 0, 7, 0,250, 0, 7, 0,251, 0, 7, 0,252,
+ 0, 2, 0,253, 0, 2, 0,254, 0, 4, 0,255, 0, 4, 1, 0, 0, 2, 1, 1, 0, 2, 1, 2, 0, 2, 1, 3, 0, 2, 1, 4,
+ 0, 7, 1, 5, 0, 7, 1, 6, 0, 7, 1, 7, 0, 7, 1, 8, 0, 2, 1, 9, 0, 2, 1, 10, 0, 42, 1, 11, 0, 29, 0, 54,
+ 0, 32, 0, 93, 0, 52, 0, 2, 0, 26, 0, 30, 0, 29, 0, 54, 0, 53, 0,101, 0, 26, 0, 30, 0, 2, 0,143, 0, 2, 0, 19,
+ 0, 7, 0,144, 0, 7, 0,145, 0, 7, 0,146, 0, 7, 1, 12, 0, 7, 1, 13, 0, 7, 1, 14, 0, 7, 1, 15, 0, 7, 1, 16,
+ 0, 7, 1, 17, 0, 7, 1, 18, 0, 7, 1, 19, 0, 7, 1, 20, 0, 7, 1, 21, 0, 7, 1, 22, 0, 7, 1, 23, 0, 7, 1, 24,
+ 0, 7, 1, 25, 0, 7, 1, 26, 0, 7, 1, 27, 0, 7, 1, 28, 0, 7, 1, 29, 0, 7, 1, 30, 0, 7, 1, 31, 0, 7, 1, 32,
+ 0, 7, 1, 33, 0, 7, 1, 34, 0, 7, 1, 35, 0, 7, 1, 36, 0, 7, 1, 37, 0, 7, 1, 38, 0, 2, 1, 39, 0, 2, 1, 40,
+ 0, 2, 1, 41, 0, 0, 1, 42, 0, 0, 1, 43, 0, 4, 0,227, 0, 4, 1, 44, 0, 2, 1, 45, 0, 2, 1, 46, 0, 2, 1, 47,
+ 0, 2, 1, 48, 0, 7, 1, 49, 0, 7, 1, 50, 0, 7, 1, 51, 0, 7, 1, 52, 0, 7, 1, 53, 0, 7, 1, 54, 0, 7, 1, 55,
+ 0, 7, 1, 56, 0, 7, 1, 57, 0, 7, 1, 58, 0, 0, 1, 59, 0, 0, 0,253, 0, 0, 1, 60, 0, 0, 1, 61, 0, 2, 1, 62,
+ 0, 2, 1, 63, 0, 2, 1, 64, 0, 2, 1, 65, 0, 2, 1, 66, 0, 2, 1, 67, 0, 7, 1, 68, 0, 7, 1, 69, 0, 7, 1, 70,
+ 0, 7, 1, 71, 0, 7, 1, 72, 0, 2, 0,129, 0, 2, 0,130, 0, 47, 1, 73, 0, 47, 1, 74, 0, 0, 1, 75, 0, 0, 1, 76,
+ 0, 0, 1, 77, 0, 0, 1, 78, 0, 2, 1, 79, 0, 2, 1, 80, 0, 7, 1, 81, 0, 7, 1, 82, 0, 42, 1, 11, 0, 54, 1, 83,
+ 0, 29, 0, 54, 0, 55, 1, 84, 0, 7, 1, 85, 0, 7, 1, 86, 0, 7, 1, 87, 0, 7, 1, 88, 0, 7, 1, 89, 0, 2, 1, 90,
+ 0, 2, 1, 91, 0, 7, 1, 92, 0, 7, 1, 93, 0, 7, 1, 94, 0, 7, 1, 95, 0, 7, 1, 96, 0, 4, 1, 97, 0, 4, 1, 98,
+ 0, 4, 1, 99, 0, 32, 0, 93, 0, 56, 0, 6, 0, 26, 0, 30, 0, 0, 1,100, 0, 7, 1,101, 0, 7, 0, 15, 0, 57, 0, 45,
+ 0, 35, 0,120, 0, 58, 0, 26, 0, 58, 0, 0, 0, 58, 0, 1, 0, 59, 1,102, 0, 4, 1,103, 0, 4, 1,104, 0, 4, 1,105,
+ 0, 4, 1,106, 0, 4, 1,107, 0, 4, 1,108, 0, 2, 0, 17, 0, 2, 0, 19, 0, 2, 1,109, 0, 2, 1,110, 0, 7, 0, 4,
+ 0, 7, 0, 5, 0, 7, 0, 6, 0, 7, 1,111, 0, 7, 1,112, 0, 7, 1,113, 0, 7, 1,114, 0, 7, 1,115, 0, 7, 1,116,
+ 0, 7, 1,117, 0, 7, 0, 21, 0, 7, 1,118, 0, 7, 1,119, 0, 60, 0, 15, 0, 26, 0, 30, 0, 59, 1,102, 0, 11, 1,120,
+ 0, 11, 1,121, 0, 29, 0, 54, 0, 53, 1,122, 0, 2, 0, 19, 0, 2, 1,123, 0, 4, 0,142, 0, 7, 0,221, 0, 7, 0,141,
+ 0, 7, 0,222, 0, 7, 1,124, 0, 7, 1,125, 0, 7, 1,126, 0, 61, 0, 10, 0, 7, 1,127, 0, 7, 1,128, 0, 7, 1,129,
+ 0, 7, 1,130, 0, 2, 1,131, 0, 2, 1,132, 0, 0, 1,133, 0, 0, 1,134, 0, 0, 1,135, 0, 0, 1,136, 0, 62, 0, 7,
+ 0, 7, 1,137, 0, 7, 1,128, 0, 7, 1,129, 0, 2, 1,133, 0, 2, 1,136, 0, 7, 1,130, 0, 7, 0, 15, 0, 63, 0, 20,
+ 0, 63, 0, 0, 0, 63, 0, 1, 0, 2, 0, 17, 0, 2, 1,138, 0, 2, 1,136, 0, 2, 0, 19, 0, 2, 1,139, 0, 2, 1,140,
+ 0, 2, 1,141, 0, 2, 1,142, 0, 2, 1,143, 0, 2, 1,144, 0, 2, 1,145, 0, 2, 1,146, 0, 7, 1,147, 0, 7, 1,148,
+ 0, 62, 1,149, 0, 61, 1,150, 0, 4, 1,151, 0, 4, 0, 15, 0, 64, 0, 5, 0, 2, 1,152, 0, 2, 1,138, 0, 0, 0, 19,
+ 0, 0, 0, 15, 0, 2, 1, 91, 0, 65, 0, 4, 0, 7, 0, 4, 0, 7, 0, 5, 0, 7, 0, 7, 0, 7, 0, 94, 0, 66, 0, 57,
+ 0, 26, 0, 30, 0, 59, 1,102, 0, 11, 1,153, 0, 11, 1,121, 0, 43, 1,154, 0, 43, 1,155, 0, 43, 1,156, 0, 29, 0, 54,
+ 0, 67, 1,157, 0, 31, 1,158, 0, 53, 1,122, 0, 11, 1,159, 0, 7, 0,221, 0, 7, 0,141, 0, 7, 0,222, 0, 4, 0,142,
+ 0, 2, 1,160, 0, 2, 1,123, 0, 2, 0, 19, 0, 2, 1,161, 0, 7, 1,162, 0, 7, 1,163, 0, 7, 1,164, 0, 2, 1,141,
+ 0, 2, 1,142, 0, 2, 1,165, 0, 2, 1,166, 0, 4, 1, 91, 0, 2, 0, 21, 0, 2, 0, 68, 0, 2, 0, 41, 0, 2, 1,167,
+ 0, 7, 1,168, 0, 7, 1,169, 0, 7, 1,170, 0, 7, 1,171, 0, 7, 1,172, 0, 7, 1,173, 0, 7, 1,174, 0, 7, 1,175,
+ 0, 7, 1,176, 0, 7, 1,177, 0, 0, 1,178, 0, 0, 1,179, 0, 56, 1,180, 0, 56, 1,181, 0, 56, 1,182, 0, 56, 1,183,
+ 0, 4, 1,184, 0, 4, 1,185, 0, 4, 1,186, 0, 4, 0, 15, 0, 65, 1,187, 0, 4, 1,188, 0, 4, 1,189, 0, 64, 1,190,
+ 0, 64, 1,191, 0, 68, 0, 6, 0, 43, 0,226, 0, 2, 0, 39, 0, 2, 0, 43, 0, 2, 0, 17, 0, 2, 0, 19, 0, 0, 1,192,
+ 0, 69, 0, 19, 0, 69, 0, 0, 0, 69, 0, 1, 0, 62, 1,149, 0, 61, 1,150, 0, 23, 1,193, 0, 23, 1,194, 0, 2, 0, 39,
+ 0, 2, 0, 43, 0, 2, 1,195, 0, 2, 1,196, 0, 2, 1,197, 0, 2, 1,198, 0, 2, 0, 19, 0, 2, 1,199, 0, 7, 0, 10,
+ 0, 7, 0, 11, 0, 4, 1,200, 0, 7, 0, 42, 0, 68, 1,201, 0, 70, 0, 41, 0, 26, 0, 30, 0, 59, 1,102, 0, 11, 1,202,
+ 0, 29, 0, 54, 0, 31, 1,158, 0, 53, 1,122, 0, 71, 1,203, 0, 72, 1,204, 0, 73, 1,205, 0, 74, 1,206, 0, 75, 1,207,
+ 0, 76, 1,208, 0, 77, 1,209, 0, 78, 1,210, 0, 70, 1,211, 0, 79, 1,212, 0, 80, 1,213, 0, 9, 1,214, 0, 81, 1,215,
+ 0, 81, 1,216, 0, 81, 1,217, 0, 4, 1,196, 0, 4, 1,218, 0, 4, 1,219, 0, 4, 1,220, 0, 4, 1, 91, 0, 4, 0,142,
+ 0, 7, 0,221, 0, 7, 0,141, 0, 7, 0,222, 0, 7, 1,221, 0, 7, 0, 15, 0, 2, 1,222, 0, 2, 0, 19, 0, 2, 1,223,
+ 0, 2, 1,224, 0, 2, 1,123, 0, 2, 1,225, 0, 82, 1,226, 0, 83, 1,227, 0, 9, 0,128, 0, 73, 0, 8, 0, 9, 1,228,
+ 0, 7, 1,229, 0, 4, 1,230, 0, 0, 0, 19, 0, 0, 1,231, 0, 2, 0,227, 0, 2, 1,232, 0, 2, 1,233, 0, 71, 0, 8,
+ 0, 4, 1,234, 0, 4, 1,235, 0, 4, 1,236, 0, 4, 1,237, 0, 0, 0, 15, 0, 0, 1,138, 0, 0, 1,238, 0, 0, 0, 19,
+ 0, 75, 0, 5, 0, 4, 1,234, 0, 4, 1,235, 0, 0, 1,239, 0, 0, 0, 15, 0, 2, 0, 19, 0, 84, 0, 2, 0, 4, 1,240,
+ 0, 7, 1,129, 0, 76, 0, 3, 0, 84, 1,241, 0, 4, 1,242, 0, 4, 0, 19, 0, 74, 0, 4, 0, 7, 1,243, 0, 2, 1,244,
+ 0, 0, 0, 19, 0, 0, 1,138, 0, 77, 0, 4, 0, 0, 0,168, 0, 0, 0,144, 0, 0, 0,145, 0, 0, 0,146, 0, 78, 0, 1,
+ 0, 7, 1,245, 0, 79, 0, 2, 0, 4, 1,246, 0, 4, 0, 17, 0, 72, 0, 7, 0, 7, 1,229, 0, 39, 1,228, 0, 0, 0, 19,
+ 0, 0, 1,231, 0, 2, 0,227, 0, 2, 1,232, 0, 2, 1,233, 0, 85, 0, 4, 0, 7, 0,168, 0, 7, 0,144, 0, 7, 0,145,
+ 0, 7, 0,146, 0, 86, 0, 1, 0, 85, 1,230, 0, 87, 0, 6, 0, 4, 1,247, 0, 4, 1,248, 0, 4, 1,249, 0, 0, 0, 19,
+ 0, 0, 1,138, 0, 0, 1,250, 0, 88, 0, 2, 0, 4, 1,251, 0, 4, 1,248, 0, 89, 0, 13, 0, 89, 0, 0, 0, 89, 0, 1,
+ 0, 74, 1,252, 0, 87, 1,253, 0, 86, 1,254, 0, 88, 1,255, 0, 11, 2, 0, 0, 11, 2, 1, 0, 90, 2, 2, 0, 4, 1,196,
+ 0, 4, 1,219, 0, 4, 1,218, 0, 4, 0, 15, 0, 82, 0, 12, 0, 11, 2, 3, 0, 0, 2, 4, 0, 0, 2, 5, 0, 0, 2, 6,
+ 0, 0, 2, 7, 0, 0, 2, 8, 0, 0, 2, 9, 0, 0, 2, 10, 0, 0, 0, 15, 0, 81, 1,215, 0, 81, 1,217, 0, 2, 2, 11,
+ 0, 83, 0, 8, 0, 4, 2, 12, 0, 4, 2, 13, 0, 71, 2, 14, 0, 75, 2, 15, 0, 4, 1,219, 0, 4, 1,218, 0, 4, 1,196,
+ 0, 4, 0, 15, 0, 91, 0, 6, 0, 91, 0, 0, 0, 91, 0, 1, 0, 4, 0, 17, 0, 4, 0,227, 0, 0, 0, 16, 0, 0, 2, 16,
+ 0, 92, 0, 7, 0, 91, 2, 17, 0, 2, 2, 18, 0, 2, 2, 3, 0, 2, 2, 19, 0, 2, 0, 66, 0, 9, 2, 20, 0, 9, 2, 21,
+ 0, 93, 0, 3, 0, 91, 2, 17, 0, 43, 0,133, 0, 0, 0, 16, 0, 94, 0, 5, 0, 91, 2, 17, 0, 43, 0,133, 0, 0, 0, 16,
+ 0, 2, 2, 22, 0, 0, 2, 23, 0, 95, 0, 5, 0, 91, 2, 17, 0, 7, 2, 24, 0, 7, 2, 25, 0, 4, 2, 26, 0, 4, 2, 27,
+ 0, 96, 0, 11, 0, 91, 2, 17, 0, 43, 2, 28, 0, 43, 2, 29, 0, 7, 2, 30, 0, 7, 2, 31, 0, 7, 2, 25, 0, 7, 2, 32,
+ 0, 4, 2, 33, 0, 4, 2, 34, 0, 4, 0, 66, 0, 4, 2, 35, 0, 97, 0, 4, 0, 91, 2, 17, 0, 2, 2, 36, 0, 2, 0, 19,
+ 0, 7, 2, 37, 0, 98, 0, 3, 0, 91, 2, 17, 0, 7, 2, 38, 0, 4, 0, 66, 0, 99, 0, 8, 0, 91, 2, 17, 0, 44, 2, 39,
+ 0, 7, 2, 40, 0, 4, 2, 41, 0, 0, 2, 42, 0, 7, 2, 43, 0, 4, 2, 44, 0, 43, 2, 45, 0,100, 0, 7, 0, 91, 2, 17,
+ 0, 43, 2, 46, 0, 39, 2, 47, 0, 4, 0, 66, 0, 4, 2, 48, 0, 7, 2, 49, 0, 7, 2, 50, 0,101, 0, 3, 0, 91, 2, 17,
+ 0, 7, 2, 51, 0, 4, 2, 52, 0,102, 0, 13, 0, 91, 2, 17, 0, 43, 2, 53, 0, 2, 0, 19, 0, 2, 0, 15, 0, 7, 2, 54,
+ 0, 7, 2, 55, 0, 7, 2, 56, 0, 7, 1,162, 0, 7, 2, 57, 0, 7, 2, 58, 0, 7, 2, 59, 0, 7, 2, 60, 0, 7, 2, 61,
+ 0,103, 0, 6, 0, 91, 2, 17, 0, 2, 2, 62, 0, 2, 0, 80, 0, 4, 1, 91, 0, 43, 0,133, 0, 0, 2, 42, 0,104, 0, 9,
+ 0, 91, 2, 17, 0, 43, 0,133, 0, 7, 2, 63, 0, 7, 2, 64, 0, 7, 2, 65, 0, 4, 2, 66, 0, 4, 2, 67, 0, 7, 2, 68,
+ 0, 0, 0, 16, 0,105, 0, 1, 0, 91, 2, 17, 0,106, 0, 4, 0, 91, 2, 17, 0, 43, 0,133, 0, 4, 2, 69, 0, 4, 0, 15,
+ 0,107, 0, 3, 0, 91, 2, 17, 0, 4, 2, 70, 0, 7, 2, 71, 0,108, 0, 24, 0, 26, 0, 30, 0, 2, 1,139, 0, 2, 1,140,
+ 0, 2, 2, 72, 0, 2, 0, 19, 0, 2, 2, 73, 0, 2, 2, 74, 0, 2, 2, 75, 0, 2, 1, 91, 0, 0, 2, 76, 0, 0, 2, 77,
+ 0, 0, 2, 78, 0, 0, 0, 17, 0, 4, 0, 15, 0, 7, 2, 79, 0, 7, 2, 80, 0, 7, 2, 81, 0, 7, 2, 82, 0, 7, 2, 83,
+ 0, 7, 2, 84, 0, 62, 2, 85, 0, 29, 0, 54, 0, 31, 1,158, 0, 76, 1,208, 0,109, 0, 3, 0,109, 0, 0, 0,109, 0, 1,
+ 0, 0, 0, 16, 0, 59, 0, 3, 0, 7, 2, 86, 0, 4, 0, 19, 0, 4, 0, 15, 0, 80, 0, 2, 0, 7, 2, 87, 0, 7, 0,141,
+ 0,110, 0, 4, 0, 2, 0, 35, 0, 2, 2, 88, 0, 4, 0, 15, 0, 43, 2, 89, 0, 43, 0,104, 0, 26, 0, 30, 0, 2, 0, 17,
+ 0, 2, 2, 90, 0, 4, 2, 91, 0, 4, 2, 92, 0, 4, 2, 93, 0, 0, 2, 94, 0, 9, 2, 95, 0, 43, 0, 36, 0, 43, 2, 96,
+ 0, 43, 2, 97, 0, 43, 2, 98, 0, 43, 2, 99, 0, 29, 0, 54, 0, 67, 1,157, 0, 59, 1,102, 0,111, 2,100, 0,112, 2,101,
+ 0, 9, 0, 45, 0, 11, 2,102, 0, 11, 1,202, 0, 11, 2,103, 0, 11, 1,121, 0, 11, 2,104, 0, 11, 2,105, 0, 53, 1,122,
+ 0, 7, 0,221, 0, 7, 2,106, 0, 7, 2,107, 0, 7, 0,141, 0, 7, 2,108, 0, 7, 0,222, 0, 7, 2,109, 0, 7, 1,111,
+ 0, 7, 2,110, 0, 7, 2,111, 0, 7, 2, 63, 0, 7, 0,172, 0, 4, 2,112, 0, 2, 0, 19, 0, 2, 2,113, 0, 2, 2,114,
+ 0, 2, 2,115, 0, 2, 2,116, 0, 2, 2,117, 0, 2, 2,118, 0, 2, 2,119, 0, 2, 2,120, 0, 2, 2,121, 0, 2, 2,122,
+ 0, 2, 2,123, 0, 4, 2,124, 0, 4, 2,125, 0, 4, 2,126, 0, 4, 2,127, 0, 7, 2,128, 0, 7, 2,129, 0, 7, 2,130,
+ 0, 7, 2,131, 0, 7, 2,132, 0, 7, 2,133, 0, 7, 2,134, 0, 7, 2,135, 0, 7, 2,136, 0, 0, 2,137, 0, 0, 2,138,
+ 0, 0, 1,123, 0, 0, 2,139, 0, 0, 2,140, 0, 0, 2,141, 0, 7, 2,142, 0, 32, 0, 93, 0, 11, 2,143, 0, 11, 2,144,
+ 0, 11, 2,145, 0, 11, 2,146, 0, 9, 1,214, 0, 7, 2,147, 0, 2, 1,246, 0, 2, 2,148, 0, 7, 1,230, 0, 4, 2,149,
+ 0, 4, 2,150, 0, 2, 2,151, 0, 2, 0,179, 0, 7, 2,152, 0, 11, 2,153, 0, 11, 2,154, 0, 11, 2,155, 0,113, 2,156,
+ 0,114, 2,157, 0, 55, 2,158, 0, 2, 2,159, 0, 2, 2,160, 0, 2, 2,161, 0, 2, 2,162, 0, 7, 1,222, 0, 4, 2,163,
+ 0,115, 2,164, 0,116, 2,165, 0,116, 2,166, 0, 4, 2,167, 0, 4, 0, 15, 0, 9, 0,128, 0,117, 0, 14, 0,117, 0, 0,
+ 0,117, 0, 1, 0, 43, 0, 36, 0, 7, 2, 63, 0, 7, 0,223, 0, 7, 2, 64, 0, 7, 2, 65, 0, 0, 0, 16, 0, 4, 2, 66,
+ 0, 4, 2, 67, 0, 4, 2,168, 0, 2, 0, 17, 0, 2, 2,169, 0, 7, 2, 68, 0,113, 0, 13, 0, 2, 2,170, 0, 2, 2,171,
+ 0, 2, 0, 19, 0, 2, 0, 15, 0, 7, 2,172, 0, 7, 2,173, 0, 7, 2,174, 0, 7, 2,175, 0, 7, 2,176, 0, 7, 2,177,
+ 0, 7, 2,178, 0, 7, 2,179, 0, 7, 2,180, 0,118, 0, 1, 0, 7, 1,137, 0,114, 0, 40, 0, 4, 2,181, 0, 4, 2,182,
+ 0,119, 2,183, 0,120, 2,184, 0, 7, 2,129, 0, 7, 2,185, 0, 7, 2,186, 0, 7, 2,187, 0, 7, 2,188, 0, 7, 2,189,
+ 0, 7, 2,190, 0, 7, 2,191, 0, 7, 2,192, 0, 7, 2,193, 0, 7, 2,194, 0, 2, 2,195, 0, 2, 2,196, 0, 7, 2,197,
+ 0, 7, 2,198, 0, 4, 0, 99, 0, 4, 2,199, 0, 4, 2,200, 0, 2, 2,201, 0, 2, 2,202, 0,118, 2,203, 0, 4, 2,204,
+ 0, 4, 0, 56, 0, 7, 2,205, 0, 7, 2,206, 0, 7, 2,207, 0, 7, 2,208, 0, 2, 2,209, 0, 2, 2,210, 0, 2, 2,211,
+ 0, 2, 2,212, 0, 2, 2,213, 0, 2, 1, 80, 0, 2, 2,163, 0, 2, 2,214, 0,121, 2,215, 0,115, 0, 40, 0, 2, 0, 17,
+ 0, 2, 2,216, 0, 2, 2,217, 0, 2, 2,218, 0, 7, 2,219, 0, 2, 2,220, 0, 2, 2,221, 0, 7, 2,222, 0, 2, 2,223,
+ 0, 2, 2,224, 0, 7, 2,225, 0, 7, 2,226, 0, 7, 2,227, 0, 7, 2,228, 0, 7, 2,229, 0, 7, 2,230, 0, 4, 2,231,
+ 0, 7, 2,232, 0, 7, 2,233, 0, 7, 2,234, 0, 70, 2,235, 0, 70, 2,236, 0, 70, 2,237, 0, 0, 2,238, 0, 7, 2,239,
+ 0, 7, 2,240, 0, 29, 0, 54, 0, 2, 2,241, 0, 0, 2,242, 0, 0, 2,243, 0, 7, 2,244, 0, 4, 2,245, 0, 7, 2,246,
+ 0, 7, 2,247, 0, 4, 2,248, 0, 4, 2,249, 0, 7, 2,250, 0, 7, 2,251, 0, 7, 2,252, 0, 74, 2,253, 0,122, 0, 57,
+ 0, 26, 0, 30, 0, 2, 0,143, 0, 2, 0,228, 0, 2, 0,253, 0, 2, 2,254, 0, 7, 2,255, 0, 7, 3, 0, 0, 7, 3, 1,
+ 0, 7, 3, 2, 0, 7, 3, 3, 0, 7, 3, 4, 0, 7, 3, 5, 0, 7, 3, 6, 0, 7, 1, 18, 0, 7, 1, 20, 0, 7, 1, 19,
+ 0, 7, 3, 7, 0, 4, 3, 8, 0, 7, 3, 9, 0, 7, 3, 10, 0, 7, 3, 11, 0, 7, 3, 12, 0, 7, 3, 13, 0, 7, 3, 14,
+ 0, 7, 3, 15, 0, 2, 3, 16, 0, 2, 0,227, 0, 4, 3, 17, 0, 7, 3, 18, 0, 7, 3, 19, 0, 7, 3, 20, 0, 7, 3, 21,
+ 0, 7, 3, 22, 0, 7, 3, 23, 0, 7, 3, 24, 0, 7, 3, 25, 0, 7, 3, 26, 0, 7, 3, 27, 0, 7, 3, 28, 0, 7, 3, 29,
+ 0, 2, 3, 30, 0, 2, 3, 31, 0, 2, 3, 32, 0, 2, 3, 33, 0, 7, 3, 34, 0, 7, 3, 35, 0, 7, 3, 36, 0, 7, 3, 37,
+ 0, 2, 3, 38, 0, 2, 3, 39, 0, 2, 3, 40, 0, 2, 3, 41, 0, 7, 3, 42, 0, 7, 3, 43, 0, 29, 0, 54, 0, 42, 1, 11,
+ 0, 32, 0, 93, 0,123, 0, 16, 0, 2, 3, 44, 0, 2, 3, 45, 0, 2, 3, 46, 0, 2, 0, 19, 0, 2, 3, 47, 0, 2, 3, 48,
+ 0, 2, 3, 49, 0, 2, 3, 50, 0, 2, 3, 51, 0, 2, 3, 52, 0, 2, 3, 53, 0, 2, 3, 54, 0, 4, 3, 55, 0, 7, 3, 56,
+ 0, 7, 3, 57, 0, 7, 3, 58, 0,124, 0, 8, 0,124, 0, 0, 0,124, 0, 1, 0, 4, 2,112, 0, 4, 3, 59, 0, 4, 0, 19,
+ 0, 2, 3, 60, 0, 2, 3, 61, 0, 43, 0,133, 0,125, 0, 13, 0, 9, 3, 62, 0, 9, 3, 63, 0, 4, 3, 64, 0, 4, 3, 65,
+ 0, 4, 3, 66, 0, 4, 3, 67, 0, 4, 3, 68, 0, 4, 3, 69, 0, 4, 3, 70, 0, 4, 3, 71, 0, 4, 3, 72, 0, 4, 0, 15,
+ 0, 0, 3, 73, 0,126, 0, 5, 0, 9, 3, 74, 0, 9, 3, 75, 0, 4, 3, 76, 0, 4, 1, 91, 0, 0, 3, 77, 0,127, 0, 12,
+ 0, 4, 0, 17, 0, 4, 3, 78, 0, 4, 3, 79, 0, 4, 3, 80, 0, 4, 3, 81, 0, 4, 3, 82, 0, 4, 0, 66, 0, 4, 3, 83,
+ 0, 4, 3, 84, 0, 4, 3, 85, 0, 4, 3, 86, 0, 4, 3, 87, 0,128, 0, 4, 0, 4, 3, 88, 0, 7, 3, 89, 0, 2, 0, 19,
+ 0, 2, 3, 90, 0,129, 0, 9, 0,129, 0, 0, 0,129, 0, 1, 0, 0, 0, 16, 0, 53, 3, 91, 0, 55, 3, 92, 0, 4, 2,112,
+ 0, 4, 3, 93, 0, 4, 3, 94, 0, 4, 3, 95, 0,130, 0, 95, 0,125, 3, 96, 0,126, 3, 97, 0,127, 3, 98, 0, 4, 3, 99,
+ 0, 4, 0, 99, 0, 4, 2,199, 0, 4, 3,100, 0, 4, 3,101, 0, 2, 0, 19, 0, 2, 3,102, 0, 7, 2,129, 0, 7, 3,103,
+ 0, 7, 3,104, 0, 7, 3,105, 0, 7, 3,106, 0, 7, 3,107, 0, 2, 3,108, 0, 2, 3,109, 0, 2, 3,110, 0, 2, 3,111,
+ 0, 2, 0,178, 0, 2, 3,112, 0, 2, 3,113, 0, 2, 3,114, 0, 2, 3,115, 0, 2, 3,116, 0, 2, 0,242, 0, 2, 0, 77,
+ 0, 2, 3,117, 0, 2, 3,118, 0, 2, 3,119, 0, 2, 3,120, 0, 2, 3,121, 0, 2, 3,122, 0, 2, 3,123, 0, 2, 3,124,
+ 0, 2, 3,125, 0, 2, 3,126, 0, 2, 3,127, 0, 2, 0,243, 0, 2, 3,128, 0, 2, 3,129, 0, 4, 0,227, 0, 2, 3,130,
+ 0, 2, 3,131, 0, 2, 3,132, 0, 2, 3,133, 0, 2, 3,134, 0, 2, 3,135, 0, 2, 3,136, 0, 23, 3,137, 0, 23, 3,138,
+ 0, 22, 3,139, 0, 11, 3,140, 0, 2, 3,141, 0, 2, 0, 15, 0, 4, 1, 91, 0, 7, 3,142, 0, 7, 3,143, 0, 2, 3,144,
+ 0, 2, 3,145, 0, 2, 3,146, 0, 2, 3,147, 0, 2, 3,148, 0, 2, 3,149, 0, 2, 3,150, 0, 2, 3,151, 0, 2, 3,152,
+ 0, 2, 3,153, 0, 2, 3,154, 0, 2, 3,155, 0, 2, 3,156, 0, 2, 3,157, 0, 4, 3,158, 0, 4, 3,159, 0, 4, 3,160,
+ 0, 4, 3,161, 0, 4, 3,162, 0, 7, 3,163, 0, 4, 3,164, 0, 4, 3,165, 0, 4, 3,166, 0, 4, 3,167, 0, 7, 3,168,
+ 0, 7, 3,169, 0, 7, 3,170, 0, 7, 3,171, 0, 7, 3,172, 0, 7, 3,173, 0, 7, 3,174, 0, 7, 3,175, 0, 7, 3,176,
+ 0, 0, 3,177, 0, 0, 3,178, 0, 0, 3,179, 0,131, 0, 5, 0, 7, 3,180, 0, 0, 0, 17, 0, 0, 0, 80, 0, 0, 1, 91,
+ 0, 0, 1, 80, 0,132, 0, 5, 0,132, 0, 0, 0,132, 0, 1, 0, 4, 3,181, 0, 0, 3,182, 0, 4, 0, 19, 0,133, 0, 4,
+ 0,134, 3,183, 0, 2, 0, 19, 0, 2, 3,184, 0, 4, 1, 80, 0,135, 0, 26, 0, 2, 3,185, 0, 2, 3,186, 0, 7, 3,187,
+ 0, 7, 3,188, 0, 2, 3,189, 0, 2, 3,190, 0, 7, 3,191, 0, 7, 3,192, 0, 2, 3,193, 0, 2, 3,194, 0, 2, 3,195,
+ 0, 2, 3,196, 0, 7, 3,197, 0, 7, 3,198, 0, 2, 3,199, 0, 2, 3,200, 0, 2, 3,201, 0, 2, 1, 91, 0, 7, 3,202,
+ 0,133, 3,203, 0, 7, 3,204, 0, 0, 3,205, 0, 0, 3,206, 0, 0, 3,207, 0, 0, 1, 80, 0, 4, 2,163, 0,136, 0, 6,
+ 0, 2, 0, 77, 0, 0, 2, 40, 0, 0, 3,208, 0, 0, 3,209, 0, 0, 3,210, 0, 0, 1,250, 0,137, 0, 20, 0,138, 3,211,
+ 0, 42, 1, 11, 0,136, 3,212, 0,136, 3,213, 0,136, 3,214, 0,136, 3,215, 0,136, 3,216, 0,136, 3,217, 0, 2, 3,218,
+ 0, 2, 0,253, 0, 2, 3,219, 0, 2, 1,168, 0, 0, 3,220, 0, 0, 3,221, 0, 0, 3,222, 0, 0, 3,223, 0, 0, 3,224,
+ 0, 0, 3,225, 0, 0, 3,226, 0, 0, 3,227, 0,139, 0, 37, 0, 26, 0, 30, 0, 43, 3,228, 0,122, 3,229, 0,139, 3,230,
+ 0, 39, 0,170, 0, 11, 3,231, 0,124, 3,232, 0, 7, 3,233, 0, 7, 3,234, 0, 7, 3,235, 0, 7, 3,236, 0, 4, 2,112,
+ 0, 7, 3,237, 0, 2, 3,238, 0, 2, 3,239, 0, 2, 3,240, 0, 2, 1, 61, 0, 54, 1, 83, 0, 9, 3,241, 0,123, 3,242,
+ 0, 9, 1,214, 0,131, 3,243, 0,135, 3,244, 0,130, 0,144, 0,128, 3,245, 0, 32, 0, 93, 0, 11, 3,246, 0, 2, 3,247,
+ 0, 2, 0, 80, 0, 2, 1, 91, 0, 2, 1, 80, 0,140, 3,248, 0, 2, 3,249, 0, 2, 3,250, 0, 2, 2,163, 0, 2, 0,179,
+ 0,137, 3,251, 0,141, 0, 9, 0, 39, 0,170, 0, 38, 0,217, 0, 7, 1,175, 0, 7, 1,176, 0, 7, 0, 77, 0, 7, 3,252,
+ 0, 7, 3,253, 0, 2, 3,254, 0, 2, 3,255, 0,142, 0, 68, 0,143, 0, 0, 0,143, 0, 1, 0, 4, 4, 0, 0, 7, 4, 1,
+ 0,144, 4, 2, 0, 2, 4, 3, 0, 7, 4, 4, 0, 7, 4, 5, 0, 7, 4, 6, 0, 7, 4, 7, 0, 7, 4, 8, 0, 7, 4, 9,
+ 0, 7, 4, 10, 0, 7, 0,230, 0, 7, 4, 11, 0, 7, 4, 12, 0, 2, 4, 13, 0, 2, 3,210, 0, 43, 3,228, 0, 43, 4, 14,
+ 0,141, 4, 15, 0,142, 4, 16, 0,145, 4, 17, 0,146, 4, 18, 0,147, 4, 19, 0, 0, 4, 20, 0, 2, 3, 46, 0, 2, 4, 21,
+ 0, 4, 2,112, 0, 4, 4, 22, 0, 2, 4, 23, 0, 2, 4, 24, 0, 2, 4, 25, 0, 0, 4, 26, 0, 0, 0, 80, 0, 7, 0, 83,
+ 0, 7, 4, 27, 0, 7, 4, 28, 0, 7, 4, 29, 0, 7, 4, 30, 0, 7, 4, 31, 0, 7, 4, 32, 0, 7, 4, 33, 0, 7, 0,140,
+ 0, 7, 3,233, 0, 2, 4, 34, 0, 2, 4, 35, 0, 2, 4, 36, 0, 2, 4, 37, 0, 2, 0,106, 0, 2, 3,219, 0, 2, 4, 38,
+ 0, 2, 4, 39, 0, 2, 4, 40, 0, 2, 4, 41, 0, 7, 4, 42, 0, 7, 4, 43, 0, 59, 4, 44, 0, 11, 4, 45, 0, 2, 4, 46,
+ 0, 2, 1,231, 0, 2, 4, 47, 0, 2, 0, 19, 0, 2, 4, 48, 0, 2, 4, 49, 0, 2, 4, 50, 0, 2, 1, 91, 0, 9, 4, 51,
+ 0,148, 0, 16, 0, 23, 0, 35, 0, 23, 0, 38, 0, 22, 4, 52, 0, 22, 4, 53, 0, 22, 4, 54, 0, 7, 4, 55, 0, 7, 4, 56,
+ 0, 7, 4, 57, 0, 7, 4, 58, 0, 2, 4, 59, 0, 2, 4, 60, 0, 2, 4, 61, 0, 2, 4, 62, 0, 2, 4, 63, 0, 2, 4, 64,
+ 0, 4, 0, 19, 0,143, 0, 6, 0,143, 0, 0, 0,143, 0, 1, 0, 4, 4, 0, 0, 7, 4, 1, 0,144, 4, 2, 0, 2, 4, 3,
+ 0,149, 0, 6, 0,143, 0, 0, 0,143, 0, 1, 0, 4, 4, 0, 0, 7, 4, 1, 0,144, 4, 2, 0, 2, 4, 3, 0,150, 0, 26,
+ 0,143, 0, 0, 0,143, 0, 1, 0, 4, 4, 0, 0, 7, 4, 1, 0,144, 4, 2, 0, 2, 4, 3, 0, 4, 4, 65, 0, 4, 1, 91,
+ 0,148, 4, 66, 0, 9, 4, 67, 0, 11, 4, 68, 0, 29, 0, 54, 0, 26, 0, 55, 0, 0, 4, 69, 0, 0, 4, 70, 0, 2, 4, 71,
+ 0, 2, 4, 72, 0, 2, 4, 73, 0, 2, 4, 74, 0, 2, 0, 40, 0, 2, 0, 39, 0, 2, 0,106, 0, 2, 4, 75, 0, 4, 0, 19,
+ 0, 7, 4, 76, 0, 23, 0, 35, 0,151, 0, 29, 0,143, 0, 0, 0,143, 0, 1, 0, 4, 4, 0, 0, 7, 4, 1, 0,144, 4, 2,
+ 0,145, 4, 17, 0, 2, 4, 3, 0, 2, 4, 77, 0, 2, 4, 78, 0, 2, 4, 79, 0, 2, 4, 80, 0,148, 4, 66, 0, 2, 4, 81,
+ 0, 2, 0,106, 0, 2, 4, 72, 0, 2, 4, 82, 0, 9, 4, 83, 0, 2, 3,219, 0, 0, 4, 84, 0, 0, 4, 85, 0, 2, 4, 86,
+ 0, 2, 4, 87, 0, 2, 2,121, 0, 2, 4, 88, 0, 2, 4, 89, 0, 0, 0, 15, 0, 0, 0, 19, 0, 0, 0,253, 0, 0, 4, 90,
+ 0,152, 0, 15, 0,143, 0, 0, 0,143, 0, 1, 0, 4, 4, 0, 0, 7, 4, 1, 0,144, 4, 2, 0, 2, 4, 3, 0,148, 4, 66,
+ 0, 7, 1,175, 0, 7, 1,176, 0, 2, 4, 81, 0, 2, 3,252, 0, 2, 4, 91, 0, 2, 1, 91, 0, 4, 0, 19, 0, 4, 0, 15,
+ 0,153, 0, 29, 0,143, 0, 0, 0,143, 0, 1, 0, 4, 4, 0, 0, 7, 4, 1, 0,144, 4, 2, 0, 2, 4, 3, 0,154, 4, 92,
+ 0, 4, 4, 93, 0, 0, 4, 94, 0, 0, 4, 95, 0, 0, 4, 96, 0, 2, 0, 17, 0, 2, 4, 97, 0, 2, 0, 19, 0, 2, 4, 98,
+ 0, 2, 4, 99, 0, 2, 4,100, 0,155, 4,101, 0, 2, 4,102, 0, 2, 4,103, 0, 2, 4,104, 0, 2, 0,169, 0, 9, 4,105,
+ 0, 9, 4,106, 0, 9, 4,107, 0, 9, 4,108, 0, 9, 4,109, 0, 2, 4,110, 0, 0, 4,111, 0,156, 0, 23, 0,143, 0, 0,
+ 0,143, 0, 1, 0, 4, 4, 0, 0, 7, 4, 1, 0,144, 4, 2, 0, 2, 4, 3, 0,148, 4, 66, 0, 11, 4,112, 0, 2, 4, 72,
+ 0, 2, 4,113, 0, 2, 0, 19, 0, 2, 1,199, 0, 9, 4, 83, 0, 11, 4,114, 0,157, 4,115, 0, 0, 4,116, 0,158, 4,117,
+ 0, 4, 4,118, 0, 4, 4,119, 0, 2, 0, 17, 0, 2, 4,120, 0, 2, 4,121, 0, 2, 4,122, 0,159, 0, 27, 0,143, 0, 0,
+ 0,143, 0, 1, 0, 4, 4, 0, 0, 7, 4, 1, 0,144, 4, 2, 0, 2, 4, 3, 0,148, 4, 66, 0, 39, 2, 47, 0, 38, 0,217,
+ 0,160, 4,123, 0, 2, 0,227, 0, 2, 0,106, 0, 2, 4,124, 0, 2, 4,125, 0, 4, 0, 19, 0, 2, 4,126, 0, 2, 4, 75,
+ 0, 2, 4,127, 0, 2, 1, 91, 0, 7, 3,252, 0, 7, 1,175, 0, 7, 1,176, 0, 7, 4,128, 0, 7, 4,129, 0, 0, 4,130,
+ 0, 0, 4,131, 0, 49, 4,132, 0,161, 0, 10, 0,143, 0, 0, 0,143, 0, 1, 0, 4, 4, 0, 0, 7, 4, 1, 0,144, 4, 2,
+ 0, 2, 4, 3, 0, 2, 0,106, 0, 2, 4, 75, 0, 4, 0, 15, 0,148, 4, 66, 0,162, 0, 22, 0,143, 0, 0, 0,143, 0, 1,
+ 0, 4, 4, 0, 0, 7, 4, 1, 0,144, 4, 2, 0, 2, 4, 3, 0, 34, 4,133, 0, 4, 4,134, 0, 4, 4,135, 0, 2, 0, 66,
+ 0, 2, 0,106, 0, 4, 4,136, 0, 4, 4,137, 0, 4, 4,138, 0, 4, 4,139, 0, 4, 4,140, 0, 4, 4,141, 0, 4, 4,142,
+ 0, 4, 4,143, 0, 7, 4,144, 0, 22, 4,145, 0, 22, 4,146, 0,163, 0, 9, 0,143, 0, 0, 0,143, 0, 1, 0, 4, 4, 0,
+ 0, 7, 4, 1, 0,144, 4, 2, 0,164, 4,147, 0, 4, 1, 91, 0, 2, 0, 66, 0, 2, 0,106, 0,165, 0, 8, 0,143, 0, 0,
+ 0,143, 0, 1, 0, 4, 4, 0, 0, 7, 4, 1, 0,144, 4, 2, 0,148, 4, 66, 0, 4, 0, 19, 0, 4, 4,148, 0,166, 0, 18,
+ 0,143, 0, 0, 0,143, 0, 1, 0, 4, 4, 0, 0, 7, 4, 1, 0,144, 4, 2, 0,148, 4, 66, 0, 26, 4,149, 0, 26, 0, 55,
+ 0, 2, 0, 19, 0, 2, 0,106, 0, 7, 4,150, 0, 9, 4,151, 0, 7, 1,175, 0, 7, 1,176, 0, 54, 1, 83, 0, 54, 4,152,
+ 0, 4, 4,153, 0, 4, 0, 15, 0,167, 0, 81, 0,143, 0, 0, 0,143, 0, 1, 0, 4, 4, 0, 0, 7, 4, 1, 0,144, 4, 2,
+ 0, 0, 4,154, 0, 4, 4,155, 0, 2, 0,227, 0, 2, 4,156, 0, 2, 4,157, 0, 2, 4,158, 0, 2, 4,159, 0, 2, 4,160,
+ 0, 2, 4,161, 0, 2, 4,162, 0, 2, 4,163, 0, 2, 4,164, 0, 2, 4,165, 0, 2, 4,166, 0, 2, 4,167, 0, 2, 4,168,
+ 0, 2, 4,169, 0, 2, 4,170, 0, 2, 4,171, 0, 2, 4,172, 0, 2, 4,173, 0, 2, 4,174, 0, 2, 4,175, 0, 2, 4,176,
+ 0, 2, 4,177, 0, 2, 4,178, 0, 2, 4,179, 0, 2, 4,180, 0, 2, 4,181, 0, 2, 4,182, 0, 2, 4,183, 0, 2, 4,184,
+ 0, 2, 4,185, 0, 2, 4,186, 0, 2, 4,187, 0, 2, 4,188, 0, 2, 4,189, 0, 2, 4,190, 0, 2, 4,191, 0, 2, 4,192,
+ 0, 2, 4,193, 0, 2, 4,194, 0, 2, 4,195, 0, 2, 4,196, 0, 2, 4,197, 0, 2, 4,198, 0, 2, 4,199, 0, 2, 4,200,
+ 0, 2, 4,201, 0, 2, 4,202, 0, 0, 4,203, 0, 0, 4,204, 0, 0, 4,205, 0, 0, 4,206, 0,168, 4,207, 0,168, 4,208,
+ 0, 4, 4,209, 0, 4, 4,210, 0, 4, 4,211, 0, 4, 4,212, 0, 4, 4,213, 0, 7, 4,214, 0, 7, 4,215, 0, 7, 4,216,
+ 0, 2, 4,217, 0, 2, 4,218, 0, 2, 4,219, 0, 2, 4,220, 0,169, 4,221, 0,169, 4,222, 0, 2, 4,223, 0, 2, 4,224,
+ 0, 4, 1, 91, 0, 49, 4,225, 0, 9, 4,105, 0, 9, 4,108, 0,170, 0, 20, 0, 0, 4,226, 0, 0, 4,227, 0, 0, 4,228,
+ 0, 0, 4,229, 0, 0, 4,230, 0, 0, 4,231, 0, 0, 4,232, 0, 0, 4,233, 0, 0, 4,234, 0, 0, 4,235, 0, 0, 4,236,
+ 0, 0, 4,237, 0, 0, 4,238, 0, 0, 4,239, 0, 0, 4,240, 0, 0, 4,241, 0, 0, 4,242, 0, 0, 4,243, 0, 0, 3, 90,
+ 0, 0, 4,244, 0,171, 0, 48, 0, 0, 4,245, 0, 0, 4,236, 0, 0, 4,237, 0, 0, 4,246, 0, 0, 4,247, 0, 0, 4,248,
+ 0, 0, 4,249, 0, 0, 4,250, 0, 0, 4,251, 0, 0, 4,252, 0, 0, 4,253, 0, 0, 4,254, 0, 0, 4,255, 0, 0, 5, 0,
+ 0, 0, 5, 1, 0, 0, 5, 2, 0, 0, 5, 3, 0, 0, 5, 4, 0, 0, 5, 5, 0, 0, 5, 6, 0, 0, 5, 7, 0, 0, 5, 8,
+ 0, 0, 5, 9, 0, 0, 5, 10, 0, 0, 5, 11, 0, 0, 5, 12, 0, 0, 5, 13, 0, 0, 5, 14, 0, 0, 5, 15, 0, 0, 5, 16,
+ 0, 0, 5, 17, 0, 0, 5, 18, 0, 0, 5, 19, 0, 0, 5, 20, 0, 0, 5, 21, 0, 0, 5, 22, 0, 0, 5, 23, 0, 0, 5, 24,
+ 0, 0, 5, 25, 0, 0, 5, 26, 0, 0, 5, 27, 0, 0, 5, 28, 0, 0, 5, 29, 0, 0, 5, 30, 0, 0, 5, 31, 0, 0, 5, 32,
+ 0, 0, 5, 33, 0, 0, 5, 34, 0,172, 0, 21, 0,172, 0, 0, 0,172, 0, 1, 0, 0, 0, 16, 0,170, 5, 35, 0,171, 5, 36,
+ 0,171, 5, 37, 0,171, 5, 38, 0,171, 5, 39, 0,171, 5, 40, 0,171, 5, 41, 0,171, 5, 42, 0,171, 5, 43, 0,171, 5, 44,
+ 0,171, 5, 45, 0,171, 5, 46, 0,171, 5, 47, 0,171, 5, 48, 0,171, 5, 49, 0,171, 5, 50, 0, 0, 5, 51, 0, 0, 5, 34,
+ 0,173, 0, 5, 0, 4, 0, 19, 0, 4, 0, 15, 0, 7, 1,230, 0, 7, 5, 52, 0, 7, 1,137, 0,174, 0, 50, 0, 4, 0, 19,
+ 0, 4, 5, 53, 0, 4, 5, 54, 0, 0, 5, 55, 0, 0, 5, 56, 0, 0, 5, 57, 0, 0, 5, 58, 0, 0, 5, 59, 0, 0, 5, 60,
+ 0, 0, 5, 61, 0, 0, 5, 62, 0, 0, 5, 63, 0, 2, 5, 64, 0, 2, 5, 65, 0, 4, 5, 66, 0, 4, 5, 67, 0, 4, 5, 68,
+ 0, 4, 5, 69, 0, 2, 5, 70, 0, 2, 5, 71, 0, 2, 5, 72, 0, 2, 5, 73, 0, 4, 5, 74, 0, 4, 5, 75, 0, 2, 5, 76,
+ 0, 2, 5, 77, 0, 2, 5, 78, 0, 2, 5, 79, 0, 0, 5, 80, 0, 11, 5, 81, 0, 2, 5, 82, 0, 2, 5, 83, 0, 2, 5, 84,
+ 0, 2, 5, 85, 0,173, 5, 86, 0, 2, 5, 87, 0, 2, 5, 88, 0, 2, 5, 89, 0, 2, 5, 90, 0, 4, 5, 91, 0, 4, 5, 92,
+ 0, 4, 5, 93, 0, 2, 5, 94, 0, 2, 5, 95, 0, 2, 5, 96, 0, 2, 5, 97, 0, 2, 5, 98, 0, 0, 5, 99, 0, 0, 5,100,
+ 0, 2, 0, 15, 0,175, 0, 18, 0, 26, 0, 30, 0, 11, 5,101, 0, 11, 5,102, 0, 11, 5,103, 0,139, 5,104, 0, 2, 2, 54,
+ 0, 2, 5,105, 0, 2, 2, 55, 0, 2, 5,106, 0, 2, 5,107, 0, 2, 5,108, 0, 2, 5,109, 0, 2, 5,110, 0, 2, 5,111,
+ 0, 2, 0, 15, 0, 2, 5,112, 0, 2, 5,113, 0, 2, 5,114, 0,176, 0, 5, 0,176, 0, 0, 0,176, 0, 1, 0,176, 5,115,
+ 0, 12, 5,116, 0, 4, 0, 19, 0,177, 0, 7, 0,177, 0, 0, 0,177, 0, 1, 0,176, 5,117, 0,176, 5,118, 0, 2, 3,138,
+ 0, 2, 0, 19, 0, 4, 0, 15, 0,178, 0, 17, 0,178, 0, 0, 0,178, 0, 1, 0, 0, 5,119, 0, 0, 5,120, 0, 0, 5,121,
+ 0, 2, 5,122, 0, 2, 5,123, 0, 2, 5,107, 0, 2, 5,108, 0, 2, 0, 19, 0, 2, 2,169, 0, 2, 5,124, 0, 2, 5,125,
+ 0, 2, 5,126, 0, 2, 5,127, 0, 4, 5,128, 0,178, 5,129, 0,144, 0, 30, 0,144, 0, 0, 0,144, 0, 1, 0,176, 5,117,
+ 0,176, 5,118, 0,176, 5,130, 0,176, 5,131, 0,175, 5,132, 0, 7, 5,133, 0, 22, 1,194, 0, 22, 5,134, 0, 22, 5,135,
+ 0, 2, 5,136, 0, 2, 5,137, 0, 2, 5,138, 0, 0, 4, 0, 0, 0, 5,139, 0, 2, 5,140, 0, 2, 5,141, 0, 0, 5,142,
+ 0, 0, 5,143, 0, 0, 5,144, 0, 0, 5,145, 0, 2, 5,146, 0, 2, 5,147, 0, 2, 5,148, 0, 2, 0, 19, 0, 32, 0, 93,
+ 0, 11, 5,149, 0, 11, 5,150, 0, 11, 5,151, 0,179, 0, 11, 0, 0, 5,152, 0, 2, 5,153, 0, 2, 5,154, 0, 2, 5,155,
+ 0, 2, 5,156, 0, 2, 5,157, 0, 2, 3,124, 0, 9, 5,158, 0, 9, 5,159, 0, 4, 5,160, 0, 4, 5,161, 0,180, 0, 8,
+ 0, 0, 5,162, 0, 49, 5,163, 0,180, 5,164, 0,180, 5,165, 0,180, 5,166, 0, 2, 0,102, 0, 2, 0, 15, 0, 4, 5,167,
+ 0,181, 0, 10, 0,181, 0, 0, 0,181, 0, 1, 0, 4, 1,199, 0, 4, 0, 21, 0, 4, 0, 27, 0, 4, 5,168, 0,180, 5,169,
+ 0, 0, 4, 95, 0, 4, 5,170, 0, 4, 5,171, 0,182, 0, 12, 0, 0, 1,100, 0, 9, 0,155, 0, 0, 0,156, 0, 4, 0,159,
+ 0, 4, 0,167, 0, 9, 0,160, 0, 7, 0,162, 0, 7, 0,163, 0, 9, 5,172, 0, 9, 5,173, 0, 9, 0,164, 0, 9, 0,166,
+ 0,183, 0, 41, 0,183, 0, 0, 0,183, 0, 1, 0,183, 5,174, 0, 9, 0, 25, 0, 0, 0, 26, 0, 2, 0, 19, 0, 2, 0, 17,
+ 0, 4, 0, 21, 0, 4, 2, 24, 0, 4, 5,175, 0, 4, 5,176, 0, 4, 5,177, 0, 4, 5,178, 0, 4, 5,179, 0, 4, 0,178,
+ 0, 4, 5,180, 0, 4, 5,181, 0, 7, 5,182, 0, 7, 5,183, 0, 4, 0, 99, 0,181, 5,184, 0,180, 5,185, 0, 29, 0, 54,
+ 0,139, 5,104, 0, 40, 0,108, 0, 7, 5,186, 0, 7, 5,187, 0,182, 0,218, 0,183, 5,188, 0,183, 5,189, 0,183, 5,190,
+ 0, 11, 5,191, 0,184, 5,192, 0,185, 5,193, 0, 7, 5,194, 0, 7, 5,195, 0, 4, 5,196, 0, 7, 5,197, 0, 9, 5,198,
+ 0, 4, 5,199, 0, 4, 0, 15, 0,186, 0, 4, 0,186, 0, 0, 0,186, 0, 1, 0, 11, 5,200, 0,183, 5,201, 0,187, 0, 6,
+ 0, 11, 5,202, 0, 11, 5,191, 0, 11, 5,203, 0, 2, 0, 19, 0, 2, 0, 15, 0, 4, 1,199, 0,188, 0, 4, 0, 7, 5,204,
+ 0, 7, 5,205, 0, 2, 5,206, 0, 2, 5,207, 0,189, 0, 6, 0, 7, 5,208, 0, 7, 5,209, 0, 7, 5,210, 0, 7, 5,211,
+ 0, 4, 5,212, 0, 4, 5,213, 0,190, 0, 10, 0, 7, 5,214, 0, 7, 5,215, 0, 7, 5,216, 0, 7, 5,217, 0, 7, 5,218,
+ 0, 7, 5,219, 0, 7, 5,220, 0, 7, 5,221, 0, 7, 5,222, 0, 7, 5,223, 0,191, 0, 2, 0, 7, 3,180, 0, 7, 0, 15,
+ 0,192, 0, 5, 0, 7, 5,224, 0, 7, 5,225, 0, 4, 0, 66, 0, 4, 2, 25, 0, 4, 0, 15, 0,193, 0, 6, 0,193, 0, 0,
+ 0,193, 0, 1, 0, 2, 0, 17, 0, 2, 0, 19, 0, 2, 5,226, 0, 2, 1,199, 0,194, 0, 8, 0,194, 0, 0, 0,194, 0, 1,
+ 0, 2, 0, 17, 0, 2, 0, 19, 0, 2, 5,226, 0, 2, 1,199, 0, 7, 0, 21, 0, 7, 0, 99, 0,195, 0, 45, 0,195, 0, 0,
+ 0,195, 0, 1, 0, 2, 0, 17, 0, 2, 0, 19, 0, 2, 5,226, 0, 2, 0,174, 0, 2, 2,195, 0, 2, 5,227, 0, 7, 5,228,
+ 0, 7, 5,229, 0, 7, 2, 61, 0, 4, 5,230, 0, 4, 0, 56, 0, 4, 2, 27, 0, 7, 5,231, 0, 7, 5,232, 0, 7, 5,233,
+ 0, 7, 5,234, 0, 7, 5,235, 0, 7, 5,236, 0, 7, 2, 59, 0, 7, 0,216, 0, 7, 5,237, 0, 7, 5,238, 0, 7, 0, 15,
+ 0, 7, 5,239, 0, 7, 5,240, 0, 7, 5,241, 0, 2, 5,242, 0, 2, 5,243, 0, 2, 5,244, 0, 2, 5,245, 0, 2, 5,246,
+ 0, 2, 5,247, 0, 2, 5,248, 0, 2, 5,249, 0, 2, 4, 48, 0, 2, 5,250, 0, 2, 1,121, 0, 2, 5,251, 0, 0, 5,252,
+ 0, 0, 5,253, 0, 7, 0,172, 0,196, 5,254, 0, 55, 1, 84, 0,197, 0, 16, 0,197, 0, 0, 0,197, 0, 1, 0, 2, 0, 17,
+ 0, 2, 0, 19, 0, 2, 5,226, 0, 2, 0,174, 0, 7, 2, 54, 0, 7, 2, 55, 0, 7, 2, 56, 0, 7, 1,162, 0, 7, 2, 57,
+ 0, 7, 2, 58, 0, 7, 5,255, 0, 7, 2, 59, 0, 7, 2, 60, 0, 7, 2, 61, 0,158, 0, 5, 0, 2, 0, 17, 0, 2, 5,167,
+ 0, 2, 0, 19, 0, 2, 6, 0, 0, 26, 4,149, 0,157, 0, 3, 0, 4, 0, 44, 0, 4, 6, 1, 0,158, 0, 45, 0,198, 0, 12,
+ 0,198, 0, 0, 0,198, 0, 1, 0, 2, 0, 17, 0, 2, 0, 19, 0, 2, 2,137, 0, 2, 1,136, 0, 7, 0, 4, 0, 7, 0, 5,
+ 0, 7, 6, 2, 0, 7, 6, 3, 0, 26, 4,149, 0, 11, 6, 4, 0,199, 0, 11, 0,199, 0, 0, 0,199, 0, 1, 0, 0, 0, 16,
+ 0, 2, 0, 17, 0, 2, 6, 5, 0, 4, 0, 20, 0, 4, 6, 6, 0, 2, 0, 19, 0, 2, 0, 15, 0, 9, 6, 7, 0, 9, 6, 8,
+ 0,200, 0, 5, 0, 0, 0, 16, 0, 7, 0,230, 0, 7, 6, 9, 0, 4, 6, 10, 0, 4, 0, 15, 0,201, 0, 4, 0, 2, 0, 17,
+ 0, 2, 0, 19, 0, 2, 0, 80, 0, 2, 1, 91, 0,202, 0, 4, 0, 0, 0, 16, 0, 53, 6, 11, 0, 7, 0,230, 0, 7, 0, 15,
+ 0,203, 0, 6, 0, 2, 6, 12, 0, 2, 6, 13, 0, 2, 0, 17, 0, 2, 6, 14, 0, 0, 6, 15, 0, 0, 6, 16, 0,204, 0, 5,
+ 0, 4, 0, 17, 0, 4, 0, 15, 0, 0, 0, 16, 0, 0, 6, 17, 0, 0, 6, 18, 0,205, 0, 6, 0, 0, 0, 16, 0, 0, 6, 19,
+ 0, 2, 6, 20, 0, 2, 2, 59, 0, 2, 0,227, 0, 2, 1, 91, 0,206, 0, 5, 0, 0, 0, 16, 0, 7, 5,205, 0, 7, 3, 11,
+ 0, 2, 0, 19, 0, 2, 2, 36, 0,207, 0, 3, 0, 0, 0, 16, 0, 4, 2, 27, 0, 4, 6, 21, 0,208, 0, 7, 0, 0, 0, 16,
+ 0, 7, 3, 11, 0, 0, 6, 22, 0, 0, 6, 23, 0, 2, 0,227, 0, 2, 0, 80, 0, 4, 6, 24, 0,209, 0, 3, 0, 43, 6, 25,
+ 0, 0, 6, 26, 0, 0, 6, 27, 0,210, 0, 17, 0,210, 0, 0, 0,210, 0, 1, 0, 2, 0, 17, 0, 2, 6, 5, 0, 2, 0, 19,
+ 0, 2, 6, 28, 0, 2, 6, 29, 0, 2, 6, 30, 0, 2, 0, 80, 0, 2, 1, 91, 0, 0, 0, 16, 0, 9, 0, 45, 0,211, 6, 31,
+ 0, 43, 0,226, 0, 2, 6, 32, 0, 2, 6, 33, 0, 4, 0, 15, 0,212, 0, 10, 0, 0, 0, 16, 0, 2, 0, 17, 0, 2, 0, 15,
+ 0, 4, 2, 36, 0, 4, 6, 34, 0, 4, 6, 35, 0, 4, 6, 36, 0, 4, 6, 37, 0, 4, 6, 38, 0, 4, 6, 39, 0,213, 0, 1,
+ 0, 0, 6, 40, 0,214, 0, 1, 0, 34, 4,133, 0,211, 0, 18, 0,211, 0, 0, 0,211, 0, 1, 0,211, 6, 41, 0, 2, 0, 17,
+ 0, 2, 0, 19, 0, 2, 6, 42, 0, 2, 6, 30, 0, 2, 6, 5, 0, 2, 6, 43, 0, 2, 1, 91, 0, 2, 1, 80, 0, 0, 0, 16,
+ 0, 9, 0, 45, 0,215, 6, 31, 0,210, 6, 44, 0, 2, 0, 14, 0, 2, 6, 45, 0, 4, 2,214, 0,216, 0, 3, 0, 4, 6, 46,
+ 0, 4, 0, 15, 0, 43, 0,226, 0,217, 0, 10, 0,111, 6, 47, 0, 2, 0, 17, 0, 2, 0, 19, 0, 4, 5,228, 0, 4, 5,229,
+ 0, 0, 0, 16, 0, 4, 6, 48, 0, 2, 6, 49, 0, 2, 6, 50, 0, 7, 6, 51, 0,218, 0, 10, 0, 2, 0, 19, 0, 2, 6, 52,
+ 0, 4, 5,228, 0, 4, 5,229, 0, 2, 6, 53, 0,184, 5,192, 0, 2, 0, 17, 0, 2, 6, 54, 0, 2, 6, 55, 0, 2, 6, 56,
+ 0,219, 0, 7, 0, 2, 0, 19, 0, 2, 6, 52, 0, 4, 5,228, 0, 4, 5,229, 0, 2, 0, 17, 0, 2, 6, 57, 0, 7, 6, 58,
+ 0,220, 0, 9, 0, 4, 6, 46, 0, 2, 0, 17, 0, 2, 0, 19, 0, 43, 0,226, 0, 70, 6, 59, 0, 0, 0, 16, 0, 7, 6, 60,
+ 0, 2, 6, 61, 0, 2, 0, 15, 0,221, 0, 5, 0, 2, 0, 17, 0, 2, 0, 19, 0, 4, 0, 15, 0,139, 5,104, 0, 43, 3,228,
+ 0,222, 0, 5, 0, 4, 0, 19, 0, 4, 0, 17, 0, 0, 0, 16, 0, 0, 6, 17, 0, 43, 0,226, 0,223, 0, 10, 0, 4, 0, 19,
+ 0, 4, 0, 17, 0, 7, 6, 62, 0, 7, 6, 63, 0, 7, 0,221, 0, 7, 0,222, 0, 7, 2,106, 0, 7, 2,109, 0, 7, 6, 64,
+ 0, 7, 6, 65, 0,224, 0, 9, 0, 2, 0, 19, 0, 2, 0, 17, 0, 4, 5,228, 0, 4, 5,229, 0, 0, 0, 16, 0, 2, 0, 80,
+ 0, 2, 0, 38, 0, 2, 6, 66, 0, 2, 6, 67, 0,225, 0, 8, 0, 43, 0,226, 0, 7, 2, 56, 0, 7, 6, 68, 0, 7, 2, 88,
+ 0, 7, 6, 69, 0, 2, 0, 19, 0, 2, 2, 36, 0, 7, 6, 70, 0,226, 0, 7, 0, 2, 0, 19, 0, 2, 2, 59, 0, 7, 6, 71,
+ 0, 7, 6, 72, 0, 7, 6, 73, 0, 7, 6, 74, 0, 7, 6, 75, 0,227, 0, 10, 0, 2, 0, 19, 0, 2, 0, 17, 0, 4, 5,228,
+ 0, 4, 5,229, 0, 0, 0, 16, 0, 2, 3, 90, 0, 2, 0, 38, 0, 2, 6, 66, 0, 2, 6, 67, 0, 55, 1, 84, 0,228, 0, 7,
+ 0, 4, 2, 27, 0, 4, 6, 76, 0, 4, 6, 77, 0, 4, 6, 78, 0, 7, 6, 79, 0, 7, 6, 80, 0, 0, 6, 22, 0,229, 0, 7,
+ 0, 0, 6, 81, 0, 43, 6, 82, 0, 0, 6, 26, 0, 2, 6, 83, 0, 2, 0, 80, 0, 4, 1, 91, 0, 0, 6, 27, 0,230, 0, 6,
+ 0, 2, 0, 19, 0, 2, 0, 17, 0, 4, 5,228, 0, 4, 5,229, 0, 0, 6, 84, 0, 0, 6, 85, 0,231, 0, 1, 0, 4, 0, 19,
+ 0,215, 0, 10, 0,215, 0, 0, 0,215, 0, 1, 0,215, 6, 41, 0, 2, 0, 17, 0, 2, 0, 19, 0, 2, 6, 5, 0, 2, 6, 86,
+ 0, 0, 0, 16, 0, 9, 0, 45, 0, 43, 0,226, 0,232, 0, 10, 0, 7, 2,130, 0, 7, 6, 87, 0, 7, 6, 88, 0, 7, 6, 89,
+ 0, 7, 6, 90, 0, 4, 0, 19, 0, 7, 6, 91, 0, 7, 6, 92, 0, 7, 6, 93, 0, 7, 0, 15, 0,184, 0, 20, 0, 26, 0, 30,
+ 0, 0, 0,154, 0,233, 6, 94, 0, 9, 6, 95, 0, 35, 0,120, 0, 35, 6, 96, 0, 9, 6, 97, 0, 29, 0, 54, 0, 7, 6, 58,
+ 0, 7, 6, 98, 0, 7, 6, 99, 0, 7, 6,100, 0, 7, 6,101, 0, 7, 6,102, 0, 7, 6,103, 0, 4, 0, 66, 0, 4, 6,104,
+ 0, 0, 6,105, 0, 0, 6,106, 0, 0, 6,107, 0,234, 0, 6, 0, 26, 0, 30, 0, 7, 6,108, 0, 7, 6,109, 0, 7, 6,110,
+ 0, 2, 6,111, 0, 2, 6,112, 0,235, 0, 14, 0,143, 0, 0, 0,143, 0, 1, 0, 4, 4, 0, 0, 7, 4, 1, 0,144, 4, 2,
+ 0,148, 4, 66, 0,184, 5,192, 0, 2, 0,227, 0, 2, 6, 52, 0, 2, 1,175, 0, 2, 1,176, 0, 2, 0, 19, 0, 2, 4, 75,
+ 0, 4, 1, 91, 0,236, 0, 6, 0,236, 0, 0, 0,236, 0, 1, 0, 43, 0,226, 0, 9, 6,113, 0, 4, 0,179, 0, 4, 0, 15,
+ 0, 55, 0, 4, 0, 26, 0, 30, 0, 11, 6,114, 0, 4, 0,104, 0, 4, 0, 15, 0,237, 0, 25, 0,237, 0, 0, 0,237, 0, 1,
+ 0,237, 0, 36, 0, 11, 6,115, 0, 0, 0, 16, 0, 7, 6,116, 0, 7, 6,117, 0, 7, 6,118, 0, 7, 6,119, 0, 4, 0, 19,
+ 0, 7, 6,120, 0, 7, 6,121, 0, 7, 6,122, 0, 7, 0,230, 0, 7, 1,129, 0, 7, 6,123, 0, 7, 2, 25, 0, 7, 6,124,
+ 0, 7, 6,125, 0, 7, 6,126, 0, 7, 6,127, 0, 7, 6,128, 0, 7, 0,141, 0, 2, 0,104, 0, 2, 3,193, 0,238, 0, 17,
+ 0, 26, 0, 30, 0, 11, 6,129, 0, 11, 6,130, 0, 4, 0, 19, 0, 4, 3, 46, 0, 2, 2, 62, 0, 2, 6,131, 0, 2, 0,104,
+ 0, 2, 6,132, 0, 2, 6,133, 0, 2, 6,134, 0, 2, 6,135, 0, 2, 6,136, 0, 4, 6,137, 0, 4, 6,138, 0, 4, 6,139,
+ 0, 4, 6,140, 0,239, 0, 31, 0,239, 0, 0, 0,239, 0, 1, 0, 11, 2,153, 0, 0, 0, 16, 0, 2, 0, 19, 0, 2, 6,141,
+ 0, 2, 6,142, 0, 2, 6,143, 0, 2, 2,119, 0, 2, 1, 91, 0, 4, 1,160, 0, 4, 6,139, 0, 4, 6,140, 0,237, 6,144,
+ 0,239, 0, 36, 0,239, 6,145, 0, 11, 6,146, 0, 9, 6,147, 0, 7, 0,221, 0, 7, 0,141, 0, 7, 1,111, 0, 7, 6,148,
+ 0, 7, 6,149, 0, 7, 6,150, 0, 7, 6,151, 0, 7, 6,152, 0, 7, 6,153, 0, 7, 6,154, 0, 7, 6,155, 0, 7, 1,157,
+ 0, 43, 6,156, 0,112, 0, 6, 0, 11, 6,157, 0, 2, 0, 19, 0, 2, 6,158, 0, 7, 2,129, 0, 7, 6,159, 0, 7, 6,160,
+ 0,240, 0, 7, 0,240, 0, 0, 0,240, 0, 1, 0, 29, 0, 54, 0, 11, 2,102, 0, 4, 0, 19, 0, 0, 0, 16, 0, 4, 6,161,
+ 0,111, 0, 2, 0, 26, 0, 30, 0, 11, 6,157, 0,241, 0, 15, 0,143, 0, 0, 0,143, 0, 1, 0, 4, 4, 0, 0, 7, 4, 1,
+ 0,144, 4, 2, 0, 2, 4, 3, 0,148, 4, 66, 0,111, 2,100, 0, 2, 0, 19, 0, 2, 6,162, 0, 2, 4, 72, 0, 2, 6,163,
+ 0, 2, 4, 75, 0, 2, 6,164, 0, 7, 6,165, 0,242, 0, 5, 0,242, 0, 0, 0,242, 0, 1, 0, 29, 0, 54, 0, 2, 0, 19,
+ 0, 0, 6,166, 0,243, 0, 8, 0,243, 0, 0, 0,243, 0, 1, 0, 9, 0, 45, 0, 2, 0, 17, 0, 2, 0, 19, 0, 2, 6,161,
+ 0, 0, 6,166, 0, 7, 6,167, 0,244, 0, 9, 0, 43, 6,168, 0, 2, 6,169, 0, 2, 0, 19, 0, 4, 6,170, 0, 0, 6,171,
+ 0, 7, 1,129, 0, 7, 6,172, 0, 7, 6,173, 0, 4, 0, 15, 0,245, 0, 6, 0, 43, 6,168, 0, 4, 6,161, 0, 4, 6,174,
+ 0, 4, 0, 66, 0, 4, 0, 15, 0, 0, 6,171, 0,246, 0, 4, 0, 43, 6,168, 0, 4, 0, 19, 0, 4, 6,161, 0, 0, 6,171,
+ 0,247, 0, 4, 0, 43, 6,168, 0, 4, 0, 19, 0, 4, 6,161, 0, 0, 6,171, 0,248, 0, 10, 0, 43, 6,168, 0, 4, 6,175,
+ 0, 7, 0, 98, 0, 4, 0, 19, 0, 2, 6,176, 0, 2, 6,177, 0, 2, 0, 80, 0, 2, 1, 91, 0, 7, 6,178, 0, 0, 6,171,
+ 0,249, 0, 4, 0, 43, 6,168, 0, 4, 0, 19, 0, 4, 6,161, 0, 0, 6,171, 0,250, 0, 10, 0, 43, 6,168, 0, 2, 0, 17,
+ 0, 2, 2,201, 0, 4, 2, 24, 0, 4, 5,229, 0, 7, 6, 68, 0, 7, 2, 88, 0, 4, 0, 15, 0,111, 6, 47, 0, 0, 6,171,
+ 0,251, 0, 4, 0, 43, 6,168, 0, 4, 2,116, 0, 4, 6,179, 0, 0, 6,171, 0,252, 0, 5, 0, 43, 6,168, 0, 7, 0, 98,
+ 0, 4, 6,180, 0, 4, 2,116, 0, 4, 2,117, 0,253, 0, 6, 0, 43, 6,168, 0, 0, 6,171, 0, 7, 0, 80, 0, 7, 1, 91,
+ 0, 7, 6,103, 0, 7, 2, 30, 0,254, 0, 6, 0, 7, 0, 8, 0, 7, 0, 9, 0, 7, 0, 10, 0, 7, 0, 11, 0, 7, 6,181,
+ 0, 7, 6,182, 0,255, 0, 6, 0, 43, 6,168, 0, 4, 6,183, 0, 4, 6,184, 0, 7, 6,185, 0, 7, 6,186, 0, 0, 6,171,
+ 1, 0, 0, 8, 0, 7, 0, 8, 0, 7, 0, 9, 0, 7, 0, 10, 0, 7, 0, 11, 0, 7, 6,181, 0, 7, 6,182, 0, 2, 0, 19,
+ 0, 2, 4, 48, 1, 1, 0, 8, 0, 7, 0, 8, 0, 7, 0, 9, 0, 7, 0, 10, 0, 7, 0, 11, 0, 7, 6,181, 0, 7, 6,182,
+ 0, 2, 0, 19, 0, 2, 0, 80, 1, 2, 0, 8, 0, 7, 0, 8, 0, 7, 0, 9, 0, 7, 0, 10, 0, 7, 0, 11, 0, 7, 6,181,
+ 0, 7, 6,182, 0, 2, 0, 19, 0, 2, 0, 80, 1, 3, 0, 16, 0, 43, 6,168, 0, 43, 6,145, 0, 4, 0, 17, 0, 7, 6,187,
+ 0, 7, 6,188, 0, 7, 6,189, 0, 7, 6,190, 0, 7, 6,191, 0, 7, 6,192, 0, 7, 6,193, 0, 7, 6,194, 0, 7, 6,195,
+ 0, 2, 0, 19, 0, 2, 0, 15, 0, 2, 0, 80, 0, 2, 1, 91, 1, 4, 0, 8, 1, 4, 0, 0, 1, 4, 0, 1, 0, 2, 0, 17,
+ 0, 2, 0, 19, 0, 0, 6,196, 0, 2, 0, 15, 0, 2, 6,197, 0, 43, 0,226, 1, 5, 0, 22, 1, 5, 0, 0, 1, 5, 0, 1,
+ 0, 2, 0, 19, 0, 2, 0,227, 0, 2, 6,198, 0, 2, 6,199, 0, 29, 0, 54, 0,111, 6, 47, 0, 43, 0,133, 0, 7, 2, 24,
+ 0, 7, 5,229, 0, 7, 6,200, 0, 7, 6,201, 0, 7, 6,202, 0, 7, 1, 58, 0, 7, 6,203, 0, 7, 6,204, 0, 7, 6, 48,
+ 0, 7, 6,205, 0, 0, 6,206, 0, 0, 6,207, 0, 11, 2,105, 1, 6, 0, 8, 0, 7, 1,137, 0, 7, 6, 68, 0, 7, 2, 88,
+ 0, 9, 0, 45, 0, 2, 6,208, 0, 2, 6,209, 0, 2, 6,210, 0, 2, 6,211, 1, 7, 0, 17, 1, 7, 0, 0, 1, 7, 0, 1,
+ 0, 0, 0, 16, 1, 6, 6,212, 0, 2, 0, 17, 0, 2, 0, 19, 0, 2, 6,213, 0, 2, 6,214, 0, 2, 6,215, 0, 2, 6,216,
+ 0, 4, 0, 80, 0, 7, 6,217, 0, 7, 6,218, 0, 4, 6,219, 0, 4, 6,220, 1, 7, 6,221, 1, 8, 6,222, 1, 9, 0, 29,
+ 1, 9, 0, 0, 1, 9, 0, 1, 1, 9, 6,223, 0, 0, 0, 16, 0, 2, 0, 17, 0, 2, 0, 19, 0, 2, 5,168, 0, 2, 5,194,
+ 0, 2, 6,224, 0, 2, 0,106, 0, 2, 6,214, 0, 2, 5,167, 0, 11, 6, 42, 0, 11, 6,225, 0, 26, 4,149, 0, 9, 6,226,
+ 0, 7, 6,217, 0, 7, 6,218, 0, 7, 1,162, 0, 7, 6,227, 0, 2, 6,228, 0, 2, 6,229, 0, 2, 6,230, 0, 2, 6,231,
+ 0, 23, 6,232, 0, 23, 6,233, 0, 23, 6,234, 1, 10, 0,121, 1, 11, 6,235, 1, 8, 0, 6, 1, 8, 0, 0, 1, 8, 0, 1,
+ 1, 9, 6,236, 1, 9, 6,237, 1, 7, 6,238, 1, 7, 6,221, 0, 54, 0, 13, 0, 26, 0, 30, 0, 11, 6,239, 0, 11, 6,240,
+ 1, 6, 6,241, 0, 4, 0, 17, 0, 4, 6,242, 0, 4, 6,243, 0, 4, 6,244, 1, 11, 6,245, 1, 11, 6,246, 0, 9, 6,247,
+ 0, 9, 6,248, 0, 4, 6,249, 1, 12, 0, 6, 0, 4, 0, 97, 0, 4, 0, 99, 0, 4, 5,167, 0, 0, 6,250, 0, 0, 6,251,
+ 0, 2, 0, 15, 1, 13, 0, 11, 0, 2, 5,107, 0, 2, 5,108, 0, 2, 6,252, 0, 2, 6, 88, 0, 2, 6,253, 0, 2, 0, 80,
+ 0, 7, 6, 69, 0, 2, 0,242, 0, 0, 6,254, 0, 0, 3, 58, 0, 4, 1, 91, 1, 14, 0, 3, 0, 7, 6,255, 0, 7, 7, 0,
+ 0, 7, 0, 14, 1, 15, 0, 7, 0, 0, 1,100, 0, 2, 3,126, 0, 2, 3,127, 0, 2, 3,128, 0, 2, 3, 78, 0, 4, 0, 99,
+ 0, 4, 2,199, 1, 16, 0, 7, 0, 7, 7, 1, 0, 7, 7, 2, 0, 7, 7, 3, 0, 7, 1,171, 0, 7, 7, 4, 0, 7, 7, 5,
+ 0, 7, 7, 6, 1, 17, 0, 2, 0, 0, 0,135, 0, 0, 7, 7, 1, 18, 0, 1, 0, 0, 0, 16, 1, 19, 0, 10, 0, 0, 7, 8,
+ 0, 0, 7, 9, 0, 0, 7, 10, 0, 0, 7, 11, 0, 2, 6,252, 0, 2, 7, 12, 0, 7, 7, 13, 0, 7, 7, 14, 0, 7, 7, 15,
+ 0, 7, 1,101, 1, 20, 0, 4, 0, 7, 0, 4, 0, 7, 0, 5, 0, 2, 0, 19, 0, 2, 7, 16, 1, 21, 0, 10, 0, 2, 2,181,
+ 0, 2, 0, 19, 0, 7, 3, 11, 0, 7, 7, 17, 0, 7, 7, 18, 0, 7, 7, 19, 0, 7, 7, 20, 1, 20, 7, 21, 1, 20, 7, 22,
+ 1, 20, 7, 23, 0,160, 0, 9, 0, 4, 0, 19, 0, 4, 0, 38, 0, 23, 7, 24, 0, 23, 7, 25, 1, 21, 7, 26, 0, 7, 7, 27,
+ 0, 7, 7, 28, 0, 7, 7, 29, 0, 7, 1, 58, 1, 22, 0, 4, 0, 39, 2, 47, 0, 7, 7, 30, 0, 7, 1, 26, 0, 7, 0, 15,
+ 0,134, 0, 13, 0, 26, 0, 30, 0, 2, 0, 19, 0, 2, 3,253, 0, 4, 0, 77, 0, 7, 7, 31, 0, 7, 1,168, 0, 7, 7, 32,
+ 0, 7, 7, 33, 0, 7, 1, 26, 0, 2, 0,253, 0, 2, 0, 15, 0, 42, 1, 11, 1, 22, 7, 34, 1, 23, 0, 6, 0, 4, 0, 17,
+ 0, 4, 0, 98, 0, 4, 0, 19, 0, 4, 2,169, 0, 0, 0, 16, 0, 9, 0, 45, 0, 81, 0, 5, 1, 23, 7, 35, 0, 4, 7, 36,
+ 0, 4, 7, 37, 0, 4, 7, 38, 0, 4, 0, 15, 69, 78, 68, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
diff --git a/source/blender/src/previewrender.c b/source/blender/src/previewrender.c
new file mode 100644
index 00000000000..2f7b4754d76
--- /dev/null
+++ b/source/blender/src/previewrender.c
@@ -0,0 +1,912 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/* global includes */
+
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef WIN32
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+#include "MEM_guardedalloc.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+
+#include "MTC_matrixops.h"
+
+#include "DNA_texture_types.h"
+#include "DNA_world_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_image_types.h"
+#include "DNA_material_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_space_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_image.h"
+#include "BKE_icons.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_texture.h"
+#include "BKE_material.h"
+#include "BKE_node.h"
+#include "BKE_world.h"
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "BSE_headerbuttons.h"
+#include "BSE_node.h"
+#include "BSE_view.h"
+
+#include "BIF_gl.h"
+#include "BIF_screen.h"
+#include "BIF_space.h" /* allqueue */
+#include "BIF_butspace.h"
+#include "BIF_mywindow.h"
+#include "BIF_interface.h"
+#include "BIF_glutil.h"
+
+#include "BIF_previewrender.h" /* include ourself for prototypes */
+
+#include "PIL_time.h"
+
+#include "RE_pipeline.h"
+#include "BLO_readfile.h"
+
+#include "blendef.h" /* CLAMP */
+#include "interface.h" /* ui_graphics_to_window(), SOLVE! (ton) */
+#include "mydevice.h"
+
+
+#define PR_XMIN 10
+#define PR_YMIN 5
+#define PR_XMAX 200
+#define PR_YMAX 195
+
+
+static void set_previewrect(RenderInfo *ri, int win)
+{
+ rctf viewplane;
+
+ BLI_init_rctf(&viewplane, PR_XMIN, PR_XMAX, PR_YMIN, PR_YMAX);
+
+ ui_graphics_to_window_rct(win, &viewplane, &ri->disprect);
+
+ /* correction for gla draw */
+ BLI_translate_rcti(&ri->disprect, -curarea->winrct.xmin, -curarea->winrct.ymin);
+
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+
+ glaDefine2DArea(&curarea->winrct);
+
+ ri->pr_rectx= (ri->disprect.xmax-ri->disprect.xmin);
+ ri->pr_recty= (ri->disprect.ymax-ri->disprect.ymin);
+}
+
+static void end_previewrect(void)
+{
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+
+ // restore viewport / scissor which was set by glaDefine2DArea
+ glViewport(curarea->winrct.xmin, curarea->winrct.ymin, curarea->winx, curarea->winy);
+ glScissor(curarea->winrct.xmin, curarea->winrct.ymin, curarea->winx, curarea->winy);
+
+}
+
+/* unused now */
+void draw_tex_crop(Tex *tex)
+{
+ rcti rct;
+ int ret= 0;
+
+ if(tex==0) return;
+
+ if(tex->type==TEX_IMAGE) {
+ if(tex->cropxmin==0.0f) ret++;
+ if(tex->cropymin==0.0f) ret++;
+ if(tex->cropxmax==1.0f) ret++;
+ if(tex->cropymax==1.0f) ret++;
+ if(ret==4) return;
+
+ rct.xmin= PR_XMIN+2+tex->cropxmin*(PR_XMAX-PR_XMIN-4);
+ rct.xmax= PR_XMIN+2+tex->cropxmax*(PR_XMAX-PR_XMIN-4);
+ rct.ymin= PR_YMIN+2+tex->cropymin*(PR_YMAX-PR_YMIN-4);
+ rct.ymax= PR_YMIN+2+tex->cropymax*(PR_YMAX-PR_YMIN-4);
+
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+
+ glColor3ub(0, 0, 0);
+ glRecti(rct.xmin+1, rct.ymin-1, rct.xmax+1, rct.ymax-1);
+
+ glColor3ub(255, 255, 255);
+ glRecti(rct.xmin, rct.ymin, rct.xmax, rct.ymax);
+
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ }
+
+}
+
+/* temporal abuse; if id_code is -1 it only does texture.... solve! */
+void BIF_preview_changed(short id_code)
+{
+ ScrArea *sa;
+
+ for(sa= G.curscreen->areabase.first; sa; sa= sa->next) {
+ if(sa->spacetype==SPACE_BUTS) {
+ SpaceButs *sbuts= sa->spacedata.first;
+ if(sbuts->mainb==CONTEXT_SHADING) {
+ int tab= sbuts->tab[CONTEXT_SHADING];
+ if(tab==TAB_SHADING_MAT && (id_code==ID_MA || id_code==ID_TE)) {
+ if (sbuts->ri) sbuts->ri->curtile= 0;
+ addafterqueue(sa->win, RENDERPREVIEW, 1);
+ }
+ else if(tab==TAB_SHADING_TEX && (id_code==ID_TE || id_code==-1)) {
+ if (sbuts->ri) sbuts->ri->curtile= 0;
+ addafterqueue(sa->win, RENDERPREVIEW, 1);
+ }
+ else if(tab==TAB_SHADING_LAMP && (id_code==ID_LA || id_code==ID_TE)) {
+ if (sbuts->ri) sbuts->ri->curtile= 0;
+ addafterqueue(sa->win, RENDERPREVIEW, 1);
+ }
+ else if(tab==TAB_SHADING_WORLD && (id_code==ID_WO || id_code==ID_TE)) {
+ if (sbuts->ri) sbuts->ri->curtile= 0;
+ addafterqueue(sa->win, RENDERPREVIEW, 1);
+ }
+ }
+ else if (sbuts->ri)
+ sbuts->ri->curtile= 0; /* ensure changes always result in re-render when context is restored */
+ }
+ else if(sa->spacetype==SPACE_NODE) {
+ SpaceNode *snode= sa->spacedata.first;
+ if(snode->treetype==NTREE_SHADER && (id_code==ID_MA || id_code==ID_TE)) {
+ snode_tag_dirty(snode);
+ }
+ }
+ else if(sa->spacetype==SPACE_VIEW3D) {
+ View3D *vd= sa->spacedata.first;
+ /* if is has a renderinfo, we consider that reason for signalling */
+ if (vd->ri) {
+ vd->ri->curtile= 0;
+ addafterqueue(sa->win, RENDERPREVIEW, 1);
+ }
+ }
+ }
+}
+
+/* *************************** Preview for buttons *********************** */
+
+static Main *pr_main= NULL;
+
+void BIF_preview_init_dbase(void)
+{
+ BlendReadError bre;
+ BlendFileData *bfd;
+ extern int datatoc_preview_blend_size;
+ extern char datatoc_preview_blend[];
+
+ G.fileflags |= G_FILE_NO_UI;
+ bfd= BLO_read_from_memory(datatoc_preview_blend, datatoc_preview_blend_size, &bre);
+ if (bfd) {
+ pr_main= bfd->main;
+
+ MEM_freeN(bfd);
+ }
+ G.fileflags &= ~G_FILE_NO_UI;
+}
+
+void BIF_preview_free_dbase(void)
+{
+ if(pr_main)
+ free_main(pr_main);
+}
+
+/* call this with an ID pointer to initialize preview scene */
+/* call this with ID NULL to restore assigned ID pointers in preview scene */
+static Scene *preview_prepare_scene(RenderInfo *ri, int id_type, ID *id, int pr_method)
+{
+ Scene *sce;
+ Base *base;
+
+ if(pr_main==NULL) return NULL;
+
+ sce= pr_main->scene.first;
+ if(sce) {
+
+ // sce->r.mode |= G.scene->r.mode & R_THREADS;
+ /* this flag tells render to not execute depsgraph or ipos etc */
+ sce->r.scemode |= R_PREVIEWBUTS;
+ /* set world always back, is used now */
+ sce->world= pr_main->world.first;
+
+ sce->r.cfra= G.scene->r.cfra;
+
+ if(id_type==ID_MA) {
+ Material *mat= (Material *)id;
+
+ if(id) {
+ init_render_material(mat, 0, NULL); /* call that retrieves mode_l */
+ end_render_material(mat);
+
+ /* turn on raytracing if needed */
+ if(mat->mode_l & (MA_RAYTRANSP|MA_RAYMIRROR))
+ sce->r.mode |= R_RAYTRACE;
+ if(mat->sss_flag & MA_DIFF_SSS)
+ sce->r.mode |= R_SSS;
+
+ /* turn off fake shadows if needed */
+ /* this only works in a specific case where the preview.blend contains
+ * an object starting with 'c' which has a material linked to it (not the obdata)
+ * and that material has a fake shadow texture in the active texture slot */
+ for(base= sce->base.first; base; base= base->next) {
+ if(base->object->id.name[2]=='c') {
+ Material *shadmat= give_current_material(base->object, base->object->actcol);
+ if(shadmat) {
+ if (mat->mode & MA_SHADBUF) shadmat->septex = 0;
+ else shadmat->septex |= 1;
+ }
+ }
+ }
+
+
+ if(pr_method==PR_ICON_RENDER) {
+ if (mat->mode & MA_HALO) {
+ sce->lay= 1<<MA_FLAT;
+ }
+ else {
+ sce->lay= 1<<MA_SPHERE_A;
+ }
+ }
+ else {
+ sce->lay= 1<<mat->pr_type;
+ if(mat->nodetree)
+ ntreeInitPreview(mat->nodetree, ri->pr_rectx, ri->pr_recty);
+ }
+ }
+ else {
+ sce->r.mode &= ~(R_OSA|R_RAYTRACE|R_SSS);
+ }
+
+ for(base= sce->base.first; base; base= base->next) {
+ if(base->object->id.name[2]=='p') {
+ if(ELEM4(base->object->type, OB_MESH, OB_CURVE, OB_SURF, OB_MBALL))
+ assign_material(base->object, mat, base->object->actcol);
+ }
+ }
+ }
+ else if(id_type==ID_TE) {
+ Tex *tex= (Tex *)id;
+
+ sce->lay= 1<<MA_TEXTURE;
+
+ for(base= sce->base.first; base; base= base->next) {
+ if(base->object->id.name[2]=='t') {
+ Material *mat= give_current_material(base->object, base->object->actcol);
+ if(mat && mat->mtex[0]) {
+ mat->mtex[0]->tex= tex;
+ /* show alpha in this case */
+ if(tex==NULL || (tex->flag & TEX_PRV_ALPHA)) {
+ mat->mtex[0]->mapto |= MAP_ALPHA;
+ mat->alpha= 0.0f;
+ }
+ else {
+ mat->mtex[0]->mapto &= ~MAP_ALPHA;
+ mat->alpha= 1.0f;
+ }
+ }
+ }
+ }
+ }
+ else if(id_type==ID_LA) {
+ Lamp *la= (Lamp *)id;
+
+ sce->lay= 1<<MA_LAMP;
+ sce->r.mode &= ~R_SHADOW;
+
+ for(base= sce->base.first; base; base= base->next) {
+ if(base->object->id.name[2]=='p') {
+ if(base->object->type==OB_LAMP)
+ base->object->data= la;
+ }
+ }
+ }
+ else if(id_type==ID_WO) {
+ sce->lay= 1<<MA_SKY;
+ sce->world= (World *)id;
+ }
+
+ return sce;
+ }
+
+ return NULL;
+}
+
+static void previewrender_progress(RenderResult *rr, volatile rcti *renrect)
+{
+ RenderLayer *rl;
+ RenderInfo *ri= G.buts->ri;
+ float ofsx, ofsy;
+
+ if(renrect) return;
+
+ rl= rr->layers.first;
+
+ ofsx= ri->disprect.xmin + rr->tilerect.xmin;
+ ofsy= ri->disprect.ymin + rr->tilerect.ymin;
+
+ glDrawBuffer(GL_FRONT);
+ glaDrawPixelsSafe_to32(ofsx, ofsy, rr->rectx, rr->recty, rr->rectx, rl->rectf);
+ bglFlush();
+ glDrawBuffer(GL_BACK);
+}
+
+
+/* called by interface_icons.c, or by BIF_previewrender_buts or by nodes... */
+void BIF_previewrender(struct ID *id, struct RenderInfo *ri, struct ScrArea *area, int pr_method)
+{
+ Render *re;
+ RenderStats *rstats;
+ Scene *sce;
+ SpaceButs *sbuts= NULL;
+ int oldx= ri->pr_rectx, oldy= ri->pr_recty;
+ char name [32];
+
+ if(ri->tottile && ri->curtile>=ri->tottile) return;
+
+ /* check for return with a new event */
+ if(pr_method!=PR_ICON_RENDER && qtest()) {
+ if(area)
+ addafterqueue(area->win, RENDERPREVIEW, 1);
+ return;
+ }
+
+ /* get the stuff from the builtin preview dbase */
+ sce= preview_prepare_scene(ri, GS(id->name), id, pr_method);
+ if(sce==NULL) return;
+
+ /* set drawing conditions OK */
+ if(area) {
+ sbuts= area->spacedata.first; /* needed for flag */
+
+ set_previewrect(ri, area->win); // uses UImat
+
+ /* because preview render size can differs */
+ if(ri->rect && (oldx!=ri->pr_rectx || oldy!=ri->pr_recty)) {
+ MEM_freeN(ri->rect);
+ ri->rect= NULL;
+ ri->curtile= 0;
+ }
+ }
+
+ sprintf(name, "ButsPreview %d", area?area->win:0);
+ re= RE_GetRender(name);
+
+ /* full refreshed render from first tile */
+ if(re==NULL || ri->curtile==0) {
+
+ re= RE_NewRender(name);
+
+ /* handle cases */
+ if(pr_method==PR_DRAW_RENDER) {
+ RE_display_draw_cb(re, previewrender_progress);
+ RE_test_break_cb(re, qtest);
+ sce->r.scemode |= R_NODE_PREVIEW;
+ if(sbuts->flag & SB_PRV_OSA)
+ sce->r.mode |= R_OSA;
+ sce->r.scemode &= ~R_NO_IMAGE_LOAD;
+ }
+ else if(pr_method==PR_DO_RENDER) {
+ RE_test_break_cb(re, qtest);
+ sce->r.scemode |= R_NODE_PREVIEW;
+ sce->r.scemode &= ~R_NO_IMAGE_LOAD;
+ }
+ else { /* PR_ICON_RENDER */
+ sce->r.scemode &= ~R_NODE_PREVIEW;
+ sce->r.scemode |= R_NO_IMAGE_LOAD;
+ }
+
+ /* allocates render result */
+ RE_InitState(re, &sce->r, ri->pr_rectx, ri->pr_recty, NULL);
+
+ /* enforce preview image clear */
+ if(GS(id->name)==ID_MA) {
+ Material *ma= (Material *)id;
+ ntreeClearPreview(ma->nodetree);
+ }
+ }
+ /* entire cycle for render engine */
+ RE_SetCamera(re, sce->camera);
+ RE_Database_FromScene(re, sce, 1);
+ RE_TileProcessor(re, ri->curtile, 0); // actual render engine
+ RE_Database_Free(re);
+
+ /* handle results */
+ if(pr_method==PR_ICON_RENDER) {
+ if(ri->rect==NULL)
+ ri->rect= MEM_mallocN(sizeof(int)*ri->pr_rectx*ri->pr_recty, "BIF_previewrender");
+ RE_ResultGet32(re, ri->rect);
+ }
+ else {
+ rstats= RE_GetStats(re);
+
+ if(rstats->partsdone!=ri->curtile) {
+ if(ri->rect==NULL)
+ ri->rect= MEM_mallocN(sizeof(int)*ri->pr_rectx*ri->pr_recty, "BIF_previewrender");
+ RE_ResultGet32(re, ri->rect);
+ }
+
+ if(rstats->totpart==rstats->partsdone && rstats->partsdone) {
+ if(GS(id->name)==ID_MA && ((Material *)id)->use_nodes)
+ allqueue(REDRAWNODE, 0);
+ allqueue(REDRAWBUTSSHADING, 0);
+ }
+ else {
+ if(pr_method==PR_DRAW_RENDER && qtest())
+ addafterqueue(area->win, RENDERPREVIEW, 1);
+ }
+
+ ri->curtile= rstats->partsdone;
+ ri->tottile= rstats->totpart;
+ }
+
+ /* unassign the pointers, reset vars */
+ preview_prepare_scene(ri, GS(id->name), NULL, 0);
+
+}
+
+
+/* afterqueue call */
+void BIF_previewrender_buts(SpaceButs *sbuts)
+{
+ uiBlock *block;
+ struct ID* id = 0;
+ struct ID* idfrom = 0;
+ struct ID* idshow = 0;
+ Object *ob;
+
+ if (!sbuts->ri) return;
+
+ /* we safely assume curarea has panel "preview" */
+ /* quick hack for now, later on preview should become uiBlock itself */
+
+ block= uiFindOpenPanelBlockName(&curarea->uiblocks, "Preview");
+ if(block==NULL) return;
+
+ ob= ((G.scene->basact)? (G.scene->basact)->object: 0);
+
+ /* we cant trust this global lockpoin.. for example with headerless window */
+ buttons_active_id(&id, &idfrom);
+ G.buts->lockpoin= id;
+
+ if(sbuts->mainb==CONTEXT_SHADING) {
+ int tab= sbuts->tab[CONTEXT_SHADING];
+
+ if(tab==TAB_SHADING_MAT)
+ idshow = sbuts->lockpoin;
+ else if(tab==TAB_SHADING_TEX)
+ idshow = sbuts->lockpoin;
+ else if(tab==TAB_SHADING_LAMP) {
+ if(ob && ob->type==OB_LAMP) idshow= ob->data;
+ }
+ else if(tab==TAB_SHADING_WORLD)
+ idshow = sbuts->lockpoin;
+ }
+ else if(sbuts->mainb==CONTEXT_OBJECT) {
+ if(ob && ob->type==OB_LAMP) idshow = ob->data;
+ }
+
+ if (idshow) {
+ BKE_icon_changed(BKE_icon_getid(idshow));
+ uiPanelPush(block);
+ BIF_previewrender(idshow, sbuts->ri, sbuts->area, PR_DRAW_RENDER);
+ uiPanelPop(block);
+ end_previewrect();
+ }
+ else {
+ /* no active block to draw. But we do draw black if possible */
+ if(sbuts->ri->rect) {
+ memset(sbuts->ri->rect, 0, sizeof(int)*sbuts->ri->pr_rectx*sbuts->ri->pr_recty);
+ sbuts->ri->tottile= 10000;
+ addqueue(curarea->win, REDRAW, 1);
+ }
+ return;
+ }
+}
+
+
+/* is panel callback, supposed to be called with correct panel offset matrix */
+void BIF_previewdraw(ScrArea *sa, uiBlock *block)
+{
+ SpaceButs *sbuts= sa->spacedata.first;
+ short id_code= 0;
+
+ if(sbuts->lockpoin) {
+ ID *id= sbuts->lockpoin;
+ id_code= GS(id->name);
+ }
+
+ if (!sbuts->ri) {
+ sbuts->ri= MEM_callocN(sizeof(RenderInfo), "butsrenderinfo");
+ sbuts->ri->tottile = 10000;
+ }
+
+ if (sbuts->ri->rect==NULL) BIF_preview_changed(id_code);
+ else {
+ RenderInfo *ri= sbuts->ri;
+ int oldx= ri->pr_rectx, oldy= ri->pr_recty;
+
+ /* we now do scalable previews! */
+ set_previewrect(ri, sa->win);
+ if( ABS(oldx-ri->pr_rectx)<2 && ABS(oldy-ri->pr_recty)<2 ) {
+ /* restore old values for drawing! */
+ ri->pr_rectx= oldx;
+ ri->pr_recty= oldy;
+ glaDrawPixelsSafe(ri->disprect.xmin, ri->disprect.ymin, ri->pr_rectx, ri->pr_recty, ri->pr_rectx, GL_RGBA, GL_UNSIGNED_BYTE, ri->rect);
+ }
+ else {
+ MEM_freeN(ri->rect);
+ ri->rect= NULL;
+ sbuts->ri->curtile= 0;
+ }
+ end_previewrect();
+ }
+ if(sbuts->ri->curtile==0) BIF_preview_changed(id_code);
+
+}
+
+/* *************************** Preview for 3d window *********************** */
+static void view3d_previewrender_stats(RenderStats *rs)
+{
+// if(rs->convertdone)
+// printf("rendered %d %.3f\n", rs->partsdone, rs->lastframetime);
+}
+
+static void view3d_previewrender_progress(RenderResult *rr, volatile rcti *renrect)
+{
+ RenderLayer *rl;
+ int ofsx, ofsy;
+
+ if(renrect) return;
+
+ rl= rr->layers.first;
+
+ /* this case is when we render envmaps... */
+ if(rr->rectx>G.vd->ri->pr_rectx || rr->recty>G.vd->ri->pr_recty)
+ return;
+
+ ofsx= G.vd->ri->disprect.xmin + rr->tilerect.xmin;
+ ofsy= G.vd->ri->disprect.ymin + rr->tilerect.ymin;
+
+ glDrawBuffer(GL_FRONT);
+ glaDefine2DArea(&curarea->winrct);
+ glaDrawPixelsSafe_to32(ofsx, ofsy, rr->rectx, rr->recty, rr->rectx, rl->rectf);
+ bglFlush();
+ glDrawBuffer(GL_BACK);
+
+}
+
+void BIF_view3d_previewrender_signal(ScrArea *sa, short signal)
+{
+ View3D *v3d= sa->spacedata.first;
+
+ /* this can be called from other window... solve! */
+ if(sa->spacetype!=SPACE_VIEW3D)
+ v3d= G.vd;
+
+ if(v3d && v3d->ri) {
+ RenderInfo *ri= v3d->ri;
+ ri->status &= ~signal;
+ ri->curtile= 0;
+ //printf("preview signal %d\n", signal);
+ if(ri->re && (signal & PR_DBASE))
+ RE_Database_Free(ri->re);
+
+ addafterqueue(sa->win, RENDERPREVIEW, 1);
+ }
+}
+
+void BIF_view3d_previewrender_free(View3D *v3d)
+{
+
+ if(v3d->ri) {
+ RenderInfo *ri= v3d->ri;
+ if(ri->re) {
+// printf("free render\n");
+ RE_Database_Free(ri->re);
+ RE_FreeRender(ri->re);
+ ri->re= NULL;
+ }
+ if (v3d->ri->rect) MEM_freeN(v3d->ri->rect);
+ MEM_freeN(v3d->ri);
+ v3d->ri= NULL;
+ }
+}
+
+/* returns 1 if OK, do not call while in panel space! */
+static int view3d_previewrender_get_rects(ScrArea *sa, rctf *viewplane, RenderInfo *ri, float *clipsta, float *clipend, int *ortho, float *pixsize)
+{
+ int rectx, recty;
+ uiBlock *block;
+
+ block= uiFindOpenPanelBlockName(&curarea->uiblocks, "Preview");
+ if(block==NULL) return 0;
+
+ /* calculate preview rect size */
+ BLI_init_rctf(viewplane, 15.0f, (block->maxx - block->minx)-15.0f, 15.0f, (block->maxy - block->miny)-15.0f);
+ uiPanelPush(block);
+ ui_graphics_to_window_rct(sa->win, viewplane, &ri->disprect);
+ uiPanelPop(block);
+
+ /* correction for gla draw */
+ BLI_translate_rcti(&ri->disprect, -sa->winrct.xmin, -sa->winrct.ymin);
+
+ *ortho= get_view3d_viewplane(sa->winx, sa->winy, viewplane, clipsta, clipend, pixsize);
+
+ rectx= ri->disprect.xmax - ri->disprect.xmin;
+ recty= ri->disprect.ymax - ri->disprect.ymin;
+
+ if(rectx<4 || recty<4) return 0;
+
+ if(ri->rect && (rectx!=ri->pr_rectx || recty!=ri->pr_recty)) {
+ MEM_freeN(ri->rect);
+ ri->rect= NULL;
+ ri->curtile= 0;
+ printf("changed size\n");
+ }
+ ri->pr_rectx= rectx;
+ ri->pr_recty= recty;
+
+ return 1;
+}
+
+/* called before a panel gets moved/scaled, makes sure we can see through */
+void BIF_view3d_previewrender_clear(ScrArea *sa)
+{
+ View3D *v3d= sa->spacedata.first;
+
+ if(v3d->ri) {
+ RenderInfo *ri= v3d->ri;
+ ri->curtile= 0;
+ if(ri->rect)
+ MEM_freeN(ri->rect);
+ ri->rect= NULL;
+ }
+}
+
+/* afterqueue call */
+void BIF_view3d_previewrender(ScrArea *sa)
+{
+ View3D *v3d= sa->spacedata.first;
+ Render *re;
+ RenderInfo *ri; /* preview struct! */
+ RenderStats *rstats;
+ RenderData rdata;
+ rctf viewplane;
+ float clipsta, clipend, pixsize;
+ int orth;
+
+ /* first get the render info right */
+ if (!v3d->ri) {
+ ri= v3d->ri= MEM_callocN(sizeof(RenderInfo), "butsrenderinfo");
+ ri->tottile= 10000;
+ }
+ ri= v3d->ri;
+
+ if(0==view3d_previewrender_get_rects(sa, &viewplane, ri, &clipsta, &clipend, &orth, &pixsize))
+ return;
+
+ /* render is finished, so return */
+ if(ri->tottile && ri->curtile>=ri->tottile) return;
+
+ /* or return with a new event */
+ if(qtest()) {
+ addafterqueue(curarea->win, RENDERPREVIEW, 1);
+ return;
+ }
+ //printf("Enter previewrender\n");
+ /* ok, are we rendering all over? */
+ if(ri->re==NULL) {
+ char name[32];
+
+ ri->status= 0;
+
+ sprintf(name, "View3dPreview %d", sa->win);
+ re= ri->re= RE_NewRender(name);
+ RE_display_draw_cb(re, view3d_previewrender_progress);
+ RE_stats_draw_cb(re, view3d_previewrender_stats);
+ RE_test_break_cb(re, qtest);
+
+ /* no osa, blur, seq, layers, etc for preview render */
+ rdata= G.scene->r;
+ rdata.mode &= ~(R_OSA|R_MBLUR);
+ rdata.scemode &= ~(R_DOSEQ|R_DOCOMP|R_FREE_IMAGE);
+ rdata.layers.first= rdata.layers.last= NULL;
+ rdata.renderer= R_INTERN;
+
+ RE_InitState(re, &rdata, sa->winx, sa->winy, &ri->disprect);
+
+ if(orth)
+ RE_SetOrtho(re, &viewplane, clipsta, clipend);
+ else
+ RE_SetWindow(re, &viewplane, clipsta, clipend);
+ RE_SetPixelSize(re, pixsize);
+
+ /* until here are no escapes */
+ ri->status |= PR_DISPRECT;
+ ri->curtile= 0;
+ //printf("new render\n");
+ }
+
+ re= ri->re;
+
+ PIL_sleep_ms(100); /* wait 0.1 second if theres really no event... */
+ if(qtest()==0) {
+
+ /* check status */
+ if((ri->status & PR_DISPRECT)==0) {
+ RE_SetDispRect(ri->re, &ri->disprect);
+ if(orth)
+ RE_SetOrtho(ri->re, &viewplane, clipsta, clipend);
+ else
+ RE_SetWindow(ri->re, &viewplane, clipsta, clipend);
+ RE_SetPixelSize(re, pixsize);
+ ri->status |= PR_DISPRECT;
+ ri->curtile= 0;
+ //printf("disprect update\n");
+ }
+ if((ri->status & PR_DBASE)==0) {
+ unsigned int lay= G.scene->lay;
+
+ RE_SetView(re, G.vd->viewmat);
+
+ /* allow localview render for objects with lights in normal layers */
+ if(v3d->lay & 0xFF000000)
+ G.scene->lay |= v3d->lay;
+ else G.scene->lay= v3d->lay;
+
+ RE_Database_FromScene(re, G.scene, 0); // 0= dont use camera view
+ G.scene->lay= lay;
+
+ rstats= RE_GetStats(re);
+ if(rstats->convertdone)
+ ri->status |= PR_DBASE|PR_PROJECTED|PR_ROTATED;
+ ri->curtile= 0;
+
+ /* database can have created render-resol data... */
+ if(rstats->convertdone)
+ DAG_scene_update_flags(G.scene, screen_view3d_layers());
+
+ //printf("dbase update\n");
+ }
+ if((ri->status & PR_PROJECTED)==0) {
+ if(ri->status & PR_DBASE) {
+ if(orth)
+ RE_SetOrtho(ri->re, &viewplane, clipsta, clipend);
+ else
+ RE_SetWindow(ri->re, &viewplane, clipsta, clipend);
+ RE_DataBase_ApplyWindow(re);
+ ri->status |= PR_PROJECTED;
+ }
+ ri->curtile= 0;
+ //printf("project update\n");
+ }
+
+ /* OK, can we enter render code? */
+ if(ri->status==(PR_DISPRECT|PR_DBASE|PR_PROJECTED|PR_ROTATED)) {
+ //printf("curtile %d tottile %d\n", ri->curtile, ri->tottile);
+ RE_TileProcessor(ri->re, ri->curtile, 0);
+
+ if(ri->rect==NULL)
+ ri->rect= MEM_mallocN(sizeof(int)*ri->pr_rectx*ri->pr_recty, "preview view3d rect");
+
+ RE_ResultGet32(ri->re, ri->rect);
+ }
+
+ rstats= RE_GetStats(ri->re);
+ if(rstats->totpart==rstats->partsdone && rstats->partsdone)
+ addqueue(sa->win, REDRAW, 1);
+ else
+ addafterqueue(curarea->win, RENDERPREVIEW, 1);
+
+ ri->curtile= rstats->partsdone;
+ ri->tottile= rstats->totpart;
+ }
+ else {
+ addafterqueue(curarea->win, RENDERPREVIEW, 1);
+ }
+
+ //printf("\n");
+}
+
+/* in panel space! */
+static void view3d_previewdraw_rect(ScrArea *sa, uiBlock *block, RenderInfo *ri)
+{
+ rctf dispf;
+
+ if(ri->rect==NULL)
+ return;
+
+ BLI_init_rctf(&dispf, 15.0f, (block->maxx - block->minx)-15.0f, 15.0f, (block->maxy - block->miny)-15.0f);
+ ui_graphics_to_window_rct(sa->win, &dispf, &ri->disprect);
+
+ /* correction for gla draw */
+ BLI_translate_rcti(&ri->disprect, -curarea->winrct.xmin, -curarea->winrct.ymin);
+
+ /* when panel scale changed, free rect */
+ if(ri->disprect.xmax-ri->disprect.xmin != ri->pr_rectx ||
+ ri->disprect.ymax-ri->disprect.ymin != ri->pr_recty) {
+ MEM_freeN(ri->rect);
+ ri->rect= NULL;
+ }
+ else {
+ glaDefine2DArea(&sa->winrct);
+ glaDrawPixelsSafe(ri->disprect.xmin, ri->disprect.ymin, ri->pr_rectx, ri->pr_recty, ri->pr_rectx, GL_RGBA, GL_UNSIGNED_BYTE, ri->rect);
+ }
+}
+
+/* is panel callback, supposed to be called with correct panel offset matrix */
+void BIF_view3d_previewdraw(struct ScrArea *sa, struct uiBlock *block)
+{
+ View3D *v3d= sa->spacedata.first;
+
+ if (v3d->ri==NULL || v3d->ri->rect==NULL)
+ addafterqueue(sa->win, RENDERPREVIEW, 1);
+ else {
+ view3d_previewdraw_rect(sa, block, v3d->ri);
+ if(v3d->ri->curtile==0)
+ addafterqueue(sa->win, RENDERPREVIEW, 1);
+ }
+}
+
diff --git a/source/blender/src/prvicons.c b/source/blender/src/prvicons.c
new file mode 100644
index 00000000000..6222090705a
--- /dev/null
+++ b/source/blender/src/prvicons.c
@@ -0,0 +1,436 @@
+/* DataToC output of file <prvicons> */
+
+int datatoc_prvicons_size= 13732;
+char datatoc_prvicons[]= {
+137, 80, 78, 71,
+ 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0,192, 0, 0, 0,192, 8, 6, 0, 0, 0, 82,220,108, 7, 0, 0, 0,
+ 6, 98, 75, 71, 68, 0, 0, 0, 0, 0, 0,249, 67,187,127, 0, 0, 0, 9,112, 72, 89,115, 0, 0, 11, 19, 0, 0, 11, 19, 1,
+ 0,154,156, 24, 0, 0, 0, 7,116, 73, 77, 69, 7,215, 8, 27, 17, 57, 33, 43,142, 73,203, 0, 0, 0, 29,116, 69, 88,116, 67,
+111,109,109,101,110,116, 0, 67,114,101, 97,116,101,100, 32,119,105,116,104, 32, 84,104,101, 32, 71, 73, 77, 80,239,100, 37,110,
+ 0, 0, 32, 0, 73, 68, 65, 84,120,218,237,125,121,124, 84,213,249,254,115,238,189, 51,147,201,158, 12, 73, 72,216, 3,200, 98,
+ 88, 69, 66, 38, 65, 16, 20,165, 40,213,162, 32, 45,138,203, 79,176,223, 42,180,110, 72,235,190, 97, 91, 91, 21,181,149,182, 90,
+ 20, 42, 10, 66, 80,164, 34, 59,146, 5,194, 30, 18, 8, 75, 2,201,144,144,201, 62, 73,102,189,247,158,243,251, 35,235, 36, 51,
+217,200,100, 38,229, 62,159,207,124,146,123,239,153, 59,207, 61,247,125,207,121,223,247,156,243, 30, 64,129, 2, 5, 10, 20, 40,
+ 80,160, 64,129, 2, 5, 10, 20, 40, 80,160, 64,129, 2, 5, 10, 20, 40, 80,160, 64,129, 2, 5, 10, 20, 40, 80,160, 64,129, 2,
+ 5, 10, 20, 40, 80,160, 64,129, 2, 5, 10, 20, 40, 80,160, 64,129, 2, 5, 10, 20, 40, 80,160, 64,129, 2, 5, 10, 20, 40, 80,
+160, 64,129, 2, 5, 10, 20, 40, 80,160, 64,129, 2, 5, 10, 20, 40, 80,160, 64,129, 2, 5, 10, 20, 40, 80,160, 64,129, 2, 5,
+ 10, 20, 40, 80,160, 64,129, 2, 5, 10, 20, 40, 80,160, 64,129, 2, 5, 10, 20, 40, 80,160, 64,129, 2, 5, 10, 20, 40, 80,160,
+ 64,129, 2, 5, 10, 20, 40, 80,160, 64,129, 2, 5, 10, 20, 40, 80,160, 64,129, 2, 5, 10, 20, 40, 80,208, 18, 36, 41, 41,105,
+180, 32, 8,143, 16, 66, 72,119,223,156, 49, 22, 46,203,242,112,198,216,203, 41, 41, 41,251, 60,241, 0,189,157,191, 2,239, 43,
+192, 61, 49, 49, 49, 27,230,204,153,227,215,157, 55,206,206,206,198,169, 83,167, 16, 25, 25, 9,131,193, 64, 37, 73,154,150,146,
+146,146,226, 1, 5,232,213,252, 21,120, 23, 2, 0, 68, 71, 71,219, 23, 46, 92,216,109, 2,180,105,211, 38, 24, 12, 6, 60,250,
+232,163,224, 56, 14, 7, 15, 30,228, 50, 51, 51, 15, 36, 38, 38, 38,164,166,166,102,116,247, 67,244,118,254, 10,188, 7,174,187,
+111, 40, 73, 18,214,175, 95,143, 5, 11, 22,160,111,223,190,240,247,247, 71, 98, 98, 34,226,226,226, 56,149, 74,149,174,215,235,
+ 39,250,114,133,244,118,254, 10,188,172, 0, 6,131, 1,193,193,193,136,136,136,128, 32, 8,208,106,181,208,106,181,208,235,245,
+ 24, 57,114, 36,167, 86,171, 51,244,122,125,156,175, 86, 72,111,231,175,192,203, 10, 80, 88, 88, 8,157, 78,215,120,172,209,104,
+ 26,133, 40, 49, 49, 17,195,135, 15,231,213,106,245,137,132,132,132, 27,124,177, 66,122, 59,127, 5, 94, 86,128,192,192, 64, 88,
+173, 86,167,115,254,254,254,141,159,164,164, 36,196,198,198, 10,126,126,126, 89,122,189, 62,214,215, 42,164,183,243, 87,224,101,
+ 5,208,233,116, 48,153, 76,173,206, 55,180,162, 90,173, 22, 73, 73, 73, 24, 56,112,160, 74,163,209,156,213,235,245, 3,124,169,
+ 66,122, 59,127, 5,157,131,208,221, 55,140,138,138, 66, 77, 77, 13,172, 86, 43,180, 90, 45, 0,160,170,170, 10,165,165,165, 40,
+ 47, 47, 71,105,105, 41, 44, 22, 11, 6, 15, 30, 12, 81, 20,213, 87,175, 94, 61,175,215,235,135,164,165,165, 21,251, 66,133,244,
+118,254, 10,188,172, 0,106,181, 26,227,199,143, 71, 78, 78, 14,116, 58, 29, 14, 28, 56,128,130,130, 2,196,198,198, 34, 42, 42,
+ 10, 67,135, 14, 5,207,243, 72, 77, 77,133,209,104,132, 40,138,126, 26,141, 38, 79,175,215, 15, 74, 75, 75, 43,245,118,133,244,
+118,254, 10,188,172, 0, 0, 48,109,218, 52,124,250,233,167, 16, 69, 17,143, 63,254, 56,102,206,156, 9,181, 90,237, 84,102,209,
+162, 69, 48,153, 76, 88,183,110, 29,182,108,217,162,165,148,190, 9,224, 9, 0,204,219,149,210,219,249, 43,240,162, 15, 0, 0,
+ 9, 9, 9, 8, 12, 12,196, 71, 31,125,132,217,179,103,183, 18,158, 6,132,132,132,224,201, 39,159,132, 70,163, 97, 86,171,117,
+108,104,104,104,127, 0,196,219,149,210,219,249, 43,240,178, 2, 4, 5, 5, 97,205,154, 53,136,137,137,233, 80,249, 33, 67,134,
+ 72, 86,171,213,204,243,252,253,190, 32, 64,189,157,191, 2, 47, 43, 0, 0, 8, 66,199,173, 43, 63, 63, 63, 70, 41,149, 24, 99,
+ 26, 95, 17,160,222,206, 95,129,151, 21,160,139,144,123,121,125,202,138, 72, 41, 10,208, 37, 16, 66,100, 66, 72,175, 21,160,222,
+206,255,122,133,208, 19, 63, 98,178,216,193, 24,131, 74,224, 17,160, 81,185,109, 61, 25, 99, 50,122,111, 20,165,183,243, 87, 20,
+192, 19,200, 45,174,194,152,103, 62, 5, 0, 68,135, 5,226,252,234, 37,224,185,122, 51,153, 81, 56,142,252, 11,183, 71, 92,225,
+ 39,223, 22, 56, 50, 88,173,213,234, 99,111,136,134, 64,254, 25,249,155,244,139,158,230,166, 82,185, 85, 70,136,162,216,217, 30,
+128, 2,160,138, 15,160, 40,128, 19, 62, 63,112,186,241,255,171,149,181,248,241,100, 30,126, 54,113, 40, 0,128,154,174,192,126,
+124, 61,146,194,192, 35, 76, 51, 28,192,112, 0,183, 17,137,255,216,155,194,223,145,235, 45,148,132, 1,104, 48,129,148, 30, 64,
+241, 1,234,109, 2,202,240,159,159,178,157,206,125,113, 32,171,241,127, 90,118,190,213,119, 24, 80, 30,190, 60,165,192,155,194,
+223,197,251, 80,197, 9, 86, 20,192, 9, 59, 79, 93,194,213, 42, 51,180,234,166,142,230,135, 19,121, 40,173,182,212, 41, 72,217,
+ 5,184,208,128, 19,189,169, 2,155, 41, 1,173,247, 1, 20, 40, 10,224,220,218,191,255,240, 76, 52, 44, 89, 23,101,138, 13, 41,
+103,234, 36,166,212,101, 15,112,220,215, 43, 77, 20, 69,167, 15, 0, 13,165, 20, 0,244, 0,120, 69,172, 20, 5, 64,105,181, 5,
+255, 61,158,139, 65, 17, 33, 88,116, 75, 28,102,196, 13,106,230, 23,100,213,247, 0, 46, 20,128,178,227,189,173, 18, 25, 99, 0,
+ 16, 7,160, 76,241, 1, 20, 39, 24, 0,176, 33,229, 12, 68,153,226,161,105, 55,130, 16,224,161,105, 99,176,231,116, 62, 0,224,
+236,149,114,100,100,102, 97,148,189,166,213,247,204,140,157, 0,128,146,143,167, 7,242,212, 54, 7,192, 72, 70,137,131,227,113,
+ 90,148,232,145,168,223, 30, 54,250,168, 2,252, 4,160, 90, 17, 41,165, 7,104,108,229, 57, 66,240,224,180,186,229,179,115, 39,
+ 13, 67, 88, 64, 83,226,134,181,123, 91,155,250,162,204, 44,187,114,228, 75,229,171,227,159,225,101, 91, 49, 24,190, 2,195,171,
+132,176,183, 25,101,219, 4,142,228, 85,172, 78, 88,234,139, 21,233,112, 56,202, 25, 99,134,122,103, 88,193,245,172, 0, 71,115,
+139,113,246, 74, 57,102,142, 25,132,254,225, 65, 0, 0,141,138,199,130,196, 81,141,101, 54,159, 42,133, 85,118, 54,151,171,172,
+180,224, 23,113,170,117, 0,121, 23, 64,128,139, 91,251, 51,176, 79,202, 62, 72, 88,229,131,117, 25, 98,179,217,250,195,247,166,
+151, 40,232,105, 5, 88,187,191, 46,246,191,120,250, 24,167,243, 15, 79,111, 74,166, 80,227, 96,216, 86,230, 60,219, 82, 23,192,
+ 15, 35,192,130,246,238, 79, 8,123,166,236,189, 41,163,188, 85,105, 42,149,170, 85, 40,149, 16, 2, 74,169, 77, 81,128,235, 92,
+ 1, 44,118, 17,223,164,159,131, 46, 72,139,187,110, 26,234,116,109,236,160, 72,140, 27, 28,217,228, 39, 24, 7, 57,147, 33, 16,
+ 24, 96, 7,240, 79, 2,242, 75, 2,242, 75, 6, 28,112, 37,131,132,195,115,222,170,180,102,209,159, 70,225,231, 56, 14, 42,149,
+234, 40,234,162, 64,202,104,240,245,170, 0, 91,143, 92, 64,181,213,142, 7, 18, 71, 65, 45,180,142, 8, 62,220,172, 87, 72,175,
+ 14,199,101, 91,147,165, 67, 41,236,162,204,238,214, 45, 59,180, 36,124, 89,250,134,240,101,233, 27,116, 21,126,183, 1,200,105,
+221, 13,224,198,107, 17, 96, 15, 33,166,222, 7, 96, 0, 84,138,120, 93,135, 10,208, 16,251, 95, 60,205,117,238,168,249,250,145,
+240, 19,184,250,232, 9,193,134,226,129,141,215, 14, 92, 52,255, 43,250,119,135,247, 56,201,249,171,251, 37, 66, 88,178,139,216,
+139, 79,229,229,169,207,205, 43,212,127, 72,125,221,106, 20, 17,187,142, 20,224, 82,137, 9, 7,207, 26, 48, 49, 54, 10,113, 3,
+ 35, 92,150, 9, 11,240,195, 93,195,154,150, 24,126,109, 28, 8,153, 17, 88, 37, 88, 95,218,102,220,233, 70,188,170, 92,156,243,
+243,149, 74,164,148,130, 82, 10, 73,146, 56, 0, 13,221,139, 31,234,204, 57, 5, 62,140,110, 29, 7,248,226, 64, 22, 24, 3,146,
+ 70, 14, 64,102,126,137,219,114, 19,131, 42,241, 13,234, 82,142, 92,117,248, 97,127,101, 36, 2,107, 11, 47, 24,107, 36,171,171,
+242,140,161,159,139,211, 62,149,129,161,190, 7, 16,209, 52, 16,102, 82,196,235, 58, 82, 0,202, 24,214,255, 84,103,254,172,254,
+239, 81,172,254,239,209, 54, 74,107,157,142, 54, 24, 7,226, 94,114,165,202,221,130, 18, 2, 50,136,181, 30, 96,205,242, 86,165,
+ 53, 68,128,154,251, 18,140, 49,112, 28, 39,214,215,169,168,136,214,117,166, 0,187, 78, 93, 70, 97, 69, 45,166,142, 26,128,219,
+199, 14,118, 95, 80,118,192,126,116, 45, 14,155,194,177,187, 50, 10, 0,240, 99,121, 95,220,168,209, 88, 40,165,173,166, 19,151,
+175,142, 15,102, 96,183,182,234, 21, 0,175,231,234, 87,169, 84, 78, 74,192,113,156, 67, 49,123,174, 83, 5,104,112,126, 95,186,
+ 79,143,164,145,253,221,150,147,138, 78,192,106, 60,143,139,186, 64,236, 62, 86,167, 0, 14,198,225, 44, 63,108, 24, 33, 57,178,
+ 11,211,226, 9,198, 16,220,178,195,225,101,124,233, 11, 21,216,208, 27,168, 84, 42,155, 90,173,110,112,128, 21, 92, 79, 78,112,
+121,141, 21,219,143,231, 98, 72,100, 8, 18, 71,244,111,219, 84,170,159, 1, 58,204,191, 22, 55, 7, 87, 52,158, 63, 45,247, 31,
+ 76,235,167, 84, 54,160,236,195,201, 51, 24,195, 75, 46,140,162, 45, 97,191, 59,116,217,135,236,255, 82, 65, 16,120, 40, 19,225,
+174,207, 30,224,171,212,179,112, 72, 50, 22,221,114, 35,218,219,169,171,249, 26,128, 95, 70,229,227, 72,117, 56, 0, 32,207, 22,
+ 36,124,241,127,250, 79,110,139,170,120,141,112, 40,231, 25,110,167, 12,207,160,117, 40,209,194,113,228, 89, 95,170, 68,158,231,
+ 3,120,158,175, 97,140, 29,135, 50, 23,232,250,235, 1,214,238, 63, 13,142, 16, 44,186,165,253,125, 35,154,175, 2,251,121, 68,
+ 33,252, 57,169,241,120,111,109,255, 49, 60,193, 55, 28,195, 62, 6,252,158,180, 22,126, 10, 66, 30, 14,123, 50, 45,223,199,234,
+145, 17, 66,168, 39, 54,234, 83,224,163, 61, 64, 65, 89, 53,118,158,186,132,242, 26, 43,178, 13,101,232, 23, 30,136, 31, 79,230,
+ 1, 0,126, 54,113, 40, 98,194, 2, 91, 75,137,100, 3,173, 42, 64,165,164,198,119,165,117,243,128, 6,105, 45, 56,107,174, 51,
+241,183,148,246,199,232,128,186, 25,197,183,134,149, 96,160,159,197,201,125, 32,192,178,240,167,210, 55,249, 82, 5,138,162,216,
+ 16, 2,149, 91,154,112, 10,254,135, 21, 32,203, 80,134,101,159,237,110, 60, 46,172,168,109, 60, 30,214, 55,204,165, 2,208,242,
+ 92,128, 81, 20,219,253,240,252,197,113,173,174, 87, 75,170,198,243,159,141,202,104,174, 0, 57,132,224,255,133, 63,117, 40,181,
+ 59, 5,247, 90,215, 6, 55, 68,128, 24, 99,168,239, 1, 20, 5,184, 94, 20, 32,126, 88, 52,118,252, 97,190,203,107, 99, 7,185,
+ 30, 5,230,130,251, 65, 59,247, 3,140,112,200,216, 62,185,166,222,129,228,177,230,235, 31,109,135,207,228,173, 11, 12,208,156,
+126,112, 28, 25, 30,161,178, 15, 25, 27,100,178, 1,200, 97,132,238,235,243, 84,198, 94, 79,181,222,157, 77,141, 34, 73, 82,171,
+180,137,132, 16, 48,198,168, 44,203, 65,138, 72, 93, 39, 10,160, 11,210,226,150,209,157,219, 28,133,104, 67, 33,104, 39, 32, 4,
+192,173,131,155,206,127,191,245, 59, 57,220,116,225, 66,126,102,254,174, 63,236, 48,125,212,147,209,148,206, 78,140,115,151, 51,
+ 84,201, 12,119, 29, 59,193,221,132,222, 46, 64,138, 2,244,214, 30,192,100, 50, 9, 25, 25,222,219,255,217,100, 50,241,132, 16,
+ 42,203,178,220,197,239,247,106,254, 10,188,171, 0,198,226,226,226, 83,171, 86,173,226,237,118,123, 52, 99, 76,141,186,176, 30,
+234, 77, 17,214,204, 36, 97,132,144,198,255, 91, 94,115,119,189,197,189, 90,150,101,178, 44,203,146, 36,149,212, 59,145,157, 53,
+127,122, 59,127, 5, 94, 68,243,184, 53,167,211,233,150, 3,232,139,166, 44,103, 50, 99, 76, 34,132,200,140, 49,153, 16, 34, 53,
+ 59, 71,155, 93,107, 56, 47, 19, 66,164,250, 4, 81,114,195, 53, 66,136, 76, 41,149, 90, 28,203, 13,118, 51,165, 84,146,101, 89,
+ 98,140, 89,204,102,243,149,174,154,115,189,156,191, 2, 47, 43, 0, 9, 12, 12,140,230, 56, 78, 77, 8, 97,245, 19,189, 26, 91,
+185,134, 86,176,249,113,125,232,143, 1,128,195,225,112,106, 65, 9, 33,172,217,167,161, 44, 44, 22,139,211, 61, 56,142, 99,132,
+ 16, 86, 89, 89,201,234,133,182,171, 51, 41,123, 59,127, 5, 94, 86, 0, 87,199, 29, 5,243,209,231,233,109,252, 21,244,180,192,
+ 36, 37, 37,141, 22, 4,225, 17, 79, 12,227, 51,198,194,101, 89, 30,206, 24,123, 57, 37, 37,101,159, 39, 30, 64,225,175,240,191,
+ 86, 5,184, 39, 38, 38,102,195,156, 57,115,186,117,137, 97,118,118, 54, 78,157, 58,133,200,200, 72, 24, 12, 6, 42, 73,210,180,
+148,148,148, 20, 15,188, 0,133,191,194,255,154,162, 64,136,142,142,182, 47, 92,184,176,219, 30, 96,211,166, 77, 48, 24, 12,120,
+244,209, 71,193,113, 28, 14, 30, 60,200,101,102,102, 30, 72, 76, 76, 76, 72, 77, 77,237,246,120,165,194, 95,225,223, 85,116,251,
+ 64,152, 36, 73, 88,191,126, 61, 22, 44, 88,128,190,125,251,194,223,223, 31,137,137,137,136,139,139,227, 84, 42, 85,186, 94,175,
+159,232,203, 54,161,194,255,250,226,223,237, 10, 96, 48, 24, 16, 28, 28,140,136,136, 8, 8,130, 0,173, 86, 11,173, 86, 11,189,
+ 94,143,145, 35, 71,114,106,181, 58, 67,175,215,199,249,234, 11, 80,248, 95, 95,252,187, 93, 1, 10, 11, 11,161,211,233, 26,143,
+ 53, 26, 77,227, 67, 36, 38, 38, 98,248,240,225,188, 90,173, 62,145,144,144,112,131, 47,190, 0,133,255,245,197,191,219, 21, 32,
+ 48, 48, 16, 86,171,115,118, 19,127,127,255,198, 79, 82, 82, 18, 98, 99, 99, 5, 63, 63,191, 44,189, 94, 31,235,107, 47, 64,225,
+127,125,241,239,118, 5,208,233,116, 48,153, 90,167,196,105,208, 98,173, 86,139,164,164, 36, 12, 28, 56, 80,165,209,104,206,234,
+245,250, 1,190,244, 2, 20,254,215, 23,255,110,223, 32, 35, 42, 42, 10, 53, 53, 53,176, 90,173,208,106,235,242,255, 84, 85, 85,
+161,180,180, 20,229,229,229, 40, 45, 45,133,197, 98,193,224,193,131, 33,138,162,250,234,213,171,231,245,122,253,144,180,180,180,
+ 98, 95,120, 1, 10,255,235,139,127,183, 43,128, 90,173,198,248,241,227,145,147,147, 3,157, 78,135, 3, 7, 14,160,160,160, 0,
+177,177,177,136,138,138,194,208,161, 67,193,243, 60, 82, 83, 83, 97, 52, 26, 33,138,162,159, 70,163,201,211,235,245,131,210,210,
+210,188,158,237, 77,225,127,125,241,247,200, 22, 73,211,166, 77,195,167,159,126, 10, 81, 20,241,248,227,143, 99,230,204,153, 80,
+171,213, 78,101, 22, 45, 90, 4,147,201,132,117,235,214, 97,203,150, 45, 90, 74,233,155, 0,158,128, 15, 76, 75, 80,248, 95, 63,
+252, 61,178, 32, 38, 33, 33, 1,129,129,129,248,232,163,143, 48,123,246,108,183,171,168, 66, 66, 66,240,228,147, 79, 66,163,209,
+ 48,171,213, 58, 54, 52, 52,180, 63,124, 32,177, 84, 75,254, 45, 43, 95,225,255,191,195,223, 35, 10, 16, 20, 20,132, 53,107,214,
+ 32, 38, 38, 6,207, 62,251, 44,102,204,152, 1,135,195,225,182,252,144, 33, 67, 36,171,213,106,230,121,254,126, 95,120, 1,205,
+249,119, 4,189,141,191,217, 46,225, 82,105, 45,142, 95,174,192,190, 51,197,136,136,155, 70, 73,212, 40,191,136,184,169,207,196,
+175,248, 79,191,235,169,254, 61,182, 75,164, 32, 8,248,252,243,207,177,122,245,106, 0, 64,114,114, 50, 22, 44,112,189,251,145,
+159,159, 31,163,148, 74,140, 49, 13,124, 36,181,160,187, 94,171, 55,243, 63,122,169, 2,155, 50, 12,200, 41, 50,129,202, 82, 99,
+ 90,119, 22, 54,158, 15,157, 50,118,124, 8,165,227, 41,149,151, 37,190,240,245, 22,202,196,215,210,255,184,232,244,255,122,253,
+ 11,158,124,136, 63,252,225, 15, 0,128,216,216, 88,124,241,197, 23,110, 21,160, 25,122,251,146, 66,159,229,127,185,204,140, 55,
+191,205,134,192, 1, 49, 33, 26, 20,148,137, 96,148,130,177, 86, 31, 2, 70,231,129,146, 95, 76,126,118,253,188,140,119, 23, 37,
+119,250,189,111,248, 9, 89, 5,158,245,167,191,121,246, 94,168,120,238,154,235,223, 99, 10, 80, 84, 84,132,146,146, 18,188,249,
+230,155,120,238,185,231,176,120,241,226, 54,203,247,246,172, 10,190,206,255, 68,126, 37, 24,163,120,235,254, 9, 24, 17, 29,140,
+ 63,109, 59,141,189, 89, 69, 96, 13,189, 64,227, 95,214,112, 76, 64,233, 59, 0, 58,173, 0,207,220, 61, 25, 14,201,179, 85,209,
+ 82,248,187, 90,255, 30, 83,128,236,236,108, 68, 68, 68,224,217,103,159, 5, 33, 4,185,185,185, 46,115,234, 52,215,222,250,165,
+136,189,117,113,138, 79,243, 63, 83,104, 2,165, 20, 2, 87,103, 33,168, 56, 82,215, 3,180,248,180, 80,130, 27,110, 90,178,198,
+255,216, 63,150, 90, 58,243, 91, 57,133,229, 40,175,181, 94, 51,103,209, 97,119,235, 59,206, 26, 59, 24, 92,253, 18, 4,187,221,
+ 14, 89,150, 57, 89,150,213, 0, 66,208,118,126,214,234,230,215, 59,164, 0,159,237,205,196,165,146,206,109,120,146,157,150,138,
+232, 81,147,240,202,198, 84, 72, 14, 59,206,156,191,136, 87,190, 78, 1,199,183,222, 56,239, 80, 77, 8, 95, 54,112,234, 72,235,
+ 0,149, 86, 8, 31, 20, 13,144,118,133, 72, 82,227,143,248,114,101,165, 15,245, 0,180,190, 98,125, 50, 63,168, 67,148,193, 40,
+195,138, 47,143,162, 95,152, 22, 57,133,149,117, 2,207, 24, 24,163,160,204,165, 57, 4,217, 95,173, 6,208, 41, 5,200, 51, 86,
+ 33,191,172,250,154, 57,239, 92,247, 49,210,183,111,236, 72, 81, 53,128, 59,235, 63,111,183, 83,246, 70, 0,103, 58,165, 0,250,
+ 17,253,220,238,249,229, 14, 17, 86, 3,138,250,248,225,238, 73,195,240,233, 71,239, 33,208,223, 31, 63,143, 31,225,186,194, 82,
+183,211, 98, 83,126,161,228, 96,167,164,240,129,223, 18,158,111, 63,197, 96,165,214,210, 93,194, 65,171, 12,224, 66, 59, 54,162,
+110, 50,153, 96,179,217, 16, 21, 21,213,252, 52, 67, 83, 94, 32, 31,237,193,234, 4,221,108,151,113,174,200,214, 36,244,148,130,
+ 82,230,214, 20, 2,215,249, 64,225,162, 91,110,236, 22,198,166, 67,201, 72,175,139,242, 32, 34,194,181,252,157, 57,115, 6,181,
+181,181, 13,141, 80, 25, 99, 44,215,205,237, 70, 1,173,246,153,232,152, 2,140,236,167,235,188, 61, 80, 58, 4, 63, 92,202, 65,
+148,202,129, 13,159,125,130, 25, 51,102, 96,242,176,104,151,101,163, 84, 14,234, 95,109, 40,179,150,151, 95,172,201,220,123, 8,
+ 61,156, 98,220,113, 98, 61,184,136, 17, 80,199,253,162,221,178, 85, 85, 85,152, 59,119, 46,118,239,222,221,242,165, 80, 95,115,
+130, 25, 99, 16,229, 58,125, 92,126,199, 72,136,242, 8,103,253,100,117,255, 63,248,167,173,204, 14,129,184, 50,133, 0,128, 93,
+125,186, 97,177,139, 68,162,255, 42,181,247,187,203,255,189, 27, 39, 47,151, 92,187,227,158, 86,183, 59, 46, 55,106, 6,248,113,
+ 83,157,174,237,122,105, 1,212, 2,143,105,211,166, 33, 61, 61, 29, 0,160,209,104,126,176,217,108, 15,187,145,159, 61, 0,102,
+244,152, 15, 48, 96,192, 0, 28, 59,118, 12,219,183,111,135,205,102,195,252,249,243,219,109,136,235,109,104,175,180,142,246,148,
+ 15, 64, 56, 30,170,209, 63,111,183,244,217,179,103,113,199, 29,119, 96,231,206,157,232,211,167,143, 15,240,119,150,233,140,188,
+ 10,164,158, 47, 65, 70, 94, 57,204, 86, 7, 40,149, 91,181,240, 78,231,160, 34, 13, 38, 80, 75, 83,232,181,159, 93,137, 4,112,
+174,241, 25,175,254,238, 44,152,188,140,196,172,118,155,175,245,131, 71,110,235,150,103,121,222,122, 18,239,103,236,192,138,123,
+226,241,240,195,191,236,136,194,119,186,225,236,144, 2, 56, 36, 25,148,117,174,103, 55,219,108,216,187,119, 47,100, 89, 70,100,
+100, 36,102,205,254, 25,108,162,228, 38,118, 72, 64,121, 1,208,104, 57,220,189,212, 15,186,232,246, 31,100,237, 43,246,142,248,
+ 10,157, 81, 2,219, 79,127, 5, 8, 15,213,168,187,218, 45,157,149,149,133, 59,239,188, 19, 59,119, 54,238,236,234, 19, 81,160,
+ 79,246,229,226,199,204,162, 38, 97,111, 33,216, 77, 2,206,156,237,125, 23,166, 80,235, 42,162, 28,152,116, 35,152,252, 29, 51,
+ 44, 25, 72, 6,252,163,194, 21,135,175,211,114, 96,232, 6, 31,224,104,110,221,252,182, 31, 79, 94, 66,217,119,206, 43, 33,127,
+119,215,205,224,185, 86,238,150,103, 20,224,181, 77,169,157,138,235, 58,204,213, 72, 91,243, 18, 26, 50, 5, 14,152,181, 24,143,
+253, 99,143,251, 22,181, 50, 92, 85, 26, 59,123,170, 72, 84,163, 4, 77,240, 47, 96,110,223,142,150, 22,190,189, 24, 27, 96,236,
+238,158,192,118,224,207, 0,199, 67, 53, 98,118,187,165, 51, 51, 51, 49,123,246,108, 76,154, 52, 9,245,137,182,188,170, 0, 57,
+ 87,107,240,227,233,171,237, 10,182,187,191,172,222,236,113, 45,252, 18,192,228,186, 15,149, 2,192,228,223, 0,120,195,165, 73,
+ 27,226,223, 24,161,185, 22,204,152, 53, 27, 67, 6, 13, 68,220,164,201,232, 31, 17,210, 34,232,224,218,138,104,227,118, 31, 3,
+216, 6,160,184,211, 10,240,214,194, 91, 58, 69,124,225,194,133,176, 86,214,217,128, 43, 86,172,192, 27,111,188,209,102,249,167,
+159,126,218,177,235,232,174, 93,165,165,165,187, 42, 42, 42,190,132, 87,183, 25, 98,176,237,255, 35, 8,199, 67, 24, 62,171,221,
+210, 39, 78,156, 64, 97, 97,161, 42, 40, 40,136,247,182, 15,176,247,140,177, 93,193,102, 45,206, 57,149,173,239, 33,154,161,118,
+214,232,138, 64, 48, 9,160,178,179, 18, 48,233,255,220, 41,192,164,161,125, 33,201,215,254, 10,111, 31, 59, 8,192,189, 46,175,
+185, 81,176,182, 26,206, 45, 93,238, 1, 58,131, 77,155, 54, 97,243,230,205, 0,128,233,211,167, 99,220,184,113, 29, 14, 35,250,
+130, 13, 93,223,213,195,186,247,109,104, 9, 15, 97,216,204,118,139,151,148,148,112, 85, 85, 85, 51,181, 90,237, 78,111,210, 46,
+ 40, 51,183, 22,108, 39,211,135,181,109, 10, 81,218,232, 24,215,139,211, 14, 63, 34,198,131,214, 11,190,179, 18,244,101,185,247,
+ 69, 76, 93, 92,236,210, 98,200,204,247,236, 72,240,182, 23,230, 65, 45,240, 61,227, 3,116, 20, 70,163, 17,203,150, 45, 3, 0,
+ 60,245,212, 83, 88,190,124, 57,222,127,255,125,220,119,223,125,237, 9,191,207,216,208, 78, 74,176,231, 13,104, 57, 30, 66,236,
+244,246,205, 62,135, 35, 66,146,164, 21, 0, 54,163,110,176,165,199, 81,108,178,180, 22,236, 86,145,157, 54, 76, 32,103, 63,239,
+220,188,201,149,175,129,138, 59,235, 91,252,230, 38, 80,195,255,195, 93,241,248,243,131,183,122,235,173,121, 70, 1, 58, 58, 16,
+182,229,253,151, 80, 94, 94,142,126,195,227,224, 55,241,110,124,188,247, 44, 54,126,247, 3, 28, 3, 39, 35,172,175,251, 73,134,
+233, 53,193, 66,241,128, 91, 38, 89, 7,106,116, 66,112,244, 77, 62, 51, 16,198, 40,172,187, 95,131,246,118, 30,194,144,169,237,
+215, 62,165, 35,234,237,204,159, 1, 48,247,228,155,183,139, 50,202,170,173,109, 10, 56, 24,197,168,126, 97, 24, 30, 19, 10,127,
+ 53, 95,175, 36, 12,187,247,236,145, 10,140,101,217, 18,175,189,164, 14, 31,144, 77,128,172,111,127,115,246,252,128, 80,219, 23,
+ 96, 82,180,139,214, 31,245,102,209, 48, 87,202,254,238,119, 25, 56, 95, 84,225,209,231,253,248,241, 89,174,230, 2,121, 70, 1,
+166,223, 56, 16,147,134, 58,218,142,138,156, 58,129, 11,199,211,160,235, 19,129,127,253,123, 45, 34,162,250,226,245,149,207,162,
+164, 32, 23,255,120,254, 33, 68,247,235,143, 71,150, 62,137, 95, 44, 92,212,186,235, 78,219, 78, 75,170, 46, 94,144,236, 72,167,
+129,186,253,224, 85,237, 63,136, 40,246,140,128, 81, 25,214, 93,175, 64,123,199, 27, 16, 6, 37,118,228, 27,183,212, 43,193, 28,
+ 0,214,158, 82, 0,158, 35, 0, 99,110,109,252,176, 64, 53,126, 63,111, 18,110, 30, 80, 14, 34, 93, 6, 88,211,134,246, 55,251,
+149, 18,201, 94,174,234, 19, 74,252, 71, 13,171,138, 38,160,119,130, 74,227, 65,101,190,141,214, 31, 96, 82,128, 43, 5, 88,144,
+ 56, 10, 86,187,103,115, 4, 11,174, 7,232,152, 71, 20, 32, 54, 42,180,221, 50, 23,143,213,201,227,250,117, 95, 96,230,228,177,
+ 88,191,126, 61,190,251,230,171,198,235, 87, 11,175,224,237,151, 95,192,200,193, 49,120,224,129, 7,156,190,219, 71, 37,202, 1,
+181, 87, 75,106,141,198,139,181,153,123, 79,194,215,246,218,165, 18,172, 59, 95,134,118,214,155, 0, 58, 52, 71,253, 86, 0,223,
+ 1,184, 27,128,173, 39, 40, 10, 60,135,240, 0, 21, 74, 76, 98, 43, 27,159,128,225,181, 7,166, 96, 92,216, 15,224,106,178, 90,
+125, 87, 63, 30, 60, 88,232,104, 80,121,180,139, 86, 30,173,148,160, 73, 17,114, 80, 55,247,198, 9,102,155, 3,213, 86,199,255,
+142, 9,212, 17,148,151,151, 35, 52, 52, 20, 51,103,214, 57,141,111,189,245, 22,198,141, 27,135,249,243,231, 35, 47, 47, 15, 35,
+ 71,142,196, 59,239,188,131, 23, 95,124,177,149, 2, 52,115, 96,124,119, 54,168, 44,194,150,242, 30,144,240,118, 71,191,113, 27,
+128,135, 0,252,163,167, 40,246, 13,209,194, 88, 89,219,202,244,153,114, 67, 20,198, 70, 21,128,171,205,114,209,102,182, 16,112,
+ 87,166,142,203,243, 50, 64,165,179, 0,166,180,188,229,206, 83,151,112,161,216,179,214,233,196, 33, 81, 16,122,202, 4,170,181,
+ 57,218, 13,107,197, 12, 28,140, 81,163,111, 68,149,217,134,146, 18, 35,114,115,115,241,205,214,239, 16, 63, 37, 1,143, 62,180,
+ 8,171,222,125, 15, 34, 5,126,191,226, 57,100,229, 92, 64,255, 1, 77,115,111,236,148, 16, 89,229,175,146, 2,250,248,225,230,
+135, 67,161, 13,110,255, 65,198,163, 26,175,190,218, 99, 61, 5,231,175,131,118,206,187, 40, 55,117,184,151,125,191, 39,133, 31,
+ 0,134, 68, 4,226,100, 94, 73,171,112,231,232, 1,225, 32,226,233,214,214, 66, 91,173, 60,117,161, 4,206,231,175,144,184,148,
+226,164,164,164, 86, 60,150,253,108,146,119,226, 22,158,138, 2,253,101,219, 17,100, 27,218, 14,107,201, 14, 59, 78, 95,184,132,
+ 37,107,118,128,202, 18,180, 33, 58,124,145, 85,131,245, 57,251,144,117,165, 2, 75,214,236,128,100,139, 0, 39,168,240,252,231,
+ 59, 17, 24,209,228, 20,103, 85,135,169,138, 7,207,184,205, 65,212, 99, 4, 77,224, 67, 29,114,130, 79, 9, 75, 0,148,244,152,
+240,207,253, 0, 92,232, 64,192,148,223, 81,225,255, 93, 79, 11,192,188,248,193,248,238, 72, 30,100,217, 57,220, 25,232,167, 2,
+161,181, 78,206,125,199, 90,249,230,202,209,226, 26,240, 23,119, 60,126,253,207,157, 56,158,231,217, 44, 43, 7,223,248, 85,171,
+ 48,168,199,122,128, 87,238,239,144,243,135,249,199, 55,227, 47,247,223,132, 1, 3, 6,224, 29,249, 34,180,154, 34, 44, 95,190,
+ 28,203,243,247,225,165,135,146,224,231,231,135, 81,127, 95,129,109,111, 62, 1,190,217,180,232,103,158, 57,232,216,115,108, 79,
+178,209,104,252,161,188,188,124,191, 47,249, 0, 78,194,223, 49,124,224, 13,225, 7,128,200, 16, 45,102,143, 31,128,173,135,115,
+157, 28, 96,231, 9,112,157,106,229, 91, 40,135,220,240,106, 74,219,234,221,254,254,248, 44,175,188,171,102,251,187,245,188, 15,
+ 0, 0,127,255,251,223,241,252,243,207,227,239,127,255, 59, 94,120,225, 5, 36, 39, 39, 67,146, 36,140, 27, 55, 14,199,143, 31,
+ 71,126,126, 62,238,184,227, 14, 39,225,111,230,189,203,148, 82,159,154, 78,220, 89,225,231,121,254, 27, 89,150,127,231, 77,206,
+191,190, 35, 14,126, 42, 14, 7, 78, 27, 80, 92, 89, 11, 6, 82, 63,106, 74, 1, 38,186,108,229,101, 81, 6,152, 36, 19, 34, 83,
+ 14, 50,117,171, 4,117, 14,253, 81, 0,207,146,184, 84,183,211,209,119,158,186,132, 18,147,197,163,207,185, 48,105,116,171,185,
+ 64,245, 38, 16,243,154, 2,232,116, 58,188,248,226,139, 88,185,114, 37,238,186,235, 46,220,123,111,221, 48,246,152, 49, 99,240,
+250,235,175,227,198, 27,111,196,154, 53,107,220,105, 47,245,165,129,176,206, 10,127, 80, 80,208, 17,149, 74,245, 65, 69, 69,133,
+ 87,121,171, 4, 14, 75,102,197, 97,201,172, 22, 9,148, 77,123, 1, 42,186, 52,117,254,181, 45,216,158,113,228,196,231,209, 97,
+214,159, 94,249, 77,255,227, 42,158,177,102,189,193,121, 18,119,176, 83, 61,178, 40, 83,183, 19, 31,123,101, 20,232,147,157, 39,
+144,107,172,234, 56,139,209,183,227,131,173, 7,241,202,223,214,163,232, 66, 54,170,203,141,144, 28,118,140,184,255,183,120,225,
+203,159, 90,219,115,213, 33,234, 43, 3,111,157,105, 25,172, 29, 42,248,135,221,215,145, 69, 85, 18, 52,175, 99,211,211, 21,190,
+ 32,252,227,198,141,147, 36, 73,218, 89, 88, 88,232, 91,225,219, 22,161,220,186, 86,189,181,169,179,244,238, 18,205,210,187,162,
+150,128,201, 75, 90,181,254, 96, 97, 0,170, 58,243, 83,115, 38, 14,245,150, 19,236, 25, 19,104,214,184, 33,168,181,117, 50,174,
+123,155,243, 62, 6, 75, 23,221,143,135,166,141,113, 89,180,228,200,143, 82, 85,213,197,147,146,168, 74,113, 12,158,156, 5,194,
+117,224, 65,170,107,125, 65,248,151, 45, 91, 6,198,152, 99,223,190,125, 62,190,168, 95,114,107, 2, 57, 69,129, 84,209,102, 16,
+129,192,122,222,191,203,102, 88, 39,157,224,221, 47, 63,128, 32,173,218,119,123,128,142, 12,132,181,135, 49,163, 70, 96,236,160,
+ 72,151,215,250,168, 68, 57,168,182,176,168,186,176,240,172,249,232,182,147,222,242, 3,186, 34,252,239,190,251, 46,158,121,230,
+ 25,230,107, 38, 92,235,214,145, 7,105, 48,129,220,216,248,148,105,109, 92,236,218, 0, 16, 14,184,176,160, 22,142, 66,127, 0,
+246, 78,251,130, 94,114,130,225,205,129,176,230, 56,113,226, 4,190,252,242, 75, 76,157, 58, 21,115,231,206, 5, 0, 12, 29, 58,
+ 20,178, 44,187,114,128, 27, 39,195,213, 59,193,232, 77,194,239, 43,252,219, 85, 0,213, 96,192,156,222,102,180,135, 48,137,135,
+ 92, 13,112, 26, 64,174, 38, 0, 78,146,184, 84,171,175, 61,203,246,237,219, 81, 88, 88, 8, 0, 40, 46,110,234,105, 40,165, 19,
+209,148, 31,116, 63,128,156, 30, 87, 0, 74, 41,230,205,155,135, 43, 87,174,224,227,143, 63,198,241,227,199, 49,114,228, 72,132,
+132,132,192,106,181, 34, 48, 48,208,149,237,230, 85, 39,152,248,247,233,178,240,251, 2,255, 14,189,151,192, 89,224, 44,135, 64,
+172,103, 93,155, 64,160, 32,128, 10,231,127,110, 7, 56, 6, 38,137, 0,150,250,226,179,172, 94,189, 26,251,246,237,115, 37,123,
+115, 80, 55, 7, 11, 0, 30,243,138, 2,212,214,214,226,202,149, 43,141,202,208,208,226, 23, 23, 23, 67, 20, 69,119, 17, 32, 48,
+198,168,220,176,132,172,135,161,185,249, 49,128,227, 59, 84,182, 95,191,126, 78,194,239, 11,252, 59,166,229, 42, 72, 81,175,131,
+ 51,167,129,171, 88, 7, 98,191,220,220,209,109,214, 26,201,118, 64,126, 15,192,123, 36, 46,213,228,139,143,242,231, 63,255, 25,
+149,149, 77, 83, 45,254,246,183,191,217, 14, 31, 62,188,174,180,180, 52, 77, 20,197,252,250, 7,202,233,200,189,186, 93, 1,130,
+131,131,113,251,237,183, 35, 59, 59, 27,159,127,254, 57,134, 15, 31,142,140,140, 12, 24,141, 70,132,133,133,185,127, 63,222,204,
+172,214, 65,225, 7,220,231,172,236, 29,153,237, 8,104, 64, 34,104, 64, 34, 32, 87,129, 56, 10, 64, 28, 6,108,217,188,209,158,
+151,119,225,115,115,109,229, 87, 99,134, 9, 63,205,127,250,156, 79, 63,199,216,177, 99,157,142,183,109,219, 38,231,230,230, 94,
+ 48,155,205,135, 76, 38,211,185,206,248,144, 30,241, 1, 54,110,220,136,215, 94,123, 13,159,125,246, 25,190,255,254,123,232,116,
+ 58,124,240,193, 7,237,125,173, 87,167, 70,236,117,252,249, 80, 48,109, 40,152,118, 44, 82,206,236,147,246,239,207, 62, 87, 80,
+ 80,126,165,170,170,138, 94, 79,245, 47, 0,128,201,100, 18, 50, 50,186,119,255,228,150,171,192, 78,158, 60,233,182,172,201,100,
+226, 9, 33, 93, 54, 33, 60,193,191,147,191,175,240,239,165,252, 5, 0,198,226,226,226, 83,171, 86,173,226,237,118,123, 52, 99,
+ 76, 13,128,213, 71, 54, 88,179, 15,234,207, 55,254,223,242,154,187,235, 45,238,213,178, 44,147,101, 89,150, 36,169,164, 62,189,
+ 96,103, 67,160, 10,127,133,127,151,249, 55, 31,114,229,116, 58,221,114, 0,125,209,148,229, 76,102,140, 73,132, 16,153, 49, 38,
+ 19, 66,164,102,231,104,179,107, 13,231,101, 66,136, 84,191,184, 93,110,184, 70, 8,145, 41,165, 82,139, 99,185,193,110,166,148,
+ 74,178, 44, 75,140, 49,139,217,108,190,210, 85, 75, 94,225,175,240,239, 44,255,230, 10, 64, 2, 3, 3,163, 57,142, 83, 19, 66,
+152, 74,165,130, 40,138,141, 90,214,160,133,205,143,235, 67,127, 12, 0, 28, 14,135,147, 6, 19, 66, 88,179, 79, 67, 89, 88, 44,
+ 22,167,123,112, 28,199, 8, 33,172,178,178,146,213, 87, 90, 87,215,210, 41,252, 21,254,157,230, 79,218, 57,238, 40,124,101, 6,
+167,194, 95,225,223, 35,132,187, 5, 73, 73, 73, 2,128,217, 28,199,221,247,211, 79, 63, 45,238,109, 97, 7,133, 63,144,148,148,
+ 52, 90, 16,132, 71, 8, 33,221, 46, 75,140,177,112, 89,150,135, 51,198, 94, 78, 73, 73,217,231,137, 58, 16,186,169, 34,251, 1,
+ 40, 79, 73, 73,177,117,176,252,120,181, 90,189,132, 49,246, 43,157, 78,199,149,149,149, 9, 0, 22,123, 81, 16, 20,254, 93,231,
+127, 67,100,100,228,147,115,230,204,241,235,206,103,202,206,206,198,169, 83,167, 16, 25, 25, 9,131,193,176, 59, 41, 41,105, 90,
+ 74, 74, 74,138,207, 40, 64, 82, 82, 82, 8,128,121, 90,173,246,215, 14,135, 99,188, 32, 8, 59,146,146,146,230,166,164,164, 48,
+ 55,229, 35, 57,142,123, 80,173, 86,255,159, 32, 8, 81,241,241,241,154, 73,147, 38, 9, 90,173, 22,111,190,249,166,205, 11, 66,
+163,240,239, 38,254,209,209,209,246,133, 11, 23,118,155, 2,108,218,180, 9, 6,131, 1,143, 62,250, 40, 56,142,195,193,131, 7,
+185,204,204,204, 3,137,137,137, 9,169,169,169, 25, 94, 83,128,164,164, 36, 53,128,217,126,126,126, 75,101, 89,158, 62,108,216,
+ 48, 41, 62, 62, 62,104,232,208,161, 88,179,102,205,173, 37, 37, 37,239, 2,120,166, 69,249,185, 90,173,246, 73, 73,146,226,227,
+226,226,104,124,124,188,255,224,193,131, 27, 38,144,193,106,181,246,164,208, 40,252,189,200,191, 35,144, 36, 9,235,215,175,199,
+210,165, 75, 17, 22, 22,134,218,218, 90, 36, 38, 38,130, 82,202,101,101,101,165,235,245,250,155,211,210,210,142,247,152, 2, 36,
+ 37, 37, 17, 0, 73, 26,141,230, 49, 74,233,188,190,125,251,202, 83,166, 76, 9,137,139,139,131,159, 95,147,210, 63,246,216, 99,
+ 1,239,189,247,222, 19,183,220,114, 75, 14,165,244,148, 70,163, 89, 74, 41,157, 31, 19, 19, 67, 19, 18, 18,130,227,226,226,160,
+ 82,169,188, 97, 30, 40,252,189,200,191,179, 48, 24, 12, 8, 14, 14,110,220,124, 68,171,213, 66,150,101,232,245,122, 72,146,196,
+229,228,228,100,232,245,250,241,105,105,105, 89, 30, 85,128,122,231,102, 49,199,113,143, 6, 6, 6,170,227,227,227, 3, 38, 76,
+152,192,135,132,132,184, 44,239,239,239,143, 37, 75,150,248,175, 94,189,250, 35,173, 86,235,152, 50,101,138,118,226,196,137,124,
+104,104,104,183, 85,206,244,233,211,251,216,237,118,154,158,158, 94,209, 1,193, 81,248,123,145,127, 87, 81, 88, 88, 8,157,174,
+105, 71, 34,141, 70, 3, 89,150, 33,203, 50, 18, 19, 19, 33,203, 50,127,225,194,133, 19, 9, 9, 9, 55,166,167,167,159,239, 86,
+ 5, 72, 74, 74,138,225, 56,238, 87,106,181,122, 9,199,113, 49,147, 38, 77, 18,110,186,233, 38,117,223,190,125, 59,116,179,136,
+136, 8,172, 92,185, 82,237,239,239,175,238,206, 74, 73, 76, 76, 28, 17, 16, 16,176,210,110,183,223, 86, 93, 93, 29,219,134,208,
+ 40,252,189,200,191, 59, 16, 24, 24,216,202, 44,243,247,247,111,220,212, 59, 41, 41, 9,178, 44, 11,151, 46, 93,202,210,235,245,
+ 35,211,210,210,242,186, 69, 1,146,146,146, 18, 4, 65,216, 59,102,204, 24,122,243,205, 55,251,199,198,198,162, 43,145, 45,127,
+127,255,110,171,140,169, 83,167, 78, 11, 8, 8,120,153, 82,154, 16, 16, 16,160,150,101,249,163,236,236,108,135, 27,225, 81,248,
+123,145,127,119, 65,167,211,193,100,106, 61, 11,187,193, 20,146,101,185, 65, 9, 84, 5, 5, 5,103,245,122,253,176,180,180, 52,
+195, 53, 43,128,159,159,223,107,208,238,250,153, 0, 0, 20,252, 73, 68, 65, 84,119,222,121,167, 58, 33, 33,129,131, 23, 49,125,
+250,116, 65,150,229,251,252,253,253, 95,241,247,247,239,255,224,131, 15, 6, 76,159, 62,157, 44, 88,176,192,102,177, 88, 62,114,
+247, 61,133,191,119,249,119, 23,162,162,162, 80, 83, 83, 3,171,213, 10,173, 86, 11,160,110, 99,194,210,210, 82,148,151,151,163,
+180,180, 20, 22,139, 5,131, 7, 15,134, 40,138,234,171, 87,175,158,215,235,245, 67,210,210,210,138,187,172, 0, 73, 73, 73, 35,
+ 1, 36, 77,154, 52,201,107,149, 31, 31, 31, 31,172,209,104,150, 8,130,176, 98,232,208,161,154,135, 30,122, 40,104,202,148, 41,
+ 32,132, 96,247,238,221, 16, 4,225, 84,122,122,250, 69, 55,173,167,194,223,139,252,187, 19,106,181, 26,227,199,143, 71, 78, 78,
+ 14,116, 58, 29, 14, 28, 56,128,130,130, 2,196,198,198, 34, 42, 42, 10, 67,135, 14, 5,207,243, 72, 77, 77,133,209,104,132, 40,
+138,126, 26,141, 38, 79,175,215, 15, 74, 75, 75, 43,237,146, 2,104, 52,154,151,166, 78,157,170,242, 70,148,160,186,186, 26, 28,
+199,169, 2, 3, 3,139, 38, 79,158,140, 95,253,234, 87, 1, 55,220,112,131, 83,153,111,190,249,166,166,182,182,246,207,238,238,
+161,240,119,195,205, 38,225,167,139,165, 40,169,113, 64, 45,112, 80,243, 4,106,158,131, 70,224, 48, 97, 64, 40,250, 6,251,117,
+ 11,255,238,198,180,105,211,240,233,167,159, 66, 20, 69, 60,254,248,227,152, 57,115, 38,212,106,103,183,102,209,162, 69, 48,153,
+ 76, 88,183,110, 29,182,108,217,162,165,148,190,137,166,245,192, 29, 87,128,164,164,164,104, 74,233,189,122,189, 94,232, 73,193,
+ 41, 44, 44, 68, 74, 74, 10,206,157, 59,135, 57,115,230,240, 11, 22, 44, 8,136,140,108,157, 53, 34, 63, 63, 31, 5, 5, 5,148,
+231,249,111,221,180,158, 94,231, 63,243,206,159,241,139,127,249,128, 79,240,183, 75, 20,169,121,229,216,157, 83,130,140,252, 74,
+136,110,146, 26, 19, 0, 3, 53,118,220,104,207,198, 67,119, 37,240,183,205,127, 34, 32, 50, 50,170,211,252, 61,129,132,132, 4,
+124,253,245,215,120,227,141, 55, 16, 19,227, 62, 29,125, 72, 72, 8,158,124,242, 73,108,223,190,157,213,212,212,140, 13, 13, 13,
+237, 95, 85, 85,117,165, 51, 74, 32,168,213,234,231,110,186,233, 38,174, 59,157, 39,119, 96,140, 33, 39, 39, 7,169,169,169,168,
+172,172,196,125,247,221,135,215, 95,127,189, 77,199, 45, 57, 57,217,193, 24, 91,179,127,255,126,201, 77,151,233, 85,254,137,243,
+ 30,197,211,235,126,194, 61,178, 10,145, 94,228,207, 24,240,245,113, 3,214, 30, 42,128, 85,108,127, 93, 8, 3,144,111,215,224,
+151,131,181,184, 91,216, 3,203,119,199, 96, 31, 57, 3,252,144,169, 16,162,199, 55, 46, 19,109,143,191, 39, 16, 20, 20,132, 53,
+107,214,184, 93,126,218, 18, 67,134, 12,145, 12, 6,131,153,231,249,251, 81,151,152,184,227, 10,192,243,252,207, 39, 77,154,164,
+241,228, 3, 73,146,132, 99,199,142, 33, 45, 45, 13, 1, 1, 1, 88,184,112, 33,166, 77,155,230, 50, 69,138, 83,107,102,183, 99,
+231,206,157,212,106,181,254,205, 93, 25,111,242,207,200, 45,198, 93,171,190,129,213, 33,225,238,119,190,193,190, 87, 23, 34, 58,
+ 44,176,199,249,151,155, 29,120,251,199,115, 56, 90,208,249,156,252, 19, 2,235,190,227, 47, 85,193,145,181, 5,200,218, 2,226,
+ 23, 12, 97,144, 30,108,128, 30,251,246,180,205,223, 83,232,168,240,215, 7, 16, 24,165, 84, 98,140,105,208,201, 9,158, 2, 0,
+194,113,158,241,189,204,102, 51,210,211,211,113,248,240, 97,140, 26, 53, 10, 43, 86,172,232,240,174,145, 0,176,111,223, 62, 8,
+130,112, 36, 45, 45,173,173,156,228, 94,225,159,109, 40,195,188,119,183,194,234,168,107, 24, 11,202,170,113,239,159,147,177,243,
+165,249, 8,214,106,122,140,191,201, 38,225,183,155, 51, 81, 80,209,249,100,180, 4,192,248,160,214, 89, 15,153,173, 26,226,185,
+ 29,192,185, 29,248,247,108,162, 82, 17,246, 23,242,192,148,100,104,196,239,195,151, 30,243,201, 76, 17,245,232,218,154,224,238,
+ 70,105,105, 41, 82, 83, 83,145,153,153,137,105,211,166,225,195, 15, 63,196,128,102, 27, 98,116, 20, 61,237,124,117,148,127, 65,
+ 89, 53,230,190,243, 13,170,204,206,115,200, 50,243, 75,176,240,253,109, 72,126,238, 94,168, 5,222,227,252,173,162,140,231,147,
+ 79,119, 73,248, 1, 32, 86, 91,139, 16,161,237,245, 35, 42,142,241, 0,230, 49, 96, 58,236,170,229,229, 31, 76,249, 74,144,201,
+218,144,167,211,189,155, 5,152, 81,128, 52, 53, 28, 93,205,202,209,173, 10,144,151,151,135,148,148, 20, 20, 22, 22, 98,238,220,
+185,120,238,185,231,208,213,161,248,220,220, 92, 92,189,122, 85,140,142,142,254,111, 79,213,105, 71,248,151,152, 44,152,179,106,
+ 19,174, 86,185,222,163,111, 95, 86, 62,150,124,178, 3, 47,222, 57,210,227,252,255,153,122, 25, 57,198,154,182, 91,121, 2,232,
+ 71,244, 71, 76, 88, 0,204, 54, 17,149,102, 59, 14, 95, 40, 2,101, 12, 19,130, 42,219,234,151,144,122,133,179,199,199,208, 39,
+ 52, 4, 7, 67,151,165,229,250, 66, 19, 79, 45,229,176,253,176, 18,204, 82, 6,245,228, 37, 80,141,184,163,177,245,175, 95, 74,
+217,233,244,232,215,180, 26,135, 82,138,204,204, 76,164,166,166, 66,150,101, 60,240,192, 3,184,253,246,219, 91,133,173, 58,139,
+173, 91,183,218, 41,165, 31,111,218,180,169, 61,173,238, 49,254, 53, 86, 7,238,249,211, 22,228, 22,183,157, 44,121, 99,122, 14,
+ 12,185, 57,178,218,131,252, 47,150,214, 34,249, 84,161,219,235,129,126,106,172,184, 39, 30, 11, 18, 71,161,127,120,144,211,181,
+203, 37, 38,124,180,227, 56, 6, 95,106, 61,159,204, 6, 13,252, 96, 7, 24,197,153, 50, 97,227,220, 63,166,172,245, 37, 27,135,
+ 85, 23, 65,174,200,173,219,179,109,223,219, 16,179,147, 17,227, 7, 82,191, 32,158,118,197, 7,232, 18, 28, 14, 7, 14, 29, 58,
+132,244,244,116,244,239,223, 31, 79, 60,241, 4,226,227,227,209, 29, 11,131,108, 54, 27,246,236,217,195,108, 54,219, 39,158,170,
+200,206,242,183,139, 50, 22,188,247, 45, 78, 94, 54,118,232,254,233, 37,224, 53, 33,137, 20,216,227, 17,254,255, 72,201, 3,117,
+163, 58,209, 97,129,216,242,236,189, 24, 55,216,117, 50,226,193,145, 33,120,247,161, 91, 81,242,229, 23, 78,155,156,214,112, 65,
+ 8,162, 77, 61,202,226, 56,199,224, 23,124,204,200,231,251,142,129,118,214, 27,176,238,124, 9,144, 69,200, 37,103,241,255, 6,
+ 16,149,223, 20,255,193,111,109, 39, 93,234, 1,186,132,109,219,182,129, 82,138, 85,171, 86, 97,248,240,225,221,250,144,123,246,
+236,129, 32, 8,169,169,169,169, 69,158,170,200,206,240,167,140,225,145,143,183, 99,127,118, 65,167,126,195,206,107, 95,230,231,
+175, 58, 39,111, 92,185,161, 59,185,151,155, 29,200,200,175,116,217,216, 13,208, 5, 97,247, 43, 11, 49, 64, 23,212,142,187, 40,
+ 66,107,174,123, 30, 17, 2,100,162,114, 18,126, 0, 80,243,152, 90,249,158,126,124,216,239,210, 78,250,146, 18, 8,131,244,208,
+206,122, 3,182,157, 47,131,201, 14,240,132, 97,241, 36,191,113, 83, 6, 14,122, 88, 16,134,173,155,252,234,225,234,142,222,139,
+ 67, 23,246, 21, 48,155,205,200,204,204,196,202,149, 43,187, 93,248, 27,156, 95,179,217,220, 81,231,209,227,252,151,125,182, 27,
+ 91,143, 92,232,202,163, 16,194,176, 86,184,127,213,140,238,228,191, 35,171, 16,204, 77, 79,255,135,121,250,246,133, 31,128, 92,
+ 94,103, 70,128, 87, 33, 48,225, 9,248, 49,215, 11, 99, 40, 47,223,235,139,225, 30, 97,144, 30,126,179,255, 8,162,210, 54,158,
+ 27, 17,169,158, 52, 52,156, 28, 42,251, 48, 97,164, 71,123,128,163, 71,143, 34, 33, 33,161,205, 92,159, 93,197,185,115,231, 80,
+ 82, 82, 98, 59,120,240,224, 78, 79, 85, 94,103,248,191,254, 77, 42, 62,219,155,121, 45, 63,167, 6,144,172, 90,240,206, 45,226,
+215, 47,156,234, 14,254,169,103, 93, 79,126, 28,216, 39, 24, 11,147, 70,119, 44, 94, 88,114, 6, 32, 28,180,183,191, 6, 97,112,
+ 18,196,236,100,208,106, 23, 62, 5, 35, 9, 61,102,223,215,150, 64, 42, 60, 6, 72,118, 48, 89, 4,100, 7, 24, 21, 65,168, 4,
+230,176,130, 57,106,193, 28,181,128,104, 1,179,155,235,254,111,189, 51,234, 40,194,216,225,242, 15, 19,230,235,158, 74,255,177,
+219, 21,128, 82,138,140,140, 12,188,252,242,203, 30,169,132,173, 91,183,218, 68, 81,252, 0, 30, 74,149,209, 25,254,127,251,241,
+ 56,222, 73, 62,212,120, 28,164, 85, 99, 70,220, 32,216, 68, 9, 63,158,188,228,186, 66, 9, 16,224,168, 56,100, 82,133,107, 0,
+ 76,168, 63, 29,204, 40,251,193,239,129, 85,122,219, 87, 43, 47, 95, 43,255,203,149, 86,128,104, 91, 93, 91,116,203,141, 80,241,
+ 29, 27, 83,160, 37,103,161,137, 95, 10, 97,112,221, 62,191,170,225, 51, 97, 63,246,133,139, 62, 12, 61,178,233,175,116, 97, 39,
+172,123,223,118, 37,208, 93, 65, 48, 24,219, 94,241, 97,252,178,240,167, 14,255,173, 61, 19,168, 83, 56,127,254, 60,130,130,130,
+ 16, 23, 23,215,237,149, 96,177, 88,176,127,255,126, 56, 28,142,127,122,170,162, 59,202,255,235,180, 28, 60,183,110, 31,162,195,
+ 2,241,248,109,227,240,237,138,121, 48,124,242,127,216,240,219,185,109,239,129, 69, 37,140, 40, 73,253,185,180,105,229, 68, 9,
+100, 16, 1,158, 2,176, 27, 64,164, 36, 99, 7,238,125, 91,119,173,252, 45,196,245,250,243,168,144,128,142,219,102,234, 0,168,
+199, 63,208, 36, 8, 49, 19,221, 21, 13,233, 9, 5, 16,207,239,236, 46,225,111,244,151, 25, 35, 31,151,127,144,240, 62,123,213,
+189,156, 11,157,221, 91,245,240,225,195,248,197, 47,126,225,145, 74,216,181,107, 23, 83,171,213,123,247,236,217,211,225, 13,176,
+ 61,193,127, 87,230,101,252,117, 91, 6,214, 44,189, 19, 11,244,163, 58,220,170, 2, 0, 3,145,210,210,210,234,248,111,122,161,
+ 64, 4, 62, 2,240,145,102,193,159,134, 74,178,252,172, 32,112,155,164,251,255, 58, 7,155,158,182,118,149,191,138,143,133, 67,
+110,253,181,176, 64,103,197, 56,124,161, 8,195,163,195, 17,222,226, 60, 24,133,122,226,131,206, 78,180,228, 54, 49, 4,199, 54,
+222,207,147,249,155, 60,154,249,218,111,198,139,144, 75,178, 1,209, 10, 38, 90,193, 28, 22,192, 81, 3,106, 53,129,150,157,131,
+ 92,226, 58,221, 63, 31, 58, 16,124,248, 96, 64,208,128, 89, 42, 32, 22,157,172,223,240,163, 65, 64,216,242,242,176, 41, 67, 75,
+ 62,246, 91, 24,249,155,253,181, 93, 54,129, 24, 99, 40, 47, 47, 71, 65, 65, 1,110,187,237, 54,143, 84,194,166, 77,155,204,213,
+213,213,239,122,196,190,236, 32,127,179, 93,132,192, 17, 28,122,251, 33,116, 37,162, 75, 9,231,114, 79, 45,251,215,207,231, 2,
+248, 53, 22,190, 21, 37,136,142, 9, 18,144,214, 85,254, 1,125, 71,194, 97,110,253, 51,205,103,126,214,218, 28,120,107, 75, 58,
+190, 91, 49,207, 69,171,193,129,248, 59,119, 68,204,230, 54,112, 34,226,204, 38,143,103,110, 35,218, 80, 8,131, 90,111,200, 46,
+ 95,205,132, 53,111,127,171,243,170,126, 19,161,141,127, 28, 66,191,241,173,158,195,126,126, 39, 44, 41,171,235,156,124, 0,132,
+224, 46, 94,182,165,148,175,142,191, 75,183,236,240,149, 78, 41, 0, 99,245, 59,142, 51,134,195,135, 15, 99,214,172, 89,208,104,
+186,127,238,217,153, 51,103, 80, 85, 85, 85,147,154,154,186,175,187, 5,191, 51,252, 3, 52, 42,220, 26, 55,168,235,191, 7,210,
+246,172,201, 13,127, 48, 74,128,241, 90,248, 27, 11,131, 81,105,110,189,246, 99,219,145, 11, 88,152, 56, 10,140, 1,203, 63,219,
+141, 62, 65,218, 14,243, 46,185,120, 28,193,174, 47, 93, 32,175,194, 43,123, 6, 72, 23,247,192,186,239,237, 70, 65,110,236, 45,
+110,122, 8,254, 9, 75, 27,167, 66,156, 59,127, 6,102,179, 25,186,112, 29, 6, 13,138,133,223,216,251, 32, 68,220,128,154,237,
+ 43,192,172,141,131,150,227, 0,238, 61, 0,247,119,216, 7,160,148, 54,174,195,180,217,108, 56,126,252, 56,238,185,231, 30,143,
+ 60,236,150, 45, 91,172,162, 40,190,215,221, 14,111, 79,241,247,148,195,238,138,255,228,225,209, 46,203,239,204,188, 12,139, 93,
+196,239, 55, 28,192,134,212,179,152, 60, 44,186, 99, 74,230,176, 64,147,191,219, 77, 43, 79,206,244,248,131, 51, 10,251,225, 53,
+176,238,126,189,149,240,171,135,205,128,191,254,215, 0,225,112, 56, 35, 29,241, 79,188,138,184, 23,191, 67,252,170, 61, 24,246,
+220, 70,252,252,153, 55,112,241, 98, 14,132,232,177, 8,185,255, 95, 32,126,205,167,178,176,123,171, 62,156, 60,164,165, 2,180,
+138, 67, 55,175,248,134, 79,102,102, 38,134, 13, 27,134,254,253,251,119,251,243,214,212,212, 32, 53, 53,149,216,108,182, 79,187,
+214,200,123,151,255,181,119, 82,157,227, 63,101,120, 63,215, 65, 4,187,136,121,127,217,138, 15,182, 31, 5, 0, 76, 30, 22,211,
+ 33, 2,181,199,191,130,134,147,220, 24,124,108,103,143, 42,189,185, 12,150,109,203,225, 56,241,159,214,129, 64, 65, 3,255,233,
+207, 2, 0,242,242,206,227,231,171,119,227,120,133,179,127,243, 95,131, 10,243,255,244, 21, 36, 81, 4, 23,210, 15,234, 33,122,
+ 39,151, 65,166,252,114,183, 61, 0, 99,172,177,194, 37, 73,130, 36, 73,141,199,199,143, 31,199,188,121,243, 60,242,208, 59,119,
+238,132, 90,173,222,113,173,249,102,188,197,191, 59,205,181,142,240,159, 59,105, 24, 66,252, 93,155,113, 7,234, 71,171,181,106,
+ 1, 99, 6, 69,180,111,102,228,167, 65, 62,245, 31,119,151,109, 68, 35,110,236, 49,147,231,202, 49, 88,191,121, 12,114,145,235,
+225, 18, 85,244, 88,112,218,186,177,155, 15,191,254, 14,229, 14,215, 75, 72, 79, 87,249,225,207,255,168, 11, 36,170, 6, 76,110,
+209,161,177, 71, 13,127, 77,208, 58, 41, 64,131,157,217,178,213,105,120, 17, 6,131, 1, 22,139, 5, 9, 9,221, 59, 38, 66, 41,
+197,158, 61,123,176,118,237, 90,212,214,214,190,123, 45,130,227, 13,254,221,237,167,116,148,127,144, 86,141, 71,110, 29,219,230,
+ 61,199,235, 36,168,218,153, 30,239,200,254, 22,150, 31, 86,130,103,110,167, 68,127,213, 35,243,255, 25,133,253,216, 90, 88,183,
+ 63, 3,106,117, 63, 67, 85,136,106, 26,228, 59,125,213,220,230, 45,243, 74,235,156,122, 97,192,205, 45, 47, 5,169,180, 36,168,
+185, 19,204, 26, 42,186,193,217,106, 72, 66,212,240, 57,113,226, 4,238,185,231, 30,116,215,194, 19, 89,150,177,107,215, 46,124,
+246,217,103,176, 88, 44,142,226,226,226, 45, 6,131, 33, 60, 56, 56,248,230,234,234,234, 35,157,173,190,158,230, 79,105,183,250,
+132, 93,226,255,200,140, 49, 88,179,235, 68,227,130,156,150,152,192, 95,132,121,227, 98, 8, 35,102, 67,125,195, 29, 32,129,117,
+ 19,227,152,104,133,227,226, 62,148, 30,222,128, 16, 91,126, 91, 83, 39, 77, 50, 47,175,244,184,236,139, 86,216,118,189, 2,169,
+224,144,115, 67,205,171,193,192,156,124, 0, 90,219, 20, 29, 31, 18,174,193,129, 54, 18,161,140,111,152, 8,232, 98,108,193,223,
+108,111, 60, 41, 52,111,125, 26, 42,188,249, 75,176, 88, 44, 56,127,254, 60, 94,121,229,149,107,239,226, 36, 9, 63,252,240, 3,
+214,174, 93, 11,155,205,102,191,122,245,234,214,162,162,162,100, 74,105, 49,207,243, 70, 89,150, 75,174,165,245,236, 41,254,255,
+ 90,191, 3, 16, 98,187,189,245,119,197,223, 84,107,198,169,220, 43,184,243, 87, 75,177,249,240,121, 28,207, 43, 70,218,185, 66,
+156,184,100,132, 67,114,223,194,223, 20, 84, 9,106, 42,130, 35,227,159,112,100,252,179, 46, 98, 66, 56, 48, 42,131,128,181, 59,
+186, 69, 8, 94,136,252,205,145, 98,143, 10,191,189, 22,214,255, 62, 7,217,152,237,252,219,193, 49,240,159,245, 38,236, 71,254,
+ 5, 41,191, 41, 90, 44,149,158,107,252,255,233, 7,238,194,127, 94,217, 6,145,181, 86,225, 80,149,132,217,183,212,141,112,203,
+165,173,179, 39, 50, 78, 77,157,194,160, 45, 95, 64,243, 23,113,234,212, 41, 36, 36, 36,224, 90,114, 76, 58, 28, 14,124,255,253,
+247, 88,183,110, 29, 28, 14,135,173,168,168, 40,185,168,168,232,123,142,227,140,140, 49,163, 36, 73,198,170,170,170,210,107,105,
+145,123,146,255, 85, 41,226, 52,250,224,230,238,142,246,184,226,159,125,250, 52,134,198, 77,192, 15, 89,133,216,118,244, 34,174,
+ 86,214,118,232,158, 55, 5, 87,180, 50, 51,192,104,135, 38,203, 51,134,191,233,150, 29,250,196,147,194, 79,173,149,117, 38, 79,
+153,115,170, 33, 97,144, 30,126, 51, 94, 4,209, 4, 66, 24,156,232,164, 0,114,121, 30,236,103,191,135,102,212, 93, 24, 53, 50,
+ 14,219,127, 99,196, 67,255, 76, 69,177,189,105,237,198,208, 0, 59, 62, 91, 58, 3,177,177,117,169, 93,172, 39,190,108,249,211,
+162, 57,192, 97,115, 82,128, 6,123,179,229, 11,144,101, 25, 89, 89, 89,120,253,245,215,187,244,144,118,187, 29,223,126,251, 45,
+214,175, 95, 15, 89,150,109,133,133,133,155,141, 70,227, 14,198,152, 17,128,145,231,121, 99,121,121,185,241, 90, 43,179,167,249,
+ 91,198,207,187, 25,232, 62, 5,104,139,127,118,214,105,188,254,250,235, 24, 61,122, 52,254,186,120, 6, 14,157, 47, 66,114,198,
+121,108,205, 56,143,194, 10,215,202, 16,163,177, 34, 90,109,235, 98,143,132, 47,117,149,135,158,242,104,203,111,173,130,245,219,
+ 39, 65,171,154, 77,234,227, 4,104,110,126, 12,234, 9,191, 68,195, 8, 53, 63, 48,161,254,255,166,104,144, 53,245, 35,168, 98,
+ 38,128, 11,233,135, 91,111,153,137,203,137,211,177,231,192, 30, 20,149,150, 33, 38,162, 15,110,155, 62, 19, 28,199, 3,140,194,
+146,178, 26,210,149, 99, 45,186, 54,124, 25,179,244,152,197,165, 15,208,210,254,204,203,203, 67,104,104, 40, 70,143, 30,221,169,
+ 7,180, 88, 44, 72, 78, 78,198,134, 13, 27, 64, 41,181, 22, 20, 20,108, 46, 47, 47,223,205, 24, 51, 82, 74,141,130, 32, 24,203,
+202,202,140,232,194, 34,230,182,108,232,158,226, 79,253,195,251,121,194, 7,104,143, 63, 71, 8,244, 35,250, 65, 63,162, 31,254,
+180,232, 86, 28,201,189,138,228,140,243, 72, 62,124, 30, 5,101,213, 78,230, 79, 23, 32,130,177,223,235,150, 29,254, 11, 33,158,
+221,179, 75, 46, 60,234, 36,252, 92,200, 0,248,221,246, 50,248,136, 17, 78,229,184,128, 62,224,251,222, 8,185, 56,171, 89,207,
+ 97,130,233,171,135, 17,112,219, 31,160, 30, 58, 29, 60,207, 99,214,140, 89,173, 76,171,218, 29, 47, 66, 44, 56,220,170,174,193,
+216,159,156,122,156,230,161,183,150, 54,232,153, 51,103, 58, 21, 58,172,173,173,197,230,205,155,177,113,227, 70, 80, 74, 45, 6,
+131,225,155,178,178,178,253,140, 49, 35,207,243, 70,198,152,177,170,170,202,136,174,239, 68,216,102,232,176,167,248,171,180, 33,
+241,221, 37, 34, 93,229, 79, 8, 48,121, 88, 52, 38, 15,139,198,170, 95, 78,195,241, 60, 35, 54,238,203, 64,114,250,105,140, 15,
+236,148, 2, 72,140, 97, 7,227,232,107, 17,203, 50,142, 98,185,231,163, 94,252,160, 68,240,125,199, 64, 46, 57, 11,213,136,217,
+208,232,159,116,154,215,223, 28,154,164,223,194,178,229, 9,128, 54, 57,251,204, 81,139,218,255,174,132,122,232,116, 8, 81,163,
+193,135, 15, 1, 9,208, 65,174,184, 12,185,236, 2, 28,185, 7, 64,171, 91,175,165, 98,192,247,125,150, 29,118, 26,216,115,235,
+ 3,152, 76, 38, 20, 23, 23, 99,198,140, 25,237, 62, 80,117,117, 53,190,254,250,107, 36, 39, 39,131, 82,106,190,114,229,202,230,
+178,178,178,131,140, 49, 99,189,157, 95, 28, 26, 26,106,188,120,241,162,221, 35,246,164,194, 31,199,246,124,135,204,228,100, 12,
+161,212,188, 35,219,184,189,223, 56,106,191,101,120,224, 68,157, 63, 63, 26,196,133,233, 79,112,152, 49,178, 94,237,112,124, 21,
+252,236,177,178,158, 12,251, 18,149, 22,254,247,124,220,184, 32,167, 77,101,233,115, 3,212,147, 30,169,115,228, 91,250,102,185,
+251,225,200,221,223,193, 31, 37,121, 2,228, 86,234,237,214, 7,200,206,206,198,157,119,222,217,230,188,153,170,170, 42,124,249,
+229,151, 13,203, 11,107, 13, 6,195,230,170,170,170,180, 6, 27,159, 82,106,212,106,181,198,162,162, 34, 75,101,101,165,199, 42,
+ 84,225,223,154,255,243,151,152, 81,150,139,140,235, 31, 25, 64, 18, 6, 5,106,136, 74,230,136,172, 34, 96, 50, 7,162,170, 10,
+ 95,150, 82, 0,111,131,239, 88, 46, 84,205,132, 95, 1,142, 90, 56, 78,118,121,101,233, 41,153,147,238,212,185,136,106, 53, 42,
+ 64,115, 27, 84, 20, 69,156, 63,127, 30,207, 60,243,140,203,187,149,151,151, 99,253,250,245,216,177, 99, 7,100, 89,174,169,175,
+248,140, 6,161, 81,169, 84,197,140, 49, 99, 69, 69, 69,173,171, 92,239,158, 16, 32,133,191,107,254,119,191,239,203,121,172, 58,
+218,101,112,208, 76,249, 53,248, 62, 55,192,182,255,143, 96, 82,167, 28,252, 20,162, 17,239,138,116, 51,160,215,202, 4, 98,140,
+225,226,197,139, 24, 49, 98, 4,250,245,115,246,245, 74, 74, 74,240,197, 23, 95, 96,247,238,221,144, 36,169,218, 96, 48,108,169,
+174,174, 62,202, 24, 51, 54,216,201, 0,140, 37, 37, 37, 61, 90,235, 10,127,239,242,239, 41, 8,195,102,194,191,223, 68,136,103,
+190,131,120,230, 91, 48,179, 91,203,205, 0, 32,153, 3,217, 18,218,183,127, 74, 91,107, 25, 4,198, 24,107,217, 5, 95,184,112,
+ 1, 79, 61,213, 20, 9, 43, 42, 42,194,231,159,127,142, 3, 7, 14, 64,146, 36, 83,126,126,254,150,218,218,218,147, 13, 81, 17,
+158,231,141,146, 36, 25, 43, 43, 43,123, 60, 91,152, 87,248,203,220, 81,240,244, 53,215,132,136,205,231,249,247, 98,112,218, 48,
+104,110, 90, 12,205,132, 69,117,249,129, 28, 22,124,182,230, 67, 27, 45, 57,179,121, 76, 31,122,118,100,140,176,179,239,242, 35,
+ 29,158, 77, 32, 16, 66,242,171,171,171, 71,134,133,133,129, 82,138,210,210, 82,136,162,136, 41, 83,166,192, 96, 48,224,223,255,
+254, 55,210,210,210, 32,138, 98,229,229,203,151,183,154,205,230,204, 6,231, 16,128, 81,150,101, 99, 85, 85, 85,153,183, 42,196,
+ 27,252,197,205, 43,142, 2, 56,218, 91,249,255,111,104, 2, 15,190, 79,221, 96,215, 57,115,152,188,255,136,120,188,160,160, 96,
+ 91, 85, 85, 85,167, 54,241, 16,236,118,123,106, 73, 73,201,204,254,253,251, 11,148, 82, 92,188,120, 17, 19, 38, 76,192,203, 47,
+191,140, 35, 71,142,192,110,183, 87, 24, 12,134,111,107,107,107,179, 8, 33, 37,168, 91,204, 97,228,121,222, 88, 82, 82, 98,244,
+118, 61, 40,252,189, 15,147,201, 36,100,100,100,120,243,247,121, 66, 8,149,101,185,243,185, 65, 25, 99, 25,121,121,121,246, 33,
+ 67,134, 8,118,187, 29,121,121,121,200,207,207,135,205,102,107,168,248,179,205, 91,155,102,131, 88,212, 23, 42, 95,225,239,117,
+ 24,139,139,139, 79,173, 90,181,138,183,219,237,209,140, 49, 53, 0, 86,159, 97,143, 53,251,160,254, 60,107, 10,203, 59, 95,115,
+119,189,197,189, 90,150,101,178, 44,203,146, 36,149,212,167, 71,236,212, 8, 13, 1,128,105,211,166, 61, 79, 41,125, 11,128,236,
+112, 56,106,138,138,138,182,213,214,214,158,227, 56,174,193,198, 44, 97,140, 21,215, 79, 91,144,224, 99, 80,248,251,134, 81,162,
+211,233,150, 3,232, 91,175,156, 50,234, 18,214, 74,132, 16,153, 49, 38, 19, 66,164,102,231,104,179,107, 13,231,101, 66,136, 84,
+159,228, 86,110,184, 70, 8,145, 41,165, 82,139, 99,185, 33, 35, 52,165, 84,146,101, 89, 98,140, 89,204,102,243,149, 78, 43, 64,
+ 61, 84,225,225,225, 81,140,177, 48,142,227,180, 0,136, 44,203,118,142,227,202,195,195,195, 75, 60, 53, 8,212,141, 80,248,123,
+ 57, 88, 25, 24, 24, 24,205,113,156,154, 16,194, 84, 42, 21, 68, 81,108,108,165, 27, 90,241,230,199,132, 16,218,208,226, 59, 28,
+ 14,167, 30,128, 16,194,154,125, 26,202,194, 98,177, 56,221,131,227, 56, 70, 8, 97,149,149,149,172, 94,233,196,174, 42,128, 2,
+ 5,215,172, 4, 93,181, 4,189, 69,248,255, 3,212, 21,184,121, 66,226, 69,162, 0, 0, 0, 0, 73, 69, 78, 68,174, 66, 96,130,
+};
+
diff --git a/source/blender/src/pub/license_key.c b/source/blender/src/pub/license_key.c
new file mode 100644
index 00000000000..07e8296a185
--- /dev/null
+++ b/source/blender/src/pub/license_key.c
@@ -0,0 +1,447 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include "license_key.h"
+#include "keyed_functions.h"
+#include "BKE_utildefines.h"
+#include "BIF_screen.h" // splash
+#include "BIF_toolbox.h"
+#include "blenkey.h"
+#include <stdio.h>
+#include <string.h>
+
+#include "BLI_blenlib.h"
+
+#include "BLO_readfile.h"
+#include "BLO_keyStore.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+int LICENSE_KEY_VALID = TRUE;
+int I_AM_PUBLISHER = TRUE;
+
+static UserStruct User;
+
+// Python stuff
+
+#include "Python.h"
+#include "marshal.h"
+#include "compile.h" /* to give us PyCodeObject */
+#include "eval.h" /* prototype for PyEval_EvalCode */
+
+#include "BPY_extern.h"
+
+#include "IMB_imbuf.h"
+
+Fptr g_functab[PYKEY_TABLEN];
+Fptr g_ptrtab[PYKEY_TABLEN];
+
+static int g_seed[3] = PYKEY_SEED;
+static PyObject *g_module_self;
+static PyObject *g_main;
+
+
+// end Python stuff
+
+// **************** PYTHON STUFF **************************
+/* ----------------------------------------------------- */
+/* this is the dummy functions to demonstrate */
+
+int sticky_shoes(void *vp)
+{
+ return 0;
+}
+
+/*
+int key_func1(void *vp) {
+ printf("function 1 called\n");
+}
+
+*/
+int key_return_true(void *vp) {
+ return 1;
+}
+
+
+/* ----------------------------------------------------- */
+
+/* Declarations for objects of type Fplist */
+
+
+static char prot_getseed__doc__[] = "";
+
+static PyObject *
+prot_getseed(self, args)
+ PyObject *self; /* Not used */
+ PyObject *args;
+{
+ PyObject *p;
+ p = PyTuple_New(3);
+ PyTuple_SetItem(p, 0, PyInt_FromLong(g_seed[0]));
+ PyTuple_SetItem(p, 1, PyInt_FromLong(g_seed[1]));
+ PyTuple_SetItem(p, 2, PyInt_FromLong(g_seed[2]));
+ return p;
+}
+
+static char prot_getlen__doc__[] = "";
+static PyObject *
+prot_getlen(self, args)
+ PyObject *self; /* Not used */
+ PyObject *args;
+{
+ return Py_BuildValue("i", PYKEY_TABLEN);
+}
+
+static char prot_getptr__doc__[] =
+""
+;
+
+static PyObject *
+prot_getptr(self, args)
+ PyObject *self; /* Not used */
+ PyObject *args;
+{
+ PyObject *p;
+ Fptr f;
+ int index;
+ /* we don't catch errors here, we're in the key code */
+ if (!g_functab)
+ return NULL;
+ if (!PyArg_ParseTuple(args, "i", &index))
+ return NULL;
+ if (index >= PYKEY_TABLEN)
+ return NULL;
+
+ f = g_functab[index];
+ p = PyCObject_FromVoidPtr(f , NULL);
+ return p;
+}
+
+static char prot_setptr__doc__[] =
+""
+;
+static PyObject *
+prot_setptr(self, args)
+ PyObject *self; /* Not used */
+ PyObject *args;
+{
+ PyObject *p;
+
+ int index;
+
+ if (!g_ptrtab)
+ return NULL;
+ if (!PyArg_ParseTuple(args, "iO", &index, &p))
+ return NULL;
+ if (index >= PYKEY_TABLEN)
+ return NULL;
+ if (!PyCObject_Check(p)) {
+ return NULL;
+ }
+
+ g_ptrtab[index] = PyCObject_AsVoidPtr(p);
+ return Py_BuildValue("i", 1);
+}
+
+static PyObject *callkeycode(
+ unsigned char *keycode,
+ int keycodelen)
+{
+ PyCodeObject *code;
+ PyObject *maindict = PyModule_GetDict(g_main);
+
+ code = (PyCodeObject *) PyMarshal_ReadObjectFromString(keycode, keycodelen);
+ if (!PyEval_EvalCode(code, maindict, maindict))
+ return NULL;
+ return Py_BuildValue("i", 1);
+}
+
+
+
+/* List of methods defined in the module */
+
+static struct PyMethodDef prot_methods[] = {
+ {"getlen", (PyCFunction)prot_getlen, METH_VARARGS, prot_getlen__doc__},
+ {"getseed", (PyCFunction)prot_getseed, METH_VARARGS, prot_getseed__doc__},
+ {"getptr", (PyCFunction)prot_getptr, METH_VARARGS, prot_getptr__doc__},
+ {"setptr", (PyCFunction)prot_setptr, METH_VARARGS, prot_setptr__doc__},
+
+ {NULL, (PyCFunction)NULL, 0, NULL} /* sentinel */
+};
+
+
+/* Initialization function for the module (*must* be called initprot) */
+
+static char prot_module_documentation[] = "No Documentation";
+
+static void init_ftable(void) // initializes functiontable
+{
+ int i;
+
+ g_functab[0] = &key_func1;
+/* add more key_funcs here */
+
+ for (i = 1; i < PYKEY_TABLEN; i++)
+ {
+ g_functab[i] = &sticky_shoes;
+ }
+}
+
+
+static void init_ptable(void) // initializes functiontable
+{
+ int i;
+
+ for (i = 0; i < PYKEY_TABLEN; i++)
+ {
+ g_ptrtab[i] = &sticky_shoes;
+ }
+}
+
+
+static void insertname(PyObject *m,PyObject *p, char *name)
+{
+ PyObject *d = PyModule_GetDict(m);
+
+ EXPP_dict_set_item_str(d, name, p);
+}
+
+/* initialisation */
+static void initprot()
+{
+ PyObject *m, *d;
+ PyObject *capi1;
+ init_ftable();
+
+ g_main = PyImport_AddModule("__main__");
+
+ m = Py_InitModule4("prot", prot_methods,
+ prot_module_documentation,
+ (PyObject*)NULL,PYTHON_API_VERSION);
+ g_module_self = m;
+ d = PyModule_GetDict(m);
+ EXPP_dict_set_item_str(d, "error", PyString_FromString("prot.error");
+
+ /* add global object */
+
+ capi1 = PyCObject_FromVoidPtr((void *)g_functab , NULL);
+ if (capi1) {
+ insertname(m, capi1, "APIfunctab");
+ }
+
+ /* Check for errors */
+ if (PyErr_Occurred())
+ Py_FatalError("can't initialize module prot");
+
+ init_ptable();
+}
+
+// ******************************* KEY STUFF *********************
+
+static void create_key_name(char * keyname)
+{
+ sprintf(keyname, "%s/.BPkey", BLI_gethome());
+}
+
+void checkhome()
+{
+ int keyresult;
+ char *HexPriv, *HexPub, *HexPython;
+ byte *Byte;
+ char keyname[FILE_MAXDIR + FILE_MAXFILE];
+ int wasInitialized;
+ unsigned char *keycode = NULL;
+ int keycodelen = 0;
+
+ create_key_name(keyname);
+ keyresult = ReadKeyFile(keyname, &User, &HexPriv, &HexPub,
+ &Byte, &HexPython);
+ if (keyresult != 0) {
+ // printf("\nReadKeyFile error %d\n", keyresult);
+ } else {
+ // printf("\nReadKeyFile OK\n");
+ LICENSE_KEY_VALID = TRUE;
+
+ wasInitialized = Py_IsInitialized();
+
+ // make it failsafe if python interpreter was already initialized
+ if (wasInitialized)
+ Py_Initialize();
+
+ initprot(); // initialize module and function tables
+ // get python byte code
+ keycode = DeHexify(HexPython);
+ keycodelen = strlen(HexPython) / 2;
+
+ callkeycode(keycode, keycodelen);
+
+ Py_Finalize();
+
+ if (wasInitialized) // if we were initialized,
+ BPY_start_python(); // restart creator python
+
+ //some debugging stuff
+ // print_ptable();
+
+ // Store key stuff for use by stream
+ keyStoreConstructor(
+ &User,
+ HexPriv,
+ HexPub,
+ Byte,
+ HexPython);
+
+ // other initialization code
+
+ }
+}
+
+void SHOW_LICENSE_KEY(void)
+{
+ extern int datatoc_tonize;
+ extern char datatoc_ton[];
+ char string[1024];
+ int maxtype, type;
+ char *typestrings[] = {
+ "",
+ "Individual",
+ "Company",
+ "Unlimited",
+ "Educational"};
+
+ maxtype = (sizeof(typestrings) / sizeof(char *)) - 1;
+ type = User.keytype;
+ if (type > maxtype) {
+ type = 0;
+ }
+
+ if (LICENSE_KEY_VALID) {
+ sprintf(string, "%s License registered to: %s (%s)", typestrings[type], User.name, User.email);
+ splash((void *)datatoc_ton, datatoc_tonize, string);
+ }
+}
+
+void loadKeyboard(char * name)
+{
+ char keyname[FILE_MAXDIR + FILE_MAXFILE];
+ FILE *in, *out;
+ char string[1024], *match = 0;
+ int i, c;
+ int found = 0;
+
+ // make sure we don't overwrite a valid key...
+
+ if (!LICENSE_KEY_VALID) {
+ in = fopen(name, "rb");
+ if (in) {
+ // scan for blender key magic, read strings
+ // with anything but a newline
+ while (fscanf(in, "%1000[^\n\r]", string) != EOF) {
+ match = strstr(string, BLENKEYMAGIC);
+ if (match) {
+ break;
+ }
+ fscanf(in, "\n");
+ }
+
+ if (match) {
+ // found blender key magic, open output file
+ // to copy key information
+
+ create_key_name(keyname);
+ out = fopen(keyname, "wb");
+ if (out) {
+ // printout first line
+ fprintf(out, "%s", match);
+ for (i = 0; i < 350; i++) {
+ // handle control characters (\n\r)
+ while (1) {
+ c = getc(in);
+ if (c == '\n') {
+ // output a \n for each \n in the input
+ fprintf(out, "\n");
+ } else if (c == EOF) {
+ break;
+ } else if (c < ' ') {
+ // skip control characters
+ } else {
+ ungetc(c, in);
+ break;
+ }
+ }
+
+ if (fscanf(in, "%1000[^\n\r]", string) != EOF) {
+ if (strcmp(string, BLENKEYSEPERATOR) == 0) {
+ found++;
+ }
+ fprintf(out, "%s", string);
+ } else {
+ break;
+ }
+
+ if (found >= 2) {
+ break;
+ }
+ }
+
+ fclose(out);
+
+ checkhome();
+ if (LICENSE_KEY_VALID) {
+ SHOW_LICENSE_KEY();
+ } else {
+ error("Not a valid license key ! Removing installed key.");
+ BLI_delete(keyname, 0, 0);
+ }
+
+ } else {
+ error("Can't install key");
+ }
+ } else {
+ error("File doesn't contain a valid key: %s", name);
+ }
+
+ fclose(in);
+
+ if (LICENSE_KEY_VALID) {
+ if (okee("Remove input file: '%s'?", name)) {
+ BLI_delete(name, 0, 0);
+ }
+ }
+
+ } else {
+ error("File doesn't exist: %s", name);
+ }
+ }
+}
diff --git a/source/blender/src/renderwin.c b/source/blender/src/renderwin.c
new file mode 100644
index 00000000000..2d56b78b026
--- /dev/null
+++ b/source/blender/src/renderwin.c
@@ -0,0 +1,1431 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifdef WIN32
+/* for the multimedia timer */
+#include <windows.h>
+#include <mmsystem.h>
+#endif
+
+#include <string.h>
+#include <stdarg.h>
+#include <math.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WIN32
+#include "BLI_winstuff.h"
+#else
+ /* for signal callback, not (fully) supported at windows */
+#include <sys/time.h>
+#include <signal.h>
+
+#endif
+
+#include <limits.h>
+
+#include "BLI_blenlib.h"
+#include "BLI_threads.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BMF_Api.h"
+
+#include "DNA_image_types.h"
+#include "DNA_space_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_vec_types.h"
+
+#include "BKE_global.h"
+#include "BKE_image.h"
+#include "BKE_library.h"
+#include "BKE_scene.h"
+#include "BKE_utildefines.h"
+#include "BKE_writeavi.h" /* movie handle */
+
+#include "BIF_drawimage.h"
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+#include "BIF_graphics.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_mywindow.h"
+#include "BIF_renderwin.h"
+#include "BIF_resources.h"
+#include "BIF_toets.h"
+#include "BIF_toolbox.h"
+#include "BIF_writeimage.h"
+
+#include "BDR_sculptmode.h"
+#include "BDR_editobject.h"
+#include "BPY_extern.h" /* for BPY_do_all_scripts */
+
+#include "BSE_view.h"
+#include "BSE_drawview.h"
+#include "BSE_filesel.h"
+#include "BSE_headerbuttons.h"
+
+#include "RE_pipeline.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "blendef.h"
+#include "mydevice.h"
+#include "winlay.h"
+
+/* ------------ renderwin struct, to prevent too much global vars --------- */
+/* ------------ only used for display in a 2nd window --------- */
+
+
+/* flags escape presses during event handling
+* so we can test for user break later.
+*/
+#define RW_FLAGS_ESCAPE (1<<0)
+/* old zoom style (2x, locked to mouse, exits
+* when mouse leaves window), to be removed
+* at some point.
+*/
+#define RW_FLAGS_OLDZOOM (1<<1)
+/* on when image is being panned with middlemouse
+*/
+#define RW_FLAGS_PANNING (1<<2)
+/* on when the mouse is dragging over the image
+* to examine pixel values.
+*/
+#define RW_FLAGS_PIXEL_EXAMINING (1<<3)
+
+/* forces draw of alpha */
+#define RW_FLAGS_ALPHA (1<<4)
+
+
+typedef struct {
+ Window *win;
+
+ int rectx, recty; /* size of image */
+
+ int sparex, sparey; /* spare rect size */
+ unsigned int *rectspare;
+ float *rectsparef;
+
+ float zoom, zoomofs[2];
+ int active;
+ short storespare, showspare;
+
+ int mbut[5];
+ int lmouse[2];
+
+ unsigned int flags;
+
+ float pan_mouse_start[2], pan_ofs_start[2];
+
+ char *info_text;
+ char *render_text, *render_text_spare;
+
+} RenderWin;
+
+static RenderWin *render_win= NULL;
+
+/* --------------- help functions for RenderWin struct ---------------------------- */
+
+
+/* only called in function open_renderwin */
+static RenderWin *renderwin_alloc(Window *win)
+{
+ RenderWin *rw= MEM_callocN(sizeof(*rw), "RenderWin");
+ rw->win= win;
+ rw->zoom= 1.0;
+ rw->active= 0;
+ rw->flags= 0;
+ rw->zoomofs[0]= rw->zoomofs[1]= 0;
+ rw->info_text= NULL;
+ rw->render_text= MEM_callocN(RW_MAXTEXT, "rendertext");
+ rw->render_text_spare= MEM_callocN(RW_MAXTEXT, "rendertext spare");
+
+ rw->lmouse[0]= rw->lmouse[1]= 0;
+ rw->mbut[0]= rw->mbut[1]= rw->mbut[2]= rw->mbut[3] = rw->mbut[4] = 0;
+
+ return rw;
+}
+
+
+static void renderwin_queue_redraw(RenderWin *rw)
+{
+ window_queue_redraw(rw->win); // to ghost
+}
+
+static void renderwin_reshape(RenderWin *rw)
+{
+ ;
+}
+
+static void renderwin_get_fullrect(RenderWin *rw, float fullrect_r[2][2])
+{
+ float display_w, display_h;
+ float cent_x, cent_y;
+ int w, h;
+
+ window_get_size(rw->win, &w, &h);
+ h-= RW_HEADERY;
+
+ display_w= rw->rectx*rw->zoom;
+ display_h= rw->recty*rw->zoom;
+ cent_x= (rw->zoomofs[0] + rw->rectx/2)*rw->zoom;
+ cent_y= (rw->zoomofs[1] + rw->recty/2)*rw->zoom;
+
+ fullrect_r[0][0]= w/2 - cent_x;
+ fullrect_r[0][1]= h/2 - cent_y;
+ fullrect_r[1][0]= fullrect_r[0][0] + display_w;
+ fullrect_r[1][1]= fullrect_r[0][1] + display_h;
+}
+
+ /**
+ * Project window coordinate to image pixel coordinate.
+ * Returns true if resulting coordinate is within image.
+ */
+static int renderwin_win_to_image_co(RenderWin *rw, int winco[2], int imgco_r[2])
+{
+ float fullrect[2][2];
+
+ renderwin_get_fullrect(rw, fullrect);
+
+ imgco_r[0]= (int) ((winco[0]-fullrect[0][0])/rw->zoom);
+ imgco_r[1]= (int) ((winco[1]-fullrect[0][1])/rw->zoom);
+
+ return (imgco_r[0]>=0 && imgco_r[1]>=0 && imgco_r[0]<rw->rectx && imgco_r[1]<rw->recty);
+}
+
+ /**
+ * Project window coordinates to normalized device coordinates
+ * Returns true if resulting coordinate is within window.
+ */
+static int renderwin_win_to_ndc(RenderWin *rw, int win_co[2], float ndc_r[2])
+{
+ int w, h;
+
+ window_get_size(rw->win, &w, &h);
+ h-= RW_HEADERY;
+
+ ndc_r[0]= ((float)(win_co[0]*2)/(w-1) - 1.0f);
+ ndc_r[1]= ((float)(win_co[1]*2)/(h-1) - 1.0f);
+
+ return (fabs(ndc_r[0])<=1.0 && fabs(ndc_r[1])<=1.0);
+}
+
+static void renderwin_set_infotext(RenderWin *rw, char *info_text)
+{
+ if (rw->info_text) MEM_freeN(rw->info_text);
+ rw->info_text= info_text?BLI_strdup(info_text):NULL;
+}
+
+static void renderwin_reset_view(RenderWin *rw)
+{
+ int w, h;
+
+ if (rw->info_text) renderwin_set_infotext(rw, NULL);
+
+ /* now calculate a zoom for when image is larger than window */
+ window_get_size(rw->win, &w, &h);
+ h-= RW_HEADERY;
+
+ if(rw->rectx>w || rw->recty>h) {
+ if(rw->rectx-w > rw->recty-h) rw->zoom= ((float)w)/((float)rw->rectx);
+ else rw->zoom= ((float)h)/((float)rw->recty);
+ }
+ else rw->zoom= 1.0;
+
+ rw->zoomofs[0]= rw->zoomofs[1]= 0;
+ renderwin_queue_redraw(rw);
+}
+
+static void renderwin_draw_render_info(RenderWin *rw)
+{
+ /* render text is added to top */
+ if(RW_HEADERY) {
+ float colf[3];
+ rcti rect;
+ char *str;
+
+ window_get_size(rw->win, &rect.xmax, &rect.ymax);
+ rect.xmin= 0;
+ rect.ymin= rect.ymax-RW_HEADERY;
+ glEnable(GL_SCISSOR_TEST);
+ glaDefine2DArea(&rect);
+
+ /* clear header rect */
+ BIF_SetTheme(NULL); // sets view3d theme by default
+ BIF_GetThemeColor3fv(TH_HEADER, colf);
+ glClearColor(colf[0], colf[1], colf[2], 1.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ if(rw->showspare)
+ str= rw->render_text_spare;
+ else
+ str= rw->render_text;
+
+ if(str) {
+ BIF_ThemeColor(TH_TEXT);
+ glRasterPos2i(12, 5);
+ BMF_DrawString(G.fonts, str);
+ }
+
+ BIF_SetTheme(curarea); // restore theme
+ }
+
+}
+
+static void renderwin_draw(RenderWin *rw, int just_clear)
+{
+ float fullrect[2][2];
+ int set_back_mainwindow;
+ rcti rect;
+
+ /* since renderwin uses callbacks (controlled by ghost) it can
+ mess up active window output with redraw events after a render.
+ this is patchy, still WIP */
+ set_back_mainwindow = (winlay_get_active_window() != rw->win);
+ window_make_active(rw->win);
+
+ rect.xmin= rect.ymin= 0;
+ window_get_size(rw->win, &rect.xmax, &rect.ymax);
+ rect.ymax-= RW_HEADERY;
+
+ renderwin_get_fullrect(rw, fullrect);
+
+ /* do this first, so window ends with correct scissor */
+ renderwin_draw_render_info(rw);
+
+ glEnable(GL_SCISSOR_TEST);
+ glaDefine2DArea(&rect);
+
+ glClearColor(.1875, .1875, .1875, 1.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ if (just_clear) {
+ glColor3ub(0, 0, 0);
+ glRectfv(fullrect[0], fullrect[1]);
+ } else {
+ RenderResult rres;
+
+ if(rw->showspare) {
+ rres.rectx= rw->sparex;
+ rres.recty= rw->sparey;
+ rres.rect32= (int *)rw->rectspare;
+ rres.rectf= rw->rectsparef;
+ }
+ else
+ RE_GetResultImage(RE_GetRender(G.scene->id.name), &rres);
+
+ if(rres.rectf || rres.rect32) {
+
+ glPixelZoom(rw->zoom, rw->zoom);
+ if(rw->flags & RW_FLAGS_ALPHA) {
+ if(rres.rect32) {
+ /* swap bytes, so alpha is most significant one, then just draw it as luminance int */
+ if(G.order==B_ENDIAN)
+ glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
+ glaDrawPixelsSafe(fullrect[0][0], fullrect[0][1], rres.rectx, rres.recty, rres.rectx, GL_LUMINANCE, GL_UNSIGNED_INT, rres.rect32);
+ glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
+ }
+ else {
+ float *trectf= MEM_mallocN(rres.rectx*rres.recty*4, "temp");
+ int a, b;
+
+ for(a= rres.rectx*rres.recty -1, b= 4*a+3; a>=0; a--, b-=4)
+ trectf[a]= rres.rectf[b];
+
+ glaDrawPixelsSafe(fullrect[0][0], fullrect[0][1], rres.rectx, rres.recty, rres.rectx, GL_LUMINANCE, GL_FLOAT, trectf);
+ MEM_freeN(trectf);
+ }
+ }
+ else {
+ if(rres.rect32)
+ glaDrawPixelsSafe(fullrect[0][0], fullrect[0][1], rres.rectx, rres.recty, rres.rectx, GL_RGBA, GL_UNSIGNED_BYTE, rres.rect32);
+ else if(rres.rectf)
+ glaDrawPixelsSafe_to32(fullrect[0][0], fullrect[0][1], rres.rectx, rres.recty, rres.rectx, rres.rectf);
+ }
+ glPixelZoom(1.0, 1.0);
+ }
+ }
+
+ /* info text is overlayed on bottom */
+ if (rw->info_text) {
+ float w;
+ glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_BLEND);
+ w=186.0*strlen(rw->info_text)/30;
+ glColor4f(.5,.5,.5,.25);
+ glRectf(0.0,0.0,w,30.0);
+ glDisable(GL_BLEND);
+ glColor3ub(255, 255, 255);
+ glRasterPos2i(10, 10);
+ BMF_DrawString(G.font, rw->info_text);
+ }
+
+ window_swap_buffers(rw->win);
+
+ if (set_back_mainwindow) mainwindow_make_active();
+}
+
+
+/* ------ interactivity calls for RenderWin ------------- */
+static void renderwin_zoom(RenderWin *rw, int ZoomIn) {
+ if (ZoomIn) {
+ if (rw->zoom>0.26) {
+ if(rw->zoom>1.0 && rw->zoom<2.0) rw->zoom= 1.0;
+ else rw->zoom*= 0.5;
+ }
+ } else {
+ if (rw->zoom<15.9) {
+ if(rw->zoom>0.5 && rw->zoom<1.0) rw->zoom= 1.0;
+ else rw->zoom*= 2.0;
+ }
+ }
+ if (rw->zoom>1.0) rw->flags |= RW_FLAGS_OLDZOOM;
+ if (rw->zoom==1.0) rw->flags &= ~RW_FLAGS_OLDZOOM;
+ renderwin_queue_redraw(rw);
+}
+
+static void renderwin_mouse_moved(RenderWin *rw)
+{
+ RenderResult rres;
+
+ RE_GetResultImage(RE_GetRender(G.scene->id.name), &rres);
+
+ if (rw->flags & RW_FLAGS_PIXEL_EXAMINING) {
+ int imgco[2], ofs=0;
+ char buf[128];
+ char *pxl;
+
+ if (renderwin_win_to_image_co(rw, rw->lmouse, imgco)) {
+ if (rres.rect32) {
+ pxl= (char*) &rres.rect32[rres.rectx*imgco[1] + imgco[0]];
+ ofs= sprintf(buf, "R: %d G: %d B: %d A: %d", pxl[0], pxl[1], pxl[2], pxl[3]);
+ }
+ if (rres.rectf) {
+ float *pxlf= rres.rectf + 4*(rres.rectx*imgco[1] + imgco[0]);
+ ofs+= sprintf(buf+ofs, " | R: %.3f G: %.3f B: %.3f A: %.3f ", pxlf[0], pxlf[1], pxlf[2], pxlf[3]);
+ }
+ if (rres.rectz) {
+ float *pxlz= &rres.rectz[rres.rectx*imgco[1] + imgco[0]];
+ sprintf(buf+ofs, "| Z: %.3f", *pxlz );
+ }
+
+ renderwin_set_infotext(rw, buf);
+ renderwin_queue_redraw(rw);
+ } else {
+ renderwin_set_infotext(rw, NULL);
+ renderwin_queue_redraw(rw);
+ }
+ }
+ else if (rw->flags & RW_FLAGS_PANNING) {
+ int delta_x= rw->lmouse[0] - rw->pan_mouse_start[0];
+ int delta_y= rw->lmouse[1] - rw->pan_mouse_start[1];
+
+ rw->zoomofs[0]= rw->pan_ofs_start[0] - delta_x/rw->zoom;
+ rw->zoomofs[1]= rw->pan_ofs_start[1] - delta_y/rw->zoom;
+ rw->zoomofs[0]= CLAMPIS(rw->zoomofs[0], -rres.rectx/2, rres.rectx/2);
+ rw->zoomofs[1]= CLAMPIS(rw->zoomofs[1], -rres.recty/2, rres.recty/2);
+
+ renderwin_queue_redraw(rw);
+ }
+ else if (rw->flags & RW_FLAGS_OLDZOOM) {
+ float ndc[2];
+ int w, h;
+
+ window_get_size(rw->win, &w, &h);
+ h-= RW_HEADERY;
+ renderwin_win_to_ndc(rw, rw->lmouse, ndc);
+
+ rw->zoomofs[0]= -0.5*ndc[0]*(w-rres.rectx*rw->zoom)/rw->zoom;
+ rw->zoomofs[1]= -0.5*ndc[1]*(h-rres.recty*rw->zoom)/rw->zoom;
+
+ renderwin_queue_redraw(rw);
+ }
+}
+
+static void renderwin_mousebut_changed(RenderWin *rw)
+{
+ if (rw->mbut[0]) {
+ rw->flags|= RW_FLAGS_PIXEL_EXAMINING;
+ }
+ else if (rw->mbut[1]) {
+ rw->flags|= RW_FLAGS_PANNING;
+ rw->pan_mouse_start[0]= rw->lmouse[0];
+ rw->pan_mouse_start[1]= rw->lmouse[1];
+ rw->pan_ofs_start[0]= rw->zoomofs[0];
+ rw->pan_ofs_start[1]= rw->zoomofs[1];
+ } else if (rw->mbut[3]) {
+ renderwin_zoom(rw, 0);
+ rw->mbut[3]=0;
+ } else if (rw->mbut[4]) {
+ renderwin_zoom(rw, 1);
+ rw->mbut[4]=0;
+ } else {
+ if (rw->flags & RW_FLAGS_PANNING) {
+ rw->flags &= ~RW_FLAGS_PANNING;
+ renderwin_queue_redraw(rw);
+ }
+ if (rw->flags & RW_FLAGS_PIXEL_EXAMINING) {
+ rw->flags&= ~RW_FLAGS_PIXEL_EXAMINING;
+ renderwin_set_infotext(rw, NULL);
+ renderwin_queue_redraw(rw);
+ }
+ }
+}
+
+
+/* handler for renderwin, passed on to Ghost */
+static void renderwin_handler(Window *win, void *user_data, short evt, short val, char ascii)
+{
+ RenderWin *rw= user_data;
+
+ // added this for safety, while render it's just creating bezerk results
+ if(G.rendering) {
+ if(evt==ESCKEY && val)
+ rw->flags|= RW_FLAGS_ESCAPE;
+ return;
+ }
+
+ if (evt==RESHAPE) {
+ renderwin_reshape(rw);
+ }
+ else if (evt==REDRAW) {
+ renderwin_draw(rw, 0);
+ }
+ else if (evt==WINCLOSE) {
+ BIF_close_render_display();
+ }
+ else if (evt==INPUTCHANGE) {
+ rw->active= val;
+
+ if (!val && (rw->flags&RW_FLAGS_OLDZOOM)) {
+ rw->flags&= ~RW_FLAGS_OLDZOOM;
+ renderwin_reset_view(rw);
+ }
+ }
+ else if (ELEM(evt, MOUSEX, MOUSEY)) {
+ rw->lmouse[evt==MOUSEY]= val;
+ renderwin_mouse_moved(rw);
+ }
+ else if (ELEM(evt, WHEELUPMOUSE, WHEELDOWNMOUSE)) {
+ int which=(evt==WHEELUPMOUSE?3:4);
+ rw->mbut[which]=val;
+ renderwin_mousebut_changed(rw);
+ }
+ else if (ELEM3(evt, LEFTMOUSE, MIDDLEMOUSE, RIGHTMOUSE)) {
+ int which= (evt==LEFTMOUSE)?0:(evt==MIDDLEMOUSE)?1:2;
+ rw->mbut[which]= val;
+ renderwin_mousebut_changed(rw);
+ }
+ else if (val) {
+ if (evt==ESCKEY) {
+ if (rw->flags&RW_FLAGS_OLDZOOM) {
+ rw->flags&= ~RW_FLAGS_OLDZOOM;
+ renderwin_reset_view(rw);
+ }
+ else {
+ rw->flags|= RW_FLAGS_ESCAPE;
+ mainwindow_raise();
+ mainwindow_make_active();
+ rw->active= 0;
+ }
+ }
+ else if( evt==AKEY) {
+ rw->flags ^= RW_FLAGS_ALPHA;
+ renderwin_queue_redraw(render_win);
+ }
+ else if (evt==JKEY) {
+ if(G.rendering==0) BIF_swap_render_rects();
+ }
+ else if (evt==ZKEY) {
+ if (rw->flags&RW_FLAGS_OLDZOOM) {
+ rw->flags&= ~RW_FLAGS_OLDZOOM;
+ renderwin_reset_view(rw);
+ } else {
+ rw->zoom= 2.0;
+ rw->flags|= RW_FLAGS_OLDZOOM;
+ renderwin_mouse_moved(rw);
+ }
+ }
+ else if (ELEM(evt,PADPLUSKEY,PAGEUPKEY)) {
+ renderwin_zoom(rw, 0);
+ }
+ else if (ELEM(evt,PADMINUS,PAGEDOWNKEY)) {
+ renderwin_zoom(rw, 1);
+ }
+ else if (evt==PADENTER || evt==HOMEKEY) {
+ if (rw->flags&RW_FLAGS_OLDZOOM) {
+ rw->flags&= ~RW_FLAGS_OLDZOOM;
+ }
+ renderwin_reset_view(rw);
+ }
+ else if (evt==F3KEY) {
+ if(G.rendering==0) {
+ mainwindow_raise();
+ mainwindow_make_active();
+ rw->active= 0;
+ areawinset(find_biggest_area()->win);
+ BIF_save_rendered_image_fs();
+ }
+ }
+ else if (evt==F11KEY) {
+ BIF_toggle_render_display();
+ }
+ else if (evt==F12KEY) {
+ if(G.rendering==0)
+ BIF_do_render(0);
+ }
+ }
+}
+
+static char *renderwin_get_title(int doswap)
+{
+ static int swap= 0;
+ char *title="";
+
+ swap+= doswap;
+
+ if(swap & 1) {
+ if (G.scene->r.renderer==R_YAFRAY) title = "YafRay:Render (previous)";
+ else title = "Blender:Render (previous)";
+ }
+ else {
+ if (G.scene->r.renderer==R_YAFRAY) title = "YafRay:Render";
+ else title = "Blender:Render";
+ }
+
+ return title;
+}
+
+/* opens window and allocs struct */
+static void open_renderwin(int winpos[2], int winsize[2], int imagesize[2])
+{
+ extern void mywindow_build_and_set_renderwin( int orx, int ory, int sizex, int sizey); // mywindow.c
+ Window *win;
+ char *title;
+
+ title= renderwin_get_title(0); /* 0 = no swap */
+ win= window_open(title, winpos[0], winpos[1], winsize[0], winsize[1]+RW_HEADERY, 0);
+
+ render_win= renderwin_alloc(win);
+ render_win->rectx= imagesize[0];
+ render_win->recty= imagesize[1];
+
+ /* Ghost calls handler */
+ window_set_handler(win, renderwin_handler, render_win);
+
+ winlay_process_events(0);
+ window_make_active(render_win->win);
+ winlay_process_events(0);
+
+ /* mywindow has to know about it too */
+ mywindow_build_and_set_renderwin(winpos[0], winpos[1], winsize[0], winsize[1]+RW_HEADERY);
+ /* and we should be able to draw 3d in it */
+ init_gl_stuff();
+
+ renderwin_draw(render_win, 1);
+ renderwin_draw(render_win, 1);
+}
+
+/* -------------- callbacks for render loop: Window (RenderWin) ----------------------- */
+
+/* calculations for window size and position */
+void calc_renderwin_rectangle(int rectx, int recty, int posmask, int renderpos_r[2], int rendersize_r[2])
+{
+ int scr_w, scr_h, x, y, div= 0;
+ float ndc_x= 0.0, ndc_y= 0.0;
+
+ winlay_get_screensize(&scr_w, &scr_h);
+
+ rendersize_r[0]= rectx;
+ rendersize_r[1]= recty;
+
+ rendersize_r[0]= CLAMPIS(rendersize_r[0], 0, scr_w);
+ rendersize_r[1]= CLAMPIS(rendersize_r[1], 0, scr_h-RW_HEADERY);
+
+ for (y=-1; y<=1; y++) {
+ for (x=-1; x<=1; x++) {
+ if (posmask & (1<<((y+1)*3 + (x+1)))) {
+ ndc_x+= x;
+ ndc_y+= y;
+ div++;
+ }
+ }
+ }
+
+ if (div) {
+ ndc_x/= div;
+ ndc_y/= div;
+ }
+
+ renderpos_r[0]= (scr_w-rendersize_r[0])*(ndc_x*0.5 + 0.5);
+#ifdef __APPLE__
+ /* 44 pixels is topbar and window header... awaiting better fixes in ghost :) */
+ rendersize_r[1]= CLAMPIS(rendersize_r[1], 0, scr_h-44-RW_HEADERY);
+ renderpos_r[1]= -44-RW_HEADERY+(scr_h-rendersize_r[1])*(ndc_y*0.5 + 0.5);
+#else
+ renderpos_r[1]= -RW_HEADERY+(scr_h-rendersize_r[1])*(ndc_y*0.5 + 0.5);
+#endif
+}
+
+/* init renderwin, alloc/open/resize */
+static void renderwin_init_display_cb(RenderResult *rr)
+{
+ if (G.afbreek != 1) {
+ int rendersize[2], renderpos[2], imagesize[2];
+
+ calc_renderwin_rectangle(rr->rectx, rr->recty, G.winpos, renderpos, rendersize);
+
+ imagesize[0]= rr->rectx;
+ imagesize[1]= rr->recty;
+
+ if (!render_win) {
+ open_renderwin(renderpos, rendersize, imagesize);
+ renderwin_reset_view(render_win); // incl. autozoom for large images
+ } else {
+ int win_x, win_y;
+ int win_w, win_h;
+
+ window_get_position(render_win->win, &win_x, &win_y);
+ window_get_size(render_win->win, &win_w, &win_h);
+ win_h-= RW_HEADERY;
+
+ /* XXX, this is nasty and I guess bound to cause problems,
+ * but to ensure the window is at the user specified position
+ * and size we reopen the window all the time... we need
+ * a ghost _set_position to fix this -zr
+ */
+
+ /* XXX, well... it is nasty yes, and reopens windows each time on
+ subsequent renders. Better rule is to make it reopen only only
+ size change, and use the preferred position only on open_renderwin
+ cases (ton)
+ */
+ if(rendersize[0]!= win_w || rendersize[1]!= win_h) {
+ BIF_close_render_display();
+ open_renderwin(renderpos, rendersize, imagesize);
+ }
+ else {
+ window_raise(render_win->win);
+ window_make_active(render_win->win);
+
+ mywinset(2); // to assign scissor/viewport again in mywindow.c. is hackish yes, but otherwise it draws in header of button for ogl header
+ {
+ rcti win_rct;
+ win_rct.xmin= win_rct.ymin= 0;
+ window_get_size(render_win->win, &win_rct.xmax, &win_rct.ymax);
+ win_rct.ymax-= RW_HEADERY;
+ glaDefine2DArea(&win_rct);
+ }
+ }
+
+ renderwin_reset_view(render_win);
+ render_win->active= 1;
+ }
+ /* make sure we are in normal draw again */
+ render_win->flags &= ~RW_FLAGS_ALPHA;
+
+ glFinish();
+ }
+}
+
+/* callback for redraw render win */
+static void renderwin_clear_display_cb(RenderResult *rr)
+{
+ if (render_win) {
+ window_make_active(render_win->win);
+ renderwin_draw(render_win, 1);
+ }
+}
+
+/* XXX, this is not good, we do this without any regard to state
+* ... better is to make this an optimization of a more clear
+* implementation. the bug shows up when you do something like
+* open the window, then draw part of the progress, then get
+* a redraw event. whatever can go wrong will. -zr
+*
+* Note: blocked queue handling while rendering to prevent that (ton)
+*/
+
+/* can get as well the full picture, as the parts while rendering */
+static void renderwin_progress(RenderWin *rw, RenderResult *rr, volatile rcti *renrect)
+{
+ rcti win_rct;
+ float *rectf= NULL, fullrect[2][2];
+ unsigned int *rect32= NULL;
+ int ymin, ymax, xmin, xmax;
+
+ /* if renrect argument, we only display scanlines */
+ if(renrect) {
+ /* if ymax==recty, rendering of layer is ready, we should not draw, other things happen... */
+ if(rr->renlay==NULL || renrect->ymax>=rr->recty)
+ return;
+
+ /* xmin here is first subrect x coord, xmax defines subrect width */
+ xmin = renrect->xmin;
+ xmax = renrect->xmax - xmin;
+ if (xmax<2) return;
+
+ ymin= renrect->ymin;
+ ymax= renrect->ymax - ymin;
+ if(ymax<2)
+ return;
+ renrect->ymin= renrect->ymax;
+ }
+ else {
+ xmin = ymin = 0;
+ xmax = rr->rectx - 2*rr->crop;
+ ymax = rr->recty - 2*rr->crop;
+ }
+
+ /* renderwindow cruft */
+ win_rct.xmin= win_rct.ymin= 0;
+ window_get_size(rw->win, &win_rct.xmax, &win_rct.ymax);
+ win_rct.ymax-= RW_HEADERY;
+ renderwin_get_fullrect(rw, fullrect);
+
+ /* find current float rect for display, first case is after composit... still weak */
+ if(rr->rectf)
+ rectf= rr->rectf;
+ else {
+ if(rr->rect32)
+ rect32= (unsigned int *)rr->rect32;
+ else {
+ if(rr->renlay==NULL || rr->renlay->rectf==NULL) return;
+ rectf= rr->renlay->rectf;
+ }
+ }
+ if(rectf) {
+ /* if scanline updates... */
+ rectf+= 4*(rr->rectx*ymin + xmin);
+
+ /* when rendering more pixels than needed, we crop away cruft */
+ if(rr->crop)
+ rectf+= 4*(rr->crop*rr->rectx + rr->crop);
+ }
+
+ /* tilerect defines drawing offset from (0,0) */
+ /* however, tilerect (xmin, ymin) is first pixel */
+ fullrect[0][0] += (rr->tilerect.xmin + rr->crop + xmin)*rw->zoom;
+ fullrect[0][1] += (rr->tilerect.ymin + rr->crop + ymin)*rw->zoom;
+
+ glEnable(GL_SCISSOR_TEST);
+ glaDefine2DArea(&win_rct);
+
+#ifdef __APPLE__
+#else
+ glDrawBuffer(GL_FRONT);
+#endif
+ glPixelZoom(rw->zoom, rw->zoom);
+
+ if(rect32)
+ glaDrawPixelsSafe(fullrect[0][0], fullrect[0][1], xmax, ymax, rr->rectx, GL_RGBA, GL_UNSIGNED_BYTE, rect32);
+ else
+ glaDrawPixelsSafe_to32(fullrect[0][0], fullrect[0][1], xmax, ymax, rr->rectx, rectf);
+
+ glPixelZoom(1.0, 1.0);
+
+#ifdef __APPLE__
+ window_swap_buffers(render_win->win);
+#else
+ glFlush();
+ glDrawBuffer(GL_BACK);
+#endif
+}
+
+
+/* in render window; display a couple of scanlines of rendered image */
+static void renderwin_progress_display_cb(RenderResult *rr, volatile rcti *rect)
+{
+ if (render_win) {
+ renderwin_progress(render_win, rr, rect);
+ }
+}
+
+/* -------------- callbacks for render loop: interactivity ----------------------- */
+
+/* string is RW_MAXTEXT chars min */
+void make_renderinfo_string(RenderStats *rs, char *str)
+{
+ extern char info_time_str[32]; // header_info.c
+ extern unsigned long mem_in_use, mmap_in_use;
+ float megs_used_memory, mmap_used_memory;
+ char *spos= str;
+
+ megs_used_memory= (mem_in_use-mmap_in_use)/(1024.0*1024.0);
+ mmap_used_memory= (mmap_in_use)/(1024.0*1024.0);
+
+ if(G.scene->lay & 0xFF000000)
+ spos+= sprintf(spos, "Localview | ");
+ else if(G.scene->r.scemode & R_SINGLE_LAYER)
+ spos+= sprintf(spos, "Single Layer | ");
+
+ if(rs->tothalo)
+ spos+= sprintf(spos, "Fra:%d Ve:%d Fa:%d Ha:%d La:%d Mem:%.2fM (%.2fM) ", (G.scene->r.cfra), rs->totvert, rs->totface, rs->tothalo, rs->totlamp, megs_used_memory, mmap_used_memory);
+ else
+ spos+= sprintf(spos, "Fra:%d Ve:%d Fa:%d La:%d Mem:%.2fM (%.2fM) ", (G.scene->r.cfra), rs->totvert, rs->totface, rs->totlamp, megs_used_memory, mmap_used_memory);
+
+ if(rs->curfield)
+ spos+= sprintf(spos, "Field %d ", rs->curfield);
+ if(rs->curblur)
+ spos+= sprintf(spos, "Blur %d ", rs->curblur);
+
+ BLI_timestr(rs->lastframetime, info_time_str);
+ spos+= sprintf(spos, "Time:%s ", info_time_str);
+
+ if(rs->infostr)
+ spos+= sprintf(spos, "| %s ", rs->infostr);
+
+ /* very weak... but 512 characters is quite safe... we cannot malloc during thread render */
+ if(spos >= str+RW_MAXTEXT)
+ printf("WARNING! renderwin text beyond limit \n");
+
+}
+
+/* callback for print info in top header of renderwin */
+static void renderwin_renderinfo_cb(RenderStats *rs)
+{
+
+ if(render_win) {
+
+ make_renderinfo_string(rs, render_win->render_text);
+
+#ifdef __APPLE__
+#else
+ glDrawBuffer(GL_FRONT);
+#endif
+ renderwin_draw_render_info(render_win);
+
+#ifdef __APPLE__
+ window_swap_buffers(render_win->win);
+#else
+ glFlush();
+ glDrawBuffer(GL_BACK);
+#endif
+ }
+
+}
+
+/* -------------- callback system to allow ESC from rendering ----------------------- */
+
+/* POSIX & WIN32: this function is called all the time, and should not use cpu or resources */
+static int test_break(void)
+{
+
+ if(G.afbreek==2) { /* code for testing queue */
+
+ G.afbreek= 0;
+
+ blender_test_break(); /* tests blender interface */
+
+ if (G.afbreek==0 && render_win) { /* tests window */
+ winlay_process_events(0);
+ // render_win can be closed in winlay_process_events()
+ if (render_win == 0 || (render_win->flags & RW_FLAGS_ESCAPE)) {
+ G.afbreek= 1;
+ }
+ }
+ }
+
+ if(G.afbreek==1) return 1;
+ else return 0;
+}
+
+
+
+#ifdef _WIN32
+/* we use the multimedia time here */
+static UINT uRenderTimerId;
+
+void CALLBACK interruptESC(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
+{
+ if(G.afbreek==0) G.afbreek= 2; /* code for read queue */
+}
+
+/* WIN32: init SetTimer callback */
+static void init_test_break_callback()
+{
+ timeBeginPeriod(50);
+ uRenderTimerId = timeSetEvent(250, 1, interruptESC, 0, TIME_PERIODIC);
+}
+
+/* WIN32: stop SetTimer callback */
+static void end_test_break_callback()
+{
+ timeEndPeriod(50);
+ timeKillEvent(uRenderTimerId);
+}
+
+#else
+/* all other OS's support signal(SIGVTALRM) */
+
+/* XXX The ESC problem: some unix users reported that ESC doesn't cancel
+ * renders anymore. Most complaints came from linux, but it's not
+ * general, not all linux users have the problem.
+ *
+ * From tests, the systems that do have it are not signalling SIGVTALRM
+ * interrupts (an issue with signals and threads). Using SIGALRM instead
+ * fixes the problem, at least while we investigate better.
+ *
+ * ITIMER_REAL (SIGALRM): timer that counts real system time
+ * ITIMER_VIRTUAL (SIGVTALRM): only counts time spent in its owner process */
+
+/* POSIX: this function goes in the signal() callback */
+static void interruptESC(int sig)
+{
+
+ if(G.afbreek==0) G.afbreek= 2; /* code for read queue */
+
+ /* call again, timer was reset */
+ signal(SIGALRM, interruptESC);
+}
+
+/* POSIX: initialize timer and signal */
+static void init_test_break_callback()
+{
+
+ struct itimerval tmevalue;
+
+ tmevalue.it_interval.tv_sec = 0;
+ tmevalue.it_interval.tv_usec = 250000;
+ /* when the first ? */
+ tmevalue.it_value.tv_sec = 0;
+ tmevalue.it_value.tv_usec = 10000;
+
+ signal(SIGALRM, interruptESC);
+ setitimer(ITIMER_REAL, &tmevalue, 0);
+}
+
+/* POSIX: stop timer and callback */
+static void end_test_break_callback()
+{
+ struct itimerval tmevalue;
+
+ memset(&tmevalue, 0, sizeof(struct itimerval));
+
+ setitimer(ITIMER_REAL, &tmevalue, 0);
+ signal(SIGALRM, SIG_IGN);
+
+}
+
+
+#endif
+
+
+
+/* -------------- callbacks for render loop: init & run! ----------------------- */
+
+
+/* - initialize displays
+ - set callbacks
+ - cleanup
+*/
+
+static void do_render(int anim)
+{
+ Image *ima;
+ Render *re= RE_NewRender(G.scene->id.name);
+ unsigned int lay= G.scene->lay;
+ int scemode= G.scene->r.scemode;
+ int sculptmode= G.f & G_SCULPTMODE;
+
+ /* UGLY! we set this flag to prevent renderwindow queue to execute another render */
+ /* is reset in RE_BlenderFrame */
+ G.rendering= 1;
+
+ /* set render callbacks, also starts ESC timer */
+ BIF_init_render_callbacks(re, 1);
+
+ waitcursor(1);
+ if(render_win)
+ window_set_cursor(render_win->win, CURSOR_WAIT);
+
+ if(G.obedit)
+ exit_editmode(0); /* 0 = no free data */
+
+ if(sculptmode) set_sculptmode();
+
+ /* allow localview render for objects with lights in normal layers */
+ if(curarea->spacetype==SPACE_VIEW3D) {
+ /* if view is defined (might not be if called from script), check and set layers. */
+ if(G.vd) {
+ if(G.vd->lay & 0xFF000000) {
+ G.scene->lay |= G.vd->lay;
+ G.scene->r.scemode |= R_SINGLE_LAYER;
+ }
+ else G.scene->lay= G.vd->lay;
+ }
+ }
+
+ if(anim)
+ RE_BlenderAnim(re, G.scene, G.scene->r.sfra, G.scene->r.efra);
+ else
+ RE_BlenderFrame(re, G.scene, G.scene->r.cfra);
+
+ /* restore local view exception */
+ G.scene->lay= lay;
+ G.scene->r.scemode= scemode;
+
+ if(render_win) window_set_cursor(render_win->win, CURSOR_STD);
+
+ free_filesel_spec(G.scene->r.pic);
+
+ G.afbreek= 0;
+ BIF_end_render_callbacks();
+
+ /* after an envmap creation... */
+// if(R.flag & R_REDRAW_PRV) {
+// BIF_preview_changed(ID_TE);
+// }
+
+ scene_update_for_newframe(G.scene, G.scene->lay); // no redraw needed, this restores to view as we left it
+
+ /* get a render result image, and make sure it is clean */
+ ima= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
+ BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE);
+
+ if(sculptmode) set_sculptmode();
+
+ waitcursor(0);
+}
+
+/* called before render, store old render in spare buffer */
+static void renderwin_store_spare(void)
+{
+ RenderResult rres;
+
+ if(render_win==0 || render_win->storespare==0)
+ return;
+
+ /* only store when it does not show spare */
+ if(render_win->showspare==0)
+ return;
+
+ render_win->showspare= 0;
+ window_set_title(render_win->win, renderwin_get_title(1));
+
+ BLI_strncpy(render_win->render_text_spare, render_win->render_text, RW_MAXTEXT);
+
+ if(render_win->rectspare) MEM_freeN(render_win->rectspare);
+ render_win->rectspare= NULL;
+ if(render_win->rectsparef) MEM_freeN(render_win->rectsparef);
+ render_win->rectsparef= NULL;
+
+ RE_GetResultImage(RE_GetRender(G.scene->id.name), &rres);
+
+ if(rres.rect32)
+ render_win->rectspare= MEM_dupallocN(rres.rect32);
+ else if(rres.rectf)
+ render_win->rectsparef= MEM_dupallocN(rres.rectf);
+
+ render_win->sparex= rres.rectx;
+ render_win->sparey= rres.recty;
+}
+
+/* -------------- API: externally called --------------- */
+
+static void error_cb(char *str){error(str);}
+static int esc_timer_set= 0;
+
+/* set callbacks, exported to sequence render too.
+ Only call in foreground (UI) renders. */
+
+void BIF_init_render_callbacks(Render *re, int do_display)
+{
+ if(do_display) {
+ if(G.displaymode!=R_DISPLAYWIN) {
+ if(render_win)
+ BIF_close_render_display();
+ imagewindow_render_callbacks(re);
+ }
+ else {
+ RE_display_init_cb(re, renderwin_init_display_cb);
+ RE_display_draw_cb(re, renderwin_progress_display_cb);
+ RE_display_clear_cb(re, renderwin_clear_display_cb);
+ RE_stats_draw_cb(re, renderwin_renderinfo_cb);
+ }
+ }
+
+ RE_error_cb(re, error_cb);
+
+ G.afbreek= 0;
+ if(render_win)
+ render_win->flags &= ~RW_FLAGS_ESCAPE;
+
+ /* start esc timer. ensure it happens once only */
+ if(esc_timer_set==0)
+ init_test_break_callback();
+ esc_timer_set++;
+
+ RE_test_break_cb(re, test_break);
+ RE_timecursor_cb(re, set_timecursor);
+
+}
+
+/* the init/end callbacks can be called multiple times (sequence render) */
+void BIF_end_render_callbacks(void)
+{
+ esc_timer_set--;
+ if(esc_timer_set==0) {
+ end_test_break_callback();
+
+ if(render_win)
+ mainwindow_make_active();
+ }
+}
+
+void BIF_store_spare(void)
+{
+ if(render_win)
+ renderwin_store_spare();
+ else
+ imagewin_store_spare();
+}
+
+/* set up display, render an image or scene */
+void BIF_do_render(int anim)
+{
+ int slink_flag = 0;
+
+ if (G.f & G_DOSCRIPTLINKS) {
+ BPY_do_all_scripts(SCRIPT_RENDER);
+ if (!anim) { /* avoid FRAMECHANGED slink in render callback */
+ G.f &= ~G_DOSCRIPTLINKS;
+ slink_flag = 1;
+ }
+ }
+
+ BIF_store_spare();
+
+ do_render(anim);
+
+ if(G.scene->use_nodes) {
+ allqueue(REDRAWNODE, 1);
+ allqueue(REDRAWIMAGE, 1);
+ }
+ if (slink_flag) G.f |= G_DOSCRIPTLINKS;
+ if (G.f & G_DOSCRIPTLINKS) BPY_do_all_scripts(SCRIPT_POSTRENDER);
+}
+
+/* set up display, render the current area view in an image */
+/* the RE_Render is only used to make sure we got the picture in the result */
+void BIF_do_ogl_render(View3D *v3d, int anim)
+{
+ Render *re= RE_NewRender(G.scene->id.name);
+ RenderResult *rr;
+ int winx, winy;
+
+ G.afbreek= 0;
+ init_test_break_callback();
+
+ winx= (G.scene->r.size*G.scene->r.xsch)/100;
+ winy= (G.scene->r.size*G.scene->r.ysch)/100;
+
+ RE_InitState(re, &G.scene->r, winx, winy, NULL);
+
+ /* for now, result is defaulting to floats still... */
+ rr= RE_GetResult(re);
+ if(rr->rect32==NULL)
+ rr->rect32= MEM_mallocN(sizeof(int)*winx*winy, "32 bits rects");
+
+ /* open window */
+ renderwin_init_display_cb(rr);
+ if(render_win)
+ render_win->flags &= ~RW_FLAGS_ESCAPE;
+
+ init_gl_stuff();
+
+ waitcursor(1);
+
+ if(anim) {
+ bMovieHandle *mh= BKE_get_movie_handle(G.scene->r.imtype);
+ int cfrao= CFRA;
+
+ if(BKE_imtype_is_movie(G.scene->r.imtype))
+ mh->start_movie(&G.scene->r, winx, winy);
+
+ for(CFRA= SFRA; CFRA<=EFRA; CFRA++) {
+ /* user event can close window */
+ if(render_win==NULL)
+ break;
+ drawview3d_render(v3d, winx, winy);
+ glReadPixels(0, 0, winx, winy, GL_RGBA, GL_UNSIGNED_BYTE, rr->rect32);
+ window_swap_buffers(render_win->win);
+
+ if(BKE_imtype_is_movie(G.scene->r.imtype)) {
+ mh->append_movie(CFRA, rr->rect32, winx, winy);
+ printf("Append frame %d", G.scene->r.cfra);
+ }
+ else {
+ ImBuf *ibuf= IMB_allocImBuf(winx, winy, G.scene->r.planes, 0, 0);
+ char name[FILE_MAXDIR+FILE_MAXFILE];
+ int ok;
+
+ BKE_makepicstring(name, G.scene->r.pic, G.scene->r.cfra, G.scene->r.imtype);
+
+ ibuf->rect= (unsigned int *)rr->rect32;
+ ok= BKE_write_ibuf(ibuf, name, G.scene->r.imtype, G.scene->r.subimtype, G.scene->r.quality);
+
+ if(ok==0) {
+ printf("Write error: cannot save %s\n", name);
+ break;
+ }
+ else printf("Saved: %s", name);
+
+ /* imbuf knows which rects are not part of ibuf */
+ IMB_freeImBuf(ibuf);
+ }
+ /* movie stats prints have no line break */
+ printf("\n");
+
+ if(test_break()) break;
+ }
+
+ if(BKE_imtype_is_movie(G.scene->r.imtype))
+ mh->end_movie();
+
+ CFRA= cfrao;
+ }
+ else {
+ drawview3d_render(v3d, winx, winy);
+ glReadPixels(0, 0, winx, winy, GL_RGBA, GL_UNSIGNED_BYTE, rr->rect32);
+ window_swap_buffers(render_win->win);
+ }
+
+ if(render_win)
+ renderwin_draw(render_win, 0);
+
+ mainwindow_make_active();
+
+ if(anim)
+ scene_update_for_newframe(G.scene, G.scene->lay); // no redraw needed, this restores to view as we left it
+
+ end_test_break_callback();
+ waitcursor(0);
+}
+
+void BIF_redraw_render_rect(void)
+{
+ /* redraw */
+ if (render_win) {
+ renderwin_queue_redraw(render_win);
+ }
+ else {
+ allqueue(REDRAWIMAGE, 0);
+ }
+}
+
+void BIF_swap_render_rects(void)
+{
+ RenderResult rres;
+
+ if(G.displaymode!=R_DISPLAYWIN) {
+ imagewindow_swap_render_rects();
+ }
+ else if(render_win) {
+
+ render_win->storespare= 1;
+ render_win->showspare ^= 1;
+
+ RE_GetResultImage(RE_GetRender(G.scene->id.name), &rres);
+
+ if(render_win->sparex!=rres.rectx || render_win->sparey!=rres.recty) {
+ if(render_win->rectspare) MEM_freeN(render_win->rectspare);
+ render_win->rectspare= NULL;
+ if(render_win->rectsparef) MEM_freeN(render_win->rectsparef);
+ render_win->rectsparef= NULL;
+ }
+
+ window_set_title(render_win->win, renderwin_get_title(1));
+ }
+
+ /* redraw */
+ BIF_redraw_render_rect();
+
+}
+
+/* called from usiblender.c too, to free and close renderwin */
+void BIF_close_render_display(void)
+{
+ if (render_win) {
+ if (render_win->info_text) MEM_freeN(render_win->info_text);
+ if (render_win->render_text) MEM_freeN(render_win->render_text);
+ if (render_win->render_text_spare) MEM_freeN(render_win->render_text_spare);
+ if (render_win->rectspare) MEM_freeN(render_win->rectspare);
+ if (render_win->rectsparef) MEM_freeN(render_win->rectsparef);
+
+ window_destroy(render_win->win); /* ghost close window */
+ MEM_freeN(render_win);
+
+ render_win= NULL;
+ }
+}
+
+
+/* typical with F11 key, show image or hide/close */
+void BIF_toggle_render_display(void)
+{
+
+ if (G.displaymode!=R_DISPLAYWIN) {
+ imagewindow_toggle_render();
+ }
+ else {
+ if (render_win) {
+ if(render_win->active) {
+ mainwindow_raise();
+ mainwindow_make_active();
+ render_win->active= 0;
+ }
+ else {
+ window_raise(render_win->win);
+ window_make_active(render_win->win);
+ render_win->active= 1;
+ }
+ }
+ else {
+ RenderResult *rr= RE_GetResult(RE_GetRender(G.scene->id.name));
+ if(rr) renderwin_init_display_cb(rr);
+ }
+ }
+}
+
+void BIF_renderwin_set_custom_cursor(unsigned char mask[16][2], unsigned char bitmap[16][2])
+{
+ if (render_win) {
+ window_set_custom_cursor(render_win->win, mask, bitmap, 7, 7);
+ }
+}
diff --git a/source/blender/src/resources.c b/source/blender/src/resources.c
new file mode 100644
index 00000000000..125c80093a8
--- /dev/null
+++ b/source/blender/src/resources.c
@@ -0,0 +1,913 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_listBase.h"
+#include "DNA_userdef_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "BKE_utildefines.h"
+
+#include "BIF_gl.h"
+#include "BIF_resources.h"
+#include "BIF_interface_icons.h"
+
+#include "BLI_blenlib.h"
+#include "blendef.h" // CLAMP
+#include "datatoc.h"
+
+/* global for themes */
+typedef void (*VectorDrawFunc)(int x, int y, int w, int h, float alpha);
+
+static bTheme *theme_active=NULL;
+static int theme_spacetype= SPACE_VIEW3D;
+
+
+void BIF_resources_init(void)
+{
+ BIF_icons_init(BIFICONID_LAST+1);
+}
+
+void BIF_resources_free(void)
+{
+ BIF_icons_free();
+}
+
+
+/* ******************************************************** */
+/* THEMES */
+/* ******************************************************** */
+
+char *BIF_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
+{
+ ThemeSpace *ts= NULL;
+ static char error[4]={240, 0, 240, 255};
+ static char alert[4]={240, 60, 60, 255};
+ static char headerdesel[4]={0,0,0,255};
+ static char custom[4]={0,0,0,255};
+
+ char *cp= error;
+
+ if(btheme) {
+
+ // first check for ui buttons theme
+ if(colorid < TH_THEMEUI) {
+
+ switch(colorid) {
+ case TH_BUT_OUTLINE:
+ cp= btheme->tui.outline; break;
+ case TH_BUT_NEUTRAL:
+ cp= btheme->tui.neutral; break;
+ case TH_BUT_ACTION:
+ cp= btheme->tui.action; break;
+ case TH_BUT_SETTING:
+ cp= btheme->tui.setting; break;
+ case TH_BUT_SETTING1:
+ cp= btheme->tui.setting1; break;
+ case TH_BUT_SETTING2:
+ cp= btheme->tui.setting2; break;
+ case TH_BUT_NUM:
+ cp= btheme->tui.num; break;
+ case TH_BUT_TEXTFIELD:
+ cp= btheme->tui.textfield; break;
+ case TH_BUT_TEXTFIELD_HI:
+ cp= btheme->tui.textfield_hi; break;
+ case TH_BUT_POPUP:
+ cp= btheme->tui.popup; break;
+ case TH_BUT_TEXT:
+ cp= btheme->tui.text; break;
+ case TH_BUT_TEXT_HI:
+ cp= btheme->tui.text_hi; break;
+ case TH_MENU_BACK:
+ cp= btheme->tui.menu_back; break;
+ case TH_MENU_ITEM:
+ cp= btheme->tui.menu_item; break;
+ case TH_MENU_HILITE:
+ cp= btheme->tui.menu_hilite; break;
+ case TH_MENU_TEXT:
+ cp= btheme->tui.menu_text; break;
+ case TH_MENU_TEXT_HI:
+ cp= btheme->tui.menu_text_hi; break;
+
+ case TH_BUT_DRAWTYPE:
+ cp= &btheme->tui.but_drawtype; break;
+
+ case TH_ICONFILE:
+ cp= btheme->tui.iconfile; break;
+
+ case TH_REDALERT:
+ cp= alert; break;
+ case TH_CUSTOM:
+ cp= custom; break;
+ }
+ }
+ else {
+
+ switch(spacetype) {
+ case SPACE_BUTS:
+ ts= &btheme->tbuts;
+ break;
+ case SPACE_VIEW3D:
+ ts= &btheme->tv3d;
+ break;
+ case SPACE_IPO:
+ ts= &btheme->tipo;
+ break;
+ case SPACE_FILE:
+ ts= &btheme->tfile;
+ break;
+ case SPACE_NLA:
+ ts= &btheme->tnla;
+ break;
+ case SPACE_ACTION:
+ ts= &btheme->tact;
+ break;
+ case SPACE_SEQ:
+ ts= &btheme->tseq;
+ break;
+ case SPACE_IMAGE:
+ ts= &btheme->tima;
+ break;
+ case SPACE_IMASEL:
+ ts= &btheme->timasel;
+ break;
+ case SPACE_TEXT:
+ ts= &btheme->text;
+ break;
+ case SPACE_OOPS:
+ ts= &btheme->toops;
+ break;
+ case SPACE_SOUND:
+ ts= &btheme->tsnd;
+ break;
+ case SPACE_INFO:
+ ts= &btheme->tinfo;
+ break;
+ case SPACE_TIME:
+ ts= &btheme->ttime;
+ break;
+ case SPACE_NODE:
+ ts= &btheme->tnode;
+ break;
+ default:
+ ts= &btheme->tv3d;
+ break;
+ }
+
+ switch(colorid) {
+ case TH_BACK:
+ cp= ts->back; break;
+ case TH_TEXT:
+ cp= ts->text; break;
+ case TH_TEXT_HI:
+ cp= ts->text_hi; break;
+ case TH_HEADER:
+ cp= ts->header; break;
+ case TH_HEADERDESEL:
+ /* we calculate a dynamic builtin header deselect color, also for pulldowns... */
+ cp= ts->header;
+ headerdesel[0]= cp[0]>10?cp[0]-10:0;
+ headerdesel[1]= cp[1]>10?cp[1]-10:0;
+ headerdesel[2]= cp[2]>10?cp[2]-10:0;
+ cp= headerdesel;
+ break;
+ case TH_PANEL:
+ cp= ts->panel; break;
+ case TH_SHADE1:
+ cp= ts->shade1; break;
+ case TH_SHADE2:
+ cp= ts->shade2; break;
+ case TH_HILITE:
+ cp= ts->hilite; break;
+
+ case TH_GRID:
+ cp= ts->grid; break;
+ case TH_WIRE:
+ cp= ts->wire; break;
+ case TH_LAMP:
+ cp= ts->lamp; break;
+ case TH_SELECT:
+ cp= ts->select; break;
+ case TH_ACTIVE:
+ cp= ts->active; break;
+ case TH_GROUP:
+ cp= ts->group; break;
+ case TH_GROUP_ACTIVE:
+ cp= ts->group_active; break;
+ case TH_TRANSFORM:
+ cp= ts->transform; break;
+ case TH_VERTEX:
+ cp= ts->vertex; break;
+ case TH_VERTEX_SELECT:
+ cp= ts->vertex_select; break;
+ case TH_VERTEX_SIZE:
+ cp= &ts->vertex_size; break;
+ case TH_EDGE:
+ cp= ts->edge; break;
+ case TH_EDGE_SELECT:
+ cp= ts->edge_select; break;
+ case TH_EDGE_SEAM:
+ cp= ts->edge_seam; break;
+ case TH_EDGE_SHARP:
+ cp= ts->edge_sharp; break;
+ case TH_EDITMESH_ACTIVE:
+ cp= ts->editmesh_active; break;
+ case TH_EDGE_FACESEL:
+ cp= ts->edge_facesel; break;
+ case TH_FACE:
+ cp= ts->face; break;
+ case TH_FACE_SELECT:
+ cp= ts->face_select; break;
+ case TH_FACE_DOT:
+ cp= ts->face_dot; break;
+ case TH_FACEDOT_SIZE:
+ cp= &ts->facedot_size; break;
+ case TH_NORMAL:
+ cp= ts->normal; break;
+ case TH_BONE_SOLID:
+ cp= ts->bone_solid; break;
+ case TH_BONE_POSE:
+ cp= ts->bone_pose; break;
+ case TH_STRIP:
+ cp= ts->strip; break;
+ case TH_STRIP_SELECT:
+ cp= ts->strip_select; break;
+
+ case TH_SYNTAX_B:
+ cp= ts->syntaxb; break;
+ case TH_SYNTAX_V:
+ cp= ts->syntaxv; break;
+ case TH_SYNTAX_C:
+ cp= ts->syntaxc; break;
+ case TH_SYNTAX_L:
+ cp= ts->syntaxl; break;
+ case TH_SYNTAX_N:
+ cp= ts->syntaxn; break;
+
+ case TH_NODE:
+ cp= ts->syntaxl; break;
+ case TH_NODE_IN_OUT:
+ cp= ts->syntaxn; break;
+ case TH_NODE_OPERATOR:
+ cp= ts->syntaxb; break;
+ case TH_NODE_CONVERTOR:
+ cp= ts->syntaxv; break;
+ case TH_NODE_GROUP:
+ cp= ts->syntaxc; break;
+
+ case TH_SEQ_MOVIE:
+ cp= ts->movie; break;
+ case TH_SEQ_IMAGE:
+ cp= ts->image; break;
+ case TH_SEQ_SCENE:
+ cp= ts->scene; break;
+ case TH_SEQ_AUDIO:
+ cp= ts->audio; break;
+ case TH_SEQ_EFFECT:
+ cp= ts->effect; break;
+ case TH_SEQ_PLUGIN:
+ cp= ts->plugin; break;
+ case TH_SEQ_TRANSITION:
+ cp= ts->transition; break;
+ case TH_SEQ_META:
+ cp= ts->meta; break;
+
+ }
+
+ }
+ }
+
+ return cp;
+}
+
+#define SETCOL(col, r, g, b, a) col[0]=r; col[1]=g; col[2]= b; col[3]= a;
+
+/* initialize
+ Note: when you add new colors, created & saved themes need initialized
+ in usiblender.c, search for "versionfile"
+*/
+void BIF_InitTheme(void)
+{
+ bTheme *btheme= U.themes.first;
+
+ /* we search for the theme with name Default */
+ for(btheme= U.themes.first; btheme; btheme= btheme->next) {
+ if(strcmp("Default", btheme->name)==0) break;
+ }
+
+ if(btheme==NULL) {
+ btheme= MEM_callocN(sizeof(bTheme), "theme");
+ BLI_addtail(&U.themes, btheme);
+ strcpy(btheme->name, "Default");
+ }
+
+ BIF_SetTheme(NULL); // make sure the global used in this file is set
+
+ /* UI buttons (todo) */
+ SETCOL(btheme->tui.outline, 0xA0,0xA0,0xA0, 255);
+ SETCOL(btheme->tui.neutral, 0xA0,0xA0,0xA0, 255);
+ SETCOL(btheme->tui.action, 0xAD,0xA0,0x93, 255);
+ SETCOL(btheme->tui.setting, 0x8A,0x9E,0xA1, 255);
+ SETCOL(btheme->tui.setting1, 0xA1,0xA1,0xAE, 255);
+ SETCOL(btheme->tui.setting2, 0xA1,0x99,0xA7, 255);
+ SETCOL(btheme->tui.num, 0x90,0x90,0x90, 255);
+ SETCOL(btheme->tui.textfield, 0x90,0x90,0x90, 255);
+ SETCOL(btheme->tui.textfield_hi,0xc6,0x77,0x77, 255);
+ SETCOL(btheme->tui.popup, 0xA0,0xA0,0xA0, 255);
+
+ SETCOL(btheme->tui.text, 0,0,0, 255);
+ SETCOL(btheme->tui.text_hi, 255, 255, 255, 255);
+
+ SETCOL(btheme->tui.menu_back, 0xD2,0xD2,0xD2, 255);
+ SETCOL(btheme->tui.menu_item, 0xDA,0xDA,0xDA, 255);
+ SETCOL(btheme->tui.menu_hilite, 0x7F,0x7F,0x7F, 255);
+ SETCOL(btheme->tui.menu_text, 0, 0, 0, 255);
+ SETCOL(btheme->tui.menu_text_hi, 255, 255, 255, 255);
+ btheme->tui.but_drawtype= TH_SHADED;
+
+ BLI_strncpy(btheme->tui.iconfile, "", sizeof(btheme->tui.iconfile));
+
+ /* space view3d */
+ SETCOL(btheme->tv3d.back, 115, 115, 115, 255);
+ SETCOL(btheme->tv3d.text, 0, 0, 0, 255);
+ SETCOL(btheme->tv3d.text_hi, 255, 255, 255, 255);
+ SETCOL(btheme->tv3d.header, 195, 195, 195, 255);
+ SETCOL(btheme->tv3d.panel, 165, 165, 165, 127);
+
+ SETCOL(btheme->tv3d.shade1, 160, 160, 160, 100);
+ SETCOL(btheme->tv3d.shade2, 0x7f, 0x70, 0x70, 100);
+
+ SETCOL(btheme->tv3d.grid, 92, 92, 92, 255);
+ SETCOL(btheme->tv3d.wire, 0x0, 0x0, 0x0, 255);
+ SETCOL(btheme->tv3d.lamp, 0, 0, 0, 40);
+ SETCOL(btheme->tv3d.select, 0xff, 0x88, 0xff, 255);
+ SETCOL(btheme->tv3d.active, 0xff, 0xbb, 0xff, 255);
+ SETCOL(btheme->tv3d.group, 0x10, 0x40, 0x10, 255);
+ SETCOL(btheme->tv3d.group_active, 0x55, 0xbb, 0x55, 255);
+ SETCOL(btheme->tv3d.transform, 0xff, 0xff, 0xff, 255);
+ SETCOL(btheme->tv3d.vertex, 0xff, 0x70, 0xff, 255);
+ SETCOL(btheme->tv3d.vertex_select, 0xff, 0xff, 0x70, 255);
+ btheme->tv3d.vertex_size= 2;
+ SETCOL(btheme->tv3d.edge, 0x0, 0x0, 0x0, 255);
+ SETCOL(btheme->tv3d.edge_select, 0xb0, 0xb0, 0x30, 255);
+ SETCOL(btheme->tv3d.edge_seam, 230, 150, 50, 255);
+ SETCOL(btheme->tv3d.edge_facesel, 75, 75, 75, 255);
+ SETCOL(btheme->tv3d.face, 0, 50, 150, 30);
+ SETCOL(btheme->tv3d.face_select, 200, 100, 200, 60);
+ SETCOL(btheme->tv3d.normal, 0x22, 0xDD, 0xDD, 255);
+ SETCOL(btheme->tv3d.face_dot, 255, 138, 48, 255);
+ btheme->tv3d.facedot_size= 4;
+
+ SETCOL(btheme->tv3d.bone_solid, 200, 200, 200, 255);
+ SETCOL(btheme->tv3d.bone_pose, 80, 200, 255, 80); // alpha 80 is not meant editable, used for wire+action draw
+
+
+ /* space buttons */
+ /* to have something initialized */
+ btheme->tbuts= btheme->tv3d;
+
+ SETCOL(btheme->tbuts.back, 180, 180, 180, 255);
+ SETCOL(btheme->tbuts.header, 195, 195, 195, 255);
+ SETCOL(btheme->tbuts.panel, 255, 255, 255, 40);
+
+ /* space ipo */
+ /* to have something initialized */
+ btheme->tipo= btheme->tv3d;
+
+ SETCOL(btheme->tipo.grid, 94, 94, 94, 255);
+ SETCOL(btheme->tipo.back, 120, 120, 120, 255);
+ SETCOL(btheme->tipo.header, 195, 195, 195, 255);
+ SETCOL(btheme->tipo.panel, 255, 255, 255, 150);
+ SETCOL(btheme->tipo.shade1, 172, 172, 172, 100);
+ SETCOL(btheme->tipo.shade2, 0x70, 0x70, 0x70, 100);
+ SETCOL(btheme->tipo.vertex, 0xff, 0x70, 0xff, 255);
+ SETCOL(btheme->tipo.vertex_select, 0xff, 0xff, 0x70, 255);
+ SETCOL(btheme->tipo.hilite, 0x60, 0xc0, 0x40, 255);
+ btheme->tipo.vertex_size= 3;
+
+ /* space file */
+ /* to have something initialized */
+ btheme->tfile= btheme->tv3d;
+ SETCOL(btheme->tfile.back, 128, 128, 128, 255);
+ SETCOL(btheme->tfile.text, 0, 0, 0, 255);
+ SETCOL(btheme->tfile.text_hi, 255, 255, 255, 255);
+ SETCOL(btheme->tfile.header, 182, 182, 182, 255);
+ SETCOL(btheme->tfile.hilite, 0xA0, 0xA0, 0xD0, 255); // selected files
+
+
+ /* space action */
+ btheme->tact= btheme->tv3d;
+ SETCOL(btheme->tact.back, 116, 116, 116, 255);
+ SETCOL(btheme->tact.text, 0, 0, 0, 255);
+ SETCOL(btheme->tact.text_hi, 255, 255, 255, 255);
+ SETCOL(btheme->tact.header, 182, 182, 182, 255);
+ SETCOL(btheme->tact.grid, 94, 94, 94, 255);
+ SETCOL(btheme->tact.face, 166, 166, 166, 255); // RVK
+ SETCOL(btheme->tact.shade1, 172, 172, 172, 255); // sliders
+ SETCOL(btheme->tact.shade2, 84, 44, 31, 100); // bar
+ SETCOL(btheme->tact.hilite, 17, 27, 60, 100); // bar
+ SETCOL(btheme->tact.strip_select, 0xff, 0xff, 0xaa, 255);
+ SETCOL(btheme->tact.strip, 0xe4, 0x9c, 0xc6, 255);
+
+ /* space nla */
+ btheme->tnla= btheme->tv3d;
+ SETCOL(btheme->tnla.back, 116, 116, 116, 255);
+ SETCOL(btheme->tnla.text, 0, 0, 0, 255);
+ SETCOL(btheme->tnla.text_hi, 255, 255, 255, 255);
+ SETCOL(btheme->tnla.header, 182, 182, 182, 255);
+ SETCOL(btheme->tnla.grid, 94, 94, 94, 255);
+ SETCOL(btheme->tnla.shade1, 172, 172, 172, 255); // sliders
+ SETCOL(btheme->tnla.shade2, 84, 44, 31, 100); // bar
+ SETCOL(btheme->tnla.hilite, 17, 27, 60, 100); // bar
+ SETCOL(btheme->tnla.strip_select, 0xff, 0xff, 0xaa, 255);
+ SETCOL(btheme->tnla.strip, 0xe4, 0x9c, 0xc6, 255);
+
+ /* space seq */
+ btheme->tseq= btheme->tv3d;
+ SETCOL(btheme->tseq.back, 116, 116, 116, 255);
+ SETCOL(btheme->tseq.movie, 81, 105, 135, 255);
+ SETCOL(btheme->tseq.image, 109, 88, 129, 255);
+ SETCOL(btheme->tseq.scene, 78, 152, 62, 255);
+ SETCOL(btheme->tseq.audio, 46, 143, 143, 255);
+ SETCOL(btheme->tseq.effect, 169, 84, 124, 255);
+ SETCOL(btheme->tseq.plugin, 126, 126, 80, 255);
+ SETCOL(btheme->tseq.transition, 162, 95, 111, 255);
+ SETCOL(btheme->tseq.meta, 109, 145, 131, 255);
+
+
+ /* space image */
+ btheme->tima= btheme->tv3d;
+ SETCOL(btheme->tima.back, 53, 53, 53, 255);
+ SETCOL(btheme->tima.vertex, 0xff, 0x70, 0xff, 255);
+ SETCOL(btheme->tima.vertex_select, 0xff, 0xff, 0x70, 255);
+ btheme->tima.vertex_size= 2;
+ SETCOL(btheme->tima.face, 0, 50, 150, 40);
+ SETCOL(btheme->tima.face_select, 200, 100, 200, 80);
+
+ /* space imageselect */
+ btheme->timasel= btheme->tv3d;
+ SETCOL(btheme->timasel.active, 195, 195, 195, 255); /* active tile */
+ SETCOL(btheme->timasel.grid, 94, 94, 94, 255); /* active file text */
+ SETCOL(btheme->timasel.back, 110, 110, 110, 255);
+ SETCOL(btheme->timasel.header, 195, 195, 195, 255);
+ SETCOL(btheme->timasel.shade1, 94, 94, 94, 255); /* bar */
+ SETCOL(btheme->timasel.shade2, 172, 172, 172, 255); /* sliders */
+ SETCOL(btheme->timasel.hilite, 17, 27, 60, 100); /* selected tile */
+ SETCOL(btheme->timasel.text, 0, 0, 0, 255);
+ SETCOL(btheme->timasel.text_hi, 255, 255, 255, 255);
+ SETCOL(btheme->timasel.panel, 132, 132, 132, 255);
+
+ /* space text */
+ btheme->text= btheme->tv3d;
+ SETCOL(btheme->text.back, 153, 153, 153, 255);
+ SETCOL(btheme->text.shade1, 143, 143, 143, 255);
+ SETCOL(btheme->text.shade2, 0xc6, 0x77, 0x77, 255);
+ SETCOL(btheme->text.hilite, 255, 0, 0, 255);
+
+ /* syntax highlighting */
+ SETCOL(btheme->text.syntaxn, 0, 0, 200, 255); /* Numbers Blue*/
+ SETCOL(btheme->text.syntaxl, 100, 0, 0, 255); /* Strings red */
+ SETCOL(btheme->text.syntaxc, 0, 100, 50, 255); /* Comments greenish */
+ SETCOL(btheme->text.syntaxv, 95, 95, 0, 255); /* Special */
+ SETCOL(btheme->text.syntaxb, 128, 0, 80, 255); /* Builtin, red-purple */
+
+ /* space oops */
+ btheme->toops= btheme->tv3d;
+ SETCOL(btheme->toops.back, 153, 153, 153, 255);
+
+ /* space info */
+ btheme->tinfo= btheme->tv3d;
+ SETCOL(btheme->tinfo.back, 153, 153, 153, 255);
+
+ /* space sound */
+ btheme->tsnd= btheme->tv3d;
+ SETCOL(btheme->tsnd.back, 153, 153, 153, 255);
+ SETCOL(btheme->tsnd.shade1, 173, 173, 173, 255); // sliders
+ SETCOL(btheme->tsnd.grid, 140, 140, 140, 255);
+
+ /* space time */
+ btheme->ttime= btheme->tsnd; // same as sound space
+
+ /* space node, re-uses syntax color storage */
+ btheme->tnode= btheme->tv3d;
+ SETCOL(btheme->tnode.edge_select, 255, 255, 255, 255);
+ SETCOL(btheme->tnode.syntaxl, 150, 150, 150, 255); /* TH_NODE, backdrop */
+ SETCOL(btheme->tnode.syntaxn, 129, 131, 144, 255); /* in/output */
+ SETCOL(btheme->tnode.syntaxb, 127,127,127, 255); /* operator */
+ SETCOL(btheme->tnode.syntaxv, 142, 138, 145, 255); /* generator */
+ SETCOL(btheme->tnode.syntaxc, 120, 145, 120, 255); /* group */
+
+}
+
+char *BIF_ThemeColorsPup(int spacetype)
+{
+ char *cp= MEM_callocN(32*32, "theme pup");
+ char *str = cp;
+
+ if(spacetype==0) {
+ str += sprintf(str, "Outline %%x%d|", TH_BUT_OUTLINE);
+ str += sprintf(str, "Neutral %%x%d|", TH_BUT_NEUTRAL);
+ str += sprintf(str, "Action %%x%d|", TH_BUT_ACTION);
+ str += sprintf(str, "Setting %%x%d|", TH_BUT_SETTING);
+ str += sprintf(str, "Special Setting 1%%x%d|", TH_BUT_SETTING1);
+ str += sprintf(str, "Special Setting 2 %%x%d|", TH_BUT_SETTING2);
+ str += sprintf(str, "Number Input %%x%d|", TH_BUT_NUM);
+ str += sprintf(str, "Text Input %%x%d|", TH_BUT_TEXTFIELD);
+ str += sprintf(str, "Text Input Highlight %%x%d|", TH_BUT_TEXTFIELD_HI);
+ str += sprintf(str, "Popup %%x%d|", TH_BUT_POPUP);
+ str += sprintf(str, "Text %%x%d|", TH_BUT_TEXT);
+ str += sprintf(str, "Text Highlight %%x%d|", TH_BUT_TEXT_HI);
+ str += sprintf(str, "%%l|");
+ str += sprintf(str, "Menu Background %%x%d|", TH_MENU_BACK);
+ str += sprintf(str, "Menu Item %%x%d|", TH_MENU_ITEM);
+ str += sprintf(str, "Menu Item Highlight %%x%d|", TH_MENU_HILITE);
+ str += sprintf(str, "Menu Text %%x%d|", TH_MENU_TEXT);
+ str += sprintf(str, "Menu Text Highlight %%x%d|", TH_MENU_TEXT_HI);
+ str += sprintf(str, "%%l|");
+ str += sprintf(str, "Drawtype %%x%d|", TH_BUT_DRAWTYPE);
+ str += sprintf(str, "%%l|");
+ str += sprintf(str, "Icon File %%x%d|", TH_ICONFILE);
+ }
+ else {
+ // first defaults for each space
+ str += sprintf(str, "Background %%x%d|", TH_BACK);
+ str += sprintf(str, "Text %%x%d|", TH_TEXT);
+ str += sprintf(str, "Text Highlight %%x%d|", TH_TEXT_HI);
+ str += sprintf(str, "Header %%x%d|", TH_HEADER);
+
+ switch(spacetype) {
+ case SPACE_VIEW3D:
+ str += sprintf(str, "Panel %%x%d|", TH_PANEL);
+ str += sprintf(str, "%%l|");
+ str += sprintf(str, "Grid %%x%d|", TH_GRID);
+ str += sprintf(str, "Wire %%x%d|", TH_WIRE);
+ str += sprintf(str, "Lamp %%x%d|", TH_LAMP);
+ str += sprintf(str, "Object Selected %%x%d|", TH_SELECT);
+ str += sprintf(str, "Object Active %%x%d|", TH_ACTIVE);
+ str += sprintf(str, "Object Grouped %%x%d|", TH_GROUP);
+ str += sprintf(str, "Object Grouped Active %%x%d|", TH_GROUP_ACTIVE);
+ str += sprintf(str, "Transform %%x%d|", TH_TRANSFORM);
+ str += sprintf(str, "%%l|");
+ str += sprintf(str, "Vertex %%x%d|", TH_VERTEX);
+ str += sprintf(str, "Vertex Selected %%x%d|", TH_VERTEX_SELECT);
+ str += sprintf(str, "Vertex Size %%x%d|", TH_VERTEX_SIZE);
+ str += sprintf(str, "Edge Selected %%x%d|", TH_EDGE_SELECT);
+ str += sprintf(str, "Edge Seam %%x%d|", TH_EDGE_SEAM);
+ str += sprintf(str, "Edge Sharp %%x%d|", TH_EDGE_SHARP);
+ str += sprintf(str, "Edge UV Face Select %%x%d|", TH_EDGE_FACESEL);
+ str += sprintf(str, "Face (transp) %%x%d|", TH_FACE);
+ str += sprintf(str, "Face Selected (transp) %%x%d|", TH_FACE_SELECT);
+ str += sprintf(str, "Face Dot Selected %%x%d|", TH_FACE_DOT);
+ str += sprintf(str, "Face Dot Size %%x%d|", TH_FACEDOT_SIZE);
+ str += sprintf(str, "Active Vert/Edge/Face %%x%d|", TH_EDITMESH_ACTIVE);
+ str += sprintf(str, "Normal %%x%d|", TH_NORMAL);
+ str += sprintf(str, "Bone Solid %%x%d|", TH_BONE_SOLID);
+ str += sprintf(str, "Bone Pose %%x%d", TH_BONE_POSE);
+ break;
+ case SPACE_IPO:
+ str += sprintf(str, "Panel %%x%d|", TH_PANEL);
+ str += sprintf(str, "%%l|");
+ str += sprintf(str, "Grid %%x%d|", TH_GRID);
+ str += sprintf(str, "Window Sliders %%x%d|", TH_SHADE1);
+ str += sprintf(str, "Ipo Channels %%x%d|", TH_SHADE2);
+ str += sprintf(str, "Vertex %%x%d|", TH_VERTEX);
+ str += sprintf(str, "Vertex Selected %%x%d|", TH_VERTEX_SELECT);
+ str += sprintf(str, "Vertex Size %%x%d|", TH_VERTEX_SIZE);
+ break;
+ case SPACE_FILE:
+ str += sprintf(str, "Selected file %%x%d", TH_HILITE);
+ break;
+ case SPACE_NLA:
+ //str += sprintf(str, "Panel %%x%d|", TH_PANEL);
+ str += sprintf(str, "%%l|");
+ str += sprintf(str, "Grid %%x%d|", TH_GRID);
+ str += sprintf(str, "View Sliders %%x%d|", TH_SHADE1);
+ str += sprintf(str, "Bars %%x%d|", TH_SHADE2);
+ str += sprintf(str, "Bars selected %%x%d|", TH_HILITE);
+ str += sprintf(str, "Strips %%x%d|", TH_STRIP);
+ str += sprintf(str, "Strips selected %%x%d|", TH_STRIP_SELECT);
+ break;
+ case SPACE_ACTION:
+ //str += sprintf(str, "Panel %%x%d|", TH_PANEL);
+ str += sprintf(str, "%%l|");
+ str += sprintf(str, "Grid %%x%d|", TH_GRID);
+ str += sprintf(str, "RVK Sliders %%x%d|", TH_FACE);
+ str += sprintf(str, "View Sliders %%x%d|", TH_SHADE1);
+ str += sprintf(str, "Channels %%x%d|", TH_SHADE2);
+ str += sprintf(str, "Channels Selected %%x%d|", TH_HILITE);
+ str += sprintf(str, "Long Key %%x%d|", TH_STRIP);
+ str += sprintf(str, "Long Key selected %%x%d|", TH_STRIP_SELECT);
+ break;
+ case SPACE_IMAGE:
+ str += sprintf(str, "%%l|");
+ str += sprintf(str, "Vertex %%x%d|", TH_VERTEX);
+ str += sprintf(str, "Vertex Selected %%x%d|", TH_VERTEX_SELECT);
+ str += sprintf(str, "Vertex Size %%x%d|", TH_VERTEX_SIZE);
+ str += sprintf(str, "Face %%x%d|", TH_FACE);
+ str += sprintf(str, "Face Selected %%x%d", TH_FACE_SELECT);
+ break;
+ case SPACE_SEQ:
+ str += sprintf(str, "Grid %%x%d|", TH_GRID);
+ str += sprintf(str, "Window Sliders %%x%d|", TH_SHADE1);
+ str += sprintf(str, "%%l|");
+ str += sprintf(str, "Movie Strip %%x%d|", TH_SEQ_MOVIE);
+ str += sprintf(str, "Image Strip %%x%d|", TH_SEQ_IMAGE);
+ str += sprintf(str, "Scene Strip %%x%d|", TH_SEQ_SCENE);
+ str += sprintf(str, "Audio Strip %%x%d|", TH_SEQ_AUDIO);
+ str += sprintf(str, "Effect Strip %%x%d|", TH_SEQ_EFFECT);
+ str += sprintf(str, "Plugin Strip %%x%d|", TH_SEQ_PLUGIN);
+ str += sprintf(str, "Transition Strip %%x%d|", TH_SEQ_TRANSITION);
+ str += sprintf(str, "Meta Strip %%x%d|", TH_SEQ_META);
+ break;
+ case SPACE_SOUND:
+ str += sprintf(str, "Grid %%x%d|", TH_GRID);
+ str += sprintf(str, "Window Slider %%x%d|", TH_SHADE1);
+ break;
+ case SPACE_BUTS:
+ str += sprintf(str, "Panel %%x%d|", TH_PANEL);
+ break;
+ case SPACE_IMASEL:
+ str += sprintf(str, "Tiles %%x%d|", TH_PANEL);
+ str += sprintf(str, "Scrollbar %%x%d|", TH_SHADE1);
+ str += sprintf(str, "Scroll Handle %%x%d|", TH_SHADE2);
+ str += sprintf(str, "Selected File %%x%d|", TH_HILITE);
+ str += sprintf(str, "Active File %%x%d|", TH_ACTIVE);
+ str += sprintf(str, "Active File Text%%x%d|", TH_GRID);
+ break;
+ case SPACE_TEXT:
+ str += sprintf(str, "Scroll Bar %%x%d|", TH_SHADE1);
+ str += sprintf(str, "Selected Text %%x%d|", TH_SHADE2);
+ str += sprintf(str, "Cursor %%x%d|", TH_HILITE);
+ str += sprintf(str, "%%l|");
+ str += sprintf(str, "Syntax Builtin %%x%d|", TH_SYNTAX_B);
+ str += sprintf(str, "Syntax Special %%x%d|", TH_SYNTAX_V);
+ str += sprintf(str, "Syntax Comment %%x%d|", TH_SYNTAX_C);
+ str += sprintf(str, "Syntax Strings %%x%d|", TH_SYNTAX_L);
+ str += sprintf(str, "Syntax Numbers %%x%d|", TH_SYNTAX_N);
+ break;
+ case SPACE_TIME:
+ str += sprintf(str, "Grid %%x%d|", TH_GRID);
+ break;
+ case SPACE_NODE:
+ str += sprintf(str, "Wires %%x%d|", TH_WIRE);
+ str += sprintf(str, "Wires Select %%x%d|", TH_EDGE_SELECT);
+ str += sprintf(str, "%%l|");
+ str += sprintf(str, "Node Backdrop %%x%d|", TH_NODE);
+ str += sprintf(str, "In/Out Node %%x%d|", TH_NODE_IN_OUT);
+ str += sprintf(str, "Convertor Node %%x%d|", TH_NODE_CONVERTOR);
+ str += sprintf(str, "Operator Node %%x%d|", TH_NODE_OPERATOR);
+ str += sprintf(str, "Group Node %%x%d|", TH_NODE_GROUP);
+ break;
+ }
+ }
+ return cp;
+}
+
+void BIF_SetTheme(ScrArea *sa)
+{
+ if(sa==NULL) { // called for safety, when delete themes
+ theme_active= U.themes.first;
+ theme_spacetype= SPACE_VIEW3D;
+ }
+ else {
+ // later on, a local theme can be found too
+ theme_active= U.themes.first;
+ theme_spacetype= sa->spacetype;
+
+ }
+}
+
+// for space windows only
+void BIF_ThemeColor(int colorid)
+{
+ char *cp;
+
+ cp= BIF_ThemeGetColorPtr(theme_active, theme_spacetype, colorid);
+ glColor3ub(cp[0], cp[1], cp[2]);
+
+}
+
+// plus alpha
+void BIF_ThemeColor4(int colorid)
+{
+ char *cp;
+
+ cp= BIF_ThemeGetColorPtr(theme_active, theme_spacetype, colorid);
+ glColor4ub(cp[0], cp[1], cp[2], cp[3]);
+
+}
+
+// set the color with offset for shades
+void BIF_ThemeColorShade(int colorid, int offset)
+{
+ int r, g, b;
+ char *cp;
+
+ cp= BIF_ThemeGetColorPtr(theme_active, theme_spacetype, colorid);
+ r= offset + (int) cp[0];
+ CLAMP(r, 0, 255);
+ g= offset + (int) cp[1];
+ CLAMP(g, 0, 255);
+ b= offset + (int) cp[2];
+ CLAMP(b, 0, 255);
+ //glColor3ub(r, g, b);
+ glColor4ub(r, g, b, cp[3]);
+}
+void BIF_ThemeColorShadeAlpha(int colorid, int coloffset, int alphaoffset)
+{
+ int r, g, b, a;
+ char *cp;
+
+ cp= BIF_ThemeGetColorPtr(theme_active, theme_spacetype, colorid);
+ r= coloffset + (int) cp[0];
+ CLAMP(r, 0, 255);
+ g= coloffset + (int) cp[1];
+ CLAMP(g, 0, 255);
+ b= coloffset + (int) cp[2];
+ CLAMP(b, 0, 255);
+ a= alphaoffset + (int) cp[3];
+ CLAMP(a, 0, 255);
+ glColor4ub(r, g, b, a);
+}
+
+// blend between to theme colors, and set it
+void BIF_ThemeColorBlend(int colorid1, int colorid2, float fac)
+{
+ int r, g, b;
+ char *cp1, *cp2;
+
+ cp1= BIF_ThemeGetColorPtr(theme_active, theme_spacetype, colorid1);
+ cp2= BIF_ThemeGetColorPtr(theme_active, theme_spacetype, colorid2);
+
+ if(fac<0.0) fac=0.0; else if(fac>1.0) fac= 1.0;
+ r= floor((1.0-fac)*cp1[0] + fac*cp2[0]);
+ g= floor((1.0-fac)*cp1[1] + fac*cp2[1]);
+ b= floor((1.0-fac)*cp1[2] + fac*cp2[2]);
+
+ glColor3ub(r, g, b);
+}
+
+// blend between to theme colors, shade it, and set it
+void BIF_ThemeColorBlendShade(int colorid1, int colorid2, float fac, int offset)
+{
+ int r, g, b;
+ char *cp1, *cp2;
+
+ cp1= BIF_ThemeGetColorPtr(theme_active, theme_spacetype, colorid1);
+ cp2= BIF_ThemeGetColorPtr(theme_active, theme_spacetype, colorid2);
+
+ if(fac<0.0) fac=0.0; else if(fac>1.0) fac= 1.0;
+ r= offset+floor((1.0-fac)*cp1[0] + fac*cp2[0]);
+ g= offset+floor((1.0-fac)*cp1[1] + fac*cp2[1]);
+ b= offset+floor((1.0-fac)*cp1[2] + fac*cp2[2]);
+
+ r= r<0?0:(r>255?255:r);
+ g= g<0?0:(g>255?255:g);
+ b= b<0?0:(b>255?255:b);
+
+ glColor3ub(r, g, b);
+}
+
+// get individual values, not scaled
+float BIF_GetThemeValuef(int colorid)
+{
+ char *cp;
+
+ cp= BIF_ThemeGetColorPtr(theme_active, theme_spacetype, colorid);
+ return ((float)cp[0]);
+
+}
+
+// get individual values, not scaled
+int BIF_GetThemeValue(int colorid)
+{
+ char *cp;
+
+ cp= BIF_ThemeGetColorPtr(theme_active, theme_spacetype, colorid);
+ return ((int) cp[0]);
+
+}
+
+
+// get the color, range 0.0-1.0
+void BIF_GetThemeColor3fv(int colorid, float *col)
+{
+ char *cp;
+
+ cp= BIF_ThemeGetColorPtr(theme_active, theme_spacetype, colorid);
+ col[0]= ((float)cp[0])/255.0;
+ col[1]= ((float)cp[1])/255.0;
+ col[2]= ((float)cp[2])/255.0;
+}
+
+// get the color, in char pointer
+void BIF_GetThemeColor3ubv(int colorid, char *col)
+{
+ char *cp;
+
+ cp= BIF_ThemeGetColorPtr(theme_active, theme_spacetype, colorid);
+ col[0]= cp[0];
+ col[1]= cp[1];
+ col[2]= cp[2];
+}
+
+// get the color, in char pointer
+void BIF_GetThemeColor4ubv(int colorid, char *col)
+{
+ char *cp;
+
+ cp= BIF_ThemeGetColorPtr(theme_active, theme_spacetype, colorid);
+ col[0]= cp[0];
+ col[1]= cp[1];
+ col[2]= cp[2];
+ col[3]= cp[3];
+}
+
+void BIF_GetThemeColorType4ubv(int colorid, int spacetype, char *col)
+{
+ char *cp;
+
+ cp= BIF_ThemeGetColorPtr(theme_active, spacetype, colorid);
+ col[0]= cp[0];
+ col[1]= cp[1];
+ col[2]= cp[2];
+ col[3]= cp[3];
+}
+
+// blends and shades between two char color pointers
+void BIF_ColorPtrBlendShade3ubv(char *cp1, char *cp2, float fac, int offset)
+{
+ int r, g, b;
+
+ if(fac<0.0) fac=0.0; else if(fac>1.0) fac= 1.0;
+ r= offset+floor((1.0-fac)*cp1[0] + fac*cp2[0]);
+ g= offset+floor((1.0-fac)*cp1[1] + fac*cp2[1]);
+ b= offset+floor((1.0-fac)*cp1[2] + fac*cp2[2]);
+
+ r= r<0?0:(r>255?255:r);
+ g= g<0?0:(g>255?255:g);
+ b= b<0?0:(b>255?255:b);
+
+ glColor3ub(r, g, b);
+}
+
+// get a 3 byte color, blended and shaded between two other char color pointers
+void BIF_GetColorPtrBlendShade3ubv(char *cp1, char *cp2, char *col, float fac, int offset)
+{
+ int r, g, b;
+
+ if(fac<0.0) fac=0.0; else if(fac>1.0) fac= 1.0;
+ r= offset+floor((1.0-fac)*cp1[0] + fac*cp2[0]);
+ g= offset+floor((1.0-fac)*cp1[1] + fac*cp2[1]);
+ b= offset+floor((1.0-fac)*cp1[2] + fac*cp2[2]);
+
+ r= r<0?0:(r>255?255:r);
+ g= g<0?0:(g>255?255:g);
+ b= b<0?0:(b>255?255:b);
+
+ col[0] = r;
+ col[1] = g;
+ col[2] = b;
+}
diff --git a/source/blender/src/retopo.c b/source/blender/src/retopo.c
new file mode 100644
index 00000000000..4ef07b73061
--- /dev/null
+++ b/source/blender/src/retopo.c
@@ -0,0 +1,924 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 by Nicholas Bishop
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Implements the Retopo tools
+ *
+ * BIF_retopo.h
+ *
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_curve_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BDR_editobject.h"
+
+#include "BIF_editmesh.h"
+#include "BIF_editmode_undo.h"
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+#include "BIF_mywindow.h"
+#include "BIF_retopo.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_toolbox.h"
+
+#include "BKE_curve.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_mesh.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_editVert.h"
+
+#include "BSE_drawview.h"
+#include "BSE_edit.h"
+#include "BSE_view.h"
+
+#include "editmesh.h"
+#include "mydevice.h"
+
+#ifdef WIN32
+#define _USE_MATH_DEFINES
+#endif
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+typedef struct RetopoPaintHit {
+ struct RetopoPaintHit *next, *prev;
+ RetopoPaintPoint *intersection;
+ short index;
+ float where;
+} RetopoPaintHit;
+
+void retopo_do_2d(View3D *v3d, double proj[2], float *v, char adj);
+void retopo_paint_debug_print(RetopoPaintData *rpd);
+
+/* Painting */
+RetopoPaintData *get_retopo_paint_data()
+{
+ if(!retopo_mesh_paint_check()) return NULL;
+ if(!G.editMesh) return NULL;
+ return G.editMesh->retopo_paint_data;
+}
+
+char retopo_mesh_paint_check()
+{
+ return retopo_mesh_check() && G.scene->toolsettings->retopo_mode & RETOPO_PAINT;
+}
+
+void retopo_free_paint_data(RetopoPaintData *rpd)
+{
+ if(rpd) {
+ RetopoPaintLine *l;
+ for(l= rpd->lines.first; l; l= l->next) {
+ BLI_freelistN(&l->points);
+ BLI_freelistN(&l->hitlist);
+ }
+ BLI_freelistN(&rpd->lines);
+
+ BLI_freelistN(&rpd->intersections);
+
+ MEM_freeN(rpd);
+ }
+}
+
+void retopo_free_paint()
+{
+ retopo_free_paint_data(G.editMesh->retopo_paint_data);
+ G.editMesh->retopo_paint_data= NULL;
+}
+
+char line_intersection_2d(const vec2s *a, const vec2s *b, const vec2s *c, const vec2s *d, vec2s *out,
+ float *r, float *s)
+{
+ float den;
+ *r= (a->y - c->y) * (d->x - c->x) - (a->x - c->x) * (d->y - c->y);
+ *s= (a->y - c->y) * (b->x - a->x) - (a->x - c->x) * (b->y - a->y);
+ den= (b->x - a->x) * (d->y - c->y) - (b->y - a->y) * (d->x - c->x);
+
+ if((a->x==b->x && a->y==b->y) || (c->x==d->x && c->y==d->y)) return 0;
+
+ if(!den) return 0;
+
+ *r/= den;
+ *s/= den;
+
+ if(*s<0 || *s>=1 || *r<0 || *r>=1) return 0;
+
+ out->x= a->x + *r*(b->x - a->x);
+ out->y= a->y + *r*(b->y - a->y);
+ return 1;
+}
+
+void retopo_paint_add_line_hit(RetopoPaintLine *l, RetopoPaintPoint *p, RetopoPaintPoint *intersection, float w)
+{
+ RetopoPaintHit *prev, *hit= MEM_callocN(sizeof(RetopoPaintHit),"RetopoPaintHit");
+
+ hit->intersection= intersection;
+ hit->index= p->index;
+ hit->where= w;
+
+ prev= l->hitlist.first;
+ if(!prev) {
+ BLI_addtail(&l->hitlist,hit);
+ }
+ else if(prev->index>hit->index) {
+ BLI_addhead(&l->hitlist,hit);
+ }
+ else {
+ /* Move forward until we hit the next highest index */
+ while(prev->next) {
+ if(prev->next->index > hit->index) break;
+ prev= prev->next;
+ }
+ /* Move backward until we hit the next lowest where */
+ while(prev->prev && prev->prev->index==prev->index &&
+ prev->where > hit->where)
+ prev=prev->prev;
+ BLI_insertlink(&l->hitlist,prev,hit);
+ }
+
+ /* Removed duplicate intersections */
+ if(hit->prev && hit->prev->intersection==hit->intersection) {
+ BLI_freelinkN(&l->hitlist,hit);
+ }
+}
+
+char retopo_paint_add_intersection(RetopoPaintData *rpd, RetopoPaintLine *l1, RetopoPaintPoint *p1,
+ RetopoPaintLine *l2, RetopoPaintPoint *p2, vec2s *out, float r, float s)
+{
+ RetopoPaintPoint *p, *hit;
+ char found= 0;
+
+ for(p=rpd->intersections.first; p; p= p->next) {
+ if(sqrt(pow(p->loc.x-out->x,2)+pow(p->loc.y-out->y,2))<7) {
+ found= 1;
+ break;
+ }
+ }
+
+ if(!found) {
+ hit= MEM_callocN(sizeof(RetopoPaintPoint),"Retopo paint intersection");
+ hit->loc.x= out->x;
+ hit->loc.y= out->y;
+ BLI_addtail(&rpd->intersections,hit);
+ } else {
+ hit= p;
+ }
+
+ retopo_paint_add_line_hit(l1,p1,hit,r);
+ retopo_paint_add_line_hit(l2,p2,hit,s);
+
+ return !found;
+}
+
+
+/* Returns 1 if a new intersection was added */
+char do_line_intersection(RetopoPaintData *rpd, RetopoPaintLine *l1, RetopoPaintPoint *p1,
+ RetopoPaintLine *l2, RetopoPaintPoint *p2)
+{
+ vec2s out;
+ float r,s;
+ if(line_intersection_2d(&p1->loc, &p1->next->loc,
+ &p2->loc, &p2->next->loc,
+ &out,&r,&s)) {
+ if(retopo_paint_add_intersection(rpd,l1,p1,l2,p2,&out,r,s))
+ return 1;
+ }
+ return 0;
+}
+
+typedef struct FaceNode {
+ struct FaceNode *next, *prev;
+ MFace f;
+} FaceNode;
+
+char faces_equal(EditFace *f1, EditFace *f2)
+{
+ return editface_containsVert(f2,f1->v1) &&
+ editface_containsVert(f2,f1->v2) &&
+ editface_containsVert(f2,f1->v3) &&
+ (f1->v4 ? editface_containsVert(f2,f1->v4) : 1);
+}
+
+EditFace *addfaceif(EditMesh *em, EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4)
+{
+ EditFace *efa;
+
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(editface_containsVert(efa,v1) &&
+ editface_containsVert(efa,v2) &&
+ editface_containsVert(efa,v3) &&
+ (v4 ? editface_containsVert(efa,v4) : 1))
+ return NULL;
+ }
+
+ return addfacelist(v1,v2,v3,v4,NULL,NULL);
+}
+
+void retopo_paint_apply()
+{
+ RetopoPaintData *rpd= G.editMesh->retopo_paint_data;
+ EditVert *eve;
+
+ if(rpd) {
+ RetopoPaintLine *l1, *l2;
+ RetopoPaintPoint *p1, *p2;
+ unsigned hitcount= 0;
+ unsigned i;
+ RetopoPaintHit *h;
+ float hitco[3];
+
+ /* Find intersections */
+ BLI_freelistN(&rpd->intersections);
+ for(l1= rpd->lines.first; l1; l1= l1->next) {
+ for(l2= rpd->lines.first; l2; l2= l2->next) {
+ if(l1!=l2) {
+ for(p1= l1->points.first; p1 && p1!=l1->points.last; p1= p1->next) {
+ for(p2= l2->points.first; p2 && p2!=l2->points.last; p2= p2->next) {
+ if(p1!=p2) {
+ if(do_line_intersection(rpd,l1,p1,l2,p2))
+ ++hitcount;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /*topoPaintHit *hit;
+ l1= rpd->lines.first;
+ for(hit= l1->hitlist.first; hit; hit= hit->next) {
+ printf("\nhit(%p,%d) ",hit->intersection,hit->index);
+ }
+ fflush(stdout);*/
+
+ /* Deselect */
+ for(eve= G.editMesh->verts.first; eve; eve= eve->next)
+ eve->f &= ~SELECT;
+ EM_deselect_flush();
+
+ for(i=0; i<hitcount; ++i) {
+ RetopoPaintPoint *intersection= BLI_findlink(&rpd->intersections,i);
+ double proj[2] = {intersection->loc.x, intersection->loc.y};
+ retopo_do_2d(rpd->paint_v3d, proj, hitco, 1);
+ intersection->eve= addvertlist(hitco, NULL);
+ intersection->eve->f= SELECT;
+ }
+
+ for(l1= rpd->lines.first; l1; l1= l1->next) {
+ unsigned etcount= BLI_countlist(&l1->hitlist);
+ if(etcount>=2) {
+ for(h= l1->hitlist.first; (h && h->next); h= h->next)
+ addedgelist(h->intersection->eve,h->next->intersection->eve,NULL);
+ if(etcount>=3 && l1->cyclic)
+ addedgelist(((RetopoPaintHit*)l1->hitlist.first)->intersection->eve,
+ ((RetopoPaintHit*)l1->hitlist.last)->intersection->eve, NULL);
+ }
+ }
+
+ addfaces_from_edgenet();
+ }
+
+ retopo_free_paint();
+}
+
+void add_rppoint(RetopoPaintLine *l, short x, short y)
+{
+ RetopoPaintPoint *p= MEM_callocN(sizeof(RetopoPaintPoint),"RetopoPaintPoint");
+ double proj[2];
+ p->loc.x= x;
+ p->loc.y= y;
+ BLI_addtail(&l->points,p);
+ p->index= p->prev?p->prev->index+1:0;
+
+ proj[0] = p->loc.x;
+ proj[1] = p->loc.y;
+
+ retopo_do_2d(G.editMesh->retopo_paint_data->paint_v3d, proj, p->co, 1);
+}
+RetopoPaintLine *add_rpline(RetopoPaintData *rpd)
+{
+ RetopoPaintLine *l= MEM_callocN(sizeof(RetopoPaintLine),"RetopoPaintLine");
+ BLI_addtail(&rpd->lines,l);
+ return l;
+}
+
+void retopo_paint_toggle_cyclic(RetopoPaintLine *l)
+{
+ if(l==NULL)
+ return;
+ if(!l->cyclic) {
+ RetopoPaintPoint *pf= l->points.first;
+
+ if(pf) {
+ add_rppoint(l, pf->loc.x, pf->loc.y);
+ l->cyclic= l->points.last;
+ }
+ } else {
+ BLI_freelinkN(&l->points,l->cyclic);
+ l->cyclic= NULL;
+ }
+}
+
+void retopo_paint_add_line(RetopoPaintData *rpd, short mouse[2])
+{
+ RetopoPaintLine *l= add_rpline(rpd);
+ float range[2]= {mouse[0]-rpd->sloc[0],mouse[1]-rpd->sloc[1]};
+ int i;
+
+ /* Add initial point */
+ add_rppoint(l,rpd->sloc[0],rpd->sloc[1]);
+ for(i=0; i<G.scene->toolsettings->line_div; ++i) {
+ const float mul= (i+1.0f) / G.scene->toolsettings->line_div;
+ add_rppoint(l,rpd->sloc[0] + range[0]*mul,rpd->sloc[1] + range[1]*mul);
+ }
+
+ allqueue(REDRAWVIEW3D,0);
+}
+
+void retopo_paint_add_ellipse(RetopoPaintData *rpd, short mouse[2])
+{
+ int i;
+
+ add_rpline(rpd);
+ for (i=0; i<G.scene->toolsettings->ellipse_div; i++) {
+ float t= (float) i / G.scene->toolsettings->ellipse_div;
+ float cur= t*(M_PI*2);
+
+ float w= abs(mouse[0]-rpd->sloc[0]);
+ float h= abs(mouse[1]-rpd->sloc[1]);
+
+ add_rppoint(rpd->lines.last,cos(cur)*w+rpd->sloc[0],sin(cur)*h+rpd->sloc[1]);
+ }
+
+ retopo_paint_toggle_cyclic(rpd->lines.last);
+
+ allqueue(REDRAWVIEW3D,0);
+}
+
+void retopo_end_okee()
+{
+ if(okee("Apply retopo paint?"))
+ retopo_paint_apply();
+ else
+ retopo_free_paint();
+ G.scene->toolsettings->retopo_mode &= ~RETOPO_PAINT;
+}
+
+void retopo_paint_toggle(void *a, void *b)
+{
+ /* Note that these operations are reversed because mode bit has already been set! */
+ if(retopo_mesh_paint_check()) { /* Activate retopo paint */
+ RetopoPaintData *rpd= MEM_callocN(sizeof(RetopoPaintData),"RetopoPaintData");
+
+ G.editMesh->retopo_paint_data= rpd;
+ G.scene->toolsettings->retopo_paint_tool= RETOPO_PEN;
+ rpd->seldist= 15;
+ rpd->nearest.line= NULL;
+ G.scene->toolsettings->line_div= 25;
+ G.scene->toolsettings->ellipse_div= 25;
+ G.scene->toolsettings->retopo_hotspot= 1;
+ } else retopo_end_okee();
+
+ BIF_undo_push("Retopo toggle");
+
+ allqueue(REDRAWVIEW3D, 1);
+}
+
+void retopo_paint_view_update(struct View3D *v3d)
+{
+ RetopoPaintData *rpd= get_retopo_paint_data();
+
+ if(rpd && rpd->paint_v3d==v3d) {
+ RetopoPaintLine *l;
+ RetopoPaintPoint *p;
+ double ux, uy, uz;
+
+ for(l= rpd->lines.first; l; l= l->next) {
+ for(p= l->points.first; p; p= p->next) {
+ gluProject(p->co[0],p->co[1],p->co[2], v3d->retopo_view_data->mats.modelview,
+ v3d->retopo_view_data->mats.projection,
+ (GLint *)v3d->retopo_view_data->mats.viewport, &ux, &uy, &uz);
+ p->loc.x= ux;
+ p->loc.y= uy;
+ }
+ }
+ }
+}
+
+void retopo_force_update()
+{
+ RetopoPaintData *rpd= get_retopo_paint_data();
+
+ if(rpd) {
+ View3D *vd= rpd->paint_v3d;
+
+ if(vd) {
+ if(vd->depths) vd->depths->damaged= 1;
+ retopo_queue_updates(vd);
+ if(retopo_mesh_paint_check() && vd->retopo_view_data) {
+ /* Force redraw */
+ drawview3dspace(vd->area, vd);
+ retopo_paint_view_update(vd);
+ }
+ }
+ }
+}
+
+/* Returns 1 if event should be processed by caller, 0 otherwise */
+char retopo_paint(const unsigned short event)
+{
+ RetopoPaintData *rpd= get_retopo_paint_data();
+
+ if(!event) return 1;
+ if(rpd) {
+ RetopoPaintLine *l;
+ short mouse[2];
+ char lbut= get_mbut() & (U.flag & USER_LMOUSESELECT ? R_MOUSE : L_MOUSE);
+
+ if(rpd->paint_v3d && rpd->paint_v3d!=G.vd) return 1;
+
+ getmouseco_areawin(mouse);
+
+ if(rpd->in_drag && !lbut) { /* End drag */
+ rpd->in_drag= 0;
+
+ switch(G.scene->toolsettings->retopo_paint_tool) {
+ case RETOPO_PEN:
+ break;
+ case RETOPO_LINE:
+ retopo_paint_add_line(rpd, mouse);
+ break;
+ case RETOPO_ELLIPSE:
+ retopo_paint_add_ellipse(rpd, mouse);
+ break;
+ }
+ BIF_undo_push("Retopo paint");
+ }
+
+ switch(event) {
+ case MOUSEX:
+ case MOUSEY:
+ switch(G.scene->toolsettings->retopo_paint_tool) {
+ case RETOPO_PEN:
+ if(rpd->in_drag && rpd->lines.last) {
+ l= rpd->lines.last;
+
+ if(((RetopoPaintPoint*)l->points.last)->loc.x != mouse[0] ||
+ ((RetopoPaintPoint*)l->points.last)->loc.y != mouse[1]) {
+ add_rppoint(l,mouse[0],mouse[1]);
+ }
+ rpd->nearest.line= NULL;
+
+ break;
+ } else if(G.scene->toolsettings->retopo_hotspot) { /* Find nearest endpoint */
+ float sdist;
+ RetopoPaintLine *l= rpd->lines.first;
+ RetopoPaintSel n= {NULL,NULL,l,1};
+ sdist= rpd->seldist + 10;
+ for(l= rpd->lines.first; l; l= l->next) {
+ float tdist;
+ RetopoPaintPoint *p1= l->points.first, *p2= l->points.last;
+
+ tdist= sqrt(pow(mouse[0] - p1->loc.x,2)+pow(mouse[1] - p1->loc.y,2));
+ if(tdist < sdist && tdist < rpd->seldist) {
+ sdist= tdist;
+ n.line= l;
+ n.first= 1;
+ } else {
+ tdist= sqrt(pow(mouse[0] - p2->loc.x,2)+pow(mouse[1] - p2->loc.y,2));
+ if(tdist < sdist && tdist < rpd->seldist) {
+ sdist= tdist;
+ n.line= l;
+ n.first= 0;
+ }
+ }
+ }
+
+ if(sdist < rpd->seldist)
+ rpd->nearest= n;
+ else rpd->nearest.line= NULL;
+ }
+ break;
+ case RETOPO_LINE:
+ break;
+ case RETOPO_ELLIPSE:
+ break;
+ }
+ allqueue(REDRAWVIEW3D,0);
+ break;
+ case RETKEY:
+ case PADENTER:
+ retopo_paint_apply();
+ case ESCKEY:
+ G.scene->toolsettings->retopo_mode&= ~RETOPO_PAINT;
+ retopo_free_paint();
+
+ BIF_undo_push("Retopo toggle");
+
+ allqueue(REDRAWVIEW3D, 1);
+ allqueue(REDRAWBUTSEDIT, 0);
+ break;
+ case CKEY:
+ retopo_paint_toggle_cyclic(rpd->lines.last);
+ BIF_undo_push("Retopo toggle cyclic");
+ allqueue(REDRAWVIEW3D, 0);
+ break;
+ case EKEY:
+ G.scene->toolsettings->retopo_paint_tool= RETOPO_ELLIPSE;
+ allqueue(REDRAWVIEW3D, 1);
+ break;
+ case HKEY:
+ G.scene->toolsettings->retopo_hotspot= !G.scene->toolsettings->retopo_hotspot;
+ allqueue(REDRAWVIEW3D, 1);
+ break;
+ case LKEY:
+ G.scene->toolsettings->retopo_paint_tool= RETOPO_LINE;
+ allqueue(REDRAWVIEW3D, 1);
+ break;
+ case PKEY:
+ G.scene->toolsettings->retopo_paint_tool= RETOPO_PEN;
+ allqueue(REDRAWVIEW3D, 1);
+ break;
+ case XKEY:
+ case DELKEY:
+ l= rpd->lines.last;
+ if(l) {
+ BLI_freelistN(&l->points);
+ BLI_freelistN(&l->hitlist);
+ BLI_freelinkN(&rpd->lines, l);
+ if(rpd->nearest.line == l)
+ rpd->nearest.line= NULL;
+ BIF_undo_push("Erase line");
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ break;
+ case LEFTMOUSE:
+ if(!rpd->in_drag) { /* Start new drag */
+ rpd->in_drag= 1;
+
+ if(!rpd->paint_v3d)
+ rpd->paint_v3d= G.vd;
+
+ /* Location of mouse down */
+ rpd->sloc[0]= mouse[0];
+ rpd->sloc[1]= mouse[1];
+
+ switch(G.scene->toolsettings->retopo_paint_tool) {
+ case RETOPO_PEN:
+ if(rpd->nearest.line) {
+ RetopoPaintPoint *p, *pt;
+ int i;
+
+ BLI_remlink(&rpd->lines,rpd->nearest.line);
+ BLI_addtail(&rpd->lines,rpd->nearest.line);
+
+ /* Check if we need to reverse the line */
+ if(rpd->nearest.first) {
+ for(p= rpd->nearest.line->points.first; p; p= p->prev) {
+ pt= p->prev;
+ p->prev= p->next;
+ p->next= pt;
+ }
+ pt= rpd->nearest.line->points.first;
+ rpd->nearest.line->points.first= rpd->nearest.line->points.last;
+ rpd->nearest.line->points.last= pt;
+
+ /* Reverse indices */
+ i= 0;
+ for(p= rpd->nearest.line->points.first; p; p= p->next)
+ p->index= i++;
+ }
+ } else {
+ add_rpline(rpd);
+ add_rppoint(rpd->lines.last,mouse[0],mouse[1]);
+ }
+ break;
+ case RETOPO_LINE:
+ break;
+ case RETOPO_ELLIPSE:
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ break;
+ case MIDDLEMOUSE:
+ case WHEELUPMOUSE:
+ case WHEELDOWNMOUSE:
+ case PAD0: case PAD1: case PAD2: case PAD3: case PAD4:
+ case PAD5: case PAD6: case PAD7: case PAD8: case PAD9:
+ case PADMINUS: case PADPLUSKEY:
+ return 1;
+ }
+ return 0;
+ } else return 1;
+}
+void retopo_draw_paint_lines()
+{
+ RetopoPaintData *rpd= get_retopo_paint_data();
+
+ if(rpd && rpd->paint_v3d==G.vd) {
+ RetopoPaintLine *l;
+ RetopoPaintPoint *p;
+
+ glColor3f(0,0,0);
+ glLineWidth(2);
+
+ /* Draw existing lines */
+ for(l= rpd->lines.first; l; l= l->next) {
+ if(l==rpd->lines.last)
+ glColor3f(0.3,0,0);
+ glBegin(l->cyclic?GL_LINE_LOOP:GL_LINE_STRIP);
+ for(p= l->points.first; p; p= p->next) {
+ glVertex2s(p->loc.x,p->loc.y);
+ }
+ glEnd();
+ }
+
+ /* Draw ellipse */
+ if(G.scene->toolsettings->retopo_paint_tool==RETOPO_ELLIPSE && rpd->in_drag) {
+ short mouse[2];
+ getmouseco_areawin(mouse);
+
+ setlinestyle(3);
+ fdrawXORellipse(rpd->sloc[0],rpd->sloc[1],abs(mouse[0]-rpd->sloc[0]),abs(mouse[1]-rpd->sloc[1]));
+ setlinestyle(0);
+ }
+ else if(G.scene->toolsettings->retopo_paint_tool==RETOPO_LINE && rpd->in_drag) {
+ short mouse[2];
+ getmouseco_areawin(mouse);
+
+ setlinestyle(3);
+ sdrawXORline(rpd->sloc[0],rpd->sloc[1],mouse[0],mouse[1]);
+ setlinestyle(0);
+ }
+ else if(rpd->nearest.line) { /* Draw selection */
+ RetopoPaintPoint *p= rpd->nearest.first ? rpd->nearest.line->points.first :
+ rpd->nearest.line->points.last;
+ if(p)
+ fdrawXORcirc(p->loc.x, p->loc.y, rpd->seldist);
+ }
+
+ glLineWidth(1);
+ }
+}
+
+RetopoPaintData *retopo_paint_data_copy(RetopoPaintData *rpd)
+{
+ RetopoPaintData *copy;
+ RetopoPaintLine *l, *lcp;
+ RetopoPaintPoint *p, *pcp;
+
+ if(!rpd) return NULL;
+
+ copy= MEM_mallocN(sizeof(RetopoPaintData),"RetopoPaintDataCopy");
+
+ memcpy(copy,rpd,sizeof(RetopoPaintData));
+ copy->lines.first= copy->lines.last= NULL;
+ for(l= rpd->lines.first; l; l= l->next) {
+ lcp= MEM_mallocN(sizeof(RetopoPaintLine),"RetopoPaintLineCopy");
+ memcpy(lcp,l,sizeof(RetopoPaintLine));
+ BLI_addtail(&copy->lines,lcp);
+
+ lcp->hitlist.first= lcp->hitlist.last= NULL;
+ lcp->points.first= lcp->points.last= NULL;
+ for(p= l->points.first; p; p= p->next) {
+ pcp= MEM_mallocN(sizeof(RetopoPaintPoint),"RetopoPaintPointCopy");
+ memcpy(pcp,p,sizeof(RetopoPaintPoint));
+ BLI_addtail(&lcp->points,pcp);
+ }
+ }
+
+ copy->intersections.first= copy->intersections.last= NULL;
+
+ return copy;
+}
+
+char retopo_mesh_check()
+{
+ return G.obedit && G.obedit->type==OB_MESH && (G.scene->toolsettings->retopo_mode & RETOPO);
+}
+char retopo_curve_check()
+{
+ return G.obedit && (G.obedit->type==OB_CURVE ||
+ G.obedit->type==OB_SURF) && (((Curve*)G.obedit->data)->flag & CU_RETOPO);
+}
+
+void retopo_toggle(void *j1,void *j2)
+{
+ if(retopo_mesh_check() || retopo_curve_check()) {
+ if(G.vd->depths) G.vd->depths->damaged= 1;
+ retopo_queue_updates(G.vd);
+ } else {
+ if(G.editMesh && G.scene->toolsettings->retopo_mode & RETOPO_PAINT)
+ retopo_end_okee();
+ }
+
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+void retopo_do_2d(View3D *v3d, double proj[2], float *v, char adj)
+{
+ /* Check to make sure vert is visible in window */
+ if(proj[0]>0 && proj[1]>0 && proj[0] < v3d->depths->w && proj[1] < v3d->depths->h) {
+ float depth= v3d->depths->depths[((int)proj[1])*v3d->depths->w+((int)proj[0])];
+ double px, py, pz;
+
+ /* Don't modify the point if it'll be mapped to the background */
+ if(depth==v3d->depths->depth_range[1]) {
+ if(adj) {
+ /* Find the depth of (0,0,0); */
+ gluProject(0,0,0,v3d->retopo_view_data->mats.modelview,
+ v3d->retopo_view_data->mats.projection,
+ (GLint *)v3d->retopo_view_data->mats.viewport,&px,&py,&pz);
+ depth= pz;
+ }
+ else return;
+ }
+
+ /* Find 3D location with new depth (unproject) */
+ gluUnProject(proj[0],proj[1],depth,v3d->retopo_view_data->mats.modelview,
+ v3d->retopo_view_data->mats.projection,
+ (GLint *)v3d->retopo_view_data->mats.viewport,&px,&py,&pz);
+
+ v[0]= px;
+ v[1]= py;
+ v[2]= pz;
+ }
+}
+
+void retopo_do_vert(View3D *v3d, float *v)
+{
+ double proj[3];
+
+ /* Find 2D location (project) */
+ gluProject(v[0],v[1],v[2],v3d->retopo_view_data->mats.modelview,v3d->retopo_view_data->mats.projection,
+ (GLint *)v3d->retopo_view_data->mats.viewport,&proj[0],&proj[1],&proj[2]);
+
+ retopo_do_2d(v3d,proj,v,0);
+}
+
+void retopo_do_all()
+{
+ RetopoViewData *rvd= G.vd->retopo_view_data;
+ if(retopo_mesh_check()) {
+ if(rvd) {
+ EditMesh *em= G.editMesh;
+ EditVert *eve;
+
+ /* Apply retopo to all selected vertices */
+ eve= em->verts.first;
+ while(eve) {
+ if(eve->f & SELECT)
+ retopo_do_vert(G.vd,eve->co);
+ eve= eve->next;
+ }
+
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ }
+ else if(retopo_curve_check()) {
+ if(rvd) {
+ extern ListBase editNurb;
+ Nurb *nu;
+ BPoint *bp;
+ int i, j;
+
+ for(nu= editNurb.first; nu; nu= nu->next)
+ {
+ if(nu->type & CU_2D) {
+ /* Can't wrap a 2D curve onto a 3D surface */
+ }
+ else if(nu->type & CU_BEZIER) {
+ for(i=0; i<nu->pntsu; ++i) {
+ if(nu->bezt[i].f1 & 1)
+ retopo_do_vert(G.vd, nu->bezt[i].vec[0]);
+ if(nu->bezt[i].f2 & 1)
+ retopo_do_vert(G.vd, nu->bezt[i].vec[1]);
+ if(nu->bezt[i].f3 & 1)
+ retopo_do_vert(G.vd, nu->bezt[i].vec[2]);
+ }
+ }
+ else {
+ bp= nu->bp;
+ for(i=0; i<nu->pntsv; ++i) {
+ for(j=0; j<nu->pntsu; ++j, ++bp) {
+ if(bp->f1 & 1)
+ retopo_do_vert(G.vd,bp->vec);
+ }
+ }
+ }
+
+ testhandlesNurb(nu);
+ }
+
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ }
+}
+
+void retopo_do_all_cb(void *j1, void *j2)
+{
+ /* This is called from editbuttons, so user needs to specify view */
+ if(!select_area(SPACE_VIEW3D)) return;
+
+ if(G.vd->drawtype == OB_WIRE) {
+ error("Cannot apply retopo in wireframe mode");
+ return;
+ }
+
+ retopo_do_all();
+ BIF_undo_push("Retopo all");
+}
+
+void retopo_queue_updates(View3D *v3d)
+{
+ if(retopo_mesh_check() || retopo_curve_check()) {
+ if(!v3d->retopo_view_data)
+ v3d->retopo_view_data= MEM_callocN(sizeof(RetopoViewData),"RetopoViewData");
+
+ v3d->retopo_view_data->queue_matrix_update= 1;
+
+ allqueue(REDRAWVIEW3D, 0);
+ }
+}
+
+void retopo_matrix_update(View3D *v3d)
+{
+ RetopoPaintData *rpd= get_retopo_paint_data();
+ if((retopo_mesh_check() || retopo_curve_check()) && (!rpd || rpd->paint_v3d==v3d)) {
+ RetopoViewData *rvd= v3d->retopo_view_data;
+ if(!rvd) {
+ rvd= MEM_callocN(sizeof(RetopoViewData),"RetopoViewData");
+ v3d->retopo_view_data= rvd;
+ rvd->queue_matrix_update= 1;
+ }
+ if(rvd && rvd->queue_matrix_update) {
+ bgl_get_mats(&rvd->mats);
+
+ rvd->queue_matrix_update= 0;
+ }
+ }
+}
+
+void retopo_free_view_data(View3D *v3d)
+{
+ if(v3d->retopo_view_data) {
+ MEM_freeN(v3d->retopo_view_data);
+ v3d->retopo_view_data= NULL;
+ }
+}
+
+void retopo_paint_debug_print(RetopoPaintData *rpd)
+{
+ RetopoPaintLine *l;
+ RetopoPaintPoint *p;
+
+ for(l= rpd->lines.first; l; l= l->next) {
+ printf("Line:\n");
+ for(p= l->points.first; p; p= p->next) {
+ printf(" Point(%d: %d,%d)\n",p->index,p->loc.x,p->loc.y);
+ }
+ }
+
+ fflush(stdout);
+}
diff --git a/source/blender/src/scrarea.c b/source/blender/src/scrarea.c
new file mode 100644
index 00000000000..c9076a105a8
--- /dev/null
+++ b/source/blender/src/scrarea.c
@@ -0,0 +1,69 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "BIF_scrarea.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+void *scrarea_find_space_of_type(ScrArea *sa, int type)
+{
+ SpaceLink *sl;
+
+ for (sl= sa->spacedata.first; sl; sl= sl->next)
+ if (sl->spacetype==type)
+ return (void*) sl;
+
+ return 0;
+}
+
+int scrarea_get_win_x(ScrArea *sa)
+{
+ return sa->winrct.xmin;
+}
+
+int scrarea_get_win_y(ScrArea *sa)
+{
+ return sa->winrct.ymin;
+}
+
+int scrarea_get_win_width(ScrArea *sa)
+{
+ return sa->winx;
+}
+
+int scrarea_get_win_height(ScrArea *sa)
+{
+ return sa->winy;
+}
diff --git a/source/blender/src/screendump.c b/source/blender/src/screendump.c
new file mode 100644
index 00000000000..4c1cda52da3
--- /dev/null
+++ b/source/blender/src/screendump.c
@@ -0,0 +1,161 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * Making screendumps.
+ */
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_global.h"
+#include "BKE_image.h"
+#include "BKE_material.h"
+#include "BKE_sca.h"
+
+#include "BIF_gl.h"
+#include "BIF_toolbox.h"
+#include "BIF_mywindow.h"
+#include "BIF_screen.h"
+#include "BIF_toets.h"
+#include "BIF_interface.h"
+#include "BIF_writeimage.h"
+
+#include "BSE_filesel.h"
+
+#include "mydevice.h"
+
+static unsigned int *dumprect=0;
+static int dumpsx, dumpsy;
+
+void write_screendump(char *name)
+{
+ ImBuf *ibuf;
+
+ if(dumprect) {
+
+ strcpy(G.ima, name);
+ BLI_convertstringcode(name, G.sce, G.scene->r.cfra);
+
+ /* BKE_add_image_extension() checks for if extension was already set */
+ if(G.scene->r.scemode & R_EXTENSION)
+ if(strlen(name)<FILE_MAXDIR+FILE_MAXFILE-5)
+ BKE_add_image_extension(name, G.scene->r.imtype);
+
+ if(saveover(name)) {
+ waitcursor(1);
+
+ ibuf= IMB_allocImBuf(dumpsx, dumpsy, 24, 0, 0);
+ ibuf->rect= dumprect;
+
+ if(G.scene->r.planes == 8) IMB_cspace(ibuf, rgb_to_bw);
+
+ BKE_write_ibuf(ibuf, name, G.scene->r.imtype, G.scene->r.subimtype, G.scene->r.quality);
+
+ IMB_freeImBuf(ibuf);
+
+ waitcursor(0);
+ }
+ MEM_freeN(dumprect);
+ dumprect= NULL;
+ }
+}
+
+/* get dump from frontbuffer */
+void BIF_screendump(int fscreen)
+{
+ extern int uiIsMenu(int *x, int *y, int *sizex, int *sizey);
+ int ismenu;
+ static int wasmenu= 0;
+ int x=0, y=0;
+ char imstr[64];
+
+ /* this sets dumpsx/y to zero if ismenu==0 */
+ ismenu= uiIsMenu(&x, &y, &dumpsx, &dumpsy);
+
+ if(wasmenu && !ismenu) {
+ save_image_filesel_str(imstr);
+ strcat(imstr, " (Menu)");
+ activate_fileselect(FILE_SPECIAL, imstr, G.ima, write_screendump);
+ wasmenu= 0;
+ return;
+ }
+
+ if(dumprect) MEM_freeN(dumprect);
+ dumprect= NULL;
+
+ if((G.qual & LR_SHIFTKEY) || fscreen) { /* full screen */
+ x= 0;
+ y= 0;
+
+ dumpsx= G.curscreen->sizex;
+ dumpsy= G.curscreen->sizey;
+
+ }
+ else {
+ if(ismenu==0) { /* a window */
+ //int win= mywinget();
+
+ //bwin_getsuborigin(win, &x, &y);
+ //bwin_getsize(win, &dumpsx, &dumpsy);
+ x= curarea->totrct.xmin;
+ y= curarea->totrct.ymin;
+ dumpsx= curarea->totrct.xmax-x;
+ dumpsy= curarea->totrct.ymax-y;
+ }
+ }
+
+ if (dumpsx && dumpsy) {
+
+ dumprect= MEM_mallocN(sizeof(int)*dumpsx*dumpsy, "dumprect");
+ glReadBuffer(GL_FRONT);
+ glReadPixels(x, y, dumpsx, dumpsy, GL_RGBA, GL_UNSIGNED_BYTE, dumprect);
+ glFinish();
+ glReadBuffer(GL_BACK);
+
+ if(ismenu==0) {
+ wasmenu= 0;
+ save_image_filesel_str(imstr);
+ activate_fileselect(FILE_SPECIAL, imstr, G.ima, write_screendump);
+ }
+ else wasmenu= 1;
+ }
+
+}
diff --git a/source/blender/src/sculptmode-stroke.c b/source/blender/src/sculptmode-stroke.c
new file mode 100644
index 00000000000..2f8dac2818c
--- /dev/null
+++ b/source/blender/src/sculptmode-stroke.c
@@ -0,0 +1,279 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2007 by Nicholas Bishop
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Storage and manipulation of sculptmode brush strokes.
+ *
+ */
+
+#include "MEM_guardedalloc.h"
+#include "DNA_listBase.h"
+#include "DNA_scene_types.h"
+#include "BLI_blenlib.h"
+#include "BIF_gl.h"
+#include "BDR_sculptmode.h"
+#include <math.h>
+
+/* Temporary storage of input stroke control points */
+typedef struct StrokePoint {
+ struct StrokePoint *next, *prev;
+ short x, y;
+} StrokePoint;
+typedef struct SculptStroke {
+ short (*loc)[2];
+ int max;
+ int index;
+ float length;
+ ListBase final;
+ StrokePoint *final_mem;
+ float offset;
+} SculptStroke;
+
+void sculpt_stroke_new(const int max)
+{
+ SculptSession *ss = sculpt_session();
+
+ ss->stroke = MEM_callocN(sizeof(SculptStroke), "SculptStroke");
+ ss->stroke->loc = MEM_callocN(sizeof(short) * 2 * max, "SculptStroke.loc");
+ ss->stroke->max = max;
+ ss->stroke->index = -1;
+}
+
+void sculpt_stroke_free()
+{
+ SculptSession *ss = sculpt_session();
+ if(ss && ss->stroke) {
+ if(ss->stroke->loc) MEM_freeN(ss->stroke->loc);
+ if(ss->stroke->final_mem) MEM_freeN(ss->stroke->final_mem);
+
+ MEM_freeN(ss->stroke);
+ ss->stroke = NULL;
+ }
+}
+
+void sculpt_stroke_add_point(const short x, const short y)
+{
+ SculptStroke *stroke = sculpt_session()->stroke;
+ const int next = stroke->index + 1;
+
+ if(stroke->index == -1) {
+ stroke->loc[0][0] = x;
+ stroke->loc[0][1] = y;
+ stroke->index = 0;
+ }
+ else if(next < stroke->max) {
+ const int dx = x - stroke->loc[stroke->index][0];
+ const int dy = y - stroke->loc[stroke->index][1];
+ stroke->loc[next][0] = x;
+ stroke->loc[next][1] = y;
+ stroke->length += sqrt(dx*dx + dy*dy);
+ stroke->index = next;
+ }
+}
+
+void sculpt_stroke_smooth(SculptStroke *stroke)
+{
+ /* Apply smoothing (exclude the first and last points)*/
+ StrokePoint *p = stroke->final.first;
+ if(p && p->next && p->next->next) {
+ for(p = p->next->next; p && p->next && p->next->next; p = p->next) {
+ p->x = p->prev->prev->x*0.1 + p->prev->x*0.2 + p->x*0.4 + p->next->x*0.2 + p->next->next->x*0.1;
+ p->y = p->prev->prev->y*0.1 + p->prev->y*0.2 + p->y*0.4 + p->next->y*0.2 + p->next->next->y*0.1;
+ }
+ }
+}
+
+static void sculpt_stroke_create_final()
+{
+ SculptStroke *stroke = sculpt_session()->stroke;
+
+ if(stroke) {
+ StrokePoint *p, *pnext;
+ int i;
+
+ /* Copy loc into final */
+ if(stroke->final_mem)
+ MEM_freeN(stroke->final_mem);
+ stroke->final_mem = MEM_callocN(sizeof(StrokePoint) * (stroke->index + 1) * 2, "SculptStroke.final");
+ stroke->final.first = stroke->final.last = NULL;
+ for(i = 0; i <= stroke->index; ++i) {
+ p = &stroke->final_mem[i];
+ p->x = stroke->loc[i][0];
+ p->y = stroke->loc[i][1];
+ BLI_addtail(&stroke->final, p);
+ }
+
+ /* Remove shortest edges */
+ if(stroke->final.first) {
+ for(p = ((StrokePoint*)stroke->final.first)->next; p && p->next; p = pnext) {
+ const int dx = p->x - p->prev->x;
+ const int dy = p->y - p->prev->y;
+ const float len = sqrt(dx*dx + dy*dy);
+ pnext = p->next;
+ if(len < 10) {
+ BLI_remlink(&stroke->final, p);
+ }
+ }
+ }
+
+ sculpt_stroke_smooth(stroke);
+
+ /* Subdivide edges */
+ for(p = stroke->final.first; p && p->next; p = pnext) {
+ StrokePoint *np = &stroke->final_mem[i++];
+
+ pnext = p->next;
+ np->x = (p->x + p->next->x) / 2;
+ np->y = (p->y + p->next->y) / 2;
+ BLI_insertlink(&stroke->final, p, np);
+ }
+
+ sculpt_stroke_smooth(stroke);
+ }
+}
+
+float sculpt_stroke_seglen(StrokePoint *p1, StrokePoint *p2)
+{
+ int dx = p2->x - p1->x;
+ int dy = p2->y - p1->y;
+ return sqrt(dx*dx + dy*dy);
+}
+
+float sculpt_stroke_final_length(SculptStroke *stroke)
+{
+ StrokePoint *p;
+ float len = 0;
+ for(p = stroke->final.first; p && p->next; ++p)
+ len += sculpt_stroke_seglen(p, p->next);
+ return len;
+}
+
+/* If partial is nonzero, cuts off apply after that length has been processed */
+static StrokePoint *sculpt_stroke_apply_generic(SculptStroke *stroke, struct EditData *e, const int partial)
+{
+ const int sdspace = sculpt_data()->spacing;
+ const short spacing = sdspace > 0 ? sdspace : 2;
+ const int dots = sculpt_stroke_final_length(stroke) / spacing;
+ int i;
+ StrokePoint *p = stroke->final.first;
+ float startloc = stroke->offset;
+
+ for(i = 0; i < dots && p && p->next; ++i) {
+ const float dotloc = spacing * i;
+ short co[2];
+ float len = sculpt_stroke_seglen(p, p->next);
+ float u, v;
+
+ /* Find edge containing dot */
+ while(dotloc > startloc + len && p && p->next && p->next->next) {
+ p = p->next;
+ startloc += len;
+ len = sculpt_stroke_seglen(p, p->next);
+ }
+
+ if(!p || !p->next || dotloc > startloc + len)
+ break;
+
+ if(partial && startloc > partial) {
+ /* Calculate offset for next stroke segment */
+ stroke->offset = startloc + len - dotloc;
+ break;
+ }
+
+ u = (dotloc - startloc) / len;
+ v = 1 - u;
+
+ co[0] = p->x*v + p->next->x*u;
+ co[1] = p->y*v + p->next->y*u;
+
+ do_symmetrical_brush_actions(e, co, NULL);
+ }
+
+ return p ? p->next : NULL;
+}
+
+void sculpt_stroke_apply(struct EditData *e)
+{
+ SculptStroke *stroke = sculpt_session()->stroke;
+ /* TODO: make these values user-modifiable? */
+ const int partial_len = 100;
+ const int min_len = 200;
+
+ if(stroke) {
+ sculpt_stroke_create_final();
+
+ if(sculpt_stroke_final_length(stroke) > min_len) {
+ StrokePoint *p = sculpt_stroke_apply_generic(stroke, e, partial_len);
+
+ /* Replace remaining values in stroke->loc with remaining stroke->final values */
+ stroke->index = -1;
+ stroke->length = 0;
+ for(; p; p = p->next) {
+ ++stroke->index;
+ stroke->loc[stroke->index][0] = p->x;
+ stroke->loc[stroke->index][1] = p->y;
+ if(p->next) {
+ stroke->length += sculpt_stroke_seglen(p, p->next);
+ }
+ }
+ }
+ }
+}
+
+void sculpt_stroke_apply_all(struct EditData *e)
+{
+ SculptStroke *stroke = sculpt_session()->stroke;
+
+ sculpt_stroke_create_final();
+
+ if(stroke) {
+ sculpt_stroke_apply_generic(stroke, e, 0);
+ }
+}
+
+void sculpt_stroke_draw()
+{
+ SculptStroke *stroke = sculpt_session()->stroke;
+
+ if(stroke) {
+ StrokePoint *p;
+
+ /* Draws the original stroke */
+ /*glColor3f(1, 0, 0);
+ glBegin(GL_LINE_STRIP);
+ for(i = 0; i <= stroke->index; ++i)
+ glVertex2s(stroke->loc[i][0], stroke->loc[i][1]);
+ glEnd();*/
+
+ /* Draws the smoothed stroke */
+ glColor3f(0, 1, 0);
+ glBegin(GL_LINE_STRIP);
+ for(p = stroke->final.first; p; p = p->next)
+ glVertex2s(p->x, p->y);
+ glEnd();
+ }
+}
diff --git a/source/blender/src/sculptmode.c b/source/blender/src/sculptmode.c
new file mode 100644
index 00000000000..43b33a5c9a8
--- /dev/null
+++ b/source/blender/src/sculptmode.c
@@ -0,0 +1,2193 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 by Nicholas Bishop
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Implements the Sculpt Mode tools
+ *
+ * BDR_sculptmode.h
+ *
+ */
+
+#include "GHOST_Types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+#include "BLI_dynstr.h"
+
+#include "DNA_armature_types.h"
+#include "DNA_brush_types.h"
+#include "DNA_image_types.h"
+#include "DNA_key_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BKE_customdata.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_image.h"
+#include "BKE_key.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_editkey.h"
+#include "BIF_editview.h"
+#include "BIF_glutil.h"
+#include "BIF_gl.h"
+#include "BIF_interface.h"
+#include "BIF_mywindow.h"
+#include "BIF_resources.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_toolbox.h"
+
+#include "BDR_drawobject.h"
+#include "BDR_sculptmode.h"
+
+#include "BSE_drawview.h"
+#include "BSE_edit.h"
+#include "BSE_view.h"
+
+#include "IMB_imbuf_types.h"
+
+#include "blendef.h"
+#include "multires.h"
+#include "mydevice.h"
+
+#include "RE_render_ext.h"
+#include "RE_shader_ext.h" /*for multitex_ext*/
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Number of vertices to average in order to determine the flatten distance */
+#define FLATTEN_SAMPLE_SIZE 10
+
+/* ===== STRUCTS =====
+ *
+ */
+
+/* Used by vertex_users to store face indices in a list */
+typedef struct IndexNode {
+ struct IndexNode* next,* prev;
+ int Index;
+} IndexNode;
+
+
+/* ActiveData stores an Index into the mvert array of Mesh, plus Fade, which
+ stores how far the vertex is from the brush center, scaled to the range [0,1]. */
+typedef struct ActiveData {
+ struct ActiveData *next, *prev;
+ unsigned int Index;
+ float Fade;
+ float dist;
+} ActiveData;
+
+typedef struct GrabData {
+ char firsttime;
+ ListBase active_verts[8];
+ unsigned char index;
+ vec3f delta, delta_symm;
+ float depth;
+} GrabData;
+
+typedef struct EditData {
+ vec3f center;
+ float size;
+ char flip;
+ short mouse[2];
+
+ /* Adjust brush strength along each axis
+ to adjust for object scaling */
+ float scale[3];
+
+ /* View normals */
+ vec3f up, right, out;
+
+ GrabData *grabdata;
+ float *layer_disps;
+ vec3f *layer_store;
+
+ char clip[3];
+ float cliptol[3];
+
+ char symm;
+} EditData;
+
+typedef struct RectNode {
+ struct RectNode *next, *prev;
+ rcti r;
+} RectNode;
+
+/* Used to store to 2D screen coordinates of each vertex in the mesh. */
+typedef struct ProjVert {
+ short co[2];
+
+ /* Used to mark whether a vertex is inside a rough bounding box
+ containing the brush. */
+ char inside;
+} ProjVert;
+
+static ProjVert *projverts= NULL;
+static Object *active_ob= NULL;
+
+SculptData *sculpt_data(void)
+{
+ return &G.scene->sculptdata;
+}
+
+void sculpt_init_session(void);
+void init_editdata(EditData *e, short *, short *);
+
+SculptSession *sculpt_session(void)
+{
+ if(!sculpt_data()->session)
+ sculpt_init_session();
+ return sculpt_data()->session;
+}
+
+/* ===== MEMORY =====
+ *
+ * Allocate/initialize/free data
+ */
+
+/* Initialize 'permanent' sculpt data that is saved with file kept after
+ switching out of sculptmode. */
+void sculptmode_init(Scene *sce)
+{
+ SculptData *sd;
+
+ if(!sce) {
+ error("Unable to initialize sculptmode: bad scene");
+ return;
+ }
+
+ sd= &sce->sculptdata;
+
+ memset(sd, 0, sizeof(SculptData));
+
+ sd->drawbrush.size = sd->smoothbrush.size = sd->pinchbrush.size =
+ sd->inflatebrush.size = sd->grabbrush.size =
+ sd->layerbrush.size = sd->flattenbrush.size = 50;
+ sd->drawbrush.strength = sd->smoothbrush.strength =
+ sd->pinchbrush.strength = sd->inflatebrush.strength =
+ sd->grabbrush.strength = sd->layerbrush.strength =
+ sd->flattenbrush.strength = 25;
+ sd->drawbrush.dir = sd->pinchbrush.dir = sd->inflatebrush.dir = sd->layerbrush.dir= 1;
+ sd->drawbrush.airbrush = sd->smoothbrush.airbrush =
+ sd->pinchbrush.airbrush = sd->inflatebrush.airbrush =
+ sd->layerbrush.airbrush = sd->flattenbrush.airbrush = 0;
+ sd->drawbrush.view= 0;
+ sd->brush_type= DRAW_BRUSH;
+ sd->texact= -1;
+ sd->texfade= 1;
+ sd->averaging= 1;
+ sd->texsep= 0;
+ sd->texrept= SCULPTREPT_DRAG;
+ sd->flags= SCULPT_DRAW_BRUSH;
+ sd->tablet_size=3;
+ sd->tablet_strength=10;
+}
+
+void sculptmode_free_session(Scene *);
+void sculpt_init_session(void)
+{
+ if(sculpt_data()->session)
+ sculptmode_free_session(G.scene);
+ sculpt_data()->session= MEM_callocN(sizeof(SculptSession), "SculptSession");
+}
+
+void sculptmode_free_vertexusers(SculptSession *ss)
+{
+ if(ss && ss->vertex_users){
+ MEM_freeN(ss->vertex_users);
+ MEM_freeN(ss->vertex_users_mem);
+ ss->vertex_users= NULL;
+ ss->vertex_users_mem= NULL;
+ ss->vertex_users_size= 0;
+ }
+}
+
+void sculptmode_propset_end(SculptSession *ss, int);
+void sculptmode_free_session(Scene *sce)
+{
+ SculptSession *ss= sce->sculptdata.session;
+ if(ss) {
+ sculptmode_free_vertexusers(ss);
+ if(ss->texcache)
+ MEM_freeN(ss->texcache);
+ sculptmode_propset_end(ss, 1);
+ MEM_freeN(ss);
+ sce->sculptdata.session= NULL;
+ }
+}
+
+void sculptmode_free_all(Scene *sce)
+{
+ SculptData *sd= &sce->sculptdata;
+ int a;
+
+ sculptmode_free_session(sce);
+
+ for(a=0; a<MAX_MTEX; a++) {
+ MTex *mtex= sd->mtex[a];
+ if(mtex) {
+ if(mtex->tex) mtex->tex->id.us--;
+ MEM_freeN(mtex);
+ }
+ }
+}
+
+/* vertex_users is an array of Lists that store all the faces that use a
+ particular vertex. vertex_users is in the same order as mesh.mvert */
+void calc_vertex_users()
+{
+ SculptSession *ss= sculpt_session();
+ int i,j;
+ IndexNode *node= NULL;
+ Mesh *me= get_mesh(OBACT);
+
+ sculptmode_free_vertexusers(ss);
+
+ /* For efficiency, use vertex_users_mem as a memory pool (may be larger
+ than necessary if mesh has triangles, but only one alloc is needed.) */
+ ss->vertex_users= MEM_callocN(sizeof(ListBase) * me->totvert, "vertex_users");
+ ss->vertex_users_size= me->totvert;
+ ss->vertex_users_mem= MEM_callocN(sizeof(IndexNode)*me->totface*4, "vertex_users_mem");
+ node= ss->vertex_users_mem;
+
+ /* Find the users */
+ for(i=0; i<me->totface; ++i){
+ for(j=0; j<(me->mface[i].v4?4:3); ++j, ++node) {
+ node->Index=i;
+ BLI_addtail(&ss->vertex_users[((unsigned int*)(&me->mface[i]))[j]], node);
+ }
+ }
+}
+
+/* ===== INTERFACE =====
+ */
+
+void sculptmode_rem_tex(void *junk0,void *junk1)
+{
+ MTex *mtex= G.scene->sculptdata.mtex[G.scene->sculptdata.texact];
+ if(mtex) {
+ SculptSession *ss= sculpt_session();
+ if(mtex->tex) mtex->tex->id.us--;
+ MEM_freeN(mtex);
+ G.scene->sculptdata.mtex[G.scene->sculptdata.texact]= NULL;
+ /* Clear brush preview */
+ if(ss->texcache) {
+ MEM_freeN(ss->texcache);
+ ss->texcache= NULL;
+ }
+ BIF_undo_push("Unlink brush texture");
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWOOPS, 0);
+ }
+}
+
+/* ===== OPENGL =====
+ *
+ * Simple functions to get data from the GL
+ */
+
+/* Store the modelview and projection matrices and viewport. */
+void init_sculptmatrices()
+{
+ SculptSession *ss= sculpt_session();
+
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glMultMatrixf(OBACT->obmat);
+
+ bgl_get_mats(&ss->mats);
+
+ glPopMatrix();
+
+}
+
+/* Uses window coordinates (x,y) to find the depth in the GL depth buffer. If
+ available, G.vd->depths is used so that the brush doesn't sculpt on top of
+ itself (G.vd->depths is only updated at the end of a brush stroke.) */
+float get_depth(short x, short y)
+{
+ float depth;
+
+ if(x<0 || y<0) return 1;
+ if(x>=curarea->winx || y>=curarea->winy) return 1;
+
+ if(G.vd->depths && x<G.vd->depths->w && y<G.vd->depths->h)
+ return G.vd->depths->depths[y*G.vd->depths->w+x];
+
+ x+= curarea->winrct.xmin;
+ y+= curarea->winrct.ymin;
+
+ glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
+
+ return depth;
+}
+
+/* Uses window coordinates (x,y) and depth component z to find a point in
+ modelspace */
+vec3f unproject(const short x, const short y, const float z)
+{
+ SculptSession *ss= sculpt_session();
+ double ux, uy, uz;
+ vec3f p;
+
+ gluUnProject(x,y,z, ss->mats.modelview, ss->mats.projection,
+ (GLint *)ss->mats.viewport, &ux, &uy, &uz );
+ p.x= ux;
+ p.y= uy;
+ p.z= uz;
+ return p;
+}
+
+/* Convert a point in model coordinates to 2D screen coordinates. */
+void project(const float v[3], short p[2])
+{
+ SculptSession *ss= sculpt_session();
+ double ux, uy, uz;
+
+ gluProject(v[0],v[1],v[2], ss->mats.modelview, ss->mats.projection,
+ (GLint *)ss->mats.viewport, &ux, &uy, &uz);
+ p[0]= ux;
+ p[1]= uy;
+}
+
+/* ===== Sculpting =====
+ *
+ */
+
+/* Return modified brush size. Uses current tablet pressure (if available) to
+ shrink the brush. Skipped for grab brush because only the first mouse down
+ size is used, which is small if the user has just touched the pen to the
+ tablet */
+char brush_size()
+{
+ const BrushData *b= sculptmode_brush();
+ float size= b->size;
+ float pressure= get_pressure();
+ short activedevice= get_activedevice();
+
+ if(sculpt_data()->brush_type!=GRAB_BRUSH) {
+ const float size_factor= G.scene->sculptdata.tablet_size / 10.0f;
+ if(ELEM(activedevice, DEV_STYLUS, DEV_ERASER))
+ size*= G.scene->sculptdata.tablet_size==0?1:
+ (1-size_factor) + pressure*size_factor;
+ }
+
+ return size;
+}
+
+/* Return modified brush strength. Includes the direction of the brush, positive
+ values pull vertices, negative values push. Uses tablet pressure and a
+ special multiplier found experimentally to scale the strength factor. */
+float brush_strength(EditData *e)
+{
+ const BrushData* b= sculptmode_brush();
+ float dir= b->dir==1 ? 1 : -1;
+ float pressure= 1;
+ short activedevice= get_activedevice();
+ float flip= e->flip ? -1:1;
+
+ const float strength_factor= G.scene->sculptdata.tablet_strength / 10.0f;
+ if(ELEM(activedevice, DEV_STYLUS, DEV_ERASER))
+ pressure= G.scene->sculptdata.tablet_strength==0?1:
+ (1-strength_factor) + get_pressure()*strength_factor;
+
+ /* Flip direction for eraser */
+ if(activedevice==DEV_ERASER)
+ dir= -dir;
+
+ switch(G.scene->sculptdata.brush_type){
+ case DRAW_BRUSH:
+ case LAYER_BRUSH:
+ return b->strength / 5000.0f * dir * pressure * flip;
+ case SMOOTH_BRUSH:
+ return b->strength / 50.0f * pressure;
+ case PINCH_BRUSH:
+ return b->strength / 1000.0f * dir * pressure * flip;
+ case GRAB_BRUSH:
+ return 1;
+ case INFLATE_BRUSH:
+ return b->strength / 5000.0f * dir * pressure * flip;
+ case FLATTEN_BRUSH:
+ return b->strength / 500.0f * pressure;
+ default:
+ return 0;
+ }
+}
+
+/* For clipping against a mirror modifier */
+void sculpt_clip(const EditData *e, float *co, const float val[3])
+{
+ char i;
+ for(i=0; i<3; ++i) {
+ if(e->clip[i] && (fabs(co[i]) <= e->cliptol[i]))
+ co[i]= 0.0f;
+ else
+ co[i]= val[i];
+ }
+}
+
+/* Currently only for the draw brush; finds average normal for all active
+ vertices */
+vec3f calc_area_normal(const vec3f *outdir, const ListBase* active_verts)
+{
+ Mesh *me= get_mesh(OBACT);
+ vec3f area_normal= {0,0,0};
+ ActiveData *node= active_verts->first;
+ const int view= sculpt_data()->brush_type==DRAW_BRUSH ? sculptmode_brush()->view : 0;
+
+ while(node){
+ area_normal.x+= me->mvert[node->Index].no[0];
+ area_normal.y+= me->mvert[node->Index].no[1];
+ area_normal.z+= me->mvert[node->Index].no[2];
+ node= node->next;
+ }
+ Normalize(&area_normal.x);
+ if(outdir) {
+ area_normal.x= outdir->x * view + area_normal.x * (10-view);
+ area_normal.y= outdir->y * view + area_normal.y * (10-view);
+ area_normal.z= outdir->z * view + area_normal.z * (10-view);
+ }
+ Normalize(&area_normal.x);
+ return area_normal;
+}
+void do_draw_brush(const EditData *e, const ListBase* active_verts)
+{
+ Mesh *me= get_mesh(OBACT);
+ const vec3f area_normal= calc_area_normal(&e->out, active_verts);
+ ActiveData *node= active_verts->first;
+
+ while(node){
+ float *co= me->mvert[node->Index].co;
+
+ const float val[3]= {co[0]+area_normal.x*node->Fade*e->scale[0],
+ co[1]+area_normal.y*node->Fade*e->scale[1],
+ co[2]+area_normal.z*node->Fade*e->scale[2]};
+
+ sculpt_clip(e, co, val);
+
+ node= node->next;
+ }
+}
+
+/* For the smooth brush, uses the neighboring vertices around vert to calculate
+ a smoothed location for vert. Skips corner vertices (used by only one
+ polygon.) */
+vec3f neighbor_average(const int vert)
+{
+ SculptSession *ss= sculpt_session();
+ Mesh *me= get_mesh(OBACT);
+ int i, skip= -1, total=0;
+ IndexNode *node= ss->vertex_users[vert].first;
+ vec3f avg= {0,0,0};
+ char ncount= BLI_countlist(&ss->vertex_users[vert]);
+ MFace *f;
+
+ /* Don't modify corner vertices */
+ if(ncount==1) {
+ VecCopyf(&avg.x, me->mvert[vert].co);
+ return avg;
+ }
+
+ while(node){
+ f= &me->mface[node->Index];
+
+ if(f->v4) {
+ skip= (f->v1==vert?2:
+ f->v2==vert?3:
+ f->v3==vert?0:
+ f->v4==vert?1:-1);
+ }
+
+ for(i=0; i<(f->v4?4:3); ++i) {
+ if(i != skip && (ncount!=2 || BLI_countlist(&ss->vertex_users[(&f->v1)[i]]) <= 2)) {
+ VecAddf(&avg.x,&avg.x,me->mvert[(&f->v1)[i]].co);
+ ++total;
+ }
+ }
+
+ node= node->next;
+ }
+
+ if(total>0) {
+ avg.x/= total;
+ avg.y/= total;
+ avg.z/= total;
+ }
+ else
+ VecCopyf(&avg.x, me->mvert[vert].co);
+
+ return avg;
+}
+
+void do_smooth_brush(const EditData *e, const ListBase* active_verts)
+{
+ ActiveData *node= active_verts->first;
+ Mesh *me= get_mesh(OBACT);
+
+ while(node){
+ float *co= me->mvert[node->Index].co;
+ const vec3f avg= neighbor_average(node->Index);
+ const float val[3]= {co[0]+(avg.x-co[0])*node->Fade,
+ co[1]+(avg.y-co[1])*node->Fade,
+ co[2]+(avg.z-co[2])*node->Fade};
+ sculpt_clip(e, co, val);
+ node= node->next;
+ }
+}
+
+void do_pinch_brush(const EditData *e, const ListBase* active_verts)
+{
+ Mesh *me= get_mesh(OBACT);
+ ActiveData *node= active_verts->first;
+
+ while(node) {
+ float *co= me->mvert[node->Index].co;
+ const float val[3]= {co[0]+(e->center.x-co[0])*node->Fade,
+ co[1]+(e->center.y-co[1])*node->Fade,
+ co[2]+(e->center.z-co[2])*node->Fade};
+ sculpt_clip(e, co, val);
+ node= node->next;
+ }
+}
+
+void do_grab_brush(EditData *e)
+{
+ Mesh *me= get_mesh(OBACT);
+ ActiveData *node= e->grabdata->active_verts[e->grabdata->index].first;
+ float add[3];
+
+ while(node) {
+ float *co= me->mvert[node->Index].co;
+
+ VecCopyf(add, &e->grabdata->delta_symm.x);
+ VecMulf(add, node->Fade);
+ VecAddf(add, add, co);
+ sculpt_clip(e, co, add);
+
+ node= node->next;
+ }
+}
+
+void do_layer_brush(EditData *e, const ListBase *active_verts)
+{
+ Mesh *me= get_mesh(OBACT);
+ vec3f area_normal= calc_area_normal(NULL, active_verts);
+ ActiveData *node= active_verts->first;
+ const float bstr= brush_strength(e);
+
+ while(node){
+ float *disp= &e->layer_disps[node->Index];
+
+ if((bstr > 0 && *disp < bstr) ||
+ (bstr < 0 && *disp > bstr)) {
+ float *co= me->mvert[node->Index].co;
+
+ *disp+= node->Fade;
+
+ if(bstr < 0) {
+ if(*disp < bstr)
+ *disp = bstr;
+ } else {
+ if(*disp > bstr)
+ *disp = bstr;
+ }
+
+ {
+ const float val[3]= {e->layer_store[node->Index].x+area_normal.x * *disp*e->scale[0],
+ e->layer_store[node->Index].y+area_normal.y * *disp*e->scale[1],
+ e->layer_store[node->Index].z+area_normal.z * *disp*e->scale[2]};
+ sculpt_clip(e, co, val);
+ }
+ }
+
+ node= node->next;
+ }
+}
+
+void do_inflate_brush(const EditData *e, const ListBase *active_verts)
+{
+ ActiveData *node= active_verts->first;
+ float add[3];
+ Mesh *me= get_mesh(OBACT);
+
+ while(node) {
+ float *co= me->mvert[node->Index].co;
+ short *no= me->mvert[node->Index].no;
+
+ add[0]= no[0]/ 32767.0f;
+ add[1]= no[1]/ 32767.0f;
+ add[2]= no[2]/ 32767.0f;
+ VecMulf(add, node->Fade);
+ add[0]*= e->scale[0];
+ add[1]*= e->scale[1];
+ add[2]*= e->scale[2];
+ VecAddf(add, add, co);
+
+ sculpt_clip(e, co, add);
+
+ node= node->next;
+ }
+}
+
+void calc_flatten_center(Mesh *me, ActiveData *node, const EditData *e, float co[3])
+{
+ ActiveData *outer[FLATTEN_SAMPLE_SIZE];
+ int i;
+
+ for(i = 0; i < FLATTEN_SAMPLE_SIZE; ++i)
+ outer[i] = node;
+
+ for(; node; node = node->next) {
+ for(i = 0; i < FLATTEN_SAMPLE_SIZE; ++i) {
+ if(node->dist > outer[i]->dist) {
+ outer[i] = node;
+ break;
+ }
+ }
+ }
+
+ co[0] = co[1] = co[2] = 0.0f;
+ for(i = 0; i < FLATTEN_SAMPLE_SIZE; ++i)
+ VecAddf(co, co, me->mvert[outer[i]->Index].co);
+ VecMulf(co, 1.0f / FLATTEN_SAMPLE_SIZE);
+}
+
+void do_flatten_brush(const EditData *e, const ListBase *active_verts)
+{
+ Mesh *me= get_mesh(OBACT);
+ ActiveData *node= active_verts->first;
+ /* area_normal and cntr define the plane towards which vertices are squashed */
+ vec3f area_normal= calc_area_normal(&e->out, active_verts);
+ float cntr[3];
+
+ calc_flatten_center(me, node, e, cntr);
+
+ while(node){
+ float *co= me->mvert[node->Index].co;
+ float p1[3], sub1[3], sub2[3], intr[3], val[3];
+
+ /* Find the intersection between squash-plane and vertex (along the area normal) */
+ VecSubf(p1, co, &area_normal.x);
+ VecSubf(sub1, cntr, p1);
+ VecSubf(sub2, co, p1);
+ VecSubf(intr, co, p1);
+ VecMulf(intr, Inpf(&area_normal.x, sub1) / Inpf(&area_normal.x, sub2));
+ VecAddf(intr, intr, p1);
+
+ VecSubf(val, intr, co);
+ VecMulf(val, node->Fade);
+ VecAddf(val, val, co);
+
+ sculpt_clip(e, co, val);
+
+ node= node->next;
+ }
+}
+
+/* Creates a smooth curve for the brush shape. This is the cos(x) curve from
+ [0,PI] scaled to [0,len]. The range is scaled to [0,1]. */
+float simple_strength(float p, const float len)
+{
+ if(p > len) p= len;
+ return 0.5f * (cos(M_PI*p/len) + 1);
+}
+
+/* Uses symm to selectively flip any axis of a coordinate. */
+void flip_coord(float co[3], const char symm)
+{
+ if(symm & SYMM_X)
+ co[0]= -co[0];
+ if(symm & SYMM_Y)
+ co[1]= -co[1];
+ if(symm & SYMM_Z)
+ co[2]= -co[2];
+}
+
+/* Use the warpfac field in MTex to store a rotation value for sculpt textures. Value is in degrees */
+float tex_angle(void)
+{
+ SculptData *sd= sculpt_data();
+ if(sd->texact!=-1 && sd->mtex[sd->texact])
+ return sd->mtex[sd->texact]->warpfac;
+ return 0;
+}
+
+void set_tex_angle(const float f)
+{
+ SculptData *sd = sculpt_data();
+ if(sd->texact != -1 && sd->mtex[sd->texact])
+ sd->mtex[sd->texact]->warpfac = f;
+}
+
+float to_rad(const float deg)
+{
+ return deg * (M_PI/180.0f);
+}
+
+float to_deg(const float rad)
+{
+ return rad * (180.0f/M_PI);
+}
+
+/* Get a pixel from the texcache at (px, py) */
+unsigned *get_texcache_pixel(const SculptSession *ss, int px, int py)
+{
+ if(px < 0) px= 0;
+ if(py < 0) py= 0;
+ if(px > ss->texcache_w - 1) px= ss->texcache_w - 1;
+ if(py > ss->texcache_h - 1) py= ss->texcache_h - 1;
+ return ss->texcache + py * ss->texcache_w + px;
+}
+
+/* Return a multiplier for brush strength on a particular vertex. */
+float tex_strength(EditData *e, float *point, const float len,const unsigned vindex)
+{
+ SculptData *sd= sculpt_data();
+ SculptSession *ss= sculpt_session();
+ float avg= 1;
+
+ if(sd->texact==-1 || !sd->mtex[sd->texact])
+ avg= 1;
+ else if(sd->texrept==SCULPTREPT_3D) {
+ /* Get strength by feeding the vertex location directly
+ into a texture */
+ float jnk;
+ const float factor= 0.01;
+ MTex mtex;
+ memset(&mtex,0,sizeof(MTex));
+ mtex.tex= sd->mtex[sd->texact]->tex;
+ mtex.projx= 1;
+ mtex.projy= 2;
+ mtex.projz= 3;
+ VecCopyf(mtex.size, sd->mtex[sd->texact]->size);
+ VecMulf(mtex.size, factor);
+ if(!sd->texsep)
+ mtex.size[1]= mtex.size[2]= mtex.size[0];
+
+ externtex(&mtex,point,&avg,&jnk,&jnk,&jnk,&jnk);
+ }
+ else if(ss->texcache) {
+ const short bsize= sculptmode_brush()->size * 2;
+ const short half= sculptmode_brush()->size;
+ const float rot= to_rad(tex_angle());
+ const unsigned tcw = ss->texcache_w, tch = ss->texcache_h;
+ int px, py;
+ unsigned i, *p;
+ ProjVert pv;
+
+ /* If the active area is being applied for symmetry, flip it
+ across the symmetry axis in order to project it. This insures
+ that the brush texture will be oriented correctly. */
+ if(!e->symm)
+ pv= projverts[vindex];
+ else {
+ float co[3];
+ VecCopyf(co, point);
+ flip_coord(co, e->symm);
+ project(co, pv.co);
+ }
+
+ /* For Tile and Drag modes, get the 2D screen coordinates of the
+ and scale them up or down to the texture size. */
+ if(sd->texrept==SCULPTREPT_TILE) {
+ const int sx= (const int)sd->mtex[sd->texact]->size[0];
+ const int sy= (const int)sd->texsep ? sd->mtex[sd->texact]->size[1] : sx;
+
+ float fx= pv.co[0];
+ float fy= pv.co[1];
+
+ float angle= atan2(fy, fx) - rot;
+ float len= sqrtf(fx*fx + fy*fy);
+
+ if(rot<0.001 && rot>-0.001) {
+ px= pv.co[0];
+ py= pv.co[1];
+ } else {
+ px= len * cos(angle) + 2000;
+ py= len * sin(angle) + 2000;
+ }
+ px %= sx-1;
+ py %= sy-1;
+ p= get_texcache_pixel(ss, tcw*px/sx, tch*py/sy);
+ } else {
+ float fx= (pv.co[0] - e->mouse[0] + half) * (tcw*1.0f/bsize) - tcw/2;
+ float fy= (pv.co[1] - e->mouse[1] + half) * (tch*1.0f/bsize) - tch/2;
+
+ float angle= atan2(fy, fx) - rot;
+ float len= sqrtf(fx*fx + fy*fy);
+
+ px= tcw/2 + len * cos(angle);
+ py= tch/2 + len * sin(angle);
+
+ p= get_texcache_pixel(ss, px, py);
+ }
+
+ avg= 0;
+ for(i=0; i<3; ++i)
+ avg+= ((unsigned char*)(p))[i] / 255.0f;
+
+ avg/= 3;
+ }
+
+ if(sd->texfade)
+ avg*= simple_strength(len,e->size); /* Smooth curve */
+
+ return avg;
+}
+
+/* Mark area around the brush as damaged. projverts are marked if they are
+ inside the area and the damaged rectangle in 2D screen coordinates is
+ added to damaged_rects. */
+void sculptmode_add_damaged_rect(EditData *e)
+{
+ short p[2];
+ const float radius= brush_size();
+ RectNode *rn= MEM_mallocN(sizeof(RectNode),"RectNode");
+ Mesh *me= get_mesh(OBACT);
+ unsigned i;
+
+ /* Find center */
+ project(&e->center.x, p);
+ rn->r.xmin= p[0]-radius;
+ rn->r.ymin= p[1]-radius;
+ rn->r.xmax= p[0]+radius;
+ rn->r.ymax= p[1]+radius;
+
+ BLI_addtail(&sculpt_session()->damaged_rects, rn);
+
+ /* Update insides */
+ for(i=0; i<me->totvert; ++i) {
+ if(!projverts[i].inside) {
+ if(projverts[i].co[0] > rn->r.xmin && projverts[i].co[1] > rn->r.ymin &&
+ projverts[i].co[0] < rn->r.xmax && projverts[i].co[1] < rn->r.ymax) {
+ projverts[i].inside= 1;
+ }
+ }
+ }
+}
+
+void do_brush_action(EditData e)
+{
+ int i;
+ float av_dist;
+ ListBase active_verts={0,0};
+ ActiveData *adata= 0;
+ float *vert;
+ Mesh *me= get_mesh(OBACT);
+ const float bstrength= brush_strength(&e);
+ KeyBlock *keyblock= ob_get_keyblock(OBACT);
+ SculptSession *ss = sculpt_session();
+
+ sculptmode_add_damaged_rect(&e);
+
+ /* Build a list of all vertices that are potentially within the brush's
+ area of influence. Only do this once for the grab brush. */
+ if(!e.grabdata || (e.grabdata && e.grabdata->firsttime)) {
+ for(i=0; i<me->totvert; ++i) {
+ /* Projverts.inside provides a rough bounding box */
+ if(projverts[i].inside) {
+ vert= ss->vertexcosnos ? &ss->vertexcosnos[i*6] : me->mvert[i].co;
+ av_dist= VecLenf(&e.center.x,vert);
+ if(av_dist < e.size) {
+ adata= (ActiveData*)MEM_mallocN(sizeof(ActiveData), "ActiveData");
+ adata->Index = i;
+ /* Fade is used to store the final strength at which the brush
+ should modify a particular vertex. */
+ adata->Fade= tex_strength(&e,vert,av_dist,i) * bstrength;
+ adata->dist = av_dist;
+ if(e.grabdata && e.grabdata->firsttime)
+ BLI_addtail(&e.grabdata->active_verts[e.grabdata->index], adata);
+ else
+ BLI_addtail(&active_verts, adata);
+ }
+ }
+ }
+ }
+
+ /* Only act if some verts are inside the brush area */
+ if(active_verts.first || (e.grabdata && e.grabdata->active_verts[e.grabdata->index].first)) {
+ /* Apply one type of brush action */
+ switch(G.scene->sculptdata.brush_type){
+ case DRAW_BRUSH:
+ do_draw_brush(&e, &active_verts);
+ break;
+ case SMOOTH_BRUSH:
+ do_smooth_brush(&e, &active_verts);
+ break;
+ case PINCH_BRUSH:
+ do_pinch_brush(&e, &active_verts);
+ break;
+ case INFLATE_BRUSH:
+ do_inflate_brush(&e, &active_verts);
+ break;
+ case GRAB_BRUSH:
+ do_grab_brush(&e);
+ break;
+ case LAYER_BRUSH:
+ do_layer_brush(&e, &active_verts);
+ break;
+ case FLATTEN_BRUSH:
+ do_flatten_brush(&e, &active_verts);
+ break;
+ }
+
+ /* Copy the modified vertices from mesh to the active key */
+ if(keyblock) {
+ float *co= keyblock->data;
+ if(co) {
+ adata = e.grabdata ? e.grabdata->active_verts[e.grabdata->index].first : active_verts.first;
+ for(; adata; adata= adata->next)
+ if(adata->Index < keyblock->totelem)
+ VecCopyf(&co[adata->Index*3], me->mvert[adata->Index].co);
+ }
+ }
+
+ if(ss->vertexcosnos)
+ BLI_freelistN(&active_verts);
+ else {
+ if(!e.grabdata)
+ addlisttolist(&ss->damaged_verts, &active_verts);
+ }
+ }
+}
+
+/* Flip all the editdata across the axis/axes specified by symm. Used to
+ calculate multiple modifications to the mesh when symmetry is enabled. */
+EditData flip_editdata(EditData *e, const char symm)
+{
+ EditData fe= *e;
+ GrabData *gd= fe.grabdata;
+
+ flip_coord(&fe.center.x, symm);
+ flip_coord(&fe.up.x, symm);
+ flip_coord(&fe.right.x, symm);
+ flip_coord(&fe.out.x, symm);
+
+ fe.symm= symm;
+
+ project(&e->center.x,fe.mouse);
+
+ if(gd) {
+ gd->index= symm;
+ gd->delta_symm= gd->delta;
+ flip_coord(&gd->delta_symm.x, symm);
+ }
+
+ return fe;
+}
+
+void do_symmetrical_brush_actions(EditData * e, short co[2], short pr_co[2])
+{
+ const char symm= sculpt_data()->symm;
+
+ init_editdata(e, co, pr_co);
+
+ do_brush_action(flip_editdata(e, 0));
+
+ if(symm & SYMM_X)
+ do_brush_action(flip_editdata(e, SYMM_X));
+ if(symm & SYMM_Y)
+ do_brush_action(flip_editdata(e, SYMM_Y));
+ if(symm & SYMM_Z)
+ do_brush_action(flip_editdata(e, SYMM_Z));
+ if(symm & SYMM_X && symm & SYMM_Y)
+ do_brush_action(flip_editdata(e, SYMM_X | SYMM_Y));
+ if(symm & SYMM_X && symm & SYMM_Z)
+ do_brush_action(flip_editdata(e, SYMM_X | SYMM_Z));
+ if(symm & SYMM_Y && symm & SYMM_Z)
+ do_brush_action(flip_editdata(e, SYMM_Y | SYMM_Z));
+ if(symm & SYMM_X && symm & SYMM_Y && symm & SYMM_Z)
+ do_brush_action(flip_editdata(e, SYMM_X | SYMM_Y | SYMM_Z));
+}
+
+void add_face_normal(vec3f *norm, const MFace* face)
+{
+ Mesh *me= get_mesh(OBACT);
+
+ vec3f c= {me->mvert[face->v1].co[0],me->mvert[face->v1].co[1],me->mvert[face->v1].co[2]};
+ vec3f b= {me->mvert[face->v2].co[0],me->mvert[face->v2].co[1],me->mvert[face->v2].co[2]};
+ vec3f a= {me->mvert[face->v3].co[0],me->mvert[face->v3].co[1],me->mvert[face->v3].co[2]};
+ vec3f s1, s2;
+
+ VecSubf(&s1.x,&a.x,&b.x);
+ VecSubf(&s2.x,&c.x,&b.x);
+
+ norm->x+= s1.y * s2.z - s1.z * s2.y;
+ norm->y+= s1.z * s2.x - s1.x * s2.z;
+ norm->z+= s1.x * s2.y - s1.y * s2.x;
+}
+
+void update_damaged_vert(Mesh *me, ListBase *lb)
+{
+ ActiveData *vert;
+
+ for(vert= lb->first; vert; vert= vert->next) {
+ vec3f norm= {0,0,0};
+ IndexNode *face= sculpt_session()->vertex_users[vert->Index].first;
+
+ while(face){
+ add_face_normal(&norm,&me->mface[face->Index]);
+ face= face->next;
+ }
+ Normalize(&norm.x);
+
+ me->mvert[vert->Index].no[0]=norm.x*32767;
+ me->mvert[vert->Index].no[1]=norm.y*32767;
+ me->mvert[vert->Index].no[2]=norm.z*32767;
+ }
+}
+
+void calc_damaged_verts(ListBase *damaged_verts, GrabData *grabdata)
+{
+ Mesh *me= get_mesh(OBACT);
+
+ if(grabdata) {
+ int i;
+ for(i=0; i<8; ++i)
+ update_damaged_vert(me,&grabdata->active_verts[i]);
+ } else {
+ update_damaged_vert(me,damaged_verts);
+ BLI_freelistN(damaged_verts);
+ damaged_verts->first = damaged_verts->last = NULL;
+ }
+}
+
+void projverts_clear_inside()
+{
+ Mesh *me = get_mesh(OBACT);
+ if(me) {
+ int i;
+ for(i = 0; i < me->totvert; ++i)
+ projverts[i].inside = 0;
+ }
+}
+
+BrushData *sculptmode_brush(void)
+{
+ SculptData *sd= &G.scene->sculptdata;
+
+ BrushData *bd =
+ (sd->brush_type==DRAW_BRUSH ? &sd->drawbrush :
+ sd->brush_type==SMOOTH_BRUSH ? &sd->smoothbrush :
+ sd->brush_type==PINCH_BRUSH ? &sd->pinchbrush :
+ sd->brush_type==INFLATE_BRUSH ? &sd->inflatebrush :
+ sd->brush_type==GRAB_BRUSH ? &sd->grabbrush :
+ sd->brush_type==LAYER_BRUSH ? &sd->layerbrush :
+ sd->brush_type==FLATTEN_BRUSH ? &sd->flattenbrush : NULL);
+
+ if(!bd) {
+ sculptmode_init(G.scene);
+ bd = &sd->drawbrush;
+ }
+
+ return bd;
+}
+
+void sculptmode_update_tex()
+{
+ SculptData *sd= sculpt_data();
+ SculptSession *ss= sculpt_session();
+ MTex *mtex = sd->mtex[sd->texact];
+ TexResult texres = {0};
+ float x, y, step=2.0/128.0, co[3];
+ int hasrgb, ix, iy;
+
+ /* Skip Default brush shape and non-textures */
+ if(sd->texact == -1 || !sd->mtex[sd->texact]) return;
+
+ if(ss->texcache) {
+ MEM_freeN(ss->texcache);
+ ss->texcache= NULL;
+ }
+
+ ss->texcache_w = ss->texcache_h = 128;
+ ss->texcache = MEM_callocN(sizeof(int) * ss->texcache_w * ss->texcache_h, "Sculpt Texture cache");
+
+ if(mtex && mtex->tex) {
+ BKE_image_get_ibuf(sd->mtex[sd->texact]->tex->ima, NULL);
+
+ /*do normalized cannonical view coords for texture*/
+ for (y=-1.0, iy=0; iy<128; iy++, y += step) {
+ for (x=-1.0, ix=0; ix<128; ix++, x += step) {
+ co[0]= x;
+ co[1]= y;
+ co[2]= 0.0f;
+
+ /* This is copied from displace modifier code */
+ hasrgb = multitex_ext(mtex->tex, co, NULL, NULL, 1, &texres);
+
+ /* if the texture gave an RGB value, we assume it didn't give a valid
+ * intensity, so calculate one (formula from do_material_tex).
+ * if the texture didn't give an RGB value, copy the intensity across
+ */
+ if(hasrgb & TEX_RGB)
+ texres.tin = (0.35 * texres.tr + 0.45 *
+ texres.tg + 0.2 * texres.tb);
+
+ texres.tin = texres.tin * 255.0;
+ ((char*)ss->texcache)[(iy*128+ix)*4] = (char)texres.tin;
+ ((char*)ss->texcache)[(iy*128+ix)*4+1] = (char)texres.tin;
+ ((char*)ss->texcache)[(iy*128+ix)*4+2] = (char)texres.tin;
+ ((char*)ss->texcache)[(iy*128+ix)*4+3] = (char)texres.tin;
+ }
+ }
+ }
+}
+
+/* pr_mouse is only used for the grab brush, can be NULL otherwise */
+void init_editdata(EditData *e, short *mouse, short *pr_mouse)
+{
+ SculptData *sd = sculpt_data();
+ const float mouse_depth= get_depth(mouse[0],mouse[1]);
+ vec3f brush_edge_loc, zero_loc, oldloc;
+ ModifierData *md;
+ int i;
+ const char flip = (get_qual() == LR_SHIFTKEY);
+
+ e->flip= flip;
+
+ /* Convert the location and size of the brush to
+ modelspace coords */
+ e->center= unproject(mouse[0],mouse[1],mouse_depth);
+ brush_edge_loc= unproject(mouse[0] +
+ brush_size(),mouse[1],
+ mouse_depth);
+ e->size= VecLenf(&e->center.x,&brush_edge_loc.x);
+
+ /* Set the pivot to allow the model to rotate around the center of the brush */
+ if(get_depth(mouse[0],mouse[1]) < 1.0)
+ sculpt_session()->pivot= e->center;
+
+ /* Now project the Up, Right, and Out normals from view to model coords */
+ zero_loc= unproject(0, 0, 0);
+ e->up= unproject(0, -1, 0);
+ e->right= unproject(1, 0, 0);
+ e->out= unproject(0, 0, -1);
+ VecSubf(&e->up.x, &e->up.x, &zero_loc.x);
+ VecSubf(&e->right.x, &e->right.x, &zero_loc.x);
+ VecSubf(&e->out.x, &e->out.x, &zero_loc.x);
+ Normalize(&e->up.x);
+ Normalize(&e->right.x);
+ Normalize(&e->out.x);
+
+ /* Initialize mirror modifier clipping */
+ for(i=0; i<3; ++i) {
+ e->clip[i]= 0;
+ e->cliptol[i]= 0;
+ }
+ for(md= OBACT->modifiers.first; md; md= md->next) {
+ if(md->type==eModifierType_Mirror && (md->mode & eModifierMode_Realtime)) {
+ const MirrorModifierData *mmd = (MirrorModifierData*) md;
+
+ if(mmd->flag & MOD_MIR_CLIPPING) {
+ e->clip[mmd->axis]= 1;
+ if(mmd->tolerance > e->cliptol[mmd->axis])
+ e->cliptol[mmd->axis]= mmd->tolerance;
+ }
+ }
+ }
+
+ if(sd->brush_type == GRAB_BRUSH) {
+ vec3f gcenter;
+ if(!e->grabdata) {
+ e->grabdata= MEM_callocN(sizeof(GrabData),"grab data");
+ e->grabdata->firsttime= 1;
+ e->grabdata->depth= mouse_depth;
+ }
+ else
+ e->grabdata->firsttime= 0;
+
+ /* Find the delta */
+ gcenter= unproject(mouse[0],mouse[1],e->grabdata->depth);
+ oldloc= unproject(pr_mouse[0],pr_mouse[1],e->grabdata->depth);
+ VecSubf(&e->grabdata->delta.x,&gcenter.x,&oldloc.x);
+ }
+ else if(sd->brush_type == LAYER_BRUSH) {
+ Mesh *me= get_mesh(OBACT);
+
+ if(!e->layer_disps)
+ e->layer_disps= MEM_callocN(sizeof(float)*me->totvert,"Layer disps");
+ if(!e->layer_store) {
+ unsigned i;
+ e->layer_store= MEM_mallocN(sizeof(vec3f)*me->totvert,"Layer store");
+ for(i=0; i<me->totvert; ++i)
+ VecCopyf(&e->layer_store[i].x,me->mvert[i].co);
+ }
+ }
+}
+void sculptmode_set_strength(const int delta)
+{
+ int val = sculptmode_brush()->strength + delta;
+ if(val < 1) val = 1;
+ if(val > 100) val = 100;
+ sculptmode_brush()->strength= val;
+}
+
+void sculptmode_propset_calctex()
+{
+ SculptData *sd= sculpt_data();
+ SculptSession *ss= sculpt_session();
+ PropsetData *pd= sculpt_session()->propset;
+ if(pd) {
+ int i, j;
+ const int tsz = 128;
+ float *d;
+ if(!pd->texdata) {
+ pd->texdata= MEM_mallocN(sizeof(float)*tsz*tsz, "Brush preview");
+ if(sd->texrept!=SCULPTREPT_3D)
+ sculptmode_update_tex();
+ for(i=0; i<tsz; ++i)
+ for(j=0; j<tsz; ++j) {
+ float magn= sqrt(pow(i-tsz/2,2)+pow(j-tsz/2,2));
+ if(sd->texfade)
+ pd->texdata[i*tsz+j]= simple_strength(magn,tsz/2);
+ else
+ pd->texdata[i*tsz+j]= magn < tsz/2 ? 1 : 0;
+ }
+ if(sd->texact != -1 && ss->texcache) {
+ for(i=0; i<tsz; ++i)
+ for(j=0; j<tsz; ++j) {
+ const int col= ss->texcache[i*tsz+j];
+ pd->texdata[i*tsz+j]*= (((char*)&col)[0]+((char*)&col)[1]+((char*)&col)[2])/3.0f/255.0f;
+ }
+ }
+ }
+
+ /* Adjust alpha with brush strength */
+ d= MEM_dupallocN(pd->texdata);
+ for(i=0; i<tsz; ++i)
+ for(j=0; j<tsz; ++j)
+ d[i*tsz+j]*= sculptmode_brush()->strength/200.0f+0.5f;
+
+
+ if(!pd->tex)
+ glGenTextures(1, (GLuint *)&pd->tex);
+ glBindTexture(GL_TEXTURE_2D, pd->tex);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, tsz, tsz, 0, GL_ALPHA, GL_FLOAT, d);
+ MEM_freeN(d);
+ }
+}
+
+void sculptmode_propset_header()
+{
+ SculptSession *ss= sculpt_session();
+ PropsetData *pd= ss ? ss->propset : NULL;
+ if(pd) {
+ char str[512];
+ const char *name= "";
+ int val= 0;
+ if(pd->mode == PropsetSize) {
+ name= "Size";
+ val= sculptmode_brush()->size;
+ }
+ else if(pd->mode == PropsetStrength) {
+ name= "Strength";
+ val= sculptmode_brush()->strength;
+ }
+ else if(pd->mode == PropsetTexRot) {
+ name= "Texture Angle";
+ val= tex_angle();
+ }
+ sprintf(str, "Brush %s: %d", name, val);
+ headerprint(str);
+ }
+}
+
+void sculptmode_propset_end(SculptSession *ss, int cancel)
+{
+ if(ss && ss->propset) {
+ PropsetData *pd= ss->propset;
+
+ if(cancel) {
+ sculptmode_brush()->size= pd->origsize;
+ sculptmode_brush()->strength= pd->origstrength;
+ set_tex_angle(pd->origtexrot);
+ } else {
+ if(pd->mode != PropsetSize)
+ sculptmode_brush()->size= pd->origsize;
+ if(pd->mode != PropsetStrength)
+ sculptmode_brush()->strength= pd->origstrength;
+ if(pd->mode != PropsetTexRot)
+ set_tex_angle(pd->origtexrot);
+ }
+ glDeleteTextures(1, &pd->tex);
+ MEM_freeN(pd->texdata);
+ MEM_freeN(pd);
+ ss->propset= NULL;
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ }
+}
+
+void sculptmode_propset_init(PropsetMode mode)
+{
+ SculptSession *ss= sculpt_session();
+ PropsetData *pd= ss->propset;
+ const float ang= tex_angle();
+
+ if(!pd) {
+ short mouse[2];
+
+ pd= MEM_callocN(sizeof(PropsetData),"PropsetSize");
+ ss->propset= pd;
+
+ getmouseco_areawin(mouse);
+ pd->origloc[0]= mouse[0];
+ pd->origloc[1]= mouse[1];
+
+ if(mode == PropsetSize)
+ pd->origloc[0]-= sculptmode_brush()->size;
+ else if(mode == PropsetStrength)
+ pd->origloc[0]-= 200 - 2*sculptmode_brush()->strength;
+ else if(mode == PropsetTexRot) {
+ pd->origloc[0]-= 200 * cos(to_rad(ang));
+ pd->origloc[1]-= 200 * sin(to_rad(ang));
+ }
+
+ pd->origsize= sculptmode_brush()->size;
+ pd->origstrength= sculptmode_brush()->strength;
+ pd->origtexrot= ang;
+
+ sculptmode_propset_calctex();
+
+ pd->num.idx_max= 0;
+ }
+
+ pd->mode= mode;
+ sculptmode_propset_header();
+
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+void sculpt_paint_brush(char clear)
+{
+ if(sculpt_data()->flags & SCULPT_DRAW_BRUSH) {
+ static short mvalo[2];
+ short mval[2];
+ const short rad= sculptmode_brush()->size;
+
+ getmouseco_areawin(mval);
+
+ persp(PERSP_WIN);
+ if(clear)
+ fdrawXORcirc(mval[0], mval[1], rad);
+ else
+ draw_sel_circle(mval, mvalo, rad, rad, 0);
+
+ mvalo[0]= mval[0];
+ mvalo[1]= mval[1];
+ }
+}
+
+void sculptmode_propset(unsigned short event)
+{
+ PropsetData *pd= sculpt_session()->propset;
+ short mouse[2];
+ short tmp[2];
+ float dist;
+ BrushData *brush= sculptmode_brush();
+ char valset= 0;
+
+ handleNumInput(&pd->num, event);
+
+ if(hasNumInput(&pd->num)) {
+ float val;
+ applyNumInput(&pd->num, &val);
+ if(pd->mode==PropsetSize)
+ brush->size= val;
+ else if(pd->mode==PropsetStrength)
+ brush->strength= val;
+ else if(pd->mode==PropsetTexRot)
+ set_tex_angle(val);
+ valset= 1;
+ allqueue(REDRAWVIEW3D, 0);
+ }
+
+ switch(event) {
+ case MOUSEX:
+ case MOUSEY:
+ if(!hasNumInput(&pd->num)) {
+ char ctrl= G.qual & LR_CTRLKEY;
+ getmouseco_areawin(mouse);
+ tmp[0]= pd->origloc[0]-mouse[0];
+ tmp[1]= pd->origloc[1]-mouse[1];
+ dist= sqrt(tmp[0]*tmp[0]+tmp[1]*tmp[1]);
+ if(pd->mode == PropsetSize) {
+ brush->size= dist;
+ if(ctrl) brush->size= (brush->size+5)/10*10;
+ } else if(pd->mode == PropsetStrength) {
+ float fin= (200.0f - dist) * 0.5f;
+ brush->strength= fin>=0 ? fin : 0;
+ if(ctrl) brush->strength= (brush->strength+5)/10*10;
+ } else if(pd->mode == PropsetTexRot) {
+ set_tex_angle((int)to_deg(atan2(tmp[1], tmp[0])) + 180);
+ if(ctrl)
+ set_tex_angle(((int)(tex_angle())+5)/10*10);
+ }
+ valset= 1;
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ break;
+ case ESCKEY:
+ case RIGHTMOUSE:
+ brush->size= pd->origsize;
+ brush->strength= pd->origstrength;
+ set_tex_angle(pd->origtexrot);
+ case LEFTMOUSE:
+ while(get_mbut()==L_MOUSE);
+ case RETKEY:
+ case PADENTER:
+ sculptmode_propset_end(sculpt_session(), 0);
+ break;
+ default:
+ break;
+ };
+
+ if(valset) {
+ if(pd->mode == PropsetSize) {
+ if(brush->size<1) brush->size= 1;
+ if(brush->size>200) brush->size= 200;
+ }
+ else if(pd->mode == PropsetStrength) {
+ if(brush->strength > 100) brush->strength= 100;
+ sculptmode_propset_calctex();
+ }
+ else if(pd->mode == PropsetTexRot) {
+ if(tex_angle() < 0)
+ set_tex_angle(0);
+ else if(tex_angle() > 360)
+ set_tex_angle(360);
+ }
+ }
+
+ sculptmode_propset_header();
+}
+
+void sculptmode_selectbrush_menu(void)
+{
+ SculptData *sd= sculpt_data();
+ int val;
+
+ pupmenu_set_active(sd->brush_type);
+
+ val= pupmenu("Select Brush%t|Draw|Smooth|Pinch|Inflate|Grab|Layer|Flatten");
+
+ if(val>0) {
+ sd->brush_type= val;
+
+ allqueue(REDRAWVIEW3D, 1);
+ allqueue(REDRAWBUTSEDIT, 1);
+ }
+}
+
+void sculptmode_update_all_projverts(float *vertcosnos)
+{
+ Mesh *me= get_mesh(OBACT);
+ unsigned i;
+
+ if(projverts) MEM_freeN(projverts);
+ projverts= MEM_mallocN(sizeof(ProjVert)*me->totvert,"ProjVerts");
+ for(i=0; i<me->totvert; ++i) {
+ project(vertcosnos ? &vertcosnos[i * 6] : me->mvert[i].co, projverts[i].co);
+ projverts[i].inside= 0;
+ }
+}
+
+void sculptmode_draw_wires(int only_damaged, Mesh *me)
+{
+ int i;
+
+ bglPolygonOffset(1.0);
+ glDepthMask(0);
+ BIF_ThemeColor((OBACT==OBACT)?TH_ACTIVE:TH_SELECT);
+
+ for(i=0; i<me->totedge; i++) {
+ MEdge *med= &me->medge[i];
+
+ if((!only_damaged || (projverts[med->v1].inside || projverts[med->v2].inside)) &&
+ (med->flag & ME_EDGEDRAW)) {
+ glDrawElements(GL_LINES, 2, GL_UNSIGNED_INT, &med->v1);
+ }
+ }
+
+ glDepthMask(1);
+ bglPolygonOffset(0.0);
+}
+
+void sculptmode_draw_mesh(int only_damaged)
+{
+ Mesh *me= get_mesh(OBACT);
+ int i, j, dt, drawCurrentMat = 1, matnr= -1;
+
+ persp(PERSP_VIEW);
+ mymultmatrix(OBACT->obmat);
+ glEnable(GL_DEPTH_TEST);
+ glEnable(GL_LIGHTING);
+ init_gl_materials(OBACT, 0);
+ glEnable(GL_CULL_FACE);
+
+ glShadeModel(GL_SMOOTH);
+
+ glVertexPointer(3, GL_FLOAT, sizeof(MVert), &me->mvert[0].co);
+ glNormalPointer(GL_SHORT, sizeof(MVert), &me->mvert[0].no);
+
+ dt= MIN2(G.vd->drawtype, OBACT->dt);
+ if(dt==OB_WIRE)
+ glColorMask(0,0,0,0);
+
+ for(i=0; i<me->totface; ++i) {
+ MFace *f= &me->mface[i];
+ char inside= 0;
+ int new_matnr= f->mat_nr + 1;
+
+ if(new_matnr != matnr)
+ drawCurrentMat= set_gl_material(matnr = new_matnr);
+
+ /* If only_damaged!=0, only draw faces that are partially
+ inside the area(s) modified by the brush */
+ if(only_damaged) {
+ for(j=0; j<(f->v4?4:3); ++j) {
+ if(projverts[*((&f->v1)+j)].inside) {
+ inside= 1;
+ break;
+ }
+ }
+ }
+ else
+ inside= 1;
+
+ if(inside && drawCurrentMat)
+ glDrawElements(f->v4?GL_QUADS:GL_TRIANGLES, f->v4?4:3, GL_UNSIGNED_INT, &f->v1);
+ }
+
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_LIGHTING);
+ glColorMask(1,1,1,1);
+
+ if(dt==OB_WIRE || (OBACT->dtx & OB_DRAWWIRE))
+ sculptmode_draw_wires(only_damaged, me);
+
+ glDisable(GL_DEPTH_TEST);
+}
+
+void sculptmode_correct_state(void)
+{
+ if(!sculpt_session())
+ sculpt_init_session();
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_NORMAL_ARRAY);
+
+ if(!sculpt_session()->vertex_users) calc_vertex_users();
+}
+
+/* Checks whether full update mode (slower) needs to be used to work with modifiers */
+char sculpt_modifiers_active(Object *ob)
+{
+ ModifierData *md;
+
+ for(md= modifiers_getVirtualModifierList(ob); md; md= md->next) {
+ if(md->mode & eModifierMode_Realtime)
+ return 1;
+ }
+
+ return 0;
+}
+
+void sculpt(void)
+{
+ SculptData *sd= sculpt_data();
+ SculptSession *ss= sculpt_session();
+ Object *ob= OBACT;
+ short mouse[2], mvalo[2], firsttime=1, mousebut;
+ short modifier_calculations= 0;
+ EditData e;
+ RectNode *rn= NULL;
+ short spacing= 32000;
+ int scissor_box[4];
+
+ if(!(G.f & G_SCULPTMODE) || G.obedit || !ob || ob->id.lib || !get_mesh(ob) || (get_mesh(ob)->totface == 0))
+ return;
+ if(!(ob->lay & G.vd->lay))
+ error("Active object is not in this layer");
+ if(ob_get_keyblock(ob)) {
+ if(!(ob->shapeflag & OB_SHAPE_LOCK)) {
+ error("Cannot sculpt on unlocked shape key");
+ return;
+ }
+ }
+
+ if(!ss) {
+ sculpt_init_session();
+ ss= sd->session;
+ }
+
+ if(sd->flags & SCULPT_INPUT_SMOOTH)
+ sculpt_stroke_new(256);
+
+ ss->damaged_rects.first = ss->damaged_rects.last = NULL;
+ ss->damaged_verts.first = ss->damaged_verts.last = NULL;
+ ss->vertexcosnos = NULL;
+
+ /* Check that vertex users are up-to-date */
+ if(ob != active_ob || ss->vertex_users_size != get_mesh(ob)->totvert) {
+ sculptmode_free_vertexusers(ss);
+ calc_vertex_users();
+ active_ob= ob;
+ }
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_NORMAL_ARRAY);
+
+ persp(PERSP_VIEW);
+
+ getmouseco_areawin(mvalo);
+
+ /* Make sure sculptdata has been init'd properly */
+ if(!ss->vertex_users) calc_vertex_users();
+
+ /* Init texture
+ FIXME: Shouldn't be doing this every time! */
+ if(sd->texrept!=SCULPTREPT_3D)
+ sculptmode_update_tex();
+
+ getmouseco_areawin(mouse);
+ mvalo[0]= mouse[0];
+ mvalo[1]= mouse[1];
+
+ mousebut = L_MOUSE;
+
+ /* If modifier_calculations is true, then extra time must be spent
+ updating the mesh. This takes a *lot* longer, so it's worth
+ skipping if the modifier stack is empty. */
+ modifier_calculations= sculpt_modifiers_active(ob);
+
+ init_sculptmatrices();
+
+ if(modifier_calculations)
+ ss->vertexcosnos= mesh_get_mapped_verts_nors(ob);
+ sculptmode_update_all_projverts(ss->vertexcosnos);
+
+ e.grabdata= NULL;
+ e.layer_disps= NULL;
+ e.layer_store= NULL;
+
+ /* Set scaling adjustment */
+ e.scale[0]= 1.0f / ob->size[0];
+ e.scale[1]= 1.0f / ob->size[1];
+ e.scale[2]= 1.0f / ob->size[2];
+
+ /* Capture original copy */
+ if(sd->flags & SCULPT_DRAW_FAST)
+ glAccum(GL_LOAD, 1);
+
+ /* Get original scissor box */
+ glGetIntegerv(GL_SCISSOR_BOX, scissor_box);
+
+ while (get_mbut() & mousebut) {
+ getmouseco_areawin(mouse);
+
+ if(firsttime || mouse[0]!=mvalo[0] || mouse[1]!=mvalo[1] || sculptmode_brush()->airbrush) {
+ firsttime= 0;
+
+ if(sd->flags & SCULPT_INPUT_SMOOTH)
+ sculpt_stroke_add_point(mouse[0], mouse[1]);
+
+ spacing+= sqrt(pow(mvalo[0]-mouse[0],2)+pow(mvalo[1]-mouse[1],2));
+
+ if(modifier_calculations && !ss->vertexcosnos)
+ ss->vertexcosnos= mesh_get_mapped_verts_nors(ob);
+
+ if(G.scene->sculptdata.brush_type != GRAB_BRUSH) {
+ if(sd->flags & SCULPT_INPUT_SMOOTH) {
+ sculpt_stroke_apply(&e);
+ }
+ else if(sd->spacing==0 || spacing>sd->spacing) {
+ do_symmetrical_brush_actions(&e, mouse, NULL);
+ spacing= 0;
+ }
+ }
+ else {
+ do_symmetrical_brush_actions(&e, mouse, mvalo);
+ ss->pivot= unproject(mouse[0],mouse[1],e.grabdata->depth);
+ }
+
+ if(modifier_calculations || ob_get_keyblock(ob))
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+
+ if(modifier_calculations || sd->brush_type == GRAB_BRUSH || !(sd->flags & SCULPT_DRAW_FAST)) {
+ calc_damaged_verts(&ss->damaged_verts,e.grabdata);
+ scrarea_do_windraw(curarea);
+ screen_swapbuffers();
+ } else { /* Optimized drawing */
+ calc_damaged_verts(&ss->damaged_verts,e.grabdata);
+
+ /* Draw the stored image to the screen */
+ glAccum(GL_RETURN, 1);
+
+ /* Clear each of the area(s) modified by the brush */
+ for(rn=ss->damaged_rects.first; rn; rn= rn->next) {
+ rcti clp= rn->r;
+ rcti *win= &curarea->winrct;
+
+ clp.xmin+= win->xmin;
+ clp.xmax+= win->xmin;
+ clp.ymin+= win->ymin;
+ clp.ymax+= win->ymin;
+
+ if(clp.xmin<win->xmax && clp.xmax>win->xmin &&
+ clp.ymin<win->ymax && clp.ymax>win->ymin) {
+ if(clp.xmin<win->xmin) clp.xmin= win->xmin;
+ if(clp.ymin<win->ymin) clp.ymin= win->ymin;
+ if(clp.xmax>win->xmax) clp.xmax= win->xmax;
+ if(clp.ymax>win->ymax) clp.ymax= win->ymax;
+ glScissor(clp.xmin+1, clp.ymin+1,
+ clp.xmax-clp.xmin-2,clp.ymax-clp.ymin-2);
+ }
+
+ glClear(GL_DEPTH_BUFFER_BIT);
+ }
+
+ /* Draw all the polygons that are inside the modified area(s) */
+ glScissor(scissor_box[0], scissor_box[1], scissor_box[2], scissor_box[3]);
+ sculptmode_draw_mesh(1);
+ glAccum(GL_LOAD, 1);
+
+ projverts_clear_inside();
+
+ persp(PERSP_WIN);
+ glDisable(GL_DEPTH_TEST);
+
+ /* Draw cursor */
+ if(sculpt_data()->flags & SCULPT_DRAW_BRUSH)
+ fdrawXORcirc((float)mouse[0],(float)mouse[1],sculptmode_brush()->size);
+ if(sculpt_data()->flags & SCULPT_INPUT_SMOOTH)
+ sculpt_stroke_draw();
+
+ myswapbuffers();
+ }
+
+ BLI_freelistN(&ss->damaged_rects);
+ ss->damaged_rects.first = ss->damaged_rects.last = NULL;
+
+ mvalo[0]= mouse[0];
+ mvalo[1]= mouse[1];
+
+ if(ss->vertexcosnos) {
+ MEM_freeN(ss->vertexcosnos);
+ ss->vertexcosnos= NULL;
+ }
+
+ }
+ else BIF_wait_for_statechange();
+ }
+
+ if(sd->flags & SCULPT_INPUT_SMOOTH) {
+ sculpt_stroke_apply_all(&e);
+ calc_damaged_verts(&ss->damaged_verts,e.grabdata);
+ BLI_freelistN(&ss->damaged_rects);
+ }
+
+ if(projverts) MEM_freeN(projverts);
+ projverts= NULL;
+ if(e.layer_disps) MEM_freeN(e.layer_disps);
+ if(e.layer_store) MEM_freeN(e.layer_store);
+ /* Free GrabData */
+ if(e.grabdata) {
+ int i;
+ for(i=0; i<8; ++i)
+ BLI_freelistN(&e.grabdata->active_verts[i]);
+ MEM_freeN(e.grabdata);
+ }
+ sculpt_stroke_free();
+
+ switch(G.scene->sculptdata.brush_type) {
+ case DRAW_BRUSH:
+ BIF_undo_push("Draw Brush"); break;
+ case SMOOTH_BRUSH:
+ BIF_undo_push("Smooth Brush"); break;
+ case PINCH_BRUSH:
+ BIF_undo_push("Pinch Brush"); break;
+ case INFLATE_BRUSH:
+ BIF_undo_push("Inflate Brush"); break;
+ case GRAB_BRUSH:
+ BIF_undo_push("Grab Brush"); break;
+ case LAYER_BRUSH:
+ BIF_undo_push("Layer Brush"); break;
+ case FLATTEN_BRUSH:
+ BIF_undo_push("Flatten Brush"); break;
+ default:
+ BIF_undo_push("Sculpting"); break;
+ }
+
+ if(G.vd->depths) G.vd->depths->damaged= 1;
+
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+void set_sculptmode(void)
+{
+ if(G.f & G_SCULPTMODE) {
+ Mesh *me= get_mesh(OBACT);
+
+ G.f &= ~G_SCULPTMODE;
+
+ sculptmode_free_session(G.scene);
+ if(me && me->pv)
+ sculptmode_pmv_off(me);
+ }
+ else {
+ G.f |= G_SCULPTMODE;
+
+ /* Called here to sanity-check the brush */
+ sculptmode_brush();
+
+ sculpt_init_session();
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_NORMAL_ARRAY);
+ }
+
+ active_ob= NULL;
+
+ allqueue(REDRAWVIEW3D, 1);
+ allqueue(REDRAWBUTSEDIT, 0);
+}
+
+/* Partial Mesh Visibility */
+PartialVisibility *sculptmode_copy_pmv(PartialVisibility *pmv)
+{
+ PartialVisibility *n= MEM_dupallocN(pmv);
+ n->vert_map= MEM_dupallocN(pmv->vert_map);
+ n->edge_map= MEM_dupallocN(pmv->edge_map);
+ n->old_edges= MEM_dupallocN(pmv->old_edges);
+ n->old_faces= MEM_dupallocN(pmv->old_faces);
+ return n;
+}
+
+void sculptmode_pmv_free(PartialVisibility *pv)
+{
+ MEM_freeN(pv->vert_map);
+ MEM_freeN(pv->edge_map);
+ MEM_freeN(pv->old_faces);
+ MEM_freeN(pv->old_edges);
+ MEM_freeN(pv);
+}
+
+void sculptmode_revert_pmv(Mesh *me)
+{
+ if(me->pv) {
+ unsigned i;
+ MVert *nve, *old_verts;
+
+ active_ob= NULL;
+
+ /* Reorder vertices */
+ nve= me->mvert;
+ old_verts = MEM_mallocN(sizeof(MVert)*me->pv->totvert,"PMV revert verts");
+ for(i=0; i<me->pv->totvert; ++i)
+ old_verts[i]= nve[me->pv->vert_map[i]];
+
+ /* Restore verts, edges and faces */
+ CustomData_free_layer_active(&me->vdata, CD_MVERT, me->totvert);
+ CustomData_free_layer_active(&me->edata, CD_MEDGE, me->totedge);
+ CustomData_free_layer_active(&me->fdata, CD_MFACE, me->totface);
+
+ CustomData_add_layer(&me->vdata, CD_MVERT, CD_ASSIGN, old_verts, me->pv->totvert);
+ CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, me->pv->old_edges, me->pv->totedge);
+ CustomData_add_layer(&me->fdata, CD_MFACE, CD_ASSIGN, me->pv->old_faces, me->pv->totface);
+ mesh_update_customdata_pointers(me);
+
+ me->totvert= me->pv->totvert;
+ me->totedge= me->pv->totedge;
+ me->totface= me->pv->totface;
+
+ me->pv->old_edges= NULL;
+ me->pv->old_faces= NULL;
+
+ /* Free maps */
+ MEM_freeN(me->pv->edge_map);
+ me->pv->edge_map= NULL;
+ MEM_freeN(me->pv->vert_map);
+ me->pv->vert_map= NULL;
+
+ DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA);
+ }
+}
+
+void sculptmode_pmv_off(Mesh *me)
+{
+ if(me->pv) {
+ sculptmode_revert_pmv(me);
+ MEM_freeN(me->pv);
+ me->pv= NULL;
+ }
+}
+
+/* mode: 0=hide outside selection, 1=hide inside selection */
+void sculptmode_do_pmv(Object *ob, rcti *hb_2d, int mode)
+{
+ Mesh *me= get_mesh(ob);
+ vec3f hidebox[6];
+ vec3f plane_normals[4];
+ float plane_ds[4];
+ unsigned i, j;
+ unsigned ndx_show, ndx_hide;
+ MVert *nve;
+ unsigned face_cnt_show= 0, face_ndx_show= 0;
+ unsigned edge_cnt_show= 0, edge_ndx_show= 0;
+ unsigned *old_map= NULL;
+ const unsigned SHOW= 0, HIDE=1;
+
+ /* Convert hide box from 2D to 3D */
+ hidebox[0]= unproject(hb_2d->xmin, hb_2d->ymax, 1);
+ hidebox[1]= unproject(hb_2d->xmax, hb_2d->ymax, 1);
+ hidebox[2]= unproject(hb_2d->xmax, hb_2d->ymin, 1);
+ hidebox[3]= unproject(hb_2d->xmin, hb_2d->ymin, 1);
+ hidebox[4]= unproject(hb_2d->xmin, hb_2d->ymax, 0);
+ hidebox[5]= unproject(hb_2d->xmax, hb_2d->ymin, 0);
+
+ /* Calculate normals for each side of hide box */
+ CalcNormFloat(&hidebox[0].x,&hidebox[1].x,&hidebox[4].x,&plane_normals[0].x);
+ CalcNormFloat(&hidebox[1].x,&hidebox[2].x,&hidebox[5].x,&plane_normals[1].x);
+ CalcNormFloat(&hidebox[2].x,&hidebox[3].x,&hidebox[5].x,&plane_normals[2].x);
+ CalcNormFloat(&hidebox[3].x,&hidebox[0].x,&hidebox[4].x,&plane_normals[3].x);
+
+ /* Calculate D for each side of hide box */
+ for(i= 0; i<4; ++i)
+ plane_ds[i]= hidebox[i].x*plane_normals[i].x + hidebox[i].y*plane_normals[i].y +
+ hidebox[i].z*plane_normals[i].z;
+
+ /* Add partial visibility to mesh */
+ if(!me->pv) {
+ me->pv= MEM_callocN(sizeof(PartialVisibility),"PartialVisibility");
+ } else {
+ old_map= MEM_callocN(sizeof(unsigned)*me->pv->totvert,"PMV oldmap");
+ for(i=0; i<me->pv->totvert; ++i) {
+ old_map[i]= me->pv->vert_map[i]<me->totvert?0:1;
+ }
+ sculptmode_revert_pmv(me);
+ }
+
+ /* Kill sculpt data */
+ active_ob= NULL;
+
+ /* Initalize map with which verts are to be hidden */
+ me->pv->vert_map= MEM_mallocN(sizeof(unsigned)*me->totvert, "PMV vertmap");
+ me->pv->totvert= me->totvert;
+ me->totvert= 0;
+ for(i=0; i<me->pv->totvert; ++i) {
+ me->pv->vert_map[i]= mode ? HIDE:SHOW;
+ for(j=0; j<4; ++j) {
+ if(me->mvert[i].co[0] * plane_normals[j].x +
+ me->mvert[i].co[1] * plane_normals[j].y +
+ me->mvert[i].co[2] * plane_normals[j].z < plane_ds[j] ) {
+ me->pv->vert_map[i]= mode ? SHOW:HIDE; /* Vert is outside the hide box */
+ break;
+ }
+ }
+ if(old_map && old_map[i]) me->pv->vert_map[i]= 1;
+ if(!me->pv->vert_map[i]) ++me->totvert;
+
+ }
+ if(old_map) MEM_freeN(old_map);
+
+ /* Find out how many faces to show */
+ for(i=0; i<me->totface; ++i) {
+ if(!me->pv->vert_map[me->mface[i].v1] &&
+ !me->pv->vert_map[me->mface[i].v2] &&
+ !me->pv->vert_map[me->mface[i].v3]) {
+ if(me->mface[i].v4) {
+ if(!me->pv->vert_map[me->mface[i].v4])
+ ++face_cnt_show;
+ }
+ else ++face_cnt_show;
+ }
+ }
+ /* Find out how many edges to show */
+ for(i=0; i<me->totedge; ++i) {
+ if(!me->pv->vert_map[me->medge[i].v1] &&
+ !me->pv->vert_map[me->medge[i].v2])
+ ++edge_cnt_show;
+ }
+
+ /* Create new vert array and reset each vert's map with map[old]=new index */
+ nve= MEM_mallocN(sizeof(MVert)*me->pv->totvert, "PMV verts");
+ ndx_show= 0; ndx_hide= me->totvert;
+ for(i=0; i<me->pv->totvert; ++i) {
+ if(me->pv->vert_map[i]) {
+ me->pv->vert_map[i]= ndx_hide;
+ nve[me->pv->vert_map[i]]= me->mvert[i];
+ ++ndx_hide;
+ } else {
+ me->pv->vert_map[i]= ndx_show;
+ nve[me->pv->vert_map[i]]= me->mvert[i];
+ ++ndx_show;
+ }
+ }
+ CustomData_free_layer_active(&me->vdata, CD_MVERT, me->pv->totvert);
+ me->mvert= CustomData_add_layer(&me->vdata, CD_MVERT, CD_ASSIGN, nve, me->totvert);
+
+ /* Create new face array */
+ me->pv->old_faces= me->mface;
+ me->pv->totface= me->totface;
+ me->mface= MEM_mallocN(sizeof(MFace)*face_cnt_show, "PMV faces");
+ for(i=0; i<me->totface; ++i) {
+ MFace *pr_f= &me->pv->old_faces[i];
+ char show= 0;
+
+ if(me->pv->vert_map[pr_f->v1] < me->totvert &&
+ me->pv->vert_map[pr_f->v2] < me->totvert &&
+ me->pv->vert_map[pr_f->v3] < me->totvert) {
+ if(pr_f->v4) {
+ if(me->pv->vert_map[pr_f->v4] < me->totvert)
+ show= 1;
+ }
+ else show= 1;
+ }
+
+ if(show) {
+ MFace *cr_f= &me->mface[face_ndx_show];
+ *cr_f= *pr_f;
+ cr_f->v1= me->pv->vert_map[pr_f->v1];
+ cr_f->v2= me->pv->vert_map[pr_f->v2];
+ cr_f->v3= me->pv->vert_map[pr_f->v3];
+ cr_f->v4= pr_f->v4 ? me->pv->vert_map[pr_f->v4] : 0;
+ test_index_face(cr_f,NULL,0,pr_f->v4?4:3);
+ ++face_ndx_show;
+ }
+ }
+ me->totface= face_cnt_show;
+ CustomData_set_layer(&me->fdata, CD_MFACE, me->mface);
+
+ /* Create new edge array */
+ me->pv->old_edges= me->medge;
+ me->pv->totedge= me->totedge;
+ me->medge= MEM_mallocN(sizeof(MEdge)*edge_cnt_show, "PMV edges");
+ me->pv->edge_map= MEM_mallocN(sizeof(int)*me->pv->totedge,"PMV edgemap");
+ for(i=0; i<me->totedge; ++i) {
+ if(me->pv->vert_map[me->pv->old_edges[i].v1] < me->totvert &&
+ me->pv->vert_map[me->pv->old_edges[i].v2] < me->totvert) {
+ MEdge *cr_e= &me->medge[edge_ndx_show];
+ me->pv->edge_map[i]= edge_ndx_show;
+ *cr_e= me->pv->old_edges[i];
+ cr_e->v1= me->pv->vert_map[me->pv->old_edges[i].v1];
+ cr_e->v2= me->pv->vert_map[me->pv->old_edges[i].v2];
+ ++edge_ndx_show;
+ }
+ else me->pv->edge_map[i]= -1;
+ }
+ me->totedge= edge_cnt_show;
+ CustomData_set_layer(&me->edata, CD_MEDGE, me->medge);
+
+ DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA);
+}
+
+rcti sculptmode_pmv_box()
+{
+ short down[2], mouse[2];
+ rcti ret;
+
+ getmouseco_areawin(down);
+
+ while((get_mbut()&L_MOUSE) || (get_mbut()&R_MOUSE)) {
+ getmouseco_areawin(mouse);
+
+ scrarea_do_windraw(curarea);
+
+ persp(PERSP_WIN);
+ glLineWidth(2);
+ setlinestyle(2);
+ sdrawXORline(down[0],down[1],mouse[0],down[1]);
+ sdrawXORline(mouse[0],down[1],mouse[0],mouse[1]);
+ sdrawXORline(mouse[0],mouse[1],down[0],mouse[1]);
+ sdrawXORline(down[0],mouse[1],down[0],down[1]);
+ setlinestyle(0);
+ glLineWidth(1);
+ persp(PERSP_VIEW);
+
+ screen_swapbuffers();
+ backdrawview3d(0);
+ }
+
+ ret.xmin= down[0]<mouse[0]?down[0]:mouse[0];
+ ret.ymin= down[1]<mouse[1]?down[1]:mouse[1];
+ ret.xmax= down[0]>mouse[0]?down[0]:mouse[0];
+ ret.ymax= down[1]>mouse[1]?down[1]:mouse[1];
+ return ret;
+}
+
+void sculptmode_pmv(int mode)
+{
+ Object *ob= OBACT;
+ rcti hb_2d;
+
+ if(ob_get_key(ob)) {
+ error("Cannot hide mesh with shape keys enabled");
+ return;
+ }
+
+ hb_2d= sculptmode_pmv_box(); /* Get 2D hide box */
+
+ sculptmode_correct_state();
+
+ waitcursor(1);
+
+ if(hb_2d.xmax-hb_2d.xmin > 3 && hb_2d.ymax-hb_2d.ymin > 3) {
+ init_sculptmatrices();
+
+ sculptmode_do_pmv(ob,&hb_2d,mode);
+ }
+ else sculptmode_pmv_off(get_mesh(ob));
+
+ scrarea_do_windraw(curarea);
+
+ BIF_undo_push("Partial mesh hide");
+
+ waitcursor(0);
+}
diff --git a/source/blender/src/seqaudio.c b/source/blender/src/seqaudio.c
new file mode 100644
index 00000000000..de8cc488a85
--- /dev/null
+++ b/source/blender/src/seqaudio.c
@@ -0,0 +1,546 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): intrr, Peter Schlaile
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef WIN32
+#define __USE_XOPEN /* Needed for swab on linux */
+#include <unistd.h>
+#undef __USE_XOPEN
+#else
+#include <io.h>
+#endif
+
+#include <fcntl.h>
+#include <stdio.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "PIL_time.h"
+
+#include "BMF_Api.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "DNA_screen_types.h"
+#include "DNA_sound_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_sequence_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_ipo_types.h"
+
+#include "BKE_utildefines.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_blender.h"
+#include "BKE_main.h"
+#include "BKE_ipo.h"
+
+#include "BIF_gl.h"
+#include "BIF_graphics.h"
+#include "BIF_keyval.h"
+#include "BIF_mainqueue.h"
+#include "BIF_resources.h"
+#include "BIF_screen.h"
+#include "BIF_toolbox.h"
+#include "BIF_mywindow.h"
+#include "BIF_space.h"
+#include "BIF_glutil.h"
+#include "BIF_interface.h"
+
+#include "BSE_view.h"
+#include "BSE_seqaudio.h"
+#include "BIF_editsound.h"
+
+#include "mydevice.h"
+#include "blendef.h"
+
+
+void audio_fill(void *mixdown, Uint8 *sstream, int len);
+/* ************ GLOBALS ************* */
+
+static int audio_pos;
+static int audio_scrub=0;
+static int audio_playing=0;
+static int audio_initialised=0;
+static int audio_startframe=0;
+/////
+//
+/* local protos ------------------- */
+void audio_mixdown(void);
+
+void makewavstring (char *string)
+{
+ char txt[64];
+
+ if (string==0) return;
+
+ strcpy(string, G.scene->r.pic);
+ BLI_convertstringcode(string, G.sce, G.scene->r.cfra);
+
+ BLI_make_existing_file(string);
+
+ if (BLI_strcasecmp(string + strlen(string) - 4, ".wav")) {
+ sprintf(txt, "%04d_%04d.wav", (G.scene->r.sfra) , (G.scene->r.efra) );
+ strcat(string, txt);
+ }
+}
+
+void audio_mixdown()
+{
+ int file, c, totlen, totframe, i, oldcfra;
+ char *buf;
+
+ buf = MEM_mallocN(65536, "audio_mixdown");
+ makewavstring(buf);
+
+ file = open(buf, O_BINARY+O_WRONLY+O_CREAT+O_TRUNC, 0666);
+
+ if(file == -1)
+ {
+ error("Can't open output file");
+ return;
+ }
+
+ waitcursor(1);
+
+ printf("Saving: %s ", buf);
+
+ strcpy(buf, "RIFFlengWAVEfmt fmln01ccRATEbsecBP16dataDLEN");
+ totframe = (EFRA - SFRA + 1);
+ totlen = (int) ( FRA2TIME(totframe) * (float)G.scene->audio.mixrate * 4.0);
+ printf(" totlen %d\n", totlen+36+8);
+
+ totlen+= 36; /* len is filesize-8 in WAV spec, total header is 44 bytes */
+ memcpy(buf+4, &totlen, 4);
+ totlen-= 36;
+
+ buf[16] = 0x10; buf[17] = buf[18] = buf[19] = 0; buf[20] = 1; buf[21] = 0;
+ buf[22] = 2; buf[23]= 0;
+ memcpy(buf+24, &G.scene->audio.mixrate, 4);
+ i = G.scene->audio.mixrate * 4;
+ memcpy(buf+28, &i, 4);
+ buf[32] = 4; buf[33] = 0; buf[34] = 16; buf[35] = 0;
+ i = totlen;
+ memcpy(buf+40, &i, 4);
+
+ if (G.order == B_ENDIAN) {
+ /* swap the four ints to little endian */
+
+ /* length */
+ SWITCH_INT(buf[4]);
+
+ /* audio rate */
+ SWITCH_INT(buf[24]);
+
+ /* audio mixrate * 4 */
+ SWITCH_INT(buf[28]);
+
+ /* length */
+ SWITCH_INT(buf[40]);
+ }
+
+ c = write(file, buf, 44);
+
+ oldcfra = CFRA;
+ audiostream_play(SFRA, 0, 1);
+
+ i= 0;
+ while ( totlen > 0 ) {
+ totlen -= 64;
+
+ memset(buf+i, 0, 64);
+
+ CFRA=(int) ( ((float)(audio_pos-64)/( G.scene->audio.mixrate*4 ))*FPS );
+
+ audio_fill(buf+i, NULL, 64);
+ if (G.order == B_ENDIAN) {
+ char tbuf[64];
+ memcpy(tbuf, buf+i, 64);
+ swab(tbuf, buf+i, 64);
+ }
+ if (i == (65536-64)) {
+ i=0;
+ write(file, buf, 65536);
+ }
+ else i+=64;
+ }
+ write(file, buf, i);
+
+ waitcursor(0);
+ CFRA = oldcfra;
+ close(file);
+ MEM_freeN(buf);
+
+ return;
+}
+
+void audiostream_fill(Uint8 *mixdown, int len)
+{
+ int oldcfra = CFRA;
+ int i;
+
+ memset(mixdown, 0, len);
+
+ for (i = 0; i < len; i += 64) {
+ CFRA = (int) ( ((float)(audio_pos-64)
+ /( G.scene->audio.mixrate*4 ))
+ * FPS );
+
+ audio_fill(mixdown + i, NULL,
+ (len - i) > 64 ? 64 : (len - i));
+ }
+
+ CFRA = oldcfra;
+}
+
+
+static void audio_levels(Uint8 *buf, int len, float db, float facf, float pan)
+{
+ int i;
+ float facl, facr, fac;
+ signed short *sample;
+
+ if (pan>=0) { facr = 1.0; facl = 1.0-pan; }
+ else { facr = pan+1.0; facl = 1.0; }
+
+ fac = pow(10.0, ((-(db+G.scene->audio.main))/20.0)) / facf;
+ facl /= fac;
+ facr /= fac;
+
+ for (i=0; i<len; i+=4) {
+ sample = (signed short*)(buf+i);
+ sample[0] = (short) ((float)sample[0] * facl);
+ sample[1] = (short) ((float)sample[1] * facr);
+ }
+}
+
+/* convert mono/stereo and sampling rate, alloc a buffer for
+ * sound->stream to contain the new sample, and set sound->streamlen
+ * accordingly.
+ */
+void audio_makestream(bSound *sound)
+{
+ signed short *source, *dest;
+ float ratio;
+ int i;
+
+ if ( (!sound)||(sound->stream)||(!sound->sample)||(!G.scene) ) {
+ return;
+ }
+ ratio = (float)G.scene->audio.mixrate / (float)sound->sample->rate;
+ sound->streamlen = (int) ( (float)sound->sample->len * ratio * 2.0/((float)sound->sample->channels) );
+ sound->stream = malloc((int) ((float)sound->streamlen * 1.05));
+ if (sound->sample->rate == G.scene->audio.mixrate) {
+ if (sound->sample->channels == 2) {
+ memcpy(sound->stream, sound->sample->data, sound->streamlen);
+ return;
+ } else {
+ for (source = (signed short*)(sound->sample->data),
+ dest = (signed short*)(sound->stream),
+ i=0;
+ i<sound->streamlen/4;
+ dest += 2, source++, i++) dest[0] = dest[1] = source[0];
+ return;
+ }
+ }
+ if (sound->sample->channels == 1) {
+ for (dest=(signed short*)(sound->stream), i=0, source=(signed short*)(sound->sample->data);
+ i<(sound->streamlen/4); dest+=2, i++)
+ dest[0] = dest[1] = source[(int)((float)i/ratio)];
+ }
+ else if (sound->sample->channels == 2) {
+ for (dest=(signed short*)(sound->stream), i=0, source=(signed short*)(sound->sample->data);
+ i<(sound->streamlen/2); dest+=2, i+=2) {
+ dest[1] = source[(int)((float)i/ratio)];
+ dest[0] = source[(int)((float)i/ratio)+1];
+ }
+ }
+}
+
+static void audio_fill_ram_sound(Sequence *seq, void * mixdown,
+ Uint8 * sstream, int len)
+{
+ Uint8* cvtbuf;
+ bSound* sound;
+ float facf;
+
+ sound = seq->sound;
+ audio_makestream(sound);
+ if ((seq->curpos<sound->streamlen -len) && (seq->curpos>=0) &&
+ (seq->startdisp <= CFRA) && ((seq->enddisp) > CFRA))
+ {
+ if(seq->ipo && seq->ipo->curve.first) {
+ do_seq_ipo(seq);
+ facf = seq->facf0;
+ } else {
+ facf = 1.0;
+ }
+ cvtbuf = malloc(len);
+ memcpy(cvtbuf, ((Uint8*)sound->stream)+(seq->curpos & (~3)), len);
+ audio_levels(cvtbuf, len, seq->level, facf, seq->pan);
+ if (!mixdown) {
+ SDL_MixAudio(sstream, cvtbuf, len, SDL_MIX_MAXVOLUME);
+ } else {
+ SDL_MixAudio((Uint8*)mixdown, cvtbuf, len, SDL_MIX_MAXVOLUME);
+ }
+ free(cvtbuf);
+ }
+ seq->curpos += len;
+}
+
+static void audio_fill_hd_sound(Sequence *seq,
+ void * mixdown, Uint8 * sstream,
+ int len)
+{
+ Uint8* cvtbuf;
+ float facf;
+
+ if ((seq->curpos >= 0) &&
+ (seq->startdisp <= CFRA) && ((seq->enddisp) > CFRA))
+ {
+ if(seq->ipo && seq->ipo->curve.first) {
+ do_seq_ipo(seq);
+ facf = seq->facf0;
+ } else {
+ facf = 1.0;
+ }
+ cvtbuf = malloc(len);
+
+ sound_hdaudio_extract(seq->hdaudio, (short*) cvtbuf,
+ seq->curpos / 4,
+ G.scene->audio.mixrate,
+ 2,
+ len / 4);
+ audio_levels(cvtbuf, len, seq->level, facf, seq->pan);
+ if (!mixdown) {
+ SDL_MixAudio(sstream,
+ cvtbuf, len, SDL_MIX_MAXVOLUME);
+ } else {
+ SDL_MixAudio((Uint8*)mixdown,
+ cvtbuf, len, SDL_MIX_MAXVOLUME);
+ }
+ free(cvtbuf);
+ }
+ seq->curpos += len;
+}
+
+static void audio_fill_seq(Sequence * seq, void * mixdown,
+ Uint8 *sstream, int len)
+{
+ while(seq) {
+ if (seq->type == SEQ_META) {
+ audio_fill_seq(seq->seqbase.first,
+ mixdown, sstream, len);
+ }
+ if ( (seq->type == SEQ_RAM_SOUND) &&
+ (seq->sound) &&
+ (!(seq->flag & SEQ_MUTE))) {
+ audio_fill_ram_sound(seq, mixdown, sstream, len);
+ }
+ if ( (seq->type == SEQ_HD_SOUND) &&
+ (!(seq->flag & SEQ_MUTE))) {
+ if (!seq->hdaudio) {
+ char name[FILE_MAXDIR+FILE_MAXFILE];
+
+ strncpy(name, seq->strip->dir,
+ FILE_MAXDIR-1);
+ strncat(name,
+ seq->strip->stripdata->name,
+ FILE_MAXFILE-1);
+ BLI_convertstringcode(name, G.sce,
+ G.scene->r.cfra);
+
+ seq->hdaudio= sound_open_hdaudio(name);
+ }
+ if (seq->hdaudio) {
+ audio_fill_hd_sound(seq, mixdown,
+ sstream, len);
+ }
+ }
+ seq = seq->next;
+ }
+}
+
+void audio_fill(void *mixdown, Uint8 *sstream, int len)
+{
+ Editing *ed;
+ Sequence *seq;
+
+ ed = G.scene->ed;
+ if((ed) && (!(G.scene->audio.flag & AUDIO_MUTE))) {
+ seq = ed->seqbasep->first;
+ audio_fill_seq(seq, mixdown, sstream, len);
+ }
+
+ audio_pos += len;
+ if (audio_scrub) {
+ audio_scrub--;
+ if (!audio_scrub) {
+ audiostream_stop();
+ }
+ }
+}
+
+static int audio_init(SDL_AudioSpec *desired)
+{
+ SDL_AudioSpec *obtained, *hardware_spec;
+
+ SDL_CloseAudio();
+
+ obtained = (SDL_AudioSpec*)MEM_mallocN(sizeof(SDL_AudioSpec),
+ "SDL_AudioSpec");
+
+ desired->callback=audio_fill;
+
+ if ( SDL_OpenAudio(desired, obtained) < 0 ) {
+ fprintf(stderr, "Couldn't open audio: %s\n", SDL_GetError());
+ if (obtained) MEM_freeN(obtained);
+ return 0;
+ }
+ audio_initialised = 1;
+ hardware_spec=obtained;
+
+ MEM_freeN(obtained);
+
+ SDL_PauseAudio(0);
+ return 1;
+}
+
+static int audiostream_play_seq(Sequence * seq, Uint32 startframe)
+{
+ char name[FILE_MAXDIR+FILE_MAXFILE];
+ int have_sound = 0;
+
+ while(seq) {
+ if (seq->type == SEQ_META) {
+ if (audiostream_play_seq(
+ seq->seqbase.first, startframe)) {
+ have_sound = 1;
+ }
+ }
+ if ((seq->type == SEQ_RAM_SOUND) && (seq->sound)) {
+ have_sound = 1;
+ seq->curpos = (int)( (FRA2TIME((double) startframe -
+ (double) seq->start)
+ * ((float)G.scene->audio.mixrate)
+ * 4 ));
+ }
+ if ((seq->type == SEQ_HD_SOUND)) {
+ have_sound = 1;
+ if (!seq->hdaudio) {
+ strncpy(name, seq->strip->dir, FILE_MAXDIR-1);
+ strncat(name, seq->strip->stripdata->name,
+ FILE_MAXFILE-1);
+
+ seq->hdaudio = sound_open_hdaudio(name);
+ }
+ seq->curpos = (int)( (FRA2TIME((double) startframe -
+ (double) seq->start)
+ * ((float)G.scene->audio.mixrate)
+ * 4 ));
+ }
+ seq= seq->next;
+ }
+ return have_sound;
+}
+
+void audiostream_play(Uint32 startframe, Uint32 duration, int mixdown)
+{
+ static SDL_AudioSpec desired;
+ Editing *ed;
+ int have_sound = 0;
+
+ ed= G.scene->ed;
+ if(ed) {
+ have_sound =
+ audiostream_play_seq(ed->seqbasep->first, startframe);
+ }
+
+ if(have_sound) {
+ /* this call used to be in startup */
+ sound_init_audio();
+ }
+
+ if (!audio_initialised && !(duration + mixdown)) {
+ desired.freq=G.scene->audio.mixrate;
+ desired.format=AUDIO_S16SYS;
+ desired.channels=2;
+ desired.samples=U.mixbufsize;
+ desired.userdata=0;
+ if (audio_init(&desired)==0) {
+ U.mixbufsize = 0; /* no audio */
+ }
+ }
+
+ audio_startframe = startframe;
+ audio_pos = ( ((int)( FRA2TIME(startframe)
+ *(G.scene->audio.mixrate)*4 )) & (~3) );
+
+ audio_scrub = duration;
+ if (!mixdown) {
+ SDL_PauseAudio(0);
+ audio_playing++;
+ }
+}
+
+void audiostream_start(Uint32 frame)
+{
+ audiostream_play(frame, 0, 0);
+}
+
+void audiostream_scrub(Uint32 frame)
+{
+ if (U.mixbufsize) audiostream_play(frame, 4096/U.mixbufsize, 0);
+}
+
+void audiostream_stop(void)
+{
+ SDL_PauseAudio(1);
+ audio_playing=0;
+}
+
+int audiostream_pos(void)
+{
+ int pos;
+
+ pos = (int) (((double)(audio_pos-U.mixbufsize)
+ / ( G.scene->audio.mixrate*4 ))
+ * FPS );
+
+ if (pos < audio_startframe) pos = audio_startframe;
+ return ( pos );
+}
+
diff --git a/source/blender/src/seqeffects.c b/source/blender/src/seqeffects.c
new file mode 100644
index 00000000000..5b89bd3ee44
--- /dev/null
+++ b/source/blender/src/seqeffects.c
@@ -0,0 +1,3029 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Peter Schlaile <peter [at] schlaile [dot] de> 2005/2006
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <string.h>
+#include <math.h>
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+#include "PIL_dynlib.h"
+
+#include "DNA_sequence_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "BIF_interface.h"
+#include "BIF_toolbox.h"
+
+#include "BSE_seqeffects.h"
+#include "BSE_sequence.h"
+
+#include "BKE_global.h"
+#include "BKE_ipo.h"
+#include "BKE_plugin_types.h"
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "RE_pipeline.h" // talks to entire render API
+
+#include "blendef.h"
+
+/* Glow effect */
+enum {
+ GlowR=0,
+ GlowG=1,
+ GlowB=2,
+ GlowA=3
+};
+
+
+/* **********************************************************************
+ PLUGINS
+ ********************************************************************** */
+
+static void open_plugin_seq(PluginSeq *pis, const char *seqname)
+{
+ int (*version)();
+ void* (*alloc_private)();
+ char *cp;
+
+ /* to be sure: (is tested for) */
+ pis->doit= 0;
+ pis->pname= 0;
+ pis->varstr= 0;
+ pis->cfra= 0;
+ pis->version= 0;
+ pis->instance_private_data = 0;
+
+ /* clear the error list */
+ PIL_dynlib_get_error_as_string(NULL);
+
+ /* if(pis->handle) PIL_dynlib_close(pis->handle); */
+ /* pis->handle= 0; */
+
+ /* open the needed object */
+ pis->handle= PIL_dynlib_open(pis->name);
+ if(test_dlerr(pis->name, pis->name)) return;
+
+ if (pis->handle != 0) {
+ /* find the address of the version function */
+ version= (int (*)())PIL_dynlib_find_symbol(pis->handle, "plugin_seq_getversion");
+ if (test_dlerr(pis->name, "plugin_seq_getversion")) return;
+
+ if (version != 0) {
+ pis->version= version();
+ if (pis->version >= 2 && pis->version <= 5) {
+ int (*info_func)(PluginInfo *);
+ PluginInfo *info= (PluginInfo*) MEM_mallocN(sizeof(PluginInfo), "plugin_info");
+
+ info_func= (int (*)(PluginInfo *))PIL_dynlib_find_symbol(pis->handle, "plugin_getinfo");
+
+ if(info_func == NULL) error("No info func");
+ else {
+ info_func(info);
+
+ pis->pname= info->name;
+ pis->vars= info->nvars;
+ pis->cfra= info->cfra;
+
+ pis->varstr= info->varstr;
+
+ pis->doit= (void(*)(void))info->seq_doit;
+ if (info->init)
+ info->init();
+ }
+ MEM_freeN(info);
+
+ cp= PIL_dynlib_find_symbol(pis->handle, "seqname");
+ if(cp) strncpy(cp, seqname, 21);
+ } else {
+ printf ("Plugin returned unrecognized version number\n");
+ return;
+ }
+ }
+ alloc_private = (void* (*)())PIL_dynlib_find_symbol(
+ pis->handle, "plugin_seq_alloc_private_data");
+ if (alloc_private) {
+ pis->instance_private_data = alloc_private();
+ }
+
+ pis->current_private_data = (void**)
+ PIL_dynlib_find_symbol(
+ pis->handle, "plugin_private_data");
+ }
+}
+
+static PluginSeq *add_plugin_seq(const char *str, const char *seqname)
+{
+ PluginSeq *pis;
+ VarStruct *varstr;
+ int a;
+
+ pis= MEM_callocN(sizeof(PluginSeq), "PluginSeq");
+
+ strncpy(pis->name, str, FILE_MAXDIR+FILE_MAXFILE);
+ open_plugin_seq(pis, seqname);
+
+ if(pis->doit==0) {
+ if(pis->handle==0) error("no plugin: %s", str);
+ else error("in plugin: %s", str);
+ MEM_freeN(pis);
+ return 0;
+ }
+
+ /* default values */
+ varstr= pis->varstr;
+ for(a=0; a<pis->vars; a++, varstr++) {
+ if( (varstr->type & FLO)==FLO)
+ pis->data[a]= varstr->def;
+ else if( (varstr->type & INT)==INT)
+ *((int *)(pis->data+a))= (int) varstr->def;
+ }
+
+ return pis;
+}
+
+static void free_plugin_seq(PluginSeq *pis)
+{
+ if(pis==0) return;
+
+ /* no PIL_dynlib_close: same plugin can be opened multiple times with 1 handle */
+
+ if (pis->instance_private_data) {
+ void (*free_private)(void *);
+
+ free_private = (void (*)(void *))PIL_dynlib_find_symbol(
+ pis->handle, "plugin_seq_free_private_data");
+ if (free_private) {
+ free_private(pis->instance_private_data);
+ }
+ }
+
+ MEM_freeN(pis);
+}
+
+static void init_plugin(Sequence * seq, const char * fname)
+{
+ seq->plugin= (PluginSeq *)add_plugin_seq(fname, seq->name+2);
+}
+
+/*
+ * FIXME: should query plugin! Could be generator, that needs zero inputs...
+ */
+static int num_inputs_plugin()
+{
+ return 1;
+}
+
+static void load_plugin(Sequence * seq)
+{
+ if (seq) {
+ open_plugin_seq(seq->plugin, seq->name+2);
+ }
+}
+
+static void copy_plugin(Sequence * dst, Sequence * src)
+{
+ if(src->plugin) {
+ dst->plugin= MEM_dupallocN(src->plugin);
+ open_plugin_seq(dst->plugin, dst->name+2);
+ }
+}
+
+static ImBuf * IMB_cast_away_list(ImBuf * i)
+{
+ if (!i) {
+ return 0;
+ }
+ return (ImBuf*) (((void**) i) + 2);
+}
+
+static void do_plugin_effect(Sequence * seq,int cfra,
+ float facf0, float facf1, int x, int y,
+ struct ImBuf *ibuf1, struct ImBuf *ibuf2,
+ struct ImBuf *ibuf3, struct ImBuf *out)
+{
+ char *cp;
+ int float_rendering;
+ int use_temp_bufs = 0; /* Are needed since blur.c (and maybe some other
+ old plugins) do very bad stuff
+ with imbuf-internals */
+
+ if(seq->plugin && seq->plugin->doit) {
+ if(seq->plugin->cfra)
+ *(seq->plugin->cfra)= frame_to_float(cfra);
+
+ cp = PIL_dynlib_find_symbol(
+ seq->plugin->handle, "seqname");
+
+ if(cp) strncpy(cp, seq->name+2, 22);
+
+ if (seq->plugin->current_private_data) {
+ *seq->plugin->current_private_data
+ = seq->plugin->instance_private_data;
+ }
+
+ float_rendering = (out->rect_float != NULL);
+
+ if (seq->plugin->version<=3 && float_rendering) {
+ use_temp_bufs = 1;
+
+ if (ibuf1) {
+ ibuf1 = IMB_dupImBuf(ibuf1);
+ IMB_rect_from_float(ibuf1);
+ imb_freerectfloatImBuf(ibuf1);
+ ibuf1->flags &= ~IB_rectfloat;
+ }
+ if (ibuf2) {
+ ibuf2 = IMB_dupImBuf(ibuf2);
+ IMB_rect_from_float(ibuf2);
+ imb_freerectfloatImBuf(ibuf2);
+ ibuf2->flags &= ~IB_rectfloat;
+ }
+ if (ibuf3) {
+ ibuf3 = IMB_dupImBuf(ibuf3);
+ IMB_rect_from_float(ibuf3);
+ imb_freerectfloatImBuf(ibuf3);
+ ibuf3->flags &= ~IB_rectfloat;
+ }
+ if (!out->rect) imb_addrectImBuf(out);
+ imb_freerectfloatImBuf(out);
+ out->flags &= ~IB_rectfloat;
+ }
+
+ if (seq->plugin->version<=2) {
+ if(ibuf1) IMB_convert_rgba_to_abgr(ibuf1);
+ if(ibuf2) IMB_convert_rgba_to_abgr(ibuf2);
+ if(ibuf3) IMB_convert_rgba_to_abgr(ibuf3);
+ }
+
+ if (seq->plugin->version<=4) {
+ ((SeqDoit)seq->plugin->doit)(
+ seq->plugin->data, facf0, facf1, x, y,
+ IMB_cast_away_list(ibuf1),
+ IMB_cast_away_list(ibuf2),
+ IMB_cast_away_list(out),
+ IMB_cast_away_list(ibuf3));
+ } else {
+ ((SeqDoit)seq->plugin->doit)(
+ seq->plugin->data, facf0, facf1, x, y,
+ ibuf1, ibuf2, out, ibuf3);
+ }
+
+ if (seq->plugin->version<=2) {
+ if (!use_temp_bufs) {
+ if(ibuf1) IMB_convert_rgba_to_abgr(ibuf1);
+ if(ibuf2) IMB_convert_rgba_to_abgr(ibuf2);
+ if(ibuf3) IMB_convert_rgba_to_abgr(ibuf3);
+ }
+ IMB_convert_rgba_to_abgr(out);
+ }
+ if (seq->plugin->version<=3 && float_rendering) {
+ IMB_float_from_rect(out);
+ }
+
+ if (use_temp_bufs) {
+ if (ibuf1) IMB_freeImBuf(ibuf1);
+ if (ibuf2) IMB_freeImBuf(ibuf2);
+ if (ibuf3) IMB_freeImBuf(ibuf3);
+ }
+ }
+}
+
+static int do_plugin_early_out(struct Sequence *seq,
+ float facf0, float facf1)
+{
+ return 0;
+}
+
+static void free_plugin(struct Sequence * seq)
+{
+ free_plugin_seq(seq->plugin);
+ seq->plugin = 0;
+}
+
+/* **********************************************************************
+ ALPHA OVER
+ ********************************************************************** */
+
+static void init_alpha_over_or_under(Sequence * seq)
+{
+ Sequence * seq1 = seq->seq1;
+ Sequence * seq2 = seq->seq2;
+
+ seq->seq2= seq1;
+ seq->seq1= seq2;
+}
+
+static void do_alphaover_effect_byte(float facf0, float facf1, int x, int y,
+ char * rect1, char *rect2, char *out)
+{
+ int fac2, mfac, fac, fac4;
+ int xo, tempc;
+ char *rt1, *rt2, *rt;
+
+ xo= x;
+ rt1= (char *)rect1;
+ rt2= (char *)rect2;
+ rt= (char *)out;
+
+ fac2= (int)(256.0*facf0);
+ fac4= (int)(256.0*facf1);
+
+ while(y--) {
+
+ x= xo;
+ while(x--) {
+
+ /* rt = rt1 over rt2 (alpha from rt1) */
+
+ fac= fac2;
+ mfac= 256 - ( (fac2*rt1[3])>>8 );
+
+ if(fac==0) *( (unsigned int *)rt) = *( (unsigned int *)rt2);
+ else if(mfac==0) *( (unsigned int *)rt) = *( (unsigned int *)rt1);
+ else {
+ tempc= ( fac*rt1[0] + mfac*rt2[0])>>8;
+ if(tempc>255) rt[0]= 255; else rt[0]= tempc;
+ tempc= ( fac*rt1[1] + mfac*rt2[1])>>8;
+ if(tempc>255) rt[1]= 255; else rt[1]= tempc;
+ tempc= ( fac*rt1[2] + mfac*rt2[2])>>8;
+ if(tempc>255) rt[2]= 255; else rt[2]= tempc;
+ tempc= ( fac*rt1[3] + mfac*rt2[3])>>8;
+ if(tempc>255) rt[3]= 255; else rt[3]= tempc;
+ }
+ rt1+= 4; rt2+= 4; rt+= 4;
+ }
+
+ if(y==0) break;
+ y--;
+
+ x= xo;
+ while(x--) {
+
+ fac= fac4;
+ mfac= 256 - ( (fac4*rt1[3])>>8 );
+
+ if(fac==0) *( (unsigned int *)rt) = *( (unsigned int *)rt2);
+ else if(mfac==0) *( (unsigned int *)rt) = *( (unsigned int *)rt1);
+ else {
+ tempc= ( fac*rt1[0] + mfac*rt2[0])>>8;
+ if(tempc>255) rt[0]= 255; else rt[0]= tempc;
+ tempc= ( fac*rt1[1] + mfac*rt2[1])>>8;
+ if(tempc>255) rt[1]= 255; else rt[1]= tempc;
+ tempc= ( fac*rt1[2] + mfac*rt2[2])>>8;
+ if(tempc>255) rt[2]= 255; else rt[2]= tempc;
+ tempc= ( fac*rt1[3] + mfac*rt2[3])>>8;
+ if(tempc>255) rt[3]= 255; else rt[3]= tempc;
+ }
+ rt1+= 4; rt2+= 4; rt+= 4;
+ }
+ }
+}
+
+static void do_alphaover_effect_float(float facf0, float facf1, int x, int y,
+ float * rect1, float *rect2, float *out)
+{
+ float fac2, mfac, fac, fac4;
+ int xo;
+ float *rt1, *rt2, *rt;
+
+ xo= x;
+ rt1= rect1;
+ rt2= rect2;
+ rt= out;
+
+ fac2= facf0;
+ fac4= facf1;
+
+ while(y--) {
+
+ x= xo;
+ while(x--) {
+
+ /* rt = rt1 over rt2 (alpha from rt1) */
+
+ fac= fac2;
+ mfac= 1.0 - (fac2*rt1[3]) ;
+
+ if(fac <= 0.0) {
+ memcpy(rt, rt2, 4 * sizeof(float));
+ } else if(mfac <=0) {
+ memcpy(rt, rt1, 4 * sizeof(float));
+ } else {
+ rt[0] = fac*rt1[0] + mfac*rt2[0];
+ rt[1] = fac*rt1[1] + mfac*rt2[1];
+ rt[2] = fac*rt1[2] + mfac*rt2[2];
+ rt[3] = fac*rt1[3] + mfac*rt2[3];
+ }
+ rt1+= 4; rt2+= 4; rt+= 4;
+ }
+
+ if(y==0) break;
+ y--;
+
+ x= xo;
+ while(x--) {
+
+ fac= fac4;
+ mfac= 1.0 - (fac4*rt1[3]);
+
+ if(fac <= 0.0) {
+ memcpy(rt, rt2, 4 * sizeof(float));
+ } else if(mfac <= 0.0) {
+ memcpy(rt, rt1, 4 * sizeof(float));
+ } else {
+ rt[0] = fac*rt1[0] + mfac*rt2[0];
+ rt[1] = fac*rt1[1] + mfac*rt2[1];
+ rt[2] = fac*rt1[2] + mfac*rt2[2];
+ rt[3] = fac*rt1[3] + mfac*rt2[3];
+ }
+ rt1+= 4; rt2+= 4; rt+= 4;
+ }
+ }
+}
+
+static void do_alphaover_effect(Sequence * seq,int cfra,
+ float facf0, float facf1, int x, int y,
+ struct ImBuf *ibuf1, struct ImBuf *ibuf2,
+ struct ImBuf *ibuf3, struct ImBuf *out)
+{
+ if (out->rect_float) {
+ do_alphaover_effect_float(
+ facf0, facf1, x, y,
+ ibuf1->rect_float, ibuf2->rect_float,
+ out->rect_float);
+ } else {
+ do_alphaover_effect_byte(
+ facf0, facf1, x, y,
+ (char*) ibuf1->rect, (char*) ibuf2->rect,
+ (char*) out->rect);
+ }
+}
+
+
+/* **********************************************************************
+ ALPHA UNDER
+ ********************************************************************** */
+
+void do_alphaunder_effect_byte(
+ float facf0, float facf1, int x, int y, char *rect1,
+ char *rect2, char *out)
+{
+ int fac2, mfac, fac, fac4;
+ int xo;
+ char *rt1, *rt2, *rt;
+
+ xo= x;
+ rt1= rect1;
+ rt2= rect2;
+ rt= out;
+
+ fac2= (int)(256.0*facf0);
+ fac4= (int)(256.0*facf1);
+
+ while(y--) {
+
+ x= xo;
+ while(x--) {
+
+ /* rt = rt1 under rt2 (alpha from rt2) */
+
+ /* this complex optimalisation is because the
+ * 'skybuf' can be crossed in
+ */
+ if(rt2[3]==0 && fac2==256) *( (unsigned int *)rt) = *( (unsigned int *)rt1);
+ else if(rt2[3]==255) *( (unsigned int *)rt) = *( (unsigned int *)rt2);
+ else {
+ mfac= rt2[3];
+ fac= (fac2*(256-mfac))>>8;
+
+ if(fac==0) *( (unsigned int *)rt) = *( (unsigned int *)rt2);
+ else {
+ rt[0]= ( fac*rt1[0] + mfac*rt2[0])>>8;
+ rt[1]= ( fac*rt1[1] + mfac*rt2[1])>>8;
+ rt[2]= ( fac*rt1[2] + mfac*rt2[2])>>8;
+ rt[3]= ( fac*rt1[3] + mfac*rt2[3])>>8;
+ }
+ }
+ rt1+= 4; rt2+= 4; rt+= 4;
+ }
+
+ if(y==0) break;
+ y--;
+
+ x= xo;
+ while(x--) {
+
+ if(rt2[3]==0 && fac4==256) *( (unsigned int *)rt) = *( (unsigned int *)rt1);
+ else if(rt2[3]==255) *( (unsigned int *)rt) = *( (unsigned int *)rt2);
+ else {
+ mfac= rt2[3];
+ fac= (fac4*(256-mfac))>>8;
+
+ if(fac==0) *( (unsigned int *)rt) = *( (unsigned int *)rt2);
+ else {
+ rt[0]= ( fac*rt1[0] + mfac*rt2[0])>>8;
+ rt[1]= ( fac*rt1[1] + mfac*rt2[1])>>8;
+ rt[2]= ( fac*rt1[2] + mfac*rt2[2])>>8;
+ rt[3]= ( fac*rt1[3] + mfac*rt2[3])>>8;
+ }
+ }
+ rt1+= 4; rt2+= 4; rt+= 4;
+ }
+ }
+}
+
+
+static void do_alphaunder_effect_float(float facf0, float facf1, int x, int y,
+ float *rect1, float *rect2,
+ float *out)
+{
+ float fac2, mfac, fac, fac4;
+ int xo;
+ float *rt1, *rt2, *rt;
+
+ xo= x;
+ rt1= rect1;
+ rt2= rect2;
+ rt= out;
+
+ fac2= facf0;
+ fac4= facf1;
+
+ while(y--) {
+
+ x= xo;
+ while(x--) {
+
+ /* rt = rt1 under rt2 (alpha from rt2) */
+
+ /* this complex optimalisation is because the
+ * 'skybuf' can be crossed in
+ */
+ if( rt2[3]<=0 && fac2>=1.0) {
+ memcpy(rt, rt1, 4 * sizeof(float));
+ } else if(rt2[3]>=1.0) {
+ memcpy(rt, rt2, 4 * sizeof(float));
+ } else {
+ mfac = rt2[3];
+ fac = fac2 * (1.0 - mfac);
+
+ if(fac == 0) {
+ memcpy(rt, rt2, 4 * sizeof(float));
+ } else {
+ rt[0]= fac*rt1[0] + mfac*rt2[0];
+ rt[1]= fac*rt1[1] + mfac*rt2[1];
+ rt[2]= fac*rt1[2] + mfac*rt2[2];
+ rt[3]= fac*rt1[3] + mfac*rt2[3];
+ }
+ }
+ rt1+= 4; rt2+= 4; rt+= 4;
+ }
+
+ if(y==0) break;
+ y--;
+
+ x= xo;
+ while(x--) {
+
+ if(rt2[3]<=0 && fac4 >= 1.0) {
+ memcpy(rt, rt1, 4 * sizeof(float));
+
+ } else if(rt2[3]>=1.0) {
+ memcpy(rt, rt2, 4 * sizeof(float));
+ } else {
+ mfac= rt2[3];
+ fac= fac4*(1.0-mfac);
+
+ if(fac == 0) {
+ memcpy(rt, rt2, 4 * sizeof(float));
+ } else {
+ rt[0]= fac * rt1[0] + mfac * rt2[0];
+ rt[1]= fac * rt1[1] + mfac * rt2[1];
+ rt[2]= fac * rt1[2] + mfac * rt2[2];
+ rt[3]= fac * rt1[3] + mfac * rt2[3];
+ }
+ }
+ rt1+= 4; rt2+= 4; rt+= 4;
+ }
+ }
+}
+
+static void do_alphaunder_effect(Sequence * seq,int cfra,
+ float facf0, float facf1, int x, int y,
+ struct ImBuf *ibuf1, struct ImBuf *ibuf2,
+ struct ImBuf *ibuf3, struct ImBuf *out)
+{
+ if (out->rect_float) {
+ do_alphaunder_effect_float(
+ facf0, facf1, x, y,
+ ibuf1->rect_float, ibuf2->rect_float,
+ out->rect_float);
+ } else {
+ do_alphaunder_effect_byte(
+ facf0, facf1, x, y,
+ (char*) ibuf1->rect, (char*) ibuf2->rect,
+ (char*) out->rect);
+ }
+}
+
+
+/* **********************************************************************
+ CROSS
+ ********************************************************************** */
+
+void do_cross_effect_byte(float facf0, float facf1, int x, int y,
+ char *rect1, char *rect2,
+ char *out)
+{
+ int fac1, fac2, fac3, fac4;
+ int xo;
+ char *rt1, *rt2, *rt;
+
+ xo= x;
+ rt1= rect1;
+ rt2= rect2;
+ rt= out;
+
+ fac2= (int)(256.0*facf0);
+ fac1= 256-fac2;
+ fac4= (int)(256.0*facf1);
+ fac3= 256-fac4;
+
+ while(y--) {
+
+ x= xo;
+ while(x--) {
+
+ rt[0]= (fac1*rt1[0] + fac2*rt2[0])>>8;
+ rt[1]= (fac1*rt1[1] + fac2*rt2[1])>>8;
+ rt[2]= (fac1*rt1[2] + fac2*rt2[2])>>8;
+ rt[3]= (fac1*rt1[3] + fac2*rt2[3])>>8;
+
+ rt1+= 4; rt2+= 4; rt+= 4;
+ }
+
+ if(y==0) break;
+ y--;
+
+ x= xo;
+ while(x--) {
+
+ rt[0]= (fac3*rt1[0] + fac4*rt2[0])>>8;
+ rt[1]= (fac3*rt1[1] + fac4*rt2[1])>>8;
+ rt[2]= (fac3*rt1[2] + fac4*rt2[2])>>8;
+ rt[3]= (fac3*rt1[3] + fac4*rt2[3])>>8;
+
+ rt1+= 4; rt2+= 4; rt+= 4;
+ }
+
+ }
+}
+
+void do_cross_effect_float(float facf0, float facf1, int x, int y,
+ float *rect1, float *rect2, float *out)
+{
+ float fac1, fac2, fac3, fac4;
+ int xo;
+ float *rt1, *rt2, *rt;
+
+ xo= x;
+ rt1= rect1;
+ rt2= rect2;
+ rt= out;
+
+ fac2= facf0;
+ fac1= 1.0 - fac2;
+ fac4= facf1;
+ fac3= 1.0 - fac4;
+
+ while(y--) {
+
+ x= xo;
+ while(x--) {
+
+ rt[0]= fac1*rt1[0] + fac2*rt2[0];
+ rt[1]= fac1*rt1[1] + fac2*rt2[1];
+ rt[2]= fac1*rt1[2] + fac2*rt2[2];
+ rt[3]= fac1*rt1[3] + fac2*rt2[3];
+
+ rt1+= 4; rt2+= 4; rt+= 4;
+ }
+
+ if(y==0) break;
+ y--;
+
+ x= xo;
+ while(x--) {
+
+ rt[0]= fac3*rt1[0] + fac4*rt2[0];
+ rt[1]= fac3*rt1[1] + fac4*rt2[1];
+ rt[2]= fac3*rt1[2] + fac4*rt2[2];
+ rt[3]= fac3*rt1[3] + fac4*rt2[3];
+
+ rt1+= 4; rt2+= 4; rt+= 4;
+ }
+
+ }
+}
+
+/* carefull: also used by speed effect! */
+
+static void do_cross_effect(Sequence * seq,int cfra,
+ float facf0, float facf1, int x, int y,
+ struct ImBuf *ibuf1, struct ImBuf *ibuf2,
+ struct ImBuf *ibuf3, struct ImBuf *out)
+{
+ if (out->rect_float) {
+ do_cross_effect_float(
+ facf0, facf1, x, y,
+ ibuf1->rect_float, ibuf2->rect_float,
+ out->rect_float);
+ } else {
+ do_cross_effect_byte(
+ facf0, facf1, x, y,
+ (char*) ibuf1->rect, (char*) ibuf2->rect,
+ (char*) out->rect);
+ }
+}
+
+
+/* **********************************************************************
+ GAMMA CROSS
+ ********************************************************************** */
+
+/* copied code from initrender.c */
+static unsigned short *gamtab = 0;
+static unsigned short *igamtab1 = 0;
+static int gamma_tabs_refcount = 0;
+
+#define RE_GAMMA_TABLE_SIZE 400
+
+static float gamma_range_table[RE_GAMMA_TABLE_SIZE + 1];
+static float gamfactor_table[RE_GAMMA_TABLE_SIZE];
+static float inv_gamma_range_table[RE_GAMMA_TABLE_SIZE + 1];
+static float inv_gamfactor_table[RE_GAMMA_TABLE_SIZE];
+static float color_domain_table[RE_GAMMA_TABLE_SIZE + 1];
+static float color_step;
+static float inv_color_step;
+static float valid_gamma;
+static float valid_inv_gamma;
+
+static void makeGammaTables(float gamma)
+{
+ /* we need two tables: one forward, one backward */
+ int i;
+
+ valid_gamma = gamma;
+ valid_inv_gamma = 1.0 / gamma;
+ color_step = 1.0 / RE_GAMMA_TABLE_SIZE;
+ inv_color_step = (float) RE_GAMMA_TABLE_SIZE;
+
+ /* We could squeeze out the two range tables to gain some memory. */
+ for (i = 0; i < RE_GAMMA_TABLE_SIZE; i++) {
+ color_domain_table[i] = i * color_step;
+ gamma_range_table[i] = pow(color_domain_table[i],
+ valid_gamma);
+ inv_gamma_range_table[i] = pow(color_domain_table[i],
+ valid_inv_gamma);
+ }
+
+ /* The end of the table should match 1.0 carefully. In order to avoid */
+ /* rounding errors, we just set this explicitly. The last segment may */
+ /* have a different lenght than the other segments, but our */
+ /* interpolation is insensitive to that. */
+ color_domain_table[RE_GAMMA_TABLE_SIZE] = 1.0;
+ gamma_range_table[RE_GAMMA_TABLE_SIZE] = 1.0;
+ inv_gamma_range_table[RE_GAMMA_TABLE_SIZE] = 1.0;
+
+ /* To speed up calculations, we make these calc factor tables. They are */
+ /* multiplication factors used in scaling the interpolation. */
+ for (i = 0; i < RE_GAMMA_TABLE_SIZE; i++ ) {
+ gamfactor_table[i] = inv_color_step
+ * (gamma_range_table[i + 1] - gamma_range_table[i]) ;
+ inv_gamfactor_table[i] = inv_color_step
+ * (inv_gamma_range_table[i + 1] - inv_gamma_range_table[i]) ;
+ }
+
+} /* end of void makeGammaTables(float gamma) */
+
+
+static float gammaCorrect(float c)
+{
+ int i;
+ float res = 0.0;
+
+ i = floor(c * inv_color_step);
+ /* Clip to range [0,1]: outside, just do the complete calculation. */
+ /* We may have some performance problems here. Stretching up the LUT */
+ /* may help solve that, by exchanging LUT size for the interpolation. */
+ /* Negative colors are explicitly handled. */
+ if (i < 0) res = -pow(abs(c), valid_gamma);
+ else if (i >= RE_GAMMA_TABLE_SIZE ) res = pow(c, valid_gamma);
+ else res = gamma_range_table[i] +
+ ( (c - color_domain_table[i]) * gamfactor_table[i]);
+
+ return res;
+} /* end of float gammaCorrect(float col) */
+
+/* ------------------------------------------------------------------------- */
+
+static float invGammaCorrect(float col)
+{
+ int i;
+ float res = 0.0;
+
+ i = floor(col*inv_color_step);
+ /* Negative colors are explicitly handled. */
+ if (i < 0) res = -pow(abs(col), valid_inv_gamma);
+ else if (i >= RE_GAMMA_TABLE_SIZE) res = pow(col, valid_inv_gamma);
+ else res = inv_gamma_range_table[i] +
+ ( (col - color_domain_table[i]) * inv_gamfactor_table[i]);
+
+ return res;
+} /* end of float invGammaCorrect(float col) */
+
+
+static void gamtabs(float gamma)
+{
+ float val, igamma= 1.0f/gamma;
+ int a;
+
+ gamtab= MEM_mallocN(65536*sizeof(short), "initGaus2");
+ igamtab1= MEM_mallocN(256*sizeof(short), "initGaus2");
+
+ /* gamtab: in short, out short */
+ for(a=0; a<65536; a++) {
+ val= a;
+ val/= 65535.0;
+
+ if(gamma==2.0) val= sqrt(val);
+ else if(gamma!=1.0) val= pow(val, igamma);
+
+ gamtab[a]= (65535.99*val);
+ }
+ /* inverse gamtab1 : in byte, out short */
+ for(a=1; a<=256; a++) {
+ if(gamma==2.0) igamtab1[a-1]= a*a-1;
+ else if(gamma==1.0) igamtab1[a-1]= 256*a-1;
+ else {
+ val= a/256.0;
+ igamtab1[a-1]= (65535.0*pow(val, gamma)) -1 ;
+ }
+ }
+
+}
+
+static void alloc_or_ref_gammatabs()
+{
+ if (gamma_tabs_refcount == 0) {
+ gamtabs(2.0f);
+ makeGammaTables(2.0f);
+ }
+ gamma_tabs_refcount++;
+}
+
+static void init_gammacross(Sequence * seq)
+{
+ alloc_or_ref_gammatabs();
+}
+
+static void load_gammacross(Sequence * seq)
+{
+ alloc_or_ref_gammatabs();
+}
+
+static void free_gammacross(Sequence * seq)
+{
+ if (--gamma_tabs_refcount == 0) {
+ MEM_freeN(gamtab);
+ MEM_freeN(igamtab1);
+ gamtab = 0;
+ igamtab1 = 0;
+ }
+ if (gamma_tabs_refcount < 0) {
+ fprintf(stderr, "seqeffects: free_gammacross double free!\n");
+ }
+}
+
+static void do_gammacross_effect_byte(float facf0, float facf1,
+ int x, int y,
+ char *rect1,
+ char *rect2,
+ char *out)
+{
+ int fac1, fac2, col;
+ int xo;
+ char *rt1, *rt2, *rt;
+
+ xo= x;
+ rt1= (char *)rect1;
+ rt2= (char *)rect2;
+ rt= (char *)out;
+
+ fac2= (int)(256.0*facf0);
+ fac1= 256-fac2;
+
+ while(y--) {
+
+ x= xo;
+ while(x--) {
+
+ col= (fac1*igamtab1[rt1[0]] + fac2*igamtab1[rt2[0]])>>8;
+ if(col>65535) rt[0]= 255; else rt[0]= ( (char *)(gamtab+col))[MOST_SIG_BYTE];
+ col=(fac1*igamtab1[rt1[1]] + fac2*igamtab1[rt2[1]])>>8;
+ if(col>65535) rt[1]= 255; else rt[1]= ( (char *)(gamtab+col))[MOST_SIG_BYTE];
+ col= (fac1*igamtab1[rt1[2]] + fac2*igamtab1[rt2[2]])>>8;
+ if(col>65535) rt[2]= 255; else rt[2]= ( (char *)(gamtab+col))[MOST_SIG_BYTE];
+ col= (fac1*igamtab1[rt1[3]] + fac2*igamtab1[rt2[3]])>>8;
+ if(col>65535) rt[3]= 255; else rt[3]= ( (char *)(gamtab+col))[MOST_SIG_BYTE];
+
+ rt1+= 4; rt2+= 4; rt+= 4;
+ }
+
+ if(y==0) break;
+ y--;
+
+ x= xo;
+ while(x--) {
+
+ col= (fac1*igamtab1[rt1[0]] + fac2*igamtab1[rt2[0]])>>8;
+ if(col>65535) rt[0]= 255; else rt[0]= ( (char *)(gamtab+col))[MOST_SIG_BYTE];
+ col= (fac1*igamtab1[rt1[1]] + fac2*igamtab1[rt2[1]])>>8;
+ if(col>65535) rt[1]= 255; else rt[1]= ( (char *)(gamtab+col))[MOST_SIG_BYTE];
+ col= (fac1*igamtab1[rt1[2]] + fac2*igamtab1[rt2[2]])>>8;
+ if(col>65535) rt[2]= 255; else rt[2]= ( (char *)(gamtab+col))[MOST_SIG_BYTE];
+ col= (fac1*igamtab1[rt1[3]] + fac2*igamtab1[rt2[3]])>>8;
+ if(col>65535) rt[3]= 255; else rt[3]= ( (char *)(gamtab+col))[MOST_SIG_BYTE];
+
+ rt1+= 4; rt2+= 4; rt+= 4;
+ }
+ }
+
+}
+
+static void do_gammacross_effect_float(float facf0, float facf1,
+ int x, int y,
+ float *rect1, float *rect2,
+ float *out)
+{
+ float fac1, fac2, col;
+ int xo;
+ float *rt1, *rt2, *rt;
+
+ xo= x;
+ rt1= rect1;
+ rt2= rect2;
+ rt= out;
+
+ fac2= facf0;
+ fac1= 1.0 - fac2;
+
+ while(y--) {
+
+ x= xo * 4;
+ while(x--) {
+
+ *rt= gammaCorrect(
+ fac1 * invGammaCorrect(*rt1)
+ + fac2 * invGammaCorrect(*rt2));
+ rt1++; rt2++; rt++;
+ }
+
+ if(y==0) break;
+ y--;
+
+ x= xo * 4;
+ while(x--) {
+
+ col= gammaCorrect(
+ fac1*invGammaCorrect(*rt1)
+ + fac2*invGammaCorrect(*rt2));
+
+ rt1++; rt2++; rt++;
+ }
+ }
+}
+
+static void do_gammacross_effect(Sequence * seq,int cfra,
+ float facf0, float facf1, int x, int y,
+ struct ImBuf *ibuf1, struct ImBuf *ibuf2,
+ struct ImBuf *ibuf3, struct ImBuf *out)
+{
+ if (out->rect_float) {
+ do_gammacross_effect_float(
+ facf0, facf1, x, y,
+ ibuf1->rect_float, ibuf2->rect_float,
+ out->rect_float);
+ } else {
+ do_gammacross_effect_byte(
+ facf0, facf1, x, y,
+ (char*) ibuf1->rect, (char*) ibuf2->rect,
+ (char*) out->rect);
+ }
+}
+
+
+/* **********************************************************************
+ ADD
+ ********************************************************************** */
+
+static void do_add_effect_byte(float facf0, float facf1, int x, int y,
+ unsigned char *rect1, unsigned char *rect2,
+ unsigned char *out)
+{
+ int col, xo, fac1, fac3;
+ char *rt1, *rt2, *rt;
+
+ xo= x;
+ rt1= (char *)rect1;
+ rt2= (char *)rect2;
+ rt= (char *)out;
+
+ fac1= (int)(256.0*facf0);
+ fac3= (int)(256.0*facf1);
+
+ while(y--) {
+
+ x= xo;
+ while(x--) {
+
+ col= rt1[0]+ ((fac1*rt2[0])>>8);
+ if(col>255) rt[0]= 255; else rt[0]= col;
+ col= rt1[1]+ ((fac1*rt2[1])>>8);
+ if(col>255) rt[1]= 255; else rt[1]= col;
+ col= rt1[2]+ ((fac1*rt2[2])>>8);
+ if(col>255) rt[2]= 255; else rt[2]= col;
+ col= rt1[3]+ ((fac1*rt2[3])>>8);
+ if(col>255) rt[3]= 255; else rt[3]= col;
+
+ rt1+= 4; rt2+= 4; rt+= 4;
+ }
+
+ if(y==0) break;
+ y--;
+
+ x= xo;
+ while(x--) {
+
+ col= rt1[0]+ ((fac3*rt2[0])>>8);
+ if(col>255) rt[0]= 255; else rt[0]= col;
+ col= rt1[1]+ ((fac3*rt2[1])>>8);
+ if(col>255) rt[1]= 255; else rt[1]= col;
+ col= rt1[2]+ ((fac3*rt2[2])>>8);
+ if(col>255) rt[2]= 255; else rt[2]= col;
+ col= rt1[3]+ ((fac3*rt2[3])>>8);
+ if(col>255) rt[3]= 255; else rt[3]= col;
+
+ rt1+= 4; rt2+= 4; rt+= 4;
+ }
+ }
+}
+
+static void do_add_effect_float(float facf0, float facf1, int x, int y,
+ float *rect1, float *rect2,
+ float *out)
+{
+ int xo;
+ float fac1, fac3;
+ float *rt1, *rt2, *rt;
+
+ xo= x;
+ rt1= rect1;
+ rt2= rect2;
+ rt= out;
+
+ fac1= facf0;
+ fac3= facf1;
+
+ while(y--) {
+
+ x= xo * 4;
+ while(x--) {
+ *rt = *rt1 + fac1 * (*rt2);
+
+ rt1++; rt2++; rt++;
+ }
+
+ if(y==0) break;
+ y--;
+
+ x= xo * 4;
+ while(x--) {
+ *rt = *rt1 + fac3 * (*rt2);
+
+ rt1++; rt2++; rt++;
+ }
+ }
+}
+
+static void do_add_effect(Sequence * seq,int cfra,
+ float facf0, float facf1, int x, int y,
+ struct ImBuf *ibuf1, struct ImBuf *ibuf2,
+ struct ImBuf *ibuf3, struct ImBuf *out)
+{
+ if (out->rect_float) {
+ do_add_effect_float(
+ facf0, facf1, x, y,
+ ibuf1->rect_float, ibuf2->rect_float,
+ out->rect_float);
+ } else {
+ do_add_effect_byte(
+ facf0, facf1, x, y,
+ (unsigned char*) ibuf1->rect, (unsigned char*) ibuf2->rect,
+ (unsigned char*) out->rect);
+ }
+}
+
+
+/* **********************************************************************
+ SUB
+ ********************************************************************** */
+
+static void do_sub_effect_byte(float facf0, float facf1,
+ int x, int y,
+ char *rect1, char *rect2, char *out)
+{
+ int col, xo, fac1, fac3;
+ char *rt1, *rt2, *rt;
+
+ xo= x;
+ rt1= (char *)rect1;
+ rt2= (char *)rect2;
+ rt= (char *)out;
+
+ fac1= (int)(256.0*facf0);
+ fac3= (int)(256.0*facf1);
+
+ while(y--) {
+
+ x= xo;
+ while(x--) {
+
+ col= rt1[0]- ((fac1*rt2[0])>>8);
+ if(col<0) rt[0]= 0; else rt[0]= col;
+ col= rt1[1]- ((fac1*rt2[1])>>8);
+ if(col<0) rt[1]= 0; else rt[1]= col;
+ col= rt1[2]- ((fac1*rt2[2])>>8);
+ if(col<0) rt[2]= 0; else rt[2]= col;
+ col= rt1[3]- ((fac1*rt2[3])>>8);
+ if(col<0) rt[3]= 0; else rt[3]= col;
+
+ rt1+= 4; rt2+= 4; rt+= 4;
+ }
+
+ if(y==0) break;
+ y--;
+
+ x= xo;
+ while(x--) {
+
+ col= rt1[0]- ((fac3*rt2[0])>>8);
+ if(col<0) rt[0]= 0; else rt[0]= col;
+ col= rt1[1]- ((fac3*rt2[1])>>8);
+ if(col<0) rt[1]= 0; else rt[1]= col;
+ col= rt1[2]- ((fac3*rt2[2])>>8);
+ if(col<0) rt[2]= 0; else rt[2]= col;
+ col= rt1[3]- ((fac3*rt2[3])>>8);
+ if(col<0) rt[3]= 0; else rt[3]= col;
+
+ rt1+= 4; rt2+= 4; rt+= 4;
+ }
+ }
+}
+
+static void do_sub_effect_float(float facf0, float facf1, int x, int y,
+ float *rect1, float *rect2,
+ float *out)
+{
+ int xo;
+ float fac1, fac3;
+ float *rt1, *rt2, *rt;
+
+ xo= x;
+ rt1= rect1;
+ rt2= rect2;
+ rt= out;
+
+ fac1= facf0;
+ fac3= facf1;
+
+ while(y--) {
+
+ x= xo * 4;
+ while(x--) {
+ *rt = *rt1 - fac1 * (*rt2);
+
+ rt1++; rt2++; rt++;
+ }
+
+ if(y==0) break;
+ y--;
+
+ x= xo * 4;
+ while(x--) {
+ *rt = *rt1 - fac3 * (*rt2);
+
+ rt1++; rt2++; rt++;
+ }
+ }
+}
+
+static void do_sub_effect(Sequence * seq,int cfra,
+ float facf0, float facf1, int x, int y,
+ struct ImBuf *ibuf1, struct ImBuf *ibuf2,
+ struct ImBuf *ibuf3, struct ImBuf *out)
+{
+ if (out->rect_float) {
+ do_sub_effect_float(
+ facf0, facf1, x, y,
+ ibuf1->rect_float, ibuf2->rect_float,
+ out->rect_float);
+ } else {
+ do_sub_effect_byte(
+ facf0, facf1, x, y,
+ (char*) ibuf1->rect, (char*) ibuf2->rect,
+ (char*) out->rect);
+ }
+}
+
+/* **********************************************************************
+ DROP
+ ********************************************************************** */
+
+/* Must be > 0 or add precopy, etc to the function */
+#define XOFF 8
+#define YOFF 8
+
+static void do_drop_effect_byte(float facf0, float facf1, int x, int y,
+ unsigned char *rect2i, unsigned char *rect1i,
+ unsigned char *outi)
+{
+ int height, width, temp, fac, fac1, fac2;
+ char *rt1, *rt2, *out;
+ int field= 1;
+
+ width= x;
+ height= y;
+
+ fac1= (int)(70.0*facf0);
+ fac2= (int)(70.0*facf1);
+
+ rt2= (char*) (rect2i + YOFF*width);
+ rt1= (char*) rect1i;
+ out= (char*) outi;
+ for (y=0; y<height-YOFF; y++) {
+ if(field) fac= fac1;
+ else fac= fac2;
+ field= !field;
+
+ memcpy(out, rt1, sizeof(int)*XOFF);
+ rt1+= XOFF*4;
+ out+= XOFF*4;
+
+ for (x=XOFF; x<width; x++) {
+ temp= ((fac*rt2[3])>>8);
+
+ *(out++)= MAX2(0, *rt1 - temp); rt1++;
+ *(out++)= MAX2(0, *rt1 - temp); rt1++;
+ *(out++)= MAX2(0, *rt1 - temp); rt1++;
+ *(out++)= MAX2(0, *rt1 - temp); rt1++;
+ rt2+=4;
+ }
+ rt2+=XOFF*4;
+ }
+ memcpy(out, rt1, sizeof(int)*YOFF*width);
+}
+
+static void do_drop_effect_float(float facf0, float facf1, int x, int y,
+ float *rect2i, float *rect1i,
+ float *outi)
+{
+ int height, width;
+ float temp, fac, fac1, fac2;
+ float *rt1, *rt2, *out;
+ int field= 1;
+
+ width= x;
+ height= y;
+
+ fac1= 70.0*facf0;
+ fac2= 70.0*facf1;
+
+ rt2= (rect2i + YOFF*width);
+ rt1= rect1i;
+ out= outi;
+ for (y=0; y<height-YOFF; y++) {
+ if(field) fac= fac1;
+ else fac= fac2;
+ field= !field;
+
+ memcpy(out, rt1, 4 * sizeof(float)*XOFF);
+ rt1+= XOFF*4;
+ out+= XOFF*4;
+
+ for (x=XOFF; x<width; x++) {
+ temp= fac * rt2[3];
+
+ *(out++)= MAX2(0.0, *rt1 - temp); rt1++;
+ *(out++)= MAX2(0.0, *rt1 - temp); rt1++;
+ *(out++)= MAX2(0.0, *rt1 - temp); rt1++;
+ *(out++)= MAX2(0.0, *rt1 - temp); rt1++;
+ rt2+=4;
+ }
+ rt2+=XOFF*4;
+ }
+ memcpy(out, rt1, 4 * sizeof(float)*YOFF*width);
+}
+
+
+static void do_drop_effect(Sequence * seq,int cfra,
+ float facf0, float facf1, int x, int y,
+ struct ImBuf *ibuf1, struct ImBuf *ibuf2,
+ struct ImBuf * ibuf3,
+ struct ImBuf *out)
+{
+ if (out->rect_float) {
+ do_drop_effect_float(
+ facf0, facf1, x, y,
+ ibuf1->rect_float, ibuf2->rect_float,
+ out->rect_float);
+ } else {
+ do_drop_effect_byte(
+ facf0, facf1, x, y,
+ (unsigned char*) ibuf1->rect, (unsigned char*) ibuf2->rect,
+ (unsigned char*) out->rect);
+ }
+}
+
+/* **********************************************************************
+ MUL
+ ********************************************************************** */
+
+static void do_mul_effect_byte(float facf0, float facf1, int x, int y,
+ unsigned char *rect1, unsigned char *rect2,
+ unsigned char *out)
+{
+ int xo, fac1, fac3;
+ char *rt1, *rt2, *rt;
+
+ xo= x;
+ rt1= (char *)rect1;
+ rt2= (char *)rect2;
+ rt= (char *)out;
+
+ fac1= (int)(256.0*facf0);
+ fac3= (int)(256.0*facf1);
+
+ /* formula:
+ * fac*(a*b) + (1-fac)*a => fac*a*(b-1)+axaux= c*px + py*s ;//+centx
+ yaux= -s*px + c*py;//+centy
+ */
+
+ while(y--) {
+
+ x= xo;
+ while(x--) {
+
+ rt[0]= rt1[0] + ((fac1*rt1[0]*(rt2[0]-256))>>16);
+ rt[1]= rt1[1] + ((fac1*rt1[1]*(rt2[1]-256))>>16);
+ rt[2]= rt1[2] + ((fac1*rt1[2]*(rt2[2]-256))>>16);
+ rt[3]= rt1[3] + ((fac1*rt1[3]*(rt2[3]-256))>>16);
+
+ rt1+= 4; rt2+= 4; rt+= 4;
+ }
+
+ if(y==0) break;
+ y--;
+
+ x= xo;
+ while(x--) {
+
+ rt[0]= rt1[0] + ((fac3*rt1[0]*(rt2[0]-256))>>16);
+ rt[1]= rt1[1] + ((fac3*rt1[1]*(rt2[1]-256))>>16);
+ rt[2]= rt1[2] + ((fac3*rt1[2]*(rt2[2]-256))>>16);
+ rt[3]= rt1[3] + ((fac3*rt1[3]*(rt2[3]-256))>>16);
+
+ rt1+= 4; rt2+= 4; rt+= 4;
+ }
+ }
+}
+
+static void do_mul_effect_float(float facf0, float facf1, int x, int y,
+ float *rect1, float *rect2,
+ float *out)
+{
+ int xo;
+ float fac1, fac3;
+ float *rt1, *rt2, *rt;
+
+ xo= x;
+ rt1= rect1;
+ rt2= rect2;
+ rt= out;
+
+ fac1= facf0;
+ fac3= facf1;
+
+ /* formula:
+ * fac*(a*b) + (1-fac)*a => fac*a*(b-1)+a
+ */
+
+ while(y--) {
+
+ x= xo;
+ while(x--) {
+
+ rt[0]= rt1[0] + fac1*rt1[0]*(rt2[0]-1.0);
+ rt[1]= rt1[1] + fac1*rt1[1]*(rt2[1]-1.0);
+ rt[2]= rt1[2] + fac1*rt1[2]*(rt2[2]-1.0);
+ rt[3]= rt1[3] + fac1*rt1[3]*(rt2[3]-1.0);
+
+ rt1+= 4; rt2+= 4; rt+= 4;
+ }
+
+ if(y==0) break;
+ y--;
+
+ x= xo;
+ while(x--) {
+
+ rt[0]= rt1[0] + fac3*rt1[0]*(rt2[0]-1.0);
+ rt[1]= rt1[1] + fac3*rt1[1]*(rt2[1]-1.0);
+ rt[2]= rt1[2] + fac3*rt1[2]*(rt2[2]-1.0);
+ rt[3]= rt1[3] + fac3*rt1[3]*(rt2[3]-1.0);
+
+ rt1+= 4; rt2+= 4; rt+= 4;
+ }
+ }
+}
+
+static void do_mul_effect(Sequence * seq,int cfra,
+ float facf0, float facf1, int x, int y,
+ struct ImBuf *ibuf1, struct ImBuf *ibuf2,
+ struct ImBuf *ibuf3, struct ImBuf *out)
+{
+ if (out->rect_float) {
+ do_mul_effect_float(
+ facf0, facf1, x, y,
+ ibuf1->rect_float, ibuf2->rect_float,
+ out->rect_float);
+ } else {
+ do_mul_effect_byte(
+ facf0, facf1, x, y,
+ (unsigned char*) ibuf1->rect, (unsigned char*) ibuf2->rect,
+ (unsigned char*) out->rect);
+ }
+}
+
+/* **********************************************************************
+ WIPE
+ ********************************************************************** */
+
+// This function calculates the blur band for the wipe effects
+static float in_band(float width,float dist, float perc,int side,int dir){
+
+ float t1,t2,alpha,percwidth;
+ if(width == 0)
+ return (float)side;
+ if(side == 1)
+ percwidth = width * perc;
+ else
+ percwidth = width * (1 - perc);
+
+ if(width < dist)
+ return side;
+
+ t1 = dist / width; //percentange of width that is
+ t2 = 1 / width; //amount of alpha per % point
+
+ if(side == 1)
+ alpha = (t1*t2*100) + (1-perc); // add point's alpha contrib to current position in wipe
+ else
+ alpha = (1-perc) - (t1*t2*100);
+
+ if(dir == 0)
+ alpha = 1-alpha;
+ return alpha;
+}
+
+static float check_zone(int x, int y, int xo, int yo,
+ Sequence *seq, float facf0)
+{
+ float posx, posy,hyp,hyp2,angle,hwidth,b1,b2,b3,pointdist;
+/*some future stuff
+float hyp3,hyp4,b4,b5
+*/
+ float temp1,temp2,temp3,temp4; //some placeholder variables
+ float halfx = xo/2;
+ float halfy = yo/2;
+ float widthf,output=0;
+ WipeVars *wipe = (WipeVars *)seq->effectdata;
+ int width;
+
+ angle = wipe->angle;
+ if(angle < 0){
+ x = xo-x;
+ //y = yo-y
+ }
+ angle = pow(fabs(angle)/45,log(xo)/log(2));
+
+ posy = facf0 * yo;
+ if(wipe->forward){
+ posx = facf0 * xo;
+ posy = facf0 * yo;
+ } else{
+ posx = xo - facf0 * xo;
+ posy = yo - facf0 * yo;
+ }
+ switch (wipe->wipetype) {
+ case DO_SINGLE_WIPE:
+ width = (int)(wipe->edgeWidth*((xo+yo)/2.0));
+ hwidth = (float)width/2.0;
+
+ if (angle == 0.0)angle = 0.000001;
+ b1 = posy - (-angle)*posx;
+ b2 = y - (-angle)*x;
+ hyp = fabs(angle*x+y+(-posy-angle*posx))/sqrt(angle*angle+1);
+ if(angle < 0){
+ temp1 = b1;
+ b1 = b2;
+ b2 = temp1;
+ }
+ if(wipe->forward){
+ if(b1 < b2)
+ output = in_band(width,hyp,facf0,1,1);
+ else
+ output = in_band(width,hyp,facf0,0,1);
+ } else{
+ if(b1 < b2)
+ output = in_band(width,hyp,facf0,0,1);
+ else
+ output = in_band(width,hyp,facf0,1,1);
+ }
+ break;
+
+
+ case DO_DOUBLE_WIPE:
+ if(!wipe->forward)facf0 = 1-facf0; // Go the other direction
+
+ width = (int)(wipe->edgeWidth*((xo+yo)/2.0)); // calculate the blur width
+ hwidth = (float)width/2.0;
+ if (angle == 0)angle = 0.000001;
+ b1 = posy/2 - (-angle)*posx/2;
+ b3 = (yo-posy/2) - (-angle)*(xo-posx/2);
+ b2 = y - (-angle)*x;
+
+ hyp = abs(angle*x+y+(-posy/2-angle*posx/2))/sqrt(angle*angle+1);
+ hyp2 = abs(angle*x+y+(-(yo-posy/2)-angle*(xo-posx/2)))/sqrt(angle*angle+1);
+
+ temp1 = xo*(1-facf0/2)-xo*facf0/2;
+ temp2 = yo*(1-facf0/2)-yo*facf0/2;
+ pointdist = sqrt(temp1*temp1 + temp2*temp2);
+
+ if(b2 < b1 && b2 < b3 ){
+ if(hwidth < pointdist)
+ output = in_band(hwidth,hyp,facf0,0,1);
+ } else if(b2 > b1 && b2 > b3 ){
+ if(hwidth < pointdist)
+ output = in_band(hwidth,hyp2,facf0,0,1);
+ } else {
+ if( hyp < hwidth && hyp2 > hwidth )
+ output = in_band(hwidth,hyp,facf0,1,1);
+ else if( hyp > hwidth && hyp2 < hwidth )
+ output = in_band(hwidth,hyp2,facf0,1,1);
+ else
+ output = in_band(hwidth,hyp2,facf0,1,1) * in_band(hwidth,hyp,facf0,1,1);
+ }
+ if(!wipe->forward)output = 1-output;
+ break;
+ case DO_CLOCK_WIPE:
+ /*
+ temp1: angle of effect center in rads
+ temp2: angle of line through (halfx,halfy) and (x,y) in rads
+ temp3: angle of low side of blur
+ temp4: angle of high side of blur
+ */
+ output = 1-facf0;
+ widthf = wipe->edgeWidth*2*3.14159;
+ temp1 = 2 * 3.14159 * facf0;
+
+ if(wipe->forward){
+ temp1 = 2*3.14159-temp1;
+ }
+
+ x = x - halfx;
+ y = y - halfy;
+
+ temp2 = asin(abs(y)/sqrt(x*x + y*y));
+ if(x <= 0 && y >= 0) temp2 = 3.14159 - temp2;
+ else if(x<=0 && y <= 0) temp2 += 3.14159;
+ else if(x >= 0 && y <= 0) temp2 = 2*3.14159 - temp2;
+
+ if(wipe->forward){
+ temp3 = temp1-(widthf/2)*facf0;
+ temp4 = temp1+(widthf/2)*(1-facf0);
+ } else{
+ temp3 = temp1-(widthf/2)*(1-facf0);
+ temp4 = temp1+(widthf/2)*facf0;
+ }
+ if (temp3 < 0) temp3 = 0;
+ if (temp4 > 2*3.14159) temp4 = 2*3.14159;
+
+
+ if(temp2 < temp3) output = 0;
+ else if (temp2 > temp4) output = 1;
+ else output = (temp2-temp3)/(temp4-temp3);
+ if(x == 0 && y == 0) output = 1;
+ if(output != output) output = 1;
+ if(wipe->forward) output = 1 - output;
+ break;
+ /* BOX WIPE IS NOT WORKING YET */
+ /* case DO_CROSS_WIPE: */
+ /* BOX WIPE IS NOT WORKING YET */
+ /*
+ case DO_BOX_WIPE:
+ if(invert)facf0 = 1-facf0;
+
+ width = (int)(wipe->edgeWidth*((xo+yo)/2.0));
+ hwidth = (float)width/2.0;
+ if (angle == 0)angle = 0.000001;
+ b1 = posy/2 - (-angle)*posx/2;
+ b3 = (yo-posy/2) - (-angle)*(xo-posx/2);
+ b2 = y - (-angle)*x;
+
+ hyp = abs(angle*x+y+(-posy/2-angle*posx/2))/sqrt(angle*angle+1);
+ hyp2 = abs(angle*x+y+(-(yo-posy/2)-angle*(xo-posx/2)))/sqrt(angle*angle+1);
+
+ temp1 = xo*(1-facf0/2)-xo*facf0/2;
+ temp2 = yo*(1-facf0/2)-yo*facf0/2;
+ pointdist = sqrt(temp1*temp1 + temp2*temp2);
+
+ if(b2 < b1 && b2 < b3 ){
+ if(hwidth < pointdist)
+ output = in_band(hwidth,hyp,facf0,0,1);
+ } else if(b2 > b1 && b2 > b3 ){
+ if(hwidth < pointdist)
+ output = in_band(hwidth,hyp2,facf0,0,1);
+ } else {
+ if( hyp < hwidth && hyp2 > hwidth )
+ output = in_band(hwidth,hyp,facf0,1,1);
+ else if( hyp > hwidth && hyp2 < hwidth )
+ output = in_band(hwidth,hyp2,facf0,1,1);
+ else
+ output = in_band(hwidth,hyp2,facf0,1,1) * in_band(hwidth,hyp,facf0,1,1);
+ }
+
+ if(invert)facf0 = 1-facf0;
+ angle = -1/angle;
+ b1 = posy/2 - (-angle)*posx/2;
+ b3 = (yo-posy/2) - (-angle)*(xo-posx/2);
+ b2 = y - (-angle)*x;
+
+ hyp = abs(angle*x+y+(-posy/2-angle*posx/2))/sqrt(angle*angle+1);
+ hyp2 = abs(angle*x+y+(-(yo-posy/2)-angle*(xo-posx/2)))/sqrt(angle*angle+1);
+
+ if(b2 < b1 && b2 < b3 ){
+ if(hwidth < pointdist)
+ output *= in_band(hwidth,hyp,facf0,0,1);
+ } else if(b2 > b1 && b2 > b3 ){
+ if(hwidth < pointdist)
+ output *= in_band(hwidth,hyp2,facf0,0,1);
+ } else {
+ if( hyp < hwidth && hyp2 > hwidth )
+ output *= in_band(hwidth,hyp,facf0,1,1);
+ else if( hyp > hwidth && hyp2 < hwidth )
+ output *= in_band(hwidth,hyp2,facf0,1,1);
+ else
+ output *= in_band(hwidth,hyp2,facf0,1,1) * in_band(hwidth,hyp,facf0,1,1);
+ }
+
+ break;
+*/
+ case DO_IRIS_WIPE:
+ if(xo > yo) yo = xo;
+ else xo = yo;
+
+ if(!wipe->forward) facf0 = 1-facf0;
+
+ width = (int)(wipe->edgeWidth*((xo+yo)/2.0));
+ hwidth = (float)width/2.0;
+
+ temp1 = (halfx-(halfx)*facf0);
+ pointdist = sqrt(temp1*temp1 + temp1*temp1);
+
+ temp2 = sqrt((halfx-x)*(halfx-x) + (halfy-y)*(halfy-y));
+ if(temp2 > pointdist) output = in_band(hwidth,fabs(temp2-pointdist),facf0,0,1);
+ else output = in_band(hwidth,fabs(temp2-pointdist),facf0,1,1);
+
+ if(!wipe->forward) output = 1-output;
+
+ break;
+ }
+ if (output < 0) output = 0;
+ else if(output > 1) output = 1;
+ return output;
+}
+
+static void init_wipe_effect(Sequence *seq)
+{
+ if(seq->effectdata)MEM_freeN(seq->effectdata);
+ seq->effectdata = MEM_callocN(sizeof(struct WipeVars), "wipevars");
+}
+
+static int num_inputs_wipe()
+{
+ return 1;
+}
+
+static void free_wipe_effect(Sequence *seq)
+{
+ if(seq->effectdata)MEM_freeN(seq->effectdata);
+ seq->effectdata = 0;
+}
+
+static void copy_wipe_effect(Sequence *dst, Sequence *src)
+{
+ dst->effectdata = MEM_dupallocN(src->effectdata);
+}
+
+static void do_wipe_effect_byte(Sequence *seq, float facf0, float facf1,
+ int x, int y,
+ unsigned char *rect1,
+ unsigned char *rect2, unsigned char *out)
+{
+ int xo, yo;
+ char *rt1, *rt2, *rt;
+ rt1 = (char *)rect1;
+ rt2 = (char *)rect2;
+ rt = (char *)out;
+
+ xo = x;
+ yo = y;
+ for(y=0;y<yo;y++) {
+ for(x=0;x<xo;x++) {
+ float check = check_zone(x,y,xo,yo,seq,facf0);
+ if (check) {
+ if (rt1) {
+ rt[0] = (int)(rt1[0]*check)+ (int)(rt2[0]*(1-check));
+ rt[1] = (int)(rt1[1]*check)+ (int)(rt2[1]*(1-check));
+ rt[2] = (int)(rt1[2]*check)+ (int)(rt2[2]*(1-check));
+ rt[3] = (int)(rt1[3]*check)+ (int)(rt2[3]*(1-check));
+ } else {
+ rt[0] = 0;
+ rt[1] = 0;
+ rt[2] = 0;
+ rt[3] = 255;
+ }
+ } else {
+ if (rt2) {
+ rt[0] = rt2[0];
+ rt[1] = rt2[1];
+ rt[2] = rt2[2];
+ rt[3] = rt2[3];
+ } else {
+ rt[0] = 0;
+ rt[1] = 0;
+ rt[2] = 0;
+ rt[3] = 255;
+ }
+ }
+
+ rt+=4;
+ if(rt1 !=NULL){
+ rt1+=4;
+ }
+ if(rt2 !=NULL){
+ rt2+=4;
+ }
+ }
+ }
+}
+
+static void do_wipe_effect_float(Sequence *seq, float facf0, float facf1,
+ int x, int y,
+ float *rect1,
+ float *rect2, float *out)
+{
+ int xo, yo;
+ float *rt1, *rt2, *rt;
+ rt1 = rect1;
+ rt2 = rect2;
+ rt = out;
+
+ xo = x;
+ yo = y;
+ for(y=0;y<yo;y++) {
+ for(x=0;x<xo;x++) {
+ float check = check_zone(x,y,xo,yo,seq,facf0);
+ if (check) {
+ if (rt1) {
+ rt[0] = rt1[0]*check+ rt2[0]*(1-check);
+ rt[1] = rt1[1]*check+ rt2[1]*(1-check);
+ rt[2] = rt1[2]*check+ rt2[2]*(1-check);
+ rt[3] = rt1[3]*check+ rt2[3]*(1-check);
+ } else {
+ rt[0] = 0;
+ rt[1] = 0;
+ rt[2] = 0;
+ rt[3] = 1.0;
+ }
+ } else {
+ if (rt2) {
+ rt[0] = rt2[0];
+ rt[1] = rt2[1];
+ rt[2] = rt2[2];
+ rt[3] = rt2[3];
+ } else {
+ rt[0] = 0;
+ rt[1] = 0;
+ rt[2] = 0;
+ rt[3] = 1.0;
+ }
+ }
+
+ rt+=4;
+ if(rt1 !=NULL){
+ rt1+=4;
+ }
+ if(rt2 !=NULL){
+ rt2+=4;
+ }
+ }
+ }
+}
+
+static void do_wipe_effect(Sequence * seq,int cfra,
+ float facf0, float facf1, int x, int y,
+ struct ImBuf *ibuf1, struct ImBuf *ibuf2,
+ struct ImBuf *ibuf3, struct ImBuf *out)
+{
+ if (out->rect_float) {
+ do_wipe_effect_float(seq,
+ facf0, facf1, x, y,
+ ibuf1->rect_float, ibuf2->rect_float,
+ out->rect_float);
+ } else {
+ do_wipe_effect_byte(seq,
+ facf0, facf1, x, y,
+ (unsigned char*) ibuf1->rect, (unsigned char*) ibuf2->rect,
+ (unsigned char*) out->rect);
+ }
+}
+/* **********************************************************************
+ TRANSFORM
+ ********************************************************************** */
+static void init_transform_effect(Sequence *seq)
+{
+ TransformVars *scale;
+
+ if(seq->effectdata)MEM_freeN(seq->effectdata);
+ seq->effectdata = MEM_callocN(sizeof(struct TransformVars), "transformvars");
+
+ scale = (TransformVars *)seq->effectdata;
+ scale->ScalexIni = 1;
+ scale->ScaleyIni = 1;
+ scale->ScalexFin = 1;
+ scale->ScaleyFin = 1;
+
+ scale->xIni=0;
+ scale->xFin=0;
+ scale->yIni=0;
+ scale->yFin=0;
+
+ scale->rotIni=0;
+ scale->rotFin=0;
+
+ scale->interpolation=1;
+ scale->percent=1;
+}
+
+static int num_inputs_transform()
+{
+ return 1;
+}
+
+static void free_transform_effect(Sequence *seq)
+{
+ if(seq->effectdata)MEM_freeN(seq->effectdata);
+ seq->effectdata = 0;
+}
+
+static void copy_transform_effect(Sequence *dst, Sequence *src)
+{
+ dst->effectdata = MEM_dupallocN(src->effectdata);
+}
+
+static void do_transform(Sequence * seq,float facf0, int x, int y,
+ struct ImBuf *ibuf1,struct ImBuf *out)
+{
+ int xo, yo, xi, yi;
+ float xs,ys,factxScale,factyScale,tx,ty,rad,s,c,xaux,yaux,factRot,px,py;
+ TransformVars *scale;
+
+ scale = (TransformVars *)seq->effectdata;
+ xo = x;
+ yo = y;
+
+ //factor scale
+ factxScale = scale->ScalexIni + (scale->ScalexFin - scale->ScalexIni) * facf0;
+ factyScale = scale->ScaleyIni + (scale->ScaleyFin - scale->ScaleyIni) * facf0;
+
+ //Factor translate
+ if(!scale->percent){
+ tx = scale->xIni+(xo / 2.0f) + (scale->xFin-(xo / 2.0f) - scale->xIni+(xo / 2.0f)) * facf0;
+ ty = scale->yIni+(yo / 2.0f) + (scale->yFin-(yo / 2.0f) - scale->yIni+(yo / 2.0f)) * facf0;
+ }else{
+ tx = xo*(scale->xIni/100.0)+(xo / 2.0f) + (xo*(scale->xFin/100.0)-(xo / 2.0f) - xo*(scale->xIni/100.0)+(xo / 2.0f)) * facf0;
+ ty = yo*(scale->yIni/100.0)+(yo / 2.0f) + (yo*(scale->yFin/100.0)-(yo / 2.0f) - yo*(scale->yIni/100.0)+(yo / 2.0f)) * facf0;
+ }
+
+ //factor Rotate
+ factRot = scale->rotIni + (scale->rotFin - scale->rotIni) * facf0;
+ rad = (M_PI * factRot) / 180.0f;
+ s= sin(rad);
+ c= cos(rad);
+
+ for (yi = 0; yi < yo; yi++) {
+ for (xi = 0; xi < xo; xi++) {
+ //tranlate point
+ px = xi-tx;
+ py = yi-ty;
+
+ //rotate point with center ref
+ xaux = c*px + py*s ;
+ yaux = -s*px + c*py;
+
+ //scale point with center ref
+ xs = xaux / factxScale;
+ ys = yaux / factyScale;
+
+ //undo reference center point
+ xs += (xo / 2.0f);
+ ys += (yo / 2.0f);
+
+ //interpolate
+ if(scale->interpolation==0)
+ neareast_interpolation(ibuf1,out, xs,ys,xi,yi);
+ if(scale->interpolation==1)
+ bilinear_interpolation(ibuf1,out, xs,ys,xi,yi);
+ if(scale->interpolation==2)
+ bicubic_interpolation(ibuf1,out, xs,ys,xi,yi);
+ }
+ }
+
+}
+static void do_transform_effect(Sequence * seq,int cfra,
+ float facf0, float facf1, int x, int y,
+ struct ImBuf *ibuf1, struct ImBuf *ibuf2,
+ struct ImBuf *ibuf3, struct ImBuf *out)
+{
+ do_transform(seq, facf0, x, y, ibuf1, out);
+}
+
+
+/* **********************************************************************
+ GLOW
+ ********************************************************************** */
+
+static void RVBlurBitmap2_byte ( unsigned char* map, int width,int height,
+ float blur,
+ int quality)
+/* MUUUCCH better than the previous blur. */
+/* We do the blurring in two passes which is a whole lot faster. */
+/* I changed the math arount to implement an actual Gaussian */
+/* distribution. */
+/* */
+/* Watch out though, it tends to misbehaven with large blur values on */
+/* a small bitmap. Avoid avoid avoid. */
+/*=============================== */
+{
+ unsigned char* temp=NULL,*swap;
+ float *filter=NULL;
+ int x,y,i,fx,fy;
+ int index, ix, halfWidth;
+ float fval, k, curColor[3], curColor2[3], weight=0;
+
+ /* If we're not really blurring, bail out */
+ if (blur<=0)
+ return;
+
+ /* Allocate memory for the tempmap and the blur filter matrix */
+ temp= MEM_mallocN( (width*height*4), "blurbitmaptemp");
+ if (!temp)
+ return;
+
+ /* Allocate memory for the filter elements */
+ halfWidth = ((quality+1)*blur);
+ filter = (float *)MEM_mallocN(sizeof(float)*halfWidth*2, "blurbitmapfilter");
+ if (!filter){
+ MEM_freeN (temp);
+ return;
+ }
+
+ /* Apparently we're calculating a bell curve */
+ /* based on the standard deviation (or radius) */
+ /* This code is based on an example */
+ /* posted to comp.graphics.algorithms by */
+ /* Blancmange (bmange@airdmhor.gen.nz) */
+
+ k = -1.0/(2.0*3.14159*blur*blur);
+ fval=0;
+ for (ix = 0;ix< halfWidth;ix++){
+ weight = (float)exp(k*(ix*ix));
+ filter[halfWidth - ix] = weight;
+ filter[halfWidth + ix] = weight;
+ }
+ filter[0] = weight;
+
+ /* Normalize the array */
+ fval=0;
+ for (ix = 0;ix< halfWidth*2;ix++)
+ fval+=filter[ix];
+
+ for (ix = 0;ix< halfWidth*2;ix++)
+ filter[ix]/=fval;
+
+ /* Blur the rows */
+ for (y=0;y<height;y++){
+ /* Do the left & right strips */
+ for (x=0;x<halfWidth;x++){
+ index=(x+y*width)*4;
+ fx=0;
+ curColor[0]=curColor[1]=curColor[2]=0;
+ curColor2[0]=curColor2[1]=curColor2[2]=0;
+
+ for (i=x-halfWidth;i<x+halfWidth;i++){
+ if ((i>=0)&&(i<width)){
+ curColor[0]+=map[(i+y*width)*4+GlowR]*filter[fx];
+ curColor[1]+=map[(i+y*width)*4+GlowG]*filter[fx];
+ curColor[2]+=map[(i+y*width)*4+GlowB]*filter[fx];
+
+ curColor2[0]+=map[(width-1-i+y*width)*4+GlowR] *
+ filter[fx];
+ curColor2[1]+=map[(width-1-i+y*width)*4+GlowG] *
+ filter[fx];
+ curColor2[2]+=map[(width-1-i+y*width)*4+GlowB] *
+ filter[fx];
+ }
+ fx++;
+ }
+ temp[index+GlowR]=curColor[0];
+ temp[index+GlowG]=curColor[1];
+ temp[index+GlowB]=curColor[2];
+
+ temp[((width-1-x+y*width)*4)+GlowR]=curColor2[0];
+ temp[((width-1-x+y*width)*4)+GlowG]=curColor2[1];
+ temp[((width-1-x+y*width)*4)+GlowB]=curColor2[2];
+
+ }
+ /* Do the main body */
+ for (x=halfWidth;x<width-halfWidth;x++){
+ index=(x+y*width)*4;
+ fx=0;
+ curColor[0]=curColor[1]=curColor[2]=0;
+ for (i=x-halfWidth;i<x+halfWidth;i++){
+ curColor[0]+=map[(i+y*width)*4+GlowR]*filter[fx];
+ curColor[1]+=map[(i+y*width)*4+GlowG]*filter[fx];
+ curColor[2]+=map[(i+y*width)*4+GlowB]*filter[fx];
+ fx++;
+ }
+ temp[index+GlowR]=curColor[0];
+ temp[index+GlowG]=curColor[1];
+ temp[index+GlowB]=curColor[2];
+ }
+ }
+
+ /* Swap buffers */
+ swap=temp;temp=map;map=swap;
+
+
+ /* Blur the columns */
+ for (x=0;x<width;x++){
+ /* Do the top & bottom strips */
+ for (y=0;y<halfWidth;y++){
+ index=(x+y*width)*4;
+ fy=0;
+ curColor[0]=curColor[1]=curColor[2]=0;
+ curColor2[0]=curColor2[1]=curColor2[2]=0;
+ for (i=y-halfWidth;i<y+halfWidth;i++){
+ if ((i>=0)&&(i<height)){
+ /* Bottom */
+ curColor[0]+=map[(x+i*width)*4+GlowR]*filter[fy];
+ curColor[1]+=map[(x+i*width)*4+GlowG]*filter[fy];
+ curColor[2]+=map[(x+i*width)*4+GlowB]*filter[fy];
+
+ /* Top */
+ curColor2[0]+=map[(x+(height-1-i)*width) *
+ 4+GlowR]*filter[fy];
+ curColor2[1]+=map[(x+(height-1-i)*width) *
+ 4+GlowG]*filter[fy];
+ curColor2[2]+=map[(x+(height-1-i)*width) *
+ 4+GlowB]*filter[fy];
+ }
+ fy++;
+ }
+ temp[index+GlowR]=curColor[0];
+ temp[index+GlowG]=curColor[1];
+ temp[index+GlowB]=curColor[2];
+ temp[((x+(height-1-y)*width)*4)+GlowR]=curColor2[0];
+ temp[((x+(height-1-y)*width)*4)+GlowG]=curColor2[1];
+ temp[((x+(height-1-y)*width)*4)+GlowB]=curColor2[2];
+ }
+ /* Do the main body */
+ for (y=halfWidth;y<height-halfWidth;y++){
+ index=(x+y*width)*4;
+ fy=0;
+ curColor[0]=curColor[1]=curColor[2]=0;
+ for (i=y-halfWidth;i<y+halfWidth;i++){
+ curColor[0]+=map[(x+i*width)*4+GlowR]*filter[fy];
+ curColor[1]+=map[(x+i*width)*4+GlowG]*filter[fy];
+ curColor[2]+=map[(x+i*width)*4+GlowB]*filter[fy];
+ fy++;
+ }
+ temp[index+GlowR]=curColor[0];
+ temp[index+GlowG]=curColor[1];
+ temp[index+GlowB]=curColor[2];
+ }
+ }
+
+
+ /* Swap buffers */
+ swap=temp;temp=map;map=swap;
+
+ /* Tidy up */
+ MEM_freeN (filter);
+ MEM_freeN (temp);
+}
+
+static void RVBlurBitmap2_float ( float* map, int width,int height,
+ float blur,
+ int quality)
+/* MUUUCCH better than the previous blur. */
+/* We do the blurring in two passes which is a whole lot faster. */
+/* I changed the math arount to implement an actual Gaussian */
+/* distribution. */
+/* */
+/* Watch out though, it tends to misbehaven with large blur values on */
+/* a small bitmap. Avoid avoid avoid. */
+/*=============================== */
+{
+ float* temp=NULL,*swap;
+ float *filter=NULL;
+ int x,y,i,fx,fy;
+ int index, ix, halfWidth;
+ float fval, k, curColor[3], curColor2[3], weight=0;
+
+ /* If we're not really blurring, bail out */
+ if (blur<=0)
+ return;
+
+ /* Allocate memory for the tempmap and the blur filter matrix */
+ temp= MEM_mallocN( (width*height*4*sizeof(float)), "blurbitmaptemp");
+ if (!temp)
+ return;
+
+ /* Allocate memory for the filter elements */
+ halfWidth = ((quality+1)*blur);
+ filter = (float *)MEM_mallocN(sizeof(float)*halfWidth*2, "blurbitmapfilter");
+ if (!filter){
+ MEM_freeN (temp);
+ return;
+ }
+
+ /* Apparently we're calculating a bell curve */
+ /* based on the standard deviation (or radius) */
+ /* This code is based on an example */
+ /* posted to comp.graphics.algorithms by */
+ /* Blancmange (bmange@airdmhor.gen.nz) */
+
+ k = -1.0/(2.0*3.14159*blur*blur);
+ fval=0;
+ for (ix = 0;ix< halfWidth;ix++){
+ weight = (float)exp(k*(ix*ix));
+ filter[halfWidth - ix] = weight;
+ filter[halfWidth + ix] = weight;
+ }
+ filter[0] = weight;
+
+ /* Normalize the array */
+ fval=0;
+ for (ix = 0;ix< halfWidth*2;ix++)
+ fval+=filter[ix];
+
+ for (ix = 0;ix< halfWidth*2;ix++)
+ filter[ix]/=fval;
+
+ /* Blur the rows */
+ for (y=0;y<height;y++){
+ /* Do the left & right strips */
+ for (x=0;x<halfWidth;x++){
+ index=(x+y*width)*4;
+ fx=0;
+ curColor[0]=curColor[1]=curColor[2]=0.0f;
+ curColor2[0]=curColor2[1]=curColor2[2]=0.0f;
+
+ for (i=x-halfWidth;i<x+halfWidth;i++){
+ if ((i>=0)&&(i<width)){
+ curColor[0]+=map[(i+y*width)*4+GlowR]*filter[fx];
+ curColor[1]+=map[(i+y*width)*4+GlowG]*filter[fx];
+ curColor[2]+=map[(i+y*width)*4+GlowB]*filter[fx];
+
+ curColor2[0]+=map[(width-1-i+y*width)*4+GlowR] *
+ filter[fx];
+ curColor2[1]+=map[(width-1-i+y*width)*4+GlowG] *
+ filter[fx];
+ curColor2[2]+=map[(width-1-i+y*width)*4+GlowB] *
+ filter[fx];
+ }
+ fx++;
+ }
+ temp[index+GlowR]=curColor[0];
+ temp[index+GlowG]=curColor[1];
+ temp[index+GlowB]=curColor[2];
+
+ temp[((width-1-x+y*width)*4)+GlowR]=curColor2[0];
+ temp[((width-1-x+y*width)*4)+GlowG]=curColor2[1];
+ temp[((width-1-x+y*width)*4)+GlowB]=curColor2[2];
+
+ }
+ /* Do the main body */
+ for (x=halfWidth;x<width-halfWidth;x++){
+ index=(x+y*width)*4;
+ fx=0;
+ curColor[0]=curColor[1]=curColor[2]=0;
+ for (i=x-halfWidth;i<x+halfWidth;i++){
+ curColor[0]+=map[(i+y*width)*4+GlowR]*filter[fx];
+ curColor[1]+=map[(i+y*width)*4+GlowG]*filter[fx];
+ curColor[2]+=map[(i+y*width)*4+GlowB]*filter[fx];
+ fx++;
+ }
+ temp[index+GlowR]=curColor[0];
+ temp[index+GlowG]=curColor[1];
+ temp[index+GlowB]=curColor[2];
+ }
+ }
+
+ /* Swap buffers */
+ swap=temp;temp=map;map=swap;
+
+
+ /* Blur the columns */
+ for (x=0;x<width;x++){
+ /* Do the top & bottom strips */
+ for (y=0;y<halfWidth;y++){
+ index=(x+y*width)*4;
+ fy=0;
+ curColor[0]=curColor[1]=curColor[2]=0;
+ curColor2[0]=curColor2[1]=curColor2[2]=0;
+ for (i=y-halfWidth;i<y+halfWidth;i++){
+ if ((i>=0)&&(i<height)){
+ /* Bottom */
+ curColor[0]+=map[(x+i*width)*4+GlowR]*filter[fy];
+ curColor[1]+=map[(x+i*width)*4+GlowG]*filter[fy];
+ curColor[2]+=map[(x+i*width)*4+GlowB]*filter[fy];
+
+ /* Top */
+ curColor2[0]+=map[(x+(height-1-i)*width) *
+ 4+GlowR]*filter[fy];
+ curColor2[1]+=map[(x+(height-1-i)*width) *
+ 4+GlowG]*filter[fy];
+ curColor2[2]+=map[(x+(height-1-i)*width) *
+ 4+GlowB]*filter[fy];
+ }
+ fy++;
+ }
+ temp[index+GlowR]=curColor[0];
+ temp[index+GlowG]=curColor[1];
+ temp[index+GlowB]=curColor[2];
+ temp[((x+(height-1-y)*width)*4)+GlowR]=curColor2[0];
+ temp[((x+(height-1-y)*width)*4)+GlowG]=curColor2[1];
+ temp[((x+(height-1-y)*width)*4)+GlowB]=curColor2[2];
+ }
+ /* Do the main body */
+ for (y=halfWidth;y<height-halfWidth;y++){
+ index=(x+y*width)*4;
+ fy=0;
+ curColor[0]=curColor[1]=curColor[2]=0;
+ for (i=y-halfWidth;i<y+halfWidth;i++){
+ curColor[0]+=map[(x+i*width)*4+GlowR]*filter[fy];
+ curColor[1]+=map[(x+i*width)*4+GlowG]*filter[fy];
+ curColor[2]+=map[(x+i*width)*4+GlowB]*filter[fy];
+ fy++;
+ }
+ temp[index+GlowR]=curColor[0];
+ temp[index+GlowG]=curColor[1];
+ temp[index+GlowB]=curColor[2];
+ }
+ }
+
+
+ /* Swap buffers */
+ swap=temp;temp=map;map=swap;
+
+ /* Tidy up */
+ MEM_freeN (filter);
+ MEM_freeN (temp);
+}
+
+
+/* Adds two bitmaps and puts the results into a third map. */
+/* C must have been previously allocated but it may be A or B. */
+/* We clamp values to 255 to prevent weirdness */
+/*=============================== */
+static void RVAddBitmaps_byte (unsigned char* a, unsigned char* b, unsigned char* c, int width, int height)
+{
+ int x,y,index;
+
+ for (y=0;y<height;y++){
+ for (x=0;x<width;x++){
+ index=(x+y*width)*4;
+ c[index+GlowR]=MIN2(255,a[index+GlowR]+b[index+GlowR]);
+ c[index+GlowG]=MIN2(255,a[index+GlowG]+b[index+GlowG]);
+ c[index+GlowB]=MIN2(255,a[index+GlowB]+b[index+GlowB]);
+ c[index+GlowA]=MIN2(255,a[index+GlowA]+b[index+GlowA]);
+ }
+ }
+}
+
+static void RVAddBitmaps_float (float* a, float* b, float* c,
+ int width, int height)
+{
+ int x,y,index;
+
+ for (y=0;y<height;y++){
+ for (x=0;x<width;x++){
+ index=(x+y*width)*4;
+ c[index+GlowR]=MIN2(1.0,a[index+GlowR]+b[index+GlowR]);
+ c[index+GlowG]=MIN2(1.0,a[index+GlowG]+b[index+GlowG]);
+ c[index+GlowB]=MIN2(1.0,a[index+GlowB]+b[index+GlowB]);
+ c[index+GlowA]=MIN2(1.0,a[index+GlowA]+b[index+GlowA]);
+ }
+ }
+}
+
+/* For each pixel whose total luminance exceeds the threshold, */
+/* Multiply it's value by BOOST and add it to the output map */
+static void RVIsolateHighlights_byte (unsigned char* in, unsigned char* out,
+ int width, int height, int threshold,
+ float boost, float clamp)
+{
+ int x,y,index;
+ int intensity;
+
+
+ for(y=0;y< height;y++) {
+ for (x=0;x< width;x++) {
+ index= (x+y*width)*4;
+
+ /* Isolate the intensity */
+ intensity=(in[index+GlowR]+in[index+GlowG]+in[index+GlowB]-threshold);
+ if (intensity>0){
+ out[index+GlowR]=MIN2(255*clamp, (in[index+GlowR]*boost*intensity)/255);
+ out[index+GlowG]=MIN2(255*clamp, (in[index+GlowG]*boost*intensity)/255);
+ out[index+GlowB]=MIN2(255*clamp, (in[index+GlowB]*boost*intensity)/255);
+ out[index+GlowA]=MIN2(255*clamp, (in[index+GlowA]*boost*intensity)/255);
+ } else{
+ out[index+GlowR]=0;
+ out[index+GlowG]=0;
+ out[index+GlowB]=0;
+ out[index+GlowA]=0;
+ }
+ }
+ }
+}
+
+static void RVIsolateHighlights_float (float* in, float* out,
+ int width, int height, float threshold,
+ float boost, float clamp)
+{
+ int x,y,index;
+ float intensity;
+
+
+ for(y=0;y< height;y++) {
+ for (x=0;x< width;x++) {
+ index= (x+y*width)*4;
+
+ /* Isolate the intensity */
+ intensity=(in[index+GlowR]+in[index+GlowG]+in[index+GlowB]-threshold);
+ if (intensity>0){
+ out[index+GlowR]=MIN2(clamp, (in[index+GlowR]*boost*intensity));
+ out[index+GlowG]=MIN2(clamp, (in[index+GlowG]*boost*intensity));
+ out[index+GlowB]=MIN2(clamp, (in[index+GlowB]*boost*intensity));
+ out[index+GlowA]=MIN2(clamp, (in[index+GlowA]*boost*intensity));
+ } else{
+ out[index+GlowR]=0;
+ out[index+GlowG]=0;
+ out[index+GlowB]=0;
+ out[index+GlowA]=0;
+ }
+ }
+ }
+}
+
+static void init_glow_effect(Sequence *seq)
+{
+ GlowVars *glow;
+
+ if(seq->effectdata)MEM_freeN(seq->effectdata);
+ seq->effectdata = MEM_callocN(sizeof(struct GlowVars), "glowvars");
+
+ glow = (GlowVars *)seq->effectdata;
+ glow->fMini = 0.25;
+ glow->fClamp = 1.0;
+ glow->fBoost = 0.5;
+ glow->dDist = 3.0;
+ glow->dQuality = 3;
+ glow->bNoComp = 0;
+}
+
+static int num_inputs_glow()
+{
+ return 1;
+}
+
+static void free_glow_effect(Sequence *seq)
+{
+ if(seq->effectdata)MEM_freeN(seq->effectdata);
+ seq->effectdata = 0;
+}
+
+static void copy_glow_effect(Sequence *dst, Sequence *src)
+{
+ dst->effectdata = MEM_dupallocN(src->effectdata);
+}
+
+//void do_glow_effect(Cast *cast, float facf0, float facf1, int xo, int yo, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *outbuf, ImBuf *use)
+static void do_glow_effect_byte(Sequence *seq, float facf0, float facf1,
+ int x, int y, char *rect1,
+ char *rect2, char *out)
+{
+ unsigned char *outbuf=(unsigned char *)out;
+ unsigned char *inbuf=(unsigned char *)rect1;
+ GlowVars *glow = (GlowVars *)seq->effectdata;
+
+ RVIsolateHighlights_byte(inbuf, outbuf , x, y, glow->fMini*765, glow->fBoost, glow->fClamp);
+ RVBlurBitmap2_byte (outbuf, x, y, glow->dDist,glow->dQuality);
+ if (!glow->bNoComp)
+ RVAddBitmaps_byte (inbuf , outbuf, outbuf, x, y);
+}
+
+static void do_glow_effect_float(Sequence *seq, float facf0, float facf1,
+ int x, int y,
+ float *rect1, float *rect2, float *out)
+{
+ float *outbuf = out;
+ float *inbuf = rect1;
+ GlowVars *glow = (GlowVars *)seq->effectdata;
+
+ RVIsolateHighlights_float(inbuf, outbuf , x, y, glow->fMini*3.0f, glow->fBoost, glow->fClamp);
+ RVBlurBitmap2_float (outbuf, x, y, glow->dDist,glow->dQuality);
+ if (!glow->bNoComp)
+ RVAddBitmaps_float (inbuf , outbuf, outbuf, x, y);
+}
+
+static void do_glow_effect(Sequence * seq,int cfra,
+ float facf0, float facf1, int x, int y,
+ struct ImBuf *ibuf1, struct ImBuf *ibuf2,
+ struct ImBuf *ibuf3, struct ImBuf *out)
+{
+ if (out->rect_float) {
+ do_glow_effect_float(seq,
+ facf0, facf1, x, y,
+ ibuf1->rect_float, ibuf2->rect_float,
+ out->rect_float);
+ } else {
+ do_glow_effect_byte(seq,
+ facf0, facf1, x, y,
+ (char*) ibuf1->rect, (char*) ibuf2->rect,
+ (char*) out->rect);
+ }
+}
+
+/* **********************************************************************
+ SOLID COLOR
+ ********************************************************************** */
+
+static void init_solid_color(Sequence *seq)
+{
+ SolidColorVars *cv;
+
+ if(seq->effectdata)MEM_freeN(seq->effectdata);
+ seq->effectdata = MEM_callocN(sizeof(struct SolidColorVars), "solidcolor");
+
+ cv = (SolidColorVars *)seq->effectdata;
+ cv->col[0] = cv->col[1] = cv->col[2] = 0.5;
+}
+
+static int num_inputs_color()
+{
+ return 0;
+}
+
+static void free_solid_color(Sequence *seq)
+{
+ if(seq->effectdata)MEM_freeN(seq->effectdata);
+ seq->effectdata = 0;
+}
+
+static void copy_solid_color(Sequence *dst, Sequence *src)
+{
+ dst->effectdata = MEM_dupallocN(src->effectdata);
+}
+
+static int early_out_color(struct Sequence *seq,
+ float facf0, float facf1)
+{
+ return -1;
+}
+
+static void do_solid_color(Sequence * seq,int cfra,
+ float facf0, float facf1, int x, int y,
+ struct ImBuf *ibuf1, struct ImBuf *ibuf2,
+ struct ImBuf *ibuf3, struct ImBuf *out)
+{
+ SolidColorVars *cv = (SolidColorVars *)seq->effectdata;
+
+ unsigned char *rect;
+ float *rect_float;
+
+ if (out->rect) {
+ rect = (unsigned char *)out->rect;
+
+ for(y=0; y<out->y; y++) {
+ for(x=0; x<out->x; x++, rect+=4) {
+ rect[0]= (char)(cv->col[0]*255);
+ rect[1]= (char)(cv->col[1]*255);
+ rect[2]= (char)(cv->col[2]*255);
+ rect[3]= 255;
+ }
+ }
+ } else if (out->rect_float) {
+ rect_float = out->rect_float;
+
+ for(y=0; y<out->y; y++) {
+ for(x=0; x<out->x; x++, rect_float+=4) {
+ rect_float[0]= cv->col[0];
+ rect_float[1]= cv->col[1];
+ rect_float[2]= cv->col[2];
+ rect_float[3]= 1.0;
+ }
+ }
+ }
+}
+
+/* **********************************************************************
+ SPEED
+ ********************************************************************** */
+static void init_speed_effect(Sequence *seq)
+{
+ SpeedControlVars * v;
+
+ if(seq->effectdata) MEM_freeN(seq->effectdata);
+ seq->effectdata = MEM_callocN(sizeof(struct SpeedControlVars),
+ "speedcontrolvars");
+
+ v = (SpeedControlVars *)seq->effectdata;
+ v->globalSpeed = 1.0;
+ v->frameMap = 0;
+ v->flags = SEQ_SPEED_COMPRESS_IPO_Y;
+ v->length = 0;
+}
+
+static void load_speed_effect(Sequence * seq)
+{
+ SpeedControlVars * v = (SpeedControlVars *)seq->effectdata;
+
+ v->frameMap = 0;
+ v->length = 0;
+}
+
+static int num_inputs_speed()
+{
+ return 1;
+}
+
+static void free_speed_effect(Sequence *seq)
+{
+ SpeedControlVars * v = (SpeedControlVars *)seq->effectdata;
+ if(v->frameMap) MEM_freeN(v->frameMap);
+ if(seq->effectdata) MEM_freeN(seq->effectdata);
+ seq->effectdata = 0;
+}
+
+static void copy_speed_effect(Sequence *dst, Sequence *src)
+{
+ SpeedControlVars * v;
+ dst->effectdata = MEM_dupallocN(src->effectdata);
+ v = (SpeedControlVars *)dst->effectdata;
+ v->frameMap = 0;
+ v->length = 0;
+}
+
+static int early_out_speed(struct Sequence *seq,
+ float facf0, float facf1)
+{
+ return 1;
+}
+
+static void store_icu_yrange_speed(struct Sequence * seq,
+ short adrcode, float * ymin, float * ymax)
+{
+ SpeedControlVars * v = (SpeedControlVars *)seq->effectdata;
+
+ /* if not already done, load / initialize data */
+ get_sequence_effect(seq);
+
+ if ((v->flags & SEQ_SPEED_INTEGRATE) != 0) {
+ *ymin = -100.0;
+ *ymax = 100.0;
+ } else {
+ if (v->flags & SEQ_SPEED_COMPRESS_IPO_Y) {
+ *ymin = 0.0;
+ *ymax = 1.0;
+ } else {
+ *ymin = 0.0;
+ *ymax = seq->len;
+ }
+ }
+}
+
+void sequence_effect_speed_rebuild_map(struct Sequence * seq, int force)
+{
+ float facf0 = seq->facf0;
+ float ctime, div;
+ int cfra;
+ float fallback_fac;
+ SpeedControlVars * v = (SpeedControlVars *)seq->effectdata;
+
+ /* if not already done, load / initialize data */
+ get_sequence_effect(seq);
+
+ if (!(force || seq->len != v->length || !v->frameMap)) {
+ return;
+ }
+
+ if (!v->frameMap || v->length != seq->len) {
+ if (v->frameMap) MEM_freeN(v->frameMap);
+
+ v->length = seq->len;
+
+ v->frameMap = MEM_callocN(sizeof(float) * v->length,
+ "speedcontrol frameMap");
+ }
+
+ fallback_fac = 1.0;
+
+ /* if there is no IPO, try to make retiming easy by stretching the
+ strip */
+
+ if (!seq->ipo && seq->seq1 && seq->seq1->enddisp != seq->seq1->start
+ && seq->seq1->len != 0) {
+ fallback_fac = (float) seq->seq1->len /
+ (float) (seq->seq1->enddisp - seq->seq1->start);
+ /* FIXME: this strip stretching gets screwed by stripdata
+ handling one layer up.
+
+ So it currently works by enlarging, never by shrinking!
+
+ (IPOs still work, if used correctly)
+ */
+ if (fallback_fac > 1.0) {
+ fallback_fac = 1.0;
+ }
+ }
+
+ if ((v->flags & SEQ_SPEED_INTEGRATE) != 0) {
+ float cursor = 0;
+
+ v->frameMap[0] = 0;
+ v->lastValidFrame = 0;
+
+ for (cfra = 1; cfra < v->length; cfra++) {
+ if(seq->ipo) {
+ if((seq->flag & SEQ_IPO_FRAME_LOCKED) != 0) {
+ ctime = frame_to_float(seq->startdisp
+ + cfra);
+ div = 1.0;
+ } else {
+ ctime= frame_to_float(cfra);
+ div= v->length / 100.0f;
+ if(div==0.0) return;
+ }
+
+ calc_ipo(seq->ipo, ctime/div);
+ execute_ipo((ID *)seq, seq->ipo);
+ } else {
+ seq->facf0 = fallback_fac;
+ }
+ seq->facf0 *= v->globalSpeed;
+
+ cursor += seq->facf0;
+
+ if (cursor >= v->length) {
+ v->frameMap[cfra] = v->length - 1;
+ } else {
+ v->frameMap[cfra] = cursor;
+ v->lastValidFrame = cfra;
+ }
+ }
+ } else {
+ v->lastValidFrame = 0;
+ for (cfra = 0; cfra < v->length; cfra++) {
+ if(seq->ipo) {
+ if((seq->flag & SEQ_IPO_FRAME_LOCKED) != 0) {
+ ctime = frame_to_float(seq->startdisp
+ + cfra);
+ div = 1.0;
+ } else {
+ ctime= frame_to_float(cfra);
+ div= v->length / 100.0f;
+ if(div==0.0) return;
+ }
+
+ calc_ipo(seq->ipo, ctime/div);
+ execute_ipo((ID *)seq, seq->ipo);
+ }
+
+ if (v->flags & SEQ_SPEED_COMPRESS_IPO_Y) {
+ seq->facf0 *= v->length;
+ }
+ if (!seq->ipo) {
+ seq->facf0 = (float) cfra * fallback_fac;
+ }
+ seq->facf0 *= v->globalSpeed;
+ if (seq->facf0 >= v->length) {
+ seq->facf0 = v->length - 1;
+ } else {
+ v->lastValidFrame = cfra;
+ }
+ v->frameMap[cfra] = seq->facf0;
+ }
+ }
+ seq->facf0 = facf0;
+}
+
+/*
+ simply reuse do_cross_effect for blending...
+
+static void do_speed_effect(Sequence * seq,int cfra,
+ float facf0, float facf1, int x, int y,
+ struct ImBuf *ibuf1, struct ImBuf *ibuf2,
+ struct ImBuf *ibuf3, struct ImBuf *out)
+{
+
+}
+*/
+
+
+/* **********************************************************************
+ sequence effect factory
+ ********************************************************************** */
+
+
+static void init_noop(struct Sequence *seq)
+{
+
+}
+
+static void load_noop(struct Sequence *seq)
+{
+
+}
+
+static void init_plugin_noop(struct Sequence *seq, const char * fname)
+{
+
+}
+
+static void free_noop(struct Sequence *seq)
+{
+
+}
+
+static int num_inputs_default()
+{
+ return 2;
+}
+
+static int early_out_noop(struct Sequence *seq,
+ float facf0, float facf1)
+{
+ return 0;
+}
+
+static int early_out_fade(struct Sequence *seq,
+ float facf0, float facf1)
+{
+ if (facf0 == 0.0 && facf1 == 0.0) {
+ return 1;
+ } else if (facf0 == 1.0 && facf1 == 1.0) {
+ return 2;
+ }
+ return 0;
+}
+
+static int early_out_mul_input2(struct Sequence *seq,
+ float facf0, float facf1)
+{
+ if (facf0 == 0.0 && facf1 == 0.0) {
+ return 1;
+ }
+ return 0;
+}
+
+static void store_icu_yrange_noop(struct Sequence * seq,
+ short adrcode, float * ymin, float * ymax)
+{
+ /* defaults are fine */
+}
+
+static void get_default_fac_noop(struct Sequence *seq, int cfra,
+ float * facf0, float * facf1)
+{
+ *facf0 = *facf1 = 1.0;
+}
+
+static void get_default_fac_fade(struct Sequence *seq, int cfra,
+ float * facf0, float * facf1)
+{
+ *facf0 = (float)(cfra - seq->startdisp);
+ *facf1 = (float)(*facf0 + 0.5);
+ *facf0 /= seq->len;
+ *facf1 /= seq->len;
+}
+
+static void do_overdrop_effect(struct Sequence * seq, int cfra,
+ float fac, float facf,
+ int x, int y, struct ImBuf * ibuf1,
+ struct ImBuf * ibuf2,
+ struct ImBuf * ibuf3,
+ struct ImBuf * out)
+{
+ do_drop_effect(seq, cfra, fac, facf, x, y,
+ ibuf1, ibuf2, ibuf3, out);
+ do_alphaover_effect(seq, cfra, fac, facf, x, y,
+ ibuf1, ibuf2, ibuf3, out);
+}
+
+static struct SeqEffectHandle get_sequence_effect_impl(int seq_type)
+{
+ struct SeqEffectHandle rval;
+ int sequence_type = seq_type;
+
+ rval.init = init_noop;
+ rval.init_plugin = init_plugin_noop;
+ rval.num_inputs = num_inputs_default;
+ rval.load = load_noop;
+ rval.free = free_noop;
+ rval.early_out = early_out_noop;
+ rval.get_default_fac = get_default_fac_noop;
+ rval.store_icu_yrange = store_icu_yrange_noop;
+ rval.execute = NULL;
+ rval.copy = NULL;
+
+ switch (sequence_type) {
+ case SEQ_CROSS:
+ rval.execute = do_cross_effect;
+ rval.early_out = early_out_fade;
+ rval.get_default_fac = get_default_fac_fade;
+ break;
+ case SEQ_GAMCROSS:
+ rval.init = init_gammacross;
+ rval.load = load_gammacross;
+ rval.free = free_gammacross;
+ rval.early_out = early_out_fade;
+ rval.get_default_fac = get_default_fac_fade;
+ rval.execute = do_gammacross_effect;
+ break;
+ case SEQ_ADD:
+ rval.execute = do_add_effect;
+ rval.early_out = early_out_mul_input2;
+ break;
+ case SEQ_SUB:
+ rval.execute = do_sub_effect;
+ rval.early_out = early_out_mul_input2;
+ break;
+ case SEQ_MUL:
+ rval.execute = do_mul_effect;
+ rval.early_out = early_out_mul_input2;
+ break;
+ case SEQ_ALPHAOVER:
+ rval.init = init_alpha_over_or_under;
+ rval.execute = do_alphaover_effect;
+ break;
+ case SEQ_OVERDROP:
+ rval.execute = do_overdrop_effect;
+ break;
+ case SEQ_ALPHAUNDER:
+ rval.init = init_alpha_over_or_under;
+ rval.execute = do_alphaunder_effect;
+ break;
+ case SEQ_WIPE:
+ rval.init = init_wipe_effect;
+ rval.num_inputs = num_inputs_wipe;
+ rval.free = free_wipe_effect;
+ rval.copy = copy_wipe_effect;
+ rval.early_out = early_out_fade;
+ rval.get_default_fac = get_default_fac_fade;
+ rval.execute = do_wipe_effect;
+ break;
+ case SEQ_GLOW:
+ rval.init = init_glow_effect;
+ rval.num_inputs = num_inputs_glow;
+ rval.free = free_glow_effect;
+ rval.copy = copy_glow_effect;
+ rval.execute = do_glow_effect;
+ break;
+ case SEQ_TRANSFORM:
+ rval.init = init_transform_effect;
+ rval.num_inputs = num_inputs_transform;
+ rval.free = free_transform_effect;
+ rval.copy = copy_transform_effect;
+ rval.execute = do_transform_effect;
+ break;
+ case SEQ_SPEED:
+ rval.init = init_speed_effect;
+ rval.num_inputs = num_inputs_speed;
+ rval.load = load_speed_effect;
+ rval.free = free_speed_effect;
+ rval.copy = copy_speed_effect;
+ rval.execute = do_cross_effect;
+ rval.early_out = early_out_speed;
+ rval.store_icu_yrange = store_icu_yrange_speed;
+ break;
+ case SEQ_COLOR:
+ rval.init = init_solid_color;
+ rval.num_inputs = num_inputs_color;
+ rval.early_out = early_out_color;
+ rval.free = free_solid_color;
+ rval.copy = copy_solid_color;
+ rval.execute = do_solid_color;
+ break;
+ case SEQ_PLUGIN:
+ rval.init_plugin = init_plugin;
+ rval.num_inputs = num_inputs_plugin;
+ rval.load = load_plugin;
+ rval.free = free_plugin;
+ rval.copy = copy_plugin;
+ rval.execute = do_plugin_effect;
+ rval.early_out = do_plugin_early_out;
+ rval.get_default_fac = get_default_fac_fade;
+ break;
+ }
+
+ return rval;
+}
+
+
+struct SeqEffectHandle get_sequence_effect(Sequence * seq)
+{
+ struct SeqEffectHandle rval = get_sequence_effect_impl(seq->type);
+
+ if ((seq->flag & SEQ_EFFECT_NOT_LOADED) != 0) {
+ rval.load(seq);
+ seq->flag &= ~SEQ_EFFECT_NOT_LOADED;
+ }
+
+ return rval;
+}
+
+int get_sequence_effect_num_inputs(int seq_type)
+{
+ struct SeqEffectHandle rval = get_sequence_effect_impl(seq_type);
+
+ return rval.num_inputs();
+}
diff --git a/source/blender/src/seqscopes.c b/source/blender/src/seqscopes.c
new file mode 100644
index 00000000000..1fa01a6145e
--- /dev/null
+++ b/source/blender/src/seqscopes.c
@@ -0,0 +1,340 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Author: Peter Schlaile < peter [at] schlaile [dot] de >
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ *
+ */
+
+#include "BSE_seqscopes.h"
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+#include "BKE_utildefines.h"
+#include <math.h>
+#include <string.h>
+
+static void rgb_to_yuv(float rgb[3], float yuv[3]) {
+ yuv[0]= 0.299*rgb[0] + 0.587*rgb[1] + 0.114*rgb[2];
+ yuv[1]= 0.492*(rgb[2] - yuv[0]);
+ yuv[2]= 0.877*(rgb[0] - yuv[0]);
+
+ /* Normalize */
+ yuv[1]*= 255.0/(122*2.0);
+ yuv[1]+= 0.5;
+
+ yuv[2]*= 255.0/(157*2.0);
+ yuv[2]+= 0.5;
+}
+
+static void scope_put_pixel(unsigned char* table, unsigned char * pos)
+{
+ char newval = table[*pos];
+ pos[0] = pos[1] = pos[2] = newval;
+ pos[3] = 255;
+}
+
+static void wform_put_line(int w,
+ unsigned char * last_pos, unsigned char * new_pos)
+{
+ if (last_pos > new_pos) {
+ unsigned char* temp = new_pos;
+ new_pos = last_pos;
+ last_pos = temp;
+ }
+
+ while (last_pos < new_pos) {
+ if (last_pos[0] == 0) {
+ last_pos[0] = last_pos[1] = last_pos[2] = 32;
+ last_pos[3] = 255;
+ }
+ last_pos += 4*w;
+ }
+}
+
+static struct ImBuf *make_waveform_view_from_ibuf_byte(struct ImBuf * ibuf)
+{
+ struct ImBuf * rval = IMB_allocImBuf(ibuf->x + 3, 515, 32, IB_rect, 0);
+ int x,y;
+ unsigned char* src = (unsigned char*) ibuf->rect;
+ unsigned char* tgt = (unsigned char*) rval->rect;
+ int w = ibuf->x + 3;
+ int h = 515;
+ float waveform_gamma = 0.2;
+ unsigned char wtable[256];
+
+ for (x = 0; x < 256; x++) {
+ wtable[x] = (unsigned char) (pow(((float) x + 1)/256,
+ waveform_gamma)*255);
+ }
+
+ for (y = 0; y < ibuf->y; y++) {
+ unsigned char * last_p = 0;
+
+ for (x = 0; x < ibuf->x; x++) {
+ unsigned char * rgb = src + 4 * (ibuf->x * y + x);
+ float v = 1.0 *
+ ( 0.299*rgb[0]
+ + 0.587*rgb[1]
+ + 0.114*rgb[2]) / 255.0;
+ unsigned char * p = tgt;
+ p += 4 * (w * ((int) (v * (h - 3)) + 1) + x + 1);
+
+ scope_put_pixel(wtable, p);
+ p += 4 * w;
+ scope_put_pixel(wtable, p);
+
+ if (last_p != 0) {
+ wform_put_line(w, last_p, p);
+ }
+ last_p = p;
+ }
+ }
+
+ for (x = 0; x < w; x++) {
+ unsigned char * p = tgt + 4 * x;
+ p[1] = p[3] = 255.0;
+ p[4 * w + 1] = p[4 * w + 3] = 255.0;
+ p = tgt + 4 * (w * (h - 1) + x);
+ p[1] = p[3] = 255.0;
+ p[-4 * w + 1] = p[-4 * w + 3] = 255.0;
+ }
+
+ for (y = 0; y < h; y++) {
+ unsigned char * p = tgt + 4 * w * y;
+ p[1] = p[3] = 255.0;
+ p[4 + 1] = p[4 + 3] = 255.0;
+ p = tgt + 4 * (w * y + w - 1);
+ p[1] = p[3] = 255.0;
+ p[-4 + 1] = p[-4 + 3] = 255.0;
+ }
+
+ return rval;
+}
+
+static struct ImBuf *make_waveform_view_from_ibuf_float(struct ImBuf * ibuf)
+{
+ struct ImBuf * rval = IMB_allocImBuf(ibuf->x + 3, 515, 32, IB_rect, 0);
+ int x,y;
+ float* src = ibuf->rect_float;
+ unsigned char* tgt = (unsigned char*) rval->rect;
+ int w = ibuf->x + 3;
+ int h = 515;
+ float waveform_gamma = 0.2;
+ unsigned char wtable[256];
+
+ for (x = 0; x < 256; x++) {
+ wtable[x] = (unsigned char) (pow(((float) x + 1)/256,
+ waveform_gamma)*255);
+ }
+
+ for (y = 0; y < ibuf->y; y++) {
+ unsigned char * last_p = 0;
+
+ for (x = 0; x < ibuf->x; x++) {
+ float * rgb = src + 4 * (ibuf->x * y + x);
+ float v = 1.0 *
+ ( 0.299*rgb[0]
+ + 0.587*rgb[1]
+ + 0.114*rgb[2]);
+ unsigned char * p = tgt;
+
+ CLAMP(v, 0.0, 1.0);
+
+ p += 4 * (w * ((int) (v * (h - 3)) + 1) + x + 1);
+
+ scope_put_pixel(wtable, p);
+ p += 4 * w;
+ scope_put_pixel(wtable, p);
+
+ if (last_p != 0) {
+ wform_put_line(w, last_p, p);
+ }
+ last_p = p;
+ }
+ }
+
+ for (x = 0; x < w; x++) {
+ unsigned char * p = tgt + 4 * x;
+ p[1] = p[3] = 255.0;
+ p[4 * w + 1] = p[4 * w + 3] = 255.0;
+ p = tgt + 4 * (w * (h - 1) + x);
+ p[1] = p[3] = 255.0;
+ p[-4 * w + 1] = p[-4 * w + 3] = 255.0;
+ }
+
+ for (y = 0; y < h; y++) {
+ unsigned char * p = tgt + 4 * w * y;
+ p[1] = p[3] = 255.0;
+ p[4 + 1] = p[4 + 3] = 255.0;
+ p = tgt + 4 * (w * y + w - 1);
+ p[1] = p[3] = 255.0;
+ p[-4 + 1] = p[-4 + 3] = 255.0;
+ }
+
+ return rval;
+}
+
+struct ImBuf *make_waveform_view_from_ibuf(struct ImBuf * ibuf)
+{
+ if (ibuf->rect_float) {
+ return make_waveform_view_from_ibuf_float(ibuf);
+ } else {
+ return make_waveform_view_from_ibuf_byte(ibuf);
+ }
+}
+
+
+static void vectorscope_put_cross(unsigned char r, unsigned char g,
+ unsigned char b,
+ char * tgt, int w, int h, int size)
+{
+ float rgb[3], yuv[3];
+ char * p;
+ int x = 0;
+ int y = 0;
+
+ rgb[0]= (float)r/255.0;
+ rgb[1]= (float)g/255.0;
+ rgb[2]= (float)b/255.0;
+ rgb_to_yuv(rgb, yuv);
+
+ p = tgt + 4 * (w * (int) ((yuv[2] * (h - 3) + 1))
+ + (int) ((yuv[1] * (w - 3) + 1)));
+
+ if (r == 0 && g == 0 && b == 0) {
+ r = 255;
+ }
+
+ for (y = -size; y <= size; y++) {
+ for (x = -size; x <= size; x++) {
+ char * q = p + 4 * (y * w + x);
+ q[0] = r; q[1] = g; q[2] = b; q[3] = 255;
+ }
+ }
+}
+
+static struct ImBuf *make_vectorscope_view_from_ibuf_byte(struct ImBuf * ibuf)
+{
+ struct ImBuf * rval = IMB_allocImBuf(515, 515, 32, IB_rect, 0);
+ int x,y;
+ char* src = (char*) ibuf->rect;
+ char* tgt = (char*) rval->rect;
+ float rgb[3], yuv[3];
+ int w = 515;
+ int h = 515;
+ float scope_gamma = 0.2;
+ unsigned char wtable[256];
+
+ for (x = 0; x < 256; x++) {
+ wtable[x] = (unsigned char) (pow(((float) x + 1)/256,
+ scope_gamma)*255);
+ }
+
+ for (x = 0; x <= 255; x++) {
+ vectorscope_put_cross(255 , 0,255 - x, tgt, w, h, 1);
+ vectorscope_put_cross(255 , x, 0, tgt, w, h, 1);
+ vectorscope_put_cross(255- x, 255, 0, tgt, w, h, 1);
+ vectorscope_put_cross(0, 255, x, tgt, w, h, 1);
+ vectorscope_put_cross(0, 255 - x, 255, tgt, w, h, 1);
+ vectorscope_put_cross(x, 0, 255, tgt, w, h, 1);
+ }
+
+ for (y = 0; y < ibuf->y; y++) {
+ for (x = 0; x < ibuf->x; x++) {
+ char * src1 = src + 4 * (ibuf->x * y + x);
+ char * p;
+
+ rgb[0]= (float)src1[0]/255.0;
+ rgb[1]= (float)src1[1]/255.0;
+ rgb[2]= (float)src1[2]/255.0;
+ rgb_to_yuv(rgb, yuv);
+
+ p = tgt + 4 * (w * (int) ((yuv[2] * (h - 3) + 1))
+ + (int) ((yuv[1] * (w - 3) + 1)));
+ scope_put_pixel(wtable, (unsigned char*)p);
+ }
+ }
+
+ vectorscope_put_cross(0, 0, 0, tgt, w, h, 3);
+
+ return rval;
+}
+
+static struct ImBuf *make_vectorscope_view_from_ibuf_float(struct ImBuf * ibuf)
+{
+ struct ImBuf * rval = IMB_allocImBuf(515, 515, 32, IB_rect, 0);
+ int x,y;
+ float* src = ibuf->rect_float;
+ char* tgt = (char*) rval->rect;
+ float rgb[3], yuv[3];
+ int w = 515;
+ int h = 515;
+ float scope_gamma = 0.2;
+ unsigned char wtable[256];
+
+ for (x = 0; x < 256; x++) {
+ wtable[x] = (unsigned char) (pow(((float) x + 1)/256,
+ scope_gamma)*255);
+ }
+
+ for (x = 0; x <= 255; x++) {
+ vectorscope_put_cross(255 , 0,255 - x, tgt, w, h, 1);
+ vectorscope_put_cross(255 , x, 0, tgt, w, h, 1);
+ vectorscope_put_cross(255- x, 255, 0, tgt, w, h, 1);
+ vectorscope_put_cross(0, 255, x, tgt, w, h, 1);
+ vectorscope_put_cross(0, 255 - x, 255, tgt, w, h, 1);
+ vectorscope_put_cross(x, 0, 255, tgt, w, h, 1);
+ }
+
+ for (y = 0; y < ibuf->y; y++) {
+ for (x = 0; x < ibuf->x; x++) {
+ float * src1 = src + 4 * (ibuf->x * y + x);
+ char * p;
+
+ memcpy(rgb, src1, 3 * sizeof(float));
+
+ CLAMP(rgb[0], 0.0, 1.0);
+ CLAMP(rgb[1], 0.0, 1.0);
+ CLAMP(rgb[2], 0.0, 1.0);
+
+ rgb_to_yuv(rgb, yuv);
+
+ p = tgt + 4 * (w * (int) ((yuv[2] * (h - 3) + 1))
+ + (int) ((yuv[1] * (w - 3) + 1)));
+ scope_put_pixel(wtable, (unsigned char*)p);
+ }
+ }
+
+ vectorscope_put_cross(0, 0, 0, tgt, w, h, 3);
+
+ return rval;
+}
+
+struct ImBuf *make_vectorscope_view_from_ibuf(struct ImBuf * ibuf)
+{
+ if (ibuf->rect_float) {
+ return make_vectorscope_view_from_ibuf_float(ibuf);
+ } else {
+ return make_vectorscope_view_from_ibuf_byte(ibuf);
+ }
+}
diff --git a/source/blender/src/sequence.c b/source/blender/src/sequence.c
new file mode 100644
index 00000000000..e93cc1b1075
--- /dev/null
+++ b/source/blender/src/sequence.c
@@ -0,0 +1,1713 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Peter Schlaile <peter [at] schlaile [dot] de> 2005/2006
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <string.h>
+#include <math.h>
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+#include "MEM_CacheLimiterC-Api.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "DNA_ipo_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_sequence_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_global.h"
+#include "BKE_image.h"
+#include "BKE_ipo.h"
+#include "BKE_main.h"
+#include "BKE_scene.h"
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_editsound.h"
+#include "BIF_editseq.h"
+#include "BSE_filesel.h"
+#include "BSE_headerbuttons.h"
+#include "BIF_interface.h"
+#include "BIF_renderwin.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_toolbox.h"
+
+#include "BSE_sequence.h"
+#include "BSE_seqeffects.h"
+
+#include "RE_pipeline.h" // talks to entire render API
+
+#include "blendef.h"
+
+#include <pthread.h>
+
+int seqrectx, seqrecty;
+
+void free_stripdata(int len, StripElem *se)
+{
+ StripElem *seo;
+ int a;
+
+ seo= se;
+
+ for(a=0; a<len; a++, se++) {
+ if(se->ibuf && se->ok!=2) {
+ IMB_freeImBuf(se->ibuf);
+ se->ibuf = 0;
+ }
+ }
+
+ MEM_freeN(seo);
+
+}
+
+void free_strip(Strip *strip)
+{
+ strip->us--;
+ if(strip->us>0) return;
+ if(strip->us<0) {
+ printf("error: negative users in strip\n");
+ return;
+ }
+
+ if(strip->stripdata) {
+ free_stripdata(strip->len, strip->stripdata);
+ }
+ MEM_freeN(strip);
+}
+
+void new_stripdata(Sequence *seq)
+{
+ if(seq->strip) {
+ if(seq->strip->stripdata) free_stripdata(seq->strip->len, seq->strip->stripdata);
+ seq->strip->stripdata= 0;
+ seq->strip->len= seq->len;
+ if(seq->len>0) seq->strip->stripdata= MEM_callocN(seq->len*sizeof(StripElem), "stripelems");
+ }
+}
+
+void free_sequence(Sequence *seq)
+{
+ Sequence *last_seq = get_last_seq();
+
+ if(seq->strip) free_strip(seq->strip);
+
+ if(seq->anim) IMB_free_anim(seq->anim);
+ if(seq->hdaudio) sound_close_hdaudio(seq->hdaudio);
+
+ if (seq->type & SEQ_EFFECT) {
+ struct SeqEffectHandle sh = get_sequence_effect(seq);
+
+ sh.free(seq);
+ }
+
+ if(seq==last_seq) set_last_seq(NULL);
+
+ MEM_freeN(seq);
+}
+
+/*
+ **********************************************************************
+ * build_seqar
+ **********************************************************************
+ * Build a complete array of _all_ sequencies (including those
+ * in metastrips!)
+ **********************************************************************
+*/
+
+static void do_seq_count(ListBase *seqbase, int *totseq)
+{
+ Sequence *seq;
+
+ seq= seqbase->first;
+ while(seq) {
+ (*totseq)++;
+ if(seq->seqbase.first) do_seq_count(&seq->seqbase, totseq);
+ seq= seq->next;
+ }
+}
+
+static void do_build_seqar(ListBase *seqbase, Sequence ***seqar, int depth)
+{
+ Sequence *seq;
+
+ seq= seqbase->first;
+ while(seq) {
+ seq->depth= depth;
+ if(seq->seqbase.first) do_build_seqar(&seq->seqbase, seqar, depth+1);
+ **seqar= seq;
+ (*seqar)++;
+ seq= seq->next;
+ }
+}
+
+void build_seqar(ListBase *seqbase, Sequence ***seqar, int *totseq)
+{
+ Sequence **tseqar;
+
+ *totseq= 0;
+ do_seq_count(seqbase, totseq);
+
+ if(*totseq==0) {
+ *seqar= 0;
+ return;
+ }
+ *seqar= MEM_mallocN(sizeof(void *)* *totseq, "seqar");
+ tseqar= *seqar;
+
+ do_build_seqar(seqbase, seqar, 0);
+ *seqar= tseqar;
+}
+
+void free_editing(Editing *ed)
+{
+ MetaStack *ms;
+ Sequence *seq;
+
+ if(ed==NULL) return;
+ set_last_seq(NULL); /* clear_last_seq doesnt work, it screws up free_sequence */
+
+ WHILE_SEQ(&ed->seqbase) {
+ free_sequence(seq);
+ }
+ END_SEQ
+
+ while( (ms= ed->metastack.first) ) {
+ BLI_remlink(&ed->metastack, ms);
+ MEM_freeN(ms);
+ }
+
+ MEM_freeN(ed);
+
+}
+
+void calc_sequence_disp(Sequence *seq)
+{
+ if(seq->startofs && seq->startstill) seq->startstill= 0;
+ if(seq->endofs && seq->endstill) seq->endstill= 0;
+
+ seq->startdisp= seq->start + seq->startofs - seq->startstill;
+ seq->enddisp= seq->start+seq->len - seq->endofs + seq->endstill;
+
+ seq->handsize= 10.0; /* 10 frames */
+ if( seq->enddisp-seq->startdisp < 10 ) {
+ seq->handsize= (float)(0.5*(seq->enddisp-seq->startdisp));
+ }
+ else if(seq->enddisp-seq->startdisp > 250) {
+ seq->handsize= (float)((seq->enddisp-seq->startdisp)/25);
+ }
+}
+
+void calc_sequence(Sequence *seq)
+{
+ Sequence *seqm;
+ int min, max;
+
+ /* check all metas recursively */
+ seqm= seq->seqbase.first;
+ while(seqm) {
+ if(seqm->seqbase.first) calc_sequence(seqm);
+ seqm= seqm->next;
+ }
+
+ /* effects and meta: automatic start and end */
+
+ if(seq->type & SEQ_EFFECT) {
+ /* pointers */
+ if(seq->seq2==0) seq->seq2= seq->seq1;
+ if(seq->seq3==0) seq->seq3= seq->seq1;
+
+ /* effecten go from seq1 -> seq2: test */
+
+ /* we take the largest start and smallest end */
+
+ // seq->start= seq->startdisp= MAX2(seq->seq1->startdisp, seq->seq2->startdisp);
+ // seq->enddisp= MIN2(seq->seq1->enddisp, seq->seq2->enddisp);
+
+ if (seq->seq1) {
+ seq->start= seq->startdisp= MAX3(seq->seq1->startdisp, seq->seq2->startdisp, seq->seq3->startdisp);
+ seq->enddisp= MIN3(seq->seq1->enddisp, seq->seq2->enddisp, seq->seq3->enddisp);
+ seq->len= seq->enddisp - seq->startdisp;
+ } else {
+ calc_sequence_disp(seq);
+ }
+
+ if(seq->strip && seq->len!=seq->strip->len) {
+ new_stripdata(seq);
+ }
+
+ }
+ else {
+ if(seq->type==SEQ_META) {
+ seqm= seq->seqbase.first;
+ if(seqm) {
+ min= 1000000;
+ max= -1000000;
+ while(seqm) {
+ if(seqm->startdisp < min) min= seqm->startdisp;
+ if(seqm->enddisp > max) max= seqm->enddisp;
+ seqm= seqm->next;
+ }
+ seq->start= min;
+ seq->len= max-min;
+
+ if(seq->strip && seq->len!=seq->strip->len) {
+ new_stripdata(seq);
+ }
+ }
+ }
+ calc_sequence_disp(seq);
+ }
+}
+
+void sort_seq()
+{
+ /* all strips together per kind, and in order of y location ("machine") */
+ ListBase seqbase, effbase;
+ Editing *ed;
+ Sequence *seq, *seqt;
+
+ ed= G.scene->ed;
+ if(ed==0) return;
+
+ seqbase.first= seqbase.last= 0;
+ effbase.first= effbase.last= 0;
+
+ while( (seq= ed->seqbasep->first) ) {
+ BLI_remlink(ed->seqbasep, seq);
+
+ if(seq->type & SEQ_EFFECT) {
+ seqt= effbase.first;
+ while(seqt) {
+ if(seqt->machine>=seq->machine) {
+ BLI_insertlinkbefore(&effbase, seqt, seq);
+ break;
+ }
+ seqt= seqt->next;
+ }
+ if(seqt==0) BLI_addtail(&effbase, seq);
+ }
+ else {
+ seqt= seqbase.first;
+ while(seqt) {
+ if(seqt->machine>=seq->machine) {
+ BLI_insertlinkbefore(&seqbase, seqt, seq);
+ break;
+ }
+ seqt= seqt->next;
+ }
+ if(seqt==0) BLI_addtail(&seqbase, seq);
+ }
+ }
+
+ addlisttolist(&seqbase, &effbase);
+ *(ed->seqbasep)= seqbase;
+}
+
+
+void clear_scene_in_allseqs(Scene *sce)
+{
+ Scene *sce1;
+ Editing *ed;
+ Sequence *seq;
+
+ /* when a scene is deleted: test all seqs */
+
+ sce1= G.main->scene.first;
+ while(sce1) {
+ if(sce1!=sce && sce1->ed) {
+ ed= sce1->ed;
+
+ WHILE_SEQ(&ed->seqbase) {
+
+ if(seq->scene==sce) seq->scene= 0;
+
+ }
+ END_SEQ
+ }
+
+ sce1= sce1->id.next;
+ }
+}
+
+/* ***************** DO THE SEQUENCE ***************** */
+
+static void make_black_ibuf(ImBuf *ibuf)
+{
+ unsigned int *rect;
+ float *rect_float;
+ int tot;
+
+ if(ibuf==0 || (ibuf->rect==0 && ibuf->rect_float==0)) return;
+
+ tot= ibuf->x*ibuf->y;
+
+ rect= ibuf->rect;
+ rect_float = ibuf->rect_float;
+
+ if (rect) {
+ memset(rect, 0, tot * sizeof(char) * 4);
+ }
+
+ if (rect_float) {
+ memset(rect_float, 0, tot * sizeof(float) * 4);
+ }
+}
+
+static void multibuf(ImBuf *ibuf, float fmul)
+{
+ char *rt;
+ float *rt_float;
+
+ int a, mul, icol;
+
+ mul= (int)(256.0*fmul);
+
+ a= ibuf->x*ibuf->y;
+ rt= (char *)ibuf->rect;
+ rt_float = ibuf->rect_float;
+
+ if (rt) {
+ while(a--) {
+
+ icol= (mul*rt[0])>>8;
+ if(icol>254) rt[0]= 255; else rt[0]= icol;
+ icol= (mul*rt[1])>>8;
+ if(icol>254) rt[1]= 255; else rt[1]= icol;
+ icol= (mul*rt[2])>>8;
+ if(icol>254) rt[2]= 255; else rt[2]= icol;
+ icol= (mul*rt[3])>>8;
+ if(icol>254) rt[3]= 255; else rt[3]= icol;
+
+ rt+= 4;
+ }
+ }
+ if (rt_float) {
+ while(a--) {
+ rt_float[0] *= fmul;
+ rt_float[1] *= fmul;
+ rt_float[2] *= fmul;
+ rt_float[3] *= fmul;
+
+ rt_float += 4;
+ }
+ }
+}
+
+static void do_effect(int cfra, Sequence *seq, StripElem *se)
+{
+ StripElem *se1, *se2, *se3;
+ float fac, facf;
+ int x, y;
+ int early_out;
+ struct SeqEffectHandle sh = get_sequence_effect(seq);
+
+ if (!sh.execute) { /* effect not supported in this version... */
+ make_black_ibuf(se->ibuf);
+ return;
+ }
+
+ if(seq->ipo && seq->ipo->curve.first) {
+ do_seq_ipo(seq);
+ fac= seq->facf0;
+ facf= seq->facf1;
+ } else {
+ sh.get_default_fac(seq, cfra, &fac, &facf);
+ }
+
+ if( !(G.scene->r.mode & R_FIELDS) ) facf = fac;
+
+ early_out = sh.early_out(seq, fac, facf);
+
+ if (early_out == -1) { /* no input needed */
+ sh.execute(seq, cfra, fac, facf, se->ibuf->x, se->ibuf->y,
+ 0, 0, 0, se->ibuf);
+ return;
+ }
+
+ switch (early_out) {
+ case 0:
+ if (se->se1==0 || se->se2==0 || se->se3==0) {
+ make_black_ibuf(se->ibuf);
+ return;
+ }
+
+ /* if metastrip: other se's */
+ if(se->se1->ok==2) se1= se->se1->se1;
+ else se1= se->se1;
+
+ if(se->se2->ok==2) se2= se->se2->se1;
+ else se2= se->se2;
+
+ if(se->se3->ok==2) se3= se->se3->se1;
+ else se3= se->se3;
+
+ if ( (se1==0 || se2==0 || se3==0)
+ || (se1->ibuf==0 || se2->ibuf==0 || se3->ibuf==0)) {
+ make_black_ibuf(se->ibuf);
+ return;
+ }
+
+ break;
+ case 1:
+ if (se->se1 == 0) {
+ make_black_ibuf(se->ibuf);
+ return;
+ }
+
+ /* if metastrip: other se's */
+ if(se->se1->ok==2) se1= se->se1->se1;
+ else se1= se->se1;
+
+ if (se1 == 0 || se1->ibuf == 0) {
+ make_black_ibuf(se->ibuf);
+ return;
+ }
+
+ if (se->ibuf != se1->ibuf) {
+ IMB_freeImBuf(se->ibuf);
+ se->ibuf = se1->ibuf;
+ IMB_refImBuf(se->ibuf);
+ }
+ return;
+ case 2:
+ if (se->se2 == 0) {
+ make_black_ibuf(se->ibuf);
+ return;
+ }
+
+ /* if metastrip: other se's */
+ if(se->se2->ok==2) se2= se->se2->se1;
+ else se2= se->se2;
+
+ if (se2 == 0 || se2->ibuf == 0) {
+ make_black_ibuf(se->ibuf);
+ return;
+ }
+ if (se->ibuf != se2->ibuf) {
+ IMB_freeImBuf(se->ibuf);
+ se->ibuf = se2->ibuf;
+ IMB_refImBuf(se->ibuf);
+ }
+ return;
+ default:
+ make_black_ibuf(se->ibuf);
+ return;
+ }
+
+ x= se2->ibuf->x;
+ y= se2->ibuf->y;
+
+ if (!se1->ibuf->rect_float && se->ibuf->rect_float) {
+ IMB_float_from_rect(se1->ibuf);
+ }
+ if (!se2->ibuf->rect_float && se->ibuf->rect_float) {
+ IMB_float_from_rect(se2->ibuf);
+ }
+
+ if (!se1->ibuf->rect && !se->ibuf->rect_float) {
+ IMB_rect_from_float(se1->ibuf);
+ }
+ if (!se2->ibuf->rect && !se->ibuf->rect_float) {
+ IMB_rect_from_float(se2->ibuf);
+ }
+
+ sh.execute(seq, cfra, fac, facf, x, y, se1->ibuf, se2->ibuf, se3->ibuf,
+ se->ibuf);
+}
+
+StripElem *give_stripelem(Sequence *seq, int cfra)
+{
+ Strip *strip;
+ StripElem *se;
+ int nr;
+
+ strip= seq->strip;
+ se= strip->stripdata;
+
+ if(se==0) return 0;
+ if(seq->startdisp >cfra || seq->enddisp <= cfra) return 0;
+
+ if(seq->flag&SEQ_REVERSE_FRAMES) {
+ /*reverse frame in this sequence */
+ if(cfra <= seq->start) nr= seq->len-1;
+ else if(cfra >= seq->start+seq->len-1) nr= 0;
+ else nr= (seq->start + seq->len) - cfra;
+ } else {
+ if(cfra <= seq->start) nr= 0;
+ else if(cfra >= seq->start+seq->len-1) nr= seq->len-1;
+ else nr= cfra-seq->start;
+ }
+ if (seq->strobe < 1.0) seq->strobe = 1.0;
+ if (seq->strobe > 1.0) {
+ nr -= (int)fmod((double)nr, (double)seq->strobe);
+ }
+
+ se+= nr; /* don't get confused by the increment, this is the same as strip->stripdata[nr], which works on some compilers...*/
+ se->nr= nr;
+
+ return se;
+}
+
+static int evaluate_seq_frame_gen(
+ Sequence ** seq_arr, ListBase *seqbase, int cfra)
+{
+ Sequence *seq;
+ int totseq=0;
+
+ memset(seq_arr, 0, sizeof(Sequence*) * MAXSEQ);
+
+ seq= seqbase->first;
+ while(seq) {
+ if(seq->startdisp <=cfra && seq->enddisp > cfra) {
+ seq_arr[seq->machine]= seq;
+ totseq++;
+ }
+ seq= seq->next;
+ }
+
+ return totseq;
+}
+
+int evaluate_seq_frame(int cfra)
+{
+ Editing *ed;
+ Sequence *seq_arr[MAXSEQ+1];
+
+ ed= G.scene->ed;
+ if(ed==0) return 0;
+
+ return evaluate_seq_frame_gen(seq_arr, ed->seqbasep, cfra);
+
+}
+
+Sequence *get_shown_sequence(ListBase * seqbasep, int cfra, int chanshown)
+{
+ Sequence *seq, *seqim, *seqeff;
+ Sequence *seq_arr[MAXSEQ+1];
+ int b;
+
+ seq = 0;
+
+ if (chanshown > MAXSEQ) {
+ return 0;
+ }
+
+ if(evaluate_seq_frame_gen(seq_arr, seqbasep, cfra)) {
+ if (chanshown > 0) {
+ return seq_arr[chanshown];
+ }
+
+ /* we take the upper effect strip or
+ the lowest imagestrip/metastrip */
+ seqim= seqeff= 0;
+
+ for(b=1; b<MAXSEQ; b++) {
+ if(seq_arr[b]) {
+ seq= seq_arr[b];
+ if(seq->type & SEQ_EFFECT) {
+ if(seqeff==0) seqeff= seq;
+ else if(seqeff->machine < seq->machine)
+ seqeff= seq;
+ } else if (seq->type != SEQ_RAM_SOUND && seq->type != SEQ_HD_SOUND) {
+ if(seqim==0) seqim= seq;
+ else if(seqim->machine > seq->machine)
+ seqim= seq;
+ }
+ }
+ }
+ if(seqeff) seq= seqeff;
+ else if(seqim) seq= seqim;
+ else seq= 0;
+ }
+
+ return seq;
+}
+
+static Sequence * get_shown_seq_from_metastrip(Sequence * seqm, int cfra)
+{
+ return get_shown_sequence(&seqm->seqbase, cfra, 0);
+}
+
+void set_meta_stripdata(Sequence *seqm)
+{
+ Sequence *seq;
+ StripElem *se;
+ int a, cfra;
+
+ /* sets all ->se1 pointers in stripdata, to read the ibuf from it */
+
+ se= seqm->strip->stripdata;
+ for(a=0; a<seqm->len; a++, se++) {
+ cfra= a+seqm->start;
+ seq = get_shown_seq_from_metastrip(seqm, cfra);
+ if (seq) {
+ se->se1= give_stripelem(seq, cfra);
+ } else {
+ se->se1= 0;
+ }
+ }
+}
+
+static void do_build_seq_ibuf(Sequence * seq, int cfra)
+{
+ StripElem *se = seq->curelem;
+ char name[FILE_MAXDIR+FILE_MAXFILE];
+
+ if(seq->type == SEQ_META) {
+ se->ok= 2;
+ if(se->se1==0) set_meta_stripdata(seq);
+ if(se->se1) {
+ se->ibuf= se->se1->ibuf;
+ }
+ } else if(seq->type == SEQ_RAM_SOUND || seq->type == SEQ_HD_SOUND) {
+ se->ok= 2;
+ } else if(seq->type & SEQ_EFFECT) {
+
+ /* test if image is too small or discarded from cache: reload */
+ if(se->ibuf) {
+ if(se->ibuf->x < seqrectx || se->ibuf->y < seqrecty || !(se->ibuf->rect || se->ibuf->rect_float)) {
+ IMB_freeImBuf(se->ibuf);
+ se->ibuf= 0;
+ }
+ }
+
+ /* should the effect be recalculated? */
+
+ if(se->ibuf==0
+ || (seq->seq1 && se->se1 != seq->seq1->curelem)
+ || (seq->seq2 && se->se2 != seq->seq2->curelem)
+ || (seq->seq3 && se->se3 != seq->seq3->curelem)) {
+ if (seq->seq1) se->se1= seq->seq1->curelem;
+ if (seq->seq2) se->se2= seq->seq2->curelem;
+ if (seq->seq3) se->se3= seq->seq3->curelem;
+
+ if(se->ibuf==NULL) {
+ /* if one of two first inputs are rectfloat, output is float too */
+ if((se->se1 && se->se1->ibuf && se->se1->ibuf->rect_float) ||
+ (se->se2 && se->se2->ibuf && se->se2->ibuf->rect_float))
+ se->ibuf= IMB_allocImBuf((short)seqrectx, (short)seqrecty, 32, IB_rectfloat, 0);
+ else
+ se->ibuf= IMB_allocImBuf((short)seqrectx, (short)seqrecty, 32, IB_rect, 0);
+ }
+
+ do_effect(cfra, seq, se);
+ }
+
+ /* test size */
+ if(se->ibuf) {
+ if(se->ibuf->x != seqrectx || se->ibuf->y != seqrecty ) {
+ if(G.scene->r.mode & R_OSA) {
+ IMB_scaleImBuf(se->ibuf, (short)seqrectx, (short)seqrecty);
+ } else {
+ IMB_scalefastImBuf(se->ibuf, (short)seqrectx, (short)seqrecty);
+ }
+ }
+ }
+ } else if(seq->type < SEQ_EFFECT) {
+ if(se->ibuf) {
+ /* test if image too small
+ or discarded from cache: reload */
+ if(se->ibuf->x < seqrectx || se->ibuf->y < seqrecty || !(se->ibuf->rect || se->ibuf->rect_float)) {
+ IMB_freeImBuf(se->ibuf);
+ se->ibuf= 0;
+ se->ok= 1;
+ }
+ }
+
+ if(seq->type==SEQ_IMAGE) {
+ if(se->ok && se->ibuf==0) {
+ /* if playanim or render:
+ no waitcursor */
+ if((G.f & G_PLAYANIM)==0)
+ waitcursor(1);
+
+ strncpy(name, seq->strip->dir, FILE_MAXDIR-1);
+ strncat(name, se->name, FILE_MAXFILE);
+ BLI_convertstringcode(name, G.sce, G.scene->r.cfra);
+ se->ibuf= IMB_loadiffname(name, IB_rect);
+
+ if((G.f & G_PLAYANIM)==0)
+ waitcursor(0);
+
+ if(se->ibuf==0) se->ok= 0;
+ else {
+ if(seq->flag & SEQ_MAKE_PREMUL) {
+ if(se->ibuf->depth==32 && se->ibuf->zbuf==0) converttopremul(se->ibuf);
+ }
+ seq->strip->orx= se->ibuf->x;
+ seq->strip->ory= se->ibuf->y;
+ if(seq->flag & SEQ_FILTERY) IMB_filtery(se->ibuf);
+ if(seq->flag & SEQ_FLIPX) IMB_flipx(se->ibuf);
+ if(seq->flag & SEQ_FLIPY) IMB_flipy(se->ibuf);
+ if(seq->mul==0.0) seq->mul= 1.0;
+ if(seq->mul != 1.0) multibuf(se->ibuf, seq->mul);
+ }
+ }
+ }
+ else if(seq->type==SEQ_MOVIE) {
+ if(se->ok && se->ibuf==0) {
+ if(seq->anim==0) {
+ strncpy(name, seq->strip->dir, FILE_MAXDIR-1);
+ strncat(name, seq->strip->stripdata->name, FILE_MAXFILE-1);
+ BLI_convertstringcode(name, G.sce, G.scene->r.cfra);
+
+ seq->anim = openanim(name, IB_rect);
+ }
+ if(seq->anim) {
+ IMB_anim_set_preseek(seq->anim, seq->anim_preseek);
+ se->ibuf = IMB_anim_absolute(seq->anim, se->nr);
+ }
+
+ if(se->ibuf==0) se->ok= 0;
+ else {
+ if(seq->flag & SEQ_MAKE_PREMUL) {
+ if(se->ibuf->depth==32) converttopremul(se->ibuf);
+ }
+ seq->strip->orx= se->ibuf->x;
+ seq->strip->ory= se->ibuf->y;
+ if(seq->flag & SEQ_FILTERY) IMB_filtery(se->ibuf);
+ if(seq->mul==0.0) seq->mul= 1.0;
+ if(seq->mul != 1.0) multibuf(se->ibuf, seq->mul);
+ }
+ }
+ } else if(seq->type==SEQ_SCENE && se->ibuf==NULL && seq->scene) { // scene can be NULL after deletions
+ int oldcfra = CFRA;
+ Scene *sce= seq->scene, *oldsce= G.scene;
+ Render *re;
+ RenderResult rres;
+ int doseq, rendering= G.rendering;
+ char scenename[64];
+
+ waitcursor(1);
+
+ /* Hack! This function can be called from do_render_seq(), in that case
+ the seq->scene can already have a Render initialized with same name,
+ so we have to use a default name. (compositor uses G.scene name to
+ find render).
+ However, when called from within the UI (image preview in sequencer)
+ we do want to use scene Render, that way the render result is defined
+ for display in render/imagewindow */
+ if(rendering) {
+ BLI_strncpy(scenename, sce->id.name+2, 64);
+ strcpy(sce->id.name+2, " do_build_seq_ibuf");
+ }
+ re= RE_NewRender(sce->id.name);
+
+ /* prevent eternal loop */
+ doseq= G.scene->r.scemode & R_DOSEQ;
+ G.scene->r.scemode &= ~R_DOSEQ;
+
+ BIF_init_render_callbacks(re, 0); /* 0= no display callbacks */
+
+ /* hrms, set_scene still needed? work on that... */
+ if(sce!=oldsce) set_scene_bg(sce);
+ RE_BlenderFrame(re, sce, seq->sfra + se->nr);
+ if(sce!=oldsce) set_scene_bg(oldsce);
+
+ /* UGLY WARNING, it is set to zero in RE_BlenderFrame */
+ G.rendering= rendering;
+ if(rendering)
+ BLI_strncpy(sce->id.name+2, scenename, 64);
+
+ RE_GetResultImage(re, &rres);
+
+ if(rres.rectf) {
+ se->ibuf= IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rectfloat, 0);
+ memcpy(se->ibuf->rect_float, rres.rectf, 4*sizeof(float)*rres.rectx*rres.recty);
+ if(rres.rectz) {
+ addzbuffloatImBuf(se->ibuf);
+ memcpy(se->ibuf->zbuf_float, rres.rectz, sizeof(float)*rres.rectx*rres.recty);
+ }
+ } else if (rres.rect32) {
+ se->ibuf= IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rect, 0);
+ memcpy(se->ibuf->rect, rres.rect32, 4*rres.rectx*rres.recty);
+ }
+
+ BIF_end_render_callbacks();
+
+ /* restore */
+ G.scene->r.scemode |= doseq;
+
+ if((G.f & G_PLAYANIM)==0) /* bad, is set on do_render_seq */
+ waitcursor(0);
+ CFRA = oldcfra;
+ }
+
+ /* size test */
+ if(se->ibuf) {
+ if(se->ibuf->x != seqrectx || se->ibuf->y != seqrecty ) {
+
+ if (0) { // G.scene->r.mode & R_FIELDS) {
+
+ if (seqrecty > 288)
+ IMB_scalefieldImBuf(se->ibuf, (short)seqrectx, (short)seqrecty);
+ else {
+ IMB_de_interlace(se->ibuf);
+
+ if(G.scene->r.mode & R_OSA)
+ IMB_scaleImBuf(se->ibuf, (short)seqrectx, (short)seqrecty);
+ else
+ IMB_scalefastImBuf(se->ibuf, (short)seqrectx, (short)seqrecty);
+ }
+ }
+ else {
+ if(G.scene->r.mode & R_OSA)
+ IMB_scaleImBuf(se->ibuf,(short)seqrectx, (short)seqrecty);
+ else
+ IMB_scalefastImBuf(se->ibuf, (short)seqrectx, (short)seqrecty);
+ }
+ }
+
+ }
+ }
+ if (se->ibuf) {
+ IMB_cache_limiter_insert(se->ibuf);
+ IMB_cache_limiter_ref(se->ibuf);
+ IMB_cache_limiter_touch(se->ibuf);
+ }
+}
+
+static void do_build_seq_recursively(Sequence * seq, int cfra);
+
+static void do_effect_seq_recursively(int cfra, Sequence * seq, StripElem *se)
+{
+ float fac, facf;
+ struct SeqEffectHandle sh = get_sequence_effect(seq);
+ int early_out;
+
+ if(seq->ipo && seq->ipo->curve.first) {
+ do_seq_ipo(seq);
+ fac= seq->facf0;
+ facf= seq->facf1;
+ } else {
+ sh.get_default_fac(seq, cfra, &fac, &facf);
+ }
+
+ if( G.scene->r.mode & R_FIELDS ); else facf= fac;
+
+ early_out = sh.early_out(seq, fac, facf);
+ switch (early_out) {
+ case -1:
+ /* no input needed */
+ break;
+ case 0:
+ do_build_seq_recursively(seq->seq1, cfra);
+ do_build_seq_recursively(seq->seq2, cfra);
+ if (seq->seq3) {
+ do_build_seq_recursively(seq->seq3, cfra);
+ }
+ break;
+ case 1:
+ do_build_seq_recursively(seq->seq1, cfra);
+ break;
+ case 2:
+ do_build_seq_recursively(seq->seq2, cfra);
+ break;
+ }
+
+
+ do_build_seq_ibuf(seq, cfra);
+
+ /* children are not needed anymore ... */
+
+ switch (early_out) {
+ case 0:
+ if (seq->seq1->curelem && seq->seq1->curelem->ibuf)
+ IMB_cache_limiter_unref(seq->seq1->curelem->ibuf);
+ if (seq->seq2->curelem && seq->seq2->curelem->ibuf)
+ IMB_cache_limiter_unref(seq->seq2->curelem->ibuf);
+ if (seq->seq3) {
+ if (seq->seq3->curelem && seq->seq3->curelem->ibuf)
+ IMB_cache_limiter_unref(
+ seq->seq3->curelem->ibuf);
+ }
+ break;
+ case 1:
+ if (seq->seq1->curelem && seq->seq1->curelem->ibuf)
+ IMB_cache_limiter_unref(seq->seq1->curelem->ibuf);
+ break;
+ case 2:
+ if (seq->seq2->curelem && seq->seq2->curelem->ibuf)
+ IMB_cache_limiter_unref(seq->seq2->curelem->ibuf);
+ break;
+ }
+}
+
+static void do_build_seq_recursively_impl(Sequence * seq, int cfra)
+{
+ StripElem *se;
+
+ se = seq->curelem = give_stripelem(seq, cfra);
+
+ if(se) {
+ int unref_meta = FALSE;
+ if(seq->seqbase.first) {
+ Sequence * seqmshown= get_shown_seq_from_metastrip(seq, cfra);
+ if (seqmshown) {
+ if(cfra< seq->start)
+ do_build_seq_recursively(seqmshown, seq->start);
+ else if(cfra> seq->start+seq->len-1)
+ do_build_seq_recursively(seqmshown, seq->start + seq->len-1);
+ else do_build_seq_recursively(seqmshown, cfra);
+
+ unref_meta = TRUE;
+ }
+ }
+
+ if (seq->type & SEQ_EFFECT) {
+ do_effect_seq_recursively(cfra, seq, se);
+ } else {
+ do_build_seq_ibuf(seq, cfra);
+ }
+
+ if(unref_meta && seq->curelem->ibuf) {
+ IMB_cache_limiter_unref(seq->curelem->ibuf);
+ }
+ }
+}
+
+/* FIXME:
+
+If cfra was float throughout blender (especially in the render
+pipeline) one could even _render_ with subframe precision
+instead of faking using the blend code below...
+
+*/
+
+static void do_handle_speed_effect(Sequence * seq, int cfra)
+{
+ SpeedControlVars * s = (SpeedControlVars *)seq->effectdata;
+ int nr = cfra - seq->start;
+ float f_cfra;
+ int cfra_left;
+ int cfra_right;
+ StripElem * se = 0;
+ StripElem * se1 = 0;
+ StripElem * se2 = 0;
+
+ sequence_effect_speed_rebuild_map(seq, 0);
+
+ f_cfra = seq->start + s->frameMap[nr];
+
+ cfra_left = (int) floor(f_cfra);
+ cfra_right = (int) ceil(f_cfra);
+
+ se = seq->curelem = give_stripelem(seq, cfra);
+
+ if (cfra_left == cfra_right ||
+ (s->flags & SEQ_SPEED_BLEND) == 0) {
+ if(se->ibuf) {
+ if(se->ibuf->x < seqrectx || se->ibuf->y < seqrecty
+ || !(se->ibuf->rect || se->ibuf->rect_float)) {
+ IMB_freeImBuf(se->ibuf);
+ se->ibuf= 0;
+ }
+ }
+
+ if (se->ibuf == NULL) {
+ do_build_seq_recursively_impl(seq->seq1, cfra_left);
+
+ se1 = seq->seq1->curelem;
+
+ if((se1 && se1->ibuf && se1->ibuf->rect_float))
+ se->ibuf= IMB_allocImBuf((short)seqrectx, (short)seqrecty, 32, IB_rectfloat, 0);
+ else
+ se->ibuf= IMB_allocImBuf((short)seqrectx, (short)seqrecty, 32, IB_rect, 0);
+
+ if (se1 == 0 || se1->ibuf == 0) {
+ make_black_ibuf(se->ibuf);
+ } else {
+ if (se->ibuf != se1->ibuf) {
+ if (se->ibuf) {
+ IMB_freeImBuf(se->ibuf);
+ }
+
+ se->ibuf = se1->ibuf;
+ IMB_refImBuf(se->ibuf);
+ }
+ }
+ }
+ } else {
+ struct SeqEffectHandle sh;
+
+ if(se->ibuf) {
+ if(se->ibuf->x < seqrectx || se->ibuf->y < seqrecty
+ || !(se->ibuf->rect || se->ibuf->rect_float)) {
+ IMB_freeImBuf(se->ibuf);
+ se->ibuf= 0;
+ }
+ }
+
+ if (se->ibuf == NULL) {
+ do_build_seq_recursively_impl(seq->seq1, cfra_left);
+ se1 = seq->seq1->curelem;
+ do_build_seq_recursively_impl(seq->seq1, cfra_right);
+ se2 = seq->seq1->curelem;
+
+
+ if((se1 && se1->ibuf && se1->ibuf->rect_float))
+ se->ibuf= IMB_allocImBuf((short)seqrectx, (short)seqrecty, 32, IB_rectfloat, 0);
+ else
+ se->ibuf= IMB_allocImBuf((short)seqrectx, (short)seqrecty, 32, IB_rect, 0);
+
+ if (!se1 || !se2) {
+ make_black_ibuf(se->ibuf);
+ } else {
+ sh = get_sequence_effect(seq);
+
+ sh.execute(seq, cfra,
+ f_cfra - (float) cfra_left,
+ f_cfra - (float) cfra_left,
+ se->ibuf->x, se->ibuf->y,
+ se1->ibuf, se2->ibuf, 0, se->ibuf);
+ }
+ }
+
+ }
+
+ /* caller expects this to be referenced, so do it! */
+ if (se->ibuf) {
+ IMB_cache_limiter_insert(se->ibuf);
+ IMB_cache_limiter_ref(se->ibuf);
+ IMB_cache_limiter_touch(se->ibuf);
+ }
+
+ /* children are no longer needed */
+ if (se1 && se1->ibuf)
+ IMB_cache_limiter_unref(se1->ibuf);
+ if (se2 && se2->ibuf)
+ IMB_cache_limiter_unref(se2->ibuf);
+}
+
+/*
+ * build all ibufs recursively
+ *
+ * if successfull, seq->curelem->ibuf contains the (referenced!) imbuf
+ * that means: you _must_ call
+ *
+ * IMB_cache_limiter_unref(seq->curelem->ibuf);
+ *
+ * if seq->curelem exists!
+ *
+ */
+
+static void do_build_seq_recursively(Sequence * seq, int cfra)
+{
+ if (seq->type == SEQ_SPEED) {
+ do_handle_speed_effect(seq, cfra);
+ } else {
+ do_build_seq_recursively_impl(seq, cfra);
+ }
+}
+
+ImBuf *give_ibuf_seq(int rectx, int recty, int cfra, int chanshown)
+{
+ Sequence *seqfirst=0;
+ Editing *ed;
+ int count;
+ ListBase *seqbasep;
+
+ ed= G.scene->ed;
+ if(ed==0) return 0;
+
+ count = BLI_countlist(&ed->metastack);
+ if((chanshown < 0) && (count > 0)) {
+ count = MAX2(count + chanshown, 0);
+ seqbasep= ((MetaStack*)BLI_findlink(&ed->metastack, count))->oldbasep;
+ } else {
+ seqbasep= ed->seqbasep;
+ }
+
+ seqrectx= rectx; /* bad bad global! */
+ seqrecty= recty;
+
+ seqfirst = get_shown_sequence(seqbasep, cfra, chanshown);
+
+ if (!seqfirst) {
+ return 0;
+ }
+
+ do_build_seq_recursively(seqfirst, cfra);
+
+ if(!seqfirst->curelem) {
+ return 0;
+ }
+
+ if (seqfirst->curelem->ibuf) {
+ IMB_cache_limiter_unref(seqfirst->curelem->ibuf);
+ }
+
+ return seqfirst->curelem->ibuf;
+
+}
+
+/* threading api */
+
+static ListBase running_threads;
+static ListBase prefetch_wait;
+static ListBase prefetch_done;
+
+static pthread_mutex_t queue_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t wakeup_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t wakeup_cond = PTHREAD_COND_INITIALIZER;
+
+static pthread_mutex_t prefetch_ready_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t prefetch_ready_cond = PTHREAD_COND_INITIALIZER;
+
+static pthread_mutex_t frame_done_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t frame_done_cond = PTHREAD_COND_INITIALIZER;
+
+static volatile int seq_thread_shutdown = FALSE;
+static volatile int seq_last_given_monoton_cfra = 0;
+static int monoton_cfra = 0;
+
+typedef struct PrefetchThread {
+ struct PrefetchThread *next, *prev;
+ struct PrefetchQueueElem *current;
+ pthread_t pthread;
+ int running;
+} PrefetchThread;
+
+typedef struct PrefetchQueueElem {
+ struct PrefetchQueueElem *next, *prev;
+
+ int rectx;
+ int recty;
+ int cfra;
+ int chanshown;
+
+ int monoton_cfra;
+
+ struct ImBuf * ibuf;
+} PrefetchQueueElem;
+
+
+static void * seq_prefetch_thread(void * This_)
+{
+ PrefetchThread * This = This_;
+
+ while (!seq_thread_shutdown) {
+ PrefetchQueueElem * e;
+ int s_last;
+
+ pthread_mutex_lock(&queue_lock);
+ e = prefetch_wait.first;
+ if (e) {
+ BLI_remlink(&prefetch_wait, e);
+ }
+ s_last = seq_last_given_monoton_cfra;
+
+ This->current = e;
+
+ pthread_mutex_unlock(&queue_lock);
+
+ if (!e) {
+ pthread_mutex_lock(&prefetch_ready_lock);
+
+ This->running = FALSE;
+
+ pthread_cond_signal(&prefetch_ready_cond);
+ pthread_mutex_unlock(&prefetch_ready_lock);
+
+ pthread_mutex_lock(&wakeup_lock);
+ if (!seq_thread_shutdown) {
+ pthread_cond_wait(&wakeup_cond, &wakeup_lock);
+ }
+ pthread_mutex_unlock(&wakeup_lock);
+ continue;
+ }
+
+ This->running = TRUE;
+
+ if (e->cfra >= s_last) {
+ e->ibuf = give_ibuf_seq(e->rectx, e->recty, e->cfra,
+ e->chanshown);
+ }
+
+ if (e->ibuf) {
+ IMB_cache_limiter_ref(e->ibuf);
+ }
+
+ pthread_mutex_lock(&queue_lock);
+
+ BLI_addtail(&prefetch_done, e);
+
+ for (e = prefetch_wait.first; e; e = e->next) {
+ if (s_last > e->monoton_cfra) {
+ BLI_remlink(&prefetch_wait, e);
+ MEM_freeN(e);
+ }
+ }
+
+ for (e = prefetch_done.first; e; e = e->next) {
+ if (s_last > e->monoton_cfra) {
+ if (e->ibuf) {
+ IMB_cache_limiter_unref(e->ibuf);
+ }
+ BLI_remlink(&prefetch_done, e);
+ MEM_freeN(e);
+ }
+ }
+
+ pthread_mutex_unlock(&queue_lock);
+
+ pthread_mutex_lock(&frame_done_lock);
+ pthread_cond_signal(&frame_done_cond);
+ pthread_mutex_unlock(&frame_done_lock);
+ }
+ return 0;
+}
+
+void seq_start_threads()
+{
+ int i;
+
+ running_threads.first = running_threads.last = NULL;
+ prefetch_wait.first = prefetch_wait.last = NULL;
+ prefetch_done.first = prefetch_done.last = NULL;
+
+ seq_thread_shutdown = FALSE;
+ seq_last_given_monoton_cfra = monoton_cfra = 0;
+
+ /* since global structures are modified during the processing
+ of one frame, only one render thread is currently possible...
+
+ (but we code, in the hope, that we can remove this restriction
+ soon...)
+ */
+
+ fprintf(stderr, "SEQ-THREAD: seq_start_threads\n");
+
+ for (i = 0; i < 1; i++) {
+ PrefetchThread *t = MEM_callocN(sizeof(PrefetchThread),
+ "prefetch_thread");
+ t->running = TRUE;
+ BLI_addtail(&running_threads, t);
+
+ pthread_create(&t->pthread, NULL, seq_prefetch_thread, t);
+ }
+}
+
+void seq_stop_threads()
+{
+ PrefetchThread *tslot;
+ PrefetchQueueElem * e;
+
+ fprintf(stderr, "SEQ-THREAD: seq_stop_threads()\n");
+
+ if (seq_thread_shutdown) {
+ fprintf(stderr, "SEQ-THREAD: ... already stopped\n");
+ return;
+ }
+
+ pthread_mutex_lock(&wakeup_lock);
+
+ seq_thread_shutdown = TRUE;
+
+ pthread_cond_broadcast(&wakeup_cond);
+ pthread_mutex_unlock(&wakeup_lock);
+
+ for(tslot = running_threads.first; tslot; tslot= tslot->next) {
+ pthread_join(tslot->pthread, NULL);
+ }
+
+
+ for (e = prefetch_wait.first; e; e = e->next) {
+ BLI_remlink(&prefetch_wait, e);
+ MEM_freeN(e);
+ }
+
+ for (e = prefetch_done.first; e; e = e->next) {
+ if (e->ibuf) {
+ IMB_cache_limiter_unref(e->ibuf);
+ }
+ BLI_remlink(&prefetch_done, e);
+ MEM_freeN(e);
+ }
+
+ BLI_freelistN(&running_threads);
+}
+
+void give_ibuf_prefetch_request(int rectx, int recty, int cfra, int chanshown)
+{
+ PrefetchQueueElem * e;
+ if (seq_thread_shutdown) {
+ return;
+ }
+
+ e = MEM_callocN(sizeof(PrefetchQueueElem), "prefetch_queue_elem");
+ e->rectx = rectx;
+ e->recty = recty;
+ e->cfra = cfra;
+ e->chanshown = chanshown;
+ e->monoton_cfra = monoton_cfra++;
+
+ pthread_mutex_lock(&queue_lock);
+ BLI_addtail(&prefetch_wait, e);
+ pthread_mutex_unlock(&queue_lock);
+
+ pthread_mutex_lock(&wakeup_lock);
+ pthread_cond_signal(&wakeup_cond);
+ pthread_mutex_unlock(&wakeup_lock);
+}
+
+void seq_wait_for_prefetch_ready()
+{
+ PrefetchThread *tslot;
+
+ if (seq_thread_shutdown) {
+ return;
+ }
+
+ fprintf(stderr, "SEQ-THREAD: rendering prefetch frames...\n");
+
+ pthread_mutex_lock(&prefetch_ready_lock);
+
+ for(;;) {
+ for(tslot = running_threads.first; tslot; tslot= tslot->next) {
+ if (tslot->running) {
+ break;
+ }
+ }
+ if (!tslot) {
+ break;
+ }
+ pthread_cond_wait(&prefetch_ready_cond, &prefetch_ready_lock);
+ }
+
+ pthread_mutex_unlock(&prefetch_ready_lock);
+
+ fprintf(stderr, "SEQ-THREAD: prefetch done\n");
+}
+
+ImBuf * give_ibuf_threaded(int rectx, int recty, int cfra, int chanshown)
+{
+ PrefetchQueueElem * e = 0;
+ int found_something = FALSE;
+
+ if (seq_thread_shutdown) {
+ return give_ibuf_seq(rectx, recty, cfra, chanshown);
+ }
+
+ while (!e) {
+ int success = FALSE;
+ pthread_mutex_lock(&queue_lock);
+
+ for (e = prefetch_done.first; e; e = e->next) {
+ if (cfra == e->cfra &&
+ chanshown == e->chanshown &&
+ rectx == e->rectx &&
+ recty == e->recty) {
+ success = TRUE;
+ found_something = TRUE;
+ break;
+ }
+ }
+
+ if (!e) {
+ for (e = prefetch_wait.first; e; e = e->next) {
+ if (cfra == e->cfra &&
+ chanshown == e->chanshown &&
+ rectx == e->rectx &&
+ recty == e->recty) {
+ found_something = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (!e) {
+ PrefetchThread *tslot;
+
+ for(tslot = running_threads.first;
+ tslot; tslot= tslot->next) {
+ if (tslot->current &&
+ cfra == tslot->current->cfra &&
+ chanshown == tslot->current->chanshown &&
+ rectx == tslot->current->rectx &&
+ recty == tslot->current->recty) {
+ found_something = TRUE;
+ break;
+ }
+ }
+ }
+
+ /* e->ibuf is unrefed by render thread on next round. */
+
+ if (e) {
+ seq_last_given_monoton_cfra = e->monoton_cfra;
+ }
+
+ pthread_mutex_unlock(&queue_lock);
+
+ if (!success) {
+ e = NULL;
+
+ if (!found_something) {
+ fprintf(stderr,
+ "SEQ-THREAD: Requested frame "
+ "not in queue ???\n");
+ break;
+ }
+ pthread_mutex_lock(&frame_done_lock);
+ pthread_cond_wait(&frame_done_cond, &frame_done_lock);
+ pthread_mutex_unlock(&frame_done_lock);
+ }
+ }
+
+ return e ? e->ibuf : 0;
+}
+
+/* Functions to free imbuf and anim data on changes */
+
+static void free_imbuf_strip_elem(StripElem *se)
+{
+ if (se->ibuf) {
+ if (se->ok != 2)
+ IMB_freeImBuf(se->ibuf);
+ se->ibuf= 0;
+ se->ok= 1;
+ se->se1= se->se2= se->se3= 0;
+ }
+}
+
+static void free_anim_seq(Sequence *seq)
+{
+ if(seq->anim) {
+ IMB_free_anim(seq->anim);
+ seq->anim = 0;
+ }
+}
+
+void free_imbuf_seq_except(int cfra)
+{
+ Editing *ed= G.scene->ed;
+ Sequence *seq;
+ StripElem *se;
+ int a;
+
+ if(ed==0) return;
+
+ WHILE_SEQ(&ed->seqbase) {
+ if(seq->strip) {
+ for(a=0, se= seq->strip->stripdata; a<seq->len; a++, se++)
+ if(se!=seq->curelem)
+ free_imbuf_strip_elem(se);
+
+ if(seq->type==SEQ_MOVIE)
+ if(seq->startdisp > cfra || seq->enddisp < cfra)
+ free_anim_seq(seq);
+ }
+ }
+ END_SEQ
+}
+
+void free_imbuf_seq()
+{
+ Editing *ed= G.scene->ed;
+ Sequence *seq;
+ StripElem *se;
+ int a;
+
+ if(ed==0) return;
+
+ WHILE_SEQ(&ed->seqbase) {
+ if(seq->strip) {
+ for(a=0, se= seq->strip->stripdata; a<seq->len; a++, se++)
+ free_imbuf_strip_elem(se);
+
+ if(seq->type==SEQ_MOVIE)
+ free_anim_seq(seq);
+ if(seq->type==SEQ_SPEED) {
+ sequence_effect_speed_rebuild_map(seq, 1);
+ }
+ }
+ }
+ END_SEQ
+}
+
+void free_imbuf_seq_with_ipo(struct Ipo *ipo)
+{
+ /* force update of all sequences with this ipo, on ipo changes */
+ Editing *ed= G.scene->ed;
+ Sequence *seq;
+
+ if(ed==0) return;
+
+ WHILE_SEQ(&ed->seqbase) {
+ if(seq->ipo == ipo) {
+ update_changed_seq_and_deps(seq, 0, 1);
+ if(seq->type == SEQ_SPEED) {
+ sequence_effect_speed_rebuild_map(seq, 1);
+ }
+ }
+ }
+ END_SEQ
+}
+
+static int update_changed_seq_recurs(Sequence *seq, Sequence *changed_seq, int len_change, int ibuf_change)
+{
+ Sequence *subseq;
+ int a, free_imbuf = 0;
+ StripElem *se;
+
+ /* recurs downwards to see if this seq depends on the changed seq */
+
+ if(seq == NULL)
+ return 0;
+
+ if(seq == changed_seq)
+ free_imbuf = 1;
+
+ for(subseq=seq->seqbase.first; subseq; subseq=subseq->next)
+ if(update_changed_seq_recurs(subseq, changed_seq, len_change, ibuf_change))
+ free_imbuf = 1;
+
+ if(seq->seq1)
+ if(update_changed_seq_recurs(seq->seq1, changed_seq, len_change, ibuf_change))
+ free_imbuf = 1;
+ if(seq->seq2 && (seq->seq2 != seq->seq1))
+ if(update_changed_seq_recurs(seq->seq2, changed_seq, len_change, ibuf_change))
+ free_imbuf = 1;
+ if(seq->seq3 && (seq->seq3 != seq->seq1) && (seq->seq3 != seq->seq2))
+ if(update_changed_seq_recurs(seq->seq3, changed_seq, len_change, ibuf_change))
+ free_imbuf = 1;
+
+ if(free_imbuf) {
+ if(ibuf_change) {
+ for(a=0, se= seq->strip->stripdata; a<seq->len; a++, se++)
+ free_imbuf_strip_elem(se);
+
+ if(seq->type==SEQ_MOVIE)
+ free_anim_seq(seq);
+ if(seq->type == SEQ_SPEED) {
+ sequence_effect_speed_rebuild_map(seq, 1);
+ }
+ }
+
+ if(len_change)
+ calc_sequence(seq);
+ }
+
+ return free_imbuf;
+}
+
+void update_changed_seq_and_deps(Sequence *changed_seq, int len_change, int ibuf_change)
+{
+ Editing *ed= G.scene->ed;
+ Sequence *seq;
+
+ if (!ed) return;
+
+ for (seq=ed->seqbase.first; seq; seq=seq->next)
+ update_changed_seq_recurs(seq, changed_seq, len_change, ibuf_change);
+}
+
+/* bad levell call... */
+void do_render_seq(RenderResult *rr, int cfra)
+{
+ ImBuf *ibuf;
+
+ G.f |= G_PLAYANIM; /* waitcursor patch */
+
+ ibuf= give_ibuf_seq(rr->rectx, rr->recty, cfra, 0);
+
+ if(ibuf) {
+
+ if(ibuf->rect_float) {
+ if (!rr->rectf)
+ rr->rectf= MEM_mallocN(4*sizeof(float)*rr->rectx*rr->recty, "render_seq rectf");
+
+ memcpy(rr->rectf, ibuf->rect_float, 4*sizeof(float)*rr->rectx*rr->recty);
+
+ /* TSK! Since sequence render doesn't free the *rr render result, the old rect32
+ can hang around when sequence render has rendered a 32 bits one before */
+ if(rr->rect32) {
+ MEM_freeN(rr->rect32);
+ rr->rect32= NULL;
+ }
+ }
+ else if(ibuf->rect) {
+ if (!rr->rect32)
+ rr->rect32= MEM_mallocN(sizeof(int)*rr->rectx*rr->recty, "render_seq rect");
+
+ memcpy(rr->rect32, ibuf->rect, 4*rr->rectx*rr->recty);
+
+ /* if (ibuf->zbuf) { */
+ /* if (R.rectz) freeN(R.rectz); */
+ /* R.rectz = BLI_dupallocN(ibuf->zbuf); */
+ /* } */
+ }
+
+ /* Let the cache limitor take care of this (schlaile) */
+ /* While render let's keep all memory available for render
+ (ton)
+ At least if free memory is tight...
+ This can make a big difference in encoding speed
+ (it is around 4 times(!) faster, if we do not waste time
+ on freeing _all_ buffers every time on long timelines...)
+ (schlaile)
+ */
+ {
+ extern int mem_in_use;
+ extern int mmap_in_use;
+
+ int max = MEM_CacheLimiter_get_maximum();
+ if (max != 0 && mem_in_use + mmap_in_use > max) {
+ fprintf(stderr, "mem_in_use = %d, max = %d\n",
+ mem_in_use + mmap_in_use, max);
+ fprintf(stderr, "Cleaning up, please wait...\n"
+ "If this happens very often,\n"
+ "consider "
+ "raising the memcache limit in the "
+ "user preferences.\n");
+ free_imbuf_seq();
+ }
+ }
+ }
+ else {
+ /* render result is delivered empty in most cases, nevertheless we handle all cases */
+ if (rr->rectf)
+ memset(rr->rectf, 0, 4*sizeof(float)*rr->rectx*rr->recty);
+ else if (rr->rect32)
+ memset(rr->rect32, 0, 4*rr->rectx*rr->recty);
+ else
+ rr->rect32= MEM_callocN(sizeof(int)*rr->rectx*rr->recty, "render_seq rect");
+ }
+
+ G.f &= ~G_PLAYANIM;
+
+}
diff --git a/source/blender/src/space.c b/source/blender/src/space.c
new file mode 100644
index 00000000000..8d77e32c689
--- /dev/null
+++ b/source/blender/src/space.c
@@ -0,0 +1,6603 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ *
+ *
+ * - here initialize and free and handling SPACE data
+ */
+
+#include <string.h>
+#include <stdio.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+#include "MEM_CacheLimiterC-Api.h"
+
+#ifdef INTERNATIONAL
+#include "BIF_language.h"
+#endif
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_gsqueue.h"
+#include "BLI_linklist.h"
+
+#include "DNA_action_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_group_types.h" /* used for select_same_group */
+#include "DNA_image_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h" /* used for select grouped hooks */
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_sequence_types.h"
+#include "DNA_sound_types.h"
+#include "DNA_space_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_view2d_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_blender.h"
+#include "BKE_colortools.h"
+#include "BKE_curve.h"
+#include "BKE_depsgraph.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_displist.h"
+#include "BKE_global.h"
+#include "BKE_group.h"
+#include "BKE_ipo.h"
+#include "BKE_main.h"
+#include "BKE_mesh.h"
+#include "BKE_node.h"
+#include "BKE_scene.h"
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
+#include "BKE_image.h" /* for IMA_TYPE_COMPOSITE and IMA_TYPE_R_RESULT */
+
+#include "BIF_spacetypes.h" /* first, nasty dependency with typedef */
+
+#include "BIF_butspace.h"
+#include "BIF_drawimage.h"
+#include "BIF_drawseq.h"
+#include "BIF_drawtext.h"
+#include "BIF_drawscript.h"
+#include "BIF_editarmature.h"
+#include "BIF_editconstraint.h"
+#include "BIF_editdeform.h"
+#include "BIF_editfont.h"
+#include "BIF_editgroup.h"
+#include "BIF_editkey.h"
+#include "BIF_editlattice.h"
+#include "BIF_editmesh.h"
+#include "BIF_editmode_undo.h"
+#include "BIF_editnla.h"
+#include "BIF_editoops.h"
+#include "BIF_editseq.h"
+#include "BIF_editsima.h"
+#include "BIF_editsound.h"
+#include "BIF_editview.h"
+#include "BIF_filelist.h"
+#include "BIF_gl.h"
+#include "BIF_imasel.h"
+#include "BIF_interface.h"
+#include "BIF_interface_icons.h"
+#include "BIF_meshtools.h"
+#include "BIF_mywindow.h"
+#include "BIF_oops.h"
+#include "BIF_poseobject.h"
+#include "BIF_outliner.h"
+#include "BIF_resources.h"
+#include "BIF_retopo.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_toets.h"
+#include "BIF_toolbox.h"
+#include "BIF_usiblender.h"
+#include "BIF_previewrender.h"
+
+#include "BSE_edit.h"
+#include "BSE_view.h"
+#include "BSE_editipo.h"
+#include "BSE_drawipo.h"
+#include "BSE_drawview.h"
+#include "BSE_drawnla.h"
+#include "BSE_filesel.h"
+#include "BSE_headerbuttons.h"
+#include "BSE_editnla_types.h"
+#include "BSE_time.h"
+#include "BSE_trans_types.h"
+
+#include "BDR_vpaint.h"
+#include "BDR_editmball.h"
+#include "BDR_editobject.h"
+#include "BDR_editcurve.h"
+#include "BDR_editface.h"
+#include "BDR_drawmesh.h"
+#include "BDR_drawobject.h"
+#include "BDR_imagepaint.h"
+#include "BDR_sculptmode.h"
+#include "BDR_unwrapper.h"
+
+#include "BLO_readfile.h" /* for BLO_blendhandle_close */
+
+#include "PIL_time.h"
+
+#include "BPY_extern.h"
+
+#include "butspace.h"
+#include "mydevice.h"
+#include "blendef.h"
+#include "datatoc.h"
+#include "multires.h"
+
+#include "BIF_transform.h"
+
+#include "BKE_depsgraph.h"
+
+#include "BSE_trans_types.h"
+
+#include "SYS_System.h" /* for the user def menu ... should move elsewhere. */
+
+/* maybe we need this defined somewhere else */
+extern void StartKetsjiShell(ScrArea *area, char* startscenename, struct Main* maggie, struct SpaceIpo* sipo,int always_use_expand_framing);
+extern void StartKetsjiShellSimulation(ScrArea *area, char* startscenename, struct Main* maggie, struct SpaceIpo* sipo,int always_use_expand_framing);/*rcruiz*/
+
+/**
+ * When the mipmap setting changes, we want to redraw the view right
+ * away to reflect this setting.
+ */
+void space_mipmap_button_function(int event);
+
+void free_soundspace(SpaceSound *ssound);
+
+/* *************************************** */
+
+/* don't know yet how the handlers will evolve, for simplicity
+ i choose for an array with eventcodes, this saves in a file!
+ */
+void add_blockhandler(ScrArea *sa, short eventcode, short val)
+{
+ SpaceLink *sl= sa->spacedata.first;
+ short a;
+
+ /* find empty spot */
+ for(a=0; a<SPACE_MAXHANDLER; a+=2) {
+ if( sl->blockhandler[a]==eventcode ) {
+ sl->blockhandler[a+1]= val;
+ break;
+ }
+ else if( sl->blockhandler[a]==0) {
+ sl->blockhandler[a]= eventcode;
+ sl->blockhandler[a+1]= val;
+ break;
+ }
+ }
+ if(a==SPACE_MAXHANDLER) printf("error; max (4) blockhandlers reached!\n");
+}
+
+void rem_blockhandler(ScrArea *sa, short eventcode)
+{
+ SpaceLink *sl= sa->spacedata.first;
+ short a;
+
+ for(a=0; a<SPACE_MAXHANDLER; a+=2) {
+ if( sl->blockhandler[a]==eventcode) {
+ sl->blockhandler[a]= 0;
+
+ /* specific free calls */
+ if(eventcode==IMAGE_HANDLER_PREVIEW)
+ image_preview_event(0);
+ break;
+ }
+ }
+}
+
+void toggle_blockhandler(ScrArea *sa, short eventcode, short val)
+{
+ SpaceLink *sl= sa->spacedata.first;
+ short a, addnew=1;
+
+ /* find if it exists */
+ for(a=0; a<SPACE_MAXHANDLER; a+=2) {
+ if( sl->blockhandler[a]==eventcode ) {
+ sl->blockhandler[a]= 0;
+
+ /* specific free calls */
+ if(eventcode==VIEW3D_HANDLER_PREVIEW)
+ BIF_view3d_previewrender_free(sa->spacedata.first);
+ else if(eventcode==IMAGE_HANDLER_PREVIEW)
+ image_preview_event(0);
+
+ addnew= 0;
+ }
+ }
+ if(addnew) {
+ add_blockhandler(sa, eventcode, val);
+
+ /* specific add new calls */
+ if(eventcode==IMAGE_HANDLER_PREVIEW)
+ image_preview_event(1);
+ }
+}
+
+
+
+/* ************* SPACE: VIEW3D ************* */
+
+/* extern void drawview3dspace(ScrArea *sa, void *spacedata); BSE_drawview.h */
+
+
+void copy_view3d_lock(short val)
+{
+ bScreen *sc;
+ int bit;
+
+ /* from G.scene copy to the other views */
+ sc= G.main->screen.first;
+
+ while(sc) {
+ if(sc->scene==G.scene) {
+ ScrArea *sa= sc->areabase.first;
+ while(sa) {
+ SpaceLink *sl= sa->spacedata.first;
+ while(sl) {
+ if(sl->spacetype==SPACE_OOPS && val==REDRAW) {
+ if(sa->win) scrarea_queue_winredraw(sa);
+ }
+ else if(sl->spacetype==SPACE_VIEW3D) {
+ View3D *vd= (View3D*) sl;
+ if(vd->scenelock && vd->localview==0) {
+ vd->lay= G.scene->lay;
+ vd->camera= G.scene->camera;
+
+ if(vd->camera==0 && vd->persp>1) vd->persp= 1;
+
+ if( (vd->lay & vd->layact) == 0) {
+ bit= 0;
+ while(bit<32) {
+ if(vd->lay & (1<<bit)) {
+ vd->layact= 1<<bit;
+ break;
+ }
+ bit++;
+ }
+ }
+
+ if(val==REDRAW && vd==sa->spacedata.first) {
+ if(sa->win) scrarea_queue_redraw(sa);
+ }
+ }
+ }
+ sl= sl->next;
+ }
+ sa= sa->next;
+ }
+ }
+ sc= sc->id.next;
+ }
+}
+
+void handle_view3d_around()
+{
+ bScreen *sc;
+
+ if ((U.uiflag & USER_LOCKAROUND)==0) return;
+
+ /* copies from G.vd->around to other view3ds */
+
+ sc= G.main->screen.first;
+
+ while(sc) {
+ if(sc->scene==G.scene) {
+ ScrArea *sa= sc->areabase.first;
+ while(sa) {
+ SpaceLink *sl= sa->spacedata.first;
+ while(sl) {
+ if(sl->spacetype==SPACE_VIEW3D) {
+ View3D *vd= (View3D*) sl;
+ if (vd != G.vd) {
+ vd->around= G.vd->around;
+ if (G.vd->flag & V3D_ALIGN)
+ vd->flag |= V3D_ALIGN;
+ else
+ vd->flag &= ~V3D_ALIGN;
+ scrarea_queue_headredraw(sa);
+ }
+ }
+ sl= sl->next;
+ }
+ sa= sa->next;
+ }
+ }
+ sc= sc->id.next;
+ }
+}
+
+void handle_view3d_lock()
+{
+ if (G.vd != NULL && curarea != NULL ) {
+ if(G.vd->localview==0 && G.vd->scenelock && curarea->spacetype==SPACE_VIEW3D) {
+
+ /* copy to scene */
+ G.scene->lay= G.vd->lay;
+ G.scene->camera= G.vd->camera;
+
+ copy_view3d_lock(REDRAW);
+ }
+ }
+}
+
+void space_set_commmandline_options(void) {
+ SYS_SystemHandle syshandle;
+ int a;
+
+ if ( (syshandle = SYS_GetSystem()) ) {
+ /* User defined settings */
+ a= (U.gameflags & USER_VERTEX_ARRAYS);
+ SYS_WriteCommandLineInt(syshandle, "vertexarrays", a);
+
+ a= (U.gameflags & USER_DISABLE_SOUND);
+ SYS_WriteCommandLineInt(syshandle, "noaudio", a);
+
+ a= (U.gameflags & USER_DISABLE_MIPMAP);
+ set_mipmap(!a);
+ SYS_WriteCommandLineInt(syshandle, "nomipmap", a);
+
+ /* File specific settings: */
+ /* Only test the first one. These two are switched
+ * simultaneously. */
+ a= (G.fileflags & G_FILE_SHOW_FRAMERATE);
+ SYS_WriteCommandLineInt(syshandle, "show_framerate", a);
+ SYS_WriteCommandLineInt(syshandle, "show_profile", a);
+
+ /* When in wireframe mode, always draw debug props. */
+ if (G.vd) {
+ a = ( (G.fileflags & G_FILE_SHOW_DEBUG_PROPS)
+ || (G.vd->drawtype == OB_WIRE)
+ || (G.vd->drawtype == OB_SOLID) );
+ SYS_WriteCommandLineInt(syshandle, "show_properties", a);
+ }
+
+ a= (G.fileflags & G_FILE_SHOW_PHYSICS);
+ SYS_WriteCommandLineInt(syshandle, "show_physics", a);
+
+ a= (G.fileflags & G_FILE_ENABLE_ALL_FRAMES);
+ SYS_WriteCommandLineInt(syshandle, "fixedtime", a);
+
+ a= (G.fileflags & G_FILE_GAME_TO_IPO);
+ SYS_WriteCommandLineInt(syshandle, "game2ipo", a);
+
+ a=(G.fileflags & G_FILE_GAME_MAT);
+ SYS_WriteCommandLineInt(syshandle, "blender_material", a);
+ a=(G.fileflags & G_FILE_DIAPLAY_LISTS);
+ SYS_WriteCommandLineInt(syshandle, "displaylists", a);
+
+
+ }
+}
+
+#if GAMEBLENDER == 1
+ /**
+ * These two routines imported from the gameengine,
+ * I suspect a lot of the resetting stuff is cruft
+ * and can be removed, but it should be checked.
+ */
+static void SaveState(void)
+{
+ glPushAttrib(GL_ALL_ATTRIB_BITS);
+
+ init_realtime_GL();
+ init_gl_stuff();
+
+ if(G.f & G_TEXTUREPAINT)
+ texpaint_enable_mipmap();
+
+ if(G.scene->camera==0 || G.scene->camera->type!=OB_CAMERA)
+ error("no (correct) camera");
+
+ waitcursor(1);
+}
+
+static void RestoreState(void)
+{
+ if(G.f & G_TEXTUREPAINT)
+ texpaint_disable_mipmap();
+
+ curarea->win_swap = 0;
+ curarea->head_swap=0;
+ allqueue(REDRAWVIEW3D, 1);
+ allqueue(REDRAWBUTSALL, 0);
+ reset_slowparents();
+ waitcursor(0);
+ G.qual= 0;
+ glPopAttrib();
+}
+
+static LinkNode *save_and_reset_all_scene_cfra(void)
+{
+ LinkNode *storelist= NULL;
+ Scene *sc;
+
+ for (sc= G.main->scene.first; sc; sc= sc->id.next) {
+ BLI_linklist_prepend(&storelist, (void*) (long) sc->r.cfra);
+
+ /* why is this reset to 1 ?*/
+ /* sc->r.cfra= 1;*/
+
+ set_scene_bg(sc);
+ }
+
+ BLI_linklist_reverse(&storelist);
+
+ return storelist;
+}
+
+static void restore_all_scene_cfra(LinkNode *storelist) {
+ LinkNode *sc_store= storelist;
+ Scene *sc;
+
+ for (sc= G.main->scene.first; sc; sc= sc->id.next) {
+ int stored_cfra= (long) sc_store->link;
+
+ sc->r.cfra= stored_cfra;
+ set_scene_bg(sc);
+
+ sc_store= sc_store->next;
+ }
+
+ BLI_linklist_free(storelist, NULL);
+}
+#endif
+
+void start_game(void)
+{
+#if GAMEBLENDER == 1
+#ifndef NO_KETSJI
+ Scene *sc, *startscene = G.scene;
+ LinkNode *scene_cfra_store;
+
+ /* XXX, silly code - the game engine can
+ * access any scene through logic, so we try
+ * to make sure each scene has a valid camera,
+ * just in case the game engine tries to use it.
+ *
+ * Better would be to make a better routine
+ * in the game engine for finding the camera.
+ * - zr
+ * Note: yes, this is all very badly hacked! (ton)
+ */
+ for (sc= G.main->scene.first; sc; sc= sc->id.next) {
+ if (!sc->camera) {
+ Base *base;
+
+ for (base= sc->base.first; base; base= base->next)
+ if (base->object->type==OB_CAMERA)
+ break;
+
+ sc->camera= base?base->object:NULL;
+ }
+ }
+
+ /* these two lines make sure front and backbuffer are equal. for swapbuffers */
+ markdirty_all();
+ screen_swapbuffers();
+
+ /* can start from header */
+ mywinset(curarea->win);
+
+ scene_cfra_store= save_and_reset_all_scene_cfra();
+
+
+ /* game engine will do its own sounds. */
+ sound_stop_all_sounds();
+ sound_exit_audio();
+
+ /* Before jumping into Ketsji, we configure some settings. */
+ space_set_commmandline_options();
+
+ SaveState();
+ StartKetsjiShell(curarea, startscene->id.name+2, G.main,G.sipo, 1);
+ RestoreState();
+
+ /* Restart BPY - unload the game engine modules. */
+ BPY_end_python();
+ BPY_start_python(0, NULL); /* argc, argv stored there already */
+ BPY_post_start_python(); /* userpref path and menus init */
+
+ restore_all_scene_cfra(scene_cfra_store);
+ set_scene_bg(startscene);
+ scene_update_for_newframe(G.scene, G.scene->lay);
+
+ if (G.flags & G_FILE_AUTOPLAY)
+ exit_usiblender();
+
+ /* groups could have changed ipo */
+ allqueue(REDRAWNLA, 0);
+ allqueue(REDRAWACTION, 0);
+ allspace(REMAKEIPO, 0);
+ allqueue(REDRAWIPO, 0);
+#endif
+#else
+ notice("Game engine is disabled in this release!");
+#endif
+}
+
+void start_RBSimulation(void)
+{
+#if GAMEBLENDER == 1
+#ifndef NO_KETSJI
+ Scene *sc, *startscene = G.scene;
+ LinkNode *scene_cfra_store;
+
+ /* XXX, silly code - the game engine can
+ * access any scene through logic, so we try
+ * to make sure each scene has a valid camera,
+ * just in case the game engine tries to use it.
+ *
+ * Better would be to make a better routine
+ * in the game engine for finding the camera.
+ * - zr
+ * Note: yes, this is all very badly hacked! (ton)
+ */
+ for (sc= G.main->scene.first; sc; sc= sc->id.next) {
+ if (!sc->camera) {
+ Base *base;
+
+ for (base= sc->base.first; base; base= base->next)
+ if (base->object->type==OB_CAMERA)
+ break;
+
+ sc->camera= base?base->object:NULL;
+ }
+ }
+
+ /* these two lines make sure front and backbuffer are equal. for swapbuffers */
+ markdirty_all();
+ screen_swapbuffers();
+
+ /* can start from header */
+ mywinset(curarea->win);
+
+ scene_cfra_store= save_and_reset_all_scene_cfra();
+
+
+ /* game engine will do its own sounds. */
+ sound_stop_all_sounds();
+ sound_exit_audio();
+
+ /* Before jumping into Ketsji, we configure some settings. */
+ space_set_commmandline_options();
+
+ SaveState();
+ StartKetsjiShellSimulation(curarea, startscene->id.name+2, G.main,G.sipo, 1);
+ RestoreState();
+ /* Restart BPY - unload the game engine modules. */
+ BPY_end_python();
+ BPY_start_python(0, NULL); /* argc, argv stored there already */
+ BPY_post_start_python(); /* userpref path and menus init */
+
+ restore_all_scene_cfra(scene_cfra_store);
+ set_scene_bg(startscene);
+ scene_update_for_newframe(G.scene, G.scene->lay);
+
+ if (G.flags & G_FILE_AUTOPLAY)
+ exit_usiblender();
+
+ /* groups could have changed ipo */
+ allqueue(REDRAWNLA, 0);
+ allqueue(REDRAWACTION, 0);
+ allspace(REMAKEIPO, 0);
+ allqueue(REDRAWIPO, 0);
+#endif
+#else
+ notice("YOU NEED GAME ENGIEN TO RUN THE SIMULATION!");
+#endif
+}
+
+static void changeview3dspace(ScrArea *sa, void *spacedata)
+{
+ setwinmatrixview3d(sa->winx, sa->winy, NULL); /* 0= no pick rect */
+}
+
+ /* Callable from editmode and faceselect mode from the
+ * moment, would be nice (and is easy) to generalize
+ * to any mode.
+ */
+static void align_view_to_selected(View3D *v3d)
+{
+ int nr= pupmenu("Align View (Ctrl flips)%t|To Selected (top)%x3|To Selected (front)%x2|To Selected (side)%x1");
+ if (nr!=-1) {
+ int axis= nr;
+
+ /* opposite axis in case ctrl is pressed */
+ if(G.qual==LR_CTRLKEY) axis= -axis;
+
+ if ((G.obedit) && (G.obedit->type == OB_MESH)) {
+ editmesh_align_view_to_selected(v3d, axis);
+ addqueue(v3d->area->win, REDRAW, 1);
+ } else if (FACESEL_PAINT_TEST) {
+ Object *obact= OBACT;
+ if (obact && obact->type==OB_MESH) {
+ Mesh *me= obact->data;
+ faceselect_align_view_to_selected(v3d, me, axis);
+ addqueue(v3d->area->win, REDRAW, 1);
+ }
+ }
+ }
+}
+
+
+static short select_children(Object *ob, int recursive)
+{
+ short changed = 0;
+ Base *base;
+
+ for (base= FIRSTBASE; base; base= base->next) {
+ if (ob == base->object->parent) {
+ if (BASE_SELECTABLE(base) && !(base->flag & SELECT)) {
+ base->flag |= SELECT;
+ base->object->flag |= SELECT;
+ changed = 1;
+ }
+
+ if (recursive)
+ changed |= select_children(base->object, 1);
+ }
+ }
+ return changed;
+}
+
+static short select_parent(void) /* Makes parent active and de-selected OBACT */
+{
+ short changed = 0;
+ Base *base, *startbase, *basact=NULL, *oldbasact;
+
+ if (!(OBACT) || !(OBACT->parent)) return 0;
+ BASACT->flag &= (~SELECT);
+ BASACT->object->flag &= (~SELECT);
+ startbase= FIRSTBASE;
+ if(BASACT && BASACT->next) startbase= BASACT->next;
+ base = startbase;
+ while(base) {
+ if(base->object==BASACT->object->parent) { basact=base; break; }
+ base=base->next;
+ if(base==NULL) base= FIRSTBASE;
+ if(base==startbase) break;
+ }
+ /* can be NULL if parent in other scene */
+ if(basact && BASE_SELECTABLE(basact)) {
+ oldbasact = BASACT;
+ BASACT = basact;
+ basact->flag |= SELECT;
+
+ basact->object->flag= basact->flag;
+
+ set_active_base(basact);
+ changed = 1;
+ }
+ return changed;
+}
+
+
+#define GROUP_MENU_MAX 24
+static short select_same_group(Object *ob) /* Select objects in the same group as the active */
+{
+ short changed = 0;
+ Base *base;
+ Group *group, *ob_groups[GROUP_MENU_MAX];
+ char str[10 + (24*GROUP_MENU_MAX)];
+ char *p = str;
+ int group_count=0, menu, i;
+
+ if (!ob)
+ return 0;
+
+ for ( group=G.main->group.first;
+ group && group_count < GROUP_MENU_MAX;
+ group=group->id.next
+ ) {
+ if (object_in_group (ob, group)) {
+ ob_groups[group_count] = group;
+ group_count++;
+ }
+ }
+
+ if (!group_count)
+ return 0;
+
+ else if (group_count == 1) {
+ group = ob_groups[0];
+ for (base= FIRSTBASE; base; base= base->next) {
+ if (BASE_SELECTABLE(base) && !(base->flag & SELECT) && object_in_group(base->object, group)) {
+ base->flag |= SELECT;
+ base->object->flag |= SELECT;
+ changed = 1;
+ }
+ }
+ return changed;
+ }
+
+ /* build the menu. */
+ p += sprintf(str, "Groups%%t");
+ for (i=0; i<group_count; i++) {
+ group = ob_groups[i];
+ p += sprintf (p, "|%s%%x%i", group->id.name+2, i);
+ }
+
+ menu = pupmenu (str);
+ if (menu == -1)
+ return 0;
+
+ group = ob_groups[menu];
+ for (base= FIRSTBASE; base; base= base->next) {
+ if (!(base->flag & SELECT) && object_in_group(base->object, group)) {
+ base->flag |= SELECT;
+ base->object->flag |= SELECT;
+ changed = 1;
+ }
+ }
+ return changed;
+}
+
+static short select_object_hooks(Object *ob)
+{
+ short changed = 0;
+ Base *base;
+ ModifierData *md;
+ HookModifierData *hmd;
+
+ if (!ob)
+ return 0;
+
+ for (md = ob->modifiers.first; md; md=md->next) {
+ if (md->type==eModifierType_Hook) {
+ hmd= (HookModifierData*) md;
+ if (hmd->object && !(hmd->object->flag & SELECT)) {
+ base= object_in_scene(hmd->object, G.scene);
+ if (base && BASE_SELECTABLE(base)) {
+ base->flag |= SELECT;
+ base->object->flag |= SELECT;
+ changed = 1;
+ }
+ }
+ }
+ }
+ return changed;
+}
+
+/* Select objects woth the same parent as the active (siblings),
+ * parent can be NULL also */
+static short select_same_parent(Object *ob)
+{
+ short changed = 0;
+ Base *base;
+ if (!ob)
+ return 0;
+
+ for (base= FIRSTBASE; base; base= base->next) {
+ if (BASE_SELECTABLE(base) && (base->object->parent==ob->parent) && !(base->flag & SELECT)) {
+ base->flag |= SELECT;
+ base->object->flag |= SELECT;
+ changed = 1;
+ }
+ }
+ return changed;
+}
+
+static short select_same_type(Object *ob)
+{
+ short changed = 0;
+ Base *base;
+ if (!ob)
+ return 0;
+
+ for (base= FIRSTBASE; base; base= base->next) {
+ if (BASE_SELECTABLE(base) && (base->object->type == ob->type) && !(base->flag & SELECT)) {
+ base->flag |= SELECT;
+ base->object->flag |= SELECT;
+ changed = 1;
+ }
+ }
+ return changed;
+}
+
+static short select_same_layer(Object *ob)
+{
+ char changed = 0;
+ Base *base = FIRSTBASE;
+
+ if (!ob)
+ return 0;
+
+ while(base) {
+ if (BASE_SELECTABLE(base) && (base->lay & ob->lay) && !(base->flag & SELECT)) {
+ base->flag |= SELECT;
+ base->object->flag |= SELECT;
+ changed = 1;
+ }
+ base= base->next;
+ }
+ return changed;
+}
+
+static short select_same_index_object(Object *ob)
+{
+ char changed = 0;
+ Base *base = FIRSTBASE;
+
+ if (!ob)
+ return 0;
+
+ while(base) {
+ if (BASE_SELECTABLE(base) && (base->object->index == ob->index) && !(base->flag & SELECT)) {
+ base->flag |= SELECT;
+ base->object->flag |= SELECT;
+ changed = 1;
+ }
+ base= base->next;
+ }
+ return changed;
+}
+
+void select_object_grouped(short nr)
+{
+ short changed = 0;
+ if(nr==1) changed = select_children(OBACT, 1);
+ else if(nr==2) changed = select_children(OBACT, 0);
+ else if(nr==3) changed = select_parent();
+ else if(nr==4) changed = select_same_parent(OBACT);
+ else if(nr==5) changed = select_same_type(OBACT);
+ else if(nr==6) changed = select_same_layer(OBACT);
+ else if(nr==7) changed = select_same_group(OBACT);
+ else if(nr==8) changed = select_object_hooks(OBACT);
+ else if(nr==9) changed = select_same_index_object(OBACT);
+
+ if (changed) {
+ countall();
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSOBJECT, 0);
+ allspace(REMAKEIPO, 0);
+ allqueue(REDRAWIPO, 0);
+ BIF_undo_push("Select Grouped");
+ }
+}
+
+static void select_object_grouped_menu(void)
+{
+ char *str;
+ short nr;
+
+ /* make menu string */
+
+ str= MEM_mallocN(512, "groupmenu");
+ strcpy(str, "Select Grouped%t|Children%x1|"
+ "Immediate Children%x2|Parent%x3|"
+ "Siblings (Shared Parent)%x4|"
+ "Objects of Same Type%x5|"
+ "Objects on Shared Layers%x6|"
+ "Objects in Same Group%x7|"
+ "Object Hooks%x8|Object PassIndex%x9");
+
+ /* here we go */
+
+ nr= pupmenu(str);
+ MEM_freeN(str);
+
+ select_object_grouped(nr);
+}
+
+void join_menu(void)
+{
+ Object *ob= OBACT;
+ if (G.obedit) {
+ error("This data does not support joining in editmode");
+ return;
+ }
+ if (!ob) {
+ error("Can't join unless there is an active object");
+ return;
+ }
+
+ if(ob->type == OB_MESH) {
+ if(okee("Join selected meshes")==0) return;
+ join_mesh();
+ } else if(ob->type == OB_CURVE) {
+ if(okee("Join selected curves")==0) return;
+ join_curve(OB_CURVE);
+ } else if(ob->type == OB_SURF) {
+ if(okee("Join selected NURBS")==0) return;
+ join_curve(OB_SURF);
+ } else if(ob->type == OB_ARMATURE) {
+ /* Make sure the user wants to continue*/
+ if(okee("Join selected armatures")==0) return;
+ join_armature ();
+ } else {
+ error("This object type doesn't support joining");
+ }
+}
+
+static unsigned short convert_for_nonumpad(unsigned short event)
+{
+ if (event>=ZEROKEY && event<=NINEKEY) {
+ return event - ZEROKEY + PAD0;
+ } else if (event==MINUSKEY) {
+ return PADMINUS;
+ } else if (event==EQUALKEY) {
+ return PADPLUSKEY;
+ } else if (event==BACKSLASHKEY) {
+ return PADSLASHKEY;
+ } else {
+ return event;
+ }
+}
+
+/* *************** */
+
+void BIF_undo_push(char *str)
+{
+ if(G.obedit) {
+ if (U.undosteps == 0) return;
+
+ if(G.obedit->type==OB_MESH)
+ undo_push_mesh(str);
+ else if ELEM(G.obedit->type, OB_CURVE, OB_SURF)
+ undo_push_curve(str);
+ else if (G.obedit->type==OB_FONT)
+ undo_push_font(str);
+ else if (G.obedit->type==OB_MBALL)
+ undo_push_mball(str);
+ else if (G.obedit->type==OB_LATTICE)
+ undo_push_lattice(str);
+ else if (G.obedit->type==OB_ARMATURE)
+ undo_push_armature(str);
+ }
+ else {
+ if(U.uiflag & USER_GLOBALUNDO)
+ BKE_write_undo(str);
+ }
+}
+
+void BIF_undo(void)
+{
+ if(G.obedit) {
+ if ELEM7(G.obedit->type, OB_MESH, OB_FONT, OB_CURVE, OB_SURF, OB_MBALL, OB_LATTICE, OB_ARMATURE)
+ undo_editmode_step(1);
+ }
+ else {
+ if(G.f & G_TEXTUREPAINT)
+ imagepaint_undo();
+ else if(curarea->spacetype==SPACE_IMAGE && (G.sima->flag & SI_DRAWTOOL))
+ imagepaint_undo();
+ else {
+ /* now also in faceselect mode */
+ if(U.uiflag & USER_GLOBALUNDO) {
+ BKE_undo_step(1);
+ sound_initialize_sounds();
+ }
+ }
+ }
+}
+
+void BIF_redo(void)
+{
+ if(G.obedit) {
+ if ELEM7(G.obedit->type, OB_MESH, OB_FONT, OB_CURVE, OB_SURF, OB_MBALL, OB_LATTICE, OB_ARMATURE)
+ undo_editmode_step(-1);
+ }
+ else {
+ if(G.f & G_TEXTUREPAINT)
+ imagepaint_undo();
+ else if(curarea->spacetype==SPACE_IMAGE && (G.sima->flag & SI_DRAWTOOL))
+ imagepaint_undo();
+ else {
+ /* includes faceselect now */
+ if(U.uiflag & USER_GLOBALUNDO) {
+ BKE_undo_step(-1);
+ sound_initialize_sounds();
+ }
+ }
+ }
+}
+
+void BIF_undo_menu(void)
+{
+ if(G.obedit) {
+ if ELEM7(G.obedit->type, OB_MESH, OB_FONT, OB_CURVE, OB_SURF, OB_MBALL, OB_LATTICE, OB_ARMATURE)
+ undo_editmode_menu();
+ allqueue(REDRAWALL, 0);
+ }
+ else {
+ if(U.uiflag & USER_GLOBALUNDO) {
+ char *menu= BKE_undo_menu_string();
+ if(menu) {
+ short event= pupmenu_col(menu, 20);
+ MEM_freeN(menu);
+ if(event>0) BKE_undo_number(event);
+ }
+ }
+ }
+}
+
+/* *************** */
+
+void handle_view_middlemouse() {
+ /* use '&' here, because of alt+leftmouse which emulates middlemouse */
+ if(U.flag & USER_VIEWMOVE) {
+ if((G.qual==LR_SHIFTKEY) || ((U.flag & USER_TWOBUTTONMOUSE) && (G.qual==(LR_ALTKEY|LR_SHIFTKEY))))
+ viewmove(0);
+ else if((G.qual==LR_CTRLKEY) || ((U.flag & USER_TWOBUTTONMOUSE) && (G.qual==(LR_ALTKEY|LR_CTRLKEY))))
+ viewmove(2);
+ else if((G.qual==0) || ((U.flag & USER_TWOBUTTONMOUSE) && (G.qual==LR_ALTKEY)))
+ viewmove(1);
+ }
+ else {
+ if((G.qual==LR_SHIFTKEY) || ((U.flag & USER_TWOBUTTONMOUSE) && (G.qual==(LR_ALTKEY|LR_SHIFTKEY))))
+ viewmove(1);
+ else if((G.qual==LR_CTRLKEY) || ((U.flag & USER_TWOBUTTONMOUSE) && (G.qual==(LR_ALTKEY|LR_CTRLKEY))))
+ viewmove(2);
+ else if((G.qual==0) || ((U.flag & USER_TWOBUTTONMOUSE) && (G.qual==LR_ALTKEY)))
+ viewmove(0);
+ }
+}
+
+void handle_view_wheelup()
+{
+ /* Regular: Zoom in */
+ /* Shift: Scroll up */
+ /* Ctrl: Scroll right */
+ /* Alt-Shift: Rotate up */
+ /* Alt-Ctrl: Rotate right */
+
+ if( G.qual & LR_SHIFTKEY ) {
+ if( G.qual & LR_ALTKEY ) {
+ G.qual &= ~LR_SHIFTKEY;
+ persptoetsen(PAD2);
+ G.qual |= LR_SHIFTKEY;
+ } else {
+ persptoetsen(PAD2);
+ }
+ } else if( G.qual & LR_CTRLKEY ) {
+ if( G.qual & LR_ALTKEY ) {
+ G.qual &= ~LR_CTRLKEY;
+ persptoetsen(PAD4);
+ G.qual |= LR_CTRLKEY;
+ } else {
+ persptoetsen(PAD4);
+ }
+ } else if(U.uiflag & USER_WHEELZOOMDIR)
+ persptoetsen(PADMINUS);
+ else
+ persptoetsen(PADPLUSKEY);
+}
+
+void handle_view_wheeldown()
+{
+ /* Regular: Zoom out */
+ /* Shift: Scroll down */
+ /* Ctrl: Scroll left */
+ /* Alt-Shift: Rotate down */
+ /* Alt-Ctrl: Rotate left */
+
+ if( G.qual & LR_SHIFTKEY ) {
+ if( G.qual & LR_ALTKEY ) {
+ G.qual &= ~LR_SHIFTKEY;
+ persptoetsen(PAD8);
+ G.qual |= LR_SHIFTKEY;
+ } else {
+ persptoetsen(PAD8);
+ }
+ } else if( G.qual & LR_CTRLKEY ) {
+ if( G.qual & LR_ALTKEY ) {
+ G.qual &= ~LR_CTRLKEY;
+ persptoetsen(PAD6);
+ G.qual |= LR_CTRLKEY;
+ } else {
+ persptoetsen(PAD6);
+ }
+ } else if(U.uiflag & USER_WHEELZOOMDIR)
+ persptoetsen(PADPLUSKEY);
+ else
+ persptoetsen(PADMINUS);
+}
+
+int mouse_in_header(ScrArea *sa)
+{
+ short mouse[2];
+ getmouseco_sc(mouse);
+ return mouse[0] >= sa->headrct.xmin &&
+ mouse[0] <= sa->headrct.xmax &&
+ mouse[1] >= sa->headrct.ymin &&
+ mouse[1] <= sa->headrct.ymax;
+}
+
+static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
+{
+ View3D *v3d= sa->spacedata.first;
+ Object *ob= OBACT; /* do not change! */
+ float *curs;
+ int doredraw= 0, pupval;
+ unsigned short event= evt->event;
+ short val= evt->val;
+ char ascii= evt->ascii;
+
+ if(curarea->win==0) return; /* when it comes from sa->headqread() */
+
+ if(val) {
+
+ if( uiDoBlocks(&curarea->uiblocks, event)!=UI_NOTHING ) event= 0;
+
+ if(event==UI_BUT_EVENT) do_butspace(val); /* temporal, view3d deserves own queue? */
+
+ /* we consider manipulator a button, defaulting to leftmouse */
+ if(event==LEFTMOUSE) if(BIF_do_manipulator(sa)) return;
+
+ /* swap mouse buttons based on user preference */
+ if (U.flag & USER_LMOUSESELECT) {
+ /* only swap mouse button for selection, in modes where it is relevant.
+ * painting/sculpting stays on LEFTMOUSE */
+ if ( !((G.f & G_SCULPTMODE) || (G.f & G_WEIGHTPAINT) ||
+ (G.f & G_VERTEXPAINT) || (G.f & G_TEXTUREPAINT)) ||
+ (G.obedit) )
+ {
+ if (event==LEFTMOUSE) event = RIGHTMOUSE;
+ else if (event==RIGHTMOUSE) event = LEFTMOUSE;
+ }
+ }
+
+ if(!mouse_in_header(sa)) {
+ if(!G.obedit && (G.f & G_SCULPTMODE)) {
+ SculptSession *ss= sculpt_session();
+ if(ss && ss->propset) {
+ sculptmode_propset(event);
+ return;
+ }
+ else if(event!=LEFTMOUSE && event!=MIDDLEMOUSE && (event==MOUSEY || event==MOUSEX)) {
+ if(!bwin_qtest(sa->win))
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ }
+
+ /* Handle retopo painting */
+ if(retopo_mesh_paint_check()) {
+ if(!retopo_paint(event))
+ return;
+ }
+ }
+
+ /* run any view3d event handler script links */
+ if (event && sa->scriptlink.totscript)
+ if (BPY_do_spacehandlers(sa, event, SPACEHANDLER_VIEW3D_EVENT))
+ return; /* return if event was processed (swallowed) by handler(s) */
+
+ /* TEXTEDITING?? */
+ if((G.obedit) && G.obedit->type==OB_FONT) {
+ switch(event) {
+
+ case LEFTMOUSE:
+ mouse_cursor();
+ break;
+ case MIDDLEMOUSE:
+ /* use '&' here, because of alt+leftmouse which emulates middlemouse */
+ if(U.flag & USER_VIEWMOVE) {
+ if((G.qual==LR_SHIFTKEY) || ((U.flag & USER_TWOBUTTONMOUSE) && (G.qual==(LR_ALTKEY|LR_SHIFTKEY))))
+ viewmove(0);
+ else if((G.qual==LR_CTRLKEY) || ((U.flag & USER_TWOBUTTONMOUSE) && (G.qual==(LR_ALTKEY|LR_CTRLKEY))))
+ viewmove(2);
+ else if((G.qual==0) || ((U.flag & USER_TWOBUTTONMOUSE) && (G.qual==LR_ALTKEY)))
+ viewmove(1);
+ }
+ else {
+ if((G.qual==LR_SHIFTKEY) || ((U.flag & USER_TWOBUTTONMOUSE) && (G.qual==(LR_ALTKEY|LR_SHIFTKEY))))
+ viewmove(1);
+ else if((G.qual==LR_CTRLKEY) || ((U.flag & USER_TWOBUTTONMOUSE) && (G.qual==(LR_ALTKEY|LR_CTRLKEY))))
+ viewmove(2);
+ else
+ viewmove(0);
+ }
+ break;
+
+ case WHEELUPMOUSE:
+ /* Regular: Zoom in */
+ /* Shift: Scroll up */
+ /* Ctrl: Scroll right */
+ /* Alt-Shift: Rotate up */
+ /* Alt-Ctrl: Rotate right */
+
+ if( G.qual & LR_SHIFTKEY ) {
+ if( G.qual & LR_ALTKEY ) {
+ G.qual &= ~LR_SHIFTKEY;
+ persptoetsen(PAD2);
+ G.qual |= LR_SHIFTKEY;
+ } else {
+ persptoetsen(PAD2);
+ }
+ } else if( G.qual & LR_CTRLKEY ) {
+ if( G.qual & LR_ALTKEY ) {
+ G.qual &= ~LR_CTRLKEY;
+ persptoetsen(PAD4);
+ G.qual |= LR_CTRLKEY;
+ } else {
+ persptoetsen(PAD4);
+ }
+ } else if(U.uiflag & USER_WHEELZOOMDIR)
+ persptoetsen(PADMINUS);
+ else
+ persptoetsen(PADPLUSKEY);
+
+ doredraw= 1;
+ break;
+
+ case WHEELDOWNMOUSE:
+ /* Regular: Zoom out */
+ /* Shift: Scroll down */
+ /* Ctrl: Scroll left */
+ /* Alt-Shift: Rotate down */
+ /* Alt-Ctrl: Rotate left */
+
+ if( G.qual & LR_SHIFTKEY ) {
+ if( G.qual & LR_ALTKEY ) {
+ G.qual &= ~LR_SHIFTKEY;
+ persptoetsen(PAD8);
+ G.qual |= LR_SHIFTKEY;
+ } else {
+ persptoetsen(PAD8);
+ }
+ } else if( G.qual & LR_CTRLKEY ) {
+ if( G.qual & LR_ALTKEY ) {
+ G.qual &= ~LR_CTRLKEY;
+ persptoetsen(PAD6);
+ G.qual |= LR_CTRLKEY;
+ } else {
+ persptoetsen(PAD6);
+ }
+ } else if(U.uiflag & USER_WHEELZOOMDIR)
+ persptoetsen(PADPLUSKEY);
+ else
+ persptoetsen(PADMINUS);
+
+ doredraw= 1;
+ break;
+
+ case UKEY:
+ if(G.qual==LR_ALTKEY) {
+ remake_editText();
+ doredraw= 1;
+ }
+ else {
+ do_textedit(event, val, ascii);
+ }
+ break;
+ case VKEY:
+ if(G.qual==LR_ALTKEY) {
+ paste_editText();
+ doredraw= 1;
+ }
+ else {
+ do_textedit(event, val, ascii);
+ }
+ break;
+ case PAD0: case PAD1: case PAD2: case PAD3: case PAD4:
+ case PAD5: case PAD6: case PAD7: case PAD8: case PAD9:
+ case PADENTER:
+ persptoetsen(event);
+ doredraw= 1;
+ break;
+
+ default:
+ do_textedit(event, val, ascii);
+ break;
+ }
+ }
+ else if(!G.obedit && (G.f & G_SCULPTMODE)) {
+ SculptData *sd= sculpt_data();
+ SculptSession *ss= sculpt_session();
+ BrushData *br= sculptmode_brush();
+ Mesh *me= get_mesh(OBACT);
+ char update_prop= 0;
+
+ if(U.flag & USER_NONUMPAD) {
+ event= convert_for_nonumpad(event);
+ }
+
+ switch(event) {
+ case LEFTMOUSE:
+ if(G.qual==LR_SHIFTKEY+LR_CTRLKEY)
+ sculptmode_pmv(0);
+ else if(!(ss && ss->propset))
+ sculpt();
+ break;
+ /* View */
+ case MIDDLEMOUSE:
+ handle_view_middlemouse();
+ break;
+ case WHEELUPMOUSE:
+ handle_view_wheelup();
+ doredraw= 1;
+ break;
+ case WHEELDOWNMOUSE:
+ handle_view_wheeldown();
+ doredraw= 1;
+ break;
+ case RIGHTMOUSE:
+ if(G.qual==LR_SHIFTKEY+LR_CTRLKEY)
+ sculptmode_pmv(1);
+ break;
+ case CKEY:
+ if(G.qual==LR_SHIFTKEY) {
+ view3d_home(1);
+ curs= give_cursor();
+ curs[0]=curs[1]=curs[2]= 0.0;
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ else if(G.qual==0) {
+ if (G.vd->persp==2)
+ /* center the camera offset */
+ G.vd->camdx= G.vd->camdy= 0.0;
+ else {
+ /*non camera center*/
+ float new_ofs[3];
+ curs= give_cursor();
+ new_ofs[0]= -curs[0];
+ new_ofs[1]= -curs[1];
+ new_ofs[2]= -curs[2];
+ smooth_view(G.vd, new_ofs, NULL, NULL, NULL);
+ }
+ }
+ doredraw= 1;
+ break;
+ case PAD0: case PAD1: case PAD2: case PAD3: case PAD4:
+ case PAD5: case PAD6: case PAD7: case PAD8: case PAD9:
+ case PADPLUSKEY:
+ case PADMINUS:
+ case PADENTER:
+ persptoetsen(event);
+ doredraw= 1;
+ break;
+ case BKEY:
+ if(G.qual==LR_ALTKEY)
+ view3d_edit_clipping(v3d);
+ else if(G.qual==LR_SHIFTKEY) {
+ if(G.vd->persp==2)
+ set_render_border();
+ else
+ view3d_border_zoom();
+ }
+ break;
+ case PADSLASHKEY:
+ if(!G.qual) {
+ if(G.vd->localview) {
+ G.vd->localview= 0;
+ endlocalview(curarea);
+ }
+ else {
+ G.vd->localview= 1;
+ initlocalview();
+ }
+ allqueue(REDRAWVIEW3D, 1);
+ }
+ break;
+ /* Brush properties */
+ case AKEY:
+ br->airbrush= !br->airbrush;
+ update_prop= 1; break;
+ case FKEY:
+ if(G.qual==0)
+ sculptmode_propset_init(PropsetSize);
+ if(G.qual==LR_SHIFTKEY)
+ sculptmode_propset_init(PropsetStrength);
+ if(G.qual==LR_CTRLKEY)
+ sculptmode_propset_init(PropsetTexRot);
+ break;
+ case VKEY:
+ br->dir= br->dir==1 ? 2 : 1;
+ update_prop= 1; break;
+ /* Set brush */
+ case DKEY:
+ sd->brush_type= DRAW_BRUSH;
+ update_prop= 1; break;
+ case SKEY:
+ sd->brush_type= SMOOTH_BRUSH;
+ update_prop= 1; break;
+ case PKEY:
+ sd->brush_type= PINCH_BRUSH;
+ update_prop= 1; break;
+ case IKEY:
+ sd->brush_type= INFLATE_BRUSH;
+ update_prop= 1; break;
+ case GKEY:
+ sd->brush_type= GRAB_BRUSH;
+ update_prop= 1; break;
+ case LKEY:
+ sd->brush_type= LAYER_BRUSH;
+ update_prop= 1; break;
+ case TKEY:
+ sd->brush_type= FLATTEN_BRUSH;
+ update_prop= 1; break;
+ /* Symmetry */
+ case XKEY:
+ sd->symm^= SYMM_X;
+ update_prop= 1; break;
+ case YKEY:
+ sd->symm^= SYMM_Y;
+ update_prop= 1; break;
+ case ZKEY:
+ sd->symm^= SYMM_Z;
+ update_prop= 1; break;
+ /* Interface */
+ case NKEY:
+ if(G.qual==0) {
+ toggle_blockhandler(curarea, VIEW3D_HANDLER_OBJECT, UI_PNL_TO_MOUSE);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ break;
+ /* Multires */
+ case PAGEUPKEY:
+ if(me && me->mr) {
+ me->mr->newlvl= ((Mesh*)ob->data)->mr->current+1;
+ multires_set_level(ob, ob->data, 0);
+ }
+ break;
+ case PAGEDOWNKEY:
+ if(me && me->mr) {
+ me->mr->newlvl= ((Mesh*)ob->data)->mr->current-1;
+ multires_set_level(ob, ob->data, 0);
+ }
+ break;
+ /* Partial Visibility */
+ case HKEY:
+ if(G.qual==LR_ALTKEY) {
+ waitcursor(1);
+ sculptmode_pmv_off(get_mesh(ob));
+ BIF_undo_push("Partial mesh hide");
+ allqueue(REDRAWVIEW3D,0);
+ waitcursor(0);
+ }
+ break;
+ /* Layers */
+ case ONEKEY:
+ do_layer_buttons(0); break;
+ case TWOKEY:
+ do_layer_buttons(1); break;
+ case THREEKEY:
+ do_layer_buttons(2); break;
+ case FOURKEY:
+ do_layer_buttons(3); break;
+ case FIVEKEY:
+ do_layer_buttons(4); break;
+ case SIXKEY:
+ do_layer_buttons(5); break;
+ case SEVENKEY:
+ do_layer_buttons(6); break;
+ case EIGHTKEY:
+ do_layer_buttons(7); break;
+ case NINEKEY:
+ do_layer_buttons(8); break;
+ case ZEROKEY:
+ do_layer_buttons(9); break;
+ case MINUSKEY:
+ do_layer_buttons(10); break;
+ case EQUALKEY:
+ do_layer_buttons(11); break;
+ case ACCENTGRAVEKEY:
+ do_layer_buttons(-1); break;
+ }
+
+ /* Redraw buttons window as well as view 3d (for floating panel) */
+ if(update_prop) {
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ }
+ } else {
+
+ if (U.flag & USER_NONUMPAD) {
+ event= convert_for_nonumpad(event);
+ }
+
+ switch(event) {
+
+ /* Afterqueue events */
+ case BACKBUFDRAW:
+ backdrawview3d(1);
+ break;
+ case RENDERPREVIEW:
+ BIF_view3d_previewrender(sa);
+ break;
+
+ case TABKEY:
+ /* Shift-Tabe handling (other cases are in toets) */
+ if (G.qual == LR_SHIFTKEY)
+ {
+ /* Snap toggle (only edit mesh right now) */
+ if (G.obedit && G.obedit->type==OB_MESH)
+ {
+ G.scene->snap_flag ^= SCE_SNAP;
+ allqueue(REDRAWHEADERS, 0);
+ }
+ }
+ break;
+
+ /* LEFTMOUSE and RIGHTMOUSE event codes can be swapped above,
+ * based on user preference USER_LMOUSESELECT
+ */
+ case LEFTMOUSE:
+ if ((G.obedit) || !(G.f&(G_VERTEXPAINT|G_WEIGHTPAINT|G_TEXTUREPAINT))) {
+ mouse_cursor();
+ }
+ else if (G.f & G_WEIGHTPAINT) {
+ weight_paint();
+ }
+ else if (G.f & G_VERTEXPAINT) {
+ vertex_paint();
+ }
+ else if (G.f & G_TEXTUREPAINT) {
+ imagepaint_paint(L_MOUSE, 1);
+ }
+ break;
+ case MIDDLEMOUSE:
+ handle_view_middlemouse();
+ break;
+ case RIGHTMOUSE:
+ if((G.obedit) && (G.qual & LR_CTRLKEY)==0) {
+ if(G.obedit->type==OB_MESH)
+ mouse_mesh();
+ else if ELEM(G.obedit->type, OB_CURVE, OB_SURF)
+ mouse_nurb();
+ else if(G.obedit->type==OB_MBALL)
+ mouse_mball();
+ else if(G.obedit->type==OB_LATTICE)
+ mouse_lattice();
+ else if(G.obedit->type==OB_ARMATURE)
+ mouse_armature();
+ }
+ else if((G.obedit && G.obedit->type==OB_MESH) && (G.qual == (LR_CTRLKEY|LR_ALTKEY)))
+ mouse_mesh(); /* loop select for 1 mousebutton dudes */
+ else if((G.obedit && G.obedit->type==OB_MESH) && (G.qual == (LR_CTRLKEY|LR_ALTKEY|LR_SHIFTKEY)))
+ mouse_mesh(); /* loop select for 1 mousebutton dudes */
+ else if(G.qual==LR_CTRLKEY)
+ mouse_select(); /* also allow in editmode, for vertex parenting */
+ else if(FACESEL_PAINT_TEST)
+ face_select();
+ else if( G.f & (G_VERTEXPAINT|G_TEXTUREPAINT))
+ sample_vpaint();
+ else
+ mouse_select(); /* does poses too */
+ break;
+ case WHEELUPMOUSE:
+ handle_view_wheelup();
+ doredraw= 1;
+ break;
+ case WHEELDOWNMOUSE:
+ handle_view_wheeldown();
+ doredraw= 1;
+ break;
+
+ case ONEKEY:
+ if(G.qual==LR_CTRLKEY) {
+ flip_subdivison(1);
+ }
+ else do_layer_buttons(0);
+ break;
+
+ case TWOKEY:
+ if(G.qual==LR_CTRLKEY) {
+ flip_subdivison(2);
+ }
+ else do_layer_buttons(1);
+ break;
+
+ case THREEKEY:
+ if(G.qual==LR_CTRLKEY) {
+ flip_subdivison(3);
+ }
+ else if ( G.qual == (LR_SHIFTKEY | LR_ALTKEY | LR_CTRLKEY) ) {
+ if ( (G.obedit) && (G.obedit->type==OB_MESH) )
+ select_faces_by_numverts(3);
+ }
+ else do_layer_buttons(2);
+ break;
+
+ case FOURKEY:
+ if(G.qual==LR_CTRLKEY) {
+ flip_subdivison(4);
+ }
+ else if ( G.qual == (LR_SHIFTKEY | LR_ALTKEY | LR_CTRLKEY) ) {
+ if ( (G.obedit) && (G.obedit->type==OB_MESH) )
+ select_faces_by_numverts(4);
+ }
+ else do_layer_buttons(3);
+ break;
+
+ case FIVEKEY:
+ if ( G.qual == (LR_SHIFTKEY | LR_ALTKEY | LR_CTRLKEY) ) {
+ if ( (G.obedit) && (G.obedit->type==OB_MESH) )
+ select_faces_by_numverts(5);
+ }
+ else do_layer_buttons(4);
+ break;
+
+ case SIXKEY:
+ do_layer_buttons(5); break;
+ case SEVENKEY:
+ do_layer_buttons(6); break;
+ case EIGHTKEY:
+ do_layer_buttons(7); break;
+ case NINEKEY:
+ do_layer_buttons(8); break;
+ case ZEROKEY:
+ do_layer_buttons(9); break;
+ case MINUSKEY:
+ do_layer_buttons(10); break;
+ case EQUALKEY:
+ do_layer_buttons(11); break;
+ case ACCENTGRAVEKEY:
+ do_layer_buttons(-1); break;
+
+ case SPACEKEY:
+ if(G.qual == LR_CTRLKEY) {
+ val= pupmenu("Manipulator%t|Enable/Disable|Translate|Rotate|Scale|Combo");
+ if(val>0) {
+ if(val==1) v3d->twflag ^= V3D_USE_MANIPULATOR;
+ else {
+ if(val==2) v3d->twtype= V3D_MANIP_TRANSLATE;
+ else if(val==3) v3d->twtype= V3D_MANIP_ROTATE;
+ else if(val==4) v3d->twtype= V3D_MANIP_SCALE;
+ else if(val==5) v3d->twtype= V3D_MANIP_TRANSLATE|V3D_MANIP_ROTATE|V3D_MANIP_SCALE;
+ v3d->twflag |= V3D_USE_MANIPULATOR;
+ }
+ doredraw= 1;
+ }
+ }
+ else if(G.qual == LR_ALTKEY) {
+ BIF_selectOrientation();
+ doredraw= 1;
+ }
+
+ break;
+
+ case AKEY:
+ if(G.qual & LR_CTRLKEY) apply_object(); /* also with shift! */
+ else if((G.qual==LR_SHIFTKEY)) {
+ toolbox_n_add();
+ }
+ else {
+ if(G.obedit) {
+ if(G.obedit->type==OB_MESH)
+ deselectall_mesh();
+ else if ELEM(G.obedit->type, OB_CURVE, OB_SURF)
+ deselectall_nurb();
+ else if(G.obedit->type==OB_MBALL)
+ deselectall_mball();
+ else if(G.obedit->type==OB_LATTICE)
+ deselectall_Latt();
+ else if(G.obedit->type==OB_ARMATURE)
+ deselectall_armature(1, 1); /* 1 == toggle */
+ }
+ else if (ob && (ob->flag & OB_POSEMODE)){
+ deselectall_posearmature(ob, 1, 1);
+ }
+ else {
+ if(FACESEL_PAINT_TEST) deselectall_tface();
+ else {
+ /* by design, the center of the active object
+ * (which need not necessarily by selected) will
+ * still be drawn as if it were selected.
+ */
+ deselectall();
+ }
+ }
+ }
+ break;
+ case BKEY:
+ if(G.qual==LR_ALTKEY)
+ view3d_edit_clipping(v3d);
+ else if(G.qual==LR_SHIFTKEY)
+ {
+ if(G.vd->persp==2)
+ set_render_border();
+ else
+ view3d_border_zoom();
+ }
+ else if(G.qual==LR_CTRLKEY) {
+ if(okee("Bake all selected")) {
+ extern void softbody_bake(Object *ob);
+ extern void fluidsimBake(Object *ob);
+ softbody_bake(NULL);
+ /* also bake first domain of selected objects... */
+ fluidsimBake(NULL);
+ }
+ }
+ else if(G.qual== (LR_ALTKEY|LR_CTRLKEY))
+ objects_bake_render_menu();
+ else if(G.qual==0)
+ borderselect();
+ break;
+ case CKEY:
+ if(G.qual==LR_CTRLKEY) {
+ if(ob && (ob->flag & OB_POSEMODE))
+ pose_copy_menu(); /* poseobject.c */
+ else
+ copy_attr_menu();
+ }
+ else if(G.qual==LR_ALTKEY) {
+ if(ob && (ob->flag & OB_POSEMODE))
+ pose_clear_constraints(); /* poseobject.c */
+ else
+ convertmenu(); /* editobject.c */
+ }
+ else if(G.qual==(LR_ALTKEY|LR_CTRLKEY))
+ add_constraint(0); /* editconstraint.c, generic for objects and posemode */
+ else if((G.qual==LR_SHIFTKEY)) {
+ view3d_home(1);
+ curs= give_cursor();
+ curs[0]=curs[1]=curs[2]= 0.0;
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ else if((G.obedit) && ELEM(G.obedit->type, OB_CURVE, OB_SURF) ) {
+ makecyclicNurb();
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ else if((G.qual==0)){
+ if (G.vd->persp==2)
+ /* center the camera offset */
+ G.vd->camdx= G.vd->camdy= 0.0;
+ else {
+ /*non camera center*/
+ float new_ofs[3];
+ curs= give_cursor();
+ new_ofs[0]= -curs[0];
+ new_ofs[1]= -curs[1];
+ new_ofs[2]= -curs[2];
+ smooth_view(G.vd, new_ofs, NULL, NULL, NULL);
+ }
+ scrarea_queue_winredraw(curarea);
+ }
+ break;
+ case DKEY:
+ if((G.qual==LR_SHIFTKEY)) {
+ duplicate_context_selected();
+ }
+ else if(G.qual==LR_ALTKEY) {
+ if(ob && (ob->flag & OB_POSEMODE))
+ error ("Duplicate not possible in posemode.");
+ else if((G.obedit==NULL))
+ adduplicate(0, 0);
+ }
+ else if(G.qual==LR_CTRLKEY) {
+ imagestodisplist();
+ }
+ else if((G.qual==0)){
+ pupval= pupmenu("Draw mode%t|BoundBox %x1|Wire %x2|OpenGL Solid %x3|Shaded Solid %x4|Textured Solid %x5");
+ if(pupval>0) {
+ G.vd->drawtype= pupval;
+ doredraw= 1;
+ }
+ }
+
+ break;
+ case EKEY:
+ if (G.qual==0){
+ if(G.obedit) {
+ if(G.obedit->type==OB_MESH)
+ extrude_mesh();
+ else if(G.obedit->type==OB_CURVE)
+ addvert_Nurb('e');
+ else if(G.obedit->type==OB_SURF)
+ extrude_nurb();
+ else if(G.obedit->type==OB_ARMATURE)
+ extrude_armature(0);
+ }
+ }
+ else if (G.qual==LR_CTRLKEY) {
+ if(G.obedit && G.obedit->type==OB_MESH)
+ Edge_Menu();
+ else if (FACESEL_PAINT_TEST)
+ seam_mark_clear_tface(0);
+ }
+ else if (G.qual==LR_SHIFTKEY) {
+ if (G.obedit && G.obedit->type==OB_MESH &&
+ !multires_level1_test()) {
+ initTransform(TFM_CREASE, CTX_EDGE);
+ Transform();
+ }
+ else if (G.obedit && G.obedit->type==OB_ARMATURE) {
+ extrude_armature(1);
+ }
+ }
+ break;
+ case FKEY:
+ if(G.obedit) {
+ if(G.obedit->type==OB_MESH) {
+ if(G.qual == LR_CTRLKEY)
+ Face_Menu();
+ else if((G.qual==LR_SHIFTKEY))
+ fill_mesh();
+ else if(G.qual==LR_ALTKEY)
+ beauty_fill();
+ else if(G.qual==(LR_CTRLKEY|LR_SHIFTKEY))
+ edge_flip();
+ else if (G.qual==0)
+ addedgeface_mesh();
+ else if ( G.qual ==
+ (LR_SHIFTKEY | LR_ALTKEY | LR_CTRLKEY) ) {
+ select_linked_flat_faces();
+ }
+
+ }
+ else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) addsegment_nurb();
+ }
+ else if(G.qual==LR_CTRLKEY)
+ sort_faces();
+ else if((G.qual==LR_SHIFTKEY)) {
+ if(ob && (ob->flag & OB_POSEMODE))
+ pose_activate_flipped_bone();
+ else if(G.f & G_WEIGHTPAINT)
+ pose_activate_flipped_bone();
+ else
+ fly();
+ }
+ else {
+ if (G.f & (G_VERTEXPAINT|G_WEIGHTPAINT|G_TEXTUREPAINT)){
+ G.f ^= G_FACESELECT;
+ allqueue(REDRAWVIEW3D, 1);
+ }
+ }
+
+ break;
+ case GKEY:
+ if((G.qual == LR_CTRLKEY)) {
+ if(G.obedit) {
+ if(ELEM(G.obedit->type, OB_MESH, OB_LATTICE))
+ vgroup_assign_with_menu();
+ }
+ else
+ group_operation_with_menu();
+ }
+ else if((G.qual == (LR_CTRLKEY|LR_SHIFTKEY))) {
+ if(G.obedit) {
+ if(ELEM(G.obedit->type, OB_MESH, OB_LATTICE))
+ vgroup_operation_with_menu();
+ }
+ }
+ else if((G.qual==LR_SHIFTKEY))
+ if(G.obedit) {
+ if(G.obedit->type==OB_MESH)
+ select_mesh_group_menu();
+ } else
+ select_object_grouped_menu();
+ else if((G.obedit==0) && G.qual==LR_ALTKEY) {
+ if(okee("Clear location")) {
+ clear_object('g');
+ }
+ }
+ else if(G.qual== (LR_CTRLKEY|LR_ALTKEY)) {
+ v3d->twtype= V3D_MANIP_TRANSLATE;
+ doredraw= 1;
+ }
+ else if((G.qual==0)) {
+ initTransform(TFM_TRANSLATION, CTX_NONE);
+ Transform();
+ }
+ break;
+ case HKEY:
+ if(G.obedit) {
+ if(G.obedit->type==OB_MESH) {
+ if(G.qual==LR_CTRLKEY)
+ add_hook();
+ else if(G.qual==LR_ALTKEY)
+ reveal_mesh();
+ else if((G.qual==LR_SHIFTKEY))
+ hide_mesh(1);
+ else if((G.qual==0))
+ hide_mesh(0);
+ }
+ else if(G.obedit->type== OB_SURF) {
+ if(G.qual==LR_CTRLKEY)
+ add_hook();
+ else if(G.qual==LR_ALTKEY)
+ revealNurb();
+ else if((G.qual==LR_SHIFTKEY))
+ hideNurb(1);
+ else if((G.qual==0))
+ hideNurb(0);
+ }
+ else if(G.obedit->type==OB_CURVE) {
+ if(G.qual==LR_CTRLKEY)
+ add_hook();
+ else if(G.qual==LR_ALTKEY)
+ revealNurb();
+ /* should be G.qual==LR_SHIFTKEY, but that is taken fro handles already */
+ else if((G.qual==(LR_ALTKEY|LR_SHIFTKEY)))
+ hideNurb(1);
+ /* should be G.qual==0, but that is taken for handles already */
+ else if((G.qual==(LR_ALTKEY|LR_CTRLKEY)))
+ hideNurb(0);
+ else {
+ if(G.qual==LR_CTRLKEY) /* conflict */
+ autocalchandlesNurb_all(1); /* flag=1, selected */
+ else if((G.qual==LR_SHIFTKEY))
+ sethandlesNurb(1);
+ else if((G.qual==0))
+ sethandlesNurb(3);
+
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ BIF_undo_push("Handle change");
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ }
+ else if(G.obedit->type==OB_LATTICE) {
+ if(G.qual==LR_CTRLKEY) add_hook();
+ }
+ else if(G.obedit->type==OB_MBALL) {
+ if(G.qual==LR_ALTKEY)
+ reveal_mball();
+ else if((G.qual==LR_SHIFTKEY))
+ hide_mball(1);
+ else if((G.qual==0))
+ hide_mball(0);
+ }
+ else if(G.obedit->type==OB_ARMATURE) {
+ if (G.qual==0)
+ hide_selected_armature_bones();
+ else if (G.qual==LR_SHIFTKEY)
+ hide_unselected_armature_bones();
+ else if (G.qual==LR_ALTKEY)
+ show_all_armature_bones();
+ }
+ }
+ else if(FACESEL_PAINT_TEST)
+ hide_tface();
+ else if(ob && (ob->flag & OB_POSEMODE)) {
+ if (G.qual==0)
+ hide_selected_pose_bones();
+ else if (G.qual==LR_SHIFTKEY)
+ hide_unselected_pose_bones();
+ else if (G.qual==LR_ALTKEY)
+ show_all_pose_bones();
+ }
+ /* Object mode only, other modes are accounted for above */
+ else if ((G.f & (G_VERTEXPAINT|G_TEXTUREPAINT|G_WEIGHTPAINT))==0) {
+ if(G.qual==LR_CTRLKEY)hookmenu();
+ else if(G.qual==LR_ALTKEY) show_objects();
+ else if(G.qual==LR_SHIFTKEY) hide_objects(0);
+ else hide_objects(1);
+ }
+ break;
+ case IKEY:
+ if(G.obedit) {
+ if(G.qual==LR_CTRLKEY)
+ selectswap_mesh();
+ } else if(G.qual==LR_CTRLKEY) {
+ if(ob && ob->type==OB_ARMATURE)
+ if(ob->flag & OB_POSEMODE)
+ pose_add_IK();
+ }
+ else if(G.qual==LR_ALTKEY) {
+ if(ob && ob->type==OB_ARMATURE)
+ if(ob->flag & OB_POSEMODE)
+ pose_clear_IK();
+ }
+ break;
+
+ case JKEY:
+ if(G.qual==LR_CTRLKEY) {
+ if( ob ) {
+ join_menu();
+ }
+ else if ((G.obedit) && ELEM(G.obedit->type, OB_CURVE, OB_SURF)) {
+ addsegment_nurb();
+ } else {
+ error("Can't join unless there is an active object");
+ }
+
+ }
+ else if(G.obedit) {
+ if(G.obedit->type==OB_MESH) {
+ join_triangles();
+ }
+ }
+
+ break;
+ case KKEY:
+ if(G.obedit) {
+ if (G.obedit->type==OB_MESH) {
+ if (G.qual==LR_SHIFTKEY)
+ KnifeSubdivide(KNIFE_PROMPT);
+ else if (G.qual==0)
+ LoopMenu();
+ }
+ else if(G.obedit->type==OB_SURF)
+ printknots();
+ }
+ else {
+ if((G.qual==LR_SHIFTKEY)) {
+ if(FACESEL_PAINT_TEST)
+ if (G.f & G_WEIGHTPAINT)
+ clear_wpaint_selectedfaces();
+ else
+ clear_vpaint_selectedfaces();
+ else if(G.f & G_VERTEXPAINT)
+ clear_vpaint();
+ else
+ select_select_keys();
+ }
+ else if (G.qual==0)
+ set_ob_ipoflags();
+ }
+
+ break;
+ case LKEY:
+ if(G.obedit) {
+ if(G.obedit->type==OB_MESH) {
+ if (G.qual & LR_CTRLKEY) {
+ if ((G.scene->selectmode & SCE_SELECT_FACE) == 0) {
+ selectconnected_mesh_all(); /* normal select linked */
+ } else {
+ selectconnected_delimit_mesh_all(); /* select linked with edge crease delimiting */
+ }
+ } else {
+ if ((G.scene->selectmode & SCE_SELECT_FACE) == 0) {
+ selectconnected_mesh();
+ } else {
+ selectconnected_delimit_mesh();
+ }
+ }
+ }
+ if(G.obedit->type==OB_ARMATURE)
+ selectconnected_armature();
+ else if ELEM(G.obedit->type, OB_CURVE, OB_SURF)
+ selectconnected_nurb();
+ }
+ else if(ob && (ob->flag & OB_POSEMODE)) {
+ selectconnected_posearmature();
+ }
+ else {
+ if(FACESEL_PAINT_TEST) {
+ if((G.qual==0))
+ select_linked_tfaces(0);
+ else if((G.qual==LR_SHIFTKEY))
+ select_linked_tfaces(1);
+ else if(G.qual==LR_CTRLKEY)
+ select_linked_tfaces(2);
+ }
+ else {
+ if((G.qual==0))
+ make_local_menu();
+ else if((G.qual==LR_SHIFTKEY))
+ selectlinks_menu();
+ else if(G.qual==LR_CTRLKEY)
+ make_links_menu();
+ }
+ }
+ break;
+ case MKEY:
+ if(G.obedit){
+ if (ELEM(G.qual, 0, LR_SHIFTKEY) && (G.obedit->type==OB_ARMATURE)) {
+ pose_movetolayer();
+ }
+ else if (G.qual==LR_ALTKEY) {
+ if(G.obedit->type==OB_MESH) {
+ mergemenu();
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ }
+ }
+ else if ((G.qual==0) || (G.qual==LR_CTRLKEY)) {
+ mirrormenu();
+ }
+ else if ( G.qual == (LR_SHIFTKEY | LR_ALTKEY | LR_CTRLKEY) ) {
+ if(G.obedit->type==OB_MESH) select_non_manifold();
+ }
+ }
+ else if(G.qual & LR_CTRLKEY) {
+ mirrormenu();
+ }
+ else if(G.qual==0 || G.qual==LR_SHIFTKEY) {
+ if(ob && (ob->flag & OB_POSEMODE))
+ pose_movetolayer();
+ else
+ movetolayer();
+ }
+ break;
+ case NKEY:
+ if((G.qual==0)) {
+ toggle_blockhandler(curarea, VIEW3D_HANDLER_OBJECT, UI_PNL_TO_MOUSE);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ else if(G.obedit) {
+ switch (G.obedit->type){
+ case OB_ARMATURE:
+ if(G.qual==LR_CTRLKEY) {
+ pupval= pupmenu("Recalculate Bone Roll Angles%t|Clear Roll (Z-Axis Up) %x1|Align Z-Axis to 3D-Cursor %x2");
+ if (pupval > 0) {
+ auto_align_armature(pupval - 1);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ }
+ break;
+ case OB_MESH:
+ if(G.qual==(LR_SHIFTKEY|LR_CTRLKEY)) {
+ if(okee("Recalculate normals inside")) {
+ righthandfaces(2);
+ allqueue(REDRAWVIEW3D, 0);
+ BIF_undo_push("Recalculate normals inside");
+ }
+ }
+ else if(G.qual==LR_CTRLKEY){
+ if(okee("Recalculate normals outside")) {
+ righthandfaces(1);
+ allqueue(REDRAWVIEW3D, 0);
+ BIF_undo_push("Recalculate normals outside");
+ }
+ }
+ break;
+ }
+ }
+
+ break;
+ case OKEY:
+ if (G.obedit) {
+ if (G.qual==LR_SHIFTKEY) {
+ G.scene->prop_mode = (G.scene->prop_mode+1)%7;
+ allqueue(REDRAWHEADERS, 0);
+ }
+ else if((G.qual==LR_ALTKEY)) {
+ if(G.scene->proportional==2) G.scene->proportional= 1;
+ else G.scene->proportional= 2;
+ allqueue(REDRAWHEADERS, 0);
+ }
+ else if((G.qual==0)) {
+ G.scene->proportional= !G.scene->proportional;
+ allqueue(REDRAWHEADERS, 0);
+ }
+ }
+ else if((G.qual==LR_SHIFTKEY || G.qual==(LR_ALTKEY|LR_SHIFTKEY))) {
+ flip_subdivison(-1);
+ }
+ else if(G.qual==LR_ALTKEY) {
+ if(okee("Clear origin")) {
+ clear_object('o');
+ }
+ }
+ break;
+
+ case PKEY:
+ if(G.obedit) {
+ if(G.qual==LR_CTRLKEY || G.qual==(LR_SHIFTKEY|LR_CTRLKEY)) {
+ if(G.obedit->type==OB_ARMATURE)
+ make_bone_parent();
+ else
+ make_parent();
+ }
+
+ else if(G.qual==LR_ALTKEY && G.obedit->type==OB_ARMATURE)
+ clear_bone_parent();
+ else if((G.qual==0) && (G.obedit->type==OB_ARMATURE))
+ select_bone_parent();
+ else if((G.qual==0) && G.obedit->type==OB_MESH)
+ separatemenu();
+ else if ((G.qual==0) && ELEM(G.obedit->type, OB_CURVE, OB_SURF))
+ separate_nurb();
+ else if (G.qual==LR_SHIFTKEY) {
+ initTransform(TFM_PUSHPULL, CTX_NONE);
+ Transform();
+ }
+ }
+ else if(G.qual==LR_CTRLKEY || G.qual==(LR_SHIFTKEY|LR_CTRLKEY))
+ make_parent();
+ else if(G.qual==LR_SHIFTKEY) {
+ toggle_blockhandler(curarea, VIEW3D_HANDLER_PREVIEW, 0);
+ doredraw= 1;
+ }
+ else if(G.qual==(LR_ALTKEY|LR_SHIFTKEY)) {
+ initTransform(TFM_PUSHPULL, CTX_NONE);
+ Transform();
+ }
+ else if(G.qual==LR_ALTKEY)
+ clear_parent();
+ else if(G.qual==(LR_ALTKEY|LR_CTRLKEY))
+ make_proxy();
+ else if(G.qual==(LR_ALTKEY|LR_CTRLKEY|LR_SHIFTKEY)) {
+ start_RBSimulation();
+ }
+ else if((G.qual==0) && (OBACT) && (OBACT->type==OB_ARMATURE) && (OBACT->flag & OB_POSEMODE))
+ select_bone_parent();
+ else if((G.qual==0)) {
+ start_game();
+ }
+ break;
+ case RKEY:
+ if((G.obedit==0) && G.qual==LR_ALTKEY) {
+ if(okee("Clear rotation")) {
+ clear_object('r');
+ }
+ }
+ else if(G.qual== (LR_CTRLKEY|LR_ALTKEY)) {
+ v3d->twtype= V3D_MANIP_ROTATE;
+ doredraw= 1;
+ }
+ else if (G.obedit) {
+ if((G.qual==LR_SHIFTKEY)) {
+ if ELEM(G.obedit->type, OB_CURVE, OB_SURF)
+ selectrow_nurb();
+ }
+ else if(G.qual==LR_CTRLKEY) {
+ if (G.obedit->type==OB_MESH) {
+ CutEdgeloop(1);
+ BIF_undo_push("Cut Edgeloop");
+ }
+ else if (G.obedit->type==OB_ARMATURE) {
+ initTransform(TFM_BONE_ROLL, CTX_NONE);
+ Transform();
+ }
+ }
+ else if((G.qual==0)) {
+ initTransform(TFM_ROTATION, CTX_NONE);
+ Transform();
+ }
+ }
+ else if((G.qual==0)) {
+ initTransform(TFM_ROTATION, CTX_NONE);
+ Transform();
+ }
+ break;
+ case SKEY:
+ if(G.qual== (LR_CTRLKEY|LR_ALTKEY)) {
+ v3d->twtype= V3D_MANIP_SCALE;
+ doredraw= 1;
+ }
+ else if(G.obedit) {
+
+ if(G.qual==LR_ALTKEY) {
+ if(G.obedit->type==OB_ARMATURE) {
+ initTransform(TFM_BONESIZE, CTX_NONE);
+ }
+ else if (G.obedit->type==OB_CURVE) {
+ initTransform(TFM_CURVE_SHRINKFATTEN, CTX_NONE);
+ } else {
+ initTransform(TFM_SHRINKFATTEN, CTX_NONE);
+ }
+ Transform();
+ }
+ else if(G.qual==LR_CTRLKEY) {
+ initTransform(TFM_SHEAR, CTX_NONE);
+ Transform();
+ }
+ else if(G.qual==LR_SHIFTKEY)
+ snapmenu();
+ else if(G.qual==0) {
+ if(G.obedit->type==OB_ARMATURE) {
+ bArmature *arm= G.obedit->data;
+ if(arm->drawtype==ARM_ENVELOPE)
+ initTransform(TFM_BONE_ENVELOPE, CTX_NONE);
+ else
+ initTransform(TFM_RESIZE, CTX_NONE);
+ }
+ else
+ initTransform(TFM_RESIZE, CTX_NONE);
+ Transform();
+ }
+ else if(G.qual==(LR_SHIFTKEY|LR_CTRLKEY)){
+ initTransform(TFM_TOSPHERE, CTX_NONE);
+ Transform();
+ }
+ if ( G.qual == (LR_SHIFTKEY | LR_ALTKEY | LR_CTRLKEY) ) {
+ if(G.obedit->type==OB_MESH) select_sharp_edges();
+ }
+ }
+ else if(G.qual==LR_ALTKEY) {
+ if(G.f & G_WEIGHTPAINT)
+ ob= ob->parent;
+ if(ob && (ob->flag & OB_POSEMODE)) {
+ bArmature *arm= ob->data;
+ if( ELEM(arm->drawtype, ARM_B_BONE, ARM_ENVELOPE)) {
+ initTransform(TFM_BONESIZE, CTX_NONE);
+ Transform();
+ break;
+ }
+ }
+
+ if(okee("Clear scale")) {
+ clear_object('s');
+ }
+ }
+ else if(G.qual==LR_SHIFTKEY) {
+ snapmenu();
+ }
+ else if((G.qual==0)) {
+ initTransform(TFM_RESIZE, CTX_NONE);
+ Transform();
+ }
+ else if(G.qual==(LR_SHIFTKEY|LR_CTRLKEY)) {
+ initTransform(TFM_TOSPHERE, CTX_NONE);
+ Transform();
+ }
+ else if(G.qual==(LR_CTRLKEY|LR_ALTKEY|LR_SHIFTKEY)) {
+ initTransform(TFM_SHEAR, CTX_NONE);
+ Transform();
+ }
+ break;
+ case TKEY:
+ if(G.qual == LR_SHIFTKEY) { /* toggle texture in solid draw mode */
+ G.vd->flag2 ^= V3D_SOLID_TEX;
+ allqueue(REDRAWVIEW3D, 0);
+ } else if(G.obedit){
+ if((G.qual & LR_CTRLKEY) && G.obedit->type==OB_MESH) {
+ convert_to_triface(G.qual & LR_SHIFTKEY);
+ allqueue(REDRAWVIEW3D, 0);
+ if (EM_texFaceCheck())
+ allqueue(REDRAWIMAGE, 0);
+
+ countall();
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ }
+ if (G.obedit->type==OB_CURVE) {
+ if (G.qual==LR_ALTKEY) {
+ clear_tilt();
+ }
+ else if (G.qual==0) {
+ initTransform(TFM_TILT, CTX_NONE);
+ Transform();
+ }
+ }
+ }
+ else if(G.qual==LR_CTRLKEY) {
+ if(ob && (ob->flag & OB_POSEMODE));
+ else make_track();
+ }
+ else if(G.qual==LR_ALTKEY) {
+ if(ob && (ob->flag & OB_POSEMODE));
+ else clear_track();
+ }
+ else if((G.qual==0)){
+ texspace_edit();
+ }
+
+ break;
+ case UKEY:
+ /*// Use Ctrl Z like everybody else
+ if(G.obedit) {
+ if(G.obedit->type==OB_MESH) {
+ if(G.qual==0) BIF_undo(); else BIF_redo();
+ }
+ else if ELEM5(G.obedit->type, OB_CURVE, OB_SURF, OB_MBALL, OB_LATTICE, OB_ARMATURE) {
+ if(G.qual==0) BIF_undo(); else BIF_redo();
+ }
+ }*/
+ if(G.obedit) {
+ if(G.obedit->type==OB_MESH && G.qual==0) {
+ uv_autocalc_tface();
+ }
+ }
+ else if((G.qual==0)) {
+ if(G.f & G_WEIGHTPAINT)
+ BIF_undo();
+ else if(G.f & G_VERTEXPAINT)
+ BIF_undo();
+ else if(G.f & G_TEXTUREPAINT)
+ imagepaint_undo();
+ else {
+ single_user();
+ }
+ }
+
+ break;
+ case VKEY:
+ if ((G.qual==LR_CTRLKEY)) {
+ if ((G.obedit) && G.obedit->type==OB_MESH) {
+ Vertex_Menu();
+ }
+ } else if((G.qual==LR_SHIFTKEY)) {
+ if ((G.obedit) && G.obedit->type==OB_MESH) {
+ align_view_to_selected(v3d);
+ }
+ else if (FACESEL_PAINT_TEST) {
+ align_view_to_selected(v3d);
+ }
+ }
+ else if(G.qual==LR_ALTKEY)
+ image_aspect();
+ else if (G.qual==0){
+ if(G.obedit) {
+ if(G.obedit->type==OB_MESH) {
+ mesh_rip();
+ }
+ else if(G.obedit->type==OB_CURVE) {
+ sethandlesNurb(2);
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ BIF_undo_push("Handle change");
+ }
+ }
+ else if(ob && ob->type == OB_MESH)
+ set_vpaint();
+ }
+ break;
+ case WKEY:
+ if((G.qual==LR_SHIFTKEY)) {
+ initTransform(TFM_WARP, CTX_NONE);
+ Transform();
+ }
+ /*else if(G.qual==LR_ALTKEY) {}*/
+ else if(G.qual==LR_CTRLKEY) {
+ if(G.obedit) {
+ if ELEM(G.obedit->type, OB_CURVE, OB_SURF) {
+ switchdirectionNurb2();
+ }
+ }
+ }
+ else if((G.qual==0))
+ special_editmenu();
+
+ break;
+ case XKEY:
+ case DELKEY:
+ if(G.qual==0 || G.qual==LR_SHIFTKEY)
+ delete_context_selected();
+ break;
+ case YKEY:
+ if((G.qual==0) && (G.obedit)) {
+ if(G.obedit->type==OB_MESH) split_mesh();
+ }
+ break;
+ case ZKEY:
+ toggle_shading();
+
+ scrarea_queue_headredraw(curarea);
+ scrarea_queue_winredraw(curarea);
+ break;
+
+ case HOMEKEY:
+ if(G.qual==0)
+ view3d_home(0);
+ break;
+ case COMMAKEY:
+ if(G.qual==LR_CTRLKEY) {
+ G.vd->around= V3D_CENTROID;
+ } else if(G.qual==LR_SHIFTKEY) {
+ G.vd->around= V3D_CENTROID;
+ } else if(G.qual==0) {
+ G.vd->around= V3D_CENTER;
+ }
+ handle_view3d_around();
+
+ scrarea_queue_headredraw(curarea);
+ scrarea_queue_winredraw(curarea);
+ break;
+
+ case PERIODKEY:
+ if(G.qual==LR_CTRLKEY) {
+ G.vd->around= V3D_LOCAL;
+ } else if(G.qual==LR_ALTKEY) {
+ G.vd->around= V3D_ACTIVE;
+ } else if(G.qual==0) {
+ G.vd->around= V3D_CURSOR;
+ }
+ handle_view3d_around();
+
+ scrarea_queue_headredraw(curarea);
+ scrarea_queue_winredraw(curarea);
+ break;
+
+ case PADSLASHKEY:
+ if(G.qual==0) {
+ if(G.vd->localview) {
+ G.vd->localview= 0;
+ endlocalview(curarea);
+ }
+ else {
+ G.vd->localview= 1;
+ initlocalview();
+ }
+ scrarea_queue_headredraw(curarea);
+ }
+ break;
+ case PADASTERKEY: /* '*' */
+ if(G.qual==0) {
+ if(ob) {
+ if ((G.obedit) && (G.obedit->type == OB_MESH)) {
+ editmesh_align_view_to_selected(G.vd, 3);
+ }
+ else if (FACESEL_PAINT_TEST) {
+ if(ob->type==OB_MESH) {
+ Mesh *me= ob->data;
+ faceselect_align_view_to_selected(G.vd, me, 3);
+ }
+ }
+ else
+ obmat_to_viewmat(ob, 1);
+
+ if(G.vd->persp==2) G.vd->persp= 1;
+ scrarea_queue_winredraw(curarea);
+ }
+ }
+ break;
+ case PADPERIOD: /* '.' */
+ if(G.qual==0)
+ centerview();
+ break;
+
+ case PAGEUPKEY:
+ if(G.qual==LR_CTRLKEY)
+ movekey_obipo(1);
+ else if((G.qual==0))
+ nextkey_obipo(1); /* in editipo.c */
+ break;
+
+ case PAGEDOWNKEY:
+ if(G.qual==LR_CTRLKEY)
+ movekey_obipo(-1);
+ else if((G.qual==0))
+ nextkey_obipo(-1);
+ break;
+
+ case PAD0: case PAD1: case PAD2: case PAD3: case PAD4:
+ case PAD5: case PAD6: case PAD7: case PAD8: case PAD9:
+ case PADENTER:
+ persptoetsen(event);
+ doredraw= 1;
+ break;
+ case PADMINUS:
+ if ( (G.qual==LR_CTRLKEY)
+ && (G.obedit) && (G.obedit->type==OB_MESH) )
+ select_less();
+ else if ( (G.qual==LR_CTRLKEY)
+ && (G.obedit) && (G.obedit->type==OB_CURVE) )
+ select_less_nurb();
+ else if ( (G.qual==LR_CTRLKEY)
+ && (G.obedit) && (G.obedit->type==OB_SURF) )
+ select_less_nurb();
+ else {
+ persptoetsen(event);
+ doredraw= 1;
+ }
+ break;
+
+ case PADPLUSKEY:
+ if ( (G.qual==LR_CTRLKEY)
+ && (G.obedit) && (G.obedit->type==OB_MESH) )
+ select_more();
+ else if ( (G.qual==LR_CTRLKEY)
+ && (G.obedit) && (G.obedit->type==OB_CURVE) )
+ select_more_nurb();
+ else if ( (G.qual==LR_CTRLKEY)
+ && (G.obedit) && (G.obedit->type==OB_SURF) )
+ select_more_nurb();
+ else {
+ persptoetsen(event);
+ doredraw= 1;
+ }
+ break;
+
+ case ESCKEY:
+ if(G.qual==0) {
+ if (G.vd->flag & V3D_DISPIMAGE) {
+ G.vd->flag &= ~V3D_DISPIMAGE;
+ doredraw= 1;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ if(doredraw) {
+ scrarea_queue_winredraw(curarea);
+ scrarea_queue_headredraw(curarea);
+ }
+}
+
+static void initview3d(ScrArea *sa)
+{
+ View3D *vd;
+
+ vd= MEM_callocN(sizeof(View3D), "initview3d");
+ BLI_addhead(&sa->spacedata, vd); /* addhead! not addtail */
+
+ vd->spacetype= SPACE_VIEW3D;
+ vd->blockscale= 0.7f;
+ vd->viewquat[0]= 1.0f;
+ vd->viewquat[1]= vd->viewquat[2]= vd->viewquat[3]= 0.0f;
+ vd->persp= 1;
+ vd->drawtype= OB_WIRE;
+ vd->view= 7;
+ vd->dist= 10.0;
+ vd->lens= 35.0f;
+ vd->near= 0.01f;
+ vd->far= 500.0f;
+ vd->grid= 1.0f;
+ vd->gridlines= 16;
+ vd->gridsubdiv = 10;
+
+ vd->lay= vd->layact= 1;
+ if(G.scene) {
+ vd->lay= vd->layact= G.scene->lay;
+ vd->camera= G.scene->camera;
+ }
+ vd->scenelock= 1;
+ vd->gridflag |= V3D_SHOW_X;
+ vd->gridflag |= V3D_SHOW_Y;
+ vd->gridflag |= V3D_SHOW_FLOOR;
+ vd->gridflag &= ~V3D_SHOW_Z;
+
+ vd->depths= NULL;
+}
+
+
+/* ******************** SPACE: IPO ********************** */
+
+static void changeview2dspace(ScrArea *sa, void *spacedata)
+{
+ if(G.v2d==0) return;
+
+ test_view2d(G.v2d, curarea->winx, curarea->winy);
+ myortho2(G.v2d->cur.xmin, G.v2d->cur.xmax, G.v2d->cur.ymin, G.v2d->cur.ymax);
+}
+
+static int get_cfra_from_dx(SpaceIpo * sipo, int dx)
+{
+ if (sipo->blocktype == ID_SEQ) {
+ Sequence * seq = (Sequence*) sipo->from;
+ if (!seq) {
+ return dx;
+ }
+ if ((seq->flag & SEQ_IPO_FRAME_LOCKED) != 0) {
+ return dx;
+ } else {
+ float m= (seq->enddisp - seq->startdisp)/100.0f;
+ float cfra = dx * m + seq->startdisp;
+
+ return (int) cfra;
+ }
+ } else {
+ return dx;
+ }
+}
+
+static void winqreadipospace(ScrArea *sa, void *spacedata, BWinEvent *evt)
+{
+ extern void do_ipobuts(unsigned short event); /* drawipo.c */
+ unsigned short event= evt->event;
+ short val= evt->val;
+ SpaceIpo *sipo= curarea->spacedata.first;
+ View2D *v2d= &sipo->v2d;
+ float dx, dy;
+ int cfra, doredraw= 0;
+ short mval[2];
+ short mousebut = L_MOUSE;
+
+ if(sa->win==0) return;
+
+ if(val) {
+ if( uiDoBlocks(&sa->uiblocks, event)!=UI_NOTHING ) event= 0;
+
+ /* swap mouse buttons based on user preference */
+ if (U.flag & USER_LMOUSESELECT) {
+ if (event == LEFTMOUSE) {
+ event = RIGHTMOUSE;
+ mousebut = L_MOUSE;
+ } else if (event == RIGHTMOUSE) {
+ event = LEFTMOUSE;
+ mousebut = R_MOUSE;
+ }
+ }
+
+ switch(event) {
+ case UI_BUT_EVENT:
+ /* note: bad bad code, will be cleaned! is because event queues are all shattered */
+ if(val>0 && val < 256) do_ipowin_buts(val-1);
+ else do_ipobuts(val);
+ break;
+
+ case LEFTMOUSE:
+ if( in_ipo_buttons() ) {
+ do_ipo_selectbuttons();
+ doredraw= 1;
+ }
+ else if(view2dmove(LEFTMOUSE)); /* only checks for sliders */
+ else if((G.qual & LR_CTRLKEY) && (sipo->showkey==0)) add_vert_ipo();
+ else {
+ do {
+ getmouseco_areawin(mval);
+ areamouseco_to_ipoco(v2d, mval, &dx, &dy);
+
+ cfra = get_cfra_from_dx(sipo, (int)dx);
+ if(cfra< 1) cfra= 1;
+
+ if( cfra!=CFRA ) {
+ CFRA= cfra;
+ update_for_newframe_nodraw(0); /* 1 = nosound */
+ force_draw_all(0); /* To make constraint sliders redraw */
+ }
+ else PIL_sleep_ms(30);
+
+ } while(get_mbut() & mousebut);
+ }
+ break;
+ case RIGHTMOUSE:
+ mouse_select_ipo();
+ allqueue(REDRAWMARKER, 0);
+ break;
+ case MIDDLEMOUSE:
+ if(in_ipo_buttons()) {
+ scroll_ipobuts();
+ }
+ else view2dmove(event); /* in drawipo.c */
+ break;
+ case WHEELUPMOUSE:
+ case WHEELDOWNMOUSE:
+ view2dmove(event); /* in drawipo.c */
+ break;
+ case PADPLUSKEY:
+ view2d_zoom(v2d, 0.1154f, sa->winx, sa->winy);
+ doredraw= 1;
+ break;
+ case PADMINUS:
+ view2d_zoom(v2d, -0.15f, sa->winx, sa->winy);
+ doredraw= 1;
+ break;
+ case PAGEUPKEY:
+ if(G.qual & LR_CTRLKEY)
+ movekey_ipo(1);
+ else if(G.qual & LR_SHIFTKEY)
+ nextkey_ipo(1);
+ else
+ nextprev_marker(1);
+ break;
+ case PAGEDOWNKEY:
+ if(G.qual & LR_CTRLKEY)
+ movekey_ipo(-1);
+ else if(G.qual & LR_SHIFTKEY)
+ nextkey_ipo(-1);
+ else
+ nextprev_marker(-1);
+ break;
+ case HOMEKEY:
+ if((G.qual==0))
+ do_ipo_buttons(B_IPOHOME);
+ break;
+ case PADPERIOD:
+ if((G.qual==0))
+ do_ipo_buttons(B_IPOVIEWCENTER);
+ break;
+
+ case AKEY:
+ if (G.qual & LR_CTRLKEY) {
+ deselect_markers(1, 0);
+ allqueue(REDRAWMARKER, 0);
+ }
+ else if (G.qual==0) {
+ if(in_ipo_buttons()) {
+ swap_visible_editipo();
+ }
+ else {
+ swap_selectall_editipo();
+ }
+ allspace (REMAKEIPO, 0);
+ allqueue (REDRAWNLA, 0);
+ allqueue (REDRAWACTION, 0);
+ }
+
+ break;
+ case BKEY:
+ if (G.qual==0)
+ borderselect_ipo();
+ else if (G.qual==LR_CTRLKEY) {
+ borderselect_markers();
+ }
+ break;
+ case CKEY:
+ if (G.qual == LR_SHIFTKEY)
+ center_currframe();
+ else
+ move_to_frame();
+ break;
+ case DKEY:
+ if (G.qual==LR_SHIFTKEY) {
+ add_duplicate_editipo();
+ } else if (G.qual == (LR_CTRLKEY|LR_SHIFTKEY)) {
+ duplicate_marker();
+ allqueue(REDRAWMARKER, 0);
+ }
+ break;
+ case GKEY:
+ if (G.qual & LR_CTRLKEY) {
+ transform_markers('g', 0);
+ allqueue(REDRAWMARKER, 0);
+ } else if (G.qual==0)
+ transform_ipo('g');
+ break;
+ case HKEY:
+ if (G.qual==LR_ALTKEY)
+ sethandles_ipo(HD_AUTO_ANIM);
+ if (G.qual==LR_SHIFTKEY)
+ sethandles_ipo(HD_AUTO);
+ else if (G.qual==0)
+ sethandles_ipo(HD_ALIGN);
+ break;
+ case JKEY:
+ if (G.qual==LR_CTRLKEY)
+ join_ipo_menu();
+ break;
+ case KKEY:
+ if (G.qual==0) {
+ ipo_toggle_showkey();
+ scrarea_queue_headredraw(curarea);
+ allqueue(REDRAWVIEW3D, 0);
+ doredraw= 1;
+ }
+ break;
+ case MKEY:
+ if (G.qual==0) {
+ add_marker(CFRA);
+ } else if (G.qual==LR_SHIFTKEY) {
+ ipo_mirror_menu();
+ break;
+ } else if (G.qual == LR_CTRLKEY) {
+ rename_marker();
+ } else {
+ break;
+ }
+ allqueue(REDRAWMARKER, 0);
+ break;
+ case NKEY:
+ toggle_blockhandler(sa, IPO_HANDLER_PROPERTIES, UI_PNL_TO_MOUSE);
+ doredraw= 1;
+ break;
+ case OKEY:
+ if (G.qual==LR_SHIFTKEY)
+ smooth_ipo();
+ else
+ clean_ipo();
+ break;
+ case PKEY:
+ if (G.qual & LR_CTRLKEY) /* set preview range */
+ anim_previewrange_set();
+ else if (G.qual & LR_ALTKEY) /* clear preview range */
+ anim_previewrange_clear();
+ allqueue(REDRAWTIME, 0);
+ allqueue(REDRAWBUTSALL, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWNLA, 0);
+ allqueue(REDRAWIPO, 0);
+ break;
+ case RKEY:
+ if (G.qual==LR_CTRLKEY)
+ ipo_record();
+ else
+ transform_ipo('r');
+ break;
+ case SKEY:
+ if (G.qual==LR_SHIFTKEY) {
+ ipo_snap_menu();
+ }
+ else if (G.qual==0)
+ transform_ipo('s');
+ break;
+ case TKEY:
+ if (G.qual==0)
+ set_ipotype();
+ break;
+ case VKEY:
+ if (G.qual==0)
+ sethandles_ipo(HD_VECT);
+ break;
+ case XKEY:
+ case DELKEY:
+ if (okee("Erase selected")) {
+ remove_marker();
+ del_ipo(0);
+
+ /* note: don't update the other spaces (in particular ipo)
+ * or else curves disappear.
+ */
+ allqueue(REDRAWTIME, 0);
+ allqueue(REDRAWSOUND, 0);
+ }
+ break;
+ case ACCENTGRAVEKEY:
+ if((G.qual==0)) {
+ do_ipo_buttons(B_IPOVIEWALL);
+ allqueue(REDRAWIPO, 0);
+ }
+ break;
+
+ }
+ }
+
+ if(doredraw) scrarea_queue_winredraw(sa);
+}
+
+void initipo(ScrArea *sa)
+{
+ SpaceIpo *sipo;
+
+ sipo= MEM_callocN(sizeof(SpaceIpo), "initipo");
+ BLI_addhead(&sa->spacedata, sipo);
+
+ sipo->spacetype= SPACE_IPO;
+ sipo->blockscale= 0.7f;
+
+ /* sipo space loopt van (0,-?) tot (??,?) */
+ sipo->v2d.tot.xmin= 0.0;
+ sipo->v2d.tot.ymin= -10.0;
+ sipo->v2d.tot.xmax= G.scene->r.efra;
+ sipo->v2d.tot.ymax= 10.0;
+
+ sipo->v2d.cur= sipo->v2d.tot;
+
+ sipo->v2d.min[0]= 0.01f;
+ sipo->v2d.min[1]= 0.01f;
+
+ sipo->v2d.max[0]= 15000.0f;
+ sipo->v2d.max[1]= 10000.0f;
+
+ sipo->v2d.scroll= L_SCROLL+B_SCROLL;
+ sipo->v2d.keeptot= 0;
+
+ sipo->blocktype= ID_OB;
+}
+
+/* ******************** SPACE: INFO ********************** */
+
+void space_mipmap_button_function(int event) {
+ set_mipmap(!(U.gameflags & USER_DISABLE_MIPMAP));
+
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+#if 0
+static void space_sound_button_function(int event)
+{
+ int a;
+ SYS_SystemHandle syshandle;
+
+ if ((syshandle = SYS_GetSystem()))
+ {
+ a = (U.gameflags & USER_DISABLE_SOUND);
+ SYS_WriteCommandLineInt(syshandle, "noaudio", a);
+ }
+}
+#endif
+
+
+static char *iconfile_menu(void)
+{
+ static char string[512];
+ char *str = string;
+ IconFile *ifile;
+ ListBase *iconfilelist = BIF_iconfile_list();
+
+ str += sprintf(str, "Built-in %%x0|%%l|");
+
+ for(ifile=iconfilelist->first; ifile; ifile=ifile->next) {
+ str += sprintf(str, "%s %%x%d|", ifile->filename, ifile->index);
+ }
+
+ return string;
+}
+
+static void set_userdef_iconfile_cb(void *menuindex, void *unused2)
+{
+ bTheme *btheme= U.themes.first;
+ IconFile *ifile;
+ ListBase *iconfilelist = BIF_iconfile_list();
+ int index = *((int *)menuindex);
+
+ if (index==0) {
+ BLI_strncpy(btheme->tui.iconfile, "", sizeof(btheme->tui.iconfile));
+ return;
+ }
+
+ for(ifile=iconfilelist->first; ifile; ifile=ifile->next) {
+ if (index == ifile->index) {
+ BLI_strncpy(btheme->tui.iconfile, ifile->filename, sizeof(btheme->tui.iconfile));
+ }
+ }
+}
+
+/* needed for event; choose new 'curmain' resets it... */
+static short th_curcol= TH_BACK;
+static char *th_curcol_ptr= NULL;
+static char th_curcol_arr[4]={0, 0, 0, 255};
+
+static void info_user_themebuts(uiBlock *block, short y1, short y2, short y3)
+{
+ bTheme *btheme, *bt;
+ int spacetype= 0;
+ static short cur=1, curmain=2;
+ short a, tot=0, isbuiltin= 0;
+ char string[21*32], *strp, *col;
+ /* for choosing an icon image based on index in the cached list */
+ static int iconfileindex=0;
+
+ y3= y2+23; /* exception! */
+
+ /* count total, max 16! */
+ for(bt= U.themes.first; bt; bt= bt->next) tot++;
+
+ /* if cur not is 1; move that to front of list */
+ if(cur!=1) {
+ a= 1;
+ for(bt= U.themes.first; bt; bt= bt->next, a++) {
+ if(a==cur) {
+ BLI_remlink(&U.themes, bt);
+ BLI_addhead(&U.themes, bt);
+ allqueue(REDRAWALL, 0);
+ cur= 1;
+ break;
+ }
+ }
+ }
+
+ /* the current theme */
+ btheme= U.themes.first;
+ if(strcmp(btheme->name, "Default")==0) isbuiltin= 1;
+
+ /* construct popup script */
+ string[0]= 0;
+ for(bt= U.themes.first; bt; bt= bt->next) {
+ strcat(string, bt->name);
+ if(btheme->next) strcat(string, " |");
+ }
+ uiDefButS(block, MENU, B_UPDATE_THEME_ICONS, string, 45,y3,200,20, &cur, 0, 0, 0, 0, "Current theme");
+
+
+ /* add / delete / name */
+
+ if(tot<16)
+ uiDefBut(block, BUT, B_ADD_THEME, "Add", 45,y2,200,20, NULL, 0, 0, 0, 0, "Makes new copy of this theme");
+ if(tot>1 && isbuiltin==0)
+ uiDefBut(block, BUT, B_DEL_THEME, "Delete", 45,y1,200,20, NULL, 0, 0, 0, 0, "Delete theme");
+
+ if(isbuiltin) return;
+
+ /* name */
+ uiDefBut(block, TEX, B_NAME_THEME, "", 255,y3,200,20, btheme->name, 1.0, 30.0, 0, 0, "Rename theme");
+
+ /* main choices pup: note, it uses collums, and the seperators (%l) then have to fill both halves equally for the menu to work */
+ uiDefButS(block, MENU, B_CHANGE_THEME, "UI and Buttons %x1|%l|3D View %x2|%l|Ipo Curve Editor %x3|Action Editor %x4|"
+ "NLA Editor %x5|%l|UV/Image Editor %x6|Video Sequence Editor %x7|Node Editor %x16|Timeline %x15|%l|Audio Window %x8|Text Editor %x9|%l|User Preferences %x10|"
+ "Outliner %x11|Buttons Window %x12|%l|File Browser %x13|Image Browser %x14",
+ 255,y2,200,20, &curmain, 0, 0, 0, 0, "Specify theme for...");
+ if(curmain==1) spacetype= 0;
+ else if(curmain==2) spacetype= SPACE_VIEW3D;
+ else if(curmain==3) spacetype= SPACE_IPO;
+ else if(curmain==4) spacetype= SPACE_ACTION;
+ else if(curmain==5) spacetype= SPACE_NLA;
+ else if(curmain==6) spacetype= SPACE_IMAGE;
+ else if(curmain==7) spacetype= SPACE_SEQ;
+ else if(curmain==8) spacetype= SPACE_SOUND;
+ else if(curmain==9) spacetype= SPACE_TEXT;
+ else if(curmain==10) spacetype= SPACE_INFO;
+ else if(curmain==11) spacetype= SPACE_OOPS;
+ else if(curmain==12) spacetype= SPACE_BUTS;
+ else if(curmain==13) spacetype= SPACE_FILE;
+ else if(curmain==14) spacetype= SPACE_IMASEL;
+ else if(curmain==15) spacetype= SPACE_TIME;
+ else if(curmain==16) spacetype= SPACE_NODE;
+ else return; /* only needed while coding... when adding themes for more windows */
+
+ /* color choices pup */
+ if(curmain==1) {
+ strp= BIF_ThemeColorsPup(0);
+ if(th_curcol==TH_BACK) th_curcol= TH_BUT_OUTLINE; /* switching main choices... */
+ }
+ else strp= BIF_ThemeColorsPup(spacetype);
+
+ uiDefButS(block, MENU, B_REDR, strp, 255,y1,200,20, &th_curcol, 0, 0, 0, 0, "Current color");
+ MEM_freeN(strp);
+
+ th_curcol_ptr= col= BIF_ThemeGetColorPtr(btheme, spacetype, th_curcol);
+ if(col==NULL) return;
+
+ /* first handle exceptions, special single values, row selection, etc */
+ if(th_curcol==TH_VERTEX_SIZE) {
+ uiDefButC(block, NUMSLI, B_UPDATE_THEME,"Vertex size ", 465,y3,200,20, col, 1.0, 10.0, 0, 0, "");
+ }
+ else if(th_curcol==TH_FACEDOT_SIZE) {
+ uiDefButC(block, NUMSLI, B_UPDATE_THEME,"Face dot size ", 465,y3,200,20, col, 1.0, 10.0, 0, 0, "");
+ }
+ else if(th_curcol==TH_BUT_DRAWTYPE) {
+ uiBlockBeginAlign(block);
+ uiDefButC(block, ROW, B_UPDATE_THEME, "Shaded", 465,y2,80,20, col, 2.0, (float) TH_SHADED, 0, 0, "");
+ uiDefButC(block, ROW, B_UPDATE_THEME, "Rounded", 545,y2,80,20, col, 2.0, (float) TH_ROUNDED, 0, 0, "");
+ uiDefButC(block, ROW, B_UPDATE_THEME, "Minimal", 625,y2,80,20, col, 2.0, (float) TH_MINIMAL, 0, 0, "");
+ uiDefButC(block, ROW, B_UPDATE_THEME, "OldSkool", 705,y2,80,20, col, 2.0, (float) TH_OLDSKOOL, 0, 0, "");
+ uiBlockEndAlign(block);
+ }
+ else if(th_curcol==TH_ICONFILE) {
+ uiBut *but;
+
+ /* set the icon file menu to the correct icon file index for what's stored in the theme values */
+ iconfileindex= BIF_iconfile_get_index(btheme->tui.iconfile);
+
+ but = uiDefButI(block, MENU, B_UPDATE_THEME_ICONS, iconfile_menu(),
+ 465,y2,200,20, &iconfileindex, 0, 0, 0, 0, "The icon PNG file to use, searching in .blender/icons");
+ uiButSetFunc(but, set_userdef_iconfile_cb, &iconfileindex, NULL);
+
+ }
+ else {
+ uiBlockBeginAlign(block);
+ if ELEM9(th_curcol, TH_PANEL, TH_LAMP, TH_FACE, TH_FACE_SELECT, TH_EDITMESH_ACTIVE, TH_MENU_BACK, TH_MENU_HILITE, TH_MENU_ITEM, TH_NODE) {
+ uiDefButC(block, NUMSLI, B_UPDATE_THEME,"A ", 465,y3+25,200,20, col+3, 0.0, 255.0, B_THEMECOL, 0, "");
+ }
+ uiDefButC(block, NUMSLI, B_UPDATE_THEME,"R ", 465,y3,200,20, col, 0.0, 255.0, B_THEMECOL, 0, "");
+ uiDefButC(block, NUMSLI, B_UPDATE_THEME,"G ", 465,y2,200,20, col+1, 0.0, 255.0, B_THEMECOL, 0, "");
+ uiDefButC(block, NUMSLI, B_UPDATE_THEME,"B ", 465,y1,200,20, col+2, 0.0, 255.0, B_THEMECOL, 0, "");
+ uiBlockEndAlign(block);
+
+ uiDefButC(block, COL, B_UPDATE_THEME, "", 675,y1,50,y3-y1+20, col, 0, 0, 0, 0, "");
+
+ /* copy paste */
+ uiBlockBeginAlign(block);
+ uiDefBut(block, BUT, B_THEME_COPY, "Copy Color", 755,y2,120,20, NULL, 0, 0, 0, 0, "Stores current color in buffer");
+ uiDefBut(block, BUT, B_THEME_PASTE, "Paste Color", 755,y1,120,20, NULL, 0, 0, 0, 0, "Pastes buffer color");
+ uiBlockEndAlign(block);
+
+ uiDefButC(block, COL, 0, "", 885,y1,50,y2-y1+20, th_curcol_arr, 0, 0, 0, 0, "");
+
+ }
+}
+
+
+void drawinfospace(ScrArea *sa, void *spacedata)
+{
+ uiBlock *block;
+ static short cur_light=0;
+ float fac, col[3];
+ short xpos, ypos, ypostab, buth, rspace, dx, y1, y2, y3, y4, y5, y6, y7;
+ short y2label, y3label, y4label, y5label, y6label, y7label;
+ short spref, mpref, lpref, smfileselbut;
+ short edgsp, midsp;
+ char naam[32];
+
+ if(curarea->win==0 || curarea->winy<2) return;
+
+ BIF_GetThemeColor3fv(TH_BACK, col);
+ glClearColor(col[0], col[1], col[2], 0.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ /* smaller buttons make no sense */
+ if(curarea->winx<320) return;
+
+ if(curarea->winx<=1280.0) {
+ fac= ((float)curarea->winx)/1280.0f;
+ myortho2(0.375f, 1280.375f, 0.375f, curarea->winy/fac + 0.375f);
+ }
+ else {
+ myortho2(0.375f, (float)curarea->winx + 0.375f, 0.375f, (float)curarea->winy + 0.375f);
+ }
+
+ sprintf(naam, "infowin %d", curarea->win);
+ block= uiNewBlock(&curarea->uiblocks, naam, UI_EMBOSS, UI_HELV, curarea->win);
+
+
+ /* Vars for nice grid alignment */
+ dx= (1280-90)/7; /* spacing for use in equally dividing 'tab' row */
+
+ xpos = 45; /* left padding */
+ ypos = 50; /* bottom padding for buttons */
+ ypostab = 10; /* bottom padding for 'tab' row */
+
+ buth = 20; /* standard button height */
+
+ spref = 90; /* standard size for small preferences button */
+ mpref = 189; /* standard size for medium preferences button */
+ lpref = 288; /* standard size for large preferences button */
+ smfileselbut = buth; /* standard size for fileselect button (square) */
+
+ edgsp = 3; /* space from edge of end 'tab' to edge of end button */
+ midsp = 9; /* horizontal space between buttons */
+
+ rspace = 3; /* default space between rows */
+
+ y1 = ypos; /* grid alignment for each row of buttons */
+ y2 = ypos+buth+rspace;
+ y3 = ypos+2*(buth+rspace);
+ y4 = ypos+3*(buth+rspace);
+ y5 = ypos+4*(buth+rspace);
+ y6 = ypos+5*(buth+rspace);
+ y7 = ypos+6*(buth+rspace);
+
+
+ y2label = y2-2; /* adjustments to offset the labels down to align better */
+ y3label = y3-2;
+ y4label = y4-2;
+ y5label = y5-2;
+ y6label = y6-2;
+ y7label = y7-2;
+
+
+ /* set the color to blue and draw the main 'tab' controls */
+
+ uiBlockSetCol(block, TH_BUT_SETTING1);
+ uiBlockBeginAlign(block);
+
+ uiDefButS(block, ROW,B_USERPREF,"View & Controls",
+ xpos,ypostab,(short)dx,buth,
+ &U.userpref,1.0,0.0, 0, 0,"");
+
+ uiDefButS(block, ROW,B_USERPREF,"Edit Methods",
+ (short)(xpos+dx),ypostab,(short)dx,buth,
+ &U.userpref,1.0,1.0, 0, 0,"");
+
+ uiDefButS(block, ROW,B_USERPREF,"Language & Font",
+ (short)(xpos+2*dx),ypostab,(short)dx,buth,
+ &U.userpref,1.0,2.0, 0, 0,"");
+
+ uiDefButS(block, ROW,B_USERPREF,"Themes",
+ (short)(xpos+3*dx),ypostab,(short)dx,buth,
+ &U.userpref,1.0,6.0, 0, 0,"");
+
+ uiDefButS(block, ROW,B_USERPREF,"Auto Save",
+ (short)(xpos+4*dx),ypostab,(short)dx,buth,
+ &U.userpref,1.0,3.0, 0, 0,"");
+
+ uiDefButS(block, ROW,B_USERPREF,"System & OpenGL",
+ (short)(xpos+5*dx),ypostab,(short)dx,buth,
+ &U.userpref,1.0,4.0, 0, 0,"");
+
+ uiDefButS(block, ROW,B_USERPREF,"File Paths",
+ (short)(xpos+6*dx),ypostab,(short)dx,buth,
+ &U.userpref,1.0,5.0, 0, 0,"");
+
+ uiBlockSetCol(block, TH_AUTO);
+ uiBlockEndAlign(block);
+ /* end 'tab' controls */
+
+ /* line 2: left x co-ord, top y co-ord, width, height */
+
+ if(U.userpref == 6) {
+ info_user_themebuts(block, y1, y2, y3);
+ }
+ else if (U.userpref == 0) { /* view & controls */
+
+ uiDefBut(block, LABEL,0,"Display:",
+ xpos,y6label,spref,buth,
+ 0, 0, 0, 0, 0, "");
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOG, USER_TOOLTIPS, 0, "Tool Tips",
+ (xpos+edgsp),y5,spref,buth,
+ &(U.flag), 0, 0, 0, 0,
+ "Display tooltips (help tags) over buttons");
+ uiDefButBitI(block, TOG, USER_DRAWVIEWINFO, B_DRAWINFO, "Object Info",
+ (xpos+edgsp),y4,spref,buth,
+ &(U.uiflag), 0, 0, 0, 0,
+ "Display active object name and frame number in the 3D View");
+ uiDefButBitI(block, TOG, USER_SCENEGLOBAL, 0, "Global Scene",
+ (xpos+edgsp),y3,spref,buth,
+ &(U.flag), 0, 0, 0, 0,
+ "Forces the current Scene to be displayed in all Screens");
+#ifndef __APPLE__
+ uiDefButBitS(block, TOG, 1, 0, "Large Cursors",
+ (xpos+edgsp),y2,spref,buth,
+ &(U.curssize), 0, 0, 0, 0,
+ "Use large mouse cursors when available");
+#else
+ U.curssize=0; /*Small Cursor always for OS X for now */
+#endif
+ uiDefButBitI(block, TOG, USER_SHOW_VIEWPORTNAME, B_DRAWINFO, "View Name",
+ (xpos+edgsp),y1,spref,buth,
+ &(U.uiflag), 0, 0, 0, 0,
+ "Show the name of the view's direction in each 3D View");
+ uiBlockEndAlign(block);
+
+ uiDefBut(block, LABEL,0,"Menus:",
+ (xpos+(2*edgsp)+spref),y6label,spref,buth,
+ 0, 0, 0, 0, 0, "");
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOG, USER_MENUOPENAUTO, 0, "Open on Mouse Over",
+ (xpos+edgsp+spref+midsp),y5,mpref,buth,
+ &(U.uiflag), 0, 0, 0, 0,
+ "Open menu buttons and pulldowns automatically when the mouse is hovering");
+ uiDefButS(block, NUM, 0, "Top Level:",
+ (xpos+edgsp+spref+midsp),y4,spref+edgsp,buth,
+ &(U.menuthreshold1), 1, 40, 0, 0,
+ "Time delay in 1/10 seconds before automatically opening top level menus");
+ uiDefButS(block, NUM, 0, "Sublevels:",
+ (xpos+edgsp+(2*spref)+(2*midsp)-edgsp),y4,spref+edgsp,buth,
+ &(U.menuthreshold2), 1, 40, 0, 0,
+ "Time delay in 1/10 seconds before automatically opening menu sublevels");
+ uiBlockEndAlign(block);
+
+ uiDefBut(block, LABEL,0,"Toolbox click-hold delay:",
+ (xpos+(2*edgsp)+spref),y3label,mpref,buth,
+ 0, 0, 0, 0, 0, "");
+ uiBlockBeginAlign(block);
+ uiDefButS(block, NUM, 0, "LMB:",
+ (xpos+edgsp+spref+midsp),y2,spref+edgsp,buth,
+ &(U.tb_leftmouse), 2, 40, 0, 0,
+ "Time in 1/10 seconds to hold the Left Mouse Button before opening the toolbox");
+ uiDefButS(block, NUM, 0, "RMB:",
+ (xpos+edgsp+(2*spref)+(2*midsp)-edgsp),y2,spref+edgsp,buth,
+ &(U.tb_rightmouse), 2, 40, 0, 0,
+ "Time in 1/10 seconds to hold the Right Mouse Button before opening the toolbox");
+ uiBlockEndAlign(block);
+
+ uiDefButBitI(block, TOG, USER_PANELPINNED, 0, "Pin Floating Panels",
+ (xpos+edgsp+spref+midsp),y1,(mpref/2),buth,
+ &(U.uiflag), 0, 0, 0, 0,
+ "Make floating panels invoked by a hotkey (eg. N Key) open at the previous location");
+ uiDefButBitI(block, TOG, USER_PLAINMENUS, B_PLAINMENUS, "Plain Menus",
+ (xpos+edgsp+(2*spref)+(2*midsp)),y1,spref,buth,
+ &(U.uiflag), 0, 0, 0, 0,
+ "Use a column layout for toolbox and do not flip the contents of any menu");
+ uiBlockEndAlign(block);
+
+ uiDefBut(block, LABEL,0,"Snap to grid:",
+ (xpos+(2*edgsp)+spref+midsp+mpref),y6label,mpref,buth,
+ 0, 0, 0, 0, 0, "");
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOG, USER_AUTOGRABGRID, 0, "Grab/Move",
+ (xpos+edgsp+mpref+spref+(2*midsp)),y5,spref,buth,
+ &(U.flag), 0, 0, 0, 0,
+ "Snap objects and sub-objects to grid units when moving");
+ uiDefButBitI(block, TOG, USER_AUTOROTGRID, 0, "Rotate",
+ (xpos+edgsp+mpref+spref+(2*midsp)),y4,spref,buth,
+ &(U.flag), 0, 0, 0, 0,
+ "Snap objects and sub-objects to grid units when rotating");
+ uiDefButBitI(block, TOG, USER_AUTOSIZEGRID, 0, "Scale",
+ (xpos+edgsp+mpref+spref+(2*midsp)),y3,spref,buth,
+ &(U.flag), 0, 0, 0, 0,
+ "Snap objects and sub-objects to grid units when scaling");
+ uiBlockEndAlign(block);
+
+ uiDefButBitI(block, TOG, USER_LOCKAROUND, B_DRAWINFO, "Global Pivot",
+ (xpos+edgsp+mpref+spref+(2*midsp)),y1,spref,buth,
+ &(U.uiflag), 0, 0, 0, 0,
+ "Lock the same rotation/scaling pivot in all 3D Views");
+
+ uiDefBut(block, LABEL,0,"View zoom:",
+ (xpos+(2*edgsp)+mpref+(2*spref)+(2*midsp)),y6label,mpref,buth,
+ 0, 0, 0, 0, 0, "");
+ uiBlockBeginAlign(block);
+ uiBlockSetCol(block, TH_BUT_SETTING1); /* mutually exclusive toggles, start color */
+ uiDefButS(block, ROW, 0, "Continue",
+ (xpos+edgsp+mpref+(2*spref)+(3*midsp)),y5,(mpref/3),buth,
+ &(U.viewzoom), 40, USER_ZOOM_CONT, 0, 0,
+ "Old style zoom, continues while moving mouse up or down");
+ uiDefButS(block, ROW, 0, "Dolly",
+ (xpos+edgsp+mpref+(2*spref)+(3*midsp)+(mpref/3)),y5,(mpref/3),buth,
+ &(U.viewzoom), 40, USER_ZOOM_DOLLY, 0, 0,
+ "Zooms in and out based on vertical mouse movement.");
+ uiDefButS(block, ROW, 0, "Scale",
+ (xpos+edgsp+mpref+(2*spref)+(3*midsp)+(2*mpref/3)),y5,(mpref/3),buth,
+ &(U.viewzoom), 40, USER_ZOOM_SCALE, 0, 0,
+ "Zooms in and out like scaling the view, mouse movements relative to center.");
+ uiBlockSetCol(block, TH_AUTO); /* end color */
+ uiBlockEndAlign(block);
+
+ uiDefButBitI(block, TOG, USER_ZOOM_TO_MOUSEPOS, B_DRAWINFO, "Zoom to Mouse Position",
+ (xpos+edgsp+mpref+(2*spref)+(3*midsp)),y4,mpref,buth,
+ &(U.uiflag), 0, 0, 0, 0,
+ "Zoom in towards the mouse pointer's position in the 3D view, rather than the 2D window center");
+
+ uiDefBut(block, LABEL,0,"View rotation:",
+ (xpos+(2*edgsp)+mpref+(2*spref)+(2*midsp)),y3label,mpref,buth,
+ 0, 0, 0, 0, 0, "");
+ uiBlockBeginAlign(block);
+ uiBlockSetCol(block, TH_BUT_SETTING1); /* mutually exclusive toggles, start color */
+ uiDefButBitI(block, TOG, USER_TRACKBALL, B_DRAWINFO, "Trackball",
+ (xpos+edgsp+mpref+(2*spref)+(3*midsp)),y2,(mpref/2),buth,
+ &(U.flag), 0, 0, 0, 0,
+ "Allow the view to tumble freely when orbiting with the Middle Mouse Button");
+ uiDefButBitI(block, TOGN, USER_TRACKBALL, B_DRAWINFO, "Turntable",
+ (xpos+edgsp+mpref+(2*spref)+(3*midsp)+(mpref/2)),y2,(mpref/2),buth,
+ &(U.flag), 0, 0, 0, 0,
+ "Use fixed up axis for orbiting with Middle Mouse Button");
+ uiBlockSetCol(block, TH_AUTO); /* end color */
+ uiDefButBitI(block, TOG, USER_AUTOPERSP, B_DRAWINFO, "Auto Perspective",
+ (xpos+edgsp+mpref+(2*spref)+(3*midsp)),y1,(mpref/2),buth,
+ &(U.uiflag), 0, 0, 0, 0,
+ "Automatically switch between orthographic and perspective when changing from top/front/side views");
+ uiDefButBitI(block, TOG, USER_ORBIT_SELECTION, B_DRAWINFO, "Around Selection",
+ (xpos+edgsp+mpref+(2*spref)+(3*midsp)+(mpref/2)),y1,(mpref/2),buth,
+ &(U.uiflag), 0, 0, 0, 0,
+ "Use selection as the orbiting center");
+ uiBlockEndAlign(block);
+
+ uiDefBut(block, LABEL,0,"Select with:",
+ (xpos+(2*edgsp)+(3*mpref)+(3*midsp)),y6label,mpref,buth,
+ 0, 0, 0, 0, 0, "");
+ uiBlockBeginAlign(block);
+ uiBlockSetCol(block, TH_BUT_SETTING1); /* mutually exclusive toggles, start color */
+ uiDefButBitI(block, TOG, USER_LMOUSESELECT, B_DRAWINFO, "Left Mouse",
+ (xpos+edgsp+(3*mpref)+(4*midsp)),y5,(mpref/2),buth,
+ &(U.flag), 0, 0, 0, 0, "Use the Left Mouse Button for selection");
+ uiDefButBitI(block, TOGN, USER_LMOUSESELECT, B_DRAWINFO, "Right Mouse",
+ (xpos+edgsp+(3*mpref)+(4*midsp)+(mpref/2)),y5,(mpref/2),buth,
+ &(U.flag), 0, 0, 0, 0, "Use the Right Mouse Button for selection");
+ uiBlockSetCol(block, TH_AUTO); /* end color */
+ uiBlockEndAlign(block);
+
+
+ if(U.flag & USER_LMOUSESELECT) {
+ uiDefBut(block, LABEL,0,"Cursor with: Right Mouse",
+ (xpos+(2*edgsp)+(3*mpref)+(3*midsp)),y4label+5,mpref,buth,
+ 0, 0, 0, 0, 0, "");
+ } else {
+ uiDefBut(block, LABEL,0,"Cursor with: Left Mouse",
+ (xpos+(2*edgsp)+(3*mpref)+(3*midsp)),y4label+5,mpref,buth,
+ 0, 0, 0, 0, 0, "");
+ }
+
+ /* illegal combo... */
+ if (U.flag & USER_LMOUSESELECT)
+ U.flag &= ~USER_TWOBUTTONMOUSE;
+
+ uiDefButBitI(block, TOG, USER_TWOBUTTONMOUSE, B_DRAWINFO, "Emulate 3 Button Mouse",
+ (xpos+edgsp+(3*mpref)+(4*midsp)),y3,mpref,buth,
+ &(U.flag), 0, 0, 0, 0,
+ "Emulates Middle Mouse with Alt+LeftMouse (doesnt work with Left Mouse Select option)");
+
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOG, USER_SHOW_ROTVIEWICON, B_DRAWINFO, "Mini Axis",
+ (xpos+edgsp+(3*mpref)+(4*midsp)),y1,(mpref/3),buth,
+ &(U.uiflag), 0, 0, 0, 0,
+ "Show a small rotating 3D axis in the bottom left corner of the 3D View");
+ uiDefButS(block, NUM, B_DRAWINFO, "Size:",
+ (xpos+edgsp+(3*mpref)+(4*midsp)+(mpref/3)),y1,(mpref/3),buth,
+ &U.rvisize, 10, 64, 0, 0,
+ "The axis icon's size");
+ uiDefButS(block, NUM, B_DRAWINFO, "Bright:",
+ (xpos+edgsp+(3*mpref)+(4*midsp)+2*(mpref/3)),y1,(mpref/3),buth,
+ &U.rvibright, 0, 10, 0, 0,
+ "The brightness of the icon");
+ uiBlockEndAlign(block);
+
+ uiDefBut(block, LABEL,0,"Middle Mouse Button:",
+ (xpos+(2*edgsp)+(4*mpref)+(4*midsp)),y6label,mpref,buth,
+ 0, 0, 0, 0, 0, "");
+ uiBlockBeginAlign(block);
+ uiBlockSetCol(block, TH_BUT_SETTING1); /* mutually exclusive toggles, start color */
+ uiDefButBitI(block, TOGN, USER_VIEWMOVE, B_DRAWINFO, "Rotate View",
+ (xpos+edgsp+(4*mpref)+(5*midsp)),y5,(mpref/2),buth,
+ &(U.flag), 0, 0, 0, 0, "Default action for the Middle Mouse Button");
+ uiDefButBitI(block, TOG, USER_VIEWMOVE, B_DRAWINFO, "Pan View",
+ (xpos+edgsp+(4*mpref)+(5*midsp)+(mpref/2)),y5,(mpref/2),buth,
+ &(U.flag), 0, 0, 0, 0, "Default action for the Middle Mouse Button");
+ uiBlockSetCol(block, TH_AUTO); /* end color */
+ uiBlockEndAlign(block);
+
+
+ uiDefBut(block, LABEL,0,"Mouse Wheel:",
+ (xpos+(2*edgsp)+(4*mpref)+(4*midsp)),y4label,mpref,buth,
+ 0, 0, 0, 0, 0, "");
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOG, USER_WHEELZOOMDIR, 0, "Invert Zoom",
+ (xpos+edgsp+(4*mpref)+(5*midsp)),y3,spref,buth,
+ &(U.uiflag), 0, 0, 0, 0,
+ "Swap the Mouse Wheel zoom direction");
+ uiDefButI(block, NUM, 0, "Scroll Lines:",
+ (xpos+edgsp+(4*mpref)+(6*midsp)+spref-edgsp),y3,spref+edgsp,buth,
+ &U.wheellinescroll, 0.0, 32.0, 0, 0,
+ "The number of lines scrolled at a time with the mouse wheel");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefButS(block, NUM, B_DRAWINFO, "Smooth View:",
+ (xpos+edgsp+(4*mpref)+(5*midsp)),y2,(mpref),buth,
+ &U.smooth_viewtx, 0, 1000, 0, 0,
+ "The time to animate the view in miliseconds, zero to disable");
+ uiDefButS(block, NUM, B_DRAWINFO, "Rotation Angle:",
+ (xpos+edgsp+(4*mpref)+(5*midsp)),y1,(mpref),buth,
+ &U.pad_rot_angle, 0, 90, 0, 0,
+ "The rotation step for numerical pad keys (2 4 6 8)");
+ uiBlockEndAlign(block);
+
+
+ uiDefBut(block, LABEL,0,"3D Transform Widget:",
+ (xpos+(2*edgsp)+(5*mpref)+(5*midsp)),y6label,mpref,buth,
+ 0, 0, 0, 0, 0, "");
+ uiBlockBeginAlign(block);
+ uiDefButS(block, NUM, B_REDRCURW3D, "Size:",
+ (xpos+edgsp+(5*mpref)+(6*midsp)),y5,(mpref/2),buth,
+ &(U.tw_size), 2, 40, 0, 0, "Diameter of widget, in 10 pixel units");
+ uiDefButS(block, NUM, B_REDRCURW3D, "Handle:",
+ (xpos+edgsp+(5*mpref)+(6*midsp)+(mpref/2)),y5,(mpref/2),buth,
+ &(U.tw_handlesize), 2, 40, 0, 0, "Size of widget handles as percentage of widget radius");
+ uiDefButS(block, NUM, B_REDRCURW3D, "Hotspot:",
+ (xpos+edgsp+(5*mpref)+(6*midsp)),y4,(mpref),buth,
+ &(U.tw_hotspot), 4, 40, 0, 0, "Hotspot in pixels for clicking widget handles");
+ uiBlockEndAlign(block);
+
+ uiDefButS(block, NUM, B_REDRCURW3D, "Object Center Size: ",
+ (xpos+edgsp+(5*mpref)+(6*midsp)),y3,mpref,buth,
+ &(U.obcenter_dia), 4, 10, 0, 0,
+ "Diameter in Pixels for Object/Lamp center display");
+
+
+ } else if (U.userpref == 1) { /* edit methods */
+
+
+ uiDefBut(block, LABEL,0,"Material linked to:",
+ xpos,y5label,mpref,buth,
+ 0, 0, 0, 0, 0, "");
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOGN, USER_MAT_ON_OB, B_DRAWINFO, "ObData",
+ (xpos+edgsp),y4,(mpref/2),buth,
+ &(U.flag), 0, 0, 0, 0, "Link new objects' material to the obData block");
+ uiDefButBitI(block, TOG, USER_MAT_ON_OB, B_DRAWINFO, "Object",
+ (xpos+edgsp+(mpref/2)),y4,(mpref/2),buth,
+ &(U.flag), 0, 0, 0, 0, "Link new objects' material to the object block");
+ uiBlockEndAlign(block);
+
+ uiDefBut(block, LABEL,0,"Add new objects:",
+ xpos,y3label,mpref,buth,
+ 0, 0, 0, 0, 0, "");
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOG, USER_ADD_EDITMODE, B_DRAWINFO, "Switch to Edit Mode",
+ (xpos+edgsp),y2,mpref,buth,
+ &(U.flag), 0, 0, 0, 0, "Enter Edit Mode automatically after adding a new object");
+ uiDefButBitI(block, TOG, USER_ADD_VIEWALIGNED, B_DRAWINFO, "Aligned to View",
+ (xpos+edgsp),y1,mpref,buth,
+ &(U.flag), 0, 0, 0, 0, "Align newly added objects facing the 3D View direction");
+ uiBlockEndAlign(block);
+
+
+ uiDefBut(block, LABEL,0,"Undo:",
+ (xpos+(2*edgsp)+mpref),y3label, mpref,buth,
+ 0, 0, 0, 0, 0, "");
+ uiBlockBeginAlign(block);
+ uiDefButS(block, NUMSLI, B_DRAWINFO, "Steps: ",
+ (xpos+edgsp+mpref+midsp),y2,mpref,buth,
+ &(U.undosteps), 0, 64, 0, 0, "Number of undo steps available (smaller values conserve memory)");
+
+ uiDefButBitI(block, TOG, USER_GLOBALUNDO, B_DRAWINFO, "Global Undo",
+ (xpos+edgsp+mpref+midsp),y1,mpref,buth,
+ &(U.uiflag), 2, 64, 0, 0, "Global undo works by keeping a full copy of the file itself in memory, so takes extra memory");
+ uiBlockEndAlign(block);
+
+
+ uiDefBut(block, LABEL,0,"Auto keyframe",
+ (xpos+(2*edgsp)+(2*mpref)+midsp),y5label,mpref,buth,
+ 0, 0, 0, 0, 0, "");
+
+ uiDefButBitI(block, TOG, G_RECORDKEYS, REDRAWTIME, "Action and Object",
+ (xpos+edgsp+(2*mpref)+(2*midsp)),y4,mpref, buth,
+ &(G.flags), 0, 0, 0, 0, "Automatic keyframe insertion in Object and Action Ipo curves");
+
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOG, USER_KEYINSERTAVAI, REDRAWTIME, "Available",
+ (xpos+edgsp+(2*mpref)+(2*midsp)),y3,mpref, buth,
+ &(U.uiflag), 0, 0, 0, 0, "Automatic keyframe insertion in available curves");
+
+ uiDefButBitI(block, TOG, USER_KEYINSERTNEED, REDRAWTIME, "Needed",
+ (xpos+edgsp+(2*mpref)+(2*midsp)),y2,mpref, buth,
+ &(U.uiflag), 0, 0, 0, 0, "Automatic keyframe insertion only when keyframe needed");
+
+ uiDefButBitI(block, TOG, G_AUTOMATKEYS, REDRAWTIME, "Use Visual Keying",
+ (xpos+edgsp+(2*mpref)+(2*midsp)),y1,mpref, buth,
+ &(G.flags), 0, 0, 0, 0, "Use Visual keying automatically for constrained objects");
+ uiBlockEndAlign(block);
+
+/* uiDefButBitS(block, TOG, USER_KEYINSERTACT, 0, "Action",
+ (xpos+edgsp+(2*mpref)+(2*midsp)),y2,(spref+edgsp),buth,
+ &(U.uiflag), 0, 0, 0, 0, "Automatic keyframe insertion in Action Ipo curve");
+ uiDefButBitS(block, TOG, USER_KEYINSERTOBJ, 0, "Object",
+ (xpos+edgsp+(2*mpref)+(3*midsp)+spref-edgsp),y2,(spref+edgsp),buth,
+ &(U.uiflag), 0, 0, 0, 0, "Automatic keyframe insertion in Object Ipo curve"); */
+
+
+ uiDefBut(block, LABEL,0,"Duplicate with object:",
+ (xpos+(2*edgsp)+(3*midsp)+(3*mpref)+spref),y3label,mpref,buth,
+ 0, 0, 0, 0, 0, "");
+
+ uiBlockBeginAlign(block);
+ uiDefButBitI(block, TOG, USER_DUP_MESH, 0, "Mesh",
+ (xpos+edgsp+(4*midsp)+(3*mpref)+spref),y2,(spref+edgsp),buth,
+ &(U.dupflag), 0, 0, 0, 0, "Causes mesh data to be duplicated with Shift+D");
+ uiDefButBitI(block, TOG, USER_DUP_SURF, 0, "Surface",
+ (xpos+edgsp+(5*midsp)+(3*mpref)+(2*spref)),y2,(spref+edgsp),buth,
+ &(U.dupflag), 0, 0, 0, 0, "Causes surface data to be duplicated with Shift+D");
+ uiDefButBitI(block, TOG, USER_DUP_CURVE, 0, "Curve",
+ (xpos+edgsp+(6*midsp)+(3*mpref)+(3*spref)),y2,(spref+edgsp),buth,
+ &(U.dupflag), 0, 0, 0, 0, "Causes curve data to be duplicated with Shift+D");
+ uiDefButBitI(block, TOG, USER_DUP_FONT, 0, "Text",
+ (xpos+edgsp+(7*midsp)+(3*mpref)+(4*spref)),y2,(spref+edgsp),buth,
+ &(U.dupflag), 0, 0, 0, 0, "Causes text data to be duplicated with Shift+D");
+ uiDefButBitI(block, TOG, USER_DUP_MBALL, 0, "Metaball",
+ (xpos+edgsp+(8*midsp)+(3*mpref)+(5*spref)),y2,(spref+edgsp),buth,
+ &(U.dupflag), 0, 0, 0, 0, "Causes metaball data to be duplicated with Shift+D");
+
+ uiDefButBitI(block, TOG, USER_DUP_ARM, 0, "Armature",
+ (xpos+edgsp+(4*midsp)+(3*mpref)+spref),y1,(spref+edgsp),buth,
+ &(U.dupflag), 0, 0, 0, 0, "Causes armature data to be duplicated with Shift+D");
+ uiDefButBitI(block, TOG, USER_DUP_LAMP, 0, "Lamp",
+ (xpos+edgsp+(5*midsp)+(3*mpref)+(2*spref)),y1,(spref+edgsp),buth,
+ &(U.dupflag), 0, 0, 0, 0, "Causes lamp data to be duplicated with Shift+D");
+ uiDefButBitI(block, TOG, USER_DUP_MAT, 0, "Material",
+ (xpos+edgsp+(6*midsp)+(3*mpref)+(3*spref)),y1,(spref+edgsp),buth,
+ &(U.dupflag), 0, 0, 0, 0, "Causes material data to be duplicated with Shift+D");
+ uiDefButBitI(block, TOG, USER_DUP_TEX, 0, "Texture",
+ (xpos+edgsp+(7*midsp)+(3*mpref)+(4*spref)),y1,(spref+edgsp),buth,
+ &(U.dupflag), 0, 0, 0, 0, "Causes texture data to be duplicated with Shift+D");
+ uiDefButBitI(block, TOG, USER_DUP_IPO, 0, "Ipo",
+ (xpos+edgsp+(8*midsp)+(3*mpref)+(5*spref)),y1,(spref+edgsp),buth,
+ &(U.dupflag), 0, 0, 0, 0, "Causes ipo data to be duplicated with Shift+D");
+ uiBlockEndAlign(block);
+
+ } else if(U.userpref == 2) { /* language & colors */
+
+#ifdef INTERNATIONAL
+ uiDefButBitS(block, TOG, USER_DOTRANSLATE, B_DOLANGUIFONT, "International Fonts",
+ xpos,y2,mpref,buth,
+ &(U.transopts), 0, 0, 0, 0, "Activate international interface");
+
+ if(U.transopts & USER_DOTRANSLATE) {
+ char curfont[320];
+
+ sprintf(curfont, "Interface Font: ");
+ if(U.fontname[0]) strcat(curfont, U.fontname);
+ else strcat(curfont, "Built-in");
+
+ uiDefBut(block, LABEL,0,curfont,
+ (xpos),y3,4*mpref,buth,
+ 0, 0, 0, 0, 0, "");
+
+ uiDefBut(block, BUT, B_LOADUIFONT, "Select Font",
+ xpos,y1,mpref,buth,
+ 0, 0, 0, 0, 0, "Select a new font for the interface");
+
+ uiDefButI(block, BUT, B_RESTOREFONT, "Restore to default",
+ (xpos+edgsp+mpref+midsp),y2,mpref,buth,
+ &U.fontsize, 0, 0, 0, 0, "Restores to using the default included antialised font");
+
+ uiDefButI(block, MENU, B_SETFONTSIZE, fontsize_pup(),
+ (xpos+edgsp+mpref+midsp),y1,mpref,buth,
+ &U.fontsize, 0, 0, 0, 0, "Current interface font size (points)");
+
+/*
+ uiDefButS(block, MENU, B_SETENCODING, encoding_pup(),
+ (xpos+edgsp+mpref+midsp),y1,mpref,buth,
+ &U.encoding, 0, 0, 0, 0, "Current interface font encoding");
+
+
+ uiDefBut(block, LABEL,0,"Translate:",
+ (xpos+edgsp+(2.1*mpref)+(2*midsp)),y3label,mpref,buth,
+ 0, 0, 0, 0, 0, "");
+*/
+
+ uiDefButBitS(block, TOG, USER_TR_TOOLTIPS, B_SETTRANSBUTS, "Tooltips",
+ (xpos+edgsp+(2.2*mpref)+(3*midsp)),y1,spref,buth,
+ &(U.transopts), 0, 0, 0, 0, "Translate tooltips");
+
+ uiDefButBitS(block, TOG, USER_TR_BUTTONS, B_SETTRANSBUTS, "Buttons",
+ (xpos+edgsp+(2.2*mpref)+(4*midsp)+spref),y1,spref,buth,
+ &(U.transopts), 0, 0, 0, 0, "Translate button labels");
+
+ uiDefButBitS(block, TOG, USER_TR_MENUS, B_SETTRANSBUTS, "Toolbox",
+ (xpos+edgsp+(2.2*mpref)+(5*midsp)+(2*spref)),y1,spref,buth,
+ &(U.transopts), 0, 0, 0, 0, "Translate toolbox menu");
+
+ uiDefButI(block, MENU, B_SETLANGUAGE, language_pup(),
+ (xpos+edgsp+(2.2*mpref)+(3*midsp)),y2,mpref+(0.5*mpref)+3,buth,
+ &U.language, 0, 0, 0, 0, "Select interface language");
+
+ uiDefButBitS(block, TOG, USER_USETEXTUREFONT, B_USETEXTUREFONT, "Use Textured Fonts",
+ (xpos+edgsp+(4*mpref)+(4*midsp)),y2,mpref,buth,
+ &(U.transopts), 0, 0, 0, 0,
+ "Use Textured Fonts");
+ }
+
+/* end of INTERNATIONAL */
+#endif
+
+ } else if(U.userpref == 3) { /* auto save */
+
+
+ uiDefButS(block, NUM, 0, "Save Versions:",
+ (xpos+edgsp),y3,mpref,buth,
+ &U.versions, 0.0, 32.0, 0, 0,
+ "The number of old versions to maintain in the current directory, when manually saving");
+
+ uiDefButBitI(block, TOG, USER_AUTOSAVE, B_RESETAUTOSAVE, "Auto Save Temp Files",
+ (xpos+edgsp+mpref+midsp),y3,mpref,buth,
+ &(U.flag), 0, 0, 0, 0,
+ "Enables automatic saving of temporary files");
+
+ if(U.flag & USER_AUTOSAVE) {
+
+ uiDefButI(block, NUM, B_RESETAUTOSAVE, "Minutes:",
+ (xpos+edgsp+mpref+midsp),y2,mpref,buth,
+ &(U.savetime), 1.0, 60.0, 0, 0,
+ "The time (in minutes) to wait between automatic temporary saves");
+
+ uiDefBut(block, BUT, B_LOADTEMP, "Open Recent",
+ (xpos+edgsp+mpref+midsp),y1,mpref,buth,
+ 0, 0, 0, 0, 0,"Open the most recently saved temporary file");
+ }
+
+ uiDefButS(block, NUM, B_DRAWINFO, "Recent Files:",
+ (xpos+edgsp+(2*mpref)+(3*midsp)),y3,(mpref),buth,
+ &U.recent_files, 0, 30, 0, 0,
+ "Maximum number of recently opened files to remember");
+
+ uiDefButBitI(block, TOG, USER_SAVE_PREVIEWS, 0, "Save Preview Images",
+ (xpos+edgsp+(3*mpref)+(4*midsp)),y3,mpref,buth,
+ &(U.flag), 0, 0, 0, 0,
+ "Enables automatic saving of preview images in the .blend file");
+
+ } else if (U.userpref == 4) { /* system & opengl */
+ int memcachemax;
+ if (sizeof(void *) ==8) memcachemax = 1024*16; /* 64bit system, 16 gig of ram would be nice */
+ else memcachemax = 1024; /* 32 bit system, cant address over 2gig anyway */
+
+ uiDefBut(block, LABEL,0,"Solid OpenGL lights:",
+ xpos+edgsp, y6label, mpref, buth,
+ 0, 0, 0, 0, 0, "");
+
+ for (cur_light=0; cur_light<3; cur_light++) {
+ char lightname[12];
+ int lightbutw=buth*2;
+ int offs=cur_light*(midsp+lightbutw);
+
+ sprintf(lightname, "Light %d", cur_light+1);
+
+ uiDefButBitI(block, TOG, 1, B_RECALCLIGHT, lightname,
+ xpos+edgsp+offs, y5, lightbutw, buth,
+ &U.light[cur_light].flag, 0.0, 0.0, 0, 0, "Enable this OpenGL light in Solid draw mode");
+
+ uiDefButF(block, BUT_NORMAL, B_RECALCLIGHT, "",
+ xpos+edgsp+offs, y3, lightbutw, buth*2+rspace,
+ U.light[cur_light].vec, 0.0f, 1.0f, 0, 0, "The direction that the OpenGL light is shining");
+
+ uiDefButF(block, COL, B_RECALCLIGHT, "",
+ xpos+edgsp+offs, y2, lightbutw, buth,
+ U.light[cur_light].col, 0.0, 0.0, 0, 0, "");
+ uiDefButF(block, COL, B_RECALCLIGHT, "",
+ xpos+edgsp+offs, y1, lightbutw, buth,
+ U.light[cur_light].spec, 0.0, 0.0, 0, 0, "");
+ }
+
+ uiDefBut(block, LABEL,0,"Color",
+ xpos+edgsp+140, y2, mpref/4, buth,
+ 0, 0, 0, 0, 0, "");
+ uiDefBut(block, LABEL,0,"Spec",
+ xpos+edgsp+140, y1, mpref/4, buth,
+ 0, 0, 0, 0, 0, "");
+
+
+#ifdef WITH_VERSE
+ uiDefBut(block, TEX, 0, "Verse Master: ",
+ (xpos+edgsp)+mpref*2+2*midsp,y5,mpref*2+midsp,buth,
+ U.versemaster, 1.0, 63.0, 0, 0,
+ "The Verse Master-server IP");
+ uiDefBut(block, TEX, 0, "Verse Username: ",
+ (xpos+edgsp)+mpref*2+2*midsp,y4,mpref*2+midsp,buth,
+ U.verseuser, 1.0, 63.0, 0, 0,
+ "The Verse user name");
+#endif
+
+/*
+ uiDefButBitS(block, TOG, USER_EVTTOCONSOLE, 0, "Log Events to Console",
+ (xpos+edgsp),y2,lpref,buth,
+ &(U.uiflag), 0, 0, 0, 0, "Display a list of input events in the console");
+
+ uiDefButS(block, MENU, B_CONSOLEOUT, consolemethod_pup(),
+ (xpos+edgsp), y1, lpref,buth,
+ &U.console_out, 0, 0, 0, 0, "Select console output method");
+
+ uiDefButS(block, NUM, B_CONSOLENUMLINES, "Lines:",
+ (xpos+edgsp+lpref+midsp),y1,spref,buth,
+ &U.console_buffer, 1.0, 4000.0, 0, 0, "Maximum number of internal console lines");
+*/
+
+#ifdef _WIN32
+ uiDefBut(block, LABEL,0,"Win Codecs:",
+ (xpos+edgsp+(1*midsp)+(1*mpref)),y3label,mpref,buth,
+ 0, 0, 0, 0, 0, "");
+
+ uiDefButBitI(block, TOG, USER_ALLWINCODECS, 0, "Enable all codecs",
+ (xpos+edgsp+(1*mpref)+(1*midsp)),y2,mpref,buth,
+ &(U.uiflag), 0, 0, 0, 0, "Allows all codecs for rendering (not guaranteed)");
+#endif
+
+ uiDefBut(block, LABEL,0,"Auto Run Python Scripts",
+ (xpos+edgsp+(1*midsp)+(1*mpref)),y6label,mpref,buth,
+ 0, 0, 0, 0, 0, "");
+
+ uiDefButBitI(block, TOG, G_DOSCRIPTLINKS, REDRAWBUTSSCRIPT, "Enabled by Default",
+ (xpos+edgsp+(1*mpref)+(1*midsp)),y5,mpref,buth,
+ &(G.f), 0, 0, 0, 0, "Allow any .blend file to run scripts automatically (unsafe with blend files from an untrusted source)");
+
+ uiDefBut(block, LABEL,0,"Keyboard:",
+ (xpos+edgsp+(3*midsp)+(3*mpref)),y3label,mpref,buth,
+ 0, 0, 0, 0, 0, "");
+
+ uiDefButBitI(block, TOG, USER_NO_CAPSLOCK, B_U_CAPSLOCK, "Disable Caps Lock",
+ (xpos+edgsp+(3*midsp)+(3*mpref)),y1,mpref,buth,
+ &(U.flag), 0, 0, 0, 0,
+ "Disables the Caps Lock key when entering text");
+
+ uiDefButBitI(block, TOG, USER_NONUMPAD, 0, "Emulate Numpad",
+ (xpos+edgsp+(3*midsp)+(3*mpref)),y2,mpref,buth,
+ &(U.flag), 0, 0, 0, 0,
+ "Causes the 1 to 0 keys to act as the numpad (useful for laptops)");
+
+
+ uiDefBut(block, LABEL,0,"System:",
+ (xpos+edgsp+(4*midsp)+(4*mpref)),y7label,mpref,buth,
+ 0, 0, 0, 0, 0, "");
+ uiDefButI(block, NUM, B_REDR, "Prefetch frames ",
+ (xpos+edgsp+(4*mpref)+(4*midsp)), y6, mpref, buth,
+ &U.prefetchframes, 0.0, 500.0, 20, 2,
+ "Number of frames to render ahead during playback.");
+
+ uiDefButI(block, NUM, B_MEMCACHELIMIT, "MEM Cache Limit ",
+ (xpos+edgsp+(4*mpref)+(4*midsp)), y5, mpref, buth,
+ &U.memcachelimit, 0.0, (float)memcachemax, 30, 2,
+ "Memory cache limit in sequencer (megabytes)");
+
+ uiDefButS(block, NUM, B_REDR, "Frameserver Port ",
+ (xpos+edgsp+(4*mpref)+(4*midsp)), y4, mpref, buth,
+ &U.frameserverport, 0.0, 32727.0, 30, 2,
+ "Frameserver Port for Framserver-Rendering");
+
+ uiDefButBitI(block, TOG, USER_DISABLE_SOUND, B_SOUNDTOGGLE, "Disable Game Sound",
+ (xpos+edgsp+(4*mpref)+(4*midsp)),y3,mpref,buth,
+ &(U.gameflags), 0, 0, 0, 0, "Disables sounds from being played in games");
+
+ uiDefButBitI(block, TOG, USER_FILTERFILEEXTS, 0, "Filter File Extensions",
+ (xpos+edgsp+(4*mpref)+(4*midsp)),y2,mpref,buth,
+ &(U.uiflag), 0, 0, 0, 0, "Display only files with extensions in the image select window");
+
+ uiDefButBitI(block, TOG, USER_HIDE_DOT, 0, "Hide dot file/datablock",
+ (xpos+edgsp+(4*mpref)+(4*midsp)),y1,mpref,buth,
+ &(U.uiflag), 0, 0, 0, 0, "Hide files/datablocks that start with a dot(.*)");
+
+ uiDefBut(block, LABEL,0,"OpenGL:",
+ (xpos+edgsp+(5*midsp)+(5*mpref)),y7label,mpref,buth,
+ 0, 0, 0, 0, 0, "");
+
+ uiDefButF(block, NUMSLI, B_DRAWINFO, "Clip Alpha: ",
+ (xpos+edgsp+(5*mpref)+(5*midsp)),y6,mpref,buth,
+ &(U.glalphaclip), 0.0, 1.0, 0, 0, "Clip alpha below this threshold in the 3d textured view");
+
+ uiDefButBitI(block, TOGN, USER_DISABLE_MIPMAP, B_MIPMAPCHANGED, "Mipmaps",
+ (xpos+edgsp+(5*mpref)+(5*midsp)),y5,mpref,buth,
+ &(U.gameflags), 0, 0, 0, 0, "Toggles between mipmap textures on (beautiful) and off (fast)");
+
+ /* main choices pup: note, it uses collums, and the seperators (%l) then have to fill both halves equally for the menu to work */
+ uiDefButS(block, MENU, B_GLRESLIMITCHANGED, "GL Texture Clamp Off%x0|%l|GL Texture Clamp 8192%x8192|GL Texture Clamp 4096%x4096|GL Texture Clamp 2048%x2048|GL Texture Clamp 1024%x1024|GL Texture Clamp 512%x512|GL Texture Clamp 256%x256|GL Texture Clamp 128%x128",
+ (xpos+edgsp+(5*mpref)+(5*midsp)),y4,mpref,buth, &(U.glreslimit), 0, 0, 0, 0, "Limit the texture size to save graphics memory");
+
+ uiDefButBitI(block, TOG, USER_VERTEX_ARRAYS, 0, "Vertex Arrays",
+ (xpos+edgsp+(5*mpref)+(5*midsp)),y3,mpref,buth,
+ &(U.gameflags), 0, 0, 0, 0, "Toggles between vertex arrays on (less reliable) and off (more reliable)");
+
+ uiDefButI(block, NUM, 0, "Time Out ",
+ (xpos+edgsp+(5*mpref)+(5*midsp)), y2, mpref, buth,
+ &U.textimeout, 0.0, 3600.0, 30, 2, "Time since last access of a GL texture in seconds after which it is freed. (Set to 0 to keep textures allocated)");
+ uiDefButI(block, NUM, 0, "Collect Rate ",
+ (xpos+edgsp+(5*mpref)+(5*midsp)), y1, mpref, buth,
+ &U.texcollectrate, 1.0, 3600.0, 30, 2, "Number of seconds between each run of the GL texture garbage collector.");
+
+ /* *** */
+ uiDefBut(block, LABEL,0,"Color range for weight paint",
+ (xpos+edgsp+(2*midsp)+(2*mpref)),y6label,mpref,buth,
+ 0, 0, 0, 0, 0, "");
+
+ uiDefButBitI(block, TOG, USER_CUSTOM_RANGE, B_WPAINT_RANGE, "ColorBand",
+ (xpos+edgsp+(2*midsp)+(2*mpref)),y5,mpref,buth,
+ &(U.flag), 0, 0, 0, 0,
+ "");
+
+ if((U.flag & USER_CUSTOM_RANGE)==0) {
+ vDM_ColorBand_store(NULL);
+ }
+ else {
+ rctf butrect;
+
+ vDM_ColorBand_store(&U.coba_weight); /* also signal for derivedmesh to use colorband */
+
+ BLI_init_rctf(&butrect, (xpos+edgsp+(2*midsp)+(2*mpref)),
+ (xpos+edgsp+(2*midsp)+(2*mpref)) + mpref,
+ y3, y3+30);
+
+ draw_colorband_buts_small(block, &U.coba_weight, &butrect, B_WPAINT_RANGE);
+ }
+
+ uiDefBut(block, LABEL,0,"Audio mixing buffer:",
+ (xpos+edgsp+(2*midsp)+(2*mpref)),y2label,mpref,buth,
+ 0, 0, 0, 0, 0, "");
+ uiBlockBeginAlign(block);
+ uiDefButI(block, ROW, 0, "256",
+ (xpos+edgsp+(2*midsp)+(2*mpref)),y1,(mpref/4),buth,
+ &U.mixbufsize, 2.0, 256.0, 0, 0, "Set audio mixing buffer size to 256 samples");
+ uiDefButI(block, ROW, 0, "512",
+ (xpos+edgsp+(2*midsp)+(2*mpref)+(mpref/4)),y1,(mpref/4),buth,
+ &U.mixbufsize, 2.0, 512.0, 0, 0, "Set audio mixing buffer size to 512 samples");
+ uiDefButI(block, ROW, 0, "1024",
+ (xpos+edgsp+(2*midsp)+(2*mpref)+(2*mpref/4)),y1,(mpref/4),buth,
+ &U.mixbufsize, 2.0, 1024.0, 0, 0, "Set audio mixing buffer size to 1024 samples");
+ uiDefButI(block, ROW, 0, "2048",
+ (xpos+edgsp+(2*midsp)+(2*mpref)+(3*mpref/4)),y1,(mpref/4),buth,
+ &U.mixbufsize, 2.0, 2048.0, 0, 0, "Set audio mixing buffer size to 2048 samples");
+ uiBlockEndAlign(block);
+
+ } else if(U.userpref == 5) { /* file paths */
+
+ /* yafray: (temporary) path button for yafray xml export, now with fileselect */
+ uiBlockBeginAlign(block);
+ uiDefBut(block, TEX, 0, "YFexport: ",
+ (xpos+edgsp), y2+buth+rspace, lpref-smfileselbut, buth,
+ U.yfexportdir, 1.0, 63.0, 0, 0,
+ "The default directory for yafray xml export (must exist!)");
+ uiDefIconBut(block, BUT, B_YAFRAYDIRFILESEL, ICON_FILESEL,
+ (xpos+edgsp+lpref-smfileselbut), y2+buth+rspace, smfileselbut, buth,
+ 0, 0, 0, 0, 0, "Select the default yafray export directory");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefBut(block, TEX, 0, "Fonts: ",
+ (xpos+edgsp),y2,(lpref-smfileselbut),buth,
+ U.fontdir, 1.0, 63.0, 0, 0,
+ "The default directory to search for loading fonts");
+ uiDefIconBut(block, BUT, B_FONTDIRFILESEL, ICON_FILESEL,
+ (xpos+edgsp+lpref-smfileselbut),y2,smfileselbut,buth,
+ 0, 0, 0, 0, 0, "Select the default font directory");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefBut(block, TEX, 0, "Textures: ",
+ (xpos+edgsp+lpref+midsp),y2,(lpref-smfileselbut),buth,
+ U.textudir, 1.0, 63.0, 0, 0, "The default directory to search for textures");
+ uiDefIconBut(block, BUT, B_TEXTUDIRFILESEL, ICON_FILESEL,
+ (xpos+edgsp+(2*lpref)+midsp-smfileselbut),y2,smfileselbut,buth,
+ 0, 0, 0, 0, 0, "Select the default texture location");
+ uiBlockEndAlign(block);
+
+
+ uiBlockBeginAlign(block);
+ uiDefBut(block, TEX, 0, "Tex Plugins: ",
+ (xpos+edgsp+(2*lpref)+(2*midsp)),y2,(lpref-smfileselbut),buth,
+ U.plugtexdir, 1.0, 63.0, 0, 0, "The default directory to search for texture plugins");
+ uiDefIconBut(block, BUT, B_PLUGTEXDIRFILESEL, ICON_FILESEL,
+ (xpos+edgsp+(3*lpref)+(2*midsp)-smfileselbut),y2,smfileselbut,buth,
+ 0, 0, 0, 0, 0, "Select the default texture plugin location");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefBut(block, TEX, 0, "Seq Plugins: ",
+ (xpos+edgsp+(3*lpref)+(3*midsp)),y2,(lpref-smfileselbut),buth,
+ U.plugseqdir, 1.0, 63.0, 0, 0, "The default directory to search for sequence plugins");
+ uiDefIconBut(block, BUT, B_PLUGSEQDIRFILESEL, ICON_FILESEL,
+ (xpos+edgsp+(4*lpref)+(3*midsp)-smfileselbut),y2,smfileselbut,buth,
+ 0, 0, 0, 0, 0, "Select the default sequence plugin location");
+ uiBlockEndAlign(block);
+
+
+ uiBlockBeginAlign(block);
+ uiDefBut(block, TEX, 0, "Render: ",
+ (xpos+edgsp),y1,(lpref-smfileselbut),buth,
+ U.renderdir, 1.0, 63.0, 0, 0, "The default directory for rendering output");
+ uiDefIconBut(block, BUT, B_RENDERDIRFILESEL, ICON_FILESEL,
+ (xpos+edgsp+lpref-smfileselbut),y1,smfileselbut,buth,
+ 0, 0, 0, 0, 0, "Select the default render output location");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefBut(block, TEX, 0, "Python: ",
+ (xpos+edgsp+lpref+midsp),y1,(lpref-2*smfileselbut),buth,
+ U.pythondir, 1.0, 63.0, 0, 0, "The default directory to search for Python scripts");
+ uiDefIconBut(block, BUT, B_PYMENUEVAL, ICON_SCRIPT,
+ (xpos+edgsp+(2*lpref)+midsp-2*smfileselbut),y1,smfileselbut,buth,
+ 0, 0, 0, 0, 0, "Re-evaluate scripts registration in menus");
+ uiDefIconBut(block, BUT, B_PYTHONDIRFILESEL, ICON_FILESEL,
+ (xpos+edgsp+(2*lpref)+midsp-smfileselbut),y1,smfileselbut,buth,
+ 0, 0, 0, 0, 0, "Select the default Python script location");
+ uiBlockEndAlign(block);
+
+
+ uiBlockBeginAlign(block);
+ uiDefBut(block, TEX, 0, "Sounds: ",
+ (xpos+edgsp+(2*lpref)+(2*midsp)),y1,(lpref-smfileselbut),buth,
+ U.sounddir, 1.0, 63.0, 0, 0, "The default directory to search for sounds");
+ uiDefIconBut(block, BUT, B_SOUNDDIRFILESEL, ICON_FILESEL,
+ (xpos+edgsp+(3*lpref)+(2*midsp)-smfileselbut),y1,smfileselbut,buth,
+ 0, 0, 0, 0, 0, "Selet the default sound location");
+ uiBlockEndAlign(block);
+
+ uiBlockBeginAlign(block);
+ uiDefBut(block, TEX, 0, "Temp: ",
+ (xpos+edgsp+(3*lpref)+(3*midsp)),y1,(lpref-smfileselbut),buth,
+ U.tempdir, 1.0, 63.0, 0, 0, "The directory for storing temporary save files");
+ uiDefIconBut(block, BUT, B_TEMPDIRFILESEL, ICON_FILESEL,
+ (xpos+edgsp+(4*lpref)+(3*midsp)-smfileselbut),y1,smfileselbut,buth,
+ 0, 0, 0, 0, 0, "Select the default temporary save file location");
+ uiBlockEndAlign(block);
+
+ }
+
+ uiDrawBlock(block);
+
+ myortho2(-0.375, (float)(sa->winx)-0.375, -0.375, (float)(sa->winy)-0.375);
+ draw_area_emboss(sa);
+
+ /* restore buttons transform */
+ if(curarea->winx<=1280.0) {
+ fac= ((float)curarea->winx)/1280.0f;
+ myortho2(0.0, 1280.0, 0.0, curarea->winy/fac);
+ }
+ else {
+ myortho2(0.0, (float)curarea->winx, 0.0, (float)curarea->winy);
+ }
+ sa->win_swap= WIN_BACK_OK;
+
+}
+
+
+static void winqreadinfospace(ScrArea *sa, void *spacedata, BWinEvent *evt)
+{
+ unsigned short event= evt->event;
+ short val= evt->val;
+
+ if(val) {
+ if( uiDoBlocks(&curarea->uiblocks, event)!=UI_NOTHING ) event= 0;
+
+ switch(event) {
+ case UI_BUT_EVENT:
+ if(val==REDRAWTIME) allqueue(REDRAWTIME, 0);
+ else if(val==B_ADD_THEME) {
+ bTheme *btheme, *new;
+
+ btheme= U.themes.first;
+ new= MEM_callocN(sizeof(bTheme), "theme");
+ memcpy(new, btheme, sizeof(bTheme));
+ BLI_addhead(&U.themes, new);
+ strcpy(new->name, "New User Theme");
+ addqueue(sa->win, REDRAW, 1);
+ }
+ else if(val==B_DEL_THEME) {
+ bTheme *btheme= U.themes.first;
+ BLI_remlink(&U.themes, btheme);
+ MEM_freeN(btheme);
+ BIF_SetTheme(sa); /* prevent usage of old theme in calls */
+ addqueue(sa->win, REDRAW, 1);
+ }
+ else if(val==B_NAME_THEME) {
+ bTheme *btheme= U.themes.first;
+ if(strcmp(btheme->name, "Default")==0) {
+ strcpy(btheme->name, "New User Theme");
+ addqueue(sa->win, REDRAW, 1);
+ }
+ }
+ else if(val==B_UPDATE_THEME) {
+ allqueue(REDRAWALL, 0);
+ }
+ else if(val==B_UPDATE_THEME_ICONS) {
+ BIF_icons_free();
+ BIF_icons_init(BIFICONID_LAST+1);
+ allqueue(REDRAWALL, 0);
+ }
+ else if(val==B_CHANGE_THEME) {
+ th_curcol= TH_BACK; /* backdrop color is always there... */
+ addqueue(sa->win, REDRAW, 1);
+ }
+ else if(val==B_THEME_COPY) {
+ if(th_curcol_ptr) {
+ th_curcol_arr[0]= th_curcol_ptr[0];
+ th_curcol_arr[1]= th_curcol_ptr[1];
+ th_curcol_arr[2]= th_curcol_ptr[2];
+ th_curcol_arr[3]= th_curcol_ptr[3];
+ addqueue(sa->win, REDRAW, 1);
+ }
+ }
+ else if(val==B_THEME_PASTE) {
+ if(th_curcol_ptr) {
+ th_curcol_ptr[0]= th_curcol_arr[0];
+ th_curcol_ptr[1]= th_curcol_arr[1];
+ th_curcol_ptr[2]= th_curcol_arr[2];
+ th_curcol_ptr[3]= th_curcol_arr[3];
+ allqueue(REDRAWALL, 0);
+ }
+ }
+ else if(val==B_RECALCLIGHT) {
+ if(U.light[0].flag==0 && U.light[1].flag==0 && U.light[2].flag==0)
+ U.light[0].flag= 1;
+
+ default_gl_light();
+ addqueue(sa->win, REDRAW, 1);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ else if (val==B_MEMCACHELIMIT) {
+ printf("Setting memcache limit to %d\n",
+ U.memcachelimit);
+ MEM_CacheLimiter_set_maximum(
+ U.memcachelimit * 1024 * 1024);
+ }
+ else if (val==B_WPAINT_RANGE) {
+ addqueue(sa->win, REDRAW, 1);
+ if(OBACT && (G.f & G_WEIGHTPAINT)) {
+ DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ }
+ else do_global_buttons(val);
+
+ break;
+ }
+ }
+}
+
+static void init_infospace(ScrArea *sa)
+{
+ SpaceInfo *sinfo;
+
+ sinfo= MEM_callocN(sizeof(SpaceInfo), "initinfo");
+ BLI_addhead(&sa->spacedata, sinfo);
+
+ sinfo->spacetype=SPACE_INFO;
+}
+
+/* ******************** SPACE: BUTS ********************** */
+
+extern void drawbutspace(ScrArea *sa, void *spacedata); /* buttons.c */
+
+static void changebutspace(ScrArea *sa, void *spacedata)
+{
+ if(G.v2d==0) return;
+
+ test_view2d(G.v2d, curarea->winx, curarea->winy);
+ myortho2(G.v2d->cur.xmin, G.v2d->cur.xmax, G.v2d->cur.ymin, G.v2d->cur.ymax);
+}
+
+static void winqreadbutspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
+{
+ unsigned short event= evt->event;
+ short val= evt->val;
+ SpaceButs *sbuts= curarea->spacedata.first;
+ ScrArea *sa2, *sa3d;
+ int nr;
+
+ if(val) {
+
+ if( uiDoBlocks(&curarea->uiblocks, event)!=UI_NOTHING ) event= 0;
+
+ switch(event) {
+ case UI_BUT_EVENT:
+ do_butspace(val);
+ break;
+
+ case MIDDLEMOUSE:
+ case WHEELUPMOUSE:
+ case WHEELDOWNMOUSE:
+ view2dmove(event); /* in drawipo.c */
+ break;
+ case PAGEUPKEY:
+ event= WHEELUPMOUSE;
+ view2dmove(event); /* in drawipo.c */
+ break;
+ case PAGEDOWNKEY:
+ event= WHEELDOWNMOUSE;
+ view2dmove(event); /* in drawipo.c */
+ break;
+
+ case RIGHTMOUSE:
+ nr= pupmenu("Panel Alignment%t|Horizontal%x1|Vertical%x2|Free %x0");
+ if (nr>=0) {
+ sbuts->align= nr;
+ if(nr) {
+ uiAlignPanelStep(sa, 1.0);
+ do_buts_buttons(B_BUTSHOME);
+ }
+ }
+
+ break;
+ case PADPLUSKEY:
+ view2d_zoom(&sbuts->v2d, 0.06f, curarea->winx, curarea->winy);
+ scrarea_queue_winredraw(curarea);
+ break;
+ case PADMINUS:
+ view2d_zoom(&sbuts->v2d, -0.075f, curarea->winx, curarea->winy);
+ scrarea_queue_winredraw(curarea);
+ break;
+ case RENDERPREVIEW:
+ BIF_previewrender_buts(sbuts);
+ break;
+
+ case HOMEKEY:
+ do_buts_buttons(B_BUTSHOME);
+ break;
+
+
+ /* if only 1 view, also de persp, excluding arrowkeys */
+ case PAD0: case PAD1: case PAD3:
+ case PAD5: case PAD7: case PAD9:
+ case PADENTER: case ZKEY: case PKEY:
+ sa3d= 0;
+ sa2= G.curscreen->areabase.first;
+ while(sa2) {
+ if(sa2->spacetype==SPACE_VIEW3D) {
+ if(sa3d) return;
+ sa3d= sa2;
+ }
+ sa2= sa2->next;
+ }
+ if(sa3d) {
+ sa= curarea;
+ areawinset(sa3d->win);
+
+ if(event==PKEY && G.qual==0) start_game();
+ else if(event==ZKEY) toggle_shading();
+ else persptoetsen(event);
+
+ scrarea_queue_winredraw(sa3d);
+ scrarea_queue_headredraw(sa3d);
+ areawinset(sa->win);
+ }
+ }
+ }
+
+}
+
+void set_rects_butspace(SpaceButs *buts)
+{
+ /* buts space goes from (0,0) to (1280, 228) */
+
+ buts->v2d.tot.xmin= 0.0f;
+ buts->v2d.tot.ymin= 0.0f;
+ buts->v2d.tot.xmax= 1279.0f;
+ buts->v2d.tot.ymax= 228.0f;
+
+ buts->v2d.min[0]= 256.0f;
+ buts->v2d.min[1]= 42.0f;
+
+ buts->v2d.max[0]= 2048.0f;
+ buts->v2d.max[1]= 450.0f;
+
+ buts->v2d.minzoom= 0.5f;
+ buts->v2d.maxzoom= 1.21f;
+
+ buts->v2d.scroll= 0;
+ buts->v2d.keepaspect= 1;
+ buts->v2d.keepzoom= 1;
+ buts->v2d.keeptot= 1;
+
+}
+
+void test_butspace(void)
+{
+ ScrArea *area= curarea;
+ int blocksmin= uiBlocksGetYMin(&area->uiblocks)-10.0f;
+
+ G.buts->v2d.tot.ymin= MIN2(0.0f, blocksmin-10.0f);
+}
+
+static void init_butspace(ScrArea *sa)
+{
+ SpaceButs *buts;
+
+ buts= MEM_callocN(sizeof(SpaceButs), "initbuts");
+ BLI_addhead(&sa->spacedata, buts);
+
+ buts->spacetype= SPACE_BUTS;
+ buts->scaflag= BUTS_SENS_LINK|BUTS_SENS_ACT|BUTS_CONT_ACT|BUTS_ACT_ACT|BUTS_ACT_LINK;
+
+ /* set_rects only does defaults, so after reading a file the cur has not changed */
+ set_rects_butspace(buts);
+ buts->v2d.cur= buts->v2d.tot;
+
+ buts->ri = NULL;
+}
+
+void extern_set_butspace(int fkey, int do_cycle)
+{
+ ScrArea *sa;
+ SpaceButs *sbuts;
+ Object *ob= OBACT;
+
+ /* when a f-key pressed: 'closest' button window is initialized */
+ if(curarea->spacetype==SPACE_BUTS) sa= curarea;
+ else {
+ /* find area */
+ sa= G.curscreen->areabase.first;
+ while(sa) {
+ if(sa->spacetype==SPACE_BUTS) break;
+ sa= sa->next;
+ }
+ }
+
+ if(sa==NULL) return;
+
+ if(sa!=curarea) areawinset(sa->win);
+
+ sbuts= sa->spacedata.first;
+ if(!do_cycle) sbuts->oldkeypress= 0;
+
+ if(fkey==F4KEY) {
+ sbuts->mainb= CONTEXT_LOGIC;
+ }
+ else if(fkey==F5KEY) {
+ /* if it's already in shading context, cycle between tabs with the same key */
+ if (sbuts->oldkeypress == F5KEY) {
+
+ if (sbuts->tab[CONTEXT_SHADING]==TAB_SHADING_LAMP)
+ sbuts->tab[CONTEXT_SHADING]=TAB_SHADING_MAT;
+ else if (sbuts->tab[CONTEXT_SHADING]==TAB_SHADING_MAT)
+ sbuts->tab[CONTEXT_SHADING]=TAB_SHADING_TEX;
+ else if (sbuts->tab[CONTEXT_SHADING]==1) {
+ sbuts->tab[CONTEXT_SHADING]=TAB_SHADING_RAD;
+ }
+ else if (sbuts->tab[CONTEXT_SHADING]==TAB_SHADING_RAD)
+ sbuts->tab[CONTEXT_SHADING]=TAB_SHADING_WORLD;
+ else if (sbuts->tab[CONTEXT_SHADING]==TAB_SHADING_WORLD)
+ sbuts->tab[CONTEXT_SHADING]=TAB_SHADING_LAMP;
+ }
+ /* if we're coming in from texture buttons,
+ or from outside the shading context, just go to the 'default' */
+ else if (ob) {
+ sbuts->mainb= CONTEXT_SHADING;
+
+ if(ob->type==OB_CAMERA)
+ sbuts->tab[CONTEXT_SHADING]= TAB_SHADING_WORLD;
+ else if(ob->type==OB_LAMP)
+ sbuts->tab[CONTEXT_SHADING]= TAB_SHADING_LAMP;
+ else
+ sbuts->tab[CONTEXT_SHADING]= TAB_SHADING_MAT;
+ }
+ else {
+ sbuts->mainb= CONTEXT_SHADING;
+ sbuts->tab[CONTEXT_SHADING]= TAB_SHADING_MAT;
+ }
+ BIF_preview_changed(ID_TE);
+ }
+ else if(fkey==F6KEY) {
+ sbuts->mainb= CONTEXT_SHADING;
+ sbuts->tab[CONTEXT_SHADING]= TAB_SHADING_TEX;
+ BIF_preview_changed(ID_TE);
+ }
+ else if(fkey==F7KEY) {
+ /* if it's already in object context, cycle between tabs with the same key */
+ if (sbuts->oldkeypress == F7KEY) {
+
+ if (sbuts->tab[CONTEXT_OBJECT]==TAB_OBJECT_OBJECT)
+ sbuts->tab[CONTEXT_OBJECT]=TAB_OBJECT_PHYSICS;
+ else if (sbuts->tab[CONTEXT_OBJECT]==TAB_OBJECT_PHYSICS)
+ sbuts->tab[CONTEXT_OBJECT]=TAB_OBJECT_OBJECT;
+ }
+ else sbuts->mainb= CONTEXT_OBJECT;
+
+ }
+ else if(fkey==F8KEY) {
+ sbuts->mainb= CONTEXT_SHADING;
+ sbuts->tab[CONTEXT_SHADING]= TAB_SHADING_WORLD;
+ BIF_preview_changed(ID_TE);
+ }
+ else if(fkey==F9KEY) sbuts->mainb= CONTEXT_EDITING;
+ else if(fkey==F10KEY) {
+ /* if it's already in scene context, cycle between tabs with the same key */
+ if (sbuts->oldkeypress == F10KEY) {
+
+ if (sbuts->tab[CONTEXT_SCENE]==TAB_SCENE_RENDER)
+ sbuts->tab[CONTEXT_SCENE]=TAB_SCENE_ANIM;
+ else if (sbuts->tab[CONTEXT_SCENE]==TAB_SCENE_ANIM)
+ sbuts->tab[CONTEXT_SCENE]=TAB_SCENE_SOUND;
+ else if (sbuts->tab[CONTEXT_SCENE]==TAB_SCENE_SOUND)
+ sbuts->tab[CONTEXT_SCENE]=TAB_SCENE_RENDER;
+ }
+ else sbuts->mainb= CONTEXT_SCENE;
+ }
+
+ sbuts->oldkeypress = fkey;
+
+ scrarea_queue_headredraw(sa);
+ scrarea_queue_winredraw(sa);
+}
+
+/* ******************** SPACE: SEQUENCE ********************** */
+
+/* extern void drawseqspace(ScrArea *sa, void *spacedata); BIF_drawseq.h */
+
+static void winqreadseqspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
+{
+ unsigned short event= evt->event;
+ short val= evt->val;
+ SpaceSeq *sseq= curarea->spacedata.first;
+ View2D *v2d= &sseq->v2d;
+ Sequence *last_seq = get_last_seq();
+ float dx, dy;
+ int doredraw= 0, cfra=0, first;
+ short mval[2];
+ short nr;
+ short mousebut = L_MOUSE;
+
+ if(curarea->win==0) return;
+
+ if(val) {
+ if( uiDoBlocks(&curarea->uiblocks, event)!=UI_NOTHING ) event= 0;
+
+ /* swap mouse buttons based on user preference */
+ if (U.flag & USER_LMOUSESELECT) {
+ if (event == LEFTMOUSE) {
+ event = RIGHTMOUSE;
+ mousebut = L_MOUSE;
+ } else if (event == RIGHTMOUSE) {
+ event = LEFTMOUSE;
+ mousebut = R_MOUSE;
+ }
+ }
+
+ switch(event) {
+ case UI_BUT_EVENT:
+ do_seqbuttons(val);
+ break;
+ case LEFTMOUSE:
+ if(sseq->mainb || view2dmove(event)==0) {
+
+ first= 1;
+ set_special_seq_update(1);
+
+ do {
+ getmouseco_areawin(mval);
+ areamouseco_to_ipoco(v2d, mval, &dx, &dy);
+
+ cfra= (int)dx;
+ if(cfra< 1) cfra= 1;
+ /* else if(cfra> EFRA) cfra= EFRA; */
+
+ if( cfra!=CFRA || first ) {
+ first= 0;
+
+ CFRA= cfra;
+ force_draw(0);
+ update_for_newframe(); /* for audio scrubbing */
+ }
+ else PIL_sleep_ms(30);
+
+ } while(get_mbut() & mousebut);
+
+ set_special_seq_update(0);
+
+ if (cfra == 0)
+ update_for_newframe();
+ }
+ break;
+ case MIDDLEMOUSE:
+ if(sseq->mainb) seq_viewmove(sseq);
+ else view2dmove(event); /* in drawipo.c */
+ break;
+ case RIGHTMOUSE:
+ if(sseq->mainb) break;
+ mouse_select_seq();
+ break;
+ case PADPLUSKEY:
+ if (G.qual==LR_CTRLKEY) {
+ select_more_seq();
+ break;
+ }
+ case WHEELUPMOUSE:
+ if(sseq->mainb) {
+ sseq->zoom++;
+ if(sseq->zoom==-1) sseq->zoom= 1;
+ if(sseq->zoom>8) sseq->zoom= 8;
+ }
+ else {
+ if((G.qual==0)) {
+ dx= 0.1154f*(v2d->cur.xmax-v2d->cur.xmin);
+ v2d->cur.xmin+= dx;
+ v2d->cur.xmax-= dx;
+ test_view2d(G.v2d, sa->winx, sa->winy);
+ view2d_do_locks(sa, V2D_LOCK_COPY);
+ }
+ else if((G.qual==LR_SHIFTKEY)) {
+ insert_gap(25, CFRA);
+ BIF_undo_push("Insert gaps Sequencer");
+ allqueue(REDRAWSEQ, 0);
+ }
+ else if(G.qual==LR_ALTKEY) {
+ insert_gap(250, CFRA);
+ BIF_undo_push("Insert gaps Sequencer");
+ allqueue(REDRAWSEQ, 0);
+ }
+ }
+ doredraw= 1;
+ break;
+ case PADMINUS:
+ if (G.qual==LR_CTRLKEY) {
+ select_less_seq();
+ break;
+ }
+ case WHEELDOWNMOUSE:
+ if(sseq->mainb) {
+ sseq->zoom--;
+ if(sseq->zoom==0) sseq->zoom= -2;
+ if(sseq->zoom<-8) sseq->zoom= -8;
+ }
+ else {
+ if((G.qual==LR_SHIFTKEY))
+ no_gaps();
+ else if((G.qual==0)) {
+ dx= 0.15f*(v2d->cur.xmax-v2d->cur.xmin);
+ v2d->cur.xmin-= dx;
+ v2d->cur.xmax+= dx;
+ test_view2d(G.v2d, sa->winx, sa->winy);
+ view2d_do_locks(sa, V2D_LOCK_COPY);
+ }
+ }
+ doredraw= 1;
+ break;
+ case HOMEKEY:
+ if((G.qual==0))
+ do_seq_buttons(B_SEQHOME);
+ break;
+ case PADPERIOD:
+ if(last_seq) {
+ CFRA= last_seq->startdisp;
+ v2d->cur.xmin= last_seq->startdisp- (last_seq->len/20);
+ v2d->cur.xmax= last_seq->enddisp+ (last_seq->len/20);
+ update_for_newframe();
+ }
+ break;
+
+ case AKEY:
+ if (G.qual == LR_CTRLKEY) {
+ deselect_markers(1, 0);
+ allqueue(REDRAWMARKER, 0);
+ } else {
+ if(sseq->mainb) break;
+ if((G.qual==LR_SHIFTKEY)) {
+ add_sequence(-1);
+ } else if((G.qual==0)) {
+ swap_select_seq();
+ }
+ }
+ break;
+ case SPACEKEY:
+ if (G.qual==0) {
+ if (sseq->mainb) {
+ play_anim(1);
+ } else {
+ add_sequence(-1);
+ }
+ }
+ break;
+ case BKEY:
+ if(sseq->mainb) break;
+ if((G.qual==0))
+ borderselect_seq();
+ break;
+ case CKEY:
+ if((G.qual==0)) {
+ if(last_seq && (last_seq->flag & (SEQ_LEFTSEL+SEQ_RIGHTSEL))) {
+ if(last_seq->flag & SEQ_LEFTSEL) CFRA= last_seq->startdisp;
+ else CFRA= last_seq->enddisp-1;
+
+ dx= CFRA-(v2d->cur.xmax+v2d->cur.xmin)/2;
+ v2d->cur.xmax+= dx;
+ v2d->cur.xmin+= dx;
+ update_for_newframe();
+ }
+ else
+ change_sequence();
+ }
+ break;
+ case DKEY:
+ if (G.qual == (LR_CTRLKEY|LR_SHIFTKEY))
+ duplicate_marker();
+ else if ((G.qual==LR_SHIFTKEY)) {
+ if(sseq->mainb) break;
+ add_duplicate_seq();
+ }
+ break;
+ case EKEY:
+ if(sseq->mainb) break;
+ if((G.qual==0))
+ transform_seq('e', 0);
+ break;
+ case FKEY:
+ if((G.qual==0))
+ set_filter_seq();
+ break;
+ case GKEY:
+ if (G.qual & LR_CTRLKEY)
+ transform_markers('g', 0);
+ else if (G.qual==0) {
+ if(sseq->mainb) break;
+ transform_seq('g', 0);
+ }
+ break;
+ case KKEY:
+ if((G.qual==0)) { /* Cut at current frame */
+ if(okee("Cut strips")) seq_cut(CFRA);
+ }
+ break;
+ case LKEY:
+ if((G.qual==0)) { /* Cut at current frame */
+ select_linked_seq( 0 );
+ } else if((G.qual==LR_CTRLKEY)) { /* Cut at current frame */
+ select_linked_seq( 2 );
+ }
+ break;
+ case YKEY:
+ if((G.qual==0)) { /* Cut at current frame */
+ seq_separate_images();
+ }
+ break;
+ case MKEY:
+ if(G.qual==LR_ALTKEY) {
+ un_meta();
+ break; /*dont redraw timeline etc */
+ } else if((G.qual==0)){
+ if ((last_seq) &&
+ (last_seq->type == SEQ_RAM_SOUND
+ || last_seq->type == SEQ_HD_SOUND))
+ {
+ last_seq->flag ^= SEQ_MUTE;
+ doredraw = 1;
+ } else {
+ make_meta();
+ }
+ break; /*dont redraw timeline etc */
+ } else if ((G.qual==(LR_CTRLKEY|LR_ALTKEY) )) {
+ add_marker(CFRA);
+ } else if ((G.qual==LR_CTRLKEY)) {
+ rename_marker();
+ } else {
+ break; /* do nothing */
+ }
+ allqueue(REDRAWMARKER, 0);
+ break;
+ case NKEY:
+ if(G.qual==0) {
+ toggle_blockhandler(curarea, SEQ_HANDLER_PROPERTIES, UI_PNL_TO_MOUSE);
+ scrarea_queue_winredraw(curarea);
+ }
+ break;
+ case RKEY:
+ if(G.qual==LR_SHIFTKEY)
+ seq_remap_paths();
+ if(G.qual==LR_ALTKEY)
+ reload_sequence();
+ else if (G.qual==0)
+ reassign_inputs_seq_effect();
+ break;
+ case SKEY:
+ if((G.qual==LR_SHIFTKEY))
+ seq_snap_menu();
+ break;
+ case PKEY:
+ if((G.qual==0))
+ touch_seq_files();
+ break;
+ case TKEY: /* popup menu */
+ nr= pupmenu("Time value%t|Frames %x1|Seconds%x2");
+ if (nr>0) {
+ if(nr==1) sseq->flag |= SEQ_DRAWFRAMES;
+ else sseq->flag &= ~SEQ_DRAWFRAMES;
+ doredraw= 1;
+ }
+ break;
+ case XKEY:
+ case DELKEY:
+ if(G.qual==0) {
+ if(sseq->mainb) break;
+ if((G.qual==0))
+ del_seq();
+ }
+ break;
+ }
+ }
+
+ if(doredraw) scrarea_queue_winredraw(curarea);
+}
+
+
+static void init_seqspace(ScrArea *sa)
+{
+ SpaceSeq *sseq;
+
+ sseq= MEM_callocN(sizeof(SpaceSeq), "initseqspace");
+ BLI_addhead(&sa->spacedata, sseq);
+
+ sseq->spacetype= SPACE_SEQ;
+ sseq->zoom= 4;
+ sseq->blockscale= 0.7;
+ sseq->chanshown = 0;
+
+ /* seq space goes from (0,8) to (250, 0) */
+
+ sseq->v2d.tot.xmin= 0.0;
+ sseq->v2d.tot.ymin= 0.0;
+ sseq->v2d.tot.xmax= 250.0;
+ sseq->v2d.tot.ymax= 8.0;
+
+ sseq->v2d.cur= sseq->v2d.tot;
+
+ sseq->v2d.min[0]= 10.0;
+ sseq->v2d.min[1]= 4.0;
+
+ sseq->v2d.max[0]= 32000.0;
+ sseq->v2d.max[1]= MAXSEQ;
+
+ sseq->v2d.minzoom= 0.1f;
+ sseq->v2d.maxzoom= 10.0;
+
+ sseq->v2d.scroll= L_SCROLL+B_SCROLL;
+ sseq->v2d.keepaspect= 0;
+ sseq->v2d.keepzoom= 0;
+ sseq->v2d.keeptot= 0;
+}
+
+/* ******************** SPACE: ACTION ********************** */
+extern void drawactionspace(ScrArea *sa, void *spacedata);
+extern void winqreadactionspace(struct ScrArea *sa, void *spacedata, struct BWinEvent *evt);
+
+static void changeactionspace(ScrArea *sa, void *spacedata)
+{
+ if(G.v2d==0) return;
+
+ /* this sets the sub-areas correct, for scrollbars */
+ test_view2d(G.v2d, sa->winx, sa->winy);
+
+ /* action space uses weird matrices... local calculated in a function */
+ /* myortho2(G.v2d->cur.xmin, G.v2d->cur.xmax, G.v2d->cur.ymin, G.v2d->cur.ymax); */
+}
+
+
+static void init_actionspace(ScrArea *sa)
+{
+ SpaceAction *saction;
+
+ saction= MEM_callocN(sizeof(SpaceAction), "initactionspace");
+ BLI_addhead(&sa->spacedata, saction);
+
+ saction->spacetype= SPACE_ACTION;
+ saction->blockscale= 0.7;
+
+ saction->v2d.tot.xmin= 1.0;
+ saction->v2d.tot.ymin= -1000.0;
+ saction->v2d.tot.xmax= 1000.0;
+ saction->v2d.tot.ymax= 0.0;
+
+ saction->v2d.cur.xmin= -5.0;
+ saction->v2d.cur.ymin= -75.0;
+ saction->v2d.cur.xmax= 65.0;
+ saction->v2d.cur.ymax= 5.0;
+
+ saction->v2d.min[0]= 0.0;
+ saction->v2d.min[1]= 0.0;
+
+ saction->v2d.max[0]= 32000.0;
+ saction->v2d.max[1]= 1000.0;
+
+ saction->v2d.minzoom= 0.01;
+ saction->v2d.maxzoom= 50;
+
+ saction->v2d.scroll= R_SCROLL+B_SCROLL;
+ saction->v2d.keepaspect= 0;
+ saction->v2d.keepzoom= V2D_LOCKZOOM_Y;
+ saction->v2d.keeptot= 0;
+
+}
+
+static void free_actionspace(SpaceAction *saction)
+{
+ /* don't free saction itself */
+
+ /* __PINFAKE */
+/* if (saction->flag & SACTION_PIN)
+ if (saction->action)
+ saction->action->id.us --;
+
+*/ /* end PINFAKE */
+}
+
+
+/* ******************** SPACE: FILE ********************** */
+
+static void init_filespace(ScrArea *sa)
+{
+ SpaceFile *sfile;
+
+ sfile= MEM_callocN(sizeof(SpaceFile), "initfilespace");
+ BLI_addhead(&sa->spacedata, sfile);
+
+ sfile->dir[0]= '/';
+ sfile->type= FILE_UNIX;
+ sfile->blockscale= 0.7;
+ sfile->spacetype= SPACE_FILE;
+}
+
+
+/* ******************** SPACE: SOUND ********************** */
+
+extern void drawsoundspace(ScrArea *sa, void *spacedata);
+extern void winqreadsoundspace(struct ScrArea *sa, void *spacedata, struct BWinEvent *evt);
+
+static void init_soundspace(ScrArea *sa)
+{
+ SpaceSound *ssound;
+
+ ssound= MEM_callocN(sizeof(SpaceSound), "initsoundspace");
+ BLI_addhead(&sa->spacedata, ssound);
+
+ ssound->spacetype= SPACE_SOUND;
+ ssound->blockscale= 0.7;
+ /* sound space goes from (0,8) to (250, 0) */
+
+ ssound->v2d.tot.xmin= -4.0;
+ ssound->v2d.tot.ymin= -4.0;
+ ssound->v2d.tot.xmax= 250.0;
+ ssound->v2d.tot.ymax= 255.0;
+
+ ssound->v2d.cur.xmin= -4.0;
+ ssound->v2d.cur.ymin= -4.0;
+ ssound->v2d.cur.xmax= 50.0;
+ ssound->v2d.cur.ymax= 255.0;
+
+ ssound->v2d.min[0]= 1.0;
+ ssound->v2d.min[1]= 259.0;
+
+ ssound->v2d.max[0]= 32000.0;
+ ssound->v2d.max[1]= 259;
+
+ ssound->v2d.minzoom= 0.1f;
+ ssound->v2d.maxzoom= 10.0;
+
+ ssound->v2d.scroll= B_SCROLL;
+ ssound->v2d.keepaspect= 0;
+ ssound->v2d.keepzoom= 0;
+ ssound->v2d.keeptot= 0;
+
+}
+
+void free_soundspace(SpaceSound *ssound)
+{
+ /* don't free ssound itself */
+
+
+}
+
+/* ******************** SPACE: IMAGE ********************** */
+
+static void changeimagepace(ScrArea *sa, void *spacedata)
+{
+ image_preview_event(2);
+}
+
+static void winqreadimagespace(ScrArea *sa, void *spacedata, BWinEvent *evt)
+{
+ SpaceImage *sima= spacedata;
+ unsigned short event= evt->event;
+ short val= evt->val;
+
+ if(val==0) return;
+
+ if(uiDoBlocks(&sa->uiblocks, event)!=UI_NOTHING ) event= 0;
+
+ if (U.flag & USER_LMOUSESELECT) {
+ if (event == LEFTMOUSE) {
+ event = RIGHTMOUSE;
+ } else if (event == RIGHTMOUSE) {
+ event = LEFTMOUSE;
+ }
+ }
+
+ if (sima->image && (sima->flag & SI_DRAWTOOL)) {
+ switch(event) {
+ case CKEY:
+ toggle_blockhandler(sa, IMAGE_HANDLER_PAINT, UI_PNL_UNSTOW);
+ scrarea_queue_winredraw(sa);
+ break;
+ case LEFTMOUSE:
+ imagepaint_paint(L_MOUSE, 0);
+ break;
+ case RIGHTMOUSE:
+ imagepaint_pick(R_MOUSE);
+ break;
+ }
+ }
+ else if (G.obedit) {
+ /* Draw tool is inactive, editmode is enabled and the image is not a render or composite */
+ if (EM_texFaceCheck() && (G.sima->image==0 || (G.sima->image->type != IMA_TYPE_R_RESULT && G.sima->image->type != IMA_TYPE_COMPOSITE))) {
+ switch(event) {
+ case LEFTMOUSE:
+ if(G.qual == LR_SHIFTKEY) {
+ if(G.sima->image && G.sima->image->tpageflag & IMA_TILES) {
+ mouseco_to_curtile();
+ }
+ } else if (!gesture()) {
+ mouseco_to_cursor_sima();
+ }
+ break;
+ case RIGHTMOUSE:
+ mouse_select_sima();
+ break;
+ case AKEY:
+ select_swap_tface_uv();
+ break;
+ case BKEY:
+ if(G.qual==LR_SHIFTKEY)
+ borderselect_sima(UV_SELECT_PINNED);
+ else if((G.qual==0))
+ borderselect_sima(UV_SELECT_ALL);
+ break;
+ case CKEY:
+ if (G.sima->flag & SI_SYNC_UVSEL) {
+ /* operate on the editmesh */
+ if (G.qual==0) {
+ if (G.scene->selectmode != SCE_SELECT_FACE) {
+ G.sima->flag ^= SI_SELACTFACE;
+ scrarea_queue_winredraw(curarea);
+ }
+ } else {
+ error("Sync selection to Edit Mesh disables UV select options");
+ }
+ } else {
+ /* normal operaton */
+ if(G.qual==LR_CTRLKEY) {
+ G.sima->sticky = SI_STICKY_VERTEX;
+ scrarea_do_headdraw(curarea);
+ } else if(G.qual==LR_SHIFTKEY) {
+ G.sima->sticky = SI_STICKY_DISABLE;
+ scrarea_do_headdraw(curarea);
+ } else if(G.qual==LR_ALTKEY) {
+ G.sima->sticky = SI_STICKY_LOC;
+ scrarea_do_headdraw(curarea);
+ } else {
+ G.sima->flag ^= SI_SELACTFACE;
+ scrarea_queue_winredraw(curarea);
+ }
+ }
+ break;
+ case EKEY :
+ if(okee("Unwrap"))
+ unwrap_lscm(0);
+ break;
+ case HKEY:
+ if(G.qual==LR_ALTKEY)
+ reveal_tface_uv();
+ else if((G.qual==LR_SHIFTKEY))
+ hide_tface_uv(1);
+ else if((G.qual==0))
+ hide_tface_uv(0);
+ break;
+ case LKEY:
+ if(G.qual==0)
+ select_linked_tface_uv(0);
+ else if(G.qual==LR_SHIFTKEY)
+ select_linked_tface_uv(1);
+ else if(G.qual==LR_CTRLKEY)
+ select_linked_tface_uv(2);
+ else if(G.qual==LR_ALTKEY)
+ unlink_selection();
+ break;
+ case PKEY:
+ if(G.qual==LR_CTRLKEY)
+ pack_charts_tface_uv();
+ else if(G.qual==LR_SHIFTKEY)
+ select_pinned_tface_uv();
+ else if(G.qual==LR_ALTKEY)
+ pin_tface_uv(0);
+ else
+ pin_tface_uv(1);
+ break;
+ case GKEY:
+ if((G.qual==0) && is_uv_tface_editing_allowed()) {
+ initTransform(TFM_TRANSLATION, CTX_NONE);
+ Transform();
+ }
+ break;
+ case RKEY:
+ if((G.qual==0) && is_uv_tface_editing_allowed()) {
+ initTransform(TFM_ROTATION, CTX_NONE);
+ Transform();
+ }
+ break;
+ case SKEY:
+ if (is_uv_tface_editing_allowed()) {
+ if ( G.qual==LR_SHIFTKEY) {
+ /* Snap */
+ snap_menu_sima();
+ } else if (G.qual==0) {
+ initTransform(TFM_RESIZE, CTX_NONE);
+ Transform();
+ }
+ }
+ break;
+ case VKEY:
+ if(G.qual == 0)
+ stitch_vert_uv_tface();
+ else if(G.qual==LR_SHIFTKEY)
+ stitch_limit_uv_tface();
+ else if(G.qual==LR_CTRLKEY)
+ minimize_stretch_tface_uv();
+ break;
+ case WKEY:
+ weld_align_menu_tface_uv();
+ break;
+ case MKEY:
+ if((G.qual==0))
+ mirrormenu_tface_uv();
+ break;
+ case COMMAKEY:
+ if(G.qual==LR_SHIFTKEY) {
+ G.v2d->around= V3D_CENTROID;
+ } else if(G.qual==0) {
+ G.v2d->around= V3D_CENTER;
+ }
+
+ scrarea_queue_headredraw(curarea);
+ scrarea_queue_winredraw(curarea);
+ break;
+ case PERIODKEY:
+ if(G.qual==LR_CTRLKEY) {
+ G.v2d->around= V3D_LOCAL;
+ } else if(G.qual==0) {
+ G.v2d->around= V3D_CURSOR;
+ }
+ scrarea_queue_headredraw(curarea);
+ scrarea_queue_winredraw(curarea);
+ break;
+ case PADPERIOD:
+ if(G.qual==0)
+ image_viewcenter();
+ break;
+ case OKEY:
+ if(G.qual==0) {
+ G.scene->proportional= !G.scene->proportional;
+ allqueue(REDRAWHEADERS, 0);
+ } else if (G.qual==LR_SHIFTKEY) {
+ G.scene->prop_mode = (G.scene->prop_mode+1)%7;
+ allqueue(REDRAWHEADERS, 0);
+ }
+ break;
+ case PADSLASHKEY:
+ if(G.qual==0)
+ G.sima->flag ^= SI_LOCAL_UV;
+ scrarea_queue_winredraw(curarea);
+ break;
+ case TABKEY:
+ if (G.qual == LR_SHIFTKEY) {
+ G.scene->snap_flag ^= SCE_SNAP;
+ allqueue(REDRAWHEADERS, 0);
+ }
+ break;
+ }
+ }
+ } else {
+ /* Draw and editmode are inactive */
+ switch(event) {
+ case LEFTMOUSE:
+ sima_sample_color();
+ break;
+ case RIGHTMOUSE:
+ if(G.f & (G_VERTEXPAINT|G_TEXTUREPAINT))
+ sample_vpaint();
+ break;
+ case NKEY:
+ if(G.qual==LR_CTRLKEY)
+ replace_names_but();
+ break;
+ case PKEY:
+ if(G.qual==LR_SHIFTKEY) {
+ toggle_blockhandler(sa, IMAGE_HANDLER_PREVIEW, 0);
+ scrarea_queue_winredraw(sa);
+ }
+ break;
+ }
+ }
+
+
+ /* least intrusive nonumpad hack, only for plus/minus */
+ if (U.flag & USER_NONUMPAD) {
+ event= convert_for_nonumpad(event);
+ }
+
+ /* Events handled always (whether the draw tool is active or not) */
+ switch (event) {
+ case UI_BUT_EVENT:
+ do_image_buttons(val); /* header_image.c */
+ break;
+ case MIDDLEMOUSE:
+ if((G.qual==LR_CTRLKEY) || ((U.flag & USER_TWOBUTTONMOUSE) && (G.qual==(LR_ALTKEY|LR_CTRLKEY))))
+ image_viewmove(1);
+ else
+ image_viewmove(0);
+ break;
+ case WHEELUPMOUSE: case WHEELDOWNMOUSE: case PADPLUSKEY: case PADMINUS:
+ case PAD1: case PAD2: case PAD4: case PAD8:
+ image_viewzoom(event, (G.qual & LR_SHIFTKEY)==0);
+ scrarea_queue_winredraw(sa);
+ break;
+ case HOMEKEY:
+ if((G.qual==0))
+ image_home();
+
+ break;
+ case NKEY:
+ if(G.qual==LR_ALTKEY) {
+ new_image_sima();
+ } else if(G.qual==0) {
+ /*if (EM_texFaceCheck()) {
+ toggle_blockhandler(sa, IMAGE_HANDLER_TRANSFORM_PROPERTIES, UI_PNL_TO_MOUSE);
+ } else {
+ toggle_blockhandler(sa, IMAGE_HANDLER_PROPERTIES, UI_PNL_TO_MOUSE);
+ }*/
+ toggle_blockhandler(sa, IMAGE_HANDLER_PROPERTIES, UI_PNL_TO_MOUSE);
+ scrarea_queue_winredraw(sa);
+ }
+ break;
+ case OKEY:
+ if (G.qual & LR_ALTKEY)
+ open_image_sima(G.qual & LR_CTRLKEY);
+ break;
+ case RKEY:
+ if(G.qual==LR_ALTKEY)
+ reload_image_sima();
+ break;
+ case SKEY:
+ if(G.qual & LR_ALTKEY)
+ save_image_sima();
+ break;
+ case ESCKEY:
+ if(sima->flag & SI_PREVSPACE) {
+ /* only allow ESC once */
+ sima->flag &= ~SI_PREVSPACE;
+
+ sima= sa->spacedata.first;
+ if(sima->next) {
+ SpaceLink *sl;
+
+ BLI_remlink(&sa->spacedata, sima);
+ BLI_addtail(&sa->spacedata, sima);
+
+ sl= sa->spacedata.first;
+
+ newspace(sa, sl->spacetype);
+ }
+ }
+ if(sima->flag & SI_FULLWINDOW) {
+ sima->flag &= ~SI_FULLWINDOW;
+ if(sa->full)
+ area_fullscreen();
+ }
+ }
+}
+
+
+static void init_imagespace(ScrArea *sa)
+{
+ SpaceImage *sima;
+
+ sima= MEM_callocN(sizeof(SpaceImage), "initimaspace");
+ BLI_addhead(&sa->spacedata, sima);
+
+ sima->spacetype= SPACE_IMAGE;
+ sima->zoom= 1;
+ sima->blockscale= 0.7;
+
+ sima->iuser.ok= 1;
+ sima->iuser.fie_ima= 2;
+ sima->iuser.frames= 100;
+}
+
+
+/* ******************** SPACE: IMASEL ********************** */
+
+extern void drawimaselspace(ScrArea *sa, void *spacedata);
+extern void winqreadimaselspace(struct ScrArea *sa, void *spacedata, struct BWinEvent *evt);
+
+static void changeimaselspace(ScrArea *sa, void *spacedata)
+{
+ if(G.v2d==0) return;
+
+ test_view2d(G.v2d, curarea->winx, curarea->winy);
+ myortho2(G.v2d->cur.xmin, G.v2d->cur.xmax, G.v2d->cur.ymin, G.v2d->cur.ymax);
+}
+
+static void init_imaselspace(ScrArea *sa)
+{
+ SpaceImaSel *simasel;
+
+ simasel= MEM_callocN(sizeof(SpaceImaSel), "init imaselspace");
+ BLI_addhead(&sa->spacedata, simasel);
+
+ simasel->spacetype= SPACE_IMASEL;
+ simasel->blockscale= 0.7;
+
+ /* view 2D */
+ simasel->v2d.tot.xmin= -10.0;
+ simasel->v2d.tot.ymin= -10.0;
+ simasel->v2d.tot.xmax= (float)sa->winx + 10.0f;
+ simasel->v2d.tot.ymax= (float)sa->winy + 10.0f;
+
+ simasel->v2d.cur.xmin= 0.0;
+ simasel->v2d.cur.ymin= 0.0;
+ simasel->v2d.cur.xmax= (float)sa->winx;
+ simasel->v2d.cur.ymax= (float)sa->winy;
+
+ simasel->v2d.min[0]= 1.0;
+ simasel->v2d.min[1]= 1.0;
+
+ simasel->v2d.max[0]= 32000.0f;
+ simasel->v2d.max[1]= 32000.0f;
+
+ simasel->v2d.minzoom= 0.5f;
+ simasel->v2d.maxzoom= 1.21f;
+
+ simasel->v2d.scroll= 0;
+ simasel->v2d.keepaspect= 1;
+ simasel->v2d.keepzoom= 1;
+ simasel->v2d.keeptot= 0;
+
+ simasel->prv_h = 96;
+ simasel->prv_w = 96;
+
+ simasel->flag = 7; /* ??? elubie */
+ strcpy (simasel->dir, U.textudir); /* TON */
+ strcpy (simasel->file, "");
+
+ simasel->returnfunc = 0;
+ simasel->title[0] = 0;
+ simasel->type = FILE_UNIX;
+ simasel->files = BIF_filelist_new();
+}
+
+/* ******************** SPACE: OOPS ********************** */
+
+extern void drawoopsspace(ScrArea *sa, void *spacedata);
+
+static void winqreadoopsspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
+{
+ unsigned short event= evt->event;
+ short val= evt->val;
+ SpaceOops *soops= curarea->spacedata.first;
+ View2D *v2d= &soops->v2d;
+ float dx, dy;
+
+ if(val==0) return;
+
+ if( uiDoBlocks(&sa->uiblocks, event)!=UI_NOTHING ) event= 0;
+
+ if (U.flag & USER_NONUMPAD) {
+ event= convert_for_nonumpad(event);
+ }
+
+ /* keep leftmouse select for outliner, regardless of user pref */
+ if(soops->type==SO_OUTLINER) {
+ switch(event) {
+ case LEFTMOUSE:
+ case RIGHTMOUSE:
+ outliner_mouse_event(sa, event);
+ break;
+ case MIDDLEMOUSE:
+ case WHEELUPMOUSE:
+ case WHEELDOWNMOUSE:
+ view2dmove(event); /* in drawipo.c */
+ soops->storeflag |= SO_TREESTORE_REDRAW;
+ break;
+
+ case AKEY:
+ if(G.qual==LR_SHIFTKEY)
+ outliner_toggle_selected(sa);
+ else
+ outliner_toggle_visible(sa);
+ break;
+ case FKEY:
+ {
+ /* search */
+ int search_flags=0, again=0;
+
+ /* CTRL=case sensitive, SHIFT=find again, ALT=complete */
+ if (G.qual & LR_CTRLKEY) search_flags |= 1;
+ if (G.qual & LR_ALTKEY) search_flags |= 8;
+ if (G.qual & LR_SHIFTKEY) again = 1;
+
+ outliner_find_panel(sa, again, search_flags);
+ }
+ break;
+ case XKEY:
+ case DELKEY:
+ outliner_del(sa);
+ break;
+ case WKEY:
+ outliner_operation_menu(sa);
+ break;
+
+ case HOMEKEY:
+ outliner_show_hierarchy(sa);
+ break;
+ case PAGEUPKEY:
+ outliner_page_up_down(sa, 1);
+ break;
+ case PAGEDOWNKEY:
+ outliner_page_up_down(sa, -1);
+ break;
+
+ case RETKEY:
+ case PADENTER:
+ outliner_mouse_event(sa, event);
+ break;
+ case PERIODKEY:
+ case PADPERIOD:
+ outliner_show_active(sa);
+ break;
+ case PADPLUSKEY:
+ outliner_one_level(sa, 1);
+ break;
+ case PADMINUS:
+ outliner_one_level(sa, -1);
+ break;
+ }
+ }
+ else {
+ /* swap mouse buttons based on user preference */
+ if (U.flag & USER_LMOUSESELECT) {
+ if (event==LEFTMOUSE) event = RIGHTMOUSE;
+ else if (event==RIGHTMOUSE) event = LEFTMOUSE;
+ }
+
+ switch(event) {
+ case LEFTMOUSE:
+ gesture();
+ break;
+ case MIDDLEMOUSE:
+ case WHEELUPMOUSE:
+ case WHEELDOWNMOUSE:
+ view2dmove(event); /* in drawipo.c */
+ break;
+ case RIGHTMOUSE:
+ mouse_select_oops();
+ break;
+ case PADPLUSKEY:
+
+ dx= 0.1154*(v2d->cur.xmax-v2d->cur.xmin);
+ dy= 0.1154*(v2d->cur.ymax-v2d->cur.ymin);
+ v2d->cur.xmin+= dx;
+ v2d->cur.xmax-= dx;
+ v2d->cur.ymin+= dy;
+ v2d->cur.ymax-= dy;
+ test_view2d(G.v2d, curarea->winx, curarea->winy);
+ scrarea_queue_winredraw(curarea);
+ break;
+
+ case PADMINUS:
+
+ dx= 0.15*(v2d->cur.xmax-v2d->cur.xmin);
+ dy= 0.15*(v2d->cur.ymax-v2d->cur.ymin);
+ v2d->cur.xmin-= dx;
+ v2d->cur.xmax+= dx;
+ v2d->cur.ymin-= dy;
+ v2d->cur.ymax+= dy;
+ test_view2d(G.v2d, curarea->winx, curarea->winy);
+ scrarea_queue_winredraw(curarea);
+ break;
+
+ case HOMEKEY:
+ if((G.qual==0))
+ do_oops_buttons(B_OOPSHOME);
+ break;
+
+ case PADPERIOD:
+ if((G.qual==0))
+ do_oops_buttons(B_OOPSVIEWSEL);
+ break;
+
+ case AKEY:
+ if((G.qual==0)) {
+ swap_select_all_oops();
+ scrarea_queue_winredraw(curarea);
+ }
+ break;
+ case BKEY:
+ if((G.qual==0))
+ borderselect_oops();
+ break;
+ case GKEY:
+ if((G.qual==0))
+ transform_oops('g', 0);
+ break;
+ case LKEY:
+ if((G.qual==LR_SHIFTKEY))
+ select_backlinked_oops();
+ else if((G.qual==0))
+ select_linked_oops();
+ break;
+ case SKEY:
+ if((G.qual==LR_ALTKEY)) {
+ if (okee("Shrink blocks")) {
+ shrink_oops();
+ }
+ } else if((G.qual==LR_SHIFTKEY)) {
+ if (okee("Shuffle blocks")) {
+ shuffle_oops();
+ }
+ } else if((G.qual==0)) {
+ transform_oops('s', 0);
+ }
+ break;
+ case PKEY:
+ if((G.qual==LR_CTRLKEY)) {
+ make_parent();
+ } else if((G.qual==LR_ALTKEY)) {
+ clear_parent();
+ }
+ break;
+
+
+ case ONEKEY:
+ do_layer_buttons(0); break;
+ case TWOKEY:
+ do_layer_buttons(1); break;
+ case THREEKEY:
+ do_layer_buttons(2); break;
+ case FOURKEY:
+ do_layer_buttons(3); break;
+ case FIVEKEY:
+ do_layer_buttons(4); break;
+ case SIXKEY:
+ do_layer_buttons(5); break;
+ case SEVENKEY:
+ do_layer_buttons(6); break;
+ case EIGHTKEY:
+ do_layer_buttons(7); break;
+ case NINEKEY:
+ do_layer_buttons(8); break;
+ case ZEROKEY:
+ do_layer_buttons(9); break;
+ case MINUSKEY:
+ do_layer_buttons(10); break;
+ case EQUALKEY:
+ do_layer_buttons(11); break;
+ case ACCENTGRAVEKEY:
+ do_layer_buttons(-1); break;
+
+ }
+ }
+}
+
+void init_v2d_oops(ScrArea *sa, SpaceOops *soops)
+{
+ View2D *v2d= &soops->v2d;
+
+ if(soops->type==SO_OUTLINER) {
+ /* outliner space is window size */
+ calc_scrollrcts(sa, v2d, sa->winx, sa->winy);
+
+ v2d->tot.xmax= (v2d->mask.xmax-v2d->mask.xmin);
+ v2d->tot.ymax= (v2d->mask.ymax-v2d->mask.ymin);
+ v2d->tot.xmin= 0.0;
+ v2d->tot.ymin= 0.0;
+
+ v2d->cur= v2d->tot;
+
+ v2d->min[0]= v2d->tot.xmin;
+ v2d->min[1]= v2d->tot.ymin;
+
+ v2d->max[0]= v2d->tot.xmax;
+ v2d->max[1]= v2d->tot.ymax;
+
+ v2d->minzoom= 1.0;
+ v2d->maxzoom= 1.0;
+
+ /* B_SCROLLO used here instead of B_SCROLL, to stop old blender's hanging on
+ * loading a file from a version with horizontal scrolling due to an old bug
+ */
+ v2d->scroll= L_SCROLL+B_SCROLLO;
+ v2d->keepaspect= 1;
+ v2d->keepzoom= 1;
+
+ /* NOTE: keeptot is 2, as keeptot!=0 makes sure it does get
+ * too freely scrolled on x-axis, but keeptot=1 will result
+ * in a snap-back when clicking on elements
+ */
+ v2d->keeptot= 2;
+ }
+ else {
+ v2d->tot.xmin= -28.0;
+ v2d->tot.xmax= 28.0;
+ v2d->tot.ymin= -28.0;
+ v2d->tot.ymax= 28.0;
+
+ v2d->cur= v2d->tot;
+
+ v2d->min[0]= 10.0;
+ v2d->min[1]= 4.0;
+
+ v2d->max[0]= 320.0;
+ v2d->max[1]= 320.0;
+
+ v2d->minzoom= 0.01f;
+ v2d->maxzoom= 2.0;
+
+ /* v2d->scroll= L_SCROLL+B_SCROLL; */
+ v2d->scroll= 0;
+ v2d->keepaspect= 1;
+ v2d->keepzoom= 0;
+ v2d->keeptot= 0;
+ }
+}
+
+static void init_oopsspace(ScrArea *sa)
+{
+ SpaceOops *soops;
+
+ soops= MEM_callocN(sizeof(SpaceOops), "initoopsspace");
+ BLI_addhead(&sa->spacedata, soops);
+
+ soops->visiflag= OOPS_OB+OOPS_MA+OOPS_ME+OOPS_TE+OOPS_CU+OOPS_IP;
+ /* new oops is default an outliner */
+ soops->type= SO_OUTLINER;
+
+ soops->spacetype= SPACE_OOPS;
+ soops->blockscale= 0.7;
+ init_v2d_oops(sa, soops);
+}
+
+/* ******************** SPACE: NLA ********************** */
+
+static void init_nlaspace(ScrArea *sa)
+{
+ SpaceNla *snla;
+
+ snla= MEM_callocN(sizeof(SpaceNla), "initnlaspace");
+ BLI_addhead(&sa->spacedata, snla);
+
+ snla->spacetype= SPACE_NLA;
+ snla->blockscale= 0.7;
+
+ snla->v2d.tot.xmin= 1.0;
+ snla->v2d.tot.ymin= 0.0;
+ snla->v2d.tot.xmax= 1000.0;
+ snla->v2d.tot.ymax= 1000.0;
+
+ snla->v2d.cur.xmin= -5.0;
+ snla->v2d.cur.ymin= 0.0;
+ snla->v2d.cur.xmax= 65.0;
+ snla->v2d.cur.ymax= 1000.0;
+
+ snla->v2d.min[0]= 0.0;
+ snla->v2d.min[1]= 0.0;
+
+ snla->v2d.max[0]= 1000.0;
+ snla->v2d.max[1]= 1000.0;
+
+ snla->v2d.minzoom= 0.1F;
+ snla->v2d.maxzoom= 50;
+
+ snla->v2d.scroll= R_SCROLL+B_SCROLL;
+ snla->v2d.keepaspect= 0;
+ snla->v2d.keepzoom= V2D_LOCKZOOM_Y;
+ snla->v2d.keeptot= 0;
+
+ snla->lock = 0;
+}
+
+
+
+/* ******************** SPACE: Text ********************** */
+
+extern void drawtextspace(ScrArea *sa, void *spacedata);
+extern void winqreadtextspace(struct ScrArea *sa, void *spacedata, struct BWinEvent *evt);
+
+static void init_textspace(ScrArea *sa)
+{
+ SpaceText *st;
+
+ st= MEM_callocN(sizeof(SpaceText), "inittextspace");
+ BLI_addhead(&sa->spacedata, st);
+
+ st->spacetype= SPACE_TEXT;
+ st->blockscale= 0.7;
+ st->text= NULL;
+ st->flags= 0;
+
+ st->font_id= 5;
+ st->lheight= 12;
+ st->showlinenrs= 0;
+ st->tabnumber = 4;
+ st->currtab_set = 0;
+
+ st->top= 0;
+}
+
+
+/* ******************** SPACE: Script ********************** */
+
+extern void drawscriptspace(ScrArea *sa, void *spacedata);
+extern void winqreadscriptspace(struct ScrArea *sa, void *spacedata, struct BWinEvent *evt);
+
+static void init_scriptspace(ScrArea *sa)
+{
+ SpaceScript *sc;
+
+ sc = MEM_callocN(sizeof(SpaceScript), "initscriptspace");
+ BLI_addhead(&sa->spacedata, sc);
+
+ sc->spacetype = SPACE_SCRIPT;
+ sc->blockscale= 0.7;
+ sc->script = NULL;
+ sc->flags = 0;
+}
+
+
+/* ******************** SPACE: Time ********************** */
+
+extern void drawtimespace(ScrArea *sa, void *spacedata);
+extern void winqreadtimespace(struct ScrArea *sa, void *spacedata, struct BWinEvent *evt);
+
+static void init_timespace(ScrArea *sa)
+{
+ SpaceTime *stime;
+
+ stime= MEM_callocN(sizeof(SpaceTime), "init timespace");
+ BLI_addhead(&sa->spacedata, stime);
+
+ stime->spacetype= SPACE_TIME;
+ stime->blockscale= 0.7;
+ stime->redraws= TIME_ALL_3D_WIN|TIME_ALL_ANIM_WIN;
+
+ stime->v2d.tot.xmin= -4.0;
+ stime->v2d.tot.ymin= 0.0;
+ stime->v2d.tot.xmax= (float)EFRA + 4.0;
+ stime->v2d.tot.ymax= (float)sa->winy;
+
+ stime->v2d.cur= stime->v2d.tot;
+
+ stime->v2d.min[0]= 1.0;
+ stime->v2d.min[1]= (float)sa->winy;
+
+ stime->v2d.max[0]= 32000.0;
+ stime->v2d.max[1]= (float)sa->winy;
+
+ stime->v2d.minzoom= 0.1f;
+ stime->v2d.maxzoom= 10.0;
+
+ stime->v2d.scroll= 0;
+ stime->v2d.keepaspect= 0;
+ stime->v2d.keepzoom= 0;
+ stime->v2d.keeptot= 0;
+
+ stime->flag |= TIME_DRAWFRAMES;
+
+}
+
+/* ******************** SPACE: Nodes ********************** */
+
+extern void drawnodespace(ScrArea *sa, void *spacedata);
+extern void winqreadnodespace(struct ScrArea *sa, void *spacedata, struct BWinEvent *evt);
+
+static void init_nodespace(ScrArea *sa)
+{
+ SpaceNode *snode;
+
+ snode= MEM_callocN(sizeof(SpaceNode), "init nodespace");
+ BLI_addhead(&sa->spacedata, snode);
+
+ snode->spacetype= SPACE_NODE;
+ snode->blockscale= 0.7;
+
+ snode->v2d.tot.xmin= -10.0;
+ snode->v2d.tot.ymin= -10.0;
+ snode->v2d.tot.xmax= (float)sa->winx + 10.0f;
+ snode->v2d.tot.ymax= (float)sa->winy + 10.0f;
+
+ snode->v2d.cur.xmin= 0.0;
+ snode->v2d.cur.ymin= 0.0;
+ snode->v2d.cur.xmax= (float)sa->winx;
+ snode->v2d.cur.ymax= (float)sa->winy;
+
+ snode->v2d.min[0]= 1.0;
+ snode->v2d.min[1]= 1.0;
+
+ snode->v2d.max[0]= 32000.0f;
+ snode->v2d.max[1]= 32000.0f;
+
+ snode->v2d.minzoom= 0.5f;
+ snode->v2d.maxzoom= 1.21f;
+
+ snode->v2d.scroll= 0;
+ snode->v2d.keepaspect= 1;
+ snode->v2d.keepzoom= 1;
+ snode->v2d.keeptot= 0;
+}
+
+
+
+/* ******************** SPACE: GENERAL ********************** */
+
+void newspace(ScrArea *sa, int type)
+{
+ int xtra= type & 256; /* hack to enforce outliner with hotkey from toets.c */
+
+ type &= ~256;
+
+ if(type>=0) {
+ if(sa->spacetype != type) {
+ SpaceLink *sl;
+
+ sa->spacetype= type;
+ sa->headbutofs= 0;
+
+ uiFreeBlocks(&sa->uiblocks);
+ wich_cursor(sa);
+
+ if (sa->headwin) addqueue(sa->headwin, CHANGED, 1);
+ scrarea_queue_headredraw(sa);
+
+ addqueue(sa->win, CHANGED, 1);
+ scrarea_queue_winredraw(sa);
+
+ for (sl= sa->spacedata.first; sl; sl= sl->next)
+ if(sl->spacetype==type)
+ break;
+
+ if (sl) {
+ BLI_remlink(&sa->spacedata, sl);
+ BLI_addhead(&sa->spacedata, sl);
+ } else {
+ if(type==SPACE_VIEW3D)
+ initview3d(sa);
+ else if(type==SPACE_IPO)
+ initipo(sa);
+ else if(type==SPACE_INFO)
+ init_infospace(sa);
+ else if(type==SPACE_BUTS)
+ init_butspace(sa);
+ else if(type==SPACE_FILE)
+ init_filespace(sa);
+ else if(type==SPACE_SEQ)
+ init_seqspace(sa);
+ else if(type==SPACE_IMAGE)
+ init_imagespace(sa);
+ else if(type==SPACE_IMASEL)
+ init_imaselspace(sa);
+ else if(type==SPACE_OOPS)
+ init_oopsspace(sa);
+ else if(type==SPACE_ACTION)
+ init_actionspace(sa);
+ else if(type==SPACE_TEXT)
+ init_textspace(sa);
+ else if(type==SPACE_SCRIPT)
+ init_scriptspace(sa);
+ else if(type==SPACE_SOUND)
+ init_soundspace(sa);
+ else if(type==SPACE_NLA)
+ init_nlaspace(sa);
+ else if(type==SPACE_TIME)
+ init_timespace(sa);
+ else if(type==SPACE_NODE)
+ init_nodespace(sa);
+
+ sl= sa->spacedata.first;
+ sl->area= sa;
+ }
+
+ areawinset(sa->win);
+ bwin_clear_viewmat(sa->win);
+ }
+ }
+
+
+ /* exception: filespace */
+ if(sa->spacetype==SPACE_FILE) {
+ SpaceFile *sfile= sa->spacedata.first;
+
+ if(sfile->type==FILE_MAIN) {
+ freefilelist(sfile);
+ } else {
+ sfile->type= FILE_UNIX;
+ }
+
+ sfile->returnfunc= NULL;
+ sfile->title[0]= 0;
+ if(sfile->filelist) test_flags_file(sfile);
+ }
+ /* exception: imasel space */
+ else if(sa->spacetype==SPACE_IMASEL) {
+ SpaceImaSel *simasel= sa->spacedata.first;
+ if(simasel->type==FILE_MAIN) {
+ if (simasel->files) {
+ BIF_filelist_free(simasel->files);
+ BIF_filelist_settype(simasel->files, FILE_MAIN);
+ }
+ } else {
+ if (simasel->files) {
+ simasel->type= FILE_UNIX;
+ BIF_filelist_settype(simasel->files, simasel->type);
+ }
+ }
+ simasel->returnfunc= NULL;
+ simasel->title[0]= 0;
+ }
+ else if(sa->spacetype==SPACE_OOPS) {
+ SpaceOops *so= sa->spacedata.first;
+ if(xtra && so->type!=SO_OUTLINER) {
+ so->type= SO_OUTLINER;
+ init_v2d_oops(sa, so);
+ scrarea_queue_winredraw(sa);
+ scrarea_queue_headredraw(sa);
+ }
+ }
+}
+
+void freespacelist(ScrArea *sa)
+{
+ SpaceLink *sl;
+
+ for (sl= sa->spacedata.first; sl; sl= sl->next) {
+ if(sl->spacetype==SPACE_FILE) {
+ SpaceFile *sfile= (SpaceFile*) sl;
+ if(sfile->libfiledata)
+ BLO_blendhandle_close(sfile->libfiledata);
+ if(sfile->filelist)
+ freefilelist(sfile);
+ if(sfile->pupmenu)
+ MEM_freeN(sfile->pupmenu);
+ }
+ else if(sl->spacetype==SPACE_BUTS) {
+ SpaceButs *buts= (SpaceButs*) sl;
+ if(buts->ri) {
+ if (buts->ri->rect) MEM_freeN(buts->ri->rect);
+ MEM_freeN(buts->ri);
+ }
+ if(G.buts==buts) G.buts= NULL;
+ }
+ else if(sl->spacetype==SPACE_IPO) {
+ SpaceIpo *si= (SpaceIpo*) sl;
+ if(si->editipo) MEM_freeN(si->editipo);
+ free_ipokey(&si->ipokey);
+ if(G.sipo==si) G.sipo= NULL;
+ }
+ else if(sl->spacetype==SPACE_VIEW3D) {
+ View3D *vd= (View3D*) sl;
+ if(vd->bgpic) {
+ if(vd->bgpic->ima) vd->bgpic->ima->id.us--;
+ MEM_freeN(vd->bgpic);
+ }
+ if(vd->localvd) MEM_freeN(vd->localvd);
+ if(vd->clipbb) MEM_freeN(vd->clipbb);
+ if(vd->depths) {
+ if(vd->depths->depths) MEM_freeN(vd->depths->depths);
+ MEM_freeN(vd->depths);
+ vd->depths= NULL;
+ }
+ retopo_free_view_data(vd);
+ if(vd->properties_storage) MEM_freeN(vd->properties_storage);
+ if(G.vd==vd) G.vd= NULL;
+ if(vd->ri) {
+ BIF_view3d_previewrender_free(vd);
+ }
+ }
+ else if(sl->spacetype==SPACE_OOPS) {
+ SpaceOops *so= (SpaceOops *) sl;
+ free_oopspace(so);
+ }
+ else if(sl->spacetype==SPACE_IMASEL) {
+ SpaceImaSel *simasel= (SpaceImaSel*) sl;
+ free_imasel(simasel);
+ }
+ else if(sl->spacetype==SPACE_ACTION) {
+ free_actionspace((SpaceAction*)sl);
+ }
+ else if(sl->spacetype==SPACE_NLA){
+/* free_nlaspace((SpaceNla*)sl); */
+ }
+ else if(sl->spacetype==SPACE_TEXT) {
+ free_textspace((SpaceText *)sl);
+ }
+ else if(sl->spacetype==SPACE_SCRIPT) {
+ free_scriptspace((SpaceScript *)sl);
+ }
+ else if(sl->spacetype==SPACE_SOUND) {
+ free_soundspace((SpaceSound *)sl);
+ }
+ else if(sl->spacetype==SPACE_IMAGE) {
+ SpaceImage *sima= (SpaceImage *)sl;
+ if(sima->cumap)
+ curvemapping_free(sima->cumap);
+ if(sima->info_str)
+ MEM_freeN(sima->info_str);
+ if(sima->info_spare)
+ MEM_freeN(sima->info_spare);
+ if(sima->spare)
+ IMB_freeImBuf(sima->spare);
+ }
+ else if(sl->spacetype==SPACE_NODE) {
+/* SpaceNode *snode= (SpaceNode *)sl; */
+ }
+ }
+
+ BLI_freelistN(&sa->spacedata);
+}
+
+/* can be called for area-full, so it should keep interesting stuff */
+void duplicatespacelist(ScrArea *newarea, ListBase *lb1, ListBase *lb2)
+{
+ SpaceLink *sl;
+
+ duplicatelist(lb1, lb2);
+
+ /* lb1 is copy from lb2, from lb2 we free stuff, rely on event system to properly re-alloc */
+
+ sl= lb2->first;
+ while(sl) {
+ if(sl->spacetype==SPACE_FILE) {
+ SpaceFile *sfile= (SpaceFile*) sl;
+ sfile->libfiledata= NULL;
+ sfile->filelist= NULL;
+ sfile->pupmenu= NULL;
+ sfile->menup= NULL;
+ }
+ else if(sl->spacetype==SPACE_VIEW3D) {
+ View3D *v3d= (View3D*)sl;
+ BIF_view3d_previewrender_free(v3d);
+ v3d->depths= NULL;
+ v3d->retopo_view_data= NULL;
+ }
+ else if(sl->spacetype==SPACE_OOPS) {
+ SpaceOops *so= (SpaceOops *)sl;
+ so->oops.first= so->oops.last= NULL;
+ so->tree.first= so->tree.last= NULL;
+ so->treestore= NULL;
+ }
+ else if(sl->spacetype==SPACE_IMASEL) {
+ SpaceImaSel *simasel= (SpaceImaSel*) sl;
+ simasel->pupmenu= NULL;
+ simasel->menup= NULL;
+ simasel->files = BIF_filelist_new();
+ BIF_filelist_setdir(simasel->files, simasel->dir);
+ BIF_filelist_settype(simasel->files, simasel->type);
+ /* see SPACE_FILE - elubie */
+ }
+ else if(sl->spacetype==SPACE_NODE) {
+ SpaceNode *snode= (SpaceNode *)sl;
+ snode->nodetree= NULL;
+ }
+
+ sl= sl->next;
+ }
+
+ /* but some things we copy */
+
+ sl= lb1->first;
+ while(sl) {
+ sl->area= newarea;
+
+ if(sl->spacetype==SPACE_BUTS) {
+ SpaceButs *buts= (SpaceButs *)sl;
+ buts->ri= NULL;
+ }
+ else if(sl->spacetype==SPACE_FILE) {
+ SpaceFile *sfile= (SpaceFile*) sl;
+ sfile->menup= NULL;
+ }
+ else if(sl->spacetype==SPACE_IPO) {
+ SpaceIpo *si= (SpaceIpo *)sl;
+ si->editipo= NULL;
+ si->ipokey.first= si->ipokey.last= NULL;
+ }
+ else if(sl->spacetype==SPACE_VIEW3D) {
+ View3D *vd= (View3D *)sl;
+ if(vd->bgpic) {
+ vd->bgpic= MEM_dupallocN(vd->bgpic);
+ if(vd->bgpic->ima) vd->bgpic->ima->id.us++;
+ }
+ vd->clipbb= MEM_dupallocN(vd->clipbb);
+ vd->ri= NULL;
+ vd->properties_storage= NULL;
+ }
+ else if(sl->spacetype==SPACE_IMAGE) {
+ SpaceImage *sima= (SpaceImage *)sl;
+ if(sima->cumap)
+ sima->cumap= curvemapping_copy(sima->cumap);
+ if(sima->info_str)
+ sima->info_str= MEM_dupallocN(sima->info_str);
+ if(sima->info_spare)
+ sima->info_spare= MEM_dupallocN(sima->info_spare);
+ }
+ sl= sl->next;
+ }
+
+ /* again: from old View3D restore localview (because full) */
+ sl= lb2->first;
+ while(sl) {
+ if(sl->spacetype==SPACE_VIEW3D) {
+ View3D *v3d= (View3D*) sl;
+ if(v3d->localvd) {
+ restore_localviewdata(v3d);
+ v3d->localvd= NULL;
+ v3d->properties_storage= NULL;
+ v3d->localview= 0;
+ v3d->lay &= 0xFFFFFF;
+ }
+ }
+ sl= sl->next;
+ }
+}
+
+/* is called everywhere in blender */
+void allqueue(unsigned short event, short val)
+{
+ ScrArea *sa;
+ View3D *v3d;
+ SpaceButs *buts;
+ SpaceFile *sfile;
+
+ sa= G.curscreen->areabase.first;
+ while(sa) {
+
+ if(event==REDRAWALL) {
+ scrarea_queue_winredraw(sa);
+ scrarea_queue_headredraw(sa);
+ }
+ else if(sa->win != val) {
+ switch(event) {
+
+ case REDRAWHEADERS:
+ scrarea_queue_headredraw(sa);
+ break;
+ case REDRAWVIEW3D:
+ if(sa->spacetype==SPACE_VIEW3D) {
+ scrarea_queue_winredraw(sa);
+ if(val) scrarea_queue_headredraw(sa);
+ }
+ break;
+ case REDRAWVIEW3D_Z:
+ if(sa->spacetype==SPACE_VIEW3D) {
+ v3d= sa->spacedata.first;
+ if(v3d->drawtype==OB_SOLID) {
+ scrarea_queue_winredraw(sa);
+ if(val) scrarea_queue_headredraw(sa);
+ }
+ }
+ break;
+ case REDRAWVIEW3D_IMAGE:
+ if(sa->spacetype==SPACE_VIEW3D || sa->spacetype==SPACE_IMAGE) {
+ scrarea_queue_winredraw(sa);
+ if(val) scrarea_queue_headredraw(sa);
+ }
+ break;
+ case REDRAWVIEWCAM:
+ if(sa->spacetype==SPACE_VIEW3D) {
+ v3d= sa->spacedata.first;
+ if(v3d->persp>1) scrarea_queue_winredraw(sa);
+ }
+ break;
+ case REDRAWINFO:
+ if(sa->spacetype==SPACE_INFO) {
+ scrarea_queue_winredraw(sa);
+ scrarea_queue_headredraw(sa);
+ }
+ break;
+ case REDRAWIMAGE:
+ if(sa->spacetype==SPACE_IMAGE) {
+ scrarea_queue_winredraw(sa);
+ scrarea_queue_headredraw(sa);
+ }
+ break;
+ case REDRAWIPO:
+ if(sa->spacetype==SPACE_IPO) {
+ SpaceIpo *si;
+ scrarea_queue_winredraw(sa);
+ scrarea_queue_headredraw(sa);
+ if(val) {
+ si= sa->spacedata.first;
+ if (si->pin==0)
+ si->blocktype= val;
+ }
+ }
+ else if(sa->spacetype==SPACE_OOPS) {
+ scrarea_queue_winredraw(sa);
+ }
+
+ break;
+
+ case REDRAWBUTSALL:
+ if(sa->spacetype==SPACE_BUTS) {
+ buts= sa->spacedata.first;
+ buts->re_align= 1;
+ scrarea_queue_winredraw(sa);
+ scrarea_queue_headredraw(sa);
+ }
+ break;
+ case REDRAWBUTSHEAD:
+ if(sa->spacetype==SPACE_BUTS) {
+ scrarea_queue_headredraw(sa);
+ }
+ break;
+ case REDRAWBUTSSCENE:
+ if(sa->spacetype==SPACE_BUTS) {
+ buts= sa->spacedata.first;
+ if(buts->mainb==CONTEXT_SCENE) {
+ buts->re_align= 1;
+ scrarea_queue_winredraw(sa);
+ scrarea_queue_headredraw(sa);
+ }
+ }
+ break;
+ case REDRAWBUTSOBJECT:
+ if(sa->spacetype==SPACE_BUTS) {
+ buts= sa->spacedata.first;
+ if(buts->mainb==CONTEXT_OBJECT) {
+ buts->re_align= 1;
+ scrarea_queue_winredraw(sa);
+ scrarea_queue_headredraw(sa);
+ }
+ }
+ break;
+ case REDRAWBUTSSHADING:
+ if(sa->spacetype==SPACE_BUTS) {
+ buts= sa->spacedata.first;
+ if(buts->mainb==CONTEXT_SHADING) {
+ buts->re_align= 1;
+ scrarea_queue_winredraw(sa);
+ scrarea_queue_headredraw(sa);
+ }
+ }
+ break;
+ case REDRAWBUTSEDIT:
+ if(sa->spacetype==SPACE_BUTS) {
+ buts= sa->spacedata.first;
+ if(buts->mainb==CONTEXT_EDITING) {
+ buts->re_align= 1;
+ scrarea_queue_winredraw(sa);
+ scrarea_queue_headredraw(sa);
+ }
+ }
+ break;
+ case REDRAWBUTSSCRIPT:
+ if(sa->spacetype==SPACE_BUTS) {
+ buts= sa->spacedata.first;
+ if(buts->mainb==CONTEXT_SCRIPT) {
+ buts->re_align= 1;
+ scrarea_queue_winredraw(sa);
+ scrarea_queue_headredraw(sa);
+ }
+ }
+ break;
+ case REDRAWBUTSLOGIC:
+ if(sa->spacetype==SPACE_BUTS) {
+ buts= sa->spacedata.first;
+ if(buts->mainb==CONTEXT_LOGIC) {
+ scrarea_queue_winredraw(sa);
+ scrarea_queue_headredraw(sa);
+ }
+ }
+ break;
+
+ case REDRAWDATASELECT:
+ if(sa->spacetype==SPACE_FILE) {
+ sfile= sa->spacedata.first;
+ if(sfile->type==FILE_MAIN) {
+ freefilelist(sfile);
+ scrarea_queue_winredraw(sa);
+ }
+ }
+ else if(sa->spacetype==SPACE_OOPS) {
+ scrarea_queue_winredraw(sa);
+ }
+ break;
+ case REDRAWSEQ:
+ if(sa->spacetype==SPACE_SEQ) {
+ addqueue(sa->win, CHANGED, 1);
+ scrarea_queue_winredraw(sa);
+ scrarea_queue_headredraw(sa);
+ }
+ break;
+ case REDRAWOOPS:
+ if(sa->spacetype==SPACE_OOPS) {
+ scrarea_queue_winredraw(sa);
+ }
+ break;
+ case REDRAWNLA:
+ if(sa->spacetype==SPACE_NLA) {
+ scrarea_queue_headredraw(sa);
+ scrarea_queue_winredraw(sa);
+ }
+ case REDRAWACTION:
+ if(sa->spacetype==SPACE_ACTION) {
+ scrarea_queue_headredraw(sa);
+ scrarea_queue_winredraw(sa);
+ }
+ break;
+ case REDRAWTEXT:
+ if(sa->spacetype==SPACE_TEXT) {
+ scrarea_queue_winredraw(sa);
+ }
+ break;
+ case REDRAWSCRIPT:
+ if (sa->spacetype==SPACE_SCRIPT) {
+ scrarea_queue_winredraw(sa);
+ }
+ break;
+ case REDRAWSOUND:
+ if(sa->spacetype==SPACE_SOUND) {
+ scrarea_queue_headredraw(sa);
+ scrarea_queue_winredraw(sa);
+ }
+ break;
+ case REDRAWTIME:
+ if(sa->spacetype==SPACE_TIME) {
+ scrarea_queue_headredraw(sa);
+ scrarea_queue_winredraw(sa);
+ }
+ break;
+ case REDRAWNODE:
+ if(sa->spacetype==SPACE_NODE) {
+ scrarea_queue_headredraw(sa);
+ scrarea_queue_winredraw(sa);
+ }
+ break;
+ case RECALC_COMPOSITE:
+ if(sa->spacetype==SPACE_NODE) {
+ addqueue(sa->win, UI_BUT_EVENT, B_NODE_TREE_EXEC);
+ }
+ break;
+ case REDRAWANIM:
+ if ELEM6(sa->spacetype, SPACE_IPO, SPACE_SOUND, SPACE_TIME, SPACE_NLA, SPACE_ACTION, SPACE_SEQ) {
+ scrarea_queue_winredraw(sa);
+ if(val) scrarea_queue_headredraw(sa);
+ }
+ case REDRAWMARKER: /* markers may not always match animation */
+ if ELEM6(sa->spacetype, SPACE_TIME, SPACE_IPO, SPACE_ACTION, SPACE_NLA, SPACE_SOUND, SPACE_SEQ) {
+ scrarea_queue_winredraw(sa);
+ if(val) scrarea_queue_headredraw(sa);
+ }
+ }
+ }
+ sa= sa->next;
+ }
+}
+
+void allspace(unsigned short event, short val)
+{
+ bScreen *sc;
+
+ sc= G.main->screen.first;
+ while(sc) {
+ ScrArea *sa= sc->areabase.first;
+ while(sa) {
+ SpaceLink *sl= sa->spacedata.first;
+ while(sl) {
+ switch(event) {
+ case REMAKEIPO:
+ if(sl->spacetype==SPACE_IPO) {
+ SpaceIpo *si= (SpaceIpo *)sl;
+ {
+ if(si->editipo) MEM_freeN(si->editipo);
+ si->editipo= 0;
+ free_ipokey(&si->ipokey);
+ }
+ }
+ break;
+
+ case OOPS_TEST:
+ if(sl->spacetype==SPACE_OOPS) {
+ SpaceOops *so= (SpaceOops *)sl;
+ so->flag |= SO_TESTBLOCKS;
+ }
+ break;
+ }
+
+ sl= sl->next;
+ }
+ sa= sa->next;
+ }
+ sc= sc->id.next;
+ }
+}
+
+/* if header==1, then draw header for curarea too. Excepption for headerprint()... */
+void force_draw(int header)
+{
+ /* draws all areas that show something identical to curarea */
+ extern int afterqtest(short win, unsigned short evt); /*editscreen.c*/
+ ScrArea *tempsa, *sa;
+
+ scrarea_do_windraw(curarea);
+ if(header) scrarea_do_headdraw(curarea);
+
+ tempsa= curarea;
+ sa= G.curscreen->areabase.first;
+ while(sa) {
+ if(sa!=tempsa && sa->spacetype==tempsa->spacetype) {
+ areawinset(sa->win);
+ scrarea_do_windraw(sa);
+ scrarea_do_headdraw(sa);
+ }
+ sa= sa->next;
+ }
+
+ screen_swapbuffers();
+
+#ifndef __APPLE__
+ if(tempsa->spacetype==SPACE_VIEW3D) {
+ /* de the afterqueuetest for backbuf draw */
+ sa= G.curscreen->areabase.first;
+ while(sa) {
+ if(sa->spacetype==SPACE_VIEW3D) {
+ if(afterqtest(sa->win, BACKBUFDRAW)) {
+ areawinset(sa->win);
+ backdrawview3d(0);
+ }
+ }
+ sa= sa->next;
+ }
+ }
+#endif
+ if(curarea!=tempsa) areawinset(tempsa->win);
+
+}
+
+/* if header==1, then draw header for curarea too. Exception for headerprint()... */
+void force_draw_plus(int type, int header)
+{
+ /* draws all areas that show something like curarea AND areas of 'type' */
+ ScrArea *tempsa, *sa;
+
+ scrarea_do_windraw(curarea);
+ if(header) scrarea_do_headdraw(curarea);
+
+ tempsa= curarea;
+ sa= G.curscreen->areabase.first;
+ while(sa) {
+ if(sa!=tempsa && (sa->spacetype==tempsa->spacetype || sa->spacetype==type)) {
+ if(ELEM5(sa->spacetype, SPACE_VIEW3D, SPACE_IPO, SPACE_SEQ, SPACE_BUTS, SPACE_ACTION)) {
+ areawinset(sa->win);
+ scrarea_do_windraw(sa);
+ scrarea_do_headdraw(sa);
+ }
+ }
+ sa= sa->next;
+ }
+ if(curarea!=tempsa) areawinset(tempsa->win);
+
+ screen_swapbuffers();
+}
+
+/* if header==1, then draw header for curarea too. Excepption for headerprint()... */
+void force_draw_all(int header)
+{
+ /* redraws all */
+ ScrArea *tempsa, *sa;
+
+ tempsa= curarea;
+ sa= G.curscreen->areabase.first;
+ while(sa) {
+ if(sa->headwin) {
+ scrarea_do_headdraw(sa);
+ if(sa!=curarea || header) scrarea_do_headchange(sa);
+ }
+ if(sa->win) {
+ scrarea_do_windraw(sa);
+ }
+ sa= sa->next;
+ }
+ if(curarea!=tempsa) areawinset(tempsa->win);
+
+ screen_swapbuffers();
+}
+
+/***/
+
+SpaceType *spaceaction_get_type(void)
+{
+ static SpaceType *st= NULL;
+
+ if (!st) {
+ st= spacetype_new("Action");
+ spacetype_set_winfuncs(st, NULL, drawactionspace, changeactionspace, winqreadactionspace);
+ }
+
+ return st;
+}
+SpaceType *spacebuts_get_type(void)
+{
+ static SpaceType *st= NULL;
+
+ if (!st) {
+ st= spacetype_new("Buts");
+ spacetype_set_winfuncs(st, NULL, drawbutspace, changebutspace, winqreadbutspace);
+ }
+
+ return st;
+}
+SpaceType *spacefile_get_type(void)
+{
+ static SpaceType *st= NULL;
+
+ if (!st) {
+ st= spacetype_new("File");
+ spacetype_set_winfuncs(st, NULL, drawfilespace, NULL, winqreadfilespace);
+ }
+
+ return st;
+}
+SpaceType *spaceimage_get_type(void)
+{
+ static SpaceType *st= NULL;
+
+ if (!st) {
+ st= spacetype_new("Image");
+ spacetype_set_winfuncs(st, NULL, drawimagespace, changeimagepace, winqreadimagespace);
+ }
+
+ return st;
+}
+SpaceType *spaceimasel_get_type(void)
+{
+ static SpaceType *st= NULL;
+
+ if (!st) {
+ st= spacetype_new("Imasel");
+ spacetype_set_winfuncs(st, NULL, drawimaselspace, changeimaselspace, winqreadimaselspace);
+ }
+
+ return st;
+}
+SpaceType *spaceinfo_get_type(void)
+{
+ static SpaceType *st= NULL;
+
+ if (!st) {
+ st= spacetype_new("Info");
+ spacetype_set_winfuncs(st, NULL, drawinfospace, NULL, winqreadinfospace);
+ }
+
+ return st;
+}
+SpaceType *spaceipo_get_type(void)
+{
+ static SpaceType *st= NULL;
+
+ if (!st) {
+ st= spacetype_new("Ipo");
+ spacetype_set_winfuncs(st, NULL, drawipospace, changeview2dspace, winqreadipospace);
+ }
+
+ return st;
+}
+SpaceType *spacenla_get_type(void)
+{
+ static SpaceType *st= NULL;
+
+ if (!st) {
+ st= spacetype_new("Nla");
+ spacetype_set_winfuncs(st, NULL, drawnlaspace, changeview2dspace, winqreadnlaspace);
+ }
+
+ return st;
+}
+SpaceType *spaceoops_get_type(void)
+{
+ static SpaceType *st= NULL;
+
+ if (!st) {
+ st= spacetype_new("Oops");
+ spacetype_set_winfuncs(st, NULL, drawoopsspace, changeview2dspace, winqreadoopsspace);
+ }
+
+ return st;
+}
+SpaceType *spaceseq_get_type(void)
+{
+ static SpaceType *st= NULL;
+
+ if (!st) {
+ st= spacetype_new("Sequence");
+ spacetype_set_winfuncs(st, drawprefetchseqspace, drawseqspace, changeview2dspace, winqreadseqspace);
+ }
+
+ return st;
+}
+SpaceType *spacesound_get_type(void)
+{
+ static SpaceType *st= NULL;
+
+ if (!st) {
+ st= spacetype_new("Sound");
+ spacetype_set_winfuncs(st, NULL, drawsoundspace, changeview2dspace, winqreadsoundspace);
+ }
+
+ return st;
+}
+SpaceType *spacetext_get_type(void)
+{
+ static SpaceType *st= NULL;
+
+ if (!st) {
+ st= spacetype_new("Text");
+ spacetype_set_winfuncs(st, NULL, drawtextspace, NULL, winqreadtextspace);
+ }
+
+ return st;
+}
+
+static void spacescript_change(ScrArea *sa, void *spacedata)
+{
+ SpaceScript *sc = (SpaceScript*) spacedata;
+
+ /*clear all temp button references*/
+ if (sc->but_refs) {
+ BPy_Set_DrawButtonsList(sc->but_refs);
+ BPy_Free_DrawButtonsList();
+ sc->but_refs = NULL;
+ }
+}
+
+SpaceType *spacescript_get_type(void)
+{
+ static SpaceType *st = NULL;
+
+ if (!st) {
+ st = spacetype_new("Script");
+ spacetype_set_winfuncs(st, NULL, drawscriptspace, spacescript_change, winqreadscriptspace);
+ }
+
+ return st;
+}
+SpaceType *spaceview3d_get_type(void)
+{
+ static SpaceType *st= NULL;
+
+ if (!st) {
+ st= spacetype_new("View3D");
+ spacetype_set_winfuncs(st, NULL, drawview3dspace, changeview3dspace, winqreadview3dspace);
+ }
+
+ return st;
+}
+SpaceType *spacetime_get_type(void)
+{
+ static SpaceType *st= NULL;
+
+ if (!st) {
+ st= spacetype_new("Time");
+ spacetype_set_winfuncs(st, NULL, drawtimespace, NULL, winqreadtimespace);
+ }
+
+ return st;
+}
+
+SpaceType *spacenode_get_type(void)
+{
+ static SpaceType *st= NULL;
+
+ if (!st) {
+ st= spacetype_new("Node");
+ spacetype_set_winfuncs(st, NULL, drawnodespace, changeview2dspace, winqreadnodespace);
+ }
+
+ return st;
+}
diff --git a/source/blender/src/spacetypes.c b/source/blender/src/spacetypes.c
new file mode 100644
index 00000000000..4a0375f2366
--- /dev/null
+++ b/source/blender/src/spacetypes.c
@@ -0,0 +1,161 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "BLI_blenlib.h"
+
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "BIF_gl.h"
+#include "BIF_mywindow.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_spacetypes.h"
+
+/***/
+
+struct _SpaceType {
+ char name[32];
+
+ SpacePrefetchDrawFP winprefetchdraw;
+ SpaceDrawFP windraw;
+ SpaceChangeFP winchange;
+ SpaceHandleFP winhandle;
+};
+
+/* local prototypes ----------------------- */
+void scrarea_do_windraw(ScrArea *area);
+void scrarea_do_winchange(ScrArea *area);
+void scrarea_do_winhandle(ScrArea *area, BWinEvent *evt);
+
+SpaceType *spacetype_new(char *name)
+{
+ SpaceType *st= calloc(1, sizeof(*st));
+ BLI_strncpy(st->name, name, sizeof(st->name));
+
+ return st;
+}
+
+void spacetype_set_winfuncs(SpaceType *st, SpacePrefetchDrawFP prefetchdraw, SpaceDrawFP draw, SpaceChangeFP change, SpaceHandleFP handle)
+{
+ st->winprefetchdraw = prefetchdraw;
+ st->windraw= draw;
+ st->winchange= change;
+ st->winhandle= handle;
+}
+
+ /* gets SpaceType struct, but also has patch to initialize unknown spacetypes */
+
+static SpaceType *spacetype_from_area(ScrArea *area)
+{
+ switch (area->spacetype) {
+ case SPACE_ACTION: return spaceaction_get_type();
+ case SPACE_BUTS: return spacebuts_get_type();
+ case SPACE_FILE: return spacefile_get_type();
+ case SPACE_IMAGE: return spaceimage_get_type();
+ case SPACE_IMASEL: return spaceimasel_get_type();
+ case SPACE_INFO: return spaceinfo_get_type();
+ case SPACE_IPO: return spaceipo_get_type();
+ case SPACE_NLA: return spacenla_get_type();
+ case SPACE_OOPS: return spaceoops_get_type();
+ case SPACE_SEQ: return spaceseq_get_type();
+ case SPACE_SOUND: return spacesound_get_type();
+ case SPACE_TEXT: return spacetext_get_type();
+ case SPACE_SCRIPT: return spacescript_get_type();
+ case SPACE_VIEW3D: return spaceview3d_get_type();
+ case SPACE_TIME: return spacetime_get_type();
+ case SPACE_NODE: return spacenode_get_type();
+ default:
+ newspace(area, SPACE_VIEW3D);
+ return spaceview3d_get_type();
+ return NULL;
+ }
+}
+
+void scrarea_do_winprefetchdraw(ScrArea *area)
+{
+ SpaceType *st= spacetype_from_area(area);
+
+ areawinset(area->win);
+
+ if(area->win && st->winprefetchdraw) {
+ st->winprefetchdraw(area, area->spacedata.first);
+ }
+}
+
+void scrarea_do_windraw(ScrArea *area)
+{
+ SpaceType *st= spacetype_from_area(area);
+
+ areawinset(area->win);
+
+ if(area->win && st->windraw) {
+ st->windraw(area, area->spacedata.first);
+ }
+ else {
+ glClearColor(0.4375, 0.4375, 0.4375, 0.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ }
+
+ area->win_swap= WIN_BACK_OK;
+}
+void scrarea_do_winchange(ScrArea *area)
+{
+ SpaceType *st= spacetype_from_area(area);
+
+ areawinset(area->win);
+
+ if (st->winchange) {
+ st->winchange(area, area->spacedata.first);
+ } else {
+ if (!BLI_rcti_is_empty(&area->winrct)) {
+ bwin_ortho2(area->win, -0.375, area->winrct.xmax-area->winrct.xmin-0.375, -0.375, area->winrct.ymax-area->winrct.ymin-0.375);
+ glLoadIdentity();
+ }
+ }
+}
+void scrarea_do_winhandle(ScrArea *area, BWinEvent *evt)
+{
+ SpaceType *st= spacetype_from_area(area);
+
+ areawinset(area->win);
+
+ if (st->winhandle) {
+ st->winhandle(area, area->spacedata.first, evt);
+ }
+}
diff --git a/source/blender/src/splash.jpg.c b/source/blender/src/splash.jpg.c
new file mode 100644
index 00000000000..c1ca8b575e6
--- /dev/null
+++ b/source/blender/src/splash.jpg.c
@@ -0,0 +1,2483 @@
+/* DataToC output of file <splash_jpg> */
+
+int datatoc_splash_jpg_size= 79258;
+char datatoc_splash_jpg[]= {
+255,216,255,224, 0, 16, 74, 70, 73, 70, 0, 1, 1, 1, 0, 72, 0, 72, 0, 0,255,225, 0, 22, 69,120,
+105,102, 0, 0, 77, 77, 0, 42, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0,255,219, 0, 67, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 2,
+ 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,255,219, 0, 67, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,255,192, 0, 17,
+ 8, 1, 15, 1,245, 3, 1, 34, 0, 2, 17, 1, 3, 17, 1,255,196, 0, 31, 0, 0, 1, 3, 5, 1, 1, 1, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 4, 0, 7, 10, 3, 5, 6, 8, 9, 2, 1, 11,255,196, 0,103, 16, 0, 1, 3, 3, 2, 4, 3, 4, 6, 4, 7,
+ 11, 5, 9, 13, 9, 1, 2, 3, 4, 5, 6, 17, 0, 7, 8, 18, 33, 49, 19, 65, 81, 9, 20, 34, 97, 10, 21,113,129,145,240, 35,
+ 50,161,193, 22, 23, 24, 66,177,209,225, 25, 26, 36, 40, 51, 56, 73, 82, 98,232,241, 72,104,105,136,168, 41, 52, 57, 67, 84, 88,
+120,150,178, 37, 38, 68, 83, 87,115,130,135,147,152,181,200,210, 54, 89, 99,114,146,184,213,214,215,255,196, 0, 29, 1, 0, 0,
+ 6, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 5, 6, 7, 1, 4, 8, 9,255,196, 0, 80, 17, 0, 2, 1,
+ 2, 4, 4, 3, 4, 6, 7, 5, 7, 0, 7, 9, 0, 1, 2, 3, 4, 17, 0, 5, 18, 33, 6, 19, 49, 65, 7, 34, 81, 20, 97,113,
+240, 8, 35, 50,129,161,209, 21, 66, 82,145,177,193,210, 36, 51, 98,162,225, 9, 67, 83, 84,114,130,241, 52, 56, 68, 85,116,148,
+211, 22, 23, 24,115,131,146,147,180,181,255,218, 0, 12, 3, 1, 0, 2, 17, 3, 17, 0, 63, 0,159,198,150,150,150,134, 6, 22,
+150,150,190,100,122,143,199, 67, 3, 31,116,203,220, 60, 68,108,181,171,123, 70,219,170,254,224,209, 41,183,140,167, 25,101, 20,
+135,189,241, 73,101,249, 28,165,136,243,170, 77, 69, 84, 74,116,149,133,163,149,185, 15,180,226,185,211,132,158, 97,151,159, 35,
+212,126, 35, 92,108,227, 63,131, 43,145, 85,251,143,120, 54,213, 18,235,236, 86, 37,191, 87,185,237,148,243, 72,170, 67,146,224,
+ 11,147, 81,162,128, 57,167, 69, 42, 5, 75,143,213,230,242, 75, 94, 34, 50,148, 86,158, 42,113, 39, 27,112,159, 14, 38,119,193,
+ 60, 55, 23, 19,212, 81,204,173, 89, 4,134, 67, 34,209,128,198, 87,130, 56,138,188,146, 2, 0,242,151, 49,169, 50,114,101, 1,
+128,179,188, 40,225,158, 7,226,222, 37,108,143,142, 56,150,110, 23,166,172,133,150,142,120,196, 98, 54,173, 44,162, 36,158, 73,
+ 85,146, 56,200, 44,124,193, 4,140, 4,124,232,139, 41, 61,145,109,196, 58,132,173,181, 37,104, 80,200, 82, 72, 32,131,243, 26,
+247,174, 11,240,211,199, 61,219,180,206, 66,179, 55, 36, 79,186,108,118, 29, 68, 54,166, 58, 92,122,228,181,217, 65, 13, 22,219,
+ 47, 30,106,157, 61,174, 95,242, 14, 16,243, 97, 37, 45, 44,128,150,181,219,219, 46,247,181,247, 6,129, 2,231,180, 43, 48,171,
+148,106,139, 65,216,211, 33, 58, 29, 65,232, 57,219,113, 63,172,203,233, 86, 66,219, 88, 74,208,160, 66,146, 14,147,240,211,197,
+174, 19,241, 67, 46, 53, 25, 37, 79,179,102,180,202, 13, 86, 95, 49, 2,166,156,244, 38,219, 9, 97,213,178,207, 29,212,220, 7,
+ 17,201,120,194,158, 38,248, 69,197,190, 22,102, 66,159, 60,166,246,156,166,165,136,165,204, 33, 4,210,212,142,160, 95,115, 12,
+218,119,104, 36,179, 11, 18,134, 72,237, 33,202,244,180,180,181,103,226,173,194,210,210,210,208,192,194,210,210,210,208,192,194,
+210,210,210,208,192,194,210,210,210,208,192,194,210,210,210,208,192,194,210,210,210,208,192,194,210,210,210,208,192,194,210,210,
+215, 13,125,163,254,220, 13,158,224,130,240,159,178,214, 5,156,238,249,111,173, 45,150, 21,116, 81,219,173,155,110,200,219,199,
+ 39,194, 98,116, 8,215, 53,192,138,116,167,170,213,245, 68,151, 17,255, 0,171, 32,177,132, 50,233, 76,186,132, 39,249, 26, 91,
+214, 67,195,217,207, 19,102, 9,149,228,116, 47, 95, 90,224,177, 85, 42,161, 80, 16, 11,200,238, 85, 35, 64, 72, 5,157,128,185,
+ 10, 46,204, 1, 98,226, 46, 38,200,248, 79, 45,124,219,136, 51, 20,203,104, 81,130, 6, 96,204,206,237,114,169, 28,104, 26, 73,
+ 28,128, 78,148, 86, 58, 85,152,128,170,196,119, 43, 75, 80,124, 63, 73,159,141,131, 84, 83,195,103, 56, 94, 20, 82,242,212,138,
+127,240,103,117, 13, 77, 44, 20,171,195,105, 85,127,227,115,194, 91,193,101, 37, 75, 16,146, 20, 1, 1,180,147,204, 58,247,192,
+ 39,183,219,102,184,168,189,173,253,156,222,171, 32,236, 38,233,221, 18,227,210,109, 58,154,110, 6,238, 13,182,188,107,111,132,
+162, 53, 29,138,204,184,113, 36,218,181,233,114, 84, 26,131, 10, 91, 82, 88,144,233, 68,118,234,107,152,244,120,206,205,115,175,
+ 7,248,243, 35,161,151, 49,169,202, 86,166,150,157, 75,200,105,230,142,102,141, 64,185,102,140, 17, 33, 10, 55, 98,138,225, 64,
+ 44,108,160,156, 64,178, 47, 27,188, 58,226, 12,194, 28,174,151, 57,106, 90,186,150, 9, 16,169,134, 72, 82, 71, 38,202,171, 35,
+ 3, 26,179, 27, 5, 18, 50, 22, 36, 42,130,196, 12, 72, 35, 75, 94, 80,180,173, 41, 90, 8, 82, 84, 1, 73, 29, 65, 7,204, 29,
+122,213, 97,139,107, 11, 75, 75, 94, 29,117,182, 91,113,231,156, 67, 76,180,133, 56,235,174, 41, 40,109,182,208,146,165,184,226,
+212, 64, 66, 2, 65, 36,147,128, 6, 78,134, 6, 61,233,107,140, 28, 63,123, 94,236,238, 39,253,160,119,151, 9,219, 61,108,210,
+ 43,219, 63,103, 88,247, 29, 77,157,231, 77, 86, 91,178,239, 43,178,215,171, 80,169,213, 69,219, 84,214,227,166, 57,178,252,106,
+195,236,197,150, 92,117, 83,126,173,247,214, 23,238,178, 89, 3,231,181,219,218,129,127,123, 56, 15, 15,137,177,182,194,209,220,
+115,188,169,221, 85, 85, 13,213, 86,172,210,254,165,254, 47, 78,219,136, 94,225,245, 74, 79,188,123,199,240,222, 95,139,226,126,
+167,184,183,201,250,202,212,182, 30, 7,226,105,179,220,183,134,191, 71,242,179,156,218, 1, 81, 12, 50, 72,136,121, 70, 41, 38,
+ 5,203, 48, 17,183, 46, 39, 37, 28,171,130, 52,149, 12,109,136, 92,222, 32,240,164, 60, 61,154,241, 87,233, 46,118, 69,147, 78,
+105,167,158, 56,228,145,121,162,104,160, 34, 48,170, 90, 84,230,202,138, 36,140, 50, 48, 58,149,138,139,227,180, 26, 90,134, 23,
+247,207,155,251,255, 0,155, 30,209,127,235, 93,227,255, 0,232,210,254,249,243,127,127,243, 99,218, 47,253,107,188,127,253, 26,
+152,127,247, 29,226, 55,254,233,139,255, 0,155,166,255, 0,234, 98, 19,255, 0,226, 11,194,239,253,245, 55,255, 0, 37, 87,255,
+ 0,210,196,207,116,181,166,252, 3,241, 57, 89,226,255, 0,133,157,171,223,235,138,219,165,218, 85,203,250,153, 89,157, 81,183,
+232,178,101,204,165,211,157,166, 93, 53,202, 3,109,195,147, 56,120,175, 33,108, 82,154,113, 69,125, 66,221, 80, 29, 0,214,228,
+106,172,174,163,168,203,171,107, 50,250,180, 17,213, 80, 75, 36, 50,168, 33,128,146, 39, 40,224, 48, 36, 16, 25, 72,184, 36, 30,
+160,219, 22,246, 95, 93, 77,154, 80, 80,230, 84,110,100,163,204, 97,138,120,152,130,165,163,153, 22, 68, 37, 88, 6, 82, 85,129,
+ 32,128, 71, 66, 47,133,165,165,165,173, 92,110, 97,105,105,105,104, 96, 97,105,105,105,104, 96, 97,105,105,105,104, 96, 97,105,
+105,105,104, 96, 97,105,105,105,104, 96, 97,105,105,105,104, 96, 97,105,105,105,104, 96, 97,105,105,105,104, 96, 97,105,105,107,
+ 3,168,110, 45, 6, 60,249,116,122, 75, 21,123,182,183, 5,239,118,155, 75,181, 41,174, 85, 12, 9, 92,174,168,197,170, 85,150,
+166,169,212,105, 67,194, 32,183, 54,108,117,130,164,229, 32, 40, 29, 12, 12,103,154, 90,104,166,239, 21, 38,143, 91,167,219,119,
+ 13,169,123,209, 43,245,152, 83, 39,208,233, 9,165, 83, 46,121,213,134, 41,225,159,126, 83, 12, 88,181,170,177,130,134,188, 97,
+151, 38,251,171, 42,228, 95, 35,139,228, 86, 47,143, 95, 53, 54,130,157,111,109,119, 6, 76, 70,208, 28,118, 91, 44, 90, 40, 45,
+183,221,106, 77, 58, 85,222,220,217, 43, 74,114, 75,108,197,113,213, 99,149,182,214,178, 18, 70, 6, 28, 29, 45, 88,232, 23, 37,
+ 18,231,136,236,202, 36,244, 76,110, 60,135, 33,205, 97, 77,191, 18,125, 54,115, 56, 47, 83,234,212,201,141, 55, 38,149, 80, 64,
+ 82, 10,216,146,211, 78,164, 45, 36,160, 5, 2,111,154, 24, 24, 90, 90, 90, 90, 24, 24, 90, 90, 90, 90, 24, 24, 99,120,143,168,
+110,117, 51,103,174,233, 91, 65, 29,201, 23,200,138,203,116,255, 0,119,109,167,170, 12, 69,114, 67,104,169, 72,165, 50,240, 40,
+118,166,136, 69,226,200, 32,144,175,137, 0,184, 17,174, 20, 60,223, 25, 18, 95,121,199,215,190,238, 72, 83,138, 83,202, 92,139,
+187,156,186,165, 18,178,175,210,126,183, 54,117, 36,133, 36, 40, 16,160, 8, 61, 8, 35, 32,253,218,208,158, 40, 56,198,176, 54,
+ 85,185,246,165,163, 22,151,119,238,105, 66,153, 92, 54,212,151,168,214,187,171, 78, 67,245,249, 12, 43,244,179, 83,148,148,194,
+109, 65,206,185,121,108,167,148, 47,157, 60,116,224,190, 27,204, 99,139,140, 56,175,196,124,203,131,114,188,170, 14, 66,193, 75,
+ 56, 17, 77, 38,167,144,114, 96,182,185, 42,165,190,146, 16, 51, 50, 70,132,233, 84,102,199, 72,120, 15,198,220, 77,151, 75, 55,
+ 7,112,151,134,185,103, 26,102,153,172,252,246,158,170, 2,101,134, 61, 49,198,121,211,223, 68,116,145, 17,172, 23,210,170,242,
+ 53,139, 51,170,227,143,215, 53,223,196,133,153,238,191,194,219,167,117,237,195, 59,196,247, 52,214,107,151, 20, 5,201, 13, 99,
+196, 83, 45,200,148,149, 45, 41, 42, 0,144, 49,147,140,231, 88,195, 91,199,188,114, 93,109,134, 55, 39,112,100, 60,226,194, 90,
+101,171,158,186,235,142, 44,159,133, 40,109, 50,201, 90,179,216, 0, 78,177,155,198,244,186,247, 18,225,151,114, 93,181,137,181,
+218,221, 69,209,207, 34, 82,202,131,105, 39, 13, 68,134,194,112,136,145, 17,156, 33,166,210,148, 36,118, 25, 36,157,221,188, 47,
+ 45,145,246,104,112,186,239, 19, 59,221, 70, 93,217,123,214,159,133, 73,179,173, 8,106,140,213,106,227,187, 42,177, 94,153, 78,
+181,233, 18, 37,182,177, 72,167,177, 22, 51,207,212,167,150,214, 25,110, 59,132, 37,229,170, 52,119,121, 7,194,159, 15,120,203,
+198,222, 60,159,134,248, 23,136, 51,106,108,146, 23, 75,212, 85,212,201, 45, 66,164,141,162, 37, 49,195, 36, 81, 52,243,178,187,
+ 44, 97,214, 56,145, 92,188,204,177,150,110,196,241,107,196,110, 10,240, 51,128, 32,226,126, 62,225,252,162,167, 58,153, 28,251,
+ 61, 37, 52,112,211, 51, 70,161,230, 97, 36,209,203, 42,211,192,172,138,210, 20,105, 37,118,141, 82, 21,105, 2,174,163, 72,218,
+189,222,170,162, 69,126, 85,135,123,206, 76,183, 23, 46, 77, 77,218, 13, 81,227, 33,199,137, 91,146, 29,120,199, 37,106, 82,148,
+ 73, 81,238, 73, 58,203,118, 91,127, 55, 47,135,155,149,114,173,233, 18, 19, 1,201, 8, 23, 5,159, 86, 18, 27,166,212,210,217,
+229, 80,122, 50,192, 84, 10,130, 81,144,135,219, 1,196,246, 80, 91,101, 77,171,150, 85, 47,164,143,198, 35,151, 97,170, 81,118,
+183, 97,169, 54,130, 37,133,179,102, 61,111, 92, 53, 14,120, 40, 95,195, 22, 93,192,171,133,185, 46, 62,166,176, 22,235, 65,161,
+204, 74,144,218, 6, 18, 59,121,195,151, 16, 59, 31,237,121,225,250,232,188,108,251, 74, 62,216,241, 35,181,232,138,205,221,106,
+ 37,246,165,173,185,210, 97,201,126,152,244, 42,139,108,182,186,213,159, 85, 16,103, 34, 50,222,109, 50, 33,200,136,182, 92, 7,
+194, 14,201,234,207, 16,126,128,222, 38,248, 71,147,143, 16,120, 59,138,106, 38,207, 50,127,174,217,162, 46,210, 29,204,124,216,
+156,104,105,141,227, 9, 42, 77, 79, 51,176,134, 89, 64,146,237,200,222, 28,127,180, 43,194,191, 25, 51,195,225,207, 24,112,181,
+ 60, 89, 30,113,245, 32, 50,202, 17, 98, 29, 36, 17, 76,191, 88,176,139, 72,205, 19,193, 81, 10, 35, 77, 20, 76, 99, 32,118, 27,
+ 96,248,137,177,183,250,218, 21,123,106, 66,161,213,225, 37,166,235,214,228,213,160, 84,232,242,156, 78, 64,113, 41, 56,147, 13,
+101, 43,240,159, 71,192,224, 65, 7,149,105, 90, 19,106,226, 39,139,222, 29,184, 78,110,198,145,196, 38,229, 82,246,206, 6,226,
+214, 42, 20, 27, 86,171, 91,137, 84, 93, 38, 85, 78,151, 17,153,211, 89,157, 82,131, 5,214,105, 13,162, 43,237,171,196,148,182,
+ 91, 86, 72, 74,138,129, 26,224,102,199,110,133,115, 99,247, 86,135,116,199, 84,134, 26,129, 81,250,170,231,166, 5,148, 9,180,
+119, 95, 17,234,144,223,108, 28, 41,230,185, 75,173,103, 33, 47,197, 65,236, 8, 56,167,210,118,170,198,173,240,251,194, 53, 82,
+ 35,168,126, 52,237,202,189, 36,178,235,106, 10,109,214,222,179,169,238, 54,226, 20, 58, 41, 37, 10, 4, 31, 67,171, 87,232,151,
+199,112,248,245, 61, 22, 67,196,119,203,243,234, 9,141, 61,127,179,133, 66,234,105,230,150, 10,168,209,213,213, 57,175, 11,164,
+177,216,133,120,223, 78,133,116, 11, 85,125, 48,120, 26,127,163,229, 30, 99,196, 92, 52, 23, 49,200,107, 97, 90,156,188, 84,150,
+112,140, 42, 96,138,162,146, 87, 70, 70,147,148,147, 35,197, 32, 96, 89, 36,143, 86,182, 71, 38, 80,214, 61,247,102,238,101,169,
+ 68,190,118,250,231,162, 94, 86,117,203, 5,186,157, 2,229,183,106, 17,170,180, 90,196, 7, 74,146,220,186,125, 66, 35,138,110,
+ 83, 5, 72, 80,230, 66,136,202, 72,238, 8,214, 89,168, 64,112,175,237,189,221,253,134,225,159,102,120,123,225,163,133,105,251,
+189, 82,218,155, 26, 53, 58,249,186, 43,172, 93, 53, 88,104,168, 59, 62,163, 61,244, 83, 40, 54, 52,101, 57, 18,156,216,146, 0,
+149, 42, 82, 84,242,185,200,142,216, 71, 50,250, 53,193,103,210, 48,176, 55,151,114, 45,253,161,226,123,106,154,216,235,138,230,
+171,179,111,210,175,154, 45,102, 69, 70,198, 98,189, 45,246,226, 66,166, 92,208, 43, 49,218,153,107, 54,228,197,120, 94,244,183,
+101, 50,219,175, 32, 72, 17,218, 11,121, 61, 57,156,120, 63,198,153,119,233, 74,154,108,168,214, 80, 80, 73, 45,180,205, 3,212,
+154,116,102,229,204,244,233, 33,144,107,140, 7,210, 20,181,143,217, 29,185,103, 35,241,187,128,243, 63,209, 20,149, 89,184,162,
+204,179, 40,225, 7, 84, 53, 9, 74, 42, 93, 19,153, 2, 84,188, 98, 35,203,145,140,122,139,232,184,251,102,226,253,250,171,113,
+ 37,195,245, 6,251,107,107,171, 91,211,182, 52,173,200,122,165, 79,163, 51, 98,207,189,104, 17,110,183,106,213,101, 50,154, 93,
+ 53, 20, 39,167, 9, 42,157, 33, 82, 99,134, 90, 13,243,184, 95, 72, 64, 60,195, 47, 80, 32,128, 65, 4, 17,144, 71, 98, 53, 2,
+158, 50, 84,211,191, 72, 26,128,243, 1, 10, 14,113, 65,195,147,232, 82, 80,159,137,193, 34,193, 91, 78,246,248,156, 5, 45,144,
+174,224,164, 16,122, 13,118, 87,143, 15,111, 68, 62, 31,247, 89,238, 25,120, 83,218,134, 55,231,120,232,117, 24,214,189,203, 90,
+170, 59, 86,145,107, 83,239, 39, 22, 24,122,204,183,168, 86,222, 39,222, 53,230, 36, 56,219, 82, 84,212,136,236,177, 41, 11,138,
+145, 33,196, 56, 91, 91, 48,240,167, 51,118,225, 88,120,116,201,154,212,103,249,106,102, 51,243, 57,112,197, 76,172, 19, 86,169,
+ 89,130, 8,193,123, 6, 98, 25,182, 0, 19,182, 17,203, 60, 97,202,145, 56,190,163,137,196,121, 61, 47, 14,230,178,101,148,252,
+190,100,210,213,186,151,211,162, 37, 82,237, 35, 4,185, 84, 5, 84, 92,179, 1,190, 36,133,165,168,139,220,190,218,255, 0,106,
+111, 13,237, 80,239,190, 41,184, 29,183,169, 27, 89, 90,168, 69,138,228,225, 66,187,237, 23, 16,167,193,117, 20,246, 46, 35, 90,
+169, 70,163, 85,156,101, 14,120, 77, 84, 34,149,172,182,172, 54, 74, 84, 7, 85, 46,223,109,143, 13, 22,231, 5,182, 47, 26,148,
+171,102,247,187,237, 43,183,112,233,251, 83, 88,178, 40,166,138,205,225,100, 95, 50, 40, 85,218,228,250, 85,194,221, 66,123,108,
+120, 76, 51, 65,115,145,214,150,161, 37,154,132, 89, 13, 39,195,116,242,177,215,248,105,197,180, 35, 47,120,168,226,205,105,243,
+ 57,189,158, 25,168,170, 33,169,137,167,177, 60,146,241,185, 8,246, 6,193,244,130, 65, 0,146, 8,196,131, 46,241, 91,131, 43,
+206,100,147, 87, 77,147,212,229, 48,251, 76,240,215,211, 79, 73, 50,211,220, 14,112,142, 68, 5,227,187, 45,202,106, 32, 16, 72,
+ 0,223, 29,148,210,212, 92,183, 35,233, 31,162,243,160,209,233,124, 25,112,161,184,187,163,185, 51, 34, 63, 58,227,131,120, 83,
+170,147,233,118,147, 44,202,113,150,152,250,163,111,196,153,119, 10,221,142, 27,116,188,153, 48,153, 96,159, 12,248,202, 37, 72,
+198,248, 54,250, 69,151,109,251,190,214,214,200,241,107,178, 86,230,220,166,238,185, 96,217,113, 46,235, 45, 87, 21, 53,219, 86,
+231,169,204, 77, 62,159, 26,239,181,110,153, 50, 30, 76, 37,212, 94,142,195,174,178,251, 78, 69, 46,135, 23, 29,196,133, 99,108,
+248, 71,199,171, 65, 85, 94,249, 46,143, 99, 86,119,128,205, 7,180,136,210,247,113, 0,144,200, 87, 98, 84, 91, 83,129,116, 86,
+ 4, 95, 68,120,211,225,211,102, 52,121,116,121,233,147,219,157, 99,142,160, 83,212,123, 33,145,237,166, 51, 80, 99, 17,134,243,
+ 0,198,250, 99, 38,210, 50,144,109, 43, 29,120,113,198,217,109,199,157, 90, 91,105,164, 45,199, 28, 89, 9, 67,109,161, 37, 75,
+ 90,212,122, 37, 33, 32,146,124,128,215, 14,253,164,222,219,221,157,224, 86,233, 59, 61,101,218, 15,111, 86,249, 34,155, 14,165,
+ 92,161, 49, 88, 69, 18,210,176, 89,169,199,110,101, 41,155,170,176,220,103,222,151, 90,126, 19,172,190,154,124, 86,130,209, 30,
+ 75, 79, 63, 37,143, 17,182,220,230, 77,175,244,142, 56,132,142,220,122,222,253,112, 91,245, 86,205, 92,140,191, 79, 85,221,100,
+ 38,245,165, 74,102, 61, 69,151, 99,183, 46,153, 83,187,226,187, 77,174,184,128,224, 80,100, 59, 27,198, 13,148,165,214,201,230,
+ 8,229, 94, 22,113,190,113,150, 83,230,244,153, 69,168,170,198,168,121,147, 65, 20,147,169, 23, 6, 24,228,145, 93,245, 13,211,
+ 97,172, 88,173,193, 4,175,156,120,191,192, 25, 38,109, 81,146,214,231,119,174,163, 58,103,229, 65, 81, 52, 84,237,123, 17, 52,
+177, 70,232,133, 78,207,185,229,155,135,210, 65, 2, 71,219, 95,199,191, 8,187,217,187,147,118, 59,104, 55,194,208,220,189,198,
+166,208,234, 87, 13, 70,153,102, 59, 46,189, 76,133, 76,164,205,137, 79,158,183,238, 88, 81, 85, 78, 18, 91,151, 54, 58, 11, 41,
+148,167, 73, 89, 33, 4, 37, 68,109,254,160, 19,244,127,110,123,126,214,227,115,113,175, 26,237, 82, 45, 14,212,183,182, 43,113,
+ 46, 74,213,102,160,164,196,131, 73,183,233, 85,139,126,167, 62,165, 57,121, 34, 52, 86, 32, 48,235,174, 30,161, 9,104,247,198,
+186,103,185, 63, 72, 83,125,183,147,120, 38,237, 23,179,215,133,198,183, 45,182,164, 77, 98,145,112,222, 16,174, 10,229,197,113,
+192,167, 58, 82,245,199, 30,212,183,230, 68,102,215,162, 45, 1, 42, 11,168, 75,116,161,181,165, 79,248, 14, 57,225, 53, 36,226,
+ 95, 8,115, 26, 94, 38,172,201,120,104, 61, 93, 6, 89, 75, 4,245, 53,117,114,195, 4, 81, 25, 67,146,100,145,185,104,163,202,
+ 74,160,212,224, 2, 73, 32, 18, 34,220, 41,227, 94, 89, 89,194,148, 57,247, 21,178, 81,102, 57,181,101, 69, 61, 45, 29, 20, 83,
+212, 77, 48,132,160, 2, 56,151,153, 35,155,184, 12,231, 66, 18, 85, 64, 4,128,101,135,165,168,156,219,158,223, 30, 44,184,114,
+221, 75,123,111,253,161,252, 36, 55,183,244, 42,247,131, 37,117,235, 78,155, 93,160, 92, 80,232,239,201, 68,119,171,244,186,109,
+102,169, 54,159,121,211,227, 40, 44, 58,212, 57,113,220,230, 73, 71,139,226, 0,218,186, 89,198, 87,182,211,135, 30, 14,235, 27,
+ 75, 6,163,102,223, 59,171, 70,222, 93,176,167,238,197,161,117, 88, 18, 40, 31, 82,200,182,106,181, 25,180,248, 5, 70,177, 61,
+135,125,225,126,226,183, 10,124, 49,200,151, 18,149,128,224, 82, 83, 20,171,240,211,140,105,171,114,250, 40,178,177,152,182,106,
+143, 37, 52,148,179, 67, 60, 19,172, 66,242, 24,230, 71,208, 74, 13,202,146, 26,219,128, 70,248,152,209,120,173,192,245,116, 57,
+149,124,217,177,202,215, 39,120,227,171,138,178, 9,169,234, 41,218, 83,166, 46,100, 14,156,192, 28,236, 25, 67, 45,246, 36, 29,
+177,217,173,112,163,112,253,133, 28, 55, 95,188,105,212,248,162,173,202,171,215,108,187,186,163, 93,190, 47,125,152,175,202,157,
+ 87,160,214,183, 90,175, 85,141, 82,118,228,122,179, 46,114,165,201,181,228, 73,126,179, 50,101, 17,245, 57, 25,115, 93,105,180,
+ 56, 41, 5,116,160,202,240,191,237,190,220,158, 50,248,231,219, 77,158,218, 29,130,147,111,112,189, 93,145,119,193,184,247, 10,
+229,165,214,170, 87,151,189,209,182,206,237,185,233,142,205,168,210,100,170,143,106, 52,237,203, 71,166, 71,110, 59,134, 83,174,
+180,249, 30, 48,117,228, 33,185, 31,161, 92,200, 74,187,115, 37, 42,199,166, 64, 58, 74,170, 30, 49,240,218,181,169, 26,169,242,
+ 74,252,226,140, 25, 82, 41, 81,156, 65, 43,200,129, 36, 40, 91,149, 48,104,217,133,136,150, 59,130, 25, 75, 17,133,169, 38,224,
+127, 20,232, 22,181,105, 35,207,242,236,146,184,136,164,154, 23, 84, 53, 16,164,110, 94, 33, 32, 83, 44, 44,178,170,155,131, 20,
+182, 33,149,130,131,134,126,151,176,123, 71, 74,180, 27,176,226,237,253,162,205,158,136,126,226, 45,102,173,218, 59, 86,224,136,
+ 80, 27, 49, 69, 13,184, 98, 40,143,200, 0,228, 13,114,224, 99, 24,212, 4,189,180, 92, 57,109,223, 10,156,122, 93,182,174,205,
+192,141,105,218,119, 45,169,102,238,133, 50,218,161,145, 14,159,102,213,171,255, 0, 88, 69,169,211,168,140,199,193,165, 66, 53,
+106, 19,243,227,176,217, 74, 34,138,178, 89,140,150,163, 54,195, 77,254,136, 21, 90,173, 54,133, 75,169, 86,235, 51,225,210,168,
+244,120, 19, 42,149, 90,165, 66, 67, 81, 32, 83,105,180,248,238, 75,157, 62,108,183,214,148, 70,136,204, 86, 93,113,199, 22,160,
+132, 33,181, 41, 68, 0, 78,191, 57, 62, 35,175,107,151,218,161,237, 50,184, 37,109,235, 50,196, 29,229,220,202, 77,141,183,190,
+ 43, 14,184,170, 30,215, 90, 80,163, 80, 97,220,243, 97, 43, 10,140,219,118,133, 14,117,126,160,198, 73,109,217, 50,144,146,162,
+ 19,155, 39,192, 39,174,139, 62,226, 12,218,122,167,135, 34,160,161,145,235, 29,217,140, 69,217,213,208,184, 38,197,194, 71, 52,
+154,236, 88, 42,184,189,156,131, 86,125, 35,211, 47,155,135,120,111, 38,167,164, 73,184,135, 50,204, 35,142,133, 17, 84, 74, 17,
+ 81,146, 64,132, 0, 66, 51,201, 4,122, 1, 10, 89,144,218,233,113, 61,206, 11,119, 14,189,187, 28, 40,240,239,185, 23, 75,138,
+118,228,190,118, 83,107,110,250,243,171, 32,173,202,197,203, 99,208,235, 85, 53,168,134,209,146,102,205,124,159,129, 61, 79,234,
+167,176,217,253, 55, 59, 75,100,210,182,231,110,237, 11, 38,133, 20, 65,162,218,246,245, 30,223,164, 66, 7,152, 68,165, 81,169,
+241,233,212,232,193, 88, 25, 13,196,142,210,123, 15,213,211,141,170, 34,178, 72,102,172,170,154,158, 62, 77, 60,178, 59, 34,126,
+202, 51, 18,171,255, 0,106,144, 62,236,116, 69, 12, 83,193, 69, 71, 5, 76,188,250,152, 98,141, 36,127,219,117, 64, 29,191,238,
+ 96, 79,223,133,168,165,123,119,125,170,238,209, 91,175,240, 39,195,117,192,235,151, 29, 77, 14, 81,120,135,190, 40, 15,243,187,
+ 74,135, 49, 41,105,123, 57,111, 76,138,162,181,214,165, 33,194, 46, 23, 26, 41, 49,152, 90, 40,225, 78, 63, 38,166,204, 61,237,
+246,205,251, 82,224,240, 79,182,174,108,238,209, 85,161,203,226,135,116, 40,142,253, 82,227, 78, 37,255, 0,226,146,206,156,167,
+161,191,184, 53, 54, 18, 8, 53,247,252, 41,108, 80, 99, 56, 82, 61,229,165,212,159, 75,177,161, 8,147,185, 93,236,136,246, 94,
+213,106,214,149,199,198,255, 0, 17,212,217,179,238, 10,173,173,115,221, 27, 61, 64,185, 22,228,217,136, 85, 70,147, 62,106,247,
+ 98,229, 19,146,183,100,220, 18,214,234,221,164,120,203, 82,154,110, 66,170,174, 5,201,122, 11,177,110, 14, 3,225,236,179,135,
+178,212,241, 23,140, 33,215, 71, 11,133,202,168,154,193,235,170,175,228,151, 73,191,212,196,192,178,146, 8, 37, 76,132, 21, 68,
+ 89,105, 31, 17,120,151, 54,226,108,214, 79, 12, 56, 34,126, 93,116,209,151,206, 43,214,229, 40, 41, 45,231,132, 50,145,245,242,
+169, 10,202, 8, 32, 50,196, 8,105, 29,161,210,223,163,211,255, 0,132, 11,255, 0,169, 75,243,255, 0,199,236,141,116, 43,233,
+ 74,255, 0,148,224, 99,255, 0,154,226, 91,255, 0,107, 96, 53,207, 95,163,211,255, 0,132, 11,255, 0,169, 75,243,255, 0,199,
+236,141,116, 43,233, 74,255, 0,148,224, 99,255, 0,154,226, 91,255, 0,107, 96, 53,106,102,159,250,197,112,231,255, 0, 5, 39,
+255, 0,208,175,197, 59,147,255, 0,234,195,197, 95,252,124,127,255, 0,161,150,227,167,222,201,206, 30,246, 78,244,224, 27,134,
+234,253,209,181,155,125, 93,172,206,219,232,206,205,170, 85,108,219,118,161, 80,150,239,214, 85, 36,151,101, 76,151, 78, 91,146,
+ 29,229, 74, 71, 50,212, 78, 0,235,174,142,127, 36,254, 28,127,249, 20,218,239,253, 65,181,127,255, 0, 21,168, 67,236,206,242,
+251,107,106, 27, 11,183,118,135, 14,118,230,248,218,123, 35, 96,219, 49,169,246,138,246,239,108,225, 81, 63,132, 20,246, 12,185,
+ 95, 92,181,113, 85,232,203,170, 93,234,124,188,224,255, 0, 4,146,236, 21, 45,180,166, 60,100, 57,144,172,147,102,189,184,158,
+209,254, 22,247, 41, 54,175, 17, 19,170,123,167, 72,160, 84, 35,193,188,246,187,121,108,216, 86,109,253, 75, 99,149,165,201, 68,
+ 43,134, 21, 2, 5, 86,143, 93, 49, 75,106,105, 85, 86,234, 49,190, 62,117, 68, 87,136, 87,168, 78,113,225, 63, 21,230,217,158,
+127, 91,147,241, 53, 5,117, 75, 84,212,207,236, 81, 87, 72,103, 68,121,153,145, 24, 4,229,164,150,101, 82,174,202,138,219,115,
+ 58, 98,193,200,252,101,224,252,151, 41,225,202, 12,239,133, 51, 44,186,145, 41,105, 96,246,233,178,248,197, 59,201, 28, 17,171,
+186,157,124,201, 35,186,179, 6, 68,121, 25, 70,174, 95,164,237,173, 75, 62,218,177,233, 17,168, 22,157, 22,153,111,209, 33, 37,
+105,135, 73,163,193,139, 77,167, 68, 67,142,173,231, 17, 26, 20, 54,144,211, 9, 83,206, 56,178, 16,144, 10,156, 82,143, 82, 78,
+178, 93, 49, 28, 53,113, 19,183, 28, 85,108,189,139,190,123, 87, 80,118,125,159,125,210, 5, 74, 19,114,219,105,138,157, 46, 99,
+ 18, 31,167,214, 40, 85,152,204,188,226, 34,214, 96, 85,226, 78,135, 45,180, 56,227,105,126, 18,252, 55, 93,108,161,197, 62,250,
+231,250,168,106, 41,170,106, 41,234,227,104,170,224,119, 73, 85,193, 14,178, 43, 21,117,112,119, 12, 24, 16,215,222,247,190, 58,
+ 70,146,122, 90,170, 74,106,154, 41, 18,106, 58,136,209,225,120,200, 40,209, 58,134,141,144,141,138, 50,144, 84,141,172, 69,176,
+180,180,180,180,134, 54, 48,180,180,180,180, 48, 48,180,180,181,192,111,104, 5,251,125, 80, 56,143,220,198, 45,253,213,169, 89,
+ 9,183, 54,167,110,238, 27,118, 11,123,151,122, 90, 50,220,172,139,138,158,153, 72,178, 45,251,125,102, 37,197,116, 63, 9, 82,
+ 82,182, 38, 6, 89, 68,111, 26, 95,138, 30,142,216, 47, 57, 30, 78,249,221, 99, 81,164,226, 6, 84, 47,168,169,111,215, 68,181,
+129, 7,171,130, 78,246, 0,236, 78,216,215,169,168, 20,209,243, 10,234, 23,181,175,110,196,255, 0, 44,119,231, 75, 81,244,103,
+138, 29,229,219,186,190,226, 38,204,169, 55,100, 67,220,238, 34,247, 45,250,213,217,125, 65,164,205,147,104,206,165,216,118, 61,
+ 94,129,106,212, 95,186,100,197,162, 91,207, 73,151, 86,156,153, 30, 59,169, 82,141, 53,244,196,109,181, 55,135,114,241,198,191,
+ 22, 21,107, 15,123,247, 58, 21,239,182, 80, 41,252, 61,195,225,246, 85, 90,221,164,217,177,110, 10,125,254,238,232, 42, 29, 18,
+168, 34,221, 38,172, 62,174,129,245,162, 36,204, 82,163, 52,225, 82,101,134, 98,190,203,109, 37,110, 59,183, 5,230, 62, 70, 90,
+152, 57,114,114,192, 44,206, 14,169, 36, 72,144, 16,168,246,213, 43,132, 6,228, 91,204,218, 84,223, 8, 12,198, 29,193, 70,184,
+191, 64, 58, 0, 88,157,200,232,162,231,111,112,185,199,119, 52,181, 31,219,163,138, 13,215,187,247, 63,109,175,153, 87,125, 18,
+185,126,217, 23,151, 19, 82,104,252, 60,211, 45,201, 52,233,150, 71,240, 34,193,174,162,217,167,220,143,211,222, 93, 66,233,145,
+ 84,147, 75,108,134,220, 72,230,113,130,136,203, 97, 74,115,194,187,218, 60,116,241, 71, 94,159,183, 22,253, 63,112, 54,166,175,
+ 63,117,119, 39,104,237,104,115,229, 80,109,233,245, 11, 49,235,225,117,154,109,106,149, 86,182, 45, 90,232,117,138, 91, 85, 35,
+ 79, 91,126,254,228,106,167, 37, 61,109,158, 66,226,214,144,220, 23,153, 8,213,214,162, 27,132,212,225,139,174,147,174, 69, 33,
+ 78,131,172, 1, 25,109,118, 10,194,252,179, 32, 1,136, 25,140, 58,136, 42,221,108, 45, 99,125,129,245,219,115,107,117, 29,237,
+142,245,233,107,147,209,223,222, 43, 46,151,189,123,171, 87,168, 91,247, 45,193, 96,238,236,107, 86,163,184, 18,175, 13,204,135,
+ 26,223, 51,155,219,155,122,229,185,225,109, 4,121,171,160, 11, 66,149, 6,229,173, 86, 75, 18,101,144,211, 81, 94, 47, 30, 86,
+130,245,116,153,197,253,205,104,175,125,224,212,119, 98,196,186,104,182, 78,217,238,236,253,159,220, 25, 80,109,250, 84, 61,204,
+189,109, 75,111,110,106,180, 88,240, 28,129, 37, 16, 46,122,140, 59,158,240,173,209,164, 71,165, 4,181, 37,202, 9,253, 10, 30,
+ 67,199, 90, 31,253,157,169,144,255, 0,100,153, 42,109, 96,108, 24, 93,173, 25, 33,108, 27, 96, 37, 66, 3,232,144,141, 71,151,
+101, 98, 20,246,180, 31,222, 41, 75,252, 58,110, 5,250,122, 30,151, 3,109,247, 24,234,110,150,185,121,125,113, 27,190,246,141,
+ 14,226,220,138, 85,122,149, 95,137, 79,221, 29,192,219, 42, 86,219,187,104, 69,247, 57, 66,135,195,181,213,186,212,122,171,149,
+122,104, 85, 74, 93, 76, 92,212, 56,173,120, 13,169,182, 94,140,242,153, 95,134,178, 36,161,188,127,125,171, 86,214,225,238, 11,
+ 22,199, 16, 84,107,178,163,121, 39,108,124, 29,207, 68,141,169,183,108, 72,233,163,237,245,233, 92,170,211,106, 53,186,204, 89,
+ 52,202, 39, 35,139,138,182, 99, 49, 2,101, 90, 83, 81,212,194,240,184,239, 73, 25,143,134,171, 36, 66,194,104,254,198,161,110,
+ 97, 23, 14,138,202,199, 64, 11,164, 54,162,119, 6,214, 93, 86, 98,161,171, 35, 6,218, 79, 91,118,238, 9, 4, 11,239,126,158,
+238,246,218,253,134,210,215, 23,168,252, 66,238,173,122,152,237,253, 54,243, 85,110,231,171, 76,225,138,243,161,236,203, 18,102,
+193,102,123,213,219, 34,129, 34,173, 62,218,133, 2,172,137,173,218,242, 46,180,203,140,244, 86, 80,236, 39,101,213,208,220,211,
+ 33,228,132,186,236, 80,248,135,221,139,146,237,218,187, 18,214,222,123,102,243,129,185, 51,246,200,220,219,133,110,217,182,220,
+151, 54,246,175,118, 89, 27,207,114,220, 59,126,196, 88,238, 61, 5,154,162,127,128,148, 71,161,179, 83, 67,181, 56, 13,161,255,
+ 0,172, 27,152,151,144, 18,105,120, 98,178, 37,118, 51,199,104,151, 83,147,204, 1,108,138,237,184, 67,125, 33,173,125,181, 16,
+ 66,106,107,129,133,173,141,136, 1, 79,155,167, 77,247, 32,119,239,248,119,182, 58,147,171, 69,118,187, 74,182,233,114,107, 21,
+153,105,135, 2, 47,132,149,185,225,188,251,206,189, 33,212, 71,139, 18, 28, 72,205,173,217,211,223,148,235, 45, 49, 29,148, 45,
+231,222,121, 13, 52,133,184,180,164,182, 60, 63, 94, 23, 13,249,180,118,173,203,117,202,141, 58,225,125,219,146,149, 84,168, 68,
+134,221, 57,154,140,139,106,235,174,219, 34,165,238, 12,168,183, 13,217, 13, 81,219,121,198,219,253, 26, 28,125, 73,108, 37, 1,
+ 41, 13, 62,232,111,214,218, 88, 87, 53,221, 90,189,235,241,103, 84, 54,214, 35,223,192,237,191,166,243,212, 43,146,234,168,162,
+210,230,214,174, 85,210,219,108, 4, 84, 20,139,146, 5, 54, 10,228, 56,219,108, 55,239, 43,109,212,137,238, 41, 44, 50,192,240,
+207, 45, 59, 88,201, 19,178, 27,116,186,146, 13,137,182,215, 29, 72, 27,117,198,210,176,101, 86, 29, 24, 3,251,247,199,221,233,
+222,106,181,159, 75,167, 84,174,234, 93, 66,210,177,231, 69,184,235,115,168,180, 74,161,155,188,183, 37,187,104, 81,151, 91,175,
+ 70,163, 80, 40,200, 81,166, 32, 83, 84,169, 82,149, 18, 91,178,216,139, 78, 83, 11,126,159, 42,107, 42,103,136,187,179,237, 34,
+226,147,119,235, 63,197,223, 8,251,124,189,158,219,184, 97, 16, 40,176,233,212,196, 92,251,157, 84,166,150,212,167,102,185, 76,
+180, 34, 77,106,221,117,114, 22, 2, 25,135, 45, 15, 52,181, 45,110,204,125, 71,175,108,182, 23,109,174,187,130,169, 84,222,157,
+223,125,186,149,249,123, 65,247,101,210, 60,100,212,104, 54, 69,155, 36, 7,224,237,133,176,149, 2,203,148,166,146,166,158,173,
+205,109, 3,235,170,160, 43, 86, 98, 69,134,211, 59, 51,104,216,150, 77,129, 77,110,141, 99, 90, 54,213,159, 74,109, 41, 66,105,
+246,205, 18,155, 68,137,132,126,169, 91, 20,232,205,165,197,117, 57, 82,129, 81, 36,146, 73, 39, 78,217,109, 94, 95,150, 60,146,
+ 85, 80,254,145,169, 22,208, 11, 40,141, 58,223, 82,180,114, 93,186, 91, 96, 71, 98,164, 27,234,212,195, 81, 80, 21, 35,159,217,
+227,223, 81, 0,150, 61, 45, 98, 25,108, 58,223,168,247, 17,136,175,109,165,111,136, 46, 22,110, 90,253,251,188, 55,190,238, 65,
+226, 39,118,227, 73, 22,188, 43,214,173, 93, 15,170,216,230,151, 29, 53, 11,198, 13, 89,199, 26,118,108,119, 24,169, 38,135, 69,
+ 37,232,207,174, 19,213,119,127,239, 68, 64,213, 43,151,138,189,231,148,233, 93,203,191,247,220,103, 10,148,232,142,246,226, 85,
+105, 32, 96,149, 21, 51, 79,141, 84,100, 37, 35,175, 68, 55,129,142,128,107,190, 92, 81,109,158,214,113, 35, 67,184,108,237,202,
+102, 60, 43, 2,198,163,212, 42,247, 21,248,211, 49,155,173, 80, 37,183,202,252,118,173,218,155,209,221, 83, 79,170,117, 53,160,
+227, 77, 36,169,228, 67,121, 32,178,242,233,207, 57,194,234, 71, 15,220, 39, 90, 75,109,193, 77,191,119, 2,124, 94, 96,220,151,
+161,219,182,108,103,243,144, 18,185, 21,119,174, 89,106,100,163, 0,129,224,171,201, 60,131, 83,252,135, 54,165,204,160,150,105,
+ 50,197,106,184,152, 41, 60,176,194,223,170, 17,180, 5, 22, 29, 67, 58,155,146,119,189,240,193, 93, 73, 45, 59,170, 45, 73,228,
+176,184, 26,172,111,176, 36,139,220,223,181,129,216, 91,107, 91, 29, 21,246,100,113, 47,186, 91,235,125,110, 4, 59,162, 92, 75,
+222,214,164, 89,244,136,116,189,196,146,195,109, 87,221, 69, 6,164,227, 77, 68,157, 83,101,164,170,228,142,252,250,245, 93,166,
+ 94,150, 12,132,127, 7, 30, 90, 93,113,183, 73, 87,102,245,197, 62, 8,247, 59,106,118,179,113, 23,103, 90,182, 36, 75, 2, 30,
+235, 85,168,116, 25, 13,199,172,212,107, 14, 87, 43,209,216,152,205,189, 33,239,126, 9,109,170,147,105,114, 75, 75, 16,216,138,
+219,177, 93, 46, 62,219,134, 27, 74, 71,107, 53, 4,226,104,132,121,180,197, 40,197, 20,114, 5,101, 80, 0, 13,113,230,112, 20,
+149, 23,107,139, 2,109,109,247,185, 47,153,107, 22,165, 75,205,206,101,184, 39,115,107,116, 27,128,122, 88,239,235,233,133,165,
+165,165,168,254, 55,240,180, 29, 66,161, 2,147, 6, 93, 78,169, 50, 45, 58,157, 2, 59,178,166,206,154,251,113,162, 68,140,194,
+ 11,143, 72,147, 33,229, 4,178,202, 80,149, 21, 41, 68, 0, 6, 73,209,154,212,158, 53,182,250,255, 0,220,189,141,169,219,187,
+118,235,139,169,181, 89,166,213,106,148,134,158, 12, 59,113, 81, 32, 51, 52,201,162,180,181, 16,149, 58,102, 59, 6, 74, 80,165,
+ 0,225,167, 6,243,149, 0, 88,184,159, 52,173,201, 56,123, 58,205,242,220,170, 76,242,191, 45,166,150,104,105, 34,254,242,162,
+ 68, 66,203, 18,216, 19,118, 35,162,171, 57, 23, 8,172,214, 82,253,194,249, 85, 14,121,196, 89, 38, 79,153,230,209,228, 89,126,
+101, 83, 12, 51, 86, 75,253,221, 60,114, 56, 87,149,174, 85,108,160,245,102, 84, 6,197,221, 86,236, 52,131,138, 95,104, 4,186,
+199,214, 54, 22,197, 77,122, 13, 40,151,161,213,183, 5, 41, 91, 51,234, 13,245,109,214,109,116, 44, 5, 64,138,174,191,225,138,
+ 1,245,164,254,133, 45,116,112,232,102,217,108,157,245,187,134,183, 88,166,198,146,138, 37, 30, 21, 78,171, 88,184,102, 54,243,
+205,188,244, 72,207, 77,118, 44,101, 40,243, 79,168,186,180, 97, 88, 36, 32,185,206,226,129, 32, 43,100, 54, 19,129,203,238,248,
+173,181, 55,114, 41,115,173, 91,118, 27,233,241,105,111,225,154,189, 85, 72, 80,230,100,242, 40,251,132, 63, 37, 44,159, 21, 64,
+225,180,167, 62, 34,123,107,102,109,165,171,100,219,108, 91, 52,106, 68, 40,116,214, 97, 24, 34, 35, 12, 33,184,233,142,182,203,
+107,104, 54, 7, 80,164,169, 92,196,228,168,168,149, 18, 73, 58,227, 46, 26,240,155,196, 15, 27,243,131,198,254, 48,212, 79,148,
+100,169,175,216,178,205, 50, 64,197, 79,217, 84,129,142,186, 74, 91,129,173,223,251, 93, 72, 91,234, 0,172,216,237, 78, 38,241,
+115,195,223, 3, 50, 97,192,254, 13, 83, 65,156,103,114, 20, 53,217,166,164,168, 64, 71,218,103,168, 81,162,174,168,169,109, 8,
+159,217, 41, 75, 17,164,144,208,226, 44, 52,185, 13,195,169,211,165,188,142,118, 98,207,137, 33,212, 30,203,109,137, 13,184,226,
+ 8,249,165, 36,125,250,127,189,191, 59, 1,126,241, 15,193, 94,202,238,238,208,211,167, 93,244,109,151,184,170,119,101,215, 68,
+161,176,236,233,235,179,175, 10, 4, 24,142, 93, 76, 66,140, 20,185, 76,211, 95,167, 69, 50, 66, 18,165,179, 30,166,244,130, 3,
+ 76, 60,164,211,226,127,101, 42, 59, 29,186,181,187,117,109, 62,187,118,168,251,213,155, 78,162,182,200,106, 93, 34, 91,202, 95,
+186,135, 57, 66, 85, 38, 43,203, 84,119, 64,193,253, 26, 87,128,151, 18, 75,183,195, 79, 26, 53,221,151,166,139, 34,240,164,187,
+122,109,226,148,224,141, 17, 46,182,154,189, 13,183,212,165, 72,102, 2,165, 31, 10,109, 61, 74, 90,213,238,238,148, 4, 41,106,
+ 40,113, 41, 37, 5,151,232,189,226,236,127, 70,191, 20,115,188,175,140,233,189,135,151, 83, 26, 73, 43,163, 50, 69, 61, 47, 62,
+ 45, 50,104, 12,254,207, 83, 5, 76,154, 39,141, 95, 65, 49, 74, 20,198,204,234,241,244,170,240,114, 79,164,247,132,249, 46, 99,
+193,117, 94,220, 37,165,149,227,137, 29, 21,229,130,168,211,204, 26, 46, 97, 84,246,154, 89,233,163,215, 79, 35, 71,204, 2, 88,
+139, 9, 21, 81,160, 87,169,110,253, 27, 78, 31,247, 14,201, 78,246,241, 53,120, 64,159,107,237,173,207,108, 82,237,139, 90, 69,
+ 85,167,160,179,114, 68,163, 76,149, 92,175,220,241,144,248, 79,137, 70,138, 26,139, 29,153, 56, 45,188,228,137, 73,109, 71,193,
+ 94,122, 95, 89,143,236,147,185,110, 37,110, 61,103,134,205,190,118,245,118, 71,214, 47,186,246,201, 80, 28,168, 63, 81,230,241,
+ 76,135,214,152, 94,233, 38,103,139,215,198,113, 69,124,221,121,181,134,239,223, 25, 43,190,109,119, 54,195,105,109,159,226,243,
+110, 28, 97, 16,106, 24, 17,153,172,214,169,236, 0,134,169,158, 5, 63,244, 20,106, 55, 34, 82, 21, 29,165, 56,167, 82, 2, 22,
+180,183,204,210,189, 25,241,187,233,237,225,100,220, 3,152, 80,112,253, 92, 57,166, 99,153, 70,182,130, 10,152,234,164,119, 86,
+ 89, 18, 33,201, 5, 97, 70,145, 87,153, 52,237, 25, 88,195,132,133,228, 42, 7,154, 94, 3,127,179,211,197,122, 79, 17,114,220,
+207,136,233,166,203, 50,220,174, 70,250,249,233,164,165,141, 17,213,163,121,155,158,193,230,117,141,219,151, 5, 58,200, 30, 82,
+133,230, 72,149,201,211,219,222,171, 18,185,121,221,181,168, 8, 8,131, 86,185,107,149, 40,105, 74,121, 64,139, 58,167, 42, 76,
+127,132,143,135,244, 78, 35,167,207, 77, 71,183,193, 83,207, 4, 92, 7,166,161,226,120,232,185,171,137, 62, 46,121,194, 5,131,
+ 73,240, 82,160,174,160,134, 66, 7,221,173,145,216,173,173,169,238,230,227,208,109,120,108, 60,170,120,148,204,234,252,180, 33,
+ 69,184,116,136,238,161, 82, 57,156, 72,194, 30,120,132,178,214,123,173,224,113,202,149, 17,210, 31,105, 23,179, 6, 31,180, 15,
+107, 54,119,111,211,186, 82,118,157, 59, 83,112, 85,238, 6, 95,131,103, 71,187, 17, 86, 21,122, 52,122, 72,130, 99,187,113, 83,
+133, 57, 44,166, 58, 86,149,165, 78,133, 5, 20, 20, 12, 5,107,144,127,217,239, 11,228,156,117,155,248,159,196, 50, 53, 6, 69,
+ 81, 49,167, 14, 35,118, 89, 36,209, 81, 36,238,145,198, 25,217, 98,121, 98,141, 74,171, 13, 82, 58,223,200,246,236,191,246,140,
+186,241, 7,135,185, 87,133,124, 53, 18,230, 60, 67, 79, 0,168, 49,153, 35, 86,142, 62,101, 52,112, 70,242, 72,200,138,210,199,
+ 20,210,176,118, 83,166, 56,218,223, 88,151,102,125,130,112,118, 42,169,192, 62,220,155, 3,248, 58,253,211, 14, 69,121,189,216,
+141, 20,197,250,250, 61,248,229,122,168, 93,114,229,109, 39,197, 75,206, 82, 17, 78, 84, 37, 57,240,170, 2, 88, 75, 71, 8, 80,
+ 17,173,246,250, 13,156, 87,180, 78,224,103,100, 28,162, 63, 88,110,202,179, 25,220,245,218, 78, 69,118, 49,221,175,121,170, 25,
+141,184,237, 53, 69,181,220, 41,161, 42,215, 76,222, 83,227, 38, 98, 92, 68,140, 74, 75,192,117, 38,227,250, 54,119,189,161, 79,
+164, 73,216, 46, 46,110,123, 78,180,253, 25,154,101,232,154,149, 18,165, 73,135, 95,154,143, 16, 72,168,192,114,215,185, 18,237,
+ 62, 19,168, 82, 1,129, 35,223, 2, 20,149, 45, 50,202, 86, 27, 67,243,193,111,209,227,219,173,146,220,107,127,118,119,231,112,
+164,239, 85,205,109, 84,218,174, 81,173,207,169, 81, 69,178, 35, 87, 35, 60,153, 16,234,149,118, 37,204,149, 42,232,125,153, 9,
+ 75,205, 33,229,199,142, 93, 0,191, 29,240,156, 31, 80, 50,110, 36,240,255, 0,133,248,167,136,120,250,159,140,167,206,102,204,
+197, 81,139, 47, 20,147,199, 51, 60,242, 9, 52, 75, 52,159, 86,209,161, 80, 35, 44, 16, 5,210,199,204,186, 91,202,188,243,133,
+252, 73,226,222, 17,225,159, 14,106,120, 26,159, 34,131, 42, 52,130,108,204,214,211, 75, 2,165, 60, 92,190,100, 48, 71,245,171,
+ 35,134, 38, 64,165,201,109,106, 60,175,173,120,101,186,226,227, 30,216,222, 31,145,113,169,212,222, 13,238, 7, 6,204,215,213,
+ 43,196, 18, 19,114,181,106,109,123, 85, 19, 47,197,202,132,164,212,146,231,141,205,215,196, 74,201,235,211, 90,121,178,118,150,
+251, 86,248,244,118,209,176, 55, 14,149,181, 28, 67, 63,187,123,137, 77,165, 94, 87,124,150,160,183, 79,191, 68,251,137,138,172,
+ 71,101, 79,167,202, 75, 85,121,111,253, 99, 25,144,182,148,167, 95,150,150,144,124, 71, 18, 12,191, 55,139,216,145, 27,114,184,
+246,164,241,181, 23,126,103,210, 85, 77,220,141,186,220, 36,237,202,118,242, 36,168,229, 86, 2,232,107, 69, 32, 92,230,240,109,
+ 65,169, 66,136,128, 94,247, 2,166,125,229, 68, 33,194,145,159,188,127,251, 8,246,135,139,155,230, 86,246,237,181,237, 81,216,
+221,230,170,248, 18,174,153,244,186, 83, 85,171, 78,238,170, 68,109,180, 49, 90,169, 81, 81, 50, 35,244,171,136,165,166,146,236,
+232,146,128,119,194, 75,143, 69,117,254,103, 75,214, 91,226,215, 8, 67, 22, 85,150,205, 86, 35,138,175, 35,134,138,121,205, 36,
+147, 69, 73, 85, 26,176,229,203, 3,162,251, 69, 57,230, 48, 97, 30,180,109, 10,167,202,197,149,139, 52,240,103,141,106, 37,205,
+243, 72,104,140,147, 80,241, 4,245,244,244,226,182, 40, 37,173,163,149,163, 60,200,170, 35,145,189,154,161,121, 42, 80,203,203,
+117,214,204, 6,181, 8,220,174,226, 71,130,207,107,101, 91,105,167,218,220, 83,113,207,179,208,246,122,238,169,208,173,233,177,
+183, 54,243,164,208,173,170,181,102,101, 69,135,109,234, 98,103,201,178, 88, 45,207, 85, 69,134,150,209, 67,168, 82, 61,221, 78,
+173, 73,109,181,173, 58,117,197, 87, 1,155,253,192,167,179,178,235,160,238,229,199,101,215,173,141,200,226,147,102,174,107, 61,
+ 22, 93, 90,117, 86, 35,117, 8, 59,103,187,240,170,243,222, 92,168, 76,160, 38, 69, 61,202, 40,109,109,115,248,137,137,146,174,
+ 80,141,116,161,143,163,193,196, 46,228,213,168, 20,254, 34,120,219,187,111,155, 38,221,113,180,211,233, 77,199,185,174, 25,241,
+ 97,167, 8,114, 37, 29,203,202,228,122, 53,190,165, 48, 57, 82,234, 35,200, 8, 29, 60, 21,142,154,234,183, 19,126,200,187, 31,
+124, 56, 36,218,238, 11,108,125,198,175,109,125,165,181, 87,181, 22,242,163, 87, 39,211,158,220,106,188,245,210,168,215, 85, 46,
+ 68, 42,129,170,215,224,171,196,147, 34,233,147, 37,110,182,234, 91,105, 81,195, 44, 70,109,146,148, 54,214,158, 34,228,185, 53,
+ 87, 15, 81, 71,196,212, 85,249,107, 87, 71, 81, 94,180, 57, 43, 81, 65, 18, 68, 85,227,149, 89,109, 43, 77,170, 53, 86, 9, 12,
+154,144,144, 89, 2,128,238,210,120, 95,158,231,148,156, 75,152, 73,194,149,249,118,106,153,124,148,217,123,102, 25,242,215, 84,
+ 77, 36,193,146, 72,157, 90,240,164, 26,100,118, 66,243, 71,165,192, 96,175,172,152,216,127,163,207,182, 54, 85, 63,129, 26, 5,
+213, 18,131, 1,186,245,225,121, 94,117, 27,146,168, 35, 51,239,213,105, 84,250,195,212,170,127,190, 73, 8, 11,121,152,244,248,
+205, 54,202, 20, 74, 90, 10, 95, 32, 5,107, 39,133, 62,218,203,122,129,108,123, 96,109,245,210, 41,177,105,109,213,209,195,221,
+118,176, 97,180,134, 12,218,147,149, 56,208,159,168, 62, 91, 3,158, 81,133, 78,134,130,179,241, 17, 25, 57, 61, 53, 47, 47,103,
+175, 7, 75,224,115,135,139,127, 97,141,234,237,254,138, 5, 74,189, 81, 77,202,253, 13,187,113,201,102,185, 84,122,164,166,141,
+ 41,170,164,208,194, 90, 47,114, 3,239, 11, 42, 8,230, 56,206, 53,160, 92,119,251, 21,218,227, 43,139,138, 79, 20,201,223,169,
+214, 59,244,232, 27,125, 4,217,141,109,212,106,251, 11, 22, 36,247, 38,120,191, 94,185,121,196, 82, 76,164, 44, 39,151,221, 15,
+128, 83,205,151,129,228, 17,110, 24,227,108,134,131,196,238, 46,226, 60,195, 51,120,242,140,217, 51, 4,134,110, 92,238, 92, 77,
+ 42, 52, 0,198,177,153, 20,104, 81, 96,232, 2, 5, 0,233,176, 24,151,241,111, 0,241, 22, 99,225, 63, 5,112,190, 91,148,164,
+153,214, 76,249,107,207, 8,150,157, 4,109, 4, 46,181, 12, 36,105, 22, 38, 58,216,234, 40,236, 92,177, 35, 85,201,196, 94,166,
+255, 0, 4,227,251,102,171,138,226,141, 80,145,106,127, 43,106,227,151,155,183,111,130, 40, 41,134,253,197, 45,203,106, 77,100,
+206, 72,103,248, 45,250, 74, 26,201, 88, 17,189,203,148,159,208,106,118,219,255, 0, 77,225,202, 23, 11,155,155, 59,120,151,101,
+141,146,115,108, 43,142,220,242,235, 79, 83, 77, 2, 85,186,237, 13,231, 25, 76, 37,173, 94, 28,153, 78, 35,192,250,189, 49,242,
+243,146, 21, 28, 67, 5,242,214,185,225,237, 10,246, 37,236,223, 28, 51,160,110, 93, 50,230,159,180,155,231, 14,139, 6,141, 84,
+188,169, 20,168,245,170, 53,231, 14,149, 20, 69,166, 34,238,183, 93,151, 24,202,168, 48,195,108,176,204,230, 36,178,250, 35, 54,
+134, 94, 76,166,217,142,134,185,163, 99,253, 27,221,214,159, 80,165, 91,187,205,197,181,110,187,181,116,121, 33,246,109, 11, 90,
+155, 92, 73,125,180,171, 33,152,105,184, 43,142,194,160,169, 67,169,117,184,146, 84,156, 20,165, 25, 60,195,123, 59,206,248, 23,
+142, 41, 56, 79, 52,204, 56,182,110, 23,174,225,202,104,160,154,140, 82, 79, 49, 38, 34,167, 93, 35,197,104,209,156,173,149,152,
+146, 20, 70, 93, 84,165,153,191, 32,200, 60, 65,240,254,183,140,178,156,183,130,224,226,234, 14, 40,171,154,162, 10,227, 91, 4,
+ 0, 9,129, 81, 29,108,114,131, 35,162, 6,187,162,128, 11, 25, 66, 51,137, 46,188, 20,224,130, 37,122,161,107,241,207, 22,205,
+ 68,229,213,151,193,189,253, 34, 59,113,121,149, 53, 84, 40, 55,206,223, 79,185,147,150,134, 72, 22,172,106,177,123, 29, 60, 36,
+ 57,159,135, 58,112,125,151, 27,107,197,206,231,238,109,253, 66,224,219,124,109,173,154,220,132, 90,144,164, 85,209, 87,159, 18,
+ 13, 86,231,182,219,170,182,183,153,164,123,205, 6,114,159,102, 44,244,195,114, 64,108, 32,164, 58,218,149,148,246,148,183, 0,
+ 30,195,186,103, 4, 59,219, 95,221, 41, 91,210,238,236, 81,174, 43, 18,191, 97, 78,179,235, 27,115, 6,133, 5,234,101,126, 92,
+ 7,229, 25,178,149,117,212, 19, 61,159,118,131,224,173,133,199, 8,117, 50, 23,206,113,240,235, 95,184,128,250, 57, 52, 5,238,
+ 92,237,211,224,251,126,238,109,132,155, 34,168,253, 90,157,107, 61, 18,125, 66, 21,175, 38, 90,150,227,236,218, 87, 93, 26,179,
+ 18,165, 71,166,165, 75, 33,152,239, 9,107,109, 10, 40, 18,121, 2, 82, 39,213,158, 45,112, 93,125,119, 19,229,145,230,113,193,
+ 73,155,199, 76,244,245,181, 20, 18,212,211,115,163, 69, 71,134,162,150, 72,214, 70, 81,203, 66,172, 80,165,217,219, 82,178,174,
+170,226,135,193,142, 59,203,114,254, 18,205,101,202,100,158,183, 36,150,174, 58,154, 26, 92,198, 42, 74,174, 68,178, 51,199, 61,
+ 45, 92, 82, 52,106,228, 72,225,215,152, 30,200,138, 85,149,155, 79, 63,120,152,246,113,123, 73,247,246,235,219,109,167,226,139,
+140,141,138,188,175,178,213,122,187,181,118, 29,241,126, 64,166,221,115, 99, 73, 93, 54,159,112, 78,182, 41,145,237, 56,210,106,
+ 13, 56,228,106,115,110, 33, 60,254, 41,132, 84,218, 23,238,207, 41,173, 31,246,169,108, 70,229,240,207, 70,224,147, 98,119,114,
+163, 71,170,222,187,125,195,213,118,150,252,234, 12,137, 18,233, 70,139, 43,118,239, 89,244, 56,177,164,203, 97,167, 29, 12, 68,
+146, 91, 60,200, 72, 79, 32, 74, 71, 40, 26,238, 94,204,253, 30, 26,228,253,212,164,238,167, 22,156, 77, 94,219,207, 82,164, 79,
+131, 56,192,167, 63, 93,167, 79,170,174,154,224,118, 27, 85, 91,234,181, 93,149, 83, 76, 20,173, 8, 10,106, 34, 99, 59,203,144,
+220,182,137,206,183, 63,218, 81,236,103,137,199,254,225,237,141,254,141,242,159,182, 63,197,206,219,177,183,108, 80,227,216, 76,
+ 93,200,157, 30, 61,114,165, 89,102,162,106, 82,110,248, 10,142,176,154,138,153, 45, 22,157,230, 12, 37,207, 23, 42, 41,211, 54,
+ 91,226,118, 67,149,113, 15, 14, 82, 84,113, 37, 61,110, 65,151, 37, 76,179, 61, 46, 80,244,112, 67, 83, 36, 82,198,139, 2, 70,
+ 26, 87, 71,230,182,191,169, 81,168, 7, 46,218,138,163,238,105,225, 55, 17,103, 28, 53,197, 21,180,220, 43, 85, 67,196,121,172,
+148,176,195, 29,102,117, 29,117, 68,244,145,205, 12,142,213, 15, 41, 72, 99,120,249, 43,203,250,242,218, 47, 24,141,116,134,125,
+234,246,125,236,206,223,237,103, 9,155, 11, 64,179,173,250,125, 38, 3, 59, 97,100,212, 92, 17,163, 54,202,230, 85,234,214,237,
+ 54,167, 88,172, 76, 82, 19,151,234, 82,234, 82,100, 72,125,213,100,173,199,207,100,132,164,111, 48, 24, 24, 29,135, 65,166,203,
+102,236, 37,237,126,216, 88,187,122,185,202,169,155, 50,212,183,173,113, 82, 83, 9,138,169,233,160, 82, 33,210,147, 53, 81,146,
+234,196,117, 58,152,129,101,176,181,132, 21,242,133, 40, 12,150, 11,143, 78, 49,236,142, 6, 56,109,189,119,206,237,247,106,133,
+ 98, 35, 63, 80,109,189,164,235,165,183,175,125,198,171, 71,147,252, 28,183,209,200,180,173, 16, 18,168,242, 38, 84, 93, 65,230,
+143, 77,165,203,121,176,183, 80,219, 78,115,121,134,183, 63,207, 30, 26, 53,122,250,236,222,165,132, 99,114,242,188,210, 27, 18,
+ 91,123,146,215, 98,214,176,185,107, 0,113,212, 98,122, 30, 27,225,232,231,174,100,203,178,252,150,145, 76,135, 96,145, 71, 12,
+ 64, 48, 1,118,178,133,178,170,222,230,193, 65, 36, 12,113, 23,233, 10,251, 69,127,139,219, 56,240, 51,180,149,207, 14,246,220,
+ 58, 76, 90,158,253,213,105,238,225,251,107,110,170, 45,166, 69, 35,111,195,236,175,154, 61, 90,224, 64, 68,138,131,100,165, 72,
+161,165,182, 28,109,216,245,192,166,197,250, 63, 62,207,199, 44, 27, 45,238, 46,247, 46,142,166,111, 45,207,164, 38, 30,218,192,
+168, 71, 90, 31,183,118,209,231,218,148, 43,105,105,228, 15, 10,125,126, 68,104,146, 26, 88, 10, 34,147, 18, 26,217,112, 38,161,
+ 37,189,113, 27,217,255, 0,195, 62,227,251, 81,184,218,174,223,155,197, 50,161,115,219, 13, 92,234,221, 61,253,186, 37, 37,214,
+218,174, 63, 83,168,185, 34,149, 99, 68, 49,148,129, 0, 85, 37, 71,114, 43, 76, 50,166,145, 6,141, 74,151,238,188,134, 52,102,
+151,250, 18,218,182,237, 58,213,161,211,168,148,168,145,160,194,167,196,143, 18, 60, 88,140,183, 30, 52,118, 35,180,150,153,143,
+ 29,134, 82, 16,203, 8,109, 41, 74, 16,144, 18,148,164, 37, 32, 0, 53,117,113,253,101, 39, 0,112,165, 23,134, 89, 44,193,243,
+ 42,197, 90,140,226,116,234,236,225, 88, 67,126,160, 61,151,202,108, 86,153, 34, 86,213,206,123,208,254, 27, 80,214,248,145,198,
+ 53,254, 44,103,208, 52,121, 85, 11, 61, 54, 73, 76,251,132, 68, 44,166,123,116, 38, 59,183,152, 92, 53, 84,146,178,149,228, 32,
+ 25, 10, 82, 18,144,148,140, 4,128, 0,244, 3,160,215, 62, 61,164, 30,208, 29,190,246,125,108, 68,221,193,174,166, 21,195,185,
+183, 74,103,208,246,111,110, 92,144, 91,126,238,186,153,142,218,156,168, 84,144,203,169,118, 61,155, 75, 18,162, 72,171, 73, 65,
+ 65, 8,121,152,108,172, 76,155, 21, 42,223,186,157, 78,157, 69,167, 84, 43, 21,138,132, 42, 77, 34,147, 10, 85, 74,169, 84,169,
+ 74, 98, 13, 58,155, 78,130,195,146,166,207,159, 54, 83,137,106, 28, 38, 99, 52,235,142,186,226,146,134,208,218,150,181, 4,130,
+ 71, 9,184,174,225,239,128,223,109, 5,235,103,196,178,120,186,133, 90,187,118, 26,145,116,193, 93,191,180, 87, 53,159, 80,147,
+ 34,153,115,212,232,158,253, 88,147, 10,183, 72,146,245, 74,148,212,218, 52, 38,155,157, 7,154, 22,102, 37, 42,117, 74,117,156,
+212,252, 35, 69,149,207,156, 82,213,241, 20, 21, 13,195, 52, 45,174,178, 72, 34,146, 64,163, 75, 24,163,145,145, 78,133,154, 64,
+177,177,184,109, 37,180,144, 64, 34,228,227, 92,195, 55,166,201, 42,232,248, 98,122,101,226,188,193,116, 80,199, 81, 52, 81, 22,
+ 98,202, 37,146, 53,145,135, 49,160,137,154, 69, 91, 50,235, 85, 12, 10,155, 24,223,112, 43, 69,217,158, 45,184,165,187,120,165,
+246,138,241, 35,182,116,170,123, 23, 91,119, 61, 74,223,220,203,198,221,164,212,247, 82,240, 90,154,145, 18, 4,155,122, 83,169,
+ 76, 13,179,165,195,106, 27, 94,232,150, 88,134,243,109, 69,164,194,109, 80,163,204,105,153,125,220, 94,209,127,103,156, 61,184,
+186,232, 52, 94, 47, 56,125,117,247,237, 26,244, 24,113, 99,110, 45,186, 93,145, 37,234, 60,166, 35,176,203,104,151,241, 45, 78,
+ 41, 9, 74, 64,234, 84, 0,215, 43,127,189,146,225,251,255, 0,151,141,236,252,108, 47,255, 0,212,117, 98,186, 62,141, 70,193,
+ 80,109,171,134,184,206,250,111, 75,206,209,168,117,106,171, 77, 58,108, 79, 9,215, 41,240, 31,150,134,220,228,180,193,240,212,
+166, 64, 56, 32,224,156, 28,234,227,226,156,231,194,238, 48,205, 41, 42,234,248,179, 49,165,167,161, 88,226,165,164,134,136, 37,
+ 61, 52,107,164,104,141, 76,102,218,138,130,204,119, 54, 10, 44,136,138, 40,222, 15,200,252, 93,224,124,162,178,142,139,131, 50,
+202,202,154,247,146,106,202,201,235,245,213, 85, 72,218,137,121, 92, 72, 47,160, 51, 4, 81,176,187, 49,187,187,179,241,151,216,
+125,188,123, 87,177,188,108,155,223,120,111,251, 87,109,173, 15,226,150,243,164,127, 8,239, 10,196, 74, 37, 35,235, 57,181,155,
+ 69,248,144, 61,246,107,137, 71,189, 56,212, 57, 74, 66, 51,149, 6, 20, 64,192, 58,156, 37,241,179, 92, 40,241,203,106,237, 46,
+225,220,246,214,221,239,165,175,107, 85,218,191,118,150,241,196,122,245, 54, 52,165,184,202, 93,157, 69,169, 68,120, 38,161, 71,
+146,245, 54, 31,189, 67,112,189, 2,106,233, 81,140,168,239, 42, 43, 5,184, 0,123, 51,184, 59,180,120,227,226, 73,123, 35,122,
+ 92,215, 45,167, 72,254, 47,238, 75,185, 21, 91, 80,210,133, 79,223,104,181, 43,126, 19, 17,149,245,197, 62, 75, 62,234,182,234,
+239, 21,254,143,159,153,164,114,168, 12,131,250, 11,240,185,177,214,207, 9,155, 29,181,187, 7, 78,186,100,213, 41,118,141, 53,
+ 54,133,175, 62,230,151, 77, 98,183, 95,122, 59, 21, 90,234,227,165,168,172,176,212,202,144,167,198,170, 72, 83,113,218, 4, 70,
+167, 60,241, 64,109,167, 22, 49,227,201,203,105, 56,158,154,191, 47,204,234, 97,226,113, 20, 74,241,160, 40,145,211,114,230, 28,
+196,153, 44,218,218,229, 29,117,125,130,110, 45,140,253, 29, 23, 52,173,225, 42,188,187, 50,202,105,103,225, 38,158,102, 73,100,
+ 43, 36,146, 85,137, 41,207, 41,224,123,174,133, 0, 58, 57, 91,243, 2,216,220, 12, 63,180,219,118,145, 74,138,212, 72,144,152,
+ 67, 77, 33, 40, 72, 13,164, 97, 41, 24, 0, 0, 58, 12, 1,168,214,125, 36,238, 26, 44,170,175, 15, 59,113,196,205, 42,137, 14,
+ 22,224,216, 59,137, 73,176,171, 53,136,200, 98, 51,213, 75, 2,242,167, 86,221, 76, 42,145, 5, 42,168, 46, 29,213, 78,163, 42,
+ 16, 60,230, 50, 42,243,249, 18, 18,251,170, 18,111, 4, 30,160,228,122,141, 71, 19,233, 42,111, 69,183,107,112,145,182,219, 37,
+239,241,156,189,119, 91,118,169,119, 3, 20,143, 17,179, 37,155, 43,111,169, 53,105, 85,170,210,208, 57,148,210, 5,199, 87,180,
+163, 53,144,128,239,189,200, 40, 89,247,119, 16,170,219,194,167,174, 95, 16,120, 99,216, 11, 9, 94,160, 7,211,125,224, 42,220,
+240,214,234,188,157,100,223,109,175,219, 22,175,140, 41,151,191,134,156, 91,250, 68, 41,133, 41,137,143, 85,182,168, 14,158,207,
+166,253, 27,157,160, 45,183,222,221,240,212,253, 25, 45,199,171,212,118,115,136, 29,176,151, 33,247,169, 54,142,229, 80,110,122,
+ 75,110,168, 41,184,138,190, 45,181, 67,159, 26, 49, 42, 42, 67, 62, 61,152,135,139,120, 8, 14, 76, 91,137,202,221,112,234, 82,
+ 58,139,207,209,155,219, 90,149, 31, 99,247,187,115,230, 71,118, 60, 91,231,115,160,208,105,106,117,183, 80, 38,192,177,109,214,
+ 20,185,241,212,165,114,187, 24,213,110,170,156,110,100,164, 31, 22,152,242, 20,163,202, 2,101, 13,163,120,178,105,219,196, 78,
+ 41, 52,214,229,243,208, 27,116,230, 8, 34, 19,125,252,208,250,189,247,193, 60, 25, 90,149,240,199,132, 5, 93,249,190,206,228,
+ 95,175, 40,212, 76, 97,251,185, 38, 61, 63,225,181,182,194,210,210,210,213,119,139, 59, 11, 75, 75, 75, 67, 3, 11, 86,231,168,
+244,137, 50,219,159, 34,151, 78,126,123, 74,105,109, 77,122, 12,103,101,180,182, 20, 20,202,155,146,182,138,208,164, 40, 2,146,
+ 20, 10, 72,200,193,213,199, 75, 89, 4,141,193,177,247, 96, 98,222,186, 77, 45,198,165,199,114,155, 79,113,137,239,123,196,230,
+ 87, 14, 50,154,153, 32, 41, 11, 15,203,109, 77,226, 67,220,237,182,121,150, 10,178,128,115,144, 52,195, 92,219,245,176,182,149,
+122,185,103,220,245, 58,117, 38,177, 14,165, 62,137, 88,166,205,183,100,165, 18, 94,180,182,226, 54,233, 43,153,126,224, 91,159,
+ 5,155, 45,232,238,197, 88, 82,208,167,241, 10, 62,100,128,214,182, 39, 90,175,186,220, 34,237,174,239, 92, 87,189,203,114,202,
+174,179, 62,249,180,173,155, 70,114, 96, 73, 97,182,233,177,104, 55, 4, 90,205, 74,117, 39,196, 97, 70, 44,234,189, 58,155, 70,
+165,212,213,146,151,233,244,134, 89,229, 24, 36,239,229,230,133,166, 97,152,203, 44,112, 21,216,197, 98,193,245, 40, 4,130, 13,
+194,173,216,141,137,210, 0, 32,219, 9, 75,204, 10, 12, 42,165,129,253,111, 75, 29,135,199, 97,247,227,225,226,159,135, 84, 56,
+170,163,213, 95,119,172, 38, 13,219, 88,247,105, 22,125, 85,171,145, 66,203,155, 66,162,214, 18,136,138,166,123,195,149, 5, 46,
+227,166, 8,173,167, 43,148,194,220,113,158,102,153,112,164,250, 39, 17,220, 62, 92, 21, 58, 93, 58,145, 81,141, 34,185, 94,151,
+ 97,212,226,211,133,167, 80,106,170,170,149,249,112,215, 45,203,118, 92,198, 28,166,133,197,168, 51, 86,164, 85,125,241,199,121,
+ 87, 1,181,165,233, 10,109, 15,161, 74,182,220, 60, 32,109,125,201,123,215, 47,185,174, 86, 27,170, 87, 55, 43,109, 55, 45,216,
+204, 61, 29, 48, 33,205,219,106, 84,138, 75, 84, 24, 49,212,193, 12, 91,213, 70,167, 84,156,170,176, 58,201,118,122,151,204, 20,
+134,139,116,232, 92, 31,109,165,187,120,209,239,138, 92,218,235, 53,202, 30,226,110,142,227, 66,113, 79, 68,117,145, 63,115,169,
+177,233,206, 81,214,211,177,136, 85, 10,144,168, 20,183,233, 12,118,138,245, 57, 11,202,185,222, 14, 56,145,195,220,178, 86,106,
+161, 46,139,128, 74,144, 27, 78,161, 30,201,246, 67,125, 94,175,251,237,109,176,143,246,189, 67,202,133,111,239,189,175,107,245,
+235,111, 53,190,235,247,192,151, 23, 20,214,213,149,120,238,245,161,112, 90,149, 90,123,118, 93,223,110,218,116,155,146, 37, 34,
+165, 34,213,175, 92, 87,142,216, 91,119,181, 10, 5,199, 93,102, 0, 98,139, 83,155, 86,172,154, 91, 40,230,144, 74,145, 17, 79,
+169,147, 50, 58, 23,100,166,241,143,176,110, 91,118,252,155,150, 60,202,122, 85,111, 48,244,196,211,236,186,197,114,218,166, 92,
+206, 88,209,239, 59,138,199,163,207,137, 73, 87,214, 85,120,214,244,153,202, 90, 88,103,194,117, 48,100, 69, 14, 42, 91,110,197,
+ 77,226,167,194, 53, 62,224,168,214,164, 92,187,177,184,117,202, 93,207, 86,176,238,171,166,132,252, 75, 34, 52, 75,138,247,219,
+171, 22,218,178,232, 23,101, 70,124, 75, 81, 19, 90,146,100, 90,180,154,171,241, 99, 73, 98, 19,149, 8,201,195, 8,139,207, 29,
+204, 89,174, 3, 54,230, 28, 89, 84,218, 93,213,112, 83,169, 85, 8, 13,183, 62, 50,109,173,179,153, 84,126,170,109,166, 45,137,
+213, 38,111, 9,246, 59,149,202,124, 73, 44,199, 68,199, 96,199,169,183, 24, 77, 91,133, 9, 76, 55, 93,134,181,227, 28, 52, 99,
+ 65, 52,210, 44,161, 35,212, 99, 50, 88,176,141, 85,236, 90, 50, 67, 23,214,214,210, 86,214,179,139,144, 10, 77,101,201, 85, 4,
+ 92,245,183, 75,220,116, 61,133,133,239,123,246, 56,201,110, 78, 45, 54,210,143, 71,187, 69, 26,206,190,106, 23,221,159, 10,239,
+174, 77,176,164,109,229,114,157, 93,162,200,181,109, 26, 5,194,253,122,230, 66,160, 17,111,208,220,164,222, 86,170, 68,245, 41,
+ 75, 91, 85,192,134, 91,117,109,188,218, 1,107,139,222, 30, 41,208,160, 38,182,212,154, 96, 81, 98, 34,164, 83,236,138,173, 86,
+132,229,233, 73,143, 2, 77, 86,210,160,202,167, 82,150,229,102,224,167, 57, 85,155,240,177, 28,130,105,117, 4, 48,181,191, 26,
+ 67, 73,200,239, 78, 20,232,247, 93,227,184,151,181, 59,113,239,187, 58,175,186, 16,107, 20, 59,177, 20, 6,109, 25, 81, 38, 91,
+ 85,235, 26,194,177,234,148, 36, 49,113, 91, 83, 67, 13,174, 54,221, 80,228,162, 75,124,147, 24,118, 76,180,176,251,104,120,114,
+ 97, 71,129, 29,185,102, 75,134,157,116, 87,233,212,215,107,237,221,142,192,102,217,219, 23,234, 46,220,107,153, 26,125, 70, 66,
+175, 41, 86, 50,235,200,165, 73,156,220,169, 11,130,138,162, 26, 67,243,150, 16, 68, 68,166, 32,196, 67,134,204, 81,243,102,154,
+ 55, 96, 25,172, 90,225,180,141, 75,126, 89, 22, 86,190,141,141,197,203, 50,155, 12, 6,246,205, 70,202,164, 3,177,176,251,143,
+218,190,227,175,167, 96,112,231, 92,188, 65,108,253,156,237, 21, 85,234, 37,205, 77,117, 54,204, 75,162,127,188,109,197,114, 52,
+173,190,178,220,185,255, 0,131,148,235,130,242,141, 38,152,219,246,149, 21,117,198, 37, 41,160,227, 97,192,213, 50, 76,191, 5,
+ 44,199,113,212,227,232,226,211,100, 21, 21,169,244,186, 61,249, 82, 97,202,109,126,252,241,169,187, 81,118,165, 40,183,173,245,
+ 24,119, 77,250, 28,149, 70,101, 47, 81,162,201,144, 35, 61, 61,165, 56, 94,122, 73,102, 57,144,174,112,155,149,235,194,253, 54,
+254,147, 62, 77,127,114,247, 1, 75,185,109,201,150, 53,252,136,169,180, 27, 69,243,183,234,190,107,183,181, 30,208,169,151,173,
+119, 21, 76,139, 79, 23, 21, 86,150,196,154,122,162,203,114,155, 49,212, 72,121,217, 74, 76,164, 52,251,165,194,237,235, 26,209,
+179,173,109,147,172, 76,141, 81,133,182, 87,238,208, 87, 46,106,213,219, 71,163, 71,122,208,188,167,211, 39,166, 53,106,131, 47,
+109,107,104,172, 50,153,222,250,242,158,167, 46,147, 80, 97,184,166, 59, 47,172,204, 15, 66, 37, 60, 57, 12,220,152,228,168,144,
+ 77, 35, 16,197,159, 68,106,161, 88,234,102,104,191,104, 88, 1,114, 84,173,192,114,193,114,237, 84,161,152, 32, 33, 64,176, 2,
+228,155,141,128, 13,233,248,131,216, 12,110,107,245,216,236,216,210,174,155,102, 19, 51, 24,254, 12, 74,185,104,144, 74,126,174,
+102,127,139, 76,118,175, 5,151, 65,108,123,159,142,181,183,206, 74,121,146, 94, 82,148, 50, 14,180,215,116,165,219,144, 32,213,
+182,215,234, 10, 53,122,167, 42,135, 42,149,118,221,213, 70,214,169, 21,107,134,188,202,229, 86,106, 18, 4, 96,219,174,148,212,
+ 36,135,144,147, 32, 54,202,144, 24,109,164, 55, 29,160,157,199,135,107, 57, 22,193,139,100,166,162,160,236,107, 61,139, 88, 85,
+154, 99,195, 80,113,154, 42,105, 34,162,212,101, 58,174, 69,115, 39,197, 74, 10,206, 14, 19,204,123,235,144, 59,209, 19,116,167,
+ 75,115,110,234, 52,115,107,213, 46,219,210,159, 99,220,151,204, 58,236, 73,212,214, 41,117,135,213, 18,124,250, 47,142,152,243,
+ 99,207,171, 72, 8,129, 8,201,140,219, 77, 59, 90,111,154, 74,212,166,148,189, 76,174, 26,121,106,106, 29,239, 34, 68, 9, 80,
+110, 46, 9,181,201,219,183, 91,237,190,248, 60,236,234,136, 7,148,183, 95,203, 29, 10,217,141,236,135,113,237,133,155, 34,137,
+104, 94, 55, 7,131, 64,143, 79,110,109, 18,136,236,138, 4,185, 20, 96,229, 38, 91, 17,174, 7,228, 6, 36,186,204,216, 18, 99,
+188,239, 63, 35,146, 34,186,166, 84,235, 74,109,197,229,117,203,231,113,228, 81, 38, 76, 27,115, 80,181,169, 66, 35,130,109, 86,
+161, 91,167,203,170,192,109,238,102,132,198,233, 52, 53, 63, 33,184, 44,146,133,204,125, 1, 82, 99, 70,241, 95,139, 22, 83,173,
+ 37,181,115,182,167,188,183, 37,129, 6,159,182,219, 79, 95,118,221,177,236,232, 45,208,224,166,152,212, 39, 19, 54, 68, 95,130,
+ 92,184,146,164, 69, 83,145,233,254, 40, 83,113,195,107, 72,113,182, 68,151, 7,140,251,152,109,170, 91,157,184,213,165,133, 85,
+ 47,171,178,127, 33,230, 75,114,171,213, 23, 35,250,156,199, 84,159, 15,147, 25,200, 41,229,229,200, 61, 52,228,156, 45, 83, 33,
+ 46,213, 9, 12,109,184,184, 98,214, 61, 46, 54,177,183, 93,246,239,141,118,204, 17,118,208, 89,135, 93,192, 23,247,125,248,187,
+241, 61,191, 16,171, 20,120, 91, 43,100, 59, 38, 45, 50,223,155,227,110,163,143,165,182,103,212,183, 14, 41,104,204,160,206,247,
+ 98, 91,122,157, 79, 90, 99, 41,149, 50,183, 97,190,216,132,184, 46, 57, 2, 52, 39,156,210, 5, 41, 40, 66,220, 89, 66, 27,109,
+ 42, 90,220, 95,192,219,105, 72,202,150,226,212,112,218, 7, 82, 73, 32, 0, 59,247,214,204, 79,218,105, 60, 77, 67,171,238, 54,
+206,186,245, 31,112, 40,173, 83,169, 53,218, 12, 24,116,183,153,221, 11,113,130,220, 51,122, 91, 76, 85, 22,150, 26, 76, 26,164,
+146,195, 50, 28, 10, 83,241,203,235,111,199,134,228, 45,102,150, 23,179, 43,113,174,103,163, 78,220,186,172, 10, 83, 3,192,117,
+104,185,234,127,195, 25,237, 41, 32,164,174, 53,175, 72, 83, 84,104,143,114, 21,146,164,150,212, 20,190,185,198, 4,179, 46,173,
+203, 50,156,190, 58,121,100, 74, 87,131,103, 86, 97,169,159, 98, 92, 0, 11,184,125,138,176, 91,105, 32,109,107, 6,154,136,106,
+106,106, 25,213, 76,161,250, 16, 54, 3,176, 36,216, 2, 58, 17,126,183, 62,252, 48, 60, 43,109,125, 79,127,119,214,218,118,158,
+185, 44,218, 22,100,195, 85, 21,152, 78,173,176, 24,129, 33,164,215, 46, 72, 51, 89, 87,232,220,113,192,221, 34,148,242, 50,174,
+121,115,101, 55,205, 29,104,115, 82, 78,211, 25,177, 59, 3,102,236, 21,187, 50,139,108,185, 46,165, 62,173, 33,153, 53,170,245,
+ 73, 17,145, 54,114,162,180, 89,135, 17,150,162,180,148, 67,165,176,133, 61,224,176, 57,202, 21, 37,197, 41,197,149,100, 62,122,
+131,113, 6,106,185,165, 96,104,175,236,208, 11, 33, 34,197,137,182,166, 35,168,189,128, 0,244, 85, 23,220,156, 61, 80,210,154,
+104,136,127,239, 28,220,251,189, 7,243, 39,212,156, 45, 45, 45, 45, 48,227,119, 11, 95, 8, 4, 16, 70, 65,232, 65,215,221, 45,
+ 12, 12, 83, 67, 45, 53,146,219,104, 65, 61,202, 82, 1, 63,128,213, 77, 45, 45, 12, 12, 51,123,215,177,246, 78,250, 90,142,219,
+ 55,132, 15, 17, 77,169, 82, 41, 53, 88,229, 45, 85, 40,211,185, 57, 19, 46,159, 36,164,248,107,198, 2,208,160,166,221, 72,229,
+113, 10, 24,199, 21, 55, 95,128,189,229,176,101,201,126,218,136,213,251, 65, 75,139, 49,164, 82,249, 99, 86, 27,103, 36,161, 50,
+233, 82, 22, 57,221, 9,192,203, 14, 59,205,140,242,163, 60,162, 65,250,242,180, 33,192, 82,180,165, 96,247, 10, 0,143,219,170,
+147,196,127, 5, 56, 23,196,226,149, 89,229, 28,148,121,204, 74, 17, 43,169, 25, 98,168,208, 62,202, 73,169, 94, 41,209,127, 84,
+ 75, 27, 50, 11,136,217, 1, 55,183,188, 54,241,191,143, 60, 47, 87,165,200,171, 99,172,201,165,114,239, 65, 86,173, 45, 54,179,
+246,158, 61, 46,146,192,237,250,198, 41, 21, 92,216,200,174, 64,180, 88,213,177,251,198,219,222, 2,182,186,252, 11, 10,228,255,
+ 0,246, 90,178, 91,207,151,233,189,211,147, 31, 62,108,117,239,167,207,108,248, 36,222, 91,238,100,115, 87,165,127, 3,105, 10,
+113, 62, 60,170,176,241,106, 37,172,142,111,119,166, 48,172,135, 49,156,120,203,100, 12,103,174, 48,100, 58,105,148,245, 30, 99,
+ 13,130,123,231,195, 26, 33,168,236, 50, 48,211, 77,182, 63,217, 72, 31,208, 53, 83,100,223, 67,239, 15,232,107, 82,167, 52,206,
+115, 28,238,154, 50, 15,179,179, 69, 4,111, 99,246,100,120, 99, 18,149, 61,249,111, 17,244, 97,139,115, 58,250, 99,248,133, 95,
+ 67, 37, 46, 85,146,229,217, 29, 76,128,143,104, 85,150,162, 68,184,251, 81,164,210, 24,131, 14,220,200,229, 95,240,156,107,150,
+193,112,227,103,236,125, 9,184, 52,136,161,218,131,220,143, 84,106,146,130, 29,168, 84,101, 37, 56, 15, 74,120, 32, 14, 80, 10,
+130, 27, 64, 13,182, 9, 8, 72,201, 39,100,244,180,181,212,185, 94, 87,151,100,153,125, 38, 85,148,209, 71,151,101,180, 40, 35,
+134, 24,148, 36,113,160,232, 21, 70,221,110, 73,234,204, 75, 49, 36,147,142, 85,205,115, 92,203, 59,204,106,243,108,222,182, 76,
+199, 50,175,115, 36,211,204,197,228,145,207, 82,204,119,233, 96, 7, 69, 80, 21, 64, 0, 0,180,180,180,181,191,134,252, 45, 45,
+ 45, 45, 12, 12, 45, 45, 45, 45, 12, 12, 45, 45, 45, 45, 12, 12, 45, 45, 45, 45, 12, 12,104, 15, 16,151, 95, 24, 54,239, 17,123,
+ 83,103,109, 12, 84,212, 54, 75,118, 69,182, 47, 27,216,219,148, 90,131,187, 24,189,180,184,101, 92,219,132, 23, 42, 76, 82, 37,
+139,234,202,151, 77,160,210,125,241,138,135,213,181, 58,116,137,140,248, 9, 90, 64,231,117, 43,136,239,106,117,199, 89,185,105,
+117, 10, 52,219, 42, 68,189,220,218,235, 50,177, 79,135,177,151,213,106,118,216, 64,186,248,146,182,109, 10,197, 94,196,168,220,
+ 27, 33, 79,182,247, 3,109, 33,236,132,171,166,163, 88,171, 53,117,221,106,132,229, 62, 29, 72,212, 41,241, 36, 73,106, 28,131,
+ 84,132, 47, 28,201, 10,199,108,140,227, 84, 76, 88,197, 69, 69,150,202,143,115,203,215,203,250,134,165, 20, 60, 69, 77, 73, 4,
+113, 75,195,212, 85,111, 18,196, 57,143, 18,150,102,142, 70, 98,238, 24, 50,182,184,244, 70,234, 2,130, 99, 89, 13,218, 73,249,
+209, 44,195,134, 42,235,106, 36,154, 46, 37,175,163,142, 87,148,152,210,102, 8,171, 36,106,161, 35, 42,200,203,203,148, 73, 42,
+ 49, 44, 87,154,209,139, 36,116,252,158, 18,111, 54,228,113,174,250,120,178,217,207,122,222, 77,206,102,216,218,235, 50,169,182,
+183,141, 11, 96,170,118,165,187, 86,174, 81, 46, 93,174,102,187,109,151, 87,181,116,241,125,223,117,200,235,187,229, 59, 34,206,
+174, 87,232,109, 83,149, 52, 24,150,188,232,144,226,189,121,221,222, 37,189,160,182,229,237,191,208,108, 59, 58,250,169,203,183,
+173,190, 38,157,179,108,216,155, 3, 85,170, 88,180,107, 78,206,216,154,213,197,195,166,226,216,251,164,154, 35,177,247, 99,117,
+ 46, 45,225,139,109,211,166, 90,113,234, 19,223, 67, 85,233,113, 87,111, 66, 52,228,205,149,220, 51, 22, 58,149,204, 89, 65, 80,
+ 24, 4,167,168, 30,131,211, 95, 12, 72,196,133, 22, 91, 42, 29, 1,229, 25, 3,211, 75,197,197, 20,136,176,163,240,229, 36,235,
+ 18,176, 33,145, 44,210, 60, 84,241,180,133, 86, 48,170, 73,131,152, 2, 42,144,206,124,197, 76,130, 93,105,120, 70,177,218,103,
+143,138, 43, 96,121, 93, 72, 43, 36,132,172,105, 45, 76,169, 24,102,149,157,128, 21, 28,178,100,103, 82,136, 60,129,132, 70, 29,
+ 28,224,214,249,226, 54,181, 83,222,219, 55,136, 39, 43, 85,241,100, 94,246,107, 27,119,127, 86,246,245,141,190,145,120, 91, 23,
+102,204,109,181,247, 91,109,168,212,184, 17,169,213,150, 40,215,245,201,118,208,253,234, 19, 64,161,116, 5, 67,154,165,207,141,
+ 37, 70, 41, 62,217,106,175, 29, 60,104,113, 79, 93,164, 80,248, 84,226,128,108,102,199,212,235,214, 38,211,193,135,178, 27,169,
+ 46,147,113, 46, 44,255, 0,115,185,183, 61, 15,199,182, 20,196,245, 87, 38,211,216, 92, 23,154, 60,130,143, 6,156,148,254,148,
+200,113,217,206, 33,150,155, 57, 67,105, 73,237,144, 49,211,211, 67,187, 77,128,242,138,221,136,195,139, 61,212,180, 5, 19,247,
+157,111,240,175, 28,175, 11,103,243,113, 12, 25, 5, 53, 85, 91, 66,177, 70,164,152,227,133,180, 34, 75, 44,105, 26,133, 87,155,
+ 75, 19,164, 5, 65, 35,170, 0,166,216,110,227, 15, 15,159,139,248,110, 14, 25,168,226, 74,186, 58, 36,153,165,149,192, 89,101,
+157, 4,143, 36, 48,202,242,146,204,144,234, 80, 53, 18,206, 99,141,156,150, 92,126,116,252, 63,207,246,190,240,179,111, 84, 45,
+109,128,218, 78, 44,118,210,133, 86,172, 61, 95,169,195,163,240,195,113, 77,114,125, 93,248,145, 32,174,108,185,213,189,175,149,
+ 33,245,136,112, 98,182,132,169,210,134,210,214, 16,148,229, 89,216, 95,229,123,244,129, 63,242,126, 52, 63,251,173,204,255, 0,
+254, 61,169,231,253, 81, 76,255, 0,200, 99,127,246, 73,254,173, 47,170, 41,159,249, 12,111,254,201, 63,213,169,173, 79,140,244,
+149,147,203, 85, 89,225,206, 77, 85, 85, 49,212,242, 73, 10,188,142,118,221,157,162, 44,199,110,164,147,211,211, 16, 58, 95, 2,
+107,104,105,226,164,162,241, 71, 60,163,164,128,105, 72,162,157,227,141, 23,246, 81, 18, 80,170, 58,236, 0, 27,226, 37,155,115,
+253,212,126, 49,125,153,188,113,237,174,247,198,222,153, 59,193, 46,175, 96, 72,219,250, 22,228,109,202,182,202,225,187,172,138,
+ 21, 82,137,114,222,246,157,180,203,246,205, 29, 85, 20,205,129, 74,154,216, 8, 67,198, 83,220,180,197, 40, 34, 90,211,174,108,
+123, 29, 56, 93,226,149, 28,122,109, 85,237, 78,219,189,198,219,219,123,106,234,245,201,187,145,114,220,214,181,114,217,129, 10,
+149, 34,223,173, 81,102, 90, 18, 69,110, 36,113, 58,173, 81,126, 98, 97,251,154, 2,223,101, 46, 57, 49, 77,165, 17, 22,226, 63,
+ 64, 22, 96,195,143,159, 6, 51, 45,115, 12, 43,145, 0,100,124,245, 69,170, 85, 61,151,140,134,162, 50,135,137, 36,184,148, 36,
+ 40,147,243,198,154,161,241,114,174,151, 42,226,204,162,135,135, 40,168,169, 56,157,157,130, 68,186, 35,166,230,211, 71, 75, 40,
+ 72,213, 66, 72,165, 35, 14,129,130,132,145,152,182,181, 58,112,239, 63,130,212, 85,153,191, 6,103, 85,252, 79, 95, 95, 91,194,
+ 43, 26,151,149,181,201, 87,201,170,146,174, 18,242,179, 23,141,131,202, 81,202,150, 47, 18,162,175, 45,134,178, 91, 28,254, 11,
+ 94, 39,235,248,104,231,255, 0,249,185, 70,127,110,177,109,192,143, 34, 93,135,122,196,136,195,210,165, 74,180,238, 40,241,163,
+ 71,105,111, 72,145, 33,234, 68,198,217, 97,134, 91, 73, 83,175, 45,197, 37, 41, 74, 65, 82,148,160, 0, 36,235, 46,210, 35, 32,
+131,216,244, 58,169, 35,115, 27,163,129,114,132, 31,220,111,139,166, 68, 18, 35,161, 54, 14, 8,253,226,216,132, 15,176,167,134,
+142, 35,182,159,142,131,114,110,159, 15,251,217,182,150,232,218, 43,214,152,107,251,129,181, 87,213,153, 69,250,202, 85,110,207,
+118, 45, 59,235, 91,142,131, 25,143,127,113,168,178, 84,219, 62, 39,136,180,199,112,165, 36, 33, 68,117, 47,219,205,195, 55, 28,
+251,238, 54, 30,243,225,142, 29, 70,225,177,182, 89, 85,139,166,109,187, 96,220, 82, 40,155,167, 77,220,121,146, 24,110, 13,239,
+ 72,138,151, 99, 46,172,220, 26, 44, 70, 24,129,245,108,167, 42,145,159,169,206, 83,113, 11, 78,151, 83, 34,132,192,132,135, 60,
+100,198,101, 46,147,146,224, 64, 11,207,219,162, 84,132,172, 20,173, 41, 82, 79,112,160, 8, 63,113,213,149,152,120,159,153, 87,
+113,173, 39, 27,140,170,149, 43,105, 34, 16,136, 36, 15, 44, 37,116, 73, 27, 19,114,172, 24,164,140, 1, 7,202,108,119,232,106,
+156,179,194, 76,171, 47,224, 42,222, 1,108,226,174, 74, 26,217,140,230,162, 50,144,206,175,174, 41, 20, 11, 43,161, 85,120,148,
+144, 65,212, 46, 54,216,136, 25,208, 61,170, 30,218,237,168,164, 39,110,107,112,119, 42,161, 86,167,180,154,124, 73,123,145,195,
+123,147,175,152, 73, 79, 52,102, 82,236,185, 86,131, 14,213,229, 7, 80,172, 61, 80,106, 99,238,173, 39,196,113,206,163, 77,149,
+151,192,119,180,211,218, 97,189, 44,110, 46,255, 0, 64,220,170, 74,107, 38, 36, 90,246,237,239,133, 26, 85,175, 26,139,111, 48,
+234,221,106,157,101, 88, 47,198,128,235,144, 71,143, 49,200,112, 41, 20,248,116,144,252,135, 28,117,248,190, 58,222, 95,232, 6,
+237, 2,142,250,185,220,129, 29, 74,245,240,211,253, 90, 50, 61, 62, 20, 79,251,222, 43, 45, 99,205, 8, 0,254, 56,212,132,120,
+202,153,122,212, 79,195, 92, 13,149,240,246,109, 84,165, 90,170, 40,213,156,106,234, 81, 86, 56,128,223,205,165,153,208,176, 5,
+209,237, 99, 26, 62, 5,190,100,244,176,113, 87,136, 57,191, 19,100,212,110,174,148,114,202,202,135, 79, 64,238,210,202, 78,215,
+ 82,200,169, 32, 82, 66, 58, 94,248,215,190, 20,248,114,178,184, 89,217, 43, 15,102, 44, 56, 70, 37,191,100,208,163,210,163, 45,
+222, 85, 76,168, 74, 82,220,153, 87,173, 84,156, 72, 1,218,172,250,188,153,211, 37, 41, 41, 74, 21, 34,123,133,180, 33, 28,168,
+ 78,200,105,105,106,151,168,168,158,174,121,234,170,101,105,234, 42, 93,164,145,216,221,157,220,150,102, 98,119, 44,204, 73, 39,
+185, 56,189,233,169,169,232,233,169,232,233, 97, 90,122, 90, 84, 88,227,141, 5,149, 35, 69, 10,136,160,108, 21, 84, 0, 7, 96,
+ 48,180,180,180,180,142, 23,194,210,210,210,208,192,194,210,210,210,208,192,194,210,210,210,208,192,194,210,210,210,208,192,194,
+210,210,210,208,192,194,210,210,210,208,192,194,210,210,210,208,192,194,214, 53,117,217,246,213,239, 67,171,219,183, 69, 34, 21,
+ 94,149, 91,165, 79,163, 84, 24,146,195,107,113,112, 42,113, 93,135, 45,182, 95, 41,231,142,178,203,206,114,173, 5, 42, 66,136,
+ 82, 72, 80, 7, 89, 46,150,178, 24,169, 5, 77,136,238, 48, 8, 7, 98, 46, 49,196,171,235,133,221,241,219,202,252,170, 5, 5,
+186,133,255, 0,110, 54,227,142, 91,183, 24,180, 43, 87, 5, 89,218, 66,156, 34, 28, 91,130,109, 22,174,210, 93,171,176,128, 27,
+113,199, 24,105,215,249, 3,170, 47, 40,169,247, 49, 56,124, 52,111,189,235, 81,137, 67,173, 91, 85,184,244, 57,175, 52,212,250,
+127,240, 58,177,105,211,231, 52,181, 0, 89,174,220, 21,122,163,202, 77, 11,186,164,199, 97, 13, 46, 66, 17,224,173,197,178,183,
+ 24,123,188, 58, 90,146,167, 20, 85,172, 74,141, 2, 59,168,182,162, 91,115,107, 92,168, 54,223,184,232,119,216, 13,176,222,114,
+248,203, 92, 57, 11,126,155,126, 7,249,225,157,217,141,156,160,236,245,178,138, 85, 60, 53, 50,183, 53, 12, 57, 94,173,134, 82,
+202,230,190,210, 57, 90,139, 21,176, 63,193,105, 44, 36,169, 17,217, 29, 0, 37,106,202,214,163,167,139, 75, 75, 81,233,166,150,
+162, 87,154,103, 50, 73, 33,185, 39,231, 96, 58, 0, 54, 3, 97,182, 55,149, 85, 20, 42,139, 42,244,194,210,210,210,210, 88, 54,
+ 22,150,150,150,134, 6, 32,111,253,251,111,253, 25,127,246,206,255, 0,117, 13, 84, 31, 77,167, 61,189,153,157,251,127,142,111,
+251,168,234, 6,201, 25, 61, 71, 79,216,116, 66, 7, 92,227,160,237,253, 29,191, 61,180,202,213,149, 2,195, 94,231,220,191,150,
+ 52,249,178,126,215,224, 63, 44, 79, 25, 63, 77,151, 39,255, 0, 6,119,218,127,150,103,111,251, 41,107,223,247,236, 95,244,103,
+255, 0,219, 47,253,212,245, 4, 4, 2, 7, 95, 63, 47,223,170,169, 25, 61,186,122,250, 31, 81,243,210,126,219, 83,255, 0, 19,
+240, 95,203, 24,230,201,127,181,183,192, 98,119,163,233,176,103, 24,246,104, 30,163,167,248,229,121,231, 24,255, 0, 53, 62,250,
+168, 62,154,225, 35,175,179, 71, 31, 47,229,149,254,234,154,130, 42, 65,207, 67,215,212,255, 0, 96,209, 9,238, 1, 57,207, 66,
+113,249,198,136,213,245, 67, 97, 37,143,253, 43,249, 99, 60,217, 45,187,126, 3,242,196,238, 7,211, 87,201,199,247, 52,251,255,
+ 0,207, 39,240,255, 0,146,174,190,171,233,171,114,130,127,185,167,159,151,242,200,255, 0,117, 93, 65, 69, 9,235,159,151, 79,
+207,231,190,171, 4,115, 15,151,207,215,229,233,211, 26, 76,230, 21,118, 63, 93,254, 85,254,156, 37,237, 18,245,215,248, 15,203,
+ 19,165, 79,211, 89, 73, 4,159,102,170, 83,233,158, 50,135,207,254,106,191, 45, 18,215,211, 80,241, 19,205,253,205, 94, 80,123,
+127,142, 62,115,255, 0,101,109, 65, 56, 67,100,168, 18,128,163,223,185,239,242, 25,237,223, 87, 54,211,203,202, 0, 0,118, 29,
+ 49,229,158,131,238,210,103, 49,173, 22,250,254,191,225, 79,233,198, 13, 68,189,155,240, 31,150, 39, 74,159,166,146, 79,127,102,
+191, 47,111,249, 99,122,255, 0,213, 99, 85, 71,211, 69,207,250, 54, 71, 94,199,249, 98,244,199,175,249,172,106, 11,137, 0,145,
+159, 63, 79,199,240,209, 41, 7,203, 0,118, 57,237,143, 77, 96,230, 85,191,241,191,202,159,211,140,123, 76,223,183,248, 15,203,
+ 19,158,254,253, 11,254,141,175,251, 98,127,186,206,189,143,166,127,144, 15,247, 54,241,159,249,225,255, 0,186,214,160,208,144,
+ 8,234,123,244,199,237,253,218, 36, 39, 29,124,250,119, 29,189,116,145,205, 43,199,251,255, 0,242, 39,187,252, 56,199,180,205,
+109,218,196,123,135,229,137,201,143,166,116, 79,250, 55, 15,111,252,240,187,127,217,107, 94,199,211, 56, 39,191,179,119, 29, 51,
+254,120, 95,111,127,241, 91,233,219, 80,111, 66,135,111, 60,254, 7, 24,209, 8,238,125, 72,239,223, 31,119,231,182,138,115, 90,
+253,254,190,214,255, 0, 10,127, 78, 11,237, 51,116, 50, 88,250,233, 31,150, 39, 26, 62,153,166,112, 71,179,131, 57,237,142, 48,
+ 63,221,115, 94,135,211, 49, 57, 0,251, 55,241,156,227,252,112, 51,219,254,171,154,131,194, 82, 70, 48, 64,232, 51,143, 33,242,
+252, 52, 66, 49,158,191, 96,244,255, 0,142,136,115,108,195,114, 42, 46, 7,248, 19,250, 48, 95,107,159,246,255, 0, 5,252,177,
+ 56, 65,244,203, 15,159,179,135, 31,245,191,207,255, 0,149,221,122,254,252,175,166,127,185,197,246,143,229,127,219,211,254, 75,
+218,132, 10,112, 10,114,160, 9, 29, 7,168, 61,127,167, 94,243,144, 72,238,122,100,244,207,207, 69,253, 47,152,255, 0,204,127,
+146, 63,233,198, 13, 93, 64,255, 0,121,248, 47,229,137,189,127,126, 89,255, 0, 71, 16,255, 0,239,127,229,235,254,107,186, 95,
+223,150,127,209,197,255, 0,107,255, 0,247, 93,212, 32,130, 70, 78, 83,156,121,142,227,167, 97,235,175,129, 39, 36, 96,158,227,
+228, 15,174,116, 63, 75,230, 63,243, 31,228, 79,233,198, 61,174,163,175, 50,254,235, 47,229,137,191,255, 0,126, 86,112, 79,247,
+ 56,187, 99, 63,227,127,235,216,255, 0,154,238,144,250,101,100,228, 15,103, 9,200, 56,255, 0, 59,241,143,159, 95,228,189,168,
+ 65, 28, 19,201,158,160, 12,125,189, 71, 93,124,228, 56, 61, 58,142,199,215,215, 67,244,190, 96,127,246,143,242, 39,244,227, 34,
+170,163,188,157, 61,195,242,196,224, 26,250,101, 42,117,105, 66,125,155,238,173, 74, 90, 16,134,216,226,229,114, 31,117,110, 45,
+ 45,180,204,120,237,112,184, 87, 34, 67,142,173, 8,109,180, 2,183, 28,113, 40, 64, 42, 80, 26,145,125,139,237, 28,187,106,123,
+107, 97, 92,219,161,195,163, 59, 99,184,215, 61,173, 2,228,186,182,189,141,220, 55,106,172, 25, 85, 68,137, 81,173,154,141,204,
+118,206,154,106, 53,248,244,231,225,154,131,105,167, 50,136,178,214,252, 70,220,146, 35,151,215,249,251,123, 18,120, 79,167,111,
+111, 18,114,247,186,251,163, 49, 85,218,222, 24,163,210,111, 53,194,156,128,245, 62,228,222, 74,163,175, 29,169,183,157, 96,172,
+ 9,108, 83,222,131, 80,184,101, 52,174,132,209, 41,225, 89, 75,196, 25,105, 85,110, 39,101, 73,126,161, 41,197,174, 75,239,169,
+114,139,171,241, 63,239,176,162,251,170, 86,121,157, 65, 89,113, 67, 7, 35,169, 4, 18,115, 82,113,247,137,217,238, 79, 87, 22,
+ 91,147,230, 34, 26,136,198,185,156, 69, 79, 33, 23,221, 80, 44,145, 56, 6,222, 98,116,157,153,122,110, 71, 99,125, 27, 60, 13,
+161,241, 3, 47,175,226,174, 50,162,122,236,146, 71, 48, 81, 64, 36,150, 14,107, 70,214,150,114,244,239, 20,133,117,222, 36, 93,
+ 65,110,172, 77,203, 45,186,186,215,180, 61,151,139, 72, 78,210, 40, 56,230, 50,147,125, 47,149, 37, 77,151, 65,231,254, 5, 97,
+ 72, 9,229,201,242,231, 29, 51,240,235, 38,139,199, 80,146,160,145,181,193, 5,104, 75,168,255, 0,223,202, 78, 90, 39,195, 82,
+214, 13,164, 11,120,116,164, 96,142,161, 65, 94,120,215, 37, 97,212,227,199,149, 78, 9,151, 17,105,146, 42, 43,109,228,184,158,
+ 66,150,152, 96,162, 49, 81, 60,133,229, 15, 16,124, 93, 73, 25,192,198,117,127,135,119,198,133, 85,181,154, 92,152,232, 50, 28,
+186,224, 45, 77,133,168,134,145, 77,106,160,134,156, 25,228,241,210,136, 43, 91,107, 60,205,168,199, 90, 80, 50,188, 26,248,120,
+191,199, 91,223, 62,222,224, 91,217,168,122, 27,111,255, 0,163,123,205,183,183,173,183,183, 70,215,125, 26,252, 47,211,253,139,
+131,216, 17, 28,143,189,110,104,215, 17,164,174,118, 53,123,111, 17, 95, 80, 78,224,219, 29,102,143,198,144,125,124,131,109, 74,
+ 72, 74, 85,145,120,165,105,198, 84,135, 7, 50,109,142,133, 46,164,167, 31,102,112, 78, 53,145,195,226,200, 74,117, 13, 42,195,
+ 67, 36,164, 41,197, 27,185, 11, 13, 21, 41, 73,194,147,252, 30, 10, 94, 8, 28,197, 41, 32, 5,103, 39,166,121,115, 2,240,167,
+ 70, 20, 80,180,187,134,229,185, 73,145, 29,134,150,242,101, 73,157, 30, 64, 97,134,152, 42,230,117,245, 61, 19,152,140,164, 39,
+ 42, 42, 1, 32,105,211,165, 85, 16,235,177,228, 37,200,205, 55, 48,170, 47,130,211,169,144,168,175,186,194,157, 76, 57, 13,129,
+240,203, 11,104,243,140, 39,147,168, 74, 84, 64,202,195,197,222, 56, 99,182,126, 45,113,183,178,209,131, 98, 7, 66,105,253,247,
+233,115,110,128, 3,138,247, 55,240, 35,129, 40,195, 21,225,118,129, 72,107, 19, 85, 94,119, 82,194,219,213, 27,146,171,175, 96,
+ 71,152,124, 11,113,237, 58,246,213,110,191,179,158,220,176, 55, 74, 7, 3, 3,126,182, 34,238,121,155,106,229,220,202, 87, 17,
+ 78, 89, 19,118,199,113,165,190,239,212,246,205,239,105,183,176,245,193, 6,220,171, 67, 74, 62,167,174,138,129,141, 46,106, 28,
+166,201,143, 6, 89,138,153,124,121, 63, 76,188,131,211,217,192, 8,233,212,113,129,228,124,255, 0,205,115,211, 93,240,187,108,
+ 11, 23,121, 44, 27,215,104,183, 62,212,167,238, 22,218,110, 61,183, 91,177,239,203, 66,160,208, 85, 46,224,160, 85, 98, 2,253,
+ 61,213,161,121,131, 48, 56,162,244, 73, 72, 34, 68, 57,212,248,242,227, 45,183,153,109, 73,252,231,120,230,246,106,239,183, 6,
+ 60, 82, 94,220, 62, 83,108,205,193,221, 91, 81,182, 13,241,179, 87,213,187,104,220, 55, 36,155,231,104,106,242,164, 10, 21, 78,
+166,154, 13, 41,239, 10,232,165,186,219,212,154,235,124,169,228,168,210, 87, 32, 1, 30,100,114,171, 79,131, 60, 72,204,115,136,
+ 37,165,205, 43, 2, 87, 83,141, 66, 67, 28, 72,146,161, 61,172,129, 53,165,192,178,216, 50, 16, 84, 54,151,115,201,126, 41,240,
+ 67,240,133, 90, 87,229,108, 70, 77, 84,193, 66, 19,169,160,115,246, 86,238, 90, 66,143,111, 41,114, 72,109,181, 29, 64, 44,156,
+255, 0,191, 47,234, 71,247, 56, 71, 65,159,243,192,245,237,255, 0, 37,221,124,254,252,192,255, 0,251,184, 58,127,233,129,251,
+191,146,230,161, 89, 94,176, 47,187, 81,114, 17,117,216,247,149,174, 99,171,195,147,252, 35,181,171,244, 20,198,115,152,128,219,
+235,171,211, 88, 13, 56, 84, 8, 9, 81, 4,144, 64, 7, 88,123, 74, 75,159, 19, 69, 14,164, 21, 0,180, 45, 46, 36, 20,146, 20,
+ 9,109, 68, 2, 15,124,246,212,249, 51,218,185, 55,142,181, 92,123,132,103,248, 46, 42, 15,110,150,246, 51, 0,111,208,133,191,
+238,181,241, 56, 81,244,203,137,239,236,225,192, 29,201,226,255, 0,215,254,171,186,248,126,153,120, 29, 15,179,135,175,203,139,
+254,159,143,242, 93,212, 32, 71,158, 48, 9,235,223,204,253,191,118,188,167, 39,161,193,199, 83,242, 36,159,221,165,127, 75,230,
+ 63,243, 31,228, 79,233,193,189,170,162,223,222,111,255, 0, 72,252,177, 56, 1,244,203,201, 56, 30,206, 14,191,250, 95,255, 0,
+186,238,190, 43,233,152, 4,128,127,185,195,159, 80, 56,191,234, 62,223,241, 93,212, 32,142,124,128,239,248,116,243,251,245,224,
+ 2, 84,115,211, 3,186,122,117, 63,111,200,157, 15,210,249,143,252,199,249, 19,250,113,159,106,159,254, 39,224, 63, 44, 78, 11,
+251,242,241,128,127,185,197,247,127, 43,254,191,183,133,221, 47,239,203,198, 79,253,206, 35,129,231,252,175,186,125,255, 0,226,
+187,211, 80,130, 66, 58,149, 12,115,116, 4,159, 63,159,111,206, 53,240,167,226,206, 58,142,135, 29,189, 58,232,126,151,204,127,
+230, 63,200,159,211,129,237,117, 31,183,248, 47,229,137,190, 15,166, 96, 9, 35,251,156, 36, 99,204,241,125,223,236,255, 0, 21,
+237,123, 31, 76,184, 28,127,220,226,239,156,127,141,247,167,127,249, 47,106, 16, 24,207,151,108,247,244,199, 92,126,124,181,244,
+117,192,232, 61, 63,183,166,135,233,124,199,254, 99,252,145,255, 0, 78, 49,237, 85, 23, 31, 89,248, 47,229,137,191,143,166, 88,
+ 79,250, 56,122,245,233,252,175,255, 0,163,252, 87,122,235,233,250,101,100,119,246,112,227, 63,243,191,235,248,127, 37,221, 66,
+ 19, 3,190, 50, 71, 94,159,213,159,150,190,247, 32,249,119,193, 25,253,190, 93,244, 63, 75,230, 63,243, 31,228,143,250,112, 61,
+170,163,254, 39,224,191,150, 38,238,126,153,113, 31,232,224, 56,245,254, 87,248,253,159,201,119,166,169, 43,233,153, 17,254,141,
+252,140,227, 63,203, 3, 30, 93,255, 0,205,115, 80,137, 32,156,156, 0, 51,142,224,117,245, 61,123,245,213, 5, 32, 17,128, 51,
+158,253,127, 63,145,172,254,151,204, 44,127,180,111,255, 0, 68,127,211,140,251, 84,255, 0,183,248, 15,203, 19,121, 63, 76,212,
+130,113,236,221, 39, 7, 31,231,129,248,255, 0,201,111, 95, 15,211, 55, 35,183,179,120, 30,153,255, 0, 60, 47,217,254,107,125,
+245, 7,245,128, 51,129,133,119,198, 14, 62,255, 0, 77, 10,172,140,244, 29,122,244,245, 31,111,111,237,209,151, 54,175,239, 83,
+123,255, 0,129, 63,167, 25,246,169,251,191,224, 63, 44, 78, 33, 95, 76,228,167,253, 27,185, 30,191,203, 11,253,214,245, 72,253,
+ 51,220, 28,127,115,115, 63,245,194,255, 0,117,175, 77, 65,216,247,233,128,113,149, 30,227, 30,127,111,150,188, 16,112,114, 0,
+207, 92, 14,248,249,244,232, 59,232,227, 53,175, 32, 30,127, 95,240,167,244,224,235, 81, 49, 23, 50,126, 3,242,196,226, 85,244,
+208, 57,127,209,181,145,235,252,176,255, 0,221,103, 84,207,211, 67, 35,253, 27, 63,135, 24,191,238,177,168, 57, 45, 35, 56,193,
+193, 29,252,191, 31, 95,234,208,235, 73, 57,230, 30,125,255, 0,163, 74, 46,103, 90,127,223,127,149, 63,167, 0,212,205,183,155,
+175,184,126, 88,156,137,250,105, 24,200,254,230,199,108, 99,252,113,123,255, 0,217, 99, 84,213,244,210,249,127,209,175,159,250,
+227,126,239,228,175,168, 52, 41, 61, 72, 62, 89,255, 0,142,168, 41, 56, 62,164,103, 31,126, 58,232,227, 50,173,255, 0,141,127,
+251, 83,250,113,145, 81, 41,232,255, 0,128,252,177, 57,179,244,211,113,219,217,173,147,233,252,177,255, 0,221, 95, 94, 15,211,
+ 80,198,127,238,106,246,242,254, 88,253,127,254,213,181, 6, 5,142,164,147,229,220,116,200,251, 71, 97,211, 84,150, 6, 51,159,
+179,211,246,104,227, 48,172,218,243, 94,253,244,175,244,227, 62,209, 55,237,254, 3,242,196,231,207,211, 85, 32,103,251,154,121,
+199,252,242,113,255, 0,229, 87, 84,149,244,214, 72,255, 0, 70,150, 71,254,153, 61,191,236,169,168, 45,169, 56,237,219,247,143,
+ 95,191, 67, 44,117, 35, 3,175, 92,104,195, 48,171,190,242,237,255, 0, 74,254, 88, 56,158, 75,253,187,253,195,221,238,196,233,
+215,244,215,249, 15,254, 13, 12,143, 95,229,149,251,191,146,159,174,168, 31,166,202, 57,185, 71,179, 56,159, 60,255, 0, 44,190,
+159,179,133, 62,250,130,147,205,243,116, 35,207,203,167,159, 76,103,203,250,244, 42,153, 60,221,200, 3,183,150, 62,206,158,154,
+ 88, 86,212,216,125,109,255, 0,237, 95,203, 6,231, 73,183,159,240, 24,157,183,247,236,196,140,143,102,104,199,110,188,102,224,
+231,211, 31,201, 71, 94, 15,211,105,229,239,236,204,199,253,115,191,221, 71, 80, 71, 82, 0,206, 51,208,227,167, 94,222,154, 25,
+105, 72, 7, 35,174,124,242,122,252,243,246,104,235, 89, 57, 27,203,191,192,126, 88,199, 58, 77,183,189,253,195, 19,188,254,253,
+183,254,140,191,251,103,127,186,134,150,160,120, 80, 60,142, 63,111,239,210,209,253,170,163,254, 39,224,191,150, 13,205,147,246,
+191, 1,249, 99,234, 65, 0, 3,249,235,162,146, 15, 64,123,244, 31,156,106,138, 70, 79,203,207,243,246,232,132, 12,159,179,175,
+223,157,105, 22,185,191, 75,116,194,120,174, 1, 61,189,113,249,249,106,176, 0, 96,121,121,254,253, 83, 70,122,244,200, 36, 12,
+231,183,231, 58,174,144, 14,115,158,131, 61, 52, 76, 12,123, 74, 74, 73,234, 49,249,252, 52, 66, 7, 76,250,254,204,106,130, 50,
+ 71, 92,224,158,153,235,223,231,231,253,154, 41,180,246, 7,203,169,252,253,186, 65,141,205,241,131,176,191,166, 43,163, 29,135,
+197,143, 79,159,217,162,144,140,142,131, 3,207,237,253,231, 84, 17,208,244, 3,175,125, 20,140,253,223,191, 68, 98, 69,192,194,
+ 36, 91,248,227,210, 7, 98, 79, 83,230,122,244,253,253,180, 72,193, 3,207,211,167,159,110,218,164,145,147,246,117,209, 9,237,
+140,128, 1,200,251, 71,223,219, 73, 49,185,233,108, 99, 21, 18, 0,193,193,235,223, 61,241,233,162, 83,140, 14,157, 60,134,124,
+191,118,168,164,115, 31,219,247,116,237,162, 80,158,163,167, 65,235,162,147, 97,115,219, 4,244, 23,177,255, 0,199,207,250, 98,
+170, 64,242, 3,229,162, 82, 9,192,249,119,249,252,245,118,183, 45,171,130,238,172, 83,173,203, 86,135, 85,184,238, 26,180,164,
+196,164, 80,104, 52,233,117,122,213, 90, 99,129,106, 68, 58,109, 46,158,203,143,206,146,164,161,100, 33,180, 40,242,182,165, 16,
+ 2, 73,213,222,187, 99, 94,182,156,151, 98, 93, 54,117,215,108, 74, 96,148, 63, 30,227,182,235,180, 39, 90, 90, 78, 20, 28, 77,
+ 82,158,215, 41,230, 7, 90,109, 60, 43, 32,137,165, 81, 43, 11,133, 36,106,181,237,123,117,183,107,224,250, 36,229,180,162, 54,
+ 49, 41,179, 56, 83,164, 27, 94,197,173,164, 27, 88,218,247,182,248,198, 80,144,123,128, 8,207, 65,220,156,249,122,157, 86, 70,
+ 62, 33,143,179,215,239,252, 63,110,188, 32, 18, 50,217, 14, 1,220,161, 73,115,211,185, 65, 56,237,162, 27, 73, 86, 58,128,125,
+ 7,127, 95, 61,101,136,223,126,191,127,195, 26,250,131, 11,131,127,120,239,138,168, 73, 56,233,212, 12, 30,190, 64,234,179,125,
+ 79,108,128, 65, 3,191,221,251, 53,245, 40,236, 58,103,190,122,253,191,187, 85,144,140, 43,169, 3,207,228,114, 15, 95,217,164,
+240, 49, 84, 39, 42,193,232, 59,129,129,148,140,118,207,225,175, 74,108,245, 4,242,143, 47, 81,233,175,160,149,103, 24, 10,245,
+ 30, 99,243,231,175, 67,174, 2,178, 51,230, 48,123,121,159,195,246,235, 24,199,195,174, 40,165, 56,206, 85,212,156,142,157,254,
+204,246,215,148,164, 2, 50,163,223,238,235,242,243, 58,172,224,201, 29,122,122,142,157, 51,140,159,151, 93, 92,168,148, 58,189,
+195, 84,167, 81, 40,116,202,141,102,177, 88,152,213, 58,145, 73,165, 65,153, 85,171, 85,170, 18, 20, 16,196, 10, 77, 42, 3, 46,
+ 72,169,206, 90,136, 8,101,134,214,226,179,209, 58,195, 50,162,150,118, 10,171,185, 39, 96, 48, 91,133, 2,231, 97,181,254, 54,
+183,239,197,153, 93,240, 57, 64, 30,106, 3,174, 51,128, 61, 53,233, 88, 67, 69,215, 84, 27,101, 56,241, 29, 89, 8,105, 40,238,
+165, 21,172,129,140,103, 82, 39,224,247,232,242,113, 5,186, 44,209,175,126, 45,110,120,252, 41,109,245, 65, 45, 76, 98,212,168,
+192,137,115,111,205,126, 34,210,167, 80,219, 22, 95,189, 38, 13,132,167, 80,143,133, 85,151,221,152, 18,178, 69, 47,152, 99, 82,
+ 25,217,126, 4,125,158,220, 32, 70,111,248,177,225,226,214,187,174,202, 84,112,204,221,208,222,132,198,220,171,212,205,121,104,
+ 12, 72,241,238, 54,151, 77,163,211,164, 45, 56,103,220,169,241,154,109, 74,229, 79, 82, 64,134,103, 28,115,148,101,101,145, 24,
+213,204,187, 89, 14,215,247,144, 9,248, 27, 91,212,226,216,224,191, 5,184,251,142, 12,111,150,229, 38,134,142, 80, 8,158,164,
+ 20, 4, 18, 0,100,140,217,216, 94,195,204, 99,185,176, 23, 36, 3,170,254,203, 46, 26, 46, 77,165,224, 39,102,233,180,203, 98,
+123, 55, 94,240,135,247,210,247,144,229, 50, 82, 28,149, 42,249, 17,191,130, 80, 39,169,184,229, 79,197,133, 96,194,183,154,100,
+100, 99,197,117, 73, 37, 43, 81, 86,234, 87,236,203,238,132,204, 33, 46,221,170, 32,138,139, 45, 45,243, 6, 98, 99, 20,165,137,
+143,123,195,179, 60, 34, 27, 65,240,249, 15, 57, 79, 42,214, 17,130, 72, 35, 99,155,223, 42,234,221,136,202,101,194,143, 66,171,
+184,105,112,211, 76, 5,132,211,101,181, 28,123,180,100, 71, 82, 83,238,168, 82, 80,227, 9, 67, 73, 8, 14, 54,132, 97,180, 20,
+130, 37, 39,125, 42,234,171,170,153, 34,124,151,131,206,170, 19, 32, 54, 57,101,207,141,200,137,172, 48, 57,190, 37, 8,222, 27,
+165, 60,170, 39, 42, 9, 10,109, 42, 35,158,243, 89,104,243,106,250,186,249, 38,156,203, 86,236,231,104,202,139,157,149, 87, 85,
+236, 1, 10,190,110,130,198,230,248,244,231,129,168,248,183,129,184,107, 38,225,202, 14, 30,163,155, 47,200,105, 99, 77, 38, 89,
+121,146,114,215, 68,146, 59, 8,236,178, 22, 87,121, 1, 82, 69,181, 95, 73, 7, 26, 81, 90,169, 61, 79,168,208,167,204, 91, 44,
+184,170,148,168, 83, 66, 11,141, 70,124, 78,167, 84, 35, 51, 29,198, 66,130, 11, 8,121,168,165, 36,146,181, 41, 14, 44, 21, 40,
+224, 88,100, 92,178, 84,252, 41, 12, 58,134,169,236,223, 20, 56, 17, 31, 91,158, 31,213,209,106, 45, 85,162,212, 38, 53,239, 67,
+159,220,194,222,100,171, 9, 37, 41,111, 45,133, 37,120,214,238,238, 21,145,110,110,237, 53,104,141, 18,147, 65,187,160,213,226,
+ 84,226, 75, 44, 52,154, 77, 70,163,111,200,247,152,240,235,208,227,114,167,192,113, 14, 20, 25, 44,164, 59, 28,191,226, 56,135,
+145,206,141,115, 74,240, 69, 70,139, 58,226, 93, 94,157, 42,151, 38,217,171,209,163,191, 18, 75, 72, 91,241,167,211,107,148, 86,
+235, 13,120,141,225, 15,143,117,147,200,218,176,158,118,242,164,158, 78,241, 42,202,121,105,230, 69, 46, 37,138, 83,229, 96, 54,
+ 39, 96, 53, 11, 27, 48,191,217, 61,150,247, 32, 99,163,184, 11, 53,202,248,178,154, 72,228,131,244,126,105, 66,170,147,211, 72,
+202,218, 17,229, 26, 94, 18, 8, 15, 27, 23,116, 14,187, 34, 6, 89, 17, 67,170, 54,206, 82,238,185,177,160,198, 76,229,153, 13,
+208,110, 74, 4,198,235, 44, 56,149,128, 69,106, 35, 41,155, 33, 8,201, 46, 37,233,173,153, 1,226, 91, 60,203, 41, 39,176,223,
+221,171,219,215,238, 40,178, 42,213,233, 10,163,209,233,181, 8,142, 38,114, 84,251,110,185, 54, 35,209, 31, 13,197, 91,138, 79,
+143,206,150,212, 57,242,124, 38,229, 16, 84, 73,240,213,204, 75, 50,143, 87,173, 84,164, 89, 20,181,168, 46,225,151, 26,159, 71,
+109, 65, 14,184,229,111,223,226,166, 53, 41,224,179,148, 64,114, 79,132, 90,113, 73,200,104,184,146,174,118,146, 79,101,175,201,
+205,219,204,155,102,128,180, 26,125, 18, 28,150, 98,195,105, 10, 14, 85, 92,139, 49, 44, 74,113, 69,160, 66,149, 34, 98, 36, 58,
+ 20, 83,202,178,235,104, 56, 3, 26,125,225,170,120,167,231,215, 85,141,112,211,105, 68, 66,108, 25,200, 98, 1, 35,204, 2,129,
+118, 32,139,221, 73,211,171, 88,164, 60,112,168,124,170,167, 38,200,178,103, 72, 51, 44,237,231,149,166, 81,253,213, 50, 10, 79,
+172, 10, 67, 42,201, 44,175, 42,128,126,168, 90, 67,176, 82, 27, 44,157,124, 91, 86,163,172,210, 40,209, 33, 66,112,182,149, 48,
+228,143, 4,186,243,202,144,134,136, 71, 50, 71, 59,195,196, 43,253, 81,128,121,143, 54, 9,213, 9,123,191, 49,153,245, 55, 35,
+206,109,168,116,233,113, 41,236,173,165,115,203,126,108,150, 24,126, 66, 34,165,149,164, 32, 41,215,163,182,233, 78, 22,166,155,
+ 90,143, 48,108,145,165, 85, 75,154, 37, 70,161, 46,164,219,243,155,165,183, 95,162, 83, 41,204,184,183, 31,120, 38, 3,190, 45,
+101,232,203,231, 40, 76,115, 83, 50,127, 74, 20,164,143,112, 40,242, 9, 31, 98, 92, 79, 79,129, 78,140,203, 11,121,138,245, 72,
+215,101,185, 49,196, 39,158, 19, 18, 21, 36,165,158, 84,115,163,196,105,234,116,116, 44,252, 60,143,172,114,249,234,105,237,243,
+234, 88,226,151,149, 96, 84, 34, 93, 22,215, 29,128, 4, 3,181,141,183,216,168,177,185,166,163,240,166,136, 67, 12,245,145, 53,
+ 84,238, 0,153,166,177, 96,204, 18, 87, 55,144,155,186, 70,146, 43, 45,216,107,212, 1, 59, 91,122,169, 91,167, 70,186,227,184,
+197,203, 10,131, 87,163,189, 10, 69, 85,214,171,148, 90, 69,113,166, 35, 70, 56,136,137, 81,234,204,184,151,100,173,214,164,200,
+104, 6,254, 24,254, 26,193, 30, 33,214,177,238,127, 2, 62,206, 30, 34,208,151,119,167,131, 14, 31,170, 51,171, 76, 70,150,170,
+189, 2,208,133,100, 93, 16,152,156,135, 92, 15,166,232,176, 13, 54, 74,101,165,135, 57,220, 33, 69, 97,249, 39,169,192, 0, 26,
+ 93,210, 95,153, 46,142,195, 48,212,207,240,138, 76,170,188,247,144, 86,212,166, 41,209, 88, 17,109,147,200,217,240, 91,113,230,
+ 10, 86,128,162,166, 98,165, 96, 97,201, 9, 78,178,250, 69, 65,249,177,152,150,228,245, 53, 78,141,239,234,159, 40,211,220,125,
+234,189,102,123,128,204,166,210,121, 79, 70,152, 89, 40,114, 90,121,185, 11, 65,166,199,232,221,121,189,200,179, 42,152, 93, 92,
+ 75,230,181,135,235, 18,204, 69,152,107,221, 75, 2, 72,234, 69,174, 46, 14, 32, 60, 65,225, 38, 67, 80,102,246,156,185, 96,142,
+ 64,186, 65, 26,216, 43, 6, 40, 6,149,221,157,212, 46,150, 93, 69, 68,110,116,131, 41,199, 40, 55,231,232,175,112, 39,186, 52,
+233,149,158, 27,247,143,120, 56,116,174,173,153, 18, 34,210,174, 57,144,247,130,194,102, 74,185,149, 26, 52,200, 23, 10,162, 86,
+ 96,176, 86,182,130,146,213, 93,197,161,183, 1, 8, 39,149, 38, 53, 60,110,123, 1,189,162, 92, 20, 64,171,222, 82,246,226, 47,
+ 16,123, 65, 75, 15, 72,127,116,120,126, 77, 82,239, 20,202,115, 40, 46,174,117,219,183,111, 65, 69,126,215, 97, 8,232,243,169,
+139, 58, 27, 74, 74,185,166,114,142, 99,250, 18,209, 46,181,183,224, 68,113,102, 52,106,107,177, 37,200, 76, 89,105,113,113,218,
+ 56,118, 12, 55,101, 50, 10,230, 23, 86, 85, 37,215,208, 22,167,192, 67, 77,169, 69,206,125,108,205,177,123,137, 81,132,228, 77,
+240,230, 79,154,105,244,170, 68,172, 70,170, 45, 44,243, 23,229,205,128,165,133,198, 42, 67,110, 60,176,176,144,220, 86,155, 75,
+156,175,184, 82, 37,249,111, 22, 85, 64,218, 42, 36, 46,150,235,171, 86,247,176,186,185, 5,172, 47,228,140,198, 46, 44, 72,234,
+121,147,139, 60, 39, 92,176,153,168,117, 68,140,198,218, 71,144, 3, 98,138, 64,212,159,103, 84,140,214, 0, 32, 12, 28,131,124,
+126, 50,105,198, 21,146, 20, 2,150,143,132,228, 7, 26, 81,109,214,212, 65,248, 92, 74,194,146,164,156, 20,169, 37, 42, 0,131,
+165,219,161,234, 58, 18, 58,228,124,254, 71, 95,166,111,180,163,216, 17,194, 7, 31,240,238, 45,193,218,248,212,110, 26,248,173,
+144,137, 82,206,229, 89, 52, 54, 25,176,183, 2,186,219, 40,113, 49,183,135,111,169, 74,106, 53, 73,215,223,228, 75,245,122,111,
+187,214,152, 50, 20,235,206, 84, 2, 61,217,127,158,255, 0, 24,156, 20,241, 33,192,134,239,206,217, 30, 38, 54,238,125,139,118,
+182,211,245, 43,118,166,211,159, 90,217,123,137,109, 53, 37,113,155,187,182,234,235,101,180,177,115, 80,148,226, 64,116, 0,220,
+200, 46,171,221,234, 49, 34, 72, 30, 25,177,178,252,214,159, 48,137, 36,141,135,159,161, 6,234, 78,231, 77,251, 48, 0,221, 90,
+199,202,197,117, 32,214,105,170,234, 26,172,186, 65, 29, 84,101, 65, 54, 87,177, 10,215, 32, 13,141,138,150,236, 14,199,245, 75,
+111,141, 87,232, 7, 78,223, 46,186,240,164,147,156, 28, 3,215, 4,145,249,235,175, 68,129,142,189, 7, 76, 99,191,151,125, 32,
+ 65, 39, 61, 71, 76, 36,140,103,167,252,116,233,141, 78,248,166, 18, 9,199, 92,122,143, 95,234,239,175,161, 36,250,244,200, 30,
+ 93,115,158,191,142,170,121,127,171,248,116,215,196,144, 1,202,147,156,231,167, 92,228,232, 96,111,143,129, 56, 33, 89,201, 25,
+230,243,242,215,164,117, 4,143,135, 25, 61,115,251, 63, 29,125,233,140,254,206,216,252,245,215,209,215,246, 12, 1,220,121,253,
+253, 52, 48, 58,123,176,136,207, 68,245,233,231,142,164,103,246,106,130,219,198, 9,242, 61, 70,124,244, 78, 14, 58,140,121, 2,
+ 70, 49,246,252,191,175, 84,207,110,131, 39,246,103, 63,212,127,167, 88, 6,255, 0, 17,140,224, 37,160,224,249,103,215,184,207,
+168,252,247,208,170, 64, 0,231, 36, 18,123,250,252,190, 90,184, 57,205,158,184, 61, 58,231,190,125, 58,121,245,208,238, 32,242,
+231, 4,117,232, 58,231,175,203,236,214, 65,232,122, 99, 32,158,221, 78, 45,197, 1, 39, 32,245, 29, 49,158,152,199,174,188, 20,
+231, 36, 28,121, 28,159,179,207,240,209, 42, 73,234, 20, 7, 79,245,123,146,126,126, 67,174,168,242, 12, 40,100, 99,166, 0,243,
+235,158,231, 75,169,184,235,131,168, 34,219,109,243,243,111,195, 3, 40, 3,212,147,129,248,125,186,160, 70, 70, 63, 35, 70, 41,
+ 35, 56, 30,153, 63, 44, 13, 12,180,144, 73, 3,167,246,126,206,186, 81, 79,108, 24,216,116, 23,254, 71, 0,184, 0, 32,116,206,
+122,159,217,215, 31,158,154,162,160, 78, 58,100,103,175,175,221,163, 20,147,230, 7,221,216,158,250, 25, 89,201,230, 56, 39,183,
+207,211, 31,119,244,105, 92, 1,208, 95,113,129, 22,128,114, 64,199,200,249,250,140,104,117, 35,166, 6, 1,239,246,103,200,244,
+209,138,206, 65, 56,207,160,242,208,199,169,200,207, 95, 92, 14,221, 63,118,149, 7,160, 39,167,207, 95,158,248, 54, 5, 87, 76,
+228,103, 25,253,159,187, 66,172,116,206, 15, 78,216,253,164,244,237,211, 70,172,100,142,152,235,220, 30,253,124,255, 0, 62,122,
+ 25,196,228,156,100, 1,208,227,182, 79,228,104,248, 50,250, 91,127, 92, 91,215,128,112, 14, 73, 39,167,161, 29,123,232,115,223,
+168,235,158,191,184,104,199, 19,144, 83,211, 62,126,189, 61, 63, 13, 12, 80, 70, 78,114,125, 15,225,223, 58, 89,122, 97, 81,107,
+ 3,210,216, 29,105,243, 25,206,133, 90, 72, 39,183,153,251, 62,223,150,116,105, 25,251,186,250,103,228,126, 90, 25,105,206, 73,
+200, 62,126,125, 59,253,250, 85, 79, 91,157,176, 69,216,144,119,183,250, 96, 34, 48,113,165,175,107, 73, 39, 35,175,224, 52,180,
+174, 15,113,220,216,227,234, 49,143,233,209, 40, 24, 3,231,215,243,247,106,128,198, 6, 1, 31, 35,223, 85,211,204, 59,128, 49,
+233,223, 61, 58,233, 18,118, 3,231,221,140,226,178, 60,250,253,223,191, 85,209,220,253,157,189,127, 63,191, 84, 81,143, 33,215,
+204,234,178, 6,122,231,177,237,249,242,254,173, 16,157,137,190, 6, 8, 78,112,112, 70, 7,124,143,196,244,243,233,162, 27,234,
+126,239,234,213, 4,125,189,188,191,126,189, 18, 64, 86, 14, 8, 30,125, 1,207,244,255, 0,102,181,216,133,193, 78,224,142,199,
+ 7, 54,115,211, 61, 62,206,158,126, 99, 69,164, 14,128, 16,123, 15,151,236,213,189,146,233, 74, 78, 19,142,153,251,112, 63,171,
+ 71, 55,223,162,122,140, 28,224,246,249,233, 34,215,194, 71,174, 43,165, 61, 65, 57,232,123, 99,191,167,237,209, 9, 0,142,169,
+249,103, 39,175,175,217,170, 64, 18, 71,145,233,231,230,123,231,229,170,232,200, 36,116, 29,135,203,168,243, 62,103,182,176, 73,
+ 61,123, 96,167, 21,209,156, 1,208, 14,195,241,243,249,104,148, 3,216,156,228,224,103,250,117, 65,160, 72, 29, 58, 3,231,163,
+ 16, 58,231,175,203,211,211, 73,191,175,207,108, 99,107,145,181,206, 58,159,236,114,180, 36,215,120,223,178,238,166, 92,121,134,
+ 54,178,207,191,175,249, 50,154, 42, 65,101,248,212, 39,104, 52,196,151, 17,213,181, 46,101, 96,132,144, 65,248, 62,103, 82,170,
+147,119, 79,171, 52, 99,214, 12, 27,130, 56,200, 92, 43,154,147, 73,175,197,113, 32,149, 96,181, 85,136,238, 83,215,166,114, 61,
+117, 30,111, 98, 93, 13, 12,206,226,110,249, 80, 74, 93,129,102,217,118,147, 11, 61, 22,147, 89,172,205,170, 73, 66, 84, 58,128,
+180, 66,104, 17,242,215,110, 85, 89, 62, 34, 74, 78, 18,162, 18,178, 78, 2, 72, 24,243,252, 53,207,158, 33,214, 52,188, 67, 60,
+ 91,218,146, 56,163, 6,254,160, 73,191,190,242, 16, 55,233,143, 67,190,140,252, 57, 24,240,222, 10,185, 97, 89, 6,113, 87, 87,
+ 57, 12, 1, 4, 44,130,152, 2, 8,181,138,211,143,223,140, 91,113,184, 80,224,223,122, 90,127,248,197,225,195,111,141, 78, 74,
+ 74, 28,185,236, 6,100,109,189,210,202,149,255, 0,194, 25,155,109, 45,182, 30,116, 14,184,114, 58,193, 35, 36, 29,114,235,126,
+ 61,136,232,153, 30,101,195,194, 78,234, 11,142, 74, 18,167, 81,180, 59,192,184, 84, 27,145,224,126, 38,225,219, 27,129, 13, 41,
+129, 85,124,254,171,109, 79,106, 42,220, 56, 5,240, 78, 79, 93,141,126, 51,110,161,151, 93, 72, 82,213,250, 21,147,128,162,159,
+242,172,156,116, 75,192, 96,143,245,128,214,109,101, 34,179,125, 87, 98,219,150,188, 73,117, 58,171,235, 8, 75,113, 88,113,228,
+190,130,160,148, 6,130, 7,194,176,163,212,158,137, 41,207,108,226, 37, 67,197, 89,254, 85, 44,107, 65, 92,242,128,109,202,127,
+172,140,251,130, 53,244,131,234,154, 77,174, 21,133,241,105,113, 79,128,254, 26,113,109, 13, 76,249,182, 65, 22, 83, 80, 16,177,
+174,164, 11, 73, 52,123,127,120,210, 70,162, 57,108,123, 78,146,165,250,169,223, 16,133,191,246,226,251,218,171,186,173, 97,110,
+ 77,165,112,216,183,165, 5,229, 49, 86,182,110,106,115,212,202,172, 69, 5, 40, 7, 80,219,163,150,100, 37,129,150,164, 48,167,
+ 88,117, 63, 19,110, 40, 29, 97,233,193,243, 24, 29,250,143,184,116,215,232,143,190, 62,204, 45,147,226, 95,110, 34,219, 28, 90,
+ 85,225, 64,173,211, 34, 4,217, 87, 45, 7,192,123,116,108, 57, 14, 35,197, 13,193,172,182,131,239, 52,194,172,248,180,249,101,
+232,171,201,194, 80,172, 40,106, 85,157,236, 48,246, 94, 89, 49, 96, 11,150,111, 16, 59,185, 80, 43, 83, 18, 93,168,222, 84,251,
+ 54,159, 41,214,155,241, 92, 81,129, 64,166,133,196, 36,117, 74, 67,170,207,108,116,206,173,202, 63, 17, 40,214,142, 55,205,233,
+ 13, 21,112,217,227, 87,141,135,185,128, 46, 29, 67,117,210,202, 74,244,212,246,213,142, 20,207,126,143,124, 95, 14,119, 61, 31,
+ 6,200, 56,195, 36, 55,104,107, 68,114, 83, 2, 59,199, 46,168,204, 70, 69,177,250,200,100,120,157,124,223, 84, 73,137, 96,225,
+130, 70,121, 22, 8,237,202,133, 96,250, 28,227, 72,168, 32, 0, 58,146,113,140, 31, 63,151,222, 53, 61,230,125,146,190,201, 76,
+ 62,208,225,254,252, 87,128,217,112,248,251,193,118,173,197, 4, 39,152,242,173, 11, 29,115,211, 32,117,193,211, 69,186, 94,193,
+159,103, 5,247, 75, 55, 6,222,220,187,247,177,170,142,168,178, 84,212, 27,150,141,124,210, 39, 70, 74,144,228,182,226,199,187,
+233,222, 60, 23, 11, 1,196, 7, 82,242,195,107,113, 42,240,151,142, 83,177, 77,226, 46, 75, 83, 47, 41, 81,193,177, 55,242,216,
+ 0, 46, 73,185, 22,183,223,238,190, 25,235,190,143,254, 42,229,177,123, 69, 87, 14,170,171, 21, 80, 22,161, 11, 51, 57, 1, 84,
+ 2,160, 93,137, 3,114, 63,142, 35, 1,192, 79,179,155,127,248,252,190,165,208,246,210,151, 26,220,219,219, 90, 68, 49,185,187,
+209,119,179, 45,157,189,219,184,210,112,227,112,228, 57, 29, 33,219,162,244,145, 27,153, 80, 40, 80, 57,165, 61,128,236,151, 33,
+196, 10,146, 38,173,194, 71, 5, 92, 32,251, 61,109,198,127,137, 11, 71,248,111,187,134, 47,186, 92,156, 68, 95,208,233,213, 77,
+203,169,188,166,210,220,230, 45,176,210, 20,198,221, 91, 60,222, 42,147, 78,163,161, 14,132, 16,169, 50,102, 40, 41,100,251, 2,
+ 70,221,108,222,222,208,118, 35,135,219, 98,141,182,187, 99,183, 80,221, 22,253,169, 5,240, 28,175,120,202,109,117, 43,158,224,
+172,168, 42, 69,193,113,212,166, 35,154,109, 86, 73,117,239,122, 88, 75,220,172, 22,219, 70, 15, 39,112, 35,202,153, 34,108, 9,
+ 83, 16,228,242,167, 30,167,205, 67,209,101, 60,247, 40, 75,203,132,133,184, 16,103,115, 6,213,204,193,117,183,249,130, 73, 35,
+ 5, 53, 87, 20,120,131, 91,154, 84, 73, 73, 68,198,158,137, 73, 10, 65,221,198,214,239,181,250,134,185,234, 8, 61,113,217, 30,
+ 12,253, 20, 41, 50,184,169,243,158, 45,133,115, 76,244, 44,114,114,236, 90, 10,109,118,101, 69, 7,109, 69,110, 68,166,247, 32,
+244, 91, 5,122, 46, 93,207,151,112,185, 82, 84,201,237, 85,196,152,174,184, 88,241, 23,239,197, 8,146,129,239,112,210,195,217,
+143, 82, 97,220,134,151,240, 7,148,160,230, 82, 64, 42,108, 46, 11,170, 52,200,142, 42,108,229, 75,154, 25, 10,128,251,176,220,
+ 69, 62,231,164,248,160, 73,129, 34, 43, 32,148, 79,109,191, 21,101,149, 97,198,164, 54, 36, 52,149, 5,184, 19, 97,136,251,117,
+212, 9,207, 47,222, 75, 83,204, 70,166,198,109, 84,203,178,149, 49, 96, 25, 28,237,178,132,166, 28, 66,181,167, 45,188,144, 84,
+217, 47, 45,181,163,161,199,231,178,168,238, 61, 67,174,165, 50, 30, 68,210,138,101, 69, 41, 66,226,214, 24,154,175, 18, 68, 23,
+ 25,200, 16, 43,237, 53,206, 89, 40, 41,101,229, 18,227, 11, 67,153,107, 85,228,149, 94,103,214, 88,177,181,218,251, 49,190,198,
+219, 19,126,194,199,107,117, 59, 14,220,202, 56,115, 41,161,100,166,134, 46, 65,164,220,199, 24, 80,202, 6,149, 99, 29,208, 93,
+ 86,200,179, 38,148,109, 12,205,160, 36,107, 36, 87,151,170,161,165, 46,223,113,167,151, 78,170, 42, 43,148,218,139,143,133, 60,
+212,244, 50,100,136,203,150,242,135,136,250, 60, 22,164,198,112,144,183, 19, 29, 76, 58,165, 45, 0,185,112,131, 94,118, 83,239,
+ 68, 41,110,145, 84,110, 85, 61, 77, 75,109,178, 94,166,215,169,104, 8, 67,209,226,188, 8,118, 28,136,175, 69,146,129,147,227,
+180,167,144,130,160, 73, 24,237, 74,148, 41,180,184,241,225,200,118,224,181,231, 71,136, 98, 84,161,159, 30,183,110, 75,101,207,
+122,101,135, 67,139, 34,171, 78, 67,173,161, 72,116, 98, 92, 85,128,204,132, 60,193,241, 18, 44,199,101, 84, 85,252, 43,112,177,
+ 42, 84, 4, 52, 95, 52,245, 4,179, 84,167,160, 46, 60,163,202, 84, 82,137,173,158,119, 35, 43, 36, 50,180, 41,160, 2, 22, 0,
+ 48,114,196,178,177, 80, 55,211,178,238, 64,223,114,118,234, 70,226,196,234,190,160,112,250, 40,232,234, 98, 13, 29,180, 72, 74,
+135, 58,129, 51,142, 88, 77,113,191,149, 76,133, 66, 76,142, 54, 49,137, 46,240,201,115,180,187,121,113,159,112,167, 74,168,126,
+134,164, 39, 75, 21,246,192, 76,150, 24,152,101, 59, 6,160, 22,251,164, 23, 22, 86, 34,169, 37, 64, 41, 77,186,215,114,156,150,
+ 43,139, 43, 97,169, 85,218,101,105,162, 25, 69,219,106, 92, 52,234,159, 51,106,114, 59,213,187, 98, 11,114, 96,186,162,129,133,
+ 58,105, 47, 71, 91,228,165, 74,112,210, 83,241, 18,146, 11,135,106,214, 98, 78,172, 73,102, 43,177,164, 67,184,105,116,249, 76,
+184,164, 4, 42, 59,240, 23,245, 98,155,113,151,208, 49, 37,216,174, 66, 88, 82,250, 45,200,200,202,137, 72, 26,161,196, 82,249,
+ 44,237,191,114,123, 77,202,228,191, 13, 50,108,176,183, 27, 75,109,213, 41, 83,161, 73, 7, 42, 42, 37,230,219,111,224, 71, 41,
+ 82,129, 72, 56, 26, 82,178,211, 80,176, 96,117, 33, 87, 27,130, 65, 15,123,139,250, 43, 17,247,133,176, 59,154,251, 35,230,229,
+ 30, 34,101,181, 84,209,154,121,115, 5,168,137,162, 38,222, 89,169,228,145, 35,177, 23,211, 13, 74, 42,128,222, 98,209, 33, 93,
+247, 45,207, 13,114,155,103,122, 54,250,161, 33,214, 94,250,215,234,202,139,111,115, 54,235, 9,117,115, 33, 84, 25,247,117,161,
+ 36,186, 75,171,142,226, 92, 32,132,169, 8,234, 2,250,244,178,232,151, 46, 85, 85, 97, 46,180,218,152,141, 41,185, 10, 82,146,
+133, 56, 87, 49,135, 28, 75,206, 54,128, 82,149,182,149,114,148,252, 73, 40, 42, 25, 63,173,202,173,165,149,245, 27, 59,105, 37,
+133,198,106, 75, 46,199, 11,153,201,226, 56,179, 68,204,101, 51,206,133, 4,148,184,138,122, 64,229,229,233,145,221, 56, 61, 81,
+185, 75, 51, 27,159, 80,109, 41,125,186,148, 24,239, 53, 37,180,135, 92,106, 52,136,171,113, 78,165, 68,140, 37, 16,223, 89, 4,
+156,167,195, 25, 30,171,240,236,165,105,234,169,128, 26,161,150,226,251, 18, 25,116,220,216,131,250,167,125,192, 39,222,113, 12,
+241,161, 4,252, 89,144,102,166, 63, 45, 69, 19,211,173,192, 32, 52, 53, 5, 73,183,217, 0,172,167, 96,196,253, 93,251,227, 89,
+170,116,137,115, 41,150,180, 88,239, 52,228,155,128,190,219,171,105, 45,132, 20, 84,125,242,101,110, 97,109,192, 60, 15, 6, 4,
+169, 41, 7,205,101, 42, 4, 30,100,235, 48, 98,100,183,170,109, 55, 77,129, 26, 53, 90, 77, 38,159, 64,165, 69,109,165, 59, 30,
+ 52,118, 31, 90,205,199, 80, 1,144, 68, 88,139, 74, 3, 44,182, 0,117, 80,218,100,243, 23, 20, 81,245,170, 20,128,229,191, 57,
+231, 18,227,180,170, 21, 94, 83,170,231,105, 13,211, 41, 41,129, 19,194, 45,180, 74, 72,152,162,162,165,171, 24, 90,155, 91,121,
+ 64, 1, 10,190, 89,208,106, 49,147, 38,123,140,190, 42,215, 59,205, 63, 4, 41, 77, 7,232,116,248, 77, 39,221, 90,229, 3, 45,
+ 60,220, 25, 11,121, 77,164,169,180,203,154, 2,178,180,171, 50, 56, 55,242,106, 47,163,123,251,137,182,215, 39,127,128, 23, 32,
+147,183, 70, 90,252,198, 22,163,102,103,142,115, 15, 52,168, 39, 72, 47, 37, 68,133,131, 88,139,196,145, 68,178, 49, 42, 54, 4,
+ 38,158,106, 17,126,147, 14,157, 74,146,213, 34,214,106,160, 3,145, 23, 72, 93, 65,214,154,147, 60, 45,214,208,171,150,181,227,
+ 40,145, 58,176,135, 20, 0, 88, 40, 71,191, 85, 50,133, 16,199, 40,204,233,149,217, 16, 81, 74,106,213,167,196, 41,166, 68, 93,
+ 61,218,202,202,222,163, 83, 36,180,202,163, 63,224, 83, 73, 82,235, 51,209, 30, 63, 41, 12,169, 45,248,223, 4,213,169, 74, 90,
+ 53,128,211,101, 42, 82,164, 55,109,135, 89,147, 41, 74,163,196,152,181, 2,229, 14,132,196,169,105,114, 84,194,235, 37, 15,213,
+165,203, 74,222,142,144, 8, 75,184,116,146, 25,235,123, 77,126, 53, 26,159, 50,222,163, 82, 34, 87,170,209, 34,199,165,211, 98,
+196,145, 42, 52, 27, 97,182,148, 76,169,143,206,119,244, 45, 5, 21,254,145, 74, 46, 58,167, 16,167, 2, 71, 51,139,214,220,104,
+ 21,172, 65, 37,238, 69,201, 58,119, 82, 55, 23, 34,254, 81,127, 40,177, 82, 54, 23, 48,154,250, 57, 42, 21,105,164,129,171,170,
+ 20,141, 98, 87, 0,144,254, 73, 38,170, 44,234,129, 19, 88,176,146, 78, 89, 34,103,179,171,162, 77,157, 81,164,143,123,163, 8,
+ 73,114, 60, 56, 14, 56, 25,153, 92, 82, 27, 64,113,230,129,159,116,212,234,141,165, 30, 35,232,150,149, 34, 26,138, 67, 35,195,
+229,195, 64,160,161,215,163,214,229, 61,114,193,118, 3, 18,169,144,234,116,244, 83,105,213, 73,128, 42,170,162,244,180, 53, 84,
+173, 73,139, 52,114,195,114, 72, 17,209, 13, 46,130, 91, 66,252, 80,144,164,132,233,150,102,139, 89,170,162, 58, 42, 11,109, 2,
+156,194, 86,221, 33,181,251,181, 38, 42,218, 67, 77,174, 97,127,153, 78,214, 92, 14, 2,191, 29,239, 13,182, 62, 55, 80,210, 57,
+121,206,113, 74,153, 54,127,189, 8,203, 67,140,225,184,143, 85,220,123,222,211, 87,121,197,162, 59, 80,232,138, 96,225,196, 37,
+231, 93,231,158,158,124,173,226,166, 18,183, 1,113, 59,104,206, 7,217,212,166,214, 54, 39,125,193,177,184,189,190,201, 2,219,
+129,115,109, 36, 64,115,202, 58,106,133,145,131,199, 51,172,111, 27,220,150, 84, 18, 57, 32,181,236, 38,119,102,187, 2,172,173,
+245,138,161,227,115, 42,109, 53,183, 89,113,151,211, 75,165,167, 49, 32,171,220, 30, 90, 20,243,205, 83,164, 33,100, 75, 87,189,
+190,190,121, 21, 18,250, 71, 48, 94, 91,105, 75, 43,121, 74,230,229, 45,103, 23,124, 32,112,213,237, 11,217, 74,166,193,241, 37,
+103,179,117, 80, 93,247,138,133,163,115, 83, 94, 17,183, 11,108, 46,100,165,216,113, 47, 43, 30,236, 12, 41,116, 27,141,183,211,
+202, 18,144,184,181, 22,208, 98,204,139, 46, 18,220,104,135, 30,225, 76, 56, 81,105,212,133, 48, 41,180,229, 70,162,206,126, 38,
+ 92, 98,148,206, 66,164,193,166,164, 45,105,171,200, 68,140,120,203, 37, 97, 47, 60,174,114,244,144, 80, 29,171, 42,165, 30,155,
+ 49, 51, 37,181, 81, 79,132, 15,185,196,151,151,234,114, 30, 44,248, 41,113,104, 4,248,238,184,148,190,180,184, 74,188, 52,182,
+ 16,234,154, 81, 58,124,203,115, 9,169, 39, 2, 57, 12,104,246, 82,172, 26,204,163, 72, 34,253, 44, 52, 92, 91,236,149, 12,133,
+109,183, 62,241,103, 9, 69, 81, 77, 83, 52,208,150, 44, 27, 66,145,121, 36, 63,181, 37,206,204,250,129, 61,116,169,212, 89,131,
+ 43,201,249,104,123, 74,253,155,155,225,236,203,226, 10,102,204,110,202, 63,132, 86,125,198,138,149,127,100,183,134,155, 1,112,
+237,173,219,177,225,202, 67, 75,152,211, 60,203, 77, 6,247,167,123,204, 54,107,180, 85,184,167, 33, 62,251,114, 35,170, 69, 54,
+ 84, 73, 46,115,200, 36,167, 25,234, 60,137, 61, 71,217,242,198,191, 92,191,104, 95, 2, 27, 99,237, 47,225, 82,247,225,235,116,
+208,197, 6,191, 47, 55, 54,209,110, 43, 17, 27,149, 84,218, 45,211,165,197,120, 90,215,101, 56,171, 11,149, 13, 70, 66,225,214,
+ 96,115,165, 21, 26, 85, 74, 92, 66,166,214,227, 79, 55,249, 64,239, 46,206,238, 55, 15,155,187,185,155, 17,187,212, 5, 91, 27,
+163,180, 55,157,106,194,190,104,165,101,216,241,171,116, 57, 30, 18,166,211, 37, 16, 5, 70,131, 54, 18,226, 79,167, 74, 70, 81,
+ 42, 5, 78, 52,132, 18, 28, 26,183,178,186,229,171,129, 84, 73,169,212,119, 35, 85,129, 0,134,181,188,202, 72, 5,128,210,110,
+164,121,139, 34,115,126, 99,150,201,150, 78,208,177,215, 21,236,173,125, 91,218,250, 75,126,181,187, 55,113,190,246, 44, 91, 95,
+135,148,129,156,147,147,205,212, 31,144,244, 3, 58,243,202,158,132, 96,121,118,234, 51,223,167,152,213, 84,132,144, 83,212,144,
+122,231,250, 71, 93,121,229, 7,168,206, 61, 58,103,231,212,233,216,126,242, 48,223,133,202,123,243, 12,118,207,203,183,111, 61,
+ 32, 14,126, 17,140, 14,161, 90,245,202, 0,199,235, 2,114, 60,191,110,190, 5, 15,139, 57,201, 32,114,253,216,239,161,239,192,
+233,108,123, 39,162,135, 78,189, 62,195,246,249,106,136, 10, 78,112, 73, 80, 61,113,230, 62, 64,254,122,234,166, 18, 83,202,122,
+103,184,207, 81,130, 49,223,236,215,174, 80, 6, 9,201,199, 47,111, 46,189, 71,203, 89,192, 63, 27, 96, 53, 1,149, 31, 49,140,
+143,183,211, 84, 10,122,103,152,159, 49,204,115,211,229,233,253,186, 57,109,140, 0, 0, 42, 35,161, 61,188,137,207,221,161, 86,
+ 58,145,216,118,198, 58,231, 30, 93,116, 48, 63,158, 1,112, 96,228,246, 63,119,203, 84, 21,220, 28,101, 35,160,235,242,245, 31,
+102,138, 90, 22,121, 72,232, 51,231,247,231,247,104,117, 39, 61, 58, 2, 59, 96,249,104,234, 64,191,160,198, 65, 55,247,255, 0,
+ 60, 14,160, 50, 60,137, 24,206, 58,103,203, 61, 58,234,146,135,124,156,121, 99,160, 31, 51,219,236,252,116, 73,206, 49,128, 51,
+231,231,251,123,106,130,209,216,142,152, 32,159, 63,195, 75, 14,184, 84, 94,215, 29, 79,250, 96, 55, 19,215, 9, 7,190, 79,166,
+113,212,157, 10,180,231,174, 51,219, 30,163,230, 61,124,245,112, 94, 8, 35, 56,199,150, 58,254, 63, 97,208,174, 36,246, 79, 78,
+132,250,231,203,175,160,237,165,148,155, 11,141,240, 1, 23,176,233,128,148,158,253,122,158,192,247,206,126,126, 93,116, 42,219,
+ 61,126, 33,142,248, 29,128,238, 64,251,180, 98,130, 72,235,144,115,140, 99, 39,215, 61,190, 90, 29,105, 56, 32,252,142,124,190,
+223,195, 58, 58,223,238,254, 95, 39, 6,192,106, 72, 24,199,207,169,245, 30, 90,160,176, 6, 79, 92,227,183,145,249,118,249,104,
+165,167, 61,148, 78, 62, 93,254,239, 93, 12,179,220, 30,157, 60,198,115,242,249,127,110,150,193,148,246,192, 42, 80,207, 64,115,
+230, 7, 95,188,250,119,213, 21, 12,100, 99, 63,179,231,162,150,129,220, 12,103, 57, 35,191,246,104,101, 2, 7, 81,158,249, 35,
+174,127,183, 74, 39,124, 40,187,129,129,212, 62, 68,122,250,125,199, 84, 23,140,143, 92,117,213,117, 19,215,184, 4,231,175, 66,
+ 79,245,106,130,251,142,158, 93,255, 0,118,149, 29,122, 95, 24, 34,198,227,107,126,239,159,158,216, 20,140, 18, 59,227, 75, 95,
+ 85,250,199, 75, 75, 13,192, 56, 53,129,222,221,113,224, 31, 34, 70,125, 6,170,115,117, 4, 36,146,112,146, 71,252, 62, 67, 84,
+ 57, 57,156, 74,190, 46,131,167,126,189, 72,198, 14,138, 73, 72, 0,249,103,174,123,247,243,198,181,201, 39,189,191, 44, 27,238,
+190, 43,164,129,129,211, 63,236,245,233,243, 58, 32, 97, 35, 36,140, 31, 65,231,246,249,232,100,242,133, 16, 14, 78, 58,158,157,
+ 7,144, 58, 37, 4, 36, 28,167,155, 7,168,239,223,182,147, 44,119, 29,113,140, 86, 9, 88, 80, 33, 67,148,142,189, 58,147,229,
+223,183,125, 16, 27, 14, 36, 37, 73,206, 14, 71,113,233,215, 84,146,114, 59, 96,121,126,113,162,219, 33, 61, 20,122,227,203, 61,
+135,228,105, 51,107,111,211, 4, 38,221, 6,253,190,126, 24,172,132,132,167, 25,192, 31, 46,167,238,209,141,168,114,132,252,186,
+ 31, 95,234, 58, 17, 41, 24, 32,168,146,115,128, 59,159,179,174,138,108, 18,115,203,216, 12,131,215, 0,103,174,144,194, 71,174,
+ 42,227,160,207, 92,117,206, 62,223, 33,242,209, 40,194,176, 79, 64,124,186,245, 61,190,239,236,213, 16, 1, 81, 29, 64,242,237,
+249,245,209, 45,130, 6, 1,237,228,113,147,251, 59,104, 99, 7,241,193, 13,224,100, 14,158,159,183, 68, 33,125,121,112,122,103,
+ 36,117, 25,207,111,219,170, 8,237,156, 12,250,116,207,217,159, 61,101, 86,165,169,113,222,213,218, 85,175,104,208,234,151, 29,
+199, 92,154,205, 58,143, 67,162, 64,145, 83,170,213,103, 62,174, 86,162,193,129, 17,181, 57, 37,226, 79, 92, 12, 36, 30,101, 16,
+144, 78,144,150, 68,141, 93,157,130, 34,110, 73, 54, 0, 1,212,158,192, 96, 14,194,219,159, 78,228,237, 97,234, 73,216,119, 56,
+239, 95,177,184, 52,198,205,241, 34,250, 82,145, 37,219,203,111,154,116,243, 97, 74,140,138, 52,229,161, 36,121, 36, 56,165, 99,
+ 62,127,102,186,125, 58,178,168,165,224,240,108,180,227,106, 45,243,168,133, 3,219,224, 41,253, 99,156, 28,124,181,130,123, 43,
+ 61,153,123,231,176,246, 46,230, 76,226, 66, 69, 19,109, 99,238,172,123,102, 85,189,105, 61, 82,102,161,115, 83, 77, 53, 47, 41,
+114,110, 56,241, 22, 91,166,201, 83, 79, 37, 41, 96, 41, 78, 35, 7,156,131,211, 91,183,187, 60, 21, 87,216,164,202,171,216, 55,
+ 44, 43,172,211, 80,185, 34,157, 13,254, 73,133,108,167,153, 73,110, 58,212,124, 76,167,200,119,206,185,175,140,211,219,115,250,
+250,186,121,150,106, 87, 41,102, 86, 4,217, 99, 69, 62, 95,180, 64, 96, 69,237, 98, 6,161,177, 7, 30,160,125, 30, 51, 92,167,
+ 42,240,231,133, 50, 92,240,205,148,102, 10, 42, 3,172,240, 74,138,188,202,201,222, 50,206,202, 2,106, 70, 70,243, 90,193,183,
+223, 26, 33, 89,187, 38, 56,211,173, 73, 82, 68,134, 29,100, 33,180, 43,195,241,146,165,129, 30,115, 42, 79, 82,234, 84, 82, 20,
+ 61, 53,220,158, 22,104,113,246,115, 98,169, 87, 66,163,180,230,226,223, 48,159,157,245,162,217,109,215,233, 84,130, 15,134,212,
+ 53,167, 42, 99,197, 78, 84,181,167,226,199, 98, 53, 30, 10,163,245, 54,234,111,196,144,202,209, 82,166, 75, 80,109,137, 72, 83,
+ 78, 49, 38, 59,153,147, 79,146,210,250,165,126, 35,100, 96,227, 24,215,127,118,138,242,164,110, 62,192,109,157,106,149, 47, 30,
+229, 76, 54,197, 89, 17,150, 68,186,101, 86, 23, 51,106, 97,104, 7, 45,130, 23,217, 88,202,117, 28,118, 20, 81, 23,136,105,153,
+198,204, 58,139,149,189,143,111, 45,236, 65,254, 3, 29, 5,199,185,104,158, 14, 29,203,164, 80,217,101, 77, 86,170,133, 93,209,
+180,199,170, 20, 96, 14,241,187, 6, 37,127, 93,148, 45,136,181,242,106,229,223, 42,176, 31,122, 91,235, 11,114, 43,173, 63, 43,
+152,169,199,159,143,135,153, 45,243, 30,101,243,182,162,159,187,215, 88,194,171,109, 42, 52, 22,155,105,229, 73,168, 62, 22,203,
+206, 5, 45,198,219, 49,203, 37, 62, 31, 54,124, 70,223, 9,248,135, 92, 47,174,172,242, 97, 74,133, 54,150,235,136, 92,152,237,
+ 58,252, 89, 13, 45, 92,139, 46, 50,219,136, 74, 20, 9,248, 28, 41, 32,143, 62,190,122,188, 83, 18,164, 54,242,101, 71, 65,114,
+ 44, 22,132, 53, 40,114,187, 30, 75,239, 23, 82, 65, 72,234,224, 65, 70,125,121,117, 30, 87, 45,172,129,168,158,155,237,126,135,
+115,211,189,187,236, 62, 56,127,142,130,130,138,154, 49, 79, 24,120,134,234,170,193,123,180, 96, 91,169, 10, 66, 18, 15,151, 77,
+128, 4,226,231, 71,140,106,110,203,144, 95, 44, 50,131, 42, 92,249, 46, 56,161,202,196, 32,136,201,141, 24, 96, 36,190,183,201,
+194, 51,149, 21, 28,117,214,187,111,102,251,181, 33,243,106, 81,228, 61, 14, 37, 33, 97,130,251, 50, 21, 30, 63, 51,105,194,152,
+ 98,106,148, 82, 95, 81,200, 60,195,245,138,142, 20, 14, 19,125,222, 75,250, 78,218,216,238,219,180,169,142, 42,187, 85,231,169,
+204, 91,107,109, 14,183, 50,106, 86,182, 24,105,167,112,133,173,168,202, 43, 80,230, 79,199, 45, 56, 33, 67, 58,228,228,187,229,
+250,132,217, 47, 75, 67,178, 96, 58,242, 83, 61,164, 56,226,208,226,208,181,175,198,125, 46,167,157, 35,226,117, 68, 43,152, 40,
+ 32, 32, 40,140,101,246, 58, 73, 18,147,146,135, 76,211,128,242,145,107,170,177,186,198, 9,237,250,205,184,185,216,218,219,233,
+112,238, 72, 56,183, 63,169,204,229, 28,252,143,135,165, 49, 82, 40, 35,235,170, 18,203, 36,204,173, 96,202,132, 24, 98, 13,183,
+146, 66,118, 56,218,122,181,245, 81,114,145, 37,110, 60,103,198, 97,207,125,165, 84, 31, 79,131, 90,163,190,219, 97, 10,108, 48,
+ 26, 9,169, 66, 90, 80,227, 47,128, 80,181, 33,204,169, 42, 79, 34,145,144, 27,238, 36,202, 77, 46, 61, 71,146,158, 91, 77, 34,
+ 80,129, 80,121,196,192,149, 37,107, 67,234,250,134,230,105, 96,211,223,104,169, 92,205,169, 77, 58,128, 83,145,140, 41, 90,141,
+ 75,174,173, 77,251,204, 9, 44,170,156,220,176,219,244,224,164,200,165, 79,117,183, 20,184,138, 75,160,173,218,100,118, 89, 33,
+ 75, 40,230, 73, 95, 94, 82, 7, 38,179,218,117,105, 35,154,151, 61,164,211, 34, 50,180, 74,121,186,147,237,205,163, 21, 60,162,
+ 29,110, 35,204,164, 37,216,238, 48,180,134,146,248, 5,180,189,243,232,211, 62, 92,169,112,162,228, 27,221,109,123,121,123, 16,
+109,110,225, 46, 44,215,186, 62,199,161,242,220,190,156, 36,113,114, 47,203,109,107,162,234,192,145,231, 26, 47,177,110,190, 75,
+ 27, 13, 65,145,137, 24,220,138, 82,100, 86,167, 67, 85, 85, 5,217, 21, 54, 83, 26,153, 91,143, 41, 84,218,173, 77,175, 19,157,
+ 16,100, 78,167,184,142,105,169, 96,169, 46,243, 41,104,121,178, 22,223, 34,202,155, 23,250,140,137, 20,138,148,138,125, 82, 20,
+234,253, 56, 69,122, 35,244,247, 86,135, 43,244,199,152,112, 33,197, 60,228, 96,159,173,226,132, 50, 84,121,113, 53,165,176,135,
+ 82,167, 71,194, 53,242, 20, 11,121, 84,166, 35,198,155, 38, 4, 37,169, 19, 41,142,209, 42, 19,225,165,233, 62, 34, 25,142,226,
+ 80, 30,113, 17,157, 66,149,252,196,164, 18,216, 82, 84,115,167, 38,148,205,126,152,227, 49, 97,220, 38,171, 81, 86, 91, 68, 26,
+187, 13,248, 14, 69, 97, 62, 35,143,138,156,112, 22,101, 41, 15, 18, 22,226, 10,194,136,230,230,233,134,127, 42, 6, 37,206,199,
+117,101, 43,181,186,143,180, 75, 2,110, 73, 96, 5,128,176, 42, 44,157, 77, 28, 1,181, 71, 86,166, 56,195,160,133,227,150, 34,
+ 10, 48, 60,200,165, 70,147,146,168,163,204, 71, 45, 85,148, 2,193, 25,163,195,167,111,214, 86,203,172,196,137, 45,186,155,174,
+161, 10,167, 73,203, 62,227, 94,136,211,232, 33,202,160, 82,127,192,238, 54, 24, 88, 10,120, 37, 1,208,149, 43,151,151,153,182,
+170,166, 34,105,117, 25,181, 40,161, 79,194,159, 53, 78,221,148, 2,130,244,202, 62, 11,173,203,168,196,140,210,177,239,188,139,
+ 79,188, 52,148,143, 25, 25,113,159,210,140,171, 8,167, 26, 85, 94, 65,131, 35,235, 11,102,226,130, 87, 49,132, 48,166, 27,155,
+ 34,167, 24, 20, 49, 81,133, 37, 81,151, 26,170, 90,112, 31, 21,124,188,252,170, 13,201, 72, 73,201,204,105,149, 74,157, 57,200,
+147,110, 38,154,139, 18, 67,205,195,153,115, 70,104, 51, 79,155, 83, 70, 23, 21, 85, 85, 0,161, 70,146,242,249, 2, 78, 76,126,
+101,128,219,173,128,148,235, 34, 80,196, 0,231, 83, 92, 1,220, 90,204, 10,145,112, 0,185, 42, 1, 2,236,108, 45, 99,136,197,
+109, 57,134, 90,147, 78, 60,243,173,165,136,149, 15, 48,189,215,148, 86,241,202,190, 93, 81,152,134,165,148, 13, 11,202,242, 35,
+169,110,248,110,177, 16, 67, 42,158,104,128,170, 20,215, 22,194,141,110,142,176,131, 25,131,225, 54, 11,133, 84,196,180, 99,164,
+ 18, 82,252, 36, 58, 2, 73, 90,181,243,137,137,169, 94,219, 91, 8,140,165,159, 30,241,143, 84, 66,139,156,202,240, 96,192, 62,
+ 18,156, 82,206,124, 78, 89,140,129,203,241, 21, 30, 76, 19,163,109,106, 99,148,203,129,215,161, 22,149, 70,170, 36, 45,108,171,
+ 31,224, 53, 5,243, 58,217,101,215, 79,193, 25, 79,185, 33, 32, 39, 1,165,190, 66, 50,135, 15, 45,187,123,227, 46,167, 87,178,
+ 45,198, 26,115,194,143, 66,171,214,144, 26, 91,156,200,171, 26,148,118, 84,145, 31,151, 10, 8,167,198, 11, 4, 31,135,197,207,
+235, 37, 39, 74,201, 56, 20,179, 48,220, 2,160, 89,137, 27, 48,218,251, 92,218,224, 27,108,182,181,237,189, 90,213,112,199,197,
+185, 37, 66, 63, 50, 26, 82,245, 33,186, 21, 2, 41, 29,149,214,224, 41, 89,127, 85, 64, 0,155,129,164,168,195,121,106,210,157,
+ 49, 16,180, 67,123,221,105, 23,132,151, 98,143, 8,133,181, 9,233, 2,160,114,132,149, 41,152,202, 77, 80, 0,122, 20,224,133,
+140, 19,174,145,216, 85, 22,174,139, 58,117, 20,167,255, 0,116, 45,215,218,183, 92,253, 48,116, 59, 66,168, 71,135, 84,162,201,
+ 91,137, 33, 46,115, 83,165, 76,101, 96,101, 41, 92, 44,103,200,106,117,145,110,169,112,231, 15, 1,196,123,195, 84,153, 12,178,
+ 20,148, 41, 94, 28, 38,226,200,119,157,100,120, 95,165,138, 1,112,228,146,114,114,161,173,186,219, 8, 70,145, 86,150,137, 9,
+ 45, 70,158,138, 76, 55,148,216, 65,109, 45,150, 86,152,239,128, 57, 65, 12, 75,229,234,122,225,213,148,244,209,114,119,104,171,
+ 4,128,125, 92,254, 87,191, 96,110,192,158,223,104, 2,109,189,142,214,189,197,123,226,102,115, 14,101,151,130,175,170,167, 41,
+126,116, 54, 59,220, 24,181, 41, 23,243, 93, 94, 65, 97,177,125, 39,160, 56,182, 92, 20, 69, 77,185,225,210,208,218, 12,121,177,
+214,245,101,132,175,147, 20,200,207,169, 77, 67, 12,161, 64,187,239, 14, 55, 24, 58, 82,112,164,176,232,229, 32,231, 94, 29, 77,
+ 69,138,133, 70, 29, 29,163, 30,174,236, 24, 12, 74,171,176,182, 29, 93, 18,157, 80, 46,135, 10, 99,172, 22,209, 86,126, 34, 28,
+247, 86, 74,249, 90, 42, 50,212,149, 37,164,133, 61,149, 74, 50, 96,174,108,231,227,148, 73,104, 70, 98, 34, 90,232,251,142, 52,
+174, 65, 30, 63, 46, 28,230,126, 90,201,119, 25, 60,138,113, 64,225,189, 82,183,173,152,148,155,102,178,203,203, 68,215,166, 72,
+114,183, 95,156,227,173,149, 84,171, 51, 30, 74, 27, 67, 12,173, 36, 52,203, 81,219,102, 60, 68,130,144,203,109,165, 36,133,120,
+138,212,193, 31, 77,212,144, 72, 34,198,251, 27,245, 44, 15,154,214, 6,230,224,239,182,149, 3, 21, 18,113, 76, 43, 65, 3, 50,
+137,214, 49, 12, 40,135,117,121, 29,209,158, 71,223, 75, 42, 46,136,204,108, 8,145,132, 74,193,144, 72, 75, 74,213, 54, 21, 45,
+ 76, 91,246,218, 94,139, 17,193, 28, 86, 29, 14, 46,115,208,212,249, 67, 77, 64,167, 72,144, 20,185,149,135,226,180,158,101,145,
+202,195, 40, 83,141,144,227,200, 2,245, 21,216, 52, 92,248, 96, 70,161, 83,252,103, 98,197,145, 15,156,115, 78,109, 49, 66,157,
+109, 1,110,205,152,167, 16,175,119, 65,203,206,130,172,229, 69, 42, 23, 85,184,213, 38,116,122, 77, 49, 30,243,112, 48,191,122,
+156,175, 0,120, 52,218,131,205, 97, 18,106, 83,146,149, 4,194, 76, 0,146, 91, 88,241,164,101, 41,109,188,184, 10,126, 34,216,
+ 84, 0,137,213,234,155,149, 73,236,160, 76, 76,164,176,212,104,116,198,150,183, 7,131, 18, 42, 93,229,167,198,253, 69, 23,214,
+ 76,149,151, 57, 71,195,200,157,109, 69, 33, 82,243, 60,133,180,234,176,248,250,244,211,107, 91,226, 72,211,167,112,188,181,209,
+ 76,160,213,204,197,106, 0, 96, 24,179, 79, 82,204, 72, 51,121,144,128, 10,249, 98,149,218,225, 28,149, 89, 27,152,205, 94,144,
+220,249, 80,209, 79,171, 70, 91, 20,181,184,135, 92,141, 50, 72, 14, 84, 76,118, 19, 36, 34,177, 25,151, 21,138,119,187,114, 19,
+ 21, 68, 12,117,150,149,132,150,213,150, 54, 98,220,136, 16,188,119,163, 67,101, 5,113,196,105, 72,165,185, 82,119,197, 5,126,
+248,228,114,219,144,233,141, 70, 67,104,106, 56, 82,124, 82, 79,136,218, 88, 9,105, 88,156,247,222,169, 82,227,191, 45,232,212,
+218, 11, 78, 71, 98, 59,143,161,113, 39, 84, 75, 46,153, 13, 76,172, 45,229,243, 37,135, 29,104,251,180, 52,101,110, 6,210,236,
+148,169, 74, 12,138,140, 74,153, 50, 51,206, 33,177, 76,164,162, 59, 73,171, 73, 72,104, 78,168,197,125,231,124, 63, 6, 48,109,
+102,142,200, 60,234, 28,229, 82, 93, 7,244,104,105, 39, 91,241,105,141, 99, 37,254,169,195, 11, 90,214,220,144, 53, 30,151,233,
+216, 2, 62,226,207, 81, 79, 37, 64, 53, 1,150,150,100,144,129,164,144,145, 57, 33,117, 0, 73,102,157,197,144,162,146,201,229,
+185, 91, 7,133,199,163,200,101, 79,198,131, 70,106, 76,183, 83, 33, 17, 40,212,166, 60, 24,241,189,234, 27,101,247,106, 85,121,
+ 13, 51,138, 77, 9,190, 85, 34, 58,146,217, 82,185,213,225,182,227,202,108, 33,244,163, 51, 30,132, 13,122,179, 61, 46,206,167,
+178,218,106, 21, 83, 17,198,105,113, 16,255, 0,130,203, 84,152, 48,121,220,112, 58, 60, 70,144,219, 72, 14,202,154,226, 91, 75,
+137,117,229,164, 37,133,166, 84,233, 54,205, 18,152, 42, 78, 72, 74,100, 38,109, 70,157, 75,167,176,101,215,110,185, 45,168,183,
+ 26, 21, 45,132, 58, 22,233, 81, 25, 47, 73, 45, 70,101, 9, 42,121,228, 37, 28,165,217,183, 32,206,171, 85,105,149,250,165, 82,
+149, 14, 75, 94, 12,218, 69,174,167, 26, 93, 42,136,182,199, 51,171,157, 33,213,135,234, 53, 63, 17,100,187, 57, 41,104, 33, 40,
+ 8,142,218, 24, 74,121,221,169, 86, 22, 72,193,212,205, 96,202, 46, 67, 48,184, 22, 31,101,130,133,184, 4, 88, 49, 35, 72,181,
+216, 86, 28, 81, 1,116,150, 73, 25,169,242,225,205, 66,229, 73,146,164,163,105,104,209,130,181,131, 0, 76,135, 75, 68,143,118,
+149,228,145, 98,129, 95,138, 36,233,202,152,138,141, 93,169,141, 69, 80, 30,227, 5,244, 43,222, 82,165, 36,243, 74,171,176,208,
+ 41,106,160,226,222, 82, 83, 28,169, 98, 40, 10, 73, 90,220,201, 68, 52,254,150,111, 2,144,225,187,179,158,209,187, 10,132,211,
+ 79,213,165, 82,118, 15,137, 25, 20,246,210,148, 75, 91,140,190,246,200, 95,117, 36, 32,115, 57, 41, 10,102,175,109,202,146,122,
+ 41, 18,232,108, 40,225,134,134,166, 17, 71,172, 75,173,183,254, 28,202,224,136, 19,125,223,220,189,237,247, 37, 21,179, 37,214,
+ 81, 80,121,191, 1, 45, 16,166,130, 31,105, 33,106, 75, 76,149, 56,163,206,177,200,205,113,141,195,133, 51,141, 78, 12,248,147,
+225,150,176,148, 59, 23,119,182,166,230,182,237, 57, 15, 97,150,105,151,140, 70, 87, 85,176,107,200, 50, 27,253, 3,177,111, 58,
+ 93,191, 49,181, 28, 41, 2, 57, 60,193, 74,200,158,100,149,102, 22,210,191, 88,166,198,203,123,107, 2,250, 84, 17,179, 17,170,
+ 37, 36, 88, 6, 45,176, 1,135, 60,241, 94, 80,210,197, 55, 50, 52,167,146, 27, 38,149,177,141,119,250,189, 44, 46, 13,254,219,
+ 16,222,117, 4,220,220,223,242, 16, 41, 10, 0,121,103, 35, 29, 63, 35,174,144, 0,146,129,231,232,122,252,251,246,242,213,103,
+105,213, 58, 52,201,244, 90,252, 69,192,174,208,170, 53, 26, 21,114, 3,128,135, 96, 86,232,211, 30,166, 85,233,238,115, 96,133,
+177, 82,139, 41,165,103,205,147,175, 33, 3, 57, 79,194, 14, 78,124,199,203,236,212,253, 72, 96, 25, 78,160, 70,198,251, 27,216,
+220, 31, 76, 83,251,247, 22, 56,241,142, 65,215,160,207, 76,143, 35,229,243,210, 78, 79,144, 72, 39,250,186,145,142,218,250, 74,
+136, 25,198,115,208,129,220,124,245,247, 36,146,124,191,217,244,236,126,205,103,127,191, 3, 30, 72,200,230,229,206, 58,121, 15,
+199,215,251,117,236, 5, 31,245, 72,242, 7,190, 62,223, 76,233,114,133,144,114,164,245,198, 7, 65,219,215,238,215,190, 92,127,
+ 56,224,103, 31, 47,191,211, 67,221,233,129,138, 43, 71,124,156, 15,196, 14,221,186,244,208,171, 3, 3,191,166, 64,201,249,119,
+249,234,232,212, 41,147, 22,132, 71,105, 74, 46,186,134, 91, 32, 16, 29,125,194, 18,211, 12,249,188,250,213,209, 40, 72, 43, 89,
+ 56, 72, 39,166,186, 71,195,191,178, 43,142,110, 36, 99,196,171,219, 27, 61, 83,178,237, 25, 97,151, 26,188,247, 98, 90, 54,206,
+131, 38, 59,229, 63,225, 52,182,171,241,205, 66,178,148, 52,175, 16,166, 60, 5,115, 36, 97, 43,202,147,157,121,171, 41,169,236,
+ 37,148, 43, 55, 69,234,199,224,162,228,159,112,198,205, 37, 29, 93,124,188,138, 26, 89, 43, 38, 29, 86, 36,103, 32,122,182,144,
+116,143,123, 88,123,241,204, 5,140,156, 36,231, 29,252,135,224,124,251,232,117, 0, 14, 70, 1, 7, 7,183,159,203,207,166,117,
+177,124, 80,240,223,126,112,157,189,183,214,195,110,107, 49,211,119,216, 53, 54, 96,207,155, 77, 84,151,104,213,200,115,224,199,
+169,209,174, 75,118, 76,184,204,185, 50,223,157, 79,148,219,177,157,113,166,212, 74, 28, 66,144, 20,218,181,174,203,234, 48, 7,
+159, 79, 94,255, 0,111, 83,141,108, 83,203, 28,200,146,198,218,163,144, 2, 58,142,190,160,216,223,220, 69,240,155,199, 36, 18,
+203, 12,200, 98,158, 22,100,116, 59, 50,178,157, 44,164, 14,132, 16, 65,247,140, 12,160, 58, 18,122, 12,253,253, 63,179, 67,171,
+168,200, 61, 58,140,249,227,207,167,231,182,138, 63,173,208, 17,223,167,203, 25,201,252, 53, 69, 64, 1,142,253,115,246, 15, 67,
+173,144,108, 65,244,198, 70,227,125,199,254, 48, 26,129,245, 28,189,186,140,125,224,250,245,208,171,192,201, 25, 7,255, 0,104,
+122,103, 69,184, 70, 72, 57, 0, 30,195, 29,124,186,126, 31,179, 66, 47, 62,163, 30,158,121,249,116,210,202, 73, 23, 56, 0,108,
+ 61, 54,192,202,193,193,193, 4,247,206,116, 58,199,159,175, 67,233,162, 87,235,229,140,122, 96,250,252,244, 58,129,201,200,200,
+251,113,131,219, 56,209,199,198,216, 54, 6, 88, 0,100, 39,175,203,167,231,251, 52, 43,131, 39, 36, 2, 64,236, 58,254, 63, 61,
+ 22,231, 76,100,244,201,251, 60,134,132, 80, 30,188,221,127,104,193,245,251, 52,170,155,223,107, 91, 25, 22,223, 2, 44, 12, 18,
+ 70, 49,219,212,117,237,161, 87,243,234, 15,111, 44, 31, 92,249,249,232,197,140,103,249,222,127,105,251, 6,133,115, 24,236,123,
+246,244,239,223,229,165,147, 10,139, 27,123,190,126,126,252, 12,188,246,199, 76,103, 62,152,254,142,154, 13,206,249,201, 78, 51,
+156,140,231,211, 31, 46,250, 49,194, 2,122,244,243,207,151, 79, 93, 90,212,167,148,162, 20, 50,159, 34,158,248, 35,184,244,210,
+152, 2,247, 55,232, 48, 59,171, 82, 85,220,156,231,177,199, 79,179, 75, 84,137, 89, 82,129, 64,192, 61, 9,238,125,123,157, 45,
+ 11,159, 92,102,195,211, 7, 1,145,228, 49,230,115,215,175,153,251,245, 85, 41,199, 65,212,158,255, 0,159, 77, 82, 78,114, 7,
+145,207, 79, 35,223,203,237, 26, 37, 0,231, 61, 49,231,219,242, 53,130, 1,198,113, 85,164, 37, 39, 24, 29, 70, 51,230,123,121,
+232,129,156,245, 31, 8, 29,193,235,233,231,223,190,169,163, 29,176, 58,117, 7, 26,244,121,242, 2, 82, 20, 60,250,224,142,189,
+251,246,210, 76, 0,248,223, 3, 5, 39, 29, 51,146, 59,252,240,123,103,174,138, 64,206, 8, 35, 31,183,240,208,109, 54, 70, 78,
+ 78, 73,235,147,144, 6, 78, 6, 51,215, 70,163, 57,233,142,157,199,203,229,162, 27,218,255, 0,203,124, 17,187,155,224,134,240,
+161,156,231,174, 64,235,211, 29, 63,164,104,132,168,143, 60, 14,199, 24,243,245,249,127, 86,168,160, 96,103,207,203,243,246,141,
+ 16,132,224,228,245, 7,174, 63,160,231,215, 73, 16, 5,253,223, 39, 9, 28, 86, 71,127, 62,223,143,231, 58, 44, 1,220,122, 99,
+160,192,252, 52, 58, 82, 7,219,143,207,238,213, 86,242,162, 60,134,112, 57,142, 0,243, 42, 62,128, 12,232,167, 5, 97,182,231,
+108,101, 54,149,175, 93,188,238, 42, 37,171,108, 82,103,215,174, 43,142,169, 10,139, 68,162,210,216, 92,170,133, 82,169, 80,121,
+ 49,225, 64,134,195, 96,151, 31,113,229,164,118,194, 70, 84, 72, 0,157, 78, 55,217,195,236,235,180, 56, 5,219,136,183,189,229,
+ 6,143,114,241,101,120,210,144,245,197,112,186,195, 83, 99,109,101, 38,115, 41,113, 22, 77,152,167, 82, 66, 42, 9, 66,147,245,
+132,212, 0,227,174,130,132,144,210, 64, 58, 65,236, 48,224, 78,145,183,150, 91, 28,115,238,229, 25, 47, 93, 23, 10,101,211,120,
+127,163, 84,163,165, 73,163,211, 57, 87, 30,165,184, 46, 48,226, 73, 76,201, 4, 45,184,107, 35, 40,101, 37,105, 33, 78,103, 93,
+206,171,207,168, 77,158,242,214,234,165,120,206, 45,240,239, 57, 83,188,203, 36,252, 62,157, 9,239,170, 51,196, 46, 48,105, 37,
+147, 42,160,151, 76, 16,146, 37, 96,109,169,129, 27, 92,118, 83,208,119, 32,181,143,145,135,112,125, 25,188, 13,143, 54, 16,113,
+223, 19, 82,137, 17,172,244, 16, 72, 60,170,157,125,165,213,191, 93,246, 49,126,194, 16,247,212,254, 92,102,175, 95,155, 82, 46,
+162,100,151,208,236,151, 84, 86,135,157, 83,143, 45, 96,146, 94,142,181, 28,149, 31,231, 39, 61,245, 66,141,115,205,137, 57,175,
+ 1,247, 75, 76, 35,195, 76,148, 41, 72,125, 46, 37, 67,149, 50, 80, 63, 89,178,122,100,246, 29,245,245,218, 59,147,164, 45, 78,
+ 62,215, 50,202,148,134,101,254,133,244, 62,145,140,180,188,124, 11, 56,232, 71, 67,171, 83,148,233, 49,170, 13,190,247,248, 44,
+245,182, 90,104, 56,144,150, 39, 33, 63, 10,154,125, 67,225,241, 20,158,202,245,193,243,213, 56,106, 88,146,193,203,105,235,239,
+ 59, 19,191,201,199,127,158, 23,202,218,157,233,146, 24,236, 81,136, 80, 46, 1, 43,107,143, 46,174,130,197,183, 3,169,212, 47,
+102, 23,138, 45,142,166,222, 16, 42, 27,183,108,211, 81, 10,232,163, 70,247,155,186,155, 13,174, 83, 92,132, 0, 8,170,165,134,
+192, 6,115, 39, 5,106, 72,203,136, 86, 73,233,166,207,131,205,208,115,108,174, 89,118,133,206,234,163,216, 59,146,166, 20,169,
+ 42, 82,136,161, 93, 77,252, 49, 42, 33, 4,225,182,215,204,148,185,216, 20,171, 61,198,186, 27,110,114,132,166, 53, 69,148, 59,
+ 30, 90, 23, 25,101,236,171,154, 43,201,240,223,133, 36, 17,241, 35,145, 74,229, 39,161,215, 63,238,253,167,145,106,238,109,193,
+110,177, 27,154,158,103,166,165, 71,109,208, 75, 65,135,207,188, 66,117,149,227,252,159, 41,228,233,219, 3, 75,181, 66,188,109,
+ 27,157, 72,221, 61,223,199, 99,123,219,220, 65,219,108, 51,192, 88,210, 85,228, 53,174, 76,116,104, 30,157,201,185,229, 35, 0,
+ 2, 19,125,224,147, 75, 37,239,101, 33, 13,213, 69,250,103,114, 80, 10,102,173, 46, 58,164,199,113,180,212,163,184,159,141, 18,
+ 38,180,144, 27,150,219,136,255, 0, 40,194,218,193,244,234, 52, 13, 53,152, 76, 85,228, 75,126, 75,175, 83,218,112,212,170, 11,
+111, 28,170,135, 77,132,169, 78,242,115, 15,209,175, 45,242,143,153,236,117,227, 97,231, 85,171,148, 38,109,155,155,154, 91, 20,
+248,232,126,139, 84, 87,199, 38, 34, 85,134,223,163, 74, 82,186,185, 28, 40,126,141, 95,205, 7, 30, 67, 69,110,125, 33,219, 19,
+109,119, 58,172, 90, 66, 93,116, 66,166,211,214,225, 63,160,250,214, 82, 3,169, 64,233,241,150, 27,112, 39,168, 3,155, 62, 88,
+ 58,244,144,243,106,233,148, 11,197, 35,128,123,129,109,205,246,238, 6,199,184,235,108, 71, 42,184,155,216,242,188,198,154,162,
+ 95,237,180,208,232,140, 11, 90, 66,236,136,172,189,245, 3,160,145,212, 16,122,249, 73,227,159, 17,187,137, 50,231,190,101, 63,
+ 18,112,228,140,252,162,176, 30, 62, 10,228, 73, 82,164, 22, 95, 72, 63, 2, 91, 10, 66, 22,112, 8, 82, 66,185,126, 28, 29, 79,
+145, 81, 80,168, 42, 68,213, 63, 12, 37,188, 63, 45,130,209,128,132,156,150, 26, 75,203, 73, 74,254, 39, 10,138, 92, 67,124,164,
+229, 42, 25, 25,186,221,245, 35, 87,185, 43, 18,155, 90,227, 77,126,164,251,143, 7,129,118, 51,188,178, 11,120,144,148,242,135,
+ 91,232, 71, 50, 10, 92, 36, 36, 39,211, 88,139,213,131, 77,117,196,212, 27, 16,219, 83,220,225,196,169, 47,211,101,161, 71,194,
+ 11, 92,133, 4,174, 9, 66,203,105,113,183,145,240,248,193,124,202,108,130, 38, 34, 59,179, 29,137,125,253,230,246, 63,127,165,
+250, 13,186, 11,218,248,225,108,186, 60,159, 36,202,104, 33, 80,239, 79, 18, 6,232, 36, 44,108,206, 88,216,171,134,102, 58,137,
+189,193,232,183,182, 51,138,107,197,167, 35,145, 32,194, 75,137, 45,162,170,204,129, 26, 59,172, 0, 57, 16,250, 88, 42, 67,173,
+168, 44,132, 33, 97,105, 81, 89,194,193,192, 15, 21,183, 34, 93,189, 17,133,173,196,213, 88,150,133,188,239, 51, 44,199,149, 29,
+ 45,142, 86,210, 82,135, 2, 38, 68,112,144,144,148,168, 41, 39, 32,133, 0, 2, 89,200, 80,154,117,109,186,212,100,199,139, 80,
+101, 13, 33,216, 78,199,114, 51,238, 37, 74, 91, 78,189, 27,148,178,231, 80,164,172,130, 9, 41,201,238, 14,179,250, 11, 83,227,
+182,194,154,145, 2,161, 25,212,187, 44,196, 66,213, 18,124,111, 5,107,100,166, 20,148,169,198,211, 12,115,175,153, 42, 74, 80,
+ 70, 78, 78, 51,166,186,192,172,178, 6,109,136,220,117,189,189,227,117,177, 30,160, 27,119,233,139, 14,158,162, 39,142, 0,101,
+ 66, 93,128, 10,247, 70,216,130,108,214,176, 96,108, 65,243, 95,175,187, 27, 7,111,210, 27,168,182,211,116,199,151, 78, 75,232,
+110, 83,209,169,177, 26,125, 10,125, 72, 91,143,187, 34, 34,142, 34,172, 0,129,128,132, 45, 73, 72, 9, 43, 56, 80,206,163,202,
+184,216,125,223, 26,158,154,225, 56, 80,114,142,180, 69,150,162,178,150,227, 46, 61, 62,106,200, 76,129,146, 74, 91,146, 28, 87,
+ 54, 67,121, 73,211, 37, 69,159, 9, 83, 19, 42,175, 34,171, 13,106, 74,227,154,156, 84,200, 79,185,120,108,229,135, 25,169, 81,
+213,250, 96,176,134,208,128, 65, 64,248,130,145,141, 58,116, 74,219,236,148,159,175, 97, 86, 33,180,182, 20, 87, 17,108,199,169,
+180,216, 91,106, 47, 79,130,128, 61,245,230,208,113,204,207, 34,215,156,148,247,212, 94,170, 25,163,109,148, 76,140, 5,245, 41,
+218,254,142, 8,213,107,116, 44, 47, 97,229, 55,198,205, 75, 85, 29, 71,255, 0, 73, 68, 85, 96,178,164,159,111, 98,202,179, 71,
+229, 98, 69,134,130,202, 77,238, 0, 83, 96,239, 82,107, 84,106,164,152,205,214, 16,245, 17, 75,247,101, 22, 43, 1,232, 83,105,
+203,136,165, 50,229, 98, 34,151,202, 17,226, 61,202,145,202,178, 48,162,146,142,250,216,251,105,128,186, 36,170,100,211, 22, 67,
+ 77,176,209,122, 60,214,153,145, 30,167, 10, 65,240,214,164,164,158, 79, 13, 73, 45,115, 37,224,181, 33,120, 81,230, 79, 42,131,
+ 59, 69, 16,106,201,139, 50, 64,129, 87,142,243,161,150,146, 80,211,168, 90, 71,134,148, 54,236, 25, 3,150, 43,129, 5,101,229,
+ 41, 92,199,162, 51,130,112,245,208,236,136, 14, 52, 88,165, 63, 50,139, 34, 51,197,246, 98, 51,239, 14, 83,216, 91,139,113,121,
+ 76, 73,110,172, 58,223, 48, 72, 13,160,134,135,112,144, 6,154,194, 70, 23,117,229,143,129,216,236, 71, 80, 47, 96,118,184, 4,
+222,231,114, 6, 41,222, 44,205,105, 4, 73, 28,205, 45, 7, 45,193,177,250,212,141,149,187, 31, 44,137,107,144,124,172,109,102,
+184,117, 1,243, 59, 82,158,154, 90, 88,167,200,142,181,210,164,169,181, 70, 81, 89,144,237, 61,164, 97, 8,142, 95, 89, 89,114,
+156,227,128, 6,143, 58,148,202,185,146,172,161, 73, 41, 58,230,163,187, 82,190,163,190,164, 15,240, 15,170, 97, 12,245, 79, 47,
+184,169, 46, 41,174,193, 14,169,111,140,231,161, 40,198,122,227, 89, 5, 18, 3,176,154,143, 6,166,202, 9, 1, 73,143, 61,174,
+116,199,117, 99, 11,126, 47,134, 18, 84,193,229, 10, 37, 10, 37,180,225, 64, 40, 28, 13,100,168,166,120,245,217, 15,133,120,168,
+146,220, 87,219, 46, 28,171, 6, 52,112,158,128,225, 60,175, 70, 87,197,205,140, 40, 16,112, 64,214, 42,193, 90,101, 10,126,211,
+169,184,233,123, 31,188,110, 72,220, 3,125,207, 67,138, 55, 49,206,155,219,234, 42,132,129,216,197, 32, 46, 15,145,195, 50, 2,
+235,191, 86, 80, 85,250, 18, 70,227, 86,166, 57,149,157,109,178,148,183,224, 71, 1,183, 35,200,142,217, 40, 25, 72,109,212,201,
+ 82,185, 20,122,144,165,158,100,158,128,171, 25,198, 50,253,209, 40,136, 75,137, 56, 90, 16,244,102,139,216, 60,229, 92,174, 20,
+160, 14,224, 59,241,225, 62,105,200,244,214, 51,107,195,108,165,151, 16,146, 22, 20,133, 20, 2, 74, 64,121, 60,138, 65, 87, 76,
+ 96,117,207,114, 8,243, 3, 79, 5, 53,182,146, 64, 57,193,111,145, 35,178, 84, 80,226, 28,232,165,126,162,177,219, 31,234, 19,
+220,105,223, 44,132,121, 88,223, 77,198,253,250,119, 62,253,247,252,113, 75,113, 30,119, 60,175, 32, 4,249,186,239,191, 91,252,
+ 54,176,222,214,184,191,174, 50, 89, 20,195, 81,143, 72,144,180,173, 79,134, 84,226,176, 3,206, 10,131, 10, 49,156,120,149, 12,
+182, 3, 33,100, 31, 37,188, 73,238, 14,172, 46, 81, 36,215,106, 78,136, 82, 13, 46,159, 29,244,173,218,140, 98, 3,147, 86,130,
+148, 42,159, 79,101,212,148,184, 90, 82, 9,117,242, 64, 39,157,182, 86, 64, 39, 89,163,142, 4,210, 26,113,106,112, 18,169,104,
+109, 13,148, 32,151, 20,219, 9, 95, 85,156,163, 43, 88, 5, 64, 16, 3,157, 50, 73,215,199, 43, 45, 65, 83,113, 91, 14,161,136,
+145, 25, 84,196,198, 1,231, 22, 91, 74, 20,150,219,107, 33, 42,116,156, 18,165, 16, 57, 84, 58,142,131, 82, 86,141,140,129, 80,
+ 14, 99, 42, 29,250, 93,128, 39, 98, 55,238, 64,233, 99,214,219, 98,176,130,186,186, 61, 66,153, 3,200, 12,138,151, 0,172,107,
+174,228,216,130, 24,139,170,168, 32,128, 73,218,246, 35, 9,159, 71,167,209,161,120, 20,248,236,194,134,100,203, 91,178, 29, 95,
+186,251,203,202, 90, 28,149, 81,118, 76,215,143,188, 39,196, 74,202,151, 33, 97, 35,155,151,196, 40, 72,195, 37, 84,174, 73,169,
+ 84,154,106,129, 77, 18,105, 49, 10,229, 68,157, 80,241,218,102,167, 32,224, 55, 84, 90, 25,111,222,102,198, 15, 5,251,154, 64,
+109, 11,229, 46,180,231, 39, 33, 15,133, 74, 59,117,246,189,234,168,242, 95,136,212,199, 36,199,182,218,105,167,105,241,249, 74,
+146,211,181,151, 92, 73, 53, 87, 2,149,206,150, 9, 76, 54,221, 64, 80,109,197, 32, 43, 88,189, 94,149, 6, 43,205,191, 86,230,
+247,217,135,221,162,211,216,142,170,140,185,124,205,173, 45, 70,131, 10, 58,124,106,140,226, 75,124,160, 0,202, 50, 8, 82, 18,
+ 57,198,220, 72,224,134,210, 45,176,191, 96,122, 95,208, 6,189,206,219,216, 29,247,196,207, 33,174,134,153,155,219, 85,171,171,
+156, 48,220,187, 89,207, 83, 96, 67, 75, 32, 91,221,193, 17, 45,216,175, 48, 50,178,224, 84, 74, 44,154,236,184,109, 72,113,234,
+237,116,165,197,177, 54, 82,143,185,194,138,164,184,249, 16,105,241,143, 44,103,208,121, 50,164,146,226,240,182,220,119, 4,235,
+ 37,164, 65,153, 92, 80,137,106, 70,139, 82,125,151,164,197,155, 93,168,123,196,123, 46,150,251, 8,240,252, 17,238, 40, 42,185,
+170,222, 34,155, 80,141, 16,150, 88,230, 75,114,101, 51,130,141,103,113,118,222, 84,228,199,126,232, 95,240,106,136, 16,215,189,
+218, 86,235,201, 53,185, 52,220,146, 81,114, 92,236, 97, 49, 90,112,128, 36,194,166, 1,146,181, 52,236,199,138, 84, 53,147, 85,
+149, 73,182, 92,129, 6,223,109, 81,169,207,198,147, 79,163, 83, 41,232, 5, 82, 81, 29,145,152,108,180,165, 54, 91,134,211,156,
+200,113,210, 18,218, 3,193,103,153, 99, 39,101,145,165, 85,144, 39, 49,211,208,128,187,218,251,146, 58, 53,134,171, 94,215, 4,
+ 88,173,147,175,226,120,170,103,246,122, 6, 21,149, 44, 27, 66,168,189, 44, 37, 67, 23, 6, 68, 33, 36, 54, 58,210, 58,127,236,
+202,171,173,165,149, 12,145, 11, 77, 10,223,167, 90, 47,203,153, 93,154, 39,203,117,178,229, 86,225,153, 22, 43, 10, 90,217, 97,
+108,173,148, 73,109,194,197, 34,138,149,128, 98,176,158, 86, 18,160,180, 32,169,197, 18,171,243, 12, 71,188, 39, 42,174,205, 61,
+ 18, 45, 72,169, 45, 52,144,181, 82, 30,158,238, 86,184,179,219,134,160,218,163, 82,146,160,225,109, 14, 58,219,178, 20, 76,135,
+249, 18, 91,109, 56,227,176, 25,153, 75,137, 81,185,166,184,212, 78, 68,193,165, 81, 33, 56, 20,195, 85, 39, 10, 11, 82,165, 48,
+193, 47, 87,234,137,240,209,202,128,158, 72,168, 70, 91, 66, 74,214,240,187,209,162, 25,147, 29,241, 80,243, 20, 40, 45,185, 21,
+234,107,146, 57,170,243,146,235,172,178,227, 19,125,225,132, 36,196, 91,197, 42, 68,112,151, 28, 82, 94, 80,113,210, 62, 13, 58,
+210,106, 66,183, 75, 35, 17,168,117, 97,109,198,228, 16,111,212,237,190,224, 90,197,113, 23,172,103,117,158,190, 74,182,147, 48,
+ 80, 99,105, 64,211, 10, 1,101,209, 78,168, 99, 38,107,105,141, 52, 17, 20, 68,221,110,162, 55, 14,212, 81, 18,171, 73, 69, 54,
+151, 80,170,193,183,229,135,231, 85, 42,149, 41, 47, 79,143, 80,247, 20, 52,203, 16, 98,229,240,126,168,115,170, 31,125, 39,149,
+208,202, 26, 10, 40,231,230,113,232, 15, 68,139, 87,166, 53, 26, 60,198, 94,122, 51, 68, 71,148,250,148, 25,103, 63,162, 83,229,
+ 41, 41, 99, 37, 69, 44,160, 37, 60,201,103,152,129,206, 20, 27,135, 43, 8,141, 22,153, 2,220,110, 28,171,174,170,134, 89,142,
+153,169, 66, 35,209, 88,108,174, 57,126, 80,125, 99,220, 96,135, 91,113, 92,141,161, 33,199, 27, 75,101, 92,216, 34,241, 2, 53,
+ 62,152,134,101, 34,161, 49,233,206,169,137,117, 56,178,156, 90,231, 45,245,190, 29,112,130,215,199,159, 17, 9,113, 10, 64, 72,
+240,130, 80, 82, 83,212, 76,105, 31,217,222, 25, 64,230,104, 8,110,162,224, 1,102,223, 85,193, 99,246,172,183, 96, 73,103, 47,
+101, 81, 84,230, 84,205, 52, 18,164,134, 72,163,156,202, 35,140,221,164,118, 98, 85,165,150,214,109, 39, 74,162, 72,246, 71,229,
+ 5, 65, 26,139,159,203,207,219, 83,176,204,240,223,237, 79,227, 35,111, 41,204, 69,139, 67,175,238, 80,222, 59, 98, 36, 38,195,
+113,161,208,183,162,149, 7,112,132, 52,182,144, 3,101,170,213,102,182,215, 40,232,148,176,158,221,135, 48, 73, 36,100, 96, 99,
+184, 61,250,246,212,159, 62,150, 45,137, 6,222,246,135,108,254,224, 66, 67,137,123,117, 56, 94,183,220,168,135, 22,209, 74,230,
+ 88, 87,181,215, 66,109,109,161,180, 2,209, 52,250,172, 0,176,165, 45, 68,165, 61, 64, 1, 34, 48, 64,228, 21, 18, 15,251, 56,
+236,115,211, 86, 37, 3,171, 82, 68, 23,236, 70, 90, 53,182,195, 76,108,209,131,111, 66, 22,227,189,136,190,247,199, 60,230, 49,
+152,171,170, 80,253,162,193,143,184,200,162, 66, 62,237, 86,255, 0, 76,120, 41,206, 48,160,113,145,142,217,207,150, 15,125,123,
+ 0,227,148, 14, 92,116, 63,209,247,244,215,220, 39, 25, 35,191, 83,230, 71,159,125, 87,109,178,242,146,134, 70, 92, 87, 96,172,
+ 36, 4,128, 84,165, 45, 71,162, 80, 0, 36,146,112, 0,201,233,173,195,210,228,218,223,187, 26, 93,174,118,199,134, 90,117,213,
+ 33,166,208,167, 28, 90,185, 80,132, 2,165, 40,158,192, 1,174,165,240, 33,236,163,226, 11,141,133,195,187,161,181, 31,108, 54,
+ 57,185,170,102,161,188,215,148, 9, 46,210, 42,138,140,234, 81, 54,157,182,214,243, 78, 53, 39,113, 42,232,234,133, 62,203,140,
+ 81,226,186,164,251,205, 65, 68, 45,141,111,127,178,155,217, 11, 7,117,232,244, 30, 38,184,174,161,203,107,103,231,248, 21,109,
+173,218, 73,190,241, 78,168,239, 51, 13,168,169,155,182,242,228, 90, 36, 81,246,136,186,131,238,144,210, 90,151,113,134,203,171,
+ 91, 20,149, 36,203,150,181, 2, 36, 72,241, 41,180,202,125, 62, 5, 42,149, 74,131, 14,149, 68,162, 82,162, 70,166,209,168,180,
+168,109, 37,152, 52,202, 93, 50, 19, 72, 98,155, 79, 98, 58, 66, 90, 97,150,208,219,105, 24, 66, 83,166, 25,243, 9, 42, 36, 48,
+211, 63, 42, 59,216,200, 44, 75, 90,215, 17,131,112, 7, 91,187, 2, 54,178,171, 92,178, 89,124, 43,192, 18,102, 49, 69,153,103,
+ 74,240,208,200, 3, 69, 2,157, 18, 76,166,196, 60,141,179, 69, 19, 15,178, 22,210, 56, 58,131, 70,186, 89,244,203,132,143,102,
+ 23, 8,220, 37,199,165,207,176,182,222, 37,237,184,240,218, 71,188,239, 38,234, 68,167,221, 55,203,178, 8, 5,199,104, 48,157,
+143,245,101,141, 16,184, 57,155,143, 75,138,210,217, 36,230, 83,228,243,158,151, 69,160,187, 49,126, 36,133, 58,235,129, 35, 46,
+ 60, 86,226,143, 94,131,153, 68,246, 24, 3,200,118,213,202,135, 74,248, 27, 28,132,168,164, 41, 71, 3, 60,167,178,137,239,204,
+123, 15, 64, 52,232,211,232,248, 74, 64, 64, 35, 29, 71,146, 73,235,146,113,212, 96,254,205,107, 90, 40, 75,114,198,159, 86, 38,
+236,109,251, 76, 73, 38,219,253,162,109,208, 91, 22,226, 81, 83,208,192,148,180,116,233, 71, 78,189, 18, 53, 84, 94,219,144,182,
+187, 30,236,110,205,212,155,226, 36,191, 73,131,133,184, 14,237,254,198,241,107, 70,166, 37,170,205, 10,172,246,199,238, 12,230,
+ 90, 72, 51,232,213, 6,101, 92, 59,127, 50,122,210, 50,227,241,167, 51, 87,134,218,213,158, 86,166, 6,193, 0, 1,168,116,169,
+ 41, 33, 39,204,245,237,215, 39,203,251,117,250, 82,251,111,182,226,159,122,123, 47,248,158, 68,212,183,205,103,209,237,109,192,
+166, 56,164,149,248, 53, 59, 98,234,166, 45,165,183,223,145, 74, 98,100,132,103,253, 85,145,219, 95,154,217, 61, 0, 4, 2, 74,
+134, 8, 61, 7, 49,198, 52,227,147, 73,255, 0,165, 66, 15,216,112,195,220, 36, 0,159,222,225,201,223,169,197, 33,199,180,137,
+ 77,196, 45, 34, 0, 5,116, 17, 74, 69,250,190,167,136,155,109, 98,194, 32,222,246, 36,247,192,206,116, 56, 35,174, 1,207,238,
+253,186, 25, 65, 61,243,212,246,243, 7, 26, 53,192, 0,199, 55, 83,220,158,189,254, 95,142,132, 88, 87, 83,128, 65,237,142,152,
+192,193, 56,199,174,159,241, 15,192, 46, 18, 50, 66,124,241,246,227,185,249,232, 98, 58,147,216,252,251, 39,236, 30, 90, 53,207,
+ 47,191, 65, 58, 65,207,175,110,189,250, 16, 14, 52,178,244, 30,252, 20,218,254,159,207,182, 5,112,227, 39,190, 51,142,131, 31,
+120,199, 78,154, 17, 68,242,243, 31,159, 40,251,126,126,154, 37, 72, 61,249,137,198,122,121,118,238,122,245,213, 5,161, 68,100,
+ 16,191, 34,124,135,231,247,232,227,183,207,254, 48,111,134, 5, 42, 36, 16, 71,124,114,231,182, 61,126,122, 29, 68,103, 25,234,
+ 1,232, 6, 0,235,229,162, 84,147,145,215,246,116, 0,106,130,240, 62,121,237,229,142,217,251,124,180,162,141,133,183, 31, 63,
+ 61,177,144, 1, 62,151,192,138, 73, 25,229, 57,201, 57,255, 0,103,240,208,221,251,232,197, 2, 50, 70, 0,235,156, 30,227, 61,
+ 50, 61,116, 50,192, 29,129,245, 39,203,236,252,116,170,117,249,219, 10, 40, 4,116,183,200,197,185,230,249,199, 41, 42,198, 70,
+ 82, 58,103, 25,238, 71,150,116, 51,141,184, 1,235,202, 2,112,144, 0, 36,143,159,167,158,174, 42, 0, 30,132,158,249,207,174,
+132,121,178,164,158, 85,169, 7, 39, 24,254,119,219,234, 51,165,176,110,158,235,226,222, 82,148,255, 0,148, 36,147,212, 99,211,
+208,244,239,165,175, 69,181,182, 0, 82,148,225, 61, 73,192,233,242,239,165,161, 99,233,140,227,210, 7, 92,249, 15,233,252,157,
+ 20,130, 49,129,223,185,251,245, 65, 32,224, 12,117,234, 63, 19,255, 0, 13, 86, 64,238,124,199, 76,122,104, 96, 96,148,167, 3,
+175, 66,127, 28,126,227,253, 90,168,210, 0,200, 56, 61,207, 79,158, 58,231,243,223, 84,210, 73,233,142,131,166,126,239,219,162,
+ 91, 73, 57,233,223,215,207,166,147,112, 55, 61,255, 0,241,129,143, 96,121,224,159,199,161,251,180, 91, 63, 23,113,203,215, 25,
+238,123, 13, 83,109, 35,160,235,215,175,223,141, 18,148,131,208,116,233,158,223,102,147,193, 77,141,238,118,193, 72, 79,216,122,
+118,249,250,227,203,207, 85,146, 1, 56, 61, 61, 49,251, 7,109, 14,216,230,198,125, 50,122, 99, 68,160, 2, 64,198,125, 63,225,
+164, 90,192,144, 62,122, 97, 28, 86, 29, 14, 58,140,121,159, 62,158,186,218,174, 11,120,121,159,197, 23, 18,123, 87,179,145,130,
+147, 79,185,110, 40,206,220,178, 66, 73, 76, 27, 74,150,164,207,184,229,172,143,213, 6,158,202,219, 7,253,105, 35, 90,172, 1,
+206,113,144, 59,143,159,245,234, 71,254,193,173,178, 98,146,141,245,226, 34,165, 22, 63,188, 82,169,144,118,234,211,150,250, 66,
+158, 98, 93, 83, 19,235,142, 70,200,253, 26,253,223,221, 91, 42, 24, 61,198,152, 56,151, 50, 57, 86, 77, 91, 84,173,166, 80,186,
+ 80,142,161,155,107,143,122,130, 91,254,220, 76, 56, 7,134, 79, 24,113,142, 65,195,218, 75, 67, 95, 58,243,173,255, 0, 2, 48,
+101,152, 92,116,213, 26, 20, 7,179, 48,196,149,103,214, 45,203,102,139, 77,179,109,136,172, 83,237,139, 54,149, 2,215,182,224,
+ 65, 9,106, 37, 62,145, 72,142,136, 76,165, 49,147,211, 5, 45,100,145,212,231, 39, 86,118,235, 42,143,200,227, 47, 37,210,234,
+ 18, 24, 83,124,167, 5,120, 37, 7, 39,169, 39, 31,142,154, 22,235,241,228,173,213, 7, 98,188,149,229,164,178,233,228, 89, 82,
+186, 30,101,122, 21,107, 39,167, 33,181,182,204, 85, 70,113,109, 7, 2,195,161,204,169,167, 50, 20, 18,130, 15,196, 61, 53,201,
+ 85,114,187,206,236,205,119,148,147,111,221,239,252,122, 91,240,246,231,132, 50, 26, 12,191, 43,166,165,142, 30, 84, 80,168, 93,
+ 32, 13, 58, 85, 84,105,177,176, 1,109,176, 91, 3,211, 99,135,136,196,145, 38, 52,105,210, 76,121, 79,186, 10, 76,117,169, 45,
+200, 65, 31,170,160, 65,233,140,104,132,199, 66,144,161, 62, 50,221,107,148,150,150,164,248,168,109, 67, 33, 74, 86, 6, 71,200,
+131,160, 41,209,224, 56, 99,202,116, 72, 15, 50,217, 66,222,125, 75, 64,192, 24, 0,163,205, 35,215,229,172,162, 35,108, 56,218,
+125,222,104, 97,121,193, 42, 81,113, 50, 18,162, 73, 1,181,118, 3, 58, 69,199,148,148, 66,227,107,244,216,237,190,219,127, 28,
+ 18,170, 83, 9, 43,230,178, 30,161, 74, 4,185, 54, 11,164,181,128, 27, 95, 77,200, 59,139, 97, 81,169,202,247,134,228, 67, 90,
+ 39, 71, 36, 55, 34, 19,199, 15, 6,193, 24, 91, 89,234,160, 7,109, 86,220,221,191, 69, 90, 85,181,115, 68, 96, 46, 68, 6,140,
+ 7,138,147,149,150, 82,160,166,208,188,140,168, 39, 39, 25,242,233,167, 58,137, 71,166,201,142,194,201,142,212,216,196, 6,229,
+ 50,121, 11,153, 61, 65, 3,161,199,207, 78,207,240,125,201,244,162,195,141,165,106, 65, 67,236,188,216,248, 92, 90, 48, 74, 84,
+ 7, 98, 83,144,126,221,106,152,228,100,145, 44, 64,101, 22,223,184,183, 79,141,173,235, 98,111,138,187,136,120,137, 99,171,130,
+101, 58, 30, 38,100,109, 86, 82,202,195, 78,228, 88, 56, 32,141,236,172, 58, 16,109,124, 91,182, 90,193,101,183,152, 82, 35,165,
+ 30,248,200,113, 65, 41, 9, 79,140, 82, 57,198, 49,211,152,245,251, 78,155,223,104, 77, 33,251, 91,135,122,140,200,202, 44, 42,
+ 69,199, 77,109, 75, 9, 39,197,247,120, 85, 7, 27,105,208, 6, 86,128,176,147,145,219,151, 56, 58,220,141,174,167, 53, 29,232,
+216, 70, 58, 14,152,232,133,143,214, 72, 31,205, 26, 97,253,170,148,143, 23,133, 86,229, 70, 46,101,187,202, 15, 56,105, 57, 89,
+ 75,148,154,162, 84, 79, 78,191,171,143, 92,159, 93, 75, 50, 90,104,205, 42,203,166,242, 70,111,241,189,135,243,239,235,142,124,
+204,184,154,105,248,255, 0, 33,161,119,211, 75, 85, 83, 4,100,118,176,147, 86,254,237,133,254, 24,136, 5, 65,227, 38, 82,145,
+202,226, 39, 41,110,184,151,185,156,241, 27, 46, 17,149,180,210, 23,200,250, 75,169,109, 32, 45, 42, 64,235,207,202,174,244,225,
+ 84,213, 6, 69, 67,223,225,189, 84,158,167,131,113,207,129, 29,150,216,138, 80,148,182,153,212,240,151, 19, 0,248,133,126,240,
+180,243,120,152, 79,110,128, 7, 61,166, 95, 74, 93, 83,147, 93,247,105, 92,175, 73,101,190, 69, 71,105, 74,202,153, 10,108,130,
+212,142,100,163, 40, 88,230, 36,130,160, 83,202, 52, 77, 26, 68,232,229, 30, 27, 79,123,184, 37, 79,205,166,196,101, 85,116,182,
+ 73, 71, 35,108, 72, 90, 68,166,220, 46, 4, 56,180, 23, 84,209, 5, 97, 7, 3,149,225,214,234,123,129,216,253,221,239,113,176,
+ 23, 3,174,219, 95,167,161,116,245, 3,200,177,221,159,162,132,176, 97,182,229, 73, 27,128, 53, 11,223,179, 1,176, 39, 14, 61,
+179,110, 49, 87, 92,138,164, 73,146,233,178,165,150, 16,227, 84, 69, 42, 50, 94,109, 10, 71, 71, 96,168, 22, 37,159,133,105, 75,
+193, 9, 83,132,168, 41, 95, 14,158, 74, 45, 26,235,147, 34, 76,184,244,134,171, 40,104,204, 83,146, 41,175, 68,162, 76,140, 26,
+117, 76,161, 51,233,207, 31, 0,115,161,149,165, 62, 10,135, 57, 87,234, 12,157, 54,148,138,123, 5, 81,133,159, 38,108, 39, 22,
+195,242,231, 68, 66,152,157, 2, 68,128,208, 83,174, 57, 5,247, 3,144, 18,140,142,105, 41, 91,107, 89, 89, 79,134, 84,158,109,
+108,157,156,170,253, 2, 24,110, 77, 1, 74, 65,106, 28,151,106, 52, 57, 77,206,132,236,118,255, 0, 72,150,159,167,169, 41,148,
+219,202,116, 37,124,170,241, 18,165, 16, 50, 10,136,212,110,190, 89, 0,102, 91, 57, 54, 10,173, 96,125, 45,246,150,247,176,217,
+ 88,139,245,185,184,195,137,205,164,100, 34,153, 99,169,146, 43, 14, 92,202, 82, 66,118,230,106, 62, 73, 25, 71, 75,134,111, 41,
+ 23, 70, 4, 1,238,148,138, 91, 79,179, 2,163, 42,161,107, 43,221,217,145, 13, 23, 52, 5,211, 28, 76,196,148,190, 35,243,188,
+223,129, 37,188,163,195,105,198, 94, 1,193,212, 37, 68,105,199,141,108,212,103, 60,153,146,233, 80,100,164, 73,113, 42,158,134,
+163,128, 66,210,128,223, 59,193,178, 90, 87, 40, 29, 82, 74,185, 79, 84,231,174,179,235, 33,170, 93, 82, 77, 65,154,147, 17, 46,
+ 76,178,176, 41, 85, 40,140, 45,104,144,248, 64, 74, 13, 62,115,105,115, 41,101, 46,164,185,225,171,144, 31,132,142,153,120,104,
+155, 91,103, 58,196,127,118,165, 59,108,201,150,211, 50,140,139, 86,167, 83,165,188,209, 10, 66, 17, 17,112, 22,243,140, 60, 16,
+ 72, 81,231, 97,105,115,147,153, 93,245, 22,146,172,134,180,138,209, 72, 58,244, 55,189,174, 71,217, 35,212,143, 54,251,139, 30,
+173,181,252,117, 14, 86,239, 28,240, 77, 72,225, 81,117, 42, 44,182, 50, 45,220,171, 22,130, 84,251, 42, 72, 28,237, 90, 65, 85,
+ 58, 66,227, 1,178,236,216, 17,129,148,194,170,116,121,146, 79,188, 38, 93, 38, 95,133, 10, 82,217, 78, 91, 18, 24,229,114, 60,
+196,167,194, 87,134, 28,105, 10,115,149, 65, 71, 7, 26,218,107,126,109, 90, 10,162,154,132,152, 21, 33, 32, 55,133, 48,201,165,
+212, 26, 80, 33, 63, 20,102,159,113,167,222, 82, 65, 82,130, 11,105, 73, 39,225,199, 46,172,180, 45,177,175,198,113,230,233,151,
+117, 62,124, 98,178,148,183, 92,183,144,196,137, 9, 81,248,202,103, 82, 28, 65,109, 73,194,146, 20, 24,229, 74,149,158, 83,170,
+151,157, 90, 22,218, 91,117,139,187,113, 17, 73,181,172,155, 85,134,101,215,110,181,213, 99,253, 77, 72, 98, 68,134,161, 70, 15,
+171,149, 18, 12,199,165, 63, 30, 59, 44, 48,211,146,228, 58,240, 75, 8,112,149, 16,164, 80,243, 60,247, 50, 62,199,125,199,193,
+ 73, 23,219, 99,125,143, 82, 0,239, 80,241, 39, 21, 71,196,149,209, 83, 82,212,174,107, 81, 80,226, 56,226, 80,230,162, 70,147,
+234,226,138, 33, 50, 71, 80,238,238, 21, 99,138, 13,122,152,170,128,194,195, 15, 28,122,147,162, 40,105,244, 58,132, 37,223, 18,
+ 3,231,194,234,242, 86, 28,114, 59,165, 43, 30, 26,249,214,164,228,128,219,188,202,202,185,192,213,242, 37, 81,151, 30,143, 37,
+197, 57,226, 48, 3, 43, 43, 9, 11, 44,184,174,102,157, 83, 95,206, 90, 22, 66, 70, 64,200, 86,124,137, 13, 21,189,112, 82, 46,
+ 11,114,151,114, 91,117,216,119, 21,175,113, 83, 33, 86,232,117,120,238,174, 76,106,173, 26, 82, 67,145,101, 66,125,192, 11,141,
+ 45, 4,130,146,128,164, 41, 37,183, 57, 92, 66,210, 3,147,114,251,147,205, 46, 54, 83,202,178, 2, 20,226, 80,132,161, 96,169,
+ 73, 10, 36,120,173,129,204,140,147,204, 20, 64,198, 59,150,162, 37,117, 42, 5,134,194,253,108, 65,216,110,125, 71, 75, 11,250,
+ 92,139, 85, 45, 11, 75, 83, 85, 72,209,180, 51,196,206,140,172, 25, 25, 24, 29, 14,146, 35, 0,209,184, 32,134, 82, 46, 24, 18,
+ 55, 26, 78,240, 90,213, 31,208,130, 86, 9, 4, 18,130, 72, 73,229, 80, 42,230,108,126,177,199, 46,112, 65, 25,207, 93, 58,209,
+ 39,130, 16,145,159,214, 81, 60,157, 65,194, 72, 0,114,156,158,128, 96, 14,165, 71, 30,128,234, 46,217,220,212,153,116,202,237,
+193,112,215,105,214,197,177,108, 64,126,171, 91,175,213, 37,166, 53, 46,151, 79,136, 18,100, 76,145, 41, 67,244, 76, 39, 45,163,
+148, 5, 41,199, 22,134,154, 11, 82,210,147,121,177, 56,210,225,140,221, 20,202, 80,185, 43,180,231, 43, 85, 4,209,236,251,142,
+240,181,165,219, 54,109,110,224,123,244, 52,198,233,213,121,111, 56,150,164,191, 39, 34, 8,154,220, 70,223,145,203,133,133,114,
+ 37, 82, 44,159, 40,174,158,140, 87,178, 8,168, 83,237, 72, 72, 38,202, 69,200, 91,220,219, 97,125,133,250,145,136, 77,103, 11,
+113, 14, 98,249,179,100,188, 59, 93,159, 12,160, 94,161,169,105,165,154, 56,137, 78, 96, 87,150, 53,100, 83,203, 28,198, 91,150,
+ 88,129,148,174,133, 36,110,229,114, 79,128,205, 58,148,133, 31, 26, 20,100, 59, 45, 60,196,132,212, 39, 20,202,122, 50, 84, 70,
+ 84, 27, 10,142,218,188,129,109, 73,206, 70, 5,137,201, 14, 46, 63, 35,110,172, 30, 98,236,137, 60,136, 43, 66,208, 65, 73, 5,
+196,225,111,114,171,166, 73,229, 9, 25,193, 3, 88, 95,215,200,158,183, 30, 67,206, 41, 43,116,248,202,117,107,231, 82,249,143,
+ 62, 86,165,101, 75, 43, 42,230, 4, 2, 9, 87, 55,198, 14,178, 38, 92, 98, 67, 32, 20,251,201, 8, 88,240, 16,146,164, 41, 67,
+178,192, 65,194,147,145,216,231, 10,198,125,116,226,139,237, 51,153,109,101,216, 45,137,176, 85, 0, 40, 38,219,249, 64,243, 91,
+246,186, 2, 70, 32,113, 80,251, 44, 81, 44,131, 83,130, 89,141,129,187, 49,212,196,131,181,139, 18, 64, 38,192, 90,228,140, 52,
+ 23, 71, 18,155, 27,182,247,133, 23,109,175,221,230,219,141,180,184,238, 72,209,228,209,169,247,213,194,220, 10,181, 86, 20,201,
+ 78, 65,135, 62, 60,103,163,251,172, 38, 37, 75,102, 75, 81,164,214, 36, 66,142,250,153, 91,141,169,214,146, 84,119, 30,147, 66,
+165, 80,195,147, 41,232, 38,166,235,108, 25,149,121, 74, 76,250,173, 65, 50, 26, 67,141,184, 37,252, 94, 36, 34,194,208,182,218,
+140, 81, 20,180, 82, 89, 10,109, 73, 89,131, 15,180, 99,113, 31,190,120,217,226,105,247, 21, 37, 48,237,189,193,122,201,132,220,
+231, 27, 90,216,183,172, 58, 52, 11, 98, 37, 40,182,149, 41, 9,140,210,225,202, 12,167,155,149,105,150,162,177,158,154,222,143,
+101, 55,180,158,109,129,120, 91, 92, 38,241, 1,118, 84,165,108,197,201, 83,133, 67,218, 59,194,177, 84,117, 3,105,238, 58,130,
+145, 22,145,102,215, 42, 78,168,190, 54,130,167, 53,198, 99,180,128,239,129, 65,155, 33,153, 40, 74, 41,207, 76, 66, 18,163,204,
+ 18,106,169,105,103,136, 44,113,146,169, 37,205,135,152, 11, 55, 64, 21,137,251, 98,218, 65, 1,129, 26,156,119,103,137,223, 65,
+ 12,230,155,192,222, 23,241, 67,129,120,142,163, 57,207,166,202,105,115, 92,243, 34,120, 80,201, 36, 83,210, 71, 89, 57,203, 94,
+ 45, 47, 81, 37, 18,146,173, 69, 62,179, 89,161,231,164,145, 39, 16,209, 79, 40,202,229,206,203, 50, 92,167,210,208,107, 18,249,
+ 17,239,226, 44,119,234, 17,224,182,163,206,183, 36, 8,104, 87,141, 37, 68, 5, 37,149,169, 33,190,156,196,116, 73, 21, 52,233,
+ 79,123,195,137,167, 34,158,186,130, 89,101,234,213, 77, 81,234, 87, 35, 64,168, 41,152,136,167, 35, 45,198,233,144,132,186,180,
+161,158,159,161, 42, 57,214,118,211,109, 82,144, 99,162, 60,122,107, 81,146,184,210, 98, 6,209, 25, 12,173,165,168, 41,185, 13,
+180,145,149,165,224,224, 89, 57, 61,193, 61, 53,141, 63,114, 33,233, 11, 85, 22, 2,170, 6, 42, 84,212,185, 46,120, 80,168,201,
+117, 77,148,182, 88,156,160,181, 73,125, 4,163, 41,105, 11, 32, 40,146,226, 20, 64,212,177, 40,249,104,218,136, 93, 29, 1,247,
+238, 71,235, 92,237,232, 58, 18, 54,181,252,231,165,168, 98,130, 44,186,134,201, 24, 5,166,121, 54, 99,112, 87, 94,233, 10,130,
+202,186, 81,249,136, 78,144,193,201, 44, 84,122, 5, 38, 28, 86,234,113,156,144,169,205,161,212, 57, 82,170,201, 76,201, 45, 60,
+163,153,137,113,197,182,159,113,143,202,130, 20,219, 0, 33, 33, 33, 36,173, 0,232, 37,215, 92,148,250,153,181,195,113, 24,204,
+ 83,252, 40,144,178,220,218,116,212, 96,205, 77,188,203,169,196,146,181,168, 6,221,112, 41,150,139,220,205,165, 69, 32,139, 44,
+136,107,113,106,122,179, 49,215,100, 48,241,113, 20,248,234,113,186,107, 6, 70, 20,166,155,136, 28,230,125, 10, 89, 0,151, 66,
+148,164,164,149, 30,184, 24,253,199,122, 66,165, 47,234,152,208, 81, 88,170, 60,133,169,134,151, 37, 17, 89,142,182,144,160,195,
+138,116, 16,184,175,115,146, 26,228, 35,152, 2,144, 10, 70,182, 97, 64, 14,163,229,113,223,173,246,245,220,141,236, 46,119,233,
+208,144,112,239, 75,150, 79, 93, 50,162,150,205,103,109, 68,106,254,230, 52,186,181,201,144,170,200,168, 55, 28,194,177, 0, 89,
+ 74, 58, 49,195,130,197, 46,151, 71,143, 89,156,136, 50, 16,226,147,239, 45,220,146,230, 75, 91,181, 22,228,134, 85, 46, 53, 65,
+ 42,116,169,215, 27, 81,116, 21,143,136, 56,176, 83,223, 69,209,101,194,118,104,120,212,188,105, 41,116,182,242, 25, 83,206,149,
+ 54,218,214,160,181,186,242,194,131,168,108,182, 83,205,250,200,108, 3,147,240,233,134,126, 83,142,181, 21,235,160,213, 20,137,
+105,109,136,245, 1, 33,149, 69,131, 86, 73, 74,228,162, 18,225, 47,194, 98, 66,176,143,133,208, 29, 73, 36,133, 44,128, 52,237,
+ 91, 17,157, 91,145, 84,244,169,143,180,227, 68, 21, 75,109,133,243, 33,111,129, 20, 74,114, 56,241, 39,182, 84,174, 82, 70, 20,
+165,173, 69, 57,239,167,120,101, 42,241,198, 6,146, 55,181,138,219,126,164, 14,187, 16, 5,245, 16, 5,201, 45,115,133, 51, 76,
+165,169, 40,229,154,170,189,170,102,150,227, 88, 37,145,130, 42,169, 88,221,140,154,183, 83,169, 71, 40, 43,236,138, 6,155,195,
+227,233,107,174,155, 39,136,190, 10, 30, 97,107,118,164, 56,127,220, 70,158,146,160, 16,217,132,155,246,143,200,210,154, 35,155,
+222, 4,191,120, 37, 71, 9, 82, 86, 10, 64,235,168,152,132,228, 28,164,164, 19,215,231,143, 77, 73,155,233, 79, 95,204, 87,248,
+240,217,189,185, 66,217,147, 47,105,120,111,164,154,148,182,157, 83,138,126, 70,226,221,245,186,220, 86,150,133,146, 80,148, 83,
+104,144,212,158,249, 18,186,147,129,168,234,237,246,223,222, 27,165,119,219,150, 21,133,110, 86,174,219,186,237,172, 68,160, 91,
+118,213,189, 79,122,169, 91,174, 86, 39, 44, 34, 53, 58,153, 1,128, 75,239, 43,226, 82,212, 74, 91,101,180, 45,231,150,219, 72,
+ 90,211, 98,229, 79,202,203,150, 89, 92, 34,171, 76, 88,147,176, 28,199, 55,185,216, 11,111,185,252, 49,198, 60, 76,139,250,126,
+189, 32, 28,197,102,132, 46,145,114,196,195, 16, 0, 0, 1, 44, 73,181,128, 4,182,214, 7,108, 96,193, 42, 89, 72, 66,114, 71,
+100,165, 36,149, 99,176, 0,119, 58,237,167,177,211,217,215, 3,138,221,197,169,239, 54,241,210, 85, 43,135, 45,155,171,194, 77,
+122,148,248, 83,108,110,166,227, 37, 13, 84,169, 27, 94,149,140, 21,219,145, 99, 42, 44,251,145, 77,156,169,135,162, 82,185,144,
+185,207, 4,246, 39,129,175,163,187,181, 22, 69, 46,141,184, 92,116,214,164,223, 87,121,101,186,140,141,132,177,171,110,211,108,
+ 90, 17, 41, 14, 34,153,125,223, 20,181,162,117,229, 60, 3,201, 42, 45, 53,216, 84,224,161,200,151,229, 4,149, 43,177, 76, 91,
+ 27,113,181,244, 24,150, 14,210, 88, 54,166,216,237,189,188,185, 31, 81,216,214, 37, 26, 21, 6,221,166, 25,110,243, 75,144,204,
+ 24,141,132,174,107,238,225,201, 18, 29, 43,126, 67,129, 42,121,215, 23,130, 27,243, 44,205,164,167, 43, 26, 24,161, 39,118, 99,
+165,220,118, 10,191,105, 84,157,152,182,150,181,202,117, 86, 19,158, 18,240,238,182,106,218, 90,236,242, 5,138,150, 59, 56,166,
+ 62,103,145,133,180, 9, 71,217, 84,185, 12,200, 75, 22,182,135, 80, 11, 12,100, 74,154,169,242,176,132, 54,203,109, 54,195, 44,
+ 71,140,203, 81,226, 70,137, 29,164,179, 10, 4, 72,236,165, 45,195,134,212,102, 91, 75,109,182,148,182,219, 76,161, 8, 74, 80,
+ 18,144,232, 90,112, 2,249, 93,117, 25, 66,146,209, 71, 66, 22,162,163,134,241,211,245,150,177,159,152, 58,106,104,113, 92, 82,
+188, 39, 22, 57,159,117,107,144,172,114,134,208,144, 20,235, 77,249,242, 37, 62, 27, 96,249,156,159,144,217, 59, 62,158, 23, 33,
+162,160,146, 26, 67, 60,168,236,129, 33,209,134,130,134, 48, 2, 26, 35, 31, 51,211, 77,180, 46,116, 52,199,224, 54,176, 30,128,
+ 14,214, 29,134,219,219, 98, 14, 47,113, 78, 21, 72, 3, 87,123,254,238,135,222,126,240, 59, 91, 14,157, 22,158, 26,105,164,172,
+ 5,168, 4,243,159,213,231,121,125,145,208, 99, 30, 93, 60,129,211,139, 26, 35,109, 54, 49,133, 17,220, 16, 79, 83,232, 60,250,
+246, 31,187, 86,138,100, 68,165, 73, 8,229, 81,142, 64, 42, 86,112,183, 22,144, 21,130, 15, 85, 36, 19,242, 28,218,203,218, 78,
+ 49,240,169, 41, 70, 66, 74,122,165, 68,142,170,207,160, 57, 72,251,254, 88,216, 14, 90,230,251, 15,244,249,254,125, 48,211, 87,
+166, 54,210, 5,205,133,251,123,192,239,235,247, 3,211, 99,142, 83,123,105,234,144, 40, 62,204, 78, 45,213, 56,172, 10,158,223,
+193,161, 68,109,166,214,234,222,168,213,110,106, 44,120, 49,210,219,105,230, 42, 83,161,103,253,144,131,228, 53,249,148, 74,163,
+ 86, 33,178, 31,157, 73,168, 68, 97, 73, 37, 15, 75,136,244,102,150,130,114, 10, 29,117,176,149,119,242, 39, 7,166,117,250,228,
+239, 21, 54,139,113, 81,162, 91, 21,234, 77, 58,187, 2,167, 53,185, 83, 41, 53,168, 81, 42,144, 36, 71,167, 16,227,102, 68, 9,
+141, 45,167,146, 37,173,178,146,164,171, 5, 25,232, 70,154, 39,182,131,105, 43,148,145, 68,173,237, 86,217, 86,168,230, 58,226,
+138, 93, 86,195,181,102,211,147, 24,131,204,194, 99,191, 75, 41,109,188, 19,219,175, 94,132, 30,186,205, 29,108,244,181, 21, 13,
+ 12,113,200,178,104, 7, 83, 48, 55, 91,237,178,176,177,213,114,119, 55,218,198,215,196, 43,137,120, 6,163,136,230,167,205,151,
+ 49, 90, 53, 72, 22, 32,134, 2,250,180,203, 43,106, 45,205, 75, 41, 46, 64,178,159,179,125,239,183,228,250,227,101, 60,188,224,
+140,142,128,244,207,144,199,168,198, 48,126,122, 21,192, 0, 3,155, 35, 57,233,215,215,166,191, 65, 78, 47,125,129,220, 19,241,
+ 21, 2,167, 90,218,170, 35,252, 48,110, 99,233,144,252, 74,205,131, 29,202,134,222,212,103,172, 18,132, 92, 59,119, 53,242,134,
+ 99, 45,220,115, 59, 76,122, 43,169, 25, 41,109, 88,229, 48,230,227,131,217,183,196,255, 0, 1,119, 35,112,119,146,205, 19,108,
+ 74,180,247, 33,217,251,193,104,151,171, 59,105,118,144,165,248, 44, 49, 88, 13, 5,219,245,162,132,229, 84,234,138, 35,202, 73,
+200,108, 58,145,204,100,244,217,164, 82,178,199, 50, 26,105, 9, 0, 92,221, 24,250, 43,250,158,193,130,177,236,164, 11,226,164,
+206,184, 91, 56,200, 65,146,174, 1, 45, 32,219,159, 17, 47, 24,222,195, 93,194,188,123,216, 93,212, 33, 36, 42,187, 28,115,229,
+210,158,163,169, 24, 62, 96,119,253,255, 0,215,160,212, 66,187,167, 24,232, 58,249,116,198, 49,219,174,141,117, 3,152,133,229,
+ 39, 56, 41,199, 80,122,227, 65,120, 97,165,169, 73,201, 43,238, 14, 79, 41,235,146, 61, 52,244, 14,192, 1,182, 35,160, 31, 92,
+ 14,231, 32, 73, 74,186,231,203, 24,251,137,244,208,101, 3,148, 32, 40,165, 57,236, 60,201,209,133, 63, 26,186,168,231,201, 71,
+225, 29,187,121, 13, 81, 86, 50,122, 16,115,246, 12,124,177,163,142,222,236,103, 3, 40, 3,211, 29,186, 30,189,241,215, 57,208,
+203, 24, 36, 15, 67,140,252,199,207,203, 69, 47,208,103,166,115,229,147,129,215, 62,186, 25, 64,244,230, 29,124,143,175,113,215,
+212,233, 85,189,129,245,235,243,240,198, 69,172,126,125, 48, 42,129,193, 30,127,147,161, 85,246,156, 17,215,204, 2, 8,199,217,
+162,148, 58,146, 20,122,103,207,167,159, 83,161, 92, 42,235,233,230, 71,159, 95,232,210,139,215,173,176,170,143, 95,157,176, 50,
+206, 15, 76, 31, 80, 71,224,126,220,104, 85,168,227, 28,189,125, 61,126,206,154, 37,100,103, 3,200,156,244,243,249,232,117,227,
+ 57,235,233,242,251,180,182, 50,126, 54, 56, 25, 99,175,159, 81,231,229,242,210,215,178,172,119,200,244,198, 14,127, 31, 61, 45,
+ 40, 47, 97,229,191,200,255, 0, 79,155,224,126, 56,162,144, 64, 30,191,143,158,170,163, 62,125,137,232,115,220,250,106,159,236,
+213, 69, 35,156,131,204, 71,166, 63, 63,156,233, 54,219,160,220, 99, 35,227,108, 20,131,208, 14,228,121, 99,231,251,116, 80, 56,
+ 35,184,249,250,104, 22, 57,146, 8, 81,234, 59, 31, 80, 60,243,247,232,209,216,117,207,207, 68,223, 77,200,244,254, 88, 24, 45,
+ 24,207, 92,231,203, 69, 35,207,183,239,208,173,124,207, 92,126,127,118,138, 64,232, 79,221,249,252,249,105, 44, 16,142,190,251,
+ 15,145,130, 80, 58,103,215,250,244, 66, 49,140,129,215,212,247,207,245,106,146, 48, 57, 79,150, 7,252,116, 64,193,232, 49,223,
+ 31, 97,210, 44, 79, 91,236,127,211,253, 48,153,183, 97,138,128, 40, 5,103,208,224,119,235,169,123,123, 41,104,112,173, 78, 2,
+173,121, 73,134,167,220,191,111,139,158,183, 80,116, 97, 14, 1, 26, 65,131, 29, 41,199,146, 91,142, 0, 58,136,106, 65,193, 4,
+140,224,156,227,211,175, 77, 75,111,217,163,113,199,172,240, 9,183,233,105,231,146,187, 86,241,187, 45,249,133,131,143, 9,213,
+ 78,114, 75, 97,196,121, 2,219,168, 32,158,224,244,213,121,226, 65,147,244, 28, 33, 13,148,206,186,191,254, 57, 45,142,131,250,
+ 49, 71, 12,158, 42,209,137,118,101,162,169, 41,214,225,249,148,226,226,196, 27,233, 45,211,181,251, 99,118,128, 83,114,214,210,
+153,146,220,116,144,235,125, 10,212,129,205,144, 20,161,156,249,105,224,180,100,161, 50, 35, 25,130, 74, 80, 57, 85,206, 20,176,
+ 26,230,198, 22,164, 30,253,198,153, 40,181, 49,238,232, 92,122,195, 47, 73, 82,210,211, 81,100, 39,149,110,184,178, 82,218, 1,
+ 61,252,180,248,219,242,107, 80,222,162, 71,155, 77, 98,169, 61,192,124,102, 35, 56,130, 91,108,254,170, 94, 72,254,110, 58,245,
+215, 54,213, 70,193,217,152,217,148,130,111,182,219,117,233,112,127, 28,123, 9,151,215,172, 84,113,194,236,164,181,215,237,232,
+114,116,222,246,144, 11,142,228,222,194,248,216, 58, 84,210,135, 89,145,227, 49, 81,108,184, 26, 12,189,132,132,180,123, 21,146,
+ 58,249,103, 78, 29, 49,216,145,157, 46,202,141, 0, 50,165, 99,153,162,151, 0, 10,255, 0, 80, 14,216,207, 93, 55, 22,253, 58,
+116,249, 14,180,186, 68,194,162,227,110, 41, 40,100, 22,154, 72,236,208, 41,238, 63,167, 78,237, 50,222,105,197, 50,210,160,203,
+ 5, 43,248,209,238,139, 82, 16,172,254,170, 84, 6, 15, 64,123,246,209, 97,137,100, 58,121,100, 21, 38,219,129,125,253,251,159,
+203,124, 66, 51,202,138, 53, 13,169,202,221,119, 10,203,112,189, 71,216, 96, 1, 27,139,233,177,239,124, 60, 54,123, 86,252,196,
+161, 45,162, 50,155,229, 7,170, 74, 10,129,238, 6, 71,112,116,252,211,104,240,209, 29, 41,140,174, 68, 20,228, 53,207,204,217,
+ 24,234, 19,232,174,250,105,109, 74, 83,112,209, 24, 57, 24, 70, 14, 44, 8,200,152, 24,136,167,206,112,124, 36,200, 90, 75,189,
+ 71,243,115,233,167,174,148,195,204, 73,247,101,182,182, 20,172, 18,219,237, 41, 33, 67,200,161, 67,203,168,237,167,136,114,230,
+101,187, 11,252, 13,192,191, 66,125,255, 0,150, 57,147,139,234,195, 84,202, 96,169,114,138, 75, 0,206, 26,224,108, 77,134,219,
+119, 54,216,237,113,131,109,233, 2,149, 48,165, 68,165, 30, 38, 65, 7,177,206, 58, 19,172, 11,142,250,104,187,248, 72,189,156,
+100,243,201,160,212,173,234,211, 33, 37, 75, 0, 55, 52,196,120,156,116, 8,228,153,212,158,131, 26,214,142, 52, 56,200,162,240,
+178,104,182,149, 18,205,170,110, 30,239, 93,144, 68,251,106,214,167,179, 37,200,145,162, 56,240,138,204,250,159,186, 52,167, 29,
+ 74,229, 97, 13,180,210, 74,150, 65,201, 72, 25,215, 24,110,255, 0,109,214,236, 89,181,169,123, 63,196,206,212,209,225,216,219,
+139, 33, 54,133,121,152,140,200,163, 86,236,207,172, 95, 67, 44,213, 92, 50, 29, 90, 28,247, 39,220,142,243,241,228,161, 37,109,
+ 48,160, 22,133, 16,160,237,150,210, 77, 74, 30, 57, 24, 4,148, 29, 42, 55,123,122,233, 0,155, 3,252,176,190, 77,224,151, 30,
+113,173, 21, 7, 27,228,116, 52,241,195,151,149,172,136, 84,213,193, 77, 53, 92, 16, 72,162, 73, 41,163,149,129,100, 44, 12,107,
+ 36,134, 56,222, 75, 34,185, 39, 28,240,171, 81, 92, 18,235, 15,189, 50, 83, 15,182,251,205,242,193, 1,135, 11,172,188,227,129,
+215, 90,116, 41, 15,167,152, 55,128,160,127, 87,190,113,171,197,186,251, 84,199, 27,110,231, 91, 11, 8,109,105,102,164,211,204,
+152, 75, 4,120,205, 50,166, 93, 67,142, 51, 33,194, 84,147,146,190, 85, 0, 82,178, 59,103,187,207, 96, 84,168,155,135, 92,164,
+148,251,168,139, 80,118, 74,101, 49,206,195,115, 26, 83,165,196,200, 97,164,164,165, 44,172,160, 41, 39, 56, 83,110, 36,144, 0,
+213, 45,183,165,251,180,225, 57,214, 41,211,231, 46, 59,134, 32,155, 57,137, 75, 47, 56,165, 48,251,207, 7, 20,216, 97,211,207,
+ 28, 22,210,121,212,147,204,148,242,228,105,122,137, 21, 98, 46,198,247, 22, 0, 1,112,118, 0, 3,218,222,150,216,220,157,247,
+199, 91,101, 89,173, 61, 78, 87, 77, 84, 36, 38, 42,136, 21,215, 65,180,182, 96, 28, 89,154,203,123,157,181, 30,246, 5,126,214,
+ 30, 11, 94,207,114,229,117,201,237, 69,164,202,120,197,143, 54, 85, 82,157, 37,183,147, 22, 59,235,108, 65,134,165, 70,194,224,
+ 61,226, 33, 45,144,231, 55, 47,196,226,209,149,116,219,107, 39,110,107,207,161,154, 43, 53, 69,192,105,220, 59, 45, 51,224, 51,
+ 86, 64,151,226,135,152,104,200, 64, 67,211, 90, 7, 24, 74, 94, 41,111, 9,230, 0,233,156,176,182,201, 77,169, 18,170,137,115,
+223, 42,193,152,112, 99, 91,243,158,143, 35,199, 74,144,226, 36, 74,147, 13,192,137,144, 80,224, 4,151, 2,137, 82,194, 64, 37,
+ 56, 27,217,102, 90,215,133, 41, 49, 27,133, 84, 98,165, 57,224,159,142,189, 5,146, 26,113, 35,153,236,152,138,109, 46,169, 69,
+ 25, 87,137,133,140,117, 36, 18, 53, 10,175,145,203, 5,138, 80,109,208, 48, 59, 17, 96, 8,190,160,123,246, 0,108, 20, 27, 91,
+ 12, 57,247, 17, 10,106,116,134,130,190,154, 78, 89, 80,156,196, 87, 1,193, 91, 30, 97, 18,163,152,205,238,197, 65, 6,218, 88,
+ 22,108, 90,237,237,189,152,234,185, 95,164, 89,245,210,228,149, 56,245, 82,107, 53, 74,100,246, 35, 52,164,165,243, 25, 77,135,
+115,204,242, 70,121, 29, 74,177,211,148, 96, 43, 79, 29,187, 98, 95,172, 58,106, 17,164, 80, 67, 45, 56, 12, 74,109, 70,100,217,
+240, 85, 24,171,153, 44, 69,113,113, 82,236, 53, 20, 4,149, 21, 41, 69, 5, 39, 41, 86, 6,179,123,118,157, 92,141, 29, 16,156,
+183,161,203,117,169, 45, 41, 85, 8,181, 70, 27,109, 47,173,212,248,236, 71,106, 84, 99,132,175, 36, 36,133,242,100,225, 68, 4,
+141, 58,241, 37,169, 36,181, 81,162,206,163,163,196, 75,109,173,245,177, 34, 3, 69, 39,152,189,239,177, 10,146,225, 89, 79,232,
+208,128, 73,194,129, 72, 61,117,169, 79, 70,103, 39,152, 2,179,118,234, 61,230,215,211,210,196,129, 98, 64, 29,141,241, 79,103,
+220,101,153, 30,114, 70,144, 85, 43, 2, 13,228, 73, 14,130, 64, 58, 33,230, 2,133,252,192,233,140, 21,185, 0,130, 72,108,110,
+143, 14,191, 8,188, 39,209, 80,234, 30, 65,115,252, 6,171, 17,212, 71, 73, 7,149, 40, 68,198,155,113,192, 74, 65, 61,137, 39,
+175,124,235,131,126,216,205,247,152,111,141,190,225,194,146,243,176,233,118,141, 10,155,186,215,228, 17, 33,165,138,133,245,119,
+ 54,244,107, 38, 20,208,210,212, 86,213, 50,201, 6, 83, 77, 44,254,130, 77,220,242,193, 10, 9, 34, 68, 98,167, 69,113,239,115,
+ 98,162,209,150,227,169,100,164, 50,250, 30,142,153, 10, 67,104, 47,161,113,185,149,250,217,193,234, 7,124,117, 58,132,167,180,
+ 11,114,157,191, 56,207,226,110,235, 91,220,193,123,191,119, 82,161,167, 35, 13,210,109, 57,205,218, 52,134, 80,174, 65,250, 54,
+233,246,252,102,210, 48, 48,150,250,247, 58,147, 81,229,101, 16,136,212, 49,107,111,110,151,247,223,215,107,145,238, 29,206, 45,
+ 63,161,246, 88,153,247,139,149,156, 79,155,208, 8,233,184, 47, 46,150,174, 32,203, 38,147, 89, 80,241, 82,211,189,164,119, 95,
+ 36, 18,213,200,157, 74, 75, 28,114, 11, 50,130, 59,157,236,172,221, 24,215,231, 13, 23, 37,147, 81,118, 25,168,236,189,253, 46,
+152,218, 93,144,151,101, 53,102,223,141,191,116, 91,190, 19,107, 28,209, 97, 71,172, 69,186,152, 65,253, 80,165, 4,167, 7, 26,
+218,107,158,228,161,191, 61,218,125, 49, 94,245, 40,172, 37,210,202,148, 67, 42, 11,229, 81,117,224, 57, 60,114, 15, 92, 2,160,
+149, 14,100,228,234, 49,124, 2,239,229, 79,110, 55,233,155, 77,234,234,233,116, 45,237,130,141,181,173,200,114, 66, 99, 70,106,
+181, 46,104,159, 98, 79,117,194,147,225, 52,221,203, 17,152,171,112, 17,134,171,110,142, 96, 9,204,138,108,186, 50,226,248, 65,
+230, 94, 18,210,234,138,218,116, 40, 56,144,201,253, 42,228, 2,144, 82,232,125, 39,155,155,185, 24,199,163, 70,113, 75, 61, 53,
+ 66,211, 24,192,102, 80,250,173,177, 4,158,128,236,109,107, 27,244,244, 55,216,120,245,195,212, 92, 51,226,119, 20,241, 60, 83,
+ 51,208,241, 68,223,164, 41, 96, 4,170, 44,179, 42,251,111, 53,134,197,189,176, 77, 41,141,108,170,146,160, 98, 5,181, 97, 28,
+ 75,220,181, 26, 38,200,211,104,247, 69, 74,235,183,182,170,177,190,251, 65, 11,117,110,107, 14,159, 10,179,117, 91,182, 75,207,
+220, 78,183, 82,133, 14,168, 4, 79,171,216,186,153,183, 21, 41, 82,210, 98, 36, 41, 9,115, 46,170, 58, 78,196,185,236,244,224,
+218,187,107, 59,115,220,156, 71,239,126,228,237,173, 2,138,187,170,107, 84,230, 45, 75, 86, 5,193, 65,109,135,229, 52,252, 91,
+142,223,106, 82,213, 70,114, 67,192,198,106, 35, 40,154,243,242, 91,140,151, 91,112,244,112,233,245, 17, 14, 44,120,174, 52,203,
+140, 76,104,179, 45,183, 16,135, 25,122, 52,130,142,120,210,155,117, 36, 60,203,137, 64, 5,181,165, 73, 88, 7, 57,232, 53,131,
+111, 20,122,181,183,183, 23,101,181,105,248, 52,138, 5, 74, 76, 74,251,148,250,116, 97, 1, 16,222,167, 60,106, 47, 70,165, 53,
+ 21, 77,181, 6,159, 41,244,182,244,150, 67,100, 56,236,116,184, 10, 10,220, 42, 89, 95, 56,135, 46,142, 10, 39,138, 88, 81,180,
+202, 38, 14, 74,164,134,226, 72,138, 50,168,146, 61,200, 73, 86, 72,223,161, 85,177,213, 91,112,255, 0,139,220, 97, 77, 6, 89,
+195,156, 53,196, 21, 60, 22,207,152, 77, 60,242,208,138, 52, 21, 75, 82,148,144,150,121, 38,162,154,174,158,178, 4,129,185,117,
+ 52,245, 41,169, 36, 80, 81, 94, 4,118, 96,232,187,243,188, 52, 58, 53,183, 22,179,113, 84,169, 53,196, 81,160,251,245, 41,201,
+ 62,244,245, 37, 30, 24, 17,105,181, 9, 10,121,208,245, 77,152, 9,140,153, 37,110, 58,225,146,151,148,235,139,112, 41,106,217,
+189,151,227, 46,253,131,118,219,180,250,252,122,125,201, 79,118,165, 17,114,150,164, 24,178,216,166,197,117, 15,212, 36, 41,109,
+252, 46,145, 13,149,146, 84,156, 16,146,163,211, 58,229, 18,107,239, 62,242,147, 37,199, 31, 91,206,242,186,241,117,192,165, 58,
+115,211, 39,155,149,210,121, 78, 15,117, 43,161,198,175,245,237,208,133,180,123, 77,185, 27,181, 83,195,175,211, 41, 12,109,245,
+155, 17,197,165, 15, 85, 55, 47,117, 95, 93,149,109, 82, 48,149,164,169,198,162, 73,174, 84, 86, 89,234,134,109,247, 20,190, 92,
+115, 20, 34,161,174,138,166, 35, 73, 52,177, 73, 35, 11, 42,177, 35,177,251, 38,224,129,110,227,176,216, 3,139, 63, 49,225,124,
+159, 58,137,168,171, 50,122, 67, 83,155,200,176,199,104,150, 37, 89,170,228, 17, 68, 21,129,214,136, 36,145, 64, 37,137, 84, 80,
+ 88,147,124,113, 55,116,247, 70, 69,253,187,251,165,124,248,206, 6,183, 3,113, 47,219,205,230,124,103, 29,108, 53,115, 87, 43,
+ 21, 40,234, 47,172,146,232, 75, 18, 90, 9, 39, 39, 13, 39, 9,232, 14,172, 14,214,153,120, 48,183, 78, 92,152, 57,157, 10, 37,
+ 43,109,167, 26, 13,184,150,207, 80,131,206,176,172, 30,169, 9, 5, 24, 32,105,155,145, 77,159, 79,177, 55,214,248,122, 99,102,
+ 14,214,238, 37, 54,195,167, 33,244, 45,181,207,144,221, 5,213,204, 44, 21, 16,151,138, 88,241,164,244, 32,167,198, 64, 82, 64,
+ 41,200, 53, 27,141, 40,118,147, 76, 15, 45,169, 62, 12, 25,243, 2, 86, 20,234, 16,197, 62, 19, 65,165,164,117,229,247,167,138,
+ 73, 61, 22,177,202, 7, 66, 69,171, 7, 12,211, 48,141, 68, 97,196, 42, 34,118,176,243,125, 68, 82, 27,237,230, 26,101, 64, 77,
+183, 59, 94,221,125, 38,200,188, 76,203,114,202, 54,165,142, 67, 20,116, 65, 22, 8,217,183, 68, 90,250,204,182, 21, 7,236,171,
+ 60,153,116,228, 2, 70,148, 58,202,134,186, 15,209, 95,217,213,187,149,126, 36, 56, 44,216,253,206,187,174, 26,157,110,227,126,
+218,126,193,186,149,240,199, 84,155,163,109, 39,191,101, 84, 39,204,125,144, 23, 80,149, 50,149, 75,163, 76,121,231, 85,202,227,
+245, 23,148, 15, 58,213,173,192,169,181, 57,184,233, 69, 62, 75, 17,217,117,148, 54, 25,157, 8, 41, 77,184, 20, 57, 18, 85, 21,
+196, 40, 55,148, 36,167, 33,106,235,158,185, 26,226,103,176,146,232,171, 73,224,105,202, 90,107, 52,248, 49, 97,111,182,232,183,
+ 25,185,145,221,148,239,233,169,118, 36,151, 91, 74,223,144,136,236, 44, 74, 46, 41, 40,108,169, 68,173,101, 73,230, 86,187, 41,
+ 49,154,218,209,205, 42,173, 52, 52,180,165, 74, 68, 70, 98, 69,116,182, 9, 42, 83, 15,150, 84, 82,172,173, 43,228, 0,100, 3,
+231,140,166,170, 86,154, 21,107,179,160, 10, 88,238,110,160,139,147,114, 77,254, 59,238,122,227,195,207, 25,248,114,151,135,188,
+100,241, 27, 44,203,158, 10, 60,158,155, 59,204, 26,142,156, 69,166, 56,105,158,169,228,130, 24,163, 88,121, 65, 97,137,146, 53,
+ 32,147,100, 5,141,201,182, 5, 94, 69,230, 10, 94,145, 46,158,251, 79, 45,104,148,212, 6, 23, 14, 74,219,229, 12, 45,182, 36,
+ 58,225, 37,149, 97, 25,231, 83,121, 7,151,152,115,103, 88,171,145,168,116,244,134, 97,194,115,222,240,219,142,210,234,106,145,
+ 26, 99, 65,211,209,246,222,146, 74,159,116, 16, 64, 41,113, 93,130, 80,224, 61, 53,146,220, 18, 42,169, 71,189, 65,175, 23,224,
+ 43,196,110,100,138,180, 52, 73,141, 20,132,150,219,121,201, 49,146,211,140, 32,184, 66, 20, 84, 8, 65, 74, 73,198,117,138, 87,
+ 28,148,234,162, 34,187, 74,117,192,134,195,141, 85,221,124,204,165, 74, 66, 64, 8,106, 33,105, 1,113,212,225, 81, 86, 31, 66,
+ 49,205,221, 67, 11,214,189,142,171, 48,185,237,109,186,218,221,251, 94,219,220,117, 0,118,198,190, 89,205,228, 83,161,104,226,
+136,234,212,180,224,194,199, 64, 4, 7,140,136,249,140,128,157,144,137, 21, 72,107,233, 54, 57, 45, 21,111, 50,239,128,212,167,
+155,106, 99,237, 53, 50, 5, 82, 58,170,112,130, 22,133,248,114,226,201, 82, 20, 84,194, 84,162, 75, 79,133, 20,150,202,144,180,
+144, 70,158,219, 70,151, 29,231,155,118, 60,104,204, 22, 63,193,222,142,151, 20,169, 10,146,203,194, 58,208,195,190, 63,232,220,
+ 83,255, 0, 26, 27, 64, 12,165, 9, 10,230, 9, 32,105,148,162, 91,141, 33,248, 83, 89,126, 99, 48,230,182, 20,180,198,150,244,
+129, 79,113, 60,188,170,101,153,170,115,222, 32,173, 37, 93,149,240, 99,149,124,169, 9, 89,109,184,249,226, 98, 31, 5,220, 21,
+239,191, 17, 15,200,136,155,150,213,178,166,210,246,246, 59, 73,141, 4, 86, 55, 54,239,228,181,236, 42, 83, 8, 90,185, 31,124,
+220, 21, 40,178,202, 18,149,144,213, 45,220,101, 41, 86,157,232,209,181,169, 10,100,111, 40, 23, 59,177, 54,181,129, 23, 4,146,
+ 58, 1,212,220, 92, 98, 11,198,117,212,212,212,243, 58,213, 20, 77, 12,210, 54,146, 52,132, 30,109, 96, 29,244,170,155,187, 57,
+ 42, 0, 96,197, 77,204, 4,253,172,219,203, 47,139, 95,105,175, 18,183,101,176,204,138,245, 61,141,200,141,179, 22, 18, 41, 9,
+ 93, 86, 93,102,147,182,162, 46,222,210,152,166, 51, 24, 19, 62,108,219,142, 29, 80,176,134,211,151, 87, 57, 0, 2, 78, 76,168,
+189,147, 30,205, 59,119,129,141,189,137,185,219,145, 71,167,212,120,177,191,168, 72,110,225,150,239,131, 57,157,155,182, 42,104,
+109,241,183, 54,188,132,130,150,171,238,183,225,154,253, 69,162, 22,251,224,192,105, 98, 36,114, 29,230,127,176,159,128, 53, 76,
+144,190, 60,247,198,152,229, 94,166,106,149, 39, 54, 34, 21,106, 58, 84, 43, 87,116,135,159, 77,209,188,211,162, 60,140, 58,227,
+ 18,159,150,197, 29,103, 9, 19, 37, 74,154,140,150,153, 34, 80,232,121,231, 86, 94,194,151,206, 84,165,229, 89, 83,132,156,149,
+100,255, 0, 59,169,238,117, 52,214,174,144,192, 15,246,106, 75, 42,129,210, 73, 19,102,115,254, 20, 96,116, 95,171,221,172, 52,
+163, 53, 11,192,252, 48,106,170,102,226,204,206, 29, 53, 57,147,188,180,145, 48,254,234, 41, 9,101,148,237, 96,238,166,209,126,
+196, 86, 97,188,158, 91,213,199, 90, 49,104, 79,128,238, 30,144,121, 9, 61,192,192,201, 10,245,242,251,181,174, 71,196,148,241,
+192, 74,219,247,143, 25,101,101, 88, 83,109,158,100, 32,143,231,159, 20,183,140,231,245,116,231,222,179, 3,236,178,194, 18,160,
+158, 67,240,159,214,231, 63, 8,200,245,230, 7,246,107, 16,183,233,171,125,220,148, 41, 94, 26,193, 82, 72, 56, 30, 24, 42, 25,
+ 7,182, 93, 82,127,254,159,144,211, 69, 97,106,138,152,227, 83,176,254, 38,222,238,150,252, 15, 81,139, 78, 53, 68, 46, 72,176,
+ 83,107,124, 58,253,247,191,243,198,113,108,211, 19,227,169,194,215, 63,134,203, 99, 5, 93, 27,101,146, 22,246, 14, 62, 37, 45,
+242, 7,255, 0, 71, 91, 55,104, 83,196, 88,200, 91,141, 21, 62,226,125,225,196,142,201,144,233, 1,182,178,161,208, 1,200, 7,
+158, 18,112, 52,218,218, 20, 34, 11, 72, 82, 48,167, 29, 66, 86,162, 9, 37,168,227,198,115, 36,249,169,100, 15,158,126,122,216,
+ 74, 93, 56,165,176,160, 48, 80,160,230, 79, 96,234,193,228, 24,207, 80,150,250,245,243, 58,216,145,194,132,133, 59,122,123,247,
+233,252, 61, 58,123,176,171,188,113,197,169,205,134,223,126,214, 23,251,250,216,250, 19,223, 23,184, 45, 45, 45,164,250,130,146,
+ 81,130,165, 58, 79,198,161,205,211,205, 71, 39, 29,135,217,171,242, 82,161,202,146, 14, 66, 64, 79, 92, 18,112, 18,132, 16, 7,
+ 82, 71,151,110,167,174, 79, 64,225, 49,204, 6, 74,148, 8,194, 60,151,142,203, 80, 0,244,206, 50, 62, 95,110,173, 87,197, 93,
+ 84, 74, 17, 76,101,242,212,170,171, 93, 62,154, 51,254, 77,126, 25, 50,166, 56,148,245, 8,102, 57, 81, 78, 59,184,180, 13, 2,
+252,184,139,157,194,142,158,167,111,226,127,215, 17,237, 18, 87, 87, 69, 75, 8, 13, 45, 67,233, 30,130,251,146,127,194,160, 22,
+111, 64, 9,233,134, 94,191, 60,214,174, 57,178,155, 80, 92, 88,138,250,178, 34,146, 73, 75,205,197, 89,247,133,181,215,245, 87,
+ 40,172, 41, 93,185, 91, 30, 93,117,113,101,178,148, 36, 20,167, 60,185, 33, 32,115,124,125,242,123, 32, 17,235,228, 58,103, 58,
+ 6,155, 5, 49,217, 1, 3, 41, 72, 72, 43, 80,202,251,124, 13,167, 57,231,230, 87,116,142,188,202,202,181,122,119,157,164,242,
+182,128, 48,114, 74,210, 29, 82,148,174,231,149, 4, 14,112,122, 96,156, 36, 12,232, 82,130, 20, 22,181,207, 83,241,235,252,127,
+134, 38,117,241,198,136,144, 66, 60,145, 40, 65,126,182, 80, 5,205,187,158,167,191,125,177,107,145,209, 56, 56, 42,192, 31, 7,
+ 50,136, 81, 39,245,114, 6,113,145,215,212,143, 62,186,109,183, 18,195,178,183, 58,203,185,118,235,114, 45, 74, 13,245, 98, 93,
+244,185, 20,123,178,204,185,224,179, 84,161,215, 41,210,208, 90, 83, 50,227,188,143,209,202, 66, 15, 51, 50, 26, 45,202,140,234,
+ 80,244,119, 91, 90, 65, 46, 20,133,132,149, 18,121, 66, 82,146,158,167,227, 3, 9, 11,231,233,205,133, 28,116,233,240,231,231,
+171, 4,167,130,146, 70,115,130, 7, 41,230, 1,190, 97,133,140,168,119,230, 25, 87, 47,167, 66,115,128,228,164, 50,233, 32, 21,
+ 35,161, 23, 7,226, 15, 81,234, 45,238,196, 78,170, 0,218,129, 93, 72,247, 12, 8, 22, 32,141,193, 7, 98, 10,220, 16,110, 45,
+112,118,216,254,127, 62,215,111,101, 5,107,129, 75,173,157,208,218,223,173, 46,126, 22, 47,170,217,166,219, 21, 73,139,114,161,
+ 95,218,219,154, 98, 29,148,206,220,223, 83, 66, 63,194, 24, 91, 77,191,245, 45, 81, 88, 76,246, 99,150, 29,196,198,148, 28,226,
+ 11,202,192,207,250,185,206, 65,252, 7,207,183,227,175,213, 99,121,118,187,111,119,183,109,239,125,163,221, 75,114, 53,215,183,
+ 27,137, 66,147,110, 93,212, 9, 73, 66,132,168, 18, 70, 89,155, 1,197, 28,211,235,208,230, 33,137,116,249, 72, 41, 92,105,113,
+154, 90, 84, 7, 50, 85,249,178,113,225,194, 13,235,193, 55, 17,215,238,197, 93,238,191, 80,167, 82,159, 69,111,111,238,242,201,
+110, 45,251,182,117,197,186,245,165,117,196,233,203,239, 75,138,218,226,212, 26, 24, 84,122,141, 58, 75, 74, 74, 64, 71, 51,238,
+ 85, 86,192,138, 57,152,176,223,150,204,110, 72, 29, 81,137,234,203,216,159, 51, 46,237,118, 86, 99, 65,113,143, 12,174, 75, 50,
+215, 81, 41, 25,101, 83,105, 43,215,145, 46,237,160, 27,127,116,226,230, 50,126,201, 86, 67, 97,203,213,166, 30, 57, 89, 86, 50,
+ 57, 63, 91, 35,175,110,154,250,115,156,144,122,249,254,255, 0,158,190,132, 99,161, 63, 14, 7, 46, 51,204,122,121,244,234,117,
+245, 72,229, 29, 50,113,234,114, 6,127,226, 52,254, 46,118,196, 36, 11, 11,116,192,142, 40,231,160, 24, 29,207,175,231,166,135,
+ 82,137,238, 64,232,124,241,143,179, 68, 44, 19,211, 24,237,156, 99,160,245, 31,126, 52, 50,128,235,212,121,128, 78, 49,215,207,
+246,105, 68, 59, 91,211, 6,181,253,109,251,240, 59,128, 1,240,171,174,122,121,121,246,207,159,246,104,101,244,200,243, 35,246,
+ 1,147,162, 21,140, 28,140,254,113,161,148,112, 8,235,215, 56,237,248,125,154, 85,112,176,189,136, 39, 3,168, 0, 15,145, 62,
+ 99,204,143, 35,249,242,208,203,229,235,235,211,242,126,225,162, 87,140,117,249,224,122,159,158,135, 88,233,231,247,118,251,254,
+237, 44, 58,142,248,193,237,183, 67,243,247, 96, 69, 12, 31,183,175,217,165,175,171,198,113,140,126,255, 0,187,241,210,210,202,
+ 77,133,197,207,221,131, 99,202,112, 72, 7,242,117, 92, 15, 35,128, 60,190, 67,250,245, 69, 3, 39,236, 25,209, 40,239,246, 15,
+207,219,164,143,175,174, 6, 42,164,124, 64, 14,131,166, 15,207,236,243,242,209, 35,215, 56,198, 62,220,124,191, 62,122,164,143,
+ 51,208,255, 0, 72,235,253, 31,213,170,160,100,227, 56,233,145,243,252,254,237, 17,175,109,186,223, 3, 4,160,140,231, 62, 93,
+207, 79, 77, 22,130, 49,143, 63,233,251, 52, 26, 72, 30, 64,143,179,183,217,162, 1, 74,146, 72, 61, 65,252,115,142,159,159, 93,
+ 35,140, 48,184,235,108, 20,140, 18, 1,239,158,135,203,239,209,169, 7,166, 14, 79,145,253,186, 1,158,132, 17,149, 14,196, 19,
+140,124,243,251,180,122, 72, 79, 76,145,211,160,233,147,164, 9, 36,220,225, 54, 29,199,206,216, 33, 4,224,142,153, 29, 85,219,
+183,166,164, 73,236,110,220, 31,173,246,111,125,182,170, 68,175, 13,251,106,189, 68,191,169,177,199,196,183, 33, 84,227, 24, 21,
+ 2,134,250,229, 41,151, 17, 57, 35, 63,229, 6,117, 29,198,252,179,144,122, 1,230, 79,219,211, 93, 44,246, 85,110,228, 13,175,
+226,214,210,164,215,229, 24,246,198,234,192,168,237,157, 95,227,228,108, 75,174, 32, 59,111,188,224, 39, 4, 38,172,195,104, 4,
+246,247,157, 70,120,186,135,219,242, 26,232,130,234,146, 37,230, 46,215,221, 14,166,255, 0, 32, 97,247,226,198,240,131,136,227,
+225, 95, 18, 56, 87, 54,157,180, 83,123, 64,167,148,237, 97, 29, 72, 48,220,223,107, 43,186, 57,255, 0,166,248,146, 36, 30,101,
+188, 76,200, 92,160,148,190,196,228, 14, 82,218,114, 10, 92, 8,242, 87, 93,108,205,136,136, 94, 60,105,208,170, 83, 26,151, 9,
+191, 29, 82,222, 74,157, 92,231, 64, 7,195, 90, 79, 64,192,244,244, 26,103, 63,131,149,104,117, 26,148, 68,184,195,109, 83,228,
+173,134,209, 44, 2,226,202, 22, 82, 16,178, 79,234,114,242,159,179, 79,213,149, 33,113, 88, 77, 61,112, 27,121,229,248,106,149,
+ 58, 39, 41,101,148, 19,213, 63, 32, 79, 66, 62,237,115, 51,211,150,121, 6,155,219,175, 91,109,181,133,253,226,219,123,241,235,
+ 75,241, 11, 79, 76,188,137, 11, 48, 93,149, 89,118, 13,107,151, 89, 1,176, 11,212, 3, 98, 79, 75,219, 27, 67,183,181, 74,244,
+214,231, 56,229, 74,158,135, 38, 41, 14, 18,160,166,156, 74, 16,156, 36, 32,118, 65, 62,159,191, 89,190,241,113, 11,110,112,191,
+176,215,206,245, 95, 6, 20,202, 61,145, 74, 92,138,101, 45, 18,130,100, 92,247, 68,212,150, 40,116, 70,185,198, 84, 94,156,164,
+120,132, 3,202,211,110, 40,118,198,137,219,165, 83,139, 76,133, 80, 28, 90,114,210,212,240,109, 10,241, 74, 15, 76,167,253, 94,
+159,126,117,202, 47,164, 21, 92,174, 69,225,135,102, 32,209,169,178,160, 90,181,125,216,152,229,206,180, 71, 8,142,167,224, 81,
+ 11,148,102, 36,173,177,132,143, 17,201, 42, 66, 85,208,148,156,117, 26,113,203,168, 3, 58,157, 54,103, 33,125,118, 36, 94,196,
+237,222,227,213,182,195, 70, 89, 79, 69,197, 92, 91,144,112,245,125, 61,168, 43,234, 1,157,252,177,147, 20, 49, 60,207, 26,149,
+ 58,245, 75, 28, 77, 18,149, 55, 93, 87, 27,139,227,130,123,191,198,175, 16, 27,247,184, 53, 45,208,191,119, 70,231, 85, 90,163,
+ 41,199,233,180,154, 61,106,117, 46,133,107,211, 84,247, 52, 26, 77, 22,153, 17,228, 34, 20,118, 27, 40, 72, 87, 47, 57, 41, 37,
+106, 42, 36,235,167, 28, 15,251,109,119,107, 98,106,116,123, 7,136,169,179,119,107,102, 31,113,136, 72,172, 74, 90,101,223,214,
+ 83, 75, 33,180, 78,165,212, 93, 60,213,120,109,143,137,113,159, 82,138,146,217, 13,173, 11,198,163,142,186,235,108,188,164,169,
+213,165,121, 56, 0,143,231, 19,148, 16, 58,242,145,159, 46,186, 6,109,204,220, 84,151,229, 73, 75, 76,165, 69, 13,186,181,124,
+ 13,149,252, 65,167, 20,122, 32, 43,175, 41, 61, 51,208, 28,156, 25, 60, 92, 63, 80, 37, 67, 1, 49, 19,208,129,189,141,182,255,
+ 0, 21,246,184, 55, 7,184, 56,236,142, 32,151,195,140,255, 0,133,223,133,248,147,134,104, 42, 50, 10, 88,196,113,162,172,112,
+123, 24, 69,210,178, 83, 74,129,100,164,145, 7,247,111, 27, 39, 75, 54,164, 44,167,244, 98,220,125,244,218,109,207,181, 44, 93,
+211,218,219,134,218,187, 42, 87, 53, 36, 51, 69,220, 10, 51, 17,100, 76, 69,191, 35,149,215, 40, 82,159,113, 5,234, 52,228, 57,
+209,198, 86, 27,121,151, 16,161,243, 44, 38,219,240, 59,195,109,247,187, 50,119,219,118,236,200,251,153,118, 75,170, 65,173, 67,
+182,174,118,154,153,103,210,171, 16,188, 32,197, 90, 69, 61,192, 77,102, 97, 83, 13, 41, 94, 54, 91, 36,117, 74,129, 58,135, 95,
+ 6,188,107,223,252, 45,110, 43, 52,233, 52,170,149,203, 96,222, 20,101,215, 83,103, 60,250,190,174,187,227,193, 5,199, 38, 91,
+143, 44,148,196,174,178,208,123,149, 72,234,165, 37, 41, 87, 50, 84, 70,166, 95,193, 71, 19,251, 57,196,190,221, 82,183, 35,102,
+111, 8,119, 37, 13,224,211, 21,170, 59,206,165,155,154,207,170,129,201, 34,143,114, 82,138,185,226,186,219,193, 72, 75,184,240,
+221, 9,202, 85,215, 26,134,231,185, 70,123, 75,158, 38,105, 42,145, 71,202, 88,163,146, 50, 90, 29, 18, 16,197, 88, 92,133,119,
+146, 38,219,245,140,108,190,102, 70, 11,198, 92, 75,194, 16,120, 95, 13,105,224,204,246,176, 46,111, 21, 85, 20,213, 74,239, 79,
+ 89,200,142, 74,121, 30,138,165, 99, 8,209,242, 82,106, 70, 89, 32,229,195, 52, 53, 48, 77, 24, 84,168, 68, 26,105,237, 7,217,
+ 19, 64,220,153,215, 20, 88,210,156,133, 88,145, 38,124, 79,119,101, 69,163, 18,166,128,243,109, 37, 40, 1, 44,161,169, 41,117,
+174,100,245, 74, 25, 74, 0, 3, 3, 90, 51, 69,177,226,173,138, 60,234,204,122, 85, 38,221,129, 41, 51,103,211,161,176, 94,110,
+ 91,208,250,114, 84,204,148,115, 56,210,150,121,194, 65, 70, 22, 18, 73, 35, 82, 72,226, 42,210,160,110,117,160,197,162,168,115,
+ 29,188,213, 74,168, 86, 45, 9, 77, 65,126, 76, 10,156,120,126, 17,171,208,229, 78,105, 60,176,167,150, 84,151,226,161,194, 60,
+101, 71,113,182,200, 89, 26,226, 82, 54,226, 82, 43,245, 56, 55, 19,146,165, 82,168,173,189, 53,234,122,121,219,167,174, 92, 53,
+ 21,161,215,162,173,172, 60,148, 33, 24, 82, 73, 88,113, 92,185,201,201, 27,117,108,244,241,194, 26, 80, 4,200,175,177, 5,212,
+177, 33,144,129,246, 88,144, 74,234,211,113,184,242,225,135,128,248,146,174,159, 42,143, 44,172,115, 72,249,120, 15, 20,146, 35,
+ 63, 50,152, 72,218, 26, 20, 93,164,179,172,144,173,201, 8,234, 67,105,179, 12, 29,182,244,136,190,236,139,162, 43,211, 44,218,
+ 8,144,234,232,245, 56, 11, 17,235, 21,134,156,116,152, 20,134, 80,176,164, 56,209, 72, 43,143,200,135, 22,133,101, 74,113, 57,
+214,238,237,187,251,130,203, 76, 67,151, 72,167, 84, 98,133,170, 91,213, 42,148,233, 12, 76,138,192, 82,148,219,210, 68,113,202,
+170,138,219,193, 89, 73, 67,106, 72, 42, 40,200,248,181,222,133, 7,252, 38, 61, 94,168,236, 48,218, 34,198,106,222,121,215, 12,
+ 42, 5,177, 73, 72,109,202,131, 44, 54,165, 4,166,172,236,131,241, 5,128, 23,219,155,149, 1, 39,109, 54,169, 47,214,159,141,
+ 78, 48, 42, 53, 11, 73,106,126, 99,142,173,244,196,145,119,169,196,182,166,100,201, 84,167, 3,137,162,161,194, 72,100, 6,202,
+154, 9, 82,143,134, 60, 50,195, 58,115, 25,121,138, 2, 2, 5,250,155,236, 2,134,216,220, 95,168,238, 13,133,186, 73,115,220,
+216,213, 80, 74,207, 75, 13, 76, 72,128,234,144,106, 49, 40, 80,161, 99,149, 74, 52,149, 4,141,198,181, 87,112,116,142, 90,187,
+151,130,212,169,221, 85,192, 81, 71,162, 69,143, 17,233,177, 66,234,213,121,210, 29,109,249,104, 83,136, 47,211, 99,197,142,149,
+ 42, 58, 27, 13,132,100,161, 42, 4, 36, 14,234,214,192, 82,168,207, 6,100, 72,146,243,115, 36,115, 37,223,120, 83, 66, 40,134,
+150,151,200,182,225, 67,103,224,109,191, 19,152,143,214, 95, 97,205,166,202,221,175,203,122,100, 42,117, 14, 27, 48, 96, 45,217,
+109,187, 93,144,132, 73,164,149, 65, 11,113,200,212, 8,170, 80, 21,149,224, 37, 41,120,242, 70, 10, 10, 9, 83,160, 99, 78, 43,
+116,232,146, 18,162,237, 86,169, 54, 43, 79, 52,133, 63, 42,172,182,163, 42, 83,190, 32,120,165,166, 16,210, 27, 75, 65, 69,178,
+ 18,158, 64,162, 82, 50, 81,157,111, 81, 68, 21,129, 8, 22,227,101,189,237,123,109,114, 1,185,236,109,232, 47,107,226,137,226,
+141, 77, 41, 30,203, 30, 87, 20,158, 96,168, 26,121,138, 19,111,172,118,118,179, 18,159,221,137, 20, 88,110,150, 85,193, 53, 73,
+145,226,170, 46,101,196, 76,164,184, 28,240, 12,134,153, 95, 43, 10, 74,155, 46,181,207,144,121,194, 7, 62, 9, 82,143, 47,108,
+234, 4, 62,210, 58, 72,219,158, 58,184,155,183, 37, 40,183, 29,237,225,189,234, 44, 58, 57,127,200,220,181, 35,117,198, 37, 8,
+ 56,229,118,159, 89, 74,128,242, 87, 67,131,157, 78,142,170,138, 83,209,158, 69, 30, 52, 6,160, 54,228,136,114, 46, 38, 99, 50,
+181,206,146,133,248, 78, 67,166, 72,113, 37, 82, 16,149,149, 37,199,134, 91, 66,242, 26, 11, 88, 90,147, 16,207,164, 3,178,234,
+161,113, 5,183,251,173, 73,167,134,104, 59,189, 97,210,168, 85, 9, 52,211,200,236, 43,223,109,162, 38,218,168,185, 41,231, 21,
+137, 21, 23,168, 70,202,152,128, 87,226, 56, 92, 95,235,114,171, 51, 28,157, 98,150,190, 8,100,110, 92, 83,221, 79,199, 69,239,
+185,177,177, 27, 15,128,189,142, 45, 63,163,127, 17,212,112,127, 20,113, 29, 53, 38,185,106,243,156,177,196, 81, 58,133,230,212,
+ 82, 85, 83, 84, 44,108,169,172,160, 52,166,171, 97,169,163, 3, 91,114,200, 24,226, 4,154,196,244,219,106,220, 88, 18, 36,123,
+230,213,238,117, 58,151,184,116,120,110,184,212,168,118,117, 66, 76, 20,196,186,144,180, 43,157,136,145,234, 12,197, 91,146, 81,
+132, 70,114, 83, 75, 43, 75,110,100, 74,151,217,207,198,213, 39,137, 54,238, 61,133,221, 10,180, 42,127, 21,123, 72,167,219,169,
+193,146,168,241, 90,223,139, 2, 44,118,170, 52, 45,207,178, 66, 74, 81, 80,184, 88,183,166,211,141,199, 76,103,157,106, 33, 53,
+232,129,216,210,102,162, 20, 59,161,215,121,234, 81, 43, 84, 91,170,177,103,222,204, 45,171, 98,241,138,155,114,161, 89, 69, 74,
+148,180, 59, 78,143, 92,122,151, 17,151, 83,112, 82,132, 69,184,196,200,129,133, 59, 38, 25,125,133,176,243,141,180,149,244, 87,
+132,222, 13,248,140,184, 47,203, 39,113,120,121,171,199,191,238, 93,185, 98, 53,251,111, 91,251, 99, 85,166,215,175, 87, 41,240,
+ 42,241,155,165,214,182,154, 47,191, 41, 91,145,104,211,234, 42, 83, 92,148,103, 83, 85,163,199,117, 84,250,197, 33,136,225, 97,
+185,206,113,194,121,109,101, 27, 45,125, 80,163,171, 2, 95, 99, 38, 41,121,134,115,162, 78, 66,144,133, 38,141,138,205,202, 84,
+102,150,120,231,139,150,134, 90,104,163,158, 75,196,249,142,105,226,180,212, 89,118, 93,165,163,138,170,138, 74,220,202, 74,236,
+184,209, 80,208,200,239, 65, 46, 97, 87, 27,213, 71, 85, 72,252,182,203, 23, 53,133,225,134, 42, 12,195, 41,170,210,211, 69,154,
+203, 85,150,205,166,227,165, 61, 6, 5, 54, 97, 74,156, 18,227, 69,110, 35,140,180,165,169,249, 82,156, 67, 13, 71,138,218, 85,
+241,185,226,184,218, 91, 31, 9, 82,214, 50,122,244, 11,114,111, 27,114,131,182,251,199, 34,255, 0,136,154, 45,247,176,245, 58,
+ 22,218,111, 22,216,181, 81,143, 85,184, 45,221,195,188, 89,183,161, 89, 20, 42,100,159,117, 96, 92,148,187,141,187,194,223,118,
+133, 84,102, 59,113,170, 72,126, 72,105, 41,114, 12,164, 55, 75, 99,119,122,224,174, 51,245, 7, 19,219, 89,112,112,215,186,220,
+ 60,220,144,175, 61,215, 77,193,108, 87,174,237,159,151,101,211,226, 77,189, 33,110,173,151, 93,162, 70,144,154,221,142, 81, 76,
+164, 63, 80,165, 60,241,153, 77, 68,215, 72,114,100, 8,147, 31,135,146,113, 71,183, 59,103, 34, 92, 13,253,110,235,173,110,165,
+205,184,176,173,202,147,143,193,221, 91, 86, 92, 45,209,191,156,186,104, 59,129,181, 86,205,199,245, 20,121, 48,102,109,181,175,
+123,214, 32, 86,104, 82, 40,181, 28,208,209, 13, 52, 53,191, 38,135, 86,101,109,214, 19, 84,229,188, 53, 74,207,159,161,161,167,
+175,150, 56, 86,121,140,113,211, 67,100, 55, 51,107,101,157, 73,146, 72,180,145, 11, 42,168,147,153,162,197,146,162,201, 56,112,
+210,113,141, 46, 79,196, 20,245, 18, 53, 58,173, 84, 67, 46, 95,106,106,245, 73, 41,170, 2,208,207, 24, 52,245, 80, 86, 80, 37,
+ 72,165,150,158,114, 90,122,170, 9,135,212,151, 87,227, 20,104, 45, 87, 24, 85, 86,218,241, 42,148, 71,110, 43,170,211, 76,212,
+ 52,150,132,106,245,151,114, 85,109, 11,162,129, 84,104,168,251,149,106,157,112,209, 42,113,229, 48,188, 58,218,227,142,108, 33,
+ 77,169, 90, 21,237, 94,168,222, 22,133,223,195,254,202, 10, 93, 82, 93,177,180, 43,183,183,154,236,164, 81, 20,153,146, 98,238,
+125,229, 73,129, 91,163,213,175,116, 52,191, 22, 53, 66, 29,188,253,173, 71,167, 81, 57, 76,150,133,213, 81,149, 33, 81,220,148,
+211, 74,150,182,225,218, 92, 50,112,247,195,165,153, 77,165, 90,219,117, 99, 91,150, 60, 43,174,244,174,223, 49,109, 27,134,228,
+218,202,205,255, 0,107,212,149, 18,116,251,243,114,104,207,201,168, 51,121, 72,220, 7,211, 38,169, 13,184,115,170,215,251,244,
+217,244, 88,238, 70,155, 37,169, 49,121, 20,212, 93,185,118,222,225, 46,203,225,223, 98,183, 23,120,253,160,252,116, 84, 55,118,
+117,213,191, 91,223, 72,247, 69,219,219,105,184, 23,221, 98, 20,254, 44,230,237,204, 42,236,138,109, 42, 84,217,212,251,153,118,
+ 17,144, 93, 52,138,101,143, 85,175,174, 58,252, 58,125, 67, 79,254, 28, 54, 93,153,214,174,113, 79, 20,121,133, 44, 97,185,112,
+ 9,150,105,100, 73, 41, 86, 94, 92, 38, 35, 21,167, 43, 81, 29, 57,169,144, 44, 20,142, 37,170,101,154, 49, 70,106,111,238, 14,
+168,151,137,248,115,244,207, 19,210,215,101,116,144,212,140,186,131, 48,134,146, 36,164,139, 59,164,121,107,219, 53,204, 26,181,
+229,163,139, 38,160,162,201,235, 36,205,169, 85,235,234,125,154,190, 36,140, 9,162,154, 90, 72,169,213, 45,253,208,118,151, 97,
+ 90, 91,181, 38, 13,167,103, 94,215,213,102,231,174, 55, 49,215, 31,172,238, 77,247, 17,216,119, 14,228, 45, 49,233,233, 9, 77,
+ 46, 21, 66, 69,159, 70, 41,134,135, 99,193,140,211, 84,180,200,231,102, 82,155, 18,155, 83,131,120, 85,111,219,154, 3, 50,105,
+148,169, 19,160,193,160,214,170,113,194,103,214, 98,211,229,168,183, 62,159, 72, 66,178, 89,147, 84, 14,152,173,252, 45,248, 13,
+ 54,178, 84,149,147,169,133,123, 64,189,146, 86,255, 0, 13,187,109,182,187,145, 64,219,248,219,185, 14,215,178,234,116, 13,218,
+222, 42,148,217, 2, 53, 42,184,204, 22,226,237,117,131, 14,206,132,240,114,194,225,222,157, 83, 53,138,149,106,161, 29, 14, 73,
+171, 86, 42,171,153, 89,124,169,230,121, 34,177,182, 91, 65,116,111, 46,243,196,218,253,171,247,251,206,183,116,213,106,146,228,
+110, 45, 77,182, 89,136,139,118, 28,148,197,186,119, 9, 54,243, 47, 6,109,107, 54,152,143, 26, 45, 38, 35,139,255, 0, 5,141,
+ 9, 78,190, 85, 41,232,140,170,115, 83, 86,212,245, 25,140, 21,212, 63,162,231,161,141, 36,125, 43,202,166, 45, 35,172,211, 73,
+ 10, 63,152,169, 40,176, 6,149,220,186,195,120,162,104,238, 34,191,184, 15, 62,224,252,219,132,178,206, 51,225,190, 45, 60, 75,
+193,102,174,190, 55,168,174,180,249,164,116,185,109, 52,249, 86, 93, 75,153, 84,195, 32,246,103,141,107, 43,115,158, 82,101,249,
+ 74,150,205,227,150,183, 49,167,173,118,253, 35, 52,143, 98,189, 5, 54,159,179,243,109, 77,101, 98, 4,221,196,190,119, 71,112,
+ 90,102,181, 21, 8,139, 91,164,212,174, 88,182,196, 10,140, 85, 56, 18,219,240,220,254, 9,200, 41,115, 33, 74,231, 82,146,146,
+218,155, 42,234,187,209, 27,163,184,237, 90, 72,168, 42,130,200,240,165, 64,143, 38, 82,158,160,173, 74, 13, 9, 84,182,157,124,
+ 46, 93, 57, 73, 90, 10,152, 73, 43,100,172, 41,160,180,115, 32, 49, 27, 9, 77,177,109, 93,139,217,139, 99,111,227, 72,143,183,
+214,214,217,218,118,173,163, 6,173,153, 19, 88,131,108,210, 99,208,101, 65,174,135, 83,148,212,157,159, 79,150,244,181, 20,148,
+123,204,229, 43,177, 57,114,208,124, 17, 57,202, 83, 14,170, 36, 5,137, 85, 10, 36,185, 75, 84, 55, 96,202, 71, 42,132,120,171,
+113,106,241,219,116,146,219,173, 15, 11,186, 85,148,168,114,194,132,136,200,173, 31,158, 54, 80, 65, 3,168, 34,224,129,232, 65,
+213,184,220,116, 23,199, 0,113,150,101, 55, 20,241,127, 20,113, 19,235,165, 25,245,125, 85, 67,198,196,108,179, 84,182,152,185,
+133,129, 73,145, 89, 34, 14,220,203, 72, 8,103,229,150, 86,247, 81,110, 91, 49,167, 78,161,215, 37,212,219,113,213,165,218, 85,
+ 69,240,244, 26,132, 54,129, 11, 49,228,181, 29, 46, 66,168,140,245, 75,156,193,124,161,183, 27, 28,201, 86,190, 81,155,125,104,
+135, 34, 12,114,220,121, 41, 40, 98,157, 53,228,170, 35,114, 20,230, 86,221, 26, 80,200,167, 40,169,103,158, 59,169, 8,202,112,
+128,131,144, 60,211,163, 71,152,183,230, 83,229,191, 4,133,169,153, 76,134,179, 60,198, 89,109,232, 14,212,225, 62, 86,221, 65,
+ 13,185,148,165,196,101, 78, 32,243, 37,209,130, 19,153,208,146,134, 81, 41, 19, 11, 49,214, 86, 24,121,165,178,165, 69,168, 40,
+ 31,135, 1, 64,169, 46,149, 41, 36, 40,254,144, 5, 36,146,188,100, 38,134, 48, 25,152,141,172, 46, 77,136,220, 27,250,141,253,
+222,226,122,130,193, 89, 80, 41,169,164,139, 72,146, 84, 43,112,200, 85,236, 84, 40, 87, 84, 1, 94,219, 21,144, 93,244,155, 22,
+ 69,101,209,125,183,168,209, 97,190,250,204, 70,152, 5, 64,200,140,166,150,203,176, 87,241,151, 94,136,160,178,134,218, 89,230,
+ 82,128,202,114,162,164,100, 2, 53, 28,111,107, 60, 59,251,143, 63,104, 23, 11,126,205,170, 3, 53,106, 46,201,109,173, 53, 27,
+255, 0,189,117,166,249,216,137, 90,147, 49, 18,105,172,202, 66,146,174, 71, 98, 81, 45,102,106, 49, 24, 42,193, 53,155,189,229,
+160, 5,197, 73,215,123, 47,141,211, 98,142,167,173,155, 89,193, 42,229, 25,106, 76,148,165, 47, 71,180, 91,112, 5,120,181, 23,
+ 14, 83, 34,182, 58,174, 44, 18,162,180, 43,149,249, 92,173,165, 40,113,184,160,218,118,243, 51,158,189,219,161, 64, 93,228,170,
+ 58,109,137, 55, 99,177,210,229,194,253,186,103, 61, 86, 93, 46, 69, 85,196,248,174,194, 85, 90, 68,169, 42, 65, 86, 20,243,235,
+ 89,234,113,167, 76,190, 73, 36,154, 36, 66, 2,174,204,196,216,168, 96, 86,235, 97,187,142,171,113,179, 0, 79, 96, 43, 78, 39,
+200,167,207,168, 64,172,169, 48,195, 60,176,243, 35, 59,153,169,213,129,145, 9,184, 40,178,128, 35,189,201,120,217,238, 72, 33,
+152, 74, 45,191,110,218, 20, 10, 5,159,104, 82,163, 80,109, 43, 50,145, 78,182,173,138, 20, 36, 37,152,116,202, 37, 38, 58, 33,
+ 65,136,219,104, 24, 24, 97,176,165, 43,186,214,165, 45, 89, 82,137,214, 66,192, 44, 56, 50, 64, 66,255, 0, 84,246, 74, 22,174,
+188,167,230, 79,109,121, 92,114, 87,226,132,243, 5, 16,162,145,156, 45, 62, 69, 56,238,161,231,246,106,239, 2, 58, 29,109,109,
+140, 45, 4,158,231,170, 65, 29, 58, 31, 49,251,181, 41, 93,150,200, 52, 42,216, 5,236,161, 64, 0, 1,233,167,107, 95,107, 15,
+118, 6,132,133, 20,133,242, 45,129, 0, 88, 1,181,128, 29, 5,187, 14,150,219,160,198, 15, 92,140,185,115,138, 64, 42, 71,192,
+ 48, 51,148,245, 42, 81, 7,237,199,237,198,179, 75, 74,130,162,174,110, 64,124, 66, 48,124,213,215,155,149, 64,142,249, 35,240,
+215,148, 83, 60, 73,124,161, 36,156,132,103,190,121, 71, 64,125,124,254,243,173,128,177,237,177,134,150,166,134, 7, 42,186,224,
+143, 44, 12,121, 14,154, 67,202,160,201,111, 49,218,255, 0, 63,127,239,196,120,213, 0, 90,237,117,185, 55,251,239,238,249,252,
+ 47,182,197,185,224,181,226,148, 36, 57,202,148, 5,148,228,167,152, 5, 58, 79, 79, 76, 14,157,180,226, 8,126,236,203,104,229,
+ 60,234, 39, 41, 0,168,144,160, 20,178, 64, 31,173,203,129,242,206,178,138, 93, 27,145,148, 5, 35,225, 35, 39, 61,212, 7,196,
+ 78, 60,251, 1,143, 61,123,145, 19,153, 69, 69, 4, 41,106, 8, 66, 83,212,227, 32, 37, 32,103,190, 59,159, 85,124,134,144,177,
+221,137,249,239,127,225,134,106,140,228, 77, 49,141, 79,213,198,127,211,243, 54,237,139, 84,118, 89,109, 14, 61, 41,212, 70,139,
+ 13,135, 37,204,148,176, 18,212,104,172, 36,184,227,206, 40,246,108, 37, 56,249,146, 7,158,181,250,179, 86,126,239,172,200,171,
+165,165, 49, 78,105, 40,133, 70,101,239,129, 48, 41,109,171,225, 88, 0,126,146, 83,234,203,139, 61, 57, 66,130,124,177,167, 30,
+243,170, 10,151, 53,173, 13,126, 37, 62, 51,173,185, 94,117, 25,228,155, 49,165, 7, 24,164,151, 19,254, 82, 35, 74, 8, 47, 36,
+116, 83,129, 32,146, 1, 26,196,209, 13,152,192,120,189, 72, 36,248,109,160, 56, 2,128, 5, 63,163, 79, 92,103, 3, 39,160,236,
+ 58,233, 61, 70,161,194,166,241, 70,119, 63,180,195,227,217,127, 22,248, 41,196,175,135,160, 90, 56,228,204, 39, 66,107,106,150,
+209, 41, 6,241,194,108, 75, 91, 99,174, 91, 3,191,217,140, 1,191, 54, 69,192, 76, 50, 27,111, 13, 54, 73, 64, 9, 75,139, 82,
+155, 0, 43,169, 44,128, 9, 62, 93, 64,193, 61,206,129,152, 95, 41, 82,138,208, 22, 65, 72, 12,164, 32,165, 0, 36,148,163,152,
+144,217,234,147,145,223, 36,228, 96, 13, 93,159, 83,174,103,149, 32, 40,182,126, 55, 51,206,132,145,201,240,161, 7, 35, 62, 99,
+ 32,129,158,249,214, 55, 45,212, 37, 96, 41, 41,120,167,152, 0,148, 0,129,149,167, 39,148,225, 32,224,247, 61, 71,166,116,224,
+158, 91,109,185, 27,219,231,253,127,117,240,237, 35,179,146, 77,153,143,253,199,183,115,176,223,225,139, 75,238,163,147,144, 21,
+ 40, 96,142,116,142,164,165, 71,170,222, 82,187, 31,136, 4,140,243, 1,229,215, 88,252,183, 65, 72, 11, 82, 74,126, 16, 8, 28,
+184, 82, 72, 9, 66, 86,188, 18, 18,124,176, 62,100,224,157, 92, 39, 56,224, 82,146, 23,204,162,174, 95, 9, 9, 79, 55, 83,240,
+ 40,169, 64,252, 33, 36,252, 92,160,245,192,214, 45, 49,208,142,112, 21,241,171,170, 65, 78, 85,128, 50, 82, 74,129,229, 60,160,
+143,187,169,234, 53,176,135,175,112, 15,243, 31,187,175,201,195, 45, 82, 13,247,235,252, 62,255, 0,187,182,253,175,139, 84,247,
+ 82,160,163,130, 9, 39, 36,167,159,175,196, 10,138, 66,176, 19,215,191,145, 57, 25,215, 6, 61,188, 92, 35, 69,226, 19,132,201,
+ 91,199,110, 82,195,187,161,195, 10,102, 93,241, 28,140,192,126,125,115,105,170, 47, 48,214,226,219,142,184,128, 86,242, 33, 44,
+195,173,196, 64,207, 34,224, 76,242,116,235,186,178,222, 24, 37, 41, 81,237,144, 82,160, 20, 48, 84, 0, 3,162,199, 82, 58,245,
+ 31,127, 70,250,191, 79,164,215, 96, 84, 40, 85,216,173, 79,160,215, 96, 84, 40, 53,232, 14,182,151, 35,203,161,214, 98, 61, 73,
+173, 66,121,165,116,117,135,105,115,166, 54, 71,126, 85,224, 28,246,216, 14,203,105, 35, 63, 89, 25, 12,191, 17, 98, 47,238, 61,
+ 15,184,145,176, 59,197,243, 92,186, 44,214,138,175, 46,156,218, 42,180, 41,114, 7,145,137, 5, 36,183,172,110, 22, 65,210,229,
+109,238,199,229,128, 82, 2,137,239,143, 49,212, 31,152,199,126,154,248,172,145,219,166, 51,147,251,191, 13, 61,188, 74,237, 67,
+251, 7,196, 22,245,108,212,198, 21, 21, 91,103,185, 87,117,161, 21,133,168,173, 72,164, 83, 42,242, 5, 1, 65, 71,170,194,232,
+ 46, 83, 92, 10,235,144,230,114,115,146,198,169,106, 88, 4, 43,155,166, 71, 76,119,245, 30,186,153,211,202,179,197, 12,202,124,
+178,168, 97,235, 98, 1,254,120,230,119,142, 72,157,226,149,116, 75, 17, 42,227,209,212,233,101,251,152, 17,138, 46, 16, 70, 51,
+235,156, 28, 99,251,116, 42,177,142,195,148,103, 30,125,187,147,243,213,117,168, 30,224, 12,142,248,206, 79,217,161, 87,208, 31,
+ 60,156,126,255, 0,221,173,192, 44, 0,244,192, 29,190, 56, 29, 89,193,233,255, 0, 14,253, 52, 34,142,113,223,207,184, 3,240,
+209,107,237,223, 29, 71,231,243,233,161,156, 32, 2, 51,147,231,142,191, 62,154, 85, 7,124, 42, 44,119,192,171, 35,203, 63,126,
+113,231,228,117, 69,125,179,147,255, 0, 31, 93, 87, 95, 55,158, 49,229,249,245,208,235,199,207, 62, 94,159,126,149, 2,228, 99,
+ 29, 0, 3,231,255, 0, 24, 21,103,175,216, 49,159, 93, 45, 37,254,183,221,211, 75, 74,139,128, 0, 31,142, 13,143,168,198, 79,
+124,227,238,199, 79,219,162,145,140,118,235,230,113,251,254,205, 8,223, 83,147,145,208,244,251,241,215, 69, 35,177,235,231,219,
+247,232,141,107, 47,108, 12, 18,142,199,167,223,235,249,253,250,169,158,221,250,124,254,126, 94,154,164,140,245,233,211,215,247,
+124,245,237, 36, 40,144, 15, 99,131,223,161,210, 78, 54,248, 96, 99,223,140,142,249, 24, 0,103, 25,202, 78,139,108,149,129,212,
+ 0,124,241,215,168,233,211,239,253,154, 16,180, 1, 56, 0, 36,228,159, 79, 44,147,243,254,189, 86,109, 65, 36, 14,184,198, 2,
+143,203,212,253,218, 64,155,117,192,193,237, 39,151, 3,175, 66,123,119, 63, 63,144,209, 8, 95, 51,137, 73, 78, 57,115,241, 30,
+221, 60,178,126,122, 8, 60,140,148,130, 85,216,224,117, 87,159,124,253,167,240,209, 63, 11,137,248,186, 28,252, 35,168,207,219,
+248,233, 22,234,113,131,235,243,233,139,187, 64, 43,162,136, 63, 49,147,235,233,247,106,247, 70,169,212,104, 85, 90,117,110,145,
+ 41,200, 53, 90, 68,248,117, 58, 92,198,148, 80,236, 90,141, 62, 75, 82,225, 74,109, 67,170, 84,137, 44,180,175,184,141, 88,152,
+ 10,229, 79, 96, 48, 57,177,219, 35,167, 79,219,162,211,156, 40,118, 30, 71,184,249,245,242,233,162,144, 24, 21, 97,112,118, 32,
+239,132, 15,196,169, 30,155, 16, 71,112, 71, 67,137,193,240,233,185, 20, 62, 44,120,124,219, 61,240,167, 76, 71,191, 84,105,140,
+ 81, 55, 14,155, 5, 64, 73,165,223,148, 54,155,135, 89,139, 53, 8, 57,103,197,121,191, 25, 25,253,100, 72, 65, 4,131,173,161,
+180,210,245, 40,183, 10, 44, 52,248, 14,171,153,247, 36, 40,150,208,211,100, 16,181,171,201, 93, 7, 79, 83,168,161,123, 40,248,
+226,137,194,214,237,191, 97,110, 76,199, 6,196,111, 20,202,117, 42,239,113,106, 82,155,179,174, 82, 83, 18,135,123,178,146,127,
+ 69, 25, 42,113, 12, 78,199,254, 43,149,211,158, 67,169,140, 46,220,104,182,207,128,184,210,104, 79,178,197, 70,159, 80,128,226,
+ 36, 70,171, 65,146,132,189, 18, 92,121, 77,168,165,248,174, 52,182,212, 10, 73, 7,155, 84, 39, 16,240,233,203,115, 25, 99, 88,
+201,130, 67,170, 35,216,169, 61, 47,220,173,244,155,247,243, 17,102, 24,239,143, 11, 60, 80,110, 39,225,218, 88,107,103, 15,152,
+229,170,144,213, 33, 98, 60,234, 0, 89,236, 55, 34,117, 93, 98,219,115, 3,198, 8,209,135, 82,196,175,212,218,113,133,198, 84,
+117, 38, 71, 32, 67, 78,101, 4,182,142,157, 7,255, 0, 22,125,124,255, 0, 13,121,226,147, 97,169,220,100,236, 45,251,195,253,
+214, 96, 83, 89,184, 96, 55, 58,221,184,156, 71,138, 45,139,210,151,207, 34,220,169,161, 93,196,113, 36,248, 82,113,221,137, 11,
+244,198,172,116, 62,102,100,181, 29,160, 61,231,149, 60,142, 99,224,101,164,246, 3, 29,128, 25,233,173,128,164, 74, 18, 99,198,
+ 73,116,183, 25,181,114, 60,178, 57, 76,151, 16, 50,162,162, 14,124, 60,129,246,235, 82,158, 2,165,118,210,203, 98, 45,216,245,
+190,219, 94,253, 7,223,139, 66,108,214,122, 57,232,179, 76,177, 18,150,182,141,214,104,102,243, 49, 73, 35, 33,209,244,220,171,
+217,133,180,176,210,230,225,188,151,199,230,211,196, 86,208,238, 55, 15,155,153,121,237, 22,231, 81,100,219,215,221,143, 82,149,
+ 79,168, 71,125,106,110, 52,230, 88, 90,132,122,157, 46,106,128, 76,202,124,136,220,143, 71,121, 63, 11,141,186,146, 8, 36,141,
+107, 90,238,137,210, 99,242, 84,194, 39,208,228,243, 69,156,165,101, 50, 16,209, 35,156,184, 17,212, 56,158,138, 66,198, 72,229,
+ 26,253, 19,125,160,126,206, 29,169,246,133, 88,112,226,214,219,129,100,111, 5,191, 18, 68, 91, 19,116,219,132, 28,148,220, 38,
+208,181, 53, 65,186, 99,180, 66,170,182,233,119, 30, 25, 39,198,138, 86,165, 50,121, 74,144, 97, 29,196,223,179,219,138,238, 14,
+171, 85, 42, 30,238,109, 69,202,253,158,137,146, 26,165, 95,150,229, 61,202,229,149, 91,134,219,133, 41,155, 18,173, 13,165, 6,
+ 91, 82, 48,172, 57,202,180,231, 5, 26,179,178, 42,250, 57,225, 72,106,149, 86,169, 74,233, 44,116,220, 29,175, 27,118,123,216,
+133,216,130, 59,142,146,250,158, 42,173,226,215, 74,204,190,189,178,218,167,133,214,182,141,111, 32, 18,142,242, 68,219, 84,208,
+202,162, 69,119,250,199, 68, 58, 38, 17,181,158, 86, 98,205, 98,245,184,155,179,246,190,133,117, 81, 43,212, 69,205, 93,107,111,
+171,201,247,180,220, 22,125, 75,170,221,143, 77,172, 67, 70, 41, 51,212, 66,147,225, 62,180,195,146,121,152,117, 41, 82,145,153,
+ 39,123, 14, 56,116,186,118,163,136, 57,119,139, 91,231,181, 82,105,117, 56,211, 85,187, 59, 81, 50,174,154, 46,225, 86, 41,142,
+178,236, 71, 96, 81, 44, 39,154, 15, 79,169,138,138,154,146,169,140,169,198,154,240,202,146,121, 8,214,156,123, 19,246,162,147,
+184,219,245,181,214,173, 74,157,114, 91,212, 68, 94,177, 46, 9, 87,209,164, 82, 35,166,152,213, 40, 26,147,148,152, 53,249, 12,
+182,135,161, 77, 92,118,163,188,212,150,221, 87, 43,171, 72, 10, 95, 41,212,194,248,217,224, 59, 96,239,203,211,110,184,157,163,
+220,219,119,195,142,224,236,189, 90, 53,199,112,238,141,180,213, 54,131, 86,184,173, 90, 80,241,158,162,204,105,137, 44, 68,247,
+146,216,120, 38, 83,136, 82,185, 95, 91,106, 14, 36,132,105, 42,177, 85, 95, 69,196, 84,180,235, 13, 45, 13, 59, 8,229, 63, 84,
+100,153,228, 44,254,209,101,229, 8,180, 29, 45, 34, 57,120,102, 98,238, 84, 54,248,177,115, 46, 32,224,110, 24,171,225,142, 26,
+226,122,217,198,119,199, 25, 21, 76,116,245,242, 71, 93, 93, 67,144, 67, 83, 72,217,122,208,154, 38,146,170, 74,254,122,137, 97,
+203,171, 80,123,126, 86, 13, 50,114,230,134, 52, 43,104,160,110, 52,106,229, 82,239,218, 10,165,197, 42,143, 92,155,112, 63, 79,
+182,109,170,172, 86, 42, 53, 42,212, 72,110,166, 83, 17, 83, 38, 18,137,166,133, 50,164,172, 60, 85,240,145,228,123, 92,248,153,
+225, 90,117,139, 14,223,186,217,144,212,184,247, 13, 37,217,245,234, 50, 30, 68,154,188, 47,118, 5,245,153, 13, 36, 5, 84,225,
+248, 64, 45,114, 16,133, 4,120, 5,183,210,145,135, 23,170, 17,120,166,246,122,210,239, 8,251,245, 73,221, 42,108,202,125, 54,
+ 85,110, 12,136,116, 25,110, 42,164,252,181,186,183, 36, 84,100, 71,157,200,243,176,212,251, 97, 40,154,128, 27, 80, 87, 42, 0,
+ 73,215, 28,248,248,246,138,238,223, 31, 27,209,100, 13,189,190,175, 61,174,217, 13,133,184,168,247,110,220, 46,215,168, 72,182,
+ 43, 50,175, 26, 23,136,134,174, 58,133, 66, 41, 14,213, 96, 61,144,143,113,148, 85, 17,198,121,155,117,149,165, 68, 30, 78,240,
+151, 41,171,203,168,248,214,139,140,242,218,147, 61, 39, 46,146,154,176, 74, 94, 58,115, 70,238,237,110,102,210,194,237, 49, 74,
+101,167,176,152,106,242, 71,253,233, 17,120, 7,226,111,137,188, 85,195,180,126, 29,112,252,188, 55,150, 71, 72,245, 89,147,103,
+144, 54, 91, 11,230, 13, 18, 65,236,212,236,144, 84, 78,202,220,184,170, 37,144,199, 57,137, 21,156, 76,199,149, 3,245, 94,101,
+153, 14, 91, 11,118,106, 60, 38, 42, 50, 98,248, 52,232,255, 0,224, 76,210,169,176,210, 23, 58, 67, 75, 75,170,196,215, 65, 90,
+ 66,200, 82,134, 70, 57,121,122,190,116, 74, 93, 58,224,113, 52,104,137,117, 22,180, 38, 41,236, 84,166,201,117,250,127,189,196,
+138,202,165, 63, 77,135, 61,213, 5, 70,128,166,194, 12,199, 18,144,165,140,160, 16,130,179,166,155,101, 55,170,133,187,214,166,
+214,220, 55, 67, 20, 74, 22,231,223,150, 76, 91,182, 85,181, 1,133, 66,160,215,231,197,159, 82,164,204,170, 90, 80,221, 39,244,
+ 42,118,154,185, 47,211,155, 89,114, 42,164,175,221,144,228, 84, 39,195,216, 74,124, 72,107, 67,204, 60,133,205, 66,221, 76,153,
+140,248,200,105, 21,106,162,212,144,195,107,125, 39,244,116,228, 20,254,149, 32,124, 73, 74, 16, 82,160,149, 5, 73,200, 40,225,
+ 8, 33,133,138,157,182, 82, 3, 95, 73,181,137,216,116,212, 13,238,110, 49, 90,230,167, 55,225,188,207, 50,225,188,237,100,164,
+205,114, 10,186,138,102, 10, 67, 66,181, 20,181, 15, 75, 52,145, 56, 33,102, 11, 36, 14,177,206, 9, 14, 84, 59, 29,188,174, 84,
+ 59,173,112, 93,143, 85,131, 21,160,229,114, 44, 58, 45,153, 66, 12, 7, 27,139, 74, 91,136,101,170,139,205, 35,148, 83,216, 89,
+109, 47,175,160, 45,198, 97,150, 17,149, 40,129,153,191, 33,138, 45, 46, 76, 10,157, 73, 53,234,220,249, 45, 83,233,211, 28,109,
+ 44, 82,226, 34,114,131, 18, 43, 40,129, 31,153, 48, 97, 70, 47, 36,186,181,120,174, 58,242, 82,209, 95, 50,212, 18,208, 73, 83,
+ 80, 80,204,199,127,194, 85, 21,242, 79,187, 56,168,170,169,212,221,108, 50, 91,138,234,193,240,227,178,130, 24,101, 57,229,108,
+ 41, 75, 86, 74, 20, 9,139,172, 74,165, 58,245,126,172,220, 89,142, 26,131,177,226,196,130, 86,202, 30,125,154,122,189,198,155,
+ 17,167, 0, 8,166,198,149,239, 78, 60,238, 79,139,135, 31, 80, 75,139, 70,183,210, 72,208, 37,152, 14,131,107,157,246,216,129,
+183, 77,134,221,141,183, 54,195, 12,185,100, 85,145,194,212,139,125, 68,121, 69,150, 73, 36, 70, 28,168,213,141,221, 80, 38,242,
+239,121, 25,155,153,118, 55,137,194,174, 84, 41,148, 85,183, 64,162,120, 21, 9, 84,184, 49,145, 29, 46, 45, 79, 64,165, 64,110,
+ 50,132,154,165, 69,214,148, 82,194,220, 74,138,147, 28,101,231,150,232,192, 66, 9, 86,185, 17,237, 36,216, 24,156, 79,108, 45,
+ 91,106,157,145, 17,119,146,170, 52,251,163,110,235,115,214,150, 35,192,191,179, 38, 60, 55, 42, 47,160, 19, 2,219,168,211, 29,
+118,157, 56,164, 20, 50,202,227,203, 3,158, 10, 73,232,220,233,143,193,167,180,203, 82, 67,210, 37,192,145, 88,170, 20, 52,150,
+230, 54,253, 90,120,113, 41,119,149, 69, 38,115,235, 1, 12,182, 7,193, 25, 9, 82,185,130, 82,117,175,119,139, 85,218,217,157,
+245,121, 66, 42,143,213, 32,176,154,170,185, 28,143, 69, 75, 2,115,178,106, 74,141,250,175, 22, 25,108,248, 12, 35, 8, 91,142,
+ 54,181,252, 5,122, 88,213,203, 28,145, 75, 78,229, 37,167, 97, 34,183,236,148, 33,148,223, 96, 69,197,183,176, 63,102,214,216,
+ 58,240,190, 68,114,250,243,152, 23, 19,199, 8,114,242, 72, 72,231, 22,188,108,205,176,101,137,213,157,138,160, 37,149,131,121,
+245, 2, 96,171,183, 20,137,123, 31,191,149, 91, 47,123,232, 85, 27, 62, 93, 6,181, 34,220,190,237,155,214,132,186,220, 88,179,
+217,150,220, 71,128,149, 75,125,138,149,169, 90, 75,203, 96,211,110, 42, 91,143,176,165,184,194,229,195,126, 59,201,121, 83,127,
+216,175,102,198,192,241,189,192, 78,211, 93,151,173, 66,131, 11,121,110, 27,122,109, 78,202,226,103,134,152,244,170, 29,255, 0,
+106, 75, 77, 80,127, 7,147,118,200,183,170, 81,169, 27,137,124, 65,102, 20, 38,171, 53, 4, 24,110,205,241, 18,226,164,123,227,
+ 13,202,211, 37,186,124, 33,108, 79, 16, 66,211,103,113,182,182,139,118, 84,173, 7,156,166,216,183, 99,192, 67,187, 32,202, 95,
+ 52,202,236,231,238, 88,201, 46,213,173,214,193, 83,203,133, 49, 50, 99,173,245,243, 52,203, 11,115,159, 93, 2,225, 42,126,233,
+240,185,105, 84,108, 74, 45, 95,108, 43, 59, 35, 69, 97,250,141, 10,138,230,217, 90,251, 48,139, 9,233, 47,173, 83,167, 92, 23,
+133,177, 85, 69, 46,182,212,244, 48,183, 86,228,216,112,223, 43,138, 95,241, 29,230,228, 19,170, 78, 41,201,115, 12,218,154,183,
+ 54,203,228, 66,244,207, 79, 57, 83,174, 48,118,211, 36,113,139, 51,236,182,144,200,197,209, 89, 4, 74, 66, 18,100,220, 71,196,
+ 25,253, 47,135,176,101, 60, 41,197, 99, 32,207,114, 92,228,102, 52,138,194,116,168,154, 25, 34,146, 41,169,214,165, 68,180,176,
+199, 36,210, 6,122, 3, 28, 20,213, 45, 28,143, 83, 37, 84,238, 34,143, 74,120, 89,225,111,121,247,111,121,238, 89,155,225,184,
+220, 82,237,142,251,112,146,253, 17,207,229,239, 14,200,188, 40,150,199, 16, 91, 53,100,203,106,223,161,219, 59,177,105,238, 28,
+ 8,141,191,184, 84,122,123,188,237, 86, 66, 93,102,187, 65,135, 61,155,146,157, 54, 68,117, 85,170, 29, 5,246,132,237, 76,171,
+ 94,215,181, 54,235,103,182,227, 99,237,219, 50,147,100,221,151,117,186,253, 38,155, 38,143,114, 90, 87, 4,106,212, 53,220,242,
+118,242,194,180,160,179, 75,166, 81, 39, 84,235,112, 68,217,140, 61,226, 50,212,247, 22, 89,118, 35, 77,235, 83,184,202,246,199,
+112,111, 70,219,122,181, 6,171,108, 65,226,231,125,105,213,122,204, 75, 11,108,236, 27,130,252,141,176,118,155, 98, 2, 33,193,
+175,238,213,251, 13, 81, 98,223, 52,197,206, 75,206,187, 71,165, 38,170,196,168,241,155,138, 85, 9,111, 46, 98, 52, 47,111,189,
+188,183, 37,209,109, 10,103, 17, 22, 2,110,109,194,146,227,138,131,118,219,246,163,116, 11, 98,132,235,103, 52,122, 75,118,253,
+157, 38, 77, 80, 90, 17,210,101,178,248,116,206,118, 75, 83,212, 28,101,175, 1,149,162, 45,226,190, 70,185,231, 0,203,149,228,
+121,123,231,153,198,105, 91, 28,230, 88, 16, 36,112,211, 70,154,212, 24, 39,149,165, 18, 74,198, 72, 89, 35,105,100, 12, 41,231,
+158,112, 57,145,137,231, 10,100, 94, 51,241, 87, 23,112,111, 30,211,112, 52,153, 38, 73,225,242, 10, 90,124,155, 50,146, 42,116,
+ 99, 45, 52,112,243,178,218,153, 12, 21, 85, 52,171, 42,205, 88,212,181,201, 75,149,209, 37, 91, 81,100,148, 51, 81, 75, 49, 50,
+ 6,217,173,183,155,188, 84,118,173,158, 32,172,235, 87,118, 54,166,179,183,149,203,134,222,225,242, 30,215, 80,233, 54,151,241,
+165,100,213,106,245,122,156,138,221,227, 2,160,150, 46, 42,164,235,130,161, 57, 86,251,132, 51, 77,169, 64,173,174,167, 38, 59,
+ 85, 4, 56, 26, 3,109,118,123,135, 41,252, 96,110,135, 23,245,109,254,221,189,165,168,219,173, 91,123, 97, 87,216,251,190,175,
+183,219, 85, 99,219,212,155,126,209,183,217,137,183, 10,131, 66,169, 76,169,205,176,225, 70,165,194, 83,180,116,125, 88,219,175,
+148,178,243,175,199, 75,173, 59, 29, 61,249,246,206,238, 94,228,237, 61,211,181,155,117, 97, 50,205, 62,247,110,151, 14,183,114,
+ 57, 71,149,102, 55,111,211, 40,145,161,125, 74,213, 25, 54,141,222,227,180,202,188,130,169, 82, 23, 30,151, 57,136, 16,218, 83,
+108, 72, 50, 38, 25, 64,114, 67,110, 47,253,229,176,174, 10,205,199,103,238,253,237, 99, 85,238,119,154,122,231,157, 75,174,215,
+ 74,238, 7, 25, 46,152,207,214,220,157, 58, 73,170, 74,109, 18, 30, 75,110,190, 29,121,180, 44,165, 42, 9,232, 21,240,162,151,
+ 56,225, 46, 16,143, 36,205,178, 88,214,186,130,176,206,181, 50,212,206, 37,168,141, 97,228, 37, 63, 46, 9,201, 90, 37, 96,103,
+142, 25,155, 74,243, 26,157, 97,150, 33,237, 83,203,114,127,162,199,141,220, 86,188, 75, 85,151,241,125, 31, 2,167, 23,193, 83,
+150, 54, 91, 79, 78,166,152,101, 85,109, 75, 81, 85, 61, 59, 60, 98,150,158,166,174,122, 58, 72, 42,106,150,136,102, 51,123, 10,
+ 85,205,152, 73, 43, 44, 16,206,123,218, 61,196,127, 12, 59,235,177, 53, 46, 29,169, 86,189, 55,136,234,109,215, 88,166, 26,197,
+ 38, 53,233,116,109,198,223, 91,198,222, 80,171,209,234,119, 5,221, 67,164, 25,151, 10, 5, 85,136, 33,154, 93, 49, 37, 18, 15,
+233,100,202, 97,150,139,131,132,251, 87,179,251, 79,179,194,224,147,101,216,244,202, 5, 90,229,159, 17,119,149,211, 72,110, 69,
+ 46,248,110,163, 29,217, 43,129, 66,171, 79,122,116,167, 35, 90, 76, 72,147, 37,216,236, 37,215, 98,203,117,126,245, 45, 50,100,
+114,186,222,133,219, 60, 77,113, 16,220,102, 29,123,136, 11,214,170, 86,194,217,230,148,229, 46, 98, 20,211,128,115, 50,125,254,
+146,190,100,228,116,200, 4, 30,163, 7,187,151, 72,226,234,249,165, 72,105,119,173, 54,145,119,199, 91,105,138, 42,209,169,240,
+173,203,214, 44,100,188,211,178, 16,205,110,152,208,135,112, 48,176,215,197, 10,171, 13,109,124, 69,109,200, 97, 95, 24,214,226,
+126, 46,204,248,131, 53,169,253, 34,207, 26, 53,144, 71, 4, 79, 21, 56, 17,133, 22,229,150,231, 57, 26, 1, 47, 34,187, 2, 44,
+ 52,198,170,139, 50,202,126,130,126, 47,120,111,192,109,194,252, 57,154,229,220, 65,148, 9,205,116,180,137,154,214, 10,186,170,
+162, 10,137,109, 91, 69, 71,150,198,235, 25, 10, 22, 25,169,163,100, 69,105,125,166,116, 70,126,237,240,173,188,242,233, 18,100,
+237, 93,235, 42, 60,202,109,114, 92,138,190,220,221,209,196,104,148,181, 76, 74, 16,170,157,149, 92,105,110,132,210, 43,242, 74,
+ 19, 42,158,164,115,198,158,234, 36, 48,143, 6, 66,144,210,247,177, 85,202,124, 85, 41, 50, 23,238,234, 96,171,220, 84,131,201,
+ 81,167,186,242, 66,220,103,194,112,116,136,167, 49,204,218,135, 38,114,149, 36,142, 82,142, 24,109,205,249,100,111,109,188,154,
+141,169, 87,121,132, 69,149, 25,154,133, 12, 70,102, 35,244,170,162,202,228,211,227,215,160,171,156, 70, 90,220,109,197,198,112,
+ 60, 25,150,134, 86, 98, 60,242,193, 74, 54, 70, 21,203,185,137, 49, 41,209, 55, 38,242,181,228,211, 26, 17,157,129, 46,114, 42,
+180,121, 76,135,128,240,207,214,112,156,148,134, 86, 18, 75, 79, 49, 33, 50,163,165,120,248,146, 57, 73,105,106,159,147, 26, 7,
+ 37, 20,121, 74,249,129, 29,199, 81,176, 38,192,147,176,176, 11,229, 39, 28,113,196, 92, 57, 81,148,103, 21,249,110,121, 69, 46,
+ 69,155, 81,200,201, 87, 73, 60,114, 67, 44, 19, 46,155,235,139, 65,117, 46,165, 73, 11, 30,131,175, 80,250,185, 64,199, 74,170,
+247,117,187,111, 83,215, 94,171,203,137, 65,135, 79, 67,143,174,161,207, 41, 13, 62,140, 15, 16, 83, 24,105,167, 37, 84, 28, 81,
+ 82,130,227, 69,105,245, 45, 71, 41, 66,191, 91, 76,133, 87,124,171,187,130, 29,167,217, 76,213,237,251,106, 66,189,205,119,162,
+ 28, 98, 37,199, 86,142, 16,162,185, 54,235, 12, 41,106,181,161,242, 45, 99,199,119,154,162, 48, 80, 81, 16,158,154,182,205, 62,
+117, 86,178,221, 66,238,151, 81,166,214,156, 82,227, 66,168, 73,171, 77,171,198,152, 82,188,180,236, 27,145,222, 95,115, 36,148,
+242, 70, 81,136,160, 29, 56, 67,138, 29, 54, 42,202,179,153,139, 37,154,143, 44,138, 93, 90,115, 13,179, 42, 84, 55, 84,228, 58,
+130,154, 32,177, 34,167, 76,116,248, 83,164,158, 85, 21, 58, 66, 29,194,202, 84,242,134, 53,191, 74, 37,168,148, 34, 92,139,239,
+126,187,219,125,133,150,228,146, 47, 98, 55,179, 1,136, 86,103, 62, 91, 69, 8, 36,153,106, 8, 60,182,111, 58, 40,216,157, 54,
+ 98, 36, 0,234,243,171, 58, 3,101,229,106,179, 43,139,104, 91, 70, 44,120,176,217, 45, 59, 21,146,164, 50,232, 71, 43,133,111,
+117, 90,230,100,144,252,149, 40,149, 41,210, 74,150,181, 21, 44,149,171, 39, 97,160,209,196, 74, 98,138,211,204, 1,101, 39, 41,
+232,160, 84, 80, 91, 86,122, 5,117,207,217,171, 93,167, 74,230,109,190,118,227,151, 50, 18, 67, 73, 80,101,207,212, 10, 45,182,
+190,169, 65, 32, 16, 14, 72, 61, 50,113,157, 59,206,211,128,167,184,215,134, 84,218,139, 67, 9,202,136, 9, 81,207,134, 79,235,
+ 28, 17,243,252,113,169,165, 53, 56,166, 68,176, 35, 72, 23,245, 29, 5,183,191, 78,155,254, 24,174,234,171, 13, 76,138,146,157,
+228,111, 49,216, 94,228,111,219,173,201, 22,181,250,250,130,207, 61, 76, 83, 78,129,201,136,206, 30,102,214, 63,241, 74, 61,219,
+ 81,242, 79, 81,141, 92, 33, 83, 11, 11, 43, 74, 70, 79,235,128, 48,146,159, 95,183, 89,187, 48, 16,248,113,190, 78,100,130, 82,
+160,176, 65, 32, 28, 5, 99,215,168,252, 53, 65,216,162, 34,146,199,235, 39, 31, 2,200,193,233,215,144,231, 79, 81,206,164,117,
+233,252,125,253,240,213, 89,206, 82,241,176,243, 14,190,132,117, 7,227,110,189,143, 94,183,197,134,155, 9, 14, 77, 73, 35,160,
+115, 31,105,236,123,140,118,214,207,217,208, 91, 67, 45, 2, 19,212, 36, 12, 14,163,212,156,142,135,247,233,135,163, 69, 10,155,
+158, 95,135,196,200, 0,103, 57,200,252,115,173,138,183, 84,150, 18,214, 79, 47, 42, 82, 64,200,200,192, 25, 63, 34, 51,173,102,
+107,129,181,255, 0,158, 33, 53,234,201, 4,224,108,194,246,251,207,207,175,124, 57,232,109,180, 51,202, 72,248,130,113,142,248,
+ 78, 0, 31, 35,235,246,233,191,188, 42,206, 66,108,193,167,132,253,103, 41,181, 0, 71,255, 0, 2,140,174,134, 73, 35,245, 92,
+ 39, 33, 30,121,235,229,171,141, 90,228,106, 11, 32, 52, 80,236,183, 73, 12, 70, 4,229, 74, 7, 30, 43,152, 63, 3, 41, 29, 84,
+123, 28,224,100,235, 5, 13,173,197, 57, 46, 67,138,125,249, 46,120,146, 95, 88,253,117,156, 97, 40, 39,245, 91, 0,225, 35,176,
+ 29,180,142,179, 80,220,168,205,149,126,211, 15,223,164, 16,122,250,158,195,208,145,134,108,155, 45,116,149,107,106,210,241, 41,
+186,161,255, 0,120,194,221, 71,236, 47,127,218, 35, 79, 77, 86,176, 66,163, 8,205,225,197, 43, 56, 37,105, 65, 56, 36,252, 75,
+ 82,212,174,171,112,149, 28,156,245,207, 93, 15, 45,216,241, 57,146, 57, 27, 56,200, 72,192, 89, 78, 15, 85,168,159,128, 99, 39,
+226, 63, 33,223, 89, 20,167,114,130, 10,130, 80, 72,248, 26, 31, 30, 65, 0, 16,165, 3,208,231,174, 61, 61, 53,129,212,188, 52,
+ 7, 20, 82,214, 78, 74,148,226,186,164,228, 18, 84,181,103, 36,244,238,122, 30,157, 53,185, 26, 44,106,170,160, 1,238,236, 54,
+253,214,249,247,206,169,100,122,153, 25,234, 36,251, 71,160,233,212,122,216,124,236,119,197,146,116,196, 43,156, 23, 20,234,176,
+ 66, 83, 24, 44, 50, 18, 79, 66,235,132,167,159, 61, 50, 50, 18, 9,206, 15, 83,172, 58,116,165, 37, 64, 4,182,218, 73,199, 59,
+139, 10, 82, 73, 66,186, 33, 13, 30, 94, 96,174,108,228,231,168,198,123,139,140,202,131, 79, 30, 70,148,227,238, 33, 74, 65,102,
+ 43, 97,196, 54,147,211,226, 81, 41, 74,129, 0,103,226, 56,236, 70, 51,172, 78,114,228,243, 5, 43,193,100,115,243, 36,120,134,
+ 75,201,194,128, 42, 71, 54, 17,204, 60,206, 74,114,122, 18,116,112,214,210, 59,223,241,219,240,190,226,251,116,251,158,201,176,
+ 10, 23, 73, 61,143, 95,141,182, 61, 58, 16,167,226,118,197, 23,220, 24, 42, 82,202,147,250, 50,234,130,146,217, 45, 36,168,133,
+ 45, 94, 71,175,197,215,174, 49,223,174,177,233, 50,208, 66,131,105, 61,214, 66, 64, 78,114, 64, 32,244, 61, 27, 42, 36,100, 30,
+ 80, 0, 29,250,232,185,104, 66, 49, 33,199, 21,150,220, 43, 66,158, 90,158, 9, 94, 72,229, 74, 84,180,165, 36,173, 63,234,146,
+156,146, 6,173,114, 20, 80,180,165, 72, 80,112, 20,145,206,164, 41, 92,139, 1, 96,182,144,172, 56,130, 20, 14, 50, 0, 39, 56,
+233,141, 46,141, 98, 54,244,254, 95, 29,247,198,133, 76, 90,206,166, 58,175,233,178,237, 97,238,254, 93,189,215,178,204, 42, 33,
+ 93, 64, 42,248,136, 81, 57,235,147,209, 95,205, 61, 51,156,117,229,239,140,107, 16,158, 7, 42,147,206, 74,138, 85,241,171,148,
+ 17,140, 96,145,216, 96, 12,125,253, 6,178,233, 89, 1, 42, 89, 0,224,140, 40, 16,146,179,204,164, 55,201,216, 60,158,153, 29,
+114, 59,100,118,197,106, 10,207, 40, 35,170, 73,230, 36,114,149,103,155,161, 9, 87, 86,241,147,231,213, 88,193, 58, 92, 49,218,
+223,135,110,159,187,221,238,253,216,103,145, 0, 34,219,123,186,124,143,147,136, 13,251,114,237,134,237,143,105, 46,242, 73, 13,
+ 22,133,233,109,109,125,248,227,197, 1, 40,126, 69,118,199,166,197,148,182,249, 0,241, 0,122,146,174,101, 31,136,168,158, 98,
+ 78,117,200,194,180,168,126,137,101, 88,239,233,246,107,183,127, 72, 24,180,175,104, 99,158, 27,161,215, 19,195,254,205, 37,246,
+129,255, 0, 34,180,195,184,124, 52,148, 17,150,202,152, 45,175,169,201, 11, 7, 0, 99, 92, 70, 83,105,199, 81,140,246,229,242,
+249, 29, 75,178,155,181, 13, 41, 59,217,109,211,176, 36,116,235,219,242,199, 51,241, 50, 44,124, 69,158, 34,159, 47,181,212, 31,
+255, 0,116,172,199,247, 18,113, 76,168, 40,116, 72, 29, 62, 47, 63,188,117,208,235, 35, 24,207, 92,244,254,221, 86, 40, 35, 62,
+152,207, 95,232,251,116, 51,133, 67,168, 78, 71, 81,243,251,244,236, 6,194,221, 48,206,160, 29,173,211,161,253,216,162,179,229,
+143,191,211,175,217,170, 11, 0,227,176,245,245,199,175,207,160, 58,244,188,254,177,201, 82,124,188,177,231,246, 29, 81, 39, 39,
+ 58, 93, 70,194,221, 63,158, 20, 24,164,230, 60,136,232, 72,244, 39,183,109, 12,178, 9, 61,242, 59,122, 30,223,214,116, 74,241,
+130, 73, 3, 7,167,246,245,213,189,240,234,136,240,212,148, 97, 95, 22, 70, 74,128,236, 58,249,233, 68,235,140, 3,126,155,227,
+193, 36,156,254,113,165,175, 10, 63,237, 99,238,206,116,180,125, 62,182,191,207,191, 25,199,180,146, 15, 65,159,151,174,171,165,
+ 93,142, 58,142,227, 61, 70,135, 31,120,254,145,251,117, 92, 96,245, 30,127, 46,250, 37,188,191, 15,195,231,231,124, 12, 86,241,
+ 19,156,117,235,231,142,159,126,136,111, 10,193, 74,187, 28, 99, 24,201, 62,191,136,252, 53, 65, 9, 0,131,220,244,251, 58,232,
+164,225, 61,178, 7, 94,221,254,236,246,210, 76, 24,139,124,252,223, 25,219,239,197, 69,160,168,119,233,221, 93, 78, 6, 49,216,
+125,186, 33,164,115, 36, 40,247, 29, 66, 71,160,233,235,170, 64,133, 15,207,113,215, 69, 36,242,224,244,244, 35,208,105, 34, 0,
+ 39,190, 49,143,104,101, 42,238, 57, 85,215,168,198, 72,251,188,244,123,104, 72, 72, 24,201, 79, 78,191,187,166,132, 65, 39,226,
+ 72, 25,244, 39,167,152,251,180, 90, 22,144, 1, 87,195,147,231,252,236,250,124,244,153, 23,216,158,159,233,140, 17,124, 28,214,
+ 58,114,244, 24, 61, 62, 93,191,167, 70, 32, 12,103, 39,230, 60,137,199, 94,154, 13,178, 23,215,168, 29,253, 59, 99,250,245, 93,
+ 11, 73, 95, 47,114, 62,127,102,127,103,150,147,194, 39,221,190, 13,108,129,145,140,228, 16,160, 70, 82,164,158,133, 36,121,130,
+ 9,200,212,133,253,149, 30,214, 40,187, 66,197,191,195, 39, 20,245,169, 15,236,235,143,162, 14,220,110,140,213,189, 54,163,181,
+211,100,184, 17, 30,135,114, 58,162,165,203,177,148,226,240,211,164,149, 65,206, 21,150, 70, 83, 30,118,242, 14,122,121,126,206,
+218, 33, 39, 37, 68,227,168,229, 32,128, 82, 65,232, 65, 7,184, 56,237,231,157, 55,102, 89,109, 54,103, 78,208, 84, 37,251,171,
+ 11,106, 86,236, 71,240, 32,236, 71, 81,211, 14,249, 22,123,153,112,230, 99, 22,103,149,205,202,158, 63, 43, 43, 92,199, 44,100,
+130,209, 74,160,141, 72,214, 29,195, 41, 1,144,171, 0, 71,233,189, 78,163,199,149, 6, 5,118,137, 50,159, 88,161, 86, 97,179,
+ 50,145,112,209,228,179, 81,164,214, 32,202, 66, 93,106,101, 62,161, 25, 74,109,214,150,210,146, 82, 66,186,115,105,198,165,210,
+220, 45, 54,156, 0,210, 18,130, 16,156,144,132,160,130,113,234,163,215, 63,102,191, 63,142, 13, 61,168,188, 90,112, 88, 35, 91,
+187,121,119,179,119,109,106,165, 54,185,123, 83,184, 1,218,213,172,195, 74,112, 25, 31,193,231,222,112,191,110, 58,164, 21,224,
+ 48,176,215, 49, 7,195,198,117, 59, 45,161,226,130,149,124,109,157,131,126, 59,105, 34, 25,190,109, 42, 53,196,184,241, 30, 15,
+198,138,237, 78, 35, 82, 31,140,211,167,245,219, 66,220, 41, 7,190, 19,170,167, 56,203,165,200,101,140, 85,149,104,230,213,203,
+101,189,155, 78,155,220,117, 82, 3, 46,198,227,123, 43,181,137,199, 98,248,121,226, 4, 60,107, 28,144, 81,211, 52, 25,134, 94,
+168,243,195, 33, 13,165, 88,233, 15, 20,151, 2, 68,212, 8, 23, 84,117,184,212,128, 27,157,174,166,211,138,218,110, 68,166,202,
+ 12,226,136,177,129,232,166,216, 72,248,148, 83,159,213, 41, 3, 58,199,247,101,136,115, 44,202,189,191, 58, 53, 62,165, 75,147,
+ 13,232,255, 0, 85, 84,225, 70,168,193,124, 22,212, 1, 92, 57,109,173, 42, 25,207, 92,107, 7, 94,247, 82,222, 44,120, 49, 37,
+ 54,166,153, 62, 27, 97,162,180,183,147,212, 19,228,122,244,251, 53,166, 60, 82,241,139, 69,219,203, 98, 69, 54,140,180, 86,247,
+ 30,234,150,139, 66,201,183, 25,149, 29,233,234,185, 42,196, 70,134,169,113,219, 89,247, 70,154, 91,161,107, 46,114,242,132,100,
+244,206,153,205, 97,168, 2,158, 4, 44,100,219,125,135, 64, 78,228,219,222, 73,244,222,221,174, 76,131, 35,204,179,124,218,130,
+135, 45,164, 51, 85,202,227, 76,106, 62,206,255, 0,109,219,126, 90, 70,190,103,145,136, 84, 93, 78, 72, 23,191, 48,247,123,113,
+ 54,107, 98,106,146,105, 9,180, 41, 21,123,162,141, 80,151, 62,153,110, 91,228, 81,105,212,218,178,156,241, 34, 77,169, 72,130,
+226, 75, 2, 57,229, 90, 91, 71, 95, 19, 25, 61, 49,174,102,239,183, 16, 27,245,196,245, 64, 82,110,171,182,181, 46,217, 96, 6,
+ 35,218,212,137, 51, 32,219,108,198,105, 92,201, 85, 69,199, 30, 6,166,164,128, 10,220,112,144, 72,251, 53,214,202, 31,178,178,
+163,118, 58,154,214,227,110,196,250,141,229, 94, 90,234,215, 82,232,240, 89,168, 70,166, 84,170, 4,190,168, 41,121,249, 0, 76,
+ 90, 29,119,151, 56, 9,248, 73, 25,214,146,202,219, 91, 51,104,184,161,111,104, 55, 2,101, 83,114, 54,198,194,191,169, 77,110,
+ 68,221,177,164, 63, 85,175,214,237, 88,241,211, 82,147, 76,141, 78,128, 22, 91, 87,142,150, 98,205, 74, 85,132,248,171,248,142,
+ 53,173,150, 83, 84, 83,203, 81, 44,142,139,160, 27, 2,160,233, 3,114,117, 16, 12,141,127, 70, 80, 9, 35,125,241,233,239,130,
+ 41,224, 38,103, 13,117, 54, 67,153,205,226, 87, 28,112,190, 95, 45,125, 92,210, 83, 86,187,242,226, 42,178,174, 80,149,113,165,
+ 44, 65,229,100,134, 4,141,150,122,141, 81, 51, 73,162,237, 30,168,196,225,210,109,131,180,183,158,251, 93,182,173, 90, 77,131,
+ 96, 89,181, 75,242,173, 86, 98, 49,102, 9,183, 41, 18, 99, 82,213, 61,169,147, 28,108, 26,115,213,233,208, 41,241,139, 73, 89,
+155, 50, 88, 98, 57, 82,144,225, 71, 44,173,110, 47,174,107,174,254, 98, 13, 58,249, 85, 6,131, 87,171, 39,220, 44,241,181,244,
+153,180,166, 32, 5,149,154,122, 42,162,227, 19, 75,165,128, 71,188, 56,178,174,115,204, 82,145,128, 36, 3,237,235,223,234,222,
+215,112, 55,182,219, 31, 86, 98, 61,181,187,220,112, 95,208,183,126,253,180, 97, 54,220, 21,109,191, 13,155, 89, 33,113, 54, 95,
+106,218,165, 50, 18, 40,148,150,231,154,107,198, 55, 42, 67,242, 41,179, 93,113, 42,113, 74, 86,162, 97,177, 48,209, 39,113,161,
+ 58, 64, 13,211,225, 75,148, 51,140, 36,165,190, 84,143,159, 65,171, 75,135,178,168,107,242, 90,172,214,180, 51, 59,234, 16,134,
+ 17,190,133, 64, 20, 55,158, 54, 2, 70,146,225,136, 0,174,157, 43, 97,185,243, 63,233, 63,244,231,241, 66,159,196,102,225, 15,
+ 14, 51, 37,224,188,143,132, 9,142,161,114,156,207, 55,165,122,154,211,180,201, 83, 95,148,230, 89,116,181,212,212,192, 8,224,
+ 5,150, 25,142,186,190, 84,124,245,138, 25,117,109,141,230,157,201,225, 47, 99,174,184,147, 81, 37,251, 42,185,185, 27,109,239,
+116,234,109, 66,219,122, 4,155, 82,247,170, 85, 97,120, 77, 63, 82,121,198, 42, 45, 83,110,106, 65,247,182, 36,165, 14,184,226,
+150,194, 25, 9,113, 3,110,182,151,139,125,212,183,132,104, 23,139,113, 55, 18,137, 24, 33, 42,171,202,150,138, 77,231, 10, 58,
+ 80,148, 41,215,106,105,101,113,238, 23, 2, 0,109, 6, 99, 41,127,224, 0,190, 84,115,174, 89,251, 50,110,182,111,109,161,226,
+ 3,101, 36, 58,211,149,138, 21, 94,218,222,203, 78, 35,202, 81, 46, 82,231,199, 69,129,126,193,167,180, 63, 93,214,103,194,179,
+170, 50, 48, 15, 42,103, 21,168, 17,147,174,130,217,182, 49, 51,154, 91,177,188,102,144,164, 58, 35,144,191,242,169, 25, 99,159,
+148,124, 72, 7,226,207, 80, 49,207,131,216, 83, 92, 69, 69, 29, 6, 99, 95, 73, 34,235, 8,250,148,236, 9, 14, 17,197,138,133,
+ 2,215,210,116,217,110,164, 91, 97,105,119,134, 62, 33,208,248,151,225,118, 89,196, 28, 81, 28, 85,249,213, 91,213,189, 89, 99,
+ 36,143,237,143, 83, 41,169,117,146, 89,165,169, 6,105,139, 75,170, 73,228,145,245,134,150, 73, 9, 44,122, 97,110,111,221,149,
+120, 67,165,189, 58,161, 34,214,201,105,134,233, 55,148, 69, 83, 11, 50,221, 90, 92, 68, 40,213, 72,110,200,135, 46, 73, 41,108,
+171, 14,167,245, 84,130, 65,200,211,166, 94,171, 84,102, 51, 47,194,143, 89,131, 9, 5,184,240,105, 85, 40,147,218, 74,222, 40,
+ 89, 97,227, 2, 67,137, 97, 78,252, 5,254,110, 85,114,132, 39, 9, 72, 32,233, 93, 14,201,122, 65,143, 22,156,212, 69, 86,100,
+ 46, 44,135, 38, 57,135, 33,219,180,231, 22,234, 83, 60,161,192, 10,170,170, 8,144, 33,178, 71,233, 29, 30,242,191,208,181,133,
+191,182,125,129, 22,137, 24,184,219, 16,105,244,122,116,229, 24,172,196,140,227, 51,106, 82, 37,172, 0, 92,153,226, 37,249,213,
+ 57, 83, 22,165, 18,225, 82,222,113, 69, 74, 9, 71,234, 68, 9,208,198,209, 94,219,218,228, 15, 83,112, 65,184, 62,227,110,189,
+109,178,169, 62, 83, 5,218,149,249, 37,181, 42,198, 87, 89, 80,199,253,217, 86, 70, 70, 98,204, 20,146, 89,197,201,101, 22,230,
+ 59,242, 41,215, 69, 77, 73,128,236, 67, 18, 58,167,154,138,231, 60, 4,102,158,150, 80, 82,130,218,157,115, 45,198,101,174, 84,
+165, 1, 68,114, 52,130,156, 99, 89, 45, 34,212,134,228, 73, 16,146,227,205,181, 1,201, 78, 77,171, 38, 42,218,143,227,144, 4,
+201, 12,201,115, 36, 71, 12, 32,165, 43, 3,226,248,212,144, 10,146, 53,126,180,172,233, 73,154,154,212,168,202, 93,197, 80, 97,
+136,104,140,211,242,100,192,162,196,109,194,166, 41,208,221,148,163,201,135, 23,227, 62,232, 78, 95,127, 36, 0,218, 27, 1,238,
+160, 90,138,170,136,112, 34,196,122,116, 24,179, 26, 97,224,201, 66,151, 91,158, 22,121, 26, 8,112, 2,184,136,155,133, 28, 30,
+ 89, 15, 32, 1,204,132,117,220,138, 25,100, 69,141, 33, 42, 95,185,185, 36,108, 64,216, 41, 3,125, 76,119, 96, 54,234,214, 58,
+ 53,249,220, 11, 78,232,142,144,194,128, 23,101, 1, 6,175,214, 62,103,112,219,249, 82,197, 84,238,108, 17,110, 52,139,118, 47,
+ 29,184,225,215,110, 42,187,173,184,204,207, 72, 80, 85,167,183,182, 36, 9,173, 70,184,111,106,192, 66,170,116,219,106,146,227,
+200, 80,164, 50,235, 10, 77, 66,191, 84,117, 10,106,153, 79,228, 73,241, 36,174, 36,119,184, 21,190, 59,243,185,156, 69, 84,159,
+170,238, 77,125,233,212, 64,224,114,153, 96, 80,157,149, 74,219, 91,113,168,200, 9,139, 79,161,218,173,191,225,204,247,118,130,
+ 18,103,207, 18,106, 18, 92, 10,125,231,194,214, 80,151,139,218, 61,196, 11, 91,199,196,197,237, 22,149, 81, 84,157,189,217,229,
+191,180,182, 2, 88, 11, 17,100, 68,160,212, 84,221,239,112,178,210, 9,241,102,214,111,225, 52,151, 48, 84,168,148,168, 76,161,
+ 74,109,180,160,115,231,137,235,103,118, 56,127,147,104,217, 55,156,251,107,111,175,235,178,220,141,117, 86,109, 75,154,123,113,
+238, 29,183,163, 87, 2, 87,106,211,239, 74, 50,150,145, 64,189,234,148,231, 29,158,154, 36,149,174,165, 75,167,166, 52,138,188,
+ 24,138,159, 21,133,236, 83,112,252,185,180,169, 8,169, 20,176,234, 0, 18, 88, 7,176, 39, 89,211,114,119, 4, 70,189, 44,161,
+148, 22,190,159, 75,188, 43,225,207, 12,190,140,158, 22,229, 62, 49,120,177, 11,207,199,124, 79, 74, 43, 96,166,138,138, 92,199,
+ 54,166,167,120, 99,153, 50,252,166,134, 37,121,162,150, 40, 36,137,243,154,231,228, 65, 75, 44,172,185,141,117, 61, 12, 49,202,
+ 64,184,109,119,103,132,181, 74,129, 79,134,194,135, 43,190,237, 21,191, 29,100, 96, 37, 40,117, 73, 82, 99, 35, 32,124, 88, 42,
+ 63,170, 53,226,221,219, 54,154,144,210,159,144,184,110,188,191, 9,111, 50,130,176,158,110, 80, 84,251,171,202,128, 1, 93, 73,
+229, 25, 56, 37, 0,140,233,155,215,238,236,178, 81,245, 6,230,196,184, 38, 72,117,114,146,204, 10,157, 18,124,222, 68, 55,238,
+229, 13,192, 85, 62, 51,171,139,134,207, 35, 41,140,233,231,202,146,147,144,117, 96,166,239,230,251, 91, 78,170, 52,187,154,100,
+238, 69,175,198,143, 95,161, 83,106, 18,154,101, 79,165,231,152,117,164, 67,133, 45,134,212, 82, 91,194,156, 5, 45, 44,164, 2,
+ 66, 84,155, 34,147,133,243, 36,165, 20,116,217,188, 35,151,238,126, 97, 4,254,177,125, 68,239,211, 82,223,173,172, 0, 24,167,
+179, 47,246,170,125, 30,232,243,104, 31,139,124, 24,227,142, 30,161,169,102,142,147, 50,172,203, 50,121, 41,229, 42, 69,218, 3,
+ 30,118,241,202, 0,243,200, 41, 94,165,129, 22, 42, 88,227,163,116,203, 17, 8,185, 93,183,106,208,252, 38,221, 75,239, 69, 82,
+148,212, 98,226, 86,217,118, 44,165,167, 9, 65,101,223, 60,148,144,181, 96,168, 43, 0,252,174, 91,214,181,183, 10,117, 86,179,
+ 50,153, 73,166, 83,194,214,252,233, 83,209, 26, 43, 44,162, 64,140,219,206, 58,234,210,112,235,191, 11, 64,100, 44,244, 4,168,
+145,172,123, 98,119,186,189,184,148,118,141, 70,148,197, 50,191,111,207, 66,201,167,161,249, 52,249,241, 42,212,229, 7,204, 15,
+126, 66, 92,110, 3,140,161, 73,118, 19,202, 81, 97,108,148,161,199, 27, 91, 78,107, 86,119,238,216,221, 43,230,252,250,182, 13,
+ 58,183, 46,147, 70, 13, 38, 4, 56,116,185,179,162, 69, 46,180,223,141, 81,142,184,140, 41,147, 41,114, 84,242, 75,171, 82, 84,
+194, 91, 72,230, 64, 90,214,181, 33,200,201,170, 43, 89, 94,208, 24,128, 15,166, 66, 20,216, 3,112,111, 96, 88,110, 78,159,118,
+155,220, 99,160, 60, 98,250, 99,112,207,134,255, 0, 71, 46, 29,250, 64,120, 83,195, 50,248,169,148,241,245, 69, 30, 93,144,193,
+ 67, 79, 83, 28, 82,215, 85,189,122,153,115, 32,105,154,178,134, 26,105,168,101,163,146,156,211,189, 75,102,130, 44,173, 68,114,
+ 77,207, 71,110, 15, 18, 59, 61, 18,251,183, 45,234,180,107,233,187, 1,250,171, 17,238,235,214,213,164, 83,170,247, 53, 22,146,
+247, 59,114, 43, 22,149,141, 85,159, 17,119,100,134, 63, 68,234,163,187, 34, 18,164, 53,206,152,138,117,244,161,183, 58,193, 87,
+225, 15,135,235,154,206,165, 93,187, 71,198, 37,215,186, 16,174, 74, 84,106,197,183,252, 7,217, 27,135,115, 66,233,111,133,248,
+ 82,110, 88, 27,108,185, 18, 44, 98,226,138,217, 76, 74,176, 98,168,211,208, 31, 14, 67,113, 0, 40,199,138, 77, 58,219,219, 50,
+244,105,201,133,114, 94, 12, 56,227, 82,225, 41,246,106, 20,107,126, 74, 1, 10, 21,105,145, 29, 83, 87, 29,105,183,135, 90, 99,
+ 14, 24,108,168,230,161, 33,210,145, 21,121,134,197,241,157,196,167, 13,119,204,187,239,101,247, 94,228,180,103, 85, 93, 74,238,
+122, 27,239, 11,130,196,190, 89, 74, 3, 65,139,247,111,234,106, 52,187,152, 37,129,200,203,193,152,211, 98, 54, 3,112,101,197,
+108, 4,133,235, 56, 58, 10,228, 87,202, 71,178,152,134,242, 75,119, 19, 27,222,225, 88,150, 31,254, 96, 54, 34,214,141,213,129,
+ 30, 77, 63,251, 74,190,146, 28, 63,196,245, 21, 94, 41,241, 81, 90,138,137,238,120,103,135,232,114, 90, 51,145,166,250,161,204,
+ 42,243, 28,191, 56,115, 80,172, 17, 36,201,106, 30,171, 49,165, 99, 58,215,215,101, 85,180,199, 46,155,165, 84,250,206,231,112,
+167,186, 84,202,229, 58, 84, 41,147,169,133,248,238,197,175, 91,119, 93, 18,221,187,232,146, 84,224,168,218,183,125,171,122, 80,
+169,146, 69, 62, 91, 77,165,197, 50,182,199,186,202, 90, 37,197,125,153, 76,161,221, 73, 67,102,161,181,186, 27, 75, 97,238,133,
+149, 75,174, 53,111,223, 86,211, 87,109, 54,213,185, 35, 77,146,237, 17,137, 14,200,167, 84,169, 77, 86, 23, 24,190,212,104, 85,
+ 56,114,217, 98, 72, 75,241,159,101,166,228, 0, 16,240, 9,226,206,213,123,125,246,154,253,183, 26,179,248,203,225,125,202,139,
+ 46,178,168,179,235,251,104,229, 22,255, 0,179,166, 52, 82,164, 41,247,246,211,115,158,110,161, 69,150,180,149,143, 14,155, 84,
+150,134,210,172, 54,180,249,236,206,213,123, 69, 61,143,214,236,216, 85,123,123,115, 55,238,195,166,195,122, 53,197, 19,108, 46,
+ 26, 79, 16, 44,236,253, 26,226,128,250,223,131, 85,141,183, 84,234,188,232,106,173,199, 90,212, 89,142,137, 15, 83, 81,144,125,
+209,101, 40,228,141, 47, 10,102,180,149, 86,154,156, 24, 92, 29,108,129,135,154,226,204, 2, 44,137,115,111, 54,226,254, 93,182,
+ 24,147,120,185,244,188,240,119,233, 7,195,249, 54,103, 93, 17,224,159, 17,114, 33,203,106,209, 45, 37, 92,121,173, 8, 71, 34,
+150,170, 58,150,200,101,166,150, 41,220, 61, 44,139, 5, 76,112,171,213, 71, 20,136, 39, 4,118, 6, 29,186,134,194, 27,148,195,
+193, 62, 44, 68,187, 21,106,102, 84, 30, 70, 85,205,142, 80,158, 87,201, 81, 7,153,192, 0,192, 80, 64,211,149, 66,165,180,203,
+136, 67,104,240, 27, 90,130,130, 17,226, 37,166,148,162, 1, 67, 73, 94, 66, 83,252,227,140, 39, 39,160,215, 35, 46,223,110, 95,
+179,178,219,105,233,244,219,195,120, 47,233,139, 89,112, 67,182,118,102,191, 77,247,149, 21,115, 41,196,213,175, 41,244,200,241,
+ 80, 85,142,139,201,194,137, 9,207, 77,115,159,136,255, 0,164,222,229,137, 30,163, 15,134,190, 13,228, 85,153, 9, 87,213, 91,
+165,191, 87,204,167, 45, 40,174, 45, 76,182,204,169, 86, 14,216,198,101,228,255, 0,133,202,109,178,212,219,137,132, 41,194,148,
+158, 96,180,131, 37,202,248,118,182, 90,133,138, 42,118,185,221,117,133, 75,133, 32, 29,216,168,185,189,236, 14,163,109,129, 0,
+219,143,243, 63, 16,184, 90,150, 55,105,115,232, 42,165, 31,169, 77, 42,212,177, 32, 14,130, 18,226,224, 0, 53, 57, 0,216,238,
+ 55,196,195, 45, 68, 22,211,205,146,176,133, 54,151, 20,132, 15,133,229,231,144, 40,224, 37, 5, 65, 39,151,155,148, 18,158,152,
+235,167, 48, 77, 75,205,166, 35, 10,241, 36,158, 64,164, 52, 60, 79, 9, 9,207, 48, 83,160,114,149,103,148, 96,103,182, 73,215,
+230, 7, 43,219,203,237, 79,157,190,246,230,253, 61,196,180,212, 75,181, 94,156,213, 51,101,233,182,221, 22,223,225,210, 69, 2,
+168,227, 11,169,218,181,125,167,162,176,212,122,212, 25, 8,142,218,126,176,154,244,170,211, 68, 7, 88,168,182,234, 82,177,213,
+203,167,233, 12,113,211,199,133,235,182,188, 54,240, 99,176,227,101,238,251,254, 37, 46,135, 81,183,246,214,113,190,247, 95,112,
+ 47, 39, 98, 37,203,129, 54,157,199, 86,136,195, 22, 53,140,193,106, 91,252,225,149,204, 98, 19, 75,118, 84,180,165, 7, 18,169,
+178, 74,170, 69, 51, 56, 73,209, 23, 81,210,224, 42,219,115,204, 50, 5,109, 34,219,149, 87, 3,115,219, 16, 36,241, 71, 32,204,
+ 22, 85,167,138,163,219, 12,129, 32,128, 37,228,152,177, 1,116, 88,216, 92,246,107, 17,218,230,195, 19,125,171, 92,246,205, 30,
+ 90, 32, 84,171,244,168,149, 5, 16, 61,205, 83, 89,247,180,147,216, 56,218, 23,148,121,247,198,178,122,125, 22, 5,114, 40,154,
+138,154, 22,210,134, 80, 99,180,183,112, 79,162,136, 1, 95,118,123,235,152,220, 17,123, 63,247, 3,103,237, 26, 77,219,197, 85,
+255, 0, 51,114,119,174,160,202, 42, 21, 90, 12, 74,180,170,149,181,104,202,120, 37,197,211,222,171, 73, 81,114,229,171,182,181,
+ 40, 63, 37, 88,100,184,149,120, 41,228,194,143, 75,153,101, 48,185, 91,107,153,134,155, 1, 8,109,165, 41, 41, 74, 64, 1, 32,
+ 4,224, 99, 3, 80,103, 78, 51,204,101,157,185,180, 57, 21, 10,146, 34, 81, 20,149, 19,184,236,206, 95,148,177,131,216,104, 15,
+110,168,167,108, 60,209,182,123, 57,246,138,169,146,133, 91,117,142, 38,105,152,127,215, 43, 89, 24,145,251, 10, 7,241,197, 84,
+154,117, 14, 91, 72, 18,147, 35, 46,114, 97,104, 83,107, 42, 39, 25, 0,249,254,115,167, 66, 11,229, 77,120,141, 0,191,209, 21,
+ 33, 25,229,241, 84, 82, 74, 83,146, 59,103, 90,221, 94, 77, 82,101,118,154,148,130,244, 86,221,202,228,255, 0, 60, 39,160,229,
+ 89,254,119,200,247,211,203, 6,164, 88,105,150, 65,236,148,131,147,213, 56, 24,206, 62,221, 45,195,237,153,206, 43,169, 51,119,
+ 73,100,164,125, 34, 72,211, 64, 97, 96,110, 1,191, 81,243,214,210, 12,210,138, 24, 41, 40,102, 89, 57,178,213, 33,105, 1, 32,
+244, 32,111, 96, 45,125,246,219,221,139,140, 97, 48, 58,236,154,131, 46,153, 46,146, 87,204,146, 82,132, 15,242,109, 36,167,167,
+132, 6, 59,119,206,190,200,170,100,132,160, 21, 41, 56, 1, 36,134,210,133,100,156,114,158,195,191,225,170,166,170,211,105,248,
+149,212,255, 0, 59, 56, 36,156,100, 15, 64,113,246,235, 24,171,213,226, 60, 10,142, 60, 84,244, 75,137,232,164,103,245, 65, 82,
+ 71, 80, 58,100,117, 7, 79,209, 82,242,147, 69, 59,116,245, 27,159, 93,250,111,240,235,241,195,116, 85,144, 77, 56, 50,195,229,
+ 27,121,122, 40, 22, 2,202,123, 1,254, 33,247,226,229, 38, 74,212,210,138,159, 75, 96, 2, 2, 89, 3,156,146, 72,192, 46,118,
+242,234, 6,176,138,131,208,130,143, 59,105,144,180,243, 97,114, 84,183, 74, 71,117, 30, 85,124, 41, 72, 32,103,160,201,234, 15,
+ 82, 53,100,169,214,165, 52,218,131, 78,182, 91, 7, 5,229,115, 43, 41, 62,101, 9,253, 85, 99, 29,115,128,122, 16, 53,132, 78,
+168,190,250,242,169,137, 87, 33, 4, 48, 26, 80,111, 0, 28,172,132,175,226, 56, 4,128,162, 71,159, 77, 32,237, 34, 54,153, 1,
+ 86, 59,239,247,110, 15,243,248,219,221, 40,164,162, 89, 84,201, 21, 66,136,191,195,112,122,116, 32, 11,143,131, 90,221, 78,196,
+ 28, 93,170, 53, 86,220, 45,182,214,121,193, 56, 75, 24,202, 63,156,175,242,120, 8, 79,194, 49,147,208,172,140,107, 28,144,185,
+ 14,165,196,243, 54,128,227,107, 95, 40, 1,247,148, 10, 82,160,148, 36,114,161,156, 18,146,126, 53, 99, 7,225,193, 26, 21,201,
+165,223,209,170, 87, 43, 69,196,145,224,199,109, 32, 21,142, 84, 37, 68,147,135, 50, 73, 61, 7,235, 99, 61,180, 42,150, 9, 83,
+110, 45,199,193, 66,138, 91, 83,156,173,178, 57, 84,149, 20,132, 36, 4, 47, 4,158,234, 33, 74, 7,212,107, 34, 85, 36, 91,174,
+195,111,187, 14, 2, 4,136, 88, 88, 50,239,114, 9,216,252, 64,239,107,131,210,253,111, 96,106,135, 9,241, 91, 90,152,154,224,
+ 81, 10,117,183, 66,150,132,132, 32,132,199, 90, 18, 18,211, 62, 25,202,136,229, 86, 80, 71, 55, 78,180, 86,211,138, 90,218,109,
+210,132,173, 42, 40,195, 97,226,160,188,146,149, 61,202, 17, 24,252, 7, 4,147,128,148,146,114,179,143,162, 72, 66, 20, 93, 82,
+ 91, 32,243,151, 0, 13,184,226,121, 87,250, 54,210,216, 3, 57, 40,248,112, 84, 48,188,119,233,112,142, 86,234, 29, 75,124,173,
+161,158,235,112,133, 50, 75,156,174, 56,246, 66,135, 48, 3, 10, 10, 0,128, 64, 10, 4, 29,108, 70,250,118,191,227,252,183,237,
+110,134,223,125,175,163, 80,140,221,139, 15, 94,194,214,251,186,251,205,239,140,110,108, 82,150,189,228, 33,212, 54,225, 10,142,
+ 29,108, 40,168, 1,209, 40, 65, 63, 3, 28,169, 5, 42,200,193, 95, 80, 71,124, 14,168, 18,210, 86, 21,203,202, 82,160, 8, 0,
+169, 41, 24, 9, 81, 60,184, 87,196,165,224, 12, 28, 28,231,190,156,202,203, 43,100, 60,180,187, 46, 83,142,128, 90, 68,167, 20,
+ 70, 74,148,144,167, 1,235,149, 35,157, 71,249,216, 72, 0, 37, 61,155,106,154, 76,153, 41,136,149, 4,169,231,163,196, 66,202,
+129, 9,117,245, 33,158, 98,160,112, 71,136,224, 32,158,132,126, 26, 84, 48, 2,250,134,223,233,191,126,157,125,253,112,216,241,
+ 18,202,161, 65, 55, 29, 0,222,246,181,135,238, 29,126,252, 64, 99,219,127,112,181,112,123, 74,183,173,166, 28, 82,255, 0,130,
+214,206,212, 89,178, 82,176, 66, 90,159, 67,176,105, 47, 75, 67, 68,147,204,215,137, 82, 24, 35,204, 30,154,228,170,206, 51,216,
+231,166, 58, 99,237,251, 53,183, 60,121,238, 60, 93,220,227, 99,138,189,200,132,233,122,157,114,111,133,244,154,114,249,150,180,
+154,125, 6,168,171, 94, 25,104,172,228, 50, 89,161,161, 72, 29,130, 92, 0,116, 26,212,101,246, 56, 61, 59, 96,227, 63,241,212,
+247, 43,140,165, 5, 18,176,179, 8,144,144,122,130, 84, 18, 62, 32,155, 28,114,150,121, 50, 85,103,185,197, 66, 29, 81,207, 87,
+ 80,202,123, 21, 51, 57, 82, 15,189,108,126,252, 8,178, 15, 79, 76,232,117,245, 36,142,192,224,252,191,179, 85,214,174,254,137,
+207,231,246,104,101,224, 28,231,161,235,248,233,200,126,252,104, 1,220,109,129,221,230,199, 97,142,189,189, 51,215, 63,159, 61,
+ 14, 64, 0, 96,247, 29,126, 71, 68,169, 89, 62,120,252,245,208,202,238, 79,204,253,154, 92,108, 5,240, 48, 58,192,202,135, 67,
+215,243,231,249,198,133, 81, 3, 57,249,224,119,237,229,162, 28, 39,169,249,249,126,125, 52, 26,200,251,199,127,179, 74, 45,198,
+227,126,216,200,253,248,160,178, 50, 58, 3,211,207, 63,184,253,186, 90,240,163,147,159,195,236,210,210,184, 24,175,170,168, 61,
+ 49,215,167,225,161, 16,112,122,156,116,213, 97,248,103,161,251, 51,164,216, 90,227,174,173,255, 0, 60,100,245, 38,214,190, 14,
+ 73, 56, 0,142,152,239,145,247,116,213, 66,176, 7, 82,172,142,216,249,246,207,222, 52, 58, 84, 83,211, 29, 7,111,236, 58,242,
+ 80,162,174,101, 47, 8, 61,128,206, 71,222, 7,174,116,131,222,222,236,101, 69,254,127,150, 46,141,168, 96, 0, 57,137,206, 73,
+254,145,243,192,215,213, 44,173, 73, 8, 39, 9, 56, 87,124,103,247,245,254,141, 80,105,188,242,146,174, 81,158,128,117, 61, 49,
+215, 25,244,209,205,167, 57,192,206,127,164,117,237,249,237,164,172, 79,207,166, 48,109,219, 21, 90, 56, 35, 35, 32,143, 46,221,
+ 61,125, 15,125, 28, 57, 72, 79,160, 62,127,205,251, 62,125,244, 50,121,112, 0,252,253,190,154, 37,176, 85,142,192,124,135,244,
+231,207,166,177, 97,123,227, 24,184,178, 15, 76,159, 82, 63,163,247,234,184, 24, 57, 24,201, 57, 7, 31,135,219,161, 16,175, 35,
+231,219,250, 49,162,146,113,220,245,232, 65,198, 59,246,199,175,246,233, 22, 22, 36, 97, 50,187,220,155,223,231,255, 0, 56, 37,
+ 43, 8,199, 58,186,159, 32, 59,244,249,104,146,238, 70,113,140,249,250,227,183,159, 77, 4,113,144,190,153, 63, 44,227,184,200,
+252, 53, 81, 36,116, 32,231, 29,201,251,125, 7,150,146, 98, 58,223,225,130,219,221,123,117,193, 41,119, 24,248,249, 64, 32,224,
+227,175, 94,160,122,244,206,167, 39,236,166,220,118,247,115,129,157,165,148,252,148, 73,171, 88, 74,169,237,245, 93, 33, 73, 46,
+ 54,186, 44,133, 38, 1,113, 61, 74, 65,132,228,126, 92,227, 35,168,212, 42,118,215,108,110,189,211,185, 98,219, 86,181, 49, 83,
+231, 73, 5,229,186,227,137,139, 78,167,194, 66,128,145, 85,173, 84, 93, 79,135, 74,164,183,252,247,156,234,162, 66, 26, 67,174,
+148,160,203, 23,217, 2,214,215,112,241,106,238,110,209,215,119,102,143, 34,181, 87,151, 2,239,168, 76,172, 75,110,139,108, 53,
+ 53,136,201,133, 34, 21,179,239,238, 5,184,218, 82,218, 11,139,119,149,215, 15,196, 91, 66,126, 17, 4,227, 9,104,167,142,154,
+137,228, 6,169, 95, 86,155, 95, 74, 21, 96, 75,158,136, 11, 5, 3, 81, 26,142,194,230,246,184, 60, 26,124,214,135,136,167,204,
+ 41,105,100,124,178, 88, 36,167,158, 80, 44,129,137, 73, 35, 0,159,180,193,212, 2, 20, 18,129,238,218, 65, 23,235,214,231, 75,
+174,219, 59, 83,184, 21,235, 93,151, 30,184,224, 91,147, 13, 27,193,104,188,236,105,178, 18, 35, 38,162,134, 82, 50,234,163, 33,
+213,188, 0,207, 86, 70,181,171,102,120, 8,183,217,222,155,115,124, 46, 59,138, 53,229,105,208,108, 90,123, 86, 21, 10, 66,223,
+155, 42,179,121,215, 33,166, 69,211,124,221,210, 95,234,244,211, 45,231, 83, 25,177,128,216,198,122,164,107,107,162,239,150,195,
+ 32,148, 57,188,187,110,233,193, 75,141, 34,227,167, 60,130,146, 48,180, 45, 33,226, 20, 8, 39, 35,207, 26, 14,226,227, 7,134,
+ 29,183,182,107,183, 12,173,200,163,213,169,246,180, 23, 39,205,163, 89,141,125,115, 86, 84,102,186,172, 83,169,144,129, 84,133,
+127,178,128,126,237, 65,225,142,150,158, 82,226,162, 33,169,116, 0, 89,111,114, 69,200, 23, 59,157,133,183, 61,135, 91, 99,179,
+242,190, 62,226, 28,135, 33,205,114,204,161,165,203, 70,109,205,246,202,132, 82, 30, 74, 87,138, 56,249, 76,250,117, 70,177, 5,
+155, 76,136,234,116, 85, 84, 45,129,101, 97,144,207,224,179,103,238,181, 56,183, 81,123,208,158,152,250,158,156,245,169,125,220,
+ 20,116, 60,235,202, 42,121,197, 48,137, 42, 66,150, 73, 60,184, 78, 0, 56,244,208, 91,129,114,240,113,236,166,216,187,155,114,
+235, 20,202,117,183, 21,229,201,153, 69,162,189, 37,138,222,236,111, 13,232,227, 74, 84, 26, 29, 62,109, 77, 74,149, 44, 56,247,
+ 39,140,233, 40,139, 17,165, 41,231,112, 0,207, 27,248,128,250, 66,114,226, 82,170, 52,190, 16,184,115,190, 43, 19, 3, 14, 52,
+141,201,220,155,106,174, 41, 84,247,112, 66,100,195,183, 41,209, 86,185, 78,160, 14, 96, 30,113, 8, 56,248,186,103, 81,143,226,
+ 11,136,157,247,226,127,114,100,238, 30,253,238, 45,126,244,188,158,105,214,162,199,173, 62,168,205, 81,169,238, 40,172,211,168,
+ 86,223,192,221, 6,154, 50, 7, 43, 76,160,168, 1,206,181,158,186,127,203, 56,124,207, 46,161, 18,211, 34,253,166, 54, 14, 6,
+215,180,103,204, 24,247, 50, 42,129,179, 89,197,215, 20,239, 27,253, 36,248,135,244, 13, 71, 12, 80,113, 94, 97,196, 20,179,105,
+ 38, 7,168,168,108,188, 50,127,118,243,135, 96,181, 38, 34,111, 20, 96, 58,169,220, 60,100, 95, 24, 39,180,115,137,253,201,226,
+247,127,170,251,223,186, 82, 27,254, 16, 94, 74,118,124, 26, 44, 87, 92,118,155,105, 91, 81,121,162, 91, 54,141, 31,196, 63, 13,
+ 58, 13, 59, 9,230,192, 47, 62,243,210, 23,241,186,117,175, 92, 57,196, 97,202,237,211, 57,208,178,252, 42, 34,147, 24, 1,211,
+ 46,149, 5, 18, 60,253, 6,173,251,228,231, 53,219, 29,128, 65,247, 42, 12, 6, 79, 41,200, 5, 73, 4,129,215,191,174,178, 14,
+ 26,216,118, 93,122,230,134,202,121,164,204,167, 68,139, 29, 9,238,183,223,119,194,101, 41,207,153,113,104, 31,126,172,212,141,
+ 41,120,124,197, 24,209, 26, 34,128, 46,118, 28,192,119, 59,147,183, 82, 73, 39,169, 36,239,142, 53, 53,117, 21,115,214, 86, 85,
+ 74,211,213, 84,180,178, 72,231,118,103, 42,204, 73,176,238,123, 0, 0,232, 0, 27, 98,109, 63, 71,223,128,234,125,203,195, 15,
+ 16,156, 74,220,244,174,123,199,114, 99,200,218,237,155,145, 45,177,136,116,123, 98, 92, 90,221,217, 83,134,149,167,225, 85, 82,
+187, 18, 29, 56,186, 15,197, 30,152,164, 14,138, 57,216,168,246, 17,161,213, 31,142,228,117, 50, 90,146,235, 97, 10,230, 75,225,
+ 8, 56,228,115,185, 67,169,229, 41,229,239,204,112, 8, 58,236,151, 0,219, 99, 15, 98,184, 76,225,239,107,105,113, 83, 17,187,
+ 99,109,109,231,167,180,148,132, 41, 85,138,164, 38,234,181,105, 14,116, 28,206,174,124,199,201, 39,174,123,233,168,226, 23,134,
+171,150, 93,110,226,220, 91, 38, 61, 58,161, 65,144,255, 0,214,146,168, 44, 62,182, 43,237,206,148,240,247,152, 52,168, 9,103,
+146,167,207, 53,197, 58,202, 3,136, 63,166, 80, 94, 2, 65, 52,151, 19,209, 54, 99, 28, 89,138, 38,170,131,118,127, 82,142,117,
+ 40, 61, 55,137, 74,160,247, 13,239,215, 29,145,225,180,210,240,102, 89, 6, 69, 36,194, 24, 42,163, 73,100,212,214, 95,105,101,
+ 94,110,228,237,169,174, 22,254,128,108, 0, 3, 82,108,234, 84,116, 52,134,210,201, 41,147, 33, 50, 29, 8,240,203,143,186, 2,
+ 0, 83,220,201,207, 58, 67, 40, 7, 36, 0, 19,132,156,107, 99,104, 52, 8,210, 93, 98,116,150,210, 36,193,113, 47, 65, 13,129,
+225,199,203,101,135,198, 79,235, 74,113,133, 41, 10, 89, 5, 32, 16,148,242,167, 36,170, 87, 15, 59,203, 71, 82, 20,230,223, 76,
+148,128,134,151,205, 74,153, 75,168, 33,105,194, 64, 39, 19,144,162, 0, 37, 71, 41, 4, 99, 28,189,244,241,218,123, 83,186, 79,
+ 41,180, 35,109,238,133, 20,114,133, 45,113,162, 37, 61, 14, 28, 74,221,114,104, 72, 79, 81,147,216,245,198,162, 81,100,213, 74,
+ 64,146,146, 66, 91,182,134,244, 22,232, 13,237,215,211,210,214, 24,178, 78,125, 70,186,229,108,198, 24,237,177,102,158, 32, 0,
+ 54, 4, 18, 91, 96, 64, 3,222, 5,177,113,161,208, 12,134, 16,211, 10, 90, 34,143,242,202,115,224,151, 49,158,230, 50, 29, 74,
+147,238,236, 18,160, 10,191, 89, 64,114, 35, 1, 74, 86,178,171,163,112,237,237,158, 85,185, 95,170,208,239,234,203,242, 38,132,
+ 82,227,109,214,216,222,251,153, 34, 51,212,224,196,176,253,106,153, 99,209,229, 46,149, 79, 64,228, 45, 41,208,217,144,176, 88,
+142,149,168, 40, 7,150,209,216, 45,211,158,164, 57, 54,149, 73,183,217, 80,229, 46,213,234, 77, 72,113, 41, 0,142,127,114,166,
+182,234,138,136, 63, 8,231, 66,124,250,119,214,136,251,111,106,123,151,194, 15,179, 87,116,183, 91,103,247, 82,225,178,183, 81,
+ 55, 54,223, 91, 16,111, 43,121,168,212,249,212,202,101,201,112,177, 6,177, 22,136,227,168,117,112,106, 47,198, 43, 67,115,185,
+253,229,144, 74,152, 83, 75,194,132,166,147,135,179, 55,167,146,177,104,218, 8,163, 49,131, 44,171,101, 82,242, 36,105,101, 37,
+ 93,174,238, 0,210, 13,137,213,184,190, 34, 25,199,137,124, 27,150, 48, 25,157, 89,207,105, 98, 73,154, 90, 74, 25,209,101,153,
+ 68, 78,197, 69, 87, 38,162, 8,201, 42, 11,115, 17,137, 23, 64, 22,225,150, 51,124,116,238, 62,206,240, 93,121,221, 53,125,139,
+ 98,254,183,183,166,236,173,213, 46,123, 18,139,190, 78, 91,107,223,205,183,143,115, 74,157, 85, 27,132,254,217,209, 34,200,137,
+176,244,148, 57, 59,154,223,149,118,189, 34,254,168, 6,195,212,202, 37, 1,178,229,101, 17,220,184, 46,123,134,236,174, 85,110,
+107,134,183, 87,184,110, 58,228,233,117, 42,229,201, 93,156,253, 74,191, 90,168,206,125,114, 39, 77,169, 84,100,184, 86,235,239,
+ 72, 90,214,224, 4, 37, 74, 86, 72, 39, 36,218, 42,181, 73,149,138,165, 74,181, 92,157, 58,167, 88,172,212,165, 86, 43, 53,106,
+148,217, 85, 42,173, 98,179, 80,115,198,159, 87,171,212,230,186,183,234,149, 55,158, 37, 78,200,125,199, 29,112,245, 90,142, 6,
+128,109,101,110, 97, 36, 6,179,241,128, 71, 49, 62,185,242, 26,176,114, 30, 31,163,201, 33,178, 14,117, 76,191,106, 66, 5,197,
+194,141, 9,251, 40, 52,128, 22,229,136, 85,214,206, 85, 72,164,252,120,250, 73,120,157,244,128,204,169, 36,227, 28,238, 99,195,
+217, 60,113, 67, 69,150,137,165,120, 17, 41,193, 88,102,171,119, 98,213,213,195, 83,191,180, 77,245,112, 73, 61, 64,160,130,138,
+ 25,228,133,136, 90,148,234, 57, 93, 9,121, 9, 80, 90, 91,144,148,188,144,176,114,149,165, 14, 2, 18,224, 80, 4, 40, 96,130,
+ 50, 8, 58,204,169,155,143,113,209,211, 21,169,110,192,185,160, 68, 11, 17,232,183,173, 53,187,170,154,198, 82, 82, 61,205,249,
+174, 9,212,229, 15,255, 0,131, 48, 54, 63,248,163,211, 24, 96,228, 10, 88,201, 41, 7,162,137,244,238, 63, 57,213, 53,164, 43,
+ 36, 14,185,200,252,159,150,159, 39,166,130,161, 52, 77, 10,202,163,166,160, 13,137,238, 13,174,167,222, 44, 71, 99,138,111,135,
+120,167,136,248, 74,170,106,190, 27,206,170, 50,105, 42,192, 74,133,134, 66,176,213, 68, 13,249, 53,148,230,244,245,180,228,253,
+170,106,184,166,129,255, 0, 94, 54, 24,116,231,239,189,238,150, 89,133, 64,254, 15,237,252, 36,248,206,123,141,131, 77, 48, 29,
+151, 33,230,210,209,151, 80,170, 84,195,206,184,250, 26, 64,229, 8, 74, 50,160,149, 45,107, 8,109, 8,177,171,117,119, 10,108,
+ 7,169,170,189,110,207,170,159, 74,208,253, 57, 21,201,173, 71,113, 46,161, 40,144,133, 73, 74,196,165, 54,232, 78, 92,111,222,
+ 60, 37,149,168,148,124, 74,206, 0,166,219,230, 33,120, 36,117,206,124,251,143,219,175,170, 91, 74, 90, 19,207,241, 32, 19,200,
+147,240,156,250,254,205, 37, 29, 21, 36, 32,133,167, 64, 24,223,236,130,111,182,228,145,114, 71, 98, 73, 54,218,248,156,102,190,
+ 58,120,209,157,242, 99,172,241, 87, 62,130,146,154,148, 80,197, 71, 69,153,213,101,153,108, 20, 34, 40,225, 52, 84,185, 86, 89,
+ 37, 30, 91, 75, 70,241, 68,139, 37, 45, 45, 36, 84,242,232, 13, 44,108,196,177,172,227,188,193, 37, 92,169, 75,105, 8,109,150,
+208, 16,219,109,131,209, 13,161, 0, 37,180,228,147,128, 7, 82, 79,114,117, 72,146,163,205,129,140, 14, 81,216,140,129,158,184,
+237,223, 94, 84,177,158,216, 4,224, 31, 32, 73,237,246,107,233, 9, 80, 79, 50,129,198, 79,194, 64, 35,215, 61,126,205,109, 95,
+111, 47,109,189,216,170, 85, 2,233, 91,105, 10, 6,221, 0, 3,160, 30,158,131,165,177,229,212,133,160,131,128,125,112, 51,211,
+236,243,208,105, 11,230, 60,201, 8,109,191,139,226,248, 78, 71,159,207,251,116,122, 20, 20, 50, 7,145,200, 61,199,151, 95,191,
+ 67,169, 36, 55,151, 49,215,161,201, 4,252,137, 0,246,233,161,179,111,219, 6,177, 6,221,251,126,255, 0,227,138,110,123,186,
+192, 82,130,150, 8,200,194, 73, 3,182, 73, 31, 61, 75,227,232,215,112,195, 99,223,219, 35,198, 38,227,110,133,131,105,238, 13,
+175,184,202,183,248,125, 93,173,121, 80, 32, 92, 54,253,118,207, 69, 45,203,170,246,167, 78,131, 84, 97,109,174, 60,137,213,122,
+ 35, 78,132,242,171, 48, 16,160,164,173,180, 40, 68, 24,149,143, 8, 54,158,138, 74,147,205,144,144,181, 99, 24, 3, 29, 15,109,
+ 77,123,217,103,184,103,103,189,143,246,187,116, 6,164, 81,171,123,149,186,219,227, 85,173,205, 79, 52,105,170,164, 82,174,168,
+214,139, 78,199,144,180,167,195,143, 48, 82, 93, 67, 79,160,169, 10,102, 26,210,135, 57,138,185, 98,156, 99,155,193,146,101, 73,
+ 89, 80, 12,138, 37, 10,177,139, 6,150, 66,173,201,141, 9,232, 76,161, 9, 36, 16,136, 25,200, 33, 72,197,129,225,126, 86,115,
+110, 47,162,164, 72,185,210,136,228,101, 7,117,187, 20,132,234,244, 26,101,111,190,214,223, 28,193,223, 63, 97, 79, 4,115,184,
+194,185,209,179, 27,239,185, 54,175, 14,116,135,150, 47, 93,165,163, 83,105,149,186,237,191,122,205, 66,164,162,196,218,237,215,
+185, 31,144,220,155, 36, 48,243, 62, 60,137,208, 39,207,167, 56,164, 69,140,229, 65, 78,120,204,111, 6,212,251, 26,125,155,123,
+125, 58,216,185,109,203, 55,136,138,110,227, 80, 37,198,122,216,220, 26, 55, 21,119,221,175,121,219,245,200,177,194,145,114, 81,
+170, 86,149, 42, 2,105, 21,166,212, 60, 80,227, 40, 75, 45,172,132,134,150,223,194,108, 27, 71,113,203,157, 91,184, 42,197, 34,
+ 81,147,122, 93, 21, 71, 34,115, 36, 46, 82,152,170, 10,100, 82,181,243,128,150,154, 17, 84,177,200, 6, 11,105, 81, 80, 1, 58,
+222,155, 74,229,118,163, 38,164,121, 90,136,212, 8,204, 83, 34,180,202,131,110,158, 98, 36, 84,159, 83, 97, 28,172, 45, 43, 91,
+109, 37, 72,230, 95, 43, 74, 4,164,144, 53, 71,103,220, 99,198,175, 58,200,217,245, 68, 48,132, 0,197, 3,242, 22,221, 8, 44,
+154,100,147,169, 93, 83,188,174, 86,218,156,144,111,212,220, 79,225, 79, 9,228, 78,100,161,201,225, 89, 2,172,143, 33, 82, 89,
+164,178,130,234, 9,180,107,204, 58,149, 35, 85, 80,157, 55, 14,113,212,219, 99,136,234,228,106,101, 18,155, 87, 66, 43,171,106,
+ 35, 20,230,230,213, 86,165, 86,106, 81,233,145,219,143,245,157, 94,162,202, 82, 39,213,158, 8, 74,228, 72,240,144, 31,125,213,
+185,225,160,171,151, 78,181,189,187, 22,141,226,232,140,220,143,169,234, 75,115,193,110, 28,247, 27, 75, 82, 94,236, 27,137, 40,
+ 30, 71, 22, 72,232,147,202,162,122, 0, 78,185, 81, 30,244,240, 36, 85, 11, 97, 75,143, 66,134,205, 38, 36,144,114,151,170,110,
+182,100, 75, 96, 4,171,162,144,234,163,165, 65, 32,245, 74,178, 8, 26, 10, 61,219, 41,136, 17,203,239, 31,124,142,204,154,156,
+175, 13,210,158, 95,136, 52,201,108,142,169, 62, 50,148,126, 69,191,150,148,202,184,199, 54,167,208, 37,169, 53,106, 7,153,101,
+243, 27, 0,162,250,143,152, 27,234, 59,146, 0,182,199, 21,248,142,186,130, 68, 16, 73,204, 22, 91,197, 37,200, 58,148,200, 0,
+ 63,105,108,186, 23, 99,179, 29,212,244, 27,233,106,113,119,182,151,183, 20,183,231, 10, 22, 90, 95,184,110,205,174,179, 85,117,
+110, 45,213, 17,214, 92,183,173,234,168,126, 51, 38,204, 66,193,230,145, 91,105, 50,153,247,130, 7, 35, 78, 18,214, 74,210,172,
+108,130,235,136, 99,157,106, 88,230, 57, 24,206,126, 30,184, 29,122, 99, 35,174,184,239,193,253,153,180, 27, 99,196,214,228,110,
+244, 17, 42,218,187,248,132,179, 97,219,181,104, 40,144,201,180,230,222, 73,172,174,167, 38,226,195,235, 46,192,175,213,208,195,
+104,125, 33, 94,236,228,180, 23,194, 91,114, 74,129,232,125,205,113, 42, 50,221, 64,113, 73, 41, 74,147,200, 62, 21,165,105, 39,
+ 60,201, 61,142, 2,178, 62, 90,181,184,106,180,102,212,111, 59, 48, 18, 60,132, 50, 0, 46,130,202, 66,144, 55,247,134, 61, 71,
+223,105,215, 25, 75,194, 85,210,100,173,193,144,212,211,209, 46, 91, 68,149,130,172,222, 99,154, 8,239, 94,118,188, 98, 35, 41,
+ 2, 1, 17,229,242, 66,157,152,184, 14,149, 74,248,109,178, 71,136, 2,123,168,115, 2, 14, 14, 57,186,118, 32,228, 31, 62,191,
+ 45, 97, 51, 47, 98, 23,151, 29, 87,134,165, 30, 85, 12,144, 73, 56, 9, 36, 28,115,140,128, 50, 48,190,217,242,214,190, 84,238,
+181,120,174, 53,206, 10,138, 20,251,121, 81,248,208, 14, 28,111, 62,153, 35,167,145, 94,177,148, 93,188,217,104,175,152, 41, 36,
+165, 46, 12,115, 32, 15,137, 25, 36, 18,180, 96,127,181,202,144,175, 93, 74, 99,129, 80,108,110,126, 63, 15,221,249,252,113, 22,
+167,164, 88,198,195, 87, 75,254, 23,239,215,227,252,142, 54,149,187,161, 46,158,100,184, 10, 85,203,158,101, 4,148,156,144,121,
+194,199,192,114, 21,229,141, 90, 42,114,158, 91,107,145, 76, 8,113,208, 10,213, 17, 74, 45,161,212,100,229, 76, 41, 32,144,224,
+234,174, 78,161, 92,159, 14, 20,113,166, 18, 37,213,201,202, 92,120, 40, 0, 57, 92, 36, 41, 65, 39, 56, 67,160,145,146, 15, 76,
+158,152, 57, 32, 19,157,102,144,110, 4,175,225, 82,207, 50, 70, 72, 4,148,117, 57,200,207, 83,144, 6, 64,237,203,243,234,149,
+ 69, 58, 78,154, 36, 23,244, 61,193,236,111,235,211,249,140,110, 67, 81, 45, 20,162,104, 13,237,177, 83,114,174, 63,101,198,215,
+ 30,253,136,189,193, 83,190, 47,109,215,101,185,200,130,228,102,194, 92, 90, 75,164, 58,231, 42,146, 73,229, 80,113, 35, 60,189,
+138,136,248, 74,128, 86, 58,234,234,212,199,221, 1, 78,200, 88, 33, 68, 16,142,102, 27, 82, 21,132,242, 40, 55,146, 82,112, 59,
+ 17,133, 39, 33, 64,231, 88, 13,198,183, 11, 6,169, 79, 9, 91,204, 2,185,108,130,176,149,181,132,149,201, 71,135,250,206,161,
+180,146,226,123,173, 0,158,139, 29,113,232,181,233,174, 28,169, 77,128,142, 71, 27, 45,169,120, 83, 43, 79, 55, 50,121,143,249,
+ 64, 84,147,211,161, 24,193,202,134, 98,211, 43, 81,204, 98,153,246,107,216,216, 88,131,109,238, 59,250,223,241, 6,248,157, 80,
+188,121,165, 42,212, 83, 34, 68,192,217,212,145,169, 24,117,235,185,235,117, 35,175,186,197, 67,227, 22, 64, 10, 60,141,168,243,
+128, 10,146, 74,212, 91, 65, 32, 37, 74, 41, 42, 91, 32,227,252,152,234, 9,207, 49, 35, 87,149, 84, 92,140,217, 90, 25, 74, 60,
+117, 4, 33, 47,165,213,199,195,201, 42,109,160,129,149,198,144,226,142, 19,206, 49,147,240,163,148,243,105,158,139, 82, 82,138,
+ 1,113, 92,142, 19,203, 33,183,156,229, 70, 87,204,203,109,242,184,163, 29,174,101,225, 33, 28,203, 82,148,148,148,231, 35, 87,
+196, 84,214,134,138,188, 73, 40,112,151,217, 83,209,203,109,180,180,164,252, 94, 34, 22,162,183,100,103, 28,223,168, 83,130,148,
+143,136,157, 47, 28,195,190,192, 88, 95,247,119,235,183,190,247,177,191, 77,244, 42,224,209,114, 95, 93,183,232,119,183,196,245,
+ 29, 59, 16, 63, 12,178,167, 82,117,101,214,158,116,143, 5, 24, 90, 23,206,135,176,149, 30,171, 28,152, 67,133,148, 37, 68,130,
+ 72, 82,136,233,216,106,111, 20,187,199, 75,216, 78, 31,183,187,123,107, 14, 3, 11,107, 54,178,243,187,194, 90, 57,118, 69, 74,
+ 29, 37,232,118,227, 17, 80,181, 15, 26, 67,151, 45, 70,140,218, 83,159,252, 98,186,121,105,253,153, 86, 47, 7, 9,115, 32, 43,
+ 45, 41,124,222, 48,200, 88, 62, 39, 83,200,159,140,117, 57, 42,192,233,231,168,229,253, 33,126, 36,209,101,112,247,183,156, 51,
+ 81,166, 20,220,123,253,118,139,190,234,105, 14,114,189, 19,107, 54,170,107, 47, 14,101, 54,172, 24,245, 77,192,149, 76,140,166,
+ 92,229,230,106,223,125, 65, 36, 5, 99,118,157, 26,170,122,122, 52, 39, 85, 75, 0,125, 66,117,118, 29, 62,202, 6, 59,122,116,
+190,198, 41,159, 87,166, 83,147,230, 89,163, 16,134,138, 38,100,189,183,152,128,144,169, 29,124,210,178, 41,223, 96, 73,219, 16,
+244, 92,153, 82,150,236,202,131,161,234,140,247,159,157, 80,125, 32, 97,234,132,215,151, 38,107,224, 96,116, 92,167, 94, 87,207,
+155, 66,172,131,211,207, 61,115,246,127,110,136,115,169, 29,135,115,161, 87,230,174,152,245,239,216,121,254,124,181,105,160, 0,
+ 11,108, 63, 45,182,199, 34, 42,236, 13,205,207,174,253, 14, 6, 86, 50,113,249, 63, 47,150,135, 81, 10,242,192,235,159,159,204,
+250,104,133,250,130, 20, 72,252,244, 26, 21, 71,161, 62,125, 79,223,165, 20, 18, 70, 21,192,234, 32,117,249,224,103,231,246,124,
+180, 51,131, 57,234, 1, 4,245,209, 90, 17,194, 14,122,247, 57,199,203,231,165,199, 81,129,129, 85,211,167, 82, 79,115,242,244,
+199,166,116, 42,200,207,108,117,199,219,215,207, 68,185,242,238, 7,159,111, 95,223,160,150, 79,126,152, 61,193,243, 61,127, 63,
+118,148, 65, 97,210,247,249,255, 0, 92, 12, 82, 36, 2,122,129,247,254,255, 0, 61, 45, 81, 95,235,119,242,252, 62, 95,159, 93,
+ 45, 31, 3,108, 86, 29,251,103,229,162, 52, 42, 87,219, 61, 15,145,199, 76,131,229,170,129, 68,158, 94,108,116,207,111,159, 94,
+190,189,244, 71, 2,221,108, 70, 14,195,173,190, 63,195, 7, 54,123, 21,125,223, 63, 67,162, 7, 95, 35,246,121,232, 38,240, 58,
+100,147,243,252,247,254,173, 22,149,245,244, 62, 94,126, 95,102,146,193, 58,116, 56, 41,161,203,212,156, 99,200,252,243,216,104,
+214,200,243, 0,253,248, 39, 64,165, 89, 29,191, 17,231,231,131,157, 86,108, 20, 44,168,172, 16,172, 1,159, 47,179,238,210,109,
+233,109,135,242,198,113,112, 10,193, 1, 67, 4,249,129,223,237, 35,243,215, 68,167, 3,168,200, 39,161, 29,191,102,122,118,208,
+169, 81, 32, 12, 12,140,119,237,140, 1,140,143, 60,232,128,172,100,156,100, 96,228, 96,147,246, 99,229,253, 58, 79, 24,193,141,
+168,119, 61,113,211,239,233,131,248,104,132, 28,224,245, 56,235,243,233,235,143, 45, 0,133,103, 3,168, 4,250, 14,255, 0,105,
+213,126,108, 17,133, 41, 57,207,234,250,255, 0,195, 72, 55, 94,183,198, 45,251,240, 96,194,212, 65,206, 15, 99,156, 99,167, 83,
+223,166,178,107, 86,133, 46,228,174, 83,168, 84,230,131,242,231,203,102, 43, 41, 89,195, 69,215, 20,122,190,224,255, 0, 37, 29,
+ 13,165,110, 56,175,230,182,210,136,235,140,226,141,149,172,148, 40,242,164,140,243, 0,115,229,231,167, 83,107,106,201,163,215,
+ 27,102, 59,168,106,161, 80, 68,168, 17,165,168, 14,120,254,244,202,121,148,223, 55,119,212,203,110,165, 63, 53,159, 44,231, 74,
+177,164,138,154,105, 34, 0,200,138, 72,248,250,159,147,183, 77,240,231,146,208,195,153,231, 25, 94, 91, 81, 57,166,167,174,158,
+ 24,157,199, 85, 87,117, 86, 43,125,181, 16,108,183,219, 81, 23,218,248,222,138,101,205,111,109, 53,188,139, 14,206, 6, 92,185,
+106, 97,219,158,165, 20, 33,169,181,218,147,105,229, 75,211,229, 39,172,106,107, 74, 42, 76, 88,249,229,105,177,148,165, 78,169,
+197,168,202, 52, 58,189,201, 45,107,152,251,134, 43,136,241, 26,136,133, 56,212, 96, 73,206, 22, 82,160,183,187,255, 0, 56,129,
+159,230,233,172,181,109,231,101, 77,113,174, 96, 84,151, 11,234, 90,143, 58,214,238,114,165,184,181, 28,173,106, 39,185,234,115,
+211,167, 77,109, 61,163, 22, 44, 22, 27, 91,137, 83,171, 74,128, 82, 1,207,234,158,188,201, 56, 29,255, 0, 15,232,173, 43,102,
+142,152, 57, 86,230,207, 39,153,152,245, 98,109,185,219,238, 30,131, 97,176,176,238, 92,135,135, 96,160,165,130,158,154,139,217,
+233,169,194,164, 80, 40,217, 20, 91,173,247,102, 39,119, 98,117, 51, 18,204, 75, 18,113,157, 88, 27, 77, 6,162,243, 10, 91, 45,
+173,210, 17,204,134,249,192, 79, 80, 63,214,237,246,249, 13,116,123, 98,182, 58, 4, 74,205, 30,167, 79,136,195, 21, 8,242, 27,
+109,110,132, 5, 41, 73, 87,235,167, 43, 4, 56,130,140,228, 96,131,208, 99, 90,225,182, 40, 67,142, 48, 16,148,176,211,139,108,
+165, 13,164, 41,196,146, 1, 0, 28, 0,122,103,200,227, 93, 65,218,186,205,175,107,194, 23, 45,203, 58, 29, 22,218,182, 96, 72,
+174,220,149,170,131,237,177, 22,155, 74,165,199, 84,185,211,101,200,116,132,182,210, 35, 52,242,142, 78,112,156, 0, 78, 6,171,
+ 12,238,173,234,222, 88,228,156,164,106, 9, 35,215,160, 2,195,177, 61,189, 58, 92,224,103,185,230,105,150, 32,167,167,102, 26,
+193, 82, 7,165,183, 6,219, 90,219, 1,190, 56,205,197,103,181,207,127,173, 13,203,184,118,215,133,170,141, 31,104,108,203, 18,
+227,169,219,114,110, 38,173, 59,114,175,120,222, 85,138, 12,199, 41,181,154,156,153, 53,154,123,241,232,148,133, 84,163, 74,110,
+ 60, 86, 88, 82,220,105,176,227,238,146,190, 68,232,182,233,123, 64,184,141,223,154, 60,154, 6,249, 57,181,123,167, 78,146, 84,
+227, 18,107,187, 67, 98, 81,110, 42,116,165, 0,145, 34,159,117,218,148,120,114, 99,114,227,163,101, 42, 70, 84,115,229,173, 86,
+221,155,170, 61,231,185, 27,133,121, 69, 66, 4, 43,174,251,188, 46,104, 37,150,148,210, 87, 78,184, 46,106,173, 86,152,226, 26,
+ 95, 86,138,160, 76,140, 84,147,241, 37, 74, 32,128, 65, 26,194,202,138, 27, 72, 66, 66,146,164,249,147,216,250,231,207, 87, 69,
+ 31, 7,240,224,142,134,170,163, 33,165,108,202, 5, 70, 19,180, 17,154,132,144, 1,186,205,167,154,132, 27,219, 75, 46,158,139,
+101,216,113, 46,113,196, 25,150,101,152,213,213, 75, 88,211,164,146,185, 69, 33, 74, 4,212,116, 0, 45,109,150,194,253, 77,174,
+196,146, 78, 25, 29,226, 14, 57,121,205,113,232,130, 3,142,211,225,184, 35,161,210,251, 60,158, 24,194,153,113, 74, 39,194,232,
+ 48, 51,240,246,211,245,236,251,162,194,185,248,143,179, 45,121, 83, 19, 21,250,213,203,107,181, 9,165, 71,118, 87,191,186,213,
+102, 27,130, 3, 81,152, 66,148,243,239, 41, 41,105, 3, 24, 5,238,101,124, 41, 58,101,247,161,159, 22,181, 69,168, 39, 42,110,
+109, 13,166,193,234, 48,228,124, 36,164,245,239,145,174,129,251, 9,174,186, 5,165,237, 66,225,233,203,134,153, 75,169,179, 93,
+122,232,183,105,102,171, 29,185, 77,211,107,245, 27,114,161,245, 77, 90, 19,110,130,148, 84,153,121,149, 6, 86, 70, 82, 94, 37,
+ 63, 16, 4, 76,106,145,166,225,202,216,163,115, 19,154,118, 0,141,244, 17,182,175, 48,111,179,107,216,131,211,124, 55,240,245,
+ 50,102,121,237, 29, 36,238, 33, 74,218,128,140, 64, 27,115, 13,172,189, 64, 38,246, 91,130, 3, 17,112, 70,216,253, 60,108,203,
+170, 61, 38,218,163, 69,169,210,215, 6,123, 52,168, 12, 42, 18, 30, 74,149, 13, 45,197,109, 30, 2,136,232, 84,156, 96,142,195,
+ 24,211,173, 99,205,135, 95, 67,163,195, 82,216,105,226,174, 71,124,148,149, 2, 51,235,129,141,105, 44, 90,227,175,203,110, 58,
+159, 60,234,145,200,227,139, 86,113,133,225, 74, 81,201,236,156,159,187,231,170, 28, 4,113, 50,246,254,220,188, 78,211, 27,167,
+174,157, 67,217,253,200, 98,198,160, 62,226, 84,149,213,154,110, 59,134, 85, 65, 74, 80,193, 38, 67, 46,128,145,156, 36,167, 56,
+206,171,117,160,130,138,122, 97,237, 82,206,210, 2,164, 74,193,245,233, 0,234, 42, 2,170,144,127,100, 1,189,173,233,213,116,
+ 57, 94,103,152,229, 89,246,102,140,213, 17,228,201, 12,179, 73, 36,128, 58, 9,234, 18,153, 52, 40,182,162,210, 72,183, 8, 0,
+ 85, 5,141,128, 24,234, 84, 22, 97,190,160,211,140,160, 37, 73, 9, 37, 39,151, 35,203, 4,118, 61, 53,114,153, 78,153, 71,107,
+235, 40, 14, 61, 50,158,222, 60, 88,104, 36,186,207,108, 43,161,248,155, 29, 63, 29, 97, 20,201,202, 47,103,152,116,235,202, 79,
+126,158, 94,167,229,242,211,203,110,200,247,142, 86,186, 45, 43, 28,139, 74,199, 69, 36,140, 40, 28,142,185,211,232,142, 26,149,
+210,124,143,250,172, 54, 32,246,233,212,123,143,108, 87, 57,193,168,203, 88, 74,126,186, 30,174,140,110, 24, 27, 95,115,186,183,
+163, 11, 88,251,182, 38, 90,149,147, 81,103, 43,113, 42, 36,101, 41, 4, 97, 63,236,131,246,106, 57,159, 74,191,116, 98, 90,254,
+207, 59, 39,109,189,229, 13,212,183,107,126, 44,232,173, 70, 10, 79,139, 34,151,103,194,170,220, 21, 37, 33, 4,228,182,151, 83,
+ 3,152,129,211,196, 79, 81,158,178, 30,102,146,109,219,145, 41, 96, 40, 65,169, 43,197,142,145,209, 8,117, 68, 7, 25, 3,237,
+ 80, 32,127,181,168, 24,253, 41,190, 42,105,187,177,198, 54,217,240,225,110, 85, 81, 54,139,195,101,145, 34,125,214,152,206, 7,
+ 99,181,184,187,128,182, 37, 59, 9,124,170,199,189,197,183, 98, 83,146,176,122,161, 83, 8, 58, 74, 58,202,145, 17,201,101, 26,
+102,168,170,131, 88,244, 90,105, 22,173,158,223,176,226, 5,136,155, 90,243, 32,234,192, 98, 1,158, 71, 76,139, 85, 95, 79,189,
+ 36,176, 18,155, 91,205, 48,228,232,235,246,147, 91,189,183, 39,148,198,196, 2,113, 23,105, 12,224,142, 92,114,128, 57,115,230,
+ 60,193, 31,158,218,166,220,116, 96,148,167, 35,185, 0, 30,135,231,131,219, 70, 58, 91,112,228,147,129,219,200,129,212,245, 26,
+163,239, 1,162,164,182, 58, 16, 2,148, 48,123,246,233,248,234, 69,123,110, 78,199,253, 49, 95,238,192, 91,182, 41,184,218,146,
+112, 2, 85,145,205,128,115,240,232,117,175,166, 2,185, 84,122,144,123,252,146, 48, 58,249,126, 26,246,165,183,205,207,226,242,
+ 41, 68, 0,146,160, 57,188,186,141, 8,236,164,182,248, 10, 66, 79, 40,192, 24,234, 78, 51,205,246,235, 5,182,178,131,140,233,
+ 61,206, 62, 37, 37,100,130, 84,143, 85, 20,247,251, 9,215,196, 52,218, 22, 28,108, 23, 20, 73, 10, 73, 32, 16, 58,117, 3, 29,
+117,111, 83,203,146,247, 41,116,161,190, 96,162,140,245, 64, 79,113,246,247,209,173,134,220,112, 58,130,174, 68,156, 21, 96,167,
+ 56, 29,142,124,186,235, 23, 38,226,214,237,108, 24, 0, 8,223,231,108, 84,202, 80,181, 45, 75, 37, 10,236,140, 14, 84, 19,208,
+ 21, 19,249,206,145,240, 91, 89, 35, 4,168, 2,181, 39, 36, 1,143, 63,207,219,175, 14,180,248, 91,135,225, 44, 44, 19,203,230,
+113,158,202, 35,190,147, 72, 75,188,184, 10, 97,180,167,149, 94,101, 68,116,193,200,235,219, 67,113,176,234, 62,253,255, 0,241,
+140, 88, 27,158,199,247, 99,223,138,128,176, 16, 74,202,192,200, 64,234, 51,216,159,151,174,144, 56,112,168,255, 0,226,210, 65,
+ 39,211,169,193, 30,191,219,161,201, 91, 97,101, 11,229, 33,124,169,112,164, 97, 67, 25, 41,193, 29, 62,221, 18,149, 30, 64, 28,
+ 41, 83,138,201, 81,233,203,131,211, 7,167, 95,158,178,160,129,238,248, 99, 4, 11,219,211,111,159,187, 23, 91,122,216,174,223,
+151, 45,171,103, 91, 30, 48,173, 94, 23, 45, 2,211,161,169,134,124,101,166,185,117,214,160,219,116, 71, 18,206, 63, 72,148,213,
+170,176,202,135,110, 84,156,234,116,188, 70, 90, 86,214,200,237,141,191,195,253,145, 22, 45, 26,196,217,203, 30,212,219, 59,118,
+140,216, 15, 52,105,182, 85, 52,210,220,144,228,146, 7,188, 57, 58,187, 14,173, 81,121,213,101,199,100, 86,221,117,213, 5,175,
+ 81, 5,246,122, 41,151,120,231,225, 49,165, 45,167, 25, 70,253,237,171,138,109, 68, 6,138,152,185, 35, 72, 66, 58,164,128, 60,
+ 86, 81,140,142,248, 24,212,167,184,174,185,213, 80,146,133, 73, 46,189, 42,116,101,176,243,171,116,136,206,165, 92,181, 24,242,
+ 29, 66,122, 56,175,137,244, 12,128,174,102,202,115,202, 19,170, 83,197, 9,101,168,206,184,107, 46, 36,242, 99,215, 57,177, 27,
+176, 33,119, 7,246, 0,242,159,241,145,183,126,148,250, 56,229,176,205,157, 87,230, 36, 3, 52, 82, 67, 18,237,186, 42,142,113,
+ 96, 78,222,114, 22,253,238,138, 65,198,134,236,221,125, 48,227, 85,230, 51, 33,182, 20, 46,139,193, 78, 71,146, 11,172,173, 49,
+107,213, 39, 22,218,176, 65,104, 45,181, 17,240, 28,231, 10, 57,192,214,224, 91, 87, 56, 52,186,124, 87, 37, 60,195, 17, 27,114,
+181, 86,168, 52,165, 33,208,211,232, 84,135, 35,180, 82,172, 45,194,149, 57,206, 62, 17,225,181,156,149, 19,174,110, 88, 21,191,
+119,114,244,165,183,202, 67, 27,155,118,199, 87, 58,178, 4, 89, 50, 96,212,208,176,140,117, 30, 4,208, 18, 6,122, 47,168, 24,
+193,216,148,220,233, 17, 19, 8, 58,234,126,185,152,195,115,214,218,208, 94, 77, 49, 13,178,244,133,248,196, 0,223,193, 29,180,
+ 33, 36,116, 68,133,242,242,101, 71, 81,250,188,185,106, 15, 67,113, 99,239,183,107,245,232, 9,183,107,219,224, 58,227, 63,165,
+142,190,158, 48, 77,158,254, 98, 55,217,118, 36, 14,246, 5,200, 7,112, 64, 22, 35,166,219,210, 47,185, 82,233, 80,131,107,114,
+ 60,217, 83, 30,159, 55, 1, 97, 10,126, 99,143, 59,200, 93, 39, 36,248, 79, 52,216, 74,146, 85,208,149, 28,227, 87, 58,150,229,
+ 67,154,202, 4, 96, 35, 72,171, 77,110, 44, 73,100, 36,180,229, 58,157,136,136, 91,136, 10,230,111,157,193, 37,215, 17,208,101,
+244,168,228,117,214,181, 64,187,158,122, 93, 82, 99, 15, 54,251, 37,214,153,128, 31,117, 72,105,199, 39,177,225, 23,146,164,156,
+ 48,194, 20,135,157, 91,128,140, 41,148,243,100, 17,156, 82,117,230,220,185,110, 46,150,234,204, 86,210,213, 38, 18,207, 68,178,
+246, 20,194,221,232, 57,159, 45, 69, 67,133, 75, 72, 8, 74,217, 4,243, 28,107, 65,114,134, 28,192, 19, 72,150,215,216,116,216,
+247, 29,143,240, 35,215, 20,246,103,146, 44,245, 78,252,176,174,237,171, 80, 54,208, 8, 14, 67, 30,182, 4,169, 0,130, 8,141,
+150,215, 27,108,165, 82,240, 65, 91,130, 60,226,182,132,167,101,192,151, 29,238, 83, 25, 20,197,120, 81,158, 74,218, 87,253,240,
+ 30, 74,156, 5, 56, 40, 82,144, 70, 78, 52,237, 90, 94,211,206, 31,238, 61,215, 87, 13,251,187,120,211,246, 99,125,216,166,219,
+ 53, 27, 46, 70,225,213,169,180,173,188,223,218, 29,126, 20,116,211,238, 11, 14,254,117,214,224,219,183,114,235, 2,165, 77,157,
+110,215,151, 5,255, 0,172, 41,143, 26,124,233,201, 95,132,215, 47,235,155,134,253, 49,169,137,139, 33, 17,217, 13,120,112, 82,
+ 15, 49,240, 35, 44,163,195,112,169, 32,252,110,120,100, 14,255, 0, 6, 84, 78,117,197,111,105,134,220,238, 93,231, 65,219, 45,
+247,167,109,213,197, 90,217,251, 58,155,114,237,149,225,186, 16,105,102,169,111,209,111, 26,133,206,237,223, 6,220,186, 37, 68,
+ 46, 57, 71, 74,105,117,120,239,199,126, 99, 76,195, 90,234,170,101,153, 10,125, 14,182,139, 3,128,178,227, 14,113,200,102, 49,
+197, 94,146, 41, 26,186, 58, 14,100, 76, 1, 54,102, 4, 50,105,239,205,107, 48,109,241, 25,226,106, 58,222, 29,225,154,236,230,
+154,152, 85, 54, 88,209,177,136, 41, 60,216,218,101,137,193, 42, 24,198,232,143,175, 85,138,168,137,139, 93, 73, 6,112,183, 37,
+ 78,163, 2, 75,208,150,135,161,212, 82,216,153, 17,169,141,173,151,176,166,195,172,115, 50,232, 25,142,243, 42,192, 88,248, 20,
+135, 67,169, 82,146, 1,214, 30,110,102,229, 6,164, 37,229,248, 15,167,153, 14, 21,167,199,131, 45,149, 41,178,218,193,232,133,
+ 37,208,234, 20,133, 14,138, 74,146,161,200,172,136, 53,240,131,237,106,226,159,133, 24, 84, 59, 53,218,219, 59,239,178, 52,133,
+176, 33,109, 62,233,213, 42,115, 87,110, 83,210, 19,207, 27,108,183, 21,133,187, 86,176, 89, 90, 16,222, 98,161, 83,232,235, 9,
+248,233, 74,207, 48,145,223, 13,254,212,238, 15,184,152,159, 78,162,209, 47,183, 54,118,249,175,188,219, 14,237, 94,249, 74,164,
+218,245, 37, 92, 79,169, 49, 99, 27, 63,112,216,112, 91,183,164,105,106, 74, 80,226, 84,253, 38,123,107, 83, 14,125, 94,162,183,
+ 66,108,186,204,183, 48,166,102,149, 71, 62,156, 30,169,168,233, 30,174,159,105, 0, 23, 14,192, 50,168, 43,245,131, 77,196, 95,
+135,248,215,135,243,244,142, 40, 42,125,147, 48, 63,251, 60,246, 73, 9, 31,170,141,253,220,164,236, 80, 35,107,102, 86, 28,176,
+ 93, 65,235,149, 54,227,231, 82,252, 98,143,120,111, 30, 50, 3,153, 10, 74,242,148,190,207, 95,141,149, 1,219,201, 64,160,158,
+157, 92, 10, 45,120, 41, 72, 30, 42,210,211,129, 60,138, 36, 39,194, 40, 56, 9,201,199, 34, 15,194, 82,125, 71, 47, 98, 51,173,
+ 78, 57, 42, 4,150,225, 74, 68,136, 85, 24,204, 38, 66, 27,148,194,153, 91,140, 60,112,210,188, 53,165, 42, 92, 71, 18,144, 65,
+ 31, 2,199, 43,141, 41, 93, 9,204,232,245,213, 45, 41,192, 82, 28, 24, 15, 5,245, 67,125, 1,240,211,143,214, 37, 36, 97, 93,
+148, 8, 56, 7, 58,212, 89, 53, 45,155,126,155,250,244,189,247,220,131,214,195,222, 7, 80, 36, 83, 0,111,109,143, 66, 55,176,
+233,219,176,244,244,232,113,182,208,103, 41,109, 2,130, 8, 28,170, 10, 7, 24, 72, 25,194,155, 35,170,130,179,216, 16,115,215,
+ 3, 58,111, 43, 10,114,143, 57, 62, 8, 83,116,247,138,158,104, 35, 42,247, 7, 50, 75,237, 35, 36,226, 62, 87,206, 17,241, 16,
+ 21,132,140, 32, 1,125,182,231,180,168, 76, 58, 9, 40, 84,116,130,133, 30, 98,133, 5, 4,164,144,145,213, 29,122,131,213, 61,
+ 0, 36, 29, 13,118, 6,157,142,165,164,161, 74, 66,131,137, 36, 16, 75,137, 11,198, 66, 58, 1,225,133,117, 7,177,199, 76,105,
+179, 52,167, 21, 20,206, 20, 94, 88,188,203,247, 14,159,247, 13,175,219, 99,141,204,138,188,229,245,233,172,222,154,164,132,144,
+123,143, 71,223, 96, 84,155,244, 59,106, 94,135,127, 84,218,177, 40, 8,109, 77,171,152, 21,173,176,163,224,169, 71,153, 72,125,
+ 10, 73,232,160, 71, 80,122,228,147,140,224,235, 37,102,160, 10, 82,164,185,132, 45, 57, 74,215,202,149, 96,228, 37, 5, 93, 73,
+ 30, 65, 68,115, 96,128, 73,233,134, 98,157, 41, 13, 56, 75, 78,101, 30, 32, 41,200, 60,139,109,106, 31,174,223, 79,137, 36, 30,
+189,207, 76,140,117,214, 72,221,101, 45,182,162,165, 36, 32,100,243, 41, 75, 81, 70,115,204, 0,245,193,235,219, 60,157,117, 24,
+134, 67,166,254,131,225,214,223,195,240,185, 63, 9,141,122, 6,118, 85, 58,239,247, 92,246,191,191,212,255, 0,166, 51, 26,229,
+207, 71,161, 82,171, 21,250,253, 86, 21, 10,222,160,210,170, 53,218,245,110,162,164,183, 78,161,208,104,176,228, 85, 43,117,153,
+206, 45, 73, 9,137, 18,151, 18, 91,238,228,225, 72,142,160,158,165, 57,252,241,248,236,226,198,175,198,143, 19,187,139,190,210,
+211, 34, 37,167, 54, 67, 54,134,209, 80, 36, 40,149, 91,187, 67,106, 59, 42, 29,153, 29,224, 82, 63,247, 86,123, 78,203,172, 84,
+ 21,128,163, 54,224,117, 10,232,210,117,219,143,110, 55, 31,168,247, 9,220, 13,237, 45,117,106,153, 60, 65,155,196,245,118,153,
+ 33, 73,250,186,148,129, 22,167,110,108,123, 50,218, 88,204,249,174, 8,181, 59,157,180,158,102, 99, 49, 2,144,247, 42,222,154,
+216,140, 58,201, 42, 87, 55, 92,245, 24,242, 62, 93, 51,208, 99, 86, 23, 10,101,174,168,115, 74,133,179,204,161, 98, 4,110, 35,
+184, 38, 79,255, 0, 83,109, 63,224, 1,129, 34, 76,115,135,139, 28, 75, 29, 69, 68,124, 51, 69, 46,168,168, 95, 93, 91, 41,184,
+105,192,178, 67,126,252,133, 36,200, 55,250,214,208, 64,120,119,164,226,207, 66, 6, 58, 99, 61,253,127,110,168, 40,146, 14, 79,
+145, 3,176,234,117,236,175, 32,140,119,245,254,173, 14,178, 50, 7,166,115,251, 53, 54,197, 56, 6,195,215,223,143, 26, 25,222,
+163,190,112,127,103, 95,199,190,136, 80, 4, 28,249,117,233,242,208,171,236, 62,223,191, 74,170,144, 55, 30,252, 27, 3,172, 12,
+ 19,233,219,241, 26, 21,194,122,100, 96, 15, 50,122, 99,167,203, 68, 45, 88, 7,168,198,127, 12,119,207,207, 39,246,104, 39, 14,
+ 65,238,122,244,207, 92,117,243,209,240, 49, 73,194,122,158,135,167, 78,221,191,225,160,214, 70, 49,230,127,175, 85,214,124,179,
+246,254,237, 12,162,115,131,131,230, 15,203, 74,168,176, 3,231,255, 0, 56, 24,164,161,156,124, 57,251,241,165,175, 42, 81, 4,
+128,123,105,104,248, 61,215,161,234, 61,195, 9, 4, 17,131,140,142,223,159,183, 85, 65,193, 7,254, 56,208,233, 56, 57,252,117,
+ 84, 28,245,242,237,243,207,245,104, 16, 14,221,176,115,176,176,216,246,251,173,130,144,113,212,117, 31,209,147,251, 52, 64, 81,
+ 7, 3, 57,199, 92, 12,227,237,208,169, 35,151, 56,237,220,122,227,174,171,161, 97, 64, 96, 17,233,247, 31,233,206,144, 35,125,
+251,225, 50, 15,218,181,186,127, 44, 28,217, 61,137,207, 79,219,211, 69,160,115, 4,228,115, 96,228, 12,227,183,110,191,142,129,
+ 66,176,164,143, 53, 1,246,117,209,136, 61,199,167, 81,162,144, 13,182,219, 5,193,232, 56,201, 61,187,103,231,233,170,157, 57,
+128,201,237,219,190,122,158,195, 61,244, 58, 14, 70, 85,219,229,220,254, 78,137, 78, 6, 9,248,142, 58, 30,199,229,215, 73,176,
+ 32,251,176, 49, 85,178, 80, 71, 49, 24, 29,179,128,122,159,234,206,170,161,228,172,227, 5, 63, 51,208,106,130,129, 57, 36, 12,
+ 43,246, 12,103,250, 53,245, 33, 41, 28,169, 39,168,200, 39,169,243, 62,154,215,113,110,214,192,193, 69, 75, 80, 41, 11, 40, 72,
+242, 79,235, 44,117,198, 14,142,138, 84,193, 74,208,181,165,208, 82,164,172, 44,165,214,212,133, 5,182,227,107, 79, 84, 56,149,
+ 0, 82, 71,108,122,116,213,184, 21,116, 32, 12, 36, 16,175, 92,121, 99,240, 58, 41, 11, 82,192,198, 50,156, 1,158,159,143,207,
+ 73,144, 8, 32,238, 14, 5,200, 32,131, 98, 8, 32,251,198,227,247, 28,108, 53,141,190,213,107,108,134, 43,180,182,171,204,124,
+ 41, 19, 35, 60,136, 85, 18,145,128, 11,205,175, 13,186,160, 60,210,164,149, 28,156, 13,108,141,181,197, 54,220, 70, 82,197, 66,
+151,116,195,121, 72,202,146,221, 49,185,109,229, 32,244, 75,141, 75, 60,221,199, 95, 93,115,201, 4,164,124, 94,189,207, 82, 7,
+168,253,186, 37,176, 66,144, 22, 84,164,142,169, 32,227,161,236, 8,243,244,251,245, 28,174,225,188,174,181,153,164,137,162,103,
+235,203,114,160,244,191,151,117, 31,114,140, 91,121, 55,141,220,125,147,211,199, 74,107,169,243, 88,225, 80,170,107, 41,214, 89,
+ 52,139, 90,242,161,142, 87, 35,177,119,115,110,248,235,133,191,199,206,218,219, 45, 52,170,125,157,118,214,229, 55,146,132,186,
+136,148,166,213,201,219,244,179,102,224, 18, 71,250,170, 3, 29,180,196,241, 5,199, 86,232,111,197, 1,251, 8, 50,221,147,182,
+143, 56,211,211,237, 58, 60,167,100, 74,185,156,140,226, 94,138,213,215, 87, 83,109,251,229, 61,183,144,219,158,226,195,104,140,
+227,141,161,111,151,249, 82,145,162, 3,148,130, 92, 5,192, 20, 20,148,231,148, 55,212,227, 4, 14,186, 61,162, 86,176,146,225,
+ 80, 56,228,194,113,201,219,161,207,235,116, 56,211,117, 47, 5,112,245, 21, 84,117,201, 69,207,170,132,134, 71,149,218, 77, 12,
+ 8, 33,149, 73,229,134, 82, 46,173,163, 82,145,169, 72, 32, 28, 53,241, 15,138,188, 97,196,116,243, 82,213, 84,195, 69, 77, 80,
+ 10,200,180,176, 44, 69,212,245, 83, 35, 25, 38, 10,219,134, 85,145, 85,193, 42,192,169, 32,158,135, 75,235,241, 20,165,243,156,
+130,149,228,227,191,234,252,191,175, 69, 53,226, 20,169,146, 9, 42, 80, 87, 50,134, 0, 79, 79,192,118,208,142, 44, 52,130, 84,
+175,137, 56,248,146, 49,143, 64,122,117,233,170,145,222, 81, 66, 66, 73,248,178, 73, 87, 82, 79,108, 12,246, 29, 53, 36, 61, 54,
+ 29, 62, 70, 43, 94,183, 35,123, 91,175,205,241,136,238,148, 54,166, 91, 20,250,139, 88, 47,209,166,170, 59,233, 79,254, 76,255,
+ 0, 80,172, 99,160,230, 39,240, 58,198,120,103,221, 57,187, 25,196,150,199,238,244, 21,134, 94,176, 55, 62,210,175,186,181, 28,
+ 15,112,143, 87,142,138,146, 84,113,217, 84,215,101, 39,255, 0,165,167,117,218,108,106,205, 62,177, 68, 90, 2, 93,157, 79,120,
+165, 71,245, 68,134, 82, 86,218,243,228,123,254, 61,245,167, 85, 38, 11,109,188,210,135,233,152, 91,140,184,160,122,120,145,212,
+ 83,145,142,255, 0,171,251,117,187, 66, 18,104,170, 41, 36,251, 18,234, 83,255, 0, 68,162,196,254,253, 93,251,227, 20,149, 82,
+101,249,133, 45,100, 91, 73, 4,145,202,189, 62,212,108,174, 63, 16, 49,250,180,211,238,200,245, 37, 67,171,211,156, 15,194,174,
+ 65,129, 89,167, 45, 4, 20,189, 10,173, 21,153,145,214,133,121,160,178,242,122,249,231,190,180,239,217, 89,188,242,168, 28,101,
+113,223,195, 53, 74,165, 21,248,241,110,200, 59,151,105, 48,148, 54,212,150, 99, 85, 66, 25,171, 70, 90,211,133, 72, 8,121,198,
+149,215, 37, 35, 61,129,214,138,112,241,237, 18,181,246,247,217, 85,195,199, 23, 55,221,185, 92,188, 87,110,170,222,216,155,158,
+135, 70,113,168, 85, 74,133,213, 66,154,237,182,137,209,228,212, 2, 90,247, 81, 18, 12,119,150,178,172, 40, 40,165, 36,172, 99,
+ 92, 76,225,195,218, 43,112,108,191,180, 68,241,163, 87,137, 53,218, 13,213,121, 85, 13,251,109, 69,117, 79, 59,252, 93,220,210,
+ 61,214, 85, 57,148,140, 9,179,169,240, 12, 87, 90, 24,253, 35,176,207, 39, 85,140,213, 94,201, 95, 89, 89, 81, 50, 68, 88,229,
+ 41, 44, 77, 97,114,211,137, 33, 50, 70,130,251,177,141, 24, 11,126,210,130,124,216,234, 92,247,139,178,110, 30,135,135, 86, 26,
+240,171,156,212, 69, 53, 68, 96, 18, 70, 89, 60, 14, 18, 89, 46, 45,161,102,104,166, 0, 18,247,167,107, 0, 6,255, 0,166, 5,
+ 42,103, 57, 65, 82,185, 64, 32,133,247,194,134, 58, 28,253,191,183, 79,189,167, 40,130,133, 15,136,130, 15, 48,207, 92,244,234,
+ 62,127,191, 90,215,182,213,122, 45,249,108, 90, 55,197,175, 49, 85, 11, 94,248,160,211,110, 91,114,123,145,228,195, 92,170, 77,
+ 82, 51,114,163, 41,232, 51, 90,109,232,174,134,220, 0,165,196, 37, 67, 29,181,181, 22,173, 32,176,218, 22,172, 0, 58,144, 15,
+ 48, 35,161,232, 51,211,182,149,165,204, 0,210,250,182, 96, 8, 55,216,131,107, 17,234, 8,177, 7,208,223, 12,252,106,244,209,
+ 69, 44, 79,229,112, 89, 74,158,160,131,165,148,142,161,131, 2, 8,234, 8, 32,216,139, 99, 84,189,166, 92, 73, 94, 92, 36,240,
+ 71,190, 60, 72,109,253,170,139,190,243,218,251, 81,202,181, 6,152,247, 63,185,197,151, 53,246,105,136,172, 84, 2, 7, 50,224,
+ 67, 84,180,200,117, 35, 4,165,140, 2,158,227,242,123,220, 13,193,188,183,102,246,187, 55, 70,255, 0,174,202,185,175,125,193,
+184,106,119,117,217, 95,154,225, 92,154,165,106,179, 33, 82,165,200, 61,127, 70,202, 74,130, 26, 64,248, 91,109,180, 33, 32, 37,
+ 35, 95,176,103, 17, 91, 65, 79,226, 3, 96, 55,155,100,106, 73,104,195,221, 29,180,188, 44,162,167,194, 11, 49,228,215,104,147,
+ 33, 65,146,176,160, 71, 43, 83, 28, 97,207,145,107, 58,252,126,111,173,183,174,109,101,223,114,237,205,200,243, 14, 87,172,107,
+134,183,104, 86, 21, 21,196,191, 31,235, 27,118,163, 34,153, 41,108, 62,142,143, 50,181,199, 42, 74,135,250,248,242,211,205, 11,
+ 23,205,103,169,168,185,146,170,158, 46, 83,159, 68,102, 90,132, 67,211,202, 69, 43,202,122,183, 50, 37, 98,121,105,106, 87, 55,
+ 74,198,201,233,231,141, 79,232,234, 57,204, 82, 16, 6,132,158, 85, 50, 83,153, 27,174,169, 99, 74,129, 10, 55,149, 68, 19,180,
+118, 47, 41, 56, 67,100,168,171,151,155, 61, 79, 95, 60,122, 15, 61, 35,130,164,243, 43,195,200,232, 85,144,149, 30,190,103,160,
+235,163,138, 10, 81,148,161, 61, 1, 57,207,196, 1,237,229,215, 58,179, 73, 73,100, 1, 32,169,109,175, 10,108,133,117, 65, 61,
+ 64, 35,211,190,164, 33, 71, 78,184,138, 6, 12,221,108,127,211,249, 99,203,205, 18,188,146,148,164, 30,157,114,114, 49,212,122,
+121,235,227,237, 45,212, 2, 7, 84,167,184, 57,230,251,255, 0,214,210,105,196,231,225,201, 72, 78,112, 71,161,193,239,249,235,
+162,163, 54,227,231, 9,229,102, 56, 25, 86,126, 37, 18, 58,142,158,154, 26, 64,223,165,177,147,211,115,112, 58,252,252,223, 22,
+213, 70,117,150,146,176,201, 81, 88,230, 39, 35,152, 1,253, 61,115,159,248,104,168,146,144,231,232,202,255, 0, 85, 56, 40,229,
+ 0, 30,157, 78,124,245,114, 83, 5, 65, 72, 11,202,122,142,131, 4, 30,196,245,208, 41,136,220, 55, 57,130, 80,160,172,229, 74,
+ 5, 71, 24, 57,192, 61,188,255, 0, 13,102,195,174, 10, 13,246,245,219,231,231,243,194, 75,106, 66,138,139,202,121, 62, 73, 39,
+ 41, 64,244,249,235,195,175,165, 29, 16,164,129,215, 3,176, 10,244,237,242, 58, 13,247, 86, 20,162,210,241,205,219, 9,199, 76,
+118, 57,252,252,244, 57,121,183, 22, 18,162,114, 8, 46, 36,167,166,122, 30,132,122,147,160, 1, 61,122,224,218,109,176, 59,124,
+252,244,193, 73, 62, 42,249,210,160,160, 6, 10, 58, 4,243,117,237,215,174,169,202,116,144,148,163, 9, 35, 41,232,112, 73, 35,
+ 26,244,226,149,225, 44, 52,218, 83,202, 50, 6,112, 73, 3,166, 20, 60,186,106,200, 38, 56, 22,159, 25, 41, 42, 74,136,229, 35,
+ 39,237,230, 7, 25, 25,253,154,205,172, 79, 99,140,129,115,240,254,120,124,184,115,189,156,218,173,243,217,253,196,140,226,154,
+114,201,221, 29,189,186,157,144, 2, 28, 76,104,148, 91,202,137, 62,170,234,144,226,146, 10, 19, 71,106,164, 78, 72,192,235,229,
+214, 89,252, 84, 79,135, 38,165, 91,167, 64,144,125,222, 21, 90, 83,212,194, 9,203,148,103,102,202,149, 75,147, 29,226,231,198,
+199,134,165,180, 86,174, 83,250, 48, 82,145,204,117, 12,134, 36, 32, 58, 89,144,219,141, 68,148, 28, 97,215, 25,112,135,124, 41,
+ 13,150, 30, 13,148,156,182,191, 13,197,224,142,160,224,143, 93, 73,106,193,222, 9,123,221,195,158,213,110, 37, 84, 5,220,177,
+173,145, 99,221,170, 9, 90, 82,245,211, 97, 33,139, 66,186,235,106,113, 41, 18, 89,144,221, 38,151, 80,109,206,169,241,170, 79,
+ 3,133,165, 68,213,126, 32,229,133,243, 12,131, 53, 81,228,136,205, 3,157,175,169,213, 36,139,223,107, 71, 40,244, 5,135, 82,
+109,142,146,250, 55,230, 49,199,158,230,217, 92,205,165,166,142, 42,152,199,111,171, 99, 12,173,241,188,212,235,255, 0,117,239,
+229,177,215, 10, 45,116,211,119, 43,112,233,170, 37,182,230, 76,183, 43,177, 16, 48, 67,141,212,104,203,167, 84, 84,210, 85,250,
+200,247,186, 39, 42,135, 76,169,127, 17,201, 25,126, 41,181,229, 37, 94,246,130,227,139, 83, 98,158,134,210,180,160,134,139,132,
+169, 8,228,234, 57,157, 60,196,119, 33,160, 58, 3,173, 54,220,106,162,232,187,147, 64,173, 32,128,221,114,157, 86,182,101,168,
+ 2,112,236, 98,110, 58, 71, 42, 0,200, 82,156,139, 85,108,168, 12, 37, 47, 14, 99,215, 89,237, 42,241,122, 42, 89,121,149,120,
+143, 68,240,228, 71, 67,193, 97, 42,112, 20,248,104, 82,146, 14, 81,149, 36, 43, 61,130,149,202, 79, 77, 54,154, 98,201, 79, 48,
+ 93,157, 23,215,245, 64,140,254,242,183,247, 3,113,214,216,234,185,107, 85, 90,190,153,200,103,134, 73, 8,185,181,196,141,207,
+ 0,122,217, 95, 77,199,166, 54, 18,161, 94,151, 79,143,238,201, 90,156, 74, 11,144,195, 67, 45,167,222,100,242,185, 41,107, 79,
+ 47, 68,161,128,211, 94, 17, 4,143,139,237,214, 33, 94,188,163, 65,166, 48,194, 95, 91,117, 54,202,144,132, 54,165,128,183, 95,
+199,188,184,162,159,133, 33, 12,114, 39, 3,184,113, 99, 62, 90,108,110,125,200,155, 57,192,243,237, 54,135, 98, 37, 65,105,104,
+184, 83, 38, 67,170, 74,157,117,106, 82, 65,231, 43, 42, 36,158,164, 28,103,182,152, 91,179,113, 22,203, 82, 31,144,227,141,177,
+ 29,133, 60,243,188,138,117,126, 27,202,229, 79,134,132,140,173,213,186,224, 64,230, 35, 28,249, 82,146,156,168,109, 83, 80,180,
+133, 70,155,131,247,250, 91,173,253,215,233,123,143,190, 31,153,230, 40,116,234, 94, 76,155, 11, 13,199,112,250,136, 0, 48,181,
+193, 30,164,142,215, 14, 21,209,121,205, 91,172,198,128, 37,214, 37,203,151, 18,147, 71,162, 69, 74,158,159, 91,173, 84, 31, 76,
+ 74, 61, 38, 10, 82, 57,149, 46, 76,199,210,132, 36,116, 79,141,204,122, 13, 72,111,103,182,153,253,140,217, 59, 59,105,234,166,
+ 43,245,214, 40,146,102,238, 75,165,136,243,169,213, 75,230,241,120, 86, 47, 54, 36,211,230,178,227, 21, 26, 75, 53, 55, 26,167,
+ 24,207,180,236,119, 35,210, 16, 22,218,146,117, 21, 91, 99,137, 58,134,192,111, 54,211,110, 76,122, 84, 42,181,197,100,221,246,
+174,224,205,167, 84,216, 19,169,212,123, 66, 37, 89, 42,151, 77, 97,181, 39,195,159,114, 79,128,212,245,169,240, 22,212,111,116,
+105, 13,225, 69, 58,152,173,218,236, 42,179,108, 87,233, 14,186,253, 46,181, 6,157,112, 82, 30,120, 56,211,238,209,110, 10,124,
+106,204, 5, 62,219,128, 41, 18, 61,194,107, 60,193, 64, 44, 45, 4, 30,186,117,106,119,163, 48,188,177,253, 92,232,116, 31,218,
+177, 26,182, 29, 0, 5,108,118, 44, 24,145,181,142, 35,114,231,116, 85,239,152,101,148,181,162, 92,195, 43,146, 35, 87, 18,135,
+188, 13, 42, 22,128, 23, 42, 35, 98, 66,200, 24, 35, 57,137,208,164,161, 30,202,120, 41,197,183,177,147, 96, 55,194,117, 82,245,
+225,250,163, 11,134,125,197,158,169, 14,206,182,216,166, 75,169,236, 93,114,190,156,248,141,189,108,196, 90,166,237,169,121,196,
+181,250,106, 40,147, 79, 30, 49,116, 81,219, 78,117, 26, 30, 33,248, 90,223,142, 22,238, 53, 90,251,235,183, 21, 75, 77,169,146,
+228, 66,162, 92,232, 13, 87,118,250,239,240, 22,241, 75,150,189,233, 78, 11,167,214, 10,153, 99,198, 17,203,141,204,109,181,161,
+ 79, 69,104,144, 53, 62, 58,210, 27,142,235,239, 21,135, 25, 12,160, 78,108, 32,130, 2, 20,150,218,156,215,108, 60,148,173, 41,
+ 88, 7, 42, 65, 24, 28,201, 25,193,174,203,122,131,116,219,213,139,110,241,182,232, 55,173,161,112, 70, 84, 43,170,207,186,169,
+ 84,234,253,183,113,211,152,109, 97, 46, 84,104,245, 86, 28,142,237, 70, 59, 5,226,196,128,132,200, 66, 22,182,154,125,146, 80,
+180,201,178,222, 38,170,167,211, 29, 71,246,200, 86,223,104,218, 69, 29, 1, 87,177,189,186,233, 96,214, 30, 85, 40, 0, 56,170,
+184,143,195,156,143, 60, 18, 84, 69, 23,232,156,193,247, 18,194,160, 70,237,183,247,176,221, 84,146, 79,219, 83, 27,110, 29,203,
+146,109, 13, 30, 23, 61,163, 28,100,240,219, 38,149,107,237,182,228, 73,189,236,148, 58,150,218,218, 61,216, 67,151,221,136,166,
+144,210, 25,240, 41, 6,169, 45, 53, 11, 53, 66, 58, 57, 80,186, 76,248, 97,190, 98,160,218,142,164,109,178,158,214,237,167,175,
+ 65,161,127, 41,109,181,191,248, 74,174, 85,212,196, 72,247,141,118,159, 86,189,184,118,184, 38, 56,243,200, 67, 20,205,205,163,
+ 65, 92,187,103,244,108,243,134, 42,113, 37,120, 42,121, 41,114,160, 80, 84,117,167,220, 73,251, 19,182,242,247,150,245,217,194,
+ 29,220,173,162,186,165, 45,185,180,237,176,187,166,214,235, 27,115, 85,154,242,203,141, 53,105,221,169,247,138,213,131, 33,111,
+ 58, 60, 24,243, 19, 85,132,218, 80, 19,227,198, 71,195,173, 7,218,190, 57,120,161,246,121,238,117,107,135, 46, 42, 54,246,212,
+222,125,182, 66,215, 76,220,221,149,190,133,155,115,191, 81,182,165,170, 84, 41, 82,173,155,198,146,212,216, 50,159,240,155,121,
+200,241,235, 44, 76, 97,206, 80,135,152,140,178,151, 90,121,170,146, 44,222, 17, 46, 79, 77, 21,101, 90,144,210, 68,210, 26, 90,
+141, 23, 26,157, 24, 36,177, 72,226,224,221,193, 66, 60,166,100, 39,106,230,105,184,247,129,158, 20,172,144,102, 25, 56, 96,130,
+ 73, 11, 77, 13,172, 72, 85,114, 4,208,176, 63,238,220,198, 0, 12,193, 90,219,205,107,111, 55, 22,222,185,109,106, 77,203,105,
+ 92,212, 27,170,209,172,183,227,209, 46,123, 90,179, 79,185, 45,186,219, 47,160, 44, 55, 78,175, 80,230, 63, 25,215,130, 20, 20,
+227, 72,116,188,206, 64,121,180, 19,141,103,175, 87,204,134,148,133, 47,152,148,124, 42, 90,135, 81,202, 0, 79, 42,142, 57,128,
+233,159,246, 64, 39, 57, 58,138, 47, 16, 27, 71,120,112, 95, 98,211, 61,164, 94,203, 13,207,174,217,124, 50,238, 29,187,102,110,
+ 70,229,240,243,119,189, 42, 85,155, 77,162,222,245, 72, 16, 41,117, 22,108,155,169,231, 90,184,109, 7,235, 46,162,151, 58,152,
+243,203,175,208,101,130,245, 6,171, 58,144, 89,145, 18, 68,155, 3,127,214,247,155, 98,118,115,120,231, 91,109, 90,114,247, 99,
+108,236,173,194,145,108,177, 83, 77, 90, 45,188,253,219, 67,139, 87,122,147, 14,164,243,190, 44,248, 45,185, 37, 98, 59,143,101,
+242,194,155, 18, 15,188, 7, 73,143,214,196, 35,167,138,170, 9,185,212,211, 51, 37,153,116, 75, 28,128, 41, 49, 75, 29,205,152,
+ 95,170,150, 83,177,218,235,123, 43,134,115,213,207,218, 72,189,141,233,170,169,213, 93,148,221,209,145,142,149,120,220, 40,189,
+200,177, 4, 41, 27, 0, 8,185,198,215,109,149, 22, 37,219,112, 75,167, 73,165, 92, 21,191,118,183,110, 26,195, 20,107, 85,228,
+ 68,174, 84,165, 82,105,206,202, 98, 44, 87, 92,162,212, 48,165, 45,180,169,192,152,142,168,161, 4, 36, 36,229, 99, 64, 56,226,
+223, 77,219,218,203, 74,243,176,184,111,131,100,212,184,131,106,210,106,188,182,174,237,198,176,104,236,108,117, 26,191,107,238,
+ 45,231, 67,159,114, 83,238, 42,188, 53,220, 59,203, 46,201,218,125,206,169,219, 54,146, 99,166,100,164,216,146,234, 18,227,161,
+ 2,157, 2,167,204, 14, 62, 61,170,123,199,195,134,245,239, 23, 13,187,105,102,194,182,165, 83,246,238,171,105, 84,183, 81, 53,
+244,170,245,137, 87,220,107, 45,183,233,117,187, 54, 41,166, 73,133, 64,143, 76,250,217,135,130,156, 67,211,229, 61, 20,165, 50,
+ 32,160,164,235,150,155,127,199,229, 2,218,166,220, 17, 47,141,155,184,239,201,213, 27, 39,106,105,180,122,212,125,229,250,134,
+170,214,227,109, 78,199,111,230,200, 68,190,174,249,149,109,181,172,187,121, 82,106, 16, 56,129,184, 42,147, 41, 97,218,124,229,
+ 79,183,224, 36,215,213, 28,203,110, 70,206, 69,195,144, 85, 69, 5, 70, 98,154,105,203, 23, 84, 82, 9,145, 88, 2,188,203, 43,
+ 29, 22,223, 64,107,155,217,130, 11,134,211,227, 63, 18,206, 91, 83, 89,150,100, 83,153,115, 5, 2, 9,166,100,112, 41,101, 77,
+ 75, 50,195,172,141, 83, 43,150, 83, 39, 47, 66,149,186, 60,183, 82,141,110,225,240, 39,196,221,155, 81,191,231,222,141, 89,213,
+ 55,237, 88,247,245,205,127,221,171,222,173,181,185, 61,226,240,182,175, 86,237, 91,186,211,159, 89, 98,236,113,202,246,245, 75,
+190,106,209,152,110,218,100, 61,112, 84, 36,212, 28, 91, 16, 22,220,105,170,139,127,159,236,242,222,186, 77, 26,239,166, 87,232,
+112,233,215,213,183,115, 90,106,118,188, 55, 27,106, 92,217,154, 61,128,237, 3,137,199,119, 10,177,114,223, 77,221,139, 75, 53,
+122, 53,223,195, 53,253, 73,112, 71,241, 98,181, 54,200,172, 83,221,113,115,223,163, 51, 57,230,147,199, 5,183,187,182,199, 20,
+139,188,118,233,203, 98,159, 84,186,183,115,137, 91, 34, 52, 27,238, 84,170,188, 61,236,220, 94, 32, 44,203,171,108, 40,237, 75,
+107,110, 95,141, 88,160, 80,145, 95,186, 77, 97,137,205, 83, 25,174,211,162,188, 99, 84, 40,149, 52, 64,143, 46,157, 75,218, 83,
+101, 77,186,105, 19,162,236, 45,249,108,218, 84, 43,254,198,220, 58,109, 34,211,226, 14,155, 2,237, 19,173,203,215,141, 77,199,
+186,173,217,247,125, 99, 98,170, 16,170,182,125,110,232,227, 78,236,167,187, 2, 77, 5,212,166,211,181,219,161, 84, 87, 88,151,
+ 81,153, 91, 22, 42,173, 58,216, 2, 66,109,243,176,249,247,227,159,188,172,197,153,181, 23,220,146, 73, 36,158,189,183, 55,238,
+119,191, 83,134, 79,133, 94, 26, 54,163,119, 40, 23,245, 15,114,220,191,142,226,213, 56,139,225,227,133,189,165,172,237,181,249,
+ 97,155, 30,221,191,119,242,131,196, 96,167, 93,151,172, 39,236,250,202, 55, 62,208,102,241,218,107, 53,128,138, 37,126,130,149,
+ 83,107, 53, 9,204, 84,230, 17, 17,189, 55,212,190, 3,248,146,172,211,160,212,169,214,189,181, 33,186,142,219,211,247, 54, 44,
+ 95,227, 14,196,106,162,186,125, 98,181,178,180, 58, 45,166,105,207, 92, 9,120,110,100,217, 28, 70,108,107,177,109,190, 79,173,
+221, 99,115, 41,203, 76, 94, 97, 37, 17,242,109,137,226,246,211,217,104,251,163, 81,127,101, 62,187,186,171,187,235,180,188, 70,
+108,210,237,235,249, 22, 93,137,180,219,153,179, 84,221,245,137,101, 55, 93,179, 23, 99,212,230,110, 13,155, 14,126,244, 71,153,
+ 30,155, 22,183,110, 58,135, 44,136,172,191, 58, 84,105, 79,178,151,218, 87,181, 90,244, 52,109,183, 49,108, 26,164,171,191,110,
+ 45, 11, 30,153, 2,181,115,110, 83,149,219, 97,171,198,196,221, 46, 9,183, 14, 21,126,223,177, 98,217, 80,152,183,109,137, 17,
+184, 39,182,216,149, 73,247,169,115, 94,157,126,212, 38,174,188,170,109, 62,145, 66,136,100, 17, 21, 93, 71,204, 47,211,227,220,
+219,115,111,195,225,108, 1,107, 11,252,252,239,134,106, 63,179,199,115,133,155,125,215,171,187,135,179,118,237,197,106,110,150,
+201,109,205, 10,223,153,185,246, 52,250, 21,249, 15,122,172, 61,215,189,169, 23, 85,173,123,210,110, 87,226, 85,161,161,221,180,
+ 69, 50, 35, 16,154,153,245,133, 70,101, 86, 39,143, 18,101,191, 50, 43,173, 61,131,193, 94,250,238,142,241,110, 54,200, 89,144,
+172,105,247,150,215, 94, 63,197,253,209, 54,126,230, 88,150,253,156,245,230,245,238,157,187,165, 91,118,205,231,112, 87,162,211,
+175, 26,213, 74,234, 15,179, 73,139, 75,126, 92,138,179, 48,164, 75,167,183, 38, 43, 46, 58,157,172,107,218, 71,106,187,184,205,
+ 93,151, 6,202,110, 37,197,110,209,175, 29,134,190,172,246, 39,241, 13, 5,253,203,160, 93, 60, 62,109,135, 18,118,213,139,112,
+ 73,220, 10,142,200, 73,165, 84,170,177,119, 63,136, 8, 23, 60, 70,218,180,225,210,217,143,182,241, 40,114,169,117, 3, 80,155,
+ 86, 12, 7, 9,252, 89,216,124, 52,223,247, 21,199, 92,217,203,159,115,109, 71,183, 27,106,119, 94,200,183,218,221,216, 86, 93,
+205,110,222, 91, 37,184,134,249,219,247, 46, 91,196,109, 93, 86, 53,227, 71, 49,101, 84,161,213,227,179, 69,164, 59, 61,217, 13,
+ 76,139, 38,154,150, 85, 17,245,109, 21,212, 94,194,230,253,122,118,237,252, 63,118, 51,229,219,231,249, 97,202,188, 61,155,155,
+199,118,239,117,185,183,155, 45,111,219, 48,169,151,253,165,181,247, 29,144,197,255, 0,186, 86, 69,154,185,177,175,167, 54,191,
+110,233, 53, 41,149, 43,218,189, 9,184,108,215,247,190,249,155, 69,160, 50,234,210,253, 65,250, 53, 77,200,172, 42,159, 74,151,
+ 45,166,227,134, 30, 29,118,127,120,246,186,191, 46,244, 59,148,198,229, 93, 91,162,198,209,109, 69, 98,214,187, 45,122, 85,145,
+109,220,147, 54,155,112,111,218, 69, 66,255, 0,180,170,251,125, 80,157,121, 82,101,220,150,181, 18,154,240,167,215,104, 46, 83,
+162, 85, 36,212, 19,245,147,172, 55, 5,237,158,182,189,170,118,111,241,175,183,251,177,186, 92, 50,213, 47,138,213,133, 67,216,
+ 27,113, 74,181,183,186, 14,223, 84,174,122, 47, 11,119,174,202,223, 59, 29, 14,226,170,191,178,245,148,204,114,158,230,219,222,
+ 52, 89,210, 61,212, 74,157,109,221,244, 74,100,119,233,207,218,140,207,171,105,175, 15, 60, 86,219, 59, 19,183, 23, 37,185, 55,
+107, 42,215,157,246,197,244,141,202,218,155,189,189,196,135,110,218,246, 85,232,222,219,222,187,117, 26,163,120, 88,142,109,229,
+ 70, 70,225, 69,136,139,192, 85, 33, 71,143, 94,160, 33, 53, 10, 36,116,205, 53, 8, 43,126, 27,135, 2, 45, 74,111,229,107,222,
+224,251,173,219,227,235,252,241,159, 47, 99,243,255, 0,140,109,229,209,192, 61,139, 67,254, 54, 13, 55,134, 30, 56,238,159,226,
+247,134,189,165,221,155, 88, 82,239, 26, 58,127,141, 58,134,224, 29,184,254, 17,110,133,181,238,252, 37, 74,228,217,202, 39,240,
+190,165,239, 17, 99,253,100,191,208, 49,227,221, 17,185, 92,241,117, 46,135,178,187, 35, 81, 28, 31,213, 31,183,183,186,171, 31,
+122,172,157,204, 93,241,102,218,215,157,151, 58,233,188,119, 54,204,184,111, 91, 90,206,160,237,157, 94,102,218, 53, 31,110,232,
+ 55, 5,201, 73,181, 97, 62,229, 82, 21,212,253, 17,170,156,202,136, 53,143, 5,170,122,233,238,255, 0, 21,182, 21,251, 73,221,
+ 38,109, 61,163,187,173, 42,230,243,109,206,204,217,215,189, 66,226,221,186, 53,235, 74,102,187,180, 15, 88,202,106,225,181, 40,
+212,205,160,161, 61, 71,164,207,141,102,114, 42,155, 50,125, 77,232,203,169,120,130,166,250, 89,240,157,111,237,173,252,177, 83,
+ 70,217,139, 67,114,246,121,205,192,178,182,194,199,221,235, 38,179, 78,133,124, 51,107,215,171,138,221, 10,189,205, 93,167, 93,
+ 54,173,114, 93,149, 85,143,101, 93, 20, 42,173,118, 11,240,157,147, 78,174, 70,121,218, 70, 95,139,225,190, 91,109, 66, 82,230,
+223, 59,143,119,166, 50, 8,184, 3,231,127,135,166, 49, 78, 42,118,162,139,177,156, 68,238,246,208, 80, 63,132, 77, 83,182,246,
+242,168, 91, 74,166, 93,239, 65,153,117,219,117, 40, 41,100, 86,172,219,150,169, 75,166,194,137, 94,175, 81, 43, 42,159, 72,151,
+ 83,133, 10, 28, 42,156,138, 35,149, 8, 81, 34,197,146,211, 13,173, 88,184,129,221,147,190, 91,193,122,238,130, 40, 10,181,162,
+ 92,146,233,172,210,109,231,107, 47, 92,147, 40,244, 11,118,135, 75,181,237,216, 53, 75,142, 68, 40,170,184,107, 72,161, 81,105,
+222,253, 60, 68,134,137,147, 11,242, 90,133, 13,183, 81, 21,165,172, 21, 55, 58, 70,221,186,116,193,180,169,223,215, 31,255,217,
+};
+
diff --git a/source/blender/src/swapbuffers.c b/source/blender/src/swapbuffers.c
new file mode 100644
index 00000000000..cad8d86e677
--- /dev/null
+++ b/source/blender/src/swapbuffers.c
@@ -0,0 +1,289 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+
+/* HRMS!!... blender has its own swapbuffers method. for sgi only that worked pretty nice.
+ * but with porting to linux and win, with mesa and opengl variations, it all grow
+ * out of control.
+ * with the introduction of Ghost (2002) we really should bring this back to a single
+ * method again. (ton)
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "DNA_space_types.h"
+#include "DNA_screen_types.h"
+
+#include "BKE_global.h"
+
+#include "BIF_gl.h"
+#include "BIF_interface.h"
+#include "BIF_mywindow.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+
+#include "winlay.h"
+
+#if 0
+static void copy_back_to_front(void)
+{
+ int actually_swap= 0;
+ int winx, winy;
+ char *data;
+
+ winlay_get_winsize(&winx, &winy);
+
+ if (actually_swap) {
+ data= MEM_mallocN(4*winx*winy, "swap");
+ glReadPixels(0, 0, winx, winy, GL_RGBA, GL_UNSIGNED_BYTE, data);
+ }
+
+ mywinset(1);
+ glRasterPos2f(-0.5,-0.5);
+ glReadBuffer(GL_BACK);
+ glDrawBuffer(GL_FRONT);
+ glCopyPixels(0, 0, winx, winy, GL_COLOR);
+ glDrawBuffer(GL_BACK);
+ glFlush();
+
+ if (actually_swap) {
+ glRasterPos2f(-0.5,-0.5);
+ glDrawPixels(winx, winy, GL_RGBA, GL_UNSIGNED_BYTE, data);
+ glFlush();
+ MEM_freeN(data);
+ }
+}
+#endif
+
+static void screen_swapbuffers_REDRAW(bScreen *sc)
+{
+ ScrArea *sa;
+ int doswap= 0, swap;
+
+ /* a new implementation: only using redraws and a normal swapbuffer */
+
+ /* all areas front ok? */
+ sa= sc->areabase.first;
+ while(sa) {
+ if(sa->win && (sa->win_swap & WIN_FRONT_OK)==0) break;
+ if(sa->headertype==0) sa->head_swap= WIN_EQUAL;
+ if((sa->head_swap & WIN_FRONT_OK)==0) break;
+ sa= sa->next;
+ }
+ if(sa==0) return;
+
+ sa= sc->areabase.first;
+ while(sa) {
+ swap= sa->win_swap;
+ if( (swap & WIN_BACK_OK) == 0) {
+ scrarea_do_windraw(sa);
+
+ doswap= 1;
+ sa->win_swap= swap | WIN_BACK_OK;
+ }
+ else if( sa->win_swap==WIN_BACK_OK) doswap= 1;
+
+ swap= sa->head_swap;
+ if( (swap & WIN_BACK_OK) == 0) {
+ if (sa->headertype) scrarea_do_headdraw(sa);
+ doswap= 1;
+ sa->head_swap = swap | WIN_BACK_OK;
+ }
+ else if( sa->head_swap==WIN_BACK_OK) doswap= 1;
+
+ sa= sa->next;
+ }
+
+ /* the whole backbuffer should now be ok */
+ if(doswap) {
+ myswapbuffers();
+ }
+}
+
+#include "BMF_Api.h"
+#include <stdio.h>
+
+static void draw_debug_win(int win)
+{
+ static int drawcounter= 0;
+ char buf[64];
+ int x, y;
+ int w, h;
+
+ bwin_getsuborigin(win, &x, &y);
+ bwin_getsize(win, &w, &h);
+
+ mywinset(win);
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0, w, 0, h, -1, 1);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ glColor3f(0.8, 0.8, 0.8);
+ glRecti(0, 0, w, h);
+
+ glColor3f(0.6, 0.6, 0.6);
+ glRecti(2, 2, w-4, h-4);
+
+ glColor3ub(0, 0, 0);
+ glRasterPos2i(5, 5);
+
+ sprintf(buf, "win: %d - (%d, %d, %d, %d) %d\n", win, x, y, w, h, drawcounter++);
+ BMF_DrawString(G.font, buf);
+}
+
+static void screen_swapbuffers_DEBUG(bScreen *sc)
+{
+ ScrArea *sa;
+
+ for (sa= sc->areabase.first; sa; sa= sa->next) {
+ draw_debug_win(sa->win);
+ if (sa->headwin) draw_debug_win(sa->headwin);
+ }
+
+ myswapbuffers();
+}
+
+static void screen_swapbuffers_DEBUG_SWAP(bScreen *sc)
+{
+ ScrArea *sa;
+ int doswap= 0, swap;
+
+ /* a new implementation: only using redraws and a normal swapbuffer */
+
+ /* all areas front ok? */
+ sa= sc->areabase.first;
+ while(sa) {
+ if(sa->win && (sa->win_swap & WIN_FRONT_OK)==0) break;
+ if(!sa->headertype) sa->head_swap= WIN_EQUAL;
+ if((sa->head_swap & WIN_FRONT_OK)==0) break;
+ sa= sa->next;
+ }
+ if(sa==0) return;
+
+ sa= sc->areabase.first;
+ while(sa) {
+
+ swap= sa->win_swap;
+ if( (swap & WIN_BACK_OK) == 0) {
+ scrarea_do_windraw(sa);
+ draw_debug_win(sa->win);
+
+ doswap= 1;
+ sa->win_swap= swap | WIN_BACK_OK;
+ }
+ else if( sa->win_swap==WIN_BACK_OK) doswap= 1;
+
+ swap= sa->head_swap;
+ if( (swap & WIN_BACK_OK) == 0) {
+ if (sa->headertype) {
+ scrarea_do_headdraw(sa);
+ draw_debug_win(sa->headwin);
+ }
+ doswap= 1;
+ sa->head_swap = swap | WIN_BACK_OK;
+ }
+ else if( sa->head_swap==WIN_BACK_OK) doswap= 1;
+
+ sa= sa->next;
+ }
+
+ if(doswap) {
+ myswapbuffers();
+ }
+}
+
+static void screen_swapbuffers_SIMPLE(bScreen *sc)
+{
+ ScrArea *sa;
+
+ mywinset(1);
+ glClearColor(0.8, 0.6, 0.7, 1.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ for (sa= sc->areabase.first; sa; sa= sa->next) {
+ scrarea_do_windraw(sa);
+ if (sa->headertype) scrarea_do_headdraw(sa);
+ }
+
+ myswapbuffers();
+}
+
+static int drawmode_default= 'r';
+int debug_swapbuffers_override= 0;
+
+void set_debug_swapbuffers_ovveride(bScreen *sc, int mode)
+{
+ ScrArea *sa;
+ for (sa= sc->areabase.first; sa; sa= sa->next) {
+ sa->win_swap= 0;
+ sa->head_swap= 0;
+ }
+ debug_swapbuffers_override= mode;
+}
+
+void screen_swapbuffers(void)
+{
+ ScrArea *tempsa;
+
+ bScreen *sc= G.curscreen;
+ int drawmode;
+
+ if (debug_swapbuffers_override) {
+ drawmode= debug_swapbuffers_override;
+ } else {
+ drawmode= drawmode_default;
+ }
+
+ tempsa= curarea;
+ areawinset(1);
+
+ if (drawmode=='s') {
+ screen_swapbuffers_SIMPLE(sc);
+ } else if (drawmode=='d') {
+ screen_swapbuffers_DEBUG(sc);
+ } else if (drawmode=='f') {
+ screen_swapbuffers_DEBUG_SWAP(sc);
+ } else {
+ screen_swapbuffers_REDRAW(sc);
+ }
+
+ areawinset(tempsa->win);
+}
diff --git a/source/blender/src/toets.c b/source/blender/src/toets.c
new file mode 100644
index 00000000000..b174abfa873
--- /dev/null
+++ b/source/blender/src/toets.c
@@ -0,0 +1,973 @@
+/**
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+
+ *
+ *
+ * General blender hot keys (toets = dutch), special hotkeys are in space.c
+ *
+ */
+
+#include <string.h>
+#include <math.h>
+
+#ifdef WIN32
+#include "BLI_winstuff.h"
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "PIL_time.h"
+
+#include "nla.h" /* Only for the #ifdef flag - To be removed later */
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BKE_action.h"
+#include "BKE_anim.h"
+#include "BKE_blender.h"
+#include "BKE_depsgraph.h"
+#include "BKE_displist.h"
+#include "BKE_global.h"
+#include "BKE_image.h"
+#include "BKE_ipo.h"
+#include "BKE_key.h"
+#include "BKE_scene.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_butspace.h"
+#include "BIF_editseq.h"
+#include "BIF_editsound.h"
+#include "BIF_editmesh.h"
+#include "BIF_imasel.h"
+#include "BIF_interface.h"
+#include "BKE_object.h"
+#include "BIF_poseobject.h"
+#include "BIF_previewrender.h"
+#include "BIF_renderwin.h"
+#include "BIF_retopo.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_toets.h"
+#include "BIF_toolbox.h"
+#include "BIF_usiblender.h"
+#include "BIF_writeimage.h"
+
+#include "BDR_sculptmode.h"
+#include "BDR_vpaint.h"
+#include "BDR_editobject.h"
+#include "BDR_editface.h"
+
+#include "BSE_filesel.h" /* For activate_fileselect */
+#include "BSE_drawview.h" /* For play_anim */
+#include "BSE_view.h"
+#include "BSE_edit.h"
+#include "BSE_editipo.h"
+#include "BSE_headerbuttons.h"
+#include "BSE_seqaudio.h"
+
+#include "blendef.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "mydevice.h"
+
+#include "BIF_poseobject.h"
+
+#define VIEW_ZOOM_OUT_FACTOR (1.15f)
+#define VIEW_ZOOM_IN_FACTOR (1.0f/VIEW_ZOOM_OUT_FACTOR)
+
+/* ------------------------------------------------------------------------- */
+
+static int is_an_active_object(void *ob) {
+ Base *base;
+
+ for (base= FIRSTBASE; base; base= base->next)
+ if (base->object == ob)
+ return 1;
+
+ return 0;
+}
+
+/* run when pressing 1,3 or 7 */
+static void axis_set_view(float q1, float q2, float q3, float q4, short view, int perspo)
+{
+ float new_quat[4];
+ new_quat[0]= q1; new_quat[1]= q2;
+ new_quat[2]= q3; new_quat[3]= q4;
+ G.vd->view=0;
+
+ if (G.vd->persp==2 && G.vd->camera) {
+ /* Is this switching from a camera view ? */
+ float orig_ofs[3];
+ float orig_lens= G.vd->lens;
+ VECCOPY(orig_ofs, G.vd->ofs);
+ view_settings_from_ob(G.vd->camera, G.vd->ofs, G.vd->viewquat, &G.vd->dist, &G.vd->lens);
+
+ if (U.uiflag & USER_AUTOPERSP) G.vd->persp= 0;
+ else if(G.vd->persp>=2) G.vd->persp= perspo;
+
+ smooth_view(G.vd, orig_ofs, new_quat, NULL, &orig_lens);
+ } else {
+
+ if (U.uiflag & USER_AUTOPERSP) G.vd->persp= 0;
+ else if(G.vd->persp>=2) G.vd->persp= perspo;
+
+ smooth_view(G.vd, NULL, new_quat, NULL, NULL);
+ }
+ G.vd->view= view;
+}
+
+void persptoetsen(unsigned short event)
+{
+ static Object *oldcamera=0;
+ float phi, si, q1[4], vec[3];
+ static int perspo=1;
+ int preview3d_event= 1;
+ short mouseloc[2];
+
+ float new_dist, orig_ofs[3];
+
+ /* Use this to test if we started out with a camera */
+ Object *act_cam_orig=NULL;
+ if (G.vd->persp == 2)
+ act_cam_orig = G.vd->camera;
+
+ if(event==PADENTER) {
+ if (G.qual == LR_SHIFTKEY) {
+ view3d_set_1_to_1_viewborder(G.vd);
+ } else {
+ if (G.vd->persp==2) {
+ G.vd->camzoom= 0;
+ } else {
+ new_dist = 10.0;
+ smooth_view(G.vd, NULL, NULL, &new_dist, NULL);
+ }
+ }
+ }
+ else if((G.qual & (LR_SHIFTKEY | LR_CTRLKEY)) && (event != PAD0)) {
+
+ /* Indicate that this view is inverted,
+ * but only if it actually _was_ inverted (jobbe) */
+ if (event==PAD7 || event == PAD1 || event == PAD3)
+ G.vd->flag2 |= V3D_OPP_DIRECTION_NAME;
+
+ if(event==PAD0) {
+ /* G.vd->persp= 3; */
+ }
+ else if(event==PAD7) {
+ axis_set_view(0.0, -1.0, 0.0, 0.0, 7, perspo);
+ }
+ else if(event==PAD1) {
+ axis_set_view(0.0, 0.0, (float)-cos(M_PI/4.0), (float)-cos(M_PI/4.0), 1, perspo);
+ }
+ else if(event==PAD3) {
+ axis_set_view(0.5, -0.5, 0.5, 0.5, 3, perspo);
+ }
+ else if(event==PADMINUS) {
+ /* this min and max is also in viewmove() */
+ if(G.vd->persp==2) {
+ G.vd->camzoom-= 10;
+ if(G.vd->camzoom<-30) G.vd->camzoom= -30;
+ }
+ else if(G.vd->dist<10.0*G.vd->far) G.vd->dist*=1.2f;
+ }
+ else if(event==PADPLUSKEY) {
+ if(G.vd->persp==2) {
+ G.vd->camzoom+= 10;
+ if(G.vd->camzoom>300) G.vd->camzoom= 300;
+ }
+ else if(G.vd->dist> 0.001*G.vd->grid) G.vd->dist*=.83333f;
+ }
+ else {
+
+ initgrabz(0.0, 0.0, 0.0);
+
+ if(event==PAD6) window_to_3d(vec, -32, 0);
+ else if(event==PAD4) window_to_3d(vec, 32, 0);
+ else if(event==PAD8) window_to_3d(vec, 0, -25);
+ else if(event==PAD2) window_to_3d(vec, 0, 25);
+ G.vd->ofs[0]+= vec[0];
+ G.vd->ofs[1]+= vec[1];
+ G.vd->ofs[2]+= vec[2];
+ }
+ }
+ else {
+ /* Indicate that this view is not inverted.
+ * Don't do this for PADMINUS/PADPLUSKEY, though. (jobbe)*/
+ if (event != PADMINUS && event != PADPLUSKEY)
+ G.vd->flag2 &= ~V3D_OPP_DIRECTION_NAME;
+
+
+ if(event==PAD7) {
+ axis_set_view(1.0, 0.0, 0.0, 0.0, 7, perspo);
+ }
+ else if(event==PAD1) {
+ axis_set_view((float)cos(M_PI/4.0), (float)-sin(M_PI/4.0), 0.0, 0.0, 1, perspo);
+ }
+ else if(event==PAD3) {
+ axis_set_view(0.5, -0.5, -0.5, -0.5, 3, perspo);
+ }
+ else if(event==PADMINUS) {
+ /* this min and max is also in viewmove() */
+ if(G.vd->persp==2) {
+ G.vd->camzoom= MAX2(-30, G.vd->camzoom-5);
+ }
+ else if(G.vd->dist<10.0*G.vd->far) {
+ getmouseco_areawin(mouseloc);
+ view_zoom_mouseloc(VIEW_ZOOM_OUT_FACTOR, mouseloc);
+ }
+ if(G.vd->persp!=1) preview3d_event= 0;
+ }
+ else if(event==PADPLUSKEY) {
+ if(G.vd->persp==2) {
+ G.vd->camzoom= MIN2(300, G.vd->camzoom+5);
+ }
+ else if(G.vd->dist> 0.001*G.vd->grid) {
+ getmouseco_areawin(mouseloc);
+ view_zoom_mouseloc(VIEW_ZOOM_IN_FACTOR, mouseloc);
+ }
+ if(G.vd->persp!=1) preview3d_event= 0;
+ }
+ else if(event==PAD5) {
+ if (U.smooth_viewtx) {
+ if(G.vd->persp==1) { G.vd->persp=0;
+ } else if (act_cam_orig) {
+ /* were from a camera view */
+ float orig_dist= G.vd->dist;
+ float orig_lens= G.vd->lens;
+ VECCOPY(orig_ofs, G.vd->ofs);
+
+ G.vd->persp=1;
+ G.vd->dist= 0.0;
+
+ view_settings_from_ob(act_cam_orig, G.vd->ofs, NULL, NULL, &G.vd->lens);
+
+ smooth_view(G.vd, orig_ofs, NULL, &orig_dist, &orig_lens);
+
+ } else {
+ G.vd->persp=1;
+ }
+ } else {
+ if(G.vd->persp==1) G.vd->persp=0;
+ else G.vd->persp=1;
+ }
+ }
+ else if(event==PAD0) {
+ if(G.qual==LR_ALTKEY) {
+ if(oldcamera && is_an_active_object(oldcamera)) {
+ G.vd->camera= oldcamera;
+ }
+ handle_view3d_lock();
+ }
+ else if(BASACT) {
+ /* check both G.vd as G.scene cameras */
+ if(G.qual==LR_CTRLKEY) {
+ if(G.vd->camera != OBACT || G.scene->camera != OBACT) {
+ if(G.vd->camera && G.vd->camera->type==OB_CAMERA)
+ oldcamera= G.vd->camera;
+
+ G.vd->camera= OBACT;
+ handle_view3d_lock();
+ }
+ }
+ else if((G.vd->camera==NULL || G.scene->camera==NULL) && OBACT->type==OB_CAMERA) {
+ G.vd->camera= OBACT;
+ handle_view3d_lock();
+ }
+ }
+ if(G.vd->camera==0) {
+ G.vd->camera= scene_find_camera(G.scene);
+ handle_view3d_lock();
+ }
+
+ if(G.vd->camera && (G.vd->camera != act_cam_orig)) {
+ G.vd->persp= 2;
+ G.vd->view= 0;
+
+ if(((G.qual & LR_CTRLKEY) && (G.qual & LR_ALTKEY)) || (G.qual & LR_SHIFTKEY)) {
+ void setcameratoview3d(void); // view.c
+ setcameratoview3d();
+ DAG_object_flush_update(G.scene, G.scene->camera, OB_RECALC_OB);
+ BIF_undo_push("View to Camera position");
+ allqueue(REDRAWVIEW3D, 0);
+
+ } else if (U.smooth_viewtx) {
+ /* move 3d view to camera view */
+ float orig_lens = G.vd->lens;
+ VECCOPY(orig_ofs, G.vd->ofs);
+
+ if (act_cam_orig)
+ view_settings_from_ob(act_cam_orig, G.vd->ofs, G.vd->viewquat, &G.vd->dist, &G.vd->lens);
+
+ smooth_view_to_camera(G.vd);
+ VECCOPY(G.vd->ofs, orig_ofs);
+ G.vd->lens = orig_lens;
+ }
+
+
+ }
+ }
+ else if(event==PAD9) {
+ countall();
+ update_for_newframe();
+
+ reset_slowparents(); /* editobject.c */
+ }
+ else if(G.vd->persp<2) {
+ if(event==PAD4 || event==PAD6) {
+ /* z-axis */
+ phi= (float)(M_PI/360.0)*U.pad_rot_angle;
+ if(event==PAD6) phi= -phi;
+ si= (float)sin(phi);
+ q1[0]= (float)cos(phi);
+ q1[1]= q1[2]= 0.0;
+ q1[3]= si;
+ QuatMul(G.vd->viewquat, G.vd->viewquat, q1);
+ G.vd->view= 0;
+ }
+ if(event==PAD2 || event==PAD8) {
+ /* horizontal axis */
+ VECCOPY(q1+1, G.vd->viewinv[0]);
+
+ Normalize(q1+1);
+ phi= (float)(M_PI/360.0)*U.pad_rot_angle;
+ if(event==PAD2) phi= -phi;
+ si= (float)sin(phi);
+ q1[0]= (float)cos(phi);
+ q1[1]*= si;
+ q1[2]*= si;
+ q1[3]*= si;
+ QuatMul(G.vd->viewquat, G.vd->viewquat, q1);
+ G.vd->view= 0;
+ }
+ }
+
+ if(G.vd->persp<2) perspo= G.vd->persp;
+ }
+
+ if(G.vd->depths) G.vd->depths->damaged= 1;
+ retopo_queue_updates(G.vd);
+ retopo_force_update();
+
+ if(preview3d_event)
+ BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
+ else
+ BIF_view3d_previewrender_signal(curarea, PR_PROJECTED);
+
+ scrarea_queue_redraw(curarea);
+}
+
+int untitled(char * name)
+{
+ if (G.save_over == 0 ) {
+ char * c= BLI_last_slash(name);
+
+ if (c)
+ strcpy(&c[1], "untitled.blend");
+ else
+ strcpy(name, "untitled.blend");
+
+ return(TRUE);
+ }
+
+ return(FALSE);
+}
+
+char *recent_filelist(void)
+{
+ struct RecentFile *recent;
+ int event, i, ofs;
+ char pup[2048], *p;
+
+ p= pup + sprintf(pup, "Open Recent%%t");
+
+ if (G.sce[0]) {
+ p+= sprintf(p, "|%s %%x%d", G.sce, 1);
+ ofs = 1;
+ } else ofs = 0;
+
+ for (recent = G.recent_files.first, i=0; (i<U.recent_files) && (recent); recent = recent->next, i++) {
+ if (strcmp(recent->filename, G.sce)) {
+ p+= sprintf(p, "|%s %%x%d", recent->filename, i+ofs+1);
+ }
+ }
+ event= pupmenu(pup);
+ if(event>0) {
+ if (ofs && (event==1))
+ return(G.sce);
+ else
+ recent = BLI_findlink(&(G.recent_files), event-1-ofs);
+ if(recent) return(recent->filename);
+ }
+
+ return(NULL);
+}
+
+int blenderqread(unsigned short event, short val)
+{
+ /* here do the general keys handling (not screen/window/space) */
+ /* return 0: do not pass on to the other queues */
+ extern int textediting;
+ extern void playback_anim();
+ ScrArea *sa;
+ Object *ob;
+ int textspace=0;
+ /* Changed str and dir size to 160, to make sure there is enough
+ * space for filenames. */
+ char dir[FILE_MAXDIR * 2], str[FILE_MAXFILE * 2];
+ char *recentfile;
+
+ if(val==0) return 1;
+ if(event==MOUSEY || event==MOUSEX) return 1;
+ if (G.flags & G_FILE_AUTOPLAY) return 1;
+
+ if (curarea && curarea->spacetype==SPACE_TEXT) textspace= 1;
+ else if (curarea && curarea->spacetype==SPACE_SCRIPT) textspace= 1;
+
+ switch(event) {
+
+ case F1KEY:
+ if(G.qual==0) {
+ /* this exception because of the '?' button */
+ if(curarea->spacetype==SPACE_INFO) {
+ sa= closest_bigger_area();
+ areawinset(sa->win);
+ }
+
+ activate_fileselect(FILE_BLENDER, "Open File", G.sce, BIF_read_file);
+ return 0;
+ }
+ else if(G.qual==LR_SHIFTKEY) {
+ activate_fileselect(FILE_LOADLIB, "Load Library", G.lib, 0);
+ return 0;
+ }
+ else if(G.qual==LR_CTRLKEY) {
+ activate_imageselect(FILE_LOADLIB, "Load Library", G.lib, 0);
+ return 0;
+ }
+ break;
+ case F2KEY:
+ if(G.qual==0) {
+ strcpy(dir, G.sce);
+ untitled(dir);
+ activate_fileselect(FILE_BLENDER, "Save File", dir, BIF_write_file);
+ return 0;
+ }
+ else if(G.qual==LR_CTRLKEY) {
+ write_vrml_fs();
+ return 0;
+ }
+ else if(G.qual==LR_SHIFTKEY) {
+ write_dxf_fs();
+ return 0;
+ }
+ break;
+ case F3KEY:
+ if(G.qual==0) {
+ BIF_save_rendered_image_fs();
+ return 0;
+ }
+ else if(G.qual==LR_SHIFTKEY) {
+ newspace(curarea, SPACE_NODE);
+ return 0;
+ }
+ else if(G.qual & LR_CTRLKEY) {
+ BIF_screendump(0);
+ }
+ break;
+ case F4KEY:
+ if(G.qual==LR_SHIFTKEY) {
+
+ memset(str, 0, 16);
+ ob= OBACT;
+ if(ob) strcpy(str, ob->id.name);
+
+ activate_fileselect(FILE_MAIN, "Data Select", str, NULL);
+ return 0;
+ }
+ else if(G.qual==LR_CTRLKEY) {
+
+ memset(str, 0, 16);
+ ob= OBACT;
+ if(ob) strcpy(str, ob->id.name);
+
+ activate_imageselect(FILE_MAIN, "Data Select", str, 0);
+ return 0;
+ }
+ else if(G.qual==0) {
+ extern_set_butspace(event, 1);
+ }
+ break;
+ case F5KEY:
+ if(G.qual==LR_SHIFTKEY) {
+ newspace(curarea, SPACE_VIEW3D);
+ return 0;
+ }
+ else if(G.qual==0) {
+ extern_set_butspace(event, 1);
+ }
+ break;
+ case F6KEY:
+ if(G.qual==LR_SHIFTKEY) {
+ newspace(curarea, SPACE_IPO);
+ return 0;
+ }
+ else if(G.qual==0) {
+ extern_set_butspace(event, 1);
+ }
+ break;
+ case F7KEY:
+ if(G.qual==LR_SHIFTKEY) {
+ newspace(curarea, SPACE_BUTS);
+ return 0;
+ }
+ else if(G.qual==0) {
+ extern_set_butspace(event, 1);
+ }
+ break;
+ case F8KEY:
+ if(G.qual==LR_SHIFTKEY) {
+ newspace(curarea, SPACE_SEQ);
+ return 0;
+ }
+ else if(G.qual==0) {
+ extern_set_butspace(event, 1);
+ }
+ break;
+ case F9KEY:
+ if(G.qual==LR_SHIFTKEY) {
+ newspace(curarea, SPACE_OOPS);
+ return 0;
+ }
+ else if(G.qual==(LR_SHIFTKEY|LR_ALTKEY)) {
+ newspace(curarea, SPACE_OOPS+256);
+ return 0;
+ }
+ else if(G.qual==0) {
+ extern_set_butspace(event, 1);
+ }
+ break;
+ case F10KEY:
+ if(G.qual==LR_SHIFTKEY) {
+ newspace(curarea, SPACE_IMAGE);
+ return 0;
+ }
+ else if(G.qual==0) {
+ extern_set_butspace(event, 1);
+ }
+ break;
+ case F11KEY:
+ if(G.qual==LR_SHIFTKEY) {
+ newspace(curarea, SPACE_TEXT);
+ return 0;
+ }
+ else if (G.qual==LR_CTRLKEY) {
+ playback_anim();
+ }
+ else if(G.qual==0) {
+ BIF_toggle_render_display();
+ return 0;
+ }
+ break;
+ case F12KEY:
+ if(G.qual==LR_SHIFTKEY) {
+ newspace(curarea, SPACE_ACTION);
+ return 0;
+ }
+ else if (G.qual==(LR_SHIFTKEY|LR_CTRLKEY)) {
+ newspace(curarea, SPACE_NLA);
+ return 0;
+ }
+ else if (G.qual==LR_CTRLKEY) {
+ BIF_do_render(1);
+ }
+ else {
+ /* ctrl/alt + f12 should render too, for some macs have f12 assigned to cd eject */
+ BIF_do_render(0);
+ }
+ return 0;
+ break;
+
+ case WHEELUPMOUSE:
+ if(G.qual==LR_ALTKEY || G.qual==LR_COMMANDKEY) {
+ if(CFRA>1) {
+ CFRA--;
+ update_for_newframe();
+ }
+ return 0;
+ }
+ break;
+ case WHEELDOWNMOUSE:
+ if(G.qual==LR_ALTKEY || G.qual==LR_COMMANDKEY) {
+ CFRA++;
+ update_for_newframe();
+ return 0;
+ }
+ break;
+
+ case LEFTARROWKEY:
+ case DOWNARROWKEY:
+ if(textediting==0 && textspace==0) {
+
+#if 0
+//#ifdef _WIN32 // FULLSCREEN
+ if(event==DOWNARROWKEY){
+ if (G.qual==LR_ALTKEY)
+ mainwindow_toggle_fullscreen(0);
+ else if(G.qual==0)
+ CFRA-= G.scene->jumpframe;
+ }
+#else
+ if((event==DOWNARROWKEY)&&(G.qual==0))
+ CFRA-= G.scene->jumpframe;
+#endif
+ else if((event==LEFTARROWKEY)&&(G.qual==0))
+ CFRA--;
+
+ if(G.qual==LR_SHIFTKEY)
+ CFRA= PSFRA;
+ if(CFRA<1) CFRA=1;
+
+ update_for_newframe();
+ return 0;
+ }
+ break;
+
+ case RIGHTARROWKEY:
+ case UPARROWKEY:
+ if(textediting==0 && textspace==0) {
+
+#if 0
+//#ifdef _WIN32 // FULLSCREEN
+ if(event==UPARROWKEY){
+ if(G.qual==LR_ALTKEY)
+ mainwindow_toggle_fullscreen(1);
+ else if(G.qual==0)
+ CFRA+= G.scene->jumpframe;
+ }
+#else
+ if((event==UPARROWKEY)&&(G.qual==0))
+ CFRA+= G.scene->jumpframe;
+#endif
+ else if((event==RIGHTARROWKEY)&&(G.qual==0))
+ CFRA++;
+
+ if(G.qual==LR_SHIFTKEY)
+ CFRA= PEFRA;
+
+ update_for_newframe();
+ }
+ break;
+
+ case ESCKEY:
+ sound_stop_all_sounds(); // whats this?
+
+ /* stop playback on ESC always */
+ rem_screenhandler(G.curscreen, SCREEN_HANDLER_ANIM);
+ audiostream_stop();
+ allqueue(REDRAWALL, 0);
+
+ break;
+ case TABKEY:
+ if(G.qual==0) {
+ if(textspace==0) {
+ if(curarea->spacetype==SPACE_IPO)
+ set_editflag_editipo();
+ else if(curarea->spacetype==SPACE_SEQ)
+ enter_meta();
+ else if(curarea->spacetype==SPACE_NODE)
+ return 1;
+ else if(G.vd) {
+ /* also when Alt-E */
+ if(G.obedit==NULL) {
+ enter_editmode(EM_WAITCURSOR);
+ if(G.obedit) BIF_undo_push("Original"); // here, because all over code enter_editmode is abused
+ }
+ else
+ exit_editmode(EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR); // freedata, and undo
+ }
+ return 0;
+ }
+ }
+ else if(G.qual==LR_CTRLKEY){
+ Object *ob= OBACT;
+ if(ob) {
+ if(ob->type==OB_ARMATURE) {
+ if(ob->flag & OB_POSEMODE) exit_posemode();
+ else enter_posemode();
+ }
+ else if(ob->type==OB_MESH) {
+ if(ob==G.obedit) EM_selectmode_menu();
+ else if(G.f & G_SCULPTMODE)
+ sculptmode_selectbrush_menu();
+ else set_wpaint();
+ }
+ }
+ }
+ break;
+
+ case BACKSPACEKEY:
+ break;
+
+ case AKEY:
+ if(textediting==0 && textspace==0) {
+ if(G.qual==(LR_SHIFTKEY|LR_ALTKEY)){
+ play_anim(1);
+ return 0;
+ }
+ else if(G.qual==LR_ALTKEY) {
+ play_anim(0);
+ return 0;
+ }
+ }
+ break;
+ case EKEY:
+ if(G.qual==LR_ALTKEY) {
+ if(G.vd && textspace==0) {
+ if(G.obedit==0) {
+ enter_editmode(EM_WAITCURSOR);
+ BIF_undo_push("Original");
+ }
+ else
+ exit_editmode(EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR); // freedata, and undo
+ return 0;
+ }
+ }
+ break;
+ case IKEY:
+ if(textediting==0 && textspace==0 && !ELEM3(curarea->spacetype, SPACE_FILE, SPACE_IMASEL, SPACE_NODE)) {
+ if(G.f & G_SCULPTMODE) return 1;
+ else if(G.qual==0) {
+ common_insertkey();
+ return 0;
+ }
+ }
+ break;
+ case JKEY:
+ if(textediting==0 && textspace==0) {
+ if (G.qual==0) {
+ BIF_swap_render_rects();
+ return 0;
+ }
+ }
+ break;
+
+ case NKEY:
+ if(textediting==0 && textspace==0) {
+ if(G.qual & LR_CTRLKEY);
+ else if(G.qual==0 || (G.qual & LR_SHIFTKEY)) {
+ if(curarea->spacetype==SPACE_VIEW3D); // is new panel, in view3d queue
+ else if(curarea->spacetype==SPACE_IPO); // is new panel, in ipo queue
+ else if(curarea->spacetype==SPACE_IMAGE); // is new panel, in ipo queue
+ else if(curarea->spacetype==SPACE_ACTION); // is own queue
+ else if(curarea->spacetype==SPACE_NLA); // is new panel
+ else if(curarea->spacetype==SPACE_SEQ); // is new panel
+ else {
+ clever_numbuts();
+ return 0;
+ }
+ }
+ }
+ break;
+
+ case OKEY:
+ if(textediting==0) {
+ if(G.qual==LR_CTRLKEY) {
+ recentfile = recent_filelist();
+ if(recentfile) {
+ BIF_read_file(recentfile);
+ }
+ return 0;
+ }
+ }
+ break;
+
+ case SKEY:
+ if(G.obedit==NULL) {
+ if(G.qual==LR_CTRLKEY) {
+ strcpy(dir, G.sce);
+ if (untitled(dir)) {
+ activate_fileselect(FILE_BLENDER, "Save File", dir, BIF_write_file);
+ } else {
+ BIF_write_file(dir);
+ free_filesel_spec(dir);
+ }
+ return 0;
+ }
+ }
+ break;
+
+ case TKEY:
+ if (G.qual==(LR_SHIFTKEY|LR_ALTKEY|LR_CTRLKEY)) {
+ Object *ob = OBACT;
+ int event = pupmenu(ob?"Time%t|draw|recalc ob|recalc data":"Time%t|draw");
+ int a;
+ double delta, stime;
+
+ if (event < 0) return 0; /* cancelled by user */
+
+ waitcursor(1);
+
+ stime= PIL_check_seconds_timer();
+ for(a=0; a<100000; a++) {
+ if (event==1) {
+ scrarea_do_windraw(curarea);
+ } else if (event==2) {
+ ob->recalc |= OB_RECALC_OB;
+ object_handle_update(ob);
+ } else if (event==3) {
+ ob->recalc |= OB_RECALC_DATA;
+ object_handle_update(ob);
+ }
+
+ delta= PIL_check_seconds_timer()-stime;
+ if (delta>5.0) break;
+ }
+
+ waitcursor(0);
+ notice("%8.6f s/op - %6.2f ops/s - %d iterations", delta/a, a/delta, a);
+ return 0;
+ }
+ else if(G.qual==(LR_ALTKEY|LR_CTRLKEY)) {
+ int a;
+ int event= pupmenu("10 Timer%t|draw|draw+swap|undo");
+ if(event>0) {
+ double stime= PIL_check_seconds_timer();
+ char tmpstr[128];
+ int time;
+
+ waitcursor(1);
+
+ for(a=0; a<10; a++) {
+ if (event==1) {
+ scrarea_do_windraw(curarea);
+ } else if (event==2) {
+ scrarea_do_windraw(curarea);
+ screen_swapbuffers();
+ }
+ else if(event==3) {
+ BIF_undo();
+ BIF_redo();
+ }
+ }
+
+ time= (int) ((PIL_check_seconds_timer()-stime)*1000);
+
+ if(event==1) sprintf(tmpstr, "draw %%t|%d ms", time);
+ if(event==2) sprintf(tmpstr, "d+sw %%t|%d ms", time);
+ if(event==3) sprintf(tmpstr, "undo %%t|%d ms", time);
+
+ waitcursor(0);
+ pupmenu(tmpstr);
+
+ }
+ return 0;
+ }
+ break;
+
+ case UKEY:
+ if(textediting==0) {
+ if(G.qual==LR_CTRLKEY) {
+ if(okee("Save user defaults")) {
+ BIF_write_homefile();
+ }
+ return 0;
+ }
+ else if(G.qual==LR_ALTKEY) {
+ if(curarea->spacetype!=SPACE_TEXT) {
+ BIF_undo_menu();
+ return 0;
+ }
+ }
+ }
+ break;
+
+ case WKEY:
+ if(textediting==0) {
+ if(G.qual==LR_CTRLKEY) {
+ strcpy(dir, G.sce);
+ if (untitled(dir)) {
+ activate_fileselect(FILE_BLENDER, "Save File", dir, BIF_write_file);
+ } else {
+ BIF_write_file(dir);
+ free_filesel_spec(dir);
+ }
+ return 0;
+ }
+ /* Python specials? ;)
+ else if(G.qual==LR_ALTKEY) {
+ write_videoscape_fs();
+ return 0;
+ }*/
+ }
+ break;
+
+ case XKEY:
+ if(textspace==0 && textediting==0) {
+ if(G.qual==LR_CTRLKEY) {
+ if(okee("Erase all")) {
+ if( BIF_read_homefile(0, 1)==0) error("No file ~/.B.blend");
+ }
+ return 0;
+ }
+ }
+ break;
+ case YKEY: // redo alternative
+ if(textspace==0) {
+ if(G.qual==LR_CTRLKEY) {
+ BIF_redo();
+ return 0;
+ }
+ }
+ break;
+ case ZKEY: // undo
+ if(textspace==0) {
+ if(G.qual & (LR_CTRLKEY|LR_COMMANDKEY)) { // all combos with ctrl/commandkey are accepted
+ if ELEM(G.qual, LR_CTRLKEY, LR_COMMANDKEY) BIF_undo();
+ else BIF_redo(); // all combos with ctrl is redo
+ return 0;
+ }
+ }
+ break;
+ }
+
+ return 1;
+}
+
+/* eof */
diff --git a/source/blender/src/toolbox.c b/source/blender/src/toolbox.c
new file mode 100644
index 00000000000..f517eec055c
--- /dev/null
+++ b/source/blender/src/toolbox.c
@@ -0,0 +1,2245 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#define PY_TOOLBOX 1
+
+#include <math.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef WIN32
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+
+#include <fcntl.h>
+#include "MEM_guardedalloc.h"
+
+#include "BMF_Api.h"
+#include "BIF_language.h"
+#include "BIF_resources.h"
+
+#include "DNA_group_types.h"
+#include "DNA_image_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_camera_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "BKE_displist.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_image.h"
+#include "BKE_library.h"
+#include "BKE_mesh.h"
+#include "BKE_node.h"
+#include "BKE_main.h"
+#include "BKE_plugin_types.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_editnla.h"
+#include "BIF_editarmature.h"
+#include "BIF_editdeform.h"
+#include "BIF_editfont.h"
+#include "BIF_editmesh.h"
+#include "BIF_editseq.h"
+#include "BIF_editlattice.h"
+#include "BIF_editsima.h"
+#include "BIF_editoops.h"
+#include "BIF_editview.h"
+#include "BIF_gl.h"
+#include "BIF_graphics.h"
+#include "BIF_imasel.h"
+#include "BIF_interface.h"
+#include "BIF_mainqueue.h"
+#include "BIF_mywindow.h"
+#include "BIF_renderwin.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_toolbox.h"
+#include "BIF_tbcallback.h"
+#include "BIF_transform.h"
+
+#include "BDR_editobject.h"
+#include "BDR_editcurve.h"
+#include "BDR_editmball.h"
+
+#include "BSE_drawipo.h"
+#include "BSE_edit.h"
+#include "BSE_editipo.h"
+#include "BSE_filesel.h"
+#include "BSE_headerbuttons.h"
+#include "BSE_node.h"
+
+#include "IMB_imbuf.h"
+
+#include "blendef.h"
+#include "butspace.h"
+#include "mydevice.h"
+
+/* bpymenu */
+#include "BPY_extern.h"
+#include "BPY_menus.h"
+
+void asciitoraw(int ch, unsigned short *event, unsigned short *qual)
+{
+ if( isalpha(ch)==0 ) return;
+
+ if( isupper(ch) ) {
+ *qual= LEFTSHIFTKEY;
+ ch= tolower(ch);
+ }
+
+ switch(ch) {
+ case 'a': *event= AKEY; break;
+ case 'b': *event= BKEY; break;
+ case 'c': *event= CKEY; break;
+ case 'd': *event= DKEY; break;
+ case 'e': *event= EKEY; break;
+ case 'f': *event= FKEY; break;
+ case 'g': *event= GKEY; break;
+ case 'h': *event= HKEY; break;
+ case 'i': *event= IKEY; break;
+ case 'j': *event= JKEY; break;
+ case 'k': *event= KKEY; break;
+ case 'l': *event= LKEY; break;
+ case 'm': *event= MKEY; break;
+ case 'n': *event= NKEY; break;
+ case 'o': *event= OKEY; break;
+ case 'p': *event= PKEY; break;
+ case 'q': *event= QKEY; break;
+ case 'r': *event= RKEY; break;
+ case 's': *event= SKEY; break;
+ case 't': *event= TKEY; break;
+ case 'u': *event= UKEY; break;
+ case 'v': *event= VKEY; break;
+ case 'w': *event= WKEY; break;
+ case 'x': *event= XKEY; break;
+ case 'y': *event= YKEY; break;
+ case 'z': *event= ZKEY; break;
+ }
+}
+
+/* ************************************ */
+
+/* this va_ stuff allows printf() style codes in these menus */
+
+static int vconfirm(char *title, char *itemfmt, va_list ap)
+{
+ char *s, buf[512];
+
+ s= buf;
+ if (title) s+= sprintf(s, "%s%%t|", title);
+ vsprintf(s, itemfmt, ap);
+
+ return (pupmenu(buf)>=0);
+}
+
+static int confirm(char *title, char *itemfmt, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, itemfmt);
+ ret= vconfirm(title, itemfmt, ap);
+ va_end(ap);
+
+ return ret;
+}
+
+int okee(char *str, ...)
+{
+ va_list ap;
+ int ret;
+ char titlestr[256];
+
+ sprintf(titlestr, "OK? %%i%d", ICON_HELP);
+
+ va_start(ap, str);
+ ret= vconfirm(titlestr, str, ap);
+ va_end(ap);
+
+ return ret;
+}
+
+void notice(char *str, ...)
+{
+ va_list ap;
+
+ va_start(ap, str);
+ vconfirm(NULL, str, ap);
+ va_end(ap);
+}
+
+void error(char *fmt, ...)
+{
+ va_list ap;
+ char nfmt[256];
+ char titlestr[256];
+
+ sprintf(titlestr, "Error %%i%d", ICON_ERROR);
+
+ sprintf(nfmt, "%s", fmt);
+
+ va_start(ap, fmt);
+ if (G.background || !G.curscreen) {
+ vprintf(nfmt, ap);
+ printf("\n");
+ } else {
+ vconfirm(titlestr, nfmt, ap);
+ }
+ va_end(ap);
+}
+
+void error_libdata(void)
+{
+ error(ERROR_LIBDATA_MESSAGE);
+}
+
+int saveover(char *file)
+{
+ int len= strlen(file);
+
+ if(len==0)
+ return 0;
+
+ if(BLI_exists(file)==0)
+ return 1;
+
+ if( file[len-1]=='/' || file[len-1]=='\\' ) {
+ error("Cannot overwrite a directory");
+ return 0;
+ }
+
+ return confirm("Save over", file);
+}
+
+/* ****************** EXTRA STUFF **************** */
+
+short button(short *var, short min, short max, char *str)
+{
+ uiBlock *block;
+ ListBase listb={0, 0};
+ short x1,y1;
+ short mval[2], ret=0;
+
+ if(min>max) min= max;
+
+ getmouseco_sc(mval);
+
+ if(mval[0]<150) mval[0]=150;
+ if(mval[1]<30) mval[1]=30;
+ if(mval[0]>G.curscreen->sizex) mval[0]= G.curscreen->sizex-10;
+ if(mval[1]>G.curscreen->sizey) mval[1]= G.curscreen->sizey-10;
+
+ block= uiNewBlock(&listb, "button", UI_EMBOSS, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetFlag(block, UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_RET_1|UI_BLOCK_ENTER_OK);
+
+ x1=mval[0]-150;
+ y1=mval[1]-20;
+
+ uiDefButS(block, NUM, 0, str, (short)(x1+5),(short)(y1+10),125,20, var,(float)min,(float)max, 0, 0, "");
+ uiDefBut(block, BUT, 32767, "OK", (short)(x1+136),(short)(y1+10),25,20, NULL, 0, 0, 0, 0, "");
+
+ uiBoundsBlock(block, 5);
+
+ ret= uiDoBlocks(&listb, 0);
+
+ if(ret==UI_RETURN_OK) return 1;
+ return 0;
+}
+
+short sbutton(char *var, float min, float max, char *str)
+{
+ uiBlock *block;
+ ListBase listb={0, 0};
+ short x1,y1;
+ short mval[2], ret=0;
+
+ if(min>max) min= max;
+
+ getmouseco_sc(mval);
+
+ if(mval[0]<250) mval[0]=250;
+ if(mval[1]<30) mval[1]=30;
+ if(mval[0]>G.curscreen->sizex) mval[0]= G.curscreen->sizex-10;
+ if(mval[1]>G.curscreen->sizey) mval[1]= G.curscreen->sizey-10;
+
+ block= uiNewBlock(&listb, "button", UI_EMBOSS, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetFlag(block, UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_RET_1|UI_BLOCK_ENTER_OK);
+
+ x1=mval[0]-250;
+ y1=mval[1]-20;
+
+ uiDefButC(block, TEX, 32766, str, x1+5,y1+10,225,20, var,(float)min,(float)max, 0, 0, "");
+ uiDefBut(block, BUT, 32767, "OK", x1+236,y1+10,25,20, NULL, 0, 0, 0, 0, "");
+
+ uiBoundsBlock(block, 5);
+
+ mainqenter_ext(BUT_ACTIVATE, 32766, 0); /* note, button id '32766' is asking for errors some day! */
+ ret= uiDoBlocks(&listb, 0);
+
+ if(ret==UI_RETURN_OK) return 1;
+ return 0;
+
+}
+
+short fbutton(float *var, float min, float max, float a1, float a2, char *str)
+{
+ uiBlock *block;
+ ListBase listb={0, 0};
+ short x1,y1;
+ short mval[2], ret=0;
+
+ if(min>max) min= max;
+
+ getmouseco_sc(mval);
+
+ if(mval[0]<150) mval[0]=150;
+ if(mval[1]<30) mval[1]=30;
+ if(mval[0]>G.curscreen->sizex) mval[0]= G.curscreen->sizex-10;
+ if(mval[1]>G.curscreen->sizey) mval[1]= G.curscreen->sizey-10;
+
+ block= uiNewBlock(&listb, "button", UI_EMBOSS, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetFlag(block, UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_RET_1);
+
+ x1=mval[0]-150;
+ y1=mval[1]-20;
+
+ uiDefButF(block, NUM, 0, str,(short)(x1+5),(short)(y1+10),125,20, var, min, max, a1, a2, "");
+ uiDefBut(block, BUT, 32767, "OK",(short)(x1+136),(short)(y1+10), 35, 20, NULL, 0, 0, 0, 0, "");
+
+ uiBoundsBlock(block, 2);
+
+ ret= uiDoBlocks(&listb, 0);
+
+ if(ret==UI_RETURN_OK) return 1;
+ return 0;
+}
+
+int movetolayer_buts(unsigned int *lay, char *title)
+{
+ uiBlock *block;
+ ListBase listb={0, 0};
+ int dx, dy, a, x1, y1, sizex=160, sizey=30;
+ short pivot[2], mval[2], ret=0;
+
+ if(G.vd->localview) {
+ error("Not in localview ");
+ return ret;
+ }
+
+ getmouseco_sc(mval);
+
+ pivot[0]= CLAMPIS(mval[0], (sizex+10), G.curscreen->sizex-30);
+ pivot[1]= CLAMPIS(mval[1], (sizey/2)+10, G.curscreen->sizey-(sizey/2)-10);
+
+ if (pivot[0]!=mval[0] || pivot[1]!=mval[1])
+ warp_pointer(pivot[0], pivot[1]);
+
+ mywinset(G.curscreen->mainwin);
+
+ x1= pivot[0]-sizex+10;
+ y1= pivot[1]-sizey/2;
+
+ block= uiNewBlock(&listb, "button", UI_EMBOSS, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetFlag(block, UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_NUMSELECT|UI_BLOCK_ENTER_OK);
+
+ dx= (sizex-5)/12;
+ dy= sizey/2;
+
+ if(title)
+ uiDefBut(block, LABEL, 0, title, (short)(x1), (short)y1+30, sizex, 20, NULL, 1, 0, 0, 0, "");
+
+ /* buttons have 0 as return event, to prevent menu to close on hotkeys */
+ uiBlockBeginAlign(block);
+ for(a=0; a<5; a++)
+ uiDefButBitI(block, TOGR, 1<<a, 0, "",(short)(x1+a*dx),(short)(y1+dy),(short)dx,(short)dy, (int *)lay, 0, 0, 0, 0, "");
+ for(a=0; a<5; a++)
+ uiDefButBitI(block, TOGR, 1<<(a+10), 0, "",(short)(x1+a*dx),(short)y1,(short)dx,(short)dy, (int *)lay, 0, 0, 0, 0, "");
+ x1+= 5;
+
+ uiBlockBeginAlign(block);
+ for(a=5; a<10; a++)
+ uiDefButBitI(block, TOGR, 1<<a, 0, "",(short)(x1+a*dx),(short)(y1+dy),(short)dx,(short)dy, (int *)lay, 0, 0, 0, 0, "");
+ for(a=5; a<10; a++)
+ uiDefButBitI(block, TOGR, 1<<(a+10), 0, "",(short)(x1+a*dx),(short)y1,(short)dx,(short)dy, (int *)lay, 0, 0, 0, 0, "");
+ uiBlockEndAlign(block);
+
+ x1-= 5;
+ uiDefBut(block, BUT, 32767, "OK", (short)(x1+10*dx+10), (short)y1, (short)(3*dx), (short)(2*dy), NULL, 0, 0, 0, 0, "");
+
+ uiBoundsBlock(block, 2);
+
+ ret= uiDoBlocks(&listb, 0);
+
+ if(ret==UI_RETURN_OK) return 1;
+ return 0;
+}
+
+/* armature or bone */
+int movetolayer_short_buts(short *lay, char *title)
+{
+ uiBlock *block;
+ ListBase listb={0, 0};
+ int dx, dy, a, x1, y1, sizex=120, sizey=30;
+ short pivot[2], mval[2], ret=0;
+
+ getmouseco_sc(mval);
+
+ pivot[0]= CLAMPIS(mval[0], (sizex+10), G.curscreen->sizex-30);
+ pivot[1]= CLAMPIS(mval[1], (sizey/2)+10, G.curscreen->sizey-(sizey/2)-10);
+
+ if (pivot[0]!=mval[0] || pivot[1]!=mval[1])
+ warp_pointer(pivot[0], pivot[1]);
+
+ mywinset(G.curscreen->mainwin);
+
+ x1= pivot[0]-sizex+10;
+ y1= pivot[1]-sizey/2;
+
+ block= uiNewBlock(&listb, "button", UI_EMBOSS, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetFlag(block, UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_NUMSELECT|UI_BLOCK_ENTER_OK);
+
+ dx= (sizex-5)/10;
+ dy= sizey/2;
+
+ if(title)
+ uiDefBut(block, LABEL, 0, title, (short)(x1), (short)y1+30, sizex, 20, NULL, 1, 0, 0, 0, "");
+
+ /* buttons have 0 as return event, to prevent menu to close on hotkeys */
+ uiBlockBeginAlign(block);
+ for(a=0; a<8; a++)
+ uiDefButBitS(block, TOGR, 1<<a, 0, "",(short)(x1+a*dx),(short)(y1+dy),(short)dx,(short)dy, lay, 0, 0, 0, 0, "");
+ for(a=0; a<8; a++)
+ uiDefButBitS(block, TOGR, 1<<(a+8), 0, "",(short)(x1+a*dx),(short)y1,(short)dx,(short)dy, lay, 0, 0, 0, 0, "");
+
+ uiBlockEndAlign(block);
+
+ x1-= 5;
+ uiDefBut(block, BUT, 32767, "OK", (short)(x1+8*dx+10), (short)y1, (short)(3*dx), (short)(2*dy), NULL, 0, 0, 0, 0, "");
+
+ uiBoundsBlock(block, 2);
+
+ ret= uiDoBlocks(&listb, 0);
+
+ if(ret==UI_RETURN_OK) return 1;
+ return 0;
+}
+
+
+/* ********************** CLEVER_NUMBUTS ******************** */
+
+#define MAXNUMBUTS 120
+#define MAXNUMBUTROWS 8
+
+VarStruct numbuts[MAXNUMBUTS];
+void *numbpoin[MAXNUMBUTS];
+int numbdata[MAXNUMBUTS];
+
+void draw_numbuts_tip(char *str, int x1, int y1, int x2, int y2)
+{
+ static char *last=0; /* avoid ugly updates! */
+ int temp;
+
+ if(str==last) return;
+ last= str;
+ if(str==0) return;
+
+ glColor3ub(160, 160, 160); /* MGREY */
+ glRecti(x1+4, y2-36, x2-4, y2-16);
+
+ cpack(0x0);
+
+ temp= 0;
+ while( BIF_GetStringWidth(G.fonts, str+temp, (U.transopts & USER_TR_BUTTONS))>(x2 - x1-24)) temp++;
+ glRasterPos2i(x1+16, y2-30);
+ BIF_DrawString(G.fonts, str+temp, (U.transopts & USER_TR_BUTTONS));
+}
+
+int do_clever_numbuts(char *name, int tot, int winevent)
+{
+ ListBase listb= {NULL, NULL};
+ uiBlock *block;
+ VarStruct *varstr;
+ int a, sizex, sizey, x1, y2, width, colunms=1, xi=0, yi=0;
+ short mval[2], event;
+
+ /* Clear all events so tooltips work, this is not ideal and
+ only needed because calls from the menu still have some events
+ left over when do_clever_numbuts is called.
+ Calls from keyshortcuts do not have this problem.*/
+ ScrArea *sa;
+ BWinEvent temp_bevt;
+ for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
+ if(sa->win) {
+ while( bwin_qread( sa->win, &temp_bevt ) ) {}
+ }
+ if(sa->headwin) {
+ while( bwin_qread( sa->headwin, &temp_bevt ) ) {}
+ }
+ }
+ /* Done clearing events */
+
+ if(tot<=0 || tot>MAXNUMBUTS) return 0;
+
+ /* if we have too many buttons then have more then 1 column */
+ colunms= (int)ceil((double)tot / (double)MAXNUMBUTROWS);
+
+ getmouseco_sc(mval);
+
+ /* size */
+ sizex= 175;
+ sizey= 30+20*(MIN2(MAXNUMBUTROWS, tot)+1);
+ width= (sizex*colunms)+60;
+
+ /* center */
+ if(mval[0]<width/2) mval[0]=width/2;
+ if(mval[1]<sizey/2) mval[1]=sizey/2;
+ if(mval[0]>G.curscreen->sizex -width/2) mval[0]= G.curscreen->sizex -width/2;
+ if(mval[1]>G.curscreen->sizey -sizey/2) mval[1]= G.curscreen->sizey -sizey/2;
+
+ mywinset(G.curscreen->mainwin);
+
+ x1= mval[0]-width/2;
+ y2= mval[1]+sizey/2;
+
+ block= uiNewBlock(&listb, "numbuts", UI_EMBOSS, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetFlag(block, UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_RET_1|UI_BLOCK_ENTER_OK);
+
+ /* WATCH IT: TEX BUTTON EXCEPTION */
+ /* WARNING: ONLY A SINGLE BIT-BUTTON POSSIBLE: WE WORK AT COPIED DATA! */
+
+ BIF_ThemeColor(TH_MENU_TEXT); /* makes text readable on dark theme */
+
+ uiDefBut(block, LABEL, 0, name, (short)(x1+15), (short)(y2-35), (short)(width-60), 19, 0, 1.0, 0.0, 0, 0, "");
+
+ /*
+ if(name[0]=='A' && name[7]=='O') {
+ y2 -= 20;
+ uiDefBut(block, LABEL, 0, "Rotations in degrees!", (short)(x1+15), (short)(y2-35), (short)(sizex-60), 19, 0, 0.0, 0.0, 0, 0, "");
+ }*/
+
+ uiBlockBeginAlign(block);
+ varstr= &numbuts[0];
+ for(a=0; a<tot; a++, varstr++) {
+
+ if(varstr->type==TEX) {
+ uiDefBut(block, TEX, 0, varstr->name,(short)((x1+15) + (sizex*xi)),(short)(y2-55- 20*yi),(short)(sizex), 19, numbpoin[a], varstr->min, varstr->max, 0, 0, varstr->tip);
+ } else if(varstr->type==COL) {
+ uiDefButF(block, COL, 0, "",(short)((x1+15) + (sizex*xi)),(short)(y2-55- 20*yi),(short)(sizex), 19, numbpoin[a], varstr->min, varstr->max, 0, 0, "");
+ } else {
+ if(varstr->type==LABEL) {/* dont include the label when rounding the buttons */
+ uiBlockEndAlign(block);
+
+ /* using the tip for the name, this is incorrect lets us get around the 16 char limit of name */
+ /* Changed from the line below to use the tip since the tip isnt used for a label */
+ uiDefBut(block, varstr->type, 0, varstr->tip,(short)((x1+15) + (sizex*xi)),(short)(y2-55-20*yi), (short)(sizex), 19, &(numbdata[a]), varstr->min, varstr->max, 100, 0, "");
+ } else {
+ uiDefBut(block, varstr->type, 0, varstr->name,(short)((x1+15) + (sizex*xi)),(short)(y2-55-20*yi), (short)(sizex), 19, &(numbdata[a]), varstr->min, varstr->max, 100, 0, varstr->tip);
+ }
+
+ if(varstr->type==LABEL)
+ uiBlockBeginAlign(block);
+ }
+
+ /* move to the next column */
+ yi++;
+ if (yi>=MAXNUMBUTROWS) {
+ yi=0;
+ xi++;
+ uiBlockEndAlign(block);
+ uiBlockBeginAlign(block);
+ }
+ }
+ uiBlockEndAlign(block);
+
+ uiDefBut(block, BUT, 4000, "OK", (short)(x1+width-40),(short)(y2-35-20*MIN2(MAXNUMBUTROWS,a)), 25, (short)(sizey-50), 0, 0, 0, 0, 0, "OK: Assign Values");
+
+ uiBoundsBlock(block, 5);
+
+ event= uiDoBlocks(&listb, 0);
+
+ areawinset(curarea->win);
+
+ if(event & UI_RETURN_OK) {
+
+ varstr= &numbuts[0];
+ for(a=0; a<tot; a++, varstr++) {
+ if(varstr->type==TEX);
+ else if ELEM( (varstr->type & BUTPOIN), FLO, INT ) memcpy(numbpoin[a], numbdata+a, 4);
+ else if((varstr->type & BUTPOIN)==SHO ) *((short *)(numbpoin[a]))= *( (short *)(numbdata+a));
+ }
+
+ if(winevent) {
+ ScrArea *sa;
+
+ sa= G.curscreen->areabase.first;
+ while(sa) {
+ if(sa->spacetype==curarea->spacetype) addqueue(sa->win, winevent, 1);
+ sa= sa->next;
+ }
+ }
+
+ return 1;
+ }
+ return 0;
+}
+
+void add_numbut(int nr, int type, char *str, float min, float max, void *poin, char *tip)
+{
+ int tip_max = sizeof(numbuts[nr].tip);
+ int name_max = sizeof(numbuts[nr].name);
+
+ if(nr >= MAXNUMBUTS || (nr < 0)) return;
+
+ numbuts[nr].type= type;
+
+ numbuts[nr].min= min;
+ numbuts[nr].max= max;
+
+ if (type==LABEL) {
+ /* evil use it tooltip for the label string to get around the 16 char limit of "name" */
+ if (str) {
+ strncpy(numbuts[nr].tip, str, tip_max);
+ numbuts[nr].tip[tip_max-1] = 0;
+ } else {
+ strcpy(numbuts[nr].tip, "");
+ }
+ } else {
+ /* for all other types */
+ if (str) {
+ strncpy(numbuts[nr].name, str, name_max);
+ numbuts[nr].name[name_max-1] = 0;
+ } else {
+ strcpy(numbuts[nr].name, "");
+ }
+ if (tip) {
+ strncpy(numbuts[nr].tip, tip, tip_max);
+ numbuts[nr].tip[tip_max-1] = 0;
+ } else {
+ strcpy(numbuts[nr].tip, "");
+ }
+ }
+
+ /*WATCH: TEX BUTTON EXCEPTION */
+
+ numbpoin[nr]= poin;
+
+ if ELEM( (type & BUTPOIN), FLO, INT ) memcpy(numbdata+nr, poin, 4);
+ if((type & BUTPOIN)==SHO ) *((short *)(numbdata+nr))= *( (short *)poin);
+
+ /* if( strncmp(numbuts[nr].name, "Rot", 3)==0 ) {
+ float *fp;
+
+ fp= (float *)(numbdata+nr);
+ fp[0]= 180.0*fp[0]/M_PI;
+ } */
+
+}
+
+void clever_numbuts(void)
+{
+
+ if(curarea->spacetype==SPACE_VIEW3D) {
+ // panel now
+ }
+ else if(curarea->spacetype==SPACE_NLA){
+ // panel now
+ }
+ else if(curarea->spacetype==SPACE_IPO) {
+ // panel now
+ }
+ else if(curarea->spacetype==SPACE_SEQ) {
+ // panel now
+ }
+ else if(curarea->spacetype==SPACE_IMAGE) {
+ // panel now
+ }
+ else if(curarea->spacetype==SPACE_IMASEL) {
+ clever_numbuts_imasel();
+ }
+ else if(curarea->spacetype==SPACE_OOPS) {
+ clever_numbuts_oops();
+ }
+ else if(curarea->spacetype==SPACE_ACTION){
+ // in its own queue
+ }
+ else if(curarea->spacetype==SPACE_FILE) {
+ clever_numbuts_filesel();
+ }
+}
+
+
+void replace_names_but(void)
+{
+ Image *ima= G.main->image.first;
+ short len, tot=0;
+ char old[64], new[64], temp[80];
+
+ strcpy(old, "/");
+ strcpy(new, "/");
+
+ add_numbut(0, TEX, "Old:", 0, 63, old, 0);
+ add_numbut(1, TEX, "New:", 0, 63, new, 0);
+
+ if (do_clever_numbuts("Replace image name", 2, REDRAW) ) {
+
+ len= strlen(old);
+
+ while(ima) {
+
+ if(strncmp(old, ima->name, len)==0) {
+
+ strcpy(temp, new);
+ strcat(temp, ima->name+len);
+ BLI_strncpy(ima->name, temp, sizeof(ima->name));
+
+ BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE);
+
+ tot++;
+ }
+
+ ima= ima->id.next;
+ }
+
+ notice("Replaced %d names", tot);
+ }
+
+}
+
+
+/* ********************** NEW TOOLBOX ********************** */
+
+ListBase tb_listb= {NULL, NULL};
+
+#define TB_TAB 256
+#define TB_ALT 512
+#define TB_CTRL 1024
+#define TB_PAD 2048
+#define TB_SHIFT 4096
+
+typedef struct TBitem {
+ int icon;
+ char *name;
+ int retval;
+ void *poin;
+} TBitem;
+
+static void tb_do_hotkey(void *arg, int event)
+{
+ unsigned short i, key=0;
+ unsigned short qual[] = { 0,0,0,0 };
+
+ if(event & TB_CTRL) {
+ qual[0] = LEFTCTRLKEY;
+ event &= ~TB_CTRL;
+ }
+ if(event & TB_ALT) {
+ qual[1] = LEFTALTKEY;
+ event &= ~TB_ALT;
+ }
+ if(event & TB_SHIFT) {
+ qual[2] = LEFTSHIFTKEY;
+ event &= ~TB_SHIFT;
+ }
+
+ if(event & TB_TAB) key= TABKEY;
+ else if(event & TB_PAD) {
+ event &= ~TB_PAD;
+ switch(event) {
+ case '-': key= PADMINUS; break;
+ case '+': key= PADPLUSKEY; break;
+ case '0': key= PAD0; break;
+ case '5': key= PAD5; break;
+ case '/': key= PADSLASHKEY; break;
+ case '.': key= PADPERIOD; break;
+ case '*': key= PADASTERKEY; break;
+ case 'h': key= HOMEKEY; break;
+ case 'u': key= PAGEUPKEY; break;
+ case 'd': key= PAGEDOWNKEY; break;
+ }
+ }
+ else asciitoraw(event, &key, &qual[3]);
+
+ for (i=0;i<4;i++)
+ {
+ if(qual[i]) mainqenter(qual[i], 1);
+ }
+ mainqenter(key, 1);
+ mainqenter(key, 0);
+ mainqenter(EXECUTE, 1);
+
+ for (i=0;i<4;i++)
+ {
+ if(qual[i]) mainqenter(qual[i], 0);
+ }
+}
+
+/* *************Select ********** */
+
+static TBitem tb_object_select_layer1_5[]= {
+{ 0, "1", 1, NULL},
+{ 0, "2", 2, NULL},
+{ 0, "3", 3, NULL},
+{ 0, "4", 4, NULL},
+{ 0, "5", 5, NULL},
+{ -1, "", 0, do_view3d_select_object_layermenu}};
+
+static TBitem tb_object_select_layer6_10[]= {
+{ 0, "6", 6, NULL},
+{ 0, "7", 7, NULL},
+{ 0, "8", 8, NULL},
+{ 0, "9", 9, NULL},
+{ 0, "10", 10, NULL},
+{ -1, "", 0, do_view3d_select_object_layermenu}};
+
+static TBitem tb_object_select_layer11_15[]= {
+{ 0, "11", 11, NULL},
+{ 0, "12", 12, NULL},
+{ 0, "13", 13, NULL},
+{ 0, "14", 14, NULL},
+{ 0, "15", 15, NULL},
+{ -1, "", 0, do_view3d_select_object_layermenu}};
+
+static TBitem tb_object_select_layer16_20[]= {
+{ 0, "16", 16, NULL},
+{ 0, "17", 17, NULL},
+{ 0, "18", 18, NULL},
+{ 0, "19", 19, NULL},
+{ 0, "20", 20, NULL},
+{ -1, "", 0, do_view3d_select_object_layermenu}};
+
+static TBitem tb_object_select_layer[]= {
+{ 0, "Layers 1-5", 0, tb_object_select_layer1_5},
+{ 0, "Layers 6-10", 0, tb_object_select_layer6_10},
+{ 0, "Layers 11-15", 0, tb_object_select_layer11_15},
+{ 0, "Layers 16-20", 0, tb_object_select_layer16_20},
+{ -1, "", 0, tb_do_hotkey}};
+
+static TBitem tb_object_select_type[]= {
+{ 0, "Mesh", 1, NULL},
+{ 0, "Curve", 2, NULL},
+{ 0, "Surface", 3, NULL},
+{ 0, "Meta", 4, NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Armature", 5, NULL},
+{ 0, "Lattice", 6, NULL},
+{ 0, "Text", 7, NULL},
+{ 0, "Empty", 8, NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Camera", 9, NULL},
+{ 0, "Lamp", 10, NULL},
+{ -1, "", 0, do_view3d_select_object_typemenu}};
+
+static TBitem tb_object_select_linked[]= {
+{ 0, "Object Ipo|Shift L, 1", 1, NULL},
+{ 0, "ObData|Shift L, 2", 2, NULL},
+{ 0, "Material|Shift L, 3", 3, NULL},
+{ 0, "Texture|Shift L, 4", 4, NULL},
+{ -1, "", 0, do_view3d_select_object_linkedmenu}};
+
+static TBitem tb_object_select_grouped[]= {
+{ 0, "Children|Shift G, 1", 1, NULL},
+{ 0, "Immediate Children|Shift G, 2", 2, NULL},
+{ 0, "Parent|Shift G, 3", 3, NULL},
+{ 0, "Siblings (Shared Parent)|Shift G, 4", 4, NULL},
+{ 0, "Objects of Same Type|Shift G, 5", 5, NULL},
+{ 0, "Objects on Shared Layers|Shift G, 6", 6, NULL},
+{ 0, "Objects in Same Group|Shift G, 7", 7, NULL},
+{ 0, "Object Hooks|Shift G, 8", 8, NULL},
+{ 0, "Object PassIndex|Shift G, 9", 9, NULL},
+{ -1, "", 0, do_view3d_select_object_groupedmenu}};
+
+static TBitem tb_object_select[]= {
+{ 0, "Border Select|B", 0, NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Select/Deselect All|A", 1, NULL},
+{ 0, "Inverse", 2, NULL},
+{ 0, "Select All by Layer", 0, tb_object_select_layer},
+{ 0, "Select All by Type", 0, tb_object_select_type},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Linked", 0, tb_object_select_linked},
+{ 0, "Grouped", 0, tb_object_select_grouped},
+{ -1, "", 0, do_view3d_select_objectmenu}};
+
+static TBitem tb_face_select[]= {
+{ 0, "Border Select|B", 0, NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Select/Deselect All|A", 2, NULL},
+{ 0, "Inverse", 3, NULL},
+{ 0, "Same UV", 4, NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Linked Faces|Ctrl L", 5, NULL},
+{ -1, "", 0, do_view3d_select_faceselmenu}};
+
+static TBitem tb_mesh_select[]= {
+{ 0, "Border Select|B", 0, NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Select/Deselect All|A", 2, NULL},
+{ 0, "Inverse|Ctrl I", 3, NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Random...", 5, NULL},
+{ 0, "Non-Manifold|Shift Ctrl Alt M", 9, NULL},
+{ 0, "Sharp Edges|Shift Ctrl Alt S", 14, NULL},
+{ 0, "Linked Flat Faces|Shift Ctrl Alt F", 15, NULL},
+{ 0, "Triangles|Shift Ctrl Alt 3", 11, NULL},
+{ 0, "Quads|Shift Ctrl Alt 4", 12, NULL},
+{ 0, "Non-Triangles/Quads|Shift Ctrl Alt 5", 13, NULL},
+{ 0, "Similar to Selection|Shift G", 21, NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "More|Ctrl NumPad +", 7, NULL},
+{ 0, "Less|Ctrl NumPad -", 8, NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Linked Vertices|Ctrl L", 4, NULL},
+{ 0, "Vertex Path|W Alt 7", 16, NULL},
+{ 0, "Edge Loop|Ctrl E 6", 17, NULL},
+{ 0, "Edge Ring|Ctrl E 7", 18, NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Loop to Region|Ctrl E 8", 19, NULL},
+{ 0, "Region to Loop|Ctrl E 9", 20, NULL},
+{ -1, "", 0, do_view3d_select_meshmenu}};
+
+
+static TBitem tb_curve_select[]= {
+{ 0, "Border Select|B", 0, NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "(De)select All|A", 2, NULL},
+{ 0, "Inverse", 3, NULL},
+{ 0, "Random...", 13, NULL},
+{ 0, "Every Nth", 14, NULL},
+{ 0, "Row|Shift R", 5, NULL}, /* shouldn't be visible in case of bezier curves*/
+{ 0, "SEPR", 0, NULL},
+{ 0, "(De)select First", 7, NULL},
+{ 0, "(De)select Last", 8, NULL},
+{ 0, "Select Next", 11, NULL},
+{ 0, "Select Previous", 12, NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "More|Ctrl NumPad +", 9, NULL},
+{ 0, "Less|Ctrl NumPad -", 10, NULL},
+{ -1, "", 0, do_view3d_select_curvemenu}};
+
+static TBitem tb_mball_select[]= {
+{ 0, "Border Select|B", 0, NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "(De)select All|A", 2, NULL},
+{ 0, "Inverse", 3, NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Random...", 4, NULL},
+{ -1, "", 0, do_view3d_select_metaballmenu}};
+
+static TBitem tb__select[]= {
+{ 0, "Border Select|B", 'b', NULL},
+{ 0, "(De)select All|A", 'a', NULL},
+{ -1, "", 0, tb_do_hotkey}};
+
+
+/* *************Edit ********** */
+
+static TBitem tb_edit[]= {
+{ 0, "Exit Editmode|Tab", TB_TAB, NULL},
+{ -1, "", 0, tb_do_hotkey}};
+
+static TBitem tb_curve_edit_seg[]= {
+{ 0, "Subdivide|W, 1", 0, NULL},
+{ 0, "Switch Direction|W, 2", 1, NULL},
+{ -1, "", 0, do_view3d_edit_curve_segmentsmenu}};
+
+static TBitem tb_curve_edit_cv[]= {
+{ 0, "Tilt|T", 't', NULL},
+{ 0, "Clear Tilt|Alt T", TB_ALT|'t', NULL},
+{ 0, "Separate|P", 'p', NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Automatic|Shift H", 'H', NULL},
+{ 0, "Toggle Free/Aligned|H", 'h', NULL},
+{ 0, "Vector|V", 'v', NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Make Vertex Parent|Ctrl P", TB_CTRL|'p', NULL},
+{ 0, "Add Hook|Ctrl H", TB_CTRL|'h', NULL},
+{ -1, "", 0, tb_do_hotkey}};
+
+
+static TBitem tb_curve_edit[]= {
+{ 0, "Exit Editmode|Tab", TB_TAB, NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Extrude|E", 'e', NULL},
+{ 0, "Duplicate|Shift D", 'D', NULL},
+{ 0, "Make Segment|F", 'f', NULL},
+{ 0, "Toggle Cyclic|C", 'c', NULL},
+{ 0, "Delete...|X", 'x', NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Control Points", 0, tb_curve_edit_cv},
+{ 0, "Segments", 0, tb_curve_edit_seg},
+{ -1, "", 0, tb_do_hotkey}};
+
+
+static TBitem tb_mesh_edit_vertex[]= {
+{ 0, "Merge...|Alt M", 5, NULL},
+{ 0, "Rip|V", 7, NULL},
+{ 0, "Split|Y", 4, NULL},
+{ 0, "Separate|P", 3, NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Smooth|W, Alt 1", 2, NULL},
+{ 0, "Remove Doubles|W, 6", 1, NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Make Vertex Parent|Ctrl P", 0, NULL},
+{ 0, "Add Hook|Ctrl H", 6, NULL},
+{ -1, "", 0, do_view3d_edit_mesh_verticesmenu}};
+
+static TBitem tb_mesh_edit_edge[]= {
+{ 0, "Make Edge/Face|F", 5, NULL},
+{ 0, "Collapse|Alt M", 14, NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Bevel|W, Alt 2", 6, NULL},
+{ 0, "Loop Subdivide|Ctrl R", 4, NULL},
+{ 0, "Knife Subdivide...|Shift K", 3, NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Subdivide|W, 1", 2, NULL},
+{ 0, "Subdivide Fractal|W, 2", 1, NULL},
+{ 0, "Subdivide Smooth|W, 3", 0, NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Mark Seam|Ctrl E", 7, NULL},
+{ 0, "Clear Seam|Ctrl E", 8, NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Crease SubSurf|Shift E", 9, NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Rotate Edge CW|Ctrl E", 10, NULL},
+{ 0, "Rotate Edge CCW|Ctrl E", 11, NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Slide Edge|Ctrl E", 12, NULL},
+{ 0, "Delete Edge Loop|X", 13, NULL},
+{ -1, "", 0, do_view3d_edit_mesh_edgesmenu}};
+
+static TBitem tb_mesh_edit_face[]= {
+{ 0, "Make Edge/Face|F", 5, NULL},
+{ 0, "Fill|Shift F", 0, NULL},
+{ 0, "Beautify Fill|Alt F", 1, NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Convert to Triangles|Ctrl T", 2, NULL},
+{ 0, "Convert to Quads|Alt J", 3, NULL},
+{ 0, "Flip Triangle Edges|Ctrl Shift F", 4, NULL},
+{ 0, "Set Smooth|Ctrl F, 3", 6, NULL},
+{ 0, "Set Solid|Ctrl F, 4", 7, NULL},
+{ -1, "", 0, do_view3d_edit_mesh_facesmenu}};
+
+
+static TBitem tb_mesh_edit_normal[]= {
+{ 0, "Recalculate Outside|Ctrl N", 2, NULL},
+{ 0, "Recalculate Inside|Ctrl Shift N", 1, NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Flip|Ctrl F, 1", 0, NULL},
+{ -1, "", 0, do_view3d_edit_mesh_normalsmenu}};
+
+static TBitem tb_mesh_edit[]= {
+{ 0, "Exit Editmode|Tab", TB_TAB, NULL},
+{ 0, "Undo|Ctrl Z", 'u', NULL},
+{ 0, "Redo|Ctrl Shift Z", 'U', NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Extrude|E", 'e', NULL},
+{ 0, "Duplicate|Shift D", 'D', NULL},
+{ 0, "Delete...|X", 'x', NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Vertices", 0, tb_mesh_edit_vertex},
+{ 0, "Edges", 0, tb_mesh_edit_edge},
+{ 0, "Faces", 0, tb_mesh_edit_face},
+{ 0, "Normals", 0, tb_mesh_edit_normal},
+{ -1, "", 0, tb_do_hotkey}};
+
+
+static TBitem tb_object_ipo[]= {
+{ 0, "Show/Hide", 'k', NULL},
+{ 0, "Select Next", TB_PAD|'u', NULL},
+{ 0, "Select Prev", TB_PAD|'d', NULL},
+{ -1, "", 0, tb_do_hotkey}};
+
+
+static TBitem tb_object_edit[]= {
+{ 0, "Enter Editmode|Tab", TB_TAB, NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Duplicate|Shift D", 'D', NULL},
+{ 0, "Duplicate Linked|Alt D", TB_ALT|'d', NULL},
+{ 0, "Delete|X", 'x', NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Object Keys", 0, tb_object_ipo},
+{ -1, "", 0, tb_do_hotkey}};
+
+
+/* ************* Type ********** */
+
+static TBitem tb_obdata_hide[]= {
+{ 0, "Show Hidden|Alt H", TB_ALT|'h', NULL},
+{ 0, "Hide Selected|H", 'h', NULL},
+{ 0, "Hide Deselected|Shift H", 'H', NULL},
+{ -1, "", 0, tb_do_hotkey}};
+
+static void tb_do_mesh(void *arg, int event){
+ switch(event) {
+ case 1: common_insertkey(); break;
+ case 2: G.f ^= G_DRAWEDGES; break;
+ case 3: G.f ^= G_DRAWFACES; break;
+ case 4: G.f ^= G_DRAWNORMALS; break;
+ case 5: flip_subdivison(-1); break;
+ }
+ addqueue(curarea->win, REDRAW, 1);
+}
+
+static TBitem tb_mesh[]= {
+{ 0, "Insert Keyframe|I", 1, NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Show/Hide Edges", 2, NULL},
+{ 0, "Show/Hide Faces", 3, NULL},
+{ 0, "Show/Hide Normals", 4, NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Subdivision Surface", 5, NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Show/Hide Vertices", 0, tb_obdata_hide},
+{ -1, "", 0, tb_do_mesh}};
+
+static TBitem tb_curve_hide[]= {
+{ 0, "Show Hidden|Alt H", 10, NULL},
+{ 0, "Hide Selected|Alt Ctrl H", 11, NULL},
+{ -1, "", 0, do_view3d_edit_curve_showhidemenu}};
+
+
+static TBitem tb_curve[]= {
+{ 0, "Insert Keyframe|I", 'i', NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Show/Hide Points", 0, tb_curve_hide},
+{ -1, "", 0, tb_do_hotkey}};
+
+static TBitem tb_obdata[]= {
+{ 0, "Duplicate|Shift D", 'D', NULL},
+{ 0, "Delete|X", 'x', NULL},
+{ -1, "", 0, tb_do_hotkey}};
+
+static TBitem tb_object_parent[]= {
+{ 0, "Make Parent...|Ctrl P", TB_CTRL|'p', NULL},
+{ 0, "Clear Parent...|Alt P", TB_ALT|'p', NULL},
+{ -1, "", 0, tb_do_hotkey}};
+
+static TBitem tb_object_track[]= {
+{ 0, "Make Track|Ctrl T", TB_CTRL|'t', NULL},
+{ 0, "Clear Track|Alt T", TB_ALT|'t', NULL},
+{ -1, "", 0, tb_do_hotkey}};
+
+static TBitem tb_object[]= {
+{ 0, "Insert Keyframe|I", 'i', NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Make Links...|Ctrl L", TB_CTRL|'l', NULL},
+{ 0, "Make Single User...|U", 'u', NULL},
+{ 0, "Copy Attributes...|Ctrl C", TB_CTRL|'c', NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Parent", 0, tb_object_parent},
+{ 0, "Track", 0, tb_object_track},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Boolean Operation|W", 'w', NULL},
+{ 0, "Join Objects...|Ctrl J", TB_CTRL|'j', NULL},
+{ 0, "Convert Object Type...|Alt C", TB_ALT|'c', NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Move to Layer...|M", 'm', NULL},
+{ -1, "", 0, tb_do_hotkey}};
+
+
+/* *************VIEW ********** */
+
+static void tb_do_view_dt(void *arg, int event){
+ G.vd->drawtype= event;
+ addqueue(curarea->win, REDRAW, 1);
+}
+
+static TBitem tb_view_dt[]= {
+{ ICON_BBOX, "Bounding Box", 1, NULL},
+{ ICON_WIRE, "Wireframe|Z", 2, NULL},
+{ ICON_SOLID, "Solid|Z", 3, NULL},
+{ ICON_SMOOTH, "Shaded|Shift Z", 4, NULL},
+{ ICON_POTATO, "Textured|Alt Z", 5, NULL},
+{ -1, "", 0, tb_do_view_dt}};
+
+static TBitem tb_view_alignview[]= {
+{ 0, "Center View to Cursor|C", 'c', NULL},
+{ 0, "Align Active Camera to View|Ctrl Alt NumPad 0",
+TB_CTRL|TB_ALT|TB_PAD|'0', NULL},
+{ 0, "Align View to Selected|NumPad *", TB_PAD|'*', NULL},
+{ -1, "", 0, tb_do_hotkey}};
+
+static TBitem tb_view[]= {
+{ 0, "Viewport Shading", 0, tb_view_dt},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Ortho/Perspective|NumPad 5", TB_PAD|'5', NULL},
+{ 0, "Local/Global View|NumPad /", TB_PAD|'/', NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Align View", 0, tb_view_alignview},
+{ 0, "SEPR", 0, NULL},
+{ 0, "View Selected|NumPad .", TB_PAD|'.', NULL},
+{ 0, "View All|Home", TB_PAD|'h', NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Play Back Animation|Alt A", TB_ALT|'a', NULL},
+{ 0, "Camera Fly Mode|Shift F", TB_SHIFT|'f', NULL},
+{ -1, "", 0, tb_do_hotkey}};
+
+
+/* *************TRANSFORM ********** */
+
+static TBitem tb_transform_moveaxis[]= {
+{ 0, "X Global|G, X", 0, NULL},
+{ 0, "Y Global|G, Y", 1, NULL},
+{ 0, "Z Global|G, Z", 2, NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "X Local|G, X, X", 3, NULL},
+{ 0, "Y Local|G, Y, Y", 4, NULL},
+{ 0, "Z Local|G, Z, Z", 5, NULL},
+{ -1, "", 0, do_view3d_transform_moveaxismenu}};
+
+static TBitem tb_transform_rotateaxis[]= {
+{ 0, "X Global|R, X", 0, NULL},
+{ 0, "Y Global|R, Y", 1, NULL},
+{ 0, "Z Global|R, Z", 2, NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "X Local|R, X, X", 3, NULL},
+{ 0, "Y Local|R, Y, Y", 4, NULL},
+{ 0, "Z Local|R, Z, Z", 5, NULL},
+{ -1, "", 0, do_view3d_transform_rotateaxismenu}};
+
+static TBitem tb_transform_scaleaxis[]= {
+{ 0, "X Global|S, X", 0, NULL},
+{ 0, "Y Global|S, Y", 1, NULL},
+{ 0, "Z Global|S, Z", 2, NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "X Local|S, X, X", 3, NULL},
+{ 0, "Y Local|S, Y, Y", 4, NULL},
+{ 0, "Z Local|S, Z, Z", 5, NULL},
+{ -1, "", 0, do_view3d_transform_scaleaxismenu}};
+
+static void tb_do_transform_clearapply(void *arg, int event)
+{
+ Object *ob;
+ ob= OBACT;
+
+ switch(event)
+ {
+ case 0: /* clear location */
+ clear_object('g');
+ break;
+ case 1: /* clear rotation */
+ clear_object('r');
+ break;
+ case 2: /* clear scale */
+ clear_object('s');
+ break;
+ case 3: /* apply scale/rotation */
+ apply_object();
+ break;
+ case 4: /* apply deformation */
+ object_apply_deform(ob);
+ break;
+ case 5: /* make duplicates real */
+ if (ob->transflag & OB_DUPLI) make_duplilist_real();
+ else error("The active object does not have dupliverts");
+ break;
+ }
+}
+
+static TBitem tb_transform_clearapply[]= {
+{ 0, "Clear Location|Alt G", 0, NULL},
+{ 0, "Clear Rotation|Alt R", 1, NULL},
+{ 0, "Clear Scale|Alt S", 2, NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Apply Scale/Rotation|Ctrl A", 3, NULL},
+{ 0, "Apply Deformation|Shift Ctrl A", 4, NULL},
+{ 0, "Make Duplicates Real|Shift Ctrl A", 5, NULL},
+{ -1, "", 0, tb_do_transform_clearapply}};
+
+static TBitem tb_transform_snap[]= {
+{ 0, "Selection -> Grid|Shift S, 1", 1, NULL},
+{ 0, "Selection -> Cursor|Shift S, 2", 2, NULL},
+{ 0, "Cursor -> Grid|Shift S, 3", 3, NULL},
+{ 0, "Cursor -> Selection|Shift S, 4", 4, NULL},
+{ 0, "Selection -> Center|Shift S, 5", 5, NULL},
+{ -1, "", 0, do_view3d_edit_snapmenu}};
+
+static void tb_do_transform(void *arg, int event)
+{
+ switch(event)
+ {
+ case 0: /* Grab/move */
+ initTransform(TFM_TRANSLATION, CTX_NONE);
+ Transform();
+ break;
+ case 1: /* Rotate */
+ initTransform(TFM_ROTATION, CTX_NONE);
+ Transform();
+ break;
+ case 2: /* Scale */
+ initTransform(TFM_RESIZE,CTX_NONE);
+ Transform();
+ break;
+ case 3: /* transform properties */
+ add_blockhandler(curarea, VIEW3D_HANDLER_OBJECT, UI_PNL_UNSTOW);
+ break;
+ case 4: /* snap */
+ snapmenu();
+ break;
+ case 5: /* Shrink/Fatten Along Normals */
+ initTransform(TFM_SHRINKFATTEN, CTX_NONE);
+ Transform();
+ break;
+ case 6: /* Shear */
+ initTransform(TFM_SHEAR, CTX_NONE);
+ Transform();
+ break;
+ case 7: /* Warp */
+ initTransform(TFM_WARP, CTX_NONE);
+ Transform();
+ break;
+ case 8: /* proportional edit (toggle) */
+ if(G.scene->proportional) G.scene->proportional= 0;
+ else G.scene->proportional= 1;
+ break;
+ case 10:
+ docenter(0);
+ break;
+ case 11:
+ docenter_new();
+ break;
+ case 12:
+ docenter_cursor();
+ break;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static TBitem tb_transform_object_mirror[]= {
+{ 0, "X Local|Ctrl M, 1", 1, NULL},
+{ 0, "Y Local|Ctrl M, 2", 2, NULL},
+{ 0, "Z Local|Ctrl M, 3", 3, NULL},
+{ -1, "", 0, do_view3d_object_mirrormenu}};
+
+static TBitem tb_transform[]= {
+{ 0, "Grab/Move|G", 0, NULL},
+{ 0, "Grab/Move on Axis| ", 0, tb_transform_moveaxis},
+{ 0, "Rotate|R", 1, NULL},
+{ 0, "Rotate on Axis", 0, tb_transform_rotateaxis},
+{ 0, "Scale|S", 2, NULL},
+{ 0, "Scale on Axis", 0, tb_transform_scaleaxis},
+{ 0, "SEPR", 0, NULL},
+{ 0, "ObData to Center", 10, NULL},
+{ 0, "Center New", 11, NULL},
+{ 0, "Center Cursor", 12, NULL},
+{ 0, "SEPR", 0, NULL},
+{ ICON_MENU_PANEL, "Properties|N", 3, NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Mirror", 0, tb_transform_object_mirror},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Snap", 0, tb_transform_snap},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Clear/Apply", 0, tb_transform_clearapply},
+{ -1, "", 0, tb_do_transform}};
+
+static TBitem tb_transform_edit_mirror[]= {
+{ 0, "X Global|Ctrl M, 1", 1, NULL},
+{ 0, "Y Global|Ctrl M, 2", 2, NULL},
+{ 0, "Z Global|Ctrl M, 3", 3, NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "X Local|Ctrl M, 4", 4, NULL},
+{ 0, "Y Local|Ctrl M, 5", 5, NULL},
+{ 0, "Z Local|Ctrl M, 6", 6, NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "X View|Ctrl M, 7", 7, NULL},
+{ 0, "Y View|Ctrl M, 8", 8, NULL},
+{ 0, "Z View|Ctrl M, 9", 9, NULL},
+{ -1, "", 0, do_view3d_edit_mirrormenu}};
+
+static TBitem tb_transform_editmode1[]= {
+{ 0, "Grab/Move|G", 0, NULL},
+{ 0, "Grab/Move on Axis| ", 0, tb_transform_moveaxis},
+{ 0, "Rotate|R", 1, NULL},
+{ 0, "Rotate on Axis", 0, tb_transform_rotateaxis},
+{ 0, "Scale|S", 2, NULL},
+{ 0, "Scale on Axis", 0, tb_transform_scaleaxis},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Shrink/Fatten|Alt S", 5, NULL},
+{ 0, "Shear|Ctrl S", 6, NULL},
+{ 0, "Warp|Shift W", 7, NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "ObData to Center", 10, NULL},
+{ 0, "SEPR", 0, NULL},
+{ ICON_MENU_PANEL, "Properties|N", 3, NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Mirror", 0, tb_transform_edit_mirror},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Snap", 0, tb_transform_snap},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Proportional Edit|O", 8, NULL},
+{ -1, "", 0, tb_do_transform}};
+
+
+static TBitem tb_transform_editmode2[]= {
+{ 0, "Grab/Move|G", 0, NULL},
+{ 0, "Grab/Move on Axis| ", 0, tb_transform_moveaxis},
+{ 0, "Rotate|R", 1, NULL},
+{ 0, "Rotate on Axis", 0, tb_transform_rotateaxis},
+{ 0, "Scale|S", 2, NULL},
+{ 0, "Scale on Axis", 0, tb_transform_scaleaxis},
+{ 0, "SEPR", 0, NULL},
+{ ICON_MENU_PANEL, "Properties|N", 3, NULL},
+{ 0, "Snap", 0, tb_transform_snap},
+{ -1, "", 0, tb_do_transform}};
+
+
+/* *************ADD ********** */
+
+static TBitem addmenu_curve[]= {
+{ 0, "Bezier Curve", 0, NULL},
+{ 0, "Bezier Circle", 1, NULL},
+{ 0, "NURBS Curve", 2, NULL},
+{ 0, "NURBS Circle", 3, NULL},
+{ 0, "Path", 4, NULL},
+{ -1, "", 0, do_info_add_curvemenu}};
+
+static TBitem addmenu_surf[]= {
+{ 0, "NURBS Curve", 0, NULL},
+{ 0, "NURBS Circle", 1, NULL},
+{ 0, "NURBS Surface", 2, NULL},
+{ 0, "NURBS Tube", 3, NULL},
+{ 0, "NURBS Sphere", 4, NULL},
+{ 0, "NURBS Donut", 5, NULL},
+{ -1, "", 0, do_info_add_surfacemenu}};
+
+static TBitem addmenu_meta[]= {
+{ 0, "Meta Ball", 0, NULL},
+{ 0, "Meta Tube", 1, NULL},
+{ 0, "Meta Plane", 2, NULL},
+{ 0, "Meta Ellipsoid", 3, NULL},
+{ 0, "Meta Cube", 4, NULL},
+{ -1, "", 0, do_info_add_metamenu}};
+
+static TBitem addmenu_lamp[]= {
+{ 0, "Lamp", 0, NULL},
+{ 0, "Sun", 1, NULL},
+{ 0, "Spot", 2, NULL},
+{ 0, "Hemi", 3, NULL},
+{ 0, "Area", 4, NULL},
+{ -1, "", 0, do_info_add_lampmenu}};
+
+static TBitem addmenu_YF_lamp[]= {
+{ 0, "Lamp", 0, NULL},
+{ 0, "Sun", 1, NULL},
+{ 0, "Spot", 2, NULL},
+{ 0, "Hemi", 3, NULL},
+{ 0, "Area", 4, NULL},
+{ 0, "Photon", 5, NULL},
+{ -1, "", 0, do_info_add_lampmenu}};
+
+
+static TBitem addmenu_armature[]= {
+{ 0, "Bone", 8, NULL},
+{ -1, "", 0, do_info_addmenu}};
+
+/* dynamic items */
+#define TB_ADD_MESH 0
+#define TB_ADD_GROUP 7
+#define TB_ADD_LAMP 10
+
+static TBitem tb_add[]= {
+{ 0, "Mesh", 0, NULL},
+{ 0, "Curve", 1, addmenu_curve},
+{ 0, "Surface", 2, addmenu_surf},
+{ 0, "Meta", 3, addmenu_meta},
+{ 0, "Text", 4, NULL},
+{ 0, "Empty", 5, NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Group", 10, NULL},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Camera", 6, NULL},
+{ 0, "Lamp", 7, addmenu_lamp},
+{ 0, "SEPR", 0, NULL},
+{ 0, "Armature", 8, NULL},
+{ 0, "Lattice", 9, NULL},
+{ -1, "", 0, do_info_addmenu}};
+
+static TBitem tb_empty[]= {
+{ 0, "Nothing...", 0, NULL},
+{ -1, "", 0, NULL}};
+
+
+/* *************RENDER ********** */
+
+static void tb_do_render(void *arg, int event){
+ switch(event)
+ {
+ case 1: /* set render border */
+ set_render_border();
+ break;
+ case 2: /* render */
+ BIF_do_render(0);
+ break;
+ case 3: /* render anim */
+ BIF_do_render(1);
+ break;
+ case 4: /* passepartout */
+ {
+ Camera *ca= NULL;
+ if(G.vd->camera==NULL) return;
+
+ if(G.vd->camera->type==OB_CAMERA)
+ ca= G.vd->camera->data;
+ else return;
+
+ if (ca && (ca->flag & CAM_SHOWPASSEPARTOUT))
+ ca->flag &= ~CAM_SHOWPASSEPARTOUT;
+ else
+ ca->flag |= CAM_SHOWPASSEPARTOUT;
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ break;
+ case 5: /*preview render */
+ toggle_blockhandler(curarea, VIEW3D_HANDLER_PREVIEW, 0);
+ scrarea_queue_winredraw(curarea);
+ break;
+ }
+}
+
+static TBitem tb_render[]= {
+ { 0, "Passepartout", 4, NULL},
+ { 0, "Set Border|Shift B", 1, NULL},
+ { 0, "SEPR", 0, NULL},
+ { 0, "Render|F12", 2, NULL},
+ { 0, "Anim|Ctrl F12", 3, NULL},
+ { 0, "Preview|Shift P", 5, NULL},
+ { -1, "", 0, tb_do_render}};
+
+/* ************************* NODES *********************** */
+
+
+/* dynamic items */
+
+static TBitem tb_node_addsh[]= {
+ { 0, "Input", 1, NULL},
+ { 0, "Output", 2, NULL},
+ { 0, "Color", 3, NULL},
+ { 0, "Vector", 4, NULL},
+ { 0, "Convertor", 5, NULL},
+ { 0, "Group", 6, NULL},
+ { -1, "", 0, NULL}};
+
+static TBitem tb_node_addcomp[]= {
+ { 0, "Input", 1, NULL},
+ { 0, "Output", 2, NULL},
+ { 0, "Color", 3, NULL},
+ { 0, "Vector", 4, NULL},
+ { 0, "Filter", 5, NULL},
+ { 0, "Convertor", 6, NULL},
+ { 0, "Matte", 7, NULL},
+ { 0, "Distort", 8, NULL},
+ { 0, "Group", 9, NULL},
+ { -1, "", 0, NULL}};
+
+/* do_node_addmenu() in header_node.c, prototype in BSE_headerbuttons.h */
+
+/* dynamic toolbox sublevel */
+static TBitem *node_add_sublevel(ListBase *storage, bNodeTree *ntree, int nodeclass)
+{
+ static TBitem _addmenu[]= { { 0, " ", 0, NULL}, { -1, "", 0, NULL}};
+ Link *link;
+ TBitem *addmenu;
+ int tot= 0, a;
+
+ if(ntree) {
+ if(nodeclass==NODE_CLASS_GROUP) {
+ bNodeTree *ngroup= G.main->nodetree.first;
+ for(; ngroup; ngroup= ngroup->id.next)
+ if(ngroup->type==ntree->type)
+ tot++;
+ }
+ else {
+ bNodeType *ntype = ntree->alltypes.first;
+ while(ntype) {
+ if(ntype->nclass == nodeclass) {
+ tot++;
+ }
+ ntype= ntype->next;
+ }
+ }
+ }
+ if(tot==0) {
+ return _addmenu;
+ }
+
+ link= MEM_callocN(sizeof(Link) + sizeof(TBitem)*(tot+1), "types menu");
+ BLI_addtail(storage, link);
+ addmenu= (TBitem *)(link+1);
+
+ if(nodeclass==NODE_CLASS_GROUP) {
+ bNodeTree *ngroup= G.main->nodetree.first;
+ for(tot=0, a=0; ngroup; ngroup= ngroup->id.next, tot++) {
+ if(ngroup->type==ntree->type) {
+ addmenu[a].name= ngroup->id.name+2;
+ addmenu[a].retval= NODE_GROUP_MENU+tot; /* so we can use BLI_findlink() */
+ a++;
+ }
+ }
+ }
+ else {
+ bNodeType *ntype= ntree->alltypes.first;
+ for(a=0; ntype; ntype= ntype->next) {
+ if( ntype->nclass == nodeclass ) {
+ addmenu[a].name= ntype->name;
+ addmenu[a].retval= ntype->type;
+ a++;
+ }
+ }
+ }
+
+ addmenu[a].icon= -1; /* end signal */
+ addmenu[a].name= "";
+ addmenu[a].retval= a;
+ addmenu[a].poin= do_node_addmenu;
+
+ return addmenu;
+}
+
+
+static TBitem tb_node_node[]= {
+ { 0, "Duplicate|Shift D", TB_SHIFT|'d', NULL},
+ { 0, "Delete|X", 'x', NULL},
+ { 0, "SEPR", 0, NULL},
+ { 0, "Make Group|Ctrl G", TB_CTRL|'g', NULL},
+ { 0, "Ungroup|Alt G", TB_ALT|'g', NULL},
+ { 0, "Edit Group|Tab", TB_TAB, NULL},
+ { 0, "SEPR", 0, NULL},
+ { 0, "Hide/Unhide|H", 'h', NULL},
+ { 0, "SEPR", 0, NULL},
+ { 0, "Read Saved Render Results|R", 'r', NULL},
+ { 0, "Show Cyclic Dependencies|C", 'c', NULL},
+ { -1, "", 0, tb_do_hotkey}};
+
+static TBitem tb_node_select[]= {
+ { 0, "Select/Deselect All|A", 'a', NULL},
+ { 0, "Border Select|B", 'b', NULL},
+ { -1, "", 0, tb_do_hotkey}};
+
+static TBitem tb_node_transform[]= {
+ { 0, "Grab/Move|G", 'g', NULL},
+ { -1, "", 0, tb_do_hotkey}};
+
+static TBitem tb_node_view[]= {
+ { 0, "Zoom In|NumPad +", TB_PAD|'+', NULL},
+ { 0, "Zoom Out|NumPad -", TB_PAD|'-', NULL},
+ { 0, "View All|Home", TB_PAD|'h', NULL},
+ { -1, "", 0, tb_do_hotkey}};
+
+
+/* *********************************************** */
+
+static uiBlock *tb_makemenu(void *arg)
+{
+ static int counter=0;
+ TBitem *item= arg, *itemt;
+ uiBlock *block;
+ int xco= 0, yco= 0;
+ char str[10];
+
+ if(arg==NULL) return NULL;
+
+ sprintf(str, "tb %d", counter++);
+ block= uiNewBlock(&tb_listb, str, UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetCol(block, TH_MENU_ITEM);
+
+ // last item has do_menu func, has to be stored in each button
+ itemt= item;
+ while(itemt->icon != -1) itemt++;
+ uiBlockSetButmFunc(block, itemt->poin, NULL);
+
+ // now make the buttons
+ while(item->icon != -1) {
+
+ if(strcmp(item->name, "SEPR")==0) {
+ uiDefBut(block, SEPR, 0, "", xco, yco-=6, 50, 6, NULL, 0.0, 0.0, 0, 0, "");
+ }
+ else if(item->icon) {
+ uiDefIconTextBut(block, BUTM, 1, item->icon, item->name, xco, yco-=20, 80, 19, NULL, 0.0, 0.0, 0, item->retval, "");
+ }
+ else if(item->poin) {
+ uiDefIconTextBlockBut(block, tb_makemenu, item->poin, ICON_RIGHTARROW_THIN, item->name, 0, yco-=20, 80, 19, "");
+ }
+ else {
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, item->name, xco, yco-=20, 80, 19, NULL, 0.0, 0.0, 0, item->retval, "");
+ }
+
+ if(yco <= -600) {
+ yco = 0;
+ xco += 80;
+ }
+
+ item++;
+ }
+
+ uiTextBoundsBlock(block, 60);
+
+ /* direction is also set in the function that calls this */
+ if(U.uiflag & USER_PLAINMENUS)
+ uiBlockSetDirection(block, UI_RIGHT);
+ else
+ uiBlockSetDirection(block, UI_RIGHT|UI_CENTER);
+
+ return block;
+}
+
+static int tb_mainx= 1234, tb_mainy= 0;
+static void store_main(void *arg1, void *arg2)
+{
+ tb_mainx= (long)arg1;
+ tb_mainy= (long)arg2;
+}
+
+static void do_group_addmenu(void *arg, int event)
+{
+ Object *ob;
+
+ if(event<0) return;
+
+ add_object_draw(OB_EMPTY);
+ ob= OBACT;
+
+ ob->dup_group= BLI_findlink(&G.main->group, event);
+ if(ob->dup_group) {
+ id_us_plus((ID *)ob->dup_group);
+ ob->transflag |= OB_DUPLIGROUP;
+ DAG_scene_sort(G.scene);
+ }
+}
+
+/* helper for create group menu */
+static void tag_groups_for_toolbox(void)
+{
+ Group *group;
+ GroupObject *go;
+
+ for(group= G.main->group.first; group; group= group->id.next)
+ group->id.flag |= LIB_DOIT;
+
+ for(group= G.main->group.first; group; group= group->id.next) {
+ if(group->id.flag & LIB_DOIT)
+ for(go= group->gobject.first; go; go= go->next)
+ if(go->ob && go->ob->dup_group)
+ go->ob->dup_group->id.flag &= ~LIB_DOIT;
+ }
+}
+
+/* helper for create group menu */
+/* note that group id.flag was set */
+static int count_group_libs(void)
+{
+ Group *group;
+ Library *lib;
+ int tot= 0;
+
+ for(lib= G.main->library.first; lib; lib= lib->id.next)
+ lib->id.flag |= LIB_DOIT;
+
+ for(group= G.main->group.first; group; group= group->id.next) {
+ if(group->id.flag & LIB_DOIT) {
+ if(group->id.lib && (group->id.lib->id.flag & LIB_DOIT)) {
+ group->id.lib->id.flag &= ~LIB_DOIT;
+ tot++;
+ }
+ }
+ }
+ return tot;
+}
+
+/* dynamic toolbox sublevel */
+static TBitem *create_group_sublevel(ListBase *storage, Library *lib)
+{
+ static TBitem addmenu[]= { { 0, "No Groups", 0, NULL}, { -1, "", 0, NULL}};
+ Link *link;
+ TBitem *groupmenu, *gm;
+ Group *group;
+ int a;
+ int tot= BLI_countlist(&G.main->group);
+
+ if(tot==0) {
+ return addmenu;
+ }
+
+ /* build menu, we insert a Link before the array of TBitems */
+ link= MEM_callocN(sizeof(Link) + sizeof(TBitem)*(tot+1), "group menu lib");
+ BLI_addtail(storage, link);
+ gm= groupmenu= (TBitem *)(link+1);
+ for(a=0, group= G.main->group.first; group; group= group->id.next, a++) {
+ if(group->id.lib==lib && (group->id.flag & LIB_DOIT)) {
+ gm->name= group->id.name+2;
+ gm->retval= a;
+ gm++;
+ }
+ }
+ gm->icon= -1; /* end signal */
+ gm->name= "";
+ gm->retval= a;
+ gm->poin= do_group_addmenu;
+
+ return groupmenu;
+}
+
+static TBitem *create_group_all_sublevels(ListBase *storage)
+{
+ Library *lib;
+ Group *group;
+ Link *link;
+ TBitem *groupmenu, *gm;
+ int a;
+ int totlevel= 0;
+ int totlocal= 0;
+
+ /* we add totlevel + local groups entries */
+
+ /* let's skip group-in-group */
+ tag_groups_for_toolbox();
+
+ /* this call checks for skipped group-in-groups */
+ totlevel= count_group_libs();
+
+ for(group= G.main->group.first; group; group= group->id.next)
+ if(group->id.flag & LIB_DOIT)
+ if(group->id.lib==NULL)
+ totlocal++;
+
+ if(totlocal+totlevel==0)
+ return create_group_sublevel(storage, NULL);
+
+ /* build menu, we insert a Link before the array of TBitems */
+ link= MEM_callocN(sizeof(Link) + sizeof(TBitem)*(totlocal+totlevel+1), "group menu");
+ BLI_addtail(storage, link);
+ gm= groupmenu= (TBitem *)(link+1);
+
+ /* first all levels. libs with groups are not tagged */
+ for(lib= G.main->library.first; lib; lib= lib->id.next) {
+ if(!(lib->id.flag & LIB_DOIT)) {
+ char *str;
+ /* do some tricks to get .blend file name without extension */
+ link= MEM_callocN(sizeof(Link) + 128, "string");
+ BLI_addtail(storage, link);
+ str= (char *)(link+1);
+ BLI_strncpy(str, BLI_last_slash(lib->filename)+1, 128);
+ if(strlen(str)>6) str[strlen(str)-6]= 0;
+ gm->name= str;
+ gm->retval= -1;
+ gm->poin= create_group_sublevel(storage, lib);
+ gm++;
+ }
+ }
+ /* remaining groups */
+ for(a=0, group= G.main->group.first; group; group= group->id.next, a++) {
+ if(group->id.lib==NULL && (group->id.flag & LIB_DOIT)) {
+ gm->name= group->id.name+2;
+ gm->retval= a;
+ gm++;
+ }
+ }
+ gm->icon= -1; /* end signal */
+ gm->name= "";
+ gm->retval= a;
+ gm->poin= do_group_addmenu;
+
+ return groupmenu;
+}
+
+static TBitem *create_mesh_sublevel(ListBase *storage)
+{
+ Link *link;
+ TBitem *meshmenu, *mm;
+ int totmenu= 10, totpymenu=0, a=0;
+
+ /* Python Menu */
+ BPyMenu *pym;
+
+ /* count the python menu items*/
+ for (pym = BPyMenuTable[PYMENU_ADDMESH]; pym; pym = pym->next, totpymenu++) {}
+ if (totpymenu) totmenu += totpymenu+1; /* add 1 for the seperator */
+
+ link= MEM_callocN(sizeof(Link) + sizeof(TBitem)*(totmenu+1), "mesh menu");
+ BLI_addtail(storage, link);
+ mm= meshmenu= (TBitem *)(link+1);
+
+ mm->icon = 0; mm->retval= a; mm->name = "Plane"; mm++; a++;
+ mm->icon = 0; mm->retval= a; mm->name = "Cube"; mm++; a++;
+ mm->icon = 0; mm->retval= a; mm->name = "Circle"; mm++; a++;
+ mm->icon = 0; mm->retval= a; mm->name = "UVsphere"; mm++; a++;
+ mm->icon = 0; mm->retval= a; mm->name = "Icosphere"; mm++; a++;
+ mm->icon = 0; mm->retval= a; mm->name = "Cylinder"; mm++; a++; a++;
+ mm->icon = 0; mm->retval= a; mm->name = "Cone"; mm++; a++;
+ mm->icon = 0; mm->retval= 0; mm->name = "SEPR"; mm++;
+ mm->icon = 0; mm->retval= a; mm->name = "Grid"; mm++; a++;
+ mm->icon = 0; mm->retval= a; mm->name = "Monkey"; mm++; a++;
+ /* a == 10 */
+
+ if (totpymenu) {
+ int i=0;
+ mm->icon = 0; mm->retval= 0; mm->name = "SEPR"; mm++;
+
+ /* note that we account for the 10 previous entries with i+4: */
+ for (pym = BPyMenuTable[PYMENU_ADDMESH]; pym; pym = pym->next, i++) {
+ mm->icon = ICON_PYTHON;
+ mm->retval= i+20;
+ mm->name = pym->name;
+ mm++; a++;
+ }
+ }
+
+ /* terminate the menu */
+ mm->icon= -1; mm->retval= a; mm->name= ""; mm->poin= do_info_add_meshmenu;
+
+ return meshmenu;
+}
+
+
+
+void toolbox_n(void)
+{
+ uiBlock *block;
+ uiBut *but;
+ ListBase storage= {NULL, NULL};
+ TBitem *menu1=NULL, *menu2=NULL, *menu3=NULL;
+ TBitem *menu4=NULL, *menu5=NULL, *menu6=NULL;
+ TBitem *menu7=NULL;
+ int dx=0;
+ short event, mval[2], tot=0;
+ char *str1=NULL, *str2=NULL, *str3=NULL, *str4=NULL, *str5=NULL, *str6=NULL, *str7=NULL;
+
+ /* temporal too... when this flag is (was) saved, it should initialize OK */
+ if(tb_mainx==1234) {
+ if(U.uiflag & USER_PLAINMENUS) {
+ tb_mainx= -32;
+ tb_mainy= -5;
+ } else {
+ tb_mainx= 0;
+ tb_mainy= -5;
+ }
+ }
+
+ mywinset(G.curscreen->mainwin); // we go to screenspace
+
+ block= uiNewBlock(&tb_listb, "toolbox", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
+ uiBlockSetFlag(block, UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_RET_1);
+ uiBlockSetCol(block, TH_MENU_ITEM);
+
+ /* select context for main items */
+ if(curarea->spacetype==SPACE_VIEW3D) {
+
+ /* dynamic menu entries */
+ tb_add[TB_ADD_GROUP].poin= create_group_all_sublevels(&storage);
+ tb_add[TB_ADD_MESH].poin= create_mesh_sublevel(&storage);
+
+ /* static */
+ if (G.scene->r.renderer==R_YAFRAY)
+ tb_add[TB_ADD_LAMP].poin= addmenu_YF_lamp;
+ else
+ tb_add[TB_ADD_LAMP].poin= addmenu_lamp;
+
+ if(U.uiflag & USER_PLAINMENUS) {
+ menu1= tb_add; str1= "Add";
+ menu2= tb_object_edit; str2= "Edit";
+ menu3= tb_object_select; str3= "Select";
+ menu4= tb_transform; str4= "Transform";
+ menu5= tb_object; str5= "Object";
+ menu6= tb_view; str6= "View";
+ menu7= tb_render; str7= "Render";
+
+ dx= 96;
+ tot= 7;
+ } else {
+ /* 3x2 layout menu */
+ menu1= tb_object; str1= "Object";
+ menu2= tb_add; str2= "Add";
+ menu3= tb_object_select; str3= "Select";
+ menu4= tb_object_edit; str4= "Edit";
+ menu5= tb_transform; str5= "Transform";
+ menu6= tb_view; str6= "View";
+
+ dx= 64;
+ tot= 6;
+ }
+
+ if(G.obedit) {
+ if(U.uiflag & USER_PLAINMENUS) {
+ switch(G.obedit->type){
+ case OB_MESH:
+ menu1= create_mesh_sublevel(&storage);
+ menu2= tb_mesh_edit;
+ menu3= tb_mesh_select;
+ menu4= tb_transform_editmode1;
+ menu5= tb_mesh; str5= "Mesh";
+ break;
+ case OB_CURVE:
+ menu1= addmenu_curve;
+ menu2= tb_curve_edit;
+ menu3= tb_curve_select;
+ menu4= tb_transform_editmode1;
+ menu5= tb_curve; str5= "Curve";
+ break;
+ case OB_SURF:
+ menu1= addmenu_surf;
+ menu2= tb_curve_edit;
+ menu3= tb_curve_select;
+ menu4= tb_transform_editmode1;
+ menu5= tb_curve; str5= "Surface";
+ break;
+ case OB_MBALL:
+ menu1= addmenu_meta;
+ menu2= tb_edit;
+ menu3= tb_mball_select;
+ menu4= tb_transform_editmode2;
+ menu5= tb_obdata; str5= "Meta";
+ break;
+ case OB_ARMATURE:
+ menu1= addmenu_armature;
+ menu2= tb_edit;
+ menu3= tb__select;
+ menu4= tb_transform_editmode2;
+ menu5= tb_obdata;str5= "Armature";
+ break;
+ case OB_LATTICE:
+ menu1= tb_empty;
+ menu2= tb_edit;
+ menu3= tb__select;
+ menu4= tb_transform_editmode1;
+ menu5= tb_empty;str5= "Lattice";
+ break;
+ }
+ } else {
+ if(G.obedit->type==OB_MESH) {
+ menu1= tb_mesh; str1= "Mesh";
+ menu2= create_mesh_sublevel(&storage);
+ menu3= tb_mesh_select;
+ menu4= tb_mesh_edit;
+ menu5= tb_transform_editmode1;
+ }
+ else if(G.obedit->type==OB_CURVE) {
+ menu1= tb_curve; str1= "Curve";
+ menu2= addmenu_curve;
+ menu3= tb_curve_select;
+ menu4= tb_curve_edit;
+ menu5= tb_transform_editmode1;
+ }
+ else if(G.obedit->type==OB_SURF) {
+ menu1= tb_curve; str1= "Surface";
+ menu2= addmenu_surf;
+ menu3= tb_curve_select;
+ menu4= tb_curve_edit;
+ menu5= tb_transform_editmode1;
+ }
+ else if(G.obedit->type==OB_MBALL) {
+ menu1= tb_obdata; str1= "Meta";
+ menu2= addmenu_meta;
+ menu3= tb__select;
+ menu4= tb_edit;
+ menu5= tb_transform_editmode2;
+ }
+ else if(G.obedit->type==OB_ARMATURE) {
+ menu1= tb_obdata;str1= "Armature";
+ menu2= addmenu_armature;
+ menu3= tb__select;
+ menu4= tb_edit;
+ menu5= tb_transform_editmode2;
+ }
+ else if(G.obedit->type==OB_LATTICE) {
+ menu1= tb_empty;str1= "Lattice";
+ menu2= tb_empty;
+ menu3= tb__select;
+ menu4= tb_edit;
+ menu5= tb_transform_editmode1;
+ }
+ }
+ }
+ else if (FACESEL_PAINT_TEST) {
+ menu3 = tb_face_select;
+ }
+ }
+ else if(curarea->spacetype==SPACE_NODE) {
+ SpaceNode *snode= curarea->spacedata.first;
+
+ if(snode->treetype==NTREE_COMPOSIT)
+ menu1= tb_node_addcomp;
+ else
+ menu1= tb_node_addsh;
+ str1= "Add";
+ menu2= tb_node_node; str2= "Node";
+ menu3= tb_node_select; str3= "Select";
+ menu4= tb_node_transform; str4= "Transform";
+ menu5= tb_node_view; str5= "View";
+
+ if(snode->treetype==NTREE_SHADER) {
+ menu1[0].poin= node_add_sublevel(&storage, snode->nodetree, NODE_CLASS_INPUT);
+ menu1[1].poin= node_add_sublevel(&storage, snode->nodetree, NODE_CLASS_OUTPUT);
+ menu1[2].poin= node_add_sublevel(&storage, snode->nodetree, NODE_CLASS_OP_COLOR);
+ menu1[3].poin= node_add_sublevel(&storage, snode->nodetree, NODE_CLASS_OP_VECTOR);
+ menu1[4].poin= node_add_sublevel(&storage, snode->nodetree, NODE_CLASS_CONVERTOR);
+ menu1[5].poin= node_add_sublevel(&storage, snode->nodetree, NODE_CLASS_GROUP);
+ }
+ else if(snode->treetype==NTREE_COMPOSIT) {
+ menu1[0].poin= node_add_sublevel(&storage, snode->nodetree, NODE_CLASS_INPUT);
+ menu1[1].poin= node_add_sublevel(&storage, snode->nodetree, NODE_CLASS_OUTPUT);
+ menu1[2].poin= node_add_sublevel(&storage, snode->nodetree, NODE_CLASS_OP_COLOR);
+ menu1[3].poin= node_add_sublevel(&storage, snode->nodetree, NODE_CLASS_OP_VECTOR);
+ menu1[4].poin= node_add_sublevel(&storage, snode->nodetree, NODE_CLASS_OP_FILTER);
+ menu1[5].poin= node_add_sublevel(&storage, snode->nodetree, NODE_CLASS_CONVERTOR);
+ menu1[6].poin= node_add_sublevel(&storage, snode->nodetree, NODE_CLASS_MATTE);
+ menu1[7].poin= node_add_sublevel(&storage, snode->nodetree, NODE_CLASS_DISTORT);
+ menu1[8].poin= node_add_sublevel(&storage, snode->nodetree, NODE_CLASS_GROUP);
+
+ }
+
+ dx= 96;
+ tot= 5;
+
+ }
+
+ getmouseco_sc(mval);
+
+ /* create the main buttons menu */
+ if(tot==6) {
+
+ /* check if it fits */
+ if(mval[0]-1.5*dx+tb_mainx < 6) mval[0]= 6 + 1.5*dx -tb_mainx;
+ else if(mval[0]+1.5*dx+tb_mainx > G.curscreen->sizex-6)
+ mval[0]= G.curscreen->sizex-6-1.5*dx-tb_mainx;
+
+ if(mval[1]-20+tb_mainy < 6) mval[1]= 6+20 -tb_mainy;
+ else if(mval[1]+20+tb_mainy > G.curscreen->sizey-6)
+ mval[1]= G.curscreen->sizey-6-20-tb_mainy;
+
+ but=uiDefBlockBut(block, tb_makemenu, menu1, str1, mval[0]-(1.5*dx)+tb_mainx,mval[1]+tb_mainy, dx, 19, "");
+ uiButSetFlag(but, UI_MAKE_TOP|UI_MAKE_RIGHT);
+ uiButSetFunc(but, store_main, (void *)(long)dx, (void *)(long)-5);
+
+ but=uiDefBlockBut(block, tb_makemenu, menu2, str2, mval[0]-(0.5*dx)+tb_mainx,mval[1]+tb_mainy, dx, 19, "");
+ uiButSetFlag(but, UI_MAKE_TOP);
+ uiButSetFunc(but, store_main, (void *)(long)0, (void *)(long)-5);
+
+ but=uiDefBlockBut(block, tb_makemenu, menu3, str3, mval[0]+(0.5*dx)+tb_mainx,mval[1]+tb_mainy, dx, 19, "");
+ uiButSetFlag(but, UI_MAKE_TOP|UI_MAKE_LEFT);
+ uiButSetFunc(but, store_main, (void *)(long)-dx, (void *)(long)-5);
+
+ but=uiDefBlockBut(block, tb_makemenu, menu4, str4, mval[0]-(1.5*dx)+tb_mainx,mval[1]+tb_mainy-20, dx, 19, "");
+ uiButSetFlag(but, UI_MAKE_DOWN|UI_MAKE_RIGHT);
+ uiButSetFunc(but, store_main, (void *)(long)dx, (void *)(long)5);
+
+ but=uiDefBlockBut(block, tb_makemenu, menu5, str5, mval[0]-(0.5*dx)+tb_mainx,mval[1]+tb_mainy-20, dx, 19, "");
+ uiButSetFlag(but, UI_MAKE_DOWN);
+ uiButSetFunc(but, store_main, (void *)(long)0, (void *)(long)5);
+
+ but=uiDefBlockBut(block, tb_makemenu, menu6, str6, mval[0]+(0.5*dx)+tb_mainx,mval[1]+tb_mainy-20, dx, 19, "");
+ uiButSetFlag(but, UI_MAKE_DOWN|UI_MAKE_LEFT);
+ uiButSetFunc(but, store_main, (void *)(long)-dx, (void *)(long)5);
+ } else if (tot==5 || tot==7) {
+ /* check if it fits, dubious */
+ if(mval[0]-0.25*dx+tb_mainx < 6) mval[0]= 6 + 0.25*dx -tb_mainx;
+ else if(mval[0]+0.25*dx+tb_mainx > G.curscreen->sizex-6)
+ mval[0]= G.curscreen->sizex-6-0.25*dx-tb_mainx;
+
+ if(mval[1]-20+tb_mainy < 6) mval[1]= 6+20 -tb_mainy;
+ else if(mval[1]+20+tb_mainy > G.curscreen->sizey-6)
+ mval[1]= G.curscreen->sizey-6-20-tb_mainy;
+
+ but=uiDefIconTextBlockBut(block, tb_makemenu, menu1, ICON_RIGHTARROW_THIN, str1, mval[0]+tb_mainx,mval[1]+tb_mainy, dx, 19, "");
+ uiButSetFlag(but, UI_MAKE_RIGHT);
+ uiButSetFunc(but, store_main, (void *)-32, (void *)-5);
+
+ but=uiDefIconTextBlockBut(block, tb_makemenu, menu2, ICON_RIGHTARROW_THIN, str2, mval[0]+tb_mainx,mval[1]+tb_mainy-20, dx, 19, "");
+ uiButSetFlag(but, UI_MAKE_RIGHT);
+ uiButSetFunc(but, store_main, (void *)-32, (void *)15);
+
+ but=uiDefIconTextBlockBut(block, tb_makemenu, menu3, ICON_RIGHTARROW_THIN, str3, mval[0]+tb_mainx,mval[1]+tb_mainy-40, dx, 19, "");
+ uiButSetFlag(but, UI_MAKE_RIGHT);
+ uiButSetFunc(but, store_main, (void *)-32, (void *)35);
+
+ but=uiDefIconTextBlockBut(block, tb_makemenu, menu4, ICON_RIGHTARROW_THIN, str4, mval[0]+tb_mainx,mval[1]+tb_mainy-60, dx, 19, "");
+ uiButSetFlag(but, UI_MAKE_RIGHT);
+ uiButSetFunc(but, store_main, (void *)-32, (void *)55);
+
+ but=uiDefIconTextBlockBut(block, tb_makemenu, menu5, ICON_RIGHTARROW_THIN, str5, mval[0]+tb_mainx,mval[1]+tb_mainy-80, dx, 19, "");
+ uiButSetFlag(but, UI_MAKE_RIGHT);
+ uiButSetFunc(but, store_main, (void *)-32, (void *)75);
+
+ if(tot>5) {
+ but=uiDefIconTextBlockBut(block, tb_makemenu, menu6, ICON_RIGHTARROW_THIN, str6, mval[0]+tb_mainx,mval[1]+tb_mainy-100, dx, 19, "");
+ uiButSetFlag(but, UI_MAKE_RIGHT);
+ uiButSetFunc(but, store_main, (void *)-32, (void *)95);
+ }
+ if(tot>6) {
+ but=uiDefIconTextBlockBut(block, tb_makemenu, menu7, ICON_RIGHTARROW_THIN, str7, mval[0]+tb_mainx,mval[1]+tb_mainy-120, dx, 19, "");
+ uiButSetFlag(but, UI_MAKE_RIGHT);
+ uiButSetFunc(but, store_main, (void *)-32, (void *)105);
+ }
+ }
+
+ uiBoundsBlock(block, 2);
+ event= uiDoBlocks(&tb_listb, 0);
+
+ /* free all dynamic entries... */
+ BLI_freelistN(&storage);
+
+ mywinset(curarea->win);
+}
+
+void toolbox_n_add(void)
+{
+ reset_toolbox();
+ toolbox_n();
+}
+
+void reset_toolbox(void)
+{
+ if(U.uiflag & USER_PLAINMENUS) {
+ tb_mainx= -32;
+ tb_mainy= -5;
+ } else {
+ tb_mainx= 0;
+ tb_mainy= -5;
+ }
+}
diff --git a/source/blender/src/transform.c b/source/blender/src/transform.c
new file mode 100644
index 00000000000..2a7f744f219
--- /dev/null
+++ b/source/blender/src/transform.c
@@ -0,0 +1,3890 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef WIN32
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_armature_types.h"
+#include "DNA_action_types.h" /* for some special action-editor settings */
+#include "DNA_ipo_types.h" /* some silly ipo flag */
+#include "DNA_listBase.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h" /* PET modes */
+#include "DNA_screen_types.h" /* area dimensions */
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_space_types.h"
+
+#include "BIF_editview.h" /* arrows_move_cursor */
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+#include "BIF_mywindow.h"
+#include "BIF_resources.h"
+#include "BIF_screen.h"
+#include "BIF_space.h" /* undo */
+#include "BIF_toets.h" /* persptoetsen */
+#include "BIF_mywindow.h" /* warp_pointer */
+#include "BIF_toolbox.h" /* notice */
+#include "BIF_editmesh.h"
+#include "BIF_editsima.h"
+#include "BIF_drawimage.h" /* uvco_to_areaco_noclip */
+#include "BIF_editaction.h"
+
+#include "BKE_action.h" /* get_action_frame */
+#include "BKE_global.h"
+#include "BKE_utildefines.h"
+#include "BKE_bad_level_calls.h"/* popmenu and error */
+
+#include "BSE_drawipo.h"
+#include "BSE_editnla_types.h" /* for NLAWIDTH */
+#include "BSE_editaction_types.h"
+#include "BSE_time.h"
+#include "BSE_view.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+#include "BLI_editVert.h"
+
+#include "PIL_time.h" /* sleep */
+
+#include "blendef.h"
+
+#include "mydevice.h"
+
+#include "transform.h"
+
+/* GLOBAL VARIABLE THAT SHOULD MOVED TO SCREEN MEMBER OR SOMETHING */
+TransInfo Trans = {TFM_INIT, 0}; // enforce init on first usage
+
+/******************************** Helper functions ************************************/
+
+/* GLOBAL Wrapper Fonctions */
+
+void BIF_drawSnap()
+{
+ drawSnapping(&Trans);
+}
+
+/* ************************** Dashed help line **************************** */
+
+
+/* bad frontbuffer call... because it is used in transform after force_draw() */
+static void helpline(TransInfo *t, float *vec)
+{
+ float vecrot[3], cent[2];
+ short mval[2];
+
+ VECCOPY(vecrot, vec);
+ if(t->flag & T_EDIT) {
+ Object *ob=G.obedit;
+ if(ob) Mat4MulVecfl(ob->obmat, vecrot);
+ }
+ else if(t->flag & T_POSE) {
+ Object *ob=t->poseobj;
+ if(ob) Mat4MulVecfl(ob->obmat, vecrot);
+ }
+
+ getmouseco_areawin(mval);
+ projectFloatView(t, vecrot, cent); // no overflow in extreme cases
+ if(cent[0]!=IS_CLIPPED) {
+ persp(PERSP_WIN);
+
+ glDrawBuffer(GL_FRONT);
+
+ BIF_ThemeColor(TH_WIRE);
+
+ setlinestyle(3);
+ glBegin(GL_LINE_STRIP);
+ glVertex2sv(mval);
+ glVertex2fv(cent);
+ glEnd();
+ setlinestyle(0);
+
+ persp(PERSP_VIEW);
+ bglFlush(); // flush display for frontbuffer
+ glDrawBuffer(GL_BACK);
+ }
+}
+/* ************************** INPUT FROM MOUSE *************************** */
+
+float InputScaleRatio(TransInfo *t, short mval[2]) {
+ float ratio, dx, dy;
+ if(t->flag & T_SHIFT_MOD) {
+ /* calculate ratio for shiftkey pos, and for total, and blend these for precision */
+ dx = (float)(t->center2d[0] - t->shiftmval[0]);
+ dy = (float)(t->center2d[1] - t->shiftmval[1]);
+ ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
+
+ dx= (float)(t->center2d[0] - mval[0]);
+ dy= (float)(t->center2d[1] - mval[1]);
+ ratio+= 0.1f*(float)(sqrt( dx*dx + dy*dy)/t->fac -ratio);
+ }
+ else {
+ dx = (float)(t->center2d[0] - mval[0]);
+ dy = (float)(t->center2d[1] - mval[1]);
+ ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
+ }
+ return ratio;
+}
+
+float InputHorizontalRatio(TransInfo *t, short mval[2]) {
+ float x, pad;
+
+ pad = curarea->winx / 10;
+
+ if (t->flag & T_SHIFT_MOD) {
+ /* deal with Shift key by adding motion / 10 to motion before shift press */
+ x = t->shiftmval[0] + (float)(mval[0] - t->shiftmval[0]) / 10.0f;
+ }
+ else {
+ x = mval[0];
+ }
+ return (x - pad) / (curarea->winx - 2 * pad);
+}
+
+float InputHorizontalAbsolute(TransInfo *t, short mval[2]) {
+ float vec[3];
+ if(t->flag & T_SHIFT_MOD) {
+ float dvec[3];
+ /* calculate the main translation and the precise one separate */
+ convertViewVec(t, dvec, (short)(mval[0] - t->shiftmval[0]), (short)(mval[1] - t->shiftmval[1]));
+ VecMulf(dvec, 0.1f);
+ convertViewVec(t, t->vec, (short)(t->shiftmval[0] - t->imval[0]), (short)(t->shiftmval[1] - t->imval[1]));
+ VecAddf(t->vec, t->vec, dvec);
+ }
+ else {
+ convertViewVec(t, t->vec, (short)(mval[0] - t->imval[0]), (short)(mval[1] - t->imval[1]));
+ }
+ Projf(vec, t->vec, t->viewinv[0]);
+ return Inpf(t->viewinv[0], vec) * 2.0f;
+}
+
+float InputVerticalRatio(TransInfo *t, short mval[2]) {
+ float y, pad;
+
+ pad = curarea->winy / 10;
+
+ if (t->flag & T_SHIFT_MOD) {
+ /* deal with Shift key by adding motion / 10 to motion before shift press */
+ y = t->shiftmval[1] + (float)(mval[1] - t->shiftmval[1]) / 10.0f;
+ }
+ else {
+ y = mval[0];
+ }
+ return (y - pad) / (curarea->winy - 2 * pad);
+}
+
+float InputVerticalAbsolute(TransInfo *t, short mval[2]) {
+ float vec[3];
+ if(t->flag & T_SHIFT_MOD) {
+ float dvec[3];
+ /* calculate the main translation and the precise one separate */
+ convertViewVec(t, dvec, (short)(mval[0] - t->shiftmval[0]), (short)(mval[1] - t->shiftmval[1]));
+ VecMulf(dvec, 0.1f);
+ convertViewVec(t, t->vec, (short)(t->shiftmval[0] - t->imval[0]), (short)(t->shiftmval[1] - t->imval[1]));
+ VecAddf(t->vec, t->vec, dvec);
+ }
+ else {
+ convertViewVec(t, t->vec, (short)(mval[0] - t->imval[0]), (short)(mval[1] - t->imval[1]));
+ }
+ Projf(vec, t->vec, t->viewinv[1]);
+ return Inpf(t->viewinv[1], vec) * 2.0f;
+}
+
+/* ************************** SPACE DEPENDANT CODE **************************** */
+
+void setTransformViewMatrices(TransInfo *t)
+{
+ if(t->spacetype==SPACE_VIEW3D) {
+ Mat4CpyMat4(t->viewmat, G.vd->viewmat);
+ Mat4CpyMat4(t->viewinv, G.vd->viewinv);
+ Mat4CpyMat4(t->persmat, G.vd->persmat);
+ Mat4CpyMat4(t->persinv, G.vd->persinv);
+ t->persp= G.vd->persp;
+ }
+ else {
+ Mat4One(t->viewmat);
+ Mat4One(t->viewinv);
+ Mat4One(t->persmat);
+ Mat4One(t->persinv);
+ t->persp = 0; // ortho
+ }
+
+ calculateCenter2D(t);
+
+}
+
+void convertViewVec(TransInfo *t, float *vec, short dx, short dy)
+{
+ if (t->spacetype==SPACE_VIEW3D) {
+ window_to_3d(vec, dx, dy);
+ }
+ else if(t->spacetype==SPACE_IMAGE) {
+ float divx, divy, aspx, aspy;
+
+ transform_aspect_ratio_tface_uv(&aspx, &aspy);
+
+ divx= G.v2d->mask.xmax-G.v2d->mask.xmin;
+ divy= G.v2d->mask.ymax-G.v2d->mask.ymin;
+
+ vec[0]= aspx*(G.v2d->cur.xmax-G.v2d->cur.xmin)*(dx)/divx;
+ vec[1]= aspy*(G.v2d->cur.ymax-G.v2d->cur.ymin)*(dy)/divy;
+ vec[2]= 0.0f;
+ }
+ else if(t->spacetype==SPACE_IPO) {
+ float divx, divy;
+
+ divx= G.v2d->mask.xmax-G.v2d->mask.xmin;
+ divy= G.v2d->mask.ymax-G.v2d->mask.ymin;
+
+ vec[0]= (G.v2d->cur.xmax-G.v2d->cur.xmin)*(dx) / (divx);
+ vec[1]= (G.v2d->cur.ymax-G.v2d->cur.ymin)*(dy) / (divy);
+ vec[2]= 0.0f;
+ }
+}
+
+void projectIntView(TransInfo *t, float *vec, int *adr)
+{
+ if (t->spacetype==SPACE_VIEW3D)
+ project_int(vec, adr);
+ else if(t->spacetype==SPACE_IMAGE) {
+ float aspx, aspy, v[2];
+
+ transform_aspect_ratio_tface_uv(&aspx, &aspy);
+ v[0]= vec[0]/aspx;
+ v[1]= vec[1]/aspy;
+
+ uvco_to_areaco_noclip(v, adr);
+ }
+ else if(t->spacetype==SPACE_IPO) {
+ short out[2] = {0.0f, 0.0f};
+
+ ipoco_to_areaco(G.v2d, vec, out);
+ adr[0]= out[0];
+ adr[1]= out[1];
+ }
+}
+
+void projectFloatView(TransInfo *t, float *vec, float *adr)
+{
+ if (t->spacetype==SPACE_VIEW3D)
+ project_float(vec, adr);
+ else if(t->spacetype==SPACE_IMAGE) {
+ int a[2];
+
+ projectIntView(t, vec, a);
+ adr[0]= a[0];
+ adr[1]= a[1];
+ }
+ else if(t->spacetype==SPACE_IPO) {
+ int a[2];
+
+ projectIntView(t, vec, a);
+ adr[0]= a[0];
+ adr[1]= a[1];
+ }
+}
+
+void convertVecToDisplayNum(float *vec, float *num)
+{
+ TransInfo *t= BIF_GetTransInfo();
+
+ VECCOPY(num, vec);
+
+ if ((t->spacetype==SPACE_IMAGE) && (t->mode==TFM_TRANSLATION)) {
+ float aspx, aspy;
+
+ if((G.sima->flag & SI_COORDFLOATS)==0) {
+ int width, height;
+ transform_width_height_tface_uv(&width, &height);
+
+ num[0] *= width;
+ num[1] *= height;
+ }
+
+ transform_aspect_ratio_tface_uv(&aspx, &aspy);
+ num[0] /= aspx;
+ num[1] /= aspy;
+ }
+}
+
+void convertDisplayNumToVec(float *num, float *vec)
+{
+ TransInfo *t= BIF_GetTransInfo();
+
+ VECCOPY(vec, num);
+
+ if ((t->spacetype==SPACE_IMAGE) && (t->mode==TFM_TRANSLATION)) {
+ float aspx, aspy;
+
+ if((G.sima->flag & SI_COORDFLOATS)==0) {
+ int width, height;
+ transform_width_height_tface_uv(&width, &height);
+
+ vec[0] /= width;
+ vec[1] /= height;
+ }
+
+ transform_aspect_ratio_tface_uv(&aspx, &aspy);
+ vec[0] *= aspx;
+ vec[1] *= aspy;
+ }
+}
+
+static void viewRedrawForce(TransInfo *t)
+{
+ if (t->spacetype == SPACE_VIEW3D)
+ force_draw(0);
+ else if (t->spacetype==SPACE_IMAGE) {
+ if (G.sima->lock) force_draw_plus(SPACE_VIEW3D, 0);
+ else force_draw(0);
+ }
+ else if (t->spacetype == SPACE_ACTION) {
+ if (G.saction->lock) {
+ short context;
+
+ /* we ignore the pointer this function returns (not needed) */
+ get_action_context(&context);
+
+ if (context == ACTCONT_ACTION)
+ force_draw_plus(SPACE_VIEW3D, 0);
+ else if (context == ACTCONT_SHAPEKEY)
+ force_draw_all(0);
+ else
+ force_draw(0);
+ }
+ else {
+ force_draw(0);
+ }
+ }
+ else if (t->spacetype == SPACE_NLA) {
+ if (G.snla->lock)
+ force_draw_all(0);
+ else
+ force_draw(0);
+ }
+ else if (t->spacetype == SPACE_IPO) {
+ /* update realtime */
+ if (G.sipo->lock) {
+ if (G.sipo->blocktype==ID_MA || G.sipo->blocktype==ID_TE)
+ force_draw_plus(SPACE_BUTS, 0);
+ else if (G.sipo->blocktype==ID_CA)
+ force_draw_plus(SPACE_VIEW3D, 0);
+ else if (G.sipo->blocktype==ID_KE)
+ force_draw_plus(SPACE_VIEW3D, 0);
+ else if (G.sipo->blocktype==ID_PO)
+ force_draw_plus(SPACE_VIEW3D, 0);
+ else if (G.sipo->blocktype==ID_OB)
+ force_draw_plus(SPACE_VIEW3D, 0);
+ else if (G.sipo->blocktype==ID_SEQ)
+ force_draw_plus(SPACE_SEQ, 0);
+ else
+ force_draw(0);
+ }
+ else {
+ force_draw(0);
+ }
+ }
+}
+
+static void viewRedrawPost(TransInfo *t)
+{
+ if(t->spacetype==SPACE_VIEW3D) {
+ allqueue(REDRAWBUTSOBJECT, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ else if(t->spacetype==SPACE_IMAGE) {
+ allqueue(REDRAWIMAGE, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+ else if(ELEM3(t->spacetype, SPACE_ACTION, SPACE_NLA, SPACE_IPO)) {
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWNLA, 0);
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWTIME, 0);
+ allqueue(REDRAWBUTSOBJECT, 0);
+ }
+
+ scrarea_queue_headredraw(curarea);
+}
+
+/* ************************** TRANSFORMATIONS **************************** */
+
+void BIF_selectOrientation() {
+ short val;
+ val= pupmenu("Orientation%t|Global|Local|Normal|View");
+ if(val>0) {
+ if(val==1) G.vd->twmode= V3D_MANIP_GLOBAL;
+ else if(val==2) G.vd->twmode= V3D_MANIP_LOCAL;
+ else if(val==3) G.vd->twmode= V3D_MANIP_NORMAL;
+ else if(val==4) G.vd->twmode= V3D_MANIP_VIEW;
+ }
+}
+
+static void view_editmove(unsigned short event)
+{
+ int refresh = 0;
+ /* Regular: Zoom in */
+ /* Shift: Scroll up */
+ /* Ctrl: Scroll right */
+ /* Alt-Shift: Rotate up */
+ /* Alt-Ctrl: Rotate right */
+
+ /* only work in 3D window for now
+ * In the end, will have to send to event to a 2D window handler instead
+ */
+ if (Trans.flag & T_2D_EDIT)
+ return;
+
+ switch(event) {
+ case WHEELUPMOUSE:
+
+ if( G.qual & LR_SHIFTKEY ) {
+ if( G.qual & LR_ALTKEY ) {
+ G.qual &= ~LR_SHIFTKEY;
+ persptoetsen(PAD2);
+ G.qual |= LR_SHIFTKEY;
+ } else {
+ persptoetsen(PAD2);
+ }
+ } else if( G.qual & LR_CTRLKEY ) {
+ if( G.qual & LR_ALTKEY ) {
+ G.qual &= ~LR_CTRLKEY;
+ persptoetsen(PAD4);
+ G.qual |= LR_CTRLKEY;
+ } else {
+ persptoetsen(PAD4);
+ }
+ } else if(U.uiflag & USER_WHEELZOOMDIR)
+ persptoetsen(PADMINUS);
+ else
+ persptoetsen(PADPLUSKEY);
+
+ refresh = 1;
+ break;
+ case WHEELDOWNMOUSE:
+ if( G.qual & LR_SHIFTKEY ) {
+ if( G.qual & LR_ALTKEY ) {
+ G.qual &= ~LR_SHIFTKEY;
+ persptoetsen(PAD8);
+ G.qual |= LR_SHIFTKEY;
+ } else {
+ persptoetsen(PAD8);
+ }
+ } else if( G.qual & LR_CTRLKEY ) {
+ if( G.qual & LR_ALTKEY ) {
+ G.qual &= ~LR_CTRLKEY;
+ persptoetsen(PAD6);
+ G.qual |= LR_CTRLKEY;
+ } else {
+ persptoetsen(PAD6);
+ }
+ } else if(U.uiflag & USER_WHEELZOOMDIR)
+ persptoetsen(PADPLUSKEY);
+ else
+ persptoetsen(PADMINUS);
+
+ refresh = 1;
+ break;
+ }
+
+ if (refresh)
+ setTransformViewMatrices(&Trans);
+}
+
+void checkFirstTime() {
+ if(Trans.mode==TFM_INIT) {
+ memset(&Trans, 0, sizeof(TransInfo));
+ Trans.propsize = 1.0;
+ }
+}
+
+static char *transform_to_undostr(TransInfo *t)
+{
+ switch (t->mode) {
+ case TFM_TRANSLATION:
+ return "Translate";
+ case TFM_ROTATION:
+ return "Rotate";
+ case TFM_RESIZE:
+ return "Scale";
+ case TFM_TOSPHERE:
+ return "To Sphere";
+ case TFM_SHEAR:
+ return "Shear";
+ case TFM_WARP:
+ return "Warp";
+ case TFM_SHRINKFATTEN:
+ return "Shrink/Fatten";
+ case TFM_TILT:
+ return "Tilt";
+ case TFM_TRACKBALL:
+ return "Trackball";
+ case TFM_PUSHPULL:
+ return "Push/Pull";
+ case TFM_CREASE:
+ return "Crease";
+ case TFM_BONESIZE:
+ return "Bone Width";
+ case TFM_BONE_ENVELOPE:
+ return "Bone Envelope";
+ case TFM_TIME_TRANSLATE:
+ return "Translate Anim. Data";
+ case TFM_TIME_SCALE:
+ return "Scale Anim. Data";
+ case TFM_TIME_SLIDE:
+ return "Time Slide";
+ }
+ return "Transform";
+}
+
+/* ************************************************* */
+
+static void transformEvent(unsigned short event, short val) {
+ float mati[3][3] = {{1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}};
+ char cmode = constraintModeToChar(&Trans);
+
+ if (val) {
+ switch (event){
+ /* enforce redraw of transform when modifiers are used */
+ case LEFTCTRLKEY:
+ case RIGHTCTRLKEY:
+ Trans.redraw = 1;
+ break;
+ case LEFTSHIFTKEY:
+ case RIGHTSHIFTKEY:
+ /* shift is modifier for higher resolution transform, works nice to store this mouse position */
+ getmouseco_areawin(Trans.shiftmval);
+ Trans.flag |= T_SHIFT_MOD;
+ Trans.redraw = 1;
+ break;
+
+ case SPACEKEY:
+ if ((Trans.spacetype==SPACE_VIEW3D) && (G.qual & LR_ALTKEY)) {
+ short mval[2];
+
+ getmouseco_sc(mval);
+ BIF_selectOrientation();
+ calc_manipulator_stats(curarea);
+ Mat3CpyMat4(Trans.spacemtx, G.vd->twmat);
+ warp_pointer(mval[0], mval[1]);
+ }
+ else {
+ Trans.state = TRANS_CONFIRM;
+ }
+ break;
+
+
+ case MIDDLEMOUSE:
+ if ((Trans.flag & T_NO_CONSTRAINT)==0) {
+ /* exception for switching to dolly, or trackball, in camera view */
+ if (Trans.flag & T_CAMERA) {
+ if (Trans.mode==TFM_TRANSLATION)
+ setLocalConstraint(&Trans, (CON_AXIS2), "along local Z");
+ else if (Trans.mode==TFM_ROTATION) {
+ restoreTransObjects(&Trans);
+ initTrackball(&Trans);
+ }
+ }
+ else {
+ Trans.flag |= T_MMB_PRESSED;
+ if (Trans.con.mode & CON_APPLY) {
+ stopConstraint(&Trans);
+ }
+ else {
+ if (G.qual & LR_CTRLKEY) {
+ initSelectConstraint(&Trans, Trans.spacemtx);
+ }
+ else {
+ /* bit hackish... but it prevents mmb select to print the orientation from menu */
+ strcpy(Trans.spacename, "global");
+ initSelectConstraint(&Trans, mati);
+ }
+ postSelectConstraint(&Trans);
+ }
+ }
+ Trans.redraw = 1;
+ }
+ break;
+ case ESCKEY:
+ case RIGHTMOUSE:
+ Trans.state = TRANS_CANCEL;
+ break;
+ case LEFTMOUSE:
+ case PADENTER:
+ case RETKEY:
+ Trans.state = TRANS_CONFIRM;
+ break;
+ case GKEY:
+ /* only switch when... */
+ if( ELEM3(Trans.mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL) ) {
+ restoreTransObjects(&Trans);
+ initTranslation(&Trans);
+ Trans.redraw = 1;
+ }
+ break;
+ case SKEY:
+ /* only switch when... */
+ if( ELEM3(Trans.mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL) ) {
+ restoreTransObjects(&Trans);
+ initResize(&Trans);
+ Trans.redraw = 1;
+ }
+ break;
+ case RKEY:
+ /* only switch when... */
+ if( ELEM4(Trans.mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION) ) {
+
+ if (Trans.mode == TFM_ROTATION) {
+ restoreTransObjects(&Trans);
+ initTrackball(&Trans);
+ }
+ else {
+ restoreTransObjects(&Trans);
+ initRotation(&Trans);
+ }
+ Trans.redraw = 1;
+ }
+ break;
+ case CKEY:
+ if (G.qual & LR_ALTKEY) {
+ Trans.flag ^= T_PROP_CONNECTED;
+ sort_trans_data_dist(&Trans);
+ calculatePropRatio(&Trans);
+ Trans.redraw= 1;
+ }
+ else {
+ stopConstraint(&Trans);
+ Trans.redraw = 1;
+ }
+ break;
+ case XKEY:
+ if ((Trans.flag & T_NO_CONSTRAINT)==0) {
+ if (cmode == 'X') {
+ if (Trans.flag & T_2D_EDIT) {
+ stopConstraint(&Trans);
+ }
+ else {
+ if (Trans.con.mode & CON_USER) {
+ stopConstraint(&Trans);
+ }
+ else {
+ if (G.qual == 0)
+ setUserConstraint(&Trans, (CON_AXIS0), "along %s X");
+ else if (G.qual == LR_SHIFTKEY)
+ setUserConstraint(&Trans, (CON_AXIS1|CON_AXIS2), "locking %s X");
+ }
+ }
+ }
+ else {
+ if (Trans.flag & T_2D_EDIT) {
+ setConstraint(&Trans, mati, (CON_AXIS0), "along X axis");
+ }
+ else {
+ if (G.qual == 0)
+ setConstraint(&Trans, mati, (CON_AXIS0), "along global X");
+ else if (G.qual == LR_SHIFTKEY)
+ setConstraint(&Trans, mati, (CON_AXIS1|CON_AXIS2), "locking global X");
+ }
+ }
+ Trans.redraw = 1;
+ }
+ break;
+ case YKEY:
+ if ((Trans.flag & T_NO_CONSTRAINT)==0) {
+ if (cmode == 'Y') {
+ if (Trans.flag & T_2D_EDIT) {
+ stopConstraint(&Trans);
+ }
+ else {
+ if (Trans.con.mode & CON_USER) {
+ stopConstraint(&Trans);
+ }
+ else {
+ if (G.qual == 0)
+ setUserConstraint(&Trans, (CON_AXIS1), "along %s Y");
+ else if (G.qual == LR_SHIFTKEY)
+ setUserConstraint(&Trans, (CON_AXIS0|CON_AXIS2), "locking %s Y");
+ }
+ }
+ }
+ else {
+ if (Trans.flag & T_2D_EDIT) {
+ setConstraint(&Trans, mati, (CON_AXIS1), "along Y axis");
+ }
+ else {
+ if (G.qual == 0)
+ setConstraint(&Trans, mati, (CON_AXIS1), "along global Y");
+ else if (G.qual == LR_SHIFTKEY)
+ setConstraint(&Trans, mati, (CON_AXIS0|CON_AXIS2), "locking global Y");
+ }
+ }
+ Trans.redraw = 1;
+ }
+ break;
+ case ZKEY:
+ if ((Trans.flag & T_NO_CONSTRAINT)==0) {
+ if (cmode == 'Z') {
+ if (Trans.con.mode & CON_USER) {
+ stopConstraint(&Trans);
+ }
+ else {
+ if (G.qual == 0)
+ setUserConstraint(&Trans, (CON_AXIS2), "along %s Z");
+ else if ((G.qual == LR_SHIFTKEY) && ((Trans.flag & T_2D_EDIT)==0))
+ setUserConstraint(&Trans, (CON_AXIS0|CON_AXIS1), "locking %s Z");
+ }
+ }
+ else if ((Trans.flag & T_2D_EDIT)==0) {
+ if (G.qual == 0)
+ setConstraint(&Trans, mati, (CON_AXIS2), "along global Z");
+ else if (G.qual == LR_SHIFTKEY)
+ setConstraint(&Trans, mati, (CON_AXIS0|CON_AXIS1), "locking global Z");
+ }
+ Trans.redraw = 1;
+ }
+ break;
+ case OKEY:
+ if (Trans.flag & T_PROP_EDIT && G.qual==LR_SHIFTKEY) {
+ G.scene->prop_mode = (G.scene->prop_mode+1)%6;
+ calculatePropRatio(&Trans);
+ Trans.redraw= 1;
+ }
+ break;
+ case PADPLUSKEY:
+ if(G.qual & LR_ALTKEY && Trans.flag & T_PROP_EDIT) {
+ Trans.propsize*= 1.1f;
+ calculatePropRatio(&Trans);
+ }
+ Trans.redraw= 1;
+ break;
+ case PAGEUPKEY:
+ case WHEELDOWNMOUSE:
+ if(Trans.flag & T_PROP_EDIT) {
+ Trans.propsize*= 1.1f;
+ calculatePropRatio(&Trans);
+ }
+ else view_editmove(event);
+ Trans.redraw= 1;
+ break;
+ case PADMINUS:
+ if(G.qual & LR_ALTKEY && Trans.flag & T_PROP_EDIT) {
+ Trans.propsize*= 0.90909090f;
+ calculatePropRatio(&Trans);
+ }
+ Trans.redraw= 1;
+ break;
+ case PAGEDOWNKEY:
+ case WHEELUPMOUSE:
+ if(Trans.flag & T_PROP_EDIT) {
+ Trans.propsize*= 0.90909090f;
+ calculatePropRatio(&Trans);
+ }
+ else view_editmove(event);
+ Trans.redraw= 1;
+ break;
+ }
+
+ // Numerical input events
+ Trans.redraw |= handleNumInput(&(Trans.num), event);
+
+ // Snapping events
+ Trans.redraw |= handleSnapping(&Trans, event);
+
+ arrows_move_cursor(event);
+ }
+ else {
+ switch (event){
+ /* no redraw on release modifier keys! this makes sure you can assign the 'grid' still
+ after releasing modifer key */
+ case MIDDLEMOUSE:
+ if ((Trans.flag & T_NO_CONSTRAINT)==0) {
+ Trans.flag &= ~T_MMB_PRESSED;
+ postSelectConstraint(&Trans);
+ Trans.redraw = 1;
+ }
+ break;
+ case LEFTMOUSE:
+ case RIGHTMOUSE:
+ if (Trans.context & CTX_TWEAK)
+ Trans.state = TRANS_CONFIRM;
+ break;
+ case LEFTSHIFTKEY:
+ case RIGHTSHIFTKEY:
+ /* shift is modifier for higher resolution transform */
+ Trans.flag &= ~T_SHIFT_MOD;
+ break;
+ }
+ }
+
+ // Per transform event, if present
+ if (Trans.handleEvent)
+ Trans.redraw |= Trans.handleEvent(&Trans, event, val);
+}
+
+int calculateTransformCenter(int centerMode, float *vec)
+{
+ int success = 1;
+ checkFirstTime();
+
+ Trans.state = TRANS_RUNNING;
+
+ Trans.context = CTX_NONE;
+
+ Trans.mode = TFM_DUMMY;
+
+ initTrans(&Trans); // internal data, mouse, vectors
+
+ createTransData(&Trans); // make TransData structs from selection
+
+ Trans.around = centerMode; // override userdefined mode
+
+ if (Trans.total == 0) {
+ success = 0;
+ }
+ else {
+ success = 1;
+
+ calculateCenter(&Trans);
+
+ // Copy center from constraint center. Transform center can be local
+ VECCOPY(vec, Trans.con.center);
+ }
+
+ postTrans(&Trans);
+
+ /* aftertrans does insert ipos and action channels, and clears base flags, doesnt read transdata */
+ special_aftertrans_update(&Trans);
+
+ return success;
+}
+
+void initTransform(int mode, int context) {
+ /* added initialize, for external calls to set stuff in TransInfo, like undo string */
+ checkFirstTime();
+
+ Trans.state = TRANS_RUNNING;
+
+ Trans.context = context;
+
+ Trans.mode = mode;
+
+ initTrans(&Trans); // internal data, mouse, vectors
+
+ if(Trans.spacetype==SPACE_VIEW3D) {
+ calc_manipulator_stats(curarea);
+ Mat3CpyMat4(Trans.spacemtx, G.vd->twmat);
+ }
+ else
+ Mat3One(Trans.spacemtx);
+
+ createTransData(&Trans); // make TransData structs from selection
+
+ initSnapping(&Trans); // Initialize snapping data AFTER mode flags
+
+ if (Trans.total == 0) {
+ postTrans(&Trans);
+ return;
+ }
+
+ /* EVIL! posemode code can switch translation to rotate when 1 bone is selected. will be removed (ton) */
+ /* EVIL2: we gave as argument also texture space context bit... was cleared */
+ /* EVIL3: extend mode for animation editors also switches modes... but is best way to avoid duplicate code */
+ mode = Trans.mode;
+
+ calculatePropRatio(&Trans);
+ calculateCenter(&Trans);
+
+ switch (mode) {
+ case TFM_TRANSLATION:
+ initTranslation(&Trans);
+ break;
+ case TFM_ROTATION:
+ initRotation(&Trans);
+ break;
+ case TFM_RESIZE:
+ initResize(&Trans);
+ break;
+ case TFM_TOSPHERE:
+ initToSphere(&Trans);
+ break;
+ case TFM_SHEAR:
+ initShear(&Trans);
+ break;
+ case TFM_WARP:
+ initWarp(&Trans);
+ break;
+ case TFM_SHRINKFATTEN:
+ initShrinkFatten(&Trans);
+ break;
+ case TFM_TILT:
+ initTilt(&Trans);
+ break;
+ case TFM_CURVE_SHRINKFATTEN:
+ initCurveShrinkFatten(&Trans);
+ break;
+ case TFM_TRACKBALL:
+ initTrackball(&Trans);
+ break;
+ case TFM_PUSHPULL:
+ initPushPull(&Trans);
+ break;
+ case TFM_CREASE:
+ initCrease(&Trans);
+ break;
+ case TFM_BONESIZE:
+ { /* used for both B-Bone width (bonesize) as for deform-dist (envelope) */
+ bArmature *arm= Trans.poseobj->data;
+ if(arm->drawtype==ARM_ENVELOPE)
+ initBoneEnvelope(&Trans);
+ else
+ initBoneSize(&Trans);
+ }
+ break;
+ case TFM_BONE_ENVELOPE:
+ initBoneEnvelope(&Trans);
+ break;
+ case TFM_BONE_ROLL:
+ initBoneRoll(&Trans);
+ break;
+ case TFM_TIME_TRANSLATE:
+ initTimeTranslate(&Trans);
+ break;
+ case TFM_TIME_SLIDE:
+ initTimeSlide(&Trans);
+ break;
+ case TFM_TIME_SCALE:
+ initTimeScale(&Trans);
+ break;
+ case TFM_TIME_EXTEND:
+ /* now that transdata has been made, do like for TFM_TIME_TRANSLATE */
+ initTimeTranslate(&Trans);
+ break;
+ }
+}
+
+void Transform()
+{
+ short pmval[2] = {0, 0}, mval[2], val;
+ unsigned short event;
+
+ if(Trans.total==0) return; // added, can happen now! (ton)
+
+ // Emptying event queue
+ while( qtest() ) {
+ event= extern_qread(&val);
+ }
+
+ Trans.redraw = 1; /* initial draw */
+
+ while (Trans.state == TRANS_RUNNING) {
+
+ getmouseco_areawin(mval);
+
+ if (mval[0] != pmval[0] || mval[1] != pmval[1]) {
+ if (Trans.flag & T_MMB_PRESSED)
+ Trans.con.mode |= CON_SELECT;
+ Trans.redraw = 1;
+ }
+ if (Trans.redraw) {
+ pmval[0] = mval[0];
+ pmval[1] = mval[1];
+
+ selectConstraint(&Trans);
+ if (Trans.transform) {
+ Trans.transform(&Trans, mval); // calls recalcData()
+ }
+ Trans.redraw = 0;
+ }
+
+ /* essential for idling subloop */
+ if( qtest()==0) PIL_sleep_ms(2);
+
+ while( qtest() ) {
+ event= extern_qread(&val);
+ transformEvent(event, val);
+ }
+ }
+
+
+ /* handle restoring objects */
+ if(Trans.state == TRANS_CANCEL)
+ restoreTransObjects(&Trans); // calls recalcData()
+
+ /* free data */
+ postTrans(&Trans);
+
+ /* aftertrans does insert ipos and action channels, and clears base flags, doesnt read transdata */
+ special_aftertrans_update(&Trans);
+
+ /* send events out for redraws */
+ viewRedrawPost(&Trans);
+
+ /* Undo as last, certainly after special_trans_update! */
+ if(Trans.state == TRANS_CANCEL) {
+ if(Trans.undostr) BIF_undo_push(Trans.undostr);
+ }
+ else {
+ if(Trans.undostr) BIF_undo_push(Trans.undostr);
+ else BIF_undo_push(transform_to_undostr(&Trans));
+ }
+ Trans.undostr= NULL;
+
+}
+
+/* ************************** Manipulator init and main **************************** */
+
+void initManipulator(int mode)
+{
+ Trans.state = TRANS_RUNNING;
+
+ Trans.context = CTX_NONE;
+
+ Trans.mode = mode;
+
+ /* automatic switch to scaling bone envelopes */
+ if(mode==TFM_RESIZE && G.obedit && G.obedit->type==OB_ARMATURE) {
+ bArmature *arm= G.obedit->data;
+ if(arm->drawtype==ARM_ENVELOPE)
+ mode= TFM_BONE_ENVELOPE;
+ }
+
+ initTrans(&Trans); // internal data, mouse, vectors
+
+ G.moving |= G_TRANSFORM_MANIP; // signal to draw manipuls while transform
+ createTransData(&Trans); // make TransData structs from selection
+
+ if (Trans.total == 0)
+ return;
+
+ initSnapping(&Trans); // Initialize snapping data AFTER mode flags
+
+ /* EVIL! posemode code can switch translation to rotate when 1 bone is selected. will be removed (ton) */
+ /* EVIL2: we gave as argument also texture space context bit... was cleared */
+ mode = Trans.mode;
+
+ calculatePropRatio(&Trans);
+ calculateCenter(&Trans);
+
+ switch (mode) {
+ case TFM_TRANSLATION:
+ initTranslation(&Trans);
+ break;
+ case TFM_ROTATION:
+ initRotation(&Trans);
+ break;
+ case TFM_RESIZE:
+ initResize(&Trans);
+ break;
+ case TFM_TRACKBALL:
+ initTrackball(&Trans);
+ break;
+ }
+
+ Trans.flag |= T_USES_MANIPULATOR;
+}
+
+void ManipulatorTransform()
+{
+ int mouse_moved = 0;
+ short pmval[2] = {0, 0}, mval[2], val;
+ unsigned short event;
+
+ if (Trans.total == 0)
+ return;
+
+ Trans.redraw = 1; /* initial draw */
+
+ while (Trans.state == TRANS_RUNNING) {
+
+ getmouseco_areawin(mval);
+
+ if (mval[0] != pmval[0] || mval[1] != pmval[1]) {
+ Trans.redraw = 1;
+ }
+ if (Trans.redraw) {
+ pmval[0] = mval[0];
+ pmval[1] = mval[1];
+
+ //selectConstraint(&Trans); needed?
+ if (Trans.transform) {
+ Trans.transform(&Trans, mval);
+ }
+ Trans.redraw = 0;
+ }
+
+ /* essential for idling subloop */
+ if( qtest()==0) PIL_sleep_ms(2);
+
+ while( qtest() ) {
+ event= extern_qread(&val);
+
+ switch (event){
+ case MOUSEX:
+ case MOUSEY:
+ mouse_moved = 1;
+ break;
+ /* enforce redraw of transform when modifiers are used */
+ case LEFTCTRLKEY:
+ case RIGHTCTRLKEY:
+ if(val) Trans.redraw = 1;
+ break;
+ case LEFTSHIFTKEY:
+ case RIGHTSHIFTKEY:
+ /* shift is modifier for higher resolution transform, works nice to store this mouse position */
+ if(val) {
+ getmouseco_areawin(Trans.shiftmval);
+ Trans.flag |= T_SHIFT_MOD;
+ Trans.redraw = 1;
+ }
+ else Trans.flag &= ~T_SHIFT_MOD;
+ break;
+
+ case ESCKEY:
+ case RIGHTMOUSE:
+ Trans.state = TRANS_CANCEL;
+ break;
+ case LEFTMOUSE:
+ if(mouse_moved==0 && val==0) break;
+ // else we pass on event to next, which cancels
+ case SPACEKEY:
+ case PADENTER:
+ case RETKEY:
+ Trans.state = TRANS_CONFIRM;
+ break;
+ }
+ if(val) {
+ switch(event) {
+ case WHEELDOWNMOUSE:
+ case PADPLUSKEY:
+ if(Trans.flag & T_PROP_EDIT) {
+ Trans.propsize*= 1.1f;
+ calculatePropRatio(&Trans);
+ Trans.redraw= 1;
+ }
+ break;
+ case WHEELUPMOUSE:
+ case PADMINUS:
+ if(Trans.flag & T_PROP_EDIT) {
+ Trans.propsize*= 0.90909090f;
+ calculatePropRatio(&Trans);
+ Trans.redraw= 1;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ if(Trans.state == TRANS_CANCEL) {
+ restoreTransObjects(&Trans);
+ }
+
+ /* free data, reset vars */
+ postTrans(&Trans);
+
+ /* aftertrans does insert ipos and action channels, and clears base flags */
+ special_aftertrans_update(&Trans);
+
+ /* send events out for redraws */
+ viewRedrawPost(&Trans);
+
+ if(Trans.state != TRANS_CANCEL) {
+ BIF_undo_push(transform_to_undostr(&Trans));
+ }
+
+}
+
+/* ************************** TRANSFORMATIONS **************************** */
+
+static void protectedTransBits(short protectflag, float *vec)
+{
+ if(protectflag & OB_LOCK_LOCX)
+ vec[0]= 0.0f;
+ if(protectflag & OB_LOCK_LOCY)
+ vec[1]= 0.0f;
+ if(protectflag & OB_LOCK_LOCZ)
+ vec[2]= 0.0f;
+}
+
+static void protectedSizeBits(short protectflag, float *size)
+{
+ if(protectflag & OB_LOCK_SCALEX)
+ size[0]= 1.0f;
+ if(protectflag & OB_LOCK_SCALEY)
+ size[1]= 1.0f;
+ if(protectflag & OB_LOCK_SCALEZ)
+ size[2]= 1.0f;
+}
+
+static void protectedRotateBits(short protectflag, float *eul, float *oldeul)
+{
+ if(protectflag & OB_LOCK_ROTX)
+ eul[0]= oldeul[0];
+ if(protectflag & OB_LOCK_ROTY)
+ eul[1]= oldeul[1];
+ if(protectflag & OB_LOCK_ROTZ)
+ eul[2]= oldeul[2];
+}
+
+static void protectedQuaternionBits(short protectflag, float *quat, float *oldquat)
+{
+ /* quaternions get limited with euler... */
+ /* this function only does the delta rotation */
+
+ if(protectflag) {
+ float eul[3], oldeul[3], quat1[4];
+
+ QUATCOPY(quat1, quat);
+ QuatToEul(quat, eul);
+ QuatToEul(oldquat, oldeul);
+
+ if(protectflag & OB_LOCK_ROTX)
+ eul[0]= oldeul[0];
+ if(protectflag & OB_LOCK_ROTY)
+ eul[1]= oldeul[1];
+ if(protectflag & OB_LOCK_ROTZ)
+ eul[2]= oldeul[2];
+
+ EulToQuat(eul, quat);
+ /* quaternions flip w sign to accumulate rotations correctly */
+ if( (quat1[0]<0.0f && quat[0]>0.0f) || (quat1[0]>0.0f && quat[0]<0.0f) ) {
+ QuatMulf(quat, -1.0f);
+ }
+ }
+}
+
+/* ************************** WARP *************************** */
+
+void initWarp(TransInfo *t)
+{
+ float max[3], min[3];
+ int i;
+
+ t->mode = TFM_WARP;
+ t->transform = Warp;
+
+ t->idx_max = 0;
+ t->num.idx_max = 0;
+ t->snap[0] = 0.0f;
+ t->snap[1] = 5.0f;
+ t->snap[2] = 1.0f;
+
+ t->flag |= T_NO_CONSTRAINT;
+
+/* warp is done fully in view space */
+ calculateCenterCursor(t);
+ t->fac = (float)(t->center2d[0] - t->imval[0]);
+
+ /* we need min/max in view space */
+ for(i = 0; i < t->total; i++) {
+ float center[3];
+ VECCOPY(center, t->data[i].center);
+ Mat3MulVecfl(t->data[i].mtx, center);
+ Mat4MulVecfl(t->viewmat, center);
+ VecSubf(center, center, t->viewmat[3]);
+ if (i)
+ MinMax3(min, max, center);
+ else {
+ VECCOPY(max, center);
+ VECCOPY(min, center);
+ }
+ }
+
+ t->center[0]= (min[0]+max[0])/2.0f;
+ t->center[1]= (min[1]+max[1])/2.0f;
+ t->center[2]= (min[2]+max[2])/2.0f;
+
+ if (max[0] == min[0]) max[0] += 0.1; /* not optimal, but flipping is better than invalid garbage (i.e. division by zero!) */
+ t->val= (max[0]-min[0])/2.0f; /* t->val is X dimension projected boundbox */
+}
+
+int Warp(TransInfo *t, short mval[2])
+{
+ TransData *td = t->data;
+ float vec[3], circumfac, dist, phi0, co, si, *curs, cursor[3], gcursor[3];
+ int i;
+ char str[50];
+
+ curs= give_cursor();
+ /*
+ * gcursor is the one used for helpline.
+ * It has to be in the same space as the drawing loop
+ * (that means it needs to be in the object's space when in edit mode and
+ * in global space in object mode)
+ *
+ * cursor is used for calculations.
+ * It needs to be in view space, but we need to take object's offset
+ * into account if in Edit mode.
+ */
+ VECCOPY(cursor, curs);
+ VECCOPY(gcursor, cursor);
+ if (t->flag & T_EDIT) {
+ VecSubf(cursor, cursor, G.obedit->obmat[3]);
+ VecSubf(gcursor, gcursor, G.obedit->obmat[3]);
+ Mat3MulVecfl(t->data->smtx, gcursor);
+ }
+ Mat4MulVecfl(t->viewmat, cursor);
+ VecSubf(cursor, cursor, t->viewmat[3]);
+
+ /* amount of degrees for warp */
+ circumfac= 360.0f * InputHorizontalRatio(t, mval);
+
+ snapGrid(t, &circumfac);
+ applyNumInput(&t->num, &circumfac);
+
+ /* header print for NumInput */
+ if (hasNumInput(&t->num)) {
+ char c[20];
+
+ outputNumInput(&(t->num), c);
+
+ sprintf(str, "Warp: %s", c);
+ }
+ else {
+ /* default header print */
+ sprintf(str, "Warp: %.3f", circumfac);
+ }
+
+ circumfac*= (float)(-M_PI/360.0);
+
+ for(i = 0; i < t->total; i++, td++) {
+ float loc[3];
+ if (td->flag & TD_NOACTION)
+ break;
+
+ /* translate point to center, rotate in such a way that outline==distance */
+ VECCOPY(vec, td->iloc);
+ Mat3MulVecfl(td->mtx, vec);
+ Mat4MulVecfl(t->viewmat, vec);
+ VecSubf(vec, vec, t->viewmat[3]);
+
+ dist= vec[0]-cursor[0];
+
+ /* t->val is X dimension projected boundbox */
+ phi0= (circumfac*dist/t->val);
+
+ vec[1]= (vec[1]-cursor[1]);
+
+ co= (float)cos(phi0);
+ si= (float)sin(phi0);
+ loc[0]= -si*vec[1]+cursor[0];
+ loc[1]= co*vec[1]+cursor[1];
+ loc[2]= vec[2];
+
+ Mat4MulVecfl(t->viewinv, loc);
+ VecSubf(loc, loc, t->viewinv[3]);
+ Mat3MulVecfl(td->smtx, loc);
+
+ VecSubf(loc, loc, td->iloc);
+ VecMulf(loc, td->factor);
+ VecAddf(td->loc, td->iloc, loc);
+ }
+
+ recalcData(t);
+
+ headerprint(str);
+
+ viewRedrawForce(t);
+
+ helpline(t, gcursor);
+
+ return 1;
+}
+
+/* ************************** SHEAR *************************** */
+
+void initShear(TransInfo *t)
+{
+ t->mode = TFM_SHEAR;
+ t->transform = Shear;
+ t->handleEvent = handleEventShear;
+
+ t->idx_max = 0;
+ t->num.idx_max = 0;
+ t->snap[0] = 0.0f;
+ t->snap[1] = 0.1f;
+ t->snap[2] = t->snap[1] * 0.1f;
+
+ t->flag |= T_NO_CONSTRAINT;
+}
+
+int handleEventShear(TransInfo *t, unsigned short event, short val)
+{
+ int status = 0;
+
+ if (event == MIDDLEMOUSE && val)
+ {
+ // Use customData pointer to signal Shear direction
+ if (t->customData == 0)
+ t->customData = (void*)1;
+ else
+ t->customData = 0;
+
+ status = 1;
+ }
+
+ return status;
+}
+
+
+int Shear(TransInfo *t, short mval[2])
+{
+ TransData *td = t->data;
+ float vec[3];
+ float smat[3][3], tmat[3][3], totmat[3][3], persmat[3][3], persinv[3][3];
+ float value;
+ int i;
+ char str[50];
+
+ Mat3CpyMat4(persmat, t->viewmat);
+ Mat3Inv(persinv, persmat);
+
+ // Custom data signals shear direction
+ if (t->customData == 0)
+ value = 0.05f * InputHorizontalAbsolute(t, mval);
+ else
+ value = 0.05f * InputVerticalAbsolute(t, mval);
+
+ snapGrid(t, &value);
+
+ applyNumInput(&t->num, &value);
+
+ /* header print for NumInput */
+ if (hasNumInput(&t->num)) {
+ char c[20];
+
+ outputNumInput(&(t->num), c);
+
+ sprintf(str, "Shear: %s %s", c, t->proptext);
+ }
+ else {
+ /* default header print */
+ sprintf(str, "Shear: %.3f %s", value, t->proptext);
+ }
+
+ Mat3One(smat);
+
+ // Custom data signals shear direction
+ if (t->customData == 0)
+ smat[1][0] = value;
+ else
+ smat[0][1] = value;
+
+ Mat3MulMat3(tmat, smat, persmat);
+ Mat3MulMat3(totmat, persinv, tmat);
+
+ for(i = 0 ; i < t->total; i++, td++) {
+ if (td->flag & TD_NOACTION)
+ break;
+
+ if (G.obedit) {
+ float mat3[3][3];
+ Mat3MulMat3(mat3, totmat, td->mtx);
+ Mat3MulMat3(tmat, td->smtx, mat3);
+ }
+ else {
+ Mat3CpyMat3(tmat, totmat);
+ }
+ VecSubf(vec, td->center, t->center);
+
+ Mat3MulVecfl(tmat, vec);
+
+ VecAddf(vec, vec, t->center);
+ VecSubf(vec, vec, td->center);
+
+ VecMulf(vec, td->factor);
+
+ VecAddf(td->loc, td->iloc, vec);
+ }
+
+ recalcData(t);
+
+ headerprint(str);
+
+ viewRedrawForce(t);
+
+ helpline (t, t->center);
+
+ return 1;
+}
+
+/* ************************** RESIZE *************************** */
+
+void initResize(TransInfo *t)
+{
+ t->mode = TFM_RESIZE;
+ t->transform = Resize;
+
+ t->flag |= T_NULL_ONE;
+ t->num.flag |= NUM_NULL_ONE;
+ t->num.flag |= NUM_AFFECT_ALL;
+ if (!G.obedit) {
+ t->flag |= T_NO_ZERO;
+ t->num.flag |= NUM_NO_ZERO;
+ }
+
+ t->idx_max = 2;
+ t->num.idx_max = 2;
+ t->snap[0] = 0.0f;
+ t->snap[1] = 0.1f;
+ t->snap[2] = t->snap[1] * 0.1f;
+
+ t->fac = (float)sqrt(
+ (
+ ((float)(t->center2d[1] - t->imval[1]))*((float)(t->center2d[1] - t->imval[1]))
+ +
+ ((float)(t->center2d[0] - t->imval[0]))*((float)(t->center2d[0] - t->imval[0]))
+ ) );
+
+ if(t->fac==0.0f) t->fac= 1.0f; // prevent Inf
+}
+
+static void headerResize(TransInfo *t, float vec[3], char *str) {
+ char tvec[60];
+ if (hasNumInput(&t->num)) {
+ outputNumInput(&(t->num), tvec);
+ }
+ else {
+ sprintf(&tvec[0], "%.4f", vec[0]);
+ sprintf(&tvec[20], "%.4f", vec[1]);
+ sprintf(&tvec[40], "%.4f", vec[2]);
+ }
+
+ if (t->con.mode & CON_APPLY) {
+ switch(t->num.idx_max) {
+ case 0:
+ sprintf(str, "Scale: %s%s %s", &tvec[0], t->con.text, t->proptext);
+ break;
+ case 1:
+ sprintf(str, "Scale: %s : %s%s %s", &tvec[0], &tvec[20], t->con.text, t->proptext);
+ break;
+ case 2:
+ sprintf(str, "Scale: %s : %s : %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
+ }
+ }
+ else {
+ if (t->flag & T_2D_EDIT)
+ sprintf(str, "Scale X: %s Y: %s%s %s", &tvec[0], &tvec[20], t->con.text, t->proptext);
+ else
+ sprintf(str, "Scale X: %s Y: %s Z: %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
+ }
+}
+
+#define SIGN(a) (a<-FLT_EPSILON?1:a>FLT_EPSILON?2:3)
+#define VECSIGNFLIP(a, b) ((SIGN(a[0]) & SIGN(b[0]))==0 || (SIGN(a[1]) & SIGN(b[1]))==0 || (SIGN(a[2]) & SIGN(b[2]))==0)
+
+/* smat is reference matrix, only scaled */
+static void TransMat3ToSize( float mat[][3], float smat[][3], float *size)
+{
+ float vec[3];
+
+ VecCopyf(vec, mat[0]);
+ size[0]= Normalize(vec);
+ VecCopyf(vec, mat[1]);
+ size[1]= Normalize(vec);
+ VecCopyf(vec, mat[2]);
+ size[2]= Normalize(vec);
+
+ /* first tried with dotproduct... but the sign flip is crucial */
+ if( VECSIGNFLIP(mat[0], smat[0]) ) size[0]= -size[0];
+ if( VECSIGNFLIP(mat[1], smat[1]) ) size[1]= -size[1];
+ if( VECSIGNFLIP(mat[2], smat[2]) ) size[2]= -size[2];
+}
+
+
+static void ElementResize(TransInfo *t, TransData *td, float mat[3][3]) {
+ float tmat[3][3], smat[3][3], center[3];
+ float vec[3];
+
+ if (t->flag & T_EDIT) {
+ Mat3MulMat3(smat, mat, td->mtx);
+ Mat3MulMat3(tmat, td->smtx, smat);
+ }
+ else {
+ Mat3CpyMat3(tmat, mat);
+ }
+
+ if (t->con.applySize) {
+ t->con.applySize(t, td, tmat);
+ }
+
+ /* local constraint shouldn't alter center */
+ if (t->around == V3D_LOCAL) {
+ if (t->flag & T_OBJECT) {
+ VECCOPY(center, td->center);
+ }
+ else if (t->flag & T_EDIT) {
+
+ if(G.vd->around==V3D_LOCAL && (G.scene->selectmode & SCE_SELECT_FACE)) {
+ VECCOPY(center, td->center);
+ }
+ else {
+ VECCOPY(center, t->center);
+ }
+ }
+ else {
+ VECCOPY(center, t->center);
+ }
+ }
+ else {
+ VECCOPY(center, t->center);
+ }
+
+ if (td->ext) {
+ float fsize[3];
+
+ if (t->flag & (T_OBJECT|T_TEXTURE|T_POSE)) {
+ float obsizemat[3][3];
+ // Reorient the size mat to fit the oriented object.
+ Mat3MulMat3(obsizemat, tmat, td->axismtx);
+ //printmatrix3("obsizemat", obsizemat);
+ TransMat3ToSize(obsizemat, td->axismtx, fsize);
+ //printvecf("fsize", fsize);
+ }
+ else {
+ Mat3ToSize(tmat, fsize);
+ }
+
+ protectedSizeBits(td->protectflag, fsize);
+
+ if ((t->flag & T_V3D_ALIGN)==0) { // align mode doesn't resize objects itself
+ /* handle ipokeys? */
+ if(td->tdi) {
+ TransDataIpokey *tdi= td->tdi;
+ /* calculate delta size (equal for size and dsize) */
+
+ vec[0]= (tdi->oldsize[0])*(fsize[0] -1.0f) * td->factor;
+ vec[1]= (tdi->oldsize[1])*(fsize[1] -1.0f) * td->factor;
+ vec[2]= (tdi->oldsize[2])*(fsize[2] -1.0f) * td->factor;
+
+ add_tdi_poin(tdi->sizex, tdi->oldsize, vec[0]);
+ add_tdi_poin(tdi->sizey, tdi->oldsize+1, vec[1]);
+ add_tdi_poin(tdi->sizez, tdi->oldsize+2, vec[2]);
+
+ }
+ else if((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)){
+ /* scale val and reset size */
+ *td->val = td->ival * fsize[0] * td->factor;
+
+ td->ext->size[0] = td->ext->isize[0];
+ td->ext->size[1] = td->ext->isize[1];
+ td->ext->size[2] = td->ext->isize[2];
+ }
+ else {
+ /* Reset val if SINGLESIZE but using a constraint */
+ if (td->flag & TD_SINGLESIZE)
+ *td->val = td->ival;
+
+ td->ext->size[0] = td->ext->isize[0] * (fsize[0]) * td->factor;
+ td->ext->size[1] = td->ext->isize[1] * (fsize[1]) * td->factor;
+ td->ext->size[2] = td->ext->isize[2] * (fsize[2]) * td->factor;
+ }
+ }
+ }
+ /* For individual element center, Editmode need to use iloc */
+ if (t->flag & T_POINTS)
+ VecSubf(vec, td->iloc, center);
+ else
+ VecSubf(vec, td->center, center);
+
+ Mat3MulVecfl(tmat, vec);
+
+ VecAddf(vec, vec, center);
+ if (t->flag & T_POINTS)
+ VecSubf(vec, vec, td->iloc);
+ else
+ VecSubf(vec, vec, td->center);
+
+ VecMulf(vec, td->factor);
+
+ if (t->flag & T_OBJECT) {
+ Mat3MulVecfl(td->smtx, vec);
+ }
+
+ protectedTransBits(td->protectflag, vec);
+
+ if(td->tdi) {
+ TransDataIpokey *tdi= td->tdi;
+ add_tdi_poin(tdi->locx, tdi->oldloc, vec[0]);
+ add_tdi_poin(tdi->locy, tdi->oldloc+1, vec[1]);
+ add_tdi_poin(tdi->locz, tdi->oldloc+2, vec[2]);
+ }
+ else VecAddf(td->loc, td->iloc, vec);
+}
+
+int Resize(TransInfo *t, short mval[2])
+{
+ TransData *td;
+ float size[3], mat[3][3];
+ float ratio;
+ int i;
+ char str[200];
+
+ /* for manipulator, center handle, the scaling can't be done relative to center */
+ if( (t->flag & T_USES_MANIPULATOR) && t->con.mode==0) {
+ ratio = 1.0f - ((t->imval[0] - mval[0]) + (t->imval[1] - mval[1]))/100.0f;
+ }
+ else {
+ ratio = InputScaleRatio(t, mval);
+
+ /* flip scale, but not for manipulator center handle */
+ if ((t->center2d[0] - mval[0]) * (t->center2d[0] - t->imval[0]) +
+ (t->center2d[1] - mval[1]) * (t->center2d[1] - t->imval[1]) < 0)
+ ratio *= -1.0f;
+ }
+
+ size[0] = size[1] = size[2] = ratio;
+
+ snapGrid(t, size);
+
+ if (hasNumInput(&t->num)) {
+ applyNumInput(&t->num, size);
+ constraintNumInput(t, size);
+ }
+
+ SizeToMat3(size, mat);
+
+ if (t->con.applySize) {
+ t->con.applySize(t, NULL, mat);
+ }
+
+ Mat3CpyMat3(t->mat, mat); // used in manipulator
+
+ headerResize(t, size, str);
+
+ for(i = 0, td=t->data; i < t->total; i++, td++) {
+ if (td->flag & TD_NOACTION)
+ break;
+
+ ElementResize(t, td, mat);
+ }
+
+ /* evil hack - redo resize if cliping needed */
+ if (t->flag & T_CLIP_UV && clipUVTransform(t, size, 1)) {
+ SizeToMat3(size, mat);
+
+ if (t->con.applySize)
+ t->con.applySize(t, NULL, mat);
+
+ for(i = 0, td=t->data; i < t->total; i++, td++)
+ ElementResize(t, td, mat);
+ }
+
+ recalcData(t);
+
+ headerprint(str);
+
+ viewRedrawForce(t);
+
+ if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
+
+ return 1;
+}
+
+/* ************************** TOSPHERE *************************** */
+
+void initToSphere(TransInfo *t)
+{
+ TransData *td = t->data;
+ int i;
+
+ t->mode = TFM_TOSPHERE;
+ t->transform = ToSphere;
+
+ t->idx_max = 0;
+ t->num.idx_max = 0;
+ t->snap[0] = 0.0f;
+ t->snap[1] = 0.1f;
+ t->snap[2] = t->snap[1] * 0.1f;
+
+ t->num.flag |= NUM_NULL_ONE | NUM_NO_NEGATIVE;
+ t->flag |= T_NO_CONSTRAINT;
+
+ // Calculate average radius
+ for(i = 0 ; i < t->total; i++, td++) {
+ t->val += VecLenf(t->center, td->iloc);
+ }
+
+ t->val /= (float)t->total;
+}
+
+int ToSphere(TransInfo *t, short mval[2])
+{
+ float vec[3];
+ float ratio, radius;
+ int i;
+ char str[64];
+ TransData *td = t->data;
+
+ ratio = InputHorizontalRatio(t, mval);
+
+ snapGrid(t, &ratio);
+
+ applyNumInput(&t->num, &ratio);
+
+ if (ratio < 0)
+ ratio = 0.0f;
+ else if (ratio > 1)
+ ratio = 1.0f;
+
+ /* header print for NumInput */
+ if (hasNumInput(&t->num)) {
+ char c[20];
+
+ outputNumInput(&(t->num), c);
+
+ sprintf(str, "To Sphere: %s %s", c, t->proptext);
+ }
+ else {
+ /* default header print */
+ sprintf(str, "To Sphere: %.4f %s", ratio, t->proptext);
+ }
+
+
+ for(i = 0 ; i < t->total; i++, td++) {
+ float tratio;
+ if (td->flag & TD_NOACTION)
+ break;
+
+ VecSubf(vec, td->iloc, t->center);
+
+ radius = Normalize(vec);
+
+ tratio = ratio * td->factor;
+
+ VecMulf(vec, radius * (1.0f - tratio) + t->val * tratio);
+
+ VecAddf(td->loc, t->center, vec);
+ }
+
+
+ recalcData(t);
+
+ headerprint(str);
+
+ viewRedrawForce(t);
+
+ return 1;
+}
+
+/* ************************** ROTATION *************************** */
+
+
+void initRotation(TransInfo *t)
+{
+ t->mode = TFM_ROTATION;
+ t->transform = Rotation;
+
+ t->idx_max = 0;
+ t->num.idx_max = 0;
+ t->snap[0] = 0.0f;
+ t->snap[1] = (float)((5.0/180)*M_PI);
+ t->snap[2] = t->snap[1] * 0.2f;
+ t->fac = 0;
+
+ if (t->flag & T_2D_EDIT)
+ t->flag |= T_NO_CONSTRAINT;
+}
+
+static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3]) {
+ float vec[3], totmat[3][3], smat[3][3];
+ float eul[3], fmat[3][3], quat[4];
+
+ if (t->flag & T_POINTS) {
+ Mat3MulMat3(totmat, mat, td->mtx);
+ Mat3MulMat3(smat, td->smtx, totmat);
+
+ VecSubf(vec, td->iloc, t->center);
+ Mat3MulVecfl(smat, vec);
+
+ VecAddf(td->loc, vec, t->center);
+
+ if(td->flag & TD_USEQUAT) {
+ Mat3MulSerie(fmat, td->mtx, mat, td->smtx, 0, 0, 0, 0, 0);
+ Mat3ToQuat(fmat, quat); // Actual transform
+ QuatMul(td->ext->quat, quat, td->ext->iquat);
+ }
+ }
+ /**
+ * HACK WARNING
+ *
+ * This is some VERY ugly special case to deal with pose mode.
+ *
+ * The problem is that mtx and smtx include each bone orientation.
+ *
+ * That is needed to rotate each bone properly, HOWEVER, to calculate
+ * the translation component, we only need the actual armature object's
+ * matrix (and inverse). That is not all though. Once the proper translation
+ * has been computed, it has to be converted back into the bone's space.
+ */
+ else if (t->flag & T_POSE) {
+ float pmtx[3][3], imtx[3][3];
+
+ // Extract and invert armature object matrix
+ Mat3CpyMat4(pmtx, t->poseobj->obmat);
+ Mat3Inv(imtx, pmtx);
+
+ VecSubf(vec, td->center, t->center);
+
+ Mat3MulVecfl(pmtx, vec); // To Global space
+ Mat3MulVecfl(mat, vec); // Applying rotation
+ Mat3MulVecfl(imtx, vec); // To Local space
+
+ VecAddf(vec, vec, t->center);
+ /* vec now is the location where the object has to be */
+
+ VecSubf(vec, vec, td->center); // Translation needed from the initial location
+
+ Mat3MulVecfl(pmtx, vec); // To Global space
+ Mat3MulVecfl(td->smtx, vec);// To Pose space
+
+ protectedTransBits(td->protectflag, vec);
+
+ VecAddf(td->loc, td->iloc, vec);
+
+ /* rotation */
+ if ((t->flag & T_V3D_ALIGN)==0) { // align mode doesn't rotate objects itself
+ Mat3MulSerie(fmat, td->mtx, mat, td->smtx, 0, 0, 0, 0, 0);
+
+ Mat3ToQuat(fmat, quat); // Actual transform
+
+ QuatMul(td->ext->quat, quat, td->ext->iquat);
+ /* this function works on end result */
+ protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat);
+ }
+ }
+ else {
+ /* translation */
+
+ VecSubf(vec, td->center, t->center);
+ Mat3MulVecfl(mat, vec);
+ VecAddf(vec, vec, t->center);
+ /* vec now is the location where the object has to be */
+ VecSubf(vec, vec, td->center);
+ Mat3MulVecfl(td->smtx, vec);
+
+ protectedTransBits(td->protectflag, vec);
+
+ if(td->tdi) {
+ TransDataIpokey *tdi= td->tdi;
+ add_tdi_poin(tdi->locx, tdi->oldloc, vec[0]);
+ add_tdi_poin(tdi->locy, tdi->oldloc+1, vec[1]);
+ add_tdi_poin(tdi->locz, tdi->oldloc+2, vec[2]);
+ }
+ else VecAddf(td->loc, td->iloc, vec);
+
+ /* rotation */
+ if ((t->flag & T_V3D_ALIGN)==0) { // align mode doesn't rotate objects itself
+
+ if(td->flag & TD_USEQUAT) {
+ Mat3MulSerie(fmat, td->mtx, mat, td->smtx, 0, 0, 0, 0, 0);
+ Mat3ToQuat(fmat, quat); // Actual transform
+
+ QuatMul(td->ext->quat, quat, td->ext->iquat);
+ /* this function works on end result */
+ protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat);
+ }
+ else {
+ float obmat[3][3];
+
+ /* are there ipo keys? */
+ if(td->tdi) {
+ TransDataIpokey *tdi= td->tdi;
+ float rot[3];
+
+ /* calculate the total rotatation in eulers */
+ VecAddf(eul, td->ext->irot, td->ext->drot);
+ EulToMat3(eul, obmat);
+ /* mat = transform, obmat = object rotation */
+ Mat3MulMat3(fmat, mat, obmat);
+
+ Mat3ToCompatibleEul(fmat, eul, td->ext->irot);
+
+ /* correct back for delta rot */
+ if(tdi->flag & TOB_IPODROT) {
+ VecSubf(rot, eul, td->ext->irot);
+ }
+ else {
+ VecSubf(rot, eul, td->ext->drot);
+ }
+
+ VecMulf(rot, (float)(9.0/M_PI_2));
+ VecSubf(rot, rot, tdi->oldrot);
+
+ protectedRotateBits(td->protectflag, rot, tdi->oldrot);
+
+ add_tdi_poin(tdi->rotx, tdi->oldrot, rot[0]);
+ add_tdi_poin(tdi->roty, tdi->oldrot+1, rot[1]);
+ add_tdi_poin(tdi->rotz, tdi->oldrot+2, rot[2]);
+ }
+ else {
+ Mat3MulMat3(totmat, mat, td->mtx);
+ Mat3MulMat3(smat, td->smtx, totmat);
+
+ /* calculate the total rotatation in eulers */
+ VecAddf(eul, td->ext->irot, td->ext->drot); /* we have to correct for delta rot */
+ EulToMat3(eul, obmat);
+ /* mat = transform, obmat = object rotation */
+ Mat3MulMat3(fmat, smat, obmat);
+
+ Mat3ToCompatibleEul(fmat, eul, td->ext->irot);
+
+ /* correct back for delta rot */
+ VecSubf(eul, eul, td->ext->drot);
+
+ /* and apply */
+ protectedRotateBits(td->protectflag, eul, td->ext->irot);
+ VECCOPY(td->ext->rot, eul);
+ }
+ }
+ }
+ }
+}
+
+static void applyRotation(TransInfo *t, float angle, float axis[3])
+{
+ TransData *td = t->data;
+ float mat[3][3], center[3];
+ int i;
+
+ /* saving original center */
+ if (t->around == V3D_LOCAL) {
+ VECCOPY(center, t->center);
+ }
+ else {
+ center[0] = center[1] = center[2] = 0.0f;
+ }
+
+ VecRotToMat3(axis, angle, mat);
+
+ for(i = 0 ; i < t->total; i++, td++) {
+
+ if (td->flag & TD_NOACTION)
+ break;
+
+ /* local constraint shouldn't alter center */
+ if (t->around == V3D_LOCAL) {
+ if (t->flag & (T_OBJECT|T_POSE)) {
+ VECCOPY(t->center, td->center);
+ }
+ else {
+ if(G.vd->around==V3D_LOCAL && (G.scene->selectmode & SCE_SELECT_FACE)) {
+ VECCOPY(t->center, td->center);
+ }
+ }
+ }
+
+ if (t->con.applyRot) {
+ t->con.applyRot(t, td, axis);
+ VecRotToMat3(axis, angle * td->factor, mat);
+ }
+ else if (t->flag & T_PROP_EDIT) {
+ VecRotToMat3(axis, angle * td->factor, mat);
+ }
+
+ ElementRotation(t, td, mat);
+ }
+
+ /* restoring original center */
+ if (t->around == V3D_LOCAL) {
+ VECCOPY(t->center, center);
+ }
+}
+
+int Rotation(TransInfo *t, short mval[2])
+{
+ char str[64];
+
+ float final;
+
+ int dx2 = t->center2d[0] - mval[0];
+ int dy2 = t->center2d[1] - mval[1];
+ double B = sqrt(dx2*dx2+dy2*dy2);
+
+ int dx1 = t->center2d[0] - t->imval[0];
+ int dy1 = t->center2d[1] - t->imval[1];
+ double A = sqrt(dx1*dx1+dy1*dy1);
+
+ int dx3 = mval[0] - t->imval[0];
+ int dy3 = mval[1] - t->imval[1];
+ /* use doubles here, to make sure a "1.0" (no rotation) doesnt become 9.999999e-01, which gives 0.02 for acos */
+ double deler= ((double)((dx1*dx1+dy1*dy1)+(dx2*dx2+dy2*dy2)-(dx3*dx3+dy3*dy3) ))
+ / (2.0 * (A*B?A*B:1.0));
+ /* (A*B?A*B:1.0f) this takes care of potential divide by zero errors */
+
+ float dphi;
+
+ float axis[3];
+ float mat[3][3];
+
+ VECCOPY(axis, t->viewinv[2]);
+ VecMulf(axis, -1.0f);
+ Normalize(axis);
+
+ dphi = saacos((float)deler);
+ if( (dx1*dy2-dx2*dy1)>0.0 ) dphi= -dphi;
+
+ if(G.qual & LR_SHIFTKEY) t->fac += dphi/30.0f;
+ else t->fac += dphi;
+
+ /*
+ clamping angle between -2 PI and 2 PI (not sure if useful so commented out - theeth)
+ if (t->fac >= 2 * M_PI)
+ t->fac -= 2 * M_PI;
+ else if (t->fac <= -2 * M_PI)
+ t->fac -= -2 * M_PI;
+ */
+
+ final = t->fac;
+
+ snapGrid(t, &final);
+
+ t->imval[0] = mval[0];
+ t->imval[1] = mval[1];
+
+ if (t->con.applyRot) {
+ t->con.applyRot(t, NULL, axis);
+ }
+
+ applySnapping(t, &final);
+
+ if (hasNumInput(&t->num)) {
+ char c[20];
+
+ applyNumInput(&t->num, &final);
+
+ outputNumInput(&(t->num), c);
+
+ sprintf(str, "Rot: %s %s", &c[0], t->proptext);
+
+ /* Clamp between -180 and 180 */
+ while (final >= 180.0)
+ final -= 360.0;
+
+ while (final <= -180.0)
+ final += 360.0;
+
+ final *= (float)(M_PI / 180.0);
+ }
+ else {
+ sprintf(str, "Rot: %.2f%s %s", 180.0*final/M_PI, t->con.text, t->proptext);
+ }
+
+ VecRotToMat3(axis, final, mat);
+
+ t->val = final; // used in manipulator
+ Mat3CpyMat3(t->mat, mat); // used in manipulator
+
+ applyRotation(t, final, axis);
+
+ recalcData(t);
+
+ headerprint(str);
+
+ viewRedrawForce(t);
+
+ if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
+
+ return 1;
+}
+
+
+/* ************************** TRACKBALL *************************** */
+
+void initTrackball(TransInfo *t)
+{
+ t->mode = TFM_TRACKBALL;
+ t->transform = Trackball;
+
+ t->idx_max = 1;
+ t->num.idx_max = 1;
+ t->snap[0] = 0.0f;
+ t->snap[1] = (float)((5.0/180)*M_PI);
+ t->snap[2] = t->snap[1] * 0.2f;
+ t->fac = 0;
+
+ t->flag |= T_NO_CONSTRAINT;
+}
+
+static void applyTrackball(TransInfo *t, float axis1[3], float axis2[3], float angles[2])
+{
+ TransData *td = t->data;
+ float mat[3][3], smat[3][3], totmat[3][3];
+ float center[3];
+ int i;
+
+ VecRotToMat3(axis1, angles[0], smat);
+ VecRotToMat3(axis2, angles[1], totmat);
+
+ Mat3MulMat3(mat, smat, totmat);
+
+ for(i = 0 ; i < t->total; i++, td++) {
+ if (td->flag & TD_NOACTION)
+ break;
+
+ VECCOPY(center, t->center);
+
+ if (t->around == V3D_LOCAL) {
+ /* local-mode shouldn't change center */
+ if (t->flag & (T_OBJECT|T_POSE)) {
+ VECCOPY(t->center, td->center);
+ }
+ else {
+ if(G.vd->around==V3D_LOCAL && (G.scene->selectmode & SCE_SELECT_FACE)) {
+ VECCOPY(t->center, td->center);
+ }
+ }
+ }
+
+ if (t->flag & T_PROP_EDIT) {
+ VecRotToMat3(axis1, td->factor * angles[0], smat);
+ VecRotToMat3(axis2, td->factor * angles[1], totmat);
+
+ Mat3MulMat3(mat, smat, totmat);
+ }
+
+ ElementRotation(t, td, mat);
+
+ VECCOPY(t->center, center);
+ }
+}
+
+int Trackball(TransInfo *t, short mval[2])
+{
+ char str[128];
+ float axis1[3], axis2[3];
+ float mat[3][3], totmat[3][3], smat[3][3];
+ float phi[2];
+
+ VECCOPY(axis1, t->persinv[0]);
+ VECCOPY(axis2, t->persinv[1]);
+ Normalize(axis1);
+ Normalize(axis2);
+
+ /* factore has to become setting or so */
+ phi[0]= 0.01f*(float)( t->imval[1] - mval[1] );
+ phi[1]= 0.01f*(float)( mval[0] - t->imval[0] );
+
+ //if(G.qual & LR_SHIFTKEY) t->fac += dphi/30.0f;
+ //else t->fac += dphi;
+
+ snapGrid(t, phi);
+
+ if (hasNumInput(&t->num)) {
+ char c[40];
+
+ applyNumInput(&t->num, phi);
+
+ outputNumInput(&(t->num), c);
+
+ sprintf(str, "Trackball: %s %s %s", &c[0], &c[20], t->proptext);
+
+ phi[0] *= (float)(M_PI / 180.0);
+ phi[1] *= (float)(M_PI / 180.0);
+ }
+ else {
+ sprintf(str, "Trackball: %.2f %.2f %s", 180.0*phi[0]/M_PI, 180.0*phi[1]/M_PI, t->proptext);
+ }
+
+ VecRotToMat3(axis1, phi[0], smat);
+ VecRotToMat3(axis2, phi[1], totmat);
+
+ Mat3MulMat3(mat, smat, totmat);
+
+ Mat3CpyMat3(t->mat, mat); // used in manipulator
+
+ applyTrackball(t, axis1, axis2, phi);
+
+ recalcData(t);
+
+ headerprint(str);
+
+ viewRedrawForce(t);
+
+ if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
+
+ return 1;
+}
+
+/* ************************** TRANSLATION *************************** */
+
+void initTranslation(TransInfo *t)
+{
+ t->mode = TFM_TRANSLATION;
+ t->transform = Translation;
+
+ t->idx_max = (t->flag & T_2D_EDIT)? 1: 2;
+ t->num.flag = 0;
+ t->num.idx_max = t->idx_max;
+
+
+ if(t->spacetype == SPACE_VIEW3D) {
+ /* initgrabz() defines a factor for perspective depth correction, used in window_to_3d() */
+ if(t->flag & (T_EDIT|T_POSE)) {
+ Object *ob= G.obedit?G.obedit:t->poseobj;
+ float vec[3];
+
+ VECCOPY(vec, t->center);
+ Mat4MulVecfl(ob->obmat, vec);
+ initgrabz(vec[0], vec[1], vec[2]);
+ }
+ else {
+ initgrabz(t->center[0], t->center[1], t->center[2]);
+ }
+
+ t->snap[0] = 0.0f;
+ t->snap[1] = G.vd->gridview * 1.0f;
+ t->snap[2] = t->snap[1] * 0.1f;
+ }
+ else if(t->spacetype == SPACE_IMAGE) {
+ t->snap[0] = 0.0f;
+ t->snap[1] = 0.125f;
+ t->snap[2] = 0.0625f;
+ }
+ else {
+ t->snap[0] = 0.0f;
+ t->snap[1] = t->snap[2] = 1.0f;
+ }
+}
+
+static void headerTranslation(TransInfo *t, float vec[3], char *str) {
+ char tvec[60];
+ char distvec[20];
+ float dvec[3];
+ float dist;
+
+ convertVecToDisplayNum(vec, dvec);
+
+ if (hasNumInput(&t->num)) {
+ outputNumInput(&(t->num), tvec);
+ dist = VecLength(t->num.val);
+ }
+ else {
+ dist = VecLength(vec);
+ sprintf(&tvec[0], "%.4f", dvec[0]);
+ sprintf(&tvec[20], "%.4f", dvec[1]);
+ sprintf(&tvec[40], "%.4f", dvec[2]);
+ }
+
+ if( dist > 1e10 || dist < -1e10 ) /* prevent string buffer overflow */
+ sprintf(distvec, "%.4e", dist);
+ else
+ sprintf(distvec, "%.4f", dist);
+
+ if (t->con.mode & CON_APPLY) {
+ switch(t->num.idx_max) {
+ case 0:
+ sprintf(str, "D: %s (%s)%s %s", &tvec[0], distvec, t->con.text, t->proptext);
+ break;
+ case 1:
+ sprintf(str, "D: %s D: %s (%s)%s %s", &tvec[0], &tvec[20], distvec, t->con.text, t->proptext);
+ break;
+ case 2:
+ sprintf(str, "D: %s D: %s D: %s (%s)%s %s", &tvec[0], &tvec[20], &tvec[40], distvec, t->con.text, t->proptext);
+ }
+ }
+ else {
+ if(t->flag & T_2D_EDIT)
+ sprintf(str, "Dx: %s Dy: %s (%s)%s %s", &tvec[0], &tvec[20], distvec, t->con.text, t->proptext);
+ else
+ sprintf(str, "Dx: %s Dy: %s Dz: %s (%s)%s %s", &tvec[0], &tvec[20], &tvec[40], distvec, t->con.text, t->proptext);
+ }
+}
+
+static void applyTranslation(TransInfo *t, float vec[3]) {
+ TransData *td = t->data;
+ float tvec[3];
+ int i;
+
+ for(i = 0 ; i < t->total; i++, td++) {
+ if (td->flag & TD_NOACTION)
+ break;
+
+ if (t->con.applyVec) {
+ float pvec[3];
+ t->con.applyVec(t, td, vec, tvec, pvec);
+ }
+ else {
+ VECCOPY(tvec, vec);
+ }
+
+ Mat3MulVecfl(td->smtx, tvec);
+ VecMulf(tvec, td->factor);
+
+ protectedTransBits(td->protectflag, tvec);
+
+ /* transdata ipokey */
+ if(td->tdi) {
+ TransDataIpokey *tdi= td->tdi;
+ add_tdi_poin(tdi->locx, tdi->oldloc, tvec[0]);
+ add_tdi_poin(tdi->locy, tdi->oldloc+1, tvec[1]);
+ add_tdi_poin(tdi->locz, tdi->oldloc+2, tvec[2]);
+ }
+ else VecAddf(td->loc, td->iloc, tvec);
+ }
+}
+
+/* uses t->vec to store actual translation in */
+int Translation(TransInfo *t, short mval[2])
+{
+ float tvec[3];
+ char str[200];
+
+ if(t->flag & T_SHIFT_MOD) {
+ float dvec[3];
+ /* calculate the main translation and the precise one separate */
+ convertViewVec(t, dvec, (short)(mval[0] - t->shiftmval[0]), (short)(mval[1] - t->shiftmval[1]));
+ VecMulf(dvec, 0.1f);
+ convertViewVec(t, t->vec, (short)(t->shiftmval[0] - t->imval[0]), (short)(t->shiftmval[1] - t->imval[1]));
+ VecAddf(t->vec, t->vec, dvec);
+ }
+ else convertViewVec(t, t->vec, (short)(mval[0] - t->imval[0]), (short)(mval[1] - t->imval[1]));
+
+ if (t->con.mode & CON_APPLY) {
+ float pvec[3] = {0.0f, 0.0f, 0.0f};
+ applySnapping(t, t->vec);
+ t->con.applyVec(t, NULL, t->vec, tvec, pvec);
+ VECCOPY(t->vec, tvec);
+ headerTranslation(t, pvec, str);
+ }
+ else {
+ snapGrid(t, t->vec);
+ applyNumInput(&t->num, t->vec);
+ applySnapping(t, t->vec);
+ headerTranslation(t, t->vec, str);
+ }
+
+ applyTranslation(t, t->vec);
+
+ /* evil hack - redo translation if cliiping needeed */
+ if (t->flag & T_CLIP_UV && clipUVTransform(t, t->vec, 0))
+ applyTranslation(t, t->vec);
+
+ recalcData(t);
+
+ headerprint(str);
+
+ viewRedrawForce(t);
+
+ drawSnapping(t);
+
+ return 1;
+}
+
+/* ************************** SHRINK/FATTEN *************************** */
+
+void initShrinkFatten(TransInfo *t)
+{
+ // If not in mesh edit mode, fallback to Resize
+ if (G.obedit==NULL || G.obedit->type != OB_MESH) {
+ initResize(t);
+ }
+ else {
+ t->mode = TFM_SHRINKFATTEN;
+ t->transform = ShrinkFatten;
+
+ t->idx_max = 0;
+ t->num.idx_max = 0;
+ t->snap[0] = 0.0f;
+ t->snap[1] = 1.0f;
+ t->snap[2] = t->snap[1] * 0.1f;
+
+ t->flag |= T_NO_CONSTRAINT;
+ }
+}
+
+
+
+int ShrinkFatten(TransInfo *t, short mval[2])
+{
+ float vec[3];
+ float distance;
+ int i;
+ char str[64];
+ TransData *td = t->data;
+
+ distance = -InputVerticalAbsolute(t, mval);
+
+ snapGrid(t, &distance);
+
+ applyNumInput(&t->num, &distance);
+
+ /* header print for NumInput */
+ if (hasNumInput(&t->num)) {
+ char c[20];
+
+ outputNumInput(&(t->num), c);
+
+ sprintf(str, "Shrink/Fatten: %s %s", c, t->proptext);
+ }
+ else {
+ /* default header print */
+ sprintf(str, "Shrink/Fatten: %.4f %s", distance, t->proptext);
+ }
+
+
+ for(i = 0 ; i < t->total; i++, td++) {
+ if (td->flag & TD_NOACTION)
+ break;
+
+ VECCOPY(vec, td->axismtx[2]);
+ VecMulf(vec, distance);
+ VecMulf(vec, td->factor);
+
+ VecAddf(td->loc, td->iloc, vec);
+ }
+
+ recalcData(t);
+
+ headerprint(str);
+
+ viewRedrawForce(t);
+
+ return 1;
+}
+
+/* ************************** TILT *************************** */
+
+void initTilt(TransInfo *t)
+{
+ t->mode = TFM_TILT;
+ t->transform = Tilt;
+
+ t->idx_max = 0;
+ t->num.idx_max = 0;
+ t->snap[0] = 0.0f;
+ t->snap[1] = (float)((5.0/180)*M_PI);
+ t->snap[2] = t->snap[1] * 0.2f;
+ t->fac = 0;
+
+ t->flag |= T_NO_CONSTRAINT;
+}
+
+
+
+int Tilt(TransInfo *t, short mval[2])
+{
+ TransData *td = t->data;
+ int i;
+ char str[50];
+
+ float final;
+
+ int dx2 = t->center2d[0] - mval[0];
+ int dy2 = t->center2d[1] - mval[1];
+ float B = (float)sqrt(dx2*dx2+dy2*dy2);
+
+ int dx1 = t->center2d[0] - t->imval[0];
+ int dy1 = t->center2d[1] - t->imval[1];
+ float A = (float)sqrt(dx1*dx1+dy1*dy1);
+
+ int dx3 = mval[0] - t->imval[0];
+ int dy3 = mval[1] - t->imval[1];
+
+ float deler= ((dx1*dx1+dy1*dy1)+(dx2*dx2+dy2*dy2)-(dx3*dx3+dy3*dy3))
+ / (2 * A * B);
+
+ float dphi;
+
+ dphi = saacos(deler);
+ if( (dx1*dy2-dx2*dy1)>0.0 ) dphi= -dphi;
+
+ if(G.qual & LR_SHIFTKEY) t->fac += dphi/30.0f;
+ else t->fac += dphi;
+
+ final = t->fac;
+
+ snapGrid(t, &final);
+
+ t->imval[0] = mval[0];
+ t->imval[1] = mval[1];
+
+ if (hasNumInput(&t->num)) {
+ char c[20];
+
+ applyNumInput(&t->num, &final);
+
+ outputNumInput(&(t->num), c);
+
+ sprintf(str, "Tilt: %s %s", &c[0], t->proptext);
+
+ final *= (float)(M_PI / 180.0);
+ }
+ else {
+ sprintf(str, "Tilt: %.2f %s", 180.0*final/M_PI, t->proptext);
+ }
+
+ for(i = 0 ; i < t->total; i++, td++) {
+ if (td->flag & TD_NOACTION)
+ break;
+
+ if (td->val) {
+ *td->val = td->ival + final * td->factor;
+ }
+ }
+
+ recalcData(t);
+
+ headerprint(str);
+
+ viewRedrawForce(t);
+
+ helpline (t, t->center);
+
+ return 1;
+}
+
+
+/* ******************** Curve Shrink/Fatten *************** */
+
+int CurveShrinkFatten(TransInfo *t, short mval[2])
+{
+ TransData *td = t->data;
+ float ratio;
+ int i;
+ char str[50];
+
+ if(t->flag & T_SHIFT_MOD) {
+ /* calculate ratio for shiftkey pos, and for total, and blend these for precision */
+ float dx= (float)(t->center2d[0] - t->shiftmval[0]);
+ float dy= (float)(t->center2d[1] - t->shiftmval[1]);
+ ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
+
+ dx= (float)(t->center2d[0] - mval[0]);
+ dy= (float)(t->center2d[1] - mval[1]);
+ ratio+= 0.1f*(float)(sqrt( dx*dx + dy*dy)/t->fac -ratio);
+
+ }
+ else {
+ float dx= (float)(t->center2d[0] - mval[0]);
+ float dy= (float)(t->center2d[1] - mval[1]);
+ ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
+ }
+
+ snapGrid(t, &ratio);
+
+ applyNumInput(&t->num, &ratio);
+
+ /* header print for NumInput */
+ if (hasNumInput(&t->num)) {
+ char c[20];
+
+ outputNumInput(&(t->num), c);
+ sprintf(str, "Shrink/Fatten: %s", c);
+ }
+ else {
+ sprintf(str, "Shrink/Fatten: %3f", ratio);
+ }
+
+ for(i = 0 ; i < t->total; i++, td++) {
+ if (td->flag & TD_NOACTION)
+ break;
+
+ if(td->val) {
+ //*td->val= ratio;
+ *td->val= td->ival*ratio;
+ if (*td->val <= 0.0f) *td->val = 0.0001f;
+ }
+ }
+
+ recalcData(t);
+
+ headerprint(str);
+
+ viewRedrawForce(t);
+
+ if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
+
+ return 1;
+}
+
+void initCurveShrinkFatten(TransInfo *t)
+{
+ t->mode = TFM_CURVE_SHRINKFATTEN;
+ t->transform = CurveShrinkFatten;
+
+ t->idx_max = 0;
+ t->num.idx_max = 0;
+ t->snap[0] = 0.0f;
+ t->snap[1] = 0.1f;
+ t->snap[2] = t->snap[1] * 0.1f;
+
+ t->flag |= T_NO_CONSTRAINT;
+
+ t->fac = (float)sqrt( (
+ ((float)(t->center2d[1] - t->imval[1]))*((float)(t->center2d[1] - t->imval[1]))
+ +
+ ((float)(t->center2d[0] - t->imval[0]))*((float)(t->center2d[0] - t->imval[0]))
+ ) );
+}
+
+/* ************************** PUSH/PULL *************************** */
+
+void initPushPull(TransInfo *t)
+{
+ t->mode = TFM_PUSHPULL;
+ t->transform = PushPull;
+
+ t->idx_max = 0;
+ t->num.idx_max = 0;
+ t->snap[0] = 0.0f;
+ t->snap[1] = 1.0f;
+ t->snap[2] = t->snap[1] * 0.1f;
+}
+
+
+int PushPull(TransInfo *t, short mval[2])
+{
+ float vec[3], axis[3];
+ float distance;
+ int i;
+ char str[128];
+ TransData *td = t->data;
+
+ distance = InputVerticalAbsolute(t, mval);
+
+ snapGrid(t, &distance);
+
+ applyNumInput(&t->num, &distance);
+
+ /* header print for NumInput */
+ if (hasNumInput(&t->num)) {
+ char c[20];
+
+ outputNumInput(&(t->num), c);
+
+ sprintf(str, "Push/Pull: %s%s %s", c, t->con.text, t->proptext);
+ }
+ else {
+ /* default header print */
+ sprintf(str, "Push/Pull: %.4f%s %s", distance, t->con.text, t->proptext);
+ }
+
+ if (t->con.applyRot && t->con.mode & CON_APPLY) {
+ t->con.applyRot(t, NULL, axis);
+ }
+
+ for(i = 0 ; i < t->total; i++, td++) {
+ if (td->flag & TD_NOACTION)
+ break;
+
+ VecSubf(vec, t->center, td->center);
+ if (t->con.applyRot && t->con.mode & CON_APPLY) {
+ t->con.applyRot(t, td, axis);
+ if (isLockConstraint(t)) {
+ float dvec[3];
+ Projf(dvec, vec, axis);
+ VecSubf(vec, vec, dvec);
+ }
+ else {
+ Projf(vec, vec, axis);
+ }
+ }
+ Normalize(vec);
+ VecMulf(vec, distance);
+ VecMulf(vec, td->factor);
+
+ VecAddf(td->loc, td->iloc, vec);
+ }
+
+ recalcData(t);
+
+ headerprint(str);
+
+ viewRedrawForce(t);
+
+ return 1;
+}
+
+/* ************************** CREASE *************************** */
+
+void initCrease(TransInfo *t)
+{
+ t->mode = TFM_CREASE;
+ t->transform = Crease;
+
+ t->idx_max = 0;
+ t->num.idx_max = 0;
+ t->snap[0] = 0.0f;
+ t->snap[1] = 0.1f;
+ t->snap[2] = t->snap[1] * 0.1f;
+
+ t->flag |= T_NO_CONSTRAINT;
+
+ t->fac = (float)sqrt(
+ (
+ ((float)(t->center2d[1] - t->imval[1]))*((float)(t->center2d[1] - t->imval[1]))
+ +
+ ((float)(t->center2d[0] - t->imval[0]))*((float)(t->center2d[0] - t->imval[0]))
+ ) );
+
+ if(t->fac==0.0f) t->fac= 1.0f; // prevent Inf
+}
+
+int Crease(TransInfo *t, short mval[2])
+{
+ TransData *td = t->data;
+ float crease;
+ int i;
+ char str[50];
+
+
+ if(t->flag & T_SHIFT_MOD) {
+ /* calculate ratio for shiftkey pos, and for total, and blend these for precision */
+ float dx= (float)(t->center2d[0] - t->shiftmval[0]);
+ float dy= (float)(t->center2d[1] - t->shiftmval[1]);
+ crease = (float)sqrt( dx*dx + dy*dy)/t->fac;
+
+ dx= (float)(t->center2d[0] - mval[0]);
+ dy= (float)(t->center2d[1] - mval[1]);
+ crease+= 0.1f*(float)(sqrt( dx*dx + dy*dy)/t->fac -crease);
+
+ }
+ else {
+ float dx= (float)(t->center2d[0] - mval[0]);
+ float dy= (float)(t->center2d[1] - mval[1]);
+ crease = (float)sqrt( dx*dx + dy*dy)/t->fac;
+ }
+
+ crease -= 1.0f;
+ if (crease > 1.0f) crease = 1.0f;
+
+ snapGrid(t, &crease);
+
+ applyNumInput(&t->num, &crease);
+
+ /* header print for NumInput */
+ if (hasNumInput(&t->num)) {
+ char c[20];
+
+ outputNumInput(&(t->num), c);
+
+ if (crease >= 0.0f)
+ sprintf(str, "Crease: +%s %s", c, t->proptext);
+ else
+ sprintf(str, "Crease: %s %s", c, t->proptext);
+ }
+ else {
+ /* default header print */
+ if (crease >= 0.0f)
+ sprintf(str, "Crease: +%.3f %s", crease, t->proptext);
+ else
+ sprintf(str, "Crease: %.3f %s", crease, t->proptext);
+ }
+
+ for(i = 0 ; i < t->total; i++, td++) {
+ if (td->flag & TD_NOACTION)
+ break;
+
+ if (td->val) {
+ *td->val = td->ival + crease * td->factor;
+ if (*td->val < 0.0f) *td->val = 0.0f;
+ if (*td->val > 1.0f) *td->val = 1.0f;
+ }
+ }
+
+ recalcData(t);
+
+ headerprint(str);
+
+ viewRedrawForce(t);
+
+ helpline (t, t->center);
+
+ return 1;
+}
+
+/* ******************** EditBone (B-bone) width scaling *************** */
+
+void initBoneSize(TransInfo *t)
+{
+ t->mode = TFM_BONESIZE;
+ t->transform = BoneSize;
+
+ t->idx_max = 2;
+ t->num.idx_max = 2;
+ t->num.flag |= NUM_NULL_ONE;
+ t->snap[0] = 0.0f;
+ t->snap[1] = 0.1f;
+ t->snap[2] = t->snap[1] * 0.1f;
+
+ t->fac = (float)sqrt( (
+ ((float)(t->center2d[1] - t->imval[1]))*((float)(t->center2d[1] - t->imval[1]))
+ +
+ ((float)(t->center2d[0] - t->imval[0]))*((float)(t->center2d[0] - t->imval[0]))
+ ) );
+
+ if(t->fac==0.0f) t->fac= 1.0f; // prevent Inf
+}
+
+static void headerBoneSize(TransInfo *t, float vec[3], char *str) {
+ char tvec[60];
+ if (hasNumInput(&t->num)) {
+ outputNumInput(&(t->num), tvec);
+ }
+ else {
+ sprintf(&tvec[0], "%.4f", vec[0]);
+ sprintf(&tvec[20], "%.4f", vec[1]);
+ sprintf(&tvec[40], "%.4f", vec[2]);
+ }
+
+ /* hmm... perhaps the y-axis values don't need to be shown? */
+ if (t->con.mode & CON_APPLY) {
+ if (t->num.idx_max == 0)
+ sprintf(str, "ScaleB: %s%s %s", &tvec[0], t->con.text, t->proptext);
+ else
+ sprintf(str, "ScaleB: %s : %s : %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
+ }
+ else {
+ sprintf(str, "ScaleB X: %s Y: %s Z: %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
+ }
+}
+
+static void ElementBoneSize(TransInfo *t, TransData *td, float mat[3][3])
+{
+ float tmat[3][3], smat[3][3], oldy;
+ float sizemat[3][3];
+
+ Mat3MulMat3(smat, mat, td->mtx);
+ Mat3MulMat3(tmat, td->smtx, smat);
+
+ if (t->con.applySize) {
+ t->con.applySize(t, td, tmat);
+ }
+
+ /* we've tucked the scale in loc */
+ oldy= td->iloc[1];
+ SizeToMat3(td->iloc, sizemat);
+ Mat3MulMat3(tmat, tmat, sizemat);
+ Mat3ToSize(tmat, td->loc);
+ td->loc[1]= oldy;
+}
+
+int BoneSize(TransInfo *t, short mval[2])
+{
+ TransData *td = t->data;
+ float size[3], mat[3][3];
+ float ratio;
+ int i;
+ char str[60];
+
+ /* for manipulator, center handle, the scaling can't be done relative to center */
+ if( (t->flag & T_USES_MANIPULATOR) && t->con.mode==0) {
+ ratio = 1.0f - ((t->imval[0] - mval[0]) + (t->imval[1] - mval[1]))/100.0f;
+ }
+ else {
+
+ if(t->flag & T_SHIFT_MOD) {
+ /* calculate ratio for shiftkey pos, and for total, and blend these for precision */
+ float dx= (float)(t->center2d[0] - t->shiftmval[0]);
+ float dy= (float)(t->center2d[1] - t->shiftmval[1]);
+ ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
+
+ dx= (float)(t->center2d[0] - mval[0]);
+ dy= (float)(t->center2d[1] - mval[1]);
+ ratio+= 0.1f*(float)(sqrt( dx*dx + dy*dy)/t->fac -ratio);
+
+ }
+ else {
+ float dx= (float)(t->center2d[0] - mval[0]);
+ float dy= (float)(t->center2d[1] - mval[1]);
+ ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
+ }
+
+ /* flip scale, but not for manipulator center handle */
+ if ((t->center2d[0] - mval[0]) * (t->center2d[0] - t->imval[0]) +
+ (t->center2d[1] - mval[1]) * (t->center2d[1] - t->imval[1]) < 0)
+ ratio *= -1.0f;
+ }
+
+ size[0] = size[1] = size[2] = ratio;
+
+ snapGrid(t, size);
+
+ if (hasNumInput(&t->num)) {
+ applyNumInput(&t->num, size);
+ constraintNumInput(t, size);
+ }
+
+ SizeToMat3(size, mat);
+
+ if (t->con.applySize) {
+ t->con.applySize(t, NULL, mat);
+ }
+
+ Mat3CpyMat3(t->mat, mat); // used in manipulator
+
+ headerBoneSize(t, size, str);
+
+ for(i = 0 ; i < t->total; i++, td++) {
+ if (td->flag & TD_NOACTION)
+ break;
+
+ ElementBoneSize(t, td, mat);
+ }
+
+ recalcData(t);
+
+ headerprint(str);
+
+ viewRedrawForce(t);
+
+ if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
+
+ return 1;
+}
+
+
+/* ******************** EditBone envelope *************** */
+
+void initBoneEnvelope(TransInfo *t)
+{
+ t->mode = TFM_BONE_ENVELOPE;
+ t->transform = BoneEnvelope;
+
+ t->idx_max = 0;
+ t->num.idx_max = 0;
+ t->snap[0] = 0.0f;
+ t->snap[1] = 0.1f;
+ t->snap[2] = t->snap[1] * 0.1f;
+
+ t->flag |= T_NO_CONSTRAINT;
+
+ t->fac = (float)sqrt( (
+ ((float)(t->center2d[1] - t->imval[1]))*((float)(t->center2d[1] - t->imval[1]))
+ +
+ ((float)(t->center2d[0] - t->imval[0]))*((float)(t->center2d[0] - t->imval[0]))
+ ) );
+
+ if(t->fac==0.0f) t->fac= 1.0f; // prevent Inf
+}
+
+int BoneEnvelope(TransInfo *t, short mval[2])
+{
+ TransData *td = t->data;
+ float ratio;
+ int i;
+ char str[50];
+
+ if(t->flag & T_SHIFT_MOD) {
+ /* calculate ratio for shiftkey pos, and for total, and blend these for precision */
+ float dx= (float)(t->center2d[0] - t->shiftmval[0]);
+ float dy= (float)(t->center2d[1] - t->shiftmval[1]);
+ ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
+
+ dx= (float)(t->center2d[0] - mval[0]);
+ dy= (float)(t->center2d[1] - mval[1]);
+ ratio+= 0.1f*(float)(sqrt( dx*dx + dy*dy)/t->fac -ratio);
+
+ }
+ else {
+ float dx= (float)(t->center2d[0] - mval[0]);
+ float dy= (float)(t->center2d[1] - mval[1]);
+ ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
+ }
+
+ snapGrid(t, &ratio);
+
+ applyNumInput(&t->num, &ratio);
+
+ /* header print for NumInput */
+ if (hasNumInput(&t->num)) {
+ char c[20];
+
+ outputNumInput(&(t->num), c);
+ sprintf(str, "Envelope: %s", c);
+ }
+ else {
+ sprintf(str, "Envelope: %3f", ratio);
+ }
+
+ for(i = 0 ; i < t->total; i++, td++) {
+ if (td->flag & TD_NOACTION)
+ break;
+
+ if (td->val) {
+ /* if the old/original value was 0.0f, then just use ratio */
+ if (td->ival)
+ *td->val= td->ival*ratio;
+ else
+ *td->val= ratio;
+ }
+ }
+
+ recalcData(t);
+
+ headerprint(str);
+
+ force_draw(0);
+
+ if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
+
+ return 1;
+}
+
+
+/* ******************** EditBone roll *************** */
+
+void initBoneRoll(TransInfo *t)
+{
+ t->mode = TFM_BONE_ROLL;
+ t->transform = BoneRoll;
+
+ t->idx_max = 0;
+ t->num.idx_max = 0;
+ t->snap[0] = 0.0f;
+ t->snap[1] = (float)((5.0/180)*M_PI);
+ t->snap[2] = t->snap[1] * 0.2f;
+
+ t->fac = 0.0f;
+
+ t->flag |= T_NO_CONSTRAINT;
+}
+
+int BoneRoll(TransInfo *t, short mval[2])
+{
+ TransData *td = t->data;
+ int i;
+ char str[50];
+
+ float final;
+
+ int dx2 = t->center2d[0] - mval[0];
+ int dy2 = t->center2d[1] - mval[1];
+ double B = sqrt(dx2*dx2+dy2*dy2);
+
+ int dx1 = t->center2d[0] - t->imval[0];
+ int dy1 = t->center2d[1] - t->imval[1];
+ double A = sqrt(dx1*dx1+dy1*dy1);
+
+ int dx3 = mval[0] - t->imval[0];
+ int dy3 = mval[1] - t->imval[1];
+ /* use doubles here, to make sure a "1.0" (no rotation) doesnt become 9.999999e-01, which gives 0.02 for acos */
+ double deler= ((double)((dx1*dx1+dy1*dy1)+(dx2*dx2+dy2*dy2)-(dx3*dx3+dy3*dy3) ))
+ / (2.0 * (A*B?A*B:1.0));
+ /* (A*B?A*B:1.0f) this takes care of potential divide by zero errors */
+
+ float dphi;
+
+ dphi = saacos((float)deler);
+ if( (dx1*dy2-dx2*dy1)>0.0 ) dphi= -dphi;
+
+ if(G.qual & LR_SHIFTKEY) t->fac += dphi/30.0f;
+ else t->fac += dphi;
+
+ final = t->fac;
+
+ snapGrid(t, &final);
+
+ t->imval[0] = mval[0];
+ t->imval[1] = mval[1];
+
+ if (hasNumInput(&t->num)) {
+ char c[20];
+
+ applyNumInput(&t->num, &final);
+
+ outputNumInput(&(t->num), c);
+
+ sprintf(str, "Roll: %s", &c[0]);
+
+ final *= (float)(M_PI / 180.0);
+ }
+ else {
+ sprintf(str, "Roll: %.2f", 180.0*final/M_PI);
+ }
+
+ /* set roll values */
+ for (i = 0; i < t->total; i++, td++) {
+ if (td->flag & TD_NOACTION)
+ break;
+
+ *(td->val) = td->ival - final;
+ }
+
+ recalcData(t);
+
+ headerprint(str);
+
+ viewRedrawForce(t);
+
+ if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
+
+ return 1;
+}
+
+/* ************************** MIRROR *************************** */
+
+void Mirror(short mode)
+{
+ TransData *td;
+ float mati[3][3], matview[3][3], mat[3][3];
+ float size[3];
+ int i;
+
+ Trans.context = CTX_NO_PET;
+
+ initTrans(&Trans); // internal data, mouse, vectors
+
+ Mat3One(mati);
+ Mat3CpyMat4(matview, Trans.viewinv); // t->viewinv was set in initTrans
+ Mat3Ortho(matview);
+
+ createTransData(&Trans); // make TransData structs from selection
+
+ calculatePropRatio(&Trans);
+ calculateCenter(&Trans);
+
+ initResize(&Trans);
+
+ if (Trans.total == 0) {
+ postTrans(&Trans);
+ return;
+ }
+
+ size[0] = size[1] = size[2] = 1.0f;
+ td = Trans.data;
+
+ switch (mode) {
+ case 1:
+ size[0] = -1.0f;
+ setConstraint(&Trans, mati, (CON_AXIS0), "");
+ break;
+ case 2:
+ size[1] = -1.0f;
+ setConstraint(&Trans, mati, (CON_AXIS1), "");
+ break;
+ case 3:
+ size[2] = -1.0f;
+ setConstraint(&Trans, mati, (CON_AXIS2), "");
+ break;
+ case 4:
+ size[0] = -1.0f;
+ setLocalConstraint(&Trans, (CON_AXIS0), "");
+ break;
+ case 5:
+ size[1] = -1.0f;
+ setLocalConstraint(&Trans, (CON_AXIS1), "");
+ break;
+ case 6:
+ size[2] = -1.0f;
+ setLocalConstraint(&Trans, (CON_AXIS2), "");
+ break;
+ case 7:
+ size[0] = -1.0f;
+ setConstraint(&Trans, matview, (CON_AXIS0), "");
+ break;
+ case 8:
+ size[1] = -1.0f;
+ setConstraint(&Trans, matview, (CON_AXIS1), "");
+ break;
+ case 9:
+ size[2] = -1.0f;
+ setConstraint(&Trans, matview, (CON_AXIS2), "");
+ break;
+ default:
+ return;
+ }
+
+ SizeToMat3(size, mat);
+
+ if (Trans.con.applySize) {
+ Trans.con.applySize(&Trans, NULL, mat);
+ }
+
+ for(i = 0 ; i < Trans.total; i++, td++) {
+ if (td->flag & TD_NOACTION)
+ break;
+
+ ElementResize(&Trans, td, mat);
+ }
+
+ recalcData(&Trans);
+
+ BIF_undo_push("Mirror");
+
+ /* free data, reset vars */
+ postTrans(&Trans);
+
+ /* send events out for redraws */
+ viewRedrawPost(&Trans);
+}
+
+/* ************************** ANIM EDITORS - TRANSFORM TOOLS *************************** */
+
+/* ---------------- Special Helpers for Various Settings ------------- */
+
+/* This function returns the snapping 'mode' for Animation Editors only
+ * We cannot use the standard snapping due to NLA-strip scaling complexities.
+ */
+static short getAnimEdit_SnapMode(TransInfo *t)
+{
+ short autosnap= SACTSNAP_OFF;
+
+ /* currently, some of these are only for the action editor */
+ if (t->spacetype == SPACE_ACTION && G.saction) {
+ switch (G.saction->autosnap) {
+ case SACTSNAP_OFF:
+ if (G.qual == LR_CTRLKEY)
+ autosnap= SACTSNAP_STEP;
+ else if (G.qual == LR_SHIFTKEY)
+ autosnap= SACTSNAP_FRAME;
+ else if (G.qual == LR_ALTKEY)
+ autosnap= SACTSNAP_MARKER;
+ else
+ autosnap= SACTSNAP_OFF;
+ break;
+ case SACTSNAP_STEP:
+ autosnap= (G.qual==LR_CTRLKEY)? SACTSNAP_OFF: SACTSNAP_STEP;
+ break;
+ case SACTSNAP_FRAME:
+ autosnap= (G.qual==LR_SHIFTKEY)? SACTSNAP_OFF: SACTSNAP_FRAME;
+ break;
+ case SACTSNAP_MARKER:
+ autosnap= (G.qual==LR_ALTKEY)? SACTSNAP_OFF: SACTSNAP_MARKER;
+ break;
+ }
+ }
+ else if (t->spacetype == SPACE_NLA && G.snla) {
+ switch (G.snla->autosnap) {
+ case SACTSNAP_OFF:
+ if (G.qual == LR_CTRLKEY)
+ autosnap= SACTSNAP_STEP;
+ else if (G.qual == LR_SHIFTKEY)
+ autosnap= SACTSNAP_FRAME;
+ else if (G.qual == LR_ALTKEY)
+ autosnap= SACTSNAP_MARKER;
+ else
+ autosnap= SACTSNAP_OFF;
+ break;
+ case SACTSNAP_STEP:
+ autosnap= (G.qual==LR_CTRLKEY)? SACTSNAP_OFF: SACTSNAP_STEP;
+ break;
+ case SACTSNAP_FRAME:
+ autosnap= (G.qual==LR_SHIFTKEY)? SACTSNAP_OFF: SACTSNAP_FRAME;
+ break;
+ case SACTSNAP_MARKER:
+ autosnap= (G.qual==LR_ALTKEY)? SACTSNAP_OFF: SACTSNAP_MARKER;
+ break;
+ }
+ }
+ else {
+ if (G.qual == LR_CTRLKEY)
+ autosnap= SACTSNAP_STEP;
+ else if (G.qual == LR_SHIFTKEY)
+ autosnap= SACTSNAP_FRAME;
+ else if (G.qual == LR_ALTKEY)
+ autosnap= SACTSNAP_MARKER;
+ else
+ autosnap= SACTSNAP_OFF;
+ }
+
+ return autosnap;
+}
+
+/* This function is used for testing if an Animation Editor is displaying
+ * its data in frames or seconds (and the data needing to be edited as such).
+ * Returns 1 if in seconds, 0 if in frames
+ */
+static short getAnimEdit_DrawTime(TransInfo *t)
+{
+ short drawtime;
+
+ /* currently, some of these are only for the action editor */
+ if (t->spacetype == SPACE_ACTION && G.saction) {
+ drawtime = (G.saction->flag & SACTION_DRAWTIME)? 1 : 0;
+ }
+ else if (t->spacetype == SPACE_NLA && G.snla) {
+ drawtime = (G.snla->flag & SNLA_DRAWTIME)? 1 : 0;
+ }
+ else {
+ drawtime = 0;
+ }
+
+ return drawtime;
+}
+
+
+/* This function is used by Animation Editor specific transform functions to do
+ * the Snap Keyframe to Nearest Frame/Marker
+ */
+static void doAnimEdit_SnapFrame(TransInfo *t, TransData *td, Object *ob, short autosnap)
+{
+ /* snap key to nearest frame? */
+ if (autosnap == SACTSNAP_FRAME) {
+ short doTime= getAnimEdit_DrawTime(t);
+ double secf= FPS;
+ float val;
+
+ /* convert frame to nla-action time (if needed) */
+ if (ob)
+ val= get_action_frame_inv(ob, *(td->val));
+ else
+ val= *(td->val);
+
+ /* do the snapping to nearest frame/second */
+ if (doTime)
+ val= (float)( floor((val/secf) + 0.5f) * secf );
+ else
+ val= (float)( floor(val+0.5f) );
+
+ /* convert frame out of nla-action time */
+ if (ob)
+ *(td->val)= get_action_frame(ob, val);
+ else
+ *(td->val)= val;
+ }
+ /* snap key to nearest marker? */
+ else if (autosnap == SACTSNAP_MARKER) {
+ float val;
+
+ /* convert frame to nla-action time (if needed) */
+ if (ob)
+ val= get_action_frame_inv(ob, *(td->val));
+ else
+ val= *(td->val);
+
+ /* snap to nearest marker */
+ val= (float)find_nearest_marker_time(val);
+
+ /* convert frame out of nla-action time */
+ if (ob)
+ *(td->val)= get_action_frame(ob, val);
+ else
+ *(td->val)= val;
+ }
+}
+
+/* ----------------- Translation ----------------------- */
+
+void initTimeTranslate(TransInfo *t)
+{
+ t->mode = TFM_TIME_TRANSLATE;
+ t->transform = TimeTranslate;
+
+ /* num-input has max of (n-1) */
+ t->idx_max = 0;
+ t->num.flag = 0;
+ t->num.idx_max = t->idx_max;
+
+ /* initialise snap like for everything else */
+ t->snap[0] = 0.0f;
+ t->snap[1] = t->snap[2] = 1.0f;
+}
+
+static void headerTimeTranslate(TransInfo *t, char *str)
+{
+ char tvec[60];
+
+ /* if numeric input is active, use results from that, otherwise apply snapping to result */
+ if (hasNumInput(&t->num)) {
+ outputNumInput(&(t->num), tvec);
+ }
+ else {
+ short autosnap= getAnimEdit_SnapMode(t);
+ short doTime = getAnimEdit_DrawTime(t);
+ double secf= FPS;
+ float val= t->fac;
+
+ /* take into account scaling (for Action Editor only) */
+ if ((t->spacetype == SPACE_ACTION) && (NLA_ACTION_SCALED)) {
+ float cval, sval[2];
+
+ /* recalculate the delta based on 'visual' times */
+ areamouseco_to_ipoco(G.v2d, t->imval, &sval[0], &sval[1]);
+ cval= sval[0] + t->fac;
+
+ val = get_action_frame_inv(OBACT, cval);
+ val -= get_action_frame_inv(OBACT, sval[0]);
+ }
+
+ /* apply snapping + frame->seconds conversions */
+ if (autosnap == SACTSNAP_STEP) {
+ if (doTime)
+ val= floor(val/secf + 0.5f);
+ else
+ val= floor(val + 0.5f);
+ }
+ else {
+ if (doTime)
+ val= val / secf;
+ }
+
+ sprintf(&tvec[0], "%.4f", val);
+ }
+
+ sprintf(str, "DeltaX: %s", &tvec[0]);
+}
+
+static void applyTimeTranslate(TransInfo *t, float sval)
+{
+ TransData *td = t->data;
+ int i;
+
+ short doTime= getAnimEdit_DrawTime(t);
+ double secf= FPS;
+
+ short autosnap= getAnimEdit_SnapMode(t);
+ float cval= sval + t->fac;
+
+ float deltax, val;
+
+ /* it doesn't matter whether we apply to t->data or t->data2d, but t->data2d is more convenient */
+ for (i = 0 ; i < t->total; i++, td++) {
+ /* it is assumed that td->ob is a pointer to the object,
+ * whose active action is where this keyframe comes from
+ */
+ Object *ob= td->ob;
+
+ /* check if any need to apply nla-scaling */
+ if (ob) {
+ deltax = get_action_frame_inv(ob, cval);
+ deltax -= get_action_frame_inv(ob, sval);
+
+ if (autosnap == SACTSNAP_STEP) {
+ if (doTime)
+ deltax= (float)( floor((deltax/secf) + 0.5f) * secf );
+ else
+ deltax= (float)( floor(deltax + 0.5f) );
+ }
+
+ val = get_action_frame_inv(ob, td->ival);
+ val += deltax;
+ *(td->val) = get_action_frame(ob, val);
+ }
+ else {
+ deltax = val = t->fac;
+
+ if (autosnap == SACTSNAP_STEP) {
+ if (doTime)
+ val= (float)( floor((deltax/secf) + 0.5f) * secf );
+ else
+ val= (float)( floor(val + 0.5f) );
+ }
+
+ *(td->val) = td->ival + val;
+ }
+
+ /* apply nearest snapping */
+ doAnimEdit_SnapFrame(t, td, ob, autosnap);
+ }
+}
+
+int TimeTranslate(TransInfo *t, short mval[2])
+{
+ float cval[2], sval[2];
+ char str[200];
+
+ /* calculate translation amount from mouse movement - in 'time-grid space' */
+ areamouseco_to_ipoco(G.v2d, mval, &cval[0], &cval[1]);
+ areamouseco_to_ipoco(G.v2d, t->imval, &sval[0], &sval[1]);
+
+ /* we only need to calculate effect for time (applyTimeTranslate only needs that) */
+ t->fac= cval[0] - sval[0];
+
+ /* handle numeric-input stuff */
+ t->vec[0] = t->fac;
+ applyNumInput(&t->num, &t->vec[0]);
+ t->fac = t->vec[0];
+ headerTimeTranslate(t, str);
+
+ applyTimeTranslate(t, sval[0]);
+
+ recalcData(t);
+
+ headerprint(str);
+
+ viewRedrawForce(t);
+
+ return 1;
+}
+
+/* ----------------- Time Slide ----------------------- */
+
+void initTimeSlide(TransInfo *t)
+{
+ /* this tool is only really available in the Action Editor... */
+ if (t->spacetype == SPACE_ACTION) {
+ /* set flag for drawing stuff*/
+ G.saction->flag |= SACTION_MOVING;
+ }
+
+ t->mode = TFM_TIME_SLIDE;
+ t->transform = TimeSlide;
+ t->flag |= T_FREE_CUSTOMDATA;
+
+ /* num-input has max of (n-1) */
+ t->idx_max = 0;
+ t->num.flag = 0;
+ t->num.idx_max = t->idx_max;
+
+ /* initialise snap like for everything else */
+ t->snap[0] = 0.0f;
+ t->snap[1] = t->snap[2] = 1.0f;
+}
+
+static void headerTimeSlide(TransInfo *t, float sval, char *str)
+{
+ char tvec[60];
+
+ if (hasNumInput(&t->num)) {
+ outputNumInput(&(t->num), tvec);
+ }
+ else {
+ float minx= *((float *)(t->customData));
+ float maxx= *((float *)(t->customData) + 1);
+ float cval= t->fac;
+ float val;
+
+ val= 2.0*(cval-sval) / (maxx-minx);
+ CLAMP(val, -1.0f, 1.0f);
+
+ sprintf(&tvec[0], "%.4f", val);
+ }
+
+ sprintf(str, "TimeSlide: %s", &tvec[0]);
+}
+
+static void applyTimeSlide(TransInfo *t, float sval)
+{
+ TransData *td = t->data;
+ int i;
+
+ float minx= *((float *)(t->customData));
+ float maxx= *((float *)(t->customData) + 1);
+
+ /* set value for drawing black line */
+ if (t->spacetype == SPACE_ACTION) {
+ G.saction->timeslide= t->fac;
+
+ if (NLA_ACTION_SCALED)
+ sval= get_action_frame(OBACT, sval);
+ }
+
+ /* it doesn't matter whether we apply to t->data or t->data2d, but t->data2d is more convenient */
+ for (i = 0 ; i < t->total; i++, td++) {
+ /* it is assumed that td->ob is a pointer to the object,
+ * whose active action is where this keyframe comes from
+ */
+ Object *ob= td->ob;
+ float cval = t->fac;
+
+ /* apply scaling to necessary values */
+ if (ob)
+ cval= get_action_frame(ob, cval);
+
+ /* only apply to data if in range */
+ if (sval > minx && sval < maxx) {
+ float cvalc= CLAMPIS(cval, minx, maxx);
+ float timefac;
+
+ /* left half? */
+ if (td->ival < sval) {
+ timefac= (sval - td->ival) / (sval - minx);
+ *(td->val)= cvalc - timefac * (cvalc - minx);
+ }
+ else {
+ timefac= (td->ival - sval) / (maxx - sval);
+ *(td->val)= cvalc + timefac * (maxx - cvalc);
+ }
+ }
+ }
+}
+
+int TimeSlide(TransInfo *t, short mval[2])
+{
+ float cval[2], sval[2];
+ char str[200];
+
+ /* calculate mouse co-ordinates */
+ areamouseco_to_ipoco(G.v2d, mval, &cval[0], &cval[1]);
+ areamouseco_to_ipoco(G.v2d, t->imval, &sval[0], &sval[1]);
+
+ /* calculate fake value to work with */
+ t->fac= cval[0];
+
+ /* handle numeric-input stuff */
+ t->vec[0] = t->fac;
+ applyNumInput(&t->num, &t->vec[0]);
+ t->fac = t->vec[0];
+ headerTimeSlide(t, sval[0], str);
+
+ applyTimeSlide(t, sval[0]);
+
+ recalcData(t);
+
+ headerprint(str);
+
+ viewRedrawForce(t);
+
+ return 1;
+}
+
+/* ----------------- Scaling ----------------------- */
+
+void initTimeScale(TransInfo *t)
+{
+ t->mode = TFM_TIME_SCALE;
+ t->transform = TimeScale;
+
+ t->flag |= T_NULL_ONE;
+ t->num.flag |= NUM_NULL_ONE;
+
+ /* num-input has max of (n-1) */
+ t->idx_max = 0;
+ t->num.flag = 0;
+ t->num.idx_max = t->idx_max;
+
+ /* initialise snap like for everything else */
+ t->snap[0] = 0.0f;
+ t->snap[1] = t->snap[2] = 1.0f;
+}
+
+static void headerTimeScale(TransInfo *t, char *str) {
+ char tvec[60];
+
+ if (hasNumInput(&t->num))
+ outputNumInput(&(t->num), tvec);
+ else
+ sprintf(&tvec[0], "%.4f", t->fac);
+
+ sprintf(str, "ScaleX: %s", &tvec[0]);
+}
+
+static void applyTimeScale(TransInfo *t) {
+ TransData *td = t->data;
+ int i;
+
+ short autosnap= getAnimEdit_SnapMode(t);
+ short doTime= getAnimEdit_DrawTime(t);
+ double secf= FPS;
+
+
+ for (i = 0 ; i < t->total; i++, td++) {
+ /* it is assumed that td->ob is a pointer to the object,
+ * whose active action is where this keyframe comes from
+ */
+ Object *ob= td->ob;
+ float startx= CFRA;
+ float fac= t->fac;
+
+ if (autosnap == SACTSNAP_STEP) {
+ if (doTime)
+ fac= (float)( floor(fac/secf + 0.5f) * secf );
+ else
+ fac= (float)( floor(fac + 0.5f) );
+ }
+
+ /* check if any need to apply nla-scaling */
+ if (ob)
+ startx= get_action_frame(ob, startx);
+
+ /* now, calculate the new value */
+ *(td->val) = td->ival - startx;
+ *(td->val) *= fac;
+ *(td->val) += startx;
+
+ /* apply nearest snapping */
+ doAnimEdit_SnapFrame(t, td, ob, autosnap);
+ }
+}
+
+int TimeScale(TransInfo *t, short mval[2])
+{
+ float cval, sval;
+ float deltax, startx;
+ float width= 0.0f;
+ char str[200];
+
+ sval= t->imval[0];
+ cval= mval[0];
+
+ switch (t->spacetype) {
+ case SPACE_ACTION:
+ width= ACTWIDTH;
+ break;
+ case SPACE_NLA:
+ width= NLAWIDTH;
+ break;
+ }
+
+ /* calculate scaling factor */
+ startx= sval-(width/2+(curarea->winrct.xmax-curarea->winrct.xmin)/2);
+ deltax= cval-(width/2+(curarea->winrct.xmax-curarea->winrct.xmin)/2);
+ t->fac = deltax / startx;
+
+ /* handle numeric-input stuff */
+ t->vec[0] = t->fac;
+ applyNumInput(&t->num, &t->vec[0]);
+ t->fac = t->vec[0];
+ headerTimeScale(t, str);
+
+ applyTimeScale(t);
+
+ recalcData(t);
+
+ headerprint(str);
+
+ viewRedrawForce(t);
+
+ return 1;
+}
+
+/* ************************************ */
+
+void BIF_TransformSetUndo(char *str)
+{
+ Trans.undostr= str;
+}
+
+
diff --git a/source/blender/src/transform_constraints.c b/source/blender/src/transform_constraints.c
new file mode 100644
index 00000000000..ad48d3cc919
--- /dev/null
+++ b/source/blender/src/transform_constraints.c
@@ -0,0 +1,1027 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef WIN32
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_action_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_effect_types.h"
+#include "DNA_image_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_key_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BIF_screen.h"
+#include "BIF_resources.h"
+#include "BIF_mywindow.h"
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+#include "BKE_global.h"
+#include "BKE_utildefines.h"
+
+#include "BSE_view.h"
+
+#include "BLI_arithb.h"
+
+#include "BDR_drawobject.h" /* drawcircball */
+
+#include "blendef.h"
+
+#include "mydevice.h"
+
+#include "transform.h"
+
+static void drawObjectConstraint(TransInfo *t);
+
+/* ************************** CONSTRAINTS ************************* */
+void constraintNumInput(TransInfo *t, float vec[3])
+{
+ int mode = t->con.mode;
+ if (mode & CON_APPLY) {
+ float nval = (t->flag & T_NULL_ONE)?1.0f:0.0f;
+
+ if (getConstraintSpaceDimension(t) == 2) {
+ int axis = mode & (CON_AXIS0|CON_AXIS1|CON_AXIS2);
+ if (axis == (CON_AXIS0|CON_AXIS1)) {
+ vec[2] = nval;
+ }
+ else if (axis == (CON_AXIS1|CON_AXIS2)) {
+ vec[2] = vec[1];
+ vec[1] = vec[0];
+ vec[0] = nval;
+ }
+ else if (axis == (CON_AXIS0|CON_AXIS2)) {
+ vec[2] = vec[1];
+ vec[1] = nval;
+ }
+ }
+ else if (getConstraintSpaceDimension(t) == 1) {
+ if (mode & CON_AXIS0) {
+ vec[1] = nval;
+ vec[2] = nval;
+ }
+ else if (mode & CON_AXIS1) {
+ vec[1] = vec[0];
+ vec[0] = nval;
+ vec[2] = nval;
+ }
+ else if (mode & CON_AXIS2) {
+ vec[2] = vec[0];
+ vec[0] = nval;
+ vec[1] = nval;
+ }
+ }
+ }
+}
+
+static void postConstraintChecks(TransInfo *t, float vec[3], float pvec[3]) {
+ int i = 0;
+
+ Mat3MulVecfl(t->con.imtx, vec);
+
+ snapGrid(t, vec);
+
+ if (t->num.flag & T_NULL_ONE) {
+ if (!(t->con.mode & CON_AXIS0))
+ vec[0] = 1.0f;
+
+ if (!(t->con.mode & CON_AXIS1))
+ vec[1] = 1.0f;
+
+ if (!(t->con.mode & CON_AXIS2))
+ vec[2] = 1.0f;
+ }
+
+ if (hasNumInput(&t->num)) {
+ applyNumInput(&t->num, vec);
+ constraintNumInput(t, vec);
+ }
+
+ if (t->con.mode & CON_AXIS0) {
+ pvec[i++] = vec[0];
+ }
+ if (t->con.mode & CON_AXIS1) {
+ pvec[i++] = vec[1];
+ }
+ if (t->con.mode & CON_AXIS2) {
+ pvec[i++] = vec[2];
+ }
+
+ Mat3MulVecfl(t->con.mtx, vec);
+}
+
+static void axisProjection(TransInfo *t, float axis[3], float in[3], float out[3]) {
+ float norm[3], vec[3], factor;
+
+ if(in[0]==0.0f && in[1]==0.0f && in[2]==0.0f)
+ return;
+
+ /* For when view is parallel to constraint... will cause NaNs otherwise
+ So we take vertical motion in 3D space and apply it to the
+ constraint axis. Nice for camera grab + MMB */
+ if(1.0f - fabs(Inpf(axis, t->viewinv[2])) < 0.000001f) {
+ Projf(vec, in, t->viewinv[1]);
+ factor = Inpf(t->viewinv[1], vec) * 2.0f;
+ /* since camera distance is quite relative, use quadratic relationship. holding shift can compensate */
+ if(factor<0.0f) factor*= -factor;
+ else factor*= factor;
+
+ VECCOPY(out, axis);
+ Normalize(out);
+ VecMulf(out, -factor); /* -factor makes move down going backwards */
+ }
+ else {
+ float cb[3], ab[3];
+
+ VECCOPY(out, axis);
+
+ /* Get view vector on axis to define a plane */
+ VecAddf(vec, t->con.center, in);
+ getViewVector(vec, norm);
+
+ Crossf(vec, norm, axis);
+
+ /* Project input vector on the plane passing on axis */
+ Projf(vec, in, vec);
+ VecSubf(vec, in, vec);
+
+ /* intersect the two lines: axis and norm */
+ Crossf(cb, vec, norm);
+ Crossf(ab, axis, norm);
+
+ VecMulf(out, Inpf(cb, ab) / Inpf(ab, ab));
+ }
+}
+
+static void planeProjection(TransInfo *t, float in[3], float out[3]) {
+ float vec[3], factor, norm[3];
+
+ VecAddf(vec, in, t->con.center);
+ getViewVector(vec, norm);
+
+ VecSubf(vec, out, in);
+
+ factor = Inpf(vec, norm);
+ if (fabs(factor) <= 0.001) {
+ return; /* prevent divide by zero */
+ }
+ factor = Inpf(vec, vec) / factor;
+
+ VECCOPY(vec, norm);
+ VecMulf(vec, factor);
+
+ VecAddf(out, in, vec);
+}
+
+/*
+ * Generic callback for constant spacial constraints applied to linear motion
+ *
+ * The IN vector in projected into the constrained space and then further
+ * projected along the view vector.
+ * (in perspective mode, the view vector is relative to the position on screen)
+ *
+ */
+
+static void applyAxisConstraintVec(TransInfo *t, TransData *td, float in[3], float out[3], float pvec[3])
+{
+ VECCOPY(out, in);
+ if (!td && t->con.mode & CON_APPLY) {
+ Mat3MulVecfl(t->con.pmtx, out);
+
+ // With snap, a projection is alright, no need to correct for view alignment
+ if ((t->tsnap.status & SNAP_ON) == 0)
+ {
+ if (getConstraintSpaceDimension(t) == 2) {
+ if (out[0] != 0.0f || out[1] != 0.0f || out[2] != 0.0f) {
+ planeProjection(t, in, out);
+ }
+ }
+ else if (getConstraintSpaceDimension(t) == 1) {
+ float c[3];
+
+ if (t->con.mode & CON_AXIS0) {
+ VECCOPY(c, t->con.mtx[0]);
+ }
+ else if (t->con.mode & CON_AXIS1) {
+ VECCOPY(c, t->con.mtx[1]);
+ }
+ else if (t->con.mode & CON_AXIS2) {
+ VECCOPY(c, t->con.mtx[2]);
+ }
+ axisProjection(t, c, in, out);
+ }
+ }
+ postConstraintChecks(t, out, pvec);
+ }
+}
+
+/*
+ * Generic callback for object based spacial constraints applied to linear motion
+ *
+ * At first, the following is applied to the first data in the array
+ * The IN vector in projected into the constrained space and then further
+ * projected along the view vector.
+ * (in perspective mode, the view vector is relative to the position on screen)
+ *
+ * Further down, that vector is mapped to each data's space.
+ */
+
+static void applyObjectConstraintVec(TransInfo *t, TransData *td, float in[3], float out[3], float pvec[3])
+{
+ VECCOPY(out, in);
+ if (t->con.mode & CON_APPLY) {
+ if (!td) {
+ Mat3MulVecfl(t->con.pmtx, out);
+ if (getConstraintSpaceDimension(t) == 2) {
+ if (out[0] != 0.0f || out[1] != 0.0f || out[2] != 0.0f) {
+ planeProjection(t, in, out);
+ }
+ }
+ else if (getConstraintSpaceDimension(t) == 1) {
+ float c[3];
+
+ if (t->con.mode & CON_AXIS0) {
+ VECCOPY(c, t->con.mtx[0]);
+ }
+ else if (t->con.mode & CON_AXIS1) {
+ VECCOPY(c, t->con.mtx[1]);
+ }
+ else if (t->con.mode & CON_AXIS2) {
+ VECCOPY(c, t->con.mtx[2]);
+ }
+ axisProjection(t, c, in, out);
+ }
+ postConstraintChecks(t, out, pvec);
+ VECCOPY(out, pvec);
+ }
+ else {
+ int i=0;
+
+ out[0] = out[1] = out[2] = 0.0f;
+ if (t->con.mode & CON_AXIS0) {
+ out[0] = in[i++];
+ }
+ if (t->con.mode & CON_AXIS1) {
+ out[1] = in[i++];
+ }
+ if (t->con.mode & CON_AXIS2) {
+ out[2] = in[i++];
+ }
+ Mat3MulVecfl(td->axismtx, out);
+ }
+ }
+}
+
+/*
+ * Generic callback for constant spacial constraints applied to resize motion
+ *
+ *
+ */
+
+static void applyAxisConstraintSize(TransInfo *t, TransData *td, float smat[3][3])
+{
+ if (!td && t->con.mode & CON_APPLY) {
+ float tmat[3][3];
+
+ if (!(t->con.mode & CON_AXIS0)) {
+ smat[0][0] = 1.0f;
+ }
+ if (!(t->con.mode & CON_AXIS1)) {
+ smat[1][1] = 1.0f;
+ }
+ if (!(t->con.mode & CON_AXIS2)) {
+ smat[2][2] = 1.0f;
+ }
+
+ Mat3MulMat3(tmat, smat, t->con.imtx);
+ Mat3MulMat3(smat, t->con.mtx, tmat);
+ }
+}
+
+/*
+ * Callback for object based spacial constraints applied to resize motion
+ *
+ *
+ */
+
+static void applyObjectConstraintSize(TransInfo *t, TransData *td, float smat[3][3])
+{
+ if (td && t->con.mode & CON_APPLY) {
+ float tmat[3][3];
+ float imat[3][3];
+
+ Mat3Inv(imat, td->axismtx);
+
+ if (!(t->con.mode & CON_AXIS0)) {
+ smat[0][0] = 1.0f;
+ }
+ if (!(t->con.mode & CON_AXIS1)) {
+ smat[1][1] = 1.0f;
+ }
+ if (!(t->con.mode & CON_AXIS2)) {
+ smat[2][2] = 1.0f;
+ }
+
+ Mat3MulMat3(tmat, smat, imat);
+ Mat3MulMat3(smat, td->axismtx, tmat);
+ }
+}
+
+/*
+ * Generic callback for constant spacial constraints applied to rotations
+ *
+ * The rotation axis is copied into VEC.
+ *
+ * In the case of single axis constraints, the rotation axis is directly the one constrained to.
+ * For planar constraints (2 axis), the rotation axis is the normal of the plane.
+ *
+ * The following only applies when CON_NOFLIP is not set.
+ * The vector is then modified to always point away from the screen (in global space)
+ * This insures that the rotation is always logically following the mouse.
+ * (ie: not doing counterclockwise rotations when the mouse moves clockwise).
+ */
+
+static void applyAxisConstraintRot(TransInfo *t, TransData *td, float vec[3])
+{
+ if (!td && t->con.mode & CON_APPLY) {
+ int mode = t->con.mode & (CON_AXIS0|CON_AXIS1|CON_AXIS2);
+
+ switch(mode) {
+ case CON_AXIS0:
+ case (CON_AXIS1|CON_AXIS2):
+ VECCOPY(vec, t->con.mtx[0]);
+ break;
+ case CON_AXIS1:
+ case (CON_AXIS0|CON_AXIS2):
+ VECCOPY(vec, t->con.mtx[1]);
+ break;
+ case CON_AXIS2:
+ case (CON_AXIS0|CON_AXIS1):
+ VECCOPY(vec, t->con.mtx[2]);
+ break;
+ }
+ if (!(mode & CON_NOFLIP)) {
+ if (Inpf(vec, t->viewinv[2]) > 0.0f) {
+ VecMulf(vec, -1.0f);
+ }
+ }
+ }
+}
+
+/*
+ * Callback for object based spacial constraints applied to rotations
+ *
+ * The rotation axis is copied into VEC.
+ *
+ * In the case of single axis constraints, the rotation axis is directly the one constrained to.
+ * For planar constraints (2 axis), the rotation axis is the normal of the plane.
+ *
+ * The following only applies when CON_NOFLIP is not set.
+ * The vector is then modified to always point away from the screen (in global space)
+ * This insures that the rotation is always logically following the mouse.
+ * (ie: not doing counterclockwise rotations when the mouse moves clockwise).
+ */
+
+static void applyObjectConstraintRot(TransInfo *t, TransData *td, float vec[3])
+{
+ if (td && t->con.mode & CON_APPLY) {
+ int mode = t->con.mode & (CON_AXIS0|CON_AXIS1|CON_AXIS2);
+
+ switch(mode) {
+ case CON_AXIS0:
+ case (CON_AXIS1|CON_AXIS2):
+ VECCOPY(vec, td->axismtx[0]);
+ break;
+ case CON_AXIS1:
+ case (CON_AXIS0|CON_AXIS2):
+ VECCOPY(vec, td->axismtx[1]);
+ break;
+ case CON_AXIS2:
+ case (CON_AXIS0|CON_AXIS1):
+ VECCOPY(vec, td->axismtx[2]);
+ break;
+ }
+ if (!(mode & CON_NOFLIP)) {
+ if (Inpf(vec, t->viewinv[2]) > 0.0f) {
+ VecMulf(vec, -1.0f);
+ }
+ }
+ }
+}
+
+/*--------------------- INTERNAL SETUP CALLS ------------------*/
+
+void setConstraint(TransInfo *t, float space[3][3], int mode, const char text[]) {
+ strncpy(t->con.text + 1, text, 48);
+ Mat3CpyMat3(t->con.mtx, space);
+ t->con.mode = mode;
+ getConstraintMatrix(t);
+
+ startConstraint(t);
+
+ t->con.drawExtra = NULL;
+ t->con.applyVec = applyAxisConstraintVec;
+ t->con.applySize = applyAxisConstraintSize;
+ t->con.applyRot = applyAxisConstraintRot;
+ t->redraw = 1;
+}
+
+void setLocalConstraint(TransInfo *t, int mode, const char text[]) {
+ if (t->flag & T_EDIT) {
+ float obmat[3][3];
+ Mat3CpyMat4(obmat, G.obedit->obmat);
+ setConstraint(t, obmat, mode|CON_LOCAL, text);
+ }
+ else {
+ if (t->total == 1) {
+ setConstraint(t, t->data->axismtx, mode|CON_LOCAL, text);
+ }
+ else {
+ strncpy(t->con.text + 1, text, 48);
+ Mat3CpyMat3(t->con.mtx, t->data->axismtx);
+ t->con.mode = mode|CON_LOCAL;
+ getConstraintMatrix(t);
+
+ startConstraint(t);
+
+ t->con.drawExtra = drawObjectConstraint;
+ t->con.applyVec = applyObjectConstraintVec;
+ t->con.applySize = applyObjectConstraintSize;
+ t->con.applyRot = applyObjectConstraintRot;
+ t->redraw = 1;
+ }
+ }
+}
+
+/*
+ Set the constraint according to the user defined orientation
+
+ ftext is a format string passed to sprintf. It will add the name of
+ the orientation where %s is (logically).
+*/
+void setUserConstraint(TransInfo *t, int mode, const char ftext[]) {
+ char text[40];
+ short twmode= (t->spacetype==SPACE_VIEW3D)? G.vd->twmode: V3D_MANIP_GLOBAL;
+
+ switch(twmode) {
+ case V3D_MANIP_GLOBAL:
+ /*
+ sprintf(text, ftext, "global");
+ Mat3One(mtx);
+ setConstraint(t, mtx, mode, text);
+ break;
+ */
+ case V3D_MANIP_LOCAL:
+ sprintf(text, ftext, "local");
+ setLocalConstraint(t, mode, text);
+ break;
+ case V3D_MANIP_NORMAL:
+ sprintf(text, ftext, "normal");
+ setConstraint(t, t->spacemtx, mode, text);
+ break;
+ case V3D_MANIP_VIEW:
+ sprintf(text, ftext, "view");
+ setConstraint(t, t->spacemtx, mode, text);
+ break;
+ }
+
+ t->con.mode |= CON_USER;
+}
+
+/*--------------------- EXTERNAL SETUP CALLS ------------------*/
+
+void BIF_setLocalLockConstraint(char axis, char *text) {
+ TransInfo *t = BIF_GetTransInfo();
+
+ switch (axis) {
+ case 'x':
+ setLocalConstraint(t, (CON_AXIS1|CON_AXIS2), text);
+ break;
+ case 'y':
+ setLocalConstraint(t, (CON_AXIS0|CON_AXIS2), text);
+ break;
+ case 'z':
+ setLocalConstraint(t, (CON_AXIS0|CON_AXIS1), text);
+ break;
+ }
+}
+
+void BIF_setLocalAxisConstraint(char axis, char *text) {
+ TransInfo *t = BIF_GetTransInfo();
+
+ switch (axis) {
+ case 'X':
+ setLocalConstraint(t, CON_AXIS0, text);
+ break;
+ case 'Y':
+ setLocalConstraint(t, CON_AXIS1, text);
+ break;
+ case 'Z':
+ setLocalConstraint(t, CON_AXIS2, text);
+ break;
+ }
+}
+
+/* text is optional, for header print */
+void BIF_setSingleAxisConstraint(float vec[3], char *text) {
+ TransInfo *t = BIF_GetTransInfo();
+ float space[3][3], v[3];
+
+ VECCOPY(space[0], vec);
+
+ v[0] = vec[2];
+ v[1] = vec[0];
+ v[2] = vec[1];
+
+ Crossf(space[1], vec, v);
+ Crossf(space[2], vec, space[1]);
+ Mat3Ortho(space);
+
+ Mat3CpyMat3(t->con.mtx, space);
+ t->con.mode = (CON_AXIS0|CON_APPLY);
+ getConstraintMatrix(t);
+
+ /* start copying with an offset of 1, to reserve a spot for the SPACE char */
+ if(text) strncpy(t->con.text+1, text, 48); // 50 in struct
+
+
+ t->con.drawExtra = NULL;
+ t->con.applyVec = applyAxisConstraintVec;
+ t->con.applySize = applyAxisConstraintSize;
+ t->con.applyRot = applyAxisConstraintRot;
+ t->redraw = 1;
+}
+
+void BIF_setDualAxisConstraint(float vec1[3], float vec2[3], char *text) {
+ TransInfo *t = BIF_GetTransInfo();
+ float space[3][3];
+
+ VECCOPY(space[0], vec1);
+ VECCOPY(space[1], vec2);
+ Crossf(space[2], space[0], space[1]);
+ Mat3Ortho(space);
+
+ Mat3CpyMat3(t->con.mtx, space);
+ t->con.mode = (CON_AXIS0|CON_AXIS1|CON_APPLY);
+ getConstraintMatrix(t);
+
+ /* start copying with an offset of 1, to reserve a spot for the SPACE char */
+ if(text) strncpy(t->con.text+1, text, 48); // 50 in struct
+
+ t->con.drawExtra = NULL;
+ t->con.applyVec = applyAxisConstraintVec;
+ t->con.applySize = applyAxisConstraintSize;
+ t->con.applyRot = applyAxisConstraintRot;
+ t->redraw = 1;
+}
+
+/*----------------- DRAWING CONSTRAINTS -------------------*/
+
+void BIF_drawConstraint(void)
+{
+ TransInfo *t = BIF_GetTransInfo();
+ TransCon *tc = &(t->con);
+
+ if (t->spacetype!=SPACE_VIEW3D)
+ return;
+ if (!(tc->mode & CON_APPLY))
+ return;
+ if (t->flag & T_USES_MANIPULATOR)
+ return;
+
+ /* nasty exception for Z constraint in camera view */
+ if((t->flag & T_OBJECT) && G.vd->camera==OBACT && G.vd->persp>1)
+ return;
+
+ if (tc->drawExtra) {
+ tc->drawExtra(t);
+ }
+ else {
+ if (tc->mode & CON_SELECT) {
+ float vec[3];
+ short mval[2];
+ char col2[3] = {255,255,255};
+ getmouseco_areawin(mval);
+ convertViewVec(t, vec, (short)(mval[0] - t->con.imval[0]), (short)(mval[1] - t->con.imval[1]));
+ VecAddf(vec, vec, tc->center);
+
+ drawLine(tc->center, tc->mtx[0], 'x', 0);
+ drawLine(tc->center, tc->mtx[1], 'y', 0);
+ drawLine(tc->center, tc->mtx[2], 'z', 0);
+
+ glColor3ubv((GLubyte *)col2);
+
+ glDisable(GL_DEPTH_TEST);
+ setlinestyle(1);
+ glBegin(GL_LINE_STRIP);
+ glVertex3fv(tc->center);
+ glVertex3fv(vec);
+ glEnd();
+ setlinestyle(0);
+ if(G.vd->zbuf) glEnable(GL_DEPTH_TEST);
+ }
+
+ if (tc->mode & CON_AXIS0) {
+ drawLine(tc->center, tc->mtx[0], 'x', DRAWLIGHT);
+ }
+ if (tc->mode & CON_AXIS1) {
+ drawLine(tc->center, tc->mtx[1], 'y', DRAWLIGHT);
+ }
+ if (tc->mode & CON_AXIS2) {
+ drawLine(tc->center, tc->mtx[2], 'z', DRAWLIGHT);
+ }
+ }
+}
+
+/* called from drawview.c, as an extra per-window draw option */
+void BIF_drawPropCircle()
+{
+ TransInfo *t = BIF_GetTransInfo();
+
+ if (t->flag & T_PROP_EDIT) {
+ float tmat[4][4], imat[4][4];
+
+ BIF_ThemeColor(TH_GRID);
+
+ /* if editmode we need to go into object space */
+ if(G.obedit) mymultmatrix(G.obedit->obmat);
+
+ mygetmatrix(tmat);
+ Mat4Invert(imat, tmat);
+
+ set_inverted_drawing(1);
+ drawcircball(GL_LINE_LOOP, t->center, t->propsize, imat);
+ set_inverted_drawing(0);
+
+ /* if editmode we restore */
+ if(G.obedit) myloadmatrix(G.vd->viewmat);
+ }
+}
+
+void BIF_getPropCenter(float *center)
+{
+ TransInfo *t = BIF_GetTransInfo();
+
+ if (t && t->flag & T_PROP_EDIT) {
+ VECCOPY(center, t->center);
+ }
+ else
+ center[0] = center[1] = center[2] = 0.0f;
+}
+static void drawObjectConstraint(TransInfo *t) {
+ int i;
+ TransData * td = t->data;
+
+ /* Draw the first one lighter because that's the one who controls the others.
+ Meaning the transformation is projected on that one and just copied on the others
+ constraint space.
+ In a nutshell, the object with light axis is controlled by the user and the others follow.
+ Without drawing the first light, users have little clue what they are doing.
+ */
+ if (t->con.mode & CON_AXIS0) {
+ drawLine(td->ob->obmat[3], td->axismtx[0], 'x', DRAWLIGHT);
+ }
+ if (t->con.mode & CON_AXIS1) {
+ drawLine(td->ob->obmat[3], td->axismtx[1], 'y', DRAWLIGHT);
+ }
+ if (t->con.mode & CON_AXIS2) {
+ drawLine(td->ob->obmat[3], td->axismtx[2], 'z', DRAWLIGHT);
+ }
+
+ td++;
+
+ for(i=1;i<t->total;i++,td++) {
+ if (t->con.mode & CON_AXIS0) {
+ drawLine(td->ob->obmat[3], td->axismtx[0], 'x', 0);
+ }
+ if (t->con.mode & CON_AXIS1) {
+ drawLine(td->ob->obmat[3], td->axismtx[1], 'y', 0);
+ }
+ if (t->con.mode & CON_AXIS2) {
+ drawLine(td->ob->obmat[3], td->axismtx[2], 'z', 0);
+ }
+ }
+}
+
+/*--------------------- START / STOP CONSTRAINTS ---------------------- */
+
+void startConstraint(TransInfo *t) {
+ t->con.mode |= CON_APPLY;
+ *t->con.text = ' ';
+ t->num.idx_max = MIN2(getConstraintSpaceDimension(t) - 1, t->idx_max);
+}
+
+void stopConstraint(TransInfo *t) {
+ t->con.mode &= ~(CON_APPLY|CON_SELECT);
+ *t->con.text = '\0';
+ t->num.idx_max = t->idx_max;
+}
+
+void getConstraintMatrix(TransInfo *t)
+{
+ float mat[3][3];
+ Mat3Inv(t->con.imtx, t->con.mtx);
+ Mat3One(t->con.pmtx);
+
+ if (!(t->con.mode & CON_AXIS0)) {
+ t->con.pmtx[0][0] =
+ t->con.pmtx[0][1] =
+ t->con.pmtx[0][2] = 0.0f;
+ }
+
+ if (!(t->con.mode & CON_AXIS1)) {
+ t->con.pmtx[1][0] =
+ t->con.pmtx[1][1] =
+ t->con.pmtx[1][2] = 0.0f;
+ }
+
+ if (!(t->con.mode & CON_AXIS2)) {
+ t->con.pmtx[2][0] =
+ t->con.pmtx[2][1] =
+ t->con.pmtx[2][2] = 0.0f;
+ }
+
+ Mat3MulMat3(mat, t->con.pmtx, t->con.imtx);
+ Mat3MulMat3(t->con.pmtx, t->con.mtx, mat);
+}
+
+/*------------------------- MMB Select -------------------------------*/
+
+void initSelectConstraint(TransInfo *t, float mtx[3][3])
+{
+ Mat3CpyMat3(t->con.mtx, mtx);
+ t->con.mode |= CON_APPLY;
+ t->con.mode |= CON_SELECT;
+ t->con.mode &= ~CON_LOCAL;
+
+ setNearestAxis(t);
+ t->con.drawExtra = NULL;
+ t->con.applyVec = applyAxisConstraintVec;
+ t->con.applySize = applyAxisConstraintSize;
+ t->con.applyRot = applyAxisConstraintRot;
+}
+
+void selectConstraint(TransInfo *t) {
+ if (t->con.mode & CON_SELECT) {
+ setNearestAxis(t);
+ startConstraint(t);
+ }
+}
+
+void postSelectConstraint(TransInfo *t)
+{
+ if (!(t->con.mode & CON_SELECT))
+ return;
+
+ t->con.mode &= ~CON_AXIS0;
+ t->con.mode &= ~CON_AXIS1;
+ t->con.mode &= ~CON_AXIS2;
+ t->con.mode &= ~CON_SELECT;
+
+ setNearestAxis(t);
+
+ startConstraint(t);
+ t->redraw = 1;
+}
+
+static void setNearestAxis2d(TransInfo *t)
+{
+ short mval[2];
+ short ival[2];
+
+ getmouseco_areawin(mval);
+ ival[0]= t->imval[0];
+ ival[1]= t->imval[1];
+
+ /* no correction needed... just use whichever one is lower */
+ if ( abs(mval[0]-ival[0]) < abs(mval[1]-ival[1]) ) {
+ t->con.mode |= CON_AXIS1;
+ sprintf(t->con.text, " along Y axis");
+ }
+ else {
+ t->con.mode |= CON_AXIS0;
+ sprintf(t->con.text, " along X axis");
+ }
+}
+
+static void setNearestAxis3d(TransInfo *t)
+{
+ float zfac;
+ float mvec[3], axis[3], proj[3];
+ float len[3];
+ int i, icoord[2];
+ short coord[2];
+
+ /* calculate mouse movement */
+ getmouseco_areawin(coord);
+ mvec[0] = (float)(coord[0] - t->con.imval[0]);
+ mvec[1] = (float)(coord[1] - t->con.imval[1]);
+ mvec[2] = 0.0f;
+
+ /* we need to correct axis length for the current zoomlevel of view,
+ this to prevent projected values to be clipped behind the camera
+ and to overflow the short integers.
+ The formula used is a bit stupid, just a simplification of the substraction
+ of two 2D points 30 pixels apart (that's the last factor in the formula) after
+ projecting them with window_to_3d and then get the length of that vector.
+ */
+ zfac= t->persmat[0][3]*t->center[0]+ t->persmat[1][3]*t->center[1]+ t->persmat[2][3]*t->center[2]+ t->persmat[3][3];
+ zfac = VecLength(t->persinv[0]) * 2.0f/curarea->winx * zfac * 30.0f;
+
+ for (i = 0; i<3; i++) {
+ VECCOPY(axis, t->con.mtx[i]);
+
+ VecMulf(axis, zfac);
+ /* now we can project to get window coordinate */
+ VecAddf(axis, axis, t->con.center);
+ projectIntView(t, axis, icoord);
+
+ axis[0] = (float)(icoord[0] - t->center2d[0]);
+ axis[1] = (float)(icoord[1] - t->center2d[1]);
+ axis[2] = 0.0f;
+
+ if (Normalize(axis) != 0.0f) {
+ Projf(proj, mvec, axis);
+ VecSubf(axis, mvec, proj);
+ len[i] = Normalize(axis);
+ }
+ else {
+ len[i] = 10000000000.0f;
+ }
+ }
+
+ if (len[0] <= len[1] && len[0] <= len[2]) {
+ if (G.qual & LR_SHIFTKEY) {
+ t->con.mode |= (CON_AXIS1|CON_AXIS2);
+ sprintf(t->con.text, " locking %s X axis", t->spacename);
+ }
+ else {
+ t->con.mode |= CON_AXIS0;
+ sprintf(t->con.text, " along %s X axis", t->spacename);
+ }
+ }
+ else if (len[1] <= len[0] && len[1] <= len[2]) {
+ if (G.qual & LR_SHIFTKEY) {
+ t->con.mode |= (CON_AXIS0|CON_AXIS2);
+ sprintf(t->con.text, " locking %s Y axis", t->spacename);
+ }
+ else {
+ t->con.mode |= CON_AXIS1;
+ sprintf(t->con.text, " along %s Y axis", t->spacename);
+ }
+ }
+ else if (len[2] <= len[1] && len[2] <= len[0]) {
+ if (G.qual & LR_SHIFTKEY) {
+ t->con.mode |= (CON_AXIS0|CON_AXIS1);
+ sprintf(t->con.text, " locking %s Z axis", t->spacename);
+ }
+ else {
+ t->con.mode |= CON_AXIS2;
+ sprintf(t->con.text, " along %s Z axis", t->spacename);
+ }
+ }
+}
+
+void setNearestAxis(TransInfo *t)
+{
+ /* clear any prior constraint flags */
+ t->con.mode &= ~CON_AXIS0;
+ t->con.mode &= ~CON_AXIS1;
+ t->con.mode &= ~CON_AXIS2;
+
+ /* constraint setting - depends on spacetype */
+ if (t->spacetype == SPACE_VIEW3D) {
+ /* 3d-view */
+ setNearestAxis3d(t);
+ }
+ else {
+ /* assume that this means a 2D-Editor */
+ setNearestAxis2d(t);
+ }
+
+ getConstraintMatrix(t);
+}
+
+/*-------------- HELPER FUNCTIONS ----------------*/
+
+char constraintModeToChar(TransInfo *t) {
+ if ((t->con.mode & CON_APPLY)==0) {
+ return '\0';
+ }
+ switch (t->con.mode & (CON_AXIS0|CON_AXIS1|CON_AXIS2)) {
+ case (CON_AXIS0):
+ case (CON_AXIS1|CON_AXIS2):
+ return 'X';
+ case (CON_AXIS1):
+ case (CON_AXIS0|CON_AXIS2):
+ return 'Y';
+ case (CON_AXIS2):
+ case (CON_AXIS0|CON_AXIS1):
+ return 'Z';
+ default:
+ return '\0';
+ }
+}
+
+
+int isLockConstraint(TransInfo *t) {
+ int mode = t->con.mode;
+
+ if ( (mode & (CON_AXIS0|CON_AXIS1)) == (CON_AXIS0|CON_AXIS1))
+ return 1;
+
+ if ( (mode & (CON_AXIS1|CON_AXIS2)) == (CON_AXIS1|CON_AXIS2))
+ return 1;
+
+ if ( (mode & (CON_AXIS0|CON_AXIS2)) == (CON_AXIS0|CON_AXIS2))
+ return 1;
+
+ return 0;
+}
+
+/*
+ * Returns the dimension of the constraint space.
+ *
+ * For that reason, the flags always needs to be set to properly evaluate here,
+ * even if they aren't actually used in the callback function. (Which could happen
+ * for weird constraints not yet designed. Along a path for example.)
+ */
+
+int getConstraintSpaceDimension(TransInfo *t)
+{
+ int n = 0;
+
+ if (t->con.mode & CON_AXIS0)
+ n++;
+
+ if (t->con.mode & CON_AXIS1)
+ n++;
+
+ if (t->con.mode & CON_AXIS2)
+ n++;
+
+ return n;
+/*
+ Someone willing to do it criptically could do the following instead:
+
+ return t->con & (CON_AXIS0|CON_AXIS1|CON_AXIS2);
+
+ Based on the assumptions that the axis flags are one after the other and start at 1
+*/
+}
diff --git a/source/blender/src/transform_conversions.c b/source/blender/src/transform_conversions.c
new file mode 100644
index 00000000000..820d79eb809
--- /dev/null
+++ b/source/blender/src/transform_conversions.c
@@ -0,0 +1,3242 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef WIN32
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+#include <string.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_action_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_effect_types.h"
+#include "DNA_image_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_key_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_nla_types.h"
+#include "DNA_object_types.h"
+#include "DNA_object_force.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_world_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_property_types.h"
+#include "DNA_vfont_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_listBase.h"
+
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_blender.h"
+#include "BKE_curve.h"
+#include "BKE_constraint.h"
+#include "BKE_depsgraph.h"
+#include "BKE_displist.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_effect.h"
+#include "BKE_font.h"
+#include "BKE_global.h"
+#include "BKE_ipo.h"
+#include "BKE_lattice.h"
+#include "BKE_key.h"
+#include "BKE_main.h"
+#include "BKE_mball.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+#include "BKE_softbody.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_editaction.h"
+#include "BIF_editview.h"
+#include "BIF_editlattice.h"
+#include "BIF_editconstraint.h"
+#include "BIF_editarmature.h"
+#include "BIF_editmesh.h"
+#include "BIF_editnla.h"
+#include "BIF_editsima.h"
+#include "BIF_gl.h"
+#include "BIF_poseobject.h"
+#include "BIF_meshtools.h"
+#include "BIF_mywindow.h"
+#include "BIF_resources.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_toolbox.h"
+
+#include "BSE_view.h"
+#include "BSE_drawipo.h"
+#include "BSE_edit.h"
+#include "BSE_editipo.h"
+#include "BSE_editipo_types.h"
+#include "BSE_editaction_types.h"
+
+#include "BDR_editobject.h" // reset_slowparents()
+#include "BDR_unwrapper.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+#include "BLI_editVert.h"
+
+#include "editmesh.h"
+
+#include "blendef.h"
+
+#include "mydevice.h"
+
+extern ListBase editNurb;
+extern ListBase editelems;
+
+#include "transform.h"
+
+/* local function prototype - for Object/Bone Constraints */
+static short constraints_list_needinv(ListBase *list);
+
+/* ************************** Functions *************************** */
+
+static void qsort_trans_data(TransInfo *t, TransData *head, TransData *tail) {
+ TransData pivot = *head;
+ TransData *ihead = head;
+ TransData *itail = tail;
+ short connected = t->flag & T_PROP_CONNECTED;
+
+ while (head < tail)
+ {
+ if (connected) {
+ while ((tail->dist >= pivot.dist) && (head < tail))
+ tail--;
+ }
+ else {
+ while ((tail->rdist >= pivot.rdist) && (head < tail))
+ tail--;
+ }
+
+ if (head != tail)
+ {
+ *head = *tail;
+ head++;
+ }
+
+ if (connected) {
+ while ((head->dist <= pivot.dist) && (head < tail))
+ head++;
+ }
+ else {
+ while ((head->rdist <= pivot.rdist) && (head < tail))
+ head++;
+ }
+
+ if (head != tail)
+ {
+ *tail = *head;
+ tail--;
+ }
+ }
+
+ *head = pivot;
+ if (ihead < head) {
+ qsort_trans_data(t, ihead, head-1);
+ }
+ if (itail > head) {
+ qsort_trans_data(t, head+1, itail);
+ }
+}
+
+void sort_trans_data_dist(TransInfo *t) {
+ TransData *start = t->data;
+ int i = 1;
+
+ while(i < t->total && start->flag & TD_SELECTED) {
+ start++;
+ i++;
+ }
+ qsort_trans_data(t, start, t->data + t->total - 1);
+}
+
+static void sort_trans_data(TransInfo *t)
+{
+ TransData *sel, *unsel;
+ TransData temp;
+ unsel = t->data;
+ sel = t->data;
+ sel += t->total - 1;
+ while (sel > unsel) {
+ while (unsel->flag & TD_SELECTED) {
+ unsel++;
+ if (unsel == sel) {
+ return;
+ }
+ }
+ while (!(sel->flag & TD_SELECTED)) {
+ sel--;
+ if (unsel == sel) {
+ return;
+ }
+ }
+ temp = *unsel;
+ *unsel = *sel;
+ *sel = temp;
+ sel--;
+ unsel++;
+ }
+}
+
+/* distance calculated from not-selected vertex to nearest selected vertex
+ warning; this is loops inside loop, has minor N^2 issues, but by sorting list it is OK */
+static void set_prop_dist(TransInfo *t, short with_dist)
+{
+ TransData *tob;
+ int a;
+
+ for(a=0, tob= t->data; a<t->total; a++, tob++) {
+
+ tob->rdist= 0.0f; // init, it was mallocced
+
+ if((tob->flag & TD_SELECTED)==0) {
+ TransData *td;
+ int i;
+ float dist, vec[3];
+
+ tob->rdist = -1.0f; // signal for next loop
+
+ for (i = 0, td= t->data; i < t->total; i++, td++) {
+ if(td->flag & TD_SELECTED) {
+ VecSubf(vec, tob->center, td->center);
+ Mat3MulVecfl(tob->mtx, vec);
+ dist = Normalize(vec);
+ if (tob->rdist == -1.0f) {
+ tob->rdist = dist;
+ }
+ else if (dist < tob->rdist) {
+ tob->rdist = dist;
+ }
+ }
+ else break; // by definition transdata has selected items in beginning
+ }
+ if (with_dist) {
+ tob->dist = tob->rdist;
+ }
+ }
+ }
+}
+
+/* ************************** CONVERSIONS ************************* */
+
+/* ********************* texture space ********* */
+
+static void createTransTexspace(TransInfo *t)
+{
+ TransData *td;
+ Object *ob;
+ ID *id;
+
+ ob= OBACT;
+
+ if (ob==NULL) { // Shouldn't logically happen, but still...
+ t->total = 0;
+ return;
+ }
+
+ id= ob->data;
+ if(id==NULL || !ELEM3( GS(id->name), ID_ME, ID_CU, ID_MB )) {
+ t->total = 0;
+ return;
+ }
+
+ t->total = 1;
+ td= t->data= MEM_callocN(sizeof(TransData), "TransTexspace");
+ td->ext= t->ext= MEM_callocN(sizeof(TransDataExtension), "TransTexspace");
+
+ td->flag= TD_SELECTED;
+ VECCOPY(td->center, ob->obmat[3]);
+ td->ob = ob;
+
+ Mat3CpyMat4(td->mtx, ob->obmat);
+ Mat3CpyMat4(td->axismtx, ob->obmat);
+ Mat3Ortho(td->axismtx);
+ Mat3Inv(td->smtx, td->mtx);
+
+ if( GS(id->name)==ID_ME) {
+ Mesh *me= ob->data;
+ me->texflag &= ~AUTOSPACE;
+ td->loc= me->loc;
+ td->ext->rot= me->rot;
+ td->ext->size= me->size;
+ }
+ else if( GS(id->name)==ID_CU) {
+ Curve *cu= ob->data;
+ cu->texflag &= ~CU_AUTOSPACE;
+ td->loc= cu->loc;
+ td->ext->rot= cu->rot;
+ td->ext->size= cu->size;
+ }
+ else if( GS(id->name)==ID_MB) {
+ MetaBall *mb= ob->data;
+ mb->texflag &= ~MB_AUTOSPACE;
+ td->loc= mb->loc;
+ td->ext->rot= mb->rot;
+ td->ext->size= mb->size;
+ }
+
+ VECCOPY(td->iloc, td->loc);
+ VECCOPY(td->ext->irot, td->ext->rot);
+ VECCOPY(td->ext->isize, td->ext->size);
+}
+
+/* ********************* edge (for crease) ***** */
+
+static void createTransEdge(TransInfo *t) {
+ TransData *td = NULL;
+ EditMesh *em = G.editMesh;
+ EditEdge *eed;
+ float mtx[3][3], smtx[3][3];
+ int count=0, countsel=0;
+ int propmode = t->flag & T_PROP_EDIT;
+
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->h==0) {
+ if (eed->f & SELECT) countsel++;
+ if (propmode) count++;
+ }
+ }
+
+ if (countsel == 0)
+ return;
+
+ if(propmode) {
+ t->total = count;
+ }
+ else {
+ t->total = countsel;
+ }
+
+ td= t->data= MEM_callocN(t->total * sizeof(TransData), "TransCrease");
+
+ Mat3CpyMat4(mtx, G.obedit->obmat);
+ Mat3Inv(smtx, mtx);
+
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->h==0 && (eed->f & SELECT || propmode)) {
+ /* need to set center for center calculations */
+ VecAddf(td->center, eed->v1->co, eed->v2->co);
+ VecMulf(td->center, 0.5f);
+
+ td->loc= NULL;
+ if (eed->f & SELECT)
+ td->flag= TD_SELECTED;
+ else
+ td->flag= 0;
+
+
+ Mat3CpyMat3(td->smtx, smtx);
+ Mat3CpyMat3(td->mtx, mtx);
+
+ td->ext = NULL;
+ td->tdi = NULL;
+ td->val = &(eed->crease);
+ td->ival = eed->crease;
+
+ td++;
+ }
+ }
+}
+
+/* ********************* pose mode ************* */
+
+static bKinematicConstraint *has_targetless_ik(bPoseChannel *pchan)
+{
+ bConstraint *con= pchan->constraints.first;
+
+ for(;con; con= con->next) {
+ if(con->type==CONSTRAINT_TYPE_KINEMATIC) {
+ bKinematicConstraint *data= con->data;
+
+ if(data->tar==NULL)
+ return data;
+ if(data->tar->type==OB_ARMATURE && data->subtarget[0]==0)
+ return data;
+ }
+ }
+ return NULL;
+}
+
+static short apply_targetless_ik(Object *ob)
+{
+ bPoseChannel *pchan, *parchan, *chanlist[256];
+ bKinematicConstraint *data;
+ int segcount, apply= 0;
+
+ /* now we got a difficult situation... we have to find the
+ target-less IK pchans, and apply transformation to the all
+ pchans that were in the chain */
+
+ for (pchan=ob->pose->chanbase.first; pchan; pchan=pchan->next) {
+ data= has_targetless_ik(pchan);
+ if(data && (data->flag & CONSTRAINT_IK_AUTO)) {
+
+ /* fill the array with the bones of the chain (armature.c does same, keep it synced) */
+ segcount= 0;
+
+ /* exclude tip from chain? */
+ if(!(data->flag & CONSTRAINT_IK_TIP))
+ parchan= pchan->parent;
+ else
+ parchan= pchan;
+
+ /* Find the chain's root & count the segments needed */
+ for (; parchan; parchan=parchan->parent){
+ chanlist[segcount]= parchan;
+ segcount++;
+
+ if(segcount==data->rootbone || segcount>255) break; // 255 is weak
+ }
+ for(;segcount;segcount--) {
+ Bone *bone;
+ float rmat[4][4], tmat[4][4], imat[4][4];
+
+ /* pose_mat(b) = pose_mat(b-1) * offs_bone * channel * constraint * IK */
+ /* we put in channel the entire result of rmat= (channel * constraint * IK) */
+ /* pose_mat(b) = pose_mat(b-1) * offs_bone * rmat */
+ /* rmat = pose_mat(b) * inv( pose_mat(b-1) * offs_bone ) */
+
+ parchan= chanlist[segcount-1];
+ bone= parchan->bone;
+ bone->flag |= BONE_TRANSFORM; /* ensures it gets an auto key inserted */
+
+ if(parchan->parent) {
+ Bone *parbone= parchan->parent->bone;
+ float offs_bone[4][4];
+
+ /* offs_bone = yoffs(b-1) + root(b) + bonemat(b) */
+ Mat4CpyMat3(offs_bone, bone->bone_mat);
+
+ /* The bone's root offset (is in the parent's coordinate system) */
+ VECCOPY(offs_bone[3], bone->head);
+
+ /* Get the length translation of parent (length along y axis) */
+ offs_bone[3][1]+= parbone->length;
+
+ /* pose_mat(b-1) * offs_bone */
+ if(parchan->bone->flag & BONE_HINGE) {
+ /* the rotation of the parent restposition */
+ Mat4CpyMat4(rmat, parbone->arm_mat); /* rmat used as temp */
+
+ /* the location of actual parent transform */
+ VECCOPY(rmat[3], offs_bone[3]);
+ offs_bone[3][0]= offs_bone[3][1]= offs_bone[3][2]= 0.0f;
+ Mat4MulVecfl(parchan->parent->pose_mat, rmat[3]);
+
+ Mat4MulMat4(tmat, offs_bone, rmat);
+ }
+ else
+ Mat4MulMat4(tmat, offs_bone, parchan->parent->pose_mat);
+
+ Mat4Invert(imat, tmat);
+ }
+ else {
+ Mat4CpyMat3(tmat, bone->bone_mat);
+
+ VECCOPY(tmat[3], bone->head);
+ Mat4Invert(imat, tmat);
+ }
+ /* result matrix */
+ Mat4MulMat4(rmat, parchan->pose_mat, imat);
+
+ /* apply and decompose, doesn't work for constraints or non-uniform scale well */
+ {
+ float rmat3[3][3], qmat[3][3], imat[3][3], smat[3][3];
+
+ Mat3CpyMat4(rmat3, rmat);
+
+ /* quaternion */
+ Mat3ToQuat(rmat3, parchan->quat);
+
+ /* for size, remove rotation */
+ QuatToMat3(parchan->quat, qmat);
+ Mat3Inv(imat, qmat);
+ Mat3MulMat3(smat, rmat3, imat);
+ Mat3ToSize(smat, parchan->size);
+
+ VECCOPY(parchan->loc, rmat[3]);
+ }
+
+ }
+
+ apply= 1;
+ data->flag &= ~CONSTRAINT_IK_AUTO;
+ }
+ }
+
+ return apply;
+}
+
+static void add_pose_transdata(TransInfo *t, bPoseChannel *pchan, Object *ob, TransData *td)
+{
+ Bone *bone= pchan->bone;
+ float pmat[3][3], omat[3][3];
+ float cmat[3][3], tmat[3][3];
+ float vec[3];
+
+ VECCOPY(vec, pchan->pose_mat[3]);
+ VECCOPY(td->center, vec);
+
+ td->ob = ob;
+ td->flag= TD_SELECTED|TD_USEQUAT;
+ if(bone->flag & BONE_HINGE_CHILD_TRANSFORM)
+ td->flag |= TD_NOCENTER;
+ td->protectflag= pchan->protectflag;
+
+ td->loc = pchan->loc;
+ VECCOPY(td->iloc, pchan->loc);
+
+ td->ext->rot= NULL;
+ td->ext->quat= pchan->quat;
+ td->ext->size= pchan->size;
+
+ QUATCOPY(td->ext->iquat, pchan->quat);
+ VECCOPY(td->ext->isize, pchan->size);
+
+ /* proper way to get parent transform + own transform + constraints transform */
+ Mat3CpyMat4(omat, ob->obmat);
+
+ if(pchan->parent) {
+ if(pchan->bone->flag & BONE_HINGE)
+ Mat3CpyMat4(pmat, pchan->parent->bone->arm_mat);
+ else
+ Mat3CpyMat4(pmat, pchan->parent->pose_mat);
+
+ if (constraints_list_needinv(&pchan->constraints)) {
+ Mat3CpyMat4(tmat, pchan->constinv);
+ Mat3Inv(cmat, tmat);
+ Mat3MulSerie(td->mtx, pchan->bone->bone_mat, pmat, cmat, omat, 0,0,0,0); // dang mulserie swaps args
+ }
+ else
+ Mat3MulSerie(td->mtx, pchan->bone->bone_mat, pmat, omat, 0,0,0,0,0); // dang mulserie swaps args
+ }
+ else {
+ if (constraints_list_needinv(&pchan->constraints)) {
+ Mat3CpyMat4(tmat, pchan->constinv);
+ Mat3Inv(cmat, tmat);
+ Mat3MulSerie(td->mtx, pchan->bone->bone_mat, cmat, omat, 0, 0,0,0,0); // dang mulserie swaps args
+ }
+ else
+ Mat3MulMat3(td->mtx, omat, pchan->bone->bone_mat); // Mat3MulMat3 has swapped args!
+ }
+
+ Mat3Inv(td->smtx, td->mtx);
+
+ /* for axismat we use bone's own transform */
+ Mat3CpyMat4(pmat, pchan->pose_mat);
+ Mat3MulMat3(td->axismtx, omat, pmat);
+ Mat3Ortho(td->axismtx);
+
+ if(t->mode==TFM_BONESIZE) {
+ bArmature *arm= t->poseobj->data;
+
+ if(arm->drawtype==ARM_ENVELOPE) {
+ td->loc= NULL;
+ td->val= &bone->dist;
+ td->ival= bone->dist;
+ }
+ else {
+ // abusive storage of scale in the loc pointer :)
+ td->loc= &bone->xwidth;
+ VECCOPY (td->iloc, td->loc);
+ td->val= NULL;
+ }
+ }
+
+ /* in this case we can do target-less IK grabbing */
+ if(t->mode==TFM_TRANSLATION) {
+ bKinematicConstraint *data= has_targetless_ik(pchan);
+ if(data) {
+ if(data->flag & CONSTRAINT_IK_TIP) {
+ VECCOPY(data->grabtarget, pchan->pose_tail);
+ }
+ else {
+ VECCOPY(data->grabtarget, pchan->pose_head);
+ }
+ td->loc = data->grabtarget;
+ VECCOPY(td->iloc, td->loc);
+ data->flag |= CONSTRAINT_IK_AUTO;
+
+ /* only object matrix correction */
+ Mat3CpyMat3 (td->mtx, omat);
+ Mat3Inv (td->smtx, td->mtx);
+ }
+ }
+}
+
+static void bone_children_clear_transflag(ListBase *lb)
+{
+ Bone *bone= lb->first;
+
+ for(;bone;bone= bone->next) {
+ if(bone->flag & BONE_HINGE)
+ bone->flag |= BONE_HINGE_CHILD_TRANSFORM;
+ else
+ bone->flag &= ~BONE_TRANSFORM;
+
+ bone_children_clear_transflag(&bone->childbase);
+ }
+}
+
+/* sets transform flags in the bones, returns total */
+static void set_pose_transflags(TransInfo *t, Object *ob)
+{
+ bArmature *arm= ob->data;
+ bPoseChannel *pchan;
+ Bone *bone;
+
+ t->total= 0;
+
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ bone= pchan->bone;
+ if(bone->layer & arm->layer) {
+ if(bone->flag & BONE_SELECTED)
+ bone->flag |= BONE_TRANSFORM;
+ else
+ bone->flag &= ~BONE_TRANSFORM;
+
+ bone->flag &= ~BONE_HINGE_CHILD_TRANSFORM;
+ }
+ }
+
+ /* make sure no bone can be transformed when a parent is transformed */
+ /* since pchans are depsgraph sorted, the parents are in beginning of list */
+ if(t->mode!=TFM_BONESIZE) {
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ bone= pchan->bone;
+ if(bone->flag & BONE_TRANSFORM)
+ bone_children_clear_transflag(&bone->childbase);
+ }
+ }
+ /* now count, and check if we have autoIK or have to switch from translate to rotate */
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ bone= pchan->bone;
+ if(bone->flag & BONE_TRANSFORM) {
+ t->total++;
+
+ if(t->mode==TFM_TRANSLATION) {
+ if( has_targetless_ik(pchan)==NULL ) {
+ if(pchan->parent && (pchan->bone->flag & BONE_CONNECTED)) {
+ if(!(pchan->bone->flag & BONE_HINGE_CHILD_TRANSFORM))
+ t->mode= TFM_ROTATION;
+ }
+ else if((pchan->protectflag & OB_LOCK_LOC)==OB_LOCK_LOC)
+ t->mode= TFM_ROTATION;
+ }
+ }
+ }
+ }
+}
+
+/* frees temporal IKs */
+static void pose_grab_with_ik_clear(Object *ob)
+{
+ bKinematicConstraint *data;
+ bPoseChannel *pchan;
+ bConstraint *con;
+
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ for(con= pchan->constraints.first; con; con= con->next) {
+ if(con->type==CONSTRAINT_TYPE_KINEMATIC) {
+ data= con->data;
+ if(data->flag & CONSTRAINT_IK_TEMP) {
+ BLI_remlink(&pchan->constraints, con);
+ MEM_freeN(con->data);
+ MEM_freeN(con);
+ pchan->constflag &= ~(PCHAN_HAS_IK|PCHAN_HAS_TARGET);
+ break;
+ }
+ }
+ }
+ }
+}
+
+/* adds the IK to pchan */
+static void pose_grab_with_ik_add(bPoseChannel *pchan)
+{
+ bKinematicConstraint *data;
+ bConstraint *con;
+
+ if (pchan == NULL) { // Sanity check
+ return;
+ }
+
+ /* rule: not if there's already an IK on this channel */
+ for(con= pchan->constraints.first; con; con= con->next)
+ if(con->type==CONSTRAINT_TYPE_KINEMATIC)
+ break;
+
+ if(con) {
+ /* but, if this is a targetless IK, we make it auto anyway (for the children loop) */
+ data= has_targetless_ik(pchan);
+ if(data)
+ data->flag |= CONSTRAINT_IK_AUTO;
+ return;
+ }
+
+ con = add_new_constraint(CONSTRAINT_TYPE_KINEMATIC);
+ BLI_addtail(&pchan->constraints, con);
+ pchan->constflag |= (PCHAN_HAS_IK|PCHAN_HAS_TARGET); /* for draw, but also for detecting while pose solving */
+ data= con->data;
+ data->flag= CONSTRAINT_IK_TIP|CONSTRAINT_IK_TEMP|CONSTRAINT_IK_AUTO;
+ VECCOPY(data->grabtarget, pchan->pose_tail);
+ data->rootbone= 1;
+
+ /* we include only a connected chain */
+ while(pchan && (pchan->bone->flag & BONE_CONNECTED)) {
+ data->rootbone++;
+ pchan= pchan->parent;
+ }
+}
+
+/* bone is a canditate to get IK, but we don't do it if it has children connected */
+static void pose_grab_with_ik_children(bPose *pose, Bone *bone)
+{
+ Bone *bonec;
+ int wentdeeper= 0;
+
+ /* go deeper if children & children are connected */
+ for(bonec= bone->childbase.first; bonec; bonec= bonec->next) {
+ if(bonec->flag & BONE_CONNECTED) {
+ wentdeeper= 1;
+ pose_grab_with_ik_children(pose, bonec);
+ }
+ }
+ if(wentdeeper==0) {
+ bPoseChannel *pchan= get_pose_channel(pose, bone->name);
+ if(pchan)
+ pose_grab_with_ik_add(pchan);
+ }
+}
+
+/* main call which adds temporal IK chains */
+static void pose_grab_with_ik(Object *ob)
+{
+ bArmature *arm;
+ bPoseChannel *pchan, *pchansel= NULL;
+
+ if(ob==NULL || ob->pose==NULL || (ob->flag & OB_POSEMODE)==0)
+ return;
+
+ arm = ob->data;
+
+ /* rule: only one Bone */
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ if(pchan->bone->layer & arm->layer) {
+ if(pchan->bone->flag & BONE_SELECTED) {
+ if(pchansel)
+ break;
+ pchansel= pchan;
+ }
+ }
+ }
+ if(pchan || pchansel==NULL) return;
+
+ /* rule: if selected Bone is not a root bone, it gets a temporal IK */
+ if(pchansel->parent) {
+ /* only adds if there's no IK yet */
+ pose_grab_with_ik_add(pchansel);
+ }
+ else {
+ /* rule: go over the children and add IK to the tips */
+ pose_grab_with_ik_children(ob->pose, pchansel->bone);
+ }
+}
+
+
+
+/* only called with pose mode active object now */
+static void createTransPose(TransInfo *t, Object *ob)
+{
+ bArmature *arm;
+ bPoseChannel *pchan;
+ TransData *td;
+ TransDataExtension *tdx;
+ int i;
+
+ t->total= 0;
+
+ /* check validity of state */
+ arm=get_armature (ob);
+ if (arm==NULL || ob->pose==NULL) return;
+
+ if (arm->flag & ARM_RESTPOS) {
+ if(t->mode!=TFM_BONESIZE) {
+ notice ("Pose edit not possible while Rest Position is enabled");
+ return;
+ }
+ }
+ if (!(ob->lay & G.vd->lay)) return;
+
+ /* do we need to add temporal IK chains? */
+ if((arm->flag & ARM_AUTO_IK) && t->mode==TFM_TRANSLATION)
+ pose_grab_with_ik(ob);
+
+ /* set flags and count total (warning, can change transform to rotate) */
+ set_pose_transflags(t, ob);
+
+ if(t->total==0) return;
+
+ t->flag |= T_POSE;
+ t->poseobj= ob; /* we also allow non-active objects to be transformed, in weightpaint */
+
+ /* make sure the lock is set OK, unlock can be accidentally saved? */
+ ob->pose->flag |= POSE_LOCKED;
+ ob->pose->flag &= ~POSE_DO_UNLOCK;
+
+ /* init trans data */
+ td = t->data = MEM_callocN(t->total*sizeof(TransData), "TransPoseBone");
+ tdx = t->ext = MEM_callocN(t->total*sizeof(TransDataExtension), "TransPoseBoneExt");
+ for(i=0; i<t->total; i++, td++, tdx++) {
+ td->ext= tdx;
+ td->tdi = NULL;
+ td->val = NULL;
+ }
+
+ /* use pose channels to fill trans data */
+ td= t->data;
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ if(pchan->bone->flag & BONE_TRANSFORM) {
+ add_pose_transdata(t, pchan, ob, td);
+ td++;
+ }
+ }
+
+ if(td != (t->data+t->total)) printf("Bone selection count error\n");
+
+}
+
+/* ********************* armature ************** */
+
+static void createTransArmatureVerts(TransInfo *t)
+{
+ EditBone *ebo;
+ bArmature *arm= G.obedit->data;
+ TransData *td;
+ float mtx[3][3], smtx[3][3], delta[3], bonemat[3][3];
+
+ t->total = 0;
+ for (ebo=G.edbo.first;ebo;ebo=ebo->next) {
+ if(ebo->layer & arm->layer) {
+ if (t->mode==TFM_BONESIZE) {
+ if (ebo->flag & BONE_SELECTED)
+ t->total++;
+ }
+ else if (t->mode==TFM_BONE_ROLL) {
+ if (ebo->flag & BONE_SELECTED)
+ t->total++;
+ }
+ else {
+ if (ebo->flag & BONE_TIPSEL)
+ t->total++;
+ if (ebo->flag & BONE_ROOTSEL)
+ t->total++;
+ }
+ }
+ }
+
+ if (!t->total) return;
+
+ Mat3CpyMat4(mtx, G.obedit->obmat);
+ Mat3Inv(smtx, mtx);
+
+ td = t->data = MEM_callocN(t->total*sizeof(TransData), "TransEditBone");
+
+ for (ebo=G.edbo.first;ebo;ebo=ebo->next){
+ ebo->oldlength= ebo->length; // length==0.0 on extrude, used for scaling radius of bone points
+
+ if(ebo->layer & arm->layer) {
+ if (t->mode==TFM_BONE_ENVELOPE) {
+
+ if (ebo->flag & BONE_ROOTSEL){
+ td->val= &ebo->rad_head;
+ td->ival= *td->val;
+
+ VECCOPY (td->center, ebo->head);
+ td->flag= TD_SELECTED;
+
+ Mat3CpyMat3(td->smtx, smtx);
+ Mat3CpyMat3(td->mtx, mtx);
+
+ td->loc = NULL;
+ td->ext = NULL;
+ td->tdi = NULL;
+
+ td++;
+ }
+ if (ebo->flag & BONE_TIPSEL){
+ td->val= &ebo->rad_tail;
+ td->ival= *td->val;
+ VECCOPY (td->center, ebo->tail);
+ td->flag= TD_SELECTED;
+
+ Mat3CpyMat3(td->smtx, smtx);
+ Mat3CpyMat3(td->mtx, mtx);
+
+ td->loc = NULL;
+ td->ext = NULL;
+ td->tdi = NULL;
+
+ td++;
+ }
+
+ }
+ else if (t->mode==TFM_BONESIZE) {
+ if (ebo->flag & BONE_SELECTED) {
+ if(arm->drawtype==ARM_ENVELOPE) {
+ td->loc= NULL;
+ td->val= &ebo->dist;
+ td->ival= ebo->dist;
+ }
+ else {
+ // abusive storage of scale in the loc pointer :)
+ td->loc= &ebo->xwidth;
+ VECCOPY (td->iloc, td->loc);
+ td->val= NULL;
+ }
+ VECCOPY (td->center, ebo->head);
+ td->flag= TD_SELECTED;
+
+ /* use local bone matrix */
+ VecSubf(delta, ebo->tail, ebo->head);
+ vec_roll_to_mat3(delta, ebo->roll, bonemat);
+ Mat3MulMat3(td->mtx, mtx, bonemat);
+ Mat3Inv(td->smtx, td->mtx);
+
+ Mat3CpyMat3(td->axismtx, td->mtx);
+ Mat3Ortho(td->axismtx);
+
+ td->ext = NULL;
+ td->tdi = NULL;
+
+ td++;
+ }
+ }
+ else if (t->mode==TFM_BONE_ROLL) {
+ if (ebo->flag & BONE_SELECTED) {
+ td->loc= NULL;
+ td->val= &(ebo->roll);
+ td->ival= ebo->roll;
+
+ VECCOPY (td->center, ebo->head);
+ td->flag= TD_SELECTED;
+
+ td->ext = NULL;
+ td->tdi = NULL;
+
+ td++;
+ }
+ }
+ else {
+ if (ebo->flag & BONE_TIPSEL){
+ VECCOPY (td->iloc, ebo->tail);
+ VECCOPY (td->center, td->iloc);
+ td->loc= ebo->tail;
+ td->flag= TD_SELECTED;
+
+ Mat3CpyMat3(td->smtx, smtx);
+ Mat3CpyMat3(td->mtx, mtx);
+
+ td->ext = NULL;
+ td->tdi = NULL;
+ td->val = NULL;
+
+ td++;
+ }
+ if (ebo->flag & BONE_ROOTSEL){
+ VECCOPY (td->iloc, ebo->head);
+ VECCOPY (td->center, td->iloc);
+ td->loc= ebo->head;
+ td->flag= TD_SELECTED;
+
+ Mat3CpyMat3(td->smtx, smtx);
+ Mat3CpyMat3(td->mtx, mtx);
+
+ td->ext = NULL;
+ td->tdi = NULL;
+ td->val = NULL;
+
+ td++;
+ }
+ }
+ }
+ }
+}
+
+/* ********************* meta elements ********* */
+
+static void createTransMBallVerts(TransInfo *t)
+{
+ MetaElem *ml;
+ TransData *td;
+ TransDataExtension *tx;
+ float mtx[3][3], smtx[3][3];
+ int count=0, countsel=0;
+ int propmode = t->flag & T_PROP_EDIT;
+
+ /* count totals */
+ for(ml= editelems.first; ml; ml= ml->next) {
+ if(ml->flag & SELECT) countsel++;
+ if(propmode) count++;
+ }
+
+ /* note: in prop mode we need at least 1 selected */
+ if (countsel==0) return;
+
+ if(propmode) t->total = count;
+ else t->total = countsel;
+
+ td = t->data= MEM_callocN(t->total*sizeof(TransData), "TransObData(MBall EditMode)");
+ tx = t->ext = MEM_callocN(t->total*sizeof(TransDataExtension), "MetaElement_TransExtension");
+
+ Mat3CpyMat4(mtx, G.obedit->obmat);
+ Mat3Inv(smtx, mtx);
+
+ for(ml= editelems.first; ml; ml= ml->next) {
+ if(propmode || (ml->flag & SELECT)) {
+ td->loc= &ml->x;
+ VECCOPY(td->iloc, td->loc);
+ VECCOPY(td->center, td->loc);
+
+ if(ml->flag & SELECT) td->flag= TD_SELECTED | TD_USEQUAT | TD_SINGLESIZE;
+ else td->flag= TD_USEQUAT;
+
+ Mat3CpyMat3(td->smtx, smtx);
+ Mat3CpyMat3(td->mtx, mtx);
+
+ td->ext = tx;
+ td->tdi = NULL;
+
+ /* Radius of MetaElem (mass of MetaElem influence) */
+ if(ml->flag & MB_SCALE_RAD){
+ td->val = &ml->rad;
+ td->ival = ml->rad;
+ }
+ else{
+ td->val = &ml->s;
+ td->ival = ml->s;
+ }
+
+ /* expx/expy/expz determine "shape" of some MetaElem types */
+ tx->size = &ml->expx;
+ tx->isize[0] = ml->expx;
+ tx->isize[1] = ml->expy;
+ tx->isize[2] = ml->expz;
+
+ /* quat is used for rotation of MetaElem */
+ tx->quat = ml->quat;
+ QUATCOPY(tx->iquat, ml->quat);
+
+ tx->rot = NULL;
+
+ td++;
+ tx++;
+ }
+ }
+}
+
+/* ********************* curve/surface ********* */
+
+static void calc_distanceCurveVerts(TransData *head, TransData *tail) {
+ TransData *td, *td_near = NULL;
+ for (td = head; td<=tail; td++) {
+ if (td->flag & TD_SELECTED) {
+ td_near = td;
+ td->dist = 0.0f;
+ }
+ else if(td_near) {
+ float dist;
+ dist = VecLenf(td_near->center, td->center);
+ if (dist < (td-1)->dist) {
+ td->dist = (td-1)->dist;
+ }
+ else {
+ td->dist = dist;
+ }
+ }
+ else {
+ td->dist = MAXFLOAT;
+ td->flag |= TD_NOTCONNECTED;
+ }
+ }
+ td_near = NULL;
+ for (td = tail; td>=head; td--) {
+ if (td->flag & TD_SELECTED) {
+ td_near = td;
+ td->dist = 0.0f;
+ }
+ else if(td_near) {
+ float dist;
+ dist = VecLenf(td_near->center, td->center);
+ if (td->flag & TD_NOTCONNECTED || dist < td->dist || (td+1)->dist < td->dist) {
+ td->flag &= ~TD_NOTCONNECTED;
+ if (dist < (td+1)->dist) {
+ td->dist = (td+1)->dist;
+ }
+ else {
+ td->dist = dist;
+ }
+ }
+ }
+ }
+}
+
+static void createTransCurveVerts(TransInfo *t)
+{
+ TransData *td = NULL;
+ Nurb *nu;
+ BezTriple *bezt;
+ BPoint *bp;
+ float mtx[3][3], smtx[3][3];
+ int a;
+ int count=0, countsel=0;
+ int propmode = t->flag & T_PROP_EDIT;
+
+ /* count total of vertices, check identical as in 2nd loop for making transdata! */
+ for(nu= editNurb.first; nu; nu= nu->next) {
+ if((nu->type & 7)==CU_BEZIER) {
+ for(a=0, bezt= nu->bezt; a<nu->pntsu; a++, bezt++) {
+ if(bezt->hide==0) {
+ if (G.f & G_HIDDENHANDLES) {
+ if(bezt->f2 & 1) countsel+=3;
+ if(propmode) count+= 3;
+ } else {
+ if(bezt->f1 & 1) countsel++;
+ if(bezt->f2 & 1) countsel++;
+ if(bezt->f3 & 1) countsel++;
+ if(propmode) count+= 3;
+ }
+ }
+ }
+ }
+ else {
+ for(a= nu->pntsu*nu->pntsv, bp= nu->bp; a>0; a--, bp++) {
+ if(bp->hide==0) {
+ if(propmode) count++;
+ if(bp->f1 & 1) countsel++;
+ }
+ }
+ }
+ }
+ /* note: in prop mode we need at least 1 selected */
+ if (countsel==0) return;
+
+ if(propmode) t->total = count;
+ else t->total = countsel;
+ t->data= MEM_callocN(t->total*sizeof(TransData), "TransObData(Curve EditMode)");
+
+ Mat3CpyMat4(mtx, G.obedit->obmat);
+ Mat3Inv(smtx, mtx);
+
+ td = t->data;
+ for(nu= editNurb.first; nu; nu= nu->next) {
+ if((nu->type & 7)==CU_BEZIER) {
+ TransData *head, *tail;
+ head = tail = td;
+ for(a=0, bezt= nu->bezt; a<nu->pntsu; a++, bezt++) {
+ if(bezt->hide==0) {
+
+ if( propmode ||
+ ((bezt->f2 & 1) && (G.f & G_HIDDENHANDLES)) ||
+ ((bezt->f1 & 1) && (G.f & G_HIDDENHANDLES)==0)
+ ) {
+ VECCOPY(td->iloc, bezt->vec[0]);
+ td->loc= bezt->vec[0];
+ VECCOPY(td->center, bezt->vec[1]);
+ if(bezt->f1 & 1 || G.f & G_HIDDENHANDLES) td->flag= TD_SELECTED;
+ else td->flag= 0;
+ td->ext = NULL;
+ td->tdi = NULL;
+ td->val = NULL;
+
+ Mat3CpyMat3(td->smtx, smtx);
+ Mat3CpyMat3(td->mtx, mtx);
+
+ td++;
+ count++;
+ tail++;
+ }
+
+ /* This is the Curve Point, the other two are handles */
+ if(propmode || (bezt->f2 & 1)) {
+ VECCOPY(td->iloc, bezt->vec[1]);
+ td->loc= bezt->vec[1];
+ VECCOPY(td->center, td->loc);
+ if(bezt->f2 & 1) td->flag= TD_SELECTED;
+ else td->flag= 0;
+ td->ext = NULL;
+ td->tdi = NULL;
+
+ if (t->mode==TFM_CURVE_SHRINKFATTEN) { /* || t->mode==TFM_RESIZE) {*/ /* TODO - make points scale */
+ td->val = &(bezt->radius);
+ td->ival = bezt->radius;
+ } else if (t->mode==TFM_TILT) {
+ td->val = &(bezt->alfa);
+ td->ival = bezt->alfa;
+ } else {
+ td->val = NULL;
+ }
+
+ Mat3CpyMat3(td->smtx, smtx);
+ Mat3CpyMat3(td->mtx, mtx);
+
+ td++;
+ count++;
+ tail++;
+ }
+ if( propmode ||
+ ((bezt->f1 & 1) && (G.f & G_HIDDENHANDLES)) ||
+ ((bezt->f3 & 1) && (G.f & G_HIDDENHANDLES)==0)
+ ) {
+ VECCOPY(td->iloc, bezt->vec[2]);
+ td->loc= bezt->vec[2];
+ VECCOPY(td->center, bezt->vec[1]);
+ if(bezt->f3 & 1 || (G.f & G_HIDDENHANDLES)) td->flag= TD_SELECTED;
+ else td->flag= 0;
+ td->ext = NULL;
+ td->tdi = NULL;
+ td->val = NULL;
+
+ Mat3CpyMat3(td->smtx, smtx);
+ Mat3CpyMat3(td->mtx, mtx);
+
+ td++;
+ count++;
+ tail++;
+ }
+ }
+ else if (propmode && head != tail) {
+ calc_distanceCurveVerts(head, tail-1);
+ head = tail;
+ }
+ }
+ if (propmode && head != tail)
+ calc_distanceCurveVerts(head, tail-1);
+ }
+ else {
+ TransData *head, *tail;
+ head = tail = td;
+ for(a= nu->pntsu*nu->pntsv, bp= nu->bp; a>0; a--, bp++) {
+ if(bp->hide==0) {
+ if(propmode || (bp->f1 & 1)) {
+ VECCOPY(td->iloc, bp->vec);
+ td->loc= bp->vec;
+ VECCOPY(td->center, td->loc);
+ if(bp->f1 & 1) td->flag= TD_SELECTED;
+ else td->flag= 0;
+ td->ext = NULL;
+ td->tdi = NULL;
+
+ if (t->mode==TFM_CURVE_SHRINKFATTEN || t->mode==TFM_RESIZE) {
+ td->val = &(bp->radius);
+ td->ival = bp->radius;
+ } else {
+ td->val = &(bp->alfa);
+ td->ival = bp->alfa;
+ }
+
+ Mat3CpyMat3(td->smtx, smtx);
+ Mat3CpyMat3(td->mtx, mtx);
+
+ td++;
+ count++;
+ tail++;
+ }
+ }
+ else if (propmode && head != tail) {
+ calc_distanceCurveVerts(head, tail-1);
+ head = tail;
+ }
+ }
+ if (propmode && head != tail)
+ calc_distanceCurveVerts(head, tail-1);
+ }
+ }
+}
+
+/* ********************* lattice *************** */
+
+static void createTransLatticeVerts(TransInfo *t)
+{
+ TransData *td = NULL;
+ BPoint *bp;
+ float mtx[3][3], smtx[3][3];
+ int a;
+ int count=0, countsel=0;
+ int propmode = t->flag & T_PROP_EDIT;
+
+ bp= editLatt->def;
+ a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
+ while(a--) {
+ if(bp->hide==0) {
+ if(bp->f1 & 1) countsel++;
+ if(propmode) count++;
+ }
+ bp++;
+ }
+
+ /* note: in prop mode we need at least 1 selected */
+ if (countsel==0) return;
+
+ if(propmode) t->total = count;
+ else t->total = countsel;
+ t->data= MEM_callocN(t->total*sizeof(TransData), "TransObData(Lattice EditMode)");
+
+ Mat3CpyMat4(mtx, G.obedit->obmat);
+ Mat3Inv(smtx, mtx);
+
+ td = t->data;
+ bp= editLatt->def;
+ a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
+ while(a--) {
+ if(propmode || (bp->f1 & 1)) {
+ if(bp->hide==0) {
+ VECCOPY(td->iloc, bp->vec);
+ td->loc= bp->vec;
+ VECCOPY(td->center, td->loc);
+ if(bp->f1 & 1) td->flag= TD_SELECTED;
+ else td->flag= 0;
+ Mat3CpyMat3(td->smtx, smtx);
+ Mat3CpyMat3(td->mtx, mtx);
+
+ td->ext = NULL;
+ td->tdi = NULL;
+ td->val = NULL;
+
+ td++;
+ count++;
+ }
+ }
+ bp++;
+ }
+}
+
+/* ********************* mesh ****************** */
+
+/* proportional distance based on connectivity */
+#define E_VEC(a) (vectors + (3 * (a)->tmp.l))
+#define E_NEAR(a) (nears[((a)->tmp.l)])
+#define THRESHOLD 0.0001f
+static void editmesh_set_connectivity_distance(int total, float *vectors, EditVert **nears)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+ EditEdge *eed;
+ int i= 0, done= 1;
+
+ /* f2 flag is used for 'selection' */
+ /* tmp.l is offset on scratch array */
+ for(eve= em->verts.first; eve; eve= eve->next) {
+ if(eve->h==0) {
+ eve->tmp.l = i++;
+
+ if(eve->f & SELECT) {
+ eve->f2= 2;
+ E_NEAR(eve) = eve;
+ E_VEC(eve)[0] = 0.0f;
+ E_VEC(eve)[1] = 0.0f;
+ E_VEC(eve)[2] = 0.0f;
+ }
+ else {
+ eve->f2 = 0;
+ }
+ }
+ }
+
+
+ /* Floodfill routine */
+ /*
+ At worst this is n*n of complexity where n is number of edges
+ Best case would be n if the list is ordered perfectly.
+ Estimate is n log n in average (so not too bad)
+ */
+ while(done) {
+ done= 0;
+
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->h==0) {
+ EditVert *v1= eed->v1, *v2= eed->v2;
+ float *vec2 = E_VEC(v2);
+ float *vec1 = E_VEC(v1);
+
+ if (v1->f2 + v2->f2 == 4)
+ continue;
+
+ if (v1->f2) {
+ if (v2->f2) {
+ float nvec[3];
+ float len1 = VecLength(vec1);
+ float len2 = VecLength(vec2);
+ float lenn;
+ /* for v2 if not selected */
+ if (v2->f2 != 2) {
+ VecSubf(nvec, v2->co, E_NEAR(v1)->co);
+ lenn = VecLength(nvec);
+ /* 1 < n < 2 */
+ if (lenn - len1 > THRESHOLD && len2 - lenn > THRESHOLD) {
+ VECCOPY(vec2, nvec);
+ E_NEAR(v2) = E_NEAR(v1);
+ done = 1;
+ }
+ /* n < 1 < 2 */
+ else if (len2 - len1 > THRESHOLD && len1 - lenn > THRESHOLD) {
+ VECCOPY(vec2, vec1);
+ E_NEAR(v2) = E_NEAR(v1);
+ done = 1;
+ }
+ }
+ /* for v1 if not selected */
+ if (v1->f2 != 2) {
+ VecSubf(nvec, v1->co, E_NEAR(v2)->co);
+ lenn = VecLength(nvec);
+ /* 2 < n < 1 */
+ if (lenn - len2 > THRESHOLD && len1 - lenn > THRESHOLD) {
+ VECCOPY(vec1, nvec);
+ E_NEAR(v1) = E_NEAR(v2);
+ done = 1;
+ }
+ /* n < 2 < 1 */
+ else if (len1 - len2 > THRESHOLD && len2 - lenn > THRESHOLD) {
+ VECCOPY(vec1, vec2);
+ E_NEAR(v1) = E_NEAR(v2);
+ done = 1;
+ }
+ }
+ }
+ else {
+ v2->f2 = 1;
+ VecSubf(vec2, v2->co, E_NEAR(v1)->co);
+ /* 2 < 1 */
+ if (VecLength(vec1) - VecLength(vec2) > THRESHOLD) {
+ VECCOPY(vec2, vec1);
+ }
+ E_NEAR(v2) = E_NEAR(v1);
+ done = 1;
+ }
+ }
+ else if (v2->f2) {
+ v1->f2 = 1;
+ VecSubf(vec1, v1->co, E_NEAR(v2)->co);
+ /* 2 < 1 */
+ if (VecLength(vec2) - VecLength(vec1) > THRESHOLD) {
+ VECCOPY(vec1, vec2);
+ }
+ E_NEAR(v1) = E_NEAR(v2);
+ done = 1;
+ }
+ }
+ }
+ }
+}
+
+/* loop-in-a-loop I know, but we need it! (ton) */
+static void get_face_center(float *cent, EditVert *eve)
+{
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+
+ for(efa= em->faces.first; efa; efa= efa->next)
+ if(efa->f & SELECT)
+ if(efa->v1==eve || efa->v2==eve || efa->v3==eve || efa->v4==eve)
+ break;
+ if(efa) {
+ VECCOPY(cent, efa->cent);
+ }
+}
+
+static void VertsToTransData(TransData *td, EditVert *eve)
+{
+ td->flag = 0;
+ td->loc = eve->co;
+
+ VECCOPY(td->center, td->loc);
+ if(G.vd->around==V3D_LOCAL && (G.scene->selectmode & SCE_SELECT_FACE))
+ get_face_center(td->center, eve);
+ VECCOPY(td->iloc, td->loc);
+
+ // Setting normals
+ VECCOPY(td->axismtx[2], eve->no);
+ td->axismtx[0][0] =
+ td->axismtx[0][1] =
+ td->axismtx[0][2] =
+ td->axismtx[1][0] =
+ td->axismtx[1][1] =
+ td->axismtx[1][2] = 0.0f;
+
+ td->ext = NULL;
+ td->tdi = NULL;
+ td->val = NULL;
+ td->tdmir= NULL;
+
+#ifdef WITH_VERSE
+ if(eve->vvert) {
+ td->verse = (void*)eve->vvert;
+ td->flag |= TD_VERSE_VERT;
+ }
+ else
+ td->flag &= ~TD_VERSE_VERT;
+#endif
+}
+
+/* *********************** CrazySpace correction. Now without doing subsurf optimal ****************** */
+
+static void make_vertexcos__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s)
+{
+ float *vec = userData;
+
+ vec+= 3*index;
+ VECCOPY(vec, co);
+}
+
+static int modifiers_disable_subsurf_temporary(Object *ob)
+{
+ ModifierData *md;
+ int disabled = 0;
+
+ for(md=ob->modifiers.first; md; md=md->next)
+ if(md->type==eModifierType_Subsurf)
+ if(md->mode & eModifierMode_OnCage) {
+ md->mode ^= eModifierMode_DisableTemporary;
+ disabled= 1;
+ }
+
+ return disabled;
+}
+
+/* disable subsurf temporal, get mapped cos, and enable it */
+static float *get_crazy_mapped_editverts(void)
+{
+ DerivedMesh *dm;
+ float *vertexcos;
+
+ /* disable subsurf temporal, get mapped cos, and enable it */
+ if(modifiers_disable_subsurf_temporary(G.obedit)) {
+ /* need to make new derivemesh */
+ makeDerivedMesh(G.obedit, CD_MASK_BAREMESH);
+ }
+
+ /* now get the cage */
+ dm= editmesh_get_derived_cage(CD_MASK_BAREMESH);
+
+ vertexcos= MEM_mallocN(3*sizeof(float)*G.totvert, "vertexcos map");
+ dm->foreachMappedVert(dm, make_vertexcos__mapFunc, vertexcos);
+
+ dm->release(dm);
+
+ /* set back the flag, no new cage needs to be built, transform does it */
+ modifiers_disable_subsurf_temporary(G.obedit);
+
+ return vertexcos;
+}
+
+#define TAN_MAKE_VEC(a, b, c) a[0]= b[0] + 0.2f*(b[0]-c[0]); a[1]= b[1] + 0.2f*(b[1]-c[1]); a[2]= b[2] + 0.2f*(b[2]-c[2])
+static void set_crazy_vertex_quat(float *quat, float *v1, float *v2, float *v3, float *def1, float *def2, float *def3)
+{
+ float vecu[3], vecv[3];
+ float q1[4], q2[4];
+
+ TAN_MAKE_VEC(vecu, v1, v2);
+ TAN_MAKE_VEC(vecv, v1, v3);
+ triatoquat(v1, vecu, vecv, q1);
+
+ TAN_MAKE_VEC(vecu, def1, def2);
+ TAN_MAKE_VEC(vecv, def1, def3);
+ triatoquat(def1, vecu, vecv, q2);
+
+ QuatSub(quat, q2, q1);
+}
+#undef TAN_MAKE_VEC
+
+static void set_crazyspace_quats(float *origcos, float *mappedcos, float *quats)
+{
+ EditMesh *em = G.editMesh;
+ EditVert *eve, *prev;
+ EditFace *efa;
+ float *v1, *v2, *v3, *v4, *co1, *co2, *co3, *co4;
+ long index= 0;
+
+ /* two abused locations in vertices */
+ for(eve= em->verts.first; eve; eve= eve->next, index++) {
+ eve->tmp.p = NULL;
+ eve->prev= (EditVert *)index;
+ }
+
+ /* first store two sets of tangent vectors in vertices, we derive it just from the face-edges */
+ for(efa= em->faces.first; efa; efa= efa->next) {
+
+ /* retrieve mapped coordinates */
+ v1= mappedcos + 3*(long)(efa->v1->prev);
+ v2= mappedcos + 3*(long)(efa->v2->prev);
+ v3= mappedcos + 3*(long)(efa->v3->prev);
+
+ co1= (origcos)? origcos + 3*(long)(efa->v1->prev): efa->v1->co;
+ co2= (origcos)? origcos + 3*(long)(efa->v2->prev): efa->v2->co;
+ co3= (origcos)? origcos + 3*(long)(efa->v3->prev): efa->v3->co;
+
+ if(efa->v2->tmp.p==NULL && efa->v2->f1) {
+ set_crazy_vertex_quat(quats, co2, co3, co1, v2, v3, v1);
+ efa->v2->tmp.p= (void*)quats;
+ quats+= 4;
+ }
+
+ if(efa->v4) {
+ v4= mappedcos + 3*(long)(efa->v4->prev);
+ co4= (origcos)? origcos + 3*(long)(efa->v4->prev): efa->v4->co;
+
+ if(efa->v1->tmp.p==NULL && efa->v1->f1) {
+ set_crazy_vertex_quat(quats, co1, co2, co4, v1, v2, v4);
+ efa->v1->tmp.p= (void*)quats;
+ quats+= 4;
+ }
+ if(efa->v3->tmp.p==NULL && efa->v3->f1) {
+ set_crazy_vertex_quat(quats, co3, co4, co2, v3, v4, v2);
+ efa->v3->tmp.p= (void*)quats;
+ quats+= 4;
+ }
+ if(efa->v4->tmp.p==NULL && efa->v4->f1) {
+ set_crazy_vertex_quat(quats, co4, co1, co3, v4, v1, v3);
+ efa->v4->tmp.p= (void*)quats;
+ quats+= 4;
+ }
+ }
+ else {
+ if(efa->v1->tmp.p==NULL && efa->v1->f1) {
+ set_crazy_vertex_quat(quats, co1, co2, co3, v1, v2, v3);
+ efa->v1->tmp.p= (void*)quats;
+ quats+= 4;
+ }
+ if(efa->v3->tmp.p==NULL && efa->v3->f1) {
+ set_crazy_vertex_quat(quats, co3, co1, co2, v3, v1, v2);
+ efa->v3->tmp.p= (void*)quats;
+ quats+= 4;
+ }
+ }
+ }
+
+ /* restore abused prev pointer */
+ for(prev= NULL, eve= em->verts.first; eve; prev= eve, eve= eve->next)
+ eve->prev= prev;
+
+}
+
+static void createTransEditVerts(TransInfo *t)
+{
+ TransData *tob = NULL;
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+ EditVert **nears = NULL;
+ float *vectors = NULL, *mappedcos = NULL, *quats= NULL;
+ float mtx[3][3], smtx[3][3], (*defmats)[3][3] = NULL, (*defcos)[3] = NULL;
+ int count=0, countsel=0, a, totleft;
+ int propmode = t->flag & T_PROP_EDIT;
+ int mirror= (G.scene->toolsettings->editbutflag & B_MESH_X_MIRROR);
+
+ // transform now requires awareness for select mode, so we tag the f1 flags in verts
+ if(G.scene->selectmode & SCE_SELECT_VERTEX) {
+ for(eve= em->verts.first; eve; eve= eve->next) {
+ if(eve->h==0 && (eve->f & SELECT))
+ eve->f1= SELECT;
+ else
+ eve->f1= 0;
+ }
+ }
+ else if(G.scene->selectmode & SCE_SELECT_EDGE) {
+ EditEdge *eed;
+ for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->h==0 && (eed->f & SELECT))
+ eed->v1->f1= eed->v2->f1= SELECT;
+ }
+ }
+ else {
+ EditFace *efa;
+ for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->h==0 && (efa->f & SELECT)) {
+ efa->v1->f1= efa->v2->f1= efa->v3->f1= SELECT;
+ if(efa->v4) efa->v4->f1= SELECT;
+ }
+ }
+ }
+
+ /* now we can count */
+ for(eve= em->verts.first; eve; eve= eve->next) {
+ if(eve->h==0) {
+ if(eve->f1) countsel++;
+ if(propmode) count++;
+ }
+ }
+
+ /* note: in prop mode we need at least 1 selected */
+ if (countsel==0) return;
+
+ if(propmode) {
+ t->total = count;
+
+ /* allocating scratch arrays */
+ vectors = (float *)MEM_mallocN(t->total * 3 * sizeof(float), "scratch vectors");
+ nears = (EditVert**)MEM_mallocN(t->total * sizeof(EditVert*), "scratch nears");
+ }
+ else t->total = countsel;
+ tob= t->data= MEM_callocN(t->total*sizeof(TransData), "TransObData(Mesh EditMode)");
+
+ Mat3CpyMat4(mtx, G.obedit->obmat);
+ Mat3Inv(smtx, mtx);
+
+ if(propmode) editmesh_set_connectivity_distance(t->total, vectors, nears);
+
+ /* detect CrazySpace [tm] */
+ if(propmode==0) {
+ if(modifiers_getCageIndex(G.obedit, NULL)>=0) {
+ if(modifiers_isDeformed(G.obedit)) {
+ /* check if we can use deform matrices for modifier from the
+ start up to stack, they are more accurate than quats */
+ totleft= editmesh_get_first_deform_matrices(&defmats, &defcos);
+
+ /* if we still have more modifiers, also do crazyspace
+ correction with quats, relative to the coordinates after
+ the modifiers that support deform matrices (defcos) */
+ if(totleft > 0) {
+ mappedcos= get_crazy_mapped_editverts();
+ quats= MEM_mallocN( (t->total)*sizeof(float)*4, "crazy quats");
+ set_crazyspace_quats((float*)defcos, mappedcos, quats);
+ if(mappedcos)
+ MEM_freeN(mappedcos);
+ }
+
+ if(defcos)
+ MEM_freeN(defcos);
+ }
+ }
+ }
+
+ /* find out which half we do */
+ if(mirror) {
+ for (eve=em->verts.first; eve; eve=eve->next) {
+ if(eve->h==0 && eve->f1 && eve->co[0]!=0.0f) {
+ if(eve->co[0]<0.0f)
+ mirror = -1;
+ break;
+ }
+ }
+ }
+
+ for (a=0, eve=em->verts.first; eve; eve=eve->next, a++) {
+ if(eve->h==0) {
+ if(propmode || eve->f1) {
+ VertsToTransData(tob, eve);
+
+ if(eve->f1) tob->flag |= TD_SELECTED;
+ if(propmode) {
+ if (eve->f2) {
+ float vec[3];
+ VECCOPY(vec, E_VEC(eve));
+ Mat3MulVecfl(mtx, vec);
+ tob->dist= VecLength(vec);
+ }
+ else {
+ tob->flag |= TD_NOTCONNECTED;
+ tob->dist = MAXFLOAT;
+ }
+ }
+
+ /* CrazySpace */
+ if(defmats || (quats && eve->tmp.p)) {
+ float mat[3][3], imat[3][3], qmat[3][3];
+
+ /* use both or either quat and defmat correction */
+ if(quats && eve->tmp.f) {
+ QuatToMat3(eve->tmp.p, qmat);
+
+ if(defmats)
+ Mat3MulSerie(mat, mtx, qmat, defmats[a],
+ NULL, NULL, NULL, NULL, NULL);
+ else
+ Mat3MulMat3(mat, mtx, qmat);
+ }
+ else
+ Mat3MulMat3(mat, mtx, defmats[a]);
+
+ Mat3Inv(imat, mat);
+
+ Mat3CpyMat3(tob->smtx, imat);
+ Mat3CpyMat3(tob->mtx, mat);
+ }
+ else {
+ Mat3CpyMat3(tob->smtx, smtx);
+ Mat3CpyMat3(tob->mtx, mtx);
+ }
+
+ /* Mirror? */
+ if( (mirror>0 && tob->iloc[0]>0.0f) || (mirror<0 && tob->iloc[0]<0.0f)) {
+ EditVert *vmir= editmesh_get_x_mirror_vert(G.obedit, tob->iloc); /* initializes octree on first call */
+ if(vmir!=eve) tob->tdmir= vmir;
+ }
+ tob++;
+ }
+ }
+ }
+ if (propmode) {
+ MEM_freeN(vectors);
+ MEM_freeN(nears);
+ }
+ /* crazy space free */
+ if(quats)
+ MEM_freeN(quats);
+ if(defmats)
+ MEM_freeN(defmats);
+}
+
+/* ********************* UV ****************** */
+
+static void UVsToTransData(TransData *td, TransData2D *td2d, float *uv, int selected)
+{
+ float aspx, aspy;
+
+ transform_aspect_ratio_tface_uv(&aspx, &aspy);
+
+ /* uv coords are scaled by aspects. this is needed for rotations and
+ proportional editing to be consistent with the stretchted uv coords
+ that are displayed. this also means that for display and numinput,
+ and when the the uv coords are flushed, these are converted each time */
+ td2d->loc[0] = uv[0]*aspx;
+ td2d->loc[1] = uv[1]*aspy;
+ td2d->loc[2] = 0.0f;
+ td2d->loc2d = uv;
+
+ td->flag = 0;
+ td->loc = td2d->loc;
+ VECCOPY(td->center, td->loc);
+ VECCOPY(td->iloc, td->loc);
+
+ memset(td->axismtx, 0, sizeof(td->axismtx));
+ td->axismtx[2][2] = 1.0f;
+
+ td->ext= NULL; td->tdi= NULL; td->val= NULL;
+
+ if(selected) {
+ td->flag |= TD_SELECTED;
+ td->dist= 0.0;
+ }
+ else
+ td->dist= MAXFLOAT;
+
+ Mat3One(td->mtx);
+ Mat3One(td->smtx);
+}
+
+static void createTransUVs(TransInfo *t)
+{
+ TransData *td = NULL;
+ TransData2D *td2d = NULL;
+ MTFace *tf;
+ int count=0, countsel=0;
+ int propmode = t->flag & T_PROP_EDIT;
+
+ EditMesh *em = G.editMesh;
+ EditFace *efa;
+
+ if(is_uv_tface_editing_allowed()==0) return;
+
+ /* count */
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ if SIMA_FACEDRAW_CHECK(efa, tf) {
+ if (SIMA_UVSEL_CHECK(efa, tf, 0)) countsel++;
+ if (SIMA_UVSEL_CHECK(efa, tf, 1)) countsel++;
+ if (SIMA_UVSEL_CHECK(efa, tf, 2)) countsel++;
+ if (efa->v4 && SIMA_UVSEL_CHECK(efa, tf, 3)) countsel++;
+ if(propmode)
+ count += (efa->v4)? 4: 3;
+ }
+ }
+
+ /* note: in prop mode we need at least 1 selected */
+ if (countsel==0) return;
+
+ t->total= (propmode)? count: countsel;
+ t->data= MEM_callocN(t->total*sizeof(TransData), "TransObData(UV Editing)");
+ /* for each 2d uv coord a 3d vector is allocated, so that they can be
+ treated just as if they were 3d verts */
+ t->data2d= MEM_callocN(t->total*sizeof(TransData2D), "TransObData2D(UV Editing)");
+
+ if(G.sima->flag & SI_CLIP_UV)
+ t->flag |= T_CLIP_UV;
+
+ td= t->data;
+ td2d= t->data2d;
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ if SIMA_FACEDRAW_CHECK(efa, tf) {
+ if(propmode || SIMA_UVSEL_CHECK(efa, tf, 0))
+ UVsToTransData(td++, td2d++, tf->uv[0], SIMA_UVSEL_CHECK(efa, tf, 0));
+ if(propmode || SIMA_UVSEL_CHECK(efa, tf, 1))
+ UVsToTransData(td++, td2d++, tf->uv[1], SIMA_UVSEL_CHECK(efa, tf, 1));
+ if(propmode || SIMA_UVSEL_CHECK(efa, tf, 2))
+ UVsToTransData(td++, td2d++, tf->uv[2], SIMA_UVSEL_CHECK(efa, tf, 2));
+
+ if(efa->v4 && (propmode || SIMA_UVSEL_CHECK(efa, tf, 3)))
+ UVsToTransData(td++, td2d++, tf->uv[3], SIMA_UVSEL_CHECK(efa, tf, 3));
+ }
+ }
+
+ if (G.sima->flag & SI_LIVE_UNWRAP)
+ unwrap_lscm_live_begin();
+}
+
+void flushTransUVs(TransInfo *t)
+{
+ TransData2D *td;
+ int a, width, height;
+ Object *ob= OBACT;
+ EditMesh *em = G.editMesh;
+ float aspx, aspy, invx, invy;
+
+ transform_aspect_ratio_tface_uv(&aspx, &aspy);
+ transform_width_height_tface_uv(&width, &height);
+ invx= 1.0f/aspx;
+ invy= 1.0f/aspy;
+
+ /* flush to 2d vector from internally used 3d vector */
+ for(a=0, td= t->data2d; a<t->total; a++, td++) {
+ td->loc2d[0]= td->loc[0]*invx;
+ td->loc2d[1]= td->loc[1]*invy;
+
+ if((G.sima->flag & SI_PIXELSNAP) && (t->state != TRANS_CANCEL)) {
+ td->loc2d[0]= floor(width*td->loc2d[0] + 0.5f)/width;
+ td->loc2d[1]= floor(height*td->loc2d[1] + 0.5f)/height;
+ }
+ }
+
+ /* always call this, also for cancel (it transforms non-selected vertices...) */
+ if((G.sima->flag & SI_BE_SQUARE))
+ be_square_tface_uv(em);
+
+ /* this is overkill if G.sima->lock is not set, but still needed */
+ object_uvs_changed(ob);
+}
+
+int clipUVTransform(TransInfo *t, float *vec, int resize)
+{
+ TransData *td;
+ int a, clipx=1, clipy=1;
+ float aspx, aspy, min[2], max[2];
+
+ transform_aspect_ratio_tface_uv(&aspx, &aspy);
+ min[0]= min[1]= 0.0f;
+ max[0]= aspx; max[1]= aspy;
+
+ for(a=0, td= t->data; a<t->total; a++, td++) {
+ DO_MINMAX2(td->loc, min, max);
+ }
+
+ if(resize) {
+ if(min[0] < 0.0f && t->center[0] > 0.0f && t->center[0] < aspx*0.5f)
+ vec[0] *= t->center[0]/(t->center[0] - min[0]);
+ else if(max[0] > aspx && t->center[0] < aspx)
+ vec[0] *= (t->center[0] - aspx)/(t->center[0] - max[0]);
+ else
+ clipx= 0;
+
+ if(min[1] < 0.0f && t->center[1] > 0.0f && t->center[1] < aspy*0.5f)
+ vec[1] *= t->center[1]/(t->center[1] - min[1]);
+ else if(max[1] > aspy && t->center[1] < aspy)
+ vec[1] *= (t->center[1] - aspy)/(t->center[1] - max[1]);
+ else
+ clipy= 0;
+ }
+ else {
+ if(min[0] < 0.0f)
+ vec[0] -= min[0];
+ else if(max[0] > aspx)
+ vec[0] -= max[0]-aspx;
+ else
+ clipx= 0;
+
+ if(min[1] < 0.0f)
+ vec[1] -= min[1];
+ else if(max[1] > aspy)
+ vec[1] -= max[1]-aspy;
+ else
+ clipy= 0;
+ }
+
+ return (clipx || clipy);
+}
+
+/* ********************* IPO EDITOR ************************* */
+
+/* for IPO Editor transform - but actual creation of transform structures is not performed here
+ * due to bad globals that would need to be imported specially for this
+ */
+static void createTransIpoData(TransInfo *t)
+{
+ /* in editipo.c due to some globals that are defined in that file... */
+ make_ipo_transdata(t);
+}
+
+/* this function is called on recalcData to apply the transforms applied
+ * to the transdata on to the actual keyframe data
+ */
+void flushTransIpoData(TransInfo *t)
+{
+ TransData2D *td;
+ int a;
+
+ /* flush to 2d vector from internally used 3d vector */
+ for (a=0, td= t->data2d; a<t->total; a++, td++) {
+ /* we need to unapply the nla-scaling from the time in some situations */
+ if (NLA_IPO_SCALED)
+ td->loc2d[0]= get_action_frame(OBACT, td->loc[0]);
+ else
+ td->loc2d[0]= td->loc[0];
+
+ /* when the icu that point comes from is a bitflag holder, don't allow adjusting values */
+ if ((t->data[a].flag & TD_TIMEONLY)==0)
+ td->loc2d[1]= td->loc[1];
+ }
+}
+
+/* ********************* ACTION/NLA EDITOR ****************** */
+
+/* This function tests if a point is on the "mouse" side of the cursor/frame-marking */
+static short FrameOnMouseSide(char side, float frame, float cframe)
+{
+ /* both sides, so it doesn't matter */
+ if (side == 'B') return 1;
+
+ /* only on the named side */
+ if (side == 'R')
+ return (frame >= cframe) ? 1 : 0;
+ else
+ return (frame <= cframe) ? 1 : 0;
+}
+
+/* fully select selected beztriples, but only include if it's on the right side of cfra */
+static int count_ipo_keys(Ipo *ipo, char side, float cfra)
+{
+ IpoCurve *icu;
+ BezTriple *bezt;
+ int i, count = 0;
+
+ if (ipo == NULL)
+ return count;
+
+ /* only include points that occur on the right side of cfra */
+ for (icu= ipo->curve.first; icu; icu= icu->next) {
+ for (i=0, bezt=icu->bezt; i < icu->totvert; i++, bezt++) {
+ if (bezt->f2) {
+ /* fully select the other two keys */
+ bezt->f1 |= 1;
+ bezt->f3 |= 1;
+
+ /* increment by 3, as there are 3 points (3 * x-coordinates) that need transform */
+ if (FrameOnMouseSide(side, bezt->vec[1][0], cfra))
+ count += 3;
+ }
+ }
+ }
+
+ return count;
+}
+
+/* This function assigns the information to transdata */
+static void TimeToTransData(TransData *td, float *time, Object *ob)
+{
+ /* memory is calloc'ed, so that should zero everything nicely for us */
+ td->val = time;
+ td->ival = *(time);
+
+ /* store the Object where this keyframe exists as a keyframe of the
+ * active action as td->ob. Usually, this member is only used for constraints
+ * drawing
+ */
+ td->ob= ob;
+}
+
+/* This function advances the address to which td points to, so it must return
+ * the new address so that the next time new transform data is added, it doesn't
+ * overwrite the existing ones... i.e. td = IpoToTransData(td, ipo, ob, side, cfra);
+ *
+ * The 'side' argument is needed for the extend mode. 'B' = both sides, 'R'/'L' mean only data
+ * on the named side are used.
+ */
+static TransData *IpoToTransData(TransData *td, Ipo *ipo, Object *ob, char side, float cfra)
+{
+ IpoCurve *icu;
+ BezTriple *bezt;
+ int i;
+
+ if (ipo == NULL)
+ return td;
+
+ for (icu= ipo->curve.first; icu; icu= icu->next) {
+ for (i=0, bezt=icu->bezt; i < icu->totvert; i++, bezt++) {
+ /* only add selected keyframes (for now, proportional edit is not enabled) */
+ if (BEZSELECTED(bezt)) {
+ /* only add if on the right 'side' of the current frame */
+ if (FrameOnMouseSide(side, bezt->vec[1][0], cfra)) {
+ /* each control point needs to be added separetely */
+ TimeToTransData(td, bezt->vec[0], ob);
+ td++;
+
+ TimeToTransData(td, bezt->vec[1], ob);
+ td++;
+
+ TimeToTransData(td, bezt->vec[2], ob);
+ td++;
+ }
+ }
+ }
+ }
+
+ return td;
+}
+
+static void createTransActionData(TransInfo *t)
+{
+ TransData *td = NULL;
+ Object *ob= NULL;
+
+ ListBase act_data = {NULL, NULL};
+ bActListElem *ale;
+ void *data;
+ short datatype;
+ int filter;
+
+ int count=0;
+ float cfra;
+ char side;
+
+ /* determine what type of data we are operating on */
+ data = get_action_context(&datatype);
+ if (data == NULL) return;
+
+ /* filter data */
+ filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS);
+ actdata_filter(&act_data, filter, data, datatype);
+
+ /* is the action scaled? if so, the it should belong to the active object */
+ if (NLA_ACTION_SCALED)
+ ob= OBACT;
+
+ /* which side of the current frame should be allowed */
+ if (t->mode == TFM_TIME_EXTEND) {
+ /* only side on which mouse is gets transformed */
+ float xmouse, ymouse;
+
+ areamouseco_to_ipoco(G.v2d, t->imval, &xmouse, &ymouse);
+ side = (xmouse > CFRA) ? 'R' : 'L';
+ }
+ else {
+ /* normal transform - both sides of current frame are considered */
+ side = 'B';
+ }
+
+ /* convert current-frame to action-time (slightly less accurate, espcially under
+ * higher scaling ratios, but is faster than converting all points)
+ */
+ if (ob)
+ cfra = get_action_frame(ob, CFRA);
+ else
+ cfra = CFRA;
+
+ /* loop 1: fully select ipo-keys and count how many BezTriples are selected */
+ for (ale= act_data.first; ale; ale= ale->next)
+ count += count_ipo_keys(ale->key_data, side, cfra);
+
+ /* stop if trying to build list if nothing selected */
+ if (count == 0) {
+ /* cleanup temp list */
+ BLI_freelistN(&act_data);
+ return;
+ }
+
+ /* allocate memory for data */
+ t->total= count;
+ t->data= MEM_callocN(t->total*sizeof(TransData), "TransData(Action Editor)");
+ if (t->mode == TFM_TIME_SLIDE)
+ t->customData= MEM_callocN(sizeof(float)*2, "TimeSlide Min/Max");
+
+ td= t->data;
+ /* loop 2: build transdata array */
+ for (ale= act_data.first; ale; ale= ale->next) {
+ Ipo *ipo= (Ipo *)ale->key_data;
+
+ td= IpoToTransData(td, ipo, ob, side, cfra);
+ }
+
+ /* check if we're supposed to be setting minx/maxx for TimeSlide */
+ if (t->mode == TFM_TIME_SLIDE) {
+ float min = 0, max = 0;
+ int i;
+
+ td= (t->data + 1);
+ for (i=1; i < count; i+=3, td+=3) {
+ if (min > *(td->val)) min= *(td->val);
+ if (max < *(td->val)) max= *(td->val);
+ }
+
+ /* minx/maxx values used by TimeSlide are stored as a
+ * calloced 2-float array in t->customData. This gets freed
+ * in postTrans (T_FREE_CUSTOMDATA).
+ */
+ *((float *)(t->customData)) = min;
+ *((float *)(t->customData) + 1) = max;
+ }
+
+ /* cleanup temp list */
+ BLI_freelistN(&act_data);
+}
+
+static void createTransNlaData(TransInfo *t)
+{
+ Base *base;
+ bActionStrip *strip;
+ bActionChannel *achan;
+ bConstraintChannel *conchan;
+
+ TransData *td = NULL;
+ int count=0, i;
+ float cfra;
+ char side;
+
+ /* which side of the current frame should be allowed */
+ if (t->mode == TFM_TIME_EXTEND) {
+ /* only side on which mouse is gets transformed */
+ float xmouse, ymouse;
+
+ areamouseco_to_ipoco(G.v2d, t->imval, &xmouse, &ymouse);
+ side = (xmouse > CFRA) ? 'R' : 'L';
+ }
+ else {
+ /* normal transform - both sides of current frame are considered */
+ side = 'B';
+ }
+
+ /* Ensure that partial selections result in beztriple selections */
+ for (base=G.scene->base.first; base; base=base->next) {
+ /* Check object ipos */
+ i= count_ipo_keys(base->object->ipo, side, CFRA);
+ if (i) base->flag |= BA_HAS_RECALC_OB;
+ count += i;
+
+ /* Check object constraint ipos */
+ for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
+ count += count_ipo_keys(conchan->ipo, side, CFRA);
+
+ /* skip actions and nlastrips if object is collapsed */
+ if (base->object->nlaflag & OB_NLA_COLLAPSED)
+ continue;
+
+ /* Check action ipos */
+ if (base->object->action) {
+ /* exclude if strip is selected too */
+ for (strip=base->object->nlastrips.first; strip; strip=strip->next) {
+ if (strip->flag & ACTSTRIP_SELECT)
+ if (strip->act == base->object->action)
+ break;
+ }
+ if (strip==NULL) {
+ cfra = get_action_frame(base->object, CFRA);
+
+ for (achan=base->object->action->chanbase.first; achan; achan=achan->next) {
+ if (EDITABLE_ACHAN(achan)) {
+ i= count_ipo_keys(achan->ipo, side, cfra);
+ if (i) base->flag |= BA_HAS_RECALC_OB|BA_HAS_RECALC_DATA;
+ count += i;
+
+ /* Check action constraint ipos */
+ if (EXPANDED_ACHAN(achan) && FILTER_CON_ACHAN(achan)) {
+ for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next) {
+ if (EDITABLE_CONCHAN(conchan))
+ count += count_ipo_keys(conchan->ipo, side, cfra);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Check nlastrips */
+ for (strip=base->object->nlastrips.first; strip; strip=strip->next) {
+ if (strip->flag & ACTSTRIP_SELECT) {
+ base->flag |= BA_HAS_RECALC_OB|BA_HAS_RECALC_DATA;
+
+ if (FrameOnMouseSide(side, strip->start, CFRA)) count++;
+ if (FrameOnMouseSide(side, strip->end, CFRA)) count++;
+ }
+ }
+ }
+
+ /* If nothing is selected, bail out */
+ if (count == 0)
+ return;
+
+ /* allocate memory for data */
+ t->total= count;
+ t->data= MEM_callocN(t->total*sizeof(TransData), "TransData (NLA Editor)");
+
+ /* build the transdata structure */
+ td= t->data;
+ for (base=G.scene->base.first; base; base=base->next) {
+ /* Manipulate object ipos */
+ /* - no scaling of keyframe times is allowed here */
+ td= IpoToTransData(td, base->object->ipo, NULL, side, CFRA);
+
+ /* Manipulate object constraint ipos */
+ /* - no scaling of keyframe times is allowed here */
+ for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
+ td= IpoToTransData(td, conchan->ipo, NULL, side, CFRA);
+
+ /* skip actions and nlastrips if object collapsed */
+ if (base->object->nlaflag & OB_NLA_COLLAPSED)
+ continue;
+
+ /* Manipulate action ipos */
+ if (base->object->action) {
+ /* exclude if strip that active action belongs to is selected too */
+ for (strip=base->object->nlastrips.first; strip; strip=strip->next) {
+ if (strip->flag & ACTSTRIP_SELECT)
+ if (strip->act == base->object->action)
+ break;
+ }
+
+ /* can include if no strip found */
+ if (strip==NULL) {
+ cfra = get_action_frame(base->object, CFRA);
+
+ for (achan=base->object->action->chanbase.first; achan; achan=achan->next) {
+ if (EDITABLE_ACHAN(achan)) {
+ td= IpoToTransData(td, achan->ipo, base->object, side, cfra);
+
+ /* Manipulate action constraint ipos */
+ if (EXPANDED_ACHAN(achan) && FILTER_CON_ACHAN(achan)) {
+ for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next) {
+ if (EDITABLE_CONCHAN(conchan))
+ td= IpoToTransData(td, conchan->ipo, base->object, side, cfra);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Manipulate nlastrips */
+ for (strip=base->object->nlastrips.first; strip; strip=strip->next) {
+ if (strip->flag & ACTSTRIP_SELECT) {
+ /* first TransData is the start, second is the end */
+ if (FrameOnMouseSide(side, strip->start, CFRA)) {
+ td->val = &strip->start;
+ td->ival = strip->start;
+ td++;
+ }
+ if (FrameOnMouseSide(side, strip->end, CFRA)) {
+ td->val = &strip->end;
+ td->ival = strip->end;
+ td++;
+ }
+ }
+ }
+ }
+}
+
+/* **************** IpoKey stuff, for Object TransData ********** */
+
+/* storage of bezier triple. thats why -3 and +3! */
+static void set_tdi_old(float *old, float *poin)
+{
+ old[0]= *(poin);
+ old[3]= *(poin-3);
+ old[6]= *(poin+3);
+}
+
+/* while transforming */
+void add_tdi_poin(float *poin, float *old, float delta)
+{
+ if(poin) {
+ poin[0]= old[0]+delta;
+ poin[-3]= old[3]+delta;
+ poin[3]= old[6]+delta;
+ }
+}
+
+/* fill ipokey transdata with old vals and pointers */
+static void ipokey_to_transdata(IpoKey *ik, TransData *td)
+{
+ extern int ob_ar[]; // blenkernel ipo.c
+ TransDataIpokey *tdi= td->tdi;
+ BezTriple *bezt;
+ int a, delta= 0;
+
+ td->val= NULL; // is read on ESC
+
+ for(a=0; a<OB_TOTIPO; a++) {
+ if(ik->data[a]) {
+ bezt= ik->data[a];
+
+ switch( ob_ar[a] ) {
+ case OB_LOC_X:
+ case OB_DLOC_X:
+ tdi->locx= &(bezt->vec[1][1]); break;
+ case OB_LOC_Y:
+ case OB_DLOC_Y:
+ tdi->locy= &(bezt->vec[1][1]); break;
+ case OB_LOC_Z:
+ case OB_DLOC_Z:
+ tdi->locz= &(bezt->vec[1][1]); break;
+
+ case OB_DROT_X:
+ delta= 1;
+ case OB_ROT_X:
+ tdi->rotx= &(bezt->vec[1][1]); break;
+ case OB_DROT_Y:
+ delta= 1;
+ case OB_ROT_Y:
+ tdi->roty= &(bezt->vec[1][1]); break;
+ case OB_DROT_Z:
+ delta= 1;
+ case OB_ROT_Z:
+ tdi->rotz= &(bezt->vec[1][1]); break;
+
+ case OB_SIZE_X:
+ case OB_DSIZE_X:
+ tdi->sizex= &(bezt->vec[1][1]); break;
+ case OB_SIZE_Y:
+ case OB_DSIZE_Y:
+ tdi->sizey= &(bezt->vec[1][1]); break;
+ case OB_SIZE_Z:
+ case OB_DSIZE_Z:
+ tdi->sizez= &(bezt->vec[1][1]); break;
+ }
+ }
+ }
+
+ /* oldvals for e.g. undo */
+ if(tdi->locx) set_tdi_old(tdi->oldloc, tdi->locx);
+ if(tdi->locy) set_tdi_old(tdi->oldloc+1, tdi->locy);
+ if(tdi->locz) set_tdi_old(tdi->oldloc+2, tdi->locz);
+
+ /* remember, for mapping curves ('1'=10 degrees) */
+ if(tdi->rotx) set_tdi_old(tdi->oldrot, tdi->rotx);
+ if(tdi->roty) set_tdi_old(tdi->oldrot+1, tdi->roty);
+ if(tdi->rotz) set_tdi_old(tdi->oldrot+2, tdi->rotz);
+
+ /* this is not allowed to be dsize! */
+ if(tdi->sizex) set_tdi_old(tdi->oldsize, tdi->sizex);
+ if(tdi->sizey) set_tdi_old(tdi->oldsize+1, tdi->sizey);
+ if(tdi->sizez) set_tdi_old(tdi->oldsize+2, tdi->sizez);
+
+ tdi->flag= TOB_IPO;
+ if(delta) tdi->flag |= TOB_IPODROT;
+}
+
+
+/* *************************** Object Transform data ******************* */
+
+/* Little helper function for ObjectToTransData used to give certain
+ * constraints (ChildOf, FollowPath, and others that may be added)
+ * inverse corrections for transform, so that they aren't in CrazySpace.
+ * These particular constraints benefit from this, but others don't, hence
+ * this semi-hack ;-) - Aligorith
+ */
+static short constraints_list_needinv(ListBase *list)
+{
+ bConstraint *con;
+
+ /* loop through constraints, checking if there's one of the mentioned
+ * constraints needing special crazyspace corrections
+ */
+ if (list) {
+ for (con= list->first; con; con=con->next) {
+ /* only consider constraint if it is enabled, and has influence on result */
+ if ((con->flag & CONSTRAINT_DISABLE)==0 && (con->enforce!=0.0)) {
+ /* (affirmative) returns for specific constraints here... */
+ if (con->type == CONSTRAINT_TYPE_CHILDOF) return 1;
+ if (con->type == CONSTRAINT_TYPE_FOLLOWPATH) return 1;
+ if (con->type == CONSTRAINT_TYPE_CLAMPTO) return 1;
+ }
+ }
+ }
+
+ /* no appropriate candidates found */
+ return 0;
+}
+
+/* transcribe given object into TransData for Transforming */
+static void ObjectToTransData(TransData *td, Object *ob)
+{
+ Object *track;
+ ListBase fakecons = {NULL, NULL};
+ float obmtx[3][3];
+ short constinv;
+
+ /* axismtx has the real orientation */
+ Mat3CpyMat4(td->axismtx, ob->obmat);
+ Mat3Ortho(td->axismtx);
+
+ /* hack: tempolarily disable tracking and/or constraints when getting
+ * object matrix, if tracking is on, or if constraints don't need
+ * inverse correction to stop it from screwing up space conversion
+ * matrix later
+ */
+ constinv= constraints_list_needinv(&ob->constraints);
+ if (ob->track || constinv==0) {
+ track= ob->track;
+ ob->track= NULL;
+
+ if (constinv == 0) {
+ fakecons.first = ob->constraints.first;
+ fakecons.last = ob->constraints.last;
+ ob->constraints.first = ob->constraints.last = NULL;
+ }
+
+ where_is_object(ob);
+
+ if (constinv == 0) {
+ ob->constraints.first = fakecons.first;
+ ob->constraints.last = fakecons.last;
+ }
+
+ ob->track= track;
+ }
+ else
+ where_is_object(ob);
+
+ td->ob = ob;
+
+ td->loc = ob->loc;
+ VECCOPY(td->iloc, td->loc);
+
+ td->ext->rot = ob->rot;
+ VECCOPY(td->ext->irot, ob->rot);
+ VECCOPY(td->ext->drot, ob->drot);
+
+ td->ext->size = ob->size;
+ VECCOPY(td->ext->isize, ob->size);
+ VECCOPY(td->ext->dsize, ob->dsize);
+
+ VECCOPY(td->center, ob->obmat[3]);
+
+ /* is there a need to set the global<->data space conversion matrices? */
+ if (ob->parent || constinv) {
+ float totmat[3][3], obinv[3][3];
+
+ /* Get the effect of parenting, and/or certain constraints.
+ * NOTE: some Constraints, and also Tracking should never get this
+ * done, as it doesn't work well.
+ */
+ object_to_mat3(ob, obmtx);
+ Mat3CpyMat4(totmat, ob->obmat);
+ Mat3Inv(obinv, totmat);
+ Mat3MulMat3(td->smtx, obmtx, obinv);
+ Mat3Inv(td->mtx, td->smtx);
+ }
+ else {
+ /* no conversion to/from dataspace */
+ Mat3One(td->smtx);
+ Mat3One(td->mtx);
+ }
+#ifdef WITH_VERSE
+ if(ob->vnode) {
+ td->verse = (void*)ob;
+ td->flag |= TD_VERSE_OBJECT;
+ }
+ else
+ td->flag &= ~TD_VERSE_OBJECT;
+#endif
+}
+
+
+/* sets flags in Bases to define whether they take part in transform */
+/* it deselects Bases, so we have to call the clear function always after */
+static void set_trans_object_base_flags(TransInfo *t)
+{
+ /*
+ if Base selected and has parent selected:
+ base->flag= BA_WAS_SEL
+ */
+ Base *base;
+
+ /* makes sure base flags and object flags are identical */
+ copy_baseflags();
+
+ /* handle pending update events, otherwise they got copied below */
+ for (base= FIRSTBASE; base; base= base->next) {
+ if(base->object->recalc)
+ object_handle_update(base->object);
+ }
+
+ for (base= FIRSTBASE; base; base= base->next) {
+ base->flag &= ~BA_WAS_SEL;
+
+ if(TESTBASELIB(base)) {
+ Object *ob= base->object;
+ Object *parsel= ob->parent;
+
+ /* if parent selected, deselect */
+ while(parsel) {
+ if(parsel->flag & SELECT) break;
+ parsel= parsel->parent;
+ }
+
+ if(parsel) {
+ base->flag &= ~SELECT;
+ base->flag |= BA_WAS_SEL;
+ }
+ /* used for flush, depgraph will change recalcs if needed :) */
+ ob->recalc |= OB_RECALC_OB;
+ }
+ }
+ /* all recalc flags get flushed to all layers, so a layer flip later on works fine */
+ DAG_scene_flush_update(G.scene, -1);
+
+ /* and we store them temporal in base (only used for transform code) */
+ /* this because after doing updates, the object->recalc is cleared */
+ for (base= FIRSTBASE; base; base= base->next) {
+ if(base->object->recalc & OB_RECALC_OB)
+ base->flag |= BA_HAS_RECALC_OB;
+ if(base->object->recalc & OB_RECALC_DATA)
+ base->flag |= BA_HAS_RECALC_DATA;
+ }
+}
+
+static void clear_trans_object_base_flags(void)
+{
+ Base *base;
+
+ base= FIRSTBASE;
+ while(base) {
+ if(base->flag & BA_WAS_SEL) base->flag |= SELECT;
+ base->flag &= ~(BA_WAS_SEL|BA_HAS_RECALC_OB|BA_HAS_RECALC_DATA|BA_DO_IPO);
+
+ base = base->next;
+ }
+}
+
+/* auto-keyframing feature - for objects
+ * tmode: should be a transform mode
+ */
+void autokeyframe_ob_cb_func(Object *ob, int tmode)
+{
+ IpoCurve *icu;
+ char *actname="";
+
+ if (G.flags & G_RECORDKEYS) {
+ if(ob->ipoflag & OB_ACTION_OB)
+ actname= "Object";
+
+ if(U.uiflag & USER_KEYINSERTAVAI) {
+ if(ob->ipo || ob->action) {
+ ID *id= (ID *)(ob);
+
+ if (ob->ipo) {
+ icu= ob->ipo->curve.first;
+ }
+ else {
+ bActionChannel *achan;
+ achan= get_action_channel(ob->action, actname);
+
+ if (achan && achan->ipo)
+ icu= achan->ipo->curve.first;
+ else
+ icu= NULL;
+ }
+
+ while(icu) {
+ icu->flag &= ~IPO_SELECT;
+ if (U.uiflag & USER_KEYINSERTNEED)
+ insertkey_smarter(id, ID_OB, actname, NULL, icu->adrcode);
+ else
+ insertkey(id, ID_OB, actname, NULL, icu->adrcode, 0);
+ icu= icu->next;
+ }
+ }
+ }
+ else if (U.uiflag & USER_KEYINSERTNEED) {
+ if (tmode==TFM_RESIZE) {
+ insertkey_smarter(&ob->id, ID_OB, actname, NULL, OB_SIZE_X);
+ insertkey_smarter(&ob->id, ID_OB, actname, NULL, OB_SIZE_Y);
+ insertkey_smarter(&ob->id, ID_OB, actname, NULL, OB_SIZE_Z);
+ }
+ else if (tmode==TFM_ROTATION) {
+ insertkey_smarter(&ob->id, ID_OB, actname, NULL, OB_ROT_X);
+ insertkey_smarter(&ob->id, ID_OB, actname, NULL, OB_ROT_Y);
+ insertkey_smarter(&ob->id, ID_OB, actname, NULL, OB_ROT_Z);
+ }
+ else if (tmode==TFM_TRANSLATION) {
+ insertkey_smarter(&ob->id, ID_OB, actname, NULL, OB_LOC_X);
+ insertkey_smarter(&ob->id, ID_OB, actname, NULL, OB_LOC_Y);
+ insertkey_smarter(&ob->id, ID_OB, actname, NULL, OB_LOC_Z);
+ }
+ }
+ else {
+ insertkey(&ob->id, ID_OB, actname, NULL, OB_ROT_X, 0);
+ insertkey(&ob->id, ID_OB, actname, NULL, OB_ROT_Y, 0);
+ insertkey(&ob->id, ID_OB, actname, NULL, OB_ROT_Z, 0);
+
+ insertkey(&ob->id, ID_OB, actname, NULL, OB_LOC_X, 0);
+ insertkey(&ob->id, ID_OB, actname, NULL, OB_LOC_Y, 0);
+ insertkey(&ob->id, ID_OB, actname, NULL, OB_LOC_Z, 0);
+
+ insertkey(&ob->id, ID_OB, actname, NULL, OB_SIZE_X, 0);
+ insertkey(&ob->id, ID_OB, actname, NULL, OB_SIZE_Y, 0);
+ insertkey(&ob->id, ID_OB, actname, NULL, OB_SIZE_Z, 0);
+ }
+
+ remake_object_ipos(ob);
+ allqueue(REDRAWMARKER, 0);
+ }
+}
+
+/* auto-keyframing feature - for poses/pose-channels
+ * tmode: should be a transform mode
+ * targetless_ik: has targetless ik been done on any channels?
+ */
+void autokeyframe_pose_cb_func(Object *ob, int tmode, short targetless_ik)
+{
+ bAction *act;
+ bPose *pose;
+ bPoseChannel *pchan;
+ IpoCurve *icu;
+
+ pose= ob->pose;
+ act= ob->action;
+
+ if (G.flags & G_RECORDKEYS) {
+ if (!act)
+ act= ob->action= add_empty_action("Action");
+
+ for (pchan=pose->chanbase.first; pchan; pchan=pchan->next) {
+ if (pchan->bone->flag & BONE_TRANSFORM) {
+ /* clear any 'unkeyed' flag it may have */
+ pchan->bone->flag &= ~BONE_UNKEYED;
+
+ /* only insert into available channels? */
+ if(U.uiflag & USER_KEYINSERTAVAI) {
+ bActionChannel *achan;
+
+ for (achan = act->chanbase.first; achan; achan=achan->next){
+ if (achan->ipo && !strcmp (achan->name, pchan->name)){
+ for (icu = achan->ipo->curve.first; icu; icu=icu->next){
+ /* only insert keyframe if needed? */
+ if (U.uiflag & USER_KEYINSERTNEED)
+ insertkey_smarter(&ob->id, ID_PO, pchan->name, NULL, icu->adrcode);
+ else
+ insertkey(&ob->id, ID_PO, pchan->name, NULL, icu->adrcode, 0);
+ }
+ break;
+ }
+ }
+ }
+ /* only insert keyframe if needed? */
+ else if (U.uiflag & USER_KEYINSERTNEED) {
+ if ((tmode==TFM_TRANSLATION) && (targetless_ik==0)) {
+ insertkey_smarter(&ob->id, ID_PO, pchan->name, NULL, AC_LOC_X);
+ insertkey_smarter(&ob->id, ID_PO, pchan->name, NULL, AC_LOC_Y);
+ insertkey_smarter(&ob->id, ID_PO, pchan->name, NULL, AC_LOC_Z);
+ }
+ if ((tmode==TFM_ROTATION) || ((tmode==TFM_TRANSLATION) && targetless_ik)) {
+ insertkey_smarter(&ob->id, ID_PO, pchan->name, NULL, AC_QUAT_W);
+ insertkey_smarter(&ob->id, ID_PO, pchan->name, NULL, AC_QUAT_X);
+ insertkey_smarter(&ob->id, ID_PO, pchan->name, NULL, AC_QUAT_Y);
+ insertkey_smarter(&ob->id, ID_PO, pchan->name, NULL, AC_QUAT_Z);
+ }
+ if (tmode==TFM_RESIZE) {
+ insertkey_smarter(&ob->id, ID_PO, pchan->name, NULL, AC_SIZE_X);
+ insertkey_smarter(&ob->id, ID_PO, pchan->name, NULL, AC_SIZE_Y);
+ insertkey_smarter(&ob->id, ID_PO, pchan->name, NULL, AC_SIZE_Z);
+ }
+ }
+ /* insert keyframe in any channel that's appropriate */
+ else {
+ insertkey(&ob->id, ID_PO, pchan->name, NULL, AC_SIZE_X, 0);
+ insertkey(&ob->id, ID_PO, pchan->name, NULL, AC_SIZE_Y, 0);
+ insertkey(&ob->id, ID_PO, pchan->name, NULL, AC_SIZE_Z, 0);
+
+ insertkey(&ob->id, ID_PO, pchan->name, NULL, AC_QUAT_W, 0);
+ insertkey(&ob->id, ID_PO, pchan->name, NULL, AC_QUAT_X, 0);
+ insertkey(&ob->id, ID_PO, pchan->name, NULL, AC_QUAT_Y, 0);
+ insertkey(&ob->id, ID_PO, pchan->name, NULL, AC_QUAT_Z, 0);
+
+ insertkey(&ob->id, ID_PO, pchan->name, NULL, AC_LOC_X, 0);
+ insertkey(&ob->id, ID_PO, pchan->name, NULL, AC_LOC_Y, 0);
+ insertkey(&ob->id, ID_PO, pchan->name, NULL, AC_LOC_Z, 0);
+ }
+ }
+ }
+
+ remake_action_ipos (act);
+ allqueue(REDRAWMARKER, 0);
+ }
+ else {
+ /* tag channels that should have unkeyed data */
+ for (pchan=pose->chanbase.first; pchan; pchan=pchan->next) {
+ if (pchan->bone->flag & BONE_TRANSFORM) {
+ /* tag this channel */
+ pchan->bone->flag |= BONE_UNKEYED;
+ }
+ }
+ }
+}
+
+/* very bad call!!! - copied from editnla.c! */
+static void recalc_all_ipos(void)
+{
+ Ipo *ipo;
+ IpoCurve *icu;
+
+ /* Go to each ipo */
+ for (ipo=G.main->ipo.first; ipo; ipo=ipo->id.next){
+ for (icu = ipo->curve.first; icu; icu=icu->next){
+ sort_time_ipocurve(icu);
+ testhandles_ipocurve(icu);
+ }
+ }
+}
+
+/* inserting keys, refresh ipo-keys, softbody, redraw events... (ton) */
+/* note: transdata has been freed already! */
+void special_aftertrans_update(TransInfo *t)
+{
+ Object *ob;
+ Base *base;
+ short redrawipo=0, resetslowpar=1;
+ int cancelled= (t->state == TRANS_CANCEL);
+
+ if (t->spacetype==SPACE_VIEW3D)
+ EM_automerge(1);
+
+ if(t->spacetype == SPACE_ACTION) {
+ void *data;
+ short datatype;
+
+ /* determine what type of data we are operating on */
+ data = get_action_context(&datatype);
+ if (data == NULL) return;
+ ob = OBACT;
+
+ if (datatype == ACTCONT_ACTION) {
+ /* Update the curve */
+ /* Depending on the lock status, draw necessary views */
+ if (ob) {
+ ob->ctime= -1234567.0f;
+
+ if(ob->pose || ob_get_key(ob))
+ DAG_object_flush_update(G.scene, ob, OB_RECALC);
+ else
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_OB);
+ }
+
+ remake_action_ipos((bAction *)data);
+
+ G.saction->flag &= ~SACTION_MOVING;
+ }
+ else if (datatype == ACTCONT_SHAPEKEY) {
+ /* fix up the Ipocurves and redraw stuff */
+ Key *key= (Key *)data;
+ if (key->ipo) {
+ IpoCurve *icu;
+
+ for (icu = key->ipo->curve.first; icu; icu=icu->next) {
+ sort_time_ipocurve(icu);
+ testhandles_ipocurve(icu);
+ }
+ }
+
+ DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA);
+ }
+ }
+ else if(t->spacetype == SPACE_NLA) {
+ synchronize_action_strips();
+
+ /* cleanup */
+ for (base=G.scene->base.first; base; base=base->next)
+ base->flag &= ~(BA_HAS_RECALC_OB|BA_HAS_RECALC_DATA);
+
+ recalc_all_ipos(); // bad
+ }
+ else if(t->spacetype == SPACE_IPO) {
+ // FIXME! is there any code from the old transform_ipo that needs to be added back?
+
+ /* resetting slow-parents isn't really necessary when editing sequence ipo's */
+ if (G.sipo->blocktype==ID_SEQ)
+ resetslowpar= 0;
+ }
+ else if(G.obedit) {
+ if(t->mode==TFM_BONESIZE || t->mode==TFM_BONE_ENVELOPE)
+ allqueue(REDRAWBUTSEDIT, 0);
+
+ /* table needs to be created for each edit command, since vertices can move etc */
+ mesh_octree_table(G.obedit, NULL, 'e');
+ }
+ else if( (t->flag & T_POSE) && t->poseobj) {
+ bArmature *arm;
+ bPose *pose;
+ bPoseChannel *pchan;
+ short targetless_ik= 0;
+
+ ob= t->poseobj;
+ arm= ob->data;
+ pose= ob->pose;
+
+ /* this signal does one recalc on pose, then unlocks, so ESC or edit will work */
+ pose->flag |= POSE_DO_UNLOCK;
+
+ /* if target-less IK grabbing, we calculate the pchan transforms and clear flag */
+ if(!cancelled && t->mode==TFM_TRANSLATION)
+ targetless_ik= apply_targetless_ik(ob);
+ else {
+ /* not forget to clear the auto flag */
+ for (pchan=ob->pose->chanbase.first; pchan; pchan=pchan->next) {
+ bKinematicConstraint *data= has_targetless_ik(pchan);
+ if(data) data->flag &= ~CONSTRAINT_IK_AUTO;
+ }
+ }
+
+ if(t->mode==TFM_TRANSLATION)
+ pose_grab_with_ik_clear(ob);
+
+ /* automatic inserting of keys and unkeyed tagging - only if transform wasn't cancelled (or TFM_DUMMY) */
+ if(!cancelled && (t->mode != TFM_DUMMY)) {
+ autokeyframe_pose_cb_func(ob, t->mode, targetless_ik);
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ }
+ else if(arm->flag & ARM_DELAYDEFORM) {
+ /* old optimize trick... this enforces to bypass the depgraph */
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ ob->recalc= 0; // is set on OK position already by recalcData()
+ }
+ else
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+
+ if(t->mode==TFM_BONESIZE || t->mode==TFM_BONE_ENVELOPE)
+ allqueue(REDRAWBUTSEDIT, 0);
+
+ }
+ else {
+ base= FIRSTBASE;
+ while(base) {
+
+ if(base->flag & BA_DO_IPO) redrawipo= 1;
+
+ ob= base->object;
+
+ if(modifiers_isSoftbodyEnabled(ob)) ob->softflag |= OB_SB_REDO;
+
+ /* Set autokey if necessary */
+ if ((!cancelled) && (t->mode != TFM_DUMMY) && (base->flag & SELECT)) {
+ autokeyframe_ob_cb_func(ob, t->mode);
+ }
+
+ base= base->next;
+ }
+
+ }
+
+ clear_trans_object_base_flags();
+
+ if(redrawipo) {
+ allqueue(REDRAWNLA, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWIPO, 0);
+ }
+
+ if(resetslowpar)
+ reset_slowparents();
+
+ /* note; should actually only be done for all objects when a lamp is moved... (ton) */
+ if(t->spacetype==SPACE_VIEW3D && G.vd->drawtype == OB_SHADED)
+ reshadeall_displist();
+}
+
+static void createTransObject(TransInfo *t)
+{
+ TransData *td = NULL;
+ TransDataExtension *tx;
+ Object *ob;
+ Base *base;
+ IpoKey *ik;
+ ListBase elems;
+
+ set_trans_object_base_flags(t);
+
+ /* count */
+ for(base= FIRSTBASE; base; base= base->next) {
+ if TESTBASELIB(base) {
+ ob= base->object;
+
+ /* store ipo keys? */
+ if(ob->ipo && ob->ipo->showkey && (ob->ipoflag & OB_DRAWKEY)) {
+ elems.first= elems.last= NULL;
+ make_ipokey_transform(ob, &elems, 1); /* '1' only selected keys */
+
+ pushdata(&elems, sizeof(ListBase));
+
+ for(ik= elems.first; ik; ik= ik->next) t->total++;
+
+ if(elems.first==NULL) t->total++;
+ }
+ else {
+ t->total++;
+ }
+ }
+ }
+
+ if(!t->total) {
+ /* clear here, main transform function escapes too */
+ clear_trans_object_base_flags();
+ return;
+ }
+
+ td = t->data = MEM_callocN(t->total*sizeof(TransData), "TransOb");
+ tx = t->ext = MEM_callocN(t->total*sizeof(TransDataExtension), "TransObExtension");
+
+ for(base= FIRSTBASE; base; base= base->next) {
+ if TESTBASELIB(base) {
+ ob= base->object;
+
+ td->flag= TD_SELECTED;
+ td->protectflag= ob->protectflag;
+ td->ext = tx;
+
+ /* store ipo keys? */
+ if(ob->ipo && ob->ipo->showkey && (ob->ipoflag & OB_DRAWKEY)) {
+
+ popfirst(&elems); // bring back pushed listbase
+
+ if(elems.first) {
+ int cfraont;
+ int ipoflag;
+
+ base->flag |= BA_DO_IPO+BA_WAS_SEL;
+ base->flag &= ~SELECT;
+
+ cfraont= CFRA;
+ set_no_parent_ipo(1);
+ ipoflag= ob->ipoflag;
+ ob->ipoflag &= ~OB_OFFS_OB;
+
+ /*
+ * This is really EVIL code that pushes down Object values
+ * (loc, dloc, orig, size, dsize, rot, drot)
+ * */
+
+ pushdata((void*)ob->loc, 7 * 3 * sizeof(float)); // tsk! tsk!
+
+ for(ik= elems.first; ik; ik= ik->next) {
+
+ /* weak... this doesn't correct for floating values, giving small errors */
+ CFRA= (int)(ik->val/G.scene->r.framelen);
+
+ do_ob_ipo(ob);
+ ObjectToTransData(td, ob); // does where_is_object()
+
+ td->flag= TD_SELECTED;
+
+ td->tdi= MEM_callocN(sizeof(TransDataIpokey), "TransDataIpokey");
+ /* also does tdi->flag and oldvals, needs to be after ob_to_transob()! */
+ ipokey_to_transdata(ik, td);
+
+ td++;
+ tx++;
+ if(ik->next) td->ext= tx; // prevent corrupting mem!
+ }
+ free_ipokey(&elems);
+
+ poplast(ob->loc);
+ set_no_parent_ipo(0);
+
+ CFRA= cfraont;
+ ob->ipoflag= ipoflag;
+
+ where_is_object(ob); // restore
+ }
+ else {
+ ObjectToTransData(td, ob);
+ td->tdi = NULL;
+ td->val = NULL;
+ td++;
+ tx++;
+ }
+ }
+ else {
+ ObjectToTransData(td, ob);
+ td->tdi = NULL;
+ td->val = NULL;
+ td++;
+ tx++;
+ }
+ }
+ }
+}
+
+void createTransData(TransInfo *t)
+{
+ Object *ob= OBACT;
+
+ if (t->context == CTX_TEXTURE) {
+ t->flag |= T_TEXTURE;
+ createTransTexspace(t);
+ }
+ else if (t->context == CTX_EDGE) {
+ t->ext = NULL;
+ t->flag |= T_EDIT;
+ createTransEdge(t);
+ if(t->data && t->flag & T_PROP_EDIT) {
+ sort_trans_data(t); // makes selected become first in array
+ set_prop_dist(t, 1);
+ sort_trans_data_dist(t);
+ }
+ }
+ else if (t->spacetype == SPACE_IMAGE) {
+ t->flag |= T_POINTS|T_2D_EDIT;
+ createTransUVs(t);
+ if(t->data && (t->flag & T_PROP_EDIT)) {
+ sort_trans_data(t); // makes selected become first in array
+ set_prop_dist(t, 1);
+ sort_trans_data_dist(t);
+ }
+ }
+ else if (t->spacetype == SPACE_ACTION) {
+ t->flag |= T_POINTS|T_2D_EDIT;
+ createTransActionData(t);
+ }
+ else if (t->spacetype == SPACE_NLA) {
+ t->flag |= T_POINTS|T_2D_EDIT;
+ createTransNlaData(t);
+ }
+ else if (t->spacetype == SPACE_IPO) {
+ t->flag |= T_POINTS|T_2D_EDIT;
+ createTransIpoData(t);
+ if (t->data && (t->flag & T_PROP_EDIT)) {
+ sort_trans_data(t); // makes selected become first in array
+ set_prop_dist(t, 1);
+ sort_trans_data_dist(t);
+ }
+ }
+ else if (G.obedit) {
+ t->ext = NULL;
+ if (G.obedit->type == OB_MESH) {
+ createTransEditVerts(t);
+ }
+ else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) {
+ createTransCurveVerts(t);
+ }
+ else if (G.obedit->type==OB_LATTICE) {
+ createTransLatticeVerts(t);
+ }
+ else if (G.obedit->type==OB_MBALL) {
+ createTransMBallVerts(t);
+ }
+ else if (G.obedit->type==OB_ARMATURE) {
+ t->flag &= ~T_PROP_EDIT;
+ createTransArmatureVerts(t);
+ }
+ else {
+ printf("not done yet! only have mesh surface curve lattice mball armature\n");
+ }
+
+ if(t->data && t->flag & T_PROP_EDIT) {
+ if (ELEM(G.obedit->type, OB_CURVE, OB_MESH)) {
+ sort_trans_data(t); // makes selected become first in array
+ set_prop_dist(t, 0);
+ sort_trans_data_dist(t);
+ }
+ else {
+ sort_trans_data(t); // makes selected become first in array
+ set_prop_dist(t, 1);
+ sort_trans_data_dist(t);
+ }
+ }
+
+ t->flag |= T_EDIT|T_POINTS;
+
+ /* exception... hackish, we want bonesize to use bone orientation matrix (ton) */
+ if(t->mode==TFM_BONESIZE) {
+ t->flag &= ~(T_EDIT|T_POINTS);
+ t->flag |= T_POSE;
+ t->poseobj= ob; /* <- tsk tsk, this is going to give issues one day */
+ }
+ }
+ else if (ob && (ob->flag & OB_POSEMODE)) {
+ createTransPose(t, OBACT);
+ }
+ else if (G.f & G_WEIGHTPAINT) {
+ /* exception, we look for the one selected armature */
+ Base *base;
+ for(base=FIRSTBASE; base; base= base->next) {
+ if(TESTBASELIB(base)) {
+ if(base->object->type==OB_ARMATURE)
+ if(base->object->flag & OB_POSEMODE)
+ break;
+ }
+ }
+ if(base) {
+ createTransPose(t, base->object);
+ }
+ }
+ else {
+ createTransObject(t);
+ t->flag |= T_OBJECT;
+ }
+
+ if((t->flag & T_OBJECT) && G.vd->camera==OBACT && G.vd->persp>1) {
+ t->flag |= T_CAMERA;
+ }
+
+ /* temporal...? */
+ G.scene->recalc |= SCE_PRV_CHANGED; /* test for 3d preview */
+}
+
diff --git a/source/blender/src/transform_generics.c b/source/blender/src/transform_generics.c
new file mode 100644
index 00000000000..bf9de8d4e3f
--- /dev/null
+++ b/source/blender/src/transform_generics.c
@@ -0,0 +1,1009 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <string.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_action_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_object_force.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BIF_screen.h"
+#include "BIF_resources.h"
+#include "BIF_mywindow.h"
+#include "BIF_gl.h"
+#include "BIF_editaction.h"
+#include "BIF_editarmature.h"
+#include "BIF_editmesh.h"
+#include "BIF_editnla.h"
+#include "BIF_editsima.h"
+#include "BIF_meshtools.h"
+#include "BIF_retopo.h"
+
+#include "BSE_editipo.h"
+#include "BSE_editipo_types.h"
+
+#ifdef WITH_VERSE
+#include "BIF_verse.h"
+#endif
+
+#include "BKE_action.h"
+#include "BKE_anim.h"
+#include "BKE_armature.h"
+#include "BKE_curve.h"
+#include "BKE_depsgraph.h"
+#include "BKE_displist.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_group.h"
+#include "BKE_ipo.h"
+#include "BKE_lattice.h"
+#include "BKE_key.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+#include "BKE_utildefines.h"
+
+#ifdef WITH_VERSE
+#include "BKE_verse.h"
+#endif
+
+#include "BSE_view.h"
+#include "BSE_editaction_types.h"
+#include "BDR_unwrapper.h"
+
+#include "BLI_arithb.h"
+#include "BLI_blenlib.h"
+#include "BLI_editVert.h"
+#include "BLI_rand.h"
+
+#include "blendef.h"
+
+#include "mydevice.h"
+
+#include "transform.h"
+
+extern ListBase editNurb;
+extern ListBase editelems;
+
+extern TransInfo Trans; /* From transform.c */
+
+/* ************************** Functions *************************** */
+
+
+void getViewVector(float coord[3], float vec[3])
+{
+ TransInfo *t = BIF_GetTransInfo();
+
+ if (t->persp)
+ {
+ float p1[4], p2[4];
+
+ VECCOPY(p1, coord);
+ p1[3] = 1.0f;
+ VECCOPY(p2, p1);
+ p2[3] = 1.0f;
+ Mat4MulVec4fl(t->viewmat, p2);
+
+ p2[0] = 2.0f * p2[0];
+ p2[1] = 2.0f * p2[1];
+ p2[2] = 2.0f * p2[2];
+
+ Mat4MulVec4fl(t->viewinv, p2);
+
+ VecSubf(vec, p1, p2);
+ }
+ else {
+ VECCOPY(vec, t->viewinv[2]);
+ }
+ Normalize(vec);
+}
+
+/* ************************** GENERICS **************************** */
+
+static void clipMirrorModifier(TransInfo *t, Object *ob)
+{
+ ModifierData *md= ob->modifiers.first;
+ float tolerance[3] = {0.0f, 0.0f, 0.0f};
+ int axis = 0;
+
+ for (; md; md=md->next) {
+ if (md->type==eModifierType_Mirror) {
+ MirrorModifierData *mmd = (MirrorModifierData*) md;
+
+ if(mmd->flag & MOD_MIR_CLIPPING) {
+ if(mmd->flag & MOD_MIR_AXIS_X) {
+ axis |= 1;
+ tolerance[0] = mmd->tolerance;
+ }
+ if(mmd->flag & MOD_MIR_AXIS_Y) {
+ axis |= 2;
+ tolerance[1] = mmd->tolerance;
+ }
+ if(mmd->flag & MOD_MIR_AXIS_Z) {
+ axis |= 4;
+ tolerance[2] = mmd->tolerance;
+ }
+ }
+ }
+ }
+ if (axis) {
+ TransData *td = t->data;
+ int i;
+
+ for(i = 0 ; i < t->total; i++, td++) {
+ if (td->flag & TD_NOACTION)
+ break;
+ if (td->loc==NULL)
+ break;
+
+ if(axis & 1) {
+ if(fabs(td->iloc[0])<=tolerance[0] || td->loc[0]*td->iloc[0]<0.0f) td->loc[0]= 0.0f;
+ }
+
+ if(axis & 2) {
+ if(fabs(td->iloc[1])<=tolerance[1] || td->loc[1]*td->iloc[1]<0.0f) td->loc[1]= 0.0f;
+ }
+ if(axis & 4) {
+ if(fabs(td->iloc[2])<=tolerance[2] || td->loc[2]*td->iloc[2]<0.0f) td->loc[2]= 0.0f;
+ }
+ }
+ }
+}
+
+/* assumes G.obedit set to mesh object */
+static void editmesh_apply_to_mirror(TransInfo *t)
+{
+ TransData *td = t->data;
+ EditVert *eve;
+ int i;
+
+ for(i = 0 ; i < t->total; i++, td++) {
+ if (td->flag & TD_NOACTION)
+ break;
+ if (td->loc==NULL)
+ break;
+
+ eve= td->tdmir;
+ if(eve) {
+ eve->co[0]= -td->loc[0];
+ eve->co[1]= td->loc[1];
+ eve->co[2]= td->loc[2];
+ }
+ }
+}
+
+/* called for updating while transform acts, once per redraw */
+void recalcData(TransInfo *t)
+{
+ Base *base;
+#ifdef WITH_VERSE
+ struct TransData *td;
+#endif
+
+ if (t->spacetype == SPACE_ACTION) {
+ Object *ob= OBACT;
+ void *data;
+ short context;
+
+ /* determine what type of data we are operating on */
+ data = get_action_context(&context);
+ if (data == NULL) return;
+
+ if (G.saction->lock) {
+ if (context == ACTCONT_ACTION) {
+ if(ob) {
+ ob->ctime= -1234567.0f;
+ if(ob->pose || ob_get_key(ob))
+ DAG_object_flush_update(G.scene, ob, OB_RECALC);
+ else
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_OB);
+ }
+ }
+ else if (context == ACTCONT_SHAPEKEY) {
+ DAG_object_flush_update(G.scene, OBACT, OB_RECALC_OB|OB_RECALC_DATA);
+ }
+ }
+ }
+ else if (t->spacetype == SPACE_NLA) {
+ if (G.snla->lock) {
+ for (base=G.scene->base.first; base; base=base->next) {
+ if (base->flag & BA_HAS_RECALC_OB)
+ base->object->recalc |= OB_RECALC_OB;
+ if (base->flag & BA_HAS_RECALC_DATA)
+ base->object->recalc |= OB_RECALC_DATA;
+
+ if (base->object->recalc)
+ base->object->ctime= -1234567.0f; // eveil!
+ }
+
+ DAG_scene_flush_update(G.scene, screen_view3d_layers());
+ }
+ }
+ else if (t->spacetype == SPACE_IPO) {
+ EditIpo *ei;
+ int dosort = 0;
+ int a;
+
+ /* do the flush first */
+ flushTransIpoData(t);
+
+ /* now test if there is a need to re-sort */
+ ei= G.sipo->editipo;
+ for (a=0; a<G.sipo->totipo; a++, ei++) {
+ if (ISPOIN(ei, flag & IPO_VISIBLE, icu)) {
+
+ /* watch it: if the time is wrong: do not correct handles */
+ if (test_time_ipocurve(ei->icu)) dosort++;
+ else testhandles_ipocurve(ei->icu);
+ }
+ }
+
+ /* do resort and other updates? */
+ if (dosort) remake_ipo_transdata(t);
+ if (G.sipo->showkey) update_ipokey_val();
+
+ calc_ipo(G.sipo->ipo, (float)CFRA);
+
+ /* update realtime - not working? */
+ if (G.sipo->lock) {
+ if (G.sipo->blocktype==ID_MA || G.sipo->blocktype==ID_TE) {
+ do_ipo(G.sipo->ipo);
+ }
+ else if(G.sipo->blocktype==ID_CA) {
+ do_ipo(G.sipo->ipo);
+ }
+ else if(G.sipo->blocktype==ID_KE) {
+ Object *ob= OBACT;
+ if(ob) {
+ ob->shapeflag &= ~OB_SHAPE_TEMPLOCK;
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ }
+ }
+ else if(G.sipo->blocktype==ID_PO) {
+ Object *ob= OBACT;
+ if(ob && ob->pose) {
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ }
+ }
+ else if(G.sipo->blocktype==ID_OB) {
+ Base *base= FIRSTBASE;
+
+ while(base) {
+ if(base->object->ipo==G.sipo->ipo) {
+ do_ob_ipo(base->object);
+ base->object->recalc |= OB_RECALC_OB;
+ }
+ base= base->next;
+ }
+ DAG_scene_flush_update(G.scene, screen_view3d_layers());
+ }
+ }
+ }
+ else if (G.obedit) {
+ if (G.obedit->type == OB_MESH) {
+ if(t->spacetype==SPACE_IMAGE) {
+ flushTransUVs(t);
+ if (G.sima->flag & SI_LIVE_UNWRAP)
+ unwrap_lscm_live_re_solve();
+ } else {
+
+ retopo_do_all();
+
+ /* mirror modifier clipping? */
+ if(t->state != TRANS_CANCEL)
+ clipMirrorModifier(t, G.obedit);
+
+ if(G.scene->toolsettings->editbutflag & B_MESH_X_MIRROR)
+ editmesh_apply_to_mirror(t);
+
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); /* sets recalc flags */
+
+ recalc_editnormals();
+ }
+ }
+ else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) {
+ Nurb *nu= editNurb.first;
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); /* sets recalc flags */
+
+ while(nu) {
+ test2DNurb(nu);
+ testhandlesNurb(nu); /* test for bezier too */
+ nu= nu->next;
+ }
+
+ retopo_do_all();
+ }
+ else if(G.obedit->type==OB_ARMATURE){ /* no recalc flag, does pose */
+ bArmature *arm= G.obedit->data;
+ EditBone *ebo;
+
+ /* Ensure all bones are correctly adjusted */
+ for (ebo=G.edbo.first; ebo; ebo=ebo->next){
+
+ if ((ebo->flag & BONE_CONNECTED) && ebo->parent){
+ /* If this bone has a parent tip that has been moved */
+ if (ebo->parent->flag & BONE_TIPSEL){
+ VECCOPY (ebo->head, ebo->parent->tail);
+ if(t->mode==TFM_BONE_ENVELOPE) ebo->rad_head= ebo->parent->rad_tail;
+ }
+ /* If this bone has a parent tip that has NOT been moved */
+ else{
+ VECCOPY (ebo->parent->tail, ebo->head);
+ if(t->mode==TFM_BONE_ENVELOPE) ebo->parent->rad_tail= ebo->rad_head;
+ }
+ }
+
+ /* on extrude bones, oldlength==0.0f, so we scale radius of points */
+ ebo->length= VecLenf(ebo->head, ebo->tail);
+ if(ebo->oldlength==0.0f) {
+ ebo->rad_head= 0.25f*ebo->length;
+ ebo->rad_tail= 0.10f*ebo->length;
+ ebo->dist= 0.25f*ebo->length;
+ if(ebo->parent) {
+ if(ebo->rad_head > ebo->parent->rad_tail)
+ ebo->rad_head= ebo->parent->rad_tail;
+ }
+ }
+ else if(t->mode!=TFM_BONE_ENVELOPE) {
+ /* if bones change length, lets do that for the deform distance as well */
+ ebo->dist*= ebo->length/ebo->oldlength;
+ ebo->rad_head*= ebo->length/ebo->oldlength;
+ ebo->rad_tail*= ebo->length/ebo->oldlength;
+ ebo->oldlength= ebo->length;
+ }
+ }
+ if(arm->flag & ARM_MIRROR_EDIT)
+ transform_armature_mirror_update();
+
+ }
+ else if(G.obedit->type==OB_LATTICE) {
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); /* sets recalc flags */
+
+ if(editLatt->flag & LT_OUTSIDE) outside_lattice(editLatt);
+ }
+ else {
+ DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA); /* sets recalc flags */
+ }
+ }
+ else if( (t->flag & T_POSE) && t->poseobj) {
+ Object *ob= t->poseobj;
+ bArmature *arm= ob->data;
+
+ /* old optimize trick... this enforces to bypass the depgraph */
+ if (!(arm->flag & ARM_DELAYDEFORM)) {
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); /* sets recalc flags */
+
+ /* bah, softbody exception... recalcdata doesnt reset */
+ for(base= FIRSTBASE; base; base= base->next) {
+ if(base->object->recalc & OB_RECALC_DATA)
+ if(modifiers_isSoftbodyEnabled(base->object)) {
+ base->object->softflag |= OB_SB_REDO;
+ }
+ }
+ }
+ else
+ where_is_pose(ob);
+ }
+ else {
+ for(base= FIRSTBASE; base; base= base->next) {
+ Object *ob= base->object;
+
+ /* this flag is from depgraph, was stored in nitialize phase, handled in drawview.c */
+ if(base->flag & BA_HAS_RECALC_OB)
+ ob->recalc |= OB_RECALC_OB;
+ if(base->flag & BA_HAS_RECALC_DATA)
+ ob->recalc |= OB_RECALC_DATA;
+
+ /* thanks to ob->ctime usage, ipos are not called in where_is_object,
+ unless we edit ipokeys */
+ if(base->flag & BA_DO_IPO) {
+ if(ob->ipo) {
+ IpoCurve *icu;
+
+ ob->ctime= -1234567.0;
+
+ icu= ob->ipo->curve.first;
+ while(icu) {
+ calchandles_ipocurve(icu);
+ icu= icu->next;
+ }
+ }
+ }
+
+ /* softbody exception */
+ if(modifiers_isSoftbodyEnabled(ob)) {
+ if(ob->recalc & OB_RECALC_DATA)
+ ob->softflag |= OB_SB_REDO;
+ }
+
+ /* proxy exception */
+ if(ob->proxy)
+ ob->proxy->recalc |= ob->recalc;
+ if(ob->proxy_group)
+ group_tag_recalc(ob->proxy_group->dup_group);
+ }
+ }
+
+#ifdef WITH_VERSE
+ for (td = t->data; td < t->data + t->total; td++) {
+ if(td->flag & TD_VERSE_VERT) {
+ if(td->verse)
+ send_versevert_pos((VerseVert*)td->verse);
+ }
+ else if(td->flag & TD_VERSE_OBJECT)
+ if(td->verse) b_verse_send_transformation((Object*)td->verse);
+ }
+#endif
+
+ /* update shaded drawmode while transform */
+ if(t->spacetype==SPACE_VIEW3D && G.vd->drawtype == OB_SHADED)
+ reshadeall_displist();
+
+}
+
+void drawLine(float *center, float *dir, char axis, short options)
+{
+ extern void make_axis_color(char *col, char *col2, char axis); // drawview.c
+ float v1[3], v2[3], v3[3];
+ char col[3], col2[3];
+
+ //if(G.obedit) mymultmatrix(G.obedit->obmat); // sets opengl viewing
+
+ VecCopyf(v3, dir);
+ VecMulf(v3, G.vd->far);
+
+ VecSubf(v2, center, v3);
+ VecAddf(v1, center, v3);
+
+ if (options & DRAWLIGHT) {
+ col[0] = col[1] = col[2] = 220;
+ }
+ else {
+ BIF_GetThemeColor3ubv(TH_GRID, col);
+ }
+ make_axis_color(col, col2, axis);
+ glColor3ubv((GLubyte *)col2);
+
+ setlinestyle(0);
+ glBegin(GL_LINE_STRIP);
+ glVertex3fv(v1);
+ glVertex3fv(v2);
+ glEnd();
+
+ myloadmatrix(G.vd->viewmat);
+}
+
+void initTrans (TransInfo *t)
+{
+ /* moving: is shown in drawobject() (transform color) */
+ if(G.obedit || (t->flag & T_POSE) ) G.moving= G_TRANSFORM_EDIT;
+ else G.moving= G_TRANSFORM_OBJ;
+
+ t->data = NULL;
+ t->ext = NULL;
+
+ t->flag = 0;
+ t->num.flag = 0;
+
+
+ /* setting PET flag */
+ if ((t->context & CTX_NO_PET) == 0 && (G.scene->proportional)) {
+ t->flag |= T_PROP_EDIT;
+ if(G.scene->proportional==2) t->flag |= T_PROP_CONNECTED; // yes i know, has to become define
+ }
+
+ getmouseco_areawin(t->imval);
+ t->con.imval[0] = t->imval[0];
+ t->con.imval[1] = t->imval[1];
+
+ t->transform = NULL;
+ t->handleEvent = NULL;
+ t->customData = NULL;
+
+ t->total =
+ t->num.idx =
+ t->num.idx_max =
+ t->num.ctrl[0] =
+ t->num.ctrl[1] =
+ t->num.ctrl[2] = 0;
+
+ t->val = 0.0f;
+
+ t->num.val[0] =
+ t->num.val[1] =
+ t->num.val[2] = 0.0f;
+
+ t->vec[0] =
+ t->vec[1] =
+ t->vec[2] = 0.0f;
+
+ t->center[0] =
+ t->center[1] =
+ t->center[2] = 0.0f;
+
+ Mat3One(t->mat);
+
+ t->spacetype = curarea->spacetype;
+ if(t->spacetype==SPACE_VIEW3D) {
+ if(G.vd->flag & V3D_ALIGN) t->flag |= T_V3D_ALIGN;
+ t->around = G.vd->around;
+ } else if(t->spacetype==SPACE_IMAGE) {
+ t->around = G.v2d->around;
+ }
+ else
+ t->around = V3D_CENTER;
+
+ setTransformViewMatrices(t);
+}
+
+/* Here I would suggest only TransInfo related issues, like free data & reset vars. Not redraws */
+void postTrans (TransInfo *t)
+{
+ TransData *td;
+
+ G.moving = 0; // Set moving flag off (display as usual)
+#ifdef WITH_VERSE
+
+ for (td = t->data; td < t->data + t->total; td++) {
+ if(td->flag & TD_VERSE_VERT) {
+ if(td->verse) send_versevert_pos((VerseVert*)td->verse);
+ }
+ else if(td->flag & TD_VERSE_OBJECT) {
+ if(td->verse) {
+ struct VNode *vnode;
+ vnode = (VNode*)((Object*)td->verse)->vnode;
+ ((VObjectData*)vnode->data)->flag |= POS_SEND_READY;
+ ((VObjectData*)vnode->data)->flag |= ROT_SEND_READY;
+ ((VObjectData*)vnode->data)->flag |= SCALE_SEND_READY;
+ b_verse_send_transformation((Object*)td->verse);
+ }
+ }
+ }
+#endif
+
+ stopConstraint(t);
+
+ /* postTrans can be called when nothing is selected, so data is NULL already */
+ if (t->data) {
+ int a;
+
+ /* since ipokeys are optional on objects, we mallocced them per trans-data */
+ for(a=0, td= t->data; a<t->total; a++, td++) {
+ if(td->tdi) MEM_freeN(td->tdi);
+ }
+ MEM_freeN(t->data);
+ }
+
+ if (t->ext) MEM_freeN(t->ext);
+ if (t->data2d) {
+ MEM_freeN(t->data2d);
+ t->data2d= NULL;
+ }
+
+ if ((t->flag & T_FREE_CUSTOMDATA) && t->customData != NULL) {
+ MEM_freeN(t->customData);
+ }
+
+ if(t->spacetype==SPACE_IMAGE) {
+ if (G.sima->flag & SI_LIVE_UNWRAP)
+ unwrap_lscm_live_end(t->state == TRANS_CANCEL);
+ }
+}
+
+void applyTransObjects(TransInfo *t)
+{
+ TransData *td;
+
+ for (td = t->data; td < t->data + t->total; td++) {
+ VECCOPY(td->iloc, td->loc);
+ if (td->ext->rot) {
+ VECCOPY(td->ext->irot, td->ext->rot);
+ }
+ if (td->ext->size) {
+ VECCOPY(td->ext->isize, td->ext->size);
+ }
+ }
+ recalcData(t);
+}
+
+/* helper for below */
+static void restore_ipokey(float *poin, float *old)
+{
+ if(poin) {
+ poin[0]= old[0];
+ poin[-3]= old[3];
+ poin[3]= old[6];
+ }
+}
+
+static void restoreElement(TransData *td) {
+ /* TransData for crease has no loc */
+ if (td->loc) {
+ VECCOPY(td->loc, td->iloc);
+ }
+ if (td->val) {
+ *td->val = td->ival;
+ }
+ if (td->ext) {
+ if (td->ext->rot) {
+ VECCOPY(td->ext->rot, td->ext->irot);
+ }
+ if (td->ext->size) {
+ VECCOPY(td->ext->size, td->ext->isize);
+ }
+ if(td->flag & TD_USEQUAT) {
+ if (td->ext->quat) {
+ QUATCOPY(td->ext->quat, td->ext->iquat);
+ }
+ }
+ }
+ if(td->tdi) {
+ TransDataIpokey *tdi= td->tdi;
+
+ restore_ipokey(tdi->locx, tdi->oldloc);
+ restore_ipokey(tdi->locy, tdi->oldloc+1);
+ restore_ipokey(tdi->locz, tdi->oldloc+2);
+
+ restore_ipokey(tdi->rotx, tdi->oldrot);
+ restore_ipokey(tdi->roty, tdi->oldrot+1);
+ restore_ipokey(tdi->rotz, tdi->oldrot+2);
+
+ restore_ipokey(tdi->sizex, tdi->oldsize);
+ restore_ipokey(tdi->sizey, tdi->oldsize+1);
+ restore_ipokey(tdi->sizez, tdi->oldsize+2);
+ }
+}
+
+void restoreTransObjects(TransInfo *t)
+{
+ TransData *td;
+
+ for (td = t->data; td < t->data + t->total; td++) {
+ restoreElement(td);
+#ifdef WITH_VERSE
+ /* position of vertexes and object transformation matrix is sent
+ * extra, becuase blender uses synchronous sending of vertexes
+ * position as well object trans. matrix and it isn't possible to
+ * send it in recalcData sometimes */
+ if(td->flag & TD_VERSE_VERT) {
+ if(td->verse) {
+ ((VerseVert*)td->verse)->flag |= VERT_POS_OBSOLETE;
+ }
+ }
+ else if(td->flag & TD_VERSE_OBJECT)
+ if(td->verse) {
+ struct VNode *vnode;
+ vnode = (VNode*)((Object*)td->verse)->vnode;
+ ((VObjectData*)vnode->data)->flag |= POS_SEND_READY;
+ ((VObjectData*)vnode->data)->flag |= ROT_SEND_READY;
+ ((VObjectData*)vnode->data)->flag |= SCALE_SEND_READY;
+ }
+#endif
+ }
+ recalcData(t);
+}
+
+void calculateCenter2D(TransInfo *t)
+{
+ if (t->flag & (T_EDIT|T_POSE)) {
+ Object *ob= G.obedit?G.obedit:t->poseobj;
+ float vec[3];
+
+ VECCOPY(vec, t->center);
+ Mat4MulVecfl(ob->obmat, vec);
+ projectIntView(t, vec, t->center2d);
+ }
+ else {
+ projectIntView(t, t->center, t->center2d);
+ }
+}
+
+void calculateCenterCursor(TransInfo *t)
+{
+ float *cursor;
+
+ cursor = give_cursor();
+ VECCOPY(t->center, cursor);
+
+ /* If edit or pose mode, move cursor in local space */
+ if (t->flag & (T_EDIT|T_POSE)) {
+ Object *ob = G.obedit?G.obedit:t->poseobj;
+ float mat[3][3], imat[3][3];
+
+ VecSubf(t->center, t->center, ob->obmat[3]);
+ Mat3CpyMat4(mat, ob->obmat);
+ Mat3Inv(imat, mat);
+ Mat3MulVecfl(imat, t->center);
+ }
+
+ calculateCenter2D(t);
+}
+
+void calculateCenterCursor2D(TransInfo *t)
+{
+ float aspx=1.0, aspy=1.0;
+
+ if(t->spacetype==SPACE_IMAGE) /* only space supported right now but may change */
+ transform_aspect_ratio_tface_uv(&aspx, &aspy);
+ if (G.v2d) {
+ t->center[0] = G.v2d->cursor[0] * aspx;
+ t->center[1] = G.v2d->cursor[1] * aspy;
+ }
+ calculateCenter2D(t);
+}
+
+void calculateCenterMedian(TransInfo *t)
+{
+ float partial[3] = {0.0f, 0.0f, 0.0f};
+ int i;
+
+ for(i = 0; i < t->total; i++) {
+ if (t->data[i].flag & TD_SELECTED) {
+ if (!(t->data[i].flag & TD_NOCENTER))
+ VecAddf(partial, partial, t->data[i].center);
+ }
+ else {
+ /*
+ All the selected elements are at the head of the array
+ which means we can stop when it finds unselected data
+ */
+ break;
+ }
+ }
+ if(i)
+ VecMulf(partial, 1.0f / i);
+ VECCOPY(t->center, partial);
+
+ calculateCenter2D(t);
+}
+
+void calculateCenterBound(TransInfo *t)
+{
+ float max[3];
+ float min[3];
+ int i;
+ for(i = 0; i < t->total; i++) {
+ if (i) {
+ if (t->data[i].flag & TD_SELECTED) {
+ if (!(t->data[i].flag & TD_NOCENTER))
+ MinMax3(min, max, t->data[i].center);
+ }
+ else {
+ /*
+ All the selected elements are at the head of the array
+ which means we can stop when it finds unselected data
+ */
+ break;
+ }
+ }
+ else {
+ VECCOPY(max, t->data[i].center);
+ VECCOPY(min, t->data[i].center);
+ }
+ }
+ VecAddf(t->center, min, max);
+ VecMulf(t->center, 0.5);
+
+ calculateCenter2D(t);
+}
+
+void calculateCenter(TransInfo *t)
+{
+ switch(t->around) {
+ case V3D_CENTER:
+ calculateCenterBound(t);
+ break;
+ case V3D_CENTROID:
+ calculateCenterMedian(t);
+ break;
+ case V3D_CURSOR:
+ if(t->spacetype==SPACE_IMAGE)
+ calculateCenterCursor2D(t);
+ else
+ calculateCenterCursor(t);
+ break;
+ case V3D_LOCAL:
+ /* Individual element center uses median center for helpline and such */
+ calculateCenterMedian(t);
+ break;
+ case V3D_ACTIVE:
+ /* set median, and if if if... do object center */
+
+ /* EDIT MODE ACTIVE EDITMODE ELEMENT */
+ if (G.obedit && G.obedit->type == OB_MESH && G.editMesh->selected.last) {
+ EM_editselection_center(t->center, G.editMesh->selected.last);
+ calculateCenter2D(t);
+ break;
+ } /* END EDIT MODE ACTIVE ELEMENT */
+
+ calculateCenterMedian(t);
+ if((t->flag & (T_EDIT|T_POSE))==0) {
+ Object *ob= OBACT;
+ if(ob) {
+ VECCOPY(t->center, ob->obmat[3]);
+ projectIntView(t, t->center, t->center2d);
+ }
+ }
+ }
+
+ /* setting constraint center */
+ VECCOPY(t->con.center, t->center);
+ if(t->flag & (T_EDIT|T_POSE)) {
+ Object *ob= G.obedit?G.obedit:t->poseobj;
+ Mat4MulVecfl(ob->obmat, t->con.center);
+ }
+
+ /* voor panning from cameraview */
+ if(t->flag & T_OBJECT) {
+ if( G.vd->camera==OBACT && G.vd->persp>1) {
+ float axis[3];
+ /* persinv is nasty, use viewinv instead, always right */
+ VECCOPY(axis, t->viewinv[2]);
+ Normalize(axis);
+
+ /* 6.0 = 6 grid units */
+ axis[0]= t->center[0]- 6.0f*axis[0];
+ axis[1]= t->center[1]- 6.0f*axis[1];
+ axis[2]= t->center[2]- 6.0f*axis[2];
+
+ projectIntView(t, axis, t->center2d);
+
+ /* rotate only needs correct 2d center, grab needs initgrabz() value */
+ if(t->mode==TFM_TRANSLATION) {
+ VECCOPY(t->center, axis);
+ VECCOPY(t->con.center, t->center);
+ }
+ }
+ }
+
+ if(t->spacetype==SPACE_VIEW3D)
+ initgrabz(t->center[0], t->center[1], t->center[2]);
+}
+
+void calculatePropRatio(TransInfo *t)
+{
+ TransData *td = t->data;
+ int i;
+ float dist;
+ short connected = t->flag & T_PROP_CONNECTED;
+
+ if (t->flag & T_PROP_EDIT) {
+ for(i = 0 ; i < t->total; i++, td++) {
+ if (td->flag & TD_SELECTED) {
+ td->factor = 1.0f;
+ }
+ else if ((connected &&
+ (td->flag & TD_NOTCONNECTED || td->dist > t->propsize))
+ ||
+ (connected == 0 &&
+ td->rdist > t->propsize)) {
+ /*
+ The elements are sorted according to their dist member in the array,
+ that means we can stop when it finds one element outside of the propsize.
+ */
+ td->flag |= TD_NOACTION;
+ td->factor = 0.0f;
+ restoreElement(td);
+ }
+ else {
+ /* Use rdist for falloff calculations, it is the real distance */
+ td->flag &= ~TD_NOACTION;
+ dist= (t->propsize-td->rdist)/t->propsize;
+
+ /*
+ * Clamp to positive numbers.
+ * Certain corner cases with connectivity and individual centers
+ * can give values of rdist larger than propsize.
+ */
+ if (dist < 0.0f)
+ dist = 0.0f;
+
+ switch(G.scene->prop_mode) {
+ case PROP_SHARP:
+ td->factor= dist*dist;
+ break;
+ case PROP_SMOOTH:
+ td->factor= 3.0f*dist*dist - 2.0f*dist*dist*dist;
+ break;
+ case PROP_ROOT:
+ td->factor = (float)sqrt(dist);
+ break;
+ case PROP_LIN:
+ td->factor = dist;
+ break;
+ case PROP_CONST:
+ td->factor = 1.0f;
+ break;
+ case PROP_SPHERE:
+ td->factor = (float)sqrt(2*dist - dist * dist);
+ break;
+ case PROP_RANDOM:
+ BLI_srand( BLI_rand() ); /* random seed */
+ td->factor = BLI_frand()*dist;
+ break;
+ default:
+ td->factor = 1;
+ }
+ }
+ }
+ switch(G.scene->prop_mode) {
+ case PROP_SHARP:
+ strcpy(t->proptext, "(Sharp)");
+ break;
+ case PROP_SMOOTH:
+ strcpy(t->proptext, "(Smooth)");
+ break;
+ case PROP_ROOT:
+ strcpy(t->proptext, "(Root)");
+ break;
+ case PROP_LIN:
+ strcpy(t->proptext, "(Linear)");
+ break;
+ case PROP_CONST:
+ strcpy(t->proptext, "(Constant)");
+ break;
+ case PROP_SPHERE:
+ strcpy(t->proptext, "(Sphere)");
+ break;
+ case PROP_RANDOM:
+ strcpy(t->proptext, "(Random)");
+ break;
+ default:
+ strcpy(t->proptext, "");
+ }
+ }
+ else {
+ for(i = 0 ; i < t->total; i++, td++) {
+ td->factor = 1.0;
+ }
+ strcpy(t->proptext, "");
+ }
+}
+
+TransInfo * BIF_GetTransInfo() {
+ return &Trans;
+}
+
diff --git a/source/blender/src/transform_manipulator.c b/source/blender/src/transform_manipulator.c
new file mode 100644
index 00000000000..8035cbb7d76
--- /dev/null
+++ b/source/blender/src/transform_manipulator.c
@@ -0,0 +1,1692 @@
+/**
+* $Id:
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef WIN32
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_armature_types.h"
+#include "DNA_action_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_armature.h"
+#include "BKE_global.h"
+#include "BKE_lattice.h"
+#include "BKE_object.h"
+#include "BKE_utildefines.h"
+
+#include "BLI_arithb.h"
+#include "BLI_editVert.h"
+
+#include "BIF_editarmature.h"
+#include "BIF_gl.h"
+#include "BIF_mywindow.h"
+#include "BIF_resources.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_transform.h"
+#include "BIF_editmesh.h"
+
+#include "BSE_edit.h"
+#include "BSE_view.h"
+#include "BDR_drawobject.h"
+
+#include "blendef.h"
+#include "transform.h"
+
+/* return codes for select, and drawing flags */
+
+#define MAN_TRANS_X 1
+#define MAN_TRANS_Y 2
+#define MAN_TRANS_Z 4
+#define MAN_TRANS_C 7
+
+#define MAN_ROT_X 8
+#define MAN_ROT_Y 16
+#define MAN_ROT_Z 32
+#define MAN_ROT_V 64
+#define MAN_ROT_T 128
+#define MAN_ROT_C 248
+
+#define MAN_SCALE_X 256
+#define MAN_SCALE_Y 512
+#define MAN_SCALE_Z 1024
+#define MAN_SCALE_C 1792
+
+/* color codes */
+
+#define MAN_RGB 0
+#define MAN_GHOST 1
+#define MAN_MOVECOL 2
+
+/* GLOBAL VARIABLE THAT SHOULD MOVED TO SCREEN MEMBER OR SOMETHING */
+extern TransInfo Trans;
+
+
+static int is_mat4_flipped(float mat[][4])
+{
+ float vec[3];
+
+ Crossf(vec, mat[0], mat[1]);
+ if( Inpf(vec, mat[2]) < 0.0 ) return 1;
+ return 0;
+}
+
+/* transform widget center calc helper for below */
+static void calc_tw_center(float *co)
+{
+ float *twcent= G.scene->twcent;
+ float *min= G.scene->twmin;
+ float *max= G.scene->twmax;
+
+ DO_MINMAX(co, min, max);
+ VecAddf(twcent, twcent, co);
+}
+
+static void protectflag_to_drawflags(short protectflag, short *drawflags)
+{
+ if(protectflag & OB_LOCK_LOCX)
+ *drawflags &= ~MAN_TRANS_X;
+ if(protectflag & OB_LOCK_LOCY)
+ *drawflags &= ~MAN_TRANS_Y;
+ if(protectflag & OB_LOCK_LOCZ)
+ *drawflags &= ~MAN_TRANS_Z;
+
+ if(protectflag & OB_LOCK_ROTX)
+ *drawflags &= ~MAN_ROT_X;
+ if(protectflag & OB_LOCK_ROTY)
+ *drawflags &= ~MAN_ROT_Y;
+ if(protectflag & OB_LOCK_ROTZ)
+ *drawflags &= ~MAN_ROT_Z;
+
+ if(protectflag & OB_LOCK_SCALEX)
+ *drawflags &= ~MAN_SCALE_X;
+ if(protectflag & OB_LOCK_SCALEY)
+ *drawflags &= ~MAN_SCALE_Y;
+ if(protectflag & OB_LOCK_SCALEZ)
+ *drawflags &= ~MAN_SCALE_Z;
+}
+
+/* for pose mode */
+static void stats_pose(View3D *v3d, bPoseChannel *pchan, float *normal, float *plane)
+{
+ Bone *bone= pchan->bone;
+
+ if(bone) {
+ if (bone->flag & BONE_TRANSFORM) {
+ calc_tw_center(pchan->pose_head);
+ protectflag_to_drawflags(pchan->protectflag, &v3d->twdrawflag);
+
+ VecAddf(normal, normal, pchan->pose_mat[2]);
+ VecAddf(plane, plane, pchan->pose_mat[1]);
+ }
+ }
+}
+
+/* only counts the parent selection, and tags transform flag */
+/* bad call... should re-use method from transform_conversion once */
+static void count_bone_select(TransInfo *t, bArmature *arm, ListBase *lb, int do_it)
+{
+ Bone *bone;
+ int do_next;
+
+ for(bone= lb->first; bone; bone= bone->next) {
+ bone->flag &= ~BONE_TRANSFORM;
+ do_next= do_it;
+ if(do_it) {
+ if(bone->layer & arm->layer) {
+ if (bone->flag & BONE_SELECTED) {
+ /* We don't let connected children get "grabbed" */
+ if ( (t->mode!=TFM_TRANSLATION) || (bone->flag & BONE_CONNECTED)==0 ) {
+ bone->flag |= BONE_TRANSFORM;
+ t->total++;
+ do_next= 0; // no transform on children if one parent bone is selected
+ }
+ }
+ }
+ }
+ count_bone_select(t, arm, &bone->childbase, do_next);
+ }
+}
+
+/* centroid, boundbox, of selection */
+/* returns total items selected */
+int calc_manipulator_stats(ScrArea *sa)
+{
+ extern ListBase editNurb;
+ TransInfo *t;
+ View3D *v3d= sa->spacedata.first;
+ Base *base;
+ Object *ob= OBACT;
+ float normal[3]={0.0, 0.0, 0.0};
+ float plane[3]={0.0, 0.0, 0.0};
+ int a, totsel=0;
+
+ t = BIF_GetTransInfo();
+
+ /* transform widget matrix */
+ Mat4One(v3d->twmat);
+
+ v3d->twdrawflag= 0xFFFF;
+
+ /* transform widget centroid/center */
+ G.scene->twcent[0]= G.scene->twcent[1]= G.scene->twcent[2]= 0.0f;
+ INIT_MINMAX(G.scene->twmin, G.scene->twmax);
+
+ if(G.obedit) {
+ ob= G.obedit;
+ if((ob->lay & G.vd->lay)==0) return 0;
+
+ if(G.obedit->type==OB_MESH) {
+ EditMesh *em = G.editMesh;
+ EditVert *eve;
+ float vec[3]= {0,0,0};
+ int no_faces= 1;
+
+ /* USE LAST SELECTE WITH ACTIVE */
+ if (G.vd->around==V3D_ACTIVE && em->selected.last) {
+ EM_editselection_center(vec, em->selected.last);
+ calc_tw_center(vec);
+ totsel= 1;
+ if (v3d->twmode == V3D_MANIP_NORMAL) {
+ EM_editselection_normal(normal, em->selected.last);
+ EM_editselection_plane(plane, em->selected.last);
+ } /* NORMAL OPERATION */
+ } else {
+ if(v3d->twmode == V3D_MANIP_NORMAL) {
+ EditFace *efa;
+
+ for(efa= em->faces.first; efa; efa= efa->next) {
+ if(efa->f & SELECT) {
+ no_faces= 0;
+ VECADD(normal, normal, efa->n);
+ VecSubf(vec, efa->v2->co, efa->v1->co);
+ VECADD(plane, plane, vec);
+ }
+ }
+ }
+
+ /* do vertices for center, and if still no normal found, use vertex normals */
+ for(eve= em->verts.first; eve; eve= eve->next) {
+ if(eve->f & SELECT) {
+ if(no_faces) VECADD(normal, normal, eve->no);
+
+ totsel++;
+ calc_tw_center(eve->co);
+ }
+ }
+ /* the edge case... */
+ if(no_faces && v3d->twmode == V3D_MANIP_NORMAL) {
+ EditEdge *eed;
+
+ for(eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->f & SELECT) {
+ /* ok we got an edge, only use one, and as normal */
+ VECCOPY(plane, normal);
+ VecSubf(normal, eed->v2->co, eed->v1->co);
+ break;
+ }
+ }
+ }
+ }
+ } /* end editmesh */
+ else if (G.obedit->type==OB_ARMATURE){
+ bArmature *arm= G.obedit->data;
+ EditBone *ebo;
+ for (ebo=G.edbo.first;ebo;ebo=ebo->next){
+ if(ebo->layer & arm->layer) {
+ if (ebo->flag & BONE_TIPSEL) {
+ calc_tw_center(ebo->tail);
+ totsel++;
+ }
+ if (ebo->flag & BONE_ROOTSEL) {
+ calc_tw_center(ebo->head);
+ totsel++;
+ }
+ }
+ }
+ }
+ else if ELEM3(G.obedit->type, OB_CURVE, OB_SURF, OB_FONT) {
+ Nurb *nu;
+ BezTriple *bezt;
+ BPoint *bp;
+
+ nu= editNurb.first;
+ while(nu) {
+ if((nu->type & 7)==CU_BEZIER) {
+ bezt= nu->bezt;
+ a= nu->pntsu;
+ while(a--) {
+ /* exception */
+ if( (bezt->f1 & SELECT) + (bezt->f2 & SELECT) + (bezt->f3 & SELECT) > SELECT ) {
+ calc_tw_center(bezt->vec[1]);
+ totsel++;
+ }
+ else {
+ if(bezt->f1) {
+ calc_tw_center(bezt->vec[0]);
+ totsel++;
+ }
+ if(bezt->f2) {
+ calc_tw_center(bezt->vec[1]);
+ totsel++;
+ }
+ if(bezt->f3) {
+ calc_tw_center(bezt->vec[2]);
+ totsel++;
+ }
+ }
+ bezt++;
+ }
+ }
+ else {
+ bp= nu->bp;
+ a= nu->pntsu*nu->pntsv;
+ while(a--) {
+ if(bp->f1 & 1) {
+ calc_tw_center(bp->vec);
+ totsel++;
+ }
+ bp++;
+ }
+ }
+ nu= nu->next;
+ }
+ }
+ else if(G.obedit->type==OB_MBALL) {
+ /* editmball.c */
+ extern ListBase editelems; /* go away ! */
+ MetaElem *ml, *ml_sel=NULL;
+
+ ml= editelems.first;
+ while(ml) {
+ if(ml->flag & SELECT) {
+ calc_tw_center(&ml->x);
+ ml_sel = ml;
+ totsel++;
+ }
+ ml= ml->next;
+ }
+ /* normal manipulator */
+ if(totsel==1){
+ float mat1[4][4];
+
+ /* Rotation of MetaElem is stored in quat */
+ QuatToMat4(ml_sel->quat, mat1);
+
+ /* Translation of MetaElem */
+ mat1[3][0]= ml_sel->x;
+ mat1[3][1]= ml_sel->y;
+ mat1[3][2]= ml_sel->z;
+
+ VECCOPY(normal, mat1[2]);
+ VECCOPY(plane, mat1[1]);
+
+ VecMulf(plane, -1.0);
+ }
+ }
+ else if(G.obedit->type==OB_LATTICE) {
+ BPoint *bp;
+ bp= editLatt->def;
+
+ a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
+ while(a--) {
+ if(bp->f1 & 1) {
+ calc_tw_center(bp->vec);
+ totsel++;
+ }
+ bp++;
+ }
+ }
+
+ /* selection center */
+ if(totsel) {
+ VecMulf(G.scene->twcent, 1.0f/(float)totsel); // centroid!
+ Mat4MulVecfl(G.obedit->obmat, G.scene->twcent);
+ Mat4MulVecfl(G.obedit->obmat, G.scene->twmin);
+ Mat4MulVecfl(G.obedit->obmat, G.scene->twmax);
+ }
+ }
+ else if(ob && (ob->flag & OB_POSEMODE)) {
+ bArmature *arm= ob->data;
+ bPoseChannel *pchan;
+ int mode;
+
+ if((ob->lay & G.vd->lay)==0) return 0;
+
+ mode= Trans.mode;
+ Trans.mode= TFM_ROTATION; // mislead counting bones... bah
+
+ /* count total, we use same method as transform will do */
+ Trans.total= 0;
+ count_bone_select(&Trans, arm, &arm->bonebase, 1);
+ totsel= Trans.total;
+ if(totsel) {
+ /* use channels to get stats */
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ stats_pose(v3d, pchan, normal, plane);
+ }
+ //VecMulf(normal, -1.0);
+ VecMulf(plane, -1.0);
+
+ VecMulf(G.scene->twcent, 1.0f/(float)totsel); // centroid!
+ Mat4MulVecfl(ob->obmat, G.scene->twcent);
+ Mat4MulVecfl(ob->obmat, G.scene->twmin);
+ Mat4MulVecfl(ob->obmat, G.scene->twmax);
+ }
+ /* restore, mode can be TFM_INIT */
+ Trans.mode= mode;
+ }
+ else if(G.f & (G_VERTEXPAINT + G_TEXTUREPAINT + G_WEIGHTPAINT + G_SCULPTMODE)) {
+ ;
+ }
+ else {
+
+ /* we need the one selected object, if its not active */
+ ob= OBACT;
+ if(ob && !(ob->flag & SELECT)) ob= NULL;
+
+ for(base= G.scene->base.first; base; base= base->next) {
+ if TESTBASELIB(base) {
+ if(ob==NULL)
+ ob= base->object;
+ calc_tw_center(base->object->obmat[3]);
+ protectflag_to_drawflags(base->object->protectflag, &v3d->twdrawflag);
+ totsel++;
+ }
+ }
+
+ /* selection center */
+ if(totsel) {
+ VecMulf(G.scene->twcent, 1.0f/(float)totsel); // centroid!
+ }
+ }
+
+ /* global, local or normal orientation? */
+ if(ob && totsel) {
+
+ switch(v3d->twmode) {
+ case V3D_MANIP_GLOBAL:
+ strcpy(t->spacename, "global");
+ break;
+
+ case V3D_MANIP_NORMAL:
+ if(G.obedit || (ob->flag & OB_POSEMODE)) {
+ strcpy(t->spacename, "normal");
+ if(normal[0]!=0.0 || normal[1]!=0.0 || normal[2]!=0.0) {
+ float imat[3][3], mat[3][3];
+
+ /* we need the transpose of the inverse for a normal... */
+ Mat3CpyMat4(imat, ob->obmat);
+
+ Mat3Inv(mat, imat);
+ Mat3Transp(mat);
+ Mat3MulVecfl(mat, normal);
+ Mat3MulVecfl(mat, plane);
+
+ Normalize(normal);
+ if(0.0==Normalize(plane)) VECCOPY(plane, mat[1]);
+
+ VECCOPY(mat[2], normal);
+ Crossf(mat[0], normal, plane);
+ Crossf(mat[1], mat[2], mat[0]);
+
+ Mat4CpyMat3(v3d->twmat, mat);
+ Mat4Ortho(v3d->twmat);
+
+ break;
+ }
+ }
+ /* no break we define 'normal' as 'local' in Object mode */
+ case V3D_MANIP_LOCAL:
+ strcpy(t->spacename, "local");
+ Mat4CpyMat4(v3d->twmat, ob->obmat);
+ Mat4Ortho(v3d->twmat);
+ break;
+
+ case V3D_MANIP_VIEW:
+ {
+ float mat[3][3];
+ strcpy(t->spacename, "view");
+ Mat3CpyMat4(mat, v3d->viewinv);
+ Mat3Ortho(mat);
+ Mat4CpyMat3(v3d->twmat, mat);
+ }
+ break;
+ }
+
+ }
+
+ return totsel;
+}
+
+/* ******************** DRAWING STUFFIES *********** */
+
+static float screen_aligned(float mat[][4])
+{
+ float vec[3], size;
+
+ VECCOPY(vec, mat[0]);
+ size= Normalize(vec);
+
+ glTranslatef(mat[3][0], mat[3][1], mat[3][2]);
+
+ /* sets view screen aligned */
+ glRotatef( -360.0f*saacos(G.vd->viewquat[0])/(float)M_PI, G.vd->viewquat[1], G.vd->viewquat[2], G.vd->viewquat[3]);
+
+ return size;
+}
+
+
+/* radring = radius of donut rings
+ radhole = radius hole
+ start = starting segment (based on nrings)
+ end = end segment
+ nsides = amount of points in ring
+ nrigns = amount of rings
+*/
+static void partial_donut(float radring, float radhole, int start, int end, int nsides, int nrings)
+{
+ float theta, phi, theta1;
+ float cos_theta, sin_theta;
+ float cos_theta1, sin_theta1;
+ float ring_delta, side_delta;
+ int i, j, docaps= 1;
+
+ if(start==0 && end==nrings) docaps= 0;
+
+ ring_delta= 2.0f*(float)M_PI/(float)nrings;
+ side_delta= 2.0f*(float)M_PI/(float)nsides;
+
+ theta= (float)M_PI+0.5f*ring_delta;
+ cos_theta= (float)cos(theta);
+ sin_theta= (float)sin(theta);
+
+ for(i= nrings - 1; i >= 0; i--) {
+ theta1= theta + ring_delta;
+ cos_theta1= (float)cos(theta1);
+ sin_theta1= (float)sin(theta1);
+
+ if(docaps && i==start) { // cap
+ glBegin(GL_POLYGON);
+ phi= 0.0;
+ for(j= nsides; j >= 0; j--) {
+ float cos_phi, sin_phi, dist;
+
+ phi += side_delta;
+ cos_phi= (float)cos(phi);
+ sin_phi= (float)sin(phi);
+ dist= radhole + radring * cos_phi;
+
+ glVertex3f(cos_theta1 * dist, -sin_theta1 * dist, radring * sin_phi);
+ }
+ glEnd();
+ }
+ if(i>=start && i<=end) {
+ glBegin(GL_QUAD_STRIP);
+ phi= 0.0;
+ for(j= nsides; j >= 0; j--) {
+ float cos_phi, sin_phi, dist;
+
+ phi += side_delta;
+ cos_phi= (float)cos(phi);
+ sin_phi= (float)sin(phi);
+ dist= radhole + radring * cos_phi;
+
+ glVertex3f(cos_theta1 * dist, -sin_theta1 * dist, radring * sin_phi);
+ glVertex3f(cos_theta * dist, -sin_theta * dist, radring * sin_phi);
+ }
+ glEnd();
+ }
+
+ if(docaps && i==end) { // cap
+ glBegin(GL_POLYGON);
+ phi= 0.0;
+ for(j= nsides; j >= 0; j--) {
+ float cos_phi, sin_phi, dist;
+
+ phi -= side_delta;
+ cos_phi= (float)cos(phi);
+ sin_phi= (float)sin(phi);
+ dist= radhole + radring * cos_phi;
+
+ glVertex3f(cos_theta * dist, -sin_theta * dist, radring * sin_phi);
+ }
+ glEnd();
+ }
+
+
+ theta= theta1;
+ cos_theta= cos_theta1;
+ sin_theta= sin_theta1;
+ }
+}
+
+/* three colors can be set;
+ grey for ghosting
+ moving: in transform theme color
+ else the red/green/blue
+*/
+static void manipulator_setcolor(char axis, int colcode)
+{
+ float vec[4];
+ char col[4];
+
+ vec[3]= 0.7f; // alpha set on 0.5, can be glEnabled or not
+
+ if(colcode==MAN_GHOST) {
+ glColor4ub(0, 0, 0, 70);
+ }
+ else if(colcode==MAN_MOVECOL) {
+ BIF_GetThemeColor3ubv(TH_TRANSFORM, col);
+ glColor4ub(col[0], col[1], col[2], 128);
+ }
+ else {
+ switch(axis) {
+ case 'c':
+ BIF_GetThemeColor3ubv(TH_TRANSFORM, col);
+ if(G.vd->twmode == V3D_MANIP_LOCAL) {
+ col[0]= col[0]>200?255:col[0]+55;
+ col[1]= col[1]>200?255:col[1]+55;
+ col[2]= col[2]>200?255:col[2]+55;
+ }
+ else if(G.vd->twmode == V3D_MANIP_NORMAL) {
+ col[0]= col[0]<55?0:col[0]-55;
+ col[1]= col[1]<55?0:col[1]-55;
+ col[2]= col[2]<55?0:col[2]-55;
+ }
+ glColor4ub(col[0], col[1], col[2], 128);
+ break;
+ case 'x':
+ glColor4ub(220, 0, 0, 128);
+ break;
+ case 'y':
+ glColor4ub(0, 220, 0, 128);
+ break;
+ case 'z':
+ glColor4ub(30, 30, 220, 128);
+ break;
+ }
+ }
+}
+
+/* viewmatrix should have been set OK, also no shademode! */
+static void draw_manipulator_axes(int colcode, int flagx, int flagy, int flagz)
+{
+
+ /* axes */
+ if(flagx) {
+ manipulator_setcolor('x', colcode);
+ if(flagx & MAN_SCALE_X) glLoadName(MAN_SCALE_X);
+ else if(flagx & MAN_TRANS_X) glLoadName(MAN_TRANS_X);
+ glBegin(GL_LINES);
+ glVertex3f(0.2f, 0.0f, 0.0f);
+ glVertex3f(1.0f, 0.0f, 0.0f);
+ glEnd();
+ }
+ if(flagy) {
+ if(flagy & MAN_SCALE_Y) glLoadName(MAN_SCALE_Y);
+ else if(flagy & MAN_TRANS_Y) glLoadName(MAN_TRANS_Y);
+ manipulator_setcolor('y', colcode);
+ glBegin(GL_LINES);
+ glVertex3f(0.0f, 0.2f, 0.0f);
+ glVertex3f(0.0f, 1.0f, 0.0f);
+ glEnd();
+ }
+ if(flagz) {
+ if(flagz & MAN_SCALE_Z) glLoadName(MAN_SCALE_Z);
+ else if(flagz & MAN_TRANS_Z) glLoadName(MAN_TRANS_Z);
+ manipulator_setcolor('z', colcode);
+ glBegin(GL_LINES);
+ glVertex3f(0.0f, 0.0f, 0.2f);
+ glVertex3f(0.0f, 0.0f, 1.0f);
+ glEnd();
+ }
+}
+
+/* only called while G.moving */
+static void draw_manipulator_rotate_ghost(float mat[][4], int drawflags)
+{
+ GLUquadricObj *qobj;
+ float size, phi, startphi, vec[3], svec[3], matt[4][4], cross[3], tmat[3][3];
+ int arcs= (G.rt!=2);
+
+ glDisable(GL_DEPTH_TEST);
+
+ qobj= gluNewQuadric();
+ gluQuadricDrawStyle(qobj, GLU_FILL);
+
+ glColor4ub(0,0,0,64);
+ glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_BLEND);
+
+ /* we need both [4][4] transforms, Trans.mat seems to be premul, not post for mat[][4] */
+ Mat4CpyMat4(matt, mat); // to copy the parts outside of [3][3]
+ Mat4MulMat34(matt, Trans.mat, mat);
+
+ /* Screen aligned view rot circle */
+ if(drawflags & MAN_ROT_V) {
+
+ /* prepare for screen aligned draw */
+ glPushMatrix();
+ size= screen_aligned(mat);
+
+ vec[0]= (float)(Trans.con.imval[0] - Trans.center2d[0]);
+ vec[1]= (float)(Trans.con.imval[1] - Trans.center2d[1]);
+ vec[2]= 0.0f;
+ Normalize(vec);
+
+ startphi= saacos( vec[1] );
+ if(vec[0]<0.0) startphi= -startphi;
+
+ phi= (float)fmod(180.0*Trans.val/M_PI, 360.0);
+ if(phi > 180.0) phi-= 360.0;
+ else if(phi<-180.0) phi+= 360.0;
+
+ gluPartialDisk(qobj, 0.0, size, 32, 1, 180.0*startphi/M_PI, phi);
+
+ glPopMatrix();
+ }
+ else if(arcs) {
+ float imat[3][3], ivmat[3][3];
+ /* try to get the start rotation */
+
+ svec[0]= (float)(Trans.con.imval[0] - Trans.center2d[0]);
+ svec[1]= (float)(Trans.con.imval[1] - Trans.center2d[1]);
+ svec[2]= 0.0f;
+
+ /* screen aligned vec transform back to manipulator space */
+ Mat3CpyMat4(ivmat, G.vd->viewinv);
+ Mat3CpyMat4(tmat, mat);
+ Mat3Inv(imat, tmat);
+ Mat3MulMat3(tmat, imat, ivmat);
+
+ Mat3MulVecfl(tmat, svec); // tmat is used further on
+ Normalize(svec);
+ }
+
+ mymultmatrix(mat); // aligns with original widget
+
+ /* Z disk */
+ if(drawflags & MAN_ROT_Z) {
+ if(arcs) {
+ /* correct for squeezed arc */
+ svec[0]+= tmat[2][0];
+ svec[1]+= tmat[2][1];
+ Normalize(svec);
+
+ startphi= (float)atan2(svec[0], svec[1]);
+ }
+ else startphi= 0.5f*(float)M_PI;
+
+ VECCOPY(vec, mat[0]); // use x axis to detect rotation
+ Normalize(vec);
+ Normalize(matt[0]);
+ phi= saacos( Inpf(vec, matt[0]) );
+ if(phi!=0.0) {
+ Crossf(cross, vec, matt[0]); // results in z vector
+ if(Inpf(cross, mat[2]) > 0.0) phi= -phi;
+ gluPartialDisk(qobj, 0.0, 1.0, 32, 1, 180.0*startphi/M_PI, 180.0*(phi)/M_PI);
+ }
+ }
+ /* X disk */
+ if(drawflags & MAN_ROT_X) {
+ if(arcs) {
+ /* correct for squeezed arc */
+ svec[1]+= tmat[2][1];
+ svec[2]+= tmat[2][2];
+ Normalize(svec);
+
+ startphi= (float)(M_PI + atan2(svec[2], -svec[1]));
+ }
+ else startphi= 0.0f;
+
+ VECCOPY(vec, mat[1]); // use y axis to detect rotation
+ Normalize(vec);
+ Normalize(matt[1]);
+ phi= saacos( Inpf(vec, matt[1]) );
+ if(phi!=0.0) {
+ Crossf(cross, vec, matt[1]); // results in x vector
+ if(Inpf(cross, mat[0]) > 0.0) phi= -phi;
+ glRotatef(90.0, 0.0, 1.0, 0.0);
+ gluPartialDisk(qobj, 0.0, 1.0, 32, 1, 180.0*startphi/M_PI, 180.0*phi/M_PI);
+ glRotatef(-90.0, 0.0, 1.0, 0.0);
+ }
+ }
+ /* Y circle */
+ if(drawflags & MAN_ROT_Y) {
+ if(arcs) {
+ /* correct for squeezed arc */
+ svec[0]+= tmat[2][0];
+ svec[2]+= tmat[2][2];
+ Normalize(svec);
+
+ startphi= (float)(M_PI + atan2(-svec[0], svec[2]));
+ }
+ else startphi= (float)M_PI;
+
+ VECCOPY(vec, mat[2]); // use z axis to detect rotation
+ Normalize(vec);
+ Normalize(matt[2]);
+ phi= saacos( Inpf(vec, matt[2]) );
+ if(phi!=0.0) {
+ Crossf(cross, vec, matt[2]); // results in y vector
+ if(Inpf(cross, mat[1]) > 0.0) phi= -phi;
+ glRotatef(-90.0, 1.0, 0.0, 0.0);
+ gluPartialDisk(qobj, 0.0, 1.0, 32, 1, 180.0*startphi/M_PI, 180.0*phi/M_PI);
+ glRotatef(90.0, 1.0, 0.0, 0.0);
+ }
+ }
+
+ glDisable(GL_BLEND);
+ myloadmatrix(G.vd->viewmat);
+}
+
+static void draw_manipulator_rotate(float mat[][4], int moving, int drawflags, int combo)
+{
+ GLUquadricObj *qobj;
+ double plane[4];
+ float size, vec[3], unitmat[4][4];
+ float cywid= 0.33f*0.01f*(float)U.tw_handlesize;
+ float cusize= cywid*0.65f;
+ int arcs= (G.rt!=2);
+ int colcode;
+
+ if(moving) colcode= MAN_MOVECOL;
+ else colcode= MAN_RGB;
+
+ /* when called while moving in mixed mode, do not draw when... */
+ if((drawflags & MAN_ROT_C)==0) return;
+
+ /* Init stuff */
+ glDisable(GL_DEPTH_TEST);
+ Mat4One(unitmat);
+
+ qobj= gluNewQuadric();
+ gluQuadricDrawStyle(qobj, GLU_FILL);
+
+ /* prepare for screen aligned draw */
+ VECCOPY(vec, mat[0]);
+ size= Normalize(vec);
+ glPushMatrix();
+ glTranslatef(mat[3][0], mat[3][1], mat[3][2]);
+
+ if(arcs) {
+ /* clipplane makes nice handles, calc here because of multmatrix but with translate! */
+ VECCOPY(plane, G.vd->viewinv[2]);
+ plane[3]= -0.02*size; // clip just a bit more
+ glClipPlane(GL_CLIP_PLANE0, plane);
+ }
+ /* sets view screen aligned */
+ glRotatef( -360.0f*saacos(G.vd->viewquat[0])/(float)M_PI, G.vd->viewquat[1], G.vd->viewquat[2], G.vd->viewquat[3]);
+
+ /* Screen aligned help circle */
+ if(arcs) {
+ if((G.f & G_PICKSEL)==0) {
+ BIF_ThemeColorShade(TH_BACK, -30);
+ drawcircball(GL_LINE_LOOP, unitmat[3], size, unitmat);
+ }
+ }
+ /* Screen aligned view rot circle */
+ if(drawflags & MAN_ROT_V) {
+ if(G.f & G_PICKSEL) glLoadName(MAN_ROT_V);
+ BIF_ThemeColor(TH_TRANSFORM);
+ drawcircball(GL_LINE_LOOP, unitmat[3], 1.2f*size, unitmat);
+
+ if(moving) {
+ float vec[3];
+ vec[0]= (float)(Trans.imval[0] - Trans.center2d[0]);
+ vec[1]= (float)(Trans.imval[1] - Trans.center2d[1]);
+ vec[2]= 0.0f;
+ Normalize(vec);
+ VecMulf(vec, 1.2f*size);
+ glBegin(GL_LINES);
+ glVertex3f(0.0f, 0.0f, 0.0f);
+ glVertex3fv(vec);
+ glEnd();
+ }
+ }
+ glPopMatrix();
+
+ /* apply the transform delta */
+ if(moving) {
+ float matt[4][4];
+ Mat4CpyMat4(matt, mat); // to copy the parts outside of [3][3]
+ Mat4MulMat34(matt, Trans.mat, mat);
+ mymultmatrix(matt);
+ glFrontFace( is_mat4_flipped(matt)?GL_CW:GL_CCW);
+ }
+ else {
+ glFrontFace( is_mat4_flipped(mat)?GL_CW:GL_CCW);
+ mymultmatrix(mat);
+ }
+
+ /* axes */
+ if(arcs==0) {
+ if(!(G.f & G_PICKSEL)) {
+ if( (combo & V3D_MANIP_SCALE)==0) {
+ /* axis */
+ glBegin(GL_LINES);
+ if( (drawflags & MAN_ROT_X) || (moving && (drawflags & MAN_ROT_Z)) ) {
+ manipulator_setcolor('x', colcode);
+ glVertex3f(0.2f, 0.0f, 0.0f);
+ glVertex3f(1.0f, 0.0f, 0.0f);
+ }
+ if( (drawflags & MAN_ROT_Y) || (moving && (drawflags & MAN_ROT_X)) ) {
+ manipulator_setcolor('y', colcode);
+ glVertex3f(0.0f, 0.2f, 0.0f);
+ glVertex3f(0.0f, 1.0f, 0.0f);
+ }
+ if( (drawflags & MAN_ROT_Z) || (moving && (drawflags & MAN_ROT_Y)) ) {
+ manipulator_setcolor('z', colcode);
+ glVertex3f(0.0f, 0.0f, 0.2f);
+ glVertex3f(0.0f, 0.0f, 1.0f);
+ }
+ glEnd();
+ }
+ }
+ }
+
+ if(arcs==0 && moving) {
+
+ /* Z circle */
+ if(drawflags & MAN_ROT_Z) {
+ if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Z);
+ manipulator_setcolor('z', colcode);
+ drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat);
+ }
+ /* X circle */
+ if(drawflags & MAN_ROT_X) {
+ if(G.f & G_PICKSEL) glLoadName(MAN_ROT_X);
+ glRotatef(90.0, 0.0, 1.0, 0.0);
+ manipulator_setcolor('x', colcode);
+ drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat);
+ glRotatef(-90.0, 0.0, 1.0, 0.0);
+ }
+ /* Y circle */
+ if(drawflags & MAN_ROT_Y) {
+ if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Y);
+ glRotatef(-90.0, 1.0, 0.0, 0.0);
+ manipulator_setcolor('y', colcode);
+ drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat);
+ glRotatef(90.0, 1.0, 0.0, 0.0);
+ }
+
+ if(arcs) glDisable(GL_CLIP_PLANE0);
+ }
+ // donut arcs
+ if(arcs) {
+ glEnable(GL_CLIP_PLANE0);
+
+ /* Z circle */
+ if(drawflags & MAN_ROT_Z) {
+ if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Z);
+ manipulator_setcolor('z', colcode);
+ partial_donut(cusize/4.0f, 1.0f, 0, 48, 8, 48);
+ }
+ /* X circle */
+ if(drawflags & MAN_ROT_X) {
+ if(G.f & G_PICKSEL) glLoadName(MAN_ROT_X);
+ glRotatef(90.0, 0.0, 1.0, 0.0);
+ manipulator_setcolor('x', colcode);
+ partial_donut(cusize/4.0f, 1.0f, 0, 48, 8, 48);
+ glRotatef(-90.0, 0.0, 1.0, 0.0);
+ }
+ /* Y circle */
+ if(drawflags & MAN_ROT_Y) {
+ if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Y);
+ glRotatef(-90.0, 1.0, 0.0, 0.0);
+ manipulator_setcolor('y', colcode);
+ partial_donut(cusize/4.0f, 1.0f, 0, 48, 8, 48);
+ glRotatef(90.0, 1.0, 0.0, 0.0);
+ }
+
+ glDisable(GL_CLIP_PLANE0);
+ }
+
+ if(arcs==0) {
+
+ /* Z handle on X axis */
+ if(drawflags & MAN_ROT_Z) {
+ glPushMatrix();
+ if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Z);
+ manipulator_setcolor('z', colcode);
+
+ partial_donut(0.7f*cusize, 1.0f, 31, 33, 8, 64);
+
+ glPopMatrix();
+ }
+
+ /* Y handle on X axis */
+ if(drawflags & MAN_ROT_Y) {
+ glPushMatrix();
+ if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Y);
+ manipulator_setcolor('y', colcode);
+
+ glRotatef(90.0, 1.0, 0.0, 0.0);
+ glRotatef(90.0, 0.0, 0.0, 1.0);
+ partial_donut(0.7f*cusize, 1.0f, 31, 33, 8, 64);
+
+ glPopMatrix();
+ }
+
+ /* X handle on Z axis */
+ if(drawflags & MAN_ROT_X) {
+ glPushMatrix();
+ if(G.f & G_PICKSEL) glLoadName(MAN_ROT_X);
+ manipulator_setcolor('x', colcode);
+
+ glRotatef(-90.0, 0.0, 1.0, 0.0);
+ glRotatef(90.0, 0.0, 0.0, 1.0);
+ partial_donut(0.7f*cusize, 1.0f, 31, 33, 8, 64);
+
+ glPopMatrix();
+ }
+
+ }
+
+ /* restore */
+ myloadmatrix(G.vd->viewmat);
+ gluDeleteQuadric(qobj);
+ if(G.vd->zbuf) glEnable(GL_DEPTH_TEST);
+
+}
+
+static void draw_manipulator_scale(float mat[][4], int moving, int drawflags, int combo, int colcode)
+{
+ float cywid= 0.25f*0.01f*(float)U.tw_handlesize;
+ float cusize= cywid*0.75f, dz;
+
+ /* when called while moving in mixed mode, do not draw when... */
+ if((drawflags & MAN_SCALE_C)==0) return;
+
+ glDisable(GL_DEPTH_TEST);
+
+ /* not in combo mode */
+ if( (combo & (V3D_MANIP_TRANSLATE|V3D_MANIP_ROTATE))==0) {
+ float size, unitmat[4][4];
+
+ /* center circle, do not add to selection when shift is pressed (planar constraint) */
+ if( (G.f & G_PICKSEL) && (G.qual & LR_SHIFTKEY)==0) glLoadName(MAN_SCALE_C);
+
+ manipulator_setcolor('c', colcode);
+ glPushMatrix();
+ size= screen_aligned(mat);
+ Mat4One(unitmat);
+ drawcircball(GL_LINE_LOOP, unitmat[3], 0.2f*size, unitmat);
+ glPopMatrix();
+
+ dz= 1.0;
+ }
+ else dz= 1.0f-4.0f*cusize;
+
+ if(moving) {
+ float matt[4][4];
+
+ Mat4CpyMat4(matt, mat); // to copy the parts outside of [3][3]
+ Mat4MulMat34(matt, Trans.mat, mat);
+ mymultmatrix(matt);
+ glFrontFace( is_mat4_flipped(matt)?GL_CW:GL_CCW);
+ }
+ else {
+ mymultmatrix(mat);
+ glFrontFace( is_mat4_flipped(mat)?GL_CW:GL_CCW);
+ }
+
+ /* axis */
+
+ /* in combo mode, this is always drawn as first type */
+ draw_manipulator_axes(colcode, drawflags & MAN_SCALE_X, drawflags & MAN_SCALE_Y, drawflags & MAN_SCALE_Z);
+
+ /* Z cube */
+ glTranslatef(0.0, 0.0, dz);
+ if(drawflags & MAN_SCALE_Z) {
+ if(G.f & G_PICKSEL) glLoadName(MAN_SCALE_Z);
+ manipulator_setcolor('z', colcode);
+ drawsolidcube(cusize);
+ }
+ /* X cube */
+ glTranslatef(dz, 0.0, -dz);
+ if(drawflags & MAN_SCALE_X) {
+ if(G.f & G_PICKSEL) glLoadName(MAN_SCALE_X);
+ manipulator_setcolor('x', colcode);
+ drawsolidcube(cusize);
+ }
+ /* Y cube */
+ glTranslatef(-dz, dz, 0.0);
+ if(drawflags & MAN_SCALE_Y) {
+ if(G.f & G_PICKSEL) glLoadName(MAN_SCALE_Y);
+ manipulator_setcolor('y', colcode);
+ drawsolidcube(cusize);
+ }
+
+ /* if shiftkey, center point as last, for selectbuffer order */
+ if(G.f & G_PICKSEL) {
+ if(G.qual & LR_SHIFTKEY) {
+ glTranslatef(0.0, -dz, 0.0);
+ glLoadName(MAN_SCALE_C);
+ glBegin(GL_POINTS);
+ glVertex3f(0.0, 0.0, 0.0);
+ glEnd();
+ }
+ }
+
+ /* restore */
+ myloadmatrix(G.vd->viewmat);
+
+ if(G.vd->zbuf) glEnable(GL_DEPTH_TEST);
+ glFrontFace(GL_CCW);
+}
+
+
+static void draw_cone(GLUquadricObj *qobj, float len, float width)
+{
+ glTranslatef(0.0, 0.0, -0.5f*len);
+ gluCylinder(qobj, width, 0.0, len, 8, 1);
+ gluQuadricOrientation(qobj, GLU_INSIDE);
+ gluDisk(qobj, 0.0, width, 8, 1);
+ gluQuadricOrientation(qobj, GLU_OUTSIDE);
+ glTranslatef(0.0, 0.0, 0.5f*len);
+}
+
+static void draw_cylinder(GLUquadricObj *qobj, float len, float width)
+{
+
+ width*= 0.8f; // just for beauty
+
+ glTranslatef(0.0, 0.0, -0.5f*len);
+ gluCylinder(qobj, width, width, len, 8, 1);
+ gluQuadricOrientation(qobj, GLU_INSIDE);
+ gluDisk(qobj, 0.0, width, 8, 1);
+ gluQuadricOrientation(qobj, GLU_OUTSIDE);
+ glTranslatef(0.0, 0.0, len);
+ gluDisk(qobj, 0.0, width, 8, 1);
+ glTranslatef(0.0, 0.0, -0.5f*len);
+}
+
+
+static void draw_manipulator_translate(float mat[][4], int moving, int drawflags, int combo, int colcode)
+{
+ GLUquadricObj *qobj;
+ float cylen= 0.01f*(float)U.tw_handlesize;
+ float cywid= 0.25f*cylen, dz, size;
+ float unitmat[4][4];
+
+ /* when called while moving in mixed mode, do not draw when... */
+ if((drawflags & MAN_TRANS_C)==0) return;
+
+ if(moving) glTranslatef(Trans.vec[0], Trans.vec[1], Trans.vec[2]);
+ glDisable(GL_DEPTH_TEST);
+
+ qobj= gluNewQuadric();
+ gluQuadricDrawStyle(qobj, GLU_FILL);
+
+ /* center circle, do not add to selection when shift is pressed (planar constraint) */
+ if( (G.f & G_PICKSEL) && (G.qual & LR_SHIFTKEY)==0) glLoadName(MAN_TRANS_C);
+
+ manipulator_setcolor('c', colcode);
+ glPushMatrix();
+ size= screen_aligned(mat);
+ Mat4One(unitmat);
+ drawcircball(GL_LINE_LOOP, unitmat[3], 0.2f*size, unitmat);
+ glPopMatrix();
+
+ /* and now apply matrix, we move to local matrix drawing */
+ mymultmatrix(mat);
+
+ /* axis */
+ glLoadName(-1);
+
+ // translate drawn as last, only axis when no combo with scale, or for ghosting
+ if((combo & V3D_MANIP_SCALE)==0 || colcode==MAN_GHOST)
+ draw_manipulator_axes(colcode, drawflags & MAN_TRANS_X, drawflags & MAN_TRANS_Y, drawflags & MAN_TRANS_Z);
+
+
+ /* offset in combo mode, for rotate a bit more */
+ if(combo & (V3D_MANIP_ROTATE)) dz= 1.0f+2.0f*cylen;
+ else if(combo & (V3D_MANIP_SCALE)) dz= 1.0f+0.5f*cylen;
+ else dz= 1.0f;
+
+ /* Z Cone */
+ glTranslatef(0.0, 0.0, dz);
+ if(drawflags & MAN_TRANS_Z) {
+ if(G.f & G_PICKSEL) glLoadName(MAN_TRANS_Z);
+ manipulator_setcolor('z', colcode);
+ draw_cone(qobj, cylen, cywid);
+ }
+ /* X Cone */
+ glTranslatef(dz, 0.0, -dz);
+ if(drawflags & MAN_TRANS_X) {
+ if(G.f & G_PICKSEL) glLoadName(MAN_TRANS_X);
+ glRotatef(90.0, 0.0, 1.0, 0.0);
+ manipulator_setcolor('x', colcode);
+ draw_cone(qobj, cylen, cywid);
+ glRotatef(-90.0, 0.0, 1.0, 0.0);
+ }
+ /* Y Cone */
+ glTranslatef(-dz, dz, 0.0);
+ if(drawflags & MAN_TRANS_Y) {
+ if(G.f & G_PICKSEL) glLoadName(MAN_TRANS_Y);
+ glRotatef(-90.0, 1.0, 0.0, 0.0);
+ manipulator_setcolor('y', colcode);
+ draw_cone(qobj, cylen, cywid);
+ }
+
+ gluDeleteQuadric(qobj);
+ myloadmatrix(G.vd->viewmat);
+
+ if(G.vd->zbuf) glEnable(GL_DEPTH_TEST);
+
+}
+
+static void draw_manipulator_rotate_cyl(float mat[][4], int moving, int drawflags, int combo, int colcode)
+{
+ GLUquadricObj *qobj;
+ float size;
+ float cylen= 0.01f*(float)U.tw_handlesize;
+ float cywid= 0.25f*cylen;
+
+ /* when called while moving in mixed mode, do not draw when... */
+ if((drawflags & MAN_ROT_C)==0) return;
+
+ /* prepare for screen aligned draw */
+ glPushMatrix();
+ size= screen_aligned(mat);
+
+ glDisable(GL_DEPTH_TEST);
+
+ qobj= gluNewQuadric();
+
+ /* Screen aligned view rot circle */
+ if(drawflags & MAN_ROT_V) {
+ float unitmat[4][4];
+ Mat4One(unitmat);
+
+ if(G.f & G_PICKSEL) glLoadName(MAN_ROT_V);
+ BIF_ThemeColor(TH_TRANSFORM);
+ drawcircball(GL_LINE_LOOP, unitmat[3], 1.2f*size, unitmat);
+
+ if(moving) {
+ float vec[3];
+ vec[0]= (float)(Trans.imval[0] - Trans.center2d[0]);
+ vec[1]= (float)(Trans.imval[1] - Trans.center2d[1]);
+ vec[2]= 0.0f;
+ Normalize(vec);
+ VecMulf(vec, 1.2f*size);
+ glBegin(GL_LINES);
+ glVertex3f(0.0, 0.0, 0.0);
+ glVertex3fv(vec);
+ glEnd();
+ }
+ }
+ glPopMatrix();
+
+ /* apply the transform delta */
+ if(moving) {
+ float matt[4][4];
+ Mat4CpyMat4(matt, mat); // to copy the parts outside of [3][3]
+ if (Trans.flag & T_USES_MANIPULATOR) {
+ Mat4MulMat34(matt, Trans.mat, mat);
+ }
+ mymultmatrix(matt);
+ }
+ else {
+ mymultmatrix(mat);
+ }
+
+ glFrontFace( is_mat4_flipped(mat)?GL_CW:GL_CCW);
+
+ /* axis */
+ if( (G.f & G_PICKSEL)==0 ) {
+
+ // only draw axis when combo didn't draw scale axes
+ if((combo & V3D_MANIP_SCALE)==0)
+ draw_manipulator_axes(colcode, drawflags & MAN_ROT_X, drawflags & MAN_ROT_Y, drawflags & MAN_ROT_Z);
+
+ /* only has to be set when not in picking */
+ gluQuadricDrawStyle(qobj, GLU_FILL);
+ }
+
+ /* Z cyl */
+ glTranslatef(0.0, 0.0, 1.0);
+ if(drawflags & MAN_ROT_Z) {
+ if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Z);
+ manipulator_setcolor('z', colcode);
+ draw_cylinder(qobj, cylen, cywid);
+ }
+ /* X cyl */
+ glTranslatef(1.0, 0.0, -1.0);
+ if(drawflags & MAN_ROT_X) {
+ if(G.f & G_PICKSEL) glLoadName(MAN_ROT_X);
+ glRotatef(90.0, 0.0, 1.0, 0.0);
+ manipulator_setcolor('x', colcode);
+ draw_cylinder(qobj, cylen, cywid);
+ glRotatef(-90.0, 0.0, 1.0, 0.0);
+ }
+ /* Y cylinder */
+ glTranslatef(-1.0, 1.0, 0.0);
+ if(drawflags & MAN_ROT_Y) {
+ if(G.f & G_PICKSEL) glLoadName(MAN_ROT_Y);
+ glRotatef(-90.0, 1.0, 0.0, 0.0);
+ manipulator_setcolor('y', colcode);
+ draw_cylinder(qobj, cylen, cywid);
+ }
+
+ /* restore */
+
+ gluDeleteQuadric(qobj);
+ myloadmatrix(G.vd->viewmat);
+
+ if(G.vd->zbuf) glEnable(GL_DEPTH_TEST);
+
+}
+
+
+/* ********************************************* */
+
+float get_drawsize(View3D *v3d)
+{
+ ScrArea *sa = v3d->area;
+ float size, vec[3], len1, len2;
+
+ /* size calculus, depending ortho/persp settings, like initgrabz() */
+ size= v3d->persmat[0][3]*v3d->twmat[3][0]+ v3d->persmat[1][3]*v3d->twmat[3][1]+ v3d->persmat[2][3]*v3d->twmat[3][2]+ v3d->persmat[3][3];
+
+ VECCOPY(vec, v3d->persinv[0]);
+ len1= Normalize(vec);
+ VECCOPY(vec, v3d->persinv[1]);
+ len2= Normalize(vec);
+
+ size*= 0.01f*(len1>len2?len1:len2);
+
+ /* correct for window size to make widgets appear fixed size */
+ if(sa->winx > sa->winy) size*= 1000.0f/(float)sa->winx;
+ else size*= 1000.0f/(float)sa->winy;
+
+ return size;
+}
+
+static float get_manipulator_drawsize(ScrArea *sa)
+{
+ View3D *v3d= sa->spacedata.first;
+ float size = get_drawsize(v3d);
+
+ size*= (float)U.tw_size;
+
+ return size;
+}
+
+/* exported to transform_constraints.c */
+/* mat, vec = default orientation and location */
+/* type = transform type */
+/* axis = x, y, z, c */
+/* col: 0 = colored, 1 = moving, 2 = ghost */
+void draw_manipulator_ext(ScrArea *sa, int type, char axis, int col, float vec[3], float mat[][3])
+{
+ int drawflags= 0;
+ float mat4[4][4];
+ int colcode;
+
+ Mat4CpyMat3(mat4, mat);
+ VECCOPY(mat4[3], vec);
+
+ Mat4MulFloat3((float *)mat4, get_manipulator_drawsize(sa));
+
+ glEnable(GL_BLEND); // let's do it transparent by default
+ if(col==0) colcode= MAN_RGB;
+ else if(col==1) colcode= MAN_MOVECOL;
+ else colcode= MAN_GHOST;
+
+
+ if(type==TFM_ROTATION) {
+ if(axis=='x') drawflags= MAN_ROT_X;
+ else if(axis=='y') drawflags= MAN_ROT_Y;
+ else if(axis=='z') drawflags= MAN_ROT_Z;
+ else drawflags= MAN_ROT_C;
+
+ draw_manipulator_rotate_cyl(mat4, col, drawflags, V3D_MANIP_ROTATE, colcode);
+ }
+ else if(type==TFM_RESIZE) {
+ if(axis=='x') drawflags= MAN_SCALE_X;
+ else if(axis=='y') drawflags= MAN_SCALE_Y;
+ else if(axis=='z') drawflags= MAN_SCALE_Z;
+ else drawflags= MAN_SCALE_C;
+
+ draw_manipulator_scale(mat4, col, drawflags, V3D_MANIP_SCALE, colcode);
+ }
+ else {
+ if(axis=='x') drawflags= MAN_TRANS_X;
+ else if(axis=='y') drawflags= MAN_TRANS_Y;
+ else if(axis=='z') drawflags= MAN_TRANS_Z;
+ else drawflags= MAN_TRANS_C;
+
+ draw_manipulator_translate(mat4, 0, drawflags, V3D_MANIP_TRANSLATE, colcode);
+ }
+
+
+ glDisable(GL_BLEND);
+}
+
+/* main call, does calc centers & orientation too */
+/* uses global G.moving */
+static int drawflags= 0xFFFF; // only for the calls below, belongs in scene...?
+void BIF_draw_manipulator(ScrArea *sa)
+{
+ View3D *v3d= sa->spacedata.first;
+ int totsel;
+
+ if(!(v3d->twflag & V3D_USE_MANIPULATOR)) return;
+ if(G.moving && (G.moving & G_TRANSFORM_MANIP)==0) return;
+
+ if(G.moving==0) {
+ v3d->twflag &= ~V3D_DRAW_MANIPULATOR;
+
+ totsel= calc_manipulator_stats(sa);
+ if(totsel==0) return;
+ drawflags= v3d->twdrawflag; /* set in calc_manipulator_stats */
+
+ v3d->twflag |= V3D_DRAW_MANIPULATOR;
+
+ /* now we can define center */
+ switch(v3d->around) {
+ case V3D_CENTER:
+ case V3D_ACTIVE:
+ v3d->twmat[3][0]= (G.scene->twmin[0] + G.scene->twmax[0])/2.0f;
+ v3d->twmat[3][1]= (G.scene->twmin[1] + G.scene->twmax[1])/2.0f;
+ v3d->twmat[3][2]= (G.scene->twmin[2] + G.scene->twmax[2])/2.0f;
+ if(v3d->around==V3D_ACTIVE && G.obedit==NULL) {
+ Object *ob= OBACT;
+ if(ob && !(ob->flag & OB_POSEMODE))
+ VECCOPY(v3d->twmat[3], ob->obmat[3]);
+ }
+ break;
+ case V3D_LOCAL:
+ case V3D_CENTROID:
+ VECCOPY(v3d->twmat[3], G.scene->twcent);
+ break;
+ case V3D_CURSOR:
+ VECCOPY(v3d->twmat[3], give_cursor());
+ break;
+ }
+
+ Mat4MulFloat3((float *)v3d->twmat, get_manipulator_drawsize(sa));
+ }
+
+ if(v3d->twflag & V3D_DRAW_MANIPULATOR) {
+
+ if(v3d->twtype & V3D_MANIP_ROTATE) {
+
+ /* rotate has special ghosting draw, for pie chart */
+ if(G.moving) draw_manipulator_rotate_ghost(v3d->twmat, drawflags);
+
+ if(G.moving) glEnable(GL_BLEND);
+
+ if(G.rt==3) {
+ if(G.moving) draw_manipulator_rotate_cyl(v3d->twmat, 1, drawflags, v3d->twtype, MAN_MOVECOL);
+ else draw_manipulator_rotate_cyl(v3d->twmat, 0, drawflags, v3d->twtype, MAN_RGB);
+ }
+ else
+ draw_manipulator_rotate(v3d->twmat, G.moving, drawflags, v3d->twtype);
+
+ glDisable(GL_BLEND);
+ }
+ if(v3d->twtype & V3D_MANIP_SCALE) {
+ if(G.moving) {
+ glEnable(GL_BLEND);
+ draw_manipulator_scale(v3d->twmat, 0, drawflags, v3d->twtype, MAN_GHOST);
+ draw_manipulator_scale(v3d->twmat, 1, drawflags, v3d->twtype, MAN_MOVECOL);
+ glDisable(GL_BLEND);
+ }
+ else draw_manipulator_scale(v3d->twmat, 0, drawflags, v3d->twtype, MAN_RGB);
+ }
+ if(v3d->twtype & V3D_MANIP_TRANSLATE) {
+ if(G.moving) {
+ glEnable(GL_BLEND);
+ draw_manipulator_translate(v3d->twmat, 0, drawflags, v3d->twtype, MAN_GHOST);
+ draw_manipulator_translate(v3d->twmat, 1, drawflags, v3d->twtype, MAN_MOVECOL);
+ glDisable(GL_BLEND);
+ }
+ else draw_manipulator_translate(v3d->twmat, 0, drawflags, v3d->twtype, MAN_RGB);
+ }
+ }
+}
+
+static int manipulator_selectbuf(ScrArea *sa, float hotspot)
+{
+ View3D *v3d= sa->spacedata.first;
+ rctf rect;
+ GLuint buffer[64]; // max 4 items per select, so large enuf
+ short hits, mval[2];
+
+ G.f |= G_PICKSEL;
+
+ getmouseco_areawin(mval);
+ rect.xmin= mval[0]-hotspot;
+ rect.xmax= mval[0]+hotspot;
+ rect.ymin= mval[1]-hotspot;
+ rect.ymax= mval[1]+hotspot;
+
+ /* get rid of overlay button matrix */
+ persp(PERSP_VIEW);
+
+ setwinmatrixview3d(sa->winx, sa->winy, &rect);
+ Mat4MulMat4(v3d->persmat, v3d->viewmat, sa->winmat);
+
+ glSelectBuffer( 64, buffer);
+ glRenderMode(GL_SELECT);
+ glInitNames(); /* these two calls whatfor? It doesnt work otherwise */
+ glPushName(-2);
+
+ /* do the drawing */
+ if(v3d->twtype & V3D_MANIP_ROTATE) {
+ if(G.rt==3) draw_manipulator_rotate_cyl(v3d->twmat, 0, MAN_ROT_C & v3d->twdrawflag, v3d->twtype, MAN_RGB);
+ else draw_manipulator_rotate(v3d->twmat, 0, MAN_ROT_C & v3d->twdrawflag, v3d->twtype);
+ }
+ if(v3d->twtype & V3D_MANIP_SCALE)
+ draw_manipulator_scale(v3d->twmat, 0, MAN_SCALE_C & v3d->twdrawflag, v3d->twtype, MAN_RGB);
+ if(v3d->twtype & V3D_MANIP_TRANSLATE)
+ draw_manipulator_translate(v3d->twmat, 0, MAN_TRANS_C & v3d->twdrawflag, v3d->twtype, MAN_RGB);
+
+ glPopName();
+ hits= glRenderMode(GL_RENDER);
+
+ G.f &= ~G_PICKSEL;
+ setwinmatrixview3d(sa->winx, sa->winy, NULL);
+ Mat4MulMat4(v3d->persmat, v3d->viewmat, sa->winmat);
+
+ persp(PERSP_WIN);
+
+ if(hits==1) return buffer[3];
+ else if(hits>1) {
+ GLuint val, dep, mindep=0, mindeprot=0, minval=0, minvalrot=0;
+ int a;
+
+ /* we compare the hits in buffer, but value centers highest */
+ /* we also store the rotation hits separate (because of arcs) and return hits on other widgets if there are */
+
+ for(a=0; a<hits; a++) {
+ dep= buffer[4*a + 1];
+ val= buffer[4*a + 3];
+
+ if(val==MAN_TRANS_C) return MAN_TRANS_C;
+ else if(val==MAN_SCALE_C) return MAN_SCALE_C;
+ else {
+ if(val & MAN_ROT_C) {
+ if(minvalrot==0 || dep<mindeprot) {
+ mindeprot= dep;
+ minvalrot= val;
+ }
+ }
+ else {
+ if(minval==0 || dep<mindep) {
+ mindep= dep;
+ minval= val;
+ }
+ }
+ }
+ }
+
+ if(minval)
+ return minval;
+ else
+ return minvalrot;
+ }
+ return 0;
+}
+
+/* return 0; nothing happened */
+int BIF_do_manipulator(ScrArea *sa)
+{
+ View3D *v3d= sa->spacedata.first;
+ int val;
+
+ if(!(v3d->twflag & V3D_USE_MANIPULATOR)) return 0;
+ if(!(v3d->twflag & V3D_DRAW_MANIPULATOR)) return 0;
+
+ // find the hotspots first test narrow hotspot
+ val= manipulator_selectbuf(sa, 0.5f*(float)U.tw_hotspot);
+ if(val) {
+ checkFirstTime(); // TEMPORARY, check this before doing any transform call.
+ // drawflags still global, for drawing call above
+ drawflags= manipulator_selectbuf(sa, 0.2f*(float)U.tw_hotspot);
+ if(drawflags==0) drawflags= val;
+
+ if (drawflags & MAN_TRANS_C) {
+ initManipulator(TFM_TRANSLATION);
+ switch(drawflags) {
+ case MAN_TRANS_C:
+ break;
+ case MAN_TRANS_X:
+ if(G.qual & LR_SHIFTKEY) {
+ drawflags= MAN_TRANS_Y|MAN_TRANS_Z;
+ BIF_setDualAxisConstraint(v3d->twmat[1], v3d->twmat[2], " Y+Z");
+ }
+ else
+ BIF_setSingleAxisConstraint(v3d->twmat[0], " X");
+ break;
+ case MAN_TRANS_Y:
+ if(G.qual & LR_SHIFTKEY) {
+ drawflags= MAN_TRANS_X|MAN_TRANS_Z;
+ BIF_setDualAxisConstraint(v3d->twmat[0], v3d->twmat[2], " X+Z");
+ }
+ else
+ BIF_setSingleAxisConstraint(v3d->twmat[1], " Y");
+ break;
+ case MAN_TRANS_Z:
+ if(G.qual & LR_SHIFTKEY) {
+ drawflags= MAN_TRANS_X|MAN_TRANS_Y;
+ BIF_setDualAxisConstraint(v3d->twmat[0], v3d->twmat[1], " X+Y");
+ }
+ else
+ BIF_setSingleAxisConstraint(v3d->twmat[2], " Z");
+ break;
+ }
+ ManipulatorTransform();
+ }
+ else if (drawflags & MAN_SCALE_C) {
+ initManipulator(TFM_RESIZE);
+ switch(drawflags) {
+ case MAN_SCALE_X:
+ if(G.qual & LR_SHIFTKEY) {
+ drawflags= MAN_SCALE_Y|MAN_SCALE_Z;
+ BIF_setDualAxisConstraint(v3d->twmat[1], v3d->twmat[2], " Y+Z");
+ }
+ else
+ BIF_setSingleAxisConstraint(v3d->twmat[0], " X");
+ break;
+ case MAN_SCALE_Y:
+ if(G.qual & LR_SHIFTKEY) {
+ drawflags= MAN_SCALE_X|MAN_SCALE_Z;
+ BIF_setDualAxisConstraint(v3d->twmat[0], v3d->twmat[2], " X+Z");
+ }
+ else
+ BIF_setSingleAxisConstraint(v3d->twmat[1], " Y");
+ break;
+ case MAN_SCALE_Z:
+ if(G.qual & LR_SHIFTKEY) {
+ drawflags= MAN_SCALE_X|MAN_SCALE_Y;
+ BIF_setDualAxisConstraint(v3d->twmat[0], v3d->twmat[1], " X+Y");
+ }
+ else
+ BIF_setSingleAxisConstraint(v3d->twmat[2], " Z");
+ break;
+ }
+ ManipulatorTransform();
+ }
+ else if (drawflags == MAN_ROT_T) { /* trackbal need special case, init is different */
+ initManipulator(TFM_TRACKBALL);
+ ManipulatorTransform();
+ }
+ else if (drawflags & MAN_ROT_C) {
+ initManipulator(TFM_ROTATION);
+ switch(drawflags) {
+ case MAN_ROT_X:
+ BIF_setSingleAxisConstraint(v3d->twmat[0], " X");
+ break;
+ case MAN_ROT_Y:
+ BIF_setSingleAxisConstraint(v3d->twmat[1], " Y");
+ break;
+ case MAN_ROT_Z:
+ BIF_setSingleAxisConstraint(v3d->twmat[2], " Z");
+ break;
+ }
+ ManipulatorTransform();
+ }
+ }
+ /* after transform, restore drawflags */
+ drawflags= 0xFFFF;
+
+ return val;
+}
+
+
diff --git a/source/blender/src/transform_numinput.c b/source/blender/src/transform_numinput.c
new file mode 100644
index 00000000000..730d25545bd
--- /dev/null
+++ b/source/blender/src/transform_numinput.c
@@ -0,0 +1,247 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <math.h> /* fabs */
+#include <stdio.h> /* for sprintf */
+
+#include "BKE_global.h" /* for G */
+#include "BKE_utildefines.h" /* ABS */
+
+#include "mydevice.h" /* for KEY defines */
+
+#include "transform.h"
+
+/* ************************** Functions *************************** */
+
+/* ************************** NUMINPUT **************************** */
+
+void outputNumInput(NumInput *n, char *str)
+{
+ char cur;
+ short i, j;
+
+ for (j=0; j<=n->idx_max; j++) {
+ /* if AFFECTALL and no number typed and cursor not on number, use first number */
+ if (n->flag & NUM_AFFECT_ALL && n->idx != j && n->ctrl[j] == 0)
+ i = 0;
+ else
+ i = j;
+
+ if (n->idx != i)
+ cur = ' ';
+ else
+ cur = '|';
+
+ if( n->val[i] > 1e10 || n->val[i] < -1e10 )
+ sprintf(&str[j*20], "%.4e%c", n->val[i], cur);
+ else
+ switch (n->ctrl[i]) {
+ case 0:
+ sprintf(&str[j*20], "NONE%c", cur);
+ break;
+ case 1:
+ case -1:
+ sprintf(&str[j*20], "%.0f%c", n->val[i], cur);
+ break;
+ case 10:
+ case -10:
+ sprintf(&str[j*20], "%.f.%c", n->val[i], cur);
+ break;
+ case 100:
+ case -100:
+ sprintf(&str[j*20], "%.1f%c", n->val[i], cur);
+ break;
+ case 1000:
+ case -1000:
+ sprintf(&str[j*20], "%.2f%c", n->val[i], cur);
+ break;
+ case 10000:
+ case -10000:
+ sprintf(&str[j*20], "%.3f%c", n->val[i], cur);
+ break;
+ default:
+ sprintf(&str[j*20], "%.4e%c", n->val[i], cur);
+ }
+ }
+}
+
+short hasNumInput(NumInput *n)
+{
+ short i;
+
+ for (i=0; i<=n->idx_max; i++) {
+ if (n->ctrl[i])
+ return 1;
+ }
+
+ return 0;
+}
+
+void applyNumInput(NumInput *n, float *vec)
+{
+ short i, j;
+ float val[3];
+
+ if (hasNumInput(n)) {
+ convertDisplayNumToVec(n->val, val);
+
+ for (j=0; j<=n->idx_max; j++) {
+ /* if AFFECTALL and no number typed and cursor not on number, use first number */
+ if (n->flag & NUM_AFFECT_ALL && n->idx != j && n->ctrl[j] == 0)
+ i = 0;
+ else
+ i = j;
+
+ if (n->ctrl[i] == 0 && n->flag & NUM_NULL_ONE) {
+ vec[j] = 1.0f;
+ }
+ else if (val[i] == 0.0f && n->flag & NUM_NO_ZERO) {
+ vec[j] = 0.0001f;
+ }
+ else {
+ vec[j] = val[i];
+ }
+ }
+ }
+}
+
+char handleNumInput(NumInput *n, unsigned short event)
+{
+ float Val = 0;
+ short idx = n->idx, idx_max = n->idx_max;
+
+ switch (event) {
+ case BACKSPACEKEY:
+ if (n->ctrl[idx] == 0) {
+ n->val[0] =
+ n->val[1] =
+ n->val[2] = 0.0f;
+ n->ctrl[0] =
+ n->ctrl[1] =
+ n->ctrl[2] = 0;
+ }
+ else {
+ n->val[idx] = 0.0f;
+ n->ctrl[idx] = 0;
+ }
+ break;
+ case PERIODKEY:
+ case PADPERIOD:
+ if (n->flag & NUM_NO_FRACTION)
+ break;
+
+ switch (n->ctrl[idx])
+ {
+ case 0:
+ case 1:
+ n->ctrl[idx] = 10;
+ break;
+ case -1:
+ n->ctrl[idx] = -10;
+ }
+ break;
+ case PADMINUS:
+ if(G.qual & LR_ALTKEY)
+ break;
+ case MINUSKEY:
+ if (n->flag & NUM_NO_NEGATIVE)
+ break;
+
+ if (n->ctrl[idx]) {
+ n->ctrl[idx] *= -1;
+ n->val[idx] *= -1;
+ }
+ else
+ n->ctrl[idx] = -1;
+ break;
+ case TABKEY:
+ idx++;
+ if (idx > idx_max)
+ idx = 0;
+ n->idx = idx;
+ break;
+ case PAD9:
+ case NINEKEY:
+ Val += 1.0f;
+ case PAD8:
+ case EIGHTKEY:
+ Val += 1.0f;
+ case PAD7:
+ case SEVENKEY:
+ Val += 1.0f;
+ case PAD6:
+ case SIXKEY:
+ Val += 1.0f;
+ case PAD5:
+ case FIVEKEY:
+ Val += 1.0f;
+ case PAD4:
+ case FOURKEY:
+ Val += 1.0f;
+ case PAD3:
+ case THREEKEY:
+ Val += 1.0f;
+ case PAD2:
+ case TWOKEY:
+ Val += 1.0f;
+ case PAD1:
+ case ONEKEY:
+ Val += 1.0f;
+ case PAD0:
+ case ZEROKEY:
+ if (!n->ctrl[idx])
+ n->ctrl[idx] = 1;
+
+ if (fabs(n->val[idx]) > 9999999.0f);
+ else if (n->ctrl[idx] == 1) {
+ n->val[idx] *= 10;
+ n->val[idx] += Val;
+ }
+ else if (n->ctrl[idx] == -1) {
+ n->val[idx] *= 10;
+ n->val[idx] -= Val;
+ }
+ else {
+ /* float resolution breaks when over six digits after comma */
+ if( ABS(n->ctrl[idx]) < 10000000) {
+ n->val[idx] += Val / (float)n->ctrl[idx];
+ n->ctrl[idx] *= 10;
+ }
+ }
+ break;
+ default:
+ return 0;
+ }
+
+ /* REDRAW SINCE NUMBERS HAVE CHANGED */
+ return 1;
+}
diff --git a/source/blender/src/transform_snap.c b/source/blender/src/transform_snap.c
new file mode 100644
index 00000000000..d62d49c2de8
--- /dev/null
+++ b/source/blender/src/transform_snap.c
@@ -0,0 +1,710 @@
+/**
+ * $Id:
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Martin Poirier
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <math.h>
+#include <stdio.h>
+
+#include "PIL_time.h"
+
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_meshdata_types.h" // Temporary, for snapping to other unselected meshes
+#include "DNA_space_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BLI_arithb.h"
+#include "BLI_editVert.h"
+
+#include "BDR_drawobject.h"
+
+#include "editmesh.h"
+#include "BIF_editsima.h"
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+#include "BIF_mywindow.h"
+#include "BIF_resources.h"
+#include "BIF_screen.h"
+#include "BIF_editsima.h"
+#include "BIF_drawimage.h"
+
+#include "BKE_global.h"
+#include "BKE_utildefines.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_object.h"
+
+#include "BSE_view.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "transform.h"
+#include "mydevice.h" /* for KEY defines */
+#include "blendef.h" /* for selection modes */
+
+/********************* PROTOTYPES ***********************/
+
+void setSnappingCallback(TransInfo *t);
+
+void ApplySnapTranslation(TransInfo *t, float vec[3]);
+void ApplySnapRotation(TransInfo *t, float *vec);
+
+void CalcSnapGrid(TransInfo *t, float *vec);
+void CalcSnapGeometry(TransInfo *t, float *vec);
+
+void TargetSnapMedian(TransInfo *t);
+void TargetSnapCenter(TransInfo *t);
+void TargetSnapClosest(TransInfo *t);
+
+float RotationBetween(TransInfo *t, float p1[3], float p2[3]);
+float TranslationBetween(TransInfo *t, float p1[3], float p2[3]);
+
+// Trickery
+int findNearestVertFromObjects(int *dist, float *loc);
+
+/****************** IMPLEMENTATIONS *********************/
+
+void drawSnapping(TransInfo *t)
+{
+ if ((t->tsnap.status & (SNAP_ON|POINT_INIT|TARGET_INIT)) == (SNAP_ON|POINT_INIT|TARGET_INIT) &&
+ (G.qual & LR_CTRLKEY)) {
+
+ char col[4];
+ BIF_GetThemeColor3ubv(TH_TRANSFORM, col);
+ glColor4ub(col[0], col[1], col[2], 128);
+
+ if (t->spacetype==SPACE_VIEW3D) {
+ float unitmat[4][4];
+ float size;
+
+ glDisable(GL_DEPTH_TEST);
+
+ size = get_drawsize(G.vd);
+
+ size *= 0.5f * BIF_GetThemeValuef(TH_VERTEX_SIZE);
+
+ glPushMatrix();
+
+ glTranslatef(t->tsnap.snapPoint[0], t->tsnap.snapPoint[1], t->tsnap.snapPoint[2]);
+
+ /* sets view screen aligned */
+ glRotatef( -360.0f*saacos(G.vd->viewquat[0])/(float)M_PI, G.vd->viewquat[1], G.vd->viewquat[2], G.vd->viewquat[3]);
+
+ Mat4One(unitmat);
+ drawcircball(GL_LINE_LOOP, unitmat[3], size, unitmat);
+
+ glPopMatrix();
+
+ if(G.vd->zbuf) glEnable(GL_DEPTH_TEST);
+ } else if (t->spacetype==SPACE_IMAGE) {
+ /*This will not draw, and Im nor sure why - campbell */
+
+ /*
+ float xuser_asp, yuser_asp;
+ int wi, hi;
+ float w, h;
+
+ calc_image_view(G.sima, 'f'); // float
+ myortho2(G.v2d->cur.xmin, G.v2d->cur.xmax, G.v2d->cur.ymin, G.v2d->cur.ymax);
+ glLoadIdentity();
+
+ aspect_sima(G.sima, &xuser_asp, &yuser_asp);
+
+ transform_width_height_tface_uv(&wi, &hi);
+ w = (((float)wi)/256.0f)*G.sima->zoom * xuser_asp;
+ h = (((float)hi)/256.0f)*G.sima->zoom * yuser_asp;
+
+ cpack(0xFFFFFF);
+ glTranslatef(t->tsnap.snapPoint[0], t->tsnap.snapPoint[1], 0.0f);
+
+ //glRectf(0,0,1,1);
+
+ setlinestyle(0);
+ cpack(0x0);
+ fdrawline(-0.020/w, 0, -0.1/w, 0);
+ fdrawline(0.1/w, 0, .020/w, 0);
+ fdrawline(0, -0.020/h, 0, -0.1/h);
+ fdrawline(0, 0.1/h, 0, 0.020/h);
+
+ glTranslatef(-t->tsnap.snapPoint[0], -t->tsnap.snapPoint[1], 0.0f);
+ setlinestyle(0);
+ */
+
+ }
+ }
+}
+
+int handleSnapping(TransInfo *t, int event)
+{
+ int status = 0;
+
+ // Put keyhandling code here
+
+ return status;
+}
+
+void applySnapping(TransInfo *t, float *vec)
+{
+ if ((t->tsnap.status & SNAP_ON) &&
+ (G.qual & LR_CTRLKEY))
+ {
+ double current = PIL_check_seconds_timer();
+
+ // Time base quirky code to go around findnearest slowness
+ if (current - t->tsnap.last >= 0.25)
+ {
+ t->tsnap.calcSnap(t, vec);
+ t->tsnap.targetSnap(t);
+
+ t->tsnap.last = current;
+ }
+ if ((t->tsnap.status & (POINT_INIT|TARGET_INIT)) == (POINT_INIT|TARGET_INIT))
+ {
+ t->tsnap.applySnap(t, vec);
+ }
+ }
+}
+
+void resetSnapping(TransInfo *t)
+{
+ t->tsnap.status = 0;
+ t->tsnap.modePoint = 0;
+ t->tsnap.modeTarget = 0;
+ t->tsnap.last = 0;
+ t->tsnap.applySnap = NULL;
+}
+
+void initSnapping(TransInfo *t)
+{
+ resetSnapping(t);
+
+ if (t->spacetype == SPACE_VIEW3D || t->spacetype == SPACE_IMAGE) { // Only 3D view or UV
+ setSnappingCallback(t);
+
+ if (t->tsnap.applySnap != NULL && // A snapping function actually exist
+ (G.obedit != NULL && G.obedit->type==OB_MESH) && // Temporary limited to edit mode meshes
+ (G.scene->snap_flag & SCE_SNAP) && // Only if the snap flag is on
+ (t->flag & T_PROP_EDIT) == 0) // No PET, obviously
+ {
+ t->tsnap.status |= SNAP_ON;
+ t->tsnap.modePoint = SNAP_GEO;
+ }
+ else
+ {
+ /* Grid if snap is not possible */
+ t->tsnap.modePoint = SNAP_GRID;
+ }
+ }
+ else
+ {
+ /* Always grid outside of 3D view */
+ t->tsnap.modePoint = SNAP_GRID;
+ }
+}
+
+void setSnappingCallback(TransInfo *t)
+{
+ t->tsnap.calcSnap = CalcSnapGeometry;
+
+ switch(G.scene->snap_target)
+ {
+ case SCE_SNAP_TARGET_CLOSEST:
+ t->tsnap.modeTarget = SNAP_CLOSEST;
+ t->tsnap.targetSnap = TargetSnapClosest;
+ break;
+ case SCE_SNAP_TARGET_CENTER:
+ t->tsnap.modeTarget = SNAP_CENTER;
+ t->tsnap.targetSnap = TargetSnapCenter;
+ break;
+ case SCE_SNAP_TARGET_MEDIAN:
+ t->tsnap.modeTarget = SNAP_MEDIAN;
+ t->tsnap.targetSnap = TargetSnapMedian;
+ break;
+ }
+
+ switch (t->mode)
+ {
+ case TFM_TRANSLATION:
+ t->tsnap.applySnap = ApplySnapTranslation;
+ t->tsnap.distance = TranslationBetween;
+ break;
+ case TFM_ROTATION:
+ t->tsnap.applySnap = ApplySnapRotation;
+ t->tsnap.distance = RotationBetween;
+
+ // Can't do TARGET_CENTER with rotation, use TARGET_MEDIAN instead
+ if (G.scene->snap_target == SCE_SNAP_TARGET_CENTER) {
+ t->tsnap.modeTarget = SNAP_MEDIAN;
+ t->tsnap.targetSnap = TargetSnapMedian;
+ }
+ break;
+ default:
+ t->tsnap.applySnap = NULL;
+ break;
+ }
+}
+
+/********************** APPLY **************************/
+
+void ApplySnapTranslation(TransInfo *t, float vec[3])
+{
+ VecSubf(vec, t->tsnap.snapPoint, t->tsnap.snapTarget);
+}
+
+void ApplySnapRotation(TransInfo *t, float *vec)
+{
+ if (t->tsnap.modeTarget == SNAP_CLOSEST) {
+ *vec = t->tsnap.dist;
+ }
+ else {
+ *vec = RotationBetween(t, t->tsnap.snapTarget, t->tsnap.snapPoint);
+ }
+}
+
+
+/********************** DISTANCE **************************/
+
+float TranslationBetween(TransInfo *t, float p1[3], float p2[3])
+{
+ return VecLenf(p1, p2);
+}
+
+float RotationBetween(TransInfo *t, float p1[3], float p2[3])
+{
+ float angle, start[3], end[3], center[3];
+
+ VECCOPY(center, t->center);
+ if(t->flag & (T_EDIT|T_POSE)) {
+ Object *ob= G.obedit?G.obedit:t->poseobj;
+ Mat4MulVecfl(ob->obmat, center);
+ }
+
+ VecSubf(start, p1, center);
+ VecSubf(end, p2, center);
+
+ // Angle around a constraint axis (error prone, will need debug)
+ if (t->con.applyRot != NULL && (t->con.mode & CON_APPLY)) {
+ float axis[3], tmp[3];
+
+ t->con.applyRot(t, NULL, axis);
+
+ Projf(tmp, end, axis);
+ VecSubf(end, end, tmp);
+
+ Projf(tmp, start, axis);
+ VecSubf(start, start, tmp);
+
+ Normalize(end);
+ Normalize(start);
+
+ Crossf(tmp, start, end);
+
+ if (Inpf(tmp, axis) < 0.0)
+ angle = -acos(Inpf(start, end));
+ else
+ angle = acos(Inpf(start, end));
+ }
+ else {
+ float mtx[3][3];
+
+ Mat3CpyMat4(mtx, t->viewmat);
+
+ Mat3MulVecfl(mtx, end);
+ Mat3MulVecfl(mtx, start);
+
+ angle = atan2(start[1],start[0]) - atan2(end[1],end[0]);
+ }
+
+ if (angle > M_PI) {
+ angle = angle - 2 * M_PI;
+ }
+ else if (angle < -(M_PI)) {
+ angle = 2 * M_PI + angle;
+ }
+
+ return angle;
+}
+
+/********************** CALC **************************/
+
+void CalcSnapGrid(TransInfo *t, float *vec)
+{
+ snapGridAction(t, t->tsnap.snapPoint, BIG_GEARS);
+}
+
+void CalcSnapGeometry(TransInfo *t, float *vec)
+{
+ if (G.obedit != NULL && G.obedit->type==OB_MESH)
+ {
+ /*if (G.scene->selectmode & B_SEL_VERT)*/
+
+ if (t->spacetype == SPACE_VIEW3D)
+ {
+ EditVert *nearest=NULL;
+ float vec[3];
+ int found = 0;
+ int dist = 40; // Use a user defined value here
+
+ // use findnearestverts in vert mode, others in other modes
+ nearest = findnearestvert(&dist, SELECT, 1);
+
+ found = findNearestVertFromObjects(&dist, vec);
+ if (found == 1)
+ {
+ VECCOPY(t->tsnap.snapPoint, vec);
+
+ t->tsnap.status |= POINT_INIT;
+ }
+ /* If there's no outside vertex nearer, but there's one in this mesh
+ */
+ else if (nearest != NULL)
+ {
+ VECCOPY(t->tsnap.snapPoint, nearest->co);
+ Mat4MulVecfl(G.obedit->obmat, t->tsnap.snapPoint);
+
+ t->tsnap.status |= POINT_INIT;
+ }
+ else
+ {
+ t->tsnap.status &= ~POINT_INIT;
+ }
+ }
+ else if (t->spacetype == SPACE_IMAGE)
+ { /* same as above but for UV's */
+ MTFace *nearesttf=NULL;
+ int face_corner;
+
+ find_nearest_uv(&nearesttf, NULL, NULL, &face_corner);
+
+ if (nearesttf != NULL)
+ {
+ VECCOPY2D(t->tsnap.snapPoint, nearesttf->uv[face_corner]);
+ //Mat4MulVecfl(G.obedit->obmat, t->tsnap.snapPoint);
+
+ t->tsnap.status |= POINT_INIT;
+ }
+ else
+ {
+ t->tsnap.status &= ~POINT_INIT;
+ }
+ }
+
+
+ /*
+ if (G.scene->selectmode & B_SEL_EDGE)
+ {
+ EditEdge *nearest=NULL;
+ int dist = 50; // Use a user defined value here
+
+ // use findnearestverts in vert mode, others in other modes
+ nearest = findnearestedge(&dist);
+
+ if (nearest != NULL)
+ {
+ VecAddf(t->tsnap.snapPoint, nearest->v1->co, nearest->v2->co);
+
+ VecMulf(t->tsnap.snapPoint, 0.5f);
+
+ Mat4MulVecfl(G.obedit->obmat, t->tsnap.snapPoint);
+
+ t->tsnap.status |= POINT_INIT;
+ }
+ else
+ {
+ t->tsnap.status &= ~POINT_INIT;
+ }
+ }
+ */
+ }
+}
+
+/********************** TARGET **************************/
+
+void TargetSnapCenter(TransInfo *t)
+{
+ // Only need to calculate once
+ if ((t->tsnap.status & TARGET_INIT) == 0)
+ {
+ VECCOPY(t->tsnap.snapTarget, t->center);
+ if(t->flag & (T_EDIT|T_POSE)) {
+ Object *ob= G.obedit?G.obedit:t->poseobj;
+ Mat4MulVecfl(ob->obmat, t->tsnap.snapTarget);
+ }
+
+ t->tsnap.status |= TARGET_INIT;
+ }
+}
+
+void TargetSnapMedian(TransInfo *t)
+{
+ // Only need to calculate once
+ if ((t->tsnap.status & TARGET_INIT) == 0)
+ {
+ TransData *td = NULL;
+
+ t->tsnap.snapTarget[0] = 0;
+ t->tsnap.snapTarget[1] = 0;
+ t->tsnap.snapTarget[2] = 0;
+
+ for (td = t->data; td != NULL && td->flag & TD_SELECTED ; td++)
+ {
+ VecAddf(t->tsnap.snapTarget, t->tsnap.snapTarget, td->iloc);
+ }
+
+ VecMulf(t->tsnap.snapTarget, 1.0 / t->total);
+
+ if(t->flag & (T_EDIT|T_POSE)) {
+ Object *ob= G.obedit?G.obedit:t->poseobj;
+ Mat4MulVecfl(ob->obmat, t->tsnap.snapTarget);
+ }
+
+ t->tsnap.status |= TARGET_INIT;
+ }
+}
+
+void TargetSnapClosest(TransInfo *t)
+{
+ // Only valid if a snap point has been selected
+ if (t->tsnap.status & POINT_INIT)
+ {
+ TransData *closest = NULL, *td = NULL;
+
+ // Base case, only one selected item
+ if (t->total == 1)
+ {
+ VECCOPY(t->tsnap.snapTarget, t->data[0].iloc);
+
+ if(t->flag & (T_EDIT|T_POSE)) {
+ Object *ob= G.obedit?G.obedit:t->poseobj;
+ Mat4MulVecfl(ob->obmat, t->tsnap.snapTarget);
+ }
+
+ t->tsnap.dist = t->tsnap.distance(t, t->tsnap.snapTarget, t->tsnap.snapPoint);
+ }
+ // More than one selected item
+ else
+ {
+ for (td = t->data; td != NULL && td->flag & TD_SELECTED ; td++)
+ {
+ float loc[3];
+ float dist;
+
+ VECCOPY(loc, td->iloc);
+
+ if(t->flag & (T_EDIT|T_POSE)) {
+ Object *ob= G.obedit?G.obedit:t->poseobj;
+ Mat4MulVecfl(ob->obmat, loc);
+ }
+
+ dist = t->tsnap.distance(t, loc, t->tsnap.snapPoint);
+
+ if (closest == NULL || fabs(dist) < fabs(t->tsnap.dist))
+ {
+ VECCOPY(t->tsnap.snapTarget, loc);
+ closest = td;
+ t->tsnap.dist = dist;
+ }
+ }
+ }
+
+ t->tsnap.status |= TARGET_INIT;
+ }
+}
+/*================================================================*/
+
+int findNearestVertFromObjects(int *dist, float *loc) {
+ Base *base;
+ int retval = 0;
+ short mval[2];
+
+ getmouseco_areawin(mval);
+
+ base= FIRSTBASE;
+ for ( base = FIRSTBASE; base != NULL; base = base->next ) {
+ if ( TESTBASE(base) && base != BASACT ) {
+ Object *ob = base->object;
+
+ if (ob->type == OB_MESH) {
+ Mesh *me = ob->data;
+
+ if (me->totvert > 0) {
+ int test = 1;
+ int i;
+
+ /* If number of vert is more than an arbitrary limit,
+ * test against boundbox first
+ * */
+ if (me->totvert > 16) {
+ struct BoundBox *bb = object_get_boundbox(ob);
+
+ int minx = 0, miny = 0, maxx = 0, maxy = 0;
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ float gloc[3];
+ int sloc[2];
+
+ VECCOPY(gloc, bb->vec[i]);
+ Mat4MulVecfl(ob->obmat, gloc);
+ project_int(gloc, sloc);
+
+ if (i == 0) {
+ minx = maxx = sloc[0];
+ miny = maxy = sloc[1];
+ }
+ else {
+ if (minx > sloc[0]) minx = sloc[0];
+ else if (maxx < sloc[0]) maxx = sloc[0];
+
+ if (miny > sloc[1]) miny = sloc[1];
+ else if (maxy < sloc[1]) maxy = sloc[1];
+ }
+ }
+
+ /* Pad with distance */
+
+ minx -= *dist;
+ miny -= *dist;
+ maxx += *dist;
+ maxy += *dist;
+
+ if (mval[0] > maxx || mval[0] < minx ||
+ mval[1] > maxy || mval[1] < miny) {
+
+ test = 0;
+ }
+ }
+
+ if (test == 1) {
+ float *verts = mesh_get_mapped_verts_nors(ob);
+
+ if (verts != NULL) {
+ float *fp;
+
+ fp = verts;
+ for( i = 0; i < me->totvert; i++, fp += 6) {
+ float gloc[3];
+ int sloc[2];
+ int curdist;
+
+ VECCOPY(gloc, fp);
+ Mat4MulVecfl(ob->obmat, gloc);
+ project_int(gloc, sloc);
+
+ sloc[0] -= mval[0];
+ sloc[1] -= mval[1];
+
+ curdist = abs(sloc[0]) + abs(sloc[1]);
+
+ if (curdist < *dist) {
+ *dist = curdist;
+ retval = 1;
+ VECCOPY(loc, gloc);
+ }
+ }
+ }
+
+ MEM_freeN(verts);
+ }
+ }
+ }
+ }
+ }
+
+ return retval;
+}
+
+/*================================================================*/
+
+static void applyGrid(TransInfo *t, float *val, int max_index, float fac[3], GearsType action);
+
+
+void snapGridAction(TransInfo *t, float *val, GearsType action) {
+ float fac[3];
+
+ fac[NO_GEARS] = t->snap[0];
+ fac[BIG_GEARS] = t->snap[1];
+ fac[SMALL_GEARS] = t->snap[2];
+
+ applyGrid(t, val, t->idx_max, fac, action);
+}
+
+
+void snapGrid(TransInfo *t, float *val) {
+ int invert;
+ GearsType action;
+
+ // Only do something if using Snap to Grid
+ if (t->tsnap.modePoint != SNAP_GRID)
+ return;
+
+ if(t->mode==TFM_ROTATION || t->mode==TFM_WARP || t->mode==TFM_TILT || t->mode==TFM_TRACKBALL || t->mode==TFM_BONE_ROLL)
+ invert = U.flag & USER_AUTOROTGRID;
+ else if(t->mode==TFM_RESIZE || t->mode==TFM_SHEAR || t->mode==TFM_BONESIZE || t->mode==TFM_SHRINKFATTEN || t->mode==TFM_CURVE_SHRINKFATTEN)
+ invert = U.flag & USER_AUTOSIZEGRID;
+ else
+ invert = U.flag & USER_AUTOGRABGRID;
+
+ if(invert) {
+ action = (G.qual & LR_CTRLKEY) ? NO_GEARS: BIG_GEARS;
+ }
+ else {
+ action = (G.qual & LR_CTRLKEY) ? BIG_GEARS : NO_GEARS;
+ }
+
+ if (action == BIG_GEARS && (G.qual & LR_SHIFTKEY)) {
+ action = SMALL_GEARS;
+ }
+
+ snapGridAction(t, val, action);
+}
+
+
+static void applyGrid(TransInfo *t, float *val, int max_index, float fac[3], GearsType action)
+{
+ int i;
+ float asp[3] = {1.0f, 1.0f, 1.0f}; // TODO: Remove hard coded limit here (3)
+
+ // Early bailing out if no need to snap
+ if (fac[action] == 0.0)
+ return;
+
+ /* evil hack - snapping needs to be adapted for image aspect ratio */
+ if((t->spacetype==SPACE_IMAGE) && (t->mode==TFM_TRANSLATION)) {
+ transform_aspect_ratio_tface_uv(asp, asp+1);
+ }
+
+ for (i=0; i<=max_index; i++) {
+ val[i]= fac[action]*asp[i]*(float)floor(val[i]/(fac[action]*asp[i]) +.5);
+ }
+}
diff --git a/source/blender/src/unwrapper.c b/source/blender/src/unwrapper.c
new file mode 100644
index 00000000000..bca7e44ed72
--- /dev/null
+++ b/source/blender/src/unwrapper.c
@@ -0,0 +1,480 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+
+#include "BKE_global.h"
+#include "BKE_mesh.h"
+#include "BKE_utildefines.h"
+#include "BKE_customdata.h"
+
+#include "BLI_arithb.h"
+#include "BLI_edgehash.h"
+#include "BLI_editVert.h"
+
+#include "BIF_editsima.h"
+#include "BIF_space.h"
+#include "BIF_screen.h"
+#include "BIF_editmesh.h"
+
+#include "blendef.h"
+#include "mydevice.h"
+
+#include "BDR_unwrapper.h"
+
+#include "PIL_time.h"
+
+#include "parametrizer.h"
+
+/* Set tface seams based on edge data, uses hash table to find seam edges. */
+
+static void hash_add_face(EdgeHash *ehash, MFace *mf)
+{
+ BLI_edgehash_insert(ehash, mf->v1, mf->v2, NULL);
+ BLI_edgehash_insert(ehash, mf->v2, mf->v3, NULL);
+ if(mf->v4) {
+ BLI_edgehash_insert(ehash, mf->v3, mf->v4, NULL);
+ BLI_edgehash_insert(ehash, mf->v4, mf->v1, NULL);
+ }
+ else
+ BLI_edgehash_insert(ehash, mf->v3, mf->v1, NULL);
+}
+
+void select_linked_tfaces_with_seams(int mode, Mesh *me, unsigned int index)
+{
+ MFace *mf;
+ int a, doit=1, mark=0;
+ char *linkflag;
+ EdgeHash *ehash, *seamhash;
+ MEdge *med;
+
+ ehash= BLI_edgehash_new();
+ seamhash = BLI_edgehash_new();
+ linkflag= MEM_callocN(sizeof(char)*me->totface, "linkflaguv");
+
+ for(med=me->medge, a=0; a < me->totedge; a++, med++)
+ if(med->flag & ME_SEAM)
+ BLI_edgehash_insert(seamhash, med->v1, med->v2, NULL);
+
+ if (mode==0 || mode==1) {
+ /* only put face under cursor in array */
+ mf= ((MFace*)me->mface) + index;
+ hash_add_face(ehash, mf);
+ linkflag[index]= 1;
+ }
+ else {
+ /* fill array by selection */
+ mf= me->mface;
+ for(a=0; a<me->totface; a++, mf++) {
+ if(mf->flag & ME_HIDE);
+ else if(mf->flag & ME_FACE_SEL) {
+ hash_add_face(ehash, mf);
+ linkflag[a]= 1;
+ }
+ }
+ }
+
+ while(doit) {
+ doit= 0;
+
+ /* expand selection */
+ mf= me->mface;
+ for(a=0; a<me->totface; a++, mf++) {
+ if(mf->flag & ME_HIDE)
+ continue;
+
+ if(!linkflag[a]) {
+ mark= 0;
+
+ if(!BLI_edgehash_haskey(seamhash, mf->v1, mf->v2))
+ if(BLI_edgehash_haskey(ehash, mf->v1, mf->v2))
+ mark= 1;
+ if(!BLI_edgehash_haskey(seamhash, mf->v2, mf->v3))
+ if(BLI_edgehash_haskey(ehash, mf->v2, mf->v3))
+ mark= 1;
+ if(mf->v4) {
+ if(!BLI_edgehash_haskey(seamhash, mf->v3, mf->v4))
+ if(BLI_edgehash_haskey(ehash, mf->v3, mf->v4))
+ mark= 1;
+ if(!BLI_edgehash_haskey(seamhash, mf->v4, mf->v1))
+ if(BLI_edgehash_haskey(ehash, mf->v4, mf->v1))
+ mark= 1;
+ }
+ else if(!BLI_edgehash_haskey(seamhash, mf->v3, mf->v1))
+ if(BLI_edgehash_haskey(ehash, mf->v3, mf->v1))
+ mark = 1;
+
+ if(mark) {
+ linkflag[a]= 1;
+ hash_add_face(ehash, mf);
+ doit= 1;
+ }
+ }
+ }
+
+ }
+
+ BLI_edgehash_free(ehash, NULL);
+ BLI_edgehash_free(seamhash, NULL);
+
+ if(mode==0 || mode==2) {
+ for(a=0, mf=me->mface; a<me->totface; a++, mf++)
+ if(linkflag[a])
+ mf->flag |= ME_FACE_SEL;
+ else
+ mf->flag &= ~ME_FACE_SEL;
+ }
+ else if(mode==1) {
+ for(a=0, mf=me->mface; a<me->totface; a++, mf++)
+ if(linkflag[a] && (mf->flag & ME_FACE_SEL))
+ break;
+
+ if (a<me->totface) {
+ for(a=0, mf=me->mface; a<me->totface; a++, mf++)
+ if(linkflag[a])
+ mf->flag &= ~ME_FACE_SEL;
+ }
+ else {
+ for(a=0, mf=me->mface; a<me->totface; a++, mf++)
+ if(linkflag[a])
+ mf->flag |= ME_FACE_SEL;
+ }
+ }
+
+ MEM_freeN(linkflag);
+
+ BIF_undo_push("Select linked UV face");
+ object_tface_flags_changed(OBACT, 0);
+}
+
+/* Parametrizer */
+ParamHandle *construct_param_handle(EditMesh *em, short implicit, short fill, short sel)
+{
+ int a;
+ MTFace *tf;
+
+ EditFace *efa;
+ EditEdge *eed;
+ EditVert *ev;
+
+ ParamHandle *handle;
+
+ handle = param_construct_begin();
+
+ /* we need the vert indicies */
+ for (ev= em->verts.first, a=0; ev; ev= ev->next, a++)
+ ev->tmp.l = a;
+
+ for (efa= em->faces.first; efa; efa= efa->next) {
+ ParamKey key, vkeys[4];
+ ParamBool pin[4], select[4];
+ float *co[4];
+ float *uv[4];
+ int nverts;
+
+ if ((efa->h) || (sel && (efa->f & SELECT)==0))
+ continue;
+
+ tf= (MTFace *)CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+
+ if (implicit &&
+ !( SIMA_UVSEL_CHECK(efa, tf, 0) ||
+ SIMA_UVSEL_CHECK(efa, tf, 1) ||
+ SIMA_UVSEL_CHECK(efa, tf, 2) ||
+ (efa->v4 && SIMA_UVSEL_CHECK(efa, tf, 3)) )
+ ) {
+ continue;
+ }
+
+ key = (ParamKey)efa;
+ vkeys[0] = (ParamKey)efa->v1->tmp.l;
+ vkeys[1] = (ParamKey)efa->v2->tmp.l;
+ vkeys[2] = (ParamKey)efa->v3->tmp.l;
+
+ co[0] = efa->v1->co;
+ co[1] = efa->v2->co;
+ co[2] = efa->v3->co;
+
+ uv[0] = tf->uv[0];
+ uv[1] = tf->uv[1];
+ uv[2] = tf->uv[2];
+
+ pin[0] = ((tf->unwrap & TF_PIN1) != 0);
+ pin[1] = ((tf->unwrap & TF_PIN2) != 0);
+ pin[2] = ((tf->unwrap & TF_PIN3) != 0);
+
+ select[0] = ((SIMA_UVSEL_CHECK(efa, tf, 0)) != 0);
+ select[1] = ((SIMA_UVSEL_CHECK(efa, tf, 1)) != 0);
+ select[2] = ((SIMA_UVSEL_CHECK(efa, tf, 2)) != 0);
+
+ if (efa->v4) {
+ vkeys[3] = (ParamKey)efa->v4->tmp.l;
+ co[3] = efa->v4->co;
+ uv[3] = tf->uv[3];
+ pin[3] = ((tf->unwrap & TF_PIN4) != 0);
+ select[3] = (SIMA_UVSEL_CHECK(efa, tf, 3) != 0);
+ nverts = 4;
+ }
+ else
+ nverts = 3;
+
+ param_face_add(handle, key, nverts, vkeys, co, uv, pin, select);
+ }
+
+ if (!implicit) {
+ for (eed= em->edges.first; eed; eed= eed->next) {
+ if(eed->seam) {
+ ParamKey vkeys[2];
+ vkeys[0] = (ParamKey)eed->v1->tmp.l;
+ vkeys[1] = (ParamKey)eed->v2->tmp.l;
+ param_edge_set_seam(handle, vkeys);
+ }
+ }
+ }
+
+ param_construct_end(handle, fill, implicit);
+
+ return handle;
+}
+
+
+extern int EM_texFaceCheck(void);
+
+void unwrap_lscm(short seamcut)
+{
+ EditMesh *em = G.editMesh;
+ ParamHandle *handle;
+ short abf = G.scene->toolsettings->unwrapper == 1;
+ short fillholes = G.scene->toolsettings->uvcalc_flag & 1;
+
+ /* add uvs if there not here */
+ if (!EM_texFaceCheck()) {
+ if (em && em->faces.first)
+ EM_add_data_layer(&em->fdata, CD_MTFACE);
+
+ if (!EM_texFaceCheck())
+ return;
+
+ /* select new UV's */
+ if ((G.sima==0 || G.sima->flag & SI_SYNC_UVSEL)==0) {
+ EditFace *efa;
+ MTFace *tf;
+ for(efa=em->faces.first; efa; efa=efa->next) {
+ tf= (MTFace *)CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+ SIMA_FACESEL_SET(efa, tf);
+ }
+ }
+ }
+
+ handle = construct_param_handle(em, 0, fillholes, seamcut == 0);
+
+ param_lscm_begin(handle, PARAM_FALSE, abf);
+ param_lscm_solve(handle);
+ param_lscm_end(handle);
+
+ param_pack(handle);
+
+ param_flush(handle);
+
+ param_delete(handle);
+
+ if (!seamcut)
+ BIF_undo_push("UV unwrap");
+
+ object_uvs_changed(OBACT);
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWIMAGE, 0);
+}
+
+void minimize_stretch_tface_uv(void)
+{
+ EditMesh *em = G.editMesh;
+ ParamHandle *handle;
+ double lasttime;
+ short doit = 1, escape = 0, val, blend = 0;
+ unsigned short event = 0;
+ short fillholes = G.scene->toolsettings->uvcalc_flag & 1;
+
+ if(!EM_texFaceCheck()) return;
+
+ handle = construct_param_handle(em, 1, fillholes, 1);
+
+ lasttime = PIL_check_seconds_timer();
+
+ param_stretch_begin(handle);
+
+ while (doit) {
+ param_stretch_iter(handle);
+
+ while (qtest()) {
+ event= extern_qread(&val);
+
+ if (val) {
+ switch (event) {
+ case ESCKEY:
+ escape = 1;
+ case RETKEY:
+ case PADENTER:
+ doit = 0;
+ break;
+ case PADPLUSKEY:
+ case WHEELUPMOUSE:
+ if (blend < 10) {
+ blend++;
+ param_stretch_blend(handle, blend*0.1f);
+ param_flush(handle);
+ lasttime = 0.0f;
+ }
+ break;
+ case PADMINUS:
+ case WHEELDOWNMOUSE:
+ if (blend > 0) {
+ blend--;
+ param_stretch_blend(handle, blend*0.1f);
+ param_flush(handle);
+ lasttime = 0.0f;
+ }
+ break;
+ }
+ }
+ else if ((event == LEFTMOUSE) || (event == RIGHTMOUSE)) {
+ escape = (event == RIGHTMOUSE);
+ doit = 0;
+ }
+ }
+
+ if (!doit)
+ break;
+
+ if (PIL_check_seconds_timer() - lasttime > 0.5) {
+ char str[100];
+
+ param_flush(handle);
+
+ sprintf(str, "Stretch minimize. Blend %.2f.", blend*0.1f);
+ headerprint(str);
+
+ lasttime = PIL_check_seconds_timer();
+ object_uvs_changed(OBACT);
+ if(G.sima->lock) force_draw_plus(SPACE_VIEW3D, 0);
+ else force_draw(0);
+ }
+ }
+
+ if (escape)
+ param_flush_restore(handle);
+ else
+ param_flush(handle);
+
+ param_stretch_end(handle);
+
+ param_delete(handle);
+
+ BIF_undo_push("UV stretch minimize");
+
+ object_uvs_changed(OBACT);
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWIMAGE, 0);
+}
+
+void pack_charts_tface_uv(void)
+{
+ EditMesh *em = G.editMesh;
+ ParamHandle *handle;
+
+ if(!EM_texFaceCheck()) return;
+
+ handle = construct_param_handle(em, 1, 0, 1);
+ param_pack(handle);
+ param_flush(handle);
+ param_delete(handle);
+
+ BIF_undo_push("UV pack charts");
+
+ object_uvs_changed(OBACT);
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWIMAGE, 0);
+}
+
+/* LSCM live mode */
+
+static ParamHandle *liveHandle = NULL;
+
+void unwrap_lscm_live_begin(void)
+{
+ EditMesh *em = G.editMesh;
+ short abf = G.scene->toolsettings->unwrapper == 1;
+ short fillholes = G.scene->toolsettings->uvcalc_flag & 1;
+
+ if(!EM_texFaceCheck()) return;
+
+ liveHandle = construct_param_handle(em, 0, fillholes, 1);
+
+ param_lscm_begin(liveHandle, PARAM_TRUE, abf);
+}
+
+void unwrap_lscm_live_re_solve(void)
+{
+ if (liveHandle) {
+ param_lscm_solve(liveHandle);
+ param_flush(liveHandle);
+ }
+}
+
+void unwrap_lscm_live_end(short cancel)
+{
+ if (liveHandle) {
+ param_lscm_end(liveHandle);
+ if (cancel)
+ param_flush_restore(liveHandle);
+ param_delete(liveHandle);
+ liveHandle = NULL;
+ }
+}
+
diff --git a/source/blender/src/usiblender.c b/source/blender/src/usiblender.c
new file mode 100644
index 00000000000..3b22b84ad99
--- /dev/null
+++ b/source/blender/src/usiblender.c
@@ -0,0 +1,1039 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+ /* placed up here because of crappy
+ * winsock stuff.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef WIN32
+#include <windows.h> /* need to include windows.h so _WIN32_IE is defined */
+#ifndef _WIN32_IE
+#define _WIN32_IE 0x0400 /* minimal requirements for SHGetSpecialFolderPath on MINGW MSVC has this defined already */
+#endif
+#include <shlobj.h> /* for SHGetSpecialFolderPath, has to be done before BLI_winstuff because 'near' is disabled through BLI_windstuff */
+#include "BLI_winstuff.h"
+#include <process.h> /* getpid */
+#else
+#include <unistd.h> /* getpid */
+#endif
+#include "MEM_guardedalloc.h"
+#include "MEM_CacheLimiterC-Api.h"
+
+#include "BMF_Api.h"
+#include "BIF_language.h"
+#ifdef INTERNATIONAL
+#include "FTF_Api.h"
+#endif
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_linklist.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "DNA_object_types.h"
+#include "DNA_space_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_sound_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+
+#include "BKE_blender.h"
+#include "BKE_curve.h"
+#include "BKE_displist.h"
+#include "BKE_exotic.h"
+#include "BKE_font.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_mball.h"
+#include "BKE_node.h"
+#include "BKE_packedFile.h"
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
+
+#ifdef WITH_VERSE
+#include "BKE_verse.h"
+#endif
+
+#include "BLI_vfontdata.h"
+
+#include "BIF_fsmenu.h"
+#include "BIF_gl.h"
+#include "BIF_interface.h"
+#include "BIF_usiblender.h"
+#include "BIF_drawtext.h"
+#include "BIF_editaction.h"
+#include "BIF_editarmature.h"
+#include "BIF_editlattice.h"
+#include "BIF_editfont.h"
+#include "BIF_editmesh.h"
+#include "BIF_editmode_undo.h"
+#include "BIF_editsound.h"
+#include "BIF_filelist.h"
+#include "BIF_poseobject.h"
+#include "BIF_previewrender.h"
+#include "BIF_renderwin.h"
+#include "BIF_resources.h"
+#include "BIF_screen.h"
+#include "BIF_space.h"
+#include "BIF_toolbox.h"
+#include "BIF_cursors.h"
+
+#ifdef WITH_VERSE
+#include "BIF_verse.h"
+#endif
+
+
+#include "BSE_drawview.h"
+#include "BSE_edit.h"
+#include "BSE_editipo.h"
+#include "BSE_filesel.h"
+#include "BSE_headerbuttons.h"
+#include "BSE_node.h"
+
+#include "BLO_readfile.h"
+#include "BLO_writefile.h"
+
+#include "BDR_drawobject.h"
+#include "BDR_editobject.h"
+#include "BDR_editcurve.h"
+#include "BDR_imagepaint.h"
+#include "BDR_vpaint.h"
+
+#include "BPY_extern.h"
+
+#include "blendef.h"
+
+#include "RE_pipeline.h" /* RE_ free stuff */
+
+#include "radio.h"
+#include "datatoc.h"
+
+#include "SYS_System.h"
+
+#include "PIL_time.h"
+
+/***/
+
+/* define for setting colors in theme below */
+#define SETCOL(col, r, g, b, a) col[0]=r; col[1]=g; col[2]= b; col[3]= a;
+
+/* patching UserDef struct, set globals for UI stuff */
+static void init_userdef_file(void)
+{
+
+ BIF_InitTheme(); // sets default again
+
+ mainwindow_set_filename_to_title(""); // empty string re-initializes title to "Blender"
+ countall();
+ G.save_over = 0; // start with save preference untitled.blend
+
+ /* disable autoplay in .B.blend... */
+ G.fileflags &= ~G_FILE_AUTOPLAY;
+
+ /* the UserDef struct is not corrected with do_versions() .... ugh! */
+ if(U.wheellinescroll == 0) U.wheellinescroll = 3;
+ if(U.menuthreshold1==0) {
+ U.menuthreshold1= 5;
+ U.menuthreshold2= 2;
+ }
+ if(U.tb_leftmouse==0) {
+ U.tb_leftmouse= 5;
+ U.tb_rightmouse= 5;
+ }
+ if(U.mixbufsize==0) U.mixbufsize= 2048;
+ if (BLI_streq(U.tempdir, "/")) {
+ char *tmp= getenv("TEMP");
+
+ strcpy(U.tempdir, tmp?tmp:"/tmp/");
+ }
+ if (U.savetime <= 0) {
+ U.savetime = 1;
+ error(".B.blend is buggy, please consider removing it.\n");
+ }
+ /* transform widget settings */
+ if(U.tw_hotspot==0) {
+ U.tw_hotspot= 14;
+ U.tw_size= 20; // percentage of window size
+ U.tw_handlesize= 16; // percentage of widget radius
+ }
+ if(U.pad_rot_angle==0)
+ U.pad_rot_angle= 15;
+
+ if (G.main->versionfile <= 191) {
+ strcpy(U.plugtexdir, U.textudir);
+ strcpy(U.sounddir, "/");
+ }
+
+ /* patch to set Dupli Armature */
+ if (G.main->versionfile < 220) {
+ U.dupflag |= USER_DUP_ARM;
+ }
+
+ /* userdef new option */
+ if (G.main->versionfile <= 222) {
+ U.vrmlflag= USER_VRML_LAYERS;
+ }
+
+ /* added seam, normal color, undo */
+ if (G.main->versionfile <= 234) {
+ bTheme *btheme;
+
+ U.uiflag |= USER_GLOBALUNDO;
+ if (U.undosteps==0) U.undosteps=32;
+
+ for(btheme= U.themes.first; btheme; btheme= btheme->next) {
+ /* check for alpha==0 is safe, then color was never set */
+ if(btheme->tv3d.edge_seam[3]==0) {
+ SETCOL(btheme->tv3d.edge_seam, 230, 150, 50, 255);
+ }
+ if(btheme->tv3d.normal[3]==0) {
+ SETCOL(btheme->tv3d.normal, 0x22, 0xDD, 0xDD, 255);
+ }
+ if(btheme->tv3d.face_dot[3]==0) {
+ SETCOL(btheme->tv3d.face_dot, 255, 138, 48, 255);
+ btheme->tv3d.facedot_size= 4;
+ }
+ }
+ }
+ if (G.main->versionfile <= 235) {
+ /* illegal combo... */
+ if (U.flag & USER_LMOUSESELECT)
+ U.flag &= ~USER_TWOBUTTONMOUSE;
+ }
+ if (G.main->versionfile <= 236) {
+ bTheme *btheme;
+ /* new space type */
+ for(btheme= U.themes.first; btheme; btheme= btheme->next) {
+ /* check for alpha==0 is safe, then color was never set */
+ if(btheme->ttime.back[3]==0) {
+ btheme->ttime = btheme->tsnd; // copy from sound
+ }
+ if(btheme->text.syntaxn[3]==0) {
+ SETCOL(btheme->text.syntaxn, 0, 0, 200, 255); /* Numbers Blue*/
+ SETCOL(btheme->text.syntaxl, 100, 0, 0, 255); /* Strings red */
+ SETCOL(btheme->text.syntaxc, 0, 100, 50, 255); /* Comments greenish */
+ SETCOL(btheme->text.syntaxv, 95, 95, 0, 255); /* Special */
+ SETCOL(btheme->text.syntaxb, 128, 0, 80, 255); /* Builtin, red-purple */
+ }
+ }
+ }
+ if (G.main->versionfile <= 237) {
+ bTheme *btheme;
+ /* bone colors */
+ for(btheme= U.themes.first; btheme; btheme= btheme->next) {
+ /* check for alpha==0 is safe, then color was never set */
+ if(btheme->tv3d.bone_solid[3]==0) {
+ SETCOL(btheme->tv3d.bone_solid, 200, 200, 200, 255);
+ SETCOL(btheme->tv3d.bone_pose, 80, 200, 255, 80);
+ }
+ }
+ }
+ if (G.main->versionfile <= 238) {
+ bTheme *btheme;
+ /* bone colors */
+ for(btheme= U.themes.first; btheme; btheme= btheme->next) {
+ /* check for alpha==0 is safe, then color was never set */
+ if(btheme->tnla.strip[3]==0) {
+ SETCOL(btheme->tnla.strip_select, 0xff, 0xff, 0xaa, 255);
+ SETCOL(btheme->tnla.strip, 0xe4, 0x9c, 0xc6, 255);
+ }
+ }
+ }
+ if (G.main->versionfile <= 239) {
+ bTheme *btheme;
+
+ for(btheme= U.themes.first; btheme; btheme= btheme->next) {
+ /* Lamp theme, check for alpha==0 is safe, then color was never set */
+ if(btheme->tv3d.lamp[3]==0) {
+ SETCOL(btheme->tv3d.lamp, 0, 0, 0, 40);
+/* TEMPORAL, remove me! (ton) */
+ U.uiflag |= USER_PLAINMENUS;
+ }
+
+ /* check for text field selection highlight, set it to text editor highlight by default */
+ if(btheme->tui.textfield_hi[3]==0) {
+ SETCOL(btheme->tui.textfield_hi,
+ btheme->text.shade2[0],
+ btheme->text.shade2[1],
+ btheme->text.shade2[2],
+ 255);
+ }
+ }
+ if(U.obcenter_dia==0) U.obcenter_dia= 6;
+ }
+ if (G.main->versionfile <= 241) {
+ bTheme *btheme;
+ for(btheme= U.themes.first; btheme; btheme= btheme->next) {
+ /* Node editor theme, check for alpha==0 is safe, then color was never set */
+ if(btheme->tnode.syntaxn[3]==0) {
+ /* re-uses syntax color storage */
+ btheme->tnode= btheme->tv3d;
+ SETCOL(btheme->tnode.edge_select, 255, 255, 255, 255);
+ SETCOL(btheme->tnode.syntaxl, 150, 150, 150, 255); /* TH_NODE, backdrop */
+ SETCOL(btheme->tnode.syntaxn, 129, 131, 144, 255); /* in/output */
+ SETCOL(btheme->tnode.syntaxb, 127,127,127, 255); /* operator */
+ SETCOL(btheme->tnode.syntaxv, 142, 138, 145, 255); /* generator */
+ SETCOL(btheme->tnode.syntaxc, 120, 145, 120, 255); /* group */
+ }
+ /* Group theme colors */
+ if(btheme->tv3d.group[3]==0) {
+ SETCOL(btheme->tv3d.group, 0x10, 0x40, 0x10, 255);
+ SETCOL(btheme->tv3d.group_active, 0x66, 0xFF, 0x66, 255);
+ }
+ /* Sequence editor theme*/
+ if(btheme->tseq.movie[3]==0) {
+ SETCOL(btheme->tseq.movie, 81, 105, 135, 255);
+ SETCOL(btheme->tseq.image, 109, 88, 129, 255);
+ SETCOL(btheme->tseq.scene, 78, 152, 62, 255);
+ SETCOL(btheme->tseq.audio, 46, 143, 143, 255);
+ SETCOL(btheme->tseq.effect, 169, 84, 124, 255);
+ SETCOL(btheme->tseq.plugin, 126, 126, 80, 255);
+ SETCOL(btheme->tseq.transition, 162, 95, 111, 255);
+ SETCOL(btheme->tseq.meta, 109, 145, 131, 255);
+ }
+ if(!(btheme->tui.iconfile)) {
+ BLI_strncpy(btheme->tui.iconfile, "", sizeof(btheme->tui.iconfile));
+ }
+ }
+
+ /* set defaults for 3D View rotating axis indicator */
+ /* since size can't be set to 0, this indicates it's not saved in .B.blend */
+ if (U.rvisize == 0) {
+ U.rvisize = 15;
+ U.rvibright = 8;
+ U.uiflag |= USER_SHOW_ROTVIEWICON;
+ }
+
+ }
+ if (G.main->versionfile <= 242) {
+ bTheme *btheme;
+
+ for(btheme= U.themes.first; btheme; btheme= btheme->next) {
+ /* long keyframe color */
+ /* check for alpha==0 is safe, then color was never set */
+ if(btheme->tact.strip[3]==0) {
+ SETCOL(btheme->tv3d.edge_sharp, 255, 32, 32, 255);
+ SETCOL(btheme->tact.strip_select, 0xff, 0xff, 0xaa, 204);
+ SETCOL(btheme->tact.strip, 0xe4, 0x9c, 0xc6, 204);
+ }
+
+ /* IPO-Editor - Vertex Size*/
+ if(btheme->tipo.vertex_size == 0) {
+ btheme->tipo.vertex_size= 3;
+ }
+ }
+ }
+ if (G.main->versionfile <= 243) {
+ /* set default number of recently-used files (if not set) */
+ if (U.recent_files == 0) U.recent_files = 10;
+ }
+ if (G.main->versionfile < 245 || (G.main->versionfile == 245 && G.main->subversionfile < 3)) {
+ bTheme *btheme;
+ for(btheme= U.themes.first; btheme; btheme= btheme->next) {
+ SETCOL(btheme->tv3d.editmesh_active, 255, 255, 255, 128);
+ }
+ if(U.coba_weight.tot==0)
+ init_colorband(&U.coba_weight, 1);
+ }
+
+ /* GL Texture Garbage Collection (variable abused above!) */
+ if (U.textimeout == 0) {
+ U.texcollectrate = 60;
+ U.textimeout = 120;
+ }
+ if (U.memcachelimit <= 0) {
+ U.memcachelimit = 32;
+ }
+ if (U.frameserverport == 0) {
+ U.frameserverport = 8080;
+ }
+
+ MEM_CacheLimiter_set_maximum(U.memcachelimit * 1024 * 1024);
+
+ reset_autosave();
+
+#ifdef INTERNATIONAL
+ read_languagefile();
+#endif
+
+ refresh_interface_font();
+
+#ifdef WITH_VERSE
+ if(strlen(U.versemaster)<1) {
+ strcpy(U.versemaster, "master.uni-verse.org");
+ }
+ if(strlen(U.verseuser)<1) {
+ char *name = verse_client_name();
+ strcpy(U.verseuser, name);
+ MEM_freeN(name);
+ }
+#endif
+
+}
+
+#ifdef WITH_VERSE
+extern ListBase session_list;
+#endif
+
+void BIF_read_file(char *name)
+{
+ extern short winqueue_break; /* editscreen.c */
+ int retval;
+#ifdef WITH_VERSE
+ struct VerseSession *session;
+ struct VNode *vnode;
+
+ session = session_list.first;
+ while(session) {
+ vnode = session->nodes.lb.first;
+ while(vnode) {
+ switch(vnode->type) {
+ case V_NT_OBJECT:
+ unsubscribe_from_obj_node(vnode);
+ break;
+ case V_NT_GEOMETRY:
+ unsubscribe_from_geom_node(vnode);
+ break;
+ case V_NT_BITMAP:
+ unsubscribe_from_bitmap_node(vnode);
+ break;
+ }
+ vnode = vnode->next;
+ }
+ session = session->next;
+ }
+#endif
+
+ /* first try to read exotic file formats... */
+ /* it throws error box when file doesnt exist and returns -1 */
+ retval= BKE_read_exotic(name);
+
+ if (retval== 0) {
+ /* we didn't succeed, now try to read Blender file */
+ retval= BKE_read_file(name, NULL);
+
+ mainwindow_set_filename_to_title(G.main->name);
+ countall();
+ sound_initialize_sounds();
+
+ winqueue_break= 1; /* leave queues everywhere */
+
+ if(retval==2) init_userdef_file(); // in case a userdef is read from regular .blend
+
+ G.relbase_valid = 1;
+
+ undo_editmode_clear();
+ BKE_reset_undo();
+ BKE_write_undo("original"); /* save current state */
+
+ refresh_interface_font();
+ }
+ else if(retval==1)
+ BIF_undo_push("Import file");
+}
+
+static void outliner_242_patch(void)
+{
+ ScrArea *sa;
+
+ for(sa= G.curscreen->areabase.first; sa; sa= sa->next) {
+ SpaceLink *sl= sa->spacedata.first;
+ for(; sl; sl= sl->next) {
+ if(sl->spacetype==SPACE_OOPS) {
+ SpaceOops *soops= (SpaceOops *)sl;
+ if(soops->type!=SO_OUTLINER) {
+ soops->type= SO_OUTLINER;
+ init_v2d_oops(sa, soops);
+ }
+ }
+ }
+ }
+ G.fileflags |= G_FILE_GAME_MAT;
+}
+
+/* only here settings for fullscreen */
+int BIF_read_homefile(int from_memory, int do_undo)
+{
+ char tstr[FILE_MAXDIR+FILE_MAXFILE], scestr[FILE_MAXDIR];
+ char *home= BLI_gethome();
+ int success;
+ struct TmpFont *tf;
+
+ BLI_clean(home);
+
+ tf= G.ttfdata.first;
+ while(tf)
+ {
+ freePackedFile(tf->pf);
+ tf->pf = NULL;
+ tf->vfont = NULL;
+ tf= tf->next;
+ }
+ BLI_freelistN(&G.ttfdata);
+
+ G.relbase_valid = 0;
+ if (!from_memory) BLI_make_file_string(G.sce, tstr, home, ".B.blend");
+ strcpy(scestr, G.sce); /* temporal store */
+
+ /* prevent loading no UI */
+ G.fileflags &= ~G_FILE_NO_UI;
+
+ if (!from_memory && BLI_exists(tstr)) {
+ success = BKE_read_file(tstr, NULL);
+ } else {
+ success = BKE_read_file_from_memory(datatoc_B_blend, datatoc_B_blend_size, NULL);
+ /* outliner patch for 2.42 .b.blend */
+ outliner_242_patch();
+ }
+
+ BLI_clean(scestr);
+ strcpy(G.sce, scestr);
+
+ space_set_commmandline_options();
+
+ init_userdef_file();
+
+ undo_editmode_clear();
+ BKE_reset_undo();
+
+ if (do_undo)
+ BIF_undo_push("original");
+
+ return success;
+}
+
+
+static void get_autosave_location(char buf[FILE_MAXDIR+FILE_MAXFILE])
+{
+ char pidstr[32];
+#ifdef WIN32
+ char subdir[9];
+ char savedir[FILE_MAXDIR];
+#endif
+
+ sprintf(pidstr, "%d.blend", abs(getpid()));
+
+#ifdef WIN32
+ if (!BLI_exists(U.tempdir)) {
+ BLI_strncpy(subdir, "autosave", sizeof(subdir));
+ BLI_make_file_string("/", savedir, BLI_gethome(), subdir);
+
+ /* create a new autosave dir
+ * function already checks for existence or not */
+ BLI_recurdir_fileops(savedir);
+
+ BLI_make_file_string("/", buf, savedir, pidstr);
+ return;
+ }
+#endif
+
+ BLI_make_file_string("/", buf, U.tempdir, pidstr);
+}
+
+void BIF_read_autosavefile(void)
+{
+ char tstr[FILE_MAX], scestr[FILE_MAX];
+ int save_over;
+
+ BLI_strncpy(scestr, G.sce, FILE_MAX); /* temporal store */
+
+ get_autosave_location(tstr);
+
+ save_over = G.save_over;
+ BKE_read_file(tstr, NULL);
+ G.save_over = save_over;
+ BLI_strncpy(G.sce, scestr, FILE_MAX);
+}
+
+/* free strings of open recent files */
+static void free_openrecent(void)
+{
+ struct RecentFile *recent;
+
+ for(recent = G.recent_files.first; recent; recent=recent->next)
+ MEM_freeN(recent->filename);
+
+ BLI_freelistN(&(G.recent_files));
+}
+
+static void readBlog(void)
+{
+ char name[FILE_MAX], filename[FILE_MAX];
+ LinkNode *l, *lines;
+ struct RecentFile *recent;
+ char *line;
+ int num;
+
+ BLI_make_file_string("/", name, BLI_gethome(), ".Blog");
+ lines= BLI_read_file_as_lines(name);
+
+ G.recent_files.first = G.recent_files.last = NULL;
+
+ /* read list of recent opend files from .Blog to memory */
+ for (l= lines, num= 0; l && (num<U.recent_files); l= l->next, num++) {
+ line = l->link;
+ if (!BLI_streq(line, "")) {
+ if (num==0)
+ strcpy(G.sce, line);
+
+ recent = (RecentFile*)MEM_mallocN(sizeof(RecentFile),"RecentFile");
+ BLI_addtail(&(G.recent_files), recent);
+ recent->filename = (char*)MEM_mallocN(sizeof(char)*(strlen(line)+1), "name of file");
+ recent->filename[0] = '\0';
+
+ strcpy(recent->filename, line);
+ }
+ }
+
+ if(G.sce[0] == 0)
+ BLI_make_file_string("/", G.sce, BLI_gethome(), "untitled.blend");
+
+ BLI_free_file_lines(lines);
+
+#ifdef WIN32
+ /* Add the drive names to the listing */
+ {
+ __int64 tmp;
+ char folder[MAX_PATH];
+ char tmps[4];
+ int i;
+
+ tmp= GetLogicalDrives();
+
+ for (i=2; i < 26; i++) {
+ if ((tmp>>i) & 1) {
+ tmps[0]='a'+i;
+ tmps[1]=':';
+ tmps[2]='\\';
+ tmps[3]=0;
+
+ fsmenu_insert_entry(tmps, 0, 0);
+ }
+ }
+
+ /* Adding Desktop and My Documents */
+ fsmenu_append_separator();
+
+ SHGetSpecialFolderPath(0, folder, CSIDL_PERSONAL, 0);
+ fsmenu_insert_entry(folder, 0, 0);
+ SHGetSpecialFolderPath(0, folder, CSIDL_DESKTOPDIRECTORY, 0);
+ fsmenu_insert_entry(folder, 0, 0);
+
+ fsmenu_append_separator();
+ }
+#endif
+
+ BLI_make_file_string(G.sce, name, BLI_gethome(), ".Bfs");
+ lines= BLI_read_file_as_lines(name);
+
+ for (l= lines; l; l= l->next) {
+ char *line= l->link;
+
+ if (!BLI_streq(line, "")) {
+ fsmenu_insert_entry(line, 0, 1);
+ }
+ }
+
+ fsmenu_append_separator();
+
+ /* add last saved file */
+ BLI_split_dirfile(G.sce, name, filename); /* G.sce shouldn't be relative */
+
+ fsmenu_insert_entry(name, 0, 0);
+
+ BLI_free_file_lines(lines);
+}
+
+static void writeBlog(void)
+{
+ struct RecentFile *recent, *next_recent;
+ char name[FILE_MAXDIR+FILE_MAXFILE];
+ FILE *fp;
+ int i;
+
+ BLI_make_file_string("/", name, BLI_gethome(), ".Blog");
+
+ recent = G.recent_files.first;
+ /* refresh .Blog of recent opened files, when current file was changed */
+ if(!(recent) || (strcmp(recent->filename, G.sce)!=0)) {
+ fp= fopen(name, "w");
+ if (fp) {
+ /* add current file to the beginning of list */
+ recent = (RecentFile*)MEM_mallocN(sizeof(RecentFile),"RecentFile");
+ recent->filename = (char*)MEM_mallocN(sizeof(char)*(strlen(G.sce)+1), "name of file");
+ recent->filename[0] = '\0';
+ strcpy(recent->filename, G.sce);
+ BLI_addhead(&(G.recent_files), recent);
+ /* write current file to .Blog */
+ fprintf(fp, "%s\n", recent->filename);
+ recent = recent->next;
+ i=1;
+ /* write rest of recent opened files to .Blog */
+ while((i<U.recent_files) && (recent)){
+ /* this prevents to have duplicities in list */
+ if (strcmp(recent->filename, G.sce)!=0) {
+ fprintf(fp, "%s\n", recent->filename);
+ recent = recent->next;
+ }
+ else {
+ next_recent = recent->next;
+ MEM_freeN(recent->filename);
+ BLI_freelinkN(&(G.recent_files), recent);
+ recent = next_recent;
+ }
+ i++;
+ }
+ fclose(fp);
+ }
+ }
+}
+
+static void do_history(char *name)
+{
+ char tempname1[FILE_MAXDIR+FILE_MAXFILE], tempname2[FILE_MAXDIR+FILE_MAXFILE];
+ int hisnr= U.versions;
+
+ if(U.versions==0) return;
+ if(strlen(name)<2) return;
+
+ while( hisnr > 1) {
+ sprintf(tempname1, "%s%d", name, hisnr-1);
+ sprintf(tempname2, "%s%d", name, hisnr);
+
+ if(BLI_rename(tempname1, tempname2))
+ error("Unable to make version backup");
+
+ hisnr--;
+ }
+
+ /* is needed when hisnr==1 */
+ sprintf(tempname1, "%s%d", name, hisnr);
+
+ if(BLI_rename(name, tempname1))
+ error("Unable to make version backup");
+}
+
+void BIF_write_file(char *target)
+{
+ Library *li;
+ int writeflags, len;
+ char di[FILE_MAX];
+ char *err;
+
+ len = strlen(target);
+
+ if (len == 0) return;
+ if (len >= FILE_MAX) {
+ error("Path too long, cannot save");
+ return;
+ }
+
+ /* send the OnSave event */
+ if (G.f & G_DOSCRIPTLINKS) BPY_do_pyscript(&G.scene->id, SCRIPT_ONSAVE);
+
+ for (li= G.main->library.first; li; li= li->id.next) {
+ if (BLI_streq(li->name, target)) {
+ error("Cannot overwrite used library");
+ return;
+ }
+ }
+
+ if (!BLO_has_bfile_extension(target) && (len+6 < FILE_MAX)) {
+ sprintf(di, "%s.blend", target);
+ } else {
+ strcpy(di, target);
+ }
+
+ if (BLI_exists(di)) {
+ if(!saveover(di))
+ return;
+ }
+
+ if(G.obedit) {
+ exit_editmode(0); /* 0 = no free data */
+ }
+ if (G.fileflags & G_AUTOPACK) {
+ packAll();
+ }
+
+ waitcursor(1); // exit_editmode sets cursor too
+
+ do_history(di);
+
+ /* we use the UserDef to define compression flag */
+ writeflags= G.fileflags & ~G_FILE_COMPRESS;
+ if(U.flag & USER_FILECOMPRESS)
+ writeflags |= G_FILE_COMPRESS;
+
+ if (BLO_write_file(di, writeflags, &err)) {
+ strcpy(G.sce, di);
+ G.relbase_valid = 1;
+ strcpy(G.main->name, di); /* is guaranteed current file */
+
+ mainwindow_set_filename_to_title(G.main->name);
+
+ G.save_over = 1;
+
+ writeBlog();
+ } else {
+ error("%s", err);
+ }
+
+ waitcursor(0);
+}
+
+void BIF_write_homefile(void)
+{
+ char *err, tstr[FILE_MAXDIR+FILE_MAXFILE];
+ int write_flags;
+
+ BLI_make_file_string("/", tstr, BLI_gethome(), ".B.blend");
+
+ /* force save as regular blend file */
+ write_flags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_LOCK | G_FILE_SIGN);
+ BLO_write_file(tstr, write_flags, &err);
+}
+
+void BIF_write_autosave(void)
+{
+ char *err, tstr[FILE_MAXDIR+FILE_MAXFILE];
+ int write_flags;
+
+ get_autosave_location(tstr);
+
+ /* force save as regular blend file */
+ write_flags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_LOCK | G_FILE_SIGN);
+ BLO_write_file(tstr, write_flags, &err);
+}
+
+/* if global undo; remove tempsave, otherwise rename */
+static void delete_autosave(void)
+{
+ char tstr[FILE_MAXDIR+FILE_MAXFILE];
+
+ get_autosave_location(tstr);
+
+ if (BLI_exists(tstr)) {
+ char str[FILE_MAXDIR+FILE_MAXFILE];
+ BLI_make_file_string("/", str, U.tempdir, "quit.blend");
+
+ if(U.uiflag & USER_GLOBALUNDO) BLI_delete(tstr, 0, 0);
+ else BLI_rename(tstr, str);
+ }
+}
+
+/***/
+
+static void initbuttons(void)
+{
+ uiDefFont(UI_HELVB,
+ BMF_GetFont(BMF_kHelveticaBold14),
+ BMF_GetFont(BMF_kHelveticaBold12),
+ BMF_GetFont(BMF_kHelveticaBold10),
+ BMF_GetFont(BMF_kHelveticaBold8));
+ uiDefFont(UI_HELV,
+ BMF_GetFont(BMF_kHelvetica12),
+ BMF_GetFont(BMF_kHelvetica12),
+ BMF_GetFont(BMF_kHelvetica10),
+ BMF_GetFont(BMF_kHelveticaBold8));
+
+ glClearColor(.7f, .7f, .6f, 0.0);
+
+ G.font= BMF_GetFont(BMF_kHelvetica12);
+ G.fonts= BMF_GetFont(BMF_kHelvetica10);
+ G.fontss= BMF_GetFont(BMF_kHelveticaBold8);
+
+ clear_matcopybuf();
+
+ glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+}
+
+
+static void sound_init_listener(void)
+{
+ G.listener = MEM_callocN(sizeof(bSoundListener), "soundlistener");
+ G.listener->gain = 1.0;
+ G.listener->dopplerfactor = 1.0;
+ G.listener->dopplervelocity = 340.29f;
+}
+
+void BIF_init(void)
+{
+
+ initscreen(); /* for (visuele) speed, this first, then setscreen */
+ initbuttons();
+ InitCursorData();
+ sound_init_listener();
+ init_node_butfuncs();
+
+ BIF_preview_init_dbase();
+
+ /* dont set an undo here because this sets the default scene to be the initial
+ undo state when loading blender with a file a new file, so holding Ctrl+Z will undo to the default
+ scene rather then to the new file */
+ BIF_read_homefile(0, 0);
+
+ BIF_resources_init(); /* after homefile, to dynamically load an icon file based on theme settings */
+
+ BIF_filelist_init_icons();
+
+ init_gl_stuff(); /* drawview.c, after homefile */
+ readBlog();
+ BLI_strncpy(G.lib, G.sce, FILE_MAX);
+}
+
+/***/
+
+extern ListBase editNurb;
+extern ListBase editelems;
+
+void exit_usiblender(void)
+{
+ struct TmpFont *tf;
+ tf= G.ttfdata.first;
+ while(tf)
+ {
+ freePackedFile(tf->pf);
+ tf->pf= NULL;
+ tf->vfont= NULL;
+ tf= tf->next;
+ }
+ BLI_freelistN(&G.ttfdata);
+#ifdef WITH_VERSE
+ end_all_verse_sessions();
+#endif
+ free_openrecent();
+
+ freeAllRad();
+ BKE_freecubetable();
+
+ if (G.background == 0)
+ sound_end_all_sounds();
+
+ if(G.obedit) {
+ if(G.obedit->type==OB_FONT) {
+ free_editText();
+ }
+ else if(G.obedit->type==OB_MBALL) BLI_freelistN(&editelems);
+ free_editMesh(G.editMesh);
+ }
+
+ free_editLatt();
+ free_editArmature();
+ free_posebuf();
+
+ /* before free_blender so py's gc happens while library still exists */
+ /* needed at least for a rare sigsegv that can happen in pydrivers */
+ BPY_end_python();
+
+ fastshade_free_render(); /* shaded view */
+ free_blender(); /* blender.c, does entire library */
+ free_matcopybuf();
+ free_ipocopybuf();
+ free_actcopybuf();
+ free_vertexpaint();
+ free_imagepaint();
+
+ /* editnurb can remain to exist outside editmode */
+ freeNurblist(&editNurb);
+
+ fsmenu_free();
+
+#ifdef INTERNATIONAL
+ free_languagemenu();
+#endif
+
+ RE_FreeAllRender();
+
+ free_txt_data();
+
+ sound_exit_audio();
+ if(G.listener) MEM_freeN(G.listener);
+
+
+ libtiff_exit();
+
+#ifdef WITH_QUICKTIME
+ quicktime_exit();
+#endif
+
+ if (!G.background) {
+ BIF_resources_free();
+
+ BIF_filelist_free_icons();
+
+ BIF_close_render_display();
+ mainwindow_close();
+ }
+
+#ifdef INTERNATIONAL
+ FTF_End();
+#endif
+
+ if (copybuf) MEM_freeN(copybuf);
+ if (copybufinfo) MEM_freeN(copybufinfo);
+
+ /* undo free stuff */
+ undo_editmode_clear();
+
+ BKE_undo_save_quit(); // saves quit.blend if global undo is on
+ BKE_reset_undo();
+
+ BLI_freelistN(&U.themes);
+ BIF_preview_free_dbase();
+
+ if(totblock!=0) {
+ printf("Error Totblock: %d\n",totblock);
+ MEM_printmemlist();
+ }
+ delete_autosave();
+
+ printf("\nBlender quit\n");
+
+#ifdef WIN32
+ /* ask user to press enter when in debug mode */
+ if(G.f & G_DEBUG) {
+ printf("press enter key to exit...\n\n");
+ getchar();
+ }
+#endif
+
+
+ SYS_DeleteSystem(SYS_GetSystem());
+
+ exit(G.afbreek==1);
+}
diff --git a/source/blender/src/verse_common.c b/source/blender/src/verse_common.c
new file mode 100644
index 00000000000..d91c09dc2cd
--- /dev/null
+++ b/source/blender/src/verse_common.c
@@ -0,0 +1,298 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributor(s): Jiri Hnidek.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifdef WITH_VERSE
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "mydevice.h"
+
+#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
+
+#include "BKE_global.h"
+#include "BKE_blender.h"
+
+#include "BIF_verse.h"
+#include "BIF_space.h"
+#include "BIF_interface.h"
+
+extern ListBase session_list;
+extern ListBase server_list;
+
+/*
+ * this function creates popup menu with all active VerseSessions
+ * it return pointer at selected VerseSession, if no VerseSession
+ * is selected, then NULL is returned
+ */
+VerseSession *session_menu(void)
+{
+ struct VerseSession *session;
+ char session_number[10];
+ short i=1, num=1;
+ char session_address_list[1024]; /* pupmenu business */
+
+ session_number[0] = '\0';
+ session_address_list[0] = '\0';
+
+ strcat(session_address_list, "Session list %t");
+
+ session = session_list.first;
+
+ while(session){
+ strcat(session_address_list, "| ");
+ strcat(session_address_list, session->address);
+ strcat(session_address_list, " %x");
+ sprintf(session_number, "%d", num);
+ strcat(session_address_list, session_number);
+ num++;
+ session = session->next;
+ }
+
+ printf("session list: %s\n", session_address_list);
+ num = pupmenu(session_address_list);
+
+ if(num==-1) return NULL;
+
+ session = session_list.first;
+
+ while(session) {
+ if(i==num) return session;
+ i++;
+ session = session->next;
+ }
+
+ return NULL;
+}
+
+/*
+ * returns name of verse client (it is used as avatar's name)
+ */
+char *verse_client_name(void)
+{
+ char *client_name;
+ char blender_version[5];
+ short name_lenght = 14;
+
+#ifndef WIN32
+ char *hostname;
+ hostname = getenv("HOSTNAME");
+ if(hostname) name_lenght += strlen(hostname);
+#endif
+
+ client_name = (char*)MEM_mallocN(sizeof(char)*name_lenght, "verse client name");
+ client_name[0] = '\0';
+
+ strcat(client_name, "blender_");
+ blender_version[0] = '\0';
+ sprintf(blender_version, "%d", BLENDER_VERSION);
+ strcat(client_name, blender_version);
+
+#ifndef WIN32
+ /* add at the end of the client name hostname */
+ if(hostname) {
+ strcat(client_name, ":");
+ strcat(client_name, hostname);
+ }
+#endif
+
+ return client_name;
+}
+
+/*===========================================================
+ *
+ * functions executed after calling callback functions
+ *
+ ============================================================*/
+
+/*
+ * this function is called, when some tag was changed or new tag was created
+ */
+void post_tag_change(VTag *vtag)
+{
+ printf("\tnew tag %s was created or changed\n", vtag->name);
+}
+
+/*
+ * this function is called, when verse taggroup was created
+ */
+void post_taggroup_create(VTagGroup *vtaggroup)
+{
+ printf("\tnew taggroup %s was created\n", vtaggroup->name);
+}
+
+/*
+ * this function is called after creating of new VerseNode
+ */
+void post_node_create(VNode *vnode)
+{
+ struct VerseSession *session = vnode->session;
+
+ if((session->flag & VERSE_AUTOSUBSCRIBE) && (vnode->owner_id != VN_OWNER_MINE)) {
+ if(vnode->type == V_NT_OBJECT) {
+ create_object_from_verse_node(vnode);
+ }
+ else if(vnode->type == V_NT_GEOMETRY) {
+ create_mesh_from_geom_node(vnode);;
+ }
+ }
+
+ allqueue(REDRAWOOPS, 0);
+}
+
+/*
+ * this function is called after destroying of VerseNode
+ */
+void post_node_destroy(VNode *vnode)
+{
+ allqueue(REDRAWOOPS, 0);
+
+ /* TODO: destroy bindings between vnode and blender data structures */
+}
+
+/*
+ * this function is calles after renaming of VerseNode by verse_server
+ */
+void post_node_name_set(VNode *vnode)
+{
+ /* if VerseNode has coresponding blender data structure, then
+ * change ID name of data structure */
+ if(vnode->type==V_NT_OBJECT) {
+ struct Object *ob;
+ ob = (Object*)((VObjectData*)vnode->data)->object;
+ if(ob) {
+ char *str;
+ str = (char*)malloc(sizeof(char)*(strlen(vnode->name)+3));
+ str[0] = '\0';
+ strcat(str, "OB");
+ strcat(str, vnode->name);
+ strncpy(ob->id.name, str, 23);
+ printf("\tob->id.name: %s\n", ob->id.name);
+ free(str);
+ }
+ }
+ else if(vnode->type==V_NT_GEOMETRY) {
+ struct Mesh *me;
+
+ me = (Mesh*)((VGeomData*)vnode->data)->mesh;
+ if(me) {
+ char *str;
+ str = (char*)malloc(sizeof(char)*(strlen(vnode->name)+3));
+ str[0] = '\0';
+ strcat(str, "ME");
+ strcat(str, vnode->name);
+ strncpy(me->id.name, str, 23);
+ printf("\tme->id.name: %s\n", me->id.name);
+ free(str);
+ }
+ }
+
+ allqueue(REDRAWALL, 0);
+}
+
+/*
+ * this function is called after acception connection with verse server
+ */
+void post_connect_accept(VerseSession *session)
+{
+ VerseServer *server;
+
+ G.f |= G_VERSE_CONNECTED;
+
+ session->counter = 0;
+
+ server = server_list.first;
+ while(server) {
+ if(strcmp(server->ip, session->address)==0) {
+ server->flag = session->flag;
+ break;
+ }
+ server = server->next;
+ }
+
+ allqueue(REDRAWOOPS, 0);
+}
+
+void post_server_add(void)
+{
+ allqueue(REDRAWOOPS, 0);
+}
+
+/*
+ * this function is called, when connestion with verse server is ended/terminated/etc.
+ */
+void post_connect_terminated(VerseSession *session)
+{
+ VerseServer *server;
+ server = server_list.first;
+ while(server) {
+ if(strcmp(server->ip, session->address)==0) {
+ server->flag = 0;
+ server->session=NULL;
+ break;
+ }
+ server = server->next;
+ }
+
+ /* if it is last session, then no other will exist ... set Global flag */
+ if((session->prev==NULL) && (session->next==NULL))
+ G.f &= ~G_VERSE_CONNECTED;
+
+ allqueue(REDRAWOOPS, 0);
+}
+
+/*
+ * if connection wasn't accepted, then free VerseSession
+ * and print warning message with popupmenu
+ */
+void post_connect_update(VerseSession *session)
+{
+ if(session->flag & VERSE_CONNECTING) {
+ session->counter++;
+ if(session->counter > MAX_UNCONNECTED_EVENTS) {
+ char *str;
+ /* popup menu*/
+ str = malloc(sizeof(char)*(strlen(session->address)+35));
+ str[0]='\0';
+ strcat(str, "Error%t|No response from server: ");
+ strcat(str, session->address);
+ pupmenu(str);
+ free(str);
+
+ session->flag = 0;
+ session->counter = 0;
+ session->post_connect_terminated(session);
+ free_verse_session(session);
+ }
+ }
+}
+
+#endif
+
diff --git a/source/blender/src/verse_image.c b/source/blender/src/verse_image.c
new file mode 100644
index 00000000000..9e9b478980e
--- /dev/null
+++ b/source/blender/src/verse_image.c
@@ -0,0 +1,343 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributor(s): Jiri Hnidek.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifdef WITH_VERSE
+
+#include <string.h>
+
+#include "mydevice.h"
+
+#include "BKE_verse.h"
+#include "BKE_image.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_image_types.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "BDR_drawmesh.h"
+
+#include "BIF_verse.h"
+#include "BIF_space.h"
+
+/*
+ * unsubscribe from verse bitmap
+ */
+void unsubscribe_from_bitmap_node(VNode *vnode)
+{
+ if(vnode->type != V_NT_BITMAP) return;
+
+ /* TODO */
+}
+
+/*
+ * upload image to verse server
+ */
+void push_image_to_verse_server(VerseSession *session, Image *image)
+{
+ ImBuf *ibuf= BKE_image_get_ibuf(image, NULL);
+ struct VNode *vnode;
+
+ if(!session) return;
+
+ if(!(session->flag & VERSE_CONNECTED)) return;
+
+ /* create "my" new object VerseNode */
+ vnode= create_verse_node(session, -1 , V_NT_BITMAP, VN_OWNER_MINE);
+ /* create object data */
+ vnode->data = create_bitmap_data();
+
+ /* set up name of VerseNode */
+ vnode->name = (char*)MEM_mallocN(sizeof(char*)*(strlen(image->id.name)-1), "object node name");
+ vnode->name[0] = '\0';
+ strcat(vnode->name, image->id.name+2);
+
+ /* set up dimension of image */
+ if(ibuf) {
+ ((VBitmapData*)vnode->data)->width = ibuf->x;
+ ((VBitmapData*)vnode->data)->height = ibuf->y;
+ }
+ else {
+ ((VBitmapData*)vnode->data)->width = 0;
+ ((VBitmapData*)vnode->data)->height = 0;
+ }
+ ((VBitmapData*)(vnode->data))->height = 1;
+
+ /* set up pointers between Object and VerseNode */
+ ((VBitmapData*)vnode->data)->image = (void*)image;
+ image->vnode = (void*)vnode;
+
+ /* add node to sending queue */
+ add_item_to_send_queue(&(session->queue), vnode, VERSE_NODE);
+}
+
+/*
+ * synchronize blender image channel (R,G,B,A) with verse bitmap layer
+ */
+void sync_blender_image_channel_with_verse_layer(VNode *vnode, VBitmapLayer *vblayer)
+{
+ struct Image *image = (Image*)((VBitmapData*)(vnode->data))->image;
+ struct ImBuf *ibuf= BKE_image_get_ibuf(image, NULL);
+ unsigned char *rect;
+ int x, y, height, t_width, i, channel=0;
+
+ if(!image) return;
+
+ if(!ibuf) return;
+
+ rect = (unsigned char*)ibuf->rect;
+
+ /* select channel due to verse layer name */
+ if(strcmp(vblayer->name,"col_r")==0)
+ channel = 0;
+ else if(strcmp(vblayer->name,"col_g")==0)
+ channel = 1;
+ else if(strcmp(vblayer->name, "col_b")==0)
+ channel = 2;
+ else if(strcmp(vblayer->name,"alpha")==0)
+ channel = 3;
+
+#ifdef VERSE_DEBUG_PRINT
+ printf(" %s:%d\n", vblayer->name, channel);
+#endif
+
+ height = ((VBitmapData*)(vnode->data))->height;
+ t_width = ((VBitmapData*)(vnode->data))->t_width;
+
+ i = (height-1)*t_width;
+
+#ifdef VERSE_DEBUG_PRINT
+ printf("\ti:%d\n", i);
+#endif
+
+ if(vblayer->type==VN_B_LAYER_UINT8) {
+ unsigned char *vuint8 = (unsigned char*)vblayer->data;
+ for(y=height-1; y>=0; y--, i=y*t_width)
+ for(x=0; x<ibuf->x; x++, rect+=4, i++)
+ rect[channel] = (char)vuint8[i];
+ }
+
+ allqueue(REDRAWIMAGE, 0);
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+/*
+ * synchronize blender image with verse image
+ */
+void sync_blender_image_with_verse_bitmap_node(VNode *vnode)
+{
+ struct VBitmapLayer *vblayer;
+
+ vblayer = ((VBitmapData*)(vnode->data))->layers.lb.first;
+
+ while(vblayer) {
+#ifdef VERSE_DEBUG_PRINT
+ printf("\tsyncing layer:");
+#endif
+ sync_blender_image_channel_with_verse_layer(vnode, vblayer);
+ vblayer = vblayer->next;
+ }
+}
+
+/*
+ * This function is called, when some other verse client change dimension of image.
+ * It is neccesary to reallocate blender image too, when dimension of verse image
+ * is different from blender image.
+ */
+void post_bitmap_dimension_set(VNode *vnode)
+{
+ struct Image *image = (Image*)((VBitmapData*)(vnode->data))->image;
+ struct ImBuf *ibuf= BKE_image_get_ibuf(image, NULL);
+
+ if(!image) return;
+
+ if(!ibuf) return;
+
+ if(vnode->owner_id == VN_OWNER_MINE) {
+ if( ((VBitmapData*)vnode->data)->layers.lb.first == NULL ) {
+ /* send all verse bitmap layers (RGBA) to verse server */
+ printf("\tsending all bitmap layers to verse server\n");
+ verse_send_b_layer_create(vnode->id, -1, "col_r", VN_B_LAYER_UINT8);
+ verse_send_b_layer_create(vnode->id, -1, "col_g", VN_B_LAYER_UINT8);
+ verse_send_b_layer_create(vnode->id, -1, "col_b", VN_B_LAYER_UINT8);
+ verse_send_b_layer_create(vnode->id, -1, "alpha", VN_B_LAYER_UINT8);
+
+ return;
+ }
+ }
+
+ if((ibuf->x!=((VBitmapData*)vnode->data)->width) || (ibuf->y!=((VBitmapData*)vnode->data)->height)) {
+ struct VBitmapLayer *vblayer;
+ struct ImBuf *new_ibuf;
+
+ /* allocate new ibuf */
+ new_ibuf= IMB_allocImBuf(((VBitmapData*)vnode->data)->width,
+ ((VBitmapData*)vnode->data)->height, 24, IB_rect, 0);
+ /* free old ibuf */
+ BKE_image_signal(image, NULL, IMA_SIGNAL_FREE);
+ /* set up pointer at new ibuf */
+ BKE_image_assign_ibuf(image, ibuf);
+
+ /* sync blender image with all verse layers */
+ vblayer = ((VBitmapData*)(vnode->data))->layers.lb.first;
+ while(vblayer) {
+ sync_blender_image_channel_with_verse_layer(vnode, vblayer);
+ vblayer = vblayer->next;
+ }
+ }
+}
+
+/*
+ * when blender tries to upload image to verse server, then it is neccessary
+ * to push coresponding channel data to verse server, when verse bitmap layer
+ * was created
+ */
+void post_bitmap_layer_create(VBitmapLayer *vblayer)
+{
+ struct VNode *vnode = vblayer->vnode;
+ struct Image *image = (Image*)((VBitmapData*)(vnode->data))->image;
+ struct ImBuf *ibuf= BKE_image_get_ibuf(image, NULL);
+ unsigned char *rect;
+ short channel;
+/* VNBTile tile[VN_B_TILE_SIZE*VN_B_TILE_SIZE];
+ unsigned int width, t_width, height, t_height, x, y, i, j; */
+
+ /* if this application doesn't try to upload this image to verse
+ * server then do nothing */
+ if(vnode->owner_id != VN_OWNER_MINE) return;
+
+ if(!image) return;
+
+ if(!ibuf) return;
+
+ rect = (unsigned char*)ibuf->rect;
+
+ if(strncmp(vblayer->name, "col_r", 5))
+ channel = 0;
+ else if(strncmp(vblayer->name, "col_g", 5))
+ channel = 1;
+ else if(strncmp(vblayer->name, "col_b", 5))
+ channel = 2;
+ else if(strncmp(vblayer->name, "alpha", 5))
+ channel = 3;
+
+ /* TODO: send all data of channel to verse server */
+}
+
+/*
+ * dummy function now
+ */
+void post_bitmap_layer_destroy(VBitmapLayer *vblayer)
+{
+}
+
+/*
+ * this function is executed, when some image changed tile comes from verse server,
+ * it is neccessary to do some crazy transformation here, because blender uses
+ * different (very unstandard) image coordinate system (begining of coordinate
+ * system is in bottom left corner) ... all other programs (including verse) has
+ * begining of image coordinate system in left top corner
+ */
+void post_bitmap_tile_set(VBitmapLayer *vblayer, unsigned int xs, unsigned int ys)
+{
+ struct VNode *vnode = vblayer->vnode;
+ struct Image *image = (Image*)((VBitmapData*)(vnode->data))->image;
+ struct ImBuf *ibuf= BKE_image_get_ibuf(image, NULL);
+ unsigned char *rect, *i_rect;
+ unsigned int x, y, t_width, t_height, height, m_ys, m_y, d, i, j, channel=0;
+
+ if(!image) return;
+
+ if(!ibuf) return;
+
+ /* select channel due to verse layer name */
+ if(strcmp(vblayer->name,"color_r")==0)
+ channel = 0;
+ else if(strcmp(vblayer->name,"color_g")==0)
+ channel = 1;
+ else if(strcmp(vblayer->name, "color_b")==0)
+ channel = 2;
+ else if(strcmp(vblayer->name,"transparency")==0)
+ channel = 3;
+
+ i_rect = rect = (unsigned char*)ibuf->rect;
+
+ /* width of verse image including all tiles */
+ t_width =((VBitmapData*)vnode->data)->t_width;
+ /* height of verse image including all tiles */
+ t_height =((VBitmapData*)vnode->data)->t_height;
+ /* height of blender image */
+ height = ((VBitmapData*)vnode->data)->height;
+
+ /* if the bitmap's dimensions are not integer multiples of the tile
+ * side length, eight, then d will not be zero (height of "uncomplete
+ * tile") */
+ d = VN_B_TILE_SIZE - (t_height - height);
+ /* mirrored coordination of received tile */
+ m_ys = t_height - ys - VN_B_TILE_SIZE;
+
+ /* ys and m_ys are y axis, where we will do some changes */
+ if(ys + VN_B_TILE_SIZE > height) {
+ m_ys = 0;
+ ys = ys + d - 1;
+ }
+ else {
+ m_ys = m_ys - VN_B_TILE_SIZE + d;
+ ys = ys + VN_B_TILE_SIZE - 1;
+ }
+
+ /* "index" of blender image */
+ j = m_ys*ibuf->x + xs;
+ /* index of verse image */
+ i = ys*t_width + xs;
+
+ /* pointer at image data, that will be changed in following loop */
+ rect = i_rect + 4*j;
+
+ /* it seems hackish, but I didn't find better solution :-/ */
+ if(vblayer->type==VN_B_LAYER_UINT8) {
+ unsigned char *vuint8 = (unsigned char*)vblayer->data;
+ for(y=ys, m_y = m_ys;
+ (m_y<m_ys+VN_B_TILE_SIZE) && (m_y<ibuf->y);
+ y--, m_y++, i=y*t_width+xs, j=m_y*ibuf->x+xs, rect=i_rect+4*j)
+ for(x=xs; (x<xs+VN_B_TILE_SIZE) && (x<ibuf->x); x++, rect+=4, i++, j++)
+ rect[channel] = (char)vuint8[i];
+ }
+
+ free_realtime_image(image);
+
+ /* redraw preview of image ... uncommented, because rendering
+ * was computed too often */
+/* BIF_preview_changed(ID_TE); */
+ allqueue(REDRAWIMAGE, 0);
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+#endif
+
diff --git a/source/blender/src/verse_mesh.c b/source/blender/src/verse_mesh.c
new file mode 100644
index 00000000000..2257eac41f5
--- /dev/null
+++ b/source/blender/src/verse_mesh.c
@@ -0,0 +1,1629 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributor(s): Jiri Hnidek.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifdef WITH_VERSE
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "mydevice.h"
+
+#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
+
+#include "BLI_dynamiclist.h"
+#include "BLI_blenlib.h"
+#include "BLI_edgehash.h"
+#include "BLI_editVert.h"
+
+#include "BKE_customdata.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_mesh.h"
+#include "BKE_utildefines.h"
+#include "BKE_verse.h"
+
+#include "BIF_verse.h"
+#include "BIF_editmesh.h"
+#include "BIF_space.h"
+#include "BIF_screen.h"
+
+#include "BSE_edit.h"
+
+#include "editmesh.h"
+
+#include "verse.h"
+
+/* prototypes of static functions */
+
+static void mark_changed_face_obsolete(struct VerseFace *vface);
+static void sync_verseface_with_editface(struct VLayer *vlayer, struct VerseFace *vface);
+
+void createVerseVertNL(struct EditVert *ev, struct VNode *vnode, struct VLayer *vlayer);
+static void createAllVerseVerts(struct VNode *vnode, struct VLayer *vlayer);
+void createVerseFaceNL(struct EditFace *efa, struct VNode *vnode, struct VLayer *vlayer);
+static void createAllVerseFaces(struct VNode *vnode, struct VLayer *vlayer);
+
+/*=============================================================================
+ *
+ * functions handling verse/blender FACES
+ *
+ *===========================================================================*/
+
+/*
+ * create new VerseFace (polygon), due to information about EditFace
+ * put VerseFace to queue ... send to verse host (server)
+ */
+void createVerseFace(EditFace *efa)
+{
+ if(G.editMesh->vnode) {
+ struct VLayer *vlayer = find_verse_layer_type((VGeomData*)((VNode*)G.editMesh->vnode)->data, POLYGON_LAYER);
+ createVerseFaceNL(efa, (VNode*)G.editMesh->vnode, vlayer);
+ }
+ else efa->vface = NULL;
+}
+
+/*
+ * create new VerseFace (polygon), due to information about EditFace
+ * put VerseFace to queue ... send to verse host (server)
+ * NL version of function (infomration about verse node and
+ * layer is known ... optimalisation)
+ */
+void createVerseFaceNL(EditFace *efa, VNode *vnode, VLayer *vlayer)
+{
+ struct VerseFace *vface;
+
+ vface = (VerseFace*)create_verse_face(vlayer, vlayer->counter, -1, -1, -1, -1);
+
+ vface->face = (void*)efa;
+ efa->vface = (void*)vface;
+
+ vface->flag |= FACE_SEND_READY;
+
+ /* EditVert #1 */
+ if(efa->v1) {
+ if(efa->v1->vvert) {
+ vface->vvert0 = (VerseVert*)efa->v1->vvert;
+ if(((VerseVert*)efa->v1->vvert)->flag & VERT_RECEIVED) {
+ vface->v0 = ((VerseVert*)efa->v1->vvert)->id;
+ vface->counter--;
+ }
+ else
+ vface->flag &= ~FACE_SEND_READY;
+ }
+ }
+ else
+ vface->counter--;
+
+ /* EditVert #2 */
+ if(efa->v2) {
+ if(efa->v2->vvert) {
+ vface->vvert1 = (VerseVert*)efa->v2->vvert;
+ if(((VerseVert*)efa->v2->vvert)->flag & VERT_RECEIVED) {
+ vface->v1 = ((VerseVert*)efa->v2->vvert)->id;
+ vface->counter--;
+ }
+ else
+ vface->flag &= ~FACE_SEND_READY;
+ }
+ }
+ else
+ vface->counter--;
+ /* EditVert #3 */
+ if(efa->v3) {
+ if(efa->v3->vvert) {
+ vface->vvert2 = (VerseVert*)efa->v3->vvert;
+ if(((VerseVert*)efa->v3->vvert)->flag & VERT_RECEIVED) {
+ vface->v2 = ((VerseVert*)efa->v3->vvert)->id;
+ vface->counter--;
+ }
+ else
+ vface->flag &= ~FACE_SEND_READY;
+ }
+ }
+ else
+ vface->counter--;
+ /* EditVert #4 */
+ if(efa->v4) {
+ if(efa->v4->vvert) {
+ vface->vvert3 = (VerseVert*)efa->v4->vvert;
+ if(((VerseVert*)efa->v4->vvert)->flag & VERT_RECEIVED) {
+ vface->v3 = ((VerseVert*)efa->v4->vvert)->id;
+ vface->counter--;
+ }
+ else
+ vface->flag &= ~FACE_SEND_READY;
+ }
+ }
+ else
+ vface->counter--;
+
+ add_item_to_send_queue(&(vlayer->queue), (void*)vface, VERSE_FACE);
+}
+
+/*
+ * creates new verse faces, add all of then to queue ... send to verse server
+ */
+static void createAllVerseFaces(VNode *vnode, VLayer *vlayer)
+{
+ if(G.obedit) {
+ struct EditMesh *em;
+ struct EditFace *efa;
+
+ em = G.editMesh;
+
+ efa = em->faces.first;
+ /* push all EditFaces to the verse server */
+ while(efa){
+ createVerseFaceNL(efa, vnode, vlayer);
+ efa = efa->next;
+ }
+ }
+}
+
+/*
+ * When verse face is changed during sending/receiving from verse server, then
+ * this verse face is marked as obsolete and it will be send again, when it
+ * will be received from verse server
+ */
+static void mark_changed_face_obsolete(VerseFace *vface)
+{
+ struct EditFace *efa = (EditFace*)vface->face;
+
+ if(efa) {
+ if(vface->vvert0->vertex != efa->v1) vface->flag |= FACE_OBSOLETE;
+ if(vface->vvert1->vertex != efa->v2) vface->flag |= FACE_OBSOLETE;
+ if(vface->vvert2->vertex != efa->v3) vface->flag |= FACE_OBSOLETE;
+ if(vface->vvert3 && (vface->vvert3->vertex != efa->v4)) vface->flag |= FACE_OBSOLETE;
+ }
+}
+
+/*
+ * this function will sync EditFace and VerseFace and it will send changes to
+ * verse server too
+ */
+static void sync_verseface_with_editface(VLayer *vlayer, VerseFace *vface)
+{
+ struct EditFace *efa = (EditFace*)vface->face;
+ int dosend = 0;
+
+ /* edit face and probably verse face was deleted */
+ if(!efa || (vface->flag & FACE_DELETED)) return;
+
+ /* blender nor verse don't support such crazy things */
+ if(!(vface->vvert0) || !(vface->vvert1) || !(vface->vvert2)) {
+ printf("\tERROR: vface->vvert0: %p, vface->vvert1: %p, vface->vvert2: %p\n", vface->vvert0, vface->vvert1, vface->vvert2);
+ return;
+ }
+
+ /* initialize verse face flag */
+ vface->flag |= FACE_SEND_READY;
+
+ /* debug print */
+#if 0
+ printf("\n");
+ if(efa->v4) {
+ printf("\tefa->v1,v2,v3,v4->vvert->id: %d, %d, %d, %d\n",
+ ((VerseVert*)efa->v1->vvert)->id,
+ ((VerseVert*)efa->v2->vvert)->id,
+ ((VerseVert*)efa->v3->vvert)->id,
+ ((VerseVert*)efa->v4->vvert)->id);
+ printf("\tefa->v1,v2,v3,v4->vvert: %p, %p, %p, %p\n",
+ efa->v1->vvert,
+ efa->v2->vvert,
+ efa->v3->vvert,
+ efa->v4->vvert);
+ }
+ else {
+ printf("\tefa->v1,v2,v3->vvert->id: %d, %d, %d, NULL\n",
+ ((VerseVert*)efa->v1->vvert)->id,
+ ((VerseVert*)efa->v2->vvert)->id,
+ ((VerseVert*)efa->v3->vvert)->id);
+ printf("\tefa->v1,v2,v3,v4->vvert: %p, %p, %p, NULL\n",
+ efa->v1->vvert,
+ efa->v2->vvert,
+ efa->v3->vvert);
+ }
+ printf("\tvface->vvert0, vvvert1, vvvert2, vvvert3: %p, %p, %p, %p\n",
+ vface->vvert0,
+ vface->vvert1,
+ vface->vvert2,
+ vface->vvert3);
+
+ printf("\tefa->v1, v2, v3, v4: %p, %p, %p, %p\n",
+ efa->v1,
+ efa->v2,
+ efa->v3,
+ efa->v4);
+ if(vface->vvert3) {
+ printf("\tvface->v0,v1,v2,v3: %d, %d, %d, %d\n",
+ vface->v0,
+ vface->v1,
+ vface->v2,
+ vface->v3);
+ printf("\tvface->vvert0,vvvert1,vvvert2,vvvert3->vertex: %p, %p, %p, %p\n",
+ vface->vvert0->vertex,
+ vface->vvert1->vertex,
+ vface->vvert2->vertex,
+ vface->vvert3->vertex);
+ }
+ else {
+ printf("\tvface->v0,v1,v2,v3: %d, %d, %d, NULL\n",
+ vface->v0,
+ vface->v1,
+ vface->v2);
+ printf("\tvface->vvert0,vvvert1,vvvert2->vertex: %p, %p, %p, NULL\n",
+ vface->vvert0->vertex,
+ vface->vvert1->vertex,
+ vface->vvert2->vertex);
+ }
+#endif
+
+ /* initialize counter of unreceived vertexes */
+ vface->counter = 4;
+
+ /* 1st vertex */
+ if(vface->vvert0->vertex != efa->v1) {
+ dosend = 1;
+ vface->vvert0->counter--;
+ vface->vvert0 = (VerseVert*)efa->v1->vvert;
+ vface->v0 = vface->vvert0->id;
+ if(vface->vvert0->flag & VERT_RECEIVED)
+ vface->counter--;
+ else
+ vface->flag &= ~FACE_SEND_READY;
+ }
+ else
+ vface->counter--;
+
+ /* 2nd vertex */
+ if(vface->vvert1->vertex != efa->v2) {
+ dosend = 1;
+ vface->vvert1->counter--;
+ vface->vvert1 = (VerseVert*)efa->v2->vvert;
+ vface->v1 = vface->vvert1->id;
+ if(vface->vvert1->flag & VERT_RECEIVED)
+ vface->counter--;
+ else
+ vface->flag &= ~FACE_SEND_READY;
+ }
+ else
+ vface->counter--;
+
+ /* 3th vertex */
+ if(vface->vvert2->vertex != efa->v3) {
+ dosend = 1;
+ vface->vvert2->counter--;
+ vface->vvert2 = (VerseVert*)efa->v3->vvert;
+ vface->v2 = vface->vvert2->id;
+ if(vface->vvert2->flag & VERT_RECEIVED)
+ vface->counter--;
+ else
+ vface->flag &= ~FACE_SEND_READY;
+ }
+ else
+ vface->counter--;
+
+ /* 4th vertex */
+ if(vface->vvert3 && ((vface->vvert3->vertex != efa->v4) || (vface->vvert3 && !efa->v4) || (vface->v3 != vface->vvert3->id))) {
+ dosend = 1;
+ if(efa->v4) {
+ vface->vvert3->counter--;
+ vface->vvert3 = (VerseVert*)efa->v4->vvert;
+ vface->v3 = vface->vvert3->id;
+ if(vface->vvert3->flag & VERT_RECEIVED)
+ vface->counter--;
+ else
+ vface->flag &= ~FACE_SEND_READY;
+ }
+ else {
+ vface->vvert3->counter--;
+ vface->vvert3 = NULL;
+ vface->v3 = -1;
+ vface->counter--;
+ }
+ }
+ /* verse face has 4 vertexes now, not 3 vertexes as in past */
+ else if(!(vface->vvert3) && efa->v4) {
+ dosend = 1;
+ vface->vvert3 = (VerseVert*)efa->v4->vvert;
+ vface->v3 = vface->vvert3->id;
+ if(vface->vvert3->flag & VERT_RECEIVED)
+ vface->counter--;
+ else
+ vface->flag &= ~FACE_SEND_READY;
+ }
+ else
+ vface->counter--;
+
+ if(dosend) {
+ /* printf("\tsending CHANGED FACE\n");
+ printf("\t\tnew: %d %d %d %d\n", vface->v0, vface->v1, vface->v2, vface->v3);*/
+ vface->flag |= FACE_CHANGED;
+ /* remove verse face from list of received faces */
+ BLI_dlist_rem_item(&(vlayer->dl), vface->id);
+ /* and add verse face again to sending queue */
+ add_item_to_send_queue(&(vlayer->queue), (void*)vface, VERSE_FACE);
+ }
+}
+
+/*
+ * this function will sync all VerseFaces with coresponding EditFaces,
+ * this is useful, when some editmesh tool has changed editface pointers at
+ * vertexes (edges), parameter of this function is geometry node
+ */
+void sync_all_versefaces_with_editfaces(VNode *vnode)
+{
+ struct VLayer *vlayer;
+ struct VerseFace *vface, *nvface;
+
+ if(vnode->type != V_NT_GEOMETRY) return;
+
+ vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER);
+
+ /* mark changed verse faces in sending queue as obsolete at the first time */
+ vface = vlayer->queue.first;
+ while(vface) {
+ mark_changed_face_obsolete(vface);
+ vface = vface->next;
+ }
+
+ /* send all received and changed verse face again to verse server */
+ vface = vlayer->dl.lb.first;
+ while(vface) {
+ nvface = vface->next;
+ sync_verseface_with_editface(vlayer, vface);
+ vface = nvface;
+ }
+}
+
+/*
+ * send delete polygon command to verse server
+ */
+void b_verse_send_face_delete(EditFace *efa)
+{
+ ((VerseFace*)efa->vface)->face = NULL;
+ send_verse_face_delete((VerseFace*)efa->vface);
+ efa->vface = NULL;
+}
+
+/*=============================================================================
+ *
+ * functions handling verse/blender VERTEXES
+ *
+ *===========================================================================*/
+
+/*
+ * this function will sync position of all VerseVerts with EditVerts
+ * this function is called after actions: Smooth, Noise and To Sphere,
+ * because position of vertexes isn't managed by transform system
+ */
+void sync_all_verseverts_with_editverts(VNode *vnode)
+{
+ struct VLayer *vlayer;
+ struct VerseVert *vvert;
+
+ if(vnode->type != V_NT_GEOMETRY) return;
+
+ vlayer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER);
+
+ vvert = vlayer->dl.lb.first;
+
+ /* sync all received vertexes */
+ while(vvert) {
+ send_versevert_pos(vvert);
+ vvert = vvert->next;
+ }
+
+ vvert = vlayer->queue.first;
+
+ /* sync all unreceived vertexes (mar pos as obsolete, when
+ * actual position was changed) */
+ while(vvert) {
+ send_versevert_pos(vvert);
+ vvert = vvert->next;
+ }
+
+ verse_callback_update(0);
+}
+
+/*
+ * send delete vertex command to verse server
+ */
+void b_verse_send_vertex_delete(EditVert *eve)
+{
+ ((VerseVert*)eve->vvert)->vertex = NULL;
+ send_verse_vertex_delete((VerseVert*)eve->vvert);
+ eve->vvert = NULL;
+}
+
+/*
+ * send position of verse vertex to verse server
+ */
+void send_versevert_pos(VerseVert *vvert)
+{
+ /* delete command was sent to verse server ... sending one
+ * more position command would create new vertex */
+ if ((vvert->flag & VERT_DELETED) | (vvert->flag & VERT_OBSOLETE)) return;
+
+ /* don't send position of verse vertex to verse server, because it could create
+ * new vertex */
+ if(vvert->flag & VERT_RECEIVED) {
+ if(vvert->flag & VERT_LOCKED) {
+ /* when position of verse vert was sent to verse server
+ * and it wasn't received yet, then mark sent position
+ * as obsolete ... blender will automaticaly send actual
+ * position, when old will be received */
+ vvert->flag |= VERT_POS_OBSOLETE;
+ }
+ else {
+ struct EditVert *eve = (EditVert*)vvert->vertex;
+ /* send position to verse server, when it is different from actual position */
+ if(eve && (eve->co[0]!=vvert->co[0] || eve->co[1]!=vvert->co[1] || eve->co[2]!=vvert->co[2])) {
+ /* lock vertex and send its position to verse server,
+ * locking of vertex prevents from sending too many
+ * informations about vertex position during draging
+ * of vertex */
+ vvert->flag |= VERT_LOCKED;
+ VECCOPY(vvert->co, eve->co);
+ send_verse_vertex(vvert);
+ }
+ }
+ }
+ else {
+ /* we created this vertex and we sent new position to verse server, but "confirmation" command about
+ * position of vertex didn't arrived yet, then we can't send new position of vertex ... we only mark
+ * position of vertex as obsolete and new position will be sent to verse server, when confirmation
+ * command will arive */
+ struct EditVert *eve = (EditVert*)vvert->vertex;
+ if(eve && (eve->co[0]!=vvert->co[0] || eve->co[1]!=vvert->co[1] || eve->co[2]!=vvert->co[2])) {
+ vvert->flag |= VERT_POS_OBSOLETE;
+ }
+ }
+
+ verse_callback_update(0);
+}
+
+/*
+ * create new VerseVert due to information about EditVert,
+ * put VerseVert to queue ... send to verse host (server)
+ */
+void createVerseVert(EditVert *eve)
+{
+ if(G.editMesh->vnode) {
+ struct VLayer *vlayer = find_verse_layer_type((VGeomData*)((VNode*)G.editMesh->vnode)->data, VERTEX_LAYER);
+ createVerseVertNL(eve, (VNode*)G.editMesh->vnode, vlayer);
+ }
+ else eve->vvert = NULL;
+}
+
+/*
+ * create new VerseVert due to information about EditVert,
+ * put VerseVert to queue ... send to verse host (server)
+ * NL version of function (infomration about verse node and
+ * layer is known ... optimalisation)
+ */
+void createVerseVertNL(EditVert *eve, VNode *vnode, VLayer *vlayer)
+{
+ struct VerseVert *vvert;
+
+ vvert = create_verse_vertex(vlayer, vlayer->counter, eve->co[0], eve->co[1], eve->co[2]);
+
+ vvert->vertex = (void*)eve;
+ eve->vvert = (void*)vvert;
+
+ vvert->flag |= VERT_LOCKED;
+
+/* printf("\tsend_versevert_pos: %d create and LOCK \n", vvert->id);*/
+
+ /* add vvert to sending queue */
+ add_item_to_send_queue(&(vlayer->queue), (void*)vvert, VERSE_VERT);
+}
+
+/*
+ * create new verse vertexes due to all vertexes and send all of them to verse server
+ */
+static void createAllVerseVerts(VNode *vnode, VLayer *vlayer)
+{
+ if(G.obedit) {
+ struct EditMesh *em;
+ struct EditVert *eve;
+
+ em = G.editMesh;
+ eve = em->verts.first;
+
+ /* push all EditVertexes to the verse server */
+ while(eve){
+ createVerseVertNL(eve, vnode, vlayer);
+ eve = eve->next;
+ }
+ }
+}
+
+/*
+ * unsubscribe from verse geometry layers of verse geometry node
+ * and clear bindings between verse node and mesh
+ */
+void unsubscribe_from_geom_node(VNode *vnode)
+{
+ struct VerseSession *session = vnode->session;
+
+ struct VLayer *vlayer = ((VGeomData*)vnode->data)->layers.lb.first;
+
+ if(vnode->type != V_NT_GEOMETRY) return;
+
+ /* free bindings between verse node and blender mesh*/
+ if(((VGeomData*)vnode->data)->mesh) {
+ ((Mesh*)((VGeomData*)vnode->data)->mesh)->vnode = NULL;
+ ((VGeomData*)vnode->data)->mesh = NULL;
+ }
+
+ /* free bindings between verse node and blender editmesh */
+ if(((VGeomData*)vnode->data)->editmesh) {
+ ((EditMesh*)((VGeomData*)vnode->data)->editmesh)->vnode = NULL;
+ ((VGeomData*)vnode->data)->editmesh = NULL;
+ }
+
+ /* free all verse layer data and unsubscribe from all layers */
+ while(vlayer) {
+ BLI_dlist_reinit(&(vlayer->dl));
+ BLI_freelistN(&(vlayer->queue));
+ BLI_freelistN(&(vlayer->orphans));
+
+ if(session->flag & VERSE_CONNECTED)
+ verse_send_g_layer_unsubscribe(vnode->id, vlayer->id);
+
+ vlayer = vlayer->next;
+ }
+
+}
+
+/* ===================================================================================
+ *
+ * Function executed after execution of callback functions
+ *
+ * ===================================================================================*/
+
+/*
+ * Actions executed after new VerseLayer is created
+ */
+void post_layer_create(struct VLayer *vlayer)
+{
+ /* if we are owners of VerseNode, then push geometry to verse server */
+ if(vlayer->vnode->owner_id == VN_OWNER_MINE) {
+ switch(vlayer->type){
+ case VN_G_LAYER_VERTEX_XYZ:
+/* if(vlayer->id==0) createAllVerseVerts(vlayer->vnode, vlayer);
+ break;*/
+ case VN_G_LAYER_POLYGON_CORNER_UINT32:
+/* if(vlayer->id==1) createAllVerseFaces(vlayer->vnode, vlayer);
+ break;*/
+ case VN_G_LAYER_VERTEX_UINT32:
+ case VN_G_LAYER_VERTEX_REAL:
+ case VN_G_LAYER_POLYGON_CORNER_REAL:
+ case VN_G_LAYER_POLYGON_FACE_UINT8:
+ case VN_G_LAYER_POLYGON_FACE_UINT32:
+ case VN_G_LAYER_POLYGON_FACE_REAL:
+ break;
+ }
+ }
+ else {
+ switch(vlayer->type) {
+ case VN_G_LAYER_VERTEX_XYZ:
+ case VN_G_LAYER_POLYGON_CORNER_UINT32:
+ case VN_G_LAYER_VERTEX_UINT32:
+ case VN_G_LAYER_VERTEX_REAL:
+ case VN_G_LAYER_POLYGON_CORNER_REAL:
+ case VN_G_LAYER_POLYGON_FACE_UINT8:
+ case VN_G_LAYER_POLYGON_FACE_UINT32:
+ case VN_G_LAYER_POLYGON_FACE_REAL:
+ break;
+ }
+ }
+}
+
+/*
+ * Actions after destroying of VerseLayer
+ */
+void post_layer_destroy(struct VLayer *vlayer)
+{
+}
+
+/*
+ * Actions executed after creating of new VerseVert, when object is in edit
+ * mode, and this client didn't create this VerseVert (vvert->vertex is NULL),
+ * then new editvert is created
+ */
+void post_vertex_create(VerseVert *vvert)
+{
+ struct VNode *obj_vnode;
+ struct VNode *geom_vnode = vvert->vlayer->vnode;
+ struct EditMesh *em=NULL;
+
+ if(G.obedit && (((Mesh*)G.obedit->data)->vnode==geom_vnode)) {
+ em = (EditMesh*)((VGeomData*)geom_vnode->data)->editmesh;
+ }
+
+ /* when vert was changed during sending to verse server, then
+ * we have to send it to verse server again */
+ if(vvert->flag & VERT_POS_OBSOLETE) {
+ vvert->flag &= ~VERT_POS_OBSOLETE;
+
+ if(em && (vvert->vertex)) {
+ struct EditVert *eve = (EditVert*)vvert->vertex;
+ VECCOPY(vvert->co, eve->co);
+ send_verse_vertex(vvert);
+ verse_callback_update(0);
+
+ return;
+ }
+ }
+
+ if(em && !(vvert->vertex)) {
+ struct EditVert *eve;
+
+ /* to prevent never ending loop of sending and receiving
+ * vertexes, because addvertlist() sends new vertex to verse
+ * server if em->vnode isn't NULL */
+ em->vnode = NULL;
+ eve = addvertlist(vvert->co, NULL);
+ em->vnode = (void*)geom_vnode;
+
+ eve->vvert = (void*)vvert;
+ vvert->vertex = (void*)eve;
+
+ countall();
+
+ recalc_editnormals();
+ }
+
+ if(((VGeomData*)geom_vnode->data)->vlink) {
+ obj_vnode = ((VGeomData*)geom_vnode->data)->vlink->source;
+ DAG_object_flush_update(G.scene, (Object*)((VObjectData*)obj_vnode->data)->object, OB_RECALC_DATA);
+
+ allqueue(REDRAWVIEW3D, 1);
+ }
+}
+
+/*
+ * Actions executed, when position of VerseVert was changed
+ * position of EditVert is changed in edit mode
+ */
+void post_vertex_set_xyz(VerseVert *vvert)
+{
+ struct VNode *obj_vnode;
+ struct VNode *geom_vnode = vvert->vlayer->vnode;
+ struct EditVert *eve = NULL;
+
+ /* when vert was changed during sending to verse server, then
+ * we have to send it to verse server again */
+ if(vvert->flag & VERT_POS_OBSOLETE) {
+ if(vvert->vertex) {
+ vvert->flag &= ~VERT_POS_OBSOLETE;
+ vvert->flag |= VERT_LOCKED;
+
+ eve = (EditVert*)vvert->vertex;
+ VECCOPY(vvert->co, eve->co);
+ send_verse_vertex(vvert);
+ verse_callback_update(0);
+ }
+ else {
+ printf("\terror: vvert->vertex shouldn't be NULL\n");
+ }
+
+ return;
+ }
+
+ /* when shared object is in edit mode, then update editmesh */
+ if(G.obedit && (((Mesh*)G.obedit->data)->vnode==geom_vnode)) {
+ if(vvert->vertex) {
+ eve = (EditVert*)vvert->vertex;
+ VECCOPY(eve->co, vvert->co);
+ recalc_editnormals();
+ }
+ else {
+ printf("\terror: vvert->vertex shouldn't be NULL\n");
+ }
+ }
+
+ if(((VGeomData*)geom_vnode->data)->vlink) {
+ obj_vnode = ((VGeomData*)geom_vnode->data)->vlink->source;
+ DAG_object_flush_update(G.scene, (Object*)((VObjectData*)obj_vnode->data)->object, OB_RECALC_DATA);
+
+ allqueue(REDRAWVIEW3D, 1);
+ }
+}
+
+/*
+ * Actions executed after deleting of VerseVert
+ */
+void post_vertex_delete(VerseVert *vvert)
+{
+ struct VNode *obj_vnode;
+ struct VNode *geom_vnode = vvert->vlayer->vnode;
+ struct EditMesh *em = NULL;
+ struct EditEdge *ed, *edn;
+ struct EditVert *eve = NULL;
+
+ if(G.obedit && (((Mesh*)G.obedit->data)->vnode==geom_vnode)) {
+ em = (EditMesh*)((VGeomData*)geom_vnode->data)->editmesh;
+ eve = (EditVert*)vvert->vertex;
+ }
+
+ if(em && eve) {
+ /*printf("\tPOST_VERTEX_DELETE()\n");*/
+
+ /* delete all edges needing eve vertex */
+ ed = em->edges.first;
+ while(ed) {
+ edn = ed->next;
+ if(ed->v1==eve || ed->v2==eve) {
+ remedge(ed);
+ free_editedge(ed);
+ }
+ ed = edn;
+ }
+
+ eve->vvert = NULL;
+ BLI_remlink(&em->verts, eve);
+ free_editvert(eve);
+ vvert->vertex = NULL;
+
+ countall();
+
+ recalc_editnormals();
+ }
+
+ if(((VGeomData*)geom_vnode->data)->vlink) {
+ obj_vnode = ((VGeomData*)geom_vnode->data)->vlink->source;
+ DAG_object_flush_update(G.scene, (Object*)((VObjectData*)obj_vnode->data)->object, OB_RECALC_DATA);
+
+ allqueue(REDRAWVIEW3D, 1);
+ }
+}
+
+/*
+ * free constraint between VerseVert and EditVert
+ */
+void post_vertex_free_constraint(VerseVert *vvert)
+{
+ if(vvert->vertex) {
+ ((EditVert*)vvert->vertex)->vvert=NULL;
+ vvert->vertex=NULL;
+ }
+}
+
+/*
+ * Action executed after setting up uint8 value of polygon
+ */
+void post_polygon_set_uint8(VerseFace *vface)
+{
+}
+
+/*
+ * Action executed after creating of new VerseFace
+ */
+void post_polygon_create(VerseFace *vface)
+{
+ struct VNode *obj_vnode;
+ struct VNode *geom_vnode = vface->vlayer->vnode;
+ struct EditMesh *em = NULL;
+
+ /* if verse face was set as deleted during sending to verse server, then send
+ * delete command to verse server now ... we know verse face id */
+/* if(vface->flag & FACE_DELETED) {
+ send_verse_face_delete(vface);
+ return;
+ }*/
+
+ if(G.obedit && (((Mesh*)G.obedit->data)->vnode==geom_vnode)) {
+ em = (EditMesh*)((VGeomData*)geom_vnode->data)->editmesh;
+ }
+
+ /* when face was changed during sending to verse server, then
+ * we have to send it to verse server again */
+ if(vface->flag & FACE_OBSOLETE) {
+ vface->flag &= ~FACE_OBSOLETE;
+ sync_verseface_with_editface(vface->vlayer, vface);
+ return;
+ }
+
+ if(em && !(vface->face) && (vface->counter==0)) {
+ struct VLayer *vlayer;
+ struct VerseVert *vvert;
+ struct EditFace *efa;
+ struct EditVert *eves[4]={NULL, NULL, NULL, NULL};
+ uint32 vert_ids[4]={vface->v0, vface->v1, vface->v2, vface->v3};
+ int i;
+
+ /*printf("\tPOST_POLYGON_CREATE()\n");*/
+
+ vlayer = find_verse_layer_type((VGeomData*)geom_vnode->data, VERTEX_LAYER);
+
+ for(i=0; i<4; i++) {
+ if(vert_ids[i] != -1) {
+ vvert = BLI_dlist_find_link(&(vlayer->dl), vert_ids[i]);
+ if(vvert) eves[i] = (EditVert*)vvert->vertex;
+ }
+ }
+
+ /* to prevent never ending loop of sending and receiving
+ * faces, because addfacelist() sends new face to verse
+ * server if em->vnode isn't NULL */
+ em->vnode = NULL;
+ efa = addfacelist(eves[0], eves[1], eves[2], eves[3], NULL, NULL);
+ em->vnode = geom_vnode;
+
+ if(efa) {
+ efa->vface = vface;
+ vface->face = efa;
+ }
+
+ countall();
+
+ recalc_editnormals();
+ }
+
+ if(((VGeomData*)geom_vnode->data)->vlink) {
+ obj_vnode = ((VGeomData*)geom_vnode->data)->vlink->source;
+ DAG_object_flush_update(G.scene, (Object*)((VObjectData*)obj_vnode->data)->object, OB_RECALC_DATA);
+
+ allqueue(REDRAWVIEW3D, 1);
+ }
+}
+
+/*
+ * Action executed after changes of VerseFace
+ * ... order of vertexes was fliped, etc.
+ */
+void post_polygon_set_corner(VerseFace *vface)
+{
+ struct VNode *obj_vnode;
+ struct VNode *geom_vnode = vface->vlayer->vnode;
+ struct EditMesh *em = NULL;
+ struct EditFace *efa = NULL;
+ struct EditEdge *eed, *eedn;
+
+ if(G.obedit && (((Mesh*)G.obedit->data)->vnode==geom_vnode)) {
+ em = (EditMesh*)((VGeomData*)geom_vnode->data)->editmesh;
+ efa = (EditFace*)vface->face;
+ }
+
+ if(em && efa) {
+
+ /* when face was changed during sending to verse server, then
+ * we have to send it to verse server again */
+ if(vface->flag & FACE_OBSOLETE) {
+ vface->flag &= ~FACE_OBSOLETE;
+ sync_verseface_with_editface(vface->vlayer, vface);
+ return;
+ }
+
+ /* mark all edges, which are part of face efa */
+ efa->e1->f2 = 1;
+ efa->e2->f2 = 1;
+ efa->e3->f2 = 1;
+ if(efa->e4) efa->e4->f2 = 1;
+
+ /* change pointers at EdtitVerts and decrease counters of "old"
+ * VerseVertexes reference ... less VerseFaces will need them */
+ if(vface->vvert0 != efa->v1->vvert)
+ efa->v1 = (EditVert*)vface->vvert0->vertex;
+ if(vface->vvert1 != efa->v2->vvert)
+ efa->v2 = (EditVert*)vface->vvert1->vertex;
+ if(vface->vvert2 != efa->v3->vvert)
+ efa->v3 = (EditVert*)vface->vvert2->vertex;
+ if(efa->v4) {
+ if(!vface->vvert3)
+ efa->v4 = NULL;
+ else if(vface->vvert3 != efa->v4->vvert)
+ efa->v4 = (EditVert*)vface->vvert3->vertex;
+ }
+
+ /* change pointers at EditEdges */
+
+ /* 1st edge */
+ eed = findedgelist(efa->v1, efa->v2);
+ if(eed) efa->e1 = eed;
+ else efa->e1 = addedgelist(efa->v1, efa->v2, NULL);
+
+ /* 2nd edge */
+ eed = findedgelist(efa->v2, efa->v3);
+ if(eed) efa->e2 = eed;
+ else efa->e2 = addedgelist(efa->v2, efa->v3, NULL);
+
+ if(efa->v4) {
+ /* 3th edge */
+ eed = findedgelist(efa->v2, efa->v3);
+ if(eed) efa->e3 = eed;
+ else efa->e3 = addedgelist(efa->v2, efa->v3, NULL);
+ /* 4th edge */
+ eed = findedgelist(efa->v4, efa->v1);
+ if(eed) efa->e4 = eed;
+ else efa->e4 = addedgelist(efa->v4, efa->v1, NULL);
+ }
+ else {
+ /* 3th edge */
+ eed = findedgelist(efa->v3, efa->v1);
+ if(eed) efa->e3 = eed;
+ else efa->e3 = addedgelist(efa->v3, efa->v1, NULL);
+ /* 4th edge */
+ efa->e4 = NULL;
+ }
+
+ /* unmark needed edges */
+ efa = em->faces.first;
+ while(efa) {
+ efa->e1->f2 = 0;
+ efa->e2->f2 = 0;
+ efa->e3->f2 = 0;
+ if(efa->e4) efa->e4->f2 = 0;
+ efa = efa->next;
+ }
+
+ /* delete all unneeded edges */
+ eed = em->edges.first;
+ while(eed) {
+ eedn = eed->next;
+ if(eed->f2) {
+ remedge(eed);
+ free_editedge(eed);
+ }
+ eed = eedn;
+ }
+
+ countall();
+
+ recalc_editnormals();
+ }
+
+ if(((VGeomData*)geom_vnode->data)->vlink) {
+ obj_vnode = ((VGeomData*)geom_vnode->data)->vlink->source;
+ DAG_object_flush_update(G.scene, (Object*)((VObjectData*)obj_vnode->data)->object, OB_RECALC_DATA);
+
+ allqueue(REDRAWVIEW3D, 1);
+ }
+}
+
+/*
+ * Action executed after deleting of VerseFace
+ */
+void post_polygon_delete(VerseFace *vface)
+{
+ struct VNode *obj_vnode;
+ struct VNode *geom_vnode = vface->vlayer->vnode;
+ struct EditMesh *em = NULL;
+ struct EditFace *efa = NULL;
+ struct EditEdge *eed, *eedn;
+
+ if(G.obedit && (((Mesh*)G.obedit->data)->vnode==geom_vnode)) {
+ em = (EditMesh*)((VGeomData*)geom_vnode->data)->editmesh;
+ efa = (EditFace*)vface->face;
+ }
+
+ if(em && efa) {
+ /*printf("\tPOST_POLYGON_DELETE()\n");*/
+
+ /* mark all edges, which are part of face efa */
+ efa->e1->f2 = 1;
+ efa->e2->f2 = 1;
+ efa->e3->f2 = 1;
+ if(efa->e4) efa->e4->f2 = 1;
+
+ efa->vface = NULL;
+ BLI_remlink(&em->faces, efa);
+ free_editface(efa);
+ vface->face = NULL;
+
+ /* following two crazy loops wouldn't be neccessary if verse spec
+ * would support edges */
+
+ /* unmark needed edges */
+ efa = em->faces.first;
+ while(efa) {
+ efa->e1->f2 = 0;
+ efa->e2->f2 = 0;
+ efa->e3->f2 = 0;
+ if(efa->e4) efa->e4->f2 = 0;
+ efa = efa->next;
+ }
+
+ /* delete all unneeded edges */
+ eed = em->edges.first;
+ while(eed) {
+ eedn = eed->next;
+ if(eed->f2) {
+ remedge(eed);
+ free_editedge(eed);
+ }
+ eed = eedn;
+ }
+
+ countall();
+ }
+
+ if(((VGeomData*)geom_vnode->data)->vlink) {
+ obj_vnode = ((VGeomData*)geom_vnode->data)->vlink->source;
+ DAG_object_flush_update(G.scene, (Object*)((VObjectData*)obj_vnode->data)->object, OB_RECALC_DATA);
+
+ allqueue(REDRAWVIEW3D, 1);
+ }
+}
+
+/*
+ * free constraint between VerseFace and EditFace
+ */
+void post_polygon_free_constraint(VerseFace *vface)
+{
+ if(vface->face) {
+ ((EditFace*)vface->face)->vface = NULL;
+ vface->face = NULL;
+ }
+}
+
+/*
+ * free constraint between VGeomData, EditMesh and Mesh
+ */
+void post_geometry_free_constraint(VNode *vnode)
+{
+ if(((VGeomData*)vnode->data)->editmesh) {
+ G.editMesh->vnode = NULL;
+ ((VGeomData*)vnode->data)->editmesh = NULL;
+ }
+ if(((VGeomData*)vnode->data)->mesh) {
+ ((Mesh*)((VGeomData*)vnode->data)->mesh)->vnode = NULL;
+ ((VGeomData*)vnode->data)->mesh = NULL;
+ }
+}
+
+/* =========================================================================
+ *
+ * Functions influencing whole EditMesh or VerseMesh
+ *
+ * ========================================================================= */
+
+/*
+ * free all bindings between EditMesh and "verse mesh" ... it is called between
+ * restorng editmesh from undo stack
+ */
+void destroy_versemesh(VNode *vnode)
+{
+ struct VLayer *vert_vlayer, *face_vlayer;
+ struct VerseVert *vvert;
+ struct VerseFace *vface;
+
+ if(vnode->type != V_NT_GEOMETRY) return;
+
+ vert_vlayer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER);
+ face_vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER);
+
+
+ /* send delete command to all received verse faces */
+ vface = face_vlayer->dl.lb.first;
+ while(vface) {
+ if(vface->face) ((EditFace*)vface->face)->vface = NULL;
+ vface->face = NULL;
+ send_verse_face_delete(vface);
+ vface = vface->next;
+ }
+ /* send delete command to all verse faces waiting in orphan list */
+ vface = face_vlayer->orphans.first;
+ while(vface) {
+ if(vface->face) ((EditFace*)vface->face)->vface = NULL;
+ vface->face = NULL;
+ send_verse_face_delete(vface);
+ vface = vface->next;
+ }
+ /* mark all verse faces waiting in sending queue as deleted,
+ * send delete command, when this verse face was changed */
+ vface = face_vlayer->queue.first;
+ while(vface) {
+ if(vface->face) ((EditFace*)vface->face)->vface = NULL;
+ vface->face = NULL;
+ if(vface->flag & FACE_CHANGED)
+ send_verse_face_delete(vface);
+ else {
+ vface->flag |= FACE_DELETED;
+ }
+ vface = vface->next;
+ }
+
+ /* send delete command to all received verse vertexes */
+ vvert = vert_vlayer->dl.lb.first;
+ while(vvert) {
+ if(vvert->vertex) ((EditVert*)vvert->vertex)->vvert = NULL;
+ vvert->vertex = NULL;
+ send_verse_vertex_delete(vvert);
+ vvert = vvert->next;
+ }
+ /* mark all verse vertexes waiting in sending queue as deleted
+ * ... verse vertexes will be deleted, when received */
+ vvert = vert_vlayer->queue.first;
+ while(vvert) {
+ if(vvert->vertex) ((EditVert*)vvert->vertex)->vvert = NULL;
+ vvert->vertex = NULL;
+ vvert = vvert->next;
+ }
+}
+
+/*
+ * duplicate geometry verse node, this can be handy, when you duplicate some
+ * object or make object single user
+ */
+VNode *create_geom_vnode_from_geom_vnode(VNode *vnode)
+{
+ struct VNode *n_vnode; /* new verse geometry node */
+ struct VGeomData *geom_data; /* new geometry data */
+ struct VLayer *n_vert_vlayer, *n_face_vlayer; /* new vertex and polygon layer */
+ struct VLayer *vert_vlayer, *face_vlayer;
+ struct VerseVert *n_vvert, *vvert;
+ struct VerseFace *n_vface, *vface;
+ int i;
+
+ if(!vnode) return NULL;
+
+ if(vnode->type != V_NT_GEOMETRY) return NULL;
+
+ /* create new verse node, when no one exist */
+ n_vnode= create_verse_node(vnode->session, -1 , V_NT_GEOMETRY, VN_OWNER_MINE);
+ /* create new geometry data */
+ geom_data = create_geometry_data();
+ n_vnode->data = (void*)geom_data;
+
+ /* set up name of VerseNode */
+ n_vnode->name = (char*)MEM_mallocN(sizeof(char*)*(strlen(vnode->name)-1), "new geom node name");
+ n_vnode->name[0] = '\0';
+ strcat(n_vnode->name, vnode->name);
+
+ /* add node to sending queue */
+ add_item_to_send_queue(&(vnode->session->queue), n_vnode, VERSE_NODE);
+
+ /* create vertex verse layer */
+ n_vert_vlayer = create_verse_layer(n_vnode, 0, "vertex", VN_G_LAYER_VERTEX_XYZ, 0, 0);
+ add_item_to_send_queue(&(geom_data->queue), n_vert_vlayer, VERSE_LAYER);
+
+ /* create polygon verse layer */
+ n_face_vlayer = create_verse_layer(n_vnode, 1, "polygon", VN_G_LAYER_POLYGON_CORNER_UINT32, 0, 0);
+ add_item_to_send_queue(&(geom_data->queue), n_face_vlayer, VERSE_LAYER);
+
+ /* find vertex layer of old verse node */
+ vert_vlayer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER);
+ /* find polygon layer of old verse node */
+ face_vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER);
+
+ /* duplicate verse vertexes */
+ for(i=0, vvert = (VerseVert*)vert_vlayer->dl.lb.first; vvert; vvert = vvert->next, i++) {
+ n_vvert = create_verse_vertex(n_vert_vlayer, i, vvert->co[0], vvert->co[1], vvert->co[2]);
+ vvert->tmp.vvert = n_vvert;
+ add_item_to_send_queue(&(n_vert_vlayer->queue), n_vvert, VERSE_VERT);
+ }
+
+ /* duplicate verse faces (polyons) */
+ for(i=0, vface = (VerseFace*)face_vlayer->dl.lb.first; vface; vface = vface->next, i++) {
+ n_vface = create_verse_face(n_face_vlayer, i, -1, -1, -1, -1);
+ n_vface->vvert0 = vface->vvert0->tmp.vvert;
+ n_vface->vvert1 = vface->vvert1->tmp.vvert;
+ n_vface->vvert2 = vface->vvert2->tmp.vvert;
+ if(vface->vvert3)
+ n_vface->vvert3 = vface->vvert3->tmp.vvert;
+ else
+ n_vface->vvert3 = NULL;
+ add_item_to_send_queue(&(n_face_vlayer->queue), n_vface, VERSE_FACE);
+ }
+
+ return n_vnode;
+}
+
+/*
+ * create new geometry node, make bindings between geometry node and editmesh,
+ * make bindings between editverts and verseverts, make bindings between editfaces
+ * and versefaces
+ */
+VNode *create_geom_vnode_data_from_editmesh(VerseSession *session, EditMesh *em)
+{
+ struct VNode *vnode;
+ struct Mesh *me;
+ struct VGeomData *geom_data;
+ struct VLayer *vert_vlayer, *face_vlayer;
+
+ if(!session) return NULL;
+
+ if(!em) return NULL;
+
+ /* some verse geometry node already exists */
+ if(em->vnode) return NULL;
+
+ /* we will need mesh too (mesh name, creating bindings between verse node, etc.) */
+ me = get_mesh(G.obedit);
+
+ /* create new verse node, when no one exist */
+ vnode = create_verse_node(session, -1 , V_NT_GEOMETRY, VN_OWNER_MINE);
+ /* create new geometry data */
+ geom_data = create_geometry_data();
+ vnode->data = (void*)geom_data;
+
+ /* set up name of VerseNode */
+ vnode->name = (char*)MEM_mallocN(sizeof(char*)*(strlen(me->id.name)-1), "geom node name");
+ vnode->name[0] = '\0';
+ strcat(vnode->name, me->id.name+2);
+
+ /* set up bindings */
+ me->vnode = (void*)vnode;
+ em->vnode = (void*)vnode;
+ geom_data->mesh = (void*)me;
+ geom_data->editmesh = (void*)em;
+
+ /* add node to sending queue */
+ add_item_to_send_queue(&(session->queue), vnode, VERSE_NODE);
+
+ /* create vertex verse layer */
+ vert_vlayer = create_verse_layer(vnode, 0, "vertex", VN_G_LAYER_VERTEX_XYZ, 0, 0);
+ add_item_to_send_queue(&(geom_data->queue), vert_vlayer, VERSE_LAYER);
+
+ /* create polygon verse layer */
+ face_vlayer = create_verse_layer(vnode, 1, "polygon", VN_G_LAYER_POLYGON_CORNER_UINT32, 0, 0);
+ add_item_to_send_queue(&(geom_data->queue), face_vlayer, VERSE_LAYER);
+
+ /* create all verse verts and add them to sending queue */
+ createAllVerseVerts(vnode, vert_vlayer);
+
+ /* create all verse faces and add tehm to sending queue */
+ createAllVerseFaces(vnode, face_vlayer);
+
+ return vnode;
+}
+
+/*
+ * create new geometry node, make bindings between geometry node and mesh and
+ * fill geometry node with new data based at mesh data
+ */
+VNode *create_geom_vnode_data_from_mesh(VerseSession *session, Mesh *me)
+{
+ struct VNode *vnode;
+ struct VGeomData *geom_data;
+ struct VLayer *vert_vlayer, *face_vlayer;
+ struct VerseVert *vvert, **vverts;
+ struct VerseFace *vface;
+ struct MVert *mvert;
+ struct MFace *mface;
+ int i;
+
+ if(!session) return NULL;
+
+ if(!me) return NULL;
+
+ /* some verse geometry node already exists */
+ if(me->vnode) return NULL;
+
+ /* create new verse node, when no one exist */
+ vnode = create_verse_node(session, -1 , V_NT_GEOMETRY, VN_OWNER_MINE);
+ /* create new geometry data */
+ geom_data = create_geometry_data();
+ vnode->data = (void*)geom_data;
+
+ /* set up name of VerseNode */
+ vnode->name = (char*)MEM_mallocN(sizeof(char*)*(strlen(me->id.name)-1), "geom node name");
+ vnode->name[0] = '\0';
+ strcat(vnode->name, me->id.name+2);
+
+ /* set up bindings */
+ me->vnode = (void*)vnode;
+ geom_data->mesh = (void*)me;
+
+ /* add node to sending queue */
+ add_item_to_send_queue(&(session->queue), vnode, VERSE_NODE);
+
+ /* create vertex verse layer */
+ vert_vlayer = create_verse_layer(vnode, 0, "vertex", VN_G_LAYER_VERTEX_XYZ, 0, 0);
+ add_item_to_send_queue(&(geom_data->queue), vert_vlayer, VERSE_LAYER);
+
+ /* create polygon verse layer */
+ face_vlayer = create_verse_layer(vnode, 1, "polygon", VN_G_LAYER_POLYGON_CORNER_UINT32, 0, 0);
+ add_item_to_send_queue(&(geom_data->queue), face_vlayer, VERSE_LAYER);
+
+ /* temporary array of VerseVerts */
+ vverts = (VerseVert**)MEM_mallocN(sizeof(VerseVert*)*me->totvert,"temp array of vverts");
+
+ /* "fill vertex layer with vertexes" and add them to sending queue (send them to verse server) */
+ for(i=0, mvert=me->mvert; i<me->totvert; i++, mvert++) {
+ vverts[i] = vvert = create_verse_vertex(vert_vlayer, i, mvert->co[0], mvert->co[1], mvert->co[2]);
+ add_item_to_send_queue(&(vert_vlayer->queue), vvert, VERSE_VERT);
+ }
+
+ /* "fill face/polygon layer with faces" and them to sending queue */
+ for(i=0, mface = me->mface; i<me->totface; i++, mface++) {
+ if(mface->v4) {
+ vface = create_verse_face(face_vlayer, i, mface->v1, mface->v2, mface->v3, mface->v4);
+ vface->vvert0 = vverts[mface->v1];
+ vface->vvert1 = vverts[mface->v2];
+ vface->vvert2 = vverts[mface->v3];
+ vface->vvert3 = vverts[mface->v4];
+ vface->counter = 4;
+ }
+ else {
+ vface = create_verse_face(face_vlayer, i, mface->v1, mface->v2, mface->v3, -1);
+ vface->vvert0 = vverts[mface->v1];
+ vface->vvert1 = vverts[mface->v2];
+ vface->vvert2 = vverts[mface->v3];
+ vface->counter = 3;
+ }
+ add_item_to_send_queue(&(face_vlayer->queue), vface, VERSE_FACE);
+ }
+
+ MEM_freeN(vverts);
+
+ return vnode;
+}
+
+/*
+ * creates Mesh from verse geometry node and create bindings
+ * between them
+ */
+Mesh *create_mesh_from_geom_node(VNode *vnode)
+{
+ struct Mesh *me;
+
+ if(vnode->type != V_NT_GEOMETRY) return NULL;
+
+ /* add new empty mesh*/
+ me = add_mesh("Mesh");
+ /* set up bindings between mesh and verse node */
+ me->vnode = (void*)vnode;
+ ((VGeomData*)vnode->data)->mesh = (void*)me;
+
+ return me;
+}
+
+/*
+ * create mesh from verse mesh
+ */
+void create_meshdata_from_geom_node(Mesh *me, VNode *vnode)
+{
+ struct VLayer *vert_vlayer, *face_vlayer;
+ struct VerseVert *vvert;
+ struct VerseFace *vface;
+ struct MVert *mvert;
+ struct MFace *mface;
+ struct EdgeHash *edges;
+ int index;
+
+ if(!me || !vnode) return;
+
+ if(vnode->type != V_NT_GEOMETRY) return;
+
+ vert_vlayer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER);
+ face_vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER);
+
+ CustomData_free(&me->vdata, me->totvert);
+ CustomData_free(&me->edata, me->totedge);
+ CustomData_free(&me->fdata, me->totface);
+ mesh_update_customdata_pointers(me);
+
+ if(me->mselect) {
+ MEM_freeN(me->mselect);
+ me->mselect = NULL;
+ }
+
+ me->totvert = vert_vlayer ? vert_vlayer->dl.da.count : 0;
+ me->totface = face_vlayer ? face_vlayer->dl.da.count : 0;
+ me->totselect = 0;
+
+ CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, me->totvert);
+ CustomData_add_layer(&me->fdata, CD_MFACE, CD_CALLOC, NULL, me->totface);
+ mesh_update_customdata_pointers(me);
+
+ mvert = me->mvert;
+ mface = me->mface;
+
+ index = 0;
+ vvert = vert_vlayer ? vert_vlayer->dl.lb.first : NULL;
+ while(vvert) {
+ VECCOPY(mvert->co, vvert->co);
+ VECCOPY(mvert->no, vvert->no);
+ mvert->flag = 0;
+ mvert->mat_nr = 0;
+ vvert->tmp.index = index++;
+ vvert = vvert->next;
+ mvert++;
+ }
+
+ edges = BLI_edgehash_new();
+ vface = face_vlayer ? face_vlayer->dl.lb.first : NULL;
+ while(vface) {
+ mface->v1 = vface->vvert0->tmp.index;
+ mface->v2 = vface->vvert1->tmp.index;
+ mface->v3 = vface->vvert2->tmp.index;
+
+ if(!BLI_edgehash_haskey(edges, mface->v1, mface->v2))
+ BLI_edgehash_insert(edges, mface->v1, mface->v2, NULL);
+ if(!BLI_edgehash_haskey(edges, mface->v2, mface->v3))
+ BLI_edgehash_insert(edges, mface->v2, mface->v3, NULL);
+ if(vface->vvert3) {
+ mface->v4 = vface->vvert3->tmp.index;
+ if(!BLI_edgehash_haskey(edges, mface->v3, mface->v4))
+ BLI_edgehash_insert(edges, mface->v3, mface->v4, NULL);
+ if(!BLI_edgehash_haskey(edges, mface->v4, mface->v1))
+ BLI_edgehash_insert(edges, mface->v4, mface->v1, NULL);
+ } else {
+ mface->v4 = 0;
+ if(!BLI_edgehash_haskey(edges, mface->v3, mface->v1))
+ BLI_edgehash_insert(edges, mface->v3, mface->v1, NULL);
+ }
+
+ mface->flag = 0;
+ mface->pad = 0;
+ mface->mat_nr = 0;
+ mface->edcode = 0;
+
+ /* index 0 isn't allowed at location 3 or 4 */
+ test_index_face(mface, NULL, 0, vface->vvert3?4:3);
+/* printf("\t mface: %d, %d, %d, %d\n", mface->v1, mface->v2, mface->v3, mface->v4);*/
+
+ vface = vface->next;
+ mface++;
+ }
+
+ me->totedge = BLI_edgehash_size(edges);
+
+ if(me->totedge) {
+ EdgeHashIterator *i;
+ MEdge *medge = me->medge = CustomData_add_layer(&me->edata, CD_MEDGE, CD_CALLOC, NULL, me->totedge);
+
+ for(i = BLI_edgehashIterator_new(edges); !BLI_edgehashIterator_isDone(i); BLI_edgehashIterator_step(i), ++medge) {
+ BLI_edgehashIterator_getKey(i, (int*)&medge->v1, (int*)&medge->v2);
+ medge->crease = medge->pad = medge->flag = 0;
+ }
+ BLI_edgehashIterator_free(i);
+ }
+
+ BLI_edgehash_free(edges, NULL);
+
+ mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
+}
+
+/*
+ * Create EditMesh from VerseMesh and keep system in consitant state, this
+ * function is called, when edit mode is entered ... edit mesh is generated
+ * from verse mesh (not from Mesh: (Mesh*)ob->data)
+ */
+void create_edit_mesh_from_geom_node(VNode *vnode)
+{
+ struct VLayer *vert_layer, *face_layer;
+ struct VerseVert *vvert;
+ struct VerseFace *vface;
+ struct Mesh *me;
+ struct EditVert *eve, *eve0, *eve1, *eve2, *eve3;
+ struct EditFace *efa;
+ unsigned int keyindex;
+
+ if(!(G.obedit && G.obedit->type==OB_MESH)) return;
+ me = (Mesh*)G.obedit->data;
+ if(vnode!=(VNode*)me->vnode || vnode->type!=V_NT_GEOMETRY) return;
+
+ vert_layer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER);
+ face_layer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER);
+
+ if(!(vert_layer && face_layer)) return;
+
+ waitcursor(1);
+
+ /* free old editMesh */
+ free_editMesh(G.editMesh);
+
+ G.editMesh->vnode = NULL;
+
+ vvert = vert_layer->dl.lb.first;
+
+ keyindex = 0;
+
+ /* create all EditVerts */
+ while(vvert) {
+ eve = addvertlist(vvert->co, NULL);
+
+ eve->f = 0;
+ eve->h = 0;
+ eve->data = NULL;
+ eve->keyindex = keyindex;
+ eve->vvert = (void*)vvert;
+
+ vvert->vertex = (void*)eve;
+
+ keyindex++;
+ vvert = vvert->next;
+ }
+
+ vface = face_layer->dl.lb.first;
+
+ /* create all EditFaces and EditEdges */
+ while(vface) {
+ if(vface->vvert0) eve0= vface->vvert0->vertex;
+ else eve0 = NULL;
+ if(vface->vvert1) eve1= vface->vvert1->vertex;
+ else eve1 = NULL;
+ if(vface->vvert2) eve2= vface->vvert2->vertex;
+ else eve2 = NULL;
+ if(vface->vvert3) eve3= vface->vvert3->vertex;
+ else eve3 = NULL;
+
+ efa= addfacelist(eve0, eve1, eve2, eve3, NULL, NULL);
+ if(efa) {
+ efa->f = 0;
+ efa->h = 0;
+ efa->vface = (void*)vface;
+ vface->face = (void*)efa;
+ }
+ vface = vface->next;
+ }
+
+ countall();
+
+ recalc_editnormals();
+
+ G.editMesh->vnode = (void*)vnode;
+ ((VGeomData*)vnode->data)->editmesh = (void*)G.editMesh;
+
+ waitcursor(0);
+}
+
+/*
+ * destroy bindings between EditMesh and VerseMesh and send delete commands
+ * for all VerseVerts and VerseFaces to verse server, Verse Node has to be
+ * geometry node
+ */
+
+void destroy_verse_mesh(VNode *vnode)
+{
+ struct VLayer *vert_vlayer, *face_vlayer;
+ struct VerseFace *vface;
+ struct VerseVert *vvert;
+
+ if(vnode->type != V_NT_GEOMETRY) return;
+
+ face_vlayer = find_verse_layer_type((VGeomData*)vnode->data, POLYGON_LAYER);
+ vface = face_vlayer->dl.lb.first;
+
+ while(vface) {
+ ((EditFace*)vface->face)->vface = NULL;
+ vface->face = NULL;
+ vface = vface->next;
+ }
+
+ vert_vlayer = find_verse_layer_type((VGeomData*)vnode->data, VERTEX_LAYER);
+ vvert = vert_vlayer->dl.lb.first;
+
+ while(vvert) {
+ ((EditVert*)vvert->vertex)->vvert = NULL;
+ vvert->vertex = NULL;
+ vvert = vvert->next;
+ }
+
+ destroy_geometry(vnode);
+}
+
+#endif
+
diff --git a/source/blender/src/verse_object.c b/source/blender/src/verse_object.c
new file mode 100644
index 00000000000..fc937469d42
--- /dev/null
+++ b/source/blender/src/verse_object.c
@@ -0,0 +1,600 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Contributor(s): Jiri Hnidek.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifdef WITH_VERSE
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "mydevice.h"
+
+#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_image_types.h"
+#include "DNA_listBase.h"
+
+#include "BLI_dynamiclist.h"
+#include "BLI_blenlib.h"
+#include "BLI_editVert.h"
+#include "BLI_arithb.h"
+
+#include "BIF_verse.h"
+#include "BIF_space.h"
+#include "BIF_editmesh.h"
+#include "BIF_drawimage.h"
+#include "BIF_editmode_undo.h"
+#include "BIF_toolbox.h"
+
+#include "BKE_verse.h"
+#include "BKE_global.h"
+#include "BKE_object.h"
+#include "BKE_utildefines.h"
+#include "BKE_depsgraph.h"
+#include "BKE_image.h"
+#include "BKE_library.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_mesh.h"
+#include "BKE_displist.h"
+
+#include "BDR_editobject.h"
+
+#include "verse.h"
+
+/* button callback function, it test object name and send new name to verse server */
+void test_and_send_idbutton_cb(void *obj, void *ob_name)
+{
+ struct Object *ob = (Object*)obj;
+ char *name= (char*)ob_name;
+
+ test_idbutton(name+2);
+
+ if(ob->vnode) verse_send_node_name_set(((VNode*)ob->vnode)->id, name+2);
+}
+
+/*
+ * duplicate verse object nodes
+ */
+void b_verse_duplicate_object(VerseSession *session, Object *ob, Object *n_ob)
+{
+ struct VNode *obj_vnode;
+
+ if(!session) return;
+
+ if(!(session->flag & VERSE_CONNECTED)) return;
+
+ /* create "my" new object VerseNode */
+ obj_vnode= create_verse_node(session, -1 , V_NT_OBJECT, VN_OWNER_MINE);
+ /* create object data */
+ obj_vnode->data = create_object_data();
+
+ /* set up name of VerseNode */
+ obj_vnode->name = (char*)MEM_mallocN(sizeof(char*)*(strlen(n_ob->id.name)-1), "object node name");
+ obj_vnode->name[0] = '\0';
+ strcat(obj_vnode->name, n_ob->id.name+2);
+
+ /* set up object node transformation */
+ VECCOPY(((VObjectData*)obj_vnode->data)->pos, n_ob->loc);
+ EulToQuat(n_ob->rot, ((VObjectData*)obj_vnode->data)->quat);
+ VECCOPY(((VObjectData*)obj_vnode->data)->scale, n_ob->size);
+
+ /* set up pointers between Object and VerseNode */
+ ((VObjectData*)obj_vnode->data)->object = (void*)n_ob;
+ n_ob->vnode = (void*)obj_vnode;
+
+ /* add node to sending queue */
+ add_item_to_send_queue(&(session->queue), obj_vnode, VERSE_NODE);
+
+ if(ob->type==OB_MESH) {
+ struct Mesh *me;
+ struct VNode *geom_vnode;
+ struct VLink *vlink;
+
+ /* when current mesh already shared at verse server, then only set up link
+ * between object node and geometry node */
+ if(ob->data == n_ob->data) {
+ geom_vnode = (VNode*)((Mesh*)ob->data)->vnode;
+ }
+ else {
+ geom_vnode = create_geom_vnode_from_geom_vnode((VNode*)((Mesh*)ob->data)->vnode);
+ me = (Mesh*)n_ob->data;
+ me->vnode = (void*)geom_vnode;
+ ((VGeomData*)geom_vnode->data)->mesh = (void*)me;
+
+ }
+ /* create new link between VereseNodes */
+ vlink = create_verse_link(session, obj_vnode, geom_vnode, -1, -1, "geometry");
+ /* "send" link to verse server */
+ add_item_to_send_queue(&(((VObjectData*)obj_vnode->data)->queue), vlink, VERSE_LINK);
+ }
+}
+
+/*
+ * temp hack: this function push mesh objects (edit mode only) to verse server
+ */
+void b_verse_push_object(VerseSession *session, Object *ob)
+{
+ struct VNode *obj_vnode;
+
+ if(!session) return;
+
+ if(!(session->flag & VERSE_CONNECTED)) return;
+
+ /* create "my" new object VerseNode */
+ obj_vnode= create_verse_node(session, -1 , V_NT_OBJECT, VN_OWNER_MINE);
+ /* create object data */
+ obj_vnode->data = create_object_data();
+
+ /* set up name of VerseNode */
+ obj_vnode->name = (char*)MEM_mallocN(sizeof(char*)*(strlen(ob->id.name)-1), "object node name");
+ obj_vnode->name[0] = '\0';
+ strcat(obj_vnode->name, ob->id.name+2);
+
+ /* set up object node transformation */
+ VECCOPY(((VObjectData*)obj_vnode->data)->pos, ob->loc);
+ EulToQuat(ob->rot, ((VObjectData*)obj_vnode->data)->quat);
+ VECCOPY(((VObjectData*)obj_vnode->data)->scale, ob->size);
+
+ /* set up pointers between Object and VerseNode */
+ ((VObjectData*)obj_vnode->data)->object = (void*)ob;
+ ob->vnode = (void*)obj_vnode;
+
+ /* add node to sending queue */
+ add_item_to_send_queue(&(session->queue), obj_vnode, VERSE_NODE);
+
+ if(ob->type==OB_MESH) {
+ struct VNode *geom_vnode;
+ struct VLink *vlink;
+
+ if(G.obedit)
+ geom_vnode = create_geom_vnode_data_from_editmesh(session, G.editMesh);
+ else
+ geom_vnode = create_geom_vnode_data_from_mesh(session, get_mesh(ob));
+
+ if(geom_vnode) {
+ /* create new link between VereseNodes */
+ vlink = create_verse_link(session, obj_vnode, geom_vnode, -1, -1, "geometry");
+ /* send link to verse server */
+ add_item_to_send_queue(&(((VObjectData*)obj_vnode->data)->queue), vlink, VERSE_LINK);
+ }
+ }
+}
+
+/*
+ * creates blender object from verse object node and it
+ * will create links between them
+ */
+Object *create_object_from_verse_node(VNode *vnode)
+{
+ struct Object *ob;
+
+ if(vnode->type != V_NT_OBJECT) return NULL;
+
+ /* create new object*/
+ ob = add_object(OB_MESH);
+ /* set up bindings between verse node and blender object */
+ ob->vnode = (void*)vnode;
+ ((VObjectData*)vnode->data)->object = (void*)ob;
+ /* set up flags */
+ ((VObjectData*)vnode->data)->flag |= POS_RECEIVE_READY;
+ ((VObjectData*)vnode->data)->flag |= ROT_RECEIVE_READY;
+ ((VObjectData*)vnode->data)->flag |= SCALE_RECEIVE_READY;
+ /* copy name from verse node to object */
+ if(vnode->name) {
+ char *str;
+ str = (char*)MEM_mallocN(sizeof(char)*(strlen(vnode->name)+3), "temp object name");
+ str[0] = '\0';
+ strcat(str, "OB");
+ strcat(str, vnode->name);
+ strncpy(ob->id.name, str, 23);
+ MEM_freeN(str);
+ }
+ /* subscribe for object transformation */
+ verse_send_o_transform_subscribe(vnode->id, 0);
+
+ return ob;
+}
+
+/*
+ * Create blender object-mesh from verse object node, verse geometry node,
+ */
+void b_verse_pop_node(VNode *vnode)
+{
+ if((!vnode) || (!(vnode->data))) return;
+
+ if(vnode->type==V_NT_OBJECT) {
+ struct VNode *geom_node=NULL;
+ struct VLink *vlink;
+ struct VLayer *vlayer;
+ struct Object *ob;
+ struct Mesh *me;
+
+ if(((VObjectData*)vnode->data)->object) {
+ printf("\tError: already subscribed to object node.\n");
+ return;
+ }
+
+ vlink = ((VObjectData*)vnode->data)->links.lb.first;
+
+ /* try to find geometry node */
+ while(vlink) {
+ if(vlink->target && vlink->target->type==V_NT_GEOMETRY){
+ geom_node = vlink->target;
+ break;
+ }
+ vlink = vlink->next;
+ }
+
+ /* we are not interested now in avatars node, etc. (vnodes without
+ * links at geometry node) */
+ if(!geom_node) return;
+
+ /* subscribe to all verse geometry layer */
+ vlayer = ((VGeomData*)geom_node->data)->layers.lb.first;
+ while(vlayer) {
+ verse_send_g_layer_subscribe(geom_node->id, vlayer->id, 0);
+ vlayer = vlayer->next;
+ }
+
+ ob = create_object_from_verse_node(vnode);
+
+ me = create_mesh_from_geom_node(geom_node);
+
+ /* set up bindings between object and mesh */
+ if(ob && me) ob->data = me;
+ }
+ else if(vnode->type==V_NT_BITMAP) {
+ struct VBitmapData *vbitmap;
+ struct VBitmapLayer *vblayer;
+ float color[] = {0, 0, 0, 1};
+
+ vbitmap = (VBitmapData*)vnode->data;
+
+ vblayer = vbitmap->layers.lb.first;
+
+ while(vblayer) {
+ if(!(vblayer->flag & VBLAYER_SUBSCRIBED)) {
+ /* 0 means level of subscription (full resolution) */
+ verse_send_b_layer_subscribe(vnode->id, vblayer->id, 0);
+ vblayer->flag |= VBLAYER_SUBSCRIBED;
+ }
+ vblayer = vblayer->next;
+ }
+
+ if(vbitmap->image) {
+ printf("\tError: already subscribed to image node.\n");
+ return;
+ }
+
+ vbitmap->image = (void*)BKE_add_image_size(
+ vbitmap->width,
+ vbitmap->height,
+ vnode->name,
+ 0,
+ color);
+ ((Image*)vbitmap->image)->vnode = (void*)vnode;
+ sync_blender_image_with_verse_bitmap_node(vnode);
+
+ allqueue(REDRAWIMAGE, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ }
+}
+
+/*
+ * this function will unsubscribe object node from transformation, but it will
+ * keep all tags and links at other nodes ... user could subscribe to this node
+ * again in future
+ */
+void unsubscribe_from_obj_node(VNode *vnode)
+{
+ struct VerseSession *session = vnode->session;
+ struct VLink *vlink;
+
+ if(vnode->type != V_NT_OBJECT) return;
+
+ /* unsubscribe from receiving changes of transformation matrix */
+ if(session->flag & VERSE_CONNECTED)
+ verse_send_o_transform_unsubscribe(vnode->id, 0);
+
+ /* we have to reinitialize object node transformation */
+ ((VObjectData*)vnode->data)->pos[0] = 0.0f;
+ ((VObjectData*)vnode->data)->pos[1] = 0.0f;
+ ((VObjectData*)vnode->data)->pos[2] = 0.0f;
+
+ ((VObjectData*)vnode->data)->quat[0] = 0.0f;
+ ((VObjectData*)vnode->data)->quat[1] = 0.0f;
+ ((VObjectData*)vnode->data)->quat[2] = 0.0f;
+ ((VObjectData*)vnode->data)->quat[3] = 0.0f;
+
+ ((VObjectData*)vnode->data)->scale[0] = 0.0f;
+ ((VObjectData*)vnode->data)->scale[1] = 0.0f;
+ ((VObjectData*)vnode->data)->scale[2] = 0.0f;
+
+ /* clear bindings between object and object node */
+ if(((VObjectData*)vnode->data)->object) {
+ ((Object*)((VObjectData*)vnode->data)->object)->vnode = NULL;
+ ((VObjectData*)vnode->data)->object = NULL;
+ }
+
+ /* unsubscribe from all supported verse nodes */
+ vlink = ((VObjectData*)vnode->data)->links.lb.first;
+ while(vlink) {
+ if(vlink->target->counter==1) {
+ switch(vlink->target->type) {
+ case V_NT_OBJECT:
+ unsubscribe_from_obj_node(vlink->target);
+ break;
+ case V_NT_GEOMETRY:
+ unsubscribe_from_geom_node(vlink->target);
+ break;
+ case V_NT_BITMAP:
+ unsubscribe_from_bitmap_node(vlink->target);
+ break;
+ default:
+ break;
+ }
+ }
+ vlink = vlink->next;
+ }
+}
+
+/*
+ * when blender Object is deleted, then we have to unsubscribe and free all
+ * VerseNode dependent on this object
+ */
+void b_verse_delete_object(Object *object)
+{
+ struct VNode *vnode;
+
+ vnode = (VNode*)object->vnode;
+
+ if(vnode) unsubscribe_from_obj_node(vnode);
+}
+
+/*
+ * "fake" unsubscribing from object node and all child nodes
+ */
+void b_verse_unsubscribe(VNode *vnode)
+{
+ struct VLink *vlink = ((VObjectData*)vnode->data)->links.lb.first;
+ struct Object *ob = (Object*)((VObjectData*)vnode->data)->object;
+
+ if(vnode->type==V_NT_OBJECT) {
+ /* exit edit mode */
+ if(G.obedit && G.obedit->vnode == (void*)vnode)
+ exit_editmode(EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR);
+
+ /* when some geometry node is child of this object node, then create mesh data */
+ while(vlink){
+ if(vlink->target->type == V_NT_GEOMETRY) {
+ struct Mesh *me;
+ me = ((VGeomData*)vlink->target->data)->mesh;
+ create_meshdata_from_geom_node(me, vlink->target);
+ break;
+ }
+ vlink = vlink->next;
+ }
+
+ /* unsubscribe from object transformation and clear bindings between
+ * verse object node and object */
+ unsubscribe_from_obj_node(vnode);
+
+ /* when geometry node was shared with more object nodes, then make
+ * data single user */
+ if(ob->type == OB_MESH) {
+ struct ID *id = ob->data;
+ if(id && id->us>1 && id->lib==0) {
+ ob->recalc= OB_RECALC_DATA;
+ ob->data = copy_mesh(ob->data);
+ id->us--;
+ id->newid= ob->data;
+ }
+ }
+
+ /* reinitialize object derived mesh */
+ makeDerivedMesh(ob, get_viewedit_datamask());
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ }
+ else if(vnode->type==V_NT_BITMAP) {
+ /* fake ... it isn't impelemented yet ... poke jiri, when needed */
+ unsubscribe_from_bitmap_node(vnode);
+ }
+
+ allqueue(REDRAWVIEW3D, 1);
+}
+
+/*
+ * whe VerseLink is created between two nodes, the Object start to point at
+ * coresponding data
+ */
+void post_link_set(VLink *vlink)
+{
+ struct VNode *target, *source;
+ struct Object *ob=NULL;
+ struct Mesh *me=NULL;
+
+ source = vlink->source;
+ target = vlink->target;
+
+ if(source->type==V_NT_OBJECT && target->type==V_NT_GEOMETRY){
+ if(((VObjectData*)source->data)->object)
+ ob = (Object*)((VObjectData*)source->data)->object;
+ if(((VGeomData*)target->data)->mesh)
+ me = (Mesh*)((VGeomData*)target->data)->mesh;
+ if(ob && me && ob->data!=me) {
+ ob->data = me;
+ makeDerivedMesh(ob, get_viewedit_datamask());
+ }
+ }
+
+ allqueue(REDRAWALL, 1);
+}
+
+/*
+ * when VerseLink is deleted, then bindings between Object and data should be removed
+ */
+void post_link_destroy(VLink *vlink)
+{
+ struct VNode *source, *target;
+ struct Object *ob;
+
+ source = vlink->source;
+ target = vlink->target;
+
+ if(source->type==V_NT_OBJECT && target->type==V_NT_GEOMETRY) {
+ if(((VObjectData*)source->data)->object) {
+ ob = (Object*)((VObjectData*)source->data)->object;
+ ob->data=NULL;
+ }
+ }
+
+ allqueue(REDRAWALL, 1);
+}
+
+/*
+ * update position of blender object
+ */
+void post_transform_pos(VNode *vnode)
+{
+ struct VObjectData *obj_data = (VObjectData*)vnode->data;
+ struct Object *ob = (Object*)obj_data->object;
+
+ VECCOPY(ob->loc, obj_data->pos);
+
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_OB);
+
+ allqueue(REDRAWVIEW3D, 1);
+}
+
+/*
+ * update rotation of blender object
+ */
+void post_transform_rot(VNode *vnode)
+{
+ struct VObjectData *obj_data = (VObjectData*)vnode->data;
+ struct Object *ob = (Object*)obj_data->object;
+
+ /* convert quaternion to euler rotation */
+ QuatToEul(obj_data->quat, ob->rot);
+
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_OB);
+
+ allqueue(REDRAWVIEW3D, 1);
+}
+
+/*
+ * update scale of blender object
+ */
+void post_transform_scale(VNode *vnode)
+{
+ struct VObjectData *obj_data = (VObjectData*)vnode->data;
+ struct Object *ob = (Object*)obj_data->object;
+
+ VECCOPY(ob->size, obj_data->scale);
+
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_OB);
+
+ allqueue(REDRAWVIEW3D, 1);
+}
+
+/*
+ * send transformation of Object to verse server
+ */
+void b_verse_send_transformation(Object *ob)
+{
+ struct VNode *vnode= ob->vnode;
+ float quat[4];
+
+ if(!vnode) return;
+
+ /* if last sent position wasn't received yet, then next change of position
+ * can't be send until last send change is received */
+ if( ((VObjectData*)vnode->data)->flag & POS_SEND_READY ) {
+ if((((VObjectData*)vnode->data)->pos[0]!=ob->loc[0]) ||
+ (((VObjectData*)vnode->data)->pos[1]!=ob->loc[1]) ||
+ (((VObjectData*)vnode->data)->pos[2]!=ob->loc[2])) {
+ VECCOPY(((VObjectData*)vnode->data)->pos, ob->loc);
+ send_verse_object_position(vnode);
+ }
+ }
+
+ /* if last sent rotation wasn't received yet, then next change of rotation
+ * can't be send until last send change is received */
+ if( ((VObjectData*)vnode->data)->flag & ROT_SEND_READY ) {
+ EulToQuat(ob->rot, quat);
+
+ if((((VObjectData*)vnode->data)->quat[0] != quat[0]) ||
+ (((VObjectData*)vnode->data)->quat[1] != quat[1]) ||
+ (((VObjectData*)vnode->data)->quat[2] != quat[2]) ||
+ (((VObjectData*)vnode->data)->quat[3] != quat[3])) {
+ QUATCOPY(((VObjectData*)vnode->data)->quat, quat);
+ send_verse_object_rotation(vnode);
+ }
+ }
+
+ /* if last sent object size wasn't received yet, then next change of object size
+ * can't be send until last send change is received */
+ if( ((VObjectData*)vnode->data)->flag & SCALE_SEND_READY ) {
+ if((((VObjectData*)vnode->data)->scale[0]!=ob->size[0]) ||
+ (((VObjectData*)vnode->data)->scale[1]!=ob->size[1]) ||
+ (((VObjectData*)vnode->data)->scale[2]!=ob->size[2])) {
+ VECCOPY(((VObjectData*)vnode->data)->scale, ob->size);
+ send_verse_object_scale(vnode);
+ }
+ }
+
+ verse_callback_update(0);
+}
+
+/*
+ * free constraint between object VerseNode and blender Object
+ */
+void post_object_free_constraint(VNode *vnode)
+{
+ if(((VObjectData*)vnode->data)->object) {
+ /* free pointer at verse derived mesh */
+ struct Object *ob = (Object*)((VObjectData*)vnode->data)->object;
+ if(ob) {
+ if(ob->derivedFinal) {
+ ob->derivedFinal->needsFree = 1;
+ ob->derivedFinal->release((DerivedMesh*)ob->derivedFinal);
+ ob->derivedFinal = NULL;
+ }
+ if(ob->derivedDeform) {
+ ob->derivedDeform->needsFree = 1;
+ ob->derivedDeform->release((DerivedMesh*)ob->derivedDeform);
+ ob->derivedDeform = NULL;
+ }
+ }
+ /* free constraint */
+ ((Object*)((VObjectData*)vnode->data)->object)->vnode = NULL;
+ ((VObjectData*)vnode->data)->object = NULL;
+ }
+}
+
+#endif
+
diff --git a/source/blender/src/view.c b/source/blender/src/view.c
new file mode 100644
index 00000000000..4ddd6d71dea
--- /dev/null
+++ b/source/blender/src/view.c
@@ -0,0 +1,1867 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Trackball math (in calctrackballvec()) Copyright (C) Silicon Graphics, Inc.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <math.h>
+#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef WIN32
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "DNA_action_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_action.h"
+#include "BKE_anim.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_object.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_gl.h"
+#include "BIF_space.h"
+#include "BIF_mywindow.h"
+#include "BIF_previewrender.h"
+#include "BIF_retopo.h"
+#include "BIF_screen.h"
+#include "BIF_toolbox.h"
+
+#include "BSE_view.h"
+#include "BSE_edit.h" /* For countall */
+#include "BSE_drawview.h" /* For inner_play_anim_loop */
+
+#include "BDR_drawobject.h" /* For draw_object */
+#include "BDR_editface.h" /* For minmax_tface */
+#include "BDR_sculptmode.h"
+
+#include "mydevice.h"
+#include "blendef.h"
+
+#include "PIL_time.h" /* smoothview */
+
+#define TRACKBALLSIZE (1.1)
+#define BL_NEAR_CLIP 0.001
+
+
+/* local prototypes ----------*/
+void setcameratoview3d(void); /* windows.c & toets.c */
+
+void persp_general(int a)
+{
+ /* for all window types, not 3D */
+
+ if(a== 0) {
+ glPushMatrix();
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glMatrixMode(GL_MODELVIEW);
+
+ myortho2(-0.375, ((float)(curarea->winx))-0.375, -0.375, ((float)(curarea->winy))-0.375);
+ glLoadIdentity();
+ }
+ else if(a== 1) {
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+ }
+}
+
+void persp(int a)
+{
+ /* only 3D windows */
+
+ if(curarea->spacetype!=SPACE_VIEW3D) persp_general(a);
+ else if(a == PERSP_STORE) { // only store
+ glMatrixMode(GL_PROJECTION);
+ mygetmatrix(G.vd->winmat1);
+ glMatrixMode(GL_MODELVIEW);
+ mygetmatrix(G.vd->viewmat1);
+ }
+ else if(a== PERSP_WIN) { // only set
+ myortho2(-0.375, (float)(curarea->winx)-0.375, -0.375, (float)(curarea->winy)-0.375);
+ glLoadIdentity();
+ }
+ else if(a== PERSP_VIEW) {
+ glMatrixMode(GL_PROJECTION);
+ myloadmatrix(G.vd->winmat1); // put back
+ Mat4CpyMat4(curarea->winmat, G.vd->winmat1); // to be sure?
+ glMatrixMode(GL_MODELVIEW);
+ myloadmatrix(G.vd->viewmat); // put back
+
+ }
+}
+
+
+void initgrabz(float x, float y, float z)
+{
+ if(G.vd==NULL) return;
+ G.vd->zfac= G.vd->persmat[0][3]*x+ G.vd->persmat[1][3]*y+ G.vd->persmat[2][3]*z+ G.vd->persmat[3][3];
+
+ /* if x,y,z is exactly the viewport offset, zfac is 0 and we don't want that
+ * (accounting for near zero values)
+ * */
+ if (G.vd->zfac < 1.e-6f && G.vd->zfac > -1.e-6f) G.vd->zfac = 1.0f;
+
+ /* Negative zfac means x, y, z was behind the camera (in perspective).
+ * This gives flipped directions, so revert back to ok default case.
+ */
+ if (G.vd->zfac < 0.0f) G.vd->zfac = 1.0f;
+}
+
+void window_to_3d(float *vec, short mx, short my)
+{
+ /* always call initgrabz */
+ float dx, dy;
+
+ dx= 2.0f*mx*G.vd->zfac/curarea->winx;
+ dy= 2.0f*my*G.vd->zfac/curarea->winy;
+
+ vec[0]= (G.vd->persinv[0][0]*dx + G.vd->persinv[1][0]*dy);
+ vec[1]= (G.vd->persinv[0][1]*dx + G.vd->persinv[1][1]*dy);
+ vec[2]= (G.vd->persinv[0][2]*dx + G.vd->persinv[1][2]*dy);
+}
+
+void project_short(float *vec, short *adr) /* clips */
+{
+ float fx, fy, vec4[4];
+
+ adr[0]= IS_CLIPPED;
+
+ if(G.vd->flag & V3D_CLIPPING) {
+ if(view3d_test_clipping(G.vd, vec))
+ return;
+ }
+
+ VECCOPY(vec4, vec);
+ vec4[3]= 1.0;
+ Mat4MulVec4fl(G.vd->persmat, vec4);
+
+ if( vec4[3]>BL_NEAR_CLIP ) { /* 0.001 is the NEAR clipping cutoff for picking */
+ fx= (curarea->winx/2)*(1 + vec4[0]/vec4[3]);
+
+ if( fx>0 && fx<curarea->winx) {
+
+ fy= (curarea->winy/2)*(1 + vec4[1]/vec4[3]);
+
+ if(fy>0.0 && fy< (float)curarea->winy) {
+ adr[0]= floor(fx);
+ adr[1]= floor(fy);
+ }
+ }
+ }
+}
+
+void project_int(float *vec, int *adr)
+{
+ float fx, fy, vec4[4];
+
+ adr[0]= 2140000000.0f;
+ VECCOPY(vec4, vec);
+ vec4[3]= 1.0;
+
+ Mat4MulVec4fl(G.vd->persmat, vec4);
+
+ if( vec4[3]>BL_NEAR_CLIP ) { /* 0.001 is the NEAR clipping cutoff for picking */
+ fx= (curarea->winx/2)*(1 + vec4[0]/vec4[3]);
+
+ if( fx>-2140000000.0f && fx<2140000000.0f) {
+ fy= (curarea->winy/2)*(1 + vec4[1]/vec4[3]);
+
+ if(fy>-2140000000.0f && fy<2140000000.0f) {
+ adr[0]= floor(fx);
+ adr[1]= floor(fy);
+ }
+ }
+ }
+}
+
+void project_short_noclip(float *vec, short *adr)
+{
+ float fx, fy, vec4[4];
+
+ adr[0]= IS_CLIPPED;
+ VECCOPY(vec4, vec);
+ vec4[3]= 1.0;
+
+ Mat4MulVec4fl(G.vd->persmat, vec4);
+
+ if( vec4[3]>BL_NEAR_CLIP ) { /* 0.001 is the NEAR clipping cutoff for picking */
+ fx= (curarea->winx/2)*(1 + vec4[0]/vec4[3]);
+
+ if( fx>-32700 && fx<32700) {
+
+ fy= (curarea->winy/2)*(1 + vec4[1]/vec4[3]);
+
+ if(fy>-32700.0 && fy<32700.0) {
+ adr[0]= floor(fx);
+ adr[1]= floor(fy);
+ }
+ }
+ }
+}
+
+void project_float(float *vec, float *adr)
+{
+ float vec4[4];
+
+ adr[0]= IS_CLIPPED;
+ VECCOPY(vec4, vec);
+ vec4[3]= 1.0;
+
+ Mat4MulVec4fl(G.vd->persmat, vec4);
+
+ if( vec4[3]>BL_NEAR_CLIP ) {
+ adr[0]= (curarea->winx/2.0)+(curarea->winx/2.0)*vec4[0]/vec4[3];
+ adr[1]= (curarea->winy/2.0)+(curarea->winy/2.0)*vec4[1]/vec4[3];
+ }
+}
+
+void view3d_get_object_project_mat(ScrArea *area, Object *ob, float pmat[4][4], float vmat[4][4])
+{
+ if (area->spacetype!=SPACE_VIEW3D || !area->spacedata.first) {
+ Mat4One(pmat);
+ Mat4One(vmat);
+ } else {
+ View3D *vd = area->spacedata.first;
+
+ Mat4MulMat4(vmat, ob->obmat, vd->viewmat);
+ Mat4MulMat4(pmat, vmat, vd->winmat1);
+ Mat4CpyMat4(vmat, ob->obmat);
+ }
+}
+
+/* projectmat brings it to window coords, wmat to rotated world space */
+void view3d_project_short_clip(ScrArea *area, float *vec, short *adr, float projmat[4][4], float wmat[4][4])
+{
+ View3D *v3d= area->spacedata.first;
+ float fx, fy, vec4[4];
+
+ adr[0]= IS_CLIPPED;
+
+ /* clipplanes in eye space */
+ if(v3d->flag & V3D_CLIPPING) {
+ VECCOPY(vec4, vec);
+ Mat4MulVecfl(wmat, vec4);
+ if(view3d_test_clipping(v3d, vec4))
+ return;
+ }
+
+ VECCOPY(vec4, vec);
+ vec4[3]= 1.0;
+
+ Mat4MulVec4fl(projmat, vec4);
+
+ /* clipplanes in window space */
+ if( vec4[3]>BL_NEAR_CLIP ) { /* 0.001 is the NEAR clipping cutoff for picking */
+ fx= (area->winx/2)*(1 + vec4[0]/vec4[3]);
+
+ if( fx>0 && fx<area->winx) {
+
+ fy= (area->winy/2)*(1 + vec4[1]/vec4[3]);
+
+ if(fy>0.0 && fy< (float)area->winy) {
+ adr[0]= floor(fx);
+ adr[1]= floor(fy);
+ }
+ }
+ }
+}
+
+void view3d_project_short_noclip(ScrArea *area, float *vec, short *adr, float mat[4][4])
+{
+ float fx, fy, vec4[4];
+
+ adr[0]= IS_CLIPPED;
+
+ VECCOPY(vec4, vec);
+ vec4[3]= 1.0;
+
+ Mat4MulVec4fl(mat, vec4);
+
+ if( vec4[3]>BL_NEAR_CLIP ) { /* 0.001 is the NEAR clipping cutoff for picking */
+ fx= (area->winx/2)*(1 + vec4[0]/vec4[3]);
+
+ if( fx>-32700 && fx<32700) {
+
+ fy= (area->winy/2)*(1 + vec4[1]/vec4[3]);
+
+ if(fy>-32700.0 && fy<32700.0) {
+ adr[0]= floor(fx);
+ adr[1]= floor(fy);
+ }
+ }
+ }
+}
+
+void view3d_project_float(ScrArea *area, float *vec, float *adr, float mat[4][4])
+{
+ float vec4[4];
+
+ adr[0]= IS_CLIPPED;
+ VECCOPY(vec4, vec);
+ vec4[3]= 1.0;
+
+ Mat4MulVec4fl(mat, vec4);
+
+ if( vec4[3]>FLT_EPSILON ) {
+ adr[0] = (area->winx/2.0)+(area->winx/2.0)*vec4[0]/vec4[3];
+ adr[1] = (area->winy/2.0)+(area->winy/2.0)*vec4[1]/vec4[3];
+ } else {
+ adr[0] = adr[1] = 0.0;
+ }
+}
+
+int boundbox_clip(float obmat[][4], BoundBox *bb)
+{
+ /* return 1: draw */
+
+ float mat[4][4];
+ float vec[4], min, max;
+ int a, flag= -1, fl;
+
+ if(bb==NULL) return 1;
+ if(bb->flag & OB_BB_DISABLED) return 1;
+
+ Mat4MulMat4(mat, obmat, G.vd->persmat);
+
+ for(a=0; a<8; a++) {
+ VECCOPY(vec, bb->vec[a]);
+ vec[3]= 1.0;
+ Mat4MulVec4fl(mat, vec);
+ max= vec[3];
+ min= -vec[3];
+
+ fl= 0;
+ if(vec[0] < min) fl+= 1;
+ if(vec[0] > max) fl+= 2;
+ if(vec[1] < min) fl+= 4;
+ if(vec[1] > max) fl+= 8;
+ if(vec[2] < min) fl+= 16;
+ if(vec[2] > max) fl+= 32;
+
+ flag &= fl;
+ if(flag==0) return 1;
+ }
+
+ return 0;
+
+}
+
+void fdrawline(float x1, float y1, float x2, float y2)
+{
+ float v[2];
+
+ glBegin(GL_LINE_STRIP);
+ v[0] = x1; v[1] = y1;
+ glVertex2fv(v);
+ v[0] = x2; v[1] = y2;
+ glVertex2fv(v);
+ glEnd();
+}
+
+void fdrawbox(float x1, float y1, float x2, float y2)
+{
+ float v[2];
+
+ glBegin(GL_LINE_STRIP);
+
+ v[0] = x1; v[1] = y1;
+ glVertex2fv(v);
+ v[0] = x1; v[1] = y2;
+ glVertex2fv(v);
+ v[0] = x2; v[1] = y2;
+ glVertex2fv(v);
+ v[0] = x2; v[1] = y1;
+ glVertex2fv(v);
+ v[0] = x1; v[1] = y1;
+ glVertex2fv(v);
+
+ glEnd();
+}
+
+void sdrawline(short x1, short y1, short x2, short y2)
+{
+ short v[2];
+
+ glBegin(GL_LINE_STRIP);
+ v[0] = x1; v[1] = y1;
+ glVertex2sv(v);
+ v[0] = x2; v[1] = y2;
+ glVertex2sv(v);
+ glEnd();
+}
+
+void sdrawbox(short x1, short y1, short x2, short y2)
+{
+ short v[2];
+
+ glBegin(GL_LINE_STRIP);
+
+ v[0] = x1; v[1] = y1;
+ glVertex2sv(v);
+ v[0] = x1; v[1] = y2;
+ glVertex2sv(v);
+ v[0] = x2; v[1] = y2;
+ glVertex2sv(v);
+ v[0] = x2; v[1] = y1;
+ glVertex2sv(v);
+ v[0] = x1; v[1] = y1;
+ glVertex2sv(v);
+
+ glEnd();
+}
+
+/* the central math in this function was copied from trackball.cpp, sample code from the
+ Developers Toolbox series by SGI. */
+
+/* trackball: better one than a full spherical solution */
+
+void calctrackballvecfirst(rcti *area, short *mval, float *vec)
+{
+ float x, y, radius, d, z, t;
+
+ radius= TRACKBALLSIZE;
+
+ /* normalize x and y */
+ x= (area->xmax + area->xmin)/2 -mval[0];
+ x/= (float)((area->xmax - area->xmin)/2);
+ y= (area->ymax + area->ymin)/2 -mval[1];
+ y/= (float)((area->ymax - area->ymin)/2);
+
+ d = sqrt(x*x + y*y);
+ if (d < radius*M_SQRT1_2) /* Inside sphere */
+ z = sqrt(radius*radius - d*d);
+ else
+ { /* On hyperbola */
+ t = radius / M_SQRT2;
+ z = t*t / d;
+ }
+
+ vec[0]= x;
+ vec[1]= y;
+ vec[2]= -z; /* yah yah! */
+
+ if( fabs(vec[2])>fabs(vec[1]) && fabs(vec[2])>fabs(vec[0]) ) {
+ vec[0]= 0.0;
+ vec[1]= 0.0;
+ if(vec[2]>0.0) vec[2]= 1.0; else vec[2]= -1.0;
+ }
+ else if( fabs(vec[1])>fabs(vec[0]) && fabs(vec[1])>fabs(vec[2]) ) {
+ vec[0]= 0.0;
+ vec[2]= 0.0;
+ if(vec[1]>0.0) vec[1]= 1.0; else vec[1]= -1.0;
+ }
+ else {
+ vec[1]= 0.0;
+ vec[2]= 0.0;
+ if(vec[0]>0.0) vec[0]= 1.0; else vec[0]= -1.0;
+ }
+}
+
+void calctrackballvec(rcti *area, short *mval, float *vec)
+{
+ float x, y, radius, d, z, t;
+
+ radius= TRACKBALLSIZE;
+
+ /* x en y normalizeren */
+ x= (area->xmax + area->xmin)/2 -mval[0];
+ x/= (float)((area->xmax - area->xmin)/4);
+ y= (area->ymax + area->ymin)/2 -mval[1];
+ y/= (float)((area->ymax - area->ymin)/2);
+
+ d = sqrt(x*x + y*y);
+ if (d < radius*M_SQRT1_2) /* Inside sphere */
+ z = sqrt(radius*radius - d*d);
+ else
+ { /* On hyperbola */
+ t = radius / M_SQRT2;
+ z = t*t / d;
+ }
+
+ vec[0]= x;
+ vec[1]= y;
+ vec[2]= -z; /* yah yah! */
+
+}
+
+void viewmove(int mode)
+{
+ Object *ob = OBACT;
+ float firstvec[3], newvec[3], dvec[3];
+ float reverse, oldquat[4], q1[4], si, phi, dist0;
+ float ofs[3], obofs[3]= {0.0f, 0.0f, 0.0f};
+ int firsttime=1;
+ short mvalball[2], mval[2], mvalo[2], mval_area[2];
+ short use_sel = 0;
+ short preview3d_event= 1;
+
+ /* 3D window may not be defined */
+ if( !G.vd ) {
+ fprintf( stderr, "G.vd == NULL in viewmove()\n" );
+ return;
+ }
+
+ /* sometimes this routine is called from headerbuttons */
+
+ areawinset(curarea->win);
+
+ initgrabz(-G.vd->ofs[0], -G.vd->ofs[1], -G.vd->ofs[2]);
+
+ QUATCOPY(oldquat, G.vd->viewquat);
+
+ getmouseco_areawin(mval_area); /* for zoom to mouse loc */
+ getmouseco_sc(mvalo); /* work with screen coordinates because of trackball function */
+ mvalball[0]= mvalo[0]; /* needed for turntable to work */
+ mvalball[1]= mvalo[1];
+ dist0= G.vd->dist;
+
+ calctrackballvec(&curarea->winrct, mvalo, firstvec);
+
+ /* cumultime(0); */
+
+ if(!G.obedit && (G.f & G_SCULPTMODE) && ob && G.vd->pivot_last) {
+ use_sel= 1;
+ VecCopyf(ofs, G.vd->ofs);
+
+ VecCopyf(obofs,&sculpt_session()->pivot.x);
+ Mat4MulVecfl(ob->obmat, obofs);
+ obofs[0]= -obofs[0];
+ obofs[1]= -obofs[1];
+ obofs[2]= -obofs[2];
+ }
+ else if (ob && (U.uiflag & USER_ORBIT_SELECTION)) {
+ use_sel = 1;
+
+ VECCOPY(ofs, G.vd->ofs);
+
+ /* If there's no selection, obofs is unmodified, so <0,0,0> */
+ calculateTransformCenter(V3D_CENTROID, obofs);
+ VecMulf(obofs, -1.0f);
+ }
+ else
+ ofs[0] = ofs[1] = ofs[2] = 0.0f;
+
+ reverse= 1.0f;
+ if (G.vd->persmat[2][1] < 0.0f)
+ reverse= -1.0f;
+
+ while(TRUE) {
+ getmouseco_sc(mval);
+
+ // if playanim = alt+A, screenhandlers are for animated UI, python, etc
+ if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || (G.f & G_PLAYANIM) || do_screenhandlers(G.curscreen)) {
+
+ if(firsttime) {
+
+ firsttime= 0;
+ /* are we translating, rotating or zooming? */
+ if(mode==0) {
+ if(G.vd->view!=0) scrarea_queue_headredraw(curarea); /*for button */
+ G.vd->view= 0;
+ }
+ if(G.vd->persp==2 && mode!=1 && G.vd->camera) {
+ G.vd->persp= 1;
+ scrarea_do_windraw(curarea);
+ scrarea_queue_headredraw(curarea);
+ }
+ }
+
+ if(mode==0) { /* view rotate */
+ if (U.uiflag & USER_AUTOPERSP) G.vd->persp= 1;
+
+ if (U.flag & USER_TRACKBALL) mvalball[0]= mval[0];
+ mvalball[1]= mval[1];
+
+ calctrackballvec(&curarea->winrct, mvalball, newvec);
+
+ VecSubf(dvec, newvec, firstvec);
+
+ si= sqrt(dvec[0]*dvec[0]+ dvec[1]*dvec[1]+ dvec[2]*dvec[2]);
+ si/= (2.0*TRACKBALLSIZE);
+
+ if (U.flag & USER_TRACKBALL) {
+ Crossf(q1+1, firstvec, newvec);
+
+ Normalize(q1+1);
+
+ /* Allow for rotation beyond the interval
+ * [-pi, pi] */
+ while (si > 1.0)
+ si -= 2.0;
+
+ /* This relation is used instead of
+ * phi = asin(si) so that the angle
+ * of rotation is linearly proportional
+ * to the distance that the mouse is
+ * dragged. */
+ phi = si * M_PI / 2.0;
+
+ si= sin(phi);
+ q1[0]= cos(phi);
+ q1[1]*= si;
+ q1[2]*= si;
+ q1[3]*= si;
+ QuatMul(G.vd->viewquat, q1, oldquat);
+
+ if (use_sel) {
+ /* compute the post multiplication quat, to rotate the offset correctly */
+ QUATCOPY(q1, oldquat);
+ QuatConj(q1);
+ QuatMul(q1, q1, G.vd->viewquat);
+
+ QuatConj(q1); /* conj == inv for unit quat */
+ VECCOPY(G.vd->ofs, ofs);
+ VecSubf(G.vd->ofs, G.vd->ofs, obofs);
+ QuatMulVecf(q1, G.vd->ofs);
+ VecAddf(G.vd->ofs, G.vd->ofs, obofs);
+ }
+ } else {
+ /* New turntable view code by John Aughey */
+
+ float m[3][3];
+ float m_inv[3][3];
+ float xvec[3] = {1,0,0};
+ /* Sensitivity will control how fast the viewport rotates. 0.0035 was
+ obtained experimentally by looking at viewport rotation sensitivities
+ on other modeling programs. */
+ /* Perhaps this should be a configurable user parameter. */
+ const float sensitivity = 0.0035;
+
+ /* Get the 3x3 matrix and its inverse from the quaternion */
+ QuatToMat3(G.vd->viewquat, m);
+ Mat3Inv(m_inv,m);
+
+ /* Determine the direction of the x vector (for rotating up and down) */
+ /* This can likely be compuated directly from the quaternion. */
+ Mat3MulVecfl(m_inv,xvec);
+
+ /* Perform the up/down rotation */
+ phi = sensitivity * -(mval[1] - mvalo[1]);
+ si = sin(phi);
+ q1[0] = cos(phi);
+ q1[1] = si * xvec[0];
+ q1[2] = si * xvec[1];
+ q1[3] = si * xvec[2];
+ QuatMul(G.vd->viewquat, G.vd->viewquat, q1);
+
+ if (use_sel) {
+ QuatConj(q1); /* conj == inv for unit quat */
+ VecSubf(G.vd->ofs, G.vd->ofs, obofs);
+ QuatMulVecf(q1, G.vd->ofs);
+ VecAddf(G.vd->ofs, G.vd->ofs, obofs);
+ }
+
+ /* Perform the orbital rotation */
+ phi = sensitivity * reverse * (mval[0] - mvalo[0]);
+ q1[0] = cos(phi);
+ q1[1] = q1[2] = 0.0;
+ q1[3] = sin(phi);
+ QuatMul(G.vd->viewquat, G.vd->viewquat, q1);
+
+ if (use_sel) {
+ QuatConj(q1);
+ VecSubf(G.vd->ofs, G.vd->ofs, obofs);
+ QuatMulVecf(q1, G.vd->ofs);
+ VecAddf(G.vd->ofs, G.vd->ofs, obofs);
+ }
+ }
+ }
+ else if(mode==1) { /* translate */
+ if(G.vd->persp==2) {
+ float max= (float)MAX2(curarea->winx, curarea->winy);
+
+ G.vd->camdx += (mvalo[0]-mval[0])/(max);
+ G.vd->camdy += (mvalo[1]-mval[1])/(max);
+ CLAMP(G.vd->camdx, -1.0f, 1.0f);
+ CLAMP(G.vd->camdy, -1.0f, 1.0f);
+ preview3d_event= 0;
+ }
+ else {
+ window_to_3d(dvec, mval[0]-mvalo[0], mval[1]-mvalo[1]);
+ VecAddf(G.vd->ofs, G.vd->ofs, dvec);
+ }
+ }
+ else if(mode==2) {
+ float zfac=1.0;
+ if(U.viewzoom==USER_ZOOM_CONT) {
+ // oldstyle zoom
+ zfac = 1.0+(float)(mvalo[0]-mval[0]+mvalo[1]-mval[1])/1000.0;
+ }
+ else if(U.viewzoom==USER_ZOOM_SCALE) {
+ int ctr[2], len1, len2;
+ // method which zooms based on how far you move the mouse
+
+ ctr[0] = (curarea->winrct.xmax + curarea->winrct.xmin)/2;
+ ctr[1] = (curarea->winrct.ymax + curarea->winrct.ymin)/2;
+
+ len1 = (int)sqrt((ctr[0] - mval[0])*(ctr[0] - mval[0]) + (ctr[1] - mval[1])*(ctr[1] - mval[1])) + 5;
+ len2 = (int)sqrt((ctr[0] - mvalo[0])*(ctr[0] - mvalo[0]) + (ctr[1] - mvalo[1])*(ctr[1] - mvalo[1])) + 5;
+
+ zfac = dist0 * ((float)len2/len1) / G.vd->dist;
+ }
+ else { /* USER_ZOOM_DOLLY */
+ float len1 = (curarea->winrct.ymax - mval[1]) + 5;
+ float len2 = (curarea->winrct.ymax - mvalo[1]) + 5;
+ zfac = dist0 * (2.0*((len2/len1)-1.0) + 1.0) / G.vd->dist;
+ }
+
+ if(zfac != 1.0 && zfac*G.vd->dist > 0.001*G.vd->grid &&
+ zfac*G.vd->dist < 10.0*G.vd->far)
+ view_zoom_mouseloc(zfac, mval_area);
+
+ /* these limits are in toets.c too */
+ if(G.vd->dist<0.001*G.vd->grid) G.vd->dist= 0.001*G.vd->grid;
+ if(G.vd->dist>10.0*G.vd->far) G.vd->dist=10.0*G.vd->far;
+
+ mval[1]= mvalo[1]; /* preserve first value */
+ mval[0]= mvalo[0];
+
+ if(G.vd->persp==0 || G.vd->persp==2) preview3d_event= 0;
+ }
+
+ mvalo[0]= mval[0];
+ mvalo[1]= mval[1];
+
+ if(G.f & G_PLAYANIM) inner_play_anim_loop(0, 0);
+ if(G.f & G_SIMULATION) break;
+
+ /* If in retopo paint mode, update lines */
+ if(retopo_mesh_paint_check() && G.vd->retopo_view_data) {
+ G.vd->retopo_view_data->queue_matrix_update= 1;
+ retopo_paint_view_update(G.vd);
+ }
+
+ scrarea_do_windraw(curarea);
+ screen_swapbuffers();
+ }
+ else {
+ short val;
+ unsigned short event;
+ /* we need to empty the queue... when you do this very long it overflows */
+ while(qtest()) event= extern_qread(&val);
+
+ BIF_wait_for_statechange();
+ }
+
+ /* this in the end, otherwise get_mbut does not work on a PC... */
+ if( !(get_mbut() & (L_MOUSE|M_MOUSE))) break;
+ }
+
+ if(G.vd->depths) G.vd->depths->damaged= 1;
+ retopo_queue_updates(G.vd);
+ allqueue(REDRAWVIEW3D, 0);
+
+ if(preview3d_event)
+ BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
+ else
+ BIF_view3d_previewrender_signal(curarea, PR_PROJECTED);
+
+}
+
+void view_zoom_mouseloc(float dfac, short *mouseloc)
+{
+ if(U.uiflag & USER_ZOOM_TO_MOUSEPOS) {
+ short vb[2];
+ float dvec[3];
+ float tvec[3];
+ float tpos[3];
+ float new_dist;
+
+ /* find the current window width and height */
+ vb[0] = G.vd->area->winx;
+ vb[1] = G.vd->area->winy;
+
+ tpos[0] = -G.vd->ofs[0];
+ tpos[1] = -G.vd->ofs[1];
+ tpos[2] = -G.vd->ofs[2];
+
+ /* Project cursor position into 3D space */
+ initgrabz(tpos[0], tpos[1], tpos[2]);
+ window_to_3d(dvec, mouseloc[0]-vb[0]/2, mouseloc[1]-vb[1]/2);
+
+ /* Calculate view target position for dolly */
+ tvec[0] = -(tpos[0] + dvec[0]);
+ tvec[1] = -(tpos[1] + dvec[1]);
+ tvec[2] = -(tpos[2] + dvec[2]);
+
+ /* Offset to target position and dolly */
+ new_dist = G.vd->dist * dfac;
+
+ VECCOPY(G.vd->ofs, tvec);
+ G.vd->dist = new_dist;
+
+ /* Calculate final offset */
+ dvec[0] = tvec[0] + dvec[0] * dfac;
+ dvec[1] = tvec[1] + dvec[1] * dfac;
+ dvec[2] = tvec[2] + dvec[2] * dfac;
+
+ VECCOPY(G.vd->ofs, dvec);
+ } else {
+ G.vd->dist *= dfac;
+ }
+}
+
+/* Gets the lens and clipping values from a camera of lamp type object */
+void object_view_settings(Object *ob, float *lens, float *clipsta, float *clipend)
+{
+ if (!ob) return;
+
+ if(ob->type==OB_LAMP ) {
+ Lamp *la = ob->data;
+ if (lens) {
+ float x1, fac;
+ fac= cos( M_PI*la->spotsize/360.0);
+ x1= saacos(fac);
+ *lens= 16.0*fac/sin(x1);
+ }
+ if (clipsta) *clipsta= la->clipsta;
+ if (clipend) *clipend= la->clipend;
+ }
+ else if(ob->type==OB_CAMERA) {
+ Camera *cam= ob->data;
+ if (lens) *lens= cam->lens;
+ if (clipsta) *clipsta= cam->clipsta;
+ if (clipend) *clipend= cam->clipend;
+ }
+}
+
+
+int get_view3d_viewplane(int winxi, int winyi, rctf *viewplane, float *clipsta, float *clipend, float *pixsize)
+{
+ Camera *cam=NULL;
+ float lens, fac, x1, y1, x2, y2;
+ float winx= (float)winxi, winy= (float)winyi;
+ int orth= 0;
+
+ lens= G.vd->lens;
+
+ *clipsta= G.vd->near;
+ *clipend= G.vd->far;
+
+/*
+ * Cant use this since we need the fac and x1 values set
+ * if(G.vd->persp==2)
+ object_view_settings(G.vd->camera, &lens, &(*clipsta), &(*clipend));*/
+
+ if(G.vd->persp==2) {
+ if(G.vd->camera) {
+ if(G.vd->camera->type==OB_LAMP ) {
+ Lamp *la;
+
+ la= G.vd->camera->data;
+ fac= cos( M_PI*la->spotsize/360.0);
+
+ x1= saacos(fac);
+ lens= 16.0*fac/sin(x1);
+
+ *clipsta= la->clipsta;
+ *clipend= la->clipend;
+ }
+ else if(G.vd->camera->type==OB_CAMERA) {
+ cam= G.vd->camera->data;
+ lens= cam->lens;
+ *clipsta= cam->clipsta;
+ *clipend= cam->clipend;
+ }
+ }
+ }
+
+ if(G.vd->persp==0) {
+ if(winx>winy) x1= -G.vd->dist;
+ else x1= -winx*G.vd->dist/winy;
+ x2= -x1;
+
+ if(winx>winy) y1= -winy*G.vd->dist/winx;
+ else y1= -G.vd->dist;
+ y2= -y1;
+
+ *clipend *= 0.5; // otherwise too extreme low zbuffer quality
+ *clipsta= - *clipend;
+ orth= 1;
+ }
+ else {
+ /* fac for zoom, also used for camdx */
+ if(G.vd->persp==2) {
+ fac= (1.41421+( (float)G.vd->camzoom )/50.0);
+ fac*= fac;
+ }
+ else fac= 2.0;
+
+ /* viewplane size depends... */
+ if(cam && cam->type==CAM_ORTHO) {
+ /* ortho_scale == 1 means exact 1 to 1 mapping */
+ float dfac= 2.0*cam->ortho_scale/fac;
+
+ if(winx>winy) x1= -dfac;
+ else x1= -winx*dfac/winy;
+ x2= -x1;
+
+ if(winx>winy) y1= -winy*dfac/winx;
+ else y1= -dfac;
+ y2= -y1;
+ orth= 1;
+ }
+ else {
+ float dfac;
+
+ if(winx>winy) dfac= 64.0/(fac*winx*lens);
+ else dfac= 64.0/(fac*winy*lens);
+
+ x1= - *clipsta * winx*dfac;
+ x2= -x1;
+ y1= - *clipsta * winy*dfac;
+ y2= -y1;
+ orth= 0;
+ }
+ /* cam view offset */
+ if(cam) {
+ float dx= 0.5*fac*G.vd->camdx*(x2-x1);
+ float dy= 0.5*fac*G.vd->camdy*(y2-y1);
+ x1+= dx;
+ x2+= dx;
+ y1+= dy;
+ y2+= dy;
+ }
+ }
+
+ if(pixsize) {
+ float viewfac;
+
+ if(orth) {
+ viewfac= (winx >= winy)? winx: winy;
+ *pixsize= 1.0f/viewfac;
+ }
+ else {
+ viewfac= (((winx >= winy)? winx: winy)*lens)/32.0;
+ *pixsize= *clipsta/viewfac;
+ }
+ }
+
+ viewplane->xmin= x1;
+ viewplane->ymin= y1;
+ viewplane->xmax= x2;
+ viewplane->ymax= y2;
+
+ return orth;
+}
+
+/* important to not set windows active in here, can be renderwin for example */
+void setwinmatrixview3d(int winx, int winy, rctf *rect) /* rect: for picking */
+{
+ rctf viewplane;
+ float clipsta, clipend, x1, y1, x2, y2;
+ int orth;
+
+ orth= get_view3d_viewplane(winx, winy, &viewplane, &clipsta, &clipend, NULL);
+// printf("%d %d %f %f %f %f %f %f\n", winx, winy, viewplane.xmin, viewplane.ymin, viewplane.xmax, viewplane.ymax, clipsta, clipend);
+ x1= viewplane.xmin;
+ y1= viewplane.ymin;
+ x2= viewplane.xmax;
+ y2= viewplane.ymax;
+
+ if(rect) { /* picking */
+ rect->xmin/= (float)curarea->winx;
+ rect->xmin= x1+rect->xmin*(x2-x1);
+ rect->ymin/= (float)curarea->winy;
+ rect->ymin= y1+rect->ymin*(y2-y1);
+ rect->xmax/= (float)curarea->winx;
+ rect->xmax= x1+rect->xmax*(x2-x1);
+ rect->ymax/= (float)curarea->winy;
+ rect->ymax= y1+rect->ymax*(y2-y1);
+
+ if(orth) myortho(rect->xmin, rect->xmax, rect->ymin, rect->ymax, -clipend, clipend);
+ else mywindow(rect->xmin, rect->xmax, rect->ymin, rect->ymax, clipsta, clipend);
+
+ }
+ else {
+ if(orth) myortho(x1, x2, y1, y2, clipsta, clipend);
+ else mywindow(x1, x2, y1, y2, clipsta, clipend);
+ }
+
+ /* not sure what this was for? (ton) */
+ glMatrixMode(GL_PROJECTION);
+ mygetmatrix(curarea->winmat);
+ glMatrixMode(GL_MODELVIEW);
+}
+
+void obmat_to_viewmat(Object *ob, short smooth)
+{
+ float bmat[4][4];
+ float tmat[3][3];
+
+ Mat4CpyMat4(bmat, ob->obmat);
+ Mat4Ortho(bmat);
+ Mat4Invert(G.vd->viewmat, bmat);
+
+ /* view quat calculation, needed for add object */
+ Mat3CpyMat4(tmat, G.vd->viewmat);
+ if (smooth) {
+ float new_quat[4];
+ if (G.vd->persp==2 && G.vd->camera) {
+ /* were from a camera view */
+
+ float orig_ofs[3];
+ float orig_dist= G.vd->dist;
+ float orig_lens= G.vd->lens;
+ VECCOPY(orig_ofs, G.vd->ofs);
+
+ /* Switch from camera view */
+ Mat3ToQuat(tmat, new_quat);
+
+ G.vd->persp=1;
+ G.vd->dist= 0.0;
+
+ view_settings_from_ob(G.vd->camera, G.vd->ofs, NULL, NULL, &G.vd->lens);
+ smooth_view(G.vd, orig_ofs, new_quat, &orig_dist, &orig_lens);
+
+ G.vd->persp=2; /* just to be polite, not needed */
+
+ } else {
+ Mat3ToQuat(tmat, new_quat);
+ smooth_view(G.vd, NULL, new_quat, NULL, NULL);
+ }
+ } else {
+ Mat3ToQuat(tmat, G.vd->viewquat);
+ }
+}
+
+/* dont set windows active in in here, is used by renderwin too */
+void setviewmatrixview3d()
+{
+ Camera *cam;
+
+ if(G.vd->persp>=2) { /* obs/camera */
+ if(G.vd->camera) {
+
+ where_is_object(G.vd->camera);
+ obmat_to_viewmat(G.vd->camera, 0);
+
+ if(G.vd->camera->type==OB_CAMERA) {
+ cam= G.vd->camera->data;
+ //if(cam->type==CAM_ORTHO) G.vd->viewmat[3][2]*= 100.0;
+ }
+ }
+ else {
+ QuatToMat4(G.vd->viewquat, G.vd->viewmat);
+ G.vd->viewmat[3][2]-= G.vd->dist;
+ }
+ }
+ else {
+
+ QuatToMat4(G.vd->viewquat, G.vd->viewmat);
+ if(G.vd->persp==1) G.vd->viewmat[3][2]-= G.vd->dist;
+ if(G.vd->ob_centre) {
+ Object *ob= G.vd->ob_centre;
+ float vec[3];
+
+ VECCOPY(vec, ob->obmat[3]);
+ if(ob->type==OB_ARMATURE && G.vd->ob_centre_bone[0]) {
+ bPoseChannel *pchan= get_pose_channel(ob->pose, G.vd->ob_centre_bone);
+ if(pchan) {
+ VECCOPY(vec, pchan->pose_mat[3]);
+ Mat4MulVecfl(ob->obmat, vec);
+ }
+ }
+ i_translate(-vec[0], -vec[1], -vec[2], G.vd->viewmat);
+ }
+ else i_translate(G.vd->ofs[0], G.vd->ofs[1], G.vd->ofs[2], G.vd->viewmat);
+ }
+}
+
+void setcameratoview3d(void)
+{
+ Object *ob;
+ float dvec[3];
+
+ ob= G.vd->camera;
+ dvec[0]= G.vd->dist*G.vd->viewinv[2][0];
+ dvec[1]= G.vd->dist*G.vd->viewinv[2][1];
+ dvec[2]= G.vd->dist*G.vd->viewinv[2][2];
+ VECCOPY(ob->loc, dvec);
+ VecSubf(ob->loc, ob->loc, G.vd->ofs);
+ G.vd->viewquat[0]= -G.vd->viewquat[0];
+ if (ob->transflag & OB_QUAT) {
+ QUATCOPY(ob->quat, G.vd->viewquat);
+ } else {
+ QuatToEul(G.vd->viewquat, ob->rot);
+ }
+ G.vd->viewquat[0]= -G.vd->viewquat[0];
+}
+
+/* IGLuint-> GLuint*/
+/* Warning: be sure to account for a negative return value
+ * This is an error, "Too many objects in select buffer"
+ * and no action should be taken (can crash blender) if this happens
+ */
+short view3d_opengl_select(unsigned int *buffer, unsigned int bufsize, short x1, short y1, short x2, short y2)
+{
+ rctf rect;
+ short mval[2], code, hits;
+
+ G.f |= G_PICKSEL;
+
+ if(x1==0 && x2==0 && y1==0 && y2==0) {
+ getmouseco_areawin(mval);
+ rect.xmin= mval[0]-12; // seems to be default value for bones only now
+ rect.xmax= mval[0]+12;
+ rect.ymin= mval[1]-12;
+ rect.ymax= mval[1]+12;
+ }
+ else {
+ rect.xmin= x1;
+ rect.xmax= x2;
+ rect.ymin= y1;
+ rect.ymax= y2;
+ }
+ /* get rid of overlay button matrix */
+ persp(PERSP_VIEW);
+ setwinmatrixview3d(curarea->winx, curarea->winy, &rect);
+ Mat4MulMat4(G.vd->persmat, G.vd->viewmat, curarea->winmat);
+
+ if(G.vd->drawtype > OB_WIRE) {
+ G.vd->zbuf= TRUE;
+ glEnable(GL_DEPTH_TEST);
+ }
+
+ if(G.vd->flag & V3D_CLIPPING)
+ view3d_set_clipping(G.vd);
+
+ glSelectBuffer( bufsize, (GLuint *)buffer);
+ glRenderMode(GL_SELECT);
+ glInitNames(); /* these two calls whatfor? It doesnt work otherwise */
+ glPushName(-1);
+ code= 1;
+
+ if(G.obedit && G.obedit->type==OB_MBALL) {
+ draw_object(BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
+ }
+ else if ((G.obedit && G.obedit->type==OB_ARMATURE)) {
+ draw_object(BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
+ }
+ else {
+ Base *base;
+
+ G.vd->xray= TRUE; // otherwise it postpones drawing
+ for(base= G.scene->base.first; base; base= base->next) {
+ if(base->lay & G.vd->lay) {
+
+ if (base->object->restrictflag & OB_RESTRICT_SELECT)
+ base->selcol= 0;
+ else {
+ base->selcol= code;
+ glLoadName(code);
+ draw_object(base, DRAW_PICKING|DRAW_CONSTCOLOR);
+
+ /* we draw group-duplicators for selection too */
+ if((base->object->transflag & OB_DUPLI) && base->object->dup_group) {
+ ListBase *lb;
+ DupliObject *dob;
+ Base tbase;
+
+ tbase.flag= OB_FROMDUPLI;
+ lb= object_duplilist(G.scene, base->object);
+
+ for(dob= lb->first; dob; dob= dob->next) {
+ tbase.object= dob->ob;
+ Mat4CpyMat4(dob->ob->obmat, dob->mat);
+
+ draw_object(&tbase, DRAW_PICKING|DRAW_CONSTCOLOR);
+
+ Mat4CpyMat4(dob->ob->obmat, dob->omat);
+ }
+ free_object_duplilist(lb);
+ }
+ code++;
+ }
+ }
+ }
+ G.vd->xray= FALSE; // restore
+ }
+
+ glPopName(); /* see above (pushname) */
+ hits= glRenderMode(GL_RENDER);
+
+ G.f &= ~G_PICKSEL;
+ setwinmatrixview3d(curarea->winx, curarea->winy, NULL);
+ Mat4MulMat4(G.vd->persmat, G.vd->viewmat, curarea->winmat);
+
+ if(G.vd->drawtype > OB_WIRE) {
+ G.vd->zbuf= 0;
+ glDisable(GL_DEPTH_TEST);
+ }
+ persp(PERSP_WIN);
+
+ if(G.vd->flag & V3D_CLIPPING)
+ view3d_clr_clipping();
+
+ if(hits<0) error("Too many objects in select buffer");
+
+ return hits;
+}
+
+float *give_cursor()
+{
+ if(G.vd && G.vd->localview) return G.vd->cursor;
+ else return G.scene->cursor;
+}
+
+unsigned int free_localbit()
+{
+ unsigned int lay;
+ ScrArea *sa;
+ bScreen *sc;
+
+ lay= 0;
+
+ /* sometimes we loose a localview: when an area is closed */
+ /* check all areas: which localviews are in use? */
+ sc= G.main->screen.first;
+ while(sc) {
+ sa= sc->areabase.first;
+ while(sa) {
+ SpaceLink *sl= sa->spacedata.first;
+ while(sl) {
+ if(sl->spacetype==SPACE_VIEW3D) {
+ View3D *v3d= (View3D*) sl;
+ lay |= v3d->lay;
+ }
+ sl= sl->next;
+ }
+ sa= sa->next;
+ }
+ sc= sc->id.next;
+ }
+
+ if( (lay & 0x01000000)==0) return 0x01000000;
+ if( (lay & 0x02000000)==0) return 0x02000000;
+ if( (lay & 0x04000000)==0) return 0x04000000;
+ if( (lay & 0x08000000)==0) return 0x08000000;
+ if( (lay & 0x10000000)==0) return 0x10000000;
+ if( (lay & 0x20000000)==0) return 0x20000000;
+ if( (lay & 0x40000000)==0) return 0x40000000;
+ if( (lay & 0x80000000)==0) return 0x80000000;
+
+ return 0;
+}
+
+
+void initlocalview()
+{
+ Base *base;
+ float size = 0.0, min[3], max[3], afm[3];
+ unsigned int locallay;
+ int ok=0;
+
+ if(G.vd->localvd) return;
+
+ min[0]= min[1]= min[2]= 1.0e10;
+ max[0]= max[1]= max[2]= -1.0e10;
+
+ locallay= free_localbit();
+
+ if(locallay==0) {
+ error("Sorry, no more than 8 localviews");
+ ok= 0;
+ }
+ else {
+ if(G.obedit) {
+ minmax_object(G.obedit, min, max);
+
+ ok= 1;
+
+ BASACT->lay |= locallay;
+ G.obedit->lay= BASACT->lay;
+ }
+ else {
+ base= FIRSTBASE;
+ while(base) {
+ if TESTBASE(base) {
+ minmax_object(base->object, min, max);
+ base->lay |= locallay;
+ base->object->lay= base->lay;
+ ok= 1;
+ }
+ base= base->next;
+ }
+ }
+
+ afm[0]= (max[0]-min[0]);
+ afm[1]= (max[1]-min[1]);
+ afm[2]= (max[2]-min[2]);
+ size= 0.7*MAX3(afm[0], afm[1], afm[2]);
+ if(size<=0.01) size= 0.01;
+ }
+
+ if(ok) {
+ G.vd->localvd= MEM_mallocN(sizeof(View3D), "localview");
+ memcpy(G.vd->localvd, G.vd, sizeof(View3D));
+
+ G.vd->ofs[0]= -(min[0]+max[0])/2.0;
+ G.vd->ofs[1]= -(min[1]+max[1])/2.0;
+ G.vd->ofs[2]= -(min[2]+max[2])/2.0;
+
+ G.vd->dist= size;
+
+ // correction for window aspect ratio
+ if(curarea->winy>2 && curarea->winx>2) {
+ size= (float)curarea->winx/(float)curarea->winy;
+ if(size<1.0) size= 1.0/size;
+ G.vd->dist*= size;
+ }
+
+ if (G.vd->persp>1) G.vd->persp= 1;
+ if (G.vd->near> 0.1) G.vd->near= 0.1;
+
+ G.vd->cursor[0]= -G.vd->ofs[0];
+ G.vd->cursor[1]= -G.vd->ofs[1];
+ G.vd->cursor[2]= -G.vd->ofs[2];
+
+ G.vd->lay= locallay;
+
+ countall();
+ scrarea_queue_winredraw(curarea);
+ }
+ else {
+ /* clear flags */
+ base= FIRSTBASE;
+ while(base) {
+ if( base->lay & locallay ) {
+ base->lay-= locallay;
+ if(base->lay==0) base->lay= G.vd->layact;
+ if(base->object != G.obedit) base->flag |= SELECT;
+ base->object->lay= base->lay;
+ }
+ base= base->next;
+ }
+ scrarea_queue_headredraw(curarea);
+
+ G.vd->localview= 0;
+ }
+ BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
+}
+
+void centerview() /* like a localview without local! */
+{
+ Object *ob= OBACT;
+ float size, min[3], max[3], afm[3];
+ int ok=0;
+
+ /* SMOOTHVIEW */
+ float new_ofs[3];
+ float new_dist;
+
+
+ min[0]= min[1]= min[2]= 1.0e10;
+ max[0]= max[1]= max[2]= -1.0e10;
+
+ if (G.f & G_WEIGHTPAINT) {
+ /* hardcoded exception, we look for the one selected armature */
+ /* this is weak code this way, we should make a generic active/selection callback interface once... */
+ Base *base;
+ for(base=FIRSTBASE; base; base= base->next) {
+ if(TESTBASELIB(base)) {
+ if(base->object->type==OB_ARMATURE)
+ if(base->object->flag & OB_POSEMODE)
+ break;
+ }
+ }
+ if(base)
+ ob= base->object;
+ }
+
+
+ if(G.obedit) {
+ ok = minmax_verts(min, max); /* only selected */
+ }
+ else if(ob && (ob->flag & OB_POSEMODE)) {
+ if(ob->pose) {
+ bArmature *arm= ob->data;
+ bPoseChannel *pchan;
+ float vec[3];
+
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ if(pchan->bone->flag & BONE_SELECTED) {
+ if(pchan->bone->layer & arm->layer) {
+ ok= 1;
+ VECCOPY(vec, pchan->pose_head);
+ Mat4MulVecfl(ob->obmat, vec);
+ DO_MINMAX(vec, min, max);
+ VECCOPY(vec, pchan->pose_tail);
+ Mat4MulVecfl(ob->obmat, vec);
+ DO_MINMAX(vec, min, max);
+ }
+ }
+ }
+ }
+ }
+ else if (FACESEL_PAINT_TEST) {
+ ok= minmax_tface(min, max);
+ }
+ else {
+ Base *base= FIRSTBASE;
+ while(base) {
+ if TESTBASE(base) {
+ minmax_object(base->object, min, max);
+ /* account for duplis */
+ minmax_object_duplis(base->object, min, max);
+
+ ok= 1;
+ }
+ base= base->next;
+ }
+ }
+
+ if(ok==0) return;
+
+ afm[0]= (max[0]-min[0]);
+ afm[1]= (max[1]-min[1]);
+ afm[2]= (max[2]-min[2]);
+ size= 0.7*MAX3(afm[0], afm[1], afm[2]);
+
+ if(size <= G.vd->near*1.5) size= G.vd->near*1.5;
+
+ new_ofs[0]= -(min[0]+max[0])/2.0;
+ new_ofs[1]= -(min[1]+max[1])/2.0;
+ new_ofs[2]= -(min[2]+max[2])/2.0;
+
+ new_dist = size;
+
+ /* correction for window aspect ratio */
+ if(curarea->winy>2 && curarea->winx>2) {
+ size= (float)curarea->winx/(float)curarea->winy;
+ if(size<1.0) size= 1.0/size;
+ new_dist*= size;
+ }
+
+ G.vd->cursor[0]= -new_ofs[0];
+ G.vd->cursor[1]= -new_ofs[1];
+ G.vd->cursor[2]= -new_ofs[2];
+
+ if (G.vd->persp==2 && G.vd->camera) {
+ float orig_lens= G.vd->lens;
+
+ G.vd->persp=1;
+ G.vd->dist= 0.0;
+ view_settings_from_ob(G.vd->camera, G.vd->ofs, NULL, NULL, &G.vd->lens);
+ smooth_view(G.vd, new_ofs, NULL, &new_dist, &orig_lens);
+ } else {
+ if(G.vd->persp>=2)
+ G.vd->persp= 1;
+
+ smooth_view(G.vd, new_ofs, NULL, &new_dist, NULL);
+ }
+ scrarea_queue_winredraw(curarea);
+ BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
+
+}
+
+
+void restore_localviewdata(View3D *vd)
+{
+ if(vd->localvd==0) return;
+
+ VECCOPY(vd->ofs, vd->localvd->ofs);
+ vd->dist= vd->localvd->dist;
+ vd->persp= vd->localvd->persp;
+ vd->view= vd->localvd->view;
+ vd->near= vd->localvd->near;
+ vd->far= vd->localvd->far;
+ vd->lay= vd->localvd->lay;
+ vd->layact= vd->localvd->layact;
+ vd->drawtype= vd->localvd->drawtype;
+ vd->camera= vd->localvd->camera;
+ QUATCOPY(vd->viewquat, vd->localvd->viewquat);
+
+}
+
+void endlocalview(ScrArea *sa)
+{
+ View3D *v3d;
+ struct Base *base;
+ unsigned int locallay;
+
+ if(sa->spacetype!=SPACE_VIEW3D) return;
+ v3d= sa->spacedata.first;
+
+ if(v3d->localvd) {
+
+ locallay= v3d->lay & 0xFF000000;
+
+ restore_localviewdata(v3d);
+
+ MEM_freeN(v3d->localvd);
+ v3d->localvd= 0;
+ v3d->localview= 0;
+
+ /* for when in other window the layers have changed */
+ if(v3d->scenelock) v3d->lay= G.scene->lay;
+
+ base= FIRSTBASE;
+ while(base) {
+ if( base->lay & locallay ) {
+ base->lay-= locallay;
+ if(base->lay==0) base->lay= v3d->layact;
+ if(base->object != G.obedit) {
+ base->flag |= SELECT;
+ base->object->flag |= SELECT;
+ }
+ base->object->lay= base->lay;
+ }
+ base= base->next;
+ }
+
+ countall();
+ allqueue(REDRAWVIEW3D, 0); /* because of select */
+ allqueue(REDRAWOOPS, 0); /* because of select */
+ BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
+ }
+}
+
+void view3d_home(int center)
+{
+ Base *base;
+ float size, min[3], max[3], afm[3];
+ int ok= 1, onedone=0;
+
+ if(center) {
+ min[0]= min[1]= min[2]= 0.0;
+ max[0]= max[1]= max[2]= 0.0;
+ }
+ else {
+ min[0]= min[1]= min[2]= 1.0e10;
+ max[0]= max[1]= max[2]= -1.0e10;
+ }
+
+ for(base= FIRSTBASE; base; base= base->next) {
+ if(base->lay & G.vd->lay) {
+ onedone= 1;
+ minmax_object(base->object, min, max);
+ }
+ }
+ if(!onedone) return;
+
+ afm[0]= (max[0]-min[0]);
+ afm[1]= (max[1]-min[1]);
+ afm[2]= (max[2]-min[2]);
+ size= 0.7*MAX3(afm[0], afm[1], afm[2]);
+ if(size==0.0) ok= 0;
+
+ if(ok) {
+ float new_dist;
+ float new_ofs[3];
+
+ new_dist = size;
+ new_ofs[0]= -(min[0]+max[0])/2.0;
+ new_ofs[1]= -(min[1]+max[1])/2.0;
+ new_ofs[2]= -(min[2]+max[2])/2.0;
+
+ // correction for window aspect ratio
+ if(curarea->winy>2 && curarea->winx>2) {
+ size= (float)curarea->winx/(float)curarea->winy;
+ if(size<1.0) size= 1.0/size;
+ new_dist*= size;
+ }
+
+ if (G.vd->persp==2 && G.vd->camera) {
+ /* switch out of camera view */
+ float orig_lens= G.vd->lens;
+
+ G.vd->persp=1;
+ G.vd->dist= 0.0;
+ view_settings_from_ob(G.vd->camera, G.vd->ofs, NULL, NULL, &G.vd->lens);
+ smooth_view(G.vd, new_ofs, NULL, &new_dist, &orig_lens);
+
+ } else {
+ if(G.vd->persp>=2) G.vd->persp= 1;
+ smooth_view(G.vd, new_ofs, NULL, &new_dist, NULL);
+ }
+ scrarea_queue_winredraw(curarea);
+ }
+ BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
+
+}
+
+
+void view3d_align_axis_to_vector(View3D *v3d, int axisidx, float vec[3])
+{
+ float alignaxis[3] = {0.0, 0.0, 0.0};
+ float norm[3], axis[3], angle, new_quat[4];
+
+ if(axisidx > 0) alignaxis[axisidx-1]= 1.0;
+ else alignaxis[-axisidx-1]= -1.0;
+
+ VECCOPY(norm, vec);
+ Normalize(norm);
+
+ angle= acos(Inpf(alignaxis, norm));
+ Crossf(axis, alignaxis, norm);
+ VecRotToQuat(axis, -angle, new_quat);
+
+ v3d->view= 0;
+
+ if (v3d->persp==2 && v3d->camera) {
+ /* switch out of camera view */
+ float orig_ofs[3];
+ float orig_dist= v3d->dist;
+ float orig_lens= v3d->lens;
+
+ VECCOPY(orig_ofs, v3d->ofs);
+ G.vd->persp=1;
+ G.vd->dist= 0.0;
+ view_settings_from_ob(v3d->camera, v3d->ofs, NULL, NULL, &v3d->lens);
+ smooth_view(G.vd, orig_ofs, new_quat, &orig_dist, &orig_lens);
+ } else {
+ if (v3d->persp>=2) v3d->persp= 1; /* switch out of camera mode */
+ smooth_view(v3d, NULL, new_quat, NULL, NULL);
+ }
+}
+
+
+
+/* SMOOTHVIEW */
+void smooth_view(View3D *v3d, float *ofs, float *quat, float *dist, float *lens)
+{
+ /* View Animation enabled */
+ if (U.smooth_viewtx) {
+ int i;
+ char changed = 0;
+ float step = 0.0, step_inv;
+ float orig_dist;
+ float orig_lens;
+ float orig_quat[4];
+ float orig_ofs[3];
+
+ double time_allowed, time_current, time_start;
+
+ /* if there is no difference, return */
+ changed = 0; /* zero means no difference */
+ if (dist) {
+ if ((*dist) != v3d->dist)
+ changed = 1;
+ }
+
+ if (lens) {
+ if ((*lens) != v3d->lens)
+ changed = 1;
+ }
+
+ if (!changed && ofs) {
+ if ((ofs[0]!=v3d->ofs[0]) ||
+ (ofs[1]!=v3d->ofs[1]) ||
+ (ofs[2]!=v3d->ofs[2]) )
+ changed = 1;
+ }
+
+ if (!changed && quat ) {
+ if ((quat[0]!=v3d->viewquat[0]) ||
+ (quat[1]!=v3d->viewquat[1]) ||
+ (quat[2]!=v3d->viewquat[2]) ||
+ (quat[3]!=v3d->viewquat[3]) )
+ changed = 1;
+ }
+
+ /* The new view is different from teh old one
+ * so animate the view */
+ if (changed) {
+
+ /* store original values */
+ VECCOPY(orig_ofs, v3d->ofs);
+ QUATCOPY(orig_quat, v3d->viewquat);
+ orig_dist = v3d->dist;
+ orig_lens = v3d->lens;
+
+ time_allowed= (float)U.smooth_viewtx / 1000.0;
+ time_current = time_start = PIL_check_seconds_timer();
+
+ /* if this is view rotation only
+ * we can decrease the time allowed by
+ * the angle between quats
+ * this means small rotations wont lag */
+ if (quat && !ofs && !dist) {
+ float vec1[3], vec2[3];
+ VECCOPY(vec1, quat);
+ VECCOPY(vec2, v3d->viewquat);
+ Normalize(vec1);
+ Normalize(vec2);
+ /* scale the time allowed by the rotation */
+ time_allowed *= NormalizedVecAngle2(vec1, vec2)/(M_PI/2);
+ }
+
+ while (time_start + time_allowed > time_current) {
+
+ step = (float)((time_current-time_start) / time_allowed);
+
+ /* ease in/out */
+ if (step < 0.5) step = pow(step*2, 2)/2;
+ else step = 1-(pow(2*(1-step) ,2)/2);
+
+ step_inv = 1-step;
+
+ if (ofs)
+ for (i=0; i<3; i++)
+ v3d->ofs[i] = ofs[i]*step + orig_ofs[i]*step_inv;
+
+
+ if (quat)
+ QuatInterpol(v3d->viewquat, orig_quat, quat, step);
+
+ if (dist)
+ v3d->dist = ((*dist)*step) + (orig_dist*step_inv);
+
+ if (lens)
+ v3d->lens = ((*lens)*step) + (orig_lens*step_inv);
+
+ /*redraw the view*/
+ scrarea_do_windraw(curarea);
+ screen_swapbuffers();
+
+ time_current= PIL_check_seconds_timer();
+ }
+ }
+ }
+
+ /* set these values even if animation is enabled because flaot
+ * error will make then not quite accurate */
+ if (ofs)
+ VECCOPY(v3d->ofs, ofs);
+ if (quat)
+ QUATCOPY(v3d->viewquat, quat);
+ if (dist)
+ v3d->dist = *dist;
+ if (lens)
+ v3d->lens = *lens;
+
+}
+
+
+
+/* Gets the view trasnformation from a camera
+ * currently dosnt take camzoom into account
+ *
+ * The dist is not modified for this function, if NULL its assimed zero
+ * */
+void view_settings_from_ob(Object *ob, float *ofs, float *quat, float *dist, float *lens)
+{
+ float bmat[4][4];
+ float imat[4][4];
+ float tmat[3][3];
+
+ if (!ob) return;
+
+ /* Offset */
+ if (ofs) {
+ where_is_object(ob);
+ VECCOPY(ofs, ob->obmat[3]);
+ VecMulf(ofs, -1.0f); /*flip the vector*/
+ }
+
+ /* Quat */
+ if (quat) {
+ Mat4CpyMat4(bmat, ob->obmat);
+ Mat4Ortho(bmat);
+ Mat4Invert(imat, bmat);
+ Mat3CpyMat4(tmat, imat);
+ Mat3ToQuat(tmat, quat);
+ }
+
+ if (dist) {
+ float vec[3];
+ Mat3CpyMat4(tmat, ob->obmat);
+
+ vec[0]= vec[1] = 0.0;
+ vec[2]= -(*dist);
+ Mat3MulVecfl(tmat, vec);
+ VecSubf(ofs, ofs, vec);
+ }
+
+ /* Lens */
+ if (lens)
+ object_view_settings(ob, lens, NULL, NULL);
+}
+
+/* For use with smooth view
+ *
+ * the current view is unchanged, blend between the current view and the
+ * camera view
+ * */
+void smooth_view_to_camera(View3D *v3d)
+{
+ if (!U.smooth_viewtx || !v3d->camera || G.vd->persp != 2) {
+ return;
+ } else {
+ Object *ob = v3d->camera;
+
+ float orig_ofs[3];
+ float orig_dist=v3d->dist;
+ float orig_lens=v3d->lens;
+ float new_dist=0.0;
+ float new_lens=35.0;
+ float new_quat[4];
+ float new_ofs[3];
+
+ VECCOPY(orig_ofs, v3d->ofs);
+
+ view_settings_from_ob(ob, new_ofs, new_quat, NULL, &new_lens);
+
+ G.vd->persp=1;
+ smooth_view(v3d, new_ofs, new_quat, &new_dist, &new_lens);
+ VECCOPY(v3d->ofs, orig_ofs);
+ v3d->lens= orig_lens;
+ v3d->dist = orig_dist; /* restore the dist */
+
+ v3d->camera = ob;
+ v3d->persp=2;
+ }
+}
diff --git a/source/blender/src/vpaint.c b/source/blender/src/vpaint.c
new file mode 100644
index 00000000000..2f82cd2e2b2
--- /dev/null
+++ b/source/blender/src/vpaint.c
@@ -0,0 +1,1621 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <math.h>
+#include <string.h>
+
+#ifdef WIN32
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "MTC_matrixops.h"
+
+#include "DNA_action_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_brush_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_object_force.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BKE_armature.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_customdata.h"
+#include "BKE_depsgraph.h"
+#include "BKE_deform.h"
+#include "BKE_displist.h"
+#include "BKE_global.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_editview.h"
+#include "BIF_graphics.h"
+#include "BIF_glutil.h"
+#include "BIF_gl.h"
+#include "BIF_interface.h"
+#include "BIF_meshtools.h"
+#include "BIF_mywindow.h"
+#include "BIF_space.h"
+#include "BIF_screen.h"
+#include "BIF_toolbox.h"
+
+#include "BDR_vpaint.h"
+#include "BDR_editobject.h"
+
+#include "BSE_drawview.h"
+#include "BSE_trans_types.h"
+#include "BSE_view.h"
+
+#include "multires.h"
+#include "mydevice.h"
+#include "blendef.h"
+
+#include "BIF_editdeform.h"
+
+ /* Gvp.mode */
+#define VP_MIX 0
+#define VP_ADD 1
+#define VP_SUB 2
+#define VP_MUL 3
+#define VP_FILT 4
+#define VP_LIGHTEN 5
+#define VP_DARKEN 6
+
+#define MAXINDEX 512000
+
+VPaint Gvp= {1.0, 1.0, 1.0, 0.2, 25.0, 1.0, 1.0, 0, VP_AREA+VP_SOFT+VP_SPRAY, 0};
+VPaint Gwp= {1.0, 1.0, 1.0, 0.2, 25.0, 1.0, 1.0, 0, VP_AREA+VP_SOFT, 0};
+
+static int *get_indexarray(void)
+{
+ return MEM_mallocN(sizeof(int)*MAXINDEX + 2, "vertexpaint");
+}
+
+void free_vertexpaint()
+{
+
+ if(Gvp.vpaint_prev) MEM_freeN(Gvp.vpaint_prev);
+ Gvp.vpaint_prev= NULL;
+
+ mesh_octree_table(NULL, NULL, 'e');
+}
+
+/* in contradiction to cpack drawing colors, the MCOL colors (vpaint colors) are per byte!
+ so not endian sensitive. Mcol = ABGR!!! so be cautious with cpack calls */
+
+unsigned int rgba_to_mcol(float r, float g, float b, float a)
+{
+ int ir, ig, ib, ia;
+ unsigned int col;
+ char *cp;
+
+ ir= floor(255.0*r);
+ if(ir<0) ir= 0; else if(ir>255) ir= 255;
+ ig= floor(255.0*g);
+ if(ig<0) ig= 0; else if(ig>255) ig= 255;
+ ib= floor(255.0*b);
+ if(ib<0) ib= 0; else if(ib>255) ib= 255;
+ ia= floor(255.0*a);
+ if(ia<0) ia= 0; else if(ia>255) ia= 255;
+
+ cp= (char *)&col;
+ cp[0]= ia;
+ cp[1]= ib;
+ cp[2]= ig;
+ cp[3]= ir;
+
+ return col;
+
+}
+
+static unsigned int vpaint_get_current_col(VPaint *vp)
+{
+ return rgba_to_mcol(vp->r, vp->g, vp->b, 1.0f);
+}
+
+void do_shared_vertexcol(Mesh *me)
+{
+ /* if no mcol: do not do */
+ /* if tface: only the involved faces, otherwise all */
+ MFace *mface;
+ MTFace *tface;
+ int a;
+ short *scolmain, *scol;
+ char *mcol;
+
+ if(me->mcol==0 || me->totvert==0 || me->totface==0) return;
+
+ scolmain= MEM_callocN(4*sizeof(short)*me->totvert, "colmain");
+
+ tface= me->mtface;
+ mface= me->mface;
+ mcol= (char *)me->mcol;
+ for(a=me->totface; a>0; a--, mface++, mcol+=16) {
+ if((tface && tface->mode & TF_SHAREDCOL) || (G.f & G_FACESELECT)==0) {
+ scol= scolmain+4*mface->v1;
+ scol[0]++; scol[1]+= mcol[1]; scol[2]+= mcol[2]; scol[3]+= mcol[3];
+ scol= scolmain+4*mface->v2;
+ scol[0]++; scol[1]+= mcol[5]; scol[2]+= mcol[6]; scol[3]+= mcol[7];
+ scol= scolmain+4*mface->v3;
+ scol[0]++; scol[1]+= mcol[9]; scol[2]+= mcol[10]; scol[3]+= mcol[11];
+ if(mface->v4) {
+ scol= scolmain+4*mface->v4;
+ scol[0]++; scol[1]+= mcol[13]; scol[2]+= mcol[14]; scol[3]+= mcol[15];
+ }
+ }
+ if(tface) tface++;
+ }
+
+ a= me->totvert;
+ scol= scolmain;
+ while(a--) {
+ if(scol[0]>1) {
+ scol[1]/= scol[0];
+ scol[2]/= scol[0];
+ scol[3]/= scol[0];
+ }
+ scol+= 4;
+ }
+
+ tface= me->mtface;
+ mface= me->mface;
+ mcol= (char *)me->mcol;
+ for(a=me->totface; a>0; a--, mface++, mcol+=16) {
+ if((tface && tface->mode & TF_SHAREDCOL) || (G.f & G_FACESELECT)==0) {
+ scol= scolmain+4*mface->v1;
+ mcol[1]= scol[1]; mcol[2]= scol[2]; mcol[3]= scol[3];
+ scol= scolmain+4*mface->v2;
+ mcol[5]= scol[1]; mcol[6]= scol[2]; mcol[7]= scol[3];
+ scol= scolmain+4*mface->v3;
+ mcol[9]= scol[1]; mcol[10]= scol[2]; mcol[11]= scol[3];
+ if(mface->v4) {
+ scol= scolmain+4*mface->v4;
+ mcol[13]= scol[1]; mcol[14]= scol[2]; mcol[15]= scol[3];
+ }
+ }
+ if(tface) tface++;
+ }
+
+ MEM_freeN(scolmain);
+}
+
+void make_vertexcol(int shade) /* single ob */
+{
+ Object *ob;
+ Mesh *me;
+
+ if(G.obedit) {
+ error("Unable to perform function in Edit Mode");
+ return;
+ }
+
+ ob= OBACT;
+ if(!ob || ob->id.lib) return;
+ me= get_mesh(ob);
+ if(me==0) return;
+
+ /* copies from shadedisplist to mcol */
+ if(!me->mcol) {
+ CustomData_add_layer(&me->fdata, CD_MCOL, CD_CALLOC, NULL, me->totface);
+ mesh_update_customdata_pointers(me);
+ }
+
+ if(shade)
+ shadeMeshMCol(ob, me);
+ else
+ memset(me->mcol, 255, 4*sizeof(MCol)*me->totface);
+
+ if (me->mr) multires_load_cols(me);
+
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+
+ allqueue(REDRAWBUTSEDIT, 0);
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+static void copy_vpaint_prev(VPaint *vp, unsigned int *mcol, int tot)
+{
+ if(vp->vpaint_prev) {
+ MEM_freeN(vp->vpaint_prev);
+ vp->vpaint_prev= NULL;
+ }
+ vp->tot= tot;
+
+ if(mcol==NULL || tot==0) return;
+
+ vp->vpaint_prev= MEM_mallocN(4*sizeof(int)*tot, "vpaint_prev");
+ memcpy(vp->vpaint_prev, mcol, 4*sizeof(int)*tot);
+
+}
+
+static void copy_wpaint_prev (VPaint *vp, MDeformVert *dverts, int dcount)
+{
+ if (vp->wpaint_prev) {
+ free_dverts(vp->wpaint_prev, vp->tot);
+ vp->wpaint_prev= NULL;
+ }
+
+ if(dverts && dcount) {
+
+ vp->wpaint_prev = MEM_mallocN (sizeof(MDeformVert)*dcount, "wpaint prev");
+ vp->tot = dcount;
+ copy_dverts (vp->wpaint_prev, dverts, dcount);
+ }
+}
+
+
+void clear_vpaint()
+{
+ Mesh *me;
+ Object *ob;
+ unsigned int *to, paintcol;
+ int a;
+
+ if((G.f & G_VERTEXPAINT)==0) return;
+
+ ob= OBACT;
+ me= get_mesh(ob);
+ if(!ob || ob->id.lib) return;
+
+ if(me==0 || me->mcol==0 || me->totface==0) return;
+
+ paintcol= vpaint_get_current_col(&Gvp);
+
+ to= (unsigned int *)me->mcol;
+ a= 4*me->totface;
+ while(a--) {
+ *to= paintcol;
+ to++;
+ }
+ BIF_undo_push("Clear vertex colors");
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+void clear_vpaint_selectedfaces()
+{
+ Mesh *me;
+ MFace *mf;
+ Object *ob;
+ unsigned int paintcol, *mcol;
+ int i;
+
+ ob= OBACT;
+ me= get_mesh(ob);
+ if(me==0 || me->totface==0) return;
+
+ if(!me->mcol)
+ make_vertexcol(0);
+
+ paintcol= vpaint_get_current_col(&Gvp);
+
+ mf = me->mface;
+ mcol = (unsigned int*)me->mcol;
+ for (i = 0; i < me->totface; i++, mf++, mcol+=4) {
+ if (mf->flag & ME_FACE_SEL) {
+ mcol[0] = paintcol;
+ mcol[1] = paintcol;
+ mcol[2] = paintcol;
+ mcol[3] = paintcol;
+ }
+ }
+
+ BIF_undo_push("Clear vertex colors");
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+
+/* fills in the selected faces with the current weight and vertex group */
+void clear_wpaint_selectedfaces()
+{
+ extern float editbutvweight;
+ float paintweight= editbutvweight;
+ Mesh *me;
+ MFace *mface;
+ Object *ob;
+ MDeformWeight *dw, *uw;
+ int *indexar;
+ int index, vgroup;
+ unsigned int faceverts[5]={0,0,0,0,0};
+ unsigned char i;
+ int vgroup_mirror= -1;
+
+ ob= OBACT;
+ me= ob->data;
+ if(me==0 || me->totface==0 || me->dvert==0 || !me->mface) return;
+
+ indexar= get_indexarray();
+ for(index=0, mface=me->mface; index<me->totface; index++, mface++) {
+ if((mface->flag & ME_FACE_SEL)==0)
+ indexar[index]= 0;
+ else
+ indexar[index]= index+1;
+ }
+
+ vgroup= ob->actdef-1;
+
+ /* directly copied from weight_paint, should probaby split into a seperate function */
+ /* if mirror painting, find the other group */
+ if(Gwp.flag & VP_MIRROR_X) {
+ bDeformGroup *defgroup= BLI_findlink(&ob->defbase, ob->actdef-1);
+ if(defgroup) {
+ bDeformGroup *curdef;
+ int actdef= 0;
+ char name[32];
+
+ BLI_strncpy(name, defgroup->name, 32);
+ bone_flip_name(name, 0); /* 0 = don't strip off number extensions */
+
+ for (curdef = ob->defbase.first; curdef; curdef=curdef->next, actdef++)
+ if (!strcmp(curdef->name, name))
+ break;
+ if(curdef==NULL) {
+ int olddef= ob->actdef; /* tsk, add_defgroup sets the active defgroup */
+ curdef= add_defgroup_name (ob, name);
+ ob->actdef= olddef;
+ }
+
+ if(curdef && curdef!=defgroup)
+ vgroup_mirror= actdef;
+ }
+ }
+ /* end copy from weight_paint*/
+
+ copy_wpaint_prev(&Gwp, me->dvert, me->totvert);
+
+ for(index=0; index<me->totface; index++) {
+ if(indexar[index] && indexar[index]<=me->totface) {
+ mface= me->mface + (indexar[index]-1);
+ /* just so we can loop through the verts */
+ faceverts[0]= mface->v1;
+ faceverts[1]= mface->v2;
+ faceverts[2]= mface->v3;
+ faceverts[3]= mface->v4;
+ for (i=0; i<3 || faceverts[i]; i++) {
+ if(!((me->dvert+faceverts[i])->flag)) {
+ dw= verify_defweight(me->dvert+faceverts[i], vgroup);
+ if(dw) {
+ uw= verify_defweight(Gwp.wpaint_prev+faceverts[i], vgroup);
+ uw->weight= dw->weight; /* set the undio weight */
+ dw->weight= paintweight;
+
+ if(Gwp.flag & VP_MIRROR_X) { /* x mirror painting */
+ int j= mesh_get_x_mirror_vert(ob, faceverts[i]);
+ if(j>=0) {
+ /* copy, not paint again */
+ if(vgroup_mirror != -1) {
+ dw= verify_defweight(me->dvert+j, vgroup_mirror);
+ uw= verify_defweight(Gwp.wpaint_prev+j, vgroup_mirror);
+ } else {
+ dw= verify_defweight(me->dvert+j, vgroup);
+ uw= verify_defweight(Gwp.wpaint_prev+j, vgroup);
+ }
+ uw->weight= dw->weight; /* set the undo weight */
+ dw->weight= paintweight;
+ }
+ }
+ }
+ (me->dvert+faceverts[i])->flag= 1;
+ }
+ }
+ }
+ }
+
+ index=0;
+ while (index<me->totvert) {
+ (me->dvert+index)->flag= 0;
+ index++;
+ }
+
+ MEM_freeN(indexar);
+ copy_wpaint_prev(&Gwp, NULL, 0);
+
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ BIF_undo_push("Set vertex weight");
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+
+void vpaint_dogamma()
+{
+ Mesh *me;
+ Object *ob;
+ float igam, fac;
+ int a, temp;
+ char *cp, gamtab[256];
+
+ if((G.f & G_VERTEXPAINT)==0) return;
+
+ ob= OBACT;
+ me= get_mesh(ob);
+ if(me==0 || me->mcol==0 || me->totface==0) return;
+
+ igam= 1.0/Gvp.gamma;
+ for(a=0; a<256; a++) {
+
+ fac= ((float)a)/255.0;
+ fac= Gvp.mul*pow( fac, igam);
+
+ temp= 255.9*fac;
+
+ if(temp<=0) gamtab[a]= 0;
+ else if(temp>=255) gamtab[a]= 255;
+ else gamtab[a]= temp;
+ }
+
+ a= 4*me->totface;
+ cp= (char *)me->mcol;
+ while(a--) {
+
+ cp[1]= gamtab[ cp[1] ];
+ cp[2]= gamtab[ cp[2] ];
+ cp[3]= gamtab[ cp[3] ];
+
+ cp+= 4;
+ }
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+/* used for both 3d view and image window */
+void sample_vpaint() /* frontbuf */
+{
+ unsigned int col;
+ int x, y;
+ short mval[2];
+ char *cp;
+
+ getmouseco_areawin(mval);
+ x= mval[0]; y= mval[1];
+
+ if(x<0 || y<0) return;
+ if(x>=curarea->winx || y>=curarea->winy) return;
+
+ x+= curarea->winrct.xmin;
+ y+= curarea->winrct.ymin;
+
+ glReadBuffer(GL_FRONT);
+ glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col);
+ glReadBuffer(GL_BACK);
+
+ cp = (char *)&col;
+
+ if(G.f & (G_VERTEXPAINT|G_WEIGHTPAINT)) {
+ Gvp.r= cp[0]/255.0f;
+ Gvp.g= cp[1]/255.0f;
+ Gvp.b= cp[2]/255.0f;
+ }
+ else {
+ Brush *brush= G.scene->toolsettings->imapaint.brush;
+
+ if(brush) {
+ brush->rgb[0]= cp[0]/255.0f;
+ brush->rgb[1]= cp[1]/255.0f;
+ brush->rgb[2]= cp[2]/255.0f;
+
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWIMAGE, 0);
+ }
+ }
+
+ allqueue(REDRAWBUTSEDIT, 0);
+ addqueue(curarea->win, REDRAW, 1); /* needed for when panel is open... */
+}
+
+static unsigned int mcol_blend(unsigned int col1, unsigned int col2, int fac)
+{
+ char *cp1, *cp2, *cp;
+ int mfac;
+ unsigned int col=0;
+
+ if(fac==0) return col1;
+ if(fac>=255) return col2;
+
+ mfac= 255-fac;
+
+ cp1= (char *)&col1;
+ cp2= (char *)&col2;
+ cp= (char *)&col;
+
+ cp[0]= 255;
+ cp[1]= (mfac*cp1[1]+fac*cp2[1])>>8;
+ cp[2]= (mfac*cp1[2]+fac*cp2[2])>>8;
+ cp[3]= (mfac*cp1[3]+fac*cp2[3])>>8;
+
+ return col;
+}
+
+static unsigned int mcol_add(unsigned int col1, unsigned int col2, int fac)
+{
+ char *cp1, *cp2, *cp;
+ int temp;
+ unsigned int col=0;
+
+ if(fac==0) return col1;
+
+ cp1= (char *)&col1;
+ cp2= (char *)&col2;
+ cp= (char *)&col;
+
+ cp[0]= 255;
+ temp= cp1[1] + ((fac*cp2[1])>>8);
+ if(temp>254) cp[1]= 255; else cp[1]= temp;
+ temp= cp1[2] + ((fac*cp2[2])>>8);
+ if(temp>254) cp[2]= 255; else cp[2]= temp;
+ temp= cp1[3] + ((fac*cp2[3])>>8);
+ if(temp>254) cp[3]= 255; else cp[3]= temp;
+
+ return col;
+}
+
+static unsigned int mcol_sub(unsigned int col1, unsigned int col2, int fac)
+{
+ char *cp1, *cp2, *cp;
+ int temp;
+ unsigned int col=0;
+
+ if(fac==0) return col1;
+
+ cp1= (char *)&col1;
+ cp2= (char *)&col2;
+ cp= (char *)&col;
+
+ cp[0]= 255;
+ temp= cp1[1] - ((fac*cp2[1])>>8);
+ if(temp<0) cp[1]= 0; else cp[1]= temp;
+ temp= cp1[2] - ((fac*cp2[2])>>8);
+ if(temp<0) cp[2]= 0; else cp[2]= temp;
+ temp= cp1[3] - ((fac*cp2[3])>>8);
+ if(temp<0) cp[3]= 0; else cp[3]= temp;
+
+ return col;
+}
+
+static unsigned int mcol_mul(unsigned int col1, unsigned int col2, int fac)
+{
+ char *cp1, *cp2, *cp;
+ int mfac;
+ unsigned int col=0;
+
+ if(fac==0) return col1;
+
+ mfac= 255-fac;
+
+ cp1= (char *)&col1;
+ cp2= (char *)&col2;
+ cp= (char *)&col;
+
+ /* first mul, then blend the fac */
+ cp[0]= 255;
+ cp[1]= (mfac*cp1[1] + fac*((cp2[1]*cp1[1])>>8) )>>8;
+ cp[2]= (mfac*cp1[2] + fac*((cp2[2]*cp1[2])>>8) )>>8;
+ cp[3]= (mfac*cp1[3] + fac*((cp2[3]*cp1[3])>>8) )>>8;
+
+
+ return col;
+}
+
+static unsigned int mcol_lighten(unsigned int col1, unsigned int col2, int fac)
+{
+ char *cp1, *cp2, *cp;
+ int mfac;
+ unsigned int col=0;
+
+ if(fac==0) return col1;
+ if(fac>=255) return col2;
+
+ mfac= 255-fac;
+
+ cp1= (char *)&col1;
+ cp2= (char *)&col2;
+ cp= (char *)&col;
+
+ /* See if are lighter, if so mix, else dont do anything.
+ if the paint col is darker then the original, then ignore */
+ if (cp1[1]+cp1[2]+cp1[3] > cp2[1]+cp2[2]+cp2[3])
+ return col1;
+
+ cp[0]= 255;
+ cp[1]= (mfac*cp1[1]+fac*cp2[1])>>8;
+ cp[2]= (mfac*cp1[2]+fac*cp2[2])>>8;
+ cp[3]= (mfac*cp1[3]+fac*cp2[3])>>8;
+
+ return col;
+}
+
+static unsigned int mcol_darken(unsigned int col1, unsigned int col2, int fac)
+{
+ char *cp1, *cp2, *cp;
+ int mfac;
+ unsigned int col=0;
+
+ if(fac==0) return col1;
+ if(fac>=255) return col2;
+
+ mfac= 255-fac;
+
+ cp1= (char *)&col1;
+ cp2= (char *)&col2;
+ cp= (char *)&col;
+
+ /* See if were darker, if so mix, else dont do anything.
+ if the paint col is brighter then the original, then ignore */
+ if (cp1[1]+cp1[2]+cp1[3] < cp2[1]+cp2[2]+cp2[3])
+ return col1;
+
+ cp[0]= 255;
+ cp[1]= (mfac*cp1[1]+fac*cp2[1])>>8;
+ cp[2]= (mfac*cp1[2]+fac*cp2[2])>>8;
+ cp[3]= (mfac*cp1[3]+fac*cp2[3])>>8;
+ return col;
+}
+
+static void vpaint_blend( unsigned int *col, unsigned int *colorig, unsigned int paintcol, int alpha)
+{
+
+ if(Gvp.mode==VP_MIX || Gvp.mode==VP_FILT) *col= mcol_blend( *col, paintcol, alpha);
+ else if(Gvp.mode==VP_ADD) *col= mcol_add( *col, paintcol, alpha);
+ else if(Gvp.mode==VP_SUB) *col= mcol_sub( *col, paintcol, alpha);
+ else if(Gvp.mode==VP_MUL) *col= mcol_mul( *col, paintcol, alpha);
+ else if(Gvp.mode==VP_LIGHTEN) *col= mcol_lighten( *col, paintcol, alpha);
+ else if(Gvp.mode==VP_DARKEN) *col= mcol_darken( *col, paintcol, alpha);
+
+ /* if no spray, clip color adding with colorig & orig alpha */
+ if((Gvp.flag & VP_SPRAY)==0) {
+ unsigned int testcol=0, a;
+ char *cp, *ct, *co;
+
+ alpha= (int)(255.0*Gvp.a);
+
+ if(Gvp.mode==VP_MIX || Gvp.mode==VP_FILT) testcol= mcol_blend( *colorig, paintcol, alpha);
+ else if(Gvp.mode==VP_ADD) testcol= mcol_add( *colorig, paintcol, alpha);
+ else if(Gvp.mode==VP_SUB) testcol= mcol_sub( *colorig, paintcol, alpha);
+ else if(Gvp.mode==VP_MUL) testcol= mcol_mul( *colorig, paintcol, alpha);
+ else if(Gvp.mode==VP_LIGHTEN) testcol= mcol_lighten( *colorig, paintcol, alpha);
+ else if(Gvp.mode==VP_DARKEN) testcol= mcol_darken( *colorig, paintcol, alpha);
+
+ cp= (char *)col;
+ ct= (char *)&testcol;
+ co= (char *)colorig;
+
+ for(a=0; a<4; a++) {
+ if( ct[a]<co[a] ) {
+ if( cp[a]<ct[a] ) cp[a]= ct[a];
+ else if( cp[a]>co[a] ) cp[a]= co[a];
+ }
+ else {
+ if( cp[a]<co[a] ) cp[a]= co[a];
+ else if( cp[a]>ct[a] ) cp[a]= ct[a];
+ }
+ }
+ }
+}
+
+
+static int sample_backbuf_area(VPaint *vp, int *indexar, int totface, int x, int y, float size)
+{
+ unsigned int *rt;
+ struct ImBuf *ibuf;
+ int x1, y1, x2, y2, a, tot=0, index;
+
+ if(totface>=MAXINDEX) return 0;
+
+ if(size>64.0) size= 64.0;
+
+ x1= x-size;
+ x2= x+size;
+ CLAMP(x1, 0, curarea->winx-1);
+ CLAMP(x2, 0, curarea->winx-1);
+ y1= y-size;
+ y2= y+size;
+ CLAMP(y1, 0, curarea->winy-1);
+ CLAMP(y2, 0, curarea->winy-1);
+#ifdef __APPLE__
+ glReadBuffer(GL_AUX0);
+#endif
+
+ if(x1>=x2 || y1>=y2) return 0;
+
+ ibuf = IMB_allocImBuf(2*size + 4, 2*size + 4, 32, IB_rect, 0);
+ glReadPixels(x1+curarea->winrct.xmin, y1+curarea->winrct.ymin, x2-x1+1, y2-y1+1, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
+ glReadBuffer(GL_BACK);
+
+ if(G.order==B_ENDIAN) {
+ IMB_convert_rgba_to_abgr(ibuf);
+ }
+
+ rt= ibuf->rect;
+ size= (y2-y1)*(x2-x1);
+ if(size<=0) return 0;
+
+ memset(indexar, 0, sizeof(int)*totface+2); /* plus 2! first element is total */
+
+ while(size--) {
+
+ if(*rt) {
+ index= framebuffer_to_index(*rt);
+ if(index>0 && index<=totface)
+ indexar[index] = 1;
+ }
+
+ rt++;
+ }
+
+ for(a=1; a<=totface; a++) {
+ if(indexar[a]) indexar[tot++]= a;
+ }
+
+ IMB_freeImBuf(ibuf);
+
+ return tot;
+}
+
+static int calc_vp_alpha_dl(VPaint *vp, float vpimat[][3], float *vert_nor, short *mval)
+{
+ float fac, dx, dy;
+ int alpha;
+ short vertco[2];
+
+ if(vp->flag & VP_SOFT) {
+ project_short_noclip(vert_nor, vertco);
+ dx= mval[0]-vertco[0];
+ dy= mval[1]-vertco[1];
+
+ fac= sqrt(dx*dx + dy*dy);
+ if(fac > vp->size) return 0;
+ if(vp->flag & VP_HARD)
+ alpha= 255;
+ else
+ alpha= 255.0*vp->a*(1.0-fac/vp->size);
+ }
+ else {
+ alpha= 255.0*vp->a;
+ }
+
+ if(vp->flag & VP_NORMALS) {
+ float *no= vert_nor+3;
+
+ /* transpose ! */
+ fac= vpimat[2][0]*no[0]+vpimat[2][1]*no[1]+vpimat[2][2]*no[2];
+ if(fac>0.0) {
+ dx= vpimat[0][0]*no[0]+vpimat[0][1]*no[1]+vpimat[0][2]*no[2];
+ dy= vpimat[1][0]*no[0]+vpimat[1][1]*no[1]+vpimat[1][2]*no[2];
+
+ alpha*= fac/sqrt(dx*dx + dy*dy + fac*fac);
+ }
+ else return 0;
+ }
+
+ return alpha;
+}
+
+static void wpaint_blend(MDeformWeight *dw, MDeformWeight *uw, float alpha, float paintval)
+{
+
+ if(dw==NULL || uw==NULL) return;
+
+ if(Gwp.mode==VP_MIX || Gwp.mode==VP_FILT)
+ dw->weight = paintval*alpha + dw->weight*(1.0-alpha);
+ else if(Gwp.mode==VP_ADD)
+ dw->weight += paintval*alpha;
+ else if(Gwp.mode==VP_SUB)
+ dw->weight -= paintval*alpha;
+ else if(Gwp.mode==VP_MUL)
+ /* first mul, then blend the fac */
+ dw->weight = ((1.0-alpha) + alpha*paintval)*dw->weight;
+ else if(Gwp.mode==VP_LIGHTEN) {
+ if (dw->weight < paintval)
+ dw->weight = paintval*alpha + dw->weight*(1.0-alpha);
+ } else if(Gwp.mode==VP_DARKEN) {
+ if (dw->weight > paintval)
+ dw->weight = paintval*alpha + dw->weight*(1.0-alpha);
+ }
+ CLAMP(dw->weight, 0.0f, 1.0f);
+
+ /* if no spray, clip result with orig weight & orig alpha */
+ if((Gwp.flag & VP_SPRAY)==0) {
+ float testw=0.0f;
+
+ alpha= Gwp.a;
+ if(Gwp.mode==VP_MIX || Gwp.mode==VP_FILT)
+ testw = paintval*alpha + uw->weight*(1.0-alpha);
+ else if(Gwp.mode==VP_ADD)
+ testw = uw->weight + paintval*alpha;
+ else if(Gwp.mode==VP_SUB)
+ testw = uw->weight - paintval*alpha;
+ else if(Gwp.mode==VP_MUL)
+ /* first mul, then blend the fac */
+ testw = ((1.0-alpha) + alpha*paintval)*uw->weight;
+ else if(Gwp.mode==VP_LIGHTEN) {
+ if (uw->weight < paintval)
+ testw = paintval*alpha + uw->weight*(1.0-alpha);
+ else
+ testw = uw->weight;
+ } else if(Gwp.mode==VP_DARKEN) {
+ if (uw->weight > paintval)
+ testw = paintval*alpha + uw->weight*(1.0-alpha);
+ else
+ testw = uw->weight;
+ }
+ CLAMP(testw, 0.0f, 1.0f);
+
+ if( testw<uw->weight ) {
+ if(dw->weight < testw) dw->weight= testw;
+ else if(dw->weight > uw->weight) dw->weight= uw->weight;
+ }
+ else {
+ if(dw->weight > testw) dw->weight= testw;
+ else if(dw->weight < uw->weight) dw->weight= uw->weight;
+ }
+ }
+
+}
+
+/* ----------------------------------------------------- */
+
+/* used for 3d view, on active object, assumes me->dvert exists */
+/* if mode==1: */
+/* samples cursor location, and gives menu with vertex groups to activate */
+/* else */
+/* sets editbutvweight to the closest weight value to vertex */
+/* note: we cant sample frontbuf, weight colors are interpolated too unpredictable */
+static void sample_wpaint(int mode)
+{
+ Object *ob= OBACT;
+ Mesh *me= get_mesh(ob);
+ int index;
+ short mval[2], sco[2];
+
+ if (!me) return;
+
+ getmouseco_areawin(mval);
+ index= sample_backbuf(mval[0], mval[1]);
+
+ if(index && index<=me->totface) {
+ MFace *mface;
+
+ mface= ((MFace *)me->mface) + index-1;
+
+ if(mode==1) { /* sampe which groups are in here */
+ MDeformVert *dv;
+ int a, totgroup;
+
+ totgroup= BLI_countlist(&ob->defbase);
+ if(totgroup) {
+ int totmenu=0;
+ int *groups=MEM_callocN(totgroup*sizeof(int), "groups");
+
+ dv= me->dvert+mface->v1;
+ for(a=0; a<dv->totweight; a++) {
+ if (dv->dw[a].def_nr<totgroup)
+ groups[dv->dw[a].def_nr]= 1;
+ }
+ dv= me->dvert+mface->v2;
+ for(a=0; a<dv->totweight; a++) {
+ if (dv->dw[a].def_nr<totgroup)
+ groups[dv->dw[a].def_nr]= 1;
+ }
+ dv= me->dvert+mface->v3;
+ for(a=0; a<dv->totweight; a++) {
+ if (dv->dw[a].def_nr<totgroup)
+ groups[dv->dw[a].def_nr]= 1;
+ }
+ if(mface->v4) {
+ dv= me->dvert+mface->v4;
+ for(a=0; a<dv->totweight; a++) {
+ if (dv->dw[a].def_nr<totgroup)
+ groups[dv->dw[a].def_nr]= 1;
+ }
+ }
+ for(a=0; a<totgroup; a++)
+ if(groups[a]) totmenu++;
+
+ if(totmenu==0) {
+ notice("No Vertex Group Selected");
+ }
+ else {
+ bDeformGroup *dg;
+ short val;
+ char item[40], *str= MEM_mallocN(40*totmenu+40, "menu");
+
+ strcpy(str, "Vertex Groups %t");
+ for(a=0, dg=ob->defbase.first; dg && a<totgroup; a++, dg= dg->next) {
+ if(groups[a]) {
+ sprintf(item, "|%s %%x%d", dg->name, a);
+ strcat(str, item);
+ }
+ }
+
+ val= pupmenu(str);
+ if(val>=0) {
+ ob->actdef= val+1;
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWOOPS, 0);
+ allqueue(REDRAWBUTSEDIT, 0);
+ }
+ MEM_freeN(str);
+ }
+ MEM_freeN(groups);
+ }
+ else notice("No Vertex Groups in Object");
+ }
+ else {
+ DerivedMesh *dm;
+ MDeformWeight *dw;
+ extern float editbutvweight;
+ float w1, w2, w3, w4, co[3], fac;
+
+ dm = mesh_get_derived_final(ob, CD_MASK_BAREMESH);
+ if(dm->getVertCo==NULL) {
+ notice("Not supported yet");
+ }
+ else {
+ /* calc 3 or 4 corner weights */
+ dm->getVertCo(dm, mface->v1, co);
+ project_short_noclip(co, sco);
+ w1= ((mval[0]-sco[0])*(mval[0]-sco[0]) + (mval[1]-sco[1])*(mval[1]-sco[1]));
+
+ dm->getVertCo(dm, mface->v2, co);
+ project_short_noclip(co, sco);
+ w2= ((mval[0]-sco[0])*(mval[0]-sco[0]) + (mval[1]-sco[1])*(mval[1]-sco[1]));
+
+ dm->getVertCo(dm, mface->v3, co);
+ project_short_noclip(co, sco);
+ w3= ((mval[0]-sco[0])*(mval[0]-sco[0]) + (mval[1]-sco[1])*(mval[1]-sco[1]));
+
+ if(mface->v4) {
+ dm->getVertCo(dm, mface->v4, co);
+ project_short_noclip(co, sco);
+ w4= ((mval[0]-sco[0])*(mval[0]-sco[0]) + (mval[1]-sco[1])*(mval[1]-sco[1]));
+ }
+ else w4= 1.0e10;
+
+ fac= MIN4(w1, w2, w3, w4);
+ if(w1==fac) {
+ dw= get_defweight(me->dvert+mface->v1, ob->actdef-1);
+ if(dw) editbutvweight= dw->weight; else editbutvweight= 0.0f;
+ }
+ else if(w2==fac) {
+ dw= get_defweight(me->dvert+mface->v2, ob->actdef-1);
+ if(dw) editbutvweight= dw->weight; else editbutvweight= 0.0f;
+ }
+ else if(w3==fac) {
+ dw= get_defweight(me->dvert+mface->v3, ob->actdef-1);
+ if(dw) editbutvweight= dw->weight; else editbutvweight= 0.0f;
+ }
+ else if(w4==fac) {
+ if(mface->v4) {
+ dw= get_defweight(me->dvert+mface->v4, ob->actdef-1);
+ if(dw) editbutvweight= dw->weight; else editbutvweight= 0.0f;
+ }
+ }
+ }
+ dm->release(dm);
+ }
+
+ }
+ allqueue(REDRAWBUTSEDIT, 0);
+
+}
+
+static void do_weight_paint_vertex(Object *ob, int index, int alpha, float paintweight, int vgroup_mirror)
+{
+ Mesh *me= ob->data;
+ MDeformWeight *dw, *uw;
+ int vgroup= ob->actdef-1;
+
+ if(Gwp.flag & VP_ONLYVGROUP) {
+ dw= get_defweight(me->dvert+index, vgroup);
+ uw= get_defweight(Gwp.wpaint_prev+index, vgroup);
+ }
+ else {
+ dw= verify_defweight(me->dvert+index, vgroup);
+ uw= verify_defweight(Gwp.wpaint_prev+index, vgroup);
+ }
+ if(dw==NULL || uw==NULL)
+ return;
+
+ wpaint_blend(dw, uw, (float)alpha/255.0, paintweight);
+
+ if(Gwp.flag & VP_MIRROR_X) { /* x mirror painting */
+ int j= mesh_get_x_mirror_vert(ob, index);
+ if(j>=0) {
+ /* copy, not paint again */
+ if(vgroup_mirror != -1)
+ uw= verify_defweight(me->dvert+j, vgroup_mirror);
+ else
+ uw= verify_defweight(me->dvert+j, vgroup);
+
+ uw->weight= dw->weight;
+ }
+ }
+}
+
+void weight_paint(void)
+{
+ extern float editbutvweight;
+ Object *ob;
+ Mesh *me;
+ MFace *mface;
+ float mat[4][4], imat[4][4], paintweight, *vertexcosnos;
+ float vpimat[3][3];
+ int *indexar, index, totindex, alpha, totw;
+ int vgroup_mirror= -1;
+ short mval[2], mvalo[2], firsttime=1;
+
+ if((G.f & G_WEIGHTPAINT)==0) return;
+ if(G.obedit) return;
+ if(multires_level1_test()) return;
+
+ ob= OBACT;
+ if(!ob || ob->id.lib) return;
+
+ me= get_mesh(ob);
+ if(me==NULL || me->totface==0) return;
+
+ /* if nothing was added yet, we make dverts and a vertex deform group */
+ if (!me->dvert)
+ create_dverts(&me->id);
+
+ if(G.qual & LR_CTRLKEY) {
+ sample_wpaint(0);
+ return;
+ }
+ if(G.qual & LR_SHIFTKEY) {
+ sample_wpaint(1);
+ return;
+ }
+
+ /* ALLOCATIONS! no return after this line */
+ /* painting on subsurfs should give correct points too, this returns me->totvert amount */
+ vertexcosnos= mesh_get_mapped_verts_nors(ob);
+ indexar= get_indexarray();
+ copy_wpaint_prev(&Gwp, me->dvert, me->totvert);
+
+ /* this happens on a Bone select, when no vgroup existed yet */
+ if(ob->actdef<=0) {
+ Object *modob;
+ if((modob = modifiers_isDeformedByArmature(ob))) {
+ bPoseChannel *pchan;
+ for(pchan= modob->pose->chanbase.first; pchan; pchan= pchan->next)
+ if(pchan->bone->flag & SELECT)
+ break;
+ if(pchan) {
+ bDeformGroup *dg= get_named_vertexgroup(ob, pchan->name);
+ if(dg==NULL)
+ dg= add_defgroup_name(ob, pchan->name); /* sets actdef */
+ else
+ ob->actdef= get_defgroup_num(ob, dg);
+ allqueue(REDRAWBUTSEDIT, 0);
+ }
+ }
+ }
+ if(ob->defbase.first==NULL) {
+ add_defgroup(ob);
+ allqueue(REDRAWBUTSEDIT, 0);
+ }
+
+ if(ob->lay & G.vd->lay); else error("Active object is not in this layer");
+
+ persp(PERSP_VIEW);
+ /* imat for normals */
+ Mat4MulMat4(mat, ob->obmat, G.vd->viewmat);
+ Mat4Invert(imat, mat);
+ Mat3CpyMat4(vpimat, imat);
+
+ /* load projection matrix */
+ mymultmatrix(ob->obmat);
+ mygetsingmatrix(mat);
+ myloadmatrix(G.vd->viewmat);
+
+ getmouseco_areawin(mvalo);
+
+ getmouseco_areawin(mval);
+ mvalo[0]= mval[0];
+ mvalo[1]= mval[1];
+
+ /* if mirror painting, find the other group */
+ if(Gwp.flag & VP_MIRROR_X) {
+ bDeformGroup *defgroup= BLI_findlink(&ob->defbase, ob->actdef-1);
+ if(defgroup) {
+ bDeformGroup *curdef;
+ int actdef= 0;
+ char name[32];
+
+ BLI_strncpy(name, defgroup->name, 32);
+ bone_flip_name(name, 0); /* 0 = don't strip off number extensions */
+
+ for (curdef = ob->defbase.first; curdef; curdef=curdef->next, actdef++)
+ if (!strcmp(curdef->name, name))
+ break;
+ if(curdef==NULL) {
+ int olddef= ob->actdef; /* tsk, add_defgroup sets the active defgroup */
+ curdef= add_defgroup_name (ob, name);
+ ob->actdef= olddef;
+ }
+
+ if(curdef && curdef!=defgroup)
+ vgroup_mirror= actdef;
+ }
+ }
+
+ while (get_mbut() & L_MOUSE) {
+ getmouseco_areawin(mval);
+
+ if(firsttime || mval[0]!=mvalo[0] || mval[1]!=mvalo[1]) {
+ firsttime= 0;
+
+ /* which faces are involved */
+ if(Gwp.flag & VP_AREA) {
+ totindex= sample_backbuf_area(&Gwp, indexar, me->totface, mval[0], mval[1], Gwp.size);
+ }
+ else {
+ indexar[0]= sample_backbuf(mval[0], mval[1]);
+ if(indexar[0]) totindex= 1;
+ else totindex= 0;
+ }
+
+ MTC_Mat4SwapMat4(G.vd->persmat, mat);
+
+ if(Gwp.flag & VP_COLINDEX) {
+ for(index=0; index<totindex; index++) {
+ if(indexar[index] && indexar[index]<=me->totface) {
+
+ mface= ((MFace *)me->mface) + (indexar[index]-1);
+
+ if(mface->mat_nr!=ob->actcol-1) {
+ indexar[index]= 0;
+ }
+ }
+ }
+ }
+
+ if((G.f & G_FACESELECT) && me->mface) {
+ for(index=0; index<totindex; index++) {
+ if(indexar[index] && indexar[index]<=me->totface) {
+
+ mface= ((MFace *)me->mface) + (indexar[index]-1);
+
+ if((mface->flag & ME_FACE_SEL)==0) {
+ indexar[index]= 0;
+ }
+ }
+ }
+ }
+
+ /* make sure each vertex gets treated only once */
+ /* and calculate filter weight */
+ totw= 0;
+ if(Gwp.mode==VP_FILT)
+ paintweight= 0.0f;
+ else
+ paintweight= editbutvweight;
+
+ for(index=0; index<totindex; index++) {
+ if(indexar[index] && indexar[index]<=me->totface) {
+ mface= me->mface + (indexar[index]-1);
+
+ (me->dvert+mface->v1)->flag= 1;
+ (me->dvert+mface->v2)->flag= 1;
+ (me->dvert+mface->v3)->flag= 1;
+ if(mface->v4) (me->dvert+mface->v4)->flag= 1;
+
+ if(Gwp.mode==VP_FILT) {
+ MDeformWeight *dw, *(*dw_func)(MDeformVert *, int) = verify_defweight;
+
+ if(Gwp.flag & VP_ONLYVGROUP)
+ dw_func= get_defweight;
+
+ dw= dw_func(me->dvert+mface->v1, ob->actdef-1);
+ if(dw) {paintweight+= dw->weight; totw++;}
+ dw= dw_func(me->dvert+mface->v2, ob->actdef-1);
+ if(dw) {paintweight+= dw->weight; totw++;}
+ dw= dw_func(me->dvert+mface->v3, ob->actdef-1);
+ if(dw) {paintweight+= dw->weight; totw++;}
+ if(mface->v4) {
+ dw= dw_func(me->dvert+mface->v4, ob->actdef-1);
+ if(dw) {paintweight+= dw->weight; totw++;}
+ }
+ }
+ }
+ }
+
+ if(Gwp.mode==VP_FILT)
+ paintweight/= (float)totw;
+
+ for(index=0; index<totindex; index++) {
+
+ if(indexar[index] && indexar[index]<=me->totface) {
+ mface= me->mface + (indexar[index]-1);
+
+ if((me->dvert+mface->v1)->flag) {
+ alpha= calc_vp_alpha_dl(&Gwp, vpimat, vertexcosnos+6*mface->v1, mval);
+ if(alpha) {
+ do_weight_paint_vertex(ob, mface->v1, alpha, paintweight, vgroup_mirror);
+ }
+ (me->dvert+mface->v1)->flag= 0;
+ }
+
+ if((me->dvert+mface->v2)->flag) {
+ alpha= calc_vp_alpha_dl(&Gwp, vpimat, vertexcosnos+6*mface->v2, mval);
+ if(alpha) {
+ do_weight_paint_vertex(ob, mface->v2, alpha, paintweight, vgroup_mirror);
+ }
+ (me->dvert+mface->v2)->flag= 0;
+ }
+
+ if((me->dvert+mface->v3)->flag) {
+ alpha= calc_vp_alpha_dl(&Gwp, vpimat, vertexcosnos+6*mface->v3, mval);
+ if(alpha) {
+ do_weight_paint_vertex(ob, mface->v3, alpha, paintweight, vgroup_mirror);
+ }
+ (me->dvert+mface->v3)->flag= 0;
+ }
+
+ if((me->dvert+mface->v4)->flag) {
+ if(mface->v4) {
+ alpha= calc_vp_alpha_dl(&Gwp, vpimat, vertexcosnos+6*mface->v4, mval);
+ if(alpha) {
+ do_weight_paint_vertex(ob, mface->v4, alpha, paintweight, vgroup_mirror);
+ }
+ (me->dvert+mface->v4)->flag= 0;
+ }
+ }
+ }
+ }
+
+ MTC_Mat4SwapMat4(G.vd->persmat, mat);
+
+ }
+ else BIF_wait_for_statechange();
+
+ if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1]) {
+
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ scrarea_do_windraw(curarea);
+
+ if(Gwp.flag & (VP_AREA|VP_SOFT)) {
+ /* draw circle in backbuf! */
+ persp(PERSP_WIN);
+ fdrawXORcirc((float)mval[0], (float)mval[1], Gwp.size);
+ persp(PERSP_VIEW);
+ }
+
+ screen_swapbuffers();
+ backdrawview3d(0);
+
+ mvalo[0]= mval[0];
+ mvalo[1]= mval[1];
+ }
+ }
+
+ if(vertexcosnos)
+ MEM_freeN(vertexcosnos);
+ MEM_freeN(indexar);
+ copy_wpaint_prev(&Gwp, NULL, 0);
+
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ /* this flag is event for softbody to refresh weightpaint values */
+ if(ob->soft) ob->softflag |= OB_SB_REDO;
+
+ BIF_undo_push("Weight Paint");
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+void vertex_paint()
+{
+ Object *ob;
+ Mesh *me;
+ MFace *mface;
+ float mat[4][4], imat[4][4], *vertexcosnos;
+ float vpimat[3][3];
+ unsigned int paintcol=0, *mcol, *mcolorig, fcol1, fcol2;
+ int *indexar, index, alpha, totindex;
+ short mval[2], mvalo[2], firsttime=1;
+
+ if((G.f & G_VERTEXPAINT)==0) return;
+ if(G.obedit) return;
+
+ ob= OBACT;
+ if(!ob || ob->id.lib) return;
+
+ me= get_mesh(ob);
+ if(me==NULL || me->totface==0) return;
+ if(ob->lay & G.vd->lay); else error("Active object is not in this layer");
+
+ if(me->mcol==NULL) make_vertexcol(1);
+
+ if(me->mcol==NULL) return;
+
+ /* ALLOCATIONS! No return after his line */
+
+ /* painting on subsurfs should give correct points too, this returns me->totvert amount */
+ vertexcosnos= mesh_get_mapped_verts_nors(ob);
+ indexar= get_indexarray();
+ copy_vpaint_prev(&Gvp, (unsigned int *)me->mcol, me->totface);
+
+ /* opengl/matrix stuff */
+ persp(PERSP_VIEW);
+ /* imat for normals */
+ Mat4MulMat4(mat, ob->obmat, G.vd->viewmat);
+ Mat4Invert(imat, mat);
+ Mat3CpyMat4(vpimat, imat);
+
+ /* load projection matrix */
+ mymultmatrix(ob->obmat);
+ mygetsingmatrix(mat);
+ myloadmatrix(G.vd->viewmat);
+
+ paintcol= vpaint_get_current_col(&Gvp);
+
+ getmouseco_areawin(mvalo);
+
+ getmouseco_areawin(mval);
+ mvalo[0]= mval[0];
+ mvalo[1]= mval[1];
+
+ while (get_mbut() & L_MOUSE) {
+ getmouseco_areawin(mval);
+
+ if(firsttime || mval[0]!=mvalo[0] || mval[1]!=mvalo[1]) {
+
+ firsttime= 0;
+
+ /* which faces are involved */
+ if(Gvp.flag & VP_AREA) {
+ totindex= sample_backbuf_area(&Gvp, indexar, me->totface, mval[0], mval[1], Gvp.size);
+ }
+ else {
+ indexar[0]= sample_backbuf(mval[0], mval[1]);
+ if(indexar[0]) totindex= 1;
+ else totindex= 0;
+ }
+
+ MTC_Mat4SwapMat4(G.vd->persmat, mat);
+
+ if(Gvp.flag & VP_COLINDEX) {
+ for(index=0; index<totindex; index++) {
+ if(indexar[index] && indexar[index]<=me->totface) {
+
+ mface= ((MFace *)me->mface) + (indexar[index]-1);
+
+ if(mface->mat_nr!=ob->actcol-1) {
+ indexar[index]= 0;
+ }
+ }
+ }
+ }
+ if((G.f & G_FACESELECT) && me->mface) {
+ for(index=0; index<totindex; index++) {
+ if(indexar[index] && indexar[index]<=me->totface) {
+ mface= ((MFace *)me->mface) + (indexar[index]-1);
+
+ if((mface->flag & ME_FACE_SEL)==0)
+ indexar[index]= 0;
+ }
+ }
+ }
+
+ for(index=0; index<totindex; index++) {
+
+ if(indexar[index] && indexar[index]<=me->totface) {
+
+ mface= ((MFace *)me->mface) + (indexar[index]-1);
+ mcol= ( (unsigned int *)me->mcol) + 4*(indexar[index]-1);
+ mcolorig= ( (unsigned int *)Gvp.vpaint_prev) + 4*(indexar[index]-1);
+
+ if(Gvp.mode==VP_FILT) {
+ fcol1= mcol_blend( mcol[0], mcol[1], 128);
+ if(mface->v4) {
+ fcol2= mcol_blend( mcol[2], mcol[3], 128);
+ paintcol= mcol_blend( fcol1, fcol2, 128);
+ }
+ else {
+ paintcol= mcol_blend( mcol[2], fcol1, 170);
+ }
+
+ }
+
+ alpha= calc_vp_alpha_dl(&Gvp, vpimat, vertexcosnos+6*mface->v1, mval);
+ if(alpha) vpaint_blend( mcol, mcolorig, paintcol, alpha);
+
+ alpha= calc_vp_alpha_dl(&Gvp, vpimat, vertexcosnos+6*mface->v2, mval);
+ if(alpha) vpaint_blend( mcol+1, mcolorig+1, paintcol, alpha);
+
+ alpha= calc_vp_alpha_dl(&Gvp, vpimat, vertexcosnos+6*mface->v3, mval);
+ if(alpha) vpaint_blend( mcol+2, mcolorig+2, paintcol, alpha);
+
+ if(mface->v4) {
+ alpha= calc_vp_alpha_dl(&Gvp, vpimat, vertexcosnos+6*mface->v4, mval);
+ if(alpha) vpaint_blend( mcol+3, mcolorig+3, paintcol, alpha);
+ }
+ }
+ }
+
+ MTC_Mat4SwapMat4(G.vd->persmat, mat);
+
+ do_shared_vertexcol(me);
+
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+ scrarea_do_windraw(curarea);
+
+ if(Gvp.flag & (VP_AREA|VP_SOFT)) {
+ /* draw circle in backbuf! */
+ persp(PERSP_WIN);
+ fdrawXORcirc((float)mval[0], (float)mval[1], Gvp.size);
+ persp(PERSP_VIEW);
+ }
+ screen_swapbuffers();
+ backdrawview3d(0);
+
+ mvalo[0]= mval[0];
+ mvalo[1]= mval[1];
+ }
+ else BIF_wait_for_statechange();
+ }
+
+ if(vertexcosnos)
+ MEM_freeN(vertexcosnos);
+ MEM_freeN(indexar);
+
+ /* frees prev buffer */
+ copy_vpaint_prev(&Gvp, NULL, 0);
+
+ BIF_undo_push("Vertex Paint");
+
+ allqueue(REDRAWVIEW3D, 0);
+}
+
+void set_wpaint(void) /* toggle */
+{
+ Object *ob;
+ Mesh *me;
+
+ scrarea_queue_headredraw(curarea);
+ ob= OBACT;
+ if(!ob || ob->id.lib) return;
+ me= get_mesh(ob);
+
+ if(me && me->totface>=MAXINDEX) {
+ error("Maximum number of faces: %d", MAXINDEX-1);
+ G.f &= ~G_WEIGHTPAINT;
+ return;
+ }
+
+ if(G.f & G_WEIGHTPAINT) G.f &= ~G_WEIGHTPAINT;
+ else G.f |= G_WEIGHTPAINT;
+
+ allqueue(REDRAWVIEW3D, 1); /* including header */
+ allqueue(REDRAWBUTSEDIT, 0);
+
+ /* Weightpaint works by overriding colors in mesh,
+ * so need to make sure we recalc on enter and
+ * exit (exit needs doing regardless because we
+ * should redeform).
+ */
+ if (me) {
+ DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA);
+ }
+
+ if(G.f & G_WEIGHTPAINT) {
+ Object *par;
+
+ setcursor_space(SPACE_VIEW3D, CURSOR_VPAINT);
+
+ mesh_octree_table(ob, NULL, 's');
+
+ /* verify if active weight group is also active bone */
+ par= modifiers_isDeformedByArmature(ob);
+ if(par && (par->flag & OB_POSEMODE)) {
+ bPoseChannel *pchan;
+ for(pchan= par->pose->chanbase.first; pchan; pchan= pchan->next)
+ if(pchan->bone->flag & BONE_ACTIVE)
+ break;
+ if(pchan)
+ vertexgroup_select_by_name(ob, pchan->name);
+ }
+ }
+ else {
+ if(!(G.f & G_FACESELECT))
+ setcursor_space(SPACE_VIEW3D, CURSOR_STD);
+
+ mesh_octree_table(ob, NULL, 'e');
+ }
+}
+
+
+void set_vpaint(void) /* toggle */
+{
+ Object *ob;
+ Mesh *me;
+
+ scrarea_queue_headredraw(curarea);
+ ob= OBACT;
+ if(!ob || object_data_is_libdata(ob)) {
+ G.f &= ~G_VERTEXPAINT;
+ return;
+ }
+
+ me= get_mesh(ob);
+
+ if(me && me->totface>=MAXINDEX) {
+ error("Maximum number of faces: %d", MAXINDEX-1);
+ G.f &= ~G_VERTEXPAINT;
+ return;
+ }
+
+ if(me && me->mcol==NULL) make_vertexcol(1);
+
+ if(G.f & G_VERTEXPAINT){
+ G.f &= ~G_VERTEXPAINT;
+ }
+ else {
+ G.f |= G_VERTEXPAINT;
+ /* Turn off weight painting */
+ if (G.f & G_WEIGHTPAINT)
+ set_wpaint();
+ }
+
+ allqueue(REDRAWVIEW3D, 1); /* including header */
+ allqueue(REDRAWBUTSEDIT, 0);
+
+ if (me)
+ /* update modifier stack for mapping requirements */
+ DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
+
+ if(G.f & G_VERTEXPAINT) {
+ setcursor_space(SPACE_VIEW3D, CURSOR_VPAINT);
+ }
+ else {
+ if((G.f & G_FACESELECT)==0) setcursor_space(SPACE_VIEW3D, CURSOR_STD);
+ }
+}
+
diff --git a/source/blender/src/winlay.h b/source/blender/src/winlay.h
new file mode 100644
index 00000000000..2fdc2c70ac3
--- /dev/null
+++ b/source/blender/src/winlay.h
@@ -0,0 +1,88 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+/* Abstract window operations */
+
+struct BCursor;
+
+typedef struct _Window Window;
+typedef void (*WindowHandlerFP) (Window *win, void *user_data, short evt, short val, char ascii);
+
+Window* window_open (char *title, int x, int y, int width, int height, int start_maximized);
+void window_set_handler (Window *win, WindowHandlerFP handler, void *user_data);
+void window_destroy (Window *win);
+
+void window_set_timer (Window *win, int delay_ms, int event);
+
+void window_make_active (Window *win);
+void window_swap_buffers (Window *win);
+
+#if 0
+//#ifdef _WIN32 // FULLSCREEN
+void window_toggle_fullscreen(Window *win, int fullscreen);
+#endif
+
+void window_raise (Window *win);
+void window_lower (Window *win);
+
+short window_get_qual (Window *win);
+short window_get_mbut (Window *win);
+void window_get_mouse (Window *win, short *mval);
+
+float window_get_pressure(Window *win);
+void window_get_tilt(Window *win, float *xtilt, float *ytilt);
+short window_get_activedevice(Window *win);
+
+void window_get_position (Window *win, int *posx_r, int *poxy_r);
+
+void window_get_size (Window *win, int *width_r, int *height_r);
+void window_set_size (Window *win, int width, int height);
+
+char* window_get_title (Window *win);
+void window_set_title (Window *win, char *title);
+
+void window_set_cursor (Window *win, int cursor);
+void window_set_custom_cursor (Window *win, unsigned char mask[16][2],
+ unsigned char bitmap[16][2], int hotx, int hoty );
+void window_set_custom_cursor_ex (Window *win, struct BCursor *cursor, int useBig);
+
+void window_warp_pointer (Window *win, int x, int y);
+
+void window_queue_redraw (Window *win);
+
+ /* Global windowing operations */
+
+Window* winlay_get_active_window(void);
+
+void winlay_process_events (int wait_for_event);
+
+void winlay_get_screensize (int *width_r, int *height_r);
diff --git a/source/blender/src/writeavicodec.c b/source/blender/src/writeavicodec.c
new file mode 100644
index 00000000000..6ee42d7807a
--- /dev/null
+++ b/source/blender/src/writeavicodec.c
@@ -0,0 +1,835 @@
+/**
+ * Functions for writing windows avi-format files.
+ *
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if defined(_WIN32) && !defined(FREE_WINDOWS)
+
+#define INC_OLE2
+#include <windows.h>
+#undef rad1
+#undef rad2
+
+#include <windowsx.h>
+#include <memory.h>
+#include <mmsystem.h>
+#include <vfw.h>
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+#include "BLI_blenlib.h"
+#include "DNA_userdef_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_global.h"
+#include "BKE_scene.h"
+#include "BKE_writeavi.h"
+
+#include "BIF_toolbox.h"
+
+// this defines the compression type for
+// the output video stream
+
+AVICOMPRESSOPTIONS opts;
+
+static int sframe;
+static PAVIFILE pfile = NULL;
+static int avifileinitdone = 0;
+static PAVISTREAM psUncompressed = NULL, psCompressed = NULL;
+
+// function definitions
+static void init_bmi(BITMAPINFOHEADER *bmi,int rectx, int recty );
+static void opts_to_acd(AviCodecData *acd);
+static void acd_to_opts(AviCodecData *acd);
+static void free_opts_data();
+static int open_avi_codec_file(char * name,RenderData *rd,int rectx, int recty );
+
+///////////////////////////////////////////////////////////////////////////
+//
+// silly default parameters
+//
+///////////////////////////////////////////////////////////////////////////
+
+#define DEFAULT_WIDTH 240
+#define DEFAULT_HEIGHT 120
+#define DEFAULT_LENGTH 100
+#define DEFAULT_SIZE 6
+#define DEFAULT_COLOR RGB(255,0,0)
+#define XSPEED 7
+#define YSPEED 5
+
+///////////////////////////////////////////////////////////////////////////
+//
+// useful macros
+//
+///////////////////////////////////////////////////////////////////////////
+
+#define ALIGNULONG(i) ((i+3)&(~3)) /* ULONG aligned ! */
+#define WIDTHBYTES(i) ((unsigned)((i+31)&(~31))/8) /* ULONG aligned ! */
+#define DIBWIDTHBYTES(bi) (int)WIDTHBYTES((int)(bi).biWidth * (int)(bi).biBitCount)
+#define DIBPTR(lpbi) ((LPBYTE)(lpbi) + \
+ (int)(lpbi)->biSize + \
+ (int)(lpbi)->biClrUsed * sizeof(RGBQUAD) )
+
+///////////////////////////////////////////////////////////////////////////
+//
+// custom video stream instance structure
+//
+///////////////////////////////////////////////////////////////////////////
+
+typedef struct {
+
+ //
+ // The Vtbl must come first
+ //
+ IAVIStreamVtbl * lpvtbl;
+
+ //
+ // private ball instance data
+ //
+ ULONG ulRefCount;
+
+ DWORD fccType; // is this audio/video
+
+ int width; // size in pixels of each frame
+ int height;
+ int length; // length in frames of the pretend AVI movie
+ int size;
+ COLORREF color; // ball color
+
+} AVIBALL, * PAVIBALL;
+
+///////////////////////////////////////////////////////////////////////////
+//
+// custom stream methods
+//
+///////////////////////////////////////////////////////////////////////////
+
+HRESULT STDMETHODCALLTYPE AVIBallQueryInterface(PAVISTREAM ps, REFIID riid, LPVOID * ppvObj);
+HRESULT STDMETHODCALLTYPE AVIBallCreate (PAVISTREAM ps, LONG lParam1, LONG lParam2);
+ULONG STDMETHODCALLTYPE AVIBallAddRef (PAVISTREAM ps);
+ULONG STDMETHODCALLTYPE AVIBallRelease (PAVISTREAM ps);
+HRESULT STDMETHODCALLTYPE AVIBallInfo (PAVISTREAM ps, AVISTREAMINFOW * psi, LONG lSize);
+LONG STDMETHODCALLTYPE AVIBallFindSample (PAVISTREAM ps, LONG lPos, LONG lFlags);
+HRESULT STDMETHODCALLTYPE AVIBallReadFormat (PAVISTREAM ps, LONG lPos, LPVOID lpFormat, LONG *lpcbFormat);
+HRESULT STDMETHODCALLTYPE AVIBallSetFormat (PAVISTREAM ps, LONG lPos, LPVOID lpFormat, LONG cbFormat);
+HRESULT STDMETHODCALLTYPE AVIBallRead (PAVISTREAM ps, LONG lStart, LONG lSamples, LPVOID lpBuffer, LONG cbBuffer, LONG * plBytes,LONG * plSamples);
+HRESULT STDMETHODCALLTYPE AVIBallWrite (PAVISTREAM ps, LONG lStart, LONG lSamples, LPVOID lpBuffer, LONG cbBuffer, DWORD dwFlags, LONG *plSampWritten, LONG *plBytesWritten);
+HRESULT STDMETHODCALLTYPE AVIBallDelete (PAVISTREAM ps, LONG lStart, LONG lSamples);
+HRESULT STDMETHODCALLTYPE AVIBallReadData (PAVISTREAM ps, DWORD fcc, LPVOID lp,LONG *lpcb);
+HRESULT STDMETHODCALLTYPE AVIBallWriteData (PAVISTREAM ps, DWORD fcc, LPVOID lp,LONG cb);
+
+IAVIStreamVtbl AVIBallHandler = {
+ AVIBallQueryInterface,
+ AVIBallAddRef,
+ AVIBallRelease,
+ AVIBallCreate,
+ AVIBallInfo,
+ AVIBallFindSample,
+ AVIBallReadFormat,
+ AVIBallSetFormat,
+ AVIBallRead,
+ AVIBallWrite,
+ AVIBallDelete,
+ AVIBallReadData,
+ AVIBallWriteData
+};
+
+
+//
+// This is the function an application would call to create a PAVISTREAM to
+// reference the ball. Then the standard AVIStream function calls can be
+// used to work with this stream.
+//
+PAVISTREAM WINAPI NewBall(void)
+{
+ static AVIBALL ball;
+ PAVIBALL pball = &ball;
+
+ //
+ // Fill the function table
+ //
+ pball->lpvtbl = &AVIBallHandler;
+
+ //
+ // Call our own create code to create a new instance (calls AVIBallCreate)
+ // For now, don't use any lParams.
+ //
+ pball->lpvtbl->Create((PAVISTREAM) pball, 0, 0);
+
+ return (PAVISTREAM) pball;
+}
+
+///////////////////////////////////////////////////////////////////////////
+//
+// This function is called to initialize an instance of the bouncing ball.
+//
+// When called, we look at the information possibly passed in <lParam1>,
+// if any, and use it to determine the length of movie they want. (Not
+// supported by NewBall right now, but it could be).
+//
+///////////////////////////////////////////////////////////////////////////
+HRESULT STDMETHODCALLTYPE AVIBallCreate(PAVISTREAM ps, LONG lParam1, LONG lParam2)
+{
+ PAVIBALL pball = (PAVIBALL) ps;
+
+ //
+ // what type of data are we? (audio/video/other stream)
+ //
+ pball->fccType = streamtypeVIDEO;
+
+ //
+ // We define lParam1 as being the length of movie they want us to pretend
+ // to be.
+ //
+ if (lParam1)
+ pball->length = (int) lParam1;
+ else
+ pball->length = DEFAULT_LENGTH;
+
+ switch (pball->fccType) {
+
+ case streamtypeVIDEO:
+ pball->color = DEFAULT_COLOR;
+ pball->width = DEFAULT_WIDTH;
+ pball->height = DEFAULT_HEIGHT;
+ pball->size = DEFAULT_SIZE;
+ pball->ulRefCount = 1; // note that we are opened once
+ return AVIERR_OK; // success
+
+ case streamtypeAUDIO:
+ return ResultFromScode(AVIERR_UNSUPPORTED); // we don't do audio
+
+ default:
+ return ResultFromScode(AVIERR_UNSUPPORTED); // or anything else
+ }
+}
+
+
+//
+// Increment our reference count
+//
+ULONG STDMETHODCALLTYPE AVIBallAddRef(PAVISTREAM ps)
+{
+ PAVIBALL pball = (PAVIBALL) ps;
+ return (++pball->ulRefCount);
+}
+
+
+//
+// Decrement our reference count
+//
+ULONG STDMETHODCALLTYPE AVIBallRelease(PAVISTREAM ps)
+{
+ PAVIBALL pball = (PAVIBALL) ps;
+ if (--pball->ulRefCount)
+ return pball->ulRefCount;
+
+ // Free any data we're keeping around - like our private structure
+ GlobalFreePtr(pball);
+
+ return 0;
+}
+
+
+//
+// Fills an AVISTREAMINFO structure
+//
+HRESULT STDMETHODCALLTYPE AVIBallInfo(PAVISTREAM ps, AVISTREAMINFOW * psi, LONG lSize)
+{
+ PAVIBALL pball = (PAVIBALL) ps;
+
+ if (lSize < sizeof(AVISTREAMINFO))
+ return ResultFromScode(AVIERR_BUFFERTOOSMALL);
+
+ _fmemset(psi, 0, (int)lSize);
+
+ // Fill out a stream header with information about us.
+ psi->fccType = pball->fccType;
+ psi->fccHandler = mmioFOURCC('B','a','l','l');
+ psi->dwScale = 1;
+ psi->dwRate = 15;
+ psi->dwLength = pball->length;
+ psi->dwSuggestedBufferSize = pball->height * ALIGNULONG(pball->width);
+ psi->rcFrame.right = pball->width;
+ psi->rcFrame.bottom = pball->height;
+ CopyMemory((PVOID)psi->szName,
+ (PVOID)L"Bouncing ball video",
+ sizeof(L"Bouncing ball video"));
+
+ return AVIERR_OK;
+}
+
+///////////////////////////////////////////////////////////////////////////
+//
+// AVIBallReadFormat: needs to return the format of our data.
+//
+///////////////////////////////////////////////////////////////////////////
+HRESULT STDMETHODCALLTYPE AVIBallReadFormat (PAVISTREAM ps, LONG lPos,LPVOID lpFormat,LONG *lpcbFormat)
+{
+ PAVIBALL pball = (PAVIBALL) ps;
+ LPBITMAPINFO lpbi = (LPBITMAPINFO) lpFormat;
+
+ if (lpFormat == NULL || *lpcbFormat == 0) {
+ *lpcbFormat = sizeof(BITMAPINFOHEADER);
+ return AVIERR_OK;
+ }
+
+ if (*lpcbFormat < sizeof(BITMAPINFOHEADER))
+ return ResultFromScode(AVIERR_BUFFERTOOSMALL);
+
+ // This is a relatively silly example: we build up our
+ // format from scratch every time.
+
+ /*
+ lpbi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ lpbi->bmiHeader.biCompression = BI_RGB;
+ lpbi->bmiHeader.biWidth = pball->width;
+ lpbi->bmiHeader.biHeight = pball->height;
+ lpbi->bmiHeader.biBitCount = 8;
+ lpbi->bmiHeader.biPlanes = 1;
+ lpbi->bmiHeader.biClrUsed = 2;
+ lpbi->bmiHeader.biSizeImage = pball->height * DIBWIDTHBYTES(lpbi->bmiHeader);
+ */
+
+ //init_bmi(&lpbi->bmiHeader);
+
+ memset(&lpbi->bmiHeader, 0, sizeof(BITMAPINFOHEADER));
+ lpbi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ lpbi->bmiHeader.biWidth = pball->width;
+ lpbi->bmiHeader.biHeight = pball->height;
+ lpbi->bmiHeader.biPlanes = 1;
+ lpbi->bmiHeader.biBitCount = 24;
+ lpbi->bmiHeader.biSizeImage = pball->width * pball->height * sizeof(RGBTRIPLE);
+
+ /*
+ lpbi->bmiColors[0].rgbRed = 0;
+ lpbi->bmiColors[0].rgbGreen = 0;
+ lpbi->bmiColors[0].rgbBlue = 0;
+ lpbi->bmiColors[1].rgbRed = GetRValue(pball->color);
+ lpbi->bmiColors[1].rgbGreen = GetGValue(pball->color);
+ lpbi->bmiColors[1].rgbBlue = GetBValue(pball->color);
+ */
+
+ *lpcbFormat = sizeof(BITMAPINFOHEADER);
+
+ return AVIERR_OK;
+}
+
+///////////////////////////////////////////////////////////////////////////
+//
+// AVIBallRead: needs to return the data for a particular frame.
+//
+///////////////////////////////////////////////////////////////////////////
+HRESULT STDMETHODCALLTYPE AVIBallRead (PAVISTREAM ps, LONG lStart,LONG lSamples,LPVOID lpBuffer,LONG cbBuffer,LONG * plBytes,LONG * plSamples)
+{
+ PAVIBALL pball = (PAVIBALL) ps;
+ LONG lSize = pball->height * ALIGNULONG(pball->width); // size of frame
+ // in bytes
+ int x, y;
+ HPSTR hp = lpBuffer;
+ int xPos, yPos;
+
+ // Reject out of range values
+ if (lStart < 0 || lStart >= pball->length)
+ return ResultFromScode(AVIERR_BADPARAM);
+
+ // Did they just want to know the size of our data?
+ if (lpBuffer == NULL || cbBuffer == 0)
+ goto exit;
+
+ // Will our frame fit in the buffer passed?
+ if (lSize > cbBuffer)
+ return ResultFromScode(AVIERR_BUFFERTOOSMALL);
+
+ // Figure out the position of the ball.
+ // It just bounces back and forth.
+
+ xPos = 5 + XSPEED * (int) lStart; // x = x0 + vt
+ xPos = xPos % ((pball->width - pball->size) * 2); // limit to 2xwidth
+ if (xPos > (pball->width - pball->size)) // reflect if
+ xPos = 2 * (pball->width - pball->size) - xPos; // needed
+
+ yPos = 5 + YSPEED * (int) lStart;
+ yPos = yPos % ((pball->height - pball->size) * 2);
+ if (yPos > (pball->height - pball->size))
+ yPos = 2 * (pball->height - pball->size) - yPos;
+
+ //
+ // Build a DIB from scratch by writing in 1's where the ball is, 0's
+ // where it isn't.
+ //
+ // Notice that we just build it in the buffer we've been passed.
+ //
+ // This is pretty ugly, I have to admit.
+ //
+ for (y = 0; y < pball->height; y++)
+ {
+ if (y >= yPos && y < yPos + pball->size)
+ {
+ for (x = 0; x < pball->width; x++)
+ {
+ *hp++ = (BYTE) ((x >= xPos && x < xPos + pball->size) ? 1 : 0);
+ }
+ }
+ else
+ {
+ for (x = 0; x < pball->width; x++)
+ {
+ *hp++ = 0;
+ }
+ }
+
+ hp += pball->width - ALIGNULONG(pball->width);
+ }
+
+exit:
+ // We always return exactly one frame
+ if (plSamples)
+ *plSamples = 1;
+
+ // Return the size of our frame
+ if (plBytes)
+ *plBytes = lSize;
+
+ return AVIERR_OK;
+}
+
+
+HRESULT STDMETHODCALLTYPE AVIBallQueryInterface(PAVISTREAM ps, REFIID riid, LPVOID * ppvObj)
+{
+ PAVIBALL pball = (PAVIBALL) ps;
+
+ // We support the Unknown interface (everybody does) and our Stream
+ // interface.
+
+ if (_fmemcmp(riid, &IID_IUnknown, sizeof(GUID)) == 0)
+ *ppvObj = (LPVOID)pball;
+
+ else if (_fmemcmp(riid, &IID_IAVIStream, sizeof(GUID)) == 0)
+ *ppvObj = (LPVOID)pball;
+
+ else {
+ *ppvObj = NULL;
+ return ResultFromScode(E_NOINTERFACE);
+ }
+
+ AVIBallAddRef(ps);
+
+ return AVIERR_OK;
+}
+
+LONG STDMETHODCALLTYPE AVIBallFindSample (PAVISTREAM ps, LONG lPos, LONG lFlags)
+{
+ // The only format change is frame 0
+ if ((lFlags & FIND_TYPE) == FIND_FORMAT) {
+ if ((lFlags & FIND_DIR) == FIND_NEXT && lPos > 0)
+ return -1; // no more format changes
+ else
+ return 0;
+
+ // FIND_KEY and FIND_ANY always return the same position because
+ // every frame is non-empty and a key frame
+ } else
+ return lPos;
+}
+
+HRESULT STDMETHODCALLTYPE AVIBallReadData (PAVISTREAM ps, DWORD fcc, LPVOID lp, LONG *lpcb)
+{
+ return ResultFromScode(AVIERR_UNSUPPORTED);
+}
+
+HRESULT STDMETHODCALLTYPE AVIBallSetFormat (PAVISTREAM ps, LONG lPos, LPVOID lpFormat, LONG cbFormat)
+{
+ return ResultFromScode(AVIERR_UNSUPPORTED);
+}
+
+HRESULT STDMETHODCALLTYPE AVIBallWriteData (PAVISTREAM ps, DWORD fcc, LPVOID lp, LONG cb)
+{
+ return ResultFromScode(AVIERR_UNSUPPORTED);
+}
+
+HRESULT STDMETHODCALLTYPE AVIBallWrite (PAVISTREAM ps, LONG lStart, LONG lSamples, LPVOID lpBuffer, LONG cbBuffer, DWORD dwFlags, LONG *plSampWritten, LONG *plBytesWritten)
+{
+ return ResultFromScode(AVIERR_UNSUPPORTED);
+}
+
+HRESULT STDMETHODCALLTYPE AVIBallDelete (PAVISTREAM ps, LONG lStart, LONG lSamples)
+{
+ return ResultFromScode(AVIERR_UNSUPPORTED);
+}
+
+
+//////////////////////////////////////
+static void init_bmi(BITMAPINFOHEADER *bmi,int rectx, int recty )
+{
+ memset(bmi, 0, sizeof(BITMAPINFOHEADER));
+ bmi->biSize = sizeof(BITMAPINFOHEADER);
+ bmi->biWidth = rectx;
+ bmi->biHeight = recty;
+ bmi->biPlanes = 1;
+ bmi->biBitCount = 24;
+ bmi->biSizeImage = bmi->biWidth * bmi->biHeight * sizeof(RGBTRIPLE);
+}
+
+
+static void opts_to_acd(AviCodecData *acd)
+{
+ HIC hic;
+ ICINFO icinfo;
+
+ acd->fccType = opts.fccType;
+ acd->fccHandler = opts.fccHandler;
+ acd->dwKeyFrameEvery = opts.dwKeyFrameEvery;
+ acd->dwQuality = opts.dwQuality;
+ acd->dwBytesPerSecond = opts.dwBytesPerSecond;
+ acd->dwFlags = opts.dwFlags;
+ acd->dwInterleaveEvery = opts.dwInterleaveEvery;
+ acd->cbFormat = opts.cbFormat;
+ acd->cbParms = opts.cbParms;
+
+ if (opts.lpFormat && opts.cbFormat) {
+ acd->lpFormat = MEM_mallocN(opts.cbFormat, "avi.lpFormat");
+ memcpy(acd->lpFormat, opts.lpFormat, opts.cbFormat);
+ }
+
+ if (opts.lpParms && opts.cbParms) {
+ acd->lpParms = MEM_mallocN(opts.cbParms, "avi.lpParms");
+ memcpy(acd->lpParms, opts.lpParms, opts.cbParms);
+ }
+
+ if ((hic=ICOpen(ICTYPE_VIDEO,acd->fccHandler,ICMODE_QUERY))!=NULL) {
+ icinfo.dwSize=sizeof(ICINFO);
+ if (ICGetInfo(hic,&icinfo,sizeof(ICINFO))) {
+ WideCharToMultiByte(CP_ACP,0,icinfo.szDescription,-1,acd->avicodecname,128,NULL,NULL);
+ } else
+ sprintf(acd->avicodecname, "undefined");
+ if (ICClose(hic)!=ICERR_OK)
+;// return 0;
+ } else {
+ sprintf(acd->avicodecname, "Full Frames (Uncompressed)"); //heh, nasty
+ }
+}
+
+
+static void acd_to_opts(AviCodecData *acd)
+{
+ memset(&opts, 0, sizeof(opts));
+ if (acd) {
+ opts.fccType = acd->fccType;
+ opts.fccHandler = acd->fccHandler;
+ opts.dwKeyFrameEvery = acd->dwKeyFrameEvery;
+ opts.dwQuality = acd->dwQuality;
+ opts.dwBytesPerSecond = acd->dwBytesPerSecond;
+ opts.dwFlags = acd->dwFlags;
+ opts.dwInterleaveEvery = acd->dwInterleaveEvery;
+ opts.cbFormat = acd->cbFormat;
+ opts.cbParms = acd->cbParms;
+
+ if (acd->lpFormat && acd->cbFormat) {
+ opts.lpFormat = MEM_mallocN(opts.cbFormat, "opts lpFormat");
+ memcpy(opts.lpFormat, acd->lpFormat, opts.cbFormat);
+ }
+
+ if (acd->lpParms && acd->cbParms) {
+ opts.lpParms = MEM_mallocN(opts.cbParms, "opts.cbParms");
+ memcpy(opts.lpParms, acd->lpParms, opts.cbParms);
+ }
+ }
+}
+
+static void free_opts_data()
+{
+ if (opts.lpFormat) {
+ MEM_freeN(opts.lpFormat);
+ opts.lpFormat = NULL;
+ }
+ if (opts.lpParms) {
+ MEM_freeN(opts.lpParms);
+ opts.lpParms = NULL;
+ }
+}
+
+static int open_avi_codec_file(char * name,RenderData *rd,int rectx, int recty )
+{
+ HRESULT hr;
+ WORD wVer;
+ BITMAPINFOHEADER bmi;
+ AVISTREAMINFO strhdr;
+ int ret_val = 0;
+
+ wVer = HIWORD(VideoForWindowsVersion());
+ if (wVer < 0x010a){
+ // this is probably an obsolete check...
+ ret_val = 1;
+ } else {
+ AVIFileInit();
+ avifileinitdone++;
+
+ hr = AVIFileOpen(&pfile, // returned file pointer
+ name, // file name
+ OF_WRITE | OF_CREATE, // mode to open file with
+ NULL); // use handler determined
+
+ if (hr != AVIERR_OK) {
+ ret_val = 1;
+ } else {
+ // initialize the BITMAPINFOHEADER
+ init_bmi(&bmi,rectx,recty);
+ // and associate a stream with the input images
+ memset(&strhdr, 0, sizeof(strhdr));
+ strhdr.fccType = streamtypeVIDEO; // stream type
+ if (G.scene->r.avicodecdata) {
+ strhdr.fccHandler = G.scene->r.avicodecdata->fccHandler;
+ }
+ strhdr.dwScale = 1;
+ strhdr.dwRate = rd->frs_sec;
+ strhdr.dwSuggestedBufferSize = bmi.biSizeImage;
+ SetRect(&strhdr.rcFrame, 0, 0, // rectangle for stream
+ (int) bmi.biWidth,
+ (int) bmi.biHeight);
+
+ // And create the stream
+ hr = AVIFileCreateStream(
+ pfile, // file pointer
+ &psUncompressed,// returned stream pointer
+ &strhdr); // stream header
+
+ if (hr != AVIERR_OK) {
+ ret_val = 1;
+ } else {
+ acd_to_opts(G.scene->r.avicodecdata);
+ }
+ }
+ }
+
+ return(ret_val);
+}
+
+
+void end_avi_codec(void)
+{
+ free_opts_data();
+
+ if (psUncompressed) {
+ AVIStreamClose(psUncompressed);
+ psUncompressed = NULL;
+ }
+
+ if (psCompressed) {
+ AVIStreamClose(psCompressed);
+ psCompressed = NULL;
+ }
+
+ if (pfile) {
+ AVIFileClose(pfile);
+ pfile = NULL;
+ }
+
+ if (avifileinitdone > 0) {
+ AVIFileExit();
+ avifileinitdone--;
+ }
+}
+
+
+void start_avi_codec(RenderData *rd,int rectx, int recty )
+{
+ HRESULT hr;
+ BITMAPINFOHEADER bmi;
+ char name[2048];
+ char bakname[2048];
+
+ makeavistring(rd,name);
+ sframe = (G.scene->r.sfra);
+
+ strcpy(bakname, name);
+ strcat(bakname, ".bak");
+
+ if (BLI_exists(name)) {
+ BLI_move(name, bakname);
+ }
+
+ // initialize the BITMAPINFOHEADER
+ init_bmi(&bmi,rectx,recty);
+
+ if (open_avi_codec_file(name,rd,rectx,recty)) {
+ error("Can not open file %s", name);
+ G.afbreek = 1;
+ } else {
+ // now create a compressed stream from the uncompressed
+ // stream and the compression options
+ hr = AVIMakeCompressedStream(
+ &psCompressed, // returned stream pointer
+ psUncompressed, // uncompressed stream
+ &opts, // compression options
+ NULL); // Unknown...
+ if (hr != AVIERR_OK) {
+ error("Codec is locked or not supported.");
+ G.afbreek = 1;
+ } else {
+ hr = AVIStreamSetFormat(psCompressed, 0,
+ &bmi, // stream format
+ bmi.biSize + // format size
+ bmi.biClrUsed * sizeof(RGBQUAD)); // plus size of colormap
+ if (hr != AVIERR_OK) {
+ printf("AVIStreamSetFormat() failed .. may be bad image dimensions? \n");
+ error("Codec refuses format.");
+ G.afbreek = 1;
+ }
+ }
+ }
+
+ if (G.afbreek != 1) {
+ printf("Created win avi: %s\n", name);
+ if (BLI_exists(bakname)) {
+ BLI_delete(bakname, 0, 0);
+ }
+ } else {
+ // close the darn thing and remove it.
+ end_avi_codec();
+ if (BLI_exists(name)) {
+ BLI_delete(name, 0, 0);
+ }
+ if (BLI_exists(bakname)) {
+ BLI_move(bakname, name);
+ }
+ }
+}
+
+
+void append_avi_codec(int frame,int *pixels,int rectx, int recty)
+{
+ HRESULT hr;
+ BITMAPINFOHEADER bmi;
+ RGBTRIPLE *buffer, *to;
+ int x, y ,pad, align =2;
+ unsigned char *from;
+
+ if (psCompressed) {
+ // initialize the BITMAPINFOHEADER
+ init_bmi(&bmi, rectx, recty);
+
+ //windows wants bitmap rows aligned
+ pad = (rectx*3) - align*((rectx*3)/align);
+ if (pad) {
+ pad = align - pad;
+ }
+
+ // copy pixels
+ buffer = MEM_mallocN(bmi.biSizeImage + pad * recty, "append_win_avi");
+ to = buffer;
+ from = (unsigned char *) pixels;
+ for (y = recty; y > 0 ; y--) {
+ for (x = rectx; x > 0 ; x--) {
+ to->rgbtRed = from[0];
+ to->rgbtGreen = from[1];
+ to->rgbtBlue = from[2];
+ to++; from += 4;
+ }
+ (unsigned char *)to += pad;
+ }
+
+ hr = AVIStreamWrite(
+ psCompressed, // stream pointer
+ frame - sframe, // frame number
+ 1, // number to write
+ (LPBYTE) buffer,// pointer to data
+ bmi.biSizeImage + pad * recty, // size of this frame
+ AVIIF_KEYFRAME, // flags....
+ NULL,
+ NULL);
+
+ MEM_freeN(buffer);
+
+ if (hr != AVIERR_OK) {
+ G.afbreek = 1;
+ } else {
+ printf ("added frame %3d (frame %3d in avi): ", frame, frame-sframe);
+ }
+ }
+}
+
+
+int get_avicodec_settings(void)
+{
+ int ret_val = 0;
+ AVICOMPRESSOPTIONS *aopts[1] = {&opts};
+ AviCodecData *acd = G.scene->r.avicodecdata;
+ static PAVISTREAM psdummy;
+ UINT uiFlags;
+
+ acd_to_opts(G.scene->r.avicodecdata);
+
+ psdummy = NewBall();
+
+ if(U.uiflag & USER_ALLWINCODECS)
+ uiFlags = ICMF_CHOOSE_ALLCOMPRESSORS;
+ else
+ uiFlags = ICMF_CHOOSE_KEYFRAME | ICMF_CHOOSE_DATARATE;
+
+ if (psdummy == NULL) {
+ ret_val = 1;
+ } else {
+ if (!AVISaveOptions(NULL,
+ uiFlags,
+// ICMF_CHOOSE_KEYFRAME | ICMF_CHOOSE_DATARATE,
+// ICMF_CHOOSE_ALLCOMPRESSORS,
+ 1,
+ &psdummy,
+ (LPAVICOMPRESSOPTIONS *) &aopts))
+ {
+ ret_val = 1;
+ } else {
+ if (acd) {
+ free_avicodecdata(acd);
+ } else {
+ acd = G.scene->r.avicodecdata = MEM_callocN(sizeof(AviCodecData), "AviCodecData");
+ }
+
+ opts_to_acd(acd);
+
+ AVISaveOptionsFree(1, aopts);
+ memset(&opts, 0, sizeof(opts));
+ }
+ }
+
+ return(ret_val);
+}
+
+#endif // _WIN32
diff --git a/source/blender/src/writeimage.c b/source/blender/src/writeimage.c
new file mode 100644
index 00000000000..cb3d4158ec1
--- /dev/null
+++ b/source/blender/src/writeimage.c
@@ -0,0 +1,242 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "IMB_imbuf.h"
+#include "IMB_imbuf_types.h" // ImBuf{}
+
+#include "BLI_blenlib.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
+#include "DNA_texture_types.h" // EnvMap{}
+#include "DNA_image_types.h" // Image{}
+
+#include "BKE_global.h" // struct G
+#include "BKE_image.h"
+#include "BKE_utildefines.h" // ELEM
+
+#include "BIF_screen.h" // waitcursor
+#include "BIF_toolbox.h"
+#include "BIF_writeimage.h"
+
+#include "BSE_filesel.h"
+
+#include "RE_pipeline.h"
+
+/* ------------------------------------------------------------------------- */
+
+
+void BIF_save_envmap(EnvMap *env, char *str)
+{
+ ImBuf *ibuf;
+/* extern rectcpy(); */
+ int dx;
+
+ /* all interactive stuff is handled in buttons.c */
+ if(env->cube[0]==NULL) return;
+
+ dx= env->cube[0]->x;
+ ibuf= IMB_allocImBuf(3*dx, 2*dx, 24, IB_rect, 0);
+
+ IMB_rectcpy(ibuf, env->cube[0], 0, 0, 0, 0, dx, dx);
+ IMB_rectcpy(ibuf, env->cube[1], dx, 0, 0, 0, dx, dx);
+ IMB_rectcpy(ibuf, env->cube[2], 2*dx, 0, 0, 0, dx, dx);
+ IMB_rectcpy(ibuf, env->cube[3], 0, dx, 0, 0, dx, dx);
+ IMB_rectcpy(ibuf, env->cube[4], dx, dx, 0, 0, dx, dx);
+ IMB_rectcpy(ibuf, env->cube[5], 2*dx, dx, 0, 0, dx, dx);
+
+ BKE_write_ibuf(ibuf, str, G.scene->r.imtype, G.scene->r.subimtype, G.scene->r.quality);
+ IMB_freeImBuf(ibuf);
+}
+
+
+#define FTOCHAR(val) val<=0.0f?255: 255-(val>=255.0f?255: (char)(val))
+
+/* callback for fileselect to save rendered image, renderresult was checked to exist */
+static void save_rendered_image_cb_real(char *name, int confirm)
+{
+ char str[FILE_MAXDIR+FILE_MAXFILE];
+ int overwrite;
+
+ if(BLI_testextensie(name,".blend")) {
+ error("Wrong filename");
+ return;
+ }
+
+ /* BKE_add_image_extension() checks for if extension was already set */
+ if(G.scene->r.scemode & R_EXTENSION)
+ if(strlen(name)<FILE_MAXDIR+FILE_MAXFILE-5)
+ BKE_add_image_extension(name, G.scene->r.imtype);
+
+ strcpy(str, name);
+ BLI_convertstringcode(str, G.sce, G.scene->r.cfra);
+
+ if (confirm)
+ overwrite = saveover(str);
+ else
+ overwrite = 1;
+
+ if(overwrite) {
+ if(G.scene->r.imtype==R_MULTILAYER) {
+ RenderResult *rr= RE_GetResult(RE_GetRender(G.scene->id.name));
+ if(rr)
+ RE_WriteRenderResult(rr, str, G.scene->r.quality);
+ }
+ else {
+ RenderResult rres;
+ ImBuf *ibuf;
+
+ RE_GetResultImage(RE_GetRender(G.scene->id.name), &rres);
+
+ waitcursor(1); /* from screen.c */
+
+ ibuf= IMB_allocImBuf(rres.rectx, rres.recty, G.scene->r.planes, 0, 0);
+ ibuf->rect= (unsigned int *)rres.rect32;
+ ibuf->rect_float= rres.rectf;
+ ibuf->zbuf_float= rres.rectz;
+
+ /* float factor for random dither, imbuf takes care of it */
+ ibuf->dither= G.scene->r.dither_intensity;
+
+ BKE_write_ibuf(ibuf, str, G.scene->r.imtype, G.scene->r.subimtype, G.scene->r.quality);
+ IMB_freeImBuf(ibuf); /* imbuf knows rects are not part of ibuf */
+ }
+
+ strcpy(G.ima, name);
+
+ waitcursor(0);
+ }
+}
+
+
+void save_image_filesel_str(char *str)
+{
+ switch(G.scene->r.imtype) {
+ case R_RADHDR:
+ strcpy(str, "Save Radiance HDR");
+ break;
+ case R_PNG:
+ strcpy(str, "Save PNG");
+ break;
+#ifdef WITH_DDS
+ case R_DDS:
+ strcpy(str, "Save DDS");
+ break;
+#endif
+ case R_BMP:
+ strcpy(str, "Save BMP");
+ break;
+ case R_TIFF:
+ if (G.have_libtiff)
+ strcpy(str, "Save TIFF");
+ break;
+#ifdef WITH_OPENEXR
+ case R_OPENEXR:
+ strcpy(str, "Save OpenEXR");
+ break;
+#endif
+ case R_CINEON:
+ strcpy(str, "Save Cineon");
+ break;
+ case R_DPX:
+ strcpy(str, "Save DPX");
+ break;
+ case R_RAWTGA:
+ strcpy(str, "Save Raw Targa");
+ break;
+ case R_IRIS:
+ strcpy(str, "Save IRIS");
+ break;
+ case R_IRIZ:
+ strcpy(str, "Save IRIS");
+ break;
+ case R_HAMX:
+ strcpy(str, "Save HAMX");
+ break;
+ case R_TARGA:
+ strcpy(str, "Save Targa");
+ break;
+ case R_MULTILAYER:
+ strcpy(str, "Save Multi Layer EXR");
+ break;
+ /* default we save jpeg, also for all movie formats */
+ case R_JPEG90:
+ case R_MOVIE:
+ case R_AVICODEC:
+ case R_AVIRAW:
+ case R_AVIJPEG:
+ default:
+ strcpy(str, "Save JPEG");
+ break;
+ }
+}
+
+static void save_rendered_image_cb(char *name)
+{
+ save_rendered_image_cb_real(name, 1);
+}
+
+/* no fileselect, no confirm */
+void BIF_save_rendered_image(char *name)
+{
+ save_rendered_image_cb_real(name, 0);
+}
+
+/* calls fileselect */
+void BIF_save_rendered_image_fs(void)
+{
+ RenderResult rres;
+
+ RE_GetResultImage(RE_GetRender(G.scene->id.name), &rres);
+
+ if(!rres.rectf && !rres.rect32) {
+ error("No image rendered");
+ }
+ else {
+ char dir[FILE_MAXDIR * 2], str[FILE_MAXFILE * 2];
+
+ if(G.ima[0]==0) {
+ strcpy(dir, G.sce);
+ BLI_splitdirstring(dir, str);
+ strcpy(G.ima, dir);
+ }
+
+ save_image_filesel_str(str);
+ activate_fileselect(FILE_SPECIAL, str, G.ima, save_rendered_image_cb);
+ }
+}
+
+
diff --git a/source/blender/src/writemovie.c b/source/blender/src/writemovie.c
new file mode 100644
index 00000000000..4be739dd5d1
--- /dev/null
+++ b/source/blender/src/writemovie.c
@@ -0,0 +1,502 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+//#ifdef __sgi
+#if 0
+
+#include <unistd.h>
+#include <movie.h>
+#include <cdaudio.h>
+#include <dmedia/cl.h>
+#include <dmedia/cl_cosmo.h>
+#include <sys/file.h> /* flock */
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "BKE_global.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_gl.h"
+#include "BIF_writemovie.h"
+#include "BIF_toolbox.h"
+
+#include "render.h"
+
+#define error(str) {perror(str) ; error("%s", str); G.afbreek= 1;}
+#define QUIT(str) {error(str); return;}
+
+#define DIR_UP 1
+#define DIR_DOWN 2
+#define DIR_BOTH (DIR_UP | DIR_DOWN)
+
+#define MAXQUAL R.r.quality
+#define MINQUAL 30
+
+
+/* globals */
+
+static CL_Handle compr, soft_compr;
+static MVid movie, image;
+static DMparams *movie_params, *image_params;
+static int compr_params[64];
+static int myindex, qualindex, qualnow, mv_outx, mv_outy, numfields= 2;
+static char *comp_buf;
+static int sfra, efra, first = TRUE, maxbufsize;
+static int ntsc = FALSE;
+
+#define FIRST_IMAGE "FIRST_IMAGE"
+#define BLENDER_FIRST_IMAGE "BLENDER_1ST_IMG"
+
+
+static void report_flock(void)
+{
+ static int flock_reported = FALSE;
+
+ if (flock_reported) return;
+ flock_reported = TRUE;
+
+ error("WriteMovie: couldn't flock() moviefile. Ignoring.");
+}
+
+
+static void make_movie_name(char *string)
+{
+ int len;
+ char txt[64];
+
+ if (string==0) return;
+
+ strcpy(string, G.scene->r.pic);
+ BLI_convertstringcode(string, G.sce, G.scene->r.cfra);
+ len= strlen(string);
+
+ BLI_make_existing_file(string);
+
+ if (BLI_strcasecmp(string + len - 3, ".mv")) {
+ sprintf(txt, "%04d_%04d.mv", sfra, efra);
+ strcat(string, txt);
+ }
+}
+
+static int my_Compress(uint * rect, int *bufsize)
+{
+ int err = 0;
+
+ compr_params[qualindex] = qualnow;
+ clSetParams(compr, compr_params, myindex);
+
+ while (clCompress(compr, numfields, rect, bufsize, comp_buf) != numfields) {
+ if (compr == soft_compr) {
+ error("clCompress (software)");
+ return 1;
+ }
+
+ /* hardware opnieuw initialiseren */
+ clCloseCompressor(compr);
+ clOpenCompressor(CL_JPEG_COSMO, &compr);
+
+ qualnow--;
+ compr_params[qualindex] = qualnow;
+ clSetParams(compr, compr_params, myindex);
+ printf("retrying at quality %d\n", qualnow);
+
+ err= TRUE;
+ }
+
+ return (err);
+}
+
+static void set_sfra_efra(void)
+{
+ sfra = (G.scene->r.sfra);
+ efra = (G.scene->r.efra);
+}
+
+static void open_compressor(void)
+{
+ int cosmo = FAILURE;
+
+ /* initialiseren van de compressor */
+
+ if (clOpenCompressor(CL_JPEG_SOFTWARE, &soft_compr) != SUCCESS) QUIT("clOpenCompressor");
+
+ if (G.scene->r.mode & R_COSMO) {
+ cosmo = clOpenCompressor(CL_JPEG_COSMO, &compr);
+ if (cosmo != SUCCESS && first) error("warning: using software compression");
+ first = FALSE;
+ }
+
+ if (cosmo != SUCCESS) compr = soft_compr;
+
+ myindex = 0;
+
+ compr_params[myindex++]= CL_IMAGE_WIDTH;
+ compr_params[myindex++]= mv_outx;
+
+ compr_params[myindex++]= CL_IMAGE_HEIGHT;
+ compr_params[myindex++]= mv_outy / numfields;
+
+ compr_params[myindex++]= CL_JPEG_QUALITY_FACTOR;
+ qualindex = myindex;
+ compr_params[myindex++]= R.r.quality;
+
+ compr_params[myindex++]= CL_ORIGINAL_FORMAT;
+ compr_params[myindex++]= CL_RGBX;
+
+ compr_params[myindex++]= CL_ORIENTATION;
+ compr_params[myindex++]= CL_TOP_DOWN;
+
+ compr_params[myindex++]= CL_INTERNAL_FORMAT;
+ compr_params[myindex++]= CL_YUV422;
+
+ /* this parameter must be set for non-queueing mode */
+ compr_params[myindex++]= CL_ENABLE_IMAGEINFO;
+ compr_params[myindex++]= 1;
+
+ /* enable stream headers */
+ compr_params[myindex++]= CL_STREAM_HEADERS;
+ compr_params[myindex++]= TRUE;
+
+ clSetParams(compr, compr_params, myindex);
+ if (compr != soft_compr) clSetParams(soft_compr, compr_params, myindex);
+
+ maxbufsize = 2 * clGetParam(compr, CL_COMPRESSED_BUFFER_SIZE);
+ comp_buf = MEM_mallocN(maxbufsize, "cosmo_buffer");
+}
+
+static void close_compressor(void)
+{
+ MEM_freeN(comp_buf);
+ comp_buf = 0;
+
+ clCloseCompressor(compr);
+ if (soft_compr != compr) clCloseCompressor(soft_compr);
+}
+
+void end_movie(void)
+{
+}
+
+static void new_movie(int fd)
+{
+ char string[120];
+
+ if (dmParamsCreate(&movie_params) != DM_SUCCESS) QUIT("dmParamsCreate");
+ if (dmParamsCreate(&image_params) != DM_SUCCESS) QUIT("dmParamsCreate");
+
+ if (mvSetMovieDefaults(movie_params, MV_FORMAT_SGI_3) != DM_SUCCESS) QUIT("mvSetMovieDefaults");
+ if (dmSetImageDefaults(image_params, mv_outx, mv_outy, DM_PACKING_RGBX) != DM_SUCCESS) QUIT("dmSetImageDefaults");
+
+ mvAddUserParam(BLENDER_FIRST_IMAGE);
+ sprintf(string, "%04d", sfra);
+ dmParamsSetString(image_params, BLENDER_FIRST_IMAGE, string);
+
+ if (ntsc) dmParamsSetFloat(image_params, DM_IMAGE_RATE, 29.97);
+ else dmParamsSetFloat(image_params, DM_IMAGE_RATE, 25.0);
+
+ if (numfields == 2) {
+ if (ntsc) dmParamsSetEnum(image_params, DM_IMAGE_INTERLACING, DM_IMAGE_INTERLACED_ODD);
+ else dmParamsSetEnum(image_params, DM_IMAGE_INTERLACING, DM_IMAGE_INTERLACED_EVEN);
+ } else dmParamsSetEnum(image_params, DM_IMAGE_INTERLACING, DM_IMAGE_NONINTERLACED);
+
+ dmParamsSetEnum(image_params, DM_IMAGE_ORIENTATION, DM_TOP_TO_BOTTOM);
+ dmParamsSetString(image_params, DM_IMAGE_COMPRESSION, DM_IMAGE_JPEG);
+
+ if (mvCreateFD(fd, movie_params, NULL, &movie) != DM_SUCCESS) QUIT("mvCreateFile");
+ if (mvAddTrack(movie, DM_IMAGE, image_params, NULL, &image)) QUIT("mvAddTrack");;
+ if (mvSetLoopMode(movie, MV_LOOP_CONTINUOUSLY) != DM_SUCCESS) QUIT("mvSetMovieDefaults");
+
+ if (mvWrite(movie) != DM_SUCCESS) QUIT("mvWrite");
+ if (mvClose(movie) != DM_SUCCESS) QUIT("mvClose");
+
+ dmParamsDestroy(image_params);
+ dmParamsDestroy(movie_params);
+}
+
+
+void start_movie(void)
+{
+ char name[FILE_MAXDIR+FILE_MAXFILE];
+ char bak[sizeof(name) + 4];
+ int fd;
+
+ first = TRUE;
+
+ set_sfra_efra();
+
+ /* naam bedenken voor de movie */
+ make_movie_name(name);
+
+ ntsc = FALSE;
+
+ switch (R.recty) {
+ case 480: case 360: case 240: case 120:
+ ntsc = TRUE;
+ }
+
+ if (ntsc) {
+ switch (R.rectx) {
+ case 360: case 320: case 720: case 640:
+ mv_outx = R.rectx;
+ break;
+ default:
+ if (R.rectx <= 320) mv_outx = 320;
+ else if (R.rectx <= 640) mv_outx = 640;
+ else mv_outx = 720;
+ }
+ } else {
+ switch (R.rectx) {
+ case 360: case 384: case 720: case 768:
+ mv_outx = R.rectx;
+ break;
+ default:
+ if (R.rectx < 384) mv_outx = 384;
+ else mv_outx = 768;
+ }
+ }
+
+ if (ntsc) {
+ if (R.recty <= 240) {
+ mv_outy = 240;
+ numfields = 1;
+ } else {
+ mv_outy = 480;
+ numfields = 2;
+ }
+ } else {
+ if (R.recty <= 288) {
+ mv_outy = 288;
+ numfields = 1;
+ } else {
+ mv_outy = 576;
+ numfields = 2;
+ }
+ }
+
+ qualnow = R.r.quality;
+
+ fd = open(name, O_BINARY|O_RDWR);
+ if (fd != -1) {
+ if (flock(fd, LOCK_EX) == -1) report_flock();
+
+ if (mvOpenFD(fd, &movie) == DM_SUCCESS) {
+ if (mvFindTrackByMedium(movie, DM_IMAGE, &image) == DM_SUCCESS) {
+ if (mvGetImageWidth(image) == mv_outx) {
+ if (mvGetImageHeight(image) == mv_outy) {
+ mvClose(movie);
+ close(fd);
+ return;
+ }
+ }
+ }
+ strcpy(bak, name);
+ strcat(bak, ".bak");
+ BLI_rename(name, bak);
+ mvClose(movie);
+ }
+
+ close(fd);
+ }
+ fd = open(name, O_BINARY|O_RDWR | O_CREAT | O_EXCL, 0664);
+ if (fd != -1) {
+ if (flock(fd, LOCK_EX) == -1) report_flock();
+ new_movie(fd);
+ printf("Created movie: %s\n", name);
+ close(fd);
+ }
+}
+
+void append_movie(int cfra)
+{
+ ImBuf *ibuf, *tbuf;
+ int err, ofsx, ofsy, bufsize, rate, lastqual, qualstep, direction, first_image, num_images;
+ char name[FILE_MAXDIR+FILE_MAXFILE];
+ const char *string;
+ int fd;
+ float col[4] = {0.0,0.0,0.0,0.0};
+
+ set_sfra_efra();
+ make_movie_name(name);
+ open_compressor();
+
+ rate = 1024 * R.r.maximsize;
+
+ /* veranderd: kopie van rectot maken */
+ ibuf= IMB_allocImBuf(R.rectx, R.recty, 32, IB_rect, 0);
+ memcpy(ibuf->rect, R.rectot, 4*R.rectx*R.recty);
+
+ if (ibuf->x != mv_outx || ibuf->y != mv_outy) {
+ tbuf = IMB_allocImBuf(mv_outx, mv_outy, 32, IB_rect, 0);
+ IMB_rectfill(tbuf,col);
+
+ ofsx = (tbuf->x - ibuf->x) / 2;
+ ofsy = (tbuf->y - ibuf->y) / 2;
+ if (numfields == 2) ofsy &= ~1;
+
+ IMB_rectcpy(tbuf, ibuf, ofsx, ofsy, 0, 0, ibuf->x, ibuf->y);
+ IMB_freeImBuf(ibuf);
+ strcpy(tbuf->name, ibuf->name);
+ ibuf = tbuf;
+ }
+ IMB_convert_rgba_to_abgr(ibuf);
+
+ if (numfields == 2) {
+ if (ntsc) {
+ IMB_rectcpy(ibuf, ibuf, 0, 0, 0, 1, ibuf->x, ibuf->y);
+ IMB_flipy(ibuf);
+ IMB_de_interlace(ibuf);
+ if (ntsc) IMB_rectcpy(ibuf, ibuf, 0, 0, 0, 1, ibuf->x, ibuf->y);
+ } else {
+ IMB_flipy(ibuf);
+ IMB_rectcpy(ibuf, ibuf, 0, 0, 0, 1, ibuf->x, ibuf->y);
+ IMB_de_interlace(ibuf);
+ }
+ }
+ else {
+ /* kleine movies anders op de kop */
+ IMB_flipy(ibuf);
+ }
+
+ if (rate == 0) {
+ qualnow = R.r.quality;
+ my_Compress(ibuf->rect, &bufsize);
+ } else {
+ qualstep = 4;
+ direction = 0;
+
+ do {
+ if (qualnow > MAXQUAL) qualnow = MAXQUAL;
+ if (qualnow < MINQUAL) qualnow = MINQUAL;
+
+ compr_params[qualindex] = qualnow;
+ clSetParams(compr, compr_params, myindex);
+
+ lastqual = qualnow;
+ err = my_Compress(ibuf->rect, &bufsize);
+
+ printf(" tried quality: %d, size %d\n", qualnow, bufsize);
+
+ if (bufsize < 0.9 * rate) {
+ if (err) {
+ /* forget about this frame, retry next frame at old quality settting */
+ qualnow = lastqual;
+ break;
+ }
+ if (qualnow == MAXQUAL) break;
+ direction |= DIR_UP;
+ if (direction == DIR_BOTH) qualstep /= 2;
+ qualnow += qualstep;
+ } else if (bufsize > 1.1 * rate) {
+ if (qualnow == MINQUAL) break;
+ direction |= DIR_DOWN;
+ if (direction == DIR_BOTH) qualstep /= 2;
+ qualnow -= qualstep;
+ } else break;
+
+ if (qualstep == 0) {
+ /* this was the last iteration. Make sure that the buffer isn't to big */
+ if (bufsize < 1.1 * rate) break;
+ else qualnow--;
+ }
+ } while (1);
+
+ printf("used quality: %d\n", qualnow);
+
+ if (bufsize < rate) qualnow++;
+ else qualnow--;
+
+ }
+
+ fd = open(name, O_BINARY|O_RDWR);
+
+ if (fd != -1) {
+ if (flock(fd, LOCK_EX) == -1) report_flock();
+ if (mvOpenFD(fd, &movie) == DM_SUCCESS){
+ if (mvFindTrackByMedium(movie, DM_IMAGE, &image) == DM_SUCCESS) {
+ image_params = mvGetParams(image);
+
+ first_image = 1;
+
+ string = dmParamsGetString(image_params, FIRST_IMAGE);
+ if (string) {
+ first_image = atoi(string);
+ }
+ string = dmParamsGetString(image_params, BLENDER_FIRST_IMAGE);
+ if (string) {
+ first_image = atoi(string);
+ }
+
+ num_images = mvGetTrackLength(image);
+
+ if (cfra >= first_image && cfra <= (first_image + num_images - 1)) {
+ if (mvDeleteFrames(image, cfra - first_image, 1) != DM_SUCCESS) {
+ mvDestroyMovie(movie);
+ error("mvDeleteFrames");
+ G.afbreek = 1;
+ }
+ }
+
+ if (G.afbreek != 1) {
+ if (mvInsertCompressedImage(image, cfra - first_image, bufsize, comp_buf) == DM_SUCCESS) {
+ printf("added frame %3d (frame %3d in movie): length %6d: ", cfra, cfra - first_image + 1, bufsize);
+ mvClose(movie);
+ } else {
+ mvDestroyMovie(movie);
+ error("mvInsertCompressedImage");
+ G.afbreek = 1;
+ }
+ }
+ } else {
+ mvDestroyMovie(movie);
+ error("mvFindTrackByMedium");
+ G.afbreek = 1;
+ }
+ }else {
+ error("mvOpenFD");
+ G.afbreek = 1;
+ }
+ close(fd);
+ } else {
+ error("open movie");
+ G.afbreek = 1;
+ }
+
+ IMB_freeImBuf(ibuf);
+
+ close_compressor();
+}
+
+#endif /* __sgi */
diff --git a/source/blender/verify/BLO_sign_verify_Header.h b/source/blender/verify/BLO_sign_verify_Header.h
new file mode 100644
index 00000000000..d2290dc4ad7
--- /dev/null
+++ b/source/blender/verify/BLO_sign_verify_Header.h
@@ -0,0 +1,83 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ *
+ */
+
+#ifndef BLO_SIGN_VERIFY_H
+#define BLO_SIGN_VERIFY_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef FREE_WINDOWS
+typedef int int32_t;
+#endif
+
+#include "BLO_sys_types.h"
+
+#define SIGNVERIFYHEADERSTRUCTSIZE sizeof(struct BLO_sign_verify_HeaderStruct)
+/* TODO use reasonable sizes
+Tests showed: pubKeyLen 64, cryptedKeyLen 64 bytes
+So we pick 2*64 bytes + tail for now : */
+
+#define MAXPUBKEYLEN 130
+#define MAXSIGNATURELEN 130
+
+struct BLO_sign_verify_HeaderStruct {
+ uint8_t magic; /* poor mans header recognize check */
+ uint32_t length; /* how much signed data is there */
+ uint8_t pubKey[MAXPUBKEYLEN];
+ uint32_t pubKeyLen; /* the actual pubKey length */
+ uint8_t signature[MAXSIGNATURELEN];
+ int32_t signatureLen; /* the actual signature length */
+ uint32_t datacrc; /* data crc checksum */
+ uint32_t headercrc; /* header minus crc itself checksum */
+};
+
+#define SIGNERHEADERSTRUCTSIZE sizeof(struct BLO_SignerHeaderStruct)
+#define MAXSIGNERLEN 100
+
+struct BLO_SignerHeaderStruct {
+ uint8_t name[MAXSIGNERLEN]; /* the signers name (from the key) */
+ uint8_t email[MAXSIGNERLEN]; /* the signers email (from the key) */
+ uint8_t homeUrl[MAXSIGNERLEN]; /* the signers home page */
+ uint8_t text[MAXSIGNERLEN]; /* optional additional user text */
+ uint8_t pubKeyUrl1[MAXSIGNERLEN]; /* the signers pubKey store */
+ uint8_t pubKeyUrl2[MAXSIGNERLEN]; /* the signers pubKey at NaN */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BLO_SIGN_VERIFY_H */
+
diff --git a/source/blender/verify/BLO_signer_info.h b/source/blender/verify/BLO_signer_info.h
new file mode 100644
index 00000000000..d2e6b987147
--- /dev/null
+++ b/source/blender/verify/BLO_signer_info.h
@@ -0,0 +1,48 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ *
+ */
+
+#include "BLO_sign_verify_Header.h"
+
+/* external struct for signer info */
+
+struct BLO_SignerInfo {
+ char name[MAXSIGNERLEN];
+ char email[MAXSIGNERLEN];
+ char homeUrl[MAXSIGNERLEN];
+ /* more to come... */
+};
+
+struct BLO_SignerInfo *BLO_getSignerInfo(void);
+int BLO_isValidSignerInfo(struct BLO_SignerInfo *info);
+void BLO_clrSignerInfo(struct BLO_SignerInfo *info);
+
diff --git a/source/blender/verify/BLO_verify.h b/source/blender/verify/BLO_verify.h
new file mode 100644
index 00000000000..6396c4d6c73
--- /dev/null
+++ b/source/blender/verify/BLO_verify.h
@@ -0,0 +1,79 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ */
+
+#ifndef BLO_VERIFY_H
+#define BLO_VERIFY_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define VERIFY_DECLARE_HANDLE(name) typedef struct name##__ { int unused; } *name
+
+VERIFY_DECLARE_HANDLE(BLO_verifyStructHandle);
+
+/**
+ * openssl verify initializer
+ * @retval pointer to verify control structure
+ */
+ BLO_verifyStructHandle
+BLO_verify_begin(
+ void *endControl);
+
+/**
+ * openssl verify dataprocessor wrapper
+ * @param BLO_verify Pointer to verify control structure
+ * @param data Pointer to new data
+ * @param dataIn New data amount
+ * @retval streamGlueRead return value
+ */
+ int
+BLO_verify_process(
+ BLO_verifyStructHandle BLO_verifyHandle,
+ unsigned char *data,
+ unsigned int dataIn);
+
+/**
+ * openssl verify final call and cleanup
+ * @param BLO_verify Pointer to verify control structure
+ * @retval streamGlueRead return value
+ */
+ int
+BLO_verify_end(
+ BLO_verifyStructHandle BLO_verifyHandle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BLO_VERIFY_H */
+
diff --git a/source/blender/verify/Makefile b/source/blender/verify/Makefile
new file mode 100644
index 00000000000..73c2c53ad9c
--- /dev/null
+++ b/source/blender/verify/Makefile
@@ -0,0 +1,37 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+# Bounces make to subdirectories.
+
+SOURCEDIR = source/blender/verify
+DIRS = intern
+
+include nan_subdirs.mk
diff --git a/source/blender/verify/intern/BLO_verify.c b/source/blender/verify/intern/BLO_verify.c
new file mode 100644
index 00000000000..1091b91255f
--- /dev/null
+++ b/source/blender/verify/intern/BLO_verify.c
@@ -0,0 +1,427 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+ * openssl verify wrapper library
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "openssl/rsa.h"
+#include "openssl/ripemd.h"
+#include "openssl/objects.h"
+#include "zlib.h"
+
+#include "GEN_messaging.h"
+
+#include "BLO_readStreamGlue.h"
+#include "BLO_verify.h"
+#include "BLO_sign_verify_Header.h" /* used by verify and encrypt */
+
+#include "BLO_signer_info.h" /* external signer info struct */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+static struct BLO_SignerInfo g_SignerInfo = {"", "", ""};
+
+struct verifyStructType {
+ struct readStreamGlueStruct *streamGlue;
+ unsigned int streamDone;
+ unsigned char headerbuffer[SIGNVERIFYHEADERSTRUCTSIZE];
+ uint32_t datacrc;
+ struct BLO_sign_verify_HeaderStruct *streamHeader;
+ RIPEMD160_CTX ripemd160_ctx;
+ struct BLO_SignerHeaderStruct *signerHeader;
+ unsigned char signerHeaderBuffer[SIGNERHEADERSTRUCTSIZE];
+ void *endControl;
+};
+
+ BLO_verifyStructHandle
+BLO_verify_begin(
+ void *endControl)
+{
+ struct verifyStructType *control;
+ control = malloc(sizeof(struct verifyStructType));
+ if (!control) return NULL;
+
+ control->streamGlue = NULL;
+ control->streamDone = 0;
+ memset(control->headerbuffer, 0, SIGNVERIFYHEADERSTRUCTSIZE);
+ control->datacrc = 0;
+
+ control->streamHeader = malloc(SIGNVERIFYHEADERSTRUCTSIZE);
+ if (!control->streamHeader) {
+ free(control);
+ return NULL;
+ }
+ control->streamHeader->magic = 0;
+ control->streamHeader->length = 0;
+ strcpy(control->streamHeader->pubKey, "");
+ control->streamHeader->pubKeyLen = 0;
+ strcpy(control->streamHeader->signature, "");
+ control->streamHeader->signatureLen = 0;
+ control->streamHeader->datacrc = 0;
+ control->streamHeader->headercrc = 0;
+
+ RIPEMD160_Init(&(control->ripemd160_ctx));
+
+ control->signerHeader = malloc(SIGNERHEADERSTRUCTSIZE);
+ if (!control->signerHeader) {
+ free(control->streamHeader);
+ free(control);
+ return NULL;
+ }
+ memset(control->signerHeader->name, 0, MAXSIGNERLEN);
+ memset(control->signerHeader->email, 0, MAXSIGNERLEN);
+ memset(control->signerHeader->homeUrl, 0, MAXSIGNERLEN);
+ memset(control->signerHeader->text, 0, MAXSIGNERLEN);
+ memset(control->signerHeader->pubKeyUrl1, 0, MAXSIGNERLEN);
+ memset(control->signerHeader->pubKeyUrl2, 0, MAXSIGNERLEN);
+
+ control->endControl = endControl;
+ return((BLO_verifyStructHandle) control);
+}
+
+ int
+BLO_verify_process(
+ BLO_verifyStructHandle BLO_verifyHandle,
+ unsigned char *data,
+ unsigned int dataIn)
+{
+ int err = 0;
+ struct verifyStructType *BLO_verify =
+ (struct verifyStructType *) BLO_verifyHandle;
+
+ if (!BLO_verify) {
+ err = BRS_SETFUNCTION(BRS_VERIFY) |
+ BRS_SETGENERR(BRS_NULL);
+ return err;
+ }
+
+ /* First check if we have our header filled in yet */
+ if (BLO_verify->streamHeader->length == 0) {
+ unsigned int processed;
+ if (dataIn == 0) return err; /* really need data to do anything */
+ processed = ((dataIn + BLO_verify->streamDone) <=
+ SIGNVERIFYHEADERSTRUCTSIZE)
+ ? dataIn : SIGNVERIFYHEADERSTRUCTSIZE;
+ memcpy(BLO_verify->headerbuffer + BLO_verify->streamDone,
+ data, processed);
+ BLO_verify->streamDone += processed;
+ dataIn -= processed;
+ data += processed;
+ if (BLO_verify->streamDone == SIGNVERIFYHEADERSTRUCTSIZE) {
+ /* we have the whole header, absorb it */
+ struct BLO_sign_verify_HeaderStruct *header;
+ uint32_t crc;
+
+ header = (struct BLO_sign_verify_HeaderStruct *)
+ BLO_verify->headerbuffer;
+ crc = crc32(0L, (const Bytef *) header,
+ SIGNVERIFYHEADERSTRUCTSIZE - 4);
+
+ if (header->magic == 'A') {
+#ifndef NDEBUG
+ fprintf(GEN_errorstream,
+ "BLO_sign_verify_HeaderStruct Magic confirmed\n");
+#endif
+ } else {
+#ifndef NDEBUG
+ fprintf(GEN_errorstream,
+ "ERROR BLO_sign_verify_HeaderStruct Magic NOT confirmed\n");
+#endif
+ err = BRS_SETFUNCTION(BRS_VERIFY) |
+ BRS_SETGENERR(BRS_MAGIC);
+ if (BLO_verify->streamGlue) free(BLO_verify->streamGlue);
+ if (BLO_verify->streamHeader) free(BLO_verify->streamHeader);
+ if (BLO_verify->signerHeader) free(BLO_verify->signerHeader);
+ free(BLO_verify);
+ return err;
+ }
+
+ if (crc == ntohl(header->headercrc)) {
+#ifndef NDEBUG
+ fprintf(GEN_errorstream,"BLO_sign_verify_Header CRC correct\n");
+#endif
+ } else {
+#ifndef NDEBUG
+ fprintf(GEN_errorstream,"ERROR BLO_sign_verify_Header CRC NOT correct\n");
+#endif
+ err = BRS_SETFUNCTION(BRS_VERIFY) |
+ BRS_SETGENERR(BRS_CRCHEADER);
+ if (BLO_verify->streamGlue) free(BLO_verify->streamGlue);
+ if (BLO_verify->streamHeader) free(BLO_verify->streamHeader);
+ if (BLO_verify->signerHeader) free(BLO_verify->signerHeader);
+ free(BLO_verify);
+ return err;
+ }
+ BLO_verify->streamHeader->length = ntohl(header->length);
+ BLO_verify->streamHeader->pubKeyLen = ntohl(header->pubKeyLen);
+ memcpy(BLO_verify->streamHeader->pubKey, header->pubKey,
+ BLO_verify->streamHeader->pubKeyLen);
+ BLO_verify->streamHeader->signatureLen =
+ ntohl(header->signatureLen);
+ memcpy(BLO_verify->streamHeader->signature, header->signature,
+ BLO_verify->streamHeader->signatureLen);
+ BLO_verify->streamHeader->datacrc = ntohl(header->datacrc);
+
+#ifndef NDEBUG
+ fprintf(GEN_errorstream,
+ "BLO_verify_process gets %u bytes\n",
+ (unsigned int) BLO_verify->streamHeader->length);
+#endif
+
+ }
+ }
+
+ /* Is there really (still) new data available ? */
+ if (dataIn > 0) {
+ /* BLO_SignerHeaderStruct */
+ if (BLO_verify->signerHeader->name[0] == 0) {
+ /* we don't have our signerHeader complete yet */
+ unsigned int processed;
+ processed = ((dataIn + BLO_verify->streamDone -
+ SIGNVERIFYHEADERSTRUCTSIZE) <= SIGNERHEADERSTRUCTSIZE)
+ ? dataIn : SIGNERHEADERSTRUCTSIZE;
+ memcpy(BLO_verify->signerHeaderBuffer +
+ BLO_verify->streamDone - SIGNVERIFYHEADERSTRUCTSIZE,
+ data, processed);
+ BLO_verify->streamDone += processed;
+ dataIn -= processed;
+ data += processed;
+ if (BLO_verify->streamDone == SIGNVERIFYHEADERSTRUCTSIZE +
+ SIGNERHEADERSTRUCTSIZE) {
+ /* we have the whole header, absorb it */
+ struct BLO_SignerHeaderStruct *signerHeader;
+ signerHeader = (struct BLO_SignerHeaderStruct *)
+ BLO_verify->signerHeaderBuffer;
+ strncpy(BLO_verify->signerHeader->name,
+ signerHeader->name, MAXSIGNERLEN-1);
+ strncpy(BLO_verify->signerHeader->email,
+ signerHeader->email, MAXSIGNERLEN-1);
+ strncpy(BLO_verify->signerHeader->homeUrl,
+ signerHeader->homeUrl, MAXSIGNERLEN-1);
+ strncpy(BLO_verify->signerHeader->text,
+ signerHeader->text, MAXSIGNERLEN-1);
+ strncpy(BLO_verify->signerHeader->pubKeyUrl1,
+ signerHeader->pubKeyUrl1, MAXSIGNERLEN-1);
+ strncpy(BLO_verify->signerHeader->pubKeyUrl2,
+ signerHeader->pubKeyUrl2, MAXSIGNERLEN-1);
+
+#ifndef NDEBUG
+ fprintf(GEN_errorstream,
+ "name %s\nemail %s\nhomeUrl %s\ntext %s\n",
+ BLO_verify->signerHeader->name,
+ BLO_verify->signerHeader->email,
+ BLO_verify->signerHeader->homeUrl,
+ BLO_verify->signerHeader->text);
+ fprintf(GEN_errorstream,
+ "pubKeyUrl1 %s\npubKeyUrl2 %s\n",
+ BLO_verify->signerHeader->pubKeyUrl1,
+ BLO_verify->signerHeader->pubKeyUrl2);
+#endif
+ /* also update the signature and crc checksum */
+ RIPEMD160_Update(&(BLO_verify->ripemd160_ctx),
+ BLO_verify->signerHeaderBuffer,
+ SIGNERHEADERSTRUCTSIZE);
+
+ /* update datacrc */
+ BLO_verify->datacrc = crc32(
+ BLO_verify->datacrc, (const Bytef *)
+ BLO_verify->signerHeaderBuffer,
+ SIGNERHEADERSTRUCTSIZE);
+ }
+ }
+ }
+
+ /* Is there really (still) new data available ? */
+ if (dataIn > 0) {
+ RIPEMD160_Update(&(BLO_verify->ripemd160_ctx), data, dataIn);
+
+ /* update datacrc */
+ BLO_verify->datacrc = crc32(
+ BLO_verify->datacrc, (const Bytef *) data, dataIn);
+
+ BLO_verify->streamDone += dataIn;
+
+ /* give data to streamGlueRead, it will find out what to do next */
+ err = readStreamGlue(
+ BLO_verify->endControl,
+ &(BLO_verify->streamGlue),
+ (unsigned char *) data,
+ dataIn);
+ }
+ return err;
+}
+
+/**
+ * openssl verify final call and cleanup
+ * @param BLO_verify Pointer to verify control structure
+ * @retval streamGlueRead return value
+ */
+ int
+BLO_verify_end(
+ BLO_verifyStructHandle BLO_verifyHandle)
+{
+ int err = 0;
+ unsigned char *digest;
+ static unsigned char rsa_e[] = "\x01\x00\x01";
+ RSA *rsa = NULL;
+ int verifySuccess;
+ struct verifyStructType *BLO_verify =
+ (struct verifyStructType *) BLO_verifyHandle;
+
+ if (!BLO_verify) {
+ err = BRS_SETFUNCTION(BRS_VERIFY) |
+ BRS_SETGENERR(BRS_NULL);
+ return err;
+ }
+
+ if (BLO_verify->streamDone == BLO_verify->streamHeader->length +
+ SIGNVERIFYHEADERSTRUCTSIZE) {
+#ifndef NDEBUG
+ fprintf(GEN_errorstream, "Signed data length is correct\n");
+#endif
+ } else {
+#ifndef NDEBUG
+ fprintf(GEN_errorstream, "Signed data length is NOT correct\n");
+#endif
+ err = BRS_SETFUNCTION(BRS_VERIFY) |
+ BRS_SETGENERR(BRS_DATALEN);
+ if (BLO_verify->streamGlue) free(BLO_verify->streamGlue);
+ if (BLO_verify->streamHeader) free(BLO_verify->streamHeader);
+ if (BLO_verify->signerHeader) free(BLO_verify->signerHeader);
+ free(BLO_verify);
+ return err;
+ }
+
+ if (BLO_verify->datacrc == BLO_verify->streamHeader->datacrc) {
+#ifndef NDEBUG
+ fprintf(GEN_errorstream, "Signed data CRC is correct\n");
+#endif
+ } else {
+#ifndef NDEBUG
+ fprintf(GEN_errorstream, "Signed data CRC is NOT correct\n");
+#endif
+ err = BRS_SETFUNCTION(BRS_VERIFY) |
+ BRS_SETGENERR(BRS_CRCDATA);
+ if (BLO_verify->streamGlue) free(BLO_verify->streamGlue);
+ if (BLO_verify->streamHeader) free(BLO_verify->streamHeader);
+ if (BLO_verify->signerHeader) free(BLO_verify->signerHeader);
+ free(BLO_verify);
+ return err;
+ }
+
+ digest = malloc(RIPEMD160_DIGEST_LENGTH);
+ if (!digest) {
+ err = BRS_SETFUNCTION(BRS_VERIFY) |
+ BRS_SETGENERR(BRS_MALLOC);
+ if (BLO_verify->streamGlue) free(BLO_verify->streamGlue);
+ if (BLO_verify->streamHeader) free(BLO_verify->streamHeader);
+ if (BLO_verify->signerHeader) free(BLO_verify->signerHeader);
+ free(BLO_verify);
+ return err;
+ }
+
+ RIPEMD160_Final(digest, &(BLO_verify->ripemd160_ctx));
+
+ rsa = RSA_new();
+ if (rsa == NULL) {
+#ifndef NDEBUG
+ fprintf(GEN_errorstream, "Error in RSA_new\n");
+#endif
+ err = BRS_SETFUNCTION(BRS_VERIFY) |
+ BRS_SETSPECERR(BRS_RSANEWERROR);
+ free(digest);
+ if (BLO_verify->streamGlue) free(BLO_verify->streamGlue);
+ if (BLO_verify->streamHeader) free(BLO_verify->streamHeader);
+ if (BLO_verify->signerHeader) free(BLO_verify->signerHeader);
+ free(BLO_verify);
+ return err;
+ }
+ /* static exponent */
+ rsa->e = BN_bin2bn(rsa_e, sizeof(rsa_e)-1, rsa->e);
+
+ /* public part into rsa->n */
+ rsa->n = BN_bin2bn(BLO_verify->streamHeader->pubKey,
+ BLO_verify->streamHeader->pubKeyLen,
+ rsa->n);
+ /*DEBUG RSA_print_fp(stdout, rsa, 0); */
+
+ /* verify the signature */
+ verifySuccess = RSA_verify(NID_ripemd160, digest, RIPEMD160_DIGEST_LENGTH,
+ BLO_verify->streamHeader->signature,
+ BLO_verify->streamHeader->signatureLen, rsa);
+ if (verifySuccess == 1) {
+#ifndef NDEBUG
+ fprintf(GEN_errorstream,
+ "Signature verified\n");
+#endif
+ } else {
+#ifndef NDEBUG
+ fprintf(GEN_errorstream,
+ "Signature INCORRECT\n");
+#endif
+ err = BRS_SETFUNCTION(BRS_VERIFY) |
+ BRS_SETSPECERR(BRS_SIGFAILED);
+ }
+
+/* copy signer information to external struct */
+
+ strncpy(g_SignerInfo.name, BLO_verify->signerHeader->name, MAXSIGNERLEN-1);
+ strncpy(g_SignerInfo.email, BLO_verify->signerHeader->email, MAXSIGNERLEN-1);
+ strncpy(g_SignerInfo.homeUrl, BLO_verify->signerHeader->homeUrl, MAXSIGNERLEN-1);
+
+ free(digest);
+ free(BLO_verify->streamGlue);
+ free(BLO_verify->streamHeader);
+ free(BLO_verify->signerHeader);
+ free(BLO_verify);
+ RSA_free(rsa);
+
+ return err;
+}
+
+struct BLO_SignerInfo *BLO_getSignerInfo(){
+ return &g_SignerInfo;
+}
+
+int BLO_isValidSignerInfo(struct BLO_SignerInfo *info){
+ return info->name[0] != 0;
+}
+
+void BLO_clrSignerInfo(struct BLO_SignerInfo *info)
+{
+ info->name[0] = 0;
+}
+
diff --git a/source/blender/verify/intern/Makefile b/source/blender/verify/intern/Makefile
new file mode 100644
index 00000000000..c05f035caf2
--- /dev/null
+++ b/source/blender/verify/intern/Makefile
@@ -0,0 +1,53 @@
+#
+# $Id$
+#
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+#
+
+LIBNAME = verify
+DIR = $(OCGDIR)/blender/$(LIBNAME)
+
+include nan_compile.mk
+
+CFLAGS += $(LEVEL_2_C_WARNINGS)
+
+# path to our own external headerfiles
+CPPFLAGS += -I..
+
+# external modules
+CPPFLAGS += -I../../../kernel/gen_messaging
+CPPFLAGS += -I../../readstreamglue
+
+CPPFLAGS += -I$(NAN_OPENSSL)/include
+
+ifeq ($(OS),$(findstring $(OS), "solaris windows"))
+ CPPFLAGS += -I$(NAN_ZLIB)/include
+endif
+
diff --git a/source/blender/yafray/CMakeLists.txt b/source/blender/yafray/CMakeLists.txt
new file mode 100644
index 00000000000..d5486137799
--- /dev/null
+++ b/source/blender/yafray/CMakeLists.txt
@@ -0,0 +1,38 @@
+# $Id$
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2006, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Jacques Beaurain.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+
+FILE(GLOB SRC intern/*.cpp)
+
+SET(INC
+ ../../../intern/guardedalloc ../blenlib ../makesdna ../blenkernel
+ ../imbuf ../include ../render/extern/include ../render/intern/include
+)
+
+BLENDERLIB(bf_yafray "${SRC}" "${INC}")
+#env.BlenderLib ( 'bf_yafray', sources, Split(incs), [], libtype=['blender','player'], priority=[5, 190] )
diff --git a/source/blender/yafray/Makefile b/source/blender/yafray/Makefile
new file mode 100644
index 00000000000..af64089623a
--- /dev/null
+++ b/source/blender/yafray/Makefile
@@ -0,0 +1,34 @@
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+# Bounces make to subdirectories.
+
+SOURCEDIR = source/blender/yafray
+DIRS = intern
+
+include nan_subdirs.mk
diff --git a/source/blender/yafray/SConscript b/source/blender/yafray/SConscript
new file mode 100644
index 00000000000..dd744f92d39
--- /dev/null
+++ b/source/blender/yafray/SConscript
@@ -0,0 +1,9 @@
+#!/usr/bin/python
+Import ('env')
+
+sources = env.Glob('intern/*.cpp')
+
+incs = '#/intern/guardedalloc ../blenlib ../makesdna ../blenkernel'
+incs += ' ../imbuf ../include ../render/extern/include ../render/intern/include'
+
+env.BlenderLib ( 'bf_yafray', sources, Split(incs), [], libtype=['blender','player'], priority=[5, 190] )
diff --git a/source/blender/yafray/YafRay_Api.h b/source/blender/yafray/YafRay_Api.h
new file mode 100644
index 00000000000..8c47a79837f
--- /dev/null
+++ b/source/blender/yafray/YafRay_Api.h
@@ -0,0 +1,17 @@
+#ifndef __YAFRAY_API_H
+#define __YAFRAY_API_H
+
+/* C interface for Blender */
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void YAF_switchPlugin();
+ void YAF_switchFile();
+ int YAF_exportScene(Render* re);
+ void YAF_addDupliMtx(Object* obj);
+ int YAF_objectKnownData(Object* obj);
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/source/blender/yafray/intern/Makefile b/source/blender/yafray/intern/Makefile
new file mode 100644
index 00000000000..f7f6ccb559f
--- /dev/null
+++ b/source/blender/yafray/intern/Makefile
@@ -0,0 +1,46 @@
+# ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version. The Blender
+# Foundation also sells licenses for use in proprietary software under
+# the Blender License. See http://www.blender.org/BL/ for information
+# about this.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): none yet.
+#
+# ***** END GPL/BL DUAL LICENSE BLOCK *****
+#
+#
+
+LIBNAME = yafrayexport
+DIR = $(OCGDIR)/blender/yafray
+
+include nan_compile.mk
+
+CFLAGS += $(LEVEL_1_C_WARNINGS)
+
+CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
+CPPFLAGS += -I../../makesdna
+CPPFLAGS += -I../../blenkernel
+CPPFLAGS += -I../../blenlib
+CPPFLAGS += -I../../render/extern/include
+CPPFLAGS += -I../../render/intern/include
+CPPFLAGS += -I../../imbuf
+CPPFLAGS += -I../../include
+CPPFLAGS += -I..
diff --git a/source/blender/yafray/intern/api.cpp b/source/blender/yafray/intern/api.cpp
new file mode 100644
index 00000000000..f59c5e1f73e
--- /dev/null
+++ b/source/blender/yafray/intern/api.cpp
@@ -0,0 +1,16 @@
+#include "export_File.h"
+#include "export_Plugin.h"
+
+static yafrayFileRender_t byfile;
+static yafrayPluginRender_t byplugin;
+
+yafrayRender_t *YAFBLEND = &byplugin;
+
+extern "C"
+{
+ void YAF_switchPlugin() { YAFBLEND = &byplugin; }
+ void YAF_switchFile() { YAFBLEND = &byfile; }
+ int YAF_exportScene(Render* re) { return (int)YAFBLEND->exportScene(re); }
+ void YAF_addDupliMtx(Object* obj) { YAFBLEND->addDupliMtx(obj); }
+ int YAF_objectKnownData(Object* obj) { return (int)YAFBLEND->objectKnownData(obj); }
+}
diff --git a/source/blender/yafray/intern/export_File.cpp b/source/blender/yafray/intern/export_File.cpp
new file mode 100644
index 00000000000..c8c0b3c6bb1
--- /dev/null
+++ b/source/blender/yafray/intern/export_File.cpp
@@ -0,0 +1,2058 @@
+#include "export_File.h"
+
+#include <math.h>
+
+using namespace std;
+
+static string command_path = "";
+
+#ifdef WIN32
+#define WIN32_SKIP_HKEY_PROTECTION
+#include "BLI_winstuff.h"
+
+#ifndef FILE_MAXDIR
+#define FILE_MAXDIR 160
+#endif
+
+#ifndef FILE_MAXFILE
+#define FILE_MAXFILE 80
+#endif
+
+
+static string find_path()
+{
+ HKEY hkey;
+ DWORD dwType, dwSize;
+
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,"Software\\YafRay Team\\YafRay",0,KEY_READ,&hkey)==ERROR_SUCCESS)
+ {
+ dwType = REG_EXPAND_SZ;
+ dwSize = MAX_PATH;
+ DWORD dwStat;
+
+ char *pInstallDir=new char[MAX_PATH];
+
+ dwStat=RegQueryValueEx(hkey, TEXT("InstallDir"),
+ NULL, NULL,(LPBYTE)pInstallDir, &dwSize);
+
+ if (dwStat == NO_ERROR)
+ {
+ string res=pInstallDir;
+ delete [] pInstallDir;
+ return res;
+ }
+ else
+ cout << "Couldn't READ \'InstallDir\' value. Is yafray correctly installed?\n";
+ delete [] pInstallDir;
+
+ RegCloseKey(hkey);
+ }
+ else
+ cout << "Couldn't FIND registry key for yafray, is it installed?\n";
+
+ return string("");
+
+}
+
+static int createDir(char* name)
+{
+ if (BLI_exists(name))
+ return 2; //exists
+ if (CreateDirectory((LPCTSTR)(name), NULL)) {
+ cout << "Directory: " << name << " created\n";
+ return 1; // created
+ }
+ else {
+ cout << "Could not create directory: " << name << endl;
+ return 0; // fail
+ }
+}
+
+extern "C" { extern char bprogname[]; }
+
+// add drive character if not in path string, using blender executable location as reference
+// later added note: doesn't make much sense actually,
+// the intended file might not be located on the same drive as where blender is located...
+static void addDrive(string &path)
+{
+ int sp = path.find_first_of(":");
+ if (sp==-1) {
+ string blpath = bprogname;
+ sp = blpath.find_first_of(":");
+ if (sp!=-1) path = blpath.substr(0, sp+1) + path;
+ }
+}
+
+#else
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static string unixYafrayPath()
+{
+ static char *alternative[]=
+ {
+ "/usr/local/bin/",
+ "/usr/bin/",
+ "/bin/",
+ NULL
+ };
+
+ for(int i=0;alternative[i]!=NULL;++i)
+ {
+ string fp=string(alternative[i])+"yafray";
+ struct stat st;
+ if(stat(fp.c_str(),&st)<0) continue;
+ if(st.st_mode&S_IXOTH) return alternative[i];
+ }
+ return "";
+}
+
+#endif
+
+#ifdef WIN32
+#define MAXPATHLEN MAX_PATH
+#else
+#include <sys/param.h>
+#endif
+static void adjustPath(string &path)
+{
+ // if relative, expand to full path
+ char cpath[MAXPATHLEN];
+ strcpy(cpath, path.c_str());
+ BLI_convertstringcode(cpath, G.sce, 0);
+ path = cpath;
+#ifdef WIN32
+ // add drive char if not there
+ addDrive(path);
+#endif
+}
+
+bool yafrayFileRender_t::initExport()
+{
+ xmlpath = "";
+ bool dir_failed = false;
+ // try the user setting setting first, export dir must be set and exist
+ if (strlen(U.yfexportdir)==0)
+ {
+ cout << "No export directory set in user defaults!" << endl;
+ char* temp = getenv("TEMP");
+ // if no envar, use /tmp
+ xmlpath = temp ? temp : "/tmp";
+ cout << "Will try TEMP instead: " << xmlpath << endl;
+ // no fail here, but might fail when opening file...
+ }
+ else
+ {
+ xmlpath = U.yfexportdir;
+ adjustPath(xmlpath); // possibly relative
+ cout << "YFexport path is: " << xmlpath << endl;
+ // check if it exists
+ if (!BLI_exists(const_cast<char*>(xmlpath.c_str()))) {
+ cout << "YafRay temporary xml export directory:\n" << U.yfexportdir << "\ndoes not exist!\n";
+#ifdef WIN32
+ // try to create it
+ cout << "Trying to create...\n";
+ if (createDir(const_cast<char*>(xmlpath.c_str()))==0) dir_failed=true; else dir_failed=false;
+#else
+ dir_failed = true;
+#endif
+ }
+ }
+
+#ifdef WIN32
+ // for windows try to get the path to the yafray binary from the registry, only done once
+ if (command_path=="")
+ {
+ char path[FILE_MAXDIR+FILE_MAXFILE];
+ string yafray_path = find_path();
+ if (yafray_path=="")
+ {
+ // error already printed in find_path()
+ clearAll();
+ return false;
+ }
+ GetShortPathName((LPCTSTR)(yafray_path.c_str()), path, FILE_MAXDIR+FILE_MAXFILE);
+ command_path = string(path) + "\\";
+ cout << "Yafray found at : " << command_path << endl;
+ }
+ // if no export dir set, or could not create, try to create one in the yafray dir, unless it already exists
+ if (dir_failed)
+ {
+ string ybdir = command_path + "YBtest";
+ if (createDir(const_cast<char*>(ybdir.c_str()))==0) dir_failed=true; else dir_failed=false;
+ xmlpath = ybdir;
+ }
+#else
+ if (command_path=="")
+ {
+ command_path = unixYafrayPath();
+ if (command_path.size()) cout << "Yafray found at : " << command_path << endl;
+ }
+#endif
+
+ // for all
+ if (dir_failed) return false;
+
+#ifdef WIN32
+ string DLM = "\\";
+#else
+ string DLM = "/";
+#endif
+ // remove trailing slash if needed
+ if (xmlpath.find_last_of(DLM)!=(xmlpath.length()-1)) xmlpath += DLM;
+
+ imgout = xmlpath + "YBtest.tga";
+ xmlpath += "YBtest.xml";
+ xmlfile.open(xmlpath.c_str());
+ if (xmlfile.fail())
+ {
+ cout << "Could not open file\n";
+ return false;
+ }
+ ostr << setiosflags(ios::showpoint | ios::fixed);
+ xmlfile << "<scene>\n\n";
+ return true;
+}
+
+bool yafrayFileRender_t::writeRender()
+{
+ // finally export render block
+ ostr.str("");
+ ostr << "<render camera_name=\"MAINCAM\"\n";
+ ostr << "\traydepth=\"" << re->r.YF_raydepth << "\" gamma=\"" << re->r.YF_gamma << "\" exposure=\"" << re->r.YF_exposure << "\"\n";
+
+ if(re->r.YF_AA) {
+ ostr << "\tAA_passes=\"" << re->r.YF_AApasses << "\" AA_minsamples=\"" << re->r.YF_AAsamples << "\"\n";
+ ostr << "\tAA_pixelwidth=\"" << re->r.YF_AApixelsize << "\" AA_threshold=\"" << re->r.YF_AAthreshold << "\"\n";
+ }
+ else {
+ // removed the default AA settings for midquality GI, better leave it to user
+ if ((re->r.mode & R_OSA) && (re->r.osa)) {
+ int passes = (re->r.osa & 3)==0 ? (re->r.osa >> 2) : 1;
+ int minsamples=(re->r.osa & 3)==0 ? 4 : re->r.osa;
+ ostr << "\tAA_passes=\"" << passes << "\" AA_minsamples=\"" << minsamples << "\"\n";
+ }
+ else ostr << "\tAA_passes=\"0\" AA_minsamples=\"1\"\n";
+ ostr << "\tAA_pixelwidth=\"1.5\" AA_threshold=\"0.05\" bias=\"" << re->r.YF_raybias
+ << "\" clamp_rgb=\"" << ((re->r.YF_clamprgb==0) ? "on" : "off") << "\"\n";
+ }
+
+ World *world = G.scene->world;
+ if (world) ostr << "\tbackground_name=\"world_background\"\n";
+
+ // alpha channel render when RGBA button enabled
+ if (re->r.planes==R_PLANES32) ostr << "\n\tsave_alpha=\"on\"";
+ ostr << " >\n";
+
+ // basic fog
+ if (world && (world->mode & WO_MIST)) {
+ float fd = world->mistdist;
+ if (fd>0) fd=1.f/fd; else fd=1;
+ ostr << "\t<fog_density value=\"" << fd << "\" />\n";
+ ostr << "\t<fog_color r=\"" << world->horr << "\" g=\"" << world->horg << "\" b=\"" << world->horb << "\" />\n";
+ }
+ ostr << "\t<outfile value=\"" << imgout << "\" />\n";
+
+ ostr << "</render>\n\n";
+ xmlfile << ostr.str();
+ return true;
+}
+
+bool yafrayFileRender_t::finishExport()
+{
+ xmlfile << "</scene>\n";
+ xmlfile.close();
+
+ // file exported, now render
+ if (executeYafray(xmlpath))
+ displayImage();
+ else
+ {
+ cout << "Could not execute yafray. Is it in path?" << endl;
+ return false;
+ }
+ return true;
+}
+
+// displays the image rendered with xml export
+// Now loads rendered image into blender renderbuf.
+void yafrayFileRender_t::displayImage()
+{
+ // although it is possible to load the image using blender,
+ // maybe it is best to just do a read here, for now the yafray output is always a raw tga anyway
+
+ FILE* fp = fopen(imgout.c_str(), "rb");
+ if (fp==NULL) {
+ cout << "YAF_displayImage(): Could not open image file\n";
+ return;
+ }
+
+ unsigned char header[18];
+ fread(&header, 1, 18, fp);
+ unsigned short width = (unsigned short)(header[12] + (header[13]<<8));
+ unsigned short height = (unsigned short)(header[14] + (header[15]<<8));
+ // don't do anything if resolution doesn't match that of rectot
+ if ((width!=re->winx) || (height!=re->winy)) {
+ cout << "Wrong image width/height: " << width << "/" << height <<
+ " expected " << re->winx << "/" << re->winy << endl;
+ fclose(fp);
+ fp = NULL;
+ return;
+ }
+ unsigned char byte_per_pix = (unsigned char)(header[16]>>3);
+ // read past any id (none in this case though)
+ unsigned int idlen = (unsigned int)header[0];
+ if (idlen) fseek(fp, idlen, SEEK_CUR);
+
+ /* XXX how to get the image from Blender and write to it. This call doesn't allow to change buffer rects */
+ RenderResult rres;
+ RE_GetResultImage(re, &rres);
+ // rres.rectx, rres.recty is width/height
+ // rres.rectf is float buffer, scanlines starting in bottom
+ // rres.rectz is zbuffer, available when associated pass is set
+
+ // read data directly into buffer, picture is upside down
+ const float btf = 1.f/255.f;
+ if (re->r.mode & R_BORDER) {
+ // border render, yafray is full size render, blender at this point only wants the region
+ unsigned int xs = (unsigned int)(re->r.border.xmin * re->winx),
+ ys = (unsigned int)((1.f-re->r.border.ymax) * re->winy);
+ for (unsigned short y=0; y<height; y++) {
+ for (unsigned short x=0; x<width; x++) {
+ char r = fgetc(fp);
+ char g = fgetc(fp);
+ char b = fgetc(fp);
+ char a = (byte_per_pix==4) ? fgetc(fp) : 255;
+ int bx = x-xs, by = y-ys;
+ if ((bx >= 0) && (bx < (int)re->rectx) && (by >= 0) && (by < re->recty)) {
+ float* bpt = (float*)rres.rectf + (bx + (((re->recty-1) - by)*re->rectx) << 2);
+ bpt[2] = (float)r * btf;
+ bpt[1] = (float)g * btf;
+ bpt[0] = (float)b * btf;
+ bpt[3] = (float)a * btf;
+ bpt += 4;
+ }
+ }
+ }
+ }
+ else {
+ for (unsigned short y=0; y<height; y++) {
+ float* bpt = (float*)rres.rectf + ((((height-1)-y)*width) << 2);
+ for (unsigned short x=0; x<width; x++) {
+ bpt[2] = ((float)fgetc(fp) * btf);
+ bpt[1] = ((float)fgetc(fp) * btf);
+ bpt[0] = ((float)fgetc(fp) * btf);
+ bpt[3] = (byte_per_pix==4) ? ((float)fgetc(fp) * btf) : 1.f;
+ bpt += 4;
+ }
+ }
+ }
+
+ fclose(fp);
+ fp = NULL;
+
+ // based on another assumption of ogl errors on my system, forgot to actually draw it...
+ re->result->renlay = render_get_active_layer(re, re->result);
+ re->display_draw(re->result, NULL);
+
+}
+
+static string noise2string(short nbtype)
+{
+ switch (nbtype) {
+ case TEX_BLENDER:
+ return "blender";
+ case TEX_STDPERLIN:
+ return "stdperlin";
+ case TEX_VORONOI_F1:
+ return "voronoi_f1";
+ case TEX_VORONOI_F2:
+ return "voronoi_f2";
+ case TEX_VORONOI_F3:
+ return "voronoi_f3";
+ case TEX_VORONOI_F4:
+ return "voronoi_f4";
+ case TEX_VORONOI_F2F1:
+ return "voronoi_f2f1";
+ case TEX_VORONOI_CRACKLE:
+ return "voronoi_crackle";
+ case TEX_CELLNOISE:
+ return "cellnoise";
+ default:
+ case TEX_NEWPERLIN:
+ return "newperlin";
+ }
+}
+
+void yafrayFileRender_t::writeTextures()
+{
+ // used to keep track of images already written
+ // (to avoid duplicates if also in imagetex for material TexFace texture)
+ set<Image*> dupimg;
+
+ for (map<string, MTex*>::const_iterator blendtex=used_textures.begin();
+ blendtex!=used_textures.end();++blendtex) {
+ MTex* mtex = blendtex->second;
+ Tex* tex = mtex->tex;
+
+ float nsz = tex->noisesize;
+ if (nsz!=0.f) nsz=1.f/nsz;
+
+ // noisebasis type
+ string ntype = noise2string(tex->noisebasis);
+ string ts, hardnoise=(tex->noisetype==TEX_NOISESOFT) ? "off" : "on";
+
+ switch (tex->type) {
+ case TEX_STUCCI:
+ // stucci is clouds as bump, only difference is an extra parameter to handle wall in/out
+ // turbulence value is not used, so for large values will not match well
+ case TEX_CLOUDS: {
+ ostr.str("");
+ ostr << "<shader type=\"clouds\" name=\"" << blendtex->first << "\" >\n";
+ ostr << "\t<attributes>\n";
+ ostr << "\t\t<size value=\"" << nsz << "\" />\n";
+ ostr << "\t\t<hard value=\"" << hardnoise << "\" />\n";
+ if (tex->type==TEX_STUCCI) {
+ if (tex->stype==1)
+ ts = "positive";
+ else if (tex->stype==2)
+ ts = "negative";
+ else ts = "none";
+ ostr << "\t\t<bias value=\"" << ts << "\" />\n";
+ ostr << "\t\t<depth value=\"0\" />\n"; // for stucci always 0
+ }
+ else ostr << "\t\t<depth value=\"" << tex->noisedepth << "\" />\n";
+ ostr << "\t\t<color_type value=\"" << tex->stype << "\" />\n";
+ ostr << "\t\t<noise_type value=\"" << ntype << "\" />\n";
+ ostr << "\t</attributes>\n</shader >\n\n";
+ xmlfile << ostr.str();
+ break;
+ }
+ case TEX_WOOD: {
+ ostr.str("");
+ ostr << "<shader type=\"wood\" name=\"" << blendtex->first << "\" >\n";
+ ostr << "\t\t<attributes>\n";
+ // blender does not use depth value for wood, always 0
+ ostr << "\t\t<depth value=\"0\" />\n";
+ float turb = (tex->stype<2) ? 0.0 : tex->turbul;
+ ostr << "\t\t<turbulence value=\"" << turb << "\" />\n";
+ ostr << "\t\t<size value=\"" << nsz << "\" />\n";
+ ostr << "\t\t<hard value=\"" << hardnoise << "\" />\n";
+ ts = (tex->stype & 1) ? "rings" : "bands"; //stype 1&3 ringtype
+ ostr << "\t\t<wood_type value=\"" << ts << "\" />\n";
+ ostr << "\t\t<noise_type value=\"" << ntype << "\" />\n";
+ // shape parameter, for some reason noisebasis2 is used...
+ ts = "sin";
+ if (tex->noisebasis2==1) ts="saw"; else if (tex->noisebasis2==2) ts="tri";
+ ostr << "\t\t<shape value=\"" << ts << "\" />\n";
+ ostr << "\t</attributes>\n</shader>\n\n";
+ xmlfile << ostr.str();
+ break;
+ }
+ case TEX_MARBLE: {
+ ostr.str("");
+ ostr << "<shader type=\"marble\" name=\"" << blendtex->first << "\" >\n";
+ ostr << "\t<attributes>\n";
+ ostr << "\t\t<depth value=\"" << tex->noisedepth << "\" />\n";
+ ostr << "\t\t<turbulence value=\"" << tex->turbul << "\" />\n";
+ ostr << "\t\t<size value=\"" << nsz << "\" />\n";
+ ostr << "\t\t<hard value=\"" << hardnoise << "\" />\n";
+ ostr << "\t\t<sharpness value=\"" << (float)(1<<tex->stype) << "\" />\n";
+ ostr << "\t\t<noise_type value=\"" << ntype << "\" />\n";
+ ts = "sin";
+ if (tex->noisebasis2==1) ts="saw"; else if (tex->noisebasis2==2) ts="tri";
+ ostr << "\t\t<shape value=\"" << ts << "\" />\n";
+ ostr << "\t</attributes>\n</shader>\n\n";
+ xmlfile << ostr.str();
+ break;
+ }
+ case TEX_VORONOI: {
+ ostr.str("");
+ ostr << "<shader type=\"voronoi\" name=\"" << blendtex->first << "\" >\n";
+ ostr << "\t<attributes>\n";
+ ts = "int";
+ if (tex->vn_coltype==1)
+ ts = "col1";
+ else if (tex->vn_coltype==2)
+ ts = "col2";
+ else if (tex->vn_coltype==3)
+ ts = "col3";
+ ostr << "\t\t<color_type value=\"" << ts << "\" />\n";
+ ostr << "\t\t<weight1 value=\"" << tex->vn_w1 << "\" />\n";
+ ostr << "\t\t<weight2 value=\"" << tex->vn_w2 << "\" />\n";
+ ostr << "\t\t<weight3 value=\"" << tex->vn_w3 << "\" />\n";
+ ostr << "\t\t<weight4 value=\"" << tex->vn_w4 << "\" />\n";
+ ostr << "\t\t<mk_exponent value=\"" << tex->vn_mexp << "\" />\n";
+ ostr << "\t\t<intensity value=\"" << tex->ns_outscale << "\" />\n";
+ ostr << "\t\t<size value=\"" << nsz << "\" />\n";
+ ts = "actual";
+ if (tex->vn_distm==TEX_DISTANCE_SQUARED)
+ ts = "squared";
+ else if (tex->vn_distm==TEX_MANHATTAN)
+ ts = "manhattan";
+ else if (tex->vn_distm==TEX_CHEBYCHEV)
+ ts = "chebychev";
+ else if (tex->vn_distm==TEX_MINKOVSKY_HALF)
+ ts = "minkovsky_half";
+ else if (tex->vn_distm==TEX_MINKOVSKY_FOUR)
+ ts = "minkovsky_four";
+ else if (tex->vn_distm==TEX_MINKOVSKY)
+ ts = "minkovsky";
+ ostr << "\t\t<distance_metric value=\"" << ts << "\" />\n";
+ ostr << "\t</attributes>\n</shader>\n\n";
+ xmlfile << ostr.str();
+ break;
+ }
+ case TEX_MUSGRAVE: {
+ ostr.str("");
+ ostr << "<shader type=\"musgrave\" name=\"" << blendtex->first << "\" >\n";
+ ostr << "\t<attributes>\n";
+ switch (tex->stype) {
+ case TEX_MFRACTAL:
+ ts = "multifractal";
+ break;
+ case TEX_RIDGEDMF:
+ ts = "ridgedmf";
+ break;
+ case TEX_HYBRIDMF:
+ ts = "hybridmf";
+ break;
+ case TEX_HTERRAIN:
+ ts = "heteroterrain";
+ break;
+ default:
+ case TEX_FBM:
+ ts = "fBm";
+ }
+ ostr << "\t\t<musgrave_type value=\"" << ts << "\" />\n";
+ ostr << "\t\t<noise_type value=\"" << ntype << "\" />\n";
+ ostr << "\t\t<H value=\"" << tex->mg_H << "\" />\n";
+ ostr << "\t\t<lacunarity value=\"" << tex->mg_lacunarity << "\" />\n";
+ ostr << "\t\t<octaves value=\"" << tex->mg_octaves << "\" />\n";
+ if ((tex->stype==TEX_HTERRAIN) || (tex->stype==TEX_RIDGEDMF) || (tex->stype==TEX_HYBRIDMF)) {
+ ostr << "\t\t<offset value=\"" << tex->mg_offset << "\" />\n";
+ if ((tex->stype==TEX_RIDGEDMF) || (tex->stype==TEX_HYBRIDMF))
+ ostr << "\t\t<gain value=\"" << tex->mg_gain << "\" />\n";
+ }
+ ostr << "\t\t<size value=\"" << nsz << "\" />\n";
+ ostr << "\t\t<intensity value=\"" << tex->ns_outscale << "\" />\n";
+ ostr << "\t</attributes>\n</shader>\n\n";
+ xmlfile << ostr.str();
+ break;
+ }
+ case TEX_DISTNOISE: {
+ ostr.str("");
+ ostr << "<shader type=\"distorted_noise\" name=\"" << blendtex->first << "\" >\n";
+ ostr << "\t<attributes>\n";
+ ostr << "\t\t<distort value=\"" << tex->dist_amount << "\" />\n";
+ ostr << "\t\t<size value=\"" << nsz << "\" />\n";
+ ostr << "\t\t<noise_type1 value=\"" << ntype << "\" />\n";
+ ostr << "\t\t<noise_type2 value=\"" << noise2string(tex->noisebasis2) << "\" />\n";
+ ostr << "\t</attributes>\n</shader>\n\n";
+ xmlfile << ostr.str();
+ break;
+ }
+ case TEX_BLEND: {
+ ostr.str("");
+ ostr << "<shader type=\"gradient\" name=\"" << blendtex->first << "\" >\n";
+ ostr << "\t<attributes>\n";
+ switch (tex->stype) {
+ case 1: ts="quadratic"; break;
+ case 2: ts="cubic"; break;
+ case 3: ts="diagonal"; break;
+ case 4: ts="sphere"; break;
+ case 5: ts="halo"; break;
+ default:
+ case 0: ts="linear"; break;
+ }
+ ostr << "\t\t<gradient_type value=\"" << ts << "\" />\n";
+ if (tex->flag & TEX_FLIPBLEND) ts="on"; else ts="off";
+ ostr << "\t\t<flip_xy value=\"" << ts << "\" />\n";
+ ostr << "\t</attributes>\n</shader>\n\n";
+ xmlfile << ostr.str();
+ break;
+ }
+ case TEX_NOISE: {
+ ostr.str("");
+ ostr << "<shader type=\"random_noise\" name=\"" << blendtex->first << "\" >\n";
+ ostr << "\t<attributes>\n";
+ ostr << "\t\t<depth value=\"" << tex->noisedepth << "\" />\n";
+ ostr << "\t</attributes>\n</shader>\n\n";
+ xmlfile << ostr.str();
+ break;
+ }
+ case TEX_IMAGE: {
+ Image* ima = tex->ima;
+ if (ima) {
+ // remember image to avoid duplicates later if also in imagetex
+ // (formerly done by removing from imagetex, but need image/material link)
+ dupimg.insert(ima);
+ ostr.str("");
+ // use image name instead of texname here
+ ostr << "<shader type=\"image\" name=\"" << ima->id.name << "\" >\n";
+ ostr << "\t<attributes>\n";
+ string texpath(ima->name);
+ adjustPath(texpath);
+ ostr << "\t\t<filename value=\"" << texpath << "\" />\n";
+ ostr << "\t\t<interpolate value=\"" << ((tex->imaflag & TEX_INTERPOL) ? "bilinear" : "none") << "\" />\n";
+ ostr << "\t</attributes>\n</shader>\n\n";
+ xmlfile << ostr.str();
+ }
+ break;
+ }
+ default:
+ cout << "Unsupported texture type\n";
+ }
+
+ // colorbands
+ if (tex->flag & TEX_COLORBAND) {
+ ColorBand* cb = tex->coba;
+ if (cb) {
+ ostr.str("");
+ ostr << "<shader type=\"colorband\" name=\"" << blendtex->first + "_coba" << "\" >\n";
+ ostr << "\t<attributes>\n";
+ ostr << "\t\t<input value=\"" << blendtex->first << "\" />\n";
+ ostr << "\t</attributes>\n";
+ for (int i=0;i<cb->tot;i++) {
+ ostr << "\t<modulator value=\"" << cb->data[i].pos << "\" >\n";
+ ostr << "\t\t<color r=\"" << cb->data[i].r << "\"" <<
+ " g=\"" << cb->data[i].g << "\"" <<
+ " b=\"" << cb->data[i].b << "\"" <<
+ " a=\"" << cb->data[i].a << "\" />\n";
+ ostr << "\t</modulator>\n";
+ }
+ ostr << "</shader>\n\n";
+ xmlfile << ostr.str();
+ }
+ }
+
+ }
+
+ // If used, textures for the material 'TexFace' case
+ if (!imagetex.empty()) {
+ for (map<Image*, set<Material*> >::const_iterator imgtex=imagetex.begin();
+ imgtex!=imagetex.end();++imgtex)
+ {
+ // skip if already written above
+ Image* ima = imgtex->first;
+ if (dupimg.find(ima)==dupimg.end()) {
+ ostr.str("");
+ ostr << "<shader type=\"image\" name=\"" << ima->id.name << "\" >\n";
+ ostr << "\t<attributes>\n";
+ string texpath(ima->name);
+ adjustPath(texpath);
+ ostr << "\t\t<filename value=\"" << texpath << "\" />\n";
+ ostr << "\t</attributes>\n</shader>\n\n";
+ xmlfile << ostr.str();
+ }
+ }
+ }
+
+}
+
+void yafrayFileRender_t::writeShader(const string &shader_name, Material* matr, const string &facetexname)
+{
+ // if material has ramps, export colorbands first
+ if (matr->mode & (MA_RAMP_COL|MA_RAMP_SPEC))
+ {
+ // both colorbands without input shader
+ ColorBand* cb = matr->ramp_col;
+ if ((matr->mode & MA_RAMP_COL) && (cb!=NULL))
+ {
+ ostr.str("");
+ ostr << "<shader type=\"colorband\" name=\"" << shader_name+"_difframp" << "\" >\n";
+ ostr << "\t<attributes>\n\t</attributes>\n";
+ for (int i=0;i<cb->tot;i++) {
+ ostr << "\t<modulator value=\"" << cb->data[i].pos << "\" >\n";
+ ostr << "\t\t<color r=\"" << cb->data[i].r << "\"" <<
+ " g=\"" << cb->data[i].g << "\"" <<
+ " b=\"" << cb->data[i].b << "\"" <<
+ " a=\"" << cb->data[i].a << "\" />\n";
+ ostr << "\t</modulator>\n";
+ }
+ ostr << "</shader>\n\n";
+ xmlfile << ostr.str();
+ }
+ cb = matr->ramp_spec;
+ if ((matr->mode & MA_RAMP_SPEC) && (cb!=NULL))
+ {
+ ostr.str("");
+ ostr << "<shader type=\"colorband\" name=\"" << shader_name+"_specramp" << "\" >\n";
+ ostr << "\t<attributes>\n\t</attributes>\n";
+ for (int i=0;i<cb->tot;i++) {
+ ostr << "\t<modulator value=\"" << cb->data[i].pos << "\" >\n";
+ ostr << "\t\t<color r=\"" << cb->data[i].r << "\"" <<
+ " g=\"" << cb->data[i].g << "\"" <<
+ " b=\"" << cb->data[i].b << "\"" <<
+ " a=\"" << cb->data[i].a << "\" />\n";
+ ostr << "\t</modulator>\n";
+ }
+ ostr << "</shader>\n\n";
+ xmlfile << ostr.str();
+ }
+ }
+
+ ostr.str("");
+ ostr << "<shader type=\"blendershader\" name=\"" << shader_name << "\" >\n";
+ ostr << "\t<attributes>\n";
+ ostr << "\t\t<color r=\"" << matr->r << "\" g=\"" << matr->g << "\" b=\"" << matr->b << "\" />\n";
+ float sr=matr->specr, sg=matr->specg, sb=matr->specb;
+ if (matr->spec_shader==MA_SPEC_WARDISO) {
+ // ........
+ sr /= M_PI;
+ sg /= M_PI;
+ sb /= M_PI;
+ }
+ ostr << "\t\t<specular_color r=\"" << sr << "\" g=\"" << sg << "\" b=\"" << sb << "\" />\n";
+ ostr << "\t\t<mirror_color r=\"" << matr->mirr << "\" g=\"" << matr->mirg << "\" b=\"" << matr->mirb << "\" />\n";
+ ostr << "\t\t<diffuse_reflect value=\"" << matr->ref << "\" />\n";
+ ostr << "\t\t<specular_amount value=\"" << matr->spec << "\" />\n";
+ ostr << "\t\t<alpha value=\"" << matr->alpha << "\" />\n";
+ // if no GI used, the GIpower parameter is not always initialized, so in that case ignore it
+ float bg_mult = (re->r.GImethod==0) ? 1 : re->r.GIpower;
+ ostr << "\t\t<emit value=\"" << (matr->emit * bg_mult) << "\" />\n";
+
+ // reflection/refraction
+ if ( (matr->mode & MA_RAYMIRROR) || (matr->mode & MA_RAYTRANSP) )
+ ostr << "\t\t<IOR value=\"" << matr->ang << "\" />\n";
+
+ if (matr->mode & MA_RAYMIRROR)
+ {
+ // Sofar yafray's min_refle parameter (which misleadingly actually controls fresnel reflection offset)
+ // has been mapped to Blender's ray_mirror parameter.
+ // This causes it be be misinterpreted and misused as a reflection amount control however.
+ // Besides that, it also causes extra complications for the yafray Blendershader.
+ // So added an actual amount of reflection parameter instead, and another
+ // extra parameter 'frsOfs' to actually control fresnel offset (re-uses Blender fresnel_mir_i param).
+ ostr << "\t\t<reflect value=\"on\" />\n";
+ ostr << "\t\t<reflect_amount value=\""<< matr->ray_mirror << "\" />\n";
+ float fo = 1.f-(matr->fresnel_mir_i-1.f)*0.25f; // blender param range [1,5], also here reversed (1 in Blender -> no fresnel)
+ ostr << "\t\t<fresnel_offset value=\""<< fo << "\" />\n";
+
+ // for backward compatibility, also add old 'reflected' parameter, copy of mirror_color
+ ostr << "\t\t<reflected r=\"" << matr->mirr << "\" g=\"" << matr->mirg << "\" b=\"" << matr->mirb << "\" />\n";
+ // same for 'min_refle' param. Instead of the ray_mirror parameter that was used before, since now
+ // the parameter's function is taken over by the fresnel offset parameter, use that instead.
+ ostr << "\t\t<min_refle value=\"" << fo << "\" />\n";
+
+ }
+
+ if (matr->mode & MA_RAYTRANSP)
+ {
+ ostr << "\t\t<refract value=\"on\" />\n";
+ ostr << "\t\t<transmit_filter value=\"" << matr->filter << "\" />\n";
+ // tir on by default
+ ostr << "\t\t<tir value=\"on\" />\n";
+
+ // transmit absorption color
+ // to make things easier(?) for user it now specifies the actual color at 1 unit / YF_dscale of distance
+ const float maxlog = -log(1e-38);
+ float ar = (matr->YF_ar>0) ? -log(matr->YF_ar) : maxlog;
+ float ag = (matr->YF_ag>0) ? -log(matr->YF_ag) : maxlog;
+ float ab = (matr->YF_ab>0) ? -log(matr->YF_ab) : maxlog;
+ float sc = matr->YF_dscale;
+ if (sc!=0.f) sc=1.f/sc;
+ ostr << "\t\t<absorption r=\"" << ar*sc << "\" g=\"" << ag*sc << "\" b=\"" << ab*sc << "\" />\n";
+ // dispersion
+ ostr << "\t\t<dispersion_power value=\"" << matr->YF_dpwr << "\" />\n";
+ ostr << "\t\t<dispersion_samples value=\"" << matr->YF_dsmp << "\" />\n";
+ ostr << "\t\t<dispersion_jitter value=\"" << (matr->YF_djit ? "on" : "off") << "\" />\n";
+
+ // for backward compatibility, also add old 'transmitted' parameter, copy of 'color' * (1-alpha)
+ float na = 1.f-matr->alpha;
+ ostr << "\t\t<transmitted r=\"" << matr->r*na << "\" g=\"" << matr->g*na << "\" b=\"" << matr->b*na << "\" />\n";
+ }
+
+ string Mmode = "";
+ if (matr->mode & MA_TRACEBLE) Mmode += "traceable";
+ if (matr->mode & MA_SHADOW) Mmode += " shadow";
+ if (matr->mode & MA_SHLESS) Mmode += " shadeless";
+ if (matr->mode & MA_VERTEXCOL) Mmode += " vcol_light";
+ if (matr->mode & MA_VERTEXCOLP) Mmode += " vcol_paint";
+ if (matr->mode & MA_ZTRA) Mmode += " ztransp";
+ if (matr->mode & MA_ONLYSHADOW) Mmode += " onlyshadow";
+ if (Mmode!="") ostr << "\t\t<matmodes value=\"" << Mmode << "\" />\n";
+
+ // diffuse & specular brdf, lambert/cooktorr defaults
+ // diffuse
+ if (matr->diff_shader==MA_DIFF_ORENNAYAR) {
+ ostr << "\t\t<diffuse_brdf value=\"oren_nayar\" />\n";
+ ostr << "\t\t<roughness value=\"" << matr->roughness << "\" />\n";
+ }
+ else if (matr->diff_shader==MA_DIFF_TOON) {
+ ostr << "\t\t<diffuse_brdf value=\"toon\" />\n";
+ ostr << "\t\t<toondiffuse_size value=\"" << matr->param[0] << "\" />\n";
+ ostr << "\t\t<toondiffuse_smooth value=\"" << matr->param[1] << "\" />\n";
+ }
+ else if (matr->diff_shader==MA_DIFF_MINNAERT) {
+ ostr << "\t\t<diffuse_brdf value=\"minnaert\" />\n";
+ ostr << "\t\t<darkening value=\"" << matr->darkness << "\" />\n";
+ }
+ else ostr << "\t\t<diffuse_brdf value=\"lambert\" />\n";
+ // specular
+ if (matr->spec_shader==MA_SPEC_PHONG) {
+ ostr << "\t\t<specular_brdf value=\"phong\" />\n";
+ ostr << "\t\t<hard value=\"" << matr->har << "\" />\n";
+ }
+ else if (matr->spec_shader==MA_SPEC_BLINN) {
+ ostr << "\t\t<specular_brdf value=\"blinn\" />\n";
+ ostr << "\t\t<blinn_ior value=\"" << matr->refrac << "\" />\n";
+ ostr << "\t\t<hard value=\"" << matr->har << "\" />\n";
+ }
+ else if (matr->spec_shader==MA_SPEC_TOON) {
+ ostr << "\t\t<specular_brdf value=\"toon\" />\n";
+ ostr << "\t\t<toonspecular_size value=\"" << matr->param[2] << "\" />\n";
+ ostr << "\t\t<toonspecular_smooth value=\"" << matr->param[3] << "\" />\n";
+ }
+ else if (matr->spec_shader==MA_SPEC_WARDISO) {
+ ostr << "\t\t<specular_brdf value=\"ward\" />\n";
+ ostr << "\t\t<u_roughness value=\"" << matr->rms << "\" />\n";
+ ostr << "\t\t<v_roughness value=\"" << matr->rms << "\" />\n";
+ }
+ else {
+ ostr << "\t\t<specular_brdf value=\"blender_cooktorr\" />\n";
+ ostr << "\t\t<hard value=\"" << matr->har << "\" />\n";
+ }
+
+ // ramps, if used
+ if (matr->mode & (MA_RAMP_COL|MA_RAMP_SPEC))
+ {
+ const string rm_blend[9] = {"mix", "add", "mul", "sub", "screen", "divide", "difference", "darken", "lighten"};
+ const string rm_mode[4] = {"shader", "energy", "normal", "result"};
+ // diffuse
+ if ((matr->mode & MA_RAMP_COL) && (matr->ramp_col!=NULL))
+ {
+ ostr << "\t\t<diffuse_ramp value=\"" << shader_name+"_difframp" << "\" />\n";
+ ostr << "\t\t<diffuse_ramp_mode value=\"" << rm_mode[(int)matr->rampin_col] << "\" />\n";
+ ostr << "\t\t<diffuse_ramp_blend value=\"" << rm_blend[(int)matr->rampblend_col] << "\" />\n";
+ ostr << "\t\t<diffuse_ramp_factor value=\"" << matr->rampfac_col << "\" />\n";
+ }
+ // specular
+ if ((matr->mode & MA_RAMP_SPEC) && (matr->ramp_spec!=NULL)) {
+ ostr << "\t\t<specular_ramp value=\"" << shader_name+"_specramp" << "\" />\n";
+ ostr << "\t\t<specular_ramp_mode value=\"" << rm_mode[(int)matr->rampin_spec] << "\" />\n";
+ ostr << "\t\t<specular_ramp_blend value=\"" << rm_blend[(int)matr->rampblend_spec] << "\" />\n";
+ ostr << "\t\t<specular_ramp_factor value=\"" << matr->rampfac_spec << "\" />\n";
+ }
+ }
+
+ ostr << "\t</attributes>\n";
+ xmlfile << ostr.str();
+
+ // modulators
+ // first modulator is the texture of the face, if used (TexFace mode)
+ if (facetexname.length()!=0) {
+ ostr.str("");
+ ostr << "\t<modulator>\n";
+ ostr << "\t\t<input value=\"" << facetexname << "\" />\n";
+ ostr << "\t\t<color value=\"1\" />\n";
+ ostr << "\t</modulator>\n";
+ xmlfile << ostr.str();
+ }
+
+ for (int m2=0;m2<MAX_MTEX;m2++) {
+
+ if (matr->septex & (1<<m2)) continue;// all active channels
+
+ // ignore null mtex
+ MTex* mtex = matr->mtex[m2];
+ if (mtex==NULL) continue;
+
+ // ignore null tex
+ Tex* tex = mtex->tex;
+ if (tex==NULL) continue;
+
+ map<string, MTex*>::const_iterator mtexL = used_textures.find(string(tex->id.name));
+ if (mtexL!=used_textures.end()) {
+
+ ostr.str("");
+ ostr << "\t<modulator>\n";
+ // when no facetex used, shader_name is created from original material name
+ if (facetexname.length()!=0)
+ ostr << "\t\t<input value=\"" << matr->id.name << "_map" << m2 << "\" />\n";
+ else
+ ostr << "\t\t<input value=\"" << shader_name << "_map" << m2 << "\" />\n";
+
+ // blendtype, would have been nice if the order would have been the same as for ramps...
+ const string blendtype[9] = {"mix", "mul", "add", "sub", "divide", "darken", "difference", "lighten", "screen"};
+ ostr << "\t\t<mode value=\"" << blendtype[(int)mtex->blendtype] << "\" />\n";
+
+ // texture color (for use with MUL and/or no_rgb etc..)
+ ostr << "\t\t<texcol r=\"" << mtex->r << "\" g=\"" << mtex->g << "\" b=\"" << mtex->b << "\" />\n";
+
+ // texture contrast, brightness & color adjustment
+ ostr << "\t\t<filtercolor r=\"" << tex->rfac << "\" g=\"" << tex->gfac << "\" b=\"" << tex->bfac << "\" />\n";
+ ostr << "\t\t<contrast value=\"" << tex->contrast << "\" />\n";
+ ostr << "\t\t<brightness value=\"" << tex->bright << "\" />\n";
+
+ // all texture flags now are switches, having the value 1 or -1 (negative option)
+ // the negative option only used for the intensity modulation options.
+
+ // material (diffuse) color, amount controlled by colfac (see below)
+ if (mtex->mapto & MAP_COL)
+ ostr << "\t\t<color value=\"1\" />\n";
+
+ // bumpmapping
+ if ((mtex->mapto & MAP_NORM) || (mtex->maptoneg & MAP_NORM)) {
+ // for yafray, bump factor is negated (unless tex is stucci, not affected by 'Neg')
+ // scaled down quite a bit
+ float nf = mtex->norfac;
+ if (tex->type!=TEX_STUCCI) nf *= -1.f;
+ if (mtex->maptoneg & MAP_NORM) nf *= -1.f;
+ ostr << "\t\t<normal value=\"" << (nf/60.f) << "\" />\n";
+
+ }
+
+ // all blender texture modulation as switches, either 1 or -1 (negative state of button)
+ // Csp, specular color modulation
+ if (mtex->mapto & MAP_COLSPEC)
+ ostr << "\t\t<colspec value=\"1\" />\n";
+
+ // CMir, mirror color modulation
+ if (mtex->mapto & MAP_COLMIR)
+ ostr << "\t\t<colmir value=\"1\" />\n";
+
+ // Ref, diffuse reflection amount modulation
+ if ((mtex->mapto & MAP_REF) || (mtex->maptoneg & MAP_REF)) {
+ int t = 1;
+ if (mtex->maptoneg & MAP_REF) t = -1;
+ ostr << "\t\t<difref value=\"" << t << "\" />\n";
+ }
+
+ // Spec, specular amount mod
+ if ((mtex->mapto & MAP_SPEC) || (mtex->maptoneg & MAP_SPEC)) {
+ int t = 1;
+ if (mtex->maptoneg & MAP_SPEC) t = -1;
+ ostr << "\t\t<specular value=\"" << t << "\" />\n";
+ }
+
+ // hardness modulation
+ if ((mtex->mapto & MAP_HAR) || (mtex->maptoneg & MAP_HAR)) {
+ int t = 1;
+ if (mtex->maptoneg & MAP_HAR) t = -1;
+ ostr << "\t\t<hard value=\"" << t << "\" />\n";
+ }
+
+ // alpha modulation
+ if ((mtex->mapto & MAP_ALPHA) || (mtex->maptoneg & MAP_ALPHA)) {
+ int t = 1;
+ if (mtex->maptoneg & MAP_ALPHA) t = -1;
+ ostr << "\t\t<alpha value=\"" << t << "\" />\n";
+ }
+
+ // emit modulation
+ if ((mtex->mapto & MAP_EMIT) || (mtex->maptoneg & MAP_EMIT)) {
+ int t = 1;
+ if (mtex->maptoneg & MAP_EMIT) t = -1;
+ ostr << "\t\t<emit value=\"" << t << "\" />\n";
+ }
+
+ // raymir modulation
+ if ((mtex->mapto & MAP_RAYMIRR) || (mtex->maptoneg & MAP_RAYMIRR)) {
+ int t = 1;
+ if (mtex->maptoneg & MAP_RAYMIRR) t = -1;
+ ostr << "\t\t<raymir value=\"" << t << "\" />\n";
+ }
+
+ // texture flag, combination of strings
+ string ts = "";
+ if (mtex->texflag & (MTEX_RGBTOINT | MTEX_STENCIL | MTEX_NEGATIVE)) {
+ if (mtex->texflag & MTEX_RGBTOINT) ts += "no_rgb ";
+ if (mtex->texflag & MTEX_STENCIL) ts += "stencil ";
+ if (mtex->texflag & MTEX_NEGATIVE) ts += "negative";
+ ostr << "\t\t<texflag value=\"" << ts << "\" />\n";
+ }
+
+ // colfac, controls amount of color modulation
+ ostr << "\t\t<colfac value=\"" << mtex->colfac << "\" />\n";
+
+ // def_var
+ ostr << "\t\t<def_var value=\"" << mtex->def_var << "\" />\n";
+
+ //varfac
+ ostr << "\t\t<varfac value=\"" << mtex->varfac << "\" />\n";
+
+ if ((tex->imaflag & (TEX_CALCALPHA | TEX_USEALPHA)) || (tex->flag & TEX_NEGALPHA)) {
+ ts = "";
+ if (tex->imaflag & TEX_CALCALPHA) ts += "calc_alpha ";
+ if (tex->imaflag & TEX_USEALPHA) ts += "use_alpha ";
+ if (tex->flag & TEX_NEGALPHA) ts += "neg_alpha";
+ ostr << "\t\t<alpha_flag value=\"" << ts << "\" />\n";
+ }
+
+ // image as normalmap flag
+ if (tex->imaflag & TEX_NORMALMAP) ostr << "\t\t<normalmap value=\"on\" />\n";
+
+ ostr << "\t</modulator>\n";
+ xmlfile << ostr.str();
+
+ }
+ }
+ xmlfile << "</shader>\n\n";
+
+}
+
+
+// write all materials & modulators
+void yafrayFileRender_t::writeMaterialsAndModulators()
+{
+ // shaders/mappers for regular texture (or non-texture) mode
+ // In case material has texface mode, and all faces have an image texture,
+ // this shader will not be used, but still be written
+ for (map<string, Material*>::const_iterator blendmat=used_materials.begin();
+ blendmat!=used_materials.end();++blendmat)
+ {
+
+ Material* matr = blendmat->second;
+
+ // mapper(s)
+ for (int m=0;m<MAX_MTEX;m++)
+ {
+
+ if (matr->septex & (1<<m)) continue;// all active channels
+
+ // ignore null mtex
+ MTex* mtex = matr->mtex[m];
+ if (mtex==NULL) continue;
+ // ignore null tex
+ Tex* tex = mtex->tex;
+ if (tex==NULL) continue;
+
+ map<string, MTex*>::const_iterator mtexL = used_textures.find(string(tex->id.name));
+ if (mtexL!=used_textures.end()) {
+ ostr.str("");
+ ostr << "<shader type=\"blendermapper\" name=\"" << blendmat->first + "_map" << m <<"\"";
+ if ((mtex->texco & TEXCO_OBJECT) || (mtex->texco & TEXCO_REFL) || (mtex->texco & TEXCO_NORM))
+ {
+ // For object, reflection & normal mapping, add the object matrix to the modulator,
+ // as in LF script, use camera matrix if no object specified.
+ // In this case this means the inverse of that matrix
+ float texmat[4][4], itexmat[4][4];
+ if ((mtex->texco & TEXCO_OBJECT) && (mtex->object))
+ MTC_Mat4CpyMat4(texmat, mtex->object->obmat);
+ else // also for refl. map
+ MTC_Mat4CpyMat4(texmat, maincam_obj->obmat);
+ MTC_Mat4Invert(itexmat, texmat);
+ ostr << "\n\t\tm00=\"" << itexmat[0][0] << "\" m01=\"" << itexmat[1][0]
+ << "\" m02=\"" << itexmat[2][0] << "\" m03=\"" << itexmat[3][0] << "\"\n";
+ ostr << "\t\tm10=\"" << itexmat[0][1] << "\" m11=\"" << itexmat[1][1]
+ << "\" m12=\"" << itexmat[2][1] << "\" m13=\"" << itexmat[3][1] << "\"\n";
+ ostr << "\t\tm20=\"" << itexmat[0][2] << "\" m21=\"" << itexmat[1][2]
+ << "\" m22=\"" << itexmat[2][2] << "\" m23=\"" << itexmat[3][2] << "\"\n";
+ ostr << "\t\tm30=\"" << itexmat[0][3] << "\" m31=\"" << itexmat[1][3]
+ << "\" m32=\"" << itexmat[2][3] << "\" m33=\"" << itexmat[3][3] << "\">\n";
+ }
+ else ostr << ">\n";
+ ostr << "\t<attributes>\n";
+
+ // use image name instead of texname when texture is image
+ if ((tex->type==TEX_IMAGE) && tex->ima)
+ ostr << "\t\t<input value=\"" << tex->ima->id.name << "\" />\n";
+ else if ((tex->flag & TEX_COLORBAND) & (tex->coba!=NULL))
+ ostr << "\t\t<input value=\"" << mtexL->first + "_coba" << "\" />\n";
+ else
+ ostr << "\t\t<input value=\"" << mtexL->first << "\" />\n";
+
+ // texture size
+ ostr << "\t\t<sizex value=\"" << mtex->size[0] << "\" />\n";
+ ostr << "\t\t<sizey value=\"" << mtex->size[1] << "\" />\n";
+ ostr << "\t\t<sizez value=\"" << mtex->size[2] << "\" />\n";
+
+ // texture offset
+ ostr << "\t\t<ofsx value=\"" << mtex->ofs[0] << "\" />\n";
+ ostr << "\t\t<ofsy value=\"" << mtex->ofs[1] << "\" />\n";
+ ostr << "\t\t<ofsz value=\"" << mtex->ofs[2] << "\" />\n";
+
+ // texture coordinates, have to disable 'sticky' in Blender
+ if (mtex->texco & TEXCO_UV)
+ ostr << "\t\t<texco value=\"uv\" />\n";
+ else if ((mtex->texco & TEXCO_GLOB) || (mtex->texco & TEXCO_OBJECT))
+ // object mode is also set as global, but the object matrix was specified above with <modulator..>
+ ostr << "\t\t<texco value=\"global\" />\n";
+ else if ((mtex->texco & TEXCO_ORCO) || (mtex->texco & TEXCO_STRAND))
+ // orco flag now used for 'strand'-mapping as well, see mesh code
+ ostr << "\t\t<texco value=\"orco\" />\n";
+ else if (mtex->texco & TEXCO_WINDOW)
+ ostr << "\t\t<texco value=\"window\" />\n";
+ else if (mtex->texco & TEXCO_NORM)
+ ostr << "\t\t<texco value=\"normal\" />\n";
+ else if (mtex->texco & TEXCO_REFL)
+ ostr << "\t\t<texco value=\"reflect\" />\n";
+
+ // texture projection axes, both image & procedural
+ string proj = "nxyz"; // 'n' for 'none'
+ ostr << "\t\t<proj_x value=\"" << proj[mtex->projx] << "\" />\n";
+ ostr << "\t\t<proj_y value=\"" << proj[mtex->projy] << "\" />\n";
+ ostr << "\t\t<proj_z value=\"" << proj[mtex->projz] << "\" />\n";
+
+ // texture mapping parameters only relevant to image type
+ if (tex->type==TEX_IMAGE) {
+ if (mtex->mapping==MTEX_FLAT)
+ ostr << "\t\t<mapping value=\"flat\" />\n";
+ else if (mtex->mapping==MTEX_CUBE)
+ ostr << "\t\t<mapping value=\"cube\" />\n";
+ else if (mtex->mapping==MTEX_TUBE)
+ ostr << "\t\t<mapping value=\"tube\" />\n";
+ else if (mtex->mapping==MTEX_SPHERE)
+ ostr << "\t\t<mapping value=\"sphere\" />\n";
+
+ // repeat
+ ostr << "\t\t<xrepeat value=\"" << tex->xrepeat << "\" />\n";
+ ostr << "\t\t<yrepeat value=\"" << tex->yrepeat << "\" />\n";
+
+ // clipping
+ if (tex->extend==TEX_EXTEND)
+ ostr << "\t\t<clipping value=\"extend\" />\n";
+ else if (tex->extend==TEX_CLIP)
+ ostr << "\t\t<clipping value=\"clip\" />\n";
+ else if (tex->extend==TEX_CLIPCUBE)
+ ostr << "\t\t<clipping value=\"clipcube\" />\n";
+ else if (tex->extend==TEX_CHECKER) {
+ ostr << "\t\t<clipping value=\"checker\" />\n";
+ string ts = "";
+ if (tex->flag & TEX_CHECKER_ODD) ts += "odd";
+ if (tex->flag & TEX_CHECKER_EVEN) ts += " even";
+ ostr << "\t\t<checker_mode value=\"" << ts << "\" />\n";
+ ostr << "\t\t<checker_dist value=\"" << tex->checkerdist << "\" />\n";
+ }
+ else
+ ostr << "\t\t<clipping value=\"repeat\" />\n";
+
+ // crop min/max
+ ostr << "\t\t<cropmin_x value=\"" << tex->cropxmin << "\" />\n";
+ ostr << "\t\t<cropmin_y value=\"" << tex->cropymin << "\" />\n";
+ ostr << "\t\t<cropmax_x value=\"" << tex->cropxmax << "\" />\n";
+ ostr << "\t\t<cropmax_y value=\"" << tex->cropymax << "\" />\n";
+
+ // rot90 flag
+ string ts = "off";
+ if (tex->imaflag & TEX_IMAROT) ts = "on";
+ ostr << "\t\t<rot90 value=\"" << ts << "\" />\n";
+ }
+
+ ostr << "\t</attributes>\n";
+ ostr << "</shader>\n\n";
+
+ xmlfile << ostr.str();
+ }
+ }
+
+ // shader + modulators
+ writeShader(blendmat->first, matr);
+
+ }
+
+ // write the mappers & shaders for the TexFace case
+ if (!imagetex.empty()) {
+ // Yafray doesn't have per-face-textures, only per-face-shaders,
+ // so create as many mappers/shaders as the images used by the object
+ int snum = 0;
+ for (map<Image*, set<Material*> >::const_iterator imgtex=imagetex.begin();
+ imgtex!=imagetex.end();++imgtex)
+ {
+
+ for (set<Material*>::const_iterator imgmat=imgtex->second.begin();
+ imgmat!=imgtex->second.end();++imgmat)
+ {
+ Material* matr = *imgmat;
+ // mapper
+ ostr.str("");
+ ostr << "<shader type=\"blendermapper\" name=\"" << string(matr->id.name) + "_ftmap" << snum << "\" >\n";
+ ostr << "\t<attributes>\n";
+ ostr << "\t\t<input value=\"" << imgtex->first->id.name << "\" />\n";
+ // all yafray default settings, except for texco, so no need to set others
+ ostr << "\t\t<texco value=\"uv\" />\n";
+ ostr << "\t</attributes>\n";
+ ostr << "</shader>\n\n";
+ xmlfile << ostr.str();
+
+ // shader, remember name, used later when writing per-face-shaders
+ ostr.str("");
+ ostr << matr->id.name << "_ftsha" << snum;
+ string shader_name = ostr.str();
+ imgtex_shader[string(matr->id.name) + string(imgtex->first->id.name)] = shader_name;
+
+ ostr.str("");
+ ostr << matr->id.name << "_ftmap" << snum++;
+ writeShader(shader_name, matr, ostr.str());
+ }
+
+ }
+ }
+
+}
+
+
+void yafrayFileRender_t::writeObject(Object* obj, const vector<VlakRen*> &VLR_list, const float obmat[4][4])
+{
+ ostr.str("");
+ // transform first (not necessarily actual obj->obmat, can be duplivert see below)
+ ostr << "<transform m00=\"" << obmat[0][0] << "\" m01=\"" << obmat[1][0]
+ << "\" m02=\"" << obmat[2][0] << "\" m03=\"" << obmat[3][0] << "\"\n";
+ ostr << " m10=\"" << obmat[0][1] << "\" m11=\"" << obmat[1][1]
+ << "\" m12=\"" << obmat[2][1] << "\" m13=\"" << obmat[3][1] << "\"\n";
+ ostr << " m20=\"" << obmat[0][2] << "\" m21=\"" << obmat[1][2]
+ << "\" m22=\"" << obmat[2][2] << "\" m23=\"" << obmat[3][2] << "\"\n";
+ ostr << " m30=\"" << obmat[0][3] << "\" m31=\"" << obmat[1][3]
+ << "\" m32=\"" << obmat[2][3] << "\" m33=\"" << obmat[3][3] << "\">\n";
+ xmlfile << ostr.str();
+
+ ostr.str("");
+
+ // using the ObjectRen database, contruct a new name if object has a parent.
+ // This is done to prevent name clashes (group/library link related)
+ string obname(obj->id.name);
+ // previous implementation, keep around, in case this is still useful
+ //if (obj->id.flag & (LIB_EXTERN|LIB_INDIRECT))obname = "lib_" + obname;
+ ObjectRen *obren;
+ for (obren = static_cast<ObjectRen*>(re->objecttable.first);
+ obren; obren=static_cast<ObjectRen*>(obren->next))
+ {
+ Object *db_ob = obren->ob, *db_par = obren->par;
+ if (db_ob==obj)
+ if ((db_ob!=NULL) && (db_par!=NULL)) {
+ obname += "_" + string(db_par->id.name);
+ break;
+ }
+ }
+
+ ostr << "<object name=\"" << obname << "\"";
+ // Yafray still needs default shader name in object def.,
+ // since we write a shader with every face, simply use the material of the first face.
+ // If this is an empty string, assume default material.
+ VlakRen* face0 = VLR_list[0];
+ Material* face0mat = face0->mat;
+ string matname(face0mat->id.name);
+ // use name in imgtex_shader list if 'TexFace' enabled for this material
+ if (face0mat->mode & MA_FACETEXTURE) {
+ MTFace* tface = RE_vlakren_get_tface(re, face0, 0, NULL, 0);
+ if (tface) {
+ Image* fimg = (Image*)tface->tpage;
+ if (fimg) matname = imgtex_shader[string(face0mat->id.name) + string(fimg->id.name)];
+ }
+ }
+ bool shadow = face0mat->mode & MA_TRACEBLE;
+ ostr <<" shadow=\""<< (shadow ? "on" : "off" ) << "\" ";
+ bool caus = (((face0mat->mode & MA_RAYTRANSP) | (face0->mat->mode & MA_RAYMIRROR))!=0);
+ if (caus) ostr << "caus_IOR=\"" << face0mat->ang << "\"";
+ if (matname.length()==0) matname = "blender_default";
+ ostr << " shader_name=\"" << matname << "\" >\n";
+ ostr << "\t<attributes>\n";
+ if (caus)
+ {
+ float tr = 1.0-face0mat->alpha;
+ ostr << "\t\t<caus_tcolor r=\"" << face0mat->r*tr
+ << "\" g=\"" << face0mat->g*tr
+ << "\" b=\"" << face0mat->b*tr << "\" />\n";
+ tr = face0mat->ray_mirror;
+ ostr << "\t\t<caus_rcolor r=\"" << face0mat->mirr*tr
+ << "\" g=\"" << face0mat->mirg*tr
+ << "\" b=\"" << face0mat->mirb*tr << "\" />\n";
+ }
+ ostr << "\t</attributes>\n";
+ xmlfile << ostr.str();
+
+ // Export orco coords test.
+ // Previously was done by checking orco pointer, however this can be non-null but still not initialized.
+ // Test the rendermaterial texco flag instead.
+ // update2: bug #3193 it seems it has changed again with the introduction of static 'hair' particles,
+ // now it uses the vert pointer again as an extra test to make sure there are orco coords available
+ int has_orco = 0;
+ if (face0mat->texco & TEXCO_STRAND)
+ has_orco = 1;
+ else
+ has_orco = (((face0mat->texco & TEXCO_ORCO)!=0) && (face0->v1->orco!=NULL)) ? 2 : 0;
+
+ string has_orco_st = has_orco ? "on" : "off";
+
+ // smooth shading if enabled
+ bool no_auto = true; //in case non-mesh, or mesh has no autosmooth
+ if (obj->type==OB_MESH) {
+ Mesh* mesh = (Mesh*)obj->data;
+ if (mesh->flag & ME_AUTOSMOOTH) {
+ no_auto = false;
+ ostr.str("");
+ ostr << "\t<mesh autosmooth=\"" << mesh->smoothresh << "\" has_orco=\"" << has_orco_st << "\" >\n";
+ xmlfile << ostr.str();
+ }
+ }
+ // this for non-mesh as well
+ if (no_auto) {
+ // If AutoSmooth not used, since yafray currently cannot specify if a face is smooth
+ // or flat shaded, the smooth flag of the first face is used to determine
+ // the shading for the whole mesh
+ if (face0->flag & ME_SMOOTH)
+ xmlfile << "\t<mesh autosmooth=\"180\" has_orco=\"" << has_orco_st << "\" >\n";
+ else
+ xmlfile << "\t<mesh autosmooth=\"0.1\" has_orco=\"" << has_orco_st << "\" >\n"; //0 shows artefacts
+ }
+
+ // now all vertices
+ map<VertRen*, int> vert_idx; // for removing duplicate verts and creating an index list
+ int vidx = 0; // vertex index counter
+
+ // vertices, transformed back to world
+ xmlfile << "\t\t<points>\n";
+
+ // for deformed objects, object->imat is no longer valid,
+ // so have to create inverse render matrix ourselves here
+ float mat[4][4], imat[4][4];
+ MTC_Mat4MulMat4(mat, obj->obmat, re->viewmat);
+ MTC_Mat4Invert(imat, mat);
+
+ for (vector<VlakRen*>::const_iterator fci=VLR_list.begin();
+ fci!=VLR_list.end();++fci)
+ {
+ VlakRen* vlr = *fci;
+ VertRen* ver;
+ float* orco;
+ float tvec[3];
+ ostr.str("");
+ if (vert_idx.find(vlr->v1)==vert_idx.end()) {
+ vert_idx[vlr->v1] = vidx++;
+ ver = vlr->v1;
+ MTC_cp3Float(ver->co, tvec);
+ MTC_Mat4MulVecfl(imat, tvec);
+ ostr << "\t\t\t<p x=\"" << tvec[0]
+ << "\" y=\"" << tvec[1]
+ << "\" z=\"" << tvec[2] << "\" />\n";
+ // has_orco now an int, if 1 -> strand mapping, if 2 -> normal orco mapping
+ if (has_orco==1) {
+ ostr << "\t\t\t<p x=\"" << ver->accum
+ << "\" y=\"" << ver->accum
+ << "\" z=\"" << ver->accum << "\" />\n";
+ }
+ else if (has_orco==2) {
+ orco = ver->orco;
+ ostr << "\t\t\t<p x=\"" << orco[0]
+ << "\" y=\"" << orco[1]
+ << "\" z=\"" << orco[2] << "\" />\n";
+ }
+ }
+ if (vert_idx.find(vlr->v2)==vert_idx.end()) {
+ vert_idx[vlr->v2] = vidx++;
+ ver = vlr->v2;
+ MTC_cp3Float(ver->co, tvec);
+ MTC_Mat4MulVecfl(imat, tvec);
+ ostr << "\t\t\t<p x=\"" << tvec[0]
+ << "\" y=\"" << tvec[1]
+ << "\" z=\"" << tvec[2] << "\" />\n";
+ // has_orco now an int, if 1 -> strand mapping, if 2 -> normal orco mapping
+ if (has_orco==1) {
+ ostr << "\t\t\t<p x=\"" << ver->accum
+ << "\" y=\"" << ver->accum
+ << "\" z=\"" << ver->accum << "\" />\n";
+ }
+ else if (has_orco==2) {
+ orco = ver->orco;
+ ostr << "\t\t\t<p x=\"" << orco[0]
+ << "\" y=\"" << orco[1]
+ << "\" z=\"" << orco[2] << "\" />\n";
+ }
+ }
+ if (vert_idx.find(vlr->v3)==vert_idx.end()) {
+ vert_idx[vlr->v3] = vidx++;
+ ver = vlr->v3;
+ MTC_cp3Float(ver->co, tvec);
+ MTC_Mat4MulVecfl(imat, tvec);
+ ostr << "\t\t\t<p x=\"" << tvec[0]
+ << "\" y=\"" << tvec[1]
+ << "\" z=\"" << tvec[2] << "\" />\n";
+ // has_orco now an int, if 1 -> strand mapping, if 2 -> normal orco mapping
+ if (has_orco==1) {
+ ostr << "\t\t\t<p x=\"" << ver->accum
+ << "\" y=\"" << ver->accum
+ << "\" z=\"" << ver->accum << "\" />\n";
+ }
+ else if (has_orco==2) {
+ orco = ver->orco;
+ ostr << "\t\t\t<p x=\"" << orco[0]
+ << "\" y=\"" << orco[1]
+ << "\" z=\"" << orco[2] << "\" />\n";
+ }
+ }
+ if ((vlr->v4) && (vert_idx.find(vlr->v4)==vert_idx.end())) {
+ vert_idx[vlr->v4] = vidx++;
+ ver = vlr->v4;
+ MTC_cp3Float(ver->co, tvec);
+ MTC_Mat4MulVecfl(imat, tvec);
+ ostr << "\t\t\t<p x=\"" << tvec[0]
+ << "\" y=\"" << tvec[1]
+ << "\" z=\"" << tvec[2] << "\" />\n";
+ // has_orco now an int, if 1 -> strand mapping, if 2 -> normal orco mapping
+ if (has_orco==1) {
+ ostr << "\t\t\t<p x=\"" << ver->accum
+ << "\" y=\"" << ver->accum
+ << "\" z=\"" << ver->accum << "\" />\n";
+ }
+ else if (has_orco==2) {
+ orco = ver->orco;
+ ostr << "\t\t\t<p x=\"" << orco[0]
+ << "\" y=\"" << orco[1]
+ << "\" z=\"" << orco[2] << "\" />\n";
+ }
+ }
+ xmlfile << ostr.str();
+ }
+ xmlfile << "\t\t</points>\n";
+
+ // all faces using the index list created above
+ xmlfile << "\t\t<faces>\n";
+ for (vector<VlakRen*>::const_iterator fci2=VLR_list.begin();
+ fci2!=VLR_list.end();++fci2)
+ {
+ VlakRen* vlr = *fci2;
+ Material* fmat = vlr->mat;
+ bool EXPORT_VCOL = ((fmat->mode & (MA_VERTEXCOL|MA_VERTEXCOLP))!=0);
+ string fmatname(fmat->id.name);
+ // use name in imgtex_shader list if 'TexFace' enabled for this face material
+ if (fmat->mode & MA_FACETEXTURE) {
+ MTFace* tface = RE_vlakren_get_tface(re, vlr, 0, NULL, 0);
+ if (tface) {
+ Image* fimg = (Image*)tface->tpage;
+ if (fimg) fmatname = imgtex_shader[fmatname + string(fimg->id.name)];
+ }
+ }
+ else if (fmatname.length()==0) fmatname = "blender_default";
+
+ int idx1 = vert_idx.find(vlr->v1)->second;
+ int idx2 = vert_idx.find(vlr->v2)->second;
+ int idx3 = vert_idx.find(vlr->v3)->second;
+ // make sure the indices point to the vertices when orco coords exported
+ if (has_orco) { idx1*=2; idx2*=2; idx3*=2; }
+
+ ostr.str("");
+ ostr << "\t\t\t<f a=\"" << idx1 << "\" b=\"" << idx2 << "\" c=\"" << idx3 << "\"";
+
+ // triangle uv and vcol indices
+ int ui1=0, ui2=1, ui3=2;
+ if (vlr->flag & R_DIVIDE_24) {
+ ui3++;
+ if (vlr->flag & R_FACE_SPLIT) { ui1++; ui2++; }
+ }
+ else if (vlr->flag & R_FACE_SPLIT) { ui2++; ui3++; }
+
+ MTFace* uvc = RE_vlakren_get_tface(re, vlr, 0, NULL, 0); // possible uvcoords (v upside down)
+ if (uvc) {
+ ostr << " u_a=\"" << uvc->uv[ui1][0] << "\" v_a=\"" << 1-uvc->uv[ui1][1] << "\""
+ << " u_b=\"" << uvc->uv[ui2][0] << "\" v_b=\"" << 1-uvc->uv[ui2][1] << "\""
+ << " u_c=\"" << uvc->uv[ui3][0] << "\" v_c=\"" << 1-uvc->uv[ui3][1] << "\"";
+ }
+
+ MCol *mcol= RE_vlakren_get_mcol(re, vlr, 0, NULL, 0);
+
+ // since Blender seems to need vcols when uvs are used, for yafray only export when the material actually uses vcols
+ if ((EXPORT_VCOL) && mcol) {
+ // vertex colors
+ unsigned char* pt = reinterpret_cast<unsigned char*>(&mcol[ui1]);
+ ostr << " vcol_a_r=\"" << (float)pt[3]/255.f << "\" vcol_a_g=\"" << (float)pt[2]/255.f
+ << "\" vcol_a_b=\"" << (float)pt[1]/255.f << "\"";
+ pt = reinterpret_cast<unsigned char*>(&mcol[ui2]);
+ ostr << " vcol_b_r=\"" << (float)pt[3]/255.f << "\" vcol_b_g=\"" << (float)pt[2]/255.f
+ << "\" vcol_b_b=\"" << (float)pt[1]/255.f << "\"";
+ pt = reinterpret_cast<unsigned char*>(&mcol[ui3]);
+ ostr << " vcol_c_r=\"" << (float)pt[3]/255.f << "\" vcol_c_g=\"" << (float)pt[2]/255.f
+ << "\" vcol_c_b=\"" << (float)pt[1]/255.f << "\"";
+ }
+ ostr << " shader_name=\"" << fmatname << "\" />\n";
+
+ if (vlr->v4) {
+
+ idx1 = vert_idx.find(vlr->v3)->second;
+ idx2 = vert_idx.find(vlr->v4)->second;
+ idx3 = vert_idx.find(vlr->v1)->second;
+
+ // make sure the indices point to the vertices when orco coords exported
+ if (has_orco) { idx1*=2; idx2*=2; idx3*=2; }
+
+ ostr << "\t\t\t<f a=\"" << idx1 << "\" b=\"" << idx2 << "\" c=\"" << idx3 << "\"";
+
+ // increment uv & vcol indices
+ ui1 = (ui1+2) & 3;
+ ui2 = (ui2+2) & 3;
+ ui3 = (ui3+2) & 3;
+
+ if (uvc) {
+ ostr << " u_a=\"" << uvc->uv[ui1][0] << "\" v_a=\"" << 1-uvc->uv[ui1][1] << "\""
+ << " u_b=\"" << uvc->uv[ui2][0] << "\" v_b=\"" << 1-uvc->uv[ui2][1] << "\""
+ << " u_c=\"" << uvc->uv[ui3][0] << "\" v_c=\"" << 1-uvc->uv[ui3][1] << "\"";
+ }
+ if ((EXPORT_VCOL) && mcol) {
+ // vertex colors
+ unsigned char* pt = reinterpret_cast<unsigned char*>(&mcol[ui1]);
+ ostr << " vcol_a_r=\"" << (float)pt[3]/255.f << "\" vcol_a_g=\"" << (float)pt[2]/255.f
+ << "\" vcol_a_b=\"" << (float)pt[1]/255.f << "\"";
+ pt = reinterpret_cast<unsigned char*>(&mcol[ui2]);
+ ostr << " vcol_b_r=\"" << (float)pt[3]/255.f << "\" vcol_b_g=\"" << (float)pt[2]/255.f
+ << "\" vcol_b_b=\"" << (float)pt[1]/255.f << "\"";
+ pt = reinterpret_cast<unsigned char*>(&mcol[ui3]);
+ ostr << " vcol_c_r=\"" << (float)pt[3]/255.f << "\" vcol_c_g=\"" << (float)pt[2]/255.f
+ << "\" vcol_c_b=\"" << (float)pt[1]/255.f << "\"";
+ }
+ ostr << " shader_name=\"" << fmatname << "\" />\n";
+
+ }
+ xmlfile << ostr.str();
+ }
+ xmlfile << "\t\t</faces>\n\t</mesh>\n</object>\n</transform>\n\n";
+}
+
+
+// write all objects
+void yafrayFileRender_t::writeAllObjects()
+{
+
+ // first all objects except dupliverts (and main instance object for dups)
+ for (map<Object*, vector<VlakRen*> >::const_iterator obi=all_objects.begin();
+ obi!=all_objects.end(); ++obi)
+ {
+ // skip main duplivert object if in dupliMtx_list, written later
+ Object* obj = obi->first;
+ if (dupliMtx_list.find(string(obj->id.name))!=dupliMtx_list.end()) continue;
+ writeObject(obj, obi->second, obj->obmat);
+ }
+
+ // Now all duplivert objects (if any) as instances of main object
+ // The original object has been included in the VlakRen renderlist above (see convertBlenderScene.c)
+ // but is written here which all other duplis are instances of.
+ float obmat[4][4], cmat[4][4], imat[4][4], nmat[4][4];
+ for (map<string, vector<float> >::const_iterator dupMtx=dupliMtx_list.begin();
+ dupMtx!=dupliMtx_list.end();++dupMtx) {
+
+ // original inverse matrix, not actual matrix of object, but first duplivert.
+
+ for (int i=0;i<4;i++)
+ for (int j=0;j<4;j++)
+ obmat[i][j] = dupMtx->second[(i<<2)+j];
+
+ MTC_Mat4Invert(imat, obmat);
+
+ // first object written as normal (but with transform of first duplivert)
+ Object* obj = dup_srcob[dupMtx->first];
+ writeObject(obj, all_objects[obj], obmat);
+
+ // all others instances of first
+ for (unsigned int curmtx=16;curmtx<dupMtx->second.size();curmtx+=16) { // number of 4x4 matrices
+
+ // new mtx
+ for (int i=0;i<4;i++)
+ for (int j=0;j<4;j++)
+ nmat[i][j] = dupMtx->second[curmtx+(i<<2)+j];
+
+ MTC_Mat4MulMat4(cmat, imat, nmat); // transform with respect to original = inverse_original * new
+
+ ostr.str("");
+ // yafray matrix = transpose of Blender
+ ostr << "<transform m00=\"" << cmat[0][0] << "\" m01=\"" << cmat[1][0]
+ << "\" m02=\"" << cmat[2][0] << "\" m03=\"" << cmat[3][0] << "\"\n";
+ ostr << " m10=\"" << cmat[0][1] << "\" m11=\"" << cmat[1][1]
+ << "\" m12=\"" << cmat[2][1] << "\" m13=\"" << cmat[3][1] << "\"\n";
+ ostr << " m20=\"" << cmat[0][2] << "\" m21=\"" << cmat[1][2]
+ << "\" m22=\"" << cmat[2][2] << "\" m23=\"" << cmat[3][2] << "\"\n";
+ ostr << " m30=\"" << cmat[0][3] << "\" m31=\"" << cmat[1][3]
+ << "\" m32=\"" << cmat[2][3] << "\" m33=\"" << cmat[3][3] << "\">\n";
+ xmlfile << ostr.str();
+
+ // new name from original
+ ostr.str("");
+ ostr << "<object name=\"" << obj->id.name << "_dup" << (curmtx>>4) << "\" original=\"" << obj->id.name << "\" >\n";
+ xmlfile << ostr.str();
+ xmlfile << "\t<attributes>\n\t</attributes>\n\t<null/>\n</object>\n</transform>\n\n";
+
+ }
+
+ }
+
+}
+
+void yafrayFileRender_t::writeAreaLamp(LampRen* lamp, int num, float iview[4][4])
+{
+ if (lamp->area_shape!=LA_AREA_SQUARE) return;
+ float *a=lamp->area[0], *b=lamp->area[1], *c=lamp->area[2], *d=lamp->area[3];
+ float power=lamp->energy;
+
+ ostr.str("");
+ string md = "off";
+ // if no GI used, the GIphotons flag can still be set, so only use when 'full' selected
+ if ((re->r.GImethod==2) && (re->r.GIphotons)) { md="on"; power*=re->r.GIpower; }
+ ostr << "<light type=\"arealight\" name=\"LAMP" << num+1 << "\" dummy=\""<< md << "\" power=\"" << power << "\" ";
+ // samples not used for GI with photons, can still be exported, is ignored
+ int psm=0, sm = lamp->ray_totsamp;
+ if (sm>=25) psm = sm/5;
+ ostr << "samples=\"" << sm << "\" psamples=\"" << psm << "\" ";
+ ostr << ">\n";
+
+ // transform area lamp coords back to world
+ float lpco[4][3];
+ MTC_cp3Float(a, lpco[0]);
+ MTC_Mat4MulVecfl(iview, lpco[0]);
+ MTC_cp3Float(b, lpco[1]);
+ MTC_Mat4MulVecfl(iview, lpco[1]);
+ MTC_cp3Float(c, lpco[2]);
+ MTC_Mat4MulVecfl(iview, lpco[2]);
+ MTC_cp3Float(d, lpco[3]);
+ MTC_Mat4MulVecfl(iview, lpco[3]);
+ ostr << "\t<a x=\""<< lpco[0][0] <<"\" y=\""<< lpco[0][1] <<"\" z=\"" << lpco[0][2] <<"\" />\n";
+ ostr << "\t<b x=\""<< lpco[1][0] <<"\" y=\""<< lpco[1][1] <<"\" z=\"" << lpco[1][2] <<"\" />\n";
+ ostr << "\t<c x=\""<< lpco[2][0] <<"\" y=\""<< lpco[2][1] <<"\" z=\"" << lpco[2][2] <<"\" />\n";
+ ostr << "\t<d x=\""<< lpco[3][0] <<"\" y=\""<< lpco[3][1] <<"\" z=\"" << lpco[3][2] <<"\" />\n";
+
+ ostr << "\t<color r=\"" << lamp->r << "\" g=\"" << lamp->g << "\" b=\"" << lamp->b << "\" />\n";
+ ostr << "</light>\n\n";
+ xmlfile << ostr.str();
+}
+
+void yafrayFileRender_t::writeLamps()
+{
+ GroupObject *go;
+ int i=0;
+
+ // inverse viewmatrix needed for back2world transform
+ float iview[4][4];
+ // re->viewinv != inv.re->viewmat because of possible ortho mode (see convertBlenderScene.c)
+ // have to invert it here
+ MTC_Mat4Invert(iview, re->viewmat);
+
+ // all lamps
+ for(go=(GroupObject *)re->lights.first; go; go= go->next, i++) {
+ LampRen* lamp = (LampRen *)go->lampren;
+
+ ostr.str("");
+
+ if (lamp->type==LA_AREA) { writeAreaLamp(lamp, i, iview); continue; }
+
+ // TODO: add decay setting in yafray
+ ostr << "<light type=\"";
+ bool is_softL=false, is_sphereL=false;
+ if (lamp->type==LA_LOCAL) {
+ if (lamp->mode & LA_YF_SOFT) {
+ // shadowmapped omnidirectional light
+ ostr << "softlight\"";
+ is_softL = true;
+ }
+ else if ((lamp->mode & LA_SHAD_RAY) && (lamp->YF_ltradius>0.0)) {
+ // area sphere, only when ray shadows enabled and radius>0.0
+ ostr << "spherelight\"";
+ is_sphereL = true;
+ }
+ else ostr << "pointlight\"";
+ ostr << " glow_intensity=\"" << lamp->YF_glowint << "\" glow_offset=\"" << lamp->YF_glowofs
+ << "\" glow_type=\"" << lamp->YF_glowtype << "\"";
+ }
+ else if (lamp->type==LA_SPOT)
+ ostr << "spotlight\"";
+ else if ((lamp->type==LA_SUN) || (lamp->type==LA_HEMI)) // hemi exported as sun
+ ostr << "sunlight\"";
+ else if (lamp->type==LA_YF_PHOTON)
+ ostr << "photonlight\"";
+ else {
+ // possibly unknown type, ignore
+ cout << "Unknown Blender lamp type: " << lamp->type << endl;
+ continue;
+ }
+
+ //no name available here, create one
+ ostr << " name=\"LAMP" << i+1;
+ // color already premultiplied by energy, so only need distance here
+ float pwr = 1; // default for sun/hemi, distance irrelevant
+ if ((lamp->type!=LA_SUN) && (lamp->type!=LA_HEMI)) {
+ if (lamp->mode & LA_SPHERE) {
+ // best approx. as used in LFexport script (LF d.f.m. 4pi?)
+ pwr = lamp->dist*(lamp->dist+1)*(0.25/M_PI);
+ //decay = 2;
+ }
+ else {
+ pwr = lamp->dist;
+ //decay = 1;
+ }
+ }
+
+ if (is_sphereL) {
+ // 'dummy' mode for spherelight when used with gpm
+ string md = "off";
+ // if no GI used, the GIphotons flag can still be set, so only use when 'full' selected
+ if ((re->r.GImethod==2) && (re->r.GIphotons)) { md="on"; pwr*=re->r.GIpower; }
+ ostr << "\" power=\"" << pwr << "\" dummy=\"" << md << "\"";
+ }
+ else ostr << "\" power=\"" << pwr << "\"";
+
+ // cast_shadows flag not used with softlight, spherelight or photonlight
+ if ((!is_softL) && (!is_sphereL) && (lamp->type!=LA_YF_PHOTON)) {
+ string lpmode="off";
+ // Blender hemilights exported as sunlights which might have shadow flag set
+ // should have cast_shadows set to off (reported by varuag)
+ if (lamp->type!=LA_HEMI) {
+ if (re->r.mode & R_SHADOW) {
+ // old bug was here since the yafray lamp settings panel was added,
+ // blender spotlight shadbuf flag should be ignored, since it is not in the panel anymore
+ if (lamp->mode & LA_SHAD_RAY) lpmode="on";
+ }
+ }
+ ostr << " cast_shadows=\"" << lpmode << "\"";
+ }
+
+
+ // spot specific stuff
+ bool has_halo = ((lamp->type==LA_SPOT) && (lamp->mode & LA_HALO) && (lamp->haint>0.0));
+ if (lamp->type==LA_SPOT) {
+ // conversion already changed spotsize to cosine of half angle
+ float ld = 1-lamp->spotsi; //convert back to blender slider setting
+ if (ld!=0) ld = 1.f/ld;
+ ostr << " size=\"" << acos(lamp->spotsi)*180.0/M_PI << "\""
+ << " blend=\"" << lamp->spotbl*ld << "\""
+ << " beam_falloff=\"2\""; // no Blender equivalent (yet)
+ // halo params
+ if (has_halo) {
+ ostr << "\n\thalo=\"on\" " << "res=\"" << lamp->YF_bufsize << "\"\n";
+ int hsmp = ((12-lamp->shadhalostep)*16)/12;
+ hsmp = (hsmp+1)*16; // makes range (16, 272) for halostep(12, 0), good enough?
+ // halo 'samples' now 'stepsize'
+ // convert from old integer samples value to some reasonable stepsize
+ ostr << "\tstepsize=\"" << (1.0/sqrt((float)hsmp)) << "\" shadow_samples=\"" << (lamp->samp*lamp->samp) << "\"\n";
+ ostr << "\thalo_blur=\"0\" shadow_blur=\"" << (lamp->soft*0.01f) << "\"\n";
+ ostr << "\tfog_density=\"" << (lamp->haint*0.2f) << "\"";
+ }
+ }
+ else if (is_softL) {
+ // softlight
+ ostr << " res=\"" << lamp->YF_bufsize << "\""
+ << " radius=\"" << lamp->soft << "\""
+ << " bias=\"" << lamp->bias << "\"";
+ }
+ else if (is_sphereL) {
+ // spherelight
+ int psm=0, sm = lamp->ray_samp*lamp->ray_samp;
+ if (sm>=25) psm = sm/5;
+ ostr << " radius=\"" << lamp->YF_ltradius << "\""
+ << " samples=\"" << sm << "\""
+ << " psamples=\"" << psm << "\""
+ << " qmc_method=\"1\"";
+ }
+ else if (lamp->type==LA_YF_PHOTON) {
+ string qmc="off";
+ if (lamp->YF_useqmc) qmc="on";
+ ostr << "\n\tphotons=\"" << lamp->YF_numphotons << "\""
+ << " search=\"" << lamp->YF_numsearch << "\""
+ << " depth=\"" << lamp->YF_phdepth << "\""
+ << " use_QMC=\"" << qmc << "\""
+ << " angle=\"" << acos(lamp->spotsi)*180.0/M_PI << "\"";
+ float cl = lamp->YF_causticblur/sqrt((float)lamp->YF_numsearch);
+ ostr << "\n\tfixedradius=\"" << lamp->YF_causticblur << "\" cluster=\"" << cl << "\"";
+ }
+ ostr << " >\n";
+
+ // transform lamp co & vec back to world
+ float lpco[3], lpvec[3];
+ MTC_cp3Float(lamp->co, lpco);
+ MTC_Mat4MulVecfl(iview, lpco);
+ MTC_cp3Float(lamp->vec, lpvec);
+ MTC_Mat4Mul3Vecfl(iview, lpvec);
+
+ // position, (==-blendir for sun/hemi)
+ if ((lamp->type==LA_SUN) || (lamp->type==LA_HEMI))
+ ostr << "\t<from x=\"" << -lpvec[0] << "\" y=\"" << -lpvec[1] << "\" z=\"" << -lpvec[2] << "\" />\n";
+ else
+ ostr << "\t<from x=\"" << lpco[0] << "\" y=\"" << lpco[1] << "\" z=\"" << lpco[2] << "\" />\n";
+ // 'to' for spot/photonlight, already calculated by Blender
+ if ((lamp->type==LA_SPOT) || (lamp->type==LA_YF_PHOTON)) {
+ ostr << "\t<to x=\"" << lpco[0] + lpvec[0]
+ << "\" y=\"" << lpco[1] + lpvec[1]
+ << "\" z=\"" << lpco[2] + lpvec[2] << "\" />\n";
+ if (has_halo) ostr << "\t<fog r=\"1\" g=\"1\" b=\"1\" />\n";
+ }
+
+ // color
+ // rgb in LampRen is premultiplied by energy, power is compensated for that above
+ ostr << "\t<color r=\"" << lamp->r << "\" g=\"" << lamp->g << "\" b=\"" << lamp->b << "\" />\n";
+ ostr << "</light>\n\n";
+ xmlfile << ostr.str();
+ }
+}
+
+// write main camera
+void yafrayFileRender_t::writeCamera()
+{
+ // here Global used again
+ ostr.str("");
+ ostr << "<camera name=\"MAINCAM\" ";
+ if (re->r.mode & R_ORTHO)
+ ostr << "type=\"ortho\"";
+ else
+ ostr << "type=\"perspective\"";
+
+ // render resolution including the percentage buttons
+ ostr << " resx=\"" << re->winx << "\" resy=\"" << re->winy << "\"";
+
+ float f_aspect = 1;
+ if ((re->winx * re->r.xasp) <= (re->winy * re->r.yasp))
+ f_aspect = float(re->winx * re->r.xasp) / float(re->winy * re->r.yasp);
+ ostr << "\n\tfocal=\"" << mainCamLens/(f_aspect*32.f);
+ // bug #4532, when field rendering is enabled, ycor is doubled
+ if (re->r.mode & R_FIELDS)
+ ostr << "\" aspect_ratio=\"" << (re->ycor * 0.5f) << "\"";
+ else
+ ostr << "\" aspect_ratio=\"" << re->ycor << "\"";
+
+
+ // dof params, only valid for real camera
+ float fdist = 1; // only changes for ortho
+ if (maincam_obj->type==OB_CAMERA) {
+ Camera* cam = (Camera*)maincam_obj->data;
+ if (re->r.mode & R_ORTHO) fdist = cam->ortho_scale*(mainCamLens/32.f);
+ ostr << "\n\tdof_distance=\"" << cam->YF_dofdist << "\"";
+ ostr << " aperture=\"" << cam->YF_aperture << "\"";
+ string st = "on";
+ if (cam->flag & CAM_YF_NO_QMC) st = "off";
+ ostr << " use_qmc=\"" << st << "\"";
+ // bokeh params
+ st = "disk1";
+ if (cam->YF_bkhtype==1)
+ st = "disk2";
+ else if (cam->YF_bkhtype==2)
+ st = "triangle";
+ else if (cam->YF_bkhtype==3)
+ st = "square";
+ else if (cam->YF_bkhtype==4)
+ st = "pentagon";
+ else if (cam->YF_bkhtype==5)
+ st = "hexagon";
+ else if (cam->YF_bkhtype==6)
+ st = "ring";
+ ostr << "\n\tbokeh_type=\"" << st << "\"";
+ st = "uniform";
+ if (cam->YF_bkhbias==1)
+ st = "center";
+ else if (cam->YF_bkhbias==2)
+ st = "edge";
+ ostr << " bokeh_bias=\"" << st << "\"";
+ ostr << " bokeh_rotation=\"" << cam->YF_bkhrot << "\"";
+ }
+
+ ostr << " >\n";
+ xmlfile << ostr.str();
+
+ ostr.str("");
+ ostr << "\t<from x=\"" << maincam_obj->obmat[3][0] << "\""
+ << " y=\"" << maincam_obj->obmat[3][1] << "\""
+ << " z=\"" << maincam_obj->obmat[3][2] << "\" />\n";
+ ostr << "\t<to x=\"" << maincam_obj->obmat[3][0] - fdist * re->viewmat[0][2]
+ << "\" y=\"" << maincam_obj->obmat[3][1] - fdist * re->viewmat[1][2]
+ << "\" z=\"" << maincam_obj->obmat[3][2] - fdist * re->viewmat[2][2] << "\" />\n";
+ ostr << "\t<up x=\"" << maincam_obj->obmat[3][0] + re->viewmat[0][1]
+ << "\" y=\"" << maincam_obj->obmat[3][1] + re->viewmat[1][1]
+ << "\" z=\"" << maincam_obj->obmat[3][2] + re->viewmat[2][1] << "\" />\n";
+ xmlfile << ostr.str();
+
+ xmlfile << "</camera>\n\n";
+}
+
+void yafrayFileRender_t::writeHemilight()
+{
+ World *world = G.scene->world;
+ bool fromAO = false;
+ if (re->r.GIquality==6){
+ // use Blender AO params is possible
+ if (world==NULL) return;
+ if ((world->mode & WO_AMB_OCC)==0) {
+ // no AO, use default GIquality
+ cout << "No ambient occlusion enabled\nUsing defaults of 25 samples & infinite distance instead" << endl;
+ }
+ else fromAO = true;
+ }
+ ostr.str("");
+ if (re->r.GIcache) {
+ ostr << "<light type=\"pathlight\" name=\"path_LT\" power=\"" << re->r.GIpower << "\" mode=\"occlusion\"";
+ ostr << "\n\tcache=\"on\" use_QMC=\"on\" threshold=\"" << re->r.GIrefinement << "\" "
+ << "cache_size=\"" << ((2.0/float(re->winx))*re->r.GIpixelspersample) << "\"";
+ ostr << "\n\tshadow_threshold=\"" << (1.0-re->r.GIshadowquality) << "\" grid=\"82\" search=\"35\"";
+ ostr << "\n\tignore_bumpnormals=\"" << (re->r.YF_nobump ? "on" : "off") << "\"";
+ if (fromAO) {
+ // for AO, with cache, using range of 32*1 to 32*16 seems good enough
+ ostr << "\n\tsamples=\"" << 32*world->aosamp << "\" maxdistance=\"" << world->aodist << "\" >\n";
+ }
+ else {
+ switch (re->r.GIquality)
+ {
+ case 1 : ostr << " samples=\"128\" >\n"; break;
+ case 2 : ostr << " samples=\"256\" >\n"; break;
+ case 3 : ostr << " samples=\"512\" >\n"; break;
+ case 4 : ostr << " samples=\"1024\" >\n"; break;
+ case 5 : ostr << " samples=\"2048\" >\n"; break;
+ default: ostr << " samples=\"256\" >\n";
+ }
+ }
+ }
+ else {
+ ostr << "<light type=\"hemilight\" name=\"hemi_LT\" power=\"" << re->r.GIpower << "\"";
+ if (fromAO) {
+ // use minimum of 4 samples for lowest sample setting, single sample way too noisy
+ ostr << "\n\tsamples=\"" << 3 + world->aosamp*world->aosamp
+ << "\" maxdistance=\"" << world->aodist
+ << "\" use_QMC=\"" << ((world->aomode & WO_AORNDSMP) ? "off" : "on") << "\" >\n";
+ }
+ else {
+ switch (re->r.GIquality)
+ {
+ case 1 :
+ case 2 : ostr << " samples=\"16\" >\n"; break;
+ case 3 : ostr << " samples=\"36\" >\n"; break;
+ case 4 : ostr << " samples=\"64\" >\n"; break;
+ case 5 : ostr << " samples=\"128\" >\n"; break;
+ default: ostr << " samples=\"25\" >\n";
+ }
+ }
+ }
+ ostr << "</light>\n\n";
+ xmlfile << ostr.str();
+}
+
+void yafrayFileRender_t::writePathlight()
+{
+ ostr.str("");
+ if (re->r.GIphotons)
+ {
+ ostr << "<light type=\"globalphotonlight\" name=\"gpm\" photons=\"" << re->r.GIphotoncount << "\"" << endl;
+ ostr << "\tradius=\"" << re->r.GIphotonradius << "\" depth=\"" << ((re->r.GIdepth>2) ? (re->r.GIdepth-1) : 1)
+ << "\" caus_depth=\"" << re->r.GIcausdepth << "\" search=\"" << re->r.GImixphotons << "\" >"<<endl;
+ ostr << "</light>"<<endl;
+ }
+ ostr << "<light type=\"pathlight\" name=\"path_LT\" power=\"" << re->r.GIindirpower << "\"";
+ ostr << " depth=\"" << ((re->r.GIphotons) ? 1 : re->r.GIdepth) << "\" caus_depth=\"" << re->r.GIcausdepth <<"\"\n";
+ if (re->r.GIdirect && re->r.GIphotons) ostr << "direct=\"on\"" << endl;
+ if (re->r.GIcache && !(re->r.GIdirect && re->r.GIphotons))
+ {
+ switch (re->r.GIquality)
+ {
+ case 1 : ostr << " samples=\"128\" \n"; break;
+ case 2 : ostr << " samples=\"256\" \n"; break;
+ case 3 : ostr << " samples=\"512\" \n"; break;
+ case 4 : ostr << " samples=\"1024\" \n"; break;
+ case 5 : ostr << " samples=\"2048\" \n"; break;
+ default: ostr << " samples=\"512\" \n";
+ }
+ ostr << " cache=\"on\" use_QMC=\"on\" threshold=\"" << re->r.GIrefinement << "\"" << endl;
+ ostr << "\tignore_bumpnormals=\"" << (re->r.YF_nobump ? "on" : "off") << "\"\n";
+ float sbase = 2.0/float(re->winx);
+ ostr << "\tcache_size=\"" << sbase*re->r.GIpixelspersample << "\" shadow_threshold=\"" <<
+ 1.0-re->r.GIshadowquality << "\" grid=\"82\" search=\"35\" >\n";
+ }
+ else
+ {
+ switch (re->r.GIquality)
+ {
+ case 1 : ostr << " samples=\"16\" >\n"; break;
+ case 2 : ostr << " samples=\"36\" >\n"; break;
+ case 3 : ostr << " samples=\"64\" >\n"; break;
+ case 4 : ostr << " samples=\"128\" >\n"; break;
+ case 5 : ostr << " samples=\"256\" >\n"; break;
+ default: ostr << " samples=\"25\" >\n";
+ }
+ }
+ ostr << "</light>\n\n";
+ xmlfile << ostr.str();
+}
+
+bool yafrayFileRender_t::writeWorld()
+{
+ World *world = G.scene->world;
+ if (re->r.GIquality!=0) {
+ if (re->r.GImethod==1) {
+ if (world==NULL) cout << "WARNING: need world background for skydome!\n";
+ writeHemilight();
+ }
+ else if (re->r.GImethod==2) writePathlight();
+ }
+
+ if (world==NULL) return false;
+
+ for (int i=0;i<MAX_MTEX;i++) {
+ MTex* wtex = world->mtex[i];
+ if (!wtex) continue;
+ Image* wimg = wtex->tex->ima;
+ // now always exports if image used as world texture (and 'Hori' mapping enabled)
+ if ((wtex->tex->type==TEX_IMAGE) && (wimg!=NULL) && (wtex->mapto & WOMAP_HORIZ)) {
+ string wt_path = wimg->name;
+ adjustPath(wt_path);
+ ostr.str("");
+ ostr << "<background type=\"image\" name=\"world_background\" ";
+ // exposure_adjust not restricted to integer range anymore
+ ostr << "exposure_adjust=\"" << wtex->tex->bright-1.f << "\"";
+ if (wtex->texco & TEXCO_ANGMAP)
+ ostr << " mapping=\"probe\" >\n";
+ else if (wtex->texco & TEXCO_H_SPHEREMAP) // in yafray full sphere
+ ostr << " mapping=\"sphere\" >\n";
+ else // assume 'tube' for anything else
+ ostr << " mapping=\"tube\" >\n";
+ ostr << "\t<filename value=\"" << wt_path << "\" />\n";
+ ostr << "\t<interpolate value=\"" << ((wtex->tex->imaflag & TEX_INTERPOL) ? "bilinear" : "none") << "\" />\n";
+ if (wtex->tex->filtersize>1.f) ostr << "\t<prefilter value=\"on\" />\n";
+ ostr << "</background>\n\n";
+ xmlfile << ostr.str();
+ return true;
+ }
+ }
+
+ ostr.str("");
+ ostr << "<background type=\"constant\" name=\"world_background\" >\n";
+ // if no GI used, the GIpower parameter is not always initialized, so in that case ignore it
+ // (have to change method to init yafray vars in Blender)
+ float bg_mult = (re->r.GImethod==0) ? 1 : re->r.GIpower;
+ ostr << "\t<color r=\"" << (world->horr * bg_mult) <<
+ "\" g=\"" << (world->horg * bg_mult) <<
+ "\" b=\"" << (world->horb * bg_mult) << "\" />\n";
+ ostr << "</background>\n\n";
+ xmlfile << ostr.str();
+
+ return true;
+}
+
+bool yafrayFileRender_t::executeYafray(const string &xmlpath)
+{
+ ostr.str("");
+ if (re->r.mode & R_BORDER) {
+ ostr << command_path << "yafray -c " << re->r.YF_numprocs
+ << " -r " << (2.f*re->r.border.xmin - 1.f)
+ << ":" << (2.f*re->r.border.xmax - 1.f)
+ << ":" << (2.f*re->r.border.ymin - 1.f)
+ << ":" << (2.f*re->r.border.ymax - 1.f)
+ << " \"" << xmlpath << "\"";
+ }
+ else
+ ostr << command_path << "yafray -c " << re->r.YF_numprocs << " \"" << xmlpath << "\"";
+
+ string command = ostr.str();
+ cout << "COMMAND: " << command << endl;
+#ifndef WIN32
+ sigset_t yaf,old;
+ sigemptyset(&yaf);
+ sigaddset(&yaf, SIGVTALRM);
+ sigprocmask(SIG_BLOCK, &yaf, &old);
+ int ret=system(command.c_str());
+ sigprocmask(SIG_SETMASK, &old, NULL);
+ if (WIFEXITED(ret))
+ {
+ if (WEXITSTATUS(ret)) cout<<"Executed -"<<command<<"-"<<endl;
+ switch (WEXITSTATUS(ret))
+ {
+ case 0: cout << "Yafray completed successfully\n"; return true;
+ case 127: cout << "Yafray not found\n"; return false;
+ case 126: cout << "Yafray: permission denied\n"; return false;
+ default: cout << "Yafray exited with errors\n"; return false;
+ }
+ }
+ else if (WIFSIGNALED(ret))
+ cout << "Yafray crashed\n";
+ else
+ cout << "Unknown error\n";
+ return false;
+#else
+ int ret=system(command.c_str());
+ return ret==0;
+#endif
+
+}
diff --git a/source/blender/yafray/intern/export_File.h b/source/blender/yafray/intern/export_File.h
new file mode 100644
index 00000000000..5d2e0c53a21
--- /dev/null
+++ b/source/blender/yafray/intern/export_File.h
@@ -0,0 +1,34 @@
+#ifndef __EXPORT_FILE_H
+#define __EXPORT_FILE_H
+
+#include"yafray_Render.h"
+
+class yafrayFileRender_t : public yafrayRender_t
+{
+ public:
+ virtual ~yafrayFileRender_t() {}
+ protected:
+ std::string imgout;
+ std::ofstream xmlfile;
+ std::string xmlpath;
+ std::ostringstream ostr;
+
+ void displayImage();
+ bool executeYafray(const std::string &xmlpath);
+ virtual void writeTextures();
+ virtual void writeShader(const std::string &shader_name, Material* matr, const std::string &facetexname="");
+ virtual void writeMaterialsAndModulators();
+ virtual void writeObject(Object* obj, const std::vector<VlakRen*> &VLR_list, const float obmat[4][4]);
+ virtual void writeAllObjects();
+ virtual void writeAreaLamp(LampRen* lamp, int num, float iview[4][4]);
+ virtual void writeLamps();
+ virtual void writeCamera();
+ virtual void writeHemilight();
+ virtual void writePathlight();
+ virtual bool writeWorld();
+ virtual bool writeRender();
+ virtual bool initExport();
+ virtual bool finishExport();
+};
+
+#endif
diff --git a/source/blender/yafray/intern/export_Plugin.cpp b/source/blender/yafray/intern/export_Plugin.cpp
new file mode 100644
index 00000000000..6a6137fefe9
--- /dev/null
+++ b/source/blender/yafray/intern/export_Plugin.cpp
@@ -0,0 +1,1981 @@
+#include "export_Plugin.h"
+
+#include <math.h>
+using namespace std;
+
+
+#ifdef WIN32
+#define WIN32_SKIP_HKEY_PROTECTION
+#include "BLI_winstuff.h"
+
+#ifndef FILE_MAXDIR
+#define FILE_MAXDIR 160
+#endif
+
+#ifndef FILE_MAXFILE
+#define FILE_MAXFILE 80
+#endif
+
+
+static string find_path()
+{
+ HKEY hkey;
+ DWORD dwType, dwSize;
+
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,"Software\\YafRay Team\\YafRay",0,KEY_READ,&hkey)==ERROR_SUCCESS)
+ {
+ dwType = REG_EXPAND_SZ;
+ dwSize = MAX_PATH;
+ DWORD dwStat;
+
+ char *pInstallDir=new char[MAX_PATH];
+
+ dwStat=RegQueryValueEx(hkey, TEXT("InstallDir"),
+ NULL, NULL,(LPBYTE)pInstallDir, &dwSize);
+
+ if (dwStat == NO_ERROR)
+ {
+ string res=pInstallDir;
+ delete [] pInstallDir;
+ return res;
+ }
+ else
+ cout << "Couldn't READ \'InstallDir\' value. Is yafray correctly installed?\n";
+ delete [] pInstallDir;
+
+ RegCloseKey(hkey);
+ }
+ else
+ cout << "Couldn't FIND registry key for yafray, is it installed?\n";
+
+ return string("");
+
+}
+
+static int createDir(char* name)
+{
+ if (BLI_exists(name))
+ return 2; //exists
+ if (CreateDirectory((LPCTSTR)(name), NULL)) {
+ cout << "Directory: " << name << " created\n";
+ return 1; // created
+ }
+ else {
+ cout << "Could not create directory: " << name << endl;
+ return 0; // fail
+ }
+}
+
+extern "C" { extern char bprogname[]; }
+
+// add drive character if not in path string, using blender executable location as reference
+static void addDrive(string &path)
+{
+ int sp = path.find_first_of(":");
+ if (sp==-1) {
+ string blpath = bprogname;
+ sp = blpath.find_first_of(":");
+ if (sp!=-1) path = blpath.substr(0, sp+1) + path;
+ }
+}
+
+#else
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+#endif
+
+static string YafrayPath()
+{
+#ifdef WIN32
+ string path=find_path();
+ return path;
+#else
+ static char *alternative[]=
+ {
+ "/usr/local/lib/",
+ "/usr/lib/",
+ NULL
+ };
+
+ for(int i=0;alternative[i]!=NULL;++i)
+ {
+ string fp = string(alternative[i]) + "libyafrayplugin.so";
+ struct stat st;
+ if (stat(fp.c_str(), &st)<0) continue;
+ if (st.st_mode & S_IROTH) return fp;
+ }
+ return "";
+#endif
+}
+
+static string YafrayPluginPath()
+{
+#ifdef WIN32
+ return find_path()+"\\plugins";
+#else
+ static char *alternative[]=
+ {
+ "/usr/local/lib/yafray",
+ "/usr/lib/yafray",
+ NULL
+ };
+
+ for(int i=0;alternative[i]!=NULL;++i)
+ {
+ struct stat st;
+ if (stat(alternative[i], &st)<0) continue;
+ if (S_ISDIR(st.st_mode) && (st.st_mode & S_IXOTH)) return alternative[i];
+ }
+ return "";
+#endif
+}
+
+
+
+yafrayPluginRender_t::~yafrayPluginRender_t()
+{
+ if (yafrayGate!=NULL) delete yafrayGate;
+ if (handle!=NULL) PIL_dynlib_close(handle);
+#ifdef WIN32
+ if (corehandle!=NULL) PIL_dynlib_close(corehandle);
+#endif
+}
+
+bool yafrayPluginRender_t::initExport()
+{
+ // bug #1897: when forcing render without yafray present, handle can be valid,
+ // but find_symbol might have failed, trying second time will crash.
+ // So make sure plugin loaded correctly and only get handle once.
+ if ((!plugin_loaded) || (handle==NULL))
+ {
+ string location = YafrayPath();
+#ifdef WIN32
+ /* Win 32 loader cannot find needed libs in yafray dir, so we have to load them
+ * by hand. This could be fixed using setdlldirectory function, but it is not
+ * available in all win32 versions
+ */
+ corehandle = PIL_dynlib_open((char *)(location + "\\yafraycore.dll").c_str());
+ if (corehandle==NULL)
+ {
+ cerr << "Error loading yafray plugin: " << PIL_dynlib_get_error_as_string(corehandle) << endl;
+ return false;
+ }
+ location += "\\yafrayplugin.dll";
+#endif
+
+ if (handle==NULL) {
+ handle = PIL_dynlib_open((char *)location.c_str());
+ if (handle==NULL)
+ {
+ cerr << "Error loading yafray plugin: " << PIL_dynlib_get_error_as_string(handle) << endl;
+ return false;
+ }
+ }
+ yafray::yafrayConstructor *constructor;
+ constructor = (yafray::yafrayConstructor *)PIL_dynlib_find_symbol(handle, YAFRAY_SYMBOL);
+ if (constructor==NULL)
+ {
+ cerr << "Error loading yafray plugin: " << PIL_dynlib_get_error_as_string(handle) << endl;
+ return false;
+ }
+ yafrayGate = constructor(re->r.YF_numprocs, YafrayPluginPath());
+
+ cout << "YafRay plugin loaded" << endl;
+ plugin_loaded = true;
+ }
+
+ return true;
+}
+
+bool yafrayPluginRender_t::writeRender()
+{
+ yafray::paramMap_t params;
+ params["camera_name"]=yafray::parameter_t("MAINCAM");
+ params["raydepth"]=yafray::parameter_t((float)re->r.YF_raydepth);
+ params["gamma"]=yafray::parameter_t(re->r.YF_gamma);
+ params["exposure"]=yafray::parameter_t(re->r.YF_exposure);
+ if (re->r.YF_AA)
+ {
+ params["AA_passes"] = yafray::parameter_t((int)re->r.YF_AApasses);
+ params["AA_minsamples"] = yafray::parameter_t(re->r.YF_AAsamples);
+ params["AA_pixelwidth"] = yafray::parameter_t(re->r.YF_AApixelsize);
+ params["AA_threshold"] = yafray::parameter_t(re->r.YF_AAthreshold);
+ }
+ else
+ {
+ // removed the default AA settings for midquality GI, better leave it to user
+ if ((re->r.mode & R_OSA) && (re->r.osa))
+ {
+ params["AA_passes"] = yafray::parameter_t((re->r.osa & 3)==0 ? (re->r.osa >> 2) : 1);
+ params["AA_minsamples"] = yafray::parameter_t((re->r.osa & 3)==0 ? 4 : re->r.osa);
+ }
+ else
+ {
+ params["AA_passes"] = yafray::parameter_t(0);
+ params["AA_minsamples"] = yafray::parameter_t(1);
+ }
+ params["AA_pixelwidth"] = yafray::parameter_t(1.5);
+ params["AA_threshold"] = yafray::parameter_t(0.05f);
+ }
+ if (re->r.mode & R_BORDER)
+ {
+ params["border_xmin"] = yafray::parameter_t(2.f*re->r.border.xmin - 1.f);
+ params["border_xmax"] = yafray::parameter_t(2.f*re->r.border.xmax - 1.f);
+ params["border_ymin"] = yafray::parameter_t(2.f*re->r.border.ymin - 1.f);
+ params["border_ymax"] = yafray::parameter_t(2.f*re->r.border.ymax - 1.f);
+ }
+ if (hasworld) {
+ World *world = G.scene->world;
+ if (world->mode & WO_MIST) {
+ // basic fog
+ float fd = world->mistdist;
+ if (fd>0) fd=1.f/fd; else fd=1;
+ params["fog_density"] = yafray::parameter_t(fd);
+ params["fog_color"] = yafray::parameter_t(yafray::color_t(world->horr, world->horg, world->horb));
+ }
+ params["background_name"] = yafray::parameter_t("world_background");
+ }
+ params["bias"] = yafray::parameter_t(re->r.YF_raybias);
+ params["clamp_rgb"] = yafray::parameter_t((re->r.YF_clamprgb==0) ? "on" : "off");
+ // lynx request
+ params["threads"] = yafray::parameter_t((int)re->r.YF_numprocs);
+ blenderYafrayOutput_t output(re);
+ yafrayGate->render(params, output);
+ cout << "render finished" << endl;
+ yafrayGate->clear();
+ return true;
+}
+
+bool yafrayPluginRender_t::finishExport()
+{
+ return true;
+}
+
+
+// displayImage() not for plugin, see putPixel() below
+
+#ifdef WIN32
+#define MAXPATHLEN MAX_PATH
+#else
+#include <sys/param.h>
+#endif
+static void adjustPath(string &path)
+{
+ // if relative, expand to full path
+ char cpath[MAXPATHLEN];
+ strcpy(cpath, path.c_str());
+ BLI_convertstringcode(cpath, G.sce, 0);
+ path = cpath;
+#ifdef WIN32
+ // add drive char if not there
+ addDrive(path);
+#endif
+}
+
+
+static string noise2string(short nbtype)
+{
+ switch (nbtype) {
+ case TEX_BLENDER:
+ return "blender";
+ case TEX_STDPERLIN:
+ return "stdperlin";
+ case TEX_VORONOI_F1:
+ return "voronoi_f1";
+ case TEX_VORONOI_F2:
+ return "voronoi_f2";
+ case TEX_VORONOI_F3:
+ return "voronoi_f3";
+ case TEX_VORONOI_F4:
+ return "voronoi_f4";
+ case TEX_VORONOI_F2F1:
+ return "voronoi_f2f1";
+ case TEX_VORONOI_CRACKLE:
+ return "voronoi_crackle";
+ case TEX_CELLNOISE:
+ return "cellnoise";
+ default:
+ case TEX_NEWPERLIN:
+ return "newperlin";
+ }
+}
+
+void yafrayPluginRender_t::writeTextures()
+{
+ // used to keep track of images already written
+ // (to avoid duplicates if also in imagetex for material TexFace texture)
+ set<Image*> dupimg;
+
+ yafray::paramMap_t params;
+ list<yafray::paramMap_t> lparams;
+ for (map<string, MTex*>::const_iterator blendtex=used_textures.begin();
+ blendtex!=used_textures.end();++blendtex)
+ {
+ lparams.clear();
+ params.clear();
+
+ MTex* mtex = blendtex->second;
+ Tex* tex = mtex->tex;
+ // name is image name instead of texture name when type is image (see TEX_IMAGE case below)
+ // (done because of possible combinations of 'TexFace' images and regular image textures, to avoid duplicates)
+ if (tex->type!=TEX_IMAGE) params["name"] = yafray::parameter_t(blendtex->first);
+
+ float nsz = tex->noisesize;
+ if (nsz!=0.f) nsz=1.f/nsz;
+
+ // noisebasis type
+ string ntype = noise2string(tex->noisebasis);
+ string ts, hardnoise=(tex->noisetype==TEX_NOISESOFT) ? "off" : "on";
+
+ switch (tex->type) {
+ case TEX_STUCCI:
+ // stucci is clouds as bump, only difference is an extra parameter to handle wall in/out
+ // turbulence value is not used, so for large values will not match well
+ case TEX_CLOUDS: {
+ params["type"] = yafray::parameter_t("clouds");
+ params["size"] = yafray::parameter_t(nsz);
+ params["hard"] = yafray::parameter_t(hardnoise);
+ if (tex->type==TEX_STUCCI) {
+ if (tex->stype==1)
+ ts = "positive";
+ else if (tex->stype==2)
+ ts = "negative";
+ else ts = "none";
+ params["bias"] = yafray::parameter_t(ts);
+ params["depth"] = yafray::parameter_t(0); // for stucci always 0
+ }
+ else params["depth"] = yafray::parameter_t(tex->noisedepth);
+ params["color_type"] = yafray::parameter_t(tex->stype);
+ params["noise_type"] = yafray::parameter_t(ntype);
+ break;
+ }
+ case TEX_WOOD:
+ {
+ params["type"] = yafray::parameter_t("wood");
+ // blender does not use depth value for wood, always 0
+ params["depth"] = yafray::parameter_t(0);
+ float turb = (tex->stype<2) ? 0.0 : tex->turbul;
+ params["turbulence"] = yafray::parameter_t(turb);
+ params["size"] = yafray::parameter_t(nsz);
+ params["hard"] = yafray::parameter_t(hardnoise);
+ ts = (tex->stype & 1) ? "rings" : "bands"; //stype 1&3 ringtype
+ params["wood_type"] = yafray::parameter_t(ts);
+ params["noise_type"] = yafray::parameter_t(ntype);
+ // shape parameter, for some reason noisebasis2 is used...
+ ts = "sin";
+ if (tex->noisebasis2==1) ts="saw"; else if (tex->noisebasis2==2) ts="tri";
+ params["shape"] = yafray::parameter_t(ts);
+ break;
+ }
+ case TEX_MARBLE:
+ {
+ params["type"] = yafray::parameter_t("marble");
+ params["depth"] = yafray::parameter_t(tex->noisedepth);
+ params["turbulence"] = yafray::parameter_t(tex->turbul);
+ params["size"] = yafray::parameter_t(nsz);
+ params["hard"] = yafray::parameter_t(hardnoise);
+ params["sharpness"] = yafray::parameter_t((float)(1<<tex->stype));
+ params["noise_type"] = yafray::parameter_t(ntype);
+ ts = "sin";
+ if (tex->noisebasis2==1) ts="saw"; else if (tex->noisebasis2==2) ts="tri";
+ params["shape"] = yafray::parameter_t(ts);
+ break;
+ }
+ case TEX_VORONOI:
+ {
+ params["type"] = yafray::parameter_t("voronoi");
+ ts = "int";
+ if (tex->vn_coltype==1)
+ ts = "col1";
+ else if (tex->vn_coltype==2)
+ ts = "col2";
+ else if (tex->vn_coltype==3)
+ ts = "col3";
+ params["color_type"] = yafray::parameter_t(ts);
+ params["weight1"] = yafray::parameter_t(tex->vn_w1);
+ params["weight2"] = yafray::parameter_t(tex->vn_w2);
+ params["weight3"] = yafray::parameter_t(tex->vn_w3);
+ params["weight4"] = yafray::parameter_t(tex->vn_w4);
+ params["mk_exponent"] = yafray::parameter_t(tex->vn_mexp);
+ params["intensity"] = yafray::parameter_t(tex->ns_outscale);
+ params["size"] = yafray::parameter_t(nsz);
+ ts = "actual";
+ if (tex->vn_distm==TEX_DISTANCE_SQUARED)
+ ts = "squared";
+ else if (tex->vn_distm==TEX_MANHATTAN)
+ ts = "manhattan";
+ else if (tex->vn_distm==TEX_CHEBYCHEV)
+ ts = "chebychev";
+ else if (tex->vn_distm==TEX_MINKOVSKY_HALF)
+ ts = "minkovsky_half";
+ else if (tex->vn_distm==TEX_MINKOVSKY_FOUR)
+ ts = "minkovsky_four";
+ else if (tex->vn_distm==TEX_MINKOVSKY)
+ ts = "minkovsky";
+ params["distance_metric"] = yafray::parameter_t(ts);
+ break;
+ }
+ case TEX_MUSGRAVE:
+ {
+ params["type"] = yafray::parameter_t("musgrave");
+ switch (tex->stype) {
+ case TEX_MFRACTAL:
+ ts = "multifractal";
+ break;
+ case TEX_RIDGEDMF:
+ ts = "ridgedmf";
+ break;
+ case TEX_HYBRIDMF:
+ ts = "hybridmf";
+ break;
+ case TEX_HTERRAIN:
+ ts = "heteroterrain";
+ break;
+ default:
+ case TEX_FBM:
+ ts = "fBm";
+ }
+ params["musgrave_type"] = yafray::parameter_t(ts);
+ params["noise_type"] = yafray::parameter_t(ntype);
+ params["H"] = yafray::parameter_t(tex->mg_H);
+ params["lacunarity"] = yafray::parameter_t(tex->mg_lacunarity);
+ params["octaves"] = yafray::parameter_t(tex->mg_octaves);
+ if ((tex->stype==TEX_HTERRAIN) || (tex->stype==TEX_RIDGEDMF) || (tex->stype==TEX_HYBRIDMF)) {
+ params["offset"] = yafray::parameter_t(tex->mg_offset);
+ if ((tex->stype==TEX_RIDGEDMF) || (tex->stype==TEX_HYBRIDMF))
+ params["gain"] = yafray::parameter_t(tex->mg_gain);
+ }
+ params["size"] = yafray::parameter_t(nsz);
+ params["intensity"] = yafray::parameter_t(tex->ns_outscale);
+ break;
+ }
+ case TEX_DISTNOISE:
+ {
+ params["type"] = yafray::parameter_t("distorted_noise");
+ params["distort"] = yafray::parameter_t(tex->dist_amount);
+ params["size"] = yafray::parameter_t(nsz);
+ params["noise_type1"] = yafray::parameter_t(ntype);
+ params["noise_type2"] = yafray::parameter_t(noise2string(tex->noisebasis2));
+ break;
+ }
+ case TEX_BLEND:
+ {
+ params["type"] = yafray::parameter_t("gradient");
+ switch (tex->stype) {
+ case 1: ts="quadratic"; break;
+ case 2: ts="cubic"; break;
+ case 3: ts="diagonal"; break;
+ case 4: ts="sphere"; break;
+ case 5: ts="halo"; break;
+ default:
+ case 0: ts="linear"; break;
+ }
+ params["gradient_type"] = yafray::parameter_t(ts);
+ if (tex->flag & TEX_FLIPBLEND) ts="on"; else ts="off";
+ params["flip_xy"] = yafray::parameter_t(ts);
+ break;
+ }
+ case TEX_NOISE:
+ {
+ params["type"] = yafray::parameter_t("random_noise");
+ params["depth"] = yafray::parameter_t(tex->noisedepth);
+ break;
+ }
+ case TEX_IMAGE:
+ {
+ Image* ima = tex->ima;
+ if (ima) {
+ // remember image to avoid duplicates later if also in imagetex
+ // (formerly done by removing from imagetex, but need image/material link)
+ dupimg.insert(ima);
+ params["type"] = yafray::parameter_t("image");
+ params["name"] = yafray::parameter_t(ima->id.name);
+ string texpath = ima->name;
+ adjustPath(texpath);
+ params["filename"] = yafray::parameter_t(texpath);
+ params["interpolate"] = yafray::parameter_t((tex->imaflag & TEX_INTERPOL) ? "bilinear" : "none");
+ }
+ break;
+ }
+ default:
+ cout << "Unsupported texture type\n";
+ }
+ yafrayGate->addShader(params, lparams);
+
+ // colorbands
+ if (tex->flag & TEX_COLORBAND)
+ {
+ ColorBand* cb = tex->coba;
+ if (cb)
+ {
+ lparams.clear();
+ params.clear();
+ params["type"] = yafray::parameter_t("colorband");
+ params["name"] = yafray::parameter_t(blendtex->first + "_coba");
+ params["input"] = yafray::parameter_t(blendtex->first);
+ for (int i=0;i<cb->tot;i++)
+ {
+ yafray::paramMap_t mparams;
+ mparams["value"] = yafray::parameter_t(cb->data[i].pos);
+ mparams["color"] = yafray::parameter_t(yafray::colorA_t(cb->data[i].r,
+ cb->data[i].g,
+ cb->data[i].b,
+ cb->data[i].a));
+ lparams.push_back(mparams);
+ }
+ yafrayGate->addShader(params, lparams);
+ }
+ }
+
+ }
+
+ // If used, textures for the material 'TexFace' case
+ if (!imagetex.empty()) {
+ for (map<Image*, set<Material*> >::const_iterator imgtex=imagetex.begin();
+ imgtex!=imagetex.end();++imgtex)
+ {
+ // skip if already written above
+ if (dupimg.find(imgtex->first)==dupimg.end()) {
+ lparams.clear();
+ params.clear();
+ params["name"] = yafray::parameter_t(imgtex->first->id.name);
+ params["type"] = yafray::parameter_t("image");
+ string texpath(imgtex->first->name);
+ adjustPath(texpath);
+ params["filename"] = yafray::parameter_t(texpath);
+ yafrayGate->addShader(params, lparams);
+ }
+ }
+ }
+
+}
+
+
+void yafrayPluginRender_t::writeShader(const string &shader_name, Material* matr, const string &facetexname)
+{
+ yafray::paramMap_t params;
+ list<yafray::paramMap_t> lparams;
+
+ // if material has ramps, export colorbands first
+ if (matr->mode & (MA_RAMP_COL|MA_RAMP_SPEC))
+ {
+ // both colorbands without input shader
+ ColorBand* cb = matr->ramp_col;
+ if ((matr->mode & MA_RAMP_COL) && (cb!=NULL))
+ {
+ params["type"] = yafray::parameter_t("colorband");
+ params["name"] = yafray::parameter_t(shader_name+"_difframp");
+ for (int i=0;i<cb->tot;i++) {
+ yafray::paramMap_t mparams;
+ mparams["value"] = yafray::parameter_t(cb->data[i].pos);
+ mparams["color"] = yafray::parameter_t(yafray::colorA_t(cb->data[i].r, cb->data[i].g, cb->data[i].b, cb->data[i].a));
+ lparams.push_back(mparams);
+ }
+ yafrayGate->addShader(params, lparams);
+ }
+ cb = matr->ramp_spec;
+ if ((matr->mode & MA_RAMP_SPEC) && (cb!=NULL))
+ {
+ lparams.clear();
+ params.clear();
+ params["type"] = yafray::parameter_t("colorband");
+ params["name"] = yafray::parameter_t(shader_name+"_specramp");
+ for (int i=0;i<cb->tot;i++) {
+ yafray::paramMap_t mparams;
+ mparams["value"] = yafray::parameter_t(cb->data[i].pos);
+ mparams["color"] = yafray::parameter_t(yafray::colorA_t(cb->data[i].r, cb->data[i].g, cb->data[i].b, cb->data[i].a));
+ lparams.push_back(mparams);
+ }
+ yafrayGate->addShader(params, lparams);
+ }
+ lparams.clear();
+ params.clear();
+ }
+
+ params["type"] = yafray::parameter_t("blendershader");
+ params["name"] = yafray::parameter_t(shader_name);
+ params["color"] = yafray::parameter_t(yafray::color_t(matr->r, matr->g, matr->b));
+ float sr=matr->specr, sg=matr->specg, sb=matr->specb;
+ if (matr->spec_shader==MA_SPEC_WARDISO) {
+ // ........
+ sr /= M_PI;
+ sg /= M_PI;
+ sb /= M_PI;
+ }
+ params["specular_color"] = yafray::parameter_t(yafray::color_t(sr, sg, sb));
+ params["mirror_color"] = yafray::parameter_t(yafray::color_t(matr->mirr, matr->mirg, matr->mirb));
+ params["diffuse_reflect"] = yafray::parameter_t(matr->ref);
+ params["specular_amount"] = yafray::parameter_t(matr->spec);
+ params["alpha"] = yafray::parameter_t(matr->alpha);
+
+ // if no GI used, the GIpower parameter is not always initialized, so in that case ignore it
+ float bg_mult = (re->r.GImethod==0) ? 1 : re->r.GIpower;
+ params["emit"]=yafray::parameter_t(matr->emit*bg_mult);
+
+ // reflection/refraction
+ if ( (matr->mode & MA_RAYMIRROR) || (matr->mode & MA_RAYTRANSP) )
+ params["IOR"] = yafray::parameter_t(matr->ang);
+
+ if (matr->mode & MA_RAYMIRROR)
+ {
+ // Sofar yafray's min_refle parameter (which misleadingly actually controls fresnel reflection offset)
+ // has been mapped to Blender's ray_mirror parameter.
+ // This causes it be be misinterpreted and misused as a reflection amount control however.
+ // Besides that, it also causes extra complications for the yafray Blendershader.
+ // So added an actual amount of reflection parameter instead, and another
+ // extra parameter 'frsOfs' to actually control fresnel offset (re-uses Blender fresnel_mir_i param).
+ params["reflect"] = yafray::parameter_t("on");
+ params["reflect_amount"] = yafray::parameter_t(matr->ray_mirror);
+ float fo = 1.f-(matr->fresnel_mir_i-1.f)*0.25f; // blender param range [1,5], also here reversed (1 in Blender -> no fresnel)
+ params["fresnel_offset"] = yafray::parameter_t(fo);
+
+ // for backward compatibility, also add old 'reflected' parameter, copy of mirror_color
+ params["reflected"] = yafray::parameter_t(yafray::color_t(matr->mirr, matr->mirg, matr->mirb));
+ // same for 'min_refle' param. Instead of the ray_mirror parameter that was used before, since now
+ // the parameter's function is taken over by the fresnel offset parameter, use that instead.
+ params["min_refle"] = yafray::parameter_t(fo);
+
+ }
+
+ if (matr->mode & MA_RAYTRANSP)
+ {
+ params["refract"] = yafray::parameter_t("on");
+ params["transmit_filter"] = yafray::parameter_t(matr->filter);
+ // tir on by default
+ params["tir"] = yafray::parameter_t("on");
+
+ // transmit absorption color
+ // to make things easier(?) for user it now specifies the actual color at 1 unit / YF_dscale of distance
+ const float maxlog = -log(1e-38);
+ float ar = (matr->YF_ar>0) ? -log(matr->YF_ar) : maxlog;
+ float ag = (matr->YF_ag>0) ? -log(matr->YF_ag) : maxlog;
+ float ab = (matr->YF_ab>0) ? -log(matr->YF_ab) : maxlog;
+ float sc = matr->YF_dscale;
+ if (sc!=0.f) sc=1.f/sc;
+ params["absorption"] = yafray::parameter_t(yafray::color_t(ar*sc, ag*sc, ab*sc));
+ // dispersion
+ params["dispersion_power"] = yafray::parameter_t(matr->YF_dpwr);
+ params["dispersion_samples"] = yafray::parameter_t(matr->YF_dsmp);
+ params["dispersion_jitter"] = yafray::parameter_t(matr->YF_djit ? "on" : "off");
+
+ // for backward compatibility, also add old 'transmitted' parameter, copy of 'color' * (1-alpha)
+ float na = 1.f-matr->alpha;
+ params["transmitted"] = yafray::parameter_t(yafray::color_t(matr->r*na, matr->g*na, matr->b*na));
+ }
+
+ string Mmode = "";
+ if (matr->mode & MA_TRACEBLE) Mmode += "traceable";
+ if (matr->mode & MA_SHADOW) Mmode += " shadow";
+ if (matr->mode & MA_SHLESS) Mmode += " shadeless";
+ if (matr->mode & MA_VERTEXCOL) Mmode += " vcol_light";
+ if (matr->mode & MA_VERTEXCOLP) Mmode += " vcol_paint";
+ if (matr->mode & MA_ZTRA) Mmode += " ztransp";
+ if (matr->mode & MA_ONLYSHADOW) Mmode += " onlyshadow";
+ if (Mmode!="") params["matmodes"] = yafray::parameter_t(Mmode);
+
+ // diffuse & specular brdf, lambert/cooktorr defaults
+ // diffuse
+ if (matr->diff_shader==MA_DIFF_ORENNAYAR) {
+ params["diffuse_brdf"] = yafray::parameter_t("oren_nayar");
+ params["roughness"] = yafray::parameter_t(matr->roughness);
+ }
+ else if (matr->diff_shader==MA_DIFF_TOON) {
+ params["diffuse_brdf"] = yafray::parameter_t("toon");
+ params["toondiffuse_size"] = yafray::parameter_t(matr->param[0]);
+ params["toondiffuse_smooth"] = yafray::parameter_t(matr->param[1]);
+ }
+ else if (matr->diff_shader==MA_DIFF_MINNAERT) {
+ params["diffuse_brdf"] = yafray::parameter_t("minnaert");
+ params["darkening"] = yafray::parameter_t(matr->darkness);
+ }
+ else params["diffuse_brdf"] = yafray::parameter_t("lambert");
+ // specular
+ if (matr->spec_shader==MA_SPEC_PHONG) {
+ params["specular_brdf"] = yafray::parameter_t("phong");
+ params["hard"] = yafray::parameter_t(matr->har);
+ }
+ else if (matr->spec_shader==MA_SPEC_BLINN) {
+ params["specular_brdf"] = yafray::parameter_t("blinn");
+ params["blinn_ior"] = yafray::parameter_t(matr->refrac);
+ params["hard"] = yafray::parameter_t(matr->har);
+ }
+ else if (matr->spec_shader==MA_SPEC_TOON) {
+ params["specular_brdf"] = yafray::parameter_t("toon");
+ params["toonspecular_size"] = yafray::parameter_t(matr->param[2]);
+ params["toonspecular_smooth"] = yafray::parameter_t(matr->param[3]);
+ }
+ else if (matr->spec_shader==MA_SPEC_WARDISO) {
+ params["specular_brdf"] = yafray::parameter_t("ward");
+ params["u_roughness"] = yafray::parameter_t(matr->rms);
+ params["v_roughness"] = yafray::parameter_t(matr->rms);
+ }
+ else {
+ params["specular_brdf"] = yafray::parameter_t("blender_cooktorr");
+ params["hard"] = yafray::parameter_t(matr->har);
+ }
+
+ // ramps, if used
+ if (matr->mode & (MA_RAMP_COL|MA_RAMP_SPEC))
+ {
+ const string rm_blend[9] = {"mix", "add", "mul", "sub", "screen", "divide", "difference", "darken", "lighten"};
+ const string rm_mode[4] = {"shader", "energy", "normal", "result"};
+ // diffuse
+ if ((matr->mode & MA_RAMP_COL) && (matr->ramp_col!=NULL))
+ {
+ params["diffuse_ramp"] = yafray::parameter_t(shader_name+"_difframp");
+ params["diffuse_ramp_mode"] = yafray::parameter_t(rm_mode[(int)matr->rampin_col]);
+ params["diffuse_ramp_blend"] = yafray::parameter_t(rm_blend[(int)matr->rampblend_col]);
+ params["diffuse_ramp_factor"] = yafray::parameter_t(matr->rampfac_col);
+ }
+ // specular
+ if ((matr->mode & MA_RAMP_SPEC) && (matr->ramp_spec!=NULL)) {
+ params["specular_ramp"] = yafray::parameter_t(shader_name+"_specramp");
+ params["specular_ramp_mode"] = yafray::parameter_t(rm_mode[(int)matr->rampin_spec]);
+ params["specular_ramp_blend"] = yafray::parameter_t(rm_blend[(int)matr->rampblend_spec]);
+ params["specular_ramp_factor"] = yafray::parameter_t(matr->rampfac_spec);
+ }
+ }
+
+ // modulators
+ // first modulator is the texture of the face, if used (TexFace mode)
+ if (facetexname.length()!=0) {
+ yafray::paramMap_t mparams;
+ mparams["input"] = yafray::parameter_t(facetexname);
+ mparams["color"] = yafray::parameter_t(1);
+ lparams.push_back(mparams);
+ }
+
+ for (int m2=0;m2<MAX_MTEX;m2++)
+ {
+ if (matr->septex & (1<<m2)) continue;// all active channels
+ // ignore null mtex
+ MTex* mtex = matr->mtex[m2];
+ if (mtex==NULL) continue;
+ // ignore null tex
+ Tex* tex = mtex->tex;
+ if (tex==NULL) continue;
+
+ map<string, MTex*>::const_iterator mtexL = used_textures.find(string(tex->id.name));
+ if (mtexL!=used_textures.end())
+ {
+ yafray::paramMap_t mparams;
+ // when no facetex used, shader_name is created from original material name
+ char temp[32];
+ sprintf(temp,"_map%d", m2);
+ if (facetexname.length()!=0)
+ mparams["input"] = yafray::parameter_t(string(matr->id.name) + string(temp));
+ else
+ mparams["input"] = yafray::parameter_t(shader_name + temp);
+
+ // blendtype, would have been nice if the order would have been the same as for ramps...
+ const string blendtype[9] = {"mix", "mul", "add", "sub", "divide", "darken", "difference", "lighten", "screen"};
+ mparams["mode"] = yafray::parameter_t(blendtype[(int)mtex->blendtype]);
+
+ // texture color (for use with MUL and/or no_rgb etc..)
+ mparams["texcol"]=yafray::parameter_t(yafray::color_t(mtex->r,mtex->g,mtex->b));
+ // texture contrast, brightness & color adjustment
+ mparams["filtercolor"]=yafray::parameter_t(yafray::color_t(tex->rfac,tex->gfac,tex->bfac));
+ mparams["contrast"]=yafray::parameter_t(tex->contrast);
+ mparams["brightness"]=yafray::parameter_t(tex->bright);
+ // all texture flags now are switches, having the value 1 or -1 (negative option)
+ // the negative option only used for the intensity modulation options.
+
+ // material (diffuse) color, amount controlled by colfac (see below)
+ if (mtex->mapto & MAP_COL)
+ mparams["color"]=yafray::parameter_t(1.0);
+ // bumpmapping
+ if ((mtex->mapto & MAP_NORM) || (mtex->maptoneg & MAP_NORM))
+ {
+ // for yafray, bump factor is negated (unless tex is stucci, not affected by 'Neg')
+ // scaled down quite a bit
+ float nf = mtex->norfac;
+ if (tex->type!=TEX_STUCCI) nf *= -1.f;
+ if (mtex->maptoneg & MAP_NORM) nf *= -1.f;
+ mparams["normal"] = yafray::parameter_t(nf/60.f);
+ }
+
+ // all blender texture modulation as switches, either 1 or -1 (negative state of button)
+ // Csp, specular color modulation
+ if (mtex->mapto & MAP_COLSPEC)
+ mparams["colspec"] = yafray::parameter_t(1.0);
+ // CMir, mirror color modulation
+ if (mtex->mapto & MAP_COLMIR)
+ mparams["colmir"] = yafray::parameter_t(1.0);
+
+ // Ref, diffuse reflection amount modulation
+ if ((mtex->mapto & MAP_REF) || (mtex->maptoneg & MAP_REF))
+ {
+ int t = 1;
+ if (mtex->maptoneg & MAP_REF) t = -1;
+ mparams["difref"] = yafray::parameter_t(t);
+ }
+
+ // Spec, specular amount mod
+ if ((mtex->mapto & MAP_SPEC) || (mtex->maptoneg & MAP_SPEC))
+ {
+ int t = 1;
+ if (mtex->maptoneg & MAP_SPEC) t = -1;
+ mparams["specular"] = yafray::parameter_t(t);
+ }
+
+ // hardness modulation
+ if ((mtex->mapto & MAP_HAR) || (mtex->maptoneg & MAP_HAR))
+ {
+ int t = 1;
+ if (mtex->maptoneg & MAP_HAR) t = -1;
+ mparams["hard"] = yafray::parameter_t(t);
+ }
+
+ // alpha modulation
+ if ((mtex->mapto & MAP_ALPHA) || (mtex->maptoneg & MAP_ALPHA))
+ {
+ int t = 1;
+ if (mtex->maptoneg & MAP_ALPHA) t = -1;
+ mparams["alpha"] = yafray::parameter_t(t);
+ }
+
+ // emit modulation
+ if ((mtex->mapto & MAP_EMIT) || (mtex->maptoneg & MAP_EMIT)) {
+ int t = 1;
+ if (mtex->maptoneg & MAP_EMIT) t = -1;
+ mparams["emit"] = yafray::parameter_t(t);
+ }
+
+ // raymir modulation
+ if ((mtex->mapto & MAP_RAYMIRR) || (mtex->maptoneg & MAP_RAYMIRR)) {
+ int t = 1;
+ if (mtex->maptoneg & MAP_RAYMIRR) t = -1;
+ mparams["raymir"] = yafray::parameter_t(t);
+ }
+
+ // texture flag, combination of strings
+ string ts;
+ if (mtex->texflag & (MTEX_RGBTOINT | MTEX_STENCIL | MTEX_NEGATIVE)) {
+ ts = "";
+ if (mtex->texflag & MTEX_RGBTOINT) ts += "no_rgb ";
+ if (mtex->texflag & MTEX_STENCIL) ts += "stencil ";
+ if (mtex->texflag & MTEX_NEGATIVE) ts += "negative";
+ mparams["texflag"]=yafray::parameter_t(ts);
+ }
+
+ // colfac, controls amount of color modulation
+ mparams["colfac"]=yafray::parameter_t(mtex->colfac);
+ // def_var
+ mparams["def_var"]=yafray::parameter_t(mtex->def_var);
+ //varfac
+ mparams["varfac"]=yafray::parameter_t(mtex->varfac);
+
+ if ((tex->imaflag & (TEX_CALCALPHA | TEX_USEALPHA)) || (tex->flag & TEX_NEGALPHA))
+ {
+ ts = "";
+ if (tex->imaflag & TEX_CALCALPHA) ts += "calc_alpha ";
+ if (tex->imaflag & TEX_USEALPHA) ts += "use_alpha ";
+ if (tex->flag & TEX_NEGALPHA) ts += "neg_alpha";
+ mparams["alpha_flag"] = yafray::parameter_t(ts);
+ }
+
+ // image as normalmap flag
+ if (tex->imaflag & TEX_NORMALMAP) mparams["normalmap"] = yafray::parameter_t("on");
+
+ lparams.push_back(mparams);
+ }
+ }
+ yafrayGate->addShader(params, lparams);
+
+}
+
+// write all materials & modulators
+void yafrayPluginRender_t::writeMaterialsAndModulators()
+{
+ // shaders/mappers for regular texture (or non-texture) mode
+ // In case material has texface mode, and all faces have an image texture,
+ // this shader will not be used, but still be written
+ yafray::paramMap_t params;
+ list<yafray::paramMap_t> lparams;
+ for (map<string, Material*>::const_iterator blendmat=used_materials.begin();
+ blendmat!=used_materials.end();++blendmat)
+ {
+ Material* matr = blendmat->second;
+ // mapper(s)
+ for (int m=0;m<MAX_MTEX;m++)
+ {
+ if (matr->septex & (1<<m)) continue;// all active channels
+ // ignore null mtex
+ MTex* mtex = matr->mtex[m];
+ if (mtex==NULL) continue;
+ // ignore null tex
+ Tex* tex = mtex->tex;
+ if (tex==NULL) continue;
+
+ map<string, MTex*>::const_iterator mtexL = used_textures.find(string(tex->id.name));
+ if (mtexL!=used_textures.end())
+ {
+ params.clear(); //!!!
+ lparams.clear();
+ char temp[32];
+ sprintf(temp, "_map%d", m);
+ params["type"] = yafray::parameter_t("blendermapper");
+ params["name"] = yafray::parameter_t(blendmat->first + string(temp));
+ if ((mtex->texco & TEXCO_OBJECT) || (mtex->texco & TEXCO_REFL) || (mtex->texco & TEXCO_NORM))
+ {
+ // For object, reflection & normal mapping, add the object matrix to the modulator,
+ // as in LF script, use camera matrix if no object specified.
+ // In this case this means the inverse of that matrix
+ float texmat[4][4], itexmat[4][4];
+ if ((mtex->texco & TEXCO_OBJECT) && (mtex->object))
+ MTC_Mat4CpyMat4(texmat, mtex->object->obmat);
+ else // also for refl. map
+ MTC_Mat4CpyMat4(texmat, maincam_obj->obmat);
+ MTC_Mat4Invert(itexmat, texmat);
+#define flp yafray::parameter_t
+ params["m00"]=flp(itexmat[0][0]); params["m01"]=flp(itexmat[1][0]);
+ params["m02"]=flp(itexmat[2][0]); params["m03"]=flp(itexmat[3][0]);
+ params["m10"]=flp(itexmat[0][1]); params["m11"]=flp(itexmat[1][1]);
+ params["m12"]=flp(itexmat[2][1]); params["m13"]=flp(itexmat[3][1]);
+ params["m20"]=flp(itexmat[0][2]); params["m21"]=flp(itexmat[1][2]);
+ params["m22"]=flp(itexmat[2][2]); params["m23"]=flp(itexmat[3][2]);
+ params["m30"]=flp(itexmat[0][3]); params["m31"]=flp(itexmat[1][3]);
+ params["m32"]=flp(itexmat[2][3]); params["m33"]=flp(itexmat[3][3]);
+#undef flp
+ }
+ // use image name instead of texname when texture is image
+ if ((tex->type==TEX_IMAGE) && tex->ima)
+ params["input"] = yafray::parameter_t(tex->ima->id.name);
+ else if ((tex->flag & TEX_COLORBAND) & (tex->coba!=NULL))
+ params["input"] = yafray::parameter_t(mtexL->first + "_coba");
+ else
+ params["input"] = yafray::parameter_t(mtexL->first);
+
+ // texture size
+ params["sizex"] = yafray::parameter_t(mtex->size[0]);
+ params["sizey"] = yafray::parameter_t(mtex->size[1]);
+ params["sizez"] = yafray::parameter_t(mtex->size[2]);
+
+ // texture offset
+ params["ofsx"] = yafray::parameter_t(mtex->ofs[0]);
+ params["ofsy"] = yafray::parameter_t(mtex->ofs[1]);
+ params["ofsz"] = yafray::parameter_t(mtex->ofs[2]);
+
+ // texture coordinates, have to disable 'sticky' in Blender
+ if (mtex->texco & TEXCO_UV)
+ params["texco"] = yafray::parameter_t("uv");
+ else if ((mtex->texco & TEXCO_GLOB) || (mtex->texco & TEXCO_OBJECT))
+ // object mode is also set as global, but the object matrix
+ // was specified above with <modulator..>
+ params["texco"] = yafray::parameter_t("global");
+ else if ((mtex->texco & TEXCO_ORCO) || (mtex->texco & TEXCO_STRAND))
+ // orco flag now used for 'strand'-mapping as well, see mesh code
+ params["texco"] = yafray::parameter_t("orco");
+ else if (mtex->texco & TEXCO_WINDOW)
+ params["texco"] = yafray::parameter_t("window");
+ else if (mtex->texco & TEXCO_NORM)
+ params["texco"] = yafray::parameter_t("normal");
+ else if (mtex->texco & TEXCO_REFL)
+ params["texco"] = yafray::parameter_t("reflect");
+
+ // texture projection axes, both image & procedural
+ string proj = "nxyz"; // 'n' for 'none'
+ params["proj_x"] = yafray::parameter_t(string(1,proj[mtex->projx]));
+ params["proj_y"] = yafray::parameter_t(string(1,proj[mtex->projy]));
+ params["proj_z"] = yafray::parameter_t(string(1,proj[mtex->projz]));
+
+ // texture mapping parameters only relevant to image type
+ if (tex->type==TEX_IMAGE)
+ {
+ if (mtex->mapping==MTEX_FLAT)
+ params["mapping"] = yafray::parameter_t("flat");
+ else if (mtex->mapping==MTEX_CUBE)
+ params["mapping"] = yafray::parameter_t("cube");
+ else if (mtex->mapping==MTEX_TUBE)
+ params["mapping"] = yafray::parameter_t("tube");
+ else if (mtex->mapping==MTEX_SPHERE)
+ params["mapping"] = yafray::parameter_t("sphere");
+
+ // repeat
+ params["xrepeat"] = yafray::parameter_t(tex->xrepeat);
+ params["yrepeat"] = yafray::parameter_t(tex->yrepeat);
+
+ // clipping
+ if (tex->extend==TEX_EXTEND)
+ params["clipping"] = yafray::parameter_t("extend");
+ else if (tex->extend==TEX_CLIP)
+ params["clipping"] = yafray::parameter_t("clip");
+ else if (tex->extend==TEX_CLIPCUBE)
+ params["clipping"] = yafray::parameter_t("clipcube");
+ else if (tex->extend==TEX_CHECKER) {
+ params["clipping"] = yafray::parameter_t("checker");
+ string ts = "";
+ if (tex->flag & TEX_CHECKER_ODD) ts += "odd";
+ if (tex->flag & TEX_CHECKER_EVEN) ts += " even";
+ params["checker_mode"] = yafray::parameter_t(ts);
+ params["checker_dist"] = yafray::parameter_t(tex->checkerdist);
+ }
+ else
+ params["clipping"] = yafray::parameter_t("repeat");
+
+ // crop min/max
+ params["cropmin_x"] = yafray::parameter_t(tex->cropxmin);
+ params["cropmin_y"] = yafray::parameter_t(tex->cropymin);
+ params["cropmax_x"] = yafray::parameter_t(tex->cropxmax);
+ params["cropmax_y"] = yafray::parameter_t(tex->cropymax);
+
+ // rot90 flag
+ if (tex->imaflag & TEX_IMAROT)
+ params["rot90"] = yafray::parameter_t("on");
+ else
+ params["rot90"] = yafray::parameter_t("off");
+ }
+ yafrayGate->addShader(params, lparams);
+ }
+ }
+
+ // shader + modulators
+ writeShader(blendmat->first, matr);
+
+ }
+
+ // write the mappers & shaders for the TexFace case
+ if (!imagetex.empty()) {
+ // Yafray doesn't have per-face-textures, only per-face-shaders,
+ // so create as many mappers/shaders as the images used by the object
+ params.clear();
+ lparams.clear();
+ int snum = 0;
+ for (map<Image*, set<Material*> >::const_iterator imgtex=imagetex.begin();
+ imgtex!=imagetex.end();++imgtex)
+ {
+
+ for (set<Material*>::const_iterator imgmat=imgtex->second.begin();
+ imgmat!=imgtex->second.end();++imgmat)
+ {
+ Material* matr = *imgmat;
+ // mapper
+ params["type"] = yafray::parameter_t("blendermapper");
+ char temp[32];
+ sprintf(temp, "_ftmap%d", snum);
+ params["name"] = yafray::parameter_t(string(matr->id.name) + string(temp));
+ params["input"] = yafray::parameter_t(imgtex->first->id.name);
+ // all yafray default settings, except for texco, so no need to set others
+ params["texco"] = yafray::parameter_t("uv");
+ yafrayGate->addShader(params, lparams);
+
+ // shader, remember name, used later when writing per-face-shaders
+ sprintf(temp, "_ftsha%d", snum);
+ string shader_name = string(matr->id.name) + string(temp);
+ imgtex_shader[string(matr->id.name) + string(imgtex->first->id.name)] = shader_name;
+
+ sprintf(temp, "_ftmap%d", snum++);
+ string facetexname = string(matr->id.name) + string(temp);
+ writeShader(shader_name, matr, facetexname);
+ }
+
+ }
+ }
+
+}
+
+void yafrayPluginRender_t::genUVcoords(vector<yafray::GFLOAT> &uvcoords, VlakRen *vlr, MTFace* uvc, bool comple)
+{
+ if (uvc)
+ {
+ // tri uv split indices
+ int ui1=0, ui2=1, ui3=2;
+ if (vlr->flag & R_DIVIDE_24) {
+ ui3++;
+ if (vlr->flag & R_FACE_SPLIT) { ui1++; ui2++; }
+ }
+ else if (vlr->flag & R_FACE_SPLIT) { ui2++; ui3++; }
+ if (comple) {
+ ui1 = (ui1+2) & 3;
+ ui2 = (ui2+2) & 3;
+ ui3 = (ui3+2) & 3;
+ }
+ uvcoords.push_back(uvc->uv[ui1][0]); uvcoords.push_back(1-uvc->uv[ui1][1]);
+ uvcoords.push_back(uvc->uv[ui2][0]); uvcoords.push_back(1-uvc->uv[ui2][1]);
+ uvcoords.push_back(uvc->uv[ui3][0]); uvcoords.push_back(1-uvc->uv[ui3][1]);
+ }
+ else
+ {
+ uvcoords.push_back(0); uvcoords.push_back(0);
+ uvcoords.push_back(0); uvcoords.push_back(0);
+ uvcoords.push_back(0); uvcoords.push_back(0);
+ }
+}
+
+void yafrayPluginRender_t::genVcol(vector<yafray::CFLOAT> &vcol, VlakRen *vlr, bool comple)
+{
+ MCol *mcol= RE_vlakren_get_mcol(re, vlr, 0, NULL, 0);
+
+ if (mcol)
+ {
+ // tri vcol split indices
+ int ui1=0, ui2=1, ui3=2;
+ if (vlr->flag & R_DIVIDE_24) {
+ ui3++;
+ if (vlr->flag & R_FACE_SPLIT) { ui1++; ui2++; }
+ }
+ else if (vlr->flag & R_FACE_SPLIT) { ui2++; ui3++; }
+ if (comple) {
+ ui1 = (ui1+2) & 3;
+ ui2 = (ui2+2) & 3;
+ ui3 = (ui3+2) & 3;
+ }
+ unsigned char* pt = reinterpret_cast<unsigned char*>(&mcol[ui1]);
+ vcol.push_back((float)pt[3]/255.f); vcol.push_back((float)pt[2]/255.f); vcol.push_back((float)pt[1]/255.f);
+ pt = reinterpret_cast<unsigned char*>(&mcol[ui2]);
+ vcol.push_back((float)pt[3]/255.f); vcol.push_back((float)pt[2]/255.f); vcol.push_back((float)pt[1]/255.f);
+ pt = reinterpret_cast<unsigned char*>(&mcol[ui3]);
+ vcol.push_back((float)pt[3]/255.f); vcol.push_back((float)pt[2]/255.f); vcol.push_back((float)pt[1]/255.f);
+ }
+ else
+ {
+ vcol.push_back(0); vcol.push_back(0); vcol.push_back(0);
+ vcol.push_back(0); vcol.push_back(0); vcol.push_back(0);
+ vcol.push_back(0); vcol.push_back(0); vcol.push_back(0);
+ }
+}
+
+void yafrayPluginRender_t::genFace(vector<int> &faces,vector<string> &shaders,vector<int> &faceshader,
+ vector<yafray::GFLOAT> &uvcoords,vector<yafray::CFLOAT> &vcol,
+ map<VertRen*, int> &vert_idx,VlakRen *vlr,
+ int has_orco,bool has_uv)
+{
+ Material* fmat = vlr->mat;
+ bool EXPORT_VCOL = ((fmat->mode & (MA_VERTEXCOL|MA_VERTEXCOLP))!=0);
+ string fmatname(fmat->id.name);
+ // use name in imgtex_shader list if 'TexFace' enabled for this face material
+ if (fmat->mode & MA_FACETEXTURE) {
+ MTFace* tface = RE_vlakren_get_tface(re, vlr, 0, NULL, 0);
+ if (tface) {
+ Image* fimg = (Image*)tface->tpage;
+ if (fimg) fmatname = imgtex_shader[fmatname + string(fimg->id.name)];
+ }
+ }
+ else if (fmatname.length()==0) fmatname = "blender_default";
+ bool newmat=true;
+ for(unsigned int i=0;i<shaders.size();++i)
+ if(shaders[i]==fmatname)
+ {
+ newmat=false;
+ faceshader.push_back(i);
+ break;
+ }
+ if(newmat)
+ {
+ shaders.push_back(fmatname);
+ faceshader.push_back(shaders.size()-1);
+ }
+
+ MTFace* uvc = RE_vlakren_get_tface(re, vlr, 0, NULL, 0); // possible uvcoords (v upside down)
+ int idx1, idx2, idx3;
+
+ idx1 = vert_idx.find(vlr->v1)->second;
+ idx2 = vert_idx.find(vlr->v2)->second;
+ idx3 = vert_idx.find(vlr->v3)->second;
+
+ // make sure the indices point to the vertices when orco coords exported
+ if (has_orco) { idx1*=2; idx2*=2; idx3*=2; }
+
+ faces.push_back(idx1); faces.push_back(idx2); faces.push_back(idx3);
+
+ if(has_uv) genUVcoords(uvcoords, vlr, uvc);
+ if (EXPORT_VCOL) genVcol(vcol, vlr);
+}
+
+void yafrayPluginRender_t::genCompleFace(vector<int> &faces,/*vector<string> &shaders,*/vector<int> &faceshader,
+ vector<yafray::GFLOAT> &uvcoords,vector<yafray::CFLOAT> &vcol,
+ map<VertRen*, int> &vert_idx,VlakRen *vlr,
+ int has_orco,bool has_uv)
+{
+ Material* fmat = vlr->mat;
+ bool EXPORT_VCOL = ((fmat->mode & (MA_VERTEXCOL|MA_VERTEXCOLP))!=0);
+
+ faceshader.push_back(faceshader.back());
+ MTFace* uvc = RE_vlakren_get_tface(re, vlr, 0, NULL, 0); // possible uvcoords (v upside down)
+ int idx1, idx2, idx3;
+ idx1 = vert_idx.find(vlr->v3)->second;
+ idx2 = vert_idx.find(vlr->v4)->second;
+ idx3 = vert_idx.find(vlr->v1)->second;
+
+ // make sure the indices point to the vertices when orco coords exported
+ if (has_orco) { idx1*=2; idx2*=2; idx3*=2; }
+
+ faces.push_back(idx1); faces.push_back(idx2); faces.push_back(idx3);
+
+ if (has_uv) genUVcoords(uvcoords, vlr, uvc, true);
+ if (EXPORT_VCOL) genVcol(vcol, vlr, true);
+}
+
+void yafrayPluginRender_t::genVertices(vector<yafray::point3d_t> &verts, int &vidx,
+ map<VertRen*, int> &vert_idx, VlakRen* vlr, int has_orco, Object* obj)
+{
+ VertRen* ver;
+ float tvec[3]; // for back2world transform
+
+ // for deformed objects, object->imat is no longer valid,
+ // so have to create inverse render matrix ourselves here
+ float mat[4][4], imat[4][4];
+ MTC_Mat4MulMat4(mat, obj->obmat, re->viewmat);
+ MTC_Mat4Invert(imat, mat);
+
+ if (vert_idx.find(vlr->v1)==vert_idx.end())
+ {
+ vert_idx[vlr->v1] = vidx++;
+ ver = vlr->v1;
+ MTC_cp3Float(ver->co, tvec);
+ MTC_Mat4MulVecfl(imat, tvec);
+ verts.push_back(yafray::point3d_t(tvec[0], tvec[1], tvec[2]));
+ // has_orco now an int, if 1 -> strand mapping, if 2 -> normal orco mapping
+ if (has_orco==1)
+ verts.push_back(yafray::point3d_t(ver->accum));
+ else if (has_orco==2)
+ verts.push_back(yafray::point3d_t(ver->orco[0], ver->orco[1], ver->orco[2]));
+ }
+ if (vert_idx.find(vlr->v2)==vert_idx.end())
+ {
+ vert_idx[vlr->v2] = vidx++;
+ ver = vlr->v2;
+ MTC_cp3Float(ver->co, tvec);
+ MTC_Mat4MulVecfl(imat, tvec);
+ verts.push_back(yafray::point3d_t(tvec[0], tvec[1], tvec[2]));
+ // has_orco now an int, if 1 -> strand mapping, if 2 -> normal orco mapping
+ if (has_orco==1)
+ verts.push_back(yafray::point3d_t(ver->accum));
+ else if (has_orco==2)
+ verts.push_back(yafray::point3d_t(ver->orco[0], ver->orco[1], ver->orco[2]));
+ }
+ if (vert_idx.find(vlr->v3)==vert_idx.end())
+ {
+ vert_idx[vlr->v3] = vidx++;
+ ver = vlr->v3;
+ MTC_cp3Float(ver->co, tvec);
+ MTC_Mat4MulVecfl(imat, tvec);
+ verts.push_back(yafray::point3d_t(tvec[0], tvec[1], tvec[2]));
+ // has_orco now an int, if 1 -> strand mapping, if 2 -> normal orco mapping
+ if (has_orco==1)
+ verts.push_back(yafray::point3d_t(ver->accum));
+ else if (has_orco==2)
+ verts.push_back(yafray::point3d_t(ver->orco[0], ver->orco[1], ver->orco[2]));
+ }
+ if ((vlr->v4) && (vert_idx.find(vlr->v4)==vert_idx.end()))
+ {
+ vert_idx[vlr->v4] = vidx++;
+ ver = vlr->v4;
+ MTC_cp3Float(ver->co, tvec);
+ MTC_Mat4MulVecfl(imat, tvec);
+ verts.push_back(yafray::point3d_t(tvec[0], tvec[1], tvec[2]));
+ // has_orco now an int, if 1 -> strand mapping, if 2 -> normal orco mapping
+ if (has_orco==1)
+ verts.push_back(yafray::point3d_t(ver->accum));
+ else if (has_orco==2)
+ verts.push_back(yafray::point3d_t(ver->orco[0], ver->orco[1], ver->orco[2]));
+ }
+}
+
+void yafrayPluginRender_t::writeObject(Object* obj, const vector<VlakRen*> &VLR_list, const float obmat[4][4])
+{
+ float mtr[4*4];
+ mtr[0*4+0]=obmat[0][0]; mtr[0*4+1]=obmat[1][0]; mtr[0*4+2]=obmat[2][0]; mtr[0*4+3]=obmat[3][0];
+ mtr[1*4+0]=obmat[0][1]; mtr[1*4+1]=obmat[1][1]; mtr[1*4+2]=obmat[2][1]; mtr[1*4+3]=obmat[3][1];
+ mtr[2*4+0]=obmat[0][2]; mtr[2*4+1]=obmat[1][2]; mtr[2*4+2]=obmat[2][2]; mtr[2*4+3]=obmat[3][2];
+ mtr[3*4+0]=obmat[0][3]; mtr[3*4+1]=obmat[1][3]; mtr[3*4+2]=obmat[2][3]; mtr[3*4+3]=obmat[3][3];
+ yafrayGate->transformPush(mtr);
+
+ VlakRen* face0 = VLR_list[0];
+ Material* face0mat = face0->mat;
+
+ bool castShadows = face0mat->mode & MA_TRACEBLE;
+ float caus_IOR=1.0;
+ yafray::color_t caus_tcolor(0.0, 0.0, 0.0), caus_rcolor(0.0, 0.0, 0.0);
+ bool caus = (((face0->mat->mode & MA_RAYTRANSP) | (face0->mat->mode & MA_RAYMIRROR))!=0);
+ if (caus) {
+ caus_IOR = face0mat->ang;
+ float tr = 1.0-face0mat->alpha;
+ caus_tcolor.set(face0mat->r*tr, face0mat->g*tr, face0mat->b*tr);
+ tr = face0mat->ray_mirror;
+ caus_rcolor.set(face0mat->mirr*tr, face0mat->mirg*tr, face0mat->mirb*tr);
+ }
+
+ // Export orco coords test.
+ // Previously was done by checking orco pointer, however this can be non-null but still not initialized.
+ // Test the rendermaterial texco flag instead.
+ // update2: bug #3193 it seems it has changed again with the introduction of static 'hair' particles,
+ // now it uses the vert pointer again as an extra test to make sure there are orco coords available
+ int has_orco = 0;
+ if (face0mat->texco & TEXCO_STRAND)
+ has_orco = 1;
+ else
+ has_orco = (((face0mat->texco & TEXCO_ORCO)!=0) && (face0->v1->orco!=NULL)) ? 2 : 0;
+
+ bool no_auto = true; //in case non-mesh, or mesh has no autosmooth
+ float sm_angle = 0.1f;
+ if (obj->type==OB_MESH)
+ {
+ Mesh* mesh = (Mesh*)obj->data;
+ if (mesh->flag & ME_AUTOSMOOTH) {
+ sm_angle = mesh->smoothresh;
+ no_auto = false;
+ }
+ }
+ // this for non-mesh as well
+ if (no_auto) {
+ // no per face smooth flag in yafray, if AutoSmooth not used,
+ // use smooth flag of the first face instead
+ if (face0->flag & ME_SMOOTH) sm_angle=180;
+ }
+ vector<yafray::point3d_t> verts;
+ vector<yafray::CFLOAT> vcol;
+ // now all vertices
+ map<VertRen*, int> vert_idx; // for removing duplicate verts and creating an index list
+ int vidx = 0; // vertex index counter
+ bool has_uv=false;
+ for (vector<VlakRen*>::const_iterator fci=VLR_list.begin();
+ fci!=VLR_list.end();++fci)
+ {
+ VlakRen* vlr = *fci;
+ genVertices(verts, vidx, vert_idx, vlr, has_orco, obj);
+ if(RE_vlakren_get_tface(re, vlr, 0, NULL, 0)) has_uv=true;
+ }
+ // all faces using the index list created above
+ vector<int> faces;
+ vector<string> shaders;
+ vector<int> faceshader;
+ vector<yafray::GFLOAT> uvcoords;
+ for (vector<VlakRen*>::const_iterator fci2=VLR_list.begin();
+ fci2!=VLR_list.end();++fci2)
+ {
+ VlakRen* vlr = *fci2;
+ genFace(faces, shaders, faceshader, uvcoords, vcol, vert_idx, vlr, has_orco, has_uv);
+ if (vlr->v4)
+ genCompleFace(faces, faceshader, uvcoords, vcol, vert_idx, vlr, has_orco, has_uv);
+ }
+
+ // using the ObjectRen database, contruct a new name if object has a parent.
+ // This is done to prevent name clashes (group/library link related)
+ string obname(obj->id.name);
+ // previous implementation, keep around, in case this is still useful
+ //if (obj->id.flag & (LIB_EXTERN|LIB_INDIRECT))obname = "lib_" + obname;
+ ObjectRen *obren;
+ for (obren = static_cast<ObjectRen*>(re->objecttable.first);
+ obren; obren=static_cast<ObjectRen*>(obren->next))
+ {
+ Object *db_ob = obren->ob, *db_par = obren->par;
+ if (db_ob==obj)
+ if ((db_ob!=NULL) && (db_par!=NULL)) {
+ obname += "_" + string(db_par->id.name);
+ break;
+ }
+ }
+
+ yafrayGate->addObject_trimesh(obname, verts, faces, uvcoords, vcol,
+ shaders, faceshader, sm_angle, castShadows, true, true, caus, has_orco,
+ caus_rcolor, caus_tcolor, caus_IOR);
+ yafrayGate->transformPop();
+}
+
+
+// write all objects
+void yafrayPluginRender_t::writeAllObjects()
+{
+
+ // first all objects except dupliverts (and main instance object for dups)
+ for (map<Object*, vector<VlakRen*> >::const_iterator obi=all_objects.begin();
+ obi!=all_objects.end(); ++obi)
+ {
+ // skip main duplivert object if in dupliMtx_list, written later
+ Object* obj = obi->first;
+ if (dupliMtx_list.find(string(obj->id.name))!=dupliMtx_list.end()) continue;
+ writeObject(obj, obi->second, obj->obmat);
+ }
+
+ // Now all duplivert objects (if any) as instances of main object
+ // The original object has been included in the VlakRen renderlist above (see convertBlenderScene.c)
+ // but is written here which all other duplis are instances of.
+ float obmat[4][4], cmat[4][4], imat[4][4], nmat[4][4];
+ for (map<string, vector<float> >::const_iterator dupMtx=dupliMtx_list.begin();
+ dupMtx!=dupliMtx_list.end();++dupMtx) {
+
+ // original inverse matrix, not actual matrix of object, but first duplivert.
+ for (int i=0;i<4;i++)
+ for (int j=0;j<4;j++)
+ obmat[i][j] = dupMtx->second[(i<<2)+j];
+ MTC_Mat4Invert(imat, obmat);
+
+ // first object written as normal (but with transform of first duplivert)
+ Object* obj = dup_srcob[dupMtx->first];
+ writeObject(obj, all_objects[obj], obmat);
+
+ // all others instances of first
+ for (unsigned int curmtx=16;curmtx<dupMtx->second.size();curmtx+=16)
+ { // number of 4x4 matrices
+ // new mtx
+ for (int i=0;i<4;i++)
+ for (int j=0;j<4;j++)
+ nmat[i][j] = dupMtx->second[curmtx+(i<<2)+j];
+
+ MTC_Mat4MulMat4(cmat, imat, nmat); // transform with respect to original = inverse_original * new
+
+ float mtr[4*4];
+ mtr[0*4+0]=cmat[0][0]; mtr[0*4+1]=cmat[1][0]; mtr[0*4+2]=cmat[2][0]; mtr[0*4+3]=cmat[3][0];
+ mtr[1*4+0]=cmat[0][1]; mtr[1*4+1]=cmat[1][1]; mtr[1*4+2]=cmat[2][1]; mtr[1*4+3]=cmat[3][1];
+ mtr[2*4+0]=cmat[0][2]; mtr[2*4+1]=cmat[1][2]; mtr[2*4+2]=cmat[2][2]; mtr[2*4+3]=cmat[3][2];
+ mtr[3*4+0]=cmat[0][3]; mtr[3*4+1]=cmat[1][3]; mtr[3*4+2]=cmat[2][3]; mtr[3*4+3]=cmat[3][3];
+ yafrayGate->transformPush(mtr);
+
+ // new name from original
+ string name=(obj->id.name);
+ char temp[16];
+ sprintf(temp,"_dup%d",(curmtx>>4));
+ name+=temp;
+ yafrayGate->addObject_reference(name,obj->id.name);
+ yafrayGate->transformPop();
+ }
+
+ }
+
+}
+
+void yafrayPluginRender_t::writeAreaLamp(LampRen* lamp, int num, float iview[4][4])
+{
+ yafray::paramMap_t params;
+
+ if (lamp->area_shape!=LA_AREA_SQUARE) return;
+ float *a=lamp->area[0], *b=lamp->area[1], *c=lamp->area[2], *d=lamp->area[3];
+ float power=lamp->energy;
+
+ string md = "off";
+ // if no GI used, the GIphotons flag can still be set, so only use when 'full' selected
+ if ((re->r.GImethod==2) && (re->r.GIphotons)) { md="on"; power*=re->r.GIpower; }
+ params["type"]=yafray::parameter_t("arealight");
+ char temp[16];
+ sprintf(temp,"LAMP%d",num+1);
+ params["name"]=yafray::parameter_t(temp);
+ params["dummy"]=yafray::parameter_t(md);
+ params["power"]=yafray::parameter_t(power);
+ // samples not used for GI with photons, can still be exported, is ignored
+ int psm=0, sm = lamp->ray_totsamp;
+ if (sm>=25) psm = sm/5;
+ params["samples"]=yafray::parameter_t(sm);
+ params["psamples"]=yafray::parameter_t(psm);
+
+ // transform area lamp coords back to world
+ float lpco[4][3];
+ MTC_cp3Float(a, lpco[0]);
+ MTC_Mat4MulVecfl(iview, lpco[0]);
+ MTC_cp3Float(b, lpco[1]);
+ MTC_Mat4MulVecfl(iview, lpco[1]);
+ MTC_cp3Float(c, lpco[2]);
+ MTC_Mat4MulVecfl(iview, lpco[2]);
+ MTC_cp3Float(d, lpco[3]);
+ MTC_Mat4MulVecfl(iview, lpco[3]);
+ params["a"] = yafray::parameter_t(yafray::point3d_t(lpco[0][0], lpco[0][1], lpco[0][2]));
+ params["b"] = yafray::parameter_t(yafray::point3d_t(lpco[1][0], lpco[1][1], lpco[1][2]));
+ params["c"] = yafray::parameter_t(yafray::point3d_t(lpco[2][0], lpco[2][1], lpco[2][2]));
+ params["d"] = yafray::parameter_t(yafray::point3d_t(lpco[3][0], lpco[3][1], lpco[3][2]));
+
+ params["color"]=yafray::parameter_t(yafray::color_t(lamp->r,lamp->g,lamp->b));
+ yafrayGate->addLight(params);
+}
+
+void yafrayPluginRender_t::writeLamps()
+{
+ GroupObject *go;
+ int i=0;
+
+ // inver viewmatrix needed for back2world transform
+ float iview[4][4];
+ // re->viewinv != inv.re->viewmat because of possible ortho mode (see convertBlenderScene.c)
+ // have to invert it here
+ MTC_Mat4Invert(iview, re->viewmat);
+
+ // all lamps
+ for(go=(GroupObject *)re->lights.first; go; go= go->next, i++)
+ {
+ LampRen* lamp = (LampRen *)go->lampren;
+
+ yafray::paramMap_t params;
+ string type="";
+
+ if (lamp->type==LA_AREA) { writeAreaLamp(lamp, i, iview); continue; }
+
+ // TODO: add decay setting in yafray
+ bool is_softL=false, is_sphereL=false;
+ if (lamp->type==LA_LOCAL) {
+ if (lamp->mode & LA_YF_SOFT) {
+ // shadowmapped omnidirectional light
+ params["type"] = yafray::parameter_t("softlight");
+ is_softL = true;
+ }
+ else if ((lamp->mode & LA_SHAD_RAY) && (lamp->YF_ltradius>0.0)) {
+ // area sphere, only when ray shadows enabled and radius>0.0
+ params["type"] = yafray::parameter_t("spherelight");
+ is_sphereL = true;
+ }
+ else params["type"] = yafray::parameter_t("pointlight");
+ params["glow_intensity"] = yafray::parameter_t(lamp->YF_glowint);
+ params["glow_offset"] = yafray::parameter_t(lamp->YF_glowofs);
+ params["glow_type"] = yafray::parameter_t(lamp->YF_glowtype);
+ }
+ else if (lamp->type==LA_SPOT)
+ params["type"] = yafray::parameter_t("spotlight");
+ else if ((lamp->type==LA_SUN) || (lamp->type==LA_HEMI)) // hemi exported as sun
+ params["type"] = yafray::parameter_t("sunlight");
+ else if (lamp->type==LA_YF_PHOTON)
+ params["type"] = yafray::parameter_t("photonlight");
+ else {
+ // possibly unknown type, ignore
+ cout << "Unknown Blender lamp type: " << lamp->type << endl;
+ continue;
+ }
+
+ //no name available here, create one
+ char temp[16];
+ sprintf(temp,"LAMP%d",i+1);
+ params["name"] = yafray::parameter_t(temp);
+
+ // color already premultiplied by energy, so only need distance here
+ float pwr = 1; // default for sun/hemi, distance irrelevant
+ if ((lamp->type!=LA_SUN) && (lamp->type!=LA_HEMI)) {
+ if (lamp->mode & LA_SPHERE) {
+ // best approx. as used in LFexport script (LF d.f.m. 4pi?)
+ pwr = lamp->dist*(lamp->dist+1)*(0.25/M_PI);
+ //decay = 2;
+ }
+ else {
+ pwr = lamp->dist;
+ //decay = 1;
+ }
+ }
+
+ if (is_sphereL) {
+ // 'dummy' mode for spherelight when used with gpm
+ string md = "off";
+ // if no GI used, the GIphotons flag can still be set, so only use when 'full' selected
+ if ((re->r.GImethod==2) && (re->r.GIphotons)) { md="on"; pwr*=re->r.GIpower; }
+ params["power"] = yafray::parameter_t(pwr);
+ params["dummy"] = yafray::parameter_t(md);
+ }
+ else params["power"] = yafray::parameter_t(pwr);
+
+ // cast_shadows flag not used with softlight, spherelight or photonlight
+ if ((!is_softL) && (!is_sphereL) && (lamp->type!=LA_YF_PHOTON)) {
+ string lpmode="off";
+ // Blender hemilights exported as sunlights which might have shadow flag set
+ // should have cast_shadows set to off (reported by varuag)
+ if (lamp->type!=LA_HEMI) {
+ if (re->r.mode & R_SHADOW) {
+ // old bug was here since the yafray lamp settings panel was added,
+ // blender spotlight shadbuf flag should be ignored, since it is not in the panel anymore
+ if (lamp->mode & LA_SHAD_RAY) lpmode="on";
+ }
+ }
+ params["cast_shadows"] = yafray::parameter_t(lpmode);
+ }
+
+ // spot specific stuff
+ bool has_halo = ((lamp->type==LA_SPOT) && (lamp->mode & LA_HALO) && (lamp->haint>0.0));
+ if (lamp->type==LA_SPOT) {
+ // conversion already changed spotsize to cosine of half angle
+ float ld = 1-lamp->spotsi; //convert back to blender slider setting
+ if (ld!=0) ld = 1.f/ld;
+ params["size"] = yafray::parameter_t(acos(lamp->spotsi)*180.0/M_PI);
+ params["blend"] = yafray::parameter_t(lamp->spotbl*ld);
+ params["beam_falloff"] = yafray::parameter_t(2.0);
+ // halo params
+ if (has_halo) {
+ params["halo"] = yafray::parameter_t("on");
+ params["res"] = yafray::parameter_t(lamp->YF_bufsize);
+ int hsmp = ((12-lamp->shadhalostep)*16)/12;
+ hsmp = (hsmp+1)*16; // makes range (16, 272) for halostep(12, 0), good enough?
+ // halo 'samples' now 'stepsize'
+ // convert from old integer samples value to some reasonable stepsize
+ params["stepsize"] = yafray::parameter_t(1.0/sqrt((float)hsmp));
+ params["shadow_samples"] = yafray::parameter_t(lamp->samp*lamp->samp);
+ params["halo_blur"] = yafray::parameter_t(0.0);
+ params["shadow_blur"] = yafray::parameter_t(lamp->soft*0.01f);
+ params["fog_density"] = yafray::parameter_t(lamp->haint*0.2f);
+ }
+ }
+ else if (is_softL) {
+ // softlight
+ params["res"] = yafray::parameter_t(lamp->YF_bufsize);
+ params["radius"] = yafray::parameter_t(lamp->soft);
+ params["bias"] = yafray::parameter_t(lamp->bias);
+ }
+ else if (is_sphereL) {
+ // spherelight
+ int psm=0, sm = lamp->ray_samp*lamp->ray_samp;
+ if (sm>=25) psm = sm/5;
+ params["radius"] = yafray::parameter_t(lamp->YF_ltradius);
+ params["samples"] = yafray::parameter_t(sm);
+ params["psamples"] = yafray::parameter_t(psm);
+ params["qmc_method"] = yafray::parameter_t(1);
+ }
+ else if (lamp->type==LA_YF_PHOTON) {
+ string qmc="off";
+ if (lamp->YF_useqmc) qmc="on";
+ params["photons"] = yafray::parameter_t(lamp->YF_numphotons);
+ params["search"] = yafray::parameter_t(lamp->YF_numsearch);
+ params["depth"] = yafray::parameter_t(lamp->YF_phdepth);
+ params["use_QMC"] = yafray::parameter_t(qmc);
+ params["angle"] = yafray::parameter_t(acos(lamp->spotsi)*180.0/M_PI);
+ float cl = lamp->YF_causticblur/sqrt((float)lamp->YF_numsearch);
+ params["fixedradius"] = yafray::parameter_t(lamp->YF_causticblur);
+ params["cluster"] = yafray::parameter_t(cl);
+ }
+
+ // transform lamp co & vec back to world
+ float lpco[3], lpvec[3];
+ MTC_cp3Float(lamp->co, lpco);
+ MTC_Mat4MulVecfl(iview, lpco);
+ MTC_cp3Float(lamp->vec, lpvec);
+ MTC_Mat4Mul3Vecfl(iview, lpvec);
+
+ // position, (==-blendir for sun/hemi)
+ if ((lamp->type==LA_SUN) || (lamp->type==LA_HEMI))
+ params["from"] = yafray::parameter_t(yafray::point3d_t(-lpvec[0], -lpvec[1], -lpvec[2]));
+ else
+ params["from"] = yafray::parameter_t(yafray::point3d_t(lpco[0], lpco[1], lpco[2]));
+ // 'to' for spot/photonlight, already calculated by Blender
+ if ((lamp->type==LA_SPOT) || (lamp->type==LA_YF_PHOTON)) {
+ params["to"] = yafray::parameter_t(yafray::point3d_t(lpco[0] + lpvec[0],
+ lpco[1] + lpvec[1],
+ lpco[2] + lpvec[2]));
+ if (has_halo) params["fog"] = yafray::parameter_t(yafray::color_t(1.0, 1.0, 1.0));
+ }
+
+ // color
+ // rgb in LampRen is premultiplied by energy, power is compensated for that above
+ params["color"] = yafray::parameter_t(yafray::color_t(lamp->r, lamp->g, lamp->b));
+ yafrayGate->addLight(params);
+ }
+}
+
+// write main camera
+void yafrayPluginRender_t::writeCamera()
+{
+ yafray::paramMap_t params;
+ params["name"]=yafray::parameter_t("MAINCAM");
+ if (re->r.mode & R_ORTHO)
+ params["type"] = yafray::parameter_t("ortho");
+ else
+ params["type"] = yafray::parameter_t("perspective");
+
+ params["resx"] = yafray::parameter_t(re->winx);
+ params["resy"] = yafray::parameter_t(re->winy);
+
+ float f_aspect = 1;
+ if ((re->winx * re->r.xasp) <= (re->winy * re->r.yasp))
+ f_aspect = float(re->winx * re->r.xasp) / float(re->winy * re->r.yasp);
+ params["focal"] = yafray::parameter_t(mainCamLens/(f_aspect*32.f));
+ // bug #4532, when field rendering is enabled, ycor is doubled
+ if (re->r.mode & R_FIELDS)
+ params["aspect_ratio"] = yafray::parameter_t(re->ycor * 0.5f);
+ else
+ params["aspect_ratio"] = yafray::parameter_t(re->ycor);
+
+ // dof params, only valid for real camera
+ float fdist = 1; // only changes for ortho
+ if (maincam_obj->type==OB_CAMERA) {
+ Camera* cam = (Camera*)maincam_obj->data;
+ if (re->r.mode & R_ORTHO) fdist = cam->ortho_scale*(mainCamLens/32.f);
+ params["dof_distance"] = yafray::parameter_t(cam->YF_dofdist);
+ params["aperture"] = yafray::parameter_t(cam->YF_aperture);
+ if (cam->flag & CAM_YF_NO_QMC)
+ params["use_qmc"] = yafray::parameter_t("off");
+ else
+ params["use_qmc"] = yafray::parameter_t("on");
+ // bokeh params
+ string st = "disk1";
+ if (cam->YF_bkhtype==1)
+ st = "disk2";
+ else if (cam->YF_bkhtype==2)
+ st = "triangle";
+ else if (cam->YF_bkhtype==3)
+ st = "square";
+ else if (cam->YF_bkhtype==4)
+ st = "pentagon";
+ else if (cam->YF_bkhtype==5)
+ st = "hexagon";
+ else if (cam->YF_bkhtype==6)
+ st = "ring";
+ params["bokeh_type"] = yafray::parameter_t(st);
+ st = "uniform";
+ if (cam->YF_bkhbias==1)
+ st = "center";
+ else if (cam->YF_bkhbias==2)
+ st = "edge";
+ params["bokeh_bias"] = yafray::parameter_t(st);
+ params["bokeh_rotation"] = yafray::parameter_t(cam->YF_bkhrot);
+ }
+
+ params["from"]=yafray::parameter_t(
+ yafray::point3d_t(maincam_obj->obmat[3][0], maincam_obj->obmat[3][1], maincam_obj->obmat[3][2]));
+ params["to"]=yafray::parameter_t(
+ yafray::point3d_t(maincam_obj->obmat[3][0] - fdist * re->viewmat[0][2],
+ maincam_obj->obmat[3][1] - fdist * re->viewmat[1][2],
+ maincam_obj->obmat[3][2] - fdist * re->viewmat[2][2]));
+ params["up"]=yafray::parameter_t(
+ yafray::point3d_t(maincam_obj->obmat[3][0] + re->viewmat[0][1],
+ maincam_obj->obmat[3][1] + re->viewmat[1][1],
+ maincam_obj->obmat[3][2] + re->viewmat[2][1]));
+
+ yafrayGate->addCamera(params);
+}
+
+void yafrayPluginRender_t::writeHemilight()
+{
+ yafray::paramMap_t params;
+ World *world = G.scene->world;
+ bool fromAO = false;
+ if (re->r.GIquality==6){
+ // use Blender AO params is possible
+ if (world==NULL) return;
+ if ((world->mode & WO_AMB_OCC)==0) {
+ // no AO, use default GIquality
+ cout << "[Warning]: Can't use AO parameters\nNo ambient occlusion enabled, using default values instead" << endl;
+ }
+ else fromAO = true;
+ }
+ if (re->r.GIcache) {
+ params["type"] = yafray::parameter_t("pathlight");
+ params["name"] = yafray::parameter_t("path_LT");
+ params["power"] = yafray::parameter_t(re->r.GIpower);
+ params["mode"] = yafray::parameter_t("occlusion");
+ params["ignore_bumpnormals"] = yafray::parameter_t(re->r.YF_nobump ? "on" : "off");
+ if (fromAO) {
+ // for AO, with cache, using range of 32*1 to 32*16 seems good enough
+ params["samples"] = yafray::parameter_t(32*world->aosamp);
+ params["maxdistance"] = yafray::parameter_t(world->aodist);
+ }
+ else {
+ switch (re->r.GIquality)
+ {
+ case 1 : params["samples"] = yafray::parameter_t(128); break;
+ case 2 : params["samples"] = yafray::parameter_t(256); break;
+ case 3 : params["samples"] = yafray::parameter_t(512); break;
+ case 4 : params["samples"] = yafray::parameter_t(1024); break;
+ case 5 : params["samples"] = yafray::parameter_t(2048); break;
+ default: params["samples"] = yafray::parameter_t(256);
+ }
+ }
+ params["cache"] = yafray::parameter_t("on");
+ params["use_QMC"] = yafray::parameter_t("on");
+ params["threshold"] = yafray::parameter_t(re->r.GIrefinement);
+ params["cache_size"] = yafray::parameter_t((2.0/float(re->winx))*re->r.GIpixelspersample);
+ params["shadow_threshold"] = yafray::parameter_t(1.0 - re->r.GIshadowquality);
+ params["grid"] = yafray::parameter_t(82);
+ params["search"] = yafray::parameter_t(35);
+ }
+ else {
+ params["type"] = yafray::parameter_t("hemilight");
+ params["name"] = yafray::parameter_t("hemi_LT");
+ params["power"] = yafray::parameter_t(re->r.GIpower);
+ if (fromAO) {
+ // use minimum of 4 samples for lowest sample setting, single sample way too noisy
+ params["samples"] = yafray::parameter_t(3 + world->aosamp*world->aosamp);
+ params["maxdistance"] = yafray::parameter_t(world->aodist);
+ params["use_QMC"] = yafray::parameter_t((world->aomode & WO_AORNDSMP) ? "off" : "on");
+ }
+ else {
+ switch (re->r.GIquality)
+ {
+ case 1 :
+ case 2 : params["samples"]=yafray::parameter_t(16); break;
+ case 3 : params["samples"]=yafray::parameter_t(36); break;
+ case 4 : params["samples"]=yafray::parameter_t(64); break;
+ case 5 : params["samples"]=yafray::parameter_t(128); break;
+ default: params["samples"]=yafray::parameter_t(25);
+ }
+ }
+ }
+ yafrayGate->addLight(params);
+}
+
+void yafrayPluginRender_t::writePathlight()
+{
+ if (re->r.GIphotons)
+ {
+ yafray::paramMap_t params;
+ params["type"] = yafray::parameter_t("globalphotonlight");
+ params["name"] = yafray::parameter_t("gpm");
+ params["photons"] = yafray::parameter_t(re->r.GIphotoncount);
+ params["radius"] = yafray::parameter_t(re->r.GIphotonradius);
+ params["depth"] = yafray::parameter_t(((re->r.GIdepth>2) ? (re->r.GIdepth-1) : 1));
+ params["caus_depth"] = yafray::parameter_t(re->r.GIcausdepth);
+ params["search"] = yafray::parameter_t(re->r.GImixphotons);
+ yafrayGate->addLight(params);
+ }
+ yafray::paramMap_t params;
+ params["type"] = yafray::parameter_t("pathlight");
+ params["name"] = yafray::parameter_t("path_LT");
+ params["power"] = yafray::parameter_t(re->r.GIindirpower);
+ params["depth"] = yafray::parameter_t(((re->r.GIphotons) ? 1 : re->r.GIdepth));
+ params["caus_depth"] = yafray::parameter_t(re->r.GIcausdepth);
+ if (re->r.GIdirect && re->r.GIphotons) params["direct"] = yafray::parameter_t("on");
+ if (re->r.GIcache && !(re->r.GIdirect && re->r.GIphotons))
+ {
+ switch (re->r.GIquality)
+ {
+ case 1 : params["samples"] = yafray::parameter_t(128); break;
+ case 2 : params["samples"] = yafray::parameter_t(256); break;
+ case 3 : params["samples"] = yafray::parameter_t(512); break;
+ case 4 : params["samples"] = yafray::parameter_t(1024); break;
+ case 5 : params["samples"] = yafray::parameter_t(2048); break;
+ default: params["samples"] = yafray::parameter_t(256);
+ }
+ params["cache"] = yafray::parameter_t("on");
+ params["use_QMC"] = yafray::parameter_t("on");
+ params["threshold"] = yafray::parameter_t(re->r.GIrefinement);
+ params["cache_size"] = yafray::parameter_t((2.0/float(re->recty))*re->r.GIpixelspersample);
+ params["shadow_threshold"] = yafray::parameter_t(1.0 - re->r.GIshadowquality);
+ params["grid"] = yafray::parameter_t(82);
+ params["search"] = yafray::parameter_t(35);
+ params["ignore_bumpnormals"] = yafray::parameter_t(re->r.YF_nobump ? "on" : "off");
+ }
+ else
+ {
+ switch (re->r.GIquality)
+ {
+ case 1 : params["samples"] = yafray::parameter_t(16); break;
+ case 2 : params["samples"] = yafray::parameter_t(36); break;
+ case 3 : params["samples"] = yafray::parameter_t(64); break;
+ case 4 : params["samples"] = yafray::parameter_t(128); break;
+ case 5 : params["samples"] = yafray::parameter_t(256); break;
+ default: params["samples"] = yafray::parameter_t(25);
+ }
+ }
+ yafrayGate->addLight(params);
+}
+
+bool yafrayPluginRender_t::writeWorld()
+{
+ World *world = G.scene->world;
+ if (re->r.GIquality!=0) {
+ if (re->r.GImethod==1) {
+ if (world==NULL) cout << "WARNING: need world background for skydome!\n";
+ writeHemilight();
+ }
+ else if (re->r.GImethod==2) writePathlight();
+ }
+ if (world==NULL) return false;
+
+ yafray::paramMap_t params;
+ for (int i=0;i<MAX_MTEX;i++) {
+ MTex* wtex = world->mtex[i];
+ if (!wtex) continue;
+ Image* wimg = wtex->tex->ima;
+ // now always exports if image used as world texture (and 'Hori' mapping enabled)
+ if ((wtex->tex->type==TEX_IMAGE) && (wimg!=NULL) && (wtex->mapto & WOMAP_HORIZ)) {
+ string wt_path = wimg->name;
+ adjustPath(wt_path);
+ params["type"] = yafray::parameter_t("image");
+ params["name"] = yafray::parameter_t("world_background");
+ // exposure_adjust not restricted to integer range anymore
+ params["exposure_adjust"] = yafray::parameter_t(wtex->tex->bright-1.f);
+ if (wtex->texco & TEXCO_ANGMAP)
+ params["mapping"] = yafray::parameter_t("probe");
+ else if (wtex->texco & TEXCO_H_SPHEREMAP) // in yafray full sphere
+ params["mapping"] = yafray::parameter_t("sphere");
+ else // assume 'tube' for anything else
+ params["mapping"] = yafray::parameter_t("tube");
+ params["filename"] = yafray::parameter_t(wt_path);
+ params["interpolate"] = yafray::parameter_t((wtex->tex->imaflag & TEX_INTERPOL) ? "bilinear" : "none");
+ if (wtex->tex->filtersize>1.f) params["prefilter"] = yafray::parameter_t("on");
+ yafrayGate->addBackground(params);
+ return true;
+ }
+ }
+
+ params.clear();
+ params["type"] = yafray::parameter_t("constant");
+ params["name"] = yafray::parameter_t("world_background");
+ // if no GI used, the GIpower parameter is not always initialized, so in that case ignore it
+ // (have to change method to init yafray vars in Blender)
+ float bg_mult = (re->r.GImethod==0) ? 1 : re->r.GIpower;
+ params["color"]=yafray::parameter_t(yafray::color_t(world->horr * bg_mult,
+ world->horg * bg_mult,
+ world->horb * bg_mult));
+ yafrayGate->addBackground(params);
+ return true;
+}
+
+bool blenderYafrayOutput_t::putPixel(int x, int y, const yafray::color_t &c,
+ yafray::CFLOAT alpha, yafray::PFLOAT depth)
+{
+ // XXX how to get the image from Blender and write to it. This call doesn't allow to change buffer rects
+ RenderResult rres;
+ RE_GetResultImage(re, &rres);
+ // rres.rectx, rres.recty is width/height
+ // rres.rectf is float buffer, scanlines starting in bottom
+ // rres.rectz is zbuffer, available when associated pass is set
+
+ const unsigned int maxy = rres.recty-1;
+
+ if (re->r.mode & R_BORDER) {
+ // border render, blender renderwin is size of border region,
+ // but yafray returns coords relative to full resolution
+ x -= int(re->r.border.xmin * re->winx);
+ y -= int((1.f-re->r.border.ymax) * re->winy);
+ if ((x >= 0) && (x < re->rectx) && (y >= 0) && (y < re->recty))
+ {
+ const unsigned int px = rres.rectx*(maxy - y);
+ // rgba
+ float* fpt = rres.rectf + ((px + x) << 2);
+ *fpt++ = c.R;
+ *fpt++ = c.G;
+ *fpt++ = c.B;
+ *fpt = alpha;
+ // depth values
+ if (rres.rectz) rres.rectz[px + x] = depth;
+ // to simplify things a bit, just do complete redraw here...
+ out++;
+ if ((out==4096) || ((x+y*re->rectx) == ((re->rectx-1)+(re->recty-1)*re->rectx))) {
+ re->result->renlay = render_get_active_layer(re, re->result);
+ re->display_draw(re->result, NULL);
+ out = 0;
+ }
+ }
+ if (re->test_break()) return false;
+ return true;
+ }
+
+ const unsigned int px = (maxy - y)*rres.rectx;
+
+ // rgba
+ float* fpt = rres.rectf + ((px + x) << 2);
+ *fpt++ = c.R;
+ *fpt++ = c.G;
+ *fpt++ = c.B;
+ *fpt = alpha;
+
+ // depth values
+ if (rres.rectz) rres.rectz[px + x] = depth;
+
+ // attempt to optimize drawing, by only drawing the tile currently rendered by yafray,
+ // and not the entire display every time (blender has to to do float->char conversion),
+ // but since the tile is not actually known, it has to be calculated from the coords.
+ // not sure if it really makes all that much difference at all... unless rendering really large pictures
+ // (renderwin.c also had to be adapted for this)
+ // tile start & end coords
+ const int txs = x & 0xffffffc0, tys = y & 0xffffffc0;
+ int txe = txs + 63, tye = tys + 63;
+ // tile border clip
+ if (txe >= rres.rectx) txe = rres.rectx-1;
+ if (tye >= rres.recty) tye = maxy;
+ // draw tile if last pixel reached
+ if ((y*rres.rectx + x) == (tye*rres.rectx + txe)) {
+ re->result->renlay = render_get_active_layer(re, re->result);
+ // note: ymin/ymax swapped here, img. upside down!
+ rcti rt = {txs, txe+1, maxy-tye, ((tys==0) ? maxy : (rres.recty-tys))}; // !!! tys can be zero
+ re->display_draw(re->result, &rt);
+ }
+
+ if (re->test_break()) return false;
+ return true;
+}
diff --git a/source/blender/yafray/intern/export_Plugin.h b/source/blender/yafray/intern/export_Plugin.h
new file mode 100644
index 00000000000..1ce4988a260
--- /dev/null
+++ b/source/blender/yafray/intern/export_Plugin.h
@@ -0,0 +1,78 @@
+#ifndef __EXPORT_PLUGIN_H
+#define __EXPORT_PLUGIN_H
+
+#include"yafray_Render.h"
+#include"yafexternal.h"
+extern "C"
+{
+#include"PIL_dynlib.h"
+}
+
+class yafrayPluginRender_t : public yafrayRender_t
+{
+ public:
+ yafrayPluginRender_t()
+ {
+ plugin_loaded = false;
+ handle=NULL;
+#ifdef WIN32
+ corehandle=NULL;
+#endif
+ yafrayGate=NULL;
+ }
+ virtual ~yafrayPluginRender_t();
+ protected:
+ bool plugin_loaded;
+ std::string imgout;
+ PILdynlib *handle;
+#ifdef WIN32
+ PILdynlib *corehandle;
+#endif
+
+ yafray::yafrayInterface_t *yafrayGate;
+
+ void displayImage();
+ virtual void writeTextures();
+ virtual void writeShader(const std::string &shader_name, Material* matr, const std::string &facetexname="");
+ virtual void writeMaterialsAndModulators();
+ virtual void writeObject(Object* obj,
+ const std::vector<VlakRen*> &VLR_list, const float obmat[4][4]);
+ virtual void writeAllObjects();
+ virtual void writeAreaLamp(LampRen* lamp, int num, float iview[4][4]);
+ virtual void writeLamps();
+ virtual void writeCamera();
+ virtual void writeHemilight();
+ virtual void writePathlight();
+ virtual bool writeWorld();
+ virtual bool writeRender();
+ virtual bool initExport();
+ virtual bool finishExport();
+
+ void genUVcoords(std::vector<yafray::GFLOAT> &uvcoords,VlakRen *vlr,MTFace* uvc, bool comple=false);
+ void genVcol(std::vector<yafray::CFLOAT> &vcol, VlakRen *vlr, bool comple=false);
+ void genFace(std::vector<int> &faces,std::vector<std::string> &shaders,std::vector<int> &faceshader,
+ std::vector<yafray::GFLOAT> &uvcoords,std::vector<yafray::CFLOAT> &vcol,
+ std::map<VertRen*, int> &vert_idx,VlakRen *vlr,
+ int has_orco,bool has_uv);
+ void genCompleFace(std::vector<int> &faces,/*std::vector<std::string> &shaders,*/std::vector<int> &faceshader,
+ std::vector<yafray::GFLOAT> &uvcoords,std::vector<yafray::CFLOAT> &vcol,
+ std::map<VertRen*, int> &vert_idx,VlakRen *vlr,
+ int has_orco,bool has_uv);
+ void genVertices(std::vector<yafray::point3d_t> &verts, int &vidx,
+ std::map<VertRen*, int> &vert_idx, VlakRen* vlr, int has_orco, Object* obj);
+};
+
+class blenderYafrayOutput_t : public yafray::colorOutput_t
+{
+ public:
+ blenderYafrayOutput_t(Render* re):out(0) { this->re = re; }
+ virtual ~blenderYafrayOutput_t() {}
+ virtual bool putPixel(int x, int y, const yafray::color_t &c,
+ yafray::CFLOAT alpha=0, yafray::PFLOAT depth=0);
+ virtual void flush() {}
+ protected:
+ Render* re;
+ int out;
+};
+
+#endif
diff --git a/source/blender/yafray/intern/yafexternal.cpp b/source/blender/yafray/intern/yafexternal.cpp
new file mode 100644
index 00000000000..97d43cbaf5a
--- /dev/null
+++ b/source/blender/yafray/intern/yafexternal.cpp
@@ -0,0 +1,155 @@
+#include "yafexternal.h"
+#include <iostream>
+namespace yafray {
+
+parameter_t::parameter_t(const std::string &s):type(TYPE_STRING),used(false),str(s)
+{
+}
+
+parameter_t::parameter_t(float f):type(TYPE_FLOAT),used(false),fnum(f)
+{
+}
+
+parameter_t::parameter_t(const colorA_t &c):type(TYPE_COLOR),used(false)
+ ,C(c)
+{
+}
+
+parameter_t::parameter_t(const point3d_t &p):type(TYPE_POINT),used(false),P(p)
+{
+}
+
+parameter_t::parameter_t():type(TYPE_NONE),used(false)
+{
+}
+
+parameter_t::~parameter_t()
+{
+}
+
+paramMap_t::paramMap_t()
+{
+}
+
+paramMap_t::~paramMap_t()
+{
+}
+
+bool paramMap_t::getParam(const std::string &name,const std::string *&s)
+{
+ if(includes(name,TYPE_STRING))
+ {
+ std::map<std::string,parameter_t>::iterator i=dicc.find(name);
+ s=&(i->second.getStr());
+ }
+ else return false;
+ return true;
+}
+
+bool paramMap_t::getParam(const std::string &name,bool &b)
+{
+ std::string str;
+ if(includes(name,TYPE_STRING))
+ {
+ std::map<std::string,parameter_t>::iterator i=dicc.find(name);
+ str=i->second.getStr();
+ if(str=="on") b=true;
+ else if(str=="off") b=false;
+ else return false;
+ }
+ else return false;
+ return true;
+}
+
+bool paramMap_t::getParam(const std::string &name,float &f)
+{
+ if(includes(name,TYPE_FLOAT))
+ {
+ std::map<std::string,parameter_t>::iterator i=dicc.find(name);
+ f=i->second.getFnum();
+ }
+ else return false;
+ return true;
+}
+
+bool paramMap_t::getParam(const std::string &name,double &f)
+{
+ if(includes(name,TYPE_FLOAT))
+ {
+ std::map<std::string,parameter_t>::iterator i=dicc.find(name);
+ f=i->second.getFnum();
+ }
+ else return false;
+ return true;
+}
+
+bool paramMap_t::getParam(const std::string &name,int &in)
+{
+ if(includes(name,TYPE_FLOAT))
+ {
+ std::map<std::string,parameter_t>::iterator i=dicc.find(name);
+ in=(int)(i->second.getFnum());
+ }
+ else return false;
+ return true;
+}
+
+bool paramMap_t::getParam(const std::string &name,point3d_t &p)
+{
+ if(includes(name,TYPE_POINT))
+ {
+ std::map<std::string,parameter_t>::iterator i=dicc.find(name);
+ p=i->second.getP();
+ }
+ else return false;
+ return true;
+}
+
+bool paramMap_t::getParam(const std::string &name,color_t &c)
+{
+ if(includes(name,TYPE_COLOR))
+ {
+ std::map<std::string,parameter_t>::iterator i=dicc.find(name);
+ c=i->second.getC();
+ }
+ else return false;
+ return true;
+}
+
+bool paramMap_t::getParam(const std::string &name,colorA_t &c)
+{
+ if(includes(name,TYPE_COLOR))
+ {
+ std::map<std::string,parameter_t>::iterator i=dicc.find(name);
+ c=i->second.getAC();
+ }
+ else return false;
+ return true;
+}
+
+bool paramMap_t::includes(const std::string &label,int type)const
+{
+ std::map<std::string,parameter_t>::const_iterator i=dicc.find(label);
+ if(i==dicc.end()) return false;
+ if((*i).second.type!=type) return false;
+ return true;
+}
+
+void paramMap_t::checkUnused(const std::string &env)const
+{
+ for(std::map<std::string,parameter_t>::const_iterator i=dicc.begin();i!=dicc.end();++i)
+ if(!( (*i).second.used ))
+ std::cout<<"[WARNING]:Unused param "<<(*i).first<<" in "<<env<<"\n";
+}
+
+parameter_t & paramMap_t::operator [] (const std::string &key)
+{
+ return dicc[key];
+}
+
+void paramMap_t::clear()
+{
+ dicc.clear();
+}
+
+}
diff --git a/source/blender/yafray/intern/yafexternal.h b/source/blender/yafray/intern/yafexternal.h
new file mode 100644
index 00000000000..7130bd55466
--- /dev/null
+++ b/source/blender/yafray/intern/yafexternal.h
@@ -0,0 +1,186 @@
+#ifndef __YAFINTERFACE_H
+#define __YAFINTERFACE_H
+
+#include<vector>
+#include<string>
+#include<list>
+#include<map>
+
+namespace yafray
+{
+
+typedef float PFLOAT;
+typedef float GFLOAT;
+typedef float CFLOAT;
+
+class point3d_t
+{
+ public:
+ point3d_t() { x = y = z = 0; }
+ point3d_t(PFLOAT ix) { x = y = z = ix; }
+ point3d_t(PFLOAT ix, PFLOAT iy, PFLOAT iz=0) { x=ix; y=iy; z=iz; }
+ point3d_t(const point3d_t &s) { x=s.x; y=s.y; z=s.z; }
+ void set(PFLOAT ix, PFLOAT iy, PFLOAT iz=0) { x=ix; y=iy; z=iz; }
+ point3d_t& operator= (const point3d_t &s) { x=s.x; y=s.y; z=s.z; return *this; }
+ ~point3d_t() {};
+ PFLOAT x,y,z;
+};
+
+class color_t
+{
+ public:
+ color_t() {R=G=B=0;};
+ color_t(CFLOAT r,CFLOAT g,CFLOAT b) {R=r;G=g;B=b;};
+ ~color_t() {};
+ void set(CFLOAT r,CFLOAT g,CFLOAT b) {R=r;G=g;B=b;};
+
+ CFLOAT R,G,B;
+};
+
+class colorA_t : public color_t
+{
+ public:
+ colorA_t() { A=1; }
+ colorA_t(const color_t &c):color_t(c) { A=1; }
+ colorA_t(CFLOAT r, CFLOAT g, CFLOAT b, CFLOAT a=0):color_t(r,g,b) {A=a;}
+ ~colorA_t() {};
+ void set(CFLOAT r, CFLOAT g, CFLOAT b, CFLOAT a=0) {color_t::set(r,g,b);A=a; };
+
+ protected:
+ CFLOAT A;
+};
+
+#define TYPE_FLOAT 0
+#define TYPE_STRING 1
+#define TYPE_POINT 2
+#define TYPE_COLOR 3
+#define TYPE_NONE -1
+
+class parameter_t
+{
+ public:
+ parameter_t(const std::string &s);
+ parameter_t(float f);
+ parameter_t(const colorA_t &c);
+ parameter_t(const point3d_t &p);
+ parameter_t();
+ ~parameter_t();
+
+ const std::string &getStr() {used=true;return str;};
+ float &getFnum() {used=true;return fnum;};
+ const point3d_t &getP() {used=true;return P;};
+ const color_t &getC() {used=true;return C;};
+ const colorA_t &getAC() {used=true;return C;};
+ int type;
+ bool used;
+ protected:
+ std::string str;
+ float fnum;
+ point3d_t P;
+ colorA_t C;
+};
+
+class paramMap_t
+{
+ public:
+ paramMap_t();
+ virtual bool getParam(const std::string &name,const std::string *&s);
+ virtual bool getParam(const std::string &name,bool &b);
+ virtual bool getParam(const std::string &name,float &f);
+ virtual bool getParam(const std::string &name,double &f);
+ virtual bool getParam(const std::string &name,int &i);
+ virtual bool getParam(const std::string &name,point3d_t &p);
+ virtual bool getParam(const std::string &name,color_t &c);
+ virtual bool getParam(const std::string &name,colorA_t &c);
+ virtual bool includes(const std::string &label,int type)const;
+ virtual void checkUnused(const std::string &env)const;
+ virtual parameter_t & operator [] (const std::string &key);
+ virtual void clear();
+ virtual ~paramMap_t();
+ protected:
+ std::map<std::string,parameter_t> dicc;
+};
+
+class light_t;
+class shader_t;
+class texture_t;
+class filter_t;
+class background_t;
+
+class renderEnvironment_t
+{
+ public:
+ typedef light_t * light_factory_t(paramMap_t &,renderEnvironment_t &);
+ typedef shader_t *shader_factory_t(paramMap_t &,std::list<paramMap_t> &,
+ renderEnvironment_t &);
+ typedef texture_t *texture_factory_t(paramMap_t &,renderEnvironment_t &);
+ typedef filter_t *filter_factory_t(paramMap_t &,renderEnvironment_t &);
+ typedef background_t *background_factory_t(paramMap_t &,renderEnvironment_t &);
+
+ virtual shader_t *getShader(const std::string name)const=0;
+ virtual texture_t *getTexture(const std::string name)const=0;
+
+ virtual void repeatFirstPass()=0;
+
+ virtual void registerFactory(const std::string &name,light_factory_t *f)=0;
+ virtual void registerFactory(const std::string &name,shader_factory_t *f)=0;
+ virtual void registerFactory(const std::string &name,texture_factory_t *f)=0;
+ virtual void registerFactory(const std::string &name,filter_factory_t *f)=0;
+ virtual void registerFactory(const std::string &name,background_factory_t *f)=0;
+
+ renderEnvironment_t() {};
+ virtual ~renderEnvironment_t() {};
+
+};
+
+class colorOutput_t
+{
+ public:
+ virtual ~colorOutput_t() {};
+ virtual bool putPixel(int x, int y,const color_t &c,
+ CFLOAT alpha=0,PFLOAT depth=0)=0;
+ virtual void flush()=0;
+};
+
+class yafrayInterface_t : public renderEnvironment_t
+{
+ public:
+ virtual void transformPush(float *m)=0;
+ virtual void transformPop()=0;
+ virtual void addObject_trimesh(const std::string &name,
+ std::vector<point3d_t> &verts, const std::vector<int> &faces,
+ std::vector<GFLOAT> &uvcoords, std::vector<CFLOAT> &vcol,
+ const std::vector<std::string> &shaders,const std::vector<int> &faceshader,
+ float sm_angle,bool castShadows,bool useR,bool receiveR,bool caus,bool has_orco,
+ const color_t &caus_rcolor,const color_t &caus_tcolor,float caus_IOR)=0;
+
+ virtual void addObject_reference(const std::string &name,const std::string &original)=0;
+ // lights
+ virtual void addLight(paramMap_t &p)=0;
+ // textures
+ virtual void addTexture(paramMap_t &p)=0;
+ // shaders
+ virtual void addShader(paramMap_t &p,std::list<paramMap_t> &modulators)=0;
+ // filters
+ virtual void addFilter(paramMap_t &p)=0;
+ // backgrounds
+ virtual void addBackground(paramMap_t &p)=0;
+ //camera
+ virtual void addCamera(paramMap_t &p)=0;
+ //render
+ virtual void render(paramMap_t &p)=0;
+ //render
+ virtual void render(paramMap_t &p,colorOutput_t &output)=0;
+
+ virtual void clear()=0;
+
+ virtual ~yafrayInterface_t() {};
+};
+
+typedef yafrayInterface_t * yafrayConstructor(int,const std::string &);
+
+}
+
+#define YAFRAY_SYMBOL "getYafray"
+
+#endif
diff --git a/source/blender/yafray/intern/yafray_Render.cpp b/source/blender/yafray/intern/yafray_Render.cpp
new file mode 100644
index 00000000000..1106e197335
--- /dev/null
+++ b/source/blender/yafray/intern/yafray_Render.cpp
@@ -0,0 +1,219 @@
+//----------------------------------------------------------------------------------------------------
+// YafRay export
+//
+// For anyone else looking at this, this was designed for a tabspacing of 2 (YafRay/Jandro standard :)
+//----------------------------------------------------------------------------------------------------
+
+#include "yafray_Render.h"
+
+#include <math.h>
+
+using namespace std;
+
+void yafrayRender_t::clearAll()
+{
+ all_objects.clear();
+ used_materials.clear();
+ used_textures.clear();
+ dupliMtx_list.clear();
+ dup_srcob.clear();
+ objectData.clear();
+ imagetex.clear();
+ imgtex_shader.clear();
+}
+
+bool yafrayRender_t::exportScene(Render* re)
+{
+ this->re = re;
+
+ // get camera first, no checking should be necessary, all done by Blender
+ maincam_obj = G.scene->camera;
+
+ // use fixed lens for objects functioning as temporary camera (ctrl-0)
+ mainCamLens = 35.0;
+ if (maincam_obj->type==OB_CAMERA) mainCamLens=((Camera*)maincam_obj->data)->lens;
+
+ // recreate the scene as object data, as well as sorting the material & textures, ignoring duplicates
+ if (!getAllMatTexObs())
+ {
+ // error found, clear for next call
+ clearAll();
+ return false;
+ }
+
+ if (!initExport())
+ {
+ G.afbreek = 1;
+ clearAll();
+ return false;
+ }
+
+ // start actual data export
+ writeTextures();
+ writeMaterialsAndModulators();
+ writeAllObjects();
+ writeLamps();
+ hasworld = writeWorld();
+ writeCamera();
+ writeRender();
+
+ // clear for next call, before render to free some memory
+ clearAll();
+
+ if (!finishExport())
+ {
+ G.afbreek = 1; //stop render and anim if doing so
+ return false;
+ }
+ else return true;
+}
+
+// gets all unique face materials & textures,
+// and sorts the facelist rejecting anything that is not a quad or tri,
+// as well as associating them again with the original Object.
+bool yafrayRender_t::getAllMatTexObs()
+{
+ VlakRen* vlr;
+
+ // Blender does not include object which have total 0 alpha materials,
+ // however, the objects might have been included in the dupliMtx list,
+ // so this will cause a 'Duplilist non-empty...' error after going through the renderlist.
+ // To solve this, keep track of all render objects included sofar,
+ // and remove from dupliMtx_list if object not found.
+ // This should also help to solve some other yet undetected 'dupli..' errors,
+ // but on the other hand that could also hide the real problem of course...
+ map<string, Object*> renderobs;
+
+ for (int i=0; i < re->totvlak; i++) {
+
+ if ((i & 255)==0) vlr=re->vlaknodes[i>>8].vlak; else vlr++;
+
+ // ---- The materials & textures
+ // in this case, probably every face has a material assigned, which can be the default material,
+ // so checking that this is !0 is probably not necessary, but just in case...
+ Material* matr = vlr->mat;
+ if (matr) {
+ // The default assigned material seems to be nameless, no MA id, an empty string.
+ // Since this name is needed in yafray, make it 'blender_default'
+ if (strlen(matr->id.name)==0)
+ used_materials["blender_default"] = matr;
+ else
+ used_materials[matr->id.name] = matr;
+ // textures, all active channels
+ for (int m=0;m<MAX_MTEX;m++) {
+ if (matr->septex & (1<<m)) continue; // only active channels
+ MTex* mx = matr->mtex[m];
+ // if no mtex, ignore
+ if (mx==NULL) continue;
+ // if no tex, ignore
+ Tex* tx = mx->tex;
+ if (tx==NULL) continue;
+ short txtp = tx->type;
+ // if texture type not available in yafray, ignore
+ if ((txtp==0) ||
+ (txtp==TEX_MAGIC) ||
+ (txtp==TEX_PLUGIN) ||
+ (txtp==TEX_ENVMAP)) continue;
+ // if texture is stucci, only export if 'nor' enabled
+ if ((txtp==TEX_STUCCI) && !((mx->mapto & MAP_NORM) || (mx->maptoneg & MAP_NORM))) continue;
+ // In the case of an image texture, check that there is an actual image, otherwise ignore.
+ // Stupid error was here (...if (txtp & TEX_IMAGE)...),
+ // which happened to work sofar, but not anymore with the extended texture support..
+ if ((txtp==TEX_IMAGE) && (!tx->ima)) continue;
+ used_textures[tx->id.name] = mx;
+ }
+ }
+
+ // Make list of faces per object, ignore <3 vert faces, duplicate vertex sorting done later.
+ // ignore null object pointers.
+ // Also make list of facetexture images (material 'TexFace').
+ if (vlr->ob) {
+ int nv = 0; // number of vertices
+ MTFace *tface;
+
+ if (vlr->v4) nv=4; else if (vlr->v3) nv=3;
+ if (nv) {
+ renderobs[vlr->ob->id.name] = vlr->ob;
+ all_objects[vlr->ob].push_back(vlr);
+
+ tface= RE_vlakren_get_tface(re, vlr, 0, NULL, 0);
+ if (tface && tface->tpage) {
+ Material* fmat = vlr->mat;
+
+ // only save if TexFace enabled
+ if(fmat && (fmat->mode & MA_FACETEXTURE))
+ imagetex[tface->tpage].insert(fmat);
+ }
+ }
+ }
+
+ }
+
+ // now remove any objects from dupliMtx_list which are not in the renderlist
+ for (map<string, vector<float> >::iterator dL=dupliMtx_list.begin();
+ dL!=dupliMtx_list.end();)
+ {
+ string ro_name = dL->first;
+ if (renderobs.find(ro_name)==renderobs.end()) {
+ cout << "Object " << ro_name << " not in renderlist, removing from dupliMtx_list" << endl;
+ dL->second.clear();
+ ++dL;
+ dupliMtx_list.erase(ro_name);
+ }
+ else
+ ++dL;
+ }
+
+ // in case dupliMtx_list not empty, make sure that there is at least one source object
+ // in all_objects with the name given in dupliMtx_list
+ if (!dupliMtx_list.empty()) {
+
+ for (map<Object*, vector<VlakRen*> >::const_iterator obn=all_objects.begin();
+ obn!=all_objects.end();++obn)
+ {
+ Object* obj = obn->first;
+ string obname = obj->id.name;
+ if (dupliMtx_list.find(obname)!=dupliMtx_list.end()) dup_srcob[obname] = obj;
+ }
+
+ // if the name reference list is empty, return now, something was seriously wrong
+ if (dup_srcob.empty()) {
+ // error() doesn't work to well, when switching from Blender to console at least, so use stdout instead
+ cout << "ERROR: Duplilist non_empty, but no srcobs\n";
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+
+void yafrayRender_t::addDupliMtx(Object* obj)
+{
+ for (int i=0;i<4;i++)
+ for (int j=0;j<4;j++)
+ dupliMtx_list[obj->id.name].push_back(obj->obmat[i][j]);
+}
+
+
+bool yafrayRender_t::objectKnownData(Object* obj)
+{
+ // if object data already known, no need to include in renderlist, otherwise save object datapointer
+ if (objectData.find(obj->data)!=objectData.end()) {
+ Object* orgob = objectData[obj->data];
+ // first save original object matrix in dupliMtx_list, if not added yet
+ if (dupliMtx_list.find(orgob->id.name)==dupliMtx_list.end()) {
+ cout << "Added original matrix\n";
+ addDupliMtx(orgob);
+ }
+ // then save matrix of linked object in dupliMtx_list, using name of ORIGINAL object
+ for (int i=0;i<4;i++)
+ for (int j=0;j<4;j++)
+ dupliMtx_list[orgob->id.name].push_back(obj->obmat[i][j]);
+ return true;
+ }
+ // object not known yet
+ objectData[obj->data] = obj;
+ return false;
+}
diff --git a/source/blender/yafray/intern/yafray_Render.h b/source/blender/yafray/intern/yafray_Render.h
new file mode 100644
index 00000000000..4002f514a6e
--- /dev/null
+++ b/source/blender/yafray/intern/yafray_Render.h
@@ -0,0 +1,107 @@
+#ifndef __YAFRAY_RENDER_H
+#define __YAFRAY_RENDER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "MEM_guardedalloc.h"
+#include "IMB_imbuf_types.h"
+
+#include "DNA_camera_types.h"
+#include "DNA_group_types.h"
+#include "DNA_image_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_world_types.h"
+
+#include "BKE_global.h"
+
+#include "render_types.h"
+#include "renderdatabase.h"
+/* display_draw() needs render layer info */
+#include "renderpipeline.h"
+
+/* useful matrix & vector operations */
+#include "MTC_matrixops.h"
+#include "MTC_vectorops.h"
+
+#include "BLI_blenlib.h"
+
+/* need error(), so extern declare here */
+extern void error (char *fmt, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#ifdef __cplusplus
+#include <iostream>
+#include <iomanip>
+#include <sstream>
+#include <fstream>
+#include <map>
+#include <string>
+#include <vector>
+#include <set>
+
+class yafrayRender_t
+{
+ public:
+ // ctor
+ yafrayRender_t() {}
+ // dtor
+ virtual ~yafrayRender_t() {}
+
+ // mtds
+ bool exportScene(Render* re);
+ void addDupliMtx(Object* obj);
+ bool objectKnownData(Object* obj);
+
+ protected:
+ Render* re;
+ Object* maincam_obj;
+ float mainCamLens;
+
+ bool hasworld;
+
+ std::map<Object*, std::vector<VlakRen*> > all_objects;
+ std::map<std::string, Material*> used_materials;
+ std::map<std::string, MTex*> used_textures;
+ std::map<std::string, std::vector<float> > dupliMtx_list;
+ std::map<std::string, Object*> dup_srcob;
+ std::map<void*, Object*> objectData;
+ std::map<Image*, std::set<Material*> > imagetex;
+ std::map<std::string, std::string> imgtex_shader;
+
+ bool getAllMatTexObs();
+
+ virtual void writeTextures()=0;
+ virtual void writeShader(const std::string &shader_name, Material* matr, const std::string &facetexname)=0;
+ virtual void writeMaterialsAndModulators()=0;
+ virtual void writeObject(Object* obj, const std::vector<VlakRen*> &VLR_list, const float obmat[4][4])=0;
+ virtual void writeAllObjects()=0;
+ virtual void writeLamps()=0;
+ virtual void writeCamera()=0;
+ virtual void writeAreaLamp(LampRen* lamp, int num, float iview[4][4])=0;
+ virtual void writeHemilight()=0;
+ virtual void writePathlight()=0;
+ virtual bool writeWorld()=0;
+ virtual bool writeRender()=0;
+ virtual bool initExport()=0;
+ virtual bool finishExport()=0;
+
+ void clearAll();
+};
+
+#endif
+
+
+#endif /*__YAFRAY_RENDER_H */